aboutsummaryrefslogtreecommitdiffstats
path: root/library
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library')
-rw-r--r--library/README.md48
-rw-r--r--library/cpp/accurate_accumulate/accurate_accumulate.cpp1
-rw-r--r--library/cpp/accurate_accumulate/accurate_accumulate.h221
-rw-r--r--library/cpp/accurate_accumulate/benchmark/main.cpp97
-rw-r--r--library/cpp/accurate_accumulate/benchmark/metrics/main.py7
-rw-r--r--library/cpp/accurate_accumulate/benchmark/metrics/ya.make17
-rw-r--r--library/cpp/accurate_accumulate/benchmark/ya.make13
-rw-r--r--library/cpp/accurate_accumulate/ya.make10
-rw-r--r--library/cpp/actors/README.md107
-rw-r--r--library/cpp/actors/core/README.md99
-rw-r--r--library/cpp/actors/core/actor.cpp172
-rw-r--r--library/cpp/actors/core/actor.h530
-rw-r--r--library/cpp/actors/core/actor_bootstrapped.h37
-rw-r--r--library/cpp/actors/core/actor_coroutine.cpp165
-rw-r--r--library/cpp/actors/core/actor_coroutine.h174
-rw-r--r--library/cpp/actors/core/actor_coroutine_ut.cpp141
-rw-r--r--library/cpp/actors/core/actor_ut.cpp578
-rw-r--r--library/cpp/actors/core/actorid.cpp34
-rw-r--r--library/cpp/actors/core/actorid.h196
-rw-r--r--library/cpp/actors/core/actorsystem.cpp277
-rw-r--r--library/cpp/actors/core/actorsystem.h367
-rw-r--r--library/cpp/actors/core/actorsystem_ut.cpp45
-rw-r--r--library/cpp/actors/core/ask.cpp74
-rw-r--r--library/cpp/actors/core/ask.h18
-rw-r--r--library/cpp/actors/core/ask_ut.cpp131
-rw-r--r--library/cpp/actors/core/balancer.cpp293
-rw-r--r--library/cpp/actors/core/balancer.h27
-rw-r--r--library/cpp/actors/core/balancer_ut.cpp225
-rw-r--r--library/cpp/actors/core/buffer.cpp93
-rw-r--r--library/cpp/actors/core/buffer.h62
-rw-r--r--library/cpp/actors/core/callstack.cpp93
-rw-r--r--library/cpp/actors/core/callstack.h58
-rw-r--r--library/cpp/actors/core/config.h239
-rw-r--r--library/cpp/actors/core/cpu_manager.cpp108
-rw-r--r--library/cpp/actors/core/cpu_manager.h57
-rw-r--r--library/cpp/actors/core/cpu_state.h215
-rw-r--r--library/cpp/actors/core/defs.h69
-rw-r--r--library/cpp/actors/core/event.cpp38
-rw-r--r--library/cpp/actors/core/event.h344
-rw-r--r--library/cpp/actors/core/event_load.h112
-rw-r--r--library/cpp/actors/core/event_local.h74
-rw-r--r--library/cpp/actors/core/event_pb.cpp223
-rw-r--r--library/cpp/actors/core/event_pb.h500
-rw-r--r--library/cpp/actors/core/event_pb_payload_ut.cpp154
-rw-r--r--library/cpp/actors/core/event_pb_ut.cpp71
-rw-r--r--library/cpp/actors/core/events.h222
-rw-r--r--library/cpp/actors/core/events_undelivered.cpp60
-rw-r--r--library/cpp/actors/core/executelater.h87
-rw-r--r--library/cpp/actors/core/executor_pool_base.cpp168
-rw-r--r--library/cpp/actors/core/executor_pool_base.h49
-rw-r--r--library/cpp/actors/core/executor_pool_basic.cpp431
-rw-r--r--library/cpp/actors/core/executor_pool_basic.h111
-rw-r--r--library/cpp/actors/core/executor_pool_basic_ut.cpp435
-rw-r--r--library/cpp/actors/core/executor_pool_io.cpp151
-rw-r--r--library/cpp/actors/core/executor_pool_io.h49
-rw-r--r--library/cpp/actors/core/executor_pool_united.cpp1428
-rw-r--r--library/cpp/actors/core/executor_pool_united.h135
-rw-r--r--library/cpp/actors/core/executor_pool_united_ut.cpp338
-rw-r--r--library/cpp/actors/core/executor_thread.cpp563
-rw-r--r--library/cpp/actors/core/executor_thread.h112
-rw-r--r--library/cpp/actors/core/hfunc.h84
-rw-r--r--library/cpp/actors/core/interconnect.cpp170
-rw-r--r--library/cpp/actors/core/interconnect.h248
-rw-r--r--library/cpp/actors/core/invoke.h110
-rw-r--r--library/cpp/actors/core/io_dispatcher.cpp234
-rw-r--r--library/cpp/actors/core/io_dispatcher.h38
-rw-r--r--library/cpp/actors/core/lease.h56
-rw-r--r--library/cpp/actors/core/log.cpp753
-rw-r--r--library/cpp/actors/core/log.h369
-rw-r--r--library/cpp/actors/core/log_iface.h109
-rw-r--r--library/cpp/actors/core/log_settings.cpp230
-rw-r--r--library/cpp/actors/core/log_settings.h176
-rw-r--r--library/cpp/actors/core/log_ut.cpp185
-rw-r--r--library/cpp/actors/core/mailbox.cpp551
-rw-r--r--library/cpp/actors/core/mailbox.h553
-rw-r--r--library/cpp/actors/core/mailbox_queue_revolving.h214
-rw-r--r--library/cpp/actors/core/mailbox_queue_simple.h34
-rw-r--r--library/cpp/actors/core/memory_track.cpp38
-rw-r--r--library/cpp/actors/core/memory_track.h293
-rw-r--r--library/cpp/actors/core/memory_tracker.cpp103
-rw-r--r--library/cpp/actors/core/memory_tracker.h53
-rw-r--r--library/cpp/actors/core/memory_tracker_ut.cpp262
-rw-r--r--library/cpp/actors/core/mon.h234
-rw-r--r--library/cpp/actors/core/mon_stats.h147
-rw-r--r--library/cpp/actors/core/monotonic.cpp23
-rw-r--r--library/cpp/actors/core/monotonic.h111
-rw-r--r--library/cpp/actors/core/probes.cpp28
-rw-r--r--library/cpp/actors/core/probes.h176
-rw-r--r--library/cpp/actors/core/process_stats.cpp303
-rw-r--r--library/cpp/actors/core/process_stats.h66
-rw-r--r--library/cpp/actors/core/scheduler_actor.cpp279
-rw-r--r--library/cpp/actors/core/scheduler_actor.h29
-rw-r--r--library/cpp/actors/core/scheduler_actor_ut.cpp100
-rw-r--r--library/cpp/actors/core/scheduler_basic.cpp274
-rw-r--r--library/cpp/actors/core/scheduler_basic.h81
-rw-r--r--library/cpp/actors/core/scheduler_cookie.cpp84
-rw-r--r--library/cpp/actors/core/scheduler_cookie.h78
-rw-r--r--library/cpp/actors/core/scheduler_queue.h120
-rw-r--r--library/cpp/actors/core/servicemap.h168
-rw-r--r--library/cpp/actors/core/ut/ya.make46
-rw-r--r--library/cpp/actors/core/worker_context.cpp7
-rw-r--r--library/cpp/actors/core/worker_context.h175
-rw-r--r--library/cpp/actors/core/ya.make123
-rw-r--r--library/cpp/actors/dnscachelib/dnscache.cpp445
-rw-r--r--library/cpp/actors/dnscachelib/dnscache.h148
-rw-r--r--library/cpp/actors/dnscachelib/probes.cpp3
-rw-r--r--library/cpp/actors/dnscachelib/probes.h35
-rw-r--r--library/cpp/actors/dnscachelib/timekeeper.h70
-rw-r--r--library/cpp/actors/dnscachelib/ya.make24
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver.cpp475
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver.h128
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver_caching.cpp730
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp630
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp64
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp24
-rw-r--r--library/cpp/actors/dnsresolver/dnsresolver_ut.cpp98
-rw-r--r--library/cpp/actors/dnsresolver/ut/ya.make20
-rw-r--r--library/cpp/actors/dnsresolver/ya.make20
-rw-r--r--library/cpp/actors/helpers/activeactors.cpp2
-rw-r--r--library/cpp/actors/helpers/activeactors.h42
-rw-r--r--library/cpp/actors/helpers/flow_controlled_queue.cpp215
-rw-r--r--library/cpp/actors/helpers/flow_controlled_queue.h18
-rw-r--r--library/cpp/actors/helpers/future_callback.h33
-rw-r--r--library/cpp/actors/helpers/mon_histogram_helper.h86
-rw-r--r--library/cpp/actors/helpers/pool_stats_collector.h314
-rw-r--r--library/cpp/actors/helpers/selfping_actor.cpp183
-rw-r--r--library/cpp/actors/helpers/selfping_actor.h13
-rw-r--r--library/cpp/actors/helpers/selfping_actor_ut.cpp45
-rw-r--r--library/cpp/actors/helpers/ut/ya.make36
-rw-r--r--library/cpp/actors/helpers/ya.make25
-rw-r--r--library/cpp/actors/http/http.cpp653
-rw-r--r--library/cpp/actors/http/http.h703
-rw-r--r--library/cpp/actors/http/http_cache.cpp599
-rw-r--r--library/cpp/actors/http/http_cache.h27
-rw-r--r--library/cpp/actors/http/http_config.h19
-rw-r--r--library/cpp/actors/http/http_proxy.cpp314
-rw-r--r--library/cpp/actors/http/http_proxy.h239
-rw-r--r--library/cpp/actors/http/http_proxy_acceptor.cpp135
-rw-r--r--library/cpp/actors/http/http_proxy_incoming.cpp302
-rw-r--r--library/cpp/actors/http/http_proxy_outgoing.cpp298
-rw-r--r--library/cpp/actors/http/http_proxy_sock_impl.h262
-rw-r--r--library/cpp/actors/http/http_proxy_ssl.h131
-rw-r--r--library/cpp/actors/http/http_static.cpp95
-rw-r--r--library/cpp/actors/http/http_static.h9
-rw-r--r--library/cpp/actors/http/http_ut.cpp358
-rw-r--r--library/cpp/actors/http/ut/ya.make18
-rw-r--r--library/cpp/actors/http/ya.make33
-rw-r--r--library/cpp/actors/interconnect/channel_scheduler.h120
-rw-r--r--library/cpp/actors/interconnect/event_filter.h72
-rw-r--r--library/cpp/actors/interconnect/event_holder_pool.h128
-rw-r--r--library/cpp/actors/interconnect/events_local.h403
-rw-r--r--library/cpp/actors/interconnect/interconnect.h179
-rw-r--r--library/cpp/actors/interconnect/interconnect_address.cpp94
-rw-r--r--library/cpp/actors/interconnect/interconnect_address.h29
-rw-r--r--library/cpp/actors/interconnect/interconnect_channel.cpp176
-rw-r--r--library/cpp/actors/interconnect/interconnect_channel.h127
-rw-r--r--library/cpp/actors/interconnect/interconnect_common.h106
-rw-r--r--library/cpp/actors/interconnect/interconnect_counters.cpp692
-rw-r--r--library/cpp/actors/interconnect/interconnect_counters.h59
-rw-r--r--library/cpp/actors/interconnect/interconnect_handshake.cpp995
-rw-r--r--library/cpp/actors/interconnect/interconnect_handshake.h24
-rw-r--r--library/cpp/actors/interconnect/interconnect_impl.h45
-rw-r--r--library/cpp/actors/interconnect/interconnect_mon.cpp276
-rw-r--r--library/cpp/actors/interconnect/interconnect_mon.h15
-rw-r--r--library/cpp/actors/interconnect/interconnect_nameserver_base.h83
-rw-r--r--library/cpp/actors/interconnect/interconnect_nameserver_dynamic.cpp178
-rw-r--r--library/cpp/actors/interconnect/interconnect_nameserver_table.cpp86
-rw-r--r--library/cpp/actors/interconnect/interconnect_proxy_wrapper.cpp47
-rw-r--r--library/cpp/actors/interconnect/interconnect_proxy_wrapper.h12
-rw-r--r--library/cpp/actors/interconnect/interconnect_resolve.cpp174
-rw-r--r--library/cpp/actors/interconnect/interconnect_stream.cpp628
-rw-r--r--library/cpp/actors/interconnect/interconnect_stream.h131
-rw-r--r--library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp476
-rw-r--r--library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp936
-rw-r--r--library/cpp/actors/interconnect/interconnect_tcp_proxy.h537
-rw-r--r--library/cpp/actors/interconnect/interconnect_tcp_server.cpp117
-rw-r--r--library/cpp/actors/interconnect/interconnect_tcp_server.h57
-rw-r--r--library/cpp/actors/interconnect/interconnect_tcp_session.cpp1228
-rw-r--r--library/cpp/actors/interconnect/interconnect_tcp_session.h565
-rw-r--r--library/cpp/actors/interconnect/load.cpp405
-rw-r--r--library/cpp/actors/interconnect/load.h24
-rw-r--r--library/cpp/actors/interconnect/logging.h68
-rw-r--r--library/cpp/actors/interconnect/mock/ic_mock.cpp298
-rw-r--r--library/cpp/actors/interconnect/mock/ic_mock.h19
-rw-r--r--library/cpp/actors/interconnect/mock/tsan.supp1
-rw-r--r--library/cpp/actors/interconnect/mock/ya.make16
-rw-r--r--library/cpp/actors/interconnect/packet.cpp32
-rw-r--r--library/cpp/actors/interconnect/packet.h324
-rw-r--r--library/cpp/actors/interconnect/poller.h23
-rw-r--r--library/cpp/actors/interconnect/poller_actor.cpp294
-rw-r--r--library/cpp/actors/interconnect/poller_actor.h63
-rw-r--r--library/cpp/actors/interconnect/poller_actor_darwin.h95
-rw-r--r--library/cpp/actors/interconnect/poller_actor_linux.h114
-rw-r--r--library/cpp/actors/interconnect/poller_actor_win.h103
-rw-r--r--library/cpp/actors/interconnect/poller_tcp.cpp35
-rw-r--r--library/cpp/actors/interconnect/poller_tcp.h25
-rw-r--r--library/cpp/actors/interconnect/poller_tcp_unit.cpp126
-rw-r--r--library/cpp/actors/interconnect/poller_tcp_unit.h67
-rw-r--r--library/cpp/actors/interconnect/poller_tcp_unit_epoll.cpp125
-rw-r--r--library/cpp/actors/interconnect/poller_tcp_unit_epoll.h33
-rw-r--r--library/cpp/actors/interconnect/poller_tcp_unit_select.cpp86
-rw-r--r--library/cpp/actors/interconnect/poller_tcp_unit_select.h19
-rw-r--r--library/cpp/actors/interconnect/profiler.h142
-rw-r--r--library/cpp/actors/interconnect/slowpoke_actor.h47
-rw-r--r--library/cpp/actors/interconnect/types.cpp564
-rw-r--r--library/cpp/actors/interconnect/types.h43
-rw-r--r--library/cpp/actors/interconnect/ut/channel_scheduler_ut.cpp115
-rw-r--r--library/cpp/actors/interconnect/ut/dynamic_proxy_ut.cpp179
-rw-r--r--library/cpp/actors/interconnect/ut/event_holder_pool_ut.cpp59
-rw-r--r--library/cpp/actors/interconnect/ut/interconnect_ut.cpp177
-rw-r--r--library/cpp/actors/interconnect/ut/large.cpp85
-rw-r--r--library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h84
-rw-r--r--library/cpp/actors/interconnect/ut/lib/interrupter.h249
-rw-r--r--library/cpp/actors/interconnect/ut/lib/node.h137
-rw-r--r--library/cpp/actors/interconnect/ut/lib/test_actors.h83
-rw-r--r--library/cpp/actors/interconnect/ut/lib/test_events.h49
-rw-r--r--library/cpp/actors/interconnect/ut/lib/ya.make12
-rw-r--r--library/cpp/actors/interconnect/ut/poller_actor_ut.cpp264
-rw-r--r--library/cpp/actors/interconnect/ut/protos/interconnect_test.proto25
-rw-r--r--library/cpp/actors/interconnect/ut/protos/ya.make11
-rw-r--r--library/cpp/actors/interconnect/ut/ya.make36
-rw-r--r--library/cpp/actors/interconnect/ut_fat/main.cpp133
-rw-r--r--library/cpp/actors/interconnect/ut_fat/ya.make25
-rw-r--r--library/cpp/actors/interconnect/watchdog_timer.h68
-rw-r--r--library/cpp/actors/interconnect/ya.make94
-rw-r--r--library/cpp/actors/memory_log/memlog.cpp367
-rw-r--r--library/cpp/actors/memory_log/memlog.h211
-rw-r--r--library/cpp/actors/memory_log/mmap.cpp63
-rw-r--r--library/cpp/actors/memory_log/ya.make19
-rw-r--r--library/cpp/actors/prof/tag.cpp119
-rw-r--r--library/cpp/actors/prof/tag.h73
-rw-r--r--library/cpp/actors/prof/tcmalloc.cpp32
-rw-r--r--library/cpp/actors/prof/tcmalloc.h9
-rw-r--r--library/cpp/actors/prof/tcmalloc_null.cpp10
-rw-r--r--library/cpp/actors/prof/ut/tag_ut.cpp68
-rw-r--r--library/cpp/actors/prof/ut/ya.make12
-rw-r--r--library/cpp/actors/prof/ya.make33
-rw-r--r--library/cpp/actors/protos/actors.proto13
-rw-r--r--library/cpp/actors/protos/interconnect.proto113
-rw-r--r--library/cpp/actors/protos/services_common.proto21
-rw-r--r--library/cpp/actors/protos/unittests.proto20
-rw-r--r--library/cpp/actors/protos/ya.make14
-rw-r--r--library/cpp/actors/testlib/decorator_ut.cpp327
-rw-r--r--library/cpp/actors/testlib/test_runtime.cpp1902
-rw-r--r--library/cpp/actors/testlib/test_runtime.h716
-rw-r--r--library/cpp/actors/testlib/ut/ya.make20
-rw-r--r--library/cpp/actors/testlib/ya.make27
-rw-r--r--library/cpp/actors/util/affinity.cpp93
-rw-r--r--library/cpp/actors/util/affinity.h49
-rw-r--r--library/cpp/actors/util/cpumask.h133
-rw-r--r--library/cpp/actors/util/datetime.h82
-rw-r--r--library/cpp/actors/util/defs.h16
-rw-r--r--library/cpp/actors/util/funnel_queue.h240
-rw-r--r--library/cpp/actors/util/futex.h13
-rw-r--r--library/cpp/actors/util/intrinsics.h97
-rw-r--r--library/cpp/actors/util/local_process_key.h132
-rw-r--r--library/cpp/actors/util/named_tuple.h30
-rw-r--r--library/cpp/actors/util/queue_chunk.h29
-rw-r--r--library/cpp/actors/util/queue_oneone_inplace.h118
-rw-r--r--library/cpp/actors/util/recentwnd.h67
-rw-r--r--library/cpp/actors/util/rope.h1161
-rw-r--r--library/cpp/actors/util/rope_cont_deque.h181
-rw-r--r--library/cpp/actors/util/rope_cont_list.h159
-rw-r--r--library/cpp/actors/util/rope_ut.cpp231
-rw-r--r--library/cpp/actors/util/should_continue.cpp23
-rw-r--r--library/cpp/actors/util/should_continue.h22
-rw-r--r--library/cpp/actors/util/thread.h26
-rw-r--r--library/cpp/actors/util/threadparkpad.cpp148
-rw-r--r--library/cpp/actors/util/threadparkpad.h21
-rw-r--r--library/cpp/actors/util/ticket_lock.h48
-rw-r--r--library/cpp/actors/util/timerfd.h65
-rw-r--r--library/cpp/actors/util/unordered_cache.h201
-rw-r--r--library/cpp/actors/util/unordered_cache_ut.cpp138
-rw-r--r--library/cpp/actors/util/ut/ya.make18
-rw-r--r--library/cpp/actors/util/ya.make37
-rw-r--r--library/cpp/actors/wilson/wilson_event.h181
-rw-r--r--library/cpp/actors/wilson/wilson_trace.h161
-rw-r--r--library/cpp/actors/wilson/ya.make14
-rw-r--r--library/cpp/actors/ya.make16
-rw-r--r--library/cpp/archive/directory_models_archive_reader.cpp115
-rw-r--r--library/cpp/archive/directory_models_archive_reader.h38
-rw-r--r--library/cpp/archive/directory_models_archive_reader_ut.cpp55
-rw-r--r--library/cpp/archive/models_archive_reader.h20
-rw-r--r--library/cpp/archive/ut/ya.make16
-rw-r--r--library/cpp/archive/ya.make12
-rw-r--r--library/cpp/archive/yarchive.cpp398
-rw-r--r--library/cpp/archive/yarchive.h48
-rw-r--r--library/cpp/archive/yarchive_ut.cpp84
-rw-r--r--library/cpp/balloc/balloc.cpp308
-rw-r--r--library/cpp/balloc/malloc-info.cpp41
-rw-r--r--library/cpp/balloc/optional/operators.cpp1
-rw-r--r--library/cpp/balloc/optional/operators.h16
-rw-r--r--library/cpp/balloc/optional/ya.make15
-rw-r--r--library/cpp/balloc/ya.make28
-rw-r--r--library/cpp/binsaver/bin_saver.cpp81
-rw-r--r--library/cpp/binsaver/bin_saver.h646
-rw-r--r--library/cpp/binsaver/blob_io.cpp1
-rw-r--r--library/cpp/binsaver/blob_io.h47
-rw-r--r--library/cpp/binsaver/buffered_io.cpp39
-rw-r--r--library/cpp/binsaver/buffered_io.h134
-rw-r--r--library/cpp/binsaver/class_factory.h105
-rw-r--r--library/cpp/binsaver/mem_io.cpp1
-rw-r--r--library/cpp/binsaver/mem_io.h212
-rw-r--r--library/cpp/binsaver/ut/binsaver_ut.cpp198
-rw-r--r--library/cpp/binsaver/ut/ya.make11
-rw-r--r--library/cpp/binsaver/ut_util/README.md1
-rw-r--r--library/cpp/binsaver/ut_util/ut_util.cpp1
-rw-r--r--library/cpp/binsaver/ut_util/ut_util.h71
-rw-r--r--library/cpp/binsaver/ut_util/ya.make14
-rw-r--r--library/cpp/binsaver/util_stream_io.cpp1
-rw-r--r--library/cpp/binsaver/util_stream_io.h86
-rw-r--r--library/cpp/binsaver/ya.make18
-rw-r--r--library/cpp/bit_io/bitinout_ut.cpp279
-rw-r--r--library/cpp/bit_io/bitinput.cpp1
-rw-r--r--library/cpp/bit_io/bitinput.h171
-rw-r--r--library/cpp/bit_io/bitinput_impl.cpp1
-rw-r--r--library/cpp/bit_io/bitinput_impl.h110
-rw-r--r--library/cpp/bit_io/bitoutput.cpp1
-rw-r--r--library/cpp/bit_io/bitoutput.h195
-rw-r--r--library/cpp/bit_io/ut/ya.make12
-rw-r--r--library/cpp/bit_io/ya.make18
-rw-r--r--library/cpp/blockcodecs/README.md23
-rw-r--r--library/cpp/blockcodecs/codecs.cpp1
-rw-r--r--library/cpp/blockcodecs/codecs.h3
-rw-r--r--library/cpp/blockcodecs/codecs/brotli/brotli.cpp67
-rw-r--r--library/cpp/blockcodecs/codecs/brotli/ya.make15
-rw-r--r--library/cpp/blockcodecs/codecs/bzip/bzip.cpp62
-rw-r--r--library/cpp/blockcodecs/codecs/bzip/ya.make14
-rw-r--r--library/cpp/blockcodecs/codecs/fastlz/fastlz.cpp54
-rw-r--r--library/cpp/blockcodecs/codecs/fastlz/ya.make14
-rw-r--r--library/cpp/blockcodecs/codecs/legacy_zstd06/legacy_zstd06.cpp58
-rw-r--r--library/cpp/blockcodecs/codecs/legacy_zstd06/ya.make14
-rw-r--r--library/cpp/blockcodecs/codecs/lz4/lz4.cpp123
-rw-r--r--library/cpp/blockcodecs/codecs/lz4/ya.make15
-rw-r--r--library/cpp/blockcodecs/codecs/lzma/lzma.cpp74
-rw-r--r--library/cpp/blockcodecs/codecs/lzma/ya.make14
-rw-r--r--library/cpp/blockcodecs/codecs/snappy/snappy.cpp52
-rw-r--r--library/cpp/blockcodecs/codecs/snappy/ya.make14
-rw-r--r--library/cpp/blockcodecs/codecs/zlib/ya.make14
-rw-r--r--library/cpp/blockcodecs/codecs/zlib/zlib.cpp64
-rw-r--r--library/cpp/blockcodecs/codecs/zstd/ya.make14
-rw-r--r--library/cpp/blockcodecs/codecs/zstd/zstd.cpp59
-rw-r--r--library/cpp/blockcodecs/codecs_ut.cpp340
-rw-r--r--library/cpp/blockcodecs/core/codecs.cpp148
-rw-r--r--library/cpp/blockcodecs/core/codecs.h90
-rw-r--r--library/cpp/blockcodecs/core/common.h105
-rw-r--r--library/cpp/blockcodecs/core/register.h10
-rw-r--r--library/cpp/blockcodecs/core/stream.cpp212
-rw-r--r--library/cpp/blockcodecs/core/stream.h46
-rw-r--r--library/cpp/blockcodecs/core/ya.make10
-rw-r--r--library/cpp/blockcodecs/fuzz/main.cpp84
-rw-r--r--library/cpp/blockcodecs/fuzz/proto/case.proto10
-rw-r--r--library/cpp/blockcodecs/fuzz/proto/ya.make14
-rw-r--r--library/cpp/blockcodecs/fuzz/ya.make23
-rw-r--r--library/cpp/blockcodecs/stream.cpp1
-rw-r--r--library/cpp/blockcodecs/stream.h3
-rw-r--r--library/cpp/blockcodecs/ut/ya.make19
-rw-r--r--library/cpp/blockcodecs/ya.make27
-rw-r--r--library/cpp/bucket_quoter/bucket_quoter.cpp1
-rw-r--r--library/cpp/bucket_quoter/bucket_quoter.h281
-rw-r--r--library/cpp/bucket_quoter/ut/README.md20
-rw-r--r--library/cpp/bucket_quoter/ut/main.cpp44
-rw-r--r--library/cpp/bucket_quoter/ut/test_namespace.cpp13
-rw-r--r--library/cpp/bucket_quoter/ut/test_namespace.h83
-rw-r--r--library/cpp/bucket_quoter/ut/ya.make18
-rw-r--r--library/cpp/bucket_quoter/ya.make11
-rw-r--r--library/cpp/build_info/build_info.cpp.in5
-rw-r--r--library/cpp/build_info/build_info.h14
-rw-r--r--library/cpp/build_info/build_info_static.cpp27
-rw-r--r--library/cpp/build_info/build_info_static.h13
-rw-r--r--library/cpp/build_info/sandbox.cpp.in27
-rw-r--r--library/cpp/build_info/sandbox.h12
-rw-r--r--library/cpp/build_info/ya.make24
-rw-r--r--library/cpp/cache/cache.cpp1
-rw-r--r--library/cpp/cache/cache.h649
-rw-r--r--library/cpp/cache/thread_safe_cache.cpp1
-rw-r--r--library/cpp/cache/thread_safe_cache.h201
-rw-r--r--library/cpp/cache/ut/cache_ut.cpp618
-rw-r--r--library/cpp/cache/ut/ya.make16
-rw-r--r--library/cpp/cache/ya.make16
-rw-r--r--library/cpp/cgiparam/cgiparam.cpp273
-rw-r--r--library/cpp/cgiparam/cgiparam.h184
-rw-r--r--library/cpp/cgiparam/cgiparam_ut.cpp242
-rw-r--r--library/cpp/cgiparam/fuzz/main.cpp11
-rw-r--r--library/cpp/cgiparam/fuzz/ya.make16
-rw-r--r--library/cpp/cgiparam/ut/ya.make9
-rw-r--r--library/cpp/cgiparam/ya.make16
-rw-r--r--library/cpp/charset/README.md10
-rw-r--r--library/cpp/charset/ci_string.cpp42
-rw-r--r--library/cpp/charset/ci_string.h280
-rw-r--r--library/cpp/charset/ci_string_ut.cpp23
-rw-r--r--library/cpp/charset/codepage.cpp511
-rw-r--r--library/cpp/charset/codepage.h324
-rw-r--r--library/cpp/charset/codepage_ut.cpp424
-rw-r--r--library/cpp/charset/cp_encrec.cpp54
-rw-r--r--library/cpp/charset/doccodes.cpp1
-rw-r--r--library/cpp/charset/doccodes.h129
-rw-r--r--library/cpp/charset/generated/cp_data.cpp3788
-rw-r--r--library/cpp/charset/generated/encrec_data.cpp15082
-rw-r--r--library/cpp/charset/iconv.cpp94
-rw-r--r--library/cpp/charset/iconv.h136
-rw-r--r--library/cpp/charset/iconv_ut.cpp87
-rw-r--r--library/cpp/charset/recyr.hh164
-rw-r--r--library/cpp/charset/recyr_int.hh336
-rw-r--r--library/cpp/charset/ut/ya.make12
-rw-r--r--library/cpp/charset/wide.cpp18
-rw-r--r--library/cpp/charset/wide.h306
-rw-r--r--library/cpp/charset/wide_ut.cpp399
-rw-r--r--library/cpp/charset/ya.make22
-rw-r--r--library/cpp/codecs/README.md46
-rw-r--r--library/cpp/codecs/codecs.cpp190
-rw-r--r--library/cpp/codecs/codecs.h259
-rw-r--r--library/cpp/codecs/codecs_registry.cpp226
-rw-r--r--library/cpp/codecs/codecs_registry.h60
-rw-r--r--library/cpp/codecs/comptable_codec.cpp108
-rw-r--r--library/cpp/codecs/comptable_codec.h40
-rw-r--r--library/cpp/codecs/delta_codec.cpp21
-rw-r--r--library/cpp/codecs/delta_codec.h143
-rw-r--r--library/cpp/codecs/float_huffman.cpp333
-rw-r--r--library/cpp/codecs/float_huffman.h50
-rw-r--r--library/cpp/codecs/float_huffman_bench/main.cpp145
-rw-r--r--library/cpp/codecs/float_huffman_bench/ya.make13
-rw-r--r--library/cpp/codecs/greedy_dict/gd_builder.cpp142
-rw-r--r--library/cpp/codecs/greedy_dict/gd_builder.h94
-rw-r--r--library/cpp/codecs/greedy_dict/gd_entry.cpp98
-rw-r--r--library/cpp/codecs/greedy_dict/gd_entry.h103
-rw-r--r--library/cpp/codecs/greedy_dict/gd_stats.h79
-rw-r--r--library/cpp/codecs/greedy_dict/ut/greedy_dict_ut.cpp282
-rw-r--r--library/cpp/codecs/greedy_dict/ut/ya.make9
-rw-r--r--library/cpp/codecs/greedy_dict/ya.make15
-rw-r--r--library/cpp/codecs/huffman_codec.cpp592
-rw-r--r--library/cpp/codecs/huffman_codec.h39
-rw-r--r--library/cpp/codecs/pfor_codec.cpp22
-rw-r--r--library/cpp/codecs/pfor_codec.h211
-rw-r--r--library/cpp/codecs/sample.h89
-rw-r--r--library/cpp/codecs/solar_codec.cpp133
-rw-r--r--library/cpp/codecs/solar_codec.h244
-rw-r--r--library/cpp/codecs/static/README1
-rw-r--r--library/cpp/codecs/static/builder.cpp39
-rw-r--r--library/cpp/codecs/static/builder.h29
-rw-r--r--library/cpp/codecs/static/common.h32
-rw-r--r--library/cpp/codecs/static/example/example.cpp43
-rw-r--r--library/cpp/codecs/static/example/example.h17
-rw-r--r--library/cpp/codecs/static/example/huffman.1467494385.codec_infobin0 -> 385 bytes
-rw-r--r--library/cpp/codecs/static/example/solar-8k-a.huffman.1467494385.codec_infobin0 -> 3425 bytes
-rw-r--r--library/cpp/codecs/static/example/ya.make24
-rw-r--r--library/cpp/codecs/static/static.cpp98
-rw-r--r--library/cpp/codecs/static/static.h34
-rw-r--r--library/cpp/codecs/static/static_codec_info.proto17
-rw-r--r--library/cpp/codecs/static/tools/common/ct_common.cpp74
-rw-r--r--library/cpp/codecs/static/tools/common/ct_common.h75
-rw-r--r--library/cpp/codecs/static/tools/common/ya.make19
-rw-r--r--library/cpp/codecs/static/tools/static_codec_checker/README4
-rw-r--r--library/cpp/codecs/static/tools/static_codec_checker/static_codec_checker.cpp73
-rw-r--r--library/cpp/codecs/static/tools/static_codec_checker/ya.make16
-rw-r--r--library/cpp/codecs/static/tools/static_codec_generator/README4
-rw-r--r--library/cpp/codecs/static/tools/static_codec_generator/static_codec_generator.cpp82
-rw-r--r--library/cpp/codecs/static/tools/static_codec_generator/ya.make17
-rw-r--r--library/cpp/codecs/static/tools/tests/canondata/result.json6
-rw-r--r--library/cpp/codecs/static/tools/tests/static_codec_tools.py18
-rw-r--r--library/cpp/codecs/static/tools/tests/ya.make20
-rw-r--r--library/cpp/codecs/static/tools/ya.make5
-rw-r--r--library/cpp/codecs/static/ut/builder_ut.cpp57
-rw-r--r--library/cpp/codecs/static/ut/static_ut.cpp27
-rw-r--r--library/cpp/codecs/static/ut/ya.make14
-rw-r--r--library/cpp/codecs/static/ya.make18
-rw-r--r--library/cpp/codecs/tls_cache.cpp4
-rw-r--r--library/cpp/codecs/tls_cache.h100
-rw-r--r--library/cpp/codecs/ut/codecs_ut.cpp1360
-rw-r--r--library/cpp/codecs/ut/float_huffman_ut.cpp237
-rw-r--r--library/cpp/codecs/ut/tls_cache_ut.cpp36
-rw-r--r--library/cpp/codecs/ut/ya.make20
-rw-r--r--library/cpp/codecs/ya.make33
-rw-r--r--library/cpp/codecs/zstd_dict_codec.cpp281
-rw-r--r--library/cpp/codecs/zstd_dict_codec.h38
-rw-r--r--library/cpp/colorizer/colors.cpp505
-rw-r--r--library/cpp/colorizer/colors.h228
-rw-r--r--library/cpp/colorizer/fwd.h11
-rw-r--r--library/cpp/colorizer/output.cpp10
-rw-r--r--library/cpp/colorizer/output.h45
-rw-r--r--library/cpp/colorizer/ut/colorizer_ut.cpp63
-rw-r--r--library/cpp/colorizer/ut/ya.make9
-rw-r--r--library/cpp/colorizer/ya.make10
-rw-r--r--library/cpp/compproto/bit.h348
-rw-r--r--library/cpp/compproto/compproto_ut.cpp543
-rw-r--r--library/cpp/compproto/compressor.h74
-rw-r--r--library/cpp/compproto/huff.h402
-rw-r--r--library/cpp/compproto/lib.cpp4
-rw-r--r--library/cpp/compproto/metainfo.h304
-rw-r--r--library/cpp/compproto/ut/ya.make15
-rw-r--r--library/cpp/compproto/ya.make13
-rw-r--r--library/cpp/comptable/comptable.cpp443
-rw-r--r--library/cpp/comptable/comptable.h75
-rw-r--r--library/cpp/comptable/usage/usage.cpp75
-rw-r--r--library/cpp/comptable/usage/ya.make13
-rw-r--r--library/cpp/comptable/ut/comptable_ut.cpp64
-rw-r--r--library/cpp/comptable/ut/ya.make9
-rw-r--r--library/cpp/comptable/ya.make13
-rw-r--r--library/cpp/containers/2d_array/2d_array.cpp1
-rw-r--r--library/cpp/containers/2d_array/2d_array.h125
-rw-r--r--library/cpp/containers/2d_array/ya.make9
-rw-r--r--library/cpp/containers/atomizer/atomizer.cpp1
-rw-r--r--library/cpp/containers/atomizer/atomizer.h200
-rw-r--r--library/cpp/containers/atomizer/ya.make13
-rw-r--r--library/cpp/containers/bitseq/bititerator.h138
-rw-r--r--library/cpp/containers/bitseq/bititerator_ut.cpp109
-rw-r--r--library/cpp/containers/bitseq/bitvector.cpp1
-rw-r--r--library/cpp/containers/bitseq/bitvector.h158
-rw-r--r--library/cpp/containers/bitseq/bitvector_ut.cpp86
-rw-r--r--library/cpp/containers/bitseq/readonly_bitvector.cpp1
-rw-r--r--library/cpp/containers/bitseq/readonly_bitvector.h76
-rw-r--r--library/cpp/containers/bitseq/traits.h49
-rw-r--r--library/cpp/containers/bitseq/ut/ya.make10
-rw-r--r--library/cpp/containers/bitseq/ya.make15
-rw-r--r--library/cpp/containers/compact_vector/compact_vector.cpp1
-rw-r--r--library/cpp/containers/compact_vector/compact_vector.h209
-rw-r--r--library/cpp/containers/compact_vector/compact_vector_ut.cpp46
-rw-r--r--library/cpp/containers/compact_vector/ut/ya.make11
-rw-r--r--library/cpp/containers/compact_vector/ya.make9
-rw-r--r--library/cpp/containers/comptrie/README.md232
-rw-r--r--library/cpp/containers/comptrie/array_with_size.h67
-rw-r--r--library/cpp/containers/comptrie/benchmark/main.cpp260
-rw-r--r--library/cpp/containers/comptrie/benchmark/ya.make14
-rw-r--r--library/cpp/containers/comptrie/chunked_helpers_trie.h218
-rw-r--r--library/cpp/containers/comptrie/comptrie.cpp8
-rw-r--r--library/cpp/containers/comptrie/comptrie.h4
-rw-r--r--library/cpp/containers/comptrie/comptrie_builder.cpp1
-rw-r--r--library/cpp/containers/comptrie/comptrie_builder.h159
-rw-r--r--library/cpp/containers/comptrie/comptrie_builder.inl1121
-rw-r--r--library/cpp/containers/comptrie/comptrie_impl.cpp39
-rw-r--r--library/cpp/containers/comptrie/comptrie_impl.h221
-rw-r--r--library/cpp/containers/comptrie/comptrie_packer.h21
-rw-r--r--library/cpp/containers/comptrie/comptrie_trie.h663
-rw-r--r--library/cpp/containers/comptrie/comptrie_ut.cpp1791
-rw-r--r--library/cpp/containers/comptrie/first_symbol_iterator.h61
-rw-r--r--library/cpp/containers/comptrie/key_selector.h29
-rw-r--r--library/cpp/containers/comptrie/leaf_skipper.h56
-rw-r--r--library/cpp/containers/comptrie/loader/loader.cpp1
-rw-r--r--library/cpp/containers/comptrie/loader/loader.h22
-rw-r--r--library/cpp/containers/comptrie/loader/loader_ut.cpp30
-rw-r--r--library/cpp/containers/comptrie/loader/ut/dummy.triebin0 -> 25 bytes
-rw-r--r--library/cpp/containers/comptrie/loader/ut/ya.make18
-rw-r--r--library/cpp/containers/comptrie/loader/ya.make15
-rw-r--r--library/cpp/containers/comptrie/make_fast_layout.cpp467
-rw-r--r--library/cpp/containers/comptrie/make_fast_layout.h20
-rw-r--r--library/cpp/containers/comptrie/minimize.cpp359
-rw-r--r--library/cpp/containers/comptrie/minimize.h29
-rw-r--r--library/cpp/containers/comptrie/node.cpp79
-rw-r--r--library/cpp/containers/comptrie/node.h80
-rw-r--r--library/cpp/containers/comptrie/opaque_trie_iterator.cpp231
-rw-r--r--library/cpp/containers/comptrie/opaque_trie_iterator.h266
-rw-r--r--library/cpp/containers/comptrie/pattern_searcher.h606
-rw-r--r--library/cpp/containers/comptrie/prefix_iterator.cpp1
-rw-r--r--library/cpp/containers/comptrie/prefix_iterator.h88
-rw-r--r--library/cpp/containers/comptrie/protopacker.h29
-rw-r--r--library/cpp/containers/comptrie/search_iterator.cpp1
-rw-r--r--library/cpp/containers/comptrie/search_iterator.h140
-rw-r--r--library/cpp/containers/comptrie/set.h40
-rw-r--r--library/cpp/containers/comptrie/ut/ya.make9
-rw-r--r--library/cpp/containers/comptrie/write_trie_backwards.cpp110
-rw-r--r--library/cpp/containers/comptrie/write_trie_backwards.h23
-rw-r--r--library/cpp/containers/comptrie/writeable_node.cpp96
-rw-r--r--library/cpp/containers/comptrie/writeable_node.h26
-rw-r--r--library/cpp/containers/comptrie/ya.make35
-rw-r--r--library/cpp/containers/disjoint_interval_tree/disjoint_interval_tree.cpp1
-rw-r--r--library/cpp/containers/disjoint_interval_tree/disjoint_interval_tree.h272
-rw-r--r--library/cpp/containers/disjoint_interval_tree/ut/disjoint_interval_tree_ut.cpp279
-rw-r--r--library/cpp/containers/disjoint_interval_tree/ut/ya.make12
-rw-r--r--library/cpp/containers/disjoint_interval_tree/ya.make10
-rw-r--r--library/cpp/containers/flat_hash/benchmark/flat_hash_benchmark.cpp180
-rw-r--r--library/cpp/containers/flat_hash/benchmark/ya.make13
-rw-r--r--library/cpp/containers/flat_hash/flat_hash.cpp1
-rw-r--r--library/cpp/containers/flat_hash/flat_hash.h120
-rw-r--r--library/cpp/containers/flat_hash/lib/concepts/concepts.cpp4
-rw-r--r--library/cpp/containers/flat_hash/lib/concepts/container.h66
-rw-r--r--library/cpp/containers/flat_hash/lib/concepts/iterator.h20
-rw-r--r--library/cpp/containers/flat_hash/lib/concepts/size_fitter.h34
-rw-r--r--library/cpp/containers/flat_hash/lib/concepts/value_marker.h34
-rw-r--r--library/cpp/containers/flat_hash/lib/concepts/ya.make9
-rw-r--r--library/cpp/containers/flat_hash/lib/containers.cpp1
-rw-r--r--library/cpp/containers/flat_hash/lib/containers.h314
-rw-r--r--library/cpp/containers/flat_hash/lib/expanders.cpp1
-rw-r--r--library/cpp/containers/flat_hash/lib/expanders.h25
-rw-r--r--library/cpp/containers/flat_hash/lib/fuzz/dense_map_fuzz/fuzz.cpp60
-rw-r--r--library/cpp/containers/flat_hash/lib/fuzz/dense_map_fuzz/ya.make19
-rw-r--r--library/cpp/containers/flat_hash/lib/fuzz/flat_map_fuzz/fuzz.cpp53
-rw-r--r--library/cpp/containers/flat_hash/lib/fuzz/flat_map_fuzz/ya.make19
-rw-r--r--library/cpp/containers/flat_hash/lib/fuzz/fuzz_common/fuzz_common.cpp1
-rw-r--r--library/cpp/containers/flat_hash/lib/fuzz/fuzz_common/fuzz_common.h223
-rw-r--r--library/cpp/containers/flat_hash/lib/fuzz/fuzz_common/ya.make11
-rw-r--r--library/cpp/containers/flat_hash/lib/fuzz/ya.make7
-rw-r--r--library/cpp/containers/flat_hash/lib/iterator.cpp1
-rw-r--r--library/cpp/containers/flat_hash/lib/iterator.h99
-rw-r--r--library/cpp/containers/flat_hash/lib/map.cpp1
-rw-r--r--library/cpp/containers/flat_hash/lib/map.h233
-rw-r--r--library/cpp/containers/flat_hash/lib/probings.cpp1
-rw-r--r--library/cpp/containers/flat_hash/lib/probings.h45
-rw-r--r--library/cpp/containers/flat_hash/lib/set.cpp1
-rw-r--r--library/cpp/containers/flat_hash/lib/set.h147
-rw-r--r--library/cpp/containers/flat_hash/lib/size_fitters.cpp1
-rw-r--r--library/cpp/containers/flat_hash/lib/size_fitters.h47
-rw-r--r--library/cpp/containers/flat_hash/lib/table.cpp1
-rw-r--r--library/cpp/containers/flat_hash/lib/table.h314
-rw-r--r--library/cpp/containers/flat_hash/lib/ut/containers_ut.cpp410
-rw-r--r--library/cpp/containers/flat_hash/lib/ut/iterator_ut.cpp85
-rw-r--r--library/cpp/containers/flat_hash/lib/ut/probings_ut.cpp34
-rw-r--r--library/cpp/containers/flat_hash/lib/ut/size_fitters_ut.cpp51
-rw-r--r--library/cpp/containers/flat_hash/lib/ut/table_ut.cpp411
-rw-r--r--library/cpp/containers/flat_hash/lib/ut/ya.make17
-rw-r--r--library/cpp/containers/flat_hash/lib/value_markers.cpp0
-rw-r--r--library/cpp/containers/flat_hash/lib/value_markers.h130
-rw-r--r--library/cpp/containers/flat_hash/lib/ya.make17
-rw-r--r--library/cpp/containers/flat_hash/ut/flat_hash_ut.cpp272
-rw-r--r--library/cpp/containers/flat_hash/ut/ya.make13
-rw-r--r--library/cpp/containers/flat_hash/ya.make13
-rw-r--r--library/cpp/containers/intrusive_avl_tree/avltree.cpp1
-rw-r--r--library/cpp/containers/intrusive_avl_tree/avltree.h754
-rw-r--r--library/cpp/containers/intrusive_avl_tree/ut/avltree_ut.cpp103
-rw-r--r--library/cpp/containers/intrusive_avl_tree/ut/ya.make12
-rw-r--r--library/cpp/containers/intrusive_avl_tree/ya.make12
-rw-r--r--library/cpp/containers/intrusive_rb_tree/fuzz/rb_tree_fuzzing.cpp65
-rw-r--r--library/cpp/containers/intrusive_rb_tree/fuzz/ya.make20
-rw-r--r--library/cpp/containers/intrusive_rb_tree/rb_tree.cpp1
-rw-r--r--library/cpp/containers/intrusive_rb_tree/rb_tree.h818
-rw-r--r--library/cpp/containers/intrusive_rb_tree/rb_tree_ut.cpp298
-rw-r--r--library/cpp/containers/intrusive_rb_tree/ut/ya.make12
-rw-r--r--library/cpp/containers/intrusive_rb_tree/ya.make12
-rw-r--r--library/cpp/containers/paged_vector/paged_vector.cpp1
-rw-r--r--library/cpp/containers/paged_vector/paged_vector.h432
-rw-r--r--library/cpp/containers/paged_vector/ut/paged_vector_ut.cpp378
-rw-r--r--library/cpp/containers/paged_vector/ut/ya.make13
-rw-r--r--library/cpp/containers/paged_vector/ya.make9
-rw-r--r--library/cpp/containers/ring_buffer/ring_buffer.cpp1
-rw-r--r--library/cpp/containers/ring_buffer/ring_buffer.h81
-rw-r--r--library/cpp/containers/ring_buffer/ya.make9
-rw-r--r--library/cpp/containers/sorted_vector/sorted_vector.cpp1
-rw-r--r--library/cpp/containers/sorted_vector/sorted_vector.h492
-rw-r--r--library/cpp/containers/sorted_vector/sorted_vector_ut.cpp24
-rw-r--r--library/cpp/containers/sorted_vector/ut/ya.make10
-rw-r--r--library/cpp/containers/sorted_vector/ya.make11
-rw-r--r--library/cpp/containers/stack_array/range_ops.cpp1
-rw-r--r--library/cpp/containers/stack_array/range_ops.h52
-rw-r--r--library/cpp/containers/stack_array/stack_array.cpp1
-rw-r--r--library/cpp/containers/stack_array/stack_array.h40
-rw-r--r--library/cpp/containers/stack_array/ut/tests_ut.cpp94
-rw-r--r--library/cpp/containers/stack_array/ut/ya.make9
-rw-r--r--library/cpp/containers/stack_array/ya.make10
-rw-r--r--library/cpp/containers/stack_vector/stack_vec.cpp1
-rw-r--r--library/cpp/containers/stack_vector/stack_vec.h212
-rw-r--r--library/cpp/containers/stack_vector/stack_vec_ut.cpp144
-rw-r--r--library/cpp/containers/stack_vector/ut/ya.make11
-rw-r--r--library/cpp/containers/stack_vector/ya.make11
-rw-r--r--library/cpp/containers/str_map/str_map.cpp1
-rw-r--r--library/cpp/containers/str_map/str_map.h205
-rw-r--r--library/cpp/containers/str_map/ya.make9
-rw-r--r--library/cpp/containers/top_keeper/README.md26
-rw-r--r--library/cpp/containers/top_keeper/top_keeper.cpp1
-rw-r--r--library/cpp/containers/top_keeper/top_keeper.h256
-rw-r--r--library/cpp/containers/top_keeper/top_keeper/README.md26
-rw-r--r--library/cpp/containers/top_keeper/top_keeper/top_keeper.cpp1
-rw-r--r--library/cpp/containers/top_keeper/top_keeper/top_keeper.h256
-rw-r--r--library/cpp/containers/top_keeper/top_keeper/ut/top_keeper_ut.cpp222
-rw-r--r--library/cpp/containers/top_keeper/top_keeper/ut/ya.make12
-rw-r--r--library/cpp/containers/top_keeper/top_keeper/ya.make9
-rw-r--r--library/cpp/containers/top_keeper/ut/top_keeper_ut.cpp222
-rw-r--r--library/cpp/containers/top_keeper/ut/ya.make12
-rw-r--r--library/cpp/containers/top_keeper/ya.make13
-rw-r--r--library/cpp/containers/ya.make71
-rw-r--r--library/cpp/coroutine/engine/callbacks.h18
-rw-r--r--library/cpp/coroutine/engine/condvar.h38
-rw-r--r--library/cpp/coroutine/engine/cont_poller.cpp70
-rw-r--r--library/cpp/coroutine/engine/cont_poller.h245
-rw-r--r--library/cpp/coroutine/engine/coroutine_ut.cpp1007
-rw-r--r--library/cpp/coroutine/engine/custom_time.h10
-rw-r--r--library/cpp/coroutine/engine/events.h148
-rw-r--r--library/cpp/coroutine/engine/helper.cpp37
-rw-r--r--library/cpp/coroutine/engine/helper.h15
-rw-r--r--library/cpp/coroutine/engine/impl.cpp374
-rw-r--r--library/cpp/coroutine/engine/impl.h313
-rw-r--r--library/cpp/coroutine/engine/iostatus.cpp1
-rw-r--r--library/cpp/coroutine/engine/iostatus.h91
-rw-r--r--library/cpp/coroutine/engine/mutex.h49
-rw-r--r--library/cpp/coroutine/engine/network.cpp325
-rw-r--r--library/cpp/coroutine/engine/network.h55
-rw-r--r--library/cpp/coroutine/engine/poller.cpp390
-rw-r--r--library/cpp/coroutine/engine/poller.h50
-rw-r--r--library/cpp/coroutine/engine/sockmap.h24
-rw-r--r--library/cpp/coroutine/engine/sockpool.cpp58
-rw-r--r--library/cpp/coroutine/engine/sockpool.h253
-rw-r--r--library/cpp/coroutine/engine/stack/benchmark/alloc_bm.cpp316
-rw-r--r--library/cpp/coroutine/engine/stack/benchmark/ya.make13
-rw-r--r--library/cpp/coroutine/engine/stack/stack.cpp67
-rw-r--r--library/cpp/coroutine/engine/stack/stack.h77
-rw-r--r--library/cpp/coroutine/engine/stack/stack_allocator.cpp26
-rw-r--r--library/cpp/coroutine/engine/stack/stack_allocator.h52
-rw-r--r--library/cpp/coroutine/engine/stack/stack_allocator.inl138
-rw-r--r--library/cpp/coroutine/engine/stack/stack_common.h35
-rw-r--r--library/cpp/coroutine/engine/stack/stack_guards.cpp17
-rw-r--r--library/cpp/coroutine/engine/stack/stack_guards.h123
-rw-r--r--library/cpp/coroutine/engine/stack/stack_pool.h54
-rw-r--r--library/cpp/coroutine/engine/stack/stack_pool.inl132
-rw-r--r--library/cpp/coroutine/engine/stack/stack_storage.cpp46
-rw-r--r--library/cpp/coroutine/engine/stack/stack_storage.h60
-rw-r--r--library/cpp/coroutine/engine/stack/stack_utils.cpp84
-rw-r--r--library/cpp/coroutine/engine/stack/stack_utils.h27
-rw-r--r--library/cpp/coroutine/engine/stack/ut/stack_allocator_ut.cpp115
-rw-r--r--library/cpp/coroutine/engine/stack/ut/stack_guards_ut.cpp158
-rw-r--r--library/cpp/coroutine/engine/stack/ut/stack_pool_ut.cpp70
-rw-r--r--library/cpp/coroutine/engine/stack/ut/stack_ut.cpp60
-rw-r--r--library/cpp/coroutine/engine/stack/ut/stack_utils_ut.cpp73
-rw-r--r--library/cpp/coroutine/engine/stack/ut/ya.make17
-rw-r--r--library/cpp/coroutine/engine/trampoline.cpp50
-rw-r--r--library/cpp/coroutine/engine/trampoline.h60
-rw-r--r--library/cpp/coroutine/engine/ya.make36
-rw-r--r--library/cpp/coroutine/listener/listen.cpp354
-rw-r--r--library/cpp/coroutine/listener/listen.h125
-rw-r--r--library/cpp/coroutine/listener/ya.make13
-rw-r--r--library/cpp/coroutine/ya.make11
-rw-r--r--library/cpp/cppparser/README.md3
-rw-r--r--library/cpp/cppparser/parser.cpp739
-rw-r--r--library/cpp/cppparser/parser.h99
-rw-r--r--library/cpp/cppparser/ya.make9
-rw-r--r--library/cpp/cpuid_check/README.md13
-rw-r--r--library/cpp/cpuid_check/cpu_id_check.cpp64
-rw-r--r--library/cpp/cpuid_check/ya.make7
-rw-r--r--library/cpp/dbg_output/DONT_COMMIT.h16
-rw-r--r--library/cpp/dbg_output/auto.h22
-rw-r--r--library/cpp/dbg_output/colorscheme.h100
-rw-r--r--library/cpp/dbg_output/dump.cpp1
-rw-r--r--library/cpp/dbg_output/dump.h106
-rw-r--r--library/cpp/dbg_output/dumpers.cpp1
-rw-r--r--library/cpp/dbg_output/dumpers.h173
-rw-r--r--library/cpp/dbg_output/engine.cpp33
-rw-r--r--library/cpp/dbg_output/engine.h180
-rw-r--r--library/cpp/dbg_output/ut/dbg_output_ut.cpp106
-rw-r--r--library/cpp/dbg_output/ut/ya.make9
-rw-r--r--library/cpp/dbg_output/ya.make15
-rw-r--r--library/cpp/deprecated/accessors/README.md5
-rw-r--r--library/cpp/deprecated/accessors/accessors.cpp1
-rw-r--r--library/cpp/deprecated/accessors/accessors.h83
-rw-r--r--library/cpp/deprecated/accessors/accessors_impl.cpp1
-rw-r--r--library/cpp/deprecated/accessors/accessors_impl.h420
-rw-r--r--library/cpp/deprecated/accessors/accessors_ut.cpp92
-rw-r--r--library/cpp/deprecated/accessors/memory_traits.cpp1
-rw-r--r--library/cpp/deprecated/accessors/memory_traits.h168
-rw-r--r--library/cpp/deprecated/accessors/ut/ya.make9
-rw-r--r--library/cpp/deprecated/accessors/ya.make11
-rw-r--r--library/cpp/deprecated/enum_codegen/README.md3
-rw-r--r--library/cpp/deprecated/enum_codegen/enum_codegen.cpp1
-rw-r--r--library/cpp/deprecated/enum_codegen/enum_codegen.h33
-rw-r--r--library/cpp/deprecated/enum_codegen/enum_codegen_ut.cpp40
-rw-r--r--library/cpp/deprecated/enum_codegen/ut/ya.make15
-rw-r--r--library/cpp/deprecated/enum_codegen/ya.make9
-rw-r--r--library/cpp/deprecated/kmp/kmp.cpp21
-rw-r--r--library/cpp/deprecated/kmp/kmp.h108
-rw-r--r--library/cpp/deprecated/kmp/kmp_ut.cpp80
-rw-r--r--library/cpp/deprecated/kmp/ut/ya.make9
-rw-r--r--library/cpp/deprecated/kmp/ya.make10
-rw-r--r--library/cpp/deprecated/mapped_file/mapped_file.cpp64
-rw-r--r--library/cpp/deprecated/mapped_file/mapped_file.h72
-rw-r--r--library/cpp/deprecated/mapped_file/ut/mapped_file_ut.cpp18
-rw-r--r--library/cpp/deprecated/mapped_file/ya.make9
-rw-r--r--library/cpp/deprecated/split/delim_string_iter.cpp45
-rw-r--r--library/cpp/deprecated/split/delim_string_iter.h185
-rw-r--r--library/cpp/deprecated/split/delim_string_iter_ut.cpp99
-rw-r--r--library/cpp/deprecated/split/split_iterator.cpp318
-rw-r--r--library/cpp/deprecated/split/split_iterator.h317
-rw-r--r--library/cpp/deprecated/split/split_iterator_ut.cpp152
-rw-r--r--library/cpp/deprecated/split/ya.make14
-rw-r--r--library/cpp/deprecated/ya.make49
-rw-r--r--library/cpp/diff/README.md1
-rw-r--r--library/cpp/diff/diff.cpp87
-rw-r--r--library/cpp/diff/diff.h112
-rw-r--r--library/cpp/diff/diff_ut.cpp197
-rw-r--r--library/cpp/diff/ut/ya.make15
-rw-r--r--library/cpp/diff/ya.make14
-rw-r--r--library/cpp/digest/argonish/AUTHORS3
-rw-r--r--library/cpp/digest/argonish/CONTRIBUTING.md35
-rw-r--r--library/cpp/digest/argonish/LICENSE22
-rw-r--r--library/cpp/digest/argonish/README.md74
-rw-r--r--library/cpp/digest/argonish/argon2.h147
-rw-r--r--library/cpp/digest/argonish/benchmark/mbench.cpp64
-rw-r--r--library/cpp/digest/argonish/benchmark/ya.make13
-rw-r--r--library/cpp/digest/argonish/blake2b.h78
-rw-r--r--library/cpp/digest/argonish/common.h18
-rw-r--r--library/cpp/digest/argonish/factory/factory.cpp222
-rw-r--r--library/cpp/digest/argonish/internal/argon2/argon2_avx2.h117
-rw-r--r--library/cpp/digest/argonish/internal/argon2/argon2_base.h388
-rw-r--r--library/cpp/digest/argonish/internal/argon2/argon2_ref.h88
-rw-r--r--library/cpp/digest/argonish/internal/argon2/argon2_sse2.h101
-rw-r--r--library/cpp/digest/argonish/internal/argon2/argon2_sse41.h101
-rw-r--r--library/cpp/digest/argonish/internal/argon2/argon2_ssse3.h102
-rw-r--r--library/cpp/digest/argonish/internal/argon2/ya.make10
-rw-r--r--library/cpp/digest/argonish/internal/blake2b/blake2b.h187
-rw-r--r--library/cpp/digest/argonish/internal/blake2b/blake2b_avx2.h104
-rw-r--r--library/cpp/digest/argonish/internal/blake2b/blake2b_ref.h83
-rw-r--r--library/cpp/digest/argonish/internal/blake2b/blake2b_sse2.h163
-rw-r--r--library/cpp/digest/argonish/internal/blake2b/blake2b_sse41.h172
-rw-r--r--library/cpp/digest/argonish/internal/blake2b/blake2b_ssse3.h171
-rw-r--r--library/cpp/digest/argonish/internal/blake2b/load_sse41.h301
-rw-r--r--library/cpp/digest/argonish/internal/blake2b/ya.make9
-rw-r--r--library/cpp/digest/argonish/internal/blamka/blamka_avx2.h136
-rw-r--r--library/cpp/digest/argonish/internal/blamka/blamka_sse2.h95
-rw-r--r--library/cpp/digest/argonish/internal/blamka/blamka_ssse3.h103
-rw-r--r--library/cpp/digest/argonish/internal/blamka/ya.make9
-rw-r--r--library/cpp/digest/argonish/internal/proxies/avx2/proxy_avx2.cpp18
-rw-r--r--library/cpp/digest/argonish/internal/proxies/avx2/proxy_avx2.h11
-rw-r--r--library/cpp/digest/argonish/internal/proxies/avx2/ya.make18
-rw-r--r--library/cpp/digest/argonish/internal/proxies/macro/proxy_macros.h194
-rw-r--r--library/cpp/digest/argonish/internal/proxies/macro/ya.make5
-rw-r--r--library/cpp/digest/argonish/internal/proxies/ref/proxy_ref.cpp20
-rw-r--r--library/cpp/digest/argonish/internal/proxies/ref/proxy_ref.h11
-rw-r--r--library/cpp/digest/argonish/internal/proxies/ref/ya.make17
-rw-r--r--library/cpp/digest/argonish/internal/proxies/sse2/proxy_sse2.cpp18
-rw-r--r--library/cpp/digest/argonish/internal/proxies/sse2/proxy_sse2.h11
-rw-r--r--library/cpp/digest/argonish/internal/proxies/sse2/ya.make18
-rw-r--r--library/cpp/digest/argonish/internal/proxies/sse41/proxy_sse41.cpp18
-rw-r--r--library/cpp/digest/argonish/internal/proxies/sse41/proxy_sse41.h11
-rw-r--r--library/cpp/digest/argonish/internal/proxies/sse41/ya.make18
-rw-r--r--library/cpp/digest/argonish/internal/proxies/ssse3/proxy_ssse3.cpp18
-rw-r--r--library/cpp/digest/argonish/internal/proxies/ssse3/proxy_ssse3.h11
-rw-r--r--library/cpp/digest/argonish/internal/proxies/ssse3/ya.make19
-rw-r--r--library/cpp/digest/argonish/internal/proxies/ya.make8
-rw-r--r--library/cpp/digest/argonish/internal/rotations/rotations_avx2.h30
-rw-r--r--library/cpp/digest/argonish/internal/rotations/rotations_ref.h7
-rw-r--r--library/cpp/digest/argonish/internal/rotations/rotations_sse2.h27
-rw-r--r--library/cpp/digest/argonish/internal/rotations/rotations_ssse3.h28
-rw-r--r--library/cpp/digest/argonish/internal/rotations/ya.make5
-rw-r--r--library/cpp/digest/argonish/internal/ya.make7
-rw-r--r--library/cpp/digest/argonish/ut/ut.cpp549
-rw-r--r--library/cpp/digest/argonish/ut/ya.make13
-rw-r--r--library/cpp/digest/argonish/ut_fat/ut.cpp441
-rw-r--r--library/cpp/digest/argonish/ut_fat/ya.make21
-rw-r--r--library/cpp/digest/argonish/ya.make25
-rw-r--r--library/cpp/digest/crc32c/crc32c.cpp40
-rw-r--r--library/cpp/digest/crc32c/crc32c.h9
-rw-r--r--library/cpp/digest/crc32c/crc32c_ut.cpp23
-rw-r--r--library/cpp/digest/crc32c/ut/ya.make9
-rw-r--r--library/cpp/digest/crc32c/ya.make22
-rw-r--r--library/cpp/digest/lower_case/hash_ops.cpp23
-rw-r--r--library/cpp/digest/lower_case/hash_ops.h13
-rw-r--r--library/cpp/digest/lower_case/hash_ops_ut.cpp36
-rw-r--r--library/cpp/digest/lower_case/lchash.cpp1
-rw-r--r--library/cpp/digest/lower_case/lchash.h18
-rw-r--r--library/cpp/digest/lower_case/lchash_ut.cpp21
-rw-r--r--library/cpp/digest/lower_case/lciter.cpp1
-rw-r--r--library/cpp/digest/lower_case/lciter.h42
-rw-r--r--library/cpp/digest/lower_case/ut/ya.make13
-rw-r--r--library/cpp/digest/lower_case/ya.make14
-rw-r--r--library/cpp/digest/md5/bench/main.cpp20
-rw-r--r--library/cpp/digest/md5/bench/ya.make16
-rw-r--r--library/cpp/digest/md5/md5.cpp268
-rw-r--r--library/cpp/digest/md5/md5.h79
-rw-r--r--library/cpp/digest/md5/md5_medium_ut.cpp25
-rw-r--r--library/cpp/digest/md5/md5_ut.cpp66
-rw-r--r--library/cpp/digest/md5/medium_ut/ya.make18
-rw-r--r--library/cpp/digest/md5/ut/ya.make12
-rw-r--r--library/cpp/digest/md5/ya.make17
-rw-r--r--library/cpp/digest/old_crc/crc.cpp268
-rw-r--r--library/cpp/digest/old_crc/crc.h90
-rw-r--r--library/cpp/digest/old_crc/crc_ut.cpp74
-rw-r--r--library/cpp/digest/old_crc/gencrc/main.cpp56
-rw-r--r--library/cpp/digest/old_crc/gencrc/ya.make9
-rw-r--r--library/cpp/digest/old_crc/ut/ya.make12
-rw-r--r--library/cpp/digest/old_crc/ya.make17
-rw-r--r--library/cpp/digest/sfh/sfh.cpp1
-rw-r--r--library/cpp/digest/sfh/sfh.h51
-rw-r--r--library/cpp/digest/sfh/sfh_ut.cpp40
-rw-r--r--library/cpp/digest/sfh/ut/ya.make12
-rw-r--r--library/cpp/digest/sfh/ya.make12
-rw-r--r--library/cpp/digest/ya.make23
-rw-r--r--library/cpp/dns/README.md9
-rw-r--r--library/cpp/dns/cache.cpp198
-rw-r--r--library/cpp/dns/cache.h45
-rw-r--r--library/cpp/dns/magic.cpp29
-rw-r--r--library/cpp/dns/magic.h17
-rw-r--r--library/cpp/dns/thread.cpp133
-rw-r--r--library/cpp/dns/thread.h12
-rw-r--r--library/cpp/dns/ut/dns_ut.cpp25
-rw-r--r--library/cpp/dns/ut/ya.make16
-rw-r--r--library/cpp/dns/ya.make11
-rw-r--r--library/cpp/enumbitset/README.md2
-rw-r--r--library/cpp/enumbitset/enumbitset.cpp1
-rw-r--r--library/cpp/enumbitset/enumbitset.h515
-rw-r--r--library/cpp/enumbitset/enumbitset_ut.cpp83
-rw-r--r--library/cpp/enumbitset/ut/ya.make9
-rw-r--r--library/cpp/enumbitset/ya.make9
-rw-r--r--library/cpp/execprofile/annotate_profile.pl360
-rw-r--r--library/cpp/execprofile/autostart/start.cpp15
-rw-r--r--library/cpp/execprofile/autostart/ya.make13
-rw-r--r--library/cpp/execprofile/profile.cpp417
-rw-r--r--library/cpp/execprofile/profile.h17
-rw-r--r--library/cpp/execprofile/ya.make9
-rw-r--r--library/cpp/getopt/last_getopt.h3
-rw-r--r--library/cpp/getopt/last_getopt_demo/demo.cpp242
-rw-r--r--library/cpp/getopt/last_getopt_demo/ya.make13
-rw-r--r--library/cpp/getopt/last_getopt_support.h3
-rw-r--r--library/cpp/getopt/modchooser.h3
-rw-r--r--library/cpp/getopt/opt.h3
-rw-r--r--library/cpp/getopt/opt2.h3
-rw-r--r--library/cpp/getopt/posix_getopt.h3
-rw-r--r--library/cpp/getopt/print.cpp40
-rw-r--r--library/cpp/getopt/small/completer.cpp367
-rw-r--r--library/cpp/getopt/small/completer.h306
-rw-r--r--library/cpp/getopt/small/completer_command.cpp165
-rw-r--r--library/cpp/getopt/small/completer_command.h11
-rw-r--r--library/cpp/getopt/small/completion_generator.cpp791
-rw-r--r--library/cpp/getopt/small/completion_generator.h69
-rw-r--r--library/cpp/getopt/small/formatted_output.cpp36
-rw-r--r--library/cpp/getopt/small/formatted_output.h32
-rw-r--r--library/cpp/getopt/small/last_getopt.cpp9
-rw-r--r--library/cpp/getopt/small/last_getopt.h132
-rw-r--r--library/cpp/getopt/small/last_getopt_easy_setup.cpp47
-rw-r--r--library/cpp/getopt/small/last_getopt_easy_setup.h51
-rw-r--r--library/cpp/getopt/small/last_getopt_handlers.h24
-rw-r--r--library/cpp/getopt/small/last_getopt_opt.cpp113
-rw-r--r--library/cpp/getopt/small/last_getopt_opt.h812
-rw-r--r--library/cpp/getopt/small/last_getopt_opts.cpp519
-rw-r--r--library/cpp/getopt/small/last_getopt_opts.h643
-rw-r--r--library/cpp/getopt/small/last_getopt_parse_result.cpp160
-rw-r--r--library/cpp/getopt/small/last_getopt_parse_result.h321
-rw-r--r--library/cpp/getopt/small/last_getopt_parser.cpp389
-rw-r--r--library/cpp/getopt/small/last_getopt_parser.h154
-rw-r--r--library/cpp/getopt/small/last_getopt_support.h178
-rw-r--r--library/cpp/getopt/small/modchooser.cpp372
-rw-r--r--library/cpp/getopt/small/modchooser.h215
-rw-r--r--library/cpp/getopt/small/opt.cpp119
-rw-r--r--library/cpp/getopt/small/opt.h142
-rw-r--r--library/cpp/getopt/small/opt2.cpp384
-rw-r--r--library/cpp/getopt/small/opt2.h137
-rw-r--r--library/cpp/getopt/small/posix_getopt.cpp77
-rw-r--r--library/cpp/getopt/small/posix_getopt.h32
-rw-r--r--library/cpp/getopt/small/wrap.cpp99
-rw-r--r--library/cpp/getopt/small/wrap.h16
-rw-r--r--library/cpp/getopt/small/ya.make28
-rw-r--r--library/cpp/getopt/small/ygetopt.cpp108
-rw-r--r--library/cpp/getopt/small/ygetopt.h72
-rw-r--r--library/cpp/getopt/ut/last_getopt_ut.cpp794
-rw-r--r--library/cpp/getopt/ut/modchooser_ut.cpp71
-rw-r--r--library/cpp/getopt/ut/opt2_ut.cpp63
-rw-r--r--library/cpp/getopt/ut/opt_ut.cpp52
-rw-r--r--library/cpp/getopt/ut/posix_getopt_ut.cpp119
-rw-r--r--library/cpp/getopt/ut/wrap.cpp96
-rw-r--r--library/cpp/getopt/ut/ya.make15
-rw-r--r--library/cpp/getopt/ut/ygetopt_ut.cpp45
-rw-r--r--library/cpp/getopt/ya.make15
-rw-r--r--library/cpp/getopt/ygetopt.h3
-rw-r--r--library/cpp/grpc/client/grpc_client_low.cpp586
-rw-r--r--library/cpp/grpc/client/grpc_client_low.h1399
-rw-r--r--library/cpp/grpc/client/grpc_common.h84
-rw-r--r--library/cpp/grpc/client/ut/grpc_client_low_ut.cpp61
-rw-r--r--library/cpp/grpc/client/ut/ya.make11
-rw-r--r--library/cpp/grpc/client/ya.make20
-rw-r--r--library/cpp/grpc/server/actors/logger.cpp45
-rw-r--r--library/cpp/grpc/server/actors/logger.h11
-rw-r--r--library/cpp/grpc/server/actors/ya.make13
-rw-r--r--library/cpp/grpc/server/event_callback.cpp1
-rw-r--r--library/cpp/grpc/server/event_callback.h80
-rw-r--r--library/cpp/grpc/server/grpc_async_ctx_base.h94
-rw-r--r--library/cpp/grpc/server/grpc_counters.cpp45
-rw-r--r--library/cpp/grpc/server/grpc_counters.h136
-rw-r--r--library/cpp/grpc/server/grpc_request.cpp59
-rw-r--r--library/cpp/grpc/server/grpc_request.h543
-rw-r--r--library/cpp/grpc/server/grpc_request_base.h116
-rw-r--r--library/cpp/grpc/server/grpc_response.h90
-rw-r--r--library/cpp/grpc/server/grpc_server.cpp240
-rw-r--r--library/cpp/grpc/server/grpc_server.h356
-rw-r--r--library/cpp/grpc/server/logger.h43
-rw-r--r--library/cpp/grpc/server/ut/grpc_response_ut.cpp88
-rw-r--r--library/cpp/grpc/server/ut/stream_adaptor_ut.cpp121
-rw-r--r--library/cpp/grpc/server/ut/ya.make21
-rw-r--r--library/cpp/grpc/server/ya.make25
-rw-r--r--library/cpp/grpc/ya.make5
-rw-r--r--library/cpp/histogram/adaptive/README.md1
-rw-r--r--library/cpp/histogram/adaptive/adaptive_histogram.cpp637
-rw-r--r--library/cpp/histogram/adaptive/adaptive_histogram.h131
-rw-r--r--library/cpp/histogram/adaptive/auto_histogram.h148
-rw-r--r--library/cpp/histogram/adaptive/block_histogram.cpp593
-rw-r--r--library/cpp/histogram/adaptive/block_histogram.h148
-rw-r--r--library/cpp/histogram/adaptive/common.cpp19
-rw-r--r--library/cpp/histogram/adaptive/common.h12
-rw-r--r--library/cpp/histogram/adaptive/fixed_bin_histogram.cpp538
-rw-r--r--library/cpp/histogram/adaptive/fixed_bin_histogram.h91
-rw-r--r--library/cpp/histogram/adaptive/histogram.h66
-rw-r--r--library/cpp/histogram/adaptive/merger.h68
-rw-r--r--library/cpp/histogram/adaptive/multi_histogram.h143
-rw-r--r--library/cpp/histogram/adaptive/protos/histo.proto36
-rw-r--r--library/cpp/histogram/adaptive/protos/python/ya.make3
-rw-r--r--library/cpp/histogram/adaptive/protos/ya.make13
-rw-r--r--library/cpp/histogram/adaptive/ya.make20
-rw-r--r--library/cpp/histogram/ya.make9
-rw-r--r--library/cpp/html/escape/escape.cpp66
-rw-r--r--library/cpp/html/escape/escape.h9
-rw-r--r--library/cpp/html/escape/ut/escape_ut.cpp16
-rw-r--r--library/cpp/html/escape/ut/ya.make13
-rw-r--r--library/cpp/html/escape/ya.make9
-rw-r--r--library/cpp/html/pcdata/pcdata.cpp81
-rw-r--r--library/cpp/html/pcdata/pcdata.h10
-rw-r--r--library/cpp/html/pcdata/pcdata_ut.cpp48
-rw-r--r--library/cpp/html/pcdata/ut/ya.make9
-rw-r--r--library/cpp/html/pcdata/ya.make10
-rw-r--r--library/cpp/html/ya.make32
-rw-r--r--library/cpp/http/fetch/exthttpcodes.cpp266
-rw-r--r--library/cpp/http/fetch/exthttpcodes.h141
-rw-r--r--library/cpp/http/fetch/http_digest.cpp206
-rw-r--r--library/cpp/http/fetch/http_digest.h47
-rw-r--r--library/cpp/http/fetch/http_socket.cpp206
-rw-r--r--library/cpp/http/fetch/httpagent.h316
-rw-r--r--library/cpp/http/fetch/httpfetcher.h171
-rw-r--r--library/cpp/http/fetch/httpfsm.h104
-rw-r--r--library/cpp/http/fetch/httpfsm.rl6684
-rw-r--r--library/cpp/http/fetch/httpfsm_ut.cpp591
-rw-r--r--library/cpp/http/fetch/httpheader.cpp7
-rw-r--r--library/cpp/http/fetch/httpheader.h287
-rw-r--r--library/cpp/http/fetch/httpload.cpp373
-rw-r--r--library/cpp/http/fetch/httpload.h307
-rw-r--r--library/cpp/http/fetch/httpparser.h372
-rw-r--r--library/cpp/http/fetch/httpparser_ut.cpp231
-rw-r--r--library/cpp/http/fetch/httpzreader.h295
-rw-r--r--library/cpp/http/fetch/library-htfetch_ut_hreflang_in.h155
-rw-r--r--library/cpp/http/fetch/library-htfetch_ut_hreflang_out.h3
-rw-r--r--library/cpp/http/fetch/sockhandler.h130
-rw-r--r--library/cpp/http/fetch/ut/ya.make12
-rw-r--r--library/cpp/http/fetch/ya.make38
-rw-r--r--library/cpp/http/io/chunk.cpp246
-rw-r--r--library/cpp/http/io/chunk.h47
-rw-r--r--library/cpp/http/io/chunk_ut.cpp105
-rw-r--r--library/cpp/http/io/compression.cpp66
-rw-r--r--library/cpp/http/io/compression.h72
-rw-r--r--library/cpp/http/io/compression_ut.cpp60
-rw-r--r--library/cpp/http/io/fuzz/main.cpp15
-rw-r--r--library/cpp/http/io/fuzz/ya.make18
-rw-r--r--library/cpp/http/io/headers.cpp108
-rw-r--r--library/cpp/http/io/headers.h125
-rw-r--r--library/cpp/http/io/headers_ut.cpp176
-rw-r--r--library/cpp/http/io/list_codings/main.cpp8
-rw-r--r--library/cpp/http/io/list_codings/ya.make13
-rw-r--r--library/cpp/http/io/stream.cpp1005
-rw-r--r--library/cpp/http/io/stream.h178
-rw-r--r--library/cpp/http/io/stream_ut.cpp732
-rw-r--r--library/cpp/http/io/stream_ut_medium.cpp54
-rw-r--r--library/cpp/http/io/ut/medium/ya.make11
-rw-r--r--library/cpp/http/io/ut/ya.make16
-rw-r--r--library/cpp/http/io/ya.make22
-rw-r--r--library/cpp/http/misc/http_headers.h72
-rw-r--r--library/cpp/http/misc/httpcodes.cpp141
-rw-r--r--library/cpp/http/misc/httpcodes.h94
-rw-r--r--library/cpp/http/misc/httpdate.cpp83
-rw-r--r--library/cpp/http/misc/httpdate.h21
-rw-r--r--library/cpp/http/misc/httpdate_ut.cpp15
-rw-r--r--library/cpp/http/misc/httpreqdata.cpp196
-rw-r--r--library/cpp/http/misc/httpreqdata.h125
-rw-r--r--library/cpp/http/misc/httpreqdata_ut.cpp154
-rw-r--r--library/cpp/http/misc/parsed_request.cpp32
-rw-r--r--library/cpp/http/misc/parsed_request.h26
-rw-r--r--library/cpp/http/misc/parsed_request_ut.cpp28
-rw-r--r--library/cpp/http/misc/ut/ya.make11
-rw-r--r--library/cpp/http/misc/ya.make24
-rw-r--r--library/cpp/http/server/conn.cpp69
-rw-r--r--library/cpp/http/server/conn.h37
-rw-r--r--library/cpp/http/server/http.cpp843
-rw-r--r--library/cpp/http/server/http.h176
-rw-r--r--library/cpp/http/server/http_ex.cpp107
-rw-r--r--library/cpp/http/server/http_ex.h28
-rw-r--r--library/cpp/http/server/http_ut.cpp739
-rw-r--r--library/cpp/http/server/options.cpp43
-rw-r--r--library/cpp/http/server/options.h176
-rw-r--r--library/cpp/http/server/response.cpp65
-rw-r--r--library/cpp/http/server/response.h82
-rw-r--r--library/cpp/http/server/response_ut.cpp142
-rw-r--r--library/cpp/http/server/ut/ya.make12
-rw-r--r--library/cpp/http/server/ya.make27
-rw-r--r--library/cpp/http/ya.make25
-rw-r--r--library/cpp/hyperloglog/README.md3
-rw-r--r--library/cpp/hyperloglog/hyperloglog.cpp137
-rw-r--r--library/cpp/hyperloglog/hyperloglog.h64
-rw-r--r--library/cpp/hyperloglog/hyperloglog_corrections.inc1220
-rw-r--r--library/cpp/hyperloglog/hyperloglog_ut.cpp67
-rw-r--r--library/cpp/hyperloglog/ut/ya.make12
-rw-r--r--library/cpp/hyperloglog/ya.make13
-rw-r--r--library/cpp/int128/README.md6
-rw-r--r--library/cpp/int128/bench/main.cpp45
-rw-r--r--library/cpp/int128/bench/ya.make15
-rw-r--r--library/cpp/int128/int128.cpp62
-rw-r--r--library/cpp/int128/int128.h1278
-rw-r--r--library/cpp/int128/int128_common.h1
-rw-r--r--library/cpp/int128/int128_util.h15
-rw-r--r--library/cpp/int128/ut/.gitignore2
-rw-r--r--library/cpp/int128/ut/i128_and_intrinsic_identity_ut.cpp598
-rw-r--r--library/cpp/int128/ut/i128_comparison_ut.cpp145
-rw-r--r--library/cpp/int128/ut/i128_division_ut.cpp413
-rw-r--r--library/cpp/int128/ut/i128_type_traits_ut.cpp68
-rw-r--r--library/cpp/int128/ut/i128_ut.cpp12
-rw-r--r--library/cpp/int128/ut/int128_old_ut.cpp179
-rw-r--r--library/cpp/int128/ut/int128_typetraits_ut.cpp306
-rw-r--r--library/cpp/int128/ut/int128_ut.cpp83
-rw-r--r--library/cpp/int128/ut/int128_ut_helpers.cpp56
-rw-r--r--library/cpp/int128/ut/int128_ut_helpers.h15
-rw-r--r--library/cpp/int128/ut/int128_via_intrinsic_ut.cpp34
-rw-r--r--library/cpp/int128/ut/ui128_division_ut.cpp262
-rw-r--r--library/cpp/int128/ut/ya.make20
-rw-r--r--library/cpp/int128/ya.make13
-rw-r--r--library/cpp/ipmath/ipmath.cpp357
-rw-r--r--library/cpp/ipmath/ipmath.h160
-rw-r--r--library/cpp/ipmath/ipmath_ut.cpp507
-rw-r--r--library/cpp/ipmath/range_set.cpp99
-rw-r--r--library/cpp/ipmath/range_set.h66
-rw-r--r--library/cpp/ipmath/ut/ya.make16
-rw-r--r--library/cpp/ipmath/ya.make17
-rw-r--r--library/cpp/ipv6_address/ipv6_address.cpp437
-rw-r--r--library/cpp/ipv6_address/ipv6_address.h238
-rw-r--r--library/cpp/ipv6_address/ipv6_address_p.h7
-rw-r--r--library/cpp/ipv6_address/ut/ipv6_address_ut.cpp112
-rw-r--r--library/cpp/ipv6_address/ut/ya.make9
-rw-r--r--library/cpp/ipv6_address/ya.make15
-rw-r--r--library/cpp/iterator/README.md100
-rw-r--r--library/cpp/iterator/cartesian_product.cpp1
-rw-r--r--library/cpp/iterator/cartesian_product.h115
-rw-r--r--library/cpp/iterator/concatenate.cpp1
-rw-r--r--library/cpp/iterator/concatenate.h136
-rw-r--r--library/cpp/iterator/enumerate.cpp1
-rw-r--r--library/cpp/iterator/enumerate.h82
-rw-r--r--library/cpp/iterator/filtering.cpp1
-rw-r--r--library/cpp/iterator/filtering.h102
-rw-r--r--library/cpp/iterator/functools.cpp1
-rw-r--r--library/cpp/iterator/functools.h57
-rw-r--r--library/cpp/iterator/iterate_keys.cpp1
-rw-r--r--library/cpp/iterator/iterate_keys.h13
-rw-r--r--library/cpp/iterator/iterate_values.cpp1
-rw-r--r--library/cpp/iterator/iterate_values.h13
-rw-r--r--library/cpp/iterator/mapped.cpp1
-rw-r--r--library/cpp/iterator/mapped.h193
-rw-r--r--library/cpp/iterator/ut/filtering_ut.cpp41
-rw-r--r--library/cpp/iterator/ut/functools_ut.cpp603
-rw-r--r--library/cpp/iterator/ut/iterate_keys_ut.cpp37
-rw-r--r--library/cpp/iterator/ut/iterate_values_ut.cpp106
-rw-r--r--library/cpp/iterator/ut/mapped_ut.cpp61
-rw-r--r--library/cpp/iterator/ut/ya.make18
-rw-r--r--library/cpp/iterator/ut/zip_ut.cpp28
-rw-r--r--library/cpp/iterator/ya.make19
-rw-r--r--library/cpp/iterator/zip.cpp1
-rw-r--r--library/cpp/iterator/zip.h128
-rw-r--r--library/cpp/json/common/defs.cpp68
-rw-r--r--library/cpp/json/common/defs.h38
-rw-r--r--library/cpp/json/common/ya.make9
-rw-r--r--library/cpp/json/domscheme_traits.h216
-rw-r--r--library/cpp/json/easy_parse/json_easy_parser.cpp236
-rw-r--r--library/cpp/json/easy_parse/json_easy_parser.h46
-rw-r--r--library/cpp/json/easy_parse/json_easy_parser_impl.h40
-rw-r--r--library/cpp/json/easy_parse/ya.make13
-rw-r--r--library/cpp/json/fast_sax/parser.h13
-rw-r--r--library/cpp/json/fast_sax/parser.rl6314
-rw-r--r--library/cpp/json/fast_sax/unescape.cpp7
-rw-r--r--library/cpp/json/fast_sax/unescape.h5
-rw-r--r--library/cpp/json/fast_sax/ya.make17
-rw-r--r--library/cpp/json/flex_buffers/cvt.cpp139
-rw-r--r--library/cpp/json/flex_buffers/cvt.h20
-rw-r--r--library/cpp/json/flex_buffers/ut/cvt_ut.cpp21
-rw-r--r--library/cpp/json/flex_buffers/ut/ya.make9
-rw-r--r--library/cpp/json/flex_buffers/ya.make16
-rw-r--r--library/cpp/json/fuzzy_test/main.cpp30
-rw-r--r--library/cpp/json/fuzzy_test/ya.make13
-rw-r--r--library/cpp/json/json_prettifier.cpp277
-rw-r--r--library/cpp/json/json_prettifier.h58
-rw-r--r--library/cpp/json/json_reader.cpp567
-rw-r--r--library/cpp/json/json_reader.h140
-rw-r--r--library/cpp/json/json_value.h3
-rw-r--r--library/cpp/json/json_writer.cpp149
-rw-r--r--library/cpp/json/json_writer.h196
-rw-r--r--library/cpp/json/rapidjson_helpers.cpp1
-rw-r--r--library/cpp/json/rapidjson_helpers.h104
-rw-r--r--library/cpp/json/ut/json_prettifier_ut.cpp204
-rw-r--r--library/cpp/json/ut/json_reader_fast_ut.cpp304
-rw-r--r--library/cpp/json/ut/json_reader_ut.cpp430
-rw-r--r--library/cpp/json/ut/json_saveload_ut.cpp36
-rw-r--r--library/cpp/json/ut/json_writer_ut.cpp228
-rw-r--r--library/cpp/json/ut/ya.make17
-rw-r--r--library/cpp/json/writer/README23
-rw-r--r--library/cpp/json/writer/json.cpp517
-rw-r--r--library/cpp/json/writer/json.h289
-rw-r--r--library/cpp/json/writer/json_ut.cpp307
-rw-r--r--library/cpp/json/writer/json_value.cpp1105
-rw-r--r--library/cpp/json/writer/json_value.h294
-rw-r--r--library/cpp/json/writer/json_value_ut.cpp650
-rw-r--r--library/cpp/json/writer/ut/ya.make16
-rw-r--r--library/cpp/json/writer/ya.make20
-rw-r--r--library/cpp/json/ya.make23
-rw-r--r--library/cpp/json/yson/json2yson.cpp108
-rw-r--r--library/cpp/json/yson/json2yson.h179
-rw-r--r--library/cpp/json/yson/json2yson_ut.cpp107
-rw-r--r--library/cpp/json/yson/ut/ya.make28
-rw-r--r--library/cpp/json/yson/ya.make18
-rw-r--r--library/cpp/lcs/README.md33
-rw-r--r--library/cpp/lcs/lcs_via_lis.cpp1
-rw-r--r--library/cpp/lcs/lcs_via_lis.h193
-rw-r--r--library/cpp/lcs/lcs_via_lis_ut.cpp120
-rw-r--r--library/cpp/lcs/ut/ya.make15
-rw-r--r--library/cpp/lcs/ya.make13
-rw-r--r--library/cpp/lfalloc/alloc_profiler/align_ut.cpp23
-rw-r--r--library/cpp/lfalloc/alloc_profiler/profiler.cpp81
-rw-r--r--library/cpp/lfalloc/alloc_profiler/profiler.h45
-rw-r--r--library/cpp/lfalloc/alloc_profiler/profiler_ut.cpp76
-rw-r--r--library/cpp/lfalloc/alloc_profiler/stackcollect.cpp332
-rw-r--r--library/cpp/lfalloc/alloc_profiler/stackcollect.h107
-rw-r--r--library/cpp/lfalloc/alloc_profiler/ut/ya.make22
-rw-r--r--library/cpp/lfalloc/alloc_profiler/ya.make17
-rw-r--r--library/cpp/lfalloc/dbg/ya.make32
-rw-r--r--library/cpp/lfalloc/dbg_info/dbg_info.cpp124
-rw-r--r--library/cpp/lfalloc/dbg_info/dbg_info.h77
-rw-r--r--library/cpp/lfalloc/dbg_info/ya.make15
-rw-r--r--library/cpp/lfalloc/lf_allocX64.cpp144
-rw-r--r--library/cpp/lfalloc/lf_allocX64.h1926
-rw-r--r--library/cpp/lfalloc/ya.make25
-rw-r--r--library/cpp/lfalloc/yt/ya.make29
-rw-r--r--library/cpp/linear_regression/benchmark/cpu_act.features8192
-rw-r--r--library/cpp/linear_regression/benchmark/delta_ailerons.features7129
-rw-r--r--library/cpp/linear_regression/benchmark/kin8nm.features8192
-rw-r--r--library/cpp/linear_regression/benchmark/machine_cpu.features209
-rw-r--r--library/cpp/linear_regression/benchmark/main.cpp114
-rw-r--r--library/cpp/linear_regression/benchmark/pool.cpp109
-rw-r--r--library/cpp/linear_regression/benchmark/pool.h61
-rw-r--r--library/cpp/linear_regression/benchmark/puma32H.features8192
-rw-r--r--library/cpp/linear_regression/benchmark/ya.make15
-rw-r--r--library/cpp/linear_regression/linear_model.h42
-rw-r--r--library/cpp/linear_regression/linear_regression.cpp440
-rw-r--r--library/cpp/linear_regression/linear_regression.h342
-rw-r--r--library/cpp/linear_regression/linear_regression_ut.cpp374
-rw-r--r--library/cpp/linear_regression/unimodal.cpp118
-rw-r--r--library/cpp/linear_regression/unimodal.h59
-rw-r--r--library/cpp/linear_regression/ut/ya.make15
-rw-r--r--library/cpp/linear_regression/welford.cpp107
-rw-r--r--library/cpp/linear_regression/welford.h77
-rw-r--r--library/cpp/linear_regression/ya.make15
-rw-r--r--library/cpp/logger/all.h9
-rw-r--r--library/cpp/logger/backend.cpp71
-rw-r--r--library/cpp/logger/backend.h30
-rw-r--r--library/cpp/logger/backend_creator.cpp45
-rw-r--r--library/cpp/logger/backend_creator.h59
-rw-r--r--library/cpp/logger/composite.cpp18
-rw-r--r--library/cpp/logger/composite.h14
-rw-r--r--library/cpp/logger/composite_creator.cpp34
-rw-r--r--library/cpp/logger/composite_creator.h18
-rw-r--r--library/cpp/logger/composite_ut.cpp98
-rw-r--r--library/cpp/logger/element.cpp38
-rw-r--r--library/cpp/logger/element.h48
-rw-r--r--library/cpp/logger/element_ut.cpp39
-rw-r--r--library/cpp/logger/file.cpp59
-rw-r--r--library/cpp/logger/file.h19
-rw-r--r--library/cpp/logger/file_creator.cpp22
-rw-r--r--library/cpp/logger/file_creator.h17
-rw-r--r--library/cpp/logger/filter.cpp1
-rw-r--r--library/cpp/logger/filter.h32
-rw-r--r--library/cpp/logger/filter_creator.cpp20
-rw-r--r--library/cpp/logger/filter_creator.h16
-rw-r--r--library/cpp/logger/global/common.cpp36
-rw-r--r--library/cpp/logger/global/common.h149
-rw-r--r--library/cpp/logger/global/global.cpp43
-rw-r--r--library/cpp/logger/global/global.h125
-rw-r--r--library/cpp/logger/global/rty_formater.cpp94
-rw-r--r--library/cpp/logger/global/rty_formater.h61
-rw-r--r--library/cpp/logger/global/rty_formater_ut.cpp31
-rw-r--r--library/cpp/logger/global/ut/ya.make15
-rw-r--r--library/cpp/logger/global/ya.make19
-rw-r--r--library/cpp/logger/init_context/README.md5
-rw-r--r--library/cpp/logger/init_context/config.cpp26
-rw-r--r--library/cpp/logger/init_context/config.h14
-rw-r--r--library/cpp/logger/init_context/ya.make20
-rw-r--r--library/cpp/logger/init_context/yconf.cpp18
-rw-r--r--library/cpp/logger/init_context/yconf.h13
-rw-r--r--library/cpp/logger/log.cpp252
-rw-r--r--library/cpp/logger/log.h115
-rw-r--r--library/cpp/logger/log_ut.cpp191
-rw-r--r--library/cpp/logger/null.cpp13
-rw-r--r--library/cpp/logger/null.h12
-rw-r--r--library/cpp/logger/null_creator.cpp17
-rw-r--r--library/cpp/logger/null_creator.h15
-rw-r--r--library/cpp/logger/priority.h15
-rw-r--r--library/cpp/logger/record.h18
-rw-r--r--library/cpp/logger/rotating_file.cpp86
-rw-r--r--library/cpp/logger/rotating_file.h20
-rw-r--r--library/cpp/logger/rotating_file_creator.cpp28
-rw-r--r--library/cpp/logger/rotating_file_creator.h18
-rw-r--r--library/cpp/logger/rotating_file_ut.cpp57
-rw-r--r--library/cpp/logger/stream.cpp19
-rw-r--r--library/cpp/logger/stream.h17
-rw-r--r--library/cpp/logger/stream_creator.cpp32
-rw-r--r--library/cpp/logger/stream_creator.h28
-rw-r--r--library/cpp/logger/sync_page_cache_file.cpp125
-rw-r--r--library/cpp/logger/sync_page_cache_file.h19
-rw-r--r--library/cpp/logger/sync_page_cache_file_creator.cpp28
-rw-r--r--library/cpp/logger/sync_page_cache_file_creator.h18
-rw-r--r--library/cpp/logger/system.cpp87
-rw-r--r--library/cpp/logger/system.h66
-rw-r--r--library/cpp/logger/system_creator.cpp25
-rw-r--r--library/cpp/logger/system_creator.h20
-rw-r--r--library/cpp/logger/thread.cpp165
-rw-r--r--library/cpp/logger/thread.h34
-rw-r--r--library/cpp/logger/thread_creator.cpp30
-rw-r--r--library/cpp/logger/thread_creator.h20
-rw-r--r--library/cpp/logger/uninitialized_creator.cpp50
-rw-r--r--library/cpp/logger/uninitialized_creator.h16
-rw-r--r--library/cpp/logger/ut/ya.make20
-rw-r--r--library/cpp/logger/ya.make47
-rw-r--r--library/cpp/lwtrace/all.h195
-rw-r--r--library/cpp/lwtrace/check.cpp18
-rw-r--r--library/cpp/lwtrace/check.h78
-rw-r--r--library/cpp/lwtrace/control.cpp97
-rw-r--r--library/cpp/lwtrace/control.h351
-rw-r--r--library/cpp/lwtrace/custom_action.cpp21
-rw-r--r--library/cpp/lwtrace/custom_action.h75
-rw-r--r--library/cpp/lwtrace/event.h29
-rw-r--r--library/cpp/lwtrace/example1/example_query.tr10
-rw-r--r--library/cpp/lwtrace/example1/lwtrace_example1.cpp39
-rwxr-xr-xlibrary/cpp/lwtrace/example1/start_with_query.sh3
-rw-r--r--library/cpp/lwtrace/example1/ya.make13
-rw-r--r--library/cpp/lwtrace/example2/destructive.tr36
-rw-r--r--library/cpp/lwtrace/example2/empty.tr0
-rw-r--r--library/cpp/lwtrace/example2/example_query.tr79
-rw-r--r--library/cpp/lwtrace/example2/lwtrace_example2.cpp117
-rw-r--r--library/cpp/lwtrace/example2/ya.make14
-rw-r--r--library/cpp/lwtrace/example3/example_query.tr13
-rw-r--r--library/cpp/lwtrace/example3/lwtrace_example3.cpp43
-rw-r--r--library/cpp/lwtrace/example3/my_action.h85
-rwxr-xr-xlibrary/cpp/lwtrace/example3/start_with_query.sh6
-rw-r--r--library/cpp/lwtrace/example3/ya.make13
-rw-r--r--library/cpp/lwtrace/example4/example_query.tr10
-rw-r--r--library/cpp/lwtrace/example4/lwtrace_example4.cpp49
-rwxr-xr-xlibrary/cpp/lwtrace/example4/start_with_query.sh3
-rw-r--r--library/cpp/lwtrace/example4/ya.make13
-rw-r--r--library/cpp/lwtrace/example5/example_query.tr9
-rw-r--r--library/cpp/lwtrace/example5/lwtrace_example5.cpp30
-rwxr-xr-xlibrary/cpp/lwtrace/example5/start_with_query.sh3
-rw-r--r--library/cpp/lwtrace/example5/ya.make13
-rw-r--r--library/cpp/lwtrace/kill_action.cpp21
-rw-r--r--library/cpp/lwtrace/kill_action.h15
-rw-r--r--library/cpp/lwtrace/log.h906
-rw-r--r--library/cpp/lwtrace/log_shuttle.cpp67
-rw-r--r--library/cpp/lwtrace/log_shuttle.h359
-rw-r--r--library/cpp/lwtrace/lwprobe.h110
-rw-r--r--library/cpp/lwtrace/mon/analytics/all.h8
-rw-r--r--library/cpp/lwtrace/mon/analytics/analytics.cpp5
-rw-r--r--library/cpp/lwtrace/mon/analytics/csv_output.h52
-rw-r--r--library/cpp/lwtrace/mon/analytics/data.h108
-rw-r--r--library/cpp/lwtrace/mon/analytics/html_output.h86
-rw-r--r--library/cpp/lwtrace/mon/analytics/json_output.h98
-rw-r--r--library/cpp/lwtrace/mon/analytics/transform.h204
-rw-r--r--library/cpp/lwtrace/mon/analytics/util.h122
-rw-r--r--library/cpp/lwtrace/mon/analytics/ya.make15
-rw-r--r--library/cpp/lwtrace/mon/mon_lwtrace.cpp4723
-rw-r--r--library/cpp/lwtrace/mon/mon_lwtrace.h27
-rw-r--r--library/cpp/lwtrace/mon/static/analytics.css68
-rw-r--r--library/cpp/lwtrace/mon/static/analytics.flot.html49
-rw-r--r--library/cpp/lwtrace/mon/static/analytics.gantt.html26
-rw-r--r--library/cpp/lwtrace/mon/static/analytics.header.html21
-rw-r--r--library/cpp/lwtrace/mon/static/analytics.js561
-rw-r--r--library/cpp/lwtrace/mon/static/common.css3
-rw-r--r--library/cpp/lwtrace/mon/static/common.js17
-rw-r--r--library/cpp/lwtrace/mon/static/css/bootstrap.min.css9
-rw-r--r--library/cpp/lwtrace/mon/static/css/d3-gantt.css68
-rw-r--r--library/cpp/lwtrace/mon/static/css/jquery.treegrid.css8
-rw-r--r--library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.eotbin0 -> 20127 bytes
-rw-r--r--library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg288
-rw-r--r--library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.ttfbin0 -> 45404 bytes
-rw-r--r--library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.woffbin0 -> 23424 bytes
-rw-r--r--library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff2bin0 -> 18028 bytes
-rw-r--r--library/cpp/lwtrace/mon/static/footer.html0
-rw-r--r--library/cpp/lwtrace/mon/static/header.html11
-rw-r--r--library/cpp/lwtrace/mon/static/img/collapse.pngbin0 -> 2886 bytes
-rw-r--r--library/cpp/lwtrace/mon/static/img/expand.pngbin0 -> 2894 bytes
-rw-r--r--library/cpp/lwtrace/mon/static/img/file.pngbin0 -> 342 bytes
-rw-r--r--library/cpp/lwtrace/mon/static/img/folder.pngbin0 -> 537 bytes
-rw-r--r--library/cpp/lwtrace/mon/static/js/bootstrap.min.js9
-rw-r--r--library/cpp/lwtrace/mon/static/js/d3-gantt.js759
-rw-r--r--library/cpp/lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js352
-rw-r--r--library/cpp/lwtrace/mon/static/js/d3.v4.min.js2
-rw-r--r--library/cpp/lwtrace/mon/static/js/filesaver.min.js1
-rw-r--r--library/cpp/lwtrace/mon/static/js/jquery.flot.extents.js196
-rw-r--r--library/cpp/lwtrace/mon/static/js/jquery.flot.min.js8
-rw-r--r--library/cpp/lwtrace/mon/static/js/jquery.flot.navigate.min.js7
-rw-r--r--library/cpp/lwtrace/mon/static/js/jquery.flot.selection.min.js7
-rw-r--r--library/cpp/lwtrace/mon/static/js/jquery.min.js5
-rw-r--r--library/cpp/lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js4
-rw-r--r--library/cpp/lwtrace/mon/static/js/jquery.treegrid.min.js2
-rw-r--r--library/cpp/lwtrace/mon/static/js/jquery.url.min.js1
-rwxr-xr-xlibrary/cpp/lwtrace/mon/trace.sh81
-rw-r--r--library/cpp/lwtrace/mon/ya.make55
-rw-r--r--library/cpp/lwtrace/param_traits.h66
-rw-r--r--library/cpp/lwtrace/perf.cpp84
-rw-r--r--library/cpp/lwtrace/perf.h63
-rw-r--r--library/cpp/lwtrace/preprocessor.h295
-rw-r--r--library/cpp/lwtrace/probe.h266
-rw-r--r--library/cpp/lwtrace/probes.cpp3
-rw-r--r--library/cpp/lwtrace/probes.h23
-rw-r--r--library/cpp/lwtrace/protos/lwtrace.proto266
-rw-r--r--library/cpp/lwtrace/protos/ya.make11
-rw-r--r--library/cpp/lwtrace/rwspinlock.h88
-rw-r--r--library/cpp/lwtrace/shuttle.cpp20
-rw-r--r--library/cpp/lwtrace/shuttle.h358
-rw-r--r--library/cpp/lwtrace/signature.h772
-rw-r--r--library/cpp/lwtrace/sleep_action.cpp15
-rw-r--r--library/cpp/lwtrace/sleep_action.h21
-rw-r--r--library/cpp/lwtrace/start.cpp69
-rw-r--r--library/cpp/lwtrace/start.h11
-rw-r--r--library/cpp/lwtrace/stderr_writer.cpp19
-rw-r--r--library/cpp/lwtrace/stderr_writer.h19
-rw-r--r--library/cpp/lwtrace/symbol.cpp15
-rw-r--r--library/cpp/lwtrace/symbol.h68
-rwxr-xr-xlibrary/cpp/lwtrace/tests/test_all_parallel.sh29
-rw-r--r--library/cpp/lwtrace/tests/trace_tests.cpp715
-rw-r--r--library/cpp/lwtrace/tests/ya.make15
-rw-r--r--library/cpp/lwtrace/trace.cpp1051
-rw-r--r--library/cpp/lwtrace/trace_ut.cpp880
-rw-r--r--library/cpp/lwtrace/ut/ya.make11
-rw-r--r--library/cpp/lwtrace/ya.make29
-rw-r--r--library/cpp/malloc/api/helpers/io.cpp10
-rw-r--r--library/cpp/malloc/api/helpers/ya.make13
-rw-r--r--library/cpp/malloc/api/malloc.cpp37
-rw-r--r--library/cpp/malloc/api/malloc.h32
-rw-r--r--library/cpp/malloc/api/ut/ut.cpp10
-rw-r--r--library/cpp/malloc/api/ut/ya.make13
-rw-r--r--library/cpp/malloc/api/ya.make11
-rw-r--r--library/cpp/malloc/jemalloc/malloc-info.cpp65
-rw-r--r--library/cpp/malloc/jemalloc/ya.make21
-rw-r--r--library/cpp/malloc/tcmalloc/malloc-info.cpp9
-rw-r--r--library/cpp/malloc/tcmalloc/ya.make15
-rw-r--r--library/cpp/malloc/ya.make26
-rw-r--r--library/cpp/messagebus/acceptor.cpp127
-rw-r--r--library/cpp/messagebus/acceptor.h60
-rw-r--r--library/cpp/messagebus/acceptor_status.cpp68
-rw-r--r--library/cpp/messagebus/acceptor_status.h35
-rw-r--r--library/cpp/messagebus/actor/actor.h144
-rw-r--r--library/cpp/messagebus/actor/actor_ut.cpp157
-rw-r--r--library/cpp/messagebus/actor/executor.cpp338
-rw-r--r--library/cpp/messagebus/actor/executor.h105
-rw-r--r--library/cpp/messagebus/actor/queue_for_actor.h74
-rw-r--r--library/cpp/messagebus/actor/queue_in_actor.h80
-rw-r--r--library/cpp/messagebus/actor/ring_buffer.h135
-rw-r--r--library/cpp/messagebus/actor/ring_buffer_ut.cpp60
-rw-r--r--library/cpp/messagebus/actor/ring_buffer_with_spin_lock.h91
-rw-r--r--library/cpp/messagebus/actor/tasks.h48
-rw-r--r--library/cpp/messagebus/actor/tasks_ut.cpp37
-rw-r--r--library/cpp/messagebus/actor/temp_tls_vector.h40
-rw-r--r--library/cpp/messagebus/actor/thread_extra.cpp30
-rw-r--r--library/cpp/messagebus/actor/thread_extra.h41
-rw-r--r--library/cpp/messagebus/actor/what_thread_does.cpp22
-rw-r--r--library/cpp/messagebus/actor/what_thread_does.h28
-rw-r--r--library/cpp/messagebus/actor/what_thread_does_guard.h40
-rw-r--r--library/cpp/messagebus/actor/what_thread_does_guard_ut.cpp13
-rw-r--r--library/cpp/messagebus/actor/ya.make11
-rw-r--r--library/cpp/messagebus/all.lwt8
-rw-r--r--library/cpp/messagebus/all/ya.make10
-rw-r--r--library/cpp/messagebus/async_result.h54
-rw-r--r--library/cpp/messagebus/async_result_ut.cpp37
-rw-r--r--library/cpp/messagebus/base.h11
-rw-r--r--library/cpp/messagebus/cc_semaphore.h36
-rw-r--r--library/cpp/messagebus/cc_semaphore_ut.cpp45
-rw-r--r--library/cpp/messagebus/codegen.h4
-rw-r--r--library/cpp/messagebus/config/codegen.h10
-rw-r--r--library/cpp/messagebus/config/defs.h82
-rw-r--r--library/cpp/messagebus/config/netaddr.cpp183
-rw-r--r--library/cpp/messagebus/config/netaddr.h86
-rw-r--r--library/cpp/messagebus/config/session_config.cpp157
-rw-r--r--library/cpp/messagebus/config/session_config.h65
-rw-r--r--library/cpp/messagebus/config/ya.make15
-rw-r--r--library/cpp/messagebus/connection.cpp16
-rw-r--r--library/cpp/messagebus/connection.h61
-rw-r--r--library/cpp/messagebus/coreconn.cpp30
-rw-r--r--library/cpp/messagebus/coreconn.h67
-rw-r--r--library/cpp/messagebus/coreconn_ut.cpp25
-rw-r--r--library/cpp/messagebus/debug_receiver/debug_receiver.cpp42
-rw-r--r--library/cpp/messagebus/debug_receiver/debug_receiver_handler.cpp20
-rw-r--r--library/cpp/messagebus/debug_receiver/debug_receiver_handler.h10
-rw-r--r--library/cpp/messagebus/debug_receiver/debug_receiver_proto.cpp20
-rw-r--r--library/cpp/messagebus/debug_receiver/debug_receiver_proto.h27
-rw-r--r--library/cpp/messagebus/debug_receiver/ya.make17
-rw-r--r--library/cpp/messagebus/defs.h4
-rw-r--r--library/cpp/messagebus/dummy_debugger.h9
-rw-r--r--library/cpp/messagebus/duration_histogram.cpp74
-rw-r--r--library/cpp/messagebus/duration_histogram.h45
-rw-r--r--library/cpp/messagebus/duration_histogram_ut.cpp38
-rw-r--r--library/cpp/messagebus/event_loop.cpp370
-rw-r--r--library/cpp/messagebus/event_loop.h72
-rw-r--r--library/cpp/messagebus/extra_ref.h36
-rw-r--r--library/cpp/messagebus/futex_like.cpp55
-rw-r--r--library/cpp/messagebus/futex_like.h86
-rw-r--r--library/cpp/messagebus/handler.cpp36
-rw-r--r--library/cpp/messagebus/handler.h135
-rw-r--r--library/cpp/messagebus/handler_impl.h23
-rw-r--r--library/cpp/messagebus/hash.h19
-rw-r--r--library/cpp/messagebus/key_value_printer.cpp46
-rw-r--r--library/cpp/messagebus/key_value_printer.h28
-rw-r--r--library/cpp/messagebus/latch.h53
-rw-r--r--library/cpp/messagebus/latch_ut.cpp20
-rw-r--r--library/cpp/messagebus/left_right_buffer.h78
-rw-r--r--library/cpp/messagebus/lfqueue_batch.h36
-rw-r--r--library/cpp/messagebus/lfqueue_batch_ut.cpp56
-rw-r--r--library/cpp/messagebus/local_flags.cpp32
-rw-r--r--library/cpp/messagebus/local_flags.h26
-rw-r--r--library/cpp/messagebus/local_flags_ut.cpp18
-rw-r--r--library/cpp/messagebus/local_tasks.h23
-rw-r--r--library/cpp/messagebus/locator.cpp427
-rw-r--r--library/cpp/messagebus/locator.h93
-rw-r--r--library/cpp/messagebus/mb_lwtrace.cpp12
-rw-r--r--library/cpp/messagebus/mb_lwtrace.h19
-rw-r--r--library/cpp/messagebus/memory.h42
-rw-r--r--library/cpp/messagebus/memory_ut.cpp13
-rw-r--r--library/cpp/messagebus/message.cpp198
-rw-r--r--library/cpp/messagebus/message.h272
-rw-r--r--library/cpp/messagebus/message_counter.cpp46
-rw-r--r--library/cpp/messagebus/message_counter.h36
-rw-r--r--library/cpp/messagebus/message_ptr_and_header.h36
-rw-r--r--library/cpp/messagebus/message_status.cpp13
-rw-r--r--library/cpp/messagebus/message_status.h57
-rw-r--r--library/cpp/messagebus/message_status_counter.cpp71
-rw-r--r--library/cpp/messagebus/message_status_counter.h36
-rw-r--r--library/cpp/messagebus/message_status_counter_ut.cpp23
-rw-r--r--library/cpp/messagebus/messqueue.cpp198
-rw-r--r--library/cpp/messagebus/misc/atomic_box.h34
-rw-r--r--library/cpp/messagebus/misc/granup.h50
-rw-r--r--library/cpp/messagebus/misc/test_sync.h75
-rw-r--r--library/cpp/messagebus/misc/tokenquota.h83
-rw-r--r--library/cpp/messagebus/misc/weak_ptr.h99
-rw-r--r--library/cpp/messagebus/misc/weak_ptr_ut.cpp46
-rw-r--r--library/cpp/messagebus/monitoring/mon_proto.proto55
-rw-r--r--library/cpp/messagebus/monitoring/ya.make15
-rw-r--r--library/cpp/messagebus/moved.h39
-rw-r--r--library/cpp/messagebus/moved_ut.cpp22
-rw-r--r--library/cpp/messagebus/netaddr.h4
-rw-r--r--library/cpp/messagebus/netaddr_ut.cpp21
-rw-r--r--library/cpp/messagebus/network.cpp156
-rw-r--r--library/cpp/messagebus/network.h28
-rw-r--r--library/cpp/messagebus/network_ut.cpp65
-rw-r--r--library/cpp/messagebus/nondestroying_holder.h39
-rw-r--r--library/cpp/messagebus/nondestroying_holder_ut.cpp12
-rw-r--r--library/cpp/messagebus/oldmodule/module.cpp881
-rw-r--r--library/cpp/messagebus/oldmodule/module.h410
-rw-r--r--library/cpp/messagebus/oldmodule/startsession.cpp65
-rw-r--r--library/cpp/messagebus/oldmodule/startsession.h34
-rw-r--r--library/cpp/messagebus/oldmodule/ya.make15
-rw-r--r--library/cpp/messagebus/protobuf/ya.make15
-rw-r--r--library/cpp/messagebus/protobuf/ybusbuf.cpp88
-rw-r--r--library/cpp/messagebus/protobuf/ybusbuf.h233
-rw-r--r--library/cpp/messagebus/queue_config.cpp22
-rw-r--r--library/cpp/messagebus/queue_config.h19
-rw-r--r--library/cpp/messagebus/rain_check/core/coro.cpp60
-rw-r--r--library/cpp/messagebus/rain_check/core/coro.h58
-rw-r--r--library/cpp/messagebus/rain_check/core/coro_stack.cpp41
-rw-r--r--library/cpp/messagebus/rain_check/core/coro_stack.h54
-rw-r--r--library/cpp/messagebus/rain_check/core/coro_ut.cpp106
-rw-r--r--library/cpp/messagebus/rain_check/core/env.cpp3
-rw-r--r--library/cpp/messagebus/rain_check/core/env.h47
-rw-r--r--library/cpp/messagebus/rain_check/core/fwd.h18
-rw-r--r--library/cpp/messagebus/rain_check/core/rain_check.cpp1
-rw-r--r--library/cpp/messagebus/rain_check/core/rain_check.h8
-rw-r--r--library/cpp/messagebus/rain_check/core/simple.cpp18
-rw-r--r--library/cpp/messagebus/rain_check/core/simple.h62
-rw-r--r--library/cpp/messagebus/rain_check/core/simple_ut.cpp59
-rw-r--r--library/cpp/messagebus/rain_check/core/sleep.cpp47
-rw-r--r--library/cpp/messagebus/rain_check/core/sleep.h24
-rw-r--r--library/cpp/messagebus/rain_check/core/sleep_ut.cpp46
-rw-r--r--library/cpp/messagebus/rain_check/core/spawn.cpp5
-rw-r--r--library/cpp/messagebus/rain_check/core/spawn.h50
-rw-r--r--library/cpp/messagebus/rain_check/core/spawn_ut.cpp145
-rw-r--r--library/cpp/messagebus/rain_check/core/task.cpp216
-rw-r--r--library/cpp/messagebus/rain_check/core/task.h184
-rw-r--r--library/cpp/messagebus/rain_check/core/track.cpp66
-rw-r--r--library/cpp/messagebus/rain_check/core/track.h97
-rw-r--r--library/cpp/messagebus/rain_check/core/track_ut.cpp45
-rw-r--r--library/cpp/messagebus/rain_check/core/ya.make25
-rw-r--r--library/cpp/messagebus/rain_check/http/client.cpp154
-rw-r--r--library/cpp/messagebus/rain_check/http/client.h78
-rw-r--r--library/cpp/messagebus/rain_check/http/client_ut.cpp205
-rw-r--r--library/cpp/messagebus/rain_check/http/http_code_extractor.cpp39
-rw-r--r--library/cpp/messagebus/rain_check/http/http_code_extractor.h16
-rw-r--r--library/cpp/messagebus/rain_check/http/ya.make17
-rw-r--r--library/cpp/messagebus/rain_check/messagebus/messagebus_client.cpp98
-rw-r--r--library/cpp/messagebus/rain_check/messagebus/messagebus_client.h67
-rw-r--r--library/cpp/messagebus/rain_check/messagebus/messagebus_client_ut.cpp146
-rw-r--r--library/cpp/messagebus/rain_check/messagebus/messagebus_server.cpp17
-rw-r--r--library/cpp/messagebus/rain_check/messagebus/messagebus_server.h46
-rw-r--r--library/cpp/messagebus/rain_check/messagebus/messagebus_server_ut.cpp51
-rw-r--r--library/cpp/messagebus/rain_check/messagebus/ya.make15
-rw-r--r--library/cpp/messagebus/rain_check/test/TestRainCheck.py8
-rw-r--r--library/cpp/messagebus/rain_check/test/helper/misc.cpp27
-rw-r--r--library/cpp/messagebus/rain_check/test/helper/misc.h57
-rw-r--r--library/cpp/messagebus/rain_check/test/helper/ya.make13
-rw-r--r--library/cpp/messagebus/rain_check/test/perftest/perftest.cpp154
-rw-r--r--library/cpp/messagebus/rain_check/test/perftest/ya.make14
-rw-r--r--library/cpp/messagebus/rain_check/test/ut/test.h13
-rw-r--r--library/cpp/messagebus/rain_check/test/ut/ya.make24
-rw-r--r--library/cpp/messagebus/rain_check/test/ya.make6
-rw-r--r--library/cpp/messagebus/rain_check/ya.make8
-rw-r--r--library/cpp/messagebus/ref_counted.h6
-rw-r--r--library/cpp/messagebus/remote_client_connection.cpp343
-rw-r--r--library/cpp/messagebus/remote_client_connection.h65
-rw-r--r--library/cpp/messagebus/remote_client_session.cpp127
-rw-r--r--library/cpp/messagebus/remote_client_session.h59
-rw-r--r--library/cpp/messagebus/remote_client_session_semaphore.cpp67
-rw-r--r--library/cpp/messagebus/remote_client_session_semaphore.h42
-rw-r--r--library/cpp/messagebus/remote_connection.cpp974
-rw-r--r--library/cpp/messagebus/remote_connection.h294
-rw-r--r--library/cpp/messagebus/remote_connection_status.cpp265
-rw-r--r--library/cpp/messagebus/remote_connection_status.h214
-rw-r--r--library/cpp/messagebus/remote_server_connection.cpp73
-rw-r--r--library/cpp/messagebus/remote_server_connection.h32
-rw-r--r--library/cpp/messagebus/remote_server_session.cpp206
-rw-r--r--library/cpp/messagebus/remote_server_session.h54
-rw-r--r--library/cpp/messagebus/remote_server_session_semaphore.cpp59
-rw-r--r--library/cpp/messagebus/remote_server_session_semaphore.h42
-rw-r--r--library/cpp/messagebus/scheduler/scheduler.cpp119
-rw-r--r--library/cpp/messagebus/scheduler/scheduler.h68
-rw-r--r--library/cpp/messagebus/scheduler/scheduler_ut.cpp36
-rw-r--r--library/cpp/messagebus/scheduler/ya.make13
-rw-r--r--library/cpp/messagebus/scheduler_actor.h85
-rw-r--r--library/cpp/messagebus/scheduler_actor_ut.cpp48
-rw-r--r--library/cpp/messagebus/session.cpp130
-rw-r--r--library/cpp/messagebus/session.h225
-rw-r--r--library/cpp/messagebus/session_config.h4
-rw-r--r--library/cpp/messagebus/session_impl.cpp650
-rw-r--r--library/cpp/messagebus/session_impl.h259
-rw-r--r--library/cpp/messagebus/session_job_count.cpp22
-rw-r--r--library/cpp/messagebus/session_job_count.h39
-rw-r--r--library/cpp/messagebus/shutdown_state.cpp20
-rw-r--r--library/cpp/messagebus/shutdown_state.h22
-rw-r--r--library/cpp/messagebus/socket_addr.cpp79
-rw-r--r--library/cpp/messagebus/socket_addr.h113
-rw-r--r--library/cpp/messagebus/socket_addr_ut.cpp15
-rw-r--r--library/cpp/messagebus/storage.cpp161
-rw-r--r--library/cpp/messagebus/storage.h94
-rw-r--r--library/cpp/messagebus/synchandler.cpp198
-rw-r--r--library/cpp/messagebus/test/TestMessageBus.py8
-rw-r--r--library/cpp/messagebus/test/example/client/client.cpp81
-rw-r--r--library/cpp/messagebus/test/example/client/ya.make13
-rw-r--r--library/cpp/messagebus/test/example/common/messages.proto15
-rw-r--r--library/cpp/messagebus/test/example/common/proto.cpp12
-rw-r--r--library/cpp/messagebus/test/example/common/proto.h17
-rw-r--r--library/cpp/messagebus/test/example/common/ya.make15
-rw-r--r--library/cpp/messagebus/test/example/server/server.cpp58
-rw-r--r--library/cpp/messagebus/test/example/server/ya.make13
-rw-r--r--library/cpp/messagebus/test/example/ya.make7
-rw-r--r--library/cpp/messagebus/test/helper/alloc_counter.h21
-rw-r--r--library/cpp/messagebus/test/helper/example.cpp281
-rw-r--r--library/cpp/messagebus/test/helper/example.h132
-rw-r--r--library/cpp/messagebus/test/helper/example_module.cpp43
-rw-r--r--library/cpp/messagebus/test/helper/example_module.h37
-rw-r--r--library/cpp/messagebus/test/helper/fixed_port.cpp10
-rw-r--r--library/cpp/messagebus/test/helper/fixed_port.h11
-rw-r--r--library/cpp/messagebus/test/helper/hanging_server.cpp13
-rw-r--r--library/cpp/messagebus/test/helper/hanging_server.h16
-rw-r--r--library/cpp/messagebus/test/helper/message_handler_error.cpp26
-rw-r--r--library/cpp/messagebus/test/helper/message_handler_error.h19
-rw-r--r--library/cpp/messagebus/test/helper/object_count_check.h74
-rw-r--r--library/cpp/messagebus/test/helper/wait_for.h14
-rw-r--r--library/cpp/messagebus/test/helper/ya.make17
-rw-r--r--library/cpp/messagebus/test/perftest/messages.proto7
-rw-r--r--library/cpp/messagebus/test/perftest/perftest.cpp713
-rw-r--r--library/cpp/messagebus/test/perftest/simple_proto.cpp22
-rw-r--r--library/cpp/messagebus/test/perftest/simple_proto.h29
-rw-r--r--library/cpp/messagebus/test/perftest/stackcollect.diff13
-rw-r--r--library/cpp/messagebus/test/perftest/ya.make24
-rw-r--r--library/cpp/messagebus/test/ut/count_down_latch.h30
-rw-r--r--library/cpp/messagebus/test/ut/locator_uniq_ut.cpp40
-rw-r--r--library/cpp/messagebus/test/ut/messagebus_ut.cpp1151
-rw-r--r--library/cpp/messagebus/test/ut/module_client_one_way_ut.cpp143
-rw-r--r--library/cpp/messagebus/test/ut/module_client_ut.cpp368
-rw-r--r--library/cpp/messagebus/test/ut/module_server_ut.cpp119
-rw-r--r--library/cpp/messagebus/test/ut/moduletest.h221
-rw-r--r--library/cpp/messagebus/test/ut/one_way_ut.cpp255
-rw-r--r--library/cpp/messagebus/test/ut/starter_ut.cpp140
-rw-r--r--library/cpp/messagebus/test/ut/sync_client_ut.cpp69
-rw-r--r--library/cpp/messagebus/test/ut/ya.make56
-rw-r--r--library/cpp/messagebus/test/ya.make7
-rw-r--r--library/cpp/messagebus/test_utils.h12
-rw-r--r--library/cpp/messagebus/text_utils.h3
-rw-r--r--library/cpp/messagebus/thread_extra.h3
-rw-r--r--library/cpp/messagebus/use_after_free_checker.cpp22
-rw-r--r--library/cpp/messagebus/use_after_free_checker.h31
-rw-r--r--library/cpp/messagebus/use_count_checker.cpp53
-rw-r--r--library/cpp/messagebus/use_count_checker.h27
-rw-r--r--library/cpp/messagebus/vector_swaps.h171
-rw-r--r--library/cpp/messagebus/vector_swaps_ut.cpp17
-rw-r--r--library/cpp/messagebus/www/bus-ico.pngbin0 -> 2208 bytes
-rw-r--r--library/cpp/messagebus/www/concat_strings.h22
-rw-r--r--library/cpp/messagebus/www/html_output.cpp4
-rw-r--r--library/cpp/messagebus/www/html_output.h324
-rw-r--r--library/cpp/messagebus/www/messagebus.js48
-rw-r--r--library/cpp/messagebus/www/www.cpp930
-rw-r--r--library/cpp/messagebus/www/www.h45
-rw-r--r--library/cpp/messagebus/www/ya.make29
-rw-r--r--library/cpp/messagebus/ya.make68
-rw-r--r--library/cpp/messagebus/ybus.h205
-rw-r--r--library/cpp/mime/types/mime.cpp253
-rw-r--r--library/cpp/mime/types/mime.h72
-rw-r--r--library/cpp/mime/types/ya.make11
-rw-r--r--library/cpp/mime/ya.make5
-rw-r--r--library/cpp/monlib/counters/counters.cpp49
-rw-r--r--library/cpp/monlib/counters/counters.h350
-rw-r--r--library/cpp/monlib/counters/counters_ut.cpp49
-rw-r--r--library/cpp/monlib/counters/histogram.cpp40
-rw-r--r--library/cpp/monlib/counters/histogram.h189
-rw-r--r--library/cpp/monlib/counters/histogram_ut.cpp47
-rw-r--r--library/cpp/monlib/counters/meter.cpp4
-rw-r--r--library/cpp/monlib/counters/meter.h285
-rw-r--r--library/cpp/monlib/counters/meter_ut.cpp41
-rw-r--r--library/cpp/monlib/counters/timer.h176
-rw-r--r--library/cpp/monlib/counters/timer_ut.cpp81
-rw-r--r--library/cpp/monlib/counters/ut/ya.make12
-rw-r--r--library/cpp/monlib/counters/ya.make15
-rw-r--r--library/cpp/monlib/deprecated/json/ut/ya.make12
-rw-r--r--library/cpp/monlib/deprecated/json/writer.cpp100
-rw-r--r--library/cpp/monlib/deprecated/json/writer.h76
-rw-r--r--library/cpp/monlib/deprecated/json/writer_ut.cpp32
-rw-r--r--library/cpp/monlib/deprecated/json/ya.make26
-rw-r--r--library/cpp/monlib/deprecated/ya.make8
-rw-r--r--library/cpp/monlib/dynamic_counters/contention_ut.cpp61
-rw-r--r--library/cpp/monlib/dynamic_counters/counters.cpp308
-rw-r--r--library/cpp/monlib/dynamic_counters/counters.h374
-rw-r--r--library/cpp/monlib/dynamic_counters/counters_ut.cpp342
-rw-r--r--library/cpp/monlib/dynamic_counters/encode.cpp131
-rw-r--r--library/cpp/monlib/dynamic_counters/encode.h23
-rw-r--r--library/cpp/monlib/dynamic_counters/encode_ut.cpp226
-rw-r--r--library/cpp/monlib/dynamic_counters/golovan_page.cpp79
-rw-r--r--library/cpp/monlib/dynamic_counters/golovan_page.h25
-rw-r--r--library/cpp/monlib/dynamic_counters/page.cpp141
-rw-r--r--library/cpp/monlib/dynamic_counters/page.h50
-rw-r--r--library/cpp/monlib/dynamic_counters/percentile/percentile.h59
-rw-r--r--library/cpp/monlib/dynamic_counters/percentile/percentile_base.h36
-rw-r--r--library/cpp/monlib/dynamic_counters/percentile/percentile_lg.h182
-rw-r--r--library/cpp/monlib/dynamic_counters/percentile/percentile_ut.cpp129
-rw-r--r--library/cpp/monlib/dynamic_counters/percentile/ut/ya.make9
-rw-r--r--library/cpp/monlib/dynamic_counters/percentile/ya.make15
-rw-r--r--library/cpp/monlib/dynamic_counters/ut/ya.make16
-rw-r--r--library/cpp/monlib/dynamic_counters/ya.make27
-rw-r--r--library/cpp/monlib/encode/buffered/buffered_encoder_base.cpp170
-rw-r--r--library/cpp/monlib/encode/buffered/buffered_encoder_base.h100
-rw-r--r--library/cpp/monlib/encode/buffered/string_pool.cpp58
-rw-r--r--library/cpp/monlib/encode/buffered/string_pool.h92
-rw-r--r--library/cpp/monlib/encode/buffered/string_pool_ut.cpp84
-rw-r--r--library/cpp/monlib/encode/buffered/ut/ya.make12
-rw-r--r--library/cpp/monlib/encode/buffered/ya.make19
-rw-r--r--library/cpp/monlib/encode/encoder.cpp6
-rw-r--r--library/cpp/monlib/encode/encoder.h17
-rw-r--r--library/cpp/monlib/encode/encoder_state.cpp1
-rw-r--r--library/cpp/monlib/encode/encoder_state.h62
-rw-r--r--library/cpp/monlib/encode/encoder_state_enum.h12
-rw-r--r--library/cpp/monlib/encode/fake/fake.cpp51
-rw-r--r--library/cpp/monlib/encode/fake/fake.h10
-rw-r--r--library/cpp/monlib/encode/fake/ya.make12
-rw-r--r--library/cpp/monlib/encode/format.cpp202
-rw-r--r--library/cpp/monlib/encode/format.h166
-rw-r--r--library/cpp/monlib/encode/format_ut.cpp136
-rw-r--r--library/cpp/monlib/encode/fuzz/ya.make5
-rw-r--r--library/cpp/monlib/encode/json/fuzz/main.cpp16
-rw-r--r--library/cpp/monlib/encode/json/fuzz/ya.make19
-rw-r--r--library/cpp/monlib/encode/json/json.h29
-rw-r--r--library/cpp/monlib/encode/json/json_decoder.cpp1162
-rw-r--r--library/cpp/monlib/encode/json/json_decoder_ut.cpp179
-rw-r--r--library/cpp/monlib/encode/json/json_encoder.cpp556
-rw-r--r--library/cpp/monlib/encode/json/json_ut.cpp1290
-rw-r--r--library/cpp/monlib/encode/json/typed_point.h123
-rw-r--r--library/cpp/monlib/encode/json/ut/buffered_test.json36
-rw-r--r--library/cpp/monlib/encode/json/ut/buffered_ts_merge.json13
-rw-r--r--library/cpp/monlib/encode/json/ut/crash.jsonbin0 -> 655 bytes
-rw-r--r--library/cpp/monlib/encode/json/ut/empty_series.json12
-rw-r--r--library/cpp/monlib/encode/json/ut/expected.json92
-rw-r--r--library/cpp/monlib/encode/json/ut/expected_buffered.json92
-rw-r--r--library/cpp/monlib/encode/json/ut/expected_cloud.json92
-rw-r--r--library/cpp/monlib/encode/json/ut/expected_cloud_buffered.json92
-rw-r--r--library/cpp/monlib/encode/json/ut/hist_crash.jsonbin0 -> 213 bytes
-rw-r--r--library/cpp/monlib/encode/json/ut/histogram_timeseries.json61
-rw-r--r--library/cpp/monlib/encode/json/ut/histogram_value.json33
-rw-r--r--library/cpp/monlib/encode/json/ut/histogram_value_inf_before_bounds.json33
-rw-r--r--library/cpp/monlib/encode/json/ut/int_gauge.json31
-rw-r--r--library/cpp/monlib/encode/json/ut/log_histogram_timeseries.json47
-rw-r--r--library/cpp/monlib/encode/json/ut/log_histogram_value.json26
-rw-r--r--library/cpp/monlib/encode/json/ut/merged.json14
-rw-r--r--library/cpp/monlib/encode/json/ut/metrics.json43
-rw-r--r--library/cpp/monlib/encode/json/ut/named_metrics.json22
-rw-r--r--library/cpp/monlib/encode/json/ut/sensors.json40
-rw-r--r--library/cpp/monlib/encode/json/ut/summary_inf.json21
-rw-r--r--library/cpp/monlib/encode/json/ut/summary_timeseries.json37
-rw-r--r--library/cpp/monlib/encode/json/ut/summary_value.json21
-rw-r--r--library/cpp/monlib/encode/json/ut/test_decode_to_encode.json16
-rw-r--r--library/cpp/monlib/encode/json/ut/ya.make46
-rw-r--r--library/cpp/monlib/encode/json/ya.make21
-rw-r--r--library/cpp/monlib/encode/legacy_protobuf/legacy_proto_decoder.cpp527
-rw-r--r--library/cpp/monlib/encode/legacy_protobuf/legacy_protobuf.h16
-rw-r--r--library/cpp/monlib/encode/legacy_protobuf/legacy_protobuf_ut.cpp422
-rw-r--r--library/cpp/monlib/encode/legacy_protobuf/protos/metric_meta.proto73
-rw-r--r--library/cpp/monlib/encode/legacy_protobuf/protos/python/ya.make3
-rw-r--r--library/cpp/monlib/encode/legacy_protobuf/protos/ya.make13
-rw-r--r--library/cpp/monlib/encode/legacy_protobuf/ut/test_cases.proto90
-rw-r--r--library/cpp/monlib/encode/legacy_protobuf/ut/ya.make18
-rw-r--r--library/cpp/monlib/encode/legacy_protobuf/ya.make16
-rw-r--r--library/cpp/monlib/encode/prometheus/fuzz/main.cpp18
-rw-r--r--library/cpp/monlib/encode/prometheus/fuzz/ya.make16
-rw-r--r--library/cpp/monlib/encode/prometheus/prometheus.h18
-rw-r--r--library/cpp/monlib/encode/prometheus/prometheus_decoder.cpp597
-rw-r--r--library/cpp/monlib/encode/prometheus/prometheus_decoder_ut.cpp478
-rw-r--r--library/cpp/monlib/encode/prometheus/prometheus_encoder.cpp413
-rw-r--r--library/cpp/monlib/encode/prometheus/prometheus_encoder_ut.cpp414
-rw-r--r--library/cpp/monlib/encode/prometheus/prometheus_model.h70
-rw-r--r--library/cpp/monlib/encode/prometheus/ut/ya.make17
-rw-r--r--library/cpp/monlib/encode/prometheus/ya.make17
-rw-r--r--library/cpp/monlib/encode/protobuf/protobuf.h16
-rw-r--r--library/cpp/monlib/encode/protobuf/protobuf_encoder.cpp248
-rw-r--r--library/cpp/monlib/encode/protobuf/protos/samples.proto91
-rw-r--r--library/cpp/monlib/encode/protobuf/protos/ya.make14
-rw-r--r--library/cpp/monlib/encode/protobuf/ya.make17
-rw-r--r--library/cpp/monlib/encode/spack/compression.cpp383
-rw-r--r--library/cpp/monlib/encode/spack/compression.h19
-rw-r--r--library/cpp/monlib/encode/spack/fuzz/main.cpp20
-rw-r--r--library/cpp/monlib/encode/spack/fuzz/ya.make21
-rw-r--r--library/cpp/monlib/encode/spack/spack_v1.h115
-rw-r--r--library/cpp/monlib/encode/spack/spack_v1_decoder.cpp458
-rw-r--r--library/cpp/monlib/encode/spack/spack_v1_encoder.cpp318
-rw-r--r--library/cpp/monlib/encode/spack/spack_v1_ut.cpp845
-rw-r--r--library/cpp/monlib/encode/spack/ut/ya.make16
-rw-r--r--library/cpp/monlib/encode/spack/varint.cpp79
-rw-r--r--library/cpp/monlib/encode/spack/varint.h23
-rw-r--r--library/cpp/monlib/encode/spack/ya.make25
-rw-r--r--library/cpp/monlib/encode/text/text.h9
-rw-r--r--library/cpp/monlib/encode/text/text_encoder.cpp226
-rw-r--r--library/cpp/monlib/encode/text/text_encoder_ut.cpp283
-rw-r--r--library/cpp/monlib/encode/text/ut/ya.make12
-rw-r--r--library/cpp/monlib/encode/text/ya.make16
-rw-r--r--library/cpp/monlib/encode/unistat/unistat.h13
-rw-r--r--library/cpp/monlib/encode/unistat/unistat_decoder.cpp253
-rw-r--r--library/cpp/monlib/encode/unistat/unistat_ut.cpp223
-rw-r--r--library/cpp/monlib/encode/unistat/ut/ya.make16
-rw-r--r--library/cpp/monlib/encode/unistat/ya.make18
-rw-r--r--library/cpp/monlib/encode/ut/ya.make12
-rw-r--r--library/cpp/monlib/encode/ya.make20
-rw-r--r--library/cpp/monlib/exception/exception.cpp1
-rw-r--r--library/cpp/monlib/exception/exception.h13
-rw-r--r--library/cpp/monlib/exception/ya.make12
-rw-r--r--library/cpp/monlib/messagebus/mon_messagebus.cpp11
-rw-r--r--library/cpp/monlib/messagebus/mon_messagebus.h46
-rw-r--r--library/cpp/monlib/messagebus/mon_service_messagebus.cpp8
-rw-r--r--library/cpp/monlib/messagebus/mon_service_messagebus.h46
-rw-r--r--library/cpp/monlib/messagebus/ya.make16
-rw-r--r--library/cpp/monlib/metrics/atomics_array.h52
-rw-r--r--library/cpp/monlib/metrics/ewma.cpp150
-rw-r--r--library/cpp/monlib/metrics/ewma.h47
-rw-r--r--library/cpp/monlib/metrics/ewma_ut.cpp112
-rw-r--r--library/cpp/monlib/metrics/fake.cpp100
-rw-r--r--library/cpp/monlib/metrics/fake.h165
-rw-r--r--library/cpp/monlib/metrics/fake_ut.cpp34
-rw-r--r--library/cpp/monlib/metrics/fwd.h40
-rw-r--r--library/cpp/monlib/metrics/histogram_collector.h119
-rw-r--r--library/cpp/monlib/metrics/histogram_collector_explicit.cpp55
-rw-r--r--library/cpp/monlib/metrics/histogram_collector_exponential.cpp68
-rw-r--r--library/cpp/monlib/metrics/histogram_collector_linear.cpp67
-rw-r--r--library/cpp/monlib/metrics/histogram_collector_ut.cpp114
-rw-r--r--library/cpp/monlib/metrics/histogram_snapshot.cpp63
-rw-r--r--library/cpp/monlib/metrics/histogram_snapshot.h210
-rw-r--r--library/cpp/monlib/metrics/labels.cpp82
-rw-r--r--library/cpp/monlib/metrics/labels.h483
-rw-r--r--library/cpp/monlib/metrics/labels_ut.cpp194
-rw-r--r--library/cpp/monlib/metrics/log_histogram_collector.h158
-rw-r--r--library/cpp/monlib/metrics/log_histogram_collector_ut.cpp38
-rw-r--r--library/cpp/monlib/metrics/log_histogram_snapshot.cpp35
-rw-r--r--library/cpp/monlib/metrics/log_histogram_snapshot.h71
-rw-r--r--library/cpp/monlib/metrics/metric.h388
-rw-r--r--library/cpp/monlib/metrics/metric_consumer.cpp15
-rw-r--r--library/cpp/monlib/metrics/metric_consumer.h40
-rw-r--r--library/cpp/monlib/metrics/metric_registry.cpp225
-rw-r--r--library/cpp/monlib/metrics/metric_registry.h122
-rw-r--r--library/cpp/monlib/metrics/metric_registry_ut.cpp302
-rw-r--r--library/cpp/monlib/metrics/metric_sub_registry.h116
-rw-r--r--library/cpp/monlib/metrics/metric_sub_registry_ut.cpp65
-rw-r--r--library/cpp/monlib/metrics/metric_type.cpp57
-rw-r--r--library/cpp/monlib/metrics/metric_type.h25
-rw-r--r--library/cpp/monlib/metrics/metric_value.cpp27
-rw-r--r--library/cpp/monlib/metrics/metric_value.h542
-rw-r--r--library/cpp/monlib/metrics/metric_value_type.h16
-rw-r--r--library/cpp/monlib/metrics/metric_value_ut.cpp507
-rw-r--r--library/cpp/monlib/metrics/summary_collector.cpp1
-rw-r--r--library/cpp/monlib/metrics/summary_collector.h104
-rw-r--r--library/cpp/monlib/metrics/summary_collector_ut.cpp64
-rw-r--r--library/cpp/monlib/metrics/summary_snapshot.cpp34
-rw-r--r--library/cpp/monlib/metrics/summary_snapshot.h72
-rw-r--r--library/cpp/monlib/metrics/timer.h127
-rw-r--r--library/cpp/monlib/metrics/timer_ut.cpp157
-rw-r--r--library/cpp/monlib/metrics/ut/histograms.json61
-rw-r--r--library/cpp/monlib/metrics/ut/ya.make32
-rw-r--r--library/cpp/monlib/metrics/ya.make26
-rw-r--r--library/cpp/monlib/service/auth.cpp22
-rw-r--r--library/cpp/monlib/service/auth.h48
-rw-r--r--library/cpp/monlib/service/auth/tvm/auth.cpp93
-rw-r--r--library/cpp/monlib/service/auth/tvm/auth.h33
-rw-r--r--library/cpp/monlib/service/auth/tvm/ya.make14
-rw-r--r--library/cpp/monlib/service/format.cpp1
-rw-r--r--library/cpp/monlib/service/format.h86
-rw-r--r--library/cpp/monlib/service/mon_service_http_request.cpp85
-rw-r--r--library/cpp/monlib/service/mon_service_http_request.h90
-rw-r--r--library/cpp/monlib/service/monservice.cpp129
-rw-r--r--library/cpp/monlib/service/monservice.h73
-rw-r--r--library/cpp/monlib/service/pages/diag_mon_page.cpp9
-rw-r--r--library/cpp/monlib/service/pages/diag_mon_page.h16
-rw-r--r--library/cpp/monlib/service/pages/html_mon_page.cpp60
-rw-r--r--library/cpp/monlib/service/pages/html_mon_page.h25
-rw-r--r--library/cpp/monlib/service/pages/index_mon_page.cpp151
-rw-r--r--library/cpp/monlib/service/pages/index_mon_page.h38
-rw-r--r--library/cpp/monlib/service/pages/mon_page.cpp36
-rw-r--r--library/cpp/monlib/service/pages/mon_page.h66
-rw-r--r--library/cpp/monlib/service/pages/pre_mon_page.cpp18
-rw-r--r--library/cpp/monlib/service/pages/pre_mon_page.h27
-rw-r--r--library/cpp/monlib/service/pages/registry_mon_page.cpp46
-rw-r--r--library/cpp/monlib/service/pages/registry_mon_page.h32
-rw-r--r--library/cpp/monlib/service/pages/resource_mon_page.cpp49
-rw-r--r--library/cpp/monlib/service/pages/resource_mon_page.h43
-rw-r--r--library/cpp/monlib/service/pages/tablesorter/css_mon_page.h13
-rw-r--r--library/cpp/monlib/service/pages/tablesorter/js_mon_page.h13
-rw-r--r--library/cpp/monlib/service/pages/tablesorter/resources/jquery.tablesorter.css2
-rw-r--r--library/cpp/monlib/service/pages/tablesorter/resources/jquery.tablesorter.js3
-rw-r--r--library/cpp/monlib/service/pages/tablesorter/ya.make14
-rw-r--r--library/cpp/monlib/service/pages/templates.cpp35
-rw-r--r--library/cpp/monlib/service/pages/templates.h268
-rw-r--r--library/cpp/monlib/service/pages/version_mon_page.cpp16
-rw-r--r--library/cpp/monlib/service/pages/version_mon_page.h15
-rw-r--r--library/cpp/monlib/service/pages/ya.make31
-rw-r--r--library/cpp/monlib/service/service.cpp268
-rw-r--r--library/cpp/monlib/service/service.h112
-rw-r--r--library/cpp/monlib/service/ya.make28
-rw-r--r--library/cpp/monlib/ya.make45
-rw-r--r--library/cpp/object_factory/object_factory.cpp1
-rw-r--r--library/cpp/object_factory/object_factory.h243
-rw-r--r--library/cpp/object_factory/object_factory_ut.cpp189
-rw-r--r--library/cpp/object_factory/ut/ya.make15
-rw-r--r--library/cpp/object_factory/ya.make9
-rw-r--r--library/cpp/on_disk/chunks/chunked_helpers.cpp67
-rw-r--r--library/cpp/on_disk/chunks/chunked_helpers.h674
-rw-r--r--library/cpp/on_disk/chunks/chunks_ut.cpp329
-rw-r--r--library/cpp/on_disk/chunks/reader.cpp52
-rw-r--r--library/cpp/on_disk/chunks/reader.h57
-rw-r--r--library/cpp/on_disk/chunks/ut/ya.make9
-rw-r--r--library/cpp/on_disk/chunks/writer.cpp46
-rw-r--r--library/cpp/on_disk/chunks/writer.h57
-rw-r--r--library/cpp/on_disk/chunks/ya.make11
-rw-r--r--library/cpp/on_disk/ya.make31
-rw-r--r--library/cpp/openssl/holders/bio.cpp29
-rw-r--r--library/cpp/openssl/holders/bio.h25
-rw-r--r--library/cpp/openssl/holders/bn.h13
-rw-r--r--library/cpp/openssl/holders/evp.h13
-rw-r--r--library/cpp/openssl/holders/hmac.h10
-rw-r--r--library/cpp/openssl/holders/holder.h32
-rw-r--r--library/cpp/openssl/holders/ut/evp_ut.cpp15
-rw-r--r--library/cpp/openssl/holders/ut/hmac_ut.cpp10
-rw-r--r--library/cpp/openssl/holders/ut/ya.make10
-rw-r--r--library/cpp/openssl/holders/x509_vfy.cpp30
-rw-r--r--library/cpp/openssl/holders/x509_vfy.h25
-rw-r--r--library/cpp/openssl/holders/ya.make16
-rw-r--r--library/cpp/openssl/init/init.cpp66
-rw-r--r--library/cpp/openssl/init/init.h3
-rw-r--r--library/cpp/openssl/init/ya.make13
-rw-r--r--library/cpp/openssl/io/stream.cpp329
-rw-r--r--library/cpp/openssl/io/stream.h50
-rw-r--r--library/cpp/openssl/io/ut/builtin_ut.cpp9
-rw-r--r--library/cpp/openssl/io/ut/ya.make12
-rw-r--r--library/cpp/openssl/io/ya.make16
-rw-r--r--library/cpp/openssl/method/io.cpp122
-rw-r--r--library/cpp/openssl/method/io.h31
-rw-r--r--library/cpp/openssl/method/ut/io_ut.cpp52
-rw-r--r--library/cpp/openssl/method/ut/ya.make9
-rw-r--r--library/cpp/openssl/method/ya.make14
-rw-r--r--library/cpp/openssl/ya.make13
-rw-r--r--library/cpp/packedtypes/fixed_point.h71
-rw-r--r--library/cpp/packedtypes/longs.cpp1
-rw-r--r--library/cpp/packedtypes/longs.h347
-rw-r--r--library/cpp/packedtypes/longs_ut.cpp68
-rw-r--r--library/cpp/packedtypes/packed.h98
-rw-r--r--library/cpp/packedtypes/packed_ut.cpp130
-rw-r--r--library/cpp/packedtypes/packedfloat.cpp18
-rw-r--r--library/cpp/packedtypes/packedfloat.h217
-rw-r--r--library/cpp/packedtypes/packedfloat_ut.cpp130
-rw-r--r--library/cpp/packedtypes/ut/ya.make19
-rw-r--r--library/cpp/packedtypes/ya.make21
-rw-r--r--library/cpp/packedtypes/zigzag.h21
-rw-r--r--library/cpp/packedtypes/zigzag_ut.cpp38
-rw-r--r--library/cpp/packers/README.md2
-rw-r--r--library/cpp/packers/packers.cpp20
-rw-r--r--library/cpp/packers/packers.h611
-rw-r--r--library/cpp/packers/proto_packer.cpp1
-rw-r--r--library/cpp/packers/proto_packer.h50
-rw-r--r--library/cpp/packers/region_packer.cpp1
-rw-r--r--library/cpp/packers/region_packer.h42
-rw-r--r--library/cpp/packers/ut/packers_ut.cpp110
-rw-r--r--library/cpp/packers/ut/proto_packer_ut.cpp104
-rw-r--r--library/cpp/packers/ut/region_packer_ut.cpp40
-rw-r--r--library/cpp/packers/ut/test.proto11
-rw-r--r--library/cpp/packers/ut/ya.make12
-rw-r--r--library/cpp/packers/ya.make11
-rw-r--r--library/cpp/pop_count/benchmark/main.cpp52
-rw-r--r--library/cpp/pop_count/benchmark/ya.make14
-rw-r--r--library/cpp/pop_count/popcount.cpp30
-rw-r--r--library/cpp/pop_count/popcount.h105
-rw-r--r--library/cpp/pop_count/popcount_ut.cpp70
-rw-r--r--library/cpp/pop_count/ut/ya.make9
-rw-r--r--library/cpp/pop_count/ya.make9
-rw-r--r--library/cpp/protobuf/interop/cast.cpp23
-rw-r--r--library/cpp/protobuf/interop/cast.h15
-rw-r--r--library/cpp/protobuf/interop/ut/cast_ut.cpp52
-rw-r--r--library/cpp/protobuf/interop/ut/ya.make15
-rw-r--r--library/cpp/protobuf/interop/ya.make15
-rw-r--r--library/cpp/protobuf/json/README1
-rw-r--r--library/cpp/protobuf/json/config.h164
-rw-r--r--library/cpp/protobuf/json/field_option.h40
-rw-r--r--library/cpp/protobuf/json/filter.h48
-rw-r--r--library/cpp/protobuf/json/inline.h115
-rw-r--r--library/cpp/protobuf/json/json2proto.cpp428
-rw-r--r--library/cpp/protobuf/json/json2proto.h222
-rw-r--r--library/cpp/protobuf/json/json_output.h79
-rw-r--r--library/cpp/protobuf/json/json_output_create.cpp32
-rw-r--r--library/cpp/protobuf/json/json_output_create.h22
-rw-r--r--library/cpp/protobuf/json/json_value_output.cpp106
-rw-r--r--library/cpp/protobuf/json/json_value_output.h63
-rw-r--r--library/cpp/protobuf/json/json_writer_output.cpp22
-rw-r--r--library/cpp/protobuf/json/json_writer_output.h103
-rw-r--r--library/cpp/protobuf/json/name_generator.cpp1
-rw-r--r--library/cpp/protobuf/json/name_generator.h18
-rw-r--r--library/cpp/protobuf/json/proto2json.cpp56
-rw-r--r--library/cpp/protobuf/json/proto2json.h78
-rw-r--r--library/cpp/protobuf/json/proto2json_printer.cpp517
-rw-r--r--library/cpp/protobuf/json/proto2json_printer.h68
-rw-r--r--library/cpp/protobuf/json/string_transform.cpp64
-rw-r--r--library/cpp/protobuf/json/string_transform.h111
-rw-r--r--library/cpp/protobuf/json/ut/fields.incl23
-rw-r--r--library/cpp/protobuf/json/ut/filter_ut.cpp93
-rw-r--r--library/cpp/protobuf/json/ut/filter_ut.proto20
-rw-r--r--library/cpp/protobuf/json/ut/inline_ut.cpp122
-rw-r--r--library/cpp/protobuf/json/ut/inline_ut.proto29
-rw-r--r--library/cpp/protobuf/json/ut/json.h69
-rw-r--r--library/cpp/protobuf/json/ut/json2proto_ut.cpp1147
-rw-r--r--library/cpp/protobuf/json/ut/proto.h62
-rw-r--r--library/cpp/protobuf/json/ut/proto2json_ut.cpp1022
-rw-r--r--library/cpp/protobuf/json/ut/repeated_fields.incl21
-rw-r--r--library/cpp/protobuf/json/ut/string_transform_ut.cpp106
-rw-r--r--library/cpp/protobuf/json/ut/test.proto203
-rw-r--r--library/cpp/protobuf/json/ut/util_ut.cpp42
-rw-r--r--library/cpp/protobuf/json/ut/ya.make23
-rw-r--r--library/cpp/protobuf/json/util.cpp76
-rw-r--r--library/cpp/protobuf/json/util.h14
-rw-r--r--library/cpp/protobuf/json/ya.make25
-rw-r--r--library/cpp/protobuf/util/cast.h156
-rw-r--r--library/cpp/protobuf/util/is_equal.cpp163
-rw-r--r--library/cpp/protobuf/util/is_equal.h33
-rw-r--r--library/cpp/protobuf/util/is_equal_ut.cpp88
-rw-r--r--library/cpp/protobuf/util/iterators.h53
-rw-r--r--library/cpp/protobuf/util/iterators_ut.cpp52
-rw-r--r--library/cpp/protobuf/util/merge.cpp46
-rw-r--r--library/cpp/protobuf/util/merge.h22
-rw-r--r--library/cpp/protobuf/util/merge_ut.cpp83
-rw-r--r--library/cpp/protobuf/util/path.cpp61
-rw-r--r--library/cpp/protobuf/util/path.h52
-rw-r--r--library/cpp/protobuf/util/pb_io.cpp221
-rw-r--r--library/cpp/protobuf/util/pb_io.h138
-rw-r--r--library/cpp/protobuf/util/pb_io_ut.cpp418
-rw-r--r--library/cpp/protobuf/util/pb_utils.h11
-rw-r--r--library/cpp/protobuf/util/proto/merge.proto11
-rw-r--r--library/cpp/protobuf/util/proto/ya.make11
-rw-r--r--library/cpp/protobuf/util/repeated_field_utils.h96
-rw-r--r--library/cpp/protobuf/util/repeated_field_utils_ut.cpp46
-rw-r--r--library/cpp/protobuf/util/simple_reflection.cpp70
-rw-r--r--library/cpp/protobuf/util/simple_reflection.h289
-rw-r--r--library/cpp/protobuf/util/simple_reflection_ut.cpp359
-rw-r--r--library/cpp/protobuf/util/sort.h28
-rw-r--r--library/cpp/protobuf/util/traits.h320
-rw-r--r--library/cpp/protobuf/util/ut/common_ut.proto72
-rw-r--r--library/cpp/protobuf/util/ut/extensions.proto22
-rw-r--r--library/cpp/protobuf/util/ut/sample_for_is_equal.proto8
-rw-r--r--library/cpp/protobuf/util/ut/sample_for_simple_reflection.proto25
-rw-r--r--library/cpp/protobuf/util/ut/ya.make19
-rw-r--r--library/cpp/protobuf/util/walk.cpp72
-rw-r--r--library/cpp/protobuf/util/walk.h33
-rw-r--r--library/cpp/protobuf/util/walk_ut.cpp158
-rw-r--r--library/cpp/protobuf/util/ya.make26
-rw-r--r--library/cpp/protobuf/ya.make19
-rw-r--r--library/cpp/random_provider/random_provider.cpp75
-rw-r--r--library/cpp/random_provider/random_provider.h14
-rw-r--r--library/cpp/random_provider/ya.make13
-rw-r--r--library/cpp/regex/hyperscan/hyperscan.cpp282
-rw-r--r--library/cpp/regex/hyperscan/hyperscan.h160
-rw-r--r--library/cpp/regex/hyperscan/ut/hyperscan_ut.cpp231
-rw-r--r--library/cpp/regex/hyperscan/ut/ya.make13
-rw-r--r--library/cpp/regex/hyperscan/ya.make19
-rw-r--r--library/cpp/regex/pcre/README.md59
-rw-r--r--library/cpp/regex/pcre/benchmark/main.cpp80
-rw-r--r--library/cpp/regex/pcre/benchmark/ya.make14
-rw-r--r--library/cpp/regex/pcre/pcre.cpp1
-rw-r--r--library/cpp/regex/pcre/pcre.h191
-rw-r--r--library/cpp/regex/pcre/pcre_ut.cpp89
-rw-r--r--library/cpp/regex/pcre/pcre_ut_base.h38
-rw-r--r--library/cpp/regex/pcre/regexp.cpp317
-rw-r--r--library/cpp/regex/pcre/regexp.h63
-rw-r--r--library/cpp/regex/pcre/regexp_ut.cpp103
-rw-r--r--library/cpp/regex/pcre/traits.h99
-rw-r--r--library/cpp/regex/pcre/ut/ya.make10
-rw-r--r--library/cpp/regex/pcre/ya.make23
-rw-r--r--library/cpp/regex/pire/extraencodings.cpp81
-rw-r--r--library/cpp/regex/pire/inline/ya.make22
-rw-r--r--library/cpp/regex/pire/pcre2pire.cpp110
-rw-r--r--library/cpp/regex/pire/pcre2pire.h19
-rw-r--r--library/cpp/regex/pire/pire.h76
-rw-r--r--library/cpp/regex/pire/regexp.h337
-rw-r--r--library/cpp/regex/pire/ut/regexp_ut.cpp318
-rw-r--r--library/cpp/regex/pire/ut/ya.make44
-rw-r--r--library/cpp/regex/pire/ya.make40
-rw-r--r--library/cpp/regex/ya.make14
-rw-r--r--library/cpp/resource/README.md24
-rw-r--r--library/cpp/resource/registry.cpp113
-rw-r--r--library/cpp/resource/registry.h35
-rw-r--r--library/cpp/resource/resource.cpp57
-rw-r--r--library/cpp/resource/resource.h22
-rw-r--r--library/cpp/resource/ut/lib/data1
-rw-r--r--library/cpp/resource/ut/lib/ya.make9
-rw-r--r--library/cpp/resource/ut/resource_ut.cpp8
-rw-r--r--library/cpp/resource/ut/ya.make9
-rw-r--r--library/cpp/resource/ya.make15
-rw-r--r--library/cpp/retry/protos/retry_options.proto9
-rw-r--r--library/cpp/retry/protos/ya.make16
-rw-r--r--library/cpp/retry/retry.cpp26
-rw-r--r--library/cpp/retry/retry.h133
-rw-r--r--library/cpp/retry/retry_ut.cpp117
-rw-r--r--library/cpp/retry/ut/ya.make13
-rw-r--r--library/cpp/retry/utils.cpp20
-rw-r--r--library/cpp/retry/utils.h10
-rw-r--r--library/cpp/retry/ya.make17
-rw-r--r--library/cpp/scheme/README1
-rw-r--r--library/cpp/scheme/domscheme_traits.h228
-rw-r--r--library/cpp/scheme/fwd.h7
-rw-r--r--library/cpp/scheme/scheme.cpp598
-rw-r--r--library/cpp/scheme/scheme.h538
-rw-r--r--library/cpp/scheme/scheme_cast.h321
-rw-r--r--library/cpp/scheme/scimpl.h858
-rw-r--r--library/cpp/scheme/scimpl_defs.h140
-rw-r--r--library/cpp/scheme/scimpl_json_read.cpp229
-rw-r--r--library/cpp/scheme/scimpl_json_write.cpp193
-rw-r--r--library/cpp/scheme/scimpl_private.cpp74
-rw-r--r--library/cpp/scheme/scimpl_private.h114
-rw-r--r--library/cpp/scheme/scimpl_protobuf.cpp329
-rw-r--r--library/cpp/scheme/scimpl_select.rl6270
-rw-r--r--library/cpp/scheme/tests/fuzz_json/fuzz_json.cpp6
-rw-r--r--library/cpp/scheme/tests/fuzz_json/lib/fuzz_json.cpp115
-rw-r--r--library/cpp/scheme/tests/fuzz_json/lib/fuzz_json.h7
-rw-r--r--library/cpp/scheme/tests/fuzz_json/lib/ya.make18
-rw-r--r--library/cpp/scheme/tests/fuzz_json/ya.make20
-rw-r--r--library/cpp/scheme/tests/fuzz_ops/fuzz_ops.cpp6
-rw-r--r--library/cpp/scheme/tests/fuzz_ops/lib/fuzz_ops.cpp37
-rw-r--r--library/cpp/scheme/tests/fuzz_ops/lib/fuzz_ops.h7
-rw-r--r--library/cpp/scheme/tests/fuzz_ops/lib/vm_apply.cpp302
-rw-r--r--library/cpp/scheme/tests/fuzz_ops/lib/vm_apply.h9
-rw-r--r--library/cpp/scheme/tests/fuzz_ops/lib/vm_defs.cpp168
-rw-r--r--library/cpp/scheme/tests/fuzz_ops/lib/vm_defs.h277
-rw-r--r--library/cpp/scheme/tests/fuzz_ops/lib/vm_parse.cpp265
-rw-r--r--library/cpp/scheme/tests/fuzz_ops/lib/vm_parse.h16
-rw-r--r--library/cpp/scheme/tests/fuzz_ops/lib/ya.make23
-rw-r--r--library/cpp/scheme/tests/fuzz_ops/ut/vm_parse_ut.cpp225
-rw-r--r--library/cpp/scheme/tests/fuzz_ops/ut/ya.make15
-rw-r--r--library/cpp/scheme/tests/fuzz_ops/ya.make18
-rw-r--r--library/cpp/scheme/tests/ut/fuzz_ops_found_bugs_ut.cpp12
-rw-r--r--library/cpp/scheme/tests/ut/scheme_cast_ut.cpp162
-rw-r--r--library/cpp/scheme/tests/ut/scheme_json_ut.cpp161
-rw-r--r--library/cpp/scheme/tests/ut/scheme_merge_ut.cpp172
-rw-r--r--library/cpp/scheme/tests/ut/scheme_path_ut.cpp159
-rw-r--r--library/cpp/scheme/tests/ut/scheme_proto_ut.cpp220
-rw-r--r--library/cpp/scheme/tests/ut/scheme_ut.cpp879
-rw-r--r--library/cpp/scheme/tests/ut/scheme_ut.proto84
-rw-r--r--library/cpp/scheme/tests/ut/ya.make24
-rw-r--r--library/cpp/scheme/tests/ya.make13
-rw-r--r--library/cpp/scheme/ut_utils/scheme_ut_utils.cpp44
-rw-r--r--library/cpp/scheme/ut_utils/scheme_ut_utils.h55
-rw-r--r--library/cpp/scheme/ut_utils/ya.make16
-rw-r--r--library/cpp/scheme/util/scheme_holder.cpp1
-rw-r--r--library/cpp/scheme/util/scheme_holder.h76
-rw-r--r--library/cpp/scheme/util/utils.cpp23
-rw-r--r--library/cpp/scheme/util/utils.h23
-rw-r--r--library/cpp/scheme/util/ya.make14
-rw-r--r--library/cpp/scheme/ya.make25
-rw-r--r--library/cpp/sighandler/async_signals_handler.cpp245
-rw-r--r--library/cpp/sighandler/async_signals_handler.h14
-rw-r--r--library/cpp/sighandler/ya.make10
-rw-r--r--library/cpp/sliding_window/README.md30
-rw-r--r--library/cpp/sliding_window/sliding_window.cpp1
-rw-r--r--library/cpp/sliding_window/sliding_window.h224
-rw-r--r--library/cpp/sliding_window/sliding_window_ut.cpp132
-rw-r--r--library/cpp/sliding_window/ut/ya.make9
-rw-r--r--library/cpp/sliding_window/ya.make10
-rw-r--r--library/cpp/sse/README.md7
-rw-r--r--library/cpp/sse/powerpc.h1000
-rw-r--r--library/cpp/sse/sse.cpp1
-rw-r--r--library/cpp/sse/sse.h33
-rw-r--r--library/cpp/sse/sse2neon.h1045
-rw-r--r--library/cpp/sse/ut/test.cpp2088
-rw-r--r--library/cpp/sse/ut/ya.make13
-rw-r--r--library/cpp/sse/ya.make12
-rw-r--r--library/cpp/streams/brotli/brotli.cpp231
-rw-r--r--library/cpp/streams/brotli/brotli.h52
-rw-r--r--library/cpp/streams/brotli/brotli_ut.cpp89
-rw-r--r--library/cpp/streams/brotli/ut/ya.make12
-rw-r--r--library/cpp/streams/brotli/ya.make17
-rw-r--r--library/cpp/streams/bzip2/bzip2.cpp204
-rw-r--r--library/cpp/streams/bzip2/bzip2.h53
-rw-r--r--library/cpp/streams/bzip2/bzip2_ut.cpp41
-rw-r--r--library/cpp/streams/bzip2/ut/ya.make12
-rw-r--r--library/cpp/streams/bzip2/ya.make16
-rw-r--r--library/cpp/streams/lz/lz.cpp731
-rw-r--r--library/cpp/streams/lz/lz.h242
-rw-r--r--library/cpp/streams/lz/lz_ut.cpp287
-rw-r--r--library/cpp/streams/lz/ut/random.databin0 -> 8196 bytes
-rw-r--r--library/cpp/streams/lz/ut/request.data1
-rw-r--r--library/cpp/streams/lz/ut/ya.make18
-rw-r--r--library/cpp/streams/lz/ut/yq_609.databin0 -> 721 bytes
-rw-r--r--library/cpp/streams/lz/ya.make20
-rw-r--r--library/cpp/streams/lzma/lzma.cpp520
-rw-r--r--library/cpp/streams/lzma/lzma.h37
-rw-r--r--library/cpp/streams/lzma/lzma_ut.cpp127
-rw-r--r--library/cpp/streams/lzma/ut/ya.make12
-rw-r--r--library/cpp/streams/lzma/ya.make16
-rw-r--r--library/cpp/streams/ya.make26
-rw-r--r--library/cpp/streams/zc_memory_input/ya.make12
-rw-r--r--library/cpp/streams/zc_memory_input/zc_memory_input.cpp1
-rw-r--r--library/cpp/streams/zc_memory_input/zc_memory_input.h48
-rw-r--r--library/cpp/streams/zstd/ut/ya.make12
-rw-r--r--library/cpp/streams/zstd/ya.make16
-rw-r--r--library/cpp/streams/zstd/zstd.cpp173
-rw-r--r--library/cpp/streams/zstd/zstd.h53
-rw-r--r--library/cpp/streams/zstd/zstd_ut.cpp94
-rw-r--r--library/cpp/string_utils/base64/base64.cpp268
-rw-r--r--library/cpp/string_utils/base64/base64.h130
-rw-r--r--library/cpp/string_utils/base64/base64_decode_uneven_ut.cpp46
-rw-r--r--library/cpp/string_utils/base64/base64_ut.cpp497
-rw-r--r--library/cpp/string_utils/base64/bench/main.cpp326
-rw-r--r--library/cpp/string_utils/base64/bench/metrics/main.py5
-rw-r--r--library/cpp/string_utils/base64/bench/metrics/ya.make20
-rw-r--r--library/cpp/string_utils/base64/bench/ya.make16
-rw-r--r--library/cpp/string_utils/base64/fuzz/generic/ya.make12
-rw-r--r--library/cpp/string_utils/base64/fuzz/lib/main.cpp13
-rw-r--r--library/cpp/string_utils/base64/fuzz/lib/ya.make16
-rw-r--r--library/cpp/string_utils/base64/fuzz/uneven/main.cpp10
-rw-r--r--library/cpp/string_utils/base64/fuzz/uneven/ya.make15
-rw-r--r--library/cpp/string_utils/base64/fuzz/ya.make10
-rw-r--r--library/cpp/string_utils/base64/ut/ya.make22
-rw-r--r--library/cpp/string_utils/base64/ya.make23
-rw-r--r--library/cpp/string_utils/indent_text/indent_text.cpp25
-rw-r--r--library/cpp/string_utils/indent_text/indent_text.h6
-rw-r--r--library/cpp/string_utils/indent_text/ya.make9
-rw-r--r--library/cpp/string_utils/levenshtein_diff/levenshtein_diff.cpp1
-rw-r--r--library/cpp/string_utils/levenshtein_diff/levenshtein_diff.h192
-rw-r--r--library/cpp/string_utils/levenshtein_diff/levenshtein_diff_ut.cpp190
-rw-r--r--library/cpp/string_utils/levenshtein_diff/ut/ya.make9
-rw-r--r--library/cpp/string_utils/levenshtein_diff/ya.make13
-rw-r--r--library/cpp/string_utils/parse_size/parse_size.cpp95
-rw-r--r--library/cpp/string_utils/parse_size/parse_size.h33
-rw-r--r--library/cpp/string_utils/parse_size/parse_size_ut.cpp63
-rw-r--r--library/cpp/string_utils/parse_size/ut/ya.make9
-rw-r--r--library/cpp/string_utils/parse_size/ya.make10
-rw-r--r--library/cpp/string_utils/quote/quote.cpp311
-rw-r--r--library/cpp/string_utils/quote/quote.h72
-rw-r--r--library/cpp/string_utils/quote/quote_ut.cpp319
-rw-r--r--library/cpp/string_utils/quote/ut/ya.make9
-rw-r--r--library/cpp/string_utils/quote/ya.make10
-rw-r--r--library/cpp/string_utils/relaxed_escaper/relaxed_escaper.cpp1
-rw-r--r--library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h208
-rw-r--r--library/cpp/string_utils/relaxed_escaper/relaxed_escaper_ut.cpp66
-rw-r--r--library/cpp/string_utils/relaxed_escaper/ut/ya.make9
-rw-r--r--library/cpp/string_utils/relaxed_escaper/ya.make9
-rw-r--r--library/cpp/string_utils/scan/scan.cpp1
-rw-r--r--library/cpp/string_utils/scan/scan.h22
-rw-r--r--library/cpp/string_utils/scan/ya.make11
-rw-r--r--library/cpp/string_utils/url/url.cpp421
-rw-r--r--library/cpp/string_utils/url/url.h170
-rw-r--r--library/cpp/string_utils/url/url_ut.cpp281
-rw-r--r--library/cpp/string_utils/url/ut/ya.make9
-rw-r--r--library/cpp/string_utils/url/ya.make10
-rw-r--r--library/cpp/string_utils/ya.make37
-rw-r--r--library/cpp/string_utils/ztstrbuf/ya.make9
-rw-r--r--library/cpp/string_utils/ztstrbuf/ztstrbuf.cpp8
-rw-r--r--library/cpp/string_utils/ztstrbuf/ztstrbuf.h36
-rw-r--r--library/cpp/svnversion/svn_interface.c1
-rw-r--r--library/cpp/svnversion/svnversion.cpp33
-rw-r--r--library/cpp/svnversion/svnversion.h13
-rw-r--r--library/cpp/svnversion/test/main.cpp30
-rw-r--r--library/cpp/svnversion/test/ya.make6
-rw-r--r--library/cpp/svnversion/ya.make12
-rw-r--r--library/cpp/terminate_handler/sample/exception/main.cpp15
-rw-r--r--library/cpp/terminate_handler/sample/exception/ya.make13
-rw-r--r--library/cpp/terminate_handler/sample/pure-virtual/main.cpp22
-rw-r--r--library/cpp/terminate_handler/sample/pure-virtual/ya.make13
-rw-r--r--library/cpp/terminate_handler/sample/rethrow/main.cpp20
-rw-r--r--library/cpp/terminate_handler/sample/rethrow/ya.make13
-rw-r--r--library/cpp/terminate_handler/sample/segv/main.cpp15
-rw-r--r--library/cpp/terminate_handler/sample/segv/ya.make13
-rw-r--r--library/cpp/terminate_handler/sample/ya.make6
-rw-r--r--library/cpp/terminate_handler/segv_handler.cpp34
-rw-r--r--library/cpp/terminate_handler/segv_handler.h3
-rw-r--r--library/cpp/terminate_handler/terminate_handler.cpp36
-rw-r--r--library/cpp/terminate_handler/ya.make13
-rw-r--r--library/cpp/testing/README.md16
-rw-r--r--library/cpp/testing/benchmark/README.md11
-rw-r--r--library/cpp/testing/benchmark/bench.cpp604
-rw-r--r--library/cpp/testing/benchmark/bench.h92
-rw-r--r--library/cpp/testing/benchmark/dummy.cpp8
-rw-r--r--library/cpp/testing/benchmark/examples/main.cpp215
-rw-r--r--library/cpp/testing/benchmark/examples/metrics/main.py7
-rw-r--r--library/cpp/testing/benchmark/examples/metrics/ya.make20
-rw-r--r--library/cpp/testing/benchmark/examples/ya.make12
-rw-r--r--library/cpp/testing/benchmark/main/main.cpp16
-rw-r--r--library/cpp/testing/benchmark/main/ya.make16
-rw-r--r--library/cpp/testing/benchmark/ya.make22
-rw-r--r--library/cpp/testing/common/env.cpp275
-rw-r--r--library/cpp/testing/common/env.h84
-rw-r--r--library/cpp/testing/common/network.cpp208
-rw-r--r--library/cpp/testing/common/network.h52
-rw-r--r--library/cpp/testing/common/probe.cpp1
-rw-r--r--library/cpp/testing/common/probe.h140
-rw-r--r--library/cpp/testing/common/scope.cpp1
-rw-r--r--library/cpp/testing/common/scope.h39
-rw-r--r--library/cpp/testing/common/ut/env_ut.cpp162
-rw-r--r--library/cpp/testing/common/ut/network_ut.cpp54
-rw-r--r--library/cpp/testing/common/ut/scope_ut.cpp28
-rw-r--r--library/cpp/testing/common/ut/ya.make19
-rw-r--r--library/cpp/testing/common/ya.make23
-rw-r--r--library/cpp/testing/gmock_in_unittest/events.cpp32
-rw-r--r--library/cpp/testing/gmock_in_unittest/events.h8
-rw-r--r--library/cpp/testing/gmock_in_unittest/example_ut/example_ut.cpp105
-rw-r--r--library/cpp/testing/gmock_in_unittest/example_ut/ya.make13
-rw-r--r--library/cpp/testing/gmock_in_unittest/gmock.h5
-rw-r--r--library/cpp/testing/gmock_in_unittest/registration.cpp20
-rw-r--r--library/cpp/testing/gmock_in_unittest/ya.make17
-rw-r--r--library/cpp/testing/gtest_extensions/README.md5
-rw-r--r--library/cpp/testing/gtest_extensions/assertions.cpp90
-rw-r--r--library/cpp/testing/gtest_extensions/assertions.h111
-rw-r--r--library/cpp/testing/gtest_extensions/gtest_extensions.cpp1
-rw-r--r--library/cpp/testing/gtest_extensions/gtest_extensions.h6
-rw-r--r--library/cpp/testing/gtest_extensions/matchers.cpp1
-rw-r--r--library/cpp/testing/gtest_extensions/matchers.h132
-rw-r--r--library/cpp/testing/gtest_extensions/pretty_printers.cpp1
-rw-r--r--library/cpp/testing/gtest_extensions/pretty_printers.h84
-rw-r--r--library/cpp/testing/gtest_extensions/probe.cpp13
-rw-r--r--library/cpp/testing/gtest_extensions/probe.h81
-rw-r--r--library/cpp/testing/gtest_extensions/ut/README.md1
-rw-r--r--library/cpp/testing/gtest_extensions/ut/gtest_extensions_ut.cpp346
-rw-r--r--library/cpp/testing/gtest_extensions/ut/probe_ut.cpp54
-rw-r--r--library/cpp/testing/gtest_extensions/ut/ya.make20
-rw-r--r--library/cpp/testing/gtest_extensions/ya.make26
-rw-r--r--library/cpp/testing/hook/README.md25
-rw-r--r--library/cpp/testing/hook/hook.cpp45
-rw-r--r--library/cpp/testing/hook/hook.h128
-rw-r--r--library/cpp/testing/hook/ya.make13
-rw-r--r--library/cpp/testing/unittest/checks.cpp31
-rw-r--r--library/cpp/testing/unittest/env.h3
-rw-r--r--library/cpp/testing/unittest/example_ut.cpp12
-rw-r--r--library/cpp/testing/unittest/fat/test_port_manager.cpp36
-rw-r--r--library/cpp/testing/unittest/fat/ya.make19
-rw-r--r--library/cpp/testing/unittest/gtest.cpp67
-rw-r--r--library/cpp/testing/unittest/gtest.h108
-rw-r--r--library/cpp/testing/unittest/plugin.cpp50
-rw-r--r--library/cpp/testing/unittest/plugin.h29
-rw-r--r--library/cpp/testing/unittest/registar.cpp513
-rw-r--r--library/cpp/testing/unittest/registar.h1013
-rw-r--r--library/cpp/testing/unittest/registar_ut.cpp360
-rw-r--r--library/cpp/testing/unittest/simple.h39
-rw-r--r--library/cpp/testing/unittest/tests_data.cpp104
-rw-r--r--library/cpp/testing/unittest/tests_data.h54
-rw-r--r--library/cpp/testing/unittest/ut/main.cpp93
-rw-r--r--library/cpp/testing/unittest/ut/ya.make10
-rw-r--r--library/cpp/testing/unittest/utmain.cpp771
-rw-r--r--library/cpp/testing/unittest/utmain.h5
-rw-r--r--library/cpp/testing/unittest/ya.make33
-rw-r--r--library/cpp/testing/unittest_main/main.cpp5
-rw-r--r--library/cpp/testing/unittest_main/ya.make14
-rw-r--r--library/cpp/testing/ya.make24
-rw-r--r--library/cpp/threading/atomic/bool.cpp1
-rw-r--r--library/cpp/threading/atomic/bool.h36
-rw-r--r--library/cpp/threading/atomic/bool_ut.cpp31
-rw-r--r--library/cpp/threading/atomic/ut/ya.make9
-rw-r--r--library/cpp/threading/atomic/ya.make9
-rw-r--r--library/cpp/threading/chunk_queue/queue.cpp1
-rw-r--r--library/cpp/threading/chunk_queue/queue.h568
-rw-r--r--library/cpp/threading/chunk_queue/queue_ut.cpp205
-rw-r--r--library/cpp/threading/chunk_queue/readme.txt60
-rw-r--r--library/cpp/threading/chunk_queue/ut/ya.make9
-rw-r--r--library/cpp/threading/chunk_queue/ya.make9
-rw-r--r--library/cpp/threading/equeue/equeue.cpp80
-rw-r--r--library/cpp/threading/equeue/equeue.h28
-rw-r--r--library/cpp/threading/equeue/equeue_ut.cpp125
-rw-r--r--library/cpp/threading/equeue/ut/ya.make18
-rw-r--r--library/cpp/threading/equeue/ya.make15
-rw-r--r--library/cpp/threading/future/async.cpp1
-rw-r--r--library/cpp/threading/future/async.h31
-rw-r--r--library/cpp/threading/future/async_ut.cpp57
-rw-r--r--library/cpp/threading/future/core/future-inl.h986
-rw-r--r--library/cpp/threading/future/core/future.cpp1
-rw-r--r--library/cpp/threading/future/core/future.h272
-rw-r--r--library/cpp/threading/future/core/fwd.cpp1
-rw-r--r--library/cpp/threading/future/core/fwd.h11
-rw-r--r--library/cpp/threading/future/future.h4
-rw-r--r--library/cpp/threading/future/future_mt_ut.cpp215
-rw-r--r--library/cpp/threading/future/future_ut.cpp640
-rw-r--r--library/cpp/threading/future/fwd.cpp1
-rw-r--r--library/cpp/threading/future/fwd.h8
-rw-r--r--library/cpp/threading/future/legacy_future.h83
-rw-r--r--library/cpp/threading/future/legacy_future_ut.cpp73
-rw-r--r--library/cpp/threading/future/mt_ut/ya.make20
-rw-r--r--library/cpp/threading/future/perf/main.cpp50
-rw-r--r--library/cpp/threading/future/perf/ya.make16
-rw-r--r--library/cpp/threading/future/subscription/README.md104
-rw-r--r--library/cpp/threading/future/subscription/subscription-inl.h118
-rw-r--r--library/cpp/threading/future/subscription/subscription.cpp65
-rw-r--r--library/cpp/threading/future/subscription/subscription.h186
-rw-r--r--library/cpp/threading/future/subscription/subscription_ut.cpp432
-rw-r--r--library/cpp/threading/future/subscription/ut/ya.make17
-rw-r--r--library/cpp/threading/future/subscription/wait.h119
-rw-r--r--library/cpp/threading/future/subscription/wait_all.cpp1
-rw-r--r--library/cpp/threading/future/subscription/wait_all.h23
-rw-r--r--library/cpp/threading/future/subscription/wait_all_inl.h80
-rw-r--r--library/cpp/threading/future/subscription/wait_all_or_exception.cpp1
-rw-r--r--library/cpp/threading/future/subscription/wait_all_or_exception.h25
-rw-r--r--library/cpp/threading/future/subscription/wait_all_or_exception_inl.h79
-rw-r--r--library/cpp/threading/future/subscription/wait_all_or_exception_ut.cpp167
-rw-r--r--library/cpp/threading/future/subscription/wait_all_ut.cpp161
-rw-r--r--library/cpp/threading/future/subscription/wait_any.cpp1
-rw-r--r--library/cpp/threading/future/subscription/wait_any.h23
-rw-r--r--library/cpp/threading/future/subscription/wait_any_inl.h64
-rw-r--r--library/cpp/threading/future/subscription/wait_any_ut.cpp166
-rw-r--r--library/cpp/threading/future/subscription/wait_ut_common.cpp26
-rw-r--r--library/cpp/threading/future/subscription/wait_ut_common.h56
-rw-r--r--library/cpp/threading/future/subscription/ya.make24
-rw-r--r--library/cpp/threading/future/ut/ya.make14
-rw-r--r--library/cpp/threading/future/wait/fwd.cpp1
-rw-r--r--library/cpp/threading/future/wait/fwd.h1
-rw-r--r--library/cpp/threading/future/wait/wait-inl.h36
-rw-r--r--library/cpp/threading/future/wait/wait.cpp82
-rw-r--r--library/cpp/threading/future/wait/wait.h41
-rw-r--r--library/cpp/threading/future/wait/wait_group-inl.h206
-rw-r--r--library/cpp/threading/future/wait/wait_group.cpp1
-rw-r--r--library/cpp/threading/future/wait/wait_group.h65
-rw-r--r--library/cpp/threading/future/wait/wait_policy.cpp1
-rw-r--r--library/cpp/threading/future/wait/wait_policy.h10
-rw-r--r--library/cpp/threading/future/ya.make22
-rw-r--r--library/cpp/threading/light_rw_lock/bench/lightrwlock_test.cpp188
-rw-r--r--library/cpp/threading/light_rw_lock/bench/ya.make13
-rw-r--r--library/cpp/threading/light_rw_lock/lightrwlock.cpp113
-rw-r--r--library/cpp/threading/light_rw_lock/lightrwlock.h220
-rw-r--r--library/cpp/threading/light_rw_lock/ut/rwlock_ut.cpp122
-rw-r--r--library/cpp/threading/light_rw_lock/ut/ya.make9
-rw-r--r--library/cpp/threading/light_rw_lock/ya.make10
-rw-r--r--library/cpp/threading/local_executor/README.md74
-rw-r--r--library/cpp/threading/local_executor/local_executor.cpp369
-rw-r--r--library/cpp/threading/local_executor/local_executor.h294
-rw-r--r--library/cpp/threading/local_executor/tbb_local_executor.cpp53
-rw-r--r--library/cpp/threading/local_executor/tbb_local_executor.h49
-rw-r--r--library/cpp/threading/local_executor/ut/local_executor_ut.cpp371
-rw-r--r--library/cpp/threading/local_executor/ut/ya.make12
-rw-r--r--library/cpp/threading/local_executor/ya.make20
-rw-r--r--library/cpp/threading/poor_man_openmp/thread_helper.cpp7
-rw-r--r--library/cpp/threading/poor_man_openmp/thread_helper.h105
-rw-r--r--library/cpp/threading/poor_man_openmp/thread_helper_ut.cpp26
-rw-r--r--library/cpp/threading/poor_man_openmp/ut/ya.make12
-rw-r--r--library/cpp/threading/poor_man_openmp/ya.make9
-rw-r--r--library/cpp/threading/queue/basic_ut.cpp92
-rw-r--r--library/cpp/threading/queue/mpmc_unordered_ring.cpp74
-rw-r--r--library/cpp/threading/queue/mpmc_unordered_ring.h42
-rw-r--r--library/cpp/threading/queue/mpsc_htswap.cpp1
-rw-r--r--library/cpp/threading/queue/mpsc_htswap.h132
-rw-r--r--library/cpp/threading/queue/mpsc_intrusive_unordered.cpp79
-rw-r--r--library/cpp/threading/queue/mpsc_intrusive_unordered.h35
-rw-r--r--library/cpp/threading/queue/mpsc_read_as_filled.cpp1
-rw-r--r--library/cpp/threading/queue/mpsc_read_as_filled.h611
-rw-r--r--library/cpp/threading/queue/mpsc_vinfarr_obstructive.cpp1
-rw-r--r--library/cpp/threading/queue/mpsc_vinfarr_obstructive.h528
-rw-r--r--library/cpp/threading/queue/queue_ut.cpp242
-rw-r--r--library/cpp/threading/queue/tune.h125
-rw-r--r--library/cpp/threading/queue/tune_ut.cpp118
-rw-r--r--library/cpp/threading/queue/unordered_ut.cpp154
-rw-r--r--library/cpp/threading/queue/ut/ya.make16
-rw-r--r--library/cpp/threading/queue/ut_helpers.cpp1
-rw-r--r--library/cpp/threading/queue/ut_helpers.h40
-rw-r--r--library/cpp/threading/queue/ya.make18
-rw-r--r--library/cpp/threading/skip_list/compare.h77
-rw-r--r--library/cpp/threading/skip_list/perf/main.cpp362
-rw-r--r--library/cpp/threading/skip_list/perf/ya.make15
-rw-r--r--library/cpp/threading/skip_list/skiplist.cpp1
-rw-r--r--library/cpp/threading/skip_list/skiplist.h408
-rw-r--r--library/cpp/threading/skip_list/skiplist_ut.cpp185
-rw-r--r--library/cpp/threading/skip_list/ut/ya.make9
-rw-r--r--library/cpp/threading/skip_list/ya.make9
-rw-r--r--library/cpp/threading/task_scheduler/task_scheduler.cpp246
-rw-r--r--library/cpp/threading/task_scheduler/task_scheduler.h86
-rw-r--r--library/cpp/threading/task_scheduler/task_scheduler_ut.cpp86
-rw-r--r--library/cpp/threading/task_scheduler/ut/ya.make9
-rw-r--r--library/cpp/threading/task_scheduler/ya.make9
-rw-r--r--library/cpp/threading/ya.make64
-rw-r--r--library/cpp/time_provider/time_provider.cpp30
-rw-r--r--library/cpp/time_provider/time_provider.h11
-rw-r--r--library/cpp/time_provider/ya.make13
-rw-r--r--library/cpp/timezone_conversion/README.md27
-rw-r--r--library/cpp/timezone_conversion/civil-inl.h63
-rw-r--r--library/cpp/timezone_conversion/civil.cpp234
-rw-r--r--library/cpp/timezone_conversion/civil.h338
-rw-r--r--library/cpp/timezone_conversion/convert.cpp93
-rw-r--r--library/cpp/timezone_conversion/convert.h60
-rw-r--r--library/cpp/timezone_conversion/ut/civil_ut.cpp157
-rw-r--r--library/cpp/timezone_conversion/ut/convert_ut.cpp204
-rw-r--r--library/cpp/timezone_conversion/ut/ya.make15
-rw-r--r--library/cpp/timezone_conversion/ya.make22
-rwxr-xr-xlibrary/cpp/tld/gen_tld.py57
-rw-r--r--library/cpp/tld/tld.cpp48
-rw-r--r--library/cpp/tld/tld.h28
-rw-r--r--library/cpp/tld/tld_ut.cpp59
-rw-r--r--library/cpp/tld/tlds-alpha-by-domain.txt1536
-rw-r--r--library/cpp/tld/ut/ya.make15
-rw-r--r--library/cpp/tld/ya.make19
-rw-r--r--library/cpp/tvmauth/README.md2
-rw-r--r--library/cpp/tvmauth/a.yaml23
-rw-r--r--library/cpp/tvmauth/checked_service_ticket.h71
-rw-r--r--library/cpp/tvmauth/checked_user_ticket.h91
-rw-r--r--library/cpp/tvmauth/client/README.md56
-rw-r--r--library/cpp/tvmauth/client/client_status.cpp6
-rw-r--r--library/cpp/tvmauth/client/client_status.h82
-rw-r--r--library/cpp/tvmauth/client/examples/create_with_tvmapi/create.cpp102
-rw-r--r--library/cpp/tvmauth/client/examples/create_with_tvmapi/ya.make13
-rw-r--r--library/cpp/tvmauth/client/examples/create_with_tvmtool/create.cpp34
-rw-r--r--library/cpp/tvmauth/client/examples/create_with_tvmtool/ya.make13
-rw-r--r--library/cpp/tvmauth/client/examples/service_using_tvmtool_client/service.cpp84
-rw-r--r--library/cpp/tvmauth/client/examples/service_using_tvmtool_client/service.h35
-rw-r--r--library/cpp/tvmauth/client/examples/service_using_tvmtool_client/ya.make15
-rw-r--r--library/cpp/tvmauth/client/examples/ya.make5
-rw-r--r--library/cpp/tvmauth/client/exception.h23
-rw-r--r--library/cpp/tvmauth/client/facade.cpp131
-rw-r--r--library/cpp/tvmauth/client/facade.h119
-rw-r--r--library/cpp/tvmauth/client/logger.cpp12
-rw-r--r--library/cpp/tvmauth/client/logger.h59
-rw-r--r--library/cpp/tvmauth/client/misc/api/dynamic_dst/tvm_client.cpp126
-rw-r--r--library/cpp/tvmauth/client/misc/api/dynamic_dst/tvm_client.h60
-rw-r--r--library/cpp/tvmauth/client/misc/api/dynamic_dst/ut/tvm_client_ut.cpp635
-rw-r--r--library/cpp/tvmauth/client/misc/api/dynamic_dst/ut/ya.make11
-rw-r--r--library/cpp/tvmauth/client/misc/api/dynamic_dst/ya.make20
-rw-r--r--library/cpp/tvmauth/client/misc/api/retry_settings.h33
-rw-r--r--library/cpp/tvmauth/client/misc/api/roles_fetcher.cpp163
-rw-r--r--library/cpp/tvmauth/client/misc/api/roles_fetcher.h63
-rw-r--r--library/cpp/tvmauth/client/misc/api/settings.cpp89
-rw-r--r--library/cpp/tvmauth/client/misc/api/settings.h302
-rw-r--r--library/cpp/tvmauth/client/misc/api/threaded_updater.cpp954
-rw-r--r--library/cpp/tvmauth/client/misc/api/threaded_updater.h140
-rw-r--r--library/cpp/tvmauth/client/misc/async_updater.cpp152
-rw-r--r--library/cpp/tvmauth/client/misc/async_updater.h183
-rw-r--r--library/cpp/tvmauth/client/misc/checker.h67
-rw-r--r--library/cpp/tvmauth/client/misc/default_uid_checker.h46
-rw-r--r--library/cpp/tvmauth/client/misc/disk_cache.cpp165
-rw-r--r--library/cpp/tvmauth/client/misc/disk_cache.h50
-rw-r--r--library/cpp/tvmauth/client/misc/exponential_backoff.h94
-rw-r--r--library/cpp/tvmauth/client/misc/fetch_result.h13
-rw-r--r--library/cpp/tvmauth/client/misc/getter.h66
-rw-r--r--library/cpp/tvmauth/client/misc/last_error.cpp115
-rw-r--r--library/cpp/tvmauth/client/misc/last_error.h51
-rw-r--r--library/cpp/tvmauth/client/misc/proc_info.cpp53
-rw-r--r--library/cpp/tvmauth/client/misc/proc_info.h18
-rw-r--r--library/cpp/tvmauth/client/misc/retry_settings/v1/settings.proto21
-rw-r--r--library/cpp/tvmauth/client/misc/retry_settings/v1/ya.make15
-rw-r--r--library/cpp/tvmauth/client/misc/roles/decoder.cpp93
-rw-r--r--library/cpp/tvmauth/client/misc/roles/decoder.h32
-rw-r--r--library/cpp/tvmauth/client/misc/roles/entities_index.cpp114
-rw-r--r--library/cpp/tvmauth/client/misc/roles/entities_index.h107
-rw-r--r--library/cpp/tvmauth/client/misc/roles/parser.cpp149
-rw-r--r--library/cpp/tvmauth/client/misc/roles/parser.h36
-rw-r--r--library/cpp/tvmauth/client/misc/roles/roles.cpp101
-rw-r--r--library/cpp/tvmauth/client/misc/roles/roles.h182
-rw-r--r--library/cpp/tvmauth/client/misc/roles/types.h68
-rw-r--r--library/cpp/tvmauth/client/misc/settings.h13
-rw-r--r--library/cpp/tvmauth/client/misc/src_checker.h46
-rw-r--r--library/cpp/tvmauth/client/misc/threaded_updater.cpp111
-rw-r--r--library/cpp/tvmauth/client/misc/threaded_updater.h76
-rw-r--r--library/cpp/tvmauth/client/misc/tool/meta_info.cpp200
-rw-r--r--library/cpp/tvmauth/client/misc/tool/meta_info.h67
-rw-r--r--library/cpp/tvmauth/client/misc/tool/settings.cpp37
-rw-r--r--library/cpp/tvmauth/client/misc/tool/settings.h137
-rw-r--r--library/cpp/tvmauth/client/misc/tool/threaded_updater.cpp331
-rw-r--r--library/cpp/tvmauth/client/misc/tool/threaded_updater.h55
-rw-r--r--library/cpp/tvmauth/client/misc/utils.cpp46
-rw-r--r--library/cpp/tvmauth/client/misc/utils.h95
-rw-r--r--library/cpp/tvmauth/client/mocked_updater.cpp60
-rw-r--r--library/cpp/tvmauth/client/mocked_updater.h43
-rw-r--r--library/cpp/tvmauth/client/ut/async_updater_ut.cpp165
-rw-r--r--library/cpp/tvmauth/client/ut/checker_ut.cpp176
-rw-r--r--library/cpp/tvmauth/client/ut/client_status_ut.cpp18
-rw-r--r--library/cpp/tvmauth/client/ut/common.h232
-rw-r--r--library/cpp/tvmauth/client/ut/default_uid_checker_ut.cpp52
-rw-r--r--library/cpp/tvmauth/client/ut/disk_cache_ut.cpp204
-rw-r--r--library/cpp/tvmauth/client/ut/exponential_backoff_ut.cpp44
-rw-r--r--library/cpp/tvmauth/client/ut/facade_ut.cpp167
-rw-r--r--library/cpp/tvmauth/client/ut/files/ok.cachebin0 -> 113 bytes
-rw-r--r--library/cpp/tvmauth/client/ut/files/public_keysbin0 -> 2840 bytes
-rw-r--r--library/cpp/tvmauth/client/ut/files/rolesbin0 -> 295 bytes
-rw-r--r--library/cpp/tvmauth/client/ut/files/service_ticketsbin0 -> 250 bytes
-rw-r--r--library/cpp/tvmauth/client/ut/last_error_ut.cpp56
-rw-r--r--library/cpp/tvmauth/client/ut/logger_ut.cpp43
-rw-r--r--library/cpp/tvmauth/client/ut/roles/decoder_ut.cpp163
-rw-r--r--library/cpp/tvmauth/client/ut/roles/entities_index_ut.cpp358
-rw-r--r--library/cpp/tvmauth/client/ut/roles/parser_ut.cpp160
-rw-r--r--library/cpp/tvmauth/client/ut/roles/roles_ut.cpp415
-rw-r--r--library/cpp/tvmauth/client/ut/roles/tvmapi_roles_fetcher_ut.cpp197
-rw-r--r--library/cpp/tvmauth/client/ut/settings_ut.cpp169
-rw-r--r--library/cpp/tvmauth/client/ut/src_checker_ut.cpp47
-rw-r--r--library/cpp/tvmauth/client/ut/tvmapi_updater_ut.cpp1272
-rw-r--r--library/cpp/tvmauth/client/ut/tvmtool_updater_ut.cpp744
-rw-r--r--library/cpp/tvmauth/client/ut/utils_ut.cpp88
-rw-r--r--library/cpp/tvmauth/client/ut/ya.make36
-rw-r--r--library/cpp/tvmauth/client/ya.make49
-rw-r--r--library/cpp/tvmauth/deprecated/README.md2
-rw-r--r--library/cpp/tvmauth/deprecated/service_context.cpp37
-rw-r--r--library/cpp/tvmauth/deprecated/service_context.h63
-rw-r--r--library/cpp/tvmauth/deprecated/user_context.cpp20
-rw-r--r--library/cpp/tvmauth/deprecated/user_context.h30
-rw-r--r--library/cpp/tvmauth/exception.h20
-rw-r--r--library/cpp/tvmauth/src/parser.cpp97
-rw-r--r--library/cpp/tvmauth/src/parser.h51
-rw-r--r--library/cpp/tvmauth/src/protos/ticket2.proto31
-rw-r--r--library/cpp/tvmauth/src/protos/tvm_keys.proto36
-rw-r--r--library/cpp/tvmauth/src/protos/ya.make12
-rw-r--r--library/cpp/tvmauth/src/rw/keys.cpp138
-rw-r--r--library/cpp/tvmauth/src/rw/keys.h65
-rw-r--r--library/cpp/tvmauth/src/rw/rw.h86
-rw-r--r--library/cpp/tvmauth/src/rw/rw_asn1.c81
-rw-r--r--library/cpp/tvmauth/src/rw/rw_key.c135
-rw-r--r--library/cpp/tvmauth/src/rw/rw_lib.c77
-rw-r--r--library/cpp/tvmauth/src/rw/rw_ossl.c473
-rw-r--r--library/cpp/tvmauth/src/rw/rw_pss.c328
-rw-r--r--library/cpp/tvmauth/src/rw/rw_pss_sign.c211
-rw-r--r--library/cpp/tvmauth/src/rw/rw_sign.c46
-rw-r--r--library/cpp/tvmauth/src/rw/ut/rw_ut.cpp200
-rw-r--r--library/cpp/tvmauth/src/rw/ut/ya.make17
-rw-r--r--library/cpp/tvmauth/src/rw/ut_large/gen/main.cpp32
-rw-r--r--library/cpp/tvmauth/src/rw/ut_large/gen/ya.make14
-rw-r--r--library/cpp/tvmauth/src/rw/ut_large/test.py35
-rw-r--r--library/cpp/tvmauth/src/rw/ut_large/ya.make17
-rw-r--r--library/cpp/tvmauth/src/rw/ya.make30
-rw-r--r--library/cpp/tvmauth/src/service_impl.cpp203
-rw-r--r--library/cpp/tvmauth/src/service_impl.h77
-rw-r--r--library/cpp/tvmauth/src/service_ticket.cpp41
-rw-r--r--library/cpp/tvmauth/src/status.cpp32
-rw-r--r--library/cpp/tvmauth/src/unittest.cpp14
-rw-r--r--library/cpp/tvmauth/src/user_impl.cpp241
-rw-r--r--library/cpp/tvmauth/src/user_impl.h72
-rw-r--r--library/cpp/tvmauth/src/user_ticket.cpp56
-rw-r--r--library/cpp/tvmauth/src/ut/parser_ut.cpp143
-rw-r--r--library/cpp/tvmauth/src/ut/public_ut.cpp290
-rw-r--r--library/cpp/tvmauth/src/ut/service_ut.cpp156
-rw-r--r--library/cpp/tvmauth/src/ut/user_ut.cpp216
-rw-r--r--library/cpp/tvmauth/src/ut/utils_ut.cpp95
-rw-r--r--library/cpp/tvmauth/src/ut/version_ut.cpp18
-rw-r--r--library/cpp/tvmauth/src/ut/ya.make14
-rw-r--r--library/cpp/tvmauth/src/utils.cpp162
-rw-r--r--library/cpp/tvmauth/src/utils.h30
-rw-r--r--library/cpp/tvmauth/src/version1
-rw-r--r--library/cpp/tvmauth/src/version.cpp26
-rw-r--r--library/cpp/tvmauth/test_all/ya.make21
-rw-r--r--library/cpp/tvmauth/ticket_status.h23
-rw-r--r--library/cpp/tvmauth/type.h11
-rw-r--r--library/cpp/tvmauth/unittest.h20
-rw-r--r--library/cpp/tvmauth/utils.cpp18
-rw-r--r--library/cpp/tvmauth/utils.h12
-rw-r--r--library/cpp/tvmauth/version.h7
-rw-r--r--library/cpp/tvmauth/ya.make40
-rw-r--r--library/cpp/unicode/normalization/custom_encoder.cpp83
-rw-r--r--library/cpp/unicode/normalization/custom_encoder.h11
-rw-r--r--library/cpp/unicode/normalization/decomposition_table.h28
-rw-r--r--library/cpp/unicode/normalization/generated/composition.cpp950
-rw-r--r--library/cpp/unicode/normalization/generated/decomposition.cpp91132
-rw-r--r--library/cpp/unicode/normalization/normalization.cpp66
-rw-r--r--library/cpp/unicode/normalization/normalization.h384
-rw-r--r--library/cpp/unicode/normalization/ut/normalization_ut.cpp32
-rw-r--r--library/cpp/unicode/normalization/ut/ya.make13
-rw-r--r--library/cpp/unicode/normalization/ya.make24
-rw-r--r--library/cpp/unicode/punycode/punycode.cpp143
-rw-r--r--library/cpp/unicode/punycode/punycode.h46
-rw-r--r--library/cpp/unicode/punycode/punycode_ut.cpp126
-rw-r--r--library/cpp/unicode/punycode/ut/ya.make13
-rw-r--r--library/cpp/unicode/punycode/ya.make17
-rw-r--r--library/cpp/unicode/ya.make14
-rw-r--r--library/cpp/uri/assign.cpp426
-rw-r--r--library/cpp/uri/benchmark/main.cpp46
-rw-r--r--library/cpp/uri/benchmark/ya.make17
-rw-r--r--library/cpp/uri/common.cpp115
-rw-r--r--library/cpp/uri/common.h511
-rw-r--r--library/cpp/uri/encode.cpp221
-rw-r--r--library/cpp/uri/encode.h282
-rw-r--r--library/cpp/uri/encodefsm.rl651
-rw-r--r--library/cpp/uri/http_url.h77
-rw-r--r--library/cpp/uri/location.cpp31
-rw-r--r--library/cpp/uri/location.h13
-rw-r--r--library/cpp/uri/location_ut.cpp40
-rw-r--r--library/cpp/uri/other.cpp82
-rw-r--r--library/cpp/uri/other.h42
-rw-r--r--library/cpp/uri/parse.cpp207
-rw-r--r--library/cpp/uri/parse.h361
-rw-r--r--library/cpp/uri/parsefsm.rl6501
-rw-r--r--library/cpp/uri/qargs.cpp279
-rw-r--r--library/cpp/uri/qargs.h22
-rw-r--r--library/cpp/uri/uri-ru_ut.cpp163
-rw-r--r--library/cpp/uri/uri.cpp623
-rw-r--r--library/cpp/uri/uri.h626
-rw-r--r--library/cpp/uri/uri_ut.cpp1022
-rw-r--r--library/cpp/uri/uri_ut.h81
-rw-r--r--library/cpp/uri/ut/ya.make19
-rw-r--r--library/cpp/uri/ya.make32
-rw-r--r--library/cpp/xml/document/README42
-rw-r--r--library/cpp/xml/document/libxml-guards.h50
-rw-r--r--library/cpp/xml/document/node-attr.h209
-rw-r--r--library/cpp/xml/document/ut/ya.make11
-rw-r--r--library/cpp/xml/document/xml-document-decl.h718
-rw-r--r--library/cpp/xml/document/xml-document.cpp393
-rw-r--r--library/cpp/xml/document/xml-document.h4
-rw-r--r--library/cpp/xml/document/xml-document_ut.cpp319
-rw-r--r--library/cpp/xml/document/xml-options.cpp1
-rw-r--r--library/cpp/xml/document/xml-options.h67
-rw-r--r--library/cpp/xml/document/xml-options_ut.cpp26
-rw-r--r--library/cpp/xml/document/xml-textreader.cpp318
-rw-r--r--library/cpp/xml/document/xml-textreader.h325
-rw-r--r--library/cpp/xml/document/xml-textreader_ut.cpp290
-rw-r--r--library/cpp/xml/document/ya.make17
-rw-r--r--library/cpp/xml/init/init.cpp39
-rw-r--r--library/cpp/xml/init/init.h5
-rw-r--r--library/cpp/xml/init/ptr.cpp1
-rw-r--r--library/cpp/xml/init/ptr.h69
-rw-r--r--library/cpp/xml/init/ya.make15
-rw-r--r--library/cpp/xml/ya.make13
-rw-r--r--library/cpp/ya.make450
-rw-r--r--library/cpp/yaml/as/tstring.h27
-rw-r--r--library/cpp/yaml/as/ut/tstring_test.cpp59
-rw-r--r--library/cpp/yaml/as/ut/ya.make14
-rw-r--r--library/cpp/yaml/as/ya.make13
-rw-r--r--library/cpp/yaml/ya.make4
-rw-r--r--library/cpp/yson/consumer.cpp15
-rw-r--r--library/cpp/yson/consumer.h13
-rw-r--r--library/cpp/yson/detail.h806
-rw-r--r--library/cpp/yson/format.h25
-rw-r--r--library/cpp/yson/json/json_writer.cpp220
-rw-r--r--library/cpp/yson/json/json_writer.h89
-rw-r--r--library/cpp/yson/json/ya.make17
-rw-r--r--library/cpp/yson/json/yson2json_adapter.cpp82
-rw-r--r--library/cpp/yson/json/yson2json_adapter.h53
-rw-r--r--library/cpp/yson/lexer.cpp43
-rw-r--r--library/cpp/yson/lexer.h26
-rw-r--r--library/cpp/yson/lexer_detail.h296
-rw-r--r--library/cpp/yson/node/node.cpp915
-rw-r--r--library/cpp/yson/node/node.h523
-rw-r--r--library/cpp/yson/node/node_builder.cpp96
-rw-r--r--library/cpp/yson/node/node_builder.h46
-rw-r--r--library/cpp/yson/node/node_io.cpp154
-rw-r--r--library/cpp/yson/node/node_io.h40
-rw-r--r--library/cpp/yson/node/node_ut.cpp484
-rw-r--r--library/cpp/yson/node/node_visitor.cpp152
-rw-r--r--library/cpp/yson/node/node_visitor.h37
-rw-r--r--library/cpp/yson/node/pybind/node.cpp105
-rw-r--r--library/cpp/yson/node/pybind/node.h9
-rw-r--r--library/cpp/yson/node/pybind/ya.make16
-rw-r--r--library/cpp/yson/node/serialize.cpp101
-rw-r--r--library/cpp/yson/node/serialize.h45
-rw-r--r--library/cpp/yson/node/ut/ya.make12
-rw-r--r--library/cpp/yson/node/ya.make25
-rw-r--r--library/cpp/yson/parser.cpp179
-rw-r--r--library/cpp/yson/parser.h83
-rw-r--r--library/cpp/yson/parser_detail.h381
-rw-r--r--library/cpp/yson/public.h30
-rw-r--r--library/cpp/yson/string-inl.h57
-rw-r--r--library/cpp/yson/token.cpp236
-rw-r--r--library/cpp/yson/token.h93
-rw-r--r--library/cpp/yson/tokenizer.cpp37
-rw-r--r--library/cpp/yson/tokenizer.h28
-rw-r--r--library/cpp/yson/varint.cpp71
-rw-r--r--library/cpp/yson/varint.h24
-rw-r--r--library/cpp/yson/writer.cpp355
-rw-r--r--library/cpp/yson/writer.h89
-rw-r--r--library/cpp/yson/ya.make23
-rw-r--r--library/cpp/yson/zigzag.h31
-rw-r--r--library/cpp/yson_pull/bridge.h34
-rw-r--r--library/cpp/yson_pull/buffer.h79
-rw-r--r--library/cpp/yson_pull/consumer.cpp83
-rw-r--r--library/cpp/yson_pull/consumer.h37
-rw-r--r--library/cpp/yson_pull/cyson_enums.h47
-rw-r--r--library/cpp/yson_pull/detail/byte_reader.h74
-rw-r--r--library/cpp/yson_pull/detail/byte_writer.h77
-rw-r--r--library/cpp/yson_pull/detail/cescape.h143
-rw-r--r--library/cpp/yson_pull/detail/cescape_decode.h154
-rw-r--r--library/cpp/yson_pull/detail/cescape_encode.h114
-rw-r--r--library/cpp/yson_pull/detail/fail.h20
-rw-r--r--library/cpp/yson_pull/detail/format_string.h26
-rw-r--r--library/cpp/yson_pull/detail/input/buffered.h35
-rw-r--r--library/cpp/yson_pull/detail/input/stdio_file.h42
-rw-r--r--library/cpp/yson_pull/detail/input/stream.h69
-rw-r--r--library/cpp/yson_pull/detail/lexer_base.h343
-rw-r--r--library/cpp/yson_pull/detail/macros.h24
-rw-r--r--library/cpp/yson_pull/detail/number.h37
-rw-r--r--library/cpp/yson_pull/detail/output/buffered.h51
-rw-r--r--library/cpp/yson_pull/detail/output/stdio_file.h33
-rw-r--r--library/cpp/yson_pull/detail/output/stream.h56
-rw-r--r--library/cpp/yson_pull/detail/percent_scalar.h36
-rw-r--r--library/cpp/yson_pull/detail/reader.h677
-rw-r--r--library/cpp/yson_pull/detail/stream_counter.h51
-rw-r--r--library/cpp/yson_pull/detail/symbols.h55
-rw-r--r--library/cpp/yson_pull/detail/traits.h29
-rw-r--r--library/cpp/yson_pull/detail/varint.h260
-rw-r--r--library/cpp/yson_pull/detail/writer.h566
-rw-r--r--library/cpp/yson_pull/detail/zigzag.h24
-rw-r--r--library/cpp/yson_pull/event.cpp18
-rw-r--r--library/cpp/yson_pull/event.h85
-rw-r--r--library/cpp/yson_pull/exceptions.cpp45
-rw-r--r--library/cpp/yson_pull/exceptions.h59
-rw-r--r--library/cpp/yson_pull/input.cpp33
-rw-r--r--library/cpp/yson_pull/input.h81
-rw-r--r--library/cpp/yson_pull/output.cpp29
-rw-r--r--library/cpp/yson_pull/output.h65
-rw-r--r--library/cpp/yson_pull/position_info.h23
-rw-r--r--library/cpp/yson_pull/range.h35
-rw-r--r--library/cpp/yson_pull/read_ops.cpp66
-rw-r--r--library/cpp/yson_pull/read_ops.h142
-rw-r--r--library/cpp/yson_pull/reader.cpp27
-rw-r--r--library/cpp/yson_pull/reader.h37
-rw-r--r--library/cpp/yson_pull/scalar.cpp57
-rw-r--r--library/cpp/yson_pull/scalar.h146
-rw-r--r--library/cpp/yson_pull/stream_type.h11
-rw-r--r--library/cpp/yson_pull/ut/cescape_ut.cpp71
-rw-r--r--library/cpp/yson_pull/ut/loop_ut.cpp382
-rw-r--r--library/cpp/yson_pull/ut/reader_ut.cpp410
-rw-r--r--library/cpp/yson_pull/ut/writer_ut.cpp256
-rw-r--r--library/cpp/yson_pull/ut/ya.make12
-rw-r--r--library/cpp/yson_pull/writer.cpp30
-rw-r--r--library/cpp/yson_pull/writer.h126
-rw-r--r--library/cpp/yson_pull/ya.make21
-rw-r--r--library/cpp/yson_pull/yson.h14
-rw-r--r--library/cpp/yt/assert/assert.cpp29
-rw-r--r--library/cpp/yt/assert/assert.h76
-rw-r--r--library/cpp/yt/assert/ya.make9
-rw-r--r--library/cpp/yt/coding/unittests/varint_ut.cpp134
-rw-r--r--library/cpp/yt/coding/unittests/ya.make15
-rw-r--r--library/cpp/yt/coding/unittests/zig_zag_ut.cpp57
-rw-r--r--library/cpp/yt/coding/varint-inl.h240
-rw-r--r--library/cpp/yt/coding/varint.h56
-rw-r--r--library/cpp/yt/coding/ya.make12
-rw-r--r--library/cpp/yt/coding/zig_zag-inl.h40
-rw-r--r--library/cpp/yt/coding/zig_zag.h24
-rw-r--r--library/cpp/yt/exception/exception.cpp48
-rw-r--r--library/cpp/yt/exception/exception.h45
-rw-r--r--library/cpp/yt/exception/ya.make7
-rw-r--r--library/cpp/yt/malloc/malloc.cpp19
-rw-r--r--library/cpp/yt/malloc/malloc.h8
-rw-r--r--library/cpp/yt/malloc/ya.make7
-rw-r--r--library/cpp/yt/memory/blob.cpp224
-rw-r--r--library/cpp/yt/memory/blob.h221
-rw-r--r--library/cpp/yt/memory/intrusive_ptr.h360
-rw-r--r--library/cpp/yt/memory/leaky_ref_counted_singleton-inl.h43
-rw-r--r--library/cpp/yt/memory/leaky_ref_counted_singleton.h18
-rw-r--r--library/cpp/yt/memory/leaky_singleton-inl.h34
-rw-r--r--library/cpp/yt/memory/leaky_singleton.h34
-rw-r--r--library/cpp/yt/memory/new-inl.h310
-rw-r--r--library/cpp/yt/memory/new.h127
-rw-r--r--library/cpp/yt/memory/range.h556
-rw-r--r--library/cpp/yt/memory/ref-inl.h517
-rw-r--r--library/cpp/yt/memory/ref.cpp378
-rw-r--r--library/cpp/yt/memory/ref.h384
-rw-r--r--library/cpp/yt/memory/ref_counted-inl.h278
-rw-r--r--library/cpp/yt/memory/ref_counted.h190
-rw-r--r--library/cpp/yt/memory/ref_tracked-inl.h49
-rw-r--r--library/cpp/yt/memory/ref_tracked.cpp38
-rw-r--r--library/cpp/yt/memory/ref_tracked.h111
-rw-r--r--library/cpp/yt/memory/shared_range.h297
-rw-r--r--library/cpp/yt/memory/unittests/intrusive_ptr_ut.cpp562
-rw-r--r--library/cpp/yt/memory/unittests/weak_ptr_ut.cpp433
-rw-r--r--library/cpp/yt/memory/unittests/ya.make19
-rw-r--r--library/cpp/yt/memory/weak_ptr.h314
-rw-r--r--library/cpp/yt/memory/ya.make31
-rw-r--r--library/cpp/yt/misc/cast-inl.h113
-rw-r--r--library/cpp/yt/misc/cast.h29
-rw-r--r--library/cpp/yt/misc/enum-inl.h385
-rw-r--r--library/cpp/yt/misc/enum.h243
-rw-r--r--library/cpp/yt/misc/guid-inl.h76
-rw-r--r--library/cpp/yt/misc/guid.cpp203
-rw-r--r--library/cpp/yt/misc/guid.h109
-rw-r--r--library/cpp/yt/misc/hash-inl.h47
-rw-r--r--library/cpp/yt/misc/hash.h42
-rw-r--r--library/cpp/yt/misc/port.h70
-rw-r--r--library/cpp/yt/misc/preprocessor-gen.h1249
-rw-r--r--library/cpp/yt/misc/preprocessor-gen.h.pump70
-rw-r--r--library/cpp/yt/misc/preprocessor.h124
-rw-r--r--library/cpp/yt/misc/property.h289
-rw-r--r--library/cpp/yt/misc/source_location.cpp54
-rw-r--r--library/cpp/yt/misc/source_location.h38
-rw-r--r--library/cpp/yt/misc/unittests/enum_ut.cpp250
-rw-r--r--library/cpp/yt/misc/unittests/guid_ut.cpp20
-rw-r--r--library/cpp/yt/misc/unittests/preprocessor_ut.cpp102
-rw-r--r--library/cpp/yt/misc/unittests/ya.make15
-rw-r--r--library/cpp/yt/misc/variant-inl.h70
-rw-r--r--library/cpp/yt/misc/variant.h76
-rw-r--r--library/cpp/yt/misc/ya.make27
-rw-r--r--library/cpp/yt/small_containers/compact_flat_map-inl.h184
-rw-r--r--library/cpp/yt/small_containers/compact_flat_map.h109
-rw-r--r--library/cpp/yt/small_containers/compact_heap-inl.h152
-rw-r--r--library/cpp/yt/small_containers/compact_heap.h75
-rw-r--r--library/cpp/yt/small_containers/compact_set-inl.h322
-rw-r--r--library/cpp/yt/small_containers/compact_set.h86
-rw-r--r--library/cpp/yt/small_containers/compact_vector-inl.h1011
-rw-r--r--library/cpp/yt/small_containers/compact_vector.h219
-rw-r--r--library/cpp/yt/small_containers/unittests/compact_flat_map_ut.cpp225
-rw-r--r--library/cpp/yt/small_containers/unittests/compact_heap_ut.cpp108
-rw-r--r--library/cpp/yt/small_containers/unittests/compact_set_ut.cpp204
-rw-r--r--library/cpp/yt/small_containers/unittests/compact_vector_ut.cpp1084
-rw-r--r--library/cpp/yt/small_containers/unittests/ya.make17
-rw-r--r--library/cpp/yt/small_containers/ya.make20
-rw-r--r--library/cpp/yt/string/enum-inl.h118
-rw-r--r--library/cpp/yt/string/enum.cpp44
-rw-r--r--library/cpp/yt/string/enum.h31
-rw-r--r--library/cpp/yt/string/format-inl.h744
-rw-r--r--library/cpp/yt/string/format.h114
-rw-r--r--library/cpp/yt/string/guid.cpp22
-rw-r--r--library/cpp/yt/string/guid.h14
-rw-r--r--library/cpp/yt/string/string.cpp272
-rw-r--r--library/cpp/yt/string/string.h221
-rw-r--r--library/cpp/yt/string/string_builder-inl.h129
-rw-r--r--library/cpp/yt/string/string_builder.h116
-rw-r--r--library/cpp/yt/string/unittests/enum_ut.cpp61
-rw-r--r--library/cpp/yt/string/unittests/format_ut.cpp149
-rw-r--r--library/cpp/yt/string/unittests/guid_ut.cpp58
-rw-r--r--library/cpp/yt/string/unittests/string_ut.cpp52
-rw-r--r--library/cpp/yt/string/unittests/ya.make17
-rw-r--r--library/cpp/yt/string/ya.make30
-rw-r--r--library/cpp/yt/ya.make24
-rw-r--r--library/cpp/yt/yson/consumer.cpp16
-rw-r--r--library/cpp/yt/yson/consumer.h111
-rw-r--r--library/cpp/yt/yson/public.h11
-rw-r--r--library/cpp/yt/yson/ya.make11
-rw-r--r--library/cpp/yt/yson_string/convert.cpp381
-rw-r--r--library/cpp/yt/yson_string/convert.h114
-rw-r--r--library/cpp/yt/yson_string/format.h44
-rw-r--r--library/cpp/yt/yson_string/public.h39
-rw-r--r--library/cpp/yt/yson_string/string-inl.h93
-rw-r--r--library/cpp/yt/yson_string/string.cpp185
-rw-r--r--library/cpp/yt/yson_string/string.h140
-rw-r--r--library/cpp/yt/yson_string/unittests/convert_ut.cpp79
-rw-r--r--library/cpp/yt/yson_string/unittests/ya.make15
-rw-r--r--library/cpp/yt/yson_string/ya.make21
-rw-r--r--library/cpp/ytalloc/api/README.md6
-rw-r--r--library/cpp/ytalloc/api/fallback.cpp220
-rw-r--r--library/cpp/ytalloc/api/ya.make13
-rw-r--r--library/cpp/ytalloc/api/ytalloc-inl.h105
-rw-r--r--library/cpp/ytalloc/api/ytalloc.h416
-rw-r--r--library/cpp/ytalloc/ya.make17
-rw-r--r--library/python/certifi/.dist-info/METADATA2
-rw-r--r--library/python/certifi/.dist-info/top_level.txt1
-rw-r--r--library/python/certifi/README.md7
-rw-r--r--library/python/certifi/certifi/__init__.py10
-rw-r--r--library/python/certifi/certifi/binary.py25
-rw-r--r--library/python/certifi/certifi/source.py13
-rw-r--r--library/python/certifi/ya.make18
-rw-r--r--library/python/cores/__init__.py193
-rw-r--r--library/python/cores/ya.make15
-rw-r--r--library/python/filelock/__init__.py122
-rw-r--r--library/python/filelock/ut/lib/test_filelock.py83
-rw-r--r--library/python/filelock/ut/lib/ya.make11
-rw-r--r--library/python/filelock/ut/py2/ya.make9
-rw-r--r--library/python/filelock/ut/py3/ya.make9
-rw-r--r--library/python/filelock/ut/ya.make7
-rw-r--r--library/python/filelock/ya.make11
-rw-r--r--library/python/find_root/__init__.py20
-rw-r--r--library/python/find_root/ya.make7
-rw-r--r--library/python/fs/__init__.py501
-rw-r--r--library/python/fs/clonefile.pyx18
-rw-r--r--library/python/fs/test/test_fs.py1037
-rw-r--r--library/python/fs/test/ya.make14
-rw-r--r--library/python/fs/ya.make23
-rw-r--r--library/python/func/__init__.py170
-rw-r--r--library/python/func/ut/test_func.py162
-rw-r--r--library/python/func/ut/ya.make11
-rw-r--r--library/python/func/ya.make11
-rw-r--r--library/python/pytest/__init__.py0
-rw-r--r--library/python/pytest/allure/conftest.py8
-rw-r--r--library/python/pytest/allure/ya.make11
-rw-r--r--library/python/pytest/context.py1
-rw-r--r--library/python/pytest/empty/main.c7
-rw-r--r--library/python/pytest/empty/ya.make12
-rw-r--r--library/python/pytest/main.py116
-rw-r--r--library/python/pytest/plugins/collection.py128
-rw-r--r--library/python/pytest/plugins/conftests.py50
-rw-r--r--library/python/pytest/plugins/fakeid_py2.py2
-rw-r--r--library/python/pytest/plugins/fakeid_py3.py2
-rw-r--r--library/python/pytest/plugins/fixtures.py85
-rw-r--r--library/python/pytest/plugins/ya.make32
-rw-r--r--library/python/pytest/plugins/ya.py963
-rw-r--r--library/python/pytest/pytest.yatest.ini7
-rw-r--r--library/python/pytest/rewrite.py123
-rw-r--r--library/python/pytest/ya.make32
-rw-r--r--library/python/pytest/yatest_tools.py304
-rw-r--r--library/python/reservoir_sampling/README.md11
-rw-r--r--library/python/reservoir_sampling/__init__.py16
-rw-r--r--library/python/reservoir_sampling/ya.make10
-rw-r--r--library/python/resource/__init__.py49
-rw-r--r--library/python/resource/ut/lib/qw.txt1
-rw-r--r--library/python/resource/ut/lib/test_simple.py31
-rw-r--r--library/python/resource/ut/lib/ya.make17
-rw-r--r--library/python/resource/ut/py2/ya.make9
-rw-r--r--library/python/resource/ut/py3/ya.make9
-rw-r--r--library/python/resource/ut/ya.make6
-rw-r--r--library/python/resource/ya.make13
-rw-r--r--library/python/runtime_py3/__res.pyx36
-rw-r--r--library/python/runtime_py3/entry_points.py52
-rw-r--r--library/python/runtime_py3/importer.pxi571
-rw-r--r--library/python/runtime_py3/main/get_py_main.cpp8
-rw-r--r--library/python/runtime_py3/main/main.c231
-rw-r--r--library/python/runtime_py3/main/ya.make26
-rw-r--r--library/python/runtime_py3/sitecustomize.pyx69
-rw-r--r--library/python/runtime_py3/test/.dist-info/METADATA14
-rw-r--r--library/python/runtime_py3/test/.dist-info/RECORD1
-rw-r--r--library/python/runtime_py3/test/.dist-info/entry_points.txt2
-rw-r--r--library/python/runtime_py3/test/.dist-info/top_level.txt1
-rw-r--r--library/python/runtime_py3/test/canondata/result.json62
-rw-r--r--library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-default_/stderr.txt12
-rw-r--r--library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-default_/stdout.txt2
-rw-r--r--library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-ultratb_color_/stderr.txt13
-rw-r--r--library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-ultratb_color_/stdout.txt2
-rw-r--r--library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-ultratb_verbose_/stderr.txt41
-rw-r--r--library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-ultratb_verbose_/stdout.txt2
-rw-r--r--library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-default_/stderr.txt12
-rw-r--r--library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-default_/stdout.txt2
-rw-r--r--library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-ultratb_color_/stderr.txt13
-rw-r--r--library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-ultratb_color_/stdout.txt2
-rw-r--r--library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-ultratb_verbose_/stderr.txt41
-rw-r--r--library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-ultratb_verbose_/stdout.txt2
-rw-r--r--library/python/runtime_py3/test/resources/__init__.py0
-rw-r--r--library/python/runtime_py3/test/resources/foo.txt1
-rw-r--r--library/python/runtime_py3/test/resources/submodule/__init__.py0
-rw-r--r--library/python/runtime_py3/test/resources/submodule/bar.txt1
-rw-r--r--library/python/runtime_py3/test/test_arcadia_source_finder.py317
-rw-r--r--library/python/runtime_py3/test/test_metadata.py44
-rw-r--r--library/python/runtime_py3/test/test_resources.py60
-rw-r--r--library/python/runtime_py3/test/test_traceback.py63
-rw-r--r--library/python/runtime_py3/test/traceback/__main__.py4
-rw-r--r--library/python/runtime_py3/test/traceback/crash.py44
-rw-r--r--library/python/runtime_py3/test/traceback/mod/__init__.py3
-rw-r--r--library/python/runtime_py3/test/traceback/ya.make19
-rw-r--r--library/python/runtime_py3/test/ya.make40
-rw-r--r--library/python/runtime_py3/ya.make49
-rw-r--r--library/python/strings/__init__.py17
-rw-r--r--library/python/strings/strings.py129
-rw-r--r--library/python/strings/ut/test_strings.py205
-rw-r--r--library/python/strings/ut/ya.make11
-rw-r--r--library/python/strings/ya.make16
-rw-r--r--library/python/svn_version/__init__.py1
-rw-r--r--library/python/svn_version/__svn_version.pyx35
-rw-r--r--library/python/svn_version/ut/lib/test_simple.py16
-rw-r--r--library/python/svn_version/ut/lib/ya.make13
-rw-r--r--library/python/svn_version/ut/py2/ya.make9
-rw-r--r--library/python/svn_version/ut/py3/ya.make9
-rw-r--r--library/python/svn_version/ut/ya.make5
-rw-r--r--library/python/svn_version/ya.make15
-rw-r--r--library/python/symbols/libc/syms.cpp157
-rw-r--r--library/python/symbols/libc/ya.make19
-rw-r--r--library/python/symbols/module/__init__.py48
-rw-r--r--library/python/symbols/module/module.cpp85
-rw-r--r--library/python/symbols/module/ya.make23
-rw-r--r--library/python/symbols/python/syms.cpp17
-rw-r--r--library/python/symbols/python/ut/py2/ya.make9
-rw-r--r--library/python/symbols/python/ut/py3/ya.make9
-rw-r--r--library/python/symbols/python/ut/test_ctypes.py37
-rw-r--r--library/python/symbols/python/ut/ya.make16
-rw-r--r--library/python/symbols/python/ya.make15
-rw-r--r--library/python/symbols/registry/syms.cpp31
-rw-r--r--library/python/symbols/registry/syms.h24
-rw-r--r--library/python/symbols/registry/ya.make9
-rw-r--r--library/python/symbols/ya.make12
-rw-r--r--library/python/testing/__init__.py0
-rw-r--r--library/python/testing/filter/filter.py57
-rw-r--r--library/python/testing/filter/ya.make5
-rw-r--r--library/python/testing/import_test/import_test.py124
-rw-r--r--library/python/testing/import_test/ya.make10
-rw-r--r--library/python/testing/recipe/__init__.py102
-rw-r--r--library/python/testing/recipe/ports.py33
-rw-r--r--library/python/testing/recipe/ya.make19
-rw-r--r--library/python/testing/ya.make22
-rw-r--r--library/python/testing/yatest_common/ya.make40
-rw-r--r--library/python/testing/yatest_common/yatest/__init__.py3
-rw-r--r--library/python/testing/yatest_common/yatest/common/__init__.py8
-rw-r--r--library/python/testing/yatest_common/yatest/common/benchmark.py22
-rw-r--r--library/python/testing/yatest_common/yatest/common/canonical.py176
-rw-r--r--library/python/testing/yatest_common/yatest/common/environment.py5
-rw-r--r--library/python/testing/yatest_common/yatest/common/errors.py20
-rw-r--r--library/python/testing/yatest_common/yatest/common/legacy.py12
-rw-r--r--library/python/testing/yatest_common/yatest/common/misc.py19
-rw-r--r--library/python/testing/yatest_common/yatest/common/network.py271
-rw-r--r--library/python/testing/yatest_common/yatest/common/path.py90
-rw-r--r--library/python/testing/yatest_common/yatest/common/process.py733
-rw-r--r--library/python/testing/yatest_common/yatest/common/runtime.py343
-rw-r--r--library/python/testing/yatest_common/yatest/common/runtime_java.py46
-rw-r--r--library/python/testing/yatest_common/yatest/common/tags.py5
-rw-r--r--library/python/testing/yatest_common/yatest/common/ya.make1
-rw-r--r--library/python/testing/yatest_lib/__init__.py0
-rw-r--r--library/python/testing/yatest_lib/external.py192
-rw-r--r--library/python/testing/yatest_lib/test_splitter.py102
-rw-r--r--library/python/testing/yatest_lib/tests/test_external.py20
-rw-r--r--library/python/testing/yatest_lib/tests/test_testsplitter.py103
-rw-r--r--library/python/testing/yatest_lib/tests/ya.make14
-rw-r--r--library/python/testing/yatest_lib/tools.py64
-rw-r--r--library/python/testing/yatest_lib/ya.make26
-rw-r--r--library/python/testing/yatest_lib/ya.py239
-rw-r--r--library/python/windows/__init__.py364
-rw-r--r--library/python/windows/ut/test_windows.py96
-rw-r--r--library/python/windows/ut/ya.make11
-rw-r--r--library/python/windows/ya.make13
-rw-r--r--library/python/ya.make222
-rw-r--r--library/ya.make18
3110 files changed, 494804 insertions, 0 deletions
diff --git a/library/README.md b/library/README.md
new file mode 100644
index 0000000000..fc418bef7b
--- /dev/null
+++ b/library/README.md
@@ -0,0 +1,48 @@
+library
+===
+`library/` is a directory with reusable libraries. Common ideas (with [key words](https://tools.ietf.org/html/rfc2119)):
+
+1. Libraries are categorized by the languages in which they will be used.
+ Bindings **MUST** be put in `<language>` directory.
+
+2. Grouping by any other criteria **SHOULD** be defined by the language committee in `<language>` directory.
+
+3. The library **SHOULD** be in use in at least two projects.
+
+ If you are not sure if you should put some library in `library/`, please contact `<language>` committee or arcadia-wg@yandex-team.ru.
+
+4. The library **SHOULD** be portable.
+
+ Please contact `<language>` committee if you cannot provide usage on all platforms: `linux`, `darwin`, `windows`.
+
+5. The library **MUST** depend only on a limited list of external components
+ (currently it is `util/`, `contrib/`, `vendor/`, `library/`).
+
+6. Any code in Arcadia (except `contrib/`, `vendor/` and `util/`) **MAY** depend on the `library/`.
+
+7. The library **MUST** be accompanied by `README.md` file and a brief description of the project.
+
+8. The library **MUST** be accompanied by unit-tests.
+
+9. CPU- or/and RAM-bound algorithms **SHOULD** provide benchmarks.
+
+10. There **MUST** be no trade secrets of Yandex in `library/`: anything that can cause harm on publishing as OpenSource. For example:
+ * spam filter rules;
+ * coefficients for ML;
+ * etc.
+
+11. All OSS (OpenSource Software) ready code **MUST** be accompanied by macro [LICENCE](https://docs.yandex-team.ru/ya-make/manual/common/macros#licence(license...)) in `ya.make`.
+
+12. All language specific aspects are defined by `<language>` committee: see `library/<language>/README.md`.
+
+13. The library **MUST** satisfy `<language>` style-guide.
+
+14. The existing library **SHOULD** be improved instead of creating a new one - if it is possible.
+
+ Please do not create yet another library for the same thing: just improve existing one.
+
+Contacts
+===
+If you have any language-specific questions, please contact `<language>` [committee](https://wiki.yandex-team.ru/devrules/#profilnyekomitety).
+
+If you have any other question about `library/`, please contact arcadia-wg@yandex-team.ru.
diff --git a/library/cpp/accurate_accumulate/accurate_accumulate.cpp b/library/cpp/accurate_accumulate/accurate_accumulate.cpp
new file mode 100644
index 0000000000..20928f81f4
--- /dev/null
+++ b/library/cpp/accurate_accumulate/accurate_accumulate.cpp
@@ -0,0 +1 @@
+#include "accurate_accumulate.h"
diff --git a/library/cpp/accurate_accumulate/accurate_accumulate.h b/library/cpp/accurate_accumulate/accurate_accumulate.h
new file mode 100644
index 0000000000..dacced17e9
--- /dev/null
+++ b/library/cpp/accurate_accumulate/accurate_accumulate.h
@@ -0,0 +1,221 @@
+#pragma once
+
+#include <util/ysaveload.h>
+#include <util/generic/vector.h>
+#include <util/system/yassert.h>
+
+//! See more details here http://en.wikipedia.org/wiki/Kahan_summation_algorithm
+template <typename TAccumulateType>
+class TKahanAccumulator {
+public:
+ using TValueType = TAccumulateType;
+
+ template <typename TFloatType>
+ explicit TKahanAccumulator(const TFloatType x)
+ : Sum_(x)
+ , Compensation_()
+ {
+ }
+
+ TKahanAccumulator()
+ : Sum_()
+ , Compensation_()
+ {
+ }
+
+ template <typename TFloatType>
+ TKahanAccumulator& operator=(const TFloatType& rhs) {
+ Sum_ = TValueType(rhs);
+ Compensation_ = TValueType();
+ return *this;
+ }
+
+ TValueType Get() const {
+ return Sum_ + Compensation_;
+ }
+
+ template <typename TFloatType>
+ inline operator TFloatType() const {
+ return Get();
+ }
+
+ template <typename TFloatType>
+ inline bool operator<(const TKahanAccumulator<TFloatType>& other) const {
+ return Get() < other.Get();
+ }
+
+ template <typename TFloatType>
+ inline bool operator<=(const TKahanAccumulator<TFloatType>& other) const {
+ return !(other < *this);
+ }
+
+ template <typename TFloatType>
+ inline bool operator>(const TKahanAccumulator<TFloatType>& other) const {
+ return other < *this;
+ }
+
+ template <typename TFloatType>
+ inline bool operator>=(const TKahanAccumulator<TFloatType>& other) const {
+ return !(*this < other);
+ }
+
+ template <typename TFloatType>
+ inline TKahanAccumulator& operator+=(const TFloatType x) {
+ const TValueType y = TValueType(x) - Compensation_;
+ const TValueType t = Sum_ + y;
+ Compensation_ = (t - Sum_) - y;
+ Sum_ = t;
+ return *this;
+ }
+
+ template <typename TFloatType>
+ inline TKahanAccumulator& operator-=(const TFloatType x) {
+ return *this += -TValueType(x);
+ }
+
+ template <typename TFloatType>
+ inline TKahanAccumulator& operator*=(const TFloatType x) {
+ return *this = TValueType(*this) * TValueType(x);
+ }
+
+ template <typename TFloatType>
+ inline TKahanAccumulator& operator/=(const TFloatType x) {
+ return *this = TValueType(*this) / TValueType(x);
+ }
+
+ Y_SAVELOAD_DEFINE(Sum_, Compensation_)
+
+private:
+ TValueType Sum_;
+ TValueType Compensation_;
+};
+
+template <typename TAccumulateType, typename TFloatType>
+inline const TKahanAccumulator<TAccumulateType>
+operator+(TKahanAccumulator<TAccumulateType> lhs, const TFloatType rhs) {
+ return lhs += rhs;
+}
+
+template <typename TAccumulateType, typename TFloatType>
+inline const TKahanAccumulator<TAccumulateType>
+operator-(TKahanAccumulator<TAccumulateType> lhs, const TFloatType rhs) {
+ return lhs -= rhs;
+}
+
+template <typename TAccumulateType, typename TFloatType>
+inline const TKahanAccumulator<TAccumulateType>
+operator*(TKahanAccumulator<TAccumulateType> lhs, const TFloatType rhs) {
+ return lhs *= rhs;
+}
+
+template <typename TAccumulateType, typename TFloatType>
+inline const TKahanAccumulator<TAccumulateType>
+operator/(TKahanAccumulator<TAccumulateType> lhs, const TFloatType rhs) {
+ return lhs /= rhs;
+}
+
+template <typename TAccumulatorType, typename It>
+static inline TAccumulatorType TypedFastAccumulate(It begin, It end) {
+ TAccumulatorType accumulator = TAccumulatorType();
+
+ for (; begin + 15 < end; begin += 16) {
+ accumulator += *(begin + 0) +
+ *(begin + 1) +
+ *(begin + 2) +
+ *(begin + 3) +
+ *(begin + 4) +
+ *(begin + 5) +
+ *(begin + 6) +
+ *(begin + 7) +
+ *(begin + 8) +
+ *(begin + 9) +
+ *(begin + 10) +
+ *(begin + 11) +
+ *(begin + 12) +
+ *(begin + 13) +
+ *(begin + 14) +
+ *(begin + 15);
+ }
+ for (; begin != end; ++begin) {
+ accumulator += *begin;
+ }
+
+ return accumulator;
+}
+
+template <class TOperation, typename TAccumulatorType, typename It1, typename It2>
+static inline TAccumulatorType TypedFastInnerOperation(It1 begin1, It1 end1, It2 begin2) {
+ TAccumulatorType accumulator = TAccumulatorType();
+
+ const TOperation op;
+ for (; begin1 + 15 < end1; begin1 += 16, begin2 += 16) {
+ accumulator += op(*(begin1 + 0), *(begin2 + 0)) +
+ op(*(begin1 + 1), *(begin2 + 1)) +
+ op(*(begin1 + 2), *(begin2 + 2)) +
+ op(*(begin1 + 3), *(begin2 + 3)) +
+ op(*(begin1 + 4), *(begin2 + 4)) +
+ op(*(begin1 + 5), *(begin2 + 5)) +
+ op(*(begin1 + 6), *(begin2 + 6)) +
+ op(*(begin1 + 7), *(begin2 + 7)) +
+ op(*(begin1 + 8), *(begin2 + 8)) +
+ op(*(begin1 + 9), *(begin2 + 9)) +
+ op(*(begin1 + 10), *(begin2 + 10)) +
+ op(*(begin1 + 11), *(begin2 + 11)) +
+ op(*(begin1 + 12), *(begin2 + 12)) +
+ op(*(begin1 + 13), *(begin2 + 13)) +
+ op(*(begin1 + 14), *(begin2 + 14)) +
+ op(*(begin1 + 15), *(begin2 + 15));
+ }
+ for (; begin1 != end1; ++begin1, ++begin2) {
+ accumulator += op(*begin1, *begin2);
+ }
+
+ return accumulator;
+}
+
+template <typename TAccumulatorType, typename It1, typename It2>
+static inline TAccumulatorType TypedFastInnerProduct(It1 begin1, It1 end1, It2 begin2) {
+ return TypedFastInnerOperation<std::multiplies<>, TAccumulatorType>(begin1, end1, begin2);
+}
+
+template <typename It>
+static inline double FastAccumulate(It begin, It end) {
+ return TypedFastAccumulate<double>(begin, end);
+}
+
+template <typename T>
+static inline double FastAccumulate(const TVector<T>& sequence) {
+ return FastAccumulate(sequence.begin(), sequence.end());
+}
+
+template <typename It>
+static inline double FastKahanAccumulate(It begin, It end) {
+ return TypedFastAccumulate<TKahanAccumulator<double>>(begin, end);
+}
+
+template <typename T>
+static inline double FastKahanAccumulate(const TVector<T>& sequence) {
+ return FastKahanAccumulate(sequence.begin(), sequence.end());
+}
+
+template <typename It1, typename It2>
+static inline double FastInnerProduct(It1 begin1, It1 end1, It2 begin2) {
+ return TypedFastInnerProduct<double>(begin1, end1, begin2);
+}
+
+template <typename T>
+static inline double FastInnerProduct(const TVector<T>& lhs, const TVector<T>& rhs) {
+ Y_ASSERT(lhs.size() == rhs.size());
+ return FastInnerProduct(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+template <typename It1, typename It2>
+static inline double FastKahanInnerProduct(It1 begin1, It1 end1, It2 begin2) {
+ return TypedFastInnerProduct<TKahanAccumulator<double>>(begin1, end1, begin2);
+}
+
+template <typename T>
+static inline double FastKahanInnerProduct(const TVector<T>& lhs, const TVector<T>& rhs) {
+ Y_ASSERT(lhs.size() == rhs.size());
+ return FastKahanInnerProduct(lhs.begin(), lhs.end(), rhs.begin());
+}
diff --git a/library/cpp/accurate_accumulate/benchmark/main.cpp b/library/cpp/accurate_accumulate/benchmark/main.cpp
new file mode 100644
index 0000000000..3c5e6e775d
--- /dev/null
+++ b/library/cpp/accurate_accumulate/benchmark/main.cpp
@@ -0,0 +1,97 @@
+#include <library/cpp/accurate_accumulate/accurate_accumulate.h>
+#include <library/cpp/testing/benchmark/bench.h>
+
+#include <util/generic/algorithm.h>
+#include <util/generic/singleton.h>
+#include <util/generic/vector.h>
+#include <util/generic/xrange.h>
+#include <util/random/fast.h>
+
+namespace {
+ template <typename T, size_t N>
+ struct TNormalizedExamplesHolder {
+ TVector<T> Examples;
+ TNormalizedExamplesHolder()
+ : Examples(N)
+ {
+ TFastRng<ui64> prng{sizeof(T) * N * 42u};
+ for (auto& x : Examples) {
+ x = prng.GenRandReal4();
+ }
+ }
+ };
+
+ template <typename T, size_t N>
+ struct TExamplesHolder {
+ TVector<T> Examples;
+ TExamplesHolder()
+ : Examples(N)
+ {
+ TFastRng<ui64> prng{sizeof(T) * N * 42u + 100500u};
+ for (auto& x : Examples) {
+ // operations with non-normalized floating point numbers are rumored to work slower
+ x = prng.GenRandReal4() + prng.Uniform(1024u);
+ }
+ }
+ };
+}
+
+#define DEFINE_BENCHMARK(type, count) \
+ Y_CPU_BENCHMARK(SimpleNorm_##type##_##count, iface) { \
+ const auto& examples = Default<TNormalizedExamplesHolder<type, count>>().Examples; \
+ for (const auto i : xrange(iface.Iterations())) { \
+ Y_UNUSED(i); \
+ Y_DO_NOT_OPTIMIZE_AWAY( \
+ (type)Accumulate(std::cbegin(examples), std::cend(examples), type{})); \
+ } \
+ } \
+ \
+ Y_CPU_BENCHMARK(KahanNorm_##type##_##count, iface) { \
+ const auto& examples = Default<TNormalizedExamplesHolder<type, count>>().Examples; \
+ for (const auto i : xrange(iface.Iterations())) { \
+ Y_UNUSED(i); \
+ Y_DO_NOT_OPTIMIZE_AWAY( \
+ (type)Accumulate(std::cbegin(examples), std::cend(examples), TKahanAccumulator<type>{})); \
+ } \
+ } \
+ \
+ Y_CPU_BENCHMARK(Simple_##type##_##count, iface) { \
+ const auto& examples = Default<TExamplesHolder<type, count>>().Examples; \
+ for (const auto i : xrange(iface.Iterations())) { \
+ Y_UNUSED(i); \
+ Y_DO_NOT_OPTIMIZE_AWAY( \
+ (type)Accumulate(std::cbegin(examples), std::cend(examples), type{})); \
+ } \
+ } \
+ \
+ Y_CPU_BENCHMARK(Kahan_##type##_##count, iface) { \
+ const auto& examples = Default<TExamplesHolder<type, count>>().Examples; \
+ for (const auto i : xrange(iface.Iterations())) { \
+ Y_UNUSED(i); \
+ Y_DO_NOT_OPTIMIZE_AWAY( \
+ (type)Accumulate(std::cbegin(examples), std::cend(examples), TKahanAccumulator<type>{})); \
+ } \
+ }
+
+DEFINE_BENCHMARK(float, 2)
+DEFINE_BENCHMARK(float, 4)
+DEFINE_BENCHMARK(float, 8)
+DEFINE_BENCHMARK(float, 16)
+DEFINE_BENCHMARK(float, 32)
+DEFINE_BENCHMARK(float, 64)
+DEFINE_BENCHMARK(float, 128)
+DEFINE_BENCHMARK(float, 256)
+DEFINE_BENCHMARK(float, 512)
+DEFINE_BENCHMARK(float, 1024)
+DEFINE_BENCHMARK(double, 2)
+DEFINE_BENCHMARK(double, 4)
+DEFINE_BENCHMARK(double, 8)
+DEFINE_BENCHMARK(double, 16)
+DEFINE_BENCHMARK(double, 32)
+DEFINE_BENCHMARK(double, 64)
+DEFINE_BENCHMARK(double, 128)
+DEFINE_BENCHMARK(double, 256)
+DEFINE_BENCHMARK(double, 512)
+DEFINE_BENCHMARK(double, 1024)
+
+#undef DEFINE_BENCHMARK
diff --git a/library/cpp/accurate_accumulate/benchmark/metrics/main.py b/library/cpp/accurate_accumulate/benchmark/metrics/main.py
new file mode 100644
index 0000000000..311fc219ce
--- /dev/null
+++ b/library/cpp/accurate_accumulate/benchmark/metrics/main.py
@@ -0,0 +1,7 @@
+import yatest.common as yc
+
+
+def test_export_metrics(metrics):
+ metrics.set_benchmark(yc.execute_benchmark(
+ 'library/cpp/accurate_accumulate/benchmark/benchmark',
+ threads=8))
diff --git a/library/cpp/accurate_accumulate/benchmark/metrics/ya.make b/library/cpp/accurate_accumulate/benchmark/metrics/ya.make
new file mode 100644
index 0000000000..5d532e1479
--- /dev/null
+++ b/library/cpp/accurate_accumulate/benchmark/metrics/ya.make
@@ -0,0 +1,17 @@
+OWNER(yazevnul)
+
+PY2TEST()
+
+SIZE(LARGE)
+
+TAG(
+ ya:force_sandbox
+ sb:intel_e5_2660v1
+ ya:fat
+)
+
+TEST_SRCS(main.py)
+
+DEPENDS(library/cpp/accurate_accumulate/benchmark)
+
+END()
diff --git a/library/cpp/accurate_accumulate/benchmark/ya.make b/library/cpp/accurate_accumulate/benchmark/ya.make
new file mode 100644
index 0000000000..20fd877389
--- /dev/null
+++ b/library/cpp/accurate_accumulate/benchmark/ya.make
@@ -0,0 +1,13 @@
+OWNER(yazevnul)
+
+Y_BENCHMARK()
+
+SRCS(
+ main.cpp
+)
+
+PEERDIR(
+ library/cpp/accurate_accumulate
+)
+
+END()
diff --git a/library/cpp/accurate_accumulate/ya.make b/library/cpp/accurate_accumulate/ya.make
new file mode 100644
index 0000000000..82630d19be
--- /dev/null
+++ b/library/cpp/accurate_accumulate/ya.make
@@ -0,0 +1,10 @@
+LIBRARY()
+
+OWNER(alex-sh)
+
+SRCS(
+ accurate_accumulate.h
+ accurate_accumulate.cpp
+)
+
+END()
diff --git a/library/cpp/actors/README.md b/library/cpp/actors/README.md
new file mode 100644
index 0000000000..c39908f2f5
--- /dev/null
+++ b/library/cpp/actors/README.md
@@ -0,0 +1,107 @@
+## Actor library
+
+### Часть первая, вводная.
+Иногда приходится разрабатывать асинхронные, существенно параллельные, местами распределённые программы. Иногда еще и внутренняя логика нетривиальна, разнородна, пишется разными командами не один год. Всё как мы любим. Человечеством придумано не так много способов внутренней организации структуры и кода таких программ. Большинство из них плохие (и именно из-за плохих подходов разработка асинхронных, многопоточных программ приобрела дурную славу). Некоторые получше. А серебряной пули как обычно нет.
+
+Когда мы начинали разработку Yandex Database (тогда еще KiKiMR), сразу было понятно что простыми наколеночными поделиями обойтись (и сделать при этом хорошо, так что бы не было стыдно) не получится. В качестве базиса мы выбрали мессадж-пассинг и модель акторов. И не пожалели. Постепенно этот подход распространился на смежные проекты.
+
+### Базовые концепции.
+Если отбросить шелуху – представляем сервис (программу в случае запуска изолированного бинарника) как ансамбль независимых агентов, взаимодействующих через отправку асинхронных сообщений внутри общего окружения. Тут все слова важны:
+
+Независимых – не разделяют состояние и поток выполнения.
+Передача сообщений – формализуем протоколы, а не интерфейсы.
+
+Асинхронная – не блокируемся на отправке сообщений.
+Общее окружение – все агенты разделяют общий пул ресурсов и каждый из них, зная адрес, может послать сообщение каждому.
+
+В более хайповых терминах – очень похоже на колокейтед микросервисы, только уровнем ниже. И да, мы заведомо не хотели прятать асинхронщину и параллелизм от разработчика, показывая прям самое мясо.
+
+### IActor.
+https://a.yandex-team.ru/arc/trunk/arcadia/library/actors/core/actor.h?rev=5315854#L105
+Базовый класс всех агентов, напрямую обычно не используется. Инстанцируется либо TActor, либо TActorBootstrapped. Фактически весь полезный код программы размещается в акторах.
+(важное замечание – в коде увидите ручки с TActorContext и без него, схожие по названию и назначению. На данный момент вариант с TActorContext является устаревшим, новый код стоит писать без его использования).
+Важные методы:
+
+PassAway – единственный корректный способ зарегистрированному актору умереть. Может вызываться только находясь внутри обработчика сообщения.
+Send – отправка сообщения, зная адрес получателя. В акторе доступен хелпер, принимающий непосредственно сообщение. Базовый вызов, принимающий полный event handle – доступен в контексте.
+
+Become – установить функцию-обработчик сообщений, которая будет использована при получении следующего сообщения.
+
+Register – зарегистрировать новый актор в акторсистеме, с выделением нового мейлбокса. Важно – с момента вызова владение актором передается акторсистеме, т.е. уже к моменту выхода актор может начать выполняться на другом потоке, нельзя к нему ни обращаться прямыми вызовами, ни даже предполагать что он еще жив.
+
+Schedule – зарегистрировать сообщение, которое будет отправлено не менее чем через запрошенную задержку. В акторе доступен хелпер, декорирующий сообщение хендлом отправки самому себе, в контексте можно передать полный хендл.
+
+SelfId – узнать собственный адрес. Возвращаемый объект TActorIdentity можно передавать если требуется делегировать отправку сообщений от имени актора (например если пишете полезный код пользуясь пассивными объектами).
+Посылка сообщений дешёвая, не нужно на ней чрезмерно экономить (но не бесплатная – поэтому посылать сообщения только ради посылки сообщений то же не стоит).
+
+Инстанцирование акторов так же дёшево, актор на запрос или фазу запроса – вполне нормальная практика. Мультиплексировать обработку разных запросов в одном акторе – так же вполне нормально. В нашем коде много примеров и первого, и второго. Пользуйтесь здравым смыслов и собственным вкусом.
+Т.к. на время обработки сообщения актор занимает тред из пула акторсистемы – уходить в длинные вычисления лучше на отдельном отселённом акторе (и либо отселять в отдельный пол акторсистемы, либо контролировать параллельность брокером ресурсов), блокирующие вызовы делать почти всегда ошибка. Стремление написать мютекс - ересь и от лукавого.
+Идентифицируются акторы своим TActorID-ом, который уникален и вы не должны его придумывать из воздуха, а только получить из регистрации (для порождённых акторов) или его вам должен рассказать кто-то, законно его знающий.
+
+Отправка на несуществующий актор (уже умерший) безопасна, сообщение будет просто выброшено в момент обработки (как обрабатывать недоставку сообщений в протоколах расскажу ниже).
+
+Кроме нормальных TActorID существуют еще и сервисные (составленные из строчки и номера ноды). Под ними может быть зарегистрирован реальный актор и фактически при получении сообщения по сервисному адресу – попробует переправить его текущему фактическому. Это позволяет размещать хорошо известные сервисы по хорошо известному адресу, не выстраивая параллельную машинерию поиска.
+
+Строить из актора конечный автомат при помощи переключений функции-обработчика – выбор в каждом конкретном случае, иногда удобнее да, иногда сваливать всё в одно состояние, а иногда – применять гибридное решение (когда часть жизненного цикла – обычно инициализации и завершение – выражены в переходах, а часть – нет).
+Меньше слов, больше дела – этого уже достаточно что бы прочитать самый простой пример. https://a.yandex-team.ru/arc/trunk/arcadia/library/actors/examples/01_ping_pong
+Здесь можно увидеть образец самого простого актора, занимающегося переброской сообщений и использующего все основные вызовы. Заодно покрутив за разные ручки (количество тредов в тредпуле, количество пар перебрасывающихся акторов) можно посмотреть на изменение поведения системы (hint: в таких простых сценариях максимум перфоманса достигается при одном треде в тредпулах).
+
+### Event и Event Handle.
+Полезную нагрузку сообщений заворачиваем в наследника IEventBase, у которого два важных метода – сериализация и загрузка. Сериализация виртуальная, а вот загрузка – нет, и для разбора сообщения из байтовой последовательности – необходимо на стороне получателя сматчить число-идентификатор типа ивента с С++ типом. Именно это делают макросы из hfunc.h. На практике ивенты создаются либо как наследник TEventLocal<> (для строго локальных сообщений) либо как наследник TEventPB<> (для потенциально пересылаемых по сети сообщений, типизируются protobuf-мессаджем).
+
+Кроме непосредственно ивента (в виде структуры либо в виде байтовой строки) для пересылки сообщения необходим набор дополнительных полей
+
+Адресат
+
+Отправитель
+
+Тип сообщения
+
+Кука
+
+Флаги
+
+Сообщение + дополнительные поля = IEventHandle. Именно хендлами акторсистема и оперирует. <event-type>::TPtr – в примере выше – это и есть указатель на типизированный хендл.
+
+Технически типом сообщения может быть любое число, которое получатель и отправитель договорились понимать как идентификатор сообщения. Сложившаяся практика – выделять диапазон идентификаторов макросом EventSpaceBegin (фактически блоками по 64к), начиная с блока ES_USERSPACE.
+Кука – неинтерпретируемое ui64 число, передаваемое с хендлом. Хорошей практикой является в ответе сервиса на сообщение выставлять куку в куку исходного сообщения, особенно для сервисов, потенциально используемых конкурентно.
+
+В флагах несколько бит зарезервировано под флаги, декларирующие как необходимо обрабатывать особые ситуации и 12 бит – под номер канала интерконнекта, в котором будет пересылаться сообщение (для локальных сообщений в имеющихся реализациях номер канала не имеет значения - хотя можно представить реализацию где для каналов будут независимые очереди).
+
+### Тредпулы и мейлбоксы.
+В рамках одной акторсистемы может сосуществовать несколько независимых тредпулов, каждый актор регистрируется на конкретном и в процессе жизни не может мигрировать (но может создавать новые акторы на произвольном тредпуле). Используется для крупноблочного разделения ресурсов, либо между разными активностями (вот здесь – обрабатываем один класс запросов, а вот здесь - другой), либо между разными профилями активности (вот здесь обрабатываем быстрые запросы, здесь – медленные, а вот там – вообще батчёвые). Например в YDB работает системный тредпул (в котором запускаются акторы, необходимые для функционирования YDB, и для которого мы следим что бы не было длительной блокировки в обработчиках), пользовательский тредпул (в котором обрабатываются запросы и потенциально обработчики могут уходить в себя подольше, но это не повлияет на инфраструктуру), батчёвый тредпул (куда отгружается длительная обработка – компакшены дисков, сканы таблиц и подобное) и, в жирных нодах – тредпул интерконнекта (как наиболее чувствительного к задержкам).
+Пересылка сообщений между акторами разных тредпулов но одной локальной акторсистемы остаётся локальной, принудительной сериализации сообщения не происходит.
+
+При регистрации актор прикрепляется к мейлбоксу (в типичном случае на собственном мейлбоксе, но по особой нужде можно находясь внутри обработки сообщения прикрепить порождённый актор к текущему активному мейлбоксу – см. RegisterWithSameMailbox (ранее RegisterLocal) – в этом случае будет гарантироваться отсутствие конкурентной обработки сообщений). Собственно Send – это и есть заворачивание ивента в хендл, помещение хендла в очередь мейлбокса и добавление мейлбокса в очередь активации тредпула. В рамках одного мейлбокса – обработка FIFO, между мейлбоксами таких гарантий нет, хотя и стараемся активировать мейлбоксы примерно в порядке появления в них сообщений.
+
+При регистрации актора можно выбрать тип мейлбокса, они немного отличаются стоимость добавления – либо дёшево, но похуже под контеншеном, либо почти wait-free, но подороже. См. комментарии к TMailboxType за актуальными подсказками что-как.
+
+Полезные хелперы.
+
+STFUNC – декларация стейт-функции, рекомендую всегда использовать именно такую форму для декларации, т.к. потом проще искать.
+
+hFunc – макрос выбора хендлера, передающий ивент в обработчик.
+
+cFunc – макрос выбора хендлера, не передающий ивент в обработчик.
+
+### Обработка сбоев.
+В рамках локальной акторсистемы доставка сообщений гарантирована, если по какой-то причине сообщение не доставлено (важно! Именно не доставлено, факт обработанности сообщения уже на совести принимающего актора) – то произойдёт одно из:
+
+Если выставлен флаг FlagForwardOnNondelivery – сообщение будет переправлено на актор, переданный как forwardOnNondelivery при конструировании хендла. Полезно например если какие-то сервисы создаются по требованию и для несозданных сервисов – желаем зароутить в роутер. Работает только в рамках локальной акторсистемы.
+
+Иначе при выставленном флаге FlagTrackDelivery – для отправителя будет сгенерирован ивент TEvUndelivered от имени недоступного актора. Получение такого сообщения гарантирует что исходный ивент не был обработан и никакие эффекты не произошли. Генерация и доставка нотификации в рамках локальной акторсистемы гарантирована, в распределённой – как повезёт, может и потеряться.
+
+Иначе, если никакие флаги не выставлены – сообщение будет выброшено.
+
+Т.к. в распределённой системе доставка нотификаций о недоставке не гарантируется, то для надёжной обработки сбоев необходим дополнительный механизм – по флагу FlagSubscribeOnSession при пересечении границ ноды происходит подписка отправителя на нотификацию о разрыве сетевой сессии, в рамках которой сообщение было отправлено. Теперь при разрыве сетевой сессии отправитель узнает что сообщение могло быть недоставлено (а могло и быть доставлено – мы не знаем) и сможет отреагировать. Нужно не забывать отписываться от нотификации о разрыве сессий – иначе будут копиться вплоть до ближайшего разрыва (который может и не скоро произойти).
+
+Резюмируя: при необходимости контролировать доставку внутри локальной акторсистемы – выставляем флаг FlagTrackDelivery и обрабатываем TEvUndelivered. Для распределённой – добавляем FlagSubscribeOnSession и дополнительно обрабатываем TEvNodeDisconnected не забывая отписываться от более не нужных подписок.
+
+### Интерконнект.
+Локальная акторсистема – это только половина пирога, возможность объединить их в распределённую – вторая половина. Реализация интерконнекта доступна из коробки и умеет
+Передавать сообщения через одно tcp-соединение
+Мультиплексировать разные потоки (ака каналы) в рамках одного соединения, гарантируя порядок в рамках канала
+Старается делать это хорошо.
+В рамках распределённой системы требуется каждой локальной акторсистеме назначить уникальный номер (например табличкой или реализовав динамическую раздачу номеров ноды) и запустить в рамках каждой локальной акторсистемы локальный неймсервис (например по табличке ремапинга номера ноды в сетевой адрес либо как кеш опорного неймсервиса).
+Смотрим на второй пример https://a.yandex-team.ru/arc/trunk/arcadia/library/actors/examples/02_discovery
+Тут у нас конфигурируется распределённая акторсистема (в примере все пять запускаются в одном бинарнике, но точно так же – можно запускать и частями) на пять нод. На каждой ноде запускается реплика для паблишинга строчек и актор-эндпоинт (каждый со своим портом). Эндпоинты с помощью актора-паблишера публикуют свои явки/пароли на распределённый сторадж (с обработкой нештатных ситауций и поддержанием в актуальном состоянии). И рядом лежит реализация запроса к стораджу на листинг опубликованого по мажорити. Собственно это упрощённый и почищенный от специфики код, используемый в YDB для публикации и нахождения актуальных эндпоинтов пользовательской базы.
diff --git a/library/cpp/actors/core/README.md b/library/cpp/actors/core/README.md
new file mode 100644
index 0000000000..439a8dd459
--- /dev/null
+++ b/library/cpp/actors/core/README.md
@@ -0,0 +1,99 @@
+## Memory tracker
+
+https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/actors/core/memory_track.h
+
+Использование:
+
+* отслеживание аллокаций экземпляров конкретного класса через new/delete и new[]/delete[]
+* отслеживание аллокаций в контейнерах
+* ручное отслеживание моментов аллокации/деаллокации
+
+----
+
+### Отслеживание аллокаций класса через new/delete
+
+Использование с автоматически генерируемой меткой:
+
+```cpp
+#include <library/cpp/actors/core/memory_track.h>
+
+struct TTypeLabeled
+ : public NActors::NMemory::TTrack<TTypeLabeled>
+{
+ char payload[16];
+};
+```
+
+Использование с пользовательским именем метки:
+
+```cpp
+#include <library/cpp/actors/core/memory_track.h>
+
+static const char NamedLabel[] = "NamedLabel";
+
+struct TNameLabeled
+ : public NActors::NMemory::TTrack<TNameLabeled, NamedLabel>
+{
+ char payload[32];
+};
+```
+
+----
+
+### Отслеживание аллокаций в контейнерах
+
+```cpp
+#include <library/cpp/actors/core/memory_track.h>
+
+static const char InContainerLabel[] = "InContainerLabel";
+
+struct TInContainer {
+ char payload[16];
+};
+
+std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer>> vecT;
+
+std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer, InContainerLabel>> vecN;
+
+using TKey = int;
+
+std::map<TKey, TInContainer, std::less<TKey>,
+ NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> mapT;
+
+std::map<TKey, TInContainer, std::less<TKey>,
+ NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> mapN;
+
+std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>,
+ NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> umapT;
+
+std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>,
+ NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> umapN;
+```
+
+----
+
+### Ручное отслеживание аллокаций/деаллокаций
+
+```cpp
+#include <library/cpp/actors/core/memory_track.h>
+
+static const char ManualLabel[] = "ManualLabel";
+
+...
+NActors::NMemory::TLabel<ManualLabel>::Add(size);
+
+...
+NActors::NMemory::TLabel<ManualLabel>::Sub(size);
+```
+
+----
+
+### Собираемые метрики
+
+Сервис **utils**, пользовательская метка **label**, сенсоры:
+
+- MT/Count: количество аллокаций в моменте
+- MT/Memory: аллоцированная память в моменте
+- MT/PeakCount: пиковое значение количества аллокаций (сэмплится с фиксированной частотой)
+- MT/PeakMemory: пиковое значение аллоцированной памяти
+
diff --git a/library/cpp/actors/core/actor.cpp b/library/cpp/actors/core/actor.cpp
new file mode 100644
index 0000000000..6f9ba6a42b
--- /dev/null
+++ b/library/cpp/actors/core/actor.cpp
@@ -0,0 +1,172 @@
+#include "actor.h"
+#include "executor_thread.h"
+#include "mailbox.h"
+#include <library/cpp/actors/util/datetime.h>
+
+namespace NActors {
+ Y_POD_THREAD(TActivationContext*)
+ TlsActivationContext((TActivationContext*)nullptr);
+
+ bool TActorContext::Send(const TActorId& recipient, IEventBase* ev, ui32 flags, ui64 cookie, NWilson::TTraceId traceId) const {
+ return Send(new IEventHandle(recipient, SelfID, ev, flags, cookie, nullptr, std::move(traceId)));
+ }
+
+ bool TActorContext::Send(TAutoPtr<IEventHandle> ev) const {
+ return ExecutorThread.Send(ev);
+ }
+
+ void IActor::Registered(TActorSystem* sys, const TActorId& owner) {
+ // fallback to legacy method, do not use it anymore
+ if (auto eh = AfterRegister(SelfId(), owner))
+ sys->Send(eh);
+ }
+
+ void IActor::Describe(IOutputStream &out) const noexcept {
+ SelfActorId.Out(out);
+ }
+
+ bool IActor::Send(const TActorId& recipient, IEventBase* ev, ui32 flags, ui64 cookie, NWilson::TTraceId traceId) const noexcept {
+ return SelfActorId.Send(recipient, ev, flags, cookie, std::move(traceId));
+ }
+
+ bool TActivationContext::Send(TAutoPtr<IEventHandle> ev) {
+ return TlsActivationContext->ExecutorThread.Send(ev);
+ }
+
+ void TActivationContext::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) {
+ TlsActivationContext->ExecutorThread.Schedule(deadline, ev, cookie);
+ }
+
+ void TActivationContext::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) {
+ TlsActivationContext->ExecutorThread.Schedule(deadline, ev, cookie);
+ }
+
+ void TActivationContext::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) {
+ TlsActivationContext->ExecutorThread.Schedule(delta, ev, cookie);
+ }
+
+ bool TActorIdentity::Send(const TActorId& recipient, IEventBase* ev, ui32 flags, ui64 cookie, NWilson::TTraceId traceId) const {
+ return TActivationContext::Send(new IEventHandle(recipient, *this, ev, flags, cookie, nullptr, std::move(traceId)));
+ }
+
+ void TActorIdentity::Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie) const {
+ return TActivationContext::Schedule(deadline, new IEventHandle(*this, {}, ev), cookie);
+ }
+
+ void TActorIdentity::Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie) const {
+ return TActivationContext::Schedule(deadline, new IEventHandle(*this, {}, ev), cookie);
+ }
+
+ void TActorIdentity::Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie) const {
+ return TActivationContext::Schedule(delta, new IEventHandle(*this, {}, ev), cookie);
+ }
+
+ TActorId TActivationContext::RegisterWithSameMailbox(IActor* actor, TActorId parentId) {
+ Y_VERIFY_DEBUG(parentId);
+ auto& ctx = *TlsActivationContext;
+ return ctx.ExecutorThread.RegisterActor(actor, &ctx.Mailbox, parentId.Hint(), parentId);
+ }
+
+ TActorId TActorContext::RegisterWithSameMailbox(IActor* actor) const {
+ return ExecutorThread.RegisterActor(actor, &Mailbox, SelfID.Hint(), SelfID);
+ }
+
+ TActorId IActor::RegisterWithSameMailbox(IActor* actor) const noexcept {
+ return TlsActivationContext->ExecutorThread.RegisterActor(actor, &TlsActivationContext->Mailbox, SelfActorId.Hint(), SelfActorId);
+ }
+
+ TActorId TActivationContext::Register(IActor* actor, TActorId parentId, TMailboxType::EType mailboxType, ui32 poolId) {
+ return TlsActivationContext->ExecutorThread.RegisterActor(actor, mailboxType, poolId, parentId);
+ }
+
+ TActorId TActivationContext::InterconnectProxy(ui32 destinationNodeId) {
+ return TlsActivationContext->ExecutorThread.ActorSystem->InterconnectProxy(destinationNodeId);
+ }
+
+ TActorSystem* TActivationContext::ActorSystem() {
+ return TlsActivationContext->ExecutorThread.ActorSystem;
+ }
+
+ i64 TActivationContext::GetCurrentEventTicks() {
+ return GetCycleCountFast() - TlsActivationContext->EventStart;
+ }
+
+ double TActivationContext::GetCurrentEventTicksAsSeconds() {
+ return NHPTimer::GetSeconds(GetCurrentEventTicks());
+ }
+
+ TActorId TActorContext::Register(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId) const {
+ return ExecutorThread.RegisterActor(actor, mailboxType, poolId, SelfID);
+ }
+
+ TActorId IActor::Register(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId) const noexcept {
+ return TlsActivationContext->ExecutorThread.RegisterActor(actor, mailboxType, poolId, SelfActorId);
+ }
+
+ void TActorContext::Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie) const {
+ ExecutorThread.Schedule(deadline, new IEventHandle(SelfID, TActorId(), ev), cookie);
+ }
+
+ void TActorContext::Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie) const {
+ ExecutorThread.Schedule(deadline, new IEventHandle(SelfID, TActorId(), ev), cookie);
+ }
+
+ void TActorContext::Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie) const {
+ ExecutorThread.Schedule(delta, new IEventHandle(SelfID, TActorId(), ev), cookie);
+ }
+
+ void IActor::Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie) const noexcept {
+ TlsActivationContext->ExecutorThread.Schedule(deadline, new IEventHandle(SelfActorId, TActorId(), ev), cookie);
+ }
+
+ void IActor::Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie) const noexcept {
+ TlsActivationContext->ExecutorThread.Schedule(deadline, new IEventHandle(SelfActorId, TActorId(), ev), cookie);
+ }
+
+ void IActor::Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie) const noexcept {
+ TlsActivationContext->ExecutorThread.Schedule(delta, new IEventHandle(SelfActorId, TActorId(), ev), cookie);
+ }
+
+ TInstant TActivationContext::Now() {
+ return TlsActivationContext->ExecutorThread.ActorSystem->Timestamp();
+ }
+
+ TMonotonic TActivationContext::Monotonic() {
+ return TlsActivationContext->ExecutorThread.ActorSystem->Monotonic();
+ }
+
+ TInstant TActorContext::Now() const {
+ return ExecutorThread.ActorSystem->Timestamp();
+ }
+
+ TMonotonic TActorContext::Monotonic() const {
+ return ExecutorThread.ActorSystem->Monotonic();
+ }
+
+ NLog::TSettings* TActivationContext::LoggerSettings() const {
+ return ExecutorThread.ActorSystem->LoggerSettings();
+ }
+
+ std::pair<ui32, ui32> TActorContext::CountMailboxEvents(ui32 maxTraverse) const {
+ return Mailbox.CountMailboxEvents(SelfID.LocalId(), maxTraverse);
+ }
+
+ std::pair<ui32, ui32> IActor::CountMailboxEvents(ui32 maxTraverse) const {
+ return TlsActivationContext->Mailbox.CountMailboxEvents(SelfActorId.LocalId(), maxTraverse);
+ }
+
+ void IActor::Die(const TActorContext& ctx) {
+ if (ctx.SelfID)
+ Y_VERIFY(ctx.SelfID == SelfActorId);
+ PassAway();
+ }
+
+ void IActor::PassAway() {
+ auto& cx = *TlsActivationContext;
+ cx.ExecutorThread.UnregisterActor(&cx.Mailbox, SelfActorId.LocalId());
+ }
+
+ double IActor::GetElapsedTicksAsSeconds() const {
+ return NHPTimer::GetSeconds(ElapsedTicks);
+ }
+}
diff --git a/library/cpp/actors/core/actor.h b/library/cpp/actors/core/actor.h
new file mode 100644
index 0000000000..ed29bd14b9
--- /dev/null
+++ b/library/cpp/actors/core/actor.h
@@ -0,0 +1,530 @@
+#pragma once
+
+#include "event.h"
+#include "monotonic.h"
+#include <util/system/tls.h>
+#include <library/cpp/actors/util/local_process_key.h>
+
+namespace NActors {
+ class TActorSystem;
+ class TMailboxTable;
+ struct TMailboxHeader;
+
+ class TExecutorThread;
+ class IActor;
+ class ISchedulerCookie;
+
+ namespace NLog {
+ struct TSettings;
+ }
+
+ struct TActorContext;
+
+ struct TActivationContext {
+ public:
+ TMailboxHeader& Mailbox;
+ TExecutorThread& ExecutorThread;
+ const NHPTimer::STime EventStart;
+
+ protected:
+ explicit TActivationContext(TMailboxHeader& mailbox, TExecutorThread& executorThread, NHPTimer::STime eventStart)
+ : Mailbox(mailbox)
+ , ExecutorThread(executorThread)
+ , EventStart(eventStart)
+ {
+ }
+
+ public:
+ static bool Send(TAutoPtr<IEventHandle> ev);
+
+ /**
+ * Schedule one-shot event that will be send at given time point in the future.
+ *
+ * @param deadline the wallclock time point in future when event must be send
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ */
+ static void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr);
+
+ /**
+ * Schedule one-shot event that will be send at given time point in the future.
+ *
+ * @param deadline the monotonic time point in future when event must be send
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ */
+ static void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr);
+
+ /**
+ * Schedule one-shot event that will be send after given delay.
+ *
+ * @param delta the time from now to delay event sending
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ */
+ static void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr);
+
+ static TInstant Now();
+ static TMonotonic Monotonic();
+ NLog::TSettings* LoggerSettings() const;
+
+ // register new actor in ActorSystem on new fresh mailbox.
+ static TActorId Register(IActor* actor, TActorId parentId = TActorId(), TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>());
+
+ // Register new actor in ActorSystem on same _mailbox_ as current actor.
+ // There is one thread per mailbox to execute actor, which mean
+ // no _cpu core scalability_ for such actors.
+ // This method of registration can be usefull if multiple actors share
+ // some memory.
+ static TActorId RegisterWithSameMailbox(IActor* actor, TActorId parentId);
+
+ static const TActorContext& AsActorContext();
+ static TActorContext ActorContextFor(TActorId id);
+
+ static TActorId InterconnectProxy(ui32 nodeid);
+ static TActorSystem* ActorSystem();
+
+ static i64 GetCurrentEventTicks();
+ static double GetCurrentEventTicksAsSeconds();
+ };
+
+ struct TActorContext: public TActivationContext {
+ const TActorId SelfID;
+
+ explicit TActorContext(TMailboxHeader& mailbox, TExecutorThread& executorThread, NHPTimer::STime eventStart, const TActorId& selfID)
+ : TActivationContext(mailbox, executorThread, eventStart)
+ , SelfID(selfID)
+ {
+ }
+
+ bool Send(const TActorId& recipient, IEventBase* ev, ui32 flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const;
+ template <typename TEvent>
+ bool Send(const TActorId& recipient, THolder<TEvent> ev, ui32 flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const {
+ return Send(recipient, static_cast<IEventBase*>(ev.Release()), flags, cookie, std::move(traceId));
+ }
+ bool Send(TAutoPtr<IEventHandle> ev) const;
+
+ TInstant Now() const;
+ TMonotonic Monotonic() const;
+
+ /**
+ * Schedule one-shot event that will be send at given time point in the future.
+ *
+ * @param deadline the wallclock time point in future when event must be send
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ */
+ void Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const;
+
+ /**
+ * Schedule one-shot event that will be send at given time point in the future.
+ *
+ * @param deadline the monotonic time point in future when event must be send
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ */
+ void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const;
+
+ /**
+ * Schedule one-shot event that will be send after given delay.
+ *
+ * @param delta the time from now to delay event sending
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ */
+ void Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const;
+
+ TActorContext MakeFor(const TActorId& otherId) const {
+ return TActorContext(Mailbox, ExecutorThread, EventStart, otherId);
+ }
+
+ // register new actor in ActorSystem on new fresh mailbox.
+ TActorId Register(IActor* actor, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>()) const;
+
+ // Register new actor in ActorSystem on same _mailbox_ as current actor.
+ // There is one thread per mailbox to execute actor, which mean
+ // no _cpu core scalability_ for such actors.
+ // This method of registration can be usefull if multiple actors share
+ // some memory.
+ TActorId RegisterWithSameMailbox(IActor* actor) const;
+
+ std::pair<ui32, ui32> CountMailboxEvents(ui32 maxTraverse = Max<ui32>()) const;
+ };
+
+ extern Y_POD_THREAD(TActivationContext*) TlsActivationContext;
+
+ struct TActorIdentity: public TActorId {
+ explicit TActorIdentity(TActorId actorId)
+ : TActorId(actorId)
+ {
+ }
+
+ void operator=(TActorId actorId) {
+ *this = TActorIdentity(actorId);
+ }
+
+ bool Send(const TActorId& recipient, IEventBase* ev, ui32 flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const;
+ void Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const;
+ void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const;
+ void Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const;
+ };
+
+ class IActor;
+
+ class IActorOps : TNonCopyable {
+ public:
+ virtual void Describe(IOutputStream&) const noexcept = 0;
+ virtual bool Send(const TActorId& recipient, IEventBase*, ui32 flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const noexcept = 0;
+
+ /**
+ * Schedule one-shot event that will be send at given time point in the future.
+ *
+ * @param deadline the wallclock time point in future when event must be send
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ */
+ virtual void Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept = 0;
+
+ /**
+ * Schedule one-shot event that will be send at given time point in the future.
+ *
+ * @param deadline the monotonic time point in future when event must be send
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ */
+ virtual void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept = 0;
+
+ /**
+ * Schedule one-shot event that will be send after given delay.
+ *
+ * @param delta the time from now to delay event sending
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ */
+ virtual void Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept = 0;
+
+ virtual TActorId Register(IActor*, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>()) const noexcept = 0;
+ virtual TActorId RegisterWithSameMailbox(IActor*) const noexcept = 0;
+ };
+
+ class TDecorator;
+
+ class IActor : protected IActorOps {
+ public:
+ typedef void (IActor::*TReceiveFunc)(TAutoPtr<IEventHandle>& ev, const TActorContext& ctx);
+
+ private:
+ TReceiveFunc StateFunc;
+ TActorIdentity SelfActorId;
+ i64 ElapsedTicks;
+ ui64 HandledEvents;
+
+ friend void DoActorInit(TActorSystem*, IActor*, const TActorId&, const TActorId&);
+ friend class TDecorator;
+
+ public:
+ /// @sa services.proto NKikimrServices::TActivity::EType
+ enum EActorActivity {
+ OTHER = 0,
+ ACTOR_SYSTEM = 1,
+ ACTORLIB_COMMON = 2,
+ ACTORLIB_STATS = 3,
+ LOG_ACTOR = 4,
+ INTERCONNECT_PROXY_TCP = 12,
+ INTERCONNECT_SESSION_TCP = 13,
+ INTERCONNECT_COMMON = 171,
+ SELF_PING_ACTOR = 207,
+ TEST_ACTOR_RUNTIME = 283,
+ INTERCONNECT_HANDSHAKE = 284,
+ INTERCONNECT_POLLER = 285,
+ INTERCONNECT_SESSION_KILLER = 286,
+ ACTOR_SYSTEM_SCHEDULER_ACTOR = 312,
+ ACTOR_FUTURE_CALLBACK = 337,
+ INTERCONNECT_MONACTOR = 362,
+ INTERCONNECT_LOAD_ACTOR = 376,
+ INTERCONNECT_LOAD_RESPONDER = 377,
+ NAMESERVICE = 450,
+ DNS_RESOLVER = 481,
+ INTERCONNECT_PROXY_WRAPPER = 546,
+ };
+
+ using EActivityType = EActorActivity;
+ ui32 ActivityType;
+
+ protected:
+ IActor(TReceiveFunc stateFunc, ui32 activityType = OTHER)
+ : StateFunc(stateFunc)
+ , SelfActorId(TActorId())
+ , ElapsedTicks(0)
+ , HandledEvents(0)
+ , ActivityType(activityType)
+ {
+ }
+
+ public:
+ virtual ~IActor() {
+ } // must not be called for registered actors, see Die method instead
+
+ protected:
+ virtual void Die(const TActorContext& ctx); // would unregister actor so call exactly once and only from inside of message processing
+ virtual void PassAway();
+
+ public:
+ template <typename T>
+ void Become(T stateFunc) {
+ StateFunc = static_cast<TReceiveFunc>(stateFunc);
+ }
+
+ template <typename T, typename... TArgs>
+ void Become(T stateFunc, const TActorContext& ctx, TArgs&&... args) {
+ StateFunc = static_cast<TReceiveFunc>(stateFunc);
+ ctx.Schedule(std::forward<TArgs>(args)...);
+ }
+
+ template <typename T, typename... TArgs>
+ void Become(T stateFunc, TArgs&&... args) {
+ StateFunc = static_cast<TReceiveFunc>(stateFunc);
+ Schedule(std::forward<TArgs>(args)...);
+ }
+
+ protected:
+ void SetActivityType(ui32 activityType) {
+ ActivityType = activityType;
+ }
+
+ public:
+ TReceiveFunc CurrentStateFunc() const {
+ return StateFunc;
+ }
+
+ // NOTE: exceptions must not escape state function but if an exception hasn't be caught
+ // by the actor then we want to crash an see the stack
+ void Receive(TAutoPtr<IEventHandle>& ev, const TActorContext& ctx) {
+ (this->*StateFunc)(ev, ctx);
+ HandledEvents++;
+ }
+
+ // must be called to wrap any call trasitions from one actor to another
+ template<typename TActor, typename TMethod, typename... TArgs>
+ static decltype((std::declval<TActor>().*std::declval<TMethod>())(std::declval<TArgs>()...))
+ InvokeOtherActor(TActor& actor, TMethod&& method, TArgs&&... args) {
+ struct TRecurseContext : TActorContext {
+ TActivationContext *Prev;
+ TRecurseContext(const TActorId& actorId)
+ : TActorContext(TActivationContext::ActorContextFor(actorId))
+ , Prev(TlsActivationContext)
+ {
+ TlsActivationContext = this;
+ }
+ ~TRecurseContext() {
+ TlsActivationContext = Prev;
+ }
+ } context(actor.SelfId());
+ return (actor.*method)(std::forward<TArgs>(args)...);
+ }
+
+ virtual void Registered(TActorSystem* sys, const TActorId& owner);
+
+ virtual TAutoPtr<IEventHandle> AfterRegister(const TActorId& self, const TActorId& parentId) {
+ Y_UNUSED(self);
+ Y_UNUSED(parentId);
+ return TAutoPtr<IEventHandle>();
+ }
+
+ i64 GetElapsedTicks() const {
+ return ElapsedTicks;
+ }
+ double GetElapsedTicksAsSeconds() const;
+ void AddElapsedTicks(i64 ticks) {
+ ElapsedTicks += ticks;
+ }
+ auto GetActivityType() const {
+ return ActivityType;
+ }
+ ui64 GetHandledEvents() const {
+ return HandledEvents;
+ }
+ TActorIdentity SelfId() const {
+ return SelfActorId;
+ }
+
+ protected:
+ void Describe(IOutputStream&) const noexcept override;
+ bool Send(const TActorId& recipient, IEventBase* ev, ui32 flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const noexcept final;
+ template <typename TEvent>
+ bool Send(const TActorId& recipient, THolder<TEvent> ev, ui32 flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) const{
+ return Send(recipient, static_cast<IEventBase*>(ev.Release()), flags, cookie, std::move(traceId));
+ }
+
+ template <class TEvent, class ... TEventArgs>
+ bool Send(TActorId recipient, TEventArgs&& ... args) const {
+ return Send(recipient, MakeHolder<TEvent>(std::forward<TEventArgs>(args)...));
+ }
+
+ void Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept final;
+ void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept final;
+ void Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie = nullptr) const noexcept final;
+
+ // register new actor in ActorSystem on new fresh mailbox.
+ TActorId Register(IActor* actor, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>()) const noexcept final;
+
+ // Register new actor in ActorSystem on same _mailbox_ as current actor.
+ // There is one thread per mailbox to execute actor, which mean
+ // no _cpu core scalability_ for such actors.
+ // This method of registration can be usefull if multiple actors share
+ // some memory.
+ TActorId RegisterWithSameMailbox(IActor* actor) const noexcept final;
+
+ std::pair<ui32, ui32> CountMailboxEvents(ui32 maxTraverse = Max<ui32>()) const;
+
+ private:
+ void ChangeSelfId(TActorId actorId) {
+ SelfActorId = actorId;
+ }
+ };
+
+ struct TActorActivityTag {};
+
+ inline size_t GetActivityTypeCount() {
+ return TLocalProcessKeyState<TActorActivityTag>::GetInstance().GetCount();
+ }
+
+ inline TStringBuf GetActivityTypeName(size_t index) {
+ return TLocalProcessKeyState<TActorActivityTag>::GetInstance().GetNameByIndex(index);
+ }
+
+ template <typename TDerived>
+ class TActor: public IActor {
+ private:
+ template <typename T, typename = const char*>
+ struct HasActorName: std::false_type { };
+ template <typename T>
+ struct HasActorName<T, decltype((void)T::ActorName, (const char*)nullptr)>: std::true_type { };
+
+ static ui32 GetActivityTypeIndex() {
+ if constexpr(HasActorName<TDerived>::value) {
+ return TLocalProcessKey<TActorActivityTag, TDerived::ActorName>::GetIndex();
+ } else {
+ using TActorActivity = decltype(((TDerived*)nullptr)->ActorActivityType());
+ // if constexpr(std::is_enum<TActorActivity>::value) {
+ return TEnumProcessKey<TActorActivityTag, TActorActivity>::GetIndex(
+ TDerived::ActorActivityType());
+ //} else {
+ // for int, ui32, ...
+ // return TEnumProcessKey<TActorActivityTag, IActor::EActorActivity>::GetIndex(
+ // static_cast<IActor::EActorActivity>(TDerived::ActorActivityType()));
+ //}
+ }
+ }
+
+ protected:
+ //* Comment this function to find unmarked activities
+ static constexpr IActor::EActivityType ActorActivityType() {
+ return EActorActivity::OTHER;
+ } //*/
+
+ // static constexpr char ActorName[] = "UNNAMED";
+
+ TActor(void (TDerived::*func)(TAutoPtr<IEventHandle>& ev, const TActorContext& ctx), ui32 activityType = GetActivityTypeIndex())
+ : IActor(static_cast<TReceiveFunc>(func), activityType)
+ { }
+
+ public:
+ typedef TDerived TThis;
+ };
+
+
+#define STFUNC_SIG TAutoPtr< ::NActors::IEventHandle>&ev, const ::NActors::TActorContext &ctx
+#define STATEFN_SIG TAutoPtr<::NActors::IEventHandle>& ev
+#define STFUNC(funcName) void funcName(TAutoPtr< ::NActors::IEventHandle>& ev, const ::NActors::TActorContext& ctx)
+#define STATEFN(funcName) void funcName(TAutoPtr< ::NActors::IEventHandle>& ev, const ::NActors::TActorContext& )
+
+#define STRICT_STFUNC(NAME, HANDLERS) \
+ void NAME(STFUNC_SIG) { \
+ Y_UNUSED(ctx); \
+ switch (const ui32 etype = ev->GetTypeRewrite()) { \
+ HANDLERS \
+ default: \
+ Y_VERIFY_DEBUG(false, "%s: unexpected message type 0x%08" PRIx32, __func__, etype); \
+ } \
+ }
+
+ inline const TActorContext& TActivationContext::AsActorContext() {
+ TActivationContext* tls = TlsActivationContext;
+ return *static_cast<TActorContext*>(tls);
+ }
+
+ inline TActorContext TActivationContext::ActorContextFor(TActorId id) {
+ auto& tls = *TlsActivationContext;
+ return TActorContext(tls.Mailbox, tls.ExecutorThread, tls.EventStart, id);
+ }
+
+ class TDecorator : public IActor {
+ protected:
+ THolder<IActor> Actor;
+
+ public:
+ TDecorator(THolder<IActor>&& actor)
+ : IActor(static_cast<TReceiveFunc>(&TDecorator::State), actor->GetActivityType())
+ , Actor(std::move(actor))
+ {
+ }
+
+ void Registered(TActorSystem* sys, const TActorId& owner) override {
+ Actor->ChangeSelfId(SelfId());
+ Actor->Registered(sys, owner);
+ }
+
+ virtual bool DoBeforeReceiving(TAutoPtr<IEventHandle>& /*ev*/, const TActorContext& /*ctx*/) {
+ return true;
+ }
+
+ virtual void DoAfterReceiving(const TActorContext& /*ctx*/)
+ {
+ }
+
+ STFUNC(State) {
+ if (DoBeforeReceiving(ev, ctx)) {
+ Actor->Receive(ev, ctx);
+ DoAfterReceiving(ctx);
+ }
+ }
+ };
+
+ // TTestDecorator doesn't work with the real actor system
+ struct TTestDecorator : public TDecorator {
+ TTestDecorator(THolder<IActor>&& actor)
+ : TDecorator(std::move(actor))
+ {
+ }
+
+ virtual ~TTestDecorator() = default;
+
+ // This method must be called in the test actor system
+ bool BeforeSending(TAutoPtr<IEventHandle>& ev)
+ {
+ bool send = true;
+ TTestDecorator *decorator = dynamic_cast<TTestDecorator*>(Actor.Get());
+ if (decorator) {
+ send = decorator->BeforeSending(ev);
+ }
+ return send && ev && DoBeforeSending(ev);
+ }
+
+ virtual bool DoBeforeSending(TAutoPtr<IEventHandle>& /*ev*/) {
+ return true;
+ }
+ };
+}
+
+template <>
+inline void Out<NActors::TActorIdentity>(IOutputStream& o, const NActors::TActorIdentity& x) {
+ return x.Out(o);
+}
+
+template <>
+struct THash<NActors::TActorIdentity> {
+ inline ui64 operator()(const NActors::TActorIdentity& x) const {
+ return x.Hash();
+ }
+};
diff --git a/library/cpp/actors/core/actor_bootstrapped.h b/library/cpp/actors/core/actor_bootstrapped.h
new file mode 100644
index 0000000000..a37887c939
--- /dev/null
+++ b/library/cpp/actors/core/actor_bootstrapped.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "actor.h"
+#include "events.h"
+
+namespace NActors {
+ template<typename T> struct dependent_false : std::false_type {};
+
+ template<typename TDerived>
+ class TActorBootstrapped : public TActor<TDerived> {
+ protected:
+ TAutoPtr<IEventHandle> AfterRegister(const TActorId& self, const TActorId& parentId) override {
+ return new IEventHandle(TEvents::TSystem::Bootstrap, 0, self, parentId, {}, 0);
+ }
+
+ STFUNC(StateBootstrap) {
+ Y_VERIFY(ev->GetTypeRewrite() == TEvents::TSystem::Bootstrap, "Unexpected bootstrap message");
+ using T = decltype(&TDerived::Bootstrap);
+ TDerived& self = static_cast<TDerived&>(*this);
+ if constexpr (std::is_invocable_v<T, TDerived, const TActorContext&>) {
+ self.Bootstrap(ctx);
+ } else if constexpr (std::is_invocable_v<T, TDerived, const TActorId&, const TActorContext&>) {
+ self.Bootstrap(ev->Sender, ctx);
+ } else if constexpr (std::is_invocable_v<T, TDerived>) {
+ self.Bootstrap();
+ } else if constexpr (std::is_invocable_v<T, TDerived, const TActorId&>) {
+ self.Bootstrap(ev->Sender);
+ } else {
+ static_assert(dependent_false<TDerived>::value, "No correct Bootstrap() signature");
+ }
+ }
+
+ TActorBootstrapped()
+ : TActor<TDerived>(&TDerived::StateBootstrap)
+ {}
+ };
+}
diff --git a/library/cpp/actors/core/actor_coroutine.cpp b/library/cpp/actors/core/actor_coroutine.cpp
new file mode 100644
index 0000000000..0ab4d2b24d
--- /dev/null
+++ b/library/cpp/actors/core/actor_coroutine.cpp
@@ -0,0 +1,165 @@
+#include "actor_coroutine.h"
+#include "executor_thread.h"
+
+#include <util/system/sanitizers.h>
+#include <util/system/type_name.h>
+
+namespace NActors {
+ static constexpr size_t StackOverflowGap = 4096;
+ static char GoodStack[StackOverflowGap];
+
+ static struct TInitGoodStack {
+ TInitGoodStack() {
+ // fill stack with some pseudo-random pattern
+ for (size_t k = 0; k < StackOverflowGap; ++k) {
+ GoodStack[k] = k + k * 91;
+ }
+ }
+ } initGoodStack;
+
+ TActorCoroImpl::TActorCoroImpl(size_t stackSize, bool allowUnhandledPoisonPill, bool allowUnhandledDtor)
+ : Stack(stackSize)
+ , AllowUnhandledPoisonPill(allowUnhandledPoisonPill)
+ , AllowUnhandledDtor(allowUnhandledDtor)
+ , FiberClosure{this, TArrayRef(Stack.Begin(), Stack.End())}
+ , FiberContext(FiberClosure)
+ {
+#ifndef NDEBUG
+ char* p;
+#if STACK_GROW_DOWN
+ p = Stack.Begin();
+#else
+ p = Stack.End() - StackOverflowGap;
+#endif
+ memcpy(p, GoodStack, StackOverflowGap);
+#endif
+ }
+
+ TActorCoroImpl::~TActorCoroImpl() {
+ if (!Finished && !NSan::TSanIsOn()) { // only resume when we have bootstrapped and Run() was entered and not yet finished; in other case simply terminate
+ Y_VERIFY(!PendingEvent);
+ Resume();
+ }
+ }
+
+ bool TActorCoroImpl::Send(TAutoPtr<IEventHandle> ev) {
+ return GetActorContext().ExecutorThread.Send(ev);
+ }
+
+ THolder<IEventHandle> TActorCoroImpl::WaitForEvent(TInstant deadline) {
+ const ui64 cookie = ++WaitCookie;
+ if (deadline != TInstant::Max()) {
+ ActorContext->ExecutorThread.Schedule(deadline - Now(), new IEventHandle(SelfActorId, {}, new TEvCoroTimeout,
+ 0, cookie));
+ }
+
+ // ensure we have no unprocessed event and return back to actor system to receive one
+ Y_VERIFY(!PendingEvent);
+ ReturnToActorSystem();
+
+ // obtain pending event and ensure we've got one
+ while (THolder<IEventHandle> event = std::exchange(PendingEvent, {})) {
+ if (event->GetTypeRewrite() != TEvents::TSystem::CoroTimeout) {
+ // special handling for poison pill -- we throw exception
+ if (event->GetTypeRewrite() == TEvents::TEvPoisonPill::EventType) {
+ throw TPoisonPillException();
+ }
+
+ // otherwise just return received event
+ return event;
+ } else if (event->Cookie == cookie) {
+ return nullptr; // it is not a race -- we've got timeout exactly for our current wait
+ } else {
+ ReturnToActorSystem(); // drop this event and wait for the next one
+ }
+ }
+ Y_FAIL("no pending event");
+ }
+
+ const TActorContext& TActorCoroImpl::GetActorContext() const {
+ Y_VERIFY(ActorContext);
+ return *ActorContext;
+ }
+
+ bool TActorCoroImpl::ProcessEvent(THolder<IEventHandle> ev) {
+ Y_VERIFY(!PendingEvent);
+ if (!SelfActorId) { // process bootstrap message, extract actor ids
+ Y_VERIFY(ev->GetTypeRewrite() == TEvents::TSystem::Bootstrap);
+ SelfActorId = ev->Recipient;
+ ParentActorId = ev->Sender;
+ } else { // process further messages
+ PendingEvent = std::move(ev);
+ }
+
+ // prepare actor context for in-coroutine use
+ TActivationContext *ac = TlsActivationContext;
+ TlsActivationContext = nullptr;
+ TActorContext ctx(ac->Mailbox, ac->ExecutorThread, ac->EventStart, SelfActorId);
+ ActorContext = &ctx;
+
+ Resume();
+
+ // drop actor context
+ TlsActivationContext = ac;
+ ActorContext = nullptr;
+
+ return Finished;
+ }
+
+ void TActorCoroImpl::Resume() {
+ // save caller context for a later return
+ Y_VERIFY(!ActorSystemContext);
+ TExceptionSafeContext actorSystemContext;
+ ActorSystemContext = &actorSystemContext;
+
+ // go to actor coroutine
+ BeforeResume();
+ ActorSystemContext->SwitchTo(&FiberContext);
+
+ // check for stack overflow
+#ifndef NDEBUG
+ const char* p;
+#if STACK_GROW_DOWN
+ p = Stack.Begin();
+#else
+ p = Stack.End() - StackOverflowGap;
+#endif
+ Y_VERIFY_DEBUG(memcmp(p, GoodStack, StackOverflowGap) == 0);
+#endif
+ }
+
+ void TActorCoroImpl::DoRun() {
+ try {
+ if (ActorContext) { // ActorContext may be nullptr here if the destructor was invoked before bootstrapping
+ Y_VERIFY(!PendingEvent);
+ Run();
+ }
+ } catch (const TPoisonPillException& /*ex*/) {
+ if (!AllowUnhandledPoisonPill) {
+ Y_FAIL("unhandled TPoisonPillException");
+ }
+ } catch (const TDtorException& /*ex*/) {
+ if (!AllowUnhandledDtor) {
+ Y_FAIL("unhandled TDtorException");
+ }
+ } catch (const std::exception& ex) {
+ Y_FAIL("unhandled exception of type %s", TypeName(ex).data());
+ } catch (...) {
+ Y_FAIL("unhandled exception of type not derived from std::exception");
+ }
+ Finished = true;
+ ReturnToActorSystem();
+ }
+
+ void TActorCoroImpl::ReturnToActorSystem() {
+ TExceptionSafeContext* returnContext = std::exchange(ActorSystemContext, nullptr);
+ Y_VERIFY(returnContext);
+ FiberContext.SwitchTo(returnContext);
+ if (!PendingEvent) {
+ // we have returned from the actor system and it kindly asks us to terminate the coroutine as it is being
+ // stopped
+ throw TDtorException();
+ }
+ }
+
+}
diff --git a/library/cpp/actors/core/actor_coroutine.h b/library/cpp/actors/core/actor_coroutine.h
new file mode 100644
index 0000000000..6bcb768eaf
--- /dev/null
+++ b/library/cpp/actors/core/actor_coroutine.h
@@ -0,0 +1,174 @@
+#pragma once
+
+#include <util/system/context.h>
+#include <util/system/filemap.h>
+
+#include "actor_bootstrapped.h"
+#include "executor_thread.h"
+#include "event_local.h"
+
+namespace NActors {
+
+ class TActorCoro;
+
+ class TActorCoroImpl : public ITrampoLine {
+ TMappedAllocation Stack;
+ bool AllowUnhandledPoisonPill;
+ bool AllowUnhandledDtor;
+ TContClosure FiberClosure;
+ TExceptionSafeContext FiberContext;
+ TExceptionSafeContext* ActorSystemContext = nullptr;
+ THolder<IEventHandle> PendingEvent;
+ bool Finished = false;
+ ui64 WaitCookie = 0;
+ TActorContext *ActorContext = nullptr;
+
+ protected:
+ TActorIdentity SelfActorId = TActorIdentity(TActorId());
+ TActorId ParentActorId;
+
+ private:
+ template <typename TFirstEvent, typename... TOtherEvents>
+ struct TIsOneOf: public TIsOneOf<TOtherEvents...> {
+ bool operator()(IEventHandle& ev) const {
+ return ev.GetTypeRewrite() == TFirstEvent::EventType || TIsOneOf<TOtherEvents...>()(ev);
+ }
+ };
+
+ template <typename TSingleEvent>
+ struct TIsOneOf<TSingleEvent> {
+ bool operator()(IEventHandle& ev) const {
+ return ev.GetTypeRewrite() == TSingleEvent::EventType;
+ }
+ };
+
+ struct TEvCoroTimeout : TEventLocal<TEvCoroTimeout, TEvents::TSystem::CoroTimeout> {};
+
+ protected:
+ struct TPoisonPillException : yexception {};
+ struct TDtorException : yexception {};
+
+ public:
+ TActorCoroImpl(size_t stackSize, bool allowUnhandledPoisonPill = false, bool allowUnhandledDtor = false);
+ // specify stackSize explicitly for each actor; don't forget about overflow control gap
+
+ virtual ~TActorCoroImpl();
+
+ virtual void Run() = 0;
+
+ virtual void BeforeResume() {}
+
+ // Handle all events that are not expected in wait loops.
+ virtual void ProcessUnexpectedEvent(TAutoPtr<IEventHandle> ev) = 0;
+
+ // Release execution ownership and wait for some event to arrive. When PoisonPill event is received, then
+ // TPoisonPillException is thrown.
+ THolder<IEventHandle> WaitForEvent(TInstant deadline = TInstant::Max());
+
+ // Wait for specific event set by filter functor. Function returns first event that matches filter. On any other
+ // kind of event ProcessUnexpectedEvent() is called.
+ //
+ // Example: WaitForSpecificEvent([](IEventHandle& ev) { return ev.Cookie == 42; });
+ template <typename TFunc>
+ THolder<IEventHandle> WaitForSpecificEvent(TFunc&& filter, TInstant deadline = TInstant::Max()) {
+ for (;;) {
+ if (THolder<IEventHandle> event = WaitForEvent(deadline); !event) {
+ return nullptr;
+ } else if (filter(*event)) {
+ return event;
+ } else {
+ ProcessUnexpectedEvent(event);
+ }
+ }
+ }
+
+ // Wait for specific event or set of events. Function returns first event that matches enlisted type. On any other
+ // kind of event ProcessUnexpectedEvent() is called.
+ //
+ // Example: WaitForSpecificEvent<TEvReadResult, TEvFinished>();
+ template <typename TFirstEvent, typename TSecondEvent, typename... TOtherEvents>
+ THolder<IEventHandle> WaitForSpecificEvent(TInstant deadline = TInstant::Max()) {
+ TIsOneOf<TFirstEvent, TSecondEvent, TOtherEvents...> filter;
+ return WaitForSpecificEvent(filter, deadline);
+ }
+
+ // Wait for single specific event.
+ template <typename TEventType>
+ THolder<typename TEventType::THandle> WaitForSpecificEvent(TInstant deadline = TInstant::Max()) {
+ auto filter = [](IEventHandle& ev) {
+ return ev.GetTypeRewrite() == TEventType::EventType;
+ };
+ THolder<IEventHandle> event = WaitForSpecificEvent(filter, deadline);
+ return THolder<typename TEventType::THandle>(static_cast<typename TEventType::THandle*>(event ? event.Release() : nullptr));
+ }
+
+ protected: // Actor System compatibility section
+ const TActorContext& GetActorContext() const;
+ TActorSystem *GetActorSystem() const { return GetActorContext().ExecutorThread.ActorSystem; }
+ TInstant Now() const { return GetActorContext().Now(); }
+
+ bool Send(const TActorId& recipient, IEventBase* ev, ui32 flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) {
+ return GetActorContext().Send(recipient, ev, flags, cookie, std::move(traceId));
+ }
+
+ template <typename TEvent>
+ bool Send(const TActorId& recipient, THolder<TEvent> ev, ui32 flags = 0, ui64 cookie = 0, NWilson::TTraceId traceId = {}) {
+ return GetActorContext().Send(recipient, ev.Release(), flags, cookie, std::move(traceId));
+ }
+
+ bool Send(TAutoPtr<IEventHandle> ev);
+
+ void Schedule(TDuration delta, IEventBase* ev, ISchedulerCookie* cookie = nullptr) {
+ return GetActorContext().Schedule(delta, ev, cookie);
+ }
+
+ void Schedule(TInstant deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) {
+ return GetActorContext().Schedule(deadline, ev, cookie);
+ }
+
+ void Schedule(TMonotonic deadline, IEventBase* ev, ISchedulerCookie* cookie = nullptr) {
+ return GetActorContext().Schedule(deadline, ev, cookie);
+ }
+
+ TActorId Register(IActor* actor, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>()) {
+ return GetActorContext().Register(actor, mailboxType, poolId);
+ }
+
+ TActorId RegisterWithSameMailbox(IActor* actor) {
+ return GetActorContext().RegisterWithSameMailbox(actor);
+ }
+
+ private:
+ friend class TActorCoro;
+ bool ProcessEvent(THolder<IEventHandle> ev);
+
+ private:
+ /* Resume() function goes to actor coroutine context and continues (or starts) to execute it until actor finishes
+ * his job or it is blocked on WaitForEvent. Then the function returns. */
+ void Resume();
+ void ReturnToActorSystem();
+ void DoRun() override final;
+ };
+
+ class TActorCoro : public IActor {
+ THolder<TActorCoroImpl> Impl;
+
+ public:
+ TActorCoro(THolder<TActorCoroImpl> impl, ui32 activityType = IActor::ACTORLIB_COMMON)
+ : IActor(static_cast<TReceiveFunc>(&TActorCoro::StateFunc), activityType)
+ , Impl(std::move(impl))
+ {}
+
+ TAutoPtr<IEventHandle> AfterRegister(const TActorId& self, const TActorId& parent) override {
+ return new IEventHandle(TEvents::TSystem::Bootstrap, 0, self, parent, {}, 0);
+ }
+
+ private:
+ STATEFN(StateFunc) {
+ if (Impl->ProcessEvent(ev)) {
+ PassAway();
+ }
+ }
+ };
+
+}
diff --git a/library/cpp/actors/core/actor_coroutine_ut.cpp b/library/cpp/actors/core/actor_coroutine_ut.cpp
new file mode 100644
index 0000000000..951512b877
--- /dev/null
+++ b/library/cpp/actors/core/actor_coroutine_ut.cpp
@@ -0,0 +1,141 @@
+#include "actor_coroutine.h"
+#include "actorsystem.h"
+#include "executor_pool_basic.h"
+#include "scheduler_basic.h"
+#include "events.h"
+#include "event_local.h"
+#include "hfunc.h"
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/system/sanitizers.h>
+
+using namespace NActors;
+
+Y_UNIT_TEST_SUITE(ActorCoro) {
+ enum {
+ Begin = EventSpaceBegin(TEvents::ES_USERSPACE),
+ Request,
+ Response,
+ Enough
+ };
+
+ struct TEvRequest: public TEventLocal<TEvRequest, Request> {
+ };
+
+ struct TEvResponse: public TEventLocal<TEvResponse, Response> {
+ };
+
+ struct TEvEnough: public TEventLocal<TEvEnough, Enough> {
+ };
+
+ class TBasicResponderActor: public TActorBootstrapped<TBasicResponderActor> {
+ TDeque<TActorId> RespondTo;
+
+ public:
+ TBasicResponderActor() {
+ }
+
+ void Bootstrap(const TActorContext& /*ctx*/) {
+ Become(&TBasicResponderActor::StateFunc);
+ }
+
+ STFUNC(StateFunc) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TEvRequest, Handle);
+ HFunc(TEvents::TEvWakeup, Handle);
+ HFunc(TEvents::TEvPoisonPill, Handle);
+ }
+ }
+
+ void Handle(TEvRequest::TPtr& ev, const TActorContext& ctx) {
+ RespondTo.push_back(ev->Sender);
+ ctx.Schedule(TDuration::Seconds(1), new TEvents::TEvWakeup);
+ }
+
+ void Handle(TEvents::TEvWakeup::TPtr& /*ev*/, const TActorContext& ctx) {
+ ctx.Send(RespondTo.front(), new TEvResponse());
+ RespondTo.pop_front();
+ }
+
+ void Handle(TEvents::TEvPoisonPill::TPtr& /*ev*/, const TActorContext& ctx) {
+ Die(ctx);
+ }
+ };
+
+ class TCoroActor: public TActorCoroImpl {
+ TManualEvent& DoneEvent;
+ TAtomic& ItemsProcessed;
+ bool Finish;
+
+ public:
+ TCoroActor(TManualEvent& doneEvent, TAtomic& itemsProcessed)
+ : TActorCoroImpl(1 << 20)
+ , DoneEvent(doneEvent)
+ , ItemsProcessed(itemsProcessed)
+ , Finish(false)
+ {
+ }
+
+ void Run() override {
+ TActorId child = GetActorContext().Register(new TBasicResponderActor);
+ ui32 itemsProcessed = 0;
+ try {
+ while (!Finish) {
+ GetActorContext().Send(child, new TEvRequest());
+ THolder<IEventHandle> resp = WaitForSpecificEvent<TEvResponse>();
+ UNIT_ASSERT_EQUAL(resp->GetTypeRewrite(), TEvResponse::EventType);
+ ++itemsProcessed;
+ }
+ } catch (const TPoisonPillException& /*ex*/) {
+ }
+ GetActorContext().Send(child, new TEvents::TEvPoisonPill);
+
+ AtomicSet(ItemsProcessed, itemsProcessed);
+ DoneEvent.Signal();
+ }
+
+ void ProcessUnexpectedEvent(TAutoPtr<IEventHandle> event) override {
+ if (event->GetTypeRewrite() == Enough) {
+ Finish = true;
+ }
+ }
+ };
+
+ void Check(THolder<IEventBase> && message) {
+ THolder<TActorSystemSetup> setup = MakeHolder<TActorSystemSetup>();
+ setup->NodeId = 0;
+ setup->ExecutorsCount = 1;
+ setup->Executors.Reset(new TAutoPtr<IExecutorPool>[setup->ExecutorsCount]);
+ for (ui32 i = 0; i < setup->ExecutorsCount; ++i) {
+ setup->Executors[i] = new TBasicExecutorPool(i, 5, 10, "basic");
+ }
+ setup->Scheduler = new TBasicSchedulerThread;
+
+ TActorSystem actorSystem(setup);
+
+ actorSystem.Start();
+
+ TManualEvent doneEvent;
+ TAtomic itemsProcessed = 0;
+ TActorId actor = actorSystem.Register(new TActorCoro(MakeHolder<TCoroActor>(doneEvent, itemsProcessed)));
+ NanoSleep(3UL * 1000 * 1000 * 1000);
+ actorSystem.Send(actor, message.Release());
+ doneEvent.WaitI();
+
+ UNIT_ASSERT(AtomicGet(itemsProcessed) >= 2);
+
+ actorSystem.Stop();
+ }
+
+ Y_UNIT_TEST(Basic) {
+ if (NSan::TSanIsOn()) {
+ // TODO https://st.yandex-team.ru/DEVTOOLS-3154
+ return;
+ }
+ Check(MakeHolder<TEvEnough>());
+ }
+
+ Y_UNIT_TEST(PoisonPill) {
+ Check(MakeHolder<TEvents::TEvPoisonPill>());
+ }
+}
diff --git a/library/cpp/actors/core/actor_ut.cpp b/library/cpp/actors/core/actor_ut.cpp
new file mode 100644
index 0000000000..e1b765ec72
--- /dev/null
+++ b/library/cpp/actors/core/actor_ut.cpp
@@ -0,0 +1,578 @@
+#include "actor.cpp"
+#include "events.h"
+#include "actorsystem.h"
+#include "executor_pool_basic.h"
+#include "scheduler_basic.h"
+#include "actor_bootstrapped.h"
+
+#include <library/cpp/actors/util/threadparkpad.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/algorithm.h>
+#include <util/system/atomic.h>
+#include <util/system/rwlock.h>
+#include <util/system/hp_timer.h>
+
+using namespace NActors;
+
+struct TTestEndDecorator : TDecorator {
+ TThreadParkPad* Pad;
+ TAtomic* ActorsAlive;
+
+ TTestEndDecorator(THolder<IActor>&& actor, TThreadParkPad* pad, TAtomic* actorsAlive)
+ : TDecorator(std::move(actor))
+ , Pad(pad)
+ , ActorsAlive(actorsAlive)
+ {
+ AtomicIncrement(*ActorsAlive);
+ }
+
+ ~TTestEndDecorator() {
+ if (AtomicDecrement(*ActorsAlive) == 0) {
+ Pad->Unpark();
+ }
+ }
+};
+
+Y_UNIT_TEST_SUITE(ActorBenchmark) {
+ static constexpr bool DefaultNoRealtime = true;
+ static constexpr ui32 DefaultSpinThreshold = 1000000;
+ static constexpr ui32 TotalEventsAmount = 1000;
+
+ class TDummyActor : public TActor<TDummyActor> {
+ public:
+ TDummyActor() : TActor<TDummyActor>(&TDummyActor::StateFunc) {}
+ STFUNC(StateFunc) {
+ (void)ev;
+ (void)ctx;
+ }
+ };
+
+ enum ERole {
+ Leader,
+ Follower
+ };
+
+ class TSendReceiveActor : public TActorBootstrapped<TSendReceiveActor> {
+ public:
+ static constexpr auto ActorActivityType() {
+ return ACTORLIB_COMMON;
+ }
+
+ TSendReceiveActor(double* elapsedTime, TActorId receiver, bool allocation, ERole role, ui32 neighbours = 0)
+ : EventsCounter(TotalEventsAmount)
+ , ElapsedTime(elapsedTime)
+ , Receiver(receiver)
+ , AllocatesMemory(allocation)
+ , Role(role)
+ , MailboxNeighboursCount(neighbours)
+ {}
+
+ void Bootstrap(const TActorContext &ctx) {
+ if (!Receiver) {
+ this->Receiver = SelfId();
+ } else {
+ EventsCounter /= 2; // We want to measure CPU requirement for one-way send
+ }
+ Timer.Reset();
+ Become(&TThis::StateFunc);
+ for (ui32 i = 0; i < MailboxNeighboursCount; ++i) {
+ ctx.RegisterWithSameMailbox(new TDummyActor());
+ }
+ if (Role == Leader) {
+ Send(Receiver, new TEvents::TEvPing());
+ }
+ }
+
+ STATEFN(StateFunc) {
+ if (EventsCounter == 0 && ElapsedTime != nullptr) {
+ *ElapsedTime = Timer.Passed() / TotalEventsAmount;
+ PassAway();
+ }
+
+ if (AllocatesMemory) {
+ Send(ev->Sender, new TEvents::TEvPing());
+ } else {
+ std::swap(*const_cast<TActorId*>(&ev->Sender), *const_cast<TActorId*>(&ev->Recipient));
+ ev->DropRewrite();
+ TActivationContext::Send(ev.Release());
+ }
+ EventsCounter--;
+ }
+
+ private:
+ THPTimer Timer;
+ ui64 EventsCounter;
+ double* ElapsedTime;
+ TActorId Receiver;
+ bool AllocatesMemory;
+ ERole Role;
+ ui32 MailboxNeighboursCount;
+ };
+
+ void AddBasicPool(THolder<TActorSystemSetup>& setup, ui32 threads, bool activateEveryEvent) {
+ TBasicExecutorPoolConfig basic;
+ basic.PoolId = setup->GetExecutorsCount();
+ basic.PoolName = TStringBuilder() << "b" << basic.PoolId;
+ basic.Threads = threads;
+ basic.SpinThreshold = DefaultSpinThreshold;
+ basic.TimePerMailbox = TDuration::Hours(1);
+ if (activateEveryEvent) {
+ basic.EventsPerMailbox = 1;
+ } else {
+ basic.EventsPerMailbox = Max<ui32>();
+ }
+ setup->CpuManager.Basic.emplace_back(std::move(basic));
+ }
+
+ void AddUnitedPool(THolder<TActorSystemSetup>& setup, ui32 concurrency, bool activateEveryEvent) {
+ TUnitedExecutorPoolConfig united;
+ united.PoolId = setup->GetExecutorsCount();
+ united.PoolName = TStringBuilder() << "u" << united.PoolId;
+ united.Concurrency = concurrency;
+ united.TimePerMailbox = TDuration::Hours(1);
+ if (activateEveryEvent) {
+ united.EventsPerMailbox = 1;
+ } else {
+ united.EventsPerMailbox = Max<ui32>();
+ }
+ setup->CpuManager.United.emplace_back(std::move(united));
+ }
+
+ THolder<TActorSystemSetup> GetActorSystemSetup(ui32 unitedCpuCount, bool preemption) {
+ auto setup = MakeHolder<NActors::TActorSystemSetup>();
+ setup->NodeId = 1;
+ setup->CpuManager.UnitedWorkers.CpuCount = unitedCpuCount;
+ setup->CpuManager.UnitedWorkers.SpinThresholdUs = DefaultSpinThreshold;
+ setup->CpuManager.UnitedWorkers.NoRealtime = DefaultNoRealtime;
+ if (preemption) {
+ setup->CpuManager.UnitedWorkers.PoolLimitUs = 500;
+ setup->CpuManager.UnitedWorkers.EventLimitUs = 100;
+ setup->CpuManager.UnitedWorkers.LimitPrecisionUs = 100;
+ } else {
+ setup->CpuManager.UnitedWorkers.PoolLimitUs = 100'000'000'000;
+ setup->CpuManager.UnitedWorkers.EventLimitUs = 10'000'000'000;
+ setup->CpuManager.UnitedWorkers.LimitPrecisionUs = 10'000'000'000;
+ }
+ setup->Scheduler = new TBasicSchedulerThread(NActors::TSchedulerConfig(512, 0));
+ return setup;
+ }
+
+ enum class EPoolType {
+ Basic,
+ United
+ };
+
+ THolder<TActorSystemSetup> InitActorSystemSetup(EPoolType poolType, ui32 poolsCount, ui32 threads, bool activateEveryEvent, bool preemption) {
+ if (poolType == EPoolType::Basic) {
+ THolder<TActorSystemSetup> setup = GetActorSystemSetup(0, false);
+ for (ui32 i = 0; i < poolsCount; ++i) {
+ AddBasicPool(setup, threads, activateEveryEvent);
+ }
+ return setup;
+ } else if (poolType == EPoolType::United) {
+ THolder<TActorSystemSetup> setup = GetActorSystemSetup(poolsCount * threads, preemption);
+ for (ui32 i = 0; i < poolsCount; ++i) {
+ AddUnitedPool(setup, threads, activateEveryEvent);
+ }
+ return setup;
+ }
+ Y_FAIL();
+ }
+
+ double BenchSendReceive(bool allocation, NActors::TMailboxType::EType mType, EPoolType poolType) {
+ THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, 1, 1, false, false);
+ TActorSystem actorSystem(setup);
+ actorSystem.Start();
+
+ TThreadParkPad pad;
+ TAtomic actorsAlive = 0;
+ double elapsedTime = 0;
+ THolder<IActor> endActor{
+ new TTestEndDecorator(THolder(
+ new TSendReceiveActor(&elapsedTime, {}, allocation, Leader)), &pad, &actorsAlive)};
+
+ actorSystem.Register(endActor.Release(), mType);
+
+ pad.Park();
+ actorSystem.Stop();
+
+ return 1e9 * elapsedTime;
+ }
+
+ double BenchSendActivateReceive(ui32 poolsCount, ui32 threads, bool allocation, EPoolType poolType) {
+ THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, poolsCount, threads, true, false);
+ TActorSystem actorSystem(setup);
+ actorSystem.Start();
+
+ TThreadParkPad pad;
+ TAtomic actorsAlive = 0;
+ double elapsedTime = 0;
+ ui32 followerPoolId = 0;
+
+ ui32 leaderPoolId = poolsCount == 1 ? 0 : 1;
+ TActorId followerId = actorSystem.Register(
+ new TSendReceiveActor(nullptr, {}, allocation, Follower), TMailboxType::HTSwap, followerPoolId);
+ THolder<IActor> leader{
+ new TTestEndDecorator(THolder(
+ new TSendReceiveActor(&elapsedTime, followerId, allocation, Leader)), &pad, &actorsAlive)};
+ actorSystem.Register(leader.Release(), TMailboxType::HTSwap, leaderPoolId);
+
+ pad.Park();
+ actorSystem.Stop();
+
+ return 1e9 * elapsedTime;
+ }
+
+ double BenchSendActivateReceiveWithMailboxNeighbours(ui32 MailboxNeighbourActors, EPoolType poolType) {
+ THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, 1, 1, false, false);
+ TActorSystem actorSystem(setup);
+ actorSystem.Start();
+
+ TThreadParkPad pad;
+ TAtomic actorsAlive = 0;
+ double elapsedTime = 0;
+
+ TActorId followerId = actorSystem.Register(
+ new TSendReceiveActor(nullptr, {}, false, Follower, MailboxNeighbourActors), TMailboxType::HTSwap);
+ THolder<IActor> leader{
+ new TTestEndDecorator(THolder(
+ new TSendReceiveActor(&elapsedTime, followerId, false, Leader, MailboxNeighbourActors)), &pad, &actorsAlive)};
+ actorSystem.Register(leader.Release(), TMailboxType::HTSwap);
+
+ pad.Park();
+ actorSystem.Stop();
+
+ return 1e9 * elapsedTime;
+ }
+
+ double BenchContentedThreads(ui32 threads, ui32 actorsPairsCount, EPoolType poolType) {
+ THolder<TActorSystemSetup> setup = InitActorSystemSetup(poolType, 1, threads, true, false);
+ TActorSystem actorSystem(setup);
+ actorSystem.Start();
+
+ TThreadParkPad pad;
+ TAtomic actorsAlive = 0;
+ THPTimer Timer;
+
+ TVector<double> dummy(actorsPairsCount);
+ Timer.Reset();
+ for (ui32 i = 0; i < actorsPairsCount; ++i) {
+ ui32 followerPoolId = 0;
+ ui32 leaderPoolId = 0;
+ TActorId followerId = actorSystem.Register(
+ new TSendReceiveActor(nullptr, {}, true, Follower), TMailboxType::HTSwap, followerPoolId);
+ THolder<IActor> leader{
+ new TTestEndDecorator(THolder(
+ new TSendReceiveActor(&dummy[i], followerId, true, Leader)), &pad, &actorsAlive)};
+ actorSystem.Register(leader.Release(), TMailboxType::HTSwap, leaderPoolId);
+ }
+
+ pad.Park();
+ auto elapsedTime = Timer.Passed() / TotalEventsAmount;
+ actorSystem.Stop();
+
+ return 1e9 * elapsedTime;
+ }
+
+ auto Mean(const TVector<double>& data) {
+ return Accumulate(data.begin(), data.end(), 0.0) / data.size();
+ }
+
+ auto Deviation(const TVector<double>& data) {
+ auto mean = Mean(data);
+ double deviation = 0.0;
+ for (const auto& x : data) {
+ deviation += (x - mean) * (x - mean);
+ }
+ return std::sqrt(deviation / data.size());
+ }
+
+ struct TStats {
+ double Mean;
+ double Deviation;
+ TString ToString() {
+ return TStringBuilder() << Mean << " ± " << Deviation << " ns " << std::ceil(Deviation / Mean * 1000) / 10.0 << "%";
+ }
+ };
+
+ template <typename Func>
+ TStats CountStats(Func func, ui32 itersCount = 5) {
+ TVector<double> elapsedTimes;
+ for (ui32 i = 0; i < itersCount; ++i) {
+ auto elapsedTime = func();
+ elapsedTimes.push_back(elapsedTime);
+ }
+ return {Mean(elapsedTimes), Deviation(elapsedTimes)};
+ }
+
+ TVector<NActors::TMailboxType::EType> MailboxTypes = {
+ TMailboxType::Simple,
+ TMailboxType::Revolving,
+ TMailboxType::HTSwap,
+ TMailboxType::ReadAsFilled,
+ TMailboxType::TinyReadAsFilled
+ };
+
+ Y_UNIT_TEST(SendReceive1Pool1ThreadAlloc) {
+ for (const auto& mType : MailboxTypes) {
+ auto stats = CountStats([mType] {
+ return BenchSendReceive(true, mType, EPoolType::Basic);
+ });
+ Cerr << stats.ToString() << " " << mType << Endl;
+ }
+ }
+
+ Y_UNIT_TEST(SendReceive1Pool1ThreadAllocUnited) {
+ for (const auto& mType : MailboxTypes) {
+ auto stats = CountStats([mType] {
+ return BenchSendReceive(true, mType, EPoolType::United);
+ });
+ Cerr << stats.ToString() << " " << mType << Endl;
+ }
+ }
+
+ Y_UNIT_TEST(SendReceive1Pool1ThreadNoAlloc) {
+ for (const auto& mType : MailboxTypes) {
+ auto stats = CountStats([mType] {
+ return BenchSendReceive(false, mType, EPoolType::Basic);
+ });
+ Cerr << stats.ToString() << " " << mType << Endl;
+ }
+ }
+
+ Y_UNIT_TEST(SendReceive1Pool1ThreadNoAllocUnited) {
+ for (const auto& mType : MailboxTypes) {
+ auto stats = CountStats([mType] {
+ return BenchSendReceive(false, mType, EPoolType::United);
+ });
+ Cerr << stats.ToString() << " " << mType << Endl;
+ }
+ }
+
+ Y_UNIT_TEST(SendActivateReceive1Pool1ThreadAlloc) {
+ auto stats = CountStats([] {
+ return BenchSendActivateReceive(1, 1, true, EPoolType::Basic);
+ });
+ Cerr << stats.ToString() << Endl;
+ }
+
+ Y_UNIT_TEST(SendActivateReceive1Pool1ThreadAllocUnited) {
+ auto stats = CountStats([] {
+ return BenchSendActivateReceive(1, 1, true, EPoolType::United);
+ });
+ Cerr << stats.ToString() << Endl;
+ }
+
+ Y_UNIT_TEST(SendActivateReceive1Pool1ThreadNoAlloc) {
+ auto stats = CountStats([] {
+ return BenchSendActivateReceive(1, 1, false, EPoolType::Basic);
+ });
+ Cerr << stats.ToString() << Endl;
+ }
+
+ Y_UNIT_TEST(SendActivateReceive1Pool1ThreadNoAllocUnited) {
+ auto stats = CountStats([] {
+ return BenchSendActivateReceive(1, 1, false, EPoolType::United);
+ });
+ Cerr << stats.ToString() << Endl;
+ }
+
+ Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsAlloc) {
+ auto stats = CountStats([] {
+ return BenchSendActivateReceive(1, 2, true, EPoolType::Basic);
+ });
+ Cerr << stats.ToString() << Endl;
+ }
+
+ Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsAllocUnited) {
+ auto stats = CountStats([] {
+ return BenchSendActivateReceive(1, 2, true, EPoolType::United);
+ });
+ Cerr << stats.ToString() << Endl;
+ }
+
+ Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsNoAlloc) {
+ auto stats = CountStats([] {
+ return BenchSendActivateReceive(1, 2, false, EPoolType::Basic);
+ });
+ Cerr << stats.ToString() << Endl;
+ }
+
+ Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsNoAllocUnited) {
+ auto stats = CountStats([] {
+ return BenchSendActivateReceive(1, 2, false, EPoolType::United);
+ });
+ Cerr << stats.ToString() << Endl;
+ }
+
+ Y_UNIT_TEST(SendActivateReceive2Pool1ThreadAlloc) {
+ auto stats = CountStats([] {
+ return BenchSendActivateReceive(2, 1, true, EPoolType::Basic);
+ });
+ Cerr << stats.ToString() << Endl;
+ }
+
+ Y_UNIT_TEST(SendActivateReceive2Pool1ThreadAllocUnited) {
+ auto stats = CountStats([] {
+ return BenchSendActivateReceive(2, 1, true, EPoolType::United);
+ });
+ Cerr << stats.ToString() << Endl;
+ }
+
+ Y_UNIT_TEST(SendActivateReceive2Pool1ThreadNoAlloc) {
+ auto stats = CountStats([] {
+ return BenchSendActivateReceive(2, 1, false, EPoolType::Basic);
+ });
+ Cerr << stats.ToString() << Endl;
+ }
+
+ Y_UNIT_TEST(SendActivateReceive2Pool1ThreadNoAllocUnited) {
+ auto stats = CountStats([] {
+ return BenchSendActivateReceive(2, 1, false, EPoolType::United);
+ });
+ Cerr << stats.ToString() << Endl;
+ }
+
+ void RunBenchContentedThreads(ui32 threads, EPoolType poolType) {
+ for (ui32 actorPairs = 1; actorPairs <= 2 * threads; actorPairs++) {
+ auto stats = CountStats([threads, actorPairs, poolType] {
+ return BenchContentedThreads(threads, actorPairs, poolType);
+ });
+ Cerr << stats.ToString() << " actorPairs: " << actorPairs << Endl;
+ }
+ }
+
+ Y_UNIT_TEST(SendActivateReceive1Pool1Threads) { RunBenchContentedThreads(1, EPoolType::Basic); }
+ Y_UNIT_TEST(SendActivateReceive1Pool1ThreadsUnited) { RunBenchContentedThreads(1, EPoolType::United); }
+ Y_UNIT_TEST(SendActivateReceive1Pool2Threads) { RunBenchContentedThreads(2, EPoolType::Basic); }
+ Y_UNIT_TEST(SendActivateReceive1Pool2ThreadsUnited) { RunBenchContentedThreads(2, EPoolType::United); }
+ Y_UNIT_TEST(SendActivateReceive1Pool3Threads) { RunBenchContentedThreads(3, EPoolType::Basic); }
+ Y_UNIT_TEST(SendActivateReceive1Pool3ThreadsUnited) { RunBenchContentedThreads(3, EPoolType::United); }
+ Y_UNIT_TEST(SendActivateReceive1Pool4Threads) { RunBenchContentedThreads(4, EPoolType::Basic); }
+ Y_UNIT_TEST(SendActivateReceive1Pool4ThreadsUnited) { RunBenchContentedThreads(4, EPoolType::United); }
+ Y_UNIT_TEST(SendActivateReceive1Pool5Threads) { RunBenchContentedThreads(5, EPoolType::Basic); }
+ Y_UNIT_TEST(SendActivateReceive1Pool5ThreadsUnited) { RunBenchContentedThreads(5, EPoolType::United); }
+ Y_UNIT_TEST(SendActivateReceive1Pool6Threads) { RunBenchContentedThreads(6, EPoolType::Basic); }
+ Y_UNIT_TEST(SendActivateReceive1Pool6ThreadsUnited) { RunBenchContentedThreads(6, EPoolType::United); }
+ Y_UNIT_TEST(SendActivateReceive1Pool7Threads) { RunBenchContentedThreads(7, EPoolType::Basic); }
+ Y_UNIT_TEST(SendActivateReceive1Pool7ThreadsUnited) { RunBenchContentedThreads(7, EPoolType::United); }
+ Y_UNIT_TEST(SendActivateReceive1Pool8Threads) { RunBenchContentedThreads(8, EPoolType::Basic); }
+ Y_UNIT_TEST(SendActivateReceive1Pool8ThreadsUnited) { RunBenchContentedThreads(8, EPoolType::United); }
+
+ Y_UNIT_TEST(SendActivateReceiveWithMailboxNeighbours) {
+ TVector<ui32> NeighbourActors = {0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 64, 128, 256};
+ for (const auto& neighbour : NeighbourActors) {
+ auto stats = CountStats([neighbour] {
+ return BenchSendActivateReceiveWithMailboxNeighbours(neighbour, EPoolType::Basic);
+ });
+ Cerr << stats.ToString() << " neighbourActors: " << neighbour << Endl;
+ }
+ }
+
+ Y_UNIT_TEST(SendActivateReceiveWithMailboxNeighboursUnited) {
+ TVector<ui32> NeighbourActors = {0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 64, 128, 256};
+ for (const auto& neighbour : NeighbourActors) {
+ auto stats = CountStats([neighbour] {
+ return BenchSendActivateReceiveWithMailboxNeighbours(neighbour, EPoolType::United);
+ });
+ Cerr << stats.ToString() << " neighbourActors: " << neighbour << Endl;
+ }
+ }
+}
+
+Y_UNIT_TEST_SUITE(TestDecorator) {
+ struct TPingDecorator : TDecorator {
+ TAutoPtr<IEventHandle> SavedEvent = nullptr;
+ ui64* Counter;
+
+ TPingDecorator(THolder<IActor>&& actor, ui64* counter)
+ : TDecorator(std::move(actor))
+ , Counter(counter)
+ {
+ }
+
+ bool DoBeforeReceiving(TAutoPtr<IEventHandle>& ev, const TActorContext& ctx) override {
+ *Counter += 1;
+ if (ev->Type != TEvents::THelloWorld::Pong) {
+ TAutoPtr<IEventHandle> pingEv = new IEventHandle(SelfId(), SelfId(), new TEvents::TEvPing());
+ SavedEvent = ev;
+ Actor->Receive(pingEv, ctx);
+ } else {
+ Actor->Receive(SavedEvent, ctx);
+ }
+ return false;
+ }
+ };
+
+ struct TPongDecorator : TDecorator {
+ ui64* Counter;
+
+ TPongDecorator(THolder<IActor>&& actor, ui64* counter)
+ : TDecorator(std::move(actor))
+ , Counter(counter)
+ {
+ }
+
+ bool DoBeforeReceiving(TAutoPtr<IEventHandle>& ev, const TActorContext&) override {
+ *Counter += 1;
+ if (ev->Type == TEvents::THelloWorld::Ping) {
+ TAutoPtr<IEventHandle> pongEv = new IEventHandle(SelfId(), SelfId(), new TEvents::TEvPong());
+ Send(SelfId(), new TEvents::TEvPong());
+ return false;
+ }
+ return true;
+ }
+ };
+
+ struct TTestActor : TActorBootstrapped<TTestActor> {
+ static constexpr char ActorName[] = "TestActor";
+
+ void Bootstrap()
+ {
+ const auto& activityTypeIndex = GetActivityType();
+ Y_ENSURE(activityTypeIndex < GetActivityTypeCount());
+ Y_ENSURE(GetActivityTypeName(activityTypeIndex) == "TestActor");
+ PassAway();
+ }
+ };
+
+ Y_UNIT_TEST(Basic) {
+ THolder<TActorSystemSetup> setup = MakeHolder<TActorSystemSetup>();
+ setup->NodeId = 0;
+ setup->ExecutorsCount = 1;
+ setup->Executors.Reset(new TAutoPtr<IExecutorPool>[setup->ExecutorsCount]);
+ for (ui32 i = 0; i < setup->ExecutorsCount; ++i) {
+ setup->Executors[i] = new TBasicExecutorPool(i, 1, 10, "basic");
+ }
+ setup->Scheduler = new TBasicSchedulerThread;
+
+ TActorSystem actorSystem(setup);
+ actorSystem.Start();
+
+ THolder<IActor> innerActor = MakeHolder<TTestActor>();
+ ui64 pongCounter = 0;
+ THolder<IActor> pongActor = MakeHolder<TPongDecorator>(std::move(innerActor), &pongCounter);
+ ui64 pingCounter = 0;
+ THolder<IActor> pingActor = MakeHolder<TPingDecorator>(std::move(pongActor), &pingCounter);
+
+ TThreadParkPad pad;
+ TAtomic actorsAlive = 0;
+
+ THolder<IActor> endActor = MakeHolder<TTestEndDecorator>(std::move(pingActor), &pad, &actorsAlive);
+ actorSystem.Register(endActor.Release(), TMailboxType::HTSwap);
+
+ pad.Park();
+ actorSystem.Stop();
+ UNIT_ASSERT(pongCounter == 2 && pingCounter == 2);
+ }
+
+ Y_UNIT_TEST(LocalProcessKey) {
+ static constexpr char ActorName[] = "TestActor";
+
+ UNIT_ASSERT((TEnumProcessKey<TActorActivityTag, IActor::EActorActivity>::GetName(IActor::INTERCONNECT_PROXY_TCP) == "INTERCONNECT_PROXY_TCP"));
+
+ UNIT_ASSERT((TLocalProcessKey<TActorActivityTag, ActorName>::GetName() == ActorName));
+ UNIT_ASSERT((TEnumProcessKey<TActorActivityTag, IActor::EActorActivity>::GetIndex(IActor::INTERCONNECT_PROXY_TCP) == IActor::INTERCONNECT_PROXY_TCP));
+ }
+}
diff --git a/library/cpp/actors/core/actorid.cpp b/library/cpp/actors/core/actorid.cpp
new file mode 100644
index 0000000000..ccda035eac
--- /dev/null
+++ b/library/cpp/actors/core/actorid.cpp
@@ -0,0 +1,34 @@
+#include "actorid.h"
+#include <util/string/builder.h>
+#include <util/string/cast.h>
+
+namespace NActors {
+ void TActorId::Out(IOutputStream& o) const {
+ o << "[" << NodeId() << ":" << LocalId() << ":" << Hint() << "]";
+ }
+
+ TString TActorId::ToString() const {
+ TString x;
+ TStringOutput o(x);
+ Out(o);
+ return x;
+ }
+
+ bool TActorId::Parse(const char* buf, ui32 sz) {
+ if (sz < 4 || buf[0] != '[' || buf[sz - 1] != ']')
+ return false;
+
+ size_t semicolons[2];
+ TStringBuf str(buf, sz);
+ semicolons[0] = str.find(':', 1);
+ if (semicolons[0] == TStringBuf::npos)
+ return false;
+ semicolons[1] = str.find(':', semicolons[0] + 1);
+ if (semicolons[1] == TStringBuf::npos)
+ return false;
+
+ bool success = TryFromString(buf + 1, semicolons[0] - 1, Raw.N.NodeId) && TryFromString(buf + semicolons[0] + 1, semicolons[1] - semicolons[0] - 1, Raw.N.LocalId) && TryFromString(buf + semicolons[1] + 1, sz - semicolons[1] - 2, Raw.N.Hint);
+
+ return success;
+ }
+}
diff --git a/library/cpp/actors/core/actorid.h b/library/cpp/actors/core/actorid.h
new file mode 100644
index 0000000000..d972b1a0ff
--- /dev/null
+++ b/library/cpp/actors/core/actorid.h
@@ -0,0 +1,196 @@
+#pragma once
+
+#include "defs.h"
+#include <util/stream/output.h> // for IOutputStream
+#include <util/generic/hash.h>
+
+namespace NActors {
+ // used as global uniq address of actor
+ // also could be used to transport service id (12 byte strings placed in hint-localid)
+ // highest 1 bit of node - mark of service id
+ // next 11 bits of node-id - pool id
+ // next 20 bits - node id itself
+
+ struct TActorId {
+ static constexpr ui32 MaxServiceIDLength = 12;
+ static constexpr ui32 MaxPoolID = 0x000007FF;
+ static constexpr ui32 MaxNodeId = 0x000FFFFF;
+ static constexpr ui32 PoolIndexShift = 20;
+ static constexpr ui32 PoolIndexMask = MaxPoolID << PoolIndexShift;
+ static constexpr ui32 ServiceMask = 0x80000000;
+ static constexpr ui32 NodeIdMask = MaxNodeId;
+
+ private:
+ union {
+ struct {
+ ui64 LocalId;
+ ui32 Hint;
+ ui32 NodeId;
+ } N;
+
+ struct {
+ ui64 X1;
+ ui64 X2;
+ } X;
+
+ ui8 Buf[16];
+ } Raw;
+
+ public:
+ TActorId() noexcept {
+ Raw.X.X1 = 0;
+ Raw.X.X2 = 0;
+ }
+
+ explicit TActorId(ui32 nodeId, ui32 poolId, ui64 localId, ui32 hint) noexcept {
+ Y_VERIFY_DEBUG(poolId <= MaxPoolID);
+ Raw.N.LocalId = localId;
+ Raw.N.Hint = hint;
+ Raw.N.NodeId = nodeId | (poolId << PoolIndexShift);
+ }
+
+ explicit TActorId(ui32 nodeId, const TStringBuf& x) noexcept {
+ Y_VERIFY(x.size() <= MaxServiceIDLength, "service id is too long");
+ Raw.N.LocalId = 0;
+ Raw.N.Hint = 0;
+ Raw.N.NodeId = nodeId | ServiceMask;
+ memcpy(Raw.Buf, x.data(), x.size());
+ }
+
+ explicit TActorId(ui64 x1, ui64 x2) noexcept {
+ Raw.X.X1 = x1;
+ Raw.X.X2 = x2;
+ }
+
+ explicit operator bool() const noexcept {
+ return Raw.X.X1 != 0 || Raw.X.X2 != 0;
+ }
+
+ ui64 LocalId() const noexcept {
+ return Raw.N.LocalId;
+ }
+
+ ui32 Hint() const noexcept {
+ return Raw.N.Hint;
+ }
+
+ ui32 NodeId() const noexcept {
+ return Raw.N.NodeId & NodeIdMask;
+ }
+
+ bool IsService() const noexcept {
+ return (Raw.N.NodeId & ServiceMask);
+ }
+
+ TStringBuf ServiceId() const noexcept {
+ Y_VERIFY_DEBUG(IsService());
+ return TStringBuf((const char*)Raw.Buf, MaxServiceIDLength);
+ }
+
+ static ui32 PoolIndex(ui32 nodeid) noexcept {
+ return ((nodeid & PoolIndexMask) >> PoolIndexShift);
+ }
+
+ ui32 PoolID() const noexcept {
+ return PoolIndex(Raw.N.NodeId);
+ }
+
+ ui64 RawX1() const noexcept {
+ return Raw.X.X1;
+ }
+
+ ui64 RawX2() const noexcept {
+ return Raw.X.X2;
+ }
+
+ bool operator<(const TActorId& x) const noexcept {
+ const ui64 s1 = Raw.X.X1;
+ const ui64 s2 = Raw.X.X2;
+ const ui64 x1 = x.Raw.X.X1;
+ const ui64 x2 = x.Raw.X.X2;
+
+ return (s1 != x1) ? (s1 < x1) : (s2 < x2);
+ }
+
+ bool operator!=(const TActorId& x) const noexcept {
+ return Raw.X.X1 != x.Raw.X.X1 || Raw.X.X2 != x.Raw.X.X2;
+ }
+
+ bool operator==(const TActorId& x) const noexcept {
+ return !(x != *this);
+ }
+
+ ui64 Hash() const noexcept {
+ const ui32* x = (const ui32*)Raw.Buf;
+
+ const ui64 x1 = x[0] * 0x001DFF3D8DC48F5Dull;
+ const ui64 x2 = x[1] * 0x179CA10C9242235Dull;
+ const ui64 x3 = x[2] * 0x0F530CAD458B0FB1ull;
+ const ui64 x4 = x[3] * 0xB5026F5AA96619E9ull;
+
+ const ui64 z1 = x1 + x2;
+ const ui64 z2 = x3 + x4;
+
+ const ui64 sum = 0x5851F42D4C957F2D + z1 + z2;
+
+ return (sum >> 32) | (sum << 32);
+ }
+
+ ui32 Hash32() const noexcept {
+ const ui32* x = (const ui32*)Raw.Buf;
+
+ const ui64 x1 = x[0] * 0x001DFF3D8DC48F5Dull;
+ const ui64 x2 = x[1] * 0x179CA10C9242235Dull;
+ const ui64 x3 = x[2] * 0x0F530CAD458B0FB1ull;
+ const ui64 x4 = x[3] * 0xB5026F5AA96619E9ull;
+
+ const ui64 z1 = x1 + x2;
+ const ui64 z2 = x3 + x4;
+
+ const ui64 sum = 0x5851F42D4C957F2D + z1 + z2;
+
+ return sum >> 32;
+ }
+
+ struct THash {
+ ui64 operator()(const TActorId& actorId) const noexcept {
+ return actorId.Hash();
+ }
+ };
+
+ struct THash32 {
+ ui64 operator()(const TActorId& actorId) const noexcept {
+ return actorId.Hash();
+ }
+ };
+
+ struct TOrderedCmp {
+ bool operator()(const TActorId &left, const TActorId &right) const noexcept {
+ Y_VERIFY_DEBUG(!left.IsService() && !right.IsService(), "ordered compare works for plain actorids only");
+ const ui32 n1 = left.NodeId();
+ const ui32 n2 = right.NodeId();
+
+ return (n1 != n2) ? (n1 < n2) : left.LocalId() < right.LocalId();
+ }
+ };
+
+ TString ToString() const;
+ void Out(IOutputStream& o) const;
+ bool Parse(const char* buf, ui32 sz);
+ };
+
+ static_assert(sizeof(TActorId) == 16, "expect sizeof(TActorId) == 16");
+ static_assert(MaxPools < TActorId::MaxPoolID); // current implementation of united pool has limit MaxPools on pool id
+}
+
+template <>
+inline void Out<NActors::TActorId>(IOutputStream& o, const NActors::TActorId& x) {
+ return x.Out(o);
+}
+
+template <>
+struct THash<NActors::TActorId> {
+ inline ui64 operator()(const NActors::TActorId& x) const {
+ return x.Hash();
+ }
+};
diff --git a/library/cpp/actors/core/actorsystem.cpp b/library/cpp/actors/core/actorsystem.cpp
new file mode 100644
index 0000000000..c58698a206
--- /dev/null
+++ b/library/cpp/actors/core/actorsystem.cpp
@@ -0,0 +1,277 @@
+#include "defs.h"
+#include "actorsystem.h"
+#include "callstack.h"
+#include "cpu_manager.h"
+#include "mailbox.h"
+#include "events.h"
+#include "interconnect.h"
+#include "servicemap.h"
+#include "scheduler_queue.h"
+#include "scheduler_actor.h"
+#include "log.h"
+#include "probes.h"
+#include "ask.h"
+#include <library/cpp/actors/util/affinity.h>
+#include <library/cpp/actors/util/datetime.h>
+#include <util/generic/hash.h>
+#include <util/system/rwlock.h>
+#include <util/random/random.h>
+
+namespace NActors {
+ LWTRACE_USING(ACTORLIB_PROVIDER);
+
+ struct TActorSystem::TServiceMap : TNonCopyable {
+ NActors::TServiceMap<TActorId, TActorId, TActorId::THash> LocalMap;
+ TTicketLock Lock;
+
+ TActorId RegisterLocalService(const TActorId& serviceId, const TActorId& actorId) {
+ TTicketLock::TGuard guard(&Lock);
+ const TActorId old = LocalMap.Update(serviceId, actorId);
+ return old;
+ }
+
+ TActorId LookupLocal(const TActorId& x) {
+ return LocalMap.Find(x);
+ }
+ };
+
+ TActorSystem::TActorSystem(THolder<TActorSystemSetup>& setup, void* appData,
+ TIntrusivePtr<NLog::TSettings> loggerSettings)
+ : NodeId(setup->NodeId)
+ , CpuManager(new TCpuManager(setup))
+ , ExecutorPoolCount(CpuManager->GetExecutorsCount())
+ , Scheduler(setup->Scheduler)
+ , InterconnectCount((ui32)setup->Interconnect.ProxyActors.size())
+ , CurrentTimestamp(0)
+ , CurrentMonotonic(0)
+ , CurrentIDCounter(RandomNumber<ui64>())
+ , SystemSetup(setup.Release())
+ , DefSelfID(NodeId, "actorsystem")
+ , AppData0(appData)
+ , LoggerSettings0(loggerSettings)
+ , StartExecuted(false)
+ , StopExecuted(false)
+ , CleanupExecuted(false)
+ {
+ ServiceMap.Reset(new TServiceMap());
+ }
+
+ TActorSystem::~TActorSystem() {
+ Cleanup();
+ }
+
+ bool TActorSystem::Send(TAutoPtr<IEventHandle> ev) const {
+ if (Y_UNLIKELY(!ev))
+ return false;
+
+#ifdef USE_ACTOR_CALLSTACK
+ ev->Callstack.TraceIfEmpty();
+#endif
+
+ TActorId recipient = ev->GetRecipientRewrite();
+ const ui32 recpNodeId = recipient.NodeId();
+
+ if (recpNodeId != NodeId && recpNodeId != 0) {
+ // if recipient is not local one - rewrite with forward instruction
+ Y_VERIFY_DEBUG(!ev->HasEvent() || ev->GetBase()->IsSerializable());
+ Y_VERIFY(ev->Recipient == recipient,
+ "Event rewrite from %s to %s would be lost via interconnect",
+ ev->Recipient.ToString().c_str(),
+ recipient.ToString().c_str());
+ recipient = InterconnectProxy(recpNodeId);
+ ev->Rewrite(TEvInterconnect::EvForward, recipient);
+ }
+ if (recipient.IsService()) {
+ TActorId target = ServiceMap->LookupLocal(recipient);
+ if (!target && IsInterconnectProxyId(recipient) && ProxyWrapperFactory) {
+ const TActorId actorId = ProxyWrapperFactory(const_cast<TActorSystem*>(this),
+ GetInterconnectProxyNode(recipient));
+ with_lock(ProxyCreationLock) {
+ target = ServiceMap->LookupLocal(recipient);
+ if (!target) {
+ target = actorId;
+ ServiceMap->RegisterLocalService(recipient, target);
+ }
+ }
+ if (target != actorId) {
+ // a race has occured, terminate newly created actor
+ Send(new IEventHandle(TEvents::TSystem::Poison, 0, actorId, {}, nullptr, 0));
+ }
+ }
+ recipient = target;
+ ev->Rewrite(ev->GetTypeRewrite(), recipient);
+ }
+
+ Y_VERIFY_DEBUG(recipient == ev->GetRecipientRewrite());
+ const ui32 recpPool = recipient.PoolID();
+ if (recipient && recpPool < ExecutorPoolCount) {
+ if (CpuManager->GetExecutorPool(recpPool)->Send(ev)) {
+ return true;
+ }
+ }
+
+ Send(ev->ForwardOnNondelivery(TEvents::TEvUndelivered::ReasonActorUnknown));
+ return false;
+ }
+
+ bool TActorSystem::Send(const TActorId& recipient, IEventBase* ev, ui32 flags) const {
+ return this->Send(new IEventHandle(recipient, DefSelfID, ev, flags));
+ }
+
+ void TActorSystem::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) const {
+ Schedule(deadline - Timestamp(), ev, cookie);
+ }
+
+ void TActorSystem::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) const {
+ const auto current = Monotonic();
+ if (deadline < current)
+ deadline = current;
+
+ TTicketLock::TGuard guard(&ScheduleLock);
+ ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie);
+ }
+
+ void TActorSystem::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) const {
+ const auto deadline = Monotonic() + delta;
+
+ TTicketLock::TGuard guard(&ScheduleLock);
+ ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie);
+ }
+
+ TActorId TActorSystem::Register(IActor* actor, TMailboxType::EType mailboxType, ui32 executorPool, ui64 revolvingCounter,
+ const TActorId& parentId) {
+ Y_VERIFY(executorPool < ExecutorPoolCount, "executorPool# %" PRIu32 ", ExecutorPoolCount# %" PRIu32,
+ (ui32)executorPool, (ui32)ExecutorPoolCount);
+ return CpuManager->GetExecutorPool(executorPool)->Register(actor, mailboxType, revolvingCounter, parentId);
+ }
+
+ NThreading::TFuture<THolder<IEventBase>> TActorSystem::AskGeneric(TMaybe<ui32> expectedEventType,
+ TActorId recipient, THolder<IEventBase> event,
+ TDuration timeout) {
+ auto promise = NThreading::NewPromise<THolder<IEventBase>>();
+ Register(MakeAskActor(expectedEventType, recipient, std::move(event), timeout, promise).Release());
+ return promise.GetFuture();
+ }
+
+ ui64 TActorSystem::AllocateIDSpace(ui64 count) {
+ Y_VERIFY_DEBUG(count < Max<ui32>() / 65536);
+
+ static_assert(sizeof(TAtomic) == sizeof(ui64), "expect sizeof(TAtomic) == sizeof(ui64)");
+
+ // get high 32 bits as seconds from epoch
+ // it could wrap every century, but we don't expect any actor-reference to live this long so such wrap will do no harm
+ const ui64 timeFromEpoch = TInstant::MicroSeconds(RelaxedLoad(&CurrentTimestamp)).Seconds();
+
+ // get low 32 bits as counter value
+ ui32 lowPartEnd = (ui32)(AtomicAdd(CurrentIDCounter, count));
+ while (lowPartEnd < count) // if our request crosses 32bit boundary - retry
+ lowPartEnd = (ui32)(AtomicAdd(CurrentIDCounter, count));
+
+ const ui64 lowPart = lowPartEnd - count;
+ const ui64 ret = (timeFromEpoch << 32) | lowPart;
+
+ return ret;
+ }
+
+ TActorId TActorSystem::InterconnectProxy(ui32 destinationNode) const {
+ if (destinationNode < InterconnectCount)
+ return Interconnect[destinationNode];
+ else if (destinationNode != NodeId)
+ return MakeInterconnectProxyId(destinationNode);
+ else
+ return TActorId();
+ }
+
+ ui32 TActorSystem::BroadcastToProxies(const std::function<IEventHandle*(const TActorId&)>& eventFabric) {
+ // TODO: get rid of this method
+ for (ui32 i = 0; i < InterconnectCount; ++i) {
+ Send(eventFabric(Interconnect[i]));
+ }
+ return InterconnectCount;
+ }
+
+ TActorId TActorSystem::LookupLocalService(const TActorId& x) const {
+ return ServiceMap->LookupLocal(x);
+ }
+
+ TActorId TActorSystem::RegisterLocalService(const TActorId& serviceId, const TActorId& actorId) {
+ // TODO: notify old actor about demotion
+ return ServiceMap->RegisterLocalService(serviceId, actorId);
+ }
+
+ void TActorSystem::GetPoolStats(ui32 poolId, TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const {
+ CpuManager->GetPoolStats(poolId, poolStats, statsCopy);
+ }
+
+ void TActorSystem::Start() {
+ Y_VERIFY(StartExecuted == false);
+ StartExecuted = true;
+
+ ScheduleQueue.Reset(new NSchedulerQueue::TQueueType());
+ TVector<NSchedulerQueue::TReader*> scheduleReaders;
+ scheduleReaders.push_back(&ScheduleQueue->Reader);
+ CpuManager->PrepareStart(scheduleReaders, this);
+ Scheduler->Prepare(this, &CurrentTimestamp, &CurrentMonotonic);
+ Scheduler->PrepareSchedules(&scheduleReaders.front(), (ui32)scheduleReaders.size());
+
+ // setup interconnect proxies
+ {
+ const TInterconnectSetup& setup = SystemSetup->Interconnect;
+ Interconnect.Reset(new TActorId[InterconnectCount + 1]);
+ for (ui32 i = 0, e = InterconnectCount; i != e; ++i) {
+ const TActorSetupCmd& x = setup.ProxyActors[i];
+ if (x.Actor) {
+ Interconnect[i] = Register(x.Actor, x.MailboxType, x.PoolId, i);
+ Y_VERIFY(!!Interconnect[i]);
+ }
+ }
+ ProxyWrapperFactory = std::move(SystemSetup->Interconnect.ProxyWrapperFactory);
+ }
+
+ // setup local services
+ {
+ for (ui32 i = 0, e = (ui32)SystemSetup->LocalServices.size(); i != e; ++i) {
+ const std::pair<TActorId, TActorSetupCmd>& x = SystemSetup->LocalServices[i];
+ const TActorId xid = Register(x.second.Actor, x.second.MailboxType, x.second.PoolId, i);
+ Y_VERIFY(!!xid);
+ if (!!x.first)
+ RegisterLocalService(x.first, xid);
+ }
+ }
+
+ // ok, setup complete, we could destroy setup config
+ SystemSetup.Destroy();
+
+ Scheduler->PrepareStart();
+ CpuManager->Start();
+ Send(MakeSchedulerActorId(), new TEvSchedulerInitialize(scheduleReaders, &CurrentTimestamp, &CurrentMonotonic));
+ Scheduler->Start();
+ }
+
+ void TActorSystem::Stop() {
+ if (StopExecuted || !StartExecuted)
+ return;
+
+ StopExecuted = true;
+
+ for (auto&& fn : std::exchange(DeferredPreStop, {})) {
+ fn();
+ }
+
+ Scheduler->PrepareStop();
+ CpuManager->PrepareStop();
+ Scheduler->Stop();
+ CpuManager->Shutdown();
+ }
+
+ void TActorSystem::Cleanup() {
+ Stop();
+ if (CleanupExecuted || !StartExecuted)
+ return;
+ CleanupExecuted = true;
+ CpuManager->Cleanup();
+ Scheduler.Destroy();
+ }
+
+ ui32 TActorSystem::MemProfActivityBase;
+}
diff --git a/library/cpp/actors/core/actorsystem.h b/library/cpp/actors/core/actorsystem.h
new file mode 100644
index 0000000000..40499d7586
--- /dev/null
+++ b/library/cpp/actors/core/actorsystem.h
@@ -0,0 +1,367 @@
+#pragma once
+
+#include "defs.h"
+
+#include "actor.h"
+#include "balancer.h"
+#include "config.h"
+#include "event.h"
+#include "log_settings.h"
+#include "scheduler_cookie.h"
+#include "mon_stats.h"
+
+#include <library/cpp/threading/future/future.h>
+#include <library/cpp/actors/util/ticket_lock.h>
+
+#include <util/generic/vector.h>
+#include <util/datetime/base.h>
+#include <util/system/mutex.h>
+
+namespace NActors {
+ class TActorSystem;
+ class TCpuManager;
+ class IExecutorPool;
+ struct TWorkerContext;
+
+ inline TActorId MakeInterconnectProxyId(ui32 destNodeId) {
+ char data[12];
+ memcpy(data, "ICProxy@", 8);
+ memcpy(data + 8, &destNodeId, sizeof(ui32));
+ return TActorId(0, TStringBuf(data, 12));
+ }
+
+ inline bool IsInterconnectProxyId(const TActorId& actorId) {
+ return actorId.IsService() && !memcmp(actorId.ServiceId().data(), "ICProxy@", 8);
+ }
+
+ inline ui32 GetInterconnectProxyNode(const TActorId& actorId) {
+ ui32 nodeId;
+ memcpy(&nodeId, actorId.ServiceId().data() + 8, sizeof(ui32));
+ return nodeId;
+ }
+
+ namespace NSchedulerQueue {
+ class TReader;
+ struct TQueueType;
+ }
+
+ class IExecutorPool : TNonCopyable {
+ public:
+ const ui32 PoolId;
+
+ TAtomic ActorRegistrations;
+ TAtomic DestroyedActors;
+
+ IExecutorPool(ui32 poolId)
+ : PoolId(poolId)
+ , ActorRegistrations(0)
+ , DestroyedActors(0)
+ {
+ }
+
+ virtual ~IExecutorPool() {
+ }
+
+ // for workers
+ virtual ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) = 0;
+ virtual void ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingCounter) = 0;
+
+ /**
+ * Schedule one-shot event that will be send at given time point in the future.
+ *
+ * @param deadline the wallclock time point in future when event must be send
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ * @param workerId index of thread which will perform event dispatching
+ */
+ virtual void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) = 0;
+
+ /**
+ * Schedule one-shot event that will be send at given time point in the future.
+ *
+ * @param deadline the monotonic time point in future when event must be send
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ * @param workerId index of thread which will perform event dispatching
+ */
+ virtual void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) = 0;
+
+ /**
+ * Schedule one-shot event that will be send after given delay.
+ *
+ * @param delta the time from now to delay event sending
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ * @param workerId index of thread which will perform event dispatching
+ */
+ virtual void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) = 0;
+
+ // for actorsystem
+ virtual bool Send(TAutoPtr<IEventHandle>& ev) = 0;
+ virtual void ScheduleActivation(ui32 activation) = 0;
+ virtual void ScheduleActivationEx(ui32 activation, ui64 revolvingCounter) = 0;
+ virtual TActorId Register(IActor* actor, TMailboxType::EType mailboxType, ui64 revolvingCounter, const TActorId& parentId) = 0;
+ virtual TActorId Register(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId) = 0;
+
+ // lifecycle stuff
+ virtual void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) = 0;
+ virtual void Start() = 0;
+ virtual void PrepareStop() = 0;
+ virtual void Shutdown() = 0;
+ virtual bool Cleanup() = 0;
+
+ virtual void GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const {
+ // TODO: make pure virtual and override everywhere
+ Y_UNUSED(poolStats);
+ Y_UNUSED(statsCopy);
+ }
+
+ virtual TString GetName() const {
+ return TString();
+ }
+
+ virtual ui32 GetThreads() const {
+ return 1;
+ }
+
+ // generic
+ virtual TAffinity* Affinity() const = 0;
+
+ virtual void SetRealTimeMode() const {}
+ };
+
+ // could be proxy to in-pool schedulers (for NUMA-aware executors)
+ class ISchedulerThread : TNonCopyable {
+ public:
+ virtual ~ISchedulerThread() {
+ }
+
+ virtual void Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) = 0;
+ virtual void PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) = 0;
+ virtual void PrepareStart() { /* empty */ }
+ virtual void Start() = 0;
+ virtual void PrepareStop() = 0;
+ virtual void Stop() = 0;
+ };
+
+ struct TActorSetupCmd {
+ TMailboxType::EType MailboxType;
+ ui32 PoolId;
+ IActor* Actor;
+
+ TActorSetupCmd()
+ : MailboxType(TMailboxType::HTSwap)
+ , PoolId(0)
+ , Actor(nullptr)
+ {
+ }
+
+ TActorSetupCmd(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId)
+ : MailboxType(mailboxType)
+ , PoolId(poolId)
+ , Actor(actor)
+ {
+ }
+
+ void Set(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId) {
+ MailboxType = mailboxType;
+ PoolId = poolId;
+ Actor = actor;
+ }
+ };
+
+ using TProxyWrapperFactory = std::function<TActorId(TActorSystem*, ui32)>;
+
+ struct TInterconnectSetup {
+ TVector<TActorSetupCmd> ProxyActors;
+ TProxyWrapperFactory ProxyWrapperFactory;
+ };
+
+ struct TActorSystemSetup {
+ ui32 NodeId = 0;
+
+ // Either Executors or CpuManager must be initialized
+ ui32 ExecutorsCount = 0;
+ TArrayHolder<TAutoPtr<IExecutorPool>> Executors;
+
+ TAutoPtr<IBalancer> Balancer; // main implementation will be implicitly created if not set
+
+ TCpuManagerConfig CpuManager;
+
+ TAutoPtr<ISchedulerThread> Scheduler;
+ ui32 MaxActivityType = 5; // for default entries
+
+ TInterconnectSetup Interconnect;
+
+ using TLocalServices = TVector<std::pair<TActorId, TActorSetupCmd>>;
+ TLocalServices LocalServices;
+
+ ui32 GetExecutorsCount() const {
+ return Executors ? ExecutorsCount : CpuManager.GetExecutorsCount();
+ }
+
+ TString GetPoolName(ui32 poolId) const {
+ return Executors ? Executors[poolId]->GetName() : CpuManager.GetPoolName(poolId);
+ }
+
+ ui32 GetThreads(ui32 poolId) const {
+ return Executors ? Executors[poolId]->GetThreads() : CpuManager.GetThreads(poolId);
+ }
+ };
+
+ class TActorSystem : TNonCopyable {
+ struct TServiceMap;
+
+ public:
+ const ui32 NodeId;
+
+ private:
+ THolder<TCpuManager> CpuManager;
+ const ui32 ExecutorPoolCount;
+
+ TAutoPtr<ISchedulerThread> Scheduler;
+ THolder<TServiceMap> ServiceMap;
+
+ const ui32 InterconnectCount;
+ TArrayHolder<TActorId> Interconnect;
+
+ volatile ui64 CurrentTimestamp;
+ volatile ui64 CurrentMonotonic;
+ volatile ui64 CurrentIDCounter;
+
+ THolder<NSchedulerQueue::TQueueType> ScheduleQueue;
+ mutable TTicketLock ScheduleLock;
+
+ friend class TExecutorThread;
+
+ THolder<TActorSystemSetup> SystemSetup;
+ TActorId DefSelfID;
+ void* AppData0;
+ TIntrusivePtr<NLog::TSettings> LoggerSettings0;
+ TProxyWrapperFactory ProxyWrapperFactory;
+ TMutex ProxyCreationLock;
+
+ bool StartExecuted;
+ bool StopExecuted;
+ bool CleanupExecuted;
+
+ std::deque<std::function<void()>> DeferredPreStop;
+ public:
+ TActorSystem(THolder<TActorSystemSetup>& setup, void* appData = nullptr,
+ TIntrusivePtr<NLog::TSettings> loggerSettings = TIntrusivePtr<NLog::TSettings>(nullptr));
+ ~TActorSystem();
+
+ void Start();
+ void Stop();
+ void Cleanup();
+
+ TActorId Register(IActor* actor, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 executorPool = 0,
+ ui64 revolvingCounter = 0, const TActorId& parentId = TActorId());
+
+ bool Send(TAutoPtr<IEventHandle> ev) const;
+ bool Send(const TActorId& recipient, IEventBase* ev, ui32 flags = 0) const;
+
+ /**
+ * Schedule one-shot event that will be send at given time point in the future.
+ *
+ * @param deadline the wallclock time point in future when event must be send
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ */
+ void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr) const;
+
+ /**
+ * Schedule one-shot event that will be send at given time point in the future.
+ *
+ * @param deadline the monotonic time point in future when event must be send
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ */
+ void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr) const;
+
+ /**
+ * Schedule one-shot event that will be send after given delay.
+ *
+ * @param delta the time from now to delay event sending
+ * @param ev the event to send
+ * @param cookie cookie that will be piggybacked with event
+ */
+ void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr) const;
+
+ /**
+ * A way to interact with actors from non-actor context.
+ *
+ * This method will send the `event` to the `recipient` and then will wait for a response. When response arrives,
+ * it will be passed to the future. If response is not of type `T`, the future will resolve into an exception.
+ *
+ * @tparam T expected response type. Must be derived from `TEventBase`,
+ * or use `IEventBase` to catch any response.
+ * @param actorSystem actor system that will be used to register an actor that'll wait for response.
+ * @param recipient who will get a request.
+ * @param event a request message.
+ * @return future that will be resolved when a message from `recipient` arrives.
+ */
+ template <typename T>
+ [[nodiscard]]
+ NThreading::TFuture<THolder<T>> Ask(TActorId recipient, THolder<IEventBase> event, TDuration timeout = TDuration::Max()) {
+ if constexpr (std::is_same_v<T, IEventBase>) {
+ return AskGeneric(Nothing(), recipient, std::move(event), timeout);
+ } else {
+ return AskGeneric(T::EventType, recipient, std::move(event), timeout)
+ .Apply([](const NThreading::TFuture<THolder<IEventBase>>& ev) {
+ return THolder<T>(static_cast<T*>(const_cast<THolder<IEventBase>&>(ev.GetValueSync()).Release())); // =(
+ });
+ }
+ }
+
+ [[nodiscard]]
+ NThreading::TFuture<THolder<IEventBase>> AskGeneric(
+ TMaybe<ui32> expectedEventType,
+ TActorId recipient,
+ THolder<IEventBase> event,
+ TDuration timeout);
+
+ ui64 AllocateIDSpace(ui64 count);
+
+ TActorId InterconnectProxy(ui32 destinationNode) const;
+ ui32 BroadcastToProxies(const std::function<IEventHandle*(const TActorId&)>&);
+
+ void UpdateLinkStatus(ui8 status, ui32 destinationNode);
+ ui8 LinkStatus(ui32 destinationNode);
+
+ TActorId LookupLocalService(const TActorId& x) const;
+ TActorId RegisterLocalService(const TActorId& serviceId, const TActorId& actorId);
+
+ ui32 GetMaxActivityType() const {
+ return SystemSetup ? SystemSetup->MaxActivityType : 1;
+ }
+
+ TInstant Timestamp() const {
+ return TInstant::MicroSeconds(RelaxedLoad(&CurrentTimestamp));
+ }
+
+ TMonotonic Monotonic() const {
+ return TMonotonic::MicroSeconds(RelaxedLoad(&CurrentMonotonic));
+ }
+
+ template <typename T>
+ T* AppData() const {
+ return (T*)AppData0;
+ }
+
+ NLog::TSettings* LoggerSettings() const {
+ return LoggerSettings0.Get();
+ }
+
+ void GetPoolStats(ui32 poolId, TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const;
+
+ void DeferPreStop(std::function<void()> fn) {
+ DeferredPreStop.push_back(std::move(fn));
+ }
+
+ /* This is the base for memory profiling tags.
+ System sets memory profiling tag for debug version of lfalloc.
+ The tag is set as "base_tag + actor_activity_type". */
+ static ui32 MemProfActivityBase;
+ };
+}
diff --git a/library/cpp/actors/core/actorsystem_ut.cpp b/library/cpp/actors/core/actorsystem_ut.cpp
new file mode 100644
index 0000000000..231d6f0ca1
--- /dev/null
+++ b/library/cpp/actors/core/actorsystem_ut.cpp
@@ -0,0 +1,45 @@
+#include "actorsystem.h"
+
+#include <library/cpp/actors/testlib/test_runtime.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NActors;
+
+Y_UNIT_TEST_SUITE(TActorSystemTest) {
+
+ class TTestActor: public TActor<TTestActor> {
+ public:
+ TTestActor()
+ : TActor{&TThis::Main}
+ {
+ }
+
+ STATEFN(Main) {
+ Y_UNUSED(ev);
+ }
+ };
+
+ THolder<TTestActorRuntimeBase> CreateRuntime() {
+ auto runtime = MakeHolder<TTestActorRuntimeBase>();
+ runtime->SetScheduledEventFilter([](auto&&, auto&&, auto&&, auto&&) { return false; });
+ runtime->Initialize();
+ return runtime;
+ }
+
+ Y_UNIT_TEST(LocalService) {
+ THolder<TTestActorRuntimeBase> runtime = CreateRuntime();
+ auto actorA = runtime->Register(new TTestActor);
+ auto actorB = runtime->Register(new TTestActor);
+
+ TActorId myServiceId{0, TStringBuf{"my-service"}};
+
+ auto prevActorId = runtime->RegisterService(myServiceId, actorA);
+ UNIT_ASSERT(!prevActorId);
+ UNIT_ASSERT_EQUAL(runtime->GetLocalServiceId(myServiceId), actorA);
+
+ prevActorId = runtime->RegisterService(myServiceId, actorB);
+ UNIT_ASSERT(prevActorId);
+ UNIT_ASSERT_EQUAL(prevActorId, actorA);
+ UNIT_ASSERT_EQUAL(runtime->GetLocalServiceId(myServiceId), actorB);
+ }
+}
diff --git a/library/cpp/actors/core/ask.cpp b/library/cpp/actors/core/ask.cpp
new file mode 100644
index 0000000000..0054c9a906
--- /dev/null
+++ b/library/cpp/actors/core/ask.cpp
@@ -0,0 +1,74 @@
+#include "ask.h"
+
+#include "actor_bootstrapped.h"
+#include "actorid.h"
+#include "event.h"
+#include "hfunc.h"
+
+namespace NActors {
+ namespace {
+ class TAskActor: public TActorBootstrapped<TAskActor> {
+ enum {
+ Timeout = EventSpaceBegin(TEvents::ES_PRIVATE),
+ };
+
+ // We can't use the standard timeout event because recipient may send us one.
+ struct TTimeout: public TEventLocal<TTimeout, Timeout> {
+ };
+
+ public:
+ TAskActor(
+ TMaybe<ui32> expectedEventType,
+ TActorId recipient,
+ THolder<IEventBase> event,
+ TDuration timeout,
+ const NThreading::TPromise<THolder<IEventBase>>& promise)
+ : ExpectedEventType_(expectedEventType)
+ , Recipient_(recipient)
+ , Event_(std::move(event))
+ , Timeout_(timeout)
+ , Promise_(promise)
+ {
+ }
+
+ public:
+ void Bootstrap() {
+ Send(Recipient_, std::move(Event_));
+ Become(&TAskActor::Waiting);
+
+ if (Timeout_ != TDuration::Max()) {
+ Schedule(Timeout_, new TTimeout);
+ }
+ }
+
+ STATEFN(Waiting) {
+ if (ev->GetTypeRewrite() == TTimeout::EventType) {
+ Promise_.SetException(std::make_exception_ptr(yexception() << "ask timeout"));
+ } else if (!ExpectedEventType_ || ev->GetTypeRewrite() == ExpectedEventType_) {
+ Promise_.SetValue(ev->ReleaseBase());
+ } else {
+ Promise_.SetException(std::make_exception_ptr(yexception() << "received unexpected response " << ev->GetBase()->ToString()));
+ }
+
+ PassAway();
+ }
+
+ public:
+ TMaybe<ui32> ExpectedEventType_;
+ TActorId Recipient_;
+ THolder<IEventBase> Event_;
+ TDuration Timeout_;
+ NThreading::TPromise<THolder<IEventBase>> Promise_;
+ };
+ }
+
+ THolder<IActor> MakeAskActor(
+ TMaybe<ui32> expectedEventType,
+ TActorId recipient,
+ THolder<IEventBase> event,
+ TDuration timeout,
+ const NThreading::TPromise<THolder<IEventBase>>& promise)
+ {
+ return MakeHolder<TAskActor>(expectedEventType, std::move(recipient), std::move(event), timeout, promise);
+ }
+}
diff --git a/library/cpp/actors/core/ask.h b/library/cpp/actors/core/ask.h
new file mode 100644
index 0000000000..036f1833a4
--- /dev/null
+++ b/library/cpp/actors/core/ask.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "actor.h"
+#include "event.h"
+
+#include <library/cpp/threading/future/future.h>
+
+namespace NActors {
+ /**
+ * See `TActorSystem::Ask`.
+ */
+ THolder<IActor> MakeAskActor(
+ TMaybe<ui32> expectedEventType,
+ TActorId recipient,
+ THolder<IEventBase> event,
+ TDuration timeout,
+ const NThreading::TPromise<THolder<IEventBase>>& promise);
+}
diff --git a/library/cpp/actors/core/ask_ut.cpp b/library/cpp/actors/core/ask_ut.cpp
new file mode 100644
index 0000000000..e72ebdba9b
--- /dev/null
+++ b/library/cpp/actors/core/ask_ut.cpp
@@ -0,0 +1,131 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "actorsystem.h"
+
+#include <library/cpp/actors/testlib/test_runtime.h>
+
+using namespace NActors;
+
+class TPingPong: public TActor<TPingPong> {
+public:
+ TPingPong()
+ : TActor(&TPingPong::Main)
+ {
+ }
+
+ STATEFN(Main) {
+ switch (ev->GetTypeRewrite()) {
+ hFunc(TEvents::TEvPing, OnPing);
+ hFunc(TEvents::TEvBlob, OnBlob);
+ }
+ }
+
+ void OnPing(const TEvents::TEvPing::TPtr& ev) {
+ Send(ev->Sender, new TEvents::TEvPong);
+ }
+
+ void OnBlob(const TEvents::TEvBlob::TPtr& ev) {
+ Send(ev->Sender, ev->Release().Release());
+ }
+};
+
+class TPing: public TActor<TPing> {
+public:
+ TPing()
+ : TActor(&TPing::Main)
+ {
+ }
+
+ STATEFN(Main) {
+ Y_UNUSED(ev);
+ }
+};
+
+THolder<TTestActorRuntimeBase> CreateRuntime() {
+ auto runtime = MakeHolder<TTestActorRuntimeBase>();
+ runtime->SetScheduledEventFilter([](auto&&, auto&&, auto&&, auto&&) { return false; });
+ runtime->Initialize();
+ return runtime;
+}
+
+Y_UNIT_TEST_SUITE(AskActor) {
+ Y_UNIT_TEST(Ok) {
+ auto runtime = CreateRuntime();
+ auto pingpong = runtime->Register(new TPingPong);
+
+ {
+ auto fut = runtime->GetAnyNodeActorSystem()->Ask<TEvents::TEvPong>(
+ pingpong,
+ THolder(new TEvents::TEvPing));
+ runtime->DispatchEvents();
+ fut.ExtractValueSync();
+ }
+
+ {
+ auto fut = runtime->GetAnyNodeActorSystem()->Ask<TEvents::TEvBlob>(
+ pingpong,
+ THolder(new TEvents::TEvBlob("hello!")));
+ runtime->DispatchEvents();
+ auto ev = fut.ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL(ev->Blob, "hello!");
+ }
+
+ {
+ auto fut = runtime->GetAnyNodeActorSystem()->Ask<IEventBase>(
+ pingpong,
+ THolder(new TEvents::TEvPing));
+ runtime->DispatchEvents();
+ auto ev = fut.ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL(ev->Type(), TEvents::TEvPong::EventType);
+ }
+ }
+
+ Y_UNIT_TEST(Err) {
+ auto runtime = CreateRuntime();
+ auto pingpong = runtime->Register(new TPingPong);
+
+ {
+ auto fut = runtime->GetAnyNodeActorSystem()->Ask<TEvents::TEvBlob>(
+ pingpong,
+ THolder(new TEvents::TEvPing));
+ runtime->DispatchEvents();
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ fut.ExtractValueSync(),
+ yexception,
+ "received unexpected response HelloWorld: Pong");
+ }
+ }
+
+ Y_UNIT_TEST(Timeout) {
+ auto runtime = CreateRuntime();
+ auto ping = runtime->Register(new TPing);
+
+ {
+ auto fut = runtime->GetAnyNodeActorSystem()->Ask<TEvents::TEvPong>(
+ ping,
+ THolder(new TEvents::TEvPing),
+ TDuration::Seconds(1));
+ auto start = runtime->GetCurrentTime();
+ runtime->DispatchEvents({}, TDuration::Seconds(5));
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ fut.ExtractValueSync(),
+ yexception,
+ "ask timeout");
+ UNIT_ASSERT_VALUES_EQUAL(runtime->GetCurrentTime() - start, TDuration::Seconds(1));
+ }
+
+ {
+ auto fut = runtime->GetAnyNodeActorSystem()->Ask<IEventBase>(
+ ping,
+ THolder(new TEvents::TEvPing),
+ TDuration::Seconds(1));
+ auto start = runtime->GetCurrentTime();
+ runtime->DispatchEvents({}, TDuration::Seconds(5));
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ fut.ExtractValueSync(),
+ yexception,
+ "ask timeout");
+ UNIT_ASSERT_VALUES_EQUAL(runtime->GetCurrentTime() - start, TDuration::Seconds(1));
+ }
+ }
+}
diff --git a/library/cpp/actors/core/balancer.cpp b/library/cpp/actors/core/balancer.cpp
new file mode 100644
index 0000000000..cc5417b0b5
--- /dev/null
+++ b/library/cpp/actors/core/balancer.cpp
@@ -0,0 +1,293 @@
+#include "balancer.h"
+
+#include "probes.h"
+
+#include <library/cpp/actors/util/intrinsics.h>
+#include <library/cpp/actors/util/datetime.h>
+
+#include <util/system/spinlock.h>
+
+#include <algorithm>
+
+namespace NActors {
+ LWTRACE_USING(ACTORLIB_PROVIDER);
+
+ // Describes balancing-related state of pool, the most notable is `Importance` to add new cpu
+ struct TLevel {
+ // Balancer will try to give more cpu to overloaded pools
+ enum ELoadClass {
+ Underloaded = 0,
+ Moderate = 1,
+ Overloaded = 2,
+ };
+
+ double ScaleFactor;
+ ELoadClass LoadClass;
+ ui64 Importance; // pool with lower importance is allowed to pass cpu to pool with higher, but the opposite is forbidden
+
+ TLevel() {}
+
+ TLevel(const TBalancingConfig& cfg, TPoolId poolId, ui64 currentCpus, double cpuIdle) {
+ ScaleFactor = double(currentCpus) / cfg.Cpus;
+ if (cpuIdle > 1.3) { // TODO: add a better underload criterion, based on estimated latency w/o 1 cpu
+ LoadClass = Underloaded;
+ } else if (cpuIdle < 0.2) { // TODO: add a better overload criterion, based on latency
+ LoadClass = Overloaded;
+ } else {
+ LoadClass = Moderate;
+ }
+ Importance = MakeImportance(LoadClass, cfg.Priority, ScaleFactor, cpuIdle, poolId);
+ }
+
+ private:
+ // Importance is simple ui64 value (from highest to lowest):
+ // 2 Bits: LoadClass
+ // 8 Bits: Priority
+ // 10 Bits: -ScaleFactor (for max-min fairness with weights equal to TBalancingConfig::Cpus)
+ // 10 Bits: -CpuIdle
+ // 6 Bits: PoolId
+ static ui64 MakeImportance(ELoadClass load, ui8 priority, double scaleFactor, double cpuIdle, TPoolId poolId) {
+ ui64 idle = std::clamp<i64>(1024 - cpuIdle * 512, 0, 1023);
+ ui64 scale = std::clamp<i64>(1024 - scaleFactor * 32, 0, 1023);
+
+ Y_VERIFY(ui64(load) < (1ull << 2ull));
+ Y_VERIFY(ui64(priority) < (1ull << 8ull));
+ Y_VERIFY(ui64(scale) < (1ull << 10ull));
+ Y_VERIFY(ui64(idle) < (1ull << 10ull));
+ Y_VERIFY(ui64(poolId) < (1ull << 6ull));
+
+ static_assert(ui64(MaxPools) <= (1ull << 6ull));
+
+ ui64 importance =
+ (ui64(load) << ui64(6 + 10 + 10 + 8)) |
+ (ui64(priority) << ui64(6 + 10 + 10)) |
+ (ui64(scale) << ui64(6 + 10)) |
+ (ui64(idle) << ui64(6)) |
+ ui64(poolId);
+ return importance;
+ }
+ };
+
+ // Main balancer implemenation
+ class TBalancer: public IBalancer {
+ private:
+ struct TCpu;
+ struct TPool;
+
+ bool Disabled = true;
+ TSpinLock Lock;
+ ui64 NextBalanceTs;
+ TVector<TCpu> Cpus; // Indexed by CpuId, can have gaps
+ TVector<TPool> Pools; // Indexed by PoolId, can have gaps
+ TBalancerConfig Config;
+
+ public:
+ // Setup
+ TBalancer(const TBalancerConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, ui64 ts);
+ bool AddCpu(const TCpuAllocation& cpuAlloc, TCpuState* cpu) override;
+ ~TBalancer();
+
+ // Balancing
+ bool TryLock(ui64 ts) override;
+ void SetPoolStats(TPoolId pool, const TBalancerStats& stats) override;
+ void Balance() override;
+ void Unlock() override;
+
+ private:
+ void MoveCpu(TPool& from, TPool& to);
+ };
+
+ struct TBalancer::TPool {
+ TBalancingConfig Config;
+ TPoolId PoolId;
+ TString PoolName;
+
+ // Input data for balancing
+ TBalancerStats Prev;
+ TBalancerStats Next;
+
+ // Derived stats
+ double CpuLoad;
+ double CpuIdle;
+
+ // Classification
+ // NOTE: We want to avoid passing cpu back and forth, so we must consider not only current level,
+ // NOTE: but expected levels after movements also
+ TLevel CurLevel; // Level with current amount of cpu
+ TLevel AddLevel; // Level after one cpu acception
+ TLevel SubLevel; // Level after one cpu donation
+
+ // Balancing state
+ ui64 CurrentCpus = 0; // Total number of cpus assigned for this pool (zero means pools is not balanced)
+ ui64 PrevCpus = 0; // Cpus in last period
+
+ explicit TPool(const TBalancingConfig& cfg = {})
+ : Config(cfg)
+ {}
+
+ void Configure(const TBalancingConfig& cfg, const TString& poolName) {
+ Config = cfg;
+ // Enforce constraints
+ Config.MinCpus = std::clamp<ui32>(Config.MinCpus, 1, Config.Cpus);
+ Config.MaxCpus = Max<ui32>(Config.MaxCpus, Config.Cpus);
+ PoolName = poolName;
+ }
+ };
+
+ struct TBalancer::TCpu {
+ TCpuState* State = nullptr; // Cpu state, nullptr means cpu is not used (gap)
+ TCpuAllocation Alloc;
+ TPoolId Current;
+ TPoolId Assigned;
+ };
+
+ TBalancer::TBalancer(const TBalancerConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, ui64 ts)
+ : NextBalanceTs(ts)
+ , Config(config)
+ {
+ for (TPoolId pool = 0; pool < MaxPools; pool++) {
+ Pools.emplace_back();
+ Pools.back().PoolId = pool;
+ }
+ for (const TUnitedExecutorPoolConfig& united : unitedPools) {
+ Pools[united.PoolId].Configure(united.Balancing, united.PoolName);
+ }
+ }
+
+ TBalancer::~TBalancer() {
+ }
+
+ bool TBalancer::AddCpu(const TCpuAllocation& cpuAlloc, TCpuState* state) {
+ // Setup
+ TCpuId cpuId = cpuAlloc.CpuId;
+ if (Cpus.size() <= cpuId) {
+ Cpus.resize(cpuId + 1);
+ }
+ TCpu& cpu = Cpus[cpuId];
+ cpu.State = state;
+ cpu.Alloc = cpuAlloc;
+
+ // Fill every pool with cpus up to TBalancingConfig::Cpus
+ TPoolId pool = 0;
+ for (TPool& p : Pools) {
+ if (p.CurrentCpus < p.Config.Cpus) {
+ p.CurrentCpus++;
+ break;
+ }
+ pool++;
+ }
+ if (pool != MaxPools) { // cpu under balancer control
+ state->SwitchPool(pool);
+ state->AssignPool(pool);
+ Disabled = false;
+ return true;
+ }
+ return false; // non-balanced cpu
+ }
+
+ bool TBalancer::TryLock(ui64 ts) {
+ if (!Disabled && NextBalanceTs < ts && Lock.TryAcquire()) {
+ NextBalanceTs = ts + Us2Ts(Config.PeriodUs);
+ return true;
+ }
+ return false;
+ }
+
+ void TBalancer::SetPoolStats(TPoolId pool, const TBalancerStats& stats) {
+ Y_VERIFY(pool < MaxPools);
+ TPool& p = Pools[pool];
+ p.Prev = p.Next;
+ p.Next = stats;
+ }
+
+ void TBalancer::Balance() {
+ // Update every cpu state
+ for (TCpu& cpu : Cpus) {
+ if (cpu.State) {
+ cpu.State->Load(cpu.Assigned, cpu.Current);
+ if (cpu.Current < MaxPools && cpu.Current != cpu.Assigned) {
+ return; // previous movement has not been applied yet, wait
+ }
+ }
+ }
+
+ // Process stats, classify and compute pool importance
+ TStackVec<TPool*, MaxPools> order;
+ for (TPool& pool : Pools) {
+ if (pool.Config.Cpus == 0) {
+ continue; // skip gaps (non-existent or non-united pools)
+ }
+ if (pool.Prev.Ts == 0 || pool.Prev.Ts >= pool.Next.Ts) {
+ return; // invalid stats
+ }
+
+ // Compute derived stats
+ pool.CpuLoad = (pool.Next.CpuUs - pool.Prev.CpuUs) / Ts2Us(pool.Next.Ts - pool.Prev.Ts);
+ if (pool.Prev.IdleUs == ui64(-1) || pool.Next.IdleUs == ui64(-1)) {
+ pool.CpuIdle = pool.CurrentCpus - pool.CpuLoad; // for tests
+ } else {
+ pool.CpuIdle = (pool.Next.IdleUs - pool.Prev.IdleUs) / Ts2Us(pool.Next.Ts - pool.Prev.Ts);
+ }
+
+ // Compute levels
+ pool.CurLevel = TLevel(pool.Config, pool.PoolId, pool.CurrentCpus, pool.CpuIdle);
+ pool.AddLevel = TLevel(pool.Config, pool.PoolId, pool.CurrentCpus + 1, pool.CpuIdle); // we expect taken cpu to became utilized
+ pool.SubLevel = TLevel(pool.Config, pool.PoolId, pool.CurrentCpus - 1, pool.CpuIdle - 1);
+
+ // Prepare for balancing
+ pool.PrevCpus = pool.CurrentCpus;
+ order.push_back(&pool);
+ }
+
+ // Sort pools by importance
+ std::sort(order.begin(), order.end(), [] (TPool* l, TPool* r) {return l->CurLevel.Importance < r->CurLevel.Importance; });
+ for (TPool* pool : order) {
+ LWPROBE(PoolStats, pool->PoolId, pool->PoolName, pool->CurrentCpus, pool->CurLevel.LoadClass, pool->Config.Priority, pool->CurLevel.ScaleFactor, pool->CpuIdle, pool->CpuLoad, pool->CurLevel.Importance, pool->AddLevel.Importance, pool->SubLevel.Importance);
+ }
+
+ // Move cpus from lower importance to higher importance pools
+ for (auto toIter = order.rbegin(); toIter != order.rend(); ++toIter) {
+ TPool& to = **toIter;
+ if (to.CurLevel.LoadClass == TLevel::Overloaded && // if pool is overloaded
+ to.CurrentCpus < to.Config.MaxCpus) // and constraints would not be violated
+ {
+ for (auto fromIter = order.begin(); (*fromIter)->CurLevel.Importance < to.CurLevel.Importance; ++fromIter) {
+ TPool& from = **fromIter;
+ if (from.CurrentCpus == from.PrevCpus && // if not balanced yet
+ from.CurrentCpus > from.Config.MinCpus && // and constraints would not be violated
+ from.SubLevel.Importance < to.AddLevel.Importance) // and which of two pools is more important would not change after cpu movement
+ {
+ MoveCpu(from, to);
+ from.CurrentCpus--;
+ to.CurrentCpus++;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ void TBalancer::MoveCpu(TBalancer::TPool& from, TBalancer::TPool& to) {
+ for (auto ci = Cpus.rbegin(), ce = Cpus.rend(); ci != ce; ci++) {
+ TCpu& cpu = *ci;
+ if (!cpu.State) {
+ continue;
+ }
+ if (cpu.Assigned == from.PoolId) {
+ cpu.State->AssignPool(to.PoolId);
+ cpu.Assigned = to.PoolId;
+ LWPROBE(MoveCpu, from.PoolId, to.PoolId, from.PoolName, to.PoolName, cpu.Alloc.CpuId);
+ return;
+ }
+ }
+ Y_FAIL();
+ }
+
+ void TBalancer::Unlock() {
+ Lock.Release();
+ }
+
+ IBalancer* MakeBalancer(const TBalancerConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, ui64 ts) {
+ return new TBalancer(config, unitedPools, ts);
+ }
+}
diff --git a/library/cpp/actors/core/balancer.h b/library/cpp/actors/core/balancer.h
new file mode 100644
index 0000000000..9763ec79e1
--- /dev/null
+++ b/library/cpp/actors/core/balancer.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "defs.h"
+#include "config.h"
+#include "cpu_state.h"
+
+namespace NActors {
+ // Per-pool statistics used by balancer
+ struct TBalancerStats {
+ ui64 Ts = 0; // Measurement timestamp
+ ui64 CpuUs = 0; // Total cpu microseconds consumed by pool on all cpus since start
+ ui64 IdleUs = ui64(-1); // Total cpu microseconds in spinning or waiting on futex
+ };
+
+ // Pool cpu balancer
+ struct IBalancer {
+ virtual ~IBalancer() {}
+ virtual bool AddCpu(const TCpuAllocation& cpuAlloc, TCpuState* cpu) = 0;
+ virtual bool TryLock(ui64 ts) = 0;
+ virtual void SetPoolStats(TPoolId pool, const TBalancerStats& stats) = 0;
+ virtual void Balance() = 0;
+ virtual void Unlock() = 0;
+ // TODO: add method for reconfiguration on fly
+ };
+
+ IBalancer* MakeBalancer(const TBalancerConfig& config, const TVector<TUnitedExecutorPoolConfig>& unitedPools, ui64 ts);
+}
diff --git a/library/cpp/actors/core/balancer_ut.cpp b/library/cpp/actors/core/balancer_ut.cpp
new file mode 100644
index 0000000000..7e5e95f4b9
--- /dev/null
+++ b/library/cpp/actors/core/balancer_ut.cpp
@@ -0,0 +1,225 @@
+#include "balancer.h"
+
+#include <library/cpp/actors/util/datetime.h>
+#include <library/cpp/lwtrace/all.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/str.h>
+
+using namespace NActors;
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_UNIT_TEST_SUITE(PoolCpuBalancer) {
+ struct TTest {
+ TCpuManagerConfig Config;
+ TCpuMask Available;
+ THolder<IBalancer> Balancer;
+ TVector<TCpuState> CpuStates;
+ TVector<ui64> CpuUs;
+ ui64 Now = 0;
+
+ void SetCpuCount(size_t count) {
+ Config.UnitedWorkers.CpuCount = count;
+ for (TCpuId cpuId = 0; cpuId < count; cpuId++) {
+ Available.Set(cpuId);
+ }
+ }
+
+ void AddPool(ui32 minCpus, ui32 cpus, ui32 maxCpus, ui8 priority = 0) {
+ TUnitedExecutorPoolConfig u;
+ u.PoolId = TPoolId(Config.United.size());
+ u.Balancing.Cpus = cpus;
+ u.Balancing.MinCpus = minCpus;
+ u.Balancing.MaxCpus = maxCpus;
+ u.Balancing.Priority = priority;
+ Config.United.push_back(u);
+ }
+
+ void Start() {
+ TCpuAllocationConfig allocation(Available, Config);
+ Balancer.Reset(MakeBalancer(Config.UnitedWorkers.Balancer, Config.United, 0));
+ CpuStates.resize(allocation.Items.size()); // do not resize it later to avoid dangling pointers
+ CpuUs.resize(CpuStates.size());
+ for (const TCpuAllocation& cpuAlloc : allocation.Items) {
+ bool added = Balancer->AddCpu(cpuAlloc, &CpuStates[cpuAlloc.CpuId]);
+ UNIT_ASSERT(added);
+ }
+ }
+
+ void Balance(ui64 deltaTs, const TVector<ui64>& cpuUs) {
+ Now += deltaTs;
+ ui64 ts = Now;
+ if (Balancer->TryLock(ts)) {
+ for (TPoolId pool = 0; pool < cpuUs.size(); pool++) {
+ CpuUs[pool] += cpuUs[pool];
+ TBalancerStats stats;
+ stats.Ts = ts;
+ stats.CpuUs = CpuUs[pool];
+ Balancer->SetPoolStats(pool, stats);
+ }
+ Balancer->Balance();
+ Balancer->Unlock();
+ }
+ }
+
+ void ApplyMovements() {
+ for (TCpuState& state : CpuStates) {
+ TPoolId current;
+ TPoolId assigned;
+ state.Load(assigned, current);
+ state.SwitchPool(assigned);
+ }
+ }
+
+ static TString ToStr(const TVector<ui64>& values) {
+ TStringStream ss;
+ ss << "{";
+ for (auto v : values) {
+ ss << " " << v;
+ }
+ ss << " }";
+ return ss.Str();
+ }
+
+ void AssertPoolsCurrentCpus(const TVector<ui64>& cpuRequired) {
+ TVector<ui64> cpuCurrent;
+ cpuCurrent.resize(cpuRequired.size());
+ for (TCpuState& state : CpuStates) {
+ TPoolId current;
+ TPoolId assigned;
+ state.Load(assigned, current);
+ cpuCurrent[current]++;
+ }
+ for (TPoolId pool = 0; pool < cpuRequired.size(); pool++) {
+ UNIT_ASSERT_C(cpuCurrent[pool] == cpuRequired[pool],
+ "cpu distribution mismatch, required " << ToStr(cpuRequired) << " but got " << ToStr(cpuCurrent));
+ }
+ }
+ };
+
+ Y_UNIT_TEST(StartLwtrace) {
+ NLWTrace::StartLwtraceFromEnv();
+ }
+
+ Y_UNIT_TEST(AllOverloaded) {
+ TTest t;
+ int cpus = 10;
+ t.SetCpuCount(cpus);
+ t.AddPool(1, 1, 10); // pool=0
+ t.AddPool(1, 2, 10); // pool=1
+ t.AddPool(1, 3, 10); // pool=2
+ t.AddPool(1, 4, 10); // pool=2
+ t.Start();
+ ui64 dts = 1.01 * Us2Ts(t.Config.UnitedWorkers.Balancer.PeriodUs);
+ ui64 totalCpuUs = cpus * Ts2Us(dts); // pretend every pool has consumed as whole actorsystem, overload
+ for (int i = 0; i < cpus; i++) {
+ t.Balance(dts, {totalCpuUs, totalCpuUs, totalCpuUs, totalCpuUs});
+ t.ApplyMovements();
+ }
+ t.AssertPoolsCurrentCpus({1, 2, 3, 4});
+ }
+
+ Y_UNIT_TEST(OneOverloaded) {
+ TTest t;
+ int cpus = 10;
+ t.SetCpuCount(cpus);
+ t.AddPool(1, 1, 10); // pool=0
+ t.AddPool(1, 2, 10); // pool=1
+ t.AddPool(1, 3, 10); // pool=2
+ t.AddPool(1, 4, 10); // pool=2
+ t.Start();
+ ui64 dts = 1.01 * Us2Ts(t.Config.UnitedWorkers.Balancer.PeriodUs);
+ ui64 totalCpuUs = cpus * Ts2Us(dts);
+ for (int i = 0; i < cpus; i++) {
+ t.Balance(dts, {totalCpuUs, 0, 0, 0});
+ t.ApplyMovements();
+ }
+ t.AssertPoolsCurrentCpus({7, 1, 1, 1});
+ for (int i = 0; i < cpus; i++) {
+ t.Balance(dts, {0, totalCpuUs, 0, 0});
+ t.ApplyMovements();
+ }
+ t.AssertPoolsCurrentCpus({1, 7, 1, 1});
+ for (int i = 0; i < cpus; i++) {
+ t.Balance(dts, {0, 0, totalCpuUs, 0});
+ t.ApplyMovements();
+ }
+ t.AssertPoolsCurrentCpus({1, 1, 7, 1});
+ for (int i = 0; i < cpus; i++) {
+ t.Balance(dts, {0, 0, 0, totalCpuUs});
+ t.ApplyMovements();
+ }
+ t.AssertPoolsCurrentCpus({1, 1, 1, 7});
+ }
+
+ Y_UNIT_TEST(TwoOverloadedFairness) {
+ TTest t;
+ int cpus = 10;
+ t.SetCpuCount(cpus);
+ t.AddPool(1, 1, 10); // pool=0
+ t.AddPool(1, 2, 10); // pool=1
+ t.AddPool(1, 3, 10); // pool=2
+ t.AddPool(1, 4, 10); // pool=2
+ t.Start();
+ ui64 dts = 1.01 * Us2Ts(t.Config.UnitedWorkers.Balancer.PeriodUs);
+ ui64 totalCpuUs = cpus * Ts2Us(dts);
+ for (int i = 0; i < cpus; i++) {
+ t.Balance(dts, {totalCpuUs, totalCpuUs, 0, 0});
+ t.ApplyMovements();
+ }
+ t.AssertPoolsCurrentCpus({3, 5, 1, 1});
+ for (int i = 0; i < cpus; i++) {
+ t.Balance(dts, {totalCpuUs, 0, totalCpuUs, 0});
+ t.ApplyMovements();
+ }
+ t.AssertPoolsCurrentCpus({2, 1, 6, 1});
+ for (int i = 0; i < cpus; i++) {
+ t.Balance(dts, {totalCpuUs, 0, 0, totalCpuUs});
+ t.ApplyMovements();
+ }
+ t.AssertPoolsCurrentCpus({2, 1, 1, 6});
+ for (int i = 0; i < cpus; i++) {
+ t.Balance(dts, {0, totalCpuUs, totalCpuUs, 0});
+ t.ApplyMovements();
+ }
+ t.AssertPoolsCurrentCpus({1, 3, 5, 1});
+ for (int i = 0; i < cpus; i++) {
+ t.Balance(dts, {0, totalCpuUs, 0, totalCpuUs});
+ t.ApplyMovements();
+ }
+ t.AssertPoolsCurrentCpus({1, 3, 1, 5});
+ for (int i = 0; i < cpus; i++) {
+ t.Balance(dts, {0, 0, totalCpuUs, totalCpuUs});
+ t.ApplyMovements();
+ }
+ t.AssertPoolsCurrentCpus({1, 1, 3, 5});
+ }
+
+ Y_UNIT_TEST(TwoOverloadedPriority) {
+ TTest t;
+ int cpus = 20;
+ t.SetCpuCount(cpus);
+ t.AddPool(1, 5, 20, 0); // pool=0
+ t.AddPool(1, 5, 20, 1); // pool=1
+ t.AddPool(1, 5, 20, 2); // pool=2
+ t.AddPool(1, 5, 20, 3); // pool=3
+ t.Start();
+ ui64 dts = 1.01 * Us2Ts(t.Config.UnitedWorkers.Balancer.PeriodUs);
+ ui64 mErlang = Ts2Us(dts) / 1000;
+ for (int i = 0; i < cpus; i++) {
+ t.Balance(dts, {20000 * mErlang, 2500 * mErlang, 4500 * mErlang, 9500 * mErlang});
+ t.ApplyMovements();
+ }
+ t.AssertPoolsCurrentCpus({2, 3, 5, 10});
+ t.Balance(dts, {20000 * mErlang, 2500 * mErlang, 4500 * mErlang, 8500 * mErlang});
+ t.ApplyMovements();
+ t.AssertPoolsCurrentCpus({3, 3, 5, 9});
+ // NOTE: this operation require one move, but we do not make global analysis, so multiple steps (1->2 & 0->1) are required (can be optimized later)
+ for (int i = 0; i < 3; i++) {
+ t.Balance(dts, {20000 * mErlang, 2500 * mErlang, 5500 * mErlang, 8500 * mErlang});
+ t.ApplyMovements();
+ }
+ t.AssertPoolsCurrentCpus({2, 3, 6, 9});
+ }
+}
diff --git a/library/cpp/actors/core/buffer.cpp b/library/cpp/actors/core/buffer.cpp
new file mode 100644
index 0000000000..48128d76ef
--- /dev/null
+++ b/library/cpp/actors/core/buffer.cpp
@@ -0,0 +1,93 @@
+#include "buffer.h"
+
+#include <util/system/yassert.h>
+
+#include <algorithm>
+
+TBufferBase::TBufferBase(size_t size) noexcept
+ : Size(size)
+{
+}
+
+size_t
+TBufferBase::GetSize() const noexcept {
+ return Size;
+}
+
+void TBufferBase::SetSize(size_t size) noexcept {
+ Size = size;
+}
+
+/////////////////////////////////////////////////////////////////////
+
+template <typename PointerType>
+TBufferBaseT<PointerType>::TBufferBaseT(PointerType data, size_t size) noexcept
+ : TBufferBase(size)
+ , Data(data)
+{
+}
+
+template <typename PointerType>
+PointerType
+TBufferBaseT<PointerType>::GetPointer() const noexcept {
+ return Data;
+}
+
+template <typename PointerType>
+void TBufferBaseT<PointerType>::Assign(PointerType data, size_t size) noexcept {
+ Data = data;
+ Size = size;
+}
+
+template <>
+void TBufferBaseT<void*>::Cut(size_t offset) noexcept {
+ Y_VERIFY_DEBUG(offset <= Size);
+ Data = static_cast<char*>(Data) + offset;
+ TBufferBase::Size -= offset;
+}
+
+template <>
+void TBufferBaseT<const void*>::Cut(size_t offset) noexcept {
+ Y_VERIFY_DEBUG(offset <= Size);
+ Data = static_cast<const char*>(Data) + offset;
+ TBufferBase::Size -= offset;
+}
+
+template class TBufferBaseT<void*>;
+template class TBufferBaseT<const void*>;
+
+/////////////////////////////////////////////////////////////////////
+
+TConstBuffer::TConstBuffer(const void* data, size_t size) noexcept
+ : TBufferBaseT<const void*>(data, size)
+{
+}
+
+TConstBuffer::TConstBuffer(const TMutableBuffer& buffer) noexcept
+ : TBufferBaseT<const void*>(buffer.GetPointer(), buffer.GetSize())
+{
+}
+
+TConstBuffer
+TConstBuffer::Offset(ptrdiff_t offset, size_t size) const noexcept {
+ return TConstBuffer(static_cast<const char*>(Data) + offset, std::min(Size - offset, size));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+TMutableBuffer::TMutableBuffer(void* data, size_t size) noexcept
+ : TBufferBaseT<void*>(data, size)
+{
+}
+
+TMutableBuffer
+TMutableBuffer::Offset(ptrdiff_t offset, size_t size) const noexcept {
+ return TMutableBuffer(static_cast<char*>(Data) + offset, std::min(Size - offset, size));
+}
+
+size_t
+TMutableBuffer::CopyFrom(const TConstBuffer& buffer) const noexcept {
+ const auto size = std::min(Size, buffer.Size);
+ std::memcpy(Data, buffer.Data, size);
+ return size;
+}
diff --git a/library/cpp/actors/core/buffer.h b/library/cpp/actors/core/buffer.h
new file mode 100644
index 0000000000..95425046d6
--- /dev/null
+++ b/library/cpp/actors/core/buffer.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include <limits>
+
+class TConstBuffer;
+class TMutableBuffer;
+
+class TBufferBase {
+public:
+ size_t GetSize() const noexcept;
+
+ void SetSize(size_t newSize) noexcept;
+
+protected:
+ TBufferBase(size_t size = 0) noexcept;
+
+ size_t Size;
+};
+
+template <typename PointerType>
+class TBufferBaseT: public TBufferBase {
+public:
+ PointerType GetPointer() const noexcept;
+
+ void Cut(size_t offset) noexcept;
+
+ void Assign(PointerType data = nullptr, size_t size = 0U) noexcept;
+
+protected:
+ TBufferBaseT(PointerType data, size_t size) noexcept;
+
+ PointerType Data;
+};
+
+/// Represents constant memory buffer, but do not owns it.
+class TConstBuffer: public TBufferBaseT<const void*> {
+ friend class TMutableBuffer;
+
+public:
+ TConstBuffer(const TMutableBuffer& buffer) noexcept;
+
+ TConstBuffer(const void* data = nullptr, size_t size = 0U) noexcept;
+
+ TConstBuffer Offset(ptrdiff_t offset, size_t size = std::numeric_limits<size_t>::max()) const noexcept;
+};
+
+/// Represents mutable memory buffer, but do not owns it.
+class TMutableBuffer: public TBufferBaseT<void*> {
+ friend class TConstBuffer;
+
+public:
+ TMutableBuffer(void* data = nullptr, size_t size = 0U) noexcept;
+
+ TMutableBuffer(const TMutableBuffer& value) noexcept
+ : TBufferBaseT<void*>(value)
+ {
+ }
+
+ TMutableBuffer Offset(ptrdiff_t offset, size_t size = std::numeric_limits<size_t>::max()) const noexcept;
+
+ size_t CopyFrom(const TConstBuffer& buffer) const noexcept;
+};
diff --git a/library/cpp/actors/core/callstack.cpp b/library/cpp/actors/core/callstack.cpp
new file mode 100644
index 0000000000..9297c1a079
--- /dev/null
+++ b/library/cpp/actors/core/callstack.cpp
@@ -0,0 +1,93 @@
+#include "callstack.h"
+#include <util/thread/singleton.h>
+
+#ifdef USE_ACTOR_CALLSTACK
+
+namespace NActors {
+ namespace {
+ void (*PreviousFormatBackTrace)(IOutputStream*) = 0;
+ ui32 ActorBackTraceEnableCounter = 0;
+ }
+
+ void ActorFormatBackTrace(IOutputStream* out) {
+ TStringStream str;
+ PreviousFormatBackTrace(&str);
+ str << Endl;
+ TCallstack::DumpCallstack(str);
+ *out << str.Str();
+ }
+
+ void EnableActorCallstack() {
+ if (ActorBackTraceEnableCounter == 0) {
+ Y_VERIFY(PreviousFormatBackTrace == 0);
+ PreviousFormatBackTrace = SetFormatBackTraceFn(ActorFormatBackTrace);
+ }
+
+ ++ActorBackTraceEnableCounter;
+ }
+
+ void DisableActorCallstack() {
+ --ActorBackTraceEnableCounter;
+
+ if (ActorBackTraceEnableCounter == 0) {
+ Y_VERIFY(PreviousFormatBackTrace);
+ SetFormatBackTraceFn(PreviousFormatBackTrace);
+ PreviousFormatBackTrace = 0;
+ }
+ }
+
+ TCallstack::TCallstack()
+ : BeginIdx(0)
+ , Size(0)
+ , LinesToSkip(0)
+ {
+ }
+
+ void TCallstack::SetLinesToSkip() {
+ TTrace record;
+ LinesToSkip = BackTrace(record.Data, TTrace::CAPACITY);
+ }
+
+ void TCallstack::Trace() {
+ size_t currentIdx = (BeginIdx + Size) % RECORDS;
+ if (Size == RECORDS) {
+ ++BeginIdx;
+ } else {
+ ++Size;
+ }
+ TTrace& record = Record[currentIdx];
+ record.Size = BackTrace(record.Data, TTrace::CAPACITY);
+ record.LinesToSkip = LinesToSkip;
+ }
+
+ void TCallstack::TraceIfEmpty() {
+ if (Size == 0) {
+ LinesToSkip = 0;
+ Trace();
+ }
+ }
+
+ TCallstack& TCallstack::GetTlsCallstack() {
+ return *FastTlsSingleton<TCallstack>();
+ }
+
+ void TCallstack::DumpCallstack(TStringStream& str) {
+ TCallstack& callstack = GetTlsCallstack();
+ for (int i = callstack.Size - 1; i >= 0; --i) {
+ TTrace& record = callstack.Record[(callstack.BeginIdx + i) % RECORDS];
+ str << Endl << "Trace entry " << i << Endl << Endl;
+ size_t size = record.Size;
+ if (size > record.LinesToSkip && size < TTrace::CAPACITY) {
+ size -= record.LinesToSkip;
+ }
+ if (size > RECORDS_TO_SKIP) {
+ FormatBackTrace(&str, &record.Data[RECORDS_TO_SKIP], size - RECORDS_TO_SKIP);
+ } else {
+ FormatBackTrace(&str, record.Data, size);
+ }
+ str << Endl;
+ }
+ }
+}
+
+#endif
diff --git a/library/cpp/actors/core/callstack.h b/library/cpp/actors/core/callstack.h
new file mode 100644
index 0000000000..176717d2ae
--- /dev/null
+++ b/library/cpp/actors/core/callstack.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#ifndef NDEBUG
+//#define ENABLE_ACTOR_CALLSTACK
+#endif
+
+#ifdef ENABLE_ACTOR_CALLSTACK
+#include "defs.h"
+#include <util/system/backtrace.h>
+#include <util/stream/str.h>
+#include <util/generic/deque.h>
+#define USE_ACTOR_CALLSTACK
+
+namespace NActors {
+ struct TCallstack {
+ struct TTrace {
+ static const size_t CAPACITY = 50;
+ void* Data[CAPACITY];
+ size_t Size;
+ size_t LinesToSkip;
+
+ TTrace()
+ : Size(0)
+ , LinesToSkip(0)
+ {
+ }
+ };
+
+ static const size_t RECORDS = 8;
+ static const size_t RECORDS_TO_SKIP = 2;
+ TTrace Record[RECORDS];
+ size_t BeginIdx;
+ size_t Size;
+ size_t LinesToSkip;
+
+ TCallstack();
+ void SetLinesToSkip();
+ void Trace();
+ void TraceIfEmpty();
+ static TCallstack& GetTlsCallstack();
+ static void DumpCallstack(TStringStream& str);
+ };
+
+ void EnableActorCallstack();
+ void DisableActorCallstack();
+
+}
+
+#else
+
+namespace NActors {
+ inline void EnableActorCallstack(){};
+
+ inline void DisableActorCallstack(){};
+
+}
+
+#endif
diff --git a/library/cpp/actors/core/config.h b/library/cpp/actors/core/config.h
new file mode 100644
index 0000000000..2486bf4c43
--- /dev/null
+++ b/library/cpp/actors/core/config.h
@@ -0,0 +1,239 @@
+#pragma once
+
+#include "defs.h"
+#include <library/cpp/actors/util/cpumask.h>
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+#include <util/datetime/base.h>
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+
+namespace NActors {
+
+ struct TBalancingConfig {
+ // Default cpu count (used during overload). Zero value disables this pool balancing
+ // 1) Sum of `Cpus` on all pools cannot be changed without restart
+ // (changing cpu mode between Shared and Assigned is not implemented yet)
+ // 2) This sum must be equal to TUnitedWorkersConfig::CpuCount,
+ // otherwise `CpuCount - SUM(Cpus)` cpus will be in Shared mode (i.e. actorsystem 2.0)
+ ui32 Cpus = 0;
+
+ ui32 MinCpus = 0; // Lower balancing bound, should be at least 1, and not greater than `Cpus`
+ ui32 MaxCpus = 0; // Higher balancing bound, should be not lower than `Cpus`
+ ui8 Priority = 0; // Priority of pool to obtain cpu due to balancing (higher is better)
+ ui64 ToleratedLatencyUs = 0; // p100-latency threshold indicating that more cpus are required by pool
+ };
+
+ struct TBalancerConfig {
+ ui64 PeriodUs = 15000000; // Time between balancer steps
+ };
+
+ struct TBasicExecutorPoolConfig {
+ static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = TDuration::MilliSeconds(10);
+ static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = 100;
+
+ ui32 PoolId = 0;
+ TString PoolName;
+ ui32 Threads = 1;
+ ui64 SpinThreshold = 100;
+ TCpuMask Affinity; // Executor thread affinity
+ TDuration TimePerMailbox = DEFAULT_TIME_PER_MAILBOX;
+ ui32 EventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX;
+ int RealtimePriority = 0;
+ ui32 MaxActivityType = 1;
+ };
+
+ struct TIOExecutorPoolConfig {
+ ui32 PoolId = 0;
+ TString PoolName;
+ ui32 Threads = 1;
+ TCpuMask Affinity; // Executor thread affinity
+ ui32 MaxActivityType = 1;
+ };
+
+ struct TUnitedExecutorPoolConfig {
+ static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = TDuration::MilliSeconds(10);
+ static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = 100;
+
+ ui32 PoolId = 0;
+ TString PoolName;
+
+ // Resource sharing
+ ui32 Concurrency = 0; // Limits simultaneously running mailboxes count if set to non-zero value (do not set if Balancing.Cpus != 0)
+ TPoolWeight Weight = 0; // Weight in fair cpu-local pool scheduler
+ TCpuMask Allowed; // Allowed CPUs for workers to run this pool on (ignored if balancer works, i.e. actorsystem 1.5)
+
+ // Single mailbox execution limits
+ TDuration TimePerMailbox = DEFAULT_TIME_PER_MAILBOX;
+ ui32 EventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX;
+
+ // Introspection
+ ui32 MaxActivityType = 1;
+
+ // Long-term balancing
+ TBalancingConfig Balancing;
+ };
+
+ struct TUnitedWorkersConfig {
+ ui32 CpuCount = 0; // Total CPUs running united workers (i.e. TBasicExecutorPoolConfig::Threads analog); set to zero to disable united workers
+ ui64 SpinThresholdUs = 100; // Limit for active spinning in case all pools became idle
+ ui64 PoolLimitUs = 500; // Soft limit on pool execution
+ ui64 EventLimitUs = 100; // Hard limit on last event execution exceeding pool limit
+ ui64 LimitPrecisionUs = 100; // Maximum delay of timer on limit excess (delay needed to avoid settimer syscall on every pool switch)
+ ui64 FastWorkerPriority = 10; // Real-time priority of workers not exceeding hard limits
+ ui64 IdleWorkerPriority = 20; // Real-time priority of standby workers waiting for hard preemption on timers (should be greater than FastWorkerPriority)
+ TCpuMask Allowed; // Allowed CPUs for workers to run on (every worker has affinity for exactly one cpu)
+ bool NoRealtime = false; // For environments w/o permissions for RT-threads
+ bool NoAffinity = false; // For environments w/o permissions for cpu affinity
+ TBalancerConfig Balancer;
+ };
+
+ struct TCpuManagerConfig {
+ TUnitedWorkersConfig UnitedWorkers;
+ TVector<TBasicExecutorPoolConfig> Basic;
+ TVector<TIOExecutorPoolConfig> IO;
+ TVector<TUnitedExecutorPoolConfig> United;
+
+ ui32 GetExecutorsCount() const {
+ return Basic.size() + IO.size() + United.size();
+ }
+
+ TString GetPoolName(ui32 poolId) const {
+ for (const auto& p : Basic) {
+ if (p.PoolId == poolId) {
+ return p.PoolName;
+ }
+ }
+ for (const auto& p : IO) {
+ if (p.PoolId == poolId) {
+ return p.PoolName;
+ }
+ }
+ for (const auto& p : United) {
+ if (p.PoolId == poolId) {
+ return p.PoolName;
+ }
+ }
+ Y_FAIL("undefined pool id: %" PRIu32, (ui32)poolId);
+ }
+
+ ui32 GetThreads(ui32 poolId) const {
+ for (const auto& p : Basic) {
+ if (p.PoolId == poolId) {
+ return p.Threads;
+ }
+ }
+ for (const auto& p : IO) {
+ if (p.PoolId == poolId) {
+ return p.Threads;
+ }
+ }
+ for (const auto& p : United) {
+ if (p.PoolId == poolId) {
+ return p.Concurrency ? p.Concurrency : UnitedWorkers.CpuCount;
+ }
+ }
+ Y_FAIL("undefined pool id: %" PRIu32, (ui32)poolId);
+ }
+ };
+
+ struct TSchedulerConfig {
+ TSchedulerConfig(
+ ui64 resolution = 1024,
+ ui64 spinThreshold = 100,
+ ui64 progress = 10000,
+ bool useSchedulerActor = false)
+ : ResolutionMicroseconds(resolution)
+ , SpinThreshold(spinThreshold)
+ , ProgressThreshold(progress)
+ , UseSchedulerActor(useSchedulerActor)
+ {}
+
+ ui64 ResolutionMicroseconds = 1024;
+ ui64 SpinThreshold = 100;
+ ui64 ProgressThreshold = 10000;
+ bool UseSchedulerActor = false; // False is default because tests use scheduler thread
+ ui64 RelaxedSendPaceEventsPerSecond = 200000;
+ ui64 RelaxedSendPaceEventsPerCycle = RelaxedSendPaceEventsPerSecond * ResolutionMicroseconds / 1000000;
+ // For resolution >= 250000 microseconds threshold is SendPace
+ // For resolution <= 250 microseconds threshold is 20 * SendPace
+ ui64 RelaxedSendThresholdEventsPerSecond = RelaxedSendPaceEventsPerSecond *
+ (20 - ((20 - 1) * ClampVal(ResolutionMicroseconds, ui64(250), ui64(250000)) - 250) / (250000 - 250));
+ ui64 RelaxedSendThresholdEventsPerCycle = RelaxedSendThresholdEventsPerSecond * ResolutionMicroseconds / 1000000;
+
+ // Optional subsection for scheduler counters (usually subsystem=utils)
+ NMonitoring::TDynamicCounterPtr MonCounters = nullptr;
+ };
+
+ struct TCpuAllocation {
+ struct TPoolAllocation {
+ TPoolId PoolId;
+ TPoolWeight Weight;
+
+ TPoolAllocation(TPoolId poolId = 0, TPoolWeight weight = 0)
+ : PoolId(poolId)
+ , Weight(weight)
+ {}
+ };
+
+ TCpuId CpuId;
+ TVector<TPoolAllocation> AllowedPools;
+
+ TPoolsMask GetPoolsMask() const {
+ TPoolsMask mask = 0;
+ for (const auto& pa : AllowedPools) {
+ if (pa.PoolId < MaxPools) {
+ mask &= (1ull << pa.PoolId);
+ }
+ }
+ return mask;
+ }
+
+ bool HasPool(TPoolId pool) const {
+ for (const auto& pa : AllowedPools) {
+ if (pa.PoolId == pool) {
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ struct TCpuAllocationConfig {
+ TVector<TCpuAllocation> Items;
+
+ TCpuAllocationConfig(const TCpuMask& available, const TCpuManagerConfig& cfg) {
+ for (const TUnitedExecutorPoolConfig& pool : cfg.United) {
+ Y_VERIFY(pool.PoolId < MaxPools, "wrong PoolId of united executor pool: %s(%d)",
+ pool.PoolName.c_str(), (pool.PoolId));
+ }
+ ui32 allocated[MaxPools] = {0};
+ for (TCpuId cpu = 0; cpu < available.Size() && Items.size() < cfg.UnitedWorkers.CpuCount; cpu++) {
+ if (available.IsSet(cpu)) {
+ TCpuAllocation item;
+ item.CpuId = cpu;
+ for (const TUnitedExecutorPoolConfig& pool : cfg.United) {
+ if (cfg.UnitedWorkers.Allowed.IsEmpty() || cfg.UnitedWorkers.Allowed.IsSet(cpu)) {
+ if (pool.Allowed.IsEmpty() || pool.Allowed.IsSet(cpu)) {
+ item.AllowedPools.emplace_back(pool.PoolId, pool.Weight);
+ allocated[pool.PoolId]++;
+ }
+ }
+ }
+ if (!item.AllowedPools.empty()) {
+ Items.push_back(item);
+ }
+ }
+ }
+ for (const TUnitedExecutorPoolConfig& pool : cfg.United) {
+ Y_VERIFY(allocated[pool.PoolId] > 0, "unable to allocate cpu for united executor pool: %s(%d)",
+ pool.PoolName.c_str(), (pool.PoolId));
+ }
+ }
+
+ operator bool() const {
+ return !Items.empty();
+ }
+ };
+
+}
diff --git a/library/cpp/actors/core/cpu_manager.cpp b/library/cpp/actors/core/cpu_manager.cpp
new file mode 100644
index 0000000000..39089b5d83
--- /dev/null
+++ b/library/cpp/actors/core/cpu_manager.cpp
@@ -0,0 +1,108 @@
+#include "cpu_manager.h"
+#include "probes.h"
+
+namespace NActors {
+ LWTRACE_USING(ACTORLIB_PROVIDER);
+
+ void TCpuManager::Setup() {
+ TAffinity available;
+ available.Current();
+ TCpuAllocationConfig allocation(available, Config);
+
+ if (allocation) {
+ if (!Balancer) {
+ Balancer.Reset(MakeBalancer(Config.UnitedWorkers.Balancer, Config.United, GetCycleCountFast()));
+ }
+ UnitedWorkers.Reset(new TUnitedWorkers(Config.UnitedWorkers, Config.United, allocation, Balancer.Get()));
+ }
+
+ Executors.Reset(new TAutoPtr<IExecutorPool>[ExecutorPoolCount]);
+
+ for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) {
+ Executors[excIdx].Reset(CreateExecutorPool(excIdx));
+ }
+ }
+
+ void TCpuManager::PrepareStart(TVector<NSchedulerQueue::TReader*>& scheduleReaders, TActorSystem* actorSystem) {
+ if (UnitedWorkers) {
+ UnitedWorkers->Prepare(actorSystem, scheduleReaders);
+ }
+ for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) {
+ NSchedulerQueue::TReader* readers;
+ ui32 readersCount = 0;
+ Executors[excIdx]->Prepare(actorSystem, &readers, &readersCount);
+ for (ui32 i = 0; i != readersCount; ++i, ++readers) {
+ scheduleReaders.push_back(readers);
+ }
+ }
+ }
+
+ void TCpuManager::Start() {
+ if (UnitedWorkers) {
+ UnitedWorkers->Start();
+ }
+ for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) {
+ Executors[excIdx]->Start();
+ }
+ }
+
+ void TCpuManager::PrepareStop() {
+ for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) {
+ Executors[excIdx]->PrepareStop();
+ }
+ if (UnitedWorkers) {
+ UnitedWorkers->PrepareStop();
+ }
+ }
+
+ void TCpuManager::Shutdown() {
+ for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) {
+ Executors[excIdx]->Shutdown();
+ }
+ if (UnitedWorkers) {
+ UnitedWorkers->Shutdown();
+ }
+ for (ui32 round = 0, done = 0; done < ExecutorPoolCount && round < 3; ++round) {
+ done = 0;
+ for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) {
+ if (Executors[excIdx]->Cleanup()) {
+ ++done;
+ }
+ }
+ }
+ }
+
+ void TCpuManager::Cleanup() {
+ for (ui32 round = 0, done = 0; done < ExecutorPoolCount; ++round) {
+ Y_VERIFY(round < 10, "actorsystem cleanup could not be completed in 10 rounds");
+ done = 0;
+ for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) {
+ if (Executors[excIdx]->Cleanup()) {
+ ++done;
+ }
+ }
+ }
+ Executors.Destroy();
+ UnitedWorkers.Destroy();
+ }
+
+ IExecutorPool* TCpuManager::CreateExecutorPool(ui32 poolId) {
+ for (TBasicExecutorPoolConfig& cfg : Config.Basic) {
+ if (cfg.PoolId == poolId) {
+ return new TBasicExecutorPool(cfg);
+ }
+ }
+ for (TIOExecutorPoolConfig& cfg : Config.IO) {
+ if (cfg.PoolId == poolId) {
+ return new TIOExecutorPool(cfg);
+ }
+ }
+ for (TUnitedExecutorPoolConfig& cfg : Config.United) {
+ if (cfg.PoolId == poolId) {
+ IExecutorPool* result = new TUnitedExecutorPool(cfg, UnitedWorkers.Get());
+ return result;
+ }
+ }
+ Y_FAIL("missing PoolId: %d", int(poolId));
+ }
+}
diff --git a/library/cpp/actors/core/cpu_manager.h b/library/cpp/actors/core/cpu_manager.h
new file mode 100644
index 0000000000..454035477b
--- /dev/null
+++ b/library/cpp/actors/core/cpu_manager.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#include "actorsystem.h"
+#include "executor_pool_basic.h"
+#include "executor_pool_io.h"
+#include "executor_pool_united.h"
+
+namespace NActors {
+ class TCpuManager : public TNonCopyable {
+ const ui32 ExecutorPoolCount;
+ TArrayHolder<TAutoPtr<IExecutorPool>> Executors;
+ THolder<TUnitedWorkers> UnitedWorkers;
+ THolder<IBalancer> Balancer;
+ TCpuManagerConfig Config;
+ public:
+ explicit TCpuManager(THolder<TActorSystemSetup>& setup)
+ : ExecutorPoolCount(setup->GetExecutorsCount())
+ , Balancer(setup->Balancer)
+ , Config(setup->CpuManager)
+ {
+ if (setup->Executors) { // Explicit mode w/o united pools
+ Executors.Reset(setup->Executors.Release());
+ for (ui32 excIdx = 0; excIdx != ExecutorPoolCount; ++excIdx) {
+ IExecutorPool* pool = Executors[excIdx].Get();
+ Y_VERIFY(dynamic_cast<TUnitedExecutorPool*>(pool) == nullptr,
+ "united executor pool is prohibited in explicit mode of NActors::TCpuManager");
+ }
+ } else {
+ Setup();
+ }
+ }
+
+ void Setup();
+ void PrepareStart(TVector<NSchedulerQueue::TReader*>& scheduleReaders, TActorSystem* actorSystem);
+ void Start();
+ void PrepareStop();
+ void Shutdown();
+ void Cleanup();
+
+ ui32 GetExecutorsCount() const {
+ return ExecutorPoolCount;
+ }
+
+ IExecutorPool* GetExecutorPool(ui32 poolId) {
+ return Executors[poolId].Get();
+ }
+
+ void GetPoolStats(ui32 poolId, TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const {
+ if (poolId < ExecutorPoolCount) {
+ Executors[poolId]->GetCurrentStats(poolStats, statsCopy);
+ }
+ }
+
+ private:
+ IExecutorPool* CreateExecutorPool(ui32 poolId);
+ };
+}
diff --git a/library/cpp/actors/core/cpu_state.h b/library/cpp/actors/core/cpu_state.h
new file mode 100644
index 0000000000..b8030149a7
--- /dev/null
+++ b/library/cpp/actors/core/cpu_state.h
@@ -0,0 +1,215 @@
+#pragma once
+
+#include "defs.h"
+
+#include <library/cpp/actors/util/futex.h>
+
+namespace NActors {
+
+ class alignas(64) TCpuState {
+ // Atomic cachelign-aligned 64-bit state, see description below
+ TAtomic State = 0;
+ char Padding[64 - sizeof(TAtomic)];
+
+ // Bits 0-31: Currently executing pool
+ // - value less than MaxPools means cpu is executing corresponding pool (fast-worker is executing or waiting for slow-workers)
+ // - one of Cpu* values in case of idle cpu
+ // - used as futex by blocked fast-worker
+ static constexpr ui64 CurrentBits = 32;
+ static constexpr ui64 CurrentMask = ui64((1ull << CurrentBits) - 1);
+
+ // Bits 32-63: Assigned pool
+ // - value is set by balancer
+ // - NOT used as futex
+ // - Not balanced
+ static constexpr ui64 AssignedOffs = 32;
+ static constexpr ui64 AssignedMask = ~CurrentMask;
+
+ public:
+ TCpuState() {
+ Y_UNUSED(Padding);
+ }
+
+ void Load(TPoolId& assigned, TPoolId& current) const {
+ TAtomicBase state = AtomicLoad(&State);
+ assigned = (state & AssignedMask) >> AssignedOffs;
+ current = state & CurrentMask;
+ }
+
+ TPoolId CurrentPool() const {
+ return TPoolId(AtomicLoad(&State) & CurrentMask);
+ }
+
+ void SwitchPool(TPoolId pool) {
+ while (true) {
+ TAtomicBase state = AtomicLoad(&State);
+ if (AtomicCas(&State, (state & ~CurrentMask) | pool, state)) {
+ return;
+ }
+ }
+ }
+
+ TPoolId AssignedPool() const {
+ return TPoolId((AtomicLoad(&State) & AssignedMask) >> AssignedOffs);
+ }
+
+ // Assigns new pool to cpu and wakes it up if cpu is idle
+ void AssignPool(TPoolId pool) {
+ while (true) {
+ TAtomicBase state = AtomicLoad(&State);
+ TPoolId current(state & CurrentMask);
+ if (Y_UNLIKELY(current == CpuStopped)) {
+ return; // it would be better to shutdown instead of balancing
+ }
+ // Idle cpu must be woken up after balancing to handle pending tokens (if any) in assigned/schedulable pool(s)
+ if (current == CpuSpinning) {
+ if (AtomicCas(&State, (ui64(pool) << AssignedOffs) | pool, state)) {
+ return; // successfully woken up
+ }
+ } else if (current == CpuBlocked) {
+ if (AtomicCas(&State, (ui64(pool) << AssignedOffs) | pool, state)) {
+ FutexWake();
+ return; // successfully woken up
+ }
+ } else {
+ if (AtomicCas(&State, (ui64(pool) << AssignedOffs) | (state & ~AssignedMask), state)) {
+ return; // wakeup is not required
+ }
+ }
+ }
+ }
+
+ void Stop() {
+ while (true) {
+ TAtomicBase state = AtomicLoad(&State);
+ if (AtomicCas(&State, (state & ~CurrentMask) | CpuStopped, state)) {
+ FutexWake();
+ return; // successfully stopped
+ }
+ }
+ }
+
+ // Start waiting, returns false in case of actorsystem shutdown
+ bool StartSpinning() {
+ while (true) {
+ TAtomicBase state = AtomicLoad(&State);
+ TPoolId current(state & CurrentMask);
+ if (Y_UNLIKELY(current == CpuStopped)) {
+ return false;
+ }
+ Y_VERIFY_DEBUG(current < MaxPools, "unexpected already waiting state of cpu (%d)", (int)current);
+ if (AtomicCas(&State, (state & ~CurrentMask) | CpuSpinning, state)) { // successfully marked as spinning
+ return true;
+ }
+ }
+ }
+
+ bool StartBlocking() {
+ while (true) {
+ TAtomicBase state = AtomicLoad(&State);
+ TPoolId current(state & CurrentMask);
+ if (current == CpuSpinning) {
+ if (AtomicCas(&State, (state & ~CurrentMask) | CpuBlocked, state)) {
+ return false; // successful switch
+ }
+ } else {
+ return true; // wakeup
+ }
+ }
+ }
+
+ bool Block(ui64 timeoutNs, TPoolId& result) {
+#ifdef _linux_
+ timespec timeout;
+ timeout.tv_sec = timeoutNs / 1'000'000'000;
+ timeout.tv_nsec = timeoutNs % 1'000'000'000;
+ SysFutex(Futex(), FUTEX_WAIT_PRIVATE, CpuBlocked, &timeout, nullptr, 0);
+#else
+ NanoSleep(timeoutNs); // non-linux wake is not supported, cpu will go idle on wake after blocked state
+#endif
+ TAtomicBase state = AtomicLoad(&State);
+ TPoolId current(state & CurrentMask);
+ if (current == CpuBlocked) {
+ return false; // timeout
+ } else {
+ result = current;
+ return true; // wakeup
+ }
+ }
+
+ enum EWakeResult {
+ Woken, // successfully woken up
+ NotIdle, // cpu is already not idle
+ Forbidden, // cpu is assigned to another pool
+ Stopped, // cpu is shutdown
+ };
+
+ EWakeResult WakeWithoutToken(TPoolId pool) {
+ while (true) {
+ TAtomicBase state = RelaxedLoad(&State);
+ TPoolId current(state & CurrentMask);
+ TPoolId assigned((state & AssignedMask) >> AssignedOffs);
+ if (assigned == CpuShared || assigned == pool) {
+ if (current == CpuSpinning) {
+ if (AtomicCas(&State, (state & ~CurrentMask) | pool, state)) {
+ return Woken;
+ }
+ } else if (current == CpuBlocked) {
+ if (AtomicCas(&State, (state & ~CurrentMask) | pool, state)) {
+ FutexWake();
+ return Woken;
+ }
+ } else if (current == CpuStopped) {
+ return Stopped;
+ } else {
+ return NotIdle;
+ }
+ } else {
+ return Forbidden;
+ }
+ }
+ }
+
+ EWakeResult WakeWithTokenAcquired(TPoolId token) {
+ while (true) {
+ TAtomicBase state = RelaxedLoad(&State);
+ TPoolId current(state & CurrentMask);
+ // NOTE: We ignore assigned value because we already have token, so
+ // NOTE: not assigned pool may be run here. This will be fixed
+ // NOTE: after we finish with current activation
+ if (current == CpuSpinning) {
+ if (AtomicCas(&State, (state & ~CurrentMask) | token, state)) {
+ return Woken;
+ }
+ } else if (current == CpuBlocked) {
+ if (AtomicCas(&State, (state & ~CurrentMask) | token, state)) {
+ FutexWake();
+ return Woken;
+ }
+ } else if (current == CpuStopped) {
+ return Stopped;
+ } else {
+ return NotIdle;
+ }
+ }
+ }
+
+ bool IsPoolReassigned(TPoolId current) const {
+ TAtomicBase state = AtomicLoad(&State);
+ TPoolId assigned((state & AssignedMask) >> AssignedOffs);
+ return assigned != current;
+ }
+
+ private:
+ void* Futex() {
+ return (void*)&State; // little endian assumed
+ }
+
+ void FutexWake() {
+#ifdef _linux_
+ SysFutex(Futex(), FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0);
+#endif
+ }
+ };
+
+}
diff --git a/library/cpp/actors/core/defs.h b/library/cpp/actors/core/defs.h
new file mode 100644
index 0000000000..980b7d767b
--- /dev/null
+++ b/library/cpp/actors/core/defs.h
@@ -0,0 +1,69 @@
+#pragma once
+
+// unique tag to fix pragma once gcc glueing: ./library/actorlib/core/defs.h
+
+#include <library/cpp/actors/util/defs.h>
+#include <util/generic/hash.h>
+#include <util/string/printf.h>
+
+// Enables collection of
+// event send/receive counts
+// activation time histograms
+// event processing time histograms
+#define ACTORSLIB_COLLECT_EXEC_STATS
+
+namespace NActors {
+ using TPoolId = ui8;
+ using TPoolsMask = ui64;
+ static constexpr TPoolId PoolBits = 6;
+ static constexpr TPoolId MaxPools = (1 << PoolBits) - 1; // maximum amount of pools (poolid=63 is reserved)
+ static constexpr TPoolsMask WaitPoolsFlag = (1ull << MaxPools); // wait-for-slow-workers flag bitmask
+
+ // Special TPoolId values used by TCpuState
+ static constexpr TPoolId CpuSpinning = MaxPools; // fast-worker is actively spinning, no slow-workers
+ static constexpr TPoolId CpuBlocked = MaxPools + 1; // fast-worker is blocked, no slow-workers
+ static constexpr TPoolId CpuStopped = TPoolId(-1); // special value indicating worker should stop
+ static constexpr TPoolId CpuShared = MaxPools; // special value for `assigned` meaning balancer disabled, pool scheduler is used instead
+
+ using TPoolWeight = ui16;
+ static constexpr TPoolWeight MinPoolWeight = 1;
+ static constexpr TPoolWeight DefPoolWeight = 32;
+ static constexpr TPoolWeight MaxPoolWeight = 1024;
+
+ using TWorkerId = ui16;
+ static constexpr TWorkerId WorkerBits = 11;
+ static constexpr TWorkerId MaxWorkers = 1 << WorkerBits;
+
+ using TThreadId = ui64;
+ static constexpr TThreadId UnknownThreadId = ui64(-1);
+
+ struct TMailboxType {
+ enum EType {
+ Inherited = -1, // inherit mailbox from parent
+ Simple = 0, // simplest queue under producer lock. fastest in no-contention case
+ Revolving = 1, // somewhat outdated, tries to be wait-free. replaced by ReadAsFilled
+ HTSwap = 2, // other simple lf queue, suggested for low-contention case
+ ReadAsFilled = 3, // wait-free queue, suggested for high-contention or latency critical
+ TinyReadAsFilled = 4, // same as 3 but with lower overhead
+ //Inplace;
+ //Direct;
+ //Virtual
+ };
+ };
+
+ struct TScopeId : std::pair<ui64, ui64> {
+ using TBase = std::pair<ui64, ui64>;
+ using TBase::TBase;
+ static const TScopeId LocallyGenerated;
+ };
+
+ static inline TString ScopeIdToString(const TScopeId& scopeId) {
+ return Sprintf("<%" PRIu64 ":%" PRIu64 ">", scopeId.first, scopeId.second);
+ }
+
+}
+
+template<>
+struct hash<NActors::TScopeId> : hash<std::pair<ui64, ui64>> {};
+
+class TAffinity;
diff --git a/library/cpp/actors/core/event.cpp b/library/cpp/actors/core/event.cpp
new file mode 100644
index 0000000000..33f8ce2aaf
--- /dev/null
+++ b/library/cpp/actors/core/event.cpp
@@ -0,0 +1,38 @@
+#include "event.h"
+#include "event_pb.h"
+
+namespace NActors {
+
+ const TScopeId TScopeId::LocallyGenerated{
+ Max<ui64>(), Max<ui64>()
+ };
+
+ TIntrusivePtr<TEventSerializedData> IEventHandle::ReleaseChainBuffer() {
+ if (Buffer) {
+ TIntrusivePtr<TEventSerializedData> result;
+ DoSwap(result, Buffer);
+ Event.Reset();
+ return result;
+ }
+ if (Event) {
+ TAllocChunkSerializer serializer;
+ Event->SerializeToArcadiaStream(&serializer);
+ auto chainBuf = serializer.Release(Event->IsExtendedFormat());
+ Event.Reset();
+ return chainBuf;
+ }
+ return new TEventSerializedData;
+ }
+
+ TIntrusivePtr<TEventSerializedData> IEventHandle::GetChainBuffer() {
+ if (Buffer)
+ return Buffer;
+ if (Event) {
+ TAllocChunkSerializer serializer;
+ Event->SerializeToArcadiaStream(&serializer);
+ Buffer = serializer.Release(Event->IsExtendedFormat());
+ return Buffer;
+ }
+ return new TEventSerializedData;
+ }
+}
diff --git a/library/cpp/actors/core/event.h b/library/cpp/actors/core/event.h
new file mode 100644
index 0000000000..6ff02aaf94
--- /dev/null
+++ b/library/cpp/actors/core/event.h
@@ -0,0 +1,344 @@
+#pragma once
+
+#include "defs.h"
+#include "actorid.h"
+#include "callstack.h"
+#include "event_load.h"
+
+#include <library/cpp/actors/wilson/wilson_trace.h>
+
+#include <util/system/hp_timer.h>
+#include <util/generic/maybe.h>
+
+namespace NActors {
+ class TChunkSerializer;
+
+ class ISerializerToStream {
+ public:
+ virtual bool SerializeToArcadiaStream(TChunkSerializer*) const = 0;
+ };
+
+ class IEventBase
+ : TNonCopyable,
+ public ISerializerToStream {
+ public:
+ // actual typing is performed by IEventHandle
+
+ virtual ~IEventBase() {
+ }
+
+ virtual TString ToStringHeader() const = 0;
+ virtual TString ToString() const {
+ return ToStringHeader();
+ }
+ virtual ui32 CalculateSerializedSize() const {
+ return 0;
+ }
+ virtual ui32 Type() const = 0;
+ virtual bool SerializeToArcadiaStream(TChunkSerializer*) const = 0;
+ virtual bool IsSerializable() const = 0;
+ virtual bool IsExtendedFormat() const {
+ return false;
+ }
+ virtual ui32 CalculateSerializedSizeCached() const {
+ return CalculateSerializedSize();
+ }
+ };
+
+ // fat handle
+ class IEventHandle : TNonCopyable {
+ struct TOnNondelivery {
+ TActorId Recipient;
+
+ TOnNondelivery(const TActorId& recipient)
+ : Recipient(recipient)
+ {
+ }
+ };
+
+ public:
+ template <typename TEv>
+ inline TEv* CastAsLocal() const noexcept {
+ auto fits = GetTypeRewrite() == TEv::EventType;
+
+ return fits ? static_cast<TEv*>(Event.Get()) : nullptr;
+ }
+
+ template <typename TEventType>
+ TEventType* Get() {
+ if (Type != TEventType::EventType)
+ Y_FAIL("Event type %" PRIu32 " doesn't match the expected type %" PRIu32, Type, TEventType::EventType);
+
+ if (!Event) {
+ Event.Reset(TEventType::Load(Buffer.Get()));
+ }
+
+ if (Event) {
+ return static_cast<TEventType*>(Event.Get());
+ }
+
+ Y_FAIL("Failed to Load() event type %" PRIu32 " class %s", Type, TypeName<TEventType>().data());
+ }
+
+ template <typename T>
+ TAutoPtr<T> Release() {
+ TAutoPtr<T> x = Get<T>();
+ Y_UNUSED(Event.Release());
+ Buffer.Reset();
+ return x;
+ }
+
+ enum EFlags {
+ FlagTrackDelivery = 1 << 0,
+ FlagForwardOnNondelivery = 1 << 1,
+ FlagSubscribeOnSession = 1 << 2,
+ FlagUseSubChannel = 1 << 3,
+ FlagGenerateUnsureUndelivered = 1 << 4,
+ FlagExtendedFormat = 1 << 5,
+ };
+
+ const ui32 Type;
+ const ui32 Flags;
+ const TActorId Recipient;
+ const TActorId Sender;
+ const ui64 Cookie;
+ const TScopeId OriginScopeId = TScopeId::LocallyGenerated; // filled in when the message is received from Interconnect
+
+ // if set, used by ActorSystem/Interconnect to report tracepoints
+ NWilson::TTraceId TraceId;
+
+ // filled if feeded by interconnect session
+ const TActorId InterconnectSession;
+
+#ifdef ACTORSLIB_COLLECT_EXEC_STATS
+ ::NHPTimer::STime SendTime;
+#endif
+
+ static const size_t ChannelBits = 12;
+ static const size_t ChannelShift = (sizeof(ui32) << 3) - ChannelBits;
+
+#ifdef USE_ACTOR_CALLSTACK
+ TCallstack Callstack;
+#endif
+ ui16 GetChannel() const noexcept {
+ return Flags >> ChannelShift;
+ }
+
+ ui64 GetSubChannel() const noexcept {
+ return Flags & FlagUseSubChannel ? Sender.LocalId() : 0ULL;
+ }
+
+ static ui32 MakeFlags(ui32 channel, ui32 flags) {
+ Y_VERIFY(channel < (1 << ChannelBits));
+ Y_VERIFY(flags < (1 << ChannelShift));
+ return (flags | (channel << ChannelShift));
+ }
+
+ private:
+ THolder<IEventBase> Event;
+ TIntrusivePtr<TEventSerializedData> Buffer;
+
+ TActorId RewriteRecipient;
+ ui32 RewriteType;
+
+ THolder<TOnNondelivery> OnNondeliveryHolder; // only for local events
+
+ public:
+ void Rewrite(ui32 typeRewrite, TActorId recipientRewrite) {
+ RewriteRecipient = recipientRewrite;
+ RewriteType = typeRewrite;
+ }
+
+ void DropRewrite() {
+ RewriteRecipient = Recipient;
+ RewriteType = Type;
+ }
+
+ const TActorId& GetRecipientRewrite() const {
+ return RewriteRecipient;
+ }
+
+ ui32 GetTypeRewrite() const {
+ return RewriteType;
+ }
+
+ TActorId GetForwardOnNondeliveryRecipient() const {
+ return OnNondeliveryHolder.Get() ? OnNondeliveryHolder->Recipient : TActorId();
+ }
+
+ IEventHandle(const TActorId& recipient, const TActorId& sender, IEventBase* ev, ui32 flags = 0, ui64 cookie = 0,
+ const TActorId* forwardOnNondelivery = nullptr, NWilson::TTraceId traceId = {})
+ : Type(ev->Type())
+ , Flags(flags)
+ , Recipient(recipient)
+ , Sender(sender)
+ , Cookie(cookie)
+ , TraceId(std::move(traceId))
+#ifdef ACTORSLIB_COLLECT_EXEC_STATS
+ , SendTime(0)
+#endif
+ , Event(ev)
+ , RewriteRecipient(Recipient)
+ , RewriteType(Type)
+ {
+ if (forwardOnNondelivery)
+ OnNondeliveryHolder.Reset(new TOnNondelivery(*forwardOnNondelivery));
+ }
+
+ IEventHandle(ui32 type,
+ ui32 flags,
+ const TActorId& recipient,
+ const TActorId& sender,
+ TIntrusivePtr<TEventSerializedData> buffer,
+ ui64 cookie,
+ const TActorId* forwardOnNondelivery = nullptr,
+ NWilson::TTraceId traceId = {})
+ : Type(type)
+ , Flags(flags)
+ , Recipient(recipient)
+ , Sender(sender)
+ , Cookie(cookie)
+ , TraceId(std::move(traceId))
+#ifdef ACTORSLIB_COLLECT_EXEC_STATS
+ , SendTime(0)
+#endif
+ , Buffer(std::move(buffer))
+ , RewriteRecipient(Recipient)
+ , RewriteType(Type)
+ {
+ if (forwardOnNondelivery)
+ OnNondeliveryHolder.Reset(new TOnNondelivery(*forwardOnNondelivery));
+ }
+
+ // Special ctor for events from interconnect.
+ IEventHandle(const TActorId& session,
+ ui32 type,
+ ui32 flags,
+ const TActorId& recipient,
+ const TActorId& sender,
+ TIntrusivePtr<TEventSerializedData> buffer,
+ ui64 cookie,
+ TScopeId originScopeId,
+ NWilson::TTraceId traceId) noexcept
+ : Type(type)
+ , Flags(flags)
+ , Recipient(recipient)
+ , Sender(sender)
+ , Cookie(cookie)
+ , OriginScopeId(originScopeId)
+ , TraceId(std::move(traceId))
+ , InterconnectSession(session)
+#ifdef ACTORSLIB_COLLECT_EXEC_STATS
+ , SendTime(0)
+#endif
+ , Buffer(std::move(buffer))
+ , RewriteRecipient(Recipient)
+ , RewriteType(Type)
+ {
+ }
+
+ TIntrusivePtr<TEventSerializedData> GetChainBuffer();
+ TIntrusivePtr<TEventSerializedData> ReleaseChainBuffer();
+
+ ui32 GetSize() const {
+ if (Buffer) {
+ return Buffer->GetSize();
+ } else if (Event) {
+ return Event->CalculateSerializedSize();
+ } else {
+ return 0;
+ }
+ }
+
+ bool HasBuffer() const {
+ return bool(Buffer);
+ }
+
+ bool HasEvent() const {
+ return bool(Event);
+ }
+
+ IEventBase* GetBase() {
+ if (!Event) {
+ if (!Buffer)
+ return nullptr;
+ else
+ ythrow TWithBackTrace<yexception>() << "don't know how to load the event from buffer";
+ }
+
+ return Event.Get();
+ }
+
+ TAutoPtr<IEventBase> ReleaseBase() {
+ TAutoPtr<IEventBase> x = GetBase();
+ Y_UNUSED(Event.Release());
+ Buffer.Reset();
+ return x;
+ }
+
+ TAutoPtr<IEventHandle> Forward(const TActorId& dest) {
+ if (Event)
+ return new IEventHandle(dest, Sender, Event.Release(), Flags, Cookie, nullptr, std::move(TraceId));
+ else
+ return new IEventHandle(Type, Flags, dest, Sender, Buffer, Cookie, nullptr, std::move(TraceId));
+ }
+
+ TAutoPtr<IEventHandle> ForwardOnNondelivery(ui32 reason, bool unsure = false);
+ };
+
+ template <typename TEventType>
+ class TEventHandle: public IEventHandle {
+ TEventHandle(); // we never made instance of TEventHandle
+ public:
+ TEventType* Get() {
+ return IEventHandle::Get<TEventType>();
+ }
+
+ TAutoPtr<TEventType> Release() {
+ return IEventHandle::Release<TEventType>();
+ }
+ };
+
+ static_assert(sizeof(TEventHandle<IEventBase>) == sizeof(IEventHandle), "expect sizeof(TEventHandle<IEventBase>) == sizeof(IEventHandle)");
+
+ template <typename TEventType, ui32 EventType0>
+ class TEventBase: public IEventBase {
+ public:
+ static constexpr ui32 EventType = EventType0;
+ ui32 Type() const override {
+ return EventType0;
+ }
+ // still abstract
+
+ typedef TEventHandle<TEventType> THandle;
+ typedef TAutoPtr<THandle> TPtr;
+ };
+
+#define DEFINE_SIMPLE_LOCAL_EVENT(eventType, header) \
+ TString ToStringHeader() const override { \
+ return TString(header); \
+ } \
+ bool SerializeToArcadiaStream(NActors::TChunkSerializer*) const override { \
+ Y_FAIL("Local event " #eventType " is not serializable"); \
+ } \
+ static IEventBase* Load(NActors::TEventSerializedData*) { \
+ Y_FAIL("Local event " #eventType " has no load method"); \
+ } \
+ bool IsSerializable() const override { \
+ return false; \
+ }
+
+#define DEFINE_SIMPLE_NONLOCAL_EVENT(eventType, header) \
+ TString ToStringHeader() const override { \
+ return TString(header); \
+ } \
+ bool SerializeToArcadiaStream(NActors::TChunkSerializer*) const override { \
+ return true; \
+ } \
+ static IEventBase* Load(NActors::TEventSerializedData*) { \
+ return new eventType(); \
+ } \
+ bool IsSerializable() const override { \
+ return true; \
+ }
+}
diff --git a/library/cpp/actors/core/event_load.h b/library/cpp/actors/core/event_load.h
new file mode 100644
index 0000000000..0dab1dd374
--- /dev/null
+++ b/library/cpp/actors/core/event_load.h
@@ -0,0 +1,112 @@
+#pragma once
+
+#include <util/stream/walk.h>
+#include <util/system/types.h>
+#include <util/generic/string.h>
+#include <library/cpp/actors/util/rope.h>
+#include <library/cpp/actors/wilson/wilson_trace.h>
+
+namespace NActors {
+ class IEventHandle;
+
+ struct TConstIoVec {
+ const void* Data;
+ size_t Size;
+ };
+
+ struct TIoVec {
+ void* Data;
+ size_t Size;
+ };
+
+ class TEventSerializedData
+ : public TThrRefBase
+ {
+ TRope Rope;
+ bool ExtendedFormat = false;
+
+ public:
+ TEventSerializedData() = default;
+
+ TEventSerializedData(TRope&& rope, bool extendedFormat)
+ : Rope(std::move(rope))
+ , ExtendedFormat(extendedFormat)
+ {}
+
+ TEventSerializedData(const TEventSerializedData& original, TString extraBuffer)
+ : Rope(original.Rope)
+ , ExtendedFormat(original.ExtendedFormat)
+ {
+ Append(std::move(extraBuffer));
+ }
+
+ TEventSerializedData(TString buffer, bool extendedFormat)
+ : ExtendedFormat(extendedFormat)
+ {
+ Append(std::move(buffer));
+ }
+
+ void SetExtendedFormat() {
+ ExtendedFormat = true;
+ }
+
+ bool IsExtendedFormat() const {
+ return ExtendedFormat;
+ }
+
+ TRope::TConstIterator GetBeginIter() const {
+ return Rope.Begin();
+ }
+
+ size_t GetSize() const {
+ return Rope.GetSize();
+ }
+
+ TString GetString() const {
+ TString result;
+ result.reserve(GetSize());
+ for (auto it = Rope.Begin(); it.Valid(); it.AdvanceToNextContiguousBlock()) {
+ result.append(it.ContiguousData(), it.ContiguousSize());
+ }
+ return result;
+ }
+
+ TRope EraseBack(size_t count) {
+ Y_VERIFY(count <= Rope.GetSize());
+ TRope::TIterator iter = Rope.End();
+ iter -= count;
+ return Rope.Extract(iter, Rope.End());
+ }
+
+ void Append(TRope&& from) {
+ Rope.Insert(Rope.End(), std::move(from));
+ }
+
+ void Append(TString buffer) {
+ if (buffer) {
+ Rope.Insert(Rope.End(), TRope(std::move(buffer)));
+ }
+ }
+ };
+}
+
+class TChainBufWalk : public IWalkInput {
+ TIntrusivePtr<NActors::TEventSerializedData> Buffer;
+ TRope::TConstIterator Iter;
+
+public:
+ TChainBufWalk(TIntrusivePtr<NActors::TEventSerializedData> buffer)
+ : Buffer(std::move(buffer))
+ , Iter(Buffer->GetBeginIter())
+ {}
+
+private:
+ size_t DoUnboundedNext(const void **ptr) override {
+ const size_t size = Iter.ContiguousSize();
+ *ptr = Iter.ContiguousData();
+ if (Iter.Valid()) {
+ Iter.AdvanceToNextContiguousBlock();
+ }
+ return size;
+ }
+};
diff --git a/library/cpp/actors/core/event_local.h b/library/cpp/actors/core/event_local.h
new file mode 100644
index 0000000000..2845aa94dd
--- /dev/null
+++ b/library/cpp/actors/core/event_local.h
@@ -0,0 +1,74 @@
+#pragma once
+
+#include "event.h"
+#include "scheduler_cookie.h"
+#include "event_load.h"
+#include <util/system/type_name.h>
+
+namespace NActors {
+ template <typename TEv, ui32 TEventType>
+ class TEventLocal: public TEventBase<TEv, TEventType> {
+ public:
+ TString ToStringHeader() const override {
+ return TypeName<TEv>();
+ }
+
+ bool SerializeToArcadiaStream(TChunkSerializer* /*serializer*/) const override {
+ Y_FAIL("Serialization of local event %s type %" PRIu32, TypeName<TEv>().data(), TEventType);
+ }
+
+ bool IsSerializable() const override {
+ return false;
+ }
+
+ static IEventBase* Load(TEventSerializedData*) {
+ Y_FAIL("Loading of local event %s type %" PRIu32, TypeName<TEv>().data(), TEventType);
+ }
+ };
+
+ template <typename TEv, ui32 TEventType>
+ class TEventScheduler: public TEventLocal<TEv, TEventType> {
+ public:
+ TSchedulerCookieHolder Cookie;
+
+ TEventScheduler(ISchedulerCookie* cookie)
+ : Cookie(cookie)
+ {
+ }
+ };
+
+ template <ui32 TEventType>
+ class TEventSchedulerEv: public TEventScheduler<TEventSchedulerEv<TEventType>, TEventType> {
+ public:
+ TEventSchedulerEv(ISchedulerCookie* cookie)
+ : TEventScheduler<TEventSchedulerEv<TEventType>, TEventType>(cookie)
+ {
+ }
+ };
+
+ template <typename TEv, ui32 TEventType>
+ class TEventSimple: public TEventBase<TEv, TEventType> {
+ public:
+ TString ToStringHeader() const override {
+ static TString header(TypeName<TEv>());
+ return header;
+ }
+
+ bool SerializeToArcadiaStream(TChunkSerializer* /*serializer*/) const override {
+ static_assert(sizeof(TEv) == sizeof(TEventSimple<TEv, TEventType>), "Descendant should be an empty class");
+ return true;
+ }
+
+ bool IsSerializable() const override {
+ return true;
+ }
+
+ static IEventBase* Load(NActors::TEventSerializedData*) {
+ return new TEv();
+ }
+
+ static IEventBase* Load(const TString&) {
+ return new TEv();
+ }
+ };
+}
diff --git a/library/cpp/actors/core/event_pb.cpp b/library/cpp/actors/core/event_pb.cpp
new file mode 100644
index 0000000000..018ff9ac34
--- /dev/null
+++ b/library/cpp/actors/core/event_pb.cpp
@@ -0,0 +1,223 @@
+#include "event_pb.h"
+
+namespace NActors {
+ bool TRopeStream::Next(const void** data, int* size) {
+ *data = Iter.ContiguousData();
+ *size = Iter.ContiguousSize();
+ if (size_t(*size + TotalByteCount) > Size) {
+ *size = Size - TotalByteCount;
+ Iter += *size;
+ } else if (Iter.Valid()) {
+ Iter.AdvanceToNextContiguousBlock();
+ }
+ TotalByteCount += *size;
+ return *size != 0;
+ }
+
+ void TRopeStream::BackUp(int count) {
+ Y_VERIFY(count <= TotalByteCount);
+ Iter -= count;
+ TotalByteCount -= count;
+ }
+
+ bool TRopeStream::Skip(int count) {
+ if (static_cast<size_t>(TotalByteCount + count) > Size) {
+ count = Size - TotalByteCount;
+ }
+ Iter += count;
+ TotalByteCount += count;
+ return static_cast<size_t>(TotalByteCount) != Size;
+ }
+
+ TCoroutineChunkSerializer::TCoroutineChunkSerializer()
+ : TotalSerializedDataSize(0)
+ , Stack(64 * 1024)
+ , SelfClosure{this, TArrayRef(Stack.Begin(), Stack.End())}
+ , InnerContext(SelfClosure)
+ {}
+
+ TCoroutineChunkSerializer::~TCoroutineChunkSerializer() {
+ CancelFlag = true;
+ Resume();
+ Y_VERIFY(Finished);
+ }
+
+ bool TCoroutineChunkSerializer::AllowsAliasing() const {
+ return true;
+ }
+
+ bool TCoroutineChunkSerializer::Produce(const void *data, size_t size) {
+ Y_VERIFY(size <= SizeRemain);
+ SizeRemain -= size;
+ TotalSerializedDataSize += size;
+
+ if (NumChunks) {
+ auto& last = Chunks[NumChunks - 1];
+ if (last.first + last.second == data) {
+ last.second += size; // just extend the last buffer
+ return true;
+ }
+ }
+
+ if (NumChunks == MaxChunks) {
+ InnerContext.SwitchTo(BufFeedContext);
+ if (CancelFlag || AbortFlag) {
+ return false;
+ }
+ }
+
+ Y_VERIFY(NumChunks < MaxChunks);
+ Chunks[NumChunks++] = {static_cast<const char*>(data), size};
+ return true;
+ }
+
+ bool TCoroutineChunkSerializer::WriteAliasedRaw(const void* data, int size) {
+ Y_VERIFY(size >= 0);
+ while (size) {
+ if (CancelFlag || AbortFlag) {
+ return false;
+ } else if (const size_t bytesToAppend = Min<size_t>(size, SizeRemain)) {
+ if (!Produce(data, bytesToAppend)) {
+ return false;
+ }
+ data = static_cast<const char*>(data) + bytesToAppend;
+ size -= bytesToAppend;
+ } else {
+ InnerContext.SwitchTo(BufFeedContext);
+ }
+ }
+ return true;
+ }
+
+ bool TCoroutineChunkSerializer::Next(void** data, int* size) {
+ if (CancelFlag || AbortFlag) {
+ return false;
+ }
+ if (!SizeRemain) {
+ InnerContext.SwitchTo(BufFeedContext);
+ if (CancelFlag || AbortFlag) {
+ return false;
+ }
+ }
+ Y_VERIFY(SizeRemain);
+ *data = BufferPtr;
+ *size = SizeRemain;
+ BufferPtr += SizeRemain;
+ return Produce(*data, *size);
+ }
+
+ void TCoroutineChunkSerializer::BackUp(int count) {
+ if (!count) {
+ return;
+ }
+ Y_VERIFY(count > 0);
+ Y_VERIFY(NumChunks);
+ TChunk& buf = Chunks[NumChunks - 1];
+ Y_VERIFY((size_t)count <= buf.second);
+ Y_VERIFY(buf.first + buf.second == BufferPtr);
+ buf.second -= count;
+ if (!buf.second) {
+ --NumChunks;
+ }
+ BufferPtr -= count;
+ SizeRemain += count;
+ TotalSerializedDataSize -= count;
+ }
+
+ void TCoroutineChunkSerializer::Resume() {
+ TContMachineContext feedContext;
+ BufFeedContext = &feedContext;
+ feedContext.SwitchTo(&InnerContext);
+ BufFeedContext = nullptr;
+ }
+
+ bool TCoroutineChunkSerializer::WriteRope(const TRope *rope) {
+ for (auto iter = rope->Begin(); iter.Valid(); iter.AdvanceToNextContiguousBlock()) {
+ if (!WriteAliasedRaw(iter.ContiguousData(), iter.ContiguousSize())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool TCoroutineChunkSerializer::WriteString(const TString *s) {
+ return WriteAliasedRaw(s->data(), s->length());
+ }
+
+ std::pair<TCoroutineChunkSerializer::TChunk*, TCoroutineChunkSerializer::TChunk*> TCoroutineChunkSerializer::FeedBuf(void* data, size_t size) {
+ // fill in base params
+ BufferPtr = static_cast<char*>(data);
+ SizeRemain = size;
+
+ // transfer control to the coroutine
+ Y_VERIFY(Event);
+ NumChunks = 0;
+ Resume();
+
+ return {Chunks, Chunks + NumChunks};
+ }
+
+ void TCoroutineChunkSerializer::SetSerializingEvent(const IEventBase *event) {
+ Y_VERIFY(Event == nullptr);
+ Event = event;
+ TotalSerializedDataSize = 0;
+ AbortFlag = false;
+ }
+
+ void TCoroutineChunkSerializer::Abort() {
+ Y_VERIFY(Event);
+ AbortFlag = true;
+ Resume();
+ }
+
+ void TCoroutineChunkSerializer::DoRun() {
+ while (!CancelFlag) {
+ Y_VERIFY(Event);
+ SerializationSuccess = Event->SerializeToArcadiaStream(this);
+ Event = nullptr;
+ if (!CancelFlag) { // cancel flag may have been received during serialization
+ InnerContext.SwitchTo(BufFeedContext);
+ }
+ }
+ Finished = true;
+ InnerContext.SwitchTo(BufFeedContext);
+ }
+
+ bool TAllocChunkSerializer::Next(void** pdata, int* psize) {
+ if (Backup) {
+ // we have some data in backup rope -- move the first chunk from the backup rope to the buffer and return
+ // pointer to the buffer; it is safe to remove 'const' here as we uniquely own this buffer
+ TRope::TIterator iter = Backup.Begin();
+ *pdata = const_cast<char*>(iter.ContiguousData());
+ *psize = iter.ContiguousSize();
+ iter.AdvanceToNextContiguousBlock();
+ Buffers->Append(Backup.Extract(Backup.Begin(), iter));
+ } else {
+ // no backup buffer, so we have to create new one
+ auto item = TRopeAlignedBuffer::Allocate(4096);
+ *pdata = item->GetBuffer();
+ *psize = item->GetCapacity();
+ Buffers->Append(TRope(std::move(item)));
+ }
+ return true;
+ }
+
+ void TAllocChunkSerializer::BackUp(int count) {
+ Backup.Insert(Backup.Begin(), Buffers->EraseBack(count));
+ }
+
+ bool TAllocChunkSerializer::WriteAliasedRaw(const void*, int) {
+ Y_VERIFY(false);
+ return false;
+ }
+
+ bool TAllocChunkSerializer::WriteRope(const TRope *rope) {
+ Buffers->Append(TRope(*rope));
+ return true;
+ }
+
+ bool TAllocChunkSerializer::WriteString(const TString *s) {
+ Buffers->Append(*s);
+ return true;
+ }
+}
diff --git a/library/cpp/actors/core/event_pb.h b/library/cpp/actors/core/event_pb.h
new file mode 100644
index 0000000000..d7546b901a
--- /dev/null
+++ b/library/cpp/actors/core/event_pb.h
@@ -0,0 +1,500 @@
+#pragma once
+
+#include "event.h"
+#include "event_load.h"
+
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/arena.h>
+#include <library/cpp/actors/protos/actors.pb.h>
+#include <util/generic/deque.h>
+#include <util/system/context.h>
+#include <util/system/filemap.h>
+#include <array>
+
+namespace NActors {
+
+ class TRopeStream : public NProtoBuf::io::ZeroCopyInputStream {
+ TRope::TConstIterator Iter;
+ const size_t Size;
+
+ public:
+ TRopeStream(TRope::TConstIterator iter, size_t size)
+ : Iter(iter)
+ , Size(size)
+ {}
+
+ bool Next(const void** data, int* size) override;
+ void BackUp(int count) override;
+ bool Skip(int count) override;
+ int64_t ByteCount() const override {
+ return TotalByteCount;
+ }
+
+ private:
+ int64_t TotalByteCount = 0;
+ };
+
+ class TChunkSerializer : public NProtoBuf::io::ZeroCopyOutputStream {
+ public:
+ TChunkSerializer() = default;
+ virtual ~TChunkSerializer() = default;
+
+ virtual bool WriteRope(const TRope *rope) = 0;
+ virtual bool WriteString(const TString *s) = 0;
+ };
+
+ class TAllocChunkSerializer final : public TChunkSerializer {
+ public:
+ bool Next(void** data, int* size) override;
+ void BackUp(int count) override;
+ int64_t ByteCount() const override {
+ return Buffers->GetSize();
+ }
+ bool WriteAliasedRaw(const void* data, int size) override;
+
+ // WARNING: these methods require owner to retain ownership and immutability of passed objects
+ bool WriteRope(const TRope *rope) override;
+ bool WriteString(const TString *s) override;
+
+ inline TIntrusivePtr<TEventSerializedData> Release(bool extendedFormat) {
+ if (extendedFormat) {
+ Buffers->SetExtendedFormat();
+ }
+ return std::move(Buffers);
+ }
+
+ protected:
+ TIntrusivePtr<TEventSerializedData> Buffers = new TEventSerializedData;
+ TRope Backup;
+ };
+
+ class TCoroutineChunkSerializer final : public TChunkSerializer, protected ITrampoLine {
+ public:
+ using TChunk = std::pair<const char*, size_t>;
+
+ TCoroutineChunkSerializer();
+ ~TCoroutineChunkSerializer();
+
+ void SetSerializingEvent(const IEventBase *event);
+ void Abort();
+ std::pair<TChunk*, TChunk*> FeedBuf(void* data, size_t size);
+ bool IsComplete() const {
+ return !Event;
+ }
+ bool IsSuccessfull() const {
+ return SerializationSuccess;
+ }
+ const IEventBase *GetCurrentEvent() const {
+ return Event;
+ }
+
+ bool Next(void** data, int* size) override;
+ void BackUp(int count) override;
+ int64_t ByteCount() const override {
+ return TotalSerializedDataSize;
+ }
+ bool WriteAliasedRaw(const void* data, int size) override;
+ bool AllowsAliasing() const override;
+
+ bool WriteRope(const TRope *rope) override;
+ bool WriteString(const TString *s) override;
+
+ protected:
+ void DoRun() override;
+ void Resume();
+ bool Produce(const void *data, size_t size);
+
+ i64 TotalSerializedDataSize;
+ TMappedAllocation Stack;
+ TContClosure SelfClosure;
+ TContMachineContext InnerContext;
+ TContMachineContext *BufFeedContext = nullptr;
+ char *BufferPtr;
+ size_t SizeRemain;
+ static constexpr size_t MaxChunks = 16;
+ TChunk Chunks[MaxChunks];
+ size_t NumChunks = 0;
+ const IEventBase *Event = nullptr;
+ bool CancelFlag = false;
+ bool AbortFlag;
+ bool SerializationSuccess;
+ bool Finished = false;
+ };
+
+#ifdef ACTORLIB_HUGE_PB_SIZE
+ static const size_t EventMaxByteSize = 140 << 20; // (140MB)
+#else
+ static const size_t EventMaxByteSize = 67108000;
+#endif
+
+ template <typename TEv, typename TRecord /*protobuf record*/, ui32 TEventType, typename TRecHolder>
+ class TEventPBBase: public TEventBase<TEv, TEventType> , public TRecHolder {
+ // a vector of data buffers referenced by record; if filled, then extended serialization mechanism applies
+ TVector<TRope> Payload;
+
+ public:
+ using TRecHolder::Record;
+
+ public:
+ using ProtoRecordType = TRecord;
+
+ TEventPBBase() = default;
+
+ explicit TEventPBBase(const TRecord& rec)
+ {
+ Record = rec;
+ }
+
+ explicit TEventPBBase(TRecord&& rec)
+ {
+ Record = std::move(rec);
+ }
+
+ TString ToStringHeader() const override {
+ return Record.GetTypeName();
+ }
+
+ TString ToString() const override {
+ return Record.ShortDebugString();
+ }
+
+ bool IsSerializable() const override {
+ return true;
+ }
+
+ bool IsExtendedFormat() const override {
+ return static_cast<bool>(Payload);
+ }
+
+ bool SerializeToArcadiaStream(TChunkSerializer* chunker) const override {
+ // serialize payload first
+ if (Payload) {
+ void *data;
+ int size = 0;
+ auto append = [&](const char *p, size_t len) {
+ while (len) {
+ if (size) {
+ const size_t numBytesToCopy = std::min<size_t>(size, len);
+ memcpy(data, p, numBytesToCopy);
+ data = static_cast<char*>(data) + numBytesToCopy;
+ size -= numBytesToCopy;
+ p += numBytesToCopy;
+ len -= numBytesToCopy;
+ } else if (!chunker->Next(&data, &size)) {
+ return false;
+ }
+ }
+ return true;
+ };
+ auto appendNumber = [&](size_t number) {
+ char buf[MaxNumberBytes];
+ return append(buf, SerializeNumber(number, buf));
+ };
+ char marker = PayloadMarker;
+ append(&marker, 1);
+ if (!appendNumber(Payload.size())) {
+ return false;
+ }
+ for (const TRope& rope : Payload) {
+ if (!appendNumber(rope.GetSize())) {
+ return false;
+ }
+ if (rope) {
+ if (size) {
+ chunker->BackUp(std::exchange(size, 0));
+ }
+ if (!chunker->WriteRope(&rope)) {
+ return false;
+ }
+ }
+ }
+ if (size) {
+ chunker->BackUp(size);
+ }
+ }
+
+ return Record.SerializeToZeroCopyStream(chunker);
+ }
+
+ ui32 CalculateSerializedSize() const override {
+ ssize_t result = Record.ByteSize();
+ if (result >= 0 && Payload) {
+ ++result; // marker
+ char buf[MaxNumberBytes];
+ result += SerializeNumber(Payload.size(), buf);
+ for (const TRope& rope : Payload) {
+ result += SerializeNumber(rope.GetSize(), buf);
+ result += rope.GetSize();
+ }
+ }
+ return result;
+ }
+
+ static IEventBase* Load(TIntrusivePtr<TEventSerializedData> input) {
+ THolder<TEventPBBase> ev(new TEv());
+ if (!input->GetSize()) {
+ Y_PROTOBUF_SUPPRESS_NODISCARD ev->Record.ParseFromString(TString());
+ } else {
+ TRope::TConstIterator iter = input->GetBeginIter();
+ ui64 size = input->GetSize();
+
+ if (input->IsExtendedFormat()) {
+ // check marker
+ if (!iter.Valid() || *iter.ContiguousData() != PayloadMarker) {
+ Y_FAIL("invalid event");
+ }
+ // skip marker
+ iter += 1;
+ --size;
+ // parse number of payload ropes
+ size_t numRopes = DeserializeNumber(iter, size);
+ if (numRopes == Max<size_t>()) {
+ Y_FAIL("invalid event");
+ }
+ while (numRopes--) {
+ // parse length of the rope
+ const size_t len = DeserializeNumber(iter, size);
+ if (len == Max<size_t>() || size < len) {
+ Y_FAIL("invalid event len# %zu size# %" PRIu64, len, size);
+ }
+ // extract the rope
+ TRope::TConstIterator begin = iter;
+ iter += len;
+ size -= len;
+ ev->Payload.emplace_back(begin, iter);
+ }
+ }
+
+ // parse the protobuf
+ TRopeStream stream(iter, size);
+ if (!ev->Record.ParseFromZeroCopyStream(&stream)) {
+ Y_FAIL("Failed to parse protobuf event type %" PRIu32 " class %s", TEventType, TypeName(ev->Record).data());
+ }
+ }
+ ev->CachedByteSize = input->GetSize();
+ return ev.Release();
+ }
+
+ size_t GetCachedByteSize() const {
+ if (CachedByteSize == 0) {
+ CachedByteSize = CalculateSerializedSize();
+ }
+ return CachedByteSize;
+ }
+
+ ui32 CalculateSerializedSizeCached() const override {
+ return GetCachedByteSize();
+ }
+
+ void InvalidateCachedByteSize() {
+ CachedByteSize = 0;
+ }
+
+ public:
+ void ReservePayload(size_t size) {
+ Payload.reserve(size);
+ }
+
+ ui32 AddPayload(TRope&& rope) {
+ const ui32 id = Payload.size();
+ Payload.push_back(std::move(rope));
+ InvalidateCachedByteSize();
+ return id;
+ }
+
+ const TRope& GetPayload(ui32 id) const {
+ Y_VERIFY(id < Payload.size());
+ return Payload[id];
+ }
+
+ ui32 GetPayloadCount() const {
+ return Payload.size();
+ }
+
+ void StripPayload() {
+ Payload.clear();
+ }
+
+ protected:
+ mutable size_t CachedByteSize = 0;
+
+ static constexpr char PayloadMarker = 0x07;
+ static constexpr size_t MaxNumberBytes = (sizeof(size_t) * CHAR_BIT + 6) / 7;
+
+ static size_t SerializeNumber(size_t num, char *buffer) {
+ char *begin = buffer;
+ do {
+ *buffer++ = (num & 0x7F) | (num >= 128 ? 0x80 : 0x00);
+ num >>= 7;
+ } while (num);
+ return buffer - begin;
+ }
+
+ static size_t DeserializeNumber(const char **ptr, const char *end) {
+ const char *p = *ptr;
+ size_t res = 0;
+ size_t offset = 0;
+ for (;;) {
+ if (p == end) {
+ return Max<size_t>();
+ }
+ const char byte = *p++;
+ res |= (static_cast<size_t>(byte) & 0x7F) << offset;
+ offset += 7;
+ if (!(byte & 0x80)) {
+ break;
+ }
+ }
+ *ptr = p;
+ return res;
+ }
+
+ static size_t DeserializeNumber(TRope::TConstIterator& iter, ui64& size) {
+ size_t res = 0;
+ size_t offset = 0;
+ for (;;) {
+ if (!iter.Valid()) {
+ return Max<size_t>();
+ }
+ const char byte = *iter.ContiguousData();
+ iter += 1;
+ --size;
+ res |= (static_cast<size_t>(byte) & 0x7F) << offset;
+ offset += 7;
+ if (!(byte & 0x80)) {
+ break;
+ }
+ }
+ return res;
+ }
+ };
+
+ // Protobuf record not using arena
+ template <typename TRecord>
+ struct TRecordHolder {
+ TRecord Record;
+ };
+
+ // Protobuf arena and a record allocated on it
+ template <typename TRecord, size_t InitialBlockSize, size_t MaxBlockSize>
+ struct TArenaRecordHolder {
+ google::protobuf::Arena PbArena;
+ TRecord& Record;
+
+ static const google::protobuf::ArenaOptions GetArenaOptions() {
+ google::protobuf::ArenaOptions opts;
+ opts.initial_block_size = InitialBlockSize;
+ opts.max_block_size = MaxBlockSize;
+ return opts;
+ }
+
+ TArenaRecordHolder()
+ : PbArena(GetArenaOptions())
+ , Record(*google::protobuf::Arena::CreateMessage<TRecord>(&PbArena))
+ {}
+ };
+
+ template <typename TEv, typename TRecord, ui32 TEventType>
+ class TEventPB : public TEventPBBase<TEv, TRecord, TEventType, TRecordHolder<TRecord> > {
+ typedef TEventPBBase<TEv, TRecord, TEventType, TRecordHolder<TRecord> > TPbBase;
+ // NOTE: No extra fields allowed: TEventPB must be a "template typedef"
+ public:
+ using TPbBase::TPbBase;
+ };
+
+ template <typename TEv, typename TRecord, ui32 TEventType, size_t InitialBlockSize = 512, size_t MaxBlockSize = 16*1024>
+ using TEventPBWithArena = TEventPBBase<TEv, TRecord, TEventType, TArenaRecordHolder<TRecord, InitialBlockSize, MaxBlockSize> >;
+
+ template <typename TEv, typename TRecord, ui32 TEventType>
+ class TEventShortDebugPB: public TEventPB<TEv, TRecord, TEventType> {
+ public:
+ using TBase = TEventPB<TEv, TRecord, TEventType>;
+ TEventShortDebugPB() = default;
+ explicit TEventShortDebugPB(const TRecord& rec)
+ : TBase(rec)
+ {
+ }
+ explicit TEventShortDebugPB(TRecord&& rec)
+ : TBase(std::move(rec))
+ {
+ }
+ TString ToString() const override {
+ return TypeName<TEv>() + " { " + TBase::Record.ShortDebugString() + " }";
+ }
+ };
+
+ template <typename TEv, typename TRecord, ui32 TEventType>
+ class TEventPreSerializedPB: public TEventPB<TEv, TRecord, TEventType> {
+ protected:
+ using TBase = TEventPB<TEv, TRecord, TEventType>;
+ using TSelf = TEventPreSerializedPB<TEv, TRecord, TEventType>;
+ using TBase::Record;
+
+ public:
+ TString PreSerializedData; // already serialized PB data (using message::SerializeToString)
+
+ TEventPreSerializedPB() = default;
+
+ explicit TEventPreSerializedPB(const TRecord& rec)
+ : TBase(rec)
+ {
+ }
+
+ explicit TEventPreSerializedPB(TRecord&& rec)
+ : TBase(std::move(rec))
+ {
+ }
+
+ // when remote event received locally this method will merge preserialized data
+ const TRecord& GetRecord() {
+ TRecord& base(TBase::Record);
+ if (!PreSerializedData.empty()) {
+ TRecord copy;
+ Y_PROTOBUF_SUPPRESS_NODISCARD copy.ParseFromString(PreSerializedData);
+ copy.MergeFrom(base);
+ base.Swap(&copy);
+ PreSerializedData.clear();
+ }
+ return TBase::Record;
+ }
+
+ const TRecord& GetRecord() const {
+ return const_cast<TSelf*>(this)->GetRecord();
+ }
+
+ TRecord* MutableRecord() {
+ GetRecord(); // Make sure PreSerializedData is parsed
+ return &(TBase::Record);
+ }
+
+ TString ToString() const override {
+ return GetRecord().ShortDebugString();
+ }
+
+ bool SerializeToArcadiaStream(TChunkSerializer* chunker) const override {
+ return chunker->WriteString(&PreSerializedData) && TBase::SerializeToArcadiaStream(chunker);
+ }
+
+ ui32 CalculateSerializedSize() const override {
+ return PreSerializedData.size() + TBase::CalculateSerializedSize();
+ }
+
+ size_t GetCachedByteSize() const {
+ return PreSerializedData.size() + TBase::GetCachedByteSize();
+ }
+
+ ui32 CalculateSerializedSizeCached() const override {
+ return GetCachedByteSize();
+ }
+ };
+
+ inline TActorId ActorIdFromProto(const NActorsProto::TActorId& actorId) {
+ return TActorId(actorId.GetRawX1(), actorId.GetRawX2());
+ }
+
+ inline void ActorIdToProto(const TActorId& src, NActorsProto::TActorId* dest) {
+ Y_VERIFY_DEBUG(dest);
+ dest->SetRawX1(src.RawX1());
+ dest->SetRawX2(src.RawX2());
+ }
+}
diff --git a/library/cpp/actors/core/event_pb_payload_ut.cpp b/library/cpp/actors/core/event_pb_payload_ut.cpp
new file mode 100644
index 0000000000..eab007bc15
--- /dev/null
+++ b/library/cpp/actors/core/event_pb_payload_ut.cpp
@@ -0,0 +1,154 @@
+#include "event_pb.h"
+#include "events.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/actors/protos/unittests.pb.h>
+
+using namespace NActors;
+
+enum {
+ EvMessageWithPayload = EventSpaceBegin(TEvents::ES_PRIVATE),
+ EvArenaMessage,
+ EvArenaMessageBig,
+ EvMessageWithPayloadPreSerialized
+};
+
+struct TEvMessageWithPayload : TEventPB<TEvMessageWithPayload, TMessageWithPayload, EvMessageWithPayload> {
+ TEvMessageWithPayload() = default;
+ explicit TEvMessageWithPayload(const TMessageWithPayload& p)
+ : TEventPB<TEvMessageWithPayload, TMessageWithPayload, EvMessageWithPayload>(p)
+ {}
+};
+
+struct TEvMessageWithPayloadPreSerialized : TEventPreSerializedPB<TEvMessageWithPayloadPreSerialized, TMessageWithPayload, EvMessageWithPayloadPreSerialized> {
+};
+
+
+TRope MakeStringRope(const TString& message) {
+ return message ? TRope(message) : TRope();
+}
+
+TString MakeString(size_t len) {
+ TString res;
+ for (size_t i = 0; i < len; ++i) {
+ res += RandomNumber<char>();
+ }
+ return res;
+}
+
+Y_UNIT_TEST_SUITE(TEventProtoWithPayload) {
+
+ template <class TEventFrom, class TEventTo>
+ void TestSerializeDeserialize(size_t size1, size_t size2) {
+ static_assert(TEventFrom::EventType == TEventTo::EventType, "Must be same event type");
+
+ TEventFrom msg;
+ msg.Record.SetMeta("hello, world!");
+ msg.Record.AddPayloadId(msg.AddPayload(MakeStringRope(MakeString(size1))));
+ msg.Record.AddPayloadId(msg.AddPayload(MakeStringRope(MakeString(size2))));
+ msg.Record.AddSomeData(MakeString((size1 + size2) % 50 + 11));
+
+ auto serializer = MakeHolder<TAllocChunkSerializer>();
+ msg.SerializeToArcadiaStream(serializer.Get());
+ auto buffers = serializer->Release(msg.IsExtendedFormat());
+ UNIT_ASSERT_VALUES_EQUAL(buffers->GetSize(), msg.CalculateSerializedSize());
+ TString ser = buffers->GetString();
+
+ TString chunkerRes;
+ TCoroutineChunkSerializer chunker;
+ chunker.SetSerializingEvent(&msg);
+ while (!chunker.IsComplete()) {
+ char buffer[4096];
+ auto range = chunker.FeedBuf(buffer, sizeof(buffer));
+ for (auto p = range.first; p != range.second; ++p) {
+ chunkerRes += TString(p->first, p->second);
+ }
+ }
+ UNIT_ASSERT_VALUES_EQUAL(chunkerRes, ser);
+
+ THolder<IEventBase> ev2 = THolder(TEventTo::Load(buffers));
+ TEventTo& msg2 = static_cast<TEventTo&>(*ev2);
+ UNIT_ASSERT_VALUES_EQUAL(msg2.Record.GetMeta(), msg.Record.GetMeta());
+ UNIT_ASSERT_EQUAL(msg2.GetPayload(msg2.Record.GetPayloadId(0)), msg.GetPayload(msg.Record.GetPayloadId(0)));
+ UNIT_ASSERT_EQUAL(msg2.GetPayload(msg2.Record.GetPayloadId(1)), msg.GetPayload(msg.Record.GetPayloadId(1)));
+ }
+
+ template <class TEvent>
+ void TestAllSizes(size_t step1 = 100, size_t step2 = 111) {
+ for (size_t size1 = 0; size1 < 10000; size1 += step1) {
+ for (size_t size2 = 0; size2 < 10000; size2 += step2) {
+ TestSerializeDeserialize<TEvent, TEvent>(size1, size2);
+ }
+ }
+ }
+
+#if (!defined(_tsan_enabled_))
+ Y_UNIT_TEST(SerializeDeserialize) {
+ TestAllSizes<TEvMessageWithPayload>();
+ }
+#endif
+
+
+ struct TEvArenaMessage : TEventPBWithArena<TEvArenaMessage, TMessageWithPayload, EvArenaMessage> {
+ };
+
+ Y_UNIT_TEST(SerializeDeserializeArena) {
+ TestAllSizes<TEvArenaMessage>(500, 111);
+ }
+
+
+ struct TEvArenaMessageBig : TEventPBWithArena<TEvArenaMessageBig, TMessageWithPayload, EvArenaMessageBig, 4000, 32000> {
+ };
+
+ Y_UNIT_TEST(SerializeDeserializeArenaBig) {
+ TestAllSizes<TEvArenaMessageBig>(111, 500);
+ }
+
+
+ // Compatible with TEvArenaMessage but doesn't use arenas
+ struct TEvArenaMessageWithoutArena : TEventPB<TEvArenaMessageWithoutArena, TMessageWithPayload, EvArenaMessage> {
+ };
+
+ Y_UNIT_TEST(Compatibility) {
+ TestSerializeDeserialize<TEvArenaMessage, TEvArenaMessageWithoutArena>(200, 14010);
+ TestSerializeDeserialize<TEvArenaMessageWithoutArena, TEvArenaMessage>(2000, 4010);
+ }
+
+ Y_UNIT_TEST(PreSerializedCompatibility) {
+ // ensure TEventPreSerializedPB and TEventPB are interchangable with no compatibility issues
+ TMessageWithPayload msg;
+ msg.SetMeta("hello, world!");
+ msg.AddPayloadId(123);
+ msg.AddPayloadId(999);
+ msg.AddSomeData("abc");
+ msg.AddSomeData("xyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz");
+
+ TEvMessageWithPayloadPreSerialized e1;
+ Y_PROTOBUF_SUPPRESS_NODISCARD msg.SerializeToString(&e1.PreSerializedData);
+
+ auto serializer1 = MakeHolder<TAllocChunkSerializer>();
+ e1.SerializeToArcadiaStream(serializer1.Get());
+ auto buffers1 = serializer1->Release(e1.IsExtendedFormat());
+ UNIT_ASSERT_VALUES_EQUAL(buffers1->GetSize(), e1.CalculateSerializedSize());
+ TString ser1 = buffers1->GetString();
+
+ TEvMessageWithPayload e2(msg);
+ auto serializer2 = MakeHolder<TAllocChunkSerializer>();
+ e2.SerializeToArcadiaStream(serializer2.Get());
+ auto buffers2 = serializer2->Release(e2.IsExtendedFormat());
+ UNIT_ASSERT_VALUES_EQUAL(buffers2->GetSize(), e2.CalculateSerializedSize());
+ TString ser2 = buffers2->GetString();
+ UNIT_ASSERT_VALUES_EQUAL(ser1, ser2);
+
+ // deserialize
+ auto data = MakeIntrusive<TEventSerializedData>(ser1, false);
+ THolder<TEvMessageWithPayloadPreSerialized> parsedEvent(static_cast<TEvMessageWithPayloadPreSerialized*>(TEvMessageWithPayloadPreSerialized::Load(data)));
+ UNIT_ASSERT_VALUES_EQUAL(parsedEvent->PreSerializedData, ""); // this field is empty after deserialization
+ auto& record = parsedEvent->GetRecord();
+ UNIT_ASSERT_VALUES_EQUAL(record.GetMeta(), msg.GetMeta());
+ UNIT_ASSERT_VALUES_EQUAL(record.PayloadIdSize(), msg.PayloadIdSize());
+ UNIT_ASSERT_VALUES_EQUAL(record.PayloadIdSize(), 2);
+ UNIT_ASSERT_VALUES_EQUAL(record.GetPayloadId(0), msg.GetPayloadId(0));
+ UNIT_ASSERT_VALUES_EQUAL(record.GetPayloadId(1), msg.GetPayloadId(1));
+ }
+}
diff --git a/library/cpp/actors/core/event_pb_ut.cpp b/library/cpp/actors/core/event_pb_ut.cpp
new file mode 100644
index 0000000000..a16c3092b3
--- /dev/null
+++ b/library/cpp/actors/core/event_pb_ut.cpp
@@ -0,0 +1,71 @@
+#include "event_pb.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/actors/protos/unittests.pb.h>
+
+Y_UNIT_TEST_SUITE(TEventSerialization) {
+ struct TMockEvent: public NActors::IEventBase {
+ TBigMessage* msg;
+ bool
+ SerializeToArcadiaStream(NActors::TChunkSerializer* chunker) const override {
+ return msg->SerializeToZeroCopyStream(chunker);
+ }
+ bool IsSerializable() const override {
+ return true;
+ }
+ TString ToStringHeader() const override {
+ return TString();
+ }
+ virtual TString Serialize() const {
+ return TString();
+ }
+ ui32 Type() const override {
+ return 0;
+ };
+ };
+
+ Y_UNIT_TEST(Coroutine) {
+ TString strA(507, 'a');
+ TString strB(814, 'b');
+ TString strC(198, 'c');
+
+ TBigMessage bm;
+
+ TSimple* simple0 = bm.AddSimples();
+ simple0->SetStr1(strA);
+ simple0->SetStr2(strB);
+ simple0->SetNumber1(213431324);
+
+ TSimple* simple1 = bm.AddSimples();
+ simple1->SetStr1(strC);
+ simple1->SetStr2(strA);
+ simple1->SetNumber1(21039313);
+
+ bm.AddManyStr(strA);
+ bm.AddManyStr(strC);
+ bm.AddManyStr(strB);
+
+ bm.SetOneMoreStr(strB);
+ bm.SetYANumber(394143);
+
+ TString bmSerialized;
+ Y_PROTOBUF_SUPPRESS_NODISCARD bm.SerializeToString(&bmSerialized);
+ UNIT_ASSERT_UNEQUAL(bmSerialized.size(), 0);
+
+ NActors::TCoroutineChunkSerializer chunker;
+ for (int i = 0; i < 4; ++i) {
+ TMockEvent event;
+ event.msg = &bm;
+ chunker.SetSerializingEvent(&event);
+ char buf1[87];
+ TString bmChunkedSerialized;
+ while (!chunker.IsComplete()) {
+ auto range = chunker.FeedBuf(&buf1[0], sizeof(buf1));
+ for (auto p = range.first; p != range.second; ++p) {
+ bmChunkedSerialized.append(p->first, p->second);
+ }
+ }
+ UNIT_ASSERT_EQUAL(bmSerialized, bmChunkedSerialized);
+ }
+ }
+}
diff --git a/library/cpp/actors/core/events.h b/library/cpp/actors/core/events.h
new file mode 100644
index 0000000000..702cf50fad
--- /dev/null
+++ b/library/cpp/actors/core/events.h
@@ -0,0 +1,222 @@
+#pragma once
+
+#include "event.h"
+#include "event_pb.h"
+
+#include <library/cpp/actors/protos/actors.pb.h>
+#include <util/system/unaligned_mem.h>
+
+namespace NActors {
+ struct TEvents {
+ enum EEventSpace {
+ ES_HELLOWORLD = 0,
+ ES_SYSTEM = 1,
+ ES_INTERCONNECT = 2,
+ ES_INTERCONNECT_MSGBUS = 3,
+ ES_DNS = 4,
+ ES_SOCKET_POLLER = 5,
+ ES_LOGGER = 6,
+ ES_MON = 7,
+ ES_INTERCONNECT_TCP = 8,
+ ES_PROFILER = 9,
+ ES_YF = 10,
+ ES_HTTP = 11,
+
+ ES_USERSPACE = 4096,
+
+ ES_PRIVATE = (1 << 15) - 16,
+ ES_MAX = (1 << 15),
+ };
+
+#define EventSpaceBegin(eventSpace) (eventSpace << 16u)
+#define EventSpaceEnd(eventSpace) ((eventSpace << 16u) + (1u << 16u))
+
+ struct THelloWorld {
+ enum {
+ Start = EventSpaceBegin(ES_HELLOWORLD),
+ Ping,
+ Pong,
+ Blob,
+ End
+ };
+
+ static_assert(End < EventSpaceEnd(ES_HELLOWORLD), "expect End < EventSpaceEnd(ES_HELLOWORLD)");
+ };
+
+ struct TEvPing: public TEventBase<TEvPing, THelloWorld::Ping> {
+ DEFINE_SIMPLE_NONLOCAL_EVENT(TEvPing, "HelloWorld: Ping");
+ };
+
+ struct TEvPong: public TEventBase<TEvPong, THelloWorld::Pong> {
+ DEFINE_SIMPLE_NONLOCAL_EVENT(TEvPong, "HelloWorld: Pong");
+ };
+
+ struct TEvBlob: public TEventBase<TEvBlob, THelloWorld::Blob> {
+ const TString Blob;
+
+ TEvBlob(const TString& blob) noexcept
+ : Blob(blob)
+ {
+ }
+
+ TString ToStringHeader() const noexcept override {
+ return "THelloWorld::Blob";
+ }
+
+ bool SerializeToArcadiaStream(TChunkSerializer *serializer) const override {
+ return serializer->WriteString(&Blob);
+ }
+
+ static IEventBase* Load(TEventSerializedData* bufs) noexcept {
+ return new TEvBlob(bufs->GetString());
+ }
+
+ bool IsSerializable() const override {
+ return true;
+ }
+ };
+
+ struct TSystem {
+ enum {
+ Start = EventSpaceBegin(ES_SYSTEM),
+ Bootstrap, // generic bootstrap event
+ Wakeup, // generic timeout
+ Subscribe, // generic subscribe to something
+ Unsubscribe, // generic unsubscribe from something
+ Delivered, // event delivered
+ Undelivered, // event undelivered
+ Poison, // request actor to shutdown
+ Completed, // generic async job result event
+ PoisonTaken, // generic Poison taken (reply to PoisonPill event, i.e. died completely)
+ FlushLog,
+ CallbackCompletion,
+ CallbackException,
+ Gone, // Generic notification of actor death
+ TrackActor,
+ UntrackActor,
+ InvokeResult,
+ CoroTimeout,
+ InvokeQuery,
+ End,
+
+ // Compatibility section
+ PoisonPill = Poison,
+ ActorDied = Gone,
+ };
+
+ static_assert(End < EventSpaceEnd(ES_SYSTEM), "expect End < EventSpaceEnd(ES_SYSTEM)");
+ };
+
+ struct TEvBootstrap: public TEventBase<TEvBootstrap, TSystem::Bootstrap> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvBootstrap, "System: TEvBootstrap")
+ };
+
+ struct TEvPoison : public TEventBase<TEvPoison, TSystem::Poison> {
+ DEFINE_SIMPLE_NONLOCAL_EVENT(TEvPoison, "System: TEvPoison")
+ };
+
+ struct TEvWakeup: public TEventBase<TEvWakeup, TSystem::Wakeup> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvWakeup, "System: TEvWakeup")
+
+ TEvWakeup(ui64 tag = 0) : Tag(tag) { }
+
+ const ui64 Tag = 0;
+ };
+
+ struct TEvSubscribe: public TEventBase<TEvSubscribe, TSystem::Subscribe> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvSubscribe, "System: TEvSubscribe")
+ };
+
+ struct TEvUnsubscribe: public TEventBase<TEvUnsubscribe, TSystem::Unsubscribe> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvUnsubscribe, "System: TEvUnsubscribe")
+ };
+
+ struct TEvUndelivered: public TEventBase<TEvUndelivered, TSystem::Undelivered> {
+ enum EReason {
+ ReasonUnknown,
+ ReasonActorUnknown,
+ Disconnected
+ };
+ const ui32 SourceType;
+ const EReason Reason;
+ const bool Unsure;
+ const TString Data;
+
+ TEvUndelivered(ui32 sourceType, ui32 reason, bool unsure = false)
+ : SourceType(sourceType)
+ , Reason(static_cast<EReason>(reason))
+ , Unsure(unsure)
+ , Data(MakeData(sourceType, reason))
+ {}
+
+ TString ToStringHeader() const override;
+ bool SerializeToArcadiaStream(TChunkSerializer *serializer) const override;
+ static IEventBase* Load(TEventSerializedData* bufs);
+ bool IsSerializable() const override;
+
+ ui32 CalculateSerializedSize() const override { return 2 * sizeof(ui32); }
+
+ static void Out(IOutputStream& o, EReason x);
+
+ private:
+ static TString MakeData(ui32 sourceType, ui32 reason) {
+ TString s = TString::Uninitialized(sizeof(ui32) + sizeof(ui32));
+ char *p = s.Detach();
+ WriteUnaligned<ui32>(p + 0, sourceType);
+ WriteUnaligned<ui32>(p + 4, reason);
+ return s;
+ }
+ };
+
+ struct TEvCompleted: public TEventBase<TEvCompleted, TSystem::Completed> {
+ const ui32 Id;
+ const ui32 Status;
+ TEvCompleted(ui32 id = 0, ui32 status = 0)
+ : Id(id)
+ , Status(status)
+ {
+ }
+
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvCompleted, "System: TEvCompleted")
+ };
+
+ struct TEvPoisonTaken: public TEventBase<TEvPoisonTaken, TSystem::PoisonTaken> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvPoisonTaken, "System: TEvPoisonTaken")
+ };
+
+ struct TEvFlushLog: public TEventBase<TEvFlushLog, TSystem::FlushLog> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvFlushLog, "System: TEvFlushLog")
+ };
+
+ struct TEvCallbackException: public TEventPB<TEvCallbackException,
+ NActorsProto::TCallbackException,
+ TSystem::CallbackException> {
+ TEvCallbackException(const TActorId& id, const TString& msg) {
+ ActorIdToProto(id, Record.MutableActorId());
+ Record.SetExceptionMessage(msg);
+ }
+ };
+
+ struct TEvCallbackCompletion: public TEventPB<TEvCallbackCompletion,
+ NActorsProto::TActorId,
+ TSystem::CallbackCompletion> {
+ TEvCallbackCompletion(const TActorId& id) {
+ ActorIdToProto(id, &Record);
+ }
+ };
+
+ struct TEvGone: public TEventBase<TEvGone, TSystem::Gone> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvGone, "System: TEvGone")
+ };
+
+ struct TEvInvokeResult;
+
+ using TEvPoisonPill = TEvPoison; // Legacy name, deprecated
+ using TEvActorDied = TEvGone;
+ };
+}
+
+template <>
+inline void Out<NActors::TEvents::TEvUndelivered::EReason>(IOutputStream& o, NActors::TEvents::TEvUndelivered::EReason x) {
+ NActors::TEvents::TEvUndelivered::Out(o, x);
+}
diff --git a/library/cpp/actors/core/events_undelivered.cpp b/library/cpp/actors/core/events_undelivered.cpp
new file mode 100644
index 0000000000..23deaffd10
--- /dev/null
+++ b/library/cpp/actors/core/events_undelivered.cpp
@@ -0,0 +1,60 @@
+#include "events.h"
+#include "actorsystem.h"
+
+namespace NActors {
+ TString TEvents::TEvUndelivered::ToStringHeader() const {
+ return "TSystem::Undelivered";
+ }
+
+ bool TEvents::TEvUndelivered::SerializeToArcadiaStream(TChunkSerializer *serializer) const {
+ Y_VERIFY(!Unsure); // these are local-only events generated by Interconnect
+ return serializer->WriteString(&Data);
+ }
+
+ void TEvents::TEvUndelivered::Out(IOutputStream& o, EReason x) {
+ switch (x) {
+ case ReasonActorUnknown:
+ o << "ActorUnknown";
+ break;
+ case Disconnected:
+ o << "Disconnected";
+ break;
+ default:
+ o << "Undefined";
+ break;
+ }
+ }
+
+ bool TEvents::TEvUndelivered::IsSerializable() const {
+ return true;
+ }
+
+ IEventBase* TEvents::TEvUndelivered::Load(TEventSerializedData* bufs) {
+ TString str = bufs->GetString();
+ Y_VERIFY(str.size() == (sizeof(ui32) + sizeof(ui32)));
+ const char* p = str.data();
+ const ui64 sourceType = ReadUnaligned<ui32>(p + 0);
+ const ui64 reason = ReadUnaligned<ui32>(p + 4);
+ return new TEvUndelivered(sourceType, reason);
+ }
+
+ TAutoPtr<IEventHandle> IEventHandle::ForwardOnNondelivery(ui32 reason, bool unsure) {
+ if (Flags & FlagForwardOnNondelivery) {
+ const ui32 updatedFlags = Flags & ~(FlagForwardOnNondelivery | FlagSubscribeOnSession);
+ const TActorId recp = OnNondeliveryHolder ? OnNondeliveryHolder->Recipient : TActorId();
+
+ if (Event)
+ return new IEventHandle(recp, Sender, Event.Release(), updatedFlags, Cookie, &Recipient, TraceId.Clone());
+ else
+ return new IEventHandle(Type, updatedFlags, recp, Sender, Buffer, Cookie, &Recipient, TraceId.Clone());
+ }
+
+ if (Flags & FlagTrackDelivery) {
+ const ui32 updatedFlags = Flags & ~(FlagTrackDelivery | FlagSubscribeOnSession | FlagGenerateUnsureUndelivered);
+ return new IEventHandle(Sender, Recipient, new TEvents::TEvUndelivered(Type, reason, unsure), updatedFlags,
+ Cookie, nullptr, TraceId.Clone());
+ }
+
+ return nullptr;
+ }
+}
diff --git a/library/cpp/actors/core/executelater.h b/library/cpp/actors/core/executelater.h
new file mode 100644
index 0000000000..e7a13c1005
--- /dev/null
+++ b/library/cpp/actors/core/executelater.h
@@ -0,0 +1,87 @@
+#pragma once
+
+#include "actor_bootstrapped.h"
+
+#include <utility>
+
+namespace NActors {
+ template <typename TCallback>
+ class TExecuteLater: public TActorBootstrapped<TExecuteLater<TCallback>> {
+ public:
+ static constexpr IActor::EActivityType ActorActivityType() {
+ return IActor::ACTORLIB_COMMON;
+ }
+
+ TExecuteLater(
+ TCallback&& callback,
+ IActor::EActivityType activityType,
+ ui32 channel = 0,
+ ui64 cookie = 0,
+ const TActorId& reportCompletionTo = TActorId(),
+ const TActorId& reportExceptionTo = TActorId()) noexcept
+ : Callback(std::move(callback))
+ , Channel(channel)
+ , Cookie(cookie)
+ , ReportCompletionTo(reportCompletionTo)
+ , ReportExceptionTo(reportExceptionTo)
+ {
+ this->SetActivityType(activityType);
+ }
+
+ void Bootstrap(const TActorContext& ctx) noexcept {
+ try {
+ {
+ /* RAII, Callback should be destroyed right before sending
+ TEvCallbackCompletion */
+
+ auto local = std::move(Callback);
+ using T = decltype(local);
+
+ if constexpr (std::is_invocable_v<T, const TActorContext&>) {
+ local(ctx);
+ } else {
+ local();
+ }
+ }
+
+ if (ReportCompletionTo) {
+ ctx.Send(ReportCompletionTo,
+ new TEvents::TEvCallbackCompletion(ctx.SelfID),
+ Channel, Cookie);
+ }
+ } catch (...) {
+ if (ReportExceptionTo) {
+ const TString msg = CurrentExceptionMessage();
+ ctx.Send(ReportExceptionTo,
+ new TEvents::TEvCallbackException(ctx.SelfID, msg),
+ Channel, Cookie);
+ }
+ }
+
+ this->Die(ctx);
+ }
+
+ private:
+ TCallback Callback;
+ const ui32 Channel;
+ const ui64 Cookie;
+ const TActorId ReportCompletionTo;
+ const TActorId ReportExceptionTo;
+ };
+
+ template <typename T>
+ IActor* CreateExecuteLaterActor(
+ T&& func,
+ IActor::EActivityType activityType,
+ ui32 channel = 0,
+ ui64 cookie = 0,
+ const TActorId& reportCompletionTo = TActorId(),
+ const TActorId& reportExceptionTo = TActorId()) noexcept {
+ return new TExecuteLater<T>(std::forward<T>(func),
+ activityType,
+ channel,
+ cookie,
+ reportCompletionTo,
+ reportExceptionTo);
+ }
+}
diff --git a/library/cpp/actors/core/executor_pool_base.cpp b/library/cpp/actors/core/executor_pool_base.cpp
new file mode 100644
index 0000000000..c3b9999168
--- /dev/null
+++ b/library/cpp/actors/core/executor_pool_base.cpp
@@ -0,0 +1,168 @@
+#include "executor_pool_base.h"
+#include "executor_thread.h"
+#include "mailbox.h"
+#include "probes.h"
+#include <library/cpp/actors/util/datetime.h>
+
+namespace NActors {
+ LWTRACE_USING(ACTORLIB_PROVIDER);
+
+ void DoActorInit(TActorSystem* sys, IActor* actor, const TActorId& self, const TActorId& owner) {
+ actor->SelfActorId = self;
+ actor->Registered(sys, owner);
+ }
+
+ TExecutorPoolBaseMailboxed::TExecutorPoolBaseMailboxed(ui32 poolId, ui32 maxActivityType)
+ : IExecutorPool(poolId)
+ , ActorSystem(nullptr)
+ , MailboxTable(new TMailboxTable)
+#ifdef ACTORSLIB_COLLECT_EXEC_STATS
+ , Stats(maxActivityType)
+#endif
+ {}
+
+ TExecutorPoolBaseMailboxed::~TExecutorPoolBaseMailboxed() {
+ MailboxTable.Destroy();
+ }
+
+ TExecutorPoolBase::TExecutorPoolBase(ui32 poolId, ui32 threads, TAffinity* affinity, ui32 maxActivityType)
+ : TExecutorPoolBaseMailboxed(poolId, maxActivityType)
+ , PoolThreads(threads)
+ , ThreadsAffinity(affinity)
+ {}
+
+ TExecutorPoolBase::~TExecutorPoolBase() {
+ while (Activations.Pop(0))
+ ;
+ }
+
+ void TExecutorPoolBaseMailboxed::ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingWriteCounter) {
+ Y_UNUSED(workerId);
+ MailboxTable->ReclaimMailbox(mailboxType, hint, revolvingWriteCounter);
+ }
+
+ ui64 TExecutorPoolBaseMailboxed::AllocateID() {
+ return ActorSystem->AllocateIDSpace(1);
+ }
+
+ bool TExecutorPoolBaseMailboxed::Send(TAutoPtr<IEventHandle>& ev) {
+ Y_VERIFY_DEBUG(ev->GetRecipientRewrite().PoolID() == PoolId);
+#ifdef ACTORSLIB_COLLECT_EXEC_STATS
+ RelaxedStore(&ev->SendTime, (::NHPTimer::STime)GetCycleCountFast());
+#endif
+ return MailboxTable->SendTo(ev, this);
+ }
+
+ void TExecutorPoolBase::ScheduleActivation(ui32 activation) {
+ ScheduleActivationEx(activation, AtomicIncrement(ActivationsRevolvingCounter));
+ }
+
+ TActorId TExecutorPoolBaseMailboxed::Register(IActor* actor, TMailboxType::EType mailboxType, ui64 revolvingWriteCounter, const TActorId& parentId) {
+ NHPTimer::STime hpstart = GetCycleCountFast();
+#ifdef ACTORSLIB_COLLECT_EXEC_STATS
+ ui32 at = actor->GetActivityType();
+ if (at >= Stats.MaxActivityType())
+ at = 0;
+ AtomicIncrement(Stats.ActorsAliveByActivity[at]);
+#endif
+ AtomicIncrement(ActorRegistrations);
+
+ // first step - find good enough mailbox
+ ui32 hint = 0;
+ TMailboxHeader* mailbox = nullptr;
+
+ if (revolvingWriteCounter == 0)
+ revolvingWriteCounter = AtomicIncrement(RegisterRevolvingCounter);
+
+ {
+ ui32 hintBackoff = 0;
+
+ while (hint == 0) {
+ hint = MailboxTable->AllocateMailbox(mailboxType, ++revolvingWriteCounter);
+ mailbox = MailboxTable->Get(hint);
+
+ if (!mailbox->LockFromFree()) {
+ MailboxTable->ReclaimMailbox(mailboxType, hintBackoff, ++revolvingWriteCounter);
+ hintBackoff = hint;
+ hint = 0;
+ }
+ }
+
+ MailboxTable->ReclaimMailbox(mailboxType, hintBackoff, ++revolvingWriteCounter);
+ }
+
+ const ui64 localActorId = AllocateID();
+
+ // ok, got mailbox
+ mailbox->AttachActor(localActorId, actor);
+
+ // do init
+ const TActorId actorId(ActorSystem->NodeId, PoolId, localActorId, hint);
+ DoActorInit(ActorSystem, actor, actorId, parentId);
+
+ // Once we unlock the mailbox the actor starts running and we cannot use the pointer any more
+ actor = nullptr;
+
+ switch (mailboxType) {
+ case TMailboxType::Simple:
+ UnlockFromExecution((TMailboxTable::TSimpleMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter);
+ break;
+ case TMailboxType::Revolving:
+ UnlockFromExecution((TMailboxTable::TRevolvingMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter);
+ break;
+ case TMailboxType::HTSwap:
+ UnlockFromExecution((TMailboxTable::THTSwapMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter);
+ break;
+ case TMailboxType::ReadAsFilled:
+ UnlockFromExecution((TMailboxTable::TReadAsFilledMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter);
+ break;
+ case TMailboxType::TinyReadAsFilled:
+ UnlockFromExecution((TMailboxTable::TTinyReadAsFilledMailbox*)mailbox, this, false, hint, MaxWorkers, ++revolvingWriteCounter);
+ break;
+ default:
+ Y_FAIL();
+ }
+
+ NHPTimer::STime elapsed = GetCycleCountFast() - hpstart;
+ if (elapsed > 1000000) {
+ LWPROBE(SlowRegisterNew, PoolId, NHPTimer::GetSeconds(elapsed) * 1000.0);
+ }
+
+ return actorId;
+ }
+
+ TActorId TExecutorPoolBaseMailboxed::Register(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId) {
+ NHPTimer::STime hpstart = GetCycleCountFast();
+#ifdef ACTORSLIB_COLLECT_EXEC_STATS
+ ui32 at = actor->GetActivityType();
+ if (at >= Stats.MaxActivityType())
+ at = 0;
+ AtomicIncrement(Stats.ActorsAliveByActivity[at]);
+#endif
+ AtomicIncrement(ActorRegistrations);
+
+ const ui64 localActorId = AllocateID();
+ mailbox->AttachActor(localActorId, actor);
+
+ const TActorId actorId(ActorSystem->NodeId, PoolId, localActorId, hint);
+ DoActorInit(ActorSystem, actor, actorId, parentId);
+ NHPTimer::STime elapsed = GetCycleCountFast() - hpstart;
+ if (elapsed > 1000000) {
+ LWPROBE(SlowRegisterAdd, PoolId, NHPTimer::GetSeconds(elapsed) * 1000.0);
+ }
+
+ return actorId;
+ }
+
+ TAffinity* TExecutorPoolBase::Affinity() const {
+ return ThreadsAffinity.Get();
+ }
+
+ bool TExecutorPoolBaseMailboxed::Cleanup() {
+ return MailboxTable->Cleanup();
+ }
+
+ ui32 TExecutorPoolBase::GetThreads() const {
+ return PoolThreads;
+ }
+}
diff --git a/library/cpp/actors/core/executor_pool_base.h b/library/cpp/actors/core/executor_pool_base.h
new file mode 100644
index 0000000000..c84ce1af77
--- /dev/null
+++ b/library/cpp/actors/core/executor_pool_base.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "actorsystem.h"
+#include "executor_thread.h"
+#include "scheduler_queue.h"
+#include <library/cpp/actors/util/affinity.h>
+#include <library/cpp/actors/util/unordered_cache.h>
+#include <library/cpp/actors/util/threadparkpad.h>
+
+namespace NActors {
+ class TExecutorPoolBaseMailboxed: public IExecutorPool {
+ protected:
+ TActorSystem* ActorSystem;
+ THolder<TMailboxTable> MailboxTable;
+#ifdef ACTORSLIB_COLLECT_EXEC_STATS
+ // Need to have per pool object to collect stats like actor registrations (because
+ // registrations might be done in threads from other pools)
+ TExecutorThreadStats Stats;
+#endif
+ TAtomic RegisterRevolvingCounter = 0;
+ ui64 AllocateID();
+ public:
+ TExecutorPoolBaseMailboxed(ui32 poolId, ui32 maxActivityType);
+ ~TExecutorPoolBaseMailboxed();
+ void ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingWriteCounter) override;
+ bool Send(TAutoPtr<IEventHandle>& ev) override;
+ TActorId Register(IActor* actor, TMailboxType::EType mailboxType, ui64 revolvingWriteCounter, const TActorId& parentId) override;
+ TActorId Register(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId) override;
+ bool Cleanup() override;
+ };
+
+ class TExecutorPoolBase: public TExecutorPoolBaseMailboxed {
+ protected:
+ const ui32 PoolThreads;
+ TIntrusivePtr<TAffinity> ThreadsAffinity;
+ TAtomic Semaphore = 0;
+ TUnorderedCache<ui32, 512, 4> Activations;
+ TAtomic ActivationsRevolvingCounter = 0;
+ volatile bool StopFlag = false;
+ public:
+ TExecutorPoolBase(ui32 poolId, ui32 threads, TAffinity* affinity, ui32 maxActivityType);
+ ~TExecutorPoolBase();
+ void ScheduleActivation(ui32 activation) override;
+ TAffinity* Affinity() const override;
+ ui32 GetThreads() const override;
+ };
+
+ void DoActorInit(TActorSystem*, IActor*, const TActorId&, const TActorId&);
+}
diff --git a/library/cpp/actors/core/executor_pool_basic.cpp b/library/cpp/actors/core/executor_pool_basic.cpp
new file mode 100644
index 0000000000..4dce16939a
--- /dev/null
+++ b/library/cpp/actors/core/executor_pool_basic.cpp
@@ -0,0 +1,431 @@
+#include "executor_pool_basic.h"
+#include "probes.h"
+#include "mailbox.h"
+#include <library/cpp/actors/util/affinity.h>
+#include <library/cpp/actors/util/datetime.h>
+
+#ifdef _linux_
+#include <pthread.h>
+#endif
+
+namespace NActors {
+ LWTRACE_USING(ACTORLIB_PROVIDER);
+
+ constexpr TDuration TBasicExecutorPool::DEFAULT_TIME_PER_MAILBOX;
+
+ TBasicExecutorPool::TBasicExecutorPool(
+ ui32 poolId,
+ ui32 threads,
+ ui64 spinThreshold,
+ const TString& poolName,
+ TAffinity* affinity,
+ TDuration timePerMailbox,
+ ui32 eventsPerMailbox,
+ int realtimePriority,
+ ui32 maxActivityType)
+ : TExecutorPoolBase(poolId, threads, affinity, maxActivityType)
+ , SpinThreshold(spinThreshold)
+ , SpinThresholdCycles(spinThreshold * NHPTimer::GetCyclesPerSecond() * 0.000001) // convert microseconds to cycles
+ , Threads(new TThreadCtx[threads])
+ , PoolName(poolName)
+ , TimePerMailbox(timePerMailbox)
+ , EventsPerMailbox(eventsPerMailbox)
+ , RealtimePriority(realtimePriority)
+ , ThreadUtilization(0)
+ , MaxUtilizationCounter(0)
+ , MaxUtilizationAccumulator(0)
+ , ThreadCount(threads)
+ {
+ }
+
+ TBasicExecutorPool::TBasicExecutorPool(const TBasicExecutorPoolConfig& cfg)
+ : TBasicExecutorPool(
+ cfg.PoolId,
+ cfg.Threads,
+ cfg.SpinThreshold,
+ cfg.PoolName,
+ new TAffinity(cfg.Affinity),
+ cfg.TimePerMailbox,
+ cfg.EventsPerMailbox,
+ cfg.RealtimePriority,
+ cfg.MaxActivityType
+ )
+ {}
+
+ TBasicExecutorPool::~TBasicExecutorPool() {
+ Threads.Destroy();
+ }
+
+ ui32 TBasicExecutorPool::GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) {
+ ui32 workerId = wctx.WorkerId;
+ Y_VERIFY_DEBUG(workerId < PoolThreads);
+
+ NHPTimer::STime elapsed = 0;
+ NHPTimer::STime parked = 0;
+ NHPTimer::STime blocked = 0;
+ NHPTimer::STime hpstart = GetCycleCountFast();
+ NHPTimer::STime hpnow;
+
+ TThreadCtx& threadCtx = Threads[workerId];
+ AtomicSet(threadCtx.WaitingFlag, TThreadCtx::WS_NONE);
+
+ if (Y_UNLIKELY(AtomicGet(threadCtx.BlockedFlag) != TThreadCtx::BS_NONE)) {
+ do {
+ if (AtomicCas(&threadCtx.BlockedFlag, TThreadCtx::BS_BLOCKED, TThreadCtx::BS_BLOCKING)) {
+ hpnow = GetCycleCountFast();
+ elapsed += hpnow - hpstart;
+ if (threadCtx.BlockedPad.Park()) // interrupted
+ return 0;
+ hpstart = GetCycleCountFast();
+ blocked += hpstart - hpnow;
+ }
+ } while (AtomicGet(threadCtx.BlockedFlag) != TThreadCtx::BS_NONE && !AtomicLoad(&StopFlag));
+ }
+
+ const TAtomic x = AtomicDecrement(Semaphore);
+
+ if (x < 0) {
+#if defined ACTORSLIB_COLLECT_EXEC_STATS
+ if (AtomicGetAndIncrement(ThreadUtilization) == 0) {
+ // Initially counter contains -t0, the pool start timestamp
+ // When the first thread goes to sleep we add t1, so the counter
+ // becomes t1-t0 >= 0, or the duration of max utilization so far.
+ // If the counter was negative and becomes positive, that means
+ // counter just turned into a duration and we should store that
+ // duration. Otherwise another thread raced with us and
+ // subtracted some other timestamp t2.
+ const i64 t = GetCycleCountFast();
+ const i64 x = AtomicGetAndAdd(MaxUtilizationCounter, t);
+ if (x < 0 && x + t > 0)
+ AtomicStore(&MaxUtilizationAccumulator, x + t);
+ }
+#endif
+
+ Y_VERIFY(AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_NONE);
+
+ if (SpinThreshold > 0) {
+ // spin configured period
+ AtomicSet(threadCtx.WaitingFlag, TThreadCtx::WS_ACTIVE);
+ ui64 start = GetCycleCountFast();
+ bool doSpin = true;
+ while (true) {
+ for (ui32 j = 0; doSpin && j < 12; ++j) {
+ if (GetCycleCountFast() >= (start + SpinThresholdCycles)) {
+ doSpin = false;
+ break;
+ }
+ for (ui32 i = 0; i < 12; ++i) {
+ if (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_ACTIVE) {
+ SpinLockPause();
+ } else {
+ doSpin = false;
+ break;
+ }
+ }
+ }
+ if (!doSpin) {
+ break;
+ }
+ if (RelaxedLoad(&StopFlag)) {
+ break;
+ }
+ }
+ // then - sleep
+ if (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_ACTIVE) {
+ if (AtomicCas(&threadCtx.WaitingFlag, TThreadCtx::WS_BLOCKED, TThreadCtx::WS_ACTIVE)) {
+ do {
+ hpnow = GetCycleCountFast();
+ elapsed += hpnow - hpstart;
+ if (threadCtx.Pad.Park()) // interrupted
+ return 0;
+ hpstart = GetCycleCountFast();
+ parked += hpstart - hpnow;
+ } while (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_BLOCKED);
+ }
+ }
+ } else {
+ AtomicSet(threadCtx.WaitingFlag, TThreadCtx::WS_BLOCKED);
+ do {
+ hpnow = GetCycleCountFast();
+ elapsed += hpnow - hpstart;
+ if (threadCtx.Pad.Park()) // interrupted
+ return 0;
+ hpstart = GetCycleCountFast();
+ parked += hpstart - hpnow;
+ } while (AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_BLOCKED);
+ }
+
+ Y_VERIFY_DEBUG(AtomicLoad(&StopFlag) || AtomicLoad(&threadCtx.WaitingFlag) == TThreadCtx::WS_RUNNING);
+
+#if defined ACTORSLIB_COLLECT_EXEC_STATS
+ if (AtomicDecrement(ThreadUtilization) == 0) {
+ // When we started sleeping counter contained t1-t0, or the
+ // last duration of max utilization. Now we subtract t2 >= t1,
+ // which turns counter negative again, and the next sleep cycle
+ // at timestamp t3 would be adding some new duration t3-t2.
+ // If the counter was positive and becomes negative that means
+ // there are no current races with other threads and we should
+ // store the last positive duration we observed. Multiple
+ // threads may be adding and subtracting values in potentially
+ // arbitrary order, which would cause counter to oscillate
+ // around zero. When it crosses zero is a good indication of a
+ // correct value.
+ const i64 t = GetCycleCountFast();
+ const i64 x = AtomicGetAndAdd(MaxUtilizationCounter, -t);
+ if (x > 0 && x - t < 0)
+ AtomicStore(&MaxUtilizationAccumulator, x);
+ }
+#endif
+ } else {
+ AtomicSet(threadCtx.WaitingFlag, TThreadCtx::WS_RUNNING);
+ }
+
+ // ok, has work suggested, must dequeue
+ while (!RelaxedLoad(&StopFlag)) {
+ if (const ui32 activation = Activations.Pop(++revolvingCounter)) {
+ hpnow = GetCycleCountFast();
+ elapsed += hpnow - hpstart;
+ wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, elapsed);
+ if (parked > 0) {
+ wctx.AddParkedCycles(parked);
+ }
+ if (blocked > 0) {
+ wctx.AddBlockedCycles(blocked);
+ }
+ return activation;
+ }
+ SpinLockPause();
+ }
+
+ // stopping, die!
+ return 0;
+ }
+
+ inline void TBasicExecutorPool::WakeUpLoop() {
+ for (ui32 i = 0;;) {
+ TThreadCtx& threadCtx = Threads[i % PoolThreads];
+ switch (AtomicLoad(&threadCtx.WaitingFlag)) {
+ case TThreadCtx::WS_NONE:
+ case TThreadCtx::WS_RUNNING:
+ ++i;
+ break;
+ case TThreadCtx::WS_ACTIVE: // in active spin-lock, just set flag
+ if (AtomicCas(&threadCtx.WaitingFlag, TThreadCtx::WS_RUNNING, TThreadCtx::WS_ACTIVE)) {
+ return;
+ }
+ break;
+ case TThreadCtx::WS_BLOCKED:
+ if (AtomicCas(&threadCtx.WaitingFlag, TThreadCtx::WS_RUNNING, TThreadCtx::WS_BLOCKED)) {
+ threadCtx.Pad.Unpark();
+ return;
+ }
+ break;
+ default:
+ Y_FAIL();
+ }
+ }
+ }
+
+ void TBasicExecutorPool::ScheduleActivationEx(ui32 activation, ui64 revolvingCounter) {
+ Activations.Push(activation, revolvingCounter);
+ const TAtomic x = AtomicIncrement(Semaphore);
+ if (x <= 0) { // we must find someone to wake-up
+ WakeUpLoop();
+ }
+ }
+
+ void TBasicExecutorPool::GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const {
+ poolStats.MaxUtilizationTime = RelaxedLoad(&MaxUtilizationAccumulator) / (i64)(NHPTimer::GetCyclesPerSecond() / 1000);
+
+ statsCopy.resize(PoolThreads + 1);
+ // Save counters from the pool object
+ statsCopy[0] = TExecutorThreadStats();
+ statsCopy[0].Aggregate(Stats);
+ // Per-thread stats
+ for (size_t i = 0; i < PoolThreads; ++i) {
+ Threads[i].Thread->GetCurrentStats(statsCopy[i + 1]);
+ }
+ }
+
+ void TBasicExecutorPool::Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) {
+ TAffinityGuard affinityGuard(Affinity());
+
+ ActorSystem = actorSystem;
+
+ ScheduleReaders.Reset(new NSchedulerQueue::TReader[PoolThreads]);
+ ScheduleWriters.Reset(new NSchedulerQueue::TWriter[PoolThreads]);
+
+ for (ui32 i = 0; i != PoolThreads; ++i) {
+ Threads[i].Thread.Reset(
+ new TExecutorThread(
+ i,
+ 0, // CpuId is not used in BASIC pool
+ actorSystem,
+ this,
+ MailboxTable.Get(),
+ PoolName,
+ TimePerMailbox,
+ EventsPerMailbox));
+ ScheduleWriters[i].Init(ScheduleReaders[i]);
+ }
+
+ *scheduleReaders = ScheduleReaders.Get();
+ *scheduleSz = PoolThreads;
+ }
+
+ void TBasicExecutorPool::Start() {
+ TAffinityGuard affinityGuard(Affinity());
+
+ ThreadUtilization = 0;
+ AtomicAdd(MaxUtilizationCounter, -(i64)GetCycleCountFast());
+
+ for (ui32 i = 0; i != PoolThreads; ++i) {
+ Threads[i].Thread->Start();
+ }
+ }
+
+ void TBasicExecutorPool::PrepareStop() {
+ AtomicStore(&StopFlag, true);
+ for (ui32 i = 0; i != PoolThreads; ++i) {
+ Threads[i].Pad.Interrupt();
+ Threads[i].BlockedPad.Interrupt();
+ }
+ }
+
+ void TBasicExecutorPool::Shutdown() {
+ for (ui32 i = 0; i != PoolThreads; ++i)
+ Threads[i].Thread->Join();
+ }
+
+ void TBasicExecutorPool::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) {
+ Y_VERIFY_DEBUG(workerId < PoolThreads);
+
+ Schedule(deadline - ActorSystem->Timestamp(), ev, cookie, workerId);
+ }
+
+ void TBasicExecutorPool::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) {
+ Y_VERIFY_DEBUG(workerId < PoolThreads);
+
+ const auto current = ActorSystem->Monotonic();
+ if (deadline < current)
+ deadline = current;
+
+ ScheduleWriters[workerId].Push(deadline.MicroSeconds(), ev.Release(), cookie);
+ }
+
+ void TBasicExecutorPool::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) {
+ Y_VERIFY_DEBUG(workerId < PoolThreads);
+
+ const auto deadline = ActorSystem->Monotonic() + delta;
+ ScheduleWriters[workerId].Push(deadline.MicroSeconds(), ev.Release(), cookie);
+ }
+
+ void TBasicExecutorPool::SetRealTimeMode() const {
+// TODO: musl-libc version of `sched_param` struct is for some reason different from pthread
+// version in Ubuntu 12.04
+#if defined(_linux_) && !defined(_musl_)
+ if (RealtimePriority != 0) {
+ pthread_t threadSelf = pthread_self();
+ sched_param param = {RealtimePriority};
+ if (pthread_setschedparam(threadSelf, SCHED_FIFO, &param)) {
+ Y_FAIL("Cannot set realtime priority");
+ }
+ }
+#else
+ Y_UNUSED(RealtimePriority);
+#endif
+ }
+
+ ui32 TBasicExecutorPool::GetThreadCount() const {
+ return AtomicGet(ThreadCount);
+ }
+
+ void TBasicExecutorPool::SetThreadCount(ui32 threads) {
+ threads = Max(1u, Min(PoolThreads, threads));
+ with_lock (ChangeThreadsLock) {
+ size_t prevCount = GetThreadCount();
+ AtomicSet(ThreadCount, threads);
+ if (prevCount < threads) {
+ for (size_t i = prevCount; i < threads; ++i) {
+ bool repeat = true;
+ while (repeat) {
+ switch (AtomicGet(Threads[i].BlockedFlag)) {
+ case TThreadCtx::BS_BLOCKING:
+ if (AtomicCas(&Threads[i].BlockedFlag, TThreadCtx::BS_NONE, TThreadCtx::BS_BLOCKING)) {
+ // thread not entry to blocked loop
+ repeat = false;
+ }
+ break;
+ case TThreadCtx::BS_BLOCKED:
+ // thread entry to blocked loop and we wake it
+ AtomicSet(Threads[i].BlockedFlag, TThreadCtx::BS_NONE);
+ Threads[i].BlockedPad.Unpark();
+ repeat = false;
+ break;
+ default:
+ // thread mustn't has TThreadCtx::BS_NONE because last time it was started to block
+ Y_FAIL("BlockedFlag is not TThreadCtx::BS_BLOCKING and TThreadCtx::BS_BLOCKED when thread was waked up");
+ }
+ }
+ }
+ } else if (prevCount > threads) {
+ // at first, start to block
+ for (size_t i = threads; i < prevCount; ++i) {
+ Y_VERIFY(AtomicGet(Threads[i].BlockedFlag) == TThreadCtx::BS_NONE);
+ AtomicSet(Threads[i].BlockedFlag, TThreadCtx::BS_BLOCKING);
+ }
+ // after check need to wake up threads
+ for (size_t idx = threads; idx < prevCount; ++idx) {
+ TThreadCtx& threadCtx = Threads[idx];
+ auto waitingFlag = AtomicGet(threadCtx.WaitingFlag);
+ auto blockedFlag = AtomicGet(threadCtx.BlockedFlag);
+ // while thread has this states (WS_NONE and BS_BLOCKING) we can't guess which way thread will go.
+ // Either go to sleep and it will have to wake up,
+ // or go to execute task and after completion will be blocked.
+ while (waitingFlag == TThreadCtx::WS_NONE && blockedFlag == TThreadCtx::BS_BLOCKING) {
+ waitingFlag = AtomicGet(threadCtx.WaitingFlag);
+ blockedFlag = AtomicGet(threadCtx.BlockedFlag);
+ }
+ // next states:
+ // 1) WS_ACTIVE BS_BLOCKING - waiting and start spinig | need wake up to block
+ // 2) WS_BLOCKED BS_BLOCKING - waiting and start sleep | need wake up to block
+ // 3) WS_RUNNING BS_BLOCKING - start execute | not need wake up, will block after executing
+ // 4) WS_NONE BS_BLOCKED - blocked | not need wake up, already blocked
+
+ if (waitingFlag == TThreadCtx::WS_ACTIVE || waitingFlag == TThreadCtx::WS_BLOCKED) {
+ // need wake up
+ Y_VERIFY(blockedFlag == TThreadCtx::BS_BLOCKING);
+
+ // creaty empty mailBoxHint, where LineIndex == 1 and LineHint == 0, and activations will be ignored
+ constexpr auto emptyMailBoxHint = TMailboxTable::LineIndexMask & -TMailboxTable::LineIndexMask;
+ ui64 revolvingCounter = AtomicGet(ActivationsRevolvingCounter);
+
+ Activations.Push(emptyMailBoxHint, revolvingCounter);
+
+ auto x = AtomicIncrement(Semaphore);
+ if (x <= 0) {
+ // try wake up. if success then go to next thread
+ switch (waitingFlag){
+ case TThreadCtx::WS_ACTIVE: // in active spin-lock, just set flag
+ if (AtomicCas(&threadCtx.WaitingFlag, TThreadCtx::WS_RUNNING, TThreadCtx::WS_ACTIVE)) {
+ continue;
+ }
+ break;
+ case TThreadCtx::WS_BLOCKED:
+ if (AtomicCas(&threadCtx.WaitingFlag, TThreadCtx::WS_RUNNING, TThreadCtx::WS_BLOCKED)) {
+ threadCtx.Pad.Unpark();
+ continue;
+ }
+ break;
+ default:
+ ; // other thread woke this sleeping thread
+ }
+ // if thread has already been awakened then we must awaken the other
+ WakeUpLoop();
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/library/cpp/actors/core/executor_pool_basic.h b/library/cpp/actors/core/executor_pool_basic.h
new file mode 100644
index 0000000000..023190f7fe
--- /dev/null
+++ b/library/cpp/actors/core/executor_pool_basic.h
@@ -0,0 +1,111 @@
+#pragma once
+
+#include "actorsystem.h"
+#include "executor_thread.h"
+#include "scheduler_queue.h"
+#include "executor_pool_base.h"
+#include <library/cpp/actors/util/unordered_cache.h>
+#include <library/cpp/actors/util/threadparkpad.h>
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+
+#include <util/system/mutex.h>
+
+namespace NActors {
+ class TBasicExecutorPool: public TExecutorPoolBase {
+ struct TThreadCtx {
+ TAutoPtr<TExecutorThread> Thread;
+ TThreadParkPad Pad;
+ TThreadParkPad BlockedPad;
+ TAtomic WaitingFlag;
+ TAtomic BlockedFlag;
+
+ // different threads must spin/block on different cache-lines.
+ // we add some padding bytes to enforce this rule
+ static const size_t SizeWithoutPadding = sizeof(TAutoPtr<TExecutorThread>) + 2 * sizeof(TThreadParkPad) + 2 * sizeof(TAtomic);
+ ui8 Padding[64 - SizeWithoutPadding];
+ static_assert(64 >= SizeWithoutPadding);
+
+ enum EWaitState {
+ WS_NONE,
+ WS_ACTIVE,
+ WS_BLOCKED,
+ WS_RUNNING
+ };
+
+ enum EBlockedState {
+ BS_NONE,
+ BS_BLOCKING,
+ BS_BLOCKED
+ };
+
+ TThreadCtx()
+ : WaitingFlag(WS_NONE)
+ , BlockedFlag(BS_NONE)
+ {
+ }
+ };
+
+ const ui64 SpinThreshold;
+ const ui64 SpinThresholdCycles;
+
+ TArrayHolder<TThreadCtx> Threads;
+
+ TArrayHolder<NSchedulerQueue::TReader> ScheduleReaders;
+ TArrayHolder<NSchedulerQueue::TWriter> ScheduleWriters;
+
+ const TString PoolName;
+ const TDuration TimePerMailbox;
+ const ui32 EventsPerMailbox;
+
+ const int RealtimePriority;
+
+ TAtomic ThreadUtilization;
+ TAtomic MaxUtilizationCounter;
+ TAtomic MaxUtilizationAccumulator;
+
+ TAtomic ThreadCount;
+ TMutex ChangeThreadsLock;
+
+ public:
+ static constexpr TDuration DEFAULT_TIME_PER_MAILBOX = TBasicExecutorPoolConfig::DEFAULT_TIME_PER_MAILBOX;
+ static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX;
+
+ TBasicExecutorPool(ui32 poolId,
+ ui32 threads,
+ ui64 spinThreshold,
+ const TString& poolName = "",
+ TAffinity* affinity = nullptr,
+ TDuration timePerMailbox = DEFAULT_TIME_PER_MAILBOX,
+ ui32 eventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX,
+ int realtimePriority = 0,
+ ui32 maxActivityType = 1);
+ explicit TBasicExecutorPool(const TBasicExecutorPoolConfig& cfg);
+ ~TBasicExecutorPool();
+
+ ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingReadCounter) override;
+
+ void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override;
+ void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override;
+ void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override;
+
+ void ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) override;
+
+ void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) override;
+ void Start() override;
+ void PrepareStop() override;
+ void Shutdown() override;
+
+ void GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const override;
+ TString GetName() const override {
+ return PoolName;
+ }
+
+ void SetRealTimeMode() const override;
+
+ ui32 GetThreadCount() const;
+ void SetThreadCount(ui32 threads);
+
+ private:
+ void WakeUpLoop();
+ };
+}
diff --git a/library/cpp/actors/core/executor_pool_basic_ut.cpp b/library/cpp/actors/core/executor_pool_basic_ut.cpp
new file mode 100644
index 0000000000..76dff693af
--- /dev/null
+++ b/library/cpp/actors/core/executor_pool_basic_ut.cpp
@@ -0,0 +1,435 @@
+#include "actorsystem.h"
+#include "executor_pool_basic.h"
+#include "hfunc.h"
+#include "scheduler_basic.h"
+
+#include <library/cpp/actors/util/should_continue.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/actors/protos/unittests.pb.h>
+
+using namespace NActors;
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct TEvMsg : public NActors::TEventBase<TEvMsg, 10347> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvMsg, "ExecutorPoolTest: Msg");
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TTestSenderActor : public IActor {
+private:
+ using EActivityType = IActor::EActivityType ;
+ using EActorActivity = IActor::EActorActivity;
+
+private:
+ TAtomic Counter;
+ TActorId Receiver;
+
+ std::function<void(void)> Action;
+
+public:
+ TTestSenderActor(std::function<void(void)> action = [](){},
+ EActivityType activityType = EActorActivity::OTHER)
+ : IActor(static_cast<TReceiveFunc>(&TTestSenderActor::Execute), activityType)
+ , Action(action)
+ {}
+
+ void Start(TActorId receiver, size_t count)
+ {
+ AtomicSet(Counter, count);
+ Receiver = receiver;
+ }
+
+ void Stop() {
+ while (true) {
+ if (GetCounter() == 0) {
+ break;
+ }
+
+ Sleep(TDuration::MilliSeconds(1));
+ }
+ }
+
+ size_t GetCounter() const {
+ return AtomicGet(Counter);
+ }
+
+private:
+ STFUNC(Execute)
+ {
+ Y_UNUSED(ctx);
+ switch (ev->GetTypeRewrite()) {
+ hFunc(TEvMsg, Handle);
+ }
+ }
+
+ void Handle(TEvMsg::TPtr &ev)
+ {
+ Y_UNUSED(ev);
+ Action();
+ TAtomicBase count = AtomicDecrement(Counter);
+ Y_VERIFY(count != Max<TAtomicBase>());
+ if (count) {
+ Send(Receiver, new TEvMsg());
+ }
+ }
+};
+
+THolder<TActorSystemSetup> GetActorSystemSetup(TBasicExecutorPool* pool)
+{
+ auto setup = MakeHolder<NActors::TActorSystemSetup>();
+ setup->NodeId = 1;
+ setup->ExecutorsCount = 1;
+ setup->Executors.Reset(new TAutoPtr<NActors::IExecutorPool>[1]);
+ setup->Executors[0] = pool;
+ setup->Scheduler = new TBasicSchedulerThread(NActors::TSchedulerConfig(512, 0));
+ return setup;
+}
+
+Y_UNIT_TEST_SUITE(BasicExecutorPool) {
+
+ Y_UNIT_TEST(DecreaseIncreaseThreadsCount) {
+ const size_t msgCount = 1e4;
+ const size_t size = 4;
+ const size_t halfSize = size / 2;
+ TBasicExecutorPool* executorPool = new TBasicExecutorPool(0, size, 50);
+
+ auto setup = GetActorSystemSetup(executorPool);
+ TActorSystem actorSystem(setup);
+ actorSystem.Start();
+
+ executorPool->SetThreadCount(halfSize);
+ TTestSenderActor* actors[size];
+ TActorId actorIds[size];
+ for (size_t i = 0; i < size; ++i) {
+ actors[i] = new TTestSenderActor();
+ actorIds[i] = actorSystem.Register(actors[i]);
+ }
+
+ const int testCount = 2;
+
+ TExecutorPoolStats poolStats[testCount];
+ TVector<TExecutorThreadStats> statsCopy[testCount];
+
+ for (size_t testIdx = 0; testIdx < testCount; ++testIdx) {
+ for (size_t i = 0; i < size; ++i) {
+ actors[i]->Start(actors[i]->SelfId(), msgCount);
+ }
+ for (size_t i = 0; i < size; ++i) {
+ actorSystem.Send(actorIds[i], new TEvMsg());
+ }
+
+ Sleep(TDuration::MilliSeconds(100));
+
+ for (size_t i = 0; i < size; ++i) {
+ actors[i]->Stop();
+ }
+
+ executorPool->GetCurrentStats(poolStats[testIdx], statsCopy[testIdx]);
+ }
+
+ for (size_t i = 1; i <= halfSize; ++i) {
+ UNIT_ASSERT_UNEQUAL(statsCopy[0][i].ReceivedEvents, statsCopy[1][i].ReceivedEvents);
+ }
+
+ for (size_t i = halfSize + 1; i <= size; ++i) {
+ UNIT_ASSERT_EQUAL(statsCopy[0][i].ReceivedEvents, statsCopy[1][i].ReceivedEvents);
+ }
+
+ executorPool->SetThreadCount(size);
+
+ for (size_t testIdx = 0; testIdx < testCount; ++testIdx) {
+ for (size_t i = 0; i < size; ++i) {
+ actors[i]->Start(actors[i]->SelfId(), msgCount);
+ }
+ for (size_t i = 0; i < size; ++i) {
+ actorSystem.Send(actorIds[i], new TEvMsg());
+ }
+
+ Sleep(TDuration::MilliSeconds(100));
+
+ for (size_t i = 0; i < size; ++i) {
+ actors[i]->Stop();
+ }
+
+ executorPool->GetCurrentStats(poolStats[testIdx], statsCopy[testIdx]);
+ }
+
+ for (size_t i = 1; i <= size; ++i) {
+ UNIT_ASSERT_UNEQUAL(statsCopy[0][i].ReceivedEvents, statsCopy[1][i].ReceivedEvents);
+ }
+ }
+
+ Y_UNIT_TEST(ChangeCount) {
+ const size_t msgCount = 1e3;
+ const size_t size = 4;
+ const size_t halfSize = size / 2;
+ TBasicExecutorPool* executorPool = new TBasicExecutorPool(0, size, 50);
+
+ auto begin = TInstant::Now();
+
+ auto setup = GetActorSystemSetup(executorPool);
+ TActorSystem actorSystem(setup);
+ actorSystem.Start();
+ executorPool->SetThreadCount(halfSize);
+
+ TTestSenderActor* actors[size];
+ TActorId actorIds[size];
+ for (size_t i = 0; i < size; ++i) {
+ actors[i] = new TTestSenderActor();
+ actorIds[i] = actorSystem.Register(actors[i]);
+ }
+
+ for (size_t i = 0; i < size; ++i) {
+ actors[i]->Start(actorIds[i], msgCount);
+ }
+ for (size_t i = 0; i < size; ++i) {
+ actorSystem.Send(actorIds[i], new TEvMsg());
+ }
+
+ const i32 N = 6;
+ const i32 threadsCouns[N] = { 1, 3, 2, 3, 1, 4 };
+
+ ui64 counter = 0;
+
+ TTestSenderActor* changerActor = new TTestSenderActor([&]{
+ executorPool->SetThreadCount(threadsCouns[counter]);
+ counter++;
+ if (counter == N) {
+ counter = 0;
+ }
+ });
+ TActorId changerActorId = actorSystem.Register(changerActor);
+ changerActor->Start(changerActorId, msgCount);
+ actorSystem.Send(changerActorId, new TEvMsg());
+
+ while (true) {
+ size_t maxCounter = 0;
+ for (size_t i = 0; i < size; ++i) {
+ maxCounter = Max(maxCounter, actors[i]->GetCounter());
+ }
+
+ if (maxCounter == 0) {
+ break;
+ }
+
+ auto now = TInstant::Now();
+ UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Max counter is " << maxCounter);
+
+ Sleep(TDuration::MilliSeconds(1));
+ }
+
+ changerActor->Stop();
+ }
+
+ Y_UNIT_TEST(CheckCompleteOne) {
+ const size_t size = 4;
+ const size_t msgCount = 1e4;
+ TBasicExecutorPool* executorPool = new TBasicExecutorPool(0, size, 50);
+
+ auto setup = GetActorSystemSetup(executorPool);
+ TActorSystem actorSystem(setup);
+ actorSystem.Start();
+
+ auto begin = TInstant::Now();
+
+ auto actor = new TTestSenderActor();
+ auto actorId = actorSystem.Register(actor);
+ actor->Start(actor->SelfId(), msgCount);
+ actorSystem.Send(actorId, new TEvMsg());
+
+ while (actor->GetCounter()) {
+ auto now = TInstant::Now();
+ UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Counter is " << actor->GetCounter());
+
+ Sleep(TDuration::MilliSeconds(1));
+ }
+ }
+
+ Y_UNIT_TEST(CheckCompleteAll) {
+ const size_t size = 4;
+ const size_t msgCount = 1e4;
+ TBasicExecutorPool* executorPool = new TBasicExecutorPool(0, size, 50);
+
+ auto setup = GetActorSystemSetup(executorPool);
+ TActorSystem actorSystem(setup);
+ actorSystem.Start();
+
+ auto begin = TInstant::Now();
+
+ TTestSenderActor* actors[size];
+ TActorId actorIds[size];
+
+ for (size_t i = 0; i < size; ++i) {
+ actors[i] = new TTestSenderActor();
+ actorIds[i] = actorSystem.Register(actors[i]);
+ }
+ for (size_t i = 0; i < size; ++i) {
+ actors[i]->Start(actors[i]->SelfId(), msgCount);
+ }
+ for (size_t i = 0; i < size; ++i) {
+ actorSystem.Send(actorIds[i], new TEvMsg());
+ }
+
+
+ while (true) {
+ size_t maxCounter = 0;
+ for (size_t i = 0; i < size; ++i) {
+ maxCounter = Max(maxCounter, actors[i]->GetCounter());
+ }
+
+ if (maxCounter == 0) {
+ break;
+ }
+
+ auto now = TInstant::Now();
+ UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Max counter is " << maxCounter);
+
+ Sleep(TDuration::MilliSeconds(1));
+ }
+ }
+
+ Y_UNIT_TEST(CheckCompleteOver) {
+ const size_t size = 4;
+ const size_t actorsCount = size * 2;
+ const size_t msgCount = 1e4;
+ TBasicExecutorPool* executorPool = new TBasicExecutorPool(0, size, 50);
+
+ auto setup = GetActorSystemSetup(executorPool);
+ TActorSystem actorSystem(setup);
+ actorSystem.Start();
+
+ auto begin = TInstant::Now();
+
+ TTestSenderActor* actors[actorsCount];
+ TActorId actorIds[actorsCount];
+
+ for (size_t i = 0; i < actorsCount; ++i) {
+ actors[i] = new TTestSenderActor();
+ actorIds[i] = actorSystem.Register(actors[i]);
+ }
+ for (size_t i = 0; i < actorsCount; ++i) {
+ actors[i]->Start(actors[i]->SelfId(), msgCount);
+ }
+ for (size_t i = 0; i < actorsCount; ++i) {
+ actorSystem.Send(actorIds[i], new TEvMsg());
+ }
+
+
+ while (true) {
+ size_t maxCounter = 0;
+ for (size_t i = 0; i < actorsCount; ++i) {
+ maxCounter = Max(maxCounter, actors[i]->GetCounter());
+ }
+
+ if (maxCounter == 0) {
+ break;
+ }
+
+ auto now = TInstant::Now();
+ UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Max counter is " << maxCounter);
+
+ Sleep(TDuration::MilliSeconds(1));
+ }
+ }
+
+ Y_UNIT_TEST(CheckCompleteRoundRobinOver) {
+ const size_t size = 4;
+ const size_t actorsCount = size * 2;
+ const size_t msgCount = 1e2;
+ TBasicExecutorPool* executorPool = new TBasicExecutorPool(0, size, 50);
+
+ auto setup = GetActorSystemSetup(executorPool);
+ TActorSystem actorSystem(setup);
+ actorSystem.Start();
+
+ auto begin = TInstant::Now();
+
+ TTestSenderActor* actors[actorsCount];
+ TActorId actorIds[actorsCount];
+
+ for (size_t i = 0; i < actorsCount; ++i) {
+ actors[i] = new TTestSenderActor();
+ actorIds[i] = actorSystem.Register(actors[i]);
+ }
+ for (size_t i = 0; i < actorsCount; ++i) {
+ actors[i]->Start(actorIds[(i + 1) % actorsCount], msgCount);
+ }
+ for (size_t i = 0; i < actorsCount; ++i) {
+ actorSystem.Send(actorIds[i], new TEvMsg());
+ }
+
+ while (true) {
+ size_t maxCounter = 0;
+ for (size_t i = 0; i < actorsCount; ++i) {
+ maxCounter = Max(maxCounter, actors[i]->GetCounter());
+ }
+
+ if (maxCounter == 0) {
+ break;
+ }
+
+ auto now = TInstant::Now();
+ UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Max counter is " << maxCounter);
+
+ Sleep(TDuration::MilliSeconds(1));
+ }
+ }
+
+ Y_UNIT_TEST(CheckStats) {
+ const size_t size = 4;
+ const size_t msgCount = 1e4;
+ TBasicExecutorPool* executorPool = new TBasicExecutorPool(0, size, 50);
+
+ auto setup = GetActorSystemSetup(executorPool);
+ TActorSystem actorSystem(setup);
+ actorSystem.Start();
+
+ auto begin = TInstant::Now();
+
+ auto actor = new TTestSenderActor();
+ auto actorId = actorSystem.Register(actor);
+ actor->Start(actor->SelfId(), msgCount);
+ actorSystem.Send(actorId, new TEvMsg());
+
+ while (actor->GetCounter()) {
+ auto now = TInstant::Now();
+ UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Counter is " << actor->GetCounter());
+
+ Sleep(TDuration::MilliSeconds(1));
+ }
+
+ TVector<TExecutorThreadStats> stats;
+ TExecutorPoolStats poolStats;
+ actorSystem.GetPoolStats(0, poolStats, stats);
+ // Sum all per-thread counters into the 0th element
+ for (ui32 idx = 1; idx < stats.size(); ++idx) {
+ stats[0].Aggregate(stats[idx]);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].SentEvents, msgCount - 1);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].PreemptedEvents, 0);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].NonDeliveredEvents, 0);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].EmptyMailboxActivation, 0);
+ //UNIT_ASSERT_VALUES_EQUAL(stats[0].CpuNs, 0); // depends on total duration of test, so undefined
+ UNIT_ASSERT(stats[0].ElapsedTicks > 0);
+ UNIT_ASSERT(stats[0].ParkedTicks > 0);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].BlockedTicks, 0);
+ UNIT_ASSERT(stats[0].ActivationTimeHistogram.TotalSamples >= msgCount / TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].EventDeliveryTimeHistogram.TotalSamples, msgCount);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].EventProcessingCountHistogram.TotalSamples, msgCount);
+ UNIT_ASSERT(stats[0].EventProcessingTimeHistogram.TotalSamples > 0);
+ UNIT_ASSERT(stats[0].ElapsedTicksByActivity[0] > 0);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEventsByActivity[0], msgCount);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].ActorsAliveByActivity[0], 1);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].ScheduledEventsByActivity[0], 0);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolDestroyedActors, 0);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolAllocatedMailboxes, 4095); // one line
+ UNIT_ASSERT(stats[0].MailboxPushedOutByTime + stats[0].MailboxPushedOutByEventCount >= msgCount / TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].MailboxPushedOutBySoftPreemption, 0);
+ }
+}
diff --git a/library/cpp/actors/core/executor_pool_io.cpp b/library/cpp/actors/core/executor_pool_io.cpp
new file mode 100644
index 0000000000..fb557ae6b0
--- /dev/null
+++ b/library/cpp/actors/core/executor_pool_io.cpp
@@ -0,0 +1,151 @@
+#include "executor_pool_io.h"
+#include "mailbox.h"
+#include <library/cpp/actors/util/affinity.h>
+#include <library/cpp/actors/util/datetime.h>
+
+namespace NActors {
+ TIOExecutorPool::TIOExecutorPool(ui32 poolId, ui32 threads, const TString& poolName, TAffinity* affinity, ui32 maxActivityType)
+ : TExecutorPoolBase(poolId, threads, affinity, maxActivityType)
+ , Threads(new TThreadCtx[threads])
+ , PoolName(poolName)
+ {}
+
+ TIOExecutorPool::TIOExecutorPool(const TIOExecutorPoolConfig& cfg)
+ : TIOExecutorPool(
+ cfg.PoolId,
+ cfg.Threads,
+ cfg.PoolName,
+ new TAffinity(cfg.Affinity),
+ cfg.MaxActivityType
+ )
+ {}
+
+ TIOExecutorPool::~TIOExecutorPool() {
+ Threads.Destroy();
+ while (ThreadQueue.Pop(0))
+ ;
+ }
+
+ ui32 TIOExecutorPool::GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) {
+ ui32 workerId = wctx.WorkerId;
+ Y_VERIFY_DEBUG(workerId < PoolThreads);
+
+ NHPTimer::STime elapsed = 0;
+ NHPTimer::STime parked = 0;
+ NHPTimer::STime hpstart = GetCycleCountFast();
+ NHPTimer::STime hpnow;
+
+ const TAtomic x = AtomicDecrement(Semaphore);
+ if (x < 0) {
+ TThreadCtx& threadCtx = Threads[workerId];
+ ThreadQueue.Push(workerId + 1, revolvingCounter);
+ hpnow = GetCycleCountFast();
+ elapsed += hpnow - hpstart;
+ if (threadCtx.Pad.Park())
+ return 0;
+ hpstart = GetCycleCountFast();
+ parked += hpstart - hpnow;
+ }
+
+ while (!RelaxedLoad(&StopFlag)) {
+ if (const ui32 activation = Activations.Pop(++revolvingCounter)) {
+ hpnow = GetCycleCountFast();
+ elapsed += hpnow - hpstart;
+ wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, elapsed);
+ if (parked > 0) {
+ wctx.AddParkedCycles(parked);
+ }
+ return activation;
+ }
+ SpinLockPause();
+ }
+
+ return 0;
+ }
+
+ void TIOExecutorPool::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) {
+ Schedule(deadline - ActorSystem->Timestamp(), ev, cookie, workerId);
+ }
+
+ void TIOExecutorPool::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) {
+ Y_UNUSED(workerId);
+
+ const auto current = ActorSystem->Monotonic();
+ if (deadline < current)
+ deadline = current;
+
+ TTicketLock::TGuard guard(&ScheduleLock);
+ ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie);
+ }
+
+ void TIOExecutorPool::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) {
+ Y_UNUSED(workerId);
+ const auto deadline = ActorSystem->Monotonic() + delta;
+
+ TTicketLock::TGuard guard(&ScheduleLock);
+ ScheduleQueue->Writer.Push(deadline.MicroSeconds(), ev.Release(), cookie);
+ }
+
+ void TIOExecutorPool::ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) {
+ Activations.Push(activation, revolvingWriteCounter);
+ const TAtomic x = AtomicIncrement(Semaphore);
+ if (x <= 0) {
+ for (;; ++revolvingWriteCounter) {
+ if (const ui32 x = ThreadQueue.Pop(revolvingWriteCounter)) {
+ const ui32 threadIdx = x - 1;
+ Threads[threadIdx].Pad.Unpark();
+ return;
+ }
+ SpinLockPause();
+ }
+ }
+ }
+
+ void TIOExecutorPool::Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) {
+ TAffinityGuard affinityGuard(Affinity());
+
+ ActorSystem = actorSystem;
+
+ ScheduleQueue.Reset(new NSchedulerQueue::TQueueType());
+
+ for (ui32 i = 0; i != PoolThreads; ++i) {
+ Threads[i].Thread.Reset(new TExecutorThread(i, 0, actorSystem, this, MailboxTable.Get(), PoolName));
+ }
+
+ *scheduleReaders = &ScheduleQueue->Reader;
+ *scheduleSz = 1;
+ }
+
+ void TIOExecutorPool::Start() {
+ TAffinityGuard affinityGuard(Affinity());
+
+ for (ui32 i = 0; i != PoolThreads; ++i)
+ Threads[i].Thread->Start();
+ }
+
+ void TIOExecutorPool::PrepareStop() {
+ AtomicStore(&StopFlag, true);
+ for (ui32 i = 0; i != PoolThreads; ++i)
+ Threads[i].Pad.Interrupt();
+ }
+
+ void TIOExecutorPool::Shutdown() {
+ for (ui32 i = 0; i != PoolThreads; ++i)
+ Threads[i].Thread->Join();
+ }
+
+ void TIOExecutorPool::GetCurrentStats(TExecutorPoolStats& /*poolStats*/, TVector<TExecutorThreadStats>& statsCopy) const {
+ statsCopy.resize(PoolThreads + 1);
+ // Save counters from the pool object
+ statsCopy[0] = TExecutorThreadStats();
+ statsCopy[0].Aggregate(Stats);
+ // Per-thread stats
+ for (size_t i = 0; i < PoolThreads; ++i) {
+ Threads[i].Thread->GetCurrentStats(statsCopy[i + 1]);
+ }
+ }
+
+ TString TIOExecutorPool::GetName() const {
+ return PoolName;
+ }
+}
diff --git a/library/cpp/actors/core/executor_pool_io.h b/library/cpp/actors/core/executor_pool_io.h
new file mode 100644
index 0000000000..e576d642a1
--- /dev/null
+++ b/library/cpp/actors/core/executor_pool_io.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "actorsystem.h"
+#include "executor_thread.h"
+#include "scheduler_queue.h"
+#include "executor_pool_base.h"
+#include <library/cpp/actors/util/ticket_lock.h>
+#include <library/cpp/actors/util/unordered_cache.h>
+#include <library/cpp/actors/util/threadparkpad.h>
+#include <util/system/condvar.h>
+
+namespace NActors {
+ class TIOExecutorPool: public TExecutorPoolBase {
+ struct TThreadCtx {
+ TAutoPtr<TExecutorThread> Thread;
+ TThreadParkPad Pad;
+ };
+
+ TArrayHolder<TThreadCtx> Threads;
+ TUnorderedCache<ui32, 512, 4> ThreadQueue;
+
+ THolder<NSchedulerQueue::TQueueType> ScheduleQueue;
+ TTicketLock ScheduleLock;
+
+ const TString PoolName;
+
+ public:
+ TIOExecutorPool(ui32 poolId, ui32 threads, const TString& poolName = "", TAffinity* affinity = nullptr,
+ ui32 maxActivityType = 1);
+ explicit TIOExecutorPool(const TIOExecutorPoolConfig& cfg);
+ ~TIOExecutorPool();
+
+ ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override;
+
+ void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override;
+ void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override;
+ void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override;
+
+ void ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) override;
+
+ void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) override;
+ void Start() override;
+ void PrepareStop() override;
+ void Shutdown() override;
+
+ void GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const override;
+ TString GetName() const override;
+ };
+}
diff --git a/library/cpp/actors/core/executor_pool_united.cpp b/library/cpp/actors/core/executor_pool_united.cpp
new file mode 100644
index 0000000000..dac6245635
--- /dev/null
+++ b/library/cpp/actors/core/executor_pool_united.cpp
@@ -0,0 +1,1428 @@
+#include "executor_pool_united.h"
+
+#include "balancer.h"
+#include "cpu_state.h"
+#include "executor_thread.h"
+#include "probes.h"
+#include "mailbox.h"
+#include "scheduler_queue.h"
+#include <library/cpp/actors/util/affinity.h>
+#include <library/cpp/actors/util/datetime.h>
+#include <library/cpp/actors/util/futex.h>
+#include <library/cpp/actors/util/intrinsics.h>
+#include <library/cpp/actors/util/timerfd.h>
+
+#include <util/system/datetime.h>
+#include <util/system/hp_timer.h>
+
+#include <algorithm>
+
+namespace NActors {
+ LWTRACE_USING(ACTORLIB_PROVIDER);
+
+ struct TUnitedWorkers::TWorker: public TNonCopyable {
+ TAutoPtr<TExecutorThread> Thread;
+ volatile TThreadId ThreadId = UnknownThreadId;
+ NSchedulerQueue::TQueueType SchedulerQueue;
+ };
+
+ struct TUnitedWorkers::TPool: public TNonCopyable {
+ TAtomic Waiters = 0; // Number of idle cpus, waiting for activations in this pool
+ char Padding[64 - sizeof(TAtomic)];
+
+ TUnorderedCache<ui32, 512, 4> Activations; // MPMC-queue for mailbox activations
+ TAtomic Active = 0; // Number of mailboxes ready for execution or currently executing
+ TAtomic Tokens = 0; // Pending tokens (token is required for worker to start execution, guarantees concurrency limit and activation availability)
+ volatile bool StopFlag = false;
+
+ // Configuration
+ TPoolId PoolId;
+ TAtomicBase Concurrency; // Max concurrent workers running this pool
+ IExecutorPool* ExecutorPool;
+ TMailboxTable* MailboxTable;
+ ui64 TimePerMailboxTs;
+ ui32 EventsPerMailbox;
+
+ // Cpus this pool is allowed to run on
+ // Cpus are specified in wake order
+ TStackVec<TCpu*, 15> WakeOrderCpus;
+
+ ~TPool() {
+ while (Activations.Pop(0)) {}
+ }
+
+ void Stop() {
+ AtomicStore(&StopFlag, true);
+ }
+
+ bool IsUnited() const {
+ return WakeOrderCpus.size();
+ }
+
+ // Add activation of newly scheduled mailbox. Returns generated token (unless concurrency is exceeded)
+ bool PushActivation(ui32 activation, ui64 revolvingCounter) {
+ Activations.Push(activation, revolvingCounter);
+ TAtomicBase active = AtomicIncrement(Active);
+ if (active <= Concurrency) { // token generated
+ AtomicIncrement(Tokens);
+ return true;
+ }
+ return false;
+ }
+
+ template <bool Relaxed>
+ static bool TryAcquireTokenImpl(TAtomic* tokens) {
+ while (true) {
+ TAtomicBase value;
+ if constexpr (Relaxed) {
+ value = RelaxedLoad(tokens);
+ } else {
+ value = AtomicLoad(tokens);
+ }
+ if (value > 0) {
+ if (AtomicCas(tokens, value - 1, value)) {
+ return true; // token acquired
+ }
+ } else {
+ return false; // no more tokens
+ }
+ }
+ }
+
+ // Try acquire pending token. Must be done before execution
+ bool TryAcquireToken() {
+ return TryAcquireTokenImpl<false>(&Tokens);
+ }
+
+ // Try acquire pending token. Must be done before execution
+ bool TryAcquireTokenRelaxed() {
+ return TryAcquireTokenImpl<true>(&Tokens);
+ }
+
+ // Get activation. Requires acquired token.
+ void BeginExecution(ui32& activation, ui64 revolvingCounter) {
+ while (!RelaxedLoad(&StopFlag)) {
+ if (activation = Activations.Pop(++revolvingCounter)) {
+ return;
+ }
+ SpinLockPause();
+ }
+ activation = 0; // should stop
+ }
+
+ // End currently active execution and start new one if token is available.
+ // Reuses token if it's not destroyed.
+ // Returned `true` means successful switch, `activation` is filled.
+ // Returned `false` means execution has ended, no need to call StopExecution()
+ bool NextExecution(ui32& activation, ui64 revolvingCounter) {
+ if (AtomicDecrement(Active) >= Concurrency) { // reuse just released token
+ BeginExecution(activation, revolvingCounter);
+ return true;
+ } else if (TryAcquireToken()) { // another token acquired
+ BeginExecution(activation, revolvingCounter);
+ return true;
+ }
+ return false; // no more tokens available
+ }
+
+ // Stop active execution. Returns released token (unless it is destroyed)
+ bool StopExecution() {
+ TAtomicBase active = AtomicDecrement(Active);
+ if (active >= Concurrency) { // token released
+ AtomicIncrement(Tokens);
+ return true;
+ }
+ return false; // token destroyed
+ }
+
+ // Switch worker context into this pool
+ void Switch(TWorkerContext& wctx, ui64 softDeadlineTs, TExecutorThreadStats& stats) {
+ wctx.Switch(ExecutorPool, MailboxTable, TimePerMailboxTs, EventsPerMailbox, softDeadlineTs, &stats);
+ }
+ };
+
+ class TPoolScheduler {
+ class TSchedulable {
+ // Lower PoolBits store PoolId
+ // All other higher bits store virtual runtime in cycles
+ using TValue = ui64;
+ TValue Value;
+
+ static constexpr ui64 PoolIdMask = ui64((1ull << PoolBits) - 1);
+ static constexpr ui64 VRunTsMask = ~PoolIdMask;
+
+ public:
+ explicit TSchedulable(TPoolId poolId = MaxPools, ui64 vrunts = 0)
+ : Value((poolId & PoolIdMask) | (vrunts & VRunTsMask))
+ {}
+
+ TPoolId GetPoolId() const {
+ return Value & PoolIdMask;
+ }
+
+ ui64 GetVRunTs() const {
+ // Do not truncate pool id
+ // NOTE: it decrease accuracy, but improves performance
+ return Value;
+ }
+
+ ui64 GetPreciseVRunTs() const {
+ return Value & VRunTsMask;
+ }
+
+ void SetVRunTs(ui64 vrunts) {
+ Value = (Value & PoolIdMask) | (vrunts & VRunTsMask);
+ }
+
+ void Account(ui64 base, ui64 ts) {
+ // Add at least minimum amount to change Value
+ SetVRunTs(base + Max(ts, PoolIdMask + 1));
+ }
+ };
+
+ // For min-heap of Items
+ struct TCmp {
+ bool operator()(TSchedulable lhs, TSchedulable rhs) const {
+ return lhs.GetVRunTs() > rhs.GetVRunTs();
+ }
+ };
+
+ TPoolId Size = 0; // total number of pools on this cpu
+ TPoolId Current = 0; // index of current pool in `Items`
+
+ // At the beginning `Current` items are orginized as binary min-heap -- ready to be scheduled
+ // The rest `Size - Current` items are unordered (required to keep track of last vrunts)
+ TSchedulable Items[MaxPools]; // virtual runtime in cycles for each pool
+ ui64 MinVRunTs = 0; // virtual runtime used by waking pools (system's vrunts)
+ ui64 Ts = 0; // real timestamp of current execution start (for accounting)
+
+ // Maps PoolId into it's inverse weight
+ ui64 InvWeights[MaxPools];
+ static constexpr ui64 VRunTsOverflow = ui64(1ull << 62ull) / MaxPoolWeight;
+
+ public:
+ void AddPool(TPoolId pool, TPoolWeight weight) {
+ Items[Size] = TSchedulable(pool, MinVRunTs);
+ Size++;
+ InvWeights[pool] = MaxPoolWeight / std::clamp(weight ? weight : DefPoolWeight, MinPoolWeight, MaxPoolWeight);
+ }
+
+ // Iterate over pools in scheduling order
+ // should be used in construction:
+ // for (TPoolId pool = Begin(); pool != End(); pool = Next())
+ TPoolId Begin() {
+ // Wrap vruntime around to avoid overflow, if required
+ if (Y_UNLIKELY(MinVRunTs >= VRunTsOverflow)) {
+ for (TPoolId i = 0; i < Size; i++) {
+ ui64 ts = Items[i].GetPreciseVRunTs();
+ Items[i].SetVRunTs(ts >= VRunTsOverflow ? ts - VRunTsOverflow : 0);
+ }
+ MinVRunTs -= VRunTsOverflow;
+ }
+ Current = Size;
+ std::make_heap(Items, Items + Current, TCmp());
+ return Next();
+ }
+
+ constexpr TPoolId End() const {
+ return MaxPools;
+ }
+
+ TPoolId Next() {
+ if (Current > 0) {
+ std::pop_heap(Items, Items + Current, TCmp());
+ Current--;
+ return CurrentPool();
+ } else {
+ return End();
+ }
+ }
+
+ // Scheduling was successful, we are going to run CurrentPool()
+ void Scheduled() {
+ MinVRunTs = Max(MinVRunTs, Items[Current].GetPreciseVRunTs());
+ // NOTE: Ts is propagated on Account() to avoid gaps
+ }
+
+ // Schedule specific pool that woke up cpu after idle
+ void ScheduledAfterIdle(TPoolId pool, ui64 ts) {
+ if (Y_UNLIKELY(ts < Ts)) { // anomaly: time goes backwards (e.g. rdtsc is reset to zero on cpu reset)
+ Ts = ts; // just skip anomalous time slice
+ return;
+ }
+ MinVRunTs += (ts - Ts) * (MaxPoolWeight / DefPoolWeight); // propagate system's vrunts to blur difference between pools
+ Ts = ts; // propagate time w/o accounting to any pool
+
+ // Set specified pool as current, it requires scan
+ for (Current = 0; Current < Size && pool != Items[Current].GetPoolId(); Current++) {}
+ Y_VERIFY(Current < Size);
+ }
+
+ // Account currently running pool till now (ts)
+ void Account(ui64 ts) {
+ // Skip time slice for the first run and when time goes backwards (e.g. rdtsc is reset to zero on cpu reset)
+ if (Y_LIKELY(Ts > 0 && Ts <= ts)) {
+ TPoolId pool = CurrentPool();
+ Y_VERIFY(pool < MaxPools);
+ Items[Current].Account(MinVRunTs, (ts - Ts) * InvWeights[pool]);
+ }
+ Ts = ts; // propagate time
+ }
+
+ TPoolId CurrentPool() const {
+ return Items[Current].GetPoolId();
+ }
+ };
+
+ // Cyclic array of timers for idle workers to wait for hard preemption on
+ struct TIdleQueue: public TNonCopyable {
+ TArrayHolder<TTimerFd> Timers;
+ size_t Size;
+ TAtomic EnqueueCounter = 0;
+ TAtomic DequeueCounter = 0;
+
+ explicit TIdleQueue(size_t size)
+ : Timers(new TTimerFd[size])
+ , Size(size)
+ {}
+
+ void Stop() {
+ for (size_t i = 0; i < Size; i++) {
+ Timers[i].Wake();
+ }
+ }
+
+ // Returns timer which new idle-worker should wait for
+ TTimerFd* Enqueue() {
+ return &Timers[AtomicGetAndIncrement(EnqueueCounter) % Size];
+ }
+
+ // Returns timer that hard preemption should trigger to wake idle-worker
+ TTimerFd* Dequeue() {
+ return &Timers[AtomicGetAndIncrement(DequeueCounter) % Size];
+ }
+ };
+
+ // Base class for cpu-local managers that help workers on single cpu to cooperate
+ struct TCpuLocalManager: public TThrRefBase {
+ TUnitedWorkers* United;
+
+ explicit TCpuLocalManager(TUnitedWorkers* united)
+ : United(united)
+ {}
+
+ virtual TWorkerId WorkerCount() const = 0;
+ virtual void AddWorker(TWorkerId workerId) = 0;
+ virtual void Stop() = 0;
+ };
+
+ // Represents cpu with single associated worker that is able to execute any pool.
+ // It always executes pool assigned by balancer and switch pool only if assigned pool has changed
+ struct TAssignedCpu: public TCpuLocalManager {
+ bool Started = false;
+
+ TAssignedCpu(TUnitedWorkers* united)
+ : TCpuLocalManager(united)
+ {}
+
+ TWorkerId WorkerCount() const override {
+ return 1;
+ }
+
+ void AddWorker(TWorkerId workerId) override {
+ Y_UNUSED(workerId);
+ }
+
+ ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) {
+ ui32 activation;
+ if (Y_UNLIKELY(!Started)) {
+ Started = true;
+ } else if (Y_UNLIKELY(United->IsPoolReassigned(wctx))) {
+ United->StopExecution(wctx.PoolId); // stop current execution and switch pool if reassigned
+ } else if (United->NextExecution(wctx.PoolId, activation, revolvingCounter)) {
+ return activation; // another activation from currently executing pool (or 0 if stopped)
+ }
+
+ // Switch to another pool, it blocks until token is acquired
+ if (Y_UNLIKELY(!SwitchPool(wctx))) {
+ return 0; // stopped
+ }
+ United->SwitchPool(wctx, 0);
+ United->BeginExecution(wctx.PoolId, activation, revolvingCounter);
+ return activation;
+ }
+
+ void Stop() override {
+ }
+
+ private:
+ // Sets next pool to run, and acquires token, blocks if there are no tokens
+ bool SwitchPool(TWorkerContext& wctx) {
+ if (Y_UNLIKELY(United->IsStopped())) {
+ return false;
+ }
+
+ // Run balancer (if it's time to)
+ United->Balance();
+
+ // Select pool to execute
+ wctx.PoolId = United->AssignedPool(wctx);
+ Y_VERIFY(wctx.PoolId != CpuShared);
+ if (United->TryAcquireToken(wctx.PoolId)) {
+ return true;
+ }
+
+ // No more work -- wait for activations (spinning, then blocked)
+ wctx.PoolId = United->Idle(wctx.PoolId, wctx);
+
+ // Wakeup or stop occured
+ if (Y_UNLIKELY(wctx.PoolId == CpuStopped)) {
+ return false;
+ }
+ return true; // United->Idle() has already acquired token
+ }
+ };
+
+ // Lock-free data structure that help workers on single cpu to discover their state and do hard preemptions
+ struct TSharedCpu: public TCpuLocalManager {
+ // Current lease
+ volatile TLease::TValue CurrentLease;
+ char Padding1[64 - sizeof(TLease)];
+
+ // Slow pools
+ // the highest bit: 1=wait-for-slow-workers mode 0=else
+ // any lower bit (poolId is bit position): 1=pool-is-slow 0=pool-is-fast
+ volatile TPoolsMask SlowPoolsMask = 0;
+ char Padding2[64 - sizeof(TPoolsMask)];
+
+ // Must be accessed under never expiring lease to avoid races
+ TPoolScheduler PoolSched;
+ TWorkerId FastWorker = MaxWorkers;
+ TTimerFd* PreemptionTimer = nullptr;
+ ui64 HardPreemptionTs = 0;
+ bool Started = false;
+
+ TIdleQueue IdleQueue;
+
+ struct TConfig {
+ const TCpuId CpuId;
+ const TWorkerId Workers;
+ ui64 SoftLimitTs;
+ ui64 HardLimitTs;
+ ui64 EventLimitTs;
+ ui64 LimitPrecisionTs;
+ const int IdleWorkerPriority;
+ const int FastWorkerPriority;
+ const bool NoRealtime;
+ const bool NoAffinity;
+ const TCpuAllocation CpuAlloc;
+
+ TConfig(const TCpuAllocation& allocation, const TUnitedWorkersConfig& united)
+ : CpuId(allocation.CpuId)
+ , Workers(allocation.AllowedPools.size() + 1)
+ , SoftLimitTs(Us2Ts(united.PoolLimitUs))
+ , HardLimitTs(Us2Ts(united.PoolLimitUs + united.EventLimitUs))
+ , EventLimitTs(Us2Ts(united.EventLimitUs))
+ , LimitPrecisionTs(Us2Ts(united.LimitPrecisionUs))
+ , IdleWorkerPriority(std::clamp<ui64>(united.IdleWorkerPriority ? united.IdleWorkerPriority : 20, 1, 99))
+ , FastWorkerPriority(std::clamp<ui64>(united.FastWorkerPriority ? united.FastWorkerPriority : 10, 1, IdleWorkerPriority - 1))
+ , NoRealtime(united.NoRealtime)
+ , NoAffinity(united.NoAffinity)
+ , CpuAlloc(allocation)
+ {}
+ };
+
+ TConfig Config;
+ TVector<TWorkerId> Workers;
+
+ TSharedCpu(const TConfig& cfg, TUnitedWorkers* united)
+ : TCpuLocalManager(united)
+ , IdleQueue(cfg.Workers)
+ , Config(cfg)
+ {
+ for (const auto& pa : Config.CpuAlloc.AllowedPools) {
+ PoolSched.AddPool(pa.PoolId, pa.Weight);
+ }
+ }
+
+ TWorkerId WorkerCount() const override {
+ return Config.Workers;
+ }
+
+ void AddWorker(TWorkerId workerId) override {
+ if (Workers.empty()) {
+ // Grant lease to the first worker
+ AtomicStore(&CurrentLease, TLease(workerId, NeverExpire).Value);
+ }
+ Workers.push_back(workerId);
+ }
+
+ ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) {
+ ui32 activation;
+ if (!wctx.Lease.IsNeverExpiring()) {
+ if (wctx.SoftDeadlineTs < GetCycleCountFast()) { // stop if lease has expired or is near to be expired
+ United->StopExecution(wctx.PoolId);
+ } else if (United->NextExecution(wctx.PoolId, activation, revolvingCounter)) {
+ return activation; // another activation from currently executing pool (or 0 if stopped)
+ }
+ }
+
+ // Switch to another pool, it blocks until token is acquired
+ if (Y_UNLIKELY(!SwitchPool(wctx))) {
+ return 0; // stopped
+ }
+ United->BeginExecution(wctx.PoolId, activation, revolvingCounter);
+ return activation;
+ }
+
+ void Stop() override {
+ IdleQueue.Stop();
+ }
+
+ private:
+ enum EPriority {
+ IdlePriority, // highest (real-time, Config.IdleWorkerPriority)
+ FastPriority, // normal (real-time, Config.FastWorkerPriority)
+ SlowPriority, // lowest (not real-time)
+ };
+
+ enum EWorkerAction {
+ // Fast-worker
+ ExecuteFast,
+ WaitForSlow,
+
+ // Slow-worker
+ BecameIdle,
+ WakeFast,
+
+ // Idle-worker
+ BecameFast,
+ Standby,
+
+ // Common
+ Stopped,
+ };
+
+ // Thread-safe; should be called from worker
+ // Blocks for idle-workers; sets lease and next pool to run
+ bool SwitchPool(TWorkerContext& wctx) {
+ TTimerFd* idleTimer = nullptr;
+ while (true) {
+ if (DisablePreemptionAndTryExtend(wctx.Lease)) { // if fast-worker
+ if (Y_UNLIKELY(!Started)) {
+ SetPriority(0, FastPriority);
+ Started = true;
+ }
+ while (true) {
+ switch (FastWorkerAction(wctx)) {
+ case ExecuteFast:
+ United->SwitchPool(wctx, wctx.Lease.GetPreciseExpireTs() - Config.EventLimitTs);
+ EnablePreemptionAndGrant(wctx.Lease);
+ return true;
+ case WaitForSlow:
+ FastWorkerSleep(GetCycleCountFast() + Config.SoftLimitTs);
+ break;
+ case Stopped: return false;
+ default: Y_FAIL();
+ }
+ }
+ } else if (wctx.Lease.IsNeverExpiring()) { // if idle-worker
+ switch (IdleWorkerAction(idleTimer, wctx.Lease.GetWorkerId())) {
+ case BecameFast:
+ SetPriority(0, FastPriority);
+ break; // try acquire new lease
+ case Standby:
+ if (!idleTimer) {
+ idleTimer = IdleQueue.Enqueue();
+ }
+ SetPriority(0, IdlePriority);
+ idleTimer->Wait();
+ break;
+ case Stopped: return false;
+ default: Y_FAIL();
+ }
+ } else { // lease has expired and hard preemption occured, so we are executing in a slow-worker
+ wctx.IncrementPreemptedEvents();
+ switch (SlowWorkerAction(wctx.PoolId)) {
+ case WakeFast:
+ WakeFastWorker();
+ [[fallthrough]]; // no break; pass through
+ case BecameIdle:
+ wctx.Lease = wctx.Lease.NeverExpire();
+ wctx.PoolId = MaxPools;
+ idleTimer = nullptr;
+ break;
+ case Stopped: return false;
+ default: Y_FAIL();
+ }
+ }
+ }
+ }
+
+ enum ETryRunPool {
+ RunFastPool,
+ RunSlowPool,
+ NoTokens,
+ };
+
+ ETryRunPool TryRun(TPoolId pool) {
+ while (true) {
+ // updates WaitPoolsFlag in SlowPoolsMask according to scheduled pool slowness
+ TPoolsMask slow = AtomicLoad(&SlowPoolsMask);
+ if ((1ull << pool) & slow) { // we are about to execute slow pool (fast-worker will just wait, token is NOT required)
+ if (slow & WaitPoolsFlag) {
+ return RunSlowPool; // wait flag is already set
+ } else {
+ if (AtomicCas(&SlowPoolsMask, slow | WaitPoolsFlag, slow)) { // try set wait flag
+ return RunSlowPool; // wait flag has been successfully set
+ }
+ }
+ } else { // we are about to execute fast pool, token required
+ if (slow & WaitPoolsFlag) { // reset wait flag if required
+ if (AtomicCas(&SlowPoolsMask, slow & ~WaitPoolsFlag, slow)) { // try reset wait flag
+ return United->TryAcquireToken(pool) ? RunFastPool : NoTokens; // wait flag has been successfully reset
+ }
+ } else {
+ return United->TryAcquireToken(pool) ? RunFastPool : NoTokens; // wait flag is already reset
+ }
+ }
+ }
+ }
+
+ EWorkerAction FastWorkerAction(TWorkerContext& wctx) {
+ if (Y_UNLIKELY(United->IsStopped())) {
+ return Stopped;
+ }
+
+ // Account current pool
+ ui64 ts = GetCycleCountFast();
+ PoolSched.Account(ts);
+
+ // Select next pool to execute
+ for (wctx.PoolId = PoolSched.Begin(); wctx.PoolId != PoolSched.End(); wctx.PoolId = PoolSched.Next()) {
+ switch (TryRun(wctx.PoolId)) {
+ case RunFastPool:
+ PoolSched.Scheduled();
+ wctx.Lease = PostponePreemption(wctx.Lease.GetWorkerId(), ts);
+ return ExecuteFast;
+ case RunSlowPool:
+ PoolSched.Scheduled();
+ ResetPreemption(wctx.Lease.GetWorkerId(), ts); // there is no point in preemption during wait
+ return WaitForSlow;
+ case NoTokens: // concurrency limit reached, or no more work in pool
+ break; // just try next pool (if any)
+ }
+ }
+
+ // No more work, no slow-workers -- wait for activations (active, then blocked)
+ wctx.PoolId = United->Idle(CpuShared, wctx);
+
+ // Wakeup or stop occured
+ if (Y_UNLIKELY(wctx.PoolId == CpuStopped)) {
+ return Stopped;
+ }
+ ts = GetCycleCountFast();
+ PoolSched.ScheduledAfterIdle(wctx.PoolId, ts);
+ wctx.Lease = PostponePreemption(wctx.Lease.GetWorkerId(), ts);
+ return ExecuteFast; // United->Idle() has already acquired token
+ }
+
+ EWorkerAction IdleWorkerAction(TTimerFd* idleTimer, TWorkerId workerId) {
+ if (Y_UNLIKELY(United->IsStopped())) {
+ return Stopped;
+ }
+ if (!idleTimer) { // either worker start or became idle -- hard preemption is not required
+ return Standby;
+ }
+
+ TLease lease = TLease(AtomicLoad(&CurrentLease));
+ ui64 ts = GetCycleCountFast();
+ if (lease.GetExpireTs() < ts) { // current lease has expired
+ if (TryBeginHardPreemption(lease)) {
+ SetPoolIsSlowFlag(PoolSched.CurrentPool());
+ TWorkerId preempted = lease.GetWorkerId();
+ SetPriority(United->GetWorkerThreadId(preempted), SlowPriority);
+ LWPROBE(HardPreemption, Config.CpuId, PoolSched.CurrentPool(), preempted, workerId);
+ EndHardPreemption(workerId);
+ return BecameFast;
+ } else {
+ // Lease has been changed just now, no way we need preemption right now, so no retry needed
+ return Standby;
+ }
+ } else {
+ // Lease has not expired yet (maybe never expiring lease)
+ return Standby;
+ }
+ }
+
+ EWorkerAction SlowWorkerAction(TPoolId pool) {
+ if (Y_UNLIKELY(United->IsStopped())) {
+ return Stopped;
+ }
+ while (true) {
+ TPoolsMask slow = AtomicLoad(&SlowPoolsMask);
+ if (slow & (1ull << pool)) {
+ if (slow == (1ull << pool) & WaitPoolsFlag) { // the last slow pool is going to became fast
+ if (AtomicCas(&SlowPoolsMask, 0, slow)) { // reset both pool-is-slow flag and WaitPoolsFlag
+ return WakeFast;
+ }
+ } else { // there are (a) several slow-worker or (b) one slow-worker w/o waiting fast-worker
+ if (AtomicCas(&SlowPoolsMask, slow & ~(1ull << pool), slow)) { // reset pool-is-slow flag
+ return BecameIdle;
+ }
+ }
+ } else {
+ // SlowWorkerAction has been called between TryBeginHardPreemption and SetPoolIsSlowFlag
+ // flag for this pool is not set yet, but we can be sure pool is slow:
+ // - because SlowWorkerAction has been called;
+ // - this mean lease has expired and hard preemption occured.
+ // So just wait other worker to call SetPoolIsSlowFlag
+ LWPROBE(SlowWorkerActionRace, Config.CpuId, pool, slow);
+ }
+ }
+ }
+
+ void SetPoolIsSlowFlag(TPoolId pool) {
+ while (true) {
+ TPoolsMask slow = AtomicLoad(&SlowPoolsMask);
+ if ((slow & (1ull << pool)) == 0) { // if pool is fast
+ if (AtomicCas(&SlowPoolsMask, slow | (1ull << pool), slow)) { // set pool-is-slow flag
+ return;
+ }
+ } else {
+ Y_FAIL("two slow-workers executing the same pool on the same core");
+ return; // pool is already slow
+ }
+ }
+ }
+
+ bool TryBeginHardPreemption(TLease lease) {
+ return AtomicCas(&CurrentLease, HardPreemptionLease, lease);
+ }
+
+ void EndHardPreemption(TWorkerId to) {
+ ATOMIC_COMPILER_BARRIER();
+ if (!AtomicCas(&CurrentLease, TLease(to, NeverExpire), HardPreemptionLease)) {
+ Y_FAIL("hard preemption failed");
+ }
+ }
+
+ bool DisablePreemptionAndTryExtend(TLease lease) {
+ return AtomicCas(&CurrentLease, lease.NeverExpire(), lease);
+ }
+
+ void EnablePreemptionAndGrant(TLease lease) {
+ ATOMIC_COMPILER_BARRIER();
+ if (!AtomicCas(&CurrentLease, lease, lease.NeverExpire())) {
+ Y_FAIL("lease grant failed");
+ }
+ }
+
+ void FastWorkerSleep(ui64 deadlineTs) {
+ while (true) {
+ TPoolsMask slow = AtomicLoad(&SlowPoolsMask);
+ if ((slow & WaitPoolsFlag) == 0) {
+ return; // woken by WakeFast action
+ }
+ ui64 ts = GetCycleCountFast();
+ if (deadlineTs <= ts) {
+ if (AtomicCas(&SlowPoolsMask, slow & ~WaitPoolsFlag, slow)) { // try reset wait flag
+ return; // wait flag has been successfully reset after timeout
+ }
+ } else { // should wait
+ ui64 timeoutNs = Ts2Ns(deadlineTs - ts);
+#ifdef _linux_
+ timespec timeout;
+ timeout.tv_sec = timeoutNs / 1'000'000'000;
+ timeout.tv_nsec = timeoutNs % 1'000'000'000;
+ SysFutex(FastWorkerFutex(), FUTEX_WAIT_PRIVATE, FastWorkerFutexValue(slow), &timeout, nullptr, 0);
+#else
+ NanoSleep(timeoutNs); // non-linux wake is not supported, cpu will go idle on slow -> fast switch
+#endif
+ }
+ }
+ }
+
+ void WakeFastWorker() {
+#ifdef _linux_
+ SysFutex(FastWorkerFutex(), FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0);
+#endif
+ }
+
+#ifdef _linux_
+ ui32* FastWorkerFutex() {
+ // Actually we wait on one highest bit, but futex value size is 4 bytes on all platforms
+ static_assert(sizeof(TPoolsMask) >= 4, "cannot be used as futex value on linux");
+ return (ui32*)&SlowPoolsMask + 1; // higher 32 bits (little endian assumed)
+ }
+
+ ui32 FastWorkerFutexValue(TPoolsMask slow) {
+ return ui32(slow >> 32); // higher 32 bits
+ }
+#endif
+
+ void SetPriority(TThreadId tid, EPriority priority) {
+ if (Config.NoRealtime) {
+ return;
+ }
+#ifdef _linux_
+ int policy;
+ struct sched_param param;
+ switch (priority) {
+ case IdlePriority:
+ policy = SCHED_FIFO;
+ param.sched_priority = Config.IdleWorkerPriority;
+ break;
+ case FastPriority:
+ policy = SCHED_FIFO;
+ param.sched_priority = Config.FastWorkerPriority;
+ break;
+ case SlowPriority:
+ policy = SCHED_OTHER;
+ param.sched_priority = 0;
+ break;
+ }
+ int ret = sched_setscheduler(tid, policy, &param);
+ switch (ret) {
+ case 0: return;
+ case EINVAL:
+ Y_FAIL("sched_setscheduler(%" PRIu64 ", %d, %d) -> EINVAL", tid, policy, param.sched_priority);
+ case EPERM:
+ // Requirements:
+ // * CAP_SYS_NICE capability to run real-time processes and set cpu affinity.
+ // Either run under root or set application capabilities:
+ // sudo setcap cap_sys_nice=eip BINARY
+ // * Non-zero rt-runtime (in case cgroups are used).
+ // Either (a) disable global limit on RT processes bandwidth:
+ // sudo sysctl -w kernel.sched_rt_runtime_us=-1
+ // Or (b) set non-zero rt-runtime for your cgroup:
+ // echo -1 > /sys/fs/cgroup/cpu/[cgroup]/cpu.rt_runtime_us
+ // (also set the same value for every parent cgroup)
+ // https://www.kernel.org/doc/Documentation/scheduler/sched-rt-group.txt
+ Y_FAIL("sched_setscheduler(%" PRIu64 ", %d, %d) -> EPERM", tid, policy, param.sched_priority);
+ case ESRCH:
+ Y_FAIL("sched_setscheduler(%" PRIu64 ", %d, %d) -> ESRCH", tid, policy, param.sched_priority);
+ default:
+ Y_FAIL("sched_setscheduler(%" PRIu64 ", %d, %d) -> %d", tid, policy, param.sched_priority, ret);
+ }
+#else
+ Y_UNUSED(tid);
+ Y_UNUSED(priority);
+#endif
+ }
+
+ void ResetPreemption(TWorkerId fastWorkerId, ui64 ts) {
+ if (Y_UNLIKELY(!PreemptionTimer)) {
+ return;
+ }
+ if (FastWorker == fastWorkerId && HardPreemptionTs > 0) {
+ PreemptionTimer->Reset();
+ LWPROBE(ResetPreemptionTimer, Config.CpuId, FastWorker, PreemptionTimer->Fd, Ts2Ms(ts), Ts2Ms(HardPreemptionTs));
+ HardPreemptionTs = 0;
+ }
+ }
+
+ TLease PostponePreemption(TWorkerId fastWorkerId, ui64 ts) {
+ // Select new timer after hard preemption
+ if (FastWorker != fastWorkerId) {
+ FastWorker = fastWorkerId;
+ PreemptionTimer = IdleQueue.Dequeue();
+ HardPreemptionTs = 0;
+ }
+
+ ui64 hardPreemptionTs = ts + Config.HardLimitTs;
+ if (hardPreemptionTs > HardPreemptionTs) {
+ // Reset timer (at most once in TickIntervalTs, sacrifice precision)
+ HardPreemptionTs = hardPreemptionTs + Config.LimitPrecisionTs;
+ PreemptionTimer->Set(HardPreemptionTs);
+ LWPROBE(SetPreemptionTimer, Config.CpuId, FastWorker, PreemptionTimer->Fd, Ts2Ms(ts), Ts2Ms(HardPreemptionTs));
+ }
+
+ return TLease(fastWorkerId, hardPreemptionTs);
+ }
+ };
+
+ // Proxy for start and switching TUnitedExecutorPool-s on single cpu via GetReadyActivation()
+ // (does not implement any other method in IExecutorPool)
+ class TCpuExecutorPool: public IExecutorPool {
+ const TString Name;
+
+ public:
+ explicit TCpuExecutorPool(const TString& name)
+ : IExecutorPool(MaxPools)
+ , Name(name)
+ {}
+
+ TString GetName() const override {
+ return Name;
+ }
+
+ void SetRealTimeMode() const override {
+ // derived classes controls rt-priority - do nothing
+ }
+
+ // Should never be called
+ void ReclaimMailbox(TMailboxType::EType, ui32, TWorkerId, ui64) override { Y_FAIL(); }
+ void Schedule(TInstant, TAutoPtr<IEventHandle>, ISchedulerCookie*, TWorkerId) override { Y_FAIL(); }
+ void Schedule(TMonotonic, TAutoPtr<IEventHandle>, ISchedulerCookie*, TWorkerId) override { Y_FAIL(); }
+ void Schedule(TDuration, TAutoPtr<IEventHandle>, ISchedulerCookie*, TWorkerId) override { Y_FAIL(); }
+ bool Send(TAutoPtr<IEventHandle>&) override { Y_FAIL(); }
+ void ScheduleActivation(ui32) override { Y_FAIL(); }
+ void ScheduleActivationEx(ui32, ui64) override { Y_FAIL(); }
+ TActorId Register(IActor*, TMailboxType::EType, ui64, const TActorId&) override { Y_FAIL(); }
+ TActorId Register(IActor*, TMailboxHeader*, ui32, const TActorId&) override { Y_FAIL(); }
+ void Prepare(TActorSystem*, NSchedulerQueue::TReader**, ui32*) override { Y_FAIL(); }
+ void Start() override { Y_FAIL(); }
+ void PrepareStop() override { Y_FAIL(); }
+ void Shutdown() override { Y_FAIL(); }
+ bool Cleanup() override { Y_FAIL(); }
+ };
+
+ // Proxy executor pool working with cpu-local scheduler (aka actorsystem 2.0)
+ class TSharedCpuExecutorPool: public TCpuExecutorPool {
+ TSharedCpu* Local;
+ TIntrusivePtr<TAffinity> SingleCpuAffinity; // no migration support yet
+ public:
+ explicit TSharedCpuExecutorPool(TSharedCpu* local, const TUnitedWorkersConfig& config)
+ : TCpuExecutorPool("u-" + ToString(local->Config.CpuId))
+ , Local(local)
+ , SingleCpuAffinity(config.NoAffinity ? nullptr : new TAffinity(TCpuMask(local->Config.CpuId)))
+ {}
+
+ TAffinity* Affinity() const override {
+ return SingleCpuAffinity.Get();
+ }
+
+ ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override {
+ return Local->GetReadyActivation(wctx, revolvingCounter);
+ }
+ };
+
+ // Proxy executor pool working with balancer and assigned pools (aka actorsystem 1.5)
+ class TAssignedCpuExecutorPool: public TCpuExecutorPool {
+ TAssignedCpu* Local;
+ TIntrusivePtr<TAffinity> CpuAffinity;
+ public:
+ explicit TAssignedCpuExecutorPool(TAssignedCpu* local, const TUnitedWorkersConfig& config)
+ : TCpuExecutorPool("United")
+ , Local(local)
+ , CpuAffinity(config.NoAffinity ? nullptr : new TAffinity(config.Allowed))
+ {}
+
+ TAffinity* Affinity() const override {
+ return CpuAffinity.Get();
+ }
+
+ ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override {
+ return Local->GetReadyActivation(wctx, revolvingCounter);
+ }
+ };
+
+ // Representation of a single cpu and it's state visible to other cpus and pools
+ struct TUnitedWorkers::TCpu: public TNonCopyable {
+ struct TScopedWaiters {
+ TCpu& Cpu;
+ TPool* AssignedPool; // nullptr if CpuShared
+
+ // Subscribe on wakeups from allowed pools
+ TScopedWaiters(TCpu& cpu, TPool* assignedPool) : Cpu(cpu), AssignedPool(assignedPool) {
+ if (!AssignedPool) {
+ for (TPool* pool : Cpu.AllowedPools) {
+ AtomicIncrement(pool->Waiters);
+ }
+ } else {
+ AtomicIncrement(AssignedPool->Waiters);
+ }
+ }
+
+ // Unsubscribe from pools we've subscribed on
+ ~TScopedWaiters() {
+ if (!AssignedPool) {
+ for (TPool* pool : Cpu.AllowedPools) {
+ AtomicDecrement(pool->Waiters);
+ }
+ } else {
+ AtomicDecrement(AssignedPool->Waiters);
+ }
+ }
+ };
+
+ // Current cpu state important for other cpus and balancer
+ TCpuState State;
+
+ // Thread-safe per pool stats
+ // NOTE: It's guaranteed that cpu never executes two instance of the same pool
+ TVector<TExecutorThreadStats> PoolStats;
+
+ // Configuration
+ TCpuId CpuId;
+ THolder<TCpuLocalManager> LocalManager;
+ THolder<TCpuExecutorPool> ExecutorPool;
+
+ // Pools allowed to run on this cpu
+ TStackVec<TPool*, 15> AllowedPools;
+
+ void Stop() {
+ if (LocalManager) {
+ State.Stop();
+ LocalManager->Stop();
+ }
+ }
+
+ bool StartSpinning(TUnitedWorkers* united, TPool* assignedPool, TPoolId& result) {
+ // Mark cpu as idle
+ if (Y_UNLIKELY(!State.StartSpinning())) {
+ result = CpuStopped;
+ return true;
+ }
+
+ // Avoid using multiple atomic seq_cst loads in cycle, use barrier once and relaxed ops
+ AtomicBarrier();
+
+ // Check there is no pending tokens (can be released before Waiters increment)
+ if (!assignedPool) {
+ for (TPool* pool : AllowedPools) {
+ if (pool->TryAcquireTokenRelaxed()) {
+ result = WakeWithTokenAcquired(united, pool->PoolId);
+ return true; // token acquired or stop
+ }
+ }
+ } else {
+ if (assignedPool->TryAcquireTokenRelaxed()) {
+ result = WakeWithTokenAcquired(united, assignedPool->PoolId);
+ return true; // token acquired or stop
+ }
+ }
+
+ // At this point we can be sure wakeup won't be lost
+ // So we can actively spin or block w/o checking for pending tokens
+ return false;
+ }
+
+ bool ActiveWait(ui64 spinThresholdTs, TPoolId& result) {
+ ui64 deadline = GetCycleCountFast() + spinThresholdTs;
+ while (GetCycleCountFast() < deadline) {
+ for (ui32 i = 0; i < 12; ++i) {
+ TPoolId current = State.CurrentPool();
+ if (current == CpuSpinning) {
+ SpinLockPause();
+ } else {
+ result = current;
+ return true; // wakeup
+ }
+ }
+ }
+ return false; // spin threshold exceeded, no wakeups
+ }
+
+ bool StartBlocking(TPoolId& result) {
+ // Switch into blocked state
+ if (State.StartBlocking()) {
+ result = State.CurrentPool();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ bool BlockedWait(TPoolId& result, ui64 timeoutNs) {
+ return State.Block(timeoutNs, result);
+ }
+
+ void SwitchPool(TPoolId pool) {
+ return State.SwitchPool(pool);
+ }
+
+ private:
+ TPoolId WakeWithTokenAcquired(TUnitedWorkers* united, TPoolId token) {
+ switch (State.WakeWithTokenAcquired(token)) {
+ case TCpuState::Woken: // we've got token and successfully woken up this cpu
+ // NOTE: sending thread may also wakeup another worker, which wont be able to acquire token and will go idle (it's ok)
+ return token;
+ case TCpuState::NotIdle: { // wakeup event has also occured
+ TPoolId wakeup = State.CurrentPool();
+ if (wakeup != token) { // token and wakeup for different pools
+ united->TryWake(wakeup); // rewake another cpu to avoid losing wakeup
+ }
+ return token;
+ }
+ case TCpuState::Forbidden:
+ Y_FAIL();
+ case TCpuState::Stopped:
+ return CpuStopped;
+ }
+ }
+ };
+
+ TUnitedWorkers::TUnitedWorkers(
+ const TUnitedWorkersConfig& config,
+ const TVector<TUnitedExecutorPoolConfig>& unitedPools,
+ const TCpuAllocationConfig& allocation,
+ IBalancer* balancer)
+ : Balancer(balancer)
+ , Config(config)
+ , Allocation(allocation)
+ {
+ // Find max pool id and initialize pools
+ PoolCount = 0;
+ for (const TCpuAllocation& cpuAlloc : allocation.Items) {
+ for (const auto& pa : cpuAlloc.AllowedPools) {
+ PoolCount = Max<size_t>(PoolCount, pa.PoolId + 1);
+ }
+ }
+ Pools.Reset(new TPool[PoolCount]);
+
+ // Find max cpu id and initialize cpus
+ CpuCount = 0;
+ for (const TCpuAllocation& cpuAlloc : allocation.Items) {
+ CpuCount = Max<size_t>(CpuCount, cpuAlloc.CpuId + 1);
+ }
+ Cpus.Reset(new TCpu[CpuCount]);
+
+ // Setup allocated cpus
+ // NOTE: leave gaps for not allocated cpus (default-initialized)
+ WorkerCount = 0;
+ for (const TCpuAllocation& cpuAlloc : allocation.Items) {
+ TCpu& cpu = Cpus[cpuAlloc.CpuId];
+ cpu.CpuId = cpuAlloc.CpuId;
+ cpu.PoolStats.resize(PoolCount); // NOTE: also may have gaps
+ for (const auto& pa : cpuAlloc.AllowedPools) {
+ cpu.AllowedPools.emplace_back(&Pools[pa.PoolId]);
+ }
+
+ // Setup balancing and cpu-local manager
+ if (!Balancer->AddCpu(cpuAlloc, &cpu.State)) {
+ cpu.State.SwitchPool(0); // set initial state to non-idle to avoid losing wakeups on start
+ cpu.State.AssignPool(CpuShared);
+ TSharedCpu* local = new TSharedCpu(TSharedCpu::TConfig(cpuAlloc, Config), this);
+ cpu.LocalManager.Reset(local);
+ cpu.ExecutorPool.Reset(new TSharedCpuExecutorPool(local, Config));
+ } else {
+ TAssignedCpu* local = new TAssignedCpu(this);
+ cpu.LocalManager.Reset(local);
+ cpu.ExecutorPool.Reset(new TAssignedCpuExecutorPool(local, Config));
+ }
+ WorkerCount += cpu.LocalManager->WorkerCount();
+ }
+
+ // Initialize workers
+ Workers.Reset(new TWorker[WorkerCount]);
+
+ // Setup pools
+ // NOTE: leave gaps for not united pools (default-initialized)
+ for (const TUnitedExecutorPoolConfig& cfg : unitedPools) {
+ TPool& pool = Pools[cfg.PoolId];
+ Y_VERIFY(cfg.PoolId < MaxPools);
+ pool.PoolId = cfg.PoolId;
+ pool.Concurrency = cfg.Concurrency ? cfg.Concurrency : Config.CpuCount;
+ pool.ExecutorPool = nullptr; // should be set later using SetupPool()
+ pool.MailboxTable = nullptr; // should be set later using SetupPool()
+ pool.TimePerMailboxTs = DurationToCycles(cfg.TimePerMailbox);
+ pool.EventsPerMailbox = cfg.EventsPerMailbox;
+
+ // Reinitialize per cpu pool stats with right MaxActivityType
+ for (const TCpuAllocation& cpuAlloc : allocation.Items) {
+ TCpu& cpu = Cpus[cpuAlloc.CpuId];
+ cpu.PoolStats[cfg.PoolId] = TExecutorThreadStats(cfg.MaxActivityType);
+ }
+
+ // Setup WakeOrderCpus: left to right exclusive cpus, then left to right shared cpus.
+ // Waking exclusive cpus first reduce load on shared cpu and improve latency isolation, which is
+ // the point of using exclusive cpu. But note that number of actively spinning idle cpus may increase,
+ // so cpu consumption on light load is higher.
+ for (const TCpuAllocation& cpuAlloc : allocation.Items) {
+ TCpu& cpu = Cpus[cpuAlloc.CpuId];
+ if (cpu.AllowedPools.size() == 1 && cpu.AllowedPools[0] == &pool) {
+ pool.WakeOrderCpus.emplace_back(&cpu);
+ }
+ }
+ for (const TCpuAllocation& cpuAlloc : allocation.Items) {
+ TCpu& cpu = Cpus[cpuAlloc.CpuId];
+ if (cpu.AllowedPools.size() > 1 && cpuAlloc.HasPool(pool.PoolId)) {
+ pool.WakeOrderCpus.emplace_back(&cpu);
+ }
+ }
+ }
+ }
+
+ TUnitedWorkers::~TUnitedWorkers() {
+ }
+
+ void TUnitedWorkers::Prepare(TActorSystem* actorSystem, TVector<NSchedulerQueue::TReader*>& scheduleReaders) {
+ // Setup allocated cpus
+ // NOTE: leave gaps for not allocated cpus (default-initialized)
+ TWorkerId workers = 0;
+ for (TCpuId cpuId = 0; cpuId < CpuCount; cpuId++) {
+ TCpu& cpu = Cpus[cpuId];
+
+ // Setup cpu-local workers
+ if (cpu.LocalManager) {
+ for (size_t i = 0; i < cpu.LocalManager->WorkerCount(); i++) {
+ TWorkerId workerId = workers++;
+ cpu.LocalManager->AddWorker(workerId);
+
+ // Setup worker
+ Y_VERIFY(workerId < WorkerCount);
+ Workers[workerId].Thread.Reset(new TExecutorThread(
+ workerId,
+ cpu.CpuId,
+ actorSystem,
+ cpu.ExecutorPool.Get(), // use cpu-local manager as proxy executor for all workers on cpu
+ nullptr, // MailboxTable is pool-specific, will be set on pool switch
+ cpu.ExecutorPool->GetName()));
+ // NOTE: TWorker::ThreadId will be initialized after in Start()
+
+ scheduleReaders.push_back(&Workers[workerId].SchedulerQueue.Reader);
+ }
+ }
+ }
+ }
+
+ void TUnitedWorkers::Start() {
+ for (TWorkerId workerId = 0; workerId < WorkerCount; workerId++) {
+ Workers[workerId].Thread->Start();
+ }
+ for (TWorkerId workerId = 0; workerId < WorkerCount; workerId++) {
+ AtomicStore(&Workers[workerId].ThreadId, Workers[workerId].Thread->GetThreadId());
+ }
+ }
+
+ inline TThreadId TUnitedWorkers::GetWorkerThreadId(TWorkerId workerId) const {
+ volatile TThreadId* threadId = &Workers[workerId].ThreadId;
+#ifdef _linux_
+ while (AtomicLoad(threadId) == UnknownThreadId) {
+ NanoSleep(1000);
+ }
+#endif
+ return AtomicLoad(threadId);
+ }
+
+ inline NSchedulerQueue::TWriter* TUnitedWorkers::GetScheduleWriter(TWorkerId workerId) const {
+ return &Workers[workerId].SchedulerQueue.Writer;
+ }
+
+ void TUnitedWorkers::SetupPool(TPoolId pool, IExecutorPool* executorPool, TMailboxTable* mailboxTable) {
+ Pools[pool].ExecutorPool = executorPool;
+ Pools[pool].MailboxTable = mailboxTable;
+ }
+
+ void TUnitedWorkers::PrepareStop() {
+ AtomicStore(&StopFlag, true);
+ for (TPoolId pool = 0; pool < PoolCount; pool++) {
+ Pools[pool].Stop();
+ }
+ for (TCpuId cpuId = 0; cpuId < CpuCount; cpuId++) {
+ Cpus[cpuId].Stop();
+ }
+ }
+
+ void TUnitedWorkers::Shutdown() {
+ for (TWorkerId workerId = 0; workerId < WorkerCount; workerId++) {
+ Workers[workerId].Thread->Join();
+ }
+ }
+
+ inline void TUnitedWorkers::PushActivation(TPoolId pool, ui32 activation, ui64 revolvingCounter) {
+ if (Pools[pool].PushActivation(activation, revolvingCounter)) { // token generated
+ TryWake(pool);
+ }
+ }
+
+ inline bool TUnitedWorkers::TryAcquireToken(TPoolId pool) {
+ return Pools[pool].TryAcquireToken();
+ }
+
+ inline void TUnitedWorkers::TryWake(TPoolId pool) {
+ // Avoid using multiple atomic seq_cst loads in cycle, use barrier once
+ AtomicBarrier();
+
+ // Scan every allowed cpu in pool's wakeup order and try to wake the first idle cpu
+ if (RelaxedLoad(&Pools[pool].Waiters) > 0) {
+ for (TCpu* cpu : Pools[pool].WakeOrderCpus) {
+ if (cpu->State.WakeWithoutToken(pool) == TCpuState::Woken) {
+ return; // successful wake up
+ }
+ }
+ }
+
+ // Cpu has not been woken up
+ }
+
+ inline void TUnitedWorkers::BeginExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter) {
+ Pools[pool].BeginExecution(activation, revolvingCounter);
+ }
+
+ inline bool TUnitedWorkers::NextExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter) {
+ return Pools[pool].NextExecution(activation, revolvingCounter);
+ }
+
+ inline void TUnitedWorkers::StopExecution(TPoolId pool) {
+ if (Pools[pool].StopExecution()) { // pending token
+ TryWake(pool);
+ }
+ }
+
+ inline void TUnitedWorkers::Balance() {
+ ui64 ts = GetCycleCountFast();
+ if (Balancer->TryLock(ts)) {
+ for (TPoolId pool = 0; pool < PoolCount; pool++) {
+ if (Pools[pool].IsUnited()) {
+ ui64 ElapsedTs = 0;
+ ui64 ParkedTs = 0;
+ for (TCpu* cpu : Pools[pool].WakeOrderCpus) {
+ const TExecutorThreadStats& cpuStats = cpu->PoolStats[pool];
+ ElapsedTs += cpuStats.ElapsedTicks;
+ ParkedTs += cpuStats.ParkedTicks;
+ }
+ TBalancerStats stats;
+ stats.Ts = ts;
+ stats.CpuUs = Ts2Us(ElapsedTs);
+ stats.IdleUs = Ts2Us(ParkedTs);
+ Balancer->SetPoolStats(pool, stats);
+ }
+ }
+ Balancer->Balance();
+ Balancer->Unlock();
+ }
+ }
+
+ inline TPoolId TUnitedWorkers::AssignedPool(TWorkerContext& wctx) {
+ return Cpus[wctx.CpuId].State.AssignedPool();
+ }
+
+ inline bool TUnitedWorkers::IsPoolReassigned(TWorkerContext& wctx) {
+ return Cpus[wctx.CpuId].State.IsPoolReassigned(wctx.PoolId);
+ }
+
+ inline void TUnitedWorkers::SwitchPool(TWorkerContext& wctx, ui64 softDeadlineTs) {
+ Pools[wctx.PoolId].Switch(wctx, softDeadlineTs, Cpus[wctx.CpuId].PoolStats[wctx.PoolId]);
+ Cpus[wctx.CpuId].SwitchPool(wctx.PoolId);
+ }
+
+ TPoolId TUnitedWorkers::Idle(TPoolId assigned, TWorkerContext& wctx) {
+ wctx.SwitchToIdle();
+
+ TPoolId result;
+ TTimeTracker timeTracker;
+ TCpu& cpu = Cpus[wctx.CpuId];
+ TPool* assignedPool = assigned == CpuShared ? nullptr : &Pools[assigned];
+ TCpu::TScopedWaiters scopedWaiters(cpu, assignedPool);
+ while (true) {
+ if (cpu.StartSpinning(this, assignedPool, result)) {
+ break; // token already acquired (or stop)
+ }
+ result = WaitSequence(cpu, wctx, timeTracker);
+ if (Y_UNLIKELY(result == CpuStopped) || TryAcquireToken(result)) {
+ break; // token acquired (or stop)
+ }
+ }
+
+ wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, timeTracker.Elapsed());
+ return result;
+ }
+
+ TPoolId TUnitedWorkers::WaitSequence(TCpu& cpu, TWorkerContext& wctx, TTimeTracker& timeTracker) {
+ TPoolId result;
+ if (cpu.ActiveWait(Us2Ts(Config.SpinThresholdUs), result)) {
+ wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, timeTracker.Elapsed());
+ return result;
+ }
+ if (cpu.StartBlocking(result)) {
+ wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, timeTracker.Elapsed());
+ return result;
+ }
+ wctx.AddElapsedCycles(IActor::ACTOR_SYSTEM, timeTracker.Elapsed());
+ bool wakeup;
+ do {
+ wakeup = cpu.BlockedWait(result, Config.Balancer.PeriodUs * 1000);
+ wctx.AddParkedCycles(timeTracker.Elapsed());
+ } while (!wakeup);
+ return result;
+ }
+
+ void TUnitedWorkers::GetCurrentStats(TPoolId pool, TVector<TExecutorThreadStats>& statsCopy) const {
+ size_t idx = 1;
+ statsCopy.resize(idx + Pools[pool].WakeOrderCpus.size());
+ for (TCpu* cpu : Pools[pool].WakeOrderCpus) {
+ TExecutorThreadStats& s = statsCopy[idx++];
+ s = TExecutorThreadStats();
+ s.Aggregate(cpu->PoolStats[pool]);
+ }
+ }
+
+ TUnitedExecutorPool::TUnitedExecutorPool(const TUnitedExecutorPoolConfig& cfg, TUnitedWorkers* united)
+ : TExecutorPoolBaseMailboxed(cfg.PoolId, cfg.MaxActivityType)
+ , United(united)
+ , PoolName(cfg.PoolName)
+ {
+ United->SetupPool(TPoolId(cfg.PoolId), this, MailboxTable.Get());
+ }
+
+ void TUnitedExecutorPool::Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) {
+ ActorSystem = actorSystem;
+
+ // Schedule readers are initialized through TUnitedWorkers::Prepare
+ *scheduleReaders = nullptr;
+ *scheduleSz = 0;
+ }
+
+ void TUnitedExecutorPool::Start() {
+ // workers are actually started in TUnitedWorkers::Start()
+ }
+
+ void TUnitedExecutorPool::PrepareStop() {
+ }
+
+ void TUnitedExecutorPool::Shutdown() {
+ // workers are actually joined in TUnitedWorkers::Shutdown()
+ }
+
+ TAffinity* TUnitedExecutorPool::Affinity() const {
+ Y_FAIL(); // should never be called, TCpuExecutorPool is used instead
+ }
+
+ ui32 TUnitedExecutorPool::GetThreads() const {
+ return 0;
+ }
+
+ ui32 TUnitedExecutorPool::GetReadyActivation(TWorkerContext&, ui64) {
+ Y_FAIL(); // should never be called, TCpu*ExecutorPool is used instead
+ }
+
+ inline void TUnitedExecutorPool::ScheduleActivation(ui32 activation) {
+ TUnitedExecutorPool::ScheduleActivationEx(activation, AtomicIncrement(ActivationsRevolvingCounter));
+ }
+
+ inline void TUnitedExecutorPool::ScheduleActivationEx(ui32 activation, ui64 revolvingCounter) {
+ United->PushActivation(PoolId, activation, revolvingCounter);
+ }
+
+ void TUnitedExecutorPool::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) {
+ TUnitedExecutorPool::Schedule(deadline - ActorSystem->Timestamp(), ev, cookie, workerId);
+ }
+
+ void TUnitedExecutorPool::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) {
+ Y_VERIFY_DEBUG(workerId < United->GetWorkerCount());
+ const auto current = ActorSystem->Monotonic();
+ if (deadline < current) {
+ deadline = current;
+ }
+ United->GetScheduleWriter(workerId)->Push(deadline.MicroSeconds(), ev.Release(), cookie);
+ }
+
+ void TUnitedExecutorPool::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) {
+ Y_VERIFY_DEBUG(workerId < United->GetWorkerCount());
+ const auto deadline = ActorSystem->Monotonic() + delta;
+ United->GetScheduleWriter(workerId)->Push(deadline.MicroSeconds(), ev.Release(), cookie);
+ }
+
+ void TUnitedExecutorPool::GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const {
+ Y_UNUSED(poolStats);
+ if (statsCopy.empty()) {
+ statsCopy.resize(1);
+ }
+ statsCopy[0] = TExecutorThreadStats();
+ statsCopy[0].Aggregate(Stats);
+ United->GetCurrentStats(PoolId, statsCopy);
+ }
+}
diff --git a/library/cpp/actors/core/executor_pool_united.h b/library/cpp/actors/core/executor_pool_united.h
new file mode 100644
index 0000000000..a090ba2466
--- /dev/null
+++ b/library/cpp/actors/core/executor_pool_united.h
@@ -0,0 +1,135 @@
+#pragma once
+
+#include "actorsystem.h"
+#include "balancer.h"
+#include "scheduler_queue.h"
+#include "executor_pool_base.h"
+
+#include <library/cpp/actors/util/unordered_cache.h>
+
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+#include <library/cpp/actors/util/unordered_cache.h>
+#include <library/cpp/containers/stack_vector/stack_vec.h>
+
+#include <util/generic/noncopyable.h>
+
+namespace NActors {
+ class TMailboxTable;
+
+ class TUnitedWorkers: public TNonCopyable {
+ struct TWorker;
+ struct TPool;
+ struct TCpu;
+
+ size_t WorkerCount;
+ TArrayHolder<TWorker> Workers; // indexed by WorkerId
+ size_t PoolCount;
+ TArrayHolder<TPool> Pools; // indexed by PoolId, so may include not used (not united) pools
+ size_t CpuCount;
+ TArrayHolder<TCpu> Cpus; // indexed by CpuId, so may include not allocated CPUs
+
+ IBalancer* Balancer; // external pool cpu balancer
+
+ TUnitedWorkersConfig Config;
+ TCpuAllocationConfig Allocation;
+
+ volatile bool StopFlag = false;
+
+ public:
+ TUnitedWorkers(
+ const TUnitedWorkersConfig& config,
+ const TVector<TUnitedExecutorPoolConfig>& unitedPools,
+ const TCpuAllocationConfig& allocation,
+ IBalancer* balancer);
+ ~TUnitedWorkers();
+ void Prepare(TActorSystem* actorSystem, TVector<NSchedulerQueue::TReader*>& scheduleReaders);
+ void Start();
+ void PrepareStop();
+ void Shutdown();
+
+ bool IsStopped() const {
+ return RelaxedLoad(&StopFlag);
+ }
+
+ TWorkerId GetWorkerCount() const {
+ return WorkerCount;
+ }
+
+ // Returns thread id of a worker
+ TThreadId GetWorkerThreadId(TWorkerId workerId) const;
+
+ // Returns per worker schedule writers
+ NSchedulerQueue::TWriter* GetScheduleWriter(TWorkerId workerId) const;
+
+ // Sets executor for specified pool
+ void SetupPool(TPoolId pool, IExecutorPool* executorPool, TMailboxTable* mailboxTable);
+
+ // Add activation of newly scheduled mailbox and wake cpu to execute it if required
+ void PushActivation(TPoolId pool, ui32 activation, ui64 revolvingCounter);
+
+ // Try acquire pending token. Must be done before execution
+ bool TryAcquireToken(TPoolId pool);
+
+ // Try to wake idle cpu waiting for tokens on specified pool
+ void TryWake(TPoolId pool);
+
+ // Get activation from pool; requires pool's token
+ void BeginExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter);
+
+ // Stop currently active execution and start new one if token is available
+ // NOTE: Reuses token if it's not destroyed
+ bool NextExecution(TPoolId pool, ui32& activation, ui64 revolvingCounter);
+
+ // Stop active execution
+ void StopExecution(TPoolId pool);
+
+ // Runs balancer to assign pools to cpus
+ void Balance();
+
+ // Returns pool to be executed by worker or `CpuShared`
+ TPoolId AssignedPool(TWorkerContext& wctx);
+
+ // Checks if balancer has assigned another pool for worker's cpu
+ bool IsPoolReassigned(TWorkerContext& wctx);
+
+ // Switch worker context into specified pool
+ void SwitchPool(TWorkerContext& wctx, ui64 softDeadlineTs);
+
+ // Wait for tokens from any pool allowed on specified cpu
+ TPoolId Idle(TPoolId assigned, TWorkerContext& wctx);
+
+ // Fill stats for specified pool
+ void GetCurrentStats(TPoolId pool, TVector<TExecutorThreadStats>& statsCopy) const;
+
+ private:
+ TPoolId WaitSequence(TCpu& cpu, TWorkerContext& wctx, TTimeTracker& timeTracker);
+ };
+
+ class TUnitedExecutorPool: public TExecutorPoolBaseMailboxed {
+ TUnitedWorkers* United;
+ const TString PoolName;
+ TAtomic ActivationsRevolvingCounter = 0;
+ public:
+ TUnitedExecutorPool(const TUnitedExecutorPoolConfig& cfg, TUnitedWorkers* united);
+
+ void Prepare(TActorSystem* actorSystem, NSchedulerQueue::TReader** scheduleReaders, ui32* scheduleSz) override;
+ void Start() override;
+ void PrepareStop() override;
+ void Shutdown() override;
+
+ TAffinity* Affinity() const override;
+ ui32 GetThreads() const override;
+ ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingReadCounter) override;
+ void ScheduleActivation(ui32 activation) override;
+ void ScheduleActivationEx(ui32 activation, ui64 revolvingWriteCounter) override;
+ void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override;
+ void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override;
+ void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie, TWorkerId workerId) override;
+
+ void GetCurrentStats(TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& statsCopy) const override;
+
+ TString GetName() const override {
+ return PoolName;
+ }
+ };
+}
diff --git a/library/cpp/actors/core/executor_pool_united_ut.cpp b/library/cpp/actors/core/executor_pool_united_ut.cpp
new file mode 100644
index 0000000000..d4df17f1b8
--- /dev/null
+++ b/library/cpp/actors/core/executor_pool_united_ut.cpp
@@ -0,0 +1,338 @@
+#include "actorsystem.h"
+#include "executor_pool_basic.h"
+#include "hfunc.h"
+#include "scheduler_basic.h"
+
+#include <library/cpp/actors/util/should_continue.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/actors/protos/unittests.pb.h>
+
+using namespace NActors;
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct TEvMsg : public NActors::TEventBase<TEvMsg, 10347> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvMsg, "ExecutorPoolTest: Msg");
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+inline ui64 DoTimedWork(ui64 workUs) {
+ ui64 startUs = ThreadCPUTime();
+ ui64 endUs = startUs + workUs;
+ ui64 nowUs = startUs;
+ do {
+ ui64 endTs = GetCycleCountFast() + Us2Ts(endUs - nowUs);
+ while (GetCycleCountFast() <= endTs) {}
+ nowUs = ThreadCPUTime();
+ } while (nowUs <= endUs);
+ return nowUs - startUs;
+}
+
+class TTestSenderActor : public IActor {
+private:
+ using EActivityType = IActor::EActivityType ;
+ using EActorActivity = IActor::EActorActivity;
+
+private:
+ TAtomic Counter;
+ TActorId Receiver;
+
+ std::function<void(void)> Action;
+
+public:
+ TTestSenderActor(std::function<void(void)> action = [](){},
+ EActivityType activityType = EActorActivity::OTHER)
+ : IActor(static_cast<TReceiveFunc>(&TTestSenderActor::Execute), activityType)
+ , Action(action)
+ {}
+
+ void Start(TActorId receiver, size_t count) {
+ AtomicSet(Counter, count);
+ Receiver = receiver;
+ }
+
+ void Stop() {
+ while (true) {
+ if (GetCounter() == 0) {
+ break;
+ }
+
+ Sleep(TDuration::MilliSeconds(1));
+ }
+ }
+
+ size_t GetCounter() const {
+ return AtomicGet(Counter);
+ }
+
+private:
+ STFUNC(Execute) {
+ Y_UNUSED(ctx);
+ switch (ev->GetTypeRewrite()) {
+ hFunc(TEvMsg, Handle);
+ }
+ }
+
+ void Handle(TEvMsg::TPtr &ev) {
+ Y_UNUSED(ev);
+ Action();
+ TAtomicBase count = AtomicDecrement(Counter);
+ Y_VERIFY(count != Max<TAtomicBase>());
+ if (count) {
+ Send(Receiver, new TEvMsg());
+ }
+ }
+};
+
+// Single cpu balancer that switches pool on every activation; not thread-safe
+struct TRoundRobinBalancer: public IBalancer {
+ TCpuState* State;
+ TMap<TPoolId, TPoolId> NextPool;
+
+ bool AddCpu(const TCpuAllocation& cpuAlloc, TCpuState* cpu) override {
+ State = cpu;
+ TPoolId prev = cpuAlloc.AllowedPools.rbegin()->PoolId;
+ for (auto& p : cpuAlloc.AllowedPools) {
+ NextPool[prev] = p.PoolId;
+ prev = p.PoolId;
+ }
+ return true;
+ }
+
+ bool TryLock(ui64) override { return true; }
+ void SetPoolStats(TPoolId, const TBalancerStats&) override {}
+ void Unlock() override {}
+
+ void Balance() override {
+ TPoolId assigned;
+ TPoolId current;
+ State->Load(assigned, current);
+ State->AssignPool(NextPool[assigned]);
+ }
+};
+
+void AddUnitedPool(THolder<TActorSystemSetup>& setup, ui32 concurrency = 0) {
+ TUnitedExecutorPoolConfig united;
+ united.PoolId = setup->GetExecutorsCount();
+ united.Concurrency = concurrency;
+ setup->CpuManager.United.emplace_back(std::move(united));
+}
+
+THolder<TActorSystemSetup> GetActorSystemSetup(ui32 cpuCount) {
+ auto setup = MakeHolder<NActors::TActorSystemSetup>();
+ setup->NodeId = 1;
+ setup->CpuManager.UnitedWorkers.CpuCount = cpuCount;
+ setup->CpuManager.UnitedWorkers.NoRealtime = true; // unavailable in test environment
+ setup->Scheduler = new TBasicSchedulerThread(NActors::TSchedulerConfig(512, 0));
+ return setup;
+}
+
+Y_UNIT_TEST_SUITE(UnitedExecutorPool) {
+
+#ifdef _linux_
+
+ Y_UNIT_TEST(OnePoolManyCpus) {
+ const size_t msgCount = 1e4;
+ auto setup = GetActorSystemSetup(4);
+ AddUnitedPool(setup);
+ TActorSystem actorSystem(setup);
+ actorSystem.Start();
+
+ auto begin = TInstant::Now();
+
+ auto actor = new TTestSenderActor();
+ auto actorId = actorSystem.Register(actor);
+ actor->Start(actor->SelfId(), msgCount);
+ actorSystem.Send(actorId, new TEvMsg());
+
+ while (actor->GetCounter()) {
+ auto now = TInstant::Now();
+ UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "Counter is " << actor->GetCounter());
+
+ Sleep(TDuration::MilliSeconds(1));
+ }
+
+ TVector<TExecutorThreadStats> stats;
+ TExecutorPoolStats poolStats;
+ actorSystem.GetPoolStats(0, poolStats, stats);
+ // Sum all per-thread counters into the 0th element
+ for (ui32 idx = 1; idx < stats.size(); ++idx) {
+ stats[0].Aggregate(stats[idx]);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].SentEvents, msgCount - 1);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount);
+ //UNIT_ASSERT_VALUES_EQUAL(stats[0].PreemptedEvents, 0); // depends on execution time and system load, so may be non-zero
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].NonDeliveredEvents, 0);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].EmptyMailboxActivation, 0);
+ //UNIT_ASSERT_VALUES_EQUAL(stats[0].CpuNs, 0); // depends on total duration of test, so undefined
+ UNIT_ASSERT(stats[0].ElapsedTicks > 0);
+ UNIT_ASSERT(stats[0].ParkedTicks == 0); // per-pool parked time does not make sense for united pools
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].BlockedTicks, 0);
+ UNIT_ASSERT(stats[0].ActivationTimeHistogram.TotalSamples >= msgCount / TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].EventDeliveryTimeHistogram.TotalSamples, msgCount);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].EventProcessingCountHistogram.TotalSamples, msgCount);
+ UNIT_ASSERT(stats[0].EventProcessingTimeHistogram.TotalSamples > 0);
+ UNIT_ASSERT(stats[0].ElapsedTicksByActivity[0] > 0);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEventsByActivity[0], msgCount);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].ActorsAliveByActivity[0], 1);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].ScheduledEventsByActivity[0], 0);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolDestroyedActors, 0);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolAllocatedMailboxes, 4095); // one line
+ UNIT_ASSERT(stats[0].MailboxPushedOutByTime + stats[0].MailboxPushedOutByEventCount + stats[0].MailboxPushedOutBySoftPreemption >= msgCount / TBasicExecutorPoolConfig::DEFAULT_EVENTS_PER_MAILBOX);
+ }
+
+ Y_UNIT_TEST(ManyPoolsOneSharedCpu) {
+ const size_t msgCount = 1e4;
+ const size_t pools = 4;
+ auto setup = GetActorSystemSetup(1);
+ for (size_t pool = 0; pool < pools; pool++) {
+ AddUnitedPool(setup);
+ }
+ TActorSystem actorSystem(setup);
+ actorSystem.Start();
+
+ auto begin = TInstant::Now();
+
+ TVector<TTestSenderActor*> actors;
+ for (size_t pool = 0; pool < pools; pool++) {
+ auto actor = new TTestSenderActor();
+ auto actorId = actorSystem.Register(actor, TMailboxType::HTSwap, pool);
+ actor->Start(actor->SelfId(), msgCount);
+ actorSystem.Send(actorId, new TEvMsg());
+ actors.push_back(actor);
+ }
+
+ while (true) {
+ size_t left = 0;
+ for (auto actor : actors) {
+ left += actor->GetCounter();
+ }
+ if (left == 0) {
+ break;
+ }
+ auto now = TInstant::Now();
+ UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "left " << left);
+ Sleep(TDuration::MilliSeconds(1));
+ }
+
+ for (size_t pool = 0; pool < pools; pool++) {
+ TVector<TExecutorThreadStats> stats;
+ TExecutorPoolStats poolStats;
+ actorSystem.GetPoolStats(pool, poolStats, stats);
+ // Sum all per-thread counters into the 0th element
+ for (ui32 idx = 1; idx < stats.size(); ++idx) {
+ stats[0].Aggregate(stats[idx]);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1);
+ }
+ }
+
+ Y_UNIT_TEST(ManyPoolsOneAssignedCpu) {
+ const size_t msgCount = 1e4;
+ const size_t pools = 4;
+ auto setup = GetActorSystemSetup(1);
+ setup->Balancer.Reset(new TRoundRobinBalancer());
+ for (size_t pool = 0; pool < pools; pool++) {
+ AddUnitedPool(setup);
+ }
+ TActorSystem actorSystem(setup);
+ actorSystem.Start();
+
+ auto begin = TInstant::Now();
+
+ TVector<TTestSenderActor*> actors;
+ for (size_t pool = 0; pool < pools; pool++) {
+ auto actor = new TTestSenderActor();
+ auto actorId = actorSystem.Register(actor, TMailboxType::HTSwap, pool);
+ actor->Start(actor->SelfId(), msgCount);
+ actorSystem.Send(actorId, new TEvMsg());
+ actors.push_back(actor);
+ }
+
+ while (true) {
+ size_t left = 0;
+ for (auto actor : actors) {
+ left += actor->GetCounter();
+ }
+ if (left == 0) {
+ break;
+ }
+ auto now = TInstant::Now();
+ UNIT_ASSERT_C(now - begin < TDuration::Seconds(5), "left " << left);
+ Sleep(TDuration::MilliSeconds(1));
+ }
+
+ for (size_t pool = 0; pool < pools; pool++) {
+ TVector<TExecutorThreadStats> stats;
+ TExecutorPoolStats poolStats;
+ actorSystem.GetPoolStats(pool, poolStats, stats);
+ // Sum all per-thread counters into the 0th element
+ for (ui32 idx = 1; idx < stats.size(); ++idx) {
+ stats[0].Aggregate(stats[idx]);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1);
+ }
+ }
+
+ Y_UNIT_TEST(ManyPoolsOneCpuSlowEvents) {
+ const size_t msgCount = 3;
+ const size_t pools = 4;
+ auto setup = GetActorSystemSetup(1);
+ for (size_t pool = 0; pool < pools; pool++) {
+ AddUnitedPool(setup);
+ }
+ TActorSystem actorSystem(setup);
+ actorSystem.Start();
+
+ auto begin = TInstant::Now();
+
+ TVector<TTestSenderActor*> actors;
+ for (size_t pool = 0; pool < pools; pool++) {
+ auto actor = new TTestSenderActor([]() {
+ DoTimedWork(100'000);
+ });
+ auto actorId = actorSystem.Register(actor, TMailboxType::HTSwap, pool);
+ actor->Start(actor->SelfId(), msgCount);
+ actorSystem.Send(actorId, new TEvMsg());
+ actors.push_back(actor);
+ }
+
+ while (true) {
+ size_t left = 0;
+ for (auto actor : actors) {
+ left += actor->GetCounter();
+ }
+ if (left == 0) {
+ break;
+ }
+ auto now = TInstant::Now();
+ UNIT_ASSERT_C(now - begin < TDuration::Seconds(15), "left " << left);
+ Sleep(TDuration::MilliSeconds(1));
+ }
+
+ for (size_t pool = 0; pool < pools; pool++) {
+ TVector<TExecutorThreadStats> stats;
+ TExecutorPoolStats poolStats;
+ actorSystem.GetPoolStats(pool, poolStats, stats);
+ // Sum all per-thread counters into the 0th element
+ for (ui32 idx = 1; idx < stats.size(); ++idx) {
+ stats[0].Aggregate(stats[idx]);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].ReceivedEvents, msgCount);
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].PreemptedEvents, msgCount); // every 100ms event should be preempted
+ UNIT_ASSERT_VALUES_EQUAL(stats[0].PoolActorRegistrations, 1);
+ }
+ }
+
+#endif
+
+}
diff --git a/library/cpp/actors/core/executor_thread.cpp b/library/cpp/actors/core/executor_thread.cpp
new file mode 100644
index 0000000000..446b651efd
--- /dev/null
+++ b/library/cpp/actors/core/executor_thread.cpp
@@ -0,0 +1,563 @@
+#include "executor_thread.h"
+#include "actorsystem.h"
+#include "callstack.h"
+#include "mailbox.h"
+#include "event.h"
+#include "events.h"
+
+#include <library/cpp/actors/prof/tag.h>
+#include <library/cpp/actors/util/affinity.h>
+#include <library/cpp/actors/util/datetime.h>
+#include <library/cpp/actors/util/thread.h>
+
+#ifdef BALLOC
+#include <library/cpp/balloc/optional/operators.h>
+#endif
+
+#ifdef _linux_
+#include <sys/syscall.h>
+#include <unistd.h>
+#endif
+
+#include <util/system/type_name.h>
+#include <util/system/datetime.h>
+
+LWTRACE_USING(ACTORLIB_PROVIDER)
+
+namespace NActors {
+ constexpr TDuration TExecutorThread::DEFAULT_TIME_PER_MAILBOX;
+
+ TExecutorThread::TExecutorThread(
+ TWorkerId workerId,
+ TWorkerId cpuId,
+ TActorSystem* actorSystem,
+ IExecutorPool* executorPool,
+ TMailboxTable* mailboxTable,
+ const TString& threadName,
+ TDuration timePerMailbox,
+ ui32 eventsPerMailbox)
+ : ActorSystem(actorSystem)
+ , ExecutorPool(executorPool)
+ , Ctx(workerId, cpuId, actorSystem ? actorSystem->GetMaxActivityType() : 1)
+ , ThreadName(threadName)
+ {
+ Ctx.Switch(
+ ExecutorPool,
+ mailboxTable,
+ NHPTimer::GetClockRate() * timePerMailbox.SecondsFloat(),
+ eventsPerMailbox,
+ ui64(-1), // infinite soft deadline
+ &Ctx.WorkerStats);
+ }
+
+ TActorId TExecutorThread::RegisterActor(IActor* actor, TMailboxType::EType mailboxType, ui32 poolId, const TActorId& parentId) {
+ if (poolId == Max<ui32>())
+ return Ctx.Executor->Register(actor, mailboxType, ++RevolvingWriteCounter, parentId ? parentId : CurrentRecipient);
+ else
+ return ActorSystem->Register(actor, mailboxType, poolId, ++RevolvingWriteCounter, parentId ? parentId : CurrentRecipient);
+ }
+
+ TActorId TExecutorThread::RegisterActor(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId) {
+ return Ctx.Executor->Register(actor, mailbox, hint, parentId ? parentId : CurrentRecipient);
+ }
+
+ void TExecutorThread::UnregisterActor(TMailboxHeader* mailbox, ui64 localActorId) {
+ IActor* actor = mailbox->DetachActor(localActorId);
+ Ctx.DecrementActorsAliveByActivity(actor->GetActivityType());
+ DyingActors.push_back(THolder(actor));
+ }
+
+ void TExecutorThread::DropUnregistered() {
+ DyingActors.clear(); // here is actual destruction of actors
+ }
+
+ void TExecutorThread::Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) {
+ ++CurrentActorScheduledEventsCounter;
+ Ctx.Executor->Schedule(deadline, ev, cookie, Ctx.WorkerId);
+ }
+
+ void TExecutorThread::Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) {
+ ++CurrentActorScheduledEventsCounter;
+ Ctx.Executor->Schedule(deadline, ev, cookie, Ctx.WorkerId);
+ }
+
+ void TExecutorThread::Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie) {
+ ++CurrentActorScheduledEventsCounter;
+ Ctx.Executor->Schedule(delta, ev, cookie, Ctx.WorkerId);
+ }
+
+ template <class T>
+ inline TString SafeTypeName(T* t) {
+ if (t == nullptr) {
+ return "nullptr";
+ }
+ try {
+ return TypeName(*t);
+ } catch (...) {
+ return "unknown-type";
+ }
+ }
+
+ inline TString ActorTypeName(const IActor* actor, ui32 activityType) {
+ return actor ? SafeTypeName(actor) : ("activityType_" + ToString(activityType) + " (destroyed)");
+ }
+
+ inline void LwTraceSlowDelivery(IEventHandle* ev, const IActor* actor, ui32 poolId, const TActorId& currentRecipient,
+ double delivMs, double sinceActivationMs, ui32 eventsExecutedBefore) {
+ const auto baseEv = (ev && ev->HasEvent()) ? ev->GetBase() : nullptr;
+ LWPROBE(EventSlowDelivery,
+ poolId,
+ delivMs,
+ sinceActivationMs,
+ eventsExecutedBefore,
+ baseEv ? SafeTypeName(baseEv) : (ev ? ToString(ev->Type) : TString("nullptr")),
+ currentRecipient.ToString(),
+ SafeTypeName(actor));
+ }
+
+ inline void LwTraceSlowEvent(IEventHandle* ev, ui32 evTypeForTracing, const IActor* actor, ui32 poolId, ui32 activityType,
+ const TActorId& currentRecipient, double eventMs) {
+ // Event could have been destroyed by actor->Receive();
+ const auto baseEv = (ev && ev->HasEvent()) ? ev->GetBase() : nullptr;
+ LWPROBE(SlowEvent,
+ poolId,
+ eventMs,
+ baseEv ? SafeTypeName(baseEv) : ToString(evTypeForTracing),
+ currentRecipient.ToString(),
+ ActorTypeName(actor, activityType));
+ }
+
+ template <typename TMailbox>
+ void TExecutorThread::Execute(TMailbox* mailbox, ui32 hint) {
+ Y_VERIFY_DEBUG(DyingActors.empty());
+
+ bool reclaimAsFree = false;
+
+ NHPTimer::STime hpstart = GetCycleCountFast();
+ NHPTimer::STime hpprev = hpstart;
+
+ IActor* actor = nullptr;
+ ui32 prevActivityType = std::numeric_limits<ui32>::max();
+ TActorId recipient;
+ for (ui32 executed = 0; executed < Ctx.EventsPerMailbox; ++executed) {
+ TAutoPtr<IEventHandle> ev(mailbox->Pop());
+ if (!!ev) {
+ NHPTimer::STime hpnow;
+ recipient = ev->GetRecipientRewrite();
+ if (actor = mailbox->FindActor(recipient.LocalId())) {
+ TActorContext ctx(*mailbox, *this, hpprev, recipient);
+ TlsActivationContext = &ctx;
+
+#ifdef USE_ACTOR_CALLSTACK
+ TCallstack::GetTlsCallstack() = ev->Callstack;
+ TCallstack::GetTlsCallstack().SetLinesToSkip();
+#endif
+ CurrentRecipient = recipient;
+ CurrentActorScheduledEventsCounter = 0;
+
+ if (executed == 0) {
+ double usec = Ctx.AddActivationStats(AtomicLoad(&mailbox->ScheduleMoment), hpprev);
+ if (usec > 500) {
+ GLOBAL_LWPROBE(ACTORLIB_PROVIDER, SlowActivation, Ctx.PoolId, usec / 1000.0);
+ }
+ }
+
+ i64 usecDeliv = Ctx.AddEventDeliveryStats(ev->SendTime, hpprev);
+ if (usecDeliv > 5000) {
+ double sinceActivationMs = NHPTimer::GetSeconds(hpprev - hpstart) * 1000.0;
+ LwTraceSlowDelivery(ev.Get(), actor, Ctx.PoolId, CurrentRecipient, NHPTimer::GetSeconds(hpprev - ev->SendTime) * 1000.0, sinceActivationMs, executed);
+ }
+
+ ui32 evTypeForTracing = ev->Type;
+
+ ui32 activityType = actor->GetActivityType();
+ if (activityType != prevActivityType) {
+ prevActivityType = activityType;
+ NProfiling::TMemoryTagScope::Reset(ActorSystem->MemProfActivityBase + activityType);
+ }
+
+ actor->Receive(ev, ctx);
+
+ size_t dyingActorsCnt = DyingActors.size();
+ Ctx.UpdateActorsStats(dyingActorsCnt);
+ if (dyingActorsCnt) {
+ DropUnregistered();
+ actor = nullptr;
+ }
+
+ if (mailbox->IsEmpty()) // was not-free and become free, we must reclaim mailbox
+ reclaimAsFree = true;
+
+ hpnow = GetCycleCountFast();
+ NHPTimer::STime elapsed = Ctx.AddEventProcessingStats(hpprev, hpnow, activityType, CurrentActorScheduledEventsCounter);
+ if (elapsed > 1000000) {
+ LwTraceSlowEvent(ev.Get(), evTypeForTracing, actor, Ctx.PoolId, activityType, CurrentRecipient, NHPTimer::GetSeconds(elapsed) * 1000.0);
+ }
+
+ // The actor might have been destroyed
+ if (actor)
+ actor->AddElapsedTicks(elapsed);
+
+ CurrentRecipient = TActorId();
+ } else {
+ TAutoPtr<IEventHandle> nonDelivered = ev->ForwardOnNondelivery(TEvents::TEvUndelivered::ReasonActorUnknown);
+ if (nonDelivered.Get()) {
+ ActorSystem->Send(nonDelivered);
+ } else {
+ Ctx.IncrementNonDeliveredEvents();
+ }
+ hpnow = GetCycleCountFast();
+ }
+
+ hpprev = hpnow;
+
+ // Soft preemption in united pool
+ if (Ctx.SoftDeadlineTs < (ui64)hpnow) {
+ AtomicStore(&mailbox->ScheduleMoment, hpnow);
+ Ctx.IncrementMailboxPushedOutBySoftPreemption();
+ LWTRACK(MailboxPushedOutBySoftPreemption,
+ Ctx.Orbit,
+ Ctx.PoolId,
+ Ctx.Executor->GetName(),
+ executed + 1,
+ CyclesToDuration(hpnow - hpstart),
+ Ctx.WorkerId,
+ recipient.ToString(),
+ SafeTypeName(actor));
+ break;
+ }
+
+ // time limit inside one mailbox passed, let others do some work
+ if (hpnow - hpstart > (i64)Ctx.TimePerMailboxTs) {
+ AtomicStore(&mailbox->ScheduleMoment, hpnow);
+ Ctx.IncrementMailboxPushedOutByTime();
+ LWTRACK(MailboxPushedOutByTime,
+ Ctx.Orbit,
+ Ctx.PoolId,
+ Ctx.Executor->GetName(),
+ executed + 1,
+ CyclesToDuration(hpnow - hpstart),
+ Ctx.WorkerId,
+ recipient.ToString(),
+ SafeTypeName(actor));
+ break;
+ }
+
+ if (executed + 1 == Ctx.EventsPerMailbox) {
+ AtomicStore(&mailbox->ScheduleMoment, hpnow);
+ Ctx.IncrementMailboxPushedOutByEventCount();
+ LWTRACK(MailboxPushedOutByEventCount,
+ Ctx.Orbit,
+ Ctx.PoolId,
+ Ctx.Executor->GetName(),
+ executed + 1,
+ CyclesToDuration(hpnow - hpstart),
+ Ctx.WorkerId,
+ recipient.ToString(),
+ SafeTypeName(actor));
+ break;
+ }
+ } else {
+ if (executed == 0)
+ Ctx.IncrementEmptyMailboxActivation();
+ LWTRACK(MailboxEmpty,
+ Ctx.Orbit,
+ Ctx.PoolId,
+ Ctx.Executor->GetName(),
+ executed,
+ CyclesToDuration(GetCycleCountFast() - hpstart),
+ Ctx.WorkerId,
+ recipient.ToString(),
+ SafeTypeName(actor));
+ break; // empty queue, leave
+ }
+ }
+
+ NProfiling::TMemoryTagScope::Reset(0);
+ TlsActivationContext = nullptr;
+ UnlockFromExecution(mailbox, Ctx.Executor, reclaimAsFree, hint, Ctx.WorkerId, RevolvingWriteCounter);
+ }
+
+ TThreadId TExecutorThread::GetThreadId() const {
+#ifdef _linux_
+ while (AtomicLoad(&ThreadId) == UnknownThreadId) {
+ NanoSleep(1000);
+ }
+#endif
+ return ThreadId;
+ }
+
+ void* TExecutorThread::ThreadProc() {
+#ifdef _linux_
+ pid_t tid = syscall(SYS_gettid);
+ AtomicSet(ThreadId, (ui64)tid);
+#endif
+
+#ifdef BALLOC
+ ThreadDisableBalloc();
+#endif
+
+ if (ThreadName) {
+ ::SetCurrentThreadName(ThreadName);
+ }
+
+ ExecutorPool->SetRealTimeMode();
+ TAffinityGuard affinity(ExecutorPool->Affinity());
+
+ NHPTimer::STime hpnow = GetCycleCountFast();
+ NHPTimer::STime hpprev = hpnow;
+ ui64 execCount = 0;
+ ui64 readyActivationCount = 0;
+ i64 execCycles = 0;
+ i64 nonExecCycles = 0;
+
+ for (;;) {
+ if (ui32 activation = ExecutorPool->GetReadyActivation(Ctx, ++RevolvingReadCounter)) {
+ LWTRACK(ActivationBegin, Ctx.Orbit, Ctx.CpuId, Ctx.PoolId, Ctx.WorkerId, NHPTimer::GetSeconds(Ctx.Lease.GetPreciseExpireTs()) * 1e3);
+ readyActivationCount++;
+ if (TMailboxHeader* header = Ctx.MailboxTable->Get(activation)) {
+ if (header->LockForExecution()) {
+ hpnow = GetCycleCountFast();
+ nonExecCycles += hpnow - hpprev;
+ hpprev = hpnow;
+ switch (header->Type) {
+ case TMailboxType::Simple:
+ Execute(static_cast<TMailboxTable::TSimpleMailbox*>(header), activation);
+ break;
+ case TMailboxType::Revolving:
+ Execute(static_cast<TMailboxTable::TRevolvingMailbox*>(header), activation);
+ break;
+ case TMailboxType::HTSwap:
+ Execute(static_cast<TMailboxTable::THTSwapMailbox*>(header), activation);
+ break;
+ case TMailboxType::ReadAsFilled:
+ Execute(static_cast<TMailboxTable::TReadAsFilledMailbox*>(header), activation);
+ break;
+ case TMailboxType::TinyReadAsFilled:
+ Execute(static_cast<TMailboxTable::TTinyReadAsFilledMailbox*>(header), activation);
+ break;
+ }
+ hpnow = GetCycleCountFast();
+ execCycles += hpnow - hpprev;
+ hpprev = hpnow;
+ execCount++;
+ if (execCycles + nonExecCycles > 39000000) { // every 15 ms at 2.6GHz, so 1000 items is 15 sec (solomon interval)
+ LWPROBE(ExecutorThreadStats, ExecutorPool->PoolId, ExecutorPool->GetName(), Ctx.WorkerId,
+ execCount, readyActivationCount,
+ NHPTimer::GetSeconds(execCycles) * 1000.0, NHPTimer::GetSeconds(nonExecCycles) * 1000.0);
+ execCount = 0;
+ readyActivationCount = 0;
+ execCycles = 0;
+ nonExecCycles = 0;
+ Ctx.UpdateThreadTime();
+ }
+ }
+ }
+ LWTRACK(ActivationEnd, Ctx.Orbit, Ctx.CpuId, Ctx.PoolId, Ctx.WorkerId);
+ Ctx.Orbit.Reset();
+ } else { // no activation means PrepareStop was called so thread must terminate
+ break;
+ }
+ }
+ return nullptr;
+ }
+
+ // there must be barrier and check-read with following cas
+ // or just cas w/o read.
+ // or queue unlocks must be performed with exchange and not generic write
+ // TODO: check performance of those options under contention
+
+ // placed here in hope for better compiler optimization
+
+ bool TMailboxHeader::MarkForSchedule() {
+ AtomicBarrier();
+ for (;;) {
+ const ui32 state = AtomicLoad(&ExecutionState);
+ switch (state) {
+ case TExecutionState::Inactive:
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::Scheduled, TExecutionState::Inactive))
+ return true;
+ break;
+ case TExecutionState::Scheduled:
+ return false;
+ case TExecutionState::Leaving:
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::LeavingMarked, TExecutionState::Leaving))
+ return true;
+ break;
+ case TExecutionState::Executing:
+ case TExecutionState::LeavingMarked:
+ return false;
+ case TExecutionState::Free:
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::Free))
+ return true;
+ break;
+ case TExecutionState::FreeScheduled:
+ return false;
+ case TExecutionState::FreeLeaving:
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeLeavingMarked, TExecutionState::FreeLeaving))
+ return true;
+ break;
+ case TExecutionState::FreeExecuting:
+ case TExecutionState::FreeLeavingMarked:
+ return false;
+ default:
+ Y_FAIL();
+ }
+ }
+ }
+
+ bool TMailboxHeader::LockForExecution() {
+ AtomicBarrier(); // strictly speaking here should be AtomicBarrier, but as we got mailboxes from queue - this barrier is already set implicitly and could be removed
+ for (;;) {
+ const ui32 state = AtomicLoad(&ExecutionState);
+ switch (state) {
+ case TExecutionState::Inactive:
+ return false;
+ case TExecutionState::Scheduled:
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::Executing, TExecutionState::Scheduled))
+ return true;
+ break;
+ case TExecutionState::Leaving:
+ case TExecutionState::Executing:
+ case TExecutionState::LeavingMarked:
+ return false;
+ case TExecutionState::Free:
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeExecuting, TExecutionState::Free))
+ return true;
+ break;
+ case TExecutionState::FreeScheduled:
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeExecuting, TExecutionState::FreeScheduled))
+ return true;
+ break;
+ case TExecutionState::FreeLeaving:
+ case TExecutionState::FreeExecuting:
+ case TExecutionState::FreeLeavingMarked:
+ return false;
+ default:
+ Y_FAIL();
+ }
+ }
+ }
+
+ bool TMailboxHeader::LockFromFree() {
+ AtomicBarrier();
+ for (;;) {
+ const ui32 state = AtomicLoad(&ExecutionState);
+ switch (state) {
+ case TExecutionState::Inactive:
+ case TExecutionState::Scheduled:
+ case TExecutionState::Leaving:
+ case TExecutionState::Executing:
+ case TExecutionState::LeavingMarked:
+ Y_FAIL();
+ case TExecutionState::Free:
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::Executing, TExecutionState::Free))
+ return true;
+ break;
+ case TExecutionState::FreeScheduled:
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::Executing, TExecutionState::FreeScheduled))
+ return true;
+ break;
+ case TExecutionState::FreeLeaving:
+ case TExecutionState::FreeExecuting:
+ case TExecutionState::FreeLeavingMarked:
+ return false;
+ default:
+ Y_FAIL();
+ }
+ }
+ }
+
+ void TMailboxHeader::UnlockFromExecution1() {
+ const ui32 state = AtomicLoad(&ExecutionState);
+ if (state == TExecutionState::Executing)
+ AtomicStore(&ExecutionState, (ui32)TExecutionState::Leaving);
+ else if (state == TExecutionState::FreeExecuting)
+ AtomicStore(&ExecutionState, (ui32)TExecutionState::FreeLeaving);
+ else
+ Y_FAIL();
+ AtomicBarrier();
+ }
+
+ bool TMailboxHeader::UnlockFromExecution2(bool wouldReschedule) {
+ AtomicBarrier();
+ for (;;) {
+ const ui32 state = AtomicLoad(&ExecutionState);
+ switch (state) {
+ case TExecutionState::Inactive:
+ case TExecutionState::Scheduled:
+ Y_FAIL();
+ case TExecutionState::Leaving:
+ if (!wouldReschedule) {
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::Inactive, TExecutionState::Leaving))
+ return false;
+ } else {
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::Scheduled, TExecutionState::Leaving))
+ return true;
+ }
+ break;
+ case TExecutionState::Executing:
+ Y_FAIL();
+ case TExecutionState::LeavingMarked:
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::Scheduled, TExecutionState::LeavingMarked))
+ return true;
+ break;
+ case TExecutionState::Free:
+ case TExecutionState::FreeScheduled:
+ Y_FAIL();
+ case TExecutionState::FreeLeaving:
+ if (!wouldReschedule) {
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::Free, TExecutionState::FreeLeaving))
+ return false;
+ } else {
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::FreeLeaving))
+ return true;
+ }
+ break;
+ case TExecutionState::FreeExecuting:
+ Y_FAIL();
+ case TExecutionState::FreeLeavingMarked:
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::FreeLeavingMarked))
+ return true;
+ break;
+ default:
+ Y_FAIL();
+ }
+ }
+ }
+
+ bool TMailboxHeader::UnlockAsFree(bool wouldReschedule) {
+ AtomicBarrier();
+ for (;;) {
+ const ui32 state = AtomicLoad(&ExecutionState);
+ switch (state) {
+ case TExecutionState::Inactive:
+ case TExecutionState::Scheduled:
+ Y_FAIL();
+ case TExecutionState::Leaving:
+ if (!wouldReschedule) {
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::Free, TExecutionState::Leaving))
+ return false;
+ } else {
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::Leaving))
+ return true;
+ }
+ break;
+ case TExecutionState::Executing:
+ Y_FAIL();
+ case TExecutionState::LeavingMarked:
+ if (AtomicUi32Cas(&ExecutionState, TExecutionState::FreeScheduled, TExecutionState::LeavingMarked))
+ return true;
+ break;
+ case TExecutionState::Free:
+ case TExecutionState::FreeScheduled:
+ case TExecutionState::FreeLeaving:
+ case TExecutionState::FreeExecuting:
+ case TExecutionState::FreeLeavingMarked:
+ Y_FAIL();
+ default:
+ Y_FAIL();
+ }
+ }
+ }
+}
diff --git a/library/cpp/actors/core/executor_thread.h b/library/cpp/actors/core/executor_thread.h
new file mode 100644
index 0000000000..9d3c573f0d
--- /dev/null
+++ b/library/cpp/actors/core/executor_thread.h
@@ -0,0 +1,112 @@
+#pragma once
+
+#include "defs.h"
+#include "event.h"
+#include "actor.h"
+#include "actorsystem.h"
+#include "callstack.h"
+#include "probes.h"
+#include "worker_context.h"
+
+#include <library/cpp/actors/util/datetime.h>
+
+#include <util/system/thread.h>
+
+namespace NActors {
+
+ class TExecutorThread: public ISimpleThread {
+ public:
+ static constexpr TDuration DEFAULT_TIME_PER_MAILBOX =
+ TDuration::MilliSeconds(10);
+ static constexpr ui32 DEFAULT_EVENTS_PER_MAILBOX = 100;
+
+ TExecutorThread(TWorkerId workerId,
+ TWorkerId cpuId,
+ TActorSystem* actorSystem,
+ IExecutorPool* executorPool,
+ TMailboxTable* mailboxTable,
+ const TString& threadName,
+ TDuration timePerMailbox = DEFAULT_TIME_PER_MAILBOX,
+ ui32 eventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX);
+
+ TExecutorThread(TWorkerId workerId,
+ TActorSystem* actorSystem,
+ IExecutorPool* executorPool,
+ TMailboxTable* mailboxTable,
+ const TString& threadName,
+ TDuration timePerMailbox = DEFAULT_TIME_PER_MAILBOX,
+ ui32 eventsPerMailbox = DEFAULT_EVENTS_PER_MAILBOX)
+ : TExecutorThread(workerId, 0, actorSystem, executorPool, mailboxTable, threadName, timePerMailbox, eventsPerMailbox)
+ {}
+
+ TActorId RegisterActor(IActor* actor, TMailboxType::EType mailboxType = TMailboxType::HTSwap, ui32 poolId = Max<ui32>(),
+ const TActorId& parentId = TActorId());
+ TActorId RegisterActor(IActor* actor, TMailboxHeader* mailbox, ui32 hint, const TActorId& parentId = TActorId());
+ void UnregisterActor(TMailboxHeader* mailbox, ui64 localActorId);
+ void DropUnregistered();
+ const std::vector<THolder<IActor>>& GetUnregistered() const { return DyingActors; }
+
+ void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr);
+ void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr);
+ void Schedule(TDuration delta, TAutoPtr<IEventHandle> ev, ISchedulerCookie* cookie = nullptr);
+
+ bool Send(TAutoPtr<IEventHandle> ev) {
+#ifdef USE_ACTOR_CALLSTACK
+ ev->Callstack = TCallstack::GetTlsCallstack();
+ ev->Callstack.Trace();
+#endif
+ Ctx.IncrementSentEvents();
+ return ActorSystem->Send(ev);
+ }
+
+ void GetCurrentStats(TExecutorThreadStats& statsCopy) const {
+ Ctx.GetCurrentStats(statsCopy);
+ }
+
+ TThreadId GetThreadId() const; // blocks, must be called after Start()
+ TWorkerId GetWorkerId() const { return Ctx.WorkerId; }
+
+ private:
+ void* ThreadProc();
+
+ template <typename TMailbox>
+ void Execute(TMailbox* mailbox, ui32 hint);
+
+ public:
+ TActorSystem* const ActorSystem;
+
+ private:
+ // Pool-specific
+ IExecutorPool* const ExecutorPool;
+
+ // Event-specific (currently executing)
+ TVector<THolder<IActor>> DyingActors;
+ TActorId CurrentRecipient;
+ ui64 CurrentActorScheduledEventsCounter = 0;
+
+ // Thread-specific
+ TWorkerContext Ctx;
+ ui64 RevolvingReadCounter = 0;
+ ui64 RevolvingWriteCounter = 0;
+ const TString ThreadName;
+ volatile TThreadId ThreadId = UnknownThreadId;
+ };
+
+ template <typename TMailbox>
+ void UnlockFromExecution(TMailbox* mailbox, IExecutorPool* executorPool, bool asFree, ui32 hint, TWorkerId workerId, ui64& revolvingWriteCounter) {
+ mailbox->UnlockFromExecution1();
+ const bool needReschedule1 = (nullptr != mailbox->Head());
+ if (!asFree) {
+ if (mailbox->UnlockFromExecution2(needReschedule1)) {
+ RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast());
+ executorPool->ScheduleActivationEx(hint, ++revolvingWriteCounter);
+ }
+ } else {
+ if (mailbox->UnlockAsFree(needReschedule1)) {
+ RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast());
+ executorPool->ScheduleActivationEx(hint, ++revolvingWriteCounter);
+ }
+ executorPool->ReclaimMailbox(TMailbox::MailboxType, hint, workerId, ++revolvingWriteCounter);
+ }
+ }
+}
diff --git a/library/cpp/actors/core/hfunc.h b/library/cpp/actors/core/hfunc.h
new file mode 100644
index 0000000000..26f3c65013
--- /dev/null
+++ b/library/cpp/actors/core/hfunc.h
@@ -0,0 +1,84 @@
+#pragma once
+
+#include "actor.h"
+#include "executor_thread.h"
+
+#include <util/system/defaults.h>
+
+#define HFunc(TEvType, HandleFunc) \
+ case TEvType::EventType: { \
+ typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \
+ HandleFunc(*x, ctx); \
+ break; \
+ }
+
+#define hFunc(TEvType, HandleFunc) \
+ case TEvType::EventType: { \
+ typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \
+ HandleFunc(*x); \
+ break; \
+ }
+
+#define HFuncTraced(TEvType, HandleFunc) \
+ case TEvType::EventType: { \
+ TRACE_EVENT_TYPE(Y_STRINGIZE(TEvType)); \
+ TEvType::TPtr* x = reinterpret_cast<TEvType::TPtr*>(&ev); \
+ HandleFunc(*x, ctx); \
+ break; \
+ }
+
+#define hFuncTraced(TEvType, HandleFunc) \
+ case TEvType::EventType: { \
+ TRACE_EVENT_TYPE(Y_STRINGIZE(TEvType)); \
+ typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \
+ HandleFunc(*x); \
+ break; \
+ }
+
+#define HTemplFunc(TEvType, HandleFunc) \
+ case TEvType::EventType: { \
+ typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \
+ HandleFunc(*x, ctx); \
+ break; \
+ }
+
+#define hTemplFunc(TEvType, HandleFunc) \
+ case TEvType::EventType: { \
+ typename TEvType::TPtr* x = reinterpret_cast<typename TEvType::TPtr*>(&ev); \
+ HandleFunc(*x); \
+ break; \
+ }
+
+#define SFunc(TEvType, HandleFunc) \
+ case TEvType::EventType: \
+ HandleFunc(ctx); \
+ break;
+
+#define sFunc(TEvType, HandleFunc) \
+ case TEvType::EventType: \
+ HandleFunc(); \
+ break;
+
+#define CFunc(TEventType, HandleFunc) \
+ case TEventType: \
+ HandleFunc(ctx); \
+ break;
+
+#define cFunc(TEventType, HandleFunc) \
+ case TEventType: \
+ HandleFunc(); \
+ break;
+
+#define FFunc(TEventType, HandleFunc) \
+ case TEventType: \
+ HandleFunc(ev, ctx); \
+ break;
+
+#define fFunc(TEventType, HandleFunc) \
+ case TEventType: \
+ HandleFunc(ev); \
+ break;
+
+#define IgnoreFunc(TEvType) \
+ case TEvType::EventType: \
+ break;
diff --git a/library/cpp/actors/core/interconnect.cpp b/library/cpp/actors/core/interconnect.cpp
new file mode 100644
index 0000000000..9fb33413b2
--- /dev/null
+++ b/library/cpp/actors/core/interconnect.cpp
@@ -0,0 +1,170 @@
+#include "interconnect.h"
+#include <util/digest/murmur.h>
+#include <google/protobuf/text_format.h>
+
+namespace NActors {
+
+ TNodeLocation::TNodeLocation(const NActorsInterconnect::TNodeLocation& location) {
+ const NProtoBuf::Descriptor *descriptor = NActorsInterconnect::TNodeLocation::descriptor();
+ const NActorsInterconnect::TNodeLocation *locp = &location;
+ NActorsInterconnect::TNodeLocation temp; // for legacy location case
+
+ // WalleConfig compatibility section
+ if (locp->HasBody()) {
+ if (locp == &location) {
+ temp.CopyFrom(*locp);
+ locp = &temp;
+ }
+ temp.SetUnit(::ToString(temp.GetBody()));
+ temp.ClearBody();
+ }
+
+ // legacy value processing
+ if (locp->HasDataCenterNum() || locp->HasRoomNum() || locp->HasRackNum() || locp->HasBodyNum()) {
+ if (locp == &location) {
+ temp.CopyFrom(*locp);
+ locp = &temp;
+ }
+ LegacyValue = TLegacyValue{temp.GetDataCenterNum(), temp.GetRoomNum(), temp.GetRackNum(), temp.GetBodyNum()};
+ temp.ClearDataCenterNum();
+ temp.ClearRoomNum();
+ temp.ClearRackNum();
+ temp.ClearBodyNum();
+
+ // legacy format must not interfere with new one
+ const NProtoBuf::Reflection *reflection = temp.GetReflection();
+ for (int i = 0, count = descriptor->field_count(); i < count; ++i) {
+ Y_VERIFY(!reflection->HasField(temp, descriptor->field(i)));
+ }
+
+ const auto& v = LegacyValue->DataCenter;
+ const char *p = reinterpret_cast<const char*>(&v);
+ temp.SetDataCenter(TString(p, strnlen(p, sizeof(ui32))));
+ temp.SetModule(::ToString(LegacyValue->Room));
+ temp.SetRack(::ToString(LegacyValue->Rack));
+ temp.SetUnit(::ToString(LegacyValue->Body));
+ }
+
+ auto makeString = [&] {
+ NProtoBuf::TextFormat::Printer p;
+ p.SetSingleLineMode(true);
+ TString s;
+ p.PrintToString(*locp, &s);
+ return s;
+ };
+
+ // modern format parsing
+ const NProtoBuf::Reflection *reflection = locp->GetReflection();
+ for (int i = 0, count = descriptor->field_count(); i < count; ++i) {
+ const NProtoBuf::FieldDescriptor *field = descriptor->field(i);
+ if (reflection->HasField(*locp, field)) {
+ Y_VERIFY(field->type() == NProtoBuf::FieldDescriptor::TYPE_STRING, "Location# %s", makeString().data());
+ Items.emplace_back(TKeys::E(field->number()), reflection->GetString(*locp, field));
+ }
+ }
+ const NProtoBuf::UnknownFieldSet& unknown = locp->unknown_fields();
+ for (int i = 0, count = unknown.field_count(); i < count; ++i) {
+ const NProtoBuf::UnknownField& field = unknown.field(i);
+ Y_VERIFY(field.type() == NProtoBuf::UnknownField::TYPE_LENGTH_DELIMITED, "Location# %s", makeString().data());
+ Items.emplace_back(TKeys::E(field.number()), field.length_delimited());
+ }
+ std::sort(Items.begin(), Items.end());
+ }
+
+ TNodeLocation::TNodeLocation(TFromSerialized, const TString& s)
+ : TNodeLocation(ParseLocation(s))
+ {}
+
+ NActorsInterconnect::TNodeLocation TNodeLocation::ParseLocation(const TString& s) {
+ NActorsInterconnect::TNodeLocation res;
+ const bool success = res.ParseFromString(s);
+ Y_VERIFY(success);
+ return res;
+ }
+
+ TString TNodeLocation::ToStringUpTo(TKeys::E upToKey) const {
+ const NProtoBuf::Descriptor *descriptor = NActorsInterconnect::TNodeLocation::descriptor();
+
+ TStringBuilder res;
+ for (const auto& [key, value] : Items) {
+ if (upToKey < key) {
+ break;
+ }
+ TString name;
+ if (const NProtoBuf::FieldDescriptor *field = descriptor->FindFieldByNumber(key)) {
+ name = field->options().GetExtension(NActorsInterconnect::PrintName);
+ } else {
+ name = ::ToString(int(key));
+ }
+ if (key != upToKey) {
+ res << name << "=" << value << "/";
+ } else {
+ res << value;
+ }
+ }
+ return res;
+ }
+
+ void TNodeLocation::Serialize(NActorsInterconnect::TNodeLocation *pb) const {
+ const NProtoBuf::Descriptor *descriptor = NActorsInterconnect::TNodeLocation::descriptor();
+ const NProtoBuf::Reflection *reflection = pb->GetReflection();
+ NProtoBuf::UnknownFieldSet *unknown = pb->mutable_unknown_fields();
+ for (const auto& [key, value] : Items) {
+ if (const NProtoBuf::FieldDescriptor *field = descriptor->FindFieldByNumber(key)) {
+ reflection->SetString(pb, field, value);
+ } else {
+ unknown->AddLengthDelimited(key)->assign(value);
+ }
+ }
+ }
+
+ TString TNodeLocation::GetSerializedLocation() const {
+ NActorsInterconnect::TNodeLocation pb;
+ Serialize(&pb);
+ TString s;
+ const bool success = pb.SerializeToString(&s);
+ Y_VERIFY(success);
+ return s;
+ }
+
+ TNodeLocation::TLegacyValue TNodeLocation::GetLegacyValue() const {
+ if (LegacyValue) {
+ return *LegacyValue;
+ }
+
+ ui32 dataCenterId = 0, moduleId = 0, rackId = 0, unitId = 0;
+
+ for (const auto& [key, value] : Items) {
+ switch (key) {
+ case TKeys::DataCenter:
+ memcpy(&dataCenterId, value.data(), Min<size_t>(sizeof(dataCenterId), value.length()));
+ break;
+
+ case TKeys::Module: {
+ const bool success = TryFromString(value, moduleId);
+ Y_VERIFY(success);
+ break;
+ }
+
+ case TKeys::Rack:
+ // hacky way to obtain numeric id by a rack name
+ if (!TryFromString(value, rackId)) {
+ rackId = MurmurHash<ui32>(value.data(), value.length());
+ }
+ break;
+
+ case TKeys::Unit: {
+ const bool success = TryFromString(value, unitId);
+ Y_VERIFY(success);
+ break;
+ }
+
+ default:
+ Y_FAIL("unexpected legacy key# %d", key);
+ }
+ }
+
+ return {dataCenterId, moduleId, rackId, unitId};
+ }
+
+} // NActors
diff --git a/library/cpp/actors/core/interconnect.h b/library/cpp/actors/core/interconnect.h
new file mode 100644
index 0000000000..8d1cbd1e77
--- /dev/null
+++ b/library/cpp/actors/core/interconnect.h
@@ -0,0 +1,248 @@
+#pragma once
+
+#include "events.h"
+#include "event_local.h"
+#include <library/cpp/actors/protos/interconnect.pb.h>
+#include <util/string/cast.h>
+#include <util/string/builder.h>
+
+namespace NActors {
+ class TNodeLocation {
+ public:
+ struct TKeys {
+ enum E : int {
+ DataCenter = 10,
+ Module = 20,
+ Rack = 30,
+ Unit = 40,
+ };
+ };
+
+ struct TLegacyValue {
+ ui32 DataCenter;
+ ui32 Room;
+ ui32 Rack;
+ ui32 Body;
+
+ auto ConvertToTuple() const { return std::make_tuple(DataCenter, Room, Rack, Body); }
+
+ int Compare(const TLegacyValue& other) const {
+ const auto x = ConvertToTuple();
+ const auto y = other.ConvertToTuple();
+ if (x < y) {
+ return -1;
+ } else if (y < x) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ friend bool operator ==(const TLegacyValue& x, const TLegacyValue& y) { return x.Compare(y) == 0; }
+ };
+
+ private:
+ std::optional<TLegacyValue> LegacyValue;
+ std::vector<std::pair<TKeys::E, TString>> Items;
+
+ public:
+ // generic ctors
+ TNodeLocation() = default;
+ TNodeLocation(const TNodeLocation&) = default;
+ TNodeLocation(TNodeLocation&&) = default;
+
+ // protobuf-parser ctor
+ explicit TNodeLocation(const NActorsInterconnect::TNodeLocation& location);
+
+ // serialized protobuf ctor
+ static constexpr struct TFromSerialized {} FromSerialized {};
+ TNodeLocation(TFromSerialized, const TString& s);
+
+ // parser helper function
+ static NActorsInterconnect::TNodeLocation ParseLocation(const TString& s);
+
+ // assignment operators
+ TNodeLocation& operator =(const TNodeLocation&) = default;
+ TNodeLocation& operator =(TNodeLocation&&) = default;
+
+ void Serialize(NActorsInterconnect::TNodeLocation *pb) const;
+ TString GetSerializedLocation() const;
+
+ TString GetDataCenterId() const { return ToStringUpTo(TKeys::DataCenter); }
+ TString GetModuleId() const { return ToStringUpTo(TKeys::Module); }
+ TString GetRackId() const { return ToStringUpTo(TKeys::Rack); }
+ TString ToString() const { return ToStringUpTo(TKeys::E(Max<int>())); }
+ TString ToStringUpTo(TKeys::E upToKey) const;
+
+ TLegacyValue GetLegacyValue() const;
+
+ const std::vector<std::pair<TKeys::E, TString>>& GetItems() const { return Items; }
+
+ bool HasKey(TKeys::E key) const {
+ auto comp = [](const auto& p, TKeys::E value) { return p.first < value; };
+ const auto it = std::lower_bound(Items.begin(), Items.end(), key, comp);
+ return it != Items.end() && it->first == key;
+ }
+
+ int Compare(const TNodeLocation& other) const {
+ if (LegacyValue || other.LegacyValue) {
+ return GetLegacyValue().Compare(other.GetLegacyValue());
+ } else if (Items < other.Items) {
+ return -1;
+ } else if (other.Items < Items) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ void InheritLegacyValue(const TNodeLocation& other) {
+ LegacyValue = other.GetLegacyValue();
+ }
+
+ friend bool operator ==(const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) == 0; }
+ friend bool operator !=(const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) != 0; }
+ friend bool operator < (const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) < 0; }
+ friend bool operator <=(const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) <= 0; }
+ friend bool operator > (const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) > 0; }
+ friend bool operator >=(const TNodeLocation& x, const TNodeLocation& y) { return x.Compare(y) >= 0; }
+ };
+
+ struct TEvInterconnect {
+ enum EEv {
+ EvForward = EventSpaceBegin(TEvents::ES_INTERCONNECT),
+ EvResolveNode, // resolve info about node (internal)
+ EvNodeAddress, // node info (internal)
+ EvConnectNode, // request proxy to establish connection (like: we would send something there soon)
+ EvAcceptIncoming,
+ EvNodeConnected, // node connected notify
+ EvNodeDisconnected, // node disconnected notify
+ EvRegisterNode,
+ EvRegisterNodeResult,
+ EvListNodes,
+ EvNodesInfo,
+ EvDisconnect,
+ EvGetNode,
+ EvNodeInfo,
+ EvClosePeerSocket,
+ EvCloseInputSession,
+ EvPoisonSession,
+ EvTerminate,
+ EvEnd
+ };
+
+ enum ESubscribes {
+ SubConnected,
+ SubDisconnected,
+ };
+
+ static_assert(EvEnd < EventSpaceEnd(TEvents::ES_INTERCONNECT), "expect EvEnd < EventSpaceEnd(TEvents::ES_INTERCONNECT)");
+
+ struct TEvResolveNode;
+ struct TEvNodeAddress;
+
+ struct TEvConnectNode: public TEventBase<TEvConnectNode, EvConnectNode> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvConnectNode, "TEvInterconnect::TEvConnectNode")
+ };
+
+ struct TEvAcceptIncoming;
+
+ struct TEvNodeConnected: public TEventLocal<TEvNodeConnected, EvNodeConnected> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvNodeConnected, "TEvInterconnect::TEvNodeConnected")
+ TEvNodeConnected(ui32 node) noexcept
+ : NodeId(node)
+ {
+ }
+ const ui32 NodeId;
+ };
+
+ struct TEvNodeDisconnected: public TEventLocal<TEvNodeDisconnected, EvNodeDisconnected> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvNodeDisconnected, "TEvInterconnect::TEvNodeDisconnected")
+ TEvNodeDisconnected(ui32 node) noexcept
+ : NodeId(node)
+ {
+ }
+ const ui32 NodeId;
+ };
+
+ struct TEvRegisterNode;
+ struct TEvRegisterNodeResult;
+
+ struct TEvListNodes: public TEventLocal<TEvListNodes, EvListNodes> {
+ };
+
+ struct TNodeInfo {
+ ui32 NodeId;
+ TString Address;
+ TString Host;
+ TString ResolveHost;
+ ui16 Port;
+ TNodeLocation Location;
+
+ TNodeInfo() = default;
+ TNodeInfo(const TNodeInfo&) = default;
+ TNodeInfo& operator =(const TNodeInfo&) = default;
+ TNodeInfo(ui32 nodeId,
+ const TString& address,
+ const TString& host,
+ const TString& resolveHost,
+ ui16 port,
+ const TNodeLocation& location)
+ : NodeId(nodeId)
+ , Address(address)
+ , Host(host)
+ , ResolveHost(resolveHost)
+ , Port(port)
+ , Location(location)
+ {
+ }
+
+ operator ui32() const {
+ return NodeId;
+ }
+ };
+
+ struct TEvNodesInfo: public TEventLocal<TEvNodesInfo, EvNodesInfo> {
+ TVector<TNodeInfo> Nodes;
+
+ const TNodeInfo* GetNodeInfo(ui32 nodeId) const {
+ for (const auto& x : Nodes) {
+ if (x.NodeId == nodeId)
+ return &x;
+ }
+ return nullptr;
+ }
+ };
+
+ struct TEvDisconnect;
+
+ struct TEvGetNode: public TEventLocal<TEvGetNode, EvGetNode> {
+ ui32 NodeId;
+ TInstant Deadline;
+
+ TEvGetNode(ui32 nodeId, TInstant deadline = TInstant::Max())
+ : NodeId(nodeId)
+ , Deadline(deadline)
+ {
+ }
+ };
+
+ struct TEvNodeInfo: public TEventLocal<TEvNodeInfo, EvNodeInfo> {
+ TEvNodeInfo(ui32 nodeId)
+ : NodeId(nodeId)
+ {
+ }
+
+ ui32 NodeId;
+ THolder<TNodeInfo> Node;
+ };
+
+ struct TEvClosePeerSocket : TEventLocal<TEvClosePeerSocket, EvClosePeerSocket> {};
+
+ struct TEvCloseInputSession : TEventLocal<TEvCloseInputSession, EvCloseInputSession> {};
+
+ struct TEvPoisonSession : TEventLocal<TEvPoisonSession, EvPoisonSession> {};
+
+ struct TEvTerminate : TEventLocal<TEvTerminate, EvTerminate> {};
+ };
+}
diff --git a/library/cpp/actors/core/invoke.h b/library/cpp/actors/core/invoke.h
new file mode 100644
index 0000000000..931a9767dd
--- /dev/null
+++ b/library/cpp/actors/core/invoke.h
@@ -0,0 +1,110 @@
+#pragma once
+
+#include "actor_bootstrapped.h"
+#include "events.h"
+#include "event_local.h"
+
+#include <any>
+#include <type_traits>
+#include <utility>
+#include <variant>
+
+#include <util/system/type_name.h>
+
+namespace NActors {
+
+ struct TEvents::TEvInvokeResult
+ : TEventLocal<TEvInvokeResult, TSystem::InvokeResult>
+ {
+ using TProcessCallback = std::function<void(TEvInvokeResult&, const TActorContext&)>;
+ TProcessCallback ProcessCallback;
+ std::variant<std::any /* the value */, std::exception_ptr> Result;
+
+ // This constructor creates TEvInvokeResult with the result of calling callback(args...) or exception_ptr,
+ // if exception occurs during evaluation.
+ template<typename TCallback, typename... TArgs>
+ TEvInvokeResult(TProcessCallback&& process, TCallback&& callback, TArgs&&... args)
+ : ProcessCallback(std::move(process))
+ {
+ try {
+ if constexpr (std::is_void_v<std::invoke_result_t<TCallback, TArgs...>>) {
+ // just invoke callback without saving any value
+ std::invoke(std::forward<TCallback>(callback), std::forward<TArgs>(args)...);
+ } else {
+ Result.emplace<std::any>(std::invoke(std::forward<TCallback>(callback), std::forward<TArgs>(args)...));
+ }
+ } catch (...) {
+ Result.emplace<std::exception_ptr>(std::current_exception());
+ }
+ }
+
+ void Process(const TActorContext& ctx) {
+ ProcessCallback(*this, ctx);
+ }
+
+ template<typename TCallback>
+ std::invoke_result_t<TCallback, const TActorContext&> GetResult() {
+ using T = std::invoke_result_t<TCallback, const TActorContext&>;
+ return std::visit([](auto& arg) -> T {
+ using TArg = std::decay_t<decltype(arg)>;
+ if constexpr (std::is_same_v<TArg, std::exception_ptr>) {
+ std::rethrow_exception(arg);
+ } else if constexpr (std::is_void_v<T>) {
+ Y_VERIFY(!arg.has_value());
+ } else if (auto *value = std::any_cast<T>(&arg)) {
+ return std::move(*value);
+ } else {
+ Y_FAIL("unspported return type for TEvInvokeResult: actual# %s != expected# %s",
+ TypeName(arg.type()).data(), TypeName<T>().data());
+ }
+ }, Result);
+ }
+ };
+
+ // Invoke Actor is used to make different procedure calls in specific threads pools.
+ //
+ // Actor is created by CreateInvokeActor(callback, complete) where `callback` is the function that will be invoked
+ // upon actor registration, which will issue then TEvInvokeResult to the parent actor with the result of called
+ // function. If the called function throws exception, then the exception will arrive in the result. Receiver of
+ // this message can either handle it by its own means calling ev.GetResult() (which will rethrow exception if it
+ // has occured in called function or return its return value; notice that when there is no return value, then
+ // GetResult() should also be called to prevent losing exception), or invoke ev.Process(), which will invoke
+ // callback provided as `complete` parameter to the CreateInvokeActor function. Complete handler is invoked with
+ // the result-getter lambda as the first argument and the actor system context as the second one. Result-getter
+ // should be called to obtain resulting value or exception like the GetResult() method of the TEvInvokeResult event.
+ //
+ // Notice that `callback` execution usually occurs in separate actor on separate mailbox and should not use parent
+ // actor's class. But `complete` handler is invoked in parent context and can use its contents. Do not forget to
+ // handle TEvInvokeResult event by calling Process/GetResult method, whichever is necessary.
+
+ template<typename TCallback, typename TCompletion, ui32 Activity>
+ class TInvokeActor : public TActorBootstrapped<TInvokeActor<TCallback, TCompletion, Activity>> {
+ TCallback Callback;
+ TCompletion Complete;
+
+ public:
+ static constexpr auto ActorActivityType() {
+ return static_cast<IActor::EActorActivity>(Activity);
+ }
+
+ TInvokeActor(TCallback&& callback, TCompletion&& complete)
+ : Callback(std::move(callback))
+ , Complete(std::move(complete))
+ {}
+
+ void Bootstrap(const TActorId& parentId, const TActorContext& ctx) {
+ auto process = [complete = std::move(Complete)](TEvents::TEvInvokeResult& res, const TActorContext& ctx) {
+ complete([&] { return res.GetResult<TCallback>(); }, ctx);
+ };
+ ctx.Send(parentId, new TEvents::TEvInvokeResult(std::move(process), std::move(Callback), ctx));
+ TActorBootstrapped<TInvokeActor>::Die(ctx);
+ }
+ };
+
+ template<ui32 Activity, typename TCallback, typename TCompletion>
+ std::unique_ptr<IActor> CreateInvokeActor(TCallback&& callback, TCompletion&& complete) {
+ return std::make_unique<TInvokeActor<std::decay_t<TCallback>, std::decay_t<TCompletion>, Activity>>(
+ std::forward<TCallback>(callback), std::forward<TCompletion>(complete));
+ }
+
+} // NActors
diff --git a/library/cpp/actors/core/io_dispatcher.cpp b/library/cpp/actors/core/io_dispatcher.cpp
new file mode 100644
index 0000000000..90699ff16c
--- /dev/null
+++ b/library/cpp/actors/core/io_dispatcher.cpp
@@ -0,0 +1,234 @@
+#include "io_dispatcher.h"
+#include "actor_bootstrapped.h"
+#include "hfunc.h"
+#include <util/system/mutex.h>
+#include <util/system/condvar.h>
+#include <util/system/thread.h>
+#include <map>
+#include <list>
+
+namespace NActors {
+
+ class TIoDispatcherActor : public TActorBootstrapped<TIoDispatcherActor> {
+ enum {
+ EvNotifyThreadStopped = EventSpaceBegin(TEvents::ES_PRIVATE),
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // IO task queue
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ class TTask {
+ TInstant Timestamp;
+ std::function<void()> Callback;
+
+ public:
+ TTask(TInstant timestamp, TEvInvokeQuery *ev)
+ : Timestamp(timestamp)
+ , Callback(std::move(ev->Callback))
+ {}
+
+ void Execute() {
+ Callback();
+ }
+
+ TInstant GetTimestamp() const {
+ return Timestamp;
+ }
+ };
+
+ class TTaskQueue {
+ std::list<TTask> Tasks;
+ TMutex Mutex;
+ TCondVar CondVar;
+ size_t NumThreadsToStop = 0;
+
+ public:
+ void Enqueue(TInstant timestamp, TEvInvokeQuery *ev) {
+ std::list<TTask> list;
+ list.emplace_back(timestamp, ev);
+ with_lock (Mutex) {
+ Tasks.splice(Tasks.end(), std::move(list));
+ }
+ CondVar.Signal();
+ }
+
+ bool Dequeue(std::list<TTask>& list, bool *sendNotify) {
+ with_lock (Mutex) {
+ CondVar.Wait(Mutex, [&] { return NumThreadsToStop || !Tasks.empty(); });
+ if (NumThreadsToStop) {
+ *sendNotify = NumThreadsToStop != Max<size_t>();
+ if (*sendNotify) {
+ --NumThreadsToStop;
+ }
+ return false;
+ } else {
+ list.splice(list.end(), Tasks, Tasks.begin());
+ return true;
+ }
+ }
+ }
+
+ void Stop() {
+ with_lock (Mutex) {
+ NumThreadsToStop = Max<size_t>();
+ }
+ CondVar.BroadCast();
+ }
+
+ void StopOne() {
+ with_lock (Mutex) {
+ ++NumThreadsToStop;
+ Y_VERIFY(NumThreadsToStop);
+ }
+ CondVar.Signal();
+ }
+
+ std::optional<TInstant> GetEarliestTaskTimestamp() {
+ with_lock (Mutex) {
+ return Tasks.empty() ? std::nullopt : std::make_optional(Tasks.front().GetTimestamp());
+ }
+ }
+ };
+
+ TTaskQueue TaskQueue;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // IO dispatcher threads
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ class TThread : public ISimpleThread {
+ TIoDispatcherActor& Actor;
+ TActorSystem* const ActorSystem;
+
+ public:
+ TThread(TIoDispatcherActor& actor, TActorSystem *actorSystem)
+ : Actor(actor)
+ , ActorSystem(actorSystem)
+ {
+ Start();
+ }
+
+ void *ThreadProc() override {
+ SetCurrentThreadName("kikimr IO");
+ for (;;) {
+ std::list<TTask> tasks;
+ bool sendNotify;
+ if (!Actor.TaskQueue.Dequeue(tasks, &sendNotify)) {
+ if (sendNotify) {
+ ActorSystem->Send(new IEventHandle(EvNotifyThreadStopped, 0, Actor.SelfId(), TActorId(),
+ nullptr, TThread::CurrentThreadId()));
+ }
+ break;
+ }
+ for (TTask& task : tasks) {
+ task.Execute();
+ ++*Actor.TasksCompleted;
+ }
+ }
+ return nullptr;
+ }
+ };
+
+ static constexpr size_t MinThreadCount = 4;
+ static constexpr size_t MaxThreadCount = 64;
+ std::map<TThread::TId, std::unique_ptr<TThread>> Threads;
+ size_t NumRunningThreads = 0;
+
+ void StartThread() {
+ auto thread = std::make_unique<TThread>(*this, TlsActivationContext->ExecutorThread.ActorSystem);
+ const TThread::TId id = thread->Id();
+ Threads.emplace(id, std::move(thread));
+ *NumThreads = ++NumRunningThreads;
+ ++*ThreadsStarted;
+ }
+
+ void StopThread() {
+ Y_VERIFY(Threads.size());
+ TaskQueue.StopOne();
+ *NumThreads = --NumRunningThreads;
+ ++*ThreadsStopped;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Counters
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ NMonitoring::TDynamicCounters::TCounterPtr NumThreads;
+ NMonitoring::TDynamicCounters::TCounterPtr TasksAdded;
+ NMonitoring::TDynamicCounters::TCounterPtr TasksCompleted;
+ NMonitoring::TDynamicCounters::TCounterPtr ThreadsStarted;
+ NMonitoring::TDynamicCounters::TCounterPtr ThreadsStopped;
+
+ public:
+ TIoDispatcherActor(const NMonitoring::TDynamicCounterPtr& counters)
+ : NumThreads(counters->GetCounter("NumThreads"))
+ , TasksAdded(counters->GetCounter("TasksAdded", true))
+ , TasksCompleted(counters->GetCounter("TasksCompleted", true))
+ , ThreadsStarted(counters->GetCounter("ThreadsStarted", true))
+ , ThreadsStopped(counters->GetCounter("ThreadsStopped", true))
+ {}
+
+ ~TIoDispatcherActor() override {
+ TaskQueue.Stop();
+ }
+
+ void Bootstrap() {
+ while (NumRunningThreads < MinThreadCount) {
+ StartThread();
+ }
+ HandleWakeup();
+ Become(&TThis::StateFunc);
+ }
+
+ void HandleThreadStopped(TAutoPtr<IEventHandle> ev) {
+ auto it = Threads.find(ev->Cookie);
+ Y_VERIFY(it != Threads.end());
+ it->second->Join();
+ Threads.erase(it);
+ }
+
+ void Handle(TEvInvokeQuery::TPtr ev) {
+ ++*TasksAdded;
+ TaskQueue.Enqueue(TActivationContext::Now(), ev->Get());
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Thread usage counter logic
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ std::optional<TInstant> IdleTimestamp;
+ static constexpr TDuration ThreadStartTime = TDuration::MilliSeconds(500);
+ static constexpr TDuration ThreadStopTime = TDuration::MilliSeconds(500);
+
+ void HandleWakeup() {
+ const TInstant now = TActivationContext::Now();
+ std::optional<TInstant> earliest = TaskQueue.GetEarliestTaskTimestamp();
+ if (earliest) {
+ if (now >= *earliest + ThreadStartTime && NumRunningThreads < MaxThreadCount) {
+ StartThread();
+ }
+ IdleTimestamp.reset();
+ } else if (!IdleTimestamp) {
+ IdleTimestamp = now;
+ } else if (now >= *IdleTimestamp + ThreadStopTime) {
+ IdleTimestamp.reset();
+ if (NumRunningThreads > MinThreadCount) {
+ StopThread();
+ }
+ }
+ Schedule(TDuration::MilliSeconds(100), new TEvents::TEvWakeup);
+ }
+
+ STRICT_STFUNC(StateFunc, {
+ fFunc(EvNotifyThreadStopped, HandleThreadStopped);
+ hFunc(TEvInvokeQuery, Handle);
+ cFunc(TEvents::TSystem::Wakeup, HandleWakeup);
+ cFunc(TEvents::TSystem::Poison, PassAway);
+ })
+ };
+
+ IActor *CreateIoDispatcherActor(const NMonitoring::TDynamicCounterPtr& counters) {
+ return new TIoDispatcherActor(counters);
+ }
+
+} // NActors
diff --git a/library/cpp/actors/core/io_dispatcher.h b/library/cpp/actors/core/io_dispatcher.h
new file mode 100644
index 0000000000..b0e4e60d1a
--- /dev/null
+++ b/library/cpp/actors/core/io_dispatcher.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "actor.h"
+#include "event_local.h"
+#include "events.h"
+#include "actorsystem.h"
+#include "executor_thread.h"
+#include "executelater.h"
+
+namespace NActors {
+
+ struct TEvInvokeQuery : TEventLocal<TEvInvokeQuery, TEvents::TSystem::InvokeQuery> {
+ std::function<void()> Callback;
+
+ TEvInvokeQuery(std::function<void()>&& callback)
+ : Callback(std::move(callback))
+ {}
+ };
+
+ inline TActorId MakeIoDispatcherActorId() {
+ return TActorId(0, TStringBuf("IoDispatcher", 12));
+ }
+
+ extern IActor *CreateIoDispatcherActor(const NMonitoring::TDynamicCounterPtr& counters);
+
+ /* InvokeIoCallback enqueues callback() to be executed in IO thread pool and then return result in TEvInvokeResult
+ * message to parentId actor.
+ */
+ template<typename TCallback>
+ static void InvokeIoCallback(TCallback&& callback, ui32 poolId, IActor::EActivityType activityType) {
+ if (!TActivationContext::Send(new IEventHandle(MakeIoDispatcherActorId(), TActorId(),
+ new TEvInvokeQuery(callback)))) {
+ TActivationContext::Register(CreateExecuteLaterActor(std::move(callback), activityType), TActorId(),
+ TMailboxType::HTSwap, poolId);
+ }
+ }
+
+} // NActors
diff --git a/library/cpp/actors/core/lease.h b/library/cpp/actors/core/lease.h
new file mode 100644
index 0000000000..650ae7b122
--- /dev/null
+++ b/library/cpp/actors/core/lease.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#include "defs.h"
+
+namespace NActors {
+ // Value representing specific worker's permission for exclusive use of CPU till specific deadline
+ struct TLease {
+ // Lower WorkerBits store current fast worker id
+ // All other higher bits store expiration (hard preemption) timestamp
+ using TValue = ui64;
+ TValue Value;
+
+ static constexpr ui64 WorkerIdMask = ui64((1ull << WorkerBits) - 1);
+ static constexpr ui64 ExpireTsMask = ~WorkerIdMask;
+
+ explicit constexpr TLease(ui64 value)
+ : Value(value)
+ {}
+
+ constexpr TLease(TWorkerId workerId, ui64 expireTs)
+ : Value((workerId & WorkerIdMask) | (expireTs & ExpireTsMask))
+ {}
+
+ TWorkerId GetWorkerId() const {
+ return Value & WorkerIdMask;
+ }
+
+ TLease NeverExpire() const {
+ return TLease(Value | ExpireTsMask);
+ }
+
+ bool IsNeverExpiring() const {
+ return (Value & ExpireTsMask) == ExpireTsMask;
+ }
+
+ ui64 GetExpireTs() const {
+ // Do not truncate worker id
+ // NOTE: it decrease accuracy, but improves performance
+ return Value;
+ }
+
+ ui64 GetPreciseExpireTs() const {
+ return Value & ExpireTsMask;
+ }
+
+ operator TValue() const {
+ return Value;
+ }
+ };
+
+ // Special expire timestamp values
+ static constexpr ui64 NeverExpire = ui64(-1);
+
+ // Special hard-preemption-in-progress lease
+ static constexpr TLease HardPreemptionLease = TLease(TLease::WorkerIdMask, NeverExpire);
+}
diff --git a/library/cpp/actors/core/log.cpp b/library/cpp/actors/core/log.cpp
new file mode 100644
index 0000000000..5f63b5af58
--- /dev/null
+++ b/library/cpp/actors/core/log.cpp
@@ -0,0 +1,753 @@
+#include "log.h"
+#include "log_settings.h"
+
+#include <library/cpp/monlib/service/pages/templates.h>
+
+static_assert(int(NActors::NLog::PRI_EMERG) == int(::TLOG_EMERG), "expect int(NActors::NLog::PRI_EMERG) == int(::TLOG_EMERG)");
+static_assert(int(NActors::NLog::PRI_ALERT) == int(::TLOG_ALERT), "expect int(NActors::NLog::PRI_ALERT) == int(::TLOG_ALERT)");
+static_assert(int(NActors::NLog::PRI_CRIT) == int(::TLOG_CRIT), "expect int(NActors::NLog::PRI_CRIT) == int(::TLOG_CRIT)");
+static_assert(int(NActors::NLog::PRI_ERROR) == int(::TLOG_ERR), "expect int(NActors::NLog::PRI_ERROR) == int(::TLOG_ERR)");
+static_assert(int(NActors::NLog::PRI_WARN) == int(::TLOG_WARNING), "expect int(NActors::NLog::PRI_WARN) == int(::TLOG_WARNING)");
+static_assert(int(NActors::NLog::PRI_NOTICE) == int(::TLOG_NOTICE), "expect int(NActors::NLog::PRI_NOTICE) == int(::TLOG_NOTICE)");
+static_assert(int(NActors::NLog::PRI_INFO) == int(::TLOG_INFO), "expect int(NActors::NLog::PRI_INFO) == int(::TLOG_INFO)");
+static_assert(int(NActors::NLog::PRI_DEBUG) == int(::TLOG_DEBUG), "expect int(NActors::NLog::PRI_DEBUG) == int(::TLOG_DEBUG)");
+static_assert(int(NActors::NLog::PRI_TRACE) == int(::TLOG_RESOURCES), "expect int(NActors::NLog::PRI_TRACE) == int(::TLOG_RESOURCES)");
+
+namespace {
+ struct TRecordWithNewline {
+ ELogPriority Priority;
+ TTempBuf Buf;
+
+ TRecordWithNewline(const TLogRecord& rec)
+ : Priority(rec.Priority)
+ , Buf(rec.Len + 1)
+ {
+ Buf.Append(rec.Data, rec.Len);
+ *Buf.Proceed(1) = '\n';
+ }
+
+ operator TLogRecord() const {
+ return TLogRecord(Priority, Buf.Data(), Buf.Filled());
+ }
+ };
+}
+
+namespace NActors {
+
+ class TLoggerCounters : public ILoggerMetrics {
+ public:
+ TLoggerCounters(TIntrusivePtr<NMonitoring::TDynamicCounters> counters)
+ : DynamicCounters(counters)
+ {
+ ActorMsgs_ = DynamicCounters->GetCounter("ActorMsgs", true);
+ DirectMsgs_ = DynamicCounters->GetCounter("DirectMsgs", true);
+ LevelRequests_ = DynamicCounters->GetCounter("LevelRequests", true);
+ IgnoredMsgs_ = DynamicCounters->GetCounter("IgnoredMsgs", true);
+ DroppedMsgs_ = DynamicCounters->GetCounter("DroppedMsgs", true);
+
+ AlertMsgs_ = DynamicCounters->GetCounter("AlertMsgs", true);
+ EmergMsgs_ = DynamicCounters->GetCounter("EmergMsgs", true);
+ }
+
+ ~TLoggerCounters() = default;
+
+ void IncActorMsgs() override {
+ ++*ActorMsgs_;
+ }
+ void IncDirectMsgs() override {
+ ++*DirectMsgs_;
+ }
+ void IncLevelRequests() override {
+ ++*LevelRequests_;
+ }
+ void IncIgnoredMsgs() override {
+ ++*IgnoredMsgs_;
+ }
+ void IncAlertMsgs() override {
+ ++*AlertMsgs_;
+ }
+ void IncEmergMsgs() override {
+ ++*EmergMsgs_;
+ }
+ void IncDroppedMsgs() override {
+ DroppedMsgs_->Inc();
+ };
+
+ void GetOutputHtml(IOutputStream& str) override {
+ HTML(str) {
+ DIV_CLASS("row") {
+ DIV_CLASS("col-md-12") {
+ H4() {
+ str << "Counters" << Endl;
+ }
+ DynamicCounters->OutputHtml(str);
+ }
+ }
+ }
+ }
+
+ private:
+ NMonitoring::TDynamicCounters::TCounterPtr ActorMsgs_;
+ NMonitoring::TDynamicCounters::TCounterPtr DirectMsgs_;
+ NMonitoring::TDynamicCounters::TCounterPtr LevelRequests_;
+ NMonitoring::TDynamicCounters::TCounterPtr IgnoredMsgs_;
+ NMonitoring::TDynamicCounters::TCounterPtr AlertMsgs_;
+ NMonitoring::TDynamicCounters::TCounterPtr EmergMsgs_;
+ // Dropped while the logger backend was unavailable
+ NMonitoring::TDynamicCounters::TCounterPtr DroppedMsgs_;
+
+ TIntrusivePtr<NMonitoring::TDynamicCounters> DynamicCounters;
+ };
+
+ class TLoggerMetrics : public ILoggerMetrics {
+ public:
+ TLoggerMetrics(std::shared_ptr<NMonitoring::TMetricRegistry> metrics)
+ : Metrics(metrics)
+ {
+ ActorMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.actor_msgs"}});
+ DirectMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.direct_msgs"}});
+ LevelRequests_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.level_requests"}});
+ IgnoredMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.ignored_msgs"}});
+ DroppedMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.dropped_msgs"}});
+
+ AlertMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.alert_msgs"}});
+ EmergMsgs_ = Metrics->Rate(NMonitoring::TLabels{{"sensor", "logger.emerg_msgs"}});
+ }
+
+ ~TLoggerMetrics() = default;
+
+ void IncActorMsgs() override {
+ ActorMsgs_->Inc();
+ }
+ void IncDirectMsgs() override {
+ DirectMsgs_->Inc();
+ }
+ void IncLevelRequests() override {
+ LevelRequests_->Inc();
+ }
+ void IncIgnoredMsgs() override {
+ IgnoredMsgs_->Inc();
+ }
+ void IncAlertMsgs() override {
+ AlertMsgs_->Inc();
+ }
+ void IncEmergMsgs() override {
+ EmergMsgs_->Inc();
+ }
+ void IncDroppedMsgs() override {
+ DroppedMsgs_->Inc();
+ };
+
+ void GetOutputHtml(IOutputStream& str) override {
+ HTML(str) {
+ DIV_CLASS("row") {
+ DIV_CLASS("col-md-12") {
+ H4() {
+ str << "Metrics" << Endl;
+ }
+ // TODO: Now, TMetricRegistry does not have the GetOutputHtml function
+ }
+ }
+ }
+ }
+
+ private:
+ NMonitoring::TRate* ActorMsgs_;
+ NMonitoring::TRate* DirectMsgs_;
+ NMonitoring::TRate* LevelRequests_;
+ NMonitoring::TRate* IgnoredMsgs_;
+ NMonitoring::TRate* AlertMsgs_;
+ NMonitoring::TRate* EmergMsgs_;
+ // Dropped while the logger backend was unavailable
+ NMonitoring::TRate* DroppedMsgs_;
+
+ std::shared_ptr<NMonitoring::TMetricRegistry> Metrics;
+ };
+
+ TAtomic TLoggerActor::IsOverflow = 0;
+
+ TLoggerActor::TLoggerActor(TIntrusivePtr<NLog::TSettings> settings,
+ TAutoPtr<TLogBackend> logBackend,
+ TIntrusivePtr<NMonitoring::TDynamicCounters> counters)
+ : TActor(&TLoggerActor::StateFunc)
+ , Settings(settings)
+ , LogBackend(logBackend.Release())
+ , Metrics(std::make_unique<TLoggerCounters>(counters))
+ {
+ }
+
+ TLoggerActor::TLoggerActor(TIntrusivePtr<NLog::TSettings> settings,
+ std::shared_ptr<TLogBackend> logBackend,
+ TIntrusivePtr<NMonitoring::TDynamicCounters> counters)
+ : TActor(&TLoggerActor::StateFunc)
+ , Settings(settings)
+ , LogBackend(logBackend)
+ , Metrics(std::make_unique<TLoggerCounters>(counters))
+ {
+ }
+
+ TLoggerActor::TLoggerActor(TIntrusivePtr<NLog::TSettings> settings,
+ TAutoPtr<TLogBackend> logBackend,
+ std::shared_ptr<NMonitoring::TMetricRegistry> metrics)
+ : TActor(&TLoggerActor::StateFunc)
+ , Settings(settings)
+ , LogBackend(logBackend.Release())
+ , Metrics(std::make_unique<TLoggerMetrics>(metrics))
+ {
+ }
+
+ TLoggerActor::TLoggerActor(TIntrusivePtr<NLog::TSettings> settings,
+ std::shared_ptr<TLogBackend> logBackend,
+ std::shared_ptr<NMonitoring::TMetricRegistry> metrics)
+ : TActor(&TLoggerActor::StateFunc)
+ , Settings(settings)
+ , LogBackend(logBackend)
+ , Metrics(std::make_unique<TLoggerMetrics>(metrics))
+ {
+ }
+
+ TLoggerActor::~TLoggerActor() {
+ }
+
+ void TLoggerActor::Log(TInstant time, NLog::EPriority priority, NLog::EComponent component, const char* c, ...) {
+ Metrics->IncDirectMsgs();
+ if (Settings && Settings->Satisfies(priority, component, 0ull)) {
+ va_list params;
+ va_start(params, c);
+ TString formatted;
+ vsprintf(formatted, c, params);
+
+ auto ok = OutputRecord(time, NLog::EPrio(priority), component, formatted);
+ Y_UNUSED(ok);
+ va_end(params);
+ }
+ }
+
+ void TLoggerActor::Throttle(const NLog::TSettings& settings) {
+ if (AtomicGet(IsOverflow))
+ Sleep(settings.ThrottleDelay);
+ }
+
+ void TLoggerActor::LogIgnoredCount(TInstant now) {
+ TString message = Sprintf("Ignored IgnoredCount# %" PRIu64 " log records due to logger overflow!", IgnoredCount);
+ if (!OutputRecord(now, NActors::NLog::EPrio::Error, Settings->LoggerComponent, message)) {
+ BecomeDefunct();
+ }
+ }
+
+ void TLoggerActor::HandleIgnoredEvent(TLogIgnored::TPtr& ev, const NActors::TActorContext& ctx) {
+ Y_UNUSED(ev);
+ LogIgnoredCount(ctx.Now());
+ IgnoredCount = 0;
+ PassedCount = 0;
+ }
+
+ void TLoggerActor::HandleIgnoredEventDrop() {
+ // logger backend is unavailable, just ignore
+ }
+
+ void TLoggerActor::WriteMessageStat(const NLog::TEvLog& ev) {
+ Metrics->IncActorMsgs();
+
+ const auto prio = ev.Level.ToPrio();
+
+ switch (prio) {
+ case ::NActors::NLog::EPrio::Alert:
+ Metrics->IncAlertMsgs();
+ break;
+ case ::NActors::NLog::EPrio::Emerg:
+ Metrics->IncEmergMsgs();
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ void TLoggerActor::HandleLogEvent(NLog::TEvLog::TPtr& ev, const NActors::TActorContext& ctx) {
+ i64 delayMillisec = (ctx.Now() - ev->Get()->Stamp).MilliSeconds();
+ WriteMessageStat(*ev->Get());
+ if (Settings->AllowDrop) {
+ // Disable throttling if it was enabled previously
+ if (AtomicGet(IsOverflow))
+ AtomicSet(IsOverflow, 0);
+
+ // Check if some records have to be dropped
+ if ((PassedCount > 10 && delayMillisec > (i64)Settings->TimeThresholdMs) || IgnoredCount > 0) {
+ Metrics->IncIgnoredMsgs();
+ if (IgnoredCount == 0) {
+ ctx.Send(ctx.SelfID, new TLogIgnored());
+ }
+ ++IgnoredCount;
+ PassedCount = 0;
+ return;
+ }
+ PassedCount++;
+ } else {
+ // Enable of disable throttling depending on the load
+ if (delayMillisec > (i64)Settings->TimeThresholdMs && !AtomicGet(IsOverflow))
+ AtomicSet(IsOverflow, 1);
+ else if (delayMillisec <= (i64)Settings->TimeThresholdMs && AtomicGet(IsOverflow))
+ AtomicSet(IsOverflow, 0);
+ }
+
+ const auto prio = ev->Get()->Level.ToPrio();
+ if (!OutputRecord(ev->Get()->Stamp, prio, ev->Get()->Component, ev->Get()->Line)) {
+ BecomeDefunct();
+ }
+ }
+
+ void TLoggerActor::BecomeDefunct() {
+ Become(&TThis::StateDefunct);
+ Schedule(WakeupInterval, new TEvents::TEvWakeup);
+ }
+
+ void TLoggerActor::HandleLogComponentLevelRequest(TLogComponentLevelRequest::TPtr& ev, const NActors::TActorContext& ctx) {
+ Metrics->IncLevelRequests();
+ TString explanation;
+ int code = Settings->SetLevel(ev->Get()->Priority, ev->Get()->Component, explanation);
+ ctx.Send(ev->Sender, new TLogComponentLevelResponse(code, explanation));
+ }
+
+ void TLoggerActor::RenderComponentPriorities(IOutputStream& str) {
+ using namespace NLog;
+ HTML(str) {
+ H4() {
+ str << "Priority Settings for the Components";
+ }
+ TABLE_SORTABLE_CLASS("table") {
+ TABLEHEAD() {
+ TABLER() {
+ TABLEH() {
+ str << "Component";
+ }
+ TABLEH() {
+ str << "Level";
+ }
+ TABLEH() {
+ str << "Sampling Level";
+ }
+ TABLEH() {
+ str << "Sampling Rate";
+ }
+ }
+ }
+ TABLEBODY() {
+ for (EComponent i = Settings->MinVal; i < Settings->MaxVal; i++) {
+ auto name = Settings->ComponentName(i);
+ if (!*name)
+ continue;
+ NLog::TComponentSettings componentSettings = Settings->GetComponentSettings(i);
+
+ TABLER() {
+ TABLED() {
+ str << "<a href='logger?c=" << i << "'>" << name << "</a>";
+ }
+ TABLED() {
+ str << PriorityToString(EPrio(componentSettings.Raw.X.Level));
+ }
+ TABLED() {
+ str << PriorityToString(EPrio(componentSettings.Raw.X.SamplingLevel));
+ }
+ TABLED() {
+ str << componentSettings.Raw.X.SamplingRate;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Logger INFO:
+ * 1. Current priority settings from components
+ * 2. Number of log messages (via actors events, directly)
+ * 3. Number of messages per components, per priority
+ * 4. Log level changes (last N changes)
+ */
+ void TLoggerActor::HandleMonInfo(NMon::TEvHttpInfo::TPtr& ev, const TActorContext& ctx) {
+ const auto& params = ev->Get()->Request.GetParams();
+ NLog::EComponent component = NLog::InvalidComponent;
+ NLog::EPriority priority = NLog::PRI_DEBUG;
+ NLog::EPriority samplingPriority = NLog::PRI_DEBUG;
+ ui32 samplingRate = 0;
+ bool hasComponent = false;
+ bool hasPriority = false;
+ bool hasSamplingPriority = false;
+ bool hasSamplingRate = false;
+ bool hasAllowDrop = false;
+ int allowDrop = 0;
+ if (params.Has("c")) {
+ if (TryFromString(params.Get("c"), component) && (component == NLog::InvalidComponent || Settings->IsValidComponent(component))) {
+ hasComponent = true;
+ if (params.Has("p")) {
+ int rawPriority;
+ if (TryFromString(params.Get("p"), rawPriority) && NLog::TSettings::IsValidPriority((NLog::EPriority)rawPriority)) {
+ priority = (NLog::EPriority)rawPriority;
+ hasPriority = true;
+ }
+ }
+ if (params.Has("sp")) {
+ int rawPriority;
+ if (TryFromString(params.Get("sp"), rawPriority) && NLog::TSettings::IsValidPriority((NLog::EPriority)rawPriority)) {
+ samplingPriority = (NLog::EPriority)rawPriority;
+ hasSamplingPriority = true;
+ }
+ }
+ if (params.Has("sr")) {
+ if (TryFromString(params.Get("sr"), samplingRate)) {
+ hasSamplingRate = true;
+ }
+ }
+ }
+ }
+ if (params.Has("allowdrop")) {
+ if (TryFromString(params.Get("allowdrop"), allowDrop)) {
+ hasAllowDrop = true;
+ }
+ }
+
+ TStringStream str;
+ if (hasComponent && !hasPriority && !hasSamplingPriority && !hasSamplingRate) {
+ NLog::TComponentSettings componentSettings = Settings->GetComponentSettings(component);
+ ui32 samplingRate = componentSettings.Raw.X.SamplingRate;
+ HTML(str) {
+ DIV_CLASS("row") {
+ DIV_CLASS("col-md-12") {
+ H4() {
+ str << "Current log settings for " << Settings->ComponentName(component) << Endl;
+ }
+ UL() {
+ LI() {
+ str << "Priority: "
+ << NLog::PriorityToString(NLog::EPrio(componentSettings.Raw.X.Level));
+ }
+ LI() {
+ str << "Sampling priority: "
+ << NLog::PriorityToString(NLog::EPrio(componentSettings.Raw.X.SamplingLevel));
+ }
+ LI() {
+ str << "Sampling rate: "
+ << samplingRate;
+ }
+ }
+ }
+ }
+
+ DIV_CLASS("row") {
+ DIV_CLASS("col-md-12") {
+ H4() {
+ str << "Change priority" << Endl;
+ }
+ UL() {
+ for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) {
+ LI() {
+ str << "<a href='logger?c=" << component << "&p=" << p << "'>"
+ << NLog::PriorityToString(NLog::EPrio(p)) << "</a>";
+ }
+ }
+ }
+ H4() {
+ str << "Change sampling priority" << Endl;
+ }
+ UL() {
+ for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) {
+ LI() {
+ str << "<a href='logger?c=" << component << "&sp=" << p << "'>"
+ << NLog::PriorityToString(NLog::EPrio(p)) << "</a>";
+ }
+ }
+ }
+ H4() {
+ str << "Change sampling rate" << Endl;
+ }
+ str << "<form method=\"GET\">" << Endl;
+ str << "Rate: <input type=\"number\" name=\"sr\" value=\"" << samplingRate << "\"/>" << Endl;
+ str << "<input type=\"hidden\" name=\"c\" value=\"" << component << "\">" << Endl;
+ str << "<input class=\"btn btn-primary\" type=\"submit\" value=\"Change\"/>" << Endl;
+ str << "</form>" << Endl;
+ H4() {
+ str << "<a href='logger'>Cancel</a>" << Endl;
+ }
+ }
+ }
+ }
+
+ } else {
+ TString explanation;
+ if (hasComponent && hasPriority) {
+ Settings->SetLevel(priority, component, explanation);
+ }
+ if (hasComponent && hasSamplingPriority) {
+ Settings->SetSamplingLevel(samplingPriority, component, explanation);
+ }
+ if (hasComponent && hasSamplingRate) {
+ Settings->SetSamplingRate(samplingRate, component, explanation);
+ }
+ if (hasAllowDrop) {
+ Settings->SetAllowDrop(allowDrop);
+ }
+
+ HTML(str) {
+ if (!explanation.empty()) {
+ DIV_CLASS("row") {
+ DIV_CLASS("col-md-12 alert alert-info") {
+ str << explanation;
+ }
+ }
+ }
+
+ DIV_CLASS("row") {
+ DIV_CLASS("col-md-6") {
+ RenderComponentPriorities(str);
+ }
+ DIV_CLASS("col-md-6") {
+ H4() {
+ str << "Change priority for all components";
+ }
+ TABLE_CLASS("table table-condensed") {
+ TABLEHEAD() {
+ TABLER() {
+ TABLEH() {
+ str << "Priority";
+ }
+ }
+ }
+ TABLEBODY() {
+ for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) {
+ TABLER() {
+ TABLED() {
+ str << "<a href = 'logger?c=-1&p=" << p << "'>"
+ << NLog::PriorityToString(NLog::EPrio(p)) << "</a>";
+ }
+ }
+ }
+ }
+ }
+ H4() {
+ str << "Change sampling priority for all components";
+ }
+ TABLE_CLASS("table table-condensed") {
+ TABLEHEAD() {
+ TABLER() {
+ TABLEH() {
+ str << "Priority";
+ }
+ }
+ }
+ TABLEBODY() {
+ for (int p = NLog::PRI_EMERG; p <= NLog::PRI_TRACE; ++p) {
+ TABLER() {
+ TABLED() {
+ str << "<a href = 'logger?c=-1&sp=" << p << "'>"
+ << NLog::PriorityToString(NLog::EPrio(p)) << "</a>";
+ }
+ }
+ }
+ }
+ }
+ H4() {
+ str << "Change sampling rate for all components";
+ }
+ str << "<form method=\"GET\">" << Endl;
+ str << "Rate: <input type=\"number\" name=\"sr\" value=\"0\"/>" << Endl;
+ str << "<input type=\"hidden\" name=\"c\" value=\"-1\">" << Endl;
+ str << "<input class=\"btn btn-primary\" type=\"submit\" value=\"Change\"/>" << Endl;
+ str << "</form>" << Endl;
+ H4() {
+ str << "Drop log entries in case of overflow: "
+ << (Settings->AllowDrop ? "Enabled" : "Disabled");
+ }
+ str << "<form method=\"GET\">" << Endl;
+ str << "<input type=\"hidden\" name=\"allowdrop\" value=\"" << (Settings->AllowDrop ? "0" : "1") << "\"/>" << Endl;
+ str << "<input class=\"btn btn-primary\" type=\"submit\" value=\"" << (Settings->AllowDrop ? "Disable" : "Enable") << "\"/>" << Endl;
+ str << "</form>" << Endl;
+ }
+ }
+ Metrics->GetOutputHtml(str);
+ }
+ }
+
+ ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(str.Str()));
+ }
+
+ constexpr size_t TimeBufSize = 512;
+
+ bool TLoggerActor::OutputRecord(TInstant time, NLog::EPrio priority, NLog::EComponent component,
+ const TString& formatted) noexcept try {
+ const auto logPrio = ::ELogPriority(ui16(priority));
+
+ char buf[TimeBufSize];
+ switch (Settings->Format) {
+ case NActors::NLog::TSettings::PLAIN_FULL_FORMAT: {
+ TStringBuilder logRecord;
+ if (Settings->UseLocalTimestamps) {
+ logRecord << FormatLocalTimestamp(time, buf);
+ } else {
+ logRecord << time;
+ }
+ logRecord
+ << Settings->MessagePrefix
+ << " :" << Settings->ComponentName(component)
+ << " " << PriorityToString(priority)
+ << ": " << formatted;
+ LogBackend->WriteData(
+ TLogRecord(logPrio, logRecord.data(), logRecord.size()));
+ } break;
+
+ case NActors::NLog::TSettings::PLAIN_SHORT_FORMAT: {
+ TStringBuilder logRecord;
+ logRecord
+ << Settings->ComponentName(component)
+ << ": " << formatted;
+ LogBackend->WriteData(
+ TLogRecord(logPrio, logRecord.data(), logRecord.size()));
+ } break;
+
+ case NActors::NLog::TSettings::JSON_FORMAT: {
+ NJsonWriter::TBuf json;
+ json.BeginObject()
+ .WriteKey("@timestamp")
+ .WriteString(Settings->UseLocalTimestamps ? FormatLocalTimestamp(time, buf) : time.ToString().data())
+ .WriteKey("microseconds")
+ .WriteULongLong(time.MicroSeconds())
+ .WriteKey("host")
+ .WriteString(Settings->ShortHostName)
+ .WriteKey("cluster")
+ .WriteString(Settings->ClusterName)
+ .WriteKey("priority")
+ .WriteString(PriorityToString(priority))
+ .WriteKey("npriority")
+ .WriteInt((int)priority)
+ .WriteKey("component")
+ .WriteString(Settings->ComponentName(component))
+ .WriteKey("tag")
+ .WriteString("KIKIMR")
+ .WriteKey("revision")
+ .WriteInt(GetProgramSvnRevision())
+ .WriteKey("message")
+ .WriteString(formatted)
+ .EndObject();
+ auto logRecord = json.Str();
+ LogBackend->WriteData(
+ TLogRecord(logPrio, logRecord.data(), logRecord.size()));
+ } break;
+ }
+
+ return true;
+ } catch (...) {
+ return false;
+ }
+
+ void TLoggerActor::HandleLogEventDrop(const NLog::TEvLog::TPtr& ev) {
+ WriteMessageStat(*ev->Get());
+ Metrics->IncDroppedMsgs();
+ }
+
+ void TLoggerActor::HandleWakeup() {
+ Become(&TThis::StateFunc);
+ }
+
+ const char* TLoggerActor::FormatLocalTimestamp(TInstant time, char* buf) {
+ struct tm localTime;
+ time.LocalTime(&localTime);
+ int r = strftime(buf, TimeBufSize, "%Y-%m-%d-%H-%M-%S", &localTime);
+ Y_VERIFY(r != 0);
+ return buf;
+ }
+
+ TAutoPtr<TLogBackend> CreateSysLogBackend(const TString& ident,
+ bool logPError, bool logCons) {
+ int flags = 0;
+ if (logPError)
+ flags |= TSysLogBackend::LogPerror;
+ if (logCons)
+ flags |= TSysLogBackend::LogCons;
+
+ return new TSysLogBackend(ident.data(), TSysLogBackend::TSYSLOG_LOCAL1, flags);
+ }
+
+ class TStderrBackend: public TLogBackend {
+ public:
+ TStderrBackend() {
+ }
+ void WriteData(const TLogRecord& rec) override {
+#ifdef _MSC_VER
+ if (IsDebuggerPresent()) {
+ TString x;
+ x.reserve(rec.Len + 2);
+ x.append(rec.Data, rec.Len);
+ x.append('\n');
+ OutputDebugString(x.c_str());
+ }
+#endif
+ bool isOk = false;
+ do {
+ try {
+ TRecordWithNewline r(rec);
+ Cerr.Write(r.Buf.Data(), r.Buf.Filled());
+ isOk = true;
+ } catch (TSystemError err) {
+ // Interrupted system call
+ Y_UNUSED(err);
+ }
+ } while (!isOk);
+ }
+
+ void ReopenLog() override {
+ }
+
+ private:
+ const TString Indent;
+ };
+
+ class TLineFileLogBackend: public TFileLogBackend {
+ public:
+ TLineFileLogBackend(const TString& path)
+ : TFileLogBackend(path)
+ {
+ }
+
+ // Append newline after every record
+ void WriteData(const TLogRecord& rec) override {
+ TFileLogBackend::WriteData(TRecordWithNewline(rec));
+ }
+ };
+
+ class TCompositeLogBackend: public TLogBackend {
+ public:
+ TCompositeLogBackend(TVector<TAutoPtr<TLogBackend>>&& underlyingBackends)
+ : UnderlyingBackends(std::move(underlyingBackends))
+ {
+ }
+
+ void WriteData(const TLogRecord& rec) override {
+ for (auto& b: UnderlyingBackends) {
+ b->WriteData(rec);
+ }
+ }
+
+ void ReopenLog() override {
+ }
+
+ private:
+ TVector<TAutoPtr<TLogBackend>> UnderlyingBackends;
+ };
+
+ TAutoPtr<TLogBackend> CreateStderrBackend() {
+ return new TStderrBackend();
+ }
+
+ TAutoPtr<TLogBackend> CreateFileBackend(const TString& fileName) {
+ return new TLineFileLogBackend(fileName);
+ }
+
+ TAutoPtr<TLogBackend> CreateNullBackend() {
+ return new TNullLogBackend();
+ }
+
+ TAutoPtr<TLogBackend> CreateCompositeLogBackend(TVector<TAutoPtr<TLogBackend>>&& underlyingBackends) {
+ return new TCompositeLogBackend(std::move(underlyingBackends));
+ }
+}
diff --git a/library/cpp/actors/core/log.h b/library/cpp/actors/core/log.h
new file mode 100644
index 0000000000..c11a7cf3c1
--- /dev/null
+++ b/library/cpp/actors/core/log.h
@@ -0,0 +1,369 @@
+#pragma once
+
+#include "defs.h"
+
+#include "log_iface.h"
+#include "log_settings.h"
+#include "actorsystem.h"
+#include "events.h"
+#include "event_local.h"
+#include "hfunc.h"
+#include "mon.h"
+
+#include <util/generic/vector.h>
+#include <util/string/printf.h>
+#include <util/string/builder.h>
+#include <library/cpp/logger/all.h>
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+#include <library/cpp/monlib/metrics/metric_registry.h>
+#include <library/cpp/json/writer/json.h>
+#include <library/cpp/svnversion/svnversion.h>
+
+#include <library/cpp/actors/memory_log/memlog.h>
+
+// TODO: limit number of messages per second
+// TODO: make TLogComponentLevelRequest/Response network messages
+
+#define IS_LOG_PRIORITY_ENABLED(actorCtxOrSystem, priority, component) \
+ (static_cast<::NActors::NLog::TSettings*>((actorCtxOrSystem).LoggerSettings()) && \
+ static_cast<::NActors::NLog::TSettings*>((actorCtxOrSystem).LoggerSettings())->Satisfies( \
+ static_cast<::NActors::NLog::EPriority>(priority), \
+ static_cast<::NActors::NLog::EComponent>(component), \
+ 0ull) \
+ )
+
+#define LOG_LOG_SAMPLED_BY(actorCtxOrSystem, priority, component, sampleBy, ...) \
+ do { \
+ ::NActors::NLog::TSettings* mSettings = static_cast<::NActors::NLog::TSettings*>((actorCtxOrSystem).LoggerSettings()); \
+ ::NActors::NLog::EPriority mPriority = static_cast<::NActors::NLog::EPriority>(priority); \
+ ::NActors::NLog::EComponent mComponent = static_cast<::NActors::NLog::EComponent>(component); \
+ if (mSettings && mSettings->Satisfies(mPriority, mComponent, sampleBy)) { \
+ ::NActors::MemLogAdapter( \
+ actorCtxOrSystem, priority, component, __VA_ARGS__); \
+ } \
+ } while (0) /**/
+
+#define LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, priority, component, sampleBy, stream) \
+ LOG_LOG_SAMPLED_BY(actorCtxOrSystem, priority, component, sampleBy, "%s", [&]() { \
+ TStringBuilder logStringBuilder; \
+ logStringBuilder << stream; \
+ return static_cast<TString>(logStringBuilder); \
+ }().data())
+
+#define LOG_LOG(actorCtxOrSystem, priority, component, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, priority, component, 0ull, __VA_ARGS__)
+#define LOG_LOG_S(actorCtxOrSystem, priority, component, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, priority, component, 0ull, stream)
+
+// use these macros for logging via actor system or actor context
+#define LOG_EMERG(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, __VA_ARGS__)
+#define LOG_ALERT(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, __VA_ARGS__)
+#define LOG_CRIT(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, __VA_ARGS__)
+#define LOG_ERROR(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, __VA_ARGS__)
+#define LOG_WARN(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, __VA_ARGS__)
+#define LOG_NOTICE(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, __VA_ARGS__)
+#define LOG_INFO(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, __VA_ARGS__)
+#define LOG_DEBUG(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, __VA_ARGS__)
+#define LOG_TRACE(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, __VA_ARGS__)
+
+#define LOG_EMERG_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, stream)
+#define LOG_ALERT_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, stream)
+#define LOG_CRIT_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, stream)
+#define LOG_ERROR_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, stream)
+#define LOG_WARN_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, stream)
+#define LOG_NOTICE_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, stream)
+#define LOG_INFO_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, stream)
+#define LOG_DEBUG_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, stream)
+#define LOG_TRACE_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, stream)
+
+#define LOG_EMERG_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, sampleBy, __VA_ARGS__)
+#define LOG_ALERT_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, sampleBy, __VA_ARGS__)
+#define LOG_CRIT_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, sampleBy, __VA_ARGS__)
+#define LOG_ERROR_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, sampleBy, __VA_ARGS__)
+#define LOG_WARN_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, sampleBy, __VA_ARGS__)
+#define LOG_NOTICE_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, sampleBy, __VA_ARGS__)
+#define LOG_INFO_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, sampleBy, __VA_ARGS__)
+#define LOG_DEBUG_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, sampleBy, __VA_ARGS__)
+#define LOG_TRACE_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, sampleBy, __VA_ARGS__)
+
+#define LOG_EMERG_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, sampleBy, stream)
+#define LOG_ALERT_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, sampleBy, stream)
+#define LOG_CRIT_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, sampleBy, stream)
+#define LOG_ERROR_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, sampleBy, stream)
+#define LOG_WARN_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, sampleBy, stream)
+#define LOG_NOTICE_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, sampleBy, stream)
+#define LOG_INFO_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, sampleBy, stream)
+#define LOG_DEBUG_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, sampleBy, stream)
+#define LOG_TRACE_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, sampleBy, stream)
+
+// Log Throttling
+#define LOG_LOG_THROTTLE(throttler, actorCtxOrSystem, priority, component, ...) \
+ do { \
+ if ((throttler).Kick()) { \
+ LOG_LOG(actorCtxOrSystem, priority, component, __VA_ARGS__); \
+ } \
+ } while (0) /**/
+
+#define TRACE_EVENT(component) \
+ const auto& currentTracer = component; \
+ if (ev->HasEvent()) { \
+ LOG_TRACE(*TlsActivationContext, currentTracer, "%s, received event# %" PRIu32 ", Sender %s, Recipient %s: %s", \
+ __FUNCTION__, ev->Type, ev->Sender.ToString().data(), SelfId().ToString().data(), ev->GetBase()->ToString().substr(0, 1000).data()); \
+ } else { \
+ LOG_TRACE(*TlsActivationContext, currentTracer, "%s, received event# %" PRIu32 ", Sender %s, Recipient %s", \
+ __FUNCTION__, ev->Type, ev->Sender.ToString().data(), ev->Recipient.ToString().data()); \
+ }
+#define TRACE_EVENT_TYPE(eventType) LOG_TRACE(*TlsActivationContext, currentTracer, "%s, processing event %s", __FUNCTION__, eventType)
+
+class TLog;
+class TLogBackend;
+
+namespace NActors {
+ class TLoggerActor;
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // SET LOG LEVEL FOR A COMPONENT
+ ////////////////////////////////////////////////////////////////////////////////
+ class TLogComponentLevelRequest: public TEventLocal<TLogComponentLevelRequest, int(NLog::EEv::LevelReq)> {
+ public:
+ // set given priority for the component
+ TLogComponentLevelRequest(NLog::EPriority priority, NLog::EComponent component)
+ : Priority(priority)
+ , Component(component)
+ {
+ }
+
+ // set given priority for all components
+ TLogComponentLevelRequest(NLog::EPriority priority)
+ : Priority(priority)
+ , Component(NLog::InvalidComponent)
+ {
+ }
+
+ protected:
+ NLog::EPriority Priority;
+ NLog::EComponent Component;
+
+ friend class TLoggerActor;
+ };
+
+ class TLogComponentLevelResponse: public TEventLocal<TLogComponentLevelResponse, int(NLog::EEv::LevelResp)> {
+ public:
+ TLogComponentLevelResponse(int code, const TString& explanation)
+ : Code(code)
+ , Explanation(explanation)
+ {
+ }
+
+ int GetCode() const {
+ return Code;
+ }
+
+ const TString& GetExplanation() const {
+ return Explanation;
+ }
+
+ protected:
+ int Code;
+ TString Explanation;
+ };
+
+ class TLogIgnored: public TEventLocal<TLogIgnored, int(NLog::EEv::Ignored)> {
+ public:
+ TLogIgnored() {
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // LOGGER ACTOR
+ ////////////////////////////////////////////////////////////////////////////////
+ class ILoggerMetrics {
+ public:
+ virtual ~ILoggerMetrics() = default;
+
+ virtual void IncActorMsgs() = 0;
+ virtual void IncDirectMsgs() = 0;
+ virtual void IncLevelRequests() = 0;
+ virtual void IncIgnoredMsgs() = 0;
+ virtual void IncAlertMsgs() = 0;
+ virtual void IncEmergMsgs() = 0;
+ virtual void IncDroppedMsgs() = 0;
+
+ virtual void GetOutputHtml(IOutputStream&) = 0;
+ };
+
+ class TLoggerActor: public TActor<TLoggerActor> {
+ public:
+ static constexpr IActor::EActivityType ActorActivityType() {
+ return IActor::LOG_ACTOR;
+ }
+
+ TLoggerActor(TIntrusivePtr<NLog::TSettings> settings,
+ TAutoPtr<TLogBackend> logBackend,
+ TIntrusivePtr<NMonitoring::TDynamicCounters> counters);
+ TLoggerActor(TIntrusivePtr<NLog::TSettings> settings,
+ std::shared_ptr<TLogBackend> logBackend,
+ TIntrusivePtr<NMonitoring::TDynamicCounters> counters);
+ TLoggerActor(TIntrusivePtr<NLog::TSettings> settings,
+ TAutoPtr<TLogBackend> logBackend,
+ std::shared_ptr<NMonitoring::TMetricRegistry> metrics);
+ TLoggerActor(TIntrusivePtr<NLog::TSettings> settings,
+ std::shared_ptr<TLogBackend> logBackend,
+ std::shared_ptr<NMonitoring::TMetricRegistry> metrics);
+ ~TLoggerActor();
+
+ void StateFunc(TAutoPtr<IEventHandle>& ev, const TActorContext& ctx) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TLogIgnored, HandleIgnoredEvent);
+ HFunc(NLog::TEvLog, HandleLogEvent);
+ HFunc(TLogComponentLevelRequest, HandleLogComponentLevelRequest);
+ HFunc(NMon::TEvHttpInfo, HandleMonInfo);
+ }
+ }
+
+ STFUNC(StateDefunct) {
+ switch (ev->GetTypeRewrite()) {
+ cFunc(TLogIgnored::EventType, HandleIgnoredEventDrop);
+ hFunc(NLog::TEvLog, HandleLogEventDrop);
+ HFunc(TLogComponentLevelRequest, HandleLogComponentLevelRequest);
+ HFunc(NMon::TEvHttpInfo, HandleMonInfo);
+ cFunc(TEvents::TEvWakeup::EventType, HandleWakeup);
+ }
+ }
+
+ // Directly call logger instead of sending a message
+ void Log(TInstant time, NLog::EPriority priority, NLog::EComponent component, const char* c, ...);
+
+ static void Throttle(const NLog::TSettings& settings);
+
+ private:
+ TIntrusivePtr<NLog::TSettings> Settings;
+ std::shared_ptr<TLogBackend> LogBackend;
+ ui64 IgnoredCount = 0;
+ ui64 PassedCount = 0;
+ static TAtomic IsOverflow;
+ TDuration WakeupInterval{TDuration::Seconds(5)};
+ std::unique_ptr<ILoggerMetrics> Metrics;
+
+ void BecomeDefunct();
+ void HandleIgnoredEvent(TLogIgnored::TPtr& ev, const NActors::TActorContext& ctx);
+ void HandleIgnoredEventDrop();
+ void HandleLogEvent(NLog::TEvLog::TPtr& ev, const TActorContext& ctx);
+ void HandleLogEventDrop(const NLog::TEvLog::TPtr& ev);
+ void HandleLogComponentLevelRequest(TLogComponentLevelRequest::TPtr& ev, const TActorContext& ctx);
+ void HandleMonInfo(NMon::TEvHttpInfo::TPtr& ev, const TActorContext& ctx);
+ void HandleWakeup();
+ [[nodiscard]] bool OutputRecord(TInstant time, NLog::EPrio priority, NLog::EComponent component, const TString& formatted) noexcept;
+ void RenderComponentPriorities(IOutputStream& str);
+ void LogIgnoredCount(TInstant now);
+ void WriteMessageStat(const NLog::TEvLog& ev);
+ static const char* FormatLocalTimestamp(TInstant time, char* buf);
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // LOG THROTTLING
+ // TTrivialLogThrottler -- log a message every 'period' duration
+ // Use case:
+ // TTrivialLogThrottler throttler(TDuration::Minutes(1));
+ // ....
+ // LOG_LOG_THROTTLE(throttler, ctx, NActors::NLog::PRI_ERROR, SOME, "Error");
+ ////////////////////////////////////////////////////////////////////////////////
+ class TTrivialLogThrottler {
+ public:
+ TTrivialLogThrottler(TDuration period)
+ : Period(period)
+ {
+ }
+
+ // return value:
+ // true -- write to log
+ // false -- don't write to log, throttle
+ bool Kick() {
+ auto now = TInstant::Now();
+ if (now >= (LastWrite + Period)) {
+ LastWrite = now;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private:
+ TInstant LastWrite;
+ TDuration Period;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // SYSLOG BACKEND
+ ////////////////////////////////////////////////////////////////////////////////
+ TAutoPtr<TLogBackend> CreateSysLogBackend(const TString& ident,
+ bool logPError, bool logCons);
+ TAutoPtr<TLogBackend> CreateStderrBackend();
+ TAutoPtr<TLogBackend> CreateFileBackend(const TString& fileName);
+ TAutoPtr<TLogBackend> CreateNullBackend();
+ TAutoPtr<TLogBackend> CreateCompositeLogBackend(TVector<TAutoPtr<TLogBackend>>&& underlyingBackends);
+
+ /////////////////////////////////////////////////////////////////////
+ // Logging adaptors for memory log and logging into filesystem
+ /////////////////////////////////////////////////////////////////////
+
+ namespace NDetail {
+ inline void Y_PRINTF_FORMAT(2, 3) PrintfV(TString& dst, const char* format, ...) {
+ va_list params;
+ va_start(params, format);
+ vsprintf(dst, format, params);
+ va_end(params);
+ }
+
+ inline void PrintfV(TString& dst, const char* format, va_list params) {
+ vsprintf(dst, format, params);
+ }
+ } // namespace NDetail
+
+ template <typename TCtx>
+ inline void DeliverLogMessage(TCtx& ctx, NLog::EPriority mPriority, NLog::EComponent mComponent, TString &&str)
+ {
+ const NLog::TSettings *mSettings = ctx.LoggerSettings();
+ TLoggerActor::Throttle(*mSettings);
+ ctx.Send(new IEventHandle(mSettings->LoggerActorId, TActorId(), new NLog::TEvLog(mPriority, mComponent, std::move(str))));
+ }
+
+ template <typename TCtx, typename... TArgs>
+ inline void MemLogAdapter(
+ TCtx& actorCtxOrSystem,
+ NLog::EPriority mPriority,
+ NLog::EComponent mComponent,
+ const char* format, TArgs&&... params) {
+ TString Formatted;
+
+
+ if constexpr (sizeof... (params) > 0) {
+ NDetail::PrintfV(Formatted, format, std::forward<TArgs>(params)...);
+ } else {
+ NDetail::PrintfV(Formatted, "%s", format);
+ }
+
+ MemLogWrite(Formatted.data(), Formatted.size(), true);
+ DeliverLogMessage(actorCtxOrSystem, mPriority, mComponent, std::move(Formatted));
+ }
+
+ template <typename TCtx>
+ Y_WRAPPER inline void MemLogAdapter(
+ TCtx& actorCtxOrSystem,
+ NLog::EPriority mPriority,
+ NLog::EComponent mComponent,
+ const TString& str) {
+
+ MemLogWrite(str.data(), str.size(), true);
+ DeliverLogMessage(actorCtxOrSystem, mPriority, mComponent, TString(str));
+ }
+
+ template <typename TCtx>
+ Y_WRAPPER inline void MemLogAdapter(
+ TCtx& actorCtxOrSystem,
+ NLog::EPriority mPriority,
+ NLog::EComponent mComponent,
+ TString&& str) {
+
+ MemLogWrite(str.data(), str.size(), true);
+ DeliverLogMessage(actorCtxOrSystem, mPriority, mComponent, std::move(str));
+ }
+}
diff --git a/library/cpp/actors/core/log_iface.h b/library/cpp/actors/core/log_iface.h
new file mode 100644
index 0000000000..b331db9ca8
--- /dev/null
+++ b/library/cpp/actors/core/log_iface.h
@@ -0,0 +1,109 @@
+#pragma once
+
+#include "events.h"
+#include "event_local.h"
+
+namespace NActors {
+ namespace NLog {
+ using EComponent = int;
+
+ enum EPriority : ui16 { // migrate it to EPrio whenever possible
+ PRI_EMERG,
+ PRI_ALERT,
+ PRI_CRIT,
+ PRI_ERROR,
+ PRI_WARN,
+ PRI_NOTICE,
+ PRI_INFO,
+ PRI_DEBUG,
+ PRI_TRACE
+ };
+
+ enum class EPrio : ui16 {
+ Emerg = 0,
+ Alert = 1,
+ Crit = 2,
+ Error = 3,
+ Warn = 4,
+ Notice = 5,
+ Info = 6,
+ Debug = 7,
+ Trace = 8,
+ };
+
+ struct TLevel {
+ TLevel(ui32 raw)
+ : Raw(raw)
+ {
+ }
+
+ TLevel(EPrio prio)
+ : Raw((ui16(prio) + 1) << 8)
+ {
+ }
+
+ EPrio ToPrio() const noexcept {
+ const auto major = Raw >> 8;
+
+ return major > 0 ? EPrio(major - 1) : EPrio::Emerg;
+ }
+
+ bool IsUrgentAbortion() const noexcept {
+ return (Raw >> 8) == 0;
+ }
+
+ /* Generalized monotonic level value composed with major and minor
+ levels. Minor is used for verbosity within major, basic EPrio
+ mapped to (EPrio + 1, 0) and Major = 0 is reserved as special
+ space with meaning like EPrio::Emerg but with extened actions.
+ Thus logger should map Major = 0 to EPrio::Emerg if it have no
+ idea how to handle special emergency actions.
+ */
+
+ ui32 Raw = 0; // ((ui16(EPrio) + 1) << 8) | ui8(minor)
+ };
+
+ enum class EEv {
+ Log = EventSpaceBegin(TEvents::ES_LOGGER),
+ LevelReq,
+ LevelResp,
+ Ignored,
+ End
+ };
+
+ static_assert(int(EEv::End) < EventSpaceEnd(TEvents::ES_LOGGER), "");
+
+ class TEvLog: public TEventLocal<TEvLog, int(EEv::Log)> {
+ public:
+ TEvLog(TInstant stamp, TLevel level, EComponent comp, const TString &line)
+ : Stamp(stamp)
+ , Level(level)
+ , Component(comp)
+ , Line(line)
+ {
+ }
+
+ TEvLog(TInstant stamp, TLevel level, EComponent comp, TString &&line)
+ : Stamp(stamp)
+ , Level(level)
+ , Component(comp)
+ , Line(std::move(line))
+ {
+ }
+
+ TEvLog(EPriority prio, EComponent comp, TString line, TInstant time = TInstant::Now())
+ : Stamp(time)
+ , Level(EPrio(prio))
+ , Component(comp)
+ , Line(std::move(line))
+ {
+ }
+
+ const TInstant Stamp = TInstant::Max();
+ const TLevel Level;
+ const EComponent Component = 0;
+ TString Line;
+ };
+
+ }
+}
diff --git a/library/cpp/actors/core/log_settings.cpp b/library/cpp/actors/core/log_settings.cpp
new file mode 100644
index 0000000000..f52f2fc5d2
--- /dev/null
+++ b/library/cpp/actors/core/log_settings.cpp
@@ -0,0 +1,230 @@
+#include "log_settings.h"
+
+#include <util/stream/str.h>
+
+namespace NActors {
+ namespace NLog {
+ TSettings::TSettings(const TActorId& loggerActorId, const EComponent loggerComponent,
+ EComponent minVal, EComponent maxVal, EComponentToStringFunc func,
+ EPriority defPriority, EPriority defSamplingPriority,
+ ui32 defSamplingRate, ui64 timeThresholdMs)
+ : LoggerActorId(loggerActorId)
+ , LoggerComponent(loggerComponent)
+ , TimeThresholdMs(timeThresholdMs)
+ , AllowDrop(true)
+ , ThrottleDelay(TDuration::MilliSeconds(100))
+ , MinVal(0)
+ , MaxVal(0)
+ , Mask(0)
+ , DefPriority(defPriority)
+ , DefSamplingPriority(defSamplingPriority)
+ , DefSamplingRate(defSamplingRate)
+ , UseLocalTimestamps(false)
+ , Format(PLAIN_FULL_FORMAT)
+ , ShortHostName("")
+ , ClusterName("")
+ {
+ Append(minVal, maxVal, func);
+ }
+
+ TSettings::TSettings(const TActorId& loggerActorId, const EComponent loggerComponent,
+ EPriority defPriority, EPriority defSamplingPriority,
+ ui32 defSamplingRate, ui64 timeThresholdMs)
+ : LoggerActorId(loggerActorId)
+ , LoggerComponent(loggerComponent)
+ , TimeThresholdMs(timeThresholdMs)
+ , AllowDrop(true)
+ , ThrottleDelay(TDuration::MilliSeconds(100))
+ , MinVal(0)
+ , MaxVal(0)
+ , Mask(0)
+ , DefPriority(defPriority)
+ , DefSamplingPriority(defSamplingPriority)
+ , DefSamplingRate(defSamplingRate)
+ , UseLocalTimestamps(false)
+ , Format(PLAIN_FULL_FORMAT)
+ , ShortHostName("")
+ , ClusterName("")
+ {
+ }
+
+ void TSettings::Append(EComponent minVal, EComponent maxVal, EComponentToStringFunc func) {
+ Y_VERIFY(minVal >= 0, "NLog::TSettings: minVal must be non-negative");
+ Y_VERIFY(maxVal > minVal, "NLog::TSettings: maxVal must be greater than minVal");
+
+ // update bounds
+ if (!MaxVal || minVal < MinVal) {
+ MinVal = minVal;
+ }
+
+ if (!MaxVal || maxVal > MaxVal) {
+ MaxVal = maxVal;
+
+ // expand ComponentNames to the new bounds
+ auto oldMask = Mask;
+ Mask = PowerOf2Mask(MaxVal);
+
+ TArrayHolder<TAtomic> oldComponentInfo(new TAtomic[Mask + 1]);
+ ComponentInfo.Swap(oldComponentInfo);
+ int startVal = oldMask ? oldMask + 1 : 0;
+ for (int i = 0; i < startVal; i++) {
+ AtomicSet(ComponentInfo[i], AtomicGet(oldComponentInfo[i]));
+ }
+
+ TComponentSettings defSetting(DefPriority, DefSamplingPriority, DefSamplingRate);
+ for (int i = startVal; i < Mask + 1; i++) {
+ AtomicSet(ComponentInfo[i], defSetting.Raw.Data);
+ }
+
+ ComponentNames.resize(Mask + 1);
+ }
+
+ // assign new names but validate if newly added members were not used before
+ for (int i = minVal; i <= maxVal; i++) {
+ Y_VERIFY(!ComponentNames[i], "component name at %d already set: %s",
+ i, ComponentNames[i].data());
+ ComponentNames[i] = func(i);
+ }
+ }
+
+ int TSettings::SetLevelImpl(
+ const TString& name, bool isSampling,
+ EPriority priority, EComponent component, TString& explanation) {
+ TString titleName(name);
+ titleName.to_title();
+
+ // check priority
+ if (!IsValidPriority(priority)) {
+ TStringStream str;
+ str << "Invalid " << name;
+ explanation = str.Str();
+ return 1;
+ }
+
+ if (component == InvalidComponent) {
+ for (int i = 0; i < Mask + 1; i++) {
+ TComponentSettings settings = AtomicGet(ComponentInfo[i]);
+ if (isSampling) {
+ settings.Raw.X.SamplingLevel = priority;
+ } else {
+ settings.Raw.X.Level = priority;
+ }
+ AtomicSet(ComponentInfo[i], settings.Raw.Data);
+ }
+
+ TStringStream str;
+
+ str << titleName
+ << " for all components has been changed to "
+ << PriorityToString(EPrio(priority));
+ explanation = str.Str();
+ return 0;
+ } else {
+ if (!IsValidComponent(component)) {
+ explanation = "Invalid component";
+ return 1;
+ }
+ TComponentSettings settings = AtomicGet(ComponentInfo[component]);
+ EPriority oldPriority;
+ if (isSampling) {
+ oldPriority = (EPriority)settings.Raw.X.SamplingLevel;
+ settings.Raw.X.SamplingLevel = priority;
+ } else {
+ oldPriority = (EPriority)settings.Raw.X.Level;
+ settings.Raw.X.Level = priority;
+ }
+ AtomicSet(ComponentInfo[component], settings.Raw.Data);
+ TStringStream str;
+ str << titleName << " for the component " << ComponentNames[component]
+ << " has been changed from " << PriorityToString(EPrio(oldPriority))
+ << " to " << PriorityToString(EPrio(priority));
+ explanation = str.Str();
+ return 0;
+ }
+ }
+
+ int TSettings::SetLevel(EPriority priority, EComponent component, TString& explanation) {
+ return SetLevelImpl("priority", false,
+ priority, component, explanation);
+ }
+
+ int TSettings::SetSamplingLevel(EPriority priority, EComponent component, TString& explanation) {
+ return SetLevelImpl("sampling priority", true,
+ priority, component, explanation);
+ }
+
+ int TSettings::SetSamplingRate(ui32 sampling, EComponent component, TString& explanation) {
+ if (component == InvalidComponent) {
+ for (int i = 0; i < Mask + 1; i++) {
+ TComponentSettings settings = AtomicGet(ComponentInfo[i]);
+ settings.Raw.X.SamplingRate = sampling;
+ AtomicSet(ComponentInfo[i], settings.Raw.Data);
+ }
+ TStringStream str;
+ str << "Sampling rate for all components has been changed to " << sampling;
+ explanation = str.Str();
+ } else {
+ if (!IsValidComponent(component)) {
+ explanation = "Invalid component";
+ return 1;
+ }
+ TComponentSettings settings = AtomicGet(ComponentInfo[component]);
+ ui32 oldSampling = settings.Raw.X.SamplingRate;
+ settings.Raw.X.SamplingRate = sampling;
+ AtomicSet(ComponentInfo[component], settings.Raw.Data);
+ TStringStream str;
+ str << "Sampling rate for the component " << ComponentNames[component]
+ << " has been changed from " << oldSampling
+ << " to " << sampling;
+ explanation = str.Str();
+ }
+ return 0;
+ }
+
+ int TSettings::PowerOf2Mask(int val) {
+ int mask = 1;
+ while ((val & mask) != val) {
+ mask <<= 1;
+ mask |= 1;
+ }
+ return mask;
+ }
+
+ bool TSettings::IsValidPriority(EPriority priority) {
+ return priority == PRI_EMERG || priority == PRI_ALERT ||
+ priority == PRI_CRIT || priority == PRI_ERROR ||
+ priority == PRI_WARN || priority == PRI_NOTICE ||
+ priority == PRI_INFO || priority == PRI_DEBUG || priority == PRI_TRACE;
+ }
+
+ bool TSettings::IsValidComponent(EComponent component) {
+ return (MinVal <= component) && (component <= MaxVal) && !ComponentNames[component].empty();
+ }
+
+ void TSettings::SetAllowDrop(bool val) {
+ AllowDrop = val;
+ }
+
+ void TSettings::SetThrottleDelay(TDuration value) {
+ ThrottleDelay = value;
+ }
+
+ void TSettings::SetUseLocalTimestamps(bool value) {
+ UseLocalTimestamps = value;
+ }
+
+ EComponent TSettings::FindComponent(const TStringBuf& componentName) const {
+ if (componentName.empty())
+ return InvalidComponent;
+
+ for (EComponent component = MinVal; component <= MaxVal; ++component) {
+ if (ComponentNames[component] == componentName)
+ return component;
+ }
+
+ return InvalidComponent;
+ }
+
+ }
+
+}
diff --git a/library/cpp/actors/core/log_settings.h b/library/cpp/actors/core/log_settings.h
new file mode 100644
index 0000000000..7fe4504edd
--- /dev/null
+++ b/library/cpp/actors/core/log_settings.h
@@ -0,0 +1,176 @@
+#pragma once
+
+#include "actor.h"
+#include "log_iface.h"
+#include <util/generic/vector.h>
+#include <util/digest/murmur.h>
+#include <util/random/easy.h>
+
+namespace NActors {
+ namespace NLog {
+ inline const char* PriorityToString(EPrio priority) {
+ switch (priority) {
+ case EPrio::Emerg:
+ return "EMERG";
+ case EPrio::Alert:
+ return "ALERT";
+ case EPrio::Crit:
+ return "CRIT";
+ case EPrio::Error:
+ return "ERROR";
+ case EPrio::Warn:
+ return "WARN";
+ case EPrio::Notice:
+ return "NOTICE";
+ case EPrio::Info:
+ return "INFO";
+ case EPrio::Debug:
+ return "DEBUG";
+ case EPrio::Trace:
+ return "TRACE";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ // You can structure your program to have multiple logical components.
+ // In this case you can set different log priorities for different
+ // components. And you can change component's priority while system
+ // is running. Suspect a component has a bug? Turn DEBUG priority level on
+ // for this component.
+ static const int InvalidComponent = -1;
+
+ // Functions converts EComponent id to string
+ using EComponentToStringFunc = std::function<const TString&(EComponent)>;
+ ;
+
+ // Log settings
+ struct TComponentSettings {
+ union {
+ struct {
+ ui32 SamplingRate;
+ ui8 SamplingLevel;
+ ui8 Level;
+ } X;
+
+ ui64 Data;
+ } Raw;
+
+ TComponentSettings(TAtomicBase data) {
+ Raw.Data = (ui64)data;
+ }
+
+ TComponentSettings(ui8 level, ui8 samplingLevel, ui32 samplingRate) {
+ Raw.X.Level = level;
+ Raw.X.SamplingLevel = samplingLevel;
+ Raw.X.SamplingRate = samplingRate;
+ }
+ };
+
+ struct TSettings: public TThrRefBase {
+ public:
+ TActorId LoggerActorId;
+ EComponent LoggerComponent;
+ ui64 TimeThresholdMs;
+ bool AllowDrop;
+ TDuration ThrottleDelay;
+ TArrayHolder<TAtomic> ComponentInfo;
+ TVector<TString> ComponentNames;
+ EComponent MinVal;
+ EComponent MaxVal;
+ EComponent Mask;
+ EPriority DefPriority;
+ EPriority DefSamplingPriority;
+ ui32 DefSamplingRate;
+ bool UseLocalTimestamps;
+
+ enum ELogFormat {
+ PLAIN_FULL_FORMAT,
+ PLAIN_SHORT_FORMAT,
+ JSON_FORMAT
+ };
+ ELogFormat Format;
+ TString ShortHostName;
+ TString ClusterName;
+ TString MessagePrefix;
+
+ // The best way to provide minVal, maxVal and func is to have
+ // protobuf enumeration of components. In this case protoc
+ // automatically generates YOURTYPE_MIN, YOURTYPE_MAX and
+ // YOURTYPE_Name for you.
+ TSettings(const TActorId& loggerActorId, const EComponent loggerComponent,
+ EComponent minVal, EComponent maxVal, EComponentToStringFunc func,
+ EPriority defPriority, EPriority defSamplingPriority = PRI_DEBUG,
+ ui32 defSamplingRate = 0, ui64 timeThresholdMs = 1000);
+
+ TSettings(const TActorId& loggerActorId, const EComponent loggerComponent,
+ EPriority defPriority, EPriority defSamplingPriority = PRI_DEBUG,
+ ui32 defSamplingRate = 0, ui64 timeThresholdMs = 1000);
+
+ void Append(EComponent minVal, EComponent maxVal, EComponentToStringFunc func);
+
+ template <typename T>
+ void Append(T minVal, T maxVal, const TString& (*func)(T)) {
+ Append(
+ static_cast<EComponent>(minVal),
+ static_cast<EComponent>(maxVal),
+ [func](EComponent c) -> const TString& {
+ return func(static_cast<T>(c));
+ }
+ );
+ }
+
+ inline bool Satisfies(EPriority priority, EComponent component, ui64 sampleBy = 0) const {
+ // by using Mask we don't get outside of array boundaries
+ TComponentSettings settings = GetComponentSettings(component);
+ if (priority > settings.Raw.X.Level) {
+ if (priority > settings.Raw.X.SamplingLevel) {
+ return false; // priority > both levels ==> do not log
+ }
+ // priority <= sampling level ==> apply sampling
+ ui32 samplingRate = settings.Raw.X.SamplingRate;
+ if (samplingRate) {
+ ui32 samplingValue = sampleBy ? MurmurHash<ui32>((const char*)&sampleBy, sizeof(sampleBy))
+ : samplingRate != 1 ? RandomNumber<ui32>() : 0;
+ return (samplingValue % samplingRate == 0);
+ } else {
+ // sampling rate not set ==> do not log
+ return false;
+ }
+ } else {
+ // priority <= log level ==> log
+ return true;
+ }
+ }
+
+ inline TComponentSettings GetComponentSettings(EComponent component) const {
+ Y_VERIFY_DEBUG((component & Mask) == component);
+ // by using Mask we don't get outside of array boundaries
+ return TComponentSettings(AtomicGet(ComponentInfo[component & Mask]));
+ }
+
+ const char* ComponentName(EComponent component) const {
+ Y_VERIFY_DEBUG((component & Mask) == component);
+ return ComponentNames[component & Mask].data();
+ }
+
+ int SetLevel(EPriority priority, EComponent component, TString& explanation);
+ int SetSamplingLevel(EPriority priority, EComponent component, TString& explanation);
+ int SetSamplingRate(ui32 sampling, EComponent component, TString& explanation);
+ EComponent FindComponent(const TStringBuf& componentName) const;
+ static int PowerOf2Mask(int val);
+ static bool IsValidPriority(EPriority priority);
+ bool IsValidComponent(EComponent component);
+ void SetAllowDrop(bool val);
+ void SetThrottleDelay(TDuration value);
+ void SetUseLocalTimestamps(bool value);
+
+ private:
+ int SetLevelImpl(
+ const TString& name, bool isSampling,
+ EPriority priority, EComponent component, TString& explanation);
+ };
+
+ }
+
+}
diff --git a/library/cpp/actors/core/log_ut.cpp b/library/cpp/actors/core/log_ut.cpp
new file mode 100644
index 0000000000..09b5f88ea2
--- /dev/null
+++ b/library/cpp/actors/core/log_ut.cpp
@@ -0,0 +1,185 @@
+#include "log.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/actors/testlib/test_runtime.h>
+
+using namespace NMonitoring;
+using namespace NActors;
+using namespace NActors::NLog;
+
+namespace {
+ const TString& ServiceToString(int) {
+ static const TString FAKE{"FAKE"};
+ return FAKE;
+ }
+
+ TIntrusivePtr<TSettings> DefaultSettings() {
+ auto loggerId = TActorId{0, "Logger"};
+ auto s = MakeIntrusive<TSettings>(loggerId, 0, EPriority::PRI_TRACE);
+ s->SetAllowDrop(false);
+ s->Append(0, 1, ServiceToString);
+ return s;
+ }
+
+ TIntrusivePtr<TSettings> DroppingSettings(ui64 timeThresholdMs) {
+ auto loggerId = TActorId{0, "Logger"};
+ auto s = MakeIntrusive<TSettings>(
+ loggerId,
+ 0,
+ EPriority::PRI_TRACE,
+ EPriority::PRI_DEBUG,
+ (ui32)0,
+ timeThresholdMs);
+ s->Append(0, 1, ServiceToString);
+ return s;
+ }
+
+ class TMockBackend: public TLogBackend {
+ public:
+ using TWriteImpl = std::function<void(const TLogRecord&)>;
+ using TReopenImpl = std::function<void()>;
+
+ static void REOPEN_NOP() { }
+
+ TMockBackend(TWriteImpl writeImpl, TReopenImpl reopenImpl = REOPEN_NOP)
+ : WriteImpl_{writeImpl}
+ , ReopenImpl_{reopenImpl}
+ {
+ }
+
+ void WriteData(const TLogRecord& r) override {
+ WriteImpl_(r);
+ }
+
+ void ReopenLog() override { }
+
+ void SetWriteImpl(TWriteImpl writeImpl) {
+ WriteImpl_ = writeImpl;
+ }
+
+ private:
+ TWriteImpl WriteImpl_;
+ TReopenImpl ReopenImpl_;
+ };
+
+ void ThrowAlways(const TLogRecord&) {
+ ythrow yexception();
+ };
+
+ struct TFixture {
+ TFixture(
+ TIntrusivePtr<TSettings> settings,
+ TMockBackend::TWriteImpl writeImpl = ThrowAlways)
+ {
+ Runtime.Initialize();
+ LogBackend.reset(new TMockBackend{writeImpl});
+ LoggerActor = Runtime.Register(new TLoggerActor{settings, LogBackend, Counters});
+ Runtime.SetScheduledEventFilter([] (auto&&, auto&&, auto&&, auto) {
+ return false;
+ });
+ }
+
+ TFixture(TMockBackend::TWriteImpl writeImpl = ThrowAlways)
+ : TFixture(DefaultSettings(), writeImpl)
+ {}
+
+ void WriteLog() {
+ Runtime.Send(new IEventHandle{LoggerActor, {}, new TEvLog(TInstant::Zero(), TLevel{EPrio::Emerg}, 0, "foo")});
+ }
+
+ void WriteLog(TInstant ts) {
+ Runtime.Send(new IEventHandle{LoggerActor, {}, new TEvLog(ts, TLevel{EPrio::Emerg}, 0, "foo")});
+ }
+
+ void Wakeup() {
+ Runtime.Send(new IEventHandle{LoggerActor, {}, new TEvents::TEvWakeup});
+ }
+
+ TIntrusivePtr<TDynamicCounters> Counters{MakeIntrusive<TDynamicCounters>()};
+ std::shared_ptr<TMockBackend> LogBackend;
+ TActorId LoggerActor;
+ TTestActorRuntimeBase Runtime;
+ };
+}
+
+
+Y_UNIT_TEST_SUITE(TLoggerActorTest) {
+ Y_UNIT_TEST(NoCrashOnWriteFailure) {
+ TFixture test;
+ test.WriteLog();
+ // everything is okay as long as we get here
+ }
+
+ Y_UNIT_TEST(SubsequentWritesAreIgnored) {
+ size_t count{0};
+ auto countWrites = [&count] (auto&& r) {
+ count++;
+ ThrowAlways(r);
+ };
+
+ TFixture test{countWrites};
+ test.WriteLog();
+ UNIT_ASSERT_VALUES_EQUAL(count, 1);
+
+ // at this point we should have started dropping messages
+ for (auto i = 0; i < 5; ++i) {
+ test.WriteLog();
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(count, 1);
+ }
+
+ Y_UNIT_TEST(LoggerCanRecover) {
+ TFixture test;
+ test.WriteLog();
+
+ TVector<TString> messages;
+ auto acceptWrites = [&] (const TLogRecord& r) {
+ messages.emplace_back(r.Data, r.Len);
+ };
+
+ auto scheduled = test.Runtime.CaptureScheduledEvents();
+ UNIT_ASSERT_VALUES_EQUAL(scheduled.size(), 1);
+
+ test.LogBackend->SetWriteImpl(acceptWrites);
+ test.Wakeup();
+
+ const auto COUNT = 10;
+ for (auto i = 0; i < COUNT; ++i) {
+ test.WriteLog();
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(messages.size(), COUNT);
+ }
+
+ Y_UNIT_TEST(ShouldObeyTimeThresholdMsWhenOverloaded) {
+ TFixture test{DroppingSettings(5000)};
+
+ TVector<TString> messages;
+ auto acceptWrites = [&] (const TLogRecord& r) {
+ messages.emplace_back(r.Data, r.Len);
+ };
+
+ test.LogBackend->SetWriteImpl(acceptWrites);
+ test.Wakeup();
+
+ const auto COUNT = 11;
+ for (auto i = 0; i < COUNT; ++i) {
+ test.WriteLog();
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(messages.size(), COUNT);
+
+ test.Runtime.AdvanceCurrentTime(TDuration::Seconds(20));
+ auto now = test.Runtime.GetCurrentTime();
+
+ test.WriteLog(now - TDuration::Seconds(5));
+
+ UNIT_ASSERT_VALUES_EQUAL(messages.size(), COUNT + 1);
+
+ test.WriteLog(now - TDuration::Seconds(6));
+
+ UNIT_ASSERT_VALUES_EQUAL(messages.size(), COUNT + 1);
+ }
+}
diff --git a/library/cpp/actors/core/mailbox.cpp b/library/cpp/actors/core/mailbox.cpp
new file mode 100644
index 0000000000..d84b4f9e46
--- /dev/null
+++ b/library/cpp/actors/core/mailbox.cpp
@@ -0,0 +1,551 @@
+#include "mailbox.h"
+#include "actorsystem.h"
+
+#include <library/cpp/actors/util/datetime.h>
+
+#include <util/system/sanitizers.h>
+
+namespace NActors {
+ TMailboxTable::TMailboxTable()
+ : LastAllocatedLine(0)
+ , AllocatedMailboxCount(0)
+ , CachedSimpleMailboxes(0)
+ , CachedRevolvingMailboxes(0)
+ , CachedHTSwapMailboxes(0)
+ , CachedReadAsFilledMailboxes(0)
+ , CachedTinyReadAsFilledMailboxes(0)
+ {
+ memset((void*)Lines, 0, sizeof(Lines));
+ }
+
+ bool IsGoodForCleanup(const TMailboxHeader* header) {
+ switch (AtomicLoad(&header->ExecutionState)) {
+ case TMailboxHeader::TExecutionState::Inactive:
+ case TMailboxHeader::TExecutionState::Scheduled:
+ return true;
+ case TMailboxHeader::TExecutionState::Leaving:
+ case TMailboxHeader::TExecutionState::Executing:
+ case TMailboxHeader::TExecutionState::LeavingMarked:
+ return false;
+ case TMailboxHeader::TExecutionState::Free:
+ case TMailboxHeader::TExecutionState::FreeScheduled:
+ return true;
+ case TMailboxHeader::TExecutionState::FreeLeaving:
+ case TMailboxHeader::TExecutionState::FreeExecuting:
+ case TMailboxHeader::TExecutionState::FreeLeavingMarked:
+ return false;
+ default:
+ Y_FAIL();
+ }
+ }
+
+ template <typename TMailbox>
+ void DestructMailboxLine(ui8* begin, ui8* end) {
+ const ui32 sx = TMailbox::AlignedSize();
+ for (ui8* x = begin; x + sx <= end; x += sx) {
+ TMailbox* mailbox = reinterpret_cast<TMailbox*>(x);
+ Y_VERIFY(IsGoodForCleanup(mailbox));
+ mailbox->ExecutionState = Max<ui32>();
+ mailbox->~TMailbox();
+ }
+ }
+
+ template <typename TMailbox>
+ bool CleanupMailboxLine(ui8* begin, ui8* end) {
+ const ui32 sx = TMailbox::AlignedSize();
+ bool done = true;
+ for (ui8* x = begin; x + sx <= end; x += sx) {
+ TMailbox* mailbox = reinterpret_cast<TMailbox*>(x);
+ Y_VERIFY(IsGoodForCleanup(mailbox));
+ done &= mailbox->CleanupActors() && mailbox->CleanupEvents();
+ }
+ return done;
+ }
+
+ TMailboxTable::~TMailboxTable() {
+ // on cleanup we must traverse everything and free stuff
+ for (ui32 i = 0; i < LastAllocatedLine; ++i) {
+ if (TMailboxLineHeader* lineHeader = Lines[i]) {
+ switch (lineHeader->MailboxType) {
+ case TMailboxType::Simple:
+ DestructMailboxLine<TSimpleMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize);
+ break;
+ case TMailboxType::Revolving:
+ DestructMailboxLine<TRevolvingMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize);
+ break;
+ case TMailboxType::HTSwap:
+ DestructMailboxLine<THTSwapMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize);
+ break;
+ case TMailboxType::ReadAsFilled:
+ DestructMailboxLine<TReadAsFilledMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize);
+ break;
+ case TMailboxType::TinyReadAsFilled:
+ DestructMailboxLine<TTinyReadAsFilledMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize);
+ break;
+ default:
+ Y_FAIL();
+ }
+
+ lineHeader->~TMailboxLineHeader();
+ free(lineHeader);
+ Lines[i] = nullptr;
+ }
+ }
+
+ while (MailboxCacheSimple.Pop(0))
+ ;
+ while (MailboxCacheRevolving.Pop(0))
+ ;
+ while (MailboxCacheHTSwap.Pop(0))
+ ;
+ while (MailboxCacheReadAsFilled.Pop(0))
+ ;
+ while (MailboxCacheTinyReadAsFilled.Pop(0))
+ ;
+ }
+
+ bool TMailboxTable::Cleanup() {
+ bool done = true;
+ for (ui32 i = 0; i < LastAllocatedLine; ++i) {
+ if (TMailboxLineHeader* lineHeader = Lines[i]) {
+ switch (lineHeader->MailboxType) {
+ case TMailboxType::Simple:
+ done &= CleanupMailboxLine<TSimpleMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize);
+ break;
+ case TMailboxType::Revolving:
+ done &= CleanupMailboxLine<TRevolvingMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize);
+ break;
+ case TMailboxType::HTSwap:
+ done &= CleanupMailboxLine<THTSwapMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize);
+ break;
+ case TMailboxType::ReadAsFilled:
+ done &= CleanupMailboxLine<TReadAsFilledMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize);
+ break;
+ case TMailboxType::TinyReadAsFilled:
+ done &= CleanupMailboxLine<TTinyReadAsFilledMailbox>((ui8*)lineHeader + 64, (ui8*)lineHeader + LineSize);
+ break;
+ default:
+ Y_FAIL();
+ }
+ }
+ }
+ return done;
+ }
+
+ TMailboxHeader* TMailboxTable::Get(ui32 hint) {
+ // get line
+ const ui32 lineIndex = (hint & LineIndexMask) >> LineIndexShift;
+ const ui32 lineHint = hint & LineHintMask;
+
+ Y_VERIFY((lineIndex < MaxLines) && (lineHint < LineSize / 64));
+ if (lineHint == 0)
+ return nullptr;
+
+ if (TMailboxLineHeader* const x = AtomicLoad(Lines + lineIndex)) {
+ switch (x->MailboxType) {
+ case TMailboxType::Simple:
+ return TSimpleMailbox::Get(lineHint, x);
+ case TMailboxType::Revolving:
+ return TRevolvingMailbox::Get(lineHint, x);
+ case TMailboxType::HTSwap:
+ return THTSwapMailbox::Get(lineHint, x);
+ case TMailboxType::ReadAsFilled:
+ return TReadAsFilledMailbox::Get(lineHint, x);
+ case TMailboxType::TinyReadAsFilled:
+ return TTinyReadAsFilledMailbox::Get(lineHint, x);
+ default:
+ Y_VERIFY_DEBUG(false);
+ break;
+ }
+ }
+
+ return nullptr;
+ }
+
+ bool TMailboxTable::SendTo(TAutoPtr<IEventHandle>& ev, IExecutorPool* executorPool) {
+ const TActorId& recipient = ev->GetRecipientRewrite();
+ const ui32 hint = recipient.Hint();
+
+ // copy-paste from Get to avoid duplicated type-switches
+ const ui32 lineIndex = (hint & LineIndexMask) >> LineIndexShift;
+ const ui32 lineHint = hint & LineHintMask;
+
+ Y_VERIFY((lineIndex < MaxLines) && (lineHint < LineSize / 64));
+ if (lineHint == 0)
+ return false;
+
+ if (TMailboxLineHeader* const x = AtomicLoad(Lines + lineIndex)) {
+ switch (x->MailboxType) {
+ case TMailboxType::Simple: {
+ TSimpleMailbox* const mailbox = TSimpleMailbox::Get(lineHint, x);
+#if (!defined(_tsan_enabled_))
+ Y_VERIFY_DEBUG(mailbox->Type == (ui32)x->MailboxType);
+#endif
+ mailbox->Queue.Push(ev.Release());
+ if (mailbox->MarkForSchedule()) {
+ RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast());
+ executorPool->ScheduleActivation(hint);
+ }
+ }
+ return true;
+ case TMailboxType::Revolving: {
+ // The actorid could be stale and coming from a different machine. If local process has restarted than
+ // the stale actorid coming from a remote machine might be referencing an actor with simple mailbox
+ // which is smaller than revolving mailbox. In this cases 'lineHint' index might be greater than actual
+ // array size. Normally its ok to store stale event to other actor's valid mailbox beacuse Receive will
+ // compare receiver actor id and discard stale event. But in this case we should discard the event right away
+ // instead of trying to enque it to a mailbox at invalid address.
+ // NOTE: lineHint is 1-based
+ static_assert(TSimpleMailbox::AlignedSize() <= TRevolvingMailbox::AlignedSize(),
+ "We expect that one line can store more simple mailboxes than revolving mailboxes");
+ if (lineHint > TRevolvingMailbox::MaxMailboxesInLine())
+ return false;
+
+ TRevolvingMailbox* const mailbox = TRevolvingMailbox::Get(lineHint, x);
+#if (!defined(_tsan_enabled_))
+ Y_VERIFY_DEBUG(mailbox->Type == (ui32)x->MailboxType);
+#endif
+ mailbox->QueueWriter.Push(ev.Release());
+ if (mailbox->MarkForSchedule()) {
+ RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast());
+ executorPool->ScheduleActivation(hint);
+ }
+ }
+ return true;
+ case TMailboxType::HTSwap: {
+ THTSwapMailbox* const mailbox = THTSwapMailbox::Get(lineHint, x);
+#if (!defined(_tsan_enabled_))
+ Y_VERIFY_DEBUG(mailbox->Type == (ui32)x->MailboxType);
+#endif
+ mailbox->Queue.Push(ev.Release());
+ if (mailbox->MarkForSchedule()) {
+ RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast());
+ executorPool->ScheduleActivation(hint);
+ }
+ }
+ return true;
+ case TMailboxType::ReadAsFilled: {
+ if (lineHint > TReadAsFilledMailbox::MaxMailboxesInLine())
+ return false;
+
+ TReadAsFilledMailbox* const mailbox = TReadAsFilledMailbox::Get(lineHint, x);
+#if (!defined(_tsan_enabled_))
+ Y_VERIFY_DEBUG(mailbox->Type == (ui32)x->MailboxType);
+#endif
+ mailbox->Queue.Push(ev.Release());
+ if (mailbox->MarkForSchedule()) {
+ RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast());
+ executorPool->ScheduleActivation(hint);
+ }
+ }
+ return true;
+ case TMailboxType::TinyReadAsFilled: {
+ if (lineHint > TTinyReadAsFilledMailbox::MaxMailboxesInLine())
+ return false;
+
+ TTinyReadAsFilledMailbox* const mailbox = TTinyReadAsFilledMailbox::Get(lineHint, x);
+#if (!defined(_tsan_enabled_))
+ Y_VERIFY_DEBUG(mailbox->Type == (ui32)x->MailboxType);
+#endif
+ mailbox->Queue.Push(ev.Release());
+ if (mailbox->MarkForSchedule()) {
+ RelaxedStore<NHPTimer::STime>(&mailbox->ScheduleMoment, GetCycleCountFast());
+ executorPool->ScheduleActivation(hint);
+ }
+ }
+ return true;
+ default:
+ Y_FAIL("unknown mailbox type");
+ }
+ }
+
+ return false;
+ }
+
+ ui32 TMailboxTable::AllocateMailbox(TMailboxType::EType type, ui64 revolvingCounter) {
+ ui32 x = TryAllocateMailbox(type, revolvingCounter);
+ if (x == 0)
+ x = AllocateNewLine(type);
+ return x;
+ }
+
+ ui32 TMailboxTable::TryAllocateMailbox(TMailboxType::EType type, ui64 revolvingCounter) {
+ switch (type) {
+ case TMailboxType::Simple:
+ do {
+ if (ui32 ret = MailboxCacheSimple.Pop(revolvingCounter)) {
+ AtomicDecrement(CachedSimpleMailboxes);
+ return ret;
+ }
+ } while (AtomicGet(CachedSimpleMailboxes) > (MailboxCacheSimple.Concurrency * 512));
+ return 0;
+ case TMailboxType::Revolving:
+ do {
+ if (ui32 ret = MailboxCacheRevolving.Pop(revolvingCounter)) {
+ AtomicDecrement(CachedRevolvingMailboxes);
+ return ret;
+ }
+ } while (AtomicGet(CachedRevolvingMailboxes) > (MailboxCacheRevolving.Concurrency * 512));
+ return 0;
+ case TMailboxType::HTSwap:
+ do {
+ if (ui32 ret = MailboxCacheHTSwap.Pop(revolvingCounter)) {
+ AtomicDecrement(CachedHTSwapMailboxes);
+ return ret;
+ }
+ } while (AtomicGet(CachedHTSwapMailboxes) > (MailboxCacheHTSwap.Concurrency * 512));
+ return 0;
+ case TMailboxType::ReadAsFilled:
+ do {
+ if (ui32 ret = MailboxCacheReadAsFilled.Pop(revolvingCounter)) {
+ AtomicDecrement(CachedReadAsFilledMailboxes);
+ return ret;
+ }
+ } while (AtomicGet(CachedReadAsFilledMailboxes) > (MailboxCacheReadAsFilled.Concurrency * 512));
+ return 0;
+ case TMailboxType::TinyReadAsFilled:
+ do {
+ if (ui32 ret = MailboxCacheTinyReadAsFilled.Pop(revolvingCounter)) {
+ AtomicDecrement(CachedTinyReadAsFilledMailboxes);
+ return ret;
+ }
+ } while (AtomicGet(CachedTinyReadAsFilledMailboxes) > (MailboxCacheTinyReadAsFilled.Concurrency * 512));
+ return 0;
+ default:
+ Y_FAIL("Unknown mailbox type");
+ }
+ }
+
+ void TMailboxTable::ReclaimMailbox(TMailboxType::EType type, ui32 hint, ui64 revolvingCounter) {
+ if (hint != 0) {
+ switch (type) {
+ case TMailboxType::Simple:
+ MailboxCacheSimple.Push(hint, revolvingCounter);
+ AtomicIncrement(CachedSimpleMailboxes);
+ break;
+ case TMailboxType::Revolving:
+ MailboxCacheRevolving.Push(hint, revolvingCounter);
+ AtomicIncrement(CachedRevolvingMailboxes);
+ break;
+ case TMailboxType::HTSwap:
+ MailboxCacheHTSwap.Push(hint, revolvingCounter);
+ AtomicIncrement(CachedHTSwapMailboxes);
+ break;
+ case TMailboxType::ReadAsFilled:
+ MailboxCacheReadAsFilled.Push(hint, revolvingCounter);
+ AtomicIncrement(CachedReadAsFilledMailboxes);
+ break;
+ case TMailboxType::TinyReadAsFilled:
+ MailboxCacheTinyReadAsFilled.Push(hint, revolvingCounter);
+ AtomicIncrement(CachedTinyReadAsFilledMailboxes);
+ break;
+ default:
+ Y_FAIL();
+ }
+ }
+ }
+
+ TMailboxHeader::TMailboxHeader(TMailboxType::EType type)
+ : ExecutionState(TExecutionState::Free)
+ , Reserved(0)
+ , Type(type)
+ , ActorPack(TMailboxActorPack::Simple)
+ , Knobs(0)
+ {
+ ActorsInfo.Simple.ActorId = 0;
+ ActorsInfo.Simple.Actor = nullptr;
+ }
+
+ TMailboxHeader::~TMailboxHeader() {
+ CleanupActors();
+ }
+
+ bool TMailboxHeader::CleanupActors() {
+ bool done = true;
+ switch (ActorPack) {
+ case TMailboxActorPack::Simple: {
+ if (ActorsInfo.Simple.ActorId != 0) {
+ delete ActorsInfo.Simple.Actor;
+ done = false;
+ }
+ break;
+ }
+ case TMailboxActorPack::Map: {
+ for (auto& [actorId, actor] : *ActorsInfo.Map.ActorsMap) {
+ delete actor;
+ }
+ delete ActorsInfo.Map.ActorsMap;
+ done = false;
+ break;
+ }
+ case TMailboxActorPack::Array: {
+ for (ui64 i = 0; i < ActorsInfo.Array.ActorsCount; ++i) {
+ delete ActorsInfo.Array.ActorsArray->Actors[i].Actor;
+ }
+ delete ActorsInfo.Array.ActorsArray;
+ done = false;
+ break;
+ }
+ }
+ ActorPack = TMailboxActorPack::Simple;
+ ActorsInfo.Simple.ActorId = 0;
+ ActorsInfo.Simple.Actor = nullptr;
+ return done;
+ }
+
+ std::pair<ui32, ui32> TMailboxHeader::CountMailboxEvents(ui64 localActorId, ui32 maxTraverse) {
+ switch (Type) {
+ case TMailboxType::Simple:
+ return static_cast<TMailboxTable::TSimpleMailbox*>(this)->CountSimpleMailboxEvents(localActorId, maxTraverse);
+ case TMailboxType::Revolving:
+ return static_cast<TMailboxTable::TRevolvingMailbox*>(this)->CountRevolvingMailboxEvents(localActorId, maxTraverse);
+ default:
+ return {0, 0};
+ }
+ }
+
+ TMailboxTable::TSimpleMailbox::TSimpleMailbox()
+ : TMailboxHeader(TMailboxType::Simple)
+ , ScheduleMoment(0)
+ {
+ }
+
+ TMailboxTable::TSimpleMailbox::~TSimpleMailbox() {
+ CleanupEvents();
+ }
+
+ bool TMailboxTable::TSimpleMailbox::CleanupEvents() {
+ const bool done = (Queue.Head() == nullptr);
+ while (IEventHandle* ev = Queue.Pop())
+ delete ev;
+ return done;
+ }
+
+ std::pair<ui32, ui32> TMailboxTable::TSimpleMailbox::CountSimpleMailboxEvents(ui64 localActorId, ui32 maxTraverse) {
+ ui32 local = 0;
+ ui32 total = 0;
+
+ auto it = Queue.ReadIterator();
+ while (IEventHandle* x = it.Next()) {
+ ++total;
+ if (x->GetRecipientRewrite().LocalId() == localActorId)
+ ++local;
+ if (total >= maxTraverse)
+ break;
+ }
+
+ return std::make_pair(local, total);
+ }
+
+ TMailboxTable::TRevolvingMailbox::TRevolvingMailbox()
+ : TMailboxHeader(TMailboxType::Revolving)
+ , QueueWriter(QueueReader)
+ , Reserved1(0)
+ , Reserved2(0)
+ , ScheduleMoment(0)
+ {
+ }
+
+ TMailboxTable::TRevolvingMailbox::~TRevolvingMailbox() {
+ CleanupEvents();
+ }
+
+ bool TMailboxTable::TRevolvingMailbox::CleanupEvents() {
+ const bool done = (QueueReader.Head() == nullptr);
+ while (IEventHandle* ev = QueueReader.Pop())
+ delete ev;
+ return done;
+ }
+
+ std::pair<ui32, ui32> TMailboxTable::TRevolvingMailbox::CountRevolvingMailboxEvents(ui64 localActorId, ui32 maxTraverse) {
+ ui32 local = 0;
+ ui32 total = 0;
+
+ auto it = QueueReader.Iterator();
+
+ while (IEventHandle* x = it.Next()) {
+ ++total;
+ if (x->GetRecipientRewrite().LocalId() == localActorId)
+ ++local;
+ if (total >= maxTraverse)
+ break;
+ }
+
+ return std::make_pair(local, total);
+ }
+
+ template <typename T>
+ static ui32 InitNewLine(ui8* x, ui8* end) {
+ const ui32 sx = T::AlignedSize();
+
+ for (ui32 index = 1; x + sx <= end; x += sx, ++index)
+ ::new (x) T();
+
+ return sx;
+ }
+
+ ui32 TMailboxTable::AllocateNewLine(TMailboxType::EType type) {
+ ui8* ptr = (ui8*)malloc(LineSize);
+ ui8* end = ptr + LineSize;
+
+ const ui32 lineIndex = (ui32)AtomicIncrement(LastAllocatedLine) - 1;
+ const ui32 lineIndexMask = (lineIndex << LineIndexShift) & LineIndexMask;
+
+ // first 64 bytes is TMailboxLineHeader
+ TMailboxLineHeader* header = ::new (ptr) TMailboxLineHeader(type, lineIndex);
+
+ ui8* x = ptr + 64;
+ ui32 sx = 0;
+ TMailboxCache* cache = nullptr;
+ TAtomic* counter = nullptr;
+
+ switch (type) {
+ case TMailboxType::Simple:
+ sx = InitNewLine<TSimpleMailbox>(x, end);
+ cache = &MailboxCacheSimple;
+ counter = &CachedSimpleMailboxes;
+ break;
+ case TMailboxType::Revolving:
+ sx = InitNewLine<TRevolvingMailbox>(x, end);
+ cache = &MailboxCacheRevolving;
+ counter = &CachedRevolvingMailboxes;
+ break;
+ case TMailboxType::HTSwap:
+ sx = InitNewLine<THTSwapMailbox>(x, end);
+ cache = &MailboxCacheHTSwap;
+ counter = &CachedHTSwapMailboxes;
+ break;
+ case TMailboxType::ReadAsFilled:
+ sx = InitNewLine<TReadAsFilledMailbox>(x, end);
+ cache = &MailboxCacheReadAsFilled;
+ counter = &CachedReadAsFilledMailboxes;
+ break;
+ case TMailboxType::TinyReadAsFilled:
+ sx = InitNewLine<TTinyReadAsFilledMailbox>(x, end);
+ cache = &MailboxCacheTinyReadAsFilled;
+ counter = &CachedTinyReadAsFilledMailboxes;
+ break;
+ default:
+ Y_FAIL();
+ }
+
+ AtomicStore(Lines + lineIndex, header);
+
+ ui32 ret = lineIndexMask | 1;
+
+ ui32 index = 2;
+ for (ui32 endIndex = LineSize / sx; index != endIndex;) {
+ const ui32 bufSize = 8;
+ ui32 buf[bufSize];
+ ui32 bufIndex;
+ for (bufIndex = 0; index != endIndex && bufIndex != bufSize; ++bufIndex, ++index)
+ buf[bufIndex] = lineIndexMask | index;
+ cache->PushBulk(buf, bufIndex, index);
+ AtomicAdd(*counter, bufIndex);
+ }
+
+ AtomicAdd(AllocatedMailboxCount, index - 1);
+
+ return ret;
+ }
+}
diff --git a/library/cpp/actors/core/mailbox.h b/library/cpp/actors/core/mailbox.h
new file mode 100644
index 0000000000..0bd9c4d314
--- /dev/null
+++ b/library/cpp/actors/core/mailbox.h
@@ -0,0 +1,553 @@
+#pragma once
+
+#include "defs.h"
+#include "event.h"
+#include "actor.h"
+#include "mailbox_queue_simple.h"
+#include "mailbox_queue_revolving.h"
+#include <library/cpp/actors/util/unordered_cache.h>
+#include <library/cpp/threading/queue/mpsc_htswap.h>
+#include <library/cpp/threading/queue/mpsc_read_as_filled.h>
+#include <util/generic/hash.h>
+#include <util/system/hp_timer.h>
+#include <util/generic/ptr.h>
+// TODO: clean all broken arcadia atomic stuff and replace with intrinsics
+
+namespace NActors {
+ class IActor;
+ class IExecutorPool;
+
+ const ui64 ARRAY_CAPACITY = 8;
+
+ // structure of hint:
+ // 1 bit: is service or direct hint
+ // 2 bits: pool index
+ // 17 bits: line
+ // 12 bits: index of mailbox inside of line
+
+ struct TMailboxHeader {
+ struct TMailboxActorPack {
+ enum EType {
+ Simple = 0,
+ Array = 1,
+ Map = 2
+ };
+ };
+
+ using TActorMap = THashMap<ui64, IActor*>;
+
+ struct TExecutionState {
+ enum EState {
+ // normal states
+ Inactive = 0,
+ Scheduled = 1,
+ Leaving = 2,
+ Executing = 3,
+ LeavingMarked = 4,
+ // states for free mailboxes (they can still be scheduled so we need duplicates)
+ Free = 5,
+ FreeScheduled = 6,
+ FreeLeaving = 7,
+ FreeExecuting = 8,
+ FreeLeavingMarked = 9,
+ };
+ };
+
+ volatile ui32 ExecutionState;
+ ui32 Reserved : 4; // never changes, always zero
+ ui32 Type : 4; // never changes
+ ui32 ActorPack : 2;
+ ui32 Knobs : 22;
+
+ struct TActorPair {
+ IActor *Actor;
+ ui64 ActorId;
+ };
+
+ struct alignas(64) TActorArray {
+ TActorPair Actors[ARRAY_CAPACITY];
+ };
+
+ union TActorsInfo {
+ TActorPair Simple;
+ struct {
+ TActorArray* ActorsArray;
+ ui64 ActorsCount;
+ } Array;
+ struct {
+ TActorMap* ActorsMap;
+ } Map;
+ } ActorsInfo;
+
+ TMailboxHeader(TMailboxType::EType type);
+ ~TMailboxHeader();
+
+ bool CleanupActors();
+
+ // this interface is used exclusively by executor thread, so implementation is there
+
+ bool MarkForSchedule(); // we put something in queue, check should we schedule?
+
+ bool LockForExecution(); // we got activation, try to lock mailbox
+ bool LockFromFree(); // try to claim mailbox from recycled (could fail if other thread process garbage)
+
+ void UnlockFromExecution1(); // prepare for releasing lock
+ bool UnlockFromExecution2(bool wouldReschedule); // proceed with releasing lock
+ bool UnlockAsFree(bool wouldReschedule); // preceed with releasing lock, but mark as free one
+
+ bool IsEmpty() const noexcept {
+ return (ActorPack == TMailboxActorPack::Simple && ActorsInfo.Simple.ActorId == 0);
+ }
+
+ template<typename T>
+ void ForEach(T&& callback) noexcept {
+ switch (ActorPack) {
+ case TMailboxActorPack::Simple:
+ if (ActorsInfo.Simple.ActorId) {
+ callback(ActorsInfo.Simple.ActorId, ActorsInfo.Simple.Actor);
+ }
+ break;
+
+ case TMailboxActorPack::Map:
+ for (const auto& [actorId, actor] : *ActorsInfo.Map.ActorsMap) {
+ callback(actorId, actor);
+ }
+ break;
+
+ case TMailboxActorPack::Array:
+ for (ui64 i = 0; i < ActorsInfo.Array.ActorsCount; ++i) {
+ auto& row = ActorsInfo.Array.ActorsArray->Actors[i];
+ callback(row.ActorId, row.Actor);
+ }
+ break;
+ }
+ }
+
+ IActor* FindActor(ui64 localActorId) noexcept {
+ switch (ActorPack) {
+ case TMailboxActorPack::Simple: {
+ if (ActorsInfo.Simple.ActorId == localActorId)
+ return ActorsInfo.Simple.Actor;
+ break;
+ }
+ case TMailboxActorPack::Map: {
+ TActorMap::iterator it = ActorsInfo.Map.ActorsMap->find(localActorId);
+ if (it != ActorsInfo.Map.ActorsMap->end())
+ return it->second;
+ break;
+ }
+ case TMailboxActorPack::Array: {
+ for (ui64 i = 0; i < ActorsInfo.Array.ActorsCount; ++i) {
+ if (ActorsInfo.Array.ActorsArray->Actors[i].ActorId == localActorId) {
+ return ActorsInfo.Array.ActorsArray->Actors[i].Actor;
+ }
+ }
+ break;
+ }
+ default:
+ Y_FAIL();
+ }
+ return nullptr;
+ }
+
+ void AttachActor(ui64 localActorId, IActor* actor) noexcept {
+ switch (ActorPack) {
+ case TMailboxActorPack::Simple: {
+ if (ActorsInfo.Simple.ActorId == 0) {
+ ActorsInfo.Simple.ActorId = localActorId;
+ ActorsInfo.Simple.Actor = actor;
+ return;
+ } else {
+ auto ar = new TActorArray;
+ ar->Actors[0] = ActorsInfo.Simple;
+ ar->Actors[1] = TActorPair{actor, localActorId};
+ ActorsInfo.Array.ActorsCount = 2;
+ ActorPack = TMailboxActorPack::Array;
+ ActorsInfo.Array.ActorsArray = ar;
+ }
+ break;
+ }
+ case TMailboxActorPack::Map: {
+ ActorsInfo.Map.ActorsMap->insert(TActorMap::value_type(localActorId, actor));
+ break;
+ }
+ case TMailboxActorPack::Array: {
+ if (ActorsInfo.Array.ActorsCount == ARRAY_CAPACITY) {
+ TActorMap* mp = new TActorMap();
+ for (ui64 i = 0; i < ARRAY_CAPACITY; ++i) {
+ mp->emplace(ActorsInfo.Array.ActorsArray->Actors[i].ActorId, ActorsInfo.Array.ActorsArray->Actors[i].Actor);
+ }
+ mp->emplace(localActorId, actor);
+ ActorPack = TMailboxActorPack::Map;
+ ActorsInfo.Array.ActorsCount = 0;
+ delete ActorsInfo.Array.ActorsArray;
+ ActorsInfo.Map.ActorsMap = mp;
+ } else {
+ ActorsInfo.Array.ActorsArray->Actors[ActorsInfo.Array.ActorsCount++] = TActorPair{actor, localActorId};
+ }
+ break;
+ }
+ default:
+ Y_FAIL();
+ }
+ }
+
+ IActor* DetachActor(ui64 localActorId) noexcept {
+ Y_VERIFY_DEBUG(FindActor(localActorId) != nullptr);
+
+ IActor* actorToDestruct = nullptr;
+
+ switch (ActorPack) {
+ case TMailboxActorPack::Simple: {
+ Y_VERIFY(ActorsInfo.Simple.ActorId == localActorId);
+ actorToDestruct = ActorsInfo.Simple.Actor;
+
+ ActorsInfo.Simple.ActorId = 0;
+ ActorsInfo.Simple.Actor = nullptr;
+ break;
+ }
+ case TMailboxActorPack::Map: {
+ TActorMap::iterator it = ActorsInfo.Map.ActorsMap->find(localActorId);
+ Y_VERIFY(it != ActorsInfo.Map.ActorsMap->end());
+
+ actorToDestruct = it->second;
+ ActorsInfo.Map.ActorsMap->erase(it);
+
+ if (ActorsInfo.Map.ActorsMap->size() == ARRAY_CAPACITY) {
+ auto ar = new TActorArray;
+ ui64 i = 0;
+ for (auto& [actorId, actor] : *ActorsInfo.Map.ActorsMap) {
+ ar->Actors[i++] = TActorPair{actor, actorId};
+ }
+ delete ActorsInfo.Map.ActorsMap;
+ ActorPack = TMailboxActorPack::Array;
+ ActorsInfo.Array.ActorsArray = ar;
+ ActorsInfo.Array.ActorsCount = ARRAY_CAPACITY;
+ }
+ break;
+ }
+ case TMailboxActorPack::Array: {
+ bool found = false;
+ for (ui64 i = 0; i < ActorsInfo.Array.ActorsCount; ++i) {
+ if (ActorsInfo.Array.ActorsArray->Actors[i].ActorId == localActorId) {
+ found = true;
+ actorToDestruct = ActorsInfo.Array.ActorsArray->Actors[i].Actor;
+ ActorsInfo.Array.ActorsArray->Actors[i] = ActorsInfo.Array.ActorsArray->Actors[ActorsInfo.Array.ActorsCount - 1];
+ ActorsInfo.Array.ActorsCount -= 1;
+ break;
+ }
+ }
+ Y_VERIFY(found);
+
+ if (ActorsInfo.Array.ActorsCount == 1) {
+ const TActorPair Actor = ActorsInfo.Array.ActorsArray->Actors[0];
+ delete ActorsInfo.Array.ActorsArray;
+ ActorPack = TMailboxActorPack::Simple;
+ ActorsInfo.Simple = Actor;
+ }
+ break;
+ }
+ }
+
+ return actorToDestruct;
+ }
+
+ std::pair<ui32, ui32> CountMailboxEvents(ui64 localActorId, ui32 maxTraverse);
+ };
+
+ class TMailboxTable : TNonCopyable {
+ private:
+ struct TMailboxLineHeader {
+ const TMailboxType::EType MailboxType;
+ const ui32 Index;
+ // some more stuff in first cache line, then goes mailboxes
+ ui8 Padding[52];
+
+ TMailboxLineHeader(TMailboxType::EType type, ui32 index)
+ : MailboxType(type)
+ , Index(index)
+ {
+ }
+ };
+ static_assert(sizeof(TMailboxLineHeader) <= 64, "expect sizeof(TMailboxLineHeader) <= 64");
+
+ constexpr static ui64 MaxLines = 131000; // somewhat less then 2^17.
+ constexpr static ui64 LineSize = 262144; // 64 * 2^12.
+
+ TAtomic LastAllocatedLine;
+ TAtomic AllocatedMailboxCount;
+
+ typedef TUnorderedCache<ui32, 512, 4> TMailboxCache;
+ TMailboxCache MailboxCacheSimple;
+ TAtomic CachedSimpleMailboxes;
+ TMailboxCache MailboxCacheRevolving;
+ TAtomic CachedRevolvingMailboxes;
+ TMailboxCache MailboxCacheHTSwap;
+ TAtomic CachedHTSwapMailboxes;
+ TMailboxCache MailboxCacheReadAsFilled;
+ TAtomic CachedReadAsFilledMailboxes;
+ TMailboxCache MailboxCacheTinyReadAsFilled;
+ TAtomic CachedTinyReadAsFilledMailboxes;
+
+ // and here goes large chunk of lines
+ // presented as array of static size to avoid sync on access
+ TMailboxLineHeader* volatile Lines[MaxLines];
+
+ ui32 AllocateNewLine(TMailboxType::EType type);
+ ui32 TryAllocateMailbox(TMailboxType::EType type, ui64 revolvingCounter);
+
+ public:
+ TMailboxTable();
+ ~TMailboxTable();
+
+ bool Cleanup(); // returns true if nothing found to destruct (so nothing new is possible to be created)
+
+ static const ui32 LineIndexShift = 12;
+ static const ui32 LineIndexMask = 0x1FFFFu << LineIndexShift;
+ static const ui32 LineHintMask = 0xFFFu;
+ static const ui32 PoolIndexShift = TActorId::PoolIndexShift;
+ static const ui32 PoolIndexMask = TActorId::PoolIndexMask;
+
+ static ui32 LineIndex(ui32 hint) {
+ return ((hint & LineIndexMask) >> LineIndexShift);
+ }
+ static ui32 PoolIndex(ui32 hint) {
+ return TActorId::PoolIndex(hint);
+ }
+
+ TMailboxHeader* Get(ui32 hint);
+ ui32 AllocateMailbox(TMailboxType::EType type, ui64 revolvingCounter);
+ void ReclaimMailbox(TMailboxType::EType type, ui32 hint, ui64 revolvingCounter);
+ ui64 GetAllocatedMailboxCount() const {
+ return RelaxedLoad(&AllocatedMailboxCount);
+ }
+
+ bool SendTo(TAutoPtr<IEventHandle>& ev, IExecutorPool* executorPool);
+
+ struct TSimpleMailbox: public TMailboxHeader {
+ // 4 bytes - state
+ // 4 bytes - knobs
+ // 8 bytes - actorid
+ // 8 bytes - actor*
+ TSimpleMailboxQueue<IEventHandle*, 64> Queue; // 24 + 8 bytes (body, lock)
+ NHPTimer::STime ScheduleMoment;
+
+ TSimpleMailbox();
+ ~TSimpleMailbox();
+
+ IEventHandle* Pop() {
+ return Queue.Pop();
+ }
+ IEventHandle* Head() {
+ return Queue.Head();
+ }
+
+ static TSimpleMailbox* Get(ui32 hint, void* line) {
+ return (TSimpleMailbox*)((ui8*)line + hint * 64); //
+ }
+ static const TMailboxType::EType MailboxType = TMailboxType::Simple;
+ constexpr static ui32 AlignedSize() {
+ return ((sizeof(TSimpleMailbox) + 63) / 64) * 64;
+ }
+
+ std::pair<ui32, ui32> CountSimpleMailboxEvents(ui64 localActorId, ui32 maxTraverse);
+ bool CleanupEvents();
+ };
+
+ static_assert(sizeof(TSimpleMailbox) == 64, "expect sizeof(TSimpleMailbox) == 64");
+
+ struct TRevolvingMailbox: public TMailboxHeader {
+ // 4 bytes - state
+ // 4 bytes - knobs
+ // 8 bytes - actorid
+ // 8 bytes - actor*
+ TRevolvingMailboxQueue<IEventHandle*, 3, 128>::TReader QueueReader; // 8 * 3 + 4 * 3 + (padding): 40 bytes
+ // here goes next cache-line, so less writers<-> reader interference
+ TRevolvingMailboxQueue<IEventHandle*, 3, 128>::TWriter QueueWriter; // 8 * 3 + 4 * 3 + 8 : 48 bytes
+ ui32 Reserved1;
+ ui32 Reserved2;
+ NHPTimer::STime ScheduleMoment;
+
+ TRevolvingMailbox();
+ ~TRevolvingMailbox();
+
+ IEventHandle* Pop() {
+ return QueueReader.Pop();
+ }
+ IEventHandle* Head() {
+ return QueueReader.Head();
+ }
+
+ static TRevolvingMailbox* Get(ui32 hint, void* line) {
+ return (TRevolvingMailbox*)((ui8*)line + 64 + (hint - 1) * 128);
+ }
+
+ constexpr static ui64 MaxMailboxesInLine() {
+ return (LineSize - 64) / AlignedSize();
+ }
+ static const TMailboxType::EType MailboxType = TMailboxType::Revolving;
+ constexpr static ui32 AlignedSize() {
+ return ((sizeof(TRevolvingMailbox) + 63) / 64) * 64;
+ }
+
+ std::pair<ui32, ui32> CountRevolvingMailboxEvents(ui64 localActorId, ui32 maxTraverse);
+ bool CleanupEvents();
+ };
+
+ static_assert(sizeof(TRevolvingMailbox) == 128, "expect sizeof(TRevolvingMailbox) == 128");
+
+ struct THTSwapMailbox: public TMailboxHeader {
+ using TQueueType = NThreading::THTSwapQueue<IEventHandle*>;
+
+ TQueueType Queue;
+ NHPTimer::STime ScheduleMoment;
+ char Padding_[16];
+
+ THTSwapMailbox()
+ : TMailboxHeader(TMailboxType::HTSwap)
+ , ScheduleMoment(0)
+ {
+ }
+
+ ~THTSwapMailbox() {
+ CleanupEvents();
+ }
+
+ IEventHandle* Pop() {
+ return Queue.Pop();
+ }
+
+ IEventHandle* Head() {
+ return Queue.Peek();
+ }
+
+ static THTSwapMailbox* Get(ui32 hint, void* line) {
+ return (THTSwapMailbox*)((ui8*)line + 64 + (hint - 1) * 64);
+ }
+
+ constexpr static ui64 MaxMailboxesInLine() {
+ return (LineSize - 64) / AlignedSize();
+ }
+
+ static const TMailboxType::EType MailboxType = TMailboxType::HTSwap;
+
+ constexpr static ui32 AlignedSize() {
+ return ((sizeof(THTSwapMailbox) + 63) / 64) * 64;
+ }
+
+ bool CleanupEvents() {
+ const bool done = (Queue.Peek() == nullptr);
+ while (IEventHandle* ev = Queue.Pop())
+ delete ev;
+ return done;
+ }
+ };
+
+ static_assert(sizeof(THTSwapMailbox) == 64,
+ "expect sizeof(THTSwapMailbox) == 64");
+
+ struct TReadAsFilledMailbox: public TMailboxHeader {
+ using TQueueType = NThreading::TReadAsFilledQueue<IEventHandle>;
+
+ TQueueType Queue;
+ NHPTimer::STime ScheduleMoment;
+ char Padding_[8];
+
+ TReadAsFilledMailbox()
+ : TMailboxHeader(TMailboxType::ReadAsFilled)
+ , ScheduleMoment(0)
+ {
+ }
+
+ ~TReadAsFilledMailbox() {
+ CleanupEvents();
+ }
+
+ IEventHandle* Pop() {
+ return Queue.Pop();
+ }
+
+ IEventHandle* Head() {
+ return Queue.Peek();
+ }
+
+ static TReadAsFilledMailbox* Get(ui32 hint, void* line) {
+ return (TReadAsFilledMailbox*)((ui8*)line + 64 + (hint - 1) * 192);
+ }
+
+ constexpr static ui64 MaxMailboxesInLine() {
+ return (LineSize - 64) / AlignedSize();
+ }
+
+ static const TMailboxType::EType MailboxType =
+ TMailboxType::ReadAsFilled;
+
+ constexpr static ui32 AlignedSize() {
+ return ((sizeof(TReadAsFilledMailbox) + 63) / 64) * 64;
+ }
+
+ bool CleanupEvents() {
+ const bool done = (Queue.Peek() == nullptr);
+ while (IEventHandle* ev = Queue.Pop())
+ delete ev;
+ return done;
+ }
+ };
+
+ static_assert(sizeof(TReadAsFilledMailbox) == 192,
+ "expect sizeof(TReadAsFilledMailbox) == 192");
+
+ struct TTinyReadAsFilledMailbox: public TMailboxHeader {
+ using TQueueType = NThreading::TReadAsFilledQueue<
+ IEventHandle,
+ NThreading::TRaFQueueBunchSize<4>>;
+
+ TQueueType Queue;
+ NHPTimer::STime ScheduleMoment;
+ char Padding_[8];
+
+ TTinyReadAsFilledMailbox()
+ : TMailboxHeader(TMailboxType::TinyReadAsFilled)
+ , ScheduleMoment(0)
+ {
+ }
+
+ ~TTinyReadAsFilledMailbox() {
+ CleanupEvents();
+ }
+
+ IEventHandle* Pop() {
+ return Queue.Pop();
+ }
+
+ IEventHandle* Head() {
+ return Queue.Peek();
+ }
+
+ static TTinyReadAsFilledMailbox* Get(ui32 hint, void* line) {
+ return (TTinyReadAsFilledMailbox*)((ui8*)line + 64 + (hint - 1) * 192);
+ }
+
+ constexpr static ui64 MaxMailboxesInLine() {
+ return (LineSize - 64) / AlignedSize();
+ }
+
+ static const TMailboxType::EType MailboxType =
+ TMailboxType::TinyReadAsFilled;
+
+ constexpr static ui32 AlignedSize() {
+ return ((sizeof(TTinyReadAsFilledMailbox) + 63) / 64) * 64;
+ }
+
+ bool CleanupEvents() {
+ const bool done = (Queue.Peek() == nullptr);
+ while (IEventHandle* ev = Queue.Pop())
+ delete ev;
+ return done;
+ }
+ };
+
+ static_assert(sizeof(TTinyReadAsFilledMailbox) == 192,
+ "expect sizeof(TTinyReadAsFilledMailbox) == 192");
+ };
+}
diff --git a/library/cpp/actors/core/mailbox_queue_revolving.h b/library/cpp/actors/core/mailbox_queue_revolving.h
new file mode 100644
index 0000000000..b0e78a18db
--- /dev/null
+++ b/library/cpp/actors/core/mailbox_queue_revolving.h
@@ -0,0 +1,214 @@
+#pragma once
+
+#include "defs.h"
+#include <library/cpp/actors/util/queue_chunk.h>
+
+namespace NActors {
+ // add some concurrency to basic queue to avoid hangs under contention (we pay with memory, so use only when really expect contention)
+ // ordering: every completed push guarantied to seen before any not-yet-initiated push. parallel pushes could reorder (and that is natural for concurrent queues).
+ // try to place reader/writer on different cache-lines to avoid congestion b/w reader and writers.
+ // if strict ordering does not matter - look at TManyOneQueue.
+
+ template <typename T, ui32 TWriteConcurrency = 3, ui32 TSize = 128>
+ class TRevolvingMailboxQueue {
+ static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value");
+
+ struct TValTagPair {
+ volatile T Value;
+ volatile ui64 Tag;
+ };
+
+ typedef TQueueChunk<TValTagPair, TSize> TChunk;
+
+ static_assert(sizeof(TAtomic) == sizeof(TChunk*), "expect sizeof(TAtomic) == sizeof(TChunk*)");
+ static_assert(sizeof(TAtomic) == sizeof(ui64), "expect sizeof(TAtomic) == sizeof(ui64)");
+
+ public:
+ class TWriter;
+
+ class TReader {
+ TChunk* ReadFrom[TWriteConcurrency];
+ ui32 ReadPosition[TWriteConcurrency];
+
+ friend class TRevolvingMailboxQueue<T, TWriteConcurrency, TSize>::TWriter; // for access to ReadFrom in constructor
+
+ bool ChunkHead(ui32 idx, ui64* tag, T* value) {
+ TChunk* head = ReadFrom[idx];
+ const ui32 pos = ReadPosition[idx];
+ if (pos != TChunk::EntriesCount) {
+ if (const T xval = AtomicLoad(&head->Entries[pos].Value)) {
+ const ui64 xtag = head->Entries[pos].Tag;
+ if (xtag < *tag) {
+ *value = xval;
+ *tag = xtag;
+ return true;
+ }
+ }
+ } else if (TChunk* next = AtomicLoad(&head->Next)) {
+ ReadFrom[idx] = next;
+ delete head;
+ ReadPosition[idx] = 0;
+ return ChunkHead(idx, tag, value);
+ }
+
+ return false;
+ }
+
+ T Head(bool pop) {
+ ui64 tag = Max<ui64>();
+ T ret = T{};
+ ui32 idx = 0;
+
+ for (ui32 i = 0; i < TWriteConcurrency; ++i)
+ if (ChunkHead(i, &tag, &ret))
+ idx = i;
+
+ // w/o second pass we could reorder updates with 'already scanned' range
+ if (ret) {
+ for (ui32 i = 0; i < TWriteConcurrency; ++i)
+ if (ChunkHead(i, &tag, &ret))
+ idx = i;
+ }
+
+ if (pop && ret)
+ ++ReadPosition[idx];
+
+ return ret;
+ }
+
+ public:
+ TReader() {
+ for (ui32 i = 0; i != TWriteConcurrency; ++i) {
+ ReadFrom[i] = new TChunk();
+ ReadPosition[i] = 0;
+ }
+ }
+
+ ~TReader() {
+ Y_VERIFY_DEBUG(Head() == 0);
+ for (ui32 i = 0; i < TWriteConcurrency; ++i)
+ delete ReadFrom[i];
+ }
+
+ T Pop() {
+ return Head(true);
+ }
+
+ T Head() {
+ return Head(false);
+ }
+
+ class TReadIterator {
+ TChunk* ReadFrom[TWriteConcurrency];
+ ui32 ReadPosition[TWriteConcurrency];
+
+ bool ChunkHead(ui32 idx, ui64* tag, T* value) {
+ TChunk* head = ReadFrom[idx];
+ const ui32 pos = ReadPosition[idx];
+ if (pos != TChunk::EntriesCount) {
+ if (const T xval = AtomicLoad(&head->Entries[pos].Value)) {
+ const ui64 xtag = head->Entries[pos].Tag;
+ if (xtag < *tag) {
+ *value = xval;
+ *tag = xtag;
+ return true;
+ }
+ }
+ } else if (TChunk* next = AtomicLoad(&head->Next)) {
+ ReadFrom[idx] = next;
+ ReadPosition[idx] = 0;
+ return ChunkHead(idx, tag, value);
+ }
+
+ return false;
+ }
+
+ public:
+ TReadIterator(TChunk* const* readFrom, const ui32* readPosition) {
+ memcpy(ReadFrom, readFrom, TWriteConcurrency * sizeof(TChunk*));
+ memcpy(ReadPosition, readPosition, TWriteConcurrency * sizeof(ui32));
+ }
+
+ T Next() {
+ ui64 tag = Max<ui64>();
+ T ret = T{};
+ ui32 idx = 0;
+
+ for (ui32 i = 0; i < TWriteConcurrency; ++i)
+ if (ChunkHead(i, &tag, &ret))
+ idx = i;
+
+ // w/o second pass we could reorder updates with 'already scanned' range
+ if (ret) {
+ for (ui32 i = 0; i < TWriteConcurrency; ++i)
+ if (ChunkHead(i, &tag, &ret))
+ idx = i;
+ }
+
+ if (ret)
+ ++ReadPosition[idx];
+
+ return ret;
+ }
+ };
+
+ TReadIterator Iterator() const {
+ return TReadIterator(ReadFrom, ReadPosition);
+ }
+ };
+
+ class TWriter {
+ TChunk* volatile WriteTo[TWriteConcurrency];
+ volatile ui64 Tag;
+ ui32 WritePosition[TWriteConcurrency];
+
+ public:
+ TWriter(const TReader& reader)
+ : Tag(0)
+ {
+ for (ui32 i = 0; i != TWriteConcurrency; ++i) {
+ WriteTo[i] = reader.ReadFrom[i];
+ WritePosition[i] = 0;
+ }
+ }
+
+ bool TryPush(T x) {
+ Y_VERIFY(x != 0);
+
+ for (ui32 i = 0; i != TWriteConcurrency; ++i) {
+ if (RelaxedLoad(&WriteTo[i]) != nullptr) {
+ if (TChunk* writeTo = AtomicSwap(&WriteTo[i], nullptr)) {
+ const ui64 nextTag = AtomicIncrement(Tag);
+ Y_VERIFY_DEBUG(nextTag < Max<ui64>());
+ const ui32 writePosition = WritePosition[i];
+ if (writePosition != TChunk::EntriesCount) {
+ writeTo->Entries[writePosition].Tag = nextTag;
+ AtomicStore(&writeTo->Entries[writePosition].Value, x);
+ ++WritePosition[i];
+ } else {
+ TChunk* next = new TChunk();
+ next->Entries[0].Tag = nextTag;
+ next->Entries[0].Value = x;
+ AtomicStore(&writeTo->Next, next);
+ writeTo = next;
+ WritePosition[i] = 1;
+ }
+ AtomicStore(WriteTo + i, writeTo);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ ui32 Push(T x) {
+ ui32 spins = 0;
+ while (!TryPush(x)) {
+ ++spins;
+ SpinLockPause();
+ }
+ return spins;
+ }
+ };
+ };
+}
diff --git a/library/cpp/actors/core/mailbox_queue_simple.h b/library/cpp/actors/core/mailbox_queue_simple.h
new file mode 100644
index 0000000000..2e44c21adb
--- /dev/null
+++ b/library/cpp/actors/core/mailbox_queue_simple.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "defs.h"
+#include <library/cpp/actors/util/ticket_lock.h>
+#include <library/cpp/actors/util/queue_oneone_inplace.h>
+
+namespace NActors {
+ // dead-simple one-one queue, based on serializability guaranties of x64 and ticket lock to ensure writer unicity.
+ template <typename T, ui32 TSize>
+ class TSimpleMailboxQueue {
+ TOneOneQueueInplace<T, TSize> Queue;
+ TTicketLock Lock;
+
+ public:
+ ui32 Push(T x) noexcept {
+ const ui32 spins = Lock.Acquire();
+ Queue.Push(x);
+ Lock.Release();
+ return spins;
+ }
+
+ T Head() {
+ return Queue.Head();
+ }
+
+ T Pop() {
+ return Queue.Pop();
+ }
+
+ typename TOneOneQueueInplace<T, TSize>::TReadIterator ReadIterator() {
+ return Queue.Iterator();
+ }
+ };
+}
diff --git a/library/cpp/actors/core/memory_track.cpp b/library/cpp/actors/core/memory_track.cpp
new file mode 100644
index 0000000000..5f422116be
--- /dev/null
+++ b/library/cpp/actors/core/memory_track.cpp
@@ -0,0 +1,38 @@
+#include "memory_track.h"
+#include "memory_tracker.h"
+
+namespace NActors {
+namespace NMemory {
+
+namespace NPrivate {
+
+TThreadLocalInfo::TThreadLocalInfo()
+ : Metrics(TMemoryTracker::Instance()->GetCount())
+{
+ TMemoryTracker::Instance()->OnCreateThread(this);
+}
+
+TThreadLocalInfo::~TThreadLocalInfo() {
+ TMemoryTracker::Instance()->OnDestroyThread(this);
+}
+
+TMetric* TThreadLocalInfo::GetMetric(size_t index) {
+ if (Y_UNLIKELY(index >= Metrics.size())) {
+ return &Null;
+ }
+ return &Metrics[index];
+}
+
+const std::vector<TMetric>& TThreadLocalInfo::GetMetrics() const {
+ return Metrics;
+}
+
+size_t TBaseLabel::RegisterStaticMemoryLabel(const char* name, bool hasSensor) {
+ return TMemoryTracker::Instance()->RegisterStaticMemoryLabel(name, hasSensor);
+}
+
+}
+
+}
+}
+
diff --git a/library/cpp/actors/core/memory_track.h b/library/cpp/actors/core/memory_track.h
new file mode 100644
index 0000000000..6035333eeb
--- /dev/null
+++ b/library/cpp/actors/core/memory_track.h
@@ -0,0 +1,293 @@
+#pragma once
+
+#include <vector>
+
+#include <util/system/type_name.h>
+#include <util/thread/singleton.h>
+
+#define ENABLE_MEMORY_TRACKING
+
+namespace NActors {
+namespace NMemory {
+
+namespace NPrivate {
+
+class TMetric {
+ std::atomic<ssize_t> Memory;
+ std::atomic<ssize_t> Count;
+
+ void Copy(const TMetric& other) {
+ Memory.store(other.GetMemory(), std::memory_order_relaxed);
+ Count.store(other.GetCount(), std::memory_order_relaxed);
+ }
+
+public:
+ TMetric()
+ : Memory(0)
+ , Count(0)
+ {}
+
+ inline TMetric(const TMetric& other) {
+ Copy(other);
+ }
+
+ inline TMetric(TMetric&& other) {
+ Copy(other);
+ }
+
+ inline TMetric& operator=(const TMetric& other) {
+ Copy(other);
+ return *this;
+ }
+
+ inline TMetric& operator=(TMetric&& other) {
+ Copy(other);
+ return *this;
+ }
+
+ inline ssize_t GetMemory() const {
+ return Memory.load(std::memory_order_relaxed);
+ }
+ inline void SetMemory(ssize_t value) {
+ Memory.store(value, std::memory_order_relaxed);
+ }
+
+ inline ssize_t GetCount() const {
+ return Count.load(std::memory_order_relaxed);
+ }
+ inline void SetCount(ssize_t value) {
+ Count.store(value, std::memory_order_relaxed);
+ }
+
+ inline void operator+=(const TMetric& other) {
+ SetMemory(GetMemory() + other.GetMemory());
+ SetCount(GetCount() + other.GetCount());
+ }
+
+ inline void CalculatePeak(const TMetric& other) {
+ SetMemory(Max(GetMemory(), other.GetMemory()));
+ SetCount(Max(GetCount(), other.GetCount()));
+ }
+
+ inline void Add(size_t size) {
+ SetMemory(GetMemory() + size);
+ SetCount(GetCount() + 1);
+ }
+
+ inline void Sub(size_t size) {
+ SetMemory(GetMemory() - size);
+ SetCount(GetCount() - 1);
+ }
+};
+
+
+class TThreadLocalInfo {
+public:
+ TThreadLocalInfo();
+ ~TThreadLocalInfo();
+
+ TMetric* GetMetric(size_t index);
+ const std::vector<TMetric>& GetMetrics() const;
+
+private:
+ std::vector<TMetric> Metrics;
+
+ inline static TMetric Null = {};
+};
+
+
+class TBaseLabel {
+protected:
+ static size_t RegisterStaticMemoryLabel(const char* name, bool hasSensor);
+
+ inline static TMetric* GetLocalMetric(size_t index) {
+ return FastTlsSingleton<TThreadLocalInfo>()->GetMetric(index);
+ }
+};
+
+
+template <const char* Name>
+class TNameLabel
+ : TBaseLabel
+{
+public:
+ static void Add(size_t size) {
+#if defined(ENABLE_MEMORY_TRACKING)
+ Y_UNUSED(MetricInit);
+
+ if (Y_UNLIKELY(!Metric)) {
+ Metric = GetLocalMetric(Index);
+ }
+
+ Metric->Add(size);
+#else
+ Y_UNUSED(size);
+#endif
+ }
+
+ static void Sub(size_t size) {
+#if defined(ENABLE_MEMORY_TRACKING)
+ Y_UNUSED(MetricInit);
+
+ if (Y_UNLIKELY(!Metric)) {
+ Metric = GetLocalMetric(Index);
+ }
+
+ Metric->Sub(size);
+#else
+ Y_UNUSED(size);
+#endif
+ }
+
+private:
+#if defined(ENABLE_MEMORY_TRACKING)
+ inline static size_t Index = Max<size_t>();
+ inline static struct TMetricInit {
+ TMetricInit() {
+ Index = RegisterStaticMemoryLabel(Name, true);
+ }
+ } MetricInit;
+
+ inline static thread_local TMetric* Metric = nullptr;
+#endif
+};
+
+
+template <typename TType>
+class TTypeLabel
+ : TBaseLabel
+{
+public:
+ static void Add(size_t size) {
+#if defined(ENABLE_MEMORY_TRACKING)
+ Y_UNUSED(MetricInit);
+
+ if (Y_UNLIKELY(!Metric)) {
+ Metric = GetLocalMetric(Index);
+ }
+
+ Metric->Add(size);
+#else
+ Y_UNUSED(size);
+#endif
+ }
+
+ static void Sub(size_t size) {
+#if defined(ENABLE_MEMORY_TRACKING)
+ Y_UNUSED(MetricInit);
+
+ if (Y_UNLIKELY(!Metric)) {
+ Metric = GetLocalMetric(Index);
+ }
+
+ Metric->Sub(size);
+#else
+ Y_UNUSED(size);
+#endif
+ }
+
+private:
+#if defined(ENABLE_MEMORY_TRACKING)
+ inline static size_t Index = Max<size_t>();
+ inline static struct TMetricInit {
+ TMetricInit() {
+ Index = RegisterStaticMemoryLabel(TypeName<TType>().c_str(), false);
+ }
+ } MetricInit;
+
+ inline static thread_local TMetric* Metric = nullptr;
+#endif
+};
+
+
+template <typename T>
+struct TTrackHelper {
+#if defined(ENABLE_MEMORY_TRACKING)
+ void* operator new(size_t size) {
+ T::Add(size);
+ return malloc(size);
+ }
+
+ void* operator new[](size_t size) {
+ T::Add(size);
+ return malloc(size);
+ }
+
+ void operator delete(void* ptr, size_t size) {
+ T::Sub(size);
+ free(ptr);
+ }
+
+ void operator delete[](void* ptr, size_t size) {
+ T::Sub(size);
+ free(ptr);
+ }
+#endif
+};
+
+template <typename TType, typename T>
+struct TAllocHelper {
+ typedef size_t size_type;
+ typedef TType value_type;
+ typedef TType* pointer;
+ typedef const TType* const_pointer;
+
+ struct propagate_on_container_copy_assignment : public std::false_type {};
+ struct propagate_on_container_move_assignment : public std::false_type {};
+ struct propagate_on_container_swap : public std::false_type {};
+
+ pointer allocate(size_type n, const void* hint = nullptr) {
+ Y_UNUSED(hint);
+ auto size = n * sizeof(TType);
+ T::Add(size);
+ return (pointer)malloc(size);
+ }
+
+ void deallocate(pointer ptr, size_t n) {
+ auto size = n * sizeof(TType);
+ T::Sub(size);
+ free((void*)ptr);
+ }
+};
+
+} // NPrivate
+
+
+template <const char* Name>
+using TLabel = NPrivate::TNameLabel<Name>;
+
+template <typename TType, const char* Name = nullptr>
+struct TTrack
+ : public NPrivate::TTrackHelper<NPrivate::TNameLabel<Name>>
+{
+};
+
+template <typename TType>
+struct TTrack<TType, nullptr>
+ : public NPrivate::TTrackHelper<NPrivate::TTypeLabel<TType>>
+{
+};
+
+template <typename TType, const char* Name = nullptr>
+struct TAlloc
+ : public NPrivate::TAllocHelper<TType, NPrivate::TNameLabel<Name>>
+{
+ template<typename U>
+ struct rebind {
+ typedef TAlloc<U, Name> other;
+ };
+};
+
+template <typename TType>
+struct TAlloc<TType, nullptr>
+ : public NPrivate::TAllocHelper<TType, NPrivate::TTypeLabel<TType>>
+{
+ template<typename U>
+ struct rebind {
+ typedef TAlloc<U> other;
+ };
+};
+
+}
+}
+
diff --git a/library/cpp/actors/core/memory_tracker.cpp b/library/cpp/actors/core/memory_tracker.cpp
new file mode 100644
index 0000000000..8a12452c71
--- /dev/null
+++ b/library/cpp/actors/core/memory_tracker.cpp
@@ -0,0 +1,103 @@
+#include "memory_tracker.h"
+
+#include <util/generic/xrange.h>
+
+namespace NActors {
+namespace NMemory {
+
+namespace NPrivate {
+
+TMemoryTracker* TMemoryTracker::Instance() {
+ return SingletonWithPriority<TMemoryTracker, 0>();
+}
+
+void TMemoryTracker::Initialize() {
+ GlobalMetrics.resize(Indices.size());
+}
+
+const std::map<TString, size_t>& TMemoryTracker::GetMetricIndices() const {
+ return Indices;
+}
+
+const std::unordered_set<size_t>& TMemoryTracker::GetSensors() const {
+ return Sensors;
+}
+
+TString TMemoryTracker::GetName(size_t index) const {
+ return Names[index];
+}
+
+size_t TMemoryTracker::GetCount() const {
+ return Indices.size();
+}
+
+void TMemoryTracker::GatherMetrics(std::vector<TMetric>& metrics) const {
+ metrics.resize(0);
+ auto count = GetCount();
+
+ if (!count || GlobalMetrics.size() != count) {
+ return;
+ }
+
+ TReadGuard guard(LockThreadInfo);
+
+ metrics.resize(count);
+ for (size_t i : xrange(count)) {
+ metrics[i] += GlobalMetrics[i];
+ }
+
+ for (auto info : ThreadInfo) {
+ auto& localMetrics = info->GetMetrics();
+ if (localMetrics.size() == count) {
+ for (size_t i : xrange(count)) {
+ metrics[i] += localMetrics[i];
+ }
+ }
+ }
+}
+
+size_t TMemoryTracker::RegisterStaticMemoryLabel(const char* name, bool hasSensor) {
+ size_t index = 0;
+ auto found = Indices.find(name);
+ if (found == Indices.end()) {
+ TString str(name);
+ auto next = Names.size();
+ Indices.emplace(str, next);
+ Names.push_back(str);
+ index = next;
+ } else {
+ index = found->second;
+ }
+
+ if (hasSensor) {
+ Sensors.emplace(index);
+ }
+ return index;
+}
+
+void TMemoryTracker::OnCreateThread(TThreadLocalInfo* info) {
+ TWriteGuard guard(LockThreadInfo);
+ ThreadInfo.insert(info);
+}
+
+void TMemoryTracker::OnDestroyThread(TThreadLocalInfo* info) {
+ TWriteGuard guard(LockThreadInfo);
+
+ auto count = GetCount();
+ if (count && GlobalMetrics.size() == count) {
+ const auto& localMetrics = info->GetMetrics();
+ if (localMetrics.size() == count) {
+ for (size_t i : xrange(count)) {
+ GlobalMetrics[i] += localMetrics[i];
+ }
+ }
+ }
+
+ ThreadInfo.erase(info);
+}
+
+}
+
+}
+}
+
diff --git a/library/cpp/actors/core/memory_tracker.h b/library/cpp/actors/core/memory_tracker.h
new file mode 100644
index 0000000000..e74508191b
--- /dev/null
+++ b/library/cpp/actors/core/memory_tracker.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#include "memory_track.h"
+
+#include <map>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <util/system/rwlock.h>
+
+namespace NActors {
+namespace NMemory {
+
+namespace NPrivate {
+
+class TMemoryTracker {
+public:
+ static TMemoryTracker* Instance();
+
+ void Initialize();
+
+ const std::map<TString, size_t>& GetMetricIndices() const;
+ const std::unordered_set<size_t>& GetSensors() const;
+ TString GetName(size_t index) const;
+ size_t GetCount() const;
+
+ void GatherMetrics(std::vector<TMetric>& metrics) const;
+
+private:
+ size_t RegisterStaticMemoryLabel(const char* name, bool hasSensor);
+
+ void OnCreateThread(TThreadLocalInfo* info);
+ void OnDestroyThread(TThreadLocalInfo* info);
+
+private:
+ std::map<TString, size_t> Indices;
+ std::vector<TString> Names;
+
+ std::vector<TMetric> GlobalMetrics;
+
+ std::unordered_set<size_t> Sensors;
+
+ std::unordered_set<TThreadLocalInfo*> ThreadInfo;
+ TRWMutex LockThreadInfo;
+
+ friend class TThreadLocalInfo;
+ friend class TBaseLabel;
+};
+
+}
+
+}
+}
diff --git a/library/cpp/actors/core/memory_tracker_ut.cpp b/library/cpp/actors/core/memory_tracker_ut.cpp
new file mode 100644
index 0000000000..d168214da6
--- /dev/null
+++ b/library/cpp/actors/core/memory_tracker_ut.cpp
@@ -0,0 +1,262 @@
+#include "memory_tracker.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/system/hp_timer.h>
+#include <util/system/thread.h>
+
+namespace NActors {
+namespace NMemory {
+
+Y_UNIT_TEST_SUITE(TMemoryTrackerTest) {
+
+#if defined(ENABLE_MEMORY_TRACKING)
+
+using namespace NPrivate;
+
+size_t FindLabelIndex(const char* label) {
+ auto indices = TMemoryTracker::Instance()->GetMetricIndices();
+ auto it = indices.find(label);
+ UNIT_ASSERT(it != indices.end());
+ return it->second;
+}
+
+
+struct TTypeLabeled
+ : public NActors::NMemory::TTrack<TTypeLabeled>
+{
+ char payload[16];
+};
+
+static constexpr char NamedLabel[] = "NamedLabel";
+
+struct TNameLabeled
+ : public NActors::NMemory::TTrack<TNameLabeled, NamedLabel>
+{
+ char payload[32];
+};
+
+Y_UNIT_TEST(Gathering)
+{
+ TMemoryTracker::Instance()->Initialize();
+
+ auto* typed = new TTypeLabeled;
+ auto* typedArray = new TTypeLabeled[3];
+
+ auto* named = new TNameLabeled;
+ auto* namedArray = new TNameLabeled[5];
+ NActors::NMemory::TLabel<NamedLabel>::Add(100);
+
+ std::vector<TMetric> metrics;
+ TMemoryTracker::Instance()->GatherMetrics(metrics);
+
+ auto typeIndex = FindLabelIndex(TypeName<TTypeLabeled>().c_str());
+ UNIT_ASSERT(typeIndex < metrics.size());
+ UNIT_ASSERT(metrics[typeIndex].GetMemory() == sizeof(TTypeLabeled) * 4 + sizeof(size_t));
+ UNIT_ASSERT(metrics[typeIndex].GetCount() == 2);
+
+ auto nameIndex = FindLabelIndex(NamedLabel);
+ UNIT_ASSERT(nameIndex < metrics.size());
+ UNIT_ASSERT(metrics[nameIndex].GetMemory() == sizeof(TNameLabeled) * 6 + sizeof(size_t) + 100);
+ UNIT_ASSERT(metrics[nameIndex].GetCount() == 3);
+
+ NActors::NMemory::TLabel<NamedLabel>::Sub(100);
+ delete [] namedArray;
+ delete named;
+
+ delete [] typedArray;
+ delete typed;
+
+ TMemoryTracker::Instance()->GatherMetrics(metrics);
+
+ UNIT_ASSERT(metrics[typeIndex].GetMemory() == 0);
+ UNIT_ASSERT(metrics[typeIndex].GetCount() == 0);
+
+ UNIT_ASSERT(metrics[nameIndex].GetMemory() == 0);
+ UNIT_ASSERT(metrics[nameIndex].GetCount() == 0);
+}
+
+
+static constexpr char InContainerLabel[] = "InContainerLabel";
+
+struct TInContainer {
+ char payload[16];
+};
+
+Y_UNIT_TEST(Containers) {
+ TMemoryTracker::Instance()->Initialize();
+
+ std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer>> vecT;
+ vecT.resize(5);
+
+ std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer, InContainerLabel>> vecN;
+ vecN.resize(7);
+
+ using TKey = int;
+
+ std::map<TKey, TInContainer, std::less<TKey>,
+ NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> mapT;
+ mapT.emplace(0, TInContainer());
+ mapT.emplace(1, TInContainer());
+
+ std::map<TKey, TInContainer, std::less<TKey>,
+ NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> mapN;
+ mapN.emplace(0, TInContainer());
+
+ std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>,
+ NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> umapT;
+ umapT.emplace(0, TInContainer());
+
+ std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>,
+ NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> umapN;
+ umapN.emplace(0, TInContainer());
+ umapN.emplace(1, TInContainer());
+
+ std::vector<TMetric> metrics;
+ TMemoryTracker::Instance()->GatherMetrics(metrics);
+
+ auto indices = TMemoryTracker::Instance()->GetMetricIndices();
+ for (auto& [name, index] : indices) {
+ Cerr << "---- " << name
+ << ": memory = " << metrics[index].GetMemory()
+ << ", count = " << metrics[index].GetCount() << Endl;
+ }
+
+ auto vecTIndex = FindLabelIndex(TypeName<TInContainer>().c_str());
+ UNIT_ASSERT(metrics[vecTIndex].GetMemory() >= ssize_t(sizeof(TInContainer) * 5));
+ UNIT_ASSERT(metrics[vecTIndex].GetCount() == 1);
+
+ auto labelIndex = FindLabelIndex(InContainerLabel);
+ UNIT_ASSERT(metrics[labelIndex].GetCount() == 5);
+ UNIT_ASSERT(metrics[labelIndex].GetMemory() >= ssize_t(
+ sizeof(TInContainer) * 7 +
+ sizeof(decltype(mapN)::value_type) +
+ sizeof(decltype(umapN)::value_type) * 2));
+}
+
+
+static constexpr char InThreadLabel[] = "InThreadLabel";
+
+struct TInThread
+ : public NActors::NMemory::TTrack<TInThread, InThreadLabel>
+{
+ char payload[16];
+};
+
+void* ThreadProc(void*) {
+ return new TInThread;
+}
+
+Y_UNIT_TEST(Threads) {
+ TMemoryTracker::Instance()->Initialize();
+
+ auto index = FindLabelIndex(InThreadLabel);
+
+ auto* object1 = new TInThread;
+
+ std::vector<TMetric> metrics;
+ TMemoryTracker::Instance()->GatherMetrics(metrics);
+ UNIT_ASSERT(metrics[index].GetMemory() == sizeof(TInThread));
+ UNIT_ASSERT(metrics[index].GetCount() == 1);
+
+ TThread thread(&ThreadProc, nullptr);
+ thread.Start();
+ auto* object2 = static_cast<TInThread*>(thread.Join());
+
+ TMemoryTracker::Instance()->GatherMetrics(metrics);
+ UNIT_ASSERT(metrics[index].GetMemory() == sizeof(TInThread) * 2);
+ UNIT_ASSERT(metrics[index].GetCount() == 2);
+
+ delete object2;
+
+ TMemoryTracker::Instance()->GatherMetrics(metrics);
+ UNIT_ASSERT(metrics[index].GetMemory() == sizeof(TInThread));
+ UNIT_ASSERT(metrics[index].GetCount() == 1);
+
+ delete object1;
+}
+
+
+struct TNotTracked {
+ char payload[16];
+};
+
+struct TTracked
+ : public NActors::NMemory::TTrack<TTracked>
+{
+ char payload[16];
+};
+
+template <typename T>
+double MeasureAllocations() {
+ constexpr size_t objectsCount = 4 << 20;
+
+ std::vector<T*> objects;
+ objects.resize(objectsCount);
+
+ THPTimer timer;
+
+ for (size_t i = 0; i < objectsCount; ++i) {
+ objects[i] = new T;
+ }
+
+ for (size_t i = 0; i < objectsCount; ++i) {
+ delete objects[i];
+ }
+
+ auto seconds = timer.Passed();
+ Cerr << "---- objects: " << objectsCount << ", time: " << seconds << Endl;
+ return seconds;
+}
+
+Y_UNIT_TEST(Performance) {
+ TMemoryTracker::Instance()->Initialize();
+
+ constexpr size_t Runs = 16;
+
+ Cerr << "---- warmup" << Endl;
+ MeasureAllocations<TNotTracked>();
+ MeasureAllocations<TTracked>();
+
+ std::vector<double> noTrack;
+ std::vector<double> track;
+
+ for (size_t run = 0; run < Runs; ++run) {
+ Cerr << "---- no track" << Endl;
+ auto time = MeasureAllocations<TNotTracked>();
+ noTrack.push_back(time);
+
+ Cerr << "---- track" << Endl;
+ time = MeasureAllocations<TTracked>();
+ track.push_back(time);
+ }
+
+ double meanNoTrack = 0, stddevNoTrack = 0;
+ double meanTrack = 0, stddevTrack = 0;
+ for (size_t i = 0; i < Runs; ++i) {
+ meanNoTrack += noTrack[i];
+ meanTrack += track[i];
+ }
+ meanNoTrack /= Runs;
+ meanTrack /= Runs;
+
+ auto sqr = [](double val) { return val * val; };
+
+ for (size_t i = 0; i < Runs; ++i) {
+ stddevNoTrack += sqr(noTrack[i] - meanNoTrack);
+ stddevTrack += sqr(track[i] - meanTrack);
+ }
+ stddevNoTrack = sqrt(stddevNoTrack / (Runs - 1));
+ stddevTrack = sqrt(stddevTrack / (Runs - 1));
+
+ Cerr << "---- no track - mean: " << meanNoTrack << ", stddev: " << stddevNoTrack << Endl;
+ Cerr << "---- track - mean: " << meanTrack << ", stddev: " << stddevTrack << Endl;
+ Cerr << "---- tracking is slower by " << int((meanTrack / meanNoTrack - 1.0) * 100) << "%" << Endl;
+}
+
+#endif
+
+}
+
+}
+}
diff --git a/library/cpp/actors/core/mon.h b/library/cpp/actors/core/mon.h
new file mode 100644
index 0000000000..c450f2338e
--- /dev/null
+++ b/library/cpp/actors/core/mon.h
@@ -0,0 +1,234 @@
+#pragma once
+
+#include "events.h"
+#include "event_local.h"
+#include <library/cpp/monlib/service/monservice.h>
+#include <library/cpp/monlib/service/pages/mon_page.h>
+
+namespace NActors {
+ namespace NMon {
+ enum {
+ HttpInfo = EventSpaceBegin(NActors::TEvents::ES_MON),
+ HttpInfoRes,
+ RemoteHttpInfo,
+ RemoteHttpInfoRes,
+ RemoteJsonInfoRes,
+ RemoteBinaryInfoRes,
+ End
+ };
+
+ static_assert(End < EventSpaceEnd(NActors::TEvents::ES_MON), "expect End < EventSpaceEnd(NActors::TEvents::ES_MON)");
+
+ // request info from an actor in HTML format
+ struct TEvHttpInfo: public NActors::TEventLocal<TEvHttpInfo, HttpInfo> {
+ TEvHttpInfo(const NMonitoring::IMonHttpRequest& request, int subReqId = 0)
+ : Request(request)
+ , SubRequestId(subReqId)
+ {
+ }
+
+ TEvHttpInfo(const NMonitoring::IMonHttpRequest& request, const TString& userToken)
+ : Request(request)
+ , UserToken(userToken)
+ , SubRequestId(0)
+ {
+ }
+
+ const NMonitoring::IMonHttpRequest& Request;
+ TString UserToken; // built and serialized
+ // SubRequestId != 0 means that we assemble reply from multiple parts and SubRequestId contains this part id
+ int SubRequestId;
+ };
+
+ // base class for HTTP info response
+ struct IEvHttpInfoRes: public NActors::TEventLocal<IEvHttpInfoRes, HttpInfoRes> {
+ enum EContentType {
+ Html,
+ Custom,
+ };
+
+ IEvHttpInfoRes() {
+ }
+
+ virtual ~IEvHttpInfoRes() {
+ }
+
+ virtual void Output(IOutputStream& out) const = 0;
+ virtual EContentType GetContentType() const = 0;
+ };
+
+ // Ready to output HTML in TString
+ struct TEvHttpInfoRes: public IEvHttpInfoRes {
+ TEvHttpInfoRes(const TString& answer, int subReqId = 0, EContentType contentType = Html)
+ : Answer(answer)
+ , SubRequestId(subReqId)
+ , ContentType(contentType)
+ {
+ }
+
+ void Output(IOutputStream& out) const override {
+ out << Answer;
+ }
+
+ EContentType GetContentType() const override {
+ return ContentType;
+ }
+
+ const TString Answer;
+ const int SubRequestId;
+ const EContentType ContentType;
+ };
+
+ struct TEvRemoteHttpInfo: public NActors::TEventBase<TEvRemoteHttpInfo, RemoteHttpInfo> {
+ TEvRemoteHttpInfo() {
+ }
+
+ TEvRemoteHttpInfo(const TString& query)
+ : Query(query)
+ {
+ }
+
+ TEvRemoteHttpInfo(const TString& query, HTTP_METHOD method)
+ : Query(query)
+ , Method(method)
+ {
+ }
+
+ TString Query;
+ HTTP_METHOD Method;
+
+ TString PathInfo() const {
+ const size_t pos = Query.find('?');
+ return (pos == TString::npos) ? TString() : Query.substr(0, pos);
+ }
+
+ TCgiParameters Cgi() const {
+ const size_t pos = Query.find('?');
+ return TCgiParameters((pos == TString::npos) ? TString() : Query.substr(pos + 1));
+ }
+
+ TString ToStringHeader() const override {
+ return "TEvRemoteHttpInfo";
+ }
+
+ bool SerializeToArcadiaStream(TChunkSerializer *serializer) const override {
+ return serializer->WriteString(&Query);
+ }
+
+ ui32 CalculateSerializedSize() const override {
+ return Query.size();
+ }
+
+ bool IsSerializable() const override {
+ return true;
+ }
+
+ static IEventBase* Load(TEventSerializedData* bufs) {
+ return new TEvRemoteHttpInfo(bufs->GetString());
+ }
+
+ HTTP_METHOD GetMethod() const
+ {
+ return Method;
+ }
+ };
+
+ struct TEvRemoteHttpInfoRes: public NActors::TEventBase<TEvRemoteHttpInfoRes, RemoteHttpInfoRes> {
+ TEvRemoteHttpInfoRes() {
+ }
+
+ TEvRemoteHttpInfoRes(const TString& html)
+ : Html(html)
+ {
+ }
+
+ TString Html;
+
+ TString ToStringHeader() const override {
+ return "TEvRemoteHttpInfoRes";
+ }
+
+ bool SerializeToArcadiaStream(TChunkSerializer *serializer) const override {
+ return serializer->WriteString(&Html);
+ }
+
+ ui32 CalculateSerializedSize() const override {
+ return Html.size();
+ }
+
+ bool IsSerializable() const override {
+ return true;
+ }
+
+ static IEventBase* Load(TEventSerializedData* bufs) {
+ return new TEvRemoteHttpInfoRes(bufs->GetString());
+ }
+ };
+
+ struct TEvRemoteJsonInfoRes: public NActors::TEventBase<TEvRemoteJsonInfoRes, RemoteJsonInfoRes> {
+ TEvRemoteJsonInfoRes() {
+ }
+
+ TEvRemoteJsonInfoRes(const TString& json)
+ : Json(json)
+ {
+ }
+
+ TString Json;
+
+ TString ToStringHeader() const override {
+ return "TEvRemoteJsonInfoRes";
+ }
+
+ bool SerializeToArcadiaStream(TChunkSerializer *serializer) const override {
+ return serializer->WriteString(&Json);
+ }
+
+ ui32 CalculateSerializedSize() const override {
+ return Json.size();
+ }
+
+ bool IsSerializable() const override {
+ return true;
+ }
+
+ static IEventBase* Load(TEventSerializedData* bufs) {
+ return new TEvRemoteJsonInfoRes(bufs->GetString());
+ }
+ };
+
+ struct TEvRemoteBinaryInfoRes: public NActors::TEventBase<TEvRemoteBinaryInfoRes, RemoteBinaryInfoRes> {
+ TEvRemoteBinaryInfoRes() {
+ }
+
+ TEvRemoteBinaryInfoRes(const TString& blob)
+ : Blob(blob)
+ {
+ }
+
+ TString Blob;
+
+ TString ToStringHeader() const override {
+ return "TEvRemoteBinaryInfoRes";
+ }
+
+ bool SerializeToArcadiaStream(TChunkSerializer *serializer) const override {
+ return serializer->WriteString(&Blob);
+ }
+
+ ui32 CalculateSerializedSize() const override {
+ return Blob.size();
+ }
+
+ bool IsSerializable() const override {
+ return true;
+ }
+
+ static IEventBase* Load(TEventSerializedData* bufs) {
+ return new TEvRemoteBinaryInfoRes(bufs->GetString());
+ }
+ };
+
+ }
+
+}
diff --git a/library/cpp/actors/core/mon_stats.h b/library/cpp/actors/core/mon_stats.h
new file mode 100644
index 0000000000..d55552af0c
--- /dev/null
+++ b/library/cpp/actors/core/mon_stats.h
@@ -0,0 +1,147 @@
+#pragma once
+
+#include "defs.h"
+#include "actor.h"
+#include <library/cpp/monlib/metrics/histogram_snapshot.h>
+#include <util/system/hp_timer.h>
+
+namespace NActors {
+ struct TLogHistogram : public NMonitoring::IHistogramSnapshot {
+ TLogHistogram() {
+ memset(Buckets, 0, sizeof(Buckets));
+ }
+
+ inline void Add(ui64 val, ui64 inc = 1) {
+ size_t ind = 0;
+#if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ == 7
+ asm volatile("" ::
+ : "memory");
+#endif
+ if (val > 1) {
+ ind = GetValueBitCount(val - 1);
+ }
+#if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ == 7
+ asm volatile("" ::
+ : "memory");
+#endif
+ RelaxedStore(&TotalSamples, RelaxedLoad(&TotalSamples) + inc);
+ RelaxedStore(&Buckets[ind], RelaxedLoad(&Buckets[ind]) + inc);
+ }
+
+ void Aggregate(const TLogHistogram& other) {
+ const ui64 inc = RelaxedLoad(&other.TotalSamples);
+ RelaxedStore(&TotalSamples, RelaxedLoad(&TotalSamples) + inc);
+ for (size_t i = 0; i < Y_ARRAY_SIZE(Buckets); ++i) {
+ Buckets[i] += RelaxedLoad(&other.Buckets[i]);
+ }
+ }
+
+ // IHistogramSnapshot
+ ui32 Count() const override {
+ return Y_ARRAY_SIZE(Buckets);
+ }
+
+ NMonitoring::TBucketBound UpperBound(ui32 index) const override {
+ Y_ASSERT(index < Y_ARRAY_SIZE(Buckets));
+ if (index == 0) {
+ return 1;
+ }
+ return NMonitoring::TBucketBound(1ull << (index - 1)) * 2.0;
+ }
+
+ NMonitoring::TBucketValue Value(ui32 index) const override {
+ Y_ASSERT(index < Y_ARRAY_SIZE(Buckets));
+ return Buckets[index];
+ }
+
+ ui64 TotalSamples = 0;
+ ui64 Buckets[65];
+ };
+
+ struct TExecutorPoolStats {
+ ui64 MaxUtilizationTime = 0;
+ };
+
+ struct TExecutorThreadStats {
+ ui64 SentEvents = 0;
+ ui64 ReceivedEvents = 0;
+ ui64 PreemptedEvents = 0; // Number of events experienced hard preemption
+ ui64 NonDeliveredEvents = 0;
+ ui64 EmptyMailboxActivation = 0;
+ ui64 CpuNs = 0; // nanoseconds thread was executing on CPU (accounts for preemtion)
+ NHPTimer::STime ElapsedTicks = 0;
+ NHPTimer::STime ParkedTicks = 0;
+ NHPTimer::STime BlockedTicks = 0;
+ TLogHistogram ActivationTimeHistogram;
+ TLogHistogram EventDeliveryTimeHistogram;
+ TLogHistogram EventProcessingCountHistogram;
+ TLogHistogram EventProcessingTimeHistogram;
+ TVector<NHPTimer::STime> ElapsedTicksByActivity;
+ TVector<ui64> ReceivedEventsByActivity;
+ TVector<i64> ActorsAliveByActivity; // the sum should be positive, but per-thread might be negative
+ TVector<ui64> ScheduledEventsByActivity;
+ ui64 PoolActorRegistrations = 0;
+ ui64 PoolDestroyedActors = 0;
+ ui64 PoolAllocatedMailboxes = 0;
+ ui64 MailboxPushedOutBySoftPreemption = 0;
+ ui64 MailboxPushedOutByTime = 0;
+ ui64 MailboxPushedOutByEventCount = 0;
+
+ TExecutorThreadStats(size_t activityVecSize = 1) // must be not empty as 0 used as default
+ : ElapsedTicksByActivity(activityVecSize)
+ , ReceivedEventsByActivity(activityVecSize)
+ , ActorsAliveByActivity(activityVecSize)
+ , ScheduledEventsByActivity(activityVecSize)
+ {}
+
+ template <typename T>
+ static void AggregateOne(TVector<T>& self, const TVector<T>& other) {
+ const size_t selfSize = self.size();
+ const size_t otherSize = other.size();
+ if (selfSize < otherSize)
+ self.resize(otherSize);
+ for (size_t at = 0; at < otherSize; ++at)
+ self[at] += RelaxedLoad(&other[at]);
+ }
+
+ void Aggregate(const TExecutorThreadStats& other) {
+ SentEvents += RelaxedLoad(&other.SentEvents);
+ ReceivedEvents += RelaxedLoad(&other.ReceivedEvents);
+ PreemptedEvents += RelaxedLoad(&other.PreemptedEvents);
+ NonDeliveredEvents += RelaxedLoad(&other.NonDeliveredEvents);
+ EmptyMailboxActivation += RelaxedLoad(&other.EmptyMailboxActivation);
+ CpuNs += RelaxedLoad(&other.CpuNs);
+ ElapsedTicks += RelaxedLoad(&other.ElapsedTicks);
+ ParkedTicks += RelaxedLoad(&other.ParkedTicks);
+ BlockedTicks += RelaxedLoad(&other.BlockedTicks);
+ MailboxPushedOutBySoftPreemption += RelaxedLoad(&other.MailboxPushedOutBySoftPreemption);
+ MailboxPushedOutByTime += RelaxedLoad(&other.MailboxPushedOutByTime);
+ MailboxPushedOutByEventCount += RelaxedLoad(&other.MailboxPushedOutByEventCount);
+
+ ActivationTimeHistogram.Aggregate(other.ActivationTimeHistogram);
+ EventDeliveryTimeHistogram.Aggregate(other.EventDeliveryTimeHistogram);
+ EventProcessingCountHistogram.Aggregate(other.EventProcessingCountHistogram);
+ EventProcessingTimeHistogram.Aggregate(other.EventProcessingTimeHistogram);
+
+ AggregateOne(ElapsedTicksByActivity, other.ElapsedTicksByActivity);
+ AggregateOne(ReceivedEventsByActivity, other.ReceivedEventsByActivity);
+ AggregateOne(ActorsAliveByActivity, other.ActorsAliveByActivity);
+ AggregateOne(ScheduledEventsByActivity, other.ScheduledEventsByActivity);
+
+ RelaxedStore(
+ &PoolActorRegistrations,
+ std::max(RelaxedLoad(&PoolActorRegistrations), RelaxedLoad(&other.PoolActorRegistrations)));
+ RelaxedStore(
+ &PoolDestroyedActors,
+ std::max(RelaxedLoad(&PoolDestroyedActors), RelaxedLoad(&other.PoolDestroyedActors)));
+ RelaxedStore(
+ &PoolAllocatedMailboxes,
+ std::max(RelaxedLoad(&PoolAllocatedMailboxes), RelaxedLoad(&other.PoolAllocatedMailboxes)));
+ }
+
+ size_t MaxActivityType() const {
+ return ActorsAliveByActivity.size();
+ }
+ };
+
+}
diff --git a/library/cpp/actors/core/monotonic.cpp b/library/cpp/actors/core/monotonic.cpp
new file mode 100644
index 0000000000..3465149dbe
--- /dev/null
+++ b/library/cpp/actors/core/monotonic.cpp
@@ -0,0 +1,23 @@
+#include "monotonic.h"
+
+#include <chrono>
+
+namespace NActors {
+
+ namespace {
+ // Unfortunately time_since_epoch() is sometimes negative on wine
+ // Remember initial time point at program start and use offsets from that
+ std::chrono::steady_clock::time_point MonotonicOffset = std::chrono::steady_clock::now();
+ }
+
+ ui64 GetMonotonicMicroSeconds() {
+ auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - MonotonicOffset).count();
+ // Steady clock is supposed to never jump backwards, but it's better to be safe in case of buggy implementations
+ if (Y_UNLIKELY(microseconds < 0)) {
+ microseconds = 0;
+ }
+ // Add one so we never return zero
+ return microseconds + 1;
+ }
+
+} // namespace NActors
diff --git a/library/cpp/actors/core/monotonic.h b/library/cpp/actors/core/monotonic.h
new file mode 100644
index 0000000000..6fceb91dbe
--- /dev/null
+++ b/library/cpp/actors/core/monotonic.h
@@ -0,0 +1,111 @@
+#pragma once
+
+#include <util/datetime/base.h>
+
+namespace NActors {
+
+ /**
+ * Returns current monotonic time in microseconds
+ */
+ ui64 GetMonotonicMicroSeconds();
+
+ /**
+ * Similar to TInstant, but measuring monotonic time
+ */
+ class TMonotonic : public TTimeBase<TMonotonic> {
+ using TBase = TTimeBase<TMonotonic>;
+
+ private:
+ constexpr explicit TMonotonic(TValue value) noexcept
+ : TBase(value)
+ { }
+
+ public:
+ constexpr TMonotonic() noexcept {
+ }
+
+ static constexpr TMonotonic FromValue(TValue value) noexcept {
+ return TMonotonic(value);
+ }
+
+ static inline TMonotonic Now() {
+ return TMonotonic::MicroSeconds(GetMonotonicMicroSeconds());
+ }
+
+ using TBase::Days;
+ using TBase::Hours;
+ using TBase::MicroSeconds;
+ using TBase::MilliSeconds;
+ using TBase::Minutes;
+ using TBase::Seconds;
+
+ static constexpr TMonotonic Max() noexcept {
+ return TMonotonic(::Max<ui64>());
+ }
+
+ static constexpr TMonotonic Zero() noexcept {
+ return TMonotonic();
+ }
+
+ static constexpr TMonotonic MicroSeconds(ui64 us) noexcept {
+ return TMonotonic(TInstant::MicroSeconds(us).GetValue());
+ }
+
+ static constexpr TMonotonic MilliSeconds(ui64 ms) noexcept {
+ return TMonotonic(TInstant::MilliSeconds(ms).GetValue());
+ }
+
+ static constexpr TMonotonic Seconds(ui64 s) noexcept {
+ return TMonotonic(TInstant::Seconds(s).GetValue());
+ }
+
+ static constexpr TMonotonic Minutes(ui64 m) noexcept {
+ return TMonotonic(TInstant::Minutes(m).GetValue());
+ }
+
+ static constexpr TMonotonic Hours(ui64 h) noexcept {
+ return TMonotonic(TInstant::Hours(h).GetValue());
+ }
+
+ static constexpr TMonotonic Days(ui64 d) noexcept {
+ return TMonotonic(TInstant::Days(d).GetValue());
+ }
+
+ template<class T>
+ inline TMonotonic& operator+=(const T& t) noexcept {
+ return (*this = (*this + t));
+ }
+
+ template<class T>
+ inline TMonotonic& operator-=(const T& t) noexcept {
+ return (*this = (*this - t));
+ }
+ };
+} // namespace NActors
+
+Y_DECLARE_PODTYPE(NActors::TMonotonic);
+
+template<>
+struct THash<NActors::TMonotonic> {
+ size_t operator()(const NActors::TMonotonic& key) const {
+ return THash<NActors::TMonotonic::TValue>()(key.GetValue());
+ }
+};
+
+namespace NActors {
+
+ constexpr TDuration operator-(const TMonotonic& l, const TMonotonic& r) {
+ return TInstant::FromValue(l.GetValue()) - TInstant::FromValue(r.GetValue());
+ }
+
+ constexpr TMonotonic operator+(const TMonotonic& l, const TDuration& r) {
+ TInstant result = TInstant::FromValue(l.GetValue()) + r;
+ return TMonotonic::FromValue(result.GetValue());
+ }
+
+ constexpr TMonotonic operator-(const TMonotonic& l, const TDuration& r) {
+ TInstant result = TInstant::FromValue(l.GetValue()) - r;
+ return TMonotonic::FromValue(result.GetValue());
+ }
+
+} // namespace NActors
diff --git a/library/cpp/actors/core/probes.cpp b/library/cpp/actors/core/probes.cpp
new file mode 100644
index 0000000000..7ace83e102
--- /dev/null
+++ b/library/cpp/actors/core/probes.cpp
@@ -0,0 +1,28 @@
+#include "probes.h"
+
+#include "actorsystem.h"
+
+#include <util/string/builder.h>
+
+LWTRACE_DEFINE_PROVIDER(ACTORLIB_PROVIDER);
+
+namespace NActors {
+ TVector<NLWTrace::TDashboard> LWTraceDashboards(TActorSystemSetup* setup) {
+ TVector<NLWTrace::TDashboard> result;
+
+ NLWTrace::TDashboard slowDash;
+ ui32 pools = setup->GetExecutorsCount();
+ size_t top = 30;
+ slowDash.SetName("ActorSystem slow events");
+ slowDash.SetDescription(TStringBuilder() << "TOP" << top << " slow event executions >1M cycles for every pool (refresh page to update)");
+ for (ui32 pool = 0; pool < pools; pool++) {
+ auto* row = slowDash.AddRows();
+ auto* cell = row->AddCells();
+ cell->SetTitle(TStringBuilder() << pool << ":" << setup->GetPoolName(pool));
+ cell->SetUrl(TStringBuilder() << "?mode=log&id=.ACTORLIB_PROVIDER.SlowEvent.ppoolId=" << pool << "&s=eventMs&reverse=y&head=30");
+ }
+ result.push_back(slowDash);
+
+ return result;
+ }
+}
diff --git a/library/cpp/actors/core/probes.h b/library/cpp/actors/core/probes.h
new file mode 100644
index 0000000000..4912d6dd26
--- /dev/null
+++ b/library/cpp/actors/core/probes.h
@@ -0,0 +1,176 @@
+#pragma once
+
+#include <library/cpp/lwtrace/all.h>
+#include <util/generic/vector.h>
+
+#define LWACTORID(x) (x).RawX1(), (x).RawX2(), (x).NodeId(), (x).PoolID()
+#define LWTYPE_ACTORID ui64, ui64, ui32, ui32
+#define LWNAME_ACTORID(n) n "Raw1", n "Raw2", n "NodeId", n "PoolId"
+
+#define ACTORLIB_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \
+ PROBE(SlowEvent, GROUPS("ActorLibSlow"), \
+ TYPES(ui32, double, TString, TString, TString), \
+ NAMES("poolId", "eventMs", "eventType", "actorId", "actorType")) \
+ PROBE(EventSlowDelivery, GROUPS("ActorLibSlow"), \
+ TYPES(ui32, double, double, ui64, TString, TString, TString), \
+ NAMES("poolId", "deliveryMs", "sinceActivationMs", "eventProcessedBefore", "eventType", "actorId", "actorType")) \
+ PROBE(SlowActivation, GROUPS("ActorLibSlow"), \
+ TYPES(ui32, double), \
+ NAMES("poolId", "activationMs")) \
+ PROBE(SlowRegisterNew, GROUPS("ActorLibSlow"), \
+ TYPES(ui32, double), \
+ NAMES("poolId", "registerNewMs")) \
+ PROBE(SlowRegisterAdd, GROUPS("ActorLibSlow"), \
+ TYPES(ui32, double), \
+ NAMES("poolId", "registerAddMs")) \
+ PROBE(MailboxPushedOutBySoftPreemption, GROUPS("ActorLibMailbox", "ActorLibMailboxPushedOut"), \
+ TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \
+ NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \
+ PROBE(MailboxPushedOutByTime, GROUPS("ActorLibMailbox", "ActorLibMailboxPushedOut"), \
+ TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \
+ NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \
+ PROBE(MailboxPushedOutByEventCount, GROUPS("ActorLibMailbox", "ActorLibMailboxPushedOut"), \
+ TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \
+ NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \
+ PROBE(MailboxEmpty, GROUPS("ActorLibMailbox"), \
+ TYPES(ui32, TString, ui32, TDuration, ui64, TString, TString), \
+ NAMES("poolId", "pool", "eventsProcessed", "procTimeMs", "workerId", "actorId", "actorType")) \
+ PROBE(ActivationBegin, GROUPS(), \
+ TYPES(ui32, ui32, ui32, double), \
+ NAMES("cpu", "poolId", "workerId", "expireMs")) \
+ PROBE(ActivationEnd, GROUPS(), \
+ TYPES(ui32, ui32, ui32), \
+ NAMES("cpu", "poolId", "workerId")) \
+ PROBE(ExecutorThreadStats, GROUPS("ActorLibStats"), \
+ TYPES(ui32, TString, ui64, ui64, ui64, double, double), \
+ NAMES("poolId", "pool", "workerId", "execCount", "readyActivationCount", "execMs", "nonExecMs")) \
+ PROBE(SlowICReadLoopAdjustSize, GROUPS("ActorLibSlowIC"), \
+ TYPES(double), \
+ NAMES("icReadLoopAdjustSizeMs")) \
+ PROBE(SlowICReadFromSocket, GROUPS("ActorLibSlowIC"), \
+ TYPES(double), \
+ NAMES("icReadFromSocketMs")) \
+ PROBE(SlowICReadLoopSend, GROUPS("ActorLibSlowIC"), \
+ TYPES(double), \
+ NAMES("icReadLoopSendMs")) \
+ PROBE(SlowICAllocPacketBuffer, GROUPS("ActorLibSlowIC"), \
+ TYPES(ui32, double), \
+ NAMES("peerId", "icAllocPacketBufferMs")) \
+ PROBE(SlowICFillSendingBuffer, GROUPS("ActorLibSlowIC"), \
+ TYPES(ui32, double), \
+ NAMES("peerId", "icFillSendingBufferMs")) \
+ PROBE(SlowICPushSentPackets, GROUPS("ActorLibSlowIC"), \
+ TYPES(ui32, double), \
+ NAMES("peerId", "icPushSentPacketsMs")) \
+ PROBE(SlowICPushSendQueue, GROUPS("ActorLibSlowIC"), \
+ TYPES(ui32, double), \
+ NAMES("peerId", "icPushSendQueueMs")) \
+ PROBE(SlowICWriteData, GROUPS("ActorLibSlowIC"), \
+ TYPES(ui32, double), \
+ NAMES("peerId", "icWriteDataMs")) \
+ PROBE(SlowICDropConfirmed, GROUPS("ActorLibSlowIC"), \
+ TYPES(ui32, double), \
+ NAMES("peerId", "icDropConfirmedMs")) \
+ PROBE(ActorsystemScheduler, GROUPS("Durations"), \
+ TYPES(ui64, ui64, ui32, ui32, ui64, ui64), \
+ NAMES("timeUs", "timerfd_expirations", "eventsGottenFromQueues", "eventsSent", \
+ "eventsInSendQueue", "eventSchedulingErrorUs")) \
+ PROBE(ForwardEvent, GROUPS("Orbit", "InterconnectSessionTCP"), \
+ TYPES(ui32, ui32, ui32, LWTYPE_ACTORID, LWTYPE_ACTORID, ui64, ui32), \
+ NAMES("peerId", "type", "flags", LWNAME_ACTORID("r"), LWNAME_ACTORID("s"), \
+ "cookie", "eventSerializedSize")) \
+ PROBE(EnqueueEvent, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, ui64, TDuration, ui16, ui64, ui64), \
+ NAMES("peerId", "numEventsInReadyChannels", "enqueueBlockedTotalMs", "channelId", "queueSizeInEvents", "queueSizeInBytes")) \
+ PROBE(SerializeToPacketBegin, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, ui16, ui64), \
+ NAMES("peerId", "channelId", "outputQueueSize")) \
+ PROBE(SerializeToPacketEnd, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, ui16, ui64, ui64), \
+ NAMES("peerId", "channelId", "outputQueueSize", "offsetInPacket")) \
+ PROBE(FillSendingBuffer, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, ui32, ui64, TDuration), \
+ NAMES("peerId", "taskBytesGenerated", "numEventsInReadyChannelsBehind", "fillBlockedTotalMs")) \
+ PROBE(PacketGenerated, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, ui64, ui64, ui64, ui64), \
+ NAMES("peerId", "bytesUnwritten", "inflightBytes", "packetsGenerated", "packetSize")) \
+ PROBE(PacketWrittenToSocket, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, ui64, bool, ui64, ui64, TDuration, int), \
+ NAMES("peerId", "packetsWrittenToSocket", "triedWriting", "packetDataSize", "bytesUnwritten", "writeBlockedTotalMs", "fd")) \
+ PROBE(GenerateTraffic, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, double, ui64, ui32, ui64), \
+ NAMES("peerId", "generateTrafficMs", "dataBytesSent", "generatedPackets", "generatedBytes")) \
+ PROBE(WriteToSocket, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, ui64, ui64, ui64, ui64, TDuration, int), \
+ NAMES("peerId", "bytesWritten", "packetsWritten", "packetsWrittenToSocket", "bytesUnwritten", "writeBlockedTotalMs", "fd")) \
+ PROBE(UpdateFromInputSession, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, double), \
+ NAMES("peerId", "pingMs")) \
+ PROBE(UnblockByDropConfirmed, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, double), \
+ NAMES("peerId", "updateDeliveryMs")) \
+ PROBE(DropConfirmed, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, ui64, ui64), \
+ NAMES("peerId", "droppedBytes", "inflightBytes")) \
+ PROBE(StartRam, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32), \
+ NAMES("peerId")) \
+ PROBE(FinishRam, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, double), \
+ NAMES("peerId", "ramMs")) \
+ PROBE(SkipGenerateTraffic, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, double), \
+ NAMES("peerId", "elapsedSinceRamMs")) \
+ PROBE(StartBatching, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, double), \
+ NAMES("peerId", "batchPeriodMs")) \
+ PROBE(FinishBatching, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, double), \
+ NAMES("peerId", "finishBatchDeliveryMs")) \
+ PROBE(BlockedWrite, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, double, ui64), \
+ NAMES("peerId", "sendQueueSize", "writtenBytes")) \
+ PROBE(ReadyWrite, GROUPS("InterconnectSessionTCP"), \
+ TYPES(ui32, double, double), \
+ NAMES("peerId", "readyWriteDeliveryMs", "blockMs")) \
+ PROBE(EpollStartWaitIn, GROUPS("EpollThread"), \
+ TYPES(), \
+ NAMES()) \
+ PROBE(EpollFinishWaitIn, GROUPS("EpollThread"), \
+ TYPES(i32), \
+ NAMES("eventsCount")) \
+ PROBE(EpollWaitOut, GROUPS("EpollThread"), \
+ TYPES(i32), \
+ NAMES("eventsCount")) \
+ PROBE(EpollSendReadyRead, GROUPS("EpollThread"), \
+ TYPES(bool, bool, int), \
+ NAMES("hangup", "event", "fd")) \
+ PROBE(EpollSendReadyWrite, GROUPS("EpollThread"), \
+ TYPES(bool, bool, int), \
+ NAMES("hangup", "event", "fd")) \
+ PROBE(HardPreemption, GROUPS("UnitedWorker"), \
+ TYPES(ui32, ui32, ui32, ui32), \
+ NAMES("cpu", "prevPoolId", "prevWorkerId", "nextWorkerId")) \
+ PROBE(SetPreemptionTimer, GROUPS("UnitedWorker", "PreemptionTimer"), \
+ TYPES(ui32, ui32, int, double, double), \
+ NAMES("cpu", "workerId", "fd", "nowMs", "preemptMs")) \
+ PROBE(ResetPreemptionTimer, GROUPS("UnitedWorker", "PreemptionTimer"), \
+ TYPES(ui32, ui32, int, double, double), \
+ NAMES("cpu", "workerId", "fd", "nowMs", "preemptMs")) \
+ PROBE(SlowWorkerActionRace, GROUPS("UnitedWorker"), \
+ TYPES(ui32, ui32, ui64), \
+ NAMES("cpu", "poolId", "slowPoolsMask")) \
+ PROBE(PoolStats, GROUPS("PoolCpuBalancer"), \
+ TYPES(ui32, TString, ui64, ui8, ui8, double, double, double, ui64, ui64, ui64), \
+ NAMES("poolId", "pool", "currentCpus", "loadClass", "priority", "scaleFactor", "cpuIdle", "cpuLoad", "importance", "addImportance", "subImportance")) \
+ PROBE(MoveCpu, GROUPS("PoolCpuBalancer"), \
+ TYPES(ui32, ui64, TString, TString, ui32), \
+ NAMES("fromPoolId", "toPoolId", "fromPool", "toPool", "cpu")) \
+ /**/
+
+LWTRACE_DECLARE_PROVIDER(ACTORLIB_PROVIDER)
+
+namespace NActors {
+ struct TActorSystemSetup;
+ TVector<NLWTrace::TDashboard> LWTraceDashboards(TActorSystemSetup* setup);
+}
diff --git a/library/cpp/actors/core/process_stats.cpp b/library/cpp/actors/core/process_stats.cpp
new file mode 100644
index 0000000000..0e1dbd0031
--- /dev/null
+++ b/library/cpp/actors/core/process_stats.cpp
@@ -0,0 +1,303 @@
+#include "actorsystem.h"
+#include "actor_bootstrapped.h"
+#include "hfunc.h"
+#include "process_stats.h"
+
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+#include <library/cpp/monlib/metrics/metric_registry.h>
+
+#include <util/datetime/uptime.h>
+#include <util/system/defaults.h>
+#include <util/stream/file.h>
+#include <util/string/vector.h>
+#include <util/string/split.h>
+
+#ifndef _win_
+#include <sys/user.h>
+#include <sys/sysctl.h>
+#endif
+
+namespace NActors {
+#ifdef _linux_
+
+ namespace {
+ template <typename TVal>
+ static bool ExtractVal(const TString& str, const TString& name, TVal& res) {
+ if (!str.StartsWith(name))
+ return false;
+ size_t pos = name.size();
+ while (pos < str.size() && (str[pos] == ' ' || str[pos] == '\t')) {
+ pos++;
+ }
+ res = atol(str.data() + pos);
+ return true;
+ }
+
+ float TicksPerMillisec() {
+#ifdef _SC_CLK_TCK
+ return sysconf(_SC_CLK_TCK) / 1000.0;
+#else
+ return 1.f;
+#endif
+ }
+ }
+
+ bool TProcStat::Fill(pid_t pid) {
+ try {
+ TString strPid(ToString(pid));
+ TFileInput proc("/proc/" + strPid + "/status");
+ TString str;
+ while (proc.ReadLine(str)) {
+ if (ExtractVal(str, "VmRSS:", Rss))
+ continue;
+ if (ExtractVal(str, "voluntary_ctxt_switches:", VolCtxSwtch))
+ continue;
+ if (ExtractVal(str, "nonvoluntary_ctxt_switches:", NonvolCtxSwtch))
+ continue;
+ }
+ // Convert from kB to bytes
+ Rss *= 1024;
+
+ float tickPerMillisec = TicksPerMillisec();
+
+ TFileInput procStat("/proc/" + strPid + "/stat");
+ procStat.ReadLine(str);
+ if (!str.empty()) {
+ sscanf(str.data(),
+ "%d %*s %c %d %d %d %d %d %u %lu %lu "
+ "%lu %lu %lu %lu %ld %ld %ld %ld %ld "
+ "%ld %llu %lu %ld %lu",
+ &Pid, &State, &Ppid, &Pgrp, &Session, &TtyNr, &TPgid, &Flags, &MinFlt, &CMinFlt,
+ &MajFlt, &CMajFlt, &Utime, &Stime, &CUtime, &CStime, &Priority, &Nice, &NumThreads,
+ &ItRealValue, &StartTime, &Vsize, &RssPages, &RssLim);
+ Utime /= tickPerMillisec;
+ Stime /= tickPerMillisec;
+ CUtime /= tickPerMillisec;
+ CStime /= tickPerMillisec;
+ SystemUptime = ::Uptime();
+ Uptime = SystemUptime - TDuration::MilliSeconds(StartTime / TicksPerMillisec());
+ }
+
+ TFileInput statm("/proc/" + strPid + "/statm");
+ statm.ReadLine(str);
+ TVector<TString> fields;
+ StringSplitter(str).Split(' ').SkipEmpty().Collect(&fields);
+ if (fields.size() >= 7) {
+ ui64 resident = FromString<ui64>(fields[1]);
+ ui64 shared = FromString<ui64>(fields[2]);
+ if (PageSize == 0) {
+ PageSize = ObtainPageSize();
+ }
+ FileRss = shared * PageSize;
+ AnonRss = (resident - shared) * PageSize;
+ }
+
+ TFileInput cgroup("/proc/" + strPid + "/cgroup");
+ TString line;
+ TString memoryCGroup;
+ while (cgroup.ReadLine(line) > 0) {
+ StringSplitter(line).Split(':').Collect(&fields);
+ if (fields.size() > 2 && fields[1] == "memory") {
+ memoryCGroup = fields[2];
+ break;
+ }
+ }
+ if (!memoryCGroup.empty()) {
+ TFileInput limit("/sys/fs/cgroup/memory" + memoryCGroup + "/memory.limit_in_bytes");
+ if (limit.ReadLine(line) > 0) {
+ CGroupMemLim = FromString<ui64>(line);
+ if (CGroupMemLim > (1ULL << 40)) {
+ CGroupMemLim = 0;
+ }
+ }
+ }
+
+ } catch (...) {
+ return false;
+ }
+ return true;
+ }
+
+ long TProcStat::ObtainPageSize() {
+ long sz = sysconf(_SC_PAGESIZE);
+ return sz;
+ }
+
+#else
+
+ bool TProcStat::Fill(pid_t pid) {
+ Y_UNUSED(pid);
+ return false;
+ }
+
+ long TProcStat::ObtainPageSize() {
+ return 0;
+ }
+
+#endif
+
+namespace {
+ // Periodically collects process stats and exposes them as mon counters
+ template <typename TDerived>
+ class TProcStatCollectingActor: public TActorBootstrapped<TProcStatCollectingActor<TDerived>> {
+ public:
+ static constexpr IActor::EActivityType ActorActivityType() {
+ return IActor::ACTORLIB_STATS;
+ }
+
+ TProcStatCollectingActor(TDuration interval)
+ : Interval(interval)
+ {
+ }
+
+ void Bootstrap(const TActorContext& ctx) {
+ ctx.Schedule(Interval, new TEvents::TEvWakeup());
+ Self()->Become(&TDerived::StateWork);
+ }
+
+ STFUNC(StateWork) {
+ switch (ev->GetTypeRewrite()) {
+ CFunc(TEvents::TSystem::Wakeup, Wakeup);
+ }
+ }
+
+ private:
+ void Wakeup(const TActorContext& ctx) {
+ Self()->UpdateCounters(ProcStat);
+ ctx.Schedule(Interval, new TEvents::TEvWakeup());
+ }
+
+ TDerived* Self() {
+ ProcStat.Fill(getpid());
+ return static_cast<TDerived*>(this);
+ }
+
+ private:
+ const TDuration Interval;
+ TProcStat ProcStat;
+ };
+
+ // Periodically collects process stats and exposes them as mon counters
+ class TDynamicCounterCollector: public TProcStatCollectingActor<TDynamicCounterCollector> {
+ using TBase = TProcStatCollectingActor<TDynamicCounterCollector>;
+ public:
+ TDynamicCounterCollector(
+ ui32 intervalSeconds,
+ NMonitoring::TDynamicCounterPtr counters)
+ : TBase{TDuration::Seconds(intervalSeconds)}
+ {
+ ProcStatGroup = counters->GetSubgroup("counters", "utils");
+
+ VmSize = ProcStatGroup->GetCounter("Process/VmSize", false);
+ AnonRssSize = ProcStatGroup->GetCounter("Process/AnonRssSize", false);
+ FileRssSize = ProcStatGroup->GetCounter("Process/FileRssSize", false);
+ CGroupMemLimit = ProcStatGroup->GetCounter("Process/CGroupMemLimit", false);
+ UserTime = ProcStatGroup->GetCounter("Process/UserTime", true);
+ SysTime = ProcStatGroup->GetCounter("Process/SystemTime", true);
+ MinorPageFaults = ProcStatGroup->GetCounter("Process/MinorPageFaults", true);
+ MajorPageFaults = ProcStatGroup->GetCounter("Process/MajorPageFaults", true);
+ UptimeSeconds = ProcStatGroup->GetCounter("Process/UptimeSeconds", false);
+ NumThreads = ProcStatGroup->GetCounter("Process/NumThreads", false);
+ SystemUptimeSeconds = ProcStatGroup->GetCounter("System/UptimeSeconds", false);
+ }
+
+ void UpdateCounters(const TProcStat& procStat) {
+ *VmSize = procStat.Vsize;
+ *AnonRssSize = procStat.AnonRss;
+ *FileRssSize = procStat.FileRss;
+ if (procStat.CGroupMemLim) {
+ *CGroupMemLimit = procStat.CGroupMemLim;
+ }
+ *UserTime = procStat.Utime;
+ *SysTime = procStat.Stime;
+ *MinorPageFaults = procStat.MinFlt;
+ *MajorPageFaults = procStat.MajFlt;
+ *UptimeSeconds = procStat.Uptime.Seconds();
+ *NumThreads = procStat.NumThreads;
+ *SystemUptimeSeconds = procStat.Uptime.Seconds();
+ }
+
+ private:
+ NMonitoring::TDynamicCounterPtr ProcStatGroup;
+ NMonitoring::TDynamicCounters::TCounterPtr VmSize;
+ NMonitoring::TDynamicCounters::TCounterPtr AnonRssSize;
+ NMonitoring::TDynamicCounters::TCounterPtr FileRssSize;
+ NMonitoring::TDynamicCounters::TCounterPtr CGroupMemLimit;
+ NMonitoring::TDynamicCounters::TCounterPtr UserTime;
+ NMonitoring::TDynamicCounters::TCounterPtr SysTime;
+ NMonitoring::TDynamicCounters::TCounterPtr MinorPageFaults;
+ NMonitoring::TDynamicCounters::TCounterPtr MajorPageFaults;
+ NMonitoring::TDynamicCounters::TCounterPtr UptimeSeconds;
+ NMonitoring::TDynamicCounters::TCounterPtr NumThreads;
+ NMonitoring::TDynamicCounters::TCounterPtr SystemUptimeSeconds;
+ };
+
+
+ class TRegistryCollector: public TProcStatCollectingActor<TRegistryCollector> {
+ using TBase = TProcStatCollectingActor<TRegistryCollector>;
+ public:
+ TRegistryCollector(TDuration interval, NMonitoring::TMetricRegistry& registry)
+ : TBase{interval}
+ {
+ VmSize = registry.IntGauge({{"sensor", "process.VmSize"}});
+ AnonRssSize = registry.IntGauge({{"sensor", "process.AnonRssSize"}});
+ FileRssSize = registry.IntGauge({{"sensor", "process.FileRssSize"}});
+ CGroupMemLimit = registry.IntGauge({{"sensor", "process.CGroupMemLimit"}});
+ UptimeSeconds = registry.IntGauge({{"sensor", "process.UptimeSeconds"}});
+ NumThreads = registry.IntGauge({{"sensor", "process.NumThreads"}});
+ SystemUptimeSeconds = registry.IntGauge({{"sensor", "system.UptimeSeconds"}});
+
+ UserTime = registry.Rate({{"sensor", "process.UserTime"}});
+ SysTime = registry.Rate({{"sensor", "process.SystemTime"}});
+ MinorPageFaults = registry.Rate({{"sensor", "process.MinorPageFaults"}});
+ MajorPageFaults = registry.Rate({{"sensor", "process.MajorPageFaults"}});
+ }
+
+ void UpdateCounters(const TProcStat& procStat) {
+ VmSize->Set(procStat.Vsize);
+ AnonRssSize->Set(procStat.AnonRss);
+ FileRssSize->Set(procStat.FileRss);
+ CGroupMemLimit->Set(procStat.CGroupMemLim);
+ UptimeSeconds->Set(procStat.Uptime.Seconds());
+ NumThreads->Set(procStat.NumThreads);
+ SystemUptimeSeconds->Set(procStat.SystemUptime.Seconds());
+
+ // it is ok here to reset and add metric value, because mutation
+ // is performed in siglethreaded context
+
+ UserTime->Reset();
+ UserTime->Add(procStat.Utime);
+
+ SysTime->Reset();
+ SysTime->Add(procStat.Stime);
+
+ MinorPageFaults->Reset();
+ MinorPageFaults->Add(procStat.MinFlt);
+
+ MajorPageFaults->Reset();
+ MajorPageFaults->Add(procStat.MajFlt);
+ }
+
+ private:
+ NMonitoring::TIntGauge* VmSize;
+ NMonitoring::TIntGauge* AnonRssSize;
+ NMonitoring::TIntGauge* FileRssSize;
+ NMonitoring::TIntGauge* CGroupMemLimit;
+ NMonitoring::TRate* UserTime;
+ NMonitoring::TRate* SysTime;
+ NMonitoring::TRate* MinorPageFaults;
+ NMonitoring::TRate* MajorPageFaults;
+ NMonitoring::TIntGauge* UptimeSeconds;
+ NMonitoring::TIntGauge* NumThreads;
+ NMonitoring::TIntGauge* SystemUptimeSeconds;
+ };
+} // namespace
+
+ IActor* CreateProcStatCollector(ui32 intervalSec, NMonitoring::TDynamicCounterPtr counters) {
+ return new TDynamicCounterCollector(intervalSec, counters);
+ }
+
+ IActor* CreateProcStatCollector(TDuration interval, NMonitoring::TMetricRegistry& registry) {
+ return new TRegistryCollector(interval, registry);
+ }
+}
diff --git a/library/cpp/actors/core/process_stats.h b/library/cpp/actors/core/process_stats.h
new file mode 100644
index 0000000000..66346d0b5a
--- /dev/null
+++ b/library/cpp/actors/core/process_stats.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include "defs.h"
+#include "actor.h"
+
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+
+namespace NMonitoring {
+ class TMetricRegistry;
+}
+
+namespace NActors {
+ struct TProcStat {
+ ui64 Rss;
+ ui64 VolCtxSwtch;
+ ui64 NonvolCtxSwtch;
+
+ int Pid;
+ char State;
+ int Ppid;
+ int Pgrp;
+ int Session;
+ int TtyNr;
+ int TPgid;
+ unsigned Flags;
+ unsigned long MinFlt;
+ unsigned long CMinFlt;
+ unsigned long MajFlt;
+ unsigned long CMajFlt;
+ unsigned long Utime;
+ unsigned long Stime;
+ long CUtime;
+ long CStime;
+ long Priority;
+ long Nice;
+ long NumThreads;
+ long ItRealValue;
+ // StartTime is measured from system boot
+ unsigned long long StartTime;
+ unsigned long Vsize;
+ long RssPages;
+ unsigned long RssLim;
+ ui64 FileRss;
+ ui64 AnonRss;
+ ui64 CGroupMemLim = 0;
+
+ TDuration Uptime;
+ TDuration SystemUptime;
+ // ...
+
+ TProcStat() {
+ Zero(*this);
+ Y_UNUSED(PageSize);
+ }
+
+ bool Fill(pid_t pid);
+
+ private:
+ long PageSize = 0;
+
+ long ObtainPageSize();
+ };
+
+ IActor* CreateProcStatCollector(ui32 intervalSec, NMonitoring::TDynamicCounterPtr counters);
+ IActor* CreateProcStatCollector(TDuration interval, NMonitoring::TMetricRegistry& registry);
+}
diff --git a/library/cpp/actors/core/scheduler_actor.cpp b/library/cpp/actors/core/scheduler_actor.cpp
new file mode 100644
index 0000000000..febc5e40dd
--- /dev/null
+++ b/library/cpp/actors/core/scheduler_actor.cpp
@@ -0,0 +1,279 @@
+#include "actor_bootstrapped.h"
+#include "hfunc.h"
+#include "probes.h"
+#include "scheduler_actor.h"
+#include "scheduler_queue.h"
+
+#include <library/cpp/actors/interconnect/poller_actor.h>
+#include <util/system/hp_timer.h>
+
+#ifdef __linux__
+#include <sys/timerfd.h>
+#include <errno.h>
+
+LWTRACE_USING(ACTORLIB_PROVIDER);
+
+namespace NActors {
+ class TTimerDescriptor: public TSharedDescriptor {
+ const int Descriptor;
+
+ public:
+ TTimerDescriptor()
+ : Descriptor(timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK))
+ {
+ Y_VERIFY(Descriptor != -1, "timerfd_create() failed with %s", strerror(errno));
+ }
+
+ ~TTimerDescriptor() override {
+ close(Descriptor);
+ }
+
+ int GetDescriptor() override {
+ return Descriptor;
+ }
+ };
+
+ class TSchedulerActor: public TActor<TSchedulerActor> {
+ const TSchedulerConfig Cfg;
+ TIntrusivePtr<TSharedDescriptor> TimerDescriptor;
+
+ TVector<NSchedulerQueue::TReader*> Readers;
+
+ TActorId PollerActor;
+ TPollerToken::TPtr PollerToken;
+
+ ui64 RealTime;
+ ui64 MonotonicTime;
+
+ ui64 ActiveTick;
+ typedef TMap<ui64, TAutoPtr<NSchedulerQueue::TQueueType>> TMomentMap; // intrasecond queues
+ typedef THashMap<ui64, TAutoPtr<TMomentMap>> TScheduleMap; // over-second schedule
+
+ TScheduleMap ScheduleMap;
+
+ THolder<NThreading::TLegacyFuture<void, false>> MainCycle;
+
+ static const ui64 IntrasecondThreshold = 1048576; // ~second
+ TAutoPtr<TMomentMap> ActiveSec;
+ volatile ui64* CurrentTimestamp = nullptr;
+ volatile ui64* CurrentMonotonic = nullptr;
+ TDeque<TAutoPtr<IEventHandle>> EventsToBeSent;
+
+ public:
+ static constexpr IActor::EActivityType ActorActivityType() {
+ return IActor::ACTOR_SYSTEM_SCHEDULER_ACTOR;
+ }
+
+ TSchedulerActor(const TSchedulerConfig& cfg)
+ : TActor(&TSchedulerActor::StateFunc)
+ , Cfg(cfg)
+ , TimerDescriptor(new TTimerDescriptor())
+ , PollerActor(MakePollerActorId())
+ {
+ Y_ASSERT(Cfg.ResolutionMicroseconds != 0);
+ Y_ASSERT(Cfg.ProgressThreshold != 0);
+ Become(&TSchedulerActor::StateFunc);
+ }
+
+ void Handle(TEvSchedulerInitialize::TPtr& ev, const TActorContext& ctx) {
+ const TEvSchedulerInitialize& evInitialize = *ev->Get();
+ Y_ASSERT(evInitialize.ScheduleReaders.size() != 0);
+ Readers.resize(evInitialize.ScheduleReaders.size());
+ Copy(evInitialize.ScheduleReaders.begin(), evInitialize.ScheduleReaders.end(), Readers.begin());
+
+ Y_ASSERT(evInitialize.CurrentTimestamp != nullptr);
+ CurrentTimestamp = evInitialize.CurrentTimestamp;
+
+ Y_ASSERT(evInitialize.CurrentMonotonic != nullptr);
+ CurrentMonotonic = evInitialize.CurrentMonotonic;
+
+ struct itimerspec new_time;
+ memset(&new_time, 0, sizeof(new_time));
+ new_time.it_value.tv_nsec = Cfg.ResolutionMicroseconds * 1000;
+ new_time.it_interval.tv_nsec = Cfg.ResolutionMicroseconds * 1000;
+ int ret = timerfd_settime(TimerDescriptor->GetDescriptor(), 0, &new_time, NULL);
+ Y_VERIFY(ret != -1, "timerfd_settime() failed with %s", strerror(errno));
+ const bool success = ctx.Send(PollerActor, new TEvPollerRegister(TimerDescriptor, SelfId(), {}));
+ Y_VERIFY(success);
+
+ RealTime = RelaxedLoad(CurrentTimestamp);
+ MonotonicTime = RelaxedLoad(CurrentMonotonic);
+
+ ActiveTick = AlignUp<ui64>(MonotonicTime, IntrasecondThreshold);
+ }
+
+ void Handle(TEvPollerRegisterResult::TPtr ev, const TActorContext& ctx) {
+ PollerToken = ev->Get()->PollerToken;
+ HandleSchedule(ctx);
+ }
+
+ void UpdateTime() {
+ RealTime = TInstant::Now().MicroSeconds();
+ MonotonicTime = Max(MonotonicTime, GetMonotonicMicroSeconds());
+ AtomicStore(CurrentTimestamp, RealTime);
+ AtomicStore(CurrentMonotonic, MonotonicTime);
+ }
+
+ void TryUpdateTime(NHPTimer::STime* lastTimeUpdate) {
+ NHPTimer::STime hpnow;
+ GetTimeFast(&hpnow);
+ const ui64 elapsedCycles = hpnow > *lastTimeUpdate ? hpnow - *lastTimeUpdate : 0;
+ if (elapsedCycles > Cfg.ResolutionMicroseconds * (NHPTimer::GetCyclesPerSecond() / IntrasecondThreshold)) {
+ UpdateTime();
+ GetTimeFast(lastTimeUpdate);
+ }
+ }
+
+ void HandleSchedule(const TActorContext& ctx) {
+ for (;;) {
+ NHPTimer::STime schedulingStart;
+ GetTimeFast(&schedulingStart);
+ NHPTimer::STime lastTimeUpdate = schedulingStart;
+
+ ui64 expired;
+ ssize_t bytesRead;
+ bytesRead = read(TimerDescriptor->GetDescriptor(), &expired, sizeof(expired));
+ if (bytesRead == -1) {
+ if (errno == EAGAIN) {
+ PollerToken->Request(true, false);
+ break;
+ } else if (errno == EINTR) {
+ continue;
+ }
+ }
+ Y_VERIFY(bytesRead == sizeof(expired), "Error while reading from timerfd, strerror# %s", strerror(errno));
+ UpdateTime();
+
+ ui32 eventsGottenFromQueues = 0;
+ // collect everything from queues
+ for (ui32 i = 0; i != Readers.size(); ++i) {
+ while (NSchedulerQueue::TEntry* x = Readers[i]->Pop()) {
+ const ui64 instant = AlignUp<ui64>(x->InstantMicroseconds, Cfg.ResolutionMicroseconds);
+ IEventHandle* const ev = x->Ev;
+ ISchedulerCookie* const cookie = x->Cookie;
+
+ // check is cookie still valid? looks like it will hurt performance w/o sagnificant memory save
+
+ if (instant <= ActiveTick) {
+ if (!ActiveSec)
+ ActiveSec.Reset(new TMomentMap());
+ TAutoPtr<NSchedulerQueue::TQueueType>& queue = (*ActiveSec)[instant];
+ if (!queue)
+ queue.Reset(new NSchedulerQueue::TQueueType());
+ queue->Writer.Push(instant, ev, cookie);
+ } else {
+ const ui64 intrasecond = AlignUp<ui64>(instant, IntrasecondThreshold);
+ TAutoPtr<TMomentMap>& msec = ScheduleMap[intrasecond];
+ if (!msec)
+ msec.Reset(new TMomentMap());
+ TAutoPtr<NSchedulerQueue::TQueueType>& queue = (*msec)[instant];
+ if (!queue)
+ queue.Reset(new NSchedulerQueue::TQueueType());
+ queue->Writer.Push(instant, ev, cookie);
+ }
+ ++eventsGottenFromQueues;
+ TryUpdateTime(&lastTimeUpdate);
+ }
+ }
+
+ ui64 eventSchedulingErrorUs = 0;
+ // send everything triggered on schedule
+ for (;;) {
+ while (!!ActiveSec && !ActiveSec->empty()) {
+ TMomentMap::iterator it = ActiveSec->begin();
+ if (it->first <= MonotonicTime) {
+ if (NSchedulerQueue::TQueueType* q = it->second.Get()) {
+ while (NSchedulerQueue::TEntry* x = q->Reader.Pop()) {
+ Y_VERIFY_DEBUG(x->InstantMicroseconds <= ActiveTick);
+ if (eventSchedulingErrorUs == 0 && MonotonicTime > x->InstantMicroseconds) {
+ eventSchedulingErrorUs = MonotonicTime - x->InstantMicroseconds;
+ }
+ IEventHandle* ev = x->Ev;
+ ISchedulerCookie* cookie = x->Cookie;
+ if (cookie) {
+ if (cookie->Detach()) {
+ EventsToBeSent.push_back(ev);
+ } else {
+ delete ev;
+ }
+ } else {
+ EventsToBeSent.push_back(ev);
+ }
+ TryUpdateTime(&lastTimeUpdate);
+ }
+ }
+ ActiveSec->erase(it);
+ } else {
+ break;
+ }
+ }
+
+ if (ActiveTick <= MonotonicTime) {
+ Y_VERIFY_DEBUG(!ActiveSec || ActiveSec->empty());
+ ActiveSec.Destroy();
+ ActiveTick += IntrasecondThreshold;
+ TScheduleMap::iterator it = ScheduleMap.find(ActiveTick);
+ if (it != ScheduleMap.end()) {
+ ActiveSec = it->second;
+ ScheduleMap.erase(it);
+ }
+ continue;
+ }
+
+ // ok, if we are here - then nothing is ready, so send step complete
+ break;
+ }
+
+ // Send all from buffer queue
+ const ui64 eventsToBeSentSize = EventsToBeSent.size();
+ ui32 sentCount = 0;
+ if (eventsToBeSentSize > Cfg.RelaxedSendThresholdEventsPerCycle) {
+ sentCount = Cfg.RelaxedSendPaceEventsPerCycle +
+ (eventsToBeSentSize - Cfg.RelaxedSendThresholdEventsPerCycle) / 2;
+ } else {
+ sentCount = Min(eventsToBeSentSize, Cfg.RelaxedSendPaceEventsPerCycle);
+ }
+ for (ui32 i = 0; i < sentCount; ++i) {
+ ctx.Send(EventsToBeSent.front());
+ EventsToBeSent.pop_front();
+ }
+
+ NHPTimer::STime hpnow;
+ GetTimeFast(&hpnow);
+ const ui64 processingTime = hpnow > schedulingStart ? hpnow - schedulingStart : 0;
+ const ui64 elapsedTimeMicroseconds = processingTime / (NHPTimer::GetCyclesPerSecond() / IntrasecondThreshold);
+ LWPROBE(ActorsystemScheduler, elapsedTimeMicroseconds, expired, eventsGottenFromQueues, sentCount,
+ eventsToBeSentSize, eventSchedulingErrorUs);
+ TryUpdateTime(&lastTimeUpdate);
+ }
+ }
+
+ STRICT_STFUNC(StateFunc,
+ HFunc(TEvSchedulerInitialize, Handle)
+ CFunc(TEvPollerReady::EventType, HandleSchedule)
+ CFunc(TEvents::TSystem::PoisonPill, Die)
+ HFunc(TEvPollerRegisterResult, Handle)
+ )
+ };
+
+ IActor* CreateSchedulerActor(const TSchedulerConfig& cfg) {
+ if (cfg.UseSchedulerActor) {
+ return new TSchedulerActor(cfg);
+ } else {
+ return nullptr;
+ }
+ }
+
+}
+
+#else // linux
+
+namespace NActors {
+ IActor* CreateSchedulerActor(const TSchedulerConfig& cfg) {
+ Y_UNUSED(cfg);
+ return nullptr;
+ }
+
+}
+
+#endif // linux
diff --git a/library/cpp/actors/core/scheduler_actor.h b/library/cpp/actors/core/scheduler_actor.h
new file mode 100644
index 0000000000..c2c561b43d
--- /dev/null
+++ b/library/cpp/actors/core/scheduler_actor.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "actor.h"
+#include "event_local.h"
+#include "events.h"
+#include "scheduler_basic.h"
+
+namespace NActors {
+ struct TEvSchedulerInitialize : TEventLocal<TEvSchedulerInitialize, TEvents::TSystem::Bootstrap> {
+ TVector<NSchedulerQueue::TReader*> ScheduleReaders;
+ volatile ui64* CurrentTimestamp;
+ volatile ui64* CurrentMonotonic;
+
+ TEvSchedulerInitialize(const TVector<NSchedulerQueue::TReader*>& scheduleReaders, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic)
+ : ScheduleReaders(scheduleReaders)
+ , CurrentTimestamp(currentTimestamp)
+ , CurrentMonotonic(currentMonotonic)
+ {
+ }
+ };
+
+ IActor* CreateSchedulerActor(const TSchedulerConfig& cfg);
+
+ inline TActorId MakeSchedulerActorId() {
+ char x[12] = {'s', 'c', 'h', 'e', 'd', 'u', 'l', 'e', 'r', 's', 'e', 'r'};
+ return TActorId(0, TStringBuf(x, 12));
+ }
+
+}
diff --git a/library/cpp/actors/core/scheduler_actor_ut.cpp b/library/cpp/actors/core/scheduler_actor_ut.cpp
new file mode 100644
index 0000000000..09b7369d36
--- /dev/null
+++ b/library/cpp/actors/core/scheduler_actor_ut.cpp
@@ -0,0 +1,100 @@
+#include "actor_coroutine.h"
+#include "actorsystem.h"
+#include "executor_pool_basic.h"
+#include "scheduler_actor.h"
+#include "scheduler_basic.h"
+#include "events.h"
+#include "event_local.h"
+#include "hfunc.h"
+#include <library/cpp/actors/interconnect/poller_actor.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/system/sanitizers.h>
+
+using namespace NActors;
+
+Y_UNIT_TEST_SUITE(SchedulerActor) {
+ class TTestActor: public TActorBootstrapped<TTestActor> {
+ TManualEvent& DoneEvent;
+ TAtomic& EventsProcessed;
+ TInstant LastWakeup;
+ const TAtomicBase EventsTotalCount;
+ const TDuration ScheduleDelta;
+
+ public:
+ TTestActor(TManualEvent& doneEvent, TAtomic& eventsProcessed, TAtomicBase eventsTotalCount, ui32 scheduleDeltaMs)
+ : DoneEvent(doneEvent)
+ , EventsProcessed(eventsProcessed)
+ , EventsTotalCount(eventsTotalCount)
+ , ScheduleDelta(TDuration::MilliSeconds(scheduleDeltaMs))
+ {
+ }
+
+ void Bootstrap(const TActorContext& ctx) {
+ LastWakeup = ctx.Now();
+ Become(&TThis::StateFunc);
+ ctx.Schedule(ScheduleDelta, new TEvents::TEvWakeup());
+ }
+
+ void Handle(TEvents::TEvWakeup::TPtr& /*ev*/, const TActorContext& ctx) {
+ const TInstant now = ctx.Now();
+ UNIT_ASSERT(now - LastWakeup >= ScheduleDelta);
+ LastWakeup = now;
+
+ if (AtomicIncrement(EventsProcessed) == EventsTotalCount) {
+ DoneEvent.Signal();
+ } else {
+ ctx.Schedule(ScheduleDelta, new TEvents::TEvWakeup());
+ }
+ }
+
+ STRICT_STFUNC(StateFunc, {HFunc(TEvents::TEvWakeup, Handle)})
+ };
+
+ void Test(TAtomicBase eventsTotalCount, ui32 scheduleDeltaMs) {
+ THolder<TActorSystemSetup> setup = MakeHolder<TActorSystemSetup>();
+ setup->NodeId = 0;
+ setup->ExecutorsCount = 1;
+ setup->Executors.Reset(new TAutoPtr<IExecutorPool>[setup->ExecutorsCount]);
+ for (ui32 i = 0; i < setup->ExecutorsCount; ++i) {
+ setup->Executors[i] = new TBasicExecutorPool(i, 5, 10, "basic");
+ }
+ // create poller actor (whether platform supports it)
+ TActorId pollerActorId;
+ if (IActor* poller = CreatePollerActor()) {
+ pollerActorId = MakePollerActorId();
+ setup->LocalServices.emplace_back(pollerActorId, TActorSetupCmd(poller, TMailboxType::ReadAsFilled, 0));
+ }
+ TActorId schedulerActorId;
+ if (IActor* schedulerActor = CreateSchedulerActor(TSchedulerConfig())) {
+ schedulerActorId = MakeSchedulerActorId();
+ setup->LocalServices.emplace_back(schedulerActorId, TActorSetupCmd(schedulerActor, TMailboxType::ReadAsFilled, 0));
+ }
+ setup->Scheduler = CreateSchedulerThread(TSchedulerConfig());
+
+ TActorSystem actorSystem(setup);
+
+ actorSystem.Start();
+
+ TManualEvent doneEvent;
+ TAtomic eventsProcessed = 0;
+ actorSystem.Register(new TTestActor(doneEvent, eventsProcessed, eventsTotalCount, scheduleDeltaMs));
+ doneEvent.WaitI();
+
+ UNIT_ASSERT(AtomicGet(eventsProcessed) == eventsTotalCount);
+
+ actorSystem.Stop();
+ }
+
+ Y_UNIT_TEST(LongEvents) {
+ Test(10, 500);
+ }
+
+ Y_UNIT_TEST(MediumEvents) {
+ Test(100, 50);
+ }
+
+ Y_UNIT_TEST(QuickEvents) {
+ Test(1000, 5);
+ }
+}
diff --git a/library/cpp/actors/core/scheduler_basic.cpp b/library/cpp/actors/core/scheduler_basic.cpp
new file mode 100644
index 0000000000..fba200e16b
--- /dev/null
+++ b/library/cpp/actors/core/scheduler_basic.cpp
@@ -0,0 +1,274 @@
+#include "scheduler_basic.h"
+#include "scheduler_queue.h"
+
+#include <library/cpp/actors/util/datetime.h>
+#include <library/cpp/actors/util/thread.h>
+
+#ifdef BALLOC
+#include <library/cpp/balloc/optional/operators.h>
+#endif
+
+namespace NActors {
+
+ struct TBasicSchedulerThread::TMonCounters {
+ NMonitoring::TDynamicCounters::TCounterPtr TimeDelayMs;
+ NMonitoring::TDynamicCounters::TCounterPtr QueueSize;
+ NMonitoring::TDynamicCounters::TCounterPtr EventsSent;
+ NMonitoring::TDynamicCounters::TCounterPtr EventsDropped;
+ NMonitoring::TDynamicCounters::TCounterPtr EventsAdded;
+ NMonitoring::TDynamicCounters::TCounterPtr Iterations;
+ NMonitoring::TDynamicCounters::TCounterPtr Sleeps;
+ NMonitoring::TDynamicCounters::TCounterPtr ElapsedMicrosec;
+
+ TMonCounters(const NMonitoring::TDynamicCounterPtr& counters)
+ : TimeDelayMs(counters->GetCounter("Scheduler/TimeDelayMs", false))
+ , QueueSize(counters->GetCounter("Scheduler/QueueSize", false))
+ , EventsSent(counters->GetCounter("Scheduler/EventsSent", true))
+ , EventsDropped(counters->GetCounter("Scheduler/EventsDropped", true))
+ , EventsAdded(counters->GetCounter("Scheduler/EventsAdded", true))
+ , Iterations(counters->GetCounter("Scheduler/Iterations", true))
+ , Sleeps(counters->GetCounter("Scheduler/Sleeps", true))
+ , ElapsedMicrosec(counters->GetCounter("Scheduler/ElapsedMicrosec", true))
+ { }
+ };
+
+ TBasicSchedulerThread::TBasicSchedulerThread(const TSchedulerConfig& config)
+ : Config(config)
+ , MonCounters(Config.MonCounters ? new TMonCounters(Config.MonCounters) : nullptr)
+ , ActorSystem(nullptr)
+ , CurrentTimestamp(nullptr)
+ , CurrentMonotonic(nullptr)
+ , TotalReaders(0)
+ , StopFlag(false)
+ , ScheduleMap(3600)
+ {
+ Y_VERIFY(!Config.UseSchedulerActor, "Cannot create scheduler thread because Config.UseSchedulerActor# true");
+ }
+
+ TBasicSchedulerThread::~TBasicSchedulerThread() {
+ Y_VERIFY(!MainCycle);
+ }
+
+ void TBasicSchedulerThread::CycleFunc() {
+#ifdef BALLOC
+ ThreadDisableBalloc();
+#endif
+ ::SetCurrentThreadName("Scheduler");
+
+ ui64 currentMonotonic = RelaxedLoad(CurrentMonotonic);
+ ui64 throttledMonotonic = currentMonotonic;
+
+ ui64 activeTick = AlignUp<ui64>(throttledMonotonic, IntrasecondThreshold);
+ TAutoPtr<TMomentMap> activeSec;
+
+ NHPTimer::STime hpprev = GetCycleCountFast();
+ ui64 nextTimestamp = TInstant::Now().MicroSeconds();
+ ui64 nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds());
+
+ while (!AtomicLoad(&StopFlag)) {
+ {
+ const ui64 delta = nextMonotonic - throttledMonotonic;
+ const ui64 elapsedDelta = nextMonotonic - currentMonotonic;
+ const ui64 threshold = Max(Min(Config.ProgressThreshold, 2 * elapsedDelta), ui64(1));
+
+ throttledMonotonic = (delta > threshold) ? throttledMonotonic + threshold : nextMonotonic;
+
+ if (MonCounters) {
+ *MonCounters->TimeDelayMs = (nextMonotonic - throttledMonotonic) / 1000;
+ }
+ }
+ AtomicStore(CurrentTimestamp, nextTimestamp);
+ AtomicStore(CurrentMonotonic, nextMonotonic);
+ currentMonotonic = nextMonotonic;
+
+ if (MonCounters) {
+ ++*MonCounters->Iterations;
+ }
+
+ bool somethingDone = false;
+
+ // first step - send everything triggered on schedule
+ ui64 eventsSent = 0;
+ ui64 eventsDropped = 0;
+ for (;;) {
+ while (!!activeSec && !activeSec->empty()) {
+ TMomentMap::iterator it = activeSec->begin();
+ if (it->first <= throttledMonotonic) {
+ if (NSchedulerQueue::TQueueType* q = it->second.Get()) {
+ while (NSchedulerQueue::TEntry* x = q->Reader.Pop()) {
+ somethingDone = true;
+ Y_VERIFY_DEBUG(x->InstantMicroseconds <= activeTick);
+ IEventHandle* ev = x->Ev;
+ ISchedulerCookie* cookie = x->Cookie;
+ // TODO: lazy send with backoff queue to not hang over contended mailboxes
+ if (cookie) {
+ if (cookie->Detach()) {
+ ActorSystem->Send(ev);
+ ++eventsSent;
+ } else {
+ delete ev;
+ ++eventsDropped;
+ }
+ } else {
+ ActorSystem->Send(ev);
+ ++eventsSent;
+ }
+ }
+ }
+ activeSec->erase(it);
+ } else
+ break;
+ }
+
+ if (activeTick <= throttledMonotonic) {
+ Y_VERIFY_DEBUG(!activeSec || activeSec->empty());
+ activeSec.Destroy();
+ activeTick += IntrasecondThreshold;
+ TScheduleMap::iterator it = ScheduleMap.find(activeTick);
+ if (it != ScheduleMap.end()) {
+ activeSec = it->second;
+ ScheduleMap.erase(it);
+ }
+ continue;
+ }
+
+ // ok, if we are here - then nothing is ready, so send step complete
+ break;
+ }
+
+ // second step - collect everything from queues
+
+ ui64 eventsAdded = 0;
+ for (ui32 i = 0; i != TotalReaders; ++i) {
+ while (NSchedulerQueue::TEntry* x = Readers[i]->Pop()) {
+ somethingDone = true;
+ const ui64 instant = AlignUp<ui64>(x->InstantMicroseconds, Config.ResolutionMicroseconds);
+ IEventHandle* const ev = x->Ev;
+ ISchedulerCookie* const cookie = x->Cookie;
+
+ // check is cookie still valid? looks like it will hurt performance w/o sagnificant memory save
+
+ if (instant <= activeTick) {
+ if (!activeSec)
+ activeSec.Reset(new TMomentMap());
+ TAutoPtr<NSchedulerQueue::TQueueType>& queue = (*activeSec)[instant];
+ if (!queue)
+ queue.Reset(new NSchedulerQueue::TQueueType());
+ queue->Writer.Push(instant, ev, cookie);
+ } else {
+ const ui64 intrasecond = AlignUp<ui64>(instant, IntrasecondThreshold);
+ TAutoPtr<TMomentMap>& msec = ScheduleMap[intrasecond];
+ if (!msec)
+ msec.Reset(new TMomentMap());
+ TAutoPtr<NSchedulerQueue::TQueueType>& queue = (*msec)[instant];
+ if (!queue)
+ queue.Reset(new NSchedulerQueue::TQueueType());
+ queue->Writer.Push(instant, ev, cookie);
+ }
+
+ ++eventsAdded;
+ }
+ }
+
+ NHPTimer::STime hpnow = GetCycleCountFast();
+
+ if (MonCounters) {
+ *MonCounters->QueueSize -= eventsSent + eventsDropped;
+ *MonCounters->QueueSize += eventsAdded;
+ *MonCounters->EventsSent += eventsSent;
+ *MonCounters->EventsDropped += eventsDropped;
+ *MonCounters->EventsAdded += eventsAdded;
+ *MonCounters->ElapsedMicrosec += NHPTimer::GetSeconds(hpnow - hpprev) * 1000000;
+ }
+
+ hpprev = hpnow;
+ nextTimestamp = TInstant::Now().MicroSeconds();
+ nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds());
+
+ // ok complete, if nothing left - sleep
+ if (!somethingDone) {
+ const ui64 nextInstant = AlignDown<ui64>(throttledMonotonic + Config.ResolutionMicroseconds, Config.ResolutionMicroseconds);
+ if (nextMonotonic >= nextInstant) // already in next time-slice
+ continue;
+
+ const ui64 delta = nextInstant - nextMonotonic;
+ if (delta < Config.SpinThreshold) // not so much time left, just spin
+ continue;
+
+ if (MonCounters) {
+ ++*MonCounters->Sleeps;
+ }
+
+ NanoSleep(delta * 1000); // ok, looks like we should sleep a bit.
+
+ // Don't count sleep in elapsed microseconds
+ hpprev = GetCycleCountFast();
+ nextTimestamp = TInstant::Now().MicroSeconds();
+ nextMonotonic = Max(currentMonotonic, GetMonotonicMicroSeconds());
+ }
+ }
+ // ok, die!
+ }
+
+ void TBasicSchedulerThread::Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) {
+ ActorSystem = actorSystem;
+ CurrentTimestamp = currentTimestamp;
+ CurrentMonotonic = currentMonotonic;
+ *CurrentTimestamp = TInstant::Now().MicroSeconds();
+ *CurrentMonotonic = GetMonotonicMicroSeconds();
+ }
+
+ void TBasicSchedulerThread::PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) {
+ Y_VERIFY(scheduleReadersCount > 0);
+ TotalReaders = scheduleReadersCount;
+ Readers.Reset(new NSchedulerQueue::TReader*[scheduleReadersCount]);
+ Copy(readers, readers + scheduleReadersCount, Readers.Get());
+ }
+
+ void TBasicSchedulerThread::PrepareStart() {
+ // Called after actor system is initialized, but before executor threads
+ // are started, giving us a chance to update current timestamp with a
+ // more recent value, taking initialization time into account. This is
+ // safe to do, since scheduler thread is not started yet, so no other
+ // threads are updating time concurrently.
+ AtomicStore(CurrentTimestamp, TInstant::Now().MicroSeconds());
+ AtomicStore(CurrentMonotonic, Max(RelaxedLoad(CurrentMonotonic), GetMonotonicMicroSeconds()));
+ }
+
+ void TBasicSchedulerThread::Start() {
+ MainCycle.Reset(new NThreading::TLegacyFuture<void, false>(std::bind(&TBasicSchedulerThread::CycleFunc, this)));
+ }
+
+ void TBasicSchedulerThread::PrepareStop() {
+ AtomicStore(&StopFlag, true);
+ }
+
+ void TBasicSchedulerThread::Stop() {
+ MainCycle->Get();
+ MainCycle.Destroy();
+ }
+
+}
+
+#ifdef __linux__
+
+namespace NActors {
+ ISchedulerThread* CreateSchedulerThread(const TSchedulerConfig& config) {
+ if (config.UseSchedulerActor) {
+ return new TMockSchedulerThread();
+ } else {
+ return new TBasicSchedulerThread(config);
+ }
+ }
+
+}
+
+#else // __linux__
+
+namespace NActors {
+ ISchedulerThread* CreateSchedulerThread(const TSchedulerConfig& config) {
+ return new TBasicSchedulerThread(config);
+ }
+}
+
+#endif // __linux__
diff --git a/library/cpp/actors/core/scheduler_basic.h b/library/cpp/actors/core/scheduler_basic.h
new file mode 100644
index 0000000000..2ccde39235
--- /dev/null
+++ b/library/cpp/actors/core/scheduler_basic.h
@@ -0,0 +1,81 @@
+#pragma once
+
+#include "actorsystem.h"
+#include "monotonic.h"
+#include "scheduler_queue.h"
+#include <library/cpp/actors/util/queue_chunk.h>
+#include <library/cpp/threading/future/legacy_future.h>
+#include <util/generic/hash.h>
+#include <util/generic/map.h>
+
+namespace NActors {
+
+ class TBasicSchedulerThread: public ISchedulerThread {
+ // TODO: replace with NUMA-local threads and per-thread schedules
+ const TSchedulerConfig Config;
+
+ struct TMonCounters;
+ const THolder<TMonCounters> MonCounters;
+
+ TActorSystem* ActorSystem;
+ volatile ui64* CurrentTimestamp;
+ volatile ui64* CurrentMonotonic;
+
+ ui32 TotalReaders;
+ TArrayHolder<NSchedulerQueue::TReader*> Readers;
+
+ volatile bool StopFlag;
+
+ typedef TMap<ui64, TAutoPtr<NSchedulerQueue::TQueueType>> TMomentMap; // intrasecond queues
+ typedef THashMap<ui64, TAutoPtr<TMomentMap>> TScheduleMap; // over-second schedule
+
+ TScheduleMap ScheduleMap;
+
+ THolder<NThreading::TLegacyFuture<void, false>> MainCycle;
+
+ static const ui64 IntrasecondThreshold = 1048576; // ~second
+
+ void CycleFunc();
+
+ public:
+ TBasicSchedulerThread(const TSchedulerConfig& config = TSchedulerConfig());
+ ~TBasicSchedulerThread();
+
+ void Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) override;
+ void PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) override;
+
+ void PrepareStart() override;
+ void Start() override;
+ void PrepareStop() override;
+ void Stop() override;
+ };
+
+ class TMockSchedulerThread: public ISchedulerThread {
+ public:
+ virtual ~TMockSchedulerThread() override {
+ }
+
+ void Prepare(TActorSystem* actorSystem, volatile ui64* currentTimestamp, volatile ui64* currentMonotonic) override {
+ Y_UNUSED(actorSystem);
+ *currentTimestamp = TInstant::Now().MicroSeconds();
+ *currentMonotonic = GetMonotonicMicroSeconds();
+ }
+
+ void PrepareSchedules(NSchedulerQueue::TReader** readers, ui32 scheduleReadersCount) override {
+ Y_UNUSED(readers);
+ Y_UNUSED(scheduleReadersCount);
+ }
+
+ void Start() override {
+ }
+
+ void PrepareStop() override {
+ }
+
+ void Stop() override {
+ }
+ };
+
+ ISchedulerThread* CreateSchedulerThread(const TSchedulerConfig& cfg);
+
+}
diff --git a/library/cpp/actors/core/scheduler_cookie.cpp b/library/cpp/actors/core/scheduler_cookie.cpp
new file mode 100644
index 0000000000..0fa6f543a7
--- /dev/null
+++ b/library/cpp/actors/core/scheduler_cookie.cpp
@@ -0,0 +1,84 @@
+#include "scheduler_cookie.h"
+
+namespace NActors {
+ class TSchedulerCookie2Way: public ISchedulerCookie {
+ TAtomic Value;
+
+ public:
+ TSchedulerCookie2Way()
+ : Value(2)
+ {
+ }
+
+ bool IsArmed() noexcept override {
+ return (AtomicGet(Value) == 2);
+ }
+
+ bool Detach() noexcept override {
+ const ui64 x = AtomicDecrement(Value);
+ if (x == 1)
+ return true;
+
+ if (x == 0) {
+ delete this;
+ return false;
+ }
+
+ Y_FAIL();
+ }
+
+ bool DetachEvent() noexcept override {
+ Y_FAIL();
+ }
+ };
+
+ ISchedulerCookie* ISchedulerCookie::Make2Way() {
+ return new TSchedulerCookie2Way();
+ }
+
+ class TSchedulerCookie3Way: public ISchedulerCookie {
+ TAtomic Value;
+
+ public:
+ TSchedulerCookie3Way()
+ : Value(3)
+ {
+ }
+
+ bool IsArmed() noexcept override {
+ return (AtomicGet(Value) == 3);
+ }
+
+ bool Detach() noexcept override {
+ const ui64 x = AtomicDecrement(Value);
+ if (x == 2)
+ return true;
+ if (x == 1)
+ return false;
+ if (x == 0) {
+ delete this;
+ return false;
+ }
+
+ Y_FAIL();
+ }
+
+ bool DetachEvent() noexcept override {
+ const ui64 x = AtomicDecrement(Value);
+ if (x == 2)
+ return false;
+ if (x == 1)
+ return true;
+ if (x == 0) {
+ delete this;
+ return false;
+ }
+
+ Y_FAIL();
+ }
+ };
+
+ ISchedulerCookie* ISchedulerCookie::Make3Way() {
+ return new TSchedulerCookie3Way();
+ }
+}
diff --git a/library/cpp/actors/core/scheduler_cookie.h b/library/cpp/actors/core/scheduler_cookie.h
new file mode 100644
index 0000000000..2c20ca67f3
--- /dev/null
+++ b/library/cpp/actors/core/scheduler_cookie.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include "defs.h"
+#include <util/generic/noncopyable.h>
+
+namespace NActors {
+ class ISchedulerCookie : TNonCopyable {
+ protected:
+ virtual ~ISchedulerCookie() {
+ }
+
+ public:
+ virtual bool Detach() noexcept = 0;
+ virtual bool DetachEvent() noexcept = 0;
+ virtual bool IsArmed() noexcept = 0;
+
+ static ISchedulerCookie* Make2Way();
+ static ISchedulerCookie* Make3Way();
+ };
+
+ class TSchedulerCookieHolder : TNonCopyable {
+ ISchedulerCookie* Cookie;
+
+ public:
+ TSchedulerCookieHolder()
+ : Cookie(nullptr)
+ {
+ }
+
+ TSchedulerCookieHolder(ISchedulerCookie* x)
+ : Cookie(x)
+ {
+ }
+
+ ~TSchedulerCookieHolder() {
+ Detach();
+ }
+
+ bool operator==(const TSchedulerCookieHolder& x) const noexcept {
+ return (Cookie == x.Cookie);
+ }
+
+ ISchedulerCookie* Get() const {
+ return Cookie;
+ }
+
+ ISchedulerCookie* Release() {
+ ISchedulerCookie* result = Cookie;
+ Cookie = nullptr;
+ return result;
+ }
+
+ void Reset(ISchedulerCookie* cookie) {
+ Detach();
+ Cookie = cookie;
+ }
+
+ bool Detach() noexcept {
+ if (Cookie) {
+ const bool res = Cookie->Detach();
+ Cookie = nullptr;
+ return res;
+ } else {
+ return false;
+ }
+ }
+
+ bool DetachEvent() noexcept {
+ if (Cookie) {
+ const bool res = Cookie->DetachEvent();
+ Cookie = nullptr;
+ return res;
+ } else {
+ return false;
+ }
+ }
+ };
+}
diff --git a/library/cpp/actors/core/scheduler_queue.h b/library/cpp/actors/core/scheduler_queue.h
new file mode 100644
index 0000000000..3b8fac28f0
--- /dev/null
+++ b/library/cpp/actors/core/scheduler_queue.h
@@ -0,0 +1,120 @@
+#pragma once
+
+#include <library/cpp/actors/util/queue_chunk.h>
+
+namespace NActors {
+ class IEventHandle;
+ class ISchedulerCookie;
+
+ namespace NSchedulerQueue {
+ struct TEntry {
+ ui64 InstantMicroseconds;
+ IEventHandle* Ev;
+ ISchedulerCookie* Cookie;
+ };
+
+ struct TChunk : TQueueChunkDerived<TEntry, 512, TChunk> {};
+
+ class TReader;
+ class TWriter;
+ class TWriterWithPadding;
+
+ class TReader : ::TNonCopyable {
+ TChunk* ReadFrom;
+ ui32 ReadPosition;
+
+ friend class TWriter;
+
+ public:
+ TReader()
+ : ReadFrom(new TChunk())
+ , ReadPosition(0)
+ {
+ }
+
+ ~TReader() {
+ while (TEntry* x = Pop()) {
+ if (x->Cookie)
+ x->Cookie->Detach();
+ delete x->Ev;
+ }
+ delete ReadFrom;
+ }
+
+ TEntry* Pop() {
+ TChunk* head = ReadFrom;
+ if (ReadPosition != TChunk::EntriesCount) {
+ if (AtomicLoad(&head->Entries[ReadPosition].InstantMicroseconds) != 0)
+ return const_cast<TEntry*>(&head->Entries[ReadPosition++]);
+ else
+ return nullptr;
+ } else if (TChunk* next = AtomicLoad(&head->Next)) {
+ ReadFrom = next;
+ delete head;
+ ReadPosition = 0;
+ return Pop();
+ }
+
+ return nullptr;
+ }
+ };
+
+ class TWriter : ::TNonCopyable {
+ TChunk* WriteTo;
+ ui32 WritePosition;
+
+ public:
+ TWriter()
+ : WriteTo(nullptr)
+ , WritePosition(0)
+ {
+ }
+
+ void Init(const TReader& reader) {
+ WriteTo = reader.ReadFrom;
+ WritePosition = 0;
+ }
+
+ void Push(ui64 instantMicrosends, IEventHandle* ev, ISchedulerCookie* cookie) {
+ if (Y_UNLIKELY(instantMicrosends == 0)) {
+ // Protect against Pop() getting stuck forever
+ instantMicrosends = 1;
+ }
+ if (WritePosition != TChunk::EntriesCount) {
+ volatile TEntry& entry = WriteTo->Entries[WritePosition];
+ entry.Cookie = cookie;
+ entry.Ev = ev;
+ AtomicStore(&entry.InstantMicroseconds, instantMicrosends);
+ ++WritePosition;
+ } else {
+ TChunk* next = new TChunk();
+ volatile TEntry& entry = next->Entries[0];
+ entry.Cookie = cookie;
+ entry.Ev = ev;
+ entry.InstantMicroseconds = instantMicrosends;
+ AtomicStore(&WriteTo->Next, next);
+ WriteTo = next;
+ WritePosition = 1;
+ }
+ }
+ };
+
+ class TWriterWithPadding: public TWriter {
+ private:
+ ui8 CacheLinePadding[64 - sizeof(TWriter)];
+
+ void UnusedCacheLinePadding() {
+ Y_UNUSED(CacheLinePadding);
+ }
+ };
+
+ struct TQueueType {
+ TReader Reader;
+ TWriter Writer;
+
+ TQueueType() {
+ Writer.Init(Reader);
+ }
+ };
+ }
+}
diff --git a/library/cpp/actors/core/servicemap.h b/library/cpp/actors/core/servicemap.h
new file mode 100644
index 0000000000..d72e50cae5
--- /dev/null
+++ b/library/cpp/actors/core/servicemap.h
@@ -0,0 +1,168 @@
+#pragma once
+
+#include "defs.h"
+
+namespace NActors {
+ // wait-free one writer multi reader hash-tree for service mapping purposes
+ // on fast updates on same key - could lead to false-negatives, we don't care as such cases are broken from service-map app logic
+
+ template <typename TKey, typename TValue, typename THash, ui64 BaseSize = 256 * 1024, ui64 ExtCount = 4, ui64 ExtBranching = 4>
+ class TServiceMap : TNonCopyable {
+ struct TEntry : TNonCopyable {
+ ui32 CounterIn;
+ ui32 CounterOut;
+ TKey Key;
+ TValue Value;
+
+ TEntry()
+ : CounterIn(0)
+ , CounterOut(0)
+ , Key()
+ , Value()
+ {
+ }
+ };
+
+ struct TBranch : TNonCopyable {
+ TEntry Entries[ExtCount];
+ TBranch* Branches[ExtBranching];
+
+ TBranch() {
+ Fill(Branches, Branches + ExtBranching, (TBranch*)nullptr);
+ }
+ };
+
+ ui32 Counter;
+ TBranch* Line[BaseSize];
+
+ bool ScanBranch(TBranch* branch, const TKey& key, ui64 hash, TValue& ret) {
+ for (ui32 i = 0; i != ExtCount; ++i) {
+ const TEntry& entry = branch->Entries[i];
+ const ui32 counterIn = AtomicLoad(&entry.CounterIn);
+ if (counterIn != 0 && entry.Key == key) {
+ ret = entry.Value;
+ const ui32 counterOut = AtomicLoad(&entry.CounterOut);
+ if (counterOut == counterIn)
+ return true;
+ }
+ }
+
+ const ui64 hash0 = hash % ExtBranching;
+ if (TBranch* next = AtomicLoad(branch->Branches + hash0))
+ return ScanBranch(next, key, hash / ExtBranching, ret);
+
+ return false;
+ }
+
+ void ScanZeroOld(TBranch* branch, const TKey& key, ui64 hash, TEntry** zeroEntry, TEntry*& oldEntry) {
+ for (ui32 i = 0; i != ExtCount; ++i) {
+ TEntry& entry = branch->Entries[i];
+ if (entry.CounterIn == 0) {
+ if (zeroEntry && !*zeroEntry) {
+ *zeroEntry = &entry;
+ if (oldEntry != nullptr)
+ return;
+ }
+ } else {
+ if (entry.Key == key) {
+ oldEntry = &entry;
+ if (!zeroEntry || *zeroEntry)
+ return;
+ }
+ }
+ }
+
+ const ui64 hash0 = hash % ExtBranching;
+ if (TBranch* next = branch->Branches[hash0]) {
+ ScanZeroOld(next, key, hash / ExtBranching, zeroEntry, oldEntry);
+ } else { // found tail, if zeroEntry requested, but not yet found - insert one
+ if (zeroEntry && !*zeroEntry) {
+ TBranch* next = new TBranch();
+ *zeroEntry = next->Entries;
+ AtomicStore(branch->Branches + hash0, next);
+ }
+ }
+ }
+
+ public:
+ TServiceMap()
+ : Counter(0)
+ {
+ Fill(Line, Line + BaseSize, (TBranch*)nullptr);
+ }
+
+ ~TServiceMap() {
+ for (ui64 i = 0; i < BaseSize; ++i) {
+ delete Line[i];
+ }
+ }
+
+ TValue Find(const TKey& key) {
+ THash hashOp;
+ const ui64 hash = hashOp(key);
+ const ui64 hash0 = hash % BaseSize;
+
+ if (TBranch* branch = AtomicLoad(Line + hash0)) {
+ TValue ret;
+ if (ScanBranch(branch, key, hash / BaseSize, ret))
+ return ret;
+ }
+
+ return TValue();
+ }
+
+ // returns true on update, false on insert
+ TValue Update(const TKey& key, const TValue& value) {
+ THash hashOp;
+ const ui64 hash = hashOp(key);
+ const ui64 hash0 = hash % BaseSize;
+
+ TEntry* zeroEntry = nullptr;
+ TEntry* oldEntry = nullptr;
+
+ if (TBranch* branch = Line[hash0]) {
+ ScanZeroOld(branch, key, hash / BaseSize, &zeroEntry, oldEntry);
+ } else {
+ TBranch* next = new TBranch();
+ zeroEntry = next->Entries;
+ AtomicStore(Line + hash0, next);
+ }
+
+ // now we got both entries, first - push new one
+ const ui32 counter = AtomicUi32Increment(&Counter);
+ AtomicStore(&zeroEntry->CounterOut, counter);
+ zeroEntry->Key = key;
+ zeroEntry->Value = value;
+ AtomicStore(&zeroEntry->CounterIn, counter);
+
+ if (oldEntry != nullptr) {
+ const TValue ret = oldEntry->Value;
+ AtomicStore<ui32>(&oldEntry->CounterOut, 0);
+ AtomicStore<ui32>(&oldEntry->CounterIn, 0);
+ return ret;
+ } else {
+ return TValue();
+ }
+ }
+
+ bool Erase(const TKey& key) {
+ THash hashOp;
+ const ui64 hash = hashOp(key);
+ const ui64 hash0 = hash % BaseSize;
+
+ TEntry* oldEntry = 0;
+
+ if (TBranch* branch = Line[hash0]) {
+ ScanZeroOld(branch, key, hash / BaseSize, 0, oldEntry);
+ }
+
+ if (oldEntry != 0) {
+ AtomicStore<ui32>(&oldEntry->CounterOut, 0);
+ AtomicStore<ui32>(&oldEntry->CounterIn, 0);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ };
+}
diff --git a/library/cpp/actors/core/ut/ya.make b/library/cpp/actors/core/ut/ya.make
new file mode 100644
index 0000000000..3ee28d5850
--- /dev/null
+++ b/library/cpp/actors/core/ut/ya.make
@@ -0,0 +1,46 @@
+UNITTEST_FOR(library/cpp/actors/core)
+
+OWNER(
+ alexvru
+ g:kikimr
+)
+
+FORK_SUBTESTS()
+IF (SANITIZER_TYPE)
+ SIZE(LARGE)
+ TIMEOUT(1200)
+ TAG(ya:fat)
+ SPLIT_FACTOR(20)
+ REQUIREMENTS(
+ ram:32
+ )
+ELSE()
+ SIZE(MEDIUM)
+ TIMEOUT(600)
+ REQUIREMENTS(
+ ram:16
+ )
+ENDIF()
+
+
+PEERDIR(
+ library/cpp/actors/interconnect
+ library/cpp/actors/testlib
+)
+
+SRCS(
+ actor_coroutine_ut.cpp
+ actor_ut.cpp
+ actorsystem_ut.cpp
+ ask_ut.cpp
+ balancer_ut.cpp
+ event_pb_payload_ut.cpp
+ event_pb_ut.cpp
+ executor_pool_basic_ut.cpp
+ executor_pool_united_ut.cpp
+ log_ut.cpp
+ memory_tracker_ut.cpp
+ scheduler_actor_ut.cpp
+)
+
+END()
diff --git a/library/cpp/actors/core/worker_context.cpp b/library/cpp/actors/core/worker_context.cpp
new file mode 100644
index 0000000000..ada6c997d4
--- /dev/null
+++ b/library/cpp/actors/core/worker_context.cpp
@@ -0,0 +1,7 @@
+#include "worker_context.h"
+#include "probes.h"
+
+namespace NActors {
+ LWTRACE_USING(ACTORLIB_PROVIDER);
+
+}
diff --git a/library/cpp/actors/core/worker_context.h b/library/cpp/actors/core/worker_context.h
new file mode 100644
index 0000000000..b4c37a7629
--- /dev/null
+++ b/library/cpp/actors/core/worker_context.h
@@ -0,0 +1,175 @@
+#pragma once
+
+#include "defs.h"
+
+#include "actorsystem.h"
+#include "event.h"
+#include "lease.h"
+#include "mailbox.h"
+#include "mon_stats.h"
+
+#include <library/cpp/actors/util/datetime.h>
+#include <library/cpp/actors/util/intrinsics.h>
+#include <library/cpp/actors/util/thread.h>
+
+#include <library/cpp/lwtrace/shuttle.h>
+
+namespace NActors {
+ struct TWorkerContext {
+ const TWorkerId WorkerId;
+ const TCpuId CpuId;
+ TLease Lease;
+ IExecutorPool* Executor = nullptr;
+ TMailboxTable* MailboxTable = nullptr;
+ ui64 TimePerMailboxTs = 0;
+ ui32 EventsPerMailbox = 0;
+ ui64 SoftDeadlineTs = ui64(-1);
+ TExecutorThreadStats* Stats = &WorkerStats; // pool stats
+ TExecutorThreadStats WorkerStats;
+ TPoolId PoolId = MaxPools;
+ mutable NLWTrace::TOrbit Orbit;
+
+ TWorkerContext(TWorkerId workerId, TCpuId cpuId, size_t activityVecSize)
+ : WorkerId(workerId)
+ , CpuId(cpuId)
+ , Lease(WorkerId, NeverExpire)
+ , WorkerStats(activityVecSize)
+ {}
+
+#ifdef ACTORSLIB_COLLECT_EXEC_STATS
+ void GetCurrentStats(TExecutorThreadStats& statsCopy) const {
+ statsCopy = TExecutorThreadStats();
+ statsCopy.Aggregate(*Stats);
+ }
+
+ void AddElapsedCycles(ui32 activityType, i64 elapsed) {
+ Y_VERIFY_DEBUG(activityType < Stats->MaxActivityType());
+ RelaxedStore(&Stats->ElapsedTicks, RelaxedLoad(&Stats->ElapsedTicks) + elapsed);
+ RelaxedStore(&Stats->ElapsedTicksByActivity[activityType], RelaxedLoad(&Stats->ElapsedTicksByActivity[activityType]) + elapsed);
+ }
+
+ void AddParkedCycles(i64 elapsed) {
+ RelaxedStore(&Stats->ParkedTicks, RelaxedLoad(&Stats->ParkedTicks) + elapsed);
+ }
+
+ void AddBlockedCycles(i64 elapsed) {
+ RelaxedStore(&Stats->BlockedTicks, RelaxedLoad(&Stats->BlockedTicks) + elapsed);
+ }
+
+ void IncrementSentEvents() {
+ RelaxedStore(&Stats->SentEvents, RelaxedLoad(&Stats->SentEvents) + 1);
+ }
+
+ void IncrementPreemptedEvents() {
+ RelaxedStore(&Stats->PreemptedEvents, RelaxedLoad(&Stats->PreemptedEvents) + 1);
+ }
+
+ void DecrementActorsAliveByActivity(ui32 activityType) {
+ if (activityType >= Stats->MaxActivityType()) {
+ activityType = 0;
+ }
+ RelaxedStore(&Stats->ActorsAliveByActivity[activityType], Stats->ActorsAliveByActivity[activityType] - 1);
+ }
+
+ inline void IncrementNonDeliveredEvents() {
+ RelaxedStore(&Stats->NonDeliveredEvents, RelaxedLoad(&Stats->NonDeliveredEvents) + 1);
+ }
+
+ inline void IncrementMailboxPushedOutBySoftPreemption() {
+ RelaxedStore(&Stats->MailboxPushedOutBySoftPreemption, RelaxedLoad(&Stats->MailboxPushedOutBySoftPreemption) + 1);
+ }
+
+ inline void IncrementMailboxPushedOutByTime() {
+ RelaxedStore(&Stats->MailboxPushedOutByTime, RelaxedLoad(&Stats->MailboxPushedOutByTime) + 1);
+ }
+
+ inline void IncrementMailboxPushedOutByEventCount() {
+ RelaxedStore(&Stats->MailboxPushedOutByEventCount, RelaxedLoad(&Stats->MailboxPushedOutByEventCount) + 1);
+ }
+
+ inline void IncrementEmptyMailboxActivation() {
+ RelaxedStore(&Stats->EmptyMailboxActivation, RelaxedLoad(&Stats->EmptyMailboxActivation) + 1);
+ }
+
+ double AddActivationStats(i64 scheduleTs, i64 deliveredTs) {
+ i64 ts = deliveredTs > scheduleTs ? deliveredTs - scheduleTs : 0;
+ double usec = NHPTimer::GetSeconds(ts) * 1000000.0;
+ Stats->ActivationTimeHistogram.Add(usec);
+ return usec;
+ }
+
+ ui64 AddEventDeliveryStats(i64 sentTs, i64 deliveredTs) {
+ ui64 usecDeliv = deliveredTs > sentTs ? NHPTimer::GetSeconds(deliveredTs - sentTs) * 1000000 : 0;
+ Stats->EventDeliveryTimeHistogram.Add(usecDeliv);
+ return usecDeliv;
+ }
+
+ i64 AddEventProcessingStats(i64 deliveredTs, i64 processedTs, ui32 activityType, ui64 scheduled) {
+ i64 elapsed = processedTs - deliveredTs;
+ ui64 usecElapsed = NHPTimer::GetSeconds(elapsed) * 1000000;
+ activityType = (activityType >= Stats->MaxActivityType()) ? 0 : activityType;
+ Stats->EventProcessingCountHistogram.Add(usecElapsed);
+ Stats->EventProcessingTimeHistogram.Add(usecElapsed, elapsed);
+ RelaxedStore(&Stats->ReceivedEvents, RelaxedLoad(&Stats->ReceivedEvents) + 1);
+ RelaxedStore(&Stats->ReceivedEventsByActivity[activityType], RelaxedLoad(&Stats->ReceivedEventsByActivity[activityType]) + 1);
+ RelaxedStore(&Stats->ScheduledEventsByActivity[activityType], RelaxedLoad(&Stats->ScheduledEventsByActivity[activityType]) + scheduled);
+ AddElapsedCycles(activityType, elapsed);
+ return elapsed;
+ }
+
+ void UpdateActorsStats(size_t dyingActorsCnt) {
+ if (dyingActorsCnt) {
+ AtomicAdd(Executor->DestroyedActors, dyingActorsCnt);
+ }
+ RelaxedStore(&Stats->PoolDestroyedActors, (ui64)RelaxedLoad(&Executor->DestroyedActors));
+ RelaxedStore(&Stats->PoolActorRegistrations, (ui64)RelaxedLoad(&Executor->ActorRegistrations));
+ RelaxedStore(&Stats->PoolAllocatedMailboxes, MailboxTable->GetAllocatedMailboxCount());
+ }
+
+ void UpdateThreadTime() {
+ RelaxedStore(&WorkerStats.CpuNs, ThreadCPUTime() * 1000);
+ }
+#else
+ void GetCurrentStats(TExecutorThreadStats&) const {}
+ inline void AddElapsedCycles(ui32, i64) {}
+ inline void AddParkedCycles(i64) {}
+ inline void AddBlockedCycles(i64) {}
+ inline void IncrementSentEvents() {}
+ inline void IncrementPreemptedEvents() {}
+ inline void IncrementMailboxPushedOutBySoftPreemption() {}
+ inline void IncrementMailboxPushedOutByTime() {}
+ inline void IncrementMailboxPushedOutByEventCount() {}
+ inline void IncrementEmptyMailboxActivation() {}
+ void DecrementActorsAliveByActivity(ui32) {}
+ void IncrementNonDeliveredEvents() {}
+ double AddActivationStats(i64, i64) { return 0; }
+ ui64 AddEventDeliveryStats(i64, i64) { return 0; }
+ i64 AddEventProcessingStats(i64, i64, ui32, ui64) { return 0; }
+ void UpdateActorsStats(size_t, IExecutorPool*) {}
+ void UpdateThreadTime() {}
+#endif
+
+ void Switch(IExecutorPool* executor,
+ TMailboxTable* mailboxTable,
+ ui64 timePerMailboxTs,
+ ui32 eventsPerMailbox,
+ ui64 softDeadlineTs,
+ TExecutorThreadStats* stats)
+ {
+ Executor = executor;
+ MailboxTable = mailboxTable;
+ TimePerMailboxTs = timePerMailboxTs;
+ EventsPerMailbox = eventsPerMailbox;
+ SoftDeadlineTs = softDeadlineTs;
+ Stats = stats;
+ PoolId = Executor ? Executor->PoolId : MaxPools;
+ }
+
+ void SwitchToIdle() {
+ Executor = nullptr;
+ MailboxTable = nullptr;
+ //Stats = &WorkerStats; // TODO: in actorsystem 2.0 idle stats cannot be related to specific pool
+ PoolId = MaxPools;
+ }
+ };
+}
diff --git a/library/cpp/actors/core/ya.make b/library/cpp/actors/core/ya.make
new file mode 100644
index 0000000000..880a9d00db
--- /dev/null
+++ b/library/cpp/actors/core/ya.make
@@ -0,0 +1,123 @@
+LIBRARY()
+
+OWNER(
+ ddoarn
+ g:kikimr
+)
+
+NO_WSHADOW()
+
+IF (PROFILE_MEMORY_ALLOCATIONS)
+ CFLAGS(-DPROFILE_MEMORY_ALLOCATIONS)
+ENDIF()
+
+IF (ALLOCATOR == "B" OR ALLOCATOR == "BS" OR ALLOCATOR == "C")
+ CXXFLAGS(-DBALLOC)
+ PEERDIR(
+ library/cpp/balloc/optional
+ )
+ENDIF()
+
+SRCS(
+ actor_bootstrapped.h
+ actor_coroutine.cpp
+ actor_coroutine.h
+ actor.cpp
+ actor.h
+ actorid.cpp
+ actorid.h
+ actorsystem.cpp
+ actorsystem.h
+ ask.cpp
+ ask.h
+ balancer.h
+ balancer.cpp
+ buffer.cpp
+ buffer.h
+ callstack.cpp
+ callstack.h
+ config.h
+ cpu_manager.cpp
+ cpu_manager.h
+ cpu_state.h
+ defs.h
+ event.cpp
+ event.h
+ event_load.h
+ event_local.h
+ event_pb.cpp
+ event_pb.h
+ events.h
+ events_undelivered.cpp
+ executelater.h
+ executor_pool_base.cpp
+ executor_pool_base.h
+ executor_pool_basic.cpp
+ executor_pool_basic.h
+ executor_pool_io.cpp
+ executor_pool_io.h
+ executor_pool_united.cpp
+ executor_pool_united.h
+ executor_thread.cpp
+ executor_thread.h
+ hfunc.h
+ interconnect.cpp
+ interconnect.h
+ invoke.h
+ io_dispatcher.cpp
+ io_dispatcher.h
+ lease.h
+ log.cpp
+ log.h
+ log_settings.cpp
+ log_settings.h
+ mailbox.cpp
+ mailbox.h
+ mailbox_queue_revolving.h
+ mailbox_queue_simple.h
+ memory_track.cpp
+ memory_track.h
+ memory_tracker.cpp
+ memory_tracker.h
+ mon.h
+ mon_stats.h
+ monotonic.cpp
+ monotonic.h
+ worker_context.cpp
+ worker_context.h
+ probes.cpp
+ probes.h
+ process_stats.cpp
+ process_stats.h
+ scheduler_actor.cpp
+ scheduler_actor.h
+ scheduler_basic.cpp
+ scheduler_basic.h
+ scheduler_cookie.cpp
+ scheduler_cookie.h
+ scheduler_queue.h
+ servicemap.h
+)
+
+GENERATE_ENUM_SERIALIZATION(defs.h)
+GENERATE_ENUM_SERIALIZATION(actor.h)
+
+PEERDIR(
+ library/cpp/actors/memory_log
+ library/cpp/actors/prof
+ library/cpp/actors/protos
+ library/cpp/actors/util
+ library/cpp/execprofile
+ library/cpp/json/writer
+ library/cpp/logger
+ library/cpp/lwtrace
+ library/cpp/monlib/dynamic_counters
+ library/cpp/svnversion
+ library/cpp/threading/future
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ ut
+)
diff --git a/library/cpp/actors/dnscachelib/dnscache.cpp b/library/cpp/actors/dnscachelib/dnscache.cpp
new file mode 100644
index 0000000000..649339ddb2
--- /dev/null
+++ b/library/cpp/actors/dnscachelib/dnscache.cpp
@@ -0,0 +1,445 @@
+#include "dnscache.h"
+#include "probes.h"
+#include "timekeeper.h"
+
+#include <contrib/libs/c-ares/ares.h>
+#include <util/system/guard.h>
+#include <util/datetime/systime.h>
+
+const TDnsCache::THost TDnsCache::NullHost;
+
+LWTRACE_USING(DNSCACHELIB_PROVIDER);
+
+static_assert(sizeof(ares_channel) == sizeof(void*), "expect sizeof(ares_channel) == sizeof(void *)");
+
+TDnsCache::TDnsCache(bool allowIpv4, bool allowIpv6, time_t lifetime, time_t neg, ui32 timeout)
+ : EntryLifetime(lifetime)
+ , NegativeLifetime(neg)
+ , Timeout(TDuration::MicroSeconds(timeout))
+ , AllowIpV4(allowIpv4)
+ , AllowIpV6(allowIpv6)
+ , ACacheHits(0)
+ , ACacheMisses(0)
+ , PtrCacheHits(0)
+ , PtrCacheMisses(0)
+{
+#ifdef _win_
+ if (ares_library_init(ARES_LIB_INIT_WIN32) != ARES_SUCCESS) {
+ LWPROBE(AresInitFailed);
+ ythrow yexception() << "ares_init() failed";
+ }
+#endif
+
+ ares_channel chan;
+
+ if (ares_init(&chan) != ARES_SUCCESS) {
+ LWPROBE(AresInitFailed);
+ ythrow yexception() << "ares_init() failed";
+ }
+ Channel = chan;
+ LWPROBE(Created);
+}
+
+TDnsCache::~TDnsCache(void) {
+ ares_channel chan = static_cast<ares_channel>(Channel);
+
+ ares_cancel(chan);
+ ares_destroy(chan);
+ LWPROBE(Destroyed);
+
+#ifdef _win_
+ ares_library_cleanup();
+#endif
+}
+
+TString TDnsCache::GetHostByAddr(const NAddr::IRemoteAddr& addr) {
+ in6_addr key;
+
+ if (addr.Addr()->sa_family == AF_INET6) {
+ const struct sockaddr_in6* s6 = (const struct sockaddr_in6*)(addr.Addr());
+ memcpy(&key, &s6->sin6_addr, sizeof(s6->sin6_addr));
+ } else if (addr.Addr()->sa_family == AF_INET) {
+ const struct sockaddr_in* s4 = (const struct sockaddr_in*)(addr.Addr());
+ memset(&key, 0, sizeof(key));
+ memcpy(&key, &s4->sin_addr, sizeof(s4->sin_addr));
+ } else {
+ return "";
+ }
+ const TAddr& host = ResolveAddr(key, addr.Addr()->sa_family);
+
+ return host.Hostname;
+}
+
+TIpHost TDnsCache::Get(const TString& hostname) {
+ if (!AllowIpV4)
+ return TIpHost(-1);
+
+ const THost& addr = Resolve(hostname, AF_INET);
+
+ TGuard<TMutex> lock(CacheMtx);
+ if (addr.AddrsV4.empty()) {
+ return TIpHost(-1);
+ }
+ return addr.AddrsV4.front();
+}
+
+NAddr::IRemoteAddrPtr TDnsCache::GetAddr(
+ const TString& hostname,
+ int family,
+ TIpPort port,
+ bool cacheOnly) {
+ if (family != AF_INET && AllowIpV6) {
+ const THost& addr = Resolve(hostname, AF_INET6, cacheOnly);
+
+ TGuard<TMutex> lock(CacheMtx);
+ if (!addr.AddrsV6.empty()) {
+ struct sockaddr_in6 sin6;
+ Zero(sin6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = addr.AddrsV6.front();
+ sin6.sin6_port = HostToInet(port);
+
+ return MakeHolder<NAddr::TIPv6Addr>(sin6);
+ }
+ }
+
+ if (family != AF_INET6 && AllowIpV4) {
+ const THost& addr = Resolve(hostname, AF_INET, cacheOnly);
+
+ TGuard<TMutex> lock(CacheMtx);
+ if (!addr.AddrsV4.empty()) {
+ return MakeHolder<NAddr::TIPv4Addr>(TIpAddress(addr.AddrsV4.front(), port));
+ }
+ }
+
+ LWPROBE(FamilyMismatch, family, AllowIpV4, AllowIpV6);
+ return nullptr;
+}
+
+void TDnsCache::GetAllAddresses(
+ const TString& hostname,
+ TVector<NAddr::IRemoteAddrPtr>& addrs) {
+ if (AllowIpV4) {
+ const THost& addr4 = Resolve(hostname, AF_INET);
+
+ TGuard<TMutex> lock(CacheMtx);
+ for (size_t i = 0; i < addr4.AddrsV4.size(); i++) {
+ addrs.push_back(MakeHolder<NAddr::TIPv4Addr>(TIpAddress(addr4.AddrsV4[i], 0)));
+ }
+ }
+
+ if (AllowIpV6) {
+ const THost& addr6 = Resolve(hostname, AF_INET6);
+
+ struct sockaddr_in6 sin6;
+ Zero(sin6);
+ sin6.sin6_family = AF_INET6;
+
+ TGuard<TMutex> lock(CacheMtx);
+ for (size_t i = 0; i < addr6.AddrsV6.size(); i++) {
+ sin6.sin6_addr = addr6.AddrsV6[i];
+
+ addrs.push_back(MakeHolder<NAddr::TIPv6Addr>(sin6));
+ }
+ }
+}
+
+void TDnsCache::GetStats(ui64& a_cache_hits, ui64& a_cache_misses,
+ ui64& ptr_cache_hits, ui64& ptr_cache_misses) {
+ TGuard<TMutex> lock(CacheMtx);
+
+ a_cache_hits = ACacheHits;
+ a_cache_misses = ACacheMisses;
+ ptr_cache_hits = PtrCacheHits;
+ ptr_cache_misses = PtrCacheMisses;
+}
+
+bool TDnsCache::THost::IsStale(int family, const TDnsCache* ctx) const noexcept {
+ time_t resolved = family == AF_INET ? ResolvedV4 : ResolvedV6;
+ time_t notfound = family == AF_INET ? NotFoundV4 : NotFoundV6;
+
+ if (TTimeKeeper::GetTime() - resolved < ctx->EntryLifetime)
+ return false;
+
+ if (TTimeKeeper::GetTime() - notfound < ctx->NegativeLifetime)
+ return false;
+
+ return true;
+}
+
+const TDnsCache::THost&
+TDnsCache::Resolve(const TString& hostname, int family, bool cacheOnly) {
+ if (!ValidateHName(hostname)) {
+ LWPROBE(ResolveNullHost, hostname, family);
+ return NullHost;
+ }
+
+ THostCache::iterator p;
+
+ Y_ASSERT(family == AF_INET || family == AF_INET6);
+
+ {
+ TGuard<TMutex> lock(CacheMtx);
+ p = HostCache.find(hostname);
+ if (p != HostCache.end()) {
+ if (!p->second.IsStale(family, this)) {
+ /* Recently resolved, just return cached value */
+ ACacheHits += 1;
+ THost& host = p->second;
+ LWPROBE(ResolveFromCache, hostname, family, host.AddrsV4ToString(), host.AddrsV6ToString(), ACacheHits);
+ return host;
+ } else {
+ LWPROBE(ResolveCacheTimeout, hostname);
+ }
+ } else {
+ /* Never resolved, create cache entry */
+ LWPROBE(ResolveCacheNew, hostname);
+ p = HostCache.insert(std::make_pair(hostname, THost())).first;
+ }
+ ACacheMisses += 1;
+ }
+
+ if (cacheOnly)
+ return NullHost;
+
+ TAtomic& inprogress = (family == AF_INET ? p->second.InProgressV4 : p->second.InProgressV6);
+
+ {
+ /* This way only! CacheMtx should always be taken AFTER AresMtx,
+ * because later in ares_process it can only be done this way.
+ * Lock order reversal will cause deadlock in unfortunate monents.
+ */
+ TGuard<TMutex> areslock(AresMtx);
+ TGuard<TMutex> cachelock(CacheMtx);
+
+ if (!inprogress) {
+ ares_channel chan = static_cast<ares_channel>(Channel);
+ TGHBNContext* ctx = new TGHBNContext();
+ ctx->Owner = this;
+ ctx->Hostname = hostname;
+ ctx->Family = family;
+
+ AtomicSet(inprogress, 1);
+ ares_gethostbyname(chan, hostname.c_str(), family,
+ &TDnsCache::GHBNCallback, ctx);
+ }
+ }
+
+ WaitTask(inprogress);
+
+ LWPROBE(ResolveDone, hostname, family, p->second.AddrsV4ToString(), p->second.AddrsV6ToString());
+ return p->second;
+}
+
+bool TDnsCache::ValidateHName(const TString& name) const noexcept {
+ return name.size() > 0;
+}
+
+const TDnsCache::TAddr& TDnsCache::ResolveAddr(const in6_addr& addr, int family) {
+ TAddrCache::iterator p;
+
+ {
+ TGuard<TMutex> lock(CacheMtx);
+ p = AddrCache.find(addr);
+ if (p != AddrCache.end()) {
+ if (TTimeKeeper::GetTime() - p->second.Resolved < EntryLifetime || TTimeKeeper::GetTime() - p->second.NotFound < NegativeLifetime) {
+ /* Recently resolved, just return cached value */
+ PtrCacheHits += 1;
+ return p->second;
+ }
+ } else {
+ /* Never resolved, create cache entry */
+
+ p = AddrCache.insert(std::make_pair(addr, TAddr())).first;
+ }
+ PtrCacheMisses += 1;
+ }
+
+ {
+ /* This way only! CacheMtx should always be taken AFTER AresMtx,
+ * because later in ares_process it can only be done this way.
+ * Lock order reversal will cause deadlock in unfortunate monents.
+ */
+ TGuard<TMutex> areslock(AresMtx);
+ TGuard<TMutex> cachelock(CacheMtx);
+
+ if (!p->second.InProgress) {
+ ares_channel chan = static_cast<ares_channel>(Channel);
+ TGHBAContext* ctx = new TGHBAContext();
+ ctx->Owner = this;
+ ctx->Addr = addr;
+
+ AtomicSet(p->second.InProgress, 1);
+ ares_gethostbyaddr(chan, &addr,
+ family == AF_INET ? sizeof(in_addr) : sizeof(in6_addr),
+ family, &TDnsCache::GHBACallback, ctx);
+ }
+ }
+
+ WaitTask(p->second.InProgress);
+
+ return p->second;
+}
+
+void TDnsCache::WaitTask(TAtomic& flag) {
+ const TInstant start = TInstant(TTimeKeeper::GetTimeval());
+
+ while (AtomicGet(flag)) {
+ ares_channel chan = static_cast<ares_channel>(Channel);
+
+ struct pollfd pfd[ARES_GETSOCK_MAXNUM];
+ int nfds;
+ ares_socket_t socks[ARES_GETSOCK_MAXNUM];
+ int bits;
+
+ {
+ TGuard<TMutex> lock(AresMtx);
+ bits = ares_getsock(chan, socks, ARES_GETSOCK_MAXNUM);
+ if (bits == 0) {
+ /* other thread did our job */
+ continue;
+ }
+ }
+
+ for (nfds = 0; nfds < ARES_GETSOCK_MAXNUM; nfds++) {
+ pfd[nfds].events = 0;
+ pfd[nfds].revents = 0;
+ if (ARES_GETSOCK_READABLE(bits, nfds)) {
+ pfd[nfds].fd = socks[nfds];
+ pfd[nfds].events |= POLLRDNORM | POLLIN;
+ }
+ if (ARES_GETSOCK_WRITABLE(bits, nfds)) {
+ pfd[nfds].fd = socks[nfds];
+ pfd[nfds].events |= POLLWRNORM | POLLOUT;
+ }
+ if (pfd[nfds].events == 0) {
+ break;
+ }
+ }
+
+ Y_ASSERT(nfds != 0);
+
+ const TDuration left = TInstant(TTimeKeeper::GetTimeval()) - start;
+ const TDuration wait = Max(Timeout - left, TDuration::Zero());
+
+ int rv = poll(pfd, nfds, wait.MilliSeconds());
+
+ if (rv == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ /* Unknown error in select, can't recover. Just pretend there was no reply */
+ rv = 0;
+ }
+
+ if (rv == 0) {
+ /* poll() timed out */
+ TGuard<TMutex> lock(AresMtx);
+ ares_process_fd(chan, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
+ } else {
+ for (int i = 0; i < nfds; i++) {
+ if (pfd[i].revents == 0) {
+ continue;
+ }
+ TGuard<TMutex> lock(AresMtx);
+ ares_process_fd(chan,
+ pfd[i].revents & (POLLRDNORM | POLLIN)
+ ? pfd[i].fd
+ : ARES_SOCKET_BAD,
+ pfd[i].revents & (POLLWRNORM | POLLOUT)
+ ? pfd[i].fd
+ : ARES_SOCKET_BAD);
+ }
+ }
+
+ if (start + Timeout <= TInstant(TTimeKeeper::GetTimeval())) {
+ break;
+ }
+ }
+}
+
+void TDnsCache::GHBNCallback(void* arg, int status, int, struct hostent* info) {
+ THolder<TGHBNContext> ctx(static_cast<TGHBNContext*>(arg));
+ TGuard<TMutex> lock(ctx->Owner->CacheMtx);
+ THostCache::iterator p = ctx->Owner->HostCache.find(ctx->Hostname);
+
+ Y_ASSERT(p != ctx->Owner->HostCache.end());
+
+ time_t& resolved = (ctx->Family == AF_INET ? p->second.ResolvedV4 : p->second.ResolvedV6);
+ time_t& notfound = (ctx->Family == AF_INET ? p->second.NotFoundV4 : p->second.NotFoundV6);
+ TAtomic& inprogress = (ctx->Family == AF_INET ? p->second.InProgressV4 : p->second.InProgressV6);
+
+ if (status == ARES_SUCCESS) {
+ if (info->h_addrtype == AF_INET) {
+ p->second.AddrsV4.clear();
+ for (int i = 0; info->h_addr_list[i] != nullptr; i++) {
+ p->second.AddrsV4.push_back(*(TIpHost*)(info->h_addr_list[i]));
+ }
+ /* It is possible to ask ares for IPv6 and have IPv4 addrs instead,
+ so take care and set V4 timers anyway.
+ */
+ p->second.ResolvedV4 = TTimeKeeper::GetTime();
+ p->second.ResolvedV4 = 0;
+ AtomicSet(p->second.InProgressV4, 0);
+ } else if (info->h_addrtype == AF_INET6) {
+ p->second.AddrsV6.clear();
+ for (int i = 0; info->h_addr_list[i] != nullptr; i++) {
+ p->second.AddrsV6.push_back(*(struct in6_addr*)(info->h_addr_list[i]));
+ }
+ } else {
+ Y_FAIL("unknown address type in ares callback");
+ }
+ resolved = TTimeKeeper::GetTime();
+ notfound = 0;
+ } else {
+ notfound = TTimeKeeper::GetTime();
+ resolved = 0;
+ }
+ AtomicSet(inprogress, 0);
+}
+
+void TDnsCache::GHBACallback(void* arg, int status, int, struct hostent* info) {
+ THolder<TGHBAContext> ctx(static_cast<TGHBAContext*>(arg));
+ TGuard<TMutex> lock(ctx->Owner->CacheMtx);
+ TAddrCache::iterator p = ctx->Owner->AddrCache.find(ctx->Addr);
+
+ Y_ASSERT(p != ctx->Owner->AddrCache.end());
+
+ if (status == ARES_SUCCESS) {
+ p->second.Hostname = info->h_name;
+ p->second.Resolved = TTimeKeeper::GetTime();
+ p->second.NotFound = 0;
+ } else {
+ p->second.NotFound = TTimeKeeper::GetTime();
+ p->second.Resolved = 0;
+ }
+ AtomicSet(p->second.InProgress, 0);
+}
+
+TString TDnsCache::THost::AddrsV4ToString() const {
+ TStringStream ss;
+ bool first = false;
+ for (TIpHost addr : AddrsV4) {
+ ss << (first ? "" : " ") << IpToString(addr);
+ first = false;
+ }
+ return ss.Str();
+}
+
+TString TDnsCache::THost::AddrsV6ToString() const {
+ TStringStream ss;
+ bool first = false;
+ for (in6_addr addr : AddrsV6) {
+ struct sockaddr_in6 sin6;
+ Zero(sin6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = addr;
+
+ NAddr::TIPv6Addr addr6(sin6);
+ ss << (first ? "" : " ") << NAddr::PrintHost(addr6);
+ first = false;
+ }
+ return ss.Str();
+}
+
+TDnsCache::TAresLibInit TDnsCache::InitAresLib;
diff --git a/library/cpp/actors/dnscachelib/dnscache.h b/library/cpp/actors/dnscachelib/dnscache.h
new file mode 100644
index 0000000000..3313a251a1
--- /dev/null
+++ b/library/cpp/actors/dnscachelib/dnscache.h
@@ -0,0 +1,148 @@
+#pragma once
+
+#include <contrib/libs/c-ares/ares.h>
+#include <util/generic/map.h>
+#include <util/generic/vector.h>
+#include <util/network/address.h>
+#include <util/system/mutex.h>
+#include <util/datetime/base.h>
+
+/** Asynchronous DNS resolver.
+ *
+ * This is NOT general purpose resolver! It is designed with very specific assumptions:
+ * 1) there is relatively small and rarely changed set of resolved names (like, server pool in cluster)
+ * 2) this names supposed to have addresses, absense of A record is equal to DNS error
+ * 3) most of the time IP addresses do not change
+ * 4) it's OK to return old IP address when DNS server not responding in time
+ */
+
+class TDnsCache {
+public:
+ TDnsCache(bool allowIpv4 = true, bool allowIpv6 = true, time_t entry_lifetime = 1800, time_t neg_lifetime = 1, ui32 request_timeout = 500000);
+ ~TDnsCache();
+
+ TString GetHostByAddr(const NAddr::IRemoteAddr&);
+
+ // ip in network byte order
+ TIpHost Get(const TString& host);
+
+ /* use with AF_INET, AF_INET6 or AF_UNSPEC */
+ NAddr::IRemoteAddrPtr GetAddr(const TString& host,
+ int family,
+ TIpPort port = 0,
+ bool cacheOnly = false);
+
+ void GetAllAddresses(const TString& host, TVector<NAddr::IRemoteAddrPtr>&);
+
+ void GetStats(ui64& a_cache_hits, ui64& a_cache_misses,
+ ui64& ptr_cache_hits, ui64& ptr_cache_misses);
+
+protected:
+ bool ValidateHName(const TString& host) const noexcept;
+
+private:
+ struct TGHBNContext {
+ TDnsCache* Owner;
+ TString Hostname;
+ int Family;
+ };
+
+ struct TGHBAContext {
+ TDnsCache* Owner;
+ in6_addr Addr;
+ };
+
+ struct THost {
+ THost() noexcept {
+ }
+
+ TVector<TIpHost> AddrsV4;
+ time_t ResolvedV4 = 0;
+ time_t NotFoundV4 = 0;
+ TAtomic InProgressV4 = 0;
+
+ TVector<in6_addr> AddrsV6;
+ time_t ResolvedV6 = 0;
+ time_t NotFoundV6 = 0;
+ TAtomic InProgressV6 = 0;
+
+ TString AddrsV4ToString() const;
+ TString AddrsV6ToString() const;
+
+ bool IsStale(int family, const TDnsCache* ctx) const noexcept;
+ };
+
+ typedef TMap<TString, THost> THostCache;
+
+ struct TAddr {
+ TString Hostname;
+ time_t Resolved = 0;
+ time_t NotFound = 0;
+ TAtomic InProgress = 0;
+ };
+ /* IRemoteAddr is annoingly hard to use, so I'll use in6_addr as key
+ * and put v4 addrs in it.
+ */
+ struct TAddrCmp {
+ bool operator()(const in6_addr& left, const in6_addr& right) const {
+ for (size_t i = 0; i < sizeof(left); i++) {
+ if (left.s6_addr[i] < right.s6_addr[i]) {
+ return true;
+ } else if (left.s6_addr[i] > right.s6_addr[i]) {
+ return false;
+ }
+ }
+ // equal
+ return false;
+ }
+ };
+ typedef TMap<in6_addr, TAddr, TAddrCmp> TAddrCache;
+
+ const THost& Resolve(const TString&, int family, bool cacheOnly = false);
+
+ const TAddr& ResolveAddr(const in6_addr&, int family);
+
+ void WaitTask(TAtomic&);
+
+ static void GHBNCallback(void* arg, int status, int timeouts,
+ struct hostent* info);
+
+ static void GHBACallback(void* arg, int status, int timeouts,
+ struct hostent* info);
+
+ const time_t EntryLifetime;
+ const time_t NegativeLifetime;
+ const TDuration Timeout;
+ const bool AllowIpV4;
+ const bool AllowIpV6;
+
+ TMutex CacheMtx;
+ THostCache HostCache;
+ TAddrCache AddrCache;
+ ui64 ACacheHits;
+ ui64 ACacheMisses;
+ ui64 PtrCacheHits;
+ ui64 PtrCacheMisses;
+
+ const static THost NullHost;
+
+ TMutex AresMtx;
+ void* Channel;
+
+ struct TAresLibInit {
+ TAresLibInit() {
+#ifdef _win_
+ const auto res = ares_library_init(ARES_LIB_INIT_ALL);
+ Y_VERIFY(res == 0);
+#endif
+ }
+
+ ~TAresLibInit() {
+#ifdef _win_
+ ares_library_cleanup();
+#endif
+ }
+ };
+
+ static TAresLibInit InitAresLib;
+};
diff --git a/library/cpp/actors/dnscachelib/probes.cpp b/library/cpp/actors/dnscachelib/probes.cpp
new file mode 100644
index 0000000000..07734ab20f
--- /dev/null
+++ b/library/cpp/actors/dnscachelib/probes.cpp
@@ -0,0 +1,3 @@
+#include "probes.h"
+
+LWTRACE_DEFINE_PROVIDER(DNSCACHELIB_PROVIDER)
diff --git a/library/cpp/actors/dnscachelib/probes.h b/library/cpp/actors/dnscachelib/probes.h
new file mode 100644
index 0000000000..313b7b8712
--- /dev/null
+++ b/library/cpp/actors/dnscachelib/probes.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <library/cpp/lwtrace/all.h>
+
+#define DNSCACHELIB_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \
+ PROBE(Created, GROUPS(), TYPES(), NAMES()) \
+ PROBE(Destroyed, GROUPS(), TYPES(), NAMES()) \
+ PROBE(AresInitFailed, GROUPS(), TYPES(), NAMES()) \
+ PROBE(FamilyMismatch, \
+ GROUPS(), \
+ TYPES(int, bool, bool), \
+ NAMES("family", "allowIpV4", "allowIpV6")) \
+ PROBE(ResolveNullHost, \
+ GROUPS(), \
+ TYPES(TString, int), \
+ NAMES("hostname", "family")) \
+ PROBE(ResolveFromCache, \
+ GROUPS(), \
+ TYPES(TString, int, TString, TString, ui64), \
+ NAMES("hostname", "family", "addrsV4", "addrsV6", "aCacheHits")) \
+ PROBE(ResolveDone, \
+ GROUPS(), \
+ TYPES(TString, int, TString, TString), \
+ NAMES("hostname", "family", "addrsV4", "addrsV6")) \
+ PROBE(ResolveCacheTimeout, \
+ GROUPS(), \
+ TYPES(TString), \
+ NAMES("hostname")) \
+ PROBE(ResolveCacheNew, \
+ GROUPS(), \
+ TYPES(TString), \
+ NAMES("hostname")) \
+ /**/
+
+LWTRACE_DECLARE_PROVIDER(DNSCACHELIB_PROVIDER)
diff --git a/library/cpp/actors/dnscachelib/timekeeper.h b/library/cpp/actors/dnscachelib/timekeeper.h
new file mode 100644
index 0000000000..0528d8549c
--- /dev/null
+++ b/library/cpp/actors/dnscachelib/timekeeper.h
@@ -0,0 +1,70 @@
+#pragma once
+
+#include <util/datetime/base.h>
+#include <util/generic/singleton.h>
+#include <util/string/cast.h>
+#include <util/system/thread.h>
+#include <util/system/event.h>
+#include <util/system/env.h>
+
+#include <cstdlib>
+
+/* Keeps current time accurate up to 1/10 second */
+
+class TTimeKeeper {
+public:
+ static TInstant GetNow(void) {
+ return TInstant::MicroSeconds(GetTime());
+ }
+
+ static time_t GetTime(void) {
+ return Singleton<TTimeKeeper>()->CurrentTime.tv_sec;
+ }
+
+ static const struct timeval& GetTimeval(void) {
+ return Singleton<TTimeKeeper>()->CurrentTime;
+ }
+
+ TTimeKeeper()
+ : Thread(&TTimeKeeper::Worker, this)
+ {
+ ConstTime = !!GetEnv("TEST_TIME");
+ if (ConstTime) {
+ try {
+ CurrentTime.tv_sec = FromString<ui32>(GetEnv("TEST_TIME"));
+ } catch (TFromStringException exc) {
+ ConstTime = false;
+ }
+ }
+ if (!ConstTime) {
+ gettimeofday(&CurrentTime, nullptr);
+ Thread.Start();
+ }
+ }
+
+ ~TTimeKeeper() {
+ if (!ConstTime) {
+ Exit.Signal();
+ Thread.Join();
+ }
+ }
+
+private:
+ static const ui32 UpdateInterval = 100000;
+ struct timeval CurrentTime;
+ bool ConstTime;
+ TSystemEvent Exit;
+ TThread Thread;
+
+ static void* Worker(void* arg) {
+ TTimeKeeper* owner = static_cast<TTimeKeeper*>(arg);
+
+ do {
+ /* Race condition may occur here but locking looks too expensive */
+
+ gettimeofday(&owner->CurrentTime, nullptr);
+ } while (!owner->Exit.WaitT(TDuration::MicroSeconds(UpdateInterval)));
+
+ return nullptr;
+ }
+};
diff --git a/library/cpp/actors/dnscachelib/ya.make b/library/cpp/actors/dnscachelib/ya.make
new file mode 100644
index 0000000000..e3a6ad6202
--- /dev/null
+++ b/library/cpp/actors/dnscachelib/ya.make
@@ -0,0 +1,24 @@
+LIBRARY()
+
+OWNER(
+ davenger
+ fomichev
+ serxa
+ dimanne
+ single
+)
+
+SRCS(
+ dnscache.cpp
+ dnscache.h
+ probes.cpp
+ probes.h
+ timekeeper.h
+)
+
+PEERDIR(
+ contrib/libs/c-ares
+ library/cpp/lwtrace
+)
+
+END()
diff --git a/library/cpp/actors/dnsresolver/dnsresolver.cpp b/library/cpp/actors/dnsresolver/dnsresolver.cpp
new file mode 100644
index 0000000000..6329bb0083
--- /dev/null
+++ b/library/cpp/actors/dnsresolver/dnsresolver.cpp
@@ -0,0 +1,475 @@
+#include "dnsresolver.h"
+
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/threading/queue/mpsc_htswap.h>
+#include <util/network/pair.h>
+#include <util/network/socket.h>
+#include <util/string/builder.h>
+#include <util/system/thread.h>
+
+#include <ares.h>
+
+#include <atomic>
+
+namespace NActors {
+namespace NDnsResolver {
+
+ class TAresLibraryInitBase {
+ protected:
+ TAresLibraryInitBase() noexcept {
+ int status = ares_library_init(ARES_LIB_INIT_ALL);
+ Y_VERIFY(status == ARES_SUCCESS, "Unexpected failure to initialize c-ares library");
+ }
+
+ ~TAresLibraryInitBase() noexcept {
+ ares_library_cleanup();
+ }
+ };
+
+ class TCallbackQueueBase {
+ protected:
+ TCallbackQueueBase() noexcept {
+ int err = SocketPair(Sockets, false, true);
+ Y_VERIFY(err == 0, "Unexpected failure to create a socket pair");
+ SetNonBlock(Sockets[0]);
+ SetNonBlock(Sockets[1]);
+ }
+
+ ~TCallbackQueueBase() noexcept {
+ closesocket(Sockets[0]);
+ closesocket(Sockets[1]);
+ }
+
+ protected:
+ using TCallback = std::function<void()>;
+ using TCallbackQueue = NThreading::THTSwapQueue<TCallback>;
+
+ void PushCallback(TCallback callback) {
+ Y_VERIFY(callback, "Cannot push an empty callback");
+ CallbackQueue.Push(std::move(callback)); // this is a lockfree queue
+
+ // Wake up worker thread on the first activation
+ if (Activations.fetch_add(1, std::memory_order_acq_rel) == 0) {
+ char ch = 'x';
+ ssize_t ret;
+#ifdef _win_
+ ret = send(SignalSock(), &ch, 1, 0);
+ if (ret == -1) {
+ Y_VERIFY(WSAGetLastError() == WSAEWOULDBLOCK, "Unexpected send error");
+ return;
+ }
+#else
+ do {
+ ret = send(SignalSock(), &ch, 1, 0);
+ } while (ret == -1 && errno == EINTR);
+ if (ret == -1) {
+ Y_VERIFY(errno == EAGAIN || errno == EWOULDBLOCK, "Unexpected send error");
+ return;
+ }
+#endif
+ Y_VERIFY(ret == 1, "Unexpected send result");
+ }
+ }
+
+ void RunCallbacks() noexcept {
+ char ch[32];
+ ssize_t ret;
+ bool signalled = false;
+ for (;;) {
+ ret = recv(WaitSock(), ch, sizeof(ch), 0);
+ if (ret > 0) {
+ signalled = true;
+ }
+ if (ret == sizeof(ch)) {
+ continue;
+ }
+ if (ret != -1) {
+ break;
+ }
+#ifdef _win_
+ if (WSAGetLastError() == WSAEWOULDBLOCK) {
+ break;
+ }
+ Y_FAIL("Unexpected recv error");
+#else
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ break;
+ }
+ Y_VERIFY(errno == EINTR, "Unexpected recv error");
+#endif
+ }
+
+ if (signalled) {
+ // There's exactly one write to SignalSock while Activations != 0
+ // It's impossible to get signalled while Activations == 0
+ // We must set Activations = 0 to receive new signals
+ size_t count = Activations.exchange(0, std::memory_order_acq_rel);
+ Y_VERIFY(count != 0);
+
+ // N.B. due to the way HTSwap works we may not be able to pop
+ // all callbacks on this activation, however we expect a new
+ // delayed activation to happen at a later time.
+ while (auto callback = CallbackQueue.Pop()) {
+ callback();
+ }
+ }
+ }
+
+ SOCKET SignalSock() {
+ return Sockets[0];
+ }
+
+ SOCKET WaitSock() {
+ return Sockets[1];
+ }
+
+ private:
+ SOCKET Sockets[2];
+ TCallbackQueue CallbackQueue;
+ std::atomic<size_t> Activations{ 0 };
+ };
+
+ class TSimpleDnsResolver
+ : public TActor<TSimpleDnsResolver>
+ , private TAresLibraryInitBase
+ , private TCallbackQueueBase
+ {
+ public:
+ TSimpleDnsResolver(TSimpleDnsResolverOptions options) noexcept
+ : TActor(&TThis::StateWork)
+ , Options(std::move(options))
+ , WorkerThread(&TThis::WorkerThreadStart, this)
+ {
+ InitAres();
+
+ WorkerThread.Start();
+ }
+
+ ~TSimpleDnsResolver() noexcept override {
+ if (!Stopped) {
+ PushCallback([this] {
+ // Mark as stopped first
+ Stopped = true;
+
+ // Cancel all current ares requests (will not send replies)
+ ares_cancel(AresChannel);
+ });
+
+ WorkerThread.Join();
+ }
+
+ StopAres();
+ }
+
+ static constexpr EActivityType ActorActivityType() {
+ return DNS_RESOLVER;
+ }
+
+ private:
+ void InitAres() noexcept {
+ struct ares_options options;
+ memset(&options, 0, sizeof(options));
+ int optmask = 0;
+
+ options.flags = ARES_FLAG_STAYOPEN;
+ optmask |= ARES_OPT_FLAGS;
+
+ options.sock_state_cb = &TThis::SockStateCallback;
+ options.sock_state_cb_data = this;
+ optmask |= ARES_OPT_SOCK_STATE_CB;
+
+ options.timeout = Options.Timeout.MilliSeconds();
+ if (options.timeout > 0) {
+ optmask |= ARES_OPT_TIMEOUTMS;
+ }
+
+ options.tries = Options.Attempts;
+ if (options.tries > 0) {
+ optmask |= ARES_OPT_TRIES;
+ }
+
+ int err = ares_init_options(&AresChannel, &options, optmask);
+ Y_VERIFY(err == 0, "Unexpected failure to initialize c-ares channel");
+
+ if (Options.Servers) {
+ TStringBuilder csv;
+ for (const TString& server : Options.Servers) {
+ if (csv) {
+ csv << ',';
+ }
+ csv << server;
+ }
+ err = ares_set_servers_ports_csv(AresChannel, csv.c_str());
+ Y_VERIFY(err == 0, "Unexpected failure to set a list of dns servers: %s", ares_strerror(err));
+ }
+ }
+
+ void StopAres() noexcept {
+ // Destroy the ares channel
+ ares_destroy(AresChannel);
+ AresChannel = nullptr;
+ }
+
+ private:
+ STRICT_STFUNC(StateWork, {
+ hFunc(TEvents::TEvPoison, Handle);
+ hFunc(TEvDns::TEvGetHostByName, Handle);
+ hFunc(TEvDns::TEvGetAddr, Handle);
+ })
+
+ void Handle(TEvents::TEvPoison::TPtr&) {
+ Y_VERIFY(!Stopped);
+
+ PushCallback([this] {
+ // Cancel all current ares requests (will send notifications)
+ ares_cancel(AresChannel);
+
+ // Mark as stopped last
+ Stopped = true;
+ });
+
+ WorkerThread.Join();
+ PassAway();
+ }
+
+ private:
+ enum class ERequestType {
+ GetHostByName,
+ GetAddr,
+ };
+
+ struct TRequestContext : public TThrRefBase {
+ using TPtr = TIntrusivePtr<TRequestContext>;
+
+ TThis* Self;
+ TActorSystem* ActorSystem;
+ TActorId SelfId;
+ TActorId Sender;
+ ui64 Cookie;
+ ERequestType Type;
+
+ TRequestContext(TThis* self, TActorSystem* as, TActorId selfId, TActorId sender, ui64 cookie, ERequestType type)
+ : Self(self)
+ , ActorSystem(as)
+ , SelfId(selfId)
+ , Sender(sender)
+ , Cookie(cookie)
+ , Type(type)
+ { }
+ };
+
+ private:
+ void Handle(TEvDns::TEvGetHostByName::TPtr& ev) {
+ auto* msg = ev->Get();
+ auto reqCtx = MakeIntrusive<TRequestContext>(
+ this, TActivationContext::ActorSystem(), SelfId(), ev->Sender, ev->Cookie, ERequestType::GetHostByName);
+ PushCallback([this, reqCtx = std::move(reqCtx), name = std::move(msg->Name), family = msg->Family] () mutable {
+ StartGetHostByName(std::move(reqCtx), std::move(name), family);
+ });
+ }
+
+ void Handle(TEvDns::TEvGetAddr::TPtr& ev) {
+ auto* msg = ev->Get();
+ auto reqCtx = MakeIntrusive<TRequestContext>(
+ this, TActivationContext::ActorSystem(), SelfId(), ev->Sender, ev->Cookie, ERequestType::GetAddr);
+ PushCallback([this, reqCtx = std::move(reqCtx), name = std::move(msg->Name), family = msg->Family] () mutable {
+ StartGetHostByName(std::move(reqCtx), std::move(name), family);
+ });
+ }
+
+ void StartGetHostByName(TRequestContext::TPtr reqCtx, TString name, int family) noexcept {
+ reqCtx->Ref();
+ ares_gethostbyname(AresChannel, name.c_str(), family,
+ &TThis::GetHostByNameAresCallback, reqCtx.Get());
+ }
+
+ private:
+ static void GetHostByNameAresCallback(void* arg, int status, int timeouts, struct hostent* info) {
+ Y_UNUSED(timeouts);
+ TRequestContext::TPtr reqCtx(static_cast<TRequestContext*>(arg));
+ reqCtx->UnRef();
+
+ if (reqCtx->Self->Stopped) {
+ // Don't send any replies after destruction
+ return;
+ }
+
+ switch (reqCtx->Type) {
+ case ERequestType::GetHostByName: {
+ auto result = MakeHolder<TEvDns::TEvGetHostByNameResult>();
+ if (status == 0) {
+ switch (info->h_addrtype) {
+ case AF_INET: {
+ for (int i = 0; info->h_addr_list[i] != nullptr; ++i) {
+ result->AddrsV4.emplace_back(*(struct in_addr*)(info->h_addr_list[i]));
+ }
+ break;
+ }
+ case AF_INET6: {
+ for (int i = 0; info->h_addr_list[i] != nullptr; ++i) {
+ result->AddrsV6.emplace_back(*(struct in6_addr*)(info->h_addr_list[i]));
+ }
+ break;
+ }
+ default:
+ Y_FAIL("unknown address family in ares callback");
+ }
+ } else {
+ result->ErrorText = ares_strerror(status);
+ }
+ result->Status = status;
+
+ reqCtx->ActorSystem->Send(new IEventHandle(reqCtx->Sender, reqCtx->SelfId, result.Release(), 0, reqCtx->Cookie));
+ break;
+ }
+
+ case ERequestType::GetAddr: {
+ auto result = MakeHolder<TEvDns::TEvGetAddrResult>();
+ if (status == 0 && Y_UNLIKELY(info->h_addr_list[0] == nullptr)) {
+ status = ARES_ENODATA;
+ }
+ if (status == 0) {
+ switch (info->h_addrtype) {
+ case AF_INET: {
+ result->Addr = *(struct in_addr*)(info->h_addr_list[0]);
+ break;
+ }
+ case AF_INET6: {
+ result->Addr = *(struct in6_addr*)(info->h_addr_list[0]);
+ break;
+ }
+ default:
+ Y_FAIL("unknown address family in ares callback");
+ }
+ } else {
+ result->ErrorText = ares_strerror(status);
+ }
+ result->Status = status;
+
+ reqCtx->ActorSystem->Send(new IEventHandle(reqCtx->Sender, reqCtx->SelfId, result.Release(), 0, reqCtx->Cookie));
+ break;
+ }
+ }
+ }
+
+ private:
+ static void SockStateCallback(void* data, ares_socket_t socket_fd, int readable, int writable) {
+ static_cast<TThis*>(data)->DoSockStateCallback(socket_fd, readable, writable);
+ }
+
+ void DoSockStateCallback(ares_socket_t socket_fd, int readable, int writable) noexcept {
+ int events = (readable ? (POLLRDNORM | POLLIN) : 0) | (writable ? (POLLWRNORM | POLLOUT) : 0);
+ if (events == 0) {
+ AresSockStates.erase(socket_fd);
+ } else {
+ AresSockStates[socket_fd].NeededEvents = events;
+ }
+ }
+
+ private:
+ static void* WorkerThreadStart(void* arg) noexcept {
+ static_cast<TSimpleDnsResolver*>(arg)->WorkerThreadLoop();
+ return nullptr;
+ }
+
+ void WorkerThreadLoop() noexcept {
+ TThread::SetCurrentThreadName("DnsResolver");
+
+ TVector<struct pollfd> fds;
+ while (!Stopped) {
+ fds.clear();
+ fds.reserve(1 + AresSockStates.size());
+ {
+ auto& entry = fds.emplace_back();
+ entry.fd = WaitSock();
+ entry.events = POLLRDNORM | POLLIN;
+ }
+ for (auto& kv : AresSockStates) {
+ auto& entry = fds.emplace_back();
+ entry.fd = kv.first;
+ entry.events = kv.second.NeededEvents;
+ }
+
+ int timeout = -1;
+ struct timeval tv;
+ if (ares_timeout(AresChannel, nullptr, &tv)) {
+ timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+ }
+
+ int ret = poll(fds.data(), fds.size(), timeout);
+ if (ret == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ // we cannot handle failures, run callbacks and pretend everything is ok
+ RunCallbacks();
+ if (Stopped) {
+ break;
+ }
+ ret = 0;
+ }
+
+ bool ares_called = false;
+ if (ret > 0) {
+ for (size_t i = 0; i < fds.size(); ++i) {
+ auto& entry = fds[i];
+
+ // Handle WaitSock activation and run callbacks
+ if (i == 0) {
+ if (entry.revents & (POLLRDNORM | POLLIN)) {
+ RunCallbacks();
+ if (Stopped) {
+ break;
+ }
+ }
+ continue;
+ }
+
+ // All other sockets belong to ares
+ if (entry.revents == 0) {
+ continue;
+ }
+ // Previous invocation of aress_process_fd might have removed some sockets
+ if (Y_UNLIKELY(!AresSockStates.contains(entry.fd))) {
+ continue;
+ }
+ ares_process_fd(
+ AresChannel,
+ entry.revents & (POLLRDNORM | POLLIN) ? entry.fd : ARES_SOCKET_BAD,
+ entry.revents & (POLLWRNORM | POLLOUT) ? entry.fd : ARES_SOCKET_BAD);
+ ares_called = true;
+ }
+
+ if (Stopped) {
+ break;
+ }
+ }
+
+ if (!ares_called) {
+ // Let ares handle timeouts
+ ares_process_fd(AresChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
+ }
+ }
+ }
+
+ private:
+ struct TSockState {
+ short NeededEvents = 0; // poll events
+ };
+
+ private:
+ TSimpleDnsResolverOptions Options;
+ TThread WorkerThread;
+
+ ares_channel AresChannel;
+ THashMap<SOCKET, TSockState> AresSockStates;
+
+ bool Stopped = false;
+ };
+
+ IActor* CreateSimpleDnsResolver(TSimpleDnsResolverOptions options) {
+ return new TSimpleDnsResolver(std::move(options));
+ }
+
+} // namespace NDnsResolver
+} // namespace NActors
diff --git a/library/cpp/actors/dnsresolver/dnsresolver.h b/library/cpp/actors/dnsresolver/dnsresolver.h
new file mode 100644
index 0000000000..88fc74df7d
--- /dev/null
+++ b/library/cpp/actors/dnsresolver/dnsresolver.h
@@ -0,0 +1,128 @@
+#pragma once
+
+#include <library/cpp/actors/core/actor.h>
+#include <library/cpp/actors/core/events.h>
+#include <library/cpp/actors/core/event_local.h>
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+#include <util/network/address.h>
+#include <variant>
+
+namespace NActors {
+namespace NDnsResolver {
+
+ struct TEvDns {
+ enum EEv {
+ EvGetHostByName = EventSpaceBegin(TEvents::ES_DNS),
+ EvGetHostByNameResult,
+ EvGetAddr,
+ EvGetAddrResult,
+ };
+
+ /**
+ * TEvGetHostByName returns the result of ares_gethostbyname
+ */
+ struct TEvGetHostByName : public TEventLocal<TEvGetHostByName, EvGetHostByName> {
+ TString Name;
+ int Family;
+
+ explicit TEvGetHostByName(TString name, int family = AF_UNSPEC)
+ : Name(std::move(name))
+ , Family(family)
+ { }
+ };
+
+ struct TEvGetHostByNameResult : public TEventLocal<TEvGetHostByNameResult, EvGetHostByNameResult> {
+ TVector<struct in_addr> AddrsV4;
+ TVector<struct in6_addr> AddrsV6;
+ TString ErrorText;
+ int Status = 0;
+ };
+
+ /**
+ * TEvGetAddr returns a single address for a given hostname
+ */
+ struct TEvGetAddr : public TEventLocal<TEvGetAddr, EvGetAddr> {
+ TString Name;
+ int Family;
+
+ explicit TEvGetAddr(TString name, int family = AF_UNSPEC)
+ : Name(std::move(name))
+ , Family(family)
+ { }
+ };
+
+ struct TEvGetAddrResult : public TEventLocal<TEvGetAddrResult, EvGetAddrResult> {
+ // N.B. "using" here doesn't work with Visual Studio compiler
+ typedef struct in6_addr TIPv6Addr;
+ typedef struct in_addr TIPv4Addr;
+
+ std::variant<std::monostate, TIPv6Addr, TIPv4Addr> Addr;
+ TString ErrorText;
+ int Status = 0;
+
+ bool IsV6() const {
+ return std::holds_alternative<TIPv6Addr>(Addr);
+ }
+
+ bool IsV4() const {
+ return std::holds_alternative<TIPv4Addr>(Addr);
+ }
+
+ const TIPv6Addr& GetAddrV6() const {
+ const TIPv6Addr* p = std::get_if<TIPv6Addr>(&Addr);
+ Y_VERIFY(p, "Result is not an ipv6 address");
+ return *p;
+ }
+
+ const TIPv4Addr& GetAddrV4() const {
+ const TIPv4Addr* p = std::get_if<TIPv4Addr>(&Addr);
+ Y_VERIFY(p, "Result is not an ipv4 address");
+ return *p;
+ }
+ };
+ };
+
+ struct TSimpleDnsResolverOptions {
+ // Initial per-server timeout, grows exponentially with each retry
+ TDuration Timeout = TDuration::Seconds(1);
+ // Number of attempts per-server
+ int Attempts = 2;
+ // Optional list of custom dns servers (ip.v4[:port], ip::v6 or [ip::v6]:port format)
+ TVector<TString> Servers;
+ };
+
+ IActor* CreateSimpleDnsResolver(TSimpleDnsResolverOptions options = TSimpleDnsResolverOptions());
+
+ struct TCachingDnsResolverOptions {
+ // Soft expire time specifies delay before name is refreshed in background
+ TDuration SoftNegativeExpireTime = TDuration::Seconds(1);
+ TDuration SoftPositiveExpireTime = TDuration::Seconds(10);
+ // Hard expire time specifies delay before the last result is forgotten
+ TDuration HardNegativeExpireTime = TDuration::Seconds(10);
+ TDuration HardPositiveExpireTime = TDuration::Hours(2);
+ // Allow these request families
+ bool AllowIPv6 = true;
+ bool AllowIPv4 = true;
+ // Optional counters
+ NMonitoring::TDynamicCounterPtr MonCounters = nullptr;
+ };
+
+ IActor* CreateCachingDnsResolver(TActorId upstream, TCachingDnsResolverOptions options = TCachingDnsResolverOptions());
+
+ struct TOnDemandDnsResolverOptions
+ : public TSimpleDnsResolverOptions
+ , public TCachingDnsResolverOptions
+ {
+ };
+
+ IActor* CreateOnDemandDnsResolver(TOnDemandDnsResolverOptions options = TOnDemandDnsResolverOptions());
+
+ /**
+ * Returns actor id of a globally registered dns resolver
+ */
+ inline TActorId MakeDnsResolverActorId() {
+ return TActorId(0, TStringBuf("dnsresolver"));
+ }
+
+} // namespace NDnsResolver
+} // namespace NActors
diff --git a/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp b/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp
new file mode 100644
index 0000000000..02760f4c27
--- /dev/null
+++ b/library/cpp/actors/dnsresolver/dnsresolver_caching.cpp
@@ -0,0 +1,730 @@
+#include "dnsresolver.h"
+
+#include <library/cpp/actors/core/hfunc.h>
+#include <util/generic/intrlist.h>
+
+#include <ares.h>
+
+#include <queue>
+
+namespace NActors {
+namespace NDnsResolver {
+
+ class TCachingDnsResolver : public TActor<TCachingDnsResolver> {
+ public:
+ struct TMonCounters {
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingInFlightV4;
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingInFlightV6;
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingErrorsV4;
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingErrorsV6;
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingTotalV4;
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingTotalV6;
+
+ NMonitoring::TDynamicCounters::TCounterPtr IncomingInFlight;
+ NMonitoring::TDynamicCounters::TCounterPtr IncomingErrors;
+ NMonitoring::TDynamicCounters::TCounterPtr IncomingTotal;
+
+ NMonitoring::TDynamicCounters::TCounterPtr CacheSize;
+ NMonitoring::TDynamicCounters::TCounterPtr CacheHits;
+ NMonitoring::TDynamicCounters::TCounterPtr CacheMisses;
+
+ TMonCounters(const NMonitoring::TDynamicCounterPtr& counters)
+ : OutgoingInFlightV4(counters->GetCounter("DnsResolver/Outgoing/InFlight/V4", false))
+ , OutgoingInFlightV6(counters->GetCounter("DnsResolver/Outgoing/InFlight/V6", false))
+ , OutgoingErrorsV4(counters->GetCounter("DnsResolver/Outgoing/Errors/V4", true))
+ , OutgoingErrorsV6(counters->GetCounter("DnsResolver/Outgoing/Errors/V6", true))
+ , OutgoingTotalV4(counters->GetCounter("DnsResolver/Outgoing/Total/V4", true))
+ , OutgoingTotalV6(counters->GetCounter("DnsResolver/Outgoing/Total/V6", true))
+ , IncomingInFlight(counters->GetCounter("DnsResolver/Incoming/InFlight", false))
+ , IncomingErrors(counters->GetCounter("DnsResolver/Incoming/Errors", true))
+ , IncomingTotal(counters->GetCounter("DnsResolver/Incoming/Total", true))
+ , CacheSize(counters->GetCounter("DnsResolver/Cache/Size", false))
+ , CacheHits(counters->GetCounter("DnsResolver/Cache/Hits", true))
+ , CacheMisses(counters->GetCounter("DnsResolver/Cache/Misses", true))
+ { }
+ };
+
+ public:
+ TCachingDnsResolver(TActorId upstream, TCachingDnsResolverOptions options)
+ : TActor(&TThis::StateWork)
+ , Upstream(upstream)
+ , Options(std::move(options))
+ , MonCounters(Options.MonCounters ? new TMonCounters(Options.MonCounters) : nullptr)
+ { }
+
+ static constexpr EActivityType ActorActivityType() {
+ return DNS_RESOLVER;
+ }
+
+ private:
+ STRICT_STFUNC(StateWork, {
+ hFunc(TEvents::TEvPoison, Handle);
+ hFunc(TEvDns::TEvGetHostByName, Handle);
+ hFunc(TEvDns::TEvGetAddr, Handle);
+ hFunc(TEvDns::TEvGetHostByNameResult, Handle);
+ hFunc(TEvents::TEvUndelivered, Handle);
+ });
+
+ void Handle(TEvents::TEvPoison::TPtr&) {
+ DropPending(ARES_ECANCELLED);
+ PassAway();
+ }
+
+ void Handle(TEvDns::TEvGetHostByName::TPtr& ev) {
+ auto req = MakeHolder<TIncomingRequest>();
+ req->Type = EIncomingRequestType::GetHostByName;
+ req->Sender = ev->Sender;
+ req->Cookie = ev->Cookie;
+ req->Name = std::move(ev->Get()->Name);
+ req->Family = ev->Get()->Family;
+ EnqueueRequest(std::move(req));
+ }
+
+ void Handle(TEvDns::TEvGetAddr::TPtr& ev) {
+ auto req = MakeHolder<TIncomingRequest>();
+ req->Type = EIncomingRequestType::GetAddr;
+ req->Sender = ev->Sender;
+ req->Cookie = ev->Cookie;
+ req->Name = std::move(ev->Get()->Name);
+ req->Family = ev->Get()->Family;
+ EnqueueRequest(std::move(req));
+ }
+
+ void Handle(TEvDns::TEvGetHostByNameResult::TPtr& ev) {
+ auto waitingIt = WaitingRequests.find(ev->Cookie);
+ Y_VERIFY(waitingIt != WaitingRequests.end(), "Unexpected reply, reqId=%" PRIu64, ev->Cookie);
+ auto waitingInfo = waitingIt->second;
+ WaitingRequests.erase(waitingIt);
+
+ switch (waitingInfo.Family) {
+ case AF_INET6:
+ if (ev->Get()->Status) {
+ ProcessErrorV6(waitingInfo.Position, ev->Get()->Status, std::move(ev->Get()->ErrorText));
+ } else {
+ ProcessAddrsV6(waitingInfo.Position, std::move(ev->Get()->AddrsV6));
+ }
+ break;
+
+ case AF_INET:
+ if (ev->Get()->Status) {
+ ProcessErrorV4(waitingInfo.Position, ev->Get()->Status, std::move(ev->Get()->ErrorText));
+ } else {
+ ProcessAddrsV4(waitingInfo.Position, std::move(ev->Get()->AddrsV4));
+ }
+ break;
+
+ default:
+ Y_FAIL("Unexpected request family %d", waitingInfo.Family);
+ }
+ }
+
+ void Handle(TEvents::TEvUndelivered::TPtr& ev) {
+ switch (ev->Get()->SourceType) {
+ case TEvDns::TEvGetHostByName::EventType: {
+ auto waitingIt = WaitingRequests.find(ev->Cookie);
+ Y_VERIFY(waitingIt != WaitingRequests.end(), "Unexpected TEvUndelivered, reqId=%" PRIu64, ev->Cookie);
+ auto waitingInfo = waitingIt->second;
+ WaitingRequests.erase(waitingIt);
+
+ switch (waitingInfo.Family) {
+ case AF_INET6:
+ ProcessErrorV6(waitingInfo.Position, ARES_ENOTINITIALIZED, "Caching dns resolver cannot deliver to the underlying resolver");
+ break;
+ case AF_INET:
+ ProcessErrorV4(waitingInfo.Position, ARES_ENOTINITIALIZED, "Caching dns resolver cannot deliver to the underlying resolver");
+ break;
+ default:
+ Y_FAIL("Unexpected request family %d", waitingInfo.Family);
+ }
+
+ break;
+ }
+
+ default:
+ Y_FAIL("Unexpected TEvUndelievered, type=%" PRIu32, ev->Get()->SourceType);
+ }
+ }
+
+ private:
+ enum EIncomingRequestType {
+ GetHostByName,
+ GetAddr,
+ };
+
+ struct TIncomingRequest : public TIntrusiveListItem<TIncomingRequest> {
+ EIncomingRequestType Type;
+ TActorId Sender;
+ ui64 Cookie;
+ TString Name;
+ int Family;
+ };
+
+ using TIncomingRequestList = TIntrusiveListWithAutoDelete<TIncomingRequest, TDelete>;
+
+ void EnqueueRequest(THolder<TIncomingRequest> req) {
+ if (MonCounters) {
+ ++*MonCounters->IncomingTotal;
+ }
+
+ CleanupExpired(TActivationContext::Now());
+
+ switch (req->Family) {
+ case AF_UNSPEC:
+ if (Options.AllowIPv6) {
+ EnqueueRequestIPv6(std::move(req));
+ return;
+ }
+ if (Options.AllowIPv4) {
+ EnqueueRequestIPv4(std::move(req));
+ return;
+ }
+ break;
+
+ case AF_INET6:
+ if (Options.AllowIPv6) {
+ EnqueueRequestIPv6(std::move(req));
+ return;
+ }
+ break;
+
+ case AF_INET:
+ if (Options.AllowIPv4) {
+ EnqueueRequestIPv4(std::move(req));
+ return;
+ }
+ break;
+ }
+
+ ReplyWithError(std::move(req), ARES_EBADFAMILY);
+ }
+
+ void EnqueueRequestIPv6(THolder<TIncomingRequest> req) {
+ auto now = TActivationContext::Now();
+
+ auto& fullState = NameToState[req->Name];
+ if (MonCounters) {
+ *MonCounters->CacheSize = NameToState.size();
+ }
+
+ auto& state = fullState.StateIPv6;
+ EnsureRequest(state, req->Name, AF_INET6, now);
+
+ if (state.IsHardExpired(now)) {
+ Y_VERIFY(state.Waiting);
+ if (MonCounters) {
+ ++*MonCounters->CacheMisses;
+ }
+ // We need to wait for ipv6 reply, schedule ipv4 request in parallel if needed
+ if (Options.AllowIPv4) {
+ EnsureRequest(fullState.StateIPv4, req->Name, AF_INET, now);
+ }
+ state.WaitingRequests.PushBack(req.Release());
+ return;
+ }
+
+ // We want to retry AF_UNSPEC with IPv4 in some cases
+ if (req->Family == AF_UNSPEC && Options.AllowIPv4 && state.RetryUnspec()) {
+ EnqueueRequestIPv4(std::move(req));
+ return;
+ }
+
+ if (MonCounters) {
+ ++*MonCounters->CacheHits;
+ }
+
+ if (state.Status != 0) {
+ ReplyWithError(std::move(req), state.Status, state.ErrorText);
+ } else {
+ ReplyWithAddrs(std::move(req), fullState.AddrsIPv6);
+ }
+ }
+
+ void EnqueueRequestIPv4(THolder<TIncomingRequest> req, bool isCacheMiss = false) {
+ auto now = TActivationContext::Now();
+
+ auto& fullState = NameToState[req->Name];
+ if (MonCounters) {
+ *MonCounters->CacheSize = NameToState.size();
+ }
+
+ auto& state = fullState.StateIPv4;
+ EnsureRequest(state, req->Name, AF_INET, now);
+
+ if (state.IsHardExpired(now)) {
+ Y_VERIFY(state.Waiting);
+ if (MonCounters && !isCacheMiss) {
+ ++*MonCounters->CacheMisses;
+ }
+ state.WaitingRequests.PushBack(req.Release());
+ return;
+ }
+
+ if (MonCounters && !isCacheMiss) {
+ ++*MonCounters->CacheHits;
+ }
+
+ if (state.Status != 0) {
+ ReplyWithError(std::move(req), state.Status, state.ErrorText);
+ } else {
+ ReplyWithAddrs(std::move(req), fullState.AddrsIPv4);
+ }
+ }
+
+ private:
+ struct TFamilyState {
+ TIncomingRequestList WaitingRequests;
+ TInstant SoftDeadline;
+ TInstant HardDeadline;
+ TInstant NextSoftDeadline;
+ TInstant NextHardDeadline;
+ TString ErrorText;
+ int Status = -1; // never requested before
+ bool InSoftHeap = false;
+ bool InHardHeap = false;
+ bool Waiting = false;
+
+ bool Needed() const {
+ return InSoftHeap || InHardHeap || Waiting;
+ }
+
+ bool RetryUnspec() const {
+ return (
+ Status == ARES_ENODATA ||
+ Status == ARES_EBADRESP ||
+ Status == ARES_ETIMEOUT);
+ }
+
+ bool ServerReplied() const {
+ return ServerReplied(Status);
+ }
+
+ bool IsSoftExpired(TInstant now) const {
+ return !InSoftHeap || NextSoftDeadline < now;
+ }
+
+ bool IsHardExpired(TInstant now) const {
+ return !InHardHeap || NextHardDeadline < now;
+ }
+
+ static bool ServerReplied(int status) {
+ return (
+ status == ARES_SUCCESS ||
+ status == ARES_ENODATA ||
+ status == ARES_ENOTFOUND);
+ }
+ };
+
+ struct TState {
+ TFamilyState StateIPv6;
+ TFamilyState StateIPv4;
+ TVector<struct in6_addr> AddrsIPv6;
+ TVector<struct in_addr> AddrsIPv4;
+
+ bool Needed() const {
+ return StateIPv6.Needed() || StateIPv4.Needed();
+ }
+ };
+
+ using TNameToState = THashMap<TString, TState>;
+
+ template<const TFamilyState TState::* StateToFamily,
+ const TInstant TFamilyState::* FamilyToDeadline>
+ struct THeapCompare {
+ // returns true when b < a
+ bool operator()(TNameToState::iterator a, TNameToState::iterator b) const {
+ const TState& aState = a->second;
+ const TState& bState = b->second;
+ const TFamilyState& aFamily = aState.*StateToFamily;
+ const TFamilyState& bFamily = bState.*StateToFamily;
+ const TInstant& aDeadline = aFamily.*FamilyToDeadline;
+ const TInstant& bDeadline = bFamily.*FamilyToDeadline;
+ return bDeadline < aDeadline;
+ }
+ };
+
+ template<const TFamilyState TState::* StateToFamily,
+ const TInstant TFamilyState::* FamilyToDeadline>
+ using TStateHeap = std::priority_queue<
+ TNameToState::iterator,
+ std::vector<TNameToState::iterator>,
+ THeapCompare<StateToFamily, FamilyToDeadline>
+ >;
+
+ struct TWaitingInfo {
+ TNameToState::iterator Position;
+ int Family;
+ };
+
+ private:
+ void EnsureRequest(TFamilyState& state, const TString& name, int family, TInstant now) {
+ if (state.Waiting) {
+ return; // request is already pending
+ }
+
+ if (!state.IsSoftExpired(now) && !state.IsHardExpired(now)) {
+ return; // response is not expired yet
+ }
+
+ if (MonCounters) {
+ switch (family) {
+ case AF_INET6:
+ ++*MonCounters->OutgoingInFlightV6;
+ ++*MonCounters->OutgoingTotalV6;
+ break;
+ case AF_INET:
+ ++*MonCounters->OutgoingInFlightV4;
+ ++*MonCounters->OutgoingTotalV4;
+ break;
+ }
+ }
+
+ ui64 reqId = ++LastRequestId;
+ auto& req = WaitingRequests[reqId];
+ req.Position = NameToState.find(name);
+ req.Family = family;
+ Y_VERIFY(req.Position != NameToState.end());
+
+ Send(Upstream, new TEvDns::TEvGetHostByName(name, family), IEventHandle::FlagTrackDelivery, reqId);
+ state.Waiting = true;
+ }
+
+ template<TFamilyState TState::* StateToFamily,
+ TInstant TFamilyState::* FamilyToDeadline,
+ TInstant TFamilyState::* FamilyToNextDeadline,
+ bool TFamilyState::* FamilyToFlag,
+ class THeap>
+ void PushToHeap(THeap& heap, TNameToState::iterator it, TInstant newDeadline) {
+ auto& family = it->second.*StateToFamily;
+ TInstant& deadline = family.*FamilyToDeadline;
+ TInstant& nextDeadline = family.*FamilyToNextDeadline;
+ bool& flag = family.*FamilyToFlag;
+ nextDeadline = newDeadline;
+ if (!flag) {
+ deadline = newDeadline;
+ heap.push(it);
+ flag = true;
+ }
+ }
+
+ void PushSoftV6(TNameToState::iterator it, TInstant newDeadline) {
+ PushToHeap<&TState::StateIPv6, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv6, it, newDeadline);
+ }
+
+ void PushHardV6(TNameToState::iterator it, TInstant newDeadline) {
+ PushToHeap<&TState::StateIPv6, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv6, it, newDeadline);
+ }
+
+ void PushSoftV4(TNameToState::iterator it, TInstant newDeadline) {
+ PushToHeap<&TState::StateIPv4, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv4, it, newDeadline);
+ }
+
+ void PushHardV4(TNameToState::iterator it, TInstant newDeadline) {
+ PushToHeap<&TState::StateIPv4, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv4, it, newDeadline);
+ }
+
+ void ProcessErrorV6(TNameToState::iterator it, int status, TString errorText) {
+ auto now = TActivationContext::Now();
+ if (MonCounters) {
+ --*MonCounters->OutgoingInFlightV6;
+ ++*MonCounters->OutgoingErrorsV6;
+ }
+
+ auto& state = it->second.StateIPv6;
+ Y_VERIFY(state.Waiting, "Got error for a state we are not waiting");
+ state.Waiting = false;
+
+ // When we have a cached positive reply, don't overwrite it with spurious errors
+ const bool serverReplied = TFamilyState::ServerReplied(status);
+ if (!serverReplied && state.ServerReplied() && !state.IsHardExpired(now)) {
+ PushSoftV6(it, now + Options.SoftNegativeExpireTime);
+ if (state.Status == ARES_SUCCESS) {
+ SendAddrsV6(it);
+ } else {
+ SendErrorsV6(it, now);
+ }
+ return;
+ }
+
+ state.Status = status;
+ state.ErrorText = std::move(errorText);
+ PushSoftV6(it, now + Options.SoftNegativeExpireTime);
+ if (serverReplied) {
+ // Server actually replied, so keep it cached for longer
+ PushHardV6(it, now + Options.HardPositiveExpireTime);
+ } else {
+ PushHardV6(it, now + Options.HardNegativeExpireTime);
+ }
+
+ SendErrorsV6(it, now);
+ }
+
+ void SendErrorsV6(TNameToState::iterator it, TInstant now) {
+ bool cleaned = false;
+ auto& state = it->second.StateIPv6;
+ while (state.WaitingRequests) {
+ THolder<TIncomingRequest> req(state.WaitingRequests.PopFront());
+ if (req->Family == AF_UNSPEC && Options.AllowIPv4 && state.RetryUnspec()) {
+ if (!cleaned) {
+ CleanupExpired(now);
+ cleaned = true;
+ }
+ EnqueueRequestIPv4(std::move(req), /* isCacheMiss */ true);
+ } else {
+ ReplyWithError(std::move(req), state.Status, state.ErrorText);
+ }
+ }
+ }
+
+ void ProcessErrorV4(TNameToState::iterator it, int status, TString errorText) {
+ auto now = TActivationContext::Now();
+ if (MonCounters) {
+ --*MonCounters->OutgoingInFlightV4;
+ ++*MonCounters->OutgoingErrorsV4;
+ }
+
+ auto& state = it->second.StateIPv4;
+ Y_VERIFY(state.Waiting, "Got error for a state we are not waiting");
+ state.Waiting = false;
+
+ // When we have a cached positive reply, don't overwrite it with spurious errors
+ const bool serverReplied = TFamilyState::ServerReplied(status);
+ if (!serverReplied && state.ServerReplied() && !state.IsHardExpired(now)) {
+ PushSoftV4(it, now + Options.SoftNegativeExpireTime);
+ if (state.Status == ARES_SUCCESS) {
+ SendAddrsV4(it);
+ } else {
+ SendErrorsV4(it);
+ }
+ return;
+ }
+
+ state.Status = status;
+ state.ErrorText = std::move(errorText);
+ PushSoftV4(it, now + Options.SoftNegativeExpireTime);
+ if (serverReplied) {
+ // Server actually replied, so keep it cached for longer
+ PushHardV4(it, now + Options.HardPositiveExpireTime);
+ } else {
+ PushHardV4(it, now + Options.HardNegativeExpireTime);
+ }
+
+ SendErrorsV4(it);
+ }
+
+ void SendErrorsV4(TNameToState::iterator it) {
+ auto& state = it->second.StateIPv4;
+ while (state.WaitingRequests) {
+ THolder<TIncomingRequest> req(state.WaitingRequests.PopFront());
+ ReplyWithError(std::move(req), state.Status, state.ErrorText);
+ }
+ }
+
+ void ProcessAddrsV6(TNameToState::iterator it, TVector<struct in6_addr> addrs) {
+ if (Y_UNLIKELY(addrs.empty())) {
+ // Probably unnecessary: we don't want to deal with empty address lists
+ return ProcessErrorV6(it, ARES_ENODATA, ares_strerror(ARES_ENODATA));
+ }
+
+ auto now = TActivationContext::Now();
+ if (MonCounters) {
+ --*MonCounters->OutgoingInFlightV6;
+ }
+
+ auto& state = it->second.StateIPv6;
+ Y_VERIFY(state.Waiting, "Got reply for a state we are not waiting");
+ state.Waiting = false;
+
+ state.Status = ARES_SUCCESS;
+ it->second.AddrsIPv6 = std::move(addrs);
+ PushSoftV6(it, now + Options.SoftPositiveExpireTime);
+ PushHardV6(it, now + Options.HardPositiveExpireTime);
+
+ SendAddrsV6(it);
+ }
+
+ void SendAddrsV6(TNameToState::iterator it) {
+ auto& state = it->second.StateIPv6;
+ while (state.WaitingRequests) {
+ THolder<TIncomingRequest> req(state.WaitingRequests.PopFront());
+ ReplyWithAddrs(std::move(req), it->second.AddrsIPv6);
+ }
+ }
+
+ void ProcessAddrsV4(TNameToState::iterator it, TVector<struct in_addr> addrs) {
+ if (Y_UNLIKELY(addrs.empty())) {
+ // Probably unnecessary: we don't want to deal with empty address lists
+ return ProcessErrorV4(it, ARES_ENODATA, ares_strerror(ARES_ENODATA));
+ }
+
+ auto now = TActivationContext::Now();
+ if (MonCounters) {
+ --*MonCounters->OutgoingInFlightV4;
+ }
+
+ auto& state = it->second.StateIPv4;
+ Y_VERIFY(state.Waiting, "Got reply for a state we are not waiting");
+ state.Waiting = false;
+
+ state.Status = ARES_SUCCESS;
+ it->second.AddrsIPv4 = std::move(addrs);
+ PushSoftV4(it, now + Options.SoftPositiveExpireTime);
+ PushHardV4(it, now + Options.HardPositiveExpireTime);
+
+ SendAddrsV4(it);
+ }
+
+ void SendAddrsV4(TNameToState::iterator it) {
+ auto& state = it->second.StateIPv4;
+ while (state.WaitingRequests) {
+ THolder<TIncomingRequest> req(state.WaitingRequests.PopFront());
+ ReplyWithAddrs(std::move(req), it->second.AddrsIPv4);
+ }
+ }
+
+ private:
+ template<TFamilyState TState::*StateToFamily,
+ TInstant TFamilyState::* FamilyToDeadline,
+ TInstant TFamilyState::* FamilyToNextDeadline,
+ bool TFamilyState::* FamilyToFlag>
+ void DoCleanupExpired(TStateHeap<StateToFamily, FamilyToDeadline>& heap, TInstant now) {
+ while (!heap.empty()) {
+ auto it = heap.top();
+ auto& family = it->second.*StateToFamily;
+ TInstant& deadline = family.*FamilyToDeadline;
+ if (now <= deadline) {
+ break;
+ }
+
+ bool& flag = family.*FamilyToFlag;
+ Y_VERIFY(flag);
+ heap.pop();
+ flag = false;
+
+ TInstant& nextDeadline = family.*FamilyToNextDeadline;
+ if (now < nextDeadline) {
+ deadline = nextDeadline;
+ heap.push(it);
+ flag = true;
+ continue;
+ }
+
+ // Remove unnecessary items
+ if (!it->second.Needed()) {
+ NameToState.erase(it);
+ if (MonCounters) {
+ *MonCounters->CacheSize = NameToState.size();
+ }
+ }
+ }
+ }
+
+ void CleanupExpired(TInstant now) {
+ DoCleanupExpired<&TState::StateIPv6, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv6, now);
+ DoCleanupExpired<&TState::StateIPv6, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv6, now);
+ DoCleanupExpired<&TState::StateIPv4, &TFamilyState::SoftDeadline, &TFamilyState::NextSoftDeadline, &TFamilyState::InSoftHeap>(SoftHeapIPv4, now);
+ DoCleanupExpired<&TState::StateIPv4, &TFamilyState::HardDeadline, &TFamilyState::NextHardDeadline, &TFamilyState::InHardHeap>(HardHeapIPv4, now);
+ }
+
+ template<class TEvent>
+ void SendError(TActorId replyTo, ui64 cookie, int status, const TString& errorText) {
+ auto reply = MakeHolder<TEvent>();
+ reply->Status = status;
+ reply->ErrorText = errorText;
+ this->Send(replyTo, reply.Release(), 0, cookie);
+ }
+
+ void ReplyWithError(THolder<TIncomingRequest> req, int status, const TString& errorText) {
+ if (MonCounters) {
+ ++*MonCounters->IncomingErrors;
+ }
+ switch (req->Type) {
+ case EIncomingRequestType::GetHostByName: {
+ SendError<TEvDns::TEvGetHostByNameResult>(req->Sender, req->Cookie, status, errorText);
+ break;
+ }
+ case EIncomingRequestType::GetAddr: {
+ SendError<TEvDns::TEvGetAddrResult>(req->Sender, req->Cookie, status, errorText);
+ break;
+ }
+ }
+ }
+
+ void ReplyWithAddrs(THolder<TIncomingRequest> req, const TVector<struct in6_addr>& addrs) {
+ switch (req->Type) {
+ case EIncomingRequestType::GetHostByName: {
+ auto reply = MakeHolder<TEvDns::TEvGetHostByNameResult>();
+ reply->AddrsV6 = addrs;
+ Send(req->Sender, reply.Release(), 0, req->Cookie);
+ break;
+ }
+ case EIncomingRequestType::GetAddr: {
+ Y_VERIFY(!addrs.empty());
+ auto reply = MakeHolder<TEvDns::TEvGetAddrResult>();
+ reply->Addr = addrs.front();
+ Send(req->Sender, reply.Release(), 0, req->Cookie);
+ break;
+ }
+ }
+ }
+
+ void ReplyWithAddrs(THolder<TIncomingRequest> req, const TVector<struct in_addr>& addrs) {
+ switch (req->Type) {
+ case EIncomingRequestType::GetHostByName: {
+ auto reply = MakeHolder<TEvDns::TEvGetHostByNameResult>();
+ reply->AddrsV4 = addrs;
+ Send(req->Sender, reply.Release(), 0, req->Cookie);
+ break;
+ }
+ case EIncomingRequestType::GetAddr: {
+ Y_VERIFY(!addrs.empty());
+ auto reply = MakeHolder<TEvDns::TEvGetAddrResult>();
+ reply->Addr = addrs.front();
+ Send(req->Sender, reply.Release(), 0, req->Cookie);
+ break;
+ }
+ }
+ }
+
+ void ReplyWithError(THolder<TIncomingRequest> req, int status) {
+ ReplyWithError(std::move(req), status, ares_strerror(status));
+ }
+
+ void DropPending(TIncomingRequestList& list, int status, const TString& errorText) {
+ while (list) {
+ THolder<TIncomingRequest> req(list.PopFront());
+ ReplyWithError(std::move(req), status, errorText);
+ }
+ }
+
+ void DropPending(int status, const TString& errorText) {
+ for (auto& [name, state] : NameToState) {
+ DropPending(state.StateIPv6.WaitingRequests, status, errorText);
+ DropPending(state.StateIPv4.WaitingRequests, status, errorText);
+ }
+ }
+
+ void DropPending(int status) {
+ DropPending(status, ares_strerror(status));
+ }
+
+ private:
+ const TActorId Upstream;
+ const TCachingDnsResolverOptions Options;
+ const THolder<TMonCounters> MonCounters;
+
+ TNameToState NameToState;
+ TStateHeap<&TState::StateIPv6, &TFamilyState::SoftDeadline> SoftHeapIPv6;
+ TStateHeap<&TState::StateIPv6, &TFamilyState::HardDeadline> HardHeapIPv6;
+ TStateHeap<&TState::StateIPv4, &TFamilyState::SoftDeadline> SoftHeapIPv4;
+ TStateHeap<&TState::StateIPv4, &TFamilyState::HardDeadline> HardHeapIPv4;
+
+ THashMap<ui64, TWaitingInfo> WaitingRequests;
+ ui64 LastRequestId = 0;
+ };
+
+ IActor* CreateCachingDnsResolver(TActorId upstream, TCachingDnsResolverOptions options) {
+ return new TCachingDnsResolver(upstream, std::move(options));
+ }
+
+} // namespace NDnsResolver
+} // namespace NActors
diff --git a/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp b/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp
new file mode 100644
index 0000000000..c3b7cb3c77
--- /dev/null
+++ b/library/cpp/actors/dnsresolver/dnsresolver_caching_ut.cpp
@@ -0,0 +1,630 @@
+#include "dnsresolver.h"
+
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/actors/testlib/test_runtime.h>
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/string/builder.h>
+
+#include <ares.h>
+
+using namespace NActors;
+using namespace NActors::NDnsResolver;
+
+// FIXME: use a mock resolver
+Y_UNIT_TEST_SUITE(CachingDnsResolver) {
+
+ struct TAddrToString {
+ TString operator()(const std::monostate&) const {
+ return "<nothing>";
+ }
+
+ TString operator()(const struct in6_addr& addr) const {
+ char dst[INET6_ADDRSTRLEN];
+ auto res = ares_inet_ntop(AF_INET6, &addr, dst, INET6_ADDRSTRLEN);
+ Y_VERIFY(res, "Cannot convert ipv6 address");
+ return dst;
+ }
+
+ TString operator()(const struct in_addr& addr) const {
+ char dst[INET_ADDRSTRLEN];
+ auto res = ares_inet_ntop(AF_INET, &addr, dst, INET_ADDRSTRLEN);
+ Y_VERIFY(res, "Cannot convert ipv4 address");
+ return dst;
+ }
+ };
+
+ TString AddrToString(const std::variant<std::monostate, struct in6_addr, struct in_addr>& v) {
+ return std::visit(TAddrToString(), v);
+ }
+
+ struct TMockReply {
+ static constexpr TDuration DefaultDelay = TDuration::MilliSeconds(1);
+
+ int Status = 0;
+ TDuration Delay;
+ TVector<struct in6_addr> AddrsV6;
+ TVector<struct in_addr> AddrsV4;
+
+ static TMockReply Error(int status, TDuration delay = DefaultDelay) {
+ Y_VERIFY(status != 0);
+ TMockReply reply;
+ reply.Status = status;
+ reply.Delay = delay;
+ return reply;
+ }
+
+ static TMockReply Empty(TDuration delay = DefaultDelay) {
+ TMockReply reply;
+ reply.Delay = delay;
+ return reply;
+ }
+
+ static TMockReply ManyV6(const TVector<TString>& addrs, TDuration delay = DefaultDelay) {
+ TMockReply reply;
+ reply.Delay = delay;
+ for (const TString& addr : addrs) {
+ void* dst = &reply.AddrsV6.emplace_back();
+ int status = ares_inet_pton(AF_INET6, addr.c_str(), dst);
+ Y_VERIFY(status == 1, "Invalid ipv6 address: %s", addr.c_str());
+ }
+ return reply;
+ }
+
+ static TMockReply ManyV4(const TVector<TString>& addrs, TDuration delay = DefaultDelay) {
+ TMockReply reply;
+ reply.Delay = delay;
+ for (const TString& addr : addrs) {
+ void* dst = &reply.AddrsV4.emplace_back();
+ int status = ares_inet_pton(AF_INET, addr.c_str(), dst);
+ Y_VERIFY(status == 1, "Invalid ipv4 address: %s", addr.c_str());
+ }
+ return reply;
+ }
+
+ static TMockReply SingleV6(const TString& addr, TDuration delay = DefaultDelay) {
+ return ManyV6({ addr }, delay);
+ }
+
+ static TMockReply SingleV4(const TString& addr, TDuration delay = DefaultDelay) {
+ return ManyV4({ addr }, delay);
+ }
+ };
+
+ using TMockDnsCallback = std::function<TMockReply (const TString&, int)>;
+
+ class TMockDnsResolver : public TActor<TMockDnsResolver> {
+ public:
+ TMockDnsResolver(TMockDnsCallback callback)
+ : TActor(&TThis::StateWork)
+ , Callback(std::move(callback))
+ { }
+
+ private:
+ struct TEvPrivate {
+ enum EEv {
+ EvScheduled = EventSpaceBegin(TEvents::ES_PRIVATE),
+ };
+
+ struct TEvScheduled : public TEventLocal<TEvScheduled, EvScheduled> {
+ TActorId Sender;
+ ui64 Cookie;
+ TMockReply Reply;
+
+ TEvScheduled(TActorId sender, ui64 cookie, TMockReply reply)
+ : Sender(sender)
+ , Cookie(cookie)
+ , Reply(std::move(reply))
+ { }
+ };
+ };
+
+ private:
+ STRICT_STFUNC(StateWork, {
+ hFunc(TEvents::TEvPoison, Handle);
+ hFunc(TEvDns::TEvGetHostByName, Handle);
+ hFunc(TEvPrivate::TEvScheduled, Handle);
+ });
+
+ void Handle(TEvents::TEvPoison::TPtr&) {
+ PassAway();
+ }
+
+ void Handle(TEvDns::TEvGetHostByName::TPtr& ev) {
+ auto reply = Callback(ev->Get()->Name, ev->Get()->Family);
+ if (reply.Delay) {
+ Schedule(reply.Delay, new TEvPrivate::TEvScheduled(ev->Sender, ev->Cookie, std::move(reply)));
+ } else {
+ SendReply(ev->Sender, ev->Cookie, std::move(reply));
+ }
+ }
+
+ void Handle(TEvPrivate::TEvScheduled::TPtr& ev) {
+ SendReply(ev->Get()->Sender, ev->Get()->Cookie, std::move(ev->Get()->Reply));
+ }
+
+ private:
+ void SendReply(const TActorId& sender, ui64 cookie, TMockReply&& reply) {
+ auto res = MakeHolder<TEvDns::TEvGetHostByNameResult>();
+ res->Status = reply.Status;
+ if (res->Status != 0) {
+ res->ErrorText = ares_strerror(res->Status);
+ } else {
+ res->AddrsV6 = std::move(reply.AddrsV6);
+ res->AddrsV4 = std::move(reply.AddrsV4);
+ }
+ Send(sender, res.Release(), 0, cookie);
+ }
+
+ private:
+ TMockDnsCallback Callback;
+ };
+
+ struct TCachingDnsRuntime : public TTestActorRuntimeBase {
+ TCachingDnsResolverOptions ResolverOptions;
+ TActorId MockResolver;
+ TActorId Resolver;
+ TActorId Sleeper;
+ TString Section_;
+
+ NMonitoring::TDynamicCounters::TCounterPtr InFlight6;
+ NMonitoring::TDynamicCounters::TCounterPtr InFlight4;
+ NMonitoring::TDynamicCounters::TCounterPtr Total6;
+ NMonitoring::TDynamicCounters::TCounterPtr Total4;
+ NMonitoring::TDynamicCounters::TCounterPtr Misses;
+ NMonitoring::TDynamicCounters::TCounterPtr Hits;
+
+ THashMap<TString, TMockReply> ReplyV6;
+ THashMap<TString, TMockReply> ReplyV4;
+
+ TCachingDnsRuntime() {
+ SetScheduledEventFilter([](auto&&, auto&&, auto&&, auto&&) { return false; });
+ ResolverOptions.MonCounters = new NMonitoring::TDynamicCounters;
+
+ ReplyV6["localhost"] = TMockReply::SingleV6("::1");
+ ReplyV4["localhost"] = TMockReply::SingleV4("127.0.0.1");
+ ReplyV6["yandex.ru"] = TMockReply::SingleV6("2a02:6b8:a::a", TDuration::MilliSeconds(500));
+ ReplyV4["yandex.ru"] = TMockReply::SingleV4("77.88.55.77", TDuration::MilliSeconds(250));
+ ReplyV6["router.asus.com"] = TMockReply::Error(ARES_ENODATA);
+ ReplyV4["router.asus.com"] = TMockReply::SingleV4("192.168.0.1");
+ }
+
+ void Start(TMockDnsCallback callback) {
+ MockResolver = Register(new TMockDnsResolver(std::move(callback)));
+ EnableScheduleForActor(MockResolver);
+ Resolver = Register(CreateCachingDnsResolver(MockResolver, ResolverOptions));
+ Sleeper = AllocateEdgeActor();
+
+ InFlight6 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/InFlight/V6", false);
+ InFlight4 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/InFlight/V4", false);
+ Total6 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/Total/V6", true);
+ Total4 = ResolverOptions.MonCounters->GetCounter("DnsResolver/Outgoing/Total/V4", true);
+ Misses = ResolverOptions.MonCounters->GetCounter("DnsResolver/Cache/Misses", true);
+ Hits = ResolverOptions.MonCounters->GetCounter("DnsResolver/Cache/Hits", true);
+ }
+
+ void Start() {
+ Start([this](const TString& name, int family) {
+ switch (family) {
+ case AF_INET6: {
+ auto it = ReplyV6.find(name);
+ if (it != ReplyV6.end()) {
+ return it->second;
+ }
+ break;
+ }
+ case AF_INET: {
+ auto it = ReplyV4.find(name);
+ if (it != ReplyV4.end()) {
+ return it->second;
+ }
+ break;
+ }
+ }
+ return TMockReply::Error(ARES_ENOTFOUND);
+ });
+ }
+
+ void Section(const TString& section) {
+ Section_ = section;
+ }
+
+ void Sleep(TDuration duration) {
+ Schedule(new IEventHandle(Sleeper, Sleeper, new TEvents::TEvWakeup), duration);
+ GrabEdgeEventRethrow<TEvents::TEvWakeup>(Sleeper);
+ }
+
+ void WaitNoInFlight() {
+ if (*InFlight6 || *InFlight4) {
+ TDispatchOptions options;
+ options.CustomFinalCondition = [&]() {
+ return !*InFlight6 && !*InFlight4;
+ };
+ DispatchEvents(options);
+ UNIT_ASSERT_C(!*InFlight6 && !*InFlight4, "Failed to wait for no inflight in " << Section_);
+ }
+ }
+
+ void SendGetHostByName(const TActorId& sender, const TString& name, int family = AF_UNSPEC) {
+ Send(new IEventHandle(Resolver, sender, new TEvDns::TEvGetHostByName(name, family)), 0, true);
+ }
+
+ void SendGetAddr(const TActorId& sender, const TString& name, int family = AF_UNSPEC) {
+ Send(new IEventHandle(Resolver, sender, new TEvDns::TEvGetAddr(name, family)), 0, true);
+ }
+
+ TEvDns::TEvGetHostByNameResult::TPtr WaitGetHostByName(const TActorId& sender) {
+ return GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
+ }
+
+ TEvDns::TEvGetAddrResult::TPtr WaitGetAddr(const TActorId& sender) {
+ return GrabEdgeEventRethrow<TEvDns::TEvGetAddrResult>(sender);
+ }
+
+ void ExpectInFlight6(i64 count) {
+ UNIT_ASSERT_VALUES_EQUAL_C(InFlight6->Val(), count, Section_);
+ }
+
+ void ExpectInFlight4(i64 count) {
+ UNIT_ASSERT_VALUES_EQUAL_C(InFlight4->Val(), count, Section_);
+ }
+
+ void ExpectTotal6(i64 count) {
+ UNIT_ASSERT_VALUES_EQUAL_C(Total6->Val(), count, Section_);
+ }
+
+ void ExpectTotal4(i64 count) {
+ UNIT_ASSERT_VALUES_EQUAL_C(Total4->Val(), count, Section_);
+ }
+
+ void Expect6(i64 total, i64 inflight) {
+ UNIT_ASSERT_C(
+ Total6->Val() == total && InFlight6->Val() == inflight,
+ Section_ << ": Expect6(" << total << ", " << inflight << ") "
+ << " but got (" << Total6->Val() << ", " << InFlight6->Val() << ")");
+ }
+
+ void Expect4(i64 total, i64 inflight) {
+ UNIT_ASSERT_C(
+ Total4->Val() == total && InFlight4->Val() == inflight,
+ Section_ << ": Expect4(" << total << ", " << inflight << ") "
+ << " got (" << Total4->Val() << ", " << InFlight4->Val() << ")");
+ }
+
+ void ExpectMisses(i64 count) {
+ UNIT_ASSERT_VALUES_EQUAL_C(Misses->Val(), count, Section_);
+ }
+
+ void ExpectHits(i64 count) {
+ UNIT_ASSERT_VALUES_EQUAL_C(Hits->Val(), count, Section_);
+ }
+
+ void ExpectGetHostByNameError(const TActorId& sender, int status) {
+ auto ev = WaitGetHostByName(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, status, Section_ << ": " << ev->Get()->ErrorText);
+ }
+
+ void ExpectGetAddrError(const TActorId& sender, int status) {
+ auto ev = WaitGetAddr(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, status, Section_ << ": " << ev->Get()->ErrorText);
+ }
+
+ void ExpectGetHostByNameSuccess(const TActorId& sender, const TString& expected) {
+ auto ev = WaitGetHostByName(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, Section_ << ": " << ev->Get()->ErrorText);
+ TStringBuilder result;
+ for (const auto& addr : ev->Get()->AddrsV6) {
+ if (result) {
+ result << ',';
+ }
+ result << TAddrToString()(addr);
+ }
+ for (const auto& addr : ev->Get()->AddrsV4) {
+ if (result) {
+ result << ',';
+ }
+ result << TAddrToString()(addr);
+ }
+ UNIT_ASSERT_VALUES_EQUAL_C(TString(result), expected, Section_);
+ }
+
+ void ExpectGetAddrSuccess(const TActorId& sender, const TString& expected) {
+ auto ev = WaitGetAddr(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, Section_ << ": " << ev->Get()->ErrorText);
+ TString result = AddrToString(ev->Get()->Addr);
+ UNIT_ASSERT_VALUES_EQUAL_C(result, expected, Section_);
+ }
+ };
+
+ Y_UNIT_TEST(UnusableResolver) {
+ TCachingDnsRuntime runtime;
+ runtime.Initialize();
+ runtime.Start();
+
+ auto sender = runtime.AllocateEdgeActor();
+
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+
+ runtime.Send(new IEventHandle(runtime.MockResolver, { }, new TEvents::TEvPoison), 0, true);
+ runtime.SendGetAddr(sender, "foo.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrError(sender, ARES_ENOTINITIALIZED);
+ }
+
+ Y_UNIT_TEST(ResolveCaching) {
+ TCachingDnsRuntime runtime;
+ runtime.Initialize();
+ runtime.Start();
+
+ auto sender = runtime.AllocateEdgeActor();
+
+ // First time resolve, ipv4 and ipv6 sent in parallel, we wait for ipv6 result
+ runtime.Section("First time resolve");
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+ runtime.Expect6(1, 0);
+ runtime.Expect4(1, 0);
+ runtime.ExpectMisses(1);
+ runtime.ExpectHits(0);
+
+ // Second resolve, ipv6 and ipv4 queries result in a cache hit
+ runtime.Section("Second resolve, ipv6");
+ runtime.SendGetAddr(sender, "yandex.ru", AF_INET6);
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+ runtime.Expect6(1, 0);
+ runtime.ExpectHits(1);
+ runtime.Section("Second resolve, ipv4");
+ runtime.SendGetAddr(sender, "yandex.ru", AF_INET);
+ runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
+ runtime.Expect4(1, 0);
+ runtime.ExpectHits(2);
+
+ // Wait until soft expiration and try ipv4 again
+ // Will cause a cache hit, but will start a new ipv4 request in background
+ runtime.Section("Retry ipv4 after soft expiration");
+ runtime.Sleep(TDuration::Seconds(15));
+ runtime.SendGetAddr(sender, "yandex.ru", AF_INET);
+ runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
+ runtime.Expect6(1, 0);
+ runtime.Expect4(2, 1);
+ runtime.ExpectMisses(1);
+ runtime.ExpectHits(3);
+ runtime.WaitNoInFlight();
+
+ // Wait until soft expiration and try both again
+ // Will cause a cache hit, but will start a new ipv6 request in background
+ runtime.Section("Retry both after soft expiration");
+ runtime.Sleep(TDuration::Seconds(15));
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+ runtime.Expect6(2, 1);
+ runtime.Expect4(2, 0);
+ runtime.ExpectMisses(1);
+ runtime.ExpectHits(4);
+ runtime.WaitNoInFlight();
+
+ // Wait until hard expiration and try both again
+ // Will cause a cache miss and new resolve requests
+ runtime.Section("Retry both after hard expiration");
+ runtime.Sleep(TDuration::Hours(2));
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+ runtime.Expect6(3, 0);
+ runtime.Expect4(3, 0);
+ runtime.ExpectMisses(2);
+ runtime.ExpectHits(4);
+
+ // Wait half the hard expiration time, must always result in a cache hit
+ runtime.Section("Retry both after half hard expiration");
+ for (ui64 i = 1; i <= 4; ++i) {
+ runtime.Sleep(TDuration::Hours(1));
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+ runtime.Expect6(3 + i, 1);
+ runtime.ExpectHits(4 + i);
+ runtime.WaitNoInFlight();
+ }
+
+ // Change v6 result to a timeout, must keep using cached result until hard expiration
+ runtime.Section("Dns keeps timing out");
+ runtime.ReplyV6["yandex.ru"] = TMockReply::Error(ARES_ETIMEOUT);
+ for (ui64 i = 1; i <= 4; ++i) {
+ runtime.Sleep(TDuration::Seconds(15));
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+ runtime.Expect6(7 + i, 1);
+ runtime.ExpectHits(8 + i);
+ runtime.WaitNoInFlight();
+ }
+
+ // Change v6 result to nodata, must switch to a v4 result eventually
+ runtime.Section("Host changes to being ipv4 only");
+ runtime.ReplyV6["yandex.ru"] = TMockReply::Error(ARES_ENODATA);
+ runtime.Sleep(TDuration::Seconds(2));
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+ runtime.WaitNoInFlight();
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
+ runtime.Expect6(12, 0);
+ runtime.Expect4(4, 0);
+ runtime.ExpectMisses(3);
+
+ // Change v6 result to nxdomain, must not fall back to a v4 result
+ runtime.Section("Host is removed from dns");
+ runtime.ReplyV6["yandex.ru"] = TMockReply::Error(ARES_ENOTFOUND);
+ runtime.Sleep(TDuration::Seconds(15));
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
+ runtime.WaitNoInFlight();
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
+ }
+
+ Y_UNIT_TEST(ResolveCachingV4) {
+ TCachingDnsRuntime runtime;
+ runtime.Initialize();
+ runtime.Start();
+
+ auto sender = runtime.AllocateEdgeActor();
+
+ runtime.Section("First request");
+ runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
+ runtime.ExpectMisses(1);
+
+ runtime.Section("Second request");
+ runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
+ runtime.ExpectHits(1);
+
+ runtime.Section("Dns keeps timing out");
+ runtime.ReplyV6["router.asus.com"] = TMockReply::Error(ARES_ETIMEOUT);
+ runtime.ReplyV4["router.asus.com"] = TMockReply::Error(ARES_ETIMEOUT);
+ for (ui64 i = 1; i <= 4; ++i) {
+ runtime.Sleep(TDuration::Seconds(15));
+ runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
+ runtime.Expect6(1 + i, 1);
+ runtime.Expect4(1 + i, 1);
+ runtime.ExpectHits(1 + i);
+ runtime.WaitNoInFlight();
+ }
+
+ runtime.Section("Host is removed from ipv4 dns");
+ runtime.ReplyV4["router.asus.com"] = TMockReply::Error(ARES_ENOTFOUND);
+ runtime.Sleep(TDuration::Seconds(15));
+ runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
+ runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
+ runtime.WaitNoInFlight();
+ runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
+ runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
+ }
+
+ Y_UNIT_TEST(EventualTimeout) {
+ TCachingDnsRuntime runtime;
+ runtime.Initialize();
+ runtime.Start();
+
+ auto sender = runtime.AllocateEdgeActor();
+
+ runtime.ReplyV6["notfound.ru"] = TMockReply::Error(ARES_ENODATA);
+ runtime.ReplyV4["notfound.ru"] = TMockReply::Error(ARES_ENOTFOUND);
+ runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
+
+ runtime.ReplyV4["notfound.ru"] = TMockReply::Error(ARES_ETIMEOUT);
+ runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
+ runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
+ runtime.WaitNoInFlight();
+
+ bool timeout = false;
+ for (ui64 i = 1; i <= 8; ++i) {
+ runtime.Sleep(TDuration::Minutes(30));
+ runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
+ auto ev = runtime.WaitGetAddr(sender);
+ if (ev->Get()->Status == ARES_ETIMEOUT && i > 2) {
+ timeout = true;
+ break;
+ }
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, ARES_ENOTFOUND,
+ "Iteration " << i << ": " << ev->Get()->ErrorText);
+ }
+
+ UNIT_ASSERT_C(timeout, "DnsResolver did not reply with a timeout");
+ }
+
+ Y_UNIT_TEST(MultipleRequestsAndHosts) {
+ TCachingDnsRuntime runtime;
+ runtime.Initialize();
+ runtime.Start();
+
+ auto sender = runtime.AllocateEdgeActor();
+
+ runtime.SendGetHostByName(sender, "router.asus.com", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
+ runtime.SendGetHostByName(sender, "yandex.ru", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetHostByNameSuccess(sender, "192.168.0.1");
+ runtime.ExpectGetAddrSuccess(sender, "192.168.0.1");
+ runtime.ExpectGetHostByNameSuccess(sender, "2a02:6b8:a::a");
+ runtime.ExpectGetAddrSuccess(sender, "2a02:6b8:a::a");
+
+ runtime.SendGetHostByName(sender, "notfound.ru", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
+ runtime.ExpectGetHostByNameError(sender, ARES_ENOTFOUND);
+ runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
+ }
+
+ Y_UNIT_TEST(DisabledIPv6) {
+ TCachingDnsRuntime runtime;
+ runtime.ResolverOptions.AllowIPv6 = false;
+ runtime.Initialize();
+ runtime.Start();
+
+ auto sender = runtime.AllocateEdgeActor();
+
+ runtime.SendGetHostByName(sender, "yandex.ru", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetHostByNameSuccess(sender, "77.88.55.77");
+ runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
+
+ runtime.SendGetHostByName(sender, "yandex.ru", AF_INET6);
+ runtime.SendGetAddr(sender, "yandex.ru", AF_INET6);
+ runtime.ExpectGetHostByNameError(sender, ARES_EBADFAMILY);
+ runtime.ExpectGetAddrError(sender, ARES_EBADFAMILY);
+
+ runtime.SendGetHostByName(sender, "yandex.ru", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.ExpectGetHostByNameSuccess(sender, "77.88.55.77");
+ runtime.ExpectGetAddrSuccess(sender, "77.88.55.77");
+
+ runtime.SendGetHostByName(sender, "notfound.ru", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
+ runtime.ExpectGetHostByNameError(sender, ARES_ENOTFOUND);
+ runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
+ }
+
+ Y_UNIT_TEST(DisabledIPv4) {
+ TCachingDnsRuntime runtime;
+ runtime.ResolverOptions.AllowIPv4 = false;
+ runtime.Initialize();
+ runtime.Start();
+
+ auto sender = runtime.AllocateEdgeActor();
+
+ runtime.SendGetHostByName(sender, "router.asus.com", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
+ runtime.ExpectGetHostByNameError(sender, ARES_ENODATA);
+ runtime.ExpectGetAddrError(sender, ARES_ENODATA);
+
+ runtime.SendGetHostByName(sender, "router.asus.com", AF_INET);
+ runtime.SendGetAddr(sender, "router.asus.com", AF_INET);
+ runtime.ExpectGetHostByNameError(sender, ARES_EBADFAMILY);
+ runtime.ExpectGetAddrError(sender, ARES_EBADFAMILY);
+
+ runtime.SendGetHostByName(sender, "router.asus.com", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "router.asus.com", AF_UNSPEC);
+ runtime.ExpectGetHostByNameError(sender, ARES_ENODATA);
+ runtime.ExpectGetAddrError(sender, ARES_ENODATA);
+
+ runtime.SendGetHostByName(sender, "notfound.ru", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "notfound.ru", AF_UNSPEC);
+ runtime.ExpectGetHostByNameError(sender, ARES_ENOTFOUND);
+ runtime.ExpectGetAddrError(sender, ARES_ENOTFOUND);
+ }
+
+ Y_UNIT_TEST(PoisonPill) {
+ TCachingDnsRuntime runtime;
+ runtime.Initialize();
+ runtime.Start();
+
+ auto sender = runtime.AllocateEdgeActor();
+
+ runtime.SendGetHostByName(sender, "yandex.ru", AF_UNSPEC);
+ runtime.SendGetAddr(sender, "yandex.ru", AF_UNSPEC);
+ runtime.Send(new IEventHandle(runtime.Resolver, sender, new TEvents::TEvPoison), 0, true);
+ runtime.ExpectGetHostByNameError(sender, ARES_ECANCELLED);
+ runtime.ExpectGetAddrError(sender, ARES_ECANCELLED);
+ }
+
+}
diff --git a/library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp b/library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp
new file mode 100644
index 0000000000..2025162e95
--- /dev/null
+++ b/library/cpp/actors/dnsresolver/dnsresolver_ondemand.cpp
@@ -0,0 +1,64 @@
+#include "dnsresolver.h"
+
+#include <library/cpp/actors/core/hfunc.h>
+
+namespace NActors {
+namespace NDnsResolver {
+
+ class TOnDemandDnsResolver : public TActor<TOnDemandDnsResolver> {
+ public:
+ TOnDemandDnsResolver(TOnDemandDnsResolverOptions options)
+ : TActor(&TThis::StateWork)
+ , Options(std::move(options))
+ { }
+
+ static constexpr EActivityType ActorActivityType() {
+ return DNS_RESOLVER;
+ }
+
+ private:
+ STRICT_STFUNC(StateWork, {
+ cFunc(TEvents::TEvPoison::EventType, PassAway);
+ fFunc(TEvDns::TEvGetHostByName::EventType, Forward);
+ fFunc(TEvDns::TEvGetAddr::EventType, Forward);
+ });
+
+ void Forward(STATEFN_SIG) {
+ ev->Rewrite(ev->GetTypeRewrite(), GetUpstream());
+ TActivationContext::Send(std::move(ev));
+ }
+
+ private:
+ TActorId GetUpstream() {
+ if (Y_UNLIKELY(!CachingResolverId)) {
+ if (Y_LIKELY(!SimpleResolverId)) {
+ SimpleResolverId = RegisterWithSameMailbox(CreateSimpleDnsResolver(Options));
+ }
+ CachingResolverId = RegisterWithSameMailbox(CreateCachingDnsResolver(SimpleResolverId, Options));
+ }
+ return CachingResolverId;
+ }
+
+ void PassAway() override {
+ if (CachingResolverId) {
+ Send(CachingResolverId, new TEvents::TEvPoison);
+ CachingResolverId = { };
+ }
+ if (SimpleResolverId) {
+ Send(SimpleResolverId, new TEvents::TEvPoison);
+ SimpleResolverId = { };
+ }
+ }
+
+ private:
+ TOnDemandDnsResolverOptions Options;
+ TActorId SimpleResolverId;
+ TActorId CachingResolverId;
+ };
+
+ IActor* CreateOnDemandDnsResolver(TOnDemandDnsResolverOptions options) {
+ return new TOnDemandDnsResolver(std::move(options));
+ }
+
+} // namespace NDnsResolver
+} // namespace NActors
diff --git a/library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp b/library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp
new file mode 100644
index 0000000000..2758484552
--- /dev/null
+++ b/library/cpp/actors/dnsresolver/dnsresolver_ondemand_ut.cpp
@@ -0,0 +1,24 @@
+#include "dnsresolver.h"
+
+#include <library/cpp/actors/testlib/test_runtime.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NActors;
+using namespace NActors::NDnsResolver;
+
+Y_UNIT_TEST_SUITE(OnDemandDnsResolver) {
+
+ Y_UNIT_TEST(ResolveLocalHost) {
+ TTestActorRuntimeBase runtime;
+ runtime.Initialize();
+ auto sender = runtime.AllocateEdgeActor();
+ auto resolver = runtime.Register(CreateOnDemandDnsResolver());
+ runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("localhost", AF_UNSPEC)),
+ 0, true);
+ auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
+ size_t addrs = ev->Get()->AddrsV4.size() + ev->Get()->AddrsV6.size();
+ UNIT_ASSERT_C(addrs > 0, "Got " << addrs << " addresses");
+ }
+
+}
diff --git a/library/cpp/actors/dnsresolver/dnsresolver_ut.cpp b/library/cpp/actors/dnsresolver/dnsresolver_ut.cpp
new file mode 100644
index 0000000000..0c343a805c
--- /dev/null
+++ b/library/cpp/actors/dnsresolver/dnsresolver_ut.cpp
@@ -0,0 +1,98 @@
+#include "dnsresolver.h"
+
+#include <library/cpp/actors/testlib/test_runtime.h>
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/string/builder.h>
+
+#include <ares.h>
+
+using namespace NActors;
+using namespace NActors::NDnsResolver;
+
+Y_UNIT_TEST_SUITE(DnsResolver) {
+
+ struct TSilentUdpServer {
+ TInetDgramSocket Socket;
+ ui16 Port;
+
+ TSilentUdpServer() {
+ TSockAddrInet addr("127.0.0.1", 0);
+ int err = Socket.Bind(&addr);
+ Y_VERIFY(err == 0, "Cannot bind a udp socket");
+ Port = addr.GetPort();
+ }
+ };
+
+ Y_UNIT_TEST(ResolveLocalHost) {
+ TTestActorRuntimeBase runtime;
+ runtime.Initialize();
+ auto sender = runtime.AllocateEdgeActor();
+ auto resolver = runtime.Register(CreateSimpleDnsResolver());
+ runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("localhost", AF_UNSPEC)),
+ 0, true);
+ auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
+ size_t addrs = ev->Get()->AddrsV4.size() + ev->Get()->AddrsV6.size();
+ UNIT_ASSERT_C(addrs > 0, "Got " << addrs << " addresses");
+ }
+
+ Y_UNIT_TEST(ResolveYandexRu) {
+ TTestActorRuntimeBase runtime;
+ runtime.Initialize();
+ auto sender = runtime.AllocateEdgeActor();
+ auto resolver = runtime.Register(CreateSimpleDnsResolver());
+ runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("yandex.ru", AF_UNSPEC)),
+ 0, true);
+ auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
+ size_t addrs = ev->Get()->AddrsV4.size() + ev->Get()->AddrsV6.size();
+ UNIT_ASSERT_C(addrs > 0, "Got " << addrs << " addresses");
+ }
+
+ Y_UNIT_TEST(GetAddrYandexRu) {
+ TTestActorRuntimeBase runtime;
+ runtime.Initialize();
+ auto sender = runtime.AllocateEdgeActor();
+ auto resolver = runtime.Register(CreateSimpleDnsResolver());
+
+ runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetAddr("yandex.ru", AF_UNSPEC)),
+ 0, true);
+ auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetAddrResult>(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, 0, ev->Get()->ErrorText);
+ UNIT_ASSERT_C(ev->Get()->IsV4() || ev->Get()->IsV6(), "Expect v4 or v6 address");
+ }
+
+ Y_UNIT_TEST(ResolveTimeout) {
+ TSilentUdpServer server;
+ TTestActorRuntimeBase runtime;
+ runtime.Initialize();
+ auto sender = runtime.AllocateEdgeActor();
+ TSimpleDnsResolverOptions options;
+ options.Timeout = TDuration::MilliSeconds(250);
+ options.Attempts = 2;
+ options.Servers.emplace_back(TStringBuilder() << "127.0.0.1:" << server.Port);
+ auto resolver = runtime.Register(CreateSimpleDnsResolver(options));
+ runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("timeout.yandex.ru", AF_INET)),
+ 0, true);
+ auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, ARES_ETIMEOUT, ev->Get()->ErrorText);
+ }
+
+ Y_UNIT_TEST(ResolveGracefulStop) {
+ TSilentUdpServer server;
+ TTestActorRuntimeBase runtime;
+ runtime.Initialize();
+ auto sender = runtime.AllocateEdgeActor();
+ TSimpleDnsResolverOptions options;
+ options.Timeout = TDuration::Seconds(5);
+ options.Attempts = 5;
+ options.Servers.emplace_back(TStringBuilder() << "127.0.0.1:" << server.Port);
+ auto resolver = runtime.Register(CreateSimpleDnsResolver(options));
+ runtime.Send(new IEventHandle(resolver, sender, new TEvDns::TEvGetHostByName("timeout.yandex.ru", AF_INET)),
+ 0, true);
+ runtime.Send(new IEventHandle(resolver, sender, new TEvents::TEvPoison), 0, true);
+ auto ev = runtime.GrabEdgeEventRethrow<TEvDns::TEvGetHostByNameResult>(sender);
+ UNIT_ASSERT_VALUES_EQUAL_C(ev->Get()->Status, ARES_ECANCELLED, ev->Get()->ErrorText);
+ }
+
+}
diff --git a/library/cpp/actors/dnsresolver/ut/ya.make b/library/cpp/actors/dnsresolver/ut/ya.make
new file mode 100644
index 0000000000..ad936bdacd
--- /dev/null
+++ b/library/cpp/actors/dnsresolver/ut/ya.make
@@ -0,0 +1,20 @@
+UNITTEST_FOR(library/cpp/actors/dnsresolver)
+
+OWNER(g:kikimr)
+
+PEERDIR(
+ library/cpp/actors/testlib
+)
+
+SRCS(
+ dnsresolver_caching_ut.cpp
+ dnsresolver_ondemand_ut.cpp
+ dnsresolver_ut.cpp
+)
+
+ADDINCL(contrib/libs/c-ares)
+
+TAG(ya:external)
+REQUIREMENTS(network:full)
+
+END()
diff --git a/library/cpp/actors/dnsresolver/ya.make b/library/cpp/actors/dnsresolver/ya.make
new file mode 100644
index 0000000000..329c56c5b3
--- /dev/null
+++ b/library/cpp/actors/dnsresolver/ya.make
@@ -0,0 +1,20 @@
+LIBRARY()
+
+OWNER(g:kikimr)
+
+SRCS(
+ dnsresolver.cpp
+ dnsresolver_caching.cpp
+ dnsresolver_ondemand.cpp
+)
+
+PEERDIR(
+ library/cpp/actors/core
+ contrib/libs/c-ares
+)
+
+ADDINCL(contrib/libs/c-ares)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/actors/helpers/activeactors.cpp b/library/cpp/actors/helpers/activeactors.cpp
new file mode 100644
index 0000000000..145e97dc57
--- /dev/null
+++ b/library/cpp/actors/helpers/activeactors.cpp
@@ -0,0 +1,2 @@
+#include "activeactors.h"
+
diff --git a/library/cpp/actors/helpers/activeactors.h b/library/cpp/actors/helpers/activeactors.h
new file mode 100644
index 0000000000..0fdb0fab10
--- /dev/null
+++ b/library/cpp/actors/helpers/activeactors.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <library/cpp/actors/core/actor.h>
+#include <library/cpp/actors/core/events.h>
+#include <util/generic/hash_set.h>
+
+namespace NActors {
+
+ ////////////////////////////////////////////////////////////////////////////
+ // TActiveActors
+ // This class helps manage created actors and kill them all on PoisonPill.
+ ////////////////////////////////////////////////////////////////////////////
+ class TActiveActors : public THashSet<TActorId> {
+ public:
+ void Insert(const TActorId &aid) {
+ bool inserted = insert(aid).second;
+ Y_VERIFY(inserted);
+ }
+
+ void Insert(const TActiveActors &moreActors) {
+ for (const auto &aid : moreActors) {
+ Insert(aid);
+ }
+ }
+
+ void Erase(const TActorId &aid) {
+ auto num = erase(aid);
+ Y_VERIFY(num == 1);
+ }
+
+ size_t KillAndClear(const TActorContext &ctx) {
+ size_t s = size(); // number of actors managed
+ for (const auto &x: *this) {
+ ctx.Send(x, new TEvents::TEvPoisonPill());
+ }
+ clear();
+ return s; // how many actors we killed
+ }
+ };
+
+} // NKikimr
+
diff --git a/library/cpp/actors/helpers/flow_controlled_queue.cpp b/library/cpp/actors/helpers/flow_controlled_queue.cpp
new file mode 100644
index 0000000000..d75cc54023
--- /dev/null
+++ b/library/cpp/actors/helpers/flow_controlled_queue.cpp
@@ -0,0 +1,215 @@
+#include "flow_controlled_queue.h"
+
+#include <library/cpp/actors/core/interconnect.h>
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/actors/util/datetime.h>
+
+#include <util/generic/deque.h>
+#include <util/datetime/cputimer.h>
+#include <util/generic/algorithm.h>
+
+namespace NActors {
+
+class TFlowControlledRequestQueue;
+
+class TFlowControlledRequestActor : public IActor {
+ TFlowControlledRequestQueue * const QueueActor;
+
+ void HandleReply(TAutoPtr<IEventHandle> &ev);
+ void HandleUndelivered(TEvents::TEvUndelivered::TPtr &ev);
+public:
+ const TActorId Source;
+ const ui64 Cookie;
+ const ui32 Flags;
+ const ui64 StartCounter;
+
+ TFlowControlledRequestActor(ui32 activity, TFlowControlledRequestQueue *queue, TActorId source, ui64 cookie, ui32 flags)
+ : IActor(static_cast<TReceiveFunc>(&TFlowControlledRequestActor::StateWait), activity)
+ , QueueActor(queue)
+ , Source(source)
+ , Cookie(cookie)
+ , Flags(flags)
+ , StartCounter(GetCycleCountFast())
+ {}
+
+ STATEFN(StateWait) {
+ switch (ev->GetTypeRewrite()) {
+ hFunc(TEvents::TEvUndelivered, HandleUndelivered);
+ default:
+ HandleReply(ev);
+ }
+ }
+
+ TDuration AccumulatedLatency() const {
+ const ui64 cc = GetCycleCountFast() - StartCounter;
+ return CyclesToDuration(cc);
+ }
+
+ using IActor::PassAway;
+};
+
+class TFlowControlledRequestQueue : public IActor {
+ const TActorId Target;
+ const TFlowControlledQueueConfig Config;
+
+ TDeque<THolder<IEventHandle>> UnhandledRequests;
+ TDeque<TFlowControlledRequestActor *> RegisteredRequests;
+
+ bool Subscribed = false;
+
+ TDuration MinimalSeenLatency;
+
+ bool CanRegister() {
+ const ui64 inFly = RegisteredRequests.size();
+ if (inFly <= Config.MinAllowedInFly) // <= for handling minAllowed == 0
+ return true;
+
+ if (inFly >= Config.MaxAllowedInFly)
+ return false;
+
+ if (Config.TargetDynamicRate) {
+ if (const ui64 dynMax = MinimalSeenLatency.MicroSeconds() * Config.TargetDynamicRate / 1000000) {
+ if (inFly >= dynMax)
+ return false;
+ }
+ }
+
+ const TDuration currentLatency = RegisteredRequests.front()->AccumulatedLatency();
+ if (currentLatency <= Config.MinTrackedLatency)
+ return true;
+
+ if (currentLatency <= MinimalSeenLatency * Config.LatencyFactor)
+ return true;
+
+ return false;
+ }
+
+ void HandleForwardedEvent(TAutoPtr<IEventHandle> &ev) {
+ if (CanRegister()) {
+ RegisterReqActor(ev);
+ } else {
+ UnhandledRequests.emplace_back(ev.Release());
+ }
+ }
+
+ void RegisterReqActor(THolder<IEventHandle> ev) {
+ TFlowControlledRequestActor *reqActor = new TFlowControlledRequestActor(ActivityType, this, ev->Sender, ev->Cookie, ev->Flags);
+ const TActorId reqActorId = RegisterWithSameMailbox(reqActor);
+ RegisteredRequests.emplace_back(reqActor);
+
+ if (!Subscribed && (Target.NodeId() != SelfId().NodeId())) {
+ Send(TActivationContext::InterconnectProxy(Target.NodeId()), new TEvents::TEvSubscribe(), IEventHandle::FlagTrackDelivery);
+ Subscribed = true;
+ }
+
+ TActivationContext::Send(new IEventHandle(Target, reqActorId, ev->ReleaseBase().Release(), IEventHandle::FlagTrackDelivery, ev->Cookie));
+ }
+
+ void PumpQueue() {
+ while (RegisteredRequests && RegisteredRequests.front() == nullptr)
+ RegisteredRequests.pop_front();
+
+ while (UnhandledRequests && CanRegister()) {
+ RegisterReqActor(std::move(UnhandledRequests.front()));
+ UnhandledRequests.pop_front();
+ }
+ }
+
+ void HandleDisconnected() {
+ Subscribed = false;
+
+ const ui32 nodeid = Target.NodeId();
+ for (TFlowControlledRequestActor *reqActor : RegisteredRequests) {
+ if (reqActor) {
+ if (reqActor->Flags & IEventHandle::FlagSubscribeOnSession) {
+ TActivationContext::Send(
+ new IEventHandle(reqActor->Source, TActorId(), new TEvInterconnect::TEvNodeDisconnected(nodeid), 0, reqActor->Cookie)
+ );
+ }
+ reqActor->PassAway();
+ }
+ }
+
+ RegisteredRequests.clear();
+
+ for (auto &ev : UnhandledRequests) {
+ const auto reason = TEvents::TEvUndelivered::Disconnected;
+ if (ev->Flags & IEventHandle::FlagTrackDelivery) {
+ TActivationContext::Send(
+ new IEventHandle(ev->Sender, ev->Recipient, new TEvents::TEvUndelivered(ev->GetTypeRewrite(), reason), 0, ev->Cookie)
+ );
+ }
+ }
+
+ UnhandledRequests.clear();
+ }
+
+ void HandlePoison() {
+ HandleDisconnected();
+
+ if (SelfId().NodeId() != Target.NodeId())
+ Send(TActivationContext::InterconnectProxy(Target.NodeId()), new TEvents::TEvUnsubscribe());
+
+ PassAway();
+ }
+public:
+ TFlowControlledRequestQueue(TActorId target, ui32 activity, const TFlowControlledQueueConfig &config)
+ : IActor(static_cast<TReceiveFunc>(&TFlowControlledRequestQueue::StateWork), activity)
+ , Target(target)
+ , Config(config)
+ , MinimalSeenLatency(TDuration::Seconds(1))
+ {}
+
+ STATEFN(StateWork) {
+ switch (ev->GetTypeRewrite()) {
+ cFunc(TEvInterconnect::TEvNodeDisconnected::EventType, HandleDisconnected);
+ IgnoreFunc(TEvInterconnect::TEvNodeConnected);
+ cFunc(TEvents::TEvUndelivered::EventType, HandleDisconnected);
+ cFunc(TEvents::TEvPoison::EventType, HandlePoison);
+ default:
+ HandleForwardedEvent(ev);
+ }
+ }
+
+ void HandleRequestReply(TAutoPtr<IEventHandle> &ev, TFlowControlledRequestActor *reqActor) {
+ auto it = Find(RegisteredRequests, reqActor);
+ if (it == RegisteredRequests.end())
+ return;
+
+ TActivationContext::Send(ev->Forward(reqActor->Source));
+ const TDuration reqLatency = reqActor->AccumulatedLatency();
+ if (reqLatency < MinimalSeenLatency)
+ MinimalSeenLatency = reqLatency;
+
+ *it = nullptr;
+ PumpQueue();
+ }
+
+ void HandleRequestUndelivered(TEvents::TEvUndelivered::TPtr &ev, TFlowControlledRequestActor *reqActor) {
+ auto it = Find(RegisteredRequests, reqActor);
+ if (it == RegisteredRequests.end())
+ return;
+
+ TActivationContext::Send(ev->Forward(reqActor->Source));
+
+ *it = nullptr;
+ PumpQueue();
+ }
+};
+
+void TFlowControlledRequestActor::HandleReply(TAutoPtr<IEventHandle> &ev) {
+ QueueActor->HandleRequestReply(ev, this);
+ PassAway();
+}
+
+void TFlowControlledRequestActor::HandleUndelivered(TEvents::TEvUndelivered::TPtr &ev) {
+ QueueActor->HandleRequestUndelivered(ev, this);
+ PassAway();
+}
+
+
+IActor* CreateFlowControlledRequestQueue(TActorId targetId, ui32 activity, const TFlowControlledQueueConfig &config) {
+ return new TFlowControlledRequestQueue(targetId, activity, config);
+}
+
+}
diff --git a/library/cpp/actors/helpers/flow_controlled_queue.h b/library/cpp/actors/helpers/flow_controlled_queue.h
new file mode 100644
index 0000000000..d250405304
--- /dev/null
+++ b/library/cpp/actors/helpers/flow_controlled_queue.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <library/cpp/actors/core/actor.h>
+
+namespace NActors {
+
+ struct TFlowControlledQueueConfig {
+ ui32 MinAllowedInFly = 20;
+ ui32 MaxAllowedInFly = 100;
+ ui32 TargetDynamicRate = 0;
+
+ TDuration MinTrackedLatency = TDuration::MilliSeconds(20);
+ ui32 LatencyFactor = 4;
+ };
+
+ IActor* CreateFlowControlledRequestQueue(TActorId targetId, ui32 activity = IActor::ACTORLIB_COMMON, const TFlowControlledQueueConfig &config = TFlowControlledQueueConfig());
+
+}
diff --git a/library/cpp/actors/helpers/future_callback.h b/library/cpp/actors/helpers/future_callback.h
new file mode 100644
index 0000000000..8ca0d99fda
--- /dev/null
+++ b/library/cpp/actors/helpers/future_callback.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <library/cpp/actors/core/actor.h>
+#include <library/cpp/actors/core/hfunc.h>
+
+namespace NActors {
+
+template <typename EventType>
+struct TActorFutureCallback : TActor<TActorFutureCallback<EventType>> {
+ using TCallback = std::function<void(TAutoPtr<TEventHandle<EventType>>&)>;
+ using TBase = TActor<TActorFutureCallback<EventType>>;
+ TCallback Callback;
+
+ static constexpr IActor::EActivityType ActorActivityType() {
+ return IActor::ACTOR_FUTURE_CALLBACK;
+ }
+
+ TActorFutureCallback(TCallback&& callback)
+ : TBase(&TActorFutureCallback::StateWaitForEvent)
+ , Callback(std::move(callback))
+ {}
+
+ STRICT_STFUNC(StateWaitForEvent,
+ HFunc(EventType, Handle)
+ )
+
+ void Handle(typename EventType::TPtr ev, const TActorContext& ctx) {
+ Callback(ev);
+ TBase::Die(ctx);
+ }
+};
+
+} // NActors
diff --git a/library/cpp/actors/helpers/mon_histogram_helper.h b/library/cpp/actors/helpers/mon_histogram_helper.h
new file mode 100644
index 0000000000..a9a57e3823
--- /dev/null
+++ b/library/cpp/actors/helpers/mon_histogram_helper.h
@@ -0,0 +1,86 @@
+#pragma once
+
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+
+#include <util/string/cast.h>
+
+namespace NActors {
+ namespace NMon {
+ class THistogramCounterHelper {
+ public:
+ THistogramCounterHelper()
+ : FirstBucketVal(0)
+ , BucketCount(0)
+ {
+ }
+
+ THistogramCounterHelper(const THistogramCounterHelper&) = default;
+
+ void Init(NMonitoring::TDynamicCounters* group, const TString& baseName, const TString& unit,
+ ui64 firstBucket, ui64 bucketCnt, bool useSensorLabelName = true)
+ {
+ Y_ASSERT(FirstBucketVal == 0);
+ Y_ASSERT(BucketCount == 0);
+
+ FirstBucketVal = firstBucket;
+ BucketCount = bucketCnt;
+ BucketsHolder.reserve(BucketCount);
+ Buckets.reserve(BucketCount);
+ for (size_t i = 0; i < BucketCount; ++i) {
+ TString bucketName = GetBucketName(i) + " " + unit;
+ auto labelName = useSensorLabelName ? "sensor" : "name";
+ BucketsHolder.push_back(group->GetSubgroup(labelName, baseName)->GetNamedCounter("range", bucketName, true));
+ Buckets.push_back(BucketsHolder.back().Get());
+ }
+ }
+
+ void Add(ui64 val) {
+ Y_ASSERT(FirstBucketVal != 0);
+ Y_ASSERT(BucketCount != 0);
+ Y_VERIFY(val <= (1ULL << 63ULL));
+ size_t ind = 0;
+ if (val > FirstBucketVal) {
+ ind = GetValueBitCount((2 * val - 1) / FirstBucketVal) - 1;
+ if (ind >= BucketCount) {
+ ind = BucketCount - 1;
+ }
+ }
+ Buckets[ind]->Inc();
+ }
+
+ ui64 GetBucketCount() const {
+ return BucketCount;
+ }
+
+ ui64 GetBucketValue(size_t index) const {
+ Y_ASSERT(index < BucketCount);
+ return Buckets[index]->Val();
+ }
+
+ void SetBucketValue(ui64 index, ui64 value) {
+ Y_ASSERT(index < BucketCount);
+ *Buckets[index] = value;
+ }
+
+ private:
+ TString GetBucketName(size_t ind) const {
+ Y_ASSERT(FirstBucketVal != 0);
+ Y_ASSERT(BucketCount != 0);
+ Y_ASSERT(ind < BucketCount);
+ if (ind + 1 < BucketCount) {
+ return ToString<ui64>(FirstBucketVal << ind);
+ } else {
+ // Last slot is up to +INF
+ return "INF";
+ }
+ }
+
+ private:
+ ui64 FirstBucketVal;
+ ui64 BucketCount;
+ TVector<NMonitoring::TDynamicCounters::TCounterPtr> BucketsHolder;
+ TVector<NMonitoring::TDeprecatedCounter*> Buckets;
+ };
+
+ }
+}
diff --git a/library/cpp/actors/helpers/pool_stats_collector.h b/library/cpp/actors/helpers/pool_stats_collector.h
new file mode 100644
index 0000000000..61d0b45780
--- /dev/null
+++ b/library/cpp/actors/helpers/pool_stats_collector.h
@@ -0,0 +1,314 @@
+#pragma once
+
+#include <library/cpp/actors/core/actor_bootstrapped.h>
+#include <library/cpp/actors/core/actorsystem.h>
+#include <library/cpp/actors/core/executor_thread.h>
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+
+#include <util/generic/vector.h>
+#include <util/generic/xrange.h>
+#include <util/string/printf.h>
+
+namespace NActors {
+
+// Periodically collects stats from executor threads and exposes them as mon counters
+class TStatsCollectingActor : public TActorBootstrapped<TStatsCollectingActor> {
+private:
+ struct THistogramCounters {
+ void Init(NMonitoring::TDynamicCounters* group, const TString& baseName, const TString& unit, ui64 maxVal) {
+ for (size_t i = 0; (1ull<<i) <= maxVal; ++i) {
+ TString bucketName = ToString(1ull<<i) + " " + unit;
+ Buckets.push_back(group->GetSubgroup("sensor", baseName)->GetNamedCounter("range", bucketName, true));
+ }
+ Buckets.push_back(group->GetSubgroup("sensor", baseName)->GetNamedCounter("range", "INF", true));
+ }
+
+ void Set(const TLogHistogram& data) {
+ ui32 i = 0;
+ for (;i < Y_ARRAY_SIZE(data.Buckets) && i < Buckets.size()-1; ++i)
+ *Buckets[i] = data.Buckets[i];
+ ui64 last = 0;
+ for (;i < Y_ARRAY_SIZE(data.Buckets); ++i)
+ last += data.Buckets[i];
+ *Buckets.back() = last;
+ }
+
+ void Set(const TLogHistogram& data, double factor) {
+ ui32 i = 0;
+ for (;i < Y_ARRAY_SIZE(data.Buckets) && i < Buckets.size()-1; ++i)
+ *Buckets[i] = data.Buckets[i]*factor;
+ ui64 last = 0;
+ for (;i < Y_ARRAY_SIZE(data.Buckets); ++i)
+ last += data.Buckets[i];
+ *Buckets.back() = last*factor;
+ }
+
+ private:
+ TVector<NMonitoring::TDynamicCounters::TCounterPtr> Buckets;
+ };
+
+ struct TActivityStats {
+ void Init(NMonitoring::TDynamicCounterPtr group) {
+ Group = group;
+
+ ElapsedMicrosecByActivityBuckets.resize(GetActivityTypeCount());
+ ReceivedEventsByActivityBuckets.resize(GetActivityTypeCount());
+ ActorsAliveByActivityBuckets.resize(GetActivityTypeCount());
+ ScheduledEventsByActivityBuckets.resize(GetActivityTypeCount());
+ }
+
+ void Set(const TExecutorThreadStats& stats) {
+ for (ui32 i : xrange(stats.MaxActivityType())) {
+ Y_VERIFY(i < GetActivityTypeCount());
+ ui64 ticks = stats.ElapsedTicksByActivity[i];
+ ui64 events = stats.ReceivedEventsByActivity[i];
+ ui64 actors = stats.ActorsAliveByActivity[i];
+ ui64 scheduled = stats.ScheduledEventsByActivity[i];
+
+ if (!ActorsAliveByActivityBuckets[i]) {
+ if (ticks || events || actors || scheduled) {
+ InitCountersForActivity(i);
+ } else {
+ continue;
+ }
+ }
+
+ *ElapsedMicrosecByActivityBuckets[i] = ::NHPTimer::GetSeconds(ticks)*1000000;
+ *ReceivedEventsByActivityBuckets[i] = events;
+ *ActorsAliveByActivityBuckets[i] = actors;
+ *ScheduledEventsByActivityBuckets[i] = scheduled;
+ }
+ }
+
+ private:
+ void InitCountersForActivity(ui32 activityType) {
+ Y_VERIFY(activityType < GetActivityTypeCount());
+
+ auto bucketName = TString(GetActivityTypeName(activityType));
+
+ ElapsedMicrosecByActivityBuckets[activityType] =
+ Group->GetSubgroup("sensor", "ElapsedMicrosecByActivity")->GetNamedCounter("activity", bucketName, true);
+ ReceivedEventsByActivityBuckets[activityType] =
+ Group->GetSubgroup("sensor", "ReceivedEventsByActivity")->GetNamedCounter("activity", bucketName, true);
+ ActorsAliveByActivityBuckets[activityType] =
+ Group->GetSubgroup("sensor", "ActorsAliveByActivity")->GetNamedCounter("activity", bucketName, false);
+ ScheduledEventsByActivityBuckets[activityType] =
+ Group->GetSubgroup("sensor", "ScheduledEventsByActivity")->GetNamedCounter("activity", bucketName, true);
+ }
+
+ private:
+ NMonitoring::TDynamicCounterPtr Group;
+
+ TVector<NMonitoring::TDynamicCounters::TCounterPtr> ElapsedMicrosecByActivityBuckets;
+ TVector<NMonitoring::TDynamicCounters::TCounterPtr> ReceivedEventsByActivityBuckets;
+ TVector<NMonitoring::TDynamicCounters::TCounterPtr> ActorsAliveByActivityBuckets;
+ TVector<NMonitoring::TDynamicCounters::TCounterPtr> ScheduledEventsByActivityBuckets;
+ };
+
+ struct TExecutorPoolCounters {
+ TIntrusivePtr<NMonitoring::TDynamicCounters> PoolGroup;
+
+ NMonitoring::TDynamicCounters::TCounterPtr SentEvents;
+ NMonitoring::TDynamicCounters::TCounterPtr ReceivedEvents;
+ NMonitoring::TDynamicCounters::TCounterPtr PreemptedEvents;
+ NMonitoring::TDynamicCounters::TCounterPtr NonDeliveredEvents;
+ NMonitoring::TDynamicCounters::TCounterPtr DestroyedActors;
+ NMonitoring::TDynamicCounters::TCounterPtr EmptyMailboxActivation;
+ NMonitoring::TDynamicCounters::TCounterPtr CpuMicrosec;
+ NMonitoring::TDynamicCounters::TCounterPtr ElapsedMicrosec;
+ NMonitoring::TDynamicCounters::TCounterPtr ParkedMicrosec;
+ NMonitoring::TDynamicCounters::TCounterPtr ActorRegistrations;
+ NMonitoring::TDynamicCounters::TCounterPtr ActorsAlive;
+ NMonitoring::TDynamicCounters::TCounterPtr AllocatedMailboxes;
+ NMonitoring::TDynamicCounters::TCounterPtr MailboxPushedOutBySoftPreemption;
+ NMonitoring::TDynamicCounters::TCounterPtr MailboxPushedOutByTime;
+ NMonitoring::TDynamicCounters::TCounterPtr MailboxPushedOutByEventCount;
+
+ THistogramCounters LegacyActivationTimeHistogram;
+ NMonitoring::THistogramPtr ActivationTimeHistogram;
+ THistogramCounters LegacyEventDeliveryTimeHistogram;
+ NMonitoring::THistogramPtr EventDeliveryTimeHistogram;
+ THistogramCounters LegacyEventProcessingCountHistogram;
+ NMonitoring::THistogramPtr EventProcessingCountHistogram;
+ THistogramCounters LegacyEventProcessingTimeHistogram;
+ NMonitoring::THistogramPtr EventProcessingTimeHistogram;
+
+ TActivityStats ActivityStats;
+ NMonitoring::TDynamicCounters::TCounterPtr MaxUtilizationTime;
+
+ double Usage = 0;
+ double LastElapsedSeconds = 0;
+ THPTimer UsageTimer;
+ TString Name;
+ ui32 Threads;
+
+ void Init(NMonitoring::TDynamicCounters* group, const TString& poolName, ui32 threads) {
+ LastElapsedSeconds = 0;
+ Usage = 0;
+ UsageTimer.Reset();
+ Name = poolName;
+ Threads = threads;
+
+ PoolGroup = group->GetSubgroup("execpool", poolName);
+
+ SentEvents = PoolGroup->GetCounter("SentEvents", true);
+ ReceivedEvents = PoolGroup->GetCounter("ReceivedEvents", true);
+ PreemptedEvents = PoolGroup->GetCounter("PreemptedEvents", true);
+ NonDeliveredEvents = PoolGroup->GetCounter("NonDeliveredEvents", true);
+ DestroyedActors = PoolGroup->GetCounter("DestroyedActors", true);
+ CpuMicrosec = PoolGroup->GetCounter("CpuMicrosec", true);
+ ElapsedMicrosec = PoolGroup->GetCounter("ElapsedMicrosec", true);
+ ParkedMicrosec = PoolGroup->GetCounter("ParkedMicrosec", true);
+ EmptyMailboxActivation = PoolGroup->GetCounter("EmptyMailboxActivation", true);
+ ActorRegistrations = PoolGroup->GetCounter("ActorRegistrations", true);
+ ActorsAlive = PoolGroup->GetCounter("ActorsAlive", false);
+ AllocatedMailboxes = PoolGroup->GetCounter("AllocatedMailboxes", false);
+ MailboxPushedOutBySoftPreemption = PoolGroup->GetCounter("MailboxPushedOutBySoftPreemption", true);
+ MailboxPushedOutByTime = PoolGroup->GetCounter("MailboxPushedOutByTime", true);
+ MailboxPushedOutByEventCount = PoolGroup->GetCounter("MailboxPushedOutByEventCount", true);
+
+ LegacyActivationTimeHistogram.Init(PoolGroup.Get(), "ActivationTime", "usec", 5*1000*1000);
+ ActivationTimeHistogram = PoolGroup->GetHistogram(
+ "ActivationTimeUs", NMonitoring::ExponentialHistogram(24, 2, 1));
+ LegacyEventDeliveryTimeHistogram.Init(PoolGroup.Get(), "EventDeliveryTime", "usec", 5*1000*1000);
+ EventDeliveryTimeHistogram = PoolGroup->GetHistogram(
+ "EventDeliveryTimeUs", NMonitoring::ExponentialHistogram(24, 2, 1));
+ LegacyEventProcessingCountHistogram.Init(PoolGroup.Get(), "EventProcessingCount", "usec", 5*1000*1000);
+ EventProcessingCountHistogram = PoolGroup->GetHistogram(
+ "EventProcessingCountUs", NMonitoring::ExponentialHistogram(24, 2, 1));
+ LegacyEventProcessingTimeHistogram.Init(PoolGroup.Get(), "EventProcessingTime", "usec", 5*1000*1000);
+ EventProcessingTimeHistogram = PoolGroup->GetHistogram(
+ "EventProcessingTimeUs", NMonitoring::ExponentialHistogram(24, 2, 1));
+
+ ActivityStats.Init(PoolGroup.Get());
+
+ MaxUtilizationTime = PoolGroup->GetCounter("MaxUtilizationTime", true);
+ }
+
+ void Set(const TExecutorPoolStats& poolStats, const TExecutorThreadStats& stats, ui32 numThreads) {
+#ifdef ACTORSLIB_COLLECT_EXEC_STATS
+ *SentEvents = stats.SentEvents;
+ *ReceivedEvents = stats.ReceivedEvents;
+ *PreemptedEvents = stats.PreemptedEvents;
+ *NonDeliveredEvents = stats.NonDeliveredEvents;
+ *DestroyedActors = stats.PoolDestroyedActors;
+ *EmptyMailboxActivation = stats.EmptyMailboxActivation;
+ *CpuMicrosec = stats.CpuNs / 1000;
+ *ElapsedMicrosec = ::NHPTimer::GetSeconds(stats.ElapsedTicks)*1000000;
+ *ParkedMicrosec = ::NHPTimer::GetSeconds(stats.ParkedTicks)*1000000;
+ *ActorRegistrations = stats.PoolActorRegistrations;
+ *ActorsAlive = stats.PoolActorRegistrations - stats.PoolDestroyedActors;
+ *AllocatedMailboxes = stats.PoolAllocatedMailboxes;
+ *MailboxPushedOutBySoftPreemption = stats.MailboxPushedOutBySoftPreemption;
+ *MailboxPushedOutByTime = stats.MailboxPushedOutByTime;
+ *MailboxPushedOutByEventCount = stats.MailboxPushedOutByEventCount;
+
+ LegacyActivationTimeHistogram.Set(stats.ActivationTimeHistogram);
+ ActivationTimeHistogram->Reset();
+ ActivationTimeHistogram->Collect(stats.ActivationTimeHistogram);
+
+ LegacyEventDeliveryTimeHistogram.Set(stats.EventDeliveryTimeHistogram);
+ EventDeliveryTimeHistogram->Reset();
+ EventDeliveryTimeHistogram->Collect(stats.EventDeliveryTimeHistogram);
+
+ LegacyEventProcessingCountHistogram.Set(stats.EventProcessingCountHistogram);
+ EventProcessingCountHistogram->Reset();
+ EventProcessingCountHistogram->Collect(stats.EventProcessingCountHistogram);
+
+ double toMicrosec = 1000000 / NHPTimer::GetClockRate();
+ LegacyEventProcessingTimeHistogram.Set(stats.EventProcessingTimeHistogram, toMicrosec);
+ EventProcessingTimeHistogram->Reset();
+ for (ui32 i = 0; i < stats.EventProcessingTimeHistogram.Count(); ++i) {
+ EventProcessingTimeHistogram->Collect(
+ stats.EventProcessingTimeHistogram.UpperBound(i),
+ stats.EventProcessingTimeHistogram.Value(i) * toMicrosec);
+ }
+
+ ActivityStats.Set(stats);
+
+ *MaxUtilizationTime = poolStats.MaxUtilizationTime;
+
+ double seconds = UsageTimer.PassedReset();
+
+ // TODO[serxa]: It doesn't account for contention. Use 1 - parkedTicksDelta / seconds / numThreads KIKIMR-11916
+ const double elapsed = NHPTimer::GetSeconds(stats.ElapsedTicks);
+ const double currentUsage = numThreads > 0 ? ((elapsed - LastElapsedSeconds) / seconds / numThreads) : 0;
+ LastElapsedSeconds = elapsed;
+
+ // update usage factor according to smoothness
+ const double smoothness = 0.5;
+ Usage = currentUsage * smoothness + Usage * (1.0 - smoothness);
+#else
+ Y_UNUSED(poolStats);
+ Y_UNUSED(stats);
+ Y_UNUSED(numThreads);
+#endif
+ }
+ };
+
+public:
+ static constexpr IActor::EActivityType ActorActivityType() {
+ return IActor::ACTORLIB_STATS;
+ }
+
+ TStatsCollectingActor(
+ ui32 intervalSec,
+ const TActorSystemSetup& setup,
+ NMonitoring::TDynamicCounterPtr counters)
+ : IntervalSec(intervalSec)
+ , Counters(counters)
+ {
+ PoolCounters.resize(setup.GetExecutorsCount());
+ for (size_t poolId = 0; poolId < PoolCounters.size(); ++poolId) {
+ PoolCounters[poolId].Init(Counters.Get(), setup.GetPoolName(poolId), setup.GetThreads(poolId));
+ }
+ }
+
+ void Bootstrap(const TActorContext& ctx) {
+ ctx.Schedule(TDuration::Seconds(IntervalSec), new TEvents::TEvWakeup());
+ Become(&TThis::StateWork);
+ }
+
+ STFUNC(StateWork) {
+ switch (ev->GetTypeRewrite()) {
+ CFunc(TEvents::TSystem::Wakeup, Wakeup);
+ }
+ }
+
+private:
+ virtual void OnWakeup(const TActorContext &ctx) {
+ Y_UNUSED(ctx);
+ }
+
+ void Wakeup(const TActorContext &ctx) {
+ for (size_t poolId = 0; poolId < PoolCounters.size(); ++poolId) {
+ TVector<TExecutorThreadStats> stats;
+ TExecutorPoolStats poolStats;
+ ctx.ExecutorThread.ActorSystem->GetPoolStats(poolId, poolStats, stats);
+ SetAggregatedCounters(PoolCounters[poolId], poolStats, stats);
+ }
+
+ OnWakeup(ctx);
+
+ ctx.Schedule(TDuration::Seconds(IntervalSec), new TEvents::TEvWakeup());
+ }
+
+ void SetAggregatedCounters(TExecutorPoolCounters& poolCounters, TExecutorPoolStats& poolStats, TVector<TExecutorThreadStats>& stats) {
+ // Sum all per-thread counters into the 0th element
+ for (ui32 idx = 1; idx < stats.size(); ++idx) {
+ stats[0].Aggregate(stats[idx]);
+ }
+ if (stats.size()) {
+ poolCounters.Set(poolStats, stats[0], stats.size() - 1);
+ }
+ }
+
+protected:
+ const ui32 IntervalSec;
+ NMonitoring::TDynamicCounterPtr Counters;
+
+ TVector<TExecutorPoolCounters> PoolCounters;
+};
+
+} // NActors
diff --git a/library/cpp/actors/helpers/selfping_actor.cpp b/library/cpp/actors/helpers/selfping_actor.cpp
new file mode 100644
index 0000000000..f9bfaf8dc0
--- /dev/null
+++ b/library/cpp/actors/helpers/selfping_actor.cpp
@@ -0,0 +1,183 @@
+#include "selfping_actor.h"
+
+#include <library/cpp/actors/core/actor_bootstrapped.h>
+#include <library/cpp/actors/core/hfunc.h>
+
+#include <library/cpp/containers/stack_vector/stack_vec.h>
+#include <library/cpp/sliding_window/sliding_window.h>
+
+namespace NActors {
+
+namespace {
+
+struct TEvPing: public TEventLocal<TEvPing, TEvents::THelloWorld::Ping> {
+ TEvPing(double timeStart)
+ : TimeStart(timeStart)
+ {}
+
+ const double TimeStart;
+};
+
+template <class TValueType_>
+struct TAvgOperation {
+ struct TValueType {
+ ui64 Count = 0;
+ TValueType_ Sum = TValueType_();
+ };
+ using TValueVector = TVector<TValueType>;
+
+ static constexpr TValueType InitialValue() {
+ return TValueType(); // zero
+ }
+
+ // Updates value in current bucket and returns window value
+ static TValueType UpdateBucket(TValueType windowValue, TValueVector& buckets, size_t index, TValueType newVal) {
+ Y_ASSERT(index < buckets.size());
+ buckets[index].Sum += newVal.Sum;
+ buckets[index].Count += newVal.Count;
+ windowValue.Sum += newVal.Sum;
+ windowValue.Count += newVal.Count;
+ return windowValue;
+ }
+
+ static TValueType ClearBuckets(TValueType windowValue, TValueVector& buckets, size_t firstElemIndex, size_t bucketsToClear) {
+ Y_ASSERT(!buckets.empty());
+ Y_ASSERT(firstElemIndex < buckets.size());
+ Y_ASSERT(bucketsToClear <= buckets.size());
+
+ const size_t arraySize = buckets.size();
+ for (size_t i = 0; i < bucketsToClear; ++i) {
+ TValueType& curVal = buckets[firstElemIndex];
+ windowValue.Sum -= curVal.Sum;
+ windowValue.Count -= curVal.Count;
+ curVal = InitialValue();
+ firstElemIndex = (firstElemIndex + 1) % arraySize;
+ }
+ return windowValue;
+ }
+
+};
+
+class TSelfPingActor : public TActorBootstrapped<TSelfPingActor> {
+private:
+ const TDuration SendInterval;
+ const NMonitoring::TDynamicCounters::TCounterPtr Counter;
+ const NMonitoring::TDynamicCounters::TCounterPtr CalculationTimeCounter;
+
+ NSlidingWindow::TSlidingWindow<NSlidingWindow::TMaxOperation<ui64>> SlidingWindow;
+ NSlidingWindow::TSlidingWindow<TAvgOperation<ui64>> CalculationSlidingWindow;
+
+ THPTimer Timer;
+
+public:
+ static constexpr auto ActorActivityType() {
+ return SELF_PING_ACTOR;
+ }
+
+ TSelfPingActor(TDuration sendInterval, const NMonitoring::TDynamicCounters::TCounterPtr& counter,
+ const NMonitoring::TDynamicCounters::TCounterPtr& calculationTimeCounter)
+ : SendInterval(sendInterval)
+ , Counter(counter)
+ , CalculationTimeCounter(calculationTimeCounter)
+ , SlidingWindow(TDuration::Seconds(15), 100)
+ , CalculationSlidingWindow(TDuration::Seconds(15), 100)
+ {
+ }
+
+ void Bootstrap(const TActorContext& ctx)
+ {
+ Become(&TSelfPingActor::RunningState);
+ SchedulePing(ctx, Timer.Passed());
+ }
+
+ STFUNC(RunningState)
+ {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TEvPing, HandlePing);
+ default:
+ Y_FAIL("TSelfPingActor::RunningState: unexpected event 0x%08" PRIx32, ev->GetTypeRewrite());
+ }
+ }
+
+ ui64 MeasureTaskDurationNs() {
+ // Prepare worm test data
+ // 11 * 11 * 3 * 8 = 2904 bytes, fits in L1 cache
+ constexpr ui64 Size = 11;
+ // Align the data to reduce random alignment effects
+ alignas(64) TStackVec<ui64, Size * Size * 3> data;
+ ui64 s = 0;
+ NHPTimer::STime beginTime;
+ NHPTimer::STime endTime;
+ // Prepare the data
+ data.resize(Size * Size * 3);
+ for (ui64 matrixIdx = 0; matrixIdx < 3; ++matrixIdx) {
+ for (ui64 y = 0; y < Size; ++y) {
+ for (ui64 x = 0; x < Size; ++x) {
+ data[matrixIdx * (Size * Size) + y * Size + x] = y * Size + x;
+ }
+ }
+ }
+ // Warm-up the cache
+ NHPTimer::GetTime(&beginTime);
+ for (ui64 idx = 0; idx < data.size(); ++idx) {
+ s += data[idx];
+ }
+ NHPTimer::GetTime(&endTime);
+ s += (ui64)(1000000.0 * NHPTimer::GetSeconds(endTime - beginTime));
+
+ // Measure the CPU performance
+ // C = A * B with injected dependency to s
+ NHPTimer::GetTime(&beginTime);
+ for (ui64 y = 0; y < Size; ++y) {
+ for (ui64 x = 0; x < Size; ++x) {
+ for (ui64 i = 0; i < Size; ++i) {
+ s += data[y * Size + i] * data[Size * Size + i * Size + x];
+ }
+ data[2 * Size * Size + y * Size + x] = s;
+ s = 0;
+ }
+ }
+ for (ui64 idx = 0; idx < data.size(); ++idx) {
+ s += data[idx];
+ }
+ NHPTimer::GetTime(&endTime);
+ // Prepare the result
+ double d = 1000000000.0 * (NHPTimer::GetSeconds(endTime - beginTime) + 0.000000001 * (s & 1));
+ return (ui64)d;
+ }
+
+ void HandlePing(TEvPing::TPtr &ev, const TActorContext &ctx)
+ {
+ const auto now = ctx.Now();
+ const double hpNow = Timer.Passed();
+ const auto& e = *ev->Get();
+ const double passedTime = hpNow - e.TimeStart;
+ const ui64 delayUs = passedTime > 0.0 ? static_cast<ui64>(passedTime * 1e6) : 0;
+
+ *Counter = SlidingWindow.Update(delayUs, now);
+
+ ui64 d = MeasureTaskDurationNs();
+ auto res = CalculationSlidingWindow.Update({1, d}, now);
+ *CalculationTimeCounter = double(res.Sum) / double(res.Count + 1);
+
+ SchedulePing(ctx, hpNow);
+ }
+
+private:
+ void SchedulePing(const TActorContext &ctx, double hpNow) const
+ {
+ ctx.Schedule(SendInterval, new TEvPing(hpNow));
+ }
+};
+
+} // namespace
+
+IActor* CreateSelfPingActor(
+ TDuration sendInterval,
+ const NMonitoring::TDynamicCounters::TCounterPtr& counter,
+ const NMonitoring::TDynamicCounters::TCounterPtr& calculationTimeCounter)
+{
+ return new TSelfPingActor(sendInterval, counter, calculationTimeCounter);
+}
+
+} // NActors
diff --git a/library/cpp/actors/helpers/selfping_actor.h b/library/cpp/actors/helpers/selfping_actor.h
new file mode 100644
index 0000000000..d7d07f9fa8
--- /dev/null
+++ b/library/cpp/actors/helpers/selfping_actor.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <library/cpp/actors/core/actor.h>
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+
+namespace NActors {
+
+NActors::IActor* CreateSelfPingActor(
+ TDuration sendInterval,
+ const NMonitoring::TDynamicCounters::TCounterPtr& counter,
+ const NMonitoring::TDynamicCounters::TCounterPtr& calculationTimeCounter);
+
+} // NActors
diff --git a/library/cpp/actors/helpers/selfping_actor_ut.cpp b/library/cpp/actors/helpers/selfping_actor_ut.cpp
new file mode 100644
index 0000000000..459635fa24
--- /dev/null
+++ b/library/cpp/actors/helpers/selfping_actor_ut.cpp
@@ -0,0 +1,45 @@
+#include "selfping_actor.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/actors/testlib/test_runtime.h>
+
+namespace NActors {
+namespace Tests {
+
+THolder<TTestActorRuntimeBase> CreateRuntime() {
+ auto runtime = MakeHolder<TTestActorRuntimeBase>();
+ runtime->SetScheduledEventFilter([](auto&&, auto&&, auto&&, auto&&) { return false; });
+ runtime->Initialize();
+ return runtime;
+}
+
+Y_UNIT_TEST_SUITE(TSelfPingTest) {
+ Y_UNIT_TEST(Basic)
+ {
+ auto runtime = CreateRuntime();
+
+ //const TActorId sender = runtime.AllocateEdgeActor();
+
+ NMonitoring::TDynamicCounters::TCounterPtr counter(new NMonitoring::TCounterForPtr());
+ NMonitoring::TDynamicCounters::TCounterPtr counter2(new NMonitoring::TCounterForPtr());
+
+ auto actor = CreateSelfPingActor(
+ TDuration::MilliSeconds(100), // sendInterval (unused in test)
+ counter, counter2);
+
+ UNIT_ASSERT_VALUES_EQUAL(counter->Val(), 0);
+ UNIT_ASSERT_VALUES_EQUAL(counter2->Val(), 0);
+
+ const TActorId actorId = runtime->Register(actor);
+ Y_UNUSED(actorId);
+
+ //runtime.Send(new IEventHandle(actorId, sender, new TEvSelfPing::TEvPing(0.0)));
+
+ // TODO check after events are handled
+ //Sleep(TDuration::Seconds(1));
+ //UNIT_ASSERT((intmax_t)counter->Val() >= (intmax_t)Delay.MicroSeconds());
+ }
+}
+
+} // namespace Tests
+} // namespace NActors
diff --git a/library/cpp/actors/helpers/ut/ya.make b/library/cpp/actors/helpers/ut/ya.make
new file mode 100644
index 0000000000..cba4d6d1d9
--- /dev/null
+++ b/library/cpp/actors/helpers/ut/ya.make
@@ -0,0 +1,36 @@
+UNITTEST_FOR(library/cpp/actors/helpers)
+
+OWNER(
+ alexvru
+ g:kikimr
+)
+
+FORK_SUBTESTS()
+IF (SANITIZER_TYPE)
+ SIZE(LARGE)
+ TIMEOUT(1200)
+ TAG(ya:fat)
+ SPLIT_FACTOR(20)
+ REQUIREMENTS(
+ ram:32
+ )
+ELSE()
+ SIZE(MEDIUM)
+ TIMEOUT(600)
+ REQUIREMENTS(
+ ram:16
+ )
+ENDIF()
+
+
+PEERDIR(
+ library/cpp/actors/interconnect
+ library/cpp/actors/testlib
+ library/cpp/actors/core
+)
+
+SRCS(
+ selfping_actor_ut.cpp
+)
+
+END()
diff --git a/library/cpp/actors/helpers/ya.make b/library/cpp/actors/helpers/ya.make
new file mode 100644
index 0000000000..d8771179de
--- /dev/null
+++ b/library/cpp/actors/helpers/ya.make
@@ -0,0 +1,25 @@
+LIBRARY()
+
+OWNER(g:kikimr)
+
+SRCS(
+ activeactors.cpp
+ activeactors.h
+ flow_controlled_queue.cpp
+ flow_controlled_queue.h
+ future_callback.h
+ mon_histogram_helper.h
+ selfping_actor.cpp
+)
+
+PEERDIR(
+ library/cpp/actors/core
+ library/cpp/monlib/dynamic_counters
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ ut
+)
+
diff --git a/library/cpp/actors/http/http.cpp b/library/cpp/actors/http/http.cpp
new file mode 100644
index 0000000000..7125f9d8b0
--- /dev/null
+++ b/library/cpp/actors/http/http.cpp
@@ -0,0 +1,653 @@
+#include "http.h"
+#include <library/cpp/string_utils/quote/quote.h>
+
+inline TStringBuf operator +(TStringBuf l, TStringBuf r) {
+ if (l.empty()) {
+ return r;
+ }
+ if (r.empty()) {
+ return l;
+ }
+ if (l.end() == r.begin()) {
+ return TStringBuf(l.data(), l.size() + r.size());
+ }
+ if (r.end() == l.begin()) {
+ return TStringBuf(r.data(), l.size() + r.size());
+ }
+ Y_FAIL("oops");
+ return TStringBuf();
+}
+
+inline TStringBuf operator +=(TStringBuf& l, TStringBuf r) {
+ return l = l + r;
+}
+
+namespace NHttp {
+
+template <> TStringBuf THttpRequest::GetName<&THttpRequest::Host>() { return "Host"; }
+template <> TStringBuf THttpRequest::GetName<&THttpRequest::Accept>() { return "Accept"; }
+template <> TStringBuf THttpRequest::GetName<&THttpRequest::Connection>() { return "Connection"; }
+template <> TStringBuf THttpRequest::GetName<&THttpRequest::ContentType>() { return "Content-Type"; }
+template <> TStringBuf THttpRequest::GetName<&THttpRequest::ContentLength>() { return "Content-Length"; }
+template <> TStringBuf THttpRequest::GetName<&THttpRequest::TransferEncoding>() { return "Transfer-Encoding"; }
+
+const TMap<TStringBuf, TStringBuf THttpRequest::*, TLessNoCase> THttpRequest::HeadersLocation = {
+ { THttpRequest::GetName<&THttpRequest::Host>(), &THttpRequest::Host },
+ { THttpRequest::GetName<&THttpRequest::Accept>(), &THttpRequest::Accept },
+ { THttpRequest::GetName<&THttpRequest::Connection>(), &THttpRequest::Connection },
+ { THttpRequest::GetName<&THttpRequest::ContentType>(), &THttpRequest::ContentType },
+ { THttpRequest::GetName<&THttpRequest::ContentLength>(), &THttpRequest::ContentLength },
+ { THttpRequest::GetName<&THttpRequest::TransferEncoding>(), &THttpRequest::TransferEncoding },
+};
+
+template <> TStringBuf THttpResponse::GetName<&THttpResponse::Connection>() { return "Connection"; }
+template <> TStringBuf THttpResponse::GetName<&THttpResponse::ContentType>() { return "Content-Type"; }
+template <> TStringBuf THttpResponse::GetName<&THttpResponse::ContentLength>() { return "Content-Length"; }
+template <> TStringBuf THttpResponse::GetName<&THttpResponse::TransferEncoding>() { return "Transfer-Encoding"; }
+template <> TStringBuf THttpResponse::GetName<&THttpResponse::LastModified>() { return "Last-Modified"; }
+template <> TStringBuf THttpResponse::GetName<&THttpResponse::ContentEncoding>() { return "Content-Encoding"; }
+
+const TMap<TStringBuf, TStringBuf THttpResponse::*, TLessNoCase> THttpResponse::HeadersLocation = {
+ { THttpResponse::GetName<&THttpResponse::Connection>(), &THttpResponse::Connection },
+ { THttpResponse::GetName<&THttpResponse::ContentType>(), &THttpResponse::ContentType },
+ { THttpResponse::GetName<&THttpResponse::ContentLength>(), &THttpResponse::ContentLength },
+ { THttpResponse::GetName<&THttpResponse::TransferEncoding>(), &THttpResponse::TransferEncoding },
+ { THttpResponse::GetName<&THttpResponse::LastModified>(), &THttpResponse::LastModified },
+ { THttpResponse::GetName<&THttpResponse::ContentEncoding>(), &THttpResponse::ContentEncoding }
+};
+
+void THttpRequest::Clear() {
+ // a dirty little trick
+ this->~THttpRequest(); // basically, do nothing
+ new (this) THttpRequest(); // reset all fields
+}
+
+template <>
+void THttpParser<THttpRequest, TSocketBuffer>::Advance(size_t len) {
+ TStringBuf data(Pos(), len);
+ while (!data.empty()) {
+ if (Stage != EParseStage::Error) {
+ LastSuccessStage = Stage;
+ }
+ switch (Stage) {
+ case EParseStage::Method: {
+ if (ProcessData(Method, data, ' ', MaxMethodSize)) {
+ Stage = EParseStage::URL;
+ }
+ break;
+ }
+ case EParseStage::URL: {
+ if (ProcessData(URL, data, ' ', MaxURLSize)) {
+ Stage = EParseStage::Protocol;
+ }
+ break;
+ }
+ case EParseStage::Protocol: {
+ if (ProcessData(Protocol, data, '/', MaxProtocolSize)) {
+ Stage = EParseStage::Version;
+ }
+ break;
+ }
+ case EParseStage::Version: {
+ if (ProcessData(Version, data, "\r\n", MaxVersionSize)) {
+ Stage = EParseStage::Header;
+ Headers = data;
+ }
+ break;
+ }
+ case EParseStage::Header: {
+ if (ProcessData(Header, data, "\r\n", MaxHeaderSize)) {
+ if (Header.empty()) {
+ Headers = TStringBuf(Headers.data(), data.begin() - Headers.begin());
+ if (HaveBody()) {
+ Stage = EParseStage::Body;
+ } else {
+ Stage = EParseStage::Done;
+ }
+ } else {
+ ProcessHeader(Header);
+ }
+ }
+ break;
+ }
+ case EParseStage::Body: {
+ if (!ContentLength.empty()) {
+ if (ProcessData(Content, data, FromString(ContentLength))) {
+ Body = Content;
+ Stage = EParseStage::Done;
+ }
+ } else if (TransferEncoding == "chunked") {
+ Stage = EParseStage::ChunkLength;
+ } else {
+ // Invalid body encoding
+ Stage = EParseStage::Error;
+ }
+ break;
+ }
+ case EParseStage::ChunkLength: {
+ if (ProcessData(Line, data, "\r\n", MaxChunkLengthSize)) {
+ if (!Line.empty()) {
+ ChunkLength = ParseHex(Line);
+ if (ChunkLength <= MaxChunkSize) {
+ ContentSize = Content.size() + ChunkLength;
+ if (ContentSize <= MaxChunkContentSize) {
+ Stage = EParseStage::ChunkData;
+ Line.Clear();
+ } else {
+ // Invalid chunk content length
+ Stage = EParseStage::Error;
+ }
+ } else {
+ // Invalid chunk length
+ Stage = EParseStage::Error;
+ }
+ } else {
+ // Invalid body encoding
+ Stage = EParseStage::Error;
+ }
+ }
+ break;
+ }
+ case EParseStage::ChunkData: {
+ if (!IsError()) {
+ if (ProcessData(Content, data, ContentSize)) {
+ if (ProcessData(Line, data, 2)) {
+ if (Line == "\r\n") {
+ if (ChunkLength == 0) {
+ Body = Content;
+ Stage = EParseStage::Done;
+ } else {
+ Stage = EParseStage::ChunkLength;
+ }
+ Line.Clear();
+ } else {
+ // Invalid body encoding
+ Stage = EParseStage::Error;
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ case EParseStage::Done:
+ case EParseStage::Error: {
+ data.Clear();
+ break;
+ }
+ default:
+ Y_FAIL("Invalid processing sequence");
+ break;
+ }
+ }
+ TSocketBuffer::Advance(len);
+}
+
+template <>
+THttpParser<THttpRequest, TSocketBuffer>::EParseStage THttpParser<THttpRequest, TSocketBuffer>::GetInitialStage() {
+ return EParseStage::Method;
+}
+
+template <>
+THttpParser<THttpResponse, TSocketBuffer>::EParseStage THttpParser<THttpResponse, TSocketBuffer>::GetInitialStage() {
+ return EParseStage::Protocol;
+}
+
+void THttpResponse::Clear() {
+ // a dirty little trick
+ this->~THttpResponse(); // basically, do nothing
+ new (this) THttpResponse(); // reset all fields
+}
+
+template <>
+void THttpParser<THttpResponse, TSocketBuffer>::Advance(size_t len) {
+ TStringBuf data(Pos(), len);
+ while (!data.empty()) {
+ if (Stage != EParseStage::Error) {
+ LastSuccessStage = Stage;
+ }
+ switch (Stage) {
+ case EParseStage::Protocol: {
+ if (ProcessData(Protocol, data, '/', MaxProtocolSize)) {
+ Stage = EParseStage::Version;
+ }
+ break;
+ }
+ case EParseStage::Version: {
+ if (ProcessData(Version, data, ' ', MaxVersionSize)) {
+ Stage = EParseStage::Status;
+ }
+ break;
+ }
+ case EParseStage::Status: {
+ if (ProcessData(Status, data, ' ', MaxStatusSize)) {
+ Stage = EParseStage::Message;
+ }
+ break;
+ }
+ case EParseStage::Message: {
+ if (ProcessData(Message, data, "\r\n", MaxMessageSize)) {
+ Stage = EParseStage::Header;
+ Headers = TStringBuf(data.data(), size_t(0));
+ }
+ break;
+ }
+ case EParseStage::Header: {
+ if (ProcessData(Header, data, "\r\n", MaxHeaderSize)) {
+ if (Header.empty()) {
+ if (HaveBody() && (ContentLength.empty() || ContentLength != "0")) {
+ Stage = EParseStage::Body;
+ } else {
+ Stage = EParseStage::Done;
+ }
+ } else {
+ ProcessHeader(Header);
+ }
+ Headers = TStringBuf(Headers.data(), data.data() - Headers.data());
+ }
+ break;
+ }
+ case EParseStage::Body: {
+ if (!ContentLength.empty()) {
+ if (ProcessData(Body, data, FromString(ContentLength))) {
+ Stage = EParseStage::Done;
+ }
+ } else if (TransferEncoding == "chunked") {
+ Stage = EParseStage::ChunkLength;
+ } else {
+ // Invalid body encoding
+ Stage = EParseStage::Error;
+ }
+ break;
+ }
+ case EParseStage::ChunkLength: {
+ if (ProcessData(Line, data, "\r\n", MaxChunkLengthSize)) {
+ if (!Line.empty()) {
+ ChunkLength = ParseHex(Line);
+ if (ChunkLength <= MaxChunkSize) {
+ ContentSize = Content.size() + ChunkLength;
+ if (ContentSize <= MaxChunkContentSize) {
+ Stage = EParseStage::ChunkData;
+ Line.Clear();
+ } else {
+ // Invalid chunk content length
+ Stage = EParseStage::Error;
+ }
+ } else {
+ // Invalid chunk length
+ Stage = EParseStage::Error;
+ }
+ } else {
+ // Invalid body encoding
+ Stage = EParseStage::Error;
+ }
+ }
+ break;
+ }
+ case EParseStage::ChunkData: {
+ if (!IsError()) {
+ if (ProcessData(Content, data, ContentSize)) {
+ if (ProcessData(Line, data, 2)) {
+ if (Line == "\r\n") {
+ if (ChunkLength == 0) {
+ Body = Content;
+ Stage = EParseStage::Done;
+ } else {
+ Stage = EParseStage::ChunkLength;
+ }
+ Line.Clear();
+ } else {
+ // Invalid body encoding
+ Stage = EParseStage::Error;
+ }
+ }
+ }
+ }
+ break;
+ }
+ case EParseStage::Done:
+ case EParseStage::Error:
+ data.Clear();
+ break;
+ default:
+ // Invalid processing sequence
+ Stage = EParseStage::Error;
+ break;
+ }
+ }
+ TSocketBuffer::Advance(len);
+}
+
+template <>
+void THttpParser<THttpResponse, TSocketBuffer>::ConnectionClosed() {
+ if (Stage == EParseStage::Done) {
+ return;
+ }
+ if (Stage == EParseStage::Body) {
+ // ?
+ Stage = EParseStage::Done;
+ } else {
+ LastSuccessStage = Stage;
+ Stage = EParseStage::Error;
+ }
+}
+
+THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseString(TStringBuf data) {
+ THttpOutgoingResponsePtr response = new THttpOutgoingResponse(this);
+ response->Append(data);
+ response->Reparse();
+ return response;
+}
+
+THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseOK(TStringBuf body, TStringBuf contentType, TInstant lastModified) {
+ return CreateResponse("200", "OK", contentType, body, lastModified);
+}
+
+THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseBadRequest(TStringBuf html, TStringBuf contentType) {
+ if (html.empty() && IsError()) {
+ contentType = "text/plain";
+ html = GetErrorText();
+ }
+ return CreateResponse("400", "Bad Request", contentType, html);
+}
+
+THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseNotFound(TStringBuf html, TStringBuf contentType) {
+ return CreateResponse("404", "Not Found", contentType, html);
+}
+
+THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseServiceUnavailable(TStringBuf html, TStringBuf contentType) {
+ return CreateResponse("503", "Service Unavailable", contentType, html);
+}
+
+THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponseGatewayTimeout(TStringBuf html, TStringBuf contentType) {
+ return CreateResponse("504", "Gateway Timeout", contentType, html);
+}
+
+THttpIncomingResponse::THttpIncomingResponse(THttpOutgoingRequestPtr request)
+ : Request(request)
+{}
+
+THttpOutgoingResponsePtr THttpIncomingRequest::CreateResponse(TStringBuf status, TStringBuf message, TStringBuf contentType, TStringBuf body, TInstant lastModified) {
+ TStringBuf version = Version;
+ if (version != "1.0" && version != "1.1") {
+ version = "1.1";
+ }
+ THttpOutgoingResponsePtr response = new THttpOutgoingResponse(this, "HTTP", version, status, message);
+ response->Set<&THttpResponse::Connection>(GetConnection());
+ if (!WorkerName.empty()) {
+ response->Set("X-Worker-Name", WorkerName);
+ }
+ if (!contentType.empty() && !body.empty()) {
+ response->Set<&THttpResponse::ContentType>(contentType);
+ }
+ if (lastModified) {
+ response->Set<&THttpResponse::LastModified>(lastModified.FormatGmTime("%a, %d %b %Y %H:%M:%S GMT"));
+ }
+ if (response->IsNeedBody() || !body.empty()) {
+ if (Method == "HEAD") {
+ response->Set<&THttpResponse::ContentLength>(ToString(body.size()));
+ } else {
+ response->Set<&THttpResponse::Body>(body);
+ }
+ }
+ return response;
+}
+
+THttpIncomingRequestPtr THttpIncomingRequest::Duplicate() {
+ THttpIncomingRequestPtr request = new THttpIncomingRequest(*this);
+ request->Reparse();
+ request->Timer.Reset();
+ return request;
+}
+
+THttpIncomingResponsePtr THttpIncomingResponse::Duplicate(THttpOutgoingRequestPtr request) {
+ THttpIncomingResponsePtr response = new THttpIncomingResponse(*this);
+ response->Reparse();
+ response->Request = request;
+ return response;
+}
+
+THttpOutgoingResponsePtr THttpOutgoingResponse::Duplicate(THttpIncomingRequestPtr request) {
+ THttpOutgoingResponsePtr response = new THttpOutgoingResponse(*this);
+ response->Reparse();
+ response->Request = request;
+ return response;
+}
+
+
+THttpOutgoingResponsePtr THttpIncomingResponse::Reverse(THttpIncomingRequestPtr request) {
+ THttpOutgoingResponsePtr response = new THttpOutgoingResponse(request);
+ response->Assign(Data(), Size());
+ response->Reparse();
+ return response;
+}
+
+THttpOutgoingRequest::THttpOutgoingRequest(TStringBuf method, TStringBuf scheme, TStringBuf host, TStringBuf uri, TStringBuf protocol, TStringBuf version) {
+ Secure = (scheme == "https");
+ TString urie = UrlEscapeRet(uri);
+ InitRequest(method, urie, protocol, version);
+ if (host) {
+ Set<&THttpRequest::Host>(host);
+ }
+}
+
+THttpOutgoingRequest::THttpOutgoingRequest(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version) {
+ TStringBuf scheme, host, uri;
+ if (!CrackURL(url, scheme, host, uri)) {
+ Y_FAIL("Invalid URL specified");
+ }
+ if (!scheme.empty() && scheme != "http" && scheme != "https") {
+ Y_FAIL("Invalid URL specified");
+ }
+ Secure = (scheme == "https");
+ TString urie = UrlEscapeRet(uri);
+ InitRequest(method, urie, protocol, version);
+ if (host) {
+ Set<&THttpRequest::Host>(host);
+ }
+}
+
+THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestString(const TString& data) {
+ THttpOutgoingRequestPtr request = new THttpOutgoingRequest();
+ request->Assign(data.data(), data.size());
+ request->Reparse();
+ return request;
+}
+
+THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestGet(TStringBuf url) {
+ return CreateRequest("GET", url);
+}
+
+THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestGet(TStringBuf host, TStringBuf uri) {
+ return CreateHttpRequest("GET", host, uri);
+}
+
+THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestPost(TStringBuf url, TStringBuf contentType, TStringBuf body) {
+ return CreateRequest("POST", url, contentType, body);
+}
+
+THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequestPost(TStringBuf host, TStringBuf uri, TStringBuf contentType, TStringBuf body) {
+ return CreateHttpRequest("POST", host, uri, contentType, body);
+}
+
+THttpOutgoingRequestPtr THttpOutgoingRequest::CreateRequest(TStringBuf method, TStringBuf url, TStringBuf contentType, TStringBuf body) {
+ THttpOutgoingRequestPtr request = new THttpOutgoingRequest(method, url, "HTTP", "1.1");
+ request->Set<&THttpRequest::Accept>("*/*");
+ if (!contentType.empty()) {
+ request->Set<&THttpRequest::ContentType>(contentType);
+ request->Set<&THttpRequest::Body>(body);
+ }
+ return request;
+}
+
+THttpOutgoingRequestPtr THttpOutgoingRequest::CreateHttpRequest(TStringBuf method, TStringBuf host, TStringBuf uri, TStringBuf contentType, TStringBuf body) {
+ THttpOutgoingRequestPtr request = new THttpOutgoingRequest(method, "http", host, uri, "HTTP", "1.1");
+ request->Set<&THttpRequest::Accept>("*/*");
+ if (!contentType.empty()) {
+ request->Set<&THttpRequest::ContentType>(contentType);
+ request->Set<&THttpRequest::Body>(body);
+ }
+ return request;
+}
+
+THttpOutgoingRequestPtr THttpOutgoingRequest::Duplicate() {
+ THttpOutgoingRequestPtr request = new THttpOutgoingRequest(*this);
+ request->Reparse();
+ return request;
+}
+
+THttpOutgoingResponse::THttpOutgoingResponse(THttpIncomingRequestPtr request)
+ : Request(request)
+{}
+
+THttpOutgoingResponse::THttpOutgoingResponse(THttpIncomingRequestPtr request, TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message)
+ : Request(request)
+{
+ InitResponse(protocol, version, status, message);
+}
+
+const size_t THttpConfig::BUFFER_MIN_STEP;
+const TDuration THttpConfig::CONNECTION_TIMEOUT;
+
+TUrlParameters::TUrlParameters(TStringBuf url) {
+ TStringBuf base;
+ TStringBuf params;
+ if (url.TrySplit('?', base, params)) {
+ for (TStringBuf param = params.NextTok('&'); !param.empty(); param = params.NextTok('&')) {
+ TStringBuf name = param.NextTok('=');
+ Parameters[name] = param;
+ }
+ }
+}
+
+TString TUrlParameters::operator [](TStringBuf name) const {
+ TString value(Get(name));
+ CGIUnescape(value);
+ return value;
+}
+
+bool TUrlParameters::Has(TStringBuf name) const {
+ return Parameters.count(name) != 0;
+}
+
+TStringBuf TUrlParameters::Get(TStringBuf name) const {
+ auto it = Parameters.find(name);
+ if (it != Parameters.end()) {
+ return it->second;
+ }
+ return TStringBuf();
+}
+
+TString TUrlParameters::Render() const {
+ TStringBuilder parameters;
+ for (const std::pair<TStringBuf, TStringBuf> parameter : Parameters) {
+ if (parameters.empty()) {
+ parameters << '?';
+ } else {
+ parameters << '&';
+ }
+ parameters << parameter.first;
+ parameters << '=';
+ parameters << parameter.second;
+ }
+ return parameters;
+}
+
+TCookies::TCookies(TStringBuf cookie) {
+ for (TStringBuf param = cookie.NextTok(';'); !param.empty(); param = cookie.NextTok(';')) {
+ param.SkipPrefix(" ");
+ TStringBuf name = param.NextTok('=');
+ Cookies[name] = param;
+ }
+}
+
+TStringBuf TCookies::operator [](TStringBuf name) const {
+ return Get(name);
+}
+
+bool TCookies::Has(TStringBuf name) const {
+ return Cookies.count(name) != 0;
+}
+
+TStringBuf TCookies::Get(TStringBuf name) const {
+ auto it = Cookies.find(name);
+ if (it != Cookies.end()) {
+ return it->second;
+ }
+ return TStringBuf();
+}
+
+TString TCookies::Render() const {
+ TStringBuilder cookies;
+ for (const std::pair<TStringBuf, TStringBuf> cookie : Cookies) {
+ if (!cookies.empty()) {
+ cookies << ' ';
+ }
+ cookies << cookie.first;
+ cookies << '=';
+ cookies << cookie.second;
+ cookies << ';';
+ }
+ return cookies;
+}
+
+TCookiesBuilder::TCookiesBuilder()
+ :TCookies(TStringBuf())
+{}
+
+void TCookiesBuilder::Set(TStringBuf name, TStringBuf data) {
+ Data.emplace_back(name, data);
+ Cookies[Data.back().first] = Data.back().second;
+}
+
+THeaders::THeaders(TStringBuf headers) {
+ for (TStringBuf param = headers.NextTok("\r\n"); !param.empty(); param = headers.NextTok("\r\n")) {
+ TStringBuf name = param.NextTok(":");
+ param.SkipPrefix(" ");
+ Headers[name] = param;
+ }
+}
+
+TStringBuf THeaders::operator [](TStringBuf name) const {
+ return Get(name);
+}
+
+bool THeaders::Has(TStringBuf name) const {
+ return Headers.count(name) != 0;
+}
+
+TStringBuf THeaders::Get(TStringBuf name) const {
+ auto it = Headers.find(name);
+ if (it != Headers.end()) {
+ return it->second;
+ }
+ return TStringBuf();
+}
+
+TString THeaders::Render() const {
+ TStringBuilder headers;
+ for (const std::pair<TStringBuf, TStringBuf> header : Headers) {
+ headers << header.first;
+ headers << ": ";
+ headers << header.second;
+ headers << "\r\n";
+ }
+ return headers;
+}
+
+THeadersBuilder::THeadersBuilder()
+ :THeaders(TStringBuf())
+{}
+
+THeadersBuilder::THeadersBuilder(const THeadersBuilder& builder) {
+ for (const auto& pr : builder.Headers) {
+ Set(pr.first, pr.second);
+ }
+}
+
+void THeadersBuilder::Set(TStringBuf name, TStringBuf data) {
+ Data.emplace_back(name, data);
+ Headers[Data.back().first] = Data.back().second;
+}
+
+}
diff --git a/library/cpp/actors/http/http.h b/library/cpp/actors/http/http.h
new file mode 100644
index 0000000000..96c5c1ec48
--- /dev/null
+++ b/library/cpp/actors/http/http.h
@@ -0,0 +1,703 @@
+#pragma once
+#include <util/datetime/base.h>
+#include <util/string/builder.h>
+#include <util/system/thread.h>
+#include <util/system/hp_timer.h>
+#include <util/generic/hash_set.h>
+#include <util/generic/buffer.h>
+#include <util/generic/intrlist.h>
+#include "http_config.h"
+
+// TODO(xenoxeno): hide in implementation
+template <typename Type>
+struct THash<TIntrusivePtr<Type>> {
+ size_t operator ()(const TIntrusivePtr<Type>& ptr) const { return reinterpret_cast<size_t>(ptr.Get()); }
+};
+
+template<>
+inline void Out<TSockAddrInet6>(IOutputStream& o, const TSockAddrInet6& x) {
+ o << x.ToString();
+}
+
+namespace NHttp {
+
+bool IsIPv6(const TString& host);
+bool CrackURL(TStringBuf url, TStringBuf& scheme, TStringBuf& host, TStringBuf& uri);
+void CrackAddress(const TString& address, TString& hostname, TIpPort& port);
+void TrimBegin(TStringBuf& target, char delim);
+void TrimEnd(TStringBuf& target, char delim);
+void Trim(TStringBuf& target, char delim);
+void TrimEnd(TString& target, char delim);
+
+struct TLessNoCase {
+ bool operator()(TStringBuf l, TStringBuf r) const {
+ auto ll = l.length();
+ auto rl = r.length();
+ if (ll != rl) {
+ return ll < rl;
+ }
+ return strnicmp(l.data(), r.data(), ll) < 0;
+ }
+};
+
+struct TUrlParameters {
+ THashMap<TStringBuf, TStringBuf> Parameters;
+
+ TUrlParameters(TStringBuf url);
+ TString operator [](TStringBuf name) const;
+ bool Has(TStringBuf name) const;
+ TStringBuf Get(TStringBuf name) const; // raw
+ TString Render() const;
+};
+
+struct TCookies {
+ THashMap<TStringBuf, TStringBuf> Cookies;
+
+ TCookies(TStringBuf cookie);
+ TCookies(const TCookies&) = delete;
+ TStringBuf operator [](TStringBuf name) const;
+ bool Has(TStringBuf name) const;
+ TStringBuf Get(TStringBuf name) const; // raw
+ TString Render() const;
+};
+
+struct TCookiesBuilder : TCookies {
+ TDeque<std::pair<TString, TString>> Data;
+
+ TCookiesBuilder();
+ void Set(TStringBuf name, TStringBuf data);
+};
+
+struct THeaders {
+ TMap<TStringBuf, TStringBuf, TLessNoCase> Headers;
+
+ THeaders() = default;
+ THeaders(TStringBuf headers);
+ THeaders(const THeaders&) = delete;
+ TStringBuf operator [](TStringBuf name) const;
+ bool Has(TStringBuf name) const;
+ TStringBuf Get(TStringBuf name) const; // raw
+ TString Render() const;
+};
+
+struct THeadersBuilder : THeaders {
+ TDeque<std::pair<TString, TString>> Data;
+
+ THeadersBuilder();
+ THeadersBuilder(const THeadersBuilder& builder);
+ void Set(TStringBuf name, TStringBuf data);
+};
+
+class TSocketBuffer : public TBuffer, public THttpConfig {
+public:
+ TSocketBuffer()
+ : TBuffer(BUFFER_SIZE)
+ {}
+
+ bool EnsureEnoughSpaceAvailable(size_t need) {
+ size_t avail = Avail();
+ if (avail < need) {
+ Reserve(Capacity() + std::max(need, BUFFER_MIN_STEP));
+ return false;
+ }
+ return true;
+ }
+};
+
+class THttpRequest {
+public:
+ TStringBuf Method;
+ TStringBuf URL;
+ TStringBuf Protocol;
+ TStringBuf Version;
+ TStringBuf Headers;
+
+ TStringBuf Host;
+ TStringBuf Accept;
+ TStringBuf Connection;
+ TStringBuf ContentType;
+ TStringBuf ContentLength;
+ TStringBuf TransferEncoding;
+
+ TStringBuf Body;
+
+ static const TMap<TStringBuf, TStringBuf THttpRequest::*, TLessNoCase> HeadersLocation;
+
+ template <TStringBuf THttpRequest::* Header>
+ static TStringBuf GetName();
+ void Clear();
+};
+
+class THttpResponse {
+public:
+ TStringBuf Protocol;
+ TStringBuf Version;
+ TStringBuf Status;
+ TStringBuf Message;
+ TStringBuf Headers;
+
+ TStringBuf Connection;
+ TStringBuf ContentType;
+ TStringBuf ContentLength;
+ TStringBuf TransferEncoding;
+ TStringBuf LastModified;
+ TStringBuf ContentEncoding;
+
+ TStringBuf Body;
+
+ static const TMap<TStringBuf, TStringBuf THttpResponse::*, TLessNoCase> HeadersLocation;
+
+ template <TStringBuf THttpResponse::* Header>
+ static TStringBuf GetName();
+ void Clear();
+};
+
+template <typename HeaderType, typename BufferType>
+class THttpParser : public HeaderType, public BufferType {
+public:
+ enum class EParseStage : ui8 {
+ Method,
+ URL,
+ Protocol,
+ Version,
+ Status,
+ Message,
+ Header,
+ Body,
+ ChunkLength,
+ ChunkData,
+ Done,
+ Error,
+ };
+
+ static constexpr size_t MaxMethodSize = 6;
+ static constexpr size_t MaxURLSize = 1024;
+ static constexpr size_t MaxProtocolSize = 4;
+ static constexpr size_t MaxVersionSize = 4;
+ static constexpr size_t MaxStatusSize = 3;
+ static constexpr size_t MaxMessageSize = 1024;
+ static constexpr size_t MaxHeaderSize = 8192;
+ static constexpr size_t MaxChunkLengthSize = 8;
+ static constexpr size_t MaxChunkSize = 256 * 1024 * 1024;
+ static constexpr size_t MaxChunkContentSize = 1 * 1024 * 1024 * 1024;
+
+ EParseStage Stage;
+ EParseStage LastSuccessStage;
+ TStringBuf Line;
+ TStringBuf& Header = Line;
+ size_t ChunkLength = 0;
+ size_t ContentSize = 0;
+ TString Content;
+
+ THttpParser(const THttpParser& src)
+ : HeaderType(src)
+ , BufferType(src)
+ , Stage(src.Stage)
+ , LastSuccessStage(src.LastSuccessStage)
+ , Line()
+ , Header(Line)
+ , ChunkLength(src.ChunkLength)
+ , ContentSize(src.ContentSize)
+ , Content(src.Content)
+ {}
+
+ template <typename StringType>
+ bool ProcessData(StringType& target, TStringBuf& source, char delim, size_t maxLen) {
+ TStringBuf maxSource(source.substr(0, maxLen + 1 - target.size()));
+ size_t pos = maxSource.find(delim);
+ target += maxSource.substr(0, pos);
+ source.Skip(pos);
+ if (target.size() > maxLen) {
+ Stage = EParseStage::Error;
+ return false;
+ }
+ if (!source.empty() && *source.begin() == delim) {
+ source.Skip(1);
+ }
+ return pos != TStringBuf::npos;
+ }
+
+ template <typename StringType>
+ bool ProcessData(StringType& target, TStringBuf& source, TStringBuf delim, size_t maxLen) {
+ if (delim.empty()) {
+ return false;
+ }
+ if (delim.size() == 1) {
+ return ProcessData(target, source, delim[0], maxLen);
+ }
+ if (ProcessData(target, source, delim.back(), maxLen + 1)) {
+ for (signed i = delim.size() - 2; i >= 0; --i) {
+ TrimEnd(target, delim[i]);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ template <typename StringType>
+ bool ProcessData(StringType& target, TStringBuf& source, size_t size) {
+ TStringBuf maxSource(source.substr(0, size - target.size()));
+ target += maxSource;
+ source.Skip(maxSource.size());
+ if (target.size() > size && !source.empty()) {
+ Stage = EParseStage::Error;
+ return false;
+ }
+ return target.size() == size;
+ }
+
+ void ProcessHeader(TStringBuf& header) {
+ TStringBuf name = header.NextTok(':');
+ TrimBegin(name, ' ');
+ TStringBuf value = header;
+ Trim(value, ' ');
+ auto cit = HeaderType::HeadersLocation.find(name);
+ if (cit != HeaderType::HeadersLocation.end()) {
+ this->*cit->second = value;
+ }
+ header.Clear();
+ }
+
+ size_t ParseHex(TStringBuf value) {
+ size_t result = 0;
+ for (char ch : value) {
+ if (ch >= '0' && ch <= '9') {
+ result *= 16;
+ result += ch - '0';
+ } else if (ch >= 'a' && ch <= 'f') {
+ result *= 16;
+ result += 10 + ch - 'a';
+ } else if (ch >= 'A' && ch <= 'F') {
+ result *= 16;
+ result += 10 + ch - 'A';
+ } else if (ch == ';') {
+ break;
+ } else if (isspace(ch)) {
+ continue;
+ } else {
+ Stage = EParseStage::Error;
+ return 0;
+ }
+ }
+ return result;
+ }
+
+ void Advance(size_t len);
+ void ConnectionClosed();
+
+ void Clear() {
+ BufferType::Clear();
+ HeaderType::Clear();
+ Stage = GetInitialStage();
+ Line.Clear();
+ Content.clear();
+ }
+
+ bool IsReady() const {
+ return Stage == EParseStage::Done;
+ }
+
+ bool IsError() const {
+ return Stage == EParseStage::Error;
+ }
+
+ TStringBuf GetErrorText() const {
+ switch (LastSuccessStage) {
+ case EParseStage::Method:
+ return "Invalid http method";
+ case EParseStage::URL:
+ return "Invalid url";
+ case EParseStage::Protocol:
+ return "Invalid http protocol";
+ case EParseStage::Version:
+ return "Invalid http version";
+ case EParseStage::Status:
+ return "Invalid http status";
+ case EParseStage::Message:
+ return "Invalid http message";
+ case EParseStage::Header:
+ return "Invalid http header";
+ case EParseStage::Body:
+ return "Invalid content body";
+ case EParseStage::ChunkLength:
+ case EParseStage::ChunkData:
+ return "Broken chunked data";
+ case EParseStage::Done:
+ return "Everything is fine";
+ case EParseStage::Error:
+ return "Error on error"; // wat? ...because we don't want to include default label here
+ }
+ }
+
+ bool IsDone() const {
+ return IsReady() || IsError();
+ }
+
+ bool HaveBody() const {
+ return !HeaderType::ContentType.empty() || !HeaderType::ContentLength.empty() || !HeaderType::TransferEncoding.empty();
+ }
+
+ bool EnsureEnoughSpaceAvailable(size_t need = BufferType::BUFFER_MIN_STEP) {
+ bool result = BufferType::EnsureEnoughSpaceAvailable(need);
+ if (!result && !BufferType::Empty()) {
+ Reparse();
+ }
+ return true;
+ }
+
+ void Reparse() {
+ size_t size = BufferType::Size();
+ Clear();
+ Advance(size);
+ }
+
+ TStringBuf GetRawData() const {
+ return TStringBuf(BufferType::Data(), BufferType::Size());
+ }
+
+ TString GetObfuscatedData() const {
+ THeaders headers(HeaderType::Headers);
+ TStringBuf authorization(headers["Authorization"]);
+ TStringBuf cookie(headers["Cookie"]);
+ TStringBuf x_ydb_auth_ticket(headers["x-ydb-auth-ticket"]);
+ TStringBuf x_yacloud_subjecttoken(headers["x-yacloud-subjecttoken"]);
+ TString data(GetRawData());
+ if (!authorization.empty()) {
+ auto pos = data.find(authorization);
+ if (pos != TString::npos) {
+ data.replace(pos, authorization.size(), TString("<obfuscated>"));
+ }
+ }
+ if (!cookie.empty()) {
+ auto pos = data.find(cookie);
+ if (pos != TString::npos) {
+ data.replace(pos, cookie.size(), TString("<obfuscated>"));
+ }
+ }
+ if (!x_ydb_auth_ticket.empty()) {
+ auto pos = data.find(x_ydb_auth_ticket);
+ if (pos != TString::npos) {
+ data.replace(pos, x_ydb_auth_ticket.size(), TString("<obfuscated>"));
+ }
+ }
+ if (!x_yacloud_subjecttoken.empty()) {
+ auto pos = data.find(x_yacloud_subjecttoken);
+ if (pos != TString::npos) {
+ data.replace(pos, x_yacloud_subjecttoken.size(), TString("<obfuscated>"));
+ }
+ }
+ return data;
+ }
+
+ static EParseStage GetInitialStage();
+
+ THttpParser()
+ : Stage(GetInitialStage())
+ , LastSuccessStage(Stage)
+ {}
+};
+
+template <typename HeaderType, typename BufferType>
+class THttpRenderer : public HeaderType, public BufferType {
+public:
+ enum class ERenderStage {
+ Init,
+ Header,
+ Body,
+ Done,
+ Error,
+ };
+
+ ERenderStage Stage = ERenderStage::Init;
+
+ void Append(TStringBuf text) {
+ EnsureEnoughSpaceAvailable(text.size());
+ BufferType::Append(text.data(), text.size());
+ }
+
+ void Append(char c) {
+ EnsureEnoughSpaceAvailable(sizeof(c));
+ BufferType::Append(c);
+ }
+
+ template <TStringBuf HeaderType::* string>
+ void AppendParsedValue(TStringBuf value) {
+ Append(value);
+ static_cast<HeaderType*>(this)->*string = TStringBuf(BufferType::Pos() - value.size(), value.size());
+ }
+
+ template <TStringBuf HeaderType::* name>
+ void Set(TStringBuf value) {
+ Y_VERIFY_DEBUG(Stage == ERenderStage::Header);
+ Append(HeaderType::template GetName<name>());
+ Append(": ");
+ AppendParsedValue<name>(value);
+ Append("\r\n");
+ HeaderType::Headers = TStringBuf(HeaderType::Headers.Data(), BufferType::Pos() - HeaderType::Headers.Data());
+ }
+
+ void Set(TStringBuf name, TStringBuf value) {
+ Y_VERIFY_DEBUG(Stage == ERenderStage::Header);
+ Append(name);
+ Append(": ");
+ Append(value);
+ Append("\r\n");
+ HeaderType::Headers = TStringBuf(HeaderType::Headers.Data(), BufferType::Pos() - HeaderType::Headers.Data());
+ }
+
+ void Set(const THeaders& headers) {
+ Y_VERIFY_DEBUG(Stage == ERenderStage::Header);
+ Append(headers.Render());
+ HeaderType::Headers = TStringBuf(HeaderType::Headers.Data(), BufferType::Pos() - HeaderType::Headers.Data());
+ }
+
+ //THttpRenderer(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version); // request
+ void InitRequest(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version) {
+ Y_VERIFY_DEBUG(Stage == ERenderStage::Init);
+ AppendParsedValue<&THttpRequest::Method>(method);
+ Append(' ');
+ AppendParsedValue<&THttpRequest::URL>(url);
+ Append(' ');
+ AppendParsedValue<&THttpRequest::Protocol>(protocol);
+ Append('/');
+ AppendParsedValue<&THttpRequest::Version>(version);
+ Append("\r\n");
+ Stage = ERenderStage::Header;
+ HeaderType::Headers = TStringBuf(BufferType::Pos(), size_t(0));
+ }
+
+ //THttpRenderer(TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message); // response
+ void InitResponse(TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message) {
+ Y_VERIFY_DEBUG(Stage == ERenderStage::Init);
+ AppendParsedValue<&THttpResponse::Protocol>(protocol);
+ Append('/');
+ AppendParsedValue<&THttpResponse::Version>(version);
+ Append(' ');
+ AppendParsedValue<&THttpResponse::Status>(status);
+ Append(' ');
+ AppendParsedValue<&THttpResponse::Message>(message);
+ Append("\r\n");
+ Stage = ERenderStage::Header;
+ HeaderType::Headers = TStringBuf(BufferType::Pos(), size_t(0));
+ }
+
+ void FinishHeader() {
+ Append("\r\n");
+ HeaderType::Headers = TStringBuf(HeaderType::Headers.Data(), BufferType::Pos() - HeaderType::Headers.Data());
+ Stage = ERenderStage::Body;
+ }
+
+ void SetBody(TStringBuf body) {
+ Y_VERIFY_DEBUG(Stage == ERenderStage::Header);
+ if (HeaderType::ContentLength.empty()) {
+ Set<&HeaderType::ContentLength>(ToString(body.size()));
+ }
+ FinishHeader();
+ AppendParsedValue<&HeaderType::Body>(body);
+ Stage = ERenderStage::Done;
+ }
+
+ bool IsDone() const {
+ return Stage == ERenderStage::Done;
+ }
+
+ void Finish() {
+ switch (Stage) {
+ case ERenderStage::Header:
+ FinishHeader();
+ break;
+ default:
+ break;
+ }
+ }
+
+ bool EnsureEnoughSpaceAvailable(size_t need = BufferType::BUFFER_MIN_STEP) {
+ bool result = BufferType::EnsureEnoughSpaceAvailable(need);
+ if (!result && !BufferType::Empty()) {
+ Reparse();
+ }
+ return true;
+ }
+
+ void Clear() {
+ BufferType::Clear();
+ HeaderType::Clear();
+ }
+
+ void Reparse() {
+ // move-magic
+ size_t size = BufferType::Size();
+ THttpParser<HeaderType, BufferType> parser;
+ // move the buffer to parser
+ static_cast<BufferType&>(parser) = std::move(static_cast<BufferType&>(*this));
+ // reparse
+ parser.Clear();
+ parser.Advance(size);
+ // move buffer and result back
+ static_cast<HeaderType&>(*this) = std::move(static_cast<HeaderType&>(parser));
+ static_cast<BufferType&>(*this) = std::move(static_cast<BufferType&>(parser));
+ switch (parser.Stage) {
+ case THttpParser<HeaderType, BufferType>::EParseStage::Method:
+ case THttpParser<HeaderType, BufferType>::EParseStage::URL:
+ case THttpParser<HeaderType, BufferType>::EParseStage::Protocol:
+ case THttpParser<HeaderType, BufferType>::EParseStage::Version:
+ case THttpParser<HeaderType, BufferType>::EParseStage::Status:
+ case THttpParser<HeaderType, BufferType>::EParseStage::Message:
+ Stage = ERenderStage::Init;
+ break;
+ case THttpParser<HeaderType, BufferType>::EParseStage::Header:
+ Stage = ERenderStage::Header;
+ break;
+ case THttpParser<HeaderType, BufferType>::EParseStage::Body:
+ case THttpParser<HeaderType, BufferType>::EParseStage::ChunkLength:
+ case THttpParser<HeaderType, BufferType>::EParseStage::ChunkData:
+ Stage = ERenderStage::Body;
+ break;
+ case THttpParser<HeaderType, BufferType>::EParseStage::Done:
+ Stage = ERenderStage::Done;
+ break;
+ case THttpParser<HeaderType, BufferType>::EParseStage::Error:
+ Stage = ERenderStage::Error;
+ break;
+ }
+ Y_VERIFY(size == BufferType::Size());
+ }
+
+ TStringBuf GetRawData() const {
+ return TStringBuf(BufferType::Data(), BufferType::Size());
+ }
+};
+
+template <>
+template <>
+inline void THttpRenderer<THttpResponse, TSocketBuffer>::Set<&THttpResponse::Body>(TStringBuf value) {
+ SetBody(value);
+}
+
+template <>
+template <>
+inline void THttpRenderer<THttpRequest, TSocketBuffer>::Set<&THttpRequest::Body>(TStringBuf value) {
+ SetBody(value);
+}
+
+class THttpIncomingRequest;
+using THttpIncomingRequestPtr = TIntrusivePtr<THttpIncomingRequest>;
+
+class THttpOutgoingResponse;
+using THttpOutgoingResponsePtr = TIntrusivePtr<THttpOutgoingResponse>;
+
+class THttpIncomingRequest :
+ public THttpParser<THttpRequest, TSocketBuffer>,
+ public TRefCounted<THttpIncomingRequest, TAtomicCounter> {
+public:
+ THttpConfig::SocketAddressType Address;
+ TString WorkerName;
+ THPTimer Timer;
+ bool Secure = false;
+
+ bool IsConnectionClose() const {
+ if (Connection.empty()) {
+ return Version == "1.0";
+ } else {
+ return Connection == "close";
+ }
+ }
+
+ TStringBuf GetConnection() const {
+ if (!Connection.empty()) {
+ return Connection;
+ }
+ return Version == "1.0" ? "close" : "keep-alive";
+ }
+
+ THttpOutgoingResponsePtr CreateResponseOK(TStringBuf body, TStringBuf contentType = "text/html", TInstant lastModified = TInstant());
+ THttpOutgoingResponsePtr CreateResponseString(TStringBuf data);
+ THttpOutgoingResponsePtr CreateResponseBadRequest(TStringBuf html = TStringBuf(), TStringBuf contentType = "text/html"); // 400
+ THttpOutgoingResponsePtr CreateResponseNotFound(TStringBuf html = TStringBuf(), TStringBuf contentType = "text/html"); // 404
+ THttpOutgoingResponsePtr CreateResponseServiceUnavailable(TStringBuf html = TStringBuf(), TStringBuf contentType = "text/html"); // 503
+ THttpOutgoingResponsePtr CreateResponseGatewayTimeout(TStringBuf html = TStringBuf(), TStringBuf contentType = "text/html"); // 504
+ THttpOutgoingResponsePtr CreateResponse(
+ TStringBuf status,
+ TStringBuf message,
+ TStringBuf contentType = TStringBuf(),
+ TStringBuf body = TStringBuf(),
+ TInstant lastModified = TInstant());
+
+ THttpIncomingRequestPtr Duplicate();
+};
+
+class THttpIncomingResponse;
+using THttpIncomingResponsePtr = TIntrusivePtr<THttpIncomingResponse>;
+
+class THttpOutgoingRequest;
+using THttpOutgoingRequestPtr = TIntrusivePtr<THttpOutgoingRequest>;
+
+class THttpIncomingResponse :
+ public THttpParser<THttpResponse, TSocketBuffer>,
+ public TRefCounted<THttpIncomingResponse, TAtomicCounter> {
+public:
+ THttpIncomingResponse(THttpOutgoingRequestPtr request);
+
+ THttpOutgoingRequestPtr GetRequest() const {
+ return Request;
+ }
+
+ THttpIncomingResponsePtr Duplicate(THttpOutgoingRequestPtr request);
+ THttpOutgoingResponsePtr Reverse(THttpIncomingRequestPtr request);
+
+protected:
+ THttpOutgoingRequestPtr Request;
+};
+
+class THttpOutgoingRequest :
+ public THttpRenderer<THttpRequest, TSocketBuffer>,
+ public TRefCounted<THttpOutgoingRequest, TAtomicCounter> {
+public:
+ THPTimer Timer;
+ bool Secure = false;
+
+ THttpOutgoingRequest() = default;
+ THttpOutgoingRequest(TStringBuf method, TStringBuf url, TStringBuf protocol, TStringBuf version);
+ THttpOutgoingRequest(TStringBuf method, TStringBuf scheme, TStringBuf host, TStringBuf uri, TStringBuf protocol, TStringBuf version);
+ static THttpOutgoingRequestPtr CreateRequestString(TStringBuf data);
+ static THttpOutgoingRequestPtr CreateRequestString(const TString& data);
+ static THttpOutgoingRequestPtr CreateRequestGet(TStringBuf url);
+ static THttpOutgoingRequestPtr CreateRequestGet(TStringBuf host, TStringBuf uri); // http only
+ static THttpOutgoingRequestPtr CreateRequestPost(TStringBuf url, TStringBuf contentType = {}, TStringBuf body = {});
+ static THttpOutgoingRequestPtr CreateRequestPost(TStringBuf host, TStringBuf uri, TStringBuf contentType, TStringBuf body); // http only
+ static THttpOutgoingRequestPtr CreateRequest(TStringBuf method, TStringBuf url, TStringBuf contentType = TStringBuf(), TStringBuf body = TStringBuf());
+ static THttpOutgoingRequestPtr CreateHttpRequest(TStringBuf method, TStringBuf host, TStringBuf uri, TStringBuf contentType = TStringBuf(), TStringBuf body = TStringBuf());
+ THttpOutgoingRequestPtr Duplicate();
+};
+
+class THttpOutgoingResponse :
+ public THttpRenderer<THttpResponse, TSocketBuffer>,
+ public TRefCounted<THttpOutgoingResponse, TAtomicCounter> {
+public:
+ THttpOutgoingResponse(THttpIncomingRequestPtr request);
+ THttpOutgoingResponse(THttpIncomingRequestPtr request, TStringBuf protocol, TStringBuf version, TStringBuf status, TStringBuf message);
+
+ bool IsConnectionClose() const {
+ if (!Connection.empty()) {
+ return Connection == "close";
+ } else {
+ return Request->IsConnectionClose();
+ }
+ }
+
+ bool IsNeedBody() const {
+ return Status != "204";
+ }
+
+ THttpIncomingRequestPtr GetRequest() const {
+ return Request;
+ }
+
+ THttpOutgoingResponsePtr Duplicate(THttpIncomingRequestPtr request);
+
+// it's temporary accessible for cleanup
+//protected:
+ THttpIncomingRequestPtr Request;
+};
+
+}
diff --git a/library/cpp/actors/http/http_cache.cpp b/library/cpp/actors/http/http_cache.cpp
new file mode 100644
index 0000000000..27c4eeb6f3
--- /dev/null
+++ b/library/cpp/actors/http/http_cache.cpp
@@ -0,0 +1,599 @@
+#include "http.h"
+#include "http_proxy.h"
+#include "http_cache.h"
+#include <library/cpp/actors/core/actor_bootstrapped.h>
+#include <library/cpp/actors/core/executor_pool_basic.h>
+#include <library/cpp/actors/core/log.h>
+#include <library/cpp/actors/core/scheduler_basic.h>
+#include <library/cpp/actors/http/http.h>
+#include <library/cpp/digest/md5/md5.h>
+#include <util/digest/multi.h>
+#include <util/generic/queue.h>
+#include <util/string/cast.h>
+
+namespace NHttp {
+
+class THttpOutgoingCacheActor : public NActors::TActorBootstrapped<THttpOutgoingCacheActor>, THttpConfig {
+public:
+ using TBase = NActors::TActorBootstrapped<THttpOutgoingCacheActor>;
+ NActors::TActorId HttpProxyId;
+ TGetCachePolicy GetCachePolicy;
+ static constexpr TDuration RefreshTimeout = TDuration::Seconds(1);
+
+ struct TCacheKey {
+ TString Host;
+ TString URL;
+ TString Headers;
+
+ operator size_t() const {
+ return MultiHash(Host, URL, Headers);
+ }
+
+ TString GetId() const {
+ return MD5::Calc(Host + ':' + URL + ':' + Headers);
+ }
+ };
+
+ struct TCacheRecord {
+ TInstant RefreshTime;
+ TInstant DeathTime;
+ TCachePolicy CachePolicy;
+ NHttp::THttpOutgoingRequestPtr Request;
+ NHttp::THttpOutgoingRequestPtr OutgoingRequest;
+ TDuration Timeout;
+ NHttp::THttpIncomingResponsePtr Response;
+ TString Error;
+ TVector<NHttp::TEvHttpProxy::TEvHttpOutgoingRequest::TPtr> Waiters;
+
+ TCacheRecord(const TCachePolicy cachePolicy)
+ : CachePolicy(cachePolicy)
+ {}
+
+ bool IsValid() const {
+ return Response != nullptr || !Error.empty();
+ }
+
+ void UpdateResponse(NHttp::THttpIncomingResponsePtr response, const TString& error, TInstant now) {
+ if (error.empty() || Response == nullptr || !CachePolicy.KeepOnError) {
+ Response = response;
+ Error = error;
+ }
+ RefreshTime = now + CachePolicy.TimeToRefresh;
+ if (CachePolicy.PaceToRefresh) {
+ RefreshTime += TDuration::MilliSeconds(RandomNumber<ui64>() % CachePolicy.PaceToRefresh.MilliSeconds());
+ }
+ }
+
+ TString GetName() const {
+ return TStringBuilder() << (Request->Secure ? "https://" : "http://") << Request->Host << Request->URL;
+ }
+ };
+
+ struct TRefreshRecord {
+ TCacheKey Key;
+ TInstant RefreshTime;
+
+ bool operator <(const TRefreshRecord& b) const {
+ return RefreshTime > b.RefreshTime;
+ }
+ };
+
+ THashMap<TCacheKey, TCacheRecord> Cache;
+ TPriorityQueue<TRefreshRecord> RefreshQueue;
+ THashMap<THttpOutgoingRequest*, TCacheKey> OutgoingRequests;
+
+ THttpOutgoingCacheActor(const NActors::TActorId& httpProxyId, TGetCachePolicy getCachePolicy)
+ : HttpProxyId(httpProxyId)
+ , GetCachePolicy(std::move(getCachePolicy))
+ {}
+
+ void Bootstrap(const NActors::TActorContext&) {
+ //
+ Become(&THttpOutgoingCacheActor::StateWork, RefreshTimeout, new NActors::TEvents::TEvWakeup());
+ }
+
+ static TString GetCacheHeadersKey(const NHttp::THttpOutgoingRequest* request, const TCachePolicy& policy) {
+ TStringBuilder key;
+ if (!policy.HeadersToCacheKey.empty()) {
+ NHttp::THeaders headers(request->Headers);
+ for (const TString& header : policy.HeadersToCacheKey) {
+ key << headers[header];
+ }
+ }
+ return key;
+ }
+
+ static TCacheKey GetCacheKey(const NHttp::THttpOutgoingRequest* request, const TCachePolicy& policy) {
+ return { ToString(request->Host), ToString(request->URL), GetCacheHeadersKey(request, policy) };
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpOutgoingResponse::TPtr event, const NActors::TActorContext& ctx) {
+ ctx.Send(event->Forward(HttpProxyId));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ ctx.Send(event->Forward(HttpProxyId));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) {
+ ctx.Send(event->Forward(HttpProxyId));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvRegisterHandler::TPtr event, const NActors::TActorContext& ctx) {
+ ctx.Send(event->Forward(HttpProxyId));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingResponse::TPtr event, const NActors::TActorContext& ctx) {
+ NHttp::THttpOutgoingRequestPtr request(event->Get()->Request);
+ NHttp::THttpIncomingResponsePtr response(event->Get()->Response);
+ auto itRequests = OutgoingRequests.find(request.Get());
+ if (itRequests == OutgoingRequests.end()) {
+ LOG_ERROR_S(ctx, HttpLog, "Cache received response to unknown request " << request->Host << request->URL);
+ return;
+ }
+ auto key = itRequests->second;
+ OutgoingRequests.erase(itRequests);
+ auto it = Cache.find(key);
+ if (it == Cache.end()) {
+ LOG_ERROR_S(ctx, HttpLog, "Cache received response to unknown cache key " << request->Host << request->URL);
+ return;
+ }
+ TCacheRecord& cacheRecord = it->second;
+ cacheRecord.OutgoingRequest.Reset();
+ for (auto& waiter : cacheRecord.Waiters) {
+ NHttp::THttpIncomingResponsePtr response2;
+ TString error2;
+ if (response != nullptr) {
+ response2 = response->Duplicate(waiter->Get()->Request);
+ }
+ if (!event->Get()->Error.empty()) {
+ error2 = event->Get()->Error;
+ }
+ ctx.Send(waiter->Sender, new NHttp::TEvHttpProxy::TEvHttpIncomingResponse(waiter->Get()->Request, response2, error2));
+ }
+ cacheRecord.Waiters.clear();
+ TString error;
+ if (event->Get()->Error.empty()) {
+ if (event->Get()->Response != nullptr && event->Get()->Response->Status != "200") {
+ error = event->Get()->Response->Message;
+ }
+ } else {
+ error = event->Get()->Error;
+ }
+ if (!error.empty()) {
+ LOG_WARN_S(ctx, HttpLog, "Error from " << cacheRecord.GetName() << ": " << error);
+ }
+ LOG_DEBUG_S(ctx, HttpLog, "OutgoingUpdate " << cacheRecord.GetName());
+ cacheRecord.UpdateResponse(response, event->Get()->Error, ctx.Now());
+ RefreshQueue.push({it->first, it->second.RefreshTime});
+ LOG_DEBUG_S(ctx, HttpLog, "OutgoingSchedule " << cacheRecord.GetName() << " at " << cacheRecord.RefreshTime << " until " << cacheRecord.DeathTime);
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ const NHttp::THttpOutgoingRequest* request = event->Get()->Request.Get();
+ auto policy = GetCachePolicy(request);
+ if (policy.TimeToExpire == TDuration()) {
+ ctx.Send(event->Forward(HttpProxyId));
+ return;
+ }
+ auto key = GetCacheKey(request, policy);
+ auto it = Cache.find(key);
+ if (it != Cache.end()) {
+ if (it->second.IsValid()) {
+ LOG_DEBUG_S(ctx, HttpLog, "OutgoingRespond "
+ << it->second.GetName()
+ << " ("
+ << ((it->second.Response != nullptr) ? ToString(it->second.Response->Size()) : TString("error"))
+ << ")");
+ NHttp::THttpIncomingResponsePtr response = it->second.Response;
+ if (response != nullptr) {
+ response = response->Duplicate(event->Get()->Request);
+ }
+ ctx.Send(event->Sender,
+ new NHttp::TEvHttpProxy::TEvHttpIncomingResponse(event->Get()->Request,
+ response,
+ it->second.Error));
+ it->second.DeathTime = ctx.Now() + it->second.CachePolicy.TimeToExpire; // prolong active cache items
+ return;
+ }
+ } else {
+ it = Cache.emplace(key, policy).first;
+ it->second.Request = event->Get()->Request;
+ it->second.Timeout = event->Get()->Timeout;
+ it->second.OutgoingRequest = it->second.Request->Duplicate();
+ OutgoingRequests[it->second.OutgoingRequest.Get()] = key;
+ LOG_DEBUG_S(ctx, HttpLog, "OutgoingInitiate " << it->second.GetName());
+ ctx.Send(HttpProxyId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(it->second.OutgoingRequest, it->second.Timeout));
+ }
+ it->second.DeathTime = ctx.Now() + it->second.CachePolicy.TimeToExpire;
+ it->second.Waiters.emplace_back(std::move(event));
+ }
+
+ void HandleRefresh(const NActors::TActorContext& ctx) {
+ while (!RefreshQueue.empty() && RefreshQueue.top().RefreshTime <= ctx.Now()) {
+ TRefreshRecord rrec = RefreshQueue.top();
+ RefreshQueue.pop();
+ auto it = Cache.find(rrec.Key);
+ if (it != Cache.end()) {
+ if (it->second.DeathTime > ctx.Now()) {
+ LOG_DEBUG_S(ctx, HttpLog, "OutgoingRefresh " << it->second.GetName());
+ it->second.OutgoingRequest = it->second.Request->Duplicate();
+ OutgoingRequests[it->second.OutgoingRequest.Get()] = it->first;
+ ctx.Send(HttpProxyId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(it->second.OutgoingRequest, it->second.Timeout));
+ } else {
+ LOG_DEBUG_S(ctx, HttpLog, "OutgoingForget " << it->second.GetName());
+ if (it->second.OutgoingRequest) {
+ OutgoingRequests.erase(it->second.OutgoingRequest.Get());
+ }
+ Cache.erase(it);
+ }
+ }
+ }
+ ctx.Schedule(RefreshTimeout, new NActors::TEvents::TEvWakeup());
+ }
+
+ STFUNC(StateWork) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingResponse, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvHttpOutgoingRequest, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvAddListeningPort, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvRegisterHandler, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvHttpOutgoingResponse, Handle);
+ CFunc(NActors::TEvents::TSystem::Wakeup, HandleRefresh);
+ }
+ }
+};
+
+const TDuration THttpOutgoingCacheActor::RefreshTimeout;
+
+class THttpIncomingCacheActor : public NActors::TActorBootstrapped<THttpIncomingCacheActor>, THttpConfig {
+public:
+ using TBase = NActors::TActorBootstrapped<THttpIncomingCacheActor>;
+ NActors::TActorId HttpProxyId;
+ TGetCachePolicy GetCachePolicy;
+ static constexpr TDuration RefreshTimeout = TDuration::Seconds(1);
+ THashMap<TString, TActorId> Handlers;
+
+ struct TCacheKey {
+ TString Host;
+ TString URL;
+ TString Headers;
+
+ operator size_t() const {
+ return MultiHash(Host, URL, Headers);
+ }
+
+ TString GetId() const {
+ return MD5::Calc(Host + ':' + URL + ':' + Headers);
+ }
+ };
+
+ struct TCacheRecord {
+ TInstant RefreshTime;
+ TInstant DeathTime;
+ TCachePolicy CachePolicy;
+ TString CacheId;
+ NHttp::THttpIncomingRequestPtr Request;
+ TDuration Timeout;
+ NHttp::THttpOutgoingResponsePtr Response;
+ TVector<NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr> Waiters;
+ ui32 Retries = 0;
+ bool Enqueued = false;
+
+ TCacheRecord(const TCachePolicy cachePolicy)
+ : CachePolicy(cachePolicy)
+ {}
+
+ bool IsValid() const {
+ return Response != nullptr;
+ }
+
+ void InitRequest(NHttp::THttpIncomingRequestPtr request) {
+ Request = request;
+ if (CachePolicy.TimeToExpire) {
+ DeathTime = NActors::TlsActivationContext->Now() + CachePolicy.TimeToExpire;
+ }
+ }
+
+ void UpdateResponse(NHttp::THttpOutgoingResponsePtr response, const TString& error, TInstant now) {
+ if (error.empty() || !CachePolicy.KeepOnError) {
+ Response = response;
+ }
+ Retries = 0;
+ if (CachePolicy.TimeToRefresh) {
+ RefreshTime = now + CachePolicy.TimeToRefresh;
+ if (CachePolicy.PaceToRefresh) {
+ RefreshTime += TDuration::MilliSeconds(RandomNumber<ui64>() % CachePolicy.PaceToRefresh.MilliSeconds());
+ }
+ }
+ }
+
+ void UpdateExpireTime() {
+ if (CachePolicy.TimeToExpire) {
+ DeathTime = NActors::TlsActivationContext->Now() + CachePolicy.TimeToExpire;
+ }
+ }
+
+ TString GetName() const {
+ return TStringBuilder() << (Request->Secure ? "https://" : "http://") << Request->Host << Request->URL
+ << " (" << CacheId << ")";
+ }
+ };
+
+ struct TRefreshRecord {
+ TCacheKey Key;
+ TInstant RefreshTime;
+
+ bool operator <(const TRefreshRecord& b) const {
+ return RefreshTime > b.RefreshTime;
+ }
+ };
+
+ THashMap<TCacheKey, TCacheRecord> Cache;
+ TPriorityQueue<TRefreshRecord> RefreshQueue;
+ THashMap<THttpIncomingRequest*, TCacheKey> IncomingRequests;
+
+ THttpIncomingCacheActor(const NActors::TActorId& httpProxyId, TGetCachePolicy getCachePolicy)
+ : HttpProxyId(httpProxyId)
+ , GetCachePolicy(std::move(getCachePolicy))
+ {}
+
+ void Bootstrap(const NActors::TActorContext&) {
+ //
+ Become(&THttpIncomingCacheActor::StateWork, RefreshTimeout, new NActors::TEvents::TEvWakeup());
+ }
+
+ static TString GetCacheHeadersKey(const NHttp::THttpIncomingRequest* request, const TCachePolicy& policy) {
+ TStringBuilder key;
+ if (!policy.HeadersToCacheKey.empty()) {
+ NHttp::THeaders headers(request->Headers);
+ for (const TString& header : policy.HeadersToCacheKey) {
+ key << headers[header];
+ }
+ }
+ return key;
+ }
+
+ static TCacheKey GetCacheKey(const NHttp::THttpIncomingRequest* request, const TCachePolicy& policy) {
+ return { ToString(request->Host), ToString(request->URL), GetCacheHeadersKey(request, policy) };
+ }
+
+ TActorId GetRequestHandler(NHttp::THttpIncomingRequestPtr request) {
+ TStringBuf url = request->URL.Before('?');
+ THashMap<TString, TActorId>::iterator it;
+ while (!url.empty()) {
+ it = Handlers.find(url);
+ if (it != Handlers.end()) {
+ return it->second;
+ } else {
+ if (url.EndsWith('/')) {
+ url.Trunc(url.size() - 1);
+ }
+ size_t pos = url.rfind('/');
+ if (pos == TStringBuf::npos) {
+ break;
+ } else {
+ url = url.substr(0, pos + 1);
+ }
+ }
+ }
+ return {};
+ }
+
+ void SendCacheRequest(const TCacheKey& cacheKey, TCacheRecord& cacheRecord, const NActors::TActorContext& ctx) {
+ cacheRecord.Request = cacheRecord.Request->Duplicate();
+ IncomingRequests[cacheRecord.Request.Get()] = cacheKey;
+ TActorId handler = GetRequestHandler(cacheRecord.Request);
+ if (handler) {
+ Send(handler, new NHttp::TEvHttpProxy::TEvHttpIncomingRequest(cacheRecord.Request));
+ } else {
+ LOG_ERROR_S(ctx, HttpLog, "Can't find cache handler for " << cacheRecord.GetName());
+ }
+ }
+
+ void DropCacheRecord(THashMap<TCacheKey, TCacheRecord>::iterator it) {
+ if (it->second.Request) {
+ IncomingRequests.erase(it->second.Request.Get());
+ }
+ for (auto& waiter : it->second.Waiters) {
+ NHttp::THttpOutgoingResponsePtr response;
+ response = waiter->Get()->Request->CreateResponseGatewayTimeout("Timeout", "text/plain");
+ Send(waiter->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
+ }
+ Cache.erase(it);
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingResponse::TPtr event, const NActors::TActorContext& ctx) {
+ ctx.Send(event->Forward(HttpProxyId));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ ctx.Send(event->Forward(HttpProxyId));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) {
+ ctx.Send(event->Forward(HttpProxyId));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvRegisterHandler::TPtr event, const NActors::TActorContext& ctx) {
+ Handlers[event->Get()->Path] = event->Get()->Handler;
+ ctx.Send(HttpProxyId, new NHttp::TEvHttpProxy::TEvRegisterHandler(event->Get()->Path, ctx.SelfID));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpOutgoingResponse::TPtr event, const NActors::TActorContext& ctx) {
+ NHttp::THttpIncomingRequestPtr request(event->Get()->Response->GetRequest());
+ NHttp::THttpOutgoingResponsePtr response(event->Get()->Response);
+ auto itRequests = IncomingRequests.find(request.Get());
+ if (itRequests == IncomingRequests.end()) {
+ LOG_ERROR_S(ctx, HttpLog, "Cache received response to unknown request " << request->Host << request->URL);
+ return;
+ }
+
+ TCacheKey key = itRequests->second;
+ auto it = Cache.find(key);
+ if (it == Cache.end()) {
+ LOG_ERROR_S(ctx, HttpLog, "Cache received response to unknown cache key " << request->Host << request->URL);
+ return;
+ }
+
+ IncomingRequests.erase(itRequests);
+ TCacheRecord& cacheRecord = it->second;
+ TStringBuf status;
+ TString error;
+
+ if (event->Get()->Response != nullptr) {
+ status = event->Get()->Response->Status;
+ if (!status.StartsWith("2")) {
+ error = event->Get()->Response->Message;
+ }
+ }
+ if (cacheRecord.CachePolicy.RetriesCount > 0) {
+ auto itStatusToRetry = std::find(cacheRecord.CachePolicy.StatusesToRetry.begin(), cacheRecord.CachePolicy.StatusesToRetry.end(), status);
+ if (itStatusToRetry != cacheRecord.CachePolicy.StatusesToRetry.end()) {
+ if (cacheRecord.Retries < cacheRecord.CachePolicy.RetriesCount) {
+ ++cacheRecord.Retries;
+ LOG_WARN_S(ctx, HttpLog, "IncomingRetry " << cacheRecord.GetName() << ": " << status << " " << error);
+ SendCacheRequest(key, cacheRecord, ctx);
+ return;
+ }
+ }
+ }
+ for (auto& waiter : cacheRecord.Waiters) {
+ NHttp::THttpOutgoingResponsePtr response2;
+ response2 = response->Duplicate(waiter->Get()->Request);
+ ctx.Send(waiter->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response2));
+ }
+ cacheRecord.Waiters.clear();
+ if (!error.empty()) {
+ LOG_WARN_S(ctx, HttpLog, "Error from " << cacheRecord.GetName() << ": " << error);
+ if (!cacheRecord.Response) {
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingDiscard " << cacheRecord.GetName());
+ DropCacheRecord(it);
+ return;
+ }
+ }
+ if (cacheRecord.CachePolicy.TimeToRefresh) {
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingUpdate " << cacheRecord.GetName());
+ cacheRecord.UpdateResponse(response, error, ctx.Now());
+ if (!cacheRecord.Enqueued) {
+ RefreshQueue.push({it->first, it->second.RefreshTime});
+ cacheRecord.Enqueued = true;
+ }
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingSchedule " << cacheRecord.GetName() << " at " << cacheRecord.RefreshTime << " until " << cacheRecord.DeathTime);
+ } else {
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingDrop " << cacheRecord.GetName());
+ DropCacheRecord(it);
+ }
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ const NHttp::THttpIncomingRequest* request = event->Get()->Request.Get();
+ TCachePolicy policy = GetCachePolicy(request);
+ if (policy.TimeToExpire == TDuration() && policy.RetriesCount == 0) {
+ TActorId handler = GetRequestHandler(event->Get()->Request);
+ if (handler) {
+ ctx.Send(event->Forward(handler));
+ }
+ return;
+ }
+ auto key = GetCacheKey(request, policy);
+ auto it = Cache.find(key);
+ if (it != Cache.end() && !policy.DiscardCache) {
+ it->second.UpdateExpireTime();
+ if (it->second.IsValid()) {
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingRespond "
+ << it->second.GetName()
+ << " ("
+ << ((it->second.Response != nullptr) ? ToString(it->second.Response->Size()) : TString("error"))
+ << ")");
+ NHttp::THttpOutgoingResponsePtr response = it->second.Response;
+ if (response != nullptr) {
+ response = response->Duplicate(event->Get()->Request);
+ }
+ ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
+ return;
+ }
+ } else {
+ it = Cache.emplace(key, policy).first;
+ it->second.CacheId = key.GetId(); // for debugging
+ it->second.InitRequest(event->Get()->Request);
+ if (policy.DiscardCache) {
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingDiscardCache " << it->second.GetName());
+ }
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingInitiate " << it->second.GetName());
+ SendCacheRequest(key, it->second, ctx);
+ }
+ it->second.Waiters.emplace_back(std::move(event));
+ }
+
+ void HandleRefresh(const NActors::TActorContext& ctx) {
+ while (!RefreshQueue.empty() && RefreshQueue.top().RefreshTime <= ctx.Now()) {
+ TRefreshRecord rrec = RefreshQueue.top();
+ RefreshQueue.pop();
+ auto it = Cache.find(rrec.Key);
+ if (it != Cache.end()) {
+ it->second.Enqueued = false;
+ if (it->second.DeathTime > ctx.Now()) {
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingRefresh " << it->second.GetName());
+ SendCacheRequest(it->first, it->second, ctx);
+ } else {
+ LOG_DEBUG_S(ctx, HttpLog, "IncomingForget " << it->second.GetName());
+ DropCacheRecord(it);
+ }
+ }
+ }
+ ctx.Schedule(RefreshTimeout, new NActors::TEvents::TEvWakeup());
+ }
+
+ STFUNC(StateWork) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingResponse, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvHttpOutgoingRequest, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvAddListeningPort, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvRegisterHandler, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle);
+ HFunc(NHttp::TEvHttpProxy::TEvHttpOutgoingResponse, Handle);
+ CFunc(NActors::TEvents::TSystem::Wakeup, HandleRefresh);
+ }
+ }
+};
+
+TCachePolicy GetDefaultCachePolicy(const THttpRequest* request, const TCachePolicy& defaultPolicy) {
+ TCachePolicy policy = defaultPolicy;
+ THeaders headers(request->Headers);
+ TStringBuf cacheControl(headers["Cache-Control"]);
+ while (TStringBuf cacheItem = cacheControl.NextTok(',')) {
+ Trim(cacheItem, ' ');
+ if (cacheItem == "no-store" || cacheItem == "no-cache") {
+ policy.DiscardCache = true;
+ }
+ TStringBuf itemName = cacheItem.NextTok('=');
+ TrimEnd(itemName, ' ');
+ TrimBegin(cacheItem, ' ');
+ if (itemName == "max-age") {
+ policy.TimeToRefresh = policy.TimeToExpire = TDuration::Seconds(FromString(cacheItem));
+ }
+ if (itemName == "min-fresh") {
+ policy.TimeToRefresh = policy.TimeToExpire = TDuration::Seconds(FromString(cacheItem));
+ }
+ if (itemName == "stale-if-error") {
+ policy.KeepOnError = true;
+ }
+ }
+ return policy;
+}
+
+NActors::IActor* CreateHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy) {
+ return new THttpOutgoingCacheActor(httpProxyId, std::move(cachePolicy));
+}
+
+NActors::IActor* CreateOutgoingHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy) {
+ return new THttpOutgoingCacheActor(httpProxyId, std::move(cachePolicy));
+}
+
+NActors::IActor* CreateIncomingHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy) {
+ return new THttpIncomingCacheActor(httpProxyId, std::move(cachePolicy));
+}
+
+}
diff --git a/library/cpp/actors/http/http_cache.h b/library/cpp/actors/http/http_cache.h
new file mode 100644
index 0000000000..ac38bdcac8
--- /dev/null
+++ b/library/cpp/actors/http/http_cache.h
@@ -0,0 +1,27 @@
+#pragma once
+#include <library/cpp/actors/core/actor.h>
+#include "http.h"
+
+namespace NHttp {
+
+struct TCachePolicy {
+ TDuration TimeToExpire;
+ TDuration TimeToRefresh;
+ TDuration PaceToRefresh;
+ bool KeepOnError = false;
+ bool DiscardCache = false;
+ TArrayRef<TString> HeadersToCacheKey;
+ TArrayRef<TString> StatusesToRetry;
+ ui32 RetriesCount = 0;
+
+ TCachePolicy() = default;
+};
+
+using TGetCachePolicy = std::function<TCachePolicy(const THttpRequest*)>;
+
+NActors::IActor* CreateHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy);
+NActors::IActor* CreateOutgoingHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy);
+NActors::IActor* CreateIncomingHttpCache(const NActors::TActorId& httpProxyId, TGetCachePolicy cachePolicy);
+TCachePolicy GetDefaultCachePolicy(const THttpRequest* request, const TCachePolicy& policy = TCachePolicy());
+
+}
diff --git a/library/cpp/actors/http/http_config.h b/library/cpp/actors/http/http_config.h
new file mode 100644
index 0000000000..faeff79449
--- /dev/null
+++ b/library/cpp/actors/http/http_config.h
@@ -0,0 +1,19 @@
+#pragma once
+#include <util/network/sock.h>
+#include <library/cpp/actors/core/log.h>
+#include <library/cpp/actors/protos/services_common.pb.h>
+
+namespace NHttp {
+
+struct THttpConfig {
+ static constexpr NActors::NLog::EComponent HttpLog = NActorsServices::EServiceCommon::HTTP;
+ static constexpr size_t BUFFER_SIZE = 64 * 1024;
+ static constexpr size_t BUFFER_MIN_STEP = 10 * 1024;
+ static constexpr int LISTEN_QUEUE = 10;
+ static constexpr TDuration SOCKET_TIMEOUT = TDuration::MilliSeconds(60000);
+ static constexpr TDuration CONNECTION_TIMEOUT = TDuration::MilliSeconds(60000);
+ using SocketType = TInet6StreamSocket;
+ using SocketAddressType = TSockAddrInet6;
+};
+
+}
diff --git a/library/cpp/actors/http/http_proxy.cpp b/library/cpp/actors/http/http_proxy.cpp
new file mode 100644
index 0000000000..36c6855d93
--- /dev/null
+++ b/library/cpp/actors/http/http_proxy.cpp
@@ -0,0 +1,314 @@
+#include <library/cpp/actors/core/events.h>
+#include <library/cpp/monlib/metrics/metric_registry.h>
+#include "http_proxy.h"
+
+namespace NHttp {
+
+class THttpProxy : public NActors::TActorBootstrapped<THttpProxy>, public THttpConfig {
+public:
+ IActor* AddListeningPort(TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) {
+ IActor* listeningSocket = CreateHttpAcceptorActor(ctx.SelfID, Poller);
+ TActorId acceptorId = ctx.Register(listeningSocket);
+ ctx.Send(event->Forward(acceptorId));
+ Acceptors.emplace_back(acceptorId);
+ return listeningSocket;
+ }
+
+ IActor* AddOutgoingConnection(const TString& address, bool secure, const NActors::TActorContext& ctx) {
+ IActor* connectionSocket = CreateOutgoingConnectionActor(ctx.SelfID, address, secure, Poller);
+ TActorId connectionId = ctx.Register(connectionSocket);
+ Connections.emplace(connectionId);
+ return connectionSocket;
+ }
+
+ void Bootstrap(const NActors::TActorContext& ctx) {
+ Poller = ctx.Register(NActors::CreatePollerActor());
+ Become(&THttpProxy::StateWork);
+ }
+
+ THttpProxy(NMonitoring::TMetricRegistry& sensors)
+ : Sensors(sensors)
+ {}
+
+protected:
+ STFUNC(StateWork) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TEvHttpProxy::TEvAddListeningPort, Handle);
+ HFunc(TEvHttpProxy::TEvRegisterHandler, Handle);
+ HFunc(TEvHttpProxy::TEvHttpIncomingRequest, Handle);
+ HFunc(TEvHttpProxy::TEvHttpOutgoingRequest, Handle);
+ HFunc(TEvHttpProxy::TEvHttpIncomingResponse, Handle);
+ HFunc(TEvHttpProxy::TEvHttpOutgoingResponse, Handle);
+ HFunc(TEvHttpProxy::TEvHttpAcceptorClosed, Handle);
+ HFunc(TEvHttpProxy::TEvHttpConnectionClosed, Handle);
+ HFunc(TEvHttpProxy::TEvResolveHostRequest, Handle);
+ HFunc(TEvHttpProxy::TEvReportSensors, Handle);
+ HFunc(NActors::TEvents::TEvPoison, Handle);
+ }
+ }
+
+ void PassAway() override {
+ Send(Poller, new NActors::TEvents::TEvPoisonPill());
+ for (const NActors::TActorId& connection : Connections) {
+ Send(connection, new NActors::TEvents::TEvPoisonPill());
+ }
+ for (const NActors::TActorId& acceptor : Acceptors) {
+ Send(acceptor, new NActors::TEvents::TEvPoisonPill());
+ }
+ NActors::TActorBootstrapped<THttpProxy>::PassAway();
+ }
+
+ void Handle(TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ TStringBuf url = event->Get()->Request->URL.Before('?');
+ THashMap<TString, TActorId>::iterator it;
+ while (!url.empty()) {
+ it = Handlers.find(url);
+ if (it != Handlers.end()) {
+ ctx.Send(event->Forward(it->second));
+ return;
+ } else {
+ if (url.EndsWith('/')) {
+ url.Trunc(url.size() - 1);
+ }
+ size_t pos = url.rfind('/');
+ if (pos == TStringBuf::npos) {
+ break;
+ } else {
+ url = url.substr(0, pos + 1);
+ }
+ }
+ }
+ ctx.Send(event->Sender, new TEvHttpProxy::TEvHttpOutgoingResponse(event->Get()->Request->CreateResponseNotFound()));
+ }
+
+ void Handle(TEvHttpProxy::TEvHttpIncomingResponse::TPtr event, const NActors::TActorContext& ctx) {
+ Y_UNUSED(event);
+ Y_UNUSED(ctx);
+ Y_FAIL("This event shouldn't be there, it should go to the http connection owner directly");
+ }
+
+ void Handle(TEvHttpProxy::TEvHttpOutgoingResponse::TPtr event, const NActors::TActorContext& ctx) {
+ Y_UNUSED(event);
+ Y_UNUSED(ctx);
+ Y_FAIL("This event shouldn't be there, it should go to the http connection directly");
+ }
+
+ void Handle(TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ TStringBuf host(event->Get()->Request->Host);
+ bool secure(event->Get()->Request->Secure);
+ NActors::IActor* actor = AddOutgoingConnection(TString(host), secure, ctx);
+ ctx.Send(event->Forward(actor->SelfId()));
+ }
+
+ void Handle(TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) {
+ AddListeningPort(event, ctx);
+ }
+
+ void Handle(TEvHttpProxy::TEvHttpAcceptorClosed::TPtr event, const NActors::TActorContext&) {
+ for (auto it = Acceptors.begin(); it != Acceptors.end(); ++it) {
+ if (*it == event->Get()->ConnectionID) {
+ Acceptors.erase(it);
+ break;
+ }
+ }
+ }
+
+ void Handle(TEvHttpProxy::TEvHttpConnectionClosed::TPtr event, const NActors::TActorContext&) {
+ Connections.erase(event->Get()->ConnectionID);
+ }
+
+ void Handle(TEvHttpProxy::TEvRegisterHandler::TPtr event, const NActors::TActorContext&) {
+ Handlers[event->Get()->Path] = event->Get()->Handler;
+ }
+
+ void Handle(TEvHttpProxy::TEvResolveHostRequest::TPtr event, const NActors::TActorContext& ctx) {
+ const TString& host(event->Get()->Host);
+ auto it = Hosts.find(host);
+ if (it == Hosts.end() || it->second.DeadlineTime > ctx.Now()) {
+ TString addressPart;
+ TIpPort portPart = 0;
+ CrackAddress(host, addressPart, portPart);
+ if (IsIPv6(addressPart)) {
+ TSockAddrInet6 address(addressPart.c_str(), portPart);
+ if (it == Hosts.end()) {
+ it = Hosts.emplace(host, THostEntry()).first;
+ }
+ it->second.Address = address;
+ it->second.DeadlineTime = ctx.Now() + HostsTimeToLive;
+ } else {
+ // TODO(xenoxeno): move to another, possible blocking actor
+ try {
+ const NDns::TResolvedHost* result = NDns::CachedResolve(NDns::TResolveInfo(addressPart, portPart));
+ if (result != nullptr) {
+ auto pAddr = result->Addr.Begin();
+ while (pAddr != result->Addr.End() && pAddr->ai_family != AF_INET6) {
+ ++pAddr;
+ }
+ if (pAddr == result->Addr.End()) {
+ ctx.Send(event->Sender, new TEvHttpProxy::TEvResolveHostResponse("Invalid address family resolved"));
+ return;
+ }
+ TSockAddrInet6 address = {};
+ static_cast<sockaddr_in6&>(address) = *reinterpret_cast<sockaddr_in6*>(pAddr->ai_addr);
+ LOG_DEBUG_S(ctx, HttpLog, "Host " << host << " resolved to " << address.ToString());
+ if (it == Hosts.end()) {
+ it = Hosts.emplace(host, THostEntry()).first;
+ }
+ it->second.Address = address;
+ it->second.DeadlineTime = ctx.Now() + HostsTimeToLive;
+ } else {
+ ctx.Send(event->Sender, new TEvHttpProxy::TEvResolveHostResponse("Error resolving host"));
+ return;
+ }
+ }
+ catch (const yexception& e) {
+ ctx.Send(event->Sender, new TEvHttpProxy::TEvResolveHostResponse(e.what()));
+ return;
+ }
+ }
+ }
+ ctx.Send(event->Sender, new TEvHttpProxy::TEvResolveHostResponse(it->first, it->second.Address));
+ }
+
+ void Handle(TEvHttpProxy::TEvReportSensors::TPtr event, const NActors::TActorContext&) {
+ const TEvHttpProxy::TEvReportSensors& sensors(*event->Get());
+ const static TString urlNotFound = "not-found";
+ const TString& url = (sensors.Status == "404" ? urlNotFound : sensors.Url);
+
+ Sensors.Rate({
+ {"sensor", "count"},
+ {"direction", sensors.Direction},
+ {"peer", sensors.Host},
+ {"url", url},
+ {"status", sensors.Status}
+ })->Inc();
+ Sensors.HistogramRate({
+ {"sensor", "time_us"},
+ {"direction", sensors.Direction},
+ {"peer", sensors.Host},
+ {"url", url},
+ {"status", sensors.Status}
+ },
+ NMonitoring::ExplicitHistogram({1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 30000, 60000}))->Record(sensors.Time.MicroSeconds());
+ Sensors.HistogramRate({
+ {"sensor", "time_ms"},
+ {"direction", sensors.Direction},
+ {"peer", sensors.Host},
+ {"url", url},
+ {"status", sensors.Status}
+ },
+ NMonitoring::ExplicitHistogram({1, 5, 10, 50, 100, 500, 1000, 5000, 10000, 30000, 60000}))->Record(sensors.Time.MilliSeconds());
+ }
+
+ void Handle(NActors::TEvents::TEvPoison::TPtr, const NActors::TActorContext&) {
+ PassAway();
+ }
+
+ NActors::TActorId Poller;
+ TVector<TActorId> Acceptors;
+
+ struct THostEntry {
+ TSockAddrInet6 Address;
+ TInstant DeadlineTime;
+ };
+
+ static constexpr TDuration HostsTimeToLive = TDuration::Seconds(60);
+
+ THashMap<TString, THostEntry> Hosts;
+ THashMap<TString, TActorId> Handlers;
+ THashSet<TActorId> Connections; // outgoing
+ NMonitoring::TMetricRegistry& Sensors;
+};
+
+TEvHttpProxy::TEvReportSensors* BuildOutgoingRequestSensors(const THttpOutgoingRequestPtr& request, const THttpIncomingResponsePtr& response) {
+ return new TEvHttpProxy::TEvReportSensors(
+ "out",
+ request->Host,
+ request->URL.Before('?'),
+ response ? response->Status : "504",
+ TDuration::Seconds(std::abs(request->Timer.Passed()))
+ );
+}
+
+TEvHttpProxy::TEvReportSensors* BuildIncomingRequestSensors(const THttpIncomingRequestPtr& request, const THttpOutgoingResponsePtr& response) {
+ return new TEvHttpProxy::TEvReportSensors(
+ "in",
+ request->Host,
+ request->URL.Before('?'),
+ response->Status,
+ TDuration::Seconds(std::abs(request->Timer.Passed()))
+ );
+}
+
+NActors::IActor* CreateHttpProxy(NMonitoring::TMetricRegistry& sensors) {
+ return new THttpProxy(sensors);
+}
+
+bool IsIPv6(const TString& host) {
+ return host.find_first_not_of(":0123456789abcdef") == TString::npos;
+}
+
+bool CrackURL(TStringBuf url, TStringBuf& scheme, TStringBuf& host, TStringBuf& uri) {
+ url.TrySplit("://", scheme, url);
+ auto pos = url.find('/');
+ if (pos == TStringBuf::npos) {
+ host = url;
+ } else {
+ host = url.substr(0, pos);
+ uri = url.substr(pos);
+ }
+ return true;
+}
+
+void CrackAddress(const TString& address, TString& hostname, TIpPort& port) {
+ size_t first_colon_pos = address.find(':');
+ if (first_colon_pos != TString::npos) {
+ size_t last_colon_pos = address.rfind(':');
+ if (last_colon_pos == first_colon_pos) {
+ // only one colon, simple case
+ port = FromStringWithDefault<TIpPort>(address.substr(first_colon_pos + 1), 0);
+ hostname = address.substr(0, first_colon_pos);
+ } else {
+ // ipv6?
+ size_t closing_bracket_pos = address.rfind(']');
+ if (closing_bracket_pos == TString::npos || closing_bracket_pos > last_colon_pos) {
+ // whole address is ipv6 host
+ hostname = address;
+ } else {
+ port = FromStringWithDefault<TIpPort>(address.substr(last_colon_pos + 1), 0);
+ hostname = address.substr(0, last_colon_pos);
+ }
+ if (hostname.StartsWith('[') && hostname.EndsWith(']')) {
+ hostname = hostname.substr(1, hostname.size() - 2);
+ }
+ }
+ } else {
+ hostname = address;
+ }
+}
+
+
+void TrimBegin(TStringBuf& target, char delim) {
+ while (!target.empty() && *target.begin() == delim) {
+ target.Skip(1);
+ }
+}
+
+void TrimEnd(TStringBuf& target, char delim) {
+ while (!target.empty() && target.back() == delim) {
+ target.Trunc(target.size() - 1);
+ }
+}
+
+void Trim(TStringBuf& target, char delim) {
+ TrimBegin(target, delim);
+ TrimEnd(target, delim);
+}
+
+void TrimEnd(TString& target, char delim) {
+ while (!target.empty() && target.back() == delim) {
+ target.resize(target.size() - 1);
+ }
+}
+
+}
diff --git a/library/cpp/actors/http/http_proxy.h b/library/cpp/actors/http/http_proxy.h
new file mode 100644
index 0000000000..afd0170997
--- /dev/null
+++ b/library/cpp/actors/http/http_proxy.h
@@ -0,0 +1,239 @@
+#pragma once
+#include <library/cpp/actors/core/actorsystem.h>
+#include <library/cpp/actors/core/actor.h>
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/actors/core/events.h>
+#include <library/cpp/actors/core/event_local.h>
+#include <library/cpp/actors/core/actor_bootstrapped.h>
+#include <library/cpp/actors/core/log.h>
+#include <library/cpp/actors/interconnect/poller_actor.h>
+#include <library/cpp/dns/cache.h>
+#include <library/cpp/monlib/metrics/metric_registry.h>
+#include <util/generic/variant.h>
+#include "http.h"
+#include "http_proxy_ssl.h"
+
+namespace NHttp {
+
+struct TSocketDescriptor : NActors::TSharedDescriptor, THttpConfig {
+ SocketType Socket;
+
+ int GetDescriptor() override {
+ return static_cast<SOCKET>(Socket);
+ }
+};
+
+struct TEvHttpProxy {
+ enum EEv {
+ EvAddListeningPort = EventSpaceBegin(NActors::TEvents::ES_HTTP),
+ EvConfirmListen,
+ EvRegisterHandler,
+ EvHttpIncomingRequest,
+ EvHttpOutgoingRequest,
+ EvHttpIncomingResponse,
+ EvHttpOutgoingResponse,
+ EvHttpConnectionOpened,
+ EvHttpConnectionClosed,
+ EvHttpAcceptorClosed,
+ EvResolveHostRequest,
+ EvResolveHostResponse,
+ EvReportSensors,
+ EvEnd
+ };
+
+ static_assert(EvEnd < EventSpaceEnd(NActors::TEvents::ES_HTTP), "ES_HTTP event space is too small.");
+
+ struct TEvAddListeningPort : NActors::TEventLocal<TEvAddListeningPort, EvAddListeningPort> {
+ TIpPort Port;
+ TString WorkerName;
+ bool Secure = false;
+ TString CertificateFile;
+ TString PrivateKeyFile;
+ TString SslCertificatePem;
+
+ TEvAddListeningPort(TIpPort port)
+ : Port(port)
+ {}
+
+ TEvAddListeningPort(TIpPort port, const TString& workerName)
+ : Port(port)
+ , WorkerName(workerName)
+ {}
+ };
+
+ struct TEvConfirmListen : NActors::TEventLocal<TEvConfirmListen, EvConfirmListen> {
+ THttpConfig::SocketAddressType Address;
+
+ TEvConfirmListen(const THttpConfig::SocketAddressType& address)
+ : Address(address)
+ {}
+ };
+
+ struct TEvRegisterHandler : NActors::TEventLocal<TEvRegisterHandler, EvRegisterHandler> {
+ TString Path;
+ TActorId Handler;
+
+ TEvRegisterHandler(const TString& path, const TActorId& handler)
+ : Path(path)
+ , Handler(handler)
+ {}
+ };
+
+ struct TEvHttpIncomingRequest : NActors::TEventLocal<TEvHttpIncomingRequest, EvHttpIncomingRequest> {
+ THttpIncomingRequestPtr Request;
+
+ TEvHttpIncomingRequest(THttpIncomingRequestPtr request)
+ : Request(std::move(request))
+ {}
+ };
+
+ struct TEvHttpOutgoingRequest : NActors::TEventLocal<TEvHttpOutgoingRequest, EvHttpOutgoingRequest> {
+ THttpOutgoingRequestPtr Request;
+ TDuration Timeout;
+
+ TEvHttpOutgoingRequest(THttpOutgoingRequestPtr request)
+ : Request(std::move(request))
+ {}
+
+ TEvHttpOutgoingRequest(THttpOutgoingRequestPtr request, TDuration timeout)
+ : Request(std::move(request))
+ , Timeout(timeout)
+ {}
+ };
+
+ struct TEvHttpIncomingResponse : NActors::TEventLocal<TEvHttpIncomingResponse, EvHttpIncomingResponse> {
+ THttpOutgoingRequestPtr Request;
+ THttpIncomingResponsePtr Response;
+ TString Error;
+
+ TEvHttpIncomingResponse(THttpOutgoingRequestPtr request, THttpIncomingResponsePtr response, const TString& error)
+ : Request(std::move(request))
+ , Response(std::move(response))
+ , Error(error)
+ {}
+
+ TEvHttpIncomingResponse(THttpOutgoingRequestPtr request, THttpIncomingResponsePtr response)
+ : Request(std::move(request))
+ , Response(std::move(response))
+ {}
+
+ TString GetError() const {
+ TStringBuilder error;
+ if (Response != nullptr && !Response->Status.StartsWith('2')) {
+ error << Response->Status << ' ' << Response->Message;
+ }
+ if (!Error.empty()) {
+ if (!error.empty()) {
+ error << ';';
+ }
+ error << Error;
+ }
+ return error;
+ }
+ };
+
+ struct TEvHttpOutgoingResponse : NActors::TEventLocal<TEvHttpOutgoingResponse, EvHttpOutgoingResponse> {
+ THttpOutgoingResponsePtr Response;
+
+ TEvHttpOutgoingResponse(THttpOutgoingResponsePtr response)
+ : Response(std::move(response))
+ {}
+ };
+
+ struct TEvHttpConnectionOpened : NActors::TEventLocal<TEvHttpConnectionOpened, EvHttpConnectionOpened> {
+ TString PeerAddress;
+ TActorId ConnectionID;
+
+ TEvHttpConnectionOpened(const TString& peerAddress, const TActorId& connectionID)
+ : PeerAddress(peerAddress)
+ , ConnectionID(connectionID)
+ {}
+ };
+
+ struct TEvHttpConnectionClosed : NActors::TEventLocal<TEvHttpConnectionClosed, EvHttpConnectionClosed> {
+ TActorId ConnectionID;
+ TDeque<THttpIncomingRequestPtr> RecycledRequests;
+
+ TEvHttpConnectionClosed(const TActorId& connectionID)
+ : ConnectionID(connectionID)
+ {}
+
+ TEvHttpConnectionClosed(const TActorId& connectionID, TDeque<THttpIncomingRequestPtr> recycledRequests)
+ : ConnectionID(connectionID)
+ , RecycledRequests(std::move(recycledRequests))
+ {}
+ };
+
+ struct TEvHttpAcceptorClosed : NActors::TEventLocal<TEvHttpAcceptorClosed, EvHttpAcceptorClosed> {
+ TActorId ConnectionID;
+
+ TEvHttpAcceptorClosed(const TActorId& connectionID)
+ : ConnectionID(connectionID)
+ {}
+ };
+
+ struct TEvResolveHostRequest : NActors::TEventLocal<TEvResolveHostRequest, EvResolveHostRequest> {
+ TString Host;
+
+ TEvResolveHostRequest(const TString& host)
+ : Host(host)
+ {}
+ };
+
+ struct TEvResolveHostResponse : NActors::TEventLocal<TEvResolveHostResponse, EvResolveHostResponse> {
+ TString Host;
+ TSockAddrInet6 Address;
+ TString Error;
+
+ TEvResolveHostResponse(const TString& host, const TSockAddrInet6& address)
+ : Host(host)
+ , Address(address)
+ {}
+
+ TEvResolveHostResponse(const TString& error)
+ : Error(error)
+ {}
+ };
+
+ struct TEvReportSensors : NActors::TEventLocal<TEvReportSensors, EvReportSensors> {
+ TString Direction;
+ TString Host;
+ TString Url;
+ TString Status;
+ TDuration Time;
+
+ TEvReportSensors(
+ TStringBuf direction,
+ TStringBuf host,
+ TStringBuf url,
+ TStringBuf status,
+ TDuration time)
+ : Direction(direction)
+ , Host(host)
+ , Url(url)
+ , Status(status)
+ , Time(time)
+ {}
+ };
+};
+
+struct TEndpointInfo {
+ TActorId Proxy;
+ TActorId Owner;
+ TString WorkerName;
+ bool Secure;
+ TSslHelpers::TSslHolder<SSL_CTX> SecureContext;
+};
+
+NActors::IActor* CreateHttpProxy(NMonitoring::TMetricRegistry& sensors);
+NActors::IActor* CreateHttpAcceptorActor(const TActorId& owner, const TActorId& poller);
+NActors::IActor* CreateOutgoingConnectionActor(const TActorId& owner, const TString& host, bool secure, const TActorId& poller);
+NActors::IActor* CreateIncomingConnectionActor(
+ const TEndpointInfo& endpoint,
+ TIntrusivePtr<TSocketDescriptor> socket,
+ THttpConfig::SocketAddressType address,
+ THttpIncomingRequestPtr recycledRequest = nullptr);
+TEvHttpProxy::TEvReportSensors* BuildOutgoingRequestSensors(const THttpOutgoingRequestPtr& request, const THttpIncomingResponsePtr& response);
+TEvHttpProxy::TEvReportSensors* BuildIncomingRequestSensors(const THttpIncomingRequestPtr& request, const THttpOutgoingResponsePtr& response);
+
+}
diff --git a/library/cpp/actors/http/http_proxy_acceptor.cpp b/library/cpp/actors/http/http_proxy_acceptor.cpp
new file mode 100644
index 0000000000..9780541b71
--- /dev/null
+++ b/library/cpp/actors/http/http_proxy_acceptor.cpp
@@ -0,0 +1,135 @@
+#include <util/network/sock.h>
+#include "http_proxy.h"
+#include "http_proxy_ssl.h"
+
+namespace NHttp {
+
+class TAcceptorActor : public NActors::TActor<TAcceptorActor>, public THttpConfig {
+public:
+ using TBase = NActors::TActor<TAcceptorActor>;
+ const TActorId Owner;
+ const TActorId Poller;
+ TIntrusivePtr<TSocketDescriptor> Socket;
+ NActors::TPollerToken::TPtr PollerToken;
+ THashSet<TActorId> Connections;
+ TDeque<THttpIncomingRequestPtr> RecycledRequests;
+ TEndpointInfo Endpoint;
+
+ TAcceptorActor(const TActorId& owner, const TActorId& poller)
+ : NActors::TActor<TAcceptorActor>(&TAcceptorActor::StateInit)
+ , Owner(owner)
+ , Poller(poller)
+ , Socket(new TSocketDescriptor())
+ {
+ // for unit tests :(
+ CheckedSetSockOpt(Socket->Socket, SOL_SOCKET, SO_REUSEADDR, (int)true, "reuse address");
+#ifdef SO_REUSEPORT
+ CheckedSetSockOpt(Socket->Socket, SOL_SOCKET, SO_REUSEPORT, (int)true, "reuse port");
+#endif
+ }
+
+protected:
+ STFUNC(StateListening) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(NActors::TEvPollerRegisterResult, Handle);
+ HFunc(NActors::TEvPollerReady, Handle);
+ HFunc(TEvHttpProxy::TEvHttpConnectionClosed, Handle);
+ HFunc(TEvHttpProxy::TEvReportSensors, Handle);
+ }
+ }
+
+ STFUNC(StateInit) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TEvHttpProxy::TEvAddListeningPort, HandleInit);
+ }
+ }
+
+ void HandleInit(TEvHttpProxy::TEvAddListeningPort::TPtr event, const NActors::TActorContext& ctx) {
+ SocketAddressType bindAddress("::", event->Get()->Port);
+ Endpoint.Owner = ctx.SelfID;
+ Endpoint.Proxy = Owner;
+ Endpoint.WorkerName = event->Get()->WorkerName;
+ Endpoint.Secure = event->Get()->Secure;
+ int err = 0;
+ if (Endpoint.Secure) {
+ if (!event->Get()->SslCertificatePem.empty()) {
+ Endpoint.SecureContext = TSslHelpers::CreateServerContext(event->Get()->SslCertificatePem);
+ } else {
+ Endpoint.SecureContext = TSslHelpers::CreateServerContext(event->Get()->CertificateFile, event->Get()->PrivateKeyFile);
+ }
+ if (Endpoint.SecureContext == nullptr) {
+ err = -1;
+ LOG_WARN_S(ctx, HttpLog, "Failed to construct server security context");
+ }
+ }
+ if (err == 0) {
+ err = Socket->Socket.Bind(&bindAddress);
+ }
+ if (err == 0) {
+ err = Socket->Socket.Listen(LISTEN_QUEUE);
+ if (err == 0) {
+ LOG_INFO_S(ctx, HttpLog, "Listening on " << bindAddress.ToString());
+ SetNonBlock(Socket->Socket);
+ ctx.Send(Poller, new NActors::TEvPollerRegister(Socket, SelfId(), SelfId()));
+ TBase::Become(&TAcceptorActor::StateListening);
+ ctx.Send(event->Sender, new TEvHttpProxy::TEvConfirmListen(bindAddress), 0, event->Cookie);
+ return;
+ }
+ }
+ LOG_WARN_S(ctx, HttpLog, "Failed to listen on " << bindAddress.ToString() << " - retrying...");
+ ctx.ExecutorThread.Schedule(TDuration::Seconds(1), event.Release());
+ }
+
+ void Die(const NActors::TActorContext& ctx) override {
+ ctx.Send(Owner, new TEvHttpProxy::TEvHttpAcceptorClosed(ctx.SelfID));
+ for (const NActors::TActorId& connection : Connections) {
+ ctx.Send(connection, new NActors::TEvents::TEvPoisonPill());
+ }
+ }
+
+ void Handle(NActors::TEvPollerRegisterResult::TPtr ev, const NActors::TActorContext& /*ctx*/) {
+ PollerToken = std::move(ev->Get()->PollerToken);
+ PollerToken->Request(true, false); // request read polling
+ }
+
+ void Handle(NActors::TEvPollerReady::TPtr, const NActors::TActorContext& ctx) {
+ TIntrusivePtr<TSocketDescriptor> socket = new TSocketDescriptor();
+ SocketAddressType addr;
+ int err;
+ while ((err = Socket->Socket.Accept(&socket->Socket, &addr)) == 0) {
+ NActors::IActor* connectionSocket = nullptr;
+ if (RecycledRequests.empty()) {
+ connectionSocket = CreateIncomingConnectionActor(Endpoint, socket, addr);
+ } else {
+ connectionSocket = CreateIncomingConnectionActor(Endpoint, socket, addr, std::move(RecycledRequests.front()));
+ RecycledRequests.pop_front();
+ }
+ NActors::TActorId connectionId = ctx.Register(connectionSocket);
+ ctx.Send(Poller, new NActors::TEvPollerRegister(socket, connectionId, connectionId));
+ Connections.emplace(connectionId);
+ socket = new TSocketDescriptor();
+ }
+ if (err == -EAGAIN || err == -EWOULDBLOCK) { // request poller for further connection polling
+ Y_VERIFY(PollerToken);
+ PollerToken->Request(true, false);
+ }
+ }
+
+ void Handle(TEvHttpProxy::TEvHttpConnectionClosed::TPtr event, const NActors::TActorContext&) {
+ Connections.erase(event->Get()->ConnectionID);
+ for (auto& req : event->Get()->RecycledRequests) {
+ req->Clear();
+ RecycledRequests.push_back(std::move(req));
+ }
+ }
+
+ void Handle(TEvHttpProxy::TEvReportSensors::TPtr event, const NActors::TActorContext& ctx) {
+ ctx.Send(event->Forward(Owner));
+ }
+};
+
+NActors::IActor* CreateHttpAcceptorActor(const TActorId& owner, const TActorId& poller) {
+ return new TAcceptorActor(owner, poller);
+}
+
+}
diff --git a/library/cpp/actors/http/http_proxy_incoming.cpp b/library/cpp/actors/http/http_proxy_incoming.cpp
new file mode 100644
index 0000000000..80fe2af53d
--- /dev/null
+++ b/library/cpp/actors/http/http_proxy_incoming.cpp
@@ -0,0 +1,302 @@
+#include "http_proxy.h"
+#include "http_proxy_sock_impl.h"
+
+namespace NHttp {
+
+using namespace NActors;
+
+template <typename TSocketImpl>
+class TIncomingConnectionActor : public TActor<TIncomingConnectionActor<TSocketImpl>>, public TSocketImpl, virtual public THttpConfig {
+public:
+ using TBase = TActor<TIncomingConnectionActor<TSocketImpl>>;
+ static constexpr bool RecycleRequests = true;
+
+ const TEndpointInfo& Endpoint;
+ SocketAddressType Address;
+ TList<THttpIncomingRequestPtr> Requests;
+ THashMap<THttpIncomingRequestPtr, THttpOutgoingResponsePtr> Responses;
+ THttpIncomingRequestPtr CurrentRequest;
+ THttpOutgoingResponsePtr CurrentResponse;
+ TDeque<THttpIncomingRequestPtr> RecycledRequests;
+
+ THPTimer InactivityTimer;
+ static constexpr TDuration InactivityTimeout = TDuration::Minutes(2);
+ TEvPollerReady* InactivityEvent = nullptr;
+
+ TPollerToken::TPtr PollerToken;
+
+ TIncomingConnectionActor(
+ const TEndpointInfo& endpoint,
+ TIntrusivePtr<TSocketDescriptor> socket,
+ SocketAddressType address,
+ THttpIncomingRequestPtr recycledRequest = nullptr)
+ : TBase(&TIncomingConnectionActor::StateAccepting)
+ , TSocketImpl(std::move(socket))
+ , Endpoint(endpoint)
+ , Address(address)
+ {
+ if (recycledRequest != nullptr) {
+ RecycledRequests.emplace_back(std::move(recycledRequest));
+ }
+ TSocketImpl::SetNonBlock();
+ }
+
+ void CleanupRequest(THttpIncomingRequestPtr& request) {
+ if (RecycleRequests) {
+ request->Clear();
+ RecycledRequests.push_back(std::move(request));
+ } else {
+ request = nullptr;
+ }
+ }
+
+ void CleanupResponse(THttpOutgoingResponsePtr& response) {
+ CleanupRequest(response->Request);
+ // TODO: maybe recycle too?
+ response = nullptr;
+ }
+
+ TAutoPtr<IEventHandle> AfterRegister(const TActorId& self, const TActorId& parent) override {
+ return new IEventHandle(self, parent, new TEvents::TEvBootstrap());
+ }
+
+ void Die(const TActorContext& ctx) override {
+ ctx.Send(Endpoint.Owner, new TEvHttpProxy::TEvHttpConnectionClosed(ctx.SelfID, std::move(RecycledRequests)));
+ TSocketImpl::Shutdown();
+ TBase::Die(ctx);
+ }
+
+protected:
+ void Bootstrap(const TActorContext& ctx) {
+ InactivityTimer.Reset();
+ ctx.Schedule(InactivityTimeout, InactivityEvent = new TEvPollerReady(nullptr, false, false));
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") incoming connection opened");
+ OnAccept(ctx);
+ }
+
+ void OnAccept(const NActors::TActorContext& ctx) {
+ int res;
+ bool read = false, write = false;
+ if ((res = TSocketImpl::OnAccept(Endpoint, read, write)) != 1) {
+ if (-res == EAGAIN) {
+ if (PollerToken) {
+ PollerToken->Request(read, write);
+ }
+ return; // wait for further notifications
+ } else {
+ LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - error in Accept: " << strerror(-res));
+ return Die(ctx);
+ }
+ }
+ TBase::Become(&TIncomingConnectionActor::StateConnected);
+ ctx.Send(ctx.SelfID, new TEvPollerReady(nullptr, true, true));
+ }
+
+ void HandleAccepting(TEvPollerRegisterResult::TPtr ev, const NActors::TActorContext& ctx) {
+ PollerToken = std::move(ev->Get()->PollerToken);
+ OnAccept(ctx);
+ }
+
+ void HandleAccepting(NActors::TEvPollerReady::TPtr, const NActors::TActorContext& ctx) {
+ OnAccept(ctx);
+ }
+
+ void HandleConnected(TEvPollerReady::TPtr event, const TActorContext& ctx) {
+ if (event->Get()->Read) {
+ for (;;) {
+ if (CurrentRequest == nullptr) {
+ if (RecycleRequests && !RecycledRequests.empty()) {
+ CurrentRequest = std::move(RecycledRequests.front());
+ RecycledRequests.pop_front();
+ } else {
+ CurrentRequest = new THttpIncomingRequest();
+ }
+ CurrentRequest->Address = Address;
+ CurrentRequest->WorkerName = Endpoint.WorkerName;
+ CurrentRequest->Secure = Endpoint.Secure;
+ }
+ if (!CurrentRequest->EnsureEnoughSpaceAvailable()) {
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - not enough space available");
+ return Die(ctx);
+ }
+ ssize_t need = CurrentRequest->Avail();
+ bool read = false, write = false;
+ ssize_t res = TSocketImpl::Recv(CurrentRequest->Pos(), need, read, write);
+ if (res > 0) {
+ InactivityTimer.Reset();
+ CurrentRequest->Advance(res);
+ if (CurrentRequest->IsDone()) {
+ Requests.emplace_back(CurrentRequest);
+ CurrentRequest->Timer.Reset();
+ if (CurrentRequest->IsReady()) {
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") -> (" << CurrentRequest->Method << " " << CurrentRequest->URL << ")");
+ ctx.Send(Endpoint.Proxy, new TEvHttpProxy::TEvHttpIncomingRequest(CurrentRequest));
+ CurrentRequest = nullptr;
+ } else if (CurrentRequest->IsError()) {
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") -! (" << CurrentRequest->Method << " " << CurrentRequest->URL << ")");
+ bool success = Respond(CurrentRequest->CreateResponseBadRequest(), ctx);
+ if (!success) {
+ return;
+ }
+ CurrentRequest = nullptr;
+ }
+ }
+ } else if (-res == EAGAIN || -res == EWOULDBLOCK) {
+ if (PollerToken) {
+ if (!read && !write) {
+ read = true;
+ }
+ PollerToken->Request(read, write);
+ }
+ break;
+ } else if (-res == EINTR) {
+ continue;
+ } else if (!res) {
+ // connection closed
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed");
+ return Die(ctx);
+ } else {
+ LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - error in Receive: " << strerror(-res));
+ return Die(ctx);
+ }
+ }
+ if (event->Get() == InactivityEvent) {
+ const TDuration passed = TDuration::Seconds(std::abs(InactivityTimer.Passed()));
+ if (passed >= InactivityTimeout) {
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed by inactivity timeout");
+ return Die(ctx); // timeout
+ } else {
+ ctx.Schedule(InactivityTimeout - passed, InactivityEvent = new TEvPollerReady(nullptr, false, false));
+ }
+ }
+ }
+ if (event->Get()->Write) {
+ FlushOutput(ctx);
+ }
+ }
+
+ void HandleConnected(TEvPollerRegisterResult::TPtr ev, const TActorContext& /*ctx*/) {
+ PollerToken = std::move(ev->Get()->PollerToken);
+ PollerToken->Request(true, true);
+ }
+
+ void HandleConnected(TEvHttpProxy::TEvHttpOutgoingResponse::TPtr event, const TActorContext& ctx) {
+ Respond(event->Get()->Response, ctx);
+ }
+
+ bool Respond(THttpOutgoingResponsePtr response, const TActorContext& ctx) {
+ THttpIncomingRequestPtr request = response->GetRequest();
+ response->Finish();
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") <- (" << response->Status << " " << response->Message << ")");
+ if (response->Status != "200" && response->Status != "404") {
+ static constexpr size_t MAX_LOGGED_SIZE = 1024;
+ LOG_DEBUG_S(ctx, HttpLog,
+ "(#"
+ << TSocketImpl::GetRawSocket()
+ << ","
+ << Address
+ << ") Request: "
+ << request->GetObfuscatedData().substr(0, MAX_LOGGED_SIZE));
+ LOG_DEBUG_S(ctx, HttpLog,
+ "(#"
+ << TSocketImpl::GetRawSocket()
+ << ","
+ << Address
+ << ") Response: "
+ << TString(response->GetRawData()).substr(0, MAX_LOGGED_SIZE));
+ }
+ THolder<TEvHttpProxy::TEvReportSensors> sensors(BuildIncomingRequestSensors(request, response));
+ ctx.Send(Endpoint.Owner, sensors.Release());
+ if (request == Requests.front() && CurrentResponse == nullptr) {
+ CurrentResponse = response;
+ return FlushOutput(ctx);
+ } else {
+ // we are ahead of our pipeline
+ Responses.emplace(request, response);
+ return true;
+ }
+ }
+
+ bool FlushOutput(const TActorContext& ctx) {
+ while (CurrentResponse != nullptr) {
+ size_t size = CurrentResponse->Size();
+ if (size == 0) {
+ Y_VERIFY(Requests.front() == CurrentResponse->GetRequest());
+ bool close = CurrentResponse->IsConnectionClose();
+ Requests.pop_front();
+ CleanupResponse(CurrentResponse);
+ if (!Requests.empty()) {
+ auto it = Responses.find(Requests.front());
+ if (it != Responses.end()) {
+ CurrentResponse = it->second;
+ Responses.erase(it);
+ continue;
+ } else {
+ LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - FlushOutput request not found");
+ Die(ctx);
+ return false;
+ }
+ } else {
+ if (close) {
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed");
+ Die(ctx);
+ return false;
+ } else {
+ continue;
+ }
+ }
+ }
+ bool read = false, write = false;
+ ssize_t res = TSocketImpl::Send(CurrentResponse->Data(), size, read, write);
+ if (res > 0) {
+ CurrentResponse->ChopHead(res);
+ } else if (-res == EINTR) {
+ continue;
+ } else if (-res == EAGAIN || -res == EWOULDBLOCK) {
+ if (PollerToken) {
+ if (!read && !write) {
+ write = true;
+ }
+ PollerToken->Request(read, write);
+ }
+ break;
+ } else {
+ CleanupResponse(CurrentResponse);
+ LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed - error in FlushOutput: " << strerror(-res));
+ Die(ctx);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ STFUNC(StateAccepting) {
+ switch (ev->GetTypeRewrite()) {
+ CFunc(TEvents::TEvBootstrap::EventType, Bootstrap);
+ HFunc(TEvPollerReady, HandleAccepting);
+ HFunc(TEvPollerRegisterResult, HandleAccepting);
+ }
+ }
+
+ STFUNC(StateConnected) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TEvPollerReady, HandleConnected);
+ HFunc(TEvHttpProxy::TEvHttpOutgoingResponse, HandleConnected);
+ HFunc(TEvPollerRegisterResult, HandleConnected);
+ }
+ }
+};
+
+IActor* CreateIncomingConnectionActor(
+ const TEndpointInfo& endpoint,
+ TIntrusivePtr<TSocketDescriptor> socket,
+ THttpConfig::SocketAddressType address,
+ THttpIncomingRequestPtr recycledRequest) {
+ if (endpoint.Secure) {
+ return new TIncomingConnectionActor<TSecureSocketImpl>(endpoint, std::move(socket), address, std::move(recycledRequest));
+ } else {
+ return new TIncomingConnectionActor<TPlainSocketImpl>(endpoint, std::move(socket), address, std::move(recycledRequest));
+ }
+}
+
+}
diff --git a/library/cpp/actors/http/http_proxy_outgoing.cpp b/library/cpp/actors/http/http_proxy_outgoing.cpp
new file mode 100644
index 0000000000..d9189dba8a
--- /dev/null
+++ b/library/cpp/actors/http/http_proxy_outgoing.cpp
@@ -0,0 +1,298 @@
+#include "http_proxy.h"
+#include "http_proxy_sock_impl.h"
+
+namespace NHttp {
+
+template <typename TSocketImpl>
+class TOutgoingConnectionActor : public NActors::TActor<TOutgoingConnectionActor<TSocketImpl>>, public TSocketImpl, virtual public THttpConfig {
+public:
+ using TBase = NActors::TActor<TOutgoingConnectionActor<TSocketImpl>>;
+ using TSelf = TOutgoingConnectionActor<TSocketImpl>;
+ const TActorId Owner;
+ const TActorId Poller;
+ SocketAddressType Address;
+ TString Host;
+ TActorId RequestOwner;
+ THttpOutgoingRequestPtr Request;
+ THttpIncomingResponsePtr Response;
+ TInstant LastActivity;
+ TDuration ConnectionTimeout = CONNECTION_TIMEOUT;
+ NActors::TPollerToken::TPtr PollerToken;
+
+ TOutgoingConnectionActor(const TActorId& owner, const TString& host, const TActorId& poller)
+ : TBase(&TSelf::StateWaiting)
+ , Owner(owner)
+ , Poller(poller)
+ , Host(host)
+ {
+ TSocketImpl::SetNonBlock();
+ TSocketImpl::SetTimeout(SOCKET_TIMEOUT);
+ }
+
+ void Die(const NActors::TActorContext& ctx) override {
+ ctx.Send(Owner, new TEvHttpProxy::TEvHttpConnectionClosed(ctx.SelfID));
+ TSocketImpl::Shutdown(); // to avoid errors when connection already closed
+ TBase::Die(ctx);
+ }
+
+ void ReplyAndDie(const NActors::TActorContext& ctx) {
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") -> (" << Response->Status << " " << Response->Message << ")");
+ ctx.Send(RequestOwner, new TEvHttpProxy::TEvHttpIncomingResponse(Request, Response));
+ RequestOwner = TActorId();
+ THolder<TEvHttpProxy::TEvReportSensors> sensors(BuildOutgoingRequestSensors(Request, Response));
+ ctx.Send(Owner, sensors.Release());
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed");
+ Die(ctx);
+ }
+
+ void ReplyErrorAndDie(const NActors::TActorContext& ctx, const TString& error) {
+ LOG_ERROR_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connection closed with error: " << error);
+ if (RequestOwner) {
+ ctx.Send(RequestOwner, new TEvHttpProxy::TEvHttpIncomingResponse(Request, Response, error));
+ RequestOwner = TActorId();
+ THolder<TEvHttpProxy::TEvReportSensors> sensors(BuildOutgoingRequestSensors(Request, Response));
+ ctx.Send(Owner, sensors.Release());
+ Die(ctx);
+ }
+ }
+
+protected:
+ void FailConnection(const NActors::TActorContext& ctx, const TString& error) {
+ if (Request) {
+ return ReplyErrorAndDie(ctx, error);
+ }
+ return TBase::Become(&TOutgoingConnectionActor::StateFailed);
+ }
+
+ void Connect(const NActors::TActorContext& ctx) {
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") connecting");
+ int res = TSocketImpl::Connect(Address);
+ RegisterPoller(ctx);
+ switch (-res) {
+ case 0:
+ return OnConnect(ctx);
+ case EINPROGRESS:
+ case EAGAIN:
+ return TBase::Become(&TOutgoingConnectionActor::StateConnecting);
+ default:
+ return ReplyErrorAndDie(ctx, strerror(-res));
+ }
+ }
+
+ void FlushOutput(const NActors::TActorContext& ctx) {
+ if (Request != nullptr) {
+ Request->Finish();
+ while (auto size = Request->Size()) {
+ bool read = false, write = false;
+ ssize_t res = TSocketImpl::Send(Request->Data(), size, read, write);
+ if (res > 0) {
+ Request->ChopHead(res);
+ } else if (-res == EINTR) {
+ continue;
+ } else if (-res == EAGAIN || -res == EWOULDBLOCK) {
+ if (PollerToken) {
+ if (!read && !write) {
+ write = true;
+ }
+ PollerToken->Request(read, write);
+ }
+ break;
+ } else {
+ if (!res) {
+ ReplyAndDie(ctx);
+ } else {
+ ReplyErrorAndDie(ctx, strerror(-res));
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ void PullInput(const NActors::TActorContext& ctx) {
+ for (;;) {
+ if (Response == nullptr) {
+ Response = new THttpIncomingResponse(Request);
+ }
+ if (!Response->EnsureEnoughSpaceAvailable()) {
+ return ReplyErrorAndDie(ctx, "Not enough space in socket buffer");
+ }
+ bool read = false, write = false;
+ ssize_t res = TSocketImpl::Recv(Response->Pos(), Response->Avail(), read, write);
+ if (res > 0) {
+ Response->Advance(res);
+ if (Response->IsDone() && Response->IsReady()) {
+ return ReplyAndDie(ctx);
+ }
+ } else if (-res == EINTR) {
+ continue;
+ } else if (-res == EAGAIN || -res == EWOULDBLOCK) {
+ if (PollerToken) {
+ if (!read && !write) {
+ read = true;
+ }
+ PollerToken->Request(read, write);
+ }
+ return;
+ } else {
+ if (!res) {
+ Response->ConnectionClosed();
+ }
+ if (Response->IsDone() && Response->IsReady()) {
+ return ReplyAndDie(ctx);
+ }
+ return ReplyErrorAndDie(ctx, strerror(-res));
+ }
+ }
+ }
+
+ void RegisterPoller(const NActors::TActorContext& ctx) {
+ ctx.Send(Poller, new NActors::TEvPollerRegister(TSocketImpl::Socket, ctx.SelfID, ctx.SelfID));
+ }
+
+ void OnConnect(const NActors::TActorContext& ctx) {
+ bool read = false, write = false;
+ if (int res = TSocketImpl::OnConnect(read, write); res != 1) {
+ if (-res == EAGAIN) {
+ if (PollerToken) {
+ PollerToken->Request(read, write);
+ }
+ return;
+ } else {
+ return ReplyErrorAndDie(ctx, strerror(-res));
+ }
+ }
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") outgoing connection opened");
+ TBase::Become(&TOutgoingConnectionActor::StateConnected);
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << "," << Address << ") <- (" << Request->Method << " " << Request->URL << ")");
+ ctx.Send(ctx.SelfID, new NActors::TEvPollerReady(nullptr, true, true));
+ }
+
+ void HandleResolving(TEvHttpProxy::TEvResolveHostResponse::TPtr event, const NActors::TActorContext& ctx) {
+ LastActivity = ctx.Now();
+ if (!event->Get()->Error.empty()) {
+ return FailConnection(ctx, event->Get()->Error);
+ }
+ Address = event->Get()->Address;
+ if (Address.GetPort() == 0) {
+ Address.SetPort(Request->Secure ? 443 : 80);
+ }
+ Connect(ctx);
+ }
+
+ void HandleConnecting(NActors::TEvPollerReady::TPtr, const NActors::TActorContext& ctx) {
+ LastActivity = ctx.Now();
+ int res = TSocketImpl::GetError();
+ if (res == 0) {
+ OnConnect(ctx);
+ } else {
+ FailConnection(ctx, TStringBuilder() << strerror(res));
+ }
+ }
+
+ void HandleConnecting(NActors::TEvPollerRegisterResult::TPtr ev, const NActors::TActorContext& ctx) {
+ PollerToken = std::move(ev->Get()->PollerToken);
+ LastActivity = ctx.Now();
+ int res = TSocketImpl::GetError();
+ if (res == 0) {
+ OnConnect(ctx);
+ } else {
+ FailConnection(ctx, TStringBuilder() << strerror(res));
+ }
+ }
+
+ void HandleWaiting(TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ LastActivity = ctx.Now();
+ Request = std::move(event->Get()->Request);
+ Host = Request->Host;
+ LOG_DEBUG_S(ctx, HttpLog, "(#" << TSocketImpl::GetRawSocket() << ") resolving " << Host);
+ Request->Timer.Reset();
+ RequestOwner = event->Sender;
+ ctx.Send(Owner, new TEvHttpProxy::TEvResolveHostRequest(Host));
+ if (event->Get()->Timeout) {
+ ConnectionTimeout = event->Get()->Timeout;
+ TSocketImpl::SetTimeout(ConnectionTimeout);
+ }
+ ctx.Schedule(ConnectionTimeout, new NActors::TEvents::TEvWakeup());
+ LastActivity = ctx.Now();
+ TBase::Become(&TOutgoingConnectionActor::StateResolving);
+ }
+
+ void HandleConnected(NActors::TEvPollerReady::TPtr event, const NActors::TActorContext& ctx) {
+ LastActivity = ctx.Now();
+ if (event->Get()->Read) {
+ PullInput(ctx);
+ }
+ if (event->Get()->Write) {
+ FlushOutput(ctx);
+ }
+ }
+
+ void HandleConnected(NActors::TEvPollerRegisterResult::TPtr ev, const NActors::TActorContext& ctx) {
+ PollerToken = std::move(ev->Get()->PollerToken);
+ LastActivity = ctx.Now();
+ PullInput(ctx);
+ FlushOutput(ctx);
+ }
+
+ void HandleFailed(TEvHttpProxy::TEvHttpOutgoingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ Request = std::move(event->Get()->Request);
+ RequestOwner = event->Sender;
+ ReplyErrorAndDie(ctx, "Failed");
+ }
+
+ void HandleTimeout(const NActors::TActorContext& ctx) {
+ TDuration inactivityTime = ctx.Now() - LastActivity;
+ if (inactivityTime >= ConnectionTimeout) {
+ FailConnection(ctx, "Connection timed out");
+ } else {
+ ctx.Schedule(Min(ConnectionTimeout - inactivityTime, TDuration::MilliSeconds(100)), new NActors::TEvents::TEvWakeup());
+ }
+ }
+
+ STFUNC(StateWaiting) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TEvHttpProxy::TEvHttpOutgoingRequest, HandleWaiting);
+ CFunc(NActors::TEvents::TEvWakeup::EventType, HandleTimeout);
+ }
+ }
+
+ STFUNC(StateResolving) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TEvHttpProxy::TEvResolveHostResponse, HandleResolving);
+ CFunc(NActors::TEvents::TEvWakeup::EventType, HandleTimeout);
+ }
+ }
+
+ STFUNC(StateConnecting) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(NActors::TEvPollerReady, HandleConnecting);
+ CFunc(NActors::TEvents::TEvWakeup::EventType, HandleTimeout);
+ HFunc(NActors::TEvPollerRegisterResult, HandleConnecting);
+ }
+ }
+
+ STFUNC(StateConnected) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(NActors::TEvPollerReady, HandleConnected);
+ CFunc(NActors::TEvents::TEvWakeup::EventType, HandleTimeout);
+ HFunc(NActors::TEvPollerRegisterResult, HandleConnected);
+ }
+ }
+
+ STFUNC(StateFailed) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TEvHttpProxy::TEvHttpOutgoingRequest, HandleFailed);
+ }
+ }
+};
+
+NActors::IActor* CreateOutgoingConnectionActor(const TActorId& owner, const TString& host, bool secure, const TActorId& poller) {
+ if (secure) {
+ return new TOutgoingConnectionActor<TSecureSocketImpl>(owner, host, poller);
+ } else {
+ return new TOutgoingConnectionActor<TPlainSocketImpl>(owner, host, poller);
+ }
+}
+
+}
diff --git a/library/cpp/actors/http/http_proxy_sock_impl.h b/library/cpp/actors/http/http_proxy_sock_impl.h
new file mode 100644
index 0000000000..bf8c71d05a
--- /dev/null
+++ b/library/cpp/actors/http/http_proxy_sock_impl.h
@@ -0,0 +1,262 @@
+#pragma once
+
+#include "http.h"
+#include "http_proxy.h"
+
+namespace NHttp {
+
+struct TPlainSocketImpl : virtual public THttpConfig {
+ TIntrusivePtr<TSocketDescriptor> Socket;
+
+ TPlainSocketImpl()
+ : Socket(new TSocketDescriptor())
+ {}
+
+ TPlainSocketImpl(TIntrusivePtr<TSocketDescriptor> socket)
+ : Socket(std::move(socket))
+ {}
+
+ SOCKET GetRawSocket() const {
+ return static_cast<SOCKET>(Socket->Socket);
+ }
+
+ void SetNonBlock(bool nonBlock = true) noexcept {
+ try {
+ ::SetNonBlock(Socket->Socket, nonBlock);
+ }
+ catch (const yexception&) {
+ }
+ }
+
+ void SetTimeout(TDuration timeout) noexcept {
+ try {
+ ::SetSocketTimeout(Socket->Socket, timeout.Seconds(), timeout.MilliSecondsOfSecond());
+ }
+ catch (const yexception&) {
+ }
+ }
+
+ void Shutdown() {
+ //Socket->Socket.ShutDown(SHUT_RDWR); // KIKIMR-3895
+ ::shutdown(Socket->Socket, SHUT_RDWR);
+ }
+
+ int Connect(const SocketAddressType& address) {
+ return Socket->Socket.Connect(&address);
+ }
+
+ static constexpr int OnConnect(bool&, bool&) {
+ return 1;
+ }
+
+ static constexpr int OnAccept(const TEndpointInfo&, bool&, bool&) {
+ return 1;
+ }
+
+ bool IsGood() {
+ int res;
+ GetSockOpt(Socket->Socket, SOL_SOCKET, SO_ERROR, res);
+ return res == 0;
+ }
+
+ int GetError() {
+ int res;
+ GetSockOpt(Socket->Socket, SOL_SOCKET, SO_ERROR, res);
+ return res;
+ }
+
+ ssize_t Send(const void* data, size_t size, bool&, bool&) {
+ return Socket->Socket.Send(data, size);
+ }
+
+ ssize_t Recv(void* data, size_t size, bool&, bool&) {
+ return Socket->Socket.Recv(data, size);
+ }
+};
+
+struct TSecureSocketImpl : TPlainSocketImpl, TSslHelpers {
+ static TSecureSocketImpl* IO(BIO* bio) noexcept {
+ return static_cast<TSecureSocketImpl*>(BIO_get_data(bio));
+ }
+
+ static int IoWrite(BIO* bio, const char* data, int dlen) noexcept {
+ BIO_clear_retry_flags(bio);
+ int res = IO(bio)->Socket->Socket.Send(data, dlen);
+ if (-res == EAGAIN) {
+ BIO_set_retry_write(bio);
+ }
+ return res;
+ }
+
+ static int IoRead(BIO* bio, char* data, int dlen) noexcept {
+ BIO_clear_retry_flags(bio);
+ int res = IO(bio)->Socket->Socket.Recv(data, dlen);
+ if (-res == EAGAIN) {
+ BIO_set_retry_read(bio);
+ }
+ return res;
+ }
+
+ static int IoPuts(BIO* bio, const char* buf) noexcept {
+ Y_UNUSED(bio);
+ Y_UNUSED(buf);
+ return -2;
+ }
+
+ static int IoGets(BIO* bio, char* buf, int size) noexcept {
+ Y_UNUSED(bio);
+ Y_UNUSED(buf);
+ Y_UNUSED(size);
+ return -2;
+ }
+
+ static long IoCtrl(BIO* bio, int cmd, long larg, void* parg) noexcept {
+ Y_UNUSED(larg);
+ Y_UNUSED(parg);
+
+ if (cmd == BIO_CTRL_FLUSH) {
+ IO(bio)->Flush();
+ return 1;
+ }
+
+ return -2;
+ }
+
+ static int IoCreate(BIO* bio) noexcept {
+ BIO_set_data(bio, nullptr);
+ BIO_set_init(bio, 1);
+ return 1;
+ }
+
+ static int IoDestroy(BIO* bio) noexcept {
+ BIO_set_data(bio, nullptr);
+ BIO_set_init(bio, 0);
+ return 1;
+ }
+
+ static BIO_METHOD* CreateIoMethod() {
+ BIO_METHOD* method = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK, "SecureSocketImpl");
+ BIO_meth_set_write(method, IoWrite);
+ BIO_meth_set_read(method, IoRead);
+ BIO_meth_set_puts(method, IoPuts);
+ BIO_meth_set_gets(method, IoGets);
+ BIO_meth_set_ctrl(method, IoCtrl);
+ BIO_meth_set_create(method, IoCreate);
+ BIO_meth_set_destroy(method, IoDestroy);
+ return method;
+ }
+
+ static BIO_METHOD* IoMethod() {
+ static BIO_METHOD* method = CreateIoMethod();
+ return method;
+ }
+
+ TSslHolder<BIO> Bio;
+ TSslHolder<SSL_CTX> Ctx;
+ TSslHolder<SSL> Ssl;
+
+ TSecureSocketImpl() = default;
+
+ TSecureSocketImpl(TIntrusivePtr<TSocketDescriptor> socket)
+ : TPlainSocketImpl(std::move(socket))
+ {}
+
+ void InitClientSsl() {
+ Bio.Reset(BIO_new(IoMethod()));
+ BIO_set_data(Bio.Get(), this);
+ BIO_set_nbio(Bio.Get(), 1);
+ Ctx = CreateClientContext();
+ Ssl = ConstructSsl(Ctx.Get(), Bio.Get());
+ SSL_set_connect_state(Ssl.Get());
+ }
+
+ void InitServerSsl(SSL_CTX* ctx) {
+ Bio.Reset(BIO_new(IoMethod()));
+ BIO_set_data(Bio.Get(), this);
+ BIO_set_nbio(Bio.Get(), 1);
+ Ssl = ConstructSsl(ctx, Bio.Get());
+ SSL_set_accept_state(Ssl.Get());
+ }
+
+ void Flush() {}
+
+ ssize_t Send(const void* data, size_t size, bool& read, bool& write) {
+ ssize_t res = SSL_write(Ssl.Get(), data, size);
+ if (res < 0) {
+ res = SSL_get_error(Ssl.Get(), res);
+ switch(res) {
+ case SSL_ERROR_WANT_READ:
+ read = true;
+ return -EAGAIN;
+ case SSL_ERROR_WANT_WRITE:
+ write = true;
+ return -EAGAIN;
+ default:
+ return -EIO;
+ }
+ }
+ return res;
+ }
+
+ ssize_t Recv(void* data, size_t size, bool& read, bool& write) {
+ ssize_t res = SSL_read(Ssl.Get(), data, size);
+ if (res < 0) {
+ res = SSL_get_error(Ssl.Get(), res);
+ switch(res) {
+ case SSL_ERROR_WANT_READ:
+ read = true;
+ return -EAGAIN;
+ case SSL_ERROR_WANT_WRITE:
+ write = true;
+ return -EAGAIN;
+ default:
+ return -EIO;
+ }
+ }
+ return res;
+ }
+
+ int OnConnect(bool& read, bool& write) {
+ if (!Ssl) {
+ InitClientSsl();
+ }
+ int res = SSL_connect(Ssl.Get());
+ if (res <= 0) {
+ res = SSL_get_error(Ssl.Get(), res);
+ switch(res) {
+ case SSL_ERROR_WANT_READ:
+ read = true;
+ return -EAGAIN;
+ case SSL_ERROR_WANT_WRITE:
+ write = true;
+ return -EAGAIN;
+ default:
+ return -EIO;
+ }
+ }
+ return res;
+ }
+
+ int OnAccept(const TEndpointInfo& endpoint, bool& read, bool& write) {
+ if (!Ssl) {
+ InitServerSsl(endpoint.SecureContext.Get());
+ }
+ int res = SSL_accept(Ssl.Get());
+ if (res <= 0) {
+ res = SSL_get_error(Ssl.Get(), res);
+ switch(res) {
+ case SSL_ERROR_WANT_READ:
+ read = true;
+ return -EAGAIN;
+ case SSL_ERROR_WANT_WRITE:
+ write = true;
+ return -EAGAIN;
+ default:
+ return -EIO;
+ }
+ }
+ return res;
+ }
+};
+
+}
diff --git a/library/cpp/actors/http/http_proxy_ssl.h b/library/cpp/actors/http/http_proxy_ssl.h
new file mode 100644
index 0000000000..ffce12997f
--- /dev/null
+++ b/library/cpp/actors/http/http_proxy_ssl.h
@@ -0,0 +1,131 @@
+#pragma once
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/tls1.h>
+
+namespace NHttp {
+
+struct TSslHelpers {
+ struct TSslDestroy {
+ static void Destroy(SSL_CTX* ctx) noexcept {
+ SSL_CTX_free(ctx);
+ }
+
+ static void Destroy(SSL* ssl) noexcept {
+ SSL_free(ssl);
+ }
+
+ static void Destroy(X509* cert) noexcept {
+ X509_free(cert);
+ }
+
+ static void Destroy(EVP_PKEY* pkey) noexcept {
+ EVP_PKEY_free(pkey);
+ }
+
+ static void Destroy(BIO* bio) noexcept {
+ BIO_free(bio);
+ }
+ };
+
+ template <typename T>
+ using TSslHolder = THolder<T, TSslDestroy>;
+
+ static TSslHolder<SSL_CTX> CreateSslCtx(const SSL_METHOD* method) {
+ TSslHolder<SSL_CTX> ctx(SSL_CTX_new(method));
+
+ if (ctx) {
+ SSL_CTX_set_options(ctx.Get(), SSL_OP_NO_SSLv2);
+ SSL_CTX_set_options(ctx.Get(), SSL_OP_NO_SSLv3);
+ SSL_CTX_set_options(ctx.Get(), SSL_OP_MICROSOFT_SESS_ID_BUG);
+ SSL_CTX_set_options(ctx.Get(), SSL_OP_NETSCAPE_CHALLENGE_BUG);
+ }
+
+ return ctx;
+ }
+
+ static TSslHolder<SSL_CTX> CreateClientContext() {
+ return CreateSslCtx(SSLv23_client_method());
+ }
+
+ static TSslHolder<SSL_CTX> CreateServerContext(const TString& certificate, const TString& key) {
+ TSslHolder<SSL_CTX> ctx = CreateSslCtx(SSLv23_server_method());
+ SSL_CTX_set_ecdh_auto(ctx.Get(), 1);
+ int res;
+ res = SSL_CTX_use_certificate_chain_file(ctx.Get(), certificate.c_str());
+ if (res < 0) {
+ // TODO(xenoxeno): more diagnostics?
+ return nullptr;
+ }
+ res = SSL_CTX_use_PrivateKey_file(ctx.Get(), key.c_str(), SSL_FILETYPE_PEM);
+ if (res < 0) {
+ // TODO(xenoxeno): more diagnostics?
+ return nullptr;
+ }
+ return ctx;
+ }
+
+ static bool LoadX509Chain(TSslHolder<SSL_CTX>& ctx, const TString& pem) {
+ TSslHolder<BIO> bio(BIO_new_mem_buf(pem.c_str(), pem.size()));
+ if (bio == nullptr) {
+ return false;
+ }
+ TSslHolder<X509> cert(PEM_read_bio_X509_AUX(bio.Get(), nullptr, nullptr, nullptr));
+ if (cert == nullptr) {
+ return false;
+ }
+ if (SSL_CTX_use_certificate(ctx.Get(), cert.Release()) <= 0) {
+ return false;
+ }
+ SSL_CTX_clear_chain_certs(ctx.Get());
+ while (true) {
+ TSslHolder<X509> ca(PEM_read_bio_X509(bio.Get(), nullptr, nullptr, nullptr));
+ if (ca == nullptr) {
+ break;
+ }
+ if (!SSL_CTX_add0_chain_cert(ctx.Get(), ca.Release())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static bool LoadPrivateKey(TSslHolder<SSL_CTX>& ctx, const TString& pem) {
+ TSslHolder<BIO> bio(BIO_new_mem_buf(pem.c_str(), pem.size()));
+ if (bio == nullptr) {
+ return false;
+ }
+ TSslHolder<EVP_PKEY> pkey(PEM_read_bio_PrivateKey(bio.Get(), nullptr, nullptr, nullptr));
+ if (SSL_CTX_use_PrivateKey(ctx.Get(), pkey.Release()) <= 0) {
+ return false;
+ }
+ return true;
+ }
+
+ static TSslHolder<SSL_CTX> CreateServerContext(const TString& pem) {
+ TSslHolder<SSL_CTX> ctx = CreateSslCtx(SSLv23_server_method());
+ SSL_CTX_set_ecdh_auto(ctx.Get(), 1);
+ if (!LoadX509Chain(ctx, pem)) {
+ return nullptr;
+ }
+ if (!LoadPrivateKey(ctx, pem)) {
+ return nullptr;
+ }
+ return ctx;
+ }
+
+ static TSslHolder<SSL> ConstructSsl(SSL_CTX* ctx, BIO* bio) {
+ TSslHolder<SSL> ssl(SSL_new(ctx));
+
+ if (ssl) {
+ BIO_up_ref(bio); // SSL_set_bio consumes only one reference if rbio and wbio are the same
+ SSL_set_bio(ssl.Get(), bio, bio);
+ }
+
+ return ssl;
+ }
+};
+
+}
diff --git a/library/cpp/actors/http/http_static.cpp b/library/cpp/actors/http/http_static.cpp
new file mode 100644
index 0000000000..c075c5f693
--- /dev/null
+++ b/library/cpp/actors/http/http_static.cpp
@@ -0,0 +1,95 @@
+#include "http_proxy.h"
+#include "http_static.h"
+#include <library/cpp/actors/core/executor_pool_basic.h>
+#include <library/cpp/actors/core/log.h>
+#include <library/cpp/actors/core/scheduler_basic.h>
+#include <library/cpp/actors/http/http.h>
+#include <library/cpp/resource/resource.h>
+#include <util/folder/path.h>
+#include <util/stream/file.h>
+
+namespace NHttp {
+
+class THttpStaticContentHandler : public NActors::TActor<THttpStaticContentHandler> {
+public:
+ using TBase = NActors::TActor<THttpStaticContentHandler>;
+ const TFsPath URL;
+ const TFsPath FilePath;
+ const TFsPath ResourcePath;
+ const TFsPath Index;
+
+ THttpStaticContentHandler(const TString& url, const TString& filePath, const TString& resourcePath, const TString& index)
+ : TBase(&THttpStaticContentHandler::StateWork)
+ , URL(url)
+ , FilePath(filePath)
+ , ResourcePath(resourcePath)
+ , Index(index)
+ {}
+
+ static TInstant GetCompileTime() {
+ tm compileTime;
+ strptime(__DATE__ " " __TIME__, "%B %d %Y %H:%M:%S", &compileTime);
+ return TInstant::Seconds(mktime(&compileTime));
+ }
+
+ void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) {
+ THttpOutgoingResponsePtr response;
+ if (event->Get()->Request->Method != "GET") {
+ response = event->Get()->Request->CreateResponseBadRequest("Wrong request");
+ ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
+ return;
+ }
+ TFsPath url(event->Get()->Request->URL.Before('?'));
+ if (!url.IsAbsolute()) {
+ response = event->Get()->Request->CreateResponseBadRequest("Completely wrong URL");
+ ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
+ return;
+ }
+ if (url.GetPath().EndsWith('/') && Index.IsDefined()) {
+ url /= Index;
+ }
+ url = url.RelativeTo(URL);
+ try {
+ // TODO: caching?
+ TString contentType = mimetypeByExt(url.GetExtension().c_str());
+ TString data;
+ TFileStat filestat;
+ TFsPath resourcename(ResourcePath / url);
+ if (NResource::FindExact(resourcename.GetPath(), &data)) {
+ static TInstant compileTime(GetCompileTime());
+ filestat.MTime = compileTime.Seconds();
+ } else {
+ TFsPath filename(FilePath / url);
+ if (!filename.IsSubpathOf(FilePath) && filename != FilePath) {
+ response = event->Get()->Request->CreateResponseBadRequest("Wrong URL");
+ ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
+ return;
+ }
+ if (filename.Stat(filestat) && filestat.IsFile()) {
+ data = TUnbufferedFileInput(filename).ReadAll();
+ }
+ }
+ if (!filestat.IsNull()) {
+ response = event->Get()->Request->CreateResponseOK(data, contentType, TInstant::Seconds(filestat.MTime));
+ } else {
+ response = event->Get()->Request->CreateResponseNotFound("File not found");
+ }
+ }
+ catch (const yexception&) {
+ response = event->Get()->Request->CreateResponseServiceUnavailable("Not available");
+ }
+ ctx.Send(event->Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
+ }
+
+ STFUNC(StateWork) {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle);
+ }
+ }
+};
+
+NActors::IActor* CreateHttpStaticContentHandler(const TString& url, const TString& filePath, const TString& resourcePath, const TString& index) {
+ return new THttpStaticContentHandler(url, filePath, resourcePath, index);
+}
+
+}
diff --git a/library/cpp/actors/http/http_static.h b/library/cpp/actors/http/http_static.h
new file mode 100644
index 0000000000..f91e15dfb1
--- /dev/null
+++ b/library/cpp/actors/http/http_static.h
@@ -0,0 +1,9 @@
+#pragma once
+#include <library/cpp/actors/core/actor.h>
+#include "http.h"
+
+namespace NHttp {
+
+NActors::IActor* CreateHttpStaticContentHandler(const TString& url, const TString& filePath, const TString& resourcePath, const TString& index = TString());
+
+}
diff --git a/library/cpp/actors/http/http_ut.cpp b/library/cpp/actors/http/http_ut.cpp
new file mode 100644
index 0000000000..4c922f8d0f
--- /dev/null
+++ b/library/cpp/actors/http/http_ut.cpp
@@ -0,0 +1,358 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/testing/unittest/tests_data.h>
+#include <library/cpp/actors/core/executor_pool_basic.h>
+#include <library/cpp/actors/core/scheduler_basic.h>
+#include <library/cpp/actors/testlib/test_runtime.h>
+#include <util/system/tempfile.h>
+#include "http.h"
+#include "http_proxy.h"
+
+
+
+enum EService : NActors::NLog::EComponent {
+ MIN,
+ Logger,
+ MVP,
+ MAX
+};
+
+namespace {
+
+template <typename HttpType>
+void EatWholeString(TIntrusivePtr<HttpType>& request, const TString& data) {
+ request->EnsureEnoughSpaceAvailable(data.size());
+ auto size = std::min(request->Avail(), data.size());
+ memcpy(request->Pos(), data.data(), size);
+ request->Advance(size);
+}
+
+template <typename HttpType>
+void EatPartialString(TIntrusivePtr<HttpType>& request, const TString& data) {
+ for (char c : data) {
+ request->EnsureEnoughSpaceAvailable(1);
+ memcpy(request->Pos(), &c, 1);
+ request->Advance(1);
+ }
+}
+
+}
+
+Y_UNIT_TEST_SUITE(HttpProxy) {
+ Y_UNIT_TEST(BasicParsing) {
+ NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest();
+ EatWholeString(request, "GET /test HTTP/1.1\r\nHost: test\r\nSome-Header: 32344\r\n\r\n");
+ UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done);
+ UNIT_ASSERT_EQUAL(request->Method, "GET");
+ UNIT_ASSERT_EQUAL(request->URL, "/test");
+ UNIT_ASSERT_EQUAL(request->Protocol, "HTTP");
+ UNIT_ASSERT_EQUAL(request->Version, "1.1");
+ UNIT_ASSERT_EQUAL(request->Host, "test");
+ UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n");
+ }
+
+ Y_UNIT_TEST(BasicParsingChunkedBody) {
+ NHttp::THttpOutgoingRequestPtr request = nullptr; //new NHttp::THttpOutgoingRequest();
+ NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(request);
+ EatWholeString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n4\r\nthis\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n");
+ UNIT_ASSERT_EQUAL(response->Stage, NHttp::THttpIncomingResponse::EParseStage::Done);
+ UNIT_ASSERT_EQUAL(response->Status, "200");
+ UNIT_ASSERT_EQUAL(response->Connection, "close");
+ UNIT_ASSERT_EQUAL(response->Protocol, "HTTP");
+ UNIT_ASSERT_EQUAL(response->Version, "1.1");
+ UNIT_ASSERT_EQUAL(response->TransferEncoding, "chunked");
+ UNIT_ASSERT_EQUAL(response->Body, "this is test.");
+ }
+
+ Y_UNIT_TEST(InvalidParsingChunkedBody) {
+ NHttp::THttpOutgoingRequestPtr request = nullptr; //new NHttp::THttpOutgoingRequest();
+ NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(request);
+ EatWholeString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nthis\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n");
+ UNIT_ASSERT(response->IsError());
+ }
+
+ Y_UNIT_TEST(AdvancedParsingChunkedBody) {
+ NHttp::THttpOutgoingRequestPtr request = nullptr; //new NHttp::THttpOutgoingRequest();
+ NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(request);
+ EatWholeString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n6\r\nthis\r\n\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n");
+ UNIT_ASSERT_EQUAL(response->Stage, NHttp::THttpIncomingResponse::EParseStage::Done);
+ UNIT_ASSERT_EQUAL(response->Status, "200");
+ UNIT_ASSERT_EQUAL(response->Connection, "close");
+ UNIT_ASSERT_EQUAL(response->Protocol, "HTTP");
+ UNIT_ASSERT_EQUAL(response->Version, "1.1");
+ UNIT_ASSERT_EQUAL(response->TransferEncoding, "chunked");
+ UNIT_ASSERT_EQUAL(response->Body, "this\r\n is test.");
+ }
+
+ Y_UNIT_TEST(CreateRepsonseWithCompressedBody) {
+ NHttp::THttpIncomingRequestPtr request = nullptr;
+ NHttp::THttpOutgoingResponsePtr response = new NHttp::THttpOutgoingResponse(request, "HTTP", "1.1", "200", "OK");
+ response->Set<&NHttp::THttpResponse::ContentEncoding>("gzip");
+ TString compressedBody = "compressed body";
+ response->SetBody(compressedBody);
+ UNIT_ASSERT_VALUES_EQUAL("gzip", response->ContentEncoding);
+ UNIT_ASSERT_VALUES_EQUAL(ToString(compressedBody.size()), response->ContentLength);
+ UNIT_ASSERT_VALUES_EQUAL(compressedBody, response->Body);
+ }
+
+ Y_UNIT_TEST(BasicPartialParsing) {
+ NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest();
+ EatPartialString(request, "GET /test HTTP/1.1\r\nHost: test\r\nSome-Header: 32344\r\n\r\n");
+ UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done);
+ UNIT_ASSERT_EQUAL(request->Method, "GET");
+ UNIT_ASSERT_EQUAL(request->URL, "/test");
+ UNIT_ASSERT_EQUAL(request->Protocol, "HTTP");
+ UNIT_ASSERT_EQUAL(request->Version, "1.1");
+ UNIT_ASSERT_EQUAL(request->Host, "test");
+ UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n");
+ }
+
+ Y_UNIT_TEST(BasicPartialParsingChunkedBody) {
+ NHttp::THttpOutgoingRequestPtr request = nullptr; //new NHttp::THttpOutgoingRequest();
+ NHttp::THttpIncomingResponsePtr response = new NHttp::THttpIncomingResponse(request);
+ EatPartialString(response, "HTTP/1.1 200 OK\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n4\r\nthis\r\n4\r\n is \r\n5\r\ntest.\r\n0\r\n\r\n");
+ UNIT_ASSERT_EQUAL(response->Stage, NHttp::THttpIncomingResponse::EParseStage::Done);
+ UNIT_ASSERT_EQUAL(response->Status, "200");
+ UNIT_ASSERT_EQUAL(response->Connection, "close");
+ UNIT_ASSERT_EQUAL(response->Protocol, "HTTP");
+ UNIT_ASSERT_EQUAL(response->Version, "1.1");
+ UNIT_ASSERT_EQUAL(response->TransferEncoding, "chunked");
+ UNIT_ASSERT_EQUAL(response->Body, "this is test.");
+ }
+
+ Y_UNIT_TEST(AdvancedParsing) {
+ NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest();
+ EatWholeString(request, "GE");
+ EatWholeString(request, "T");
+ EatWholeString(request, " ");
+ EatWholeString(request, "/test");
+ EatWholeString(request, " HTTP/1.1\r");
+ EatWholeString(request, "\nHo");
+ EatWholeString(request, "st: test");
+ EatWholeString(request, "\r\n");
+ EatWholeString(request, "Some-Header: 32344\r\n\r");
+ EatWholeString(request, "\n");
+ UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done);
+ UNIT_ASSERT_EQUAL(request->Method, "GET");
+ UNIT_ASSERT_EQUAL(request->URL, "/test");
+ UNIT_ASSERT_EQUAL(request->Protocol, "HTTP");
+ UNIT_ASSERT_EQUAL(request->Version, "1.1");
+ UNIT_ASSERT_EQUAL(request->Host, "test");
+ UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n");
+ }
+
+ Y_UNIT_TEST(AdvancedPartialParsing) {
+ NHttp::THttpIncomingRequestPtr request = new NHttp::THttpIncomingRequest();
+ EatPartialString(request, "GE");
+ EatPartialString(request, "T");
+ EatPartialString(request, " ");
+ EatPartialString(request, "/test");
+ EatPartialString(request, " HTTP/1.1\r");
+ EatPartialString(request, "\nHo");
+ EatPartialString(request, "st: test");
+ EatPartialString(request, "\r\n");
+ EatPartialString(request, "Some-Header: 32344\r\n\r");
+ EatPartialString(request, "\n");
+ UNIT_ASSERT_EQUAL(request->Stage, NHttp::THttpIncomingRequest::EParseStage::Done);
+ UNIT_ASSERT_EQUAL(request->Method, "GET");
+ UNIT_ASSERT_EQUAL(request->URL, "/test");
+ UNIT_ASSERT_EQUAL(request->Protocol, "HTTP");
+ UNIT_ASSERT_EQUAL(request->Version, "1.1");
+ UNIT_ASSERT_EQUAL(request->Host, "test");
+ UNIT_ASSERT_EQUAL(request->Headers, "Host: test\r\nSome-Header: 32344\r\n\r\n");
+ }
+
+ Y_UNIT_TEST(BasicRenderBodyWithHeadersAndCookies) {
+ NHttp::THttpOutgoingRequestPtr request = NHttp::THttpOutgoingRequest::CreateRequestGet("http://www.yandex.ru/data/url");
+ NHttp::THeadersBuilder headers;
+ NHttp::TCookiesBuilder cookies;
+ cookies.Set("cookie1", "123456");
+ cookies.Set("cookie2", "45678");
+ headers.Set("Cookie", cookies.Render());
+ request->Set(headers);
+ TString requestData;
+ request->AsString(requestData);
+ UNIT_ASSERT_VALUES_EQUAL(requestData, "GET /data/url HTTP/1.1\r\nHost: www.yandex.ru\r\nAccept: */*\r\nCookie: cookie1=123456; cookie2=45678;\r\n");
+ }
+
+ Y_UNIT_TEST(BasicRunning) {
+ NActors::TTestActorRuntimeBase actorSystem;
+ TPortManager portManager;
+ TIpPort port = portManager.GetTcpPort();
+ TAutoPtr<NActors::IEventHandle> handle;
+ actorSystem.Initialize();
+ NMonitoring::TMetricRegistry sensors;
+
+ NActors::IActor* proxy = NHttp::CreateHttpProxy(sensors);
+ NActors::TActorId proxyId = actorSystem.Register(proxy);
+ actorSystem.Send(new NActors::IEventHandle(proxyId, TActorId(), new NHttp::TEvHttpProxy::TEvAddListeningPort(port)), 0, true);
+ actorSystem.DispatchEvents();
+
+ NActors::TActorId serverId = actorSystem.AllocateEdgeActor();
+ actorSystem.Send(new NActors::IEventHandle(proxyId, serverId, new NHttp::TEvHttpProxy::TEvRegisterHandler("/test", serverId)), 0, true);
+
+ NActors::TActorId clientId = actorSystem.AllocateEdgeActor();
+ NHttp::THttpOutgoingRequestPtr httpRequest = NHttp::THttpOutgoingRequest::CreateRequestGet("http://[::1]:" + ToString(port) + "/test");
+ actorSystem.Send(new NActors::IEventHandle(proxyId, clientId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(httpRequest)), 0, true);
+
+ NHttp::TEvHttpProxy::TEvHttpIncomingRequest* request = actorSystem.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpIncomingRequest>(handle);
+
+ UNIT_ASSERT_EQUAL(request->Request->URL, "/test");
+
+ NHttp::THttpOutgoingResponsePtr httpResponse = request->Request->CreateResponseString("HTTP/1.1 200 Found\r\nConnection: Close\r\nTransfer-Encoding: chunked\r\n\r\n6\r\npassed\r\n0\r\n\r\n");
+ actorSystem.Send(new NActors::IEventHandle(handle->Sender, serverId, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(httpResponse)), 0, true);
+
+ NHttp::TEvHttpProxy::TEvHttpIncomingResponse* response = actorSystem.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpIncomingResponse>(handle);
+
+ UNIT_ASSERT_EQUAL(response->Response->Status, "200");
+ UNIT_ASSERT_EQUAL(response->Response->Body, "passed");
+ }
+
+ Y_UNIT_TEST(TlsRunning) {
+ NActors::TTestActorRuntimeBase actorSystem;
+ TPortManager portManager;
+ TIpPort port = portManager.GetTcpPort();
+ TAutoPtr<NActors::IEventHandle> handle;
+ actorSystem.Initialize();
+ NMonitoring::TMetricRegistry sensors;
+
+ TString certificateContent = R"___(-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCzRZjodO7Aqe1w
+RyOj6kG6g2nn8ZGAxfao4mLT0jDTbVksrhV/h2s3uldLkFo5WrNQ8WZe+iIbXeFL
+s8tO6hslzreo9sih2IHoRcH5KnS/6YTqVhRTJb1jE2dM8NwYbwTi+T2Pe0FrBPjI
+kgVO50gAtYl9C+fc715uZiSKW+rRlP5OoFTwxrOjiU27RPZjFYyWK9wTI1Es9uRr
+lbZbLl5cY6dK2J1AViRraaYKCWO26VbOPWLsY4OD3e+ZXIc3OMCz6Yb0wmRPeJ60
+bbbkGfI8O27kDdv69MAWHIm0yYMzKEnom1dce7rNQNDEqJfocsYIsg+EvayT1yQ9
+KTBegw7LAgMBAAECggEBAKaOCrotqYQmXArsjRhFFDwMy+BKdzyEr93INrlFl0dX
+WHpCYobRcbOc1G3H94tB0UdqgAnNqtJyLlb+++ydZAuEOu4oGc8EL+10ofq0jzOd
+6Xct8kQt0/6wkFDTlii9PHUDy0X65ZRgUiNGRtg/2I2QG+SpowmI+trm2xwQueFs
+VaWrjc3cVvXx0b8Lu7hqZUv08kgC38stzuRk/n2T5VWSAr7Z4ZWQbO918Dv35HUw
+Wy/0jNUFP9CBCvFJ4l0OoH9nYhWFG+HXWzNdw6/Hca4jciRKo6esCiOZ9uWYv/ec
+/NvX9rgFg8G8/SrTisX10+Bbeq+R1RKwq/IG409TH4ECgYEA14L+3QsgNIUMeYAx
+jSCyk22R/tOHI1BM+GtKPUhnwHlAssrcPcxXMJovl6WL93VauYjym0wpCz9urSpA
+I2CqTsG8GYciA6Dr3mHgD6cK0jj9UPAU6EnZ5S0mjhPqKZqutu9QegzD2uESvuN8
+36xezwQthzAf0nI/P3sJGjVXjikCgYEA1POm5xcV6SmM6HnIdadEebhzZIJ9TXQz
+ry3Jj3a7CKyD5C7fAdkHUTCjgT/2ElxPi9ABkZnC+d/cW9GtJFa0II5qO/agm3KQ
+ZXYiutu9A7xACHYFXRiJEjVUdGG9dKMVOHUEa8IHEgrrcUVM/suy/GgutywIfaXs
+y58IFP24K9MCgYEAk6zjz7wL+XEiNy+sxLQfKf7vB9sSwxQHakK6wHuY/L8Zomp3
+uLEJHfjJm/SIkK0N2g0JkXkCtv5kbKyC/rsCeK0wo52BpVLjzaLr0k34kE0U6B1b
+dkEE2pGx1bG3x4KDLj+Wuct9ecK5Aa0IqIyI+vo16GkFpUM8K9e3SQo8UOECgYEA
+sCZYAkILYtJ293p9giz5rIISGasDAUXE1vxWBXEeJ3+kneTTnZCrx9Im/ewtnWR0
+fF90XL9HFDDD88POqAd8eo2zfKR2l/89SGBfPBg2EtfuU9FkgGyiPciVcqvC7q9U
+B15saMKX3KnhtdGwbfeLt9RqCCTJZT4SUSDcq5hwdvcCgYAxY4Be8mNipj8Cgg22
+mVWSolA0TEzbtUcNk6iGodpi+Z0LKpsPC0YRqPRyh1K+rIltG1BVdmUBHcMlOYxl
+lWWvbJH6PkJWy4n2MF7PO45kjN3pPZg4hgH63JjZeAineBwEArUGb9zHnvzcdRvF
+wuQ2pZHL/HJ0laUSieHDJ5917w==
+-----END PRIVATE KEY-----
+
+
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIURt5IBx0J3xgEaQvmyrFH2A+NkpMwDQYJKoZIhvcNAQEL
+BQAwVjELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9z
+Y293MQ8wDQYDVQQKDAZZYW5kZXgxFDASBgNVBAMMC3Rlc3Qtc2VydmVyMB4XDTE5
+MDkyMDE3MTQ0MVoXDTQ3MDIwNDE3MTQ0MVowVjELMAkGA1UEBhMCUlUxDzANBgNV
+BAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MQ8wDQYDVQQKDAZZYW5kZXgxFDAS
+BgNVBAMMC3Rlc3Qtc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAs0WY6HTuwKntcEcjo+pBuoNp5/GRgMX2qOJi09Iw021ZLK4Vf4drN7pXS5Ba
+OVqzUPFmXvoiG13hS7PLTuobJc63qPbIodiB6EXB+Sp0v+mE6lYUUyW9YxNnTPDc
+GG8E4vk9j3tBawT4yJIFTudIALWJfQvn3O9ebmYkilvq0ZT+TqBU8Mazo4lNu0T2
+YxWMlivcEyNRLPbka5W2Wy5eXGOnStidQFYka2mmCgljtulWzj1i7GODg93vmVyH
+NzjAs+mG9MJkT3ietG225BnyPDtu5A3b+vTAFhyJtMmDMyhJ6JtXXHu6zUDQxKiX
+6HLGCLIPhL2sk9ckPSkwXoMOywIDAQABo1MwUTAdBgNVHQ4EFgQUDv/xuJ4CvCgG
+fPrZP3hRAt2+/LwwHwYDVR0jBBgwFoAUDv/xuJ4CvCgGfPrZP3hRAt2+/LwwDwYD
+VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAinKpMYaA2tjLpAnPVbjy
+/ZxSBhhB26RiQp3Re8XOKyhTWqgYE6kldYT0aXgK9x9mPC5obQannDDYxDc7lX+/
+qP/u1X81ZcDRo/f+qQ3iHfT6Ftt/4O3qLnt45MFM6Q7WabRm82x3KjZTqpF3QUdy
+tumWiuAP5DMd1IRDtnKjFHO721OsEsf6NLcqdX89bGeqXDvrkwg3/PNwTyW5E7cj
+feY8L2eWtg6AJUnIBu11wvfzkLiH3QKzHvO/SIZTGf5ihDsJ3aKEE9UNauTL3bVc
+CRA/5XcX13GJwHHj6LCoc3sL7mt8qV9HKY2AOZ88mpObzISZxgPpdKCfjsrdm63V
+6g==
+-----END CERTIFICATE-----)___";
+
+ TTempFileHandle certificateFile;
+
+ certificateFile.Write(certificateContent.data(), certificateContent.size());
+
+ NActors::IActor* proxy = NHttp::CreateHttpProxy(sensors);
+ NActors::TActorId proxyId = actorSystem.Register(proxy);
+
+ THolder<NHttp::TEvHttpProxy::TEvAddListeningPort> add = MakeHolder<NHttp::TEvHttpProxy::TEvAddListeningPort>(port);
+ ///////// https configuration
+ add->Secure = true;
+ add->CertificateFile = certificateFile.Name();
+ add->PrivateKeyFile = certificateFile.Name();
+ /////////
+ actorSystem.Send(new NActors::IEventHandle(proxyId, TActorId(), add.Release()), 0, true);
+ actorSystem.DispatchEvents();
+
+ NActors::TActorId serverId = actorSystem.AllocateEdgeActor();
+ actorSystem.Send(new NActors::IEventHandle(proxyId, serverId, new NHttp::TEvHttpProxy::TEvRegisterHandler("/test", serverId)), 0, true);
+
+ NActors::TActorId clientId = actorSystem.AllocateEdgeActor();
+ NHttp::THttpOutgoingRequestPtr httpRequest = NHttp::THttpOutgoingRequest::CreateRequestGet("https://[::1]:" + ToString(port) + "/test");
+ actorSystem.Send(new NActors::IEventHandle(proxyId, clientId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(httpRequest)), 0, true);
+
+ NHttp::TEvHttpProxy::TEvHttpIncomingRequest* request = actorSystem.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpIncomingRequest>(handle);
+
+ UNIT_ASSERT_EQUAL(request->Request->URL, "/test");
+
+ NHttp::THttpOutgoingResponsePtr httpResponse = request->Request->CreateResponseString("HTTP/1.1 200 Found\r\nConnection: Close\r\nTransfer-Encoding: chunked\r\n\r\n6\r\npassed\r\n0\r\n\r\n");
+ actorSystem.Send(new NActors::IEventHandle(handle->Sender, serverId, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(httpResponse)), 0, true);
+
+ NHttp::TEvHttpProxy::TEvHttpIncomingResponse* response = actorSystem.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpIncomingResponse>(handle);
+
+ UNIT_ASSERT_EQUAL(response->Response->Status, "200");
+ UNIT_ASSERT_EQUAL(response->Response->Body, "passed");
+ }
+
+ /*Y_UNIT_TEST(AdvancedRunning) {
+ THolder<NActors::TActorSystemSetup> setup = MakeHolder<NActors::TActorSystemSetup>();
+ setup->NodeId = 1;
+ setup->ExecutorsCount = 1;
+ setup->Executors = new TAutoPtr<NActors::IExecutorPool>[1];
+ setup->Executors[0] = new NActors::TBasicExecutorPool(0, 2, 10);
+ setup->Scheduler = new NActors::TBasicSchedulerThread(NActors::TSchedulerConfig(512, 100));
+ NActors::TActorSystem actorSystem(setup);
+ actorSystem.Start();
+ NHttp::THttpProxy* incomingProxy = new NHttp::THttpProxy();
+ NActors::TActorId incomingProxyId = actorSystem.Register(incomingProxy);
+ actorSystem.Send(incomingProxyId, new NHttp::TEvHttpProxy::TEvAddListeningPort(13337));
+
+ NHttp::THttpProxy* outgoingProxy = new NHttp::THttpProxy();
+ NActors::TActorId outgoingProxyId = actorSystem.Register(outgoingProxy);
+
+ THolder<NHttp::THttpStaticStringRequest> httpRequest = MakeHolder<NHttp::THttpStaticStringRequest>("GET /test HTTP/1.1\r\n\r\n");
+ actorSystem.Send(outgoingProxyId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest("[::]:13337", std::move(httpRequest)));
+
+ Sleep(TDuration::Minutes(60));
+ }*/
+
+ Y_UNIT_TEST(TooLongHeader) {
+ NActors::TTestActorRuntimeBase actorSystem;
+ TPortManager portManager;
+ TIpPort port = portManager.GetTcpPort();
+ TAutoPtr<NActors::IEventHandle> handle;
+ actorSystem.Initialize();
+ NMonitoring::TMetricRegistry sensors;
+
+ NActors::IActor* proxy = NHttp::CreateHttpProxy(sensors);
+ NActors::TActorId proxyId = actorSystem.Register(proxy);
+ actorSystem.Send(new NActors::IEventHandle(proxyId, TActorId(), new NHttp::TEvHttpProxy::TEvAddListeningPort(port)), 0, true);
+ actorSystem.DispatchEvents();
+
+ NActors::TActorId serverId = actorSystem.AllocateEdgeActor();
+ actorSystem.Send(new NActors::IEventHandle(proxyId, serverId, new NHttp::TEvHttpProxy::TEvRegisterHandler("/test", serverId)), 0, true);
+
+ NActors::TActorId clientId = actorSystem.AllocateEdgeActor();
+ NHttp::THttpOutgoingRequestPtr httpRequest = NHttp::THttpOutgoingRequest::CreateRequestGet("http://[::1]:" + ToString(port) + "/test");
+ httpRequest->Set("Connection", "close");
+ TString longHeader;
+ longHeader.append(9000, 'X');
+ httpRequest->Set(longHeader, "data");
+ actorSystem.Send(new NActors::IEventHandle(proxyId, clientId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(httpRequest)), 0, true);
+
+ NHttp::TEvHttpProxy::TEvHttpIncomingResponse* response = actorSystem.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpIncomingResponse>(handle);
+
+ UNIT_ASSERT_EQUAL(response->Response->Status, "400");
+ UNIT_ASSERT_EQUAL(response->Response->Body, "Invalid http header");
+ }
+}
diff --git a/library/cpp/actors/http/ut/ya.make b/library/cpp/actors/http/ut/ya.make
new file mode 100644
index 0000000000..8b4c04c4d3
--- /dev/null
+++ b/library/cpp/actors/http/ut/ya.make
@@ -0,0 +1,18 @@
+UNITTEST_FOR(library/cpp/actors/http)
+
+OWNER(xenoxeno)
+
+SIZE(SMALL)
+
+PEERDIR(
+ library/cpp/actors/testlib
+)
+
+IF (NOT OS_WINDOWS)
+SRCS(
+ http_ut.cpp
+)
+ELSE()
+ENDIF()
+
+END()
diff --git a/library/cpp/actors/http/ya.make b/library/cpp/actors/http/ya.make
new file mode 100644
index 0000000000..7ce68b7a75
--- /dev/null
+++ b/library/cpp/actors/http/ya.make
@@ -0,0 +1,33 @@
+RECURSE_FOR_TESTS(ut)
+
+LIBRARY()
+
+OWNER(xenoxeno g:kikimr)
+
+SRCS(
+ http_cache.cpp
+ http_cache.h
+ http_config.h
+ http_proxy_acceptor.cpp
+ http_proxy_incoming.cpp
+ http_proxy_outgoing.cpp
+ http_proxy_sock_impl.h
+ http_proxy_ssl.h
+ http_proxy.cpp
+ http_proxy.h
+ http_static.cpp
+ http_static.h
+ http.cpp
+ http.h
+)
+
+PEERDIR(
+ contrib/libs/openssl
+ library/cpp/actors/core
+ library/cpp/actors/interconnect
+ library/cpp/dns
+ library/cpp/monlib/metrics
+ library/cpp/string_utils/quote
+)
+
+END()
diff --git a/library/cpp/actors/interconnect/channel_scheduler.h b/library/cpp/actors/interconnect/channel_scheduler.h
new file mode 100644
index 0000000000..551a4cb61a
--- /dev/null
+++ b/library/cpp/actors/interconnect/channel_scheduler.h
@@ -0,0 +1,120 @@
+#pragma once
+
+#include "interconnect_channel.h"
+#include "event_holder_pool.h"
+
+#include <memory>
+
+namespace NActors {
+
+ class TChannelScheduler {
+ const ui32 PeerNodeId;
+ std::array<std::optional<TEventOutputChannel>, 16> ChannelArray;
+ THashMap<ui16, TEventOutputChannel> ChannelMap;
+ std::shared_ptr<IInterconnectMetrics> Metrics;
+ TEventHolderPool& Pool;
+ const ui32 MaxSerializedEventSize;
+ const TSessionParams Params;
+
+ struct THeapItem {
+ TEventOutputChannel *Channel;
+ ui64 WeightConsumed = 0;
+
+ friend bool operator <(const THeapItem& x, const THeapItem& y) {
+ return x.WeightConsumed > y.WeightConsumed;
+ }
+ };
+
+ std::vector<THeapItem> Heap;
+
+ public:
+ TChannelScheduler(ui32 peerNodeId, const TChannelsConfig& predefinedChannels,
+ std::shared_ptr<IInterconnectMetrics> metrics, TEventHolderPool& pool, ui32 maxSerializedEventSize,
+ TSessionParams params)
+ : PeerNodeId(peerNodeId)
+ , Metrics(std::move(metrics))
+ , Pool(pool)
+ , MaxSerializedEventSize(maxSerializedEventSize)
+ , Params(std::move(params))
+ {
+ for (const auto& item : predefinedChannels) {
+ GetOutputChannel(item.first);
+ }
+ }
+
+ TEventOutputChannel *PickChannelWithLeastConsumedWeight() {
+ Y_VERIFY(!Heap.empty());
+ return Heap.front().Channel;
+ }
+
+ void AddToHeap(TEventOutputChannel& channel, ui64 counter) {
+ if (channel.IsWorking()) {
+ ui64 weight = channel.WeightConsumedOnPause;
+ weight -= Min(weight, counter - channel.EqualizeCounterOnPause);
+ Heap.push_back(THeapItem{&channel, weight});
+ std::push_heap(Heap.begin(), Heap.end());
+ }
+ }
+
+ void FinishPick(ui64 weightConsumed, ui64 counter) {
+ std::pop_heap(Heap.begin(), Heap.end());
+ auto& item = Heap.back();
+ item.WeightConsumed += weightConsumed;
+ if (item.Channel->IsWorking()) { // reschedule
+ std::push_heap(Heap.begin(), Heap.end());
+ } else { // remove from heap
+ item.Channel->EqualizeCounterOnPause = counter;
+ item.Channel->WeightConsumedOnPause = item.WeightConsumed;
+ Heap.pop_back();
+ }
+ }
+
+ TEventOutputChannel& GetOutputChannel(ui16 channel) {
+ if (channel < ChannelArray.size()) {
+ auto& res = ChannelArray[channel];
+ if (Y_UNLIKELY(!res)) {
+ res.emplace(Pool, channel, PeerNodeId, MaxSerializedEventSize, Metrics,
+ Params);
+ }
+ return *res;
+ } else {
+ auto it = ChannelMap.find(channel);
+ if (Y_UNLIKELY(it == ChannelMap.end())) {
+ it = ChannelMap.emplace(std::piecewise_construct, std::forward_as_tuple(channel),
+ std::forward_as_tuple(Pool, channel, PeerNodeId, MaxSerializedEventSize,
+ Metrics, Params)).first;
+ }
+ return it->second;
+ }
+ }
+
+ ui64 Equalize() {
+ if (Heap.empty()) {
+ return 0; // nothing to do here -- no working channels
+ }
+
+ // find the minimum consumed weight among working channels and then adjust weights
+ ui64 min = Max<ui64>();
+ for (THeapItem& item : Heap) {
+ min = Min(min, item.WeightConsumed);
+ }
+ for (THeapItem& item : Heap) {
+ item.WeightConsumed -= min;
+ }
+ return min;
+ }
+
+ template<typename TCallback>
+ void ForEach(TCallback&& callback) {
+ for (auto& channel : ChannelArray) {
+ if (channel) {
+ callback(*channel);
+ }
+ }
+ for (auto& [id, channel] : ChannelMap) {
+ callback(channel);
+ }
+ }
+ };
+
+} // NActors
diff --git a/library/cpp/actors/interconnect/event_filter.h b/library/cpp/actors/interconnect/event_filter.h
new file mode 100644
index 0000000000..47dabf5f16
--- /dev/null
+++ b/library/cpp/actors/interconnect/event_filter.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include <library/cpp/actors/core/event.h>
+
+namespace NActors {
+
+ enum class ENodeClass {
+ SYSTEM,
+ LOCAL_TENANT,
+ PEER_TENANT,
+ COUNT
+ };
+
+ class TEventFilter : TNonCopyable {
+ using TRouteMask = ui16;
+
+ TVector<TVector<TRouteMask>> ScopeRoutes;
+
+ public:
+ TEventFilter()
+ : ScopeRoutes(65536)
+ {}
+
+ void RegisterEvent(ui32 type, TRouteMask routes) {
+ auto& evSpaceIndex = ScopeRoutes[type >> 16];
+ const ui16 subtype = type & 65535;
+ size_t size = (subtype + 512) & ~511;
+ if (evSpaceIndex.size() < size) {
+ evSpaceIndex.resize(size);
+ }
+ evSpaceIndex[subtype] = routes;
+ }
+
+ bool CheckIncomingEvent(const IEventHandle& ev, const TScopeId& localScopeId) const {
+ TRouteMask routes = 0;
+ if (const auto& evSpaceIndex = ScopeRoutes[ev.Type >> 16]) {
+ const ui16 subtype = ev.Type & 65535;
+ routes = subtype < evSpaceIndex.size() ? evSpaceIndex[subtype] : 0;
+ } else {
+ routes = ~TRouteMask(); // allow unfilled event spaces by default
+ }
+ return routes & MakeRouteMask(GetNodeClass(ev.OriginScopeId, localScopeId), GetNodeClass(localScopeId, ev.OriginScopeId));
+ }
+
+ static ENodeClass GetNodeClass(const TScopeId& scopeId, const TScopeId& localScopeId) {
+ if (scopeId.first == 0) {
+ // system scope, or null scope
+ return scopeId.second ? ENodeClass::SYSTEM : ENodeClass::COUNT;
+ } else if (scopeId == localScopeId) {
+ return ENodeClass::LOCAL_TENANT;
+ } else {
+ return ENodeClass::PEER_TENANT;
+ }
+ }
+
+ static TRouteMask MakeRouteMask(ENodeClass from, ENodeClass to) {
+ if (from == ENodeClass::COUNT || to == ENodeClass::COUNT) {
+ return 0;
+ }
+ return 1U << (static_cast<unsigned>(from) * static_cast<unsigned>(ENodeClass::COUNT) + static_cast<unsigned>(to));
+ }
+
+ static TRouteMask MakeRouteMask(std::initializer_list<std::pair<ENodeClass, ENodeClass>> items) {
+ TRouteMask mask = 0;
+ for (const auto& p : items) {
+ mask |= MakeRouteMask(p.first, p.second);
+ }
+ return mask;
+ }
+ };
+
+} // NActors
diff --git a/library/cpp/actors/interconnect/event_holder_pool.h b/library/cpp/actors/interconnect/event_holder_pool.h
new file mode 100644
index 0000000000..b6090a3bc8
--- /dev/null
+++ b/library/cpp/actors/interconnect/event_holder_pool.h
@@ -0,0 +1,128 @@
+#pragma once
+
+#include <library/cpp/containers/stack_vector/stack_vec.h>
+
+#include "packet.h"
+
+namespace NActors {
+ struct TEvFreeItems : TEventLocal<TEvFreeItems, EventSpaceBegin(TEvents::ES_PRIVATE)> {
+ static constexpr size_t MaxEvents = 256;
+
+ TList<TTcpPacketOutTask> Items;
+ std::list<TEventHolder> FreeQueue;
+ TStackVec<THolder<IEventBase>, MaxEvents> Events;
+ TStackVec<THolder<TEventSerializedData>, MaxEvents> Buffers;
+ std::shared_ptr<std::atomic<TAtomicBase>> Counter;
+ ui64 NumBytes = 0;
+
+ ~TEvFreeItems() {
+ if (Counter) {
+ TAtomicBase res = Counter->fetch_sub(NumBytes) - NumBytes;
+ Y_VERIFY(res >= 0);
+ }
+ }
+
+ bool GetInLineForDestruction(const TIntrusivePtr<TInterconnectProxyCommon>& common) {
+ Y_VERIFY(!Counter);
+ const auto& counter = common->DestructorQueueSize;
+ const auto& max = common->MaxDestructorQueueSize;
+ if (counter && (TAtomicBase)(counter->fetch_add(NumBytes) + NumBytes) > max) {
+ counter->fetch_sub(NumBytes);
+ return false;
+ }
+ Counter = counter;
+ return true;
+ }
+ };
+
+ class TEventHolderPool {
+ using TDestroyCallback = std::function<void(THolder<IEventBase>)>;
+
+ static constexpr size_t MaxFreeQueueItems = 32;
+ static constexpr size_t FreeQueueTrimThreshold = MaxFreeQueueItems * 2;
+ static constexpr ui64 MaxBytesPerMessage = 10 * 1024 * 1024;
+
+ TIntrusivePtr<TInterconnectProxyCommon> Common;
+ std::list<TEventHolder> Cache;
+ THolder<TEvFreeItems> PendingFreeEvent;
+ TDestroyCallback DestroyCallback;
+
+ public:
+ TEventHolderPool(TIntrusivePtr<TInterconnectProxyCommon> common,
+ TDestroyCallback destroyCallback)
+ : Common(std::move(common))
+ , DestroyCallback(std::move(destroyCallback))
+ {}
+
+ TEventHolder& Allocate(std::list<TEventHolder>& queue) {
+ if (Cache.empty()) {
+ queue.emplace_back();
+ } else {
+ queue.splice(queue.end(), Cache, Cache.begin());
+ }
+ return queue.back();
+ }
+
+ void Release(std::list<TEventHolder>& queue) {
+ for (auto it = queue.begin(); it != queue.end(); ) {
+ Release(queue, it++);
+ }
+ }
+
+ void Release(std::list<TEventHolder>& queue, std::list<TEventHolder>::iterator event) {
+ bool trim = false;
+
+ // release held event, if any
+ if (THolder<IEventBase> ev = std::move(event->Event)) {
+ auto p = GetPendingEvent();
+ p->NumBytes += event->EventSerializedSize;
+ auto& events = p->Events;
+ events.push_back(std::move(ev));
+ trim = trim || events.size() >= TEvFreeItems::MaxEvents || p->NumBytes >= MaxBytesPerMessage;
+ }
+
+ // release buffer, if any
+ if (event->Buffer && event->Buffer.RefCount() == 1) {
+ auto p = GetPendingEvent();
+ p->NumBytes += event->EventSerializedSize;
+ auto& buffers = p->Buffers;
+ buffers.emplace_back(event->Buffer.Release());
+ trim = trim || buffers.size() >= TEvFreeItems::MaxEvents || p->NumBytes >= MaxBytesPerMessage;
+ }
+
+ // free event and trim the cache if its size is exceeded
+ event->Clear();
+ Cache.splice(Cache.end(), queue, event);
+ if (Cache.size() >= FreeQueueTrimThreshold) {
+ auto& freeQueue = GetPendingEvent()->FreeQueue;
+ auto it = Cache.begin();
+ std::advance(it, Cache.size() - MaxFreeQueueItems);
+ freeQueue.splice(freeQueue.end(), Cache, Cache.begin(), it);
+ trim = true;
+ }
+
+ // release items if we have hit the limit
+ if (trim) {
+ Trim();
+ }
+ }
+
+ void Trim() {
+ if (auto ev = std::move(PendingFreeEvent); ev && ev->GetInLineForDestruction(Common)) {
+ DestroyCallback(std::move(ev));
+ }
+
+ // ensure it is dropped
+ PendingFreeEvent.Reset();
+ }
+
+ private:
+ TEvFreeItems* GetPendingEvent() {
+ if (!PendingFreeEvent) {
+ PendingFreeEvent.Reset(new TEvFreeItems);
+ }
+ return PendingFreeEvent.Get();
+ }
+ };
+
+}
diff --git a/library/cpp/actors/interconnect/events_local.h b/library/cpp/actors/interconnect/events_local.h
new file mode 100644
index 0000000000..8a46ffd535
--- /dev/null
+++ b/library/cpp/actors/interconnect/events_local.h
@@ -0,0 +1,403 @@
+#pragma once
+
+#include <library/cpp/actors/core/events.h>
+#include <library/cpp/actors/core/event_local.h>
+#include <library/cpp/actors/protos/interconnect.pb.h>
+#include <util/generic/deque.h>
+#include <util/network/address.h>
+
+#include "interconnect_stream.h"
+#include "packet.h"
+#include "types.h"
+
+namespace NActors {
+ struct TProgramInfo {
+ ui64 PID = 0;
+ ui64 StartTime = 0;
+ ui64 Serial = 0;
+ };
+
+ enum class ENetwork : ui32 {
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // local messages
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ Start = EventSpaceBegin(TEvents::ES_INTERCONNECT_TCP),
+
+ SocketReadyRead = Start,
+ SocketReadyWrite,
+ SocketError,
+ Connect,
+ Disconnect,
+ IncomingConnection,
+ HandshakeAsk,
+ HandshakeAck,
+ HandshakeNak,
+ HandshakeDone,
+ HandshakeFail,
+ Kick,
+ Flush,
+ NodeInfo,
+ BunchOfEventsToDestroy,
+ HandshakeRequest,
+ HandshakeReplyOK,
+ HandshakeReplyError,
+ ResolveAddress,
+ AddressInfo,
+ ResolveError,
+ HTTPStreamStatus,
+ HTTPSendContent,
+ ConnectProtocolWakeup,
+ HTTPProtocolRetry,
+ EvPollerRegister,
+ EvPollerRegisterResult,
+ EvPollerReady,
+ EvUpdateFromInputSession,
+ EvConfirmUpdate,
+ EvSessionBufferSizeRequest,
+ EvSessionBufferSizeResponse,
+ EvProcessPingRequest,
+ EvGetSecureSocket,
+ EvSecureSocket,
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // nonlocal messages; their indices must be preserved in order to work properly while doing rolling update
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ // interconnect load test message
+ EvLoadMessage = Start + 256,
+ };
+
+ struct TEvSocketReadyRead: public TEventLocal<TEvSocketReadyRead, ui32(ENetwork::SocketReadyRead)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvSocketReadyRead, "Network: TEvSocketReadyRead")
+ };
+
+ struct TEvSocketReadyWrite: public TEventLocal<TEvSocketReadyWrite, ui32(ENetwork::SocketReadyWrite)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvSocketReadyWrite, "Network: TEvSocketReadyWrite")
+ };
+
+ struct TEvSocketError: public TEventLocal<TEvSocketError, ui32(ENetwork::SocketError)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvSocketError, ::strerror(Error))
+ TString GetReason() const {
+ return ::strerror(Error);
+ }
+ const int Error;
+ TIntrusivePtr<NInterconnect::TStreamSocket> Socket;
+
+ TEvSocketError(int error, TIntrusivePtr<NInterconnect::TStreamSocket> sock)
+ : Error(error)
+ , Socket(std::move(sock))
+ {
+ }
+ };
+
+ struct TEvSocketConnect: public TEventLocal<TEvSocketConnect, ui32(ENetwork::Connect)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvSocketConnect, "Network: TEvSocketConnect")
+ };
+
+ struct TEvSocketDisconnect: public TEventLocal<TEvSocketDisconnect, ui32(ENetwork::Disconnect)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvSocketDisconnect, "Network: TEvSocketDisconnect")
+ TDisconnectReason Reason;
+
+ TEvSocketDisconnect(TDisconnectReason reason)
+ : Reason(std::move(reason))
+ {
+ }
+ };
+
+ struct TEvHandshakeAsk: public TEventLocal<TEvHandshakeAsk, ui32(ENetwork::HandshakeAsk)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeAsk, "Network: TEvHandshakeAsk")
+ TEvHandshakeAsk(const TActorId& self,
+ const TActorId& peer,
+ ui64 counter)
+ : Self(self)
+ , Peer(peer)
+ , Counter(counter)
+ {
+ }
+ const TActorId Self;
+ const TActorId Peer;
+ const ui64 Counter;
+ };
+
+ struct TEvHandshakeAck: public TEventLocal<TEvHandshakeAck, ui32(ENetwork::HandshakeAck)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeAck, "Network: TEvHandshakeAck")
+
+ TEvHandshakeAck(const TActorId& self, ui64 nextPacket, TSessionParams params)
+ : Self(self)
+ , NextPacket(nextPacket)
+ , Params(std::move(params))
+ {}
+
+ const TActorId Self;
+ const ui64 NextPacket;
+ const TSessionParams Params;
+ };
+
+ struct TEvHandshakeNak : TEventLocal<TEvHandshakeNak, ui32(ENetwork::HandshakeNak)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvSocketReadyRead, "Network: TEvHandshakeNak")
+ };
+
+ struct TEvHandshakeRequest
+ : public TEventLocal<TEvHandshakeRequest,
+ ui32(ENetwork::HandshakeRequest)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeRequest,
+ "Network: TEvHandshakeRequest")
+
+ NActorsInterconnect::THandshakeRequest Record;
+ };
+
+ struct TEvHandshakeReplyOK
+ : public TEventLocal<TEvHandshakeReplyOK,
+ ui32(ENetwork::HandshakeReplyOK)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeReplyOK,
+ "Network: TEvHandshakeReplyOK")
+
+ NActorsInterconnect::THandshakeReply Record;
+ };
+
+ struct TEvHandshakeReplyError
+ : public TEventLocal<TEvHandshakeReplyError,
+ ui32(ENetwork::HandshakeReplyError)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeReplyError,
+ "Network: TEvHandshakeReplyError")
+
+ TEvHandshakeReplyError(TString error) {
+ Record.SetErrorExplaination(error);
+ }
+
+ NActorsInterconnect::THandshakeReply Record;
+ };
+
+ struct TEvIncomingConnection: public TEventLocal<TEvIncomingConnection, ui32(ENetwork::IncomingConnection)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvIncomingConnection, "Network: TEvIncomingConnection")
+ TIntrusivePtr<NInterconnect::TStreamSocket> Socket;
+ NInterconnect::TAddress Address;
+
+ TEvIncomingConnection(TIntrusivePtr<NInterconnect::TStreamSocket> socket, NInterconnect::TAddress address)
+ : Socket(std::move(socket))
+ , Address(std::move(address))
+ {}
+ };
+
+ struct TEvHandshakeDone: public TEventLocal<TEvHandshakeDone, ui32(ENetwork::HandshakeDone)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeDone, "Network: TEvHandshakeDone")
+
+ TEvHandshakeDone(
+ TIntrusivePtr<NInterconnect::TStreamSocket> socket,
+ const TActorId& peer,
+ const TActorId& self,
+ ui64 nextPacket,
+ TAutoPtr<TProgramInfo>&& programInfo,
+ TSessionParams params)
+ : Socket(std::move(socket))
+ , Peer(peer)
+ , Self(self)
+ , NextPacket(nextPacket)
+ , ProgramInfo(std::move(programInfo))
+ , Params(std::move(params))
+ {
+ }
+
+ TIntrusivePtr<NInterconnect::TStreamSocket> Socket;
+ const TActorId Peer;
+ const TActorId Self;
+ const ui64 NextPacket;
+ TAutoPtr<TProgramInfo> ProgramInfo;
+ const TSessionParams Params;
+ };
+
+ struct TEvHandshakeFail: public TEventLocal<TEvHandshakeFail, ui32(ENetwork::HandshakeFail)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvHandshakeFail, "Network: TEvHandshakeFail")
+
+ enum EnumHandshakeFail {
+ HANDSHAKE_FAIL_TRANSIENT,
+ HANDSHAKE_FAIL_PERMANENT,
+ HANDSHAKE_FAIL_SESSION_MISMATCH,
+ };
+
+ TEvHandshakeFail(EnumHandshakeFail temporary, TString explanation)
+ : Temporary(temporary)
+ , Explanation(std::move(explanation))
+ {
+ }
+
+ const EnumHandshakeFail Temporary;
+ const TString Explanation;
+ };
+
+ struct TEvKick: public TEventLocal<TEvKick, ui32(ENetwork::Kick)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvKick, "Network: TEvKick")
+ };
+
+ struct TEvFlush: public TEventLocal<TEvFlush, ui32(ENetwork::Flush)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvFlush, "Network: TEvFlush")
+ };
+
+ struct TEvLocalNodeInfo
+ : public TEventLocal<TEvLocalNodeInfo, ui32(ENetwork::NodeInfo)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvLocalNodeInfo, "Network: TEvLocalNodeInfo")
+
+ ui32 NodeId;
+ NAddr::IRemoteAddrPtr Address;
+ };
+
+ struct TEvBunchOfEventsToDestroy : TEventLocal<TEvBunchOfEventsToDestroy, ui32(ENetwork::BunchOfEventsToDestroy)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvBunchOfEventsToDestroy,
+ "Network: TEvBunchOfEventsToDestroy")
+
+ TEvBunchOfEventsToDestroy(TDeque<TAutoPtr<IEventBase>> events)
+ : Events(std::move(events))
+ {
+ }
+
+ TDeque<TAutoPtr<IEventBase>> Events;
+ };
+
+ struct TEvResolveAddress
+ : public TEventLocal<TEvResolveAddress, ui32(ENetwork::ResolveAddress)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvResolveAddress, "Network: TEvResolveAddress")
+
+ TString Address;
+ ui16 Port;
+ };
+
+ struct TEvAddressInfo
+ : public TEventLocal<TEvAddressInfo, ui32(ENetwork::AddressInfo)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvAddressInfo, "Network: TEvAddressInfo")
+
+ NAddr::IRemoteAddrPtr Address;
+ };
+
+ struct TEvResolveError
+ : public TEventLocal<TEvResolveError, ui32(ENetwork::ResolveError)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvResolveError, "Network: TEvResolveError")
+
+ TString Explain;
+ };
+
+ struct TEvHTTPStreamStatus
+ : public TEventLocal<TEvHTTPStreamStatus, ui32(ENetwork::HTTPStreamStatus)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvHTTPStreamStatus,
+ "Network: TEvHTTPStreamStatus")
+ enum EStatus {
+ READY,
+ COMPLETE,
+ ERROR,
+ };
+
+ EStatus Status;
+ TString Error;
+ TString HttpHeaders;
+ };
+
+ struct TEvHTTPSendContent
+ : public TEventLocal<TEvHTTPSendContent, ui32(ENetwork::HTTPSendContent)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvHTTPSendContent, "Network: TEvHTTPSendContent")
+
+ const char* Data;
+ size_t Len;
+ bool Last;
+ };
+
+ struct TEvConnectWakeup
+ : public TEventLocal<TEvConnectWakeup,
+ ui32(ENetwork::ConnectProtocolWakeup)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvConnectWakeup, "Protocols: TEvConnectWakeup")
+ };
+
+ struct TEvHTTPProtocolRetry
+ : public TEventLocal<TEvHTTPProtocolRetry,
+ ui32(ENetwork::HTTPProtocolRetry)> {
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvHTTPProtocolRetry,
+ "Protocols: TEvHTTPProtocolRetry")
+ };
+
+ struct TEvLoadMessage
+ : TEventPB<TEvLoadMessage, NActorsInterconnect::TEvLoadMessage, static_cast<ui32>(ENetwork::EvLoadMessage)> {
+ TEvLoadMessage() = default;
+
+ template <typename TContainer>
+ TEvLoadMessage(const TContainer& route, const TString& id, const TString* payload) {
+ for (const TActorId& actorId : route) {
+ auto* hop = Record.AddHops();
+ if (actorId) {
+ ActorIdToProto(actorId, hop->MutableNextHop());
+ }
+ }
+ Record.SetId(id);
+ if (payload) {
+ Record.SetPayload(*payload);
+ }
+ }
+
+ template <typename TContainer>
+ TEvLoadMessage(const TContainer& route, const TString& id, TRope&& payload) {
+ for (const TActorId& actorId : route) {
+ auto* hop = Record.AddHops();
+ if (actorId) {
+ ActorIdToProto(actorId, hop->MutableNextHop());
+ }
+ }
+ Record.SetId(id);
+ AddPayload(std::move(payload));
+ }
+ };
+
+ struct TEvUpdateFromInputSession : TEventLocal<TEvUpdateFromInputSession, static_cast<ui32>(ENetwork::EvUpdateFromInputSession)> {
+ ui64 ConfirmedByInput; // latest Confirm value from processed input packet
+ ui64 NumDataBytes;
+ TDuration Ping;
+
+ TEvUpdateFromInputSession(ui64 confirmedByInput, ui64 numDataBytes, TDuration ping)
+ : ConfirmedByInput(confirmedByInput)
+ , NumDataBytes(numDataBytes)
+ , Ping(ping)
+ {
+ }
+ };
+
+ struct TEvConfirmUpdate : TEventLocal<TEvConfirmUpdate, static_cast<ui32>(ENetwork::EvConfirmUpdate)>
+ {};
+
+ struct TEvSessionBufferSizeRequest : TEventLocal<TEvSessionBufferSizeRequest, static_cast<ui32>(ENetwork::EvSessionBufferSizeRequest)> {
+ //DEFINE_SIMPLE_LOCAL_EVENT(TEvSessionBufferSizeRequest, "Session: TEvSessionBufferSizeRequest")
+ DEFINE_SIMPLE_LOCAL_EVENT(TEvSessionBufferSizeRequest, "Network: TEvSessionBufferSizeRequest");
+ };
+
+ struct TEvSessionBufferSizeResponse : TEventLocal<TEvSessionBufferSizeResponse, static_cast<ui32>(ENetwork::EvSessionBufferSizeResponse)> {
+ TEvSessionBufferSizeResponse(const TActorId& sessionId, ui64 outputBufferSize)
+ : SessionID(sessionId)
+ , BufferSize(outputBufferSize)
+ {
+ }
+
+ TActorId SessionID;
+ ui64 BufferSize;
+ };
+
+ struct TEvProcessPingRequest : TEventLocal<TEvProcessPingRequest, static_cast<ui32>(ENetwork::EvProcessPingRequest)> {
+ const ui64 Payload;
+
+ TEvProcessPingRequest(ui64 payload)
+ : Payload(payload)
+ {}
+ };
+
+ struct TEvGetSecureSocket : TEventLocal<TEvGetSecureSocket, (ui32)ENetwork::EvGetSecureSocket> {
+ TIntrusivePtr<NInterconnect::TStreamSocket> Socket;
+
+ TEvGetSecureSocket(TIntrusivePtr<NInterconnect::TStreamSocket> socket)
+ : Socket(std::move(socket))
+ {}
+ };
+
+ struct TEvSecureSocket : TEventLocal<TEvSecureSocket, (ui32)ENetwork::EvSecureSocket> {
+ TIntrusivePtr<NInterconnect::TSecureSocket> Socket;
+
+ TEvSecureSocket(TIntrusivePtr<NInterconnect::TSecureSocket> socket)
+ : Socket(std::move(socket))
+ {}
+ };
+
+}
diff --git a/library/cpp/actors/interconnect/interconnect.h b/library/cpp/actors/interconnect/interconnect.h
new file mode 100644
index 0000000000..225a5243fd
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect.h
@@ -0,0 +1,179 @@
+#pragma once
+
+#include <library/cpp/actors/core/actorsystem.h>
+#include <library/cpp/actors/core/interconnect.h>
+#include <util/generic/map.h>
+#include <util/network/address.h>
+
+namespace NActors {
+ struct TInterconnectGlobalState: public TThrRefBase {
+ TString SelfAddress;
+ ui32 SelfPort;
+
+ TVector<TActorId> GlobalNameservers; // todo: add some info about (like expected reply time)
+ };
+
+ struct TInterconnectProxySetup: public TThrRefBase {
+ // synchronous (session -> proxy)
+ struct IProxy : TNonCopyable {
+ virtual ~IProxy() {
+ }
+
+ virtual void ActivateSession(const TActorContext& ctx) = 0; // session activated
+ virtual void DetachSession(const TActorContext& ctx) = 0; // session is dead
+ };
+
+ // synchronous (proxy -> session)
+ struct ISession : TNonCopyable {
+ virtual ~ISession() {
+ }
+
+ virtual void DetachSession(const TActorContext& ownerCtx, const TActorContext& sessionCtx) = 0; // kill yourself
+ virtual void ForwardPacket(TAutoPtr<IEventHandle>& ev, const TActorContext& ownerCtx, const TActorContext& sessionCtx) = 0; // receive packet for forward
+ virtual void Connect(const TActorContext& ownerCtx, const TActorContext& sessionCtx) = 0; // begin connection
+ virtual bool ReceiveIncomingSession(TAutoPtr<IEventHandle>& ev, const TActorContext& ownerCtx, const TActorContext& sessionCtx) = 0; // handle incoming session, if returns true - then session is dead and must be recreated with new one
+ };
+
+ ui32 DestinationNode;
+
+ TString StaticAddress; // if set - would be used as main destination address
+ int StaticPort;
+
+ TIntrusivePtr<TInterconnectGlobalState> GlobalState;
+
+ virtual IActor* CreateSession(const TActorId& ownerId, IProxy* owner) = 0; // returned actor is session and would be attached to same mailbox as proxy to allow sync calls
+ virtual TActorSetupCmd CreateAcceptor() = 0;
+ };
+
+ struct TNameserverSetup {
+ TActorId ServiceID;
+
+ TIntrusivePtr<TInterconnectGlobalState> GlobalState;
+ };
+
+ struct TTableNameserverSetup: public TThrRefBase {
+ struct TNodeInfo {
+ TString Address;
+ TString Host;
+ TString ResolveHost;
+ ui16 Port;
+ TNodeLocation Location;
+ TString& first;
+ ui16& second;
+
+ TNodeInfo()
+ : first(Address)
+ , second(Port)
+ {
+ }
+
+ TNodeInfo(const TNodeInfo&) = default;
+
+ // for testing purposes only
+ TNodeInfo(const TString& address, const TString& host, ui16 port)
+ : TNodeInfo()
+ {
+ Address = address;
+ Host = host;
+ ResolveHost = host;
+ Port = port;
+ }
+
+ TNodeInfo(const TString& address,
+ const TString& host,
+ const TString& resolveHost,
+ ui16 port,
+ const TNodeLocation& location)
+ : TNodeInfo()
+ {
+ Address = address;
+ Host = host;
+ ResolveHost = resolveHost;
+ Port = port;
+ Location = location;
+ }
+
+ // for testing purposes only
+ TNodeInfo& operator=(const std::pair<TString, ui32>& pr) {
+ Address = pr.first;
+ Host = pr.first;
+ ResolveHost = pr.first;
+ Port = pr.second;
+ return *this;
+ }
+
+ TNodeInfo& operator=(const TNodeInfo& ni) {
+ Address = ni.Address;
+ Host = ni.Host;
+ ResolveHost = ni.ResolveHost;
+ Port = ni.Port;
+ Location = ni.Location;
+ return *this;
+ }
+ };
+
+ TMap<ui32, TNodeInfo> StaticNodeTable;
+
+ bool IsEntriesUnique() const;
+ };
+
+ struct TNodeRegistrarSetup {
+ TActorId ServiceID;
+
+ TIntrusivePtr<TInterconnectGlobalState> GlobalState;
+ };
+
+ TActorId GetNameserviceActorId();
+
+ /**
+ * Const table-lookup based name service
+ */
+
+ IActor* CreateNameserverTable(
+ const TIntrusivePtr<TTableNameserverSetup>& setup,
+ ui32 poolId = 0);
+
+ /**
+ * Name service which can be paired with external discovery service.
+ * Copies information from setup on the start (table may be empty).
+ * Handles TEvNodesInfo to change list of known nodes.
+ *
+ * If PendingPeriod is not zero, wait for unknown nodeId
+ */
+
+ IActor* CreateDynamicNameserver(
+ const TIntrusivePtr<TTableNameserverSetup>& setup,
+ const TDuration& pendingPeriod = TDuration::Zero(),
+ ui32 poolId = 0);
+
+ /**
+ * Creates an actor that resolves host/port and replies with either:
+ *
+ * - TEvLocalNodeInfo on success
+ * - TEvResolveError on errors
+ *
+ * Optional defaultAddress may be used as fallback.
+ */
+ IActor* CreateResolveActor(
+ const TString& host, ui16 port, ui32 nodeId, const TString& defaultAddress,
+ const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline);
+
+ inline IActor* CreateResolveActor(
+ ui32 nodeId, const TTableNameserverSetup::TNodeInfo& nodeInfo,
+ const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
+ {
+ return CreateResolveActor(nodeInfo.ResolveHost, nodeInfo.Port, nodeId, nodeInfo.Address,
+ replyTo, replyFrom, deadline);
+ }
+
+ /**
+ * Creates an actor that resolves host/port and replies with either:
+ *
+ * - TEvAddressInfo on success
+ * - TEvResolveError on errors
+ */
+ IActor* CreateResolveActor(
+ const TString& host, ui16 port,
+ const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline);
+
+}
diff --git a/library/cpp/actors/interconnect/interconnect_address.cpp b/library/cpp/actors/interconnect/interconnect_address.cpp
new file mode 100644
index 0000000000..8f474f5a39
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_address.cpp
@@ -0,0 +1,94 @@
+#include "interconnect_address.h"
+
+#include <util/string/cast.h>
+#include <util/system/file.h>
+
+#if defined(_linux_)
+#include <sys/un.h>
+#include <sys/stat.h>
+#endif
+
+namespace NInterconnect {
+ TAddress::TAddress() {
+ memset(&Addr, 0, sizeof(Addr));
+ }
+
+ TAddress::TAddress(NAddr::IRemoteAddr& addr) {
+ socklen_t len = addr.Len();
+ Y_VERIFY(len <= sizeof(Addr));
+ memcpy(&Addr.Generic, addr.Addr(), len);
+ }
+
+ int TAddress::GetFamily() const {
+ return Addr.Generic.sa_family;
+ }
+
+ socklen_t TAddress::Size() const {
+ switch (Addr.Generic.sa_family) {
+ case AF_INET6:
+ return sizeof(sockaddr_in6);
+ case AF_INET:
+ return sizeof(sockaddr_in);
+ default:
+ return 0;
+ }
+ }
+
+ sockaddr* TAddress::SockAddr() {
+ return &Addr.Generic;
+ }
+
+ const sockaddr* TAddress::SockAddr() const {
+ return &Addr.Generic;
+ }
+
+ ui16 TAddress::GetPort() const {
+ switch (Addr.Generic.sa_family) {
+ case AF_INET6:
+ return ntohs(Addr.Ipv6.sin6_port);
+ case AF_INET:
+ return ntohs(Addr.Ipv4.sin_port);
+ default:
+ return 0;
+ }
+ }
+
+ TString TAddress::ToString() const {
+ return GetAddress() + ":" + ::ToString(GetPort());
+ }
+
+ TAddress::TAddress(const char* addr, ui16 port) {
+ memset(&Addr, 0, sizeof(Addr));
+ if (inet_pton(Addr.Ipv6.sin6_family = AF_INET6, addr, &Addr.Ipv6.sin6_addr)) {
+ Addr.Ipv6.sin6_port = htons(port);
+ } else if (inet_pton(Addr.Ipv4.sin_family = AF_INET, addr, &Addr.Ipv4.sin_addr)) {
+ Addr.Ipv4.sin_port = htons(port);
+ }
+ }
+
+ TAddress::TAddress(const TString& addr, ui16 port)
+ : TAddress(addr.data(), port)
+ {}
+
+ TString TAddress::GetAddress() const {
+ const void *src;
+ socklen_t size;
+
+ switch (Addr.Generic.sa_family) {
+ case AF_INET6:
+ std::tie(src, size) = std::make_tuple(&Addr.Ipv6.sin6_addr, INET6_ADDRSTRLEN);
+ break;
+
+ case AF_INET:
+ std::tie(src, size) = std::make_tuple(&Addr.Ipv4.sin_addr, INET_ADDRSTRLEN);
+ break;
+
+ default:
+ return TString();
+ }
+
+ char *buffer = static_cast<char*>(alloca(size));
+ const char *p = inet_ntop(Addr.Generic.sa_family, const_cast<void*>(src), buffer, size);
+ return p ? TString(p) : TString();
+ }
+}
diff --git a/library/cpp/actors/interconnect/interconnect_address.h b/library/cpp/actors/interconnect/interconnect_address.h
new file mode 100644
index 0000000000..e9e0faec81
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_address.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <util/system/defaults.h>
+#include <util/network/init.h>
+#include <util/network/address.h>
+#include <util/generic/string.h>
+
+namespace NInterconnect {
+ class TAddress {
+ union {
+ sockaddr Generic;
+ sockaddr_in Ipv4;
+ sockaddr_in6 Ipv6;
+ } Addr;
+
+ public:
+ TAddress();
+ TAddress(const char* addr, ui16 port);
+ TAddress(const TString& addr, ui16 port);
+ TAddress(NAddr::IRemoteAddr& addr);
+ int GetFamily() const;
+ socklen_t Size() const;
+ ::sockaddr* SockAddr();
+ const ::sockaddr* SockAddr() const;
+ ui16 GetPort() const;
+ TString GetAddress() const;
+ TString ToString() const;
+ };
+}
diff --git a/library/cpp/actors/interconnect/interconnect_channel.cpp b/library/cpp/actors/interconnect/interconnect_channel.cpp
new file mode 100644
index 0000000000..a66ba2a154
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_channel.cpp
@@ -0,0 +1,176 @@
+#include "interconnect_channel.h"
+
+#include <library/cpp/actors/core/events.h>
+#include <library/cpp/actors/core/executor_thread.h>
+#include <library/cpp/actors/core/log.h>
+#include <library/cpp/actors/core/probes.h>
+#include <library/cpp/actors/protos/services_common.pb.h>
+#include <library/cpp/actors/prof/tag.h>
+#include <library/cpp/digest/crc32c/crc32c.h>
+
+LWTRACE_USING(ACTORLIB_PROVIDER);
+
+namespace NActors {
+ DECLARE_WILSON_EVENT(EventSentToSocket);
+ DECLARE_WILSON_EVENT(EventReceivedFromSocket);
+
+ bool TEventOutputChannel::FeedDescriptor(TTcpPacketOutTask& task, TEventHolder& event, ui64 *weightConsumed) {
+ const size_t amount = sizeof(TChannelPart) + sizeof(TEventDescr);
+ if (task.GetVirtualFreeAmount() < amount) {
+ return false;
+ }
+
+ NWilson::TTraceId traceId(event.Descr.TraceId);
+// if (ctx) {
+// WILSON_TRACE(*ctx, &traceId, EventSentToSocket);
+// }
+ traceId.Serialize(&event.Descr.TraceId);
+ LWTRACK(SerializeToPacketEnd, event.Orbit, PeerNodeId, ChannelId, OutputQueueSize, task.GetDataSize());
+ task.Orbit.Take(event.Orbit);
+
+ event.Descr.Flags = (event.Descr.Flags & ~IEventHandle::FlagForwardOnNondelivery) |
+ (ExtendedFormat ? IEventHandle::FlagExtendedFormat : 0);
+
+ TChannelPart *part = static_cast<TChannelPart*>(task.GetFreeArea());
+ part->Channel = ChannelId | TChannelPart::LastPartFlag;
+ part->Size = sizeof(TEventDescr);
+ memcpy(part + 1, &event.Descr, sizeof(TEventDescr));
+ task.AppendBuf(part, amount);
+ *weightConsumed += amount;
+ OutputQueueSize -= part->Size;
+ Metrics->UpdateOutputChannelEvents(ChannelId);
+
+ return true;
+ }
+
+ void TEventOutputChannel::DropConfirmed(ui64 confirm) {
+ LOG_DEBUG_IC_SESSION("ICOCH98", "Dropping confirmed messages");
+ for (auto it = NotYetConfirmed.begin(); it != NotYetConfirmed.end() && it->Serial <= confirm; ) {
+ Pool.Release(NotYetConfirmed, it++);
+ }
+ }
+
+ bool TEventOutputChannel::FeedBuf(TTcpPacketOutTask& task, ui64 serial, ui64 *weightConsumed) {
+ for (;;) {
+ Y_VERIFY(!Queue.empty());
+ TEventHolder& event = Queue.front();
+
+ switch (State) {
+ case EState::INITIAL:
+ event.InitChecksum();
+ LWTRACK(SerializeToPacketBegin, event.Orbit, PeerNodeId, ChannelId, OutputQueueSize);
+ if (event.Event) {
+ State = EState::CHUNKER;
+ IEventBase *base = event.Event.Get();
+ Chunker.SetSerializingEvent(base);
+ ExtendedFormat = base->IsExtendedFormat();
+ } else if (event.Buffer) {
+ State = EState::BUFFER;
+ Iter = event.Buffer->GetBeginIter();
+ ExtendedFormat = event.Buffer->IsExtendedFormat();
+ } else {
+ State = EState::DESCRIPTOR;
+ ExtendedFormat = false;
+ }
+ break;
+
+ case EState::CHUNKER:
+ case EState::BUFFER: {
+ size_t maxBytes = task.GetVirtualFreeAmount();
+ if (maxBytes <= sizeof(TChannelPart)) {
+ return false;
+ }
+
+ TChannelPart *part = static_cast<TChannelPart*>(task.GetFreeArea());
+ part->Channel = ChannelId;
+ part->Size = 0;
+ task.AppendBuf(part, sizeof(TChannelPart));
+ maxBytes -= sizeof(TChannelPart);
+ Y_VERIFY(maxBytes);
+
+ auto addChunk = [&](const void *data, size_t len) {
+ event.UpdateChecksum(Params, data, len);
+ task.AppendBuf(data, len);
+ part->Size += len;
+ Y_VERIFY_DEBUG(maxBytes >= len);
+ maxBytes -= len;
+
+ event.EventActuallySerialized += len;
+ if (event.EventActuallySerialized > MaxSerializedEventSize) {
+ throw TExSerializedEventTooLarge(event.Descr.Type);
+ }
+ };
+
+ bool complete = false;
+ if (State == EState::CHUNKER) {
+ Y_VERIFY_DEBUG(task.GetFreeArea() == part + 1);
+ while (!complete && maxBytes) {
+ const auto [first, last] = Chunker.FeedBuf(task.GetFreeArea(), maxBytes);
+ for (auto p = first; p != last; ++p) {
+ addChunk(p->first, p->second);
+ }
+ complete = Chunker.IsComplete();
+ }
+ Y_VERIFY(!complete || Chunker.IsSuccessfull());
+ Y_VERIFY_DEBUG(complete || !maxBytes);
+ } else { // BUFFER
+ while (const size_t numb = Min(maxBytes, Iter.ContiguousSize())) {
+ const char *obuf = Iter.ContiguousData();
+ addChunk(obuf, numb);
+ Iter += numb;
+ }
+ complete = !Iter.Valid();
+ }
+ if (complete) {
+ Y_VERIFY(event.EventActuallySerialized == event.EventSerializedSize,
+ "EventActuallySerialized# %" PRIu32 " EventSerializedSize# %" PRIu32 " Type# 0x%08" PRIx32,
+ event.EventActuallySerialized, event.EventSerializedSize, event.Descr.Type);
+ }
+
+ if (!part->Size) {
+ task.Undo(sizeof(TChannelPart));
+ } else {
+ *weightConsumed += sizeof(TChannelPart) + part->Size;
+ OutputQueueSize -= part->Size;
+ }
+ if (complete) {
+ State = EState::DESCRIPTOR;
+ }
+ break;
+ }
+
+ case EState::DESCRIPTOR:
+ if (!FeedDescriptor(task, event, weightConsumed)) {
+ return false;
+ }
+ event.Serial = serial;
+ NotYetConfirmed.splice(NotYetConfirmed.end(), Queue, Queue.begin()); // move event to not-yet-confirmed queue
+ State = EState::INITIAL;
+ return true; // we have processed whole event, signal to the caller
+ }
+ }
+ }
+
+ void TEventOutputChannel::NotifyUndelivered() {
+ LOG_DEBUG_IC_SESSION("ICOCH89", "Notyfying about Undelivered messages! NotYetConfirmed size: %zu, Queue size: %zu", NotYetConfirmed.size(), Queue.size());
+ if (State == EState::CHUNKER) {
+ Y_VERIFY(!Chunker.IsComplete()); // chunk must have an event being serialized
+ Y_VERIFY(!Queue.empty()); // this event must be the first event in queue
+ TEventHolder& event = Queue.front();
+ Y_VERIFY(Chunker.GetCurrentEvent() == event.Event.Get()); // ensure the event is valid
+ Chunker.Abort(); // stop serializing current event
+ Y_VERIFY(Chunker.IsComplete());
+ }
+ for (auto& item : NotYetConfirmed) {
+ if (item.Descr.Flags & IEventHandle::FlagGenerateUnsureUndelivered) { // notify only when unsure flag is set
+ item.ForwardOnNondelivery(true);
+ }
+ }
+ Pool.Release(NotYetConfirmed);
+ for (auto& item : Queue) {
+ item.ForwardOnNondelivery(false);
+ }
+ Pool.Release(Queue);
+ }
+
+}
diff --git a/library/cpp/actors/interconnect/interconnect_channel.h b/library/cpp/actors/interconnect/interconnect_channel.h
new file mode 100644
index 0000000000..e4a0ae3cda
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_channel.h
@@ -0,0 +1,127 @@
+#pragma once
+
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+#include <library/cpp/actors/core/actorsystem.h>
+#include <library/cpp/actors/core/event_load.h>
+#include <library/cpp/actors/util/rope.h>
+#include <util/generic/deque.h>
+#include <util/generic/vector.h>
+#include <util/generic/map.h>
+#include <util/stream/walk.h>
+#include <library/cpp/actors/wilson/wilson_event.h>
+#include <library/cpp/actors/helpers/mon_histogram_helper.h>
+
+#include "interconnect_common.h"
+#include "interconnect_counters.h"
+#include "packet.h"
+#include "event_holder_pool.h"
+
+namespace NActors {
+#pragma pack(push, 1)
+ struct TChannelPart {
+ ui16 Channel;
+ ui16 Size;
+
+ static constexpr ui16 LastPartFlag = ui16(1) << 15;
+
+ TString ToString() const {
+ return TStringBuilder() << "{Channel# " << (Channel & ~LastPartFlag)
+ << " LastPartFlag# " << ((Channel & LastPartFlag) ? "true" : "false")
+ << " Size# " << Size << "}";
+ }
+ };
+#pragma pack(pop)
+
+ struct TExSerializedEventTooLarge : std::exception {
+ const ui32 Type;
+
+ TExSerializedEventTooLarge(ui32 type)
+ : Type(type)
+ {}
+ };
+
+ class TEventOutputChannel : public TInterconnectLoggingBase {
+ public:
+ TEventOutputChannel(TEventHolderPool& pool, ui16 id, ui32 peerNodeId, ui32 maxSerializedEventSize,
+ std::shared_ptr<IInterconnectMetrics> metrics, TSessionParams params)
+ : TInterconnectLoggingBase(Sprintf("OutputChannel %" PRIu16 " [node %" PRIu32 "]", id, peerNodeId))
+ , Pool(pool)
+ , PeerNodeId(peerNodeId)
+ , ChannelId(id)
+ , Metrics(std::move(metrics))
+ , Params(std::move(params))
+ , MaxSerializedEventSize(maxSerializedEventSize)
+ {}
+
+ ~TEventOutputChannel() {
+ }
+
+ std::pair<ui32, TEventHolder*> Push(IEventHandle& ev) {
+ TEventHolder& event = Pool.Allocate(Queue);
+ const ui32 bytes = event.Fill(ev) + sizeof(TEventDescr);
+ OutputQueueSize += bytes;
+ return std::make_pair(bytes, &event);
+ }
+
+ void DropConfirmed(ui64 confirm);
+
+ bool FeedBuf(TTcpPacketOutTask& task, ui64 serial, ui64 *weightConsumed);
+
+ bool IsEmpty() const {
+ return Queue.empty();
+ }
+
+ bool IsWorking() const {
+ return !IsEmpty();
+ }
+
+ ui32 GetQueueSize() const {
+ return (ui32)Queue.size();
+ }
+
+ ui64 GetBufferedAmountOfData() const {
+ return OutputQueueSize;
+ }
+
+ void NotifyUndelivered();
+
+ TEventHolderPool& Pool;
+ const ui32 PeerNodeId;
+ const ui16 ChannelId;
+ std::shared_ptr<IInterconnectMetrics> Metrics;
+ const TSessionParams Params;
+ const ui32 MaxSerializedEventSize;
+ ui64 UnaccountedTraffic = 0;
+ ui64 EqualizeCounterOnPause = 0;
+ ui64 WeightConsumedOnPause = 0;
+
+ enum class EState {
+ INITIAL,
+ CHUNKER,
+ BUFFER,
+ DESCRIPTOR,
+ };
+ EState State = EState::INITIAL;
+
+ static constexpr ui16 MinimumFreeSpace = sizeof(TChannelPart) + sizeof(TEventDescr);
+
+ protected:
+ ui64 OutputQueueSize = 0;
+
+ std::list<TEventHolder> Queue;
+ std::list<TEventHolder> NotYetConfirmed;
+ TRope::TConstIterator Iter;
+ TCoroutineChunkSerializer Chunker;
+ bool ExtendedFormat = false;
+
+ bool FeedDescriptor(TTcpPacketOutTask& task, TEventHolder& event, ui64 *weightConsumed);
+
+ void AccountTraffic() {
+ if (const ui64 amount = std::exchange(UnaccountedTraffic, 0)) {
+ Metrics->UpdateOutputChannelTraffic(ChannelId, amount);
+ }
+ }
+
+ friend class TInterconnectSessionTCP;
+ };
+}
diff --git a/library/cpp/actors/interconnect/interconnect_common.h b/library/cpp/actors/interconnect/interconnect_common.h
new file mode 100644
index 0000000000..285709a00c
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_common.h
@@ -0,0 +1,106 @@
+#pragma once
+
+#include <library/cpp/actors/core/actorid.h>
+#include <library/cpp/actors/core/actorsystem.h>
+#include <library/cpp/actors/util/datetime.h>
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+#include <library/cpp/monlib/metrics/metric_registry.h>
+#include <util/generic/map.h>
+#include <util/generic/set.h>
+#include <util/system/datetime.h>
+
+#include "poller_tcp.h"
+#include "logging.h"
+#include "event_filter.h"
+
+#include <atomic>
+
+namespace NActors {
+ enum class EEncryptionMode {
+ DISABLED, // no encryption is required at all
+ OPTIONAL, // encryption is enabled when supported by both peers
+ REQUIRED, // encryption is mandatory
+ };
+
+ struct TInterconnectSettings {
+ TDuration Handshake;
+ TDuration DeadPeer;
+ TDuration CloseOnIdle;
+ ui32 SendBufferDieLimitInMB = 0;
+ ui64 OutputBuffersTotalSizeLimitInMB = 0;
+ ui32 TotalInflightAmountOfData = 0;
+ bool MergePerPeerCounters = false;
+ bool MergePerDataCenterCounters = false;
+ ui32 TCPSocketBufferSize = 0;
+ TDuration PingPeriod = TDuration::Seconds(3);
+ TDuration ForceConfirmPeriod = TDuration::Seconds(1);
+ TDuration LostConnection;
+ TDuration BatchPeriod;
+ bool BindOnAllAddresses = true;
+ EEncryptionMode EncryptionMode = EEncryptionMode::DISABLED;
+ bool TlsAuthOnly = false;
+ TString Certificate; // certificate data in PEM format
+ TString PrivateKey; // private key for the certificate in PEM format
+ TString CaFilePath; // path to certificate authority file
+ TString CipherList; // encryption algorithms
+ TDuration MessagePendingTimeout = TDuration::Seconds(1); // timeout for which messages are queued while in PendingConnection state
+ ui64 MessagePendingSize = Max<ui64>(); // size of the queue
+ ui32 MaxSerializedEventSize = NActors::EventMaxByteSize;
+
+ ui32 GetSendBufferSize() const {
+ ui32 res = 512 * 1024; // 512 kb is the default value for send buffer
+ if (TCPSocketBufferSize) {
+ res = TCPSocketBufferSize;
+ }
+ return res;
+ }
+ };
+
+ struct TChannelSettings {
+ ui16 Weight;
+ };
+
+ typedef TMap<ui16, TChannelSettings> TChannelsConfig;
+
+ using TRegisterMonPageCallback = std::function<void(const TString& path, const TString& title,
+ TActorSystem* actorSystem, const TActorId& actorId)>;
+
+ using TInitWhiteboardCallback = std::function<void(ui16 icPort, TActorSystem* actorSystem)>;
+
+ using TUpdateWhiteboardCallback = std::function<void(const TString& peer, bool connected, bool green, bool yellow,
+ bool orange, bool red, TActorSystem* actorSystem)>;
+
+ struct TInterconnectProxyCommon : TAtomicRefCount<TInterconnectProxyCommon> {
+ TActorId NameserviceId;
+ NMonitoring::TDynamicCounterPtr MonCounters;
+ std::shared_ptr<NMonitoring::IMetricRegistry> Metrics;
+ TChannelsConfig ChannelsConfig;
+ TInterconnectSettings Settings;
+ TRegisterMonPageCallback RegisterMonPage;
+ TActorId DestructorId;
+ std::shared_ptr<std::atomic<TAtomicBase>> DestructorQueueSize;
+ TAtomicBase MaxDestructorQueueSize = 1024 * 1024 * 1024;
+ TString ClusterUUID;
+ TVector<TString> AcceptUUID;
+ ui64 StartTime = GetCycleCountFast();
+ TString TechnicalSelfHostName;
+ TInitWhiteboardCallback InitWhiteboard;
+ TUpdateWhiteboardCallback UpdateWhiteboard;
+ ui32 HandshakeBallastSize = 0;
+ TAtomic StartedSessionKiller = 0;
+ TScopeId LocalScopeId;
+ std::shared_ptr<TEventFilter> EventFilter;
+ TString Cookie; // unique random identifier of a node instance (generated randomly at every start)
+ std::unordered_map<ui16, TString> ChannelName;
+
+ struct TVersionInfo {
+ TString Tag; // version tag for this node
+ TSet<TString> AcceptedTags; // we accept all enlisted version tags of peer nodes, but no others; empty = accept all
+ };
+
+ TMaybe<TVersionInfo> VersionInfo;
+
+ using TPtr = TIntrusivePtr<TInterconnectProxyCommon>;
+ };
+
+}
diff --git a/library/cpp/actors/interconnect/interconnect_counters.cpp b/library/cpp/actors/interconnect/interconnect_counters.cpp
new file mode 100644
index 0000000000..ba674f664b
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_counters.cpp
@@ -0,0 +1,692 @@
+#include "interconnect_counters.h"
+
+#include <library/cpp/monlib/metrics/metric_registry.h>
+#include <library/cpp/monlib/metrics/metric_sub_registry.h>
+
+#include <unordered_map>
+
+namespace NActors {
+
+namespace {
+
+ class TInterconnectCounters: public IInterconnectMetrics {
+ public:
+ struct TOutputChannel {
+ NMonitoring::TDynamicCounters::TCounterPtr Traffic;
+ NMonitoring::TDynamicCounters::TCounterPtr Events;
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingTraffic;
+ NMonitoring::TDynamicCounters::TCounterPtr OutgoingEvents;
+
+ TOutputChannel() = default;
+
+ TOutputChannel(const TIntrusivePtr<NMonitoring::TDynamicCounters>& counters,
+ NMonitoring::TDynamicCounters::TCounterPtr traffic,
+ NMonitoring::TDynamicCounters::TCounterPtr events)
+ : Traffic(std::move(traffic))
+ , Events(std::move(events))
+ , OutgoingTraffic(counters->GetCounter("OutgoingTraffic", true))
+ , OutgoingEvents(counters->GetCounter("OutgoingEvents", true))
+ {}
+
+ TOutputChannel(const TOutputChannel&) = default;
+ };
+
+ struct TInputChannel {
+ NMonitoring::TDynamicCounters::TCounterPtr Traffic;
+ NMonitoring::TDynamicCounters::TCounterPtr Events;
+ NMonitoring::TDynamicCounters::TCounterPtr ScopeErrors;
+ NMonitoring::TDynamicCounters::TCounterPtr IncomingTraffic;
+ NMonitoring::TDynamicCounters::TCounterPtr IncomingEvents;
+
+ TInputChannel() = default;
+
+ TInputChannel(const TIntrusivePtr<NMonitoring::TDynamicCounters>& counters,
+ NMonitoring::TDynamicCounters::TCounterPtr traffic,
+ NMonitoring::TDynamicCounters::TCounterPtr events,
+ NMonitoring::TDynamicCounters::TCounterPtr scopeErrors)
+ : Traffic(std::move(traffic))
+ , Events(std::move(events))
+ , ScopeErrors(std::move(scopeErrors))
+ , IncomingTraffic(counters->GetCounter("IncomingTraffic", true))
+ , IncomingEvents(counters->GetCounter("IncomingEvents", true))
+ {}
+
+ TInputChannel(const TInputChannel&) = default;
+ };
+
+ struct TInputChannels : std::unordered_map<ui16, TInputChannel> {
+ TInputChannel OtherInputChannel;
+
+ TInputChannels() = default;
+
+ TInputChannels(const TIntrusivePtr<NMonitoring::TDynamicCounters>& counters,
+ const std::unordered_map<ui16, TString>& names,
+ NMonitoring::TDynamicCounters::TCounterPtr traffic,
+ NMonitoring::TDynamicCounters::TCounterPtr events,
+ NMonitoring::TDynamicCounters::TCounterPtr scopeErrors)
+ : OtherInputChannel(counters->GetSubgroup("channel", "other"), traffic, events, scopeErrors)
+ {
+ for (const auto& [id, name] : names) {
+ try_emplace(id, counters->GetSubgroup("channel", name), traffic, events, scopeErrors);
+ }
+ }
+
+ TInputChannels(const TInputChannels&) = default;
+
+ const TInputChannel& Get(ui16 id) const {
+ const auto it = find(id);
+ return it != end() ? it->second : OtherInputChannel;
+ }
+ };
+
+ private:
+ const TInterconnectProxyCommon::TPtr Common;
+ const bool MergePerDataCenterCounters;
+ const bool MergePerPeerCounters;
+ NMonitoring::TDynamicCounterPtr Counters;
+ NMonitoring::TDynamicCounterPtr PerSessionCounters;
+ NMonitoring::TDynamicCounterPtr PerDataCenterCounters;
+ NMonitoring::TDynamicCounterPtr& AdaptiveCounters;
+
+ bool Initialized = false;
+
+ NMonitoring::TDynamicCounters::TCounterPtr Traffic;
+ NMonitoring::TDynamicCounters::TCounterPtr Events;
+ NMonitoring::TDynamicCounters::TCounterPtr ScopeErrors;
+
+ public:
+ TInterconnectCounters(const TInterconnectProxyCommon::TPtr& common)
+ : Common(common)
+ , MergePerDataCenterCounters(common->Settings.MergePerDataCenterCounters)
+ , MergePerPeerCounters(common->Settings.MergePerPeerCounters)
+ , Counters(common->MonCounters)
+ , AdaptiveCounters(MergePerDataCenterCounters
+ ? PerDataCenterCounters :
+ MergePerPeerCounters ? Counters : PerSessionCounters)
+ {}
+
+ void AddInflightDataAmount(ui64 value) override {
+ *InflightDataAmount += value;
+ }
+
+ void SubInflightDataAmount(ui64 value) override {
+ *InflightDataAmount -= value;
+ }
+
+ void AddTotalBytesWritten(ui64 value) override {
+ *TotalBytesWritten += value;
+ }
+
+ void SetClockSkewMicrosec(i64 value) override {
+ *ClockSkewMicrosec = value;
+ }
+
+ void IncSessionDeaths() override {
+ ++*SessionDeaths;
+ }
+
+ void IncHandshakeFails() override {
+ ++*HandshakeFails;
+ }
+
+ void SetConnected(ui32 value) override {
+ *Connected = value;
+ }
+
+ void IncSubscribersCount() override {
+ ++*SubscribersCount;
+ }
+
+ void SubSubscribersCount(ui32 value) override {
+ *SubscribersCount -= value;
+ }
+
+ void SubOutputBuffersTotalSize(ui64 value) override {
+ *OutputBuffersTotalSize -= value;
+ }
+
+ void AddOutputBuffersTotalSize(ui64 value) override {
+ *OutputBuffersTotalSize += value;
+ }
+
+ ui64 GetOutputBuffersTotalSize() const override {
+ return *OutputBuffersTotalSize;
+ }
+
+ void IncDisconnections() override {
+ ++*Disconnections;
+ }
+
+ void IncUsefulWriteWakeups() override {
+ ++*UsefulWriteWakeups;
+ }
+
+ void IncSpuriousWriteWakeups() override {
+ ++*SpuriousWriteWakeups;
+ }
+
+ void IncSendSyscalls() override {
+ ++*SendSyscalls;
+ }
+
+ void IncInflyLimitReach() override {
+ ++*InflyLimitReach;
+ }
+
+ void IncUsefulReadWakeups() override {
+ ++*UsefulReadWakeups;
+ }
+
+ void IncSpuriousReadWakeups() override {
+ ++*SpuriousReadWakeups;
+ }
+
+ void IncDisconnectByReason(const TString& s) override {
+ if (auto it = DisconnectByReason.find(s); it != DisconnectByReason.end()) {
+ it->second->Inc();
+ }
+ }
+
+ void AddInputChannelsIncomingTraffic(ui16 channel, ui64 incomingTraffic) override {
+ auto& ch = InputChannels.Get(channel);
+ *ch.IncomingTraffic += incomingTraffic;
+ }
+
+ void IncInputChannelsIncomingEvents(ui16 channel) override {
+ auto& ch = InputChannels.Get(channel);
+ ++*ch.IncomingEvents;
+ }
+
+ void IncRecvSyscalls() override {
+ ++*RecvSyscalls;
+ }
+
+ void AddTotalBytesRead(ui64 value) override {
+ *TotalBytesRead += value;
+ }
+
+ void UpdateLegacyPingTimeHist(ui64 value) override {
+ LegacyPingTimeHist.Add(value);
+ PingTimeHistogram->Collect(value);
+ }
+
+ void UpdateOutputChannelTraffic(ui16 channel, ui64 value) override {
+ if (GetOutputChannel(channel).OutgoingTraffic) {
+ *(GetOutputChannel(channel).OutgoingTraffic) += value;
+ }
+ if (GetOutputChannel(channel).Traffic) {
+ *(GetOutputChannel(channel).Traffic) += value;
+ }
+ }
+
+ void UpdateOutputChannelEvents(ui16 channel) override {
+ if (GetOutputChannel(channel).OutgoingEvents) {
+ ++*(GetOutputChannel(channel).OutgoingEvents);
+ }
+ if (GetOutputChannel(channel).Events) {
+ ++*(GetOutputChannel(channel).Events);
+ }
+ }
+
+ void SetPeerInfo(const TString& name, const TString& dataCenterId) override {
+ if (name != std::exchange(HumanFriendlyPeerHostName, name)) {
+ PerSessionCounters.Reset();
+ }
+ VALGRIND_MAKE_READABLE(&DataCenterId, sizeof(DataCenterId));
+ if (dataCenterId != std::exchange(DataCenterId, dataCenterId)) {
+ PerDataCenterCounters.Reset();
+ }
+
+ const bool updatePerDataCenter = !PerDataCenterCounters && MergePerDataCenterCounters;
+ if (updatePerDataCenter) {
+ PerDataCenterCounters = Counters->GetSubgroup("dataCenterId", *DataCenterId);
+ }
+
+ const bool updatePerSession = !PerSessionCounters || updatePerDataCenter;
+ if (updatePerSession) {
+ auto base = MergePerDataCenterCounters ? PerDataCenterCounters : Counters;
+ PerSessionCounters = base->GetSubgroup("peer", *HumanFriendlyPeerHostName);
+ }
+
+ const bool updateGlobal = !Initialized;
+
+ const bool updateAdaptive =
+ &AdaptiveCounters == &Counters ? updateGlobal :
+ &AdaptiveCounters == &PerSessionCounters ? updatePerSession :
+ &AdaptiveCounters == &PerDataCenterCounters ? updatePerDataCenter :
+ false;
+
+ if (updatePerSession) {
+ Connected = PerSessionCounters->GetCounter("Connected");
+ Disconnections = PerSessionCounters->GetCounter("Disconnections", true);
+ ClockSkewMicrosec = PerSessionCounters->GetCounter("ClockSkewMicrosec");
+ Traffic = PerSessionCounters->GetCounter("Traffic", true);
+ Events = PerSessionCounters->GetCounter("Events", true);
+ ScopeErrors = PerSessionCounters->GetCounter("ScopeErrors", true);
+
+ for (const auto& [id, name] : Common->ChannelName) {
+ OutputChannels.try_emplace(id, Counters->GetSubgroup("channel", name), Traffic, Events);
+ }
+ OtherOutputChannel = TOutputChannel(Counters->GetSubgroup("channel", "other"), Traffic, Events);
+
+ InputChannels = TInputChannels(Counters, Common->ChannelName, Traffic, Events, ScopeErrors);
+ }
+
+ if (updateAdaptive) {
+ SessionDeaths = AdaptiveCounters->GetCounter("Session_Deaths", true);
+ HandshakeFails = AdaptiveCounters->GetCounter("Handshake_Fails", true);
+ InflyLimitReach = AdaptiveCounters->GetCounter("InflyLimitReach", true);
+ InflightDataAmount = AdaptiveCounters->GetCounter("Inflight_Data");
+
+ LegacyPingTimeHist = {};
+ LegacyPingTimeHist.Init(AdaptiveCounters.Get(), "PingTimeHist", "mks", 125, 18);
+
+ PingTimeHistogram = AdaptiveCounters->GetHistogram(
+ "PingTimeUs", NMonitoring::ExponentialHistogram(18, 2, 125));
+ }
+
+ if (updateGlobal) {
+ OutputBuffersTotalSize = Counters->GetCounter("OutputBuffersTotalSize");
+ SendSyscalls = Counters->GetCounter("SendSyscalls", true);
+ RecvSyscalls = Counters->GetCounter("RecvSyscalls", true);
+ SpuriousReadWakeups = Counters->GetCounter("SpuriousReadWakeups", true);
+ UsefulReadWakeups = Counters->GetCounter("UsefulReadWakeups", true);
+ SpuriousWriteWakeups = Counters->GetCounter("SpuriousWriteWakeups", true);
+ UsefulWriteWakeups = Counters->GetCounter("UsefulWriteWakeups", true);
+ SubscribersCount = AdaptiveCounters->GetCounter("SubscribersCount");
+ TotalBytesWritten = Counters->GetCounter("TotalBytesWritten", true);
+ TotalBytesRead = Counters->GetCounter("TotalBytesRead", true);
+
+ auto disconnectReasonGroup = Counters->GetSubgroup("subsystem", "disconnectReason");
+ for (const char *reason : TDisconnectReason::Reasons) {
+ DisconnectByReason[reason] = disconnectReasonGroup->GetNamedCounter("reason", reason, true);
+ }
+ }
+
+ Initialized = true;
+ }
+
+ TOutputChannel GetOutputChannel(ui16 index) const {
+ Y_VERIFY(Initialized);
+ const auto it = OutputChannels.find(index);
+ return it != OutputChannels.end() ? it->second : OtherOutputChannel;
+ }
+
+ private:
+ NMonitoring::TDynamicCounters::TCounterPtr SessionDeaths;
+ NMonitoring::TDynamicCounters::TCounterPtr HandshakeFails;
+ NMonitoring::TDynamicCounters::TCounterPtr Connected;
+ NMonitoring::TDynamicCounters::TCounterPtr Disconnections;
+ NMonitoring::TDynamicCounters::TCounterPtr InflightDataAmount;
+ NMonitoring::TDynamicCounters::TCounterPtr InflyLimitReach;
+ NMonitoring::TDynamicCounters::TCounterPtr OutputBuffersTotalSize;
+ NMonitoring::TDynamicCounters::TCounterPtr QueueUtilization;
+ NMonitoring::TDynamicCounters::TCounterPtr SubscribersCount;
+ NMonitoring::TDynamicCounters::TCounterPtr SendSyscalls;
+ NMonitoring::TDynamicCounters::TCounterPtr ClockSkewMicrosec;
+ NMonitoring::TDynamicCounters::TCounterPtr RecvSyscalls;
+ NMonitoring::TDynamicCounters::TCounterPtr UsefulReadWakeups;
+ NMonitoring::TDynamicCounters::TCounterPtr SpuriousReadWakeups;
+ NMonitoring::TDynamicCounters::TCounterPtr UsefulWriteWakeups;
+ NMonitoring::TDynamicCounters::TCounterPtr SpuriousWriteWakeups;
+ NMon::THistogramCounterHelper LegacyPingTimeHist;
+ NMonitoring::THistogramPtr PingTimeHistogram;
+
+ std::unordered_map<ui16, TOutputChannel> OutputChannels;
+ TOutputChannel OtherOutputChannel;
+ TInputChannels InputChannels;
+ THashMap<TString, NMonitoring::TDynamicCounters::TCounterPtr> DisconnectByReason;
+
+ NMonitoring::TDynamicCounters::TCounterPtr TotalBytesWritten, TotalBytesRead;
+ };
+
+ class TInterconnectMetrics: public IInterconnectMetrics {
+ public:
+ struct TOutputChannel {
+ NMonitoring::IRate* Traffic;
+ NMonitoring::IRate* Events;
+ NMonitoring::IRate* OutgoingTraffic;
+ NMonitoring::IRate* OutgoingEvents;
+
+ TOutputChannel() = default;
+
+ TOutputChannel(const std::shared_ptr<NMonitoring::IMetricRegistry>& metrics,
+ NMonitoring::IRate* traffic,
+ NMonitoring::IRate* events)
+ : Traffic(traffic)
+ , Events(events)
+ , OutgoingTraffic(metrics->Rate(NMonitoring::MakeLabels({{"sensor", "interconnect.outgoing_traffic"}})))
+ , OutgoingEvents(metrics->Rate(NMonitoring::MakeLabels({{"sensor", "interconnect.outgoing_events"}})))
+ {}
+
+ TOutputChannel(const TOutputChannel&) = default;
+ };
+
+ struct TInputChannel {
+ NMonitoring::IRate* Traffic;
+ NMonitoring::IRate* Events;
+ NMonitoring::IRate* ScopeErrors;
+ NMonitoring::IRate* IncomingTraffic;
+ NMonitoring::IRate* IncomingEvents;
+
+ TInputChannel() = default;
+
+ TInputChannel(const std::shared_ptr<NMonitoring::IMetricRegistry>& metrics,
+ NMonitoring::IRate* traffic, NMonitoring::IRate* events,
+ NMonitoring::IRate* scopeErrors)
+ : Traffic(traffic)
+ , Events(events)
+ , ScopeErrors(scopeErrors)
+ , IncomingTraffic(metrics->Rate(NMonitoring::MakeLabels({{"sensor", "interconnect.incoming_traffic"}})))
+ , IncomingEvents(metrics->Rate(NMonitoring::MakeLabels({{"sensor", "interconnect.incoming_events"}})))
+ {}
+
+ TInputChannel(const TInputChannel&) = default;
+ };
+
+ struct TInputChannels : std::unordered_map<ui16, TInputChannel> {
+ TInputChannel OtherInputChannel;
+
+ TInputChannels() = default;
+
+ TInputChannels(const std::shared_ptr<NMonitoring::IMetricRegistry>& metrics,
+ const std::unordered_map<ui16, TString>& names,
+ NMonitoring::IRate* traffic, NMonitoring::IRate* events,
+ NMonitoring::IRate* scopeErrors)
+ : OtherInputChannel(std::make_shared<NMonitoring::TMetricSubRegistry>(
+ NMonitoring::TLabels{{"channel", "other"}}, metrics), traffic, events, scopeErrors)
+ {
+ for (const auto& [id, name] : names) {
+ try_emplace(id, std::make_shared<NMonitoring::TMetricSubRegistry>(NMonitoring::TLabels{{"channel", name}}, metrics),
+ traffic, events, scopeErrors);
+ }
+ }
+
+ TInputChannels(const TInputChannels&) = default;
+
+ const TInputChannel& Get(ui16 id) const {
+ const auto it = find(id);
+ return it != end() ? it->second : OtherInputChannel;
+ }
+ };
+
+ TInterconnectMetrics(const TInterconnectProxyCommon::TPtr& common)
+ : Common(common)
+ , MergePerDataCenterMetrics_(common->Settings.MergePerDataCenterCounters)
+ , MergePerPeerMetrics_(common->Settings.MergePerPeerCounters)
+ , Metrics_(common->Metrics)
+ , AdaptiveMetrics_(MergePerDataCenterMetrics_
+ ? PerDataCenterMetrics_ :
+ MergePerPeerMetrics_ ? Metrics_ : PerSessionMetrics_)
+ {}
+
+ void AddInflightDataAmount(ui64 value) override {
+ InflightDataAmount_->Add(value);
+ }
+
+ void SubInflightDataAmount(ui64 value) override {
+ InflightDataAmount_->Add(-value);
+ }
+
+ void AddTotalBytesWritten(ui64 value) override {
+ TotalBytesWritten_->Add(value);
+ }
+
+ void SetClockSkewMicrosec(i64 value) override {
+ ClockSkewMicrosec_->Set(value);
+ }
+
+ void IncSessionDeaths() override {
+ SessionDeaths_->Inc();
+ }
+
+ void IncHandshakeFails() override {
+ HandshakeFails_->Inc();
+ }
+
+ void SetConnected(ui32 value) override {
+ Connected_->Set(value);
+ }
+
+ void IncSubscribersCount() override {
+ SubscribersCount_->Inc();
+ }
+
+ void SubSubscribersCount(ui32 value) override {
+ SubscribersCount_->Add(-value);
+ }
+
+ void SubOutputBuffersTotalSize(ui64 value) override {
+ OutputBuffersTotalSize_->Add(-value);
+ }
+
+ void AddOutputBuffersTotalSize(ui64 value) override {
+ OutputBuffersTotalSize_->Add(value);
+ }
+
+ ui64 GetOutputBuffersTotalSize() const override {
+ return OutputBuffersTotalSize_->Get();
+ }
+
+ void IncDisconnections() override {
+ Disconnections_->Inc();
+ }
+
+ void IncUsefulWriteWakeups() override {
+ UsefulWriteWakeups_->Inc();
+ }
+
+ void IncSpuriousWriteWakeups() override {
+ SpuriousWriteWakeups_->Inc();
+ }
+
+ void IncSendSyscalls() override {
+ SendSyscalls_->Inc();
+ }
+
+ void IncInflyLimitReach() override {
+ InflyLimitReach_->Inc();
+ }
+
+ void IncUsefulReadWakeups() override {
+ UsefulReadWakeups_->Inc();
+ }
+
+ void IncSpuriousReadWakeups() override {
+ SpuriousReadWakeups_->Inc();
+ }
+
+ void IncDisconnectByReason(const TString& s) override {
+ if (auto it = DisconnectByReason_.find(s); it != DisconnectByReason_.end()) {
+ it->second->Inc();
+ }
+ }
+
+ void AddInputChannelsIncomingTraffic(ui16 channel, ui64 incomingTraffic) override {
+ auto& ch = InputChannels_.Get(channel);
+ ch.IncomingTraffic->Add(incomingTraffic);
+ }
+
+ void IncInputChannelsIncomingEvents(ui16 channel) override {
+ auto& ch = InputChannels_.Get(channel);
+ ch.IncomingEvents->Inc();
+ }
+
+ void IncRecvSyscalls() override {
+ RecvSyscalls_->Inc();
+ }
+
+ void AddTotalBytesRead(ui64 value) override {
+ TotalBytesRead_->Add(value);
+ }
+
+ void UpdateLegacyPingTimeHist(ui64 value) override {
+ PingTimeHistogram_->Record(value);
+ }
+
+ void UpdateOutputChannelTraffic(ui16 channel, ui64 value) override {
+ if (GetOutputChannel(channel).OutgoingTraffic) {
+ GetOutputChannel(channel).OutgoingTraffic->Add(value);
+ }
+ if (GetOutputChannel(channel).Traffic) {
+ GetOutputChannel(channel).Traffic->Add(value);
+ }
+ }
+
+ void UpdateOutputChannelEvents(ui16 channel) override {
+ if (GetOutputChannel(channel).OutgoingEvents) {
+ GetOutputChannel(channel).OutgoingEvents->Inc();
+ }
+ if (GetOutputChannel(channel).Events) {
+ GetOutputChannel(channel).Events->Inc();
+ }
+ }
+
+ void SetPeerInfo(const TString& name, const TString& dataCenterId) override {
+ if (name != std::exchange(HumanFriendlyPeerHostName, name)) {
+ PerSessionMetrics_.reset();
+ }
+ VALGRIND_MAKE_READABLE(&DataCenterId, sizeof(DataCenterId));
+ if (dataCenterId != std::exchange(DataCenterId, dataCenterId)) {
+ PerDataCenterMetrics_.reset();
+ }
+
+ const bool updatePerDataCenter = !PerDataCenterMetrics_ && MergePerDataCenterMetrics_;
+ if (updatePerDataCenter) {
+ PerDataCenterMetrics_ = std::make_shared<NMonitoring::TMetricSubRegistry>(
+ NMonitoring::TLabels{{"datacenter_id", *DataCenterId}}, Metrics_);
+ }
+
+ const bool updatePerSession = !PerSessionMetrics_ || updatePerDataCenter;
+ if (updatePerSession) {
+ auto base = MergePerDataCenterMetrics_ ? PerDataCenterMetrics_ : Metrics_;
+ PerSessionMetrics_ = std::make_shared<NMonitoring::TMetricSubRegistry>(
+ NMonitoring::TLabels{{"peer", *HumanFriendlyPeerHostName}}, base);
+ }
+
+ const bool updateGlobal = !Initialized_;
+
+ const bool updateAdaptive =
+ &AdaptiveMetrics_ == &Metrics_ ? updateGlobal :
+ &AdaptiveMetrics_ == &PerSessionMetrics_ ? updatePerSession :
+ &AdaptiveMetrics_ == &PerDataCenterMetrics_ ? updatePerDataCenter :
+ false;
+
+ auto createRate = [](std::shared_ptr<NMonitoring::IMetricRegistry> metrics, TStringBuf name) mutable {
+ return metrics->Rate(NMonitoring::MakeLabels(NMonitoring::TLabels{{"sensor", name}}));
+ };
+ auto createIntGauge = [](std::shared_ptr<NMonitoring::IMetricRegistry> metrics, TStringBuf name) mutable {
+ return metrics->IntGauge(NMonitoring::MakeLabels(NMonitoring::TLabels{{"sensor", name}}));
+ };
+
+ if (updatePerSession) {
+ Connected_ = createIntGauge(PerSessionMetrics_, "interconnect.connected");
+ Disconnections_ = createRate(PerSessionMetrics_, "interconnect.disconnections");
+ ClockSkewMicrosec_ = createIntGauge(PerSessionMetrics_, "interconnect.clock_skew_microsec");
+ Traffic_ = createRate(PerSessionMetrics_, "interconnect.traffic");
+ Events_ = createRate(PerSessionMetrics_, "interconnect.events");
+ ScopeErrors_ = createRate(PerSessionMetrics_, "interconnect.scope_errors");
+
+ for (const auto& [id, name] : Common->ChannelName) {
+ OutputChannels_.try_emplace(id, std::make_shared<NMonitoring::TMetricSubRegistry>(
+ NMonitoring::TLabels{{"channel", name}}, Metrics_), Traffic_, Events_);
+ }
+ OtherOutputChannel_ = TOutputChannel(std::make_shared<NMonitoring::TMetricSubRegistry>(
+ NMonitoring::TLabels{{"channel", "other"}}, Metrics_), Traffic_, Events_);
+
+ InputChannels_ = TInputChannels(Metrics_, Common->ChannelName, Traffic_, Events_, ScopeErrors_);
+ }
+
+ if (updateAdaptive) {
+ SessionDeaths_ = createRate(AdaptiveMetrics_, "interconnect.session_deaths");
+ HandshakeFails_ = createRate(AdaptiveMetrics_, "interconnect.handshake_fails");
+ InflyLimitReach_ = createRate(AdaptiveMetrics_, "interconnect.infly_limit_reach");
+ InflightDataAmount_ = createRate(AdaptiveMetrics_, "interconnect.inflight_data");
+ PingTimeHistogram_ = AdaptiveMetrics_->HistogramRate(
+ NMonitoring::MakeLabels({{"sensor", "interconnect.ping_time_us"}}), NMonitoring::ExponentialHistogram(18, 2, 125));
+ }
+
+ if (updateGlobal) {
+ OutputBuffersTotalSize_ = createRate(Metrics_, "interconnect.output_buffers_total_size");
+ SendSyscalls_ = createRate(Metrics_, "interconnect.send_syscalls");
+ RecvSyscalls_ = createRate(Metrics_, "interconnect.recv_syscalls");
+ SpuriousReadWakeups_ = createRate(Metrics_, "interconnect.spurious_read_wakeups");
+ UsefulReadWakeups_ = createRate(Metrics_, "interconnect.useful_read_wakeups");
+ SpuriousWriteWakeups_ = createRate(Metrics_, "interconnect.spurious_write_wakeups");
+ UsefulWriteWakeups_ = createRate(Metrics_, "interconnect.useful_write_wakeups");
+ SubscribersCount_ = createIntGauge(AdaptiveMetrics_, "interconnect.subscribers_count");
+ TotalBytesWritten_ = createRate(Metrics_, "interconnect.total_bytes_written");
+ TotalBytesRead_ = createRate(Metrics_, "interconnect.total_bytes_read");
+
+ for (const char *reason : TDisconnectReason::Reasons) {
+ DisconnectByReason_[reason] = Metrics_->Rate(
+ NMonitoring::MakeLabels({
+ {"sensor", "interconnect.disconnect_reason"},
+ {"reason", reason},
+ }));
+ }
+ }
+
+ Initialized_ = true;
+ }
+
+ TOutputChannel GetOutputChannel(ui16 index) const {
+ Y_VERIFY(Initialized_);
+ const auto it = OutputChannels_.find(index);
+ return it != OutputChannels_.end() ? it->second : OtherOutputChannel_;
+ }
+
+ private:
+ const TInterconnectProxyCommon::TPtr Common;
+ const bool MergePerDataCenterMetrics_;
+ const bool MergePerPeerMetrics_;
+ std::shared_ptr<NMonitoring::IMetricRegistry> Metrics_;
+ std::shared_ptr<NMonitoring::IMetricRegistry> PerSessionMetrics_;
+ std::shared_ptr<NMonitoring::IMetricRegistry> PerDataCenterMetrics_;
+ std::shared_ptr<NMonitoring::IMetricRegistry>& AdaptiveMetrics_;
+ bool Initialized_ = false;
+
+ NMonitoring::IRate* Traffic_;
+
+ NMonitoring::IRate* Events_;
+ NMonitoring::IRate* ScopeErrors_;
+ NMonitoring::IRate* Disconnections_;
+ NMonitoring::IIntGauge* Connected_;
+
+ NMonitoring::IRate* SessionDeaths_;
+ NMonitoring::IRate* HandshakeFails_;
+ NMonitoring::IRate* InflyLimitReach_;
+ NMonitoring::IRate* InflightDataAmount_;
+ NMonitoring::IRate* OutputBuffersTotalSize_;
+ NMonitoring::IIntGauge* SubscribersCount_;
+ NMonitoring::IRate* SendSyscalls_;
+ NMonitoring::IRate* RecvSyscalls_;
+ NMonitoring::IRate* SpuriousWriteWakeups_;
+ NMonitoring::IRate* UsefulWriteWakeups_;
+ NMonitoring::IRate* SpuriousReadWakeups_;
+ NMonitoring::IRate* UsefulReadWakeups_;
+ NMonitoring::IIntGauge* ClockSkewMicrosec_;
+
+ NMonitoring::IHistogram* PingTimeHistogram_;
+
+ std::unordered_map<ui16, TOutputChannel> OutputChannels_;
+ TOutputChannel OtherOutputChannel_;
+ TInputChannels InputChannels_;
+
+ THashMap<TString, NMonitoring::IRate*> DisconnectByReason_;
+
+ NMonitoring::IRate* TotalBytesWritten_;
+ NMonitoring::IRate* TotalBytesRead_;
+ };
+
+} // namespace
+
+std::unique_ptr<IInterconnectMetrics> CreateInterconnectCounters(const TInterconnectProxyCommon::TPtr& common) {
+ return std::make_unique<TInterconnectCounters>(common);
+}
+
+std::unique_ptr<IInterconnectMetrics> CreateInterconnectMetrics(const TInterconnectProxyCommon::TPtr& common) {
+ return std::make_unique<TInterconnectMetrics>(common);
+}
+
+} // NActors
diff --git a/library/cpp/actors/interconnect/interconnect_counters.h b/library/cpp/actors/interconnect/interconnect_counters.h
new file mode 100644
index 0000000000..e30f03a0bc
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_counters.h
@@ -0,0 +1,59 @@
+#pragma once
+
+#include <library/cpp/actors/helpers/mon_histogram_helper.h>
+
+#include <util/system/valgrind.h>
+
+#include "types.h"
+
+#include "interconnect_common.h"
+
+#include <memory>
+#include <optional>
+
+namespace NActors {
+
+class IInterconnectMetrics {
+public:
+ virtual ~IInterconnectMetrics() = default;
+
+ virtual void AddInflightDataAmount(ui64 value) = 0;
+ virtual void SubInflightDataAmount(ui64 value) = 0;
+ virtual void AddTotalBytesWritten(ui64 value) = 0;
+ virtual void SetClockSkewMicrosec(i64 value) = 0;
+ virtual void IncSessionDeaths() = 0;
+ virtual void IncHandshakeFails() = 0;
+ virtual void SetConnected(ui32 value) = 0;
+ virtual void IncSubscribersCount() = 0;
+ virtual void SubSubscribersCount(ui32 value) = 0;
+ virtual void SubOutputBuffersTotalSize(ui64 value) = 0;
+ virtual void AddOutputBuffersTotalSize(ui64 value) = 0;
+ virtual ui64 GetOutputBuffersTotalSize() const = 0;
+ virtual void IncDisconnections() = 0;
+ virtual void IncUsefulWriteWakeups() = 0;
+ virtual void IncSpuriousWriteWakeups() = 0;
+ virtual void IncSendSyscalls() = 0;
+ virtual void IncInflyLimitReach() = 0;
+ virtual void IncDisconnectByReason(const TString& s) = 0;
+ virtual void IncUsefulReadWakeups() = 0;
+ virtual void IncSpuriousReadWakeups() = 0;
+ virtual void SetPeerInfo(const TString& name, const TString& dataCenterId) = 0;
+ virtual void AddInputChannelsIncomingTraffic(ui16 channel, ui64 incomingTraffic) = 0;
+ virtual void IncInputChannelsIncomingEvents(ui16 channel) = 0;
+ virtual void IncRecvSyscalls() = 0;
+ virtual void AddTotalBytesRead(ui64 value) = 0;
+ virtual void UpdateLegacyPingTimeHist(ui64 value) = 0;
+ virtual void UpdateOutputChannelTraffic(ui16 channel, ui64 value) = 0;
+ virtual void UpdateOutputChannelEvents(ui16 channel) = 0;
+ TString GetHumanFriendlyPeerHostName() const {
+ return HumanFriendlyPeerHostName.value_or(TString());
+ }
+
+protected:
+ std::optional<TString> DataCenterId;
+ std::optional<TString> HumanFriendlyPeerHostName;
+};
+
+std::unique_ptr<IInterconnectMetrics> CreateInterconnectCounters(const NActors::TInterconnectProxyCommon::TPtr& common);
+std::unique_ptr<IInterconnectMetrics> CreateInterconnectMetrics(const NActors::TInterconnectProxyCommon::TPtr& common);
+} // NActors
diff --git a/library/cpp/actors/interconnect/interconnect_handshake.cpp b/library/cpp/actors/interconnect/interconnect_handshake.cpp
new file mode 100644
index 0000000000..9ede998d8e
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_handshake.cpp
@@ -0,0 +1,995 @@
+#include "interconnect_handshake.h"
+#include "interconnect_tcp_proxy.h"
+
+#include <library/cpp/actors/core/actor_coroutine.h>
+#include <library/cpp/actors/core/log.h>
+#include <library/cpp/actors/protos/services_common.pb.h>
+#include <util/system/getpid.h>
+
+#include <google/protobuf/text_format.h>
+
+#include <variant>
+
+namespace NActors {
+ static constexpr size_t StackSize = 64 * 1024; // 64k should be enough
+
+ class THandshakeActor
+ : public TActorCoroImpl
+ , public TInterconnectLoggingBase
+ {
+ struct TExHandshakeFailed : yexception {};
+
+ static constexpr TDuration ResolveTimeout = TDuration::Seconds(1);
+
+#pragma pack(push, 1)
+
+ struct TInitialPacket {
+ struct {
+ TActorId SelfVirtualId;
+ TActorId PeerVirtualId;
+ ui64 NextPacket;
+ ui64 Version;
+ } Header;
+ ui32 Checksum;
+
+ TInitialPacket() = default;
+
+ TInitialPacket(const TActorId& self, const TActorId& peer, ui64 nextPacket, ui64 version) {
+ Header.SelfVirtualId = self;
+ Header.PeerVirtualId = peer;
+ Header.NextPacket = nextPacket;
+ Header.Version = version;
+ Checksum = Crc32cExtendMSanCompatible(0, &Header, sizeof(Header));
+ }
+
+ bool Check() const {
+ return Checksum == Crc32cExtendMSanCompatible(0, &Header, sizeof(Header));
+ }
+
+ TString ToString() const {
+ return TStringBuilder()
+ << "{SelfVirtualId# " << Header.SelfVirtualId.ToString()
+ << " PeerVirtualId# " << Header.PeerVirtualId.ToString()
+ << " NextPacket# " << Header.NextPacket
+ << " Version# " << Header.Version
+ << "}";
+ }
+ };
+
+ struct TExHeader {
+ static constexpr ui32 MaxSize = 1024 * 1024;
+
+ ui32 Checksum;
+ ui32 Size;
+
+ ui32 CalculateChecksum(const void* data, size_t len) const {
+ return Crc32cExtendMSanCompatible(Crc32cExtendMSanCompatible(0, &Size, sizeof(Size)), data, len);
+ }
+
+ void Sign(const void* data, size_t len) {
+ Checksum = CalculateChecksum(data, len);
+ }
+
+ bool Check(const void* data, size_t len) const {
+ return Checksum == CalculateChecksum(data, len);
+ }
+ };
+
+#pragma pack(pop)
+
+ private:
+ TInterconnectProxyCommon::TPtr Common;
+ TActorId SelfVirtualId;
+ TActorId PeerVirtualId;
+ ui32 PeerNodeId = 0;
+ ui64 NextPacketToPeer = 0;
+ TMaybe<ui64> NextPacketFromPeer; // will be obtained from incoming initial packet
+ TString PeerHostName;
+ TString PeerAddr;
+ TSocketPtr Socket;
+ TPollerToken::TPtr PollerToken;
+ TString State;
+ TString HandshakeKind;
+ TMaybe<THolder<TProgramInfo>> ProgramInfo; // filled in in case of successful handshake; even if null
+ TSessionParams Params;
+ bool ResolveTimedOut = false;
+ THashMap<ui32, TInstant> LastLogNotice;
+ const TDuration MuteDuration = TDuration::Seconds(15);
+ TInstant Deadline;
+
+ public:
+ static constexpr IActor::EActivityType ActorActivityType() {
+ return IActor::INTERCONNECT_HANDSHAKE;
+ }
+
+ THandshakeActor(TInterconnectProxyCommon::TPtr common, const TActorId& self, const TActorId& peer,
+ ui32 nodeId, ui64 nextPacket, TString peerHostName, TSessionParams params)
+ : TActorCoroImpl(StackSize, true, true) // allow unhandled poison pills and dtors
+ , Common(std::move(common))
+ , SelfVirtualId(self)
+ , PeerVirtualId(peer)
+ , PeerNodeId(nodeId)
+ , NextPacketToPeer(nextPacket)
+ , PeerHostName(std::move(peerHostName))
+ , HandshakeKind("outgoing handshake")
+ , Params(std::move(params))
+ {
+ Y_VERIFY(SelfVirtualId);
+ Y_VERIFY(SelfVirtualId.NodeId());
+ Y_VERIFY(PeerNodeId);
+ }
+
+ THandshakeActor(TInterconnectProxyCommon::TPtr common, TSocketPtr socket)
+ : TActorCoroImpl(StackSize, true, true) // allow unhandled poison pills and dtors
+ , Common(std::move(common))
+ , Socket(std::move(socket))
+ , HandshakeKind("incoming handshake")
+ {
+ Y_VERIFY(Socket);
+ PeerAddr = TString::Uninitialized(1024);
+ if (GetRemoteAddr(*Socket, PeerAddr.Detach(), PeerAddr.size())) {
+ PeerAddr.resize(strlen(PeerAddr.data()));
+ } else {
+ PeerAddr.clear();
+ }
+ }
+
+ void UpdatePrefix() {
+ SetPrefix(Sprintf("Handshake %s [node %" PRIu32 "]", SelfActorId.ToString().data(), PeerNodeId));
+ }
+
+ void Run() override {
+ UpdatePrefix();
+
+ // set up overall handshake process timer
+ TDuration timeout = Common->Settings.Handshake;
+ if (timeout == TDuration::Zero()) {
+ timeout = DEFAULT_HANDSHAKE_TIMEOUT;
+ }
+ timeout += ResolveTimeout * 2;
+ Deadline = Now() + timeout;
+ Schedule(Deadline, new TEvents::TEvWakeup);
+
+ try {
+ if (Socket) {
+ PerformIncomingHandshake();
+ } else {
+ PerformOutgoingHandshake();
+ }
+
+ // establish encrypted channel, or, in case when encryption is disabled, check if it matches settings
+ if (ProgramInfo) {
+ if (Params.Encryption) {
+ EstablishSecureConnection();
+ } else if (Common->Settings.EncryptionMode == EEncryptionMode::REQUIRED && !Params.AuthOnly) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Peer doesn't support encryption, which is required");
+ }
+ }
+ } catch (const TExHandshakeFailed&) {
+ ProgramInfo.Clear();
+ }
+
+ if (ProgramInfo) {
+ LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH04", NLog::PRI_INFO, "handshake succeeded");
+ Y_VERIFY(NextPacketFromPeer);
+ if (PollerToken) {
+ Y_VERIFY(PollerToken->RefCount() == 1);
+ PollerToken.Reset(); // ensure we are going to destroy poller token here as we will re-register the socket within other actor
+ }
+ SendToProxy(MakeHolder<TEvHandshakeDone>(std::move(Socket), PeerVirtualId, SelfVirtualId,
+ *NextPacketFromPeer, ProgramInfo->Release(), std::move(Params)));
+ }
+
+ Socket.Reset();
+ }
+
+ void EstablishSecureConnection() {
+ Y_VERIFY(PollerToken && PollerToken->RefCount() == 1);
+ PollerToken.Reset();
+ auto ev = AskProxy<TEvSecureSocket>(MakeHolder<TEvGetSecureSocket>(Socket), "AskProxy(TEvSecureContext)");
+ Socket = std::move(ev->Get()->Socket);
+ RegisterInPoller();
+ const ui32 myNodeId = GetActorSystem()->NodeId;
+ const bool server = myNodeId < PeerNodeId; // keep server/client role permanent to enable easy TLS session resuming
+ for (;;) {
+ TString err;
+ auto& secure = static_cast<NInterconnect::TSecureSocket&>(*Socket);
+ switch (secure.Establish(server, Params.AuthOnly, err)) {
+ case NInterconnect::TSecureSocket::EStatus::SUCCESS:
+ if (Params.AuthOnly) {
+ Params.Encryption = false;
+ Params.AuthCN = secure.GetPeerCommonName();
+ Y_VERIFY(PollerToken && PollerToken->RefCount() == 1);
+ PollerToken.Reset();
+ Socket = secure.Detach();
+ }
+ return;
+
+ case NInterconnect::TSecureSocket::EStatus::ERROR:
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, err, true);
+ [[fallthrough]];
+
+ case NInterconnect::TSecureSocket::EStatus::WANT_READ:
+ WaitPoller(true, false, "ReadEstablish");
+ break;
+
+ case NInterconnect::TSecureSocket::EStatus::WANT_WRITE:
+ WaitPoller(false, true, "WriteEstablish");
+ break;
+ }
+ }
+ }
+
+ void ProcessUnexpectedEvent(TAutoPtr<IEventHandle> ev) override {
+ switch (const ui32 type = ev->GetTypeRewrite()) {
+ case TEvents::TSystem::Wakeup:
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_TRANSIENT, Sprintf("Handshake timed out, State# %s", State.data()), true);
+ [[fallthrough]];
+
+ case ui32(ENetwork::NodeInfo):
+ case TEvInterconnect::EvNodeAddress:
+ case ui32(ENetwork::ResolveError):
+ break; // most likely a race with resolve timeout
+
+ case TEvPollerReady::EventType:
+ break;
+
+ default:
+ Y_FAIL("unexpected event 0x%08" PRIx32, type);
+ }
+ }
+
+ template<typename T>
+ void SetupVersionTag(T& proto) {
+ if (Common->VersionInfo) {
+ proto.SetVersionTag(Common->VersionInfo->Tag);
+ for (const TString& accepted : Common->VersionInfo->AcceptedTags) {
+ proto.AddAcceptedVersionTags(accepted);
+ }
+ }
+ }
+
+ template<typename T>
+ void SetupClusterUUID(T& proto) {
+ auto *pb = proto.MutableClusterUUIDs();
+ pb->SetClusterUUID(Common->ClusterUUID);
+ for (const TString& uuid : Common->AcceptUUID) {
+ pb->AddAcceptUUID(uuid);
+ }
+ }
+
+ template<typename T, typename TCallback>
+ void ValidateVersionTag(const T& proto, TCallback&& errorCallback) {
+ // check if we will accept peer's version tag (if peer provides one and if we have accepted list non-empty)
+ if (Common->VersionInfo) {
+ if (!proto.HasVersionTag()) {
+ LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH06", NLog::PRI_WARN,
+ "peer did not report VersionTag, accepting by default");
+ } else if (!Common->VersionInfo->AcceptedTags.count(proto.GetVersionTag())) {
+ // we will not accept peer's tag, so check if remote peer would accept our version tag
+ size_t i;
+ for (i = 0; i < proto.AcceptedVersionTagsSize() && Common->VersionInfo->Tag != proto.GetAcceptedVersionTags(i); ++i)
+ {}
+ if (i == proto.AcceptedVersionTagsSize()) {
+ // peer will neither accept our version -- this is total failure
+ TStringStream s("local/peer version tags did not match accepted ones");
+ s << " local Tag# " << Common->VersionInfo->Tag << " accepted Tags# [";
+ bool first = true;
+ for (const auto& tag : Common->VersionInfo->AcceptedTags) {
+ s << (std::exchange(first, false) ? "" : " ") << tag;
+ }
+ s << "] peer Tag# " << proto.GetVersionTag() << " accepted Tags# [";
+ first = true;
+ for (const auto& tag : proto.GetAcceptedVersionTags()) {
+ s << (std::exchange(first, false) ? "" : " ") << tag;
+ }
+ s << "]";
+ errorCallback(s.Str());
+ }
+ }
+ }
+ }
+
+ template<typename T, typename TCallback>
+ void ValidateClusterUUID(const T& proto, TCallback&& errorCallback, const TMaybe<TString>& uuid = {}) {
+ auto formatList = [](const auto& list) {
+ TStringStream s;
+ s << "[";
+ for (auto it = list.begin(); it != list.end(); ++it) {
+ if (it != list.begin()) {
+ s << " ";
+ }
+ s << *it;
+ }
+ s << "]";
+ return s.Str();
+ };
+ if (!Common->AcceptUUID) {
+ return; // promiscuous mode -- we accept every other peer
+ }
+ if (!proto.HasClusterUUIDs()) {
+ if (uuid) {
+ // old-style checking, peer does not support symmetric protoocol
+ bool matching = false;
+ for (const TString& accepted : Common->AcceptUUID) {
+ if (*uuid == accepted) {
+ matching = true;
+ break;
+ }
+ }
+ if (!matching) {
+ errorCallback(Sprintf("Peer ClusterUUID# %s mismatch, AcceptUUID# %s", uuid->data(), formatList(Common->AcceptUUID).data()));
+ }
+ }
+ return; // remote side did not fill in this field -- old version, symmetric protocol is not supported
+ }
+
+ const auto& uuids = proto.GetClusterUUIDs();
+
+ // check if our UUID matches remote accept list
+ for (const TString& item : uuids.GetAcceptUUID()) {
+ if (item == Common->ClusterUUID) {
+ return; // match
+ }
+ }
+
+ // check if remote UUID matches our accept list
+ const TString& remoteUUID = uuids.GetClusterUUID();
+ for (const TString& item : Common->AcceptUUID) {
+ if (item == remoteUUID) {
+ return; // match
+ }
+ }
+
+ // no match
+ errorCallback(Sprintf("Peer ClusterUUID# %s mismatch, AcceptUUID# %s", remoteUUID.data(), formatList(Common->AcceptUUID).data()));
+ }
+
+ void ParsePeerScopeId(const NActorsInterconnect::TScopeId& proto) {
+ Params.PeerScopeId = {proto.GetX1(), proto.GetX2()};
+ }
+
+ void FillInScopeId(NActorsInterconnect::TScopeId& proto) {
+ const TScopeId& scope = Common->LocalScopeId;
+ proto.SetX1(scope.first);
+ proto.SetX2(scope.second);
+ }
+
+ template<typename T>
+ void ReportProto(const T& protobuf, const char *msg) {
+ auto formatString = [&] {
+ google::protobuf::TextFormat::Printer p;
+ p.SetSingleLineMode(true);
+ TString s;
+ p.PrintToString(protobuf, &s);
+ return s;
+ };
+ LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH07", NLog::PRI_DEBUG, "%s %s", msg,
+ formatString().data());
+ }
+
+ bool CheckPeerCookie(const TString& cookie, TString *error) {
+ // create a temporary socket to connect to the peer
+ TSocketPtr tempSocket;
+ std::swap(tempSocket, Socket);
+ TPollerToken::TPtr tempPollerToken;
+ std::swap(tempPollerToken, PollerToken);
+
+ // set up virtual self id to ensure peer will not drop our connection
+ char buf[12] = {'c', 'o', 'o', 'k', 'i', 'e', ' ', 'c', 'h', 'e', 'c', 'k'};
+ SelfVirtualId = TActorId(SelfActorId.NodeId(), TStringBuf(buf, 12));
+
+ bool success = true;
+ try {
+ // issue connection and send initial packet
+ Connect(false);
+ SendInitialPacket();
+
+ // wait for basic response
+ TInitialPacket response;
+ ReceiveData(&response, sizeof(response), "ReceiveResponse");
+ if (!response.Check()) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_TRANSIENT, "Initial packet CRC error");
+ } else if (response.Header.Version != INTERCONNECT_PROTOCOL_VERSION) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, Sprintf("Incompatible protocol %" PRIu64, response.Header.Version));
+ }
+
+ // issue cookie check request
+ NActorsInterconnect::THandshakeRequest request;
+ request.SetProtocol(INTERCONNECT_PROTOCOL_VERSION);
+ request.SetProgramPID(0);
+ request.SetProgramStartTime(0);
+ request.SetSerial(0);
+ request.SetReceiverNodeId(0);
+ request.SetSenderActorId(TString());
+ request.SetCookie(cookie);
+ request.SetDoCheckCookie(true);
+ SendExBlock(request, "SendExBlockDoCheckCookie");
+
+ // process cookie check reply
+ NActorsInterconnect::THandshakeReply reply;
+ if (!reply.ParseFromString(ReceiveExBlock("ReceiveExBlockDoCheckCookie"))) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Incorrect packet from peer");
+ } else if (reply.HasCookieCheckResult() && !reply.GetCookieCheckResult()) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Cookie check error -- possible network problem");
+ }
+ } catch (const TExHandshakeFailed& e) {
+ *error = e.what();
+ success = false;
+ }
+
+ // restore state
+ SelfVirtualId = TActorId();
+ std::swap(tempSocket, Socket);
+ std::swap(tempPollerToken, PollerToken);
+ return success;
+ }
+
+ void PerformOutgoingHandshake() {
+ LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH01", NLog::PRI_DEBUG,
+ "starting outgoing handshake");
+
+ // perform connection
+ Connect(true);
+
+ // send initial request packet
+ SendInitialPacket();
+
+ TInitialPacket response;
+ ReceiveData(&response, sizeof(response), "ReceiveResponse");
+ if (!response.Check()) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_TRANSIENT, "Initial packet CRC error");
+ } else if (response.Header.Version != INTERCONNECT_PROTOCOL_VERSION) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, Sprintf("Incompatible protocol %" PRIu64, response.Header.Version));
+ }
+
+ // extract next packet
+ NextPacketFromPeer = response.Header.NextPacket;
+
+ if (!PeerVirtualId) {
+ // creating new session -- we have to generate request
+ NActorsInterconnect::THandshakeRequest request;
+
+ request.SetProtocol(INTERCONNECT_PROTOCOL_VERSION);
+ request.SetProgramPID(GetPID());
+ request.SetProgramStartTime(Common->StartTime);
+ request.SetSerial(SelfVirtualId.LocalId());
+ request.SetReceiverNodeId(PeerNodeId);
+ request.SetSenderActorId(SelfVirtualId.ToString());
+ request.SetSenderHostName(Common->TechnicalSelfHostName);
+ request.SetReceiverHostName(PeerHostName);
+
+ if (Common->LocalScopeId != TScopeId()) {
+ FillInScopeId(*request.MutableClientScopeId());
+ }
+
+ if (Common->Cookie) {
+ request.SetCookie(Common->Cookie);
+ }
+ if (Common->ClusterUUID) {
+ request.SetUUID(Common->ClusterUUID);
+ }
+ SetupClusterUUID(request);
+ SetupVersionTag(request);
+
+ if (const ui32 size = Common->HandshakeBallastSize) {
+ TString ballast(size, 0);
+ char* data = ballast.Detach();
+ for (ui32 i = 0; i < size; ++i) {
+ data[i] = i;
+ }
+ request.SetBallast(ballast);
+ }
+
+ switch (Common->Settings.EncryptionMode) {
+ case EEncryptionMode::DISABLED:
+ break;
+
+ case EEncryptionMode::OPTIONAL:
+ request.SetRequireEncryption(false);
+ break;
+
+ case EEncryptionMode::REQUIRED:
+ request.SetRequireEncryption(true);
+ break;
+ }
+
+ request.SetRequestModernFrame(true);
+ request.SetRequestAuthOnly(Common->Settings.TlsAuthOnly);
+
+ SendExBlock(request, "ExRequest");
+
+ NActorsInterconnect::THandshakeReply reply;
+ if (!reply.ParseFromString(ReceiveExBlock("ExReply"))) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Incorrect THandshakeReply");
+ }
+ ReportProto(reply, "ReceiveExBlock ExReply");
+
+ if (reply.HasErrorExplaination()) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "error from peer: " + reply.GetErrorExplaination());
+ } else if (!reply.HasSuccess()) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "empty reply");
+ }
+
+ auto generateError = [this](TString msg) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, msg);
+ };
+
+ const auto& success = reply.GetSuccess();
+ ValidateClusterUUID(success, generateError);
+ ValidateVersionTag(success, generateError);
+
+ const auto& s = success.GetSenderActorId();
+ PeerVirtualId.Parse(s.data(), s.size());
+
+ // recover flags
+ Params.Encryption = success.GetStartEncryption();
+ Params.UseModernFrame = success.GetUseModernFrame();
+ Params.AuthOnly = Params.Encryption && success.GetAuthOnly();
+ if (success.HasServerScopeId()) {
+ ParsePeerScopeId(success.GetServerScopeId());
+ }
+
+ // recover peer process info from peer's reply
+ ProgramInfo = GetProgramInfo(success);
+ } else if (!response.Header.SelfVirtualId) {
+ // peer reported error -- empty ack was generated by proxy for this request
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_SESSION_MISMATCH, "Peer rejected session continuation handshake");
+ } else if (response.Header.SelfVirtualId != PeerVirtualId || response.Header.PeerVirtualId != SelfVirtualId) {
+ // resuming existing session; check that virtual ids of peers match each other
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_SESSION_MISMATCH, "Session virtual ID mismatch");
+ } else {
+ ProgramInfo.ConstructInPlace(); // successful handshake
+ }
+ }
+
+ void PerformIncomingHandshake() {
+ LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH02", NLog::PRI_DEBUG,
+ "starting incoming handshake");
+
+ // set up incoming socket
+ SetupSocket();
+
+ // wait for initial request packet
+ TInitialPacket request;
+ ReceiveData(&request, sizeof(request), "ReceiveRequest");
+ if (!request.Check()) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_TRANSIENT, "Initial packet CRC error");
+ } else if (request.Header.Version != INTERCONNECT_PROTOCOL_VERSION) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, Sprintf("Incompatible protocol %" PRIu64, request.Header.Version));
+ }
+
+ // extract peer node id from the peer
+ PeerNodeId = request.Header.SelfVirtualId.NodeId();
+ if (!PeerNodeId) {
+ Y_VERIFY_DEBUG(false, "PeerNodeId is zero request# %s", request.ToString().data());
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "SelfVirtualId.NodeId is empty in initial packet");
+ }
+ UpdatePrefix();
+
+ // extract next packet
+ NextPacketFromPeer = request.Header.NextPacket;
+
+ if (request.Header.PeerVirtualId) {
+ // issue request to the proxy and wait for the response
+ auto reply = AskProxy<TEvHandshakeAck, TEvHandshakeNak>(MakeHolder<TEvHandshakeAsk>(
+ request.Header.SelfVirtualId, request.Header.PeerVirtualId, request.Header.NextPacket),
+ "TEvHandshakeAsk");
+ if (auto *ack = reply->CastAsLocal<TEvHandshakeAck>()) {
+ // extract self/peer virtual ids
+ SelfVirtualId = ack->Self;
+ PeerVirtualId = request.Header.SelfVirtualId;
+ NextPacketToPeer = ack->NextPacket;
+ Params = ack->Params;
+
+ // only succeed in case when proxy returned valid SelfVirtualId; otherwise it wants us to terminate
+ // the handshake process and it does not expect the handshake reply
+ ProgramInfo.ConstructInPlace();
+ } else {
+ LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH08", NLog::PRI_NOTICE,
+ "Continuation request rejected by proxy");
+
+ // report continuation reject to peer
+ SelfVirtualId = TActorId();
+ PeerVirtualId = TActorId();
+ NextPacketToPeer = 0;
+ }
+
+ // issue response to the peer
+ SendInitialPacket();
+ } else {
+ // peer wants a new session, clear fields and send initial packet
+ SelfVirtualId = TActorId();
+ PeerVirtualId = TActorId();
+ NextPacketToPeer = 0;
+ SendInitialPacket();
+
+ // wait for extended request
+ auto ev = MakeHolder<TEvHandshakeRequest>();
+ auto& request = ev->Record;
+ if (!request.ParseFromString(ReceiveExBlock("ExRequest"))) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Incorrect THandshakeRequest");
+ }
+ ReportProto(request, "ReceiveExBlock ExRequest");
+
+ auto generateError = [this](TString msg) {
+ // issue reply to the peer to prevent repeating connection retries
+ NActorsInterconnect::THandshakeReply reply;
+ reply.SetErrorExplaination(msg);
+ SendExBlock(reply, "ExReply");
+
+ // terminate ths handshake
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, msg);
+ };
+
+ // check request cookie
+ TString error;
+ if (request.HasDoCheckCookie()) {
+ NActorsInterconnect::THandshakeReply reply;
+ reply.SetCookieCheckResult(request.GetCookie() == Common->Cookie);
+ SendExBlock(reply, "ExReplyDoCheckCookie");
+ throw TExHandshakeFailed();
+ } else if (request.HasCookie() && !CheckPeerCookie(request.GetCookie(), &error)) {
+ generateError(TStringBuilder() << "Peer connectivity-checking failed, error# " << error);
+ }
+
+ // update log prefix with the reported peer host name
+ PeerHostName = request.GetSenderHostName();
+
+ // parse peer virtual id
+ const auto& str = request.GetSenderActorId();
+ PeerVirtualId.Parse(str.data(), str.size());
+
+ // validate request
+ ValidateClusterUUID(request, generateError, request.GetUUID());
+ if (request.GetReceiverNodeId() != SelfActorId.NodeId()) {
+ generateError(Sprintf("Incorrect ReceiverNodeId# %" PRIu32 " from the peer, expected# %" PRIu32,
+ request.GetReceiverNodeId(), SelfActorId.NodeId()));
+ } else if (request.GetReceiverHostName() != Common->TechnicalSelfHostName) {
+ generateError(Sprintf("ReceiverHostName# %s mismatch, expected# %s", request.GetReceiverHostName().data(),
+ Common->TechnicalSelfHostName.data()));
+ }
+ ValidateVersionTag(request, generateError);
+
+ // check peer node
+ auto peerNodeInfo = GetPeerNodeInfo();
+ if (!peerNodeInfo) {
+ generateError("Peer node not registered in nameservice");
+ } else if (peerNodeInfo->Host != request.GetSenderHostName()) {
+ generateError("SenderHostName mismatch");
+ }
+
+ // check request against encryption
+ switch (Common->Settings.EncryptionMode) {
+ case EEncryptionMode::DISABLED:
+ if (request.GetRequireEncryption()) {
+ generateError("Peer requested encryption, but it is disabled locally");
+ }
+ break;
+
+ case EEncryptionMode::OPTIONAL:
+ Params.Encryption = request.HasRequireEncryption();
+ break;
+
+ case EEncryptionMode::REQUIRED:
+ if (!request.HasRequireEncryption()) {
+ generateError("Peer did not request encryption, but it is required locally");
+ }
+ Params.Encryption = true;
+ break;
+ }
+
+ Params.UseModernFrame = request.GetRequestModernFrame();
+ Params.AuthOnly = Params.Encryption && request.GetRequestAuthOnly() && Common->Settings.TlsAuthOnly;
+
+ if (request.HasClientScopeId()) {
+ ParsePeerScopeId(request.GetClientScopeId());
+ }
+
+ // remember program info (assuming successful handshake)
+ ProgramInfo = GetProgramInfo(request);
+
+ // send to proxy
+ auto reply = AskProxy<TEvHandshakeReplyOK, TEvHandshakeReplyError>(std::move(ev), "TEvHandshakeRequest");
+
+ // parse it
+ if (auto ev = reply->CastAsLocal<TEvHandshakeReplyOK>()) {
+ // issue successful reply to the peer
+ auto& record = ev->Record;
+ Y_VERIFY(record.HasSuccess());
+ auto& success = *record.MutableSuccess();
+ SetupClusterUUID(success);
+ SetupVersionTag(success);
+ success.SetStartEncryption(Params.Encryption);
+ if (Common->LocalScopeId != TScopeId()) {
+ FillInScopeId(*success.MutableServerScopeId());
+ }
+ success.SetUseModernFrame(Params.UseModernFrame);
+ success.SetAuthOnly(Params.AuthOnly);
+ SendExBlock(record, "ExReply");
+
+ // extract sender actor id (self virtual id)
+ const auto& str = success.GetSenderActorId();
+ SelfVirtualId.Parse(str.data(), str.size());
+ } else if (auto ev = reply->CastAsLocal<TEvHandshakeReplyError>()) {
+ // in case of error just send reply to the peer and terminate handshake
+ SendExBlock(ev->Record, "ExReply");
+ ProgramInfo.Clear(); // do not issue reply to the proxy
+ } else {
+ Y_FAIL("unexpected event Type# 0x%08" PRIx32, reply->GetTypeRewrite());
+ }
+ }
+ }
+
+ template <typename T>
+ void SendExBlock(const T& proto, const char* what) {
+ TString data;
+ Y_PROTOBUF_SUPPRESS_NODISCARD proto.SerializeToString(&data);
+ Y_VERIFY(data.size() <= TExHeader::MaxSize);
+
+ ReportProto(proto, Sprintf("SendExBlock %s", what).data());
+
+ TExHeader header;
+ header.Size = data.size();
+ header.Sign(data.data(), data.size());
+ SendData(&header, sizeof(header), Sprintf("Send%sHeader", what));
+ SendData(data.data(), data.size(), Sprintf("Send%sData", what));
+ }
+
+ TString ReceiveExBlock(const char* what) {
+ TExHeader header;
+ ReceiveData(&header, sizeof(header), Sprintf("Receive%sHeader", what));
+ if (header.Size > TExHeader::MaxSize) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "Incorrect extended header size");
+ }
+
+ TString data;
+ data.resize(header.Size);
+ ReceiveData(data.Detach(), data.size(), Sprintf("Receive%sData", what));
+
+ if (!header.Check(data.data(), data.size())) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_TRANSIENT, "Extended header CRC error");
+ }
+
+ return data;
+ }
+
+ private:
+ void SendToProxy(THolder<IEventBase> ev) {
+ Y_VERIFY(PeerNodeId);
+ Send(GetActorSystem()->InterconnectProxy(PeerNodeId), ev.Release());
+ }
+
+ template <typename TEvent>
+ THolder<typename TEvent::THandle> WaitForSpecificEvent(TString state, TInstant deadline = TInstant::Max()) {
+ State = std::move(state);
+ return TActorCoroImpl::WaitForSpecificEvent<TEvent>(deadline);
+ }
+
+ template <typename T1, typename T2, typename... TEvents>
+ THolder<IEventHandle> WaitForSpecificEvent(TString state, TInstant deadline = TInstant::Max()) {
+ State = std::move(state);
+ return TActorCoroImpl::WaitForSpecificEvent<T1, T2, TEvents...>(deadline);
+ }
+
+ template <typename TEvent>
+ THolder<typename TEvent::THandle> AskProxy(THolder<IEventBase> ev, TString state) {
+ SendToProxy(std::move(ev));
+ return WaitForSpecificEvent<TEvent>(std::move(state));
+ }
+
+ template <typename T1, typename T2, typename... TOther>
+ THolder<IEventHandle> AskProxy(THolder<IEventBase> ev, TString state) {
+ SendToProxy(std::move(ev));
+ return WaitForSpecificEvent<T1, T2, TOther...>(std::move(state));
+ }
+
+ void Fail(TEvHandshakeFail::EnumHandshakeFail reason, TString explanation, bool network = false) {
+ TString msg = Sprintf("%s Peer# %s(%s) %s%s", HandshakeKind.data(), PeerHostName ? PeerHostName.data() : "<unknown>",
+ PeerAddr.size() ? PeerAddr.data() : "<unknown>", ResolveTimedOut ? "[resolve timeout] " : "",
+ explanation.data());
+
+ if (network) {
+ TInstant now = Now();
+ TInstant prevLog = LastLogNotice[PeerNodeId];
+ NActors::NLog::EPriority logPriority = NActors::NLog::PRI_DEBUG;
+ if (now - prevLog > MuteDuration) {
+ logPriority = NActors::NLog::PRI_NOTICE;
+ LastLogNotice[PeerNodeId] = now;
+ }
+ LOG_LOG_NET_X(logPriority, PeerNodeId, "network-related error occured on handshake: %s", msg.data());
+ } else {
+ // calculate log severity based on failure type; permanent failures lead to error log messages
+ auto severity = reason == TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT
+ ? NActors::NLog::PRI_NOTICE
+ : NActors::NLog::PRI_INFO;
+
+ LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH03", severity, "handshake failed, explanation# %s", msg.data());
+ }
+
+ if (PeerNodeId) {
+ SendToProxy(MakeHolder<TEvHandshakeFail>(reason, std::move(msg)));
+ }
+
+ throw TExHandshakeFailed() << explanation;
+ }
+
+ private:
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // COMMUNICATION BLOCK
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ void Connect(bool updatePeerAddr) {
+ // issue request to a nameservice to resolve peer node address
+ Send(Common->NameserviceId, new TEvInterconnect::TEvResolveNode(PeerNodeId, Deadline));
+
+ // wait for the result
+ auto ev = WaitForSpecificEvent<TEvResolveError, TEvLocalNodeInfo, TEvInterconnect::TEvNodeAddress>("ResolveNode",
+ Now() + ResolveTimeout);
+
+ // extract address from the result
+ NInterconnect::TAddress address;
+ if (!ev) {
+ ResolveTimedOut = true;
+ if (auto peerNodeInfo = GetPeerNodeInfo(); peerNodeInfo && peerNodeInfo->Address) {
+ address = {peerNodeInfo->Address, peerNodeInfo->Port};
+ } else {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve timed out and no static address defined", true);
+ }
+ } else if (auto *p = ev->CastAsLocal<TEvLocalNodeInfo>()) {
+ if (!p->Address) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve error: no address returned", true);
+ }
+ address = {*p->Address};
+ } else if (auto *p = ev->CastAsLocal<TEvInterconnect::TEvNodeAddress>()) {
+ const auto& r = p->Record;
+ if (!r.HasAddress() || !r.HasPort()) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve error: no address returned", true);
+ }
+ address = {r.GetAddress(), static_cast<ui16>(r.GetPort())};
+ } else {
+ Y_VERIFY(ev->GetTypeRewrite() == ui32(ENetwork::ResolveError));
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "DNS resolve error: " + ev->Get<TEvResolveError>()->Explain, true);
+ }
+
+ // create the socket with matching address family
+ Socket = NInterconnect::TStreamSocket::Make(address.GetFamily());
+ if (*Socket == -1) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "System error: failed to create socket");
+ }
+
+ // extract peer address
+ if (updatePeerAddr) {
+ PeerAddr = address.ToString();
+ }
+
+ // set up socket parameters
+ SetupSocket();
+
+ // start connecting
+ switch (int err = -Socket->Connect(address)) {
+ case 0: // successful connection
+ break;
+
+ case EINPROGRESS: // connection in progress
+ WaitPoller(false, true, "WaitConnect");
+ err = Socket->GetConnectStatus();
+ if (err) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, Sprintf("Connection failed: %s", strerror(err)), true);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ auto it = LastLogNotice.find(PeerNodeId);
+ NActors::NLog::EPriority logPriority = NActors::NLog::PRI_DEBUG;
+ if (it != LastLogNotice.end()) {
+ LastLogNotice.erase(it);
+ logPriority = NActors::NLog::PRI_NOTICE;
+ }
+ LOG_LOG_IC_X(NActorsServices::INTERCONNECT, "ICH05", logPriority, "connected to peer");
+ }
+
+ void SetupSocket() {
+ // switch to nonblocking mode
+ try {
+ SetNonBlock(*Socket);
+ SetNoDelay(*Socket, true);
+ } catch (...) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT, "System error: can't up nonblocking mode for socket");
+ }
+
+ // setup send buffer size
+ Socket->SetSendBufferSize(Common->Settings.GetSendBufferSize());
+
+ // register in poller
+ RegisterInPoller();
+ }
+
+ void RegisterInPoller() {
+ const bool success = Send(MakePollerActorId(), new TEvPollerRegister(Socket, SelfActorId, SelfActorId));
+ Y_VERIFY(success);
+ auto result = WaitForSpecificEvent<TEvPollerRegisterResult>("RegisterPoller");
+ PollerToken = std::move(result->Get()->PollerToken);
+ Y_VERIFY(PollerToken);
+ Y_VERIFY(PollerToken->RefCount() == 1); // ensure exclusive ownership
+ }
+
+ void SendInitialPacket() {
+ TInitialPacket packet(SelfVirtualId, PeerVirtualId, NextPacketToPeer, INTERCONNECT_PROTOCOL_VERSION);
+ SendData(&packet, sizeof(packet), "SendInitialPacket");
+ }
+
+ void WaitPoller(bool read, bool write, TString state) {
+ PollerToken->Request(read, write);
+ WaitForSpecificEvent<TEvPollerReady>(std::move(state));
+ }
+
+ template <typename TDataPtr, typename TSendRecvFunc>
+ void Process(TDataPtr buffer, size_t len, TSendRecvFunc&& sendRecv, bool read, bool write, TString state) {
+ Y_VERIFY(Socket);
+ NInterconnect::TStreamSocket* sock = Socket.Get();
+ ssize_t (NInterconnect::TStreamSocket::*pfn)(TDataPtr, size_t, TString*) const = sendRecv;
+ size_t processed = 0;
+
+ auto error = [&](TString msg) {
+ Fail(TEvHandshakeFail::HANDSHAKE_FAIL_TRANSIENT, Sprintf("Socket error# %s state# %s processed# %zu remain# %zu",
+ msg.data(), state.data(), processed, len), true);
+ };
+
+ while (len) {
+ TString err;
+ ssize_t nbytes = (sock->*pfn)(buffer, len, &err);
+ if (nbytes > 0) {
+ buffer = (char*)buffer + nbytes;
+ len -= nbytes;
+ processed += nbytes;
+ } else if (-nbytes == EAGAIN || -nbytes == EWOULDBLOCK) {
+ WaitPoller(read, write, state);
+ } else if (!nbytes) {
+ error("connection unexpectedly closed");
+ } else if (-nbytes != EINTR) {
+ error(err ? err : TString(strerror(-nbytes)));
+ }
+ }
+ }
+
+ void SendData(const void* buffer, size_t len, TString state) {
+ Process(buffer, len, &NInterconnect::TStreamSocket::Send, false, true, std::move(state));
+ }
+
+ void ReceiveData(void* buffer, size_t len, TString state) {
+ Process(buffer, len, &NInterconnect::TStreamSocket::Recv, true, false, std::move(state));
+ }
+
+ THolder<TEvInterconnect::TNodeInfo> GetPeerNodeInfo() {
+ Y_VERIFY(PeerNodeId);
+ Send(Common->NameserviceId, new TEvInterconnect::TEvGetNode(PeerNodeId, Deadline));
+ auto response = WaitForSpecificEvent<TEvInterconnect::TEvNodeInfo>("GetPeerNodeInfo");
+ return std::move(response->Get()->Node);
+ }
+
+ template <typename T>
+ static THolder<TProgramInfo> GetProgramInfo(const T& proto) {
+ auto programInfo = MakeHolder<TProgramInfo>();
+ programInfo->PID = proto.GetProgramPID();
+ programInfo->StartTime = proto.GetProgramStartTime();
+ programInfo->Serial = proto.GetSerial();
+ return programInfo;
+ }
+ };
+
+ IActor* CreateOutgoingHandshakeActor(TInterconnectProxyCommon::TPtr common, const TActorId& self,
+ const TActorId& peer, ui32 nodeId, ui64 nextPacket, TString peerHostName,
+ TSessionParams params) {
+ return new TActorCoro(MakeHolder<THandshakeActor>(std::move(common), self, peer, nodeId, nextPacket,
+ std::move(peerHostName), std::move(params)));
+ }
+
+ IActor* CreateIncomingHandshakeActor(TInterconnectProxyCommon::TPtr common, TSocketPtr socket) {
+ return new TActorCoro(MakeHolder<THandshakeActor>(std::move(common), std::move(socket)));
+ }
+
+}
diff --git a/library/cpp/actors/interconnect/interconnect_handshake.h b/library/cpp/actors/interconnect/interconnect_handshake.h
new file mode 100644
index 0000000000..b3c0db6c5d
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_handshake.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/actors/core/event_pb.h>
+#include <library/cpp/actors/core/events.h>
+
+#include "interconnect_common.h"
+#include "interconnect_impl.h"
+#include "poller_tcp.h"
+#include "events_local.h"
+
+namespace NActors {
+ static constexpr TDuration DEFAULT_HANDSHAKE_TIMEOUT = TDuration::Seconds(1);
+ static constexpr ui64 INTERCONNECT_PROTOCOL_VERSION = 2;
+
+ using TSocketPtr = TIntrusivePtr<NInterconnect::TStreamSocket>;
+
+ IActor* CreateOutgoingHandshakeActor(TInterconnectProxyCommon::TPtr common, const TActorId& self,
+ const TActorId& peer, ui32 nodeId, ui64 nextPacket, TString peerHostName,
+ TSessionParams params);
+
+ IActor* CreateIncomingHandshakeActor(TInterconnectProxyCommon::TPtr common, TSocketPtr socket);
+
+}
diff --git a/library/cpp/actors/interconnect/interconnect_impl.h b/library/cpp/actors/interconnect/interconnect_impl.h
new file mode 100644
index 0000000000..ee29e4d397
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_impl.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include "interconnect.h"
+#include <library/cpp/actors/protos/interconnect.pb.h>
+#include <library/cpp/actors/core/event_pb.h>
+#include <library/cpp/actors/helpers/mon_histogram_helper.h>
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+
+namespace NActors {
+ // resolve node info
+ struct TEvInterconnect::TEvResolveNode: public TEventPB<TEvInterconnect::TEvResolveNode, NActorsInterconnect::TEvResolveNode, TEvInterconnect::EvResolveNode> {
+ TEvResolveNode() {
+ }
+
+ TEvResolveNode(ui32 nodeId, TInstant deadline = TInstant::Max()) {
+ Record.SetNodeId(nodeId);
+ if (deadline != TInstant::Max()) {
+ Record.SetDeadline(deadline.GetValue());
+ }
+ }
+ };
+
+ // node info
+ struct TEvInterconnect::TEvNodeAddress: public TEventPB<TEvInterconnect::TEvNodeAddress, NActorsInterconnect::TEvNodeInfo, TEvInterconnect::EvNodeAddress> {
+ TEvNodeAddress() {
+ }
+
+ TEvNodeAddress(ui32 nodeId) {
+ Record.SetNodeId(nodeId);
+ }
+ };
+
+ // register node
+ struct TEvInterconnect::TEvRegisterNode: public TEventBase<TEvInterconnect::TEvRegisterNode, TEvInterconnect::EvRegisterNode> {
+ };
+
+ // reply on register node
+ struct TEvInterconnect::TEvRegisterNodeResult: public TEventBase<TEvInterconnect::TEvRegisterNodeResult, TEvInterconnect::EvRegisterNodeResult> {
+ };
+
+ // disconnect
+ struct TEvInterconnect::TEvDisconnect: public TEventLocal<TEvInterconnect::TEvDisconnect, TEvInterconnect::EvDisconnect> {
+ };
+
+}
diff --git a/library/cpp/actors/interconnect/interconnect_mon.cpp b/library/cpp/actors/interconnect/interconnect_mon.cpp
new file mode 100644
index 0000000000..cf924ccbf9
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_mon.cpp
@@ -0,0 +1,276 @@
+#include "interconnect_mon.h"
+#include "interconnect_tcp_proxy.h"
+
+#include <library/cpp/json/json_value.h>
+#include <library/cpp/json/json_writer.h>
+#include <library/cpp/monlib/service/pages/templates.h>
+
+#include <openssl/ssl.h>
+#include <openssl/pem.h>
+
+namespace NInterconnect {
+
+ using namespace NActors;
+
+ class TInterconnectMonActor : public TActor<TInterconnectMonActor> {
+ class TQueryProcessor : public TActorBootstrapped<TQueryProcessor> {
+ const TActorId Sender;
+ const bool Json;
+ TMap<ui32, TInterconnectProxyTCP::TProxyStats> Stats;
+ ui32 PendingReplies = 0;
+
+ public:
+ static constexpr IActor::EActorActivity ActorActivityType() {
+ return INTERCONNECT_MONACTOR;
+ }
+
+ TQueryProcessor(const TActorId& sender, bool json)
+ : Sender(sender)
+ , Json(json)
+ {}
+
+ void Bootstrap(const TActorContext& ctx) {
+ Become(&TThis::StateFunc, ctx, TDuration::Seconds(5), new TEvents::TEvWakeup);
+ Send(GetNameserviceActorId(), new TEvInterconnect::TEvListNodes);
+ }
+
+ void Handle(TEvInterconnect::TEvNodesInfo::TPtr ev, const TActorContext& ctx) {
+ TActorSystem* const as = ctx.ExecutorThread.ActorSystem;
+ for (const auto& node : ev->Get()->Nodes) {
+ Send(as->InterconnectProxy(node.NodeId), new TInterconnectProxyTCP::TEvQueryStats, IEventHandle::FlagTrackDelivery);
+ ++PendingReplies;
+ }
+ GenerateResultWhenReady(ctx);
+ }
+
+ STRICT_STFUNC(StateFunc,
+ HFunc(TEvInterconnect::TEvNodesInfo, Handle)
+ HFunc(TInterconnectProxyTCP::TEvStats, Handle)
+ CFunc(TEvents::TSystem::Undelivered, HandleUndelivered)
+ CFunc(TEvents::TSystem::Wakeup, HandleWakeup)
+ )
+
+ void Handle(TInterconnectProxyTCP::TEvStats::TPtr& ev, const TActorContext& ctx) {
+ auto *msg = ev->Get();
+ Stats.emplace(msg->PeerNodeId, std::move(msg->ProxyStats));
+ --PendingReplies;
+ GenerateResultWhenReady(ctx);
+ }
+
+ void HandleUndelivered(const TActorContext& ctx) {
+ --PendingReplies;
+ GenerateResultWhenReady(ctx);
+ }
+
+ void HandleWakeup(const TActorContext& ctx) {
+ PendingReplies = 0;
+ GenerateResultWhenReady(ctx);
+ }
+
+ void GenerateResultWhenReady(const TActorContext& ctx) {
+ if (!PendingReplies) {
+ if (Json) {
+ ctx.Send(Sender, new NMon::TEvHttpInfoRes(GenerateJson(), 0, NMon::IEvHttpInfoRes::EContentType::Custom));
+ } else {
+ ctx.Send(Sender, new NMon::TEvHttpInfoRes(GenerateHtml()));
+ }
+ Die(ctx);
+ }
+ }
+
+ TString GenerateHtml() {
+ TStringStream str;
+ HTML(str) {
+ TABLE_CLASS("table-sortable table") {
+ TABLEHEAD() {
+ TABLER() {
+ TABLEH() { str << "Peer node id"; }
+ TABLEH() { str << "State"; }
+ TABLEH() { str << "Ping"; }
+ TABLEH() { str << "Clock skew"; }
+ TABLEH() { str << "Scope id"; }
+ TABLEH() { str << "Encryption"; }
+ TABLEH() { str << "LastSessionDieTime"; }
+ TABLEH() { str << "TotalOutputQueueSize"; }
+ TABLEH() { str << "Connected"; }
+ TABLEH() { str << "Host"; }
+ TABLEH() { str << "Port"; }
+ TABLEH() { str << "LastErrorTimestamp"; }
+ TABLEH() { str << "LastErrorKind"; }
+ TABLEH() { str << "LastErrorExplanation"; }
+ }
+ }
+ TABLEBODY() {
+ for (const auto& kv : Stats) {
+ TABLER() {
+ TABLED() { str << "<a href='" << kv.second.Path << "'>" << kv.first << "</a>"; }
+ TABLED() { str << kv.second.State; }
+ TABLED() {
+ if (kv.second.Ping != TDuration::Zero()) {
+ str << kv.second.Ping;
+ }
+ }
+ TABLED() {
+ if (kv.second.ClockSkew < 0) {
+ str << "-" << TDuration::MicroSeconds(-kv.second.ClockSkew);
+ } else {
+ str << "+" << TDuration::MicroSeconds(kv.second.ClockSkew);
+ }
+ }
+ TABLED() { str << ScopeIdToString(kv.second.PeerScopeId); }
+ TABLED() {
+ const char *color = kv.second.Encryption != "none" ? "green" : "red";
+ str << "<font color='" << color << "'>" << kv.second.Encryption << "</font>";
+ }
+ TABLED() {
+ if (kv.second.LastSessionDieTime != TInstant::Zero()) {
+ str << kv.second.LastSessionDieTime;
+ }
+ }
+ TABLED() { str << kv.second.TotalOutputQueueSize; }
+ TABLED() { str << (kv.second.Connected ? "yes" : "<strong>no</strong>"); }
+ TABLED() { str << kv.second.Host; }
+ TABLED() { str << kv.second.Port; }
+ TABLED() {
+ str << "<strong>";
+ if (kv.second.LastErrorTimestamp != TInstant::Zero()) {
+ str << kv.second.LastErrorTimestamp;
+ }
+ str << "</strong>";
+ }
+ TABLED() { str << "<strong>" << kv.second.LastErrorKind << "</strong>"; }
+ TABLED() { str << "<strong>" << kv.second.LastErrorExplanation << "</strong>"; }
+ }
+ }
+ }
+ }
+ }
+ return str.Str();
+ }
+
+ TString GenerateJson() {
+ NJson::TJsonValue json;
+ for (const auto& [nodeId, info] : Stats) {
+ NJson::TJsonValue item;
+ item["NodeId"] = nodeId;
+
+ auto id = [](const auto& x) { return x; };
+ auto toString = [](const auto& x) { return x.ToString(); };
+
+#define JSON(NAME, FUN) item[#NAME] = FUN(info.NAME);
+ JSON(Path, id)
+ JSON(State, id)
+ JSON(PeerScopeId, ScopeIdToString)
+ JSON(LastSessionDieTime, toString)
+ JSON(TotalOutputQueueSize, id)
+ JSON(Connected, id)
+ JSON(Host, id)
+ JSON(Port, id)
+ JSON(LastErrorTimestamp, toString)
+ JSON(LastErrorKind, id)
+ JSON(LastErrorExplanation, id)
+ JSON(Ping, toString)
+ JSON(ClockSkew, id)
+ JSON(Encryption, id)
+#undef JSON
+
+ json[ToString(nodeId)] = item;
+ }
+ TStringStream str(NMonitoring::HTTPOKJSON);
+ NJson::WriteJson(&str, &json);
+ return str.Str();
+ }
+ };
+
+ private:
+ TIntrusivePtr<TInterconnectProxyCommon> Common;
+
+ public:
+ static constexpr IActor::EActorActivity ActorActivityType() {
+ return INTERCONNECT_MONACTOR;
+ }
+
+ TInterconnectMonActor(TIntrusivePtr<TInterconnectProxyCommon> common)
+ : TActor(&TThis::StateFunc)
+ , Common(std::move(common))
+ {}
+
+ STRICT_STFUNC(StateFunc,
+ HFunc(NMon::TEvHttpInfo, Handle)
+ )
+
+ void Handle(NMon::TEvHttpInfo::TPtr& ev, const TActorContext& ctx) {
+ const auto& params = ev->Get()->Request.GetParams();
+ int certinfo = 0;
+ if (TryFromString(params.Get("certinfo"), certinfo) && certinfo) {
+ ctx.Send(ev->Sender, new NMon::TEvHttpInfoRes(GetCertInfoJson(), ev->Get()->SubRequestId,
+ NMon::TEvHttpInfoRes::Custom));
+ } else {
+ const bool json = params.Has("fmt") && params.Get("fmt") == "json";
+ ctx.Register(new TQueryProcessor(ev->Sender, json));
+ }
+ }
+
+ TString GetCertInfoJson() const {
+ NJson::TJsonValue json(NJson::JSON_MAP);
+ if (const TString cert = Common ? Common->Settings.Certificate : TString()) {
+ struct TEx : yexception {};
+ try {
+ const auto& cert = Common->Settings.Certificate;
+ std::unique_ptr<BIO, void(*)(BIO*)> bio(BIO_new_mem_buf(cert.data(), cert.size()), &BIO_vfree);
+ if (!bio) {
+ throw TEx() << "BIO_new_mem_buf failed";
+ }
+ std::unique_ptr<X509, void(*)(X509*)> x509(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr),
+ &X509_free);
+ if (!x509) {
+ throw TEx() << "PEM_read_bio_X509 failed";
+ }
+ X509_NAME *name = X509_get_subject_name(x509.get());
+ if (!name) {
+ throw TEx() << "X509_get_subject_name failed";
+ }
+ char buffer[4096];
+ if (char *p = X509_NAME_oneline(name, buffer, sizeof(buffer))) {
+ json["Subject"] = p;
+ }
+ if (int loc = X509_NAME_get_index_by_NID(name, NID_commonName, -1); loc >= 0) {
+ if (X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, loc)) {
+ if (ASN1_STRING *data = X509_NAME_ENTRY_get_data(entry)) {
+ unsigned char *cn;
+ if (const int len = ASN1_STRING_to_UTF8(&cn, data); len >= 0) {
+ json["CommonName"] = TString(reinterpret_cast<char*>(cn), len);
+ OPENSSL_free(cn);
+ }
+ }
+ }
+ }
+ auto time = [](const ASN1_TIME *t, const char *name) -> TString {
+ if (t) {
+ struct tm tm;
+ if (ASN1_TIME_to_tm(t, &tm)) {
+ return Strftime("%Y-%m-%dT%H:%M:%S%z", &tm);
+ } else {
+ throw TEx() << "ASN1_TIME_to_tm failed";
+ }
+ } else {
+ throw TEx() << name << " failed";
+ }
+ };
+ json["NotBefore"] = time(X509_get0_notBefore(x509.get()), "X509_get0_notBefore");
+ json["NotAfter"] = time(X509_get0_notAfter(x509.get()), "X509_get0_notAfter");
+ } catch (const TEx& ex) {
+ json["Error"] = ex.what();
+ }
+ }
+ TStringStream str(NMonitoring::HTTPOKJSON);
+ NJson::WriteJson(&str, &json);
+ return str.Str();
+ }
+ };
+
+ IActor *CreateInterconnectMonActor(TIntrusivePtr<TInterconnectProxyCommon> common) {
+ return new TInterconnectMonActor(std::move(common));
+ }
+
+} // NInterconnect
diff --git a/library/cpp/actors/interconnect/interconnect_mon.h b/library/cpp/actors/interconnect/interconnect_mon.h
new file mode 100644
index 0000000000..3fb26053fb
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_mon.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <library/cpp/actors/core/actor.h>
+#include "interconnect_common.h"
+
+namespace NInterconnect {
+
+ NActors::IActor *CreateInterconnectMonActor(TIntrusivePtr<NActors::TInterconnectProxyCommon> common = nullptr);
+
+ static inline NActors::TActorId MakeInterconnectMonActorId(ui32 nodeId) {
+ char s[12] = {'I', 'C', 'O', 'v', 'e', 'r', 'v', 'i', 'e', 'w', 0, 0};
+ return NActors::TActorId(nodeId, TStringBuf(s, 12));
+ }
+
+} // NInterconnect
diff --git a/library/cpp/actors/interconnect/interconnect_nameserver_base.h b/library/cpp/actors/interconnect/interconnect_nameserver_base.h
new file mode 100644
index 0000000000..df614f6c2b
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_nameserver_base.h
@@ -0,0 +1,83 @@
+#include "interconnect.h"
+#include "interconnect_impl.h"
+#include "interconnect_address.h"
+#include "events_local.h"
+
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/actors/memory_log/memlog.h>
+
+namespace NActors {
+
+ template<typename TDerived>
+ class TInterconnectNameserverBase : public TActor<TDerived> {
+ protected:
+ const TMap<ui32, TTableNameserverSetup::TNodeInfo>& NodeTable;
+
+ TInterconnectNameserverBase(void (TDerived::*func)(TAutoPtr<IEventHandle>& ev, const TActorContext& ctx)
+ , const TMap<ui32, TTableNameserverSetup::TNodeInfo>& nodeTable)
+ : TActor<TDerived>(func)
+ , NodeTable(nodeTable)
+ {
+ }
+ public:
+
+ void HandleMissedNodeId(TEvInterconnect::TEvResolveNode::TPtr& ev,
+ const TActorContext& ctx,
+ const TInstant&) {
+ auto reply = new TEvLocalNodeInfo;
+ reply->NodeId = ev->Get()->Record.GetNodeId();
+ ctx.Send(ev->Sender, reply);
+ }
+
+ void Handle(TEvInterconnect::TEvResolveNode::TPtr& ev,
+ const TActorContext& ctx) {
+ const TEvInterconnect::TEvResolveNode* request = ev->Get();
+ auto& record = request->Record;
+ const ui32 nodeId = record.GetNodeId();
+ const TInstant deadline = record.HasDeadline() ? TInstant::FromValue(record.GetDeadline()) : TInstant::Max();
+ auto it = NodeTable.find(nodeId);
+
+ if (it == NodeTable.end()) {
+ static_cast<TDerived*>(this)->HandleMissedNodeId(ev, ctx, deadline);
+ } else {
+ IActor::RegisterWithSameMailbox(
+ CreateResolveActor(nodeId, it->second, ev->Sender, this->SelfId(), deadline));
+ }
+ }
+
+ void Handle(TEvResolveAddress::TPtr& ev,
+ const TActorContext&) {
+ const TEvResolveAddress* request = ev->Get();
+
+ IActor::RegisterWithSameMailbox(
+ CreateResolveActor(request->Address, request->Port, ev->Sender, this->SelfId(), TInstant::Max()));
+ }
+
+ void Handle(TEvInterconnect::TEvListNodes::TPtr& ev,
+ const TActorContext& ctx) {
+ THolder<TEvInterconnect::TEvNodesInfo>
+ reply(new TEvInterconnect::TEvNodesInfo());
+ reply->Nodes.reserve(NodeTable.size());
+ for (const auto& pr : NodeTable) {
+ reply->Nodes.emplace_back(pr.first,
+ pr.second.Address, pr.second.Host, pr.second.ResolveHost,
+ pr.second.Port, pr.second.Location);
+ }
+ ctx.Send(ev->Sender, reply.Release());
+ }
+
+ void Handle(TEvInterconnect::TEvGetNode::TPtr& ev,
+ const TActorContext& ctx) {
+ ui32 nodeId = ev->Get()->NodeId;
+ THolder<TEvInterconnect::TEvNodeInfo>
+ reply(new TEvInterconnect::TEvNodeInfo(nodeId));
+ auto it = NodeTable.find(nodeId);
+ if (it != NodeTable.end()) {
+ reply->Node = MakeHolder<TEvInterconnect::TNodeInfo>(it->first, it->second.Address,
+ it->second.Host, it->second.ResolveHost,
+ it->second.Port, it->second.Location);
+ }
+ ctx.Send(ev->Sender, reply.Release());
+ }
+ };
+}
diff --git a/library/cpp/actors/interconnect/interconnect_nameserver_dynamic.cpp b/library/cpp/actors/interconnect/interconnect_nameserver_dynamic.cpp
new file mode 100644
index 0000000000..5e48401b14
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_nameserver_dynamic.cpp
@@ -0,0 +1,178 @@
+#include "interconnect.h"
+#include "interconnect_impl.h"
+#include "interconnect_address.h"
+#include "interconnect_nameserver_base.h"
+#include "events_local.h"
+#include "logging.h"
+
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/actors/core/log.h>
+
+namespace NActors {
+
+ class TInterconnectDynamicNameserver
+ : public TInterconnectNameserverBase<TInterconnectDynamicNameserver>
+ , public TInterconnectLoggingBase
+ {
+ struct TPendingRequest {
+ TEvInterconnect::TEvResolveNode::TPtr Request;
+ TInstant Deadline;
+
+ TPendingRequest(TEvInterconnect::TEvResolveNode::TPtr request, const TInstant& deadline)
+ : Request(request), Deadline(deadline)
+ {
+ }
+ };
+
+ TMap<ui32, TTableNameserverSetup::TNodeInfo> NodeTable;
+ TVector<TPendingRequest> PendingRequests;
+ TDuration PendingPeriod;
+
+ void PrintInfo() {
+ TString logMsg = TStringBuilder() << "Table size: " << NodeTable.size();
+ for (const auto& [nodeId, node] : NodeTable) {
+ TString str = TStringBuilder() << "\n > Node " << nodeId << " `" << node.Address << "`:" << node.Port << ", host: " << node.Host << ", resolveHost: " << node.ResolveHost;
+ logMsg += str;
+ }
+ LOG_DEBUG_IC("ICN01", "%s", logMsg.c_str());
+ }
+
+ bool IsNodeUpdated(const ui32 nodeId, const TString& address, const ui32 port) {
+ bool printInfo = false;
+ auto it = NodeTable.find(nodeId);
+ if (it == NodeTable.end()) {
+ LOG_DEBUG_IC("ICN02", "New node %u `%s`: %u",
+ nodeId, address.c_str(), port);
+ printInfo = true;
+ } else if (it->second.Address != address || it->second.Port != port) {
+ LOG_DEBUG_IC("ICN03", "Updated node %u `%s`: %u (from `%s`: %u)",
+ nodeId, address.c_str(), port, it->second.Address.c_str(), it->second.Port);
+ printInfo = true;
+ Send(TActivationContext::InterconnectProxy(nodeId), new TEvInterconnect::TEvDisconnect);
+ }
+ return printInfo;
+ }
+
+ void DiscardTimedOutRequests(const TActorContext& ctx, ui32 compactionCount = 0) {
+
+ auto now = Now();
+
+ for (auto& pending : PendingRequests) {
+ if (pending.Deadline > now) {
+ LOG_ERROR_IC("ICN06", "Unknown nodeId: %u", pending.Request->Get()->Record.GetNodeId());
+ auto reply = new TEvLocalNodeInfo;
+ reply->NodeId = pending.Request->Get()->Record.GetNodeId();
+ ctx.Send(pending.Request->Sender, reply);
+ pending.Request.Reset();
+ compactionCount++;
+ }
+ }
+
+ if (compactionCount) {
+ TVector<TPendingRequest> requests;
+ if (compactionCount < PendingRequests.size()) { // sanity check
+ requests.reserve(PendingRequests.size() - compactionCount);
+ }
+ for (auto& pending : PendingRequests) {
+ if (pending.Request) {
+ requests.emplace_back(pending.Request, pending.Deadline);
+ }
+ }
+ PendingRequests.swap(requests);
+ }
+ }
+
+ void SchedulePeriodic() {
+ Schedule(TDuration::MilliSeconds(200), new TEvents::TEvWakeup());
+ }
+
+ public:
+ static constexpr EActivityType ActorActivityType() {
+ return NAMESERVICE;
+ }
+
+ TInterconnectDynamicNameserver(const TIntrusivePtr<TTableNameserverSetup>& setup, const TDuration& pendingPeriod, ui32 /*resolvePoolId*/ )
+ : TInterconnectNameserverBase<TInterconnectDynamicNameserver>(&TInterconnectDynamicNameserver::StateFunc, NodeTable)
+ , NodeTable(setup->StaticNodeTable)
+ , PendingPeriod(pendingPeriod)
+ {
+ Y_VERIFY(setup->IsEntriesUnique());
+ }
+
+ STFUNC(StateFunc) {
+ try {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TEvInterconnect::TEvResolveNode, Handle);
+ HFunc(TEvResolveAddress, Handle);
+ HFunc(TEvInterconnect::TEvListNodes, Handle);
+ HFunc(TEvInterconnect::TEvGetNode, Handle);
+ HFunc(TEvInterconnect::TEvNodesInfo, HandleUpdate);
+ CFunc(TEvents::TEvWakeup::EventType, HandlePeriodic);
+ }
+ } catch (...) {
+ LOG_ERROR_IC("ICN09", "%s", CurrentExceptionMessage().c_str());
+ }
+ }
+
+ void HandleMissedNodeId(TEvInterconnect::TEvResolveNode::TPtr& ev,
+ const TActorContext& ctx,
+ const TInstant& deadline) {
+ if (PendingPeriod) {
+ if (PendingRequests.size() == 0) {
+ SchedulePeriodic();
+ }
+ PendingRequests.emplace_back(std::move(ev), Min(deadline, Now() + PendingPeriod));
+ } else {
+ LOG_ERROR_IC("ICN07", "Unknown nodeId: %u", ev->Get()->Record.GetNodeId());
+ TInterconnectNameserverBase::HandleMissedNodeId(ev, ctx, deadline);
+ }
+ }
+
+ void HandleUpdate(TEvInterconnect::TEvNodesInfo::TPtr& ev,
+ const TActorContext& ctx) {
+
+ auto request = ev->Get();
+ LOG_DEBUG_IC("ICN04", "Update TEvNodesInfo with sz: %lu ", request->Nodes.size());
+
+ bool printInfo = false;
+ ui32 compactionCount = 0;
+
+ for (const auto& node : request->Nodes) {
+ printInfo |= IsNodeUpdated(node.NodeId, node.Address, node.Port);
+
+ NodeTable[node.NodeId] = TTableNameserverSetup::TNodeInfo(
+ node.Address, node.Host, node.ResolveHost, node.Port, node.Location);
+
+ for (auto& pending : PendingRequests) {
+ if (pending.Request->Get()->Record.GetNodeId() == node.NodeId) {
+ LOG_DEBUG_IC("ICN05", "Pending nodeId: %u discovered", node.NodeId);
+ RegisterWithSameMailbox(
+ CreateResolveActor(node.NodeId, NodeTable[node.NodeId], pending.Request->Sender, SelfId(), pending.Deadline));
+ pending.Request.Reset();
+ compactionCount++;
+ }
+ }
+ }
+
+ if (printInfo) {
+ PrintInfo();
+ }
+
+ DiscardTimedOutRequests(ctx, compactionCount);
+ }
+
+ void HandlePeriodic(const TActorContext& ctx) {
+ DiscardTimedOutRequests(ctx, 0);
+ if (PendingRequests.size()) {
+ SchedulePeriodic();
+ }
+ }
+ };
+
+ IActor* CreateDynamicNameserver(const TIntrusivePtr<TTableNameserverSetup>& setup,
+ const TDuration& pendingPeriod,
+ ui32 poolId) {
+ return new TInterconnectDynamicNameserver(setup, pendingPeriod, poolId);
+ }
+
+}
diff --git a/library/cpp/actors/interconnect/interconnect_nameserver_table.cpp b/library/cpp/actors/interconnect/interconnect_nameserver_table.cpp
new file mode 100644
index 0000000000..43419bf70d
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_nameserver_table.cpp
@@ -0,0 +1,86 @@
+#include "interconnect.h"
+#include "interconnect_impl.h"
+#include "interconnect_address.h"
+#include "interconnect_nameserver_base.h"
+#include "events_local.h"
+
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/actors/memory_log/memlog.h>
+
+namespace NActors {
+
+ class TInterconnectNameserverTable: public TInterconnectNameserverBase<TInterconnectNameserverTable> {
+ TIntrusivePtr<TTableNameserverSetup> Config;
+
+ public:
+ static constexpr EActivityType ActorActivityType() {
+ return NAMESERVICE;
+ }
+
+ TInterconnectNameserverTable(const TIntrusivePtr<TTableNameserverSetup>& setup, ui32 /*resolvePoolId*/)
+ : TInterconnectNameserverBase<TInterconnectNameserverTable>(&TInterconnectNameserverTable::StateFunc, setup->StaticNodeTable)
+ , Config(setup)
+ {
+ Y_VERIFY(Config->IsEntriesUnique());
+ }
+
+ STFUNC(StateFunc) {
+ try {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TEvInterconnect::TEvResolveNode, Handle);
+ HFunc(TEvResolveAddress, Handle);
+ HFunc(TEvInterconnect::TEvListNodes, Handle);
+ HFunc(TEvInterconnect::TEvGetNode, Handle);
+ }
+ } catch (...) {
+ // on error - do nothing
+ }
+ }
+ };
+
+ IActor* CreateNameserverTable(const TIntrusivePtr<TTableNameserverSetup>& setup, ui32 poolId) {
+ return new TInterconnectNameserverTable(setup, poolId);
+ }
+
+ bool TTableNameserverSetup::IsEntriesUnique() const {
+ TVector<const TNodeInfo*> infos;
+ infos.reserve(StaticNodeTable.size());
+ for (const auto& x : StaticNodeTable)
+ infos.push_back(&x.second);
+
+ auto CompareAddressLambda =
+ [](const TNodeInfo* left, const TNodeInfo* right) {
+ return left->Port == right->Port ? left->Address < right->Address : left->Port < right->Port;
+ };
+
+ Sort(infos, CompareAddressLambda);
+
+ for (ui32 idx = 1, end = StaticNodeTable.size(); idx < end; ++idx) {
+ const TNodeInfo* left = infos[idx - 1];
+ const TNodeInfo* right = infos[idx];
+ if (left->Address && left->Address == right->Address && left->Port == right->Port)
+ return false;
+ }
+
+ auto CompareHostLambda =
+ [](const TNodeInfo* left, const TNodeInfo* right) {
+ return left->Port == right->Port ? left->ResolveHost < right->ResolveHost : left->Port < right->Port;
+ };
+
+ Sort(infos, CompareHostLambda);
+
+ for (ui32 idx = 1, end = StaticNodeTable.size(); idx < end; ++idx) {
+ const TNodeInfo* left = infos[idx - 1];
+ const TNodeInfo* right = infos[idx];
+ if (left->ResolveHost == right->ResolveHost && left->Port == right->Port)
+ return false;
+ }
+
+ return true;
+ }
+
+ TActorId GetNameserviceActorId() {
+ return TActorId(0, "namesvc");
+ }
+
+}
diff --git a/library/cpp/actors/interconnect/interconnect_proxy_wrapper.cpp b/library/cpp/actors/interconnect/interconnect_proxy_wrapper.cpp
new file mode 100644
index 0000000000..1c44b4c59b
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_proxy_wrapper.cpp
@@ -0,0 +1,47 @@
+#include "interconnect_proxy_wrapper.h"
+#include "interconnect_tcp_proxy.h"
+#include <library/cpp/actors/interconnect/mock/ic_mock.h>
+
+namespace NActors {
+
+ class TInterconnectProxyWrapper : public IActor {
+ TIntrusivePtr<TInterconnectProxyCommon> Common;
+ const ui32 NodeId;
+ TInterconnectMock *Mock;
+ IActor *Proxy = nullptr;
+
+ public:
+ TInterconnectProxyWrapper(TIntrusivePtr<TInterconnectProxyCommon> common, ui32 nodeId, TInterconnectMock *mock)
+ : IActor(static_cast<TReceiveFunc>(&TInterconnectProxyWrapper::StateFunc), INTERCONNECT_PROXY_WRAPPER)
+ , Common(std::move(common))
+ , NodeId(nodeId)
+ , Mock(mock)
+ {}
+
+ STFUNC(StateFunc) {
+ if (ev->GetTypeRewrite() == TEvents::TSystem::Poison && !Proxy) {
+ PassAway();
+ } else {
+ if (!Proxy) {
+ IActor *actor = Mock
+ ? Mock->CreateProxyMock(TActivationContext::ActorSystem()->NodeId, NodeId, Common)
+ : new TInterconnectProxyTCP(NodeId, Common, &Proxy);
+ RegisterWithSameMailbox(actor);
+ if (Mock) {
+ Proxy = actor;
+ }
+ Y_VERIFY(Proxy);
+ }
+ InvokeOtherActor(*Proxy, &IActor::Receive, ev, ctx);
+ }
+ }
+ };
+
+ TProxyWrapperFactory CreateProxyWrapperFactory(TIntrusivePtr<TInterconnectProxyCommon> common, ui32 poolId,
+ TInterconnectMock *mock) {
+ return [=](TActorSystem *as, ui32 nodeId) -> TActorId {
+ return as->Register(new TInterconnectProxyWrapper(common, nodeId, mock), TMailboxType::HTSwap, poolId);
+ };
+ }
+
+} // NActors
diff --git a/library/cpp/actors/interconnect/interconnect_proxy_wrapper.h b/library/cpp/actors/interconnect/interconnect_proxy_wrapper.h
new file mode 100644
index 0000000000..e5942351a7
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_proxy_wrapper.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "interconnect_common.h"
+
+#include <library/cpp/actors/core/actorsystem.h>
+
+namespace NActors {
+
+ TProxyWrapperFactory CreateProxyWrapperFactory(TIntrusivePtr<TInterconnectProxyCommon> common, ui32 poolId,
+ class TInterconnectMock *mock = nullptr);
+
+}
diff --git a/library/cpp/actors/interconnect/interconnect_resolve.cpp b/library/cpp/actors/interconnect/interconnect_resolve.cpp
new file mode 100644
index 0000000000..14296194df
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_resolve.cpp
@@ -0,0 +1,174 @@
+#include "interconnect.h"
+#include "interconnect_address.h"
+#include "events_local.h"
+
+#include <library/cpp/actors/core/actor_bootstrapped.h>
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/actors/dnsresolver/dnsresolver.h>
+
+namespace NActors {
+
+ using namespace NActors::NDnsResolver;
+
+ class TInterconnectResolveActor : public TActorBootstrapped<TInterconnectResolveActor> {
+ public:
+ TInterconnectResolveActor(
+ const TString& host, ui16 port, ui32 nodeId, const TString& defaultAddress,
+ const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
+ : Host(host)
+ , NodeId(nodeId)
+ , Port(port)
+ , DefaultAddress(defaultAddress)
+ , ReplyTo(replyTo)
+ , ReplyFrom(replyFrom)
+ , Deadline(deadline)
+ { }
+
+ TInterconnectResolveActor(
+ const TString& host, ui16 port,
+ const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
+ : Host(host)
+ , Port(port)
+ , ReplyTo(replyTo)
+ , ReplyFrom(replyFrom)
+ , Deadline(deadline)
+ { }
+
+ static constexpr EActivityType ActorActivityType() {
+ return NAMESERVICE;
+ }
+
+ void Bootstrap() {
+ TMaybe<TString> errorText;
+ if (auto addr = ExtractDefaultAddr(errorText)) {
+ return SendAddrAndDie(std::move(addr));
+ }
+
+ if (errorText) {
+ SendErrorAndDie(*errorText);
+ }
+
+ auto now = TActivationContext::Now();
+ if (Deadline < now) {
+ SendErrorAndDie("Deadline");
+ return;
+ }
+
+ Send(MakeDnsResolverActorId(),
+ new TEvDns::TEvGetAddr(Host, AF_UNSPEC),
+ IEventHandle::FlagTrackDelivery);
+
+ if (Deadline != TInstant::Max()) {
+ Schedule(Deadline, new TEvents::TEvWakeup);
+ }
+
+ Become(&TThis::StateWork);
+ }
+
+ STRICT_STFUNC(StateWork, {
+ sFunc(TEvents::TEvWakeup, HandleTimeout);
+ sFunc(TEvents::TEvUndelivered, HandleUndelivered);
+ hFunc(TEvDns::TEvGetAddrResult, Handle);
+ });
+
+ void HandleTimeout() {
+ SendErrorAndDie("Deadline");
+ }
+
+ void HandleUndelivered() {
+ SendErrorAndDie("Dns resolver is unavailable");
+ }
+
+ void Handle(TEvDns::TEvGetAddrResult::TPtr& ev) {
+ if (auto addr = ExtractAddr(ev->Get())) {
+ return SendAddrAndDie(std::move(addr));
+ }
+
+ SendErrorAndDie(ev->Get()->ErrorText);
+ }
+
+ void SendAddrAndDie(NAddr::IRemoteAddrPtr addr) {
+ if (NodeId) {
+ auto reply = new TEvLocalNodeInfo;
+ reply->NodeId = *NodeId;
+ reply->Address = std::move(addr);
+ TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, reply));
+ } else {
+ auto reply = new TEvAddressInfo;
+ reply->Address = std::move(addr);
+ TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, reply));
+ }
+ PassAway();
+ }
+
+ void SendErrorAndDie(const TString& errorText) {
+ auto *event = new TEvResolveError;
+ event->Explain = errorText;
+ TActivationContext::Send(new IEventHandle(ReplyTo, ReplyFrom, event));
+ PassAway();
+ }
+
+ NAddr::IRemoteAddrPtr ExtractAddr(TEvDns::TEvGetAddrResult* msg) {
+ if (msg->Status == 0) {
+ if (msg->IsV6()) {
+ struct sockaddr_in6 sin6;
+ Zero(sin6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = msg->GetAddrV6();
+ sin6.sin6_port = HostToInet(Port);
+ return MakeHolder<NAddr::TIPv6Addr>(sin6);
+ }
+
+ if (msg->IsV4()) {
+ return MakeHolder<NAddr::TIPv4Addr>(TIpAddress(msg->GetAddrV4().s_addr, Port));
+ }
+
+ Y_FAIL("Unexpected result address family");
+ }
+
+ return nullptr;
+ }
+
+ NAddr::IRemoteAddrPtr ExtractDefaultAddr(TMaybe<TString>& errorText) {
+ if (DefaultAddress) {
+ NInterconnect::TAddress address(DefaultAddress.data(), Port);
+
+ switch (address.GetFamily()) {
+ case AF_INET:
+ return MakeHolder<NAddr::TIPv4Addr>(*(sockaddr_in*)address.SockAddr());
+ case AF_INET6:
+ return MakeHolder<NAddr::TIPv6Addr>(*(sockaddr_in6*)address.SockAddr());
+ default:
+ errorText = "Unsupported default address: " + DefaultAddress;
+ break;
+ }
+ }
+
+ return nullptr;
+ }
+
+ private:
+ const TString Host;
+ const std::optional<ui32> NodeId;
+ const ui16 Port;
+ const TString DefaultAddress;
+ const TActorId ReplyTo;
+ const TActorId ReplyFrom;
+ const TInstant Deadline;
+ };
+
+ IActor* CreateResolveActor(
+ const TString& host, ui16 port, ui32 nodeId, const TString& defaultAddress,
+ const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
+ {
+ return new TInterconnectResolveActor(host, port, nodeId, defaultAddress, replyTo, replyFrom, deadline);
+ }
+
+ IActor* CreateResolveActor(
+ const TString& host, ui16 port,
+ const TActorId& replyTo, const TActorId& replyFrom, TInstant deadline)
+ {
+ return new TInterconnectResolveActor(host, port, replyTo, replyFrom, deadline);
+ }
+
+} // namespace NActors
diff --git a/library/cpp/actors/interconnect/interconnect_stream.cpp b/library/cpp/actors/interconnect/interconnect_stream.cpp
new file mode 100644
index 0000000000..158ebc9e1d
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_stream.cpp
@@ -0,0 +1,628 @@
+#include "interconnect_stream.h"
+#include "logging.h"
+#include <library/cpp/openssl/init/init.h>
+#include <util/network/socket.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+
+#if defined(_win_)
+#include <util/system/file.h>
+#define SOCK_NONBLOCK 0
+#elif defined(_darwin_)
+#define SOCK_NONBLOCK 0
+#else
+#include <sys/un.h>
+#include <sys/stat.h>
+#endif //_win_
+
+#if !defined(_win_)
+#include <sys/ioctl.h>
+#endif
+
+#include <cerrno>
+
+namespace NInterconnect {
+ namespace {
+ inline int
+ LastSocketError() {
+#if defined(_win_)
+ return WSAGetLastError();
+#else
+ return errno;
+#endif
+ }
+ }
+
+ TSocket::TSocket(SOCKET fd)
+ : Descriptor(fd)
+ {
+ }
+
+ TSocket::~TSocket() {
+ if (Descriptor == INVALID_SOCKET) {
+ return;
+ }
+
+ auto const result = ::closesocket(Descriptor);
+ if (result == 0)
+ return;
+ switch (LastSocketError()) {
+ case EBADF:
+ Y_FAIL("Close bad descriptor");
+ case EINTR:
+ break;
+ case EIO:
+ Y_FAIL("EIO");
+ default:
+ Y_FAIL("It's something unexpected");
+ }
+ }
+
+ int TSocket::GetDescriptor() {
+ return Descriptor;
+ }
+
+ int
+ TSocket::Bind(const TAddress& addr) const {
+ const auto ret = ::bind(Descriptor, addr.SockAddr(), addr.Size());
+ if (ret < 0)
+ return -LastSocketError();
+
+ return 0;
+ }
+
+ int
+ TSocket::Shutdown(int how) const {
+ const auto ret = ::shutdown(Descriptor, how);
+ if (ret < 0)
+ return -LastSocketError();
+
+ return 0;
+ }
+
+ int TSocket::GetConnectStatus() const {
+ int err = 0;
+ socklen_t len = sizeof(err);
+ if (getsockopt(Descriptor, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&err), &len) == -1) {
+ err = LastSocketError();
+ }
+ return err;
+ }
+
+ /////////////////////////////////////////////////////////////////
+
+ TIntrusivePtr<TStreamSocket> TStreamSocket::Make(int domain) {
+ const SOCKET res = ::socket(domain, SOCK_STREAM | SOCK_NONBLOCK, 0);
+ if (res == -1) {
+ const int err = LastSocketError();
+ Y_VERIFY(err != EMFILE && err != ENFILE);
+ }
+ return MakeIntrusive<TStreamSocket>(res);
+ }
+
+ TStreamSocket::TStreamSocket(SOCKET fd)
+ : TSocket(fd)
+ {
+ }
+
+ ssize_t
+ TStreamSocket::Send(const void* msg, size_t len, TString* /*err*/) const {
+ const auto ret = ::send(Descriptor, static_cast<const char*>(msg), int(len), 0);
+ if (ret < 0)
+ return -LastSocketError();
+
+ return ret;
+ }
+
+ ssize_t
+ TStreamSocket::Recv(void* buf, size_t len, TString* /*err*/) const {
+ const auto ret = ::recv(Descriptor, static_cast<char*>(buf), int(len), 0);
+ if (ret < 0)
+ return -LastSocketError();
+
+ return ret;
+ }
+
+ ssize_t
+ TStreamSocket::WriteV(const struct iovec* iov, int iovcnt) const {
+#ifndef _win_
+ const auto ret = ::writev(Descriptor, iov, iovcnt);
+ if (ret < 0)
+ return -LastSocketError();
+ return ret;
+#else
+ Y_FAIL("WriteV() unsupported on Windows");
+#endif
+ }
+
+ ssize_t
+ TStreamSocket::ReadV(const struct iovec* iov, int iovcnt) const {
+#ifndef _win_
+ const auto ret = ::readv(Descriptor, iov, iovcnt);
+ if (ret < 0)
+ return -LastSocketError();
+ return ret;
+#else
+ Y_FAIL("ReadV() unsupported on Windows");
+#endif
+ }
+
+ ssize_t TStreamSocket::GetUnsentQueueSize() const {
+ int num = -1;
+#ifndef _win_ // we have no means to determine output queue size on Windows
+ if (ioctl(Descriptor, TIOCOUTQ, &num) == -1) {
+ num = -1;
+ }
+#endif
+ return num;
+ }
+
+ int
+ TStreamSocket::Connect(const TAddress& addr) const {
+ const auto ret = ::connect(Descriptor, addr.SockAddr(), addr.Size());
+ if (ret < 0)
+ return -LastSocketError();
+
+ return ret;
+ }
+
+ int
+ TStreamSocket::Connect(const NAddr::IRemoteAddr* addr) const {
+ const auto ret = ::connect(Descriptor, addr->Addr(), addr->Len());
+ if (ret < 0)
+ return -LastSocketError();
+
+ return ret;
+ }
+
+ int
+ TStreamSocket::Listen(int backlog) const {
+ const auto ret = ::listen(Descriptor, backlog);
+ if (ret < 0)
+ return -LastSocketError();
+
+ return ret;
+ }
+
+ int
+ TStreamSocket::Accept(TAddress& acceptedAddr) const {
+ socklen_t acceptedSize = sizeof(::sockaddr_in6);
+ const auto ret = ::accept(Descriptor, acceptedAddr.SockAddr(), &acceptedSize);
+ if (ret == INVALID_SOCKET)
+ return -LastSocketError();
+
+ return ret;
+ }
+
+ void
+ TStreamSocket::SetSendBufferSize(i32 len) const {
+ (void)SetSockOpt(Descriptor, SOL_SOCKET, SO_SNDBUF, len);
+ }
+
+ ui32 TStreamSocket::GetSendBufferSize() const {
+ ui32 res = 0;
+ CheckedGetSockOpt(Descriptor, SOL_SOCKET, SO_SNDBUF, res, "SO_SNDBUF");
+ return res;
+ }
+
+ //////////////////////////////////////////////////////
+
+ TDatagramSocket::TPtr TDatagramSocket::Make(int domain) {
+ const SOCKET res = ::socket(domain, SOCK_DGRAM, 0);
+ if (res == -1) {
+ const int err = LastSocketError();
+ Y_VERIFY(err != EMFILE && err != ENFILE);
+ }
+ return std::make_shared<TDatagramSocket>(res);
+ }
+
+ TDatagramSocket::TDatagramSocket(SOCKET fd)
+ : TSocket(fd)
+ {
+ }
+
+ ssize_t
+ TDatagramSocket::SendTo(const void* msg, size_t len, const TAddress& toAddr) const {
+ const auto ret = ::sendto(Descriptor, static_cast<const char*>(msg), int(len), 0, toAddr.SockAddr(), toAddr.Size());
+ if (ret < 0)
+ return -LastSocketError();
+
+ return ret;
+ }
+
+ ssize_t
+ TDatagramSocket::RecvFrom(void* buf, size_t len, TAddress& fromAddr) const {
+ socklen_t fromSize = sizeof(::sockaddr_in6);
+ const auto ret = ::recvfrom(Descriptor, static_cast<char*>(buf), int(len), 0, fromAddr.SockAddr(), &fromSize);
+ if (ret < 0)
+ return -LastSocketError();
+
+ return ret;
+ }
+
+
+ // deleter for SSL objects
+ struct TDeleter {
+ void operator ()(BIO *bio) const {
+ BIO_free(bio);
+ }
+
+ void operator ()(X509 *x509) const {
+ X509_free(x509);
+ }
+
+ void operator ()(RSA *rsa) const {
+ RSA_free(rsa);
+ }
+
+ void operator ()(SSL_CTX *ctx) const {
+ SSL_CTX_free(ctx);
+ }
+ };
+
+ class TSecureSocketContext::TImpl {
+ std::unique_ptr<SSL_CTX, TDeleter> Ctx;
+
+ public:
+ TImpl(const TString& certificate, const TString& privateKey, const TString& caFilePath,
+ const TString& ciphers) {
+ int ret;
+ InitOpenSSL();
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ Ctx.reset(SSL_CTX_new(TLSv1_2_method()));
+ Y_VERIFY(Ctx, "SSL_CTX_new() failed");
+#else
+ Ctx.reset(SSL_CTX_new(TLS_method()));
+ Y_VERIFY(Ctx, "SSL_CTX_new() failed");
+ ret = SSL_CTX_set_min_proto_version(Ctx.get(), TLS1_2_VERSION);
+ Y_VERIFY(ret == 1, "failed to set min proto version");
+ ret = SSL_CTX_set_max_proto_version(Ctx.get(), TLS1_2_VERSION);
+ Y_VERIFY(ret == 1, "failed to set max proto version");
+#endif
+ SSL_CTX_set_verify(Ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, &Verify);
+ SSL_CTX_set_mode(*this, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+ // apply certificates in SSL context
+ if (certificate) {
+ std::unique_ptr<BIO, TDeleter> bio(BIO_new_mem_buf(certificate.data(), certificate.size()));
+ Y_VERIFY(bio);
+
+ // first certificate in the chain is expected to be a leaf
+ std::unique_ptr<X509, TDeleter> cert(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+ Y_VERIFY(cert, "failed to parse certificate");
+ ret = SSL_CTX_use_certificate(Ctx.get(), cert.get());
+ Y_VERIFY(ret == 1);
+
+ // loading additional certificates in the chain, if any
+ while(true) {
+ X509 *ca = PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr);
+ if (ca == nullptr) {
+ break;
+ }
+ ret = SSL_CTX_add0_chain_cert(Ctx.get(), ca);
+ Y_VERIFY(ret == 1);
+ // we must not free memory if certificate was added successfully by SSL_CTX_add0_chain_cert
+ }
+ }
+ if (privateKey) {
+ std::unique_ptr<BIO, TDeleter> bio(BIO_new_mem_buf(privateKey.data(), privateKey.size()));
+ Y_VERIFY(bio);
+ std::unique_ptr<RSA, TDeleter> pkey(PEM_read_bio_RSAPrivateKey(bio.get(), nullptr, nullptr, nullptr));
+ Y_VERIFY(pkey);
+ ret = SSL_CTX_use_RSAPrivateKey(Ctx.get(), pkey.get());
+ Y_VERIFY(ret == 1);
+ }
+ if (caFilePath) {
+ ret = SSL_CTX_load_verify_locations(Ctx.get(), caFilePath.data(), nullptr);
+ Y_VERIFY(ret == 1);
+ }
+
+ int success = SSL_CTX_set_cipher_list(Ctx.get(), ciphers ? ciphers.data() : "AES128-GCM-SHA256");
+ Y_VERIFY(success, "failed to set cipher list");
+ }
+
+ operator SSL_CTX*() const {
+ return Ctx.get();
+ }
+
+ static int GetExIndex() {
+ static int index = SSL_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
+ return index;
+ }
+
+ private:
+ static int Verify(int preverify, X509_STORE_CTX *ctx) {
+ if (!preverify) {
+ X509 *badCert = X509_STORE_CTX_get_current_cert(ctx);
+ int err = X509_STORE_CTX_get_error(ctx);
+ int depth = X509_STORE_CTX_get_error_depth(ctx);
+ SSL *ssl = static_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
+ TString *errp = static_cast<TString*>(SSL_get_ex_data(ssl, GetExIndex()));
+ char buffer[1024];
+ X509_NAME_oneline(X509_get_subject_name(badCert), buffer, sizeof(buffer));
+ TStringBuilder s;
+ s << "Error during certificate validation"
+ << " error# " << X509_verify_cert_error_string(err)
+ << " depth# " << depth
+ << " cert# " << buffer;
+ if (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) {
+ X509_NAME_oneline(X509_get_issuer_name(badCert), buffer, sizeof(buffer));
+ s << " issuer# " << buffer;
+ }
+ *errp = s;
+ }
+ return preverify;
+ }
+ };
+
+ TSecureSocketContext::TSecureSocketContext(const TString& certificate, const TString& privateKey,
+ const TString& caFilePath, const TString& ciphers)
+ : Impl(new TImpl(certificate, privateKey, caFilePath, ciphers))
+ {}
+
+ TSecureSocketContext::~TSecureSocketContext()
+ {}
+
+ class TSecureSocket::TImpl {
+ SSL *Ssl;
+ TString ErrorDescription;
+ bool WantRead_ = false;
+ bool WantWrite_ = false;
+
+ public:
+ TImpl(SSL_CTX *ctx, int fd)
+ : Ssl(SSL_new(ctx))
+ {
+ Y_VERIFY(Ssl, "SSL_new() failed");
+ SSL_set_fd(Ssl, fd);
+ SSL_set_ex_data(Ssl, TSecureSocketContext::TImpl::GetExIndex(), &ErrorDescription);
+ }
+
+ ~TImpl() {
+ SSL_free(Ssl);
+ }
+
+ TString GetErrorStack() {
+ if (ErrorDescription) {
+ return ErrorDescription;
+ }
+ std::unique_ptr<BIO, int(*)(BIO*)> mem(BIO_new(BIO_s_mem()), BIO_free);
+ ERR_print_errors(mem.get());
+ char *p = nullptr;
+ auto len = BIO_get_mem_data(mem.get(), &p);
+ return TString(p, len);
+ }
+
+ EStatus ConvertResult(int res, TString& err) {
+ switch (res) {
+ case SSL_ERROR_NONE:
+ return EStatus::SUCCESS;
+
+ case SSL_ERROR_WANT_READ:
+ return EStatus::WANT_READ;
+
+ case SSL_ERROR_WANT_WRITE:
+ return EStatus::WANT_WRITE;
+
+ case SSL_ERROR_SYSCALL:
+ err = TStringBuilder() << "syscall error: " << strerror(LastSocketError()) << ": " << GetErrorStack();
+ break;
+
+ case SSL_ERROR_ZERO_RETURN:
+ err = "TLS negotiation failed";
+ break;
+
+ case SSL_ERROR_SSL:
+ err = "SSL error: " + GetErrorStack();
+ break;
+
+ default:
+ err = "unknown OpenSSL error";
+ break;
+ }
+ return EStatus::ERROR;
+ }
+
+ enum EConnectState {
+ CONNECT,
+ SHUTDOWN,
+ READ,
+ } ConnectState = EConnectState::CONNECT;
+
+ EStatus Establish(bool server, bool authOnly, TString& err) {
+ switch (ConnectState) {
+ case EConnectState::CONNECT: {
+ auto callback = server ? SSL_accept : SSL_connect;
+ const EStatus status = ConvertResult(SSL_get_error(Ssl, callback(Ssl)), err);
+ if (status != EStatus::SUCCESS || !authOnly) {
+ return status;
+ }
+ ConnectState = EConnectState::SHUTDOWN;
+ [[fallthrough]];
+ }
+
+ case EConnectState::SHUTDOWN: {
+ const int res = SSL_shutdown(Ssl);
+ if (res == 1) {
+ return EStatus::SUCCESS;
+ } else if (res != 0) {
+ return ConvertResult(SSL_get_error(Ssl, res), err);
+ }
+ ConnectState = EConnectState::READ;
+ [[fallthrough]];
+ }
+
+ case EConnectState::READ: {
+ char data[256];
+ size_t numRead = 0;
+ const int res = SSL_get_error(Ssl, SSL_read_ex(Ssl, data, sizeof(data), &numRead));
+ if (res == SSL_ERROR_ZERO_RETURN) {
+ return EStatus::SUCCESS;
+ } else if (res != SSL_ERROR_NONE) {
+ return ConvertResult(res, err);
+ } else if (numRead) {
+ err = "non-zero return from SSL_read_ex: " + ToString(numRead);
+ return EStatus::ERROR;
+ } else {
+ return EStatus::SUCCESS;
+ }
+ }
+ }
+ Y_FAIL();
+ }
+
+ std::optional<std::pair<const void*, size_t>> BlockedSend;
+
+ ssize_t Send(const void* msg, size_t len, TString *err) {
+ Y_VERIFY(!BlockedSend || *BlockedSend == std::make_pair(msg, len));
+ const ssize_t res = Operate(msg, len, &SSL_write_ex, err);
+ if (res == -EAGAIN) {
+ BlockedSend.emplace(msg, len);
+ } else {
+ BlockedSend.reset();
+ }
+ return res;
+ }
+
+ std::optional<std::pair<void*, size_t>> BlockedReceive;
+
+ ssize_t Recv(void* msg, size_t len, TString *err) {
+ Y_VERIFY(!BlockedReceive || *BlockedReceive == std::make_pair(msg, len));
+ const ssize_t res = Operate(msg, len, &SSL_read_ex, err);
+ if (res == -EAGAIN) {
+ BlockedReceive.emplace(msg, len);
+ } else {
+ BlockedReceive.reset();
+ }
+ return res;
+ }
+
+ TString GetCipherName() const {
+ return SSL_get_cipher_name(Ssl);
+ }
+
+ int GetCipherBits() const {
+ return SSL_get_cipher_bits(Ssl, nullptr);
+ }
+
+ TString GetProtocolName() const {
+ return SSL_get_cipher_version(Ssl);
+ }
+
+ TString GetPeerCommonName() const {
+ TString res;
+ if (X509 *cert = SSL_get_peer_certificate(Ssl)) {
+ char buffer[256];
+ memset(buffer, 0, sizeof(buffer));
+ if (X509_NAME *name = X509_get_subject_name(cert)) {
+ X509_NAME_get_text_by_NID(name, NID_commonName, buffer, sizeof(buffer));
+ }
+ X509_free(cert);
+ res = TString(buffer, strnlen(buffer, sizeof(buffer)));
+ }
+ return res;
+ }
+
+ bool WantRead() const {
+ return WantRead_;
+ }
+
+ bool WantWrite() const {
+ return WantWrite_;
+ }
+
+ private:
+ template<typename TBuffer, typename TOp>
+ ssize_t Operate(TBuffer* buffer, size_t len, TOp&& op, TString *err) {
+ WantRead_ = WantWrite_ = false;
+ size_t processed = 0;
+ int ret = op(Ssl, buffer, len, &processed);
+ if (ret == 1) {
+ return processed;
+ }
+ switch (const int status = SSL_get_error(Ssl, ret)) {
+ case SSL_ERROR_ZERO_RETURN:
+ return 0;
+
+ case SSL_ERROR_WANT_READ:
+ WantRead_ = true;
+ return -EAGAIN;
+
+ case SSL_ERROR_WANT_WRITE:
+ WantWrite_ = true;
+ return -EAGAIN;
+
+ case SSL_ERROR_SYSCALL:
+ return -LastSocketError();
+
+ case SSL_ERROR_SSL:
+ if (err) {
+ *err = GetErrorStack();
+ }
+ return -EPROTO;
+
+ default:
+ Y_FAIL("unexpected SSL_get_error() status# %d", status);
+ }
+ }
+ };
+
+ TSecureSocket::TSecureSocket(TStreamSocket& socket, TSecureSocketContext::TPtr context)
+ : TStreamSocket(socket.ReleaseDescriptor())
+ , Context(std::move(context))
+ , Impl(new TImpl(*Context->Impl, Descriptor))
+ {}
+
+ TSecureSocket::~TSecureSocket()
+ {}
+
+ TSecureSocket::EStatus TSecureSocket::Establish(bool server, bool authOnly, TString& err) const {
+ return Impl->Establish(server, authOnly, err);
+ }
+
+ TIntrusivePtr<TStreamSocket> TSecureSocket::Detach() {
+ return MakeIntrusive<TStreamSocket>(ReleaseDescriptor());
+ }
+
+ ssize_t TSecureSocket::Send(const void* msg, size_t len, TString *err) const {
+ return Impl->Send(msg, len, err);
+ }
+
+ ssize_t TSecureSocket::Recv(void* msg, size_t len, TString *err) const {
+ return Impl->Recv(msg, len, err);
+ }
+
+ ssize_t TSecureSocket::WriteV(const struct iovec* /*iov*/, int /*iovcnt*/) const {
+ Y_FAIL("unsupported on SSL sockets");
+ }
+
+ ssize_t TSecureSocket::ReadV(const struct iovec* /*iov*/, int /*iovcnt*/) const {
+ Y_FAIL("unsupported on SSL sockets");
+ }
+
+ TString TSecureSocket::GetCipherName() const {
+ return Impl->GetCipherName();
+ }
+
+ int TSecureSocket::GetCipherBits() const {
+ return Impl->GetCipherBits();
+ }
+
+ TString TSecureSocket::GetProtocolName() const {
+ return Impl->GetProtocolName();
+ }
+
+ TString TSecureSocket::GetPeerCommonName() const {
+ return Impl->GetPeerCommonName();
+ }
+
+ bool TSecureSocket::WantRead() const {
+ return Impl->WantRead();
+ }
+
+ bool TSecureSocket::WantWrite() const {
+ return Impl->WantWrite();
+ }
+
+}
diff --git a/library/cpp/actors/interconnect/interconnect_stream.h b/library/cpp/actors/interconnect/interconnect_stream.h
new file mode 100644
index 0000000000..074adc6e74
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_stream.h
@@ -0,0 +1,131 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/generic/noncopyable.h>
+#include <util/network/address.h>
+#include <util/network/init.h>
+#include <util/system/defaults.h>
+
+#include "poller.h"
+
+#include "interconnect_address.h"
+
+#include <memory>
+
+#include <sys/uio.h>
+
+namespace NInterconnect {
+ class TSocket: public NActors::TSharedDescriptor, public TNonCopyable {
+ protected:
+ TSocket(SOCKET fd);
+
+ virtual ~TSocket() override;
+
+ SOCKET Descriptor;
+
+ virtual int GetDescriptor() override;
+
+ private:
+ friend class TSecureSocket;
+
+ SOCKET ReleaseDescriptor() {
+ return std::exchange(Descriptor, INVALID_SOCKET);
+ }
+
+ public:
+ operator SOCKET() const {
+ return Descriptor;
+ }
+
+ int Bind(const TAddress& addr) const;
+ int Shutdown(int how) const;
+ int GetConnectStatus() const;
+ };
+
+ class TStreamSocket: public TSocket {
+ public:
+ TStreamSocket(SOCKET fd);
+
+ static TIntrusivePtr<TStreamSocket> Make(int domain);
+
+ virtual ssize_t Send(const void* msg, size_t len, TString *err = nullptr) const;
+ virtual ssize_t Recv(void* buf, size_t len, TString *err = nullptr) const;
+
+ virtual ssize_t WriteV(const struct iovec* iov, int iovcnt) const;
+ virtual ssize_t ReadV(const struct iovec* iov, int iovcnt) const;
+
+ int Connect(const TAddress& addr) const;
+ int Connect(const NAddr::IRemoteAddr* addr) const;
+ int Listen(int backlog) const;
+ int Accept(TAddress& acceptedAddr) const;
+
+ ssize_t GetUnsentQueueSize() const;
+
+ void SetSendBufferSize(i32 len) const;
+ ui32 GetSendBufferSize() const;
+ };
+
+ class TSecureSocketContext {
+ class TImpl;
+ THolder<TImpl> Impl;
+
+ friend class TSecureSocket;
+
+ public:
+ TSecureSocketContext(const TString& certificate, const TString& privateKey, const TString& caFilePath,
+ const TString& ciphers);
+ ~TSecureSocketContext();
+
+ public:
+ using TPtr = std::shared_ptr<TSecureSocketContext>;
+ };
+
+ class TSecureSocket : public TStreamSocket {
+ TSecureSocketContext::TPtr Context;
+
+ class TImpl;
+ THolder<TImpl> Impl;
+
+ public:
+ enum class EStatus {
+ SUCCESS,
+ ERROR,
+ WANT_READ,
+ WANT_WRITE,
+ };
+
+ public:
+ TSecureSocket(TStreamSocket& socket, TSecureSocketContext::TPtr context);
+ ~TSecureSocket();
+
+ EStatus Establish(bool server, bool authOnly, TString& err) const;
+ TIntrusivePtr<TStreamSocket> Detach();
+
+ ssize_t Send(const void* msg, size_t len, TString *err) const override;
+ ssize_t Recv(void* msg, size_t len, TString *err) const override;
+
+ ssize_t WriteV(const struct iovec* iov, int iovcnt) const override;
+ ssize_t ReadV(const struct iovec* iov, int iovcnt) const override;
+
+ TString GetCipherName() const;
+ int GetCipherBits() const;
+ TString GetProtocolName() const;
+ TString GetPeerCommonName() const;
+
+ bool WantRead() const;
+ bool WantWrite() const;
+ };
+
+ class TDatagramSocket: public TSocket {
+ public:
+ typedef std::shared_ptr<TDatagramSocket> TPtr;
+
+ TDatagramSocket(SOCKET fd);
+
+ static TPtr Make(int domain);
+
+ ssize_t SendTo(const void* msg, size_t len, const TAddress& toAddr) const;
+ ssize_t RecvFrom(void* buf, size_t len, TAddress& fromAddr) const;
+ };
+
+}
diff --git a/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp b/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp
new file mode 100644
index 0000000000..0abe9fe659
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_tcp_input_session.cpp
@@ -0,0 +1,476 @@
+#include "interconnect_tcp_session.h"
+#include "interconnect_tcp_proxy.h"
+#include <library/cpp/actors/core/probes.h>
+#include <library/cpp/actors/util/datetime.h>
+
+namespace NActors {
+ LWTRACE_USING(ACTORLIB_PROVIDER);
+
+ TInputSessionTCP::TInputSessionTCP(const TActorId& sessionId, TIntrusivePtr<NInterconnect::TStreamSocket> socket,
+ TIntrusivePtr<TReceiveContext> context, TInterconnectProxyCommon::TPtr common,
+ std::shared_ptr<IInterconnectMetrics> metrics, ui32 nodeId, ui64 lastConfirmed,
+ TDuration deadPeerTimeout, TSessionParams params)
+ : SessionId(sessionId)
+ , Socket(std::move(socket))
+ , Context(std::move(context))
+ , Common(std::move(common))
+ , NodeId(nodeId)
+ , Params(std::move(params))
+ , ConfirmedByInput(lastConfirmed)
+ , Metrics(std::move(metrics))
+ , DeadPeerTimeout(deadPeerTimeout)
+ {
+ Y_VERIFY(Context);
+ Y_VERIFY(Socket);
+ Y_VERIFY(SessionId);
+
+ AtomicSet(Context->PacketsReadFromSocket, 0);
+
+ Metrics->SetClockSkewMicrosec(0);
+
+ Context->UpdateState = EUpdateState::NONE;
+
+ // ensure that we do not spawn new session while the previous one is still alive
+ TAtomicBase sessions = AtomicIncrement(Context->NumInputSessions);
+ Y_VERIFY(sessions == 1, "sessions# %" PRIu64, ui64(sessions));
+ }
+
+ void TInputSessionTCP::Bootstrap() {
+ SetPrefix(Sprintf("InputSession %s [node %" PRIu32 "]", SelfId().ToString().data(), NodeId));
+ Become(&TThis::WorkingState, DeadPeerTimeout, new TEvCheckDeadPeer);
+ LOG_DEBUG_IC_SESSION("ICIS01", "InputSession created");
+ LastReceiveTimestamp = TActivationContext::Now();
+ ReceiveData();
+ }
+
+ void TInputSessionTCP::CloseInputSession() {
+ CloseInputSessionRequested = true;
+ ReceiveData();
+ }
+
+ void TInputSessionTCP::Handle(TEvPollerReady::TPtr ev) {
+ if (Context->ReadPending) {
+ Metrics->IncUsefulReadWakeups();
+ } else if (!ev->Cookie) {
+ Metrics->IncSpuriousReadWakeups();
+ }
+ Context->ReadPending = false;
+ ReceiveData();
+ if (Params.Encryption && Context->WriteBlockedByFullSendBuffer && !ev->Cookie) {
+ Send(SessionId, ev->Release().Release(), 0, 1);
+ }
+ }
+
+ void TInputSessionTCP::Handle(TEvPollerRegisterResult::TPtr ev) {
+ PollerToken = std::move(ev->Get()->PollerToken);
+ ReceiveData();
+ }
+
+ void TInputSessionTCP::HandleResumeReceiveData() {
+ ReceiveData();
+ }
+
+ void TInputSessionTCP::ReceiveData() {
+ TTimeLimit limit(GetMaxCyclesPerEvent());
+ ui64 numDataBytes = 0;
+ const size_t headerLen = Params.UseModernFrame ? sizeof(TTcpPacketHeader_v2) : sizeof(TTcpPacketHeader_v1);
+
+ LOG_DEBUG_IC_SESSION("ICIS02", "ReceiveData called");
+
+ for (int iteration = 0; Socket; ++iteration) {
+ if (iteration && limit.CheckExceeded()) {
+ // we have hit processing time limit for this message, send notification to resume processing a bit later
+ Send(SelfId(), new TEvResumeReceiveData);
+ break;
+ }
+
+ switch (State) {
+ case EState::HEADER:
+ if (IncomingData.GetSize() < headerLen) {
+ break;
+ } else {
+ ProcessHeader(headerLen);
+ }
+ continue;
+
+ case EState::PAYLOAD:
+ if (!IncomingData) {
+ break;
+ } else {
+ ProcessPayload(numDataBytes);
+ }
+ continue;
+ }
+
+ // if we have reached this point, it means that we do not have enough data in read buffer; try to obtain some
+ if (!ReadMore()) {
+ // we have no data from socket, so we have some free time to spend -- preallocate buffers using this time
+ PreallocateBuffers();
+ break;
+ }
+ }
+
+ // calculate ping time
+ auto it = std::min_element(PingQ.begin(), PingQ.end());
+ const TDuration ping = it != PingQ.end() ? *it : TDuration::Zero();
+
+ // send update to main session actor if something valuable has changed
+ if (!UpdateFromInputSession) {
+ UpdateFromInputSession = MakeHolder<TEvUpdateFromInputSession>(ConfirmedByInput, numDataBytes, ping);
+ } else {
+ Y_VERIFY(ConfirmedByInput >= UpdateFromInputSession->ConfirmedByInput);
+ UpdateFromInputSession->ConfirmedByInput = ConfirmedByInput;
+ UpdateFromInputSession->NumDataBytes += numDataBytes;
+ UpdateFromInputSession->Ping = Min(UpdateFromInputSession->Ping, ping);
+ }
+
+ for (;;) {
+ EUpdateState state = Context->UpdateState;
+ EUpdateState next;
+
+ // calculate next state
+ switch (state) {
+ case EUpdateState::NONE:
+ case EUpdateState::CONFIRMING:
+ // we have no inflight messages to session actor, we will issue one a bit later
+ next = EUpdateState::INFLIGHT;
+ break;
+
+ case EUpdateState::INFLIGHT:
+ case EUpdateState::INFLIGHT_AND_PENDING:
+ // we already have inflight message, so we will keep pending message and session actor will issue
+ // TEvConfirmUpdate to kick processing
+ next = EUpdateState::INFLIGHT_AND_PENDING;
+ break;
+ }
+
+ if (Context->UpdateState.compare_exchange_weak(state, next)) {
+ switch (next) {
+ case EUpdateState::INFLIGHT:
+ Send(SessionId, UpdateFromInputSession.Release());
+ break;
+
+ case EUpdateState::INFLIGHT_AND_PENDING:
+ Y_VERIFY(UpdateFromInputSession);
+ break;
+
+ default:
+ Y_FAIL("unexpected state");
+ }
+ break;
+ }
+ }
+ }
+
+ void TInputSessionTCP::ProcessHeader(size_t headerLen) {
+ const bool success = IncomingData.ExtractFrontPlain(Header.Data, headerLen);
+ Y_VERIFY(success);
+ if (Params.UseModernFrame) {
+ PayloadSize = Header.v2.PayloadLength;
+ HeaderSerial = Header.v2.Serial;
+ HeaderConfirm = Header.v2.Confirm;
+ if (!Params.Encryption) {
+ ChecksumExpected = std::exchange(Header.v2.Checksum, 0);
+ Checksum = Crc32cExtendMSanCompatible(0, &Header.v2, sizeof(Header.v2)); // start calculating checksum now
+ if (!PayloadSize && Checksum != ChecksumExpected) {
+ LOG_ERROR_IC_SESSION("ICIS10", "payload checksum error");
+ return ReestablishConnection(TDisconnectReason::ChecksumError());
+ }
+ }
+ } else if (!Header.v1.Check()) {
+ LOG_ERROR_IC_SESSION("ICIS03", "header checksum error");
+ return ReestablishConnection(TDisconnectReason::ChecksumError());
+ } else {
+ PayloadSize = Header.v1.DataSize;
+ HeaderSerial = Header.v1.Serial;
+ HeaderConfirm = Header.v1.Confirm;
+ ChecksumExpected = Header.v1.PayloadCRC32;
+ Checksum = 0;
+ }
+ if (PayloadSize >= 65536) {
+ LOG_CRIT_IC_SESSION("ICIS07", "payload is way too big");
+ return DestroySession(TDisconnectReason::FormatError());
+ }
+ if (ConfirmedByInput < HeaderConfirm) {
+ ConfirmedByInput = HeaderConfirm;
+ if (AtomicGet(Context->ControlPacketId) <= HeaderConfirm && !NewPingProtocol) {
+ ui64 sendTime = AtomicGet(Context->ControlPacketSendTimer);
+ TDuration duration = CyclesToDuration(GetCycleCountFast() - sendTime);
+ const auto durationUs = duration.MicroSeconds();
+ Metrics->UpdateLegacyPingTimeHist(durationUs);
+ PingQ.push_back(duration);
+ if (PingQ.size() > 16) {
+ PingQ.pop_front();
+ }
+ AtomicSet(Context->ControlPacketId, 0ULL);
+ }
+ }
+ if (PayloadSize) {
+ const ui64 expected = Context->GetLastProcessedPacketSerial() + 1;
+ if (HeaderSerial == 0 || HeaderSerial > expected) {
+ LOG_CRIT_IC_SESSION("ICIS06", "packet serial %" PRIu64 ", but %" PRIu64 " expected", HeaderSerial, expected);
+ return DestroySession(TDisconnectReason::FormatError());
+ }
+ IgnorePayload = HeaderSerial != expected;
+ State = EState::PAYLOAD;
+ } else if (HeaderSerial & TTcpPacketBuf::PingRequestMask) {
+ Send(SessionId, new TEvProcessPingRequest(HeaderSerial & ~TTcpPacketBuf::PingRequestMask));
+ } else if (HeaderSerial & TTcpPacketBuf::PingResponseMask) {
+ const ui64 sent = HeaderSerial & ~TTcpPacketBuf::PingResponseMask;
+ const ui64 received = GetCycleCountFast();
+ HandlePingResponse(CyclesToDuration(received - sent));
+ } else if (HeaderSerial & TTcpPacketBuf::ClockMask) {
+ HandleClock(TInstant::MicroSeconds(HeaderSerial & ~TTcpPacketBuf::ClockMask));
+ }
+ }
+
+ void TInputSessionTCP::ProcessPayload(ui64& numDataBytes) {
+ const size_t numBytes = Min(PayloadSize, IncomingData.GetSize());
+ IncomingData.ExtractFront(numBytes, &Payload);
+ numDataBytes += numBytes;
+ PayloadSize -= numBytes;
+ if (PayloadSize) {
+ return; // there is still some data to receive in the Payload rope
+ }
+ State = EState::HEADER; // we'll continue with header next time
+ if (!Params.UseModernFrame || !Params.Encryption) { // see if we are checksumming packet body
+ for (const auto&& [data, size] : Payload) {
+ Checksum = Crc32cExtendMSanCompatible(Checksum, data, size);
+ }
+ if (Checksum != ChecksumExpected) { // validate payload checksum
+ LOG_ERROR_IC_SESSION("ICIS04", "payload checksum error");
+ return ReestablishConnection(TDisconnectReason::ChecksumError());
+ }
+ }
+ if (Y_UNLIKELY(IgnorePayload)) {
+ return;
+ }
+ if (!Context->AdvanceLastProcessedPacketSerial()) {
+ return DestroySession(TDisconnectReason::NewSession());
+ }
+
+ while (Payload && Socket) {
+ // extract channel part header from the payload stream
+ TChannelPart part;
+ if (!Payload.ExtractFrontPlain(&part, sizeof(part))) {
+ LOG_CRIT_IC_SESSION("ICIS14", "missing TChannelPart header in payload");
+ return DestroySession(TDisconnectReason::FormatError());
+ }
+ if (!part.Size) { // bogus frame
+ continue;
+ } else if (Payload.GetSize() < part.Size) {
+ LOG_CRIT_IC_SESSION("ICIS08", "payload format error ChannelPart# %s", part.ToString().data());
+ return DestroySession(TDisconnectReason::FormatError());
+ }
+
+ const ui16 channel = part.Channel & ~TChannelPart::LastPartFlag;
+ TRope *eventData = channel < Context->ChannelArray.size()
+ ? &Context->ChannelArray[channel]
+ : &Context->ChannelMap[channel];
+
+ Metrics->AddInputChannelsIncomingTraffic(channel, sizeof(part) + part.Size);
+
+ TEventDescr descr;
+ if (~part.Channel & TChannelPart::LastPartFlag) {
+ Payload.ExtractFront(part.Size, eventData);
+ } else if (part.Size != sizeof(descr)) {
+ LOG_CRIT_IC_SESSION("ICIS11", "incorrect last part of an event");
+ return DestroySession(TDisconnectReason::FormatError());
+ } else if (Payload.ExtractFrontPlain(&descr, sizeof(descr))) {
+ Metrics->IncInputChannelsIncomingEvents(channel);
+ ProcessEvent(*eventData, descr);
+ *eventData = TRope();
+ } else {
+ Y_FAIL();
+ }
+ }
+ }
+
+ void TInputSessionTCP::ProcessEvent(TRope& data, TEventDescr& descr) {
+ if (!Params.UseModernFrame || descr.Checksum) {
+ ui32 checksum = 0;
+ for (const auto&& [data, size] : data) {
+ checksum = Crc32cExtendMSanCompatible(checksum, data, size);
+ }
+ if (checksum != descr.Checksum) {
+ LOG_CRIT_IC_SESSION("ICIS05", "event checksum error");
+ return ReestablishConnection(TDisconnectReason::ChecksumError());
+ }
+ }
+ auto ev = std::make_unique<IEventHandle>(SessionId,
+ descr.Type,
+ descr.Flags & ~IEventHandle::FlagExtendedFormat,
+ descr.Recipient,
+ descr.Sender,
+ MakeIntrusive<TEventSerializedData>(std::move(data), bool(descr.Flags & IEventHandle::FlagExtendedFormat)),
+ descr.Cookie,
+ Params.PeerScopeId,
+ NWilson::TTraceId(descr.TraceId));
+ if (Common->EventFilter && !Common->EventFilter->CheckIncomingEvent(*ev, Common->LocalScopeId)) {
+ LOG_CRIT_IC_SESSION("ICIC03", "Event dropped due to scope error LocalScopeId# %s PeerScopeId# %s Type# 0x%08" PRIx32,
+ ScopeIdToString(Common->LocalScopeId).data(), ScopeIdToString(Params.PeerScopeId).data(), descr.Type);
+ ev.reset();
+ }
+ if (ev) {
+ TActivationContext::Send(ev.release());
+ }
+ }
+
+ void TInputSessionTCP::HandleConfirmUpdate() {
+ for (;;) {
+ switch (EUpdateState state = Context->UpdateState) {
+ case EUpdateState::NONE:
+ case EUpdateState::INFLIGHT:
+ case EUpdateState::INFLIGHT_AND_PENDING:
+ // here we may have a race
+ return;
+
+ case EUpdateState::CONFIRMING:
+ Y_VERIFY(UpdateFromInputSession);
+ if (Context->UpdateState.compare_exchange_weak(state, EUpdateState::INFLIGHT)) {
+ Send(SessionId, UpdateFromInputSession.Release());
+ return;
+ }
+ }
+ }
+ }
+
+ bool TInputSessionTCP::ReadMore() {
+ PreallocateBuffers();
+
+ TStackVec<TIoVec, NumPreallocatedBuffers> buffs;
+ for (const auto& item : Buffers) {
+ TIoVec iov{item->GetBuffer(), item->GetCapacity()};
+ buffs.push_back(iov);
+ if (Params.Encryption) {
+ break; // do not put more than one buffer in queue to prevent using ReadV
+ }
+ }
+
+ const struct iovec* iovec = reinterpret_cast<const struct iovec*>(buffs.data());
+ int iovcnt = buffs.size();
+
+ ssize_t recvres = 0;
+ TString err;
+ LWPROBE_IF_TOO_LONG(SlowICReadFromSocket, ms) {
+ do {
+#ifndef _win_
+ recvres = iovcnt == 1 ? Socket->Recv(iovec->iov_base, iovec->iov_len, &err) : Socket->ReadV(iovec, iovcnt);
+#else
+ recvres = Socket->Recv(iovec[0].iov_base, iovec[0].iov_len, &err);
+#endif
+ Metrics->IncRecvSyscalls();
+ } while (recvres == -EINTR);
+ }
+
+ LOG_DEBUG_IC_SESSION("ICIS12", "ReadMore recvres# %zd iovcnt# %d err# %s", recvres, iovcnt, err.data());
+
+ if (recvres <= 0 || CloseInputSessionRequested) {
+ if ((-recvres != EAGAIN && -recvres != EWOULDBLOCK) || CloseInputSessionRequested) {
+ TString message = CloseInputSessionRequested ? "connection closed by debug command"
+ : recvres == 0 ? "connection closed by peer"
+ : err ? err
+ : Sprintf("socket: %s", strerror(-recvres));
+ LOG_NOTICE_NET(NodeId, "%s", message.data());
+ ReestablishConnection(CloseInputSessionRequested ? TDisconnectReason::Debug() :
+ recvres == 0 ? TDisconnectReason::EndOfStream() : TDisconnectReason::FromErrno(-recvres));
+ } else if (PollerToken && !std::exchange(Context->ReadPending, true)) {
+ if (Params.Encryption) {
+ auto *secure = static_cast<NInterconnect::TSecureSocket*>(Socket.Get());
+ const bool wantRead = secure->WantRead(), wantWrite = secure->WantWrite();
+ Y_VERIFY_DEBUG(wantRead || wantWrite);
+ PollerToken->Request(wantRead, wantWrite);
+ } else {
+ PollerToken->Request(true, false);
+ }
+ }
+ return false;
+ }
+
+ Y_VERIFY(recvres > 0);
+ Metrics->AddTotalBytesRead(recvres);
+ TDeque<TIntrusivePtr<TRopeAlignedBuffer>>::iterator it;
+ for (it = Buffers.begin(); recvres; ++it) {
+ Y_VERIFY(it != Buffers.end());
+ const size_t bytesFromFrontBuffer = Min<size_t>(recvres, (*it)->GetCapacity());
+ (*it)->AdjustSize(bytesFromFrontBuffer);
+ IncomingData.Insert(IncomingData.End(), TRope(std::move(*it)));
+ recvres -= bytesFromFrontBuffer;
+ }
+ Buffers.erase(Buffers.begin(), it);
+
+ LastReceiveTimestamp = TActivationContext::Now();
+
+ return true;
+ }
+
+ void TInputSessionTCP::PreallocateBuffers() {
+ // ensure that we have exactly "numBuffers" in queue
+ LWPROBE_IF_TOO_LONG(SlowICReadLoopAdjustSize, ms) {
+ const ui32 target = Params.Encryption ? 1 : NumPreallocatedBuffers;
+ while (Buffers.size() < target) {
+ Buffers.emplace_back(TRopeAlignedBuffer::Allocate(sizeof(TTcpPacketBuf)));
+ }
+ }
+ }
+
+ void TInputSessionTCP::ReestablishConnection(TDisconnectReason reason) {
+ LOG_DEBUG_IC_SESSION("ICIS09", "ReestablishConnection, reason# %s", reason.ToString().data());
+ AtomicDecrement(Context->NumInputSessions);
+ Send(SessionId, new TEvSocketDisconnect(std::move(reason)));
+ PassAway();
+ Socket.Reset();
+ }
+
+ void TInputSessionTCP::DestroySession(TDisconnectReason reason) {
+ LOG_DEBUG_IC_SESSION("ICIS13", "DestroySession, reason# %s", reason.ToString().data());
+ AtomicDecrement(Context->NumInputSessions);
+ Send(SessionId, TInterconnectSessionTCP::NewEvTerminate(std::move(reason)));
+ PassAway();
+ Socket.Reset();
+ }
+
+ void TInputSessionTCP::HandleCheckDeadPeer() {
+ const TInstant now = TActivationContext::Now();
+ if (now >= LastReceiveTimestamp + DeadPeerTimeout) {
+ ReceiveData();
+ if (Socket && now >= LastReceiveTimestamp + DeadPeerTimeout) {
+ // nothing has changed, terminate session
+ DestroySession(TDisconnectReason::DeadPeer());
+ }
+ }
+ Schedule(LastReceiveTimestamp + DeadPeerTimeout - now, new TEvCheckDeadPeer);
+ }
+
+ void TInputSessionTCP::HandlePingResponse(TDuration passed) {
+ PingQ.push_back(passed);
+ if (PingQ.size() > 16) {
+ PingQ.pop_front();
+ }
+ const TDuration ping = *std::min_element(PingQ.begin(), PingQ.end());
+ const auto pingUs = ping.MicroSeconds();
+ Context->PingRTT_us = pingUs;
+ NewPingProtocol = true;
+ Metrics->UpdateLegacyPingTimeHist(pingUs);
+ }
+
+ void TInputSessionTCP::HandleClock(TInstant clock) {
+ const TInstant here = TInstant::Now(); // wall clock
+ const TInstant remote = clock + TDuration::MicroSeconds(Context->PingRTT_us / 2);
+ i64 skew = remote.MicroSeconds() - here.MicroSeconds();
+ SkewQ.push_back(skew);
+ if (SkewQ.size() > 16) {
+ SkewQ.pop_front();
+ }
+ i64 clockSkew = SkewQ.front();
+ for (i64 skew : SkewQ) {
+ if (abs(skew) < abs(clockSkew)) {
+ clockSkew = skew;
+ }
+ }
+ Context->ClockSkew_us = clockSkew;
+ Metrics->SetClockSkewMicrosec(clockSkew);
+ }
+
+
+}
diff --git a/library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp b/library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp
new file mode 100644
index 0000000000..7e2d8ccb94
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_tcp_proxy.cpp
@@ -0,0 +1,936 @@
+#include "interconnect_tcp_proxy.h"
+#include "interconnect_handshake.h"
+#include "interconnect_tcp_session.h"
+#include <library/cpp/actors/core/log.h>
+#include <library/cpp/actors/protos/services_common.pb.h>
+#include <library/cpp/monlib/service/pages/templates.h>
+#include <util/system/getpid.h>
+
+namespace NActors {
+ static constexpr TDuration GetNodeRequestTimeout = TDuration::Seconds(5);
+
+ static constexpr TDuration FirstErrorSleep = TDuration::MilliSeconds(10);
+ static constexpr TDuration MaxErrorSleep = TDuration::Seconds(10);
+ static constexpr ui32 SleepRetryMultiplier = 4;
+
+ static TString PeerNameForHuman(ui32 nodeNum, const TString& longName, ui16 port) {
+ TStringBuf token;
+ TStringBuf(longName).NextTok('.', token);
+ return ToString<ui32>(nodeNum) + ":" + (token.size() > 0 ? TString(token) : longName) + ":" + ToString<ui16>(port);
+ }
+
+ TInterconnectProxyTCP::TInterconnectProxyTCP(const ui32 node, TInterconnectProxyCommon::TPtr common,
+ IActor **dynamicPtr)
+ : TActor(&TThis::StateInit)
+ , PeerNodeId(node)
+ , DynamicPtr(dynamicPtr)
+ , Common(std::move(common))
+ , SecureContext(new NInterconnect::TSecureSocketContext(Common->Settings.Certificate, Common->Settings.PrivateKey,
+ Common->Settings.CaFilePath, Common->Settings.CipherList))
+ {
+ Y_VERIFY(Common);
+ Y_VERIFY(Common->NameserviceId);
+ if (DynamicPtr) {
+ Y_VERIFY(!*DynamicPtr);
+ *DynamicPtr = this;
+ }
+ }
+
+ void TInterconnectProxyTCP::Bootstrap() {
+ SetPrefix(Sprintf("Proxy %s [node %" PRIu32 "]", SelfId().ToString().data(), PeerNodeId));
+
+ SwitchToInitialState();
+ PassAwayTimestamp = TActivationContext::Now() + TDuration::Seconds(15);
+
+ LOG_INFO_IC("ICP01", "ready to work");
+ }
+
+ void TInterconnectProxyTCP::Registered(TActorSystem* sys, const TActorId& owner) {
+ if (!DynamicPtr) {
+ // perform usual bootstrap for static nodes
+ sys->Send(new IEventHandle(TEvents::TSystem::Bootstrap, 0, SelfId(), owner, nullptr, 0));
+ }
+ if (const auto& mon = Common->RegisterMonPage) {
+ TString path = Sprintf("peer%04" PRIu32, PeerNodeId);
+ TString title = Sprintf("Peer #%04" PRIu32, PeerNodeId);
+ mon(path, title, sys, SelfId());
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // PendingActivation
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ void TInterconnectProxyTCP::RequestNodeInfo(STATEFN_SIG) {
+ ICPROXY_PROFILED;
+
+ Y_VERIFY(!IncomingHandshakeActor && !OutgoingHandshakeActor && !PendingIncomingHandshakeEvents && !PendingSessionEvents);
+ EnqueueSessionEvent(ev);
+ StartConfiguring();
+ }
+
+ void TInterconnectProxyTCP::RequestNodeInfoForIncomingHandshake(STATEFN_SIG) {
+ ICPROXY_PROFILED;
+
+ if (!Terminated) {
+ Y_VERIFY(!IncomingHandshakeActor && !OutgoingHandshakeActor && !PendingIncomingHandshakeEvents && !PendingSessionEvents);
+ EnqueueIncomingHandshakeEvent(ev);
+ StartConfiguring();
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // PendingNodeInfo
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ void TInterconnectProxyTCP::StartConfiguring() {
+ ICPROXY_PROFILED;
+
+ Y_VERIFY(!IncomingHandshakeActor && !OutgoingHandshakeActor);
+
+ // issue node info request
+ Send(Common->NameserviceId, new TEvInterconnect::TEvGetNode(PeerNodeId));
+
+ // arm configure timer; store pointer to event to ensure that we will handle correct one if there were any other
+ // wakeup events in flight
+ SwitchToState(__LINE__, "PendingNodeInfo", &TThis::PendingNodeInfo, GetNodeRequestTimeout,
+ ConfigureTimeoutCookie = new TEvents::TEvWakeup);
+ }
+
+ void TInterconnectProxyTCP::Configure(TEvInterconnect::TEvNodeInfo::TPtr& ev) {
+ ICPROXY_PROFILED;
+
+ Y_VERIFY(!IncomingHandshakeActor && !OutgoingHandshakeActor && !Session);
+
+ if (!ev->Get()->Node) {
+ TransitToErrorState("cannot get node info");
+ } else {
+ auto& info = *ev->Get()->Node;
+ TString name = PeerNameForHuman(PeerNodeId, info.Host, info.Port);
+ TechnicalPeerHostName = info.Host;
+ if (!Metrics) {
+ Metrics = Common->Metrics ? CreateInterconnectMetrics(Common) : CreateInterconnectCounters(Common);
+ }
+ Metrics->SetPeerInfo(name, info.Location.GetDataCenterId());
+
+ LOG_DEBUG_IC("ICP02", "configured for host %s", name.data());
+
+ ProcessConfigured();
+ }
+ }
+
+ void TInterconnectProxyTCP::ConfigureTimeout(TEvents::TEvWakeup::TPtr& ev) {
+ ICPROXY_PROFILED;
+
+ if (ev->Get() == ConfigureTimeoutCookie) {
+ TransitToErrorState("timed out while waiting for node info");
+ }
+ }
+
+ void TInterconnectProxyTCP::ProcessConfigured() {
+ ICPROXY_PROFILED;
+
+ // if the request was initiated by some activity involving Interconnect, then we are expected to start handshake
+ if (PendingSessionEvents) {
+ StartInitialHandshake();
+ }
+
+ // process incoming handshake requests; all failures were ejected from the queue along with the matching initiation requests
+ for (THolder<IEventHandle>& ev : PendingIncomingHandshakeEvents) {
+ TAutoPtr<IEventHandle> x(ev.Release());
+ IncomingHandshake(x);
+ }
+ PendingIncomingHandshakeEvents.clear();
+
+ // possible situation -- incoming handshake arrives, but actually it is not satisfied and rejected; in this case
+ // we are going to return to initial state as we have nothing to do
+ if (!IncomingHandshakeActor && !OutgoingHandshakeActor) {
+ SwitchToInitialState();
+ }
+ }
+
+ void TInterconnectProxyTCP::StartInitialHandshake() {
+ ICPROXY_PROFILED;
+
+ // since we are starting initial handshake for some reason, we'll drop any existing handshakes, if any
+ DropHandshakes();
+
+ // create and register handshake actor
+ OutgoingHandshakeActor = Register(CreateOutgoingHandshakeActor(Common, GenerateSessionVirtualId(),
+ TActorId(), PeerNodeId, 0, TechnicalPeerHostName, TSessionParams()), TMailboxType::ReadAsFilled);
+ OutgoingHandshakeActorCreated = TActivationContext::Now();
+
+ // prepare for new handshake
+ PrepareNewSessionHandshake();
+ }
+
+ void TInterconnectProxyTCP::StartResumeHandshake(ui64 inputCounter) {
+ ICPROXY_PROFILED;
+
+ // drop outgoing handshake if we have one; keep incoming handshakes as they may be useful
+ DropOutgoingHandshake();
+
+ // ensure that we have session
+ Y_VERIFY(Session);
+
+ // ensure that we have both virtual ids
+ Y_VERIFY(SessionVirtualId);
+ Y_VERIFY(RemoteSessionVirtualId);
+
+ // create and register handshake actor
+ OutgoingHandshakeActor = Register(CreateOutgoingHandshakeActor(Common, SessionVirtualId,
+ RemoteSessionVirtualId, PeerNodeId, inputCounter, TechnicalPeerHostName, Session->Params),
+ TMailboxType::ReadAsFilled);
+ OutgoingHandshakeActorCreated = TActivationContext::Now();
+ }
+
+ void TInterconnectProxyTCP::IssueIncomingHandshakeReply(const TActorId& handshakeId, ui64 peerLocalId,
+ THolder<IEventBase> event) {
+ ICPROXY_PROFILED;
+
+ Y_VERIFY(!IncomingHandshakeActor);
+ IncomingHandshakeActor = handshakeId;
+ IncomingHandshakeActorFilledIn = TActivationContext::Now();
+ Y_VERIFY(!LastSerialFromIncomingHandshake || *LastSerialFromIncomingHandshake <= peerLocalId);
+ LastSerialFromIncomingHandshake = peerLocalId;
+
+ if (OutgoingHandshakeActor && SelfId().NodeId() < PeerNodeId) {
+ // Both outgoing and incoming handshake are in progress. To prevent race condition during semultanous handshake
+ // incoming handshake must be held till outgoing handshake is complete or failed
+ LOG_DEBUG_IC("ICP06", "reply for incoming handshake (actor %s) is held", IncomingHandshakeActor.ToString().data());
+ HeldHandshakeReply = std::move(event);
+
+ // Check that we are in one of acceptable states that would properly handle handshake statuses.
+ const auto state = CurrentStateFunc();
+ Y_VERIFY(state == &TThis::PendingConnection || state == &TThis::StateWork, "invalid handshake request in state# %s", State);
+ } else {
+ LOG_DEBUG_IC("ICP07", "issued incoming handshake reply");
+
+ // No race, so we can send reply immediately.
+ Y_VERIFY(!HeldHandshakeReply);
+ Send(IncomingHandshakeActor, event.Release());
+
+ // Start waiting for handshake reply, if not yet started; also, if session is already created, then we don't
+ // switch from working state.
+ if (!Session) {
+ LOG_INFO_IC("ICP08", "No active sessions, becoming PendingConnection");
+ SwitchToState(__LINE__, "PendingConnection", &TThis::PendingConnection);
+ } else {
+ Y_VERIFY(CurrentStateFunc() == &TThis::StateWork);
+ }
+ }
+ }
+
+ void TInterconnectProxyTCP::IncomingHandshake(TEvHandshakeAsk::TPtr& ev) {
+ ICPROXY_PROFILED;
+
+ TEvHandshakeAsk *msg = ev->Get();
+
+ // TEvHandshakeAsk is only applicable for continuation requests
+ LOG_DEBUG_IC("ICP09", "(actor %s) from: %s for: %s", ev->Sender.ToString().data(),
+ ev->Get()->Self.ToString().data(), ev->Get()->Peer.ToString().data());
+
+ if (!Session) {
+ // if there is no open session, report error -- continuation request works only with open sessions
+ LOG_NOTICE_IC("ICP12", "(actor %s) peer tries to resume nonexistent session Self# %s Peer# %s",
+ ev->Sender.ToString().data(), msg->Self.ToString().data(), msg->Peer.ToString().data());
+ } else if (SessionVirtualId != ev->Get()->Peer || RemoteSessionVirtualId != ev->Get()->Self) {
+ // check session virtual ids for continuation
+ LOG_NOTICE_IC("ICP13", "(actor %s) virtual id mismatch with existing session (Peer: %s Self: %s"
+ " SessionVirtualId: %s RemoteSessionVirtualId: %s)", ev->Sender.ToString().data(),
+ ev->Get()->Peer.ToString().data(), ev->Get()->Self.ToString().data(), SessionVirtualId.ToString().data(),
+ RemoteSessionVirtualId.ToString().data());
+ } else {
+ // if we already have incoming handshake, then terminate existing one
+ DropIncomingHandshake();
+
+ // issue reply to the sender, possibly holding it while outgoing handshake is at race
+ THolder<IEventBase> reply = IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::ProcessHandshakeRequest, ev);
+ return IssueIncomingHandshakeReply(ev->Sender, RemoteSessionVirtualId.LocalId(), std::move(reply));
+ }
+
+ // error case -- report error to the handshake actor
+ Send(ev->Sender, new TEvHandshakeNak);
+ }
+
+ void TInterconnectProxyTCP::IncomingHandshake(TEvHandshakeRequest::TPtr& ev) {
+ ICPROXY_PROFILED;
+
+ LOG_DEBUG_IC("ICP17", "incoming handshake (actor %s)", ev->Sender.ToString().data());
+
+ const auto& record = ev->Get()->Record;
+ ui64 remotePID = record.GetProgramPID();
+ ui64 remoteStartTime = record.GetProgramStartTime();
+ ui64 remoteSerial = record.GetSerial();
+
+ if (RemoteProgramInfo && remotePID == RemoteProgramInfo->PID && remoteStartTime == RemoteProgramInfo->StartTime) {
+ if (remoteSerial < RemoteProgramInfo->Serial) {
+ LOG_INFO_IC("ICP18", "handshake (actor %s) is too old", ev->Sender.ToString().data());
+ Send(ev->Sender, new TEvents::TEvPoisonPill);
+ return;
+ } else {
+ RemoteProgramInfo->Serial = remoteSerial;
+ }
+ } else {
+ const auto ptr = new TProgramInfo;
+ ptr->PID = remotePID;
+ ptr->StartTime = remoteStartTime;
+ ptr->Serial = remoteSerial;
+ RemoteProgramInfo.Reset(ptr);
+ }
+
+ /* Let's check peer technical hostname */
+ if (record.HasSenderHostName() && TechnicalPeerHostName != record.GetSenderHostName()) {
+ Send(ev->Sender, new TEvHandshakeReplyError("host name mismatch"));
+ return;
+ }
+
+ // check sender actor id and check if it is not very old
+ if (LastSerialFromIncomingHandshake) {
+ const ui64 serial = record.GetSerial();
+ if (serial < *LastSerialFromIncomingHandshake) {
+ LOG_NOTICE_IC("ICP15", "Handshake# %s has duplicate serial# %" PRIu64
+ " LastSerialFromIncomingHandshake# %" PRIu64, ev->Sender.ToString().data(),
+ serial, *LastSerialFromIncomingHandshake);
+ Send(ev->Sender, new TEvHandshakeReplyError("duplicate serial"));
+ return;
+ } else if (serial == *LastSerialFromIncomingHandshake) {
+ LOG_NOTICE_IC("ICP15", "Handshake# %s is obsolete, serial# %" PRIu64
+ " LastSerialFromIncomingHandshake# %" PRIu64, ev->Sender.ToString().data(),
+ serial, *LastSerialFromIncomingHandshake);
+ Send(ev->Sender, new TEvents::TEvPoisonPill);
+ return;
+ }
+ }
+
+ // drop incoming handshake as this is definitely more recent
+ DropIncomingHandshake();
+
+ // prepare for new session
+ PrepareNewSessionHandshake();
+
+ auto event = MakeHolder<TEvHandshakeReplyOK>();
+ auto* pb = event->Record.MutableSuccess();
+ const TActorId virtualId = GenerateSessionVirtualId();
+ pb->SetProtocol(INTERCONNECT_PROTOCOL_VERSION);
+ pb->SetSenderActorId(virtualId.ToString());
+ pb->SetProgramPID(GetPID());
+ pb->SetProgramStartTime(Common->StartTime);
+ pb->SetSerial(virtualId.LocalId());
+
+ IssueIncomingHandshakeReply(ev->Sender, 0, std::move(event));
+ }
+
+ void TInterconnectProxyTCP::HandleHandshakeStatus(TEvHandshakeDone::TPtr& ev) {
+ ICPROXY_PROFILED;
+
+ TEvHandshakeDone *msg = ev->Get();
+
+ // Terminate handshake actor working in opposite direction, if set up.
+ if (ev->Sender == IncomingHandshakeActor) {
+ LOG_INFO_IC("ICP19", "incoming handshake succeeded");
+ DropIncomingHandshake(false);
+ DropOutgoingHandshake();
+ } else if (ev->Sender == OutgoingHandshakeActor) {
+ LOG_INFO_IC("ICP20", "outgoing handshake succeeded");
+ DropIncomingHandshake();
+ DropOutgoingHandshake(false);
+ } else {
+ /* It seems to be an old handshake. */
+ return;
+ }
+
+ Y_VERIFY(!IncomingHandshakeActor && !OutgoingHandshakeActor);
+ SwitchToState(__LINE__, "StateWork", &TThis::StateWork);
+
+ if (Session) {
+ // this is continuation request, check that virtual ids match
+ Y_VERIFY(SessionVirtualId == msg->Self && RemoteSessionVirtualId == msg->Peer);
+ } else {
+ // this is initial request, check that we have virtual ids not filled in
+ Y_VERIFY(!SessionVirtualId && !RemoteSessionVirtualId);
+ }
+
+ auto error = [&](const char* description) {
+ TransitToErrorState(description);
+ };
+
+ // If session is not created, then create new one.
+ if (!Session) {
+ RemoteProgramInfo = std::move(msg->ProgramInfo);
+ if (!RemoteProgramInfo) {
+ // we have received resume handshake, but session was closed concurrently while handshaking
+ return error("Session continuation race");
+ }
+
+ // Create new session actor.
+ SessionID = RegisterWithSameMailbox(Session = new TInterconnectSessionTCP(this, msg->Params));
+ IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::Init);
+ SessionVirtualId = msg->Self;
+ RemoteSessionVirtualId = msg->Peer;
+ LOG_INFO_IC("ICP22", "created new session: %s", SessionID.ToString().data());
+ }
+
+ // ensure that we have session local/peer virtual ids
+ Y_VERIFY(Session && SessionVirtualId && RemoteSessionVirtualId);
+
+ // Set up new connection for the session.
+ IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::SetNewConnection, ev);
+
+ // Reset retry timer
+ HoldByErrorWakeupDuration = TDuration::Zero();
+
+ /* Forward all held events */
+ ProcessPendingSessionEvents();
+ }
+
+ void TInterconnectProxyTCP::HandleHandshakeStatus(TEvHandshakeFail::TPtr& ev) {
+ ICPROXY_PROFILED;
+
+ // update error state log; this fail is inconclusive unless this is the last pending handshake
+ const bool inconclusive = (ev->Sender != IncomingHandshakeActor && ev->Sender != OutgoingHandshakeActor) ||
+ (IncomingHandshakeActor && OutgoingHandshakeActor);
+ LogHandshakeFail(ev, inconclusive);
+
+ if (ev->Sender == IncomingHandshakeActor) {
+ LOG_NOTICE_IC("ICP24", "incoming handshake failed, temporary: %" PRIu32 " explanation: %s outgoing: %s",
+ ui32(ev->Get()->Temporary), ev->Get()->Explanation.data(), OutgoingHandshakeActor.ToString().data());
+ DropIncomingHandshake(false);
+ } else if (ev->Sender == OutgoingHandshakeActor) {
+ LOG_NOTICE_IC("ICP25", "outgoing handshake failed, temporary: %" PRIu32 " explanation: %s incoming: %s held: %s",
+ ui32(ev->Get()->Temporary), ev->Get()->Explanation.data(), IncomingHandshakeActor.ToString().data(),
+ HeldHandshakeReply ? "yes" : "no");
+ DropOutgoingHandshake(false);
+
+ if (IEventBase* reply = HeldHandshakeReply.Release()) {
+ Y_VERIFY(IncomingHandshakeActor);
+ LOG_DEBUG_IC("ICP26", "sent held handshake reply to %s", IncomingHandshakeActor.ToString().data());
+ Send(IncomingHandshakeActor, reply);
+ }
+
+ // if we have no current session, then we have to drop all pending events as the outgoing handshake has failed
+ ProcessPendingSessionEvents();
+ } else {
+ /* It seems to be an old fail, just ignore it */
+ LOG_NOTICE_IC("ICP27", "obsolete handshake fail ignored");
+ return;
+ }
+
+ if (Metrics) {
+ Metrics->IncHandshakeFails();
+ }
+
+ if (IncomingHandshakeActor || OutgoingHandshakeActor) {
+ // one of handshakes is still going on
+ LOG_DEBUG_IC("ICP28", "other handshake is still going on");
+ return;
+ }
+
+ switch (ev->Get()->Temporary) {
+ case TEvHandshakeFail::HANDSHAKE_FAIL_TRANSIENT:
+ if (!Session) {
+ if (PendingSessionEvents) {
+ // try to start outgoing handshake as we have some events enqueued
+ StartInitialHandshake();
+ } else {
+ // return back to initial state as we have no session and no pending handshakes
+ SwitchToInitialState();
+ }
+ } else if (Session->Socket) {
+ // try to reestablish connection -- meaning restart handshake from the last known position
+ IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::ReestablishConnectionWithHandshake,
+ TDisconnectReason::HandshakeFailTransient());
+ } else {
+ // we have no active connection in that session, so just restart handshake from last known position
+ IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::StartHandshake);
+ }
+ break;
+
+ case TEvHandshakeFail::HANDSHAKE_FAIL_SESSION_MISMATCH:
+ StartInitialHandshake();
+ break;
+
+ case TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT:
+ TString timeExplanation = " LastSessionDieTime# " + LastSessionDieTime.ToString();
+ if (Session) {
+ InvokeOtherActor(*Session, &TInterconnectSessionTCP::Terminate,
+ TDisconnectReason::HandshakeFailPermanent());
+ }
+ TransitToErrorState(ev->Get()->Explanation + timeExplanation, false);
+ break;
+ }
+ }
+
+ void TInterconnectProxyTCP::LogHandshakeFail(TEvHandshakeFail::TPtr& ev, bool inconclusive) {
+ ICPROXY_PROFILED;
+
+ TString kind = "unknown";
+ switch (ev->Get()->Temporary) {
+ case TEvHandshakeFail::HANDSHAKE_FAIL_TRANSIENT:
+ kind = Session ? "transient w/session" : "transient w/o session";
+ break;
+
+ case TEvHandshakeFail::HANDSHAKE_FAIL_SESSION_MISMATCH:
+ kind = "session_mismatch";
+ break;
+
+ case TEvHandshakeFail::HANDSHAKE_FAIL_PERMANENT:
+ kind = "permanent";
+ break;
+ }
+ if (inconclusive) {
+ kind += " inconclusive";
+ }
+ UpdateErrorStateLog(TActivationContext::Now(), kind, ev->Get()->Explanation);
+ }
+
+ void TInterconnectProxyTCP::ProcessPendingSessionEvents() {
+ ICPROXY_PROFILED;
+
+ while (PendingSessionEvents) {
+ TPendingSessionEvent ev = std::move(PendingSessionEvents.front());
+ PendingSessionEventsSize -= ev.Size;
+ TAutoPtr<IEventHandle> event(ev.Event.Release());
+ PendingSessionEvents.pop_front();
+
+ if (Session) {
+ ForwardSessionEventToSession(event);
+ } else {
+ DropSessionEvent(event);
+ }
+ }
+ }
+
+ void TInterconnectProxyTCP::DropSessionEvent(STATEFN_SIG) {
+ ICPROXY_PROFILED;
+
+ ValidateEvent(ev, "DropSessionEvent");
+ switch (ev->GetTypeRewrite()) {
+ case TEvInterconnect::EvForward:
+ if (ev->Flags & IEventHandle::FlagSubscribeOnSession) {
+ Send(ev->Sender, new TEvInterconnect::TEvNodeDisconnected(PeerNodeId), 0, ev->Cookie);
+ }
+ TActivationContext::Send(ev->ForwardOnNondelivery(TEvents::TEvUndelivered::Disconnected));
+ break;
+
+ case TEvInterconnect::TEvConnectNode::EventType:
+ case TEvents::TEvSubscribe::EventType:
+ Send(ev->Sender, new TEvInterconnect::TEvNodeDisconnected(PeerNodeId), 0, ev->Cookie);
+ break;
+
+ case TEvents::TEvUnsubscribe::EventType:
+ /* Do nothing */
+ break;
+
+ default:
+ Y_FAIL("Unexpected type of event in held event queue");
+ }
+ }
+
+ void TInterconnectProxyTCP::UnregisterSession(TInterconnectSessionTCP* session) {
+ ICPROXY_PROFILED;
+
+ Y_VERIFY(Session && Session == session && SessionID);
+
+ LOG_INFO_IC("ICP30", "unregister session Session# %s VirtualId# %s", SessionID.ToString().data(),
+ SessionVirtualId.ToString().data());
+
+ Session = nullptr;
+ SessionID = TActorId();
+
+ // drop all pending events as we are closed
+ ProcessPendingSessionEvents();
+
+ // reset virtual ids as this session is terminated
+ SessionVirtualId = TActorId();
+ RemoteSessionVirtualId = TActorId();
+
+ if (Metrics) {
+ Metrics->IncSessionDeaths();
+ }
+ LastSessionDieTime = TActivationContext::Now();
+
+ if (IncomingHandshakeActor || OutgoingHandshakeActor) {
+ PrepareNewSessionHandshake();
+ } else {
+ SwitchToInitialState();
+ }
+ }
+
+ void TInterconnectProxyTCP::EnqueueSessionEvent(STATEFN_SIG) {
+ ICPROXY_PROFILED;
+
+ ValidateEvent(ev, "EnqueueSessionEvent");
+ const ui32 size = ev->GetSize();
+ PendingSessionEventsSize += size;
+ PendingSessionEvents.emplace_back(TActivationContext::Now() + Common->Settings.MessagePendingTimeout, size, ev);
+ ScheduleCleanupEventQueue();
+ CleanupEventQueue();
+ }
+
+ void TInterconnectProxyTCP::EnqueueIncomingHandshakeEvent(STATEFN_SIG) {
+ ICPROXY_PROFILED;
+
+ // enqueue handshake request
+ Y_UNUSED();
+ PendingIncomingHandshakeEvents.emplace_back(ev);
+ }
+
+ void TInterconnectProxyTCP::EnqueueIncomingHandshakeEvent(TEvHandshakeDone::TPtr& /*ev*/) {
+ ICPROXY_PROFILED;
+
+ // TEvHandshakeDone can't get into the queue, because we have to process handshake request first; this may be the
+ // race with the previous handshakes, so simply ignore it
+ }
+
+ void TInterconnectProxyTCP::EnqueueIncomingHandshakeEvent(TEvHandshakeFail::TPtr& ev) {
+ ICPROXY_PROFILED;
+
+ for (auto it = PendingIncomingHandshakeEvents.begin(); it != PendingIncomingHandshakeEvents.end(); ++it) {
+ THolder<IEventHandle>& pendingEvent = *it;
+ if (pendingEvent->Sender == ev->Sender) {
+ // we have found cancellation request for the pending handshake request; so simply remove it from the
+ // deque, as we are not interested in failure reason; must likely it happens because of handshake timeout
+ if (pendingEvent->GetTypeRewrite() == TEvHandshakeFail::EventType) {
+ TEvHandshakeFail::TPtr tmp(static_cast<TEventHandle<TEvHandshakeFail>*>(pendingEvent.Release()));
+ LogHandshakeFail(tmp, true);
+ }
+ PendingIncomingHandshakeEvents.erase(it);
+ break;
+ }
+ }
+ }
+
+ void TInterconnectProxyTCP::ForwardSessionEventToSession(STATEFN_SIG) {
+ ICPROXY_PROFILED;
+
+ Y_VERIFY(Session && SessionID);
+ ValidateEvent(ev, "ForwardSessionEventToSession");
+ InvokeOtherActor(*Session, &TInterconnectSessionTCP::Receive, ev, TActivationContext::ActorContextFor(SessionID));
+ }
+
+ void TInterconnectProxyTCP::GenerateHttpInfo(NMon::TEvHttpInfo::TPtr& ev) {
+ ICPROXY_PROFILED;
+
+ LOG_INFO_IC("ICP31", "proxy http called");
+
+ TStringStream str;
+
+ HTML(str) {
+ DIV_CLASS("panel panel-info") {
+ DIV_CLASS("panel-heading") {
+ str << "Proxy";
+ }
+ DIV_CLASS("panel-body") {
+ TABLE_CLASS("table") {
+ TABLEHEAD() {
+ TABLER() {
+ TABLEH() {
+ str << "Sensor";
+ }
+ TABLEH() {
+ str << "Value";
+ }
+ }
+ }
+#define MON_VAR(NAME) \
+ TABLER() { \
+ TABLED() { \
+ str << #NAME; \
+ } \
+ TABLED() { \
+ str << NAME; \
+ } \
+ }
+
+ TABLEBODY() {
+ MON_VAR(TActivationContext::Now())
+ MON_VAR(SessionID)
+ MON_VAR(LastSessionDieTime)
+ MON_VAR(IncomingHandshakeActor)
+ MON_VAR(IncomingHandshakeActorFilledIn)
+ MON_VAR(IncomingHandshakeActorReset)
+ MON_VAR(OutgoingHandshakeActor)
+ MON_VAR(OutgoingHandshakeActorCreated)
+ MON_VAR(OutgoingHandshakeActorReset)
+ MON_VAR(State)
+ MON_VAR(StateSwitchTime)
+ }
+ }
+ }
+ }
+
+ DIV_CLASS("panel panel-info") {
+ DIV_CLASS("panel-heading") {
+ str << "Error Log";
+ }
+ DIV_CLASS("panel-body") {
+ TABLE_CLASS("table") {
+ TABLEHEAD() {
+ TABLER() {
+ TABLEH() {
+ str << "Timestamp";
+ }
+ TABLEH() {
+ str << "Elapsed";
+ }
+ TABLEH() {
+ str << "Kind";
+ }
+ TABLEH() {
+ str << "Explanation";
+ }
+ }
+ }
+ TABLEBODY() {
+ const TInstant now = TActivationContext::Now();
+ const TInstant barrier = now - TDuration::Minutes(1);
+ for (auto it = ErrorStateLog.rbegin(); it != ErrorStateLog.rend(); ++it) {
+ auto wrapper = [&](const auto& lambda) {
+ if (std::get<0>(*it) > barrier) {
+ str << "<strong>";
+ lambda();
+ str << "</strong>";
+ } else {
+ lambda();
+ }
+ };
+ TABLER() {
+ TABLED() {
+ wrapper([&] {
+ str << std::get<0>(*it);
+ });
+ }
+ TABLED() {
+ wrapper([&] {
+ str << now - std::get<0>(*it);
+ });
+ }
+ TABLED() {
+ wrapper([&] {
+ str << std::get<1>(*it);
+ });
+ }
+ TABLED() {
+ wrapper([&] {
+ str << std::get<2>(*it);
+ });
+
+ ui32 rep = std::get<3>(*it);
+ if (rep != 1) {
+ str << " <strong>x" << rep << "</strong>";
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (Session != nullptr) {
+ Session->GenerateHttpInfo(str);
+ }
+
+ Send(ev->Sender, new NMon::TEvHttpInfoRes(str.Str()));
+ }
+
+ void TInterconnectProxyTCP::TransitToErrorState(TString explanation, bool updateErrorLog) {
+ ICPROXY_PROFILED;
+
+ LOG_NOTICE_IC("ICP32", "transit to hold-by-error state Explanation# %s", explanation.data());
+ LOG_INFO(*TlsActivationContext, NActorsServices::INTERCONNECT_STATUS, "[%u] error state: %s", PeerNodeId, explanation.data());
+
+ if (updateErrorLog) {
+ UpdateErrorStateLog(TActivationContext::Now(), "permanent conclusive", explanation);
+ }
+
+ Y_VERIFY(Session == nullptr);
+ Y_VERIFY(!SessionID);
+
+ // recalculate wakeup timeout -- if this is the first failure, then we sleep for default timeout; otherwise we
+ // sleep N times longer than the previous try, but not longer than desired number of seconds
+ HoldByErrorWakeupDuration = HoldByErrorWakeupDuration != TDuration::Zero()
+ ? Min(HoldByErrorWakeupDuration * SleepRetryMultiplier, MaxErrorSleep)
+ : FirstErrorSleep;
+
+ // transit to required state and arm wakeup timer
+ if (Terminated) {
+ // switch to this state permanently
+ SwitchToState(__LINE__, "HoldByError", &TThis::HoldByError);
+ HoldByErrorWakeupCookie = nullptr;
+ } else {
+ SwitchToState(__LINE__, "HoldByError", &TThis::HoldByError, HoldByErrorWakeupDuration,
+ HoldByErrorWakeupCookie = new TEvents::TEvWakeup);
+ }
+
+ /* Process all pending events. */
+ ProcessPendingSessionEvents();
+
+ /* Terminate handshakes */
+ DropHandshakes();
+
+ /* Terminate pending incoming handshake requests. */
+ for (auto& ev : PendingIncomingHandshakeEvents) {
+ Send(ev->Sender, new TEvents::TEvPoisonPill);
+ if (ev->GetTypeRewrite() == TEvHandshakeFail::EventType) {
+ TEvHandshakeFail::TPtr tmp(static_cast<TEventHandle<TEvHandshakeFail>*>(ev.Release()));
+ LogHandshakeFail(tmp, true);
+ }
+ }
+ PendingIncomingHandshakeEvents.clear();
+ }
+
+ void TInterconnectProxyTCP::WakeupFromErrorState(TEvents::TEvWakeup::TPtr& ev) {
+ ICPROXY_PROFILED;
+
+ LOG_INFO_IC("ICP33", "wake up from error state");
+
+ if (ev->Get() == HoldByErrorWakeupCookie) {
+ SwitchToInitialState();
+ }
+ }
+
+ void TInterconnectProxyTCP::Disconnect() {
+ ICPROXY_PROFILED;
+
+ // terminate handshakes (if any)
+ DropHandshakes();
+
+ if (Session) {
+ IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::Terminate, TDisconnectReason::UserRequest());
+ } else {
+ TransitToErrorState("forced disconnect");
+ }
+ }
+
+ void TInterconnectProxyTCP::ScheduleCleanupEventQueue() {
+ ICPROXY_PROFILED;
+
+ if (!CleanupEventQueueScheduled && PendingSessionEvents) {
+ // apply batching at 50 ms granularity
+ Schedule(Max(TDuration::MilliSeconds(50), PendingSessionEvents.front().Deadline - TActivationContext::Now()), new TEvCleanupEventQueue);
+ CleanupEventQueueScheduled = true;
+ }
+ }
+
+ void TInterconnectProxyTCP::HandleCleanupEventQueue() {
+ ICPROXY_PROFILED;
+
+ Y_VERIFY(CleanupEventQueueScheduled);
+ CleanupEventQueueScheduled = false;
+ CleanupEventQueue();
+ ScheduleCleanupEventQueue();
+ }
+
+ void TInterconnectProxyTCP::CleanupEventQueue() {
+ ICPROXY_PROFILED;
+
+ const TInstant now = TActivationContext::Now();
+ while (PendingSessionEvents) {
+ TPendingSessionEvent& ev = PendingSessionEvents.front();
+ if (now >= ev.Deadline || PendingSessionEventsSize > Common->Settings.MessagePendingSize) {
+ TAutoPtr<IEventHandle> event(ev.Event.Release());
+ PendingSessionEventsSize -= ev.Size;
+ DropSessionEvent(event);
+ PendingSessionEvents.pop_front();
+ } else {
+ break;
+ }
+ }
+ }
+
+ void TInterconnectProxyTCP::HandleClosePeerSocket() {
+ ICPROXY_PROFILED;
+
+ if (Session && Session->Socket) {
+ LOG_INFO_IC("ICP34", "closed connection by debug command");
+ Session->Socket->Shutdown(SHUT_RDWR);
+ }
+ }
+
+ void TInterconnectProxyTCP::HandleCloseInputSession() {
+ ICPROXY_PROFILED;
+
+ if (Session) {
+ IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::CloseInputSession);
+ }
+ }
+
+ void TInterconnectProxyTCP::HandlePoisonSession() {
+ ICPROXY_PROFILED;
+
+ if (Session) {
+ IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::Terminate, TDisconnectReason::Debug());
+ }
+ }
+
+ void TInterconnectProxyTCP::HandleSessionBufferSizeRequest(TEvSessionBufferSizeRequest::TPtr& ev) {
+ ICPROXY_PROFILED;
+
+ ui64 bufSize = 0;
+ if (Session) {
+ bufSize = Session->TotalOutputQueueSize;
+ }
+
+ Send(ev->Sender, new TEvSessionBufferSizeResponse(SessionID, bufSize));
+ }
+
+ void TInterconnectProxyTCP::Handle(TEvQueryStats::TPtr& ev) {
+ ICPROXY_PROFILED;
+
+ TProxyStats stats;
+ stats.Path = Sprintf("peer%04" PRIu32, PeerNodeId);
+ stats.State = State;
+ stats.PeerScopeId = Session ? Session->Params.PeerScopeId : TScopeId();
+ stats.LastSessionDieTime = LastSessionDieTime;
+ stats.TotalOutputQueueSize = Session ? Session->TotalOutputQueueSize : 0;
+ stats.Connected = Session ? (bool)Session->Socket : false;
+ stats.Host = TechnicalPeerHostName;
+ stats.Port = 0;
+ ui32 rep = 0;
+ std::tie(stats.LastErrorTimestamp, stats.LastErrorKind, stats.LastErrorExplanation, rep) = ErrorStateLog
+ ? ErrorStateLog.back()
+ : std::make_tuple(TInstant(), TString(), TString(), 1U);
+ if (rep != 1) {
+ stats.LastErrorExplanation += Sprintf(" x%" PRIu32, rep);
+ }
+ stats.Ping = Session ? Session->GetPingRTT() : TDuration::Zero();
+ stats.ClockSkew = Session ? Session->GetClockSkew() : 0;
+ if (Session) {
+ if (auto *x = dynamic_cast<NInterconnect::TSecureSocket*>(Session->Socket.Get())) {
+ stats.Encryption = Sprintf("%s/%u", x->GetCipherName().data(), x->GetCipherBits());
+ } else {
+ stats.Encryption = "none";
+ }
+ }
+
+ auto response = MakeHolder<TEvStats>();
+ response->PeerNodeId = PeerNodeId;
+ response->ProxyStats = std::move(stats);
+ Send(ev->Sender, response.Release());
+ }
+
+ void TInterconnectProxyTCP::HandleTerminate() {
+ ICPROXY_PROFILED;
+
+ if (Session) {
+ IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::Terminate, TDisconnectReason());
+ }
+ Terminated = true;
+ TransitToErrorState("terminated");
+ }
+
+ void TInterconnectProxyTCP::PassAway() {
+ if (Session) {
+ IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::Terminate, TDisconnectReason());
+ }
+ if (DynamicPtr) {
+ Y_VERIFY(*DynamicPtr == this);
+ *DynamicPtr = nullptr;
+ }
+ // TODO: unregister actor mon page
+ TActor::PassAway();
+ }
+}
diff --git a/library/cpp/actors/interconnect/interconnect_tcp_proxy.h b/library/cpp/actors/interconnect/interconnect_tcp_proxy.h
new file mode 100644
index 0000000000..023e5bd1ee
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_tcp_proxy.h
@@ -0,0 +1,537 @@
+#pragma once
+
+#include <library/cpp/actors/core/actor_bootstrapped.h>
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/actors/core/event_pb.h>
+#include <library/cpp/actors/core/events.h>
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+
+#include "interconnect_common.h"
+#include "interconnect_counters.h"
+#include "interconnect_tcp_session.h"
+#include "profiler.h"
+
+#define ICPROXY_PROFILED TFunction func(*this, __func__, __LINE__)
+
+namespace NActors {
+
+
+ /* WARNING: all proxy actors should be alive during actorsystem activity */
+ class TInterconnectProxyTCP
+ : public TActor<TInterconnectProxyTCP>
+ , public TInterconnectLoggingBase
+ , public TProfiled
+ {
+ enum {
+ EvCleanupEventQueue = EventSpaceBegin(TEvents::ES_PRIVATE),
+ EvQueryStats,
+ EvStats,
+ EvPassAwayIfNeeded,
+ };
+
+ struct TEvCleanupEventQueue : TEventLocal<TEvCleanupEventQueue, EvCleanupEventQueue> {};
+
+ public:
+ struct TEvQueryStats : TEventLocal<TEvQueryStats, EvQueryStats> {};
+
+ struct TProxyStats {
+ TString Path;
+ TString State;
+ TScopeId PeerScopeId;
+ TInstant LastSessionDieTime;
+ ui64 TotalOutputQueueSize;
+ bool Connected;
+ TString Host;
+ ui16 Port;
+ TInstant LastErrorTimestamp;
+ TString LastErrorKind;
+ TString LastErrorExplanation;
+ TDuration Ping;
+ i64 ClockSkew;
+ TString Encryption;
+ };
+
+ struct TEvStats : TEventLocal<TEvStats, EvStats> {
+ ui32 PeerNodeId;
+ TProxyStats ProxyStats;
+ };
+
+ static constexpr EActivityType ActorActivityType() {
+ return INTERCONNECT_PROXY_TCP;
+ }
+
+ TInterconnectProxyTCP(const ui32 node, TInterconnectProxyCommon::TPtr common, IActor **dynamicPtr = nullptr);
+
+ STFUNC(StateInit) {
+ Bootstrap();
+ if (ev->Type != TEvents::TSystem::Bootstrap) { // for dynamic nodes we do not receive Bootstrap event
+ Receive(ev, ctx);
+ }
+ }
+
+ void Bootstrap();
+ void Registered(TActorSystem* sys, const TActorId& owner) override;
+
+ private:
+ friend class TInterconnectSessionTCP;
+ friend class TInterconnectSessionTCPv0;
+ friend class THandshake;
+ friend class TInputSessionTCP;
+
+ void UnregisterSession(TInterconnectSessionTCP* session);
+
+#define SESSION_EVENTS(HANDLER) \
+ fFunc(TEvInterconnect::EvForward, HANDLER) \
+ fFunc(TEvInterconnect::TEvConnectNode::EventType, HANDLER) \
+ fFunc(TEvents::TEvSubscribe::EventType, HANDLER) \
+ fFunc(TEvents::TEvUnsubscribe::EventType, HANDLER)
+
+#define INCOMING_HANDSHAKE_EVENTS(HANDLER) \
+ fFunc(TEvHandshakeAsk::EventType, HANDLER) \
+ fFunc(TEvHandshakeRequest::EventType, HANDLER)
+
+#define HANDSHAKE_STATUS_EVENTS(HANDLER) \
+ hFunc(TEvHandshakeDone, HANDLER) \
+ hFunc(TEvHandshakeFail, HANDLER)
+
+#define PROXY_STFUNC(STATE, SESSION_HANDLER, INCOMING_HANDSHAKE_HANDLER, \
+ HANDSHAKE_STATUS_HANDLER, DISCONNECT_HANDLER, \
+ WAKEUP_HANDLER, NODE_INFO_HANDLER) \
+ STATEFN(STATE) { \
+ const ui32 type = ev->GetTypeRewrite(); \
+ const bool profiled = type != TEvInterconnect::EvForward \
+ && type != TEvInterconnect::EvConnectNode \
+ && type != TEvents::TSystem::Subscribe \
+ && type != TEvents::TSystem::Unsubscribe; \
+ if (profiled) { \
+ TProfiled::Start(); \
+ } \
+ { \
+ TProfiled::TFunction func(*this, __func__, __LINE__); \
+ switch (type) { \
+ SESSION_EVENTS(SESSION_HANDLER) \
+ INCOMING_HANDSHAKE_EVENTS(INCOMING_HANDSHAKE_HANDLER) \
+ HANDSHAKE_STATUS_EVENTS(HANDSHAKE_STATUS_HANDLER) \
+ cFunc(TEvInterconnect::EvDisconnect, DISCONNECT_HANDLER) \
+ hFunc(TEvents::TEvWakeup, WAKEUP_HANDLER) \
+ hFunc(TEvGetSecureSocket, Handle) \
+ hFunc(NMon::TEvHttpInfo, GenerateHttpInfo) \
+ cFunc(EvCleanupEventQueue, HandleCleanupEventQueue) \
+ hFunc(TEvInterconnect::TEvNodeInfo, NODE_INFO_HANDLER) \
+ cFunc(TEvInterconnect::EvClosePeerSocket, HandleClosePeerSocket) \
+ cFunc(TEvInterconnect::EvCloseInputSession, HandleCloseInputSession) \
+ cFunc(TEvInterconnect::EvPoisonSession, HandlePoisonSession) \
+ hFunc(TEvSessionBufferSizeRequest, HandleSessionBufferSizeRequest) \
+ hFunc(TEvQueryStats, Handle) \
+ cFunc(TEvInterconnect::EvTerminate, HandleTerminate) \
+ cFunc(EvPassAwayIfNeeded, HandlePassAwayIfNeeded) \
+ default: \
+ Y_FAIL("unexpected event Type# 0x%08" PRIx32, type); \
+ } \
+ } \
+ if (profiled) { \
+ if (TProfiled::Duration() >= TDuration::MilliSeconds(16)) { \
+ const TString report = TProfiled::Format(); \
+ LOG_ERROR_IC("ICP35", "event processing took too much time %s", report.data()); \
+ } \
+ TProfiled::Finish(); \
+ } \
+ }
+
+ template <typename T>
+ void Ignore(T& /*ev*/) {
+ ICPROXY_PROFILED;
+ }
+
+ void Ignore() {
+ ICPROXY_PROFILED;
+ }
+
+ void Ignore(TEvHandshakeDone::TPtr& ev) {
+ ICPROXY_PROFILED;
+
+ Y_VERIFY(ev->Sender != IncomingHandshakeActor);
+ Y_VERIFY(ev->Sender != OutgoingHandshakeActor);
+ }
+
+ void Ignore(TEvHandshakeFail::TPtr& ev) {
+ ICPROXY_PROFILED;
+
+ Y_VERIFY(ev->Sender != IncomingHandshakeActor);
+ Y_VERIFY(ev->Sender != OutgoingHandshakeActor);
+ LogHandshakeFail(ev, true);
+ }
+
+ const char* State = nullptr;
+ TInstant StateSwitchTime;
+
+ template <typename... TArgs>
+ void SwitchToState(int line, const char* name, TArgs&&... args) {
+ ICPROXY_PROFILED;
+
+ LOG_DEBUG_IC("ICP77", "@%d %s -> %s", line, State, name);
+ State = name;
+ StateSwitchTime = TActivationContext::Now();
+ Become(std::forward<TArgs>(args)...);
+ Y_VERIFY(!Terminated || CurrentStateFunc() == &TThis::HoldByError); // ensure we never escape this state
+ if (CurrentStateFunc() != &TThis::PendingActivation) {
+ PassAwayTimestamp = TInstant::Max();
+ }
+ }
+
+ TInstant PassAwayTimestamp;
+ bool PassAwayScheduled = false;
+
+ void SwitchToInitialState() {
+ ICPROXY_PROFILED;
+
+ Y_VERIFY(!PendingSessionEvents && !PendingIncomingHandshakeEvents, "%s PendingSessionEvents# %zu"
+ " PendingIncomingHandshakeEvents# %zu State# %s", LogPrefix.data(), PendingSessionEvents.size(),
+ PendingIncomingHandshakeEvents.size(), State);
+ SwitchToState(__LINE__, "PendingActivation", &TThis::PendingActivation);
+ if (DynamicPtr && !PassAwayScheduled && PassAwayTimestamp != TInstant::Max()) {
+ TActivationContext::Schedule(PassAwayTimestamp, new IEventHandle(EvPassAwayIfNeeded, 0, SelfId(),
+ {}, nullptr, 0));
+ PassAwayScheduled = true;
+ }
+ }
+
+ void HandlePassAwayIfNeeded() {
+ Y_VERIFY(PassAwayScheduled);
+ if (PassAwayTimestamp != TInstant::Max()) {
+ PassAway();
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // PendingActivation
+ //
+ // In this state we are just waiting for some activities, which may include:
+ // * an external Session event
+ // * incoming handshake request
+ //
+ // Upon receiving such event, we put it to corresponding queue and initiate start up by calling IssueGetNodeRequest,
+ // which, as the name says, issued TEvGetNode to the nameservice and arms timer to handle timeout (which should not
+ // occur, but we want to be sure we don't hang on this), and then switches to PendingNodeInfo state.
+
+ PROXY_STFUNC(PendingActivation,
+ RequestNodeInfo, // Session events
+ RequestNodeInfoForIncomingHandshake, // Incoming handshake requests
+ Ignore, // Handshake status
+ Ignore, // Disconnect request
+ Ignore, // Wakeup
+ Ignore // Node info
+ )
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // PendingNodeInfo
+ //
+ // This state is entered when we asked nameserver to provide description for peer node we are working with. All
+ // external Session events and incoming handshake requests are enqueued into their respective queues, TEvNodeInfo
+ // is main event that triggers processing. On success, we try to initiate outgoing handshake if needed, or process
+ // incoming handshakes. On error, we enter HoldByError state.
+ //
+ // NOTE: handshake status events are also enqueued as the handshake actor may have generated failure event due to
+ // timeout or some other reason without waiting for acknowledge, and it must be processed correctly to prevent
+ // session hang
+
+ PROXY_STFUNC(PendingNodeInfo,
+ EnqueueSessionEvent, // Session events
+ EnqueueIncomingHandshakeEvent, // Incoming handshake requests
+ EnqueueIncomingHandshakeEvent, // Handshake status
+ Disconnect, // Disconnect request
+ ConfigureTimeout, // Wakeup
+ Configure // Node info
+ )
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // PendingConnection
+ //
+ // Here we have issued outgoing handshake or have accepted (or may be both) incoming handshake and we are waiting for
+ // the status of the handshake. When one if handshakes finishes, we use this status to establish connection (or to
+ // go to error state). When one handshake terminates with error while other is running, we will still wait for the
+ // second one to finish.
+
+ PROXY_STFUNC(PendingConnection,
+ EnqueueSessionEvent, // Session events
+ IncomingHandshake, // Incoming handshake requests
+ HandleHandshakeStatus, // Handshake status
+ Disconnect, // Disconnect request
+ Ignore, // Wakeup
+ Ignore // Node info
+ )
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // StateWork
+ //
+ // We have accepted session and process any incoming messages with the session. Incoming handshakes are accepted
+ // concurrently and applied when finished.
+
+ PROXY_STFUNC(StateWork,
+ ForwardSessionEventToSession, // Session events
+ IncomingHandshake, // Incoming handshake requests
+ HandleHandshakeStatus, // Handshake status
+ Disconnect, // Disconnect request
+ Ignore, // Wakeup
+ Ignore // Node info
+ )
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // HoldByError
+ //
+ // When something bad happens with the connection, we sleep in this state. After wake up we go back to
+ // PendingActivation.
+
+ PROXY_STFUNC(HoldByError,
+ DropSessionEvent, // Session events
+ RequestNodeInfoForIncomingHandshake, // Incoming handshake requests
+ Ignore, // Handshake status
+ Ignore, // Disconnect request
+ WakeupFromErrorState, // Wakeup
+ Ignore // Node info
+ )
+
+#undef SESSION_EVENTS
+#undef INCOMING_HANDSHAKE_EVENTS
+#undef HANDSHAKE_STATUS_EVENTS
+#undef PROXY_STFUNC
+
+ void ForwardSessionEventToSession(STATEFN_SIG);
+ void EnqueueSessionEvent(STATEFN_SIG);
+
+ // Incoming handshake handlers, including special wrapper when the IncomingHandshake is used as fFunc
+ void IncomingHandshake(STATEFN_SIG) {
+ switch (ev->GetTypeRewrite()) {
+ hFunc(TEvHandshakeAsk, IncomingHandshake);
+ hFunc(TEvHandshakeRequest, IncomingHandshake);
+ default:
+ Y_FAIL();
+ }
+ }
+ void IncomingHandshake(TEvHandshakeAsk::TPtr& ev);
+ void IncomingHandshake(TEvHandshakeRequest::TPtr& ev);
+
+ void RequestNodeInfo(STATEFN_SIG);
+ void RequestNodeInfoForIncomingHandshake(STATEFN_SIG);
+
+ void StartInitialHandshake();
+ void StartResumeHandshake(ui64 inputCounter);
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Incoming handshake event queue processing
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ void EnqueueIncomingHandshakeEvent(STATEFN_SIG);
+ void EnqueueIncomingHandshakeEvent(TEvHandshakeDone::TPtr& ev);
+ void EnqueueIncomingHandshakeEvent(TEvHandshakeFail::TPtr& ev);
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // PendingNodeInfo
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ IEventBase* ConfigureTimeoutCookie; // pointer to the scheduled event used to match sent and received events
+
+ void StartConfiguring();
+ void Configure(TEvInterconnect::TEvNodeInfo::TPtr& ev);
+ void ConfigureTimeout(TEvents::TEvWakeup::TPtr& ev);
+ void ProcessConfigured();
+
+ void HandleHandshakeStatus(TEvHandshakeDone::TPtr& ev);
+ void HandleHandshakeStatus(TEvHandshakeFail::TPtr& ev);
+
+ void TransitToErrorState(TString Explanation, bool updateErrorLog = true);
+ void WakeupFromErrorState(TEvents::TEvWakeup::TPtr& ev);
+ void Disconnect();
+
+ const ui32 PeerNodeId;
+ IActor **DynamicPtr;
+
+ void ValidateEvent(TAutoPtr<IEventHandle>& ev, const char* func) {
+ if (SelfId().NodeId() == PeerNodeId) {
+ TString msg = Sprintf("Event Type# 0x%08" PRIx32 " TypeRewrite# 0x%08" PRIx32
+ " from Sender# %s sent to the proxy for the node itself via Interconnect;"
+ " THIS IS NOT A BUG IN INTERCONNECT, check the event sender instead",
+ ev->Type, ev->GetTypeRewrite(), ev->Sender.ToString().data());
+ LOG_ERROR_IC("ICP03", "%s", msg.data());
+ Y_VERIFY_DEBUG(false, "%s", msg.data());
+ }
+
+ Y_VERIFY(ev->GetTypeRewrite() != TEvInterconnect::EvForward || ev->Recipient.NodeId() == PeerNodeId,
+ "Recipient/Proxy NodeId mismatch Recipient# %s Type# 0x%08" PRIx32 " PeerNodeId# %" PRIu32 " Func# %s",
+ ev->Recipient.ToString().data(), ev->Type, PeerNodeId, func);
+ }
+
+ // Common with helpers
+ // All proxy actors share the same information in the object
+ // read only
+ TInterconnectProxyCommon::TPtr const Common;
+
+ const TActorId& GetNameserviceId() const {
+ return Common->NameserviceId;
+ }
+
+ TString TechnicalPeerHostName;
+
+ std::shared_ptr<IInterconnectMetrics> Metrics;
+
+ void HandleClosePeerSocket();
+ void HandleCloseInputSession();
+ void HandlePoisonSession();
+
+ void HandleSessionBufferSizeRequest(TEvSessionBufferSizeRequest::TPtr& ev);
+
+ bool CleanupEventQueueScheduled = false;
+ void ScheduleCleanupEventQueue();
+ void HandleCleanupEventQueue();
+ void CleanupEventQueue();
+
+ // hold all events before connection is established
+ struct TPendingSessionEvent {
+ TInstant Deadline;
+ ui32 Size;
+ THolder<IEventHandle> Event;
+
+ TPendingSessionEvent(TInstant deadline, ui32 size, TAutoPtr<IEventHandle> event)
+ : Deadline(deadline)
+ , Size(size)
+ , Event(event)
+ {}
+ };
+ TDeque<TPendingSessionEvent> PendingSessionEvents;
+ ui64 PendingSessionEventsSize = 0;
+ void ProcessPendingSessionEvents();
+ void DropSessionEvent(STATEFN_SIG);
+
+ TInterconnectSessionTCP* Session = nullptr;
+ TActorId SessionID;
+
+ // virtual ids used during handshake to check if it is the connection
+ // for the same session or to find out the latest shandshake
+ // it's virtual because session actor apears after successfull handshake
+ TActorId SessionVirtualId;
+ TActorId RemoteSessionVirtualId;
+
+ TActorId GenerateSessionVirtualId() {
+ ICPROXY_PROFILED;
+
+ const ui64 localId = TlsActivationContext->ExecutorThread.ActorSystem->AllocateIDSpace(1);
+ return NActors::TActorId(SelfId().NodeId(), 0, localId, 0);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ TActorId IncomingHandshakeActor;
+ TInstant IncomingHandshakeActorFilledIn;
+ TInstant IncomingHandshakeActorReset;
+ TMaybe<ui64> LastSerialFromIncomingHandshake;
+ THolder<IEventBase> HeldHandshakeReply;
+
+ void DropIncomingHandshake(bool poison = true) {
+ ICPROXY_PROFILED;
+
+ if (const TActorId& actorId = std::exchange(IncomingHandshakeActor, TActorId())) {
+ LOG_DEBUG_IC("ICP111", "dropped incoming handshake: %s poison: %s", actorId.ToString().data(),
+ poison ? "true" : "false");
+ if (poison) {
+ Send(actorId, new TEvents::TEvPoisonPill);
+ }
+ LastSerialFromIncomingHandshake.Clear();
+ HeldHandshakeReply.Reset();
+ IncomingHandshakeActorReset = TActivationContext::Now();
+ }
+ }
+
+ void DropOutgoingHandshake(bool poison = true) {
+ ICPROXY_PROFILED;
+
+ if (const TActorId& actorId = std::exchange(OutgoingHandshakeActor, TActorId())) {
+ LOG_DEBUG_IC("ICP112", "dropped outgoing handshake: %s poison: %s", actorId.ToString().data(),
+ poison ? "true" : "false");
+ if (poison) {
+ Send(actorId, new TEvents::TEvPoisonPill);
+ }
+ OutgoingHandshakeActorReset = TActivationContext::Now();
+ }
+ }
+
+ void DropHandshakes() {
+ ICPROXY_PROFILED;
+
+ DropIncomingHandshake();
+ DropOutgoingHandshake();
+ }
+
+ void PrepareNewSessionHandshake() {
+ ICPROXY_PROFILED;
+
+ // drop existing session if we have one
+ if (Session) {
+ LOG_INFO_IC("ICP04", "terminating current session as we are negotiating a new one");
+ IActor::InvokeOtherActor(*Session, &TInterconnectSessionTCP::Terminate, TDisconnectReason::NewSession());
+ }
+
+ // ensure we have no current session
+ Y_VERIFY(!Session);
+
+ // switch to pending connection state -- we wait for handshakes, we want more handshakes!
+ SwitchToState(__LINE__, "PendingConnection", &TThis::PendingConnection);
+ }
+
+ void IssueIncomingHandshakeReply(const TActorId& handshakeId, ui64 peerLocalId,
+ THolder<IEventBase> event);
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ TActorId OutgoingHandshakeActor;
+ TInstant OutgoingHandshakeActorCreated;
+ TInstant OutgoingHandshakeActorReset;
+
+ TInstant LastSessionDieTime;
+
+ void GenerateHttpInfo(NMon::TEvHttpInfo::TPtr& ev);
+
+ void Handle(TEvQueryStats::TPtr& ev);
+
+ TDuration HoldByErrorWakeupDuration = TDuration::Zero();
+ TEvents::TEvWakeup* HoldByErrorWakeupCookie;
+
+ THolder<TProgramInfo> RemoteProgramInfo;
+ NInterconnect::TSecureSocketContext::TPtr SecureContext;
+
+ void Handle(TEvGetSecureSocket::TPtr ev) {
+ auto socket = MakeIntrusive<NInterconnect::TSecureSocket>(*ev->Get()->Socket, SecureContext);
+ Send(ev->Sender, new TEvSecureSocket(std::move(socket)));
+ }
+
+ TDeque<THolder<IEventHandle>> PendingIncomingHandshakeEvents;
+
+ TDeque<std::tuple<TInstant, TString, TString, ui32>> ErrorStateLog;
+
+ void UpdateErrorStateLog(TInstant now, TString kind, TString explanation) {
+ ICPROXY_PROFILED;
+
+ if (ErrorStateLog) {
+ auto& back = ErrorStateLog.back();
+ TString lastKind, lastExpl;
+ if (kind == std::get<1>(back) && explanation == std::get<2>(back)) {
+ std::get<0>(back) = now;
+ ++std::get<3>(back);
+ return;
+ }
+ }
+
+ ErrorStateLog.emplace_back(now, std::move(kind), std::move(explanation), 1);
+ if (ErrorStateLog.size() > 20) {
+ ErrorStateLog.pop_front();
+ }
+ }
+
+ void LogHandshakeFail(TEvHandshakeFail::TPtr& ev, bool inconclusive);
+
+ bool Terminated = false;
+ void HandleTerminate();
+
+ void PassAway() override;
+ };
+
+}
diff --git a/library/cpp/actors/interconnect/interconnect_tcp_server.cpp b/library/cpp/actors/interconnect/interconnect_tcp_server.cpp
new file mode 100644
index 0000000000..b95c994598
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_tcp_server.cpp
@@ -0,0 +1,117 @@
+#include "interconnect_tcp_server.h"
+#include "interconnect_handshake.h"
+
+#include <library/cpp/actors/core/log.h>
+#include <library/cpp/actors/protos/services_common.pb.h>
+
+#include "interconnect_common.h"
+
+namespace NActors {
+ TInterconnectListenerTCP::TInterconnectListenerTCP(const TString& address, ui16 port, TInterconnectProxyCommon::TPtr common, const TMaybe<SOCKET>& socket)
+ : TActor(&TThis::Initial)
+ , TInterconnectLoggingBase(Sprintf("ICListener: %s", SelfId().ToString().data()))
+ , Address(address.c_str(), port)
+ , Listener(
+ socket
+ ? new NInterconnect::TStreamSocket(*socket)
+ : nullptr)
+ , ExternalSocket(!!Listener)
+ , ProxyCommonCtx(std::move(common))
+ {
+ if (ExternalSocket) {
+ SetNonBlock(*Listener);
+ }
+ }
+
+ TAutoPtr<IEventHandle> TInterconnectListenerTCP::AfterRegister(const TActorId& self, const TActorId& parentId) {
+ return new IEventHandle(self, parentId, new TEvents::TEvBootstrap, 0);
+ }
+
+ void TInterconnectListenerTCP::Die(const TActorContext& ctx) {
+ LOG_DEBUG_IC("ICL08", "Dying");
+ TActor::Die(ctx);
+ }
+
+ int TInterconnectListenerTCP::Bind() {
+ NInterconnect::TAddress addr = Address;
+
+ if (ProxyCommonCtx->Settings.BindOnAllAddresses) {
+ switch (addr.GetFamily()) {
+ case AF_INET: {
+ auto *sa = reinterpret_cast<sockaddr_in*>(addr.SockAddr());
+ sa->sin_addr = {INADDR_ANY};
+ break;
+ }
+
+ case AF_INET6: {
+ auto *sa = reinterpret_cast<sockaddr_in6*>(addr.SockAddr());
+ sa->sin6_addr = in6addr_any;
+ break;
+ }
+
+ default:
+ Y_FAIL("Unsupported address family");
+ }
+ }
+
+ Listener = NInterconnect::TStreamSocket::Make(addr.GetFamily());
+ if (*Listener == -1) {
+ return errno;
+ }
+ SetNonBlock(*Listener);
+ Listener->SetSendBufferSize(ProxyCommonCtx->Settings.GetSendBufferSize()); // TODO(alexvru): WTF?
+ SetSockOpt(*Listener, SOL_SOCKET, SO_REUSEADDR, 1);
+ if (const auto e = -Listener->Bind(addr)) {
+ return e;
+ } else if (const auto e = -Listener->Listen(SOMAXCONN)) {
+ return e;
+ } else {
+ return 0;
+ }
+ }
+
+ void TInterconnectListenerTCP::Bootstrap(const TActorContext& ctx) {
+ if (!Listener) {
+ if (const int err = Bind()) {
+ LOG_ERROR_IC("ICL01", "Bind failed: %s (%s)", strerror(err), Address.ToString().data());
+ Listener.Reset();
+ Become(&TThis::Initial, TDuration::Seconds(1), new TEvents::TEvBootstrap);
+ return;
+ }
+ }
+ if (const auto& callback = ProxyCommonCtx->InitWhiteboard) {
+ callback(Address.GetPort(), TlsActivationContext->ExecutorThread.ActorSystem);
+ }
+ const bool success = ctx.Send(MakePollerActorId(), new TEvPollerRegister(Listener, SelfId(), {}));
+ Y_VERIFY(success);
+ Become(&TThis::Listen);
+ }
+
+ void TInterconnectListenerTCP::Handle(TEvPollerRegisterResult::TPtr ev, const TActorContext& ctx) {
+ PollerToken = std::move(ev->Get()->PollerToken);
+ Process(ctx);
+ }
+
+ void TInterconnectListenerTCP::Process(const TActorContext& ctx) {
+ for (;;) {
+ NInterconnect::TAddress address;
+ const int r = Listener->Accept(address);
+ if (r >= 0) {
+ LOG_DEBUG_IC("ICL04", "Accepted from: %s", address.ToString().data());
+ auto socket = MakeIntrusive<NInterconnect::TStreamSocket>(static_cast<SOCKET>(r));
+ ctx.Register(CreateIncomingHandshakeActor(ProxyCommonCtx, std::move(socket)));
+ continue;
+ } else if (-r != EAGAIN && -r != EWOULDBLOCK) {
+ Y_VERIFY(-r != ENFILE && -r != EMFILE && !ExternalSocket);
+ LOG_ERROR_IC("ICL06", "Listen failed: %s (%s)", strerror(-r), Address.ToString().data());
+ Listener.Reset();
+ PollerToken.Reset();
+ Become(&TThis::Initial, TDuration::Seconds(1), new TEvents::TEvBootstrap);
+ } else if (PollerToken) {
+ PollerToken->Request(true, false);
+ }
+ break;
+ }
+ }
+
+}
diff --git a/library/cpp/actors/interconnect/interconnect_tcp_server.h b/library/cpp/actors/interconnect/interconnect_tcp_server.h
new file mode 100644
index 0000000000..fc71073c2d
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_tcp_server.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/actors/core/event_pb.h>
+#include <library/cpp/actors/core/events.h>
+
+#include "interconnect_common.h"
+#include "poller_actor.h"
+#include "events_local.h"
+
+namespace NActors {
+ class TInterconnectListenerTCP: public TActor<TInterconnectListenerTCP>, public TInterconnectLoggingBase {
+ public:
+ static constexpr EActivityType ActorActivityType() {
+ return INTERCONNECT_COMMON;
+ }
+
+ TInterconnectListenerTCP(const TString& address, ui16 port, TInterconnectProxyCommon::TPtr common, const TMaybe<SOCKET>& socket = Nothing());
+ int Bind();
+
+ private:
+ STFUNC(Initial) {
+ switch (ev->GetTypeRewrite()) {
+ CFunc(TEvents::TEvBootstrap::EventType, Bootstrap);
+ CFunc(TEvents::TEvPoisonPill::EventType, Die);
+ }
+ }
+
+ STFUNC(Listen) {
+ switch (ev->GetTypeRewrite()) {
+ CFunc(TEvents::TEvPoisonPill::EventType, Die);
+ HFunc(TEvPollerRegisterResult, Handle);
+ CFunc(TEvPollerReady::EventType, Process);
+ }
+ }
+
+ TAutoPtr<IEventHandle> AfterRegister(const TActorId& self, const TActorId& parentId) override;
+
+ void Die(const TActorContext& ctx) override;
+
+ void Bootstrap(const TActorContext& ctx);
+ void Handle(TEvPollerRegisterResult::TPtr ev, const TActorContext& ctx);
+
+ void Process(const TActorContext& ctx);
+
+ const NInterconnect::TAddress Address;
+ TIntrusivePtr<NInterconnect::TStreamSocket> Listener;
+ const bool ExternalSocket;
+ TPollerToken::TPtr PollerToken;
+ TInterconnectProxyCommon::TPtr const ProxyCommonCtx;
+ };
+
+ static inline TActorId MakeInterconnectListenerActorId(bool dynamic) {
+ char x[12] = {'I', 'C', 'L', 'i', 's', 't', 'e', 'n', 'e', 'r', '/', dynamic ? 'D' : 'S'};
+ return TActorId(0, TStringBuf(x, 12));
+ }
+}
diff --git a/library/cpp/actors/interconnect/interconnect_tcp_session.cpp b/library/cpp/actors/interconnect/interconnect_tcp_session.cpp
new file mode 100644
index 0000000000..2ded7f9f53
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_tcp_session.cpp
@@ -0,0 +1,1228 @@
+#include "interconnect_tcp_proxy.h"
+#include "interconnect_tcp_session.h"
+#include "interconnect_handshake.h"
+
+#include <library/cpp/actors/core/probes.h>
+#include <library/cpp/actors/core/log.h>
+#include <library/cpp/actors/core/interconnect.h>
+#include <library/cpp/actors/util/datetime.h>
+#include <library/cpp/actors/protos/services_common.pb.h>
+#include <library/cpp/monlib/service/pages/templates.h>
+
+namespace NActors {
+ LWTRACE_USING(ACTORLIB_PROVIDER);
+
+ DECLARE_WILSON_EVENT(OutputQueuePush, (ui32, QueueSizeInEvents), (ui64, QueueSizeInBytes));
+
+ template<typename T>
+ T Coalesce(T&& x) {
+ return x;
+ }
+
+ template<typename T, typename T2, typename... TRest>
+ typename std::common_type<T, T2, TRest...>::type Coalesce(T&& first, T2&& mid, TRest&&... rest) {
+ if (first != typename std::remove_reference<T>::type()) {
+ return first;
+ } else {
+ return Coalesce(std::forward<T2>(mid), std::forward<TRest>(rest)...);
+ }
+ }
+
+ TInterconnectSessionTCP::TInterconnectSessionTCP(TInterconnectProxyTCP* const proxy, TSessionParams params)
+ : TActor(&TInterconnectSessionTCP::StateFunc)
+ , Created(TInstant::Now())
+ , Proxy(proxy)
+ , CloseOnIdleWatchdog(GetCloseOnIdleTimeout(), std::bind(&TThis::OnCloseOnIdleTimerHit, this))
+ , LostConnectionWatchdog(GetLostConnectionTimeout(), std::bind(&TThis::OnLostConnectionTimerHit, this))
+ , Params(std::move(params))
+ , TotalOutputQueueSize(0)
+ , OutputStuckFlag(false)
+ , OutputQueueUtilization(16)
+ , OutputCounter(0ULL)
+ {
+ Proxy->Metrics->SetConnected(0);
+ ReceiveContext.Reset(new TReceiveContext);
+ }
+
+ TInterconnectSessionTCP::~TInterconnectSessionTCP() {
+ // close socket ASAP when actor system is being shut down
+ if (Socket) {
+ Socket->Shutdown(SHUT_RDWR);
+ }
+ }
+
+ void TInterconnectSessionTCP::Init() {
+ auto destroyCallback = [as = TlsActivationContext->ExecutorThread.ActorSystem, id = Proxy->Common->DestructorId](THolder<IEventBase> event) {
+ as->Send(id, event.Release());
+ };
+ Pool.ConstructInPlace(Proxy->Common, std::move(destroyCallback));
+ ChannelScheduler.ConstructInPlace(Proxy->PeerNodeId, Proxy->Common->ChannelsConfig, Proxy->Metrics, *Pool,
+ Proxy->Common->Settings.MaxSerializedEventSize, Params);
+
+ LOG_INFO(*TlsActivationContext, NActorsServices::INTERCONNECT_STATUS, "[%u] session created", Proxy->PeerNodeId);
+ SetPrefix(Sprintf("Session %s [node %" PRIu32 "]", SelfId().ToString().data(), Proxy->PeerNodeId));
+ SendUpdateToWhiteboard();
+ }
+
+ void TInterconnectSessionTCP::CloseInputSession() {
+ Send(ReceiverId, new TEvInterconnect::TEvCloseInputSession);
+ }
+
+ void TInterconnectSessionTCP::Handle(TEvTerminate::TPtr& ev) {
+ Terminate(ev->Get()->Reason);
+ }
+
+ void TInterconnectSessionTCP::HandlePoison() {
+ Terminate(TDisconnectReason());
+ }
+
+ void TInterconnectSessionTCP::Terminate(TDisconnectReason reason) {
+ LOG_INFO_IC_SESSION("ICS01", "socket: %" PRIi64, (Socket ? i64(*Socket) : -1));
+
+ IActor::InvokeOtherActor(*Proxy, &TInterconnectProxyTCP::UnregisterSession, this);
+ ShutdownSocket(std::move(reason));
+
+ for (const auto& kv : Subscribers) {
+ Send(kv.first, new TEvInterconnect::TEvNodeDisconnected(Proxy->PeerNodeId), 0, kv.second);
+ }
+ Proxy->Metrics->SubSubscribersCount(Subscribers.size());
+ Subscribers.clear();
+
+ ChannelScheduler->ForEach([&](TEventOutputChannel& channel) {
+ channel.NotifyUndelivered();
+ });
+
+ if (ReceiverId) {
+ Send(ReceiverId, new TEvents::TEvPoisonPill);
+ }
+
+ SendUpdateToWhiteboard(false);
+
+ Proxy->Metrics->SubOutputBuffersTotalSize(TotalOutputQueueSize);
+ Proxy->Metrics->SubInflightDataAmount(InflightDataAmount);
+
+ LOG_INFO(*TlsActivationContext, NActorsServices::INTERCONNECT_STATUS, "[%u] session destroyed", Proxy->PeerNodeId);
+
+ if (!Subscribers.empty()) {
+ Proxy->Metrics->SubSubscribersCount(Subscribers.size());
+ }
+
+ TActor::PassAway();
+ }
+
+ void TInterconnectSessionTCP::PassAway() {
+ Y_FAIL("TInterconnectSessionTCP::PassAway() can't be called directly");
+ }
+
+ void TInterconnectSessionTCP::Forward(STATEFN_SIG) {
+ Proxy->ValidateEvent(ev, "Forward");
+
+ LOG_DEBUG_IC_SESSION("ICS02", "send event from: %s to: %s", ev->Sender.ToString().data(), ev->Recipient.ToString().data());
+ ++MessagesGot;
+
+ if (ev->Flags & IEventHandle::FlagSubscribeOnSession) {
+ Subscribe(ev);
+ }
+
+ ui16 evChannel = ev->GetChannel();
+ auto& oChannel = ChannelScheduler->GetOutputChannel(evChannel);
+ const bool wasWorking = oChannel.IsWorking();
+
+ const auto [dataSize, event] = oChannel.Push(*ev);
+ LWTRACK(ForwardEvent, event->Orbit, Proxy->PeerNodeId, event->Descr.Type, event->Descr.Flags, LWACTORID(event->Descr.Recipient), LWACTORID(event->Descr.Sender), event->Descr.Cookie, event->EventSerializedSize);
+
+ TotalOutputQueueSize += dataSize;
+ Proxy->Metrics->AddOutputBuffersTotalSize(dataSize);
+ if (!wasWorking) {
+ // this channel has returned to work -- it was empty and this we have just put first event in the queue
+ ChannelScheduler->AddToHeap(oChannel, EqualizeCounter);
+ }
+
+ SetOutputStuckFlag(true);
+ ++NumEventsInReadyChannels;
+
+ LWTRACK(EnqueueEvent, event->Orbit, Proxy->PeerNodeId, NumEventsInReadyChannels, GetWriteBlockedTotal(), evChannel, oChannel.GetQueueSize(), oChannel.GetBufferedAmountOfData());
+ WILSON_TRACE(*TlsActivationContext, &ev->TraceId, OutputQueuePush,
+ QueueSizeInEvents = oChannel.GetQueueSize(),
+ QueueSizeInBytes = oChannel.GetBufferedAmountOfData());
+
+ // check for overloaded queues
+ ui64 sendBufferDieLimit = Proxy->Common->Settings.SendBufferDieLimitInMB * ui64(1 << 20);
+ if (sendBufferDieLimit != 0 && TotalOutputQueueSize > sendBufferDieLimit) {
+ LOG_ERROR_IC_SESSION("ICS03", "socket: %" PRIi64 " output queue is overloaded, actual %" PRIu64 " bytes, limit is %" PRIu64,
+ Socket ? i64(*Socket) : -1, TotalOutputQueueSize, sendBufferDieLimit);
+ return Terminate(TDisconnectReason::QueueOverload());
+ }
+
+ ui64 outputBuffersTotalSizeLimit = Proxy->Common->Settings.OutputBuffersTotalSizeLimitInMB * ui64(1 << 20);
+ if (outputBuffersTotalSizeLimit != 0 && static_cast<ui64>(Proxy->Metrics->GetOutputBuffersTotalSize()) > outputBuffersTotalSizeLimit) {
+ LOG_ERROR_IC_SESSION("ICS77", "Exceeded total limit on output buffers size");
+ if (AtomicTryLock(&Proxy->Common->StartedSessionKiller)) {
+ CreateSessionKillingActor(Proxy->Common);
+ }
+ }
+
+ if (RamInQueue && !RamInQueue->Batching) {
+ // we have pending TEvRam, so GenerateTraffic will be called no matter what
+ } else if (InflightDataAmount >= GetTotalInflightAmountOfData() || !Socket || ReceiveContext->WriteBlockedByFullSendBuffer) {
+ // we can't issue more traffic now; GenerateTraffic will be called upon unblocking
+ } else if (TotalOutputQueueSize >= 64 * 1024) {
+ // output queue size is quite big to issue some traffic
+ GenerateTraffic();
+ } else if (!RamInQueue) {
+ Y_VERIFY_DEBUG(NumEventsInReadyChannels == 1);
+ RamInQueue = new TEvRam(true);
+ auto *ev = new IEventHandle(SelfId(), {}, RamInQueue);
+ const TDuration batchPeriod = Proxy->Common->Settings.BatchPeriod;
+ if (batchPeriod != TDuration()) {
+ TActivationContext::Schedule(batchPeriod, ev);
+ } else {
+ TActivationContext::Send(ev);
+ }
+ LWPROBE(StartBatching, Proxy->PeerNodeId, batchPeriod.MillisecondsFloat());
+ LOG_DEBUG_IC_SESSION("ICS17", "batching started");
+ }
+ }
+
+ void TInterconnectSessionTCP::Subscribe(STATEFN_SIG) {
+ LOG_DEBUG_IC_SESSION("ICS04", "subscribe for session state for %s", ev->Sender.ToString().data());
+ const auto [it, inserted] = Subscribers.emplace(ev->Sender, ev->Cookie);
+ if (inserted) {
+ Proxy->Metrics->IncSubscribersCount();
+ } else {
+ it->second = ev->Cookie;
+ }
+ Send(ev->Sender, new TEvInterconnect::TEvNodeConnected(Proxy->PeerNodeId), 0, ev->Cookie);
+ }
+
+ void TInterconnectSessionTCP::Unsubscribe(STATEFN_SIG) {
+ LOG_DEBUG_IC_SESSION("ICS05", "unsubscribe for session state for %s", ev->Sender.ToString().data());
+ Proxy->Metrics->SubSubscribersCount( Subscribers.erase(ev->Sender));
+ }
+
+ THolder<TEvHandshakeAck> TInterconnectSessionTCP::ProcessHandshakeRequest(TEvHandshakeAsk::TPtr& ev) {
+ TEvHandshakeAsk *msg = ev->Get();
+
+ // close existing input session, if any, and do nothing upon its destruction
+ ReestablishConnection({}, false, TDisconnectReason::NewSession());
+ const ui64 lastInputSerial = ReceiveContext->LockLastProcessedPacketSerial();
+
+ LOG_INFO_IC_SESSION("ICS08", "incoming handshake Self# %s Peer# %s Counter# %" PRIu64 " LastInputSerial# %" PRIu64,
+ msg->Self.ToString().data(), msg->Peer.ToString().data(), msg->Counter, lastInputSerial);
+
+ return MakeHolder<TEvHandshakeAck>(msg->Peer, lastInputSerial, Params);
+ }
+
+ void TInterconnectSessionTCP::SetNewConnection(TEvHandshakeDone::TPtr& ev) {
+ if (ReceiverId) {
+ // upon destruction of input session actor invoke this callback again
+ ReestablishConnection(std::move(ev), false, TDisconnectReason::NewSession());
+ return;
+ }
+
+ LOG_INFO_IC_SESSION("ICS09", "handshake done sender: %s self: %s peer: %s socket: %" PRIi64,
+ ev->Sender.ToString().data(), ev->Get()->Self.ToString().data(), ev->Get()->Peer.ToString().data(),
+ i64(*ev->Get()->Socket));
+
+ NewConnectionSet = TActivationContext::Now();
+ PacketsWrittenToSocket = 0;
+
+ SendBufferSize = ev->Get()->Socket->GetSendBufferSize();
+ Socket = std::move(ev->Get()->Socket);
+
+ // there may be a race
+ const ui64 nextPacket = Max(LastConfirmed, ev->Get()->NextPacket);
+
+ // arm watchdogs
+ CloseOnIdleWatchdog.Arm(SelfId());
+
+ // reset activity timestamps
+ LastInputActivityTimestamp = LastPayloadActivityTimestamp = TActivationContext::Now();
+
+ LOG_INFO_IC_SESSION("ICS10", "traffic start");
+
+ // create input session actor
+ auto actor = MakeHolder<TInputSessionTCP>(SelfId(), Socket, ReceiveContext, Proxy->Common,
+ Proxy->Metrics, Proxy->PeerNodeId, nextPacket, GetDeadPeerTimeout(), Params);
+ ReceiveContext->UnlockLastProcessedPacketSerial();
+ ReceiverId = Params.Encryption ? RegisterWithSameMailbox(actor.Release()) : Register(actor.Release(), TMailboxType::ReadAsFilled);
+
+ // register our socket in poller actor
+ LOG_DEBUG_IC_SESSION("ICS11", "registering socket in PollerActor");
+ const bool success = Send(MakePollerActorId(), new TEvPollerRegister(Socket, ReceiverId, SelfId()));
+ Y_VERIFY(success);
+ ReceiveContext->WriteBlockedByFullSendBuffer = false;
+
+ LostConnectionWatchdog.Disarm();
+ Proxy->Metrics->SetConnected(1);
+ LOG_INFO(*TlsActivationContext, NActorsServices::INTERCONNECT_STATUS, "[%u] connected", Proxy->PeerNodeId);
+
+ // arm pinger timer
+ ResetFlushLogic();
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // REINITIALIZE SEND QUEUE
+ //
+ // scan through send queue and leave only those packets who have data -- we will simply resend them; drop all other
+ // auxiliary packets; also reset packet metrics to zero to start sending from the beginning
+ // also reset SendQueuePos
+
+ // drop confirmed packets first as we do not need unwanted retransmissions
+ SendQueuePos = SendQueue.end();
+ DropConfirmed(nextPacket);
+
+ for (TSendQueue::iterator it = SendQueue.begin(); it != SendQueue.end(); ) {
+ const TSendQueue::iterator next = std::next(it);
+ if (it->IsEmpty()) {
+ SendQueueCache.splice(SendQueueCache.begin(), SendQueue, it);
+ } else {
+ it->ResetBufs();
+ }
+ it = next;
+ }
+ TrimSendQueueCache();
+ SendQueuePos = SendQueue.begin();
+
+ TMaybe<ui64> s;
+ for (auto it = SendQueuePos; it != SendQueue.end(); ++it) {
+ if (!it->IsEmpty()) {
+ s = it->GetSerial();
+ }
+ }
+ const ui64 serial = s.GetOrElse(Max<ui64>());
+
+ Y_VERIFY(serial > LastConfirmed, "%s serial# %" PRIu64 " LastConfirmed# %" PRIu64, LogPrefix.data(), serial, LastConfirmed);
+ LOG_DEBUG_IC_SESSION("ICS06", "rewind SendQueue size# %zu LastConfirmed# %" PRIu64 " SendQueuePos.Serial# %" PRIu64 "\n",
+ SendQueue.size(), LastConfirmed, serial);
+
+ BytesUnwritten = 0;
+ for (const auto& packet : SendQueue) {
+ BytesUnwritten += (Params.UseModernFrame ? sizeof(TTcpPacketHeader_v2) : sizeof(TTcpPacketHeader_v1)) +
+ packet.GetDataSize();
+ }
+
+ SwitchStuckPeriod();
+
+ LastHandshakeDone = TActivationContext::Now();
+
+ RamInQueue = nullptr;
+ GenerateTraffic();
+ }
+
+ void TInterconnectSessionTCP::Handle(TEvUpdateFromInputSession::TPtr& ev) {
+ if (ev->Sender == ReceiverId) {
+ TEvUpdateFromInputSession& msg = *ev->Get();
+
+ // update ping time
+ Ping = msg.Ping;
+ LWPROBE(UpdateFromInputSession, Proxy->PeerNodeId, Ping.MillisecondsFloat());
+
+ bool needConfirm = false;
+
+ // update activity timer for dead peer checker
+ LastInputActivityTimestamp = TActivationContext::Now();
+
+ if (msg.NumDataBytes) {
+ UnconfirmedBytes += msg.NumDataBytes;
+ if (UnconfirmedBytes >= GetTotalInflightAmountOfData() / 4) {
+ needConfirm = true;
+ } else {
+ SetForcePacketTimestamp(Proxy->Common->Settings.ForceConfirmPeriod);
+ }
+
+ // reset payload watchdog that controls close-on-idle behaviour
+ LastPayloadActivityTimestamp = TActivationContext::Now();
+ CloseOnIdleWatchdog.Reset();
+ }
+
+ bool unblockedSomething = false;
+ LWPROBE_IF_TOO_LONG(SlowICDropConfirmed, Proxy->PeerNodeId, ms) {
+ unblockedSomething = DropConfirmed(msg.ConfirmedByInput);
+ }
+
+ // generate more traffic if we have unblocked state now
+ if (unblockedSomething) {
+ LWPROBE(UnblockByDropConfirmed, Proxy->PeerNodeId, NHPTimer::GetSeconds(GetCycleCountFast() - ev->SendTime) * 1000.0);
+ GenerateTraffic();
+ }
+
+ // if we haven't generated any packets, then make a lone Flush packet without any data
+ if (needConfirm && Socket) {
+ ++ConfirmPacketsForcedBySize;
+ MakePacket(false);
+ }
+
+ for (;;) {
+ switch (EUpdateState state = ReceiveContext->UpdateState) {
+ case EUpdateState::NONE:
+ case EUpdateState::CONFIRMING:
+ Y_FAIL("unexpected state");
+
+ case EUpdateState::INFLIGHT:
+ // this message we are processing was the only one in flight, so we can reset state to NONE here
+ if (ReceiveContext->UpdateState.compare_exchange_weak(state, EUpdateState::NONE)) {
+ return;
+ }
+ break;
+
+ case EUpdateState::INFLIGHT_AND_PENDING:
+ // there is more messages pending from the input session actor, so we have to inform it to release
+ // that message
+ if (ReceiveContext->UpdateState.compare_exchange_weak(state, EUpdateState::CONFIRMING)) {
+ Send(ev->Sender, new TEvConfirmUpdate);
+ return;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ void TInterconnectSessionTCP::HandleRam(TEvRam::TPtr& ev) {
+ if (ev->Get() == RamInQueue) {
+ LWPROBE(FinishRam, Proxy->PeerNodeId, NHPTimer::GetSeconds(GetCycleCountFast() - ev->SendTime) * 1000.0);
+ RamInQueue = nullptr;
+ GenerateTraffic();
+ }
+ }
+
+ void TInterconnectSessionTCP::GenerateTraffic() {
+ // generate ping request, if needed
+ IssuePingRequest();
+
+ if (RamInQueue && !RamInQueue->Batching) {
+ LWPROBE(SkipGenerateTraffic, Proxy->PeerNodeId, NHPTimer::GetSeconds(GetCycleCountFast() - RamStartedCycles) * 1000.0);
+ return; // we'll do it a bit later
+ } else {
+ RamInQueue = nullptr;
+ }
+
+ LOG_DEBUG_IC_SESSION("ICS19", "GenerateTraffic");
+
+ // There is a tradeoff between fairness and efficiency.
+ // The less traffic is generated here, the less buffering is after fair scheduler,
+ // the more fair system is, the less latency is present.
+ // The more traffic is generated here, the less syscalls and actor-system overhead occurs,
+ // the less cpu is consumed.
+ static const ui64 generateLimit = 64 * 1024;
+
+ const ui64 sizeBefore = TotalOutputQueueSize;
+ ui32 generatedPackets = 0;
+ ui64 generatedBytes = 0;
+ ui64 generateStarted = GetCycleCountFast();
+
+ // apply traffic changes
+ auto accountTraffic = [&] { ChannelScheduler->ForEach([](TEventOutputChannel& channel) { channel.AccountTraffic(); }); };
+
+ // first, we create as many data packets as we can generate under certain conditions; they include presence
+ // of events in channels queues and in flight fitting into requested limit; after we hit one of these conditions
+ // we exit cycle
+ while (Socket && NumEventsInReadyChannels && InflightDataAmount < GetTotalInflightAmountOfData() && !ReceiveContext->WriteBlockedByFullSendBuffer) {
+ if (generatedBytes >= generateLimit) {
+ // resume later but ensure that we have issued at least one packet
+ RamInQueue = new TEvRam(false);
+ Send(SelfId(), RamInQueue);
+ RamStartedCycles = GetCycleCountFast();
+ LWPROBE(StartRam, Proxy->PeerNodeId);
+ break;
+ }
+
+ try {
+ generatedBytes += MakePacket(true);
+ ++generatedPackets;
+ } catch (const TExSerializedEventTooLarge& ex) {
+ // terminate session if the event can't be serialized properly
+ accountTraffic();
+ LOG_CRIT_IC("ICS31", "serialized event Type# 0x%08" PRIx32 " is too large", ex.Type);
+ return Terminate(TDisconnectReason::EventTooLarge());
+ }
+ }
+
+ if (Socket) {
+ WriteData();
+ }
+
+ LWPROBE(GenerateTraffic, Proxy->PeerNodeId, NHPTimer::GetSeconds(GetCycleCountFast() - generateStarted) * 1000.0, sizeBefore - TotalOutputQueueSize, generatedPackets, generatedBytes);
+
+ accountTraffic();
+ EqualizeCounter += ChannelScheduler->Equalize();
+ }
+
+ void TInterconnectSessionTCP::StartHandshake() {
+ LOG_INFO_IC_SESSION("ICS15", "start handshake");
+ IActor::InvokeOtherActor(*Proxy, &TInterconnectProxyTCP::StartResumeHandshake, ReceiveContext->LockLastProcessedPacketSerial());
+ }
+
+ void TInterconnectSessionTCP::ReestablishConnectionWithHandshake(TDisconnectReason reason) {
+ ReestablishConnection({}, true, std::move(reason));
+ }
+
+ void TInterconnectSessionTCP::ReestablishConnection(TEvHandshakeDone::TPtr&& ev, bool startHandshakeOnSessionClose,
+ TDisconnectReason reason) {
+ if (Socket) {
+ LOG_INFO_IC_SESSION("ICS13", "reestablish connection");
+ ShutdownSocket(std::move(reason)); // stop sending/receiving on socket
+ PendingHandshakeDoneEvent = std::move(ev);
+ StartHandshakeOnSessionClose = startHandshakeOnSessionClose;
+ if (!ReceiverId) {
+ ReestablishConnectionExecute();
+ }
+ }
+ }
+
+ void TInterconnectSessionTCP::OnDisconnect(TEvSocketDisconnect::TPtr& ev) {
+ if (ev->Sender == ReceiverId) {
+ const bool wasConnected(Socket);
+ LOG_INFO_IC_SESSION("ICS07", "socket disconnect %" PRIi64 " reason# %s", Socket ? i64(*Socket) : -1, ev->Get()->Reason.ToString().data());
+ ReceiverId = TActorId(); // reset receiver actor id as we have no more receiver yet
+ if (wasConnected) {
+ // we were sucessfully connected and did not expect failure, so it arrived from the input side; we should
+ // restart handshake process, closing our part of socket first
+ ShutdownSocket(ev->Get()->Reason);
+ StartHandshake();
+ } else {
+ ReestablishConnectionExecute();
+ }
+ }
+ }
+
+ void TInterconnectSessionTCP::ShutdownSocket(TDisconnectReason reason) {
+ if (Socket) {
+ if (const TString& s = reason.ToString()) {
+ Proxy->Metrics->IncDisconnectByReason(s);
+ }
+
+ LOG_INFO_IC_SESSION("ICS25", "shutdown socket, reason# %s", reason.ToString().data());
+ Proxy->UpdateErrorStateLog(TActivationContext::Now(), "close_socket", reason.ToString().data());
+ Socket->Shutdown(SHUT_RDWR);
+ Socket.Reset();
+ Proxy->Metrics->IncDisconnections();
+ CloseOnIdleWatchdog.Disarm();
+ LostConnectionWatchdog.Arm(SelfId());
+ Proxy->Metrics->SetConnected(0);
+ LOG_INFO(*TlsActivationContext, NActorsServices::INTERCONNECT_STATUS, "[%u] disconnected", Proxy->PeerNodeId);
+ }
+ }
+
+ void TInterconnectSessionTCP::ReestablishConnectionExecute() {
+ bool startHandshakeOnSessionClose = std::exchange(StartHandshakeOnSessionClose, false);
+ TEvHandshakeDone::TPtr ev = std::move(PendingHandshakeDoneEvent);
+
+ if (startHandshakeOnSessionClose) {
+ StartHandshake();
+ } else if (ev) {
+ SetNewConnection(ev);
+ }
+ }
+
+ void TInterconnectSessionTCP::Handle(TEvPollerReady::TPtr& ev) {
+ LOG_DEBUG_IC_SESSION("ICS29", "HandleReadyWrite WriteBlockedByFullSendBuffer# %s",
+ ReceiveContext->WriteBlockedByFullSendBuffer ? "true" : "false");
+ if (std::exchange(ReceiveContext->WriteBlockedByFullSendBuffer, false)) {
+ Proxy->Metrics->IncUsefulWriteWakeups();
+ ui64 nowCycles = GetCycleCountFast();
+ double blockedUs = NHPTimer::GetSeconds(nowCycles - WriteBlockedCycles) * 1000000.0;
+ LWPROBE(ReadyWrite, Proxy->PeerNodeId, NHPTimer::GetSeconds(nowCycles - ev->SendTime) * 1000.0, blockedUs / 1000.0);
+ WriteBlockedTotal += TDuration::MicroSeconds(blockedUs);
+ GenerateTraffic();
+ } else if (!ev->Cookie) {
+ Proxy->Metrics->IncSpuriousWriteWakeups();
+ }
+ if (Params.Encryption && ReceiveContext->ReadPending && !ev->Cookie) {
+ Send(ReceiverId, ev->Release().Release(), 0, 1);
+ }
+ }
+
+ void TInterconnectSessionTCP::Handle(TEvPollerRegisterResult::TPtr ev) {
+ PollerToken = std::move(ev->Get()->PollerToken);
+ if (ReceiveContext->WriteBlockedByFullSendBuffer) {
+ if (Params.Encryption) {
+ auto *secure = static_cast<NInterconnect::TSecureSocket*>(Socket.Get());
+ PollerToken->Request(secure->WantRead(), secure->WantWrite());
+ } else {
+ PollerToken->Request(false, true);
+ }
+ }
+ }
+
+ void TInterconnectSessionTCP::WriteData() {
+ ui64 written = 0;
+
+ Y_VERIFY(Socket); // ensure that socket wasn't closed
+
+ LWPROBE_IF_TOO_LONG(SlowICWriteData, Proxy->PeerNodeId, ms) {
+ constexpr ui32 iovLimit = 256;
+#ifdef _linux_
+ ui32 maxElementsInIOV = Min<ui32>(iovLimit, sysconf(_SC_IOV_MAX));
+#else
+ ui32 maxElementsInIOV = 64;
+#endif
+ if (Params.Encryption) {
+ maxElementsInIOV = 1;
+ }
+
+ // vector of write buffers with preallocated stack space
+ TStackVec<TConstIoVec, iovLimit> wbuffers;
+
+ LOG_DEBUG_IC_SESSION("ICS30", "WriteData WriteBlockedByFullSendBuffer# %s SendQueue.size# %zu",
+ ReceiveContext->WriteBlockedByFullSendBuffer ? "true" : "false", SendQueue.size());
+
+ // update last confirmed packet number if it has changed
+ if (SendQueuePos != SendQueue.end()) {
+ SendQueuePos->UpdateConfirmIfPossible(ReceiveContext->GetLastProcessedPacketSerial());
+ }
+
+ while (SendQueuePos != SendQueue.end() && !ReceiveContext->WriteBlockedByFullSendBuffer) {
+ for (auto it = SendQueuePos; it != SendQueue.end() && wbuffers.size() < maxElementsInIOV; ++it) {
+ it->AppendToIoVector(wbuffers, maxElementsInIOV);
+ }
+
+ const struct iovec* iovec = reinterpret_cast<const struct iovec*>(wbuffers.data());
+ int iovcnt = wbuffers.size();
+
+ Y_VERIFY(iovcnt > 0);
+ Y_VERIFY(iovec->iov_len > 0);
+
+ TString err;
+ ssize_t r = 0;
+ do {
+#ifndef _win_
+ r = iovcnt == 1 ? Socket->Send(iovec[0].iov_base, iovec[0].iov_len, &err) : Socket->WriteV(iovec, iovcnt);
+#else
+ r = Socket->Send(iovec[0].iov_base, iovec[0].iov_len, &err);
+#endif
+ Proxy->Metrics->IncSendSyscalls();
+ } while (r == -EINTR);
+
+ LOG_DEBUG_IC_SESSION("ICS16", "written# %zd iovcnt# %d err# %s", r, iovcnt, err.data());
+
+ wbuffers.clear();
+
+ if (r > 0) {
+ Y_VERIFY(static_cast<size_t>(r) <= BytesUnwritten);
+ BytesUnwritten -= r;
+ written += r;
+ ui64 packets = 0;
+
+ // advance SendQueuePos to eat all processed items
+ for (size_t amount = r; amount && SendQueuePos->DropBufs(amount); ++SendQueuePos) {
+ if (!SendQueuePos->IsEmpty()) {
+ LastSentSerial = Max(LastSentSerial, SendQueuePos->GetSerial());
+ }
+ ++PacketsWrittenToSocket;
+ ++packets;
+ LWTRACK(PacketWrittenToSocket, SendQueuePos->Orbit, Proxy->PeerNodeId, PacketsWrittenToSocket, SendQueuePos->TriedWriting, SendQueuePos->GetDataSize(), BytesUnwritten, GetWriteBlockedTotal(), (SOCKET)*Socket);
+ }
+
+ LWPROBE(WriteToSocket, Proxy->PeerNodeId, r, packets, PacketsWrittenToSocket, BytesUnwritten, GetWriteBlockedTotal(), (SOCKET)*Socket);
+ } else if (-r != EAGAIN && -r != EWOULDBLOCK) {
+ const TString message = r == 0 ? "connection closed by peer"
+ : err ? err
+ : Sprintf("socket: %s", strerror(-r));
+ LOG_NOTICE_NET(Proxy->PeerNodeId, "%s", message.data());
+ if (written) {
+ Proxy->Metrics->AddTotalBytesWritten(written);
+ }
+ return ReestablishConnectionWithHandshake(r == 0 ? TDisconnectReason::EndOfStream() : TDisconnectReason::FromErrno(-r));
+ } else {
+ // we have to do some hack for secure socket -- mark the packet as 'tried writing'
+ if (Params.Encryption) {
+ Y_VERIFY(SendQueuePos != SendQueue.end());
+ SendQueuePos->MarkTriedWriting(); // do not try to replace buffer under SSL
+ }
+
+ // we have received EAGAIN error code, this means that we can't issue more data until we have received
+ // TEvPollerReadyWrite event from poller; set up flag meaning this and wait for that event
+ Y_VERIFY(!ReceiveContext->WriteBlockedByFullSendBuffer);
+ ReceiveContext->WriteBlockedByFullSendBuffer = true;
+ WriteBlockedCycles = GetCycleCountFast();
+ LWPROBE(BlockedWrite, Proxy->PeerNodeId, SendQueue.size(), written);
+ LOG_DEBUG_IC_SESSION("ICS18", "hit send buffer limit");
+
+ if (PollerToken) {
+ if (Params.Encryption) {
+ auto *secure = static_cast<NInterconnect::TSecureSocket*>(Socket.Get());
+ PollerToken->Request(secure->WantRead(), secure->WantWrite());
+ } else {
+ PollerToken->Request(false, true);
+ }
+ }
+ }
+ }
+ }
+ if (written) {
+ Proxy->Metrics->AddTotalBytesWritten(written);
+ }
+ }
+
+ void TInterconnectSessionTCP::SetForcePacketTimestamp(TDuration period) {
+ if (period != TDuration::Max()) {
+ const TInstant when = TActivationContext::Now() + period;
+ if (when < ForcePacketTimestamp) {
+ ForcePacketTimestamp = when;
+ ScheduleFlush();
+ }
+ }
+ }
+
+ void TInterconnectSessionTCP::ScheduleFlush() {
+ if (FlushSchedule.empty() || ForcePacketTimestamp < FlushSchedule.top()) {
+ Schedule(ForcePacketTimestamp - TActivationContext::Now(), new TEvFlush);
+ FlushSchedule.push(ForcePacketTimestamp);
+ MaxFlushSchedule = Max(MaxFlushSchedule, FlushSchedule.size());
+ ++FlushEventsScheduled;
+ }
+ }
+
+ void TInterconnectSessionTCP::HandleFlush() {
+ const TInstant now = TActivationContext::Now();
+ while (FlushSchedule && now >= FlushSchedule.top()) {
+ FlushSchedule.pop();
+ }
+ IssuePingRequest();
+ if (Socket) {
+ if (now >= ForcePacketTimestamp) {
+ ++ConfirmPacketsForcedByTimeout;
+ ++FlushEventsProcessed;
+ MakePacket(false); // just generate confirmation packet if we have preconditions for this
+ } else if (ForcePacketTimestamp != TInstant::Max()) {
+ ScheduleFlush();
+ }
+ }
+ }
+
+ void TInterconnectSessionTCP::ResetFlushLogic() {
+ ForcePacketTimestamp = TInstant::Max();
+ UnconfirmedBytes = 0;
+ const TDuration ping = Proxy->Common->Settings.PingPeriod;
+ if (ping != TDuration::Zero() && !NumEventsInReadyChannels) {
+ SetForcePacketTimestamp(ping);
+ }
+ }
+
+ void TInterconnectSessionTCP::TrimSendQueueCache() {
+ static constexpr size_t maxItems = 32;
+ static constexpr size_t trimThreshold = maxItems * 2;
+ if (SendQueueCache.size() >= trimThreshold) {
+ auto it = SendQueueCache.end();
+ for (size_t n = SendQueueCache.size() - maxItems; n; --n) {
+ --it;
+ }
+
+ auto ev = std::make_unique<TEvFreeItems>();
+ ev->Items.splice(ev->Items.end(), SendQueueCache, it, SendQueueCache.end());
+ ev->NumBytes = ev->Items.size() * sizeof(TTcpPacketOutTask);
+ if (ev->GetInLineForDestruction(Proxy->Common)) {
+ Send(Proxy->Common->DestructorId, ev.release());
+ }
+ }
+ }
+
+ ui64 TInterconnectSessionTCP::MakePacket(bool data, TMaybe<ui64> pingMask) {
+ Y_VERIFY(Socket);
+
+ TSendQueue::iterator packet;
+ if (SendQueueCache) {
+ // we have entries in cache, take one and move it to the end of SendQueue
+ packet = SendQueueCache.begin();
+ SendQueue.splice(SendQueue.end(), SendQueueCache, packet);
+ packet->Reuse(); // reset packet to initial state
+ } else {
+ // we have to allocate new packet, so just do it
+ LWPROBE_IF_TOO_LONG(SlowICAllocPacketBuffer, Proxy->PeerNodeId, ms) {
+ packet = SendQueue.emplace(SendQueue.end(), Params);
+ }
+ }
+
+ // update send queue position
+ if (SendQueuePos == SendQueue.end()) {
+ SendQueuePos = packet; // start sending this packet if we are not sending anything for now
+ }
+
+ ui64 serial = 0;
+
+ if (data) {
+ // generate serial for this data packet
+ serial = ++OutputCounter;
+
+ // fill the data packet
+ Y_VERIFY(NumEventsInReadyChannels);
+ LWPROBE_IF_TOO_LONG(SlowICFillSendingBuffer, Proxy->PeerNodeId, ms) {
+ FillSendingBuffer(*packet, serial);
+ }
+ Y_VERIFY(!packet->IsEmpty());
+
+ InflightDataAmount += packet->GetDataSize();
+ Proxy->Metrics->AddInflightDataAmount(packet->GetDataSize());
+ if (InflightDataAmount > GetTotalInflightAmountOfData()) {
+ Proxy->Metrics->IncInflyLimitReach();
+ }
+
+ if (AtomicGet(ReceiveContext->ControlPacketId) == 0) {
+ AtomicSet(ReceiveContext->ControlPacketSendTimer, GetCycleCountFast());
+ AtomicSet(ReceiveContext->ControlPacketId, OutputCounter);
+ }
+
+ // update payload activity timer
+ LastPayloadActivityTimestamp = TActivationContext::Now();
+ } else if (pingMask) {
+ serial = *pingMask;
+
+ // make this packet a priority one
+ if (SendQueuePos != packet) {
+ Y_VERIFY(SendQueuePos != SendQueue.end());
+ if (SendQueuePos->IsAtBegin()) {
+ // insert this packet just before the next being sent and step back
+ SendQueue.splice(SendQueuePos, SendQueue, packet);
+ --SendQueuePos;
+ Y_VERIFY(SendQueuePos == packet);
+ } else {
+ // current packet is already being sent, so move new packet just after it
+ SendQueue.splice(std::next(SendQueuePos), SendQueue, packet);
+ }
+ }
+ }
+
+ const ui64 lastInputSerial = ReceiveContext->GetLastProcessedPacketSerial();
+ packet->SetMetadata(serial, lastInputSerial);
+ packet->Sign();
+
+ // count number of bytes pending for write
+ ui64 packetSize = (Params.UseModernFrame ? sizeof(TTcpPacketHeader_v2) : sizeof(TTcpPacketHeader_v1)) + packet->GetDataSize();
+ BytesUnwritten += packetSize;
+
+ LOG_DEBUG_IC_SESSION("ICS22", "outgoing packet Serial# %" PRIu64 " Confirm# %" PRIu64 " DataSize# %zu"
+ " InflightDataAmount# %" PRIu64 " BytesUnwritten# %" PRIu64, serial, lastInputSerial, packet->GetDataSize(),
+ InflightDataAmount, BytesUnwritten);
+
+ // reset forced packet sending timestamp as we have confirmed all received data
+ ResetFlushLogic();
+
+ ++PacketsGenerated;
+ LWTRACK(PacketGenerated, packet->Orbit, Proxy->PeerNodeId, BytesUnwritten, InflightDataAmount, PacketsGenerated, packetSize);
+
+ if (!data) {
+ WriteData();
+ }
+
+ return packetSize;
+ }
+
+ bool TInterconnectSessionTCP::DropConfirmed(ui64 confirm) {
+ LOG_DEBUG_IC_SESSION("ICS23", "confirm count: %" PRIu64, confirm);
+
+ Y_VERIFY(LastConfirmed <= confirm && confirm <= LastSentSerial && LastSentSerial <= OutputCounter,
+ "%s confirm# %" PRIu64 " LastConfirmed# %" PRIu64 " OutputCounter# %" PRIu64 " LastSentSerial# %" PRIu64,
+ LogPrefix.data(), confirm, LastConfirmed, OutputCounter, LastSentSerial);
+ LastConfirmed = confirm;
+
+ ui64 droppedDataAmount = 0;
+ ui32 numDropped = 0;
+
+ // drop confirmed packets; this also includes any auxiliary packets as their serial is set to zero, effectively
+ // making Serial <= confirm true
+ TSendQueue::iterator it;
+ ui64 lastDroppedSerial = 0;
+ for (it = SendQueue.begin(); it != SendQueuePos && it->Confirmed(confirm); ++it) {
+ if (!it->IsEmpty()) {
+ lastDroppedSerial = it->GetSerial();
+ }
+ droppedDataAmount += it->GetDataSize();
+ ++numDropped;
+ }
+ SendQueueCache.splice(SendQueueCache.begin(), SendQueue, SendQueue.begin(), it);
+ TrimSendQueueCache();
+ ChannelScheduler->ForEach([&](TEventOutputChannel& channel) {
+ channel.DropConfirmed(lastDroppedSerial);
+ });
+
+ const ui64 current = InflightDataAmount;
+ const ui64 limit = GetTotalInflightAmountOfData();
+ const bool unblockedSomething = current >= limit && current < limit + droppedDataAmount;
+
+ PacketsConfirmed += numDropped;
+ InflightDataAmount -= droppedDataAmount;
+ Proxy->Metrics->SubInflightDataAmount(droppedDataAmount);
+ LWPROBE(DropConfirmed, Proxy->PeerNodeId, droppedDataAmount, InflightDataAmount);
+
+ LOG_DEBUG_IC_SESSION("ICS24", "exit InflightDataAmount: %" PRIu64 " bytes droppedDataAmount: %" PRIu64 " bytes"
+ " dropped %" PRIu32 " packets", InflightDataAmount, droppedDataAmount, numDropped);
+
+ Pool->Trim(); // send any unsent free requests
+
+ return unblockedSomething;
+ }
+
+ void TInterconnectSessionTCP::FillSendingBuffer(TTcpPacketOutTask& task, ui64 serial) {
+ ui32 bytesGenerated = 0;
+
+ Y_VERIFY(NumEventsInReadyChannels);
+ while (NumEventsInReadyChannels) {
+ TEventOutputChannel *channel = ChannelScheduler->PickChannelWithLeastConsumedWeight();
+ Y_VERIFY_DEBUG(!channel->IsEmpty());
+
+ // generate some data within this channel
+ const ui64 netBefore = channel->GetBufferedAmountOfData();
+ ui64 gross = 0;
+ const bool eventDone = channel->FeedBuf(task, serial, &gross);
+ channel->UnaccountedTraffic += gross;
+ const ui64 netAfter = channel->GetBufferedAmountOfData();
+ Y_VERIFY_DEBUG(netAfter <= netBefore); // net amount should shrink
+ const ui64 net = netBefore - netAfter; // number of net bytes serialized
+
+ // adjust metrics for local and global queue size
+ TotalOutputQueueSize -= net;
+ Proxy->Metrics->SubOutputBuffersTotalSize(net);
+ bytesGenerated += gross;
+ Y_VERIFY_DEBUG(!!net == !!gross && gross >= net, "net# %" PRIu64 " gross# %" PRIu64, net, gross);
+
+ // return it back to queue or delete, depending on whether this channel is still working or not
+ ChannelScheduler->FinishPick(gross, EqualizeCounter);
+
+ // update some stats if the packet was fully serialized
+ if (eventDone) {
+ ++MessagesWrittenToBuffer;
+
+ Y_VERIFY(NumEventsInReadyChannels);
+ --NumEventsInReadyChannels;
+
+ if (!NumEventsInReadyChannels) {
+ SetOutputStuckFlag(false);
+ }
+ }
+
+ if (!gross) { // no progress -- almost full packet buffer
+ break;
+ }
+ }
+
+ LWTRACK(FillSendingBuffer, task.Orbit, Proxy->PeerNodeId, bytesGenerated, NumEventsInReadyChannels, WriteBlockedTotal);
+ Y_VERIFY(bytesGenerated); // ensure we are not stalled in serialization
+ }
+
+ ui32 TInterconnectSessionTCP::CalculateQueueUtilization() {
+ SwitchStuckPeriod();
+ ui64 sumBusy = 0, sumPeriod = 0;
+ for (auto iter = OutputQueueUtilization.begin(); iter != OutputQueueUtilization.end() - 1; ++iter) {
+ sumBusy += iter->first;
+ sumPeriod += iter->second;
+ }
+ return sumBusy * 1000000 / sumPeriod;
+ }
+
+ void TInterconnectSessionTCP::SendUpdateToWhiteboard(bool connected) {
+ const ui32 utilization = Socket ? CalculateQueueUtilization() : 0;
+
+ if (const auto& callback = Proxy->Common->UpdateWhiteboard) {
+ enum class EFlag {
+ GREEN,
+ YELLOW,
+ ORANGE,
+ RED,
+ };
+ EFlag flagState = EFlag::RED;
+
+ if (Socket) {
+ flagState = EFlag::GREEN;
+
+ do {
+ auto lastInputDelay = TActivationContext::Now() - LastInputActivityTimestamp;
+ if (lastInputDelay * 4 >= GetDeadPeerTimeout() * 3) {
+ flagState = EFlag::ORANGE;
+ break;
+ } else if (lastInputDelay * 2 >= GetDeadPeerTimeout()) {
+ flagState = EFlag::YELLOW;
+ }
+
+ // check utilization
+ if (utilization > 875000) { // 7/8
+ flagState = EFlag::ORANGE;
+ break;
+ } else if (utilization > 500000) { // 1/2
+ flagState = EFlag::YELLOW;
+ }
+ } while (false);
+ }
+
+ callback(Proxy->Metrics->GetHumanFriendlyPeerHostName(),
+ connected,
+ flagState == EFlag::GREEN,
+ flagState == EFlag::YELLOW,
+ flagState == EFlag::ORANGE,
+ flagState == EFlag::RED,
+ TlsActivationContext->ExecutorThread.ActorSystem);
+ }
+
+ if (connected) {
+ Schedule(TDuration::Seconds(1), new TEvents::TEvWakeup);
+ }
+ }
+
+ void TInterconnectSessionTCP::SetOutputStuckFlag(bool state) {
+ if (OutputStuckFlag == state)
+ return;
+
+ if (OutputQueueUtilization.Size() == 0)
+ return;
+
+ auto& lastpair = OutputQueueUtilization.Last();
+ if (state)
+ lastpair.first -= GetCycleCountFast();
+ else
+ lastpair.first += GetCycleCountFast();
+
+ OutputStuckFlag = state;
+ }
+
+ void TInterconnectSessionTCP::SwitchStuckPeriod() {
+ auto now = GetCycleCountFast();
+ if (OutputQueueUtilization.Size() != 0) {
+ auto& lastpair = OutputQueueUtilization.Last();
+ lastpair.second = now - lastpair.second;
+ if (OutputStuckFlag)
+ lastpair.first += now;
+ }
+
+ OutputQueueUtilization.Push(std::pair<ui64, ui64>(0, now));
+ if (OutputStuckFlag)
+ OutputQueueUtilization.Last().first -= now;
+ }
+
+ TDuration TInterconnectSessionTCP::GetDeadPeerTimeout() const {
+ return Coalesce(Proxy->Common->Settings.DeadPeer, DEFAULT_DEADPEER_TIMEOUT);
+ }
+
+ TDuration TInterconnectSessionTCP::GetCloseOnIdleTimeout() const {
+ return Proxy->Common->Settings.CloseOnIdle;
+ }
+
+ TDuration TInterconnectSessionTCP::GetLostConnectionTimeout() const {
+ return Coalesce(Proxy->Common->Settings.LostConnection, DEFAULT_LOST_CONNECTION_TIMEOUT);
+ }
+
+ ui32 TInterconnectSessionTCP::GetTotalInflightAmountOfData() const {
+ return Coalesce(Proxy->Common->Settings.TotalInflightAmountOfData, DEFAULT_TOTAL_INFLIGHT_DATA);
+ }
+
+ ui64 TInterconnectSessionTCP::GetMaxCyclesPerEvent() const {
+ return DurationToCycles(TDuration::MicroSeconds(50));
+ }
+
+ void TInterconnectSessionTCP::IssuePingRequest() {
+ const TInstant now = TActivationContext::Now();
+ if (now >= LastPingTimestamp + PingPeriodicity) {
+ LOG_DEBUG_IC_SESSION("ICS22", "Issuing ping request");
+ if (Socket) {
+ MakePacket(false, GetCycleCountFast() | TTcpPacketBuf::PingRequestMask);
+ }
+ if (Socket) {
+ MakePacket(false, TInstant::Now().MicroSeconds() | TTcpPacketBuf::ClockMask);
+ }
+ LastPingTimestamp = now;
+ }
+ }
+
+ void TInterconnectSessionTCP::Handle(TEvProcessPingRequest::TPtr ev) {
+ if (Socket) {
+ MakePacket(false, ev->Get()->Payload | TTcpPacketBuf::PingResponseMask);
+ }
+ }
+
+ void TInterconnectSessionTCP::GenerateHttpInfo(TStringStream& str) {
+ HTML(str) {
+ DIV_CLASS("panel panel-info") {
+ DIV_CLASS("panel-heading") {
+ str << "Session";
+ }
+ DIV_CLASS("panel-body") {
+ TABLE_CLASS("table") {
+ TABLEHEAD() {
+ TABLER() {
+ TABLEH() {
+ str << "Sensor";
+ }
+ TABLEH() {
+ str << "Value";
+ }
+ }
+ }
+ TABLEBODY() {
+ TABLER() {
+ TABLED() {
+ str << "Encryption";
+ }
+ TABLED() {
+ str << (Params.Encryption ? "<font color=green>Enabled</font>" : "<font color=red>Disabled</font>");
+ }
+ }
+ if (auto *x = dynamic_cast<NInterconnect::TSecureSocket*>(Socket.Get())) {
+ TABLER() {
+ TABLED() {
+ str << "Cipher name";
+ }
+ TABLED() {
+ str << x->GetCipherName();
+ }
+ }
+ TABLER() {
+ TABLED() {
+ str << "Cipher bits";
+ }
+ TABLED() {
+ str << x->GetCipherBits();
+ }
+ }
+ TABLER() {
+ TABLED() {
+ str << "Protocol";
+ }
+ TABLED() {
+ str << x->GetProtocolName();
+ }
+ }
+ TABLER() {
+ TABLED() {
+ str << "Peer CN";
+ }
+ TABLED() {
+ str << x->GetPeerCommonName();
+ }
+ }
+ }
+ TABLER() {
+ TABLED() { str << "AuthOnly CN"; }
+ TABLED() { str << Params.AuthCN; }
+ }
+ TABLER() {
+ TABLED() {
+ str << "Local scope id";
+ }
+ TABLED() {
+ str << ScopeIdToString(Proxy->Common->LocalScopeId);
+ }
+ }
+ TABLER() {
+ TABLED() {
+ str << "Peer scope id";
+ }
+ TABLED() {
+ str << ScopeIdToString(Params.PeerScopeId);
+ }
+ }
+ TABLER() {
+ TABLED() {
+ str << "This page generated at";
+ }
+ TABLED() {
+ str << TActivationContext::Now() << " / " << Now();
+ }
+ }
+ TABLER() {
+ TABLED() {
+ str << "SelfID";
+ }
+ TABLED() {
+ str << SelfId().ToString();
+ }
+ }
+ TABLER() {
+ TABLED() { str << "Frame version/Checksum"; }
+ TABLED() { str << (!Params.UseModernFrame ? "v1/crc32c" : Params.Encryption ? "v2/none" : "v2/crc32c"); }
+ }
+#define MON_VAR(NAME) \
+ TABLER() { \
+ TABLED() { \
+ str << #NAME; \
+ } \
+ TABLED() { \
+ str << NAME; \
+ } \
+ }
+
+ MON_VAR(Created)
+ MON_VAR(NewConnectionSet)
+ MON_VAR(ReceiverId)
+ MON_VAR(MessagesGot)
+ MON_VAR(MessagesWrittenToBuffer)
+ MON_VAR(PacketsGenerated)
+ MON_VAR(PacketsWrittenToSocket)
+ MON_VAR(PacketsConfirmed)
+ MON_VAR(AtomicGet(ReceiveContext->PacketsReadFromSocket))
+ MON_VAR(ConfirmPacketsForcedBySize)
+ MON_VAR(ConfirmPacketsForcedByTimeout)
+
+ TABLER() {
+ TABLED() {
+ str << "Virtual self ID";
+ }
+ TABLED() {
+ str << Proxy->SessionVirtualId.ToString();
+ }
+ }
+ TABLER() {
+ TABLED() {
+ str << "Virtual peer ID";
+ }
+ TABLED() {
+ str << Proxy->RemoteSessionVirtualId.ToString();
+ }
+ }
+ TABLER() {
+ TABLED() {
+ str << "Socket";
+ }
+ TABLED() {
+ str << (Socket ? i64(*Socket) : -1);
+ }
+ }
+
+ ui32 unsentQueueSize = Socket ? Socket->GetUnsentQueueSize() : 0;
+
+ MON_VAR(OutputStuckFlag)
+ MON_VAR(SendQueue.size())
+ MON_VAR(SendQueueCache.size())
+ MON_VAR(NumEventsInReadyChannels)
+ MON_VAR(TotalOutputQueueSize)
+ MON_VAR(BytesUnwritten)
+ MON_VAR(InflightDataAmount)
+ MON_VAR(unsentQueueSize)
+ MON_VAR(SendBufferSize)
+ MON_VAR(LastInputActivityTimestamp)
+ MON_VAR(LastPayloadActivityTimestamp)
+ MON_VAR(LastHandshakeDone)
+ MON_VAR(OutputCounter)
+ MON_VAR(LastSentSerial)
+ MON_VAR(ReceiveContext->GetLastProcessedPacketSerial())
+ MON_VAR(LastConfirmed)
+ MON_VAR(FlushSchedule.size())
+ MON_VAR(MaxFlushSchedule)
+ MON_VAR(FlushEventsScheduled)
+ MON_VAR(FlushEventsProcessed)
+
+ TString clockSkew;
+ i64 x = GetClockSkew();
+ if (x < 0) {
+ clockSkew = Sprintf("-%s", TDuration::MicroSeconds(-x).ToString().data());
+ } else {
+ clockSkew = Sprintf("+%s", TDuration::MicroSeconds(x).ToString().data());
+ }
+
+ MON_VAR(LastPingTimestamp)
+ MON_VAR(GetPingRTT())
+ MON_VAR(clockSkew)
+
+ MON_VAR(GetDeadPeerTimeout())
+ MON_VAR(GetTotalInflightAmountOfData())
+ MON_VAR(GetCloseOnIdleTimeout())
+ MON_VAR(Subscribers.size())
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void CreateSessionKillingActor(TInterconnectProxyCommon::TPtr common) {
+ TlsActivationContext->ExecutorThread.ActorSystem->Register(new TInterconnectSessionKiller(common));
+ }
+}
diff --git a/library/cpp/actors/interconnect/interconnect_tcp_session.h b/library/cpp/actors/interconnect/interconnect_tcp_session.h
new file mode 100644
index 0000000000..7fc00dbcc5
--- /dev/null
+++ b/library/cpp/actors/interconnect/interconnect_tcp_session.h
@@ -0,0 +1,565 @@
+#pragma once
+
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/actors/core/event_pb.h>
+#include <library/cpp/actors/core/events.h>
+#include <library/cpp/actors/core/log.h>
+#include <library/cpp/actors/helpers/mon_histogram_helper.h>
+#include <library/cpp/actors/protos/services_common.pb.h>
+#include <library/cpp/actors/util/datetime.h>
+#include <library/cpp/actors/util/rope.h>
+#include <library/cpp/actors/util/funnel_queue.h>
+#include <library/cpp/actors/util/recentwnd.h>
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+#include <library/cpp/actors/core/actor_bootstrapped.h>
+
+#include <util/generic/queue.h>
+#include <util/generic/deque.h>
+#include <util/datetime/cputimer.h>
+
+#include "interconnect_impl.h"
+#include "poller_tcp.h"
+#include "poller_actor.h"
+#include "interconnect_channel.h"
+#include "logging.h"
+#include "watchdog_timer.h"
+#include "event_holder_pool.h"
+#include "channel_scheduler.h"
+
+#include <unordered_set>
+#include <unordered_map>
+
+namespace NActors {
+ class TSlowPathChecker {
+ using TTraceCallback = std::function<void(double)>;
+ TTraceCallback Callback;
+ const NHPTimer::STime Start;
+
+ public:
+ TSlowPathChecker(TTraceCallback&& callback)
+ : Callback(std::move(callback))
+ , Start(GetCycleCountFast())
+ {
+ }
+
+ ~TSlowPathChecker() {
+ const NHPTimer::STime end = GetCycleCountFast();
+ const NHPTimer::STime elapsed = end - Start;
+ if (elapsed > 1000000) {
+ Callback(NHPTimer::GetSeconds(elapsed) * 1000);
+ }
+ }
+
+ operator bool() const {
+ return false;
+ }
+ };
+
+#define LWPROBE_IF_TOO_LONG(...) \
+ if (auto __x = TSlowPathChecker{[&](double ms) { LWPROBE(__VA_ARGS__); }}) \
+ ; \
+ else
+
+ class TTimeLimit {
+ public:
+ TTimeLimit(ui64 limitInCycles)
+ : UpperLimit(limitInCycles == 0 ? 0 : GetCycleCountFast() + limitInCycles)
+ {
+ }
+
+ TTimeLimit(ui64 startTS, ui64 limitInCycles)
+ : UpperLimit(limitInCycles == 0 ? 0 : startTS + limitInCycles)
+ {
+ }
+
+ bool CheckExceeded() {
+ return UpperLimit != 0 && GetCycleCountFast() > UpperLimit;
+ }
+
+ const ui64 UpperLimit;
+ };
+
+ static constexpr TDuration DEFAULT_DEADPEER_TIMEOUT = TDuration::Seconds(10);
+ static constexpr TDuration DEFAULT_LOST_CONNECTION_TIMEOUT = TDuration::Seconds(10);
+ static constexpr ui32 DEFAULT_MAX_INFLIGHT_DATA = 10240 * 1024;
+ static constexpr ui32 DEFAULT_TOTAL_INFLIGHT_DATA = 4 * 10240 * 1024;
+
+ class TInterconnectProxyTCP;
+
+ enum class EUpdateState : ui8 {
+ NONE, // no updates generated by input session yet
+ INFLIGHT, // one update is inflight, and no more pending
+ INFLIGHT_AND_PENDING, // one update is inflight, and one is pending
+ CONFIRMING, // confirmation inflight
+ };
+
+ struct TReceiveContext: public TAtomicRefCount<TReceiveContext> {
+ /* All invokations to these fields should be thread-safe */
+
+ ui64 ControlPacketSendTimer = 0;
+ ui64 ControlPacketId = 0;
+
+ // number of packets received by input session
+ TAtomic PacketsReadFromSocket = 0;
+ TAtomic DataPacketsReadFromSocket = 0;
+
+ // last processed packet by input session
+ std::atomic_uint64_t LastProcessedPacketSerial = 0;
+ static constexpr uint64_t LastProcessedPacketSerialLockBit = uint64_t(1) << 63;
+
+ // for hardened checks
+ TAtomic NumInputSessions = 0;
+
+ NHPTimer::STime StartTime;
+
+ std::atomic<ui64> PingRTT_us = 0;
+ std::atomic<i64> ClockSkew_us = 0;
+
+ std::atomic<EUpdateState> UpdateState;
+ static_assert(std::atomic<EUpdateState>::is_always_lock_free);
+
+ bool WriteBlockedByFullSendBuffer = false;
+ bool ReadPending = false;
+
+ std::array<TRope, 16> ChannelArray;
+ std::unordered_map<ui16, TRope> ChannelMap;
+
+ TReceiveContext() {
+ GetTimeFast(&StartTime);
+ }
+
+ // returns false if sessions needs to be terminated and packet not to be processed
+ bool AdvanceLastProcessedPacketSerial() {
+ for (;;) {
+ uint64_t value = LastProcessedPacketSerial.load();
+ if (value & LastProcessedPacketSerialLockBit) {
+ return false;
+ }
+ if (LastProcessedPacketSerial.compare_exchange_weak(value, value + 1)) {
+ return true;
+ }
+ }
+ }
+
+ ui64 LockLastProcessedPacketSerial() {
+ for (;;) {
+ uint64_t value = LastProcessedPacketSerial.load();
+ if (value & LastProcessedPacketSerialLockBit) {
+ return value & ~LastProcessedPacketSerialLockBit;
+ }
+ if (LastProcessedPacketSerial.compare_exchange_strong(value, value | LastProcessedPacketSerialLockBit)) {
+ return value;
+ }
+ }
+ }
+
+ void UnlockLastProcessedPacketSerial() {
+ LastProcessedPacketSerial = LastProcessedPacketSerial.load() & ~LastProcessedPacketSerialLockBit;
+ }
+
+ ui64 GetLastProcessedPacketSerial() {
+ return LastProcessedPacketSerial.load() & ~LastProcessedPacketSerialLockBit;
+ }
+ };
+
+ class TInputSessionTCP
+ : public TActorBootstrapped<TInputSessionTCP>
+ , public TInterconnectLoggingBase
+ {
+ enum {
+ EvCheckDeadPeer = EventSpaceBegin(TEvents::ES_PRIVATE),
+ EvResumeReceiveData,
+ };
+
+ struct TEvCheckDeadPeer : TEventLocal<TEvCheckDeadPeer, EvCheckDeadPeer> {};
+ struct TEvResumeReceiveData : TEventLocal<TEvResumeReceiveData, EvResumeReceiveData> {};
+
+ public:
+ static constexpr EActivityType ActorActivityType() {
+ return INTERCONNECT_SESSION_TCP;
+ }
+
+ TInputSessionTCP(const TActorId& sessionId,
+ TIntrusivePtr<NInterconnect::TStreamSocket> socket,
+ TIntrusivePtr<TReceiveContext> context,
+ TInterconnectProxyCommon::TPtr common,
+ std::shared_ptr<IInterconnectMetrics> metrics,
+ ui32 nodeId,
+ ui64 lastConfirmed,
+ TDuration deadPeerTimeout,
+ TSessionParams params);
+
+ private:
+ friend class TActorBootstrapped<TInputSessionTCP>;
+
+ void Bootstrap();
+
+ STRICT_STFUNC(WorkingState,
+ cFunc(TEvents::TSystem::PoisonPill, PassAway)
+ hFunc(TEvPollerReady, Handle)
+ hFunc(TEvPollerRegisterResult, Handle)
+ cFunc(EvResumeReceiveData, HandleResumeReceiveData)
+ cFunc(TEvInterconnect::TEvCloseInputSession::EventType, CloseInputSession)
+ cFunc(EvCheckDeadPeer, HandleCheckDeadPeer)
+ cFunc(TEvConfirmUpdate::EventType, HandleConfirmUpdate)
+ )
+
+ private:
+ TRope IncomingData;
+
+ const TActorId SessionId;
+ TIntrusivePtr<NInterconnect::TStreamSocket> Socket;
+ TPollerToken::TPtr PollerToken;
+ TIntrusivePtr<TReceiveContext> Context;
+ TInterconnectProxyCommon::TPtr Common;
+ const ui32 NodeId;
+ const TSessionParams Params;
+
+ // header we are currently processing (parsed from the stream)
+ union {
+ TTcpPacketHeader_v1 v1;
+ TTcpPacketHeader_v2 v2;
+ char Data[1];
+ } Header;
+ ui64 HeaderConfirm, HeaderSerial;
+
+ size_t PayloadSize;
+ ui32 ChecksumExpected, Checksum;
+ bool IgnorePayload;
+ TRope Payload;
+ enum class EState {
+ HEADER,
+ PAYLOAD,
+ };
+ EState State = EState::HEADER;
+
+ THolder<TEvUpdateFromInputSession> UpdateFromInputSession;
+
+ ui64 ConfirmedByInput;
+
+ std::shared_ptr<IInterconnectMetrics> Metrics;
+
+ bool CloseInputSessionRequested = false;
+
+ void CloseInputSession();
+
+ void Handle(TEvPollerReady::TPtr ev);
+ void Handle(TEvPollerRegisterResult::TPtr ev);
+ void HandleResumeReceiveData();
+ void HandleConfirmUpdate();
+ void ReceiveData();
+ void ProcessHeader(size_t headerLen);
+ void ProcessPayload(ui64& numDataBytes);
+ void ProcessEvent(TRope& data, TEventDescr& descr);
+ bool ReadMore();
+
+ void ReestablishConnection(TDisconnectReason reason);
+ void DestroySession(TDisconnectReason reason);
+
+ TDeque<TIntrusivePtr<TRopeAlignedBuffer>> Buffers;
+
+ static constexpr size_t NumPreallocatedBuffers = 16;
+ void PreallocateBuffers();
+
+ inline ui64 GetMaxCyclesPerEvent() const {
+ return DurationToCycles(TDuration::MicroSeconds(500));
+ }
+
+ const TDuration DeadPeerTimeout;
+ TInstant LastReceiveTimestamp;
+ void HandleCheckDeadPeer();
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // pinger logic
+
+ bool NewPingProtocol = false;
+ TDeque<TDuration> PingQ; // last N ping samples
+ TDeque<i64> SkewQ; // last N calculated clock skew samples
+
+ void HandlePingResponse(TDuration passed);
+ void HandleClock(TInstant clock);
+ };
+
+ class TInterconnectSessionTCP
+ : public TActor<TInterconnectSessionTCP>
+ , public TInterconnectLoggingBase
+ {
+ enum {
+ EvCheckCloseOnIdle = EventSpaceBegin(TEvents::ES_PRIVATE),
+ EvCheckLostConnection,
+ EvRam,
+ EvTerminate,
+ EvFreeItems,
+ };
+
+ struct TEvCheckCloseOnIdle : TEventLocal<TEvCheckCloseOnIdle, EvCheckCloseOnIdle> {};
+ struct TEvCheckLostConnection : TEventLocal<TEvCheckLostConnection, EvCheckLostConnection> {};
+
+ struct TEvRam : TEventLocal<TEvRam, EvRam> {
+ const bool Batching;
+ TEvRam(bool batching) : Batching(batching) {}
+ };
+
+ struct TEvTerminate : TEventLocal<TEvTerminate, EvTerminate> {
+ TDisconnectReason Reason;
+
+ TEvTerminate(TDisconnectReason reason)
+ : Reason(std::move(reason))
+ {}
+ };
+
+ const TInstant Created;
+ TInstant NewConnectionSet;
+ ui64 MessagesGot = 0;
+ ui64 MessagesWrittenToBuffer = 0;
+ ui64 PacketsGenerated = 0;
+ ui64 PacketsWrittenToSocket = 0;
+ ui64 PacketsConfirmed = 0;
+
+ public:
+ static constexpr EActivityType ActorActivityType() {
+ return INTERCONNECT_SESSION_TCP;
+ }
+
+ TInterconnectSessionTCP(TInterconnectProxyTCP* const proxy, TSessionParams params);
+ ~TInterconnectSessionTCP();
+
+ void Init();
+ void CloseInputSession();
+
+ static TEvTerminate* NewEvTerminate(TDisconnectReason reason) {
+ return new TEvTerminate(std::move(reason));
+ }
+
+ TDuration GetPingRTT() const {
+ return TDuration::MicroSeconds(ReceiveContext->PingRTT_us);
+ }
+
+ i64 GetClockSkew() const {
+ return ReceiveContext->ClockSkew_us;
+ }
+
+ private:
+ friend class TInterconnectProxyTCP;
+
+ void Handle(TEvTerminate::TPtr& ev);
+ void HandlePoison();
+ void Terminate(TDisconnectReason reason);
+ void PassAway() override;
+
+ void Forward(STATEFN_SIG);
+ void Subscribe(STATEFN_SIG);
+ void Unsubscribe(STATEFN_SIG);
+
+ STRICT_STFUNC(StateFunc,
+ fFunc(TEvInterconnect::EvForward, Forward)
+ cFunc(TEvents::TEvPoisonPill::EventType, HandlePoison)
+ fFunc(TEvInterconnect::TEvConnectNode::EventType, Subscribe)
+ fFunc(TEvents::TEvSubscribe::EventType, Subscribe)
+ fFunc(TEvents::TEvUnsubscribe::EventType, Unsubscribe)
+ cFunc(TEvFlush::EventType, HandleFlush)
+ hFunc(TEvPollerReady, Handle)
+ hFunc(TEvPollerRegisterResult, Handle)
+ hFunc(TEvUpdateFromInputSession, Handle)
+ hFunc(TEvRam, HandleRam)
+ hFunc(TEvCheckCloseOnIdle, CloseOnIdleWatchdog)
+ hFunc(TEvCheckLostConnection, LostConnectionWatchdog)
+ cFunc(TEvents::TSystem::Wakeup, SendUpdateToWhiteboard)
+ hFunc(TEvSocketDisconnect, OnDisconnect)
+ hFunc(TEvTerminate, Handle)
+ hFunc(TEvProcessPingRequest, Handle)
+ )
+
+ void Handle(TEvUpdateFromInputSession::TPtr& ev);
+
+ void OnDisconnect(TEvSocketDisconnect::TPtr& ev);
+
+ THolder<TEvHandshakeAck> ProcessHandshakeRequest(TEvHandshakeAsk::TPtr& ev);
+ void SetNewConnection(TEvHandshakeDone::TPtr& ev);
+
+ TEvRam* RamInQueue = nullptr;
+ ui64 RamStartedCycles = 0;
+ void HandleRam(TEvRam::TPtr& ev);
+ void GenerateTraffic();
+
+ void SendUpdateToWhiteboard(bool connected = true);
+ ui32 CalculateQueueUtilization();
+
+ void Handle(TEvPollerReady::TPtr& ev);
+ void Handle(TEvPollerRegisterResult::TPtr ev);
+ void WriteData();
+
+ ui64 MakePacket(bool data, TMaybe<ui64> pingMask = {});
+ void FillSendingBuffer(TTcpPacketOutTask& packet, ui64 serial);
+ bool DropConfirmed(ui64 confirm);
+ void ShutdownSocket(TDisconnectReason reason);
+
+ void StartHandshake();
+ void ReestablishConnection(TEvHandshakeDone::TPtr&& ev, bool startHandshakeOnSessionClose,
+ TDisconnectReason reason);
+ void ReestablishConnectionWithHandshake(TDisconnectReason reason);
+ void ReestablishConnectionExecute();
+
+ TInterconnectProxyTCP* const Proxy;
+
+ // various connection settings access
+ TDuration GetDeadPeerTimeout() const;
+ TDuration GetCloseOnIdleTimeout() const;
+ TDuration GetLostConnectionTimeout() const;
+ ui32 GetTotalInflightAmountOfData() const;
+ ui64 GetMaxCyclesPerEvent() const;
+
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // pinger
+
+ TInstant LastPingTimestamp;
+ static constexpr TDuration PingPeriodicity = TDuration::Seconds(1);
+ void IssuePingRequest();
+ void Handle(TEvProcessPingRequest::TPtr ev);
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ TInstant LastInputActivityTimestamp;
+ TInstant LastPayloadActivityTimestamp;
+ TWatchdogTimer<TEvCheckCloseOnIdle> CloseOnIdleWatchdog;
+ TWatchdogTimer<TEvCheckLostConnection> LostConnectionWatchdog;
+
+ void OnCloseOnIdleTimerHit() {
+ LOG_INFO_IC("ICS27", "CloseOnIdle timer hit, session terminated");
+ Terminate(TDisconnectReason::CloseOnIdle());
+ }
+
+ void OnLostConnectionTimerHit() {
+ LOG_ERROR_IC("ICS28", "LostConnection timer hit, session terminated");
+ Terminate(TDisconnectReason::LostConnection());
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ const TSessionParams Params;
+ TMaybe<TEventHolderPool> Pool;
+ TMaybe<TChannelScheduler> ChannelScheduler;
+ ui64 TotalOutputQueueSize;
+ bool OutputStuckFlag;
+ TRecentWnd<std::pair<ui64, ui64>> OutputQueueUtilization;
+ size_t NumEventsInReadyChannels = 0;
+
+ void SetOutputStuckFlag(bool state);
+ void SwitchStuckPeriod();
+
+ using TSendQueue = TList<TTcpPacketOutTask>;
+ TSendQueue SendQueue;
+ TSendQueue SendQueueCache;
+ TSendQueue::iterator SendQueuePos;
+ ui64 WriteBlockedCycles = 0; // start of current block period
+ TDuration WriteBlockedTotal; // total incremental duration that session has been blocked
+ ui64 BytesUnwritten = 0;
+
+ void TrimSendQueueCache();
+
+ TDuration GetWriteBlockedTotal() const {
+ if (ReceiveContext->WriteBlockedByFullSendBuffer) {
+ double blockedUs = NHPTimer::GetSeconds(GetCycleCountFast() - WriteBlockedCycles) * 1000000.0;
+ return WriteBlockedTotal + TDuration::MicroSeconds(blockedUs); // append current blocking period if any
+ } else {
+ return WriteBlockedTotal;
+ }
+ }
+
+ ui64 OutputCounter;
+ ui64 LastSentSerial = 0;
+
+ TInstant LastHandshakeDone;
+
+ TIntrusivePtr<NInterconnect::TStreamSocket> Socket;
+ TPollerToken::TPtr PollerToken;
+ ui32 SendBufferSize;
+ ui64 InflightDataAmount = 0;
+
+ std::unordered_map<TActorId, ui64, TActorId::THash> Subscribers;
+
+ // time at which we want to send confirmation packet even if there was no outgoing data
+ ui64 UnconfirmedBytes = 0;
+ TInstant ForcePacketTimestamp = TInstant::Max();
+ TPriorityQueue<TInstant, TVector<TInstant>, std::greater<TInstant>> FlushSchedule;
+ size_t MaxFlushSchedule = 0;
+ ui64 FlushEventsScheduled = 0;
+ ui64 FlushEventsProcessed = 0;
+
+ void SetForcePacketTimestamp(TDuration period);
+ void ScheduleFlush();
+ void HandleFlush();
+ void ResetFlushLogic();
+
+ void GenerateHttpInfo(TStringStream& str);
+
+ TIntrusivePtr<TReceiveContext> ReceiveContext;
+ TActorId ReceiverId;
+ TDuration Ping;
+
+ ui64 ConfirmPacketsForcedBySize = 0;
+ ui64 ConfirmPacketsForcedByTimeout = 0;
+
+ ui64 LastConfirmed = 0;
+
+ TEvHandshakeDone::TPtr PendingHandshakeDoneEvent;
+ bool StartHandshakeOnSessionClose = false;
+
+ ui64 EqualizeCounter = 0;
+ };
+
+ class TInterconnectSessionKiller
+ : public TActorBootstrapped<TInterconnectSessionKiller> {
+ ui32 RepliesReceived = 0;
+ ui32 RepliesNumber = 0;
+ TActorId LargestSession = TActorId();
+ ui64 MaxBufferSize = 0;
+ TInterconnectProxyCommon::TPtr Common;
+
+ public:
+ static constexpr EActivityType ActorActivityType() {
+ return INTERCONNECT_SESSION_KILLER;
+ }
+
+ TInterconnectSessionKiller(TInterconnectProxyCommon::TPtr common)
+ : Common(common)
+ {
+ }
+
+ void Bootstrap() {
+ auto sender = SelfId();
+ const auto eventFabric = [&sender](const TActorId& recp) -> IEventHandle* {
+ auto ev = new TEvSessionBufferSizeRequest();
+ return new IEventHandle(recp, sender, ev, IEventHandle::FlagTrackDelivery);
+ };
+ RepliesNumber = TlsActivationContext->ExecutorThread.ActorSystem->BroadcastToProxies(eventFabric);
+ Become(&TInterconnectSessionKiller::StateFunc);
+ }
+
+ STRICT_STFUNC(StateFunc,
+ hFunc(TEvSessionBufferSizeResponse, ProcessResponse)
+ cFunc(TEvents::TEvUndelivered::EventType, ProcessUndelivered)
+ )
+
+ void ProcessResponse(TEvSessionBufferSizeResponse::TPtr& ev) {
+ RepliesReceived++;
+ if (MaxBufferSize < ev->Get()->BufferSize) {
+ MaxBufferSize = ev->Get()->BufferSize;
+ LargestSession = ev->Get()->SessionID;
+ }
+ if (RepliesReceived == RepliesNumber) {
+ Send(LargestSession, new TEvents::TEvPoisonPill);
+ AtomicUnlock(&Common->StartedSessionKiller);
+ PassAway();
+ }
+ }
+
+ void ProcessUndelivered() {
+ RepliesReceived++;
+ }
+ };
+
+ void CreateSessionKillingActor(TInterconnectProxyCommon::TPtr common);
+
+}
diff --git a/library/cpp/actors/interconnect/load.cpp b/library/cpp/actors/interconnect/load.cpp
new file mode 100644
index 0000000000..2a8443da71
--- /dev/null
+++ b/library/cpp/actors/interconnect/load.cpp
@@ -0,0 +1,405 @@
+#include "load.h"
+#include "interconnect_common.h"
+#include "events_local.h"
+#include <library/cpp/actors/protos/services_common.pb.h>
+#include <library/cpp/actors/core/log.h>
+#include <library/cpp/actors/core/actor_bootstrapped.h>
+#include <library/cpp/actors/core/events.h>
+#include <library/cpp/actors/core/hfunc.h>
+#include <util/generic/queue.h>
+
+namespace NInterconnect {
+ using namespace NActors;
+
+ enum {
+ EvGenerateMessages = EventSpaceBegin(TEvents::ES_PRIVATE),
+ EvPublishResults,
+ EvQueryTrafficCounter,
+ EvTrafficCounter,
+ };
+
+ struct TEvQueryTrafficCounter : TEventLocal<TEvQueryTrafficCounter, EvQueryTrafficCounter> {};
+
+ struct TEvTrafficCounter : TEventLocal<TEvTrafficCounter, EvTrafficCounter> {
+ std::shared_ptr<std::atomic_uint64_t> Traffic;
+
+ TEvTrafficCounter(std::shared_ptr<std::atomic_uint64_t> traffic)
+ : Traffic(std::move(traffic))
+ {}
+ };
+
+ class TLoadResponderActor : public TActor<TLoadResponderActor> {
+ STRICT_STFUNC(StateFunc,
+ HFunc(TEvLoadMessage, Handle);
+ CFunc(TEvents::TSystem::PoisonPill, Die);
+ )
+
+ void Handle(TEvLoadMessage::TPtr& ev, const TActorContext& ctx) {
+ ui64 bytes = ev->Get()->CalculateSerializedSizeCached();
+ auto& record = ev->Get()->Record;
+ auto *hops = record.MutableHops();
+ while (!hops->empty() && !hops->begin()->HasNextHop()) {
+ record.ClearPayload();
+ ev->Get()->StripPayload();
+ hops->erase(hops->begin());
+ }
+ if (!hops->empty()) {
+ // extract actor id of the next hop
+ const TActorId nextHopActorId = ActorIdFromProto(hops->begin()->GetNextHop());
+ hops->erase(hops->begin());
+
+ // forward message to next hop; preserve flags and cookie
+ auto msg = MakeHolder<TEvLoadMessage>();
+ record.Swap(&msg->Record);
+ bytes += msg->CalculateSerializedSizeCached();
+ ctx.Send(nextHopActorId, msg.Release(), ev->Flags, ev->Cookie);
+ }
+ *Traffic += bytes;
+ }
+
+ public:
+ TLoadResponderActor(std::shared_ptr<std::atomic_uint64_t> traffic)
+ : TActor(&TLoadResponderActor::StateFunc)
+ , Traffic(std::move(traffic))
+ {}
+
+ static constexpr IActor::EActivityType ActorActivityType() {
+ return IActor::INTERCONNECT_LOAD_RESPONDER;
+ }
+
+ private:
+ std::shared_ptr<std::atomic_uint64_t> Traffic;
+ };
+
+ class TLoadResponderMasterActor : public TActorBootstrapped<TLoadResponderMasterActor> {
+ TVector<TActorId> Slaves;
+ ui32 SlaveIndex = 0;
+
+ STRICT_STFUNC(StateFunc,
+ HFunc(TEvLoadMessage, Handle);
+ HFunc(TEvQueryTrafficCounter, Handle);
+ CFunc(TEvents::TSystem::PoisonPill, Die);
+ )
+
+ void Handle(TEvLoadMessage::TPtr& ev, const TActorContext& ctx) {
+ ctx.ExecutorThread.ActorSystem->Send(ev->Forward(Slaves[SlaveIndex]));
+ if (++SlaveIndex == Slaves.size()) {
+ SlaveIndex = 0;
+ }
+ }
+
+ void Handle(TEvQueryTrafficCounter::TPtr ev, const TActorContext& ctx) {
+ ctx.Send(ev->Sender, new TEvTrafficCounter(Traffic));
+ }
+
+ void Die(const TActorContext& ctx) override {
+ for (const TActorId& actorId : Slaves) {
+ ctx.Send(actorId, new TEvents::TEvPoisonPill);
+ }
+ TActorBootstrapped::Die(ctx);
+ }
+
+ public:
+ static constexpr IActor::EActivityType ActorActivityType() {
+ return IActor::INTERCONNECT_LOAD_RESPONDER;
+ }
+
+ TLoadResponderMasterActor()
+ {}
+
+ void Bootstrap(const TActorContext& ctx) {
+ Become(&TLoadResponderMasterActor::StateFunc);
+ while (Slaves.size() < 10) {
+ Slaves.push_back(ctx.Register(new TLoadResponderActor(Traffic)));
+ }
+ }
+
+ private:
+ std::shared_ptr<std::atomic_uint64_t> Traffic = std::make_shared<std::atomic_uint64_t>();
+ };
+
+ IActor* CreateLoadResponderActor() {
+ return new TLoadResponderMasterActor();
+ }
+
+ TActorId MakeLoadResponderActorId(ui32 nodeId) {
+ char x[12] = {'I', 'C', 'L', 'o', 'a', 'd', 'R', 'e', 's', 'p', 'A', 'c'};
+ return TActorId(nodeId, TStringBuf(x, 12));
+ }
+
+ class TLoadActor: public TActorBootstrapped<TLoadActor> {
+ struct TEvGenerateMessages : TEventLocal<TEvGenerateMessages, EvGenerateMessages> {};
+ struct TEvPublishResults : TEventLocal<TEvPublishResults, EvPublishResults> {};
+
+ struct TMessageInfo {
+ TInstant SendTimestamp;
+
+ TMessageInfo(const TInstant& sendTimestamp)
+ : SendTimestamp(sendTimestamp)
+ {
+ }
+ };
+
+ const TLoadParams Params;
+ TInstant NextMessageTimestamp;
+ THashMap<TString, TMessageInfo> InFly;
+ ui64 NextId = 1;
+ TVector<TActorId> Hops;
+ TActorId FirstHop;
+ ui64 NumDropped = 0;
+ std::shared_ptr<std::atomic_uint64_t> Traffic;
+
+ public:
+ static constexpr IActor::EActivityType ActorActivityType() {
+ return IActor::INTERCONNECT_LOAD_ACTOR;
+ }
+
+ TLoadActor(const TLoadParams& params)
+ : Params(params)
+ {}
+
+ void Bootstrap(const TActorContext& ctx) {
+ Become(&TLoadActor::QueryTrafficCounter);
+ ctx.Send(MakeLoadResponderActorId(SelfId().NodeId()), new TEvQueryTrafficCounter);
+ }
+
+ void Handle(TEvTrafficCounter::TPtr ev, const TActorContext& ctx) {
+ Traffic = std::move(ev->Get()->Traffic);
+
+ for (const ui32 nodeId : Params.NodeHops) {
+ const TActorId& actorId = nodeId ? MakeLoadResponderActorId(nodeId) : TActorId();
+ if (!FirstHop) {
+ FirstHop = actorId;
+ } else {
+ Hops.push_back(actorId);
+ }
+ }
+
+ Hops.push_back(ctx.SelfID);
+
+ Become(&TLoadActor::StateFunc);
+ NextMessageTimestamp = ctx.Now();
+ ResetThroughput(NextMessageTimestamp, *Traffic);
+ GenerateMessages(ctx);
+ ctx.Schedule(Params.Duration, new TEvents::TEvPoisonPill);
+ SchedulePublishResults(ctx);
+ }
+
+ void GenerateMessages(const TActorContext& ctx) {
+ while (InFly.size() < Params.InFlyMax && ctx.Now() >= NextMessageTimestamp) {
+ // generate payload
+ const ui32 size = Params.SizeMin + RandomNumber(Params.SizeMax - Params.SizeMin + 1);
+
+ // generate message id
+ const ui64 cookie = NextId++;
+ TString id = Sprintf("%" PRIu64, cookie);
+
+ // create message and send it to the first hop
+ THolder<TEvLoadMessage> ev;
+ if (Params.UseProtobufWithPayload && size) {
+ auto buffer = TRopeAlignedBuffer::Allocate(size);
+ memset(buffer->GetBuffer(), '*', size);
+ ev.Reset(new TEvLoadMessage(Hops, id, TRope(buffer)));
+ } else {
+ TString payload;
+ if (size) {
+ payload = TString::Uninitialized(size);
+ memset(payload.Detach(), '*', size);
+ }
+ ev.Reset(new TEvLoadMessage(Hops, id, payload ? &payload : nullptr));
+ }
+ UpdateThroughput(ev->CalculateSerializedSizeCached());
+ ctx.Send(FirstHop, ev.Release(), IEventHandle::MakeFlags(Params.Channel, 0), cookie);
+
+ // register in the map
+ InFly.emplace(id, TMessageInfo(ctx.Now()));
+
+ // put item into timeout queue
+ PutTimeoutQueueItem(ctx, id);
+
+ const TDuration duration = TDuration::MicroSeconds(Params.IntervalMin.GetValue() +
+ RandomNumber(Params.IntervalMax.GetValue() - Params.IntervalMin.GetValue() + 1));
+ if (Params.SoftLoad) {
+ NextMessageTimestamp += duration;
+ } else {
+ NextMessageTimestamp = ctx.Now() + duration;
+ }
+ }
+
+ // schedule next generate messages call
+ if (NextMessageTimestamp > ctx.Now() && InFly.size() < Params.InFlyMax) {
+ ctx.Schedule(NextMessageTimestamp - ctx.Now(), new TEvGenerateMessages);
+ }
+ }
+
+ void Handle(TEvLoadMessage::TPtr& ev, const TActorContext& ctx) {
+ const auto& record = ev->Get()->Record;
+ auto it = InFly.find(record.GetId());
+ if (it != InFly.end()) {
+ // record message rtt
+ const TDuration rtt = ctx.Now() - it->second.SendTimestamp;
+ UpdateHistogram(ctx.Now(), rtt);
+
+ // update throughput
+ UpdateThroughput(ev->Get()->CalculateSerializedSizeCached());
+
+ // remove message from the in fly map
+ InFly.erase(it);
+ } else {
+ ++NumDropped;
+ }
+ GenerateMessages(ctx);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // RTT HISTOGRAM
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ const TDuration AggregationPeriod = TDuration::Seconds(20);
+ TDeque<std::pair<TInstant, TDuration>> Histogram;
+
+ void UpdateHistogram(TInstant when, TDuration rtt) {
+ Histogram.emplace_back(when, rtt);
+
+ const TInstant barrier = when - AggregationPeriod;
+ while (Histogram && Histogram.front().first < barrier) {
+ Histogram.pop_front();
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // THROUGHPUT
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ TInstant ThroughputFirstSample = TInstant::Zero();
+ ui64 ThroughputSamples = 0;
+ ui64 ThroughputBytes = 0;
+ ui64 TrafficAtBegin = 0;
+
+ void UpdateThroughput(ui64 bytes) {
+ ThroughputBytes += bytes;
+ ++ThroughputSamples;
+ }
+
+ void ResetThroughput(TInstant when, ui64 traffic) {
+ ThroughputFirstSample = when;
+ ThroughputSamples = 0;
+ ThroughputBytes = 0;
+ TrafficAtBegin = traffic;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // TIMEOUT QUEUE OPERATIONS
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ TQueue<std::pair<TInstant, TString>> TimeoutQueue;
+
+ void PutTimeoutQueueItem(const TActorContext& ctx, TString id) {
+ TimeoutQueue.emplace(ctx.Now() + TDuration::Minutes(1), std::move(id));
+ if (TimeoutQueue.size() == 1) {
+ ScheduleWakeup(ctx);
+ }
+ }
+
+ void ScheduleWakeup(const TActorContext& ctx) {
+ ctx.Schedule(TimeoutQueue.front().first - ctx.Now(), new TEvents::TEvWakeup);
+ }
+
+ void HandleWakeup(const TActorContext& ctx) {
+ ui32 numDropped = 0;
+
+ while (TimeoutQueue && TimeoutQueue.front().first <= ctx.Now()) {
+ numDropped += InFly.erase(TimeoutQueue.front().second);
+ TimeoutQueue.pop();
+ }
+ if (TimeoutQueue) {
+ // we still have some elements in timeout queue, so schedule next wake up to tidy up
+ ScheduleWakeup(ctx);
+ }
+
+ GenerateMessages(ctx);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // RESULT PUBLISHING
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ const TDuration ResultPublishPeriod = TDuration::Seconds(15);
+
+ void SchedulePublishResults(const TActorContext& ctx) {
+ ctx.Schedule(ResultPublishPeriod, new TEvPublishResults);
+ }
+
+ void PublishResults(const TActorContext& ctx, bool schedule = true) {
+ const TInstant now = ctx.Now();
+
+ TStringStream msg;
+
+ msg << "Load# '" << Params.Name << "'";
+
+ msg << " Throughput# ";
+ const TDuration duration = now - ThroughputFirstSample;
+ const ui64 traffic = *Traffic;
+ msg << "{window# " << duration
+ << " bytes# " << ThroughputBytes
+ << " samples# " << ThroughputSamples
+ << " b/s# " << ui64(ThroughputBytes * 1000000 / duration.MicroSeconds())
+ << " common# " << ui64((traffic - TrafficAtBegin) * 1000000 / duration.MicroSeconds())
+ << "}";
+ ResetThroughput(now, traffic);
+
+ msg << " RTT# ";
+ if (Histogram) {
+ const TDuration duration = Histogram.back().first - Histogram.front().first;
+ msg << "{window# " << duration << " samples# " << Histogram.size();
+ TVector<TDuration> v;
+ v.reserve(Histogram.size());
+ for (const auto& item : Histogram) {
+ v.push_back(item.second);
+ }
+ std::sort(v.begin(), v.end());
+ for (double q : {0.5, 0.9, 0.99, 0.999, 0.9999, 1.0}) {
+ const size_t pos = q * (v.size() - 1);
+ msg << Sprintf(" %.4f# %s", q, v[pos].ToString().data());
+ }
+ msg << "}";
+ } else {
+ msg << "<empty>";
+ }
+
+ msg << " NumDropped# " << NumDropped;
+
+ if (!schedule) {
+ msg << " final";
+ }
+
+ LOG_NOTICE(ctx, NActorsServices::INTERCONNECT_SPEED_TEST, "%s", msg.Str().data());
+
+ if (schedule) {
+ SchedulePublishResults(ctx);
+ }
+ }
+
+ STRICT_STFUNC(QueryTrafficCounter,
+ HFunc(TEvTrafficCounter, Handle);
+ )
+
+ STRICT_STFUNC(StateFunc,
+ CFunc(TEvents::TSystem::PoisonPill, Die);
+ CFunc(TEvents::TSystem::Wakeup, HandleWakeup);
+ CFunc(EvPublishResults, PublishResults);
+ CFunc(EvGenerateMessages, GenerateMessages);
+ HFunc(TEvLoadMessage, Handle);
+ )
+
+ void Die(const TActorContext& ctx) override {
+ PublishResults(ctx, false);
+ TActorBootstrapped::Die(ctx);
+ }
+ };
+
+ IActor* CreateLoadActor(const TLoadParams& params) {
+ return new TLoadActor(params);
+ }
+
+}
diff --git a/library/cpp/actors/interconnect/load.h b/library/cpp/actors/interconnect/load.h
new file mode 100644
index 0000000000..0a01a0dc04
--- /dev/null
+++ b/library/cpp/actors/interconnect/load.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <library/cpp/actors/core/actor.h>
+
+namespace NInterconnect {
+ // load responder -- lives on every node as a service actor
+ NActors::IActor* CreateLoadResponderActor();
+ NActors::TActorId MakeLoadResponderActorId(ui32 node);
+
+ // load actor -- generates load with specific parameters
+ struct TLoadParams {
+ TString Name;
+ ui32 Channel;
+ TVector<ui32> NodeHops; // node ids for the message route
+ ui32 SizeMin, SizeMax; // min and max size for payloads
+ ui32 InFlyMax; // maximum number of in fly messages
+ TDuration IntervalMin, IntervalMax; // min and max intervals between sending messages
+ bool SoftLoad; // is the load soft?
+ TDuration Duration; // test duration
+ bool UseProtobufWithPayload; // store payload separately
+ };
+ NActors::IActor* CreateLoadActor(const TLoadParams& params);
+
+}
diff --git a/library/cpp/actors/interconnect/logging.h b/library/cpp/actors/interconnect/logging.h
new file mode 100644
index 0000000000..c429d1cade
--- /dev/null
+++ b/library/cpp/actors/interconnect/logging.h
@@ -0,0 +1,68 @@
+#pragma once
+
+#include <library/cpp/actors/core/log.h>
+#include <library/cpp/actors/protos/services_common.pb.h>
+
+#define LOG_LOG_IC_X(component, marker, priority, ...) \
+ do { \
+ LOG_LOG(this->GetActorContext(), (priority), (component), "%s " marker " %s", LogPrefix.data(), Sprintf(__VA_ARGS__).data()); \
+ } while (false)
+
+#define LOG_LOG_NET_X(priority, NODE_ID, FMT, ...) \
+ do { \
+ const TActorContext& ctx = this->GetActorContext(); \
+ LOG_LOG(ctx, (priority), ::NActorsServices::INTERCONNECT_NETWORK, "[%" PRIu32 " <-> %" PRIu32 "] %s", \
+ ctx.SelfID.NodeId(), (NODE_ID), Sprintf(FMT, __VA_ARGS__).data()); \
+ } while (false)
+
+#define LOG_LOG_IC(component, marker, priority, ...) \
+ do { \
+ LOG_LOG(::NActors::TActivationContext::AsActorContext(), (priority), (component), "%s " marker " %s", LogPrefix.data(), Sprintf(__VA_ARGS__).data()); \
+ } while (false)
+
+#define LOG_LOG_NET(priority, NODE_ID, FMT, ...) \
+ do { \
+ const TActorContext& ctx = ::NActors::TActivationContext::AsActorContext(); \
+ LOG_LOG(ctx, (priority), ::NActorsServices::INTERCONNECT_NETWORK, "[%" PRIu32 " <-> %" PRIu32 "] %s", \
+ ctx.SelfID.NodeId(), (NODE_ID), Sprintf(FMT, __VA_ARGS__).data()); \
+ } while (false)
+
+#define LOG_EMER_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_EMER, __VA_ARGS__)
+#define LOG_ALERT_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_ALERT, __VA_ARGS__)
+#define LOG_CRIT_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_CRIT, __VA_ARGS__)
+#define LOG_ERROR_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_ERROR, __VA_ARGS__)
+#define LOG_WARN_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_WARN, __VA_ARGS__)
+#define LOG_NOTICE_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_NOTICE, __VA_ARGS__)
+#define LOG_INFO_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_INFO, __VA_ARGS__)
+#define LOG_DEBUG_IC(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT, marker, ::NActors::NLog::PRI_DEBUG, __VA_ARGS__)
+
+#define LOG_EMER_IC_SESSION(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT_SESSION, marker, ::NActors::NLog::PRI_EMER, __VA_ARGS__)
+#define LOG_ALERT_IC_SESSION(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT_SESSION, marker, ::NActors::NLog::PRI_ALERT, __VA_ARGS__)
+#define LOG_CRIT_IC_SESSION(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT_SESSION, marker, ::NActors::NLog::PRI_CRIT, __VA_ARGS__)
+#define LOG_ERROR_IC_SESSION(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT_SESSION, marker, ::NActors::NLog::PRI_ERROR, __VA_ARGS__)
+#define LOG_WARN_IC_SESSION(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT_SESSION, marker, ::NActors::NLog::PRI_WARN, __VA_ARGS__)
+#define LOG_NOTICE_IC_SESSION(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT_SESSION, marker, ::NActors::NLog::PRI_NOTICE, __VA_ARGS__)
+#define LOG_INFO_IC_SESSION(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT_SESSION, marker, ::NActors::NLog::PRI_INFO, __VA_ARGS__)
+#define LOG_DEBUG_IC_SESSION(marker, ...) LOG_LOG_IC(::NActorsServices::INTERCONNECT_SESSION, marker, ::NActors::NLog::PRI_DEBUG, __VA_ARGS__)
+
+#define LOG_NOTICE_NET(NODE_ID, FMT, ...) LOG_LOG_NET(::NActors::NLog::PRI_NOTICE, NODE_ID, FMT, __VA_ARGS__)
+#define LOG_DEBUG_NET(NODE_ID, FMT, ...) LOG_LOG_NET(::NActors::NLog::PRI_DEBUG, NODE_ID, FMT, __VA_ARGS__)
+
+namespace NActors {
+ class TInterconnectLoggingBase {
+ protected:
+ const TString LogPrefix;
+
+ public:
+ TInterconnectLoggingBase() = default;
+
+ TInterconnectLoggingBase(const TString& prefix)
+ : LogPrefix(prefix)
+ {
+ }
+
+ void SetPrefix(TString logPrefix) const {
+ logPrefix.swap(const_cast<TString&>(LogPrefix));
+ }
+ };
+}
diff --git a/library/cpp/actors/interconnect/mock/ic_mock.cpp b/library/cpp/actors/interconnect/mock/ic_mock.cpp
new file mode 100644
index 0000000000..884503e602
--- /dev/null
+++ b/library/cpp/actors/interconnect/mock/ic_mock.cpp
@@ -0,0 +1,298 @@
+#include "ic_mock.h"
+#include <library/cpp/actors/core/interconnect.h>
+#include <util/system/yield.h>
+#include <thread>
+
+namespace NActors {
+
+ class TInterconnectMock::TImpl {
+ enum {
+ EvInject = EventSpaceBegin(TEvents::ES_PRIVATE),
+ EvCheckSession,
+ EvRam,
+ };
+
+ struct TEvInject : TEventLocal<TEvInject, EvInject> {
+ std::deque<std::unique_ptr<IEventHandle>> Messages;
+ const TScopeId OriginScopeId;
+ const ui64 SenderSessionId;
+
+ TEvInject(std::deque<std::unique_ptr<IEventHandle>>&& messages, const TScopeId& originScopeId, ui64 senderSessionId)
+ : Messages(std::move(messages))
+ , OriginScopeId(originScopeId)
+ , SenderSessionId(senderSessionId)
+ {}
+ };
+
+ class TProxyMockActor;
+
+ class TConnectionState {
+ struct TPeerInfo {
+ TRWMutex Mutex;
+ TActorSystem *ActorSystem = nullptr;
+ TActorId ProxyId;
+ };
+
+ const ui64 Key;
+ TPeerInfo PeerInfo[2];
+ std::atomic_uint64_t SessionId = 0;
+
+ public:
+ TConnectionState(ui64 key)
+ : Key(key)
+ {}
+
+ void Attach(ui32 nodeId, TActorSystem *as, const TActorId& actorId) {
+ TPeerInfo *peer = GetPeer(nodeId);
+ auto guard = TWriteGuard(peer->Mutex);
+ Y_VERIFY(!peer->ActorSystem);
+ peer->ActorSystem = as;
+ peer->ProxyId = actorId;
+ as->DeferPreStop([peer] {
+ auto guard = TWriteGuard(peer->Mutex);
+ peer->ActorSystem = nullptr;
+ });
+ }
+
+ void Inject(ui32 peerNodeId, std::deque<std::unique_ptr<IEventHandle>>&& messages,
+ const TScopeId& originScopeId, ui64 senderSessionId) {
+ TPeerInfo *peer = GetPeer(peerNodeId);
+ auto guard = TReadGuard(peer->Mutex);
+ if (peer->ActorSystem) {
+ peer->ActorSystem->Send(new IEventHandle(peer->ProxyId, TActorId(), new TEvInject(std::move(messages),
+ originScopeId, senderSessionId)));
+ } else {
+ for (auto&& ev : messages) {
+ TActivationContext::Send(ev->ForwardOnNondelivery(TEvents::TEvUndelivered::Disconnected));
+ }
+ }
+ }
+
+ ui64 GetValidSessionId() const {
+ return SessionId;
+ }
+
+ void InvalidateSessionId(ui32 peerNodeId) {
+ ++SessionId;
+ TPeerInfo *peer = GetPeer(peerNodeId);
+ auto guard = TReadGuard(peer->Mutex);
+ if (peer->ActorSystem) {
+ peer->ActorSystem->Send(new IEventHandle(EvCheckSession, 0, peer->ProxyId, {}, nullptr, 0));
+ }
+ }
+
+ private:
+ TPeerInfo *GetPeer(ui32 nodeId) {
+ if (nodeId == ui32(Key)) {
+ return PeerInfo;
+ } else if (nodeId == ui32(Key >> 32)) {
+ return PeerInfo + 1;
+ } else {
+ Y_FAIL();
+ }
+ }
+ };
+
+ class TProxyMockActor : public TActor<TProxyMockActor> {
+ class TSessionMockActor : public TActor<TSessionMockActor> {
+ std::map<TActorId, ui64> Subscribers;
+ TProxyMockActor* const Proxy;
+ std::deque<std::unique_ptr<IEventHandle>> Queue;
+
+ public:
+ const ui64 SessionId;
+
+ public:
+ TSessionMockActor(TProxyMockActor *proxy, ui64 sessionId)
+ : TActor(&TThis::StateFunc)
+ , Proxy(proxy)
+ , SessionId(sessionId)
+ {}
+
+ void Terminate() {
+ for (auto&& ev : std::exchange(Queue, {})) {
+ TActivationContext::Send(ev->ForwardOnNondelivery(TEvents::TEvUndelivered::Disconnected));
+ }
+ for (const auto& kv : Subscribers) {
+ Send(kv.first, new TEvInterconnect::TEvNodeDisconnected(Proxy->PeerNodeId), 0, kv.second);
+ }
+ Y_VERIFY(Proxy->Session == this);
+ Proxy->Session = nullptr;
+ PassAway();
+ }
+
+ void HandleForward(TAutoPtr<IEventHandle> ev) {
+ if (ev->Flags & IEventHandle::FlagSubscribeOnSession) {
+ Subscribe(ev->Sender, ev->Cookie);
+ }
+ if (Queue.empty()) {
+ TActivationContext::Send(new IEventHandle(EvRam, 0, SelfId(), {}, {}, 0));
+ }
+ Queue.emplace_back(ev.Release());
+ }
+
+ void HandleRam() {
+ if (SessionId != Proxy->State.GetValidSessionId()) {
+ Terminate();
+ } else {
+ Proxy->PeerInject(std::exchange(Queue, {}));
+ }
+ }
+
+ void Handle(TEvInterconnect::TEvConnectNode::TPtr ev) {
+ Subscribe(ev->Sender, ev->Cookie);
+ }
+
+ void Handle(TEvents::TEvSubscribe::TPtr ev) {
+ Subscribe(ev->Sender, ev->Cookie);
+ }
+
+ void Handle(TEvents::TEvUnsubscribe::TPtr ev) {
+ Subscribers.erase(ev->Sender);
+ }
+
+ void HandlePoison() {
+ Proxy->Disconnect();
+ }
+
+ STRICT_STFUNC(StateFunc,
+ fFunc(TEvInterconnect::EvForward, HandleForward)
+ hFunc(TEvInterconnect::TEvConnectNode, Handle)
+ hFunc(TEvents::TEvSubscribe, Handle)
+ hFunc(TEvents::TEvUnsubscribe, Handle)
+ cFunc(TEvents::TSystem::Poison, HandlePoison)
+ cFunc(EvRam, HandleRam)
+ )
+
+ private:
+ void Subscribe(const TActorId& actorId, ui64 cookie) {
+ Subscribers[actorId] = cookie;
+ Send(actorId, new TEvInterconnect::TEvNodeConnected(Proxy->PeerNodeId), 0, cookie);
+ }
+ };
+
+ friend class TSessionMockActor;
+
+ const ui32 NodeId;
+ const ui32 PeerNodeId;
+ TConnectionState& State;
+ const TInterconnectProxyCommon::TPtr Common;
+ TSessionMockActor *Session = nullptr;
+
+ public:
+ TProxyMockActor(ui32 nodeId, ui32 peerNodeId, TConnectionState& state, TInterconnectProxyCommon::TPtr common)
+ : TActor(&TThis::StateFunc)
+ , NodeId(nodeId)
+ , PeerNodeId(peerNodeId)
+ , State(state)
+ , Common(std::move(common))
+ {}
+
+ void Registered(TActorSystem *as, const TActorId& parent) override {
+ TActor::Registered(as, parent);
+ State.Attach(NodeId, as, SelfId());
+ }
+
+ void Handle(TEvInject::TPtr ev) {
+ auto *msg = ev->Get();
+ if (Session && Session->SessionId != msg->SenderSessionId) {
+ return; // drop messages from other sessions
+ }
+ if (auto *session = GetSession()) {
+ for (auto&& ev : ev->Get()->Messages) {
+ auto fw = std::make_unique<IEventHandle>(
+ session->SelfId(),
+ ev->Type,
+ ev->Flags & ~IEventHandle::FlagForwardOnNondelivery,
+ ev->Recipient,
+ ev->Sender,
+ ev->ReleaseChainBuffer(),
+ ev->Cookie,
+ msg->OriginScopeId,
+ std::move(ev->TraceId)
+ );
+ if (!Common->EventFilter || Common->EventFilter->CheckIncomingEvent(*fw, Common->LocalScopeId)) {
+ TActivationContext::Send(fw.release());
+ }
+ }
+ }
+ }
+
+ void PassAway() override {
+ Disconnect();
+ TActor::PassAway();
+ }
+
+ TSessionMockActor *GetSession() {
+ CheckSession();
+ if (!Session) {
+ Session = new TSessionMockActor(this, State.GetValidSessionId());
+ RegisterWithSameMailbox(Session);
+ }
+ return Session;
+ }
+
+ void HandleSessionEvent(TAutoPtr<IEventHandle> ev) {
+ auto *session = GetSession();
+ InvokeOtherActor(*session, &TSessionMockActor::Receive, ev,
+ TActivationContext::ActorContextFor(session->SelfId()));
+ }
+
+ void Disconnect() {
+ State.InvalidateSessionId(PeerNodeId);
+ if (Session) {
+ Session->Terminate();
+ }
+ }
+
+ void CheckSession() {
+ if (Session && Session->SessionId != State.GetValidSessionId()) {
+ Session->Terminate();
+ }
+ }
+
+ void PeerInject(std::deque<std::unique_ptr<IEventHandle>>&& messages) {
+ Y_VERIFY(Session);
+ return State.Inject(PeerNodeId, std::move(messages), Common->LocalScopeId, Session->SessionId);
+ }
+
+ STRICT_STFUNC(StateFunc,
+ cFunc(TEvents::TSystem::Poison, PassAway)
+ fFunc(TEvInterconnect::EvForward, HandleSessionEvent)
+ fFunc(TEvInterconnect::EvConnectNode, HandleSessionEvent)
+ fFunc(TEvents::TSystem::Subscribe, HandleSessionEvent)
+ fFunc(TEvents::TSystem::Unsubscribe, HandleSessionEvent)
+ cFunc(TEvInterconnect::EvDisconnect, Disconnect)
+ IgnoreFunc(TEvInterconnect::TEvClosePeerSocket)
+ IgnoreFunc(TEvInterconnect::TEvCloseInputSession)
+ cFunc(TEvInterconnect::EvPoisonSession, Disconnect)
+ hFunc(TEvInject, Handle)
+ cFunc(EvCheckSession, CheckSession)
+ )
+ };
+
+ std::unordered_map<ui64, TConnectionState> States;
+
+ public:
+ IActor *CreateProxyMock(ui32 nodeId, ui32 peerNodeId, TInterconnectProxyCommon::TPtr common) {
+ Y_VERIFY(nodeId != peerNodeId);
+ Y_VERIFY(nodeId);
+ Y_VERIFY(peerNodeId);
+ const ui64 key = std::min(nodeId, peerNodeId) | ui64(std::max(nodeId, peerNodeId)) << 32;
+ auto it = States.try_emplace(key, key).first;
+ return new TProxyMockActor(nodeId, peerNodeId, it->second, std::move(common));
+ }
+ };
+
+ TInterconnectMock::TInterconnectMock()
+ : Impl(std::make_unique<TImpl>())
+ {}
+
+ TInterconnectMock::~TInterconnectMock()
+ {}
+
+ IActor *TInterconnectMock::CreateProxyMock(ui32 nodeId, ui32 peerNodeId, TInterconnectProxyCommon::TPtr common) {
+ return Impl->CreateProxyMock(nodeId, peerNodeId, std::move(common));
+ }
+
+} // NActors
diff --git a/library/cpp/actors/interconnect/mock/ic_mock.h b/library/cpp/actors/interconnect/mock/ic_mock.h
new file mode 100644
index 0000000000..636bdc2b7f
--- /dev/null
+++ b/library/cpp/actors/interconnect/mock/ic_mock.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <library/cpp/actors/core/actor.h>
+
+#include <library/cpp/actors/interconnect/interconnect_common.h>
+
+namespace NActors {
+
+ class TInterconnectMock {
+ class TImpl;
+ std::unique_ptr<TImpl> Impl;
+
+ public:
+ TInterconnectMock();
+ ~TInterconnectMock();
+ IActor *CreateProxyMock(ui32 nodeId, ui32 peerNodeId, TInterconnectProxyCommon::TPtr common);
+ };
+
+} // NActors
diff --git a/library/cpp/actors/interconnect/mock/tsan.supp b/library/cpp/actors/interconnect/mock/tsan.supp
new file mode 100644
index 0000000000..19fd059419
--- /dev/null
+++ b/library/cpp/actors/interconnect/mock/tsan.supp
@@ -0,0 +1 @@
+deadlock:Attach
diff --git a/library/cpp/actors/interconnect/mock/ya.make b/library/cpp/actors/interconnect/mock/ya.make
new file mode 100644
index 0000000000..19a2834162
--- /dev/null
+++ b/library/cpp/actors/interconnect/mock/ya.make
@@ -0,0 +1,16 @@
+LIBRARY()
+
+OWNER(alexvru)
+
+SRCS(
+ ic_mock.cpp
+ ic_mock.h
+)
+
+SUPPRESSIONS(tsan.supp)
+
+PEERDIR(
+ library/cpp/actors/interconnect
+)
+
+END()
diff --git a/library/cpp/actors/interconnect/packet.cpp b/library/cpp/actors/interconnect/packet.cpp
new file mode 100644
index 0000000000..e2c289ed59
--- /dev/null
+++ b/library/cpp/actors/interconnect/packet.cpp
@@ -0,0 +1,32 @@
+#include "packet.h"
+
+#include <library/cpp/actors/core/probes.h>
+
+#include <util/system/datetime.h>
+
+LWTRACE_USING(ACTORLIB_PROVIDER);
+
+ui32 TEventHolder::Fill(IEventHandle& ev) {
+ Serial = 0;
+ Descr.Type = ev.Type;
+ Descr.Flags = ev.Flags;
+ Descr.Recipient = ev.Recipient;
+ Descr.Sender = ev.Sender;
+ Descr.Cookie = ev.Cookie;
+ ev.TraceId.Serialize(&Descr.TraceId);
+ ForwardRecipient = ev.GetForwardOnNondeliveryRecipient();
+ EventActuallySerialized = 0;
+ Descr.Checksum = 0;
+
+ if (ev.HasBuffer()) {
+ Buffer = ev.ReleaseChainBuffer();
+ EventSerializedSize = Buffer->GetSize();
+ } else if (ev.HasEvent()) {
+ Event.Reset(ev.ReleaseBase());
+ EventSerializedSize = Event->CalculateSerializedSize();
+ } else {
+ EventSerializedSize = 0;
+ }
+
+ return EventSerializedSize;
+}
diff --git a/library/cpp/actors/interconnect/packet.h b/library/cpp/actors/interconnect/packet.h
new file mode 100644
index 0000000000..4ba50a2b5f
--- /dev/null
+++ b/library/cpp/actors/interconnect/packet.h
@@ -0,0 +1,324 @@
+#pragma once
+
+#include <library/cpp/actors/core/event_pb.h>
+#include <library/cpp/actors/core/event_load.h>
+#include <library/cpp/actors/core/events.h>
+#include <library/cpp/actors/core/actor.h>
+#include <library/cpp/containers/stack_vector/stack_vec.h>
+#include <library/cpp/actors/util/rope.h>
+#include <library/cpp/actors/prof/tag.h>
+#include <library/cpp/digest/crc32c/crc32c.h>
+#include <library/cpp/lwtrace/shuttle.h>
+#include <util/generic/string.h>
+#include <util/generic/list.h>
+
+#ifndef FORCE_EVENT_CHECKSUM
+#define FORCE_EVENT_CHECKSUM 0
+#endif
+
+using NActors::IEventBase;
+using NActors::IEventHandle;
+using NActors::TActorId;
+using NActors::TConstIoVec;
+using NActors::TEventSerializedData;
+
+Y_FORCE_INLINE ui32 Crc32cExtendMSanCompatible(ui32 checksum, const void *data, size_t len) {
+ if constexpr (NSan::MSanIsOn()) {
+ const char *begin = static_cast<const char*>(data);
+ const char *end = begin + len;
+ begin -= reinterpret_cast<uintptr_t>(begin) & 15;
+ end += -reinterpret_cast<uintptr_t>(end) & 15;
+ NSan::Unpoison(begin, end - begin);
+ }
+ return Crc32cExtend(checksum, data, len);
+}
+
+struct TSessionParams {
+ bool Encryption = {};
+ bool UseModernFrame = {};
+ bool AuthOnly = {};
+ TString AuthCN;
+ NActors::TScopeId PeerScopeId;
+};
+
+struct TTcpPacketHeader_v1 {
+ ui32 HeaderCRC32;
+ ui32 PayloadCRC32;
+ ui64 Confirm;
+ ui64 Serial;
+ ui64 DataSize;
+
+ inline bool Check() const {
+ ui32 actual = Crc32cExtendMSanCompatible(0, &PayloadCRC32, sizeof(TTcpPacketHeader_v1) - sizeof(HeaderCRC32));
+ return actual == HeaderCRC32;
+ }
+
+ inline void Sign() {
+ HeaderCRC32 = Crc32cExtendMSanCompatible(0, &PayloadCRC32, sizeof(TTcpPacketHeader_v1) - sizeof(HeaderCRC32));
+ }
+
+ TString ToString() const {
+ return Sprintf("{Confirm# %" PRIu64 " Serial# %" PRIu64 " DataSize# %" PRIu64 "}", Confirm, Serial, DataSize);
+ }
+};
+
+#pragma pack(push, 1)
+struct TTcpPacketHeader_v2 {
+ ui64 Confirm;
+ ui64 Serial;
+ ui32 Checksum; // for the whole frame
+ ui16 PayloadLength;
+};
+#pragma pack(pop)
+
+union TTcpPacketBuf {
+ static constexpr ui64 PingRequestMask = 0x8000000000000000ULL;
+ static constexpr ui64 PingResponseMask = 0x4000000000000000ULL;
+ static constexpr ui64 ClockMask = 0x2000000000000000ULL;
+
+ static constexpr size_t PacketDataLen = 4096 * 2 - 96 - Max(sizeof(TTcpPacketHeader_v1), sizeof(TTcpPacketHeader_v2));
+ struct {
+ TTcpPacketHeader_v1 Header;
+ char Data[PacketDataLen];
+ } v1;
+ struct {
+ TTcpPacketHeader_v2 Header;
+ char Data[PacketDataLen];
+ } v2;
+};
+
+#pragma pack(push, 1)
+struct TEventDescr {
+ ui32 Type;
+ ui32 Flags;
+ TActorId Recipient;
+ TActorId Sender;
+ ui64 Cookie;
+ // wilson trace id is stored as a serialized entity to avoid using complex object with prohibited copy ctor
+ NWilson::TTraceId::TSerializedTraceId TraceId;
+ ui32 Checksum;
+};
+#pragma pack(pop)
+
+struct TEventHolder : TNonCopyable {
+ TEventDescr Descr;
+ TActorId ForwardRecipient;
+ THolder<IEventBase> Event;
+ TIntrusivePtr<TEventSerializedData> Buffer;
+ ui64 Serial;
+ ui32 EventSerializedSize;
+ ui32 EventActuallySerialized;
+ mutable NLWTrace::TOrbit Orbit;
+
+ ui32 Fill(IEventHandle& ev);
+
+ void InitChecksum() {
+ Descr.Checksum = 0;
+ }
+
+ void UpdateChecksum(const TSessionParams& params, const void *buffer, size_t len) {
+ if (FORCE_EVENT_CHECKSUM || !params.UseModernFrame) {
+ Descr.Checksum = Crc32cExtendMSanCompatible(Descr.Checksum, buffer, len);
+ }
+ }
+
+ void ForwardOnNondelivery(bool unsure) {
+ TEventDescr& d = Descr;
+ const TActorId& r = d.Recipient;
+ const TActorId& s = d.Sender;
+ const TActorId *f = ForwardRecipient ? &ForwardRecipient : nullptr;
+ auto ev = Event
+ ? std::make_unique<IEventHandle>(r, s, Event.Release(), d.Flags, d.Cookie, f, NWilson::TTraceId(d.TraceId))
+ : std::make_unique<IEventHandle>(d.Type, d.Flags, r, s, std::move(Buffer), d.Cookie, f, NWilson::TTraceId(d.TraceId));
+ NActors::TActivationContext::Send(ev->ForwardOnNondelivery(NActors::TEvents::TEvUndelivered::Disconnected, unsure));
+ }
+
+ void Clear() {
+ Event.Reset();
+ Buffer.Reset();
+ Orbit.Reset();
+ }
+};
+
+namespace NActors {
+ class TEventOutputChannel;
+}
+
+struct TTcpPacketOutTask : TNonCopyable {
+ const TSessionParams& Params;
+ TTcpPacketBuf Packet;
+ size_t DataSize;
+ TStackVec<TConstIoVec, 32> Bufs;
+ size_t BufferIndex;
+ size_t FirstBufferOffset;
+ bool TriedWriting;
+ char *FreeArea;
+ char *End;
+ mutable NLWTrace::TOrbit Orbit;
+
+public:
+ TTcpPacketOutTask(const TSessionParams& params)
+ : Params(params)
+ {
+ Reuse();
+ }
+
+ template<typename T>
+ auto ApplyToHeader(T&& callback) {
+ return Params.UseModernFrame ? callback(Packet.v2.Header) : callback(Packet.v1.Header);
+ }
+
+ template<typename T>
+ auto ApplyToHeader(T&& callback) const {
+ return Params.UseModernFrame ? callback(Packet.v2.Header) : callback(Packet.v1.Header);
+ }
+
+ bool IsAtBegin() const {
+ return !BufferIndex && !FirstBufferOffset && !TriedWriting;
+ }
+
+ void MarkTriedWriting() {
+ TriedWriting = true;
+ }
+
+ void Reuse() {
+ DataSize = 0;
+ ApplyToHeader([this](auto& header) { Bufs.assign(1, {&header, sizeof(header)}); });
+ BufferIndex = 0;
+ FirstBufferOffset = 0;
+ TriedWriting = false;
+ FreeArea = Params.UseModernFrame ? Packet.v2.Data : Packet.v1.Data;
+ End = FreeArea + TTcpPacketBuf::PacketDataLen;
+ Orbit.Reset();
+ }
+
+ bool IsEmpty() const {
+ return !DataSize;
+ }
+
+ void SetMetadata(ui64 serial, ui64 confirm) {
+ ApplyToHeader([&](auto& header) {
+ header.Serial = serial;
+ header.Confirm = confirm;
+ });
+ }
+
+ void UpdateConfirmIfPossible(ui64 confirm) {
+ // we don't want to recalculate whole packet checksum for single confirmation update on v2
+ if (!Params.UseModernFrame && IsAtBegin() && confirm != Packet.v1.Header.Confirm) {
+ Packet.v1.Header.Confirm = confirm;
+ Packet.v1.Header.Sign();
+ }
+ }
+
+ size_t GetDataSize() const { return DataSize; }
+
+ ui64 GetSerial() const {
+ return ApplyToHeader([](auto& header) { return header.Serial; });
+ }
+
+ bool Confirmed(ui64 confirm) const {
+ return ApplyToHeader([&](auto& header) { return IsEmpty() || header.Serial <= confirm; });
+ }
+
+ void *GetFreeArea() {
+ return FreeArea;
+ }
+
+ size_t GetVirtualFreeAmount() const {
+ return TTcpPacketBuf::PacketDataLen - DataSize;
+ }
+
+ void AppendBuf(const void *buf, size_t size) {
+ DataSize += size;
+ Y_VERIFY_DEBUG(DataSize <= TTcpPacketBuf::PacketDataLen, "DataSize# %zu AppendBuf buf# %p size# %zu"
+ " FreeArea# %p End# %p", DataSize, buf, size, FreeArea, End);
+
+ if (Bufs && static_cast<const char*>(Bufs.back().Data) + Bufs.back().Size == buf) {
+ Bufs.back().Size += size;
+ } else {
+ Bufs.push_back({buf, size});
+ }
+
+ if (buf >= FreeArea && buf < End) {
+ Y_VERIFY_DEBUG(buf == FreeArea);
+ FreeArea = const_cast<char*>(static_cast<const char*>(buf)) + size;
+ Y_VERIFY_DEBUG(FreeArea <= End);
+ }
+ }
+
+ void Undo(size_t size) {
+ Y_VERIFY(Bufs);
+ auto& buf = Bufs.back();
+ Y_VERIFY(buf.Data == FreeArea - buf.Size);
+ buf.Size -= size;
+ if (!buf.Size) {
+ Bufs.pop_back();
+ }
+ FreeArea -= size;
+ DataSize -= size;
+ }
+
+ bool DropBufs(size_t& amount) {
+ while (BufferIndex != Bufs.size()) {
+ TConstIoVec& item = Bufs[BufferIndex];
+ // calculate number of bytes to the end in current buffer
+ const size_t remain = item.Size - FirstBufferOffset;
+ if (amount >= remain) {
+ // vector item completely fits into the received amount, drop it out and switch to next buffer
+ amount -= remain;
+ ++BufferIndex;
+ FirstBufferOffset = 0;
+ } else {
+ // adjust first buffer by "amount" bytes forward and reset amount to zero
+ FirstBufferOffset += amount;
+ amount = 0;
+ // return false meaning that we have some more data to send
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void ResetBufs() {
+ BufferIndex = FirstBufferOffset = 0;
+ TriedWriting = false;
+ }
+
+ template <typename TVectorType>
+ void AppendToIoVector(TVectorType& vector, size_t max) {
+ for (size_t k = BufferIndex, offset = FirstBufferOffset; k != Bufs.size() && vector.size() < max; ++k, offset = 0) {
+ TConstIoVec v = Bufs[k];
+ v.Data = static_cast<const char*>(v.Data) + offset;
+ v.Size -= offset;
+ vector.push_back(v);
+ }
+ }
+
+ void Sign() {
+ if (Params.UseModernFrame) {
+ Packet.v2.Header.Checksum = 0;
+ Packet.v2.Header.PayloadLength = DataSize;
+ if (!Params.Encryption) {
+ ui32 sum = 0;
+ for (const auto& item : Bufs) {
+ sum = Crc32cExtendMSanCompatible(sum, item.Data, item.Size);
+ }
+ Packet.v2.Header.Checksum = sum;
+ }
+ } else {
+ Y_VERIFY(!Bufs.empty());
+ auto it = Bufs.begin();
+ static constexpr size_t headerLen = sizeof(TTcpPacketHeader_v1);
+ Y_VERIFY(it->Data == &Packet.v1.Header && it->Size >= headerLen);
+ ui32 sum = Crc32cExtendMSanCompatible(0, Packet.v1.Data, it->Size - headerLen);
+ while (++it != Bufs.end()) {
+ sum = Crc32cExtendMSanCompatible(sum, it->Data, it->Size);
+ }
+
+ Packet.v1.Header.PayloadCRC32 = sum;
+ Packet.v1.Header.DataSize = DataSize;
+ Packet.v1.Header.Sign();
+ }
+ }
+};
diff --git a/library/cpp/actors/interconnect/poller.h b/library/cpp/actors/interconnect/poller.h
new file mode 100644
index 0000000000..ff7979369f
--- /dev/null
+++ b/library/cpp/actors/interconnect/poller.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <functional>
+#include <library/cpp/actors/core/events.h>
+
+namespace NActors {
+ class TSharedDescriptor: public TThrRefBase {
+ public:
+ virtual int GetDescriptor() = 0;
+ };
+
+ using TDelegate = std::function<void()>;
+ using TFDDelegate = std::function<TDelegate(const TIntrusivePtr<TSharedDescriptor>&)>;
+
+ class IPoller: public TThrRefBase {
+ public:
+ virtual ~IPoller() = default;
+
+ virtual void StartRead(const TIntrusivePtr<TSharedDescriptor>& s, TFDDelegate&& operation) = 0;
+ virtual void StartWrite(const TIntrusivePtr<TSharedDescriptor>& s, TFDDelegate&& operation) = 0;
+ };
+
+}
diff --git a/library/cpp/actors/interconnect/poller_actor.cpp b/library/cpp/actors/interconnect/poller_actor.cpp
new file mode 100644
index 0000000000..e75cbcaef4
--- /dev/null
+++ b/library/cpp/actors/interconnect/poller_actor.cpp
@@ -0,0 +1,294 @@
+#include "poller_actor.h"
+#include "interconnect_common.h"
+
+#include <library/cpp/actors/core/actor_bootstrapped.h>
+#include <library/cpp/actors/core/actorsystem.h>
+#include <library/cpp/actors/core/hfunc.h>
+#include <library/cpp/actors/core/log.h>
+#include <library/cpp/actors/core/probes.h>
+#include <library/cpp/actors/protos/services_common.pb.h>
+#include <library/cpp/actors/util/funnel_queue.h>
+
+#include <util/generic/intrlist.h>
+#include <util/system/thread.h>
+#include <util/system/event.h>
+#include <util/system/pipe.h>
+
+#include <variant>
+
+namespace NActors {
+
+ LWTRACE_USING(ACTORLIB_PROVIDER);
+
+ namespace {
+ int LastSocketError() {
+#if defined(_win_)
+ return WSAGetLastError();
+#else
+ return errno;
+#endif
+ }
+ }
+
+ struct TSocketRecord : TThrRefBase {
+ const TIntrusivePtr<TSharedDescriptor> Socket;
+ const TActorId ReadActorId;
+ const TActorId WriteActorId;
+ std::atomic_uint32_t Flags = 0;
+
+ TSocketRecord(TEvPollerRegister& ev)
+ : Socket(std::move(ev.Socket))
+ , ReadActorId(ev.ReadActorId)
+ , WriteActorId(ev.WriteActorId)
+ {}
+ };
+
+ template<typename TDerived>
+ class TPollerThreadBase : public ISimpleThread {
+ protected:
+ struct TPollerExitThread {}; // issued then we need to terminate the poller thread
+
+ struct TPollerWakeup {};
+
+ struct TPollerUnregisterSocket {
+ TIntrusivePtr<TSharedDescriptor> Socket;
+
+ TPollerUnregisterSocket(TIntrusivePtr<TSharedDescriptor> socket)
+ : Socket(std::move(socket))
+ {}
+ };
+
+ using TPollerSyncOperation = std::variant<TPollerExitThread, TPollerWakeup, TPollerUnregisterSocket>;
+
+ struct TPollerSyncOperationWrapper {
+ TPollerSyncOperation Operation;
+ TManualEvent Event;
+
+ TPollerSyncOperationWrapper(TPollerSyncOperation&& operation)
+ : Operation(std::move(operation))
+ {}
+
+ void Wait() {
+ Event.WaitI();
+ }
+
+ void SignalDone() {
+ Event.Signal();
+ }
+ };
+
+ TActorSystem *ActorSystem;
+ TPipeHandle ReadEnd, WriteEnd; // pipe for sync event processor
+ TFunnelQueue<TPollerSyncOperationWrapper*> SyncOperationsQ; // operation queue
+
+ public:
+ TPollerThreadBase(TActorSystem *actorSystem)
+ : ActorSystem(actorSystem)
+ {
+ // create a pipe for notifications
+ try {
+ TPipeHandle::Pipe(ReadEnd, WriteEnd, CloseOnExec);
+ } catch (const TFileError& err) {
+ Y_FAIL("failed to create pipe");
+ }
+
+ // switch the read/write ends to nonblocking mode
+ SetNonBlock(ReadEnd);
+ SetNonBlock(WriteEnd);
+ }
+
+ void UnregisterSocket(const TIntrusivePtr<TSocketRecord>& record) {
+ ExecuteSyncOperation(TPollerUnregisterSocket(record->Socket));
+ }
+
+ protected:
+ void Notify(TSocketRecord *record, bool read, bool write) {
+ auto issue = [&](const TActorId& recipient) {
+ ActorSystem->Send(new IEventHandle(recipient, {}, new TEvPollerReady(record->Socket, read, write)));
+ };
+ if (read && record->ReadActorId) {
+ issue(record->ReadActorId);
+ if (write && record->WriteActorId && record->WriteActorId != record->ReadActorId) {
+ issue(record->WriteActorId);
+ }
+ } else if (write && record->WriteActorId) {
+ issue(record->WriteActorId);
+ }
+ }
+
+ void Stop() {
+ // signal poller thread to stop and wait for the thread
+ ExecuteSyncOperation(TPollerExitThread());
+ ISimpleThread::Join();
+ }
+
+ void ExecuteSyncOperation(TPollerSyncOperation&& op) {
+ TPollerSyncOperationWrapper wrapper(std::move(op));
+ if (SyncOperationsQ.Push(&wrapper)) {
+ // this was the first entry, so we push notification through the pipe
+ for (;;) {
+ char buffer = '\x00';
+ ssize_t nwritten = WriteEnd.Write(&buffer, sizeof(buffer));
+ if (nwritten < 0) {
+ const int err = LastSocketError();
+ if (err == EINTR) {
+ continue;
+ } else {
+ Y_FAIL("WriteEnd.Write() failed with %s", strerror(err));
+ }
+ } else {
+ Y_VERIFY(nwritten);
+ break;
+ }
+ }
+ }
+ // wait for operation to complete
+ wrapper.Wait();
+ }
+
+ bool DrainReadEnd() {
+ size_t totalRead = 0;
+ char buffer[4096];
+ for (;;) {
+ ssize_t n = ReadEnd.Read(buffer, sizeof(buffer));
+ if (n < 0) {
+ const int error = LastSocketError();
+ if (error == EINTR) {
+ continue;
+ } else if (error == EAGAIN || error == EWOULDBLOCK) {
+ break;
+ } else {
+ Y_FAIL("read() failed with %s", strerror(errno));
+ }
+ } else {
+ Y_VERIFY(n);
+ totalRead += n;
+ }
+ }
+ return totalRead;
+ }
+
+ bool ProcessSyncOpQueue() {
+ if (DrainReadEnd()) {
+ Y_VERIFY(!SyncOperationsQ.IsEmpty());
+ do {
+ TPollerSyncOperationWrapper *op = SyncOperationsQ.Top();
+ if (auto *unregister = std::get_if<TPollerUnregisterSocket>(&op->Operation)) {
+ static_cast<TDerived&>(*this).UnregisterSocketInLoop(unregister->Socket);
+ op->SignalDone();
+ } else if (std::get_if<TPollerExitThread>(&op->Operation)) {
+ op->SignalDone();
+ return false; // terminate the thread
+ } else if (std::get_if<TPollerWakeup>(&op->Operation)) {
+ op->SignalDone();
+ } else {
+ Y_FAIL();
+ }
+ } while (SyncOperationsQ.Pop());
+ }
+ return true;
+ }
+
+ void *ThreadProc() override {
+ SetCurrentThreadName("network poller");
+ while (ProcessSyncOpQueue()) {
+ static_cast<TDerived&>(*this).ProcessEventsInLoop();
+ }
+ return nullptr;
+ }
+ };
+
+} // namespace NActors
+
+#if defined(_linux_)
+# include "poller_actor_linux.h"
+#elif defined(_darwin_)
+# include "poller_actor_darwin.h"
+#elif defined(_win_)
+# include "poller_actor_win.h"
+#else
+# error "Unsupported platform"
+#endif
+
+namespace NActors {
+
+ class TPollerToken::TImpl {
+ std::weak_ptr<TPollerThread> Thread;
+ TIntrusivePtr<TSocketRecord> Record; // valid only when Thread is held locked
+
+ public:
+ TImpl(std::shared_ptr<TPollerThread> thread, TIntrusivePtr<TSocketRecord> record)
+ : Thread(thread)
+ , Record(std::move(record))
+ {
+ thread->RegisterSocket(Record);
+ }
+
+ ~TImpl() {
+ if (auto thread = Thread.lock()) {
+ thread->UnregisterSocket(Record);
+ }
+ }
+
+ void Request(bool read, bool write) {
+ if (auto thread = Thread.lock()) {
+ thread->Request(Record, read, write);
+ }
+ }
+
+ const TIntrusivePtr<TSharedDescriptor>& Socket() const {
+ return Record->Socket;
+ }
+ };
+
+ class TPollerActor: public TActorBootstrapped<TPollerActor> {
+ // poller thread
+ std::shared_ptr<TPollerThread> PollerThread;
+
+ public:
+ static constexpr IActor::EActivityType ActorActivityType() {
+ return IActor::INTERCONNECT_POLLER;
+ }
+
+ void Bootstrap() {
+ PollerThread = std::make_shared<TPollerThread>(TlsActivationContext->ExecutorThread.ActorSystem);
+ Become(&TPollerActor::StateFunc);
+ }
+
+ STRICT_STFUNC(StateFunc,
+ hFunc(TEvPollerRegister, Handle);
+ cFunc(TEvents::TSystem::Poison, PassAway);
+ )
+
+ void Handle(TEvPollerRegister::TPtr& ev) {
+ auto *msg = ev->Get();
+ auto impl = std::make_unique<TPollerToken::TImpl>(PollerThread, MakeIntrusive<TSocketRecord>(*msg));
+ auto socket = impl->Socket();
+ TPollerToken::TPtr token(new TPollerToken(std::move(impl)));
+ if (msg->ReadActorId && msg->WriteActorId && msg->WriteActorId != msg->ReadActorId) {
+ Send(msg->ReadActorId, new TEvPollerRegisterResult(socket, token));
+ Send(msg->WriteActorId, new TEvPollerRegisterResult(socket, std::move(token)));
+ } else if (msg->ReadActorId) {
+ Send(msg->ReadActorId, new TEvPollerRegisterResult(socket, std::move(token)));
+ } else if (msg->WriteActorId) {
+ Send(msg->WriteActorId, new TEvPollerRegisterResult(socket, std::move(token)));
+ }
+ }
+ };
+
+ TPollerToken::TPollerToken(std::unique_ptr<TImpl> impl)
+ : Impl(std::move(impl))
+ {}
+
+ TPollerToken::~TPollerToken()
+ {}
+
+ void TPollerToken::Request(bool read, bool write) {
+ Impl->Request(read, write);
+ }
+
+ IActor* CreatePollerActor() {
+ return new TPollerActor;
+ }
+
+}
diff --git a/library/cpp/actors/interconnect/poller_actor.h b/library/cpp/actors/interconnect/poller_actor.h
new file mode 100644
index 0000000000..f927b82089
--- /dev/null
+++ b/library/cpp/actors/interconnect/poller_actor.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include "events_local.h"
+#include "poller.h"
+#include <library/cpp/actors/core/actor.h>
+
+namespace NActors {
+ struct TEvPollerRegister : TEventLocal<TEvPollerRegister, ui32(ENetwork::EvPollerRegister)> {
+ const TIntrusivePtr<TSharedDescriptor> Socket; // socket to watch for
+ const TActorId ReadActorId; // actor id to notify about read availability
+ const TActorId WriteActorId; // actor id to notify about write availability; may be the same as the ReadActorId
+
+ TEvPollerRegister(TIntrusivePtr<TSharedDescriptor> socket, const TActorId& readActorId, const TActorId& writeActorId)
+ : Socket(std::move(socket))
+ , ReadActorId(readActorId)
+ , WriteActorId(writeActorId)
+ {}
+ };
+
+ // poller token is sent in response to TEvPollerRegister; it allows requesting poll when read/write returns EAGAIN
+ class TPollerToken : public TThrRefBase {
+ class TImpl;
+ std::unique_ptr<TImpl> Impl;
+
+ friend class TPollerActor;
+ TPollerToken(std::unique_ptr<TImpl> impl);
+
+ public:
+ ~TPollerToken();
+ void Request(bool read, bool write);
+
+ using TPtr = TIntrusivePtr<TPollerToken>;
+ };
+
+ struct TEvPollerRegisterResult : TEventLocal<TEvPollerRegisterResult, ui32(ENetwork::EvPollerRegisterResult)> {
+ TIntrusivePtr<TSharedDescriptor> Socket;
+ TPollerToken::TPtr PollerToken;
+
+ TEvPollerRegisterResult(TIntrusivePtr<TSharedDescriptor> socket, TPollerToken::TPtr pollerToken)
+ : Socket(std::move(socket))
+ , PollerToken(std::move(pollerToken))
+ {}
+ };
+
+ struct TEvPollerReady : TEventLocal<TEvPollerReady, ui32(ENetwork::EvPollerReady)> {
+ TIntrusivePtr<TSharedDescriptor> Socket;
+ const bool Read, Write;
+
+ TEvPollerReady(TIntrusivePtr<TSharedDescriptor> socket, bool read, bool write)
+ : Socket(std::move(socket))
+ , Read(read)
+ , Write(write)
+ {}
+ };
+
+ IActor* CreatePollerActor();
+
+ inline TActorId MakePollerActorId() {
+ char x[12] = {'I', 'C', 'P', 'o', 'l', 'l', 'e', 'r', '\xDE', '\xAD', '\xBE', '\xEF'};
+ return TActorId(0, TStringBuf(std::begin(x), std::end(x)));
+ }
+
+}
diff --git a/library/cpp/actors/interconnect/poller_actor_darwin.h b/library/cpp/actors/interconnect/poller_actor_darwin.h
new file mode 100644
index 0000000000..4cb0a58f8d
--- /dev/null
+++ b/library/cpp/actors/interconnect/poller_actor_darwin.h
@@ -0,0 +1,95 @@
+#pragma once
+
+#include <sys/event.h>
+
+namespace NActors {
+
+ class TKqueueThread : public TPollerThreadBase<TKqueueThread> {
+ // KQueue file descriptor
+ int KqDescriptor;
+
+ void SafeKevent(const struct kevent* ev, int size) {
+ int rc;
+ do {
+ rc = kevent(KqDescriptor, ev, size, nullptr, 0, nullptr);
+ } while (rc == -1 && errno == EINTR);
+ Y_VERIFY(rc != -1, "kevent() failed with %s", strerror(errno));
+ }
+
+ public:
+ TKqueueThread(TActorSystem *actorSystem)
+ : TPollerThreadBase(actorSystem)
+ {
+ // create kqueue
+ KqDescriptor = kqueue();
+ Y_VERIFY(KqDescriptor != -1, "kqueue() failed with %s", strerror(errno));
+
+ // set close-on-exit flag
+ {
+ int flags = fcntl(KqDescriptor, F_GETFD);
+ Y_VERIFY(flags >= 0, "fcntl(F_GETFD) failed with %s", strerror(errno));
+ int rc = fcntl(KqDescriptor, F_SETFD, flags | FD_CLOEXEC);
+ Y_VERIFY(rc != -1, "fcntl(F_SETFD, +FD_CLOEXEC) failed with %s", strerror(errno));
+ }
+
+ // register pipe's read end in poller
+ struct kevent ev;
+ EV_SET(&ev, (int)ReadEnd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, nullptr);
+ SafeKevent(&ev, 1);
+
+ ISimpleThread::Start(); // start poller thread
+ }
+
+ ~TKqueueThread() {
+ Stop();
+ close(KqDescriptor);
+ }
+
+ void ProcessEventsInLoop() {
+ std::array<struct kevent, 256> events;
+
+ int numReady = kevent(KqDescriptor, nullptr, 0, events.data(), events.size(), nullptr);
+ if (numReady == -1) {
+ if (errno == EINTR) {
+ return;
+ } else {
+ Y_FAIL("kevent() failed with %s", strerror(errno));
+ }
+ }
+
+ for (int i = 0; i < numReady; ++i) {
+ const struct kevent& ev = events[i];
+ if (ev.udata) {
+ TSocketRecord *it = static_cast<TSocketRecord*>(ev.udata);
+ const bool error = ev.flags & (EV_EOF | EV_ERROR);
+ const bool read = error || ev.filter == EVFILT_READ;
+ const bool write = error || ev.filter == EVFILT_WRITE;
+ Notify(it, read, write);
+ }
+ }
+ }
+
+ void UnregisterSocketInLoop(const TIntrusivePtr<TSharedDescriptor>& socket) {
+ struct kevent ev[2];
+ const int fd = socket->GetDescriptor();
+ EV_SET(&ev[0], fd, EVFILT_READ, EV_DELETE, 0, 0, nullptr);
+ EV_SET(&ev[1], fd, EVFILT_WRITE, EV_DELETE, 0, 0, nullptr);
+ SafeKevent(ev, 2);
+ }
+
+ void RegisterSocket(const TIntrusivePtr<TSocketRecord>& record) {
+ int flags = EV_ADD | EV_CLEAR | EV_ENABLE;
+ struct kevent ev[2];
+ const int fd = record->Socket->GetDescriptor();
+ EV_SET(&ev[0], fd, EVFILT_READ, flags, 0, 0, record.Get());
+ EV_SET(&ev[1], fd, EVFILT_WRITE, flags, 0, 0, record.Get());
+ SafeKevent(ev, 2);
+ }
+
+ void Request(const TIntrusivePtr<TSocketRecord>& /*socket*/, bool /*read*/, bool /*write*/)
+ {} // no special processing here as we use kqueue in edge-triggered mode
+ };
+
+ using TPollerThread = TKqueueThread;
+
+}
diff --git a/library/cpp/actors/interconnect/poller_actor_linux.h b/library/cpp/actors/interconnect/poller_actor_linux.h
new file mode 100644
index 0000000000..dd4f7c0124
--- /dev/null
+++ b/library/cpp/actors/interconnect/poller_actor_linux.h
@@ -0,0 +1,114 @@
+#pragma once
+
+#include <sys/epoll.h>
+
+namespace NActors {
+
+ class TEpollThread : public TPollerThreadBase<TEpollThread> {
+ // epoll file descriptor
+ int EpollDescriptor;
+
+ public:
+ TEpollThread(TActorSystem *actorSystem)
+ : TPollerThreadBase(actorSystem)
+ {
+ EpollDescriptor = epoll_create1(EPOLL_CLOEXEC);
+ Y_VERIFY(EpollDescriptor != -1, "epoll_create1() failed with %s", strerror(errno));
+
+ epoll_event event;
+ event.data.ptr = nullptr;
+ event.events = EPOLLIN;
+ if (epoll_ctl(EpollDescriptor, EPOLL_CTL_ADD, ReadEnd, &event) == -1) {
+ Y_FAIL("epoll_ctl(EPOLL_CTL_ADD) failed with %s", strerror(errno));
+ }
+
+ ISimpleThread::Start(); // start poller thread
+ }
+
+ ~TEpollThread() {
+ Stop();
+ close(EpollDescriptor);
+ }
+
+ void ProcessEventsInLoop() {
+ // preallocated array for events
+ std::array<epoll_event, 256> events;
+
+ // wait indefinitely for event to arrive
+ LWPROBE(EpollStartWaitIn);
+ int numReady = epoll_wait(EpollDescriptor, events.data(), events.size(), -1);
+ LWPROBE(EpollFinishWaitIn, numReady);
+
+ // check return status for any errors
+ if (numReady == -1) {
+ if (errno == EINTR) {
+ return; // restart the call a bit later
+ } else {
+ Y_FAIL("epoll_wait() failed with %s", strerror(errno));
+ }
+ }
+
+ for (int i = 0; i < numReady; ++i) {
+ const epoll_event& ev = events[i];
+ if (auto *record = static_cast<TSocketRecord*>(ev.data.ptr)) {
+ const bool read = ev.events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR);
+ const bool write = ev.events & (EPOLLOUT | EPOLLERR);
+
+ // remove hit flags from the bit set
+ ui32 flags = record->Flags;
+ const ui32 remove = (read ? EPOLLIN : 0) | (write ? EPOLLOUT : 0);
+ while (!record->Flags.compare_exchange_weak(flags, flags & ~remove))
+ {}
+ flags &= ~remove;
+
+ // rearm poller if some flags remain
+ if (flags) {
+ epoll_event event;
+ event.events = EPOLLONESHOT | EPOLLRDHUP | flags;
+ event.data.ptr = record;
+ if (epoll_ctl(EpollDescriptor, EPOLL_CTL_MOD, record->Socket->GetDescriptor(), &event) == -1) {
+ Y_FAIL("epoll_ctl(EPOLL_CTL_MOD) failed with %s", strerror(errno));
+ }
+ }
+
+ // issue notifications
+ Notify(record, read, write);
+ }
+ }
+ }
+
+ void UnregisterSocketInLoop(const TIntrusivePtr<TSharedDescriptor>& socket) {
+ if (epoll_ctl(EpollDescriptor, EPOLL_CTL_DEL, socket->GetDescriptor(), nullptr) == -1) {
+ Y_FAIL("epoll_ctl(EPOLL_CTL_DEL) failed with %s", strerror(errno));
+ }
+ }
+
+ void RegisterSocket(const TIntrusivePtr<TSocketRecord>& record) {
+ epoll_event event;
+ event.events = EPOLLONESHOT | EPOLLRDHUP;
+ event.data.ptr = record.Get();
+ if (epoll_ctl(EpollDescriptor, EPOLL_CTL_ADD, record->Socket->GetDescriptor(), &event) == -1) {
+ Y_FAIL("epoll_ctl(EPOLL_CTL_ADD) failed with %s", strerror(errno));
+ }
+ }
+
+ void Request(const TIntrusivePtr<TSocketRecord>& record, bool read, bool write) {
+ const ui32 add = (read ? EPOLLIN : 0) | (write ? EPOLLOUT : 0);
+ ui32 flags = record->Flags;
+ while (!record->Flags.compare_exchange_weak(flags, flags | add))
+ {}
+ flags |= add;
+ if (flags) {
+ epoll_event event;
+ event.events = EPOLLONESHOT | EPOLLRDHUP | flags;
+ event.data.ptr = record.Get();
+ if (epoll_ctl(EpollDescriptor, EPOLL_CTL_MOD, record->Socket->GetDescriptor(), &event) == -1) {
+ Y_FAIL("epoll_ctl(EPOLL_CTL_MOD) failed with %s", strerror(errno));
+ }
+ }
+ }
+ };
+
+ using TPollerThread = TEpollThread;
+
+} // namespace NActors
diff --git a/library/cpp/actors/interconnect/poller_actor_win.h b/library/cpp/actors/interconnect/poller_actor_win.h
new file mode 100644
index 0000000000..4b4caa0ebd
--- /dev/null
+++ b/library/cpp/actors/interconnect/poller_actor_win.h
@@ -0,0 +1,103 @@
+#pragma once
+
+namespace NActors {
+
+ class TSelectThread : public TPollerThreadBase<TSelectThread> {
+ TMutex Mutex;
+ std::unordered_map<SOCKET, TIntrusivePtr<TSocketRecord>> Descriptors;
+
+ enum {
+ READ = 1,
+ WRITE = 2,
+ };
+
+ public:
+ TSelectThread(TActorSystem *actorSystem)
+ : TPollerThreadBase(actorSystem)
+ {
+ Descriptors.emplace(ReadEnd, nullptr);
+ ISimpleThread::Start();
+ }
+
+ ~TSelectThread() {
+ Stop();
+ }
+
+ void ProcessEventsInLoop() {
+ fd_set readfds, writefds, exceptfds;
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ FD_ZERO(&exceptfds);
+ int nfds = 0;
+ with_lock (Mutex) {
+ for (const auto& [key, record] : Descriptors) {
+ const int fd = key;
+ auto add = [&](auto& set) {
+ FD_SET(fd, &set);
+ nfds = Max<int>(nfds, fd + 1);
+ };
+ if (!record || (record->Flags & READ)) {
+ add(readfds);
+ }
+ if (!record || (record->Flags & WRITE)) {
+ add(writefds);
+ }
+ add(exceptfds);
+ }
+ }
+
+ int res = select(nfds, &readfds, &writefds, &exceptfds, nullptr);
+ if (res == -1) {
+ const int err = LastSocketError();
+ if (err == EINTR) {
+ return; // try a bit later
+ } else {
+ Y_FAIL("select() failed with %s", strerror(err));
+ }
+ }
+
+ with_lock (Mutex) {
+ for (const auto& [fd, record] : Descriptors) {
+ if (record) {
+ const bool error = FD_ISSET(fd, &exceptfds);
+ const bool read = error || FD_ISSET(fd, &readfds);
+ const bool write = error || FD_ISSET(fd, &writefds);
+ if (read) {
+ record->Flags &= ~READ;
+ }
+ if (write) {
+ record->Flags &= ~WRITE;
+ }
+ Notify(record.Get(), read, write);
+ }
+ }
+ }
+ }
+
+ void UnregisterSocketInLoop(const TIntrusivePtr<TSharedDescriptor>& socket) {
+ with_lock (Mutex) {
+ Descriptors.erase(socket->GetDescriptor());
+ }
+ }
+
+ void RegisterSocket(const TIntrusivePtr<TSocketRecord>& record) {
+ with_lock (Mutex) {
+ Descriptors.emplace(record->Socket->GetDescriptor(), record);
+ }
+ ExecuteSyncOperation(TPollerWakeup());
+ }
+
+ void Request(const TIntrusivePtr<TSocketRecord>& record, bool read, bool write) {
+ with_lock (Mutex) {
+ const auto it = Descriptors.find(record->Socket->GetDescriptor());
+ Y_VERIFY(it != Descriptors.end());
+ it->second->Flags |= (read ? READ : 0) | (write ? WRITE : 0);
+ }
+ ExecuteSyncOperation(TPollerWakeup());
+ }
+ };
+
+ using TPollerThread = TSelectThread;
+
+} // NActors
diff --git a/library/cpp/actors/interconnect/poller_tcp.cpp b/library/cpp/actors/interconnect/poller_tcp.cpp
new file mode 100644
index 0000000000..8267df31ea
--- /dev/null
+++ b/library/cpp/actors/interconnect/poller_tcp.cpp
@@ -0,0 +1,35 @@
+#include "poller_tcp.h"
+
+namespace NInterconnect {
+ TPollerThreads::TPollerThreads(size_t units, bool useSelect)
+ : Units(units)
+ {
+ Y_VERIFY_DEBUG(!Units.empty());
+ for (auto& unit : Units)
+ unit = TPollerUnit::Make(useSelect);
+ }
+
+ TPollerThreads::~TPollerThreads() {
+ }
+
+ void TPollerThreads::Start() {
+ for (const auto& unit : Units)
+ unit->Start();
+ }
+
+ void TPollerThreads::Stop() {
+ for (const auto& unit : Units)
+ unit->Stop();
+ }
+
+ void TPollerThreads::StartRead(const TIntrusivePtr<TSharedDescriptor>& s, TFDDelegate&& operation) {
+ auto& unit = Units[THash<SOCKET>()(s->GetDescriptor()) % Units.size()];
+ unit->StartReadOperation(s, std::move(operation));
+ }
+
+ void TPollerThreads::StartWrite(const TIntrusivePtr<TSharedDescriptor>& s, TFDDelegate&& operation) {
+ auto& unit = Units[THash<SOCKET>()(s->GetDescriptor()) % Units.size()];
+ unit->StartWriteOperation(s, std::move(operation));
+ }
+
+}
diff --git a/library/cpp/actors/interconnect/poller_tcp.h b/library/cpp/actors/interconnect/poller_tcp.h
new file mode 100644
index 0000000000..310265eccd
--- /dev/null
+++ b/library/cpp/actors/interconnect/poller_tcp.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "poller_tcp_unit.h"
+#include "poller.h"
+
+#include <util/generic/vector.h>
+#include <util/generic/hash.h>
+
+namespace NInterconnect {
+ class TPollerThreads: public NActors::IPoller {
+ public:
+ TPollerThreads(size_t units = 1U, bool useSelect = false);
+ ~TPollerThreads();
+
+ void Start();
+ void Stop();
+
+ void StartRead(const TIntrusivePtr<TSharedDescriptor>& s, TFDDelegate&& operation) override;
+ void StartWrite(const TIntrusivePtr<TSharedDescriptor>& s, TFDDelegate&& operation) override;
+
+ private:
+ TVector<TPollerUnit::TPtr> Units;
+ };
+
+}
diff --git a/library/cpp/actors/interconnect/poller_tcp_unit.cpp b/library/cpp/actors/interconnect/poller_tcp_unit.cpp
new file mode 100644
index 0000000000..59e7dda810
--- /dev/null
+++ b/library/cpp/actors/interconnect/poller_tcp_unit.cpp
@@ -0,0 +1,126 @@
+#include "poller_tcp_unit.h"
+
+#if !defined(_win_) && !defined(_darwin_)
+#include "poller_tcp_unit_epoll.h"
+#endif
+
+#include "poller_tcp_unit_select.h"
+#include "poller.h"
+
+#include <library/cpp/actors/prof/tag.h>
+#include <library/cpp/actors/util/intrinsics.h>
+
+#if defined _linux_
+#include <pthread.h>
+#endif
+
+namespace NInterconnect {
+ TPollerUnit::TPtr
+ TPollerUnit::Make(bool useSelect) {
+#if defined(_win_) || defined(_darwin_)
+ Y_UNUSED(useSelect);
+ return TPtr(new TPollerUnitSelect);
+#else
+ return useSelect ? TPtr(new TPollerUnitSelect) : TPtr(new TPollerUnitEpoll);
+#endif
+ }
+
+ TPollerUnit::TPollerUnit()
+ : StopFlag(true)
+ , ReadLoop(TThread::TParams(IdleThread<false>, this).SetName("network read"))
+ , WriteLoop(TThread::TParams(IdleThread<true>, this).SetName("network write"))
+ {
+ }
+
+ TPollerUnit::~TPollerUnit() {
+ if (!AtomicLoad(&StopFlag))
+ Stop();
+ }
+
+ void
+ TPollerUnit::Start() {
+ AtomicStore(&StopFlag, false);
+ ReadLoop.Start();
+ WriteLoop.Start();
+ }
+
+ void
+ TPollerUnit::Stop() {
+ AtomicStore(&StopFlag, true);
+ ReadLoop.Join();
+ WriteLoop.Join();
+ }
+
+ template <>
+ TPollerUnit::TSide&
+ TPollerUnit::GetSide<false>() {
+ return Read;
+ }
+
+ template <>
+ TPollerUnit::TSide&
+ TPollerUnit::GetSide<true>() {
+ return Write;
+ }
+
+ void
+ TPollerUnit::StartReadOperation(
+ const TIntrusivePtr<TSharedDescriptor>& stream,
+ TFDDelegate&& operation) {
+ Y_VERIFY_DEBUG(stream);
+ if (AtomicLoad(&StopFlag))
+ return;
+ GetSide<false>().InputQueue.Push(TSide::TItem(stream, std::move(operation)));
+ }
+
+ void
+ TPollerUnit::StartWriteOperation(
+ const TIntrusivePtr<TSharedDescriptor>& stream,
+ TFDDelegate&& operation) {
+ Y_VERIFY_DEBUG(stream);
+ if (AtomicLoad(&StopFlag))
+ return;
+ GetSide<true>().InputQueue.Push(TSide::TItem(stream, std::move(operation)));
+ }
+
+ template <bool IsWrite>
+ void*
+ TPollerUnit::IdleThread(void* param) {
+ // TODO: musl-libc version of `sched_param` struct is for some reason different from pthread
+ // version in Ubuntu 12.04
+#if defined(_linux_) && !defined(_musl_)
+ pthread_t threadSelf = pthread_self();
+ sched_param sparam = {20};
+ pthread_setschedparam(threadSelf, SCHED_FIFO, &sparam);
+#endif
+
+ static_cast<TPollerUnit*>(param)->RunLoop<IsWrite>();
+ return nullptr;
+ }
+
+ template <>
+ void
+ TPollerUnit::RunLoop<false>() {
+ NProfiling::TMemoryTagScope tag("INTERCONNECT_RECEIVED_DATA");
+ while (!AtomicLoad(&StopFlag))
+ ProcessRead();
+ }
+
+ template <>
+ void
+ TPollerUnit::RunLoop<true>() {
+ NProfiling::TMemoryTagScope tag("INTERCONNECT_SEND_DATA");
+ while (!AtomicLoad(&StopFlag))
+ ProcessWrite();
+ }
+
+ void
+ TPollerUnit::TSide::ProcessInput() {
+ if (!InputQueue.IsEmpty())
+ do {
+ auto sock = InputQueue.Top().first->GetDescriptor();
+ if (!Operations.emplace(sock, std::move(InputQueue.Top())).second)
+ Y_FAIL("Descriptor is already in pooler.");
+ } while (InputQueue.Pop());
+ }
+}
diff --git a/library/cpp/actors/interconnect/poller_tcp_unit.h b/library/cpp/actors/interconnect/poller_tcp_unit.h
new file mode 100644
index 0000000000..692168b968
--- /dev/null
+++ b/library/cpp/actors/interconnect/poller_tcp_unit.h
@@ -0,0 +1,67 @@
+#pragma once
+
+#include <util/system/thread.h>
+#include <library/cpp/actors/util/funnel_queue.h>
+
+#include "interconnect_stream.h"
+
+#include <memory>
+#include <functional>
+#include <unordered_map>
+
+namespace NInterconnect {
+ using NActors::TFDDelegate;
+ using NActors::TSharedDescriptor;
+
+ class TPollerUnit {
+ public:
+ typedef std::unique_ptr<TPollerUnit> TPtr;
+
+ static TPtr Make(bool useSelect);
+
+ void Start();
+ void Stop();
+
+ virtual void StartReadOperation(
+ const TIntrusivePtr<TSharedDescriptor>& stream,
+ TFDDelegate&& operation);
+
+ virtual void StartWriteOperation(
+ const TIntrusivePtr<TSharedDescriptor>& stream,
+ TFDDelegate&& operation);
+
+ virtual ~TPollerUnit();
+
+ private:
+ virtual void ProcessRead() = 0;
+ virtual void ProcessWrite() = 0;
+
+ template <bool IsWrite>
+ static void* IdleThread(void* param);
+
+ template <bool IsWrite>
+ void RunLoop();
+
+ volatile bool StopFlag;
+ TThread ReadLoop, WriteLoop;
+
+ protected:
+ TPollerUnit();
+
+ struct TSide {
+ using TOperations =
+ std::unordered_map<SOCKET,
+ std::pair<TIntrusivePtr<TSharedDescriptor>, TFDDelegate>>;
+
+ TOperations Operations;
+ using TItem = TOperations::mapped_type;
+ TFunnelQueue<TItem> InputQueue;
+
+ void ProcessInput();
+ } Read, Write;
+
+ template <bool IsWrite>
+ TSide& GetSide();
+ };
+
+}
diff --git a/library/cpp/actors/interconnect/poller_tcp_unit_epoll.cpp b/library/cpp/actors/interconnect/poller_tcp_unit_epoll.cpp
new file mode 100644
index 0000000000..c78538b95b
--- /dev/null
+++ b/library/cpp/actors/interconnect/poller_tcp_unit_epoll.cpp
@@ -0,0 +1,125 @@
+#include "poller_tcp_unit_epoll.h"
+#if !defined(_win_) && !defined(_darwin_)
+#include <unistd.h>
+#include <sys/epoll.h>
+
+#include <csignal>
+#include <cerrno>
+#include <cstring>
+
+namespace NInterconnect {
+ namespace {
+ void
+ DeleteEpoll(int epoll, SOCKET stream) {
+ ::epoll_event event = {0, {.fd = stream}};
+ if (::epoll_ctl(epoll, EPOLL_CTL_DEL, stream, &event)) {
+ Cerr << "epoll_ctl errno: " << errno << Endl;
+ Y_FAIL("epoll delete error!");
+ }
+ }
+
+ template <ui32 Events>
+ void
+ AddEpoll(int epoll, SOCKET stream) {
+ ::epoll_event event = {.events = Events};
+ event.data.fd = stream;
+ if (::epoll_ctl(epoll, EPOLL_CTL_ADD, stream, &event)) {
+ Cerr << "epoll_ctl errno: " << errno << Endl;
+ Y_FAIL("epoll add error!");
+ }
+ }
+
+ int
+ Initialize() {
+ const auto epoll = ::epoll_create(10000);
+ Y_VERIFY_DEBUG(epoll > 0);
+ return epoll;
+ }
+
+ }
+
+ TPollerUnitEpoll::TPollerUnitEpoll()
+ : ReadDescriptor(Initialize())
+ , WriteDescriptor(Initialize())
+ {
+ // Block on the epoll descriptor.
+ ::sigemptyset(&sigmask);
+ ::sigaddset(&sigmask, SIGPIPE);
+ ::sigaddset(&sigmask, SIGTERM);
+ }
+
+ TPollerUnitEpoll::~TPollerUnitEpoll() {
+ ::close(ReadDescriptor);
+ ::close(WriteDescriptor);
+ }
+
+ template <>
+ int TPollerUnitEpoll::GetDescriptor<false>() const {
+ return ReadDescriptor;
+ }
+
+ template <>
+ int TPollerUnitEpoll::GetDescriptor<true>() const {
+ return WriteDescriptor;
+ }
+
+ void
+ TPollerUnitEpoll::StartReadOperation(
+ const TIntrusivePtr<TSharedDescriptor>& s,
+ TFDDelegate&& operation) {
+ TPollerUnit::StartReadOperation(s, std::move(operation));
+ AddEpoll<EPOLLRDHUP | EPOLLIN>(ReadDescriptor, s->GetDescriptor());
+ }
+
+ void
+ TPollerUnitEpoll::StartWriteOperation(
+ const TIntrusivePtr<TSharedDescriptor>& s,
+ TFDDelegate&& operation) {
+ TPollerUnit::StartWriteOperation(s, std::move(operation));
+ AddEpoll<EPOLLRDHUP | EPOLLOUT>(WriteDescriptor, s->GetDescriptor());
+ }
+
+ constexpr int EVENTS_BUF_SIZE = 128;
+
+ template <bool WriteOp>
+ void
+ TPollerUnitEpoll::Process() {
+ ::epoll_event events[EVENTS_BUF_SIZE];
+
+ const int epoll = GetDescriptor<WriteOp>();
+
+ /* Timeout just to check StopFlag sometimes */
+ const int result =
+ ::epoll_pwait(epoll, events, EVENTS_BUF_SIZE, 200, &sigmask);
+
+ if (result == -1 && errno != EINTR)
+ Y_FAIL("epoll wait error!");
+
+ auto& side = GetSide<WriteOp>();
+ side.ProcessInput();
+
+ for (int i = 0; i < result; ++i) {
+ const auto it = side.Operations.find(events[i].data.fd);
+ if (side.Operations.end() == it)
+ continue;
+ if (const auto& finalizer = it->second.second(it->second.first)) {
+ DeleteEpoll(epoll, it->first);
+ side.Operations.erase(it);
+ finalizer();
+ }
+ }
+ }
+
+ void
+ TPollerUnitEpoll::ProcessRead() {
+ Process<false>();
+ }
+
+ void
+ TPollerUnitEpoll::ProcessWrite() {
+ Process<true>();
+ }
+
+}
+
+#endif
diff --git a/library/cpp/actors/interconnect/poller_tcp_unit_epoll.h b/library/cpp/actors/interconnect/poller_tcp_unit_epoll.h
new file mode 100644
index 0000000000..ff7893eba2
--- /dev/null
+++ b/library/cpp/actors/interconnect/poller_tcp_unit_epoll.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "poller_tcp_unit.h"
+
+namespace NInterconnect {
+ class TPollerUnitEpoll: public TPollerUnit {
+ public:
+ TPollerUnitEpoll();
+ virtual ~TPollerUnitEpoll();
+
+ private:
+ virtual void StartReadOperation(
+ const TIntrusivePtr<TSharedDescriptor>& s,
+ TFDDelegate&& operation) override;
+
+ virtual void StartWriteOperation(
+ const TIntrusivePtr<TSharedDescriptor>& s,
+ TFDDelegate&& operation) override;
+
+ virtual void ProcessRead() override;
+ virtual void ProcessWrite() override;
+
+ template <bool Write>
+ void Process();
+
+ template <bool Write>
+ int GetDescriptor() const;
+
+ const int ReadDescriptor, WriteDescriptor;
+ ::sigset_t sigmask;
+ };
+
+}
diff --git a/library/cpp/actors/interconnect/poller_tcp_unit_select.cpp b/library/cpp/actors/interconnect/poller_tcp_unit_select.cpp
new file mode 100644
index 0000000000..ae7aaad566
--- /dev/null
+++ b/library/cpp/actors/interconnect/poller_tcp_unit_select.cpp
@@ -0,0 +1,86 @@
+#include "poller_tcp_unit_select.h"
+
+#include <csignal>
+
+#if defined(_win_)
+#include <winsock2.h>
+#define SOCKET_ERROR_SOURCE ::WSAGetLastError()
+#elif defined(_darwin_)
+#include <cerrno>
+#define SOCKET_ERROR_SOURCE errno
+typedef timeval TIMEVAL;
+#else
+#include <cerrno>
+#define SOCKET_ERROR_SOURCE errno
+#endif
+
+namespace NInterconnect {
+ TPollerUnitSelect::TPollerUnitSelect() {
+ }
+
+ TPollerUnitSelect::~TPollerUnitSelect() {
+ }
+
+ template <bool IsWrite>
+ void
+ TPollerUnitSelect::Process() {
+ auto& side = GetSide<IsWrite>();
+ side.ProcessInput();
+
+ enum : size_t { R,
+ W,
+ E };
+ static const auto O = IsWrite ? W : R;
+
+ ::fd_set sets[3];
+
+ FD_ZERO(&sets[R]);
+ FD_ZERO(&sets[W]);
+ FD_ZERO(&sets[E]);
+
+ for (const auto& operation : side.Operations) {
+ FD_SET(operation.first, &sets[O]);
+ FD_SET(operation.first, &sets[E]);
+ }
+
+#if defined(_win_)
+ ::TIMEVAL timeout = {0L, 99991L};
+ const auto numberEvents = !side.Operations.empty() ? ::select(FD_SETSIZE, &sets[R], &sets[W], &sets[E], &timeout)
+ : (::Sleep(100), 0);
+#elif defined(_darwin_)
+ ::TIMEVAL timeout = {0L, 99991L};
+ const auto numberEvents = ::select(FD_SETSIZE, &sets[R], &sets[W], &sets[E], &timeout);
+#else
+ ::sigset_t sigmask;
+ ::sigemptyset(&sigmask);
+ ::sigaddset(&sigmask, SIGPIPE);
+ ::sigaddset(&sigmask, SIGTERM);
+
+ struct ::timespec timeout = {0L, 99999989L};
+ const auto numberEvents = ::pselect(FD_SETSIZE, &sets[R], &sets[W], &sets[E], &timeout, &sigmask);
+#endif
+
+ Y_VERIFY_DEBUG(numberEvents >= 0);
+
+ for (auto it = side.Operations.cbegin(); side.Operations.cend() != it;) {
+ if (FD_ISSET(it->first, &sets[O]) || FD_ISSET(it->first, &sets[E]))
+ if (const auto& finalizer = it->second.second(it->second.first)) {
+ side.Operations.erase(it++);
+ finalizer();
+ continue;
+ }
+ ++it;
+ }
+ }
+
+ void
+ TPollerUnitSelect::ProcessRead() {
+ Process<false>();
+ }
+
+ void
+ TPollerUnitSelect::ProcessWrite() {
+ Process<true>();
+ }
+
+}
diff --git a/library/cpp/actors/interconnect/poller_tcp_unit_select.h b/library/cpp/actors/interconnect/poller_tcp_unit_select.h
new file mode 100644
index 0000000000..0c15217796
--- /dev/null
+++ b/library/cpp/actors/interconnect/poller_tcp_unit_select.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "poller_tcp_unit.h"
+
+namespace NInterconnect {
+ class TPollerUnitSelect: public TPollerUnit {
+ public:
+ TPollerUnitSelect();
+ virtual ~TPollerUnitSelect();
+
+ private:
+ virtual void ProcessRead() override;
+ virtual void ProcessWrite() override;
+
+ template <bool IsWrite>
+ void Process();
+ };
+
+}
diff --git a/library/cpp/actors/interconnect/profiler.h b/library/cpp/actors/interconnect/profiler.h
new file mode 100644
index 0000000000..77a59e3179
--- /dev/null
+++ b/library/cpp/actors/interconnect/profiler.h
@@ -0,0 +1,142 @@
+#pragma once
+
+#include <library/cpp/actors/util/datetime.h>
+
+namespace NActors {
+
+ class TProfiled {
+ enum class EType : ui32 {
+ ENTRY,
+ EXIT,
+ };
+
+ struct TItem {
+ EType Type; // entry kind
+ int Line;
+ const char *Marker; // name of the profiled function/part
+ ui64 Timestamp; // cycles
+ };
+
+ bool Enable = false;
+ mutable TDeque<TItem> Items;
+
+ friend class TFunction;
+
+ public:
+ class TFunction {
+ const TProfiled& Profiled;
+
+ public:
+ TFunction(const TProfiled& profiled, const char *name, int line)
+ : Profiled(profiled)
+ {
+ Log(EType::ENTRY, name, line);
+ }
+
+ ~TFunction() {
+ Log(EType::EXIT, nullptr, 0);
+ }
+
+ private:
+ void Log(EType type, const char *marker, int line) {
+ if (Profiled.Enable) {
+ Profiled.Items.push_back(TItem{
+ type,
+ line,
+ marker,
+ GetCycleCountFast()
+ });
+ }
+ }
+ };
+
+ public:
+ void Start() {
+ Enable = true;
+ }
+
+ void Finish() {
+ Items.clear();
+ Enable = false;
+ }
+
+ TDuration Duration() const {
+ return CyclesToDuration(Items ? Items.back().Timestamp - Items.front().Timestamp : 0);
+ }
+
+ TString Format() const {
+ TDeque<TItem>::iterator it = Items.begin();
+ TString res = FormatLevel(it);
+ Y_VERIFY(it == Items.end());
+ return res;
+ }
+
+ private:
+ TString FormatLevel(TDeque<TItem>::iterator& it) const {
+ struct TRecord {
+ TString Marker;
+ ui64 Duration;
+ TString Interior;
+
+ bool operator <(const TRecord& other) const {
+ return Duration < other.Duration;
+ }
+ };
+ TVector<TRecord> records;
+
+ while (it != Items.end() && it->Type != EType::EXIT) {
+ Y_VERIFY(it->Type == EType::ENTRY);
+ const TString marker = Sprintf("%s:%d", it->Marker, it->Line);
+ const ui64 begin = it->Timestamp;
+ ++it;
+ const TString interior = FormatLevel(it);
+ Y_VERIFY(it != Items.end());
+ Y_VERIFY(it->Type == EType::EXIT);
+ const ui64 end = it->Timestamp;
+ records.push_back(TRecord{marker, end - begin, interior});
+ ++it;
+ }
+
+ TStringStream s;
+ const ui64 cyclesPerMs = GetCyclesPerMillisecond();
+
+ if (records.size() <= 10) {
+ bool first = true;
+ for (const TRecord& record : records) {
+ if (first) {
+ first = false;
+ } else {
+ s << " ";
+ }
+ s << record.Marker << "(" << (record.Duration * 1000000 / cyclesPerMs) << "ns)";
+ if (record.Interior) {
+ s << " {" << record.Interior << "}";
+ }
+ }
+ } else {
+ TMap<TString, TVector<TRecord>> m;
+ for (TRecord& r : records) {
+ const TString key = r.Marker;
+ m[key].push_back(std::move(r));
+ }
+
+ s << "unordered ";
+ for (auto& [key, value] : m) {
+ auto i = std::max_element(value.begin(), value.end());
+ ui64 sum = 0;
+ for (const auto& item : value) {
+ sum += item.Duration;
+ }
+ sum = sum * 1000000 / cyclesPerMs;
+ s << key << " num# " << value.size() << " sum# " << sum << "ns max# " << (i->Duration * 1000000 / cyclesPerMs) << "ns";
+ if (i->Interior) {
+ s << " {" << i->Interior << "}";
+ }
+ }
+ }
+
+ return s.Str();
+ }
+ };
+
+} // NActors
diff --git a/library/cpp/actors/interconnect/slowpoke_actor.h b/library/cpp/actors/interconnect/slowpoke_actor.h
new file mode 100644
index 0000000000..4b02e5da48
--- /dev/null
+++ b/library/cpp/actors/interconnect/slowpoke_actor.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <library/cpp/actors/core/actor_bootstrapped.h>
+
+namespace NActors {
+
+ class TSlowpokeActor : public TActorBootstrapped<TSlowpokeActor> {
+ const TDuration Duration;
+ const TDuration SleepMin;
+ const TDuration SleepMax;
+ const TDuration RescheduleMin;
+ const TDuration RescheduleMax;
+
+ public:
+ static constexpr NKikimrServices::TActivity::EType ActorActivityType() {
+ return NKikimrServices::TActivity::INTERCONNECT_COMMON;
+ }
+
+ TSlowpokeActor(TDuration duration, TDuration sleepMin, TDuration sleepMax, TDuration rescheduleMin, TDuration rescheduleMax)
+ : Duration(duration)
+ , SleepMin(sleepMin)
+ , SleepMax(sleepMax)
+ , RescheduleMin(rescheduleMin)
+ , RescheduleMax(rescheduleMax)
+ {}
+
+ void Bootstrap(const TActorContext& ctx) {
+ Become(&TThis::StateFunc, ctx, Duration, new TEvents::TEvPoisonPill);
+ HandleWakeup(ctx);
+ }
+
+ void HandleWakeup(const TActorContext& ctx) {
+ Sleep(RandomDuration(SleepMin, SleepMax));
+ ctx.Schedule(RandomDuration(RescheduleMin, RescheduleMax), new TEvents::TEvWakeup);
+ }
+
+ static TDuration RandomDuration(TDuration min, TDuration max) {
+ return min + TDuration::FromValue(RandomNumber<ui64>(max.GetValue() - min.GetValue() + 1));
+ }
+
+ STRICT_STFUNC(StateFunc,
+ CFunc(TEvents::TSystem::PoisonPill, Die)
+ CFunc(TEvents::TSystem::Wakeup, HandleWakeup)
+ )
+ };
+
+} // NActors
diff --git a/library/cpp/actors/interconnect/types.cpp b/library/cpp/actors/interconnect/types.cpp
new file mode 100644
index 0000000000..979c55f277
--- /dev/null
+++ b/library/cpp/actors/interconnect/types.cpp
@@ -0,0 +1,564 @@
+#include "types.h"
+#include <util/string/printf.h>
+#include <util/generic/vector.h>
+#include <errno.h>
+
+namespace NActors {
+
+ TVector<const char*> TDisconnectReason::Reasons = {
+ "EndOfStream",
+ "CloseOnIdle",
+ "LostConnection",
+ "DeadPeer",
+ "NewSession",
+ "HandshakeFailTransient",
+ "HandshakeFailPermanent",
+ "UserRequest",
+ "Debug",
+ "ChecksumError",
+ "FormatError",
+ "EventTooLarge",
+ "QueueOverload",
+ "E2BIG",
+ "EACCES",
+ "EADDRINUSE",
+ "EADDRNOTAVAIL",
+ "EADV",
+ "EAFNOSUPPORT",
+ "EAGAIN",
+ "EALREADY",
+ "EBADE",
+ "EBADF",
+ "EBADFD",
+ "EBADMSG",
+ "EBADR",
+ "EBADRQC",
+ "EBADSLT",
+ "EBFONT",
+ "EBUSY",
+ "ECANCELED",
+ "ECHILD",
+ "ECHRNG",
+ "ECOMM",
+ "ECONNABORTED",
+ "ECONNREFUSED",
+ "ECONNRESET",
+ "EDEADLK",
+ "EDEADLOCK",
+ "EDESTADDRREQ",
+ "EDOM",
+ "EDOTDOT",
+ "EDQUOT",
+ "EEXIST",
+ "EFAULT",
+ "EFBIG",
+ "EHOSTDOWN",
+ "EHOSTUNREACH",
+ "EHWPOISON",
+ "EIDRM",
+ "EILSEQ",
+ "EINPROGRESS",
+ "EINTR",
+ "EINVAL",
+ "EIO",
+ "EISCONN",
+ "EISDIR",
+ "EISNAM",
+ "EKEYEXPIRED",
+ "EKEYREJECTED",
+ "EKEYREVOKED",
+ "EL2HLT",
+ "EL2NSYNC",
+ "EL3HLT",
+ "EL3RST",
+ "ELIBACC",
+ "ELIBBAD",
+ "ELIBEXEC",
+ "ELIBMAX",
+ "ELIBSCN",
+ "ELNRNG",
+ "ELOOP",
+ "EMEDIUMTYPE",
+ "EMFILE",
+ "EMLINK",
+ "EMSGSIZE",
+ "EMULTIHOP",
+ "ENAMETOOLONG",
+ "ENAVAIL",
+ "ENETDOWN",
+ "ENETRESET",
+ "ENETUNREACH",
+ "ENFILE",
+ "ENOANO",
+ "ENOBUFS",
+ "ENOCSI",
+ "ENODATA",
+ "ENODEV",
+ "ENOENT",
+ "ENOEXEC",
+ "ENOKEY",
+ "ENOLCK",
+ "ENOLINK",
+ "ENOMEDIUM",
+ "ENOMEM",
+ "ENOMSG",
+ "ENONET",
+ "ENOPKG",
+ "ENOPROTOOPT",
+ "ENOSPC",
+ "ENOSR",
+ "ENOSTR",
+ "ENOSYS",
+ "ENOTBLK",
+ "ENOTCONN",
+ "ENOTDIR",
+ "ENOTEMPTY",
+ "ENOTNAM",
+ "ENOTRECOVERABLE",
+ "ENOTSOCK",
+ "ENOTTY",
+ "ENOTUNIQ",
+ "ENXIO",
+ "EOPNOTSUPP",
+ "EOVERFLOW",
+ "EOWNERDEAD",
+ "EPERM",
+ "EPFNOSUPPORT",
+ "EPIPE",
+ "EPROTO",
+ "EPROTONOSUPPORT",
+ "EPROTOTYPE",
+ "ERANGE",
+ "EREMCHG",
+ "EREMOTE",
+ "EREMOTEIO",
+ "ERESTART",
+ "ERFKILL",
+ "EROFS",
+ "ESHUTDOWN",
+ "ESOCKTNOSUPPORT",
+ "ESPIPE",
+ "ESRCH",
+ "ESRMNT",
+ "ESTALE",
+ "ESTRPIPE",
+ "ETIME",
+ "ETIMEDOUT",
+ "ETOOMANYREFS",
+ "ETXTBSY",
+ "EUCLEAN",
+ "EUNATCH",
+ "EUSERS",
+ "EWOULDBLOCK",
+ "EXDEV",
+ "EXFULL",
+ };
+
+ TDisconnectReason TDisconnectReason::FromErrno(int err) {
+ switch (err) {
+#define REASON(ERRNO) case ERRNO: return TDisconnectReason(TString(#ERRNO))
+#if defined(E2BIG)
+ REASON(E2BIG);
+#endif
+#if defined(EACCES)
+ REASON(EACCES);
+#endif
+#if defined(EADDRINUSE)
+ REASON(EADDRINUSE);
+#endif
+#if defined(EADDRNOTAVAIL)
+ REASON(EADDRNOTAVAIL);
+#endif
+#if defined(EADV)
+ REASON(EADV);
+#endif
+#if defined(EAFNOSUPPORT)
+ REASON(EAFNOSUPPORT);
+#endif
+#if defined(EAGAIN)
+ REASON(EAGAIN);
+#endif
+#if defined(EALREADY)
+ REASON(EALREADY);
+#endif
+#if defined(EBADE)
+ REASON(EBADE);
+#endif
+#if defined(EBADF)
+ REASON(EBADF);
+#endif
+#if defined(EBADFD)
+ REASON(EBADFD);
+#endif
+#if defined(EBADMSG)
+ REASON(EBADMSG);
+#endif
+#if defined(EBADR)
+ REASON(EBADR);
+#endif
+#if defined(EBADRQC)
+ REASON(EBADRQC);
+#endif
+#if defined(EBADSLT)
+ REASON(EBADSLT);
+#endif
+#if defined(EBFONT)
+ REASON(EBFONT);
+#endif
+#if defined(EBUSY)
+ REASON(EBUSY);
+#endif
+#if defined(ECANCELED)
+ REASON(ECANCELED);
+#endif
+#if defined(ECHILD)
+ REASON(ECHILD);
+#endif
+#if defined(ECHRNG)
+ REASON(ECHRNG);
+#endif
+#if defined(ECOMM)
+ REASON(ECOMM);
+#endif
+#if defined(ECONNABORTED)
+ REASON(ECONNABORTED);
+#endif
+#if defined(ECONNREFUSED)
+ REASON(ECONNREFUSED);
+#endif
+#if defined(ECONNRESET)
+ REASON(ECONNRESET);
+#endif
+#if defined(EDEADLK)
+ REASON(EDEADLK);
+#endif
+#if defined(EDEADLOCK) && (!defined(EDEADLK) || EDEADLOCK != EDEADLK)
+ REASON(EDEADLOCK);
+#endif
+#if defined(EDESTADDRREQ)
+ REASON(EDESTADDRREQ);
+#endif
+#if defined(EDOM)
+ REASON(EDOM);
+#endif
+#if defined(EDOTDOT)
+ REASON(EDOTDOT);
+#endif
+#if defined(EDQUOT)
+ REASON(EDQUOT);
+#endif
+#if defined(EEXIST)
+ REASON(EEXIST);
+#endif
+#if defined(EFAULT)
+ REASON(EFAULT);
+#endif
+#if defined(EFBIG)
+ REASON(EFBIG);
+#endif
+#if defined(EHOSTDOWN)
+ REASON(EHOSTDOWN);
+#endif
+#if defined(EHOSTUNREACH)
+ REASON(EHOSTUNREACH);
+#endif
+#if defined(EHWPOISON)
+ REASON(EHWPOISON);
+#endif
+#if defined(EIDRM)
+ REASON(EIDRM);
+#endif
+#if defined(EILSEQ)
+ REASON(EILSEQ);
+#endif
+#if defined(EINPROGRESS)
+ REASON(EINPROGRESS);
+#endif
+#if defined(EINTR)
+ REASON(EINTR);
+#endif
+#if defined(EINVAL)
+ REASON(EINVAL);
+#endif
+#if defined(EIO)
+ REASON(EIO);
+#endif
+#if defined(EISCONN)
+ REASON(EISCONN);
+#endif
+#if defined(EISDIR)
+ REASON(EISDIR);
+#endif
+#if defined(EISNAM)
+ REASON(EISNAM);
+#endif
+#if defined(EKEYEXPIRED)
+ REASON(EKEYEXPIRED);
+#endif
+#if defined(EKEYREJECTED)
+ REASON(EKEYREJECTED);
+#endif
+#if defined(EKEYREVOKED)
+ REASON(EKEYREVOKED);
+#endif
+#if defined(EL2HLT)
+ REASON(EL2HLT);
+#endif
+#if defined(EL2NSYNC)
+ REASON(EL2NSYNC);
+#endif
+#if defined(EL3HLT)
+ REASON(EL3HLT);
+#endif
+#if defined(EL3RST)
+ REASON(EL3RST);
+#endif
+#if defined(ELIBACC)
+ REASON(ELIBACC);
+#endif
+#if defined(ELIBBAD)
+ REASON(ELIBBAD);
+#endif
+#if defined(ELIBEXEC)
+ REASON(ELIBEXEC);
+#endif
+#if defined(ELIBMAX)
+ REASON(ELIBMAX);
+#endif
+#if defined(ELIBSCN)
+ REASON(ELIBSCN);
+#endif
+#if defined(ELNRNG)
+ REASON(ELNRNG);
+#endif
+#if defined(ELOOP)
+ REASON(ELOOP);
+#endif
+#if defined(EMEDIUMTYPE)
+ REASON(EMEDIUMTYPE);
+#endif
+#if defined(EMFILE)
+ REASON(EMFILE);
+#endif
+#if defined(EMLINK)
+ REASON(EMLINK);
+#endif
+#if defined(EMSGSIZE)
+ REASON(EMSGSIZE);
+#endif
+#if defined(EMULTIHOP)
+ REASON(EMULTIHOP);
+#endif
+#if defined(ENAMETOOLONG)
+ REASON(ENAMETOOLONG);
+#endif
+#if defined(ENAVAIL)
+ REASON(ENAVAIL);
+#endif
+#if defined(ENETDOWN)
+ REASON(ENETDOWN);
+#endif
+#if defined(ENETRESET)
+ REASON(ENETRESET);
+#endif
+#if defined(ENETUNREACH)
+ REASON(ENETUNREACH);
+#endif
+#if defined(ENFILE)
+ REASON(ENFILE);
+#endif
+#if defined(ENOANO)
+ REASON(ENOANO);
+#endif
+#if defined(ENOBUFS)
+ REASON(ENOBUFS);
+#endif
+#if defined(ENOCSI)
+ REASON(ENOCSI);
+#endif
+#if defined(ENODATA)
+ REASON(ENODATA);
+#endif
+#if defined(ENODEV)
+ REASON(ENODEV);
+#endif
+#if defined(ENOENT)
+ REASON(ENOENT);
+#endif
+#if defined(ENOEXEC)
+ REASON(ENOEXEC);
+#endif
+#if defined(ENOKEY)
+ REASON(ENOKEY);
+#endif
+#if defined(ENOLCK)
+ REASON(ENOLCK);
+#endif
+#if defined(ENOLINK)
+ REASON(ENOLINK);
+#endif
+#if defined(ENOMEDIUM)
+ REASON(ENOMEDIUM);
+#endif
+#if defined(ENOMEM)
+ REASON(ENOMEM);
+#endif
+#if defined(ENOMSG)
+ REASON(ENOMSG);
+#endif
+#if defined(ENONET)
+ REASON(ENONET);
+#endif
+#if defined(ENOPKG)
+ REASON(ENOPKG);
+#endif
+#if defined(ENOPROTOOPT)
+ REASON(ENOPROTOOPT);
+#endif
+#if defined(ENOSPC)
+ REASON(ENOSPC);
+#endif
+#if defined(ENOSR)
+ REASON(ENOSR);
+#endif
+#if defined(ENOSTR)
+ REASON(ENOSTR);
+#endif
+#if defined(ENOSYS)
+ REASON(ENOSYS);
+#endif
+#if defined(ENOTBLK)
+ REASON(ENOTBLK);
+#endif
+#if defined(ENOTCONN)
+ REASON(ENOTCONN);
+#endif
+#if defined(ENOTDIR)
+ REASON(ENOTDIR);
+#endif
+#if defined(ENOTEMPTY)
+ REASON(ENOTEMPTY);
+#endif
+#if defined(ENOTNAM)
+ REASON(ENOTNAM);
+#endif
+#if defined(ENOTRECOVERABLE)
+ REASON(ENOTRECOVERABLE);
+#endif
+#if defined(ENOTSOCK)
+ REASON(ENOTSOCK);
+#endif
+#if defined(ENOTTY)
+ REASON(ENOTTY);
+#endif
+#if defined(ENOTUNIQ)
+ REASON(ENOTUNIQ);
+#endif
+#if defined(ENXIO)
+ REASON(ENXIO);
+#endif
+#if defined(EOPNOTSUPP)
+ REASON(EOPNOTSUPP);
+#endif
+#if defined(EOVERFLOW)
+ REASON(EOVERFLOW);
+#endif
+#if defined(EOWNERDEAD)
+ REASON(EOWNERDEAD);
+#endif
+#if defined(EPERM)
+ REASON(EPERM);
+#endif
+#if defined(EPFNOSUPPORT)
+ REASON(EPFNOSUPPORT);
+#endif
+#if defined(EPIPE)
+ REASON(EPIPE);
+#endif
+#if defined(EPROTO)
+ REASON(EPROTO);
+#endif
+#if defined(EPROTONOSUPPORT)
+ REASON(EPROTONOSUPPORT);
+#endif
+#if defined(EPROTOTYPE)
+ REASON(EPROTOTYPE);
+#endif
+#if defined(ERANGE)
+ REASON(ERANGE);
+#endif
+#if defined(EREMCHG)
+ REASON(EREMCHG);
+#endif
+#if defined(EREMOTE)
+ REASON(EREMOTE);
+#endif
+#if defined(EREMOTEIO)
+ REASON(EREMOTEIO);
+#endif
+#if defined(ERESTART)
+ REASON(ERESTART);
+#endif
+#if defined(ERFKILL)
+ REASON(ERFKILL);
+#endif
+#if defined(EROFS)
+ REASON(EROFS);
+#endif
+#if defined(ESHUTDOWN)
+ REASON(ESHUTDOWN);
+#endif
+#if defined(ESOCKTNOSUPPORT)
+ REASON(ESOCKTNOSUPPORT);
+#endif
+#if defined(ESPIPE)
+ REASON(ESPIPE);
+#endif
+#if defined(ESRCH)
+ REASON(ESRCH);
+#endif
+#if defined(ESRMNT)
+ REASON(ESRMNT);
+#endif
+#if defined(ESTALE)
+ REASON(ESTALE);
+#endif
+#if defined(ESTRPIPE)
+ REASON(ESTRPIPE);
+#endif
+#if defined(ETIME)
+ REASON(ETIME);
+#endif
+#if defined(ETIMEDOUT)
+ REASON(ETIMEDOUT);
+#endif
+#if defined(ETOOMANYREFS)
+ REASON(ETOOMANYREFS);
+#endif
+#if defined(ETXTBSY)
+ REASON(ETXTBSY);
+#endif
+#if defined(EUCLEAN)
+ REASON(EUCLEAN);
+#endif
+#if defined(EUNATCH)
+ REASON(EUNATCH);
+#endif
+#if defined(EUSERS)
+ REASON(EUSERS);
+#endif
+#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || EWOULDBLOCK != EAGAIN)
+ REASON(EWOULDBLOCK);
+#endif
+#if defined(EXDEV)
+ REASON(EXDEV);
+#endif
+#if defined(EXFULL)
+ REASON(EXFULL);
+#endif
+ default:
+ return TDisconnectReason(Sprintf("errno=%d", errno));
+ }
+ }
+
+} // NActors
diff --git a/library/cpp/actors/interconnect/types.h b/library/cpp/actors/interconnect/types.h
new file mode 100644
index 0000000000..2662c50c22
--- /dev/null
+++ b/library/cpp/actors/interconnect/types.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include <util/generic/string.h>
+
+namespace NActors {
+
+ class TDisconnectReason {
+ TString Text;
+
+ private:
+ explicit TDisconnectReason(TString text)
+ : Text(std::move(text))
+ {}
+
+ public:
+ TDisconnectReason() = default;
+ TDisconnectReason(const TDisconnectReason&) = default;
+ TDisconnectReason(TDisconnectReason&&) = default;
+
+ static TDisconnectReason FromErrno(int err);
+
+ static TDisconnectReason EndOfStream() { return TDisconnectReason("EndOfStream"); }
+ static TDisconnectReason CloseOnIdle() { return TDisconnectReason("CloseOnIdle"); }
+ static TDisconnectReason LostConnection() { return TDisconnectReason("LostConnection"); }
+ static TDisconnectReason DeadPeer() { return TDisconnectReason("DeadPeer"); }
+ static TDisconnectReason NewSession() { return TDisconnectReason("NewSession"); }
+ static TDisconnectReason HandshakeFailTransient() { return TDisconnectReason("HandshakeFailTransient"); }
+ static TDisconnectReason HandshakeFailPermanent() { return TDisconnectReason("HandshakeFailPermanent"); }
+ static TDisconnectReason UserRequest() { return TDisconnectReason("UserRequest"); }
+ static TDisconnectReason Debug() { return TDisconnectReason("Debug"); }
+ static TDisconnectReason ChecksumError() { return TDisconnectReason("ChecksumError"); }
+ static TDisconnectReason FormatError() { return TDisconnectReason("FormatError"); }
+ static TDisconnectReason EventTooLarge() { return TDisconnectReason("EventTooLarge"); }
+ static TDisconnectReason QueueOverload() { return TDisconnectReason("QueueOverload"); }
+
+ TString ToString() const {
+ return Text;
+ }
+
+ static TVector<const char*> Reasons;
+ };
+
+} // NActors
diff --git a/library/cpp/actors/interconnect/ut/channel_scheduler_ut.cpp b/library/cpp/actors/interconnect/ut/channel_scheduler_ut.cpp
new file mode 100644
index 0000000000..565a511859
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut/channel_scheduler_ut.cpp
@@ -0,0 +1,115 @@
+#include <library/cpp/actors/interconnect/channel_scheduler.h>
+#include <library/cpp/actors/interconnect/events_local.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NActors;
+
+Y_UNIT_TEST_SUITE(ChannelScheduler) {
+
+ Y_UNIT_TEST(PriorityTraffic) {
+ auto common = MakeIntrusive<TInterconnectProxyCommon>();
+ common->MonCounters = MakeIntrusive<NMonitoring::TDynamicCounters>();
+ std::shared_ptr<IInterconnectMetrics> ctr = CreateInterconnectCounters(common);
+ ctr->SetPeerInfo("peer", "1");
+ auto callback = [](THolder<IEventBase>) {};
+ TEventHolderPool pool(common, callback);
+ TSessionParams p;
+ TChannelScheduler scheduler(1, {}, ctr, pool, 64 << 20, p);
+
+ ui32 numEvents = 0;
+
+ auto pushEvent = [&](size_t size, int channel) {
+ TString payload(size, 'X');
+ auto ev = MakeHolder<IEventHandle>(1, 0, TActorId(), TActorId(), MakeIntrusive<TEventSerializedData>(payload, false), 0);
+ auto& ch = scheduler.GetOutputChannel(channel);
+ const bool wasWorking = ch.IsWorking();
+ ch.Push(*ev);
+ if (!wasWorking) {
+ scheduler.AddToHeap(ch, 0);
+ }
+ ++numEvents;
+ };
+
+ for (ui32 i = 0; i < 100; ++i) {
+ pushEvent(10000, 1);
+ }
+
+ for (ui32 i = 0; i < 1000; ++i) {
+ pushEvent(1000, 2);
+ }
+
+ std::map<ui16, ui32> run;
+ ui32 step = 0;
+
+ std::deque<std::map<ui16, ui32>> window;
+
+ for (; numEvents; ++step) {
+ TTcpPacketOutTask task(p);
+
+ if (step == 100) {
+ for (ui32 i = 0; i < 200; ++i) {
+ pushEvent(1000, 3);
+ }
+ }
+
+ std::map<ui16, ui32> ch;
+
+ while (numEvents) {
+ TEventOutputChannel *channel = scheduler.PickChannelWithLeastConsumedWeight();
+ ui32 before = task.GetDataSize();
+ ui64 weightConsumed = 0;
+ numEvents -= channel->FeedBuf(task, 0, &weightConsumed);
+ ui32 after = task.GetDataSize();
+ Y_VERIFY(after >= before);
+ scheduler.FinishPick(weightConsumed, 0);
+ const ui32 bytesAdded = after - before;
+ if (!bytesAdded) {
+ break;
+ }
+ ch[channel->ChannelId] += bytesAdded;
+ }
+
+ scheduler.Equalize();
+
+ for (const auto& [key, value] : ch) {
+ run[key] += value;
+ }
+ window.push_back(ch);
+
+ if (window.size() == 32) {
+ for (const auto& [key, value] : window.front()) {
+ run[key] -= value;
+ if (!run[key]) {
+ run.erase(key);
+ }
+ }
+ window.pop_front();
+ }
+
+ double mean = 0.0;
+ for (const auto& [key, value] : run) {
+ mean += value;
+ }
+ mean /= run.size();
+
+ double dev = 0.0;
+ for (const auto& [key, value] : run) {
+ dev += (value - mean) * (value - mean);
+ }
+ dev = sqrt(dev / run.size());
+
+ double devToMean = dev / mean;
+
+ Cerr << step << ": ";
+ for (const auto& [key, value] : run) {
+ Cerr << "ch" << key << "=" << value << " ";
+ }
+ Cerr << "mean# " << mean << " dev# " << dev << " part# " << devToMean;
+
+ Cerr << Endl;
+
+ UNIT_ASSERT(devToMean < 1);
+ }
+ }
+
+}
diff --git a/library/cpp/actors/interconnect/ut/dynamic_proxy_ut.cpp b/library/cpp/actors/interconnect/ut/dynamic_proxy_ut.cpp
new file mode 100644
index 0000000000..3c474979dc
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut/dynamic_proxy_ut.cpp
@@ -0,0 +1,179 @@
+#include <library/cpp/actors/interconnect/ut/lib/node.h>
+#include <library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+TActorId MakeResponderServiceId(ui32 nodeId) {
+ return TActorId(nodeId, TStringBuf("ResponderAct", 12));
+}
+
+class TArriveQueue {
+ struct TArrivedItem {
+ ui32 QueueId;
+ ui32 Index;
+ bool Success;
+ };
+
+ TMutex Lock;
+ std::size_t Counter = 0;
+ std::vector<TArrivedItem> Items;
+
+public:
+ TArriveQueue(size_t capacity)
+ : Items(capacity)
+ {}
+
+ bool Done() const {
+ with_lock (Lock) {
+ return Counter == Items.size();
+ }
+ }
+
+ void Push(ui64 cookie, bool success) {
+ with_lock (Lock) {
+ const size_t pos = Counter++;
+ TArrivedItem item{.QueueId = static_cast<ui32>(cookie >> 32), .Index = static_cast<ui32>(cookie & 0xffff'ffff),
+ .Success = success};
+ memcpy(&Items[pos], &item, sizeof(TArrivedItem));
+ }
+ }
+
+ void Check() {
+ struct TPerQueueState {
+ std::vector<ui32> Ok, Error;
+ };
+ std::unordered_map<ui32, TPerQueueState> state;
+ for (const TArrivedItem& item : Items) {
+ auto& st = state[item.QueueId];
+ auto& v = item.Success ? st.Ok : st.Error;
+ v.push_back(item.Index);
+ }
+ for (const auto& [queueId, st] : state) {
+ ui32 expected = 0;
+ for (const ui32 index : st.Ok) {
+ Y_VERIFY(index == expected);
+ ++expected;
+ }
+ for (const ui32 index : st.Error) {
+ Y_VERIFY(index == expected);
+ ++expected;
+ }
+ if (st.Error.size()) {
+ Cerr << "Error.size# " << st.Error.size() << Endl;
+ }
+ }
+ }
+};
+
+class TResponder : public TActor<TResponder> {
+ TArriveQueue& ArriveQueue;
+
+public:
+ TResponder(TArriveQueue& arriveQueue)
+ : TActor(&TResponder::StateFunc)
+ , ArriveQueue(arriveQueue)
+ {}
+
+ STRICT_STFUNC(StateFunc,
+ hFunc(TEvents::TEvPing, Handle);
+ )
+
+ void Handle(TEvents::TEvPing::TPtr ev) {
+ ArriveQueue.Push(ev->Cookie, true);
+ }
+};
+
+class TSender : public TActor<TSender> {
+ TArriveQueue& ArriveQueue;
+
+public:
+ TSender(TArriveQueue& arriveQueue)
+ : TActor(&TThis::StateFunc)
+ , ArriveQueue(arriveQueue)
+ {}
+
+ STRICT_STFUNC(StateFunc,
+ hFunc(TEvents::TEvUndelivered, Handle);
+ )
+
+ void Handle(TEvents::TEvUndelivered::TPtr ev) {
+ ArriveQueue.Push(ev->Cookie, false);
+ }
+};
+
+void SenderThread(TMutex& lock, TActorSystem *as, ui32 nodeId, ui32 queueId, ui32 count, TArriveQueue& arriveQueue) {
+ const TActorId sender = as->Register(new TSender(arriveQueue));
+ with_lock(lock) {}
+ const TActorId target = MakeResponderServiceId(nodeId);
+ for (ui32 i = 0; i < count; ++i) {
+ const ui32 flags = IEventHandle::FlagTrackDelivery;
+ as->Send(new IEventHandle(TEvents::THelloWorld::Ping, flags, target, sender, nullptr, ((ui64)queueId << 32) | i));
+ }
+}
+
+void RaceTestIter(ui32 numThreads, ui32 count) {
+ TPortManager portman;
+ THashMap<ui32, ui16> nodeToPort;
+ const ui32 numNodes = 6; // total
+ const ui32 numDynamicNodes = 3;
+ for (ui32 i = 1; i <= numNodes; ++i) {
+ nodeToPort.emplace(i, portman.GetPort());
+ }
+
+ NMonitoring::TDynamicCounterPtr counters = new NMonitoring::TDynamicCounters;
+ std::list<TNode> nodes;
+ for (ui32 i = 1; i <= numNodes; ++i) {
+ nodes.emplace_back(i, numNodes, nodeToPort, "127.1.0.0", counters->GetSubgroup("nodeId", TStringBuilder() << i),
+ TDuration::Seconds(10), TChannelsConfig(), numDynamicNodes, numThreads);
+ }
+
+ const ui32 numSenders = 10;
+ TArriveQueue arriveQueue(numSenders * numNodes * (numNodes - 1) * count);
+ for (TNode& node : nodes) {
+ node.RegisterServiceActor(MakeResponderServiceId(node.GetActorSystem()->NodeId), new TResponder(arriveQueue));
+ }
+
+ TMutex lock;
+ std::list<TThread> threads;
+ ui32 queueId = 0;
+ with_lock(lock) {
+ for (TNode& from : nodes) {
+ for (ui32 toId = 1; toId <= numNodes; ++toId) {
+ if (toId == from.GetActorSystem()->NodeId) {
+ continue;
+ }
+ for (ui32 i = 0; i < numSenders; ++i) {
+ threads.emplace_back([=, &lock, &from, &arriveQueue] {
+ SenderThread(lock, from.GetActorSystem(), toId, queueId, count, arriveQueue);
+ });
+ ++queueId;
+ }
+ }
+ }
+ for (auto& thread : threads) {
+ thread.Start();
+ }
+ }
+ for (auto& thread : threads) {
+ thread.Join();
+ }
+
+ for (THPTimer timer; !arriveQueue.Done(); TDuration::MilliSeconds(10)) {
+ Y_VERIFY(timer.Passed() < 10);
+ }
+
+ nodes.clear();
+ arriveQueue.Check();
+}
+
+Y_UNIT_TEST_SUITE(DynamicProxy) {
+ Y_UNIT_TEST(RaceCheck1) {
+ for (ui32 iteration = 0; iteration < 100; ++iteration) {
+ RaceTestIter(1 + iteration % 5, 1);
+ }
+ }
+ Y_UNIT_TEST(RaceCheck10) {
+ for (ui32 iteration = 0; iteration < 100; ++iteration) {
+ RaceTestIter(1 + iteration % 5, 10);
+ }
+ }
+}
diff --git a/library/cpp/actors/interconnect/ut/event_holder_pool_ut.cpp b/library/cpp/actors/interconnect/ut/event_holder_pool_ut.cpp
new file mode 100644
index 0000000000..e6b2bd4e4c
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut/event_holder_pool_ut.cpp
@@ -0,0 +1,59 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/actors/core/events.h>
+#include <library/cpp/actors/core/event_local.h>
+#include <library/cpp/actors/interconnect/interconnect_common.h>
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+#include <library/cpp/actors/interconnect/event_holder_pool.h>
+
+#include <atomic>
+
+using namespace NActors;
+
+template<typename T>
+TEventHolderPool Setup(T&& callback) {
+ auto common = MakeIntrusive<TInterconnectProxyCommon>();
+ common->DestructorQueueSize = std::make_shared<std::atomic<TAtomicBase>>();
+ common->MaxDestructorQueueSize = 1024 * 1024;
+ return TEventHolderPool(common, callback);
+}
+
+Y_UNIT_TEST_SUITE(EventHolderPool) {
+
+ Y_UNIT_TEST(Overflow) {
+ TDeque<THolder<IEventBase>> freeQ;
+ auto callback = [&](THolder<IEventBase> event) {
+ freeQ.push_back(std::move(event));
+ };
+ auto pool = Setup(std::move(callback));
+
+ std::list<TEventHolder> q;
+
+ auto& ev1 = pool.Allocate(q);
+ ev1.Buffer = MakeIntrusive<TEventSerializedData>(TString::Uninitialized(512 * 1024), true);
+
+ auto& ev2 = pool.Allocate(q);
+ ev2.Buffer = MakeIntrusive<TEventSerializedData>(TString::Uninitialized(512 * 1024), true);
+
+ auto& ev3 = pool.Allocate(q);
+ ev3.Buffer = MakeIntrusive<TEventSerializedData>(TString::Uninitialized(512 * 1024), true);
+
+ auto& ev4 = pool.Allocate(q);
+ ev4.Buffer = MakeIntrusive<TEventSerializedData>(TString::Uninitialized(512 * 1024), true);
+
+ pool.Release(q, q.begin());
+ pool.Release(q, q.begin());
+ pool.Trim();
+ UNIT_ASSERT_VALUES_EQUAL(freeQ.size(), 1);
+
+ pool.Release(q, q.begin());
+ UNIT_ASSERT_VALUES_EQUAL(freeQ.size(), 1);
+
+ freeQ.clear();
+ pool.Release(q, q.begin());
+ pool.Trim();
+ UNIT_ASSERT_VALUES_EQUAL(freeQ.size(), 1);
+
+ freeQ.clear(); // if we don't this, we may probablty crash due to the order of object destruction
+ }
+
+}
diff --git a/library/cpp/actors/interconnect/ut/interconnect_ut.cpp b/library/cpp/actors/interconnect/ut/interconnect_ut.cpp
new file mode 100644
index 0000000000..8ef0b1507c
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut/interconnect_ut.cpp
@@ -0,0 +1,177 @@
+#include <library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h>
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/digest/md5/md5.h>
+#include <util/random/fast.h>
+
+using namespace NActors;
+
+class TSenderActor : public TActorBootstrapped<TSenderActor> {
+ const TActorId Recipient;
+ using TSessionToCookie = std::unordered_multimap<TActorId, ui64, THash<TActorId>>;
+ TSessionToCookie SessionToCookie;
+ std::unordered_map<ui64, std::pair<TSessionToCookie::iterator, TString>> InFlight;
+ std::unordered_map<ui64, TString> Tentative;
+ ui64 NextCookie = 0;
+ TActorId SessionId;
+ bool SubscribeInFlight = false;
+
+public:
+ TSenderActor(TActorId recipient)
+ : Recipient(recipient)
+ {}
+
+ void Bootstrap() {
+ Become(&TThis::StateFunc);
+ Subscribe();
+ }
+
+ void Subscribe() {
+ Cerr << (TStringBuilder() << "Subscribe" << Endl);
+ Y_VERIFY(!SubscribeInFlight);
+ SubscribeInFlight = true;
+ Send(TActivationContext::InterconnectProxy(Recipient.NodeId()), new TEvents::TEvSubscribe);
+ }
+
+ void IssueQueries() {
+ if (!SessionId) {
+ return;
+ }
+ while (InFlight.size() < 10) {
+ size_t len = RandomNumber<size_t>(65536) + 1;
+ TString data = TString::Uninitialized(len);
+ TReallyFastRng32 rng(RandomNumber<ui32>());
+ char *p = data.Detach();
+ for (size_t i = 0; i < len; ++i) {
+ p[i] = rng();
+ }
+ const TSessionToCookie::iterator s2cIt = SessionToCookie.emplace(SessionId, NextCookie);
+ InFlight.emplace(NextCookie, std::make_tuple(s2cIt, MD5::CalcRaw(data)));
+ TActivationContext::Send(new IEventHandle(TEvents::THelloWorld::Ping, IEventHandle::FlagTrackDelivery, Recipient,
+ SelfId(), MakeIntrusive<TEventSerializedData>(std::move(data), false), NextCookie));
+// Cerr << (TStringBuilder() << "Send# " << NextCookie << Endl);
+ ++NextCookie;
+ }
+ }
+
+ void HandlePong(TAutoPtr<IEventHandle> ev) {
+// Cerr << (TStringBuilder() << "Receive# " << ev->Cookie << Endl);
+ if (const auto it = InFlight.find(ev->Cookie); it != InFlight.end()) {
+ auto& [s2cIt, hash] = it->second;
+ Y_VERIFY(hash == ev->GetChainBuffer()->GetString());
+ SessionToCookie.erase(s2cIt);
+ InFlight.erase(it);
+ } else if (const auto it = Tentative.find(ev->Cookie); it != Tentative.end()) {
+ Y_VERIFY(it->second == ev->GetChainBuffer()->GetString());
+ Tentative.erase(it);
+ } else {
+ Y_FAIL("Cookie# %" PRIu64, ev->Cookie);
+ }
+ IssueQueries();
+ }
+
+ void Handle(TEvInterconnect::TEvNodeConnected::TPtr ev) {
+ Cerr << (TStringBuilder() << "TEvNodeConnected" << Endl);
+ Y_VERIFY(SubscribeInFlight);
+ SubscribeInFlight = false;
+ Y_VERIFY(!SessionId);
+ SessionId = ev->Sender;
+ IssueQueries();
+ }
+
+ void Handle(TEvInterconnect::TEvNodeDisconnected::TPtr ev) {
+ Cerr << (TStringBuilder() << "TEvNodeDisconnected" << Endl);
+ SubscribeInFlight = false;
+ if (SessionId) {
+ Y_VERIFY(SessionId == ev->Sender);
+ auto r = SessionToCookie.equal_range(SessionId);
+ for (auto it = r.first; it != r.second; ++it) {
+ const auto inFlightIt = InFlight.find(it->second);
+ Y_VERIFY(inFlightIt != InFlight.end());
+ Tentative.emplace(inFlightIt->first, inFlightIt->second.second);
+ InFlight.erase(it->second);
+ }
+ SessionToCookie.erase(r.first, r.second);
+ SessionId = TActorId();
+ }
+ Schedule(TDuration::MilliSeconds(100), new TEvents::TEvWakeup);
+ }
+
+ void Handle(TEvents::TEvUndelivered::TPtr ev) {
+ Cerr << (TStringBuilder() << "TEvUndelivered Cookie# " << ev->Cookie << Endl);
+ if (const auto it = InFlight.find(ev->Cookie); it != InFlight.end()) {
+ auto& [s2cIt, hash] = it->second;
+ Tentative.emplace(it->first, hash);
+ SessionToCookie.erase(s2cIt);
+ InFlight.erase(it);
+ IssueQueries();
+ }
+ }
+
+ STRICT_STFUNC(StateFunc,
+ fFunc(TEvents::THelloWorld::Pong, HandlePong);
+ hFunc(TEvInterconnect::TEvNodeConnected, Handle);
+ hFunc(TEvInterconnect::TEvNodeDisconnected, Handle);
+ hFunc(TEvents::TEvUndelivered, Handle);
+ cFunc(TEvents::TSystem::Wakeup, Subscribe);
+ )
+};
+
+class TRecipientActor : public TActor<TRecipientActor> {
+public:
+ TRecipientActor()
+ : TActor(&TThis::StateFunc)
+ {}
+
+ void HandlePing(TAutoPtr<IEventHandle>& ev) {
+ const TString& data = ev->GetChainBuffer()->GetString();
+ const TString& response = MD5::CalcRaw(data);
+ TActivationContext::Send(new IEventHandle(TEvents::THelloWorld::Pong, 0, ev->Sender, SelfId(),
+ MakeIntrusive<TEventSerializedData>(response, false), ev->Cookie));
+ }
+
+ STRICT_STFUNC(StateFunc,
+ fFunc(TEvents::THelloWorld::Ping, HandlePing);
+ )
+};
+
+Y_UNIT_TEST_SUITE(Interconnect) {
+
+ Y_UNIT_TEST(SessionContinuation) {
+ TTestICCluster cluster(2);
+ const TActorId recipient = cluster.RegisterActor(new TRecipientActor, 1);
+ cluster.RegisterActor(new TSenderActor(recipient), 2);
+ for (ui32 i = 0; i < 100; ++i) {
+ const ui32 nodeId = 1 + RandomNumber(2u);
+ const ui32 peerNodeId = 3 - nodeId;
+ const ui32 action = RandomNumber(3u);
+ auto *node = cluster.GetNode(nodeId);
+ TActorId proxyId = node->InterconnectProxy(peerNodeId);
+
+ switch (action) {
+ case 0:
+ node->Send(proxyId, new TEvInterconnect::TEvClosePeerSocket);
+ Cerr << (TStringBuilder() << "nodeId# " << nodeId << " peerNodeId# " << peerNodeId
+ << " TEvClosePeerSocket" << Endl);
+ break;
+
+ case 1:
+ node->Send(proxyId, new TEvInterconnect::TEvCloseInputSession);
+ Cerr << (TStringBuilder() << "nodeId# " << nodeId << " peerNodeId# " << peerNodeId
+ << " TEvCloseInputSession" << Endl);
+ break;
+
+ case 2:
+ node->Send(proxyId, new TEvInterconnect::TEvPoisonSession);
+ Cerr << (TStringBuilder() << "nodeId# " << nodeId << " peerNodeId# " << peerNodeId
+ << " TEvPoisonSession" << Endl);
+ break;
+
+ default:
+ Y_FAIL();
+ }
+
+ Sleep(TDuration::MilliSeconds(RandomNumber<ui32>(500) + 100));
+ }
+ }
+
+}
diff --git a/library/cpp/actors/interconnect/ut/large.cpp b/library/cpp/actors/interconnect/ut/large.cpp
new file mode 100644
index 0000000000..ba2a50c6f6
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut/large.cpp
@@ -0,0 +1,85 @@
+#include "lib/ic_test_cluster.h"
+#include "lib/test_events.h"
+#include "lib/test_actors.h"
+
+#include <library/cpp/actors/interconnect/interconnect_tcp_proxy.h>
+
+#include <library/cpp/testing/unittest/tests_data.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/system/event.h>
+#include <util/system/sanitizers.h>
+
+Y_UNIT_TEST_SUITE(LargeMessage) {
+ using namespace NActors;
+
+ class TProducer: public TActorBootstrapped<TProducer> {
+ const TActorId RecipientActorId;
+
+ public:
+ TProducer(const TActorId& recipientActorId)
+ : RecipientActorId(recipientActorId)
+ {}
+
+ void Bootstrap(const TActorContext& ctx) {
+ Become(&TThis::StateFunc);
+ ctx.Send(RecipientActorId, new TEvTest(1, "hello"), IEventHandle::FlagTrackDelivery, 1);
+ ctx.Send(RecipientActorId, new TEvTest(2, TString(128 * 1024 * 1024, 'X')), IEventHandle::FlagTrackDelivery, 2);
+ }
+
+ void Handle(TEvents::TEvUndelivered::TPtr ev, const TActorContext& ctx) {
+ if (ev->Cookie == 2) {
+ Cerr << "TEvUndelivered\n";
+ ctx.Send(RecipientActorId, new TEvTest(3, "hello"), IEventHandle::FlagTrackDelivery, 3);
+ }
+ }
+
+ STRICT_STFUNC(StateFunc,
+ HFunc(TEvents::TEvUndelivered, Handle)
+ )
+ };
+
+ class TConsumer : public TActorBootstrapped<TConsumer> {
+ TManualEvent& Done;
+ TActorId SessionId;
+
+ public:
+ TConsumer(TManualEvent& done)
+ : Done(done)
+ {
+ }
+
+ void Bootstrap(const TActorContext& /*ctx*/) {
+ Become(&TThis::StateFunc);
+ }
+
+ void Handle(TEvTest::TPtr ev, const TActorContext& /*ctx*/) {
+ const auto& record = ev->Get()->Record;
+ Cerr << "RECEIVED TEvTest\n";
+ if (record.GetSequenceNumber() == 1) {
+ Y_VERIFY(!SessionId);
+ SessionId = ev->InterconnectSession;
+ } else if (record.GetSequenceNumber() == 3) {
+ Y_VERIFY(SessionId != ev->InterconnectSession);
+ Done.Signal();
+ } else {
+ Y_FAIL("incorrect sequence number");
+ }
+ }
+
+ STRICT_STFUNC(StateFunc,
+ HFunc(TEvTest, Handle)
+ )
+ };
+
+ Y_UNIT_TEST(Test) {
+ TTestICCluster testCluster(2);
+
+ TManualEvent done;
+ TConsumer* consumer = new TConsumer(done);
+ const TActorId recp = testCluster.RegisterActor(consumer, 1);
+ testCluster.RegisterActor(new TProducer(recp), 2);
+ done.WaitI();
+ }
+
+}
diff --git a/library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h b/library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h
new file mode 100644
index 0000000000..2b6d27cd3f
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h
@@ -0,0 +1,84 @@
+#pragma once
+
+#include "node.h"
+#include "interrupter.h"
+
+#include <library/cpp/actors/interconnect/interconnect_tcp_proxy.h>
+#include <library/cpp/actors/core/events.h>
+#include <library/cpp/testing/unittest/tests_data.h>
+
+#include <util/generic/noncopyable.h>
+
+class TTestICCluster: public TNonCopyable {
+public:
+ struct TTrafficInterrupterSettings {
+ TDuration RejectingTrafficTimeout;
+ double BandWidth;
+ bool Disconnect;
+ };
+
+private:
+ const ui32 NumNodes;
+ const TString Address = "::1";
+ TDuration DeadPeerTimeout = TDuration::Seconds(2);
+ NMonitoring::TDynamicCounterPtr Counters;
+ THashMap<ui32, THolder<TNode>> Nodes;
+ TList<TTrafficInterrupter> interrupters;
+ NActors::TChannelsConfig ChannelsConfig;
+ TPortManager PortManager;
+
+public:
+ TTestICCluster(ui32 numNodes = 1, NActors::TChannelsConfig channelsConfig = NActors::TChannelsConfig(),
+ TTrafficInterrupterSettings* tiSettings = nullptr)
+ : NumNodes(numNodes)
+ , Counters(new NMonitoring::TDynamicCounters)
+ , ChannelsConfig(channelsConfig)
+ {
+ THashMap<ui32, ui16> nodeToPortMap;
+ THashMap<ui32, THashMap<ui32, ui16>> specificNodePortMap;
+
+ for (ui32 i = 1; i <= NumNodes; ++i) {
+ nodeToPortMap.emplace(i, PortManager.GetPort());
+ }
+
+ if (tiSettings) {
+ ui32 nodeId;
+ ui16 listenPort;
+ ui16 forwardPort;
+ for (auto& item : nodeToPortMap) {
+ nodeId = item.first;
+ listenPort = item.second;
+ forwardPort = PortManager.GetPort();
+
+ specificNodePortMap[nodeId] = nodeToPortMap;
+ specificNodePortMap[nodeId].at(nodeId) = forwardPort;
+ interrupters.emplace_back(Address, listenPort, forwardPort, tiSettings->RejectingTrafficTimeout, tiSettings->BandWidth, tiSettings->Disconnect);
+ interrupters.back().Start();
+ }
+ }
+
+ for (ui32 i = 1; i <= NumNodes; ++i) {
+ auto& portMap = tiSettings ? specificNodePortMap[i] : nodeToPortMap;
+ Nodes.emplace(i, MakeHolder<TNode>(i, NumNodes, portMap, Address, Counters, DeadPeerTimeout, ChannelsConfig));
+ }
+ }
+
+ TNode* GetNode(ui32 id) {
+ return Nodes[id].Get();
+ }
+
+ ~TTestICCluster() {
+ }
+
+ TActorId RegisterActor(NActors::IActor* actor, ui32 nodeId) {
+ return Nodes[nodeId]->RegisterActor(actor);
+ }
+
+ TActorId InterconnectProxy(ui32 peerNodeId, ui32 nodeId) {
+ return Nodes[nodeId]->InterconnectProxy(peerNodeId);
+ }
+
+ void KillActor(ui32 nodeId, const TActorId& id) {
+ Nodes[nodeId]->Send(id, new NActors::TEvents::TEvPoisonPill);
+ }
+};
diff --git a/library/cpp/actors/interconnect/ut/lib/interrupter.h b/library/cpp/actors/interconnect/ut/lib/interrupter.h
new file mode 100644
index 0000000000..48851de2c5
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut/lib/interrupter.h
@@ -0,0 +1,249 @@
+#pragma once
+
+#include <library/cpp/testing/unittest/tests_data.h>
+
+#include <util/network/sock.h>
+#include <util/network/poller.h>
+#include <util/system/thread.h>
+#include <util/system/hp_timer.h>
+#include <util/generic/list.h>
+#include <util/generic/set.h>
+#include <util/generic/vector.h>
+#include <util/generic/deque.h>
+#include <util/random/random.h>
+
+#include <iterator>
+
+class TTrafficInterrupter
+ : public ISimpleThread {
+ const TString Address;
+ const ui16 ForwardPort;
+ TInet6StreamSocket ListenSocket;
+
+ struct TConnectionDescriptor;
+ struct TDelayedPacket {
+ TInet6StreamSocket* ForwardSocket = nullptr;
+ TVector<char> Data;
+ };
+ struct TCompare {
+ bool operator()(const std::pair<TInstant, TDelayedPacket>& x, const std::pair<TInstant, TDelayedPacket>& y) const {
+ return x.first > y.first;
+ };
+ };
+
+ struct TDirectedConnection {
+ TInet6StreamSocket* Source = nullptr;
+ TInet6StreamSocket* Destination = nullptr;
+ TList<TConnectionDescriptor>::iterator ListIterator;
+ TInstant Timestamp;
+ TPriorityQueue<std::pair<TInstant, TDelayedPacket>, TVector<std::pair<TInstant, TDelayedPacket>>, TCompare> DelayedQueue;
+
+ TDirectedConnection(TInet6StreamSocket* source, TInet6StreamSocket* destination)
+ : Source(source)
+ , Destination(destination)
+ {
+ }
+ };
+
+ struct TConnectionDescriptor {
+ std::unique_ptr<TInet6StreamSocket> FirstSocket;
+ std::unique_ptr<TInet6StreamSocket> SecondSocket;
+ TDirectedConnection ForwardConnection;
+ TDirectedConnection BackwardConnection;
+
+ TConnectionDescriptor(std::unique_ptr<TInet6StreamSocket> firstSock,
+ std::unique_ptr<TInet6StreamSocket> secondSock)
+ : FirstSocket(std::move(firstSock))
+ , SecondSocket(std::move(secondSock))
+ , ForwardConnection(FirstSocket.get(), SecondSocket.get())
+ , BackwardConnection(SecondSocket.get(), FirstSocket.get())
+ {
+ }
+ };
+
+ template <class It = TList<TConnectionDescriptor>::iterator>
+ class TCustomListIteratorCompare {
+ public:
+ bool operator()(const It& it1, const It& it2) const {
+ return (&(*it1) < &(*it2));
+ }
+ };
+
+ TList<TConnectionDescriptor> Connections;
+ TSet<TList<TConnectionDescriptor>::iterator, TCustomListIteratorCompare<>> DroppedConnections;
+
+public:
+ TTrafficInterrupter(TString address, ui16 listenPort, ui16 forwardPort, TDuration rejectingTrafficTimeout, double bandwidth, bool disconnect = true)
+ : Address(std::move(address))
+ , ForwardPort(forwardPort)
+ , ListenSocket()
+ , RejectingTrafficTimeout(rejectingTrafficTimeout)
+ , CurrentRejectingTimeout(rejectingTrafficTimeout)
+ , RejectingStateTimer()
+ , Bandwidth(bandwidth)
+ , Disconnect(disconnect)
+ , RejectingTraffic(false)
+ {
+ SetReuseAddressAndPort(ListenSocket);
+ TSockAddrInet6 addr(Address.data(), listenPort);
+ Y_VERIFY(ListenSocket.Bind(&addr) == 0);
+ Y_VERIFY(ListenSocket.Listen(5) == 0);
+
+ DelayTraffic = (Bandwidth == 0.0) ? false : true;
+
+ ForwardAddrress.Reset(new TSockAddrInet6(Address.data(), ForwardPort));
+ const ui32 BufSize = DelayTraffic ? 4096 : 65536 + 4096;
+ Buf.resize(BufSize);
+ }
+
+ ~TTrafficInterrupter() {
+ AtomicSet(Running, 0);
+ this->Join();
+ }
+
+private:
+ TAtomic Running = 1;
+ TVector<char> Buf;
+ TSocketPoller SocketPoller;
+ THolder<TSockAddrInet6> ForwardAddrress;
+ TVector<void*> Events;
+ TDuration RejectingTrafficTimeout;
+ TDuration CurrentRejectingTimeout;
+ TDuration DefaultPollTimeout = TDuration::MilliSeconds(100);
+ TDuration DisconnectTimeout = TDuration::MilliSeconds(100);
+ THPTimer RejectingStateTimer;
+ THPTimer DisconnectTimer;
+ double Bandwidth;
+ const bool Disconnect;
+ bool RejectingTraffic;
+ bool DelayTraffic;
+
+ void UpdateRejectingState() {
+ if (TDuration::Seconds(std::abs(RejectingStateTimer.Passed())) > CurrentRejectingTimeout) {
+ RejectingStateTimer.Reset();
+ CurrentRejectingTimeout = (RandomNumber<ui32>(1) ? RejectingTrafficTimeout + TDuration::Seconds(1.0) : RejectingTrafficTimeout - TDuration::Seconds(0.2));
+ RejectingTraffic = !RejectingTraffic;
+ }
+ }
+
+ void RandomlyDisconnect() {
+ if (TDuration::Seconds(std::abs(DisconnectTimer.Passed())) > DisconnectTimeout) {
+ DisconnectTimer.Reset();
+ if (RandomNumber<ui32>(100) > 90) {
+ if (!Connections.empty()) {
+ auto it = Connections.begin();
+ std::advance(it, RandomNumber<ui32>(Connections.size()));
+ SocketPoller.Unwait(static_cast<SOCKET>(*it->FirstSocket.get()));
+ SocketPoller.Unwait(static_cast<SOCKET>(*it->SecondSocket.get()));
+ Connections.erase(it);
+ }
+ }
+ }
+ }
+
+ void* ThreadProc() override {
+ int pollReadyCount = 0;
+ SocketPoller.WaitRead(static_cast<SOCKET>(ListenSocket), &ListenSocket);
+ Events.resize(10);
+
+ while (AtomicGet(Running)) {
+ if (RejectingTrafficTimeout != TDuration::Zero()) {
+ UpdateRejectingState();
+ }
+ if (Disconnect) {
+ RandomlyDisconnect();
+ }
+ if (!RejectingTraffic) {
+ TDuration timeout = DefaultPollTimeout;
+ auto updateTimout = [&timeout](TDirectedConnection& conn) {
+ if (conn.DelayedQueue) {
+ timeout = Min(timeout, conn.DelayedQueue.top().first - TInstant::Now());
+ }
+ };
+ for (auto& it : Connections) {
+ updateTimout(it.ForwardConnection);
+ updateTimout(it.BackwardConnection);
+ }
+ pollReadyCount = SocketPoller.WaitT(Events.data(), Events.size(), timeout);
+ if (pollReadyCount > 0) {
+ for (int i = 0; i < pollReadyCount; i++) {
+ HandleSocketPollEvent(Events[i]);
+ }
+ for (auto it : DroppedConnections) {
+ Connections.erase(it);
+ }
+ DroppedConnections.clear();
+ }
+ }
+ if (DelayTraffic) { // process packets from DelayQueues
+ auto processDelayedPackages = [](TDirectedConnection& conn) {
+ while (!conn.DelayedQueue.empty()) {
+ auto& frontPackage = conn.DelayedQueue.top();
+ if (TInstant::Now() >= frontPackage.first) {
+ TInet6StreamSocket* sock = frontPackage.second.ForwardSocket;
+ if (sock) {
+ sock->Send(frontPackage.second.Data.data(), frontPackage.second.Data.size());
+ }
+ conn.DelayedQueue.pop();
+ } else {
+ break;
+ }
+ }
+ };
+ for (auto& it : Connections) {
+ processDelayedPackages(it.ForwardConnection);
+ processDelayedPackages(it.BackwardConnection);
+ }
+ }
+ }
+ ListenSocket.Close();
+ return nullptr;
+ }
+
+ void HandleSocketPollEvent(void* ev) {
+ if (ev == static_cast<void*>(&ListenSocket)) {
+ TSockAddrInet6 origin;
+ Connections.emplace_back(TConnectionDescriptor(std::unique_ptr<TInet6StreamSocket>(new TInet6StreamSocket), std::unique_ptr<TInet6StreamSocket>(new TInet6StreamSocket)));
+ int err = ListenSocket.Accept(Connections.back().FirstSocket.get(), &origin);
+ if (!err) {
+ err = Connections.back().SecondSocket->Connect(ForwardAddrress.Get());
+ if (!err) {
+ Connections.back().ForwardConnection.ListIterator = --Connections.end();
+ Connections.back().BackwardConnection.ListIterator = --Connections.end();
+ SocketPoller.WaitRead(static_cast<SOCKET>(*Connections.back().FirstSocket), &Connections.back().ForwardConnection);
+ SocketPoller.WaitRead(static_cast<SOCKET>(*Connections.back().SecondSocket), &Connections.back().BackwardConnection);
+ } else {
+ Connections.back().FirstSocket->Close();
+ }
+ } else {
+ Connections.pop_back();
+ }
+ } else {
+ TDirectedConnection* directedConnection = static_cast<TDirectedConnection*>(ev);
+ int recvSize = 0;
+ do {
+ recvSize = directedConnection->Source->Recv(Buf.data(), Buf.size());
+ } while (recvSize == -EINTR);
+
+ if (recvSize > 0) {
+ if (DelayTraffic) {
+ // put packet into DelayQueue
+ const TDuration baseDelay = TDuration::MicroSeconds(recvSize * 1e6 / Bandwidth);
+ const TInstant now = TInstant::Now();
+ directedConnection->Timestamp = Max(now, directedConnection->Timestamp) + baseDelay;
+ TDelayedPacket pkt;
+ pkt.ForwardSocket = directedConnection->Destination;
+ pkt.Data.resize(recvSize);
+ memcpy(pkt.Data.data(), Buf.data(), recvSize);
+ directedConnection->DelayedQueue.emplace(directedConnection->Timestamp, std::move(pkt));
+ } else {
+ directedConnection->Destination->Send(Buf.data(), recvSize);
+ }
+ } else {
+ SocketPoller.Unwait(static_cast<SOCKET>(*directedConnection->Source));
+ SocketPoller.Unwait(static_cast<SOCKET>(*directedConnection->Destination));
+ DroppedConnections.emplace(directedConnection->ListIterator);
+ }
+ }
+ }
+};
diff --git a/library/cpp/actors/interconnect/ut/lib/node.h b/library/cpp/actors/interconnect/ut/lib/node.h
new file mode 100644
index 0000000000..ff30b1445e
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut/lib/node.h
@@ -0,0 +1,137 @@
+#pragma once
+
+#include <library/cpp/actors/core/actorsystem.h>
+#include <library/cpp/actors/core/executor_pool_basic.h>
+#include <library/cpp/actors/core/scheduler_basic.h>
+#include <library/cpp/actors/core/mailbox.h>
+#include <library/cpp/actors/dnsresolver/dnsresolver.h>
+
+#include <library/cpp/actors/interconnect/interconnect_tcp_server.h>
+#include <library/cpp/actors/interconnect/interconnect_tcp_proxy.h>
+#include <library/cpp/actors/interconnect/interconnect_proxy_wrapper.h>
+
+using namespace NActors;
+
+class TNode {
+ THolder<TActorSystem> ActorSystem;
+
+public:
+ TNode(ui32 nodeId, ui32 numNodes, const THashMap<ui32, ui16>& nodeToPort, const TString& address,
+ NMonitoring::TDynamicCounterPtr counters, TDuration deadPeerTimeout,
+ TChannelsConfig channelsSettings = TChannelsConfig(),
+ ui32 numDynamicNodes = 0, ui32 numThreads = 1) {
+ TActorSystemSetup setup;
+ setup.NodeId = nodeId;
+ setup.ExecutorsCount = 1;
+ setup.Executors.Reset(new TAutoPtr<IExecutorPool>[setup.ExecutorsCount]);
+ for (ui32 i = 0; i < setup.ExecutorsCount; ++i) {
+ setup.Executors[i].Reset(new TBasicExecutorPool(i, numThreads, 20 /* magic number */));
+ }
+ setup.Scheduler.Reset(new TBasicSchedulerThread());
+ const ui32 interconnectPoolId = 0;
+
+ auto common = MakeIntrusive<TInterconnectProxyCommon>();
+ common->NameserviceId = GetNameserviceActorId();
+ common->MonCounters = counters->GetSubgroup("nodeId", ToString(nodeId));
+ common->ChannelsConfig = channelsSettings;
+ common->ClusterUUID = "cluster";
+ common->AcceptUUID = {common->ClusterUUID};
+ common->TechnicalSelfHostName = address;
+ common->Settings.Handshake = TDuration::Seconds(1);
+ common->Settings.DeadPeer = deadPeerTimeout;
+ common->Settings.CloseOnIdle = TDuration::Minutes(1);
+ common->Settings.SendBufferDieLimitInMB = 512;
+ common->Settings.TotalInflightAmountOfData = 512 * 1024;
+ common->Settings.TCPSocketBufferSize = 2048 * 1024;
+
+ setup.Interconnect.ProxyActors.resize(numNodes + 1 - numDynamicNodes);
+ setup.Interconnect.ProxyWrapperFactory = CreateProxyWrapperFactory(common, interconnectPoolId);
+
+ for (ui32 i = 1; i <= numNodes; ++i) {
+ if (i == nodeId) {
+ // create listener actor for local node "nodeId"
+ setup.LocalServices.emplace_back(TActorId(), TActorSetupCmd(new TInterconnectListenerTCP(address,
+ nodeToPort.at(nodeId), common), TMailboxType::ReadAsFilled, interconnectPoolId));
+ } else if (i <= numNodes - numDynamicNodes) {
+ // create proxy actor to reach node "i"
+ setup.Interconnect.ProxyActors[i] = {new TInterconnectProxyTCP(i, common),
+ TMailboxType::ReadAsFilled, interconnectPoolId};
+ }
+ }
+
+ setup.LocalServices.emplace_back(MakePollerActorId(), TActorSetupCmd(CreatePollerActor(),
+ TMailboxType::ReadAsFilled, 0));
+
+ const TActorId loggerActorId(0, "logger");
+ constexpr ui32 LoggerComponentId = 410; // NKikimrServices::LOGGER
+
+ auto loggerSettings = MakeIntrusive<NLog::TSettings>(
+ loggerActorId,
+ (NLog::EComponent)LoggerComponentId,
+ NLog::PRI_INFO,
+ NLog::PRI_DEBUG,
+ 0U);
+
+ loggerSettings->Append(
+ NActorsServices::EServiceCommon_MIN,
+ NActorsServices::EServiceCommon_MAX,
+ NActorsServices::EServiceCommon_Name
+ );
+
+ constexpr ui32 WilsonComponentId = 430; // NKikimrServices::WILSON
+ static const TString WilsonComponentName = "WILSON";
+
+ loggerSettings->Append(
+ (NLog::EComponent)WilsonComponentId,
+ (NLog::EComponent)WilsonComponentId + 1,
+ [](NLog::EComponent) -> const TString & { return WilsonComponentName; });
+
+ // register nameserver table
+ auto names = MakeIntrusive<TTableNameserverSetup>();
+ for (ui32 i = 1; i <= numNodes; ++i) {
+ names->StaticNodeTable[i] = TTableNameserverSetup::TNodeInfo(address, address, nodeToPort.at(i));
+ }
+ setup.LocalServices.emplace_back(
+ NDnsResolver::MakeDnsResolverActorId(),
+ TActorSetupCmd(
+ NDnsResolver::CreateOnDemandDnsResolver(),
+ TMailboxType::ReadAsFilled, interconnectPoolId));
+ setup.LocalServices.emplace_back(GetNameserviceActorId(), TActorSetupCmd(
+ CreateNameserverTable(names, interconnectPoolId), TMailboxType::ReadAsFilled,
+ interconnectPoolId));
+
+ // register logger
+ setup.LocalServices.emplace_back(loggerActorId, TActorSetupCmd(new TLoggerActor(loggerSettings,
+ CreateStderrBackend(), counters->GetSubgroup("subsystem", "logger")),
+ TMailboxType::ReadAsFilled, interconnectPoolId));
+
+ auto sp = MakeHolder<TActorSystemSetup>(std::move(setup));
+ ActorSystem.Reset(new TActorSystem(sp, nullptr, loggerSettings));
+ ActorSystem->Start();
+ }
+
+ ~TNode() {
+ ActorSystem->Stop();
+ }
+
+ bool Send(const TActorId& recipient, IEventBase* ev) {
+ return ActorSystem->Send(recipient, ev);
+ }
+
+ TActorId RegisterActor(IActor* actor) {
+ return ActorSystem->Register(actor);
+ }
+
+ TActorId InterconnectProxy(ui32 peerNodeId) {
+ return ActorSystem->InterconnectProxy(peerNodeId);
+ }
+
+ void RegisterServiceActor(const TActorId& serviceId, IActor* actor) {
+ const TActorId actorId = ActorSystem->Register(actor);
+ ActorSystem->RegisterLocalService(serviceId, actorId);
+ }
+
+ TActorSystem *GetActorSystem() const {
+ return ActorSystem.Get();
+ }
+};
diff --git a/library/cpp/actors/interconnect/ut/lib/test_actors.h b/library/cpp/actors/interconnect/ut/lib/test_actors.h
new file mode 100644
index 0000000000..7591200471
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut/lib/test_actors.h
@@ -0,0 +1,83 @@
+#pragma once
+
+namespace NActors {
+ class TSenderBaseActor: public TActorBootstrapped<TSenderBaseActor> {
+ protected:
+ const TActorId RecipientActorId;
+ const ui32 Preload;
+ ui64 SequenceNumber = 0;
+ ui32 InFlySize = 0;
+
+ public:
+ TSenderBaseActor(const TActorId& recipientActorId, ui32 preload = 1)
+ : RecipientActorId(recipientActorId)
+ , Preload(preload)
+ {
+ }
+
+ virtual ~TSenderBaseActor() {
+ }
+
+ virtual void Bootstrap(const TActorContext& ctx) {
+ Become(&TSenderBaseActor::StateFunc);
+ ctx.Send(ctx.ExecutorThread.ActorSystem->InterconnectProxy(RecipientActorId.NodeId()), new TEvInterconnect::TEvConnectNode);
+ }
+
+ virtual void SendMessagesIfPossible(const TActorContext& ctx) {
+ while (InFlySize < Preload) {
+ SendMessage(ctx);
+ }
+ }
+
+ virtual void SendMessage(const TActorContext& /*ctx*/) {
+ ++SequenceNumber;
+ }
+
+ virtual void Handle(TEvents::TEvUndelivered::TPtr& /*ev*/, const TActorContext& ctx) {
+ SendMessage(ctx);
+ }
+
+ virtual void Handle(TEvTestResponse::TPtr& /*ev*/, const TActorContext& ctx) {
+ SendMessagesIfPossible(ctx);
+ }
+
+ void Handle(TEvInterconnect::TEvNodeConnected::TPtr& /*ev*/, const TActorContext& ctx) {
+ SendMessagesIfPossible(ctx);
+ }
+
+ void Handle(TEvInterconnect::TEvNodeDisconnected::TPtr& /*ev*/, const TActorContext& /*ctx*/) {
+ }
+
+ virtual void Handle(TEvents::TEvPoisonPill::TPtr& /*ev*/, const TActorContext& ctx) {
+ Die(ctx);
+ }
+
+ virtual STRICT_STFUNC(StateFunc,
+ HFunc(TEvTestResponse, Handle)
+ HFunc(TEvents::TEvUndelivered, Handle)
+ HFunc(TEvents::TEvPoisonPill, Handle)
+ HFunc(TEvInterconnect::TEvNodeConnected, Handle)
+ HFunc(TEvInterconnect::TEvNodeDisconnected, Handle)
+ )
+ };
+
+ class TReceiverBaseActor: public TActor<TReceiverBaseActor> {
+ protected:
+ ui64 ReceivedCount = 0;
+
+ public:
+ TReceiverBaseActor()
+ : TActor(&TReceiverBaseActor::StateFunc)
+ {
+ }
+
+ virtual ~TReceiverBaseActor() {
+ }
+
+ virtual STRICT_STFUNC(StateFunc,
+ HFunc(TEvTest, Handle)
+ )
+
+ virtual void Handle(TEvTest::TPtr& /*ev*/, const TActorContext& /*ctx*/) {}
+ };
+}
diff --git a/library/cpp/actors/interconnect/ut/lib/test_events.h b/library/cpp/actors/interconnect/ut/lib/test_events.h
new file mode 100644
index 0000000000..cd0d9e0152
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut/lib/test_events.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <library/cpp/actors/interconnect/ut/protos/interconnect_test.pb.h>
+
+namespace NActors {
+ enum {
+ EvTest = EventSpaceBegin(TEvents::ES_PRIVATE),
+ EvTestChan,
+ EvTestSmall,
+ EvTestLarge,
+ EvTestResponse,
+ };
+
+ struct TEvTest : TEventPB<TEvTest, NInterconnectTest::TEvTest, EvTest> {
+ TEvTest() = default;
+
+ TEvTest(ui64 sequenceNumber, const TString& payload) {
+ Record.SetSequenceNumber(sequenceNumber);
+ Record.SetPayload(payload);
+ }
+ };
+
+ struct TEvTestLarge : TEventPB<TEvTestLarge, NInterconnectTest::TEvTestLarge, EvTestLarge> {
+ TEvTestLarge() = default;
+
+ TEvTestLarge(ui64 sequenceNumber, const TString& payload) {
+ Record.SetSequenceNumber(sequenceNumber);
+ Record.SetPayload(payload);
+ }
+ };
+
+ struct TEvTestSmall : TEventPB<TEvTestSmall, NInterconnectTest::TEvTestSmall, EvTestSmall> {
+ TEvTestSmall() = default;
+
+ TEvTestSmall(ui64 sequenceNumber, const TString& payload) {
+ Record.SetSequenceNumber(sequenceNumber);
+ Record.SetPayload(payload);
+ }
+ };
+
+ struct TEvTestResponse : TEventPB<TEvTestResponse, NInterconnectTest::TEvTestResponse, EvTestResponse> {
+ TEvTestResponse() = default;
+
+ TEvTestResponse(ui64 confirmedSequenceNumber) {
+ Record.SetConfirmedSequenceNumber(confirmedSequenceNumber);
+ }
+ };
+
+}
diff --git a/library/cpp/actors/interconnect/ut/lib/ya.make b/library/cpp/actors/interconnect/ut/lib/ya.make
new file mode 100644
index 0000000000..80f45f364f
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut/lib/ya.make
@@ -0,0 +1,12 @@
+LIBRARY()
+
+OWNER(vkanaev)
+
+SRCS(
+ node.h
+ test_events.h
+ test_actors.h
+ ic_test_cluster.h
+)
+
+END()
diff --git a/library/cpp/actors/interconnect/ut/poller_actor_ut.cpp b/library/cpp/actors/interconnect/ut/poller_actor_ut.cpp
new file mode 100644
index 0000000000..23d846a2fd
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut/poller_actor_ut.cpp
@@ -0,0 +1,264 @@
+#include <library/cpp/actors/interconnect/poller_actor.h>
+#include <library/cpp/actors/testlib/test_runtime.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/network/pair.h>
+#include <util/network/socket.h>
+
+using namespace NActors;
+
+class TTestSocket: public TSharedDescriptor {
+public:
+ explicit TTestSocket(SOCKET fd)
+ : Fd_(fd)
+ {
+ }
+
+ int GetDescriptor() override {
+ return Fd_;
+ }
+
+private:
+ SOCKET Fd_;
+};
+using TTestSocketPtr = TIntrusivePtr<TTestSocket>;
+
+// create pair of connected, non-blocking sockets
+std::pair<TTestSocketPtr, TTestSocketPtr> NonBlockSockets() {
+ SOCKET fds[2];
+ SocketPair(fds);
+ SetNonBlock(fds[0]);
+ SetNonBlock(fds[1]);
+ return {MakeIntrusive<TTestSocket>(fds[0]), MakeIntrusive<TTestSocket>(fds[1])};
+}
+
+std::pair<TTestSocketPtr, TTestSocketPtr> TcpSockets() {
+ // create server (listening) socket
+ SOCKET server = socket(AF_INET, SOCK_STREAM, 0);
+ Y_VERIFY(server != -1, "socket() failed with %s", strerror(errno));
+
+ // bind it to local address with automatically picked port
+ sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = 0;
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ if (bind(server, (sockaddr*)&addr, sizeof(addr)) == -1) {
+ Y_FAIL("bind() failed with %s", strerror(errno));
+ } else if (listen(server, 1) == -1) {
+ Y_FAIL("listen() failed with %s", strerror(errno));
+ }
+
+ // obtain local address for client
+ socklen_t len = sizeof(addr);
+ if (getsockname(server, (sockaddr*)&addr, &len) == -1) {
+ Y_FAIL("getsockname() failed with %s", strerror(errno));
+ }
+
+ // create client socket
+ SOCKET client = socket(AF_INET, SOCK_STREAM, 0);
+ Y_VERIFY(client != -1, "socket() failed with %s", strerror(errno));
+
+ // connect to server
+ if (connect(client, (sockaddr*)&addr, len) == -1) {
+ Y_FAIL("connect() failed with %s", strerror(errno));
+ }
+
+ // accept connection from the other side
+ SOCKET accepted = accept(server, nullptr, nullptr);
+ Y_VERIFY(accepted != -1, "accept() failed with %s", strerror(errno));
+
+ // close server socket
+ closesocket(server);
+
+ return std::make_pair(MakeIntrusive<TTestSocket>(client), MakeIntrusive<TTestSocket>(accepted));
+}
+
+class TPollerActorTest: public TTestBase {
+ UNIT_TEST_SUITE(TPollerActorTest);
+ UNIT_TEST(Registration)
+ UNIT_TEST(ReadNotification)
+ UNIT_TEST(WriteNotification)
+ UNIT_TEST(HangupNotification)
+ UNIT_TEST_SUITE_END();
+
+public:
+ void SetUp() override {
+ ActorSystem_ = MakeHolder<TTestActorRuntimeBase>();
+ ActorSystem_->Initialize();
+
+ PollerId_ = ActorSystem_->Register(CreatePollerActor());
+
+ TDispatchOptions opts;
+ opts.FinalEvents.emplace_back(TEvents::TSystem::Bootstrap, 1);
+ ActorSystem_->DispatchEvents(opts);
+ }
+
+ void Registration() {
+ auto [s1, s2] = NonBlockSockets();
+ auto readerId = ActorSystem_->AllocateEdgeActor();
+ auto writerId = ActorSystem_->AllocateEdgeActor();
+
+ RegisterSocket(s1, readerId, writerId);
+
+ // reader should receive event after socket registration
+ TPollerToken::TPtr token;
+ {
+ auto ev = ActorSystem_->GrabEdgeEvent<TEvPollerRegisterResult>(readerId);
+ token = ev->Get()->PollerToken;
+ }
+
+ // writer should receive event after socket registration
+ {
+ auto ev = ActorSystem_->GrabEdgeEvent<TEvPollerRegisterResult>(writerId);
+ UNIT_ASSERT_EQUAL(token, ev->Get()->PollerToken);
+ }
+ }
+
+ void ReadNotification() {
+ auto [r, w] = NonBlockSockets();
+ auto clientId = ActorSystem_->AllocateEdgeActor();
+ RegisterSocket(r, clientId, {});
+
+ // notification after registration
+ TPollerToken::TPtr token;
+ {
+ auto ev = ActorSystem_->GrabEdgeEvent<TEvPollerRegisterResult>(clientId);
+ token = ev->Get()->PollerToken;
+ }
+
+ char buf;
+
+ // data not ready yet for read
+ UNIT_ASSERT(read(r->GetDescriptor(), &buf, sizeof(buf)) == -1);
+ UNIT_ASSERT(errno == EWOULDBLOCK);
+
+ // request read poll
+ token->Request(true, false);
+
+ // write data
+ UNIT_ASSERT(write(w->GetDescriptor(), "x", 1) == 1);
+
+ // notification after socket become readable
+ {
+ auto ev = ActorSystem_->GrabEdgeEvent<TEvPollerReady>(clientId);
+ UNIT_ASSERT_EQUAL(ev->Get()->Socket, r);
+ UNIT_ASSERT(ev->Get()->Read);
+ UNIT_ASSERT(!ev->Get()->Write);
+ }
+
+ // read data
+ UNIT_ASSERT(read(r->GetDescriptor(), &buf, sizeof(buf)) == 1);
+ UNIT_ASSERT_EQUAL('x', buf);
+
+ // no more data to read
+ UNIT_ASSERT(read(r->GetDescriptor(), &buf, sizeof(buf)) == -1);
+ UNIT_ASSERT(errno == EWOULDBLOCK);
+ }
+
+ void WriteNotification() {
+ auto [r, w] = TcpSockets();
+ auto clientId = ActorSystem_->AllocateEdgeActor();
+ SetNonBlock(w->GetDescriptor());
+ RegisterSocket(w, TActorId{}, clientId);
+
+ // notification after registration
+ TPollerToken::TPtr token;
+ {
+ auto ev = ActorSystem_->GrabEdgeEvent<TEvPollerRegisterResult>(clientId);
+ token = ev->Get()->PollerToken;
+ }
+
+ char buffer[4096];
+ memset(buffer, 'x', sizeof(buffer));
+
+ for (int i = 0; i < 1000; ++i) {
+ // write as much as possible to send buffer
+ ssize_t written = 0;
+ for (;;) {
+ ssize_t res = send(w->GetDescriptor(), buffer, sizeof(buffer), 0);
+ if (res > 0) {
+ written += res;
+ } else if (res == 0) {
+ UNIT_FAIL("unexpected zero return from send()");
+ } else {
+ UNIT_ASSERT(res == -1);
+ if (errno == EINTR) {
+ continue;
+ } else if (errno == EWOULDBLOCK || errno == EAGAIN) {
+ token->Request(false, true);
+ break;
+ } else {
+ UNIT_FAIL("unexpected error from send()");
+ }
+ }
+ }
+ Cerr << "written " << written << " bytes" << Endl;
+
+ // read all written data from the read end
+ for (;;) {
+ char buffer[4096];
+ ssize_t res = recv(r->GetDescriptor(), buffer, sizeof(buffer), 0);
+ if (res > 0) {
+ UNIT_ASSERT(written >= res);
+ written -= res;
+ if (!written) {
+ break;
+ }
+ } else if (res == 0) {
+ UNIT_FAIL("unexpected zero return from recv()");
+ } else {
+ UNIT_ASSERT(res == -1);
+ if (errno == EINTR) {
+ continue;
+ } else {
+ UNIT_FAIL("unexpected error from recv()");
+ }
+ }
+ }
+
+ // wait for notification after socket becomes writable again
+ {
+ auto ev = ActorSystem_->GrabEdgeEvent<TEvPollerReady>(clientId);
+ UNIT_ASSERT_EQUAL(ev->Get()->Socket, w);
+ UNIT_ASSERT(!ev->Get()->Read);
+ UNIT_ASSERT(ev->Get()->Write);
+ }
+ }
+ }
+
+ void HangupNotification() {
+ auto [r, w] = NonBlockSockets();
+ auto clientId = ActorSystem_->AllocateEdgeActor();
+ RegisterSocket(r, clientId, TActorId{});
+
+ // notification after registration
+ TPollerToken::TPtr token;
+ {
+ auto ev = ActorSystem_->GrabEdgeEvent<TEvPollerRegisterResult>(clientId);
+ token = ev->Get()->PollerToken;
+ }
+
+ token->Request(true, false);
+ ShutDown(w->GetDescriptor(), SHUT_RDWR);
+
+ // notification after peer shuts down its socket
+ {
+ auto ev = ActorSystem_->GrabEdgeEvent<TEvPollerReady>(clientId);
+ UNIT_ASSERT_EQUAL(ev->Get()->Socket, r);
+ UNIT_ASSERT(ev->Get()->Read);
+ }
+ }
+
+private:
+ void RegisterSocket(TTestSocketPtr socket, TActorId readActorId, TActorId writeActorId) {
+ auto ev = new TEvPollerRegister{socket, readActorId, writeActorId};
+ ActorSystem_->Send(new IEventHandle(PollerId_, TActorId{}, ev));
+ }
+
+private:
+ THolder<TTestActorRuntimeBase> ActorSystem_;
+ TActorId PollerId_;
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TPollerActorTest);
diff --git a/library/cpp/actors/interconnect/ut/protos/interconnect_test.proto b/library/cpp/actors/interconnect/ut/protos/interconnect_test.proto
new file mode 100644
index 0000000000..b9b2bd6a4e
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut/protos/interconnect_test.proto
@@ -0,0 +1,25 @@
+package NInterconnectTest;
+
+message TEvTest {
+ optional uint64 SequenceNumber = 1;
+ optional bytes Payload = 2;
+}
+
+message TEvTestChan {
+ optional uint64 SequenceNumber = 1;
+ optional uint64 Payload = 2;
+}
+
+message TEvTestLarge {
+ optional uint64 SequenceNumber = 1;
+ optional bytes Payload = 2;
+}
+
+message TEvTestSmall {
+ optional uint64 SequenceNumber = 1;
+ optional bytes Payload = 2;
+}
+
+message TEvTestResponse {
+ optional uint64 ConfirmedSequenceNumber = 1;
+}
diff --git a/library/cpp/actors/interconnect/ut/protos/ya.make b/library/cpp/actors/interconnect/ut/protos/ya.make
new file mode 100644
index 0000000000..48a8cc129f
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut/protos/ya.make
@@ -0,0 +1,11 @@
+PROTO_LIBRARY()
+
+OWNER(vkanaev)
+
+SRCS(
+ interconnect_test.proto
+)
+
+EXCLUDE_TAGS(GO_PROTO)
+
+END()
diff --git a/library/cpp/actors/interconnect/ut/ya.make b/library/cpp/actors/interconnect/ut/ya.make
new file mode 100644
index 0000000000..2f5b13352e
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut/ya.make
@@ -0,0 +1,36 @@
+UNITTEST()
+
+OWNER(
+ alexvru
+ g:kikimr
+)
+
+IF (SANITIZER_TYPE == "thread")
+ TIMEOUT(1200)
+ SIZE(LARGE)
+ TAG(ya:fat)
+ELSE()
+ TIMEOUT(600)
+ SIZE(MEDIUM)
+ENDIF()
+
+SRCS(
+ channel_scheduler_ut.cpp
+ event_holder_pool_ut.cpp
+ interconnect_ut.cpp
+ large.cpp
+ poller_actor_ut.cpp
+ dynamic_proxy_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/actors/core
+ library/cpp/actors/interconnect
+ library/cpp/actors/interconnect/ut/lib
+ library/cpp/actors/interconnect/ut/protos
+ library/cpp/actors/testlib
+ library/cpp/digest/md5
+ library/cpp/testing/unittest
+)
+
+END()
diff --git a/library/cpp/actors/interconnect/ut_fat/main.cpp b/library/cpp/actors/interconnect/ut_fat/main.cpp
new file mode 100644
index 0000000000..5d19bc3003
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut_fat/main.cpp
@@ -0,0 +1,133 @@
+
+#include <library/cpp/actors/interconnect/interconnect_tcp_proxy.h>
+#include <library/cpp/actors/interconnect/ut/protos/interconnect_test.pb.h>
+#include <library/cpp/actors/interconnect/ut/lib/ic_test_cluster.h>
+#include <library/cpp/actors/interconnect/ut/lib/interrupter.h>
+#include <library/cpp/actors/interconnect/ut/lib/test_events.h>
+#include <library/cpp/actors/interconnect/ut/lib/test_actors.h>
+#include <library/cpp/actors/interconnect/ut/lib/node.h>
+
+#include <library/cpp/testing/unittest/tests_data.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/network/sock.h>
+#include <util/network/poller.h>
+#include <util/system/atomic.h>
+#include <util/generic/set.h>
+
+Y_UNIT_TEST_SUITE(InterconnectUnstableConnection) {
+ using namespace NActors;
+
+ class TSenderActor: public TSenderBaseActor {
+ TDeque<ui64> InFly;
+ ui16 SendFlags;
+
+ public:
+ TSenderActor(const TActorId& recipientActorId, ui16 sendFlags)
+ : TSenderBaseActor(recipientActorId, 32)
+ , SendFlags(sendFlags)
+ {
+ }
+
+ ~TSenderActor() override {
+ Cerr << "Sent " << SequenceNumber << " messages\n";
+ }
+
+ void SendMessage(const TActorContext& ctx) override {
+ const ui32 flags = IEventHandle::MakeFlags(0, SendFlags);
+ const ui64 cookie = SequenceNumber;
+ const TString payload('@', RandomNumber<size_t>(65536) + 4096);
+ ctx.Send(RecipientActorId, new TEvTest(SequenceNumber, payload), flags, cookie);
+ InFly.push_back(SequenceNumber);
+ ++InFlySize;
+ ++SequenceNumber;
+ }
+
+ void Handle(TEvents::TEvUndelivered::TPtr& ev, const TActorContext& ctx) override {
+ auto record = std::find(InFly.begin(), InFly.end(), ev->Cookie);
+ if (SendFlags & IEventHandle::FlagGenerateUnsureUndelivered) {
+ if (record != InFly.end()) {
+ InFly.erase(record);
+ --InFlySize;
+ SendMessage(ctx);
+ }
+ } else {
+ Y_VERIFY(record != InFly.end());
+ }
+ }
+
+ void Handle(TEvTestResponse::TPtr& ev, const TActorContext& ctx) override {
+ Y_VERIFY(InFly);
+ const NInterconnectTest::TEvTestResponse& record = ev->Get()->Record;
+ Y_VERIFY(record.HasConfirmedSequenceNumber());
+ if (!(SendFlags & IEventHandle::FlagGenerateUnsureUndelivered)) {
+ while (record.GetConfirmedSequenceNumber() != InFly.front()) {
+ InFly.pop_front();
+ --InFlySize;
+ }
+ }
+ Y_VERIFY(record.GetConfirmedSequenceNumber() == InFly.front(), "got# %" PRIu64 " expected# %" PRIu64,
+ record.GetConfirmedSequenceNumber(), InFly.front());
+ InFly.pop_front();
+ --InFlySize;
+ SendMessagesIfPossible(ctx);
+ }
+ };
+
+ class TReceiverActor: public TReceiverBaseActor {
+ ui64 ReceivedCount = 0;
+ TNode* SenderNode = nullptr;
+
+ public:
+ TReceiverActor(TNode* senderNode)
+ : TReceiverBaseActor()
+ , SenderNode(senderNode)
+ {
+ }
+
+ void Handle(TEvTest::TPtr& ev, const TActorContext& /*ctx*/) override {
+ const NInterconnectTest::TEvTest& m = ev->Get()->Record;
+ Y_VERIFY(m.HasSequenceNumber());
+ Y_VERIFY(m.GetSequenceNumber() >= ReceivedCount, "got #%" PRIu64 " expected at least #%" PRIu64,
+ m.GetSequenceNumber(), ReceivedCount);
+ ++ReceivedCount;
+ SenderNode->Send(ev->Sender, new TEvTestResponse(m.GetSequenceNumber()));
+ }
+
+ ~TReceiverActor() override {
+ Cerr << "Received " << ReceivedCount << " messages\n";
+ }
+ };
+
+ Y_UNIT_TEST(InterconnectTestWithProxyUnsureUndelivered) {
+ ui32 numNodes = 2;
+ double bandWidth = 1000000;
+ ui16 flags = IEventHandle::FlagTrackDelivery | IEventHandle::FlagGenerateUnsureUndelivered;
+ TTestICCluster::TTrafficInterrupterSettings interrupterSettings{TDuration::Seconds(2), bandWidth, true};
+
+ TTestICCluster testCluster(numNodes, TChannelsConfig(), &interrupterSettings);
+
+ TReceiverActor* receiverActor = new TReceiverActor(testCluster.GetNode(1));
+ const TActorId recipient = testCluster.RegisterActor(receiverActor, 2);
+ TSenderActor* senderActor = new TSenderActor(recipient, flags);
+ testCluster.RegisterActor(senderActor, 1);
+
+ NanoSleep(30ULL * 1000 * 1000 * 1000);
+ }
+
+ Y_UNIT_TEST(InterconnectTestWithProxy) {
+ ui32 numNodes = 2;
+ double bandWidth = 1000000;
+ ui16 flags = IEventHandle::FlagTrackDelivery;
+ TTestICCluster::TTrafficInterrupterSettings interrupterSettings{TDuration::Seconds(2), bandWidth, true};
+
+ TTestICCluster testCluster(numNodes, TChannelsConfig(), &interrupterSettings);
+
+ TReceiverActor* receiverActor = new TReceiverActor(testCluster.GetNode(1));
+ const TActorId recipient = testCluster.RegisterActor(receiverActor, 2);
+ TSenderActor* senderActor = new TSenderActor(recipient, flags);
+ testCluster.RegisterActor(senderActor, 1);
+
+ NanoSleep(30ULL * 1000 * 1000 * 1000);
+ }
+}
diff --git a/library/cpp/actors/interconnect/ut_fat/ya.make b/library/cpp/actors/interconnect/ut_fat/ya.make
new file mode 100644
index 0000000000..6e58d08154
--- /dev/null
+++ b/library/cpp/actors/interconnect/ut_fat/ya.make
@@ -0,0 +1,25 @@
+UNITTEST()
+
+OWNER(
+ vkanaev
+ alexvru
+)
+
+SIZE(LARGE)
+
+TAG(ya:fat)
+
+SRCS(
+ main.cpp
+)
+
+PEERDIR(
+ library/cpp/actors/core
+ library/cpp/actors/interconnect
+ library/cpp/actors/interconnect/mock
+ library/cpp/actors/interconnect/ut/lib
+ library/cpp/actors/interconnect/ut/protos
+ library/cpp/testing/unittest
+)
+
+END()
diff --git a/library/cpp/actors/interconnect/watchdog_timer.h b/library/cpp/actors/interconnect/watchdog_timer.h
new file mode 100644
index 0000000000..c190105a59
--- /dev/null
+++ b/library/cpp/actors/interconnect/watchdog_timer.h
@@ -0,0 +1,68 @@
+#pragma once
+
+namespace NActors {
+ template <typename TEvent>
+ class TWatchdogTimer {
+ using TCallback = std::function<void()>;
+
+ const TDuration Timeout;
+ const TCallback Callback;
+
+ TInstant LastResetTimestamp;
+ TEvent* ExpectedEvent = nullptr;
+ ui32 Iteration = 0;
+
+ static constexpr ui32 NumIterationsBeforeFiring = 2;
+
+ public:
+ TWatchdogTimer(TDuration timeout, TCallback callback)
+ : Timeout(timeout)
+ , Callback(std::move(callback))
+ {
+ }
+
+ void Arm(const TActorIdentity& actor) {
+ if (Timeout != TDuration::Zero() && Timeout != TDuration::Max()) {
+ Schedule(Timeout, actor);
+ Reset();
+ }
+ }
+
+ void Reset() {
+ LastResetTimestamp = TActivationContext::Now();
+ }
+
+ void Disarm() {
+ ExpectedEvent = nullptr;
+ }
+
+ void operator()(typename TEvent::TPtr& ev) {
+ if (ev->Get() == ExpectedEvent) {
+ const TInstant now = TActivationContext::Now();
+ const TInstant barrier = LastResetTimestamp + Timeout;
+ if (now < barrier) {
+ // the time hasn't come yet
+ Schedule(barrier - now, TActorIdentity(ev->Recipient));
+ } else if (Iteration < NumIterationsBeforeFiring) {
+ // time has come, but we will still give actor a chance to process some messages and rearm timer
+ ++Iteration;
+ TActivationContext::Send(ev.Release()); // send this event into queue once more
+ } else {
+ // no chance to disarm, fire callback
+ Callback();
+ ExpectedEvent = nullptr;
+ Iteration = 0;
+ }
+ }
+ }
+
+ private:
+ void Schedule(TDuration timeout, const TActorIdentity& actor) {
+ auto ev = MakeHolder<TEvent>();
+ ExpectedEvent = ev.Get();
+ Iteration = 0;
+ actor.Schedule(timeout, ev.Release());
+ }
+ };
+
+}
diff --git a/library/cpp/actors/interconnect/ya.make b/library/cpp/actors/interconnect/ya.make
new file mode 100644
index 0000000000..60d29b0fc0
--- /dev/null
+++ b/library/cpp/actors/interconnect/ya.make
@@ -0,0 +1,94 @@
+LIBRARY()
+
+OWNER(
+ ddoarn
+ alexvru
+ g:kikimr
+)
+
+NO_WSHADOW()
+
+IF (PROFILE_MEMORY_ALLOCATIONS)
+ CFLAGS(-DPROFILE_MEMORY_ALLOCATIONS)
+ENDIF()
+
+SRCS(
+ channel_scheduler.h
+ event_filter.h
+ event_holder_pool.h
+ events_local.h
+ interconnect_address.cpp
+ interconnect_address.h
+ interconnect_channel.cpp
+ interconnect_channel.h
+ interconnect_common.h
+ interconnect_counters.cpp
+ interconnect.h
+ interconnect_handshake.cpp
+ interconnect_handshake.h
+ interconnect_impl.h
+ interconnect_mon.cpp
+ interconnect_mon.h
+ interconnect_nameserver_dynamic.cpp
+ interconnect_nameserver_table.cpp
+ interconnect_proxy_wrapper.cpp
+ interconnect_proxy_wrapper.h
+ interconnect_resolve.cpp
+ interconnect_stream.cpp
+ interconnect_stream.h
+ interconnect_tcp_input_session.cpp
+ interconnect_tcp_proxy.cpp
+ interconnect_tcp_proxy.h
+ interconnect_tcp_server.cpp
+ interconnect_tcp_server.h
+ interconnect_tcp_session.cpp
+ interconnect_tcp_session.h
+ load.cpp
+ load.h
+ logging.h
+ packet.cpp
+ packet.h
+ poller_actor.cpp
+ poller_actor.h
+ poller.h
+ poller_tcp.cpp
+ poller_tcp.h
+ poller_tcp_unit.cpp
+ poller_tcp_unit.h
+ poller_tcp_unit_select.cpp
+ poller_tcp_unit_select.h
+ profiler.h
+ slowpoke_actor.h
+ types.cpp
+ types.h
+ watchdog_timer.h
+)
+
+IF (OS_LINUX)
+ SRCS(
+ poller_tcp_unit_epoll.cpp
+ poller_tcp_unit_epoll.h
+ )
+ENDIF()
+
+PEERDIR(
+ contrib/libs/libc_compat
+ contrib/libs/openssl
+ library/cpp/actors/core
+ library/cpp/actors/dnscachelib
+ library/cpp/actors/dnsresolver
+ library/cpp/actors/helpers
+ library/cpp/actors/prof
+ library/cpp/actors/protos
+ library/cpp/actors/util
+ library/cpp/digest/crc32c
+ library/cpp/json
+ library/cpp/lwtrace
+ library/cpp/monlib/dynamic_counters
+ library/cpp/monlib/metrics
+ library/cpp/monlib/service/pages/tablesorter
+ library/cpp/openssl/init
+ library/cpp/packedtypes
+)
+
+END()
diff --git a/library/cpp/actors/memory_log/memlog.cpp b/library/cpp/actors/memory_log/memlog.cpp
new file mode 100644
index 0000000000..8e6b46727d
--- /dev/null
+++ b/library/cpp/actors/memory_log/memlog.cpp
@@ -0,0 +1,367 @@
+#include "memlog.h"
+
+#include <library/cpp/actors/util/datetime.h>
+
+#include <util/system/info.h>
+#include <util/system/atomic.h>
+#include <util/system/align.h>
+
+#include <contrib/libs/linuxvdso/interface.h>
+
+#if (defined(_i386_) || defined(_x86_64_)) && defined(_linux_)
+#define HAVE_VDSO_GETCPU 1
+#include <contrib/libs/linuxvdso/interface.h>
+static int (*FastGetCpu)(unsigned* cpu, unsigned* node, void* unused);
+#endif
+
+#if defined(_unix_)
+#include <sched.h>
+#elif defined(_win_)
+#include <WinBase.h>
+#else
+#error NO IMPLEMENTATION FOR THE PLATFORM
+#endif
+
+const char TMemoryLog::DEFAULT_LAST_MARK[16] = {
+ 'c',
+ 'b',
+ '7',
+ 'B',
+ '6',
+ '8',
+ 'a',
+ '8',
+ 'A',
+ '5',
+ '6',
+ '1',
+ '6',
+ '4',
+ '5',
+ '\n',
+};
+
+const char TMemoryLog::CLEAR_MARK[16] = {
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ '\n',
+};
+
+unsigned TMemoryLog::GetSelfCpu() noexcept {
+#if defined(_unix_)
+#if HAVE_VDSO_GETCPU
+ unsigned cpu;
+ if (Y_LIKELY(FastGetCpu != nullptr)) {
+ auto result = FastGetCpu(&cpu, nullptr, nullptr);
+ Y_VERIFY(result == 0);
+ return cpu;
+ } else {
+ return 0;
+ }
+
+#elif defined(_x86_64_) || defined(_i386_)
+
+#define CPUID(func, eax, ebx, ecx, edx) \
+ __asm__ __volatile__( \
+ "cpuid" \
+ : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) \
+ : "a"(func));
+
+ int a = 0, b = 0, c = 0, d = 0;
+ CPUID(0x1, a, b, c, d);
+ int acpiID = (b >> 24);
+ return acpiID;
+
+#elif defined(__CNUC__)
+ return sched_getcpu();
+#else
+ return 0;
+#endif
+
+#elif defined(_win_)
+ return GetCurrentProcessorNumber();
+#else
+ return 0;
+#endif
+}
+
+TMemoryLog* TMemoryLog::MemLogBuffer = nullptr;
+Y_POD_THREAD(TThread::TId)
+TMemoryLog::LogThreadId;
+char* TMemoryLog::LastMarkIsHere = nullptr;
+
+std::atomic<bool> TMemoryLog::PrintLastMark(true);
+
+TMemoryLog::TMemoryLog(size_t totalSize, size_t grainSize)
+ : GrainSize(grainSize)
+ , FreeGrains(DEFAULT_TOTAL_SIZE / DEFAULT_GRAIN_SIZE * 2)
+ , Buf(totalSize)
+{
+ Y_VERIFY(DEFAULT_TOTAL_SIZE % DEFAULT_GRAIN_SIZE == 0);
+ NumberOfGrains = DEFAULT_TOTAL_SIZE / DEFAULT_GRAIN_SIZE;
+
+ for (size_t i = 0; i < NumberOfGrains; ++i) {
+ new (GetGrain(i)) TGrain;
+ }
+
+ NumberOfCpus = NSystemInfo::NumberOfCpus();
+ Y_VERIFY(NumberOfGrains > NumberOfCpus);
+ ActiveGrains.Reset(new TGrain*[NumberOfCpus]);
+ for (size_t i = 0; i < NumberOfCpus; ++i) {
+ ActiveGrains[i] = GetGrain(i);
+ }
+
+ for (size_t i = NumberOfCpus; i < NumberOfGrains; ++i) {
+ FreeGrains.StubbornPush(GetGrain(i));
+ }
+
+#if HAVE_VDSO_GETCPU
+ auto vdsoFunc = (decltype(FastGetCpu))
+ NVdso::Function("__vdso_getcpu", "LINUX_2.6");
+ AtomicSet(FastGetCpu, vdsoFunc);
+#endif
+}
+
+void* TMemoryLog::GetWriteBuffer(size_t amount) noexcept {
+ // alignment required by NoCacheMemcpy
+ amount = AlignUp<size_t>(amount, MemcpyAlignment);
+
+ for (ui16 tries = MAX_GET_BUFFER_TRIES; tries-- > 0;) {
+ auto myCpu = GetSelfCpu();
+
+ TGrain* grain = AtomicGet(ActiveGrains[myCpu]);
+
+ if (grain != nullptr) {
+ auto mine = AtomicGetAndAdd(grain->WritePointer, amount);
+ if (mine + amount <= GrainSize - sizeof(TGrain)) {
+ return &grain->Data[mine];
+ }
+
+ if (!AtomicCas(&ActiveGrains[myCpu], 0, grain)) {
+ continue;
+ }
+
+ FreeGrains.StubbornPush(grain);
+ }
+
+ grain = (TGrain*)FreeGrains.Pop();
+
+ if (grain == nullptr) {
+ return nullptr;
+ }
+
+ grain->WritePointer = 0;
+
+ if (!AtomicCas(&ActiveGrains[myCpu], grain, 0)) {
+ FreeGrains.StubbornPush(grain);
+ continue;
+ }
+ }
+
+ return nullptr;
+}
+
+void ClearAlignedTail(char* tail) noexcept {
+ auto aligned = AlignUp(tail, TMemoryLog::MemcpyAlignment);
+ if (aligned > tail) {
+ memset(tail, 0, aligned - tail);
+ }
+}
+
+#if defined(_x86_64_) || defined(_i386_)
+#include <xmmintrin.h>
+// the main motivation is not poluting CPU cache
+NO_SANITIZE_THREAD
+void NoCacheMemcpy(char* dst, const char* src, size_t size) noexcept {
+ while (size >= sizeof(__m128) * 2) {
+ __m128 a = _mm_load_ps((float*)(src + 0 * sizeof(__m128)));
+ __m128 b = _mm_load_ps((float*)(src + 1 * sizeof(__m128)));
+ _mm_stream_ps((float*)(dst + 0 * sizeof(__m128)), a);
+ _mm_stream_ps((float*)(dst + 1 * sizeof(__m128)), b);
+
+ size -= sizeof(__m128) * 2;
+ src += sizeof(__m128) * 2;
+ dst += sizeof(__m128) * 2;
+ }
+ memcpy(dst, src, size);
+}
+
+NO_SANITIZE_THREAD
+void NoWCacheMemcpy(char* dst, const char* src, size_t size) noexcept {
+ constexpr ui16 ITEMS_COUNT = 1024;
+ alignas(TMemoryLog::MemcpyAlignment) __m128 buf[ITEMS_COUNT];
+ while (size >= sizeof(buf)) {
+ memcpy(&buf, src, sizeof(buf));
+
+ for (ui16 i = 0; i < ITEMS_COUNT; ++i) {
+ _mm_stream_ps((float*)dst, buf[i]);
+ dst += sizeof(__m128);
+ }
+
+ size -= sizeof(buf);
+ src += sizeof(buf);
+ }
+
+ memcpy(&buf, src, size);
+ // no problem to copy few bytes more
+ size = AlignUp(size, sizeof(__m128));
+ for (ui16 i = 0; i < size / sizeof(__m128); ++i) {
+ _mm_stream_ps((float*)dst, buf[i]);
+ dst += sizeof(__m128);
+ }
+}
+
+#endif
+
+NO_SANITIZE_THREAD
+char* BareMemLogWrite(const char* begin, size_t msgSize, bool isLast) noexcept {
+ bool lastMark =
+ isLast && TMemoryLog::PrintLastMark.load(std::memory_order_acquire);
+ size_t amount = lastMark ? msgSize + TMemoryLog::LAST_MARK_SIZE : msgSize;
+
+ char* buffer = (char*)TMemoryLog::GetWriteBufferStatic(amount);
+ if (buffer == nullptr) {
+ return nullptr;
+ }
+
+#if defined(_x86_64_) || defined(_i386_)
+ if (AlignDown(begin, TMemoryLog::MemcpyAlignment) == begin) {
+ NoCacheMemcpy(buffer, begin, msgSize);
+ } else {
+ NoWCacheMemcpy(buffer, begin, msgSize);
+ }
+#else
+ memcpy(buffer, begin, msgSize);
+#endif
+
+ if (lastMark) {
+ TMemoryLog::ChangeLastMark(buffer + msgSize);
+ }
+
+ ClearAlignedTail(buffer + amount);
+ return buffer;
+}
+
+NO_SANITIZE_THREAD
+bool MemLogWrite(const char* begin, size_t msgSize, bool addLF) noexcept {
+ bool lastMark = TMemoryLog::PrintLastMark.load(std::memory_order_acquire);
+ size_t amount = lastMark ? msgSize + TMemoryLog::LAST_MARK_SIZE : msgSize;
+
+ // Let's construct prolog with timestamp and thread id
+ auto threadId = TMemoryLog::GetTheadId();
+
+ // alignment required by NoCacheMemcpy
+ // check for format for snprintf
+ constexpr size_t prologSize = 48;
+ alignas(TMemoryLog::MemcpyAlignment) char prolog[prologSize + 1];
+ Y_VERIFY(AlignDown(&prolog, TMemoryLog::MemcpyAlignment) == &prolog);
+
+ int snprintfResult = snprintf(prolog, prologSize + 1,
+ "TS %020" PRIu64 " TI %020" PRIu64 " ", GetCycleCountFast(), threadId);
+
+ if (snprintfResult < 0) {
+ return false;
+ }
+ Y_VERIFY(snprintfResult == prologSize);
+
+ amount += prologSize;
+ if (addLF) {
+ ++amount; // add 1 byte for \n at the end of the message
+ }
+
+ char* buffer = (char*)TMemoryLog::GetWriteBufferStatic(amount);
+ if (buffer == nullptr) {
+ return false;
+ }
+
+#if defined(_x86_64_) || defined(_i386_)
+ // warning: copy prolog first to avoid corruption of the message
+ // by prolog tail
+ NoCacheMemcpy(buffer, prolog, prologSize);
+ if (AlignDown(begin + prologSize, TMemoryLog::MemcpyAlignment) == begin + prologSize) {
+ NoCacheMemcpy(buffer + prologSize, begin, msgSize);
+ } else {
+ NoWCacheMemcpy(buffer + prologSize, begin, msgSize);
+ }
+#else
+ memcpy(buffer, prolog, prologSize);
+ memcpy(buffer + prologSize, begin, msgSize);
+#endif
+
+ if (addLF) {
+ buffer[prologSize + msgSize] = '\n';
+ }
+
+ if (lastMark) {
+ TMemoryLog::ChangeLastMark(buffer + prologSize + msgSize + (int)addLF);
+ }
+
+ ClearAlignedTail(buffer + amount);
+ return true;
+}
+
+NO_SANITIZE_THREAD
+void TMemoryLog::ChangeLastMark(char* buffer) noexcept {
+ memcpy(buffer, DEFAULT_LAST_MARK, LAST_MARK_SIZE);
+ auto oldMark = AtomicSwap(&LastMarkIsHere, buffer);
+ if (Y_LIKELY(oldMark != nullptr)) {
+ memcpy(oldMark, CLEAR_MARK, LAST_MARK_SIZE);
+ }
+ if (AtomicGet(LastMarkIsHere) != buffer) {
+ memcpy(buffer, CLEAR_MARK, LAST_MARK_SIZE);
+ AtomicBarrier();
+ }
+}
+
+bool MemLogVPrintF(const char* format, va_list params) noexcept {
+ auto logger = TMemoryLog::GetMemoryLogger();
+ if (logger == nullptr) {
+ return false;
+ }
+
+ auto threadId = TMemoryLog::GetTheadId();
+
+ // alignment required by NoCacheMemcpy
+ alignas(TMemoryLog::MemcpyAlignment) char buf[TMemoryLog::MAX_MESSAGE_SIZE];
+ Y_VERIFY(AlignDown(&buf, TMemoryLog::MemcpyAlignment) == &buf);
+
+ int prologSize = snprintf(buf,
+ TMemoryLog::MAX_MESSAGE_SIZE - 2,
+ "TS %020" PRIu64 " TI %020" PRIu64 " ",
+ GetCycleCountFast(),
+ threadId);
+
+ if (Y_UNLIKELY(prologSize < 0)) {
+ return false;
+ }
+ Y_VERIFY((ui32)prologSize <= TMemoryLog::MAX_MESSAGE_SIZE);
+
+ int add = vsnprintf(
+ &buf[prologSize],
+ TMemoryLog::MAX_MESSAGE_SIZE - prologSize - 2,
+ format, params);
+
+ if (Y_UNLIKELY(add < 0)) {
+ return false;
+ }
+ Y_VERIFY(add >= 0);
+ auto totalSize = prologSize + add;
+
+ buf[totalSize++] = '\n';
+ Y_VERIFY((ui32)totalSize <= TMemoryLog::MAX_MESSAGE_SIZE);
+
+ return BareMemLogWrite(buf, totalSize) != nullptr;
+}
diff --git a/library/cpp/actors/memory_log/memlog.h b/library/cpp/actors/memory_log/memlog.h
new file mode 100644
index 0000000000..2aa27272a6
--- /dev/null
+++ b/library/cpp/actors/memory_log/memlog.h
@@ -0,0 +1,211 @@
+#pragma once
+
+#include <library/cpp/threading/queue/mpmc_unordered_ring.h>
+#include <util/generic/string.h>
+#include <util/string/printf.h>
+#include <util/system/datetime.h>
+#include <util/system/thread.h>
+#include <util/system/types.h>
+#include <util/system/atomic.h>
+#include <util/system/align.h>
+#include <util/system/tls.h>
+
+#include <atomic>
+#include <cstdio>
+
+#ifdef _win_
+#include <util/system/winint.h>
+#endif
+
+#ifndef NO_SANITIZE_THREAD
+#define NO_SANITIZE_THREAD
+#if defined(__has_feature)
+#if __has_feature(thread_sanitizer)
+#undef NO_SANITIZE_THREAD
+#define NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
+#endif
+#endif
+#endif
+
+class TMemoryLog {
+public:
+ static constexpr size_t DEFAULT_TOTAL_SIZE = 10 * 1024 * 1024;
+ static constexpr size_t DEFAULT_GRAIN_SIZE = 1024 * 64;
+ static constexpr size_t MAX_MESSAGE_SIZE = 1024;
+ static constexpr ui16 MAX_GET_BUFFER_TRIES = 4;
+ static constexpr ui16 MemcpyAlignment = 16;
+
+ // search for cb7B68a8A561645
+ static const char DEFAULT_LAST_MARK[16];
+ static const char CLEAR_MARK[16];
+
+ static constexpr size_t LAST_MARK_SIZE = sizeof(DEFAULT_LAST_MARK);
+
+ inline static TMemoryLog* GetMemoryLogger() noexcept {
+ return AtomicGet(MemLogBuffer);
+ }
+
+ void* GetWriteBuffer(size_t amount) noexcept;
+
+ inline static void* GetWriteBufferStatic(size_t amount) noexcept {
+ auto logger = GetMemoryLogger();
+ if (logger == nullptr) {
+ return nullptr;
+ }
+ return logger->GetWriteBuffer(amount);
+ }
+
+ size_t GetGlobalBufferSize() const noexcept {
+ return Buf.GetSize();
+ }
+
+ inline static void CreateMemoryLogBuffer(
+ size_t totalSize = DEFAULT_TOTAL_SIZE,
+ size_t grainSize = DEFAULT_GRAIN_SIZE)
+ Y_COLD {
+ if (AtomicGet(MemLogBuffer) != nullptr) {
+ return;
+ }
+
+ AtomicSet(MemLogBuffer, new TMemoryLog(totalSize, grainSize));
+ }
+
+ static std::atomic<bool> PrintLastMark;
+
+ // buffer must be at least 16 bytes
+ static void ChangeLastMark(char* buffer) noexcept;
+
+ inline static TThread::TId GetTheadId() noexcept {
+ if (LogThreadId == 0) {
+ LogThreadId = TThread::CurrentThreadId();
+ }
+ return LogThreadId;
+ }
+
+private:
+ TMemoryLog(size_t totalSize, size_t grainSize) Y_COLD;
+
+ struct TGrain {
+ TAtomic WritePointer = 0;
+ char Padding[MemcpyAlignment - sizeof(TAtomic)];
+ char Data[];
+ };
+
+ size_t NumberOfCpus;
+ size_t GrainSize;
+ size_t NumberOfGrains;
+ TArrayPtr<TGrain*> ActiveGrains;
+ NThreading::TMPMCUnorderedRing FreeGrains;
+
+ TGrain* GetGrain(size_t grainIndex) const noexcept {
+ return (TGrain*)((char*)GetGlobalBuffer() + GrainSize * grainIndex);
+ }
+
+ class TMMapArea {
+ public:
+ TMMapArea(size_t amount) Y_COLD {
+ MMap(amount);
+ }
+
+ TMMapArea(const TMMapArea&) = delete;
+ TMMapArea& operator=(const TMMapArea& copy) = delete;
+
+ TMMapArea(TMMapArea&& move) Y_COLD {
+ BufPtr = move.BufPtr;
+ Size = move.Size;
+
+ move.BufPtr = nullptr;
+ move.Size = 0;
+ }
+
+ TMMapArea& operator=(TMMapArea&& move) Y_COLD {
+ BufPtr = move.BufPtr;
+ Size = move.Size;
+
+ move.BufPtr = nullptr;
+ move.Size = 0;
+ return *this;
+ }
+
+ void Reset(size_t amount) Y_COLD {
+ MUnmap();
+ MMap(amount);
+ }
+
+ ~TMMapArea() noexcept Y_COLD {
+ MUnmap();
+ }
+
+ size_t GetSize() const noexcept {
+ return Size;
+ }
+
+ void* GetPtr() const noexcept {
+ return BufPtr;
+ }
+
+ private:
+ void* BufPtr;
+ size_t Size;
+#ifdef _win_
+ HANDLE Mapping;
+#endif
+
+ void MMap(size_t amount);
+ void MUnmap();
+ };
+
+ TMMapArea Buf;
+
+ void* GetGlobalBuffer() const noexcept {
+ return Buf.GetPtr();
+ }
+
+ static unsigned GetSelfCpu() noexcept;
+
+ static TMemoryLog* MemLogBuffer;
+ static Y_POD_THREAD(TThread::TId) LogThreadId;
+ static char* LastMarkIsHere;
+};
+
+// it's no use of sanitizing this function
+NO_SANITIZE_THREAD
+char* BareMemLogWrite(
+ const char* begin, size_t msgSize, bool isLast = true) noexcept;
+
+// it's no use of sanitizing this function
+NO_SANITIZE_THREAD
+bool MemLogWrite(
+ const char* begin, size_t msgSize, bool addLF = false) noexcept;
+
+Y_WRAPPER inline bool MemLogWrite(const char* begin, const char* end) noexcept {
+ if (end <= begin) {
+ return false;
+ }
+
+ size_t msgSize = end - begin;
+ return MemLogWrite(begin, msgSize);
+}
+
+template <typename TObj>
+bool MemLogWriteStruct(const TObj* obj) noexcept {
+ auto begin = (const char*)(const void*)obj;
+ return MemLogWrite(begin, begin + sizeof(TObj));
+}
+
+Y_PRINTF_FORMAT(1, 0)
+bool MemLogVPrintF(const char* format, va_list params) noexcept;
+
+Y_PRINTF_FORMAT(1, 2)
+Y_WRAPPER
+inline bool MemLogPrintF(const char* format, ...) noexcept {
+ va_list params;
+ va_start(params, format);
+ auto result = MemLogVPrintF(format, params);
+ va_end(params);
+ return result;
+}
+
+Y_WRAPPER inline bool MemLogWriteNullTerm(const char* str) noexcept {
+ return MemLogWrite(str, strlen(str));
+}
diff --git a/library/cpp/actors/memory_log/mmap.cpp b/library/cpp/actors/memory_log/mmap.cpp
new file mode 100644
index 0000000000..201998d343
--- /dev/null
+++ b/library/cpp/actors/memory_log/mmap.cpp
@@ -0,0 +1,63 @@
+#include "memlog.h"
+
+#if defined(_unix_)
+#include <sys/mman.h>
+#elif defined(_win_)
+#include <util/system/winint.h>
+#else
+#error NO IMPLEMENTATION FOR THE PLATFORM
+#endif
+
+void TMemoryLog::TMMapArea::MMap(size_t amount) {
+ Y_VERIFY(amount > 0);
+
+#if defined(_unix_)
+ constexpr int mmapProt = PROT_READ | PROT_WRITE;
+#if defined(_linux_)
+ constexpr int mmapFlags = MAP_PRIVATE | MAP_ANON | MAP_POPULATE;
+#else
+ constexpr int mmapFlags = MAP_PRIVATE | MAP_ANON;
+#endif
+
+ BufPtr = ::mmap(nullptr, amount, mmapProt, mmapFlags, -1, 0);
+ if (BufPtr == MAP_FAILED) {
+ throw std::bad_alloc();
+ }
+
+#elif defined(_win_)
+ Mapping = ::CreateFileMapping(
+ (HANDLE)-1, nullptr, PAGE_READWRITE, 0, amount, nullptr);
+ if (Mapping == NULL) {
+ throw std::bad_alloc();
+ }
+ BufPtr = ::MapViewOfFile(Mapping, FILE_MAP_WRITE, 0, 0, amount);
+ if (BufPtr == NULL) {
+ throw std::bad_alloc();
+ }
+#endif
+
+ Size = amount;
+}
+
+void TMemoryLog::TMMapArea::MUnmap() {
+ if (BufPtr == nullptr) {
+ return;
+ }
+
+#if defined(_unix_)
+ int result = ::munmap(BufPtr, Size);
+ Y_VERIFY(result == 0);
+
+#elif defined(_win_)
+ BOOL result = ::UnmapViewOfFile(BufPtr);
+ Y_VERIFY(result != 0);
+
+ result = ::CloseHandle(Mapping);
+ Y_VERIFY(result != 0);
+
+ Mapping = 0;
+#endif
+
+ BufPtr = nullptr;
+ Size = 0;
+}
diff --git a/library/cpp/actors/memory_log/ya.make b/library/cpp/actors/memory_log/ya.make
new file mode 100644
index 0000000000..d89d5db4d7
--- /dev/null
+++ b/library/cpp/actors/memory_log/ya.make
@@ -0,0 +1,19 @@
+LIBRARY()
+
+OWNER(
+ agri
+ g:kikimr
+)
+
+SRCS(
+ memlog.cpp
+ memlog.h
+ mmap.cpp
+)
+
+PEERDIR(
+ library/cpp/threading/queue
+ contrib/libs/linuxvdso
+)
+
+END()
diff --git a/library/cpp/actors/prof/tag.cpp b/library/cpp/actors/prof/tag.cpp
new file mode 100644
index 0000000000..9ccf03e1a9
--- /dev/null
+++ b/library/cpp/actors/prof/tag.cpp
@@ -0,0 +1,119 @@
+#include "tag.h"
+#include "tcmalloc.h"
+
+#include <library/cpp/charset/ci_string.h>
+#include <library/cpp/containers/atomizer/atomizer.h>
+#include <library/cpp/malloc/api/malloc.h>
+
+#if defined(PROFILE_MEMORY_ALLOCATIONS)
+#include <library/cpp/lfalloc/dbg_info/dbg_info.h>
+#include <library/cpp/ytalloc/api/ytalloc.h>
+#endif
+
+#include <util/generic/singleton.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/system/mutex.h>
+
+namespace NProfiling {
+ class TStringAtoms {
+ private:
+ TMutex Mutex;
+ atomizer<ci_hash, ci_equal_to> Tags;
+
+ public:
+ static TStringAtoms& Instance() {
+ return *Singleton<TStringAtoms>();
+ }
+
+ ui32 MakeTag(const char* s) {
+ Y_VERIFY(s);
+ with_lock (Mutex) {
+ return Tags.string_to_atom(s);
+ }
+ }
+
+ ui32 MakeTags(const TVector<const char*>& ss) {
+ Y_VERIFY(ss);
+ with_lock (Mutex) {
+ ui32 baseTag = Tags.string_to_atom(ss[0]);
+ ui32 nextTag = baseTag + 1;
+ for (auto i = ss.begin() + 1; i != ss.end(); ++i, ++nextTag) {
+ Y_VERIFY(*i);
+ ui32 ctag = Tags.string_to_atom(*i);
+ Y_VERIFY(ctag == nextTag);
+ }
+ return baseTag;
+ }
+ }
+
+ const char* GetTag(ui32 tag) const {
+ with_lock (Mutex) {
+ return Tags.get_atom_name(tag);
+ }
+ }
+
+ size_t GetTagsCount() const {
+ with_lock (Mutex) {
+ return Tags.size();
+ }
+ }
+ };
+
+ ui32 MakeTag(const char* s) {
+ return TStringAtoms::Instance().MakeTag(s);
+ }
+
+ ui32 MakeTags(const TVector<const char*>& ss) {
+ return TStringAtoms::Instance().MakeTags(ss);
+ }
+
+ const char* GetTag(ui32 tag) {
+ return TStringAtoms::Instance().GetTag(tag);
+ }
+
+ size_t GetTagsCount() {
+ return TStringAtoms::Instance().GetTagsCount();
+ }
+
+ static ui32 SetThreadAllocTag_Default(ui32 tag) {
+ Y_UNUSED(tag);
+ return 0;
+ }
+
+#if defined(PROFILE_MEMORY_ALLOCATIONS)
+ static ui32 SetThreadAllocTag_YT(ui32 tag) {
+ auto prev = NYT::NYTAlloc::GetCurrentMemoryTag();
+ NYT::NYTAlloc::SetCurrentMemoryTag(tag);
+ return prev;
+ }
+
+ static TSetThreadAllocTag* SetThreadAllocTagFn() {
+ const auto& info = NMalloc::MallocInfo();
+
+ TStringBuf name(info.Name);
+ if (name.StartsWith("lf")) {
+ return (TSetThreadAllocTag*)NAllocDbg::SetThreadAllocTag;
+ } else if (name.StartsWith("yt")) {
+ return SetThreadAllocTag_YT;
+ } else if (name.StartsWith("tc")) {
+ return SetTCMallocThreadAllocTag;
+ } else {
+ return SetThreadAllocTag_Default;
+ }
+ }
+#else
+ static TSetThreadAllocTag* SetThreadAllocTagFn() {
+ const auto& info = NMalloc::MallocInfo();
+
+ TStringBuf name(info.Name);
+ if (name.StartsWith("tc")) {
+ return SetTCMallocThreadAllocTag;
+ } else {
+ return SetThreadAllocTag_Default;
+ }
+ }
+#endif
+
+ TSetThreadAllocTag* SetThreadAllocTag = SetThreadAllocTagFn();
+}
diff --git a/library/cpp/actors/prof/tag.h b/library/cpp/actors/prof/tag.h
new file mode 100644
index 0000000000..357e264a22
--- /dev/null
+++ b/library/cpp/actors/prof/tag.h
@@ -0,0 +1,73 @@
+#pragma once
+
+#include <util/generic/fwd.h>
+
+/*
+ Common registry for tagging memory profiler.
+ Register a new tag with MakeTag using a unique string.
+ Use registered tags with SetThreadAllocTag function in allocator API.
+*/
+
+namespace NProfiling {
+ ui32 MakeTag(const char* s);
+
+ // Make only unique tags. Y_VERIFY inside.
+ ui32 MakeTags(const TVector<const char*>& ss);
+
+ const char* GetTag(ui32 tag);
+ size_t GetTagsCount();
+
+ using TSetThreadAllocTag = ui32(ui32 tag);
+ extern TSetThreadAllocTag* SetThreadAllocTag;
+
+ class TMemoryTagScope {
+ public:
+ explicit TMemoryTagScope(ui32 tag)
+ : RestoreTag(SetThreadAllocTag(tag))
+ {
+ }
+
+ explicit TMemoryTagScope(const char* tagName) {
+ ui32 newTag = MakeTag(tagName);
+ RestoreTag = SetThreadAllocTag(newTag);
+ }
+
+ TMemoryTagScope(TMemoryTagScope&& move)
+ : RestoreTag(move.RestoreTag)
+ , Released(move.Released)
+ {
+ move.Released = true;
+ }
+
+ TMemoryTagScope& operator=(TMemoryTagScope&& move) {
+ RestoreTag = move.RestoreTag;
+ Released = move.Released;
+ move.Released = true;
+ return *this;
+ }
+
+ static void Reset(ui32 tag) {
+ SetThreadAllocTag(tag);
+ }
+
+ void Release() {
+ if (!Released) {
+ SetThreadAllocTag(RestoreTag);
+ Released = true;
+ }
+ }
+
+ ~TMemoryTagScope() {
+ if (!Released) {
+ SetThreadAllocTag(RestoreTag);
+ }
+ }
+
+ protected:
+ TMemoryTagScope(const TMemoryTagScope&) = delete;
+ void operator=(const TMemoryTagScope&) = delete;
+
+ ui32 RestoreTag = 0;
+ bool Released = false;
+ };
+}
diff --git a/library/cpp/actors/prof/tcmalloc.cpp b/library/cpp/actors/prof/tcmalloc.cpp
new file mode 100644
index 0000000000..3d4f203dbb
--- /dev/null
+++ b/library/cpp/actors/prof/tcmalloc.cpp
@@ -0,0 +1,32 @@
+#include "tcmalloc.h"
+
+#include <contrib/libs/tcmalloc/tcmalloc/malloc_extension.h>
+
+namespace NProfiling {
+
+static thread_local ui32 AllocationTag = 0;
+
+static struct TInitTCMallocCallbacks {
+ static void* CreateTag() {
+ return reinterpret_cast<void*>(AllocationTag);
+ }
+ static void* CopyTag(void* tag) {
+ return tag;
+ }
+ static void DestroyTag(void* tag) {
+ Y_UNUSED(tag);
+ }
+
+ TInitTCMallocCallbacks() {
+ tcmalloc::MallocExtension::SetSampleUserDataCallbacks(
+ CreateTag, CopyTag, DestroyTag);
+ }
+} InitTCMallocCallbacks;
+
+ui32 SetTCMallocThreadAllocTag(ui32 tag) {
+ ui32 prev = AllocationTag;
+ AllocationTag = tag;
+ return prev;
+}
+
+}
diff --git a/library/cpp/actors/prof/tcmalloc.h b/library/cpp/actors/prof/tcmalloc.h
new file mode 100644
index 0000000000..659fb4eaf3
--- /dev/null
+++ b/library/cpp/actors/prof/tcmalloc.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <util/generic/fwd.h>
+
+namespace NProfiling {
+
+ui32 SetTCMallocThreadAllocTag(ui32 tag);
+
+}
diff --git a/library/cpp/actors/prof/tcmalloc_null.cpp b/library/cpp/actors/prof/tcmalloc_null.cpp
new file mode 100644
index 0000000000..75c0013154
--- /dev/null
+++ b/library/cpp/actors/prof/tcmalloc_null.cpp
@@ -0,0 +1,10 @@
+#include "tcmalloc.h"
+
+namespace NProfiling {
+
+ui32 SetTCMallocThreadAllocTag(ui32 tag) {
+ Y_UNUSED(tag);
+ return 0;
+}
+
+}
diff --git a/library/cpp/actors/prof/ut/tag_ut.cpp b/library/cpp/actors/prof/ut/tag_ut.cpp
new file mode 100644
index 0000000000..accf3921ab
--- /dev/null
+++ b/library/cpp/actors/prof/ut/tag_ut.cpp
@@ -0,0 +1,68 @@
+#include "tag.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NProfiling;
+
+class TAtomTagsTest: public TTestBase {
+private:
+ UNIT_TEST_SUITE(TAtomTagsTest);
+ UNIT_TEST(Test_MakeTag);
+ UNIT_TEST(Test_Make2Tags);
+ UNIT_TEST(Test_MakeTagTwice);
+
+ UNIT_TEST(Test_MakeAndGetTag);
+
+ UNIT_TEST(Test_MakeVector);
+ UNIT_TEST_SUITE_END();
+
+public:
+ void Test_MakeTag();
+ void Test_Make2Tags();
+ void Test_MakeTagTwice();
+ void Test_MakeAndGetTag();
+ void Test_MakeVector();
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TAtomTagsTest);
+
+void TAtomTagsTest::Test_MakeTag() {
+ ui32 tag = MakeTag("a tag");
+ UNIT_ASSERT(tag != 0);
+}
+
+void TAtomTagsTest::Test_Make2Tags() {
+ ui32 tag1 = MakeTag("a tag 1");
+ ui32 tag2 = MakeTag("a tag 2");
+ UNIT_ASSERT(tag1 != 0);
+ UNIT_ASSERT(tag2 != 0);
+ UNIT_ASSERT(tag1 != tag2);
+}
+
+void TAtomTagsTest::Test_MakeTagTwice() {
+ ui32 tag1 = MakeTag("a tag twice");
+ ui32 tag2 = MakeTag("a tag twice");
+ UNIT_ASSERT(tag1 != 0);
+ UNIT_ASSERT(tag1 == tag2);
+}
+
+void TAtomTagsTest::Test_MakeAndGetTag() {
+ const char* makeStr = "tag to get";
+ ui32 tag = MakeTag(makeStr);
+ const char* tagStr = GetTag(tag);
+ UNIT_ASSERT_STRINGS_EQUAL(makeStr, tagStr);
+}
+
+void TAtomTagsTest::Test_MakeVector() {
+ TVector<const char*> strs = {
+ "vector tag 0",
+ "vector tag 1",
+ "vector tag 3",
+ "vector tag 4"};
+ ui32 baseTag = MakeTags(strs);
+ UNIT_ASSERT(baseTag != 0);
+ for (ui32 i = 0; i < strs.size(); ++i) {
+ const char* str = GetTag(baseTag + i);
+ UNIT_ASSERT_STRINGS_EQUAL(str, strs[i]);
+ }
+}
diff --git a/library/cpp/actors/prof/ut/ya.make b/library/cpp/actors/prof/ut/ya.make
new file mode 100644
index 0000000000..47c58a8fb7
--- /dev/null
+++ b/library/cpp/actors/prof/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/actors/prof)
+
+OWNER(
+ agri
+ g:kikimr
+)
+
+SRCS(
+ tag_ut.cpp
+)
+
+END()
diff --git a/library/cpp/actors/prof/ya.make b/library/cpp/actors/prof/ya.make
new file mode 100644
index 0000000000..b5e2497563
--- /dev/null
+++ b/library/cpp/actors/prof/ya.make
@@ -0,0 +1,33 @@
+LIBRARY()
+
+OWNER(
+ agri
+ g:kikimr
+)
+
+SRCS(
+ tag.cpp
+)
+
+PEERDIR(
+ library/cpp/charset
+ library/cpp/containers/atomizer
+)
+
+IF (PROFILE_MEMORY_ALLOCATIONS)
+ CFLAGS(-DPROFILE_MEMORY_ALLOCATIONS)
+ PEERDIR(
+ library/cpp/malloc/api
+ library/cpp/lfalloc/dbg_info
+ library/cpp/ytalloc/api
+ )
+ENDIF()
+
+IF(ALLOCATOR == "TCMALLOC_256K")
+ SRCS(tcmalloc.cpp)
+ PEERDIR(contrib/libs/tcmalloc)
+ELSE()
+ SRCS(tcmalloc_null.cpp)
+ENDIF()
+
+END()
diff --git a/library/cpp/actors/protos/actors.proto b/library/cpp/actors/protos/actors.proto
new file mode 100644
index 0000000000..5fbd6d44ee
--- /dev/null
+++ b/library/cpp/actors/protos/actors.proto
@@ -0,0 +1,13 @@
+package NActorsProto;
+option java_package = "ru.yandex.kikimr.proto";
+option java_outer_classname = "NActorsBaseProto";
+
+message TActorId {
+ required fixed64 RawX1 = 1;
+ required fixed64 RawX2 = 2;
+}
+
+message TCallbackException {
+ required TActorId ActorId = 1;
+ required string ExceptionMessage = 2;
+}
diff --git a/library/cpp/actors/protos/interconnect.proto b/library/cpp/actors/protos/interconnect.proto
new file mode 100644
index 0000000000..2e3b0d0d15
--- /dev/null
+++ b/library/cpp/actors/protos/interconnect.proto
@@ -0,0 +1,113 @@
+import "library/cpp/actors/protos/actors.proto";
+import "google/protobuf/descriptor.proto";
+
+package NActorsInterconnect;
+option java_package = "ru.yandex.kikimr.proto";
+
+message TEvResolveNode {
+ optional uint32 NodeId = 1;
+ optional uint64 Deadline = 2;
+}
+
+message TEvNodeInfo {
+ optional uint32 NodeId = 1;
+ optional string Address = 2;
+ optional uint32 Port = 3;
+}
+
+extend google.protobuf.FieldOptions {
+ optional string PrintName = 50376;
+}
+
+message TNodeLocation {
+ // compatibility section -- will be removed in future versions
+ optional uint32 DataCenterNum = 1 [deprecated=true];
+ optional uint32 RoomNum = 2 [deprecated=true];
+ optional uint32 RackNum = 3 [deprecated=true];
+ optional uint32 BodyNum = 4 [deprecated=true];
+ optional uint32 Body = 100500 [deprecated=true]; // for compatibility with WalleLocation
+
+ optional string DataCenter = 10 [(PrintName) = "DC"];
+ optional string Module = 20 [(PrintName) = "M"];
+ optional string Rack = 30 [(PrintName) = "R"];
+ optional string Unit = 40 [(PrintName) = "U"];
+}
+
+message TClusterUUIDs {
+ optional string ClusterUUID = 1;
+ repeated string AcceptUUID = 2;
+}
+
+message TScopeId {
+ optional fixed64 X1 = 1;
+ optional fixed64 X2 = 2;
+}
+
+message THandshakeRequest {
+ required uint64 Protocol = 1;
+
+ required uint64 ProgramPID = 2;
+ required uint64 ProgramStartTime = 3;
+ required uint64 Serial = 4;
+
+ required uint32 ReceiverNodeId = 5;
+ required string SenderActorId = 6;
+
+ optional string SenderHostName = 7;
+ optional string ReceiverHostName = 8;
+ optional string UUID = 9;
+ optional TClusterUUIDs ClusterUUIDs = 13;
+
+ optional bytes Ballast = 10;
+
+ optional string VersionTag = 11;
+ repeated string AcceptedVersionTags = 12;
+
+ optional bool RequireEncryption = 14;
+ optional TScopeId ClientScopeId = 15;
+
+ optional string Cookie = 16;
+ optional bool DoCheckCookie = 17;
+
+ optional bool RequestModernFrame = 18;
+
+ optional bool RequestAuthOnly = 19;
+}
+
+message THandshakeSuccess {
+ required uint64 Protocol = 1;
+
+ required uint64 ProgramPID = 2;
+ required uint64 ProgramStartTime = 3;
+ required uint64 Serial = 4;
+
+ required string SenderActorId = 5;
+
+ optional string VersionTag = 6;
+ repeated string AcceptedVersionTags = 7;
+
+ optional TClusterUUIDs ClusterUUIDs = 8;
+
+ optional bool StartEncryption = 9;
+ optional TScopeId ServerScopeId = 10;
+
+ optional bool UseModernFrame = 11;
+
+ optional bool AuthOnly = 12;
+}
+
+message THandshakeReply {
+ optional THandshakeSuccess Success = 1;
+ optional string ErrorExplaination = 2;
+ optional bool CookieCheckResult = 3;
+}
+
+message TEvLoadMessage {
+ message THop {
+ optional NActorsProto.TActorId NextHop = 1; // if zero, then the payload is trimmed out of the message
+ }
+
+ repeated THop Hops = 1; // the route for the message
+ optional string Id = 3; // message identifier
+ optional bytes Payload = 4; // data payload
+}
diff --git a/library/cpp/actors/protos/services_common.proto b/library/cpp/actors/protos/services_common.proto
new file mode 100644
index 0000000000..afa0ec0073
--- /dev/null
+++ b/library/cpp/actors/protos/services_common.proto
@@ -0,0 +1,21 @@
+package NActorsServices;
+option java_package = "ru.yandex.kikimr.proto";
+
+// 0-255 range
+enum EServiceCommon {
+ // WARN: This must be the smallest value in the enumeration
+
+ GLOBAL = 0;
+ INTERCONNECT = 1;
+ TEST = 2;
+ PROTOCOLS = 3;
+ INTERCONNECT_SPEED_TEST = 4;
+ INTERCONNECT_STATUS = 5;
+ INTERCONNECT_NETWORK = 6;
+ INTERCONNECT_SESSION = 7;
+ HTTP = 8;
+
+ // This value is reserved boundary. Is must not be aliased with any values
+ // TODO: use reseved values upon protobuf update
+ // COMMON_END = 256;
+};
diff --git a/library/cpp/actors/protos/unittests.proto b/library/cpp/actors/protos/unittests.proto
new file mode 100644
index 0000000000..a856b0942a
--- /dev/null
+++ b/library/cpp/actors/protos/unittests.proto
@@ -0,0 +1,20 @@
+option cc_enable_arenas = true;
+
+message TSimple {
+ required string Str1 = 1;
+ optional string Str2 = 2;
+ optional uint64 Number1 = 3;
+}
+
+message TBigMessage {
+ repeated TSimple Simples = 1;
+ repeated string ManyStr = 2;
+ optional string OneMoreStr = 3;
+ optional uint64 YANumber = 4;
+}
+
+message TMessageWithPayload {
+ optional string Meta = 1;
+ repeated uint32 PayloadId = 2;
+ repeated string SomeData = 3;
+}
diff --git a/library/cpp/actors/protos/ya.make b/library/cpp/actors/protos/ya.make
new file mode 100644
index 0000000000..3a1488d78e
--- /dev/null
+++ b/library/cpp/actors/protos/ya.make
@@ -0,0 +1,14 @@
+PROTO_LIBRARY()
+
+OWNER(g:kikimr)
+
+SRCS(
+ actors.proto
+ interconnect.proto
+ services_common.proto
+ unittests.proto
+)
+
+EXCLUDE_TAGS(GO_PROTO)
+
+END()
diff --git a/library/cpp/actors/testlib/decorator_ut.cpp b/library/cpp/actors/testlib/decorator_ut.cpp
new file mode 100644
index 0000000000..e9a2fa3560
--- /dev/null
+++ b/library/cpp/actors/testlib/decorator_ut.cpp
@@ -0,0 +1,327 @@
+#include "test_runtime.h"
+
+#include <library/cpp/actors/core/actor_bootstrapped.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+
+using namespace NActors;
+
+
+Y_UNIT_TEST_SUITE(TesTTestDecorator) {
+
+ bool IsVerbose = false;
+ void Write(TString msg) {
+ if (IsVerbose) {
+ Cerr << (TStringBuilder() << msg << Endl);
+ }
+ }
+
+ struct TDyingChecker : TTestDecorator {
+ TActorId MasterId;
+
+ TDyingChecker(THolder<IActor> &&actor, TActorId masterId)
+ : TTestDecorator(std::move(actor))
+ , MasterId(masterId)
+ {
+ Write("TDyingChecker::Construct\n");
+ }
+
+ virtual ~TDyingChecker() {
+ Write("TDyingChecker::~TDyingChecker");
+ TActivationContext::Send(new IEventHandle(MasterId, SelfId(), new TEvents::TEvPing()));
+ }
+
+ bool DoBeforeReceiving(TAutoPtr<IEventHandle> &/*ev*/, const TActorContext &/*ctx*/) override {
+ Write("TDyingChecker::DoBeforeReceiving");
+ return true;
+ }
+
+ void DoAfterReceiving(const TActorContext &/*ctx*/) override {
+ Write("TDyingChecker::DoAfterReceiving");
+ }
+ };
+
+ struct TTestMasterActor : TActorBootstrapped<TTestMasterActor> {
+ friend TActorBootstrapped<TTestMasterActor>;
+
+ TSet<TActorId> ActorIds;
+ TVector<THolder<IActor>> Actors;
+ TActorId EdgeActor;
+
+ TTestMasterActor(TVector<THolder<IActor>> &&actors, TActorId edgeActor)
+ : TActorBootstrapped()
+ , Actors(std::move(actors))
+ , EdgeActor(edgeActor)
+ {
+ }
+
+ void Bootstrap()
+ {
+ Write("Start master actor");
+ for (auto &actor : Actors) {
+ THolder<IActor> decaratedActor = MakeHolder<TDyingChecker>(std::move(actor), SelfId());
+ TActorId id = Register(decaratedActor.Release());
+ Write("Register test actor");
+ UNIT_ASSERT(ActorIds.insert(id).second);
+ }
+ Become(&TTestMasterActor::State);
+ }
+
+ STATEFN(State) {
+ auto it = ActorIds.find(ev->Sender);
+ UNIT_ASSERT(it != ActorIds.end());
+ Write("End test actor");
+ ActorIds.erase(it);
+ if (!ActorIds) {
+ Send(EdgeActor, new TEvents::TEvPing());
+ PassAway();
+ }
+ }
+ };
+
+ enum {
+ Begin = EventSpaceBegin(TEvents::ES_USERSPACE),
+ EvWords
+ };
+
+ struct TEvWords : TEventLocal<TEvWords, EvWords> {
+ TVector<TString> Words;
+
+ TEvWords()
+ : TEventLocal()
+ {
+ }
+ };
+
+ struct TFizzBuzzToFooBar : TTestDecorator {
+ TFizzBuzzToFooBar(THolder<IActor> &&actor)
+ : TTestDecorator(std::move(actor))
+ {
+ }
+
+ bool DoBeforeSending(TAutoPtr<IEventHandle> &ev) override {
+ if (ev->Type == TEvents::TSystem::Bootstrap) {
+ return true;
+ }
+ Write("TFizzBuzzToFooBar::DoBeforeSending");
+ TEventHandle<TEvWords> *handle = reinterpret_cast<TEventHandle<TEvWords>*>(ev.Get());
+ UNIT_ASSERT(handle);
+ TEvWords *event = handle->Get();
+ TVector<TString> &words = event->Words;
+ TStringBuilder wordsMsg;
+ for (auto &word : words) {
+ wordsMsg << word << ';';
+ }
+ Write(TStringBuilder() << "Send# " << wordsMsg);
+ if (words.size() == 2 && words[0] == "Fizz" && words[1] == "Buzz") {
+ words[0] = "Foo";
+ words[1] = "Bar";
+ }
+ return true;
+ }
+
+ bool DoBeforeReceiving(TAutoPtr<IEventHandle> &/*ev*/, const TActorContext &/*ctx*/) override {
+ Write("TFizzBuzzToFooBar::DoBeforeReceiving");
+ return true;
+ }
+
+ void DoAfterReceiving(const TActorContext &/*ctx*/) override {
+ Write("TFizzBuzzToFooBar::DoAfterReceiving");
+ }
+ };
+
+ struct TWordEraser : TTestDecorator {
+ TString ErasingWord;
+
+ TWordEraser(THolder<IActor> &&actor, TString word)
+ : TTestDecorator(std::move(actor))
+ , ErasingWord(word)
+ {
+ }
+
+ bool DoBeforeSending(TAutoPtr<IEventHandle> &ev) override {
+ if (ev->Type == TEvents::TSystem::Bootstrap) {
+ return true;
+ }
+ Write("TWordEraser::DoBeforeSending");
+ TEventHandle<TEvWords> *handle = reinterpret_cast<TEventHandle<TEvWords>*>(ev.Get());
+ UNIT_ASSERT(handle);
+ TEvWords *event = handle->Get();
+ TVector<TString> &words = event->Words;
+ auto it = Find(words.begin(), words.end(), ErasingWord);
+ if (it != words.end()) {
+ words.erase(it);
+ }
+ return true;
+ }
+
+ bool DoBeforeReceiving(TAutoPtr<IEventHandle> &/*ev*/, const TActorContext &/*ctx*/) override {
+ Write("TWordEraser::DoBeforeReceiving");
+ return true;
+ }
+
+ void DoAfterReceiving(const TActorContext &/*ctx*/) override {
+ Write("TWordEraser::DoAfterReceiving");
+ }
+ };
+
+ struct TWithoutWordsDroper : TTestDecorator {
+ TWithoutWordsDroper(THolder<IActor> &&actor)
+ : TTestDecorator(std::move(actor))
+ {
+ }
+
+ bool DoBeforeSending(TAutoPtr<IEventHandle> &ev) override {
+ if (ev->Type == TEvents::TSystem::Bootstrap) {
+ return true;
+ }
+ Write("TWithoutWordsDroper::DoBeforeSending");
+ TEventHandle<TEvWords> *handle = reinterpret_cast<TEventHandle<TEvWords>*>(ev.Get());
+ UNIT_ASSERT(handle);
+ TEvWords *event = handle->Get();
+ return bool(event->Words);
+ }
+
+ bool DoBeforeReceiving(TAutoPtr<IEventHandle> &/*ev*/, const TActorContext &/*ctx*/) override {
+ Write("TWithoutWordsDroper::DoBeforeReceiving");
+ return true;
+ }
+
+ void DoAfterReceiving(const TActorContext &/*ctx*/) override {
+ Write("TWithoutWordsDroper::DoAfterReceiving");
+ }
+ };
+
+ struct TFooBarReceiver : TActorBootstrapped<TFooBarReceiver> {
+ TActorId MasterId;
+ ui64 Counter = 0;
+
+ TFooBarReceiver(TActorId masterId)
+ : TActorBootstrapped()
+ , MasterId(masterId)
+ {
+ }
+
+ void Bootstrap()
+ {
+ Become(&TFooBarReceiver::State);
+ }
+
+ STATEFN(State) {
+ TEventHandle<TEvWords> *handle = reinterpret_cast<TEventHandle<TEvWords>*>(ev.Get());
+ UNIT_ASSERT(handle);
+ UNIT_ASSERT(handle->Sender == MasterId);
+ TEvWords *event = handle->Get();
+ TVector<TString> &words = event->Words;
+ UNIT_ASSERT(words.size() == 2 && words[0] == "Foo" && words[1] == "Bar");
+ Write(TStringBuilder() << "Receive# " << Counter + 1 << '/' << 2);
+ if (++Counter == 2) {
+ PassAway();
+ }
+ }
+ };
+
+ struct TFizzBuzzSender : TActorBootstrapped<TFizzBuzzSender> {
+ TActorId SlaveId;
+
+ TFizzBuzzSender()
+ : TActorBootstrapped()
+ {
+ Write("TFizzBuzzSender::Construct");
+ }
+
+ void Bootstrap() {
+ Write("TFizzBuzzSender::Bootstrap");
+ THolder<IActor> actor = MakeHolder<TFooBarReceiver>(SelfId());
+ THolder<IActor> decoratedActor = MakeHolder<TDyingChecker>(std::move(actor), SelfId());
+ SlaveId = Register(decoratedActor.Release());
+ for (ui64 idx = 1; idx <= 30; ++idx) {
+ THolder<TEvWords> ev = MakeHolder<TEvWords>();
+ if (idx % 3 == 0) {
+ ev->Words.push_back("Fizz");
+ }
+ if (idx % 5 == 0) {
+ ev->Words.push_back("Buzz");
+ }
+ Send(SlaveId, ev.Release());
+ Write("TFizzBuzzSender::Send words");
+ }
+ Become(&TFizzBuzzSender::State);
+ }
+
+ STATEFN(State) {
+ UNIT_ASSERT(ev->Sender == SlaveId);
+ PassAway();
+ }
+ };
+
+ struct TCounters {
+ ui64 SendedCount = 0;
+ ui64 RecievedCount = 0;
+ };
+
+ struct TCountingDecorator : TTestDecorator {
+ TCounters *Counters;
+
+ TCountingDecorator(THolder<IActor> &&actor, TCounters *counters)
+ : TTestDecorator(std::move(actor))
+ , Counters(counters)
+ {
+ }
+
+ bool DoBeforeSending(TAutoPtr<IEventHandle> &ev) override {
+ if (ev->Type == TEvents::TSystem::Bootstrap) {
+ return true;
+ }
+ Write("TCountingDecorator::DoBeforeSending");
+ Counters->SendedCount++;
+ return true;
+ }
+
+ bool DoBeforeReceiving(TAutoPtr<IEventHandle> &/*ev*/, const TActorContext &/*ctx*/) override {
+ Write("TCountingDecorator::DoBeforeReceiving");
+ Counters->RecievedCount++;
+ return true;
+ }
+ };
+
+ bool ScheduledFilterFunc(NActors::TTestActorRuntimeBase& runtime, TAutoPtr<NActors::IEventHandle>& event,
+ TDuration delay, TInstant& deadline) {
+ if (runtime.IsScheduleForActorEnabled(event->GetRecipientRewrite())) {
+ deadline = runtime.GetTimeProvider()->Now() + delay;
+ return false;
+ }
+ return true;
+ }
+
+ THolder<IActor> CreateFizzBuzzSender() {
+ THolder<IActor> actor = MakeHolder<TFizzBuzzSender>();
+ THolder<IActor> foobar = MakeHolder<TFizzBuzzToFooBar>(std::move(actor));
+ THolder<IActor> fizzEraser = MakeHolder<TWordEraser>(std::move(foobar), "Fizz");
+ THolder<IActor> buzzEraser = MakeHolder<TWordEraser>(std::move(fizzEraser), "Buzz");
+ return MakeHolder<TWithoutWordsDroper>(std::move(buzzEraser));
+ }
+
+ Y_UNIT_TEST(Basic) {
+ TTestActorRuntimeBase runtime(1, false);
+
+ runtime.SetScheduledEventFilter(&ScheduledFilterFunc);
+ runtime.SetEventFilter([](NActors::TTestActorRuntimeBase&, TAutoPtr<NActors::IEventHandle>&) {
+ return false;
+ });
+ runtime.Initialize();
+
+ TActorId edgeActor = runtime.AllocateEdgeActor();
+ TVector<THolder<IActor>> actors(1);
+ actors[0] = CreateFizzBuzzSender();
+ //actors[1] = CreateFizzBuzzSender();
+ THolder<IActor> testActor = MakeHolder<TTestMasterActor>(std::move(actors), edgeActor);
+ Write("Start test");
+ runtime.Register(testActor.Release());
+
+ TAutoPtr<IEventHandle> handle;
+ auto ev = runtime.GrabEdgeEventRethrow<TEvents::TEvPing>(handle);
+ UNIT_ASSERT(ev);
+ Write("Stop test");
+ }
+}
diff --git a/library/cpp/actors/testlib/test_runtime.cpp b/library/cpp/actors/testlib/test_runtime.cpp
new file mode 100644
index 0000000000..6fa25b9965
--- /dev/null
+++ b/library/cpp/actors/testlib/test_runtime.cpp
@@ -0,0 +1,1902 @@
+#include "test_runtime.h"
+
+#include <library/cpp/actors/core/actor_bootstrapped.h>
+#include <library/cpp/actors/core/callstack.h>
+#include <library/cpp/actors/core/executor_pool_basic.h>
+#include <library/cpp/actors/core/executor_pool_io.h>
+#include <library/cpp/actors/core/log.h>
+#include <library/cpp/actors/core/scheduler_basic.h>
+#include <library/cpp/actors/util/datetime.h>
+#include <library/cpp/actors/protos/services_common.pb.h>
+#include <library/cpp/random_provider/random_provider.h>
+#include <library/cpp/actors/interconnect/interconnect.h>
+#include <library/cpp/actors/interconnect/interconnect_tcp_proxy.h>
+#include <library/cpp/actors/interconnect/interconnect_proxy_wrapper.h>
+
+#include <util/generic/maybe.h>
+#include <util/generic/bt_exception.h>
+#include <util/random/mersenne.h>
+#include <util/string/printf.h>
+#include <typeinfo>
+
+bool VERBOSE = false;
+const bool PRINT_EVENT_BODY = false;
+
+namespace {
+
+ TString MakeClusterId() {
+ pid_t pid = getpid();
+ TStringBuilder uuid;
+ uuid << "Cluster for process with id: " << pid;
+ return uuid;
+ }
+}
+
+namespace NActors {
+ ui64 TScheduledEventQueueItem::NextUniqueId = 0;
+
+ void PrintEvent(TAutoPtr<IEventHandle>& ev, const TTestActorRuntimeBase* runtime) {
+ Cerr << "mailbox: " << ev->GetRecipientRewrite().Hint() << ", type: " << Sprintf("%08x", ev->GetTypeRewrite())
+ << ", from " << ev->Sender.LocalId();
+ TString name = runtime->GetActorName(ev->Sender);
+ if (!name.empty())
+ Cerr << " \"" << name << "\"";
+ Cerr << ", to " << ev->GetRecipientRewrite().LocalId();
+ name = runtime->GetActorName(ev->GetRecipientRewrite());
+ if (!name.empty())
+ Cerr << " \"" << name << "\"";
+ Cerr << ", ";
+ if (ev->HasEvent())
+ Cerr << " : " << (PRINT_EVENT_BODY ? ev->GetBase()->ToString() : ev->GetBase()->ToStringHeader());
+ else if (ev->HasBuffer())
+ Cerr << " : BUFFER";
+ else
+ Cerr << " : EMPTY";
+
+ Cerr << "\n";
+ }
+
+ TTestActorRuntimeBase::TNodeDataBase::TNodeDataBase() {
+ ActorSystemTimestamp = nullptr;
+ ActorSystemMonotonic = nullptr;
+ }
+
+ void TTestActorRuntimeBase::TNodeDataBase::Stop() {
+ if (Poller)
+ Poller->Stop();
+
+ if (MailboxTable) {
+ for (ui32 round = 0; !MailboxTable->Cleanup(); ++round)
+ Y_VERIFY(round < 10, "cyclic event/actor spawn while trying to shutdown actorsystem stub");
+ }
+
+ if (ActorSystem)
+ ActorSystem->Stop();
+
+ ActorSystem.Destroy();
+ Poller.Reset();
+ }
+
+ TTestActorRuntimeBase::TNodeDataBase::~TNodeDataBase() {
+ Stop();
+ }
+
+
+ class TTestActorRuntimeBase::TEdgeActor : public TActor<TEdgeActor> {
+ public:
+ static constexpr EActivityType ActorActivityType() {
+ return TEST_ACTOR_RUNTIME;
+ }
+
+ TEdgeActor(TTestActorRuntimeBase* runtime)
+ : TActor(&TEdgeActor::StateFunc)
+ , Runtime(runtime)
+ {
+ }
+
+ STFUNC(StateFunc) {
+ Y_UNUSED(ctx);
+ TGuard<TMutex> guard(Runtime->Mutex);
+ bool verbose = (Runtime->CurrentDispatchContext ? !Runtime->CurrentDispatchContext->Options->Quiet : true) && VERBOSE;
+ if (Runtime->BlockedOutput.find(ev->Sender) != Runtime->BlockedOutput.end()) {
+ verbose = false;
+ }
+
+ if (verbose) {
+ Cerr << "Got event at " << TInstant::MicroSeconds(Runtime->CurrentTimestamp) << ", ";
+ PrintEvent(ev, Runtime);
+ }
+
+ if (!Runtime->EventFilterFunc(*Runtime, ev)) {
+ ui32 nodeId = ev->GetRecipientRewrite().NodeId();
+ Y_VERIFY(nodeId != 0);
+ ui32 mailboxHint = ev->GetRecipientRewrite().Hint();
+ Runtime->GetMailbox(nodeId, mailboxHint).Send(ev);
+ Runtime->MailboxesHasEvents.Signal();
+ if (verbose)
+ Cerr << "Event was added to sent queue\n";
+ }
+ else {
+ if (verbose)
+ Cerr << "Event was dropped\n";
+ }
+ }
+
+ private:
+ TTestActorRuntimeBase* Runtime;
+ };
+
+ void TEventMailBox::Send(TAutoPtr<IEventHandle> ev) {
+ IEventHandle* ptr = ev.Get();
+ Y_VERIFY(ptr);
+#ifdef DEBUG_ORDER_EVENTS
+ ui64 counter = NextToSend++;
+ TrackSent[ptr] = counter;
+#endif
+ Sent.push_back(ev);
+ }
+
+ TAutoPtr<IEventHandle> TEventMailBox::Pop() {
+ TAutoPtr<IEventHandle> result = Sent.front();
+ Sent.pop_front();
+#ifdef DEBUG_ORDER_EVENTS
+ auto it = TrackSent.find(result.Get());
+ if (it != TrackSent.end()) {
+ Y_VERIFY(ExpectedReceive == it->second);
+ TrackSent.erase(result.Get());
+ ++ExpectedReceive;
+ }
+#endif
+ return result;
+ }
+
+ bool TEventMailBox::IsEmpty() const {
+ return Sent.empty();
+ }
+
+ void TEventMailBox::Capture(TEventsList& evList) {
+ evList.insert(evList.end(), Sent.begin(), Sent.end());
+ Sent.clear();
+ }
+
+ void TEventMailBox::PushFront(TAutoPtr<IEventHandle>& ev) {
+ Sent.push_front(ev);
+ }
+
+ void TEventMailBox::PushFront(TEventsList& evList) {
+ for (auto rit = evList.rbegin(); rit != evList.rend(); ++rit) {
+ if (*rit) {
+ Sent.push_front(*rit);
+ }
+ }
+ }
+
+ void TEventMailBox::CaptureScheduled(TScheduledEventsList& evList) {
+ for (auto it = Scheduled.begin(); it != Scheduled.end(); ++it) {
+ evList.insert(*it);
+ }
+
+ Scheduled.clear();
+ }
+
+ void TEventMailBox::PushScheduled(TScheduledEventsList& evList) {
+ for (auto it = evList.begin(); it != evList.end(); ++it) {
+ if (it->Event) {
+ Scheduled.insert(*it);
+ }
+ }
+
+ evList.clear();
+ }
+
+ bool TEventMailBox::IsActive(const TInstant& currentTime) const {
+ return currentTime >= InactiveUntil;
+ }
+
+ void TEventMailBox::Freeze(const TInstant& deadline) {
+ if (deadline > InactiveUntil)
+ InactiveUntil = deadline;
+ }
+
+ TInstant TEventMailBox::GetInactiveUntil() const {
+ return InactiveUntil;
+ }
+
+ void TEventMailBox::Schedule(const TScheduledEventQueueItem& item) {
+ Scheduled.insert(item);
+ }
+
+ bool TEventMailBox::IsScheduledEmpty() const {
+ return Scheduled.empty();
+ }
+
+ TInstant TEventMailBox::GetFirstScheduleDeadline() const {
+ return Scheduled.begin()->Deadline;
+ }
+
+ ui64 TEventMailBox::GetSentEventCount() const {
+ return Sent.size();
+ }
+
+ class TTestActorRuntimeBase::TTimeProvider : public ITimeProvider {
+ public:
+ TTimeProvider(TTestActorRuntimeBase& runtime)
+ : Runtime(runtime)
+ {
+ }
+
+ TInstant Now() override {
+ return Runtime.GetCurrentTime();
+ }
+
+ private:
+ TTestActorRuntimeBase& Runtime;
+ };
+
+ class TTestActorRuntimeBase::TSchedulerThreadStub : public ISchedulerThread {
+ public:
+ TSchedulerThreadStub(TTestActorRuntimeBase* runtime, TTestActorRuntimeBase::TNodeDataBase* node)
+ : Runtime(runtime)
+ , Node(node)
+ {
+ Y_UNUSED(Runtime);
+ }
+
+ void Prepare(TActorSystem *actorSystem, volatile ui64 *currentTimestamp, volatile ui64 *currentMonotonic) override {
+ Y_UNUSED(actorSystem);
+ Node->ActorSystemTimestamp = currentTimestamp;
+ Node->ActorSystemMonotonic = currentMonotonic;
+ }
+
+ void PrepareSchedules(NSchedulerQueue::TReader **readers, ui32 scheduleReadersCount) override {
+ Y_UNUSED(readers);
+ Y_UNUSED(scheduleReadersCount);
+ }
+
+ void Start() override {
+ }
+
+ void PrepareStop() override {
+ }
+
+ void Stop() override {
+ }
+
+ private:
+ TTestActorRuntimeBase* Runtime;
+ TTestActorRuntimeBase::TNodeDataBase* Node;
+ };
+
+ class TTestActorRuntimeBase::TExecutorPoolStub : public IExecutorPool {
+ public:
+ TExecutorPoolStub(TTestActorRuntimeBase* runtime, ui32 nodeIndex, TTestActorRuntimeBase::TNodeDataBase* node, ui32 poolId)
+ : IExecutorPool(poolId)
+ , Runtime(runtime)
+ , NodeIndex(nodeIndex)
+ , Node(node)
+ {
+ }
+
+ TTestActorRuntimeBase* GetRuntime() {
+ return Runtime;
+ }
+
+ // for threads
+ ui32 GetReadyActivation(TWorkerContext& wctx, ui64 revolvingCounter) override {
+ Y_UNUSED(wctx);
+ Y_UNUSED(revolvingCounter);
+ Y_FAIL();
+ }
+
+ void ReclaimMailbox(TMailboxType::EType mailboxType, ui32 hint, TWorkerId workerId, ui64 revolvingCounter) override {
+ Y_UNUSED(workerId);
+ Node->MailboxTable->ReclaimMailbox(mailboxType, hint, revolvingCounter);
+ }
+
+ void Schedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) override {
+ DoSchedule(deadline, ev, cookie, workerId);
+ }
+
+ void Schedule(TMonotonic deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) override {
+ DoSchedule(TInstant::FromValue(deadline.GetValue()), ev, cookie, workerId);
+ }
+
+ void Schedule(TDuration delay, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) override {
+ TInstant deadline = Runtime->GetTimeProvider()->Now() + delay;
+ DoSchedule(deadline, ev, cookie, workerId);
+ }
+
+ void DoSchedule(TInstant deadline, TAutoPtr<IEventHandle> ev, ISchedulerCookie *cookie, TWorkerId workerId) {
+ Y_UNUSED(workerId);
+
+ TGuard<TMutex> guard(Runtime->Mutex);
+ bool verbose = (Runtime->CurrentDispatchContext ? !Runtime->CurrentDispatchContext->Options->Quiet : true) && VERBOSE;
+ if (Runtime->BlockedOutput.find(ev->Sender) != Runtime->BlockedOutput.end()) {
+ verbose = false;
+ }
+
+ if (verbose) {
+ Cerr << "Got scheduled event at " << TInstant::MicroSeconds(Runtime->CurrentTimestamp) << ", ";
+ PrintEvent(ev, Runtime);
+ }
+
+ auto now = Runtime->GetTimeProvider()->Now();
+ if (deadline < now) {
+ deadline = now; // avoid going backwards in time
+ }
+ TDuration delay = (deadline - now);
+
+ if (Runtime->SingleSysEnv || !Runtime->ScheduledEventFilterFunc(*Runtime, ev, delay, deadline)) {
+ ui32 mailboxHint = ev->GetRecipientRewrite().Hint();
+ Runtime->GetMailbox(Runtime->FirstNodeId + NodeIndex, mailboxHint).Schedule(TScheduledEventQueueItem(deadline, ev, cookie));
+ Runtime->MailboxesHasEvents.Signal();
+ if (verbose)
+ Cerr << "Event was added to scheduled queue\n";
+ } else {
+ if (cookie) {
+ cookie->Detach();
+ }
+ if (verbose) {
+ Cerr << "Scheduled event for " << ev->GetRecipientRewrite().ToString() << " was dropped\n";
+ }
+ }
+ }
+
+ // for actorsystem
+ bool Send(TAutoPtr<IEventHandle>& ev) override {
+ TGuard<TMutex> guard(Runtime->Mutex);
+ bool verbose = (Runtime->CurrentDispatchContext ? !Runtime->CurrentDispatchContext->Options->Quiet : true) && VERBOSE;
+ if (Runtime->BlockedOutput.find(ev->Sender) != Runtime->BlockedOutput.end()) {
+ verbose = false;
+ }
+
+ if (verbose) {
+ Cerr << "Got event at " << TInstant::MicroSeconds(Runtime->CurrentTimestamp) << ", ";
+ PrintEvent(ev, Runtime);
+ }
+
+ if (!Runtime->EventFilterFunc(*Runtime, ev)) {
+ ui32 nodeId = ev->GetRecipientRewrite().NodeId();
+ Y_VERIFY(nodeId != 0);
+ TNodeDataBase* node = Runtime->Nodes[nodeId].Get();
+
+ if (!AllowSendFrom(node, ev)) {
+ return true;
+ }
+
+ ui32 mailboxHint = ev->GetRecipientRewrite().Hint();
+ if (ev->GetTypeRewrite() == ui32(NActors::NLog::EEv::Log)) {
+ const NActors::TActorId loggerActorId = NActors::TActorId(nodeId, "logger");
+ TActorId logger = node->ActorSystem->LookupLocalService(loggerActorId);
+ if (ev->GetRecipientRewrite() == logger) {
+ TMailboxHeader* mailbox = node->MailboxTable->Get(mailboxHint);
+ IActor* recipientActor = mailbox->FindActor(ev->GetRecipientRewrite().LocalId());
+ if (recipientActor) {
+ TActorContext ctx(*mailbox, *node->ExecutorThread, GetCycleCountFast(), ev->GetRecipientRewrite());
+ TActivationContext *prevTlsActivationContext = TlsActivationContext;
+ TlsActivationContext = &ctx;
+ recipientActor->Receive(ev, ctx);
+ TlsActivationContext = prevTlsActivationContext;
+ // we expect the logger to never die in tests
+ }
+ }
+ } else {
+ Runtime->GetMailbox(nodeId, mailboxHint).Send(ev);
+ Runtime->MailboxesHasEvents.Signal();
+ }
+ if (verbose)
+ Cerr << "Event was added to sent queue\n";
+ } else {
+ if (verbose)
+ Cerr << "Event was dropped\n";
+ }
+ return true;
+ }
+
+ void ScheduleActivation(ui32 activation) override {
+ Y_UNUSED(activation);
+ }
+
+ void ScheduleActivationEx(ui32 activation, ui64 revolvingCounter) override {
+ Y_UNUSED(activation);
+ Y_UNUSED(revolvingCounter);
+ }
+
+ TActorId Register(IActor *actor, TMailboxType::EType mailboxType, ui64 revolvingCounter,
+ const TActorId& parentId) override {
+ return Runtime->Register(actor, NodeIndex, PoolId, mailboxType, revolvingCounter, parentId);
+ }
+
+ TActorId Register(IActor *actor, TMailboxHeader *mailbox, ui32 hint, const TActorId& parentId) override {
+ return Runtime->Register(actor, NodeIndex, PoolId, mailbox, hint, parentId);
+ }
+
+ // lifecycle stuff
+ void Prepare(TActorSystem *actorSystem, NSchedulerQueue::TReader **scheduleReaders, ui32 *scheduleSz) override {
+ Y_UNUSED(actorSystem);
+ Y_UNUSED(scheduleReaders);
+ Y_UNUSED(scheduleSz);
+ }
+
+ void Start() override {
+ }
+
+ void PrepareStop() override {
+ }
+
+ void Shutdown() override {
+ }
+
+ bool Cleanup() override {
+ return true;
+ }
+
+ // generic
+ TAffinity* Affinity() const override {
+ Y_FAIL();
+ }
+
+ private:
+ TTestActorRuntimeBase* const Runtime;
+ const ui32 NodeIndex;
+ TTestActorRuntimeBase::TNodeDataBase* const Node;
+ };
+
+ IExecutorPool* TTestActorRuntimeBase::CreateExecutorPoolStub(TTestActorRuntimeBase* runtime, ui32 nodeIndex, TTestActorRuntimeBase::TNodeDataBase* node, ui32 poolId) {
+ return new TExecutorPoolStub{runtime, nodeIndex, node, poolId};
+ }
+
+
+ ui32 TTestActorRuntimeBase::NextNodeId = 1;
+
+ TTestActorRuntimeBase::TTestActorRuntimeBase(THeSingleSystemEnv)
+ : TTestActorRuntimeBase(1, 1, false)
+ {
+ SingleSysEnv = true;
+ }
+
+ TTestActorRuntimeBase::TTestActorRuntimeBase(ui32 nodeCount, ui32 dataCenterCount, bool useRealThreads)
+ : ScheduledCount(0)
+ , ScheduledLimit(100000)
+ , MainThreadId(TThread::CurrentThreadId())
+ , ClusterUUID(MakeClusterId())
+ , FirstNodeId(NextNodeId)
+ , NodeCount(nodeCount)
+ , DataCenterCount(dataCenterCount)
+ , UseRealThreads(useRealThreads)
+ , LocalId(0)
+ , DispatchCyclesCount(0)
+ , DispatchedEventsCount(0)
+ , NeedMonitoring(false)
+ , RandomProvider(CreateDeterministicRandomProvider(DefaultRandomSeed))
+ , TimeProvider(new TTimeProvider(*this))
+ , ShouldContinue()
+ , CurrentTimestamp(0)
+ , DispatchTimeout(DEFAULT_DISPATCH_TIMEOUT)
+ , ReschedulingDelay(TDuration::MicroSeconds(0))
+ , ObserverFunc(&TTestActorRuntimeBase::DefaultObserverFunc)
+ , ScheduledEventsSelectorFunc(&CollapsedTimeScheduledEventsSelector)
+ , EventFilterFunc(&TTestActorRuntimeBase::DefaultFilterFunc)
+ , ScheduledEventFilterFunc(&TTestActorRuntimeBase::NopFilterFunc)
+ , RegistrationObserver(&TTestActorRuntimeBase::DefaultRegistrationObserver)
+ , CurrentDispatchContext(nullptr)
+ {
+ SetDispatcherRandomSeed(TInstant::Now(), 0);
+ EnableActorCallstack();
+ }
+
+ void TTestActorRuntimeBase::InitNode(TNodeDataBase* node, size_t nodeIndex) {
+ const NActors::TActorId loggerActorId = NActors::TActorId(FirstNodeId + nodeIndex, "logger");
+ node->LogSettings = new NActors::NLog::TSettings(loggerActorId, 410 /* NKikimrServices::LOGGER */,
+ NActors::NLog::PRI_WARN, NActors::NLog::PRI_WARN, 0);
+ node->LogSettings->SetAllowDrop(false);
+ node->LogSettings->SetThrottleDelay(TDuration::Zero());
+ node->DynamicCounters = new NMonitoring::TDynamicCounters;
+
+ InitNodeImpl(node, nodeIndex);
+ }
+
+ void TTestActorRuntimeBase::InitNodeImpl(TNodeDataBase* node, size_t nodeIndex) {
+ node->LogSettings->Append(
+ NActorsServices::EServiceCommon_MIN,
+ NActorsServices::EServiceCommon_MAX,
+ NActorsServices::EServiceCommon_Name
+ );
+
+ if (!UseRealThreads) {
+ node->SchedulerPool.Reset(CreateExecutorPoolStub(this, nodeIndex, node, 0));
+ node->MailboxTable.Reset(new TMailboxTable());
+ node->ActorSystem = MakeActorSystem(nodeIndex, node);
+ node->ExecutorThread.Reset(new TExecutorThread(0, 0, node->ActorSystem.Get(), node->SchedulerPool.Get(), node->MailboxTable.Get(), "TestExecutor"));
+ } else {
+ node->ActorSystem = MakeActorSystem(nodeIndex, node);
+ }
+
+ node->ActorSystem->Start();
+ }
+
+ bool TTestActorRuntimeBase::AllowSendFrom(TNodeDataBase* node, TAutoPtr<IEventHandle>& ev) {
+ ui64 senderLocalId = ev->Sender.LocalId();
+ ui64 senderMailboxHint = ev->Sender.Hint();
+ TMailboxHeader* senderMailbox = node->MailboxTable->Get(senderMailboxHint);
+ if (senderMailbox) {
+ IActor* senderActor = senderMailbox->FindActor(senderLocalId);
+ TTestDecorator *decorator = dynamic_cast<TTestDecorator*>(senderActor);
+ return !decorator || decorator->BeforeSending(ev);
+ }
+ return true;
+ }
+
+ TTestActorRuntimeBase::TTestActorRuntimeBase(ui32 nodeCount, ui32 dataCenterCount)
+ : TTestActorRuntimeBase(nodeCount, dataCenterCount, false) {
+ }
+
+ TTestActorRuntimeBase::TTestActorRuntimeBase(ui32 nodeCount, bool useRealThreads)
+ : TTestActorRuntimeBase(nodeCount, nodeCount, useRealThreads) {
+ }
+
+ TTestActorRuntimeBase::~TTestActorRuntimeBase() {
+ CleanupNodes();
+ Cerr.Flush();
+ Cerr.Flush();
+ Clog.Flush();
+
+ DisableActorCallstack();
+ }
+
+ void TTestActorRuntimeBase::CleanupNodes() {
+ Nodes.clear();
+ }
+
+ bool TTestActorRuntimeBase::IsRealThreads() const {
+ return UseRealThreads;
+ }
+
+ TTestActorRuntimeBase::EEventAction TTestActorRuntimeBase::DefaultObserverFunc(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event) {
+ Y_UNUSED(runtime);
+ Y_UNUSED(event);
+ return EEventAction::PROCESS;
+ }
+
+ void TTestActorRuntimeBase::DroppingScheduledEventsSelector(TTestActorRuntimeBase& runtime, TScheduledEventsList& scheduledEvents, TEventsList& queue) {
+ Y_UNUSED(runtime);
+ Y_UNUSED(queue);
+ scheduledEvents.clear();
+ }
+
+ bool TTestActorRuntimeBase::DefaultFilterFunc(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event) {
+ Y_UNUSED(runtime);
+ Y_UNUSED(event);
+ return false;
+ }
+
+ bool TTestActorRuntimeBase::NopFilterFunc(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event, TDuration delay, TInstant& deadline) {
+ Y_UNUSED(runtime);
+ Y_UNUSED(delay);
+ Y_UNUSED(event);
+ Y_UNUSED(deadline);
+ return true;
+ }
+
+
+ void TTestActorRuntimeBase::DefaultRegistrationObserver(TTestActorRuntimeBase& runtime, const TActorId& parentId, const TActorId& actorId) {
+ if (runtime.ScheduleWhiteList.find(parentId) != runtime.ScheduleWhiteList.end()) {
+ runtime.ScheduleWhiteList.insert(actorId);
+ runtime.ScheduleWhiteListParent[actorId] = parentId;
+ }
+ }
+
+ class TScheduledTreeItem {
+ public:
+ TString Name;
+ ui64 Count;
+ TVector<TScheduledTreeItem> Children;
+
+ TScheduledTreeItem(const TString& name)
+ : Name(name)
+ , Count(0)
+ {}
+
+ TScheduledTreeItem* GetItem(const TString& name) {
+ TScheduledTreeItem* item = nullptr;
+ for (TScheduledTreeItem& i : Children) {
+ if (i.Name == name) {
+ item = &i;
+ break;
+ }
+ }
+ if (item != nullptr)
+ return item;
+ Children.emplace_back(name);
+ return &Children.back();
+ }
+
+ void RecursiveSort() {
+ Sort(Children, [](const TScheduledTreeItem& a, const TScheduledTreeItem& b) -> bool { return a.Count > b.Count; });
+ for (TScheduledTreeItem& item : Children) {
+ item.RecursiveSort();
+ }
+ }
+
+ void Print(IOutputStream& stream, const TString& prefix) {
+ for (auto it = Children.begin(); it != Children.end(); ++it) {
+ bool lastChild = (std::next(it) == Children.end());
+ TString connectionPrefix = lastChild ? "└─ " : "├─ ";
+ TString subChildPrefix = lastChild ? " " : "│ ";
+ stream << prefix << connectionPrefix << it->Name << " (" << it->Count << ")\n";
+ it->Print(stream, prefix + subChildPrefix);
+ }
+ }
+
+ void Print(IOutputStream& stream) {
+ stream << Name << " (" << Count << ")\n";
+ Print(stream, TString());
+ }
+ };
+
+ void TTestActorRuntimeBase::CollapsedTimeScheduledEventsSelector(TTestActorRuntimeBase& runtime, TScheduledEventsList& scheduledEvents, TEventsList& queue) {
+ if (scheduledEvents.empty())
+ return;
+
+ TInstant time = scheduledEvents.begin()->Deadline;
+ while (!scheduledEvents.empty() && scheduledEvents.begin()->Deadline == time) {
+ static THashMap<std::pair<TActorId, TString>, ui64> eventTypes;
+ auto& item = *scheduledEvents.begin();
+ TString name = item.Event->GetBase() ? TypeName(*item.Event->GetBase()) : Sprintf("%08" PRIx32, item.Event->Type);
+ eventTypes[std::make_pair(item.Event->Recipient, name)]++;
+ runtime.ScheduledCount++;
+ if (runtime.ScheduledCount > runtime.ScheduledLimit) {
+// TScheduledTreeItem root("Root");
+// TVector<TString> path;
+// for (const auto& pr : eventTypes) {
+// path.clear();
+// path.push_back(runtime.GetActorName(pr.first.first));
+// for (auto it = runtime.ScheduleWhiteListParent.find(pr.first.first); it != runtime.ScheduleWhiteListParent.end(); it = runtime.ScheduleWhiteListParent.find(it->second)) {
+// path.insert(path.begin(), runtime.GetActorName(it->second));
+// }
+// path.push_back("<" + pr.first.second + ">"); // event name;
+// ui64 count = pr.second;
+// TScheduledTreeItem* item = &root;
+// item->Count += count;
+// for (TString name : path) {
+// item = item->GetItem(name);
+// item->Count += count;
+// }
+// }
+// root.RecursiveSort();
+// root.Print(Cerr);
+
+ ythrow TSchedulingLimitReachedException(runtime.ScheduledLimit);
+ }
+ if (item.Cookie->Get()) {
+ if (item.Cookie->Detach()) {
+ queue.push_back(item.Event);
+ }
+ } else {
+ queue.push_back(item.Event);
+ }
+
+ scheduledEvents.erase(scheduledEvents.begin());
+ }
+
+ runtime.UpdateCurrentTime(time);
+ }
+
+ TTestActorRuntimeBase::TEventObserver TTestActorRuntimeBase::SetObserverFunc(TEventObserver observerFunc) {
+ TGuard<TMutex> guard(Mutex);
+ auto result = ObserverFunc;
+ ObserverFunc = observerFunc;
+ return result;
+ }
+
+ TTestActorRuntimeBase::TScheduledEventsSelector TTestActorRuntimeBase::SetScheduledEventsSelectorFunc(TScheduledEventsSelector scheduledEventsSelectorFunc) {
+ TGuard<TMutex> guard(Mutex);
+ auto result = ScheduledEventsSelectorFunc;
+ ScheduledEventsSelectorFunc = scheduledEventsSelectorFunc;
+ return result;
+ }
+
+ TTestActorRuntimeBase::TEventFilter TTestActorRuntimeBase::SetEventFilter(TEventFilter filterFunc) {
+ TGuard<TMutex> guard(Mutex);
+ auto result = EventFilterFunc;
+ EventFilterFunc = filterFunc;
+ return result;
+ }
+
+ TTestActorRuntimeBase::TScheduledEventFilter TTestActorRuntimeBase::SetScheduledEventFilter(TScheduledEventFilter filterFunc) {
+ TGuard<TMutex> guard(Mutex);
+ auto result = ScheduledEventFilterFunc;
+ ScheduledEventFilterFunc = filterFunc;
+ return result;
+ }
+
+ TTestActorRuntimeBase::TRegistrationObserver TTestActorRuntimeBase::SetRegistrationObserverFunc(TRegistrationObserver observerFunc) {
+ TGuard<TMutex> guard(Mutex);
+ auto result = RegistrationObserver;
+ RegistrationObserver = observerFunc;
+ return result;
+ }
+
+ bool TTestActorRuntimeBase::IsVerbose() {
+ return VERBOSE;
+ }
+
+ void TTestActorRuntimeBase::SetVerbose(bool verbose) {
+ VERBOSE = verbose;
+ }
+
+ void TTestActorRuntimeBase::AddLocalService(const TActorId& actorId, const TActorSetupCmd& cmd, ui32 nodeIndex) {
+ Y_VERIFY(!IsInitialized);
+ Y_VERIFY(nodeIndex < NodeCount);
+ auto node = Nodes[nodeIndex + FirstNodeId];
+ if (!node) {
+ node = GetNodeFactory().CreateNode();
+ Nodes[nodeIndex + FirstNodeId] = node;
+ }
+
+ node->LocalServicesActors[actorId] = cmd.Actor;
+ node->LocalServices.push_back(std::make_pair(actorId, cmd));
+ }
+
+ void TTestActorRuntimeBase::InitNodes() {
+ NextNodeId += NodeCount;
+ Y_VERIFY(NodeCount > 0);
+
+ for (ui32 nodeIndex = 0; nodeIndex < NodeCount; ++nodeIndex) {
+ auto nodeIt = Nodes.emplace(FirstNodeId + nodeIndex, GetNodeFactory().CreateNode()).first;
+ TNodeDataBase* node = nodeIt->second.Get();
+ InitNode(node, nodeIndex);
+ }
+
+ }
+
+ void TTestActorRuntimeBase::Initialize() {
+ InitNodes();
+ IsInitialized = true;
+ }
+
+ void SetupCrossDC() {
+
+ }
+
+ TDuration TTestActorRuntimeBase::SetDispatchTimeout(TDuration timeout) {
+ TGuard<TMutex> guard(Mutex);
+ TDuration oldTimeout = DispatchTimeout;
+ DispatchTimeout = timeout;
+ return oldTimeout;
+ }
+
+ TDuration TTestActorRuntimeBase::SetReschedulingDelay(TDuration delay) {
+ TGuard<TMutex> guard(Mutex);
+ TDuration oldDelay = ReschedulingDelay;
+ ReschedulingDelay = delay;
+ return oldDelay;
+ }
+
+ void TTestActorRuntimeBase::SetLogBackend(const TAutoPtr<TLogBackend> logBackend) {
+ Y_VERIFY(!IsInitialized);
+ TGuard<TMutex> guard(Mutex);
+ LogBackend = logBackend;
+ }
+
+ void TTestActorRuntimeBase::SetLogPriority(NActors::NLog::EComponent component, NActors::NLog::EPriority priority) {
+ TGuard<TMutex> guard(Mutex);
+ for (ui32 nodeIndex = 0; nodeIndex < NodeCount; ++nodeIndex) {
+ TNodeDataBase* node = Nodes[FirstNodeId + nodeIndex].Get();
+ TString explanation;
+ auto status = node->LogSettings->SetLevel(priority, component, explanation);
+ if (status) {
+ Y_FAIL("SetLogPriority failed: %s", explanation.c_str());
+ }
+ }
+ }
+
+ TInstant TTestActorRuntimeBase::GetCurrentTime() const {
+ TGuard<TMutex> guard(Mutex);
+ Y_VERIFY(!UseRealThreads);
+ return TInstant::MicroSeconds(CurrentTimestamp);
+ }
+
+ void TTestActorRuntimeBase::UpdateCurrentTime(TInstant newTime) {
+ static int counter = 0;
+ ++counter;
+ if (VERBOSE) {
+ Cerr << "UpdateCurrentTime(" << counter << "," << newTime << ")\n";
+ }
+ TGuard<TMutex> guard(Mutex);
+ Y_VERIFY(!UseRealThreads);
+ if (newTime.MicroSeconds() > CurrentTimestamp) {
+ CurrentTimestamp = newTime.MicroSeconds();
+ for (auto& kv : Nodes) {
+ AtomicStore(kv.second->ActorSystemTimestamp, CurrentTimestamp);
+ AtomicStore(kv.second->ActorSystemMonotonic, CurrentTimestamp);
+ }
+ }
+ }
+
+ void TTestActorRuntimeBase::AdvanceCurrentTime(TDuration duration) {
+ UpdateCurrentTime(GetCurrentTime() + duration);
+ }
+
+ TIntrusivePtr<ITimeProvider> TTestActorRuntimeBase::GetTimeProvider() {
+ Y_VERIFY(!UseRealThreads);
+ return TimeProvider;
+ }
+
+ ui32 TTestActorRuntimeBase::GetNodeId(ui32 index) const {
+ Y_VERIFY(index < NodeCount);
+ return FirstNodeId + index;
+ }
+
+ ui32 TTestActorRuntimeBase::GetNodeCount() const {
+ return NodeCount;
+ }
+
+ ui64 TTestActorRuntimeBase::AllocateLocalId() {
+ TGuard<TMutex> guard(Mutex);
+ ui64 nextId = ++LocalId;
+ if (VERBOSE) {
+ Cerr << "Allocated id: " << nextId << "\n";
+ }
+
+ return nextId;
+ }
+
+ ui32 TTestActorRuntimeBase::InterconnectPoolId() const {
+ if (UseRealThreads && NSan::TSanIsOn()) {
+ // Interconnect coroutines may move across threads
+ // Use a special single-threaded pool to avoid that
+ return 4;
+ }
+ return 0;
+ }
+
+ TString TTestActorRuntimeBase::GetTempDir() {
+ if (!TmpDir)
+ TmpDir.Reset(new TTempDir());
+ return (*TmpDir)();
+ }
+
+ TActorId TTestActorRuntimeBase::Register(IActor* actor, ui32 nodeIndex, ui32 poolId, TMailboxType::EType mailboxType,
+ ui64 revolvingCounter, const TActorId& parentId) {
+ Y_VERIFY(nodeIndex < NodeCount);
+ TGuard<TMutex> guard(Mutex);
+ TNodeDataBase* node = Nodes[FirstNodeId + nodeIndex].Get();
+ if (UseRealThreads) {
+ Y_VERIFY(poolId < node->ExecutorPools.size());
+ return node->ExecutorPools[poolId]->Register(actor, mailboxType, revolvingCounter, parentId);
+ }
+
+ // first step - find good enough mailbox
+ ui32 hint = 0;
+ TMailboxHeader *mailbox = nullptr;
+
+ {
+ ui32 hintBackoff = 0;
+
+ while (hint == 0) {
+ hint = node->MailboxTable->AllocateMailbox(mailboxType, ++revolvingCounter);
+ mailbox = node->MailboxTable->Get(hint);
+
+ if (!mailbox->LockFromFree()) {
+ node->MailboxTable->ReclaimMailbox(mailboxType, hintBackoff, ++revolvingCounter);
+ hintBackoff = hint;
+ hint = 0;
+ }
+ }
+
+ node->MailboxTable->ReclaimMailbox(mailboxType, hintBackoff, ++revolvingCounter);
+ }
+
+ const ui64 localActorId = AllocateLocalId();
+ if (VERBOSE) {
+ Cerr << "Register actor " << TypeName(*actor) << " as " << localActorId << ", mailbox: " << hint << "\n";
+ }
+
+ // ok, got mailbox
+ mailbox->AttachActor(localActorId, actor);
+
+ // do init
+ const TActorId actorId(FirstNodeId + nodeIndex, poolId, localActorId, hint);
+ ActorNames[actorId] = TypeName(*actor);
+ RegistrationObserver(*this, parentId ? parentId : CurrentRecipient, actorId);
+ DoActorInit(node->ActorSystem.Get(), actor, actorId, parentId ? parentId : CurrentRecipient);
+
+ switch (mailboxType) {
+ case TMailboxType::Simple:
+ UnlockFromExecution((TMailboxTable::TSimpleMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter);
+ break;
+ case TMailboxType::Revolving:
+ UnlockFromExecution((TMailboxTable::TRevolvingMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter);
+ break;
+ case TMailboxType::HTSwap:
+ UnlockFromExecution((TMailboxTable::THTSwapMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter);
+ break;
+ case TMailboxType::ReadAsFilled:
+ UnlockFromExecution((TMailboxTable::TReadAsFilledMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter);
+ break;
+ case TMailboxType::TinyReadAsFilled:
+ UnlockFromExecution((TMailboxTable::TTinyReadAsFilledMailbox *)mailbox, node->ExecutorPools[0], false, hint, MaxWorkers, ++revolvingCounter);
+ break;
+ default:
+ Y_FAIL("Unsupported mailbox type");
+ }
+
+ return actorId;
+ }
+
+ TActorId TTestActorRuntimeBase::Register(IActor *actor, ui32 nodeIndex, ui32 poolId, TMailboxHeader *mailbox, ui32 hint,
+ const TActorId& parentId) {
+ Y_VERIFY(nodeIndex < NodeCount);
+ TGuard<TMutex> guard(Mutex);
+ TNodeDataBase* node = Nodes[FirstNodeId + nodeIndex].Get();
+ if (UseRealThreads) {
+ Y_VERIFY(poolId < node->ExecutorPools.size());
+ return node->ExecutorPools[poolId]->Register(actor, mailbox, hint, parentId);
+ }
+
+ const ui64 localActorId = AllocateLocalId();
+ if (VERBOSE) {
+ Cerr << "Register actor " << TypeName(*actor) << " as " << localActorId << "\n";
+ }
+
+ mailbox->AttachActor(localActorId, actor);
+ const TActorId actorId(FirstNodeId + nodeIndex, poolId, localActorId, hint);
+ ActorNames[actorId] = TypeName(*actor);
+ RegistrationObserver(*this, parentId ? parentId : CurrentRecipient, actorId);
+ DoActorInit(node->ActorSystem.Get(), actor, actorId, parentId ? parentId : CurrentRecipient);
+
+ return actorId;
+ }
+
+ TActorId TTestActorRuntimeBase::RegisterService(const TActorId& serviceId, const TActorId& actorId, ui32 nodeIndex) {
+ TGuard<TMutex> guard(Mutex);
+ Y_VERIFY(nodeIndex < NodeCount);
+ TNodeDataBase* node = Nodes[FirstNodeId + nodeIndex].Get();
+ if (!UseRealThreads) {
+ IActor* actor = FindActor(actorId, node);
+ node->LocalServicesActors[serviceId] = actor;
+ node->ActorToActorId[actor] = actorId;
+ }
+
+ return node->ActorSystem->RegisterLocalService(serviceId, actorId);
+ }
+
+ TActorId TTestActorRuntimeBase::AllocateEdgeActor(ui32 nodeIndex) {
+ TGuard<TMutex> guard(Mutex);
+ Y_VERIFY(nodeIndex < NodeCount);
+ TActorId edgeActor = Register(new TEdgeActor(this), nodeIndex);
+ EdgeActors.insert(edgeActor);
+ EdgeActorByMailbox[TEventMailboxId(edgeActor.NodeId(), edgeActor.Hint())] = edgeActor;
+ return edgeActor;
+ }
+
+ TEventsList TTestActorRuntimeBase::CaptureEvents() {
+ TGuard<TMutex> guard(Mutex);
+ TEventsList result;
+ for (auto& mbox : Mailboxes) {
+ mbox.second->Capture(result);
+ }
+
+ return result;
+ }
+
+ TEventsList TTestActorRuntimeBase::CaptureMailboxEvents(ui32 hint, ui32 nodeId) {
+ TGuard<TMutex> guard(Mutex);
+ Y_VERIFY(nodeId >= FirstNodeId && nodeId < FirstNodeId + NodeCount);
+ TEventsList result;
+ GetMailbox(nodeId, hint).Capture(result);
+ return result;
+ }
+
+ void TTestActorRuntimeBase::PushFront(TAutoPtr<IEventHandle>& ev) {
+ TGuard<TMutex> guard(Mutex);
+ ui32 nodeId = ev->GetRecipientRewrite().NodeId();
+ Y_VERIFY(nodeId != 0);
+ GetMailbox(nodeId, ev->GetRecipientRewrite().Hint()).PushFront(ev);
+ }
+
+ void TTestActorRuntimeBase::PushEventsFront(TEventsList& events) {
+ TGuard<TMutex> guard(Mutex);
+ for (auto rit = events.rbegin(); rit != events.rend(); ++rit) {
+ if (*rit) {
+ auto& ev = *rit;
+ ui32 nodeId = ev->GetRecipientRewrite().NodeId();
+ Y_VERIFY(nodeId != 0);
+ GetMailbox(nodeId, ev->GetRecipientRewrite().Hint()).PushFront(ev);
+ }
+ }
+
+ events.clear();
+ }
+
+ void TTestActorRuntimeBase::PushMailboxEventsFront(ui32 hint, ui32 nodeId, TEventsList& events) {
+ TGuard<TMutex> guard(Mutex);
+ Y_VERIFY(nodeId >= FirstNodeId && nodeId < FirstNodeId + NodeCount);
+ TEventsList result;
+ GetMailbox(nodeId, hint).PushFront(events);
+ events.clear();
+ }
+
+ TScheduledEventsList TTestActorRuntimeBase::CaptureScheduledEvents() {
+ TGuard<TMutex> guard(Mutex);
+ TScheduledEventsList result;
+ for (auto& mbox : Mailboxes) {
+ mbox.second->CaptureScheduled(result);
+ }
+
+ return result;
+ }
+
+ bool TTestActorRuntimeBase::DispatchEvents(const TDispatchOptions& options) {
+ return DispatchEvents(options, TInstant::Max());
+ }
+
+ bool TTestActorRuntimeBase::DispatchEvents(const TDispatchOptions& options, TDuration simTimeout) {
+ return DispatchEvents(options, TInstant::MicroSeconds(CurrentTimestamp) + simTimeout);
+ }
+
+ bool TTestActorRuntimeBase::DispatchEvents(const TDispatchOptions& options, TInstant simDeadline) {
+ TGuard<TMutex> guard(Mutex);
+ return DispatchEventsInternal(options, simDeadline);
+ }
+
+ // Mutex must be locked by caller!
+ bool TTestActorRuntimeBase::DispatchEventsInternal(const TDispatchOptions& options, TInstant simDeadline) {
+ TDispatchContext localContext;
+ localContext.Options = &options;
+ localContext.PrevContext = nullptr;
+ bool verbose = !options.Quiet && VERBOSE;
+
+ struct TDispatchContextSetter {
+ TDispatchContextSetter(TTestActorRuntimeBase& runtime, TDispatchContext& lastContext)
+ : Runtime(runtime)
+ {
+ lastContext.PrevContext = Runtime.CurrentDispatchContext;
+ Runtime.CurrentDispatchContext = &lastContext;
+ }
+
+ ~TDispatchContextSetter() {
+ Runtime.CurrentDispatchContext = Runtime.CurrentDispatchContext->PrevContext;
+ }
+
+ TTestActorRuntimeBase& Runtime;
+ } DispatchContextSetter(*this, localContext);
+
+ TInstant dispatchTime = TInstant::MicroSeconds(0);
+ TInstant deadline = dispatchTime + DispatchTimeout;
+ const TDuration scheduledEventsInspectInterval = TDuration::MilliSeconds(10);
+ TInstant inspectScheduledEventsAt = dispatchTime + scheduledEventsInspectInterval;
+ if (verbose) {
+ Cerr << "Start dispatch at " << TInstant::MicroSeconds(CurrentTimestamp) << ", deadline is " << deadline << "\n";
+ }
+
+ struct TTempEdgeEventsCaptor {
+ TTempEdgeEventsCaptor(TTestActorRuntimeBase& runtime)
+ : Runtime(runtime)
+ , HasEvents(false)
+ {
+ for (auto edgeActor : Runtime.EdgeActors) {
+ TEventsList events;
+ Runtime.GetMailbox(edgeActor.NodeId(), edgeActor.Hint()).Capture(events);
+ auto mboxId = TEventMailboxId(edgeActor.NodeId(), edgeActor.Hint());
+ auto storeIt = Store.find(mboxId);
+ Y_VERIFY(storeIt == Store.end());
+ storeIt = Store.insert(std::make_pair(mboxId, new TEventMailBox)).first;
+ storeIt->second->PushFront(events);
+ if (!events.empty())
+ HasEvents = true;
+ }
+ }
+
+ ~TTempEdgeEventsCaptor() {
+ for (auto edgeActor : Runtime.EdgeActors) {
+ auto mboxId = TEventMailboxId(edgeActor.NodeId(), edgeActor.Hint());
+ auto storeIt = Store.find(mboxId);
+ if (storeIt == Store.end()) {
+ continue;
+ }
+
+ TEventsList events;
+ storeIt->second->Capture(events);
+ Runtime.GetMailbox(edgeActor.NodeId(), edgeActor.Hint()).PushFront(events);
+ }
+ }
+
+ TTestActorRuntimeBase& Runtime;
+ TEventMailBoxList Store;
+ bool HasEvents;
+ };
+
+ TEventMailBoxList restrictedMailboxes;
+ const bool useRestrictedMailboxes = !options.OnlyMailboxes.empty();
+ for (auto mailboxId : options.OnlyMailboxes) {
+ auto it = Mailboxes.find(mailboxId);
+ if (it == Mailboxes.end()) {
+ it = Mailboxes.insert(std::make_pair(mailboxId, new TEventMailBox())).first;
+ }
+
+ restrictedMailboxes.insert(std::make_pair(mailboxId, it->second));
+ }
+
+ TAutoPtr<TTempEdgeEventsCaptor> tempEdgeEventsCaptor;
+ if (!restrictedMailboxes) {
+ tempEdgeEventsCaptor.Reset(new TTempEdgeEventsCaptor(*this));
+ }
+
+ TEventMailBoxList& currentMailboxes = useRestrictedMailboxes ? restrictedMailboxes : Mailboxes;
+ while (!currentMailboxes.empty()) {
+ bool hasProgress = true;
+ while (hasProgress) {
+ ++DispatchCyclesCount;
+ hasProgress = false;
+
+ ui64 eventsToDispatch = 0;
+ for (auto mboxIt = currentMailboxes.begin(); mboxIt != currentMailboxes.end(); ++mboxIt) {
+ if (mboxIt->second->IsActive(TInstant::MicroSeconds(CurrentTimestamp))) {
+ eventsToDispatch += mboxIt->second->GetSentEventCount();
+ }
+ }
+ ui32 eventsDispatched = 0;
+
+ //TODO: count events before each cycle, break after dispatching that much events
+ bool isEmpty = false;
+ while (!isEmpty && eventsDispatched < eventsToDispatch) {
+ ui64 mailboxCount = currentMailboxes.size();
+ ui64 startWith = mailboxCount ? DispatcherRandomProvider->GenRand64() % mailboxCount : 0ull;
+ auto startWithMboxIt = currentMailboxes.begin();
+ for (ui64 i = 0; i < startWith; ++i) {
+ ++startWithMboxIt;
+ }
+ auto endWithMboxIt = startWithMboxIt;
+
+ isEmpty = true;
+ auto mboxIt = startWithMboxIt;
+ TDeque<TEventMailboxId> suspectedBoxes;
+ while (true) {
+ auto& mbox = *mboxIt;
+ bool isIgnored = true;
+ if (!mbox.second->IsEmpty()) {
+ HandleNonEmptyMailboxesForEachContext(mbox.first);
+ if (mbox.second->IsActive(TInstant::MicroSeconds(CurrentTimestamp))) {
+
+ bool isEdgeMailbox = false;
+ if (EdgeActorByMailbox.FindPtr(TEventMailboxId(mbox.first.NodeId, mbox.first.Hint))) {
+ isEdgeMailbox = true;
+ TEventsList events;
+ mbox.second->Capture(events);
+ for (auto& ev : events) {
+ TInverseGuard<TMutex> inverseGuard(Mutex);
+ ObserverFunc(*this, ev);
+ }
+ mbox.second->PushFront(events);
+ }
+
+ if (!isEdgeMailbox) {
+ isEmpty = false;
+ isIgnored = false;
+ ++eventsDispatched;
+ ++DispatchedEventsCount;
+ if (DispatchedEventsCount > DispatchedEventsLimit) {
+ ythrow TWithBackTrace<yexception>() << "Dispatched "
+ << DispatchedEventsLimit << " events, limit reached.";
+ }
+
+ auto ev = mbox.second->Pop();
+ if (BlockedOutput.find(ev->Sender) == BlockedOutput.end()) {
+ //UpdateCurrentTime(TInstant::MicroSeconds(CurrentTimestamp + 10));
+ if (verbose) {
+ Cerr << "Process event at " << TInstant::MicroSeconds(CurrentTimestamp) << ", ";
+ PrintEvent(ev, this);
+ }
+ }
+
+ hasProgress = true;
+ EEventAction action;
+ {
+ TInverseGuard<TMutex> inverseGuard(Mutex);
+ action = ObserverFunc(*this, ev);
+ }
+
+ switch (action) {
+ case EEventAction::PROCESS:
+ UpdateFinalEventsStatsForEachContext(*ev);
+ SendInternal(ev.Release(), mbox.first.NodeId - FirstNodeId, false);
+ break;
+ case EEventAction::DROP:
+ // do nothing
+ break;
+ case EEventAction::RESCHEDULE: {
+ TInstant deadline = TInstant::MicroSeconds(CurrentTimestamp) + ReschedulingDelay;
+ mbox.second->Freeze(deadline);
+ mbox.second->PushFront(ev);
+ break;
+ }
+ default:
+ Y_FAIL("Unknown action");
+ }
+ }
+ }
+
+ }
+ Y_VERIFY(mboxIt != currentMailboxes.end());
+ if (!isIgnored && !CurrentDispatchContext->PrevContext && !restrictedMailboxes &&
+ mboxIt->second->IsEmpty() &&
+ mboxIt->second->IsScheduledEmpty() &&
+ mboxIt->second->IsActive(TInstant::MicroSeconds(CurrentTimestamp))) {
+ suspectedBoxes.push_back(mboxIt->first);
+ }
+ ++mboxIt;
+ if (mboxIt == currentMailboxes.end()) {
+ mboxIt = currentMailboxes.begin();
+ }
+ Y_VERIFY(endWithMboxIt != currentMailboxes.end());
+ if (mboxIt == endWithMboxIt) {
+ break;
+ }
+ }
+
+ for (auto id : suspectedBoxes) {
+ auto it = currentMailboxes.find(id);
+ if (it != currentMailboxes.end() && it->second->IsEmpty() && it->second->IsScheduledEmpty() &&
+ it->second->IsActive(TInstant::MicroSeconds(CurrentTimestamp))) {
+ currentMailboxes.erase(it);
+ }
+ }
+ }
+ }
+
+ if (localContext.FinalEventFound) {
+ return true;
+ }
+
+ if (!localContext.FoundNonEmptyMailboxes.empty())
+ return true;
+
+ if (options.CustomFinalCondition && options.CustomFinalCondition())
+ return true;
+
+ if (options.FinalEvents.empty()) {
+ for (auto& mbox : currentMailboxes) {
+ if (!mbox.second->IsActive(TInstant::MicroSeconds(CurrentTimestamp)))
+ continue;
+
+ if (!mbox.second->IsEmpty()) {
+ if (verbose) {
+ Cerr << "Dispatch complete with non-empty queue at " << TInstant::MicroSeconds(CurrentTimestamp) << "\n";
+ }
+
+ return true;
+ }
+ }
+ }
+
+ if (TInstant::MicroSeconds(CurrentTimestamp) > simDeadline) {
+ return false;
+ }
+
+ if (dispatchTime >= deadline) {
+ if (verbose) {
+ Cerr << "Reach deadline at " << TInstant::MicroSeconds(CurrentTimestamp) << "\n";
+ }
+
+ ythrow TWithBackTrace<TEmptyEventQueueException>();
+ }
+
+ if (!options.Quiet && dispatchTime >= inspectScheduledEventsAt) {
+ inspectScheduledEventsAt = dispatchTime + scheduledEventsInspectInterval;
+ bool isEmpty = true;
+ TMaybe<TInstant> nearestMailboxDeadline;
+ TVector<TIntrusivePtr<TEventMailBox>> nextScheduleMboxes;
+ TMaybe<TInstant> nextScheduleDeadline;
+ for (auto& mbox : currentMailboxes) {
+ if (!mbox.second->IsActive(TInstant::MicroSeconds(CurrentTimestamp))) {
+ if (!nearestMailboxDeadline.Defined() || *nearestMailboxDeadline.Get() > mbox.second->GetInactiveUntil()) {
+ nearestMailboxDeadline = mbox.second->GetInactiveUntil();
+ }
+
+ continue;
+ }
+
+ if (mbox.second->IsScheduledEmpty())
+ continue;
+
+ auto firstScheduleDeadline = mbox.second->GetFirstScheduleDeadline();
+ if (!nextScheduleDeadline || firstScheduleDeadline < *nextScheduleDeadline) {
+ nextScheduleMboxes.clear();
+ nextScheduleMboxes.emplace_back(mbox.second);
+ nextScheduleDeadline = firstScheduleDeadline;
+ } else if (firstScheduleDeadline == *nextScheduleDeadline) {
+ nextScheduleMboxes.emplace_back(mbox.second);
+ }
+ }
+
+ for (const auto& nextScheduleMbox : nextScheduleMboxes) {
+ TEventsList selectedEvents;
+ TScheduledEventsList capturedScheduledEvents;
+ nextScheduleMbox->CaptureScheduled(capturedScheduledEvents);
+ ScheduledEventsSelectorFunc(*this, capturedScheduledEvents, selectedEvents);
+ nextScheduleMbox->PushScheduled(capturedScheduledEvents);
+ for (auto& event : selectedEvents) {
+ if (verbose && (BlockedOutput.find(event->Sender) == BlockedOutput.end())) {
+ Cerr << "Selected scheduled event at " << TInstant::MicroSeconds(CurrentTimestamp) << ", ";
+ PrintEvent(event, this);
+ }
+
+ nextScheduleMbox->Send(event);
+ isEmpty = false;
+ }
+ }
+
+ if (!isEmpty) {
+ if (verbose) {
+ Cerr << "Process selected events at " << TInstant::MicroSeconds(CurrentTimestamp) << "\n";
+ }
+
+ deadline = dispatchTime + DispatchTimeout;
+ continue;
+ }
+
+ if (nearestMailboxDeadline.Defined()) {
+ if (verbose) {
+ Cerr << "Forward time to " << *nearestMailboxDeadline.Get() << "\n";
+ }
+
+ UpdateCurrentTime(*nearestMailboxDeadline.Get());
+ continue;
+ }
+ }
+
+ TDuration waitDelay = TDuration::MilliSeconds(10);
+ dispatchTime += waitDelay;
+ MailboxesHasEvents.WaitT(Mutex, waitDelay);
+ }
+ return false;
+ }
+
+ void TTestActorRuntimeBase::HandleNonEmptyMailboxesForEachContext(TEventMailboxId mboxId) {
+ TDispatchContext* context = CurrentDispatchContext;
+ while (context) {
+ const auto& nonEmptyMailboxes = context->Options->NonEmptyMailboxes;
+ if (Find(nonEmptyMailboxes.begin(), nonEmptyMailboxes.end(), mboxId) != nonEmptyMailboxes.end()) {
+ context->FoundNonEmptyMailboxes.insert(mboxId);
+ }
+
+ context = context->PrevContext;
+ }
+ }
+
+ void TTestActorRuntimeBase::UpdateFinalEventsStatsForEachContext(IEventHandle& ev) {
+ TDispatchContext* context = CurrentDispatchContext;
+ while (context) {
+ for (const auto& finalEvent : context->Options->FinalEvents) {
+ if (finalEvent.EventCheck(ev)) {
+ auto& freq = context->FinalEventFrequency[&finalEvent];
+ if (++freq >= finalEvent.RequiredCount) {
+ context->FinalEventFound = true;
+ }
+ }
+ }
+
+ context = context->PrevContext;
+ }
+ }
+
+ void TTestActorRuntimeBase::Send(IEventHandle* ev, ui32 senderNodeIndex, bool viaActorSystem) {
+ TGuard<TMutex> guard(Mutex);
+ Y_VERIFY(senderNodeIndex < NodeCount, "senderNodeIndex# %" PRIu32 " < NodeCount# %" PRIu32,
+ senderNodeIndex, NodeCount);
+ SendInternal(ev, senderNodeIndex, viaActorSystem);
+ }
+
+ void TTestActorRuntimeBase::Schedule(IEventHandle* ev, const TDuration& duration, ui32 nodeIndex) {
+ TGuard<TMutex> guard(Mutex);
+ Y_VERIFY(nodeIndex < NodeCount);
+ ui32 nodeId = FirstNodeId + nodeIndex;
+ ui32 mailboxHint = ev->GetRecipientRewrite().Hint();
+ TInstant deadline = TInstant::MicroSeconds(CurrentTimestamp) + duration;
+ GetMailbox(nodeId, mailboxHint).Schedule(TScheduledEventQueueItem(deadline, ev, nullptr));
+ if (VERBOSE)
+ Cerr << "Event was added to scheduled queue\n";
+ }
+
+ void TTestActorRuntimeBase::ClearCounters() {
+ TGuard<TMutex> guard(Mutex);
+ EvCounters.clear();
+ }
+
+ ui64 TTestActorRuntimeBase::GetCounter(ui32 evType) const {
+ TGuard<TMutex> guard(Mutex);
+ auto it = EvCounters.find(evType);
+ if (it == EvCounters.end())
+ return 0;
+
+ return it->second;
+ }
+
+ TActorId TTestActorRuntimeBase::GetLocalServiceId(const TActorId& serviceId, ui32 nodeIndex) {
+ TGuard<TMutex> guard(Mutex);
+ Y_VERIFY(nodeIndex < NodeCount);
+ TNodeDataBase* node = Nodes[FirstNodeId + nodeIndex].Get();
+ return node->ActorSystem->LookupLocalService(serviceId);
+ }
+
+ void TTestActorRuntimeBase::WaitForEdgeEvents(TEventFilter filter, const TSet<TActorId>& edgeFilter, TDuration simTimeout) {
+ TGuard<TMutex> guard(Mutex);
+ ui32 dispatchCount = 0;
+ if (!edgeFilter.empty()) {
+ for (auto edgeActor : edgeFilter) {
+ Y_VERIFY(EdgeActors.contains(edgeActor), "%s is not an edge actor", ToString(edgeActor).data());
+ }
+ }
+ const TSet<TActorId>& edgeActors = edgeFilter.empty() ? EdgeActors : edgeFilter;
+ TInstant deadline = TInstant::MicroSeconds(CurrentTimestamp) + simTimeout;
+ for (;;) {
+ for (auto edgeActor : edgeActors) {
+ TEventsList events;
+ auto& mbox = GetMailbox(edgeActor.NodeId(), edgeActor.Hint());
+ bool foundEvent = false;
+ mbox.Capture(events);
+ for (auto& ev : events) {
+ if (filter(*this, ev)) {
+ foundEvent = true;
+ break;
+ }
+ }
+
+ mbox.PushFront(events);
+ if (foundEvent)
+ return;
+ }
+
+ ++dispatchCount;
+ {
+ if (!DispatchEventsInternal(TDispatchOptions(), deadline)) {
+ return; // Timed out; event was not found
+ }
+ }
+
+ Y_VERIFY(dispatchCount < 1000, "Hard limit to prevent endless loop");
+ }
+ }
+
+ TActorId TTestActorRuntimeBase::GetInterconnectProxy(ui32 nodeIndexFrom, ui32 nodeIndexTo) {
+ TGuard<TMutex> guard(Mutex);
+ Y_VERIFY(nodeIndexFrom < NodeCount);
+ Y_VERIFY(nodeIndexTo < NodeCount);
+ Y_VERIFY(nodeIndexFrom != nodeIndexTo);
+ TNodeDataBase* node = Nodes[FirstNodeId + nodeIndexFrom].Get();
+ return node->ActorSystem->InterconnectProxy(FirstNodeId + nodeIndexTo);
+ }
+
+ void TTestActorRuntimeBase::BlockOutputForActor(const TActorId& actorId) {
+ TGuard<TMutex> guard(Mutex);
+ BlockedOutput.insert(actorId);
+ }
+
+ void TTestActorRuntimeBase::SetDispatcherRandomSeed(TInstant time, ui64 iteration) {
+ ui64 days = (time.Hours() / 24);
+ DispatcherRandomSeed = (days << 32) ^ iteration;
+ DispatcherRandomProvider = CreateDeterministicRandomProvider(DispatcherRandomSeed);
+ }
+
+ IActor* TTestActorRuntimeBase::FindActor(const TActorId& actorId, ui32 nodeIndex) const {
+ TGuard<TMutex> guard(Mutex);
+ if (nodeIndex == Max<ui32>()) {
+ Y_VERIFY(actorId.NodeId());
+ nodeIndex = actorId.NodeId() - FirstNodeId;
+ }
+
+ Y_VERIFY(nodeIndex < NodeCount);
+ auto nodeIt = Nodes.find(FirstNodeId + nodeIndex);
+ Y_VERIFY(nodeIt != Nodes.end());
+ TNodeDataBase* node = nodeIt->second.Get();
+ return FindActor(actorId, node);
+ }
+
+ void TTestActorRuntimeBase::EnableScheduleForActor(const TActorId& actorId, bool allow) {
+ TGuard<TMutex> guard(Mutex);
+ if (allow) {
+ if (VERBOSE) {
+ Cerr << "Actor " << actorId << " added to schedule whitelist";
+ }
+ ScheduleWhiteList.insert(actorId);
+ } else {
+ if (VERBOSE) {
+ Cerr << "Actor " << actorId << " removed from schedule whitelist";
+ }
+ ScheduleWhiteList.erase(actorId);
+ }
+ }
+
+ bool TTestActorRuntimeBase::IsScheduleForActorEnabled(const TActorId& actorId) const {
+ TGuard<TMutex> guard(Mutex);
+ return ScheduleWhiteList.find(actorId) != ScheduleWhiteList.end();
+ }
+
+ TIntrusivePtr<NMonitoring::TDynamicCounters> TTestActorRuntimeBase::GetDynamicCounters(ui32 nodeIndex) {
+ TGuard<TMutex> guard(Mutex);
+ Y_VERIFY(nodeIndex < NodeCount);
+ ui32 nodeId = FirstNodeId + nodeIndex;
+ TNodeDataBase* node = Nodes[nodeId].Get();
+ return node->DynamicCounters;
+ }
+
+ void TTestActorRuntimeBase::SetupMonitoring() {
+ NeedMonitoring = true;
+ }
+
+ void TTestActorRuntimeBase::SendInternal(IEventHandle* ev, ui32 nodeIndex, bool viaActorSystem) {
+ Y_VERIFY(nodeIndex < NodeCount);
+ ui32 nodeId = FirstNodeId + nodeIndex;
+ TNodeDataBase* node = Nodes[nodeId].Get();
+ ui32 targetNode = ev->GetRecipientRewrite().NodeId();
+ ui32 targetNodeIndex;
+ if (targetNode == 0) {
+ targetNodeIndex = nodeIndex;
+ } else {
+ targetNodeIndex = targetNode - FirstNodeId;
+ Y_VERIFY(targetNodeIndex < NodeCount);
+ }
+
+ if (viaActorSystem || UseRealThreads || ev->GetRecipientRewrite().IsService() || (targetNodeIndex != nodeIndex)) {
+ node->ActorSystem->Send(ev);
+ return;
+ }
+
+ Y_VERIFY(!ev->GetRecipientRewrite().IsService() && (targetNodeIndex == nodeIndex));
+ TAutoPtr<IEventHandle> evHolder(ev);
+
+ if (!AllowSendFrom(node, evHolder)) {
+ return;
+ }
+
+ ui32 mailboxHint = ev->GetRecipientRewrite().Hint();
+ TEventMailBox& mbox = GetMailbox(nodeId, mailboxHint);
+ if (!mbox.IsActive(TInstant::MicroSeconds(CurrentTimestamp))) {
+ mbox.PushFront(evHolder);
+ return;
+ }
+
+ ui64 recipientLocalId = ev->GetRecipientRewrite().LocalId();
+ if ((BlockedOutput.find(ev->Sender) == BlockedOutput.end()) && VERBOSE) {
+ Cerr << "Send event, ";
+ PrintEvent(evHolder, this);
+ }
+
+ EvCounters[ev->GetTypeRewrite()]++;
+
+ TMailboxHeader* mailbox = node->MailboxTable->Get(mailboxHint);
+ IActor* recipientActor = mailbox->FindActor(recipientLocalId);
+ if (recipientActor) {
+ // Save actorId by value in order to prevent ctx from being invalidated during another Send call.
+ TActorId actorId = ev->GetRecipientRewrite();
+ node->ActorToActorId[recipientActor] = ev->GetRecipientRewrite();
+ TActorContext ctx(*mailbox, *node->ExecutorThread, GetCycleCountFast(), actorId);
+ TActivationContext *prevTlsActivationContext = TlsActivationContext;
+ TlsActivationContext = &ctx;
+ CurrentRecipient = actorId;
+ {
+ TInverseGuard<TMutex> inverseGuard(Mutex);
+#ifdef USE_ACTOR_CALLSTACK
+ TCallstack::GetTlsCallstack() = ev->Callstack;
+ TCallstack::GetTlsCallstack().SetLinesToSkip();
+#endif
+ recipientActor->Receive(evHolder, ctx);
+ node->ExecutorThread->DropUnregistered();
+ }
+ CurrentRecipient = TActorId();
+ TlsActivationContext = prevTlsActivationContext;
+ } else {
+ if (VERBOSE) {
+ Cerr << "Failed to find actor with local id: " << recipientLocalId << "\n";
+ }
+
+ auto forwardedEv = ev->ForwardOnNondelivery(TEvents::TEvUndelivered::ReasonActorUnknown);
+ if (!!forwardedEv) {
+ node->ActorSystem->Send(forwardedEv);
+ }
+ }
+ }
+
+ IActor* TTestActorRuntimeBase::FindActor(const TActorId& actorId, TNodeDataBase* node) const {
+ ui32 mailboxHint = actorId.Hint();
+ ui64 localId = actorId.LocalId();
+ TMailboxHeader* mailbox = node->MailboxTable->Get(mailboxHint);
+ IActor* actor = mailbox->FindActor(localId);
+ return actor;
+ }
+
+ THolder<TActorSystemSetup> TTestActorRuntimeBase::MakeActorSystemSetup(ui32 nodeIndex, TNodeDataBase* node) {
+ THolder<TActorSystemSetup> setup(new TActorSystemSetup);
+ setup->NodeId = FirstNodeId + nodeIndex;
+
+ if (UseRealThreads) {
+ setup->ExecutorsCount = 5;
+ setup->Executors.Reset(new TAutoPtr<IExecutorPool>[5]);
+ setup->Executors[0].Reset(new TBasicExecutorPool(0, 2, 20));
+ setup->Executors[1].Reset(new TBasicExecutorPool(1, 2, 20));
+ setup->Executors[2].Reset(new TIOExecutorPool(2, 1));
+ setup->Executors[3].Reset(new TBasicExecutorPool(3, 2, 20));
+ setup->Executors[4].Reset(new TBasicExecutorPool(4, 1, 20));
+ setup->Scheduler.Reset(new TBasicSchedulerThread(TSchedulerConfig(512, 100)));
+ } else {
+ setup->ExecutorsCount = 1;
+ setup->Scheduler.Reset(new TSchedulerThreadStub(this, node));
+ setup->Executors.Reset(new TAutoPtr<IExecutorPool>[1]);
+ setup->Executors[0].Reset(new TExecutorPoolStub(this, nodeIndex, node, 0));
+ }
+
+ InitActorSystemSetup(*setup);
+
+ return setup;
+ }
+
+ THolder<TActorSystem> TTestActorRuntimeBase::MakeActorSystem(ui32 nodeIndex, TNodeDataBase* node) {
+ auto setup = MakeActorSystemSetup(nodeIndex, node);
+
+ node->ExecutorPools.resize(setup->ExecutorsCount);
+ for (ui32 i = 0; i < setup->ExecutorsCount; ++i) {
+ node->ExecutorPools[i] = setup->Executors[i].Get();
+ }
+
+ const auto& interconnectCounters = GetCountersForComponent(node->DynamicCounters, "interconnect");
+
+ setup->LocalServices = node->LocalServices;
+ setup->Interconnect.ProxyActors.resize(FirstNodeId + NodeCount);
+ const TActorId nameserviceId = GetNameserviceActorId();
+
+ TIntrusivePtr<TInterconnectProxyCommon> common;
+ common.Reset(new TInterconnectProxyCommon);
+ common->NameserviceId = nameserviceId;
+ common->MonCounters = interconnectCounters;
+ common->TechnicalSelfHostName = "::1";
+
+ if (!UseRealThreads) {
+ common->Settings.DeadPeer = TDuration::Max();
+ common->Settings.CloseOnIdle = TDuration::Max();
+ common->Settings.PingPeriod = TDuration::Max();
+ common->Settings.ForceConfirmPeriod = TDuration::Max();
+ common->Settings.Handshake = TDuration::Max();
+ }
+
+ common->ClusterUUID = ClusterUUID;
+ common->AcceptUUID = {ClusterUUID};
+
+ for (ui32 proxyNodeIndex = 0; proxyNodeIndex < NodeCount; ++proxyNodeIndex) {
+ if (proxyNodeIndex == nodeIndex)
+ continue;
+
+ const ui32 peerNodeId = FirstNodeId + proxyNodeIndex;
+
+ IActor *proxyActor = UseRealInterconnect
+ ? new TInterconnectProxyTCP(peerNodeId, common)
+ : InterconnectMock.CreateProxyMock(setup->NodeId, peerNodeId, common);
+
+ setup->Interconnect.ProxyActors[peerNodeId] = {proxyActor, TMailboxType::ReadAsFilled, InterconnectPoolId()};
+ }
+
+ setup->Interconnect.ProxyWrapperFactory = CreateProxyWrapperFactory(common, InterconnectPoolId(), &InterconnectMock);
+
+ if (UseRealInterconnect) {
+ setup->LocalServices.emplace_back(MakePollerActorId(), NActors::TActorSetupCmd(CreatePollerActor(),
+ NActors::TMailboxType::Simple, InterconnectPoolId()));
+ }
+
+ if (!SingleSysEnv) { // Single system env should do this self
+ TAutoPtr<TLogBackend> logBackend = LogBackend ? LogBackend : NActors::CreateStderrBackend();
+ NActors::TLoggerActor *loggerActor = new NActors::TLoggerActor(node->LogSettings,
+ logBackend, GetCountersForComponent(node->DynamicCounters, "utils"));
+ NActors::TActorSetupCmd loggerActorCmd(loggerActor, NActors::TMailboxType::Simple, node->GetLoggerPoolId());
+ std::pair<NActors::TActorId, NActors::TActorSetupCmd> loggerActorPair(node->LogSettings->LoggerActorId, loggerActorCmd);
+ setup->LocalServices.push_back(loggerActorPair);
+ }
+
+ return THolder<TActorSystem>(new TActorSystem(setup, node->GetAppData(), node->LogSettings));
+ }
+
+ TActorSystem* TTestActorRuntimeBase::SingleSys() const {
+ Y_VERIFY(Nodes.size() == 1, "Works only for single system env");
+
+ return Nodes.begin()->second->ActorSystem.Get();
+ }
+
+ TActorSystem* TTestActorRuntimeBase::GetAnyNodeActorSystem() {
+ for (auto& x : Nodes) {
+ return x.second->ActorSystem.Get();
+ }
+ Y_FAIL("Don't use this method.");
+ }
+
+ TActorSystem* TTestActorRuntimeBase::GetActorSystem(ui32 nodeId) {
+ auto it = Nodes.find(GetNodeId(nodeId));
+ Y_VERIFY(it != Nodes.end());
+ return it->second->ActorSystem.Get();
+ }
+
+
+ TEventMailBox& TTestActorRuntimeBase::GetMailbox(ui32 nodeId, ui32 hint) {
+ TGuard<TMutex> guard(Mutex);
+ auto mboxId = TEventMailboxId(nodeId, hint);
+ auto it = Mailboxes.find(mboxId);
+ if (it == Mailboxes.end()) {
+ it = Mailboxes.insert(std::make_pair(mboxId, new TEventMailBox())).first;
+ }
+
+ return *it->second;
+ }
+
+ void TTestActorRuntimeBase::ClearMailbox(ui32 nodeId, ui32 hint) {
+ TGuard<TMutex> guard(Mutex);
+ auto mboxId = TEventMailboxId(nodeId, hint);
+ Mailboxes.erase(mboxId);
+ }
+
+ TString TTestActorRuntimeBase::GetActorName(const TActorId& actorId) const {
+ auto it = ActorNames.find(actorId);
+ if (it != ActorNames.end())
+ return it->second;
+ return actorId.ToString();
+ }
+
+ struct TStrandingActorDecoratorContext : public TThrRefBase {
+ TStrandingActorDecoratorContext()
+ : Queue(new TQueueType)
+ {
+ }
+
+ typedef TOneOneQueueInplace<IEventHandle*, 32> TQueueType;
+ TAutoPtr<TQueueType, TQueueType::TPtrCleanDestructor> Queue;
+ };
+
+ class TStrandingActorDecorator : public TActorBootstrapped<TStrandingActorDecorator> {
+ public:
+ class TReplyActor : public TActor<TReplyActor> {
+ public:
+ static constexpr EActivityType ActorActivityType() {
+ return TEST_ACTOR_RUNTIME;
+ }
+
+ TReplyActor(TStrandingActorDecorator* owner)
+ : TActor(&TReplyActor::StateFunc)
+ , Owner(owner)
+ {
+ }
+
+ STFUNC(StateFunc);
+
+ private:
+ TStrandingActorDecorator* const Owner;
+ };
+
+ static constexpr EActivityType ActorActivityType() {
+ return TEST_ACTOR_RUNTIME;
+ }
+
+ TStrandingActorDecorator(const TActorId& delegatee, bool isSync, const TVector<TActorId>& additionalActors,
+ TSimpleSharedPtr<TStrandingActorDecoratorContext> context, TTestActorRuntimeBase* runtime,
+ TReplyCheckerCreator createReplyChecker)
+ : Delegatee(delegatee)
+ , IsSync(isSync)
+ , AdditionalActors(additionalActors)
+ , Context(context)
+ , HasReply(false)
+ , Runtime(runtime)
+ , ReplyChecker(createReplyChecker())
+ {
+ if (IsSync) {
+ Y_VERIFY(!runtime->IsRealThreads());
+ }
+ }
+
+ void Bootstrap(const TActorContext& ctx) {
+ Become(&TStrandingActorDecorator::StateFunc);
+ ReplyId = ctx.RegisterWithSameMailbox(new TReplyActor(this));
+ DelegateeOptions.OnlyMailboxes.push_back(TEventMailboxId(Delegatee.NodeId(), Delegatee.Hint()));
+ for (const auto& actor : AdditionalActors) {
+ DelegateeOptions.OnlyMailboxes.push_back(TEventMailboxId(actor.NodeId(), actor.Hint()));
+ }
+
+ DelegateeOptions.OnlyMailboxes.push_back(TEventMailboxId(ReplyId.NodeId(), ReplyId.Hint()));
+ DelegateeOptions.NonEmptyMailboxes.push_back(TEventMailboxId(ReplyId.NodeId(), ReplyId.Hint()));
+ DelegateeOptions.Quiet = true;
+ }
+
+ STFUNC(StateFunc) {
+ bool wasEmpty = !Context->Queue->Head();
+ Context->Queue->Push(ev.Release());
+ if (wasEmpty) {
+ SendHead(ctx);
+ }
+ }
+
+ STFUNC(Reply) {
+ Y_VERIFY(!HasReply);
+ IEventHandle *requestEv = Context->Queue->Head();
+ TActorId originalSender = requestEv->Sender;
+ HasReply = !ReplyChecker->IsWaitingForMoreResponses(ev.Get());
+ if (HasReply) {
+ delete Context->Queue->Pop();
+ }
+ ctx.ExecutorThread.Send(ev->Forward(originalSender));
+ if (!IsSync && Context->Queue->Head()) {
+ SendHead(ctx);
+ }
+ }
+
+ private:
+ void SendHead(const TActorContext& ctx) {
+ if (!IsSync) {
+ ctx.ExecutorThread.Send(GetForwardedEvent().Release());
+ } else {
+ while (Context->Queue->Head()) {
+ HasReply = false;
+ ctx.ExecutorThread.Send(GetForwardedEvent().Release());
+ int count = 100;
+ while (!HasReply && count > 0) {
+ try {
+ Runtime->DispatchEvents(DelegateeOptions);
+ } catch (TEmptyEventQueueException&) {
+ count--;
+ Cerr << "No reply" << Endl;
+ }
+ }
+
+ Runtime->UpdateCurrentTime(Runtime->GetCurrentTime() + TDuration::MicroSeconds(1000));
+ }
+ }
+ }
+
+ TAutoPtr<IEventHandle> GetForwardedEvent() {
+ IEventHandle* ev = Context->Queue->Head();
+ ReplyChecker->OnRequest(ev);
+ TAutoPtr<IEventHandle> forwardedEv = ev->HasEvent()
+ ? new IEventHandle(Delegatee, ReplyId, ev->ReleaseBase().Release(), ev->Flags, ev->Cookie)
+ : new IEventHandle(ev->GetTypeRewrite(), ev->Flags, Delegatee, ReplyId, ev->ReleaseChainBuffer(), ev->Cookie);
+
+ return forwardedEv;
+ }
+ private:
+ const TActorId Delegatee;
+ const bool IsSync;
+ const TVector<TActorId> AdditionalActors;
+ TSimpleSharedPtr<TStrandingActorDecoratorContext> Context;
+ TActorId ReplyId;
+ bool HasReply;
+ TDispatchOptions DelegateeOptions;
+ TTestActorRuntimeBase* Runtime;
+ THolder<IReplyChecker> ReplyChecker;
+ };
+
+ void TStrandingActorDecorator::TReplyActor::StateFunc(STFUNC_SIG) {
+ Owner->Reply(ev, ctx);
+ }
+
+ class TStrandingDecoratorFactory : public IStrandingDecoratorFactory {
+ public:
+ TStrandingDecoratorFactory(TTestActorRuntimeBase* runtime,
+ TReplyCheckerCreator createReplyChecker)
+ : Context(new TStrandingActorDecoratorContext())
+ , Runtime(runtime)
+ , CreateReplyChecker(createReplyChecker)
+ {
+ }
+
+ IActor* Wrap(const TActorId& delegatee, bool isSync, const TVector<TActorId>& additionalActors) override {
+ return new TStrandingActorDecorator(delegatee, isSync, additionalActors, Context, Runtime,
+ CreateReplyChecker);
+ }
+
+ private:
+ TSimpleSharedPtr<TStrandingActorDecoratorContext> Context;
+ TTestActorRuntimeBase* Runtime;
+ TReplyCheckerCreator CreateReplyChecker;
+ };
+
+ TAutoPtr<IStrandingDecoratorFactory> CreateStrandingDecoratorFactory(TTestActorRuntimeBase* runtime,
+ TReplyCheckerCreator createReplyChecker) {
+ return TAutoPtr<IStrandingDecoratorFactory>(new TStrandingDecoratorFactory(runtime, createReplyChecker));
+ }
+
+ ui64 DefaultRandomSeed = 9999;
+}
diff --git a/library/cpp/actors/testlib/test_runtime.h b/library/cpp/actors/testlib/test_runtime.h
new file mode 100644
index 0000000000..26e3b45c98
--- /dev/null
+++ b/library/cpp/actors/testlib/test_runtime.h
@@ -0,0 +1,716 @@
+#pragma once
+
+#include <library/cpp/actors/core/actor.h>
+#include <library/cpp/actors/core/actorsystem.h>
+#include <library/cpp/actors/core/log.h>
+#include <library/cpp/actors/core/events.h>
+#include <library/cpp/actors/core/executor_thread.h>
+#include <library/cpp/actors/core/mailbox.h>
+#include <library/cpp/actors/util/should_continue.h>
+#include <library/cpp/actors/interconnect/poller_tcp.h>
+#include <library/cpp/actors/interconnect/mock/ic_mock.h>
+#include <library/cpp/random_provider/random_provider.h>
+#include <library/cpp/time_provider/time_provider.h>
+#include <library/cpp/testing/unittest/tests_data.h>
+
+#include <util/datetime/base.h>
+#include <util/folder/tempdir.h>
+#include <util/generic/deque.h>
+#include <util/generic/hash.h>
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/generic/queue.h>
+#include <util/generic/set.h>
+#include <util/generic/vector.h>
+#include <util/system/defaults.h>
+#include <util/system/mutex.h>
+#include <util/system/condvar.h>
+#include <util/system/thread.h>
+#include <util/system/sanitizers.h>
+#include <util/system/valgrind.h>
+#include <utility>
+
+#include <functional>
+
+const TDuration DEFAULT_DISPATCH_TIMEOUT = NSan::PlainOrUnderSanitizer(
+ NValgrind::PlainOrUnderValgrind(TDuration::Seconds(60), TDuration::Seconds(120)),
+ TDuration::Seconds(120)
+);
+
+
+namespace NActors {
+ struct THeSingleSystemEnv { };
+
+ struct TEventMailboxId {
+ TEventMailboxId()
+ : NodeId(0)
+ , Hint(0)
+ {
+ }
+
+ TEventMailboxId(ui32 nodeId, ui32 hint)
+ : NodeId(nodeId)
+ , Hint(hint)
+ {
+ }
+
+ bool operator<(const TEventMailboxId& other) const {
+ return (NodeId < other.NodeId) || (NodeId == other.NodeId) && (Hint < other.Hint);
+ }
+
+ bool operator==(const TEventMailboxId& other) const {
+ return (NodeId == other.NodeId) && (Hint == other.Hint);
+ }
+
+ struct THash {
+ ui64 operator()(const TEventMailboxId& mboxId) const noexcept {
+ return mboxId.NodeId * 31ULL + mboxId.Hint;
+ }
+ };
+
+ ui32 NodeId;
+ ui32 Hint;
+ };
+
+ struct TDispatchOptions {
+ struct TFinalEventCondition {
+ std::function<bool(IEventHandle& ev)> EventCheck;
+ ui32 RequiredCount;
+
+ TFinalEventCondition(ui32 eventType, ui32 requiredCount = 1)
+ : EventCheck([eventType](IEventHandle& ev) -> bool { return ev.GetTypeRewrite() == eventType; })
+ , RequiredCount(requiredCount)
+ {
+ }
+
+ TFinalEventCondition(std::function<bool(IEventHandle& ev)> eventCheck, ui32 requiredCount = 1)
+ : EventCheck(eventCheck)
+ , RequiredCount(requiredCount)
+ {
+ }
+ };
+
+ TVector<TFinalEventCondition> FinalEvents;
+ TVector<TEventMailboxId> NonEmptyMailboxes;
+ TVector<TEventMailboxId> OnlyMailboxes;
+ std::function<bool()> CustomFinalCondition;
+ bool Quiet = false;
+ };
+
+ struct TScheduledEventQueueItem {
+ TInstant Deadline;
+ TAutoPtr<IEventHandle> Event;
+ TAutoPtr<TSchedulerCookieHolder> Cookie;
+ ui64 UniqueId;
+
+ TScheduledEventQueueItem(TInstant deadline, TAutoPtr<IEventHandle> event, ISchedulerCookie* cookie)
+ : Deadline(deadline)
+ , Event(event)
+ , Cookie(new TSchedulerCookieHolder(cookie))
+ , UniqueId(++NextUniqueId)
+ {}
+
+ bool operator<(const TScheduledEventQueueItem& other) const {
+ if (Deadline < other.Deadline)
+ return true;
+
+ if (Deadline > other.Deadline)
+ return false;
+
+ return UniqueId < other.UniqueId;
+ }
+
+ static ui64 NextUniqueId;
+ };
+
+ typedef TDeque<TAutoPtr<IEventHandle>> TEventsList;
+ typedef TSet<TScheduledEventQueueItem> TScheduledEventsList;
+
+ class TEventMailBox : public TThrRefBase {
+ public:
+ TEventMailBox()
+ : InactiveUntil(TInstant::MicroSeconds(0))
+#ifdef DEBUG_ORDER_EVENTS
+ , ExpectedReceive(0)
+ , NextToSend(0)
+#endif
+ {
+ }
+
+ void Send(TAutoPtr<IEventHandle> ev);
+ bool IsEmpty() const;
+ TAutoPtr<IEventHandle> Pop();
+ void Capture(TEventsList& evList);
+ void PushFront(TAutoPtr<IEventHandle>& ev);
+ void PushFront(TEventsList& evList);
+ void CaptureScheduled(TScheduledEventsList& evList);
+ void PushScheduled(TScheduledEventsList& evList);
+ bool IsActive(const TInstant& currentTime) const;
+ void Freeze(const TInstant& deadline);
+ TInstant GetInactiveUntil() const;
+ void Schedule(const TScheduledEventQueueItem& item);
+ bool IsScheduledEmpty() const;
+ TInstant GetFirstScheduleDeadline() const;
+ ui64 GetSentEventCount() const;
+
+ private:
+ TScheduledEventsList Scheduled;
+ TInstant InactiveUntil;
+ TEventsList Sent;
+#ifdef DEBUG_ORDER_EVENTS
+ TMap<IEventHandle*, ui64> TrackSent;
+ ui64 ExpectedReceive;
+ ui64 NextToSend;
+#endif
+ };
+
+ typedef THashMap<TEventMailboxId, TIntrusivePtr<TEventMailBox>, TEventMailboxId::THash> TEventMailBoxList;
+
+ class TEmptyEventQueueException : public yexception {
+ public:
+ TEmptyEventQueueException() {
+ Append("Event queue is still empty.");
+ }
+ };
+
+ class TSchedulingLimitReachedException : public yexception {
+ public:
+ TSchedulingLimitReachedException(ui64 limit) {
+ TStringStream str;
+ str << "TestActorRuntime Processed over " << limit << " events.";
+ Append(str.Str());
+ }
+ };
+
+ class TTestActorRuntimeBase: public TNonCopyable {
+ public:
+ class TEdgeActor;
+ class TSchedulerThreadStub;
+ class TExecutorPoolStub;
+ class TTimeProvider;
+
+ enum class EEventAction {
+ PROCESS,
+ DROP,
+ RESCHEDULE
+ };
+
+ typedef std::function<EEventAction(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event)> TEventObserver;
+ typedef std::function<void(TTestActorRuntimeBase& runtime, TScheduledEventsList& scheduledEvents, TEventsList& queue)> TScheduledEventsSelector;
+ typedef std::function<bool(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event)> TEventFilter;
+ typedef std::function<bool(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event, TDuration delay, TInstant& deadline)> TScheduledEventFilter;
+ typedef std::function<void(TTestActorRuntimeBase& runtime, const TActorId& parentId, const TActorId& actorId)> TRegistrationObserver;
+
+
+ TTestActorRuntimeBase(THeSingleSystemEnv);
+ TTestActorRuntimeBase(ui32 nodeCount, ui32 dataCenterCount, bool UseRealThreads);
+ TTestActorRuntimeBase(ui32 nodeCount, ui32 dataCenterCount);
+ TTestActorRuntimeBase(ui32 nodeCount = 1, bool useRealThreads = false);
+ virtual ~TTestActorRuntimeBase();
+ bool IsRealThreads() const;
+ static EEventAction DefaultObserverFunc(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event);
+ static void DroppingScheduledEventsSelector(TTestActorRuntimeBase& runtime, TScheduledEventsList& scheduledEvents, TEventsList& queue);
+ static void CollapsedTimeScheduledEventsSelector(TTestActorRuntimeBase& runtime, TScheduledEventsList& scheduledEvents, TEventsList& queue);
+ static bool DefaultFilterFunc(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event);
+ static bool NopFilterFunc(TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event, TDuration delay, TInstant& deadline);
+ static void DefaultRegistrationObserver(TTestActorRuntimeBase& runtime, const TActorId& parentId, const TActorId& actorId);
+ TEventObserver SetObserverFunc(TEventObserver observerFunc);
+ TScheduledEventsSelector SetScheduledEventsSelectorFunc(TScheduledEventsSelector scheduledEventsSelectorFunc);
+ TEventFilter SetEventFilter(TEventFilter filterFunc);
+ TScheduledEventFilter SetScheduledEventFilter(TScheduledEventFilter filterFunc);
+ TRegistrationObserver SetRegistrationObserverFunc(TRegistrationObserver observerFunc);
+ static bool IsVerbose();
+ static void SetVerbose(bool verbose);
+ TDuration SetDispatchTimeout(TDuration timeout);
+ void SetDispatchedEventsLimit(ui64 limit) {
+ DispatchedEventsLimit = limit;
+ }
+ TDuration SetReschedulingDelay(TDuration delay);
+ void SetLogBackend(const TAutoPtr<TLogBackend> logBackend);
+ void SetLogPriority(NActors::NLog::EComponent component, NActors::NLog::EPriority priority);
+ TIntrusivePtr<ITimeProvider> GetTimeProvider();
+ TInstant GetCurrentTime() const;
+ void UpdateCurrentTime(TInstant newTime);
+ void AdvanceCurrentTime(TDuration duration);
+ void AddLocalService(const TActorId& actorId, const TActorSetupCmd& cmd, ui32 nodeIndex = 0);
+ virtual void Initialize();
+ ui32 GetNodeId(ui32 index = 0) const;
+ ui32 GetNodeCount() const;
+ ui64 AllocateLocalId();
+ ui32 InterconnectPoolId() const;
+ TString GetTempDir();
+ TActorId Register(IActor* actor, ui32 nodeIndex = 0, ui32 poolId = 0,
+ TMailboxType::EType mailboxType = TMailboxType::Simple, ui64 revolvingCounter = 0,
+ const TActorId& parentid = TActorId());
+ TActorId Register(IActor *actor, ui32 nodeIndex, ui32 poolId, TMailboxHeader *mailbox, ui32 hint,
+ const TActorId& parentid = TActorId());
+ TActorId RegisterService(const TActorId& serviceId, const TActorId& actorId, ui32 nodeIndex = 0);
+ TActorId AllocateEdgeActor(ui32 nodeIndex = 0);
+ TEventsList CaptureEvents();
+ TEventsList CaptureMailboxEvents(ui32 hint, ui32 nodeId);
+ TScheduledEventsList CaptureScheduledEvents();
+ void PushFront(TAutoPtr<IEventHandle>& ev);
+ void PushEventsFront(TEventsList& events);
+ void PushMailboxEventsFront(ui32 hint, ui32 nodeId, TEventsList& events);
+ // doesn't dispatch events for edge actors
+ bool DispatchEvents(const TDispatchOptions& options = TDispatchOptions());
+ bool DispatchEvents(const TDispatchOptions& options, TDuration simTimeout);
+ bool DispatchEvents(const TDispatchOptions& options, TInstant simDeadline);
+ void Send(IEventHandle* ev, ui32 senderNodeIndex = 0, bool viaActorSystem = false);
+ void Schedule(IEventHandle* ev, const TDuration& duration, ui32 nodeIndex = 0);
+ void ClearCounters();
+ ui64 GetCounter(ui32 evType) const;
+ TActorId GetLocalServiceId(const TActorId& serviceId, ui32 nodeIndex = 0);
+ void WaitForEdgeEvents(TEventFilter filter, const TSet<TActorId>& edgeFilter = {}, TDuration simTimeout = TDuration::Max());
+ TActorId GetInterconnectProxy(ui32 nodeIndexFrom, ui32 nodeIndexTo);
+ void BlockOutputForActor(const TActorId& actorId);
+ IActor* FindActor(const TActorId& actorId, ui32 nodeIndex = Max<ui32>()) const;
+ void EnableScheduleForActor(const TActorId& actorId, bool allow = true);
+ bool IsScheduleForActorEnabled(const TActorId& actorId) const;
+ TIntrusivePtr<NMonitoring::TDynamicCounters> GetDynamicCounters(ui32 nodeIndex = 0);
+ void SetupMonitoring();
+
+ template<typename T>
+ void AppendToLogSettings(NLog::EComponent minVal, NLog::EComponent maxVal, T func) {
+ Y_VERIFY(!IsInitialized);
+
+ for (const auto& pair : Nodes) {
+ pair.second->LogSettings->Append(minVal, maxVal, func);
+ }
+ }
+
+ TIntrusivePtr<NLog::TSettings> GetLogSettings(ui32 nodeIdx)
+ {
+ return Nodes[FirstNodeId + nodeIdx]->LogSettings;
+ }
+
+ TActorSystem* SingleSys() const;
+ TActorSystem* GetAnyNodeActorSystem();
+ TActorSystem* GetActorSystem(ui32 nodeId);
+ template <typename TEvent>
+ TEvent* GrabEdgeEventIf(TAutoPtr<IEventHandle>& handle, std::function<bool(const TEvent&)> predicate, TDuration simTimeout = TDuration::Max()) {
+ handle.Destroy();
+ const ui32 eventType = TEvent::EventType;
+ WaitForEdgeEvents([&](TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event) {
+ Y_UNUSED(runtime);
+ if (event->GetTypeRewrite() != eventType)
+ return false;
+
+ TEvent* typedEvent = reinterpret_cast<TAutoPtr<TEventHandle<TEvent>>&>(event)->Get();
+ if (predicate(*typedEvent)) {
+ handle = event;
+ return true;
+ }
+
+ return false;
+ }, {}, simTimeout);
+
+ if (simTimeout == TDuration::Max())
+ Y_VERIFY(handle);
+
+ if (handle) {
+ return reinterpret_cast<TAutoPtr<TEventHandle<TEvent>>&>(handle)->Get();
+ } else {
+ return nullptr;
+ }
+ }
+
+ template<class TEvent>
+ typename TEvent::TPtr GrabEdgeEventIf(
+ const TSet<TActorId>& edgeFilter,
+ const std::function<bool(const typename TEvent::TPtr&)>& predicate,
+ TDuration simTimeout = TDuration::Max())
+ {
+ typename TEvent::TPtr handle;
+ const ui32 eventType = TEvent::EventType;
+ WaitForEdgeEvents([&](TTestActorRuntimeBase& runtime, TAutoPtr<IEventHandle>& event) {
+ Y_UNUSED(runtime);
+ if (event->GetTypeRewrite() != eventType)
+ return false;
+
+ typename TEvent::TPtr* typedEvent = reinterpret_cast<typename TEvent::TPtr*>(&event);
+ if (predicate(*typedEvent)) {
+ handle = *typedEvent;
+ return true;
+ }
+
+ return false;
+ }, edgeFilter, simTimeout);
+
+ if (simTimeout == TDuration::Max())
+ Y_VERIFY(handle);
+
+ return handle;
+ }
+
+ template<class TEvent>
+ typename TEvent::TPtr GrabEdgeEventIf(
+ const TActorId& edgeActor,
+ const std::function<bool(const typename TEvent::TPtr&)>& predicate,
+ TDuration simTimeout = TDuration::Max())
+ {
+ TSet<TActorId> edgeFilter{edgeActor};
+ return GrabEdgeEventIf<TEvent>(edgeFilter, predicate, simTimeout);
+ }
+
+ template <typename TEvent>
+ TEvent* GrabEdgeEvent(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) {
+ std::function<bool(const TEvent&)> truth = [](const TEvent&) { return true; };
+ return GrabEdgeEventIf(handle, truth, simTimeout);
+ }
+
+ template <typename TEvent>
+ THolder<TEvent> GrabEdgeEvent(TDuration simTimeout = TDuration::Max()) {
+ TAutoPtr<IEventHandle> handle;
+ std::function<bool(const TEvent&)> truth = [](const TEvent&) { return true; };
+ GrabEdgeEventIf(handle, truth, simTimeout);
+ return THolder(handle ? handle->Release<TEvent>().Release() : nullptr);
+ }
+
+ template<class TEvent>
+ typename TEvent::TPtr GrabEdgeEvent(const TSet<TActorId>& edgeFilter, TDuration simTimeout = TDuration::Max()) {
+ return GrabEdgeEventIf<TEvent>(edgeFilter, [](const typename TEvent::TPtr&) { return true; }, simTimeout);
+ }
+
+ template<class TEvent>
+ typename TEvent::TPtr GrabEdgeEvent(const TActorId& edgeActor, TDuration simTimeout = TDuration::Max()) {
+ TSet<TActorId> edgeFilter{edgeActor};
+ return GrabEdgeEvent<TEvent>(edgeFilter, simTimeout);
+ }
+
+ // replace with std::variant<>
+ template <typename... TEvents>
+ std::tuple<TEvents*...> GrabEdgeEvents(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) {
+ handle.Destroy();
+ auto eventTypes = { TEvents::EventType... };
+ WaitForEdgeEvents([&](TTestActorRuntimeBase&, TAutoPtr<IEventHandle>& event) {
+ if (std::find(std::begin(eventTypes), std::end(eventTypes), event->GetTypeRewrite()) == std::end(eventTypes))
+ return false;
+ handle = event;
+ return true;
+ }, {}, simTimeout);
+ if (simTimeout == TDuration::Max())
+ Y_VERIFY(handle);
+ if (handle) {
+ return std::make_tuple(handle->Type == TEvents::EventType
+ ? reinterpret_cast<TAutoPtr<TEventHandle<TEvents>>&>(handle)->Get()
+ : static_cast<TEvents*>(nullptr)...);
+ }
+ return {};
+ }
+
+ template <typename TEvent>
+ TEvent* GrabEdgeEventRethrow(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) {
+ try {
+ return GrabEdgeEvent<TEvent>(handle, simTimeout);
+ } catch (...) {
+ ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeName<TEvent>() << ": " << CurrentExceptionMessage();
+ }
+ }
+
+ template<class TEvent>
+ typename TEvent::TPtr GrabEdgeEventRethrow(const TSet<TActorId>& edgeFilter, TDuration simTimeout = TDuration::Max()) {
+ try {
+ return GrabEdgeEvent<TEvent>(edgeFilter, simTimeout);
+ } catch (...) {
+ ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeName<TEvent>() << ": " << CurrentExceptionMessage();
+ }
+ }
+
+ template<class TEvent>
+ typename TEvent::TPtr GrabEdgeEventRethrow(const TActorId& edgeActor, TDuration simTimeout = TDuration::Max()) {
+ try {
+ return GrabEdgeEvent<TEvent>(edgeActor, simTimeout);
+ } catch (...) {
+ ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeName<TEvent>() << ": " << CurrentExceptionMessage();
+ }
+ }
+
+ template <typename... TEvents>
+ static TString TypeNames() {
+ static TString names[] = { TypeName<TEvents>()... };
+ TString result;
+ for (const TString& s : names) {
+ if (result.empty()) {
+ result += '<';
+ } else {
+ result += ',';
+ }
+ result += s;
+ }
+ if (!result.empty()) {
+ result += '>';
+ }
+ return result;
+ }
+
+ template <typename... TEvents>
+ std::tuple<TEvents*...> GrabEdgeEventsRethrow(TAutoPtr<IEventHandle>& handle, TDuration simTimeout = TDuration::Max()) {
+ try {
+ return GrabEdgeEvents<TEvents...>(handle, simTimeout);
+ } catch (...) {
+ ythrow TWithBackTrace<yexception>() << "Exception occured while waiting for " << TypeNames<TEvents...>() << ": " << CurrentExceptionMessage();
+ }
+ }
+
+ void ResetScheduledCount() {
+ ScheduledCount = 0;
+ }
+
+ void SetScheduledLimit(ui64 limit) {
+ ScheduledLimit = limit;
+ }
+
+ void SetDispatcherRandomSeed(TInstant time, ui64 iteration);
+ TString GetActorName(const TActorId& actorId) const;
+
+ const TVector<ui64>& GetTxAllocatorTabletIds() const { return TxAllocatorTabletIds; }
+ void SetTxAllocatorTabletIds(const TVector<ui64>& ids) { TxAllocatorTabletIds = ids; }
+
+ void SetUseRealInterconnect() {
+ UseRealInterconnect = true;
+ }
+
+ protected:
+ struct TNodeDataBase;
+ TNodeDataBase* GetRawNode(ui32 node) const {
+ return Nodes.at(FirstNodeId + node).Get();
+ }
+
+ static IExecutorPool* CreateExecutorPoolStub(TTestActorRuntimeBase* runtime, ui32 nodeIndex, TNodeDataBase* node, ui32 poolId);
+ virtual TIntrusivePtr<NMonitoring::TDynamicCounters> GetCountersForComponent(TIntrusivePtr<NMonitoring::TDynamicCounters> counters, const char* component) {
+ Y_UNUSED(counters);
+ Y_UNUSED(component);
+
+ // do nothing, just return the existing counters
+ return counters;
+ }
+
+ THolder<TActorSystemSetup> MakeActorSystemSetup(ui32 nodeIndex, TNodeDataBase* node);
+ THolder<TActorSystem> MakeActorSystem(ui32 nodeIndex, TNodeDataBase* node);
+ virtual void InitActorSystemSetup(TActorSystemSetup& setup) {
+ Y_UNUSED(setup);
+ }
+
+ private:
+ IActor* FindActor(const TActorId& actorId, TNodeDataBase* node) const;
+ void SendInternal(IEventHandle* ev, ui32 nodeIndex, bool viaActorSystem);
+ TEventMailBox& GetMailbox(ui32 nodeId, ui32 hint);
+ void ClearMailbox(ui32 nodeId, ui32 hint);
+ void HandleNonEmptyMailboxesForEachContext(TEventMailboxId mboxId);
+ void UpdateFinalEventsStatsForEachContext(IEventHandle& ev);
+ bool DispatchEventsInternal(const TDispatchOptions& options, TInstant simDeadline);
+
+ private:
+ ui64 ScheduledCount;
+ ui64 ScheduledLimit;
+ THolder<TTempDir> TmpDir;
+ const TThread::TId MainThreadId;
+
+ protected:
+ bool UseRealInterconnect = false;
+ TInterconnectMock InterconnectMock;
+ bool IsInitialized = false;
+ bool SingleSysEnv = false;
+ const TString ClusterUUID;
+ const ui32 FirstNodeId;
+ const ui32 NodeCount;
+ const ui32 DataCenterCount;
+ const bool UseRealThreads;
+
+ ui64 LocalId;
+ TMutex Mutex;
+ TCondVar MailboxesHasEvents;
+ TEventMailBoxList Mailboxes;
+ TMap<ui32, ui64> EvCounters;
+ ui64 DispatchCyclesCount;
+ ui64 DispatchedEventsCount;
+ ui64 DispatchedEventsLimit = 2'500'000;
+ TActorId CurrentRecipient;
+ ui64 DispatcherRandomSeed;
+ TIntrusivePtr<IRandomProvider> DispatcherRandomProvider;
+ TAutoPtr<TLogBackend> LogBackend;
+ bool NeedMonitoring;
+
+ TIntrusivePtr<IRandomProvider> RandomProvider;
+ TIntrusivePtr<ITimeProvider> TimeProvider;
+
+ protected:
+ struct TNodeDataBase: public TThrRefBase {
+ TNodeDataBase();
+ void Stop();
+ virtual ~TNodeDataBase();
+ virtual ui64 GetLoggerPoolId() const {
+ return 0;
+ }
+
+ template <typename T = void>
+ T* GetAppData() {
+ return static_cast<T*>(AppData0.get());
+ }
+
+ template <typename T = void>
+ const T* GetAppData() const {
+ return static_cast<T*>(AppData0.get());
+ }
+
+ TIntrusivePtr<NMonitoring::TDynamicCounters> DynamicCounters;
+ TIntrusivePtr<NActors::NLog::TSettings> LogSettings;
+ TIntrusivePtr<NInterconnect::TPollerThreads> Poller;
+ volatile ui64* ActorSystemTimestamp;
+ volatile ui64* ActorSystemMonotonic;
+ TVector<std::pair<TActorId, TActorSetupCmd> > LocalServices;
+ TMap<TActorId, IActor*> LocalServicesActors;
+ TMap<IActor*, TActorId> ActorToActorId;
+ THolder<TMailboxTable> MailboxTable;
+ std::shared_ptr<void> AppData0;
+ THolder<TActorSystem> ActorSystem;
+ THolder<IExecutorPool> SchedulerPool;
+ TVector<IExecutorPool*> ExecutorPools;
+ THolder<TExecutorThread> ExecutorThread;
+ };
+
+ struct INodeFactory {
+ virtual ~INodeFactory() = default;
+ virtual TIntrusivePtr<TNodeDataBase> CreateNode() = 0;
+ };
+
+ struct TDefaultNodeFactory final: INodeFactory {
+ virtual TIntrusivePtr<TNodeDataBase> CreateNode() override {
+ return new TNodeDataBase();
+ }
+ };
+
+ INodeFactory& GetNodeFactory() {
+ return *NodeFactory;
+ }
+
+ virtual TNodeDataBase* GetNodeById(size_t idx) {
+ return Nodes[idx].Get();
+ }
+
+ void InitNodes();
+ void CleanupNodes();
+ virtual void InitNodeImpl(TNodeDataBase*, size_t);
+
+ static bool AllowSendFrom(TNodeDataBase* node, TAutoPtr<IEventHandle>& ev);
+
+ protected:
+ THolder<INodeFactory> NodeFactory{new TDefaultNodeFactory};
+
+ private:
+ void InitNode(TNodeDataBase* node, size_t idx);
+
+ struct TDispatchContext {
+ const TDispatchOptions* Options;
+ TDispatchContext* PrevContext;
+
+ TMap<const TDispatchOptions::TFinalEventCondition*, ui32> FinalEventFrequency;
+ TSet<TEventMailboxId> FoundNonEmptyMailboxes;
+ bool FinalEventFound = false;
+ };
+
+ TProgramShouldContinue ShouldContinue;
+ TMap<ui32, TIntrusivePtr<TNodeDataBase>> Nodes;
+ ui64 CurrentTimestamp;
+ TSet<TActorId> EdgeActors;
+ THashMap<TEventMailboxId, TActorId, TEventMailboxId::THash> EdgeActorByMailbox;
+ TDuration DispatchTimeout;
+ TDuration ReschedulingDelay;
+ TEventObserver ObserverFunc;
+ TScheduledEventsSelector ScheduledEventsSelectorFunc;
+ TEventFilter EventFilterFunc;
+ TScheduledEventFilter ScheduledEventFilterFunc;
+ TRegistrationObserver RegistrationObserver;
+ TSet<TActorId> BlockedOutput;
+ TSet<TActorId> ScheduleWhiteList;
+ THashMap<TActorId, TActorId> ScheduleWhiteListParent;
+ THashMap<TActorId, TString> ActorNames;
+ TDispatchContext* CurrentDispatchContext;
+ TVector<ui64> TxAllocatorTabletIds;
+
+ static ui32 NextNodeId;
+ };
+
+ template <typename TEvent>
+ TEvent* FindEvent(TEventsList& events) {
+ for (auto& event : events) {
+ if (event && event->GetTypeRewrite() == TEvent::EventType) {
+ return static_cast<TEvent*>(event->GetBase());
+ }
+ }
+
+ return nullptr;
+ }
+
+ template <typename TEvent>
+ TEvent* FindEvent(TEventsList& events, const std::function<bool(const TEvent&)>& predicate) {
+ for (auto& event : events) {
+ if (event && event->GetTypeRewrite() == TEvent::EventType && predicate(*static_cast<TEvent*>(event->GetBase()))) {
+ return static_cast<TEvent*>(event->GetBase());
+ }
+ }
+
+ return nullptr;
+ }
+
+ template <typename TEvent>
+ TEvent* GrabEvent(TEventsList& events, TAutoPtr<IEventHandle>& ev) {
+ ev.Destroy();
+ for (auto& event : events) {
+ if (event && event->GetTypeRewrite() == TEvent::EventType) {
+ ev = event;
+ return static_cast<TEvent*>(ev->GetBase());
+ }
+ }
+
+ return nullptr;
+ }
+
+ template <typename TEvent>
+ TEvent* GrabEvent(TEventsList& events, TAutoPtr<IEventHandle>& ev,
+ const std::function<bool(const typename TEvent::TPtr&)>& predicate) {
+ ev.Destroy();
+ for (auto& event : events) {
+ if (event && event->GetTypeRewrite() == TEvent::EventType) {
+ if (predicate(reinterpret_cast<const typename TEvent::TPtr&>(event))) {
+ ev = event;
+ return static_cast<TEvent*>(ev->GetBase());
+ }
+ }
+ }
+
+ return nullptr;
+ }
+
+ class IStrandingDecoratorFactory {
+ public:
+ virtual ~IStrandingDecoratorFactory() {}
+ virtual IActor* Wrap(const TActorId& delegatee, bool isSync, const TVector<TActorId>& additionalActors) = 0;
+ };
+
+ struct IReplyChecker {
+ virtual ~IReplyChecker() {}
+ virtual void OnRequest(IEventHandle *request) = 0;
+ virtual bool IsWaitingForMoreResponses(IEventHandle *response) = 0;
+ };
+
+ struct TNoneReplyChecker : IReplyChecker {
+ void OnRequest(IEventHandle*) override {
+ }
+
+ bool IsWaitingForMoreResponses(IEventHandle*) override {
+ return false;
+ }
+ };
+
+ using TReplyCheckerCreator = std::function<THolder<IReplyChecker>(void)>;
+
+ inline THolder<IReplyChecker> CreateNoneReplyChecker() {
+ return MakeHolder<TNoneReplyChecker>();
+ }
+
+ TAutoPtr<IStrandingDecoratorFactory> CreateStrandingDecoratorFactory(TTestActorRuntimeBase* runtime,
+ TReplyCheckerCreator createReplyChecker = CreateNoneReplyChecker);
+ extern ui64 DefaultRandomSeed;
+}
diff --git a/library/cpp/actors/testlib/ut/ya.make b/library/cpp/actors/testlib/ut/ya.make
new file mode 100644
index 0000000000..1d4aec06ff
--- /dev/null
+++ b/library/cpp/actors/testlib/ut/ya.make
@@ -0,0 +1,20 @@
+UNITTEST_FOR(library/cpp/actors/testlib)
+
+OWNER(
+ kruall
+ g:kikimr
+)
+
+FORK_SUBTESTS()
+SIZE(SMALL)
+
+
+PEERDIR(
+ library/cpp/actors/core
+)
+
+SRCS(
+ decorator_ut.cpp
+)
+
+END()
diff --git a/library/cpp/actors/testlib/ya.make b/library/cpp/actors/testlib/ya.make
new file mode 100644
index 0000000000..1afb3f6059
--- /dev/null
+++ b/library/cpp/actors/testlib/ya.make
@@ -0,0 +1,27 @@
+LIBRARY()
+
+OWNER(
+ g:kikimr
+)
+
+SRCS(
+ test_runtime.cpp
+)
+
+PEERDIR(
+ library/cpp/actors/core
+ library/cpp/actors/interconnect/mock
+ library/cpp/actors/protos
+ library/cpp/random_provider
+ library/cpp/time_provider
+)
+
+IF (GCC)
+ CFLAGS(-fno-devirtualize-speculatively)
+ENDIF()
+
+END()
+
+RECURSE_FOR_TESTS(
+ ut
+)
diff --git a/library/cpp/actors/util/affinity.cpp b/library/cpp/actors/util/affinity.cpp
new file mode 100644
index 0000000000..cc1b6e70ec
--- /dev/null
+++ b/library/cpp/actors/util/affinity.cpp
@@ -0,0 +1,93 @@
+#include "affinity.h"
+
+#ifdef _linux_
+#include <sched.h>
+#endif
+
+class TAffinity::TImpl {
+#ifdef _linux_
+ cpu_set_t Mask;
+#endif
+public:
+ TImpl() {
+#ifdef _linux_
+ int ar = sched_getaffinity(0, sizeof(cpu_set_t), &Mask);
+ Y_VERIFY_DEBUG(ar == 0);
+#endif
+ }
+
+ explicit TImpl(const ui8* cpus, ui32 size) {
+#ifdef _linux_
+ CPU_ZERO(&Mask);
+ for (ui32 i = 0; i != size; ++i) {
+ if (cpus[i]) {
+ CPU_SET(i, &Mask);
+ }
+ }
+#else
+ Y_UNUSED(cpus);
+ Y_UNUSED(size);
+#endif
+ }
+
+ void Set() const {
+#ifdef _linux_
+ int ar = sched_setaffinity(0, sizeof(cpu_set_t), &Mask);
+ Y_VERIFY_DEBUG(ar == 0);
+#endif
+ }
+
+ operator TCpuMask() const {
+ TCpuMask result;
+#ifdef _linux_
+ for (ui32 i = 0; i != CPU_SETSIZE; ++i) {
+ result.Cpus.emplace_back(CPU_ISSET(i, &Mask));
+ }
+ result.RemoveTrailingZeros();
+#endif
+ return result;
+ }
+
+};
+
+TAffinity::TAffinity() {
+}
+
+TAffinity::~TAffinity() {
+}
+
+TAffinity::TAffinity(const ui8* x, ui32 sz) {
+ if (x && sz) {
+ Impl.Reset(new TImpl(x, sz));
+ }
+}
+
+TAffinity::TAffinity(const TCpuMask& mask) {
+ if (!mask.IsEmpty()) {
+ static_assert(sizeof(ui8) == sizeof(mask.Cpus[0]));
+ const ui8* x = reinterpret_cast<const ui8*>(&mask.Cpus[0]);
+ const ui32 sz = mask.Size();
+ Impl.Reset(new TImpl(x, sz));
+ }
+}
+
+void TAffinity::Current() {
+ Impl.Reset(new TImpl());
+}
+
+void TAffinity::Set() const {
+ if (!!Impl) {
+ Impl->Set();
+ }
+}
+
+bool TAffinity::Empty() const {
+ return !Impl;
+}
+
+TAffinity::operator TCpuMask() const {
+ if (!!Impl) {
+ return *Impl;
+ }
+ return TCpuMask();
+}
diff --git a/library/cpp/actors/util/affinity.h b/library/cpp/actors/util/affinity.h
new file mode 100644
index 0000000000..ae106ed180
--- /dev/null
+++ b/library/cpp/actors/util/affinity.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "defs.h"
+#include "cpumask.h"
+
+// Platform-specific class to set or get thread affinity
+class TAffinity: public TThrRefBase, TNonCopyable {
+ class TImpl;
+ THolder<TImpl> Impl;
+
+public:
+ TAffinity();
+ TAffinity(const ui8* cpus, ui32 size);
+ explicit TAffinity(const TCpuMask& mask);
+ ~TAffinity();
+
+ void Current();
+ void Set() const;
+ bool Empty() const;
+
+ operator TCpuMask() const;
+};
+
+// Scoped affinity setter
+class TAffinityGuard : TNonCopyable {
+ bool Stacked;
+ TAffinity OldAffinity;
+
+public:
+ TAffinityGuard(const TAffinity* affinity) {
+ Stacked = false;
+ if (affinity && !affinity->Empty()) {
+ OldAffinity.Current();
+ affinity->Set();
+ Stacked = true;
+ }
+ }
+
+ ~TAffinityGuard() {
+ Release();
+ }
+
+ void Release() {
+ if (Stacked) {
+ OldAffinity.Set();
+ Stacked = false;
+ }
+ }
+};
diff --git a/library/cpp/actors/util/cpumask.h b/library/cpp/actors/util/cpumask.h
new file mode 100644
index 0000000000..29741aa1d6
--- /dev/null
+++ b/library/cpp/actors/util/cpumask.h
@@ -0,0 +1,133 @@
+#pragma once
+
+#include "defs.h"
+
+#include <library/cpp/containers/stack_vector/stack_vec.h>
+
+#include <util/string/split.h>
+#include <util/generic/yexception.h>
+
+using TCpuId = ui32;
+
+// Simple data structure to operate with set of cpus
+struct TCpuMask {
+ TStackVec<bool, 1024> Cpus;
+
+ // Creates empty mask
+ TCpuMask() {}
+
+ // Creates mask with single cpu set
+ explicit TCpuMask(TCpuId cpuId) {
+ Set(cpuId);
+ }
+
+ // Initialize mask from raw boolean array
+ template <class T>
+ TCpuMask(const T* cpus, TCpuId size) {
+ Cpus.reserve(size);
+ for (TCpuId i = 0; i != size; ++i) {
+ Cpus.emplace_back(bool(cpus[i]));
+ }
+ }
+
+ // Parse a numerical list of processors. The numbers are separated by commas and may include ranges. For example: 0,5,7,9-11
+ explicit TCpuMask(const TString& cpuList) {
+ try {
+ for (TStringBuf s : StringSplitter(cpuList).Split(',')) {
+ TCpuId l, r;
+ if (s.find('-') != TString::npos) {
+ StringSplitter(s).Split('-').CollectInto(&l, &r);
+ } else {
+ l = r = FromString<TCpuId>(s);
+ }
+ if (r >= Cpus.size()) {
+ Cpus.resize(r + 1, false);
+ }
+ for (TCpuId cpu = l; cpu <= r; cpu++) {
+ Cpus[cpu] = true;
+ }
+ }
+ } catch (...) {
+ ythrow TWithBackTrace<yexception>() << "Exception occured while parsing cpu list '" << cpuList << "': " << CurrentExceptionMessage();
+ }
+ }
+
+ // Returns size of underlying vector
+ TCpuId Size() const {
+ return Cpus.size();
+ }
+
+ // Returns number of set bits in mask
+ TCpuId CpuCount() const {
+ TCpuId result = 0;
+ for (bool value : Cpus) {
+ result += value;
+ }
+ return result;
+ }
+
+ bool IsEmpty() const {
+ for (bool value : Cpus) {
+ if (value) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool IsSet(TCpuId cpu) const {
+ return cpu < Cpus.size() && Cpus[cpu];
+ }
+
+ void Set(TCpuId cpu) {
+ if (cpu >= Cpus.size()) {
+ Cpus.resize(cpu + 1, false);
+ }
+ Cpus[cpu] = true;
+ }
+
+ void Reset(TCpuId cpu) {
+ if (cpu < Cpus.size()) {
+ Cpus[cpu] = false;
+ }
+ }
+
+ void RemoveTrailingZeros() {
+ while (!Cpus.empty() && !Cpus.back()) {
+ Cpus.pop_back();
+ }
+ }
+
+ explicit operator bool() const {
+ return !IsEmpty();
+ }
+
+ TCpuMask operator &(const TCpuMask& rhs) const {
+ TCpuMask result;
+ TCpuId size = Max(Size(), rhs.Size());
+ result.Cpus.reserve(size);
+ for (TCpuId cpu = 0; cpu < size; cpu++) {
+ result.Cpus.emplace_back(IsSet(cpu) && rhs.IsSet(cpu));
+ }
+ return result;
+ }
+
+ TCpuMask operator |(const TCpuMask& rhs) const {
+ TCpuMask result;
+ TCpuId size = Max(Size(), rhs.Size());
+ result.Cpus.reserve(size);
+ for (TCpuId cpu = 0; cpu < size; cpu++) {
+ result.Cpus.emplace_back(IsSet(cpu) || rhs.IsSet(cpu));
+ }
+ return result;
+ }
+
+ TCpuMask operator -(const TCpuMask& rhs) const {
+ TCpuMask result;
+ result.Cpus.reserve(Size());
+ for (TCpuId cpu = 0; cpu < Size(); cpu++) {
+ result.Cpus.emplace_back(IsSet(cpu) && !rhs.IsSet(cpu));
+ }
+ return result;
+ }
+};
diff --git a/library/cpp/actors/util/datetime.h b/library/cpp/actors/util/datetime.h
new file mode 100644
index 0000000000..cbec5965d6
--- /dev/null
+++ b/library/cpp/actors/util/datetime.h
@@ -0,0 +1,82 @@
+#pragma once
+
+#include <util/system/defaults.h>
+#include <util/system/hp_timer.h>
+#include <util/system/platform.h>
+
+#if defined(_win_)
+#include <intrin.h>
+#pragma intrinsic(__rdtsc)
+#endif // _win_
+
+#if defined(_darwin_) && !defined(_x86_)
+#include <mach/mach_time.h>
+#endif
+
+// GetCycleCount() from util/system/datetime.h uses rdtscp, which is more accurate than rdtsc,
+// but rdtscp disables processor's out-of-order execution, so it can be slow
+Y_FORCE_INLINE ui64 GetCycleCountFast() {
+#if defined(_MSC_VER)
+ // Generates the rdtsc instruction, which returns the processor time stamp.
+ // The processor time stamp records the number of clock cycles since the last reset.
+ return __rdtsc();
+#elif defined(__clang__) && !defined(_arm64_)
+ return __builtin_readcyclecounter();
+#elif defined(_x86_64_)
+ unsigned hi, lo;
+ __asm__ __volatile__("rdtsc"
+ : "=a"(lo), "=d"(hi));
+ return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
+#elif defined(_i386_)
+ ui64 x;
+ __asm__ volatile("rdtsc\n\t"
+ : "=A"(x));
+ return x;
+#elif defined(_darwin_)
+ return mach_absolute_time();
+#elif defined(_arm32_)
+ return MicroSeconds();
+#elif defined(_arm64_)
+ ui64 x;
+
+ __asm__ __volatile__("isb; mrs %0, cntvct_el0"
+ : "=r"(x));
+
+ return x;
+#else
+#error "unsupported arch"
+#endif
+}
+
+// NHPTimer::GetTime fast analog
+Y_FORCE_INLINE void GetTimeFast(NHPTimer::STime* pTime) noexcept {
+ *pTime = GetCycleCountFast();
+}
+
+namespace NActors {
+ inline double Ts2Ns(ui64 ts) {
+ return NHPTimer::GetSeconds(ts) * 1e9;
+ }
+
+ inline double Ts2Us(ui64 ts) {
+ return NHPTimer::GetSeconds(ts) * 1e6;
+ }
+
+ inline double Ts2Ms(ui64 ts) {
+ return NHPTimer::GetSeconds(ts) * 1e3;
+ }
+
+ inline ui64 Us2Ts(double us) {
+ return ui64(NHPTimer::GetClockRate() * us / 1e6);
+ }
+
+ struct TTimeTracker {
+ ui64 Ts;
+ TTimeTracker(): Ts(GetCycleCountFast()) {}
+ ui64 Elapsed() {
+ ui64 ts = GetCycleCountFast();
+ std::swap(Ts, ts);
+ return Ts - ts;
+ }
+ };
+}
diff --git a/library/cpp/actors/util/defs.h b/library/cpp/actors/util/defs.h
new file mode 100644
index 0000000000..5c3b57665b
--- /dev/null
+++ b/library/cpp/actors/util/defs.h
@@ -0,0 +1,16 @@
+#pragma once
+
+// unique tag to fix pragma once gcc glueing: ./library/actors/util/defs.h
+
+#include <util/system/defaults.h>
+#include <util/generic/bt_exception.h>
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+#include <util/generic/yexception.h>
+#include <util/system/atomic.h>
+#include <util/system/align.h>
+#include <util/generic/vector.h>
+#include <util/datetime/base.h>
+#include <util/generic/ylimits.h>
+#include "intrinsics.h"
diff --git a/library/cpp/actors/util/funnel_queue.h b/library/cpp/actors/util/funnel_queue.h
new file mode 100644
index 0000000000..0e21e2617c
--- /dev/null
+++ b/library/cpp/actors/util/funnel_queue.h
@@ -0,0 +1,240 @@
+#pragma once
+
+#include <util/system/atomic.h>
+#include <util/generic/noncopyable.h>
+
+template <typename ElementType>
+class TFunnelQueue: private TNonCopyable {
+public:
+ TFunnelQueue() noexcept
+ : Front(nullptr)
+ , Back(nullptr)
+ {
+ }
+
+ virtual ~TFunnelQueue() noexcept {
+ for (auto entry = Front; entry; entry = DeleteEntry(entry))
+ continue;
+ }
+
+ /// Push element. Can be used from many threads. Return true if is first element.
+ bool
+ Push(ElementType&& element) noexcept {
+ TEntry* const next = NewEntry(static_cast<ElementType&&>(element));
+ TEntry* const prev = AtomicSwap(&Back, next);
+ AtomicSet(prev ? prev->Next : Front, next);
+ return !prev;
+ }
+
+ /// Extract top element. Must be used only from one thread. Return true if have more.
+ bool
+ Pop() noexcept {
+ if (TEntry* const top = AtomicGet(Front)) {
+ const auto last = AtomicCas(&Back, nullptr, top);
+ if (last) // This is last element in queue. Queue is empty now.
+ AtomicCas(&Front, nullptr, top);
+ else // This element is not last.
+ for (;;) {
+ if (const auto next = AtomicGet(top->Next)) {
+ AtomicSet(Front, next);
+ break;
+ }
+ // But Next is null. Wait next assignment in spin lock.
+ }
+
+ DeleteEntry(top);
+ return !last;
+ }
+
+ return false;
+ }
+
+ /// Peek top element. Must be used only from one thread.
+ ElementType&
+ Top() const noexcept {
+ return AtomicGet(Front)->Data;
+ }
+
+ bool
+ IsEmpty() const noexcept {
+ return !AtomicGet(Front);
+ }
+
+protected:
+ class TEntry: private TNonCopyable {
+ friend class TFunnelQueue;
+
+ private:
+ explicit TEntry(ElementType&& element) noexcept
+ : Data(static_cast<ElementType&&>(element))
+ , Next(nullptr)
+ {
+ }
+
+ ~TEntry() noexcept {
+ }
+
+ public:
+ ElementType Data;
+ TEntry* volatile Next;
+ };
+
+ TEntry* volatile Front;
+ TEntry* volatile Back;
+
+ virtual TEntry* NewEntry(ElementType&& element) noexcept {
+ return new TEntry(static_cast<ElementType&&>(element));
+ }
+
+ virtual TEntry* DeleteEntry(TEntry* entry) noexcept {
+ const auto next = entry->Next;
+ delete entry;
+ return next;
+ }
+
+protected:
+ struct TEntryIter {
+ TEntry* ptr;
+
+ ElementType& operator*() {
+ return ptr->Data;
+ }
+
+ ElementType* operator->() {
+ return &ptr->Data;
+ }
+
+ TEntryIter& operator++() {
+ ptr = AtomicGet(ptr->Next);
+ return *this;
+ }
+
+ bool operator!=(const TEntryIter& other) const {
+ return ptr != other.ptr;
+ }
+
+ bool operator==(const TEntryIter& other) const {
+ return ptr == other.ptr;
+ }
+ };
+
+ struct TConstEntryIter {
+ const TEntry* ptr;
+
+ const ElementType& operator*() {
+ return ptr->Data;
+ }
+
+ const ElementType* operator->() {
+ return &ptr->Data;
+ }
+
+ TEntryIter& operator++() {
+ ptr = AtomicGet(ptr->Next);
+ return *this;
+ }
+
+ bool operator!=(const TConstEntryIter& other) const {
+ return ptr != other.ptr;
+ }
+
+ bool operator==(const TConstEntryIter& other) const {
+ return ptr == other.ptr;
+ }
+ };
+
+public:
+ using const_iterator = TConstEntryIter;
+ using iterator = TEntryIter;
+
+ iterator begin() {
+ return {AtomicGet(Front)};
+ }
+ const_iterator cbegin() {
+ return {AtomicGet(Front)};
+ }
+ const_iterator begin() const {
+ return {AtomicGet(Front)};
+ }
+
+ iterator end() {
+ return {nullptr};
+ }
+ const_iterator cend() {
+ return {nullptr};
+ }
+ const_iterator end() const {
+ return {nullptr};
+ }
+};
+
+template <typename ElementType>
+class TPooledFunnelQueue: public TFunnelQueue<ElementType> {
+public:
+ TPooledFunnelQueue() noexcept
+ : Stack(nullptr)
+ {
+ }
+
+ virtual ~TPooledFunnelQueue() noexcept override {
+ for (auto entry = TBase::Front; entry; entry = TBase::DeleteEntry(entry))
+ continue;
+ for (auto entry = Stack; entry; entry = TBase::DeleteEntry(entry))
+ continue;
+ TBase::Back = TBase::Front = Stack = nullptr;
+ }
+
+private:
+ typedef TFunnelQueue<ElementType> TBase;
+
+ typename TBase::TEntry* volatile Stack;
+
+protected:
+ virtual typename TBase::TEntry* NewEntry(ElementType&& element) noexcept override {
+ while (const auto top = AtomicGet(Stack))
+ if (AtomicCas(&Stack, top->Next, top)) {
+ top->Data = static_cast<ElementType&&>(element);
+ AtomicSet(top->Next, nullptr);
+ return top;
+ }
+
+ return TBase::NewEntry(static_cast<ElementType&&>(element));
+ }
+
+ virtual typename TBase::TEntry* DeleteEntry(typename TBase::TEntry* entry) noexcept override {
+ entry->Data = ElementType();
+ const auto next = entry->Next;
+ do
+ AtomicSet(entry->Next, AtomicGet(Stack));
+ while (!AtomicCas(&Stack, entry, entry->Next));
+ return next;
+ }
+};
+
+template <typename ElementType, template <typename T> class TQueueType = TFunnelQueue>
+class TCountedFunnelQueue: public TQueueType<ElementType> {
+public:
+ TCountedFunnelQueue() noexcept
+ : Count(0)
+ {
+ }
+
+ TAtomicBase GetSize() const noexcept {
+ return AtomicGet(Count);
+ }
+
+private:
+ typedef TQueueType<ElementType> TBase;
+
+ virtual typename TBase::TEntry* NewEntry(ElementType&& element) noexcept override {
+ AtomicAdd(Count, 1);
+ return TBase::NewEntry(static_cast<ElementType&&>(element));
+ }
+
+ virtual typename TBase::TEntry* DeleteEntry(typename TBase::TEntry* entry) noexcept override {
+ AtomicSub(Count, 1);
+ return TBase::DeleteEntry(entry);
+ }
+
+ TAtomic Count;
+};
diff --git a/library/cpp/actors/util/futex.h b/library/cpp/actors/util/futex.h
new file mode 100644
index 0000000000..c193f8d128
--- /dev/null
+++ b/library/cpp/actors/util/futex.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#ifdef _linux_
+
+#include <linux/futex.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+static long SysFutex(void* addr1, int op, int val1, struct timespec* timeout, void* addr2, int val3) {
+ return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
+}
+
+#endif
diff --git a/library/cpp/actors/util/intrinsics.h b/library/cpp/actors/util/intrinsics.h
new file mode 100644
index 0000000000..df07e36896
--- /dev/null
+++ b/library/cpp/actors/util/intrinsics.h
@@ -0,0 +1,97 @@
+#pragma once
+
+#include <util/system/defaults.h>
+#include <util/system/atomic.h>
+#include <util/system/spinlock.h>
+
+#include <library/cpp/sse/sse.h> // The header chooses appropriate SSE support
+
+static_assert(sizeof(TAtomic) == 8, "expect sizeof(TAtomic) == 8");
+
+// we need explicit 32 bit operations to keep cache-line friendly packs
+// so have to define some atomics additionaly to arcadia one
+#ifdef _win_
+#pragma intrinsic(_InterlockedCompareExchange)
+#pragma intrinsic(_InterlockedExchangeAdd)
+#pragma intrinsic(_InterlockedIncrement)
+#pragma intrinsic(_InterlockedDecrement)
+#endif
+
+inline bool AtomicUi32Cas(volatile ui32* a, ui32 exchange, ui32 compare) {
+#ifdef _win_
+ return _InterlockedCompareExchange((volatile long*)a, exchange, compare) == (long)compare;
+#else
+ ui32 expected = compare;
+ return __atomic_compare_exchange_n(a, &expected, exchange, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+#endif
+}
+
+inline ui32 AtomicUi32Add(volatile ui32* a, ui32 add) {
+#ifdef _win_
+ return _InterlockedExchangeAdd((volatile long*)a, add) + add;
+#else
+ return __atomic_add_fetch(a, add, __ATOMIC_SEQ_CST);
+#endif
+}
+
+inline ui32 AtomicUi32Sub(volatile ui32* a, ui32 sub) {
+#ifdef _win_
+ return _InterlockedExchangeAdd((volatile long*)a, -(long)sub) - sub;
+#else
+ return __atomic_sub_fetch(a, sub, __ATOMIC_SEQ_CST);
+#endif
+}
+
+inline ui32 AtomicUi32Increment(volatile ui32* a) {
+#ifdef _win_
+ return _InterlockedIncrement((volatile long*)a);
+#else
+ return __atomic_add_fetch(a, 1, __ATOMIC_SEQ_CST);
+#endif
+}
+
+inline ui32 AtomicUi32Decrement(volatile ui32* a) {
+#ifdef _win_
+ return _InterlockedDecrement((volatile long*)a);
+#else
+ return __atomic_sub_fetch(a, 1, __ATOMIC_SEQ_CST);
+#endif
+}
+
+template <typename T>
+inline void AtomicStore(volatile T* a, T x) {
+ static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value");
+#ifdef _win_
+ *a = x;
+#else
+ __atomic_store_n(a, x, __ATOMIC_RELEASE);
+#endif
+}
+
+template <typename T>
+inline void RelaxedStore(volatile T* a, T x) {
+ static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value");
+#ifdef _win_
+ *a = x;
+#else
+ __atomic_store_n(a, x, __ATOMIC_RELAXED);
+#endif
+}
+
+template <typename T>
+inline T AtomicLoad(volatile T* a) {
+#ifdef _win_
+ return *a;
+#else
+ return __atomic_load_n(a, __ATOMIC_ACQUIRE);
+#endif
+}
+
+template <typename T>
+inline T RelaxedLoad(volatile T* a) {
+#ifdef _win_
+ return *a;
+#else
+ return __atomic_load_n(a, __ATOMIC_RELAXED);
+#endif
+}
diff --git a/library/cpp/actors/util/local_process_key.h b/library/cpp/actors/util/local_process_key.h
new file mode 100644
index 0000000000..172f08fc73
--- /dev/null
+++ b/library/cpp/actors/util/local_process_key.h
@@ -0,0 +1,132 @@
+#pragma once
+
+#include <util/string/builder.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/vector.h>
+#include <util/generic/hash.h>
+#include <util/generic/singleton.h>
+#include <util/generic/serialized_enum.h>
+
+template <typename T>
+class TLocalProcessKeyState {
+
+template <typename U, const char* Name>
+friend class TLocalProcessKey;
+template <typename U, typename EnumT>
+friend class TEnumProcessKey;
+
+public:
+ static TLocalProcessKeyState& GetInstance() {
+ return *Singleton<TLocalProcessKeyState<T>>();
+ }
+
+ size_t GetCount() const {
+ return StartIndex + Names.size();
+ }
+
+ TStringBuf GetNameByIndex(size_t index) const {
+ if (index < StartIndex) {
+ return StaticNames[index];
+ } else {
+ index -= StartIndex;
+ Y_ENSURE(index < Names.size());
+ return Names[index];
+ }
+ }
+
+ size_t GetIndexByName(TStringBuf name) const {
+ auto it = Map.find(name);
+ Y_ENSURE(it != Map.end());
+ return it->second;
+ }
+
+private:
+ size_t Register(TStringBuf name) {
+ auto x = Map.emplace(name, Names.size()+StartIndex);
+ if (x.second) {
+ Names.emplace_back(name);
+ }
+
+ return x.first->second;
+ }
+
+ size_t Register(TStringBuf name, ui32 index) {
+ Y_VERIFY(index < StartIndex);
+ auto x = Map.emplace(name, index);
+ Y_VERIFY(x.second || x.first->second == index);
+ StaticNames[index] = name;
+ return x.first->second;
+ }
+
+private:
+ static constexpr ui32 StartIndex = 2000;
+
+ TVector<TString> FillStaticNames() {
+ TVector<TString> staticNames;
+ staticNames.reserve(StartIndex);
+ for (ui32 i = 0; i < StartIndex; i++) {
+ staticNames.push_back(TStringBuilder() << "Activity_" << i);
+ }
+ return staticNames;
+ }
+
+ TVector<TString> StaticNames = FillStaticNames();
+ TVector<TString> Names;
+ THashMap<TString, size_t> Map;
+};
+
+template <typename T, const char* Name>
+class TLocalProcessKey {
+public:
+ static TStringBuf GetName() {
+ return Name;
+ }
+
+ static size_t GetIndex() {
+ return Index;
+ }
+
+private:
+ inline static size_t Index = TLocalProcessKeyState<T>::GetInstance().Register(Name);
+};
+
+template <typename T, typename EnumT>
+class TEnumProcessKey {
+public:
+ static TStringBuf GetName(EnumT key) {
+ return TLocalProcessKeyState<T>::GetInstance().GetNameByIndex(GetIndex(key));
+ }
+
+ static size_t GetIndex(EnumT key) {
+ ui32 index = static_cast<ui32>(key);
+ if (index < TLocalProcessKeyState<T>::StartIndex) {
+ return index;
+ }
+ Y_VERIFY(index < Enum2Index.size());
+ return Enum2Index[index];
+ }
+
+private:
+ inline static TVector<size_t> RegisterAll() {
+ static_assert(std::is_enum<EnumT>::value, "Enum is required");
+
+ TVector<size_t> enum2Index;
+ auto names = GetEnumNames<EnumT>();
+ ui32 maxId = 0;
+ for (const auto& [k, v] : names) {
+ maxId = Max(maxId, static_cast<ui32>(k));
+ }
+ enum2Index.resize(maxId+1);
+ for (ui32 i = 0; i <= maxId && i < TLocalProcessKeyState<T>::StartIndex; i++) {
+ enum2Index[i] = i;
+ }
+
+ for (const auto& [k, v] : names) {
+ ui32 enumId = static_cast<ui32>(k);
+ enum2Index[enumId] = TLocalProcessKeyState<T>::GetInstance().Register(v, enumId);
+ }
+ return enum2Index;
+ }
+
+ inline static TVector<size_t> Enum2Index = RegisterAll();
+};
diff --git a/library/cpp/actors/util/named_tuple.h b/library/cpp/actors/util/named_tuple.h
new file mode 100644
index 0000000000..67f185bba8
--- /dev/null
+++ b/library/cpp/actors/util/named_tuple.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "defs.h"
+
+template <typename TDerived>
+struct TNamedTupleBase {
+ friend bool operator==(const TDerived& x, const TDerived& y) {
+ return x.ConvertToTuple() == y.ConvertToTuple();
+ }
+
+ friend bool operator!=(const TDerived& x, const TDerived& y) {
+ return x.ConvertToTuple() != y.ConvertToTuple();
+ }
+
+ friend bool operator<(const TDerived& x, const TDerived& y) {
+ return x.ConvertToTuple() < y.ConvertToTuple();
+ }
+
+ friend bool operator<=(const TDerived& x, const TDerived& y) {
+ return x.ConvertToTuple() <= y.ConvertToTuple();
+ }
+
+ friend bool operator>(const TDerived& x, const TDerived& y) {
+ return x.ConvertToTuple() > y.ConvertToTuple();
+ }
+
+ friend bool operator>=(const TDerived& x, const TDerived& y) {
+ return x.ConvertToTuple() >= y.ConvertToTuple();
+ }
+};
diff --git a/library/cpp/actors/util/queue_chunk.h b/library/cpp/actors/util/queue_chunk.h
new file mode 100644
index 0000000000..8a4e02d8cb
--- /dev/null
+++ b/library/cpp/actors/util/queue_chunk.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "defs.h"
+
+template <typename T, ui32 TSize, typename TDerived>
+struct TQueueChunkDerived {
+ static const ui32 EntriesCount = (TSize - sizeof(TQueueChunkDerived*)) / sizeof(T);
+ static_assert(EntriesCount > 0, "expect EntriesCount > 0");
+
+ volatile T Entries[EntriesCount];
+ TDerived* volatile Next;
+
+ TQueueChunkDerived() {
+ memset(this, 0, sizeof(TQueueChunkDerived));
+ }
+};
+
+template <typename T, ui32 TSize>
+struct TQueueChunk {
+ static const ui32 EntriesCount = (TSize - sizeof(TQueueChunk*)) / sizeof(T);
+ static_assert(EntriesCount > 0, "expect EntriesCount > 0");
+
+ volatile T Entries[EntriesCount];
+ TQueueChunk* volatile Next;
+
+ TQueueChunk() {
+ memset(this, 0, sizeof(TQueueChunk));
+ }
+};
diff --git a/library/cpp/actors/util/queue_oneone_inplace.h b/library/cpp/actors/util/queue_oneone_inplace.h
new file mode 100644
index 0000000000..d7ec8bb21c
--- /dev/null
+++ b/library/cpp/actors/util/queue_oneone_inplace.h
@@ -0,0 +1,118 @@
+#pragma once
+
+#include "defs.h"
+#include "queue_chunk.h"
+
+template <typename T, ui32 TSize, typename TChunk = TQueueChunk<T, TSize>>
+class TOneOneQueueInplace : TNonCopyable {
+ static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::valuer");
+
+ TChunk* ReadFrom;
+ ui32 ReadPosition;
+ ui32 WritePosition;
+ TChunk* WriteTo;
+
+ friend class TReadIterator;
+
+public:
+ class TReadIterator {
+ TChunk* ReadFrom;
+ ui32 ReadPosition;
+
+ public:
+ TReadIterator(TChunk* readFrom, ui32 readPosition)
+ : ReadFrom(readFrom)
+ , ReadPosition(readPosition)
+ {
+ }
+
+ inline T Next() {
+ TChunk* head = ReadFrom;
+ if (ReadPosition != TChunk::EntriesCount) {
+ return AtomicLoad(&head->Entries[ReadPosition++]);
+ } else if (TChunk* next = AtomicLoad(&head->Next)) {
+ ReadFrom = next;
+ ReadPosition = 0;
+ return Next();
+ }
+ return T{};
+ }
+ };
+
+ TOneOneQueueInplace()
+ : ReadFrom(new TChunk())
+ , ReadPosition(0)
+ , WritePosition(0)
+ , WriteTo(ReadFrom)
+ {
+ }
+
+ ~TOneOneQueueInplace() {
+ Y_VERIFY_DEBUG(Head() == 0);
+ delete ReadFrom;
+ }
+
+ struct TPtrCleanDestructor {
+ static inline void Destroy(TOneOneQueueInplace<T, TSize>* x) noexcept {
+ while (T head = x->Pop())
+ delete head;
+ delete x;
+ }
+ };
+
+ struct TCleanDestructor {
+ static inline void Destroy(TOneOneQueueInplace<T, TSize>* x) noexcept {
+ while (x->Pop() != nullptr)
+ continue;
+ delete x;
+ }
+ };
+
+ struct TPtrCleanInplaceMallocDestructor {
+ template <typename TPtrVal>
+ static inline void Destroy(TOneOneQueueInplace<TPtrVal*, TSize>* x) noexcept {
+ while (TPtrVal* head = x->Pop()) {
+ head->~TPtrVal();
+ free(head);
+ }
+ delete x;
+ }
+ };
+
+ void Push(T x) noexcept {
+ if (WritePosition != TChunk::EntriesCount) {
+ AtomicStore(&WriteTo->Entries[WritePosition], x);
+ ++WritePosition;
+ } else {
+ TChunk* next = new TChunk();
+ next->Entries[0] = x;
+ AtomicStore(&WriteTo->Next, next);
+ WriteTo = next;
+ WritePosition = 1;
+ }
+ }
+
+ T Head() {
+ TChunk* head = ReadFrom;
+ if (ReadPosition != TChunk::EntriesCount) {
+ return AtomicLoad(&head->Entries[ReadPosition]);
+ } else if (TChunk* next = AtomicLoad(&head->Next)) {
+ ReadFrom = next;
+ delete head;
+ ReadPosition = 0;
+ return Head();
+ }
+ return T{};
+ }
+
+ T Pop() {
+ T ret = Head();
+ if (ret)
+ ++ReadPosition;
+ return ret;
+ }
+
+ TReadIterator Iterator() {
+ return TReadIterator(ReadFrom, ReadPosition);
+ }
+};
diff --git a/library/cpp/actors/util/recentwnd.h b/library/cpp/actors/util/recentwnd.h
new file mode 100644
index 0000000000..ba1ede6f29
--- /dev/null
+++ b/library/cpp/actors/util/recentwnd.h
@@ -0,0 +1,67 @@
+#pragma once
+
+#include <util/generic/deque.h>
+
+template <typename TElem,
+ template <typename, typename...> class TContainer = TDeque>
+class TRecentWnd {
+public:
+ TRecentWnd(ui32 wndSize)
+ : MaxWndSize_(wndSize)
+ {
+ }
+
+ void Push(const TElem& elem) {
+ if (Window_.size() == MaxWndSize_)
+ Window_.erase(Window_.begin());
+ Window_.emplace_back(elem);
+ }
+
+ void Push(TElem&& elem) {
+ if (Window_.size() == MaxWndSize_)
+ Window_.erase(Window_.begin());
+ Window_.emplace_back(std::move(elem));
+ }
+
+ TElem& Last() {
+ return Window_.back();
+ }
+ const TElem& Last() const {
+ return Window_.back();
+ }
+ bool Full() const {
+ return Window_.size() == MaxWndSize_;
+ }
+ ui64 Size() const {
+ return Window_.size();
+ }
+
+ using const_iterator = typename TContainer<TElem>::const_iterator;
+
+ const_iterator begin() {
+ return Window_.begin();
+ }
+ const_iterator end() {
+ return Window_.end();
+ }
+
+ void Reset(ui32 wndSize = 0) {
+ Window_.clear();
+ if (wndSize != 0) {
+ MaxWndSize_ = wndSize;
+ }
+ }
+
+ void ResetWnd(ui32 wndSize) {
+ Y_VERIFY(wndSize != 0);
+ MaxWndSize_ = wndSize;
+ if (Window_.size() > MaxWndSize_) {
+ Window_.erase(Window_.begin(),
+ Window_.begin() + Window_.size() - MaxWndSize_);
+ }
+ }
+
+private:
+ TContainer<TElem> Window_;
+ ui32 MaxWndSize_;
+};
diff --git a/library/cpp/actors/util/rope.h b/library/cpp/actors/util/rope.h
new file mode 100644
index 0000000000..f5595efbaa
--- /dev/null
+++ b/library/cpp/actors/util/rope.h
@@ -0,0 +1,1161 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+#include <util/generic/hash_set.h>
+#include <util/stream/str.h>
+#include <util/system/sanitizers.h>
+#include <util/system/valgrind.h>
+
+// exactly one of them must be included
+#include "rope_cont_list.h"
+//#include "rope_cont_deque.h"
+
+struct IRopeChunkBackend : TThrRefBase {
+ using TData = std::tuple<const char*, size_t>;
+ virtual ~IRopeChunkBackend() = default;
+ virtual TData GetData() const = 0;
+ virtual size_t GetCapacity() const = 0;
+ using TPtr = TIntrusivePtr<IRopeChunkBackend>;
+};
+
+class TRopeAlignedBuffer : public IRopeChunkBackend {
+ static constexpr size_t Alignment = 16;
+ static constexpr size_t MallocAlignment = sizeof(size_t);
+
+ ui32 Size;
+ const ui32 Capacity;
+ const ui32 Offset;
+ alignas(Alignment) char Data[];
+
+ TRopeAlignedBuffer(size_t size)
+ : Size(size)
+ , Capacity(size)
+ , Offset((Alignment - reinterpret_cast<uintptr_t>(Data)) & (Alignment - 1))
+ {
+ Y_VERIFY(Offset <= Alignment - MallocAlignment);
+ }
+
+public:
+ static TIntrusivePtr<TRopeAlignedBuffer> Allocate(size_t size) {
+ return new(malloc(sizeof(TRopeAlignedBuffer) + size + Alignment - MallocAlignment)) TRopeAlignedBuffer(size);
+ }
+
+ void *operator new(size_t) {
+ Y_FAIL();
+ }
+
+ void *operator new(size_t, void *ptr) {
+ return ptr;
+ }
+
+ void operator delete(void *ptr) {
+ free(ptr);
+ }
+
+ void operator delete(void* p, void* ptr) {
+ Y_UNUSED(p);
+ Y_UNUSED(ptr);
+ }
+
+ TData GetData() const override {
+ return {Data + Offset, Size};
+ }
+
+ size_t GetCapacity() const override {
+ return Capacity;
+ }
+
+ char *GetBuffer() {
+ return Data + Offset;
+ }
+
+ void AdjustSize(size_t size) {
+ Y_VERIFY(size <= Capacity);
+ Size = size;
+ }
+};
+
+namespace NRopeDetails {
+
+ template<bool IsConst, typename TRope, typename TList>
+ struct TIteratorTraits;
+
+ template<typename TRope, typename TList>
+ struct TIteratorTraits<true, TRope, TList> {
+ using TRopePtr = const TRope*;
+ using TListIterator = typename TList::const_iterator;
+ };
+
+ template<typename TRope, typename TList>
+ struct TIteratorTraits<false, TRope, TList> {
+ using TRopePtr = TRope*;
+ using TListIterator = typename TList::iterator;
+ };
+
+} // NRopeDetails
+
+class TRopeArena;
+
+template<typename T>
+struct always_false : std::false_type {};
+
+class TRope {
+ friend class TRopeArena;
+
+ struct TChunk
+ {
+ class TBackend {
+ enum class EType : uintptr_t {
+ STRING,
+ ROPE_CHUNK_BACKEND,
+ };
+
+ uintptr_t Owner = 0; // lower bits contain type of the owner
+
+ public:
+ TBackend() = delete;
+
+ TBackend(const TBackend& other)
+ : Owner(Clone(other.Owner))
+ {}
+
+ TBackend(TBackend&& other)
+ : Owner(std::exchange(other.Owner, 0))
+ {}
+
+ TBackend(TString s)
+ : Owner(Construct<TString>(EType::STRING, std::move(s)))
+ {}
+
+ TBackend(IRopeChunkBackend::TPtr backend)
+ : Owner(Construct<IRopeChunkBackend::TPtr>(EType::ROPE_CHUNK_BACKEND, std::move(backend)))
+ {}
+
+ ~TBackend() {
+ if (Owner) {
+ Destroy(Owner);
+ }
+ }
+
+ TBackend& operator =(const TBackend& other) {
+ if (Owner) {
+ Destroy(Owner);
+ }
+ Owner = Clone(other.Owner);
+ return *this;
+ }
+
+ TBackend& operator =(TBackend&& other) {
+ if (Owner) {
+ Destroy(Owner);
+ }
+ Owner = std::exchange(other.Owner, 0);
+ return *this;
+ }
+
+ bool operator ==(const TBackend& other) const {
+ return Owner == other.Owner;
+ }
+
+ const void *UniqueId() const {
+ return reinterpret_cast<const void*>(Owner);
+ }
+
+ const IRopeChunkBackend::TData GetData() const {
+ return Visit(Owner, [](EType, auto& value) -> IRopeChunkBackend::TData {
+ using T = std::decay_t<decltype(value)>;
+ if constexpr (std::is_same_v<T, TString>) {
+ return {value.data(), value.size()};
+ } else if constexpr (std::is_same_v<T, IRopeChunkBackend::TPtr>) {
+ return value->GetData();
+ } else {
+ return {};
+ }
+ });
+ }
+
+ size_t GetCapacity() const {
+ return Visit(Owner, [](EType, auto& value) {
+ using T = std::decay_t<decltype(value)>;
+ if constexpr (std::is_same_v<T, TString>) {
+ return value.capacity();
+ } else if constexpr (std::is_same_v<T, IRopeChunkBackend::TPtr>) {
+ return value->GetCapacity();
+ } else {
+ Y_FAIL();
+ }
+ });
+ }
+
+ private:
+ static constexpr uintptr_t TypeMask = (1 << 3) - 1;
+ static constexpr uintptr_t ValueMask = ~TypeMask;
+
+ template<typename T>
+ struct TObjectHolder {
+ struct TWrappedObject : TThrRefBase {
+ T Value;
+ TWrappedObject(T&& value)
+ : Value(std::move(value))
+ {}
+ };
+ TIntrusivePtr<TWrappedObject> Object;
+
+ TObjectHolder(T&& object)
+ : Object(MakeIntrusive<TWrappedObject>(std::move(object)))
+ {}
+ };
+
+ template<typename TObject>
+ static uintptr_t Construct(EType type, TObject object) {
+ if constexpr (sizeof(TObject) <= sizeof(uintptr_t)) {
+ uintptr_t res = 0;
+ new(&res) TObject(std::move(object));
+ Y_VERIFY_DEBUG((res & ValueMask) == res);
+ return res | static_cast<uintptr_t>(type);
+ } else {
+ return Construct<TObjectHolder<TObject>>(type, TObjectHolder<TObject>(std::move(object)));
+ }
+ }
+
+ template<typename TCallback>
+ static std::invoke_result_t<TCallback, EType, TString&> VisitRaw(uintptr_t value, TCallback&& callback) {
+ Y_VERIFY_DEBUG(value);
+ const EType type = static_cast<EType>(value & TypeMask);
+ value &= ValueMask;
+ auto caller = [&](auto& value) { return std::invoke(std::forward<TCallback>(callback), type, value); };
+ auto wrapper = [&](auto& value) {
+ using T = std::decay_t<decltype(value)>;
+ if constexpr (sizeof(T) <= sizeof(uintptr_t)) {
+ return caller(value);
+ } else {
+ return caller(reinterpret_cast<TObjectHolder<T>&>(value));
+ }
+ };
+ switch (type) {
+ case EType::STRING: return wrapper(reinterpret_cast<TString&>(value));
+ case EType::ROPE_CHUNK_BACKEND: return wrapper(reinterpret_cast<IRopeChunkBackend::TPtr&>(value));
+ }
+ Y_FAIL("Unexpected type# %" PRIu64, static_cast<ui64>(type));
+ }
+
+ template<typename TCallback>
+ static std::invoke_result_t<TCallback, EType, TString&> Visit(uintptr_t value, TCallback&& callback) {
+ return VisitRaw(value, [&](EType type, auto& value) {
+ return std::invoke(std::forward<TCallback>(callback), type, Unwrap(value));
+ });
+ }
+
+ template<typename T> static T& Unwrap(T& object) { return object; }
+ template<typename T> static T& Unwrap(TObjectHolder<T>& holder) { return holder.Object->Value; }
+
+ static uintptr_t Clone(uintptr_t value) {
+ return VisitRaw(value, [](EType type, auto& value) { return Construct(type, value); });
+ }
+
+ static void Destroy(uintptr_t value) {
+ VisitRaw(value, [](EType, auto& value) { CallDtor(value); });
+ }
+
+ template<typename T>
+ static void CallDtor(T& value) {
+ value.~T();
+ }
+ };
+
+ TBackend Backend; // who actually holds the data
+ const char *Begin; // data start
+ const char *End; // data end
+
+ static constexpr struct TSlice {} Slice{};
+
+ template<typename T>
+ TChunk(T&& backend, const IRopeChunkBackend::TData& data)
+ : Backend(std::move(backend))
+ , Begin(std::get<0>(data))
+ , End(Begin + std::get<1>(data))
+ {
+ Y_VERIFY_DEBUG(Begin != End);
+ }
+
+ TChunk(TString s)
+ : Backend(std::move(s))
+ {
+ size_t size;
+ std::tie(Begin, size) = Backend.GetData();
+ End = Begin + size;
+ }
+
+ TChunk(IRopeChunkBackend::TPtr backend)
+ : TChunk(backend, backend->GetData())
+ {}
+
+ TChunk(TSlice, const char *data, size_t size, const TChunk& from)
+ : TChunk(from.Backend, {data, size})
+ {}
+
+ TChunk(TSlice, const char *begin, const char *end, const TChunk& from)
+ : TChunk(Slice, begin, end - begin, from)
+ {}
+
+ explicit TChunk(const TChunk& other)
+ : Backend(other.Backend)
+ , Begin(other.Begin)
+ , End(other.End)
+ {}
+
+ TChunk(TChunk&& other)
+ : Backend(std::move(other.Backend))
+ , Begin(other.Begin)
+ , End(other.End)
+ {}
+
+ TChunk& operator =(const TChunk&) = default;
+ TChunk& operator =(TChunk&&) = default;
+
+ size_t GetSize() const {
+ return End - Begin;
+ }
+
+ static void Clear(TChunk& chunk) {
+ chunk.Begin = nullptr;
+ }
+
+ static bool IsInUse(const TChunk& chunk) {
+ return chunk.Begin != nullptr;
+ }
+
+ size_t GetCapacity() const {
+ return Backend.GetCapacity();
+ }
+ };
+
+ using TChunkList = NRopeDetails::TChunkList<TChunk>;
+
+private:
+ // we use list here to store chain items as we have to keep valid iterators when erase/insert operations are invoked;
+ // iterator uses underlying container's iterator, so we have to use container that keeps valid iterators on delete,
+ // thus, the list
+ TChunkList Chain;
+ size_t Size = 0;
+
+private:
+ template<bool IsConst>
+ class TIteratorImpl {
+ using TTraits = NRopeDetails::TIteratorTraits<IsConst, TRope, TChunkList>;
+
+ typename TTraits::TRopePtr Rope;
+ typename TTraits::TListIterator Iter;
+ const char *Ptr; // ptr is always nullptr when iterator is positioned at the rope end
+
+#ifndef NDEBUG
+ ui32 ValidityToken;
+#endif
+
+ private:
+ TIteratorImpl(typename TTraits::TRopePtr rope, typename TTraits::TListIterator iter, const char *ptr = nullptr)
+ : Rope(rope)
+ , Iter(iter)
+ , Ptr(ptr)
+#ifndef NDEBUG
+ , ValidityToken(Rope->GetValidityToken())
+#endif
+ {}
+
+ public:
+ TIteratorImpl()
+ : Rope(nullptr)
+ , Ptr(nullptr)
+ {}
+
+ template<bool IsOtherConst>
+ TIteratorImpl(const TIteratorImpl<IsOtherConst>& other)
+ : Rope(other.Rope)
+ , Iter(other.Iter)
+ , Ptr(other.Ptr)
+#ifndef NDEBUG
+ , ValidityToken(other.ValidityToken)
+#endif
+ {}
+
+ void CheckValid() const {
+#ifndef NDEBUG
+ Y_VERIFY(ValidityToken == Rope->GetValidityToken());
+#endif
+ }
+
+ TIteratorImpl& operator +=(size_t amount) {
+ CheckValid();
+
+ while (amount) {
+ Y_VERIFY_DEBUG(Valid());
+ const size_t max = ContiguousSize();
+ const size_t num = std::min(amount, max);
+ amount -= num;
+ Ptr += num;
+ if (Ptr == Iter->End) {
+ AdvanceToNextContiguousBlock();
+ }
+ }
+
+ return *this;
+ }
+
+ TIteratorImpl operator +(size_t amount) const {
+ CheckValid();
+
+ return TIteratorImpl(*this) += amount;
+ }
+
+ TIteratorImpl& operator -=(size_t amount) {
+ CheckValid();
+
+ while (amount) {
+ const size_t num = Ptr ? std::min<size_t>(amount, Ptr - Iter->Begin) : 0;
+ amount -= num;
+ Ptr -= num;
+ if (amount) {
+ Y_VERIFY_DEBUG(Iter != GetChainBegin());
+ --Iter;
+ Ptr = Iter->End;
+ }
+ }
+
+ return *this;
+ }
+
+ TIteratorImpl operator -(size_t amount) const {
+ CheckValid();
+ return TIteratorImpl(*this) -= amount;
+ }
+
+ std::pair<const char*, size_t> operator *() const {
+ return {ContiguousData(), ContiguousSize()};
+ }
+
+ TIteratorImpl& operator ++() {
+ AdvanceToNextContiguousBlock();
+ return *this;
+ }
+
+ TIteratorImpl operator ++(int) const {
+ auto it(*this);
+ it.AdvanceToNextContiguousBlock();
+ return it;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Operation with contiguous data
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ // Get the pointer to the contiguous block of data; valid locations are [Data; Data + Size).
+ const char *ContiguousData() const {
+ CheckValid();
+ return Ptr;
+ }
+
+ // Get the amount of contiguous block.
+ size_t ContiguousSize() const {
+ CheckValid();
+ return Ptr ? Iter->End - Ptr : 0;
+ }
+
+ size_t ChunkOffset() const {
+ return Ptr ? Ptr - Iter->Begin : 0;
+ }
+
+ // Advance to next contiguous block of data.
+ void AdvanceToNextContiguousBlock() {
+ CheckValid();
+ Y_VERIFY_DEBUG(Valid());
+ ++Iter;
+ Ptr = Iter != GetChainEnd() ? Iter->Begin : nullptr;
+ }
+
+ // Extract some data and advance. Size is not checked here, to it must be provided valid.
+ void ExtractPlainDataAndAdvance(void *buffer, size_t len) {
+ CheckValid();
+
+ while (len) {
+ Y_VERIFY_DEBUG(Ptr);
+
+ // calculate amount of bytes we need to move
+ const size_t max = ContiguousSize();
+ const size_t num = std::min(len, max);
+
+ // copy data to the buffer and advance buffer pointers
+ memcpy(buffer, Ptr, num);
+ buffer = static_cast<char*>(buffer) + num;
+ len -= num;
+
+ // advance iterator itself
+ Ptr += num;
+ if (Ptr == Iter->End) {
+ AdvanceToNextContiguousBlock();
+ }
+ }
+ }
+
+ // Checks if the iterator points to the end of the rope or not.
+ bool Valid() const {
+ CheckValid();
+ return Ptr;
+ }
+
+ template<bool IsOtherConst>
+ bool operator ==(const TIteratorImpl<IsOtherConst>& other) const {
+ Y_VERIFY_DEBUG(Rope == other.Rope);
+ CheckValid();
+ other.CheckValid();
+ return Iter == other.Iter && Ptr == other.Ptr;
+ }
+
+ template<bool IsOtherConst>
+ bool operator !=(const TIteratorImpl<IsOtherConst>& other) const {
+ CheckValid();
+ other.CheckValid();
+ return !(*this == other);
+ }
+
+ private:
+ friend class TRope;
+
+ typename TTraits::TListIterator operator ->() const {
+ CheckValid();
+ return Iter;
+ }
+
+ const TChunk& GetChunk() const {
+ CheckValid();
+ return *Iter;
+ }
+
+ typename TTraits::TListIterator GetChainBegin() const {
+ CheckValid();
+ return Rope->Chain.begin();
+ }
+
+ typename TTraits::TListIterator GetChainEnd() const {
+ CheckValid();
+ return Rope->Chain.end();
+ }
+
+ bool PointsToChunkMiddle() const {
+ CheckValid();
+ return Ptr && Ptr != Iter->Begin;
+ }
+ };
+
+public:
+#ifndef NDEBUG
+ ui32 ValidityToken = 0;
+ ui32 GetValidityToken() const { return ValidityToken; }
+ void InvalidateIterators() { ++ValidityToken; }
+#else
+ void InvalidateIterators() {}
+#endif
+
+public:
+ using TConstIterator = TIteratorImpl<true>;
+ using TIterator = TIteratorImpl<false>;
+
+public:
+ TRope() = default;
+ TRope(const TRope& rope) = default;
+
+ TRope(TRope&& rope)
+ : Chain(std::move(rope.Chain))
+ , Size(std::exchange(rope.Size, 0))
+ {
+ rope.InvalidateIterators();
+ }
+
+ TRope(TString s) {
+ if (s) {
+ Size = s.size();
+ s.reserve(32);
+ Chain.PutToEnd(std::move(s));
+ }
+ }
+
+ TRope(IRopeChunkBackend::TPtr item) {
+ std::tie(std::ignore, Size) = item->GetData();
+ Chain.PutToEnd(std::move(item));
+ }
+
+ TRope(TConstIterator begin, TConstIterator end) {
+ Y_VERIFY_DEBUG(begin.Rope == end.Rope);
+ if (begin.Rope == this) {
+ TRope temp(begin, end);
+ *this = std::move(temp);
+ return;
+ }
+
+ while (begin.Iter != end.Iter) {
+ const size_t size = begin.ContiguousSize();
+ Chain.PutToEnd(TChunk::Slice, begin.ContiguousData(), size, begin.GetChunk());
+ begin.AdvanceToNextContiguousBlock();
+ Size += size;
+ }
+
+ if (begin != end && end.PointsToChunkMiddle()) {
+ Chain.PutToEnd(TChunk::Slice, begin.Ptr, end.Ptr, begin.GetChunk());
+ Size += end.Ptr - begin.Ptr;
+ }
+ }
+
+ ~TRope() {
+ }
+
+ // creates a copy of rope with chunks with inefficient storage ratio being copied with arena allocator
+ static TRope CopySpaceOptimized(TRope&& origin, size_t worstRatioPer1k, TRopeArena& arena);
+
+ TRope& operator=(const TRope& other) {
+ Chain = other.Chain;
+ Size = other.Size;
+ return *this;
+ }
+
+ TRope& operator=(TRope&& other) {
+ Chain = std::move(other.Chain);
+ Size = std::exchange(other.Size, 0);
+ InvalidateIterators();
+ other.InvalidateIterators();
+ return *this;
+ }
+
+ size_t GetSize() const {
+ return Size;
+ }
+
+ bool IsEmpty() const {
+ return !Size;
+ }
+
+ operator bool() const {
+ return Chain;
+ }
+
+ TIterator Begin() {
+ return *this ? TIterator(this, Chain.begin(), Chain.GetFirstChunk().Begin) : End();
+ }
+
+ TIterator End() {
+ return TIterator(this, Chain.end());
+ }
+
+ TIterator Iterator(TChunkList::iterator it) {
+ return TIterator(this, it, it != Chain.end() ? it->Begin : nullptr);
+ }
+
+ TIterator Position(size_t index) {
+ return Begin() + index;
+ }
+
+ TConstIterator Begin() const {
+ return *this ? TConstIterator(this, Chain.begin(), Chain.GetFirstChunk().Begin) : End();
+ }
+
+ TConstIterator End() const {
+ return TConstIterator(this, Chain.end());
+ }
+
+ TConstIterator Position(size_t index) const {
+ return Begin() + index;
+ }
+
+ TConstIterator begin() const { return Begin(); }
+ TConstIterator end() const { return End(); }
+
+ void Erase(TIterator begin, TIterator end) {
+ Cut(begin, end, nullptr);
+ }
+
+ TRope Extract(TIterator begin, TIterator end) {
+ TRope res;
+ Cut(begin, end, &res);
+ return res;
+ }
+
+ void ExtractFront(size_t num, TRope *dest) {
+ Y_VERIFY(Size >= num);
+ if (num == Size && !*dest) {
+ *dest = std::move(*this);
+ return;
+ }
+ Size -= num;
+ dest->Size += num;
+ TChunkList::iterator it, first = Chain.begin();
+ for (it = first; num && num >= it->GetSize(); ++it) {
+ num -= it->GetSize();
+ }
+ if (it != first) {
+ if (dest->Chain) {
+ auto& last = dest->Chain.GetLastChunk();
+ if (last.Backend == first->Backend && last.End == first->Begin) {
+ last.End = first->End;
+ first = Chain.Erase(first); // TODO(alexvru): "it" gets invalidated here on some containers
+ }
+ }
+ dest->Chain.Splice(dest->Chain.end(), Chain, first, it);
+ }
+ if (num) {
+ auto it = Chain.begin();
+ if (dest->Chain) {
+ auto& last = dest->Chain.GetLastChunk();
+ if (last.Backend == first->Backend && last.End == first->Begin) {
+ first->Begin += num;
+ last.End = first->Begin;
+ return;
+ }
+ }
+ dest->Chain.PutToEnd(TChunk::Slice, it->Begin, it->Begin + num, *it);
+ it->Begin += num;
+ }
+ }
+
+ void Insert(TIterator pos, TRope&& rope) {
+ Y_VERIFY_DEBUG(this == pos.Rope);
+ Y_VERIFY_DEBUG(this != &rope);
+
+ if (!rope) {
+ return; // do nothing for empty rope
+ }
+
+ // adjust size
+ Size += std::exchange(rope.Size, 0);
+
+ // check if we have to split the block
+ if (pos.PointsToChunkMiddle()) {
+ pos.Iter = Chain.InsertBefore(pos.Iter, TChunk::Slice, pos->Begin, pos.Ptr, pos.GetChunk());
+ ++pos.Iter;
+ pos->Begin = pos.Ptr;
+ }
+
+ // perform glueing if possible
+ TChunk *ropeLeft = &rope.Chain.GetFirstChunk();
+ TChunk *ropeRight = &rope.Chain.GetLastChunk();
+ bool gluedLeft = false, gluedRight = false;
+ if (pos.Iter != Chain.begin()) { // glue left part whenever possible
+ // obtain iterator to previous chunk
+ auto prev(pos.Iter);
+ --prev;
+ if (prev->End == ropeLeft->Begin && prev->Backend == ropeLeft->Backend) { // it is glueable
+ prev->End = ropeLeft->End;
+ gluedLeft = true;
+ }
+ }
+ if (pos.Iter != Chain.end() && ropeRight->End == pos->Begin && ropeRight->Backend == pos->Backend) {
+ pos->Begin = ropeRight->Begin;
+ gluedRight = true;
+ }
+ if (gluedLeft) {
+ rope.Chain.EraseFront();
+ }
+ if (gluedRight) {
+ if (rope) {
+ rope.Chain.EraseBack();
+ } else { // it looks like double-glueing for the same chunk, we have to drop previous one
+ auto prev(pos.Iter);
+ --prev;
+ pos->Begin = prev->Begin;
+ pos.Iter = Chain.Erase(prev);
+ }
+ }
+ if (rope) { // insert remains
+ Chain.Splice(pos.Iter, rope.Chain, rope.Chain.begin(), rope.Chain.end());
+ }
+ Y_VERIFY_DEBUG(!rope);
+ InvalidateIterators();
+ }
+
+ void EraseFront(size_t len) {
+ Y_VERIFY_DEBUG(Size >= len);
+ Size -= len;
+
+ while (len) {
+ Y_VERIFY_DEBUG(Chain);
+ TChunk& item = Chain.GetFirstChunk();
+ const size_t itemSize = item.GetSize();
+ if (len >= itemSize) {
+ Chain.EraseFront();
+ len -= itemSize;
+ } else {
+ item.Begin += len;
+ break;
+ }
+ }
+
+ InvalidateIterators();
+ }
+
+ void EraseBack(size_t len) {
+ Y_VERIFY_DEBUG(Size >= len);
+ Size -= len;
+
+ while (len) {
+ Y_VERIFY_DEBUG(Chain);
+ TChunk& item = Chain.GetLastChunk();
+ const size_t itemSize = item.GetSize();
+ if (len >= itemSize) {
+ Chain.EraseBack();
+ len -= itemSize;
+ } else {
+ item.End -= len;
+ break;
+ }
+ }
+
+ InvalidateIterators();
+ }
+
+ bool ExtractFrontPlain(void *buffer, size_t len) {
+ // check if we have enough data in the rope
+ if (Size < len) {
+ return false;
+ }
+ Size -= len;
+ while (len) {
+ auto& chunk = Chain.GetFirstChunk();
+ const size_t num = Min(len, chunk.GetSize());
+ memcpy(buffer, chunk.Begin, num);
+ buffer = static_cast<char*>(buffer) + num;
+ len -= num;
+ chunk.Begin += num;
+ if (chunk.Begin == chunk.End) {
+ Chain.Erase(Chain.begin());
+ }
+ }
+ InvalidateIterators();
+ return true;
+ }
+
+ bool FetchFrontPlain(char **ptr, size_t *remain) {
+ const size_t num = Min(*remain, Size);
+ ExtractFrontPlain(*ptr, num);
+ *ptr += num;
+ *remain -= num;
+ return !*remain;
+ }
+
+ static int Compare(const TRope& x, const TRope& y) {
+ TConstIterator xIter = x.Begin(), yIter = y.Begin();
+ while (xIter.Valid() && yIter.Valid()) {
+ const size_t step = std::min(xIter.ContiguousSize(), yIter.ContiguousSize());
+ if (int res = memcmp(xIter.ContiguousData(), yIter.ContiguousData(), step)) {
+ return res;
+ }
+ xIter += step;
+ yIter += step;
+ }
+ return xIter.Valid() - yIter.Valid();
+ }
+
+ // Use this method carefully -- it may significantly reduce performance when misused.
+ TString ConvertToString() const {
+ TString res = TString::Uninitialized(GetSize());
+ Begin().ExtractPlainDataAndAdvance(res.Detach(), res.size());
+ return res;
+ }
+
+ TString DebugString() const {
+ TStringStream s;
+ s << "{Size# " << Size;
+ for (const auto& chunk : Chain) {
+ const char *data;
+ std::tie(data, std::ignore) = chunk.Backend.GetData();
+ s << " [" << chunk.Begin - data << ", " << chunk.End - data << ")@" << chunk.Backend.UniqueId();
+ }
+ s << "}";
+ return s.Str();
+ }
+
+ friend bool operator==(const TRope& x, const TRope& y) { return Compare(x, y) == 0; }
+ friend bool operator!=(const TRope& x, const TRope& y) { return Compare(x, y) != 0; }
+ friend bool operator< (const TRope& x, const TRope& y) { return Compare(x, y) < 0; }
+ friend bool operator<=(const TRope& x, const TRope& y) { return Compare(x, y) <= 0; }
+ friend bool operator> (const TRope& x, const TRope& y) { return Compare(x, y) > 0; }
+ friend bool operator>=(const TRope& x, const TRope& y) { return Compare(x, y) >= 0; }
+
+private:
+ void Cut(TIterator begin, TIterator end, TRope *target) {
+ // ensure all iterators are belong to us
+ Y_VERIFY_DEBUG(this == begin.Rope && this == end.Rope);
+
+ // if begin and end are equal, we do nothing -- checking this case allows us to find out that begin does not
+ // point to End(), for example
+ if (begin == end) {
+ return;
+ }
+
+ auto addBlock = [&](const TChunk& from, const char *begin, const char *end) {
+ if (target) {
+ target->Chain.PutToEnd(TChunk::Slice, begin, end, from);
+ target->Size += end - begin;
+ }
+ Size -= end - begin;
+ };
+
+ // consider special case -- when begin and end point to the same block; in this case we have to split up this
+ // block into two parts
+ if (begin.Iter == end.Iter) {
+ addBlock(begin.GetChunk(), begin.Ptr, end.Ptr);
+ const char *firstChunkBegin = begin.PointsToChunkMiddle() ? begin->Begin : nullptr;
+ begin->Begin = end.Ptr; // this affects both begin and end iterator pointed values
+ if (firstChunkBegin) {
+ Chain.InsertBefore(begin.Iter, TChunk::Slice, firstChunkBegin, begin.Ptr, begin.GetChunk());
+ }
+ } else {
+ // check the first iterator -- if it starts not from the begin of the block, we have to adjust end of the
+ // first block to match begin iterator and switch to next block
+ if (begin.PointsToChunkMiddle()) {
+ addBlock(begin.GetChunk(), begin.Ptr, begin->End);
+ begin->End = begin.Ptr;
+ begin.AdvanceToNextContiguousBlock();
+ }
+
+ // now drop full blocks
+ size_t rangeSize = 0;
+ for (auto it = begin.Iter; it != end.Iter; ++it) {
+ Y_VERIFY_DEBUG(it->GetSize());
+ rangeSize += it->GetSize();
+ }
+ if (rangeSize) {
+ if (target) {
+ end.Iter = target->Chain.Splice(target->Chain.end(), Chain, begin.Iter, end.Iter);
+ target->Size += rangeSize;
+ } else {
+ end.Iter = Chain.Erase(begin.Iter, end.Iter);
+ }
+ Size -= rangeSize;
+ }
+
+ // and cut the last block if necessary
+ if (end.PointsToChunkMiddle()) {
+ addBlock(end.GetChunk(), end->Begin, end.Ptr);
+ end->Begin = end.Ptr;
+ }
+ }
+
+ InvalidateIterators();
+ }
+};
+
+class TRopeArena {
+ using TAllocateCallback = std::function<TIntrusivePtr<IRopeChunkBackend>()>;
+
+ TAllocateCallback Allocator;
+ TRope Arena;
+ size_t Size = 0;
+ THashSet<const void*> AccountedBuffers;
+
+public:
+ TRopeArena(TAllocateCallback&& allocator)
+ : Allocator(std::move(allocator))
+ {}
+
+ TRope CreateRope(const void *buffer, size_t len) {
+ TRope res;
+
+ while (len) {
+ if (Arena) {
+ auto iter = Arena.Begin();
+ Y_VERIFY_DEBUG(iter.Valid());
+ char *dest = const_cast<char*>(iter.ContiguousData());
+ const size_t bytesToCopy = std::min(len, iter.ContiguousSize());
+ memcpy(dest, buffer, bytesToCopy);
+ buffer = static_cast<const char*>(buffer) + bytesToCopy;
+ len -= bytesToCopy;
+ res.Insert(res.End(), Arena.Extract(Arena.Begin(), Arena.Position(bytesToCopy)));
+ } else {
+ Arena.Insert(Arena.End(), TRope(Allocator()));
+ }
+ }
+
+ // align arena on 8-byte boundary
+ const size_t align = 8;
+ if (const size_t padding = Arena.GetSize() % align) {
+ Arena.EraseFront(padding);
+ }
+
+ return res;
+ }
+
+ size_t GetSize() const {
+ return Size;
+ }
+
+ void AccountChunk(const TRope::TChunk& chunk) {
+ if (AccountedBuffers.insert(chunk.Backend.UniqueId()).second) {
+ Size += chunk.GetCapacity();
+ }
+ }
+};
+
+struct TRopeUtils {
+ static void Memset(TRope::TConstIterator dst, char c, size_t size) {
+ while (size) {
+ Y_VERIFY_DEBUG(dst.Valid());
+ size_t len = std::min(size, dst.ContiguousSize());
+ memset(const_cast<char*>(dst.ContiguousData()), c, len);
+ dst += len;
+ size -= len;
+ }
+ }
+
+ static void Memcpy(TRope::TConstIterator dst, TRope::TConstIterator src, size_t size) {
+ while (size) {
+ Y_VERIFY_DEBUG(dst.Valid() && src.Valid(),
+ "Invalid iterator in memcpy: dst.Valid() - %" PRIu32 ", src.Valid() - %" PRIu32,
+ (ui32)dst.Valid(), (ui32)src.Valid());
+ size_t len = std::min(size, std::min(dst.ContiguousSize(), src.ContiguousSize()));
+ memcpy(const_cast<char*>(dst.ContiguousData()), src.ContiguousData(), len);
+ dst += len;
+ src += len;
+ size -= len;
+ }
+ }
+
+ static void Memcpy(TRope::TConstIterator dst, const char* src, size_t size) {
+ while (size) {
+ Y_VERIFY_DEBUG(dst.Valid());
+ size_t len = std::min(size, dst.ContiguousSize());
+ memcpy(const_cast<char*>(dst.ContiguousData()), src, len);
+ size -= len;
+ dst += len;
+ src += len;
+ }
+ }
+
+ static void Memcpy(char* dst, TRope::TConstIterator src, size_t size) {
+ while (size) {
+ Y_VERIFY_DEBUG(src.Valid());
+ size_t len = std::min(size, src.ContiguousSize());
+ memcpy(dst, src.ContiguousData(), len);
+ size -= len;
+ dst += len;
+ src += len;
+ }
+ }
+
+ // copy less or equal to sizeBound bytes, until src is valid
+ static size_t SafeMemcpy(char* dst, TRope::TIterator src, size_t sizeBound) {
+ size_t origSize = sizeBound;
+ while (sizeBound && src.Valid()) {
+ size_t len = Min(sizeBound, src.ContiguousSize());
+ memcpy(dst, src.ContiguousData(), len);
+ sizeBound -= len;
+ dst += len;
+ src += len;
+ }
+ return origSize - sizeBound;
+ }
+};
+
+template<size_t BLOCK, size_t ALIGN = 16>
+class TRopeSlideView {
+ alignas(ALIGN) char Slide[BLOCK]; // use if distance from current point and next chunk is less than BLOCK
+ TRope::TIterator Position; // current position at rope
+ size_t Size;
+ char* Head; // points to data, it might be current rope chunk or Slide
+
+private:
+ void FillBlock() {
+ size_t chunkSize = Position.ContiguousSize();
+ if (chunkSize >= BLOCK) {
+ Size = chunkSize;
+ Head = const_cast<char*>(Position.ContiguousData());
+ } else {
+ Size = TRopeUtils::SafeMemcpy(Slide, Position, BLOCK);
+ Head = Slide;
+ }
+ }
+
+public:
+ TRopeSlideView(TRope::TIterator position)
+ : Position(position)
+ {
+ FillBlock();
+ }
+
+ TRopeSlideView(TRope &rope)
+ : TRopeSlideView(rope.Begin())
+ {}
+
+ // if view on slide then copy slide to rope
+ void FlushBlock() {
+ if (Head == Slide) {
+ TRopeUtils::Memcpy(Position, Head, Size);
+ }
+ }
+
+ TRope::TIterator operator+=(size_t amount) {
+ Position += amount;
+ FillBlock();
+ return Position;
+ }
+
+ TRope::TIterator GetPosition() const {
+ return Position;
+ }
+
+ char* GetHead() const {
+ return Head;
+ }
+
+ ui8* GetUi8Head() const {
+ return reinterpret_cast<ui8*>(Head);
+ }
+
+ size_t ContiguousSize() const {
+ return Size;
+ }
+
+ bool IsOnChunk() const {
+ return Head != Slide;
+ }
+};
+
+inline TRope TRope::CopySpaceOptimized(TRope&& origin, size_t worstRatioPer1k, TRopeArena& arena) {
+ TRope res;
+ for (TChunk& chunk : origin.Chain) {
+ size_t ratio = chunk.GetSize() * 1024 / chunk.GetCapacity();
+ if (ratio < 1024 - worstRatioPer1k) {
+ res.Insert(res.End(), arena.CreateRope(chunk.Begin, chunk.GetSize()));
+ } else {
+ res.Chain.PutToEnd(std::move(chunk));
+ }
+ }
+ res.Size = origin.Size;
+ origin = TRope();
+ for (const TChunk& chunk : res.Chain) {
+ arena.AccountChunk(chunk);
+ }
+ return res;
+}
+
+
+#if defined(WITH_VALGRIND) || defined(_msan_enabled_)
+
+inline void CheckRopeIsDefined(TRope::TConstIterator begin, ui64 size) {
+ while (size) {
+ ui64 contiguousSize = Min(size, begin.ContiguousSize());
+# if defined(WITH_VALGRIND)
+ VALGRIND_CHECK_MEM_IS_DEFINED(begin.ContiguousData(), contiguousSize);
+# endif
+# if defined(_msan_enabled_)
+ NSan::CheckMemIsInitialized(begin.ContiguousData(), contiguousSize);
+# endif
+ size -= contiguousSize;
+ begin += contiguousSize;
+ }
+}
+
+# define CHECK_ROPE_IS_DEFINED(begin, size) CheckRopeIsDefined(begin, size)
+
+#else
+
+# define CHECK_ROPE_IS_DEFINED(begin, size) do {} while (false)
+
+#endif
diff --git a/library/cpp/actors/util/rope_cont_deque.h b/library/cpp/actors/util/rope_cont_deque.h
new file mode 100644
index 0000000000..d1d122c49c
--- /dev/null
+++ b/library/cpp/actors/util/rope_cont_deque.h
@@ -0,0 +1,181 @@
+#pragma once
+
+#include <library/cpp/containers/stack_vector/stack_vec.h>
+#include <deque>
+
+namespace NRopeDetails {
+
+template<typename TChunk>
+class TChunkList {
+ std::deque<TChunk> Chunks;
+
+ static constexpr size_t MaxInplaceItems = 4;
+ using TInplace = TStackVec<TChunk, MaxInplaceItems>;
+ TInplace Inplace;
+
+private:
+ template<typename TChunksIt, typename TInplaceIt, typename TValue>
+ struct TIterator {
+ TChunksIt ChunksIt;
+ TInplaceIt InplaceIt;
+
+ TIterator() = default;
+
+ TIterator(TChunksIt chunksIt, TInplaceIt inplaceIt)
+ : ChunksIt(std::move(chunksIt))
+ , InplaceIt(inplaceIt)
+ {}
+
+ template<typename A, typename B, typename C>
+ TIterator(const TIterator<A, B, C>& other)
+ : ChunksIt(other.ChunksIt)
+ , InplaceIt(other.InplaceIt)
+ {}
+
+ TIterator(const TIterator&) = default;
+ TIterator(TIterator&&) = default;
+ TIterator& operator =(const TIterator&) = default;
+ TIterator& operator =(TIterator&&) = default;
+
+ TValue& operator *() const { return InplaceIt != TInplaceIt() ? *InplaceIt : *ChunksIt; }
+ TValue* operator ->() const { return InplaceIt != TInplaceIt() ? &*InplaceIt : &*ChunksIt; }
+
+ TIterator& operator ++() {
+ if (InplaceIt != TInplaceIt()) {
+ ++InplaceIt;
+ } else {
+ ++ChunksIt;
+ }
+ return *this;
+ }
+
+ TIterator& operator --() {
+ if (InplaceIt != TInplaceIt()) {
+ --InplaceIt;
+ } else {
+ --ChunksIt;
+ }
+ return *this;
+ }
+
+ template<typename A, typename B, typename C>
+ bool operator ==(const TIterator<A, B, C>& other) const {
+ return ChunksIt == other.ChunksIt && InplaceIt == other.InplaceIt;
+ }
+
+ template<typename A, typename B, typename C>
+ bool operator !=(const TIterator<A, B, C>& other) const {
+ return ChunksIt != other.ChunksIt || InplaceIt != other.InplaceIt;
+ }
+ };
+
+public:
+ using iterator = TIterator<typename std::deque<TChunk>::iterator, typename TInplace::iterator, TChunk>;
+ using const_iterator = TIterator<typename std::deque<TChunk>::const_iterator, typename TInplace::const_iterator, const TChunk>;
+
+public:
+ TChunkList() = default;
+ TChunkList(const TChunkList& other) = default;
+ TChunkList(TChunkList&& other) = default;
+ TChunkList& operator=(const TChunkList& other) = default;
+ TChunkList& operator=(TChunkList&& other) = default;
+
+ template<typename... TArgs>
+ void PutToEnd(TArgs&&... args) {
+ InsertBefore(end(), std::forward<TArgs>(args)...);
+ }
+
+ template<typename... TArgs>
+ iterator InsertBefore(iterator pos, TArgs&&... args) {
+ if (!Inplace) {
+ pos.InplaceIt = Inplace.end();
+ }
+ if (Chunks.empty() && Inplace.size() < MaxInplaceItems) {
+ return {{}, Inplace.emplace(pos.InplaceIt, std::forward<TArgs>(args)...)};
+ } else {
+ if (Inplace) {
+ Y_VERIFY_DEBUG(Chunks.empty());
+ for (auto& item : Inplace) {
+ Chunks.push_back(std::move(item));
+ }
+ pos.ChunksIt = pos.InplaceIt - Inplace.begin() + Chunks.begin();
+ Inplace.clear();
+ }
+ return {Chunks.emplace(pos.ChunksIt, std::forward<TArgs>(args)...), {}};
+ }
+ }
+
+ iterator Erase(iterator pos) {
+ if (Inplace) {
+ return {{}, Inplace.erase(pos.InplaceIt)};
+ } else {
+ return {Chunks.erase(pos.ChunksIt), {}};
+ }
+ }
+
+ iterator Erase(iterator first, iterator last) {
+ if (Inplace) {
+ return {{}, Inplace.erase(first.InplaceIt, last.InplaceIt)};
+ } else {
+ return {Chunks.erase(first.ChunksIt, last.ChunksIt), {}};
+ }
+ }
+
+ void EraseFront() {
+ if (Inplace) {
+ Inplace.erase(Inplace.begin());
+ } else {
+ Chunks.pop_front();
+ }
+ }
+
+ void EraseBack() {
+ if (Inplace) {
+ Inplace.pop_back();
+ } else {
+ Chunks.pop_back();
+ }
+ }
+
+ iterator Splice(iterator pos, TChunkList& from, iterator first, iterator last) {
+ if (!Inplace) {
+ pos.InplaceIt = Inplace.end();
+ }
+ size_t n = 0;
+ for (auto it = first; it != last; ++it, ++n)
+ {}
+ if (Chunks.empty() && Inplace.size() + n <= MaxInplaceItems) {
+ if (first.InplaceIt != typename TInplace::iterator()) {
+ Inplace.insert(pos.InplaceIt, first.InplaceIt, last.InplaceIt);
+ } else {
+ Inplace.insert(pos.InplaceIt, first.ChunksIt, last.ChunksIt);
+ }
+ } else {
+ if (Inplace) {
+ Y_VERIFY_DEBUG(Chunks.empty());
+ for (auto& item : Inplace) {
+ Chunks.push_back(std::move(item));
+ }
+ pos.ChunksIt = pos.InplaceIt - Inplace.begin() + Chunks.begin();
+ Inplace.clear();
+ }
+ if (first.InplaceIt != typename TInplace::iterator()) {
+ Chunks.insert(pos.ChunksIt, first.InplaceIt, last.InplaceIt);
+ } else {
+ Chunks.insert(pos.ChunksIt, first.ChunksIt, last.ChunksIt);
+ }
+ }
+ return from.Erase(first, last);
+ }
+
+ operator bool() const { return !Inplace.empty() || !Chunks.empty(); }
+ TChunk& GetFirstChunk() { return Inplace ? Inplace.front() : Chunks.front(); }
+ const TChunk& GetFirstChunk() const { return Inplace ? Inplace.front() : Chunks.front(); }
+ TChunk& GetLastChunk() { return Inplace ? Inplace.back() : Chunks.back(); }
+ iterator begin() { return {Chunks.begin(), Inplace ? Inplace.begin() : typename TInplace::iterator()}; }
+ const_iterator begin() const { return {Chunks.begin(), Inplace ? Inplace.begin() : typename TInplace::const_iterator()}; }
+ iterator end() { return {Chunks.end(), Inplace ? Inplace.end() : typename TInplace::iterator()}; }
+ const_iterator end() const { return {Chunks.end(), Inplace ? Inplace.end() : typename TInplace::const_iterator()}; }
+};
+
+} // NRopeDetails
diff --git a/library/cpp/actors/util/rope_cont_list.h b/library/cpp/actors/util/rope_cont_list.h
new file mode 100644
index 0000000000..18c136284e
--- /dev/null
+++ b/library/cpp/actors/util/rope_cont_list.h
@@ -0,0 +1,159 @@
+#pragma once
+
+#include <util/generic/intrlist.h>
+
+namespace NRopeDetails {
+
+template<typename TChunk>
+class TChunkList {
+ struct TItem : TIntrusiveListItem<TItem>, TChunk {
+ // delegating constructor
+ template<typename... TArgs> TItem(TArgs&&... args) : TChunk(std::forward<TArgs>(args)...) {}
+ };
+
+ using TList = TIntrusiveList<TItem>;
+ TList List;
+
+ static constexpr size_t NumInplaceItems = 2;
+ char InplaceItems[sizeof(TItem) * NumInplaceItems];
+
+ template<typename... TArgs>
+ TItem *AllocateItem(TArgs&&... args) {
+ for (size_t index = 0; index < NumInplaceItems; ++index) {
+ TItem *chunk = GetInplaceItemPtr(index);
+ if (!TItem::IsInUse(*chunk)) {
+ return new(chunk) TItem(std::forward<TArgs>(args)...);
+ }
+ }
+ return new TItem(std::forward<TArgs>(args)...);
+ }
+
+ void ReleaseItem(TItem *chunk) {
+ if (IsInplaceItem(chunk)) {
+ chunk->~TItem();
+ TItem::Clear(*chunk);
+ } else {
+ delete chunk;
+ }
+ }
+
+ void ReleaseItems(TList& list) {
+ while (list) {
+ ReleaseItem(list.Front());
+ }
+ }
+
+ void Prepare() {
+ for (size_t index = 0; index < NumInplaceItems; ++index) {
+ TItem::Clear(*GetInplaceItemPtr(index));
+ }
+ }
+
+ TItem *GetInplaceItemPtr(size_t index) { return reinterpret_cast<TItem*>(InplaceItems + index * sizeof(TItem)); }
+ bool IsInplaceItem(TItem *chunk) { return chunk >= GetInplaceItemPtr(0) && chunk < GetInplaceItemPtr(NumInplaceItems); }
+
+public:
+ using iterator = typename TList::iterator;
+ using const_iterator = typename TList::const_iterator;
+
+public:
+ TChunkList() {
+ Prepare();
+ }
+
+ ~TChunkList() {
+ ReleaseItems(List);
+#ifndef NDEBUG
+ for (size_t index = 0; index < NumInplaceItems; ++index) {
+ Y_VERIFY(!TItem::IsInUse(*GetInplaceItemPtr(index)));
+ }
+#endif
+ }
+
+ TChunkList(const TChunkList& other) {
+ Prepare();
+ for (const TItem& chunk : other.List) {
+ PutToEnd(TChunk(chunk));
+ }
+ }
+
+ TChunkList(TChunkList&& other) {
+ Prepare();
+ Splice(end(), other, other.begin(), other.end());
+ }
+
+ TChunkList& operator=(const TChunkList& other) {
+ if (this != &other) {
+ ReleaseItems(List);
+ for (const TItem& chunk : other.List) {
+ PutToEnd(TChunk(chunk));
+ }
+ }
+ return *this;
+ }
+
+ TChunkList& operator=(TChunkList&& other) {
+ if (this != &other) {
+ ReleaseItems(List);
+ Splice(end(), other, other.begin(), other.end());
+ }
+ return *this;
+ }
+
+ template<typename... TArgs>
+ void PutToEnd(TArgs&&... args) {
+ InsertBefore(end(), std::forward<TArgs>(args)...);
+ }
+
+ template<typename... TArgs>
+ iterator InsertBefore(iterator pos, TArgs&&... args) {
+ TItem *item = AllocateItem<TArgs...>(std::forward<TArgs>(args)...);
+ item->LinkBefore(pos.Item());
+ return item;
+ }
+
+ iterator Erase(iterator pos) {
+ ReleaseItem(&*pos++);
+ return pos;
+ }
+
+ iterator Erase(iterator first, iterator last) {
+ TList temp;
+ TList::Cut(first, last, temp.end());
+ ReleaseItems(temp);
+ return last;
+ }
+
+ void EraseFront() {
+ ReleaseItem(List.PopFront());
+ }
+
+ void EraseBack() {
+ ReleaseItem(List.PopBack());
+ }
+
+ iterator Splice(iterator pos, TChunkList& from, iterator first, iterator last) {
+ for (auto it = first; it != last; ) {
+ if (from.IsInplaceItem(&*it)) {
+ TList::Cut(first, it, pos);
+ InsertBefore(pos, std::move(*it));
+ it = first = from.Erase(it);
+ } else {
+ ++it;
+ }
+ }
+ TList::Cut(first, last, pos);
+ return last;
+ }
+
+ operator bool() const { return static_cast<bool>(List); }
+ TChunk& GetFirstChunk() { return *List.Front(); }
+ const TChunk& GetFirstChunk() const { return *List.Front(); }
+ TChunk& GetLastChunk() { return *List.Back(); }
+ iterator begin() { return List.begin(); }
+ const_iterator begin() const { return List.begin(); }
+ iterator end() { return List.end(); }
+ const_iterator end() const { return List.end(); }
+};
+
+} // NRopeDetails
diff --git a/library/cpp/actors/util/rope_ut.cpp b/library/cpp/actors/util/rope_ut.cpp
new file mode 100644
index 0000000000..cabeed9230
--- /dev/null
+++ b/library/cpp/actors/util/rope_ut.cpp
@@ -0,0 +1,231 @@
+#include "rope.h"
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/random/random.h>
+
+class TRopeStringBackend : public IRopeChunkBackend {
+ TString Buffer;
+
+public:
+ TRopeStringBackend(TString buffer)
+ : Buffer(std::move(buffer))
+ {}
+
+ TData GetData() const override {
+ return {Buffer.data(), Buffer.size()};
+ }
+
+ size_t GetCapacity() const override {
+ return Buffer.capacity();
+ }
+};
+
+TRope CreateRope(TString s, size_t sliceSize) {
+ TRope res;
+ for (size_t i = 0; i < s.size(); ) {
+ size_t len = std::min(sliceSize, s.size() - i);
+ if (i % 2) {
+ res.Insert(res.End(), TRope(MakeIntrusive<TRopeStringBackend>(s.substr(i, len))));
+ } else {
+ res.Insert(res.End(), TRope(s.substr(i, len)));
+ }
+ i += len;
+ }
+ return res;
+}
+
+TString RopeToString(const TRope& rope) {
+ TString res;
+ auto iter = rope.Begin();
+ while (iter != rope.End()) {
+ res.append(iter.ContiguousData(), iter.ContiguousSize());
+ iter.AdvanceToNextContiguousBlock();
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(rope.GetSize(), res.size());
+
+ TString temp = TString::Uninitialized(rope.GetSize());
+ rope.Begin().ExtractPlainDataAndAdvance(temp.Detach(), temp.size());
+ UNIT_ASSERT_VALUES_EQUAL(temp, res);
+
+ return res;
+}
+
+TString Text = "No elements are copied or moved, only the internal pointers of the list nodes are re-pointed.";
+
+Y_UNIT_TEST_SUITE(TRope) {
+
+ Y_UNIT_TEST(Leak) {
+ const size_t begin = 10, end = 20;
+ TRope rope = CreateRope(Text, 10);
+ rope.Erase(rope.Begin() + begin, rope.Begin() + end);
+ }
+
+ Y_UNIT_TEST(BasicRange) {
+ TRope rope = CreateRope(Text, 10);
+ for (size_t begin = 0; begin < Text.size(); ++begin) {
+ for (size_t end = begin; end <= Text.size(); ++end) {
+ TRope::TIterator rBegin = rope.Begin() + begin;
+ TRope::TIterator rEnd = rope.Begin() + end;
+ UNIT_ASSERT_VALUES_EQUAL(RopeToString(TRope(rBegin, rEnd)), Text.substr(begin, end - begin));
+ }
+ }
+ }
+
+ Y_UNIT_TEST(Erase) {
+ for (size_t begin = 0; begin < Text.size(); ++begin) {
+ for (size_t end = begin; end <= Text.size(); ++end) {
+ TRope rope = CreateRope(Text, 10);
+ rope.Erase(rope.Begin() + begin, rope.Begin() + end);
+ TString text = Text;
+ text.erase(text.begin() + begin, text.begin() + end);
+ UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), text);
+ }
+ }
+ }
+
+ Y_UNIT_TEST(Insert) {
+ TRope rope = CreateRope(Text, 10);
+ for (size_t begin = 0; begin < Text.size(); ++begin) {
+ for (size_t end = begin; end <= Text.size(); ++end) {
+ TRope part = TRope(rope.Begin() + begin, rope.Begin() + end);
+ for (size_t where = 0; where <= Text.size(); ++where) {
+ TRope x(rope);
+ x.Insert(x.Begin() + where, TRope(part));
+ UNIT_ASSERT_VALUES_EQUAL(x.GetSize(), rope.GetSize() + part.GetSize());
+ TString text = Text;
+ text.insert(text.begin() + where, Text.begin() + begin, Text.begin() + end);
+ UNIT_ASSERT_VALUES_EQUAL(RopeToString(x), text);
+ }
+ }
+ }
+ }
+
+ Y_UNIT_TEST(Extract) {
+ for (size_t begin = 0; begin < Text.size(); ++begin) {
+ for (size_t end = begin; end <= Text.size(); ++end) {
+ TRope rope = CreateRope(Text, 10);
+ TRope part = rope.Extract(rope.Begin() + begin, rope.Begin() + end);
+ TString text = Text;
+ text.erase(text.begin() + begin, text.begin() + end);
+ UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), text);
+ UNIT_ASSERT_VALUES_EQUAL(RopeToString(part), Text.substr(begin, end - begin));
+ }
+ }
+ }
+
+ Y_UNIT_TEST(EraseFront) {
+ for (size_t pos = 0; pos <= Text.size(); ++pos) {
+ TRope rope = CreateRope(Text, 10);
+ rope.EraseFront(pos);
+ UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text.substr(pos));
+ }
+ }
+
+ Y_UNIT_TEST(EraseBack) {
+ for (size_t pos = 0; pos <= Text.size(); ++pos) {
+ TRope rope = CreateRope(Text, 10);
+ rope.EraseBack(pos);
+ UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text.substr(0, Text.size() - pos));
+ }
+ }
+
+ Y_UNIT_TEST(ExtractFront) {
+ for (size_t step = 1; step <= Text.size(); ++step) {
+ TRope rope = CreateRope(Text, 10);
+ TRope out;
+ while (const size_t len = Min(step, rope.GetSize())) {
+ rope.ExtractFront(len, &out);
+ UNIT_ASSERT(rope.GetSize() + out.GetSize() == Text.size());
+ UNIT_ASSERT_VALUES_EQUAL(RopeToString(out), Text.substr(0, out.GetSize()));
+ }
+ }
+ }
+
+ Y_UNIT_TEST(ExtractFrontPlain) {
+ for (size_t step = 1; step <= Text.size(); ++step) {
+ TRope rope = CreateRope(Text, 10);
+ TString buffer = Text;
+ auto it = rope.Begin();
+ size_t remain = rope.GetSize();
+ while (const size_t len = Min(step, remain)) {
+ TString data = TString::Uninitialized(len);
+ it.ExtractPlainDataAndAdvance(data.Detach(), data.size());
+ UNIT_ASSERT_VALUES_EQUAL(data, buffer.substr(0, len));
+ UNIT_ASSERT_VALUES_EQUAL(RopeToString(TRope(it, rope.End())), buffer.substr(len));
+ buffer = buffer.substr(len);
+ remain -= len;
+ }
+ }
+ }
+
+ Y_UNIT_TEST(FetchFrontPlain) {
+ char s[10];
+ char *data = s;
+ size_t remain = sizeof(s);
+ TRope rope = TRope(TString("HELLO"));
+ UNIT_ASSERT(!rope.FetchFrontPlain(&data, &remain));
+ UNIT_ASSERT(!rope);
+ rope.Insert(rope.End(), TRope(TString("WORLD!!!")));
+ UNIT_ASSERT(rope.FetchFrontPlain(&data, &remain));
+ UNIT_ASSERT(!remain);
+ UNIT_ASSERT(rope.GetSize() == 3);
+ UNIT_ASSERT_VALUES_EQUAL(rope.ConvertToString(), "!!!");
+ UNIT_ASSERT(!strncmp(s, "HELLOWORLD", 10));
+ }
+
+ Y_UNIT_TEST(Glueing) {
+ TRope rope = CreateRope(Text, 10);
+ for (size_t begin = 0; begin <= Text.size(); ++begin) {
+ for (size_t end = begin; end <= Text.size(); ++end) {
+ TString repr = rope.DebugString();
+ TRope temp = rope.Extract(rope.Position(begin), rope.Position(end));
+ rope.Insert(rope.Position(begin), std::move(temp));
+ UNIT_ASSERT_VALUES_EQUAL(repr, rope.DebugString());
+ UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text);
+ }
+ }
+ }
+
+ Y_UNIT_TEST(IterWalk) {
+ TRope rope = CreateRope(Text, 10);
+ for (size_t step1 = 0; step1 <= rope.GetSize(); ++step1) {
+ for (size_t step2 = 0; step2 <= step1; ++step2) {
+ TRope::TConstIterator iter = rope.Begin();
+ iter += step1;
+ iter -= step2;
+ UNIT_ASSERT(iter == rope.Position(step1 - step2));
+ }
+ }
+ }
+
+ Y_UNIT_TEST(Compare) {
+ auto check = [](const TString& x, const TString& y) {
+ const TRope xRope = CreateRope(x, 7);
+ const TRope yRope = CreateRope(y, 11);
+ UNIT_ASSERT_VALUES_EQUAL(xRope == yRope, x == y);
+ UNIT_ASSERT_VALUES_EQUAL(xRope != yRope, x != y);
+ UNIT_ASSERT_VALUES_EQUAL(xRope < yRope, x < y);
+ UNIT_ASSERT_VALUES_EQUAL(xRope <= yRope, x <= y);
+ UNIT_ASSERT_VALUES_EQUAL(xRope > yRope, x > y);
+ UNIT_ASSERT_VALUES_EQUAL(xRope >= yRope, x >= y);
+ };
+
+ TVector<TString> pool;
+ for (size_t k = 0; k < 10; ++k) {
+ size_t len = RandomNumber<size_t>(100) + 100;
+ TString s = TString::Uninitialized(len);
+ char *p = s.Detach();
+ for (size_t j = 0; j < len; ++j) {
+ *p++ = RandomNumber<unsigned char>();
+ }
+ pool.push_back(std::move(s));
+ }
+
+ for (const TString& x : pool) {
+ for (const TString& y : pool) {
+ check(x, y);
+ }
+ }
+ }
+
+}
diff --git a/library/cpp/actors/util/should_continue.cpp b/library/cpp/actors/util/should_continue.cpp
new file mode 100644
index 0000000000..258e6a0aff
--- /dev/null
+++ b/library/cpp/actors/util/should_continue.cpp
@@ -0,0 +1,23 @@
+#include "should_continue.h"
+
+void TProgramShouldContinue::ShouldRestart() {
+ AtomicSet(State, Restart);
+}
+
+void TProgramShouldContinue::ShouldStop(int returnCode) {
+ AtomicSet(ReturnCode, returnCode);
+ AtomicSet(State, Stop);
+}
+
+TProgramShouldContinue::EState TProgramShouldContinue::PollState() {
+ return static_cast<EState>(AtomicGet(State));
+}
+
+int TProgramShouldContinue::GetReturnCode() {
+ return static_cast<int>(AtomicGet(ReturnCode));
+}
+
+void TProgramShouldContinue::Reset() {
+ AtomicSet(ReturnCode, 0);
+ AtomicSet(State, Continue);
+}
diff --git a/library/cpp/actors/util/should_continue.h b/library/cpp/actors/util/should_continue.h
new file mode 100644
index 0000000000..76acc40dc4
--- /dev/null
+++ b/library/cpp/actors/util/should_continue.h
@@ -0,0 +1,22 @@
+#pragma once
+#include "defs.h"
+
+class TProgramShouldContinue {
+public:
+ enum EState {
+ Continue,
+ Stop,
+ Restart,
+ };
+
+ void ShouldRestart();
+ void ShouldStop(int returnCode = 0);
+
+ EState PollState();
+ int GetReturnCode();
+
+ void Reset();
+private:
+ TAtomic ReturnCode = 0;
+ TAtomic State = Continue;
+};
diff --git a/library/cpp/actors/util/thread.h b/library/cpp/actors/util/thread.h
new file mode 100644
index 0000000000..d742c8c585
--- /dev/null
+++ b/library/cpp/actors/util/thread.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+#include <util/stream/str.h>
+#include <util/system/execpath.h>
+#include <util/system/thread.h>
+#include <util/system/thread.h>
+#include <time.h>
+
+inline void SetCurrentThreadName(const TString& name,
+ const ui32 maxCharsFromProcessName = 8) {
+#if defined(_linux_)
+ // linux limits threadname by 15 + \0
+
+ TStringBuf procName(GetExecPath());
+ procName = procName.RNextTok('/');
+ procName = procName.SubStr(0, maxCharsFromProcessName);
+
+ TStringStream linuxName;
+ linuxName << procName << "." << name;
+ TThread::SetCurrentThreadName(linuxName.Str().data());
+#else
+ Y_UNUSED(maxCharsFromProcessName);
+ TThread::SetCurrentThreadName(name.data());
+#endif
+}
diff --git a/library/cpp/actors/util/threadparkpad.cpp b/library/cpp/actors/util/threadparkpad.cpp
new file mode 100644
index 0000000000..74069ff15b
--- /dev/null
+++ b/library/cpp/actors/util/threadparkpad.cpp
@@ -0,0 +1,148 @@
+#include "threadparkpad.h"
+#include <util/system/winint.h>
+
+#ifdef _linux_
+
+#include "futex.h"
+
+namespace NActors {
+ class TThreadParkPad::TImpl {
+ volatile bool Interrupted;
+ int Futex;
+
+ public:
+ TImpl()
+ : Interrupted(false)
+ , Futex(0)
+ {
+ }
+ ~TImpl() {
+ }
+
+ bool Park() noexcept {
+ __atomic_fetch_sub(&Futex, 1, __ATOMIC_SEQ_CST);
+ while (__atomic_load_n(&Futex, __ATOMIC_ACQUIRE) == -1)
+ SysFutex(&Futex, FUTEX_WAIT_PRIVATE, -1, nullptr, nullptr, 0);
+ return IsInterrupted();
+ }
+
+ void Unpark() noexcept {
+ const int old = __atomic_fetch_add(&Futex, 1, __ATOMIC_SEQ_CST);
+ if (old == -1)
+ SysFutex(&Futex, FUTEX_WAKE_PRIVATE, -1, nullptr, nullptr, 0);
+ }
+
+ void Interrupt() noexcept {
+ __atomic_store_n(&Interrupted, true, __ATOMIC_SEQ_CST);
+ Unpark();
+ }
+
+ bool IsInterrupted() const noexcept {
+ return __atomic_load_n(&Interrupted, __ATOMIC_ACQUIRE);
+ }
+ };
+
+#elif defined _win32_
+#include <util/generic/bt_exception.h>
+#include <util/generic/yexception.h>
+
+namespace NActors {
+ class TThreadParkPad::TImpl {
+ TAtomic Interrupted;
+ HANDLE EvHandle;
+
+ public:
+ TImpl()
+ : Interrupted(false)
+ {
+ EvHandle = ::CreateEvent(0, false, false, 0);
+ if (!EvHandle)
+ ythrow TWithBackTrace<yexception>() << "::CreateEvent failed";
+ }
+ ~TImpl() {
+ if (EvHandle)
+ ::CloseHandle(EvHandle);
+ }
+
+ bool Park() noexcept {
+ ::WaitForSingleObject(EvHandle, INFINITE);
+ return AtomicGet(Interrupted);
+ }
+
+ void Unpark() noexcept {
+ ::SetEvent(EvHandle);
+ }
+
+ void Interrupt() noexcept {
+ AtomicSet(Interrupted, true);
+ Unpark();
+ }
+
+ bool IsInterrupted() const noexcept {
+ return AtomicGet(Interrupted);
+ }
+ };
+
+#else
+
+#include <util/system/event.h>
+
+namespace NActors {
+ class TThreadParkPad::TImpl {
+ TAtomic Interrupted;
+ TSystemEvent Ev;
+
+ public:
+ TImpl()
+ : Interrupted(false)
+ , Ev(TSystemEvent::rAuto)
+ {
+ }
+ ~TImpl() {
+ }
+
+ bool Park() noexcept {
+ Ev.Wait();
+ return AtomicGet(Interrupted);
+ }
+
+ void Unpark() noexcept {
+ Ev.Signal();
+ }
+
+ void Interrupt() noexcept {
+ AtomicSet(Interrupted, true);
+ Unpark();
+ }
+
+ bool IsInterrupted() const noexcept {
+ return AtomicGet(Interrupted);
+ }
+ };
+#endif
+
+ TThreadParkPad::TThreadParkPad()
+ : Impl(new TThreadParkPad::TImpl())
+ {
+ }
+
+ TThreadParkPad::~TThreadParkPad() {
+ }
+
+ bool TThreadParkPad::Park() noexcept {
+ return Impl->Park();
+ }
+
+ void TThreadParkPad::Unpark() noexcept {
+ Impl->Unpark();
+ }
+
+ void TThreadParkPad::Interrupt() noexcept {
+ Impl->Interrupt();
+ }
+
+ bool TThreadParkPad::Interrupted() const noexcept {
+ return Impl->IsInterrupted();
+ }
+
+}
diff --git a/library/cpp/actors/util/threadparkpad.h b/library/cpp/actors/util/threadparkpad.h
new file mode 100644
index 0000000000..5b574ccf34
--- /dev/null
+++ b/library/cpp/actors/util/threadparkpad.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+
+namespace NActors {
+ class TThreadParkPad {
+ private:
+ class TImpl;
+ THolder<TImpl> Impl;
+
+ public:
+ TThreadParkPad();
+ ~TThreadParkPad();
+
+ bool Park() noexcept;
+ void Unpark() noexcept;
+ void Interrupt() noexcept;
+ bool Interrupted() const noexcept;
+ };
+
+}
diff --git a/library/cpp/actors/util/ticket_lock.h b/library/cpp/actors/util/ticket_lock.h
new file mode 100644
index 0000000000..3b1fa80393
--- /dev/null
+++ b/library/cpp/actors/util/ticket_lock.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include "intrinsics.h"
+#include <util/system/guard.h>
+#include <util/system/yassert.h>
+
+class TTicketLock : TNonCopyable {
+ ui32 TicketIn;
+ ui32 TicketOut;
+
+public:
+ TTicketLock()
+ : TicketIn(0)
+ , TicketOut(0)
+ {
+ }
+
+ void Release() noexcept {
+ AtomicUi32Increment(&TicketOut);
+ }
+
+ ui32 Acquire() noexcept {
+ ui32 revolves = 0;
+ const ui32 ticket = AtomicUi32Increment(&TicketIn) - 1;
+ while (ticket != AtomicLoad(&TicketOut)) {
+ Y_VERIFY_DEBUG(ticket >= AtomicLoad(&TicketOut));
+ SpinLockPause();
+ ++revolves;
+ }
+ return revolves;
+ }
+
+ bool TryAcquire() noexcept {
+ const ui32 x = AtomicLoad(&TicketOut);
+ if (x == AtomicLoad(&TicketIn) && AtomicUi32Cas(&TicketIn, x + 1, x))
+ return true;
+ else
+ return false;
+ }
+
+ bool IsLocked() noexcept {
+ const ui32 ticketIn = AtomicLoad(&TicketIn);
+ const ui32 ticketOut = AtomicLoad(&TicketOut);
+ return (ticketIn != ticketOut);
+ }
+
+ typedef ::TGuard<TTicketLock> TGuard;
+};
diff --git a/library/cpp/actors/util/timerfd.h b/library/cpp/actors/util/timerfd.h
new file mode 100644
index 0000000000..3189e2a672
--- /dev/null
+++ b/library/cpp/actors/util/timerfd.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include "datetime.h"
+
+#include <util/generic/noncopyable.h>
+
+#ifdef _linux_
+
+#include <util/system/yassert.h>
+#include <errno.h>
+#include <sys/timerfd.h>
+
+struct TTimerFd: public TNonCopyable {
+ int Fd;
+
+ TTimerFd() {
+ Fd = timerfd_create(CLOCK_MONOTONIC, 0);
+ Y_VERIFY(Fd != -1, "timerfd_create(CLOCK_MONOTONIC, 0) -> -1; errno:%d: %s", int(errno), strerror(errno));
+ }
+
+ ~TTimerFd() {
+ close(Fd);
+ }
+
+ void Set(ui64 ts) {
+ ui64 now = GetCycleCountFast();
+ Arm(now >= ts? 1: NHPTimer::GetSeconds(ts - now) * 1e9);
+ }
+
+ void Reset() {
+ Arm(0); // disarm timer
+ }
+
+ void Wait() {
+ ui64 expirations;
+ ssize_t s = read(Fd, &expirations, sizeof(ui64));
+ Y_UNUSED(s); // Y_VERIFY(s == sizeof(ui64));
+ }
+
+ void Wake() {
+ Arm(1);
+ }
+private:
+ void Arm(ui64 ns) {
+ struct itimerspec spec;
+ spec.it_value.tv_sec = ns / 1'000'000'000;
+ spec.it_value.tv_nsec = ns % 1'000'000'000;
+ spec.it_interval.tv_sec = 0;
+ spec.it_interval.tv_nsec = 0;
+ int ret = timerfd_settime(Fd, 0, &spec, nullptr);
+ Y_VERIFY(ret != -1, "timerfd_settime(%d, 0, %" PRIu64 "ns, 0) -> %d; errno:%d: %s", Fd, ns, ret, int(errno), strerror(errno));
+ }
+};
+
+#else
+
+struct TTimerFd: public TNonCopyable {
+ int Fd = 0;
+ void Set(ui64) {}
+ void Reset() {}
+ void Wait() {}
+ void Wake() {}
+};
+
+#endif
diff --git a/library/cpp/actors/util/unordered_cache.h b/library/cpp/actors/util/unordered_cache.h
new file mode 100644
index 0000000000..76f036c0cf
--- /dev/null
+++ b/library/cpp/actors/util/unordered_cache.h
@@ -0,0 +1,201 @@
+#pragma once
+
+#include "defs.h"
+#include "queue_chunk.h"
+
+template <typename T, ui32 Size = 512, ui32 ConcurrencyFactor = 1, typename TChunk = TQueueChunk<T, Size>>
+class TUnorderedCache : TNonCopyable {
+ static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value");
+
+public:
+ static constexpr ui32 Concurrency = ConcurrencyFactor * 4;
+
+private:
+ struct TReadSlot {
+ TChunk* volatile ReadFrom;
+ volatile ui32 ReadPosition;
+ char Padding[64 - sizeof(TChunk*) - sizeof(ui32)]; // 1 slot per cache line
+ };
+
+ struct TWriteSlot {
+ TChunk* volatile WriteTo;
+ volatile ui32 WritePosition;
+ char Padding[64 - sizeof(TChunk*) - sizeof(ui32)]; // 1 slot per cache line
+ };
+
+ static_assert(sizeof(TReadSlot) == 64, "expect sizeof(TReadSlot) == 64");
+ static_assert(sizeof(TWriteSlot) == 64, "expect sizeof(TWriteSlot) == 64");
+
+private:
+ TReadSlot ReadSlots[Concurrency];
+ TWriteSlot WriteSlots[Concurrency];
+
+ static_assert(sizeof(TChunk*) == sizeof(TAtomic), "expect sizeof(TChunk*) == sizeof(TAtomic)");
+
+private:
+ struct TLockedWriter {
+ TWriteSlot* Slot;
+ TChunk* WriteTo;
+
+ TLockedWriter()
+ : Slot(nullptr)
+ , WriteTo(nullptr)
+ { }
+
+ TLockedWriter(TWriteSlot* slot, TChunk* writeTo)
+ : Slot(slot)
+ , WriteTo(writeTo)
+ { }
+
+ ~TLockedWriter() noexcept {
+ Drop();
+ }
+
+ void Drop() {
+ if (Slot) {
+ AtomicStore(&Slot->WriteTo, WriteTo);
+ Slot = nullptr;
+ }
+ }
+
+ TLockedWriter(const TLockedWriter&) = delete;
+ TLockedWriter& operator=(const TLockedWriter&) = delete;
+
+ TLockedWriter(TLockedWriter&& rhs)
+ : Slot(rhs.Slot)
+ , WriteTo(rhs.WriteTo)
+ {
+ rhs.Slot = nullptr;
+ }
+
+ TLockedWriter& operator=(TLockedWriter&& rhs) {
+ if (Y_LIKELY(this != &rhs)) {
+ Drop();
+ Slot = rhs.Slot;
+ WriteTo = rhs.WriteTo;
+ rhs.Slot = nullptr;
+ }
+ return *this;
+ }
+ };
+
+private:
+ TLockedWriter LockWriter(ui64 writerRotation) {
+ ui32 cycle = 0;
+ for (;;) {
+ TWriteSlot* slot = &WriteSlots[writerRotation % Concurrency];
+ if (AtomicLoad(&slot->WriteTo) != nullptr) {
+ if (TChunk* writeTo = AtomicSwap(&slot->WriteTo, nullptr)) {
+ return TLockedWriter(slot, writeTo);
+ }
+ }
+ ++writerRotation;
+
+ // Do a spinlock pause after a full cycle
+ if (++cycle == Concurrency) {
+ SpinLockPause();
+ cycle = 0;
+ }
+ }
+ }
+
+ void WriteOne(TLockedWriter& lock, T x) {
+ Y_VERIFY_DEBUG(x != 0);
+
+ const ui32 pos = AtomicLoad(&lock.Slot->WritePosition);
+ if (pos != TChunk::EntriesCount) {
+ AtomicStore(&lock.Slot->WritePosition, pos + 1);
+ AtomicStore(&lock.WriteTo->Entries[pos], x);
+ } else {
+ TChunk* next = new TChunk();
+ AtomicStore(&next->Entries[0], x);
+ AtomicStore(&lock.Slot->WritePosition, 1u);
+ AtomicStore(&lock.WriteTo->Next, next);
+ lock.WriteTo = next;
+ }
+ }
+
+public:
+ TUnorderedCache() {
+ for (ui32 i = 0; i < Concurrency; ++i) {
+ ReadSlots[i].ReadFrom = new TChunk();
+ ReadSlots[i].ReadPosition = 0;
+
+ WriteSlots[i].WriteTo = ReadSlots[i].ReadFrom;
+ WriteSlots[i].WritePosition = 0;
+ }
+ }
+
+ ~TUnorderedCache() {
+ Y_VERIFY(!Pop(0));
+
+ for (ui64 i = 0; i < Concurrency; ++i) {
+ if (ReadSlots[i].ReadFrom) {
+ delete ReadSlots[i].ReadFrom;
+ ReadSlots[i].ReadFrom = nullptr;
+ }
+ WriteSlots[i].WriteTo = nullptr;
+ }
+ }
+
+ T Pop(ui64 readerRotation) noexcept {
+ ui64 readerIndex = readerRotation;
+ const ui64 endIndex = readerIndex + Concurrency;
+ for (; readerIndex != endIndex; ++readerIndex) {
+ TReadSlot* slot = &ReadSlots[readerIndex % Concurrency];
+ if (AtomicLoad(&slot->ReadFrom) != nullptr) {
+ if (TChunk* readFrom = AtomicSwap(&slot->ReadFrom, nullptr)) {
+ const ui32 pos = AtomicLoad(&slot->ReadPosition);
+ if (pos != TChunk::EntriesCount) {
+ if (T ret = AtomicLoad(&readFrom->Entries[pos])) {
+ AtomicStore(&slot->ReadPosition, pos + 1);
+ AtomicStore(&slot->ReadFrom, readFrom); // release lock with same chunk
+ return ret; // found, return
+ } else {
+ AtomicStore(&slot->ReadFrom, readFrom); // release lock with same chunk
+ }
+ } else if (TChunk* next = AtomicLoad(&readFrom->Next)) {
+ if (T ret = AtomicLoad(&next->Entries[0])) {
+ AtomicStore(&slot->ReadPosition, 1u);
+ AtomicStore(&slot->ReadFrom, next); // release lock with next chunk
+ delete readFrom;
+ return ret;
+ } else {
+ AtomicStore(&slot->ReadPosition, 0u);
+ AtomicStore(&slot->ReadFrom, next); // release lock with new chunk
+ delete readFrom;
+ }
+ } else {
+ // nothing in old chunk and no next chunk, just release lock with old chunk
+ AtomicStore(&slot->ReadFrom, readFrom);
+ }
+ }
+ }
+ }
+
+ return 0; // got nothing after full cycle, return
+ }
+
+ void Push(T x, ui64 writerRotation) {
+ TLockedWriter lock = LockWriter(writerRotation);
+ WriteOne(lock, x);
+ }
+
+ void PushBulk(T* x, ui32 xcount, ui64 writerRotation) {
+ for (;;) {
+ // Fill no more then one queue chunk per round
+ const ui32 xround = Min(xcount, (ui32)TChunk::EntriesCount);
+
+ {
+ TLockedWriter lock = LockWriter(writerRotation++);
+ for (T* end = x + xround; x != end; ++x)
+ WriteOne(lock, *x);
+ }
+
+ if (xcount <= TChunk::EntriesCount)
+ break;
+
+ xcount -= TChunk::EntriesCount;
+ }
+ }
+};
diff --git a/library/cpp/actors/util/unordered_cache_ut.cpp b/library/cpp/actors/util/unordered_cache_ut.cpp
new file mode 100644
index 0000000000..37865f2f91
--- /dev/null
+++ b/library/cpp/actors/util/unordered_cache_ut.cpp
@@ -0,0 +1,138 @@
+#include "unordered_cache.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/random/random.h>
+#include <util/system/hp_timer.h>
+#include <util/system/sanitizers.h>
+#include <util/system/thread.h>
+
+Y_UNIT_TEST_SUITE(UnorderedCache) {
+
+ void DoOnePushOnePop(ui64 count) {
+ TUnorderedCache<ui64> queue;
+
+ ui64 readRotation = 0;
+ ui64 writeRotation = 0;
+
+ auto popped = queue.Pop(readRotation++);
+ UNIT_ASSERT_VALUES_EQUAL(popped, 0u);
+
+ for (ui64 i = 0; i < count; ++i) {
+ queue.Push(i + 1, writeRotation++);
+ popped = queue.Pop(readRotation++);
+ UNIT_ASSERT_VALUES_EQUAL(popped, i + 1);
+
+ popped = queue.Pop(readRotation++);
+ UNIT_ASSERT_VALUES_EQUAL(popped, 0u);
+ }
+ }
+
+ Y_UNIT_TEST(OnePushOnePop) {
+ DoOnePushOnePop(1);
+ }
+
+ Y_UNIT_TEST(OnePushOnePop_Repeat1M) {
+ DoOnePushOnePop(1000000);
+ }
+
+ /**
+ * Simplified thread spawning for testing
+ */
+ class TWorkerThread : public ISimpleThread {
+ private:
+ std::function<void()> Func;
+ double Time = 0.0;
+
+ public:
+ TWorkerThread(std::function<void()> func)
+ : Func(std::move(func))
+ { }
+
+ double GetTime() const {
+ return Time;
+ }
+
+ static THolder<TWorkerThread> Spawn(std::function<void()> func) {
+ THolder<TWorkerThread> thread = MakeHolder<TWorkerThread>(std::move(func));
+ thread->Start();
+ return thread;
+ }
+
+ private:
+ void* ThreadProc() noexcept override {
+ THPTimer timer;
+ Func();
+ Time = timer.Passed();
+ return nullptr;
+ }
+ };
+
+ void DoConcurrentPushPop(size_t threads, ui64 perThreadCount) {
+ // Concurrency factor 4 is up to 16 threads
+ TUnorderedCache<ui64, 512, 4> queue;
+
+ auto workerFunc = [&](size_t threadIndex) {
+ ui64 readRotation = 0;
+ ui64 writeRotation = 0;
+ ui64 readsDone = 0;
+ ui64 writesDone = 0;
+ for (;;) {
+ bool canRead = readsDone < writesDone;
+ bool canWrite = writesDone < perThreadCount;
+ if (!canRead && !canWrite) {
+ break;
+ }
+ if (canRead && canWrite) {
+ // Randomly choose between read and write
+ if (RandomNumber<ui64>(2)) {
+ canRead = false;
+ } else {
+ canWrite = false;
+ }
+ }
+ if (canRead) {
+ ui64 popped = queue.Pop(readRotation++);
+ if (popped) {
+ ++readsDone;
+ }
+ }
+ if (canWrite) {
+ queue.Push(1 + writesDone * threads + threadIndex, writeRotation++);
+ ++writesDone;
+ }
+ }
+ };
+
+ TVector<THolder<TWorkerThread>> workers(threads);
+ for (size_t i = 0; i < threads; ++i) {
+ workers[i] = TWorkerThread::Spawn([workerFunc, i]() {
+ workerFunc(i);
+ });
+ }
+
+ double maxTime = 0;
+ for (size_t i = 0; i < threads; ++i) {
+ workers[i]->Join();
+ maxTime = Max(maxTime, workers[i]->GetTime());
+ }
+
+ auto popped = queue.Pop(0);
+ UNIT_ASSERT_VALUES_EQUAL(popped, 0u);
+
+ Cerr << "Concurrent with " << threads << " threads: " << maxTime << " seconds" << Endl;
+ }
+
+ void DoConcurrentPushPop_3times(size_t threads, ui64 perThreadCount) {
+ for (size_t i = 0; i < 3; ++i) {
+ DoConcurrentPushPop(threads, perThreadCount);
+ }
+ }
+
+ static constexpr ui64 PER_THREAD_COUNT = NSan::PlainOrUnderSanitizer(1000000, 100000);
+
+ Y_UNIT_TEST(ConcurrentPushPop_1thread) { DoConcurrentPushPop_3times(1, PER_THREAD_COUNT); }
+ Y_UNIT_TEST(ConcurrentPushPop_2threads) { DoConcurrentPushPop_3times(2, PER_THREAD_COUNT); }
+ Y_UNIT_TEST(ConcurrentPushPop_4threads) { DoConcurrentPushPop_3times(4, PER_THREAD_COUNT); }
+ Y_UNIT_TEST(ConcurrentPushPop_8threads) { DoConcurrentPushPop_3times(8, PER_THREAD_COUNT); }
+ Y_UNIT_TEST(ConcurrentPushPop_16threads) { DoConcurrentPushPop_3times(16, PER_THREAD_COUNT); }
+}
diff --git a/library/cpp/actors/util/ut/ya.make b/library/cpp/actors/util/ut/ya.make
new file mode 100644
index 0000000000..3b08b77984
--- /dev/null
+++ b/library/cpp/actors/util/ut/ya.make
@@ -0,0 +1,18 @@
+UNITTEST_FOR(library/cpp/actors/util)
+
+IF (WITH_VALGRIND)
+ TIMEOUT(600)
+ SIZE(MEDIUM)
+ENDIF()
+
+OWNER(
+ alexvru
+ g:kikimr
+)
+
+SRCS(
+ rope_ut.cpp
+ unordered_cache_ut.cpp
+)
+
+END()
diff --git a/library/cpp/actors/util/ya.make b/library/cpp/actors/util/ya.make
new file mode 100644
index 0000000000..37488c3962
--- /dev/null
+++ b/library/cpp/actors/util/ya.make
@@ -0,0 +1,37 @@
+LIBRARY()
+
+OWNER(
+ ddoarn
+ g:kikimr
+)
+
+SRCS(
+ affinity.cpp
+ affinity.h
+ cpumask.h
+ datetime.h
+ defs.h
+ funnel_queue.h
+ futex.h
+ intrinsics.h
+ local_process_key.h
+ named_tuple.h
+ queue_chunk.h
+ queue_oneone_inplace.h
+ recentwnd.h
+ rope.h
+ should_continue.cpp
+ should_continue.h
+ thread.h
+ threadparkpad.cpp
+ threadparkpad.h
+ ticket_lock.h
+ timerfd.h
+ unordered_cache.h
+)
+
+PEERDIR(
+ util
+)
+
+END()
diff --git a/library/cpp/actors/wilson/wilson_event.h b/library/cpp/actors/wilson/wilson_event.h
new file mode 100644
index 0000000000..7d89c33b51
--- /dev/null
+++ b/library/cpp/actors/wilson/wilson_event.h
@@ -0,0 +1,181 @@
+#pragma once
+
+#include "wilson_trace.h"
+
+#include <library/cpp/string_utils/base64/base64.h>
+
+#include <library/cpp/actors/core/log.h>
+
+namespace NWilson {
+#if !defined(_win_)
+// works only for those compilers, who trait C++ as ISO IEC 14882, not their own standard
+
+#define __UNROLL_PARAMS_8(N, F, X, ...) \
+ F(X, N - 8) \
+ __UNROLL_PARAMS_7(N, F, ##__VA_ARGS__)
+#define __UNROLL_PARAMS_7(N, F, X, ...) \
+ F(X, N - 7) \
+ __UNROLL_PARAMS_6(N, F, ##__VA_ARGS__)
+#define __UNROLL_PARAMS_6(N, F, X, ...) \
+ F(X, N - 6) \
+ __UNROLL_PARAMS_5(N, F, ##__VA_ARGS__)
+#define __UNROLL_PARAMS_5(N, F, X, ...) \
+ F(X, N - 5) \
+ __UNROLL_PARAMS_4(N, F, ##__VA_ARGS__)
+#define __UNROLL_PARAMS_4(N, F, X, ...) \
+ F(X, N - 4) \
+ __UNROLL_PARAMS_3(N, F, ##__VA_ARGS__)
+#define __UNROLL_PARAMS_3(N, F, X, ...) \
+ F(X, N - 3) \
+ __UNROLL_PARAMS_2(N, F, ##__VA_ARGS__)
+#define __UNROLL_PARAMS_2(N, F, X, ...) \
+ F(X, N - 2) \
+ __UNROLL_PARAMS_1(N, F, ##__VA_ARGS__)
+#define __UNROLL_PARAMS_1(N, F, X) F(X, N - 1)
+#define __UNROLL_PARAMS_0(N, F)
+#define __EX(...) __VA_ARGS__
+#define __NUM_PARAMS(...) __NUM_PARAMS_SELECT_N(__VA_ARGS__, __NUM_PARAMS_SEQ)
+#define __NUM_PARAMS_SELECT_N(...) __EX(__NUM_PARAMS_SELECT(__VA_ARGS__))
+#define __NUM_PARAMS_SELECT(X, _1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
+#define __NUM_PARAMS_SEQ 8, 7, 6, 5, 4, 3, 2, 1, 0, ERROR
+#define __CAT(X, Y) X##Y
+#define __UNROLL_PARAMS_N(N, F, ...) __EX(__CAT(__UNROLL_PARAMS_, N)(N, F, ##__VA_ARGS__))
+#define __UNROLL_PARAMS(F, ...) __UNROLL_PARAMS_N(__NUM_PARAMS(X, ##__VA_ARGS__), F, ##__VA_ARGS__)
+#define __EX2(F, X, INDEX) __INVOKE(F, __EX X, INDEX)
+#define __INVOKE(F, ...) F(__VA_ARGS__)
+
+#define __DECLARE_PARAM(X, INDEX) __EX2(__DECLARE_PARAM_X, X, INDEX)
+#define __DECLARE_PARAM_X(TYPE, NAME, INDEX) \
+ static const struct T##NAME##Param \
+ : ::NWilson::TParamBinder<INDEX, TYPE> { \
+ T##NAME##Param() { \
+ } \
+ using ::NWilson::TParamBinder<INDEX, TYPE>::operator=; \
+ } NAME;
+
+#define __TUPLE_PARAM(X, INDEX) __EX2(__TUPLE_PARAM_X, X, INDEX)
+#define __TUPLE_PARAM_X(TYPE, NAME, INDEX) TYPE,
+
+#define __OUTPUT_PARAM(X, INDEX) __EX2(__OUTPUT_PARAM_X, X, INDEX)
+#define __OUTPUT_PARAM_X(TYPE, NAME, INDEX) str << (INDEX ? ", " : "") << #NAME << "# " << std::get<INDEX>(ParamPack);
+
+#define __FILL_PARAM(P, INDEX) \
+ do { \
+ const auto& boundParam = (NParams::P); \
+ boundParam.Apply(event.ParamPack); \
+ } while (false);
+
+#define DECLARE_WILSON_EVENT(EVENT_NAME, ...) \
+ namespace N##EVENT_NAME##Params { \
+ __UNROLL_PARAMS(__DECLARE_PARAM, ##__VA_ARGS__) \
+ \
+ using TParamPack = std::tuple< \
+ __UNROLL_PARAMS(__TUPLE_PARAM, ##__VA_ARGS__) char>; \
+ } \
+ struct T##EVENT_NAME { \
+ using TParamPack = N##EVENT_NAME##Params::TParamPack; \
+ TParamPack ParamPack; \
+ \
+ void Output(IOutputStream& str) { \
+ str << #EVENT_NAME << "{"; \
+ __UNROLL_PARAMS(__OUTPUT_PARAM, ##__VA_ARGS__) \
+ str << "}"; \
+ } \
+ };
+
+ template <size_t INDEX, typename T>
+ class TBoundParam {
+ mutable T Value;
+
+ public:
+ TBoundParam(T&& value)
+ : Value(std::move(value))
+ {
+ }
+
+ template <typename TParamPack>
+ void Apply(TParamPack& pack) const {
+ std::get<INDEX>(pack) = std::move(Value);
+ }
+ };
+
+ template <size_t INDEX, typename T>
+ struct TParamBinder {
+ template <typename TValue>
+ TBoundParam<INDEX, T> operator=(const TValue& value) const {
+ return TBoundParam<INDEX, T>(TValue(value));
+ }
+
+ template <typename TValue>
+ TBoundParam<INDEX, T> operator=(TValue&& value) const {
+ return TBoundParam<INDEX, T>(std::move(value));
+ }
+ };
+
+// generate wilson event having parent TRACE_ID and span TRACE_ID to become parent of logged event
+#define WILSON_TRACE(CTX, TRACE_ID, EVENT_NAME, ...) \
+ if (::NWilson::TraceEnabled(CTX)) { \
+ ::NWilson::TTraceId* __traceId = (TRACE_ID); \
+ if (__traceId && *__traceId) { \
+ TInstant now = Now(); \
+ T##EVENT_NAME event; \
+ namespace NParams = N##EVENT_NAME##Params; \
+ __UNROLL_PARAMS(__FILL_PARAM, ##__VA_ARGS__) \
+ ::NWilson::TraceEvent((CTX), __traceId, event, now); \
+ } \
+ }
+
+ inline ui32 GetNodeId(const NActors::TActorSystem& actorSystem) {
+ return actorSystem.NodeId;
+ }
+ inline ui32 GetNodeId(const NActors::TActivationContext& ac) {
+ return GetNodeId(*ac.ExecutorThread.ActorSystem);
+ }
+
+ constexpr ui32 WilsonComponentId = 430; // kikimrservices: wilson
+
+ template <typename TActorSystem>
+ bool TraceEnabled(const TActorSystem& ctx) {
+ const auto* loggerSettings = ctx.LoggerSettings();
+ return loggerSettings && loggerSettings->Satisfies(NActors::NLog::PRI_DEBUG, WilsonComponentId);
+ }
+
+ template <typename TActorSystem, typename TEvent>
+ void TraceEvent(const TActorSystem& actorSystem, TTraceId* traceId, TEvent&& event, TInstant timestamp) {
+ // ensure that we are not using obsolete TraceId
+ traceId->CheckConsistency();
+
+ // store parent id (for logging) and generate child trace id
+ TTraceId parentTraceId(std::move(*traceId));
+ *traceId = parentTraceId.Span();
+
+ // create encoded string buffer containing timestamp
+ const ui64 timestampValue = timestamp.GetValue();
+ const size_t base64size = Base64EncodeBufSize(sizeof(timestampValue));
+ char base64[base64size];
+ char* end = Base64Encode(base64, reinterpret_cast<const ui8*>(&timestampValue), sizeof(timestampValue));
+
+ // cut trailing padding character to save some space
+ Y_VERIFY(end > base64 && end[-1] == '=');
+ --end;
+
+ // generate log record
+ TString finalMessage;
+ TStringOutput s(finalMessage);
+ s << GetNodeId(actorSystem) << " " << TStringBuf(base64, end) << " ";
+ traceId->Output(s, parentTraceId);
+ s << " ";
+ event.Output(s);
+
+ // output wilson event FIXME: special facility for wilson events w/binary serialization
+ NActors::MemLogAdapter(actorSystem, NActors::NLog::PRI_DEBUG, WilsonComponentId, std::move(finalMessage));
+ }
+
+#else
+
+#define DECLARE_WILSON_EVENT(...)
+#define WILSON_TRACE(...)
+
+#endif
+
+} // NWilson
diff --git a/library/cpp/actors/wilson/wilson_trace.h b/library/cpp/actors/wilson/wilson_trace.h
new file mode 100644
index 0000000000..3d1ca50562
--- /dev/null
+++ b/library/cpp/actors/wilson/wilson_trace.h
@@ -0,0 +1,161 @@
+#pragma once
+
+#include <library/cpp/string_utils/base64/base64.h>
+
+#include <util/stream/output.h>
+#include <util/random/random.h>
+
+#include <util/string/printf.h>
+
+namespace NWilson {
+ class TTraceId {
+ ui64 TraceId; // Random id of topmost client request
+ ui64 SpanId; // Span id of part of request currently being executed
+
+ private:
+ TTraceId(ui64 traceId, ui64 spanId)
+ : TraceId(traceId)
+ , SpanId(spanId)
+ {
+ }
+
+ static ui64 GenerateTraceId() {
+ ui64 traceId = 0;
+ while (!traceId) {
+ traceId = RandomNumber<ui64>();
+ }
+ return traceId;
+ }
+
+ static ui64 GenerateSpanId() {
+ return RandomNumber<ui64>();
+ }
+
+ public:
+ using TSerializedTraceId = char[2 * sizeof(ui64)];
+
+ public:
+ TTraceId()
+ : TraceId(0)
+ , SpanId(0)
+ {
+ }
+
+ explicit TTraceId(ui64 traceId)
+ : TraceId(traceId)
+ , SpanId(0)
+ {
+ }
+
+ TTraceId(const TSerializedTraceId& in)
+ : TraceId(reinterpret_cast<const ui64*>(in)[0])
+ , SpanId(reinterpret_cast<const ui64*>(in)[1])
+ {
+ }
+
+ // allow move semantic
+ TTraceId(TTraceId&& other)
+ : TraceId(other.TraceId)
+ , SpanId(other.SpanId)
+ {
+ other.TraceId = 0;
+ other.SpanId = 1; // explicitly mark invalid
+ }
+
+ TTraceId& operator=(TTraceId&& other) {
+ TraceId = other.TraceId;
+ SpanId = other.SpanId;
+ other.TraceId = 0;
+ other.SpanId = 1; // explicitly mark invalid
+ return *this;
+ }
+
+ // do not allow implicit copy of trace id
+ TTraceId(const TTraceId& other) = delete;
+ TTraceId& operator=(const TTraceId& other) = delete;
+
+ static TTraceId NewTraceId() {
+ return TTraceId(GenerateTraceId(), 0);
+ }
+
+ // create separate branch from this point
+ TTraceId SeparateBranch() const {
+ return Clone();
+ }
+
+ TTraceId Clone() const {
+ return TTraceId(TraceId, SpanId);
+ }
+
+ TTraceId Span() const {
+ return *this ? TTraceId(TraceId, GenerateSpanId()) : TTraceId();
+ }
+
+ ui64 GetTraceId() const {
+ return TraceId;
+ }
+
+ // Check if request tracing is enabled
+ operator bool() const {
+ return TraceId != 0;
+ }
+
+ // Output trace id into a string stream
+ void Output(IOutputStream& s, const TTraceId& parentTraceId) const {
+ union {
+ ui8 buffer[3 * sizeof(ui64)];
+ struct {
+ ui64 traceId;
+ ui64 spanId;
+ ui64 parentSpanId;
+ } x;
+ };
+
+ x.traceId = TraceId;
+ x.spanId = SpanId;
+ x.parentSpanId = parentTraceId.SpanId;
+
+ const size_t base64size = Base64EncodeBufSize(sizeof(x));
+ char base64[base64size];
+ char* end = Base64Encode(base64, buffer, sizeof(x));
+ s << TStringBuf(base64, end);
+ }
+
+ // output just span id into stream
+ void OutputSpanId(IOutputStream& s) const {
+ const size_t base64size = Base64EncodeBufSize(sizeof(SpanId));
+ char base64[base64size];
+ char* end = Base64Encode(base64, reinterpret_cast<const ui8*>(&SpanId), sizeof(SpanId));
+
+ // cut trailing padding character
+ Y_VERIFY(end > base64 && end[-1] == '=');
+ --end;
+
+ s << TStringBuf(base64, end);
+ }
+
+ void CheckConsistency() {
+ // if TraceId is zero, then SpanId must be zero too
+ Y_VERIFY_DEBUG(*this || !SpanId);
+ }
+
+ friend bool operator==(const TTraceId& x, const TTraceId& y) {
+ return x.TraceId == y.TraceId && x.SpanId == y.SpanId;
+ }
+
+ TString ToString() const {
+ return Sprintf("%" PRIu64 ":%" PRIu64, TraceId, SpanId);
+ }
+
+ bool IsFromSameTree(const TTraceId& other) const {
+ return TraceId == other.TraceId;
+ }
+
+ void Serialize(TSerializedTraceId* out) {
+ ui64* p = reinterpret_cast<ui64*>(*out);
+ p[0] = TraceId;
+ p[1] = SpanId;
+ }
+ };
+
+}
diff --git a/library/cpp/actors/wilson/ya.make b/library/cpp/actors/wilson/ya.make
new file mode 100644
index 0000000000..e371f5061d
--- /dev/null
+++ b/library/cpp/actors/wilson/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+PEERDIR(
+ library/cpp/string_utils/base64
+)
+
+OWNER(alexvru)
+
+SRCS(
+ wilson_event.h
+ wilson_trace.h
+)
+
+END()
diff --git a/library/cpp/actors/ya.make b/library/cpp/actors/ya.make
new file mode 100644
index 0000000000..737c7fbc18
--- /dev/null
+++ b/library/cpp/actors/ya.make
@@ -0,0 +1,16 @@
+RECURSE_FOR_TESTS(ut)
+
+RECURSE(
+ log_backend
+ core
+ dnsresolver
+ examples
+ memory_log
+ helpers
+ prof
+ protos
+ util
+ wilson
+ testlib
+ http
+)
diff --git a/library/cpp/archive/directory_models_archive_reader.cpp b/library/cpp/archive/directory_models_archive_reader.cpp
new file mode 100644
index 0000000000..6de9424c7c
--- /dev/null
+++ b/library/cpp/archive/directory_models_archive_reader.cpp
@@ -0,0 +1,115 @@
+#include "directory_models_archive_reader.h"
+#include "yarchive.h"
+
+#include <util/folder/dirut.h>
+#include <util/folder/filelist.h>
+#include <util/folder/path.h>
+#include <util/memory/blob.h>
+#include <util/stream/file.h>
+#include <util/stream/input.h>
+#include <util/stream/mem.h>
+
+TDirectoryModelsArchiveReader::TDirectoryModelsArchiveReader(const TString& path, bool lockMemory, bool ownBlobs)
+ : Path_(path)
+{
+ Y_ENSURE(IsDir(path), "directory not found on this path");
+
+ LoadFilesAndSubdirs("", lockMemory, ownBlobs);
+}
+
+TDirectoryModelsArchiveReader::~TDirectoryModelsArchiveReader() {}
+
+size_t TDirectoryModelsArchiveReader::Count() const noexcept {
+ return Recs_.size();
+}
+
+TString TDirectoryModelsArchiveReader::KeyByIndex(size_t n) const {
+ Y_ENSURE(n < Count(), "incorrect index " << n);
+ return Recs_[n];
+}
+
+bool TDirectoryModelsArchiveReader::Has(const TStringBuf key) const {
+ return BlobByKey_.contains(key) || PathByKey_.contains(key);
+}
+
+namespace {
+ struct TBlobOwningStream : public TMemoryInput {
+ TBlob Blob;
+ TBlobOwningStream(TBlob blob)
+ : TMemoryInput(blob.Data(), blob.Length())
+ , Blob(blob)
+ {}
+ };
+}
+
+TAutoPtr<IInputStream> TDirectoryModelsArchiveReader::ObjectByKey(const TStringBuf key) const {
+ return new TBlobOwningStream(BlobByKey(key));
+}
+
+TBlob TDirectoryModelsArchiveReader::ObjectBlobByKey(const TStringBuf key) const {
+ return BlobByKey(key);
+}
+
+TBlob TDirectoryModelsArchiveReader::BlobByKey(const TStringBuf key) const {
+ Y_ENSURE(Has(key), "key " << key << " not found");
+ if (auto ptr = BlobByKey_.FindPtr(key); ptr) {
+ return *ptr;
+ }
+ if (auto ptr = PathByKey_.FindPtr(key); ptr) {
+ return TBlob::FromFile(*ptr);
+ }
+ Y_UNREACHABLE();
+}
+
+bool TDirectoryModelsArchiveReader::Compressed() const {
+ return false;
+}
+
+TString TDirectoryModelsArchiveReader::NormalizePath(TString path) const {
+ path = "/" + path;
+ for (size_t i = 0; i < path.size(); i++) {
+ if (path[i] == '\\')
+ path[i] = '/';
+ }
+ return path;
+}
+
+void TDirectoryModelsArchiveReader::LoadFilesAndSubdirs(const TString& subPath, bool lockMemory, bool ownBlobs) {
+ TFileList fileList;
+ fileList.Fill(JoinFsPaths(Path_, subPath));
+ const char* file;
+ while ((file = fileList.Next()) != nullptr) {
+ TString key = JoinFsPaths(subPath, TString(file));
+ TString fullPath = JoinFsPaths(Path_, key);
+ TBlob fileBlob;
+ if (lockMemory) {
+ fileBlob = TBlob::LockedFromFile(fullPath);
+ } else {
+ fileBlob = TBlob::FromFile(fullPath);
+ }
+ if (key.EndsWith(".archive")) {
+ TArchiveReader reader(fileBlob);
+ for (size_t i = 0, iEnd = reader.Count(); i < iEnd; ++i) {
+ const TString archiveKey = reader.KeyByIndex(i);
+ const TString normalizedPath = NormalizePath(JoinFsPaths(subPath, archiveKey.substr(1)));
+ BlobByKey_.emplace(normalizedPath, reader.ObjectBlobByKey(archiveKey));
+ Recs_.push_back(normalizedPath);
+ }
+ } else {
+ const TString normalizedPath = NormalizePath(key);
+ if (lockMemory || ownBlobs) {
+ BlobByKey_.emplace(normalizedPath, fileBlob);
+ } else {
+ PathByKey_.emplace(normalizedPath, RealPath(fullPath));
+ }
+ Recs_.push_back(normalizedPath);
+ }
+ }
+
+ TDirsList dirsList;
+ dirsList.Fill(JoinFsPaths(Path_, subPath));
+ const char* dir;
+ while ((dir = dirsList.Next()) != nullptr) {
+ LoadFilesAndSubdirs(JoinFsPaths(subPath, TString(dir)), lockMemory, ownBlobs);
+ }
+}
diff --git a/library/cpp/archive/directory_models_archive_reader.h b/library/cpp/archive/directory_models_archive_reader.h
new file mode 100644
index 0000000000..d16d6d728d
--- /dev/null
+++ b/library/cpp/archive/directory_models_archive_reader.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "models_archive_reader.h"
+
+#include <util/folder/path.h>
+#include <util/generic/fwd.h>
+#include <util/generic/hash.h>
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+
+
+class IInputStream;
+
+class TBlob;
+
+class TDirectoryModelsArchiveReader : public IModelsArchiveReader {
+public:
+ TDirectoryModelsArchiveReader(const TString& path, bool lockMemory = false, bool ownBlobs = false);
+ virtual ~TDirectoryModelsArchiveReader() override;
+
+ virtual size_t Count() const noexcept override;
+ virtual TString KeyByIndex(size_t n) const override;
+ virtual bool Has(const TStringBuf key) const override;
+ virtual TAutoPtr<IInputStream> ObjectByKey(const TStringBuf key) const override;
+ virtual TBlob ObjectBlobByKey(const TStringBuf key) const override;
+ virtual TBlob BlobByKey(const TStringBuf key) const override;
+ virtual bool Compressed() const override;
+
+private:
+ TString NormalizePath(TString path) const; // in archive path works unix-like path delimiter and leading slash is neccesery
+ void LoadFilesAndSubdirs(const TString& subPath, bool lockMemory, bool ownBlobs);
+
+private:
+ TString Path_;
+ THashMap<TString, TString> PathByKey_;
+ THashMap<TString, TBlob> BlobByKey_;
+ TVector<TString> Recs_;
+};
diff --git a/library/cpp/archive/directory_models_archive_reader_ut.cpp b/library/cpp/archive/directory_models_archive_reader_ut.cpp
new file mode 100644
index 0000000000..09994de9b4
--- /dev/null
+++ b/library/cpp/archive/directory_models_archive_reader_ut.cpp
@@ -0,0 +1,55 @@
+#include "directory_models_archive_reader.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/folder/tempdir.h>
+#include <util/string/cast.h>
+#include <util/stream/file.h>
+#include <util/system/tempfile.h>
+#include <util/memory/blob.h>
+
+class TDirectoryModelsArchiveReaderTest: public TTestBase {
+ UNIT_TEST_SUITE(TDirectoryModelsArchiveReaderTest)
+ UNIT_TEST(TestRead);
+ UNIT_TEST_SUITE_END();
+
+private:
+ void TestRead();
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TDirectoryModelsArchiveReaderTest);
+
+const TString MAIN_DIR = "./dir";
+const TString SUBDIR = "/subdir";
+const TString SAMPLE_FILE1 = "/sample1";
+const TString SAMPLE_FILE2 = "/sample2";
+const TString TEST_TEXT = "Test Text.";
+
+void TDirectoryModelsArchiveReaderTest::TestRead() {
+ TTempDir mainDir(MAIN_DIR);
+ TTempDir subDir(MAIN_DIR + SUBDIR);
+ TTempFileHandle file1(MAIN_DIR + SAMPLE_FILE1);
+ TTempFileHandle file2(MAIN_DIR + SUBDIR + SAMPLE_FILE2);
+
+ file1.Write(TEST_TEXT.data(), TEST_TEXT.size());
+ file1.FlushData();
+
+ TDirectoryModelsArchiveReader reader(MAIN_DIR, false);
+
+ UNIT_ASSERT_EQUAL(reader.Count(), 2);
+
+ UNIT_ASSERT(reader.Has(SAMPLE_FILE1));
+ UNIT_ASSERT(reader.Has(SUBDIR + SAMPLE_FILE2));
+
+ UNIT_ASSERT_EQUAL(reader.KeyByIndex(0), SAMPLE_FILE1);
+ UNIT_ASSERT_EQUAL(reader.KeyByIndex(1), SUBDIR + SAMPLE_FILE2);
+
+ TBlob blob = reader.BlobByKey(SAMPLE_FILE1);
+ Cout << "'" << TString(blob.AsCharPtr(), blob.Size()) << "' - '" << TEST_TEXT << "'" << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(TString(blob.AsCharPtr(), blob.Size()), TString(TEST_TEXT));
+
+ TAutoPtr<IInputStream> is = reader.ObjectByKey(SAMPLE_FILE1);
+ const TString data = is->ReadAll();
+ Cout << "'" << data << "' - '" << TEST_TEXT << "'" << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(data, TEST_TEXT);
+}
diff --git a/library/cpp/archive/models_archive_reader.h b/library/cpp/archive/models_archive_reader.h
new file mode 100644
index 0000000000..ea237aecb0
--- /dev/null
+++ b/library/cpp/archive/models_archive_reader.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <util/generic/fwd.h>
+#include <util/generic/ptr.h>
+
+class IInputStream;
+
+class TBlob;
+
+class IModelsArchiveReader {
+public:
+ virtual ~IModelsArchiveReader() = default;
+ virtual size_t Count() const = 0;
+ virtual TString KeyByIndex(size_t n) const = 0;
+ virtual bool Has(const TStringBuf key) const = 0;
+ virtual TAutoPtr<IInputStream> ObjectByKey(const TStringBuf key) const = 0;
+ virtual TBlob ObjectBlobByKey(const TStringBuf key) const = 0;
+ virtual TBlob BlobByKey(const TStringBuf key) const = 0;
+ virtual bool Compressed() const = 0;
+};
diff --git a/library/cpp/archive/ut/ya.make b/library/cpp/archive/ut/ya.make
new file mode 100644
index 0000000000..4f324ccfc6
--- /dev/null
+++ b/library/cpp/archive/ut/ya.make
@@ -0,0 +1,16 @@
+UNITTEST()
+
+OWNER(pg)
+
+PEERDIR(
+ ADDINCL library/cpp/archive
+)
+
+SRCDIR(library/cpp/archive)
+
+SRCS(
+ yarchive_ut.cpp
+ directory_models_archive_reader_ut.cpp
+)
+
+END()
diff --git a/library/cpp/archive/ya.make b/library/cpp/archive/ya.make
new file mode 100644
index 0000000000..65d36479ef
--- /dev/null
+++ b/library/cpp/archive/ya.make
@@ -0,0 +1,12 @@
+LIBRARY()
+
+OWNER(pg)
+
+SRCS(
+ yarchive.cpp
+ yarchive.h
+ directory_models_archive_reader.cpp
+ directory_models_archive_reader.h
+)
+
+END()
diff --git a/library/cpp/archive/yarchive.cpp b/library/cpp/archive/yarchive.cpp
new file mode 100644
index 0000000000..1becc3e5da
--- /dev/null
+++ b/library/cpp/archive/yarchive.cpp
@@ -0,0 +1,398 @@
+#include "yarchive.h"
+
+#include <util/generic/algorithm.h>
+#include <util/generic/hash.h>
+#include <util/generic/utility.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+#include <util/memory/blob.h>
+#include <util/memory/tempbuf.h>
+#include <util/stream/input.h>
+#include <util/stream/length.h>
+#include <util/stream/mem.h>
+#include <util/stream/output.h>
+#include <util/stream/zlib.h>
+#include <util/system/byteorder.h>
+#include <util/ysaveload.h>
+
+template <class T>
+static inline void ESSave(IOutputStream* out, const T& t_in) {
+ T t = HostToLittle(t_in);
+
+ out->Write((const void*)&t, sizeof(t));
+}
+
+static inline void ESSave(IOutputStream* out, const TString& s) {
+ ESSave(out, (ui32) s.size());
+ out->Write(s.data(), s.size());
+}
+
+template <class T>
+static inline T ESLoad(IInputStream* in) {
+ T t = T();
+
+ if (in->Load(&t, sizeof(t)) != sizeof(t)) {
+ ythrow TSerializeException() << "malformed archive";
+ }
+
+ return LittleToHost(t);
+}
+
+template <>
+inline TString ESLoad<TString>(IInputStream* in) {
+ size_t len = ESLoad<ui32>(in);
+ TString ret;
+ TTempBuf tmp;
+
+ while (len) {
+ const size_t toread = Min(len, tmp.Size());
+ const size_t readed = in->Read(tmp.Data(), toread);
+
+ if (!readed) {
+ ythrow TSerializeException() << "malformed archive";
+ }
+
+ ret.append(tmp.Data(), readed);
+ len -= readed;
+ }
+
+ return ret;
+}
+
+namespace {
+ class TArchiveRecordDescriptor: public TSimpleRefCount<TArchiveRecordDescriptor> {
+ public:
+ inline TArchiveRecordDescriptor(ui64 off, ui64 len, const TString& name)
+ : Off_(off)
+ , Len_(len)
+ , Name_(name)
+ {
+ }
+
+ inline TArchiveRecordDescriptor(IInputStream* in)
+ : Off_(ESLoad<ui64>(in))
+ , Len_(ESLoad<ui64>(in))
+ , Name_(ESLoad<TString>(in))
+ {
+ }
+
+ inline ~TArchiveRecordDescriptor() = default;
+
+ inline void SaveTo(IOutputStream* out) const {
+ ESSave(out, Off_);
+ ESSave(out, Len_);
+ ESSave(out, Name_);
+ }
+
+ inline const TString& Name() const noexcept {
+ return Name_;
+ }
+
+ inline ui64 Length() const noexcept {
+ return Len_;
+ }
+
+ inline ui64 Offset() const noexcept {
+ return Off_;
+ }
+
+ private:
+ ui64 Off_;
+ ui64 Len_;
+ TString Name_;
+ };
+
+ typedef TIntrusivePtr<TArchiveRecordDescriptor> TArchiveRecordDescriptorRef;
+}
+
+class TArchiveWriter::TImpl {
+ using TDict = THashMap<TString, TArchiveRecordDescriptorRef>;
+
+public:
+ inline TImpl(IOutputStream& out, bool compress)
+ : Off_(0)
+ , Out_(&out)
+ , UseCompression(compress)
+ {
+ }
+
+ inline ~TImpl() = default;
+
+ inline void Flush() {
+ Out_->Flush();
+ }
+
+ inline void Finish() {
+ TCountingOutput out(Out_);
+
+ {
+ TZLibCompress compress(&out);
+
+ ESSave(&compress, (ui32)Dict_.size());
+
+ for (const auto& kv : Dict_) {
+ kv.second->SaveTo(&compress);
+ }
+
+ ESSave(&compress, static_cast<ui8>(UseCompression));
+
+ compress.Finish();
+ }
+
+ ESSave(Out_, out.Counter());
+
+ Out_->Flush();
+ }
+
+ inline void Add(const TString& key, IInputStream* src) {
+ Y_ENSURE(!Dict_.contains(key), "key " << key.data() << " already stored");
+
+ TCountingOutput out(Out_);
+ if (UseCompression) {
+ TZLibCompress compress(&out);
+ TransferData(src, &compress);
+ compress.Finish();
+ } else {
+ size_t skip_size = ArchiveWriterDefaultDataAlignment - Off_ % ArchiveWriterDefaultDataAlignment;
+ if (skip_size == ArchiveWriterDefaultDataAlignment) {
+ skip_size = 0;
+ }
+ while(skip_size > 0) {
+ Out_->Write(char(0));
+ Off_ += 1;
+ skip_size -= 1;
+ }
+ TransferData(src, &out);
+ out.Finish();
+ }
+
+ TArchiveRecordDescriptorRef descr(new TArchiveRecordDescriptor(Off_, out.Counter(), key));
+
+ Dict_[key] = descr;
+ Off_ += out.Counter();
+ }
+
+ inline void AddSynonym(const TString& existingKey, const TString& newKey) {
+ Y_ENSURE(Dict_.contains(existingKey), "key " << existingKey.data() << " not stored yet");
+ Y_ENSURE(!Dict_.contains(newKey), "key " << newKey.data() << " already stored");
+
+ TArchiveRecordDescriptorRef existingDescr = Dict_[existingKey];
+ TArchiveRecordDescriptorRef descr(new TArchiveRecordDescriptor(existingDescr->Offset(), existingDescr->Length(), newKey));
+
+ Dict_[newKey] = descr;
+ }
+
+private:
+ ui64 Off_;
+ IOutputStream* Out_;
+ TDict Dict_;
+ const bool UseCompression;
+};
+
+TArchiveWriter::TArchiveWriter(IOutputStream* out, bool compress)
+ : Impl_(new TImpl(*out, compress))
+{
+}
+
+TArchiveWriter::~TArchiveWriter() {
+ try {
+ Finish();
+ } catch (...) {
+ }
+}
+
+void TArchiveWriter::Flush() {
+ if (Impl_.Get()) {
+ Impl_->Flush();
+ }
+}
+
+void TArchiveWriter::Finish() {
+ if (Impl_.Get()) {
+ Impl_->Finish();
+ Impl_.Destroy();
+ }
+}
+
+void TArchiveWriter::Add(const TString& key, IInputStream* src) {
+ Y_ENSURE(Impl_.Get(), "archive already closed");
+
+ Impl_->Add(key, src);
+}
+
+void TArchiveWriter::AddSynonym(const TString& existingKey, const TString& newKey) {
+ Y_ENSURE(Impl_.Get(), "archive already closed");
+
+ Impl_->AddSynonym(existingKey, newKey);
+}
+
+namespace {
+ class TArchiveInputStreamBase {
+ public:
+ inline TArchiveInputStreamBase(const TBlob& b)
+ : Blob_(b)
+ , Input_(b.Data(), b.Size())
+ {
+ }
+
+ protected:
+ TBlob Blob_;
+ TMemoryInput Input_;
+ };
+
+ class TArchiveInputStream: public TArchiveInputStreamBase, public TZLibDecompress {
+ public:
+ inline TArchiveInputStream(const TBlob& b)
+ : TArchiveInputStreamBase(b)
+ , TZLibDecompress(&Input_)
+ {
+ }
+
+ ~TArchiveInputStream() override = default;
+ };
+}
+
+class TArchiveReader::TImpl {
+ typedef THashMap<TString, TArchiveRecordDescriptorRef> TDict;
+
+public:
+ inline TImpl(const TBlob& blob)
+ : Blob_(blob)
+ , UseDecompression(true)
+ {
+ ReadDict();
+ }
+
+ inline ~TImpl() = default;
+
+ inline void ReadDict() {
+ Y_ENSURE(Blob_.Size() >= sizeof(ui64), "too small blob");
+
+ const char* end = (const char*)Blob_.End();
+ const char* ptr = end - sizeof(ui64);
+ ui64 dictlen = 0;
+ memcpy(&dictlen, ptr, sizeof(ui64));
+ dictlen = LittleToHost(dictlen);
+
+ Y_ENSURE(dictlen <= Blob_.Size() - sizeof(ui64), "bad blob");
+
+ const char* beg = ptr - dictlen;
+ TMemoryInput mi(beg, dictlen);
+ TZLibDecompress d(&mi);
+ const ui32 count = ESLoad<ui32>(&d);
+
+ for (size_t i = 0; i < count; ++i) {
+ TArchiveRecordDescriptorRef descr(new TArchiveRecordDescriptor(&d));
+
+ Recs_.push_back(descr);
+ Dict_[descr->Name()] = descr;
+ }
+ Sort(Recs_.begin(), Recs_.end(), [](const auto& lhs, const auto& rhs) -> bool {
+ return lhs->Offset() < rhs->Offset();
+ });
+
+ try {
+ UseDecompression = static_cast<bool>(ESLoad<ui8>(&d));
+ } catch (const TSerializeException&) {
+ // that's ok - just old format
+ UseDecompression = true;
+ }
+ }
+
+ inline size_t Count() const noexcept {
+ return Recs_.size();
+ }
+
+ inline TString KeyByIndex(size_t n) const {
+ if (n < Count()) {
+ return Recs_[n]->Name();
+ }
+
+ ythrow yexception() << "incorrect index";
+ }
+
+ inline bool Has(const TStringBuf key) const {
+ return Dict_.contains(key);
+ }
+
+ inline TAutoPtr<IInputStream> ObjectByKey(const TStringBuf key) const {
+ TBlob subBlob = BlobByKey(key);
+
+ if (UseDecompression) {
+ return new TArchiveInputStream(subBlob);
+ } else {
+ return new TMemoryInput(subBlob.Data(), subBlob.Length());
+ }
+ }
+
+ inline TBlob ObjectBlobByKey(const TStringBuf key) const {
+ TBlob subBlob = BlobByKey(key);
+
+ if (UseDecompression) {
+ TArchiveInputStream st(subBlob);
+ return TBlob::FromStream(st);
+ } else {
+ return subBlob;
+ }
+ }
+
+ inline TBlob BlobByKey(const TStringBuf key) const {
+ const auto it = Dict_.find(key);
+
+ Y_ENSURE(it != Dict_.end(), "key " << key.data() << " not found");
+
+ const size_t off = it->second->Offset();
+ const size_t len = it->second->Length();
+
+ /*
+ * TODO - overflow check
+ */
+
+ return Blob_.SubBlob(off, off + len);
+ }
+
+ inline bool Compressed() const {
+ return UseDecompression;
+ }
+
+private:
+ TBlob Blob_;
+ TVector<TArchiveRecordDescriptorRef> Recs_;
+ TDict Dict_;
+ bool UseDecompression;
+};
+
+TArchiveReader::TArchiveReader(const TBlob& data)
+ : Impl_(new TImpl(data))
+{
+}
+
+TArchiveReader::~TArchiveReader() {}
+
+size_t TArchiveReader::Count() const noexcept {
+ return Impl_->Count();
+}
+
+TString TArchiveReader::KeyByIndex(size_t n) const {
+ return Impl_->KeyByIndex(n);
+}
+
+bool TArchiveReader::Has(const TStringBuf key) const {
+ return Impl_->Has(key);
+}
+
+TAutoPtr<IInputStream> TArchiveReader::ObjectByKey(const TStringBuf key) const {
+ return Impl_->ObjectByKey(key);
+}
+
+TBlob TArchiveReader::ObjectBlobByKey(const TStringBuf key) const {
+ return Impl_->ObjectBlobByKey(key);
+}
+
+TBlob TArchiveReader::BlobByKey(const TStringBuf key) const {
+ return Impl_->BlobByKey(key);
+}
+
+bool TArchiveReader::Compressed() const {
+ return Impl_->Compressed();
+}
diff --git a/library/cpp/archive/yarchive.h b/library/cpp/archive/yarchive.h
new file mode 100644
index 0000000000..8120bcb940
--- /dev/null
+++ b/library/cpp/archive/yarchive.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include "models_archive_reader.h"
+
+#include <util/generic/fwd.h>
+#include <util/generic/ptr.h>
+
+
+class IInputStream;
+class IOutputStream;
+
+class TBlob;
+
+//noncompressed data will be stored with default alignment DEVTOOLS-4384
+static constexpr size_t ArchiveWriterDefaultDataAlignment = 16;
+
+class TArchiveWriter {
+public:
+ explicit TArchiveWriter(IOutputStream* out, bool compress = true);
+ ~TArchiveWriter();
+
+ void Flush();
+ void Finish();
+ void Add(const TString& key, IInputStream* src);
+ void AddSynonym(const TString& existingKey, const TString& newKey);
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+class TArchiveReader : public IModelsArchiveReader {
+public:
+ explicit TArchiveReader(const TBlob& data);
+ ~TArchiveReader() override;
+
+ size_t Count() const noexcept override;
+ TString KeyByIndex(size_t n) const override;
+ bool Has(TStringBuf key) const override;
+ TAutoPtr<IInputStream> ObjectByKey(TStringBuf key) const override;
+ TBlob ObjectBlobByKey(TStringBuf key) const override;
+ TBlob BlobByKey(TStringBuf key) const override;
+ bool Compressed() const override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
diff --git a/library/cpp/archive/yarchive_ut.cpp b/library/cpp/archive/yarchive_ut.cpp
new file mode 100644
index 0000000000..602a1cdbbd
--- /dev/null
+++ b/library/cpp/archive/yarchive_ut.cpp
@@ -0,0 +1,84 @@
+#include "yarchive.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/string/cast.h>
+#include <util/stream/file.h>
+#include <util/system/tempfile.h>
+#include <util/memory/blob.h>
+
+class TArchiveTest: public TTestBase {
+ UNIT_TEST_SUITE(TArchiveTest)
+ UNIT_TEST(TestCreate);
+ UNIT_TEST(TestRead);
+ UNIT_TEST(TestOffsetOrder);
+ UNIT_TEST_SUITE_END();
+
+private:
+ void CreateArchive();
+ void TestCreate();
+ void TestRead();
+ void TestOffsetOrder();
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TArchiveTest);
+
+#define ARCHIVE "./test.ar"
+
+void TArchiveTest::CreateArchive() {
+ TFixedBufferFileOutput out(ARCHIVE);
+ TArchiveWriter w(&out);
+
+ for (size_t i = 0; i < 1000; ++i) {
+ const TString path = "/" + ToString(i);
+ const TString data = "data" + ToString(i * 1000) + "dataend";
+ TStringInput si(data);
+
+ w.Add(path, &si);
+ }
+
+ w.Finish();
+ out.Finish();
+}
+
+void TArchiveTest::TestCreate() {
+ CreateArchive();
+ TTempFile tmpFile(ARCHIVE);
+}
+
+void TArchiveTest::TestRead() {
+ CreateArchive();
+ TTempFile tmpFile(ARCHIVE);
+ TBlob blob = TBlob::FromFileSingleThreaded(ARCHIVE);
+ TArchiveReader r(blob);
+
+ UNIT_ASSERT_EQUAL(r.Count(), 1000);
+
+ for (size_t i = 0; i < 1000; ++i) {
+ const TString key = "/" + ToString(i);
+ TAutoPtr<IInputStream> is = r.ObjectByKey(key);
+ const TString data = is->ReadAll();
+
+ UNIT_ASSERT_EQUAL(data, "data" + ToString(i * 1000) + "dataend");
+ }
+}
+
+void TArchiveTest::TestOffsetOrder() {
+ CreateArchive();
+ TTempFile tmpFile(ARCHIVE);
+ TBlob blob1 = TBlob::FromFileSingleThreaded(ARCHIVE);
+ TArchiveReader r(blob1);
+
+ const void* prevOffset = nullptr;
+
+ for (size_t i = 0; i < r.Count(); ++i) {
+ const TString key = r.KeyByIndex(i);
+ TBlob blob2 = r.BlobByKey(key);
+ const void* offset = blob2.Data();
+
+ if (i) {
+ UNIT_ASSERT(prevOffset < offset);
+ }
+ prevOffset = offset;
+ }
+}
diff --git a/library/cpp/balloc/balloc.cpp b/library/cpp/balloc/balloc.cpp
new file mode 100644
index 0000000000..fab489db4c
--- /dev/null
+++ b/library/cpp/balloc/balloc.cpp
@@ -0,0 +1,308 @@
+#include <library/cpp/balloc/lib/balloc.h>
+#include <errno.h>
+
+namespace NBalloc {
+
+ static constexpr size_t ALIVE_SIGNATURE = 0xaULL << 56;
+ static constexpr size_t DISABLED_SIGNATURE = 0xbULL << 56;
+ static constexpr size_t SIGNATURE_MASK = 0xfULL << 56;
+
+ static constexpr size_t MINIMAL_ALIGNMENT = sizeof(NBalloc::TAllocHeader);
+ static_assert(((MINIMAL_ALIGNMENT - 1) & MINIMAL_ALIGNMENT) == 0,
+ "invalid BALLOC_MINIMAL_ALIGNMENT");
+
+ static Y_FORCE_INLINE void* Malloc(size_t size) {
+ TLS& ltls = tls;
+ size = Align(size, sizeof(TAllocHeader));
+ if (Y_UNLIKELY(ltls.Mode == Empty || ltls.Mode == ToBeEnabled)) {
+ Init(ltls);
+ }
+ if (Y_LIKELY(ltls.Mode != Disabled)) {
+ TAllocHeader* allocHeader = AllocateRaw(size, ALIVE_SIGNATURE);
+ return allocHeader + 1;
+ } else {
+ // ltls.Mode == Disabled
+ const size_t extsize = size + sizeof(TAllocHeader);
+ TAllocHeader* allocHeader = (TAllocHeader*)LibcMalloc(extsize);
+ allocHeader->Encode(allocHeader, size, DISABLED_SIGNATURE);
+ return allocHeader + 1;
+ }
+ }
+
+ static void Y_FORCE_INLINE Free(void* ptr) {
+ if (ptr == nullptr) {
+ return;
+ }
+ TAllocHeader* allocHeader = ((TAllocHeader*)ptr) - 1;
+ size_t size = allocHeader->AllocSize;
+ const size_t signature = size & SIGNATURE_MASK;
+ if (Y_LIKELY(signature == ALIVE_SIGNATURE)) {
+ allocHeader->AllocSize = 0; // abort later on double free
+#ifdef DBG_FILL_MEMORY
+ memset(ptr, 0xde, size - signature);
+#endif
+ FreeRaw(allocHeader->Block);
+ if (NAllocStats::IsEnabled()) {
+ NAllocStats::DecThreadAllocStats(size - signature);
+ }
+ } else if (signature == DISABLED_SIGNATURE) {
+ LibcFree(allocHeader->Block);
+ } else {
+ NMalloc::AbortFromCorruptedAllocator();
+ }
+ }
+
+ static bool Y_FORCE_INLINE IsOwnedByBalloc(void* ptr) {
+ TAllocHeader* allocHeader = ((TAllocHeader*)ptr) - 1;
+ size_t size = allocHeader->AllocSize;
+ const size_t signature = size & SIGNATURE_MASK;
+ if (signature == ALIVE_SIGNATURE) {
+ return true;
+ } else if (signature == DISABLED_SIGNATURE) {
+ return false;
+ }
+ NMalloc::AbortFromCorruptedAllocator();
+ Y_UNREACHABLE();
+ }
+
+ static void Y_FORCE_INLINE Disable() {
+#if defined(_musl_)
+ // just skip it
+#else
+ tls.Mode = Disabled;
+#endif
+ }
+
+ static void Y_FORCE_INLINE Enable() {
+ tls.Mode = ToBeEnabled;
+ }
+
+ static bool Y_FORCE_INLINE IsDisabled() {
+ return tls.Mode == Disabled;
+ }
+};
+
+#if defined(Y_COVER_PTR)
+void* CoverPtr(void* ptr, size_t len) noexcept;
+void* UncoverPtr(void* ptr) noexcept;
+#endif
+
+extern "C" void* malloc(size_t size) {
+#if defined(Y_COVER_PTR)
+ return CoverPtr(NBalloc::Malloc(size + 32), size);
+#else
+ return NBalloc::Malloc(size);
+#endif
+}
+
+extern "C" void free(void* data) {
+#if defined(Y_COVER_PTR)
+ NBalloc::Free(UncoverPtr(data));
+#else
+ NBalloc::Free(data);
+#endif
+}
+
+#if defined(USE_INTELCC) || defined(_darwin_) || defined(_freebsd_) || defined(_STLPORT_VERSION)
+#define OP_THROWNOTHING noexcept
+#else
+#define OP_THROWNOTHING
+#endif
+
+void* operator new(size_t size) {
+#if defined(Y_COVER_PTR)
+ return malloc(size);
+#else
+ return NBalloc::Malloc(size);
+#endif
+}
+
+int posix_memalign(void** memptr, const size_t alignment, const size_t size) {
+#if defined(Y_COVER_PTR)
+ (void)alignment;
+ *memptr = malloc(size);
+ return 0;
+#else
+ if (((alignment - 1) & alignment) != 0 || alignment < sizeof(void*)) {
+ return EINVAL;
+ }
+ if (alignment <= NBalloc::MINIMAL_ALIGNMENT) {
+ *memptr = NBalloc::Malloc(size);
+ return 0;
+ }
+ size_t bigSize = size + alignment - NBalloc::MINIMAL_ALIGNMENT;
+ void* res = NBalloc::Malloc(bigSize);
+ void* alignedPtr = (void*)NBalloc::Align((size_t)res, alignment);
+ if (alignedPtr != res) {
+ auto oldAllocHeader = (NBalloc::TAllocHeader*)res - 1;
+ auto newAllocHeader = (NBalloc::TAllocHeader*)alignedPtr - 1;
+ void* block = oldAllocHeader->Block;
+ newAllocHeader->Encode(block, size, NBalloc::ALIVE_SIGNATURE);
+ }
+ *memptr = alignedPtr;
+ return 0;
+#endif
+}
+
+void* operator new(size_t size, const std::nothrow_t&) OP_THROWNOTHING {
+#if defined(Y_COVER_PTR)
+ return malloc(size);
+#else
+ return NBalloc::Malloc(size);
+#endif
+}
+
+void operator delete(void* p)OP_THROWNOTHING {
+#if defined(Y_COVER_PTR)
+ free(p);
+#else
+ NBalloc::Free(p);
+#endif
+}
+
+void operator delete(void* p, const std::nothrow_t&)OP_THROWNOTHING {
+#if defined(Y_COVER_PTR)
+ free(p);
+#else
+ NBalloc::Free(p);
+#endif
+}
+
+void* operator new[](size_t size) {
+#if defined(Y_COVER_PTR)
+ return malloc(size);
+#else
+ return NBalloc::Malloc(size);
+#endif
+}
+
+void* operator new[](size_t size, const std::nothrow_t&) OP_THROWNOTHING {
+#if defined(Y_COVER_PTR)
+ return malloc(size);
+#else
+ return NBalloc::Malloc(size);
+#endif
+}
+
+void operator delete[](void* p) OP_THROWNOTHING {
+#if defined(Y_COVER_PTR)
+ free(p);
+#else
+ NBalloc::Free(p);
+#endif
+}
+
+void operator delete[](void* p, const std::nothrow_t&) OP_THROWNOTHING {
+#if defined(Y_COVER_PTR)
+ free(p);
+#else
+ NBalloc::Free(p);
+#endif
+}
+
+extern "C" void* calloc(size_t n, size_t elemSize) {
+ const size_t size = n * elemSize;
+
+ if (elemSize != 0 && size / elemSize != n) {
+ return nullptr;
+ }
+
+#if defined(Y_COVER_PTR)
+ void* result = malloc(size);
+#else
+ void* result = NBalloc::Malloc(size);
+#endif
+
+ if (result) {
+ memset(result, 0, size);
+ }
+
+ return result;
+}
+
+extern "C" void cfree(void* ptr) {
+#if defined(Y_COVER_PTR)
+ free(ptr);
+#else
+ NBalloc::Free(ptr);
+#endif
+}
+
+#if defined(Y_COVER_PTR)
+static inline void* DoRealloc(void* oldPtr, size_t newSize) {
+#else
+extern "C" void* realloc(void* oldPtr, size_t newSize) {
+#endif
+ if (!oldPtr) {
+ void* result = NBalloc::Malloc(newSize);
+ return result;
+ }
+ if (newSize == 0) {
+ NBalloc::Free(oldPtr);
+ return nullptr;
+ }
+ void* newPtr = NBalloc::Malloc(newSize);
+ if (!newPtr) {
+ return nullptr;
+ }
+ NBalloc::TAllocHeader* header = (NBalloc::TAllocHeader*)oldPtr - 1;
+ const size_t oldSize = header->AllocSize & ~NBalloc::SIGNATURE_MASK;
+ const size_t signature = header->AllocSize & NBalloc::SIGNATURE_MASK;
+ if (Y_LIKELY((signature == NBalloc::ALIVE_SIGNATURE) || (signature == NBalloc::DISABLED_SIGNATURE))) {
+ memcpy(newPtr, oldPtr, oldSize < newSize ? oldSize : newSize);
+ NBalloc::Free(oldPtr);
+ return newPtr;
+ }
+ NMalloc::AbortFromCorruptedAllocator();
+ return nullptr;
+}
+
+#if defined(Y_COVER_PTR)
+extern "C" void* realloc(void* oldPtr, size_t newSize) {
+ if (!oldPtr) {
+ return malloc(newSize);
+ }
+
+ if (!newSize) {
+ free(oldPtr);
+
+ return nullptr;
+ }
+
+ return CoverPtr(DoRealloc(UncoverPtr(oldPtr), newSize + 32), newSize);
+}
+#endif
+
+// Only for testing purposes. Never use in production.
+extern "C" bool IsOwnedByBalloc(void* ptr) {
+ return NBalloc::IsOwnedByBalloc(ptr);
+}
+
+extern "C" bool BallocDisabled() {
+ return NBalloc::IsDisabled();
+}
+
+extern "C" void DisableBalloc() {
+ NBalloc::Disable();
+}
+
+extern "C" void EnableBalloc() {
+ NBalloc::Enable();
+}
+
+extern "C" void* memalign(size_t alignment, size_t size) {
+ void* ptr;
+ int res = posix_memalign(&ptr, alignment, size);
+ return res ? nullptr : ptr;
+}
+
+extern "C" void* valloc(size_t size) {
+ return memalign(NBalloc::PAGE_ELEM, size);
+}
+
+#if !defined(_MSC_VER) && !defined(_freebsd_)
+// Workaround for pthread_create bug in linux.
+extern "C" void* __libc_memalign(size_t alignment, size_t size) {
+ return memalign(alignment, size);
+}
+#endif
diff --git a/library/cpp/balloc/malloc-info.cpp b/library/cpp/balloc/malloc-info.cpp
new file mode 100644
index 0000000000..604b1fb145
--- /dev/null
+++ b/library/cpp/balloc/malloc-info.cpp
@@ -0,0 +1,41 @@
+#include <library/cpp/malloc/api/malloc.h>
+
+#include <string.h>
+
+using namespace NMalloc;
+
+extern "C" void DisableBalloc();
+extern "C" void EnableBalloc();
+extern "C" bool BallocDisabled();
+
+namespace {
+ bool SetAllocParam(const char* name, const char* value) {
+ if (strcmp(name, "disable") == 0) {
+ if (value == nullptr || strcmp(value, "false") != 0) {
+ // all values other than "false" are considred to be "true" for compatibility
+ DisableBalloc();
+ } else {
+ EnableBalloc();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ bool CheckAllocParam(const char* name, bool defaultValue) {
+ if (strcmp(name, "disable") == 0) {
+ return BallocDisabled();
+ }
+ return defaultValue;
+ }
+}
+
+TMallocInfo NMalloc::MallocInfo() {
+ TMallocInfo r;
+
+ r.Name = "balloc";
+ r.SetParam = SetAllocParam;
+ r.CheckParam = CheckAllocParam;
+
+ return r;
+}
diff --git a/library/cpp/balloc/optional/operators.cpp b/library/cpp/balloc/optional/operators.cpp
new file mode 100644
index 0000000000..79f74a5806
--- /dev/null
+++ b/library/cpp/balloc/optional/operators.cpp
@@ -0,0 +1 @@
+#include "operators.h"
diff --git a/library/cpp/balloc/optional/operators.h b/library/cpp/balloc/optional/operators.h
new file mode 100644
index 0000000000..6107d28a6e
--- /dev/null
+++ b/library/cpp/balloc/optional/operators.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <library/cpp/malloc/api/malloc.h>
+#include <util/string/type.h>
+
+inline bool BallocEnabled() {
+ return !::NMalloc::MallocInfo().CheckParam("disable", true);
+}
+
+inline void ThreadDisableBalloc() {
+ ::NMalloc::MallocInfo().SetParam("disable", "true");
+}
+
+inline void ThreadEnableBalloc() {
+ ::NMalloc::MallocInfo().SetParam("disable", "false");
+}
diff --git a/library/cpp/balloc/optional/ya.make b/library/cpp/balloc/optional/ya.make
new file mode 100644
index 0000000000..f740fc0b7d
--- /dev/null
+++ b/library/cpp/balloc/optional/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(ivanmorozov)
+
+SRCS(
+ operators.cpp
+)
+
+PEERDIR(
+ library/cpp/malloc/api
+)
+
+END()
+
+NEED_CHECK()
diff --git a/library/cpp/balloc/ya.make b/library/cpp/balloc/ya.make
new file mode 100644
index 0000000000..d4457fbba9
--- /dev/null
+++ b/library/cpp/balloc/ya.make
@@ -0,0 +1,28 @@
+LIBRARY()
+
+OWNER(
+ ironpeter
+ g:base
+)
+
+NO_UTIL()
+NO_COMPILER_WARNINGS()
+
+IF (OS_WINDOWS)
+ PEERDIR(
+ library/cpp/lfalloc
+ )
+ELSE()
+ SRCS(
+ balloc.cpp
+ malloc-info.cpp
+ )
+
+ PEERDIR(
+ library/cpp/balloc/lib
+ )
+ENDIF()
+
+END()
+
+NEED_CHECK()
diff --git a/library/cpp/binsaver/bin_saver.cpp b/library/cpp/binsaver/bin_saver.cpp
new file mode 100644
index 0000000000..fe0775af9f
--- /dev/null
+++ b/library/cpp/binsaver/bin_saver.cpp
@@ -0,0 +1,81 @@
+#include "bin_saver.h"
+
+TClassFactory<IObjectBase>* pSaverClasses;
+void StartRegisterSaveload() {
+ if (!pSaverClasses)
+ pSaverClasses = new TClassFactory<IObjectBase>;
+}
+struct SBasicChunkInit {
+ ~SBasicChunkInit() {
+ if (pSaverClasses)
+ delete pSaverClasses;
+ }
+} initSaver;
+
+//////////////////////////////////////////////////////////////////////////
+void IBinSaver::StoreObject(IObjectBase* pObject) {
+ if (pObject) {
+ Y_ASSERT(pSaverClasses->GetObjectTypeID(pObject) != -1 && "trying to save unregistered object");
+ }
+
+ ui64 ptrId = ((char*)pObject) - ((char*)nullptr);
+ if (StableOutput) {
+ ui32 id = 0;
+ if (pObject) {
+ if (!PtrIds.Get())
+ PtrIds.Reset(new PtrIdHash);
+ PtrIdHash::iterator pFound = PtrIds->find(pObject);
+ if (pFound != PtrIds->end())
+ id = pFound->second;
+ else {
+ id = PtrIds->ysize() + 1;
+ PtrIds->insert(std::make_pair(pObject, id));
+ }
+ }
+ ptrId = id;
+ }
+
+ DataChunk(&ptrId, sizeof(ptrId));
+ if (!Objects.Get())
+ Objects.Reset(new CObjectsHash);
+ if (ptrId != 0 && Objects->find(ptrId) == Objects->end()) {
+ ObjectQueue.push_back(pObject);
+ (*Objects)[ptrId];
+ int typeId = pSaverClasses->GetObjectTypeID(pObject);
+ if (typeId == -1) {
+ fprintf(stderr, "IBinSaver: trying to save unregistered object\n");
+ abort();
+ }
+ DataChunk(&typeId, sizeof(typeId));
+ }
+}
+
+IObjectBase* IBinSaver::LoadObject() {
+ ui64 ptrId = 0;
+ DataChunk(&ptrId, sizeof(ptrId));
+ if (ptrId != 0) {
+ if (!Objects.Get())
+ Objects.Reset(new CObjectsHash);
+ CObjectsHash::iterator pFound = Objects->find(ptrId);
+ if (pFound != Objects->end())
+ return pFound->second;
+ int typeId;
+ DataChunk(&typeId, sizeof(typeId));
+ IObjectBase* pObj = pSaverClasses->CreateObject(typeId);
+ Y_ASSERT(pObj != nullptr);
+ if (pObj == nullptr) {
+ fprintf(stderr, "IBinSaver: trying to load unregistered object\n");
+ abort();
+ }
+ (*Objects)[ptrId] = pObj;
+ ObjectQueue.push_back(pObj);
+ return pObj;
+ }
+ return nullptr;
+}
+
+IBinSaver::~IBinSaver() {
+ for (size_t i = 0; i < ObjectQueue.size(); ++i) {
+ AddPolymorphicBase(1, ObjectQueue[i]);
+ }
+}
diff --git a/library/cpp/binsaver/bin_saver.h b/library/cpp/binsaver/bin_saver.h
new file mode 100644
index 0000000000..412424889f
--- /dev/null
+++ b/library/cpp/binsaver/bin_saver.h
@@ -0,0 +1,646 @@
+#pragma once
+
+#include "buffered_io.h"
+#include "class_factory.h"
+
+#include <library/cpp/containers/2d_array/2d_array.h>
+
+#include <util/generic/hash_set.h>
+#include <util/generic/buffer.h>
+#include <util/generic/list.h>
+#include <util/generic/maybe.h>
+#include <util/generic/bitmap.h>
+#include <util/generic/variant.h>
+#include <util/generic/ylimits.h>
+#include <util/memory/blob.h>
+#include <util/digest/murmur.h>
+
+#include <array>
+#include <bitset>
+#include <list>
+#include <string>
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4127)
+#endif
+
+enum ESaverMode {
+ SAVER_MODE_READ = 1,
+ SAVER_MODE_WRITE = 2,
+ SAVER_MODE_WRITE_COMPRESSED = 3,
+};
+
+namespace NBinSaverInternals {
+ // This lets explicitly control the overload resolution priority
+ // The higher P means higher priority in overload resolution order
+ template <int P>
+ struct TOverloadPriority : TOverloadPriority <P-1> {
+ };
+
+ template <>
+ struct TOverloadPriority<0> {
+ };
+}
+
+//////////////////////////////////////////////////////////////////////////
+struct IBinSaver {
+public:
+ typedef unsigned char chunk_id;
+ typedef ui32 TStoredSize; // changing this will break compatibility
+
+private:
+ // This overload is required to avoid infinite recursion when overriding serialization in derived classes:
+ // struct B {
+ // virtual int operator &(IBinSaver& f) {
+ // return 0;
+ // }
+ // };
+ //
+ // struct D : B {
+ // int operator &(IBinSaver& f) override {
+ // f.Add(0, static_cast<B*>(this));
+ // return 0;
+ // }
+ // };
+ template <class T, typename = decltype(std::declval<T*>()->T::operator&(std::declval<IBinSaver&>()))>
+ void CallObjectSerialize(T* p, NBinSaverInternals::TOverloadPriority<2>) { // highest priority - will be resolved first if enabled
+ // Note: p->operator &(*this) would lead to infinite recursion
+ p->T::operator&(*this);
+ }
+
+ template <class T, typename = decltype(std::declval<T&>() & std::declval<IBinSaver&>())>
+ void CallObjectSerialize(T* p, NBinSaverInternals::TOverloadPriority<1>) { // lower priority - will be resolved second if enabled
+ (*p) & (*this);
+ }
+
+ template <class T>
+ void CallObjectSerialize(T* p, NBinSaverInternals::TOverloadPriority<0>) { // lower priority - will be resolved last
+#if (!defined(_MSC_VER))
+ // In MSVC __has_trivial_copy returns false to enums, primitive types and arrays.
+ static_assert(__has_trivial_copy(T), "Class is nontrivial copyable, you must define operator&, see");
+#endif
+ DataChunk(p, sizeof(T));
+ }
+
+ // vector
+ template <class T, class TA>
+ void DoVector(TVector<T, TA>& data) {
+ TStoredSize nSize;
+ if (IsReading()) {
+ data.clear();
+ Add(2, &nSize);
+ data.resize(nSize);
+ } else {
+ nSize = data.size();
+ CheckOverflow(nSize, data.size());
+ Add(2, &nSize);
+ }
+ for (TStoredSize i = 0; i < nSize; i++)
+ Add(1, &data[i]);
+ }
+
+ template <class T, int N>
+ void DoArray(T (&data)[N]) {
+ for (size_t i = 0; i < N; i++) {
+ Add(1, &(data[i]));
+ }
+ }
+
+ template <typename TLarge>
+ void CheckOverflow(TStoredSize nSize, TLarge origSize) {
+ if (nSize != origSize) {
+ fprintf(stderr, "IBinSaver: object size is too large to be serialized (%" PRIu32 " != %" PRIu64 ")\n", nSize, (ui64)origSize);
+ abort();
+ }
+ }
+
+ template <class T, class TA>
+ void DoDataVector(TVector<T, TA>& data) {
+ TStoredSize nSize = data.size();
+ CheckOverflow(nSize, data.size());
+ Add(1, &nSize);
+ if (IsReading()) {
+ data.clear();
+ data.resize(nSize);
+ }
+ if (nSize > 0)
+ DataChunk(&data[0], sizeof(T) * nSize);
+ }
+
+ template <class AM>
+ void DoAnyMap(AM& data) {
+ if (IsReading()) {
+ data.clear();
+ TStoredSize nSize;
+ Add(3, &nSize);
+ TVector<typename AM::key_type, typename std::allocator_traits<typename AM::allocator_type>::template rebind_alloc<typename AM::key_type>> indices;
+ indices.resize(nSize);
+ for (TStoredSize i = 0; i < nSize; ++i)
+ Add(1, &indices[i]);
+ for (TStoredSize i = 0; i < nSize; ++i)
+ Add(2, &data[indices[i]]);
+ } else {
+ TStoredSize nSize = data.size();
+ CheckOverflow(nSize, data.size());
+ Add(3, &nSize);
+
+ TVector<typename AM::key_type, typename std::allocator_traits<typename AM::allocator_type>::template rebind_alloc<typename AM::key_type>> indices;
+ indices.resize(nSize);
+ TStoredSize i = 1;
+ for (auto pos = data.begin(); pos != data.end(); ++pos, ++i)
+ indices[nSize - i] = pos->first;
+ for (TStoredSize j = 0; j < nSize; ++j)
+ Add(1, &indices[j]);
+ for (TStoredSize j = 0; j < nSize; ++j)
+ Add(2, &data[indices[j]]);
+ }
+ }
+
+ // hash_multimap
+ template <class AMM>
+ void DoAnyMultiMap(AMM& data) {
+ if (IsReading()) {
+ data.clear();
+ TStoredSize nSize;
+ Add(3, &nSize);
+ TVector<typename AMM::key_type, typename std::allocator_traits<typename AMM::allocator_type>::template rebind_alloc<typename AMM::key_type>> indices;
+ indices.resize(nSize);
+ for (TStoredSize i = 0; i < nSize; ++i)
+ Add(1, &indices[i]);
+ for (TStoredSize i = 0; i < nSize; ++i) {
+ std::pair<typename AMM::key_type, typename AMM::mapped_type> valToInsert;
+ valToInsert.first = indices[i];
+ Add(2, &valToInsert.second);
+ data.insert(valToInsert);
+ }
+ } else {
+ TStoredSize nSize = data.size();
+ CheckOverflow(nSize, data.size());
+ Add(3, &nSize);
+ for (auto pos = data.begin(); pos != data.end(); ++pos)
+ Add(1, (typename AMM::key_type*)(&pos->first));
+ for (auto pos = data.begin(); pos != data.end(); ++pos)
+ Add(2, &pos->second);
+ }
+ }
+
+ template <class T>
+ void DoAnySet(T& data) {
+ if (IsReading()) {
+ data.clear();
+ TStoredSize nSize;
+ Add(2, &nSize);
+ for (TStoredSize i = 0; i < nSize; ++i) {
+ typename T::value_type member;
+ Add(1, &member);
+ data.insert(member);
+ }
+ } else {
+ TStoredSize nSize = data.size();
+ CheckOverflow(nSize, data.size());
+ Add(2, &nSize);
+ for (const auto& elem : data) {
+ auto member = elem;
+ Add(1, &member);
+ }
+ }
+ }
+
+ // 2D array
+ template <class T>
+ void Do2DArray(TArray2D<T>& a) {
+ int nXSize = a.GetXSize(), nYSize = a.GetYSize();
+ Add(1, &nXSize);
+ Add(2, &nYSize);
+ if (IsReading())
+ a.SetSizes(nXSize, nYSize);
+ for (int i = 0; i < nXSize * nYSize; i++)
+ Add(3, &a[i / nXSize][i % nXSize]);
+ }
+ template <class T>
+ void Do2DArrayData(TArray2D<T>& a) {
+ int nXSize = a.GetXSize(), nYSize = a.GetYSize();
+ Add(1, &nXSize);
+ Add(2, &nYSize);
+ if (IsReading())
+ a.SetSizes(nXSize, nYSize);
+ if (nXSize * nYSize > 0)
+ DataChunk(&a[0][0], sizeof(T) * nXSize * nYSize);
+ }
+ // strings
+ template <class TStringType>
+ void DataChunkStr(TStringType& data, i64 elemSize) {
+ if (bRead) {
+ TStoredSize nCount = 0;
+ File.Read(&nCount, sizeof(TStoredSize));
+ data.resize(nCount);
+ if (nCount)
+ File.Read(&*data.begin(), nCount * elemSize);
+ } else {
+ TStoredSize nCount = data.size();
+ CheckOverflow(nCount, data.size());
+ File.Write(&nCount, sizeof(TStoredSize));
+ File.Write(data.c_str(), nCount * elemSize);
+ }
+ }
+ void DataChunkString(std::string& data) {
+ DataChunkStr(data, sizeof(char));
+ }
+ void DataChunkStroka(TString& data) {
+ DataChunkStr(data, sizeof(TString::char_type));
+ }
+ void DataChunkWtroka(TUtf16String& data) {
+ DataChunkStr(data, sizeof(wchar16));
+ }
+
+ void DataChunk(void* pData, i64 nSize) {
+ i64 chunkSize = 1 << 30;
+ for (i64 offset = 0; offset < nSize; offset += chunkSize) {
+ void* ptr = (char*)pData + offset;
+ i64 size = offset + chunkSize < nSize ? chunkSize : (nSize - offset);
+ if (bRead)
+ File.Read(ptr, size);
+ else
+ File.Write(ptr, size);
+ }
+ }
+
+ // storing/loading pointers to objects
+ void StoreObject(IObjectBase* pObject);
+ IObjectBase* LoadObject();
+
+ bool bRead;
+ TBufferedStream<> File;
+ // maps objects addresses during save(first) to addresses during load(second) - during loading
+ // or serves as a sign that some object has been already stored - during storing
+ bool StableOutput;
+
+ typedef THashMap<void*, ui32> PtrIdHash;
+ TAutoPtr<PtrIdHash> PtrIds;
+
+ typedef THashMap<ui64, TPtr<IObjectBase>> CObjectsHash;
+ TAutoPtr<CObjectsHash> Objects;
+
+ TVector<IObjectBase*> ObjectQueue;
+
+public:
+ bool IsReading() {
+ return bRead;
+ }
+ void AddRawData(const chunk_id, void* pData, i64 nSize) {
+ DataChunk(pData, nSize);
+ }
+
+ // return type of Add() is used to detect specialized serializer (see HasNonTrivialSerializer below)
+ template <class T>
+ char Add(const chunk_id, T* p) {
+ CallObjectSerialize(p, NBinSaverInternals::TOverloadPriority<2>());
+ return 0;
+ }
+ int Add(const chunk_id, std::string* pStr) {
+ DataChunkString(*pStr);
+ return 0;
+ }
+ int Add(const chunk_id, TString* pStr) {
+ DataChunkStroka(*pStr);
+ return 0;
+ }
+ int Add(const chunk_id, TUtf16String* pStr) {
+ DataChunkWtroka(*pStr);
+ return 0;
+ }
+ int Add(const chunk_id, TBlob* blob) {
+ if (bRead) {
+ ui64 size = 0;
+ File.Read(&size, sizeof(size));
+ TBuffer buffer;
+ buffer.Advance(size);
+ if (size > 0)
+ File.Read(buffer.Data(), buffer.Size());
+ (*blob) = TBlob::FromBuffer(buffer);
+ } else {
+ const ui64 size = blob->Size();
+ File.Write(&size, sizeof(size));
+ File.Write(blob->Data(), blob->Size());
+ }
+ return 0;
+ }
+ template <class T1, class TA>
+ int Add(const chunk_id, TVector<T1, TA>* pVec) {
+ if (HasNonTrivialSerializer<T1>(0u))
+ DoVector(*pVec);
+ else
+ DoDataVector(*pVec);
+ return 0;
+ }
+
+ template <class T, int N>
+ int Add(const chunk_id, T (*pVec)[N]) {
+ if (HasNonTrivialSerializer<T>(0u))
+ DoArray(*pVec);
+ else
+ DataChunk(pVec, sizeof(*pVec));
+ return 0;
+ }
+
+ template <class T1, class T2, class T3, class T4>
+ int Add(const chunk_id, TMap<T1, T2, T3, T4>* pMap) {
+ DoAnyMap(*pMap);
+ return 0;
+ }
+ template <class T1, class T2, class T3, class T4, class T5>
+ int Add(const chunk_id, THashMap<T1, T2, T3, T4, T5>* pHash) {
+ DoAnyMap(*pHash);
+ return 0;
+ }
+ template <class T1, class T2, class T3, class T4, class T5>
+ int Add(const chunk_id, THashMultiMap<T1, T2, T3, T4, T5>* pHash) {
+ DoAnyMultiMap(*pHash);
+ return 0;
+ }
+ template <class K, class L, class A>
+ int Add(const chunk_id, TSet<K, L, A>* pSet) {
+ DoAnySet(*pSet);
+ return 0;
+ }
+ template <class T1, class T2, class T3, class T4>
+ int Add(const chunk_id, THashSet<T1, T2, T3, T4>* pHash) {
+ DoAnySet(*pHash);
+ return 0;
+ }
+
+ template <class T1>
+ int Add(const chunk_id, TArray2D<T1>* pArr) {
+ if (HasNonTrivialSerializer<T1>(0u))
+ Do2DArray(*pArr);
+ else
+ Do2DArrayData(*pArr);
+ return 0;
+ }
+ template <class T1>
+ int Add(const chunk_id, TList<T1>* pList) {
+ TList<T1>& data = *pList;
+ if (IsReading()) {
+ int nSize;
+ Add(2, &nSize);
+ data.clear();
+ data.insert(data.begin(), nSize, T1());
+ } else {
+ int nSize = data.size();
+ Add(2, &nSize);
+ }
+ int i = 1;
+ for (typename TList<T1>::iterator k = data.begin(); k != data.end(); ++k, ++i)
+ Add(i + 2, &(*k));
+ return 0;
+ }
+ template <class T1, class T2>
+ int Add(const chunk_id, std::pair<T1, T2>* pData) {
+ Add(1, &(pData->first));
+ Add(2, &(pData->second));
+ return 0;
+ }
+
+ template <class T1, size_t N>
+ int Add(const chunk_id, std::array<T1, N>* pData) {
+ if (HasNonTrivialSerializer<T1>(0u)) {
+ for (size_t i = 0; i < N; ++i)
+ Add(1, &(*pData)[i]);
+ } else {
+ DataChunk((void*)pData->data(), pData->size() * sizeof(T1));
+ }
+ return 0;
+ }
+
+ template <size_t N>
+ int Add(const chunk_id, std::bitset<N>* pData) {
+ if (IsReading()) {
+ std::string s;
+ Add(1, &s);
+ *pData = std::bitset<N>(s);
+ } else {
+ std::string s = pData->template to_string<char, std::char_traits<char>, std::allocator<char>>();
+ Add(1, &s);
+ }
+ return 0;
+ }
+
+ int Add(const chunk_id, TDynBitMap* pData) {
+ if (IsReading()) {
+ ui64 count = 0;
+ Add(1, &count);
+ pData->Clear();
+ pData->Reserve(count * sizeof(TDynBitMap::TChunk) * 8);
+ for (ui64 i = 0; i < count; ++i) {
+ TDynBitMap::TChunk chunk = 0;
+ Add(i + 1, &chunk);
+ if (i > 0) {
+ pData->LShift(8 * sizeof(TDynBitMap::TChunk));
+ }
+ pData->Or(chunk);
+ }
+ } else {
+ ui64 count = pData->GetChunkCount();
+ Add(1, &count);
+ for (ui64 i = 0; i < count; ++i) {
+ // Write in reverse order
+ TDynBitMap::TChunk chunk = pData->GetChunks()[count - i - 1];
+ Add(i + 1, &chunk);
+ }
+ }
+ return 0;
+ }
+
+ template <class TVariantClass>
+ struct TLoadFromTypeFromListHelper {
+ template <class T0, class... TTail>
+ static void Do(IBinSaver& binSaver, ui32 typeIndex, TVariantClass* pData) {
+ if constexpr (sizeof...(TTail) == 0) {
+ Y_ASSERT(typeIndex == 0);
+ T0 chunk;
+ binSaver.Add(2, &chunk);
+ *pData = std::move(chunk);
+ } else {
+ if (typeIndex == 0) {
+ Do<T0>(binSaver, 0, pData);
+ } else {
+ Do<TTail...>(binSaver, typeIndex - 1, pData);
+ }
+ }
+ }
+ };
+
+ template <class... TVariantTypes>
+ int Add(const chunk_id, std::variant<TVariantTypes...>* pData) {
+ static_assert(std::variant_size_v<std::variant<TVariantTypes...>> < Max<ui32>());
+
+ ui32 index;
+ if (IsReading()) {
+ Add(1, &index);
+ TLoadFromTypeFromListHelper<std::variant<TVariantTypes...>>::template Do<TVariantTypes...>(
+ *this,
+ index,
+ pData
+ );
+ } else {
+ index = pData->index(); // type cast is safe because of static_assert check above
+ Add(1, &index);
+ std::visit([&](auto& dst) -> void { Add(2, &dst); }, *pData);
+ }
+ return 0;
+ }
+
+
+ void AddPolymorphicBase(chunk_id, IObjectBase* pObject) {
+ (*pObject) & (*this);
+ }
+
+ template <class T1, class T2>
+ void DoPtr(TPtrBase<T1, T2>* pData) {
+ if (pData && pData->Get()) {
+ }
+ if (IsReading())
+ pData->Set(CastToUserObject(LoadObject(), (T1*)nullptr));
+ else
+ StoreObject(pData->GetBarePtr());
+ }
+ template <class T, class TPolicy>
+ int Add(const chunk_id, TMaybe<T, TPolicy>* pData) {
+ TMaybe<T, TPolicy>& data = *pData;
+ if (IsReading()) {
+ bool defined = false;
+ Add(1, &defined);
+ if (defined) {
+ data = T();
+ Add(2, data.Get());
+ }
+ } else {
+ bool defined = data.Defined();
+ Add(1, &defined);
+ if (defined) {
+ Add(2, data.Get());
+ }
+ }
+ return 0;
+ }
+
+ template <typename TOne>
+ void AddMulti(TOne& one) {
+ Add(0, &one);
+ }
+
+ template <typename THead, typename... TTail>
+ void AddMulti(THead& head, TTail&... tail) {
+ Add(0, &head);
+ AddMulti(tail...);
+ }
+
+ template <class T, typename = decltype(std::declval<T&>() & std::declval<IBinSaver&>())>
+ static bool HasNonTrivialSerializer(ui32) {
+ return true;
+ }
+
+ template <class T>
+ static bool HasNonTrivialSerializer(...) {
+ return sizeof(std::declval<IBinSaver*>()->Add(0, std::declval<T*>())) != 1;
+ }
+
+public:
+ IBinSaver(IBinaryStream& stream, bool _bRead, bool stableOutput = false)
+ : bRead(_bRead)
+ , File(_bRead, stream)
+ , StableOutput(stableOutput)
+ {
+ }
+ virtual ~IBinSaver();
+ bool IsValid() const {
+ return File.IsValid();
+ }
+};
+
+// realisation of forward declared serialisation operator
+template <class TUserObj, class TRef>
+int TPtrBase<TUserObj, TRef>::operator&(IBinSaver& f) {
+ f.DoPtr(this);
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+extern TClassFactory<IObjectBase>* pSaverClasses;
+void StartRegisterSaveload();
+
+template <class TReg>
+struct TRegisterSaveLoadType {
+ TRegisterSaveLoadType(int num) {
+ StartRegisterSaveload();
+ pSaverClasses->RegisterType(num, TReg::NewSaveLoadNullItem, (TReg*)nullptr);
+ }
+};
+
+#define Y_BINSAVER_REGISTER(name) \
+ BASIC_REGISTER_CLASS(name) \
+ static TRegisterSaveLoadType<name> init##name(MurmurHash<int>(#name, sizeof(#name)));
+
+#define REGISTER_SAVELOAD_CLASS(N, name) \
+ BASIC_REGISTER_CLASS(name) \
+ static TRegisterSaveLoadType<name> init##name##N(N);
+
+// using TObj/TRef on forward declared templ class will not work
+// but multiple registration with same id is allowed
+#define REGISTER_SAVELOAD_TEMPL1_CLASS(N, className, T) \
+ static TRegisterSaveLoadType<className<T>> init##className##T##N(N);
+
+#define REGISTER_SAVELOAD_TEMPL2_CLASS(N, className, T1, T2) \
+ typedef className<T1, T2> temp##className##T1##_##T2##temp; \
+ static TRegisterSaveLoadType<className<T1, T2>> init##className##T1##_##T2##N(N);
+
+#define REGISTER_SAVELOAD_TEMPL3_CLASS(N, className, T1, T2, T3) \
+ typedef className<T1, T2, T3> temp##className##T1##_##T2##_##T3##temp; \
+ static TRegisterSaveLoadType<className<T1, T2, T3>> init##className##T1##_##T2##_##T3##N(N);
+
+#define REGISTER_SAVELOAD_NM_CLASS(N, nmspace, className) \
+ BASIC_REGISTER_CLASS(nmspace::className) \
+ static TRegisterSaveLoadType<nmspace::className> init_##nmspace##_##name##N(N);
+
+#define REGISTER_SAVELOAD_NM2_CLASS(N, nmspace1, nmspace2, className) \
+ BASIC_REGISTER_CLASS(nmspace1::nmspace2::className) \
+ static TRegisterSaveLoadType<nmspace1::nmspace2::className> init_##nmspace1##_##nmspace2##_##name##N(N);
+
+#define REGISTER_SAVELOAD_TEMPL1_NM_CLASS(N, nmspace, className, T) \
+ typedef nmspace::className<T> temp_init##nmspace##className##T##temp; \
+ BASIC_REGISTER_CLASS(nmspace::className<T>) \
+ static TRegisterSaveLoadType<nmspace::className<T>> temp_init##nmspace##_##name##T##N(N);
+
+#define REGISTER_SAVELOAD_CLASS_NAME(N, cls, name) \
+ BASIC_REGISTER_CLASS(cls) \
+ static TRegisterSaveLoadType<cls> init##name##N(N);
+
+#define REGISTER_SAVELOAD_CLASS_NS_PREF(N, cls, ns, pref) \
+ REGISTER_SAVELOAD_CLASS_NAME(N, ns ::cls, _##pref##_##cls)
+
+#define SAVELOAD(...) \
+ int operator&(IBinSaver& f) { \
+ f.AddMulti(__VA_ARGS__); \
+ return 0; \
+ }
+
+#define SAVELOAD_OVERRIDE_WITHOUT_BASE(...) \
+ int operator&(IBinSaver& f) override { \
+ f.AddMulti(__VA_ARGS__); \
+ return 0; \
+ }
+
+#define SAVELOAD_OVERRIDE(base, ...) \
+ int operator&(IBinSaver& f) override { \
+ base::operator&(f); \
+ f.AddMulti(__VA_ARGS__); \
+ return 0; \
+ }
+
+#define SAVELOAD_BASE(...) \
+ int operator&(IBinSaver& f) { \
+ TBase::operator&(f); \
+ f.AddMulti(__VA_ARGS__); \
+ return 0; \
+ }
diff --git a/library/cpp/binsaver/blob_io.cpp b/library/cpp/binsaver/blob_io.cpp
new file mode 100644
index 0000000000..ff10349e6f
--- /dev/null
+++ b/library/cpp/binsaver/blob_io.cpp
@@ -0,0 +1 @@
+#include "blob_io.h"
diff --git a/library/cpp/binsaver/blob_io.h b/library/cpp/binsaver/blob_io.h
new file mode 100644
index 0000000000..abe518ef30
--- /dev/null
+++ b/library/cpp/binsaver/blob_io.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "bin_saver.h"
+#include "buffered_io.h"
+
+#include <util/memory/blob.h>
+
+class TYaBlobStream: public IBinaryStream {
+ TBlob Blob;
+ i64 Pos;
+
+ int WriteImpl(const void*, int) override {
+ Y_ASSERT(0);
+ return 0;
+ }
+ int ReadImpl(void* userBuffer, int size) override {
+ if (size == 0)
+ return 0;
+ i64 res = Min<i64>(Blob.Length() - Pos, size);
+ if (res)
+ memcpy(userBuffer, ((const char*)Blob.Data()) + Pos, res);
+ Pos += res;
+ return res;
+ }
+ bool IsValid() const override {
+ return true;
+ }
+ bool IsFailed() const override {
+ return false;
+ }
+
+public:
+ TYaBlobStream(const TBlob& blob)
+ : Blob(blob)
+ , Pos(0)
+ {
+ }
+};
+
+template <class T>
+inline void SerializeBlob(const TBlob& data, T& c) {
+ TYaBlobStream f(data);
+ {
+ IBinSaver bs(f, true);
+ bs.Add(1, &c);
+ }
+}
diff --git a/library/cpp/binsaver/buffered_io.cpp b/library/cpp/binsaver/buffered_io.cpp
new file mode 100644
index 0000000000..dd88b04bc5
--- /dev/null
+++ b/library/cpp/binsaver/buffered_io.cpp
@@ -0,0 +1,39 @@
+#include "buffered_io.h"
+
+i64 IBinaryStream::LongWrite(const void* userBuffer, i64 size) {
+ Y_VERIFY(size >= 0, "IBinaryStream::Write() called with a negative buffer size.");
+
+ i64 leftToWrite = size;
+ while (leftToWrite != 0) {
+ int writeSz = static_cast<int>(Min<i64>(leftToWrite, std::numeric_limits<int>::max()));
+ int written = WriteImpl(userBuffer, writeSz);
+ Y_ASSERT(written <= writeSz);
+ leftToWrite -= written;
+ // Assumption: if WriteImpl(buf, writeSz) returns < writeSz, the stream is
+ // full and there's no sense in continuing.
+ if (written < writeSz)
+ break;
+ }
+ Y_ASSERT(size >= leftToWrite);
+ return size - leftToWrite;
+}
+
+i64 IBinaryStream::LongRead(void* userBuffer, i64 size) {
+ Y_VERIFY(size >= 0, "IBinaryStream::Read() called with a negative buffer size.");
+
+ i64 leftToRead = size;
+ while (leftToRead != 0) {
+ int readSz = static_cast<int>(Min<i64>(leftToRead, std::numeric_limits<int>::max()));
+ int read = ReadImpl(userBuffer, readSz);
+ Y_ASSERT(read <= readSz);
+ leftToRead -= read;
+ // Assumption: if ReadImpl(buf, readSz) returns < readSz, the stream is
+ // full and there's no sense in continuing.
+ if (read < readSz) {
+ memset(static_cast<char*>(userBuffer) + (size - leftToRead), 0, leftToRead);
+ break;
+ }
+ }
+ Y_ASSERT(size >= leftToRead);
+ return size - leftToRead;
+}
diff --git a/library/cpp/binsaver/buffered_io.h b/library/cpp/binsaver/buffered_io.h
new file mode 100644
index 0000000000..75465c9c5c
--- /dev/null
+++ b/library/cpp/binsaver/buffered_io.h
@@ -0,0 +1,134 @@
+#pragma once
+
+#include <util/system/yassert.h>
+#include <util/generic/utility.h>
+#include <util/generic/ylimits.h>
+#include <string.h>
+
+struct IBinaryStream {
+ virtual ~IBinaryStream() = default;
+ ;
+
+ inline i64 Write(const void* userBuffer, i64 size) {
+ if (size <= Max<int>()) {
+ return WriteImpl(userBuffer, static_cast<int>(size));
+ } else {
+ return LongWrite(userBuffer, size);
+ }
+ }
+
+ inline i64 Read(void* userBuffer, i64 size) {
+ if (size <= Max<int>()) {
+ return ReadImpl(userBuffer, static_cast<int>(size));
+ } else {
+ return LongRead(userBuffer, size);
+ }
+ }
+
+ virtual bool IsValid() const = 0;
+ virtual bool IsFailed() const = 0;
+
+private:
+ virtual int WriteImpl(const void* userBuffer, int size) = 0;
+ virtual int ReadImpl(void* userBuffer, int size) = 0;
+
+ i64 LongRead(void* userBuffer, i64 size);
+ i64 LongWrite(const void* userBuffer, i64 size);
+};
+
+template <int N_SIZE = 16384>
+class TBufferedStream {
+ char Buf[N_SIZE];
+ i64 Pos, BufSize;
+ IBinaryStream& Stream;
+ bool bIsReading, bIsEof, bFailed;
+
+ void ReadComplex(void* userBuffer, i64 size) {
+ if (bIsEof) {
+ memset(userBuffer, 0, size);
+ return;
+ }
+ char* dst = (char*)userBuffer;
+ i64 leftBytes = BufSize - Pos;
+ memcpy(dst, Buf + Pos, leftBytes);
+ dst += leftBytes;
+ size -= leftBytes;
+ Pos = BufSize = 0;
+ if (size > N_SIZE) {
+ i64 n = Stream.Read(dst, size);
+ bFailed = Stream.IsFailed();
+ if (n != size) {
+ bIsEof = true;
+ memset(dst + n, 0, size - n);
+ }
+ } else {
+ BufSize = Stream.Read(Buf, N_SIZE);
+ bFailed = Stream.IsFailed();
+ if (BufSize == 0)
+ bIsEof = true;
+ Read(dst, size);
+ }
+ }
+
+ void WriteComplex(const void* userBuffer, i64 size) {
+ Flush();
+ if (size >= N_SIZE) {
+ Stream.Write(userBuffer, size);
+ bFailed = Stream.IsFailed();
+ } else
+ Write(userBuffer, size);
+ }
+
+ void operator=(const TBufferedStream&) {
+ }
+
+public:
+ TBufferedStream(bool bRead, IBinaryStream& stream)
+ : Pos(0)
+ , BufSize(0)
+ , Stream(stream)
+ , bIsReading(bRead)
+ , bIsEof(false)
+ , bFailed(false)
+ {
+ }
+ ~TBufferedStream() {
+ if (!bIsReading)
+ Flush();
+ }
+ void Flush() {
+ Y_ASSERT(!bIsReading);
+ if (bIsReading)
+ return;
+ Stream.Write(Buf, Pos);
+ bFailed = Stream.IsFailed();
+ Pos = 0;
+ }
+ bool IsEof() const {
+ return bIsEof;
+ }
+ inline void Read(void* userBuffer, i64 size) {
+ Y_ASSERT(bIsReading);
+ if (!bIsEof && size + Pos <= BufSize) {
+ memcpy(userBuffer, Buf + Pos, size);
+ Pos += size;
+ return;
+ }
+ ReadComplex(userBuffer, size);
+ }
+ inline void Write(const void* userBuffer, i64 size) {
+ Y_ASSERT(!bIsReading);
+ if (Pos + size < N_SIZE) {
+ memcpy(Buf + Pos, userBuffer, size);
+ Pos += size;
+ return;
+ }
+ WriteComplex(userBuffer, size);
+ }
+ bool IsValid() const {
+ return Stream.IsValid();
+ }
+ bool IsFailed() const {
+ return bFailed;
+ }
+};
diff --git a/library/cpp/binsaver/class_factory.h b/library/cpp/binsaver/class_factory.h
new file mode 100644
index 0000000000..e83512331b
--- /dev/null
+++ b/library/cpp/binsaver/class_factory.h
@@ -0,0 +1,105 @@
+#pragma once
+
+#include <typeinfo>
+#include <util/generic/hash.h>
+#include <util/generic/vector.h>
+#include <util/ysafeptr.h>
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// factory is using RTTI
+// objects should inherit T and T must have at least 1 virtual function
+template <class T>
+class TClassFactory {
+public:
+ typedef const std::type_info* VFT;
+
+private:
+ typedef T* (*newFunc)();
+ typedef THashMap<int, newFunc> CTypeNewHash; // typeID->newFunc()
+ typedef THashMap<VFT, int> CTypeIndexHash; // vftable->typeID
+
+ CTypeIndexHash typeIndex;
+ CTypeNewHash typeInfo;
+
+ void RegisterTypeBase(int nTypeID, newFunc func, VFT vft);
+ static VFT GetObjectType(T* pObject) {
+ return &typeid(*pObject);
+ }
+ int VFT2TypeID(VFT t) {
+ CTypeIndexHash::iterator i = typeIndex.find(t);
+ if (i != typeIndex.end())
+ return i->second;
+ for (i = typeIndex.begin(); i != typeIndex.end(); ++i) {
+ if (*i->first == *t) {
+ typeIndex[t] = i->second;
+ return i->second;
+ }
+ }
+ return -1;
+ }
+
+public:
+ template <class TT>
+ void RegisterType(int nTypeID, newFunc func, TT*) {
+ RegisterTypeBase(nTypeID, func, &typeid(TT));
+ }
+ void RegisterTypeSafe(int nTypeID, newFunc func) {
+ TPtr<T> pObj = func();
+ VFT vft = GetObjectType(pObj);
+ RegisterTypeBase(nTypeID, func, vft);
+ }
+ T* CreateObject(int nTypeID) {
+ newFunc f = typeInfo[nTypeID];
+ if (f)
+ return f();
+ return nullptr;
+ }
+ int GetObjectTypeID(T* pObject) {
+ return VFT2TypeID(GetObjectType(pObject));
+ }
+ template <class TT>
+ int GetTypeID(TT* p = 0) {
+ (void)p;
+ return VFT2TypeID(&typeid(TT));
+ }
+
+ void GetAllTypeIDs(TVector<int>& typeIds) const {
+ typeIds.clear();
+ for (typename CTypeNewHash::const_iterator iter = typeInfo.begin();
+ iter != typeInfo.end();
+ ++iter) {
+ typeIds.push_back(iter->first);
+ }
+ }
+};
+////////////////////////////////////////////////////////////////////////////////////////////////////
+template <class T>
+void TClassFactory<T>::RegisterTypeBase(int nTypeID, newFunc func, VFT vft) {
+ if (typeInfo.find(nTypeID) != typeInfo.end()) {
+ TObj<IObjectBase> o1 = typeInfo[nTypeID]();
+ TObj<IObjectBase> o2 = func();
+
+ // stupid clang warning
+ auto& o1v = *o1;
+ auto& o2v = *o2;
+
+ if (typeid(o1v) != typeid(o2v)) {
+ fprintf(stderr, "IBinSaver: Type ID 0x%08X has been already used\n", nTypeID);
+ abort();
+ }
+ }
+
+ CTypeIndexHash::iterator typeIndexIt = typeIndex.find(vft);
+ if (typeIndexIt != typeIndex.end() && nTypeID != typeIndexIt->second) {
+ fprintf(stderr, "IBinSaver: class (Type ID 0x%08X) has been already registered (Type ID 0x%08X)\n", nTypeID, typeIndexIt->second);
+ abort();
+ }
+ typeIndex[vft] = nTypeID;
+ typeInfo[nTypeID] = func;
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// macro for registering CFundament derivatives
+#define REGISTER_CLASS(factory, N, name) factory.RegisterType(N, name::New##name, (name*)0);
+#define REGISTER_TEMPL_CLASS(factory, N, name, className) factory.RegisterType(N, name::New##className, (name*)0);
+#define REGISTER_CLASS_NM(factory, N, name, nmspace) factory.RegisterType(N, nmspace::name::New##name, (nmspace::name*)0);
diff --git a/library/cpp/binsaver/mem_io.cpp b/library/cpp/binsaver/mem_io.cpp
new file mode 100644
index 0000000000..82316606b6
--- /dev/null
+++ b/library/cpp/binsaver/mem_io.cpp
@@ -0,0 +1 @@
+#include "mem_io.h"
diff --git a/library/cpp/binsaver/mem_io.h b/library/cpp/binsaver/mem_io.h
new file mode 100644
index 0000000000..2a9e36fe68
--- /dev/null
+++ b/library/cpp/binsaver/mem_io.h
@@ -0,0 +1,212 @@
+#pragma once
+
+#include "bin_saver.h"
+
+namespace NMemIoInternals {
+ class TMemoryStream: public IBinaryStream {
+ TVector<char>& Data;
+ ui64 Pos;
+
+ public:
+ TMemoryStream(TVector<char>* data, ui64 pos = 0)
+ : Data(*data)
+ , Pos(pos)
+ {
+ }
+ ~TMemoryStream() override {
+ } // keep gcc happy
+
+ bool IsValid() const override {
+ return true;
+ }
+ bool IsFailed() const override {
+ return false;
+ }
+
+ private:
+ int WriteImpl(const void* userBuffer, int size) override {
+ if (size == 0)
+ return 0;
+ Y_ASSERT(size > 0);
+ if (Pos + size > Data.size())
+ Data.yresize(Pos + size);
+ memcpy(&Data[Pos], userBuffer, size);
+ Pos += size;
+ return size;
+ }
+ int ReadImpl(void* userBuffer, int size) override {
+ if (size == 0)
+ return 0;
+ Y_ASSERT(size > 0);
+ int res = Min(Data.size() - Pos, (ui64)size);
+ if (res)
+ memcpy(userBuffer, &Data[Pos], res);
+ Pos += res;
+ return res;
+ }
+ };
+
+ template <class T>
+ inline void SerializeMem(bool bRead, TVector<char>* data, T& c, bool stableOutput = false) {
+ if (IBinSaver::HasNonTrivialSerializer<T>(0u)) {
+ TMemoryStream f(data);
+ {
+ IBinSaver bs(f, bRead, stableOutput);
+ bs.Add(1, &c);
+ }
+ } else {
+ if (bRead) {
+ Y_ASSERT(data->size() == sizeof(T));
+ c = *reinterpret_cast<T*>(&(*data)[0]);
+ } else {
+ data->yresize(sizeof(T));
+ *reinterpret_cast<T*>(&(*data)[0]) = c;
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ class THugeMemoryStream: public IBinaryStream {
+ TVector<TVector<char>>& Data;
+ i64 Block, Pos;
+ bool ShrinkOnRead;
+
+ enum {
+ MAX_BLOCK_SIZE = 1024 * 1024 // Aligned with cache size
+ };
+
+ public:
+ THugeMemoryStream(TVector<TVector<char>>* data, bool shrinkOnRead = false)
+ : Data(*data)
+ , Block(0)
+ , Pos(0)
+ , ShrinkOnRead(shrinkOnRead)
+ {
+ Y_ASSERT(!data->empty());
+ }
+
+ ~THugeMemoryStream() override {
+ } // keep gcc happy
+
+ bool IsValid() const override {
+ return true;
+ }
+ bool IsFailed() const override {
+ return false;
+ }
+
+ private:
+ int WriteImpl(const void* userDataArg, int sizeArg) override {
+ if (sizeArg == 0)
+ return 0;
+ const char* userData = (const char*)userDataArg;
+ i64 size = sizeArg;
+ i64 newSize = Pos + size;
+ if (newSize > Data[Block].ysize()) {
+ while (newSize > MAX_BLOCK_SIZE) {
+ int maxWrite = MAX_BLOCK_SIZE - Pos;
+ Data[Block].yresize(MAX_BLOCK_SIZE);
+ if (maxWrite) {
+ memcpy(&Data[Block][Pos], userData, maxWrite);
+ userData += maxWrite;
+ size -= maxWrite;
+ }
+ ++Block;
+ Pos = 0;
+ Data.resize(Block + 1);
+ newSize = Pos + size;
+ }
+ Data[Block].yresize(newSize);
+ }
+ if (size) {
+ memcpy(&Data[Block][Pos], userData, size);
+ }
+ Pos += size;
+ return sizeArg;
+ }
+ int ReadImpl(void* userDataArg, int sizeArg) override {
+ if (sizeArg == 0)
+ return 0;
+
+ char* userData = (char*)userDataArg;
+ i64 size = sizeArg;
+ i64 rv = 0;
+ while (size > 0) {
+ int curBlockSize = Data[Block].ysize();
+ int maxRead = 0;
+ if (Pos + size > curBlockSize) {
+ maxRead = curBlockSize - Pos;
+ if (maxRead) {
+ memcpy(userData, &Data[Block][Pos], maxRead);
+ userData += maxRead;
+ size -= maxRead;
+ rv += maxRead;
+ }
+ if (Block + 1 == Data.ysize()) {
+ memset(userData, 0, size);
+ return rv;
+ }
+ if (ShrinkOnRead) {
+ TVector<char>().swap(Data[Block]);
+ }
+ ++Block;
+ Pos = 0;
+ } else {
+ memcpy(userData, &Data[Block][Pos], size);
+ Pos += size;
+ rv += size;
+ return rv;
+ }
+ }
+ return rv;
+ }
+ };
+
+ template <class T>
+ inline void SerializeMem(bool bRead, TVector<TVector<char>>* data, T& c, bool stableOutput = false) {
+ if (data->empty()) {
+ data->resize(1);
+ }
+ THugeMemoryStream f(data);
+ {
+ IBinSaver bs(f, bRead, stableOutput);
+ bs.Add(1, &c);
+ }
+ }
+}
+
+template <class T>
+inline void SerializeMem(const TVector<char>& data, T& c) {
+ if (IBinSaver::HasNonTrivialSerializer<T>(0u)) {
+ TVector<char> tmp(data);
+ SerializeFromMem(&tmp, c);
+ } else {
+ Y_ASSERT(data.size() == sizeof(T));
+ c = *reinterpret_cast<const T*>(&data[0]);
+ }
+}
+
+template <class T, class D>
+inline void SerializeToMem(D* data, T& c, bool stableOutput = false) {
+ NMemIoInternals::SerializeMem(false, data, c, stableOutput);
+}
+
+template <class T, class D>
+inline void SerializeFromMem(D* data, T& c, bool stableOutput = false) {
+ NMemIoInternals::SerializeMem(true, data, c, stableOutput);
+}
+
+// Frees memory in (*data)[i] immediately upon it's deserialization, thus keeps low overall memory consumption for data + object.
+template <class T>
+inline void SerializeFromMemShrinkInput(TVector<TVector<char>>* data, T& c) {
+ if (data->empty()) {
+ data->resize(1);
+ }
+ NMemIoInternals::THugeMemoryStream f(data, true);
+ {
+ IBinSaver bs(f, true, false);
+ bs.Add(1, &c);
+ }
+ data->resize(0);
+ data->shrink_to_fit();
+}
diff --git a/library/cpp/binsaver/ut/binsaver_ut.cpp b/library/cpp/binsaver/ut/binsaver_ut.cpp
new file mode 100644
index 0000000000..37eba5406f
--- /dev/null
+++ b/library/cpp/binsaver/ut/binsaver_ut.cpp
@@ -0,0 +1,198 @@
+#include <library/cpp/binsaver/util_stream_io.h>
+#include <library/cpp/binsaver/mem_io.h>
+#include <library/cpp/binsaver/bin_saver.h>
+#include <library/cpp/binsaver/ut_util/ut_util.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/buffer.h>
+#include <util/generic/map.h>
+
+struct TBinarySerializable {
+ ui32 Data = 0;
+};
+
+struct TNonBinarySerializable {
+ ui32 Data = 0;
+ TString StrData;
+};
+
+struct TCustomSerializer {
+ ui32 Data = 0;
+ TString StrData;
+ SAVELOAD(StrData, Data);
+};
+
+struct TCustomOuterSerializer {
+ ui32 Data = 0;
+ TString StrData;
+};
+
+void operator&(TCustomOuterSerializer& s, IBinSaver& f);
+
+struct TCustomOuterSerializerTmpl {
+ ui32 Data = 0;
+ TString StrData;
+};
+
+struct TCustomOuterSerializerTmplDerived: public TCustomOuterSerializerTmpl {
+ ui32 Data = 0;
+ TString StrData;
+};
+
+struct TMoveOnlyType {
+ ui32 Data = 0;
+
+ TMoveOnlyType() = default;
+ TMoveOnlyType(TMoveOnlyType&&) = default;
+
+ bool operator==(const TMoveOnlyType& obj) const {
+ return Data == obj.Data;
+ }
+};
+
+struct TTypeWithArray {
+ ui32 Data = 1;
+ TString Array[2][2]{{"test", "data"}, {"and", "more"}};
+
+ SAVELOAD(Data, Array);
+ bool operator==(const TTypeWithArray& obj) const {
+ return Data == obj.Data && std::equal(std::begin(Array[0]), std::end(Array[0]), obj.Array[0]) && std::equal(std::begin(Array[1]), std::end(Array[1]), obj.Array[1]);
+ }
+};
+
+template <typename T, typename = std::enable_if_t<std::is_base_of<TCustomOuterSerializerTmpl, T>::value>>
+int operator&(T& s, IBinSaver& f);
+
+static bool operator==(const TBlob& l, const TBlob& r) {
+ return TStringBuf(l.AsCharPtr(), l.Size()) == TStringBuf(r.AsCharPtr(), r.Size());
+}
+
+Y_UNIT_TEST_SUITE(BinSaver){
+ Y_UNIT_TEST(HasTrivialSerializer){
+ UNIT_ASSERT(!IBinSaver::HasNonTrivialSerializer<TBinarySerializable>(0u));
+UNIT_ASSERT(!IBinSaver::HasNonTrivialSerializer<TNonBinarySerializable>(0u));
+UNIT_ASSERT(IBinSaver::HasNonTrivialSerializer<TCustomSerializer>(0u));
+UNIT_ASSERT(IBinSaver::HasNonTrivialSerializer<TCustomOuterSerializer>(0u));
+UNIT_ASSERT(IBinSaver::HasNonTrivialSerializer<TCustomOuterSerializerTmpl>(0u));
+UNIT_ASSERT(IBinSaver::HasNonTrivialSerializer<TCustomOuterSerializerTmplDerived>(0u));
+UNIT_ASSERT(IBinSaver::HasNonTrivialSerializer<TVector<TCustomSerializer>>(0u));
+}
+
+
+Y_UNIT_TEST(TestStroka) {
+ TestBinSaverSerialization(TString("QWERTY"));
+}
+
+Y_UNIT_TEST(TestMoveOnlyType) {
+ TestBinSaverSerializationToBuffer(TMoveOnlyType());
+}
+
+Y_UNIT_TEST(TestVectorStrok) {
+ TestBinSaverSerialization(TVector<TString>{"A", "B", "C"});
+}
+
+Y_UNIT_TEST(TestCArray) {
+ TestBinSaverSerialization(TTypeWithArray());
+}
+
+Y_UNIT_TEST(TestSets) {
+ TestBinSaverSerialization(THashSet<TString>{"A", "B", "C"});
+ TestBinSaverSerialization(TSet<TString>{"A", "B", "C"});
+}
+
+Y_UNIT_TEST(TestMaps) {
+ TestBinSaverSerialization(THashMap<TString, ui32>{{"A", 1}, {"B", 2}, {"C", 3}});
+ TestBinSaverSerialization(TMap<TString, ui32>{{"A", 1}, {"B", 2}, {"C", 3}});
+}
+
+Y_UNIT_TEST(TestBlob) {
+ TestBinSaverSerialization(TBlob::FromStringSingleThreaded("qwerty"));
+}
+
+Y_UNIT_TEST(TestVariant) {
+ {
+ using T = std::variant<TString, int>;
+
+ TestBinSaverSerialization(T(TString("")));
+ TestBinSaverSerialization(T(0));
+ }
+ {
+ using T = std::variant<TString, int, float>;
+
+ TestBinSaverSerialization(T(TString("ask")));
+ TestBinSaverSerialization(T(12));
+ TestBinSaverSerialization(T(0.64f));
+ }
+}
+
+Y_UNIT_TEST(TestPod) {
+ struct TPod {
+ ui32 A = 5;
+ ui64 B = 7;
+ bool operator==(const TPod& other) const {
+ return A == other.A && B == other.B;
+ }
+ };
+ TestBinSaverSerialization(TPod());
+ TPod custom;
+ custom.A = 25;
+ custom.B = 37;
+ TestBinSaverSerialization(custom);
+ TestBinSaverSerialization(TVector<TPod>{custom});
+}
+
+Y_UNIT_TEST(TestSubPod) {
+ struct TPod {
+ struct TSub {
+ ui32 X = 10;
+ bool operator==(const TSub& other) const {
+ return X == other.X;
+ }
+ };
+ TVector<TSub> B;
+ int operator&(IBinSaver& f) {
+ f.Add(0, &B);
+ return 0;
+ }
+ bool operator==(const TPod& other) const {
+ return B == other.B;
+ }
+ };
+ TestBinSaverSerialization(TPod());
+ TPod::TSub sub;
+ sub.X = 1;
+ TPod custom;
+ custom.B = {sub};
+ TestBinSaverSerialization(TVector<TPod>{custom});
+}
+
+Y_UNIT_TEST(TestMemberAndOpIsMain) {
+ struct TBase {
+ TString S;
+ virtual int operator&(IBinSaver& f) {
+ f.Add(0, &S);
+ return 0;
+ }
+ virtual ~TBase() = default;
+ };
+
+ struct TDerived: public TBase {
+ int A = 0;
+ int operator&(IBinSaver& f)override {
+ f.Add(0, static_cast<TBase*>(this));
+ f.Add(0, &A);
+ return 0;
+ }
+ bool operator==(const TDerived& other) const {
+ return A == other.A && S == other.S;
+ }
+ };
+
+ TDerived obj;
+ obj.S = "TString";
+ obj.A = 42;
+
+ TestBinSaverSerialization(obj);
+}
+}
+;
diff --git a/library/cpp/binsaver/ut/ya.make b/library/cpp/binsaver/ut/ya.make
new file mode 100644
index 0000000000..43dc20bff7
--- /dev/null
+++ b/library/cpp/binsaver/ut/ya.make
@@ -0,0 +1,11 @@
+UNITTEST_FOR(library/cpp/binsaver)
+
+OWNER(gulin)
+
+SRCS(
+ binsaver_ut.cpp
+)
+
+PEERDIR(library/cpp/binsaver/ut_util)
+
+END()
diff --git a/library/cpp/binsaver/ut_util/README.md b/library/cpp/binsaver/ut_util/README.md
new file mode 100644
index 0000000000..41641cd1e1
--- /dev/null
+++ b/library/cpp/binsaver/ut_util/README.md
@@ -0,0 +1 @@
+Library for testing BinSaver serialization. \ No newline at end of file
diff --git a/library/cpp/binsaver/ut_util/ut_util.cpp b/library/cpp/binsaver/ut_util/ut_util.cpp
new file mode 100644
index 0000000000..4cd8daa931
--- /dev/null
+++ b/library/cpp/binsaver/ut_util/ut_util.cpp
@@ -0,0 +1 @@
+#include "ut_util.h"
diff --git a/library/cpp/binsaver/ut_util/ut_util.h b/library/cpp/binsaver/ut_util/ut_util.h
new file mode 100644
index 0000000000..52e7bcf8e1
--- /dev/null
+++ b/library/cpp/binsaver/ut_util/ut_util.h
@@ -0,0 +1,71 @@
+#pragma once
+
+#include <library/cpp/binsaver/bin_saver.h>
+#include <library/cpp/binsaver/mem_io.h>
+#include <library/cpp/binsaver/util_stream_io.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/vector.h>
+#include <util/stream/buffer.h>
+
+#include <functional>
+
+
+/* comparerChecksInside == true means comparer uses UNIT_ASSERT... inside itself
+ * comparerChecksInside == false means comparer returns if its arguments are equal
+ */
+
+template <class T, class TComparer = std::equal_to<T>, bool comparerChecksInside = false>
+void UnitTestCheckWithComparer(const T& lhs, const T& rhs, const TComparer& comparer) {
+ if constexpr (comparerChecksInside) {
+ comparer(lhs, rhs);
+ } else {
+ UNIT_ASSERT(comparer(lhs, rhs));
+ }
+}
+
+
+/* comparerChecksInside == true means comparer uses UNIT_ASSERT... inside itself
+ * comparerChecksInside == false means comparer returns true if its arguments are equal
+ */
+
+template <typename T, typename TComparer = std::equal_to<T>, bool comparerChecksInside = false>
+void TestBinSaverSerializationToBuffer(const T& original, const TComparer& comparer = TComparer()) {
+ TBufferOutput out;
+ {
+ TYaStreamOutput yaOut(out);
+
+ IBinSaver f(yaOut, false, false);
+ f.Add(0, const_cast<T*>(&original));
+ }
+ TBufferInput in(out.Buffer());
+ T restored;
+ {
+ TYaStreamInput yaIn(in);
+ IBinSaver f(yaIn, true, false);
+ f.Add(0, &restored);
+ }
+ UnitTestCheckWithComparer<T, TComparer, comparerChecksInside>(original, restored, comparer);
+}
+
+template <typename T, typename TComparer = std::equal_to<T>, bool comparerChecksInside = false>
+void TestBinSaverSerializationToVector(const T& original, const TComparer& comparer = TComparer()) {
+ TVector<char> out;
+ SerializeToMem(&out, *const_cast<T*>(&original));
+ T restored;
+ SerializeFromMem(&out, restored);
+ UnitTestCheckWithComparer<T, TComparer, comparerChecksInside>(original, restored, comparer);
+
+ TVector<TVector<char>> out2D;
+ SerializeToMem(&out2D, *const_cast<T*>(&original));
+ T restored2D;
+ SerializeFromMem(&out2D, restored2D);
+ UnitTestCheckWithComparer<T, TComparer, comparerChecksInside>(original, restored2D, comparer);
+}
+
+template <typename T, typename TComparer = std::equal_to<T>, bool comparerChecksInside = false>
+void TestBinSaverSerialization(const T& original, const TComparer& comparer = TComparer()) {
+ TestBinSaverSerializationToBuffer<T, TComparer, comparerChecksInside>(original, comparer);
+ TestBinSaverSerializationToVector<T, TComparer, comparerChecksInside>(original, comparer);
+}
diff --git a/library/cpp/binsaver/ut_util/ya.make b/library/cpp/binsaver/ut_util/ya.make
new file mode 100644
index 0000000000..7e60f13ef3
--- /dev/null
+++ b/library/cpp/binsaver/ut_util/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+OWNER(gulin)
+
+SRCS(
+ ut_util.cpp
+)
+
+PEERDIR(
+ library/cpp/binsaver
+ library/cpp/testing/unittest
+)
+
+END()
diff --git a/library/cpp/binsaver/util_stream_io.cpp b/library/cpp/binsaver/util_stream_io.cpp
new file mode 100644
index 0000000000..a2a79a2fe7
--- /dev/null
+++ b/library/cpp/binsaver/util_stream_io.cpp
@@ -0,0 +1 @@
+#include "util_stream_io.h"
diff --git a/library/cpp/binsaver/util_stream_io.h b/library/cpp/binsaver/util_stream_io.h
new file mode 100644
index 0000000000..d65d630b93
--- /dev/null
+++ b/library/cpp/binsaver/util_stream_io.h
@@ -0,0 +1,86 @@
+#pragma once
+
+#include "bin_saver.h"
+
+#include <util/stream/input.h>
+#include <util/stream/output.h>
+#include <util/stream/file.h>
+
+class TYaStreamInput: public IBinaryStream {
+ IInputStream& Stream;
+
+ int WriteImpl(const void*, int) override {
+ Y_ASSERT(0);
+ return 0;
+ }
+ int ReadImpl(void* userBuffer, int size) override {
+ return (int)Stream.Read(userBuffer, (size_t)size);
+ }
+ bool IsValid() const override {
+ return true;
+ }
+ bool IsFailed() const override {
+ return false;
+ }
+
+public:
+ TYaStreamInput(IInputStream& stream)
+ : Stream(stream)
+ {
+ }
+};
+
+template <class T>
+inline void SerializeFromStream(IInputStream& stream, T& c) {
+ TYaStreamInput f(stream);
+ {
+ IBinSaver bs(f, true);
+ bs.Add(1, &c);
+ }
+}
+
+template <class T>
+inline void SerializeFromFile(const TString& fileName, T& c) {
+ TIFStream in(fileName);
+ SerializeFromStream(in, c);
+}
+
+class TYaStreamOutput: public IBinaryStream {
+ IOutputStream& Stream;
+
+ int WriteImpl(const void* what, int size) override {
+ Stream.Write(what, (size_t)size);
+ return size;
+ }
+ int ReadImpl(void*, int) override {
+ Y_ASSERT(0);
+ return 0;
+ }
+ bool IsValid() const override {
+ return true;
+ }
+ bool IsFailed() const override {
+ return false;
+ }
+
+public:
+ TYaStreamOutput(IOutputStream& stream)
+ : Stream(stream)
+ {
+ }
+};
+
+template <class T>
+inline void SerializeToArcadiaStream(IOutputStream& stream, T& c) {
+ TYaStreamOutput f(stream);
+ {
+ IBinSaver bs(f, false);
+ bs.Add(1, &c);
+ }
+}
+
+template <class T>
+inline void SerializeToFile(const TString& fileName, T& c) {
+ TOFStream out(fileName);
+ SerializeToArcadiaStream(out, c);
+}
diff --git a/library/cpp/binsaver/ya.make b/library/cpp/binsaver/ya.make
new file mode 100644
index 0000000000..9693c54639
--- /dev/null
+++ b/library/cpp/binsaver/ya.make
@@ -0,0 +1,18 @@
+LIBRARY()
+
+OWNER(gulin)
+
+SRCS(
+ class_factory.h
+ bin_saver.cpp
+ blob_io.cpp
+ buffered_io.cpp
+ mem_io.cpp
+ util_stream_io.cpp
+)
+
+PEERDIR(
+ library/cpp/containers/2d_array
+)
+
+END()
diff --git a/library/cpp/bit_io/bitinout_ut.cpp b/library/cpp/bit_io/bitinout_ut.cpp
new file mode 100644
index 0000000000..23a1ddf344
--- /dev/null
+++ b/library/cpp/bit_io/bitinout_ut.cpp
@@ -0,0 +1,279 @@
+#include "bitinput.h"
+#include "bitoutput.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/buffer.h>
+#include <util/generic/buffer.h>
+
+namespace NBitIO {
+ static const char BITS_REF[] =
+ "00100010 01000000 00000000 00100111 11011111 01100111 11010101 00010100 "
+ "00100010 01100011 11100011 00110000 11011011 11011111 01001100 00110101 "
+ "10011110 01011111 01010000 00000110 00011011 00100110 00010100 01110011 "
+ "00001010 10101010 10101010 10101010 10101010 10101010 10101010 10101010 "
+ "10110101 01010101 01010101 01010101 01010101 01010101 01010101 01010101 "
+ "01000000";
+
+ inline ui64 Bits(ui64 bytes) {
+ return bytes << 3ULL;
+ }
+
+ inline TString PrintBits(const char* a, const char* b, bool reverse = false) {
+ TString s;
+ TStringOutput out(s);
+ for (const char* it = a; it != b; ++it) {
+ if (it != a)
+ out << ' ';
+
+ ui8 byte = *it;
+
+ if (reverse)
+ byte = ReverseBits(byte);
+
+ for (ui32 mask = 1; mask < 0xff; mask <<= 1) {
+ out << ((byte & mask) ? '1' : '0');
+ }
+ }
+
+ return s;
+ }
+
+ template <typename T>
+ inline TString PrintBits(T t, ui32 bits = Bits(sizeof(T))) {
+ return PrintBits((char*)&t, ((char*)&t) + BytesUp(bits));
+ }
+}
+
+class TBitIOTest: public TTestBase {
+ UNIT_TEST_SUITE(TBitIOTest);
+ UNIT_TEST(TestBitIO)
+ UNIT_TEST_SUITE_END();
+
+private:
+ using TBi = NBitIO::TBitInput;
+ using TVec = TVector<char>;
+
+ void static CheckBits(const TVec& v, const TString& ref, const TString& rem) {
+ UNIT_ASSERT_VALUES_EQUAL_C(NBitIO::PrintBits(v.begin(), v.end()), ref, rem);
+ }
+
+ void DoRead(TBi& b, ui32& t) {
+ b.Read(t, 1, 0); // 1
+ b.ReadK<3>(t, 1); // 4
+ b.Read(t, 5, 4); // 9
+ b.ReadK<14>(t, 9); // 23
+ b.Read(t, 1, 23); // 24
+ b.ReadK<5>(t, 24); // 29
+ b.Read(t, 3, 29); // 32
+ }
+
+ template <typename TBo>
+ void DoWrite(TBo& b, ui32 t) {
+ b.Write(t, 1, 0); //1
+ b.Write(t, 3, 1); //4
+ b.Write(t, 5, 4); //9
+ b.Write(t, 14, 9); //23
+ b.Write(t, 1, 23); //24
+ b.Write(t, 5, 24); //29
+ b.Write(t, 3, 29); //32
+ }
+
+ template <typename TBo>
+ void DoWrite1(TBo& out, const TString& rem) {
+ out.Write(0x0C, 3);
+ UNIT_ASSERT_VALUES_EQUAL_C(out.GetOffset(), 1u, (rem + ", " + ToString(__LINE__)));
+ out.Write(0x18, 4);
+ UNIT_ASSERT_VALUES_EQUAL_C(out.GetOffset(), 1u, (rem + ", " + ToString(__LINE__)));
+ out.Write(0x0C, 3);
+ UNIT_ASSERT_VALUES_EQUAL_C(out.GetOffset(), 2u, (rem + ", " + ToString(__LINE__)));
+ out.Write(0x30000, 17);
+ UNIT_ASSERT_VALUES_EQUAL_C(out.GetOffset(), 4u, (rem + ", " + ToString(__LINE__)));
+ out.Write(0x0C, 3);
+ UNIT_ASSERT_VALUES_EQUAL_C(out.GetOffset(), 4u, (rem + ", " + ToString(__LINE__)));
+ }
+
+ template <typename TBo>
+ void DoWrite2(TBo& out, const TString& rem) {
+ out.Write(0x0C, 3);
+ UNIT_ASSERT_VALUES_EQUAL_C(out.GetOffset(), 8u, (rem + ", " + ToString(__LINE__)));
+
+ out.Write(0x42, 7);
+ UNIT_ASSERT_VALUES_EQUAL_C(out.GetOffset(), 9u, (rem + ", " + ToString(__LINE__)));
+
+ DoWrite(out, 1637415112);
+ UNIT_ASSERT_VALUES_EQUAL_C(out.GetOffset(), 13u, (rem + ", " + ToString(__LINE__)));
+
+ DoWrite(out, 897998715);
+ UNIT_ASSERT_VALUES_EQUAL_C(out.GetOffset(), 17u, (rem + ", " + ToString(__LINE__)));
+
+ DoWrite(out, 201416527);
+ UNIT_ASSERT_VALUES_EQUAL_C(out.GetOffset(), 21u, (rem + ", " + ToString(__LINE__)));
+
+ DoWrite(out, 432344219);
+ UNIT_ASSERT_VALUES_EQUAL_C(out.GetOffset(), 25u, (rem + ", " + ToString(__LINE__)));
+
+ out.Write(0xAAAAAAAAAAAAAAAAULL, 64);
+ UNIT_ASSERT_VALUES_EQUAL_C(out.GetOffset(), 33u, (rem + ", " + ToString(__LINE__)));
+
+ out.Write(0x5555555555555555ULL, 64);
+ UNIT_ASSERT_VALUES_EQUAL_C(out.GetOffset(), 41u, (rem + ", " + ToString(__LINE__)));
+ }
+
+ void DoBitOutput(NBitIO::TBitOutputYVector& out, const TString& rem) {
+ DoWrite1(out, rem);
+
+ out.WriteWords<8>(0xabcdef);
+ UNIT_ASSERT_VALUES_EQUAL_C(out.GetOffset(), 8u, (rem + ", " + ToString(__LINE__)));
+
+ DoWrite2(out, rem);
+ }
+
+ void DoBitOutput(NBitIO::TBitOutputArray& out, const TString& rem) {
+ DoWrite1(out, rem);
+
+ out.WriteWords<8>(0xabcdef);
+ UNIT_ASSERT_VALUES_EQUAL_C(out.GetOffset(), 8u, (rem + ", " + ToString(__LINE__)));
+
+ DoWrite2(out, rem);
+ }
+
+ void DoBitInput(TBi& in, const TString& rem) {
+ UNIT_ASSERT(!in.Eof());
+
+ {
+ ui64 val;
+
+ val = 0;
+ UNIT_ASSERT_VALUES_EQUAL_C(in.GetOffset(), 0u, (rem + ": " + NBitIO::PrintBits(val)));
+
+ UNIT_ASSERT_C(in.Read(val, 3), (rem + ": " + NBitIO::PrintBits(val)).data());
+
+ UNIT_ASSERT_VALUES_EQUAL_C(val, 0x4u, (rem + ": " + NBitIO::PrintBits(val)));
+ UNIT_ASSERT_VALUES_EQUAL_C(in.GetOffset(), 1u, (rem + ": " + NBitIO::PrintBits(val)));
+ UNIT_ASSERT_C(!in.Eof(), (rem + ", " + ToString(__LINE__)).data());
+
+ val = 0;
+ UNIT_ASSERT_C(in.Read(val, 4), (rem + ": " + NBitIO::PrintBits(val)).data());
+
+ UNIT_ASSERT_VALUES_EQUAL_C(val, 0x8u, (rem + ": " + NBitIO::PrintBits(val)));
+ UNIT_ASSERT_VALUES_EQUAL_C(in.GetOffset(), 1u, (rem + ": " + NBitIO::PrintBits(val)));
+ UNIT_ASSERT_C(!in.Eof(), (rem + ", " + ToString(__LINE__)).data());
+
+ val = 0;
+ UNIT_ASSERT_C(in.Read(val, 3), (rem + ": " + NBitIO::PrintBits(val)).data());
+
+ UNIT_ASSERT_VALUES_EQUAL_C(val, 0x4u, (rem + ": " + NBitIO::PrintBits(val)));
+ UNIT_ASSERT_VALUES_EQUAL_C(in.GetOffset(), 2u, (rem + ": " + NBitIO::PrintBits(val)));
+ UNIT_ASSERT_C(!in.Eof(), (rem + ", " + ToString(__LINE__)).data());
+
+ val = 0;
+ UNIT_ASSERT_C(in.Read(val, 17), (rem + ": " + NBitIO::PrintBits(val)).data());
+
+ UNIT_ASSERT_VALUES_EQUAL_C(val, 0x10000u, (rem + ": " + NBitIO::PrintBits(val)));
+ UNIT_ASSERT_VALUES_EQUAL_C(in.GetOffset(), 4u, (rem + ": " + NBitIO::PrintBits(val)));
+ UNIT_ASSERT_C(!in.Eof(), (rem + ", " + ToString(__LINE__)).data());
+
+ UNIT_ASSERT_VALUES_EQUAL_C(in.GetOffset(), 4u, (rem + ": " + NBitIO::PrintBits(val)));
+
+ {
+ ui32 rt = 0;
+ in.ReadRandom(30, rt, 10, 20);
+ UNIT_ASSERT_STRINGS_EQUAL(NBitIO::PrintBits(rt).data(), "00000000 00000000 00001111 01111100");
+ }
+ val = 0;
+ UNIT_ASSERT_C(in.Read(val, 3), (rem + ": " + NBitIO::PrintBits(val)).data());
+
+ UNIT_ASSERT_VALUES_EQUAL_C(val, 0x4u, (rem + ": " + NBitIO::PrintBits(val)));
+ UNIT_ASSERT_VALUES_EQUAL_C(in.GetOffset(), 4u, (rem + ": " + NBitIO::PrintBits(val)));
+ UNIT_ASSERT_C(!in.Eof(), (rem + ", " + ToString(__LINE__)).data());
+
+ val = 0;
+ UNIT_ASSERT_C(in.ReadWords<8>(val), (rem + ": " + NBitIO::PrintBits(val)).data());
+
+ UNIT_ASSERT_VALUES_EQUAL_C(val, 0xabcdefU, (rem + ": " + NBitIO::PrintBits(val)));
+ UNIT_ASSERT_VALUES_EQUAL_C(in.GetOffset(), 8u, (rem + ": " + NBitIO::PrintBits(val)));
+ UNIT_ASSERT_C(!in.Eof(), (rem + ", " + ToString(__LINE__)).data());
+
+ val = 0;
+ UNIT_ASSERT_C(in.Read(val, 3), (rem + ", " + ToString(__LINE__)).data());
+
+ UNIT_ASSERT_VALUES_EQUAL_C(val, 0x4u, (rem + ": " + NBitIO::PrintBits(val)));
+ UNIT_ASSERT_VALUES_EQUAL_C(in.GetOffset(), 8u, (rem + ": " + NBitIO::PrintBits(val)));
+ UNIT_ASSERT_C(!in.Eof(), (rem + ", " + ToString(__LINE__)).data());
+
+ val = 0;
+ in.Read(val, 7);
+ UNIT_ASSERT_VALUES_EQUAL_C(val, 0x42u, (rem + ": " + NBitIO::PrintBits(val)));
+ }
+
+ {
+ ui32 v = 0;
+
+ DoRead(in, v);
+ UNIT_ASSERT_VALUES_EQUAL_C(v, 1637415112ul, (rem + ": " + NBitIO::PrintBits(v)));
+ DoRead(in, v);
+ UNIT_ASSERT_VALUES_EQUAL_C(v, 897998715u, (rem + ": " + NBitIO::PrintBits(v)));
+ DoRead(in, v);
+ UNIT_ASSERT_VALUES_EQUAL_C(v, 201416527u, (rem + ": " + NBitIO::PrintBits(v)));
+ DoRead(in, v);
+ UNIT_ASSERT_VALUES_EQUAL_C(v, 432344219u, (rem + ": " + NBitIO::PrintBits(v)));
+
+ UNIT_ASSERT_VALUES_EQUAL_C(in.GetOffset(), 25u, (rem + ": " + NBitIO::PrintBits(v)));
+ }
+
+ {
+ ui64 v8 = 0;
+ in.ReadSafe(v8, 64);
+
+ UNIT_ASSERT_VALUES_EQUAL_C(v8, 0xAAAAAAAAAAAAAAAAULL, (rem + ": " + NBitIO::PrintBits(v8)));
+ UNIT_ASSERT_VALUES_EQUAL_C(in.GetOffset(), 33u, (rem + ": " + NBitIO::PrintBits(v8)));
+
+ v8 = 0;
+ in.ReadK<64>(v8);
+
+ UNIT_ASSERT_VALUES_EQUAL_C(v8, 0x5555555555555555ULL, (rem + ": " + NBitIO::PrintBits(v8)));
+ UNIT_ASSERT_VALUES_EQUAL_C(in.GetOffset(), 41u, (rem + ": " + NBitIO::PrintBits(v8)));
+ }
+
+ ui32 v = 0;
+ UNIT_ASSERT_C(!in.Eof(), (rem + ", " + ToString(__LINE__)).data());
+ UNIT_ASSERT_C(in.Read(v, 5), (rem + ", " + ToString(__LINE__)).data());
+ UNIT_ASSERT_C(in.Eof(), (rem + ", " + ToString(__LINE__)).data());
+ }
+
+ void TestBitIO() {
+ {
+ TVec vec;
+
+ {
+ NBitIO::TBitOutputYVector out(&vec);
+ DoBitOutput(out, ToString(__LINE__));
+ }
+
+ CheckBits(vec, NBitIO::BITS_REF, ToString(__LINE__).data());
+
+ {
+ TBi in(vec);
+ DoBitInput(in, ToString(__LINE__));
+ }
+ }
+ {
+ TVec vec;
+ vec.resize(41, 0);
+ {
+ NBitIO::TBitOutputArray out(vec.begin(), vec.size());
+ DoBitOutput(out, ToString(__LINE__));
+ }
+
+ CheckBits(vec, NBitIO::BITS_REF, ToString(__LINE__).data());
+
+ {
+ TBi in(vec);
+ DoBitInput(in, ToString(__LINE__));
+ }
+ }
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TBitIOTest);
diff --git a/library/cpp/bit_io/bitinput.cpp b/library/cpp/bit_io/bitinput.cpp
new file mode 100644
index 0000000000..d7c37f06fc
--- /dev/null
+++ b/library/cpp/bit_io/bitinput.cpp
@@ -0,0 +1 @@
+#include "bitinput.h"
diff --git a/library/cpp/bit_io/bitinput.h b/library/cpp/bit_io/bitinput.h
new file mode 100644
index 0000000000..85711eb7f9
--- /dev/null
+++ b/library/cpp/bit_io/bitinput.h
@@ -0,0 +1,171 @@
+#pragma once
+
+#include "bitinput_impl.h"
+
+#include <util/system/yassert.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+#include <iterator>
+
+namespace NBitIO {
+ // Based on junk/solar/codecs/bitstream.h
+
+ class TBitInput: protected TBitInputImpl {
+ public:
+ template <typename TVec>
+ explicit TBitInput(const TVec& vec)
+ : TBitInputImpl(std::begin(vec), std::end(vec))
+ {
+ }
+
+ TBitInput(const char* start, const char* end)
+ : TBitInputImpl(start, end)
+ {
+ }
+
+ bool Eof() const {
+ return EofImpl();
+ }
+
+ ui64 GetOffset() const {
+ ui64 bo = BitOffset();
+ return bo / 8 + !!(bo % 8);
+ }
+
+ using TBitInputImpl::GetBitLength;
+
+ ui64 GetBitOffset() const {
+ return BitOffset() % 8;
+ }
+
+ public:
+ // Read with static number of bits.
+ // Preserves what's in result.
+ template <ui64 bits, typename T>
+ Y_FORCE_INLINE bool ReadK(T& result, ui64 skipbits) {
+ ui64 r64 = 0;
+ bool ret = bits <= 56 ? ReadKImpl<bits>(r64) : ReadSafe(r64, bits);
+ CopyToResultK<bits>(result, r64, skipbits);
+ return ret;
+ }
+
+ // Read with static number of bits.
+ // Zeroes other bits in result.
+ template <ui64 bits, typename T>
+ Y_FORCE_INLINE bool ReadK(T& result) {
+ ui64 r = 0;
+ bool res = ReadK<bits>(r);
+ result = r;
+ return res;
+ }
+
+ // Shortcut to impl.
+ template <ui64 bits>
+ Y_FORCE_INLINE bool ReadK(ui64& result) {
+ if (bits <= 56)
+ return ReadKImpl<bits>(result);
+
+ ui64 r1 = 0ULL;
+ ui64 r2 = 0ULL;
+
+ bool ret1 = ReadKImpl<56ULL>(r1);
+ bool ret2 = ReadKImpl<(bits > 56ULL ? bits - 56ULL : 0) /*or else we get negative param in template*/>(r2);
+
+ result = (r2 << 56ULL) | r1;
+
+ return ret1 & ret2;
+ }
+
+ // It's safe to read up to 64 bits.
+ // Zeroes other bits in result.
+ template <typename T>
+ Y_FORCE_INLINE bool ReadSafe(T& result, ui64 bits) {
+ if (bits <= 56ULL)
+ return Read(result, bits);
+
+ ui64 r1 = 0ULL;
+ ui64 r2 = 0ULL;
+
+ bool ret1 = ReadKImpl<56ULL>(r1);
+ bool ret2 = ReadImpl(r2, bits - 56ULL);
+
+ result = (r2 << 56ULL) | r1;
+
+ return ret1 & ret2;
+ }
+
+ // It's safe to read up to 64 bits.
+ // Preserves what's in result.
+ template <typename T>
+ Y_FORCE_INLINE bool ReadSafe(T& result, ui64 bits, ui64 skipbits) {
+ ui64 r64 = 0;
+ bool ret = ReadSafe(r64, bits);
+ CopyToResult(result, r64, bits, skipbits);
+ return ret;
+ }
+
+ // Do not try to read more than 56 bits at once. Split in two reads or use ReadSafe.
+ // Zeroes other bits in result.
+ template <typename T>
+ Y_FORCE_INLINE bool Read(T& result, ui64 bits) {
+ ui64 r64 = 0;
+ bool ret = ReadImpl(r64, bits);
+ result = r64;
+ return ret;
+ }
+
+ // Shortcut to impl.
+ Y_FORCE_INLINE bool Read(ui64& result, ui64 bits) {
+ return ReadImpl(result, bits);
+ }
+
+ // Do not try to read more than 56 bits at once. Split in two reads or use ReadSafe.
+ // Preserves what's in result.
+ template <typename T>
+ Y_FORCE_INLINE bool Read(T& result, ui64 bits, ui64 skipbits) {
+ ui64 r64 = 0;
+ bool ret = ReadImpl(r64, bits);
+ CopyToResult(result, r64, bits, skipbits);
+ return ret;
+ }
+
+ // Unsigned wordwise read. Underlying data is splitted in "words" of "bits(data) + 1(flag)" bits.
+ // Like this: (unsigned char)0x2E<3> (0010 1110) <=> 1110 0101
+ // fddd fddd
+ template <ui64 bits, typename T>
+ Y_FORCE_INLINE bool ReadWords(T& result) {
+ ui64 r64 = 0;
+
+ bool retCode = ReadWordsImpl<bits>(r64);
+ result = r64;
+
+ return retCode;
+ }
+
+ // Shortcut to impl.
+ template <ui64 bits>
+ Y_FORCE_INLINE bool ReadWords(ui64& result) {
+ return ReadWordsImpl<bits>(result);
+ }
+
+ Y_FORCE_INLINE bool Back(int bits) {
+ return Seek(BitOffset() - bits);
+ }
+
+ Y_FORCE_INLINE bool Seek(int bitoffset) {
+ return TBitInputImpl::Seek(bitoffset);
+ }
+
+ // A way to read a portion of bits at random location.
+ // Didn't want to complicate sequential read, neither to copypaste.
+ template <typename T>
+ Y_FORCE_INLINE bool ReadRandom(ui64 bitoffset, T& result, ui64 bits, ui64 skipbits) {
+ const ui64 curr = BitOffset();
+ Seek(bitoffset);
+ bool ret = ReadSafe<T>(result, bits, skipbits);
+ Seek(curr);
+ return ret;
+ }
+ };
+}
diff --git a/library/cpp/bit_io/bitinput_impl.cpp b/library/cpp/bit_io/bitinput_impl.cpp
new file mode 100644
index 0000000000..81c897f882
--- /dev/null
+++ b/library/cpp/bit_io/bitinput_impl.cpp
@@ -0,0 +1 @@
+#include "bitinput_impl.h"
diff --git a/library/cpp/bit_io/bitinput_impl.h b/library/cpp/bit_io/bitinput_impl.h
new file mode 100644
index 0000000000..b13fbef101
--- /dev/null
+++ b/library/cpp/bit_io/bitinput_impl.h
@@ -0,0 +1,110 @@
+#pragma once
+
+#include <util/generic/bitops.h>
+#include <util/system/unaligned_mem.h>
+
+namespace NBitIO {
+ class TBitInputImpl {
+ i64 RealStart;
+ i64 Start;
+ ui64 Length;
+ ui64 BOffset;
+ const ui32 FakeStart;
+ char Fake[16];
+ const i64 FStart;
+
+ public:
+ TBitInputImpl(const char* start, const char* end)
+ : RealStart((i64)start)
+ , Start((i64)start)
+ , Length((end - start) << 3)
+ , BOffset(0)
+ , FakeStart(Length > 64 ? Length - 64 : 0)
+ , FStart((i64)Fake - (FakeStart >> 3))
+ {
+ memcpy(Fake, (const char*)(RealStart + (FakeStart >> 3)), (Length - FakeStart) >> 3);
+ Start = FakeStart ? RealStart : FStart;
+ }
+
+ ui64 GetBitLength() const {
+ return Length;
+ }
+
+ protected:
+ template <ui32 bits>
+ Y_FORCE_INLINE bool ReadKImpl(ui64& result) {
+ result = (ReadUnaligned<ui64>((const void*)(Start + (BOffset >> 3))) >> (BOffset & 7)) & Mask64(bits);
+ BOffset += bits;
+ if (BOffset < FakeStart)
+ return true;
+ if (BOffset > Length) {
+ result = 0;
+ BOffset -= bits;
+ return false;
+ }
+ Start = FStart;
+ return true;
+ }
+
+ Y_FORCE_INLINE bool ReadImpl(ui64& result, ui32 bits) {
+ result = (ReadUnaligned<ui64>((const void*)(Start + (BOffset >> 3))) >> (BOffset & 7)) & MaskLowerBits(bits);
+ BOffset += bits;
+ if (BOffset < FakeStart)
+ return true;
+ if (Y_UNLIKELY(BOffset > Length)) {
+ result = 0;
+ BOffset -= bits;
+ return false;
+ }
+ Start = FStart;
+ return true;
+ }
+
+ Y_FORCE_INLINE bool EofImpl() const {
+ return BOffset >= Length;
+ }
+
+ Y_FORCE_INLINE ui64 BitOffset() const {
+ return BOffset;
+ }
+
+ Y_FORCE_INLINE bool Seek(i64 offset) {
+ if (offset < 0 || offset > (i64)Length)
+ return false;
+ BOffset = offset;
+ Start = BOffset < FakeStart ? RealStart : FStart;
+ return true;
+ }
+
+ protected:
+ template <ui64 bits, typename T>
+ Y_FORCE_INLINE static void CopyToResultK(T& result, ui64 r64, ui64 skipbits) {
+ result = (result & ~(Mask64(bits) << skipbits)) | (r64 << skipbits);
+ }
+
+ template <typename T>
+ Y_FORCE_INLINE static void CopyToResult(T& result, ui64 r64, ui64 bits, ui64 skipbits) {
+ result = (result & InverseMaskLowerBits(bits, skipbits)) | (r64 << skipbits);
+ }
+
+ public:
+ template <ui64 bits>
+ Y_FORCE_INLINE bool ReadWordsImpl(ui64& data) {
+ data = 0;
+
+ const ui64 haveMore = NthBit64(bits);
+ const ui64 mask = Mask64(bits);
+ ui64 current = 0;
+ ui64 byteNo = 0;
+
+ do {
+ if (!ReadKImpl<bits + 1>(current))
+ return false;
+
+ data |= (current & mask) << (byteNo++ * bits);
+ } while (current & haveMore);
+
+ return true;
+ }
+ };
+}
diff --git a/library/cpp/bit_io/bitoutput.cpp b/library/cpp/bit_io/bitoutput.cpp
new file mode 100644
index 0000000000..d6c1c095da
--- /dev/null
+++ b/library/cpp/bit_io/bitoutput.cpp
@@ -0,0 +1 @@
+#include "bitoutput.h"
diff --git a/library/cpp/bit_io/bitoutput.h b/library/cpp/bit_io/bitoutput.h
new file mode 100644
index 0000000000..2b886c1f02
--- /dev/null
+++ b/library/cpp/bit_io/bitoutput.h
@@ -0,0 +1,195 @@
+#pragma once
+
+#include <library/cpp/deprecated/accessors/accessors.h>
+
+#include <util/stream/output.h>
+#include <util/system/yassert.h>
+#include <util/generic/bitops.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+namespace NBitIO {
+ // Based on junk/solar/codecs/bitstream.h
+
+ // Almost all code is hard tuned for sequential write performance.
+ // Use tools/bursttrie/benchmarks/bitstreams_benchmark to check your changes.
+
+ inline constexpr ui64 BytesUp(ui64 bits) {
+ return (bits + 7ULL) >> 3ULL;
+ }
+
+ template <typename TStorage>
+ class TBitOutputBase {
+ protected:
+ TStorage* Storage;
+ ui64 FreeBits;
+ ui64 Active;
+ ui64 Offset;
+
+ public:
+ TBitOutputBase(TStorage* storage)
+ : Storage(storage)
+ , FreeBits(64)
+ , Active()
+ , Offset()
+ {
+ }
+
+ ui64 GetOffset() const {
+ return Offset + BytesUp(64ULL - FreeBits);
+ }
+
+ ui64 GetBitOffset() const {
+ return (64ULL - FreeBits) & 7ULL;
+ }
+
+ ui64 GetByteReminder() const {
+ return FreeBits & 7ULL;
+ }
+
+ public:
+ // interface
+
+ // Write "bits" lower bits.
+ Y_FORCE_INLINE void Write(ui64 data, ui64 bits) {
+ if (FreeBits < bits) {
+ if (FreeBits) {
+ bits -= FreeBits;
+
+ Active |= (data & MaskLowerBits(FreeBits)) << (64ULL - FreeBits);
+ data >>= FreeBits;
+
+ FreeBits = 0ULL;
+ }
+
+ Flush();
+ }
+
+ Active |= bits ? ((data & MaskLowerBits(bits)) << (64ULL - FreeBits)) : 0;
+ FreeBits -= bits;
+ }
+
+ // Write "bits" lower bits starting from "skipbits" bit.
+ Y_FORCE_INLINE void Write(ui64 data, ui64 bits, ui64 skipbits) {
+ Write(data >> skipbits, bits);
+ }
+
+ // Unsigned wordwise write. Underlying data is splitted in "words" of "bits(data) + 1(flag)" bits.
+ // Like this: (unsigned char)0x2E<3> (0000 0010 1110) <=> 1110 0101
+ // fddd fddd
+ template <ui64 bits>
+ Y_FORCE_INLINE void WriteWords(ui64 data) {
+ do {
+ ui64 part = data;
+
+ data >>= bits;
+ part |= FastZeroIfFalse(data, NthBit64(bits));
+ Write(part, bits + 1ULL);
+ } while (data);
+ }
+
+ Y_FORCE_INLINE ui64 /* padded bits */ Flush() {
+ const ui64 ubytes = 8ULL - (FreeBits >> 3ULL);
+
+ if (ubytes) {
+ Active <<= FreeBits;
+ Active >>= FreeBits;
+
+ Storage->WriteData((const char*)&Active, (const char*)&Active + ubytes);
+ Offset += ubytes;
+ }
+
+ const ui64 padded = FreeBits & 7;
+
+ FreeBits = 64ULL;
+ Active = 0ULL;
+
+ return padded;
+ }
+
+ virtual ~TBitOutputBase() {
+ Flush();
+ }
+
+ private:
+ static Y_FORCE_INLINE ui64 FastZeroIfFalse(bool cond, ui64 iftrue) {
+ return -i64(cond) & iftrue;
+ }
+ };
+
+ template <typename TVec>
+ class TBitOutputVectorImpl {
+ TVec* Data;
+
+ public:
+ void WriteData(const char* begin, const char* end) {
+ NAccessors::Append(*Data, begin, end);
+ }
+
+ TBitOutputVectorImpl(TVec* data)
+ : Data(data)
+ {
+ }
+ };
+
+ template <typename TVec>
+ struct TBitOutputVector: public TBitOutputVectorImpl<TVec>, public TBitOutputBase<TBitOutputVectorImpl<TVec>> {
+ inline TBitOutputVector(TVec* data)
+ : TBitOutputVectorImpl<TVec>(data)
+ , TBitOutputBase<TBitOutputVectorImpl<TVec>>(this)
+ {
+ }
+ };
+
+ class TBitOutputArrayImpl {
+ char* Data;
+ size_t Left;
+
+ public:
+ void WriteData(const char* begin, const char* end) {
+ size_t sz = end - begin;
+ Y_VERIFY(sz <= Left, " ");
+ memcpy(Data, begin, sz);
+ Data += sz;
+ Left -= sz;
+ }
+
+ TBitOutputArrayImpl(char* begin, size_t len)
+ : Data(begin)
+ , Left(len)
+ {
+ }
+ };
+
+ struct TBitOutputArray: public TBitOutputArrayImpl, public TBitOutputBase<TBitOutputArrayImpl> {
+ inline TBitOutputArray(char* begin, size_t len)
+ : TBitOutputArrayImpl(begin, len)
+ , TBitOutputBase<TBitOutputArrayImpl>(this)
+ {
+ }
+ };
+
+ using TBitOutputYVector = TBitOutputVector<TVector<char>>;
+
+ class TBitOutputStreamImpl {
+ IOutputStream* Out;
+
+ public:
+ void WriteData(const char* begin, const char* end) {
+ Out->Write(begin, end - begin);
+ }
+
+ TBitOutputStreamImpl(IOutputStream* out)
+ : Out(out)
+ {
+ }
+ };
+
+ struct TBitOutputStream: public TBitOutputStreamImpl, public TBitOutputBase<TBitOutputStreamImpl> {
+ inline TBitOutputStream(IOutputStream* out)
+ : TBitOutputStreamImpl(out)
+ , TBitOutputBase<TBitOutputStreamImpl>(this)
+ {
+ }
+ };
+}
diff --git a/library/cpp/bit_io/ut/ya.make b/library/cpp/bit_io/ut/ya.make
new file mode 100644
index 0000000000..07ee5b4997
--- /dev/null
+++ b/library/cpp/bit_io/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/bit_io)
+
+OWNER(
+ velavokr
+ g:util
+)
+
+SRCS(
+ bitinout_ut.cpp
+)
+
+END()
diff --git a/library/cpp/bit_io/ya.make b/library/cpp/bit_io/ya.make
new file mode 100644
index 0000000000..df1de81ff9
--- /dev/null
+++ b/library/cpp/bit_io/ya.make
@@ -0,0 +1,18 @@
+LIBRARY()
+
+OWNER(
+ velavokr
+ g:util
+)
+
+PEERDIR(
+ library/cpp/deprecated/accessors
+)
+
+SRCS(
+ bitinput.cpp
+ bitinput_impl.cpp
+ bitoutput.cpp
+)
+
+END()
diff --git a/library/cpp/blockcodecs/README.md b/library/cpp/blockcodecs/README.md
new file mode 100644
index 0000000000..417917a475
--- /dev/null
+++ b/library/cpp/blockcodecs/README.md
@@ -0,0 +1,23 @@
+This is a simple library for block data compression (this means data is compressed/uncompressed
+by whole blocks in memory). It's a lite-version of the `library/cpp/codecs`. Lite here means that it
+provide only well-known compression algorithms, without the possibility of learning.
+
+There are two possible ways to work with it.
+
+Codec by name
+=============
+Use `NBlockCodec::Codec` to obtain the codec by name. The codec can be asked to compress
+or decompress something and in various ways.
+
+To get a full list of codecs there is a function `NBlockCodecs::ListAllCodecs()`.
+
+Streaming
+=========
+Use `stream.h` to obtain simple streams over block codecs (buffer data, compress them by blocks,
+write to the resulting stream).
+
+Using codec plugins
+===================
+If you don't want your code to bloat from unused codecs, you can use the small version of the
+library: `library/cpp/blockcodecs/core`. In that case, you need to manually set `PEERDIR()`s to
+needed codecs (i.e. `PEERDIR(library/cpp/blockcodecs/codecs/lzma)`).
diff --git a/library/cpp/blockcodecs/codecs.cpp b/library/cpp/blockcodecs/codecs.cpp
new file mode 100644
index 0000000000..fdec4809d3
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs.cpp
@@ -0,0 +1 @@
+#include "codecs.h"
diff --git a/library/cpp/blockcodecs/codecs.h b/library/cpp/blockcodecs/codecs.h
new file mode 100644
index 0000000000..fd499b54b0
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include <library/cpp/blockcodecs/core/codecs.h>
diff --git a/library/cpp/blockcodecs/codecs/brotli/brotli.cpp b/library/cpp/blockcodecs/codecs/brotli/brotli.cpp
new file mode 100644
index 0000000000..6e3cd971bd
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/brotli/brotli.cpp
@@ -0,0 +1,67 @@
+#include <library/cpp/blockcodecs/core/codecs.h>
+#include <library/cpp/blockcodecs/core/common.h>
+#include <library/cpp/blockcodecs/core/register.h>
+
+#include <contrib/libs/brotli/include/brotli/encode.h>
+#include <contrib/libs/brotli/include/brotli/decode.h>
+
+using namespace NBlockCodecs;
+
+namespace {
+ struct TBrotliCodec : public TAddLengthCodec<TBrotliCodec> {
+ static constexpr int BEST_QUALITY = 11;
+
+ inline TBrotliCodec(ui32 level)
+ : Quality(level)
+ , MyName(TStringBuf("brotli_") + ToString(level))
+ {
+ }
+
+ static inline size_t DoMaxCompressedLength(size_t l) noexcept {
+ return BrotliEncoderMaxCompressedSize(l);
+ }
+
+ inline size_t DoCompress(const TData& in, void* out) const {
+ size_t resultSize = MaxCompressedLength(in);
+ auto result = BrotliEncoderCompress(
+ /*quality*/ Quality,
+ /*window*/ BROTLI_DEFAULT_WINDOW,
+ /*mode*/ BrotliEncoderMode::BROTLI_MODE_GENERIC,
+ /*input_size*/ in.size(),
+ /*input_buffer*/ (const unsigned char*)(in.data()),
+ /*encoded_size*/ &resultSize,
+ /*encoded_buffer*/ static_cast<unsigned char*>(out));
+ if (result != BROTLI_TRUE) {
+ ythrow yexception() << "internal brotli error during compression";
+ }
+
+ return resultSize;
+ }
+
+ inline void DoDecompress(const TData& in, void* out, size_t dsize) const {
+ size_t decoded = dsize;
+ auto result = BrotliDecoderDecompress(in.size(), (const unsigned char*)in.data(), &decoded, static_cast<unsigned char*>(out));
+ if (result != BROTLI_DECODER_RESULT_SUCCESS) {
+ ythrow yexception() << "internal brotli error during decompression";
+ } else if (decoded != dsize) {
+ ythrow TDecompressError(dsize, decoded);
+ }
+ }
+
+ TStringBuf Name() const noexcept override {
+ return MyName;
+ }
+
+ const int Quality = BEST_QUALITY;
+ const TString MyName;
+ };
+
+ struct TBrotliRegistrar {
+ TBrotliRegistrar() {
+ for (int i = 1; i <= TBrotliCodec::BEST_QUALITY; ++i) {
+ RegisterCodec(MakeHolder<TBrotliCodec>(i));
+ }
+ }
+ };
+ const TBrotliRegistrar Registrar{};
+}
diff --git a/library/cpp/blockcodecs/codecs/brotli/ya.make b/library/cpp/blockcodecs/codecs/brotli/ya.make
new file mode 100644
index 0000000000..17aff0bb72
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/brotli/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ contrib/libs/brotli/enc
+ contrib/libs/brotli/dec
+ library/cpp/blockcodecs/core
+)
+
+SRCS(
+ GLOBAL brotli.cpp
+)
+
+END()
diff --git a/library/cpp/blockcodecs/codecs/bzip/bzip.cpp b/library/cpp/blockcodecs/codecs/bzip/bzip.cpp
new file mode 100644
index 0000000000..3a5cfdd0e9
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/bzip/bzip.cpp
@@ -0,0 +1,62 @@
+#include <library/cpp/blockcodecs/core/codecs.h>
+#include <library/cpp/blockcodecs/core/common.h>
+#include <library/cpp/blockcodecs/core/register.h>
+
+#include <contrib/libs/libbz2/bzlib.h>
+
+using namespace NBlockCodecs;
+
+namespace {
+ struct TBZipCodec: public TAddLengthCodec<TBZipCodec> {
+ inline TBZipCodec(int level)
+ : Level(level)
+ , MyName("bzip2-" + ToString(Level))
+ {
+ }
+
+ static inline size_t DoMaxCompressedLength(size_t in) noexcept {
+ // very strange
+ return in * 2 + 128;
+ }
+
+ TStringBuf Name() const noexcept override {
+ return MyName;
+ }
+
+ inline size_t DoCompress(const TData& in, void* buf) const {
+ unsigned int ret = DoMaxCompressedLength(in.size());
+ const int res = BZ2_bzBuffToBuffCompress((char*)buf, &ret, (char*)in.data(), in.size(), Level, 0, 0);
+ if (res != BZ_OK) {
+ ythrow TCompressError(res);
+ }
+
+ return ret;
+ }
+
+ inline void DoDecompress(const TData& in, void* out, size_t len) const {
+ unsigned int tmp = SafeIntegerCast<unsigned int>(len);
+ const int res = BZ2_bzBuffToBuffDecompress((char*)out, &tmp, (char*)in.data(), in.size(), 0, 0);
+
+ if (res != BZ_OK) {
+ ythrow TDecompressError(res);
+ }
+
+ if (len != tmp) {
+ ythrow TDecompressError(len, tmp);
+ }
+ }
+
+ const int Level;
+ const TString MyName;
+ };
+
+ struct TBZipRegistrar {
+ TBZipRegistrar() {
+ for (int i = 1; i < 10; ++i) {
+ RegisterCodec(MakeHolder<TBZipCodec>(i));
+ }
+ RegisterAlias("bzip2", "bzip2-6");
+ }
+ };
+ const TBZipRegistrar Registrar{};
+}
diff --git a/library/cpp/blockcodecs/codecs/bzip/ya.make b/library/cpp/blockcodecs/codecs/bzip/ya.make
new file mode 100644
index 0000000000..f0a8aefd62
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/bzip/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ contrib/libs/libbz2
+ library/cpp/blockcodecs/core
+)
+
+SRCS(
+ GLOBAL bzip.cpp
+)
+
+END()
diff --git a/library/cpp/blockcodecs/codecs/fastlz/fastlz.cpp b/library/cpp/blockcodecs/codecs/fastlz/fastlz.cpp
new file mode 100644
index 0000000000..da2831fbd2
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/fastlz/fastlz.cpp
@@ -0,0 +1,54 @@
+#include <library/cpp/blockcodecs/core/codecs.h>
+#include <library/cpp/blockcodecs/core/common.h>
+#include <library/cpp/blockcodecs/core/register.h>
+
+#include <contrib/libs/fastlz/fastlz.h>
+
+using namespace NBlockCodecs;
+
+namespace {
+ struct TFastLZCodec: public TAddLengthCodec<TFastLZCodec> {
+ inline TFastLZCodec(int level)
+ : MyName("fastlz-" + ToString(level))
+ , Level(level)
+ {
+ }
+
+ static inline size_t DoMaxCompressedLength(size_t in) noexcept {
+ return Max<size_t>(in + in / 20, 128);
+ }
+
+ TStringBuf Name() const noexcept override {
+ return MyName;
+ }
+
+ inline size_t DoCompress(const TData& in, void* buf) const {
+ if (Level) {
+ return fastlz_compress_level(Level, in.data(), in.size(), buf);
+ }
+
+ return fastlz_compress(in.data(), in.size(), buf);
+ }
+
+ inline void DoDecompress(const TData& in, void* out, size_t len) const {
+ const int ret = fastlz_decompress(in.data(), in.size(), out, len);
+
+ if (ret < 0 || (size_t)ret != len) {
+ ythrow TDataError() << TStringBuf("can not decompress");
+ }
+ }
+
+ const TString MyName;
+ const int Level;
+ };
+
+ struct TFastLZRegistrar {
+ TFastLZRegistrar() {
+ for (int i = 0; i < 3; ++i) {
+ RegisterCodec(MakeHolder<TFastLZCodec>(i));
+ }
+ RegisterAlias("fastlz", "fastlz-0");
+ }
+ };
+ const TFastLZRegistrar Registrar{};
+}
diff --git a/library/cpp/blockcodecs/codecs/fastlz/ya.make b/library/cpp/blockcodecs/codecs/fastlz/ya.make
new file mode 100644
index 0000000000..59c09b329b
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/fastlz/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ contrib/libs/fastlz
+ library/cpp/blockcodecs/core
+)
+
+SRCS(
+ GLOBAL fastlz.cpp
+)
+
+END()
diff --git a/library/cpp/blockcodecs/codecs/legacy_zstd06/legacy_zstd06.cpp b/library/cpp/blockcodecs/codecs/legacy_zstd06/legacy_zstd06.cpp
new file mode 100644
index 0000000000..042f031679
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/legacy_zstd06/legacy_zstd06.cpp
@@ -0,0 +1,58 @@
+#include <library/cpp/blockcodecs/core/codecs.h>
+#include <library/cpp/blockcodecs/core/common.h>
+#include <library/cpp/blockcodecs/core/register.h>
+
+#include <contrib/libs/zstd06/common/zstd.h>
+#include <contrib/libs/zstd06/common/zstd_static.h>
+
+using namespace NBlockCodecs;
+
+namespace {
+ struct TZStd06Codec: public TAddLengthCodec<TZStd06Codec> {
+ inline TZStd06Codec(unsigned level)
+ : Level(level)
+ , MyName(TStringBuf("zstd06_") + ToString(Level))
+ {
+ }
+
+ static inline size_t CheckError(size_t ret, const char* what) {
+ if (ZSTD_isError(ret)) {
+ ythrow yexception() << what << TStringBuf(" zstd error: ") << ZSTD_getErrorName(ret);
+ }
+
+ return ret;
+ }
+
+ static inline size_t DoMaxCompressedLength(size_t l) noexcept {
+ return ZSTD_compressBound(l);
+ }
+
+ inline size_t DoCompress(const TData& in, void* out) const {
+ return CheckError(ZSTD_compress(out, DoMaxCompressedLength(in.size()), in.data(), in.size(), Level), "compress");
+ }
+
+ inline void DoDecompress(const TData& in, void* out, size_t dsize) const {
+ const size_t res = CheckError(ZSTD_decompress(out, dsize, in.data(), in.size()), "decompress");
+
+ if (res != dsize) {
+ ythrow TDecompressError(dsize, res);
+ }
+ }
+
+ TStringBuf Name() const noexcept override {
+ return MyName;
+ }
+
+ const unsigned Level;
+ const TString MyName;
+ };
+
+ struct TZStd06Registrar {
+ TZStd06Registrar() {
+ for (unsigned i = 1; i <= ZSTD_maxCLevel(); ++i) {
+ RegisterCodec(MakeHolder<TZStd06Codec>(i));
+ }
+ }
+ };
+ const TZStd06Registrar Registrar{};
+}
diff --git a/library/cpp/blockcodecs/codecs/legacy_zstd06/ya.make b/library/cpp/blockcodecs/codecs/legacy_zstd06/ya.make
new file mode 100644
index 0000000000..067f731233
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/legacy_zstd06/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ contrib/libs/zstd06
+ library/cpp/blockcodecs/core
+)
+
+SRCS(
+ GLOBAL legacy_zstd06.cpp
+)
+
+END()
diff --git a/library/cpp/blockcodecs/codecs/lz4/lz4.cpp b/library/cpp/blockcodecs/codecs/lz4/lz4.cpp
new file mode 100644
index 0000000000..fbf0fe110f
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/lz4/lz4.cpp
@@ -0,0 +1,123 @@
+#include <library/cpp/blockcodecs/core/codecs.h>
+#include <library/cpp/blockcodecs/core/common.h>
+#include <library/cpp/blockcodecs/core/register.h>
+
+#include <contrib/libs/lz4/lz4.h>
+#include <contrib/libs/lz4/lz4hc.h>
+#include <contrib/libs/lz4/generated/iface.h>
+
+using namespace NBlockCodecs;
+
+namespace {
+ struct TLz4Base {
+ static inline size_t DoMaxCompressedLength(size_t in) {
+ return LZ4_compressBound(SafeIntegerCast<int>(in));
+ }
+ };
+
+ struct TLz4FastCompress {
+ inline TLz4FastCompress(int memory)
+ : Memory(memory)
+ , Methods(LZ4Methods(Memory))
+ {
+ }
+
+ inline size_t DoCompress(const TData& in, void* buf) const {
+ return Methods->LZ4CompressLimited(in.data(), (char*)buf, in.size(), LZ4_compressBound(in.size()));
+ }
+
+ inline TString CPrefix() {
+ return "fast" + ToString(Memory);
+ }
+
+ const int Memory;
+ const TLZ4Methods* Methods;
+ };
+
+ struct TLz4BestCompress {
+ inline size_t DoCompress(const TData& in, void* buf) const {
+ return LZ4_compress_HC(in.data(), (char*)buf, in.size(), LZ4_compressBound(in.size()), 0);
+ }
+
+ static inline TString CPrefix() {
+ return "hc";
+ }
+ };
+
+ struct TLz4FastDecompress {
+ inline void DoDecompress(const TData& in, void* out, size_t len) const {
+ ssize_t res = LZ4_decompress_fast(in.data(), (char*)out, len);
+ if (res < 0) {
+ ythrow TDecompressError(res);
+ }
+ }
+
+ static inline TStringBuf DPrefix() {
+ return TStringBuf("fast");
+ }
+ };
+
+ struct TLz4SafeDecompress {
+ inline void DoDecompress(const TData& in, void* out, size_t len) const {
+ ssize_t res = LZ4_decompress_safe(in.data(), (char*)out, in.size(), len);
+ if (res < 0) {
+ ythrow TDecompressError(res);
+ }
+ }
+
+ static inline TStringBuf DPrefix() {
+ return TStringBuf("safe");
+ }
+ };
+
+ template <class TC, class TD>
+ struct TLz4Codec: public TAddLengthCodec<TLz4Codec<TC, TD>>, public TLz4Base, public TC, public TD {
+ inline TLz4Codec()
+ : MyName("lz4-" + TC::CPrefix() + "-" + TD::DPrefix())
+ {
+ }
+
+ template <class T>
+ inline TLz4Codec(const T& t)
+ : TC(t)
+ , MyName("lz4-" + TC::CPrefix() + "-" + TD::DPrefix())
+ {
+ }
+
+ TStringBuf Name() const noexcept override {
+ return MyName;
+ }
+
+ const TString MyName;
+ };
+
+ struct TLz4Registrar {
+ TLz4Registrar() {
+ for (int i = 0; i < 30; ++i) {
+ typedef TLz4Codec<TLz4FastCompress, TLz4FastDecompress> T1;
+ typedef TLz4Codec<TLz4FastCompress, TLz4SafeDecompress> T2;
+
+ THolder<T1> t1(new T1(i));
+ THolder<T2> t2(new T2(i));
+
+ if (t1->Methods) {
+ RegisterCodec(std::move(t1));
+ }
+
+ if (t2->Methods) {
+ RegisterCodec(std::move(t2));
+ }
+ }
+
+ RegisterCodec(MakeHolder<TLz4Codec<TLz4BestCompress, TLz4FastDecompress>>());
+ RegisterCodec(MakeHolder<TLz4Codec<TLz4BestCompress, TLz4SafeDecompress>>());
+
+ RegisterAlias("lz4-fast-safe", "lz4-fast14-safe");
+ RegisterAlias("lz4-fast-fast", "lz4-fast14-fast");
+ RegisterAlias("lz4", "lz4-fast-safe");
+ RegisterAlias("lz4fast", "lz4-fast-fast");
+ RegisterAlias("lz4hc", "lz4-hc-safe");
+ }
+ };
+ const TLz4Registrar Registrar{};
+}
diff --git a/library/cpp/blockcodecs/codecs/lz4/ya.make b/library/cpp/blockcodecs/codecs/lz4/ya.make
new file mode 100644
index 0000000000..f2471d7d96
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/lz4/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ contrib/libs/lz4
+ contrib/libs/lz4/generated
+ library/cpp/blockcodecs/core
+)
+
+SRCS(
+ GLOBAL lz4.cpp
+)
+
+END()
diff --git a/library/cpp/blockcodecs/codecs/lzma/lzma.cpp b/library/cpp/blockcodecs/codecs/lzma/lzma.cpp
new file mode 100644
index 0000000000..6c8d5fded4
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/lzma/lzma.cpp
@@ -0,0 +1,74 @@
+#include <library/cpp/blockcodecs/core/codecs.h>
+#include <library/cpp/blockcodecs/core/common.h>
+#include <library/cpp/blockcodecs/core/register.h>
+
+#include <contrib/libs/lzmasdk/LzmaLib.h>
+
+using namespace NBlockCodecs;
+
+namespace {
+ struct TLzmaCodec: public TAddLengthCodec<TLzmaCodec> {
+ inline TLzmaCodec(int level)
+ : Level(level)
+ , MyName("lzma-" + ToString(Level))
+ {
+ }
+
+ static inline size_t DoMaxCompressedLength(size_t in) noexcept {
+ return Max<size_t>(in + in / 20, 128) + LZMA_PROPS_SIZE;
+ }
+
+ TStringBuf Name() const noexcept override {
+ return MyName;
+ }
+
+ inline size_t DoCompress(const TData& in, void* buf) const {
+ unsigned char* props = (unsigned char*)buf;
+ unsigned char* data = props + LZMA_PROPS_SIZE;
+ size_t destLen = Max<size_t>();
+ size_t outPropsSize = LZMA_PROPS_SIZE;
+
+ const int ret = LzmaCompress(data, &destLen, (const unsigned char*)in.data(), in.size(), props, &outPropsSize, Level, 0, -1, -1, -1, -1, -1);
+
+ if (ret != SZ_OK) {
+ ythrow TCompressError(ret);
+ }
+
+ return destLen + LZMA_PROPS_SIZE;
+ }
+
+ inline void DoDecompress(const TData& in, void* out, size_t len) const {
+ if (in.size() <= LZMA_PROPS_SIZE) {
+ ythrow TDataError() << TStringBuf("broken lzma stream");
+ }
+
+ const unsigned char* props = (const unsigned char*)in.data();
+ const unsigned char* data = props + LZMA_PROPS_SIZE;
+ size_t destLen = len;
+ SizeT srcLen = in.size() - LZMA_PROPS_SIZE;
+
+ const int res = LzmaUncompress((unsigned char*)out, &destLen, data, &srcLen, props, LZMA_PROPS_SIZE);
+
+ if (res != SZ_OK) {
+ ythrow TDecompressError(res);
+ }
+
+ if (destLen != len) {
+ ythrow TDecompressError(len, destLen);
+ }
+ }
+
+ const int Level;
+ const TString MyName;
+ };
+
+ struct TLzmaRegistrar {
+ TLzmaRegistrar() {
+ for (int i = 0; i < 10; ++i) {
+ RegisterCodec(MakeHolder<TLzmaCodec>(i));
+ }
+ RegisterAlias("lzma", "lzma-5");
+ }
+ };
+ const TLzmaRegistrar Registrar{};
+}
diff --git a/library/cpp/blockcodecs/codecs/lzma/ya.make b/library/cpp/blockcodecs/codecs/lzma/ya.make
new file mode 100644
index 0000000000..e145834da6
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/lzma/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ contrib/libs/lzmasdk
+ library/cpp/blockcodecs/core
+)
+
+SRCS(
+ GLOBAL lzma.cpp
+)
+
+END()
diff --git a/library/cpp/blockcodecs/codecs/snappy/snappy.cpp b/library/cpp/blockcodecs/codecs/snappy/snappy.cpp
new file mode 100644
index 0000000000..f6be05a05f
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/snappy/snappy.cpp
@@ -0,0 +1,52 @@
+#include <library/cpp/blockcodecs/core/codecs.h>
+#include <library/cpp/blockcodecs/core/common.h>
+#include <library/cpp/blockcodecs/core/register.h>
+
+#include <contrib/libs/snappy/snappy.h>
+
+using namespace NBlockCodecs;
+
+namespace {
+ struct TSnappyCodec: public ICodec {
+ size_t DecompressedLength(const TData& in) const override {
+ size_t ret;
+
+ if (snappy::GetUncompressedLength(in.data(), in.size(), &ret)) {
+ return ret;
+ }
+
+ ythrow TDecompressError(0);
+ }
+
+ size_t MaxCompressedLength(const TData& in) const override {
+ return snappy::MaxCompressedLength(in.size());
+ }
+
+ size_t Compress(const TData& in, void* out) const override {
+ size_t ret;
+
+ snappy::RawCompress(in.data(), in.size(), (char*)out, &ret);
+
+ return ret;
+ }
+
+ size_t Decompress(const TData& in, void* out) const override {
+ if (snappy::RawUncompress(in.data(), in.size(), (char*)out)) {
+ return DecompressedLength(in);
+ }
+
+ ythrow TDecompressError(0);
+ }
+
+ TStringBuf Name() const noexcept override {
+ return "snappy";
+ }
+ };
+
+ struct TSnappyRegistrar {
+ TSnappyRegistrar() {
+ RegisterCodec(MakeHolder<TSnappyCodec>());
+ }
+ };
+ const TSnappyRegistrar Registrar{};
+}
diff --git a/library/cpp/blockcodecs/codecs/snappy/ya.make b/library/cpp/blockcodecs/codecs/snappy/ya.make
new file mode 100644
index 0000000000..0cf2be2f94
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/snappy/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ contrib/libs/snappy
+ library/cpp/blockcodecs/core
+)
+
+SRCS(
+ GLOBAL snappy.cpp
+)
+
+END()
diff --git a/library/cpp/blockcodecs/codecs/zlib/ya.make b/library/cpp/blockcodecs/codecs/zlib/ya.make
new file mode 100644
index 0000000000..9f04995f66
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/zlib/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ contrib/libs/zlib
+ library/cpp/blockcodecs/core
+)
+
+SRCS(
+ GLOBAL zlib.cpp
+)
+
+END()
diff --git a/library/cpp/blockcodecs/codecs/zlib/zlib.cpp b/library/cpp/blockcodecs/codecs/zlib/zlib.cpp
new file mode 100644
index 0000000000..cdb556c36d
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/zlib/zlib.cpp
@@ -0,0 +1,64 @@
+#include <library/cpp/blockcodecs/core/codecs.h>
+#include <library/cpp/blockcodecs/core/common.h>
+#include <library/cpp/blockcodecs/core/register.h>
+
+#include <contrib/libs/zlib/zlib.h>
+
+using namespace NBlockCodecs;
+
+namespace {
+ struct TZLibCodec: public TAddLengthCodec<TZLibCodec> {
+ inline TZLibCodec(int level)
+ : MyName("zlib-" + ToString(level))
+ , Level(level)
+ {
+ }
+
+ static inline size_t DoMaxCompressedLength(size_t in) noexcept {
+ return compressBound(in);
+ }
+
+ TStringBuf Name() const noexcept override {
+ return MyName;
+ }
+
+ inline size_t DoCompress(const TData& in, void* buf) const {
+ //TRASH detected
+ uLong ret = Max<unsigned int>();
+
+ int cres = compress2((Bytef*)buf, &ret, (const Bytef*)in.data(), in.size(), Level);
+
+ if (cres != Z_OK) {
+ ythrow TCompressError(cres);
+ }
+
+ return ret;
+ }
+
+ inline void DoDecompress(const TData& in, void* out, size_t len) const {
+ uLong ret = len;
+
+ int uncres = uncompress((Bytef*)out, &ret, (const Bytef*)in.data(), in.size());
+ if (uncres != Z_OK) {
+ ythrow TDecompressError(uncres);
+ }
+
+ if (ret != len) {
+ ythrow TDecompressError(len, ret);
+ }
+ }
+
+ const TString MyName;
+ const int Level;
+ };
+
+ struct TZLibRegistrar {
+ TZLibRegistrar() {
+ for (int i = 0; i < 10; ++i) {
+ RegisterCodec(MakeHolder<TZLibCodec>(i));
+ }
+ RegisterAlias("zlib", "zlib-6");
+ }
+ };
+ const TZLibRegistrar Registrar{};
+}
diff --git a/library/cpp/blockcodecs/codecs/zstd/ya.make b/library/cpp/blockcodecs/codecs/zstd/ya.make
new file mode 100644
index 0000000000..c077dd47b7
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/zstd/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ contrib/libs/zstd
+ library/cpp/blockcodecs/core
+)
+
+SRCS(
+ GLOBAL zstd.cpp
+)
+
+END()
diff --git a/library/cpp/blockcodecs/codecs/zstd/zstd.cpp b/library/cpp/blockcodecs/codecs/zstd/zstd.cpp
new file mode 100644
index 0000000000..95299b3f6d
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs/zstd/zstd.cpp
@@ -0,0 +1,59 @@
+#include <library/cpp/blockcodecs/core/codecs.h>
+#include <library/cpp/blockcodecs/core/common.h>
+#include <library/cpp/blockcodecs/core/register.h>
+
+#define ZSTD_STATIC_LINKING_ONLY
+#include <contrib/libs/zstd/include/zstd.h>
+
+using namespace NBlockCodecs;
+
+namespace {
+ struct TZStd08Codec: public TAddLengthCodec<TZStd08Codec> {
+ inline TZStd08Codec(unsigned level)
+ : Level(level)
+ , MyName(TStringBuf("zstd08_") + ToString(Level))
+ {
+ }
+
+ static inline size_t CheckError(size_t ret, const char* what) {
+ if (ZSTD_isError(ret)) {
+ ythrow yexception() << what << TStringBuf(" zstd error: ") << ZSTD_getErrorName(ret);
+ }
+
+ return ret;
+ }
+
+ static inline size_t DoMaxCompressedLength(size_t l) noexcept {
+ return ZSTD_compressBound(l);
+ }
+
+ inline size_t DoCompress(const TData& in, void* out) const {
+ return CheckError(ZSTD_compress(out, DoMaxCompressedLength(in.size()), in.data(), in.size(), Level), "compress");
+ }
+
+ inline void DoDecompress(const TData& in, void* out, size_t dsize) const {
+ const size_t res = CheckError(ZSTD_decompress(out, dsize, in.data(), in.size()), "decompress");
+
+ if (res != dsize) {
+ ythrow TDecompressError(dsize, res);
+ }
+ }
+
+ TStringBuf Name() const noexcept override {
+ return MyName;
+ }
+
+ const unsigned Level;
+ const TString MyName;
+ };
+
+ struct TZStd08Registrar {
+ TZStd08Registrar() {
+ for (int i = 1; i <= ZSTD_maxCLevel(); ++i) {
+ RegisterCodec(MakeHolder<TZStd08Codec>(i));
+ RegisterAlias("zstd_" + ToString(i), "zstd08_" + ToString(i));
+ }
+ }
+ };
+ const TZStd08Registrar Registrar{};
+}
diff --git a/library/cpp/blockcodecs/codecs_ut.cpp b/library/cpp/blockcodecs/codecs_ut.cpp
new file mode 100644
index 0000000000..bfe5a23690
--- /dev/null
+++ b/library/cpp/blockcodecs/codecs_ut.cpp
@@ -0,0 +1,340 @@
+#include "codecs.h"
+#include "stream.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/str.h>
+#include <util/string/join.h>
+#include <util/digest/multi.h>
+
+Y_UNIT_TEST_SUITE(TBlockCodecsTest) {
+ using namespace NBlockCodecs;
+
+ TBuffer Buffer(TStringBuf b) {
+ TBuffer bb;
+ bb.Assign(b.data(), b.size());
+ return bb;
+ }
+
+ void TestAllAtOnce(size_t n, size_t m) {
+ TVector<TBuffer> datas;
+
+ datas.emplace_back();
+ datas.push_back(Buffer("na gorshke sidel korol"));
+ datas.push_back(Buffer(TStringBuf("", 1)));
+ datas.push_back(Buffer(" "));
+ datas.push_back(Buffer(" "));
+ datas.push_back(Buffer(" "));
+ datas.push_back(Buffer(" "));
+
+ {
+ TStringStream data;
+
+ for (size_t i = 0; i < 1024; ++i) {
+ data << " " << i;
+ }
+
+ datas.push_back(Buffer(data.Str()));
+ }
+
+ TCodecList lst = ListAllCodecs();
+
+ for (size_t i = 0; i < lst.size(); ++i) {
+ const ICodec* c = Codec(lst[i]);
+ const auto h = MultiHash(c->Name(), i, 1);
+
+ if (h % n == m) {
+ } else {
+ continue;
+ }
+
+ for (size_t j = 0; j < datas.size(); ++j) {
+ const TBuffer& data = datas[j];
+ TString res;
+
+ try {
+ TBuffer e, d;
+ c->Encode(data, e);
+ c->Decode(e, d);
+ d.AsString(res);
+ UNIT_ASSERT_EQUAL(NBlockCodecs::TData(res), NBlockCodecs::TData(data));
+ } catch (...) {
+ Cerr << c->Name() << "(" << res.Quote() << ")(" << TString{NBlockCodecs::TData(data)}.Quote() << ")" << Endl;
+
+ throw;
+ }
+ }
+ }
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce0) {
+ TestAllAtOnce(20, 0);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce1) {
+ TestAllAtOnce(20, 1);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce2) {
+ TestAllAtOnce(20, 2);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce3) {
+ TestAllAtOnce(20, 3);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce4) {
+ TestAllAtOnce(20, 4);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce5) {
+ TestAllAtOnce(20, 5);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce6) {
+ TestAllAtOnce(20, 6);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce7) {
+ TestAllAtOnce(20, 7);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce8) {
+ TestAllAtOnce(20, 8);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce9) {
+ TestAllAtOnce(20, 9);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce10) {
+ TestAllAtOnce(20, 10);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce12) {
+ TestAllAtOnce(20, 12);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce13) {
+ TestAllAtOnce(20, 13);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce14) {
+ TestAllAtOnce(20, 14);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce15) {
+ TestAllAtOnce(20, 15);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce16) {
+ TestAllAtOnce(20, 16);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce17) {
+ TestAllAtOnce(20, 17);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce18) {
+ TestAllAtOnce(20, 18);
+ }
+
+ Y_UNIT_TEST(TestAllAtOnce19) {
+ TestAllAtOnce(20, 19);
+ }
+
+ void TestStreams(size_t n, size_t m) {
+ TVector<TString> datas;
+ TString res;
+
+ for (size_t i = 0; i < 256; ++i) {
+ datas.push_back(TString(i, (char)(i % 128)));
+ }
+
+ for (size_t i = 0; i < datas.size(); ++i) {
+ res += datas[i];
+ }
+
+ TCodecList lst = ListAllCodecs();
+
+ for (size_t i = 0; i < lst.size(); ++i) {
+ TStringStream ss;
+
+ const ICodec* c = Codec(lst[i]);
+ const auto h = MultiHash(c->Name(), i, 2);
+
+ if (h % n == m) {
+ } else {
+ continue;
+ }
+
+ {
+ TCodedOutput out(&ss, c, 1234);
+
+ for (size_t j = 0; j < datas.size(); ++j) {
+ out << datas[j];
+ }
+
+ out.Finish();
+ }
+
+ const TString resNew = TDecodedInput(&ss).ReadAll();
+
+ try {
+ UNIT_ASSERT_EQUAL(resNew, res);
+ } catch (...) {
+ Cerr << c->Name() << Endl;
+
+ throw;
+ }
+ }
+ }
+
+ Y_UNIT_TEST(TestStreams0) {
+ TestStreams(20, 0);
+ }
+
+ Y_UNIT_TEST(TestStreams1) {
+ TestStreams(20, 1);
+ }
+
+ Y_UNIT_TEST(TestStreams2) {
+ TestStreams(20, 2);
+ }
+
+ Y_UNIT_TEST(TestStreams3) {
+ TestStreams(20, 3);
+ }
+
+ Y_UNIT_TEST(TestStreams4) {
+ TestStreams(20, 4);
+ }
+
+ Y_UNIT_TEST(TestStreams5) {
+ TestStreams(20, 5);
+ }
+
+ Y_UNIT_TEST(TestStreams6) {
+ TestStreams(20, 6);
+ }
+
+ Y_UNIT_TEST(TestStreams7) {
+ TestStreams(20, 7);
+ }
+
+ Y_UNIT_TEST(TestStreams8) {
+ TestStreams(20, 8);
+ }
+
+ Y_UNIT_TEST(TestStreams9) {
+ TestStreams(20, 9);
+ }
+
+ Y_UNIT_TEST(TestStreams10) {
+ TestStreams(20, 10);
+ }
+
+ Y_UNIT_TEST(TestStreams11) {
+ TestStreams(20, 11);
+ }
+
+ Y_UNIT_TEST(TestStreams12) {
+ TestStreams(20, 12);
+ }
+
+ Y_UNIT_TEST(TestStreams13) {
+ TestStreams(20, 13);
+ }
+
+ Y_UNIT_TEST(TestStreams14) {
+ TestStreams(20, 14);
+ }
+
+ Y_UNIT_TEST(TestStreams15) {
+ TestStreams(20, 15);
+ }
+
+ Y_UNIT_TEST(TestStreams16) {
+ TestStreams(20, 16);
+ }
+
+ Y_UNIT_TEST(TestStreams17) {
+ TestStreams(20, 17);
+ }
+
+ Y_UNIT_TEST(TestStreams18) {
+ TestStreams(20, 18);
+ }
+
+ Y_UNIT_TEST(TestStreams19) {
+ TestStreams(20, 19);
+ }
+
+ Y_UNIT_TEST(TestMaxPossibleDecompressedSize) {
+
+ UNIT_ASSERT_VALUES_EQUAL(GetMaxPossibleDecompressedLength(), Max<size_t>());
+
+ TVector<char> input(10001, ' ');
+ TCodecList codecs = ListAllCodecs();
+ SetMaxPossibleDecompressedLength(10000);
+
+ for (const auto& codec : codecs) {
+ const ICodec* c = Codec(codec);
+ TBuffer inputBuffer(input.data(), input.size());
+ TBuffer output;
+ TBuffer decompressed;
+ c->Encode(inputBuffer, output);
+ UNIT_ASSERT_EXCEPTION(c->Decode(output, decompressed), yexception);
+ }
+
+ // restore status quo
+ SetMaxPossibleDecompressedLength(Max<size_t>());
+ }
+
+ Y_UNIT_TEST(TestListAllCodecs) {
+ static const TString ALL_CODECS =
+ "brotli_1,brotli_10,brotli_11,brotli_2,brotli_3,brotli_4,brotli_5,brotli_6,brotli_7,brotli_8,brotli_9,"
+
+ "bzip2,bzip2-1,bzip2-2,bzip2-3,bzip2-4,bzip2-5,bzip2-6,bzip2-7,bzip2-8,bzip2-9,"
+
+ "fastlz,fastlz-0,fastlz-1,fastlz-2,"
+
+ "lz4,lz4-fast-fast,lz4-fast-safe,lz4-fast10-fast,lz4-fast10-safe,lz4-fast11-fast,lz4-fast11-safe,"
+ "lz4-fast12-fast,lz4-fast12-safe,lz4-fast13-fast,lz4-fast13-safe,lz4-fast14-fast,lz4-fast14-safe,"
+ "lz4-fast15-fast,lz4-fast15-safe,lz4-fast16-fast,lz4-fast16-safe,lz4-fast17-fast,lz4-fast17-safe,"
+ "lz4-fast18-fast,lz4-fast18-safe,lz4-fast19-fast,lz4-fast19-safe,lz4-fast20-fast,lz4-fast20-safe,"
+ "lz4-hc-fast,lz4-hc-safe,lz4fast,lz4hc,"
+
+ "lzma,lzma-0,lzma-1,lzma-2,lzma-3,lzma-4,lzma-5,lzma-6,lzma-7,lzma-8,lzma-9,"
+
+ "null,"
+
+ "snappy,"
+
+ "zlib,zlib-0,zlib-1,zlib-2,zlib-3,zlib-4,zlib-5,zlib-6,zlib-7,zlib-8,zlib-9,"
+
+ "zstd06_1,zstd06_10,zstd06_11,zstd06_12,zstd06_13,zstd06_14,zstd06_15,zstd06_16,zstd06_17,zstd06_18,"
+ "zstd06_19,zstd06_2,zstd06_20,zstd06_21,zstd06_22,zstd06_3,zstd06_4,zstd06_5,zstd06_6,zstd06_7,zstd06_8,"
+ "zstd06_9,"
+
+ "zstd08_1,zstd08_10,zstd08_11,zstd08_12,zstd08_13,zstd08_14,zstd08_15,zstd08_16,zstd08_17,zstd08_18,"
+ "zstd08_19,zstd08_2,zstd08_20,zstd08_21,zstd08_22,zstd08_3,zstd08_4,zstd08_5,zstd08_6,zstd08_7,zstd08_8,"
+ "zstd08_9,zstd_1,zstd_10,zstd_11,zstd_12,zstd_13,zstd_14,zstd_15,zstd_16,zstd_17,zstd_18,zstd_19,zstd_2,"
+ "zstd_20,zstd_21,zstd_22,zstd_3,zstd_4,zstd_5,zstd_6,zstd_7,zstd_8,zstd_9";
+
+ UNIT_ASSERT_VALUES_EQUAL(ALL_CODECS, JoinSeq(",", ListAllCodecs()));
+ }
+
+ Y_UNIT_TEST(TestEncodeDecodeIntoString) {
+ TStringBuf data = "na gorshke sidel korol";
+
+ TCodecList codecs = ListAllCodecs();
+ for (const auto& codec : codecs) {
+ const ICodec* c = Codec(codec);
+ TString encoded = c->Encode(data);
+ TString decoded = c->Decode(encoded);
+
+ UNIT_ASSERT_VALUES_EQUAL(decoded, data);
+ }
+ }
+}
diff --git a/library/cpp/blockcodecs/core/codecs.cpp b/library/cpp/blockcodecs/core/codecs.cpp
new file mode 100644
index 0000000000..21506e812b
--- /dev/null
+++ b/library/cpp/blockcodecs/core/codecs.cpp
@@ -0,0 +1,148 @@
+#include "codecs.h"
+#include "common.h"
+#include "register.h"
+
+#include <util/ysaveload.h>
+#include <util/stream/null.h>
+#include <util/stream/mem.h>
+#include <util/string/cast.h>
+#include <util/string/join.h>
+#include <util/system/align.h>
+#include <util/system/unaligned_mem.h>
+#include <util/generic/hash.h>
+#include <util/generic/cast.h>
+#include <util/generic/deque.h>
+#include <util/generic/buffer.h>
+#include <util/generic/array_ref.h>
+#include <util/generic/singleton.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/mem_copy.h>
+
+using namespace NBlockCodecs;
+
+namespace {
+
+ struct TCodecFactory {
+ inline TCodecFactory() {
+ Add(&Null);
+ }
+
+ inline const ICodec* Find(const TStringBuf& name) const {
+ auto it = Registry.find(name);
+
+ if (it == Registry.end()) {
+ ythrow TNotFound() << "can not found " << name << " codec";
+ }
+
+ return it->second;
+ }
+
+ inline void ListCodecs(TCodecList& lst) const {
+ for (const auto& it : Registry) {
+ lst.push_back(it.first);
+ }
+
+ Sort(lst.begin(), lst.end());
+ }
+
+ inline void Add(ICodec* codec) {
+ Registry[codec->Name()] = codec;
+ }
+
+ inline void Add(TCodecPtr codec) {
+ Codecs.push_back(std::move(codec));
+ Add(Codecs.back().Get());
+ }
+
+ inline void Alias(TStringBuf from, TStringBuf to) {
+ Tmp.emplace_back(from);
+ Registry[Tmp.back()] = Registry[to];
+ }
+
+ TDeque<TString> Tmp;
+ TNullCodec Null;
+ TVector<TCodecPtr> Codecs;
+ typedef THashMap<TStringBuf, ICodec*> TRegistry;
+ TRegistry Registry;
+
+ // SEARCH-8344: Global decompressed size limiter (to prevent remote DoS)
+ size_t MaxPossibleDecompressedLength = Max<size_t>();
+ };
+}
+
+const ICodec* NBlockCodecs::Codec(const TStringBuf& name) {
+ return Singleton<TCodecFactory>()->Find(name);
+}
+
+TCodecList NBlockCodecs::ListAllCodecs() {
+ TCodecList ret;
+
+ Singleton<TCodecFactory>()->ListCodecs(ret);
+
+ return ret;
+}
+
+TString NBlockCodecs::ListAllCodecsAsString() {
+ return JoinSeq(TStringBuf(","), ListAllCodecs());
+}
+
+void NBlockCodecs::RegisterCodec(TCodecPtr codec) {
+ Singleton<TCodecFactory>()->Add(std::move(codec));
+}
+
+void NBlockCodecs::RegisterAlias(TStringBuf from, TStringBuf to) {
+ Singleton<TCodecFactory>()->Alias(from, to);
+}
+
+void NBlockCodecs::SetMaxPossibleDecompressedLength(size_t maxPossibleDecompressedLength) {
+ Singleton<TCodecFactory>()->MaxPossibleDecompressedLength = maxPossibleDecompressedLength;
+}
+
+size_t NBlockCodecs::GetMaxPossibleDecompressedLength() {
+ return Singleton<TCodecFactory>()->MaxPossibleDecompressedLength;
+}
+
+size_t ICodec::GetDecompressedLength(const TData& in) const {
+ const size_t len = DecompressedLength(in);
+
+ Y_ENSURE(
+ len <= NBlockCodecs::GetMaxPossibleDecompressedLength(),
+ "Attempt to decompress the block that is larger than maximum possible decompressed length, "
+ "see SEARCH-8344 for details. "
+ );
+ return len;
+}
+
+void ICodec::Encode(const TData& in, TBuffer& out) const {
+ const size_t maxLen = MaxCompressedLength(in);
+
+ out.Reserve(maxLen);
+ out.Resize(Compress(in, out.Data()));
+}
+
+void ICodec::Decode(const TData& in, TBuffer& out) const {
+ const size_t len = GetDecompressedLength(in);
+
+ out.Reserve(len);
+ out.Resize(Decompress(in, out.Data()));
+}
+
+void ICodec::Encode(const TData& in, TString& out) const {
+ const size_t maxLen = MaxCompressedLength(in);
+ out.ReserveAndResize(maxLen);
+
+ size_t actualLen = Compress(in, out.begin());
+ Y_ASSERT(actualLen <= maxLen);
+ out.resize(actualLen);
+}
+
+void ICodec::Decode(const TData& in, TString& out) const {
+ const size_t maxLen = GetDecompressedLength(in);
+ out.ReserveAndResize(maxLen);
+
+ size_t actualLen = Decompress(in, out.begin());
+ Y_ASSERT(actualLen <= maxLen);
+ out.resize(actualLen);
+}
+
+ICodec::~ICodec() = default;
diff --git a/library/cpp/blockcodecs/core/codecs.h b/library/cpp/blockcodecs/core/codecs.h
new file mode 100644
index 0000000000..9c93c00274
--- /dev/null
+++ b/library/cpp/blockcodecs/core/codecs.h
@@ -0,0 +1,90 @@
+#pragma once
+
+#include <util/generic/buffer.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+#include <util/generic/typetraits.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+namespace NBlockCodecs {
+ struct TData: public TStringBuf {
+ inline TData() = default;
+
+ Y_HAS_MEMBER(Data);
+ Y_HAS_MEMBER(Size);
+
+ template <class T, std::enable_if_t<!THasSize<T>::value || !THasData<T>::value, int> = 0>
+ inline TData(const T& t)
+ : TStringBuf((const char*)t.data(), t.size())
+ {
+ }
+
+ template <class T, std::enable_if_t<THasSize<T>::value && THasData<T>::value, int> = 0>
+ inline TData(const T& t)
+ : TStringBuf((const char*)t.Data(), t.Size())
+ {
+ }
+ };
+
+ struct TCodecError: public yexception {
+ };
+
+ struct TNotFound: public TCodecError {
+ };
+
+ struct TDataError: public TCodecError {
+ };
+
+ struct ICodec {
+ virtual ~ICodec();
+
+ // main interface
+ virtual size_t DecompressedLength(const TData& in) const = 0;
+ virtual size_t MaxCompressedLength(const TData& in) const = 0;
+ virtual size_t Compress(const TData& in, void* out) const = 0;
+ virtual size_t Decompress(const TData& in, void* out) const = 0;
+
+ virtual TStringBuf Name() const noexcept = 0;
+
+ // some useful helpers
+ void Encode(const TData& in, TBuffer& out) const;
+ void Decode(const TData& in, TBuffer& out) const;
+
+ void Encode(const TData& in, TString& out) const;
+ void Decode(const TData& in, TString& out) const;
+
+ inline TString Encode(const TData& in) const {
+ TString out;
+
+ Encode(in, out);
+
+ return out;
+ }
+
+ inline TString Decode(const TData& in) const {
+ TString out;
+
+ Decode(in, out);
+
+ return out;
+ }
+ private:
+ size_t GetDecompressedLength(const TData& in) const;
+ };
+
+ using TCodecPtr = THolder<ICodec>;
+
+ const ICodec* Codec(const TStringBuf& name);
+
+ // some aux methods
+ typedef TVector<TStringBuf> TCodecList;
+ TCodecList ListAllCodecs();
+ TString ListAllCodecsAsString();
+
+ // SEARCH-8344: Get the size of max possible decompressed block
+ size_t GetMaxPossibleDecompressedLength();
+ // SEARCH-8344: Globally set the size of max possible decompressed block
+ void SetMaxPossibleDecompressedLength(size_t maxPossibleDecompressedLength);
+
+}
diff --git a/library/cpp/blockcodecs/core/common.h b/library/cpp/blockcodecs/core/common.h
new file mode 100644
index 0000000000..f05df4d334
--- /dev/null
+++ b/library/cpp/blockcodecs/core/common.h
@@ -0,0 +1,105 @@
+#pragma once
+
+#include "codecs.h"
+
+#include <util/ysaveload.h>
+#include <util/stream/null.h>
+#include <util/stream/mem.h>
+#include <util/string/cast.h>
+#include <util/string/join.h>
+#include <util/system/align.h>
+#include <util/system/unaligned_mem.h>
+#include <util/generic/hash.h>
+#include <util/generic/cast.h>
+#include <util/generic/buffer.h>
+#include <util/generic/array_ref.h>
+#include <util/generic/singleton.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/mem_copy.h>
+
+namespace NBlockCodecs {
+ struct TDecompressError: public TDataError {
+ TDecompressError(int code) {
+ *this << "cannot decompress (errcode " << code << ")";
+ }
+
+ TDecompressError(size_t exp, size_t real) {
+ *this << "broken input (expected len: " << exp << ", got: " << real << ")";
+ }
+ };
+
+ struct TCompressError: public TDataError {
+ TCompressError(int code) {
+ *this << "cannot compress (errcode " << code << ")";
+ }
+ };
+
+ struct TNullCodec: public ICodec {
+ size_t DecompressedLength(const TData& in) const override {
+ return in.size();
+ }
+
+ size_t MaxCompressedLength(const TData& in) const override {
+ return in.size();
+ }
+
+ size_t Compress(const TData& in, void* out) const override {
+ MemCopy((char*)out, in.data(), in.size());
+
+ return in.size();
+ }
+
+ size_t Decompress(const TData& in, void* out) const override {
+ MemCopy((char*)out, in.data(), in.size());
+
+ return in.size();
+ }
+
+ TStringBuf Name() const noexcept override {
+ return TStringBuf("null");
+ }
+ };
+
+ template <class T>
+ struct TAddLengthCodec: public ICodec {
+ static inline void Check(const TData& in) {
+ if (in.size() < sizeof(ui64)) {
+ ythrow TDataError() << "too small input";
+ }
+ }
+
+ size_t DecompressedLength(const TData& in) const override {
+ Check(in);
+
+ return ReadUnaligned<ui64>(in.data());
+ }
+
+ size_t MaxCompressedLength(const TData& in) const override {
+ return T::DoMaxCompressedLength(in.size()) + sizeof(ui64);
+ }
+
+ size_t Compress(const TData& in, void* out) const override {
+ ui64* ptr = (ui64*)out;
+
+ WriteUnaligned<ui64>(ptr, (ui64) in.size());
+
+ return Base()->DoCompress(!in ? TData(TStringBuf("")) : in, ptr + 1) + sizeof(*ptr);
+ }
+
+ size_t Decompress(const TData& in, void* out) const override {
+ Check(in);
+
+ const auto len = ReadUnaligned<ui64>(in.data());
+
+ if (!len)
+ return 0;
+
+ Base()->DoDecompress(TData(in).Skip(sizeof(len)), out, len);
+ return len;
+ }
+
+ inline const T* Base() const noexcept {
+ return static_cast<const T*>(this);
+ }
+ };
+}
diff --git a/library/cpp/blockcodecs/core/register.h b/library/cpp/blockcodecs/core/register.h
new file mode 100644
index 0000000000..fa1186dd70
--- /dev/null
+++ b/library/cpp/blockcodecs/core/register.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "codecs.h"
+
+namespace NBlockCodecs{
+
+ void RegisterCodec(TCodecPtr codec);
+ void RegisterAlias(TStringBuf from, TStringBuf to);
+
+}
diff --git a/library/cpp/blockcodecs/core/stream.cpp b/library/cpp/blockcodecs/core/stream.cpp
new file mode 100644
index 0000000000..4f7db3c32b
--- /dev/null
+++ b/library/cpp/blockcodecs/core/stream.cpp
@@ -0,0 +1,212 @@
+#include "stream.h"
+#include "codecs.h"
+
+#include <util/digest/murmur.h>
+#include <util/generic/scope.h>
+#include <util/generic/cast.h>
+#include <util/generic/hash.h>
+#include <util/generic/singleton.h>
+#include <util/stream/mem.h>
+#include <util/ysaveload.h>
+
+using namespace NBlockCodecs;
+
+namespace {
+ constexpr size_t MAX_BUF_LEN = 128 * 1024 * 1024;
+
+ typedef ui16 TCodecID;
+ typedef ui64 TBlockLen;
+
+ struct TIds {
+ inline TIds() {
+ const TCodecList lst = ListAllCodecs();
+
+ for (size_t i = 0; i < lst.size(); ++i) {
+ const ICodec* c = Codec(lst[i]);
+
+ ByID[CodecID(c)] = c;
+ }
+ }
+
+ static inline TCodecID CodecID(const ICodec* c) {
+ const TStringBuf name = c->Name();
+
+ union {
+ ui16 Parts[2];
+ ui32 Data;
+ } x;
+
+ x.Data = MurmurHash<ui32>(name.data(), name.size());
+
+ return x.Parts[1] ^ x.Parts[0];
+ }
+
+ inline const ICodec* Find(TCodecID id) const {
+ TByID::const_iterator it = ByID.find(id);
+
+ if (it != ByID.end()) {
+ return it->second;
+ }
+
+ ythrow yexception() << "can not find codec by id " << id;
+ }
+
+ typedef THashMap<TCodecID, const ICodec*> TByID;
+ TByID ByID;
+ };
+
+ TCodecID CodecID(const ICodec* c) {
+ return TIds::CodecID(c);
+ }
+
+ const ICodec* CodecByID(TCodecID id) {
+ return Singleton<TIds>()->Find(id);
+ }
+}
+
+TCodedOutput::TCodedOutput(IOutputStream* out, const ICodec* c, size_t bufLen)
+ : C_(c)
+ , D_(bufLen)
+ , S_(out)
+{
+ if (bufLen > MAX_BUF_LEN) {
+ ythrow yexception() << TStringBuf("too big buffer size: ") << bufLen;
+ }
+}
+
+TCodedOutput::~TCodedOutput() {
+ try {
+ Finish();
+ } catch (...) {
+ }
+}
+
+void TCodedOutput::DoWrite(const void* buf, size_t len) {
+ const char* in = (const char*)buf;
+
+ while (len) {
+ const size_t avail = D_.Avail();
+
+ if (len < avail) {
+ D_.Append(in, len);
+
+ return;
+ }
+
+ D_.Append(in, avail);
+
+ Y_ASSERT(!D_.Avail());
+
+ in += avail;
+ len -= avail;
+
+ Y_VERIFY(FlushImpl(), "flush on writing failed");
+ }
+}
+
+bool TCodedOutput::FlushImpl() {
+ const bool ret = !D_.Empty();
+ const size_t payload = sizeof(TCodecID) + sizeof(TBlockLen);
+ O_.Reserve(C_->MaxCompressedLength(D_) + payload);
+
+ void* out = O_.Data() + payload;
+ const size_t olen = C_->Compress(D_, out);
+
+ {
+ TMemoryOutput mo(O_.Data(), payload);
+
+ ::Save(&mo, CodecID(C_));
+ ::Save(&mo, SafeIntegerCast<TBlockLen>(olen));
+ }
+
+ S_->Write(O_.Data(), payload + olen);
+
+ D_.Clear();
+ O_.Clear();
+
+ return ret;
+}
+
+void TCodedOutput::DoFlush() {
+ if (S_ && !D_.Empty()) {
+ FlushImpl();
+ }
+}
+
+void TCodedOutput::DoFinish() {
+ if (S_) {
+ Y_DEFER {
+ S_ = nullptr;
+ };
+
+ if (FlushImpl()) {
+ //always write zero-length block as eos marker
+ FlushImpl();
+ }
+ }
+}
+
+TDecodedInput::TDecodedInput(IInputStream* in)
+ : S_(in)
+ , C_(nullptr)
+{
+}
+
+TDecodedInput::TDecodedInput(IInputStream* in, const ICodec* codec)
+ : S_(in)
+ , C_(codec)
+{
+}
+
+TDecodedInput::~TDecodedInput() = default;
+
+size_t TDecodedInput::DoUnboundedNext(const void** ptr) {
+ if (!S_) {
+ return 0;
+ }
+
+ TCodecID codecId;
+ TBlockLen blockLen;
+
+ {
+ const size_t payload = sizeof(TCodecID) + sizeof(TBlockLen);
+ char buf[32];
+
+ S_->LoadOrFail(buf, payload);
+
+ TMemoryInput in(buf, payload);
+
+ ::Load(&in, codecId);
+ ::Load(&in, blockLen);
+ }
+
+ if (!blockLen) {
+ S_ = nullptr;
+
+ return 0;
+ }
+
+ if (Y_UNLIKELY(blockLen > 1024 * 1024 * 1024)) {
+ ythrow yexception() << "block size exceeds 1 GiB";
+ }
+
+ TBuffer block;
+ block.Resize(blockLen);
+
+ S_->LoadOrFail(block.Data(), blockLen);
+
+ auto codec = CodecByID(codecId);
+
+ if (C_) {
+ Y_ENSURE(C_->Name() == codec->Name(), TStringBuf("incorrect stream codec"));
+ }
+
+ if (codec->DecompressedLength(block) > MAX_BUF_LEN) {
+ ythrow yexception() << "broken stream";
+ }
+
+ codec->Decode(block, D_);
+ *ptr = D_.Data();
+
+ return D_.Size();
+}
diff --git a/library/cpp/blockcodecs/core/stream.h b/library/cpp/blockcodecs/core/stream.h
new file mode 100644
index 0000000000..fd44ef88f2
--- /dev/null
+++ b/library/cpp/blockcodecs/core/stream.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <util/stream/walk.h>
+#include <util/stream/input.h>
+#include <util/stream/output.h>
+#include <util/stream/zerocopy.h>
+#include <util/generic/buffer.h>
+
+namespace NBlockCodecs {
+ struct ICodec;
+
+ class TCodedOutput: public IOutputStream {
+ public:
+ TCodedOutput(IOutputStream* out, const ICodec* c, size_t bufLen);
+ ~TCodedOutput() override;
+
+ private:
+ void DoWrite(const void* buf, size_t len) override;
+ void DoFlush() override;
+ void DoFinish() override;
+
+ bool FlushImpl();
+
+ private:
+ const ICodec* C_;
+ TBuffer D_;
+ TBuffer O_;
+ IOutputStream* S_;
+ };
+
+ class TDecodedInput: public IWalkInput {
+ public:
+ TDecodedInput(IInputStream* in);
+ TDecodedInput(IInputStream* in, const ICodec* codec);
+
+ ~TDecodedInput() override;
+
+ private:
+ size_t DoUnboundedNext(const void** ptr) override;
+
+ private:
+ TBuffer D_;
+ IInputStream* S_;
+ const ICodec* C_;
+ };
+}
diff --git a/library/cpp/blockcodecs/core/ya.make b/library/cpp/blockcodecs/core/ya.make
new file mode 100644
index 0000000000..069e15927b
--- /dev/null
+++ b/library/cpp/blockcodecs/core/ya.make
@@ -0,0 +1,10 @@
+LIBRARY()
+
+OWNER(pg)
+
+SRCS(
+ codecs.cpp
+ stream.cpp
+)
+
+END()
diff --git a/library/cpp/blockcodecs/fuzz/main.cpp b/library/cpp/blockcodecs/fuzz/main.cpp
new file mode 100644
index 0000000000..763c6c5a10
--- /dev/null
+++ b/library/cpp/blockcodecs/fuzz/main.cpp
@@ -0,0 +1,84 @@
+#include <contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_macro.h>
+#include <google/protobuf/stubs/logging.h>
+
+#include <library/cpp/blockcodecs/codecs.h>
+#include <library/cpp/blockcodecs/fuzz/proto/case.pb.h>
+#include <library/cpp/blockcodecs/stream.h>
+
+#include <util/stream/input.h>
+#include <util/stream/length.h>
+#include <util/stream/mem.h>
+#include <util/stream/null.h>
+#include <util/stream/str.h>
+
+using NBlockCodecs::NFuzz::TPackUnpackCase;
+using NBlockCodecs::TCodedOutput;
+using NBlockCodecs::TDecodedInput;
+
+static void ValidateBufferSize(const ui32 size) {
+ Y_ENSURE(size > 0 && size <= 16ULL * 1024);
+}
+
+static void DoOnlyDecode(const TPackUnpackCase& case_) {
+ if (!case_.GetPacked()) {
+ return;
+ }
+
+ TMemoryInput mi(case_.GetData().data(), case_.GetData().size());
+ TDecodedInput di(&mi);
+ TNullOutput no;
+ TCountingOutput cno(&no);
+ TransferData(&di, &cno);
+}
+
+static void DoDecodeEncode(const TPackUnpackCase& case_) {
+ auto* const codec = NBlockCodecs::Codec(case_.GetCodecName());
+ Y_ENSURE(codec);
+
+ TMemoryInput mi(case_.GetData().data(), case_.GetData().size());
+ TDecodedInput di(&mi, codec);
+ TStringStream decoded;
+ TransferData(&di, &decoded);
+ TNullOutput no;
+ TCountingOutput cno(&no);
+ TCodedOutput co(&cno, codec, case_.GetBufferLength());
+ TransferData(&decoded, &co);
+ co.Flush();
+
+ Y_VERIFY((case_.GetData().size() > 0) == (cno.Counter() > 0));
+ Y_VERIFY((case_.GetData().size() > 0) == (decoded.Str().size() > 0));
+}
+
+static void DoEncodeDecode(const TPackUnpackCase& case_) {
+ auto* const codec = NBlockCodecs::Codec(case_.GetCodecName());
+ Y_ENSURE(codec);
+
+ TMemoryInput mi(case_.GetData().data(), case_.GetData().size());
+ TStringStream encoded;
+ TCodedOutput co(&encoded, codec, case_.GetBufferLength());
+ TransferData(&mi, &co);
+ co.Flush();
+ TStringStream decoded;
+ TDecodedInput di(&encoded, codec);
+ TransferData(&di, &decoded);
+
+ Y_VERIFY((case_.GetData().size() > 0) == (encoded.Str().size() > 0));
+ Y_VERIFY(case_.GetData() == decoded.Str());
+}
+
+DEFINE_BINARY_PROTO_FUZZER(const TPackUnpackCase& case_) {
+ try {
+ if (!case_.GetCodecName()) {
+ DoOnlyDecode(case_);
+ return;
+ }
+
+ ValidateBufferSize(case_.GetBufferLength());
+ if (case_.GetPacked()) {
+ DoDecodeEncode(case_);
+ } else {
+ DoEncodeDecode(case_);
+ }
+ } catch (const std::exception&) {
+ }
+}
diff --git a/library/cpp/blockcodecs/fuzz/proto/case.proto b/library/cpp/blockcodecs/fuzz/proto/case.proto
new file mode 100644
index 0000000000..85518b0da9
--- /dev/null
+++ b/library/cpp/blockcodecs/fuzz/proto/case.proto
@@ -0,0 +1,10 @@
+syntax="proto3";
+
+package NBlockCodecs.NFuzz;
+
+message TPackUnpackCase {
+ bool Packed = 1;
+ uint32 BufferLength = 2;
+ string CodecName = 3;
+ bytes Data = 4;
+}
diff --git a/library/cpp/blockcodecs/fuzz/proto/ya.make b/library/cpp/blockcodecs/fuzz/proto/ya.make
new file mode 100644
index 0000000000..da840bc8c9
--- /dev/null
+++ b/library/cpp/blockcodecs/fuzz/proto/ya.make
@@ -0,0 +1,14 @@
+OWNER(
+ yazevnul
+ g:util
+)
+
+PROTO_LIBRARY()
+
+SRCS(
+ case.proto
+)
+
+EXCLUDE_TAGS(GO_PROTO)
+
+END()
diff --git a/library/cpp/blockcodecs/fuzz/ya.make b/library/cpp/blockcodecs/fuzz/ya.make
new file mode 100644
index 0000000000..bc8becc9e1
--- /dev/null
+++ b/library/cpp/blockcodecs/fuzz/ya.make
@@ -0,0 +1,23 @@
+OWNER(
+ pg
+ g:util
+)
+
+IF (NOT MSVC)
+ FUZZ()
+
+ SIZE(MEDIUM)
+
+ SRCS(
+ main.cpp
+ )
+
+ PEERDIR(
+ contrib/libs/protobuf
+ contrib/libs/protobuf-mutator
+ library/cpp/blockcodecs
+ library/cpp/blockcodecs/fuzz/proto
+ )
+
+ END()
+ENDIF()
diff --git a/library/cpp/blockcodecs/stream.cpp b/library/cpp/blockcodecs/stream.cpp
new file mode 100644
index 0000000000..65e61e9221
--- /dev/null
+++ b/library/cpp/blockcodecs/stream.cpp
@@ -0,0 +1 @@
+#include "stream.h"
diff --git a/library/cpp/blockcodecs/stream.h b/library/cpp/blockcodecs/stream.h
new file mode 100644
index 0000000000..96c479cf7e
--- /dev/null
+++ b/library/cpp/blockcodecs/stream.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include <library/cpp/blockcodecs/core/stream.h>
diff --git a/library/cpp/blockcodecs/ut/ya.make b/library/cpp/blockcodecs/ut/ya.make
new file mode 100644
index 0000000000..25b882c15b
--- /dev/null
+++ b/library/cpp/blockcodecs/ut/ya.make
@@ -0,0 +1,19 @@
+UNITTEST_FOR(library/cpp/blockcodecs)
+
+OWNER(pg)
+
+FORK_TESTS()
+
+FORK_SUBTESTS()
+
+SPLIT_FACTOR(40)
+
+TIMEOUT(300)
+
+SIZE(MEDIUM)
+
+SRCS(
+ codecs_ut.cpp
+)
+
+END()
diff --git a/library/cpp/blockcodecs/ya.make b/library/cpp/blockcodecs/ya.make
new file mode 100644
index 0000000000..b8f03d5421
--- /dev/null
+++ b/library/cpp/blockcodecs/ya.make
@@ -0,0 +1,27 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ library/cpp/blockcodecs/core
+ library/cpp/blockcodecs/codecs/brotli
+ library/cpp/blockcodecs/codecs/bzip
+ library/cpp/blockcodecs/codecs/fastlz
+ library/cpp/blockcodecs/codecs/legacy_zstd06
+ library/cpp/blockcodecs/codecs/lz4
+ library/cpp/blockcodecs/codecs/lzma
+ library/cpp/blockcodecs/codecs/snappy
+ library/cpp/blockcodecs/codecs/zlib
+ library/cpp/blockcodecs/codecs/zstd
+)
+
+SRCS(
+ codecs.cpp
+ stream.cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ ut
+)
diff --git a/library/cpp/bucket_quoter/bucket_quoter.cpp b/library/cpp/bucket_quoter/bucket_quoter.cpp
new file mode 100644
index 0000000000..e7f8b1a869
--- /dev/null
+++ b/library/cpp/bucket_quoter/bucket_quoter.cpp
@@ -0,0 +1 @@
+#include "bucket_quoter.h"
diff --git a/library/cpp/bucket_quoter/bucket_quoter.h b/library/cpp/bucket_quoter/bucket_quoter.h
new file mode 100644
index 0000000000..3d92ef8450
--- /dev/null
+++ b/library/cpp/bucket_quoter/bucket_quoter.h
@@ -0,0 +1,281 @@
+#pragma once
+
+#include <util/datetime/base.h>
+#include <util/system/mutex.h>
+#include <util/system/hp_timer.h>
+
+/* Token bucket.
+ * Makes flow of *inflow* units per second in average, with up to *capacity* bursts.
+ * Do not use for STRICT flow control.
+ */
+
+/* samples: create and use quoter sending 1000 bytes per second on average,
+ with up to 60 seconds quota buildup.
+
+ TBucketQuoter quoter(1000, 60000, NULL, NULL, NULL);
+
+ for (;;) {
+ T *msg = get_message();
+
+ quoter.Sleep();
+ quoter.Use(msg->GetSize());
+ send_message(msg);
+ }
+
+ ----------------------------
+
+ TBucketQuoter quoter(1000, 60000, NULL, NULL, NULL);
+
+ for (;;) {
+ T *msg = get_message();
+
+ while (! quoter.IsAvail()) {
+ // do something else
+ }
+
+ quoter.Use(msg->GetSize());
+ send_message(msg);
+ }
+
+*/
+
+struct TInstantTimerMs {
+ using TTime = TInstant;
+ static constexpr ui64 Resolution = 1000ull; // milliseconds
+ static TTime Now() {
+ return TInstant::Now();
+ }
+ static ui64 Duration(TTime from, TTime to) {
+ return (to - from).MilliSeconds();
+ }
+};
+
+struct THPTimerUs {
+ using TTime = NHPTimer::STime;
+ static constexpr ui64 Resolution = 1000000ull; // microseconds
+ static TTime Now() {
+ NHPTimer::STime ret;
+ NHPTimer::GetTime(&ret);
+ return ret;
+ }
+ static ui64 Duration(TTime from, TTime to) {
+ i64 cycles = to - from;
+ if (cycles > 0) {
+ return ui64(double(cycles) * double(Resolution) / NHPTimer::GetClockRate());
+ } else {
+ return 0;
+ }
+ }
+};
+
+template <typename StatCounter, typename Lock = TMutex, typename Timer = TInstantTimerMs>
+class TBucketQuoter {
+public:
+ using TTime = typename Timer::TTime;
+
+ struct TResult {
+ i64 Before;
+ i64 After;
+ ui64 Seqno;
+ };
+
+ /* fixed quota */
+ TBucketQuoter(ui64 inflow, ui64 capacity, StatCounter* msgPassed = nullptr,
+ StatCounter* bucketUnderflows = nullptr, StatCounter* tokensUsed = nullptr,
+ StatCounter* usecWaited = nullptr, bool fill = false, StatCounter* aggregateInflow = nullptr)
+ : MsgPassed(msgPassed)
+ , BucketUnderflows(bucketUnderflows)
+ , TokensUsed(tokensUsed)
+ , UsecWaited(usecWaited)
+ , AggregateInflow(aggregateInflow)
+ , Bucket(fill ? capacity : 0)
+ , LastAdd(Timer::Now())
+ , InflowTokensPerSecond(&FixedInflow)
+ , BucketTokensCapacity(&FixedCapacity)
+ , FixedInflow(inflow)
+ , FixedCapacity(capacity)
+ {
+ /* no-op */
+ }
+
+ /* adjustable quotas */
+ TBucketQuoter(TAtomic* inflow, TAtomic* capacity, StatCounter* msgPassed = nullptr,
+ StatCounter* bucketUnderflows = nullptr, StatCounter* tokensUsed = nullptr,
+ StatCounter* usecWaited = nullptr, bool fill = false, StatCounter* aggregateInflow = nullptr)
+ : MsgPassed(msgPassed)
+ , BucketUnderflows(bucketUnderflows)
+ , TokensUsed(tokensUsed)
+ , UsecWaited(usecWaited)
+ , AggregateInflow(aggregateInflow)
+ , Bucket(fill ? AtomicGet(*capacity) : 0)
+ , LastAdd(Timer::Now())
+ , InflowTokensPerSecond(inflow)
+ , BucketTokensCapacity(capacity)
+ {
+ /* no-op */
+ }
+
+ bool IsAvail() {
+ TGuard<Lock> g(BucketMutex);
+ FillBucket();
+ if (Bucket < 0) {
+ if (BucketUnderflows) {
+ (*BucketUnderflows)++;
+ }
+ }
+ return (Bucket >= 0);
+ }
+
+ bool IsAvail(TResult& res) {
+ TGuard<Lock> g(BucketMutex);
+ res.Before = Bucket;
+ FillBucket();
+ res.After = Bucket;
+ res.Seqno = ++Seqno;
+ if (Bucket < 0) {
+ if (BucketUnderflows) {
+ (*BucketUnderflows)++;
+ }
+ }
+ return (Bucket >= 0);
+ }
+
+ ui64 GetAvail() {
+ TGuard<Lock> g(BucketMutex);
+ FillBucket();
+ return Max<i64>(0, Bucket);
+ }
+
+ ui64 GetAvail(TResult& res) {
+ TGuard<Lock> g(BucketMutex);
+ res.Before = Bucket;
+ FillBucket();
+ res.After = Bucket;
+ res.Seqno = ++Seqno;
+ return Max<i64>(0, Bucket);
+ }
+
+ void Use(ui64 tokens, bool sleep = false) {
+ TGuard<Lock> g(BucketMutex);
+ UseNoLock(tokens, sleep);
+ }
+
+ void Use(ui64 tokens, TResult& res, bool sleep = false) {
+ TGuard<Lock> g(BucketMutex);
+ res.Before = Bucket;
+ UseNoLock(tokens, sleep);
+ res.After = Bucket;
+ res.Seqno = ++Seqno;
+ }
+
+ i64 UseAndFill(ui64 tokens) {
+ TGuard<Lock> g(BucketMutex);
+ UseNoLock(tokens);
+ FillBucket();
+ return Bucket;
+ }
+
+ void Add(ui64 tokens) {
+ TGuard<Lock> g(BucketMutex);
+ AddNoLock(tokens);
+ }
+
+ void Add(ui64 tokens, TResult& res) {
+ TGuard<Lock> g(BucketMutex);
+ res.Before = Bucket;
+ AddNoLock(tokens);
+ res.After = Bucket;
+ res.Seqno = ++Seqno;
+ }
+
+ ui32 GetWaitTime() {
+ TGuard<Lock> g(BucketMutex);
+
+ FillBucket();
+ if (Bucket >= 0) {
+ return 0;
+ }
+
+ ui32 usec = (-Bucket * 1000000) / (*InflowTokensPerSecond);
+ return usec;
+ }
+
+ ui32 GetWaitTime(TResult& res) {
+ TGuard<Lock> g(BucketMutex);
+ res.Before = Bucket;
+ FillBucket();
+ res.After = Bucket;
+ res.Seqno = ++Seqno;
+ if (Bucket >= 0) {
+ return 0;
+ }
+ ui32 usec = (-Bucket * 1000000) / (*InflowTokensPerSecond);
+ return usec;
+ }
+
+ void Sleep() {
+ while (!IsAvail()) {
+ ui32 delay = GetWaitTime();
+ if (delay != 0) {
+ usleep(delay);
+ if (UsecWaited) {
+ (*UsecWaited) += delay;
+ }
+ }
+ }
+ }
+
+private:
+ void FillBucket() {
+ TTime now = Timer::Now();
+
+ ui64 elapsed = Timer::Duration(LastAdd, now);
+ if (*InflowTokensPerSecond * elapsed >= Timer::Resolution) {
+ ui64 inflow = *InflowTokensPerSecond * elapsed / Timer::Resolution;
+ if (AggregateInflow) {
+ *AggregateInflow += inflow;
+ }
+ Bucket += inflow;
+ if (Bucket > *BucketTokensCapacity) {
+ Bucket = *BucketTokensCapacity;
+ }
+
+ LastAdd = now;
+ }
+ }
+
+ void UseNoLock(ui64 tokens, bool sleep = false) {
+ if (sleep)
+ Sleep();
+ Bucket -= tokens;
+ if (TokensUsed) {
+ (*TokensUsed) += tokens;
+ }
+ if (MsgPassed) {
+ (*MsgPassed)++;
+ }
+ }
+
+ void AddNoLock(ui64 tokens) {
+ Bucket += tokens;
+ if (Bucket > *BucketTokensCapacity) {
+ Bucket = *BucketTokensCapacity;
+ }
+ }
+
+ StatCounter* MsgPassed;
+ StatCounter* BucketUnderflows;
+ StatCounter* TokensUsed;
+ StatCounter* UsecWaited;
+ StatCounter* AggregateInflow;
+
+ i64 Bucket;
+ TTime LastAdd;
+ Lock BucketMutex;
+ ui64 Seqno = 0;
+
+ TAtomic* InflowTokensPerSecond;
+ TAtomic* BucketTokensCapacity;
+ TAtomic FixedInflow;
+ TAtomic FixedCapacity;
+};
diff --git a/library/cpp/bucket_quoter/ut/README.md b/library/cpp/bucket_quoter/ut/README.md
new file mode 100644
index 0000000000..a0db9f6239
--- /dev/null
+++ b/library/cpp/bucket_quoter/ut/README.md
@@ -0,0 +1,20 @@
+# Unit test для bucket_quoter
+
+Этот тест предназначен не для проверки корректности bucket_quoter, а для того,
+чтобы показать некоторые его недостатки
+
+Первый недостаток: При вызове метода FillBucket, вычисляется количество токенов,
+которое можно добавить в Bucket за время, прошедшее с последнего добавления.
+Если это количество нецелое, то оно округляется вниз. Это может иметь значение для малых RPS.
+
+Второй недостаток:
+При попытке получить время через GetWaitTime, возвращается не ближайшее время, когда станут доступны новые токены.
+Возвращаемое время кратно (1 / RPS), выраженному в микросекундах.
+Кроме того, из-за округления, метод может вернуть время, в котором новые токены все еще не смогут быть начислены.
+
+Написанный тест демонстрирует, что данные недостатки могут приводить значительному снижению
+количества пропускаемых лимитером запросов(вплоть до двух раз в специальных условиях с искусственным таймером).
+
+Так же демонстрируется, что при использовании лимитера со стандартным таймером(TInstantTimerMs), RPS тоже может
+достаточно далек от заданного.
+
diff --git a/library/cpp/bucket_quoter/ut/main.cpp b/library/cpp/bucket_quoter/ut/main.cpp
new file mode 100644
index 0000000000..9c86bace4e
--- /dev/null
+++ b/library/cpp/bucket_quoter/ut/main.cpp
@@ -0,0 +1,44 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/bucket_quoter/bucket_quoter.h>
+
+#include "test_namespace.h"
+
+
+using NBucketQuoterTest::TMockTimer;
+
+#define TEST_RPS_EXACT(THREADS, RPS, EXPECTED_RESULT, TIMER) \
+Y_UNIT_TEST(Test##TIMER##RPS##Rps##THREADS##Threads) { \
+ ui32 seconds = 10; \
+ ui32 summary_requests = NBucketQuoterTest::Run<TIMER, NBucketQuoterTest::TTestScenario>\
+ (THREADS, RPS, seconds);\
+ ui32 total_rps = summary_requests / seconds; \
+ UNIT_ASSERT_EQUAL(total_rps, EXPECTED_RESULT);\
+}
+
+#define TEST_RPS_LESS(THREADS, RPS, UPPER_BOUND, TIMER) \
+Y_UNIT_TEST(Test##TIMER##RPS##rps##THREADS##threads) { \
+ ui32 seconds = 10; \
+ ui32 summary_requests = NBucketQuoterTest::Run<TIMER, NBucketQuoterTest::TTestScenario>\
+ (THREADS, RPS, seconds); \
+ ui32 total_rps = summary_requests / seconds; \
+ UNIT_ASSERT_LE(total_rps, UPPER_BOUND); \
+}
+
+Y_UNIT_TEST_SUITE(TMockTimerTest) {
+ TEST_RPS_EXACT(1, 100, 100, TMockTimer)
+ TEST_RPS_EXACT(1, 120, 60, TMockTimer)
+ TEST_RPS_EXACT(1, 200, 200, TMockTimer)
+ TEST_RPS_EXACT(1, 220, 110, TMockTimer)
+ TEST_RPS_EXACT(1, 240, 120, TMockTimer)
+ TEST_RPS_EXACT(1, 300, 150, TMockTimer)
+ TEST_RPS_EXACT(1, 320, 320, TMockTimer)
+ TEST_RPS_EXACT(1, 480, 240, TMockTimer)
+
+}
+
+Y_UNIT_TEST_SUITE(TInstantTimerTest) {
+ TEST_RPS_LESS(1, 360, 300, TInstantTimerMs)
+ TEST_RPS_LESS(1, 480, 400, TInstantTimerMs)
+ TEST_RPS_LESS(5, 420, 350, TInstantTimerMs)
+ TEST_RPS_LESS(5, 220, 185, TInstantTimerMs)
+}
diff --git a/library/cpp/bucket_quoter/ut/test_namespace.cpp b/library/cpp/bucket_quoter/ut/test_namespace.cpp
new file mode 100644
index 0000000000..ee6c84796c
--- /dev/null
+++ b/library/cpp/bucket_quoter/ut/test_namespace.cpp
@@ -0,0 +1,13 @@
+#include "test_namespace.h"
+
+namespace NBucketQuoterTest {
+
+ TMockTimer::TTime TMockTimer::CurrentTime = 0;
+
+ template <>
+ void Sleep<TMockTimer>(TDuration duration) {
+ TMockTimer::Sleep(duration);
+ }
+
+}
+
diff --git a/library/cpp/bucket_quoter/ut/test_namespace.h b/library/cpp/bucket_quoter/ut/test_namespace.h
new file mode 100644
index 0000000000..8d8dc1f2b3
--- /dev/null
+++ b/library/cpp/bucket_quoter/ut/test_namespace.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#include <library/cpp/bucket_quoter/bucket_quoter.h>
+#include <library/cpp/getopt/last_getopt.h>
+
+#include <util/thread/pool.h>
+#include <util/string/printf.h>
+#include <util/system/types.h>
+#include <util/stream/output.h>
+#include <util/datetime/base.h>
+#include <util/digest/fnv.h>
+#include <vector>
+#include <thread>
+#include <numeric>
+
+namespace NBucketQuoterTest {
+
+ // thread unsafe
+ struct TMockTimer {
+ using TTime = i64;
+ static constexpr ui64 Resolution = 1'000'000ull; // microseconds
+ static TTime CurrentTime;
+
+ static TMockTimer::TTime Now() {
+ return CurrentTime;
+ }
+
+ static ui64 Duration(TMockTimer::TTime from, TMockTimer::TTime to) {
+ return to - from;
+ }
+
+ static void Sleep(TDuration duration) {
+ CurrentTime += duration.MicroSeconds();
+ }
+ };
+
+ template <typename Timer>
+ void Sleep(TDuration duration) {
+ ::Sleep(duration);
+ }
+
+ template <>
+ void Sleep<TMockTimer>(TDuration duration);
+
+ template <class Timer>
+ using QuoterTemplate = TBucketQuoter<i64, TMutex, Timer>;
+
+ template<class Timer>
+ struct TTestScenario {
+ void operator () (TBucketQuoter<i64, TMutex, Timer>& quoter, ui64 work_time, i64 wait_time, ui64& store_result) const {
+ typename Timer::TTime start = Timer::Now();
+ work_time *= Timer::Resolution;
+ while (Timer::Duration(start, Timer::Now()) < work_time) {
+ while(!quoter.IsAvail()) {
+ NBucketQuoterTest::Sleep<Timer>(TDuration::MicroSeconds(quoter.GetWaitTime()));
+ }
+ quoter.Use(1);
+ ++store_result;
+ if (wait_time != 0) {
+ NBucketQuoterTest::Sleep<Timer>(TDuration::MicroSeconds(wait_time));
+ }
+ }
+ }
+ };
+
+ template <class Timer, template <class TT> class Scenario>
+ ui32 Run(ui64 thread_count, ui64 rps, ui64 seconds, i64 wait_time = 0) {
+ TBucketQuoter<i64, TMutex, Timer> quoter(rps, rps);
+ std::vector<std::thread> threads;
+ std::vector<ui64> results;
+ threads.reserve(thread_count);
+ results.reserve(thread_count);
+ for (ui32 i = 0; i < thread_count; ++i) {
+ results.emplace_back(0);
+ threads.emplace_back(Scenario<Timer>{}, std::ref(quoter), seconds, wait_time, std::ref(results.back()));
+ }
+ for (ui32 i = 0; i < thread_count; ++i) {
+ threads[i].join();
+ }
+ return std::reduce(results.begin(), results.end(), 0, std::plus<>());
+ }
+
+} \ No newline at end of file
diff --git a/library/cpp/bucket_quoter/ut/ya.make b/library/cpp/bucket_quoter/ut/ya.make
new file mode 100644
index 0000000000..774b85e623
--- /dev/null
+++ b/library/cpp/bucket_quoter/ut/ya.make
@@ -0,0 +1,18 @@
+UNITTEST()
+
+OWNER(
+ g:kikimr
+ svc
+)
+
+FORK_SUBTESTS()
+SRCS(
+ main.cpp
+ test_namespace.cpp
+)
+PEERDIR(
+ library/cpp/bucket_quoter
+ library/cpp/getopt
+)
+
+END()
diff --git a/library/cpp/bucket_quoter/ya.make b/library/cpp/bucket_quoter/ya.make
new file mode 100644
index 0000000000..49c407b502
--- /dev/null
+++ b/library/cpp/bucket_quoter/ya.make
@@ -0,0 +1,11 @@
+LIBRARY()
+
+OWNER(serxa)
+
+SRCS(
+ bucket_quoter.cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/build_info/build_info.cpp.in b/library/cpp/build_info/build_info.cpp.in
new file mode 100644
index 0000000000..71403af13e
--- /dev/null
+++ b/library/cpp/build_info/build_info.cpp.in
@@ -0,0 +1,5 @@
+#include <library/cpp/build_info/build_info.h>
+
+extern "C" const char* GetBuildType() {
+ return "@BUILD_TYPE@";
+}
diff --git a/library/cpp/build_info/build_info.h b/library/cpp/build_info/build_info.h
new file mode 100644
index 0000000000..a494870ba3
--- /dev/null
+++ b/library/cpp/build_info/build_info.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "sandbox.h"
+#include "build_info_static.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+const char* GetBuildType();
+
+#if defined(__cplusplus)
+}
+#endif
diff --git a/library/cpp/build_info/build_info_static.cpp b/library/cpp/build_info/build_info_static.cpp
new file mode 100644
index 0000000000..238fb1ecb0
--- /dev/null
+++ b/library/cpp/build_info/build_info_static.cpp
@@ -0,0 +1,27 @@
+#include "build_info_static.h"
+
+#include <library/cpp/build_info/buildinfo_data.h>
+
+extern "C" const char* GetCompilerVersion() {
+#if defined(BUILD_COMPILER_VERSION)
+ return BUILD_COMPILER_VERSION;
+#else
+ return "";
+#endif
+}
+
+extern "C" const char* GetCompilerFlags() {
+#if defined(BUILD_COMPILER_FLAGS)
+ return BUILD_COMPILER_FLAGS;
+#else
+ return "";
+#endif
+}
+
+extern "C" const char* GetBuildInfo() {
+#if defined(BUILD_INFO)
+ return BUILD_INFO;
+#else
+ return "";
+#endif
+}
diff --git a/library/cpp/build_info/build_info_static.h b/library/cpp/build_info/build_info_static.h
new file mode 100644
index 0000000000..9bf9939dd9
--- /dev/null
+++ b/library/cpp/build_info/build_info_static.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+const char* GetCompilerVersion();
+const char* GetCompilerFlags(); // "-std=c++14 -DNDEBUG -O2 -m64 ..."
+const char* GetBuildInfo(); // Compiler version and flags
+
+#if defined(__cplusplus)
+}
+#endif
diff --git a/library/cpp/build_info/sandbox.cpp.in b/library/cpp/build_info/sandbox.cpp.in
new file mode 100644
index 0000000000..ac3b2d9004
--- /dev/null
+++ b/library/cpp/build_info/sandbox.cpp.in
@@ -0,0 +1,27 @@
+#include <library/cpp/build_info/sandbox.h>
+#include <library/cpp/string_utils/base64/base64.h>
+#include <util/generic/string.h>
+#include <util/string/subst.h>
+
+extern "C" const char* GetSandboxTaskId() {
+ return "@SANDBOX_TASK_ID@";
+}
+
+class TKosherVersionHolder {
+public:
+ const char* Version() const {
+ if (!Version_) {
+ TString version = "@KOSHER_SVN_VERSION@";
+ SubstGlobal(version, ".", "=");
+ Version_ = Base64Decode(version);
+ }
+ return Version_.c_str();
+ }
+private:
+ mutable TString Version_;
+};
+
+// Experimental code for RMDEV-365
+extern "C" const char* GetKosherSvnVersion() {
+ return Singleton<TKosherVersionHolder>()->Version();
+}
diff --git a/library/cpp/build_info/sandbox.h b/library/cpp/build_info/sandbox.h
new file mode 100644
index 0000000000..924ff89c8c
--- /dev/null
+++ b/library/cpp/build_info/sandbox.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+const char* GetSandboxTaskId();
+const char* GetKosherSvnVersion();
+
+#if defined(__cplusplus)
+}
+#endif
diff --git a/library/cpp/build_info/ya.make b/library/cpp/build_info/ya.make
new file mode 100644
index 0000000000..99886a8893
--- /dev/null
+++ b/library/cpp/build_info/ya.make
@@ -0,0 +1,24 @@
+LIBRARY()
+
+OWNER(
+ mvel
+ snowball
+ heretic
+)
+
+DEFAULT(SANDBOX_TASK_ID 0)
+DEFAULT(KOSHER_SVN_VERSION "")
+
+CREATE_BUILDINFO_FOR(buildinfo_data.h)
+
+PEERDIR(
+ library/cpp/string_utils/base64
+)
+
+SRCS(
+ sandbox.cpp.in
+ build_info.cpp.in
+ build_info_static.cpp
+)
+
+END()
diff --git a/library/cpp/cache/cache.cpp b/library/cpp/cache/cache.cpp
new file mode 100644
index 0000000000..05b26b0cf8
--- /dev/null
+++ b/library/cpp/cache/cache.cpp
@@ -0,0 +1 @@
+#include "cache.h"
diff --git a/library/cpp/cache/cache.h b/library/cpp/cache/cache.h
new file mode 100644
index 0000000000..6dc997076d
--- /dev/null
+++ b/library/cpp/cache/cache.h
@@ -0,0 +1,649 @@
+#pragma once
+
+#include <util/generic/algorithm.h>
+#include <util/generic/ptr.h>
+#include <util/generic/intrlist.h>
+#include <util/generic/hash_set.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+#include <utility>
+
+template <class TValue>
+struct TUniformSizeProvider {
+ size_t operator()(const TValue&) {
+ return 1;
+ }
+};
+
+template <typename TKey, typename TValue, class TSizeProvider = TUniformSizeProvider<TValue>>
+class TLRUList {
+public:
+ TLRUList(size_t maxSize, const TSizeProvider& sizeProvider = TSizeProvider())
+ : List()
+ , SizeProvider(sizeProvider)
+ , ItemsAmount(0)
+ , TotalSize(0)
+ , MaxSize(maxSize)
+ {
+ }
+
+public:
+ struct TItem: public TIntrusiveListItem<TItem> {
+ typedef TIntrusiveListItem<TItem> TBase;
+ TItem(const TKey& key, const TValue& value = TValue())
+ : TBase()
+ , Key(key)
+ , Value(value)
+ {
+ }
+
+ TItem(const TItem& rhs)
+ : TBase()
+ , Key(rhs.Key)
+ , Value(rhs.Value)
+ {
+ }
+
+ bool operator<(const TItem& rhs) const {
+ return Key < rhs.Key;
+ }
+
+ bool operator==(const TItem& rhs) const {
+ return Key == rhs.Key;
+ }
+
+ TKey Key;
+ TValue Value;
+
+ struct THash {
+ size_t operator()(const TItem& item) const {
+ return ::THash<TKey>()(item.Key);
+ }
+ };
+ };
+
+public:
+ TItem* Insert(TItem* item) {
+ List.PushBack(item);
+ ++ItemsAmount;
+ TotalSize += SizeProvider(item->Value);
+
+ return RemoveIfOverflown();
+ }
+
+ TItem* RemoveIfOverflown() {
+ TItem* deleted = nullptr;
+ if (TotalSize > MaxSize && ItemsAmount > 1) {
+ deleted = GetOldest();
+ Erase(deleted);
+ }
+ return deleted;
+ }
+
+ TItem* GetOldest() {
+ typename TListType::TIterator it = List.Begin();
+ Y_ASSERT(it != List.End());
+ return &*it;
+ }
+
+ void Erase(TItem* item) {
+ item->Unlink();
+ --ItemsAmount;
+ TotalSize -= SizeProvider(item->Value);
+ }
+
+ void Promote(TItem* item) {
+ item->Unlink();
+ List.PushBack(item);
+ }
+
+ size_t GetSize() const {
+ return ItemsAmount;
+ }
+
+ size_t GetTotalSize() const {
+ return TotalSize;
+ }
+
+ size_t GetMaxSize() const {
+ return MaxSize;
+ }
+
+ // It does not remove current items if newSize is less than TotalSize.
+ // Caller should use RemoveIfOverflown to clean up list in this case
+ void SetMaxSize(size_t newSize) {
+ MaxSize = newSize;
+ }
+
+private:
+ typedef TIntrusiveList<TItem> TListType;
+ TListType List;
+ TSizeProvider SizeProvider;
+ size_t ItemsAmount;
+ size_t TotalSize;
+ size_t MaxSize;
+};
+
+template <typename TKey, typename TValue>
+class TLFUList {
+public:
+ TLFUList(size_t maxSize)
+ : List()
+ , ListSize(0)
+ , MaxSize(maxSize)
+ {
+ }
+
+ struct TItem: public TIntrusiveListItem<TItem> {
+ typedef TIntrusiveListItem<TItem> TBase;
+ TItem(const TKey& key, const TValue& value = TValue())
+ : TBase()
+ , Key(key)
+ , Value(value)
+ , Counter(0)
+ {
+ }
+
+ TItem(const TItem& rhs)
+ : TBase()
+ , Key(rhs.Key)
+ , Value(rhs.Value)
+ , Counter(rhs.Counter)
+ {
+ }
+
+ bool operator<(const TItem& rhs) const {
+ return Key < rhs.Key;
+ }
+
+ bool operator==(const TItem& rhs) const {
+ return Key == rhs.Key;
+ }
+
+ TKey Key;
+ TValue Value;
+ size_t Counter;
+
+ struct THash {
+ size_t operator()(const TItem& item) const {
+ return ::THash<TKey>()(item.Key);
+ }
+ };
+ };
+
+public:
+ TItem* Insert(TItem* item) {
+ List.PushBack(item); // give a chance for promotion
+ ++ListSize;
+
+ return RemoveIfOverflown();
+ }
+
+ TItem* RemoveIfOverflown() {
+ TItem* deleted = nullptr;
+ if (ListSize > MaxSize) {
+ deleted = GetLeastFrequentlyUsed();
+ Erase(deleted);
+ }
+ return deleted;
+ }
+
+ TItem* GetLeastFrequentlyUsed() {
+ typename TListType::TIterator it = List.Begin();
+ Y_ASSERT(it != List.End());
+ return &*it;
+ }
+
+ void Erase(TItem* item) {
+ item->Unlink();
+ --ListSize;
+ }
+
+ void Promote(TItem* item) {
+ size_t counter = ++item->Counter;
+ typename TListType::TIterator it = item;
+ while (it != List.End() && counter >= it->Counter) {
+ ++it;
+ }
+ item->LinkBefore(&*it);
+ }
+
+ size_t GetSize() const {
+ return ListSize;
+ }
+
+ size_t GetMaxSize() const {
+ return MaxSize;
+ }
+
+ // It does not remove current items if newSize is less than TotalSize.
+ // Caller should use RemoveIfOverflown to clean up list in this case
+ void SetMaxSize(size_t newSize) {
+ MaxSize = newSize;
+ }
+
+private:
+ typedef TIntrusiveList<TItem> TListType;
+ TListType List;
+ size_t ListSize;
+ size_t MaxSize;
+};
+
+// Least Weighted list
+// discards the least weighted items first
+// doesn't support promotion
+template <typename TKey, typename TValue, typename TWeight, typename TWeighter>
+class TLWList {
+public:
+ TLWList(size_t maxSize)
+ : Size(0)
+ , MaxSize(maxSize)
+ {
+ }
+
+ struct TItem {
+ TItem(const TKey& key, const TValue& value = TValue())
+ : Key(key)
+ , Value(value)
+ , Weight(TWeighter::Weight(value))
+ {
+ }
+
+ TItem(const TItem& rhs)
+ : Key(rhs.Key)
+ , Value(rhs.Value)
+ , Weight(rhs.Weight)
+ {
+ }
+
+ bool operator<(const TItem& rhs) const {
+ return Key < rhs.Key;
+ }
+
+ bool operator==(const TItem& rhs) const {
+ return Key == rhs.Key;
+ }
+
+ TKey Key;
+ TValue Value;
+ TWeight Weight;
+
+ struct THash {
+ size_t operator()(const TItem& item) const {
+ return ::THash<TKey>()(item.Key);
+ }
+ };
+ };
+
+ struct THeapComparator {
+ bool operator()(TItem* const item1, TItem* const item2) const {
+ return item1->Weight > item2->Weight;
+ }
+ };
+
+public:
+ TItem* Insert(TItem* item) {
+ FixHeap();
+
+ if (Size >= MaxSize && item->Weight < GetLightest()->Weight) {
+ return item;
+ }
+
+ Heap.push_back(item);
+ PushHeap(Heap.begin(), Heap.end(), THeapComparator());
+ ++Size;
+
+ return RemoveIfOverflown();
+ }
+
+ TItem* RemoveIfOverflown() {
+ if (Size <= MaxSize) {
+ return nullptr;
+ }
+
+ auto lightest = GetLightest();
+ Erase(lightest);
+ PopHeap(Heap.begin(), Heap.end(), THeapComparator());
+ return lightest;
+ }
+
+ TItem* GetLightest() {
+ FixHeap();
+
+ Y_ASSERT(!Heap.empty());
+
+ return Heap.front();
+ }
+
+ // This method doesn't remove items from the heap.
+ // Erased items are stored in Removed set
+ // and will be deleted on-access (using FixHeap method)
+ void Erase(TItem* item) {
+ Y_ASSERT(Size > 0);
+
+ --Size;
+ Removed.insert(item);
+ }
+
+ void Promote(TItem*) {
+ // do nothing
+ }
+
+ [[nodiscard]] size_t GetSize() const {
+ return Size;
+ }
+
+ size_t GetMaxSize() const {
+ return MaxSize;
+ }
+
+ // It does not remove current items if newSize is less than TotalSize.
+ // Caller should use RemoveIfOverflown to clean up list in this case
+ void SetMaxSize(size_t newSize) {
+ MaxSize = newSize;
+ }
+
+ void Clear() {
+ Heap.clear();
+ Removed.clear();
+ Size = 0;
+ }
+
+private:
+ // Physically remove erased elements from the heap
+ void FixHeap() {
+ if (Removed.empty()) {
+ return;
+ }
+
+ Heap.erase(std::remove_if(Heap.begin(), Heap.end(), [this](TItem* item) {
+ return this->Removed.contains(item);
+ }),
+ Heap.end());
+ MakeHeap(Heap.begin(), Heap.end(), THeapComparator());
+ Removed.clear();
+ Size = Heap.size();
+ }
+
+private:
+ TVector<TItem*> Heap;
+ THashSet<TItem*> Removed;
+
+ size_t Size;
+ size_t MaxSize;
+};
+
+template <typename TKey, typename TValue, typename TListType, typename TDeleter>
+class TCache {
+ typedef typename TListType::TItem TItem;
+ typedef typename TItem::THash THash;
+ typedef THashMultiSet<TItem, THash> TIndex;
+ typedef typename TIndex::iterator TIndexIterator;
+ typedef typename TIndex::const_iterator TIndexConstIterator;
+
+public:
+ class TIterator {
+ public:
+ explicit TIterator(const TIndexConstIterator& iter)
+ : Iter(iter)
+ {
+ }
+
+ TValue& operator*() {
+ return const_cast<TValue&>(Iter->Value);
+ }
+
+ TValue* operator->() {
+ return const_cast<TValue*>(&Iter->Value);
+ }
+
+ bool operator==(const TIterator& rhs) const {
+ return Iter == rhs.Iter;
+ }
+
+ bool operator!=(const TIterator& rhs) const {
+ return Iter != rhs.Iter;
+ }
+
+ TIterator& operator++() {
+ ++Iter;
+ return *this;
+ }
+
+ const TKey& Key() const {
+ return Iter->Key;
+ }
+
+ const TValue& Value() const {
+ return Iter->Value;
+ }
+
+ friend class TCache<TKey, TValue, TListType, TDeleter>;
+
+ private:
+ TIndexConstIterator Iter;
+ };
+
+ TCache(TListType&& list, bool multiValue = false)
+ : Index()
+ , List(std::move(list))
+ , MultiValue(multiValue)
+ {
+ }
+
+ ~TCache() {
+ Clear();
+ }
+
+ size_t Size() const {
+ return Index.size();
+ }
+
+ TIterator Begin() const {
+ return TIterator(Index.begin());
+ }
+
+ TIterator End() const {
+ return TIterator(Index.end());
+ }
+
+ TIterator Find(const TKey& key) {
+ TIndexIterator it = Index.find(TItem(key));
+ if (it != Index.end())
+ List.Promote(const_cast<TItem*>(&*it));
+ return TIterator(it);
+ }
+
+ TIterator FindWithoutPromote(const TKey& key) const {
+ return TIterator(Index.find(TItem(key)));
+ }
+
+ // note: it shouldn't touch 'value' if it returns false.
+ bool PickOut(const TKey& key, TValue* value) {
+ Y_ASSERT(value);
+ TIndexIterator it = Index.find(TItem(key));
+ if (it == Index.end())
+ return false;
+ *value = it->Value;
+ List.Erase(const_cast<TItem*>(&*it));
+ Index.erase(it);
+ Y_ASSERT(Index.size() == List.GetSize());
+ return true;
+ }
+
+ bool Insert(const std::pair<TKey, TValue>& p) {
+ return Insert(p.first, p.second);
+ }
+
+ bool Insert(const TKey& key, const TValue& value) {
+ TItem tmpItem(key, value);
+ if (!MultiValue && Index.find(tmpItem) != Index.end())
+ return false;
+ TIndexIterator it = Index.insert(tmpItem);
+
+ TItem* insertedItem = const_cast<TItem*>(&*it);
+ auto removedItem = List.Insert(insertedItem);
+ auto insertedWasRemoved = removedItem == insertedItem;
+ if (removedItem) {
+ EraseFromIndex(removedItem);
+ while ((removedItem = List.RemoveIfOverflown())) {
+ insertedWasRemoved = insertedWasRemoved || insertedItem == removedItem;
+ EraseFromIndex(removedItem);
+ }
+ }
+
+ Y_ASSERT(Index.size() == List.GetSize());
+ return !insertedWasRemoved;
+ }
+
+ void Update(const TKey& key, const TValue& value) {
+ if (MultiValue)
+ ythrow yexception() << "TCache: can't \"Update\" in multicache";
+ TIterator it = Find(key);
+ if (it != End()) {
+ Erase(it);
+ }
+ Insert(key, value);
+
+ Y_ASSERT(Index.size() == List.GetSize());
+ }
+
+ void Erase(TIterator it) {
+ TItem* item = const_cast<TItem*>(&*it.Iter);
+ List.Erase(item);
+ TDeleter::Destroy(item->Value);
+ Index.erase(it.Iter);
+
+ Y_ASSERT(Index.size() == List.GetSize());
+ }
+
+ bool Empty() const {
+ return Index.empty();
+ }
+
+ void Clear() {
+ for (TIndexIterator it = Index.begin(); it != Index.end(); ++it) {
+ TItem* item = const_cast<TItem*>(&*it);
+ List.Erase(item);
+ TDeleter::Destroy(item->Value);
+ }
+ Y_ASSERT(List.GetSize() == 0);
+ Index.clear();
+ }
+
+ void SetMaxSize(size_t newSize) {
+ List.SetMaxSize(newSize);
+
+ TItem* removedItem = nullptr;
+ while ((removedItem = List.RemoveIfOverflown())) {
+ EraseFromIndex(removedItem);
+ }
+ Y_ASSERT(Index.size() == List.GetSize());
+ }
+
+ size_t GetMaxSize() const {
+ return List.GetMaxSize();
+ }
+
+protected:
+ TIndex Index;
+ TListType List;
+ bool MultiValue;
+
+ TIterator FindByItem(TItem* item) {
+ std::pair<TIndexIterator, TIndexIterator> p = Index.equal_range(*item);
+ // we have to delete the exact unlinked item (there may be multiple items for one key)
+ TIndexIterator it;
+ for (it = p.first; it != p.second; ++it)
+ if (&*it == item)
+ break;
+ return (it == p.second ? End() : TIterator(it));
+ }
+
+ void EraseFromIndex(TItem* item) {
+ TDeleter::Destroy(item->Value);
+ TIterator it = FindByItem(item);
+ Y_ASSERT(it != End());
+ Index.erase(it.Iter);
+ }
+};
+
+struct TNoopDelete {
+ template <class T>
+ static inline void Destroy(const T&) noexcept {
+ }
+};
+
+template <typename TKey, typename TValue, typename TDeleter = TNoopDelete, class TSizeProvider = TUniformSizeProvider<TValue>>
+class TLRUCache: public TCache<TKey, TValue, TLRUList<TKey, TValue, TSizeProvider>, TDeleter> {
+ using TListType = TLRUList<TKey, TValue, TSizeProvider>;
+ typedef TCache<TKey, TValue, TListType, TDeleter> TBase;
+
+public:
+ TLRUCache(size_t maxSize, bool multiValue = false, const TSizeProvider& sizeProvider = TSizeProvider())
+ : TBase(TListType(maxSize, sizeProvider), multiValue)
+ {
+ }
+
+public:
+ typedef typename TBase::TIterator TIterator;
+
+ TValue& GetOldest() {
+ return TBase::List.GetOldest()->Value;
+ }
+
+ TIterator FindOldest() {
+ return TBase::Empty() ? TBase::End() : this->FindByItem(TBase::List.GetOldest());
+ }
+
+ size_t TotalSize() const {
+ return TBase::List.GetTotalSize();
+ }
+};
+
+template <typename TKey, typename TValue, typename TDeleter = TNoopDelete>
+class TLFUCache: public TCache<TKey, TValue, TLFUList<TKey, TValue>, TDeleter> {
+ typedef TCache<TKey, TValue, TLFUList<TKey, TValue>, TDeleter> TBase;
+ using TListType = TLFUList<TKey, TValue>;
+
+public:
+ typedef typename TBase::TIterator TIterator;
+
+ TLFUCache(size_t maxSize, bool multiValue = false)
+ : TBase(TListType(maxSize), multiValue)
+ {
+ }
+
+ TValue& GetLeastFrequentlyUsed() {
+ return TBase::List.GetLeastFrequentlyUsed()->Value;
+ }
+
+ TIterator FindLeastFrequentlyUsed() {
+ return TBase::Empty() ? TBase::End() : this->FindByItem(TBase::List.GetLeastFrequentlyUsed());
+ }
+};
+
+// Least Weighted cache
+// discards the least weighted items first
+// doesn't support promotion
+template <typename TKey, typename TValue, typename TWeight, typename TWeighter, typename TDeleter = TNoopDelete>
+class TLWCache: public TCache<TKey, TValue, TLWList<TKey, TValue, TWeight, TWeighter>, TDeleter> {
+ typedef TCache<TKey, TValue, TLWList<TKey, TValue, TWeight, TWeighter>, TDeleter> TBase;
+ using TListType = TLWList<TKey, TValue, TWeight, TWeighter>;
+
+public:
+ typedef typename TBase::TIterator TIterator;
+
+ TLWCache(size_t maxSize, bool multiValue = false)
+ : TBase(TListType(maxSize), multiValue)
+ {
+ }
+
+ TValue& GetLightest() {
+ return TBase::List.GetLightest()->Value;
+ }
+
+ TIterator FindLightest() {
+ return TBase::Empty() ? TBase::End() : this->FindByItem(TBase::List.GetLightest());
+ }
+};
diff --git a/library/cpp/cache/thread_safe_cache.cpp b/library/cpp/cache/thread_safe_cache.cpp
new file mode 100644
index 0000000000..de47076d6b
--- /dev/null
+++ b/library/cpp/cache/thread_safe_cache.cpp
@@ -0,0 +1 @@
+#include "thread_safe_cache.h"
diff --git a/library/cpp/cache/thread_safe_cache.h b/library/cpp/cache/thread_safe_cache.h
new file mode 100644
index 0000000000..71e1442717
--- /dev/null
+++ b/library/cpp/cache/thread_safe_cache.h
@@ -0,0 +1,201 @@
+#pragma once
+
+#include "cache.h"
+
+#include <util/generic/singleton.h>
+#include <util/system/rwlock.h>
+
+namespace NPrivate {
+ // We are interested in getters promotion policy _here_ because of Read-Write-Lock optimizations.
+ enum class EGettersPromotionPolicy {
+ Promoted, // LRU, TLRU, MRU, etc.
+ Unpromoted // FIFO, LIFO, LW, etc.
+ };
+
+ template <class Key, class Value, template <class, class> class List, EGettersPromotionPolicy GettersPromotionPolicy, class... TArgs>
+ class TThreadSafeCache {
+ public:
+ using TPtr = TAtomicSharedPtr<Value>;
+
+ class ICallbacks {
+ public:
+ using TKey = Key;
+ using TValue = Value;
+ using TOwner = TThreadSafeCache<Key, Value, List, GettersPromotionPolicy, TArgs...>;
+
+ public:
+ virtual ~ICallbacks() = default;
+ virtual TKey GetKey(TArgs... args) const = 0;
+ virtual TValue* CreateObject(TArgs... args) const = 0;
+ };
+
+ public:
+ TThreadSafeCache(const ICallbacks& callbacks, size_t maxSize = Max<size_t>())
+ : Callbacks(callbacks)
+ , Cache(maxSize)
+ {
+ }
+
+ bool Insert(const Key& key, const TPtr& value) {
+ if (!Contains(key)) {
+ TWriteGuard w(Mutex);
+ return Cache.Insert(key, value);
+ }
+ return false;
+ }
+
+ void Update(const Key& key, const TPtr& value) {
+ TWriteGuard w(Mutex);
+ Cache.Update(key, value);
+ }
+
+ const TPtr Get(TArgs... args) const {
+ return GetValue<true>(args...);
+ }
+
+ const TPtr GetUnsafe(TArgs... args) const {
+ return GetValue<false>(args...);
+ }
+
+ void Clear() {
+ TWriteGuard w(Mutex);
+ Cache.Clear();
+ }
+
+ void Erase(TArgs... args) {
+ Key key = Callbacks.GetKey(args...);
+ if (!Contains(key)) {
+ return;
+ }
+ TWriteGuard w(Mutex);
+ typename TInternalCache::TIterator i = Cache.Find(key);
+ if (i == Cache.End()) {
+ return;
+ }
+ Cache.Erase(i);
+ }
+
+ bool Contains(const Key& key) const {
+ TReadGuard r(Mutex);
+ auto iter = Cache.FindWithoutPromote(key);
+ return iter != Cache.End();
+ }
+
+ template <class TCallbacks>
+ static const TPtr Get(TArgs... args) {
+ return TThreadSafeCacheSingleton<TCallbacks>::Get(args...);
+ }
+
+ template <class TCallbacks>
+ static const TPtr Erase(TArgs... args) {
+ return TThreadSafeCacheSingleton<TCallbacks>::Erase(args...);
+ }
+
+ template <class TCallbacks>
+ static void Clear() {
+ return TThreadSafeCacheSingleton<TCallbacks>::Clear();
+ }
+
+ size_t GetMaxSize() const {
+ TReadGuard w(Mutex);
+ return Cache.GetMaxSize();
+ }
+
+ void SetMaxSize(size_t newSize) {
+ TWriteGuard w(Mutex);
+ Cache.SetMaxSize(newSize);
+ }
+
+ private:
+ template <bool AllowNullValues>
+ const TPtr GetValue(TArgs... args) const {
+ Key key = Callbacks.GetKey(args...);
+ switch (GettersPromotionPolicy) {
+ case EGettersPromotionPolicy::Promoted:
+ break;
+ case EGettersPromotionPolicy::Unpromoted: {
+ TReadGuard r(Mutex);
+ typename TInternalCache::TIterator i = Cache.FindWithoutPromote(key);
+ if (i != Cache.End()) {
+ return i.Value();
+ }
+ break;
+ }
+ }
+ TWriteGuard w(Mutex);
+ typename TInternalCache::TIterator i = Cache.Find(key);
+ if (i != Cache.End()) {
+ return i.Value();
+ }
+ TPtr value = Callbacks.CreateObject(args...);
+ if (value || AllowNullValues) {
+ Cache.Insert(key, value);
+ }
+ return value;
+ }
+
+ private:
+ using TInternalCache = TCache<Key, TPtr, List<Key, TPtr>, TNoopDelete>;
+
+ template <class TCallbacks>
+ class TThreadSafeCacheSingleton {
+ public:
+ static const TPtr Get(TArgs... args) {
+ return Singleton<TThreadSafeCacheSingleton>()->Cache.Get(args...);
+ }
+
+ static const TPtr Erase(TArgs... args) {
+ return Singleton<TThreadSafeCacheSingleton>()->Cache.Erase(args...);
+ }
+
+ static void Clear() {
+ return Singleton<TThreadSafeCacheSingleton>()->Cache.Clear();
+ }
+
+ TThreadSafeCacheSingleton()
+ : Cache(Callbacks)
+ {
+ }
+
+ private:
+ TCallbacks Callbacks;
+ typename TCallbacks::TOwner Cache;
+ };
+
+ private:
+ TRWMutex Mutex;
+ const ICallbacks& Callbacks;
+ mutable TInternalCache Cache;
+ };
+
+ struct TLWHelper {
+ template <class TValue>
+ struct TConstWeighter {
+ static int Weight(const TValue& /*value*/) {
+ return 0;
+ }
+ };
+
+ template <class TKey, class TValue>
+ using TListType = TLWList<TKey, TValue, int, TConstWeighter<TValue>>;
+
+ template <class TKey, class TValue, class... TArgs>
+ using TCache = TThreadSafeCache<TKey, TValue, TListType, EGettersPromotionPolicy::Unpromoted, TArgs...>;
+ };
+
+ struct TLRUHelper {
+ template <class TKey, class TValue>
+ using TListType = TLRUList<TKey, TValue>;
+
+ template <class TKey, class TValue, class... TArgs>
+ using TCache = TThreadSafeCache<TKey, TValue, TListType, EGettersPromotionPolicy::Promoted, TArgs...>;
+ };
+
+}
+
+template <class TKey, class TValue, class... TArgs>
+using TThreadSafeCache = typename NPrivate::TLWHelper::template TCache<TKey, TValue, TArgs...>;
+
+template <class TKey, class TValue, class... TArgs>
+using TThreadSafeLRUCache = typename NPrivate::TLRUHelper::template TCache<TKey, TValue, TArgs...>;
+
diff --git a/library/cpp/cache/ut/cache_ut.cpp b/library/cpp/cache/ut/cache_ut.cpp
new file mode 100644
index 0000000000..329872cfde
--- /dev/null
+++ b/library/cpp/cache/ut/cache_ut.cpp
@@ -0,0 +1,618 @@
+#include <library/cpp/cache/cache.h>
+#include <library/cpp/cache/thread_safe_cache.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+struct TStrokaWeighter {
+ static size_t Weight(const TString& s) {
+ return s.size();
+ }
+};
+
+Y_UNIT_TEST_SUITE(TCacheTest) {
+ Y_UNIT_TEST(LRUListTest) {
+ typedef TLRUList<int, TString> TListType;
+ TListType list(2);
+
+ TListType::TItem x1(1, "ttt");
+ list.Insert(&x1);
+ UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 1);
+
+ TListType::TItem x2(2, "yyy");
+ list.Insert(&x2);
+ UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 1);
+
+ list.Promote(list.GetOldest());
+ UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 2);
+
+ TListType::TItem x3(3, "zzz");
+ list.Insert(&x3);
+ UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 1);
+ }
+
+ Y_UNIT_TEST(LRUListWeightedTest) {
+ typedef TLRUList<int, TString, size_t (*)(const TString&)> TListType;
+ TListType list(7, [](auto& string) {
+ return string.size();
+ });
+
+ TListType::TItem x1(1, "ttt");
+ list.Insert(&x1);
+ while (list.RemoveIfOverflown()) {
+ }
+ UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 1);
+
+ TListType::TItem x2(2, "yyy");
+ list.Insert(&x2);
+ while (list.RemoveIfOverflown()) {
+ }
+ UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 1);
+
+ list.Promote(list.GetOldest());
+ while (list.RemoveIfOverflown()) {
+ }
+ UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 2);
+
+ TListType::TItem x3(3, "zzz");
+ list.Insert(&x3);
+ while (list.RemoveIfOverflown()) {
+ }
+ UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 1);
+
+ TListType::TItem x4(4, "longlong");
+ list.Insert(&x4);
+ while (list.RemoveIfOverflown()) {
+ }
+ UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 4);
+ }
+
+ Y_UNIT_TEST(LFUListTest) {
+ typedef TLFUList<int, TString> TListType;
+ TListType list(2);
+
+ TListType::TItem x1(1, "ttt");
+ list.Insert(&x1);
+ UNIT_ASSERT_EQUAL(list.GetLeastFrequentlyUsed()->Key, 1);
+
+ TListType::TItem x2(2, "yyy");
+ list.Insert(&x2);
+ UNIT_ASSERT_EQUAL(list.GetLeastFrequentlyUsed()->Key, 1);
+
+ list.Promote(list.GetLeastFrequentlyUsed());
+ UNIT_ASSERT_EQUAL(list.GetLeastFrequentlyUsed()->Key, 2);
+
+ TListType::TItem x3(3, "zzz");
+ list.Insert(&x3);
+ UNIT_ASSERT_EQUAL(list.GetLeastFrequentlyUsed()->Key, 1);
+ }
+
+ Y_UNIT_TEST(LWListTest) {
+ typedef TLWList<int, TString, size_t, TStrokaWeighter> TListType;
+ TListType list(2);
+
+ TListType::TItem x1(1, "tt");
+ list.Insert(&x1);
+ UNIT_ASSERT_EQUAL(list.GetLightest()->Key, 1);
+ UNIT_ASSERT_EQUAL(list.GetSize(), 1);
+
+ TListType::TItem x2(2, "yyyy");
+ list.Insert(&x2);
+ UNIT_ASSERT_EQUAL(list.GetLightest()->Key, 1);
+ UNIT_ASSERT_EQUAL(list.GetSize(), 2);
+
+ TListType::TItem x3(3, "z");
+ list.Insert(&x3);
+ UNIT_ASSERT_EQUAL(list.GetLightest()->Key, 1);
+ UNIT_ASSERT_EQUAL(list.GetSize(), 2);
+
+ TListType::TItem x4(4, "xxxxxx");
+ list.Insert(&x4);
+ UNIT_ASSERT_EQUAL(list.GetLightest()->Key, 2);
+ UNIT_ASSERT_EQUAL(list.GetSize(), 2);
+
+ list.Erase(&x2);
+ UNIT_ASSERT_EQUAL(list.GetLightest()->Key, 4);
+ UNIT_ASSERT_EQUAL(list.GetSize(), 1);
+ }
+
+ Y_UNIT_TEST(SimpleTest) {
+ typedef TLRUCache<int, TString> TCache;
+ TCache s(2); // size 2
+ s.Insert(1, "abcd");
+ UNIT_ASSERT(s.Find(1) != s.End());
+ UNIT_ASSERT_EQUAL(*s.Find(1), "abcd");
+ s.Insert(2, "defg");
+ UNIT_ASSERT(s.GetOldest() == "abcd");
+ s.Insert(3, "hjkl");
+ UNIT_ASSERT(s.GetOldest() == "defg");
+ // key 1 will be deleted
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) != s.End());
+ UNIT_ASSERT(*s.Find(2) == "defg");
+ UNIT_ASSERT(s.Find(3) != s.End());
+ UNIT_ASSERT(*s.Find(3) == "hjkl");
+
+ UNIT_ASSERT(!s.Insert(3, "abcd"));
+ UNIT_ASSERT(*s.Find(3) == "hjkl");
+ s.Update(3, "abcd");
+ UNIT_ASSERT(*s.Find(3) == "abcd");
+
+ TCache::TIterator it = s.Find(3);
+ s.Erase(it);
+ UNIT_ASSERT(s.Find(3) == s.End());
+ }
+
+ Y_UNIT_TEST(LRUWithCustomSizeProviderTest) {
+ typedef TLRUCache<int, TString, TNoopDelete, size_t(*)(const TString&)> TCache;
+ TCache s(10, false, [](auto& string) { return string.size(); }); // size 10
+ s.Insert(1, "abcd");
+ UNIT_ASSERT(s.Find(1) != s.End());
+ UNIT_ASSERT_EQUAL(*s.Find(1), "abcd");
+ s.Insert(2, "defg");
+ UNIT_ASSERT(s.GetOldest() == "abcd");
+ s.Insert(3, "2c");
+ UNIT_ASSERT(s.GetOldest() == "abcd");
+ s.Insert(4, "hjkl");
+ UNIT_ASSERT(s.GetOldest() == "defg");
+ // key 1 will be deleted
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) != s.End());
+ UNIT_ASSERT(*s.Find(2) == "defg");
+ UNIT_ASSERT(s.Find(3) != s.End());
+ UNIT_ASSERT(*s.Find(3) == "2c");
+ UNIT_ASSERT(s.Find(4) != s.End());
+ UNIT_ASSERT(*s.Find(4) == "hjkl");
+
+ UNIT_ASSERT(!s.Insert(3, "abcd"));
+ UNIT_ASSERT(*s.Find(3) == "2c");
+ s.Update(3, "abcd");
+ UNIT_ASSERT(*s.Find(3) == "abcd");
+
+ TCache::TIterator it = s.Find(3);
+ s.Erase(it);
+ UNIT_ASSERT(s.Find(3) == s.End());
+ }
+
+ Y_UNIT_TEST(LRUSetMaxSizeTest) {
+ typedef TLRUCache<int, TString> TCache;
+ TCache s(2); // size 2
+ s.Insert(1, "abcd");
+ s.Insert(2, "efgh");
+ s.Insert(3, "ijkl");
+ UNIT_ASSERT(s.GetOldest() == "efgh");
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) != s.End());
+ UNIT_ASSERT(s.Find(3) != s.End());
+
+ // Increasing size should not change anything
+ s.SetMaxSize(3);
+ UNIT_ASSERT(s.GetOldest() == "efgh");
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) != s.End());
+ UNIT_ASSERT(s.Find(3) != s.End());
+
+ // And we should be able to add fit more entries
+ s.Insert(4, "mnop");
+ s.Insert(5, "qrst");
+ UNIT_ASSERT(s.GetOldest() == "ijkl");
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) == s.End());
+ UNIT_ASSERT(s.Find(3) != s.End());
+ UNIT_ASSERT(s.Find(4) != s.End());
+ UNIT_ASSERT(s.Find(5) != s.End());
+
+ // Decreasing size should remove oldest entries
+ s.SetMaxSize(2);
+ UNIT_ASSERT(s.GetOldest() == "mnop");
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) == s.End());
+ UNIT_ASSERT(s.Find(3) == s.End());
+ UNIT_ASSERT(s.Find(4) != s.End());
+ UNIT_ASSERT(s.Find(5) != s.End());
+
+ // Ano no more entries will fit
+ s.Insert(6, "uvwx");
+ UNIT_ASSERT(s.GetOldest() == "qrst");
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) == s.End());
+ UNIT_ASSERT(s.Find(3) == s.End());
+ UNIT_ASSERT(s.Find(4) == s.End());
+ UNIT_ASSERT(s.Find(5) != s.End());
+ UNIT_ASSERT(s.Find(6) != s.End());
+ }
+
+ Y_UNIT_TEST(LWSetMaxSizeTest) {
+ typedef TLWCache<int, TString, size_t, TStrokaWeighter> TCache;
+ TCache s(2); // size 2
+ s.Insert(1, "a");
+ s.Insert(2, "aa");
+ s.Insert(3, "aaa");
+ UNIT_ASSERT(s.GetLightest() == "aa");
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) != s.End());
+ UNIT_ASSERT(s.Find(3) != s.End());
+
+ // Increasing size should not change anything
+ s.SetMaxSize(3);
+ UNIT_ASSERT(s.GetLightest() == "aa");
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) != s.End());
+ UNIT_ASSERT(s.Find(3) != s.End());
+
+ // And we should be able to add fit more entries
+ s.Insert(4, "aaaa");
+ s.Insert(5, "aaaaa");
+ UNIT_ASSERT(s.GetLightest() == "aaa");
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) == s.End());
+ UNIT_ASSERT(s.Find(3) != s.End());
+ UNIT_ASSERT(s.Find(4) != s.End());
+ UNIT_ASSERT(s.Find(5) != s.End());
+
+ // Decreasing size should remove oldest entries
+ s.SetMaxSize(2);
+ UNIT_ASSERT(s.GetLightest() == "aaaa");
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) == s.End());
+ UNIT_ASSERT(s.Find(3) == s.End());
+ UNIT_ASSERT(s.Find(4) != s.End());
+ UNIT_ASSERT(s.Find(5) != s.End());
+
+ // Ano no more entries will fit
+ s.Insert(6, "aaaaaa");
+ UNIT_ASSERT(s.GetLightest() == "aaaaa");
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) == s.End());
+ UNIT_ASSERT(s.Find(3) == s.End());
+ UNIT_ASSERT(s.Find(4) == s.End());
+ UNIT_ASSERT(s.Find(5) != s.End());
+ UNIT_ASSERT(s.Find(6) != s.End());
+ }
+
+ Y_UNIT_TEST(LFUSetMaxSizeTest) {
+ typedef TLFUCache<int, TString> TCache;
+ TCache s(2); // size 2
+ s.Insert(1, "abcd");
+ s.Insert(2, "efgh");
+ s.Insert(3, "ijkl");
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) != s.End());
+ UNIT_ASSERT(s.Find(3) != s.End());
+
+ // Increasing size should not change anything
+ s.SetMaxSize(3);
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) != s.End());
+ UNIT_ASSERT(s.Find(3) != s.End());
+
+ // And we should be able to add fit more entries
+ s.Insert(4, "mnop");
+ s.Insert(5, "qrst");
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) == s.End());
+ UNIT_ASSERT(s.Find(3) != s.End());
+ UNIT_ASSERT(s.Find(4) != s.End());
+ UNIT_ASSERT(s.Find(5) != s.End());
+
+ // Decreasing size should remove oldest entries
+ s.SetMaxSize(2);
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) == s.End());
+ UNIT_ASSERT(s.Find(3) != s.End());
+ UNIT_ASSERT(s.Find(4) == s.End());
+ UNIT_ASSERT(s.Find(5) != s.End());
+
+ // Ano no more entries will fit
+ s.Insert(6, "uvwx");
+ UNIT_ASSERT(s.Find(1) == s.End());
+ UNIT_ASSERT(s.Find(2) == s.End());
+ UNIT_ASSERT(s.Find(3) != s.End());
+ UNIT_ASSERT(s.Find(4) == s.End());
+ UNIT_ASSERT(s.Find(5) == s.End());
+ UNIT_ASSERT(s.Find(6) != s.End());
+ }
+
+ Y_UNIT_TEST(MultiCacheTest) {
+ typedef TLRUCache<int, TString> TCache;
+ TCache s(3, true);
+ UNIT_ASSERT(s.Insert(1, "abcd"));
+ UNIT_ASSERT(s.Insert(1, "bcde"));
+ UNIT_ASSERT(s.Insert(2, "fghi"));
+ UNIT_ASSERT(s.Insert(2, "ghij"));
+ // (1, "abcd") will be deleted
+ UNIT_ASSERT(*s.Find(1) == "bcde");
+ // (1, "bcde") will be promoted
+ UNIT_ASSERT(*s.FindOldest() == "fghi");
+ }
+
+ struct TMyDelete {
+ static int count;
+ template <typename T>
+ static void Destroy(const T&) {
+ ++count;
+ }
+ };
+ int TMyDelete::count = 0;
+
+ Y_UNIT_TEST(DeleterTest) {
+ typedef TLRUCache<int, TString, TMyDelete> TCache;
+ TCache s(2);
+ s.Insert(1, "123");
+ s.Insert(2, "456");
+ s.Insert(3, "789");
+ UNIT_ASSERT(TMyDelete::count == 1);
+ TCache::TIterator it = s.Find(2);
+ UNIT_ASSERT(it != s.End());
+ s.Erase(it);
+ UNIT_ASSERT(TMyDelete::count == 2);
+ }
+
+ Y_UNIT_TEST(PromoteOnFind) {
+ typedef TLRUCache<int, TString> TCache;
+ TCache s(2);
+ s.Insert(1, "123");
+ s.Insert(2, "456");
+ UNIT_ASSERT(s.Find(1) != s.End());
+ s.Insert(3, "789");
+ UNIT_ASSERT(s.Find(1) != s.End()); // Key 2 should have been deleted
+ }
+}
+
+Y_UNIT_TEST_SUITE(TThreadSafeCacheTest) {
+ typedef TThreadSafeCache<ui32, TString, ui32> TCache;
+
+ const char* VALS[] = {"abcd", "defg", "hjkl"};
+
+ class TCallbacks: public TCache::ICallbacks {
+ public:
+ TKey GetKey(ui32 i) const override {
+ return i;
+ }
+ TValue* CreateObject(ui32 i) const override {
+ Creations++;
+ return new TString(VALS[i]);
+ }
+
+ mutable i32 Creations = 0;
+ };
+
+ Y_UNIT_TEST(SimpleTest) {
+ for (ui32 i = 0; i < Y_ARRAY_SIZE(VALS); ++i) {
+ const TString data = *TCache::Get<TCallbacks>(i);
+ UNIT_ASSERT(data == VALS[i]);
+ }
+ }
+
+ Y_UNIT_TEST(InsertUpdateTest) {
+ TCallbacks callbacks;
+ TCache cache(callbacks, 10);
+
+ cache.Insert(2, MakeAtomicShared<TString>("hj"));
+ TAtomicSharedPtr<TString> item = cache.Get(2);
+
+ UNIT_ASSERT(callbacks.Creations == 0);
+ UNIT_ASSERT(*item == "hj");
+
+ cache.Insert(2, MakeAtomicShared<TString>("hjk"));
+ item = cache.Get(2);
+
+ UNIT_ASSERT(callbacks.Creations == 0);
+ UNIT_ASSERT(*item == "hj");
+
+ cache.Update(2, MakeAtomicShared<TString>("hjk"));
+ item = cache.Get(2);
+
+ UNIT_ASSERT(callbacks.Creations == 0);
+ UNIT_ASSERT(*item == "hjk");
+ }
+}
+
+Y_UNIT_TEST_SUITE(TThreadSafeCacheUnsafeTest) {
+ typedef TThreadSafeCache<ui32, TString, ui32> TCache;
+
+ const char* VALS[] = {"abcd", "defg", "hjkl"};
+ const ui32 FAILED_IDX = 1;
+
+ class TCallbacks: public TCache::ICallbacks {
+ public:
+ TKey GetKey(ui32 i) const override {
+ return i;
+ }
+ TValue* CreateObject(ui32 i) const override {
+ if (i == FAILED_IDX) {
+ return nullptr;
+ }
+ return new TString(VALS[i]);
+ }
+ };
+
+ Y_UNIT_TEST(SimpleTest) {
+ TCallbacks callbacks;
+ TCache cache(callbacks, Y_ARRAY_SIZE(VALS));
+ for (ui32 i = 0; i < Y_ARRAY_SIZE(VALS); ++i) {
+ const TString* data = cache.GetUnsafe(i).Get();
+ if (i == FAILED_IDX) {
+ UNIT_ASSERT(data == nullptr);
+ } else {
+ UNIT_ASSERT(*data == VALS[i]);
+ }
+ }
+ }
+}
+
+Y_UNIT_TEST_SUITE(TThreadSafeLRUCacheTest) {
+ typedef TThreadSafeLRUCache<size_t, TString, size_t> TCache;
+
+ TVector<TString> Values = {"zero", "one", "two", "three", "four"};
+
+ class TCallbacks: public TCache::ICallbacks {
+ public:
+ TKey GetKey(size_t i) const override {
+ return i;
+ }
+ TValue* CreateObject(size_t i) const override {
+ UNIT_ASSERT(i < Values.size());
+ Creations++;
+ return new TString(Values[i]);
+ }
+
+ mutable size_t Creations = 0;
+ };
+
+ Y_UNIT_TEST(SimpleTest) {
+ for (size_t i = 0; i < Values.size(); ++i) {
+ const TString data = *TCache::Get<TCallbacks>(i);
+ UNIT_ASSERT(data == Values[i]);
+ }
+ }
+
+ Y_UNIT_TEST(InsertUpdateTest) {
+ TCallbacks callbacks;
+ TCache cache(callbacks, 10);
+
+ cache.Insert(2, MakeAtomicShared<TString>("hj"));
+ TAtomicSharedPtr<TString> item = cache.Get(2);
+
+ UNIT_ASSERT(callbacks.Creations == 0);
+ UNIT_ASSERT(*item == "hj");
+
+ cache.Insert(2, MakeAtomicShared<TString>("hjk"));
+ item = cache.Get(2);
+
+ UNIT_ASSERT(callbacks.Creations == 0);
+ UNIT_ASSERT(*item == "hj");
+
+ cache.Update(2, MakeAtomicShared<TString>("hjk"));
+ item = cache.Get(2);
+
+ UNIT_ASSERT(callbacks.Creations == 0);
+ UNIT_ASSERT(*item == "hjk");
+ }
+
+ Y_UNIT_TEST(LRUTest) {
+ TCallbacks callbacks;
+ TCache cache(callbacks, 3);
+
+ UNIT_ASSERT_EQUAL(cache.GetMaxSize(), 3);
+
+ for (size_t i = 0; i < Values.size(); ++i) {
+ TAtomicSharedPtr<TString> item = cache.Get(i);
+ UNIT_ASSERT(*item == Values[i]);
+ }
+ UNIT_ASSERT(callbacks.Creations == Values.size());
+
+ size_t expectedCreations = Values.size();
+ TAtomicSharedPtr<TString> item;
+
+
+ item = cache.Get(4);
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "four");
+
+ item = cache.Get(2);
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "two");
+
+ item = cache.Get(0);
+ expectedCreations++;
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "zero");
+
+ UNIT_ASSERT(cache.Contains(1) == false);
+ UNIT_ASSERT(cache.Contains(3) == false);
+ UNIT_ASSERT(cache.Contains(4));
+ UNIT_ASSERT(cache.Contains(2));
+ UNIT_ASSERT(cache.Contains(0));
+
+ item = cache.Get(3);
+ expectedCreations++;
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "three");
+
+ item = cache.Get(2);
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "two");
+
+ item = cache.Get(0);
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "zero");
+
+ item = cache.Get(1);
+ expectedCreations++;
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "one");
+
+ item = cache.Get(2);
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "two");
+
+ item = cache.Get(4);
+ expectedCreations++;
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "four");
+ }
+
+ Y_UNIT_TEST(ChangeMaxSizeTest) {
+ TCallbacks callbacks;
+ TCache cache(callbacks, 3);
+
+ UNIT_ASSERT_EQUAL(cache.GetMaxSize(), 3);
+
+ for (size_t i = 0; i < Values.size(); ++i) {
+ TAtomicSharedPtr<TString> item = cache.Get(i);
+ UNIT_ASSERT(*item == Values[i]);
+ }
+
+ size_t expectedCreations = Values.size();
+ TAtomicSharedPtr<TString> item;
+
+ item = cache.Get(4);
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "four");
+
+ item = cache.Get(3);
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "three");
+
+ item = cache.Get(2);
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "two");
+
+ item = cache.Get(1);
+ expectedCreations++;
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "one");
+
+ cache.SetMaxSize(4);
+
+ item = cache.Get(0);
+ expectedCreations++;
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "zero");
+
+ item = cache.Get(4);
+ expectedCreations++;
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "four");
+
+ item = cache.Get(3);
+ expectedCreations++;
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "three");
+ UNIT_ASSERT(cache.Contains(2) == false);
+
+ cache.SetMaxSize(2);
+ UNIT_ASSERT(cache.Contains(3));
+ UNIT_ASSERT(cache.Contains(4));
+ UNIT_ASSERT(cache.Contains(2) == false);
+ UNIT_ASSERT(cache.Contains(1) == false);
+ UNIT_ASSERT(cache.Contains(0) == false);
+
+ item = cache.Get(0);
+ expectedCreations++;
+ UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
+ UNIT_ASSERT(*item == "zero");
+ UNIT_ASSERT(cache.Contains(4) == false);
+ UNIT_ASSERT(cache.Contains(3));
+ UNIT_ASSERT(cache.Contains(0));
+ }
+}
diff --git a/library/cpp/cache/ut/ya.make b/library/cpp/cache/ut/ya.make
new file mode 100644
index 0000000000..f660872369
--- /dev/null
+++ b/library/cpp/cache/ut/ya.make
@@ -0,0 +1,16 @@
+UNITTEST()
+
+OWNER(
+ g:util
+ vskipin
+)
+
+PEERDIR(
+ library/cpp/cache
+)
+
+SRCS(
+ cache_ut.cpp
+)
+
+END()
diff --git a/library/cpp/cache/ya.make b/library/cpp/cache/ya.make
new file mode 100644
index 0000000000..fd73032bf8
--- /dev/null
+++ b/library/cpp/cache/ya.make
@@ -0,0 +1,16 @@
+LIBRARY()
+
+OWNER(
+ g:util
+)
+
+SRCS(
+ cache.cpp
+ thread_safe_cache.cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ ut
+)
diff --git a/library/cpp/cgiparam/cgiparam.cpp b/library/cpp/cgiparam/cgiparam.cpp
new file mode 100644
index 0000000000..f3277b8e4b
--- /dev/null
+++ b/library/cpp/cgiparam/cgiparam.cpp
@@ -0,0 +1,273 @@
+#include "cgiparam.h"
+
+#include <library/cpp/string_utils/scan/scan.h>
+#include <library/cpp/string_utils/quote/quote.h>
+
+#include <util/generic/singleton.h>
+
+TCgiParameters::TCgiParameters(std::initializer_list<std::pair<TString, TString>> il) {
+ for (const auto& item : il) {
+ insert(item);
+ }
+}
+
+const TString& TCgiParameters::Get(const TStringBuf name, size_t numOfValue) const noexcept {
+ const auto it = Find(name, numOfValue);
+
+ return end() == it ? Default<TString>() : it->second;
+}
+
+bool TCgiParameters::Erase(const TStringBuf name, size_t pos) {
+ const auto pair = equal_range(name);
+
+ for (auto it = pair.first; it != pair.second; ++it, --pos) {
+ if (0 == pos) {
+ erase(it);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool TCgiParameters::Erase(const TStringBuf name, const TStringBuf val) {
+ const auto pair = equal_range(name);
+
+ bool found = false;
+ for (auto it = pair.first; it != pair.second;) {
+ if (val == it->second) {
+ it = erase(it);
+ found = true;
+ } else {
+ ++it;
+ }
+ }
+
+ return found;
+}
+
+size_t TCgiParameters::EraseAll(const TStringBuf name) {
+ size_t num = 0;
+
+ const auto pair = equal_range(name);
+
+ for (auto it = pair.first; it != pair.second; erase(it++), ++num)
+ ;
+
+ return num;
+}
+
+void TCgiParameters::JoinUnescaped(const TStringBuf key, char sep, TStringBuf val) {
+ const auto pair = equal_range(key);
+ auto it = pair.first;
+
+ if (it == pair.second) { // not found
+ if (val.IsInited()) {
+ emplace_hint(it, TString(key), TString(val));
+ }
+ } else {
+ TString& dst = it->second;
+
+ for (++it; it != pair.second; erase(it++)) {
+ dst += sep;
+ dst.AppendNoAlias(it->second.data(), it->second.size());
+ }
+
+ if (val.IsInited()) {
+ dst += sep;
+ dst += val;
+ }
+ }
+}
+
+static inline TString DoUnescape(const TStringBuf s) {
+ TString res;
+
+ res.reserve(CgiUnescapeBufLen(s.size()));
+ res.ReserveAndResize(CgiUnescape(res.begin(), s).size());
+
+ return res;
+}
+
+void TCgiParameters::InsertEscaped(const TStringBuf name, const TStringBuf value) {
+ InsertUnescaped(DoUnescape(name), DoUnescape(value));
+}
+
+template <bool addAll, class F>
+static inline void DoScan(const TStringBuf s, F& f) {
+ ScanKeyValue<addAll, '&', '='>(s, f);
+}
+
+struct TAddEscaped {
+ TCgiParameters* C;
+
+ inline void operator()(const TStringBuf key, const TStringBuf val) {
+ C->InsertEscaped(key, val);
+ }
+};
+
+void TCgiParameters::Scan(const TStringBuf query, bool form) {
+ Flush();
+ form ? ScanAdd(query) : ScanAddAll(query);
+}
+
+void TCgiParameters::ScanAdd(const TStringBuf query) {
+ TAddEscaped f = {this};
+
+ DoScan<false>(query, f);
+}
+
+void TCgiParameters::ScanAddUnescaped(const TStringBuf query) {
+ auto f = [this](const TStringBuf key, const TStringBuf val) {
+ this->InsertUnescaped(key, val);
+ };
+
+ DoScan<false>(query, f);
+}
+
+void TCgiParameters::ScanAddAllUnescaped(const TStringBuf query) {
+ auto f = [this](const TStringBuf key, const TStringBuf val) {
+ this->InsertUnescaped(key, val);
+ };
+
+ DoScan<true>(query, f);
+}
+
+void TCgiParameters::ScanAddAll(const TStringBuf query) {
+ TAddEscaped f = {this};
+
+ DoScan<true>(query, f);
+}
+
+TString TCgiParameters::Print() const {
+ TString res;
+
+ res.reserve(PrintSize());
+ const char* end = Print(res.begin());
+ res.ReserveAndResize(end - res.data());
+
+ return res;
+}
+
+char* TCgiParameters::Print(char* res) const {
+ if (empty()) {
+ return res;
+ }
+
+ for (auto i = begin();;) {
+ res = CGIEscape(res, i->first);
+ *res++ = '=';
+ res = CGIEscape(res, i->second);
+
+ if (++i == end()) {
+ break;
+ }
+
+ *res++ = '&';
+ }
+
+ return res;
+}
+
+size_t TCgiParameters::PrintSize() const noexcept {
+ size_t res = size(); // for '&'
+
+ for (const auto& i : *this) {
+ res += CgiEscapeBufLen(i.first.size() + i.second.size()); // extra zero will be used for '='
+ }
+
+ return res;
+}
+
+TString TCgiParameters::QuotedPrint(const char* safe) const {
+ if (empty()) {
+ return TString();
+ }
+
+ TString res;
+ res.ReserveAndResize(PrintSize());
+
+ char* ptr = res.begin();
+ for (auto i = begin();;) {
+ ptr = Quote(ptr, i->first, safe);
+ *ptr++ = '=';
+ ptr = Quote(ptr, i->second, safe);
+
+ if (++i == end()) {
+ break;
+ }
+
+ *ptr++ = '&';
+ }
+
+ res.ReserveAndResize(ptr - res.data());
+ return res;
+}
+
+TCgiParameters::const_iterator TCgiParameters::Find(const TStringBuf name, size_t pos) const noexcept {
+ const auto pair = equal_range(name);
+
+ for (auto it = pair.first; it != pair.second; ++it, --pos) {
+ if (0 == pos) {
+ return it;
+ }
+ }
+
+ return end();
+}
+
+bool TCgiParameters::Has(const TStringBuf name, const TStringBuf value) const noexcept {
+ const auto pair = equal_range(name);
+
+ for (auto it = pair.first; it != pair.second; ++it) {
+ if (value == it->second) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+TQuickCgiParam::TQuickCgiParam(const TStringBuf cgiParamStr) {
+ UnescapeBuf.reserve(CgiUnescapeBufLen(cgiParamStr.size()));
+ char* buf = UnescapeBuf.begin();
+
+ auto f = [this, &buf](const TStringBuf key, const TStringBuf val) {
+ TStringBuf name = CgiUnescapeBuf(buf, key);
+ buf += name.size() + 1;
+ TStringBuf value = CgiUnescapeBuf(buf, val);
+ buf += value.size() + 1;
+ Y_ASSERT(buf <= UnescapeBuf.begin() + UnescapeBuf.capacity() + 1 /*trailing zero*/);
+ emplace(name, value);
+ };
+
+ DoScan<false>(cgiParamStr, f);
+
+ if (buf != UnescapeBuf.begin()) {
+ UnescapeBuf.ReserveAndResize(buf - UnescapeBuf.begin() - 1 /*trailing zero*/);
+ }
+}
+
+const TStringBuf& TQuickCgiParam::Get(const TStringBuf name, size_t pos) const noexcept {
+ const auto pair = equal_range(name);
+
+ for (auto it = pair.first; it != pair.second; ++it, --pos) {
+ if (0 == pos) {
+ return it->second;
+ }
+ }
+
+ return Default<TStringBuf>();
+}
+
+bool TQuickCgiParam::Has(const TStringBuf name, const TStringBuf value) const noexcept {
+ const auto pair = equal_range(name);
+
+ for (auto it = pair.first; it != pair.second; ++it) {
+ if (value == it->second) {
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/library/cpp/cgiparam/cgiparam.h b/library/cpp/cgiparam/cgiparam.h
new file mode 100644
index 0000000000..87d1ab0ad4
--- /dev/null
+++ b/library/cpp/cgiparam/cgiparam.h
@@ -0,0 +1,184 @@
+#pragma once
+
+#include <library/cpp/iterator/iterate_values.h>
+
+#include <util/generic/iterator_range.h>
+#include <util/generic/map.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+
+#include <initializer_list>
+
+struct TStringLess {
+ template <class T1, class T2>
+ inline bool operator()(const T1& t1, const T2& t2) const noexcept {
+ return TStringBuf(t1) < TStringBuf(t2);
+ }
+};
+
+class TCgiParameters: public TMultiMap<TString, TString> {
+public:
+ TCgiParameters() = default;
+
+ explicit TCgiParameters(const TStringBuf cgiParamStr) {
+ Scan(cgiParamStr);
+ }
+
+ TCgiParameters(std::initializer_list<std::pair<TString, TString>> il);
+
+ void Flush() {
+ erase(begin(), end());
+ }
+
+ size_t EraseAll(const TStringBuf name);
+
+ size_t NumOfValues(const TStringBuf name) const noexcept {
+ return count(name);
+ }
+
+ TString operator()() const {
+ return Print();
+ }
+
+ void Scan(const TStringBuf cgiParStr, bool form = true);
+ void ScanAdd(const TStringBuf cgiParStr);
+ void ScanAddUnescaped(const TStringBuf cgiParStr);
+ void ScanAddAllUnescaped(const TStringBuf cgiParStr);
+ void ScanAddAll(const TStringBuf cgiParStr);
+
+ /// Returns the string representation of all the stored parameters
+ /**
+ * @note The returned string has format <name1>=<value1>&<name2>=<value2>&...
+ * @note Names and values in the returned string are CGI-escaped.
+ */
+ TString Print() const;
+ char* Print(char* res) const;
+
+ Y_PURE_FUNCTION
+ size_t PrintSize() const noexcept;
+
+ /** The same as Print* except that RFC-3986 reserved characters are escaped.
+ * @param safe - set of characters to be skipped in escaping
+ */
+ TString QuotedPrint(const char* safe = "/") const;
+
+ Y_PURE_FUNCTION
+ auto Range(const TStringBuf name) const noexcept {
+ return IterateValues(MakeIteratorRange(equal_range(name)));
+ }
+
+ Y_PURE_FUNCTION
+ const_iterator Find(const TStringBuf name, size_t numOfValue = 0) const noexcept;
+
+ Y_PURE_FUNCTION
+ bool Has(const TStringBuf name, const TStringBuf value) const noexcept;
+
+ Y_PURE_FUNCTION
+ bool Has(const TStringBuf name) const noexcept {
+ const auto pair = equal_range(name);
+ return pair.first != pair.second;
+ }
+ /// Returns value by name
+ /**
+ * @note The returned value is CGI-unescaped.
+ */
+ Y_PURE_FUNCTION
+ const TString& Get(const TStringBuf name, size_t numOfValue = 0) const noexcept;
+
+ void InsertEscaped(const TStringBuf name, const TStringBuf value);
+
+#if !defined(__GLIBCXX__)
+ template <typename TName, typename TValue>
+ inline void InsertUnescaped(TName&& name, TValue&& value) {
+ // TStringBuf use as TName or TValue is C++17 actually.
+ // There is no pair constructor available in C++14 when required type
+ // is not implicitly constructible from given type.
+ // But libc++ pair allows this with C++14.
+ emplace(std::forward<TName>(name), std::forward<TValue>(value));
+ }
+#else
+ template <typename TName, typename TValue>
+ inline void InsertUnescaped(TName&& name, TValue&& value) {
+ emplace(TString(name), TString(value));
+ }
+#endif
+
+ // replace all values for a given key with new values
+ template <typename TIter>
+ void ReplaceUnescaped(const TStringBuf key, TIter valuesBegin, const TIter valuesEnd);
+
+ void ReplaceUnescaped(const TStringBuf key, std::initializer_list<TStringBuf> values) {
+ ReplaceUnescaped(key, values.begin(), values.end());
+ }
+
+ void ReplaceUnescaped(const TStringBuf key, const TStringBuf value) {
+ ReplaceUnescaped(key, {value});
+ }
+
+ // join multiple values into a single one using a separator
+ // if val is a [possibly empty] non-NULL string, append it as well
+ void JoinUnescaped(const TStringBuf key, char sep, TStringBuf val = TStringBuf());
+
+ bool Erase(const TStringBuf name, size_t numOfValue = 0);
+ bool Erase(const TStringBuf name, const TStringBuf val);
+
+ inline const char* FormField(const TStringBuf name, size_t numOfValue = 0) const {
+ const_iterator it = Find(name, numOfValue);
+
+ if (it == end()) {
+ return nullptr;
+ }
+
+ return it->second.data();
+ }
+};
+
+template <typename TIter>
+void TCgiParameters::ReplaceUnescaped(const TStringBuf key, TIter valuesBegin, const TIter valuesEnd) {
+ const auto oldRange = equal_range(key);
+ auto current = oldRange.first;
+
+ // reuse as many existing nodes as possible (probably none)
+ for (; valuesBegin != valuesEnd && current != oldRange.second; ++valuesBegin, ++current) {
+ current->second = *valuesBegin;
+ }
+
+ // if there were more nodes than we need to insert then erase remaining ones
+ for (; current != oldRange.second; erase(current++)) {
+ }
+
+ // if there were less nodes than we need to insert then emplace the rest of the range
+ if (valuesBegin != valuesEnd) {
+ const TString keyStr = TString(key);
+ for (; valuesBegin != valuesEnd; ++valuesBegin) {
+ emplace_hint(oldRange.second, keyStr, TString(*valuesBegin));
+ }
+ }
+}
+
+/** TQuickCgiParam is a faster non-editable version of TCgiParameters.
+ * Care should be taken when replacing:
+ * - note that the result of Get() is invalidated when TQuickCgiParam object is destroyed.
+ */
+
+class TQuickCgiParam: public TMultiMap<TStringBuf, TStringBuf> {
+public:
+ TQuickCgiParam() = default;
+
+ explicit TQuickCgiParam(const TStringBuf cgiParamStr);
+
+ Y_PURE_FUNCTION
+ bool Has(const TStringBuf name, const TStringBuf value) const noexcept;
+
+ Y_PURE_FUNCTION
+ bool Has(const TStringBuf name) const noexcept {
+ const auto pair = equal_range(name);
+ return pair.first != pair.second;
+ }
+
+ Y_PURE_FUNCTION
+ const TStringBuf& Get(const TStringBuf name, size_t numOfValue = 0) const noexcept;
+
+private:
+ TString UnescapeBuf;
+};
diff --git a/library/cpp/cgiparam/cgiparam_ut.cpp b/library/cpp/cgiparam/cgiparam_ut.cpp
new file mode 100644
index 0000000000..a562342084
--- /dev/null
+++ b/library/cpp/cgiparam/cgiparam_ut.cpp
@@ -0,0 +1,242 @@
+#include "cgiparam.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TCgiParametersTest) {
+ Y_UNIT_TEST(TestScan1) {
+ TCgiParameters C;
+ C.Scan("aaa=b%62b&ccc=ddd&ag0=");
+ UNIT_ASSERT_EQUAL(C.Get("aaa") == "bbb", true);
+ UNIT_ASSERT_EQUAL(C.NumOfValues("ag0") == 1, true);
+ UNIT_ASSERT(C.Has("ccc", "ddd"));
+ UNIT_ASSERT(C.Has("ag0", ""));
+ UNIT_ASSERT(!C.Has("a", "bbb"));
+ UNIT_ASSERT(!C.Has("aaa", "bb"));
+
+ UNIT_ASSERT(C.Has("ccc"));
+ UNIT_ASSERT(!C.Has("zzzzzz"));
+ }
+
+ Y_UNIT_TEST(TestQuick) {
+ TQuickCgiParam C("aaa=b%62b&ccc=ddd&ag0=");
+ UNIT_ASSERT_EQUAL(C.Get("aaa") == "bbb", true);
+ UNIT_ASSERT(C.Has("ccc", "ddd"));
+ UNIT_ASSERT(C.Has("ag0", ""));
+ UNIT_ASSERT(!C.Has("a", "bbb"));
+ UNIT_ASSERT(!C.Has("aaa", "bb"));
+
+ UNIT_ASSERT(C.Has("ccc"));
+ UNIT_ASSERT(!C.Has("zzzzzz"));
+
+ TQuickCgiParam D = std::move(C);
+ UNIT_ASSERT(D.Has("aaa"));
+
+ TQuickCgiParam E("");
+ UNIT_ASSERT(!E.Has("aaa"));
+
+ C = std::move(E);
+ UNIT_ASSERT(!C.Has("aaa"));
+ }
+
+ Y_UNIT_TEST(TestScan2) {
+ const TString parsee("=000&aaa=bbb&ag0=&ccc=ddd");
+ TCgiParameters c;
+ c.Scan(parsee);
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), parsee);
+ }
+
+ Y_UNIT_TEST(TestScan3) {
+ const TString parsee("aaa=bbb&ag0=&ccc=ddd");
+ TCgiParameters c;
+ c.Scan(parsee);
+
+ c.InsertUnescaped("d", "xxx");
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), parsee + "&d=xxx");
+ }
+
+ Y_UNIT_TEST(TestScanAddAll1) {
+ TCgiParameters c;
+ c.ScanAddAll("qw");
+
+ UNIT_ASSERT_VALUES_EQUAL(c.size(), 1u);
+ UNIT_ASSERT(c.Get("qw").empty());
+ }
+
+ Y_UNIT_TEST(TestScanAddAll2) {
+ TCgiParameters c;
+ c.ScanAddAll("qw&");
+
+ UNIT_ASSERT_VALUES_EQUAL(c.size(), 1u);
+ UNIT_ASSERT(c.Get("qw").empty());
+ }
+
+ Y_UNIT_TEST(TestScanAddAll3) {
+ TCgiParameters c;
+ c.ScanAddAll("qw=1&x");
+
+ UNIT_ASSERT_VALUES_EQUAL(c.size(), 2u);
+ UNIT_ASSERT_VALUES_EQUAL(c.Get("qw"), "1");
+ UNIT_ASSERT(c.Get("x").empty());
+ }
+
+ Y_UNIT_TEST(TestScanAddAll4) {
+ TCgiParameters c;
+ c.ScanAddAll("ccc=1&aaa=1&ccc=3&bbb&ccc=2");
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), "aaa=1&bbb=&ccc=1&ccc=3&ccc=2");
+ }
+
+ Y_UNIT_TEST(TestScanAddAllUnescaped1) {
+ TCgiParameters c;
+ c.ScanAddAllUnescaped("ccc=1&aaa=1&ccc=3&bbb&ccc=2");
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), "aaa=1&bbb=&ccc=1&ccc=3&ccc=2");
+ }
+
+ Y_UNIT_TEST(TestScanAddAllUnescaped2) {
+ TCgiParameters c;
+ c.ScanAddAllUnescaped("text=something&null");
+
+ UNIT_ASSERT_VALUES_EQUAL(c.size(), 2u);
+ UNIT_ASSERT_VALUES_EQUAL(c.Get("text"), "something");
+ UNIT_ASSERT(c.Get("null").empty());
+ }
+
+ Y_UNIT_TEST(TestScanAddAllUnescaped3) {
+ TCgiParameters c;
+ c.ScanAddAllUnescaped("text=%D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82%2C");
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Get("text"), "%D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82%2C");
+ }
+
+ Y_UNIT_TEST(TestEraseAll) {
+ TCgiParameters c;
+ c.ScanAddAll("par=1&aaa=1&par=2&bbb&par=3");
+ c.EraseAll("par");
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), "aaa=1&bbb=");
+ }
+
+ Y_UNIT_TEST(TestErase) {
+ TCgiParameters c;
+ c.ScanAddAll("par=1&aaa=1&par=2&bbb&par=3&par=1");
+
+ c.Erase("par", 1);
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), "aaa=1&bbb=&par=1&par=3&par=1");
+
+ c.Erase("par", "1");
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), "aaa=1&bbb=&par=3");
+ }
+
+ Y_UNIT_TEST(TestReplaceUnescaped1) {
+ TCgiParameters c;
+ c.ScanAddAll("many_keys=1&aaa=1&many_keys=2&bbb&many_keys=3");
+ c.ReplaceUnescaped("many_keys", "new_value");
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), "aaa=1&bbb=&many_keys=new_value");
+ }
+
+ Y_UNIT_TEST(TestReplaceUnescaped2) {
+ TCgiParameters c;
+ c.ScanAddAll("par=1&only_one=1&par=2&bbb&par=3");
+ c.ReplaceUnescaped("only_one", "new_value");
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), "bbb=&only_one=new_value&par=1&par=2&par=3");
+ }
+
+ Y_UNIT_TEST(TestReplaceUnescaped3) {
+ TCgiParameters c;
+ c.ScanAddAll("par=1&aaa=1&par=2&bbb&par=3");
+ c.ReplaceUnescaped("no_such_key", "new_value");
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), "aaa=1&bbb=&no_such_key=new_value&par=1&par=2&par=3");
+ }
+
+ Y_UNIT_TEST(TestReplaceUnescapedRange1) {
+ TCgiParameters c;
+ c.ScanAddAll("par=1&aaa=1&par=2&bbb&par=3");
+ c.ReplaceUnescaped("par", {"x", "y", "z"}); // 3 old values, 3 new values
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), "aaa=1&bbb=&par=x&par=y&par=z");
+ }
+
+ Y_UNIT_TEST(TestReplaceUnescapedRange2) {
+ TCgiParameters c;
+ c.ScanAddAll("par=1&aaa=1&par=2&bbb");
+ c.ReplaceUnescaped("par", {"x", "y", "z"}); // 2 old values, 3 new values
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), "aaa=1&bbb=&par=x&par=y&par=z");
+ }
+
+ Y_UNIT_TEST(TestReplaceUnescapedRange3) {
+ TCgiParameters c;
+ c.ScanAddAll("par=1&aaa=1&par=2&bbb&par=3");
+ c.ReplaceUnescaped("par", {"x", "y"}); // 3 old values, 2 new values
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), "aaa=1&bbb=&par=x&par=y");
+ }
+
+ Y_UNIT_TEST(TestNumOfValues) {
+ TCgiParameters c;
+ c.ScanAddAll("par=1&aaa=1&par=2&bbb&par=3");
+
+ UNIT_ASSERT_VALUES_EQUAL(c.NumOfValues("par"), 3u);
+ }
+
+ Y_UNIT_TEST(TestUnscape) {
+ TCgiParameters c("f=1&t=%84R%84%7C%84%80%84%7E&reqenc=SHIFT_JIS&p=0");
+ UNIT_ASSERT_VALUES_EQUAL(c.Get("t"), "\x84R\x84\x7C\x84\x80\x84\x7E");
+ }
+
+ Y_UNIT_TEST(TestEmpty) {
+ UNIT_ASSERT(TCgiParameters().Print().empty());
+ }
+
+ Y_UNIT_TEST(TestJoinUnescaped) {
+ TCgiParameters c;
+
+ c.Scan("foo=1&foo=2");
+ c.JoinUnescaped("foo", ';', "0");
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), "foo=1;2;0");
+ }
+
+ Y_UNIT_TEST(TestContInit) {
+ TCgiParameters c = {std::make_pair("a", "a1"), std::make_pair("b", "b1"), std::make_pair("a", "a2")};
+
+ UNIT_ASSERT_VALUES_EQUAL(c.NumOfValues("a"), 2u);
+ UNIT_ASSERT_VALUES_EQUAL(c.NumOfValues("b"), 1u);
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Get("b"), "b1");
+ UNIT_ASSERT_VALUES_EQUAL(c.Get("a", 0), "a1");
+ UNIT_ASSERT_VALUES_EQUAL(c.Get("a", 1), "a2");
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), "a=a1&a=a2&b=b1");
+ }
+
+ Y_UNIT_TEST(TestPrintAsQuote) {
+ TCgiParameters c = {
+ std::make_pair("aaa", "value/with/slashes"),
+ std::make_pair("b/b/b", "value_without_slashes"),
+ std::make_pair("ccc", "value")};
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), "aaa=value/with/slashes&b/b/b=value_without_slashes&ccc=value");
+ UNIT_ASSERT_VALUES_EQUAL(c.QuotedPrint(""), "aaa=value%2Fwith%2Fslashes&b%2Fb%2Fb=value_without_slashes&ccc=value");
+ }
+
+ Y_UNIT_TEST(TestPrintAsQuoteEmpty) {
+ TCgiParameters c = {};
+ UNIT_ASSERT_VALUES_EQUAL(c.QuotedPrint(""), "");
+ }
+
+ Y_UNIT_TEST(TestPrintAsQuoteEmptyKeyOrValue) {
+ TCgiParameters c = {
+ std::make_pair("", "value/of/empty"),
+ std::make_pair("key/for/empty", "")};
+
+ UNIT_ASSERT_VALUES_EQUAL(c.Print(), "=value/of/empty&key/for/empty=");
+ UNIT_ASSERT_VALUES_EQUAL(c.QuotedPrint(""), "=value%2Fof%2Fempty&key%2Ffor%2Fempty=");
+ }
+}
diff --git a/library/cpp/cgiparam/fuzz/main.cpp b/library/cpp/cgiparam/fuzz/main.cpp
new file mode 100644
index 0000000000..69d82b5f32
--- /dev/null
+++ b/library/cpp/cgiparam/fuzz/main.cpp
@@ -0,0 +1,11 @@
+#include <library/cpp/cgiparam/cgiparam.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const ui8* data, size_t size) {
+ try {
+ TCgiParameters(TStringBuf((const char*)data, size));
+ } catch (...) {
+ // ¯\_(ツ)_/¯
+ }
+
+ return 0; // Non-zero return values are reserved for future use.
+}
diff --git a/library/cpp/cgiparam/fuzz/ya.make b/library/cpp/cgiparam/fuzz/ya.make
new file mode 100644
index 0000000000..8fb9d50d3b
--- /dev/null
+++ b/library/cpp/cgiparam/fuzz/ya.make
@@ -0,0 +1,16 @@
+FUZZ()
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ main.cpp
+)
+
+PEERDIR(
+ library/cpp/cgiparam
+)
+
+END()
diff --git a/library/cpp/cgiparam/ut/ya.make b/library/cpp/cgiparam/ut/ya.make
new file mode 100644
index 0000000000..1eee403951
--- /dev/null
+++ b/library/cpp/cgiparam/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/cgiparam)
+
+OWNER(g:util)
+
+SRCS(
+ cgiparam_ut.cpp
+)
+
+END()
diff --git a/library/cpp/cgiparam/ya.make b/library/cpp/cgiparam/ya.make
new file mode 100644
index 0000000000..fa1a6a13c0
--- /dev/null
+++ b/library/cpp/cgiparam/ya.make
@@ -0,0 +1,16 @@
+LIBRARY()
+
+OWNER(g:util)
+
+SRCS(
+ cgiparam.cpp
+ cgiparam.h
+)
+
+PEERDIR(
+ library/cpp/iterator
+ library/cpp/string_utils/quote
+ library/cpp/string_utils/scan
+)
+
+END()
diff --git a/library/cpp/charset/README.md b/library/cpp/charset/README.md
new file mode 100644
index 0000000000..9a257e3b4d
--- /dev/null
+++ b/library/cpp/charset/README.md
@@ -0,0 +1,10 @@
+Здесь представлены функции и enum'ы для работы с кодировками.
+
+Наиболее полезные конструкции этой библиотеки:
+1. [`enum ECharset`](https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/charset/doccodes.h) - перечень кодировок, которые умеет определять [детектор кодировок](https://a.yandex-team.ru/arc/trunk/arcadia/kernel/recshell/recshell.h?rev=8268697#L56).
+2. [Функция](https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/charset/recyr.hh?rev=r6888372#L137) `inline TString Recode(ECharset from, ECharset to, const TString& in)` для преобразования кодировок.
+3. [Функция](https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/charset/wide.h?rev=r6888372#L277) `inline TUtf16String UTF8ToWide(const char* text, size_t len, const CodePage& cp)`, пытающаяся построить широкую строку из UTF-8, а если не получается - с помощью кодировки `cp`.
+
+3. [Класс `TCiString`](https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/charset/ci_string.h) - аналог `TString`, но использующий case-insensitive-компаратор и хеш и поддерживающий разные кодировки.
+
+В комплекте есть ещё много функций для работы со старой однобайтной Yandex-кодировкой. Не рекомендуется к использованию. Для преобразования из UTF-8 в `TUtf16String` и для работы с Unicode используйте функции из [arcadia/util/charset](https://a.yandex-team.ru/arc/trunk/arcadia/util/charset).
diff --git a/library/cpp/charset/ci_string.cpp b/library/cpp/charset/ci_string.cpp
new file mode 100644
index 0000000000..634b05ec68
--- /dev/null
+++ b/library/cpp/charset/ci_string.cpp
@@ -0,0 +1,42 @@
+#include "ci_string.h"
+#include "wide.h"
+
+int TCiString::compare(const TCiString& s1, const TCiString& s2, const CodePage& cp) {
+ return cp.stricmp(s1.data(), s2.data());
+}
+
+int TCiString::compare(const char* p, const TCiString& s2, const CodePage& cp) {
+ return cp.stricmp(p, s2.data());
+}
+
+int TCiString::compare(const TCiString& s1, const char* p, const CodePage& cp) {
+ return cp.stricmp(s1.data(), p);
+}
+
+int TCiString::compare(const TStringBuf& p1, const TStringBuf& p2, const CodePage& cp) {
+ int rv = cp.strnicmp(p1.data(), p2.data(), Min(p1.size(), p2.size()));
+ return rv ? rv : p1.size() < p2.size() ? -1 : p1.size() == p2.size() ? 0 : 1;
+}
+
+bool TCiString::is_prefix(const TStringBuf& what, const TStringBuf& of, const CodePage& cp) {
+ size_t len = what.size();
+ return len <= of.size() && cp.strnicmp(what.data(), of.data(), len) == 0;
+}
+
+bool TCiString::is_suffix(const TStringBuf& what, const TStringBuf& of, const CodePage& cp) {
+ size_t len = what.size();
+ size_t slen = of.size();
+ return (len <= slen) && (0 == cp.strnicmp(what.data(), of.data() + slen - len, len));
+}
+
+size_t TCiString::hashVal(const char* s, size_t len, const CodePage& cp) {
+ size_t h = len;
+ for (; /* (*s) && */ len--; ++s)
+ h = 5 * h + cp.ToLower(*s);
+ return h;
+}
+
+template <>
+void Out<TCiString>(IOutputStream& o, const TCiString& p) {
+ o.Write(p.data(), p.size());
+}
diff --git a/library/cpp/charset/ci_string.h b/library/cpp/charset/ci_string.h
new file mode 100644
index 0000000000..edf24c1b6f
--- /dev/null
+++ b/library/cpp/charset/ci_string.h
@@ -0,0 +1,280 @@
+#pragma once
+
+#include "codepage.h"
+
+#include <util/generic/string.h>
+#include <util/str_stl.h>
+
+// Same as TString but uses CASE INSENSITIVE comparator and hash. Use with care.
+class TCiString: public TString {
+public:
+ TCiString() {
+ }
+
+ TCiString(const TString& s)
+ : TString(s)
+ {
+ }
+
+ TCiString(const TString& s, size_t pos, size_t n)
+ : TString(s, pos, n)
+ {
+ }
+
+ TCiString(const char* pc)
+ : TString(pc)
+ {
+ }
+
+ TCiString(const char* pc, size_t n)
+ : TString(pc, n)
+ {
+ }
+
+ TCiString(const char* pc, size_t pos, size_t n)
+ : TString(pc, pos, n)
+ {
+ }
+
+ TCiString(size_t n, char c)
+ : TString(n, c)
+ {
+ }
+
+ TCiString(const TUninitialized& uninitialized)
+ : TString(uninitialized)
+ {
+ }
+
+ TCiString(const char* b, const char* e)
+ : TString(b, e)
+ {
+ }
+
+ explicit TCiString(const TStringBuf& s)
+ : TString(s)
+ {
+ }
+
+ // ~~~ Comparison ~~~ : FAMILY0(int, compare)
+ static int compare(const TCiString& s1, const TCiString& s2, const CodePage& cp = csYandex);
+ static int compare(const char* p, const TCiString& s2, const CodePage& cp = csYandex);
+ static int compare(const TCiString& s1, const char* p, const CodePage& cp = csYandex);
+ static int compare(const TStringBuf& p1, const TStringBuf& p2, const CodePage& cp = csYandex);
+
+ // TODO: implement properly in TString via enum ECaseSensitivity
+ static bool is_prefix(const TStringBuf& what, const TStringBuf& of, const CodePage& cp = csYandex);
+ static bool is_suffix(const TStringBuf& what, const TStringBuf& of, const CodePage& cp = csYandex);
+
+ bool StartsWith(const TStringBuf& s, const CodePage& cp = csYandex) const {
+ return is_prefix(s, *this, cp);
+ }
+
+ bool EndsWith(const TStringBuf& s, const CodePage& cp = csYandex) const {
+ return is_suffix(s, *this, cp);
+ }
+
+ friend bool operator==(const TCiString& s1, const TCiString& s2) {
+ return TCiString::compare(s1, s2) == 0;
+ }
+
+ friend bool operator==(const TCiString& s, const char* pc) {
+ return TCiString::compare(s, pc) == 0;
+ }
+
+ friend bool operator==(const char* pc, const TCiString& s) {
+ return TCiString::compare(pc, s) == 0;
+ }
+
+ template <typename TDerived2, typename TTraits2>
+ friend bool operator==(const TCiString& s, const TStringBase<TDerived2, TChar, TTraits2>& pc) {
+ return TCiString::compare(s, pc) == 0;
+ }
+
+ template <typename TDerived2, typename TTraits2>
+ friend bool operator==(const TStringBase<TDerived2, TChar, TTraits2>& pc, const TCiString& s) {
+ return TCiString::compare(pc, s) == 0;
+ }
+
+ friend bool operator!=(const TCiString& s1, const TCiString& s2) {
+ return TCiString::compare(s1, s2) != 0;
+ }
+
+ friend bool operator!=(const TCiString& s, const char* pc) {
+ return TCiString::compare(s, pc) != 0;
+ }
+
+ friend bool operator!=(const char* pc, const TCiString& s) {
+ return TCiString::compare(pc, s) != 0;
+ }
+
+ template <typename TDerived2, typename TTraits2>
+ friend bool operator!=(const TCiString& s, const TStringBase<TDerived2, TChar, TTraits2>& pc) {
+ return TCiString::compare(s, pc) != 0;
+ }
+
+ template <typename TDerived2, typename TTraits2>
+ friend bool operator!=(const TStringBase<TDerived2, TChar, TTraits2>& pc, const TCiString& s) {
+ return TCiString::compare(pc, s) != 0;
+ }
+
+ friend bool operator<(const TCiString& s1, const TCiString& s2) {
+ return TCiString::compare(s1, s2) < 0;
+ }
+
+ friend bool operator<(const TCiString& s, const char* pc) {
+ return TCiString::compare(s, pc) < 0;
+ }
+
+ friend bool operator<(const char* pc, const TCiString& s) {
+ return TCiString::compare(pc, s) < 0;
+ }
+
+ template <typename TDerived2, typename TTraits2>
+ friend bool operator<(const TCiString& s, const TStringBase<TDerived2, TChar, TTraits2>& pc) {
+ return TCiString::compare(s, pc) < 0;
+ }
+
+ template <typename TDerived2, typename TTraits2>
+ friend bool operator<(const TStringBase<TDerived2, TChar, TTraits2>& pc, const TCiString& s) {
+ return TCiString::compare(pc, s) < 0;
+ }
+
+ friend bool operator<=(const TCiString& s1, const TCiString& s2) {
+ return TCiString::compare(s1, s2) <= 0;
+ }
+
+ friend bool operator<=(const TCiString& s, const char* pc) {
+ return TCiString::compare(s, pc) <= 0;
+ }
+
+ friend bool operator<=(const char* pc, const TCiString& s) {
+ return TCiString::compare(pc, s) <= 0;
+ }
+
+ template <typename TDerived2, typename TTraits2>
+ friend bool operator<=(const TCiString& s, const TStringBase<TDerived2, TChar, TTraits2>& pc) {
+ return TCiString::compare(s, pc) <= 0;
+ }
+
+ template <typename TDerived2, typename TTraits2>
+ friend bool operator<=(const TStringBase<TDerived2, TChar, TTraits2>& pc, const TCiString& s) {
+ return TCiString::compare(pc, s) <= 0;
+ }
+
+ friend bool operator>(const TCiString& s1, const TCiString& s2) {
+ return TCiString::compare(s1, s2) > 0;
+ }
+
+ friend bool operator>(const TCiString& s, const char* pc) {
+ return TCiString::compare(s, pc) > 0;
+ }
+
+ friend bool operator>(const char* pc, const TCiString& s) {
+ return TCiString::compare(pc, s) > 0;
+ }
+
+ template <typename TDerived2, typename TTraits2>
+ friend bool operator>(const TCiString& s, const TStringBase<TDerived2, TChar, TTraits2>& pc) noexcept {
+ return TCiString::compare(s, pc) > 0;
+ }
+
+ template <typename TDerived2, typename TTraits2>
+ friend bool operator>(const TStringBase<TDerived2, TChar, TTraits2>& pc, const TCiString& s) noexcept {
+ return TCiString::compare(pc, s) > 0;
+ }
+
+ friend bool operator>=(const TCiString& s1, const TCiString& s2) {
+ return TCiString::compare(s1, s2) >= 0;
+ }
+
+ friend bool operator>=(const TCiString& s, const char* pc) {
+ return TCiString::compare(s, pc) >= 0;
+ }
+
+ friend bool operator>=(const char* pc, const TCiString& s) {
+ return TCiString::compare(pc, s) >= 0;
+ }
+
+ template <typename TDerived2, typename TTraits2>
+ friend bool operator>=(const TCiString& s, const TStringBase<TDerived2, TChar, TTraits2>& pc) {
+ return TCiString::compare(s, pc) >= 0;
+ }
+
+ template <typename TDerived2, typename TTraits2>
+ friend bool operator>=(const TStringBase<TDerived2, TChar, TTraits2>& pc, const TCiString& s) {
+ return TCiString::compare(pc, s) >= 0;
+ }
+
+ static size_t hashVal(const char* pc, size_t len, const CodePage& cp = csYandex);
+
+ size_t hash() const {
+ return TCiString::hashVal(data(), length());
+ }
+};
+
+struct ci_hash {
+ inline size_t operator()(const char* s) const {
+ return TCiString::hashVal(s, strlen(s));
+ }
+ inline size_t operator()(const TStringBuf& s) const {
+ return TCiString::hashVal(s.data(), s.size());
+ }
+};
+
+struct ci_hash32 { // not the same as ci_hash under 64-bit
+ inline ui32 operator()(const char* s) const {
+ return (ui32)TCiString::hashVal(s, strlen(s));
+ }
+};
+
+//template <class T> struct hash;
+
+template <>
+struct hash<TCiString>: public ci_hash {
+};
+
+template <class T>
+struct TCIHash {
+};
+
+template <>
+struct TCIHash<const char*> {
+ inline size_t operator()(const TStringBuf& s) const {
+ return TCiString::hashVal(s.data(), s.size());
+ }
+};
+
+template <>
+struct TCIHash<TStringBuf> {
+ inline size_t operator()(const TStringBuf& s) const {
+ return TCiString::hashVal(s.data(), s.size());
+ }
+};
+
+template <>
+struct TCIHash<TString> {
+ inline size_t operator()(const TString& s) const {
+ return TCiString::hashVal(s.data(), s.size());
+ }
+};
+
+struct ci_less {
+ inline bool operator()(const char* x, const char* y) const {
+ return csYandex.stricmp(x, y) < 0;
+ }
+};
+
+struct ci_equal_to {
+ inline bool operator()(const char* x, const char* y) const {
+ return csYandex.stricmp(x, y) == 0;
+ }
+ // this implementation is not suitable for strings with zero characters inside, sorry
+ bool operator()(const TStringBuf& x, const TStringBuf& y) const {
+ return x.size() == y.size() && csYandex.strnicmp(x.data(), y.data(), y.size()) == 0;
+ }
+};
+
+template <>
+struct TEqualTo<TCiString>: public ci_equal_to {
+};
diff --git a/library/cpp/charset/ci_string_ut.cpp b/library/cpp/charset/ci_string_ut.cpp
new file mode 100644
index 0000000000..3d2a53d5fe
--- /dev/null
+++ b/library/cpp/charset/ci_string_ut.cpp
@@ -0,0 +1,23 @@
+#include "ci_string.h"
+
+#include <util/generic/hash.h>
+#include <util/generic/string_ut.h>
+
+class TCaseStringTest: public TTestBase, private TStringTestImpl<TCiString, TTestData<char>> {
+public:
+ void TestSpecial() {
+ TCiString ss = Data._0123456(); // type 'TCiString' is used as is
+ size_t hash_val = ComputeHash(ss);
+ UNIT_ASSERT(hash_val == 1489244);
+ }
+
+public:
+ UNIT_TEST_SUITE(TCaseStringTest);
+ UNIT_TEST(TestOperators);
+ UNIT_TEST(TestOperatorsCI);
+
+ UNIT_TEST(TestSpecial);
+ UNIT_TEST_SUITE_END();
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TCaseStringTest);
diff --git a/library/cpp/charset/codepage.cpp b/library/cpp/charset/codepage.cpp
new file mode 100644
index 0000000000..0431bef31b
--- /dev/null
+++ b/library/cpp/charset/codepage.cpp
@@ -0,0 +1,511 @@
+#include "ci_string.h"
+#include "wide.h"
+#include "recyr.hh"
+#include "codepage.h"
+
+#include <util/string/cast.h>
+#include <util/string/subst.h>
+#include <util/string/util.h>
+#include <util/system/hi_lo.h>
+#include <util/system/yassert.h>
+#include <util/generic/hash.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/generic/hash_set.h>
+#include <util/generic/singleton.h>
+#include <util/generic/yexception.h>
+#include <util/memory/pool.h>
+
+#include <cstring>
+
+#include <ctype.h>
+
+using namespace NCodepagePrivate;
+
+void Recoder::Create(const CodePage& source, const CodePage& target) {
+ const Encoder* wideTarget = &EncoderByCharset(target.CPEnum);
+ Create(source, wideTarget);
+}
+void Recoder::Create(const CodePage& page, wchar32 (*mapfunc)(wchar32)) {
+ const Encoder* widePage = &EncoderByCharset(page.CPEnum);
+ Create(page, widePage, mapfunc);
+}
+
+template <class T, class T1>
+static inline T1 Apply(T b, T e, T1 to, const Recoder& mapper) {
+ while (b != e) {
+ *to++ = mapper.Table[(unsigned char)*b++];
+ }
+
+ return to;
+}
+
+template <class T, class T1>
+static inline T1 Apply(T b, T1 to, const Recoder& mapper) {
+ while (*b != 0) {
+ *to++ = mapper.Table[(unsigned char)*b++];
+ }
+
+ return to;
+}
+
+char* CodePage::ToLower(const char* b, const char* e, char* to) const {
+ return Apply(b, e, to, TCodePageData::rcdr_to_lower[CPEnum]);
+}
+char* CodePage::ToLower(const char* b, char* to) const {
+ return Apply(b, to, TCodePageData::rcdr_to_lower[CPEnum]);
+}
+
+char* CodePage::ToUpper(const char* b, const char* e, char* to) const {
+ return Apply(b, e, to, TCodePageData::rcdr_to_upper[CPEnum]);
+}
+char* CodePage::ToUpper(const char* b, char* to) const {
+ return Apply(b, to, TCodePageData::rcdr_to_upper[CPEnum]);
+}
+
+int CodePage::stricmp(const char* dst, const char* src) const {
+ unsigned char f, l;
+ do {
+ f = ToLower(*dst++);
+ l = ToLower(*src++);
+ } while (f && (f == l));
+ return f - l;
+}
+
+int CodePage::strnicmp(const char* dst, const char* src, size_t len) const {
+ unsigned char f, l;
+ if (len) {
+ do {
+ f = ToLower(*dst++);
+ l = ToLower(*src++);
+ } while (--len && f && (f == l));
+ return f - l;
+ }
+ return 0;
+}
+
+static const CodePage UNSUPPORTED_CODEPAGE = {
+ CODES_UNSUPPORTED,
+ {
+ "unsupported",
+ },
+ {},
+ nullptr,
+};
+
+static const CodePage UNKNOWN_CODEPAGE = {
+ CODES_UNKNOWN,
+ {
+ "unknown",
+ },
+ {},
+ nullptr,
+};
+
+void NCodepagePrivate::TCodepagesMap::SetData(const CodePage* cp) {
+ Y_ASSERT(cp);
+ int code = static_cast<int>(cp->CPEnum) + DataShift;
+
+ Y_ASSERT(code >= 0 && code < DataSize);
+ Y_ASSERT(Data[code] == nullptr);
+
+ Data[code] = cp;
+}
+
+NCodepagePrivate::TCodepagesMap::TCodepagesMap() {
+ memset(Data, 0, sizeof(const CodePage*) * DataSize);
+ SetData(&UNSUPPORTED_CODEPAGE);
+ SetData(&UNKNOWN_CODEPAGE);
+
+ for (size_t i = 0; i != CODES_MAX; ++i) {
+ SetData(TCodePageData::AllCodePages[i]);
+ }
+}
+
+const NCodepagePrivate::TCodepagesMap& NCodepagePrivate::TCodepagesMap::Instance() {
+ return *Singleton<NCodepagePrivate::TCodepagesMap>();
+}
+
+class TCodePageHash {
+private:
+ using TData = THashMap<TStringBuf, ECharset, ci_hash, ci_equal_to>;
+
+ TData Data;
+ TMemoryPool Pool;
+
+private:
+ inline void AddNameWithCheck(const TString& name, ECharset code) {
+ if (Data.find(name.c_str()) == Data.end()) {
+ Data.insert(TData::value_type(Pool.Append(name.data(), name.size() + 1), code));
+ } else {
+ Y_ASSERT(Data.find(name.c_str())->second == code);
+ }
+ }
+
+ inline void AddName(const TString& name, ECharset code) {
+ AddNameWithCheck(name, code);
+
+ TString temp = name;
+ RemoveAll(temp, '-');
+ RemoveAll(temp, '_');
+ AddNameWithCheck(temp, code);
+
+ temp = name;
+ SubstGlobal(temp, '-', '_');
+ AddNameWithCheck(temp, code);
+
+ temp = name;
+ SubstGlobal(temp, '_', '-');
+ AddNameWithCheck(temp, code);
+ }
+
+public:
+ inline TCodePageHash()
+ : Pool(20 * 1024) /* Currently used: 17KB. */
+ {
+ TString xPrefix = "x-";
+ const char* name;
+
+ for (size_t i = 0; i != CODES_MAX; ++i) {
+ ECharset e = static_cast<ECharset>(i);
+ const CodePage* page = Singleton<NCodepagePrivate::TCodepagesMap>()->GetPrivate(e);
+
+ AddName(ToString(static_cast<int>(i)), e);
+
+ for (size_t j = 0; (name = page->Names[j]) != nullptr && name[0]; ++j) {
+ AddName(name, e);
+
+ AddName(xPrefix + name, e);
+ }
+ }
+ }
+
+ inline ECharset CharsetByName(TStringBuf name) {
+ if (!name)
+ return CODES_UNKNOWN;
+
+ TData::const_iterator it = Data.find(name);
+ if (it == Data.end())
+ return CODES_UNKNOWN;
+
+ return it->second;
+ }
+};
+
+ECharset CharsetByName(TStringBuf name) {
+ return Singleton<TCodePageHash>()->CharsetByName(name);
+}
+
+ECharset CharsetByNameOrDie(TStringBuf name) {
+ ECharset result = CharsetByName(name);
+ if (result == CODES_UNKNOWN)
+ ythrow yexception() << "CharsetByNameOrDie: unknown charset '" << name << "'";
+ return result;
+}
+
+template <typename TxChar>
+static inline RECODE_RESULT utf8_read_rune_from_unknown_plane(TxChar& rune, size_t& rune_len, const TxChar* s, const TxChar* end) {
+ if ((*s & 0xFF00) != 0xF000) {
+ rune_len = 1;
+ rune = *s;
+ return RECODE_OK;
+ }
+
+ rune_len = 0;
+
+ size_t _len = UTF8RuneLen((unsigned char)(*s));
+ if (s + _len > end)
+ return RECODE_EOINPUT; //[EOINPUT]
+ if (_len == 0)
+ return RECODE_BROKENSYMBOL; //[BROKENSYMBOL] in first byte
+
+ wchar32 _rune = (ui8)(*s++); //[00000000 0XXXXXXX]
+ if (_len > 1) {
+ _rune &= UTF8LeadByteMask(_len);
+ wchar32 ch = *s++;
+ if ((ch & 0xFFC0) != 0xF080)
+ return RECODE_BROKENSYMBOL; //[BROKENSYMBOL] in second byte
+ _rune <<= 6;
+ _rune |= ch & 0x3F; //[00000XXX XXYYYYYY]
+ if (_len > 2) {
+ ch = *s++;
+ if ((ch & 0xFFC0) != 0xF080)
+ return RECODE_BROKENSYMBOL; //[BROKENSYMBOL] in third byte
+ _rune <<= 6;
+ _rune |= ch & 0x3F; //[XXXXYYYY YYZZZZZZ]
+ if (_len > 3) {
+ ch = *s;
+ if ((ch & 0xFFC0) != 0xF080)
+ return RECODE_BROKENSYMBOL; //[BROKENSYMBOL] in fourth byte
+ _rune <<= 6;
+ _rune |= ch & 0x3F; //[XXXYY YYYYZZZZ ZZQQQQQQ]
+ }
+ }
+ }
+ rune_len = _len;
+ if (_rune > Max<TxChar>())
+ rune = ' '; // maybe put sequence
+ else
+ rune = TxChar(_rune);
+ return RECODE_OK;
+}
+
+template <typename TxChar>
+void DoDecodeUnknownPlane(TxChar* str, TxChar*& ee, const ECharset enc) {
+ TxChar* e = ee;
+ if (SingleByteCodepage(enc)) {
+ const CodePage* cp = CodePageByCharset(enc);
+ for (TxChar* s = str; s < e; s++) {
+ if (Hi8(Lo16(*s)) == 0xF0)
+ *s = (TxChar)cp->unicode[Lo8(Lo16(*s))]; // NOT mb compliant
+ }
+ } else if (enc == CODES_UTF8) {
+ TxChar* s;
+ TxChar* d;
+
+ for (s = d = str; s < e;) {
+ size_t l = 0;
+
+ if (utf8_read_rune_from_unknown_plane(*d, l, s, e) == RECODE_OK) {
+ d++, s += l;
+ } else {
+ *d++ = BROKEN_RUNE;
+ ++s;
+ }
+ }
+ e = d;
+ } else if (enc == CODES_UNKNOWN) {
+ for (TxChar* s = str; s < e; s++) {
+ if (Hi8(Lo16(*s)) == 0xF0)
+ *s = Lo8(Lo16(*s));
+ }
+ } else {
+ Y_ASSERT(!SingleByteCodepage(enc));
+
+ TxChar* s = str;
+ TxChar* d = str;
+
+ TVector<char> buf;
+
+ size_t read = 0;
+ size_t written = 0;
+ for (; s < e; ++s) {
+ if (Hi8(Lo16(*s)) == 0xF0) {
+ buf.push_back(Lo8(Lo16(*s)));
+ } else {
+ if (!buf.empty()) {
+ if (RecodeToUnicode(enc, buf.data(), d, buf.size(), e - d, read, written) == RECODE_OK) {
+ Y_ASSERT(read == buf.size());
+ d += written;
+ } else { // just copying broken symbols
+ Y_ASSERT(buf.size() <= static_cast<size_t>(e - d));
+ Copy(buf.data(), buf.size(), d);
+ d += buf.size();
+ }
+ buf.clear();
+ }
+ *d++ = *s;
+ }
+ }
+ }
+ ee = e;
+}
+
+void DecodeUnknownPlane(wchar16* str, wchar16*& ee, const ECharset enc) {
+ DoDecodeUnknownPlane(str, ee, enc);
+}
+void DecodeUnknownPlane(wchar32* str, wchar32*& ee, const ECharset enc) {
+ DoDecodeUnknownPlane(str, ee, enc);
+}
+
+namespace {
+ class THashSetType: public THashSet<TString> {
+ public:
+ inline void Add(const TString& s) {
+ insert(s);
+ }
+
+ inline bool Has(const TString& s) const noexcept {
+ return find(s) != end();
+ }
+ };
+}
+
+class TWindowsPrefixesHashSet: public THashSetType {
+public:
+ inline TWindowsPrefixesHashSet() {
+ Add("win");
+ Add("wincp");
+ Add("window");
+ Add("windowcp");
+ Add("windows");
+ Add("windowscp");
+ Add("ansi");
+ Add("ansicp");
+ }
+};
+
+class TCpPrefixesHashSet: public THashSetType {
+public:
+ inline TCpPrefixesHashSet() {
+ Add("microsoft");
+ Add("microsoftcp");
+ Add("cp");
+ }
+};
+
+class TIsoPrefixesHashSet: public THashSetType {
+public:
+ inline TIsoPrefixesHashSet() {
+ Add("iso");
+ Add("isolatin");
+ Add("latin");
+ }
+};
+
+class TLatinToIsoHash: public THashMap<const char*, TString, ci_hash, ci_equal_to> {
+public:
+ inline TLatinToIsoHash() {
+ insert(value_type("latin1", "iso-8859-1"));
+ insert(value_type("latin2", "iso-8859-2"));
+ insert(value_type("latin3", "iso-8859-3"));
+ insert(value_type("latin4", "iso-8859-4"));
+ insert(value_type("latin5", "iso-8859-9"));
+ insert(value_type("latin6", "iso-8859-10"));
+ insert(value_type("latin7", "iso-8859-13"));
+ insert(value_type("latin8", "iso-8859-14"));
+ insert(value_type("latin9", "iso-8859-15"));
+ insert(value_type("latin10", "iso-8859-16"));
+ }
+};
+
+static inline void NormalizeEncodingPrefixes(TString& enc) {
+ size_t preflen = enc.find_first_of("0123456789");
+ if (preflen == TString::npos)
+ return;
+
+ TString prefix = enc.substr(0, preflen);
+ for (size_t i = 0; i < prefix.length(); ++i) {
+ if (prefix[i] == '-') {
+ prefix.remove(i--);
+ }
+ }
+
+ if (Singleton<TWindowsPrefixesHashSet>()->Has(prefix)) {
+ enc.remove(0, preflen);
+ enc.prepend("windows-");
+ return;
+ }
+
+ if (Singleton<TCpPrefixesHashSet>()->Has(prefix)) {
+ if (enc.length() > preflen + 3 && !strncmp(enc.c_str() + preflen, "125", 3) && isdigit(enc[preflen + 3])) {
+ enc.remove(0, preflen);
+ enc.prepend("windows-");
+ return;
+ }
+ enc.remove(0, preflen);
+ enc.prepend("cp");
+ return;
+ }
+
+ if (Singleton<TIsoPrefixesHashSet>()->Has(prefix)) {
+ if (enc.length() == preflen + 1 || enc.length() == preflen + 2) {
+ TString enccopy = enc.substr(preflen);
+ enccopy.prepend("latin");
+ const TLatinToIsoHash* latinhash = Singleton<TLatinToIsoHash>();
+ TLatinToIsoHash::const_iterator it = latinhash->find(enccopy.data());
+ if (it != latinhash->end())
+ enc.assign(it->second);
+ return;
+ } else if (enc.length() > preflen + 5 && enc[preflen] == '8') {
+ enc.remove(0, preflen);
+ enc.prepend("iso-");
+ return;
+ }
+ }
+}
+
+class TEncodingNamesHashSet: public THashSetType {
+public:
+ TEncodingNamesHashSet() {
+ Add("iso-8859-1");
+ Add("iso-8859-2");
+ Add("iso-8859-3");
+ Add("iso-8859-4");
+ Add("iso-8859-5");
+ Add("iso-8859-6");
+ Add("iso-8859-7");
+ Add("iso-8859-8");
+ Add("iso-8859-8-i");
+ Add("iso-8859-9");
+ Add("iso-8859-10");
+ Add("iso-8859-11");
+ Add("iso-8859-12");
+ Add("iso-8859-13");
+ Add("iso-8859-14");
+ Add("iso-8859-15");
+ Add("windows-1250");
+ Add("windows-1251");
+ Add("windows-1252");
+ Add("windows-1253");
+ Add("windows-1254");
+ Add("windows-1255");
+ Add("windows-1256");
+ Add("windows-1257");
+ Add("windows-1258");
+ Add("windows-874");
+ Add("iso-2022-jp");
+ Add("euc-jp");
+ Add("shift-jis");
+ Add("shiftjis");
+ Add("iso-2022-kr");
+ Add("euc-kr");
+ Add("gb-2312");
+ Add("gb2312");
+ Add("gb-18030");
+ Add("gb18030");
+ Add("gbk");
+ Add("big5");
+ Add("tis-620");
+ Add("tis620");
+ }
+};
+
+ECharset EncodingHintByName(const char* encname) {
+ if (!encname)
+ return CODES_UNKNOWN; // safety check
+
+ // Common trouble: spurious "charset=" in the encoding name
+ if (!strnicmp(encname, "charset=", 8)) {
+ encname += 8;
+ }
+
+ // Strip everything up to the first alphanumeric, and after the last one
+ while (*encname && !isalnum(*encname))
+ ++encname;
+
+ if (!*encname)
+ return CODES_UNKNOWN;
+
+ const char* lastpos = encname + strlen(encname) - 1;
+ while (lastpos > encname && !isalnum(*lastpos))
+ --lastpos;
+
+ // Do some normalization
+ TString enc(encname, lastpos - encname + 1);
+ enc.to_lower();
+ for (char* p = enc.begin(); p != enc.end(); ++p) {
+ if (*p == ' ' || *p == '=' || *p == '_')
+ *p = '-';
+ }
+
+ NormalizeEncodingPrefixes(enc);
+
+ ECharset hint = CharsetByName(enc.c_str());
+ if (hint != CODES_UNKNOWN)
+ return hint;
+
+ if (Singleton<TEncodingNamesHashSet>()->Has(enc))
+ return CODES_UNSUPPORTED;
+ return CODES_UNKNOWN;
+}
diff --git a/library/cpp/charset/codepage.h b/library/cpp/charset/codepage.h
new file mode 100644
index 0000000000..30a02a4610
--- /dev/null
+++ b/library/cpp/charset/codepage.h
@@ -0,0 +1,324 @@
+#pragma once
+
+#include "doccodes.h"
+
+#include <util/charset/recode_result.h>
+#include <util/charset/unidata.h> // all wchar32 functions
+#include <util/charset/utf8.h>
+#include <util/generic/string.h>
+#include <util/generic/ylimits.h>
+#include <util/generic/yexception.h>
+#include <util/system/yassert.h>
+#include <util/system/defaults.h>
+
+#include <cctype>
+
+struct CodePage;
+struct Recoder;
+struct Encoder;
+
+/*****************************************************************\
+* struct CodePage *
+\*****************************************************************/
+struct CodePage {
+ ECharset CPEnum; // int MIBEnum;
+ const char* Names[30]; // name[0] -- preferred mime-name
+ wchar32 unicode[256];
+ const char* DefaultChar; //[CCL_NUM]
+
+ bool IsLower(unsigned char ch) const {
+ return ::IsLower(unicode[ch]);
+ }
+ bool IsUpper(unsigned char ch) const {
+ return ::IsUpper(unicode[ch]);
+ }
+ bool IsAlpha(unsigned char ch) const {
+ return ::IsAlpha(unicode[ch]);
+ }
+ bool IsDigit(unsigned char ch) const {
+ return ::IsDigit(unicode[ch]);
+ }
+ bool IsXdigit(unsigned char ch) const {
+ return ::IsXdigit(unicode[ch]);
+ }
+ bool IsAlnum(unsigned char ch) const {
+ return ::IsAlnum(unicode[ch]);
+ }
+ bool IsSpace(unsigned char ch) const {
+ return ::IsSpace(unicode[ch]);
+ }
+ bool IsPunct(unsigned char ch) const {
+ return ::IsPunct(unicode[ch]);
+ }
+ bool IsCntrl(unsigned char ch) const {
+ return ::IsCntrl(unicode[ch]);
+ }
+ bool IsGraph(unsigned char ch) const {
+ return ::IsGraph(unicode[ch]);
+ }
+ bool IsPrint(unsigned char ch) const {
+ return ::IsPrint(unicode[ch]);
+ }
+ bool IsComposed(unsigned char ch) const {
+ return ::IsComposed(unicode[ch]);
+ }
+
+ // return pointer to char after the last char
+ char* ToLower(const char* begin, const char* end, char* to) const;
+ char* ToLower(const char* begin, char* to) const;
+
+ // return pointer to char after the last char
+ char* ToUpper(const char* begin, const char* end, char* to) const;
+ char* ToUpper(const char* begin, char* to) const;
+
+ int stricmp(const char* s1, const char* s2) const;
+ int strnicmp(const char* s1, const char* s2, size_t len) const;
+
+ inline unsigned char ToUpper(unsigned char ch) const;
+ inline unsigned char ToLower(unsigned char ch) const;
+ inline unsigned char ToTitle(unsigned char ch) const;
+
+ inline int ToDigit(unsigned char ch) const {
+ return ::ToDigit(unicode[ch]);
+ }
+
+ static void Initialize();
+
+ inline bool SingleByteCodepage() const {
+ return DefaultChar != nullptr;
+ }
+ inline bool NativeCodepage() const {
+ return SingleByteCodepage() || CPEnum == CODES_UTF8;
+ }
+};
+
+class TCodePageHash;
+
+namespace NCodepagePrivate {
+ class TCodepagesMap {
+ private:
+ static const int DataShift = 2;
+ static const int DataSize = CODES_MAX + DataShift;
+ const CodePage* Data[DataSize];
+
+ private:
+ inline const CodePage* GetPrivate(ECharset e) const {
+ Y_ASSERT(e + DataShift >= 0 && e + DataShift < DataSize);
+ return Data[e + DataShift];
+ }
+
+ void SetData(const CodePage* cp);
+
+ public:
+ TCodepagesMap();
+
+ inline const CodePage* Get(ECharset e) const {
+ const CodePage* res = GetPrivate(e);
+ if (!res->SingleByteCodepage()) {
+ ythrow yexception() << "CodePage (" << (int)e << ") structure can only be used for single byte encodings";
+ }
+
+ return res;
+ }
+
+ inline bool SingleByteCodepage(ECharset e) const {
+ return GetPrivate(e)->SingleByteCodepage();
+ }
+ inline bool NativeCodepage(ECharset e) const {
+ return GetPrivate(e)->NativeCodepage();
+ }
+ inline const char* NameByCharset(ECharset e) const {
+ return GetPrivate(e)->Names[0];
+ }
+
+ static const TCodepagesMap& Instance();
+
+ friend class ::TCodePageHash;
+ };
+
+ inline bool NativeCodepage(ECharset e) {
+ return ::NCodepagePrivate::TCodepagesMap::Instance().NativeCodepage(e);
+ }
+}
+
+inline bool SingleByteCodepage(ECharset e) {
+ return ::NCodepagePrivate::TCodepagesMap::Instance().SingleByteCodepage(e);
+}
+
+inline bool ValidCodepage(ECharset e) {
+ return e >= 0 && e < CODES_MAX;
+}
+
+inline const CodePage* CodePageByCharset(ECharset e) {
+ return ::NCodepagePrivate::TCodepagesMap::Instance().Get(e);
+}
+
+ECharset CharsetByName(TStringBuf name);
+
+// Same as CharsetByName, but throws yexception() if name is invalid
+ECharset CharsetByNameOrDie(TStringBuf name);
+
+inline ECharset CharsetByCodePage(const CodePage* CP) {
+ return CP->CPEnum;
+}
+
+inline const char* NameByCharset(ECharset e) {
+ return ::NCodepagePrivate::TCodepagesMap::Instance().NameByCharset(e);
+}
+
+inline const char* NameByCharsetSafe(ECharset e) {
+ if (CODES_UNKNOWN < e && e < CODES_MAX)
+ return ::NCodepagePrivate::TCodepagesMap::Instance().NameByCharset(e);
+ else
+ ythrow yexception() << "unknown encoding: " << (int)e;
+}
+
+inline const char* NameByCodePage(const CodePage* CP) {
+ return CP->Names[0];
+}
+
+inline const CodePage* CodePageByName(const char* name) {
+ ECharset code = CharsetByName(name);
+ if (code == CODES_UNKNOWN)
+ return nullptr;
+
+ return CodePageByCharset(code);
+}
+
+ECharset EncodingHintByName(const char* name);
+
+/*****************************************************************\
+* struct Encoder *
+\*****************************************************************/
+struct Encoder {
+ char* Table[256];
+ const char* DefaultChar;
+
+ inline char Code(wchar32 ch) const {
+ if (ch > 0xFFFF)
+ return 0;
+ return (unsigned char)Table[(ch >> 8) & 255][ch & 255];
+ }
+
+ inline char Tr(wchar32 ch) const {
+ char code = Code(ch);
+ if (code == 0 && ch != 0)
+ code = DefaultChar[NUnicode::CharType(ch)];
+ Y_ASSERT(code != 0 || ch == 0);
+ return code;
+ }
+
+ inline unsigned char operator[](wchar32 ch) const {
+ return Tr(ch);
+ }
+
+ void Tr(const wchar32* in, char* out, size_t len) const;
+ void Tr(const wchar32* in, char* out) const;
+ char* DefaultPlane;
+};
+
+/*****************************************************************\
+* struct Recoder *
+\*****************************************************************/
+struct Recoder {
+ unsigned char Table[257];
+
+ void Create(const CodePage& source, const CodePage& target);
+ void Create(const CodePage& source, const Encoder* wideTarget);
+
+ void Create(const CodePage& page, wchar32 (*mapper)(wchar32));
+ void Create(const CodePage& page, const Encoder* widePage, wchar32 (*mapper)(wchar32));
+
+ inline unsigned char Tr(unsigned char c) const {
+ return Table[c];
+ }
+ inline unsigned char operator[](unsigned char c) const {
+ return Table[c];
+ }
+ void Tr(const char* in, char* out, size_t len) const;
+ void Tr(const char* in, char* out) const;
+ void Tr(char* in_out, size_t len) const;
+ void Tr(char* in_out) const;
+};
+
+extern const struct Encoder& WideCharToYandex;
+
+const Encoder& EncoderByCharset(ECharset enc);
+
+namespace NCodepagePrivate {
+ class TCodePageData {
+ private:
+ static const CodePage* const AllCodePages[];
+
+ static const Recoder rcdr_to_yandex[];
+ static const Recoder rcdr_from_yandex[];
+ static const Recoder rcdr_to_lower[];
+ static const Recoder rcdr_to_upper[];
+ static const Recoder rcdr_to_title[];
+
+ static const Encoder* const EncodeTo[];
+
+ friend struct ::CodePage;
+ friend class TCodepagesMap;
+ friend RECODE_RESULT _recodeToYandex(ECharset, const char*, char*, size_t, size_t, size_t&, size_t&);
+ friend RECODE_RESULT _recodeFromYandex(ECharset, const char*, char*, size_t, size_t, size_t&, size_t&);
+ friend const Encoder& ::EncoderByCharset(ECharset enc);
+ };
+}
+
+inline const Encoder& EncoderByCharset(ECharset enc) {
+ if (!SingleByteCodepage(enc)) {
+ ythrow yexception() << "Encoder structure can only be used for single byte encodings";
+ }
+
+ return *NCodepagePrivate::TCodePageData::EncodeTo[enc];
+}
+
+inline unsigned char CodePage::ToUpper(unsigned char ch) const {
+ return NCodepagePrivate::TCodePageData::rcdr_to_upper[CPEnum].Table[ch];
+}
+inline unsigned char CodePage::ToLower(unsigned char ch) const {
+ return NCodepagePrivate::TCodePageData::rcdr_to_lower[CPEnum].Table[ch];
+}
+inline unsigned char CodePage::ToTitle(unsigned char ch) const {
+ return NCodepagePrivate::TCodePageData::rcdr_to_title[CPEnum].Table[ch];
+}
+
+extern const CodePage& csYandex;
+
+/// these functions change (lowers) [end] position in case of utf-8
+/// null character is NOT assumed or written at [*end]
+void DecodeUnknownPlane(wchar16* start, wchar16*& end, const ECharset enc4unk);
+void DecodeUnknownPlane(wchar32* start, wchar32*& end, const ECharset enc4unk);
+
+inline void ToLower(char* s, size_t n, const CodePage& cp = csYandex) {
+ char* const e = s + n;
+ for (; s != e; ++s)
+ *s = cp.ToLower(*s);
+}
+
+inline void ToUpper(char* s, size_t n, const CodePage& cp = csYandex) {
+ char* const e = s + n;
+ for (; s != e; ++s)
+ *s = cp.ToUpper(*s);
+}
+
+inline TString ToLower(TString s, const CodePage& cp, size_t pos = 0, size_t n = TString::npos) {
+ s.Transform([&cp](size_t, char c) { return cp.ToLower(c); }, pos, n);
+ return s;
+}
+
+inline TString ToUpper(TString s, const CodePage& cp, size_t pos = 0, size_t n = TString::npos) {
+ s.Transform([&cp](size_t, char c) { return cp.ToUpper(c); }, pos, n);
+ return s;
+}
+
+inline TString ToTitle(TString s, const CodePage& cp, size_t pos = 0, size_t n = TString::npos) {
+ s.Transform(
+ [pos, &cp](size_t i, char c) {
+ return i == pos ? cp.ToTitle(c) : cp.ToLower(c);
+ },
+ pos,
+ n);
+ return s;
+}
diff --git a/library/cpp/charset/codepage_ut.cpp b/library/cpp/charset/codepage_ut.cpp
new file mode 100644
index 0000000000..c3ac3ac478
--- /dev/null
+++ b/library/cpp/charset/codepage_ut.cpp
@@ -0,0 +1,424 @@
+#include "codepage.h"
+#include "recyr.hh"
+#include "wide.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/charset/utf8.h>
+#include <util/system/yassert.h>
+
+#if defined(_MSC_VER)
+#pragma warning(disable : 4309) /*truncation of constant value*/
+#endif
+
+namespace {
+ const char yandexUpperCase[] =
+ "\x81\x82\x83\x84\x85\x86\x87"
+ "\x8E"
+ "\xA1\xA2\xA3\xA4\xA5\xA6"
+ "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF"
+ "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF"
+ "\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF";
+
+ const char yandexLowerCase[] =
+ "\x91\x92\x93\x94\x95\x96\x97"
+ "\x9E"
+ "\xB1\xB2\xB3\xB4\xB5\xB6"
+ "\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF"
+ "\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF"
+ "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";
+}
+
+class TCodepageTest: public TTestBase {
+private:
+ UNIT_TEST_SUITE(TCodepageTest);
+ UNIT_TEST(TestUTF);
+ UNIT_TEST(TestUTFFromUnknownPlane);
+ UNIT_TEST(TestBrokenMultibyte);
+ UNIT_TEST(TestSurrogatePairs);
+ UNIT_TEST(TestEncodingHints);
+ UNIT_TEST(TestToLower);
+ UNIT_TEST(TestToUpper);
+ UNIT_TEST(TestUpperLower);
+ UNIT_TEST(TestBrokenRune);
+ UNIT_TEST(TestCanEncode);
+ UNIT_TEST_SUITE_END();
+
+public:
+ void TestUTF();
+ void TestUTFFromUnknownPlane();
+ void TestBrokenMultibyte();
+ void TestSurrogatePairs();
+ void TestEncodingHints();
+ void TestToLower();
+ void TestToUpper();
+
+ void TestCanEncode();
+
+ inline void TestUpperLower() {
+ const CodePage* cp = CodePageByCharset(CODES_ASCII);
+ char tmp[100];
+
+ TStringBuf s = "abcde";
+
+ TStringBuf upper(tmp, cp->ToUpper(s.begin(), s.end(), tmp));
+ UNIT_ASSERT_VALUES_EQUAL(upper, TStringBuf("ABCDE"));
+
+ TStringBuf lower(tmp, cp->ToLower(upper.begin(), upper.end(), tmp));
+ UNIT_ASSERT_VALUES_EQUAL(lower, TStringBuf("abcde"));
+ }
+
+ void TestBrokenRune() {
+ UNIT_ASSERT_VALUES_EQUAL(BROKEN_RUNE, 0xFFFDu);
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TCodepageTest);
+
+void TCodepageTest::TestUTF() {
+ for (wchar32 i = 0; i <= 0x10FFFF; i++) {
+ unsigned char buffer[32];
+ Zero(buffer);
+ size_t rune_len;
+ size_t ref_len = 0;
+
+ if (i < 0x80)
+ ref_len = 1;
+ else if (i < 0x800)
+ ref_len = 2;
+ else if (i < 0x10000)
+ ref_len = 3;
+ else
+ ref_len = 4;
+
+ RECODE_RESULT res = SafeWriteUTF8Char(i, rune_len, buffer, buffer + 32);
+ UNIT_ASSERT(res == RECODE_OK);
+ UNIT_ASSERT(rune_len == ref_len);
+
+ res = SafeWriteUTF8Char(i, rune_len, buffer, buffer + ref_len - 1);
+ UNIT_ASSERT(res == RECODE_EOOUTPUT);
+
+ wchar32 rune;
+ res = SafeReadUTF8Char(rune, rune_len, buffer, buffer + 32);
+ UNIT_ASSERT(res == RECODE_OK);
+ UNIT_ASSERT(rune == i);
+ UNIT_ASSERT(rune_len == ref_len);
+
+ res = SafeReadUTF8Char(rune, rune_len, buffer, buffer + ref_len - 1);
+ UNIT_ASSERT(res == RECODE_EOINPUT);
+
+ if (ref_len > 1) {
+ res = SafeReadUTF8Char(rune, rune_len, buffer + 1, buffer + ref_len);
+ UNIT_ASSERT(res == RECODE_BROKENSYMBOL);
+
+ buffer[1] |= 0xC0;
+ res = SafeReadUTF8Char(rune, rune_len, buffer, buffer + ref_len);
+ UNIT_ASSERT(res == RECODE_BROKENSYMBOL);
+
+ buffer[1] &= 0x3F;
+ res = SafeReadUTF8Char(rune, rune_len, buffer, buffer + ref_len);
+ UNIT_ASSERT(res == RECODE_BROKENSYMBOL);
+ }
+ }
+ const char* badStrings[] = {
+ "\xfe",
+ "\xff",
+ "\xcc\xc0",
+ "\xf4\x90\x80\x80",
+ //overlong:
+ "\xfe\xfe\xff\xff",
+ "\xc0\xaf",
+ "\xe0\x80\xaf",
+ "\xf0\x80\x80\xaf",
+ "\xf8\x80\x80\x80\xaf",
+ "\xfc\x80\x80\x80\x80\xaf",
+ "\xc1\xbf",
+ "\xe0\x9f\xbf",
+ "\xf0\x8f\xbf\xbf",
+ "\xf8\x87\xbf\xbf\xbf",
+ "\xfc\x83\xbf\xbf\xbf\xbf",
+ "\xc0\x80",
+ "\xe0\x80\x80",
+ "\xf0\x80\x80\x80",
+ "\xf8\x80\x80\x80\x80",
+ "\xfc\x80\x80\x80\x80\x80",
+ //UTF-16 surrogate (not covered):
+ //"\xed\xa0\x80",
+ //"\xed\xad\xbf",
+ //"\xed\xae\x80",
+ //"\xed\xaf\xbf",
+ //"\xed\xb0\x80",
+ //"\xed\xbe\x80",
+ //"\xed\xbf\xbf",
+ };
+ for (size_t i = 0; i < Y_ARRAY_SIZE(badStrings); ++i) {
+ wchar32 rune;
+ const ui8* p = (const ui8*)badStrings[i];
+ size_t len;
+ RECODE_RESULT res = SafeReadUTF8Char(rune, len, p, p + strlen(badStrings[i]));
+ UNIT_ASSERT(res == RECODE_BROKENSYMBOL);
+ }
+}
+
+void TCodepageTest::TestBrokenMultibyte() {
+ const ECharset cp = CODES_EUC_JP;
+
+ const char sampletext[] = {'\xe3'};
+ wchar32 recodeResult[100];
+
+ size_t nwritten = 0;
+ size_t nread = 0;
+
+ RECODE_RESULT res = RecodeToUnicode(cp, sampletext, recodeResult, Y_ARRAY_SIZE(sampletext), Y_ARRAY_SIZE(recodeResult), nread, nwritten);
+ UNIT_ASSERT(res == RECODE_OK);
+ UNIT_ASSERT(nread == 1);
+ UNIT_ASSERT(nwritten == 0);
+
+ const char bigSample[] = {'\xC3', '\x87', '\xC3', '\x8E', '\xC2', '\xB0', '\xC3', '\x85', '\xC3', '\x85', '\xC3', '\xB8'};
+ res = RecodeToUnicode(cp, bigSample, recodeResult, Y_ARRAY_SIZE(bigSample), Y_ARRAY_SIZE(recodeResult), nread, nwritten);
+ UNIT_ASSERT(res == RECODE_OK);
+ UNIT_ASSERT(nread == Y_ARRAY_SIZE(bigSample));
+}
+
+void TCodepageTest::TestUTFFromUnknownPlane() {
+ static const wchar32 sampletext[] = {0x61, 0x62, 0x63, 0x20,
+ 0x430, 0x431, 0x432, 0x20,
+ 0x1001, 0x1002, 0x1003, 0x20,
+ 0x10001, 0x10002, 0x10003};
+
+ static const size_t BUFFER_SIZE = 1024;
+ char bytebuffer[BUFFER_SIZE];
+
+ size_t readchars = 0;
+ size_t writtenbytes = 0;
+ size_t samplelen = Y_ARRAY_SIZE(sampletext);
+
+ RECODE_RESULT res = RecodeFromUnicode(CODES_UTF8, sampletext, bytebuffer, samplelen, BUFFER_SIZE, readchars, writtenbytes);
+
+ UNIT_ASSERT(res == RECODE_OK);
+ UNIT_ASSERT(samplelen == readchars);
+
+ size_t writtenbytes2 = 0;
+ char bytebuffer2[BUFFER_SIZE];
+ for (size_t i = 0; i != samplelen; ++i) {
+ size_t nwr = 0;
+ const int res = RecodeFromUnicode(CODES_UTF8, sampletext[i], bytebuffer2 + writtenbytes2, BUFFER_SIZE - writtenbytes2, nwr);
+ UNIT_ASSERT_VALUES_EQUAL(res, int(RECODE_OK));
+ writtenbytes2 += nwr;
+ UNIT_ASSERT(BUFFER_SIZE > writtenbytes2);
+ }
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuf(bytebuffer, writtenbytes), TStringBuf(bytebuffer2, writtenbytes2));
+
+ wchar32 charbuffer[BUFFER_SIZE];
+ size_t readbytes = 0;
+ size_t writtenchars = 0;
+
+ res = RecodeToUnicode(CODES_UNKNOWNPLANE, bytebuffer, charbuffer, writtenbytes, BUFFER_SIZE, readbytes, writtenchars);
+
+ UNIT_ASSERT(res == RECODE_OK);
+ UNIT_ASSERT(readbytes == writtenbytes);
+
+ wchar32* charbufferend = charbuffer + writtenchars;
+ DecodeUnknownPlane(charbuffer, charbufferend, CODES_UTF8);
+
+ UNIT_ASSERT(charbufferend == charbuffer + samplelen);
+ for (size_t i = 0; i < samplelen; ++i)
+ UNIT_ASSERT(sampletext[i] == charbuffer[i]);
+
+ // Now, concatenate the thing with an explicit character and retest
+ res = RecodeToUnicode(CODES_UNKNOWNPLANE, bytebuffer, charbuffer, writtenbytes, BUFFER_SIZE, readbytes, writtenchars);
+ UNIT_ASSERT(res == RECODE_OK);
+ UNIT_ASSERT(readbytes == writtenbytes);
+
+ charbuffer[writtenchars] = 0x1234;
+
+ size_t morewrittenchars = 0;
+ res = RecodeToUnicode(CODES_UNKNOWNPLANE, bytebuffer, charbuffer + writtenchars + 1, writtenbytes, BUFFER_SIZE, readbytes, morewrittenchars);
+ UNIT_ASSERT(res == RECODE_OK);
+ UNIT_ASSERT(readbytes == writtenbytes);
+ UNIT_ASSERT(writtenchars == morewrittenchars);
+
+ charbuffer[2 * writtenchars + 1] = 0x5678;
+
+ charbufferend = charbuffer + 2 * writtenchars + 2;
+ DecodeUnknownPlane(charbuffer, charbufferend, CODES_UTF8);
+
+ UNIT_ASSERT(charbufferend == charbuffer + 2 * samplelen + 2);
+ for (size_t i = 0; i < samplelen; ++i) {
+ UNIT_ASSERT(sampletext[i] == charbuffer[i]);
+ UNIT_ASSERT(sampletext[i] == charbuffer[samplelen + 1 + i]);
+ }
+ UNIT_ASSERT(0x1234 == charbuffer[samplelen]);
+ UNIT_ASSERT(0x5678 == charbuffer[2 * samplelen + 1]);
+
+ // test TChar version
+ // bytebuffer of len writtenbytes contains sampletext of len samplelen chars in utf8
+ TUtf16String wtr = CharToWide(TStringBuf(bytebuffer, writtenbytes), CODES_UNKNOWNPLANE);
+ TChar* strend = wtr.begin() + wtr.size();
+ DecodeUnknownPlane(wtr.begin(), strend, CODES_UTF8);
+ wtr.resize(strend - wtr.data(), 'Q');
+ UNIT_ASSERT_VALUES_EQUAL(wtr.size(), samplelen);
+ for (size_t i = 0; i < wtr.size(); ++i) {
+ if (sampletext[i] >= 0x10000) {
+ UNIT_ASSERT_VALUES_EQUAL(wtr[i], ' ');
+ } else {
+ UNIT_ASSERT_VALUES_EQUAL(wtr[i], sampletext[i]);
+ }
+ }
+}
+
+static void TestSurrogates(const char* str, const wchar16* wide, size_t wideSize) {
+ size_t sSize = strlen(str);
+ size_t wSize = sSize * 2;
+ TArrayHolder<wchar16> w(new wchar16[wSize]);
+
+ size_t read = 0;
+ size_t written = 0;
+ RECODE_RESULT res = RecodeToUnicode(CODES_UTF8, str, w.Get(), sSize, wSize, read, written);
+ UNIT_ASSERT(res == RECODE_OK);
+ UNIT_ASSERT(read == sSize);
+ UNIT_ASSERT(written == wideSize);
+ UNIT_ASSERT(!memcmp(w.Get(), wide, wideSize));
+
+ TArrayHolder<char> s(new char[sSize]);
+ res = RecodeFromUnicode(CODES_UTF8, w.Get(), s.Get(), wideSize, sSize, read, written);
+ UNIT_ASSERT(res == RECODE_OK);
+ UNIT_ASSERT(read == wideSize);
+ UNIT_ASSERT(written == sSize);
+ UNIT_ASSERT(!memcmp(s.Get(), str, sSize));
+}
+
+void TCodepageTest::TestSurrogatePairs() {
+ const char* utf8NonBMP = "\xf4\x80\x89\x84\xf4\x80\x89\x87\xf4\x80\x88\xba";
+ wchar16 wNonBMPDummy[] = {0xDBC0, 0xDE44, 0xDBC0, 0xDE47, 0xDBC0, 0xDE3A};
+ TestSurrogates(utf8NonBMP, wNonBMPDummy, Y_ARRAY_SIZE(wNonBMPDummy));
+
+ const char* utf8NonBMP2 = "ab\xf4\x80\x89\x87n";
+ wchar16 wNonBMPDummy2[] = {'a', 'b', 0xDBC0, 0xDE47, 'n'};
+ TestSurrogates(utf8NonBMP2, wNonBMPDummy2, Y_ARRAY_SIZE(wNonBMPDummy2));
+}
+
+void TCodepageTest::TestEncodingHints() {
+ UNIT_ASSERT(CODES_WIN == EncodingHintByName("windows-1251"));
+ UNIT_ASSERT(CODES_WIN == EncodingHintByName("Windows1251"));
+ UNIT_ASSERT(CODES_WIN == EncodingHintByName("WIN1251"));
+ UNIT_ASSERT(CODES_WIN == EncodingHintByName("window-cp1251"));
+ UNIT_ASSERT(CODES_WIN == EncodingHintByName("!!!CP1251???"));
+ UNIT_ASSERT(CODES_WIN == EncodingHintByName("'ansi-cp1251;'"));
+ UNIT_ASSERT(CODES_WIN == EncodingHintByName("charset=Microsoft-CP1251;"));
+
+ UNIT_ASSERT(CODES_ISO_EAST == EncodingHintByName("iso-8859-2"));
+ UNIT_ASSERT(CODES_ISO_EAST == EncodingHintByName("iso-2"));
+ UNIT_ASSERT(CODES_ISO_EAST == EncodingHintByName("iso-latin-2"));
+ UNIT_ASSERT(CODES_ISO_EAST == EncodingHintByName("charset=\"Latin2\";"));
+
+ UNIT_ASSERT(CODES_UNKNOWN == EncodingHintByName("widow1251"));
+ UNIT_ASSERT(CODES_UNKNOWN == EncodingHintByName("default"));
+ UNIT_ASSERT(CODES_UNKNOWN == EncodingHintByName("$phpcharset"));
+
+ UNIT_ASSERT(CODES_UNSUPPORTED != EncodingHintByName("ShiftJIS"));
+ UNIT_ASSERT(CODES_UNSUPPORTED != EncodingHintByName("Shift_JIS"));
+ UNIT_ASSERT(CODES_UNSUPPORTED != EncodingHintByName("Big5"));
+ UNIT_ASSERT(CODES_UNSUPPORTED != EncodingHintByName("euc-kr"));
+ UNIT_ASSERT(CODES_UNSUPPORTED != EncodingHintByName("EUC-JP"));
+ UNIT_ASSERT(CODES_UNSUPPORTED != EncodingHintByName("charset='Shift_JIS';;"));
+ UNIT_ASSERT(CODES_UNSUPPORTED != EncodingHintByName("ISO-2022-KR"));
+ UNIT_ASSERT(CODES_UNSUPPORTED != EncodingHintByName("ISO-2022-jp"));
+}
+
+void TCodepageTest::TestToLower() {
+ TTempBuf buf;
+ char* data = buf.Data();
+ const size_t n = Y_ARRAY_SIZE(yandexUpperCase); // including NTS
+ memcpy(data, yandexUpperCase, n);
+ ToLower(data, n - 1);
+ UNIT_ASSERT(strcmp(data, yandexLowerCase) == 0);
+}
+
+void TCodepageTest::TestToUpper() {
+ TTempBuf buf;
+ char* data = buf.Data();
+ const size_t n = Y_ARRAY_SIZE(yandexLowerCase); // including NTS
+ memcpy(data, yandexLowerCase, n);
+ ToUpper(data, n - 1);
+ UNIT_ASSERT(strcmp(data, yandexUpperCase) == 0);
+}
+
+static void TestCanEncodeEmpty() {
+ TWtringBuf empty;
+ UNIT_ASSERT(CanBeEncoded(empty, CODES_WIN));
+ UNIT_ASSERT(CanBeEncoded(empty, CODES_YANDEX));
+ UNIT_ASSERT(CanBeEncoded(empty, CODES_UTF8));
+}
+
+static void TestCanEncodeEach(const TWtringBuf& text, ECharset encoding, bool expectedResult) {
+ // char by char
+ for (size_t i = 0; i < text.size(); ++i) {
+ if (CanBeEncoded(text.SubStr(i, 1), encoding) != expectedResult)
+ ythrow yexception() << "assertion failed: encoding " << NameByCharset(encoding)
+ << " on '" << text.SubStr(i, 1) << "' (expected " << expectedResult << ")";
+ }
+ // whole text
+ UNIT_ASSERT_EQUAL(CanBeEncoded(text, encoding), expectedResult);
+}
+
+void TCodepageTest::TestCanEncode() {
+ TestCanEncodeEmpty();
+
+ const TUtf16String lat = u"AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";
+ TestCanEncodeEach(lat, CODES_WIN, true);
+ TestCanEncodeEach(lat, CODES_YANDEX, true);
+ TestCanEncodeEach(lat, CODES_UTF8, true);
+
+ const TUtf16String rus = u"АаБбВвГгДдЕеЁёЖжЗзИиЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭэЮюЯя";
+ TestCanEncodeEach(rus, CODES_WIN, true);
+ TestCanEncodeEach(rus, CODES_YANDEX, true);
+ TestCanEncodeEach(rus, CODES_UTF8, true);
+
+ const TUtf16String ukr = u"ҐґЄєІіЇї";
+ TestCanEncodeEach(ukr, CODES_WIN, true);
+ TestCanEncodeEach(ukr, CODES_YANDEX, true);
+ TestCanEncodeEach(ukr, CODES_UTF8, true);
+
+ const TUtf16String pol = u"ĄĆĘŁŃÓŚŹŻąćęłńóśźż";
+ TestCanEncodeEach(pol, CODES_WIN, false);
+ TestCanEncodeEach(pol, CODES_YANDEX, true);
+ TestCanEncodeEach(pol, CODES_UTF_16BE, true);
+
+ const TUtf16String ger = u"ÄäÖöÜüß";
+ TestCanEncodeEach(ger, CODES_WIN, false);
+ TestCanEncodeEach(ger, CODES_YANDEX, true);
+ TestCanEncodeEach(ger, CODES_UTF_16LE, true);
+
+ const TUtf16String fra1 = u"éàèùâêîôûëïç"; // supported in yandex cp
+ const TUtf16String fra2 = u"ÉÀÈÙÂÊÎÔÛËÏŸÿÇ";
+ const TUtf16String fra3 = u"Æ挜";
+ TestCanEncodeEach(fra1 + fra2 + fra3, CODES_WIN, false);
+ TestCanEncodeEach(fra1, CODES_YANDEX, true);
+ TestCanEncodeEach(fra2 + fra3, CODES_YANDEX, false);
+ TestCanEncodeEach(fra1 + fra2 + fra3, CODES_UTF8, true);
+
+ const TUtf16String kaz = u"ӘәҒғҚқҢңӨөҰұҮүҺһ";
+ TestCanEncodeEach(kaz, CODES_WIN, false);
+ TestCanEncodeEach(kaz, CODES_YANDEX, false);
+ TestCanEncodeEach(kaz, CODES_UTF8, true);
+ TestCanEncodeEach(kaz, CODES_KAZWIN, true);
+
+ const TUtf16String tur1 = u"ĞİŞğş";
+ const TUtf16String tur = tur1 + u"ı";
+ TestCanEncodeEach(tur, CODES_WIN, false);
+ TestCanEncodeEach(tur, CODES_YANDEX, false);
+ TestCanEncodeEach(tur, CODES_UTF8, true);
+
+ const TUtf16String chi = u"新隶体新隸體";
+ TestCanEncodeEach(chi, CODES_WIN, false);
+ TestCanEncodeEach(chi, CODES_YANDEX, false);
+ TestCanEncodeEach(chi, CODES_UTF8, true);
+ TestCanEncodeEach(chi, CODES_UTF_16LE, true);
+
+ const TUtf16String jap = u"漢字仮字交じり文";
+ TestCanEncodeEach(jap, CODES_WIN, false);
+ TestCanEncodeEach(jap, CODES_YANDEX, false);
+ TestCanEncodeEach(jap, CODES_UTF8, true);
+ TestCanEncodeEach(jap, CODES_UTF_16BE, true);
+}
diff --git a/library/cpp/charset/cp_encrec.cpp b/library/cpp/charset/cp_encrec.cpp
new file mode 100644
index 0000000000..1334afaa90
--- /dev/null
+++ b/library/cpp/charset/cp_encrec.cpp
@@ -0,0 +1,54 @@
+#include "codepage.h"
+
+#include <util/string/cast.h>
+#include <util/stream/output.h>
+
+void Encoder::Tr(const wchar32* in, char* out, size_t len) const {
+ while (len--)
+ *out++ = Tr(*in++);
+}
+
+void Encoder::Tr(const wchar32* in, char* out) const {
+ do {
+ *out++ = Tr(*in);
+ } while (*in++);
+}
+
+void Recoder::Create(const CodePage& source, const Encoder* wideTarget) {
+ for (size_t i = 0; i != 256; ++i) {
+ Table[i] = wideTarget->Tr(source.unicode[i]);
+ Y_ASSERT(Table[i] != 0 || i == 0);
+ }
+}
+
+void Recoder::Create(const CodePage& page, const Encoder* widePage, wchar32 (*mapfunc)(wchar32)) {
+ for (size_t i = 0; i != 256; ++i) {
+ char c = widePage->Code((*mapfunc)(page.unicode[i]));
+ Table[i] = (c == 0 && i != 0) ? (unsigned char)i : (unsigned char)c;
+ }
+}
+
+void Recoder::Tr(const char* in, char* out, size_t len) const {
+ while (len--)
+ *out++ = Table[(unsigned char)*in++];
+}
+
+void Recoder::Tr(const char* in, char* out) const {
+ do {
+ *out++ = Table[(unsigned char)*in];
+ } while (*in++);
+}
+
+void Recoder::Tr(char* in_out, size_t len) const {
+ while (len--) {
+ *in_out = Table[(unsigned char)*in_out];
+ in_out++;
+ }
+}
+
+void Recoder::Tr(char* in_out) const {
+ // assuming that '\0' <--> '\0'
+ do {
+ *in_out = Table[(unsigned char)*in_out];
+ } while (*in_out++);
+}
diff --git a/library/cpp/charset/doccodes.cpp b/library/cpp/charset/doccodes.cpp
new file mode 100644
index 0000000000..1fc17a3275
--- /dev/null
+++ b/library/cpp/charset/doccodes.cpp
@@ -0,0 +1 @@
+#include "doccodes.h"
diff --git a/library/cpp/charset/doccodes.h b/library/cpp/charset/doccodes.h
new file mode 100644
index 0000000000..75c87adf9e
--- /dev/null
+++ b/library/cpp/charset/doccodes.h
@@ -0,0 +1,129 @@
+#pragma once
+
+enum ECharset {
+ CODES_UNSUPPORTED = -2, // valid but unsupported encoding
+ CODES_UNKNOWN = -1, // invalid or unspecified encoding
+ CODES_WIN, // [ 0] WINDOWS_1251 Windows
+ CODES_KOI8, // [ 1] KOI8_U Koi8-u
+ CODES_ALT, // [ 2] IBM_866 MS DOS, alternative
+ CODES_MAC, // [ 3] MAC_CYRILLIC Macintosh
+ CODES_MAIN, // [ 4] ISO_LATIN_CYRILLIC Main
+ CODES_ASCII, // [ 5] WINDOWS_1252 Latin 1
+ CODES_RESERVED_3, // reserved code: use it for new encodings before adding them to the end of the list
+ CODES_WIN_EAST, // [ 7] WINDOWS_1250 WIN PL
+ CODES_ISO_EAST, // [ 8] ISO_8859_2 ISO PL
+ // our superset of subset of windows-1251
+ CODES_YANDEX, // [ 9] YANDEX
+ CODES_UTF_16BE, // [10] UTF_16BE
+ CODES_UTF_16LE, // [11] UTF_16LE
+ // missing standard codepages
+ CODES_IBM855, // [12] IBM_855
+ CODES_UTF8, // [13] UTF8
+ CODES_UNKNOWNPLANE, // [14] Unrecognized characters are mapped into the PUA: U+F000..U+F0FF
+
+ CODES_KAZWIN, // [15] WINDOWS_1251_K Kazakh version of Windows-1251
+ CODES_TATWIN, // [16] WINDOWS_1251_T Tatarian version of Windows-1251
+ CODES_ARMSCII, // [17] Armenian ASCII
+ CODES_GEO_ITA, // [18] Academy of Sciences Georgian
+ CODES_GEO_PS, // [19] Georgian Parliament
+ CODES_ISO_8859_3, // [20] Latin-3: Turkish, Maltese and Esperanto
+ CODES_ISO_8859_4, // [21] Latin-4: Estonian, Latvian, Lithuanian, Greenlandic, Sami
+ CODES_ISO_8859_6, // [22] Latin/Arabic: Arabic
+ CODES_ISO_8859_7, // [23] Latin/Greek: Greek
+ CODES_ISO_8859_8, // [24] Latin/Hebrew: Hebrew
+ CODES_ISO_8859_9, // [25] Latin-5 or Turkish: Turkish
+ CODES_ISO_8859_13, // [26] Latin-7 or Baltic Rim: Baltic languages
+ CODES_ISO_8859_15, // [27] Latin-9: Western European languages
+ CODES_ISO_8859_16, // [28] Latin-10: South-Eastern European languages
+ CODES_WINDOWS_1253, // [29] for Greek
+ CODES_WINDOWS_1254, // [30] for Turkish
+ CODES_WINDOWS_1255, // [31] for Hebrew
+ CODES_WINDOWS_1256, // [32] for Arabic
+ CODES_WINDOWS_1257, // [33] for Estonian, Latvian and Lithuanian
+
+ // these codes are all the other 8bit codes known by libiconv
+ // they follow in alphanumeric order
+ CODES_CP1046,
+ CODES_CP1124,
+ CODES_CP1125,
+ CODES_CP1129,
+ CODES_CP1131,
+ CODES_CP1133,
+ CODES_CP1161, // [40]
+ CODES_CP1162,
+ CODES_CP1163,
+ CODES_CP1258,
+ CODES_CP437,
+ CODES_CP737,
+ CODES_CP775,
+ CODES_CP850,
+ CODES_CP852,
+ CODES_CP853,
+ CODES_CP856, // [50]
+ CODES_CP857,
+ CODES_CP858,
+ CODES_CP860,
+ CODES_CP861,
+ CODES_CP862,
+ CODES_CP863,
+ CODES_CP864,
+ CODES_CP865,
+ CODES_CP869,
+ CODES_CP874, // [60]
+ CODES_CP922,
+ CODES_HP_ROMAN8,
+ CODES_ISO646_CN,
+ CODES_ISO646_JP,
+ CODES_ISO8859_10,
+ CODES_ISO8859_11,
+ CODES_ISO8859_14,
+ CODES_JISX0201,
+ CODES_KOI8_T,
+ CODES_MAC_ARABIC, // [70]
+ CODES_MAC_CENTRALEUROPE,
+ CODES_MAC_CROATIAN,
+ CODES_MAC_GREEK,
+ CODES_MAC_HEBREW,
+ CODES_MAC_ICELAND,
+ CODES_MAC_ROMANIA,
+ CODES_MAC_ROMAN,
+ CODES_MAC_THAI,
+ CODES_MAC_TURKISH,
+ CODES_RESERVED_2, // [80] reserved code: use it for new encodings before adding them to the end of the list
+ CODES_MULELAO,
+ CODES_NEXTSTEP,
+ CODES_PT154,
+ CODES_RISCOS_LATIN1,
+ CODES_RK1048,
+ CODES_TCVN,
+ CODES_TDS565,
+ CODES_TIS620,
+ CODES_VISCII,
+
+ // libiconv multibyte codepages
+ CODES_BIG5, // [90]
+ CODES_BIG5_HKSCS,
+ CODES_BIG5_HKSCS_1999,
+ CODES_BIG5_HKSCS_2001,
+ CODES_CP932,
+ CODES_CP936,
+ CODES_CP949,
+ CODES_CP950,
+ CODES_EUC_CN,
+ CODES_EUC_JP,
+ CODES_EUC_KR, // [100]
+ CODES_EUC_TW,
+ CODES_GB18030,
+ CODES_GBK,
+ CODES_HZ,
+ CODES_ISO_2022_CN,
+ CODES_ISO_2022_CN_EXT,
+ CODES_ISO_2022_JP,
+ CODES_ISO_2022_JP_1,
+ CODES_ISO_2022_JP_2,
+ CODES_ISO_2022_KR, // [110]
+ CODES_JOHAB,
+ CODES_SHIFT_JIS,
+
+ CODES_MAX
+};
diff --git a/library/cpp/charset/generated/cp_data.cpp b/library/cpp/charset/generated/cp_data.cpp
new file mode 100644
index 0000000000..202362c596
--- /dev/null
+++ b/library/cpp/charset/generated/cp_data.cpp
@@ -0,0 +1,3788 @@
+#include <library/cpp/charset/codepage.h>
+
+extern const char defchars[][DEFCHAR_BUF];
+
+static const CodePage CODES_ALT_CODE_PAGE = {
+ CODES_ALT,
+ {"IBM866", "csIBM866", "cp866", "866", "dos-866", "alt", "windows-866",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_ARMSCII_CODE_PAGE = {
+ CODES_ARMSCII,
+ {"armscii",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0x0530, 0x0587, 0x0589, 0x0029, 0x0028, 0x00BB, 0x00AB,
+ 0x2014, 0x002E, 0x055D, 0x002C, 0x002D, 0x058A, 0x2026, 0x055C,
+ 0x055B, 0x055E, 0x0531, 0x0561, 0x0532, 0x0562, 0x0533, 0x0563,
+ 0x0534, 0x0564, 0x0535, 0x0565, 0x0536, 0x0566, 0x0537, 0x0567,
+ 0x0538, 0x0568, 0x0539, 0x0569, 0x053A, 0x056A, 0x053B, 0x056B,
+ 0x053C, 0x056C, 0x053D, 0x056D, 0x053E, 0x056E, 0x053F, 0x056F,
+ 0x0540, 0x0570, 0x0541, 0x0571, 0x0542, 0x0572, 0x0543, 0x0573,
+ 0x0544, 0x0574, 0x0545, 0x0575, 0x0546, 0x0576, 0x0547, 0x0577,
+ 0x0548, 0x0578, 0x0549, 0x0579, 0x054A, 0x057A, 0x054B, 0x057B,
+ 0x054C, 0x057C, 0x054D, 0x057D, 0x054E, 0x057E, 0x054F, 0x057F,
+ 0x0550, 0x0580, 0x0551, 0x0581, 0x0552, 0x0582, 0x0553, 0x0583,
+ 0x0554, 0x0584, 0x0555, 0x0585, 0x0556, 0x0586, 0x055A, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from armscii.txt
+
+static const CodePage CODES_ASCII_CODE_PAGE = {
+ CODES_ASCII,
+ {"windows-1252", "cp1252", "1252", "US-ASCII", "ASCII", "csASCII", "ANSI_X3.4-1968", "ANSI_X3.4-1986", "IBM367", "cp367", "367", "iso-ir-100", "IBM819", "cp819", "819", "latin1", "l1", "ISOLatin1", "csISOLatin1", "ISO-8859-1", "ISO_8859-1", "ISO_8859-1:1987", "iso-ir-6", "iso_646.irv:1991", "ISO646-US", "US",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0xFFFD, 0x017D, 0xFFFD,
+ 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0xFFFD, 0x017E, 0x0178,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_BIG5_CODE_PAGE = {
+ CODES_BIG5,
+ {"BIG5", "BIGFIVE", "CN-BIG5", "CSBIG5",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_BIG5_HKSCS_CODE_PAGE = {
+ CODES_BIG5_HKSCS,
+ {"BIG5-HKSCS", "BIG5-HKSCS:2004",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_BIG5_HKSCS_1999_CODE_PAGE = {
+ CODES_BIG5_HKSCS_1999,
+ {"BIG5-HKSCS:1999",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_BIG5_HKSCS_2001_CODE_PAGE = {
+ CODES_BIG5_HKSCS_2001,
+ {"BIG5-HKSCS:2001",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_CP1046_CODE_PAGE = {
+ CODES_CP1046,
+ {"CP1046", "windows-1046",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0xFE88, 0x00D7, 0x00F7, 0xF8F6, 0xF8F5, 0xF8F4, 0xF8F7, 0xFE71,
+ 0x0088, 0x25A0, 0x2502, 0x2500, 0x2510, 0x250C, 0x2514, 0x2518,
+ 0xFE79, 0xFE7B, 0xFE7D, 0xFE7F, 0xFE77, 0xFE8A, 0xFEF0, 0xFEF3,
+ 0xFEF2, 0xFECE, 0xFECF, 0xFED0, 0xFEF6, 0xFEF8, 0xFEFA, 0xFEFC,
+ 0x00A0, 0xF8FA, 0xF8F9, 0xF8F8, 0x00A4, 0xF8FB, 0xFE8B, 0xFE91,
+ 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0x060C, 0x00AD, 0xFEA7, 0xFEB3,
+ 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667,
+ 0x0668, 0x0669, 0xFEB7, 0x061B, 0xFEBB, 0xFEBF, 0xFECA, 0x061F,
+ 0xFECB, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
+ 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
+ 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637,
+ 0xFEC7, 0x0639, 0x063A, 0xFECC, 0xFE82, 0xFE84, 0xFE8E, 0xFED3,
+ 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647,
+ 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F,
+ 0x0650, 0x0651, 0x0652, 0xFED7, 0xFEDB, 0xFEDF, 0xF8FC, 0xFEF5,
+ 0xFEF7, 0xFEF9, 0xFEFB, 0xFEE3, 0xFEE7, 0xFEEC, 0xFEE9, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from cp1046.txt
+
+static const CodePage CODES_CP1124_CODE_PAGE = {
+ CODES_CP1124,
+ {"CP1124", "windows-1124",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x0401, 0x0402, 0x0490, 0x0404, 0x0405, 0x0406, 0x0407,
+ 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ 0x2116, 0x0451, 0x0452, 0x0491, 0x0454, 0x0455, 0x0456, 0x0457,
+ 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F,
+ },
+ defchars[0],
+}; // generated from cp1124.txt
+
+static const CodePage CODES_CP1125_CODE_PAGE = {
+ CODES_CP1125,
+ {"CP1125", "windows-1125",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ 0x0401, 0x0451, 0x0490, 0x0491, 0x0404, 0x0454, 0x0406, 0x0456,
+ 0x0407, 0x0457, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from cp1125.txt
+
+static const CodePage CODES_CP1129_CODE_PAGE = {
+ CODES_CP1129,
+ {"CP1129", "windows-1129",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x0153, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0178, 0x00B5, 0x00B6, 0x00B7,
+ 0x0152, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF,
+ 0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF,
+ 0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF,
+ },
+ defchars[0],
+}; // generated from cp1129.txt
+
+static const CodePage CODES_CP1131_CODE_PAGE = {
+ CODES_CP1131,
+ {"CP1131", "windows-1131",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E,
+ 0x0406, 0x0456, 0x00B7, 0x00A4, 0x0490, 0x0491, 0x2219, 0x00A0,
+ },
+ defchars[0],
+}; // generated from cp1131.txt
+
+static const CodePage CODES_CP1133_CODE_PAGE = {
+ CODES_CP1133,
+ {"CP1133", "IBM-CP1133", "windows-1133",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x0E81, 0x0E82, 0x0E84, 0x0E87, 0x0E88, 0x0EAA, 0x0E8A,
+ 0x0E8D, 0x0E94, 0x0E95, 0x0E96, 0x0E97, 0x0E99, 0x0E9A, 0x0E9B,
+ 0x0E9C, 0x0E9D, 0x0E9E, 0x0E9F, 0x0EA1, 0x0EA2, 0x0EA3, 0x0EA5,
+ 0x0EA7, 0x0EAB, 0x0EAD, 0x0EAE, 0xFFFD, 0xFFFD, 0xFFFD, 0x0EAF,
+ 0x0EB0, 0x0EB2, 0x0EB3, 0x0EB4, 0x0EB5, 0x0EB6, 0x0EB7, 0x0EB8,
+ 0x0EB9, 0x0EBC, 0x0EB1, 0x0EBB, 0x0EBD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0x0EC0, 0x0EC1, 0x0EC2, 0x0EC3, 0x0EC4, 0x0EC8, 0x0EC9, 0x0ECA,
+ 0x0ECB, 0x0ECC, 0x0ECD, 0x0EC6, 0xFFFD, 0x0EDC, 0x0EDD, 0x20AD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0x0ED0, 0x0ED1, 0x0ED2, 0x0ED3, 0x0ED4, 0x0ED5, 0x0ED6, 0x0ED7,
+ 0x0ED8, 0x0ED9, 0xFFFD, 0xFFFD, 0x00A2, 0x00AC, 0x00A6, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from cp1133.txt
+
+static const CodePage CODES_CP1161_CODE_PAGE = {
+ CODES_CP1161,
+ {"CP1161", "windows-1161",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0x0E48, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07,
+ 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
+ 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17,
+ 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
+ 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
+ 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
+ 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
+ 0x0E38, 0x0E39, 0x0E3A, 0x0E49, 0x0E4A, 0x0E4B, 0x20AC, 0x0E3F,
+ 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47,
+ 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F,
+ 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57,
+ 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0x00A2, 0x00AC, 0x00A6, 0x00A0,
+ },
+ defchars[0],
+}; // generated from cp1161.txt
+
+static const CodePage CODES_CP1162_CODE_PAGE = {
+ CODES_CP1162,
+ {"CP1162", "windows-1162",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, 0x0081, 0x0082, 0x0083, 0x0084, 0x2026, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07,
+ 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
+ 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17,
+ 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
+ 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
+ 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
+ 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
+ 0x0E38, 0x0E39, 0x0E3A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x0E3F,
+ 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47,
+ 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F,
+ 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57,
+ 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from cp1162.txt
+
+static const CodePage CODES_CP1163_CODE_PAGE = {
+ CODES_CP1163,
+ {"CP1163", "windows-1163",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x00A6, 0x00A7,
+ 0x0153, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0178, 0x00B5, 0x00B6, 0x00B7,
+ 0x0152, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF,
+ 0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF,
+ 0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF,
+ },
+ defchars[0],
+}; // generated from cp1163.txt
+
+static const CodePage CODES_CP1258_CODE_PAGE = {
+ CODES_CP1258,
+ {"CP1258", "windows-1258",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0xFFFD, 0x2039, 0x0152, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, 0xFFFD, 0x203A, 0x0153, 0xFFFD, 0xFFFD, 0x0178,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF,
+ 0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF,
+ 0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_CP437_CODE_PAGE = {
+ CODES_CP437,
+ {"CP437", "windows-437",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+ 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+ 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_CP737_CODE_PAGE = {
+ CODES_CP737,
+ {"CP737", "windows-737",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398,
+ 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
+ 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9,
+ 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
+ 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0,
+ 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD,
+ 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
+ 0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_CP775_CODE_PAGE = {
+ CODES_CP775,
+ {"CP775", "windows-775",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107,
+ 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A,
+ 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
+ 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6,
+ 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118,
+ 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,
+ 0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B,
+ 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144,
+ 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,
+ 0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E,
+ 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_CP850_CODE_PAGE = {
+ CODES_CP850,
+ {"CP850", "IBM850", "850", "CSPC850MULTILINGUAL", "windows-850",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+ 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE,
+ 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
+ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
+ 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
+ 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+ 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_CP852_CODE_PAGE = {
+ CODES_CP852,
+ {"CP852", "windows-852",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7,
+ 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
+ 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A,
+ 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E,
+ 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A,
+ 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE,
+ 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,
+ 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161,
+ 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,
+ 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8,
+ 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_CP853_CODE_PAGE = {
+ CODES_CP853,
+ {"CP853", "windows-853",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x0109, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x0108,
+ 0x00C9, 0x010B, 0x010A, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x0130, 0x00D6, 0x00DC, 0x011D, 0x00A3, 0x011C, 0x00D7, 0x0135,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F,
+ 0x0124, 0x0125, 0xFFFD, 0x00BD, 0x0134, 0x015F, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+ 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x015C, 0x015D,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0xFFFD, 0xFFFD, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE,
+ 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0xFFFD, 0x00CC, 0x2580,
+ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x0120, 0x0121, 0x00B5, 0x0126,
+ 0x0127, 0x00DA, 0x00DB, 0x00D9, 0x016C, 0x016D, 0xFFFD, 0x00B4,
+ 0x00AD, 0xFFFD, 0x2113, 0x0149, 0x02D8, 0x00A7, 0x00F7, 0x00B8,
+ 0x00B0, 0x00A8, 0x02D9, 0xFFFD, 0x00B3, 0x00B2, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from cp853.txt
+
+static const CodePage CODES_CP856_CODE_PAGE = {
+ CODES_CP856,
+ {"CP856", "windows-856",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+ 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+ 0x05E8, 0x05E9, 0x05EA, 0xFFFD, 0x00A3, 0xFFFD, 0x00D7, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0xFFFD, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0xFFFD, 0xFFFD,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0xFFFD, 0x2580,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x00B5, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x00AF, 0x00B4,
+ 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+ 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_CP857_CODE_PAGE = {
+ CODES_CP857,
+ {"CP857", "windows-857",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F,
+ 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+ 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0xFFFD, 0x00CD, 0x00CE,
+ 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
+ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0xFFFD,
+ 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,
+ 0x00AD, 0x00B1, 0xFFFD, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+ 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_CP858_CODE_PAGE = {
+ CODES_CP858,
+ {"CP858", "windows-858",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+ 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x20AC, 0x00CD, 0x00CE,
+ 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
+ 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
+ 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
+ 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+ 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from cp858.txt
+
+static const CodePage CODES_CP860_CODE_PAGE = {
+ CODES_CP860,
+ {"CP860", "windows-860",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7,
+ 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2,
+ 0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9,
+ 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+ 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+ 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_CP861_CODE_PAGE = {
+ CODES_CP861,
+ {"CP861", "windows-861",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD,
+ 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA,
+ 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+ 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+ 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_CP862_CODE_PAGE = {
+ CODES_CP862,
+ {"CP862", "IBM862", "862", "CSPC862LATINHEBREW", "windows-862",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+ 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+ 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+ 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+ 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_CP863_CODE_PAGE = {
+ CODES_CP863,
+ {"CP863", "windows-863",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x2017, 0x00C0, 0x00A7,
+ 0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9,
+ 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192,
+ 0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00B8, 0x00B3, 0x00AF,
+ 0x00CE, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+ 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+ 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_CP864_CODE_PAGE = {
+ CODES_CP864,
+ {"CP864", "windows-864",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x066A, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C,
+ 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518,
+ 0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB,
+ 0x00BB, 0xFEF7, 0xFEF8, 0xFFFD, 0xFFFD, 0xFEFB, 0xFEFC, 0xFFFD,
+ 0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0xFFFD, 0xFFFD,
+ 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5,
+ 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667,
+ 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F,
+ 0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D,
+ 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,
+ 0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1,
+ 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9,
+ 0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB,
+ 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1,
+ 0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0,
+ 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_CP865_CODE_PAGE = {
+ CODES_CP865,
+ {"CP865", "windows-865",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+ 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+ 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+ 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+ 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+ 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_CP869_CODE_PAGE = {
+ CODES_CP869,
+ {"CP869", "windows-869",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x0386, 0xFFFD,
+ 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389,
+ 0x038A, 0x03AA, 0x038C, 0xFFFD, 0xFFFD, 0x038E, 0x03AB, 0x00A9,
+ 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF,
+ 0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394,
+ 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C,
+ 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x03A0, 0x03A1,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3,
+ 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2,
+ 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580,
+ 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD,
+ 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384,
+ 0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385,
+ 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_CP874_CODE_PAGE = {
+ CODES_CP874,
+ {"CP874", "windows-874",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x2026, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07,
+ 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
+ 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17,
+ 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
+ 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
+ 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
+ 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
+ 0x0E38, 0x0E39, 0x0E3A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x0E3F,
+ 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47,
+ 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F,
+ 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57,
+ 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_CP922_CODE_PAGE = {
+ CODES_CP922,
+ {"CP922", "windows-922",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x203E,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x0160, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x017D, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x0161, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x017E, 0x00FF,
+ },
+ defchars[0],
+}; // generated from cp922.txt
+
+static const CodePage CODES_CP932_CODE_PAGE = {
+ CODES_CP932,
+ {"CP932",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_CP936_CODE_PAGE = {
+ CODES_CP936,
+ {"CP936",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_CP949_CODE_PAGE = {
+ CODES_CP949,
+ {"CP949", "UHC",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_CP950_CODE_PAGE = {
+ CODES_CP950,
+ {"CP950",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_EUC_CN_CODE_PAGE = {
+ CODES_EUC_CN,
+ {"EUC-CN", "CN-GB", "GB2312", "CSGB2312",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_EUC_JP_CODE_PAGE = {
+ CODES_EUC_JP,
+ {"EUC-JP", "EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE", "CSEUCPKDFMTJAPANESE",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_EUC_KR_CODE_PAGE = {
+ CODES_EUC_KR,
+ {"EUC-KR", "ISO-IR-149", "KOREAN", "KSC_5601", "KS_C_5601-1987", "KS_C_5601-1989", "CSEUCKR", "CSKSC56011987",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_EUC_TW_CODE_PAGE = {
+ CODES_EUC_TW,
+ {"EUC-TW", "CSEUCTW",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_GB18030_CODE_PAGE = {
+ CODES_GB18030,
+ {"GB18030",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_GBK_CODE_PAGE = {
+ CODES_GBK,
+ {"GBK",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_GEO_ITA_CODE_PAGE = {
+ CODES_GEO_ITA,
+ {"geo-ita",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x009D, 0x009E, 0x0178,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7,
+ 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7,
+ 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10F6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
+ },
+ defchars[0],
+}; // generated from geo-ita.txt
+
+static const CodePage CODES_GEO_PS_CODE_PAGE = {
+ CODES_GEO_PS,
+ {"geo-ps",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x009D, 0x009E, 0x0178,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10F1,
+ 0x10D7, 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10F2, 0x10DD,
+ 0x10DE, 0x10DF, 0x10E0, 0x10E1, 0x10E2, 0x10F3, 0x10E3, 0x10E4,
+ 0x10E5, 0x10E6, 0x10E7, 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC,
+ 0x10ED, 0x10EE, 0x10F4, 0x10EF, 0x10F0, 0x10F5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
+ },
+ defchars[0],
+}; // generated from geo-ps.txt
+
+static const CodePage CODES_HP_ROMAN8_CODE_PAGE = {
+ CODES_HP_ROMAN8,
+ {"HP_ROMAN8", "HP-ROMAN8", "ROMAN8", "R8", "CSHPROMAN8",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x00C0, 0x00C2, 0x00C8, 0x00CA, 0x00CB, 0x00CE, 0x00CF,
+ 0x00B4, 0x02CB, 0x02C6, 0x00A8, 0x02DC, 0x00D9, 0x00DB, 0x20A4,
+ 0x00AF, 0x00DD, 0x00FD, 0x00B0, 0x00C7, 0x00E7, 0x00D1, 0x00F1,
+ 0x00A1, 0x00BF, 0x00A4, 0x00A3, 0x00A5, 0x00A7, 0x0192, 0x00A2,
+ 0x00E2, 0x00EA, 0x00F4, 0x00FB, 0x00E1, 0x00E9, 0x00F3, 0x00FA,
+ 0x00E0, 0x00E8, 0x00F2, 0x00F9, 0x00E4, 0x00EB, 0x00F6, 0x00FC,
+ 0x00C5, 0x00EE, 0x00D8, 0x00C6, 0x00E5, 0x00ED, 0x00F8, 0x00E6,
+ 0x00C4, 0x00EC, 0x00D6, 0x00DC, 0x00C9, 0x00EF, 0x00DF, 0x00D4,
+ 0x00C1, 0x00C3, 0x00E3, 0x00D0, 0x00F0, 0x00CD, 0x00CC, 0x00D3,
+ 0x00D2, 0x00D5, 0x00F5, 0x0160, 0x0161, 0x00DA, 0x0178, 0x00FF,
+ 0x00DE, 0x00FE, 0x00B7, 0x00B5, 0x00B6, 0x00BE, 0x2014, 0x00BC,
+ 0x00BD, 0x00AA, 0x00BA, 0x00AB, 0x25A0, 0x00BB, 0x00B1, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from hp_roman8.txt
+
+static const CodePage CODES_HZ_CODE_PAGE = {
+ CODES_HZ,
+ {"HZ", "HZ-GB-2312",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_IBM855_CODE_PAGE = {
+ CODES_IBM855,
+ {"IBM855", "csIBM855", "cp855", "855", "dos-855", "windows-855",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404,
+ 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
+ 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C,
+ 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
+ 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414,
+ 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438,
+ 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,
+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A,
+ 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+ 0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E,
+ 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,
+ 0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443,
+ 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,
+ 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D,
+ 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_ISO646_CN_CODE_PAGE = {
+ CODES_ISO646_CN,
+ {"ISO646_CN", "GB_1988-80", "ISO646-CN", "ISO-IR-57", "CN", "CSISO57GB1988",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x00A5, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x203E, 0x007F,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from iso646_cn.txt
+
+static const CodePage CODES_ISO646_JP_CODE_PAGE = {
+ CODES_ISO646_JP,
+ {"ISO646_JP", "JIS_C6220-1969-RO", "ISO646-JP", "ISO-IR-14", "JP", "CSISO14JISC6220RO",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x00A5, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x203E, 0x007F,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from iso646_jp.txt
+
+static const CodePage CODES_ISO8859_10_CODE_PAGE = {
+ CODES_ISO8859_10,
+ {"ISO8859_10", "ISO-8859-10", "ISO_8859-10", "ISO_8859-10:1992", "ISO-IR-157", "LATIN6", "L6", "CSISOLATIN6", "ISO8859-10",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x0104, 0x0112, 0x0122, 0x012A, 0x0128, 0x0136, 0x00A7,
+ 0x013B, 0x0110, 0x0160, 0x0166, 0x017D, 0x00AD, 0x016A, 0x014A,
+ 0x00B0, 0x0105, 0x0113, 0x0123, 0x012B, 0x0129, 0x0137, 0x00B7,
+ 0x013C, 0x0111, 0x0161, 0x0167, 0x017E, 0x2015, 0x016B, 0x014B,
+ 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E,
+ 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x00CF,
+ 0x00D0, 0x0145, 0x014C, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0168,
+ 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
+ 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F,
+ 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x00EF,
+ 0x00F0, 0x0146, 0x014D, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0169,
+ 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x0138,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_ISO8859_11_CODE_PAGE = {
+ CODES_ISO8859_11,
+ {"ISO8859_11", "ISO-8859-11", "ISO_8859-11", "ISO8859-11",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07,
+ 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
+ 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17,
+ 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
+ 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
+ 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
+ 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
+ 0x0E38, 0x0E39, 0x0E3A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x0E3F,
+ 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47,
+ 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F,
+ 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57,
+ 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_ISO8859_14_CODE_PAGE = {
+ CODES_ISO8859_14,
+ {"ISO8859_14", "ISO-8859-14", "ISO_8859-14", "ISO_8859-14:1998", "ISO-IR-199", "LATIN8", "L8", "ISO-CELTIC", "ISO8859-14",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x1E02, 0x1E03, 0x00A3, 0x010A, 0x010B, 0x1E0A, 0x00A7,
+ 0x1E80, 0x00A9, 0x1E82, 0x1E0B, 0x1EF2, 0x00AD, 0x00AE, 0x0178,
+ 0x1E1E, 0x1E1F, 0x0120, 0x0121, 0x1E40, 0x1E41, 0x00B6, 0x1E56,
+ 0x1E81, 0x1E57, 0x1E83, 0x1E60, 0x1EF3, 0x1E84, 0x1E85, 0x1E61,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x0174, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x1E6A,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x0176, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x0175, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x1E6B,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x0177, 0x00FF,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_ISO_2022_CN_CODE_PAGE = {
+ CODES_ISO_2022_CN,
+ {"ISO-2022-CN", "CSISO2022CN",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_ISO_2022_CN_EXT_CODE_PAGE = {
+ CODES_ISO_2022_CN_EXT,
+ {"ISO-2022-CN-EXT",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_ISO_2022_JP_CODE_PAGE = {
+ CODES_ISO_2022_JP,
+ {"ISO-2022-JP", "CPISO2022JP",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_ISO_2022_JP_1_CODE_PAGE = {
+ CODES_ISO_2022_JP_1,
+ {"ISO-2022-JP-1",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_ISO_2022_JP_2_CODE_PAGE = {
+ CODES_ISO_2022_JP_2,
+ {"ISO-2022-JP-2", "CPISO2022JP2",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_ISO_2022_KR_CODE_PAGE = {
+ CODES_ISO_2022_KR,
+ {"ISO-2022-KR", "CSISO2022KR",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_ISO_8859_13_CODE_PAGE = {
+ CODES_ISO_8859_13,
+ {"iso-8859-13",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x201D, 0x00A2, 0x00A3, 0x00A4, 0x201E, 0x00A6, 0x00A7,
+ 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x201C, 0x00B5, 0x00B6, 0x00B7,
+ 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6,
+ 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112,
+ 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B,
+ 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7,
+ 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF,
+ 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113,
+ 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C,
+ 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7,
+ 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x2019,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_ISO_8859_15_CODE_PAGE = {
+ CODES_ISO_8859_15,
+ {"iso-8859-15",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7,
+ 0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x00B7,
+ 0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_ISO_8859_16_CODE_PAGE = {
+ CODES_ISO_8859_16,
+ {"iso-8859-16",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x0104, 0x0105, 0x0141, 0x20AC, 0x201E, 0x0160, 0x00A7,
+ 0x0161, 0x00A9, 0x0218, 0x00AB, 0x0179, 0x00AD, 0x017A, 0x017B,
+ 0x00B0, 0x00B1, 0x010C, 0x0142, 0x017D, 0x201D, 0x00B6, 0x00B7,
+ 0x017E, 0x010D, 0x0219, 0x00BB, 0x0152, 0x0153, 0x0178, 0x017C,
+ 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0106, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x0110, 0x0143, 0x00D2, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x015A,
+ 0x0170, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0118, 0x021A, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x0107, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x0111, 0x0144, 0x00F2, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x015B,
+ 0x0171, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0119, 0x021B, 0x00FF,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_ISO_8859_3_CODE_PAGE = {
+ CODES_ISO_8859_3,
+ {"iso-8859-3",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0xFFFD, 0x0124, 0x00A7,
+ 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0xFFFD, 0x017B,
+ 0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7,
+ 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0xFFFD, 0x017C,
+ 0x00C0, 0x00C1, 0x00C2, 0xFFFD, 0x00C4, 0x010A, 0x0108, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0xFFFD, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7,
+ 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0xFFFD, 0x00E4, 0x010B, 0x0109, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0xFFFD, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7,
+ 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_ISO_8859_4_CODE_PAGE = {
+ CODES_ISO_8859_4,
+ {"iso-8859-4",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7,
+ 0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF,
+ 0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7,
+ 0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B,
+ 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E,
+ 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A,
+ 0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF,
+ 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F,
+ 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B,
+ 0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_ISO_8859_6_CODE_PAGE = {
+ CODES_ISO_8859_6,
+ {"iso-8859-6", "cp708",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x2502, 0x2524, 0x00E9, 0x00E2, 0x2561, 0x00E0, 0x2562, 0x00E7,
+ 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x2556, 0x2555, 0x2563,
+ 0x2551, 0x2557, 0x255D, 0x00F4, 0x255C, 0x255B, 0x00FB, 0x00F9,
+ 0x2510, 0x2514, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x2534, 0x252C, 0x251C, 0x00A4, 0x2500, 0x253C, 0x255E,
+ 0x255F, 0x255A, 0x2554, 0x2569, 0x060C, 0x2566, 0x00AB, 0x00BB,
+ 0x2591, 0x2592, 0x2593, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568,
+ 0x2564, 0x2565, 0x2559, 0x061B, 0x2558, 0x2552, 0x2553, 0x061F,
+ 0x256B, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
+ 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
+ 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637,
+ 0x0638, 0x0639, 0x063A, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+ 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647,
+ 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F,
+ 0x0650, 0x0651, 0x0652, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0x256A, 0x2518, 0x250C, 0x00B5, 0x00A3, 0x25A0, 0x00A0,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_ISO_8859_7_CODE_PAGE = {
+ CODES_ISO_8859_7,
+ {"iso-8859-7",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x2018, 0x2019, 0x00A3, 0x20AC, 0x20AF, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x037A, 0x00AB, 0x00AC, 0x00AD, 0xFFFD, 0x2015,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x0385, 0x0386, 0x00B7,
+ 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F,
+ 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+ 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
+ 0x03A0, 0x03A1, 0xFFFD, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
+ 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+ 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+ 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+ 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_ISO_8859_8_CODE_PAGE = {
+ CODES_ISO_8859_8,
+ {"iso-8859-8", "iso-8859-8-i",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0xFFFD, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x2017,
+ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+ 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+ 0x05E8, 0x05E9, 0x05EA, 0xFFFD, 0xFFFD, 0x200E, 0x200F, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_ISO_8859_9_CODE_PAGE = {
+ CODES_ISO_8859_9,
+ {"iso-8859-9",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_ISO_EAST_CODE_PAGE = {
+ CODES_ISO_EAST,
+ {"iso-2", "iso_8859-2", "iso-8859-2", "iso-east", "ISO8859_2", "ISO_8859-2:1987", "ISO-IR-101", "LATIN2", "L2", "CSISOLATIN2", "ISO8859-2",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7,
+ 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B,
+ 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7,
+ 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C,
+ 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
+ 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
+ 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
+ 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
+ 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
+ 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
+ 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
+ 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_JISX0201_CODE_PAGE = {
+ CODES_JISX0201,
+ {"JISX0201", "JIS_X0201", "JISX0201-1976", "X0201", "CSHALFWIDTHKATAKANA",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x00A5, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x203E, 0x007F,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67,
+ 0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F,
+ 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77,
+ 0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F,
+ 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87,
+ 0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F,
+ 0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97,
+ 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from jisx0201.txt
+
+static const CodePage CODES_JOHAB_CODE_PAGE = {
+ CODES_JOHAB,
+ {"JOHAB", "CP1361",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_KAZWIN_CODE_PAGE = {
+ CODES_KAZWIN,
+ {"windows-1251-k", "cp1251k", "1251k", "kazwin",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x04B0, 0x0492, 0x201A, 0x0493, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x20AC, 0x2030, 0x04E8, 0x2039, 0x04A2, 0x049A, 0x04BA, 0x04AE,
+ 0x04B1, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x0098, 0x2122, 0x04E9, 0x203A, 0x04A3, 0x049B, 0x04BB, 0x04AF,
+ 0x00A0, 0x040E, 0x045E, 0x0496, 0x00A4, 0x04B2, 0x00A6, 0x00A7,
+ 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
+ 0x00B0, 0x00B1, 0x0406, 0x0456, 0x04B3, 0x00B5, 0x00B6, 0x00B7,
+ 0x0451, 0x2116, 0x0454, 0x00BB, 0x0497, 0x04D8, 0x04D9, 0x0457,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ },
+ defchars[0],
+}; // generated from cp1251-kaz.txt
+
+static const CodePage CODES_KOI8_CODE_PAGE = {
+ CODES_KOI8,
+ {"KOI8-U", "csKOI8R", "KOI8-RU", "csKOI8RU", "KOI8-R", "csKOI8U", "koi",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524,
+ 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590,
+ 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248,
+ 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7,
+ 0x2550, 0x2551, 0x2552, 0x0451, 0x0454, 0x2554, 0x0456, 0x0457,
+ 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x0491, 0x255D, 0x255E,
+ 0x255F, 0x2560, 0x2561, 0x0401, 0x0404, 0x2563, 0x0406, 0x0407,
+ 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x0490, 0x256C, 0x00A9,
+ 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
+ 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
+ 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
+ 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A,
+ 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
+ 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
+ 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
+ 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_KOI8_T_CODE_PAGE = {
+ CODES_KOI8_T,
+ {"KOI8_T", "KOI8-T",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x049B, 0x0493, 0x201A, 0x0492, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0xFFFD, 0x2030, 0x04B3, 0x2039, 0x04B2, 0x04B7, 0x04B6, 0xFFFD,
+ 0x049A, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0xFFFD, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0x04EF, 0x04EE, 0x0451, 0x00A4, 0x04E3, 0x00A6, 0x00A7,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0xFFFD,
+ 0x00B0, 0x00B1, 0x00B2, 0x0401, 0xFFFD, 0x04E2, 0x00B6, 0x00B7,
+ 0xFFFD, 0x2116, 0xFFFD, 0x00BB, 0xFFFD, 0xFFFD, 0xFFFD, 0x00A9,
+ 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
+ 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
+ 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
+ 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A,
+ 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
+ 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
+ 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
+ 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A,
+ },
+ defchars[0],
+}; // generated from koi8_t.txt
+
+static const CodePage CODES_MAC_CODE_PAGE = {
+ CODES_MAC,
+ {"MacCyrillic", "MacRussian", "mac", "windows-10007", "MAC_UKRAINE", "MACUKRAINE", "windows-10017",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x2020, 0x00B0, 0x0490, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x0406,
+ 0x00AE, 0x00A9, 0x2122, 0x0402, 0x0452, 0x2260, 0x0403, 0x0453,
+ 0x221E, 0x00B1, 0x2264, 0x2265, 0x0456, 0x00B5, 0x0491, 0x0408,
+ 0x0404, 0x0454, 0x0407, 0x0457, 0x0409, 0x0459, 0x040A, 0x045A,
+ 0x0458, 0x0405, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
+ 0x00BB, 0x2026, 0x00A0, 0x040B, 0x045B, 0x040C, 0x045C, 0x0455,
+ 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x201E,
+ 0x040E, 0x045E, 0x040F, 0x045F, 0x2116, 0x0401, 0x0451, 0x044F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x20AC,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_MAC_ARABIC_CODE_PAGE = {
+ CODES_MAC_ARABIC,
+ {"MAC_ARABIC", "MACARABIC", "windows-10004",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C4, 0x00A0, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
+ 0x00E0, 0x00E2, 0x00E4, 0x06BA, 0x00AB, 0x00E7, 0x00E9, 0x00E8,
+ 0x00EA, 0x00EB, 0x00ED, 0x2026, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
+ 0x00BB, 0x00F4, 0x00F6, 0x00F7, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x066A, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x060C, 0x002D, 0x002E, 0x002F,
+ 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667,
+ 0x0668, 0x0669, 0x003A, 0x061B, 0x003C, 0x003D, 0x003E, 0x061F,
+ 0x274A, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
+ 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
+ 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637,
+ 0x0638, 0x0639, 0x063A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647,
+ 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F,
+ 0x0650, 0x0651, 0x0652, 0x067E, 0x0679, 0x0686, 0x06D5, 0x06A4,
+ 0x06AF, 0x0688, 0x0691, 0x007B, 0x007C, 0x007D, 0x0698, 0x06D2,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_MAC_CENTRALEUROPE_CODE_PAGE = {
+ CODES_MAC_CENTRALEUROPE,
+ {"MAC_CENTRALEUROPE", "MACCENTRALEUROPE", "windows-10029",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C4, 0x0100, 0x0101, 0x00C9, 0x0104, 0x00D6, 0x00DC, 0x00E1,
+ 0x0105, 0x010C, 0x00E4, 0x010D, 0x0106, 0x0107, 0x00E9, 0x0179,
+ 0x017A, 0x010E, 0x00ED, 0x010F, 0x0112, 0x0113, 0x0116, 0x00F3,
+ 0x0117, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x011A, 0x011B, 0x00FC,
+ 0x2020, 0x00B0, 0x0118, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
+ 0x00AE, 0x00A9, 0x2122, 0x0119, 0x00A8, 0x2260, 0x0123, 0x012E,
+ 0x012F, 0x012A, 0x2264, 0x2265, 0x012B, 0x0136, 0x2202, 0x2211,
+ 0x0142, 0x013B, 0x013C, 0x013D, 0x013E, 0x0139, 0x013A, 0x0145,
+ 0x0146, 0x0143, 0x00AC, 0x221A, 0x0144, 0x0147, 0x2206, 0x00AB,
+ 0x00BB, 0x2026, 0x00A0, 0x0148, 0x0150, 0x00D5, 0x0151, 0x014C,
+ 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
+ 0x014D, 0x0154, 0x0155, 0x0158, 0x2039, 0x203A, 0x0159, 0x0156,
+ 0x0157, 0x0160, 0x201A, 0x201E, 0x0161, 0x015A, 0x015B, 0x00C1,
+ 0x0164, 0x0165, 0x00CD, 0x017D, 0x017E, 0x016A, 0x00D3, 0x00D4,
+ 0x016B, 0x016E, 0x00DA, 0x016F, 0x0170, 0x0171, 0x0172, 0x0173,
+ 0x00DD, 0x00FD, 0x0137, 0x017B, 0x0141, 0x017C, 0x0122, 0x02C7,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_MAC_CROATIAN_CODE_PAGE = {
+ CODES_MAC_CROATIAN,
+ {"MAC_CROATIAN", "MACCROATIAN", "windows-10082",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
+ 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
+ 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
+ 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
+ 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
+ 0x00AE, 0x0160, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x017D, 0x00D8,
+ 0x221E, 0x00B1, 0x2264, 0x2265, 0x2206, 0x00B5, 0x2202, 0x2211,
+ 0x220F, 0x0161, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x017E, 0x00F8,
+ 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x0106, 0x00AB,
+ 0x010C, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
+ 0x0110, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
+ 0xF8FF, 0x00A9, 0x2044, 0x20AC, 0x2039, 0x203A, 0x00C6, 0x00BB,
+ 0x2013, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x0107, 0x00C1,
+ 0x010D, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
+ 0x0111, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
+ 0x00AF, 0x03C0, 0x00CB, 0x02DA, 0x00B8, 0x00CA, 0x00E6, 0x02C7,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_MAC_GREEK_CODE_PAGE = {
+ CODES_MAC_GREEK,
+ {"MAC_GREEK", "MACGREEK", "windows-10006",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C4, 0x00B9, 0x00B2, 0x00C9, 0x00B3, 0x00D6, 0x00DC, 0x0385,
+ 0x00E0, 0x00E2, 0x00E4, 0x0384, 0x00A8, 0x00E7, 0x00E9, 0x00E8,
+ 0x00EA, 0x00EB, 0x00A3, 0x2122, 0x00EE, 0x00EF, 0x2022, 0x00BD,
+ 0x2030, 0x00F4, 0x00F6, 0x00A6, 0x20AC, 0x00F9, 0x00FB, 0x00FC,
+ 0x2020, 0x0393, 0x0394, 0x0398, 0x039B, 0x039E, 0x03A0, 0x00DF,
+ 0x00AE, 0x00A9, 0x03A3, 0x03AA, 0x00A7, 0x2260, 0x00B0, 0x00B7,
+ 0x0391, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x0392, 0x0395, 0x0396,
+ 0x0397, 0x0399, 0x039A, 0x039C, 0x03A6, 0x03AB, 0x03A8, 0x03A9,
+ 0x03AC, 0x039D, 0x00AC, 0x039F, 0x03A1, 0x2248, 0x03A4, 0x00AB,
+ 0x00BB, 0x2026, 0x00A0, 0x03A5, 0x03A7, 0x0386, 0x0388, 0x0153,
+ 0x2013, 0x2015, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x0389,
+ 0x038A, 0x038C, 0x038E, 0x03AD, 0x03AE, 0x03AF, 0x03CC, 0x038F,
+ 0x03CD, 0x03B1, 0x03B2, 0x03C8, 0x03B4, 0x03B5, 0x03C6, 0x03B3,
+ 0x03B7, 0x03B9, 0x03BE, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BF,
+ 0x03C0, 0x03CE, 0x03C1, 0x03C3, 0x03C4, 0x03B8, 0x03C9, 0x03C2,
+ 0x03C7, 0x03C5, 0x03B6, 0x03CA, 0x03CB, 0x0390, 0x03B0, 0x00AD,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_MAC_HEBREW_CODE_PAGE = {
+ CODES_MAC_HEBREW,
+ {"MAC_HEBREW", "MACHEBREW", "windows-10005",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C4, 0xFB1F, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
+ 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
+ 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
+ 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x20AA, 0x0027,
+ 0x0029, 0x0028, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x05DC, 0x201E, 0xF89B, 0xF89C, 0xF89D, 0xF89E, 0x05BC, 0xFB4B,
+ 0xFB35, 0x2026, 0x00A0, 0x05B8, 0x05B7, 0x05B5, 0x05B6, 0x05B4,
+ 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0xFB2A, 0xFB2B,
+ 0x05BF, 0x05B0, 0x05B2, 0x05B1, 0x05BB, 0x05B9, 0x05B8, 0x05B3,
+ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+ 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+ 0x05E8, 0x05E9, 0x05EA, 0x007D, 0x005D, 0x007B, 0x005B, 0x007C,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_MAC_ICELAND_CODE_PAGE = {
+ CODES_MAC_ICELAND,
+ {"MAC_ICELAND", "MACICELAND", "windows-10079",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
+ 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
+ 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
+ 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
+ 0x00DD, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
+ 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
+ 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
+ 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
+ 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
+ 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
+ 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
+ 0x00FF, 0x0178, 0x2044, 0x20AC, 0x00D0, 0x00F0, 0x00DE, 0x00FE,
+ 0x00FD, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
+ 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
+ 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
+ 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_MAC_ROMAN_CODE_PAGE = {
+ CODES_MAC_ROMAN,
+ {"MAC_ROMAN", "MACROMAN", "MACINTOSH", "CSMACINTOSH", "windows-10000",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
+ 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
+ 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
+ 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
+ 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
+ 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
+ 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
+ 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
+ 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
+ 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
+ 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
+ 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02,
+ 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
+ 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
+ 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
+ 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_MAC_ROMANIA_CODE_PAGE = {
+ CODES_MAC_ROMANIA,
+ {"MAC_ROMANIA", "MACROMANIA", "windows-10010",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
+ 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
+ 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
+ 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
+ 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
+ 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x0102, 0x0218,
+ 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
+ 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x0103, 0x0219,
+ 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
+ 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
+ 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
+ 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0x021A, 0x021B,
+ 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
+ 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
+ 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
+ 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_MAC_THAI_CODE_PAGE = {
+ CODES_MAC_THAI,
+ {"MAC_THAI", "MACTHAI", "windows-10021",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00AB, 0x00BB, 0x2026, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C,
+ 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x201C, 0x201D, 0x0E4D,
+ 0xFFFD, 0x2022, 0x0E31, 0x0E47, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
+ 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x2018, 0x2019, 0xFFFD,
+ 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07,
+ 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
+ 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17,
+ 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
+ 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
+ 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
+ 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
+ 0x0E38, 0x0E39, 0x0E3A, 0x2060, 0x200B, 0x2013, 0x2014, 0x0E3F,
+ 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47,
+ 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x2122, 0x0E4F,
+ 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57,
+ 0x0E58, 0x0E59, 0x00AE, 0x00A9, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_MAC_TURKISH_CODE_PAGE = {
+ CODES_MAC_TURKISH,
+ {"MAC_TURKISH", "MACTURKISH", "windows-10081",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
+ 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
+ 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
+ 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
+ 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
+ 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
+ 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
+ 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
+ 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
+ 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
+ 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
+ 0x00FF, 0x0178, 0x011E, 0x011F, 0x0130, 0x0131, 0x015E, 0x015F,
+ 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
+ 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
+ 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0xF8A0, 0x02C6, 0x02DC,
+ 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_MAIN_CODE_PAGE = {
+ CODES_MAIN,
+ {"ISO-8859-5", "ISOLatinCyrillic", "csISOLatinCyrillic", "iso-ir-144", "cyrillic", "ISO_8859-5", "ISO_8859-5:1988", "iso", "ISO8859_5", "ISO8859-5",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407,
+ 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
+ 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_MULELAO_CODE_PAGE = {
+ CODES_MULELAO,
+ {"MULELAO", "MULELAO-1",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ 0x00A0, 0x0E81, 0x0E82, 0xFFFD, 0x0E84, 0xFFFD, 0xFFFD, 0x0E87,
+ 0x0E88, 0xFFFD, 0x0E8A, 0xFFFD, 0xFFFD, 0x0E8D, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x0E94, 0x0E95, 0x0E96, 0x0E97,
+ 0xFFFD, 0x0E99, 0x0E9A, 0x0E9B, 0x0E9C, 0x0E9D, 0x0E9E, 0x0E9F,
+ 0xFFFD, 0x0EA1, 0x0EA2, 0x0EA3, 0xFFFD, 0x0EA5, 0xFFFD, 0x0EA7,
+ 0xFFFD, 0xFFFD, 0x0EAA, 0x0EAB, 0xFFFD, 0x0EAD, 0x0EAE, 0x0EAF,
+ 0x0EB0, 0x0EB1, 0x0EB2, 0x0EB3, 0x0EB4, 0x0EB5, 0x0EB6, 0x0EB7,
+ 0x0EB8, 0x0EB9, 0xFFFD, 0x0EBB, 0x0EBC, 0x0EBD, 0xFFFD, 0xFFFD,
+ 0x0EC0, 0x0EC1, 0x0EC2, 0x0EC3, 0x0EC4, 0xFFFD, 0x0EC6, 0xFFFD,
+ 0x0EC8, 0x0EC9, 0x0ECA, 0x0ECB, 0x0ECC, 0x0ECD, 0xFFFD, 0xFFFD,
+ 0x0ED0, 0x0ED1, 0x0ED2, 0x0ED3, 0x0ED4, 0x0ED5, 0x0ED6, 0x0ED7,
+ 0x0ED8, 0x0ED9, 0xFFFD, 0xFFFD, 0x0EDC, 0x0EDD, 0xFFFD, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from mulelao.txt
+
+static const CodePage CODES_NEXTSTEP_CODE_PAGE = {
+ CODES_NEXTSTEP,
+ {"NEXTSTEP",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00A0, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D9,
+ 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00B5, 0x00D7, 0x00F7,
+ 0x00A9, 0x00A1, 0x00A2, 0x00A3, 0x2044, 0x00A5, 0x0192, 0x00A7,
+ 0x00A4, 0x2019, 0x201C, 0x00AB, 0x2039, 0x203A, 0xFB01, 0xFB02,
+ 0x00AE, 0x2013, 0x2020, 0x2021, 0x00B7, 0x00A6, 0x00B6, 0x2022,
+ 0x201A, 0x201E, 0x201D, 0x00BB, 0x2026, 0x2030, 0x00AC, 0x00BF,
+ 0x00B9, 0x02CB, 0x00B4, 0x02C6, 0x02DC, 0x00AF, 0x02D8, 0x02D9,
+ 0x00A8, 0x00B2, 0x02DA, 0x00B8, 0x00B3, 0x02DD, 0x02DB, 0x02C7,
+ 0x2014, 0x00B1, 0x00BC, 0x00BD, 0x00BE, 0x00E0, 0x00E1, 0x00E2,
+ 0x00E3, 0x00E4, 0x00E5, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB,
+ 0x00EC, 0x00C6, 0x00ED, 0x00AA, 0x00EE, 0x00EF, 0x00F0, 0x00F1,
+ 0x0141, 0x00D8, 0x0152, 0x00BA, 0x00F2, 0x00F3, 0x00F4, 0x00F5,
+ 0x00F6, 0x00E6, 0x00F9, 0x00FA, 0x00FB, 0x0131, 0x00FC, 0x00FD,
+ 0x0142, 0x00F8, 0x0153, 0x00DF, 0x00FE, 0x00FF, 0xFFFD, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_PT154_CODE_PAGE = {
+ CODES_PT154,
+ {"PT154", "PTCP154", "CP154", "CYRILLIC-ASIAN", "CSPTCP154",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0496, 0x0492, 0x04EE, 0x0493, 0x201E, 0x2026, 0x04B6, 0x04AE,
+ 0x04B2, 0x04AF, 0x04A0, 0x04E2, 0x04A2, 0x049A, 0x04BA, 0x04B8,
+ 0x0497, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x04B3, 0x04B7, 0x04A1, 0x04E3, 0x04A3, 0x049B, 0x04BB, 0x04B9,
+ 0x00A0, 0x040E, 0x045E, 0x0408, 0x04E8, 0x0498, 0x04B0, 0x00A7,
+ 0x0401, 0x00A9, 0x04D8, 0x00AB, 0x00AC, 0x04EF, 0x00AE, 0x049C,
+ 0x00B0, 0x04B1, 0x0406, 0x0456, 0x0499, 0x04E9, 0x00B6, 0x00B7,
+ 0x0451, 0x2116, 0x04D9, 0x00BB, 0x0458, 0x04AA, 0x04AB, 0x049D,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ },
+ defchars[0],
+}; // generated from pt154.txt
+
+static const CodePage CODES_RESERVED_2_CODE_PAGE = {
+ CODES_RESERVED_2,
+ {"reserved2",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x2020, 0x00B0, 0x0490, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x0406,
+ 0x00AE, 0x00A9, 0x2122, 0x0402, 0x0452, 0x2260, 0x0403, 0x0453,
+ 0x221E, 0x00B1, 0x2264, 0x2265, 0x0456, 0x00B5, 0x0491, 0x0408,
+ 0x0404, 0x0454, 0x0407, 0x0457, 0x0409, 0x0459, 0x040A, 0x045A,
+ 0x0458, 0x0405, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
+ 0x00BB, 0x2026, 0x00A0, 0x040B, 0x045B, 0x040C, 0x045C, 0x0455,
+ 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x201E,
+ 0x040E, 0x045E, 0x040F, 0x045F, 0x2116, 0x0401, 0x0451, 0x044F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x20AC,
+ },
+ defchars[0],
+}; // generated from reserved.txt
+
+static const CodePage CODES_RESERVED_3_CODE_PAGE = {
+ CODES_RESERVED_3,
+ {"reserved3",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from reserved.txt
+
+static const CodePage CODES_RISCOS_LATIN1_CODE_PAGE = {
+ CODES_RISCOS_LATIN1,
+ {"RISCOS-LATIN1", "RISCOS_LATIN1",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x221A, 0x0174, 0x0175, 0x0083, 0x2573, 0x0176, 0x0177, 0x0087,
+ 0x21E6, 0x21E8, 0x21E9, 0x21E7, 0x2026, 0x2122, 0x2030, 0x2022,
+ 0x2018, 0x2019, 0x2039, 0x203A, 0x201C, 0x201D, 0x201E, 0x2013,
+ 0x2014, 0x2212, 0x0152, 0x0153, 0x2020, 0x2021, 0xFB01, 0xFB02,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
+ },
+ defchars[0],
+}; // generated from riscos_latin1.txt
+
+static const CodePage CODES_RK1048_CODE_PAGE = {
+ CODES_RK1048,
+ {"RK1048", "STRK1048-2002", "KZ-1048", "CSKZ1048",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x049A, 0x04BA, 0x040F,
+ 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0xFFFD, 0x2122, 0x0459, 0x203A, 0x045A, 0x049B, 0x04BB, 0x045F,
+ 0x00A0, 0x04B0, 0x04B1, 0x04D8, 0x00A4, 0x04E8, 0x00A6, 0x00A7,
+ 0x0401, 0x00A9, 0x0492, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x04AE,
+ 0x00B0, 0x00B1, 0x0406, 0x0456, 0x04E9, 0x00B5, 0x00B6, 0x00B7,
+ 0x0451, 0x2116, 0x0493, 0x00BB, 0x04D9, 0x04A2, 0x04A3, 0x04AF,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ },
+ defchars[0],
+}; // generated from rk1048.txt
+
+static const CodePage CODES_SHIFT_JIS_CODE_PAGE = {
+ CODES_SHIFT_JIS,
+ {"SHIFT_JIS", "MS_KANJI", "SJIS", "CSSHIFTJIS",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_TATWIN_CODE_PAGE = {
+ CODES_TATWIN,
+ {"windows-1251-t", "cp1251t", "1251t", "tatwin",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x04D8, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x20AC, 0x2030, 0x04E8, 0x2039, 0x04AE, 0x0496, 0x04A2, 0x04BA,
+ 0x04D9, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x0098, 0x2122, 0x04E9, 0x203A, 0x04AF, 0x0497, 0x04A3, 0x04BB,
+ 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
+ 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
+ 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
+ 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ },
+ defchars[0],
+}; // generated from cp1251-tat.txt
+
+static const CodePage CODES_TCVN_CODE_PAGE = {
+ CODES_TCVN,
+ {"TCVN", "TCVN-5712", "TCVN5712-1", "TCVN5712-1:1993",},
+ {
+ 0x0000, 0x00DA, 0x1EE4, 0x0003, 0x1EEA, 0x1EEC, 0x1EEE, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x1EE8, 0x1EF0, 0x1EF2, 0x1EF6, 0x1EF8, 0x00DD, 0x1EF4,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x00C0, 0x1EA2, 0x00C3, 0x00C1, 0x1EA0, 0x1EB6, 0x1EAC, 0x00C8,
+ 0x1EBA, 0x1EBC, 0x00C9, 0x1EB8, 0x1EC6, 0x00CC, 0x1EC8, 0x0128,
+ 0x00CD, 0x1ECA, 0x00D2, 0x1ECE, 0x00D5, 0x00D3, 0x1ECC, 0x1ED8,
+ 0x1EDC, 0x1EDE, 0x1EE0, 0x1EDA, 0x1EE2, 0x00D9, 0x1EE6, 0x0168,
+ 0x00A0, 0x0102, 0x00C2, 0x00CA, 0x00D4, 0x01A0, 0x01AF, 0x0110,
+ 0x0103, 0x00E2, 0x00EA, 0x00F4, 0x01A1, 0x01B0, 0x0111, 0x1EB0,
+ 0x0300, 0x0309, 0x0303, 0x0301, 0x0323, 0x00E0, 0x1EA3, 0x00E3,
+ 0x00E1, 0x1EA1, 0x1EB2, 0x1EB1, 0x1EB3, 0x1EB5, 0x1EAF, 0x1EB4,
+ 0x1EAE, 0x1EA6, 0x1EA8, 0x1EAA, 0x1EA4, 0x1EC0, 0x1EB7, 0x1EA7,
+ 0x1EA9, 0x1EAB, 0x1EA5, 0x1EAD, 0x00E8, 0x1EC2, 0x1EBB, 0x1EBD,
+ 0x00E9, 0x1EB9, 0x1EC1, 0x1EC3, 0x1EC5, 0x1EBF, 0x1EC7, 0x00EC,
+ 0x1EC9, 0x1EC4, 0x1EBE, 0x1ED2, 0x0129, 0x00ED, 0x1ECB, 0x00F2,
+ 0x1ED4, 0x1ECF, 0x00F5, 0x00F3, 0x1ECD, 0x1ED3, 0x1ED5, 0x1ED7,
+ 0x1ED1, 0x1ED9, 0x1EDD, 0x1EDF, 0x1EE1, 0x1EDB, 0x1EE3, 0x00F9,
+ 0x1ED6, 0x1EE7, 0x0169, 0x00FA, 0x1EE5, 0x1EEB, 0x1EED, 0x1EEF,
+ 0x1EE9, 0x1EF1, 0x1EF3, 0x1EF7, 0x1EF9, 0x00FD, 0x1EF5, 0x1ED0,
+ },
+ defchars[0],
+}; // generated from tcvn.txt
+
+static const CodePage CODES_TDS565_CODE_PAGE = {
+ CODES_TDS565,
+ {"TDS565",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x00C7, 0x0044, 0x0045, 0x00C4, 0x0046,
+ 0x0047, 0x0048, 0x0049, 0x004A, 0x017D, 0x004B, 0x004C, 0x004D,
+ 0x004E, 0x0147, 0x004F, 0x00D6, 0x0050, 0x0052, 0x0053, 0x015E,
+ 0x0054, 0x0055, 0x00DC, 0x0057, 0x0059, 0x00DD, 0x005A, 0x005F,
+ 0x2116, 0x0061, 0x0062, 0x00E7, 0x0064, 0x0065, 0x00E4, 0x0066,
+ 0x0067, 0x0068, 0x0069, 0x006A, 0x017E, 0x006B, 0x006C, 0x006D,
+ 0x006E, 0x0148, 0x006F, 0x00F6, 0x0070, 0x0072, 0x0073, 0x015F,
+ 0x0074, 0x0075, 0x00FC, 0x0077, 0x0079, 0x00FD, 0x007A, 0x007F,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from tds565.txt
+
+static const CodePage CODES_TIS620_CODE_PAGE = {
+ CODES_TIS620,
+ {"TIS620", "TIS-620", "TIS620-0", "TIS620.2529-1", "TIS620.2533-0", "TIS620.2533-1", "ISO-IR-166",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07,
+ 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
+ 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17,
+ 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
+ 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
+ 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
+ 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
+ 0x0E38, 0x0E39, 0x0E3A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x0E3F,
+ 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47,
+ 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F,
+ 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57,
+ 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from tis620.txt
+
+static const CodePage CODES_UNKNOWNPLANE_CODE_PAGE = {
+ CODES_UNKNOWNPLANE,
+ {"unknownplane", "unknown-plane",},
+ {
+ 0x0000, 0xF001, 0xF002, 0xF003, 0xF004, 0xF005, 0xF006, 0xF007,
+ 0xF008, 0xF009, 0xF00A, 0xF00B, 0xF00C, 0xF00D, 0xF00E, 0xF00F,
+ 0xF010, 0xF011, 0xF012, 0xF013, 0xF014, 0xF015, 0xF016, 0xF017,
+ 0xF018, 0xF019, 0xF01A, 0xF01B, 0xF01C, 0xF01D, 0xF01E, 0xF01F,
+ 0xF020, 0xF021, 0xF022, 0xF023, 0xF024, 0xF025, 0xF026, 0xF027,
+ 0xF028, 0xF029, 0xF02A, 0xF02B, 0xF02C, 0xF02D, 0xF02E, 0xF02F,
+ 0xF030, 0xF031, 0xF032, 0xF033, 0xF034, 0xF035, 0xF036, 0xF037,
+ 0xF038, 0xF039, 0xF03A, 0xF03B, 0xF03C, 0xF03D, 0xF03E, 0xF03F,
+ 0xF040, 0xF041, 0xF042, 0xF043, 0xF044, 0xF045, 0xF046, 0xF047,
+ 0xF048, 0xF049, 0xF04A, 0xF04B, 0xF04C, 0xF04D, 0xF04E, 0xF04F,
+ 0xF050, 0xF051, 0xF052, 0xF053, 0xF054, 0xF055, 0xF056, 0xF057,
+ 0xF058, 0xF059, 0xF05A, 0xF05B, 0xF05C, 0xF05D, 0xF05E, 0xF05F,
+ 0xF060, 0xF061, 0xF062, 0xF063, 0xF064, 0xF065, 0xF066, 0xF067,
+ 0xF068, 0xF069, 0xF06A, 0xF06B, 0xF06C, 0xF06D, 0xF06E, 0xF06F,
+ 0xF070, 0xF071, 0xF072, 0xF073, 0xF074, 0xF075, 0xF076, 0xF077,
+ 0xF078, 0xF079, 0xF07A, 0xF07B, 0xF07C, 0xF07D, 0xF07E, 0xF07F,
+ 0xF080, 0xF081, 0xF082, 0xF083, 0xF084, 0xF085, 0xF086, 0xF087,
+ 0xF088, 0xF089, 0xF08A, 0xF08B, 0xF08C, 0xF08D, 0xF08E, 0xF08F,
+ 0xF090, 0xF091, 0xF092, 0xF093, 0xF094, 0xF095, 0xF096, 0xF097,
+ 0xF098, 0xF099, 0xF09A, 0xF09B, 0xF09C, 0xF09D, 0xF09E, 0xF09F,
+ 0xF0A0, 0xF0A1, 0xF0A2, 0xF0A3, 0xF0A4, 0xF0A5, 0xF0A6, 0xF0A7,
+ 0xF0A8, 0xF0A9, 0xF0AA, 0xF0AB, 0xF0AC, 0xF0AD, 0xF0AE, 0xF0AF,
+ 0xF0B0, 0xF0B1, 0xF0B2, 0xF0B3, 0xF0B4, 0xF0B5, 0xF0B6, 0xF0B7,
+ 0xF0B8, 0xF0B9, 0xF0BA, 0xF0BB, 0xF0BC, 0xF0BD, 0xF0BE, 0xF0BF,
+ 0xF0C0, 0xF0C1, 0xF0C2, 0xF0C3, 0xF0C4, 0xF0C5, 0xF0C6, 0xF0C7,
+ 0xF0C8, 0xF0C9, 0xF0CA, 0xF0CB, 0xF0CC, 0xF0CD, 0xF0CE, 0xF0CF,
+ 0xF0D0, 0xF0D1, 0xF0D2, 0xF0D3, 0xF0D4, 0xF0D5, 0xF0D6, 0xF0D7,
+ 0xF0D8, 0xF0D9, 0xF0DA, 0xF0DB, 0xF0DC, 0xF0DD, 0xF0DE, 0xF0DF,
+ 0xF0E0, 0xF0E1, 0xF0E2, 0xF0E3, 0xF0E4, 0xF0E5, 0xF0E6, 0xF0E7,
+ 0xF0E8, 0xF0E9, 0xF0EA, 0xF0EB, 0xF0EC, 0xF0ED, 0xF0EE, 0xF0EF,
+ 0xF0F0, 0xF0F1, 0xF0F2, 0xF0F3, 0xF0F4, 0xF0F5, 0xF0F6, 0xF0F7,
+ 0xF0F8, 0xF0F9, 0xF0FA, 0xF0FB, 0xF0FC, 0xF0FD, 0xF0FE, 0xF0FF,
+ },
+ defchars[0],
+}; // generated from unknown.txt
+
+static const CodePage CODES_UTF8_CODE_PAGE = {
+ CODES_UTF8,
+ {"utf-8",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_UTF_16BE_CODE_PAGE = {
+ CODES_UTF_16BE,
+ {"UTF-16BE",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_UTF_16LE_CODE_PAGE = {
+ CODES_UTF_16LE,
+ {"UTF-16LE", "UTF-16",},
+ {},
+ nullptr,
+}; // generated from multibyte.txt
+
+static const CodePage CODES_VISCII_CODE_PAGE = {
+ CODES_VISCII,
+ {"VISCII", "VISCII1.1-1", "CSVISCII",},
+ {
+ 0x0000, 0x0001, 0x1EB2, 0x0003, 0x0004, 0x1EB4, 0x1EAA, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x1EF6, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x1EF8, 0x001A, 0x001B, 0x001C, 0x001D, 0x1EF4, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x1EA0, 0x1EAE, 0x1EB0, 0x1EB6, 0x1EA4, 0x1EA6, 0x1EA8, 0x1EAC,
+ 0x1EBC, 0x1EB8, 0x1EBE, 0x1EC0, 0x1EC2, 0x1EC4, 0x1EC6, 0x1ED0,
+ 0x1ED2, 0x1ED4, 0x1ED6, 0x1ED8, 0x1EE2, 0x1EDA, 0x1EDC, 0x1EDE,
+ 0x1ECA, 0x1ECE, 0x1ECC, 0x1EC8, 0x1EE6, 0x0168, 0x1EE4, 0x1EF2,
+ 0x00D5, 0x1EAF, 0x1EB1, 0x1EB7, 0x1EA5, 0x1EA7, 0x1EA9, 0x1EAD,
+ 0x1EBD, 0x1EB9, 0x1EBF, 0x1EC1, 0x1EC3, 0x1EC5, 0x1EC7, 0x1ED1,
+ 0x1ED3, 0x1ED5, 0x1ED7, 0x1EE0, 0x01A0, 0x1ED9, 0x1EDD, 0x1EDF,
+ 0x1ECB, 0x1EF0, 0x1EE8, 0x1EEA, 0x1EEC, 0x01A1, 0x1EDB, 0x01AF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x1EA2, 0x0102, 0x1EB3, 0x1EB5,
+ 0x00C8, 0x00C9, 0x00CA, 0x1EBA, 0x00CC, 0x00CD, 0x0128, 0x1EF3,
+ 0x0110, 0x1EE9, 0x00D2, 0x00D3, 0x00D4, 0x1EA1, 0x1EF7, 0x1EEB,
+ 0x1EED, 0x00D9, 0x00DA, 0x1EF9, 0x1EF5, 0x00DD, 0x1EE1, 0x01B0,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x1EA3, 0x0103, 0x1EEF, 0x1EAB,
+ 0x00E8, 0x00E9, 0x00EA, 0x1EBB, 0x00EC, 0x00ED, 0x0129, 0x1EC9,
+ 0x0111, 0x1EF1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x1ECF, 0x1ECD,
+ 0x1EE5, 0x00F9, 0x00FA, 0x0169, 0x1EE7, 0x00FD, 0x1EE3, 0x1EEE,
+ },
+ defchars[0],
+}; // generated from viscii.txt
+
+static const CodePage CODES_WIN_CODE_PAGE = {
+ CODES_WIN,
+ {"windows-1251", "cp1251", "1251", "win",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
+ 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0xFFFD, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
+ 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
+ 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
+ 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
+ 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_WINDOWS_1253_CODE_PAGE = {
+ CODES_WINDOWS_1253,
+ {"windows-1253",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0xFFFD, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0xFFFD, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0xFFFD, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7,
+ 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F,
+ 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+ 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
+ 0x03A0, 0x03A1, 0xFFFD, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
+ 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+ 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+ 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+ 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_WINDOWS_1254_CODE_PAGE = {
+ CODES_WINDOWS_1254,
+ {"windows-1254",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0xFFFD, 0xFFFD, 0x0178,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_WINDOWS_1255_CODE_PAGE = {
+ CODES_WINDOWS_1255,
+ {"windows-1255",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AA, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7,
+ 0x05B8, 0x05B9, 0xFFFD, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
+ 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3,
+ 0x05F4, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
+ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+ 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+ 0x05E8, 0x05E9, 0x05EA, 0xFFFD, 0xFFFD, 0x200E, 0x200F, 0xFFFD,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_WINDOWS_1256_CODE_PAGE = {
+ CODES_WINDOWS_1256,
+ {"windows-1256",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688,
+ 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA,
+ 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F,
+ 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
+ 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
+ 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7,
+ 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0641, 0x0642, 0x0643,
+ 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF,
+ 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7,
+ 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_WINDOWS_1257_CODE_PAGE = {
+ CODES_WINDOWS_1257,
+ {"windows-1257",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, 0xFFFD, 0x201A, 0xFFFD, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0xFFFD, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0x00A8, 0x02C7, 0x00B8,
+ 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0xFFFD, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0x00AF, 0x02DB, 0xFFFD,
+ 0x00A0, 0xFFFD, 0x00A2, 0x00A3, 0x00A4, 0xFFFD, 0x00A6, 0x00A7,
+ 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6,
+ 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112,
+ 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B,
+ 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7,
+ 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF,
+ 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113,
+ 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C,
+ 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7,
+ 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_WIN_EAST_CODE_PAGE = {
+ CODES_WIN_EAST,
+ {"windows-1250", "cp1250", "1250", "win-east",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, 0xFFFD, 0x201A, 0xFFFD, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0xFFFD, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179,
+ 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0xFFFD, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A,
+ 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B,
+ 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C,
+ 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
+ 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
+ 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
+ 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
+ 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
+ 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
+ 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
+ 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9,
+ },
+ defchars[0],
+}; // generated from listing.txt
+
+static const CodePage CODES_YANDEX_CODE_PAGE = {
+ CODES_YANDEX,
+ {"yandex",},
+ {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0301, 0x00C4, 0x00D6, 0x00DC, 0x0104, 0x0106, 0x0118, 0x0141,
+ 0x00E0, 0x00E2, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x0490, 0x00AD,
+ 0x00DF, 0x00E4, 0x00F6, 0x00FC, 0x0105, 0x0107, 0x0119, 0x0142,
+ 0x00EB, 0x00EE, 0x00EF, 0x00F4, 0x00F9, 0x00FB, 0x0491, 0x92CF,
+ 0x00A0, 0x0143, 0x00D3, 0x015A, 0x017B, 0x0179, 0x046C, 0x00A7,
+ 0x0401, 0x0462, 0x0472, 0x0474, 0x040E, 0x0406, 0x0404, 0x0407,
+ 0x00B0, 0x0144, 0x00F3, 0x015B, 0x017C, 0x017A, 0x046D, 0x2116,
+ 0x0451, 0x0463, 0x0473, 0x0475, 0x045E, 0x0456, 0x0454, 0x0457,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ },
+ defchars[1],
+}; // generated from yandex.txt
+
+const char defchars[][DEFCHAR_BUF] = {
+ {"\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"}, // generated from ascii_dc.txt
+ {"\077\xA6\xB6\xA6\055\xB6\x9F\x9F\x9F\x9F\x9F\x9F\x9F\200\200\200\071\130\077\071\040\040\n\n\x1A\x1A\x1A\x1A\x1A\x1A\x1A\077\077\055\055\050\042\051\042\042\042\137\052\042\056\055\055\075\055\044\140\xB0\047\047\047\047\047"}, // generated from yandex_dc.txt
+};
+
+const CodePage* const NCodepagePrivate::TCodePageData::AllCodePages[] = {
+ &CODES_ALT_CODE_PAGE,
+ &CODES_ARMSCII_CODE_PAGE,
+ &CODES_ASCII_CODE_PAGE,
+ &CODES_BIG5_CODE_PAGE,
+ &CODES_BIG5_HKSCS_CODE_PAGE,
+ &CODES_BIG5_HKSCS_1999_CODE_PAGE,
+ &CODES_BIG5_HKSCS_2001_CODE_PAGE,
+ &CODES_CP1046_CODE_PAGE,
+ &CODES_CP1124_CODE_PAGE,
+ &CODES_CP1125_CODE_PAGE,
+ &CODES_CP1129_CODE_PAGE,
+ &CODES_CP1131_CODE_PAGE,
+ &CODES_CP1133_CODE_PAGE,
+ &CODES_CP1161_CODE_PAGE,
+ &CODES_CP1162_CODE_PAGE,
+ &CODES_CP1163_CODE_PAGE,
+ &CODES_CP1258_CODE_PAGE,
+ &CODES_CP437_CODE_PAGE,
+ &CODES_CP737_CODE_PAGE,
+ &CODES_CP775_CODE_PAGE,
+ &CODES_CP850_CODE_PAGE,
+ &CODES_CP852_CODE_PAGE,
+ &CODES_CP853_CODE_PAGE,
+ &CODES_CP856_CODE_PAGE,
+ &CODES_CP857_CODE_PAGE,
+ &CODES_CP858_CODE_PAGE,
+ &CODES_CP860_CODE_PAGE,
+ &CODES_CP861_CODE_PAGE,
+ &CODES_CP862_CODE_PAGE,
+ &CODES_CP863_CODE_PAGE,
+ &CODES_CP864_CODE_PAGE,
+ &CODES_CP865_CODE_PAGE,
+ &CODES_CP869_CODE_PAGE,
+ &CODES_CP874_CODE_PAGE,
+ &CODES_CP922_CODE_PAGE,
+ &CODES_CP932_CODE_PAGE,
+ &CODES_CP936_CODE_PAGE,
+ &CODES_CP949_CODE_PAGE,
+ &CODES_CP950_CODE_PAGE,
+ &CODES_EUC_CN_CODE_PAGE,
+ &CODES_EUC_JP_CODE_PAGE,
+ &CODES_EUC_KR_CODE_PAGE,
+ &CODES_EUC_TW_CODE_PAGE,
+ &CODES_GB18030_CODE_PAGE,
+ &CODES_GBK_CODE_PAGE,
+ &CODES_GEO_ITA_CODE_PAGE,
+ &CODES_GEO_PS_CODE_PAGE,
+ &CODES_HP_ROMAN8_CODE_PAGE,
+ &CODES_HZ_CODE_PAGE,
+ &CODES_IBM855_CODE_PAGE,
+ &CODES_ISO646_CN_CODE_PAGE,
+ &CODES_ISO646_JP_CODE_PAGE,
+ &CODES_ISO8859_10_CODE_PAGE,
+ &CODES_ISO8859_11_CODE_PAGE,
+ &CODES_ISO8859_14_CODE_PAGE,
+ &CODES_ISO_2022_CN_CODE_PAGE,
+ &CODES_ISO_2022_CN_EXT_CODE_PAGE,
+ &CODES_ISO_2022_JP_CODE_PAGE,
+ &CODES_ISO_2022_JP_1_CODE_PAGE,
+ &CODES_ISO_2022_JP_2_CODE_PAGE,
+ &CODES_ISO_2022_KR_CODE_PAGE,
+ &CODES_ISO_8859_13_CODE_PAGE,
+ &CODES_ISO_8859_15_CODE_PAGE,
+ &CODES_ISO_8859_16_CODE_PAGE,
+ &CODES_ISO_8859_3_CODE_PAGE,
+ &CODES_ISO_8859_4_CODE_PAGE,
+ &CODES_ISO_8859_6_CODE_PAGE,
+ &CODES_ISO_8859_7_CODE_PAGE,
+ &CODES_ISO_8859_8_CODE_PAGE,
+ &CODES_ISO_8859_9_CODE_PAGE,
+ &CODES_ISO_EAST_CODE_PAGE,
+ &CODES_JISX0201_CODE_PAGE,
+ &CODES_JOHAB_CODE_PAGE,
+ &CODES_KAZWIN_CODE_PAGE,
+ &CODES_KOI8_CODE_PAGE,
+ &CODES_KOI8_T_CODE_PAGE,
+ &CODES_MAC_CODE_PAGE,
+ &CODES_MAC_ARABIC_CODE_PAGE,
+ &CODES_MAC_CENTRALEUROPE_CODE_PAGE,
+ &CODES_MAC_CROATIAN_CODE_PAGE,
+ &CODES_MAC_GREEK_CODE_PAGE,
+ &CODES_MAC_HEBREW_CODE_PAGE,
+ &CODES_MAC_ICELAND_CODE_PAGE,
+ &CODES_MAC_ROMAN_CODE_PAGE,
+ &CODES_MAC_ROMANIA_CODE_PAGE,
+ &CODES_MAC_THAI_CODE_PAGE,
+ &CODES_MAC_TURKISH_CODE_PAGE,
+ &CODES_MAIN_CODE_PAGE,
+ &CODES_MULELAO_CODE_PAGE,
+ &CODES_NEXTSTEP_CODE_PAGE,
+ &CODES_PT154_CODE_PAGE,
+ &CODES_RESERVED_2_CODE_PAGE,
+ &CODES_RESERVED_3_CODE_PAGE,
+ &CODES_RISCOS_LATIN1_CODE_PAGE,
+ &CODES_RK1048_CODE_PAGE,
+ &CODES_SHIFT_JIS_CODE_PAGE,
+ &CODES_TATWIN_CODE_PAGE,
+ &CODES_TCVN_CODE_PAGE,
+ &CODES_TDS565_CODE_PAGE,
+ &CODES_TIS620_CODE_PAGE,
+ &CODES_UNKNOWNPLANE_CODE_PAGE,
+ &CODES_UTF8_CODE_PAGE,
+ &CODES_UTF_16BE_CODE_PAGE,
+ &CODES_UTF_16LE_CODE_PAGE,
+ &CODES_VISCII_CODE_PAGE,
+ &CODES_WIN_CODE_PAGE,
+ &CODES_WINDOWS_1253_CODE_PAGE,
+ &CODES_WINDOWS_1254_CODE_PAGE,
+ &CODES_WINDOWS_1255_CODE_PAGE,
+ &CODES_WINDOWS_1256_CODE_PAGE,
+ &CODES_WINDOWS_1257_CODE_PAGE,
+ &CODES_WIN_EAST_CODE_PAGE,
+ &CODES_YANDEX_CODE_PAGE,
+};
+
+const CodePage& csYandex = CODES_YANDEX_CODE_PAGE;
diff --git a/library/cpp/charset/generated/encrec_data.cpp b/library/cpp/charset/generated/encrec_data.cpp
new file mode 100644
index 0000000000..c1a8579dac
--- /dev/null
+++ b/library/cpp/charset/generated/encrec_data.cpp
@@ -0,0 +1,15082 @@
+#include <library/cpp/charset/codepage.h>
+#include <library/cpp/charset/wide.h>
+
+extern const char defchars[][DEFCHAR_BUF];
+static const char PP_00[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P00 (char*)PP_00
+static const char PP_01[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\000"
+ "\000\000\244\000\246\247\000\251\000\253\254\255\256\000\260\261\000\000"
+ "\000\265\266\267\000\000\000\273\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P01 (char*)PP_01
+static const char PP_02[257] =
+ "\000\250\200\201\252\275\262\257\243\212\214\216\215\000\241\217\300\301"
+ "\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323"
+ "\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\377\000\270\220\203\272\276\263\277\274\232"
+ "\234\236\235\000\242\237\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\245\264\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P02 (char*)PP_02
+static const char PP_03[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\226\227\000\000\000\221\222\202\000\223\224\204\000\206\207\225\000"
+ "\000\000\205\000\000\000\000\000\000\000\000\000\211\000\000\000\000\000"
+ "\000\000\000\213\233\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\210\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P03 (char*)PP_03
+static const char PP_04[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\271\000\000\000\000\000\000\000\000\000\000\000\231\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P04 (char*)PP_04
+static const char PP_05[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\232\000"
+ "\000\000\000\000\000\000\000\277\000\000\000\000\000\000\234\000\235\000"
+ "\000\000\000\236\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\237\000\000\000\000"
+ "\000\000\000\000";
+#define P05 (char*)PP_05
+static const char PP_06[257] =
+ "\000\263\000\000\264\000\266\267\000\000\000\000\000\000\000\000\341\342"
+ "\367\347\344\345\366\372\351\352\353\354\355\356\357\360\362\363\364\365"
+ "\346\350\343\376\373\375\377\371\370\374\340\361\301\302\327\307\304\305"
+ "\326\332\311\312\313\314\315\316\317\320\322\323\324\325\306\310\303\336"
+ "\333\335\337\331\330\334\300\321\000\243\000\000\244\000\246\247\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\275\255\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P06 (char*)PP_06
+static const char PP_07[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\225\226\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\227\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\230\231\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P07 (char*)PP_07
+static const char PP_08[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\223\233\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P08 (char*)PP_08
+static const char PP_09[257] =
+ "\200\000\201\000\000\000\000\000\000\000\000\000\202\000\000\000\203\000"
+ "\000\000\204\000\000\000\205\000\000\000\206\000\000\000\000\000\000\000"
+ "\207\000\000\000\000\000\000\000\210\000\000\000\000\000\000\000\211\000"
+ "\000\000\000\000\000\000\212\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\240\241\242\000\245\000\000\250\251\252"
+ "\253\254\000\256\257\260\261\262\000\265\000\000\270\271\272\273\274\000"
+ "\276\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\213\000\000\000\214\000\000\000\215\000\000\000\216\000\000\000"
+ "\217\220\221\222\000\000\000\000\000\000\000\000\000\000\000\000\224\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P09 (char*)PP_09
+static const char PP_10[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000"
+ "\000\000\375\000\000\000\000\000\000\000\000\000\000\000\370\000\000\000"
+ "\000\000\000\372\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P10 (char*)PP_10
+static const char PP_11[257] =
+ "\000\360\000\000\362\000\000\364\000\000\000\000\000\000\366\000\200\201"
+ "\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223"
+ "\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245"
+ "\246\247\250\251\252\253\254\255\256\257\340\341\342\343\344\345\346\347"
+ "\350\351\352\353\354\355\356\357\000\361\000\000\363\000\000\365\000\000"
+ "\000\000\000\000\367\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P11 (char*)PP_11
+static const char PP_12[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\374\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P12 (char*)PP_12
+static const char PP_13[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\371\373\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P13 (char*)PP_13
+static const char PP_14[257] =
+ "\304\000\263\000\000\000\000\000\000\000\000\000\332\000\000\000\277\000"
+ "\000\000\300\000\000\000\331\000\000\000\303\000\000\000\000\000\000\000"
+ "\264\000\000\000\000\000\000\000\302\000\000\000\000\000\000\000\301\000"
+ "\000\000\000\000\000\000\305\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\315\272\325\326\311\270\267\273\324\323"
+ "\310\276\275\274\306\307\314\265\266\271\321\322\313\317\320\312\330\327"
+ "\316\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\337\000\000\000\334\000\000\000\333\000\000\000\335\000\000\000"
+ "\336\260\261\262\000\000\000\000\000\000\000\000\000\000\000\000\376\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P14 (char*)PP_14
+static const char PP_15[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\312\000"
+ "\000\243\000\000\000\244\000\251\000\307\302\000\250\000\241\261\000\000"
+ "\000\265\246\000\000\000\000\310\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\326\000\000\000\000"
+ "\000\000\000\000";
+#define P15 (char*)PP_15
+static const char PP_16[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\304\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P16 (char*)PP_16
+static const char PP_17[257] =
+ "\000\335\253\256\270\301\247\272\267\274\276\313\315\000\330\332\200\201"
+ "\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223"
+ "\224\225\226\227\230\231\232\233\234\235\236\237\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\337\000\336\254\257\271\317\264\273\300\275"
+ "\277\314\316\000\331\333\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\242\266\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P17 (char*)PP_17
+static const char PP_18[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\320\321\000\000\000\324\325\000\000\322\323\327\000\240\000\245\000"
+ "\000\000\311\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\377\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P18 (char*)PP_18
+static const char PP_19[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\334\000\000\000\000\000\000\000\000\000\000\000\252\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P19 (char*)PP_19
+static const char PP_20[257] =
+ "\000\000\000\000\000\000\306\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\303\000\000\000\260\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\305\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\255\000\000\000\262\263\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P20 (char*)PP_20
+static const char PP_21[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\000"
+ "\000\000\000\000\000\375\000\000\000\000\000\255\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P21 (char*)PP_21
+static const char PP_22[257] =
+ "\000\241\242\243\244\245\246\247\250\251\252\253\254\000\256\257\260\261"
+ "\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303"
+ "\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325"
+ "\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347"
+ "\350\351\352\353\354\355\356\357\000\361\362\363\364\365\366\367\370\371"
+ "\372\373\374\000\376\377\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P22 (char*)PP_22
+static const char PP_23[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\360\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P23 (char*)PP_23
+static const char PP_24[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377";
+#define P24 (char*)PP_24
+static const char PP_25[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\214\234\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\212\232\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\237\000\000\000\000\216"
+ "\236\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\203\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P25 (char*)PP_25
+static const char PP_26[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\210\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\230\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P26 (char*)PP_26
+static const char PP_27[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\226\227\000\000\000\221\222\202\000\223\224\204\000\206\207\225\000"
+ "\000\000\205\000\000\000\000\000\000\000\000\000\211\000\000\000\000\000"
+ "\000\000\000\213\233\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P27 (char*)PP_27
+static const char PP_28[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\231\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P28 (char*)PP_28
+static const char PP_29[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P29 (char*)PP_29
+static const char PP_30[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\000"
+ "\000\000\244\000\246\247\250\251\000\253\254\255\256\000\260\261\000\000"
+ "\264\265\266\267\270\000\000\273\000\000\000\000\000\301\302\000\304\000"
+ "\000\307\000\311\000\313\000\315\316\000\000\000\000\323\324\000\326\327"
+ "\000\000\332\000\334\335\000\337\000\341\342\000\344\000\000\347\000\351"
+ "\000\353\000\355\356\000\000\000\000\363\364\000\366\367\000\000\372\000"
+ "\374\375\000\000";
+#define P30 (char*)PP_30
+static const char PP_31[257] =
+ "\000\000\303\343\245\271\306\346\000\000\000\000\310\350\317\357\320\360"
+ "\000\000\000\000\000\000\312\352\314\354\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\305\345\000\000\274\276\000\000\243\263\321\361\000\000\322"
+ "\362\000\000\000\000\000\000\000\325\365\000\000\300\340\000\000\330\370"
+ "\214\234\000\000\252\272\212\232\336\376\215\235\000\000\000\000\000\000"
+ "\000\000\331\371\333\373\000\000\000\000\000\000\000\217\237\257\277\216"
+ "\236\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P31 (char*)PP_31
+static const char PP_32[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\241\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\242\377\000\262\000\275\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P32 (char*)PP_32
+static const char PP_33[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\000"
+ "\000\000\244\000\000\247\250\000\000\000\000\255\000\000\260\000\000\000"
+ "\264\000\000\000\270\000\000\000\000\000\000\000\000\301\302\000\304\000"
+ "\000\307\000\311\000\313\000\315\316\000\000\000\000\323\324\000\326\327"
+ "\000\000\332\000\334\335\000\337\000\341\342\000\344\000\000\347\000\351"
+ "\000\353\000\355\356\000\000\000\000\363\364\000\366\367\000\000\372\000"
+ "\374\375\000\000";
+#define P33 (char*)PP_33
+static const char PP_34[257] =
+ "\000\000\303\343\241\261\306\346\000\000\000\000\310\350\317\357\320\360"
+ "\000\000\000\000\000\000\312\352\314\354\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\305\345\000\000\245\265\000\000\243\263\321\361\000\000\322"
+ "\362\000\000\000\000\000\000\000\325\365\000\000\300\340\000\000\330\370"
+ "\246\266\000\000\252\272\251\271\336\376\253\273\000\000\000\000\000\000"
+ "\000\000\331\371\333\373\000\000\000\000\000\000\000\254\274\257\277\256"
+ "\276\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P34 (char*)PP_34
+static const char PP_35[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\267\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\242\377\000\262\000\275\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P35 (char*)PP_35
+static const char PP_36[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\000"
+ "\000\000\000\000\000\247\000\000\141\000\000\217\000\000\260\000\062\063"
+ "\000\000\000\000\000\061\157\000\061\061\063\000\101\101\101\101\201\101"
+ "\000\103\105\105\105\105\111\111\111\111\000\116\117\242\117\117\202\000"
+ "\000\125\125\125\203\131\000\220\210\141\211\141\221\141\000\212\213\214"
+ "\215\230\151\151\231\232\000\156\157\262\233\157\222\000\000\234\165\235"
+ "\223\171\000\171";
+#define P36 (char*)PP_36
+static const char PP_37[257] =
+ "\101\141\101\141\204\224\205\225\103\143\103\143\103\143\104\144\000\000"
+ "\105\145\105\145\105\145\206\226\105\145\107\147\107\147\107\147\107\147"
+ "\110\150\000\000\111\151\111\151\111\151\111\151\111\000\111\151\112\152"
+ "\113\153\000\114\154\114\154\114\154\114\154\207\227\241\261\116\156\116"
+ "\156\000\000\000\117\157\117\157\117\157\000\000\122\162\122\162\122\162"
+ "\243\263\123\163\123\163\123\163\124\164\124\164\000\000\125\165\125\165"
+ "\125\165\125\165\125\165\125\165\127\167\131\171\131\245\265\244\264\132"
+ "\172\163\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\117\157"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\125\165\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\104\104"
+ "\144\114\114\154\116\116\156\101\141\111\151\117\157\125\165\125\165\125"
+ "\165\125\165\125\165\000\101\141\101\141\000\000\000\000\107\147\113\153"
+ "\117\157\117\157\000\000\152\104\104\144\107\147\000\000\116\156\101\141"
+ "\000\000\000\000";
+#define P37 (char*)PP_37
+static const char PP_38[257] =
+ "\101\141\101\141\105\145\105\145\111\151\111\151\117\157\117\157\122\162"
+ "\122\162\125\165\125\165\123\163\124\164\000\000\110\150\000\000\000\000"
+ "\000\000\101\141\105\145\117\157\117\157\117\157\117\157\131\171\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\150\000\152\162"
+ "\000\000\000\167\171\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\154\163\170\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P38 (char*)PP_38
+static const char PP_39[257] =
+ "\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P39 (char*)PP_39
+static const char PP_40[257] =
+ "\305\250\000\303\256\000\255\257\000\000\000\000\312\310\254\000\300\301"
+ "\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323"
+ "\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\377\345\270\000\343\276\000\275\277\000\000"
+ "\000\000\352\350\274\000\000\000\251\271\000\000\000\000\000\000\000\000"
+ "\246\266\000\000\000\000\252\272\253\273\253\273\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\216\236\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\306\346\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\300\340\300\340\000\000\305\345"
+ "\000\000\000\000\306\346\307\347\000\000\310\350\310\350\316\356\000\000"
+ "\000\000\335\375\323\363\323\363\323\363\327\367\000\000\333\373\000\000"
+ "\000\000\000\000";
+#define P40 (char*)PP_40
+static const char PP_41[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\101\000\102\000\104\105\000\107\110\111"
+ "\112\113\114\115\116\000\117\000\120\122\124\125\127\141\000\000\000\142"
+ "\144\145\000\000\000\147\000\153\155\000\157\000\000\000\160\164\165\000"
+ "\000\166\000\000\000\000\000\000\151\162\165\166\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\355\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\143\000\000\000\146\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\172\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P41 (char*)PP_41
+static const char PP_42[257] =
+ "\101\141\102\142\102\142\102\142\103\143\104\144\104\144\104\144\104\144"
+ "\104\144\105\145\105\145\105\145\105\145\105\145\106\146\107\147\110\150"
+ "\110\150\110\150\110\150\110\150\111\151\111\151\113\153\113\153\113\153"
+ "\114\154\114\154\114\154\114\154\115\155\115\155\115\155\116\156\116\156"
+ "\116\156\116\156\117\157\117\157\117\157\117\157\120\160\120\160\122\162"
+ "\122\162\122\162\122\162\123\163\123\163\123\163\123\163\123\163\124\164"
+ "\124\164\124\164\124\164\125\165\125\165\125\165\125\165\125\165\126\166"
+ "\126\166\127\167\127\167\127\167\127\167\127\167\130\170\130\170\131\171"
+ "\132\172\132\172\132\172\150\164\167\171\141\163\000\000\000\000\101\141"
+ "\101\141\101\141\101\141\101\141\101\141\101\141\101\141\101\141\101\141"
+ "\101\141\101\141\105\145\105\145\105\145\105\145\105\145\105\145\105\145"
+ "\105\145\111\151\111\151\117\157\117\157\117\157\117\157\117\157\117\157"
+ "\117\157\117\157\117\157\117\157\117\157\117\157\125\165\125\165\125\165"
+ "\125\165\125\165\125\165\125\165\131\171\131\171\131\171\131\171\000\000"
+ "\000\000\000\000";
+#define P42 (char*)PP_42
+static const char PP_43[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\060\151\000\000\064\065\066\067\070\071\000\000\000\000"
+ "\000\156\060\061\062\063\064\065\066\067\070\071\000\000\000\000\000\000"
+ "\141\145\157\170\000\150\153\154\155\156\160\163\164\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P43 (char*)PP_43
+static const char PP_44[257] =
+ "\000\000\103\000\000\000\000\000\000\000\147\110\110\110\150\000\111\111"
+ "\114\154\000\116\267\000\000\120\121\122\122\122\000\000\000\000\000\000"
+ "\132\000\000\000\132\000\113\101\102\103\000\145\105\106\000\115\157\000"
+ "\000\000\000\151\000\000\000\000\000\000\000\000\000\000\000\104\144\145"
+ "\151\152\000\000\000\000\000\000\061\061\061\061\062\061\062\063\064\061"
+ "\065\061\063\065\067\061\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\060\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P44 (char*)PP_44
+static const char PP_45[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\061\062\063\064\065\066\067\070\071\061\061\061"
+ "\061\061\061\061\061\061\061\062\061\062\063\064\065\066\067\070\071\061"
+ "\061\061\061\061\061\061\061\061\061\062\061\062\063\064\065\066\067\070"
+ "\071\061\061\061\061\061\061\061\061\061\061\062\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\060\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P45 (char*)PP_45
+static const char PP_46[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\152\126"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P46 (char*)PP_46
+static const char PP_47[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\062\062\062\062\062\062\062\062\062"
+ "\063\063\063\063\063\063\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\063\063\063"
+ "\063\064\064\064\064\064\064\064\064\064\064\065\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P47 (char*)PP_47
+static const char PP_48[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\237\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P48 (char*)PP_48
+static const char PP_49[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\372\374\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P49 (char*)PP_49
+static const char PP_50[257] =
+ "\146\146\146\146\146\163\163\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P50 (char*)PP_50
+static const char PP_51[257] =
+ "\000\000\042\000\000\000\000\047\000\000\000\000\000\000\000\000\060\061"
+ "\062\063\064\065\066\067\070\071\000\000\000\000\000\000\000\101\102\103"
+ "\104\105\106\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125"
+ "\126\127\130\131\132\000\000\000\000\000\000\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P51 (char*)PP_51
+static const char PP_52[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000"
+ "\000\000\317\000\000\375\000\000\000\256\000\360\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\257\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P52 (char*)PP_52
+static const char PP_53[257] =
+ "\000\205\201\203\207\211\213\215\217\221\223\225\227\000\231\233\241\243"
+ "\354\255\247\251\352\364\270\276\307\321\323\325\327\335\342\344\346\350"
+ "\253\266\245\374\366\372\237\362\356\370\235\340\240\242\353\254\246\250"
+ "\351\363\267\275\306\320\322\324\326\330\341\343\345\347\252\265\244\373"
+ "\365\371\236\361\355\367\234\336\000\204\200\202\206\210\212\214\216\220"
+ "\222\224\226\000\230\232\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P53 (char*)PP_53
+static const char PP_54[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\357\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P54 (char*)PP_54
+static const char PP_55[257] =
+ "\304\000\263\000\000\000\000\000\000\000\000\000\332\000\000\000\277\000"
+ "\000\000\300\000\000\000\331\000\000\000\303\000\000\000\000\000\000\000"
+ "\264\000\000\000\000\000\000\000\302\000\000\000\000\000\000\000\301\000"
+ "\000\000\000\000\000\000\305\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\315\272\000\000\311\000\000\273\000\000"
+ "\310\000\000\274\000\000\314\000\000\271\000\000\313\000\000\312\000\000"
+ "\316\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\337\000\000\000\334\000\000\000\333\000\000\000\000\000\000\000"
+ "\000\260\261\262\000\000\000\000\000\000\000\000\000\000\000\000\376\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P55 (char*)PP_55
+static const char PP_56[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377";
+#define P56 (char*)PP_56
+static const char PP_57[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\230\000\000\000\000\000\000\000\240\000"
+ "\000\000\244\000\246\247\000\251\000\253\254\255\256\000\260\261\000\000"
+ "\000\265\266\267\000\000\000\273\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P57 (char*)PP_57
+static const char PP_58[257] =
+ "\000\250\000\000\252\000\262\257\000\000\000\000\000\000\241\000\300\301"
+ "\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323"
+ "\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\377\000\270\000\000\272\000\263\277\000\000"
+ "\000\000\000\000\242\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\201\203\000\000\243\274\000\000\215\235\000\000\000\000\000\000"
+ "\214\234\000\000\000\000\000\000\000\000\000\000\217\237\200\220\245\264"
+ "\000\000\000\000\000\000\216\236\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\275\276\000\000\000\000\000\000\000\000\000\000\000\000\000\000\212\232"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P58 (char*)PP_58
+static const char PP_59[257] =
+ "\000\250\000\201\252\275\262\257\243\000\000\000\000\000\241\000\300\301"
+ "\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323"
+ "\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\377\000\270\000\203\272\276\263\277\274\000"
+ "\000\000\000\000\242\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\245\264\000\000\000\000\215\235\000\000\000\000\000\000\000\000\000\000"
+ "\216\236\000\000\000\000\000\000\000\000\000\000\214\234\000\000\000\000"
+ "\000\000\000\000\000\000\217\237\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\200\220\000\000\000\000\000\000\000\000\000\000\000\000\000\000\212\232"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P59 (char*)PP_59
+static const char PP_60[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\247\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\246\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P60 (char*)PP_60
+static const char PP_61[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\241\262\264\266\270\272"
+ "\274\276\300\302\304\306\310\312\314\316\320\322\324\326\330\332\334\336"
+ "\340\342\344\346\350\352\354\356\360\362\364\366\370\372\374\000\000\000"
+ "\376\260\257\252\261\000\000\263\265\267\271\273\275\277\301\303\305\307"
+ "\311\313\315\317\321\323\325\327\331\333\335\337\341\343\345\347\351\353"
+ "\355\357\361\363\365\367\371\373\375\242\000\243\255\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P61 (char*)PP_61
+static const char PP_62[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\250\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\256\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P62 (char*)PP_62
+static const char PP_63[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\000\000\000\000\000\000\000\000\000\000\000\215\216\217"
+ "\220\000\000\000\000\000\000\000\000\000\000\000\000\235\236\000\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377";
+#define P63 (char*)PP_63
+static const char PP_64[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\214\234\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\212\232\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\237\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\203\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P64 (char*)PP_64
+static const char PP_65[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\300\301\302\303\304\305\306\307"
+ "\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331"
+ "\332\333\334\335\336\337\340\341\342\343\344\345\346\000\000\000\000\000"
+ "\000\000\000\000";
+#define P65 (char*)PP_65
+static const char PP_66[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\226\227\000\000\000\221\222\202\000\223\224\204\000\206\207\225\000"
+ "\000\000\205\000\000\000\000\000\000\000\000\000\211\000\000\000\000\000"
+ "\000\000\000\213\233\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P66 (char*)PP_66
+static const char PP_67[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\000\000\000\000\000\000\000\000\000\000\000\215\216\217"
+ "\220\000\000\000\000\000\000\000\000\000\000\000\000\235\236\000\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377";
+#define P67 (char*)PP_67
+static const char PP_68[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\300\301\302\303\304\305\306\310"
+ "\311\312\313\314\315\317\320\321\322\323\324\326\327\330\331\332\333\334"
+ "\335\336\337\340\341\343\344\307\316\325\342\345\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P68 (char*)PP_68
+static const char PP_69[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\000"
+ "\000\243\244\000\000\247\250\000\000\000\000\255\000\000\260\000\262\263"
+ "\264\265\000\267\270\000\000\000\000\275\000\000\300\301\302\000\304\000"
+ "\000\307\310\311\312\313\314\315\316\317\000\321\322\323\324\000\326\327"
+ "\000\331\332\333\334\000\000\337\340\341\342\000\344\000\000\347\350\351"
+ "\352\353\354\355\356\357\000\361\362\363\364\000\366\367\000\371\372\373"
+ "\374\000\000\000";
+#define P69 (char*)PP_69
+static const char PP_70[257] =
+ "\000\000\000\000\000\000\000\000\306\346\305\345\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\330\370\253\273\325\365\000\000"
+ "\246\266\241\261\000\000\000\000\000\000\000\000\251\271\000\000\254\274"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\336\376\252\272\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\335\375\000\000\000\000\000\000\000\000\000\000\000\000\000\257\277\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P70 (char*)PP_70
+static const char PP_71[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\242\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P71 (char*)PP_71
+static const char PP_72[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\000"
+ "\000\000\244\000\000\247\250\000\000\000\000\255\000\257\260\000\000\000"
+ "\264\000\000\000\270\000\000\000\000\000\000\000\000\301\302\303\304\305"
+ "\306\000\000\311\000\313\000\315\316\000\000\000\000\000\324\325\326\327"
+ "\330\000\332\333\334\000\000\337\000\341\342\343\344\345\346\000\000\351"
+ "\000\353\000\355\356\000\000\000\000\000\364\365\366\367\370\000\372\373"
+ "\374\000\000\000";
+#define P72 (char*)PP_72
+static const char PP_73[257] =
+ "\300\340\000\000\241\261\000\000\000\000\000\000\310\350\000\000\320\360"
+ "\252\272\000\000\314\354\312\352\000\000\000\000\000\000\000\000\253\273"
+ "\000\000\000\000\245\265\317\357\000\000\307\347\000\000\000\000\000\000"
+ "\323\363\242\000\000\246\266\000\000\000\000\000\000\000\000\321\361\000"
+ "\000\000\275\277\322\362\000\000\000\000\000\000\000\000\243\263\000\000"
+ "\000\000\000\000\000\000\251\271\000\000\000\000\254\274\335\375\336\376"
+ "\000\000\000\000\000\000\331\371\000\000\000\000\000\000\000\000\000\256"
+ "\276\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P73 (char*)PP_73
+static const char PP_74[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\267\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\377\000\262\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P74 (char*)PP_74
+static const char PP_75[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\232\233\234\235\236\237\240\000"
+ "\000\375\244\000\000\000\000\000\000\256\000\000\000\000\000\000\000\000"
+ "\000\374\000\000\000\000\000\257\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\205\000\203\000\000\000\000\207\212\202"
+ "\210\211\000\000\214\213\000\000\000\000\223\000\000\000\000\227\000\226"
+ "\000\000\000\000";
+#define P75 (char*)PP_75
+static const char PP_76[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\254\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\273\000\000\000\277\000\301\302\303"
+ "\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325"
+ "\326\327\330\331\332\000\000\000\000\000\340\341\342\343\344\345\346\347"
+ "\350\351\352\353\354\355\356\357\360\361\362\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P76 (char*)PP_76
+static const char PP_77[257] =
+ "\245\000\200\000\000\000\000\000\000\000\000\000\373\000\000\000\230\000"
+ "\000\000\231\000\000\000\372\000\000\000\243\000\000\000\000\000\000\000"
+ "\201\000\000\000\000\000\000\000\242\000\000\000\000\000\000\000\241\000"
+ "\000\000\000\000\000\000\246\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\264\220\275\276\252\216\215\221\274\272"
+ "\251\225\224\222\247\250\263\204\206\217\270\271\255\266\267\253\371\300"
+ "\265\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\337\000\000\000\334\000\000\000\333\000\000\000\335\000\000\000"
+ "\336\260\261\262\000\000\000\000\000\000\000\000\000\000\000\000\376\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P77 (char*)PP_77
+static const char PP_78[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\000"
+ "\000\243\000\000\246\247\250\251\000\253\254\255\000\000\260\261\262\263"
+ "\000\000\000\267\000\000\000\273\000\275\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P78 (char*)PP_78
+static const char PP_79[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\252\000\000\000"
+ "\000\000\000\000\000\000\264\265\266\000\270\271\272\000\274\000\276\277"
+ "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321"
+ "\000\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343"
+ "\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365"
+ "\366\367\370\371\372\373\374\375\376\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P79 (char*)PP_79
+static const char PP_80[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\257\000\000\241\242\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\244\000\000\245\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P80 (char*)PP_80
+static const char PP_81[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\000"
+ "\242\243\244\245\246\247\250\251\000\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\000\273\274\275\276\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\252"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\272\000\000\000\000"
+ "\000\000\000\000";
+#define P81 (char*)PP_81
+static const char PP_82[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\340\341\342\343\344\345\346\347"
+ "\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371"
+ "\372\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P82 (char*)PP_82
+static const char PP_83[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\375\376\000\000"
+ "\000\000\000\000\000\337\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P83 (char*)PP_83
+static const char PP_84[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\000\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\000\000\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\000\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\000\000\377";
+#define P84 (char*)PP_84
+static const char PP_85[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\320\360\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\335\375\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\336\376\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P85 (char*)PP_85
+static const char PP_86[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\000"
+ "\242\243\244\000\246\247\000\251\000\253\254\255\256\000\260\261\262\263"
+ "\000\265\266\267\000\271\000\273\274\275\276\000\000\000\000\000\304\305"
+ "\257\000\000\311\000\000\000\000\000\000\000\000\000\323\000\325\326\327"
+ "\250\000\000\000\334\000\000\337\000\000\000\000\344\345\277\000\000\351"
+ "\000\000\000\000\000\000\000\000\000\363\000\365\366\367\270\000\000\000"
+ "\374\000\000\000";
+#define P86 (char*)PP_86
+static const char PP_87[257] =
+ "\302\342\000\000\300\340\303\343\000\000\000\000\310\350\000\000\000\000"
+ "\307\347\000\000\313\353\306\346\000\000\000\000\000\000\000\000\314\354"
+ "\000\000\000\000\000\000\316\356\000\000\301\341\000\000\000\000\000\000"
+ "\315\355\000\000\000\317\357\000\000\000\000\331\371\321\361\322\362\000"
+ "\000\000\000\000\324\364\000\000\000\000\000\000\000\000\252\272\000\000"
+ "\332\372\000\000\000\000\320\360\000\000\000\000\000\000\000\000\333\373"
+ "\000\000\000\000\000\000\330\370\000\000\000\000\000\312\352\335\375\336"
+ "\376\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P87 (char*)PP_87
+static const char PP_88[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\377\000\000\264\241\245\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P88 (char*)PP_88
+static const char PP_89[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\000\245\000\247\000\251\252\253\254\255\256\257\260\261\262\263"
+ "\000\265\266\267\000\271\272\273\000\000\000\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377";
+#define P89 (char*)PP_89
+static const char PP_90[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\274\275\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\246\250\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\276\000\000\000\000\264"
+ "\270\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P90 (char*)PP_90
+static const char PP_91[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\244\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P91 (char*)PP_91
+static const char PP_92[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\000"
+ "\000\000\000\000\000\247\000\251\000\253\000\255\000\000\260\261\000\000"
+ "\000\000\266\267\000\000\000\273\000\000\000\000\300\301\302\000\304\000"
+ "\306\307\310\311\312\313\314\315\316\317\000\000\322\323\324\000\326\000"
+ "\000\331\332\333\334\000\000\337\340\341\342\000\344\000\346\347\350\351"
+ "\352\353\354\355\356\357\000\000\362\363\364\000\366\000\000\371\372\373"
+ "\374\000\000\377";
+#define P92 (char*)PP_92
+static const char PP_93[257] =
+ "\000\000\303\343\241\242\305\345\000\000\000\000\262\271\000\000\320\360"
+ "\000\000\000\000\000\000\335\375\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\243\263\321\361\000\000\000"
+ "\000\000\000\000\000\000\000\000\325\365\274\275\000\000\000\000\000\000"
+ "\327\367\000\000\000\000\246\250\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\330\370\000\000\000\000\000\000\276\254\256\257\277\264"
+ "\270\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P93 (char*)PP_93
+static const char PP_94[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\252\272\336\376\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P94 (char*)PP_94
+static const char PP_95[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\265\245\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\244\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P95 (char*)PP_95
+static const char PP_96[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\000"
+ "\000\243\244\245\246\247\250\251\000\253\254\255\256\000\260\261\262\263"
+ "\000\265\266\267\000\000\000\273\000\275\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P96 (char*)PP_96
+static const char PP_97[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\203\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P97 (char*)PP_97
+static const char PP_98[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\264\241\242\000\270\271\272\000\274\000\276\277"
+ "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321"
+ "\000\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343"
+ "\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365"
+ "\366\367\370\371\372\373\374\375\376\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P98 (char*)PP_98
+static const char PP_99[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\226\227\257\000\000\221\222\202\000\223\224\204\000\206\207\225\000"
+ "\000\000\205\000\000\000\000\000\000\000\000\000\211\000\000\000\000\000"
+ "\000\000\000\213\233\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P99 (char*)PP_99
+static const char PP_100[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\000\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\000\000\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\000\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\000\000\377";
+#define P100 (char*)PP_100
+static const char PP_101[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\320\360\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\335\375\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\214\234\000\000\000\000\000\000"
+ "\000\000\000\000\336\376\212\232\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\237\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\203\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P101 (char*)PP_101
+static const char PP_102[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\241"
+ "\242\243\000\245\246\247\250\251\000\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\000\273\274\275\276\277\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\252"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\272\000\000\000\000"
+ "\000\000\000\000";
+#define P102 (char*)PP_102
+static const char PP_103[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\300\301\302\303"
+ "\304\305\306\307\310\311\000\313\314\315\316\317\320\321\322\323\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\340\341\342\343\344\345\346\347"
+ "\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371"
+ "\372\000\000\000\000\000\324\325\326\327\330\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P103 (char*)PP_103
+static const char PP_104[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\375\376\000\000"
+ "\000\226\227\000\000\000\221\222\202\000\223\224\204\000\206\207\225\000"
+ "\000\000\205\000\000\000\000\000\000\000\000\000\211\000\000\000\000\000"
+ "\000\000\000\213\233\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\244\000\200\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P104 (char*)PP_104
+static const char PP_105[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\000"
+ "\242\243\244\245\246\247\250\251\000\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\000\273\274\275\276\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\327"
+ "\000\000\000\000\000\000\000\000\340\000\342\000\000\000\000\347\350\351"
+ "\352\353\000\000\356\357\000\000\000\000\364\000\000\367\000\371\000\373"
+ "\374\000\000\000";
+#define P105 (char*)PP_105
+static const char PP_106[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\214\234\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\203\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P106 (char*)PP_106
+static const char PP_107[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\210\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P107 (char*)PP_107
+static const char PP_108[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\241\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\272\000\000\000\277\000\301\302\303"
+ "\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325"
+ "\326\330\331\332\333\000\000\000\000\000\334\335\336\337\341\343\344\345"
+ "\346\354\355\360\361\362\363\365\366\370\372\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\212\000\000\000\000"
+ "\201\000\000\000\000\000\000\000\215\000\217\000\000\000\000\000\000\000"
+ "\000\232\000\000\000\000\000\000\216\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\230\000\000\000\000\000\220\000\000\000\000"
+ "\000\000\000\000\000\000\237\000\000\000\252\000\000\300\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P108 (char*)PP_108
+static const char PP_109[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\235\236\375\376\000\000"
+ "\000\226\227\000\000\000\221\222\202\000\223\224\204\000\206\207\225\000"
+ "\000\000\205\000\000\000\000\000\000\000\000\000\211\000\000\000\000\000"
+ "\000\000\000\213\233\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P109 (char*)PP_109
+static const char PP_110[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\000"
+ "\242\243\244\000\246\247\215\251\000\253\254\255\256\235\260\261\262\263"
+ "\264\265\266\267\217\271\000\273\274\275\276\000\000\000\000\000\304\305"
+ "\257\000\000\311\000\000\000\000\000\000\000\000\000\323\000\325\326\327"
+ "\250\000\000\000\334\000\000\337\000\000\000\000\344\345\277\000\000\351"
+ "\000\000\000\000\000\000\000\000\000\363\000\365\366\367\270\000\000\000"
+ "\374\000\000\000";
+#define P110 (char*)PP_110
+static const char PP_111[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\216\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\377\000\236\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P111 (char*)PP_111
+static const char PP_112[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\210\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\000"
+ "\000\000\244\000\000\000\000\000\000\000\000\255\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\201"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\202\000\000\000\000"
+ "\000\000\000\000";
+#define P112 (char*)PP_112
+static const char PP_113[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\254\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\273\000\000\000\277\000\301\302\303"
+ "\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325"
+ "\326\327\000\331\332\000\000\000\000\000\340\341\342\343\344\345\346\347"
+ "\350\351\352\353\354\355\356\357\360\361\362\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\260\261\262\263\264\265\266\267\270\271\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P113 (char*)PP_113
+static const char PP_114[257] =
+ "\213\000\212\000\000\000\000\000\000\000\000\000\215\000\000\000\214\000"
+ "\000\000\216\000\000\000\217\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\211\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P114 (char*)PP_114
+static const char PP_115[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\205\204\203\206\243\242\241\245"
+ "\366\000\000\000";
+#define P115 (char*)PP_115
+static const char PP_116[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\207\000\000\000\000\000\224\000\220\000\221\000\222"
+ "\000\223\000\000\334\000\335\000\000\000\200\000\225\246\000\000\336\000"
+ "\000\247\000\000\000\000\000\250\000\000\000\251\000\000\000\252\000\000"
+ "\000\253\000\000\000\256\000\000\000\000\000\000\000\000\000\000\000\257"
+ "\000\000\000\272\000\000\000\274\000\000\000\275\000\000\000\000\000\000"
+ "\000\330\000\000\276\300\333\000\231\232\233\000\000\337\000\000\000\363"
+ "\000\000\000\364\000\000\000\365\000\000\000\373\000\000\000\374\000\376"
+ "\000\000\375\000\000\000\226\000\230\227\000\367\234\370\235\371\236\372"
+ "\237\000\000\000";
+#define P116 (char*)PP_116
+static const char PP_117[257] =
+ "\000\241\242\000\244\245\246\247\250\251\252\253\254\000\256\257\260\261"
+ "\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303"
+ "\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325"
+ "\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347"
+ "\350\351\352\353\354\355\356\357\000\361\362\000\364\365\366\367\370\371"
+ "\372\373\374\000\376\377\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\243\363\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P117 (char*)PP_117
+static const char PP_118[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000"
+ "\000\000\375\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\372\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P118 (char*)PP_118
+static const char PP_119[257] =
+ "\000\360\000\000\364\000\366\370\000\000\000\000\000\000\000\000\200\201"
+ "\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223"
+ "\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245"
+ "\246\247\250\251\252\253\254\255\256\257\340\341\342\343\344\345\346\347"
+ "\350\351\352\353\354\355\356\357\000\361\000\000\365\000\367\371\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\362\363\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P119 (char*)PP_119
+static const char PP_120[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\373\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P120 (char*)PP_120
+static const char PP_121[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\000\251\252\253\254\255\256\257\260\261\262\263"
+ "\000\265\266\267\000\271\272\273\274\275\276\277\300\301\302\000\304\305"
+ "\306\307\310\311\312\313\000\315\316\317\000\321\000\323\324\000\326\327"
+ "\330\331\332\333\334\000\000\337\340\341\342\000\344\345\346\347\350\351"
+ "\352\353\000\355\356\357\000\361\000\363\364\000\366\367\370\371\372\373"
+ "\374\000\000\377";
+#define P121 (char*)PP_121
+static const char PP_122[257] =
+ "\000\000\303\343\000\000\000\000\000\000\000\000\000\000\000\000\320\360"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\270\250\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\264\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\325\365"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\335\375\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P122 (char*)PP_122
+static const char PP_123[257] =
+ "\314\354\000\336\000\000\000\000\000\322\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\362"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P123 (char*)PP_123
+static const char PP_124[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\376\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P124 (char*)PP_124
+static const char PP_125[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000"
+ "\000\000\373\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\372\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P125 (char*)PP_125
+static const char PP_126[257] =
+ "\000\360\000\000\362\000\370\364\000\000\000\000\000\000\366\000\200\201"
+ "\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223"
+ "\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245"
+ "\246\247\250\251\252\253\254\255\256\257\340\341\342\343\344\345\346\347"
+ "\350\351\352\353\354\355\356\357\000\361\000\000\363\000\371\365\000\000"
+ "\000\000\000\000\367\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\374\375\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P126 (char*)PP_126
+static const char PP_127[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\376\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P127 (char*)PP_127
+static const char PP_128[257] =
+ "\304\000\263\000\000\000\000\000\000\000\000\000\332\000\000\000\277\000"
+ "\000\000\300\000\000\000\331\000\000\000\303\000\000\000\000\000\000\000"
+ "\264\000\000\000\000\000\000\000\302\000\000\000\000\000\000\000\301\000"
+ "\000\000\000\000\000\000\305\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\315\272\325\326\311\270\267\273\324\323"
+ "\310\276\275\274\306\307\314\265\266\271\321\322\313\317\320\312\330\327"
+ "\316\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\337\000\000\000\334\000\000\000\333\000\000\000\335\000\000\000"
+ "\336\260\261\262\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P128 (char*)PP_128
+static const char PP_129[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\000"
+ "\374\000\000\000\376\000\000\000\000\000\375\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P129 (char*)PP_129
+static const char PP_130[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\241\242\000\243\000\000\244\245\000\247\000\000\250\000\000"
+ "\000\000\000\000\251\252\253\254\000\255\256\257\260\261\262\263\000\264"
+ "\265\266\000\267\000\270\000\000\246\271\000\272\273\277\300\312\301\302"
+ "\303\304\305\306\307\310\000\313\311\314\000\000\320\321\322\323\324\000"
+ "\333\000\325\326\327\330\331\332\000\000\360\361\362\363\364\365\366\367"
+ "\370\371\000\000\335\336\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P130 (char*)PP_130
+static const char PP_131[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\337\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P131 (char*)PP_131
+static const char PP_132[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000"
+ "\374\000\000\000\376\000\000\000\000\000\375\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P132 (char*)PP_132
+static const char PP_133[257] =
+ "\000\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261"
+ "\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303"
+ "\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325"
+ "\326\327\330\331\332\000\000\000\000\337\340\341\342\343\344\345\346\347"
+ "\240\333\334\335\354\355\356\357\360\361\362\363\364\365\366\367\370\371"
+ "\372\373\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P133 (char*)PP_133
+static const char PP_134[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\336\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P134 (char*)PP_134
+static const char PP_135[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\201\202\203\204\000\206\207\210\211\212\213\214\215\216\217"
+ "\220\000\000\000\000\000\000\000\230\231\232\233\234\235\236\237\240\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P135 (char*)PP_135
+static const char PP_136[257] =
+ "\000\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261"
+ "\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303"
+ "\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325"
+ "\326\327\330\331\332\000\000\000\000\337\340\341\342\343\344\345\346\347"
+ "\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371"
+ "\372\373\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P136 (char*)PP_136
+static const char PP_137[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\226\227\000\000\000\221\222\000\000\223\224\000\000\000\000\225\000"
+ "\000\000\205\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P137 (char*)PP_137
+static const char PP_138[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\000\245\246\247\000\251\252\253\254\255\256\257\260\261\262\263"
+ "\000\265\266\267\000\271\272\273\274\275\276\277\300\301\302\000\304\305"
+ "\306\307\310\311\312\313\000\315\316\317\000\321\000\323\324\000\326\327"
+ "\330\331\332\333\334\000\000\337\340\341\342\000\344\345\346\347\350\351"
+ "\352\353\000\355\356\357\000\361\000\363\364\000\366\367\370\371\372\373"
+ "\374\000\000\377";
+#define P138 (char*)PP_138
+static const char PP_139[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\376\244\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P139 (char*)PP_139
+static const char PP_140[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\000\304\305"
+ "\306\307\310\311\312\313\000\315\316\317\000\321\000\323\324\000\326\327"
+ "\330\331\332\333\334\000\000\337\340\341\342\000\344\345\346\347\350\351"
+ "\352\353\000\355\356\357\000\361\000\363\364\000\366\367\370\371\372\373"
+ "\374\000\000\377";
+#define P140 (char*)PP_140
+static const char PP_141[257] =
+ "\000\000\303\343\000\000\000\000\000\000\000\000\000\000\000\000\320\360"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\214\234\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\237\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\203\000\000\000\000\000\000\000\000\000\000\000\000\000\325\365"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\335\375\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P141 (char*)PP_141
+static const char PP_142[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\226\227\000\000\000\221\222\202\000\223\224\204\000\206\207\225\000"
+ "\000\000\205\000\000\000\000\000\000\000\000\000\211\000\000\000\000\000"
+ "\000\000\000\213\233\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\376\200\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P142 (char*)PP_142
+static const char PP_143[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\255"
+ "\233\234\000\235\000\000\000\000\246\256\252\000\000\000\370\361\375\000"
+ "\000\346\000\372\000\000\247\257\254\253\000\250\000\000\000\000\216\217"
+ "\222\200\000\220\000\000\000\000\000\000\000\245\000\000\000\000\231\000"
+ "\000\000\000\000\232\000\000\341\205\240\203\000\204\206\221\207\212\202"
+ "\210\211\215\241\214\213\000\244\225\242\223\000\224\366\000\227\243\226"
+ "\201\000\000\230";
+#define P143 (char*)PP_143
+static const char PP_144[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\237\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P144 (char*)PP_144
+static const char PP_145[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\342\000\000\000\000\351\000\000\000\000\000\000\000\000\000"
+ "\000\344\000\000\350\000\000\352\000\000\000\000\000\000\000\340\000\000"
+ "\353\356\000\000\000\000\000\000\000\000\000\000\343\000\000\345\347\000"
+ "\355\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P145 (char*)PP_145
+static const char PP_146[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\374\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\236\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P146 (char*)PP_146
+static const char PP_147[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\371\373\000\000\000\354\000\000\000\000\000"
+ "\000\000\000\000\000\357\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\367\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\360\000\000\363\362\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P147 (char*)PP_147
+static const char PP_148[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\251\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\364\365\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P148 (char*)PP_148
+static const char PP_149[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\370\361\375\000"
+ "\000\000\000\372\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\366\000\000\000\000"
+ "\000\000\000\000";
+#define P149 (char*)PP_149
+static const char PP_150[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\352\000\353\354\355\000\356\000\357\360"
+ "\000\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220"
+ "\000\221\222\223\224\225\226\227\364\365\341\342\343\345\000\230\231\232"
+ "\233\234\235\236\237\240\241\242\243\244\245\246\247\250\252\251\253\254"
+ "\255\256\257\340\344\350\346\347\351\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P150 (char*)PP_150
+static const char PP_151[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\374\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P151 (char*)PP_151
+static const char PP_152[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\371\373\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\367\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\363\362\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P152 (char*)PP_152
+static const char PP_153[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000"
+ "\226\234\237\000\247\365\000\250\000\256\252\360\251\000\370\361\375\374"
+ "\000\346\364\372\000\373\000\257\254\253\363\000\000\000\000\000\216\217"
+ "\222\000\000\220\000\000\000\000\000\000\000\000\000\340\000\345\231\236"
+ "\235\000\000\000\232\000\000\341\000\000\000\000\204\206\221\000\000\202"
+ "\000\000\000\000\000\000\000\000\000\242\000\344\224\366\233\000\000\000"
+ "\201\000\000\000";
+#define P153 (char*)PP_153
+static const char PP_154[257] =
+ "\240\203\000\000\265\320\200\207\000\000\000\000\266\321\000\000\000\000"
+ "\355\211\000\000\270\323\267\322\000\000\000\000\000\000\000\000\225\205"
+ "\000\000\000\000\000\000\241\214\000\000\275\324\000\000\000\000\000\000"
+ "\350\351\000\000\000\352\353\000\000\000\000\255\210\343\347\356\354\000"
+ "\000\000\000\000\342\223\000\000\000\000\000\000\000\000\212\213\000\000"
+ "\227\230\000\000\000\000\276\325\000\000\000\000\000\000\000\000\307\327"
+ "\000\000\000\000\000\000\306\326\000\000\000\000\000\215\245\243\244\317"
+ "\330\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P154 (char*)PP_154
+static const char PP_155[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\357\000\000\362\246\367\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P155 (char*)PP_155
+static const char PP_156[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\371\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P156 (char*)PP_156
+static const char PP_157[257] =
+ "\304\000\263\000\000\000\000\000\000\000\000\000\332\000\000\000\277\000"
+ "\000\000\300\000\000\000\331\000\000\000\303\000\000\000\000\000\000\000"
+ "\264\000\000\000\000\000\000\000\302\000\000\000\000\000\000\000\301\000"
+ "\000\000\000\000\000\000\305\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\315\272\000\000\311\000\000\273\000\000"
+ "\310\000\000\274\000\000\314\000\000\271\000\000\313\000\000\312\000\000"
+ "\316\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\337\000\000\000\334\000\000\000\333\000\000\000\335\000\000\000"
+ "\336\260\261\262\000\000\000\000\000\000\000\000\000\000\000\000\376\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P157 (char*)PP_157
+static const char PP_158[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\255"
+ "\275\234\317\276\335\365\371\270\246\256\252\360\251\356\370\361\375\374"
+ "\357\346\364\372\367\373\247\257\254\253\363\250\267\265\266\307\216\217"
+ "\222\200\324\220\322\323\336\326\327\330\321\245\343\340\342\345\231\236"
+ "\235\353\351\352\232\355\350\341\205\240\203\306\204\206\221\207\212\202"
+ "\210\211\215\241\214\213\320\244\225\242\223\344\224\366\233\227\243\226"
+ "\201\354\347\230";
+#define P158 (char*)PP_158
+static const char PP_159[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\325\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\237\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P159 (char*)PP_159
+static const char PP_160[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\362\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P160 (char*)PP_160
+static const char PP_161[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000"
+ "\000\000\317\000\000\365\371\000\000\256\252\360\000\000\370\000\000\000"
+ "\357\000\000\000\367\000\000\257\000\000\000\000\000\265\266\000\216\000"
+ "\000\200\000\220\000\323\000\326\327\000\000\000\000\340\342\000\231\236"
+ "\000\000\351\000\232\355\000\341\000\240\203\000\204\000\000\207\000\202"
+ "\000\211\000\241\214\000\000\000\000\242\223\000\224\366\000\000\243\000"
+ "\201\354\000\000";
+#define P161 (char*)PP_161
+static const char PP_162[257] =
+ "\000\000\306\307\244\245\217\206\000\000\000\000\254\237\322\324\321\320"
+ "\000\000\000\000\000\000\250\251\267\330\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\221\222\000\000\225\226\000\000\235\210\343\344\000\000\325"
+ "\345\000\000\000\000\000\000\000\212\213\000\000\350\352\000\000\374\375"
+ "\227\230\000\000\270\255\346\347\335\356\233\234\000\000\000\000\000\000"
+ "\000\000\336\205\353\373\000\000\000\000\000\000\000\215\253\275\276\246"
+ "\247\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P162 (char*)PP_162
+static const char PP_163[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\363\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\364\372\000\362\000\361\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P163 (char*)PP_163
+static const char PP_164[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000"
+ "\000\234\317\000\000\365\371\000\000\256\000\360\000\000\370\000\375\374"
+ "\357\346\000\000\367\000\000\257\000\253\000\000\267\265\266\000\216\000"
+ "\000\200\324\220\322\323\336\326\327\330\000\245\343\340\342\000\231\236"
+ "\000\353\351\352\232\000\000\341\205\240\203\000\204\000\000\207\212\202"
+ "\210\211\215\241\214\213\000\244\225\242\223\000\224\366\000\227\243\226"
+ "\201\000\000\000";
+#define P164 (char*)PP_164
+static const char PP_165[257] =
+ "\000\000\000\000\000\000\000\000\217\206\222\221\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\235\233\246\247\344\345\000\000"
+ "\250\251\347\350\000\000\000\000\000\000\000\000\230\325\000\000\254\237"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\363\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\306\307\270\255\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\354\355\000\000\000\000\000\000\000\000\000\000\000\000\000\275\276\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P165 (char*)PP_165
+static const char PP_166[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\364\372\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P166 (char*)PP_166
+static const char PP_167[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\362\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P167 (char*)PP_167
+static const char PP_168[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000"
+ "\275\234\317\276\335\365\371\270\000\256\252\360\251\356\370\361\375\374"
+ "\357\346\364\372\367\373\000\257\254\253\363\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\236"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\366\000\000\000\000"
+ "\000\000\000\000";
+#define P168 (char*)PP_168
+static const char PP_169[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\200\201\202\203\204\205\206\207"
+ "\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231"
+ "\232\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P169 (char*)PP_169
+static const char PP_170[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\255"
+ "\275\234\317\276\335\365\371\270\321\256\252\360\251\356\370\361\375\374"
+ "\357\346\364\372\367\373\320\257\254\253\363\250\267\265\266\307\216\217"
+ "\222\200\324\220\322\323\336\326\327\330\000\245\343\340\342\345\231\350"
+ "\235\353\351\352\232\000\000\341\205\240\203\306\204\206\221\207\212\202"
+ "\210\211\354\241\214\213\000\244\225\242\223\344\224\366\233\227\243\226"
+ "\201\000\000\355";
+#define P170 (char*)PP_170
+static const char PP_171[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\246\247\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\230\215\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\236\237\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P171 (char*)PP_171
+static const char PP_172[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\362\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\325\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P172 (char*)PP_172
+static const char PP_173[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\255"
+ "\233\234\000\000\000\000\000\000\246\256\252\000\000\000\370\361\375\000"
+ "\000\346\000\372\000\000\247\257\254\253\000\250\221\206\217\216\000\000"
+ "\000\200\222\220\211\000\230\213\000\000\000\245\251\237\214\231\000\000"
+ "\000\235\226\000\232\000\000\341\205\240\203\204\000\000\000\207\212\202"
+ "\210\000\215\241\000\000\000\244\225\242\223\224\000\366\000\227\243\000"
+ "\201\000\000\000";
+#define P173 (char*)PP_173
+static const char PP_174[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\364\365\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P174 (char*)PP_174
+static const char PP_175[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\255"
+ "\000\234\000\000\000\000\000\000\000\256\252\000\000\000\370\361\375\000"
+ "\000\346\000\372\000\000\000\257\254\253\000\250\000\244\000\000\216\217"
+ "\222\200\000\220\000\000\000\245\000\000\213\000\000\246\000\000\231\000"
+ "\235\000\247\000\232\227\215\341\205\240\203\000\204\206\221\207\212\202"
+ "\210\211\000\241\000\000\214\000\000\242\223\000\224\366\233\000\243\226"
+ "\201\230\225\000";
+#define P175 (char*)PP_175
+static const char PP_176[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\255"
+ "\233\234\000\235\000\000\000\000\246\256\252\000\000\000\370\361\375\000"
+ "\000\346\000\372\000\000\247\257\254\253\000\250\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\245\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\341\000\240\000\000\000\000\000\000\000\000"
+ "\000\000\000\241\000\000\000\244\000\242\000\000\000\366\000\000\243\000"
+ "\000\000\000\000";
+#define P176 (char*)PP_176
+static const char PP_177[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000"
+ "\233\234\230\000\240\217\244\000\000\256\252\000\000\247\370\361\375\246"
+ "\241\346\206\372\245\000\000\257\254\253\255\000\216\000\204\000\000\000"
+ "\000\200\221\220\222\224\000\000\250\225\000\000\000\000\231\000\000\000"
+ "\000\235\000\236\232\000\000\341\205\000\203\000\000\000\000\207\212\202"
+ "\210\211\000\000\214\213\000\000\000\242\223\000\000\366\000\227\243\226"
+ "\201\000\000\000";
+#define P177 (char*)PP_177
+static const char PP_178[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\215\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\374\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P178 (char*)PP_178
+static const char PP_179[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\000\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\000"
+ "\300\243\244\000\333\000\000\000\000\227\334\241\000\000\200\223\000\000"
+ "\000\000\000\201\000\000\000\230\225\224\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\335\000\000\000\000"
+ "\000\000\000\000";
+#define P179 (char*)PP_179
+static const char PP_180[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\220\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\222\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P180 (char*)PP_180
+static const char PP_181[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\254\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\273\000\000\000\277\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\340\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\361\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\260\261\262\263\264\265\266\267\270\271\045\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P181 (char*)PP_181
+static const char PP_182[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\202\203\000\000\000\221\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\226\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P182 (char*)PP_182
+static const char PP_183[257] =
+ "\205\000\206\000\000\000\000\000\000\000\000\000\215\000\000\000\214\000"
+ "\000\000\216\000\000\000\217\000\000\000\212\000\000\000\000\000\000\000"
+ "\210\000\000\000\000\000\000\000\211\000\000\000\000\000\000\000\213\000"
+ "\000\000\000\000\000\000\207\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\204\000\000\000\000\000\000\000\000\000\000\000\000\000\376\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P183 (char*)PP_183
+static const char PP_184[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\360"
+ "\000\000\301\302\242\303\245\304\000\000\000\000\000\306\000\307\250\251"
+ "\000\310\000\311\000\252\000\312\000\253\000\313\000\255\000\314\000\256"
+ "\000\315\000\257\000\316\000\317\000\320\000\321\000\322\000\274\000\323"
+ "\000\275\000\324\000\276\000\325\000\353\000\326\000\327\000\000\000\330"
+ "\000\000\000\337\305\331\354\356\355\332\367\272\000\341\000\370\000\342"
+ "\000\374\000\343\000\373\000\344\000\357\000\345\000\362\000\346\000\363"
+ "\000\347\364\350\000\351\365\375\366\352\000\371\372\231\232\000\000\235"
+ "\236\000\000\000";
+#define P184 (char*)PP_184
+static const char PP_185[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\255"
+ "\000\234\257\000\000\000\000\000\246\256\252\000\000\000\370\361\375\000"
+ "\000\346\000\372\000\000\247\000\254\253\000\250\000\000\000\000\216\217"
+ "\222\200\000\220\000\000\000\000\000\000\000\245\000\000\000\000\231\000"
+ "\235\000\000\000\232\000\000\341\205\240\203\000\204\206\221\207\212\202"
+ "\210\211\215\241\214\213\000\244\225\242\223\000\224\366\233\227\243\226"
+ "\201\000\000\230";
+#define P185 (char*)PP_185
+static const char PP_186[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000"
+ "\000\234\000\000\212\365\371\227\000\256\211\360\000\000\370\361\231\232"
+ "\000\000\000\210\000\000\000\257\000\253\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P186 (char*)PP_186
+static const char PP_187[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\357\367\206\000\215\217\220\000\222\000\225\230"
+ "\241\244\245\246\247\250\251\252\254\255\265\266\267\270\275\276\306\307"
+ "\000\317\320\321\322\323\324\325\221\226\233\235\236\237\374\326\327\330"
+ "\335\336\340\341\342\343\344\345\346\347\350\351\352\353\355\354\356\362"
+ "\363\364\366\372\240\373\242\243\375\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P187 (char*)PP_187
+static const char PP_188[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\216\000\000\213\214\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P188 (char*)PP_188
+static const char PP_189[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P189 (char*)PP_189
+static const char PP_190[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\000\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\000\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\000\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\000\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\000\377";
+#define P190 (char*)PP_190
+static const char PP_191[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\320\360\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\336"
+ "\376\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P191 (char*)PP_191
+static const char PP_192[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\257\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P192 (char*)PP_192
+static const char PP_193[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\270"
+ "\277\273\272\274\000\275\253\000\371\373\000\000\000\260\263\376\000\000"
+ "\250\363\364\362\000\000\372\375\367\370\365\271\241\340\242\341\330\320"
+ "\323\264\243\334\244\245\346\345\246\247\343\266\350\347\337\351\332\000"
+ "\322\255\355\256\333\261\360\336\310\304\300\342\314\324\327\265\311\305"
+ "\301\315\331\325\321\335\344\267\312\306\302\352\316\000\326\313\307\303"
+ "\317\262\361\357";
+#define P193 (char*)PP_193
+static const char PP_194[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\353\354\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\356\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\276\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P194 (char*)PP_194
+static const char PP_195[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\252\000\000\000\000\251\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\254\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P195 (char*)PP_195
+static const char PP_196[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\366\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\257\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P196 (char*)PP_196
+static const char PP_197[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\374\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P197 (char*)PP_197
+static const char PP_198[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\000\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\000\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\044\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P198 (char*)PP_198
+static const char PP_199[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\176\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P199 (char*)PP_199
+static const char PP_200[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\000\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\000\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\134\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P200 (char*)PP_200
+static const char PP_201[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\000"
+ "\000\000\000\000\000\247\000\000\000\000\000\255\000\000\260\000\000\000"
+ "\000\000\000\267\000\000\000\000\000\000\000\000\000\301\302\303\304\305"
+ "\306\000\000\311\000\313\000\315\316\317\320\000\000\323\324\325\326\000"
+ "\330\000\332\333\334\335\336\337\000\341\342\343\344\345\346\000\000\351"
+ "\000\353\000\355\356\357\360\000\000\363\364\365\366\000\370\000\372\373"
+ "\374\375\376\000";
+#define P201 (char*)PP_201
+static const char PP_202[257] =
+ "\300\340\000\000\241\261\000\000\000\000\000\000\310\350\000\000\251\271"
+ "\242\262\000\000\314\354\312\352\000\000\000\000\000\000\000\000\243\263"
+ "\000\000\000\000\245\265\244\264\000\000\307\347\000\000\000\000\000\000"
+ "\246\266\377\000\000\250\270\000\000\000\000\000\000\000\000\321\361\000"
+ "\000\000\257\277\322\362\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\252\272\000\000\000\000\253\273\327\367\256\276"
+ "\000\000\000\000\000\000\331\371\000\000\000\000\000\000\000\000\000\254"
+ "\274\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P202 (char*)PP_202
+static const char PP_203[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\275\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P203 (char*)PP_203
+static const char PP_204[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P204 (char*)PP_204
+static const char PP_205[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\000"
+ "\000\243\000\000\000\247\000\251\000\000\000\255\256\000\000\000\000\000"
+ "\000\000\266\000\000\000\000\000\000\000\000\000\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\000\321\322\323\324\325\326\000"
+ "\330\331\332\333\334\335\000\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\000\361\362\363\364\365\366\000\370\371\372\373"
+ "\374\375\000\377";
+#define P205 (char*)PP_205
+static const char PP_206[257] =
+ "\000\000\000\000\000\000\000\000\000\000\244\245\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\262\263\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\320\360\336\376\257\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P206 (char*)PP_206
+static const char PP_207[257] =
+ "\000\000\241\242\000\000\000\000\000\000\246\253\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\260\261\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\264\265\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\267\271\000\000"
+ "\000\000\000\000\000\000\273\277\000\000\000\000\000\000\000\000\327\367"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\250\270\252\272\275\276\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\254\274\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P207 (char*)PP_207
+static const char PP_208[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\241\242\243\244\245\246\247\250\251\252\253"
+ "\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275"
+ "\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
+ "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P208 (char*)PP_208
+static const char PP_209[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\244\000\246\247\000\277\000\253\254\255\256\000\260\261\262\000"
+ "\000\000\266\267\000\000\000\273\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P209 (char*)PP_209
+static const char PP_210[257] =
+ "\000\263\000\000\000\000\000\000\000\000\000\000\000\000\000\000\341\342"
+ "\367\347\344\345\366\372\351\352\353\354\355\356\357\360\362\363\364\365"
+ "\346\350\343\376\373\375\377\371\370\374\340\361\301\302\327\307\304\305"
+ "\326\332\311\312\313\314\315\316\317\320\322\323\324\325\306\310\303\336"
+ "\333\335\337\331\330\334\300\321\000\243\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\203\201\000\000\000\000\000\000\220\200\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\214\212"
+ "\000\000\216\215\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\265\245\000\000\000\000\000\000"
+ "\000\000\000\000\242\241\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P210 (char*)PP_210
+static const char PP_211[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\201\000"
+ "\000\000\000\000\000\000\000\000\000\214\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\230\000\000\000\000\000\000\000\000\200\000"
+ "\000\202\000\203\000\000\000\000\000\000\000\204\000\000\000\000\205\000"
+ "\000\000\000\000\206\000\000\000\210\207\211\000\212\000\000\215\217\216"
+ "\220\221\000\222\224\225\000\226\000\227\231\000\232\233\000\235\234\236"
+ "\237\000\000\000";
+#define P211 (char*)PP_211
+static const char PP_212[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\254\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\273\000\000\000\277\000\301\302\303"
+ "\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325"
+ "\326\327\330\331\332\000\000\000\000\000\340\341\342\343\344\345\346\347"
+ "\350\351\352\353\354\355\356\357\360\361\362\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\260\261\262\263\264\265\266\267\270\271\245\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\364\000\000\000\000"
+ "\363\000\000\000\000\000\000\000\365\000\371\000\000\000\000\000\000\000"
+ "\000\372\000\000\000\000\000\000\376\000\000\000\000\000\000\000\000\000"
+ "\000\000\367\000\000\000\000\000\000\000\000\000\000\370\000\000\000\000"
+ "\000\000\000\000\000\000\213\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\366\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P212 (char*)PP_212
+static const char PP_213[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\223\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P213 (char*)PP_213
+static const char PP_214[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\300\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P214 (char*)PP_214
+static const char PP_215[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\312\000"
+ "\000\243\000\000\000\244\254\251\000\307\302\000\250\000\241\000\000\000"
+ "\000\000\246\000\000\000\000\310\000\000\000\000\000\347\000\000\200\000"
+ "\000\000\000\203\000\000\000\352\000\000\000\000\000\356\357\315\205\000"
+ "\000\000\362\000\206\370\000\247\000\207\000\000\212\000\000\000\000\216"
+ "\000\000\000\222\000\000\000\000\000\227\231\233\232\326\000\000\234\000"
+ "\237\371\000\000";
+#define P215 (char*)PP_215
+static const char PP_216[257] =
+ "\201\202\000\000\204\210\214\215\000\000\000\000\211\213\221\223\000\000"
+ "\224\225\000\000\226\230\242\253\235\236\000\000\000\000\000\000\376\256"
+ "\000\000\000\000\000\000\261\264\000\000\257\260\000\000\000\000\000\000"
+ "\265\372\000\275\276\271\272\273\274\000\000\374\270\301\304\277\300\305"
+ "\313\000\000\000\317\330\000\000\314\316\000\000\331\332\337\340\333\336"
+ "\345\346\000\000\000\000\341\344\000\000\350\351\000\000\000\000\355\360"
+ "\000\000\361\363\364\365\366\367\000\000\000\000\000\217\220\373\375\353"
+ "\354\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P216 (char*)PP_216
+static const char PP_217[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P217 (char*)PP_217
+static const char PP_218[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\320\321\000\000\000\324\325\342\000\322\323\343\000\240\000\245\000"
+ "\000\000\311\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\334\335\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P218 (char*)PP_218
+static const char PP_219[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\252\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P219 (char*)PP_219
+static const char PP_220[257] =
+ "\000\000\266\000\000\000\306\000\000\000\000\000\000\000\000\000\000\267"
+ "\000\000\000\000\000\000\000\000\303\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\255\000\000\000\262\263\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P220 (char*)PP_220
+static const char PP_221[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\327\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P221 (char*)PP_221
+static const char PP_222[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\312\301"
+ "\242\243\000\000\000\244\254\331\273\307\302\000\250\370\241\261\000\000"
+ "\253\265\246\341\374\000\274\337\000\000\000\300\313\347\345\314\200\201"
+ "\336\202\351\203\375\372\355\352\353\354\000\204\361\356\357\315\205\000"
+ "\257\364\362\363\206\000\000\247\210\207\211\213\212\214\376\215\217\216"
+ "\220\221\223\222\224\225\000\226\230\227\231\233\232\326\277\235\234\236"
+ "\237\000\000\000";
+#define P222 (char*)PP_222
+static const char PP_223[257] =
+ "\000\000\000\000\000\000\306\346\000\000\000\000\310\350\000\000\320\360"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\365\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\316\317\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\251\271\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\256"
+ "\276\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\304\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P223 (char*)PP_223
+static const char PP_224[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\366\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\373\000\367\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P224 (char*)PP_224
+static const char PP_225[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\275\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\371\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P225 (char*)PP_225
+static const char PP_226[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\340\321\000\000\000\324\325\342\000\322\323\343\000\240\000\245\000"
+ "\000\000\311\000\000\000\000\000\000\000\000\000\344\000\000\000\000\000"
+ "\000\000\000\334\335\000\000\000\000\000\000\000\000\000\332\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\333\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P226 (char*)PP_226
+static const char PP_227[257] =
+ "\000\000\266\000\000\000\264\000\000\000\000\000\000\000\000\270\000\267"
+ "\000\000\000\000\000\000\000\000\303\000\000\000\260\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\272\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\305\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\255\000\000\000\262\263\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P227 (char*)PP_227
+static const char PP_228[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\330";
+#define P228 (char*)PP_228
+static const char PP_229[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\312\000"
+ "\000\222\000\264\233\254\214\251\000\307\302\377\250\000\256\261\202\204"
+ "\000\000\000\257\000\201\000\310\000\227\000\000\000\000\000\000\200\000"
+ "\000\000\000\203\000\000\000\000\000\000\000\000\000\000\000\000\205\000"
+ "\000\000\000\000\206\000\000\247\210\000\211\000\212\000\000\215\217\216"
+ "\220\221\000\000\224\225\000\000\000\000\231\000\232\326\000\235\000\236"
+ "\237\000\000\000";
+#define P229 (char*)PP_229
+static const char PP_230[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\317\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P230 (char*)PP_230
+static const char PP_231[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\213\207\315\000\316\327\330\000\331\000\332\337"
+ "\375\260\265\241\242\266\267\270\243\271\272\244\273\301\245\303\246\304"
+ "\000\252\306\313\274\314\276\277\253\275\300\333\334\335\376\341\342\347"
+ "\344\345\372\350\365\351\353\354\355\356\352\357\360\362\367\363\364\371"
+ "\346\370\343\366\373\374\336\340\361\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P231 (char*)PP_231
+static const char PP_232[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\320\000\321\000\000\324\325\000\000\322\323\000\000\240\000\226\000"
+ "\000\000\311\000\000\000\000\000\000\000\000\000\230\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\234\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P232 (char*)PP_232
+static const char PP_233[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\223\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P233 (char*)PP_233
+static const char PP_234[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\305\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\255\000\000\000\262\263\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P234 (char*)PP_234
+static const char PP_235[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\312\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\200\000"
+ "\000\202\000\203\000\000\000\000\000\000\000\204\000\000\000\000\205\000"
+ "\000\000\000\000\206\000\000\000\210\207\211\213\212\214\000\215\217\216"
+ "\220\221\223\222\224\225\000\226\230\227\231\233\232\000\000\235\234\236"
+ "\237\000\000\000";
+#define P235 (char*)PP_235
+static const char PP_236[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\331\333\332\337"
+ "\317\315\316\314\313\335\000\334\306\000\000\330\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\340\341\342\343\344\345\346\347"
+ "\350\351\352\353\300\355\356\357\360\361\362\363\364\365\366\367\370\371"
+ "\372\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P236 (char*)PP_236
+static const char PP_237[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\320\321\000\000\000\324\325\000\000\322\323\301\000\000\000\000\000"
+ "\000\000\311\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\246\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P237 (char*)PP_237
+static const char PP_238[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\302\303\304\305\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P238 (char*)PP_238
+static const char PP_239[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\201\000\000\000\000"
+ "\000\000\000\000\000\000\326\327\000\000\000\000\000\000\000\000\000\310"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\307\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P239 (char*)PP_239
+static const char PP_240[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\312\301"
+ "\242\243\000\264\000\244\254\251\273\307\302\000\250\370\241\261\000\000"
+ "\253\265\246\341\374\000\274\310\000\000\000\300\313\347\345\314\200\201"
+ "\256\202\351\203\346\350\355\352\353\354\334\204\361\356\357\315\205\000"
+ "\257\364\362\363\206\240\336\247\210\207\211\213\212\214\276\215\217\216"
+ "\220\221\223\222\224\225\335\226\230\227\231\233\232\326\277\235\234\236"
+ "\237\340\337\330";
+#define P240 (char*)PP_240
+static const char PP_241[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\365\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\316\317\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\331\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\304\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P241 (char*)PP_241
+static const char PP_242[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\366\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\371\372\373\376\367\375\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P242 (char*)PP_242
+static const char PP_243[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\275\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\271\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P243 (char*)PP_243
+static const char PP_244[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\320\321\000\000\000\324\325\342\000\322\323\343\000\000\000\245\000"
+ "\000\000\311\000\000\000\000\000\000\000\000\000\344\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\332\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\333\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P244 (char*)PP_244
+static const char PP_245[257] =
+ "\000\000\266\000\000\000\306\000\000\000\000\000\000\000\000\270\000\267"
+ "\000\000\000\000\000\000\000\000\303\000\000\000\260\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\272\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\305\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\255\000\000\000\262\263\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P245 (char*)PP_245
+static const char PP_246[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\360";
+#define P246 (char*)PP_246
+static const char PP_247[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\312\301"
+ "\242\243\000\264\000\244\254\251\273\307\302\000\250\370\241\261\000\000"
+ "\253\265\246\341\374\000\274\310\000\000\000\300\313\347\345\314\200\201"
+ "\000\202\351\203\346\350\355\352\353\354\000\204\361\356\357\315\205\000"
+ "\000\364\362\363\206\000\000\247\210\207\211\213\212\214\000\215\217\216"
+ "\220\221\223\222\224\225\000\226\230\227\231\233\232\326\000\235\234\236"
+ "\237\000\000\330";
+#define P247 (char*)PP_247
+static const char PP_248[257] =
+ "\000\000\256\276\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\365\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\316\317\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\331\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\304\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P248 (char*)PP_248
+static const char PP_249[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\257\277\336\337\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\366\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\371\372\373\376\367\375\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P249 (char*)PP_249
+static const char PP_250[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\320\321\000\000\000\324\325\342\000\322\323\343\000\240\340\245\000"
+ "\000\000\311\000\000\000\000\000\000\000\000\000\344\000\000\000\000\000"
+ "\000\000\000\334\335\000\000\000\000\000\000\000\000\000\332\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\333\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P250 (char*)PP_250
+static const char PP_251[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\312\301"
+ "\242\243\000\264\000\244\254\251\273\307\302\000\250\370\241\261\000\000"
+ "\253\265\246\341\374\000\274\310\000\000\000\300\313\347\345\314\200\201"
+ "\256\202\351\203\346\350\355\352\353\354\000\204\361\356\357\315\205\000"
+ "\257\364\362\363\206\000\000\247\210\207\211\213\212\214\276\215\217\216"
+ "\220\221\223\222\224\225\000\226\230\227\231\233\232\326\277\235\234\236"
+ "\237\000\000\330";
+#define P251 (char*)PP_251
+static const char PP_252[257] =
+ "\000\336\337\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P252 (char*)PP_252
+static const char PP_253[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\000"
+ "\000\000\000\000\000\000\000\373\000\200\000\000\372\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\201\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P253 (char*)PP_253
+static const char PP_254[257] =
+ "\000\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261"
+ "\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303"
+ "\304\305\306\307\310\311\312\313\314\315\316\317\320\222\322\323\224\225"
+ "\226\227\330\331\332\000\000\000\000\337\340\341\342\343\344\345\346\223"
+ "\203\204\205\206\207\217\000\357\360\361\362\363\364\365\366\367\370\371"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P254 (char*)PP_254
+static const char PP_255[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\334\000\000\000\000\000\000"
+ "\000\335\336\000\000\000\235\236\000\000\215\216\000\000\000\000\221\000"
+ "\000\000\202\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\333\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P255 (char*)PP_255
+static const char PP_256[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\356\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P256 (char*)PP_256
+static const char PP_257[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\332\333\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\334\335\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\316\317\000\000\000\000\000\000"
+ "\000\000\000\000\336\337\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\331\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\304\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P257 (char*)PP_257
+static const char PP_258[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\320\321\000\000\000\324\325\342\000\322\323\343\000\240\340\245\000"
+ "\000\000\311\000\000\000\000\000\000\000\000\000\344\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P258 (char*)PP_258
+static const char PP_259[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\365\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\360";
+#define P259 (char*)PP_259
+static const char PP_260[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\241\242\000\244\000\000\247\250\000\252\000\000\255\000\000"
+ "\000\000\000\000\264\265\266\267\000\271\272\273\274\275\276\277\000\301"
+ "\302\303\000\305\000\307\000\000\312\313\000\315\316\317\320\321\322\323"
+ "\324\325\326\327\330\331\000\333\334\335\000\000\340\341\342\343\344\000"
+ "\346\000\350\351\352\353\354\355\000\000\360\361\362\363\364\365\366\367"
+ "\370\371\000\000\374\375\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P260 (char*)PP_260
+static const char PP_261[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\200\241"
+ "\242\243\250\245\265\247\310\240\343\253\276\000\260\305\000\321\311\314"
+ "\302\235\266\264\313\300\353\273\322\323\324\277\201\202\203\204\205\206"
+ "\341\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\236"
+ "\351\227\230\231\232\233\234\373\325\326\327\330\331\332\361\333\334\335"
+ "\336\337\340\342\344\345\346\347\354\355\356\357\360\237\371\362\363\364"
+ "\366\367\374\375";
+#define P261 (char*)PP_261
+static const char PP_262[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\365\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\350\370\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\352\372\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\246\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P262 (char*)PP_262
+static const char PP_263[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\303\317\000\000\000\301\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\306\307\312\316\304\315\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P263 (char*)PP_263
+static const char PP_264[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\261\320\000\000\000\000\251\270\000\252\272\271\000\262\263\267\000"
+ "\000\000\274\000\000\000\000\000\000\000\000\000\275\000\000\000\000\000"
+ "\000\000\000\254\255\000\000\000\000\000\000\000\000\000\244\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P264 (char*)PP_264
+static const char PP_265[257] =
+ "\000\256\257\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P265 (char*)PP_265
+static const char PP_266[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\000"
+ "\000\000\000\000\000\247\000\251\000\253\254\000\256\000\260\000\000\000"
+ "\000\000\266\267\000\000\000\273\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P266 (char*)PP_266
+static const char PP_267[257] =
+ "\000\250\000\000\000\000\262\000\243\000\000\000\000\000\241\000\300\301"
+ "\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323"
+ "\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\377\000\270\000\000\000\000\263\000\274\000"
+ "\000\000\000\000\242\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\201\203\000\000\200\220\245\264\215\235\257\277\000\000\212\232"
+ "\214\234\000\000\000\000\000\000\275\276\000\000\207\211\246\261\210\230"
+ "\000\000\206\231\217\237\216\236\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\252\272\000\000\000\000\000\000\000\000\213\233\000\000\000\000\244\265"
+ "\000\000\000\000\202\255\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P267 (char*)PP_267
+static const char PP_268[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\226\227\000\000\000\221\222\000\000\223\224\204\000\000\000\225\000"
+ "\000\000\205\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P268 (char*)PP_268
+static const char PP_269[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\271\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P269 (char*)PP_269
+static const char PP_270[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\203\000\000\000\207\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377";
+#define P270 (char*)PP_270
+static const char PP_271[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\232\233\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\201\202\205\206\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P271 (char*)PP_271
+static const char PP_272[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\227\230\000\000\000\220\221\000\000\224\225\226\000\234\235\217\000"
+ "\000\000\214\000\000\000\000\000\000\000\000\000\216\000\000\000\000\000"
+ "\000\000\000\222\223\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P272 (char*)PP_272
+static const char PP_273[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\215\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\210\213\211\212"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P273 (char*)PP_273
+static const char PP_274[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\231\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P274 (char*)PP_274
+static const char PP_275[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\204\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P275 (char*)PP_275
+static const char PP_276[257] =
+ "\000\236\237\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P276 (char*)PP_276
+static const char PP_277[257] =
+ "\000\250\200\201\000\000\262\000\000\212\214\000\000\000\000\217\300\301"
+ "\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323"
+ "\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\377\000\270\220\203\000\000\263\000\000\232"
+ "\234\000\000\000\000\237\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\252\272\000\000\000\000\000\000\215\235\000\000\000\000\000\000"
+ "\275\276\000\000\000\000\000\000\000\000\000\000\257\277\241\242\000\000"
+ "\000\000\000\000\000\000\216\236\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\243\274\000\000\000\000\000\000\000\000\000\000\000\000\000\000\245\264"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P277 (char*)PP_277
+static const char PP_278[257] =
+ "\000\000\000\003\000\000\000\007\010\011\012\013\014\015\016\017\020\000"
+ "\000\000\000\000\000\000\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\240\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\200\203\242\202\000\000"
+ "\000\000\207\212\243\000\215\220\000\000\000\000\222\225\244\224\000\000"
+ "\000\235\001\000\000\026\000\000\265\270\251\267\000\000\000\000\314\320"
+ "\252\000\327\335\000\000\000\000\337\343\253\342\000\000\000\357\363\000"
+ "\000\375\000\000";
+#define P278 (char*)PP_278
+static const char PP_279[257] =
+ "\000\000\241\250\000\000\000\000\000\000\000\000\000\000\000\000\247\256"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\217\334\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\237\362\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\245\254"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\246\255\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P279 (char*)PP_279
+static const char PP_280[257] =
+ "\260\263\000\262\000\000\000\000\000\261\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\264"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P280 (char*)PP_280
+static const char PP_281[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\204\271"
+ "\201\266\304\312\301\307\302\310\303\311\206\313\300\276\257\273\272\274"
+ "\277\275\205\306\213\321\210\316\211\317\332\325\305\322\315\323\331\324"
+ "\214\326\216\330\221\336\226\344\223\341\377\350\333\345\340\346\360\347"
+ "\227\351\233\355\230\352\231\353\232\354\234\356\002\364\236\361\021\370"
+ "\004\365\005\366\006\367\022\371\023\372\027\376\024\373\025\374\000\000"
+ "\000\000\000\000";
+#define P281 (char*)PP_281
+static const char PP_282[257] =
+ "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\000\104\105\107\110"
+ "\111\112\113\115\116\117\120\122\124\000\125\126\130\131\000\133\000\134"
+ "\136\000\000\000\000\137\000\141\142\000\144\145\147\150\151\152\153\155"
+ "\156\157\160\162\164\000\165\166\170\171\000\173\000\174\176\000\000\000"
+ "\000\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\106\000"
+ "\000\103\000\000\000\000\000\000\000\000\000\000\000\000\000\000\123\000"
+ "\000\000\000\000\132\135\000\000\000\000\000\000\146\000\000\143\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\163\000\000\000\000\000"
+ "\172\175\000\000";
+#define P282 (char*)PP_282
+static const char PP_283[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\121"
+ "\161\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\127\167\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\114"
+ "\154\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P283 (char*)PP_283
+static const char PP_284[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\140\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P284 (char*)PP_284
+static const char PP_285[257] =
+ "\000\001\000\003\004\000\000\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\000\025\026\027\030\000\032\033\034\035\000\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\300\301\302\303\000\000"
+ "\000\000\310\311\312\000\314\315\000\000\000\000\322\323\324\240\000\000"
+ "\000\331\332\000\000\335\000\000\340\341\342\343\000\000\000\000\350\351"
+ "\352\000\354\355\000\000\000\000\362\363\364\365\000\000\000\371\372\000"
+ "\000\375\000\000";
+#define P285 (char*)PP_285
+static const char PP_286[257] =
+ "\000\000\305\345\000\000\000\000\000\000\000\000\000\000\000\000\320\360"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\316\356\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\235\373\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\264\275"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\277\337\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000";
+#define P286 (char*)PP_286
+static const char PP_287[257] =
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\200\325"
+ "\304\344\204\244\205\245\206\246\006\347\207\247\201\241\202\242\002\306"
+ "\005\307\203\243\211\251\313\353\210\250\212\252\213\253\214\254\215\255"
+ "\216\256\233\357\230\270\232\367\231\366\217\257\220\260\221\261\222\262"
+ "\223\265\225\276\226\266\227\267\263\336\224\376\236\370\234\374\272\321"
+ "\273\327\274\330\377\346\271\361\237\317\036\334\024\326\031\333\000\000"
+ "\000\000\000\000";
+#define P287 (char*)PP_287
+
+static const Encoder encoder_00 = { //windows-1251
+ {
+ P01, P00, P00, P00, P02, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P03, P04, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_01 = { //KOI8-U
+ {
+ P05, P00, P00, P00, P06, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P07, P08, P00, P09, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_02 = { //IBM866
+ {
+ P10, P00, P00, P00, P11, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P12, P13, P00, P00, P14, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_03 = { //MacCyrillic
+ {
+ P15, P16, P00, P00, P17, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P18, P19, P20, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_04 = { //ISO-8859-5
+ {
+ P21, P00, P00, P00, P22, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P23, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_05 = { //windows-1252
+ {
+ P24, P25, P26, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P27, P28, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_06 = { //reserved3
+ {
+ P29, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_07 = { //windows-1250
+ {
+ P30, P31, P32, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P27, P28, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_08 = { //iso-2
+ {
+ P33, P34, P35, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_09 = { //yandex
+ {
+ P36, P37, P38, P39, P40, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P41, P42, P00,
+ P43, P44, P00, P00, P45, P00, P00, P00,
+ P00, P00, P00, P00, P46, P00, P00, P00,
+ P00, P00, P47, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P48, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P49, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P50, P00, P00, P00, P51,
+ },
+ defchars[1],
+ P00,
+};
+
+static const Encoder encoder_12 = { //IBM855
+ {
+ P52, P00, P00, P00, P53, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P54, P00, P00, P00, P55, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_14 = { //unknownplane
+ {
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P56, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_15 = { //windows-1251-k
+ {
+ P57, P00, P00, P00, P58, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P03, P04, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_16 = { //windows-1251-t
+ {
+ P57, P00, P00, P00, P59, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P03, P04, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_17 = { //armscii
+ {
+ P60, P00, P00, P00, P00, P61, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P62, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_18 = { //geo-ita
+ {
+ P63, P64, P26, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P65, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P66, P28, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_19 = { //geo-ps
+ {
+ P67, P64, P26, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P68, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P66, P28, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_20 = { //iso-8859-3
+ {
+ P69, P70, P71, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_21 = { //iso-8859-4
+ {
+ P72, P73, P74, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_22 = { //iso-8859-6
+ {
+ P75, P00, P00, P00, P00, P00, P76, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P77, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_23 = { //iso-8859-7
+ {
+ P78, P00, P00, P79, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P80, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_24 = { //iso-8859-8
+ {
+ P81, P00, P00, P00, P00, P82, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P83, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_25 = { //iso-8859-9
+ {
+ P84, P85, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_26 = { //iso-8859-13
+ {
+ P86, P87, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P88, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_27 = { //iso-8859-15
+ {
+ P89, P90, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P91, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_28 = { //iso-8859-16
+ {
+ P92, P93, P94, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P95, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_29 = { //windows-1253
+ {
+ P96, P97, P00, P98, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P99, P28, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_30 = { //windows-1254
+ {
+ P100, P101, P26, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P27, P28, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_31 = { //windows-1255
+ {
+ P102, P97, P26, P00, P00, P103, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P104, P28, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_32 = { //windows-1256
+ {
+ P105, P106, P107, P00, P00, P00, P108, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P109, P28, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_33 = { //windows-1257
+ {
+ P110, P87, P111, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P27, P28, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_34 = { //CP1046
+ {
+ P112, P00, P00, P00, P00, P00, P113, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P114, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P115, P00, P00, P00, P00, P00, P116, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_35 = { //CP1124
+ {
+ P21, P00, P00, P00, P117, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P23, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_36 = { //CP1125
+ {
+ P118, P00, P00, P00, P119, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P12, P120, P00, P00, P14, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_37 = { //CP1129
+ {
+ P121, P122, P00, P123, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P124, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_38 = { //CP1131
+ {
+ P125, P00, P00, P00, P126, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P127, P00, P00, P128, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_39 = { //CP1133
+ {
+ P129, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P130, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P131, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_40 = { //CP1161
+ {
+ P132, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P133, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P134, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_41 = { //CP1162
+ {
+ P135, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P136, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P137, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_42 = { //CP1163
+ {
+ P138, P122, P00, P123, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P139, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_43 = { //CP1258
+ {
+ P140, P141, P26, P123, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P142, P28, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_44 = { //CP437
+ {
+ P143, P144, P00, P145, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P146, P00, P147, P148, P00, P14, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_45 = { //CP737
+ {
+ P149, P00, P00, P150, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P151, P00, P152, P00, P00, P14, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_46 = { //CP775
+ {
+ P153, P154, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P155, P00, P156, P00, P00, P157, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_47 = { //CP850
+ {
+ P158, P159, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P160, P00, P00, P00, P00, P55, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_48 = { //CP852
+ {
+ P161, P162, P163, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P55, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_49 = { //CP853
+ {
+ P164, P165, P166, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P167, P00, P00, P00, P55, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_50 = { //CP856
+ {
+ P168, P00, P00, P00, P00, P169, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P160, P00, P00, P00, P00, P55, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_51 = { //CP857
+ {
+ P170, P171, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P55, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_52 = { //CP858
+ {
+ P158, P144, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P172, P00, P00, P00, P00, P55, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_53 = { //CP860
+ {
+ P173, P00, P00, P145, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P146, P00, P147, P174, P00, P14, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_54 = { //CP861
+ {
+ P175, P144, P00, P145, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P146, P00, P147, P148, P00, P14, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_55 = { //CP862
+ {
+ P176, P144, P00, P145, P00, P169, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P146, P00, P147, P148, P00, P14, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_56 = { //CP863
+ {
+ P177, P144, P00, P145, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P178, P00, P147, P148, P00, P14, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_57 = { //CP864
+ {
+ P179, P00, P00, P180, P00, P00, P181, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P182, P00, P00, P183, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P184, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_58 = { //CP865
+ {
+ P185, P144, P00, P145, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P146, P00, P147, P148, P00, P14, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_59 = { //CP869
+ {
+ P186, P00, P00, P187, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P188, P00, P00, P00, P00, P55, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_60 = { //CP874
+ {
+ P189, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P136, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P137, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_61 = { //CP922
+ {
+ P190, P191, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P192, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_62 = { //HP_ROMAN8
+ {
+ P193, P194, P195, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P196, P00, P00, P00, P00, P197, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_63 = { //ISO646_CN
+ {
+ P198, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P199, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_64 = { //ISO646_JP
+ {
+ P200, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P199, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_65 = { //ISO8859_10
+ {
+ P201, P202, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P203, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_66 = { //ISO8859_11
+ {
+ P204, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P136, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_67 = { //ISO8859_14
+ {
+ P205, P206, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P207, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_68 = { //JISX0201
+ {
+ P200, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P199, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P208,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_69 = { //KOI8_T
+ {
+ P209, P00, P00, P00, P210, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P66, P04, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_70 = { //MAC_ARABIC
+ {
+ P211, P00, P00, P00, P00, P00, P212, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P213, P00, P00, P00, P00, P00, P00, P214,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_71 = { //MAC_CENTRALEUROPE
+ {
+ P215, P216, P217, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P218, P219, P220, P00, P00, P221, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_72 = { //MAC_CROATIAN
+ {
+ P222, P223, P224, P225, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P226, P219, P227, P00, P00, P221, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P228, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_73 = { //MAC_GREEK
+ {
+ P229, P230, P00, P231, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P232, P233, P234, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_74 = { //MAC_HEBREW
+ {
+ P235, P00, P00, P00, P00, P236, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P237, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P238, P00, P00, P239, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_75 = { //MAC_ICELAND
+ {
+ P240, P241, P242, P243, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P244, P219, P245, P00, P00, P221, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P246, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_76 = { //MAC_ROMANIA
+ {
+ P247, P248, P249, P243, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P250, P219, P245, P00, P00, P221, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P246, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_77 = { //MAC_ROMAN
+ {
+ P251, P241, P242, P243, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P250, P219, P245, P00, P00, P221, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P246, P00, P00, P252, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_78 = { //MAC_THAI
+ {
+ P253, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P254, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P255, P256, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_79 = { //MAC_TURKISH
+ {
+ P251, P257, P242, P243, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P258, P219, P245, P00, P00, P221, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P259, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_80 = { //reserved2
+ {
+ P15, P16, P00, P00, P17, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P18, P19, P20, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_81 = { //MULELAO
+ {
+ P204, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P260, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_82 = { //NEXTSTEP
+ {
+ P261, P262, P263, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P264, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P265, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_83 = { //PT154
+ {
+ P266, P00, P00, P00, P267, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P268, P269, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_84 = { //RISCOS-LATIN1
+ {
+ P270, P271, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P272, P273, P274, P00, P00, P275, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P276, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_85 = { //RK1048
+ {
+ P01, P00, P00, P00, P277, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P03, P04, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_86 = { //TCVN
+ {
+ P278, P279, P00, P280, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P281, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_87 = { //TDS565
+ {
+ P282, P283, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P284, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_88 = { //TIS620
+ {
+ P29, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P136, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+static const Encoder encoder_89 = { //VISCII
+ {
+ P285, P286, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P287, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ P00, P00, P00, P00, P00, P00, P00, P00,
+ },
+ defchars[0],
+ P00,
+};
+
+const Encoder* const NCodepagePrivate::TCodePageData::EncodeTo[] = {
+ &encoder_00,
+ &encoder_01,
+ &encoder_02,
+ &encoder_03,
+ &encoder_04,
+ &encoder_05,
+ &encoder_06,
+ &encoder_07,
+ &encoder_08,
+ &encoder_09,
+ nullptr,
+ nullptr,
+ &encoder_12,
+ nullptr,
+ &encoder_14,
+ &encoder_15,
+ &encoder_16,
+ &encoder_17,
+ &encoder_18,
+ &encoder_19,
+ &encoder_20,
+ &encoder_21,
+ &encoder_22,
+ &encoder_23,
+ &encoder_24,
+ &encoder_25,
+ &encoder_26,
+ &encoder_27,
+ &encoder_28,
+ &encoder_29,
+ &encoder_30,
+ &encoder_31,
+ &encoder_32,
+ &encoder_33,
+ &encoder_34,
+ &encoder_35,
+ &encoder_36,
+ &encoder_37,
+ &encoder_38,
+ &encoder_39,
+ &encoder_40,
+ &encoder_41,
+ &encoder_42,
+ &encoder_43,
+ &encoder_44,
+ &encoder_45,
+ &encoder_46,
+ &encoder_47,
+ &encoder_48,
+ &encoder_49,
+ &encoder_50,
+ &encoder_51,
+ &encoder_52,
+ &encoder_53,
+ &encoder_54,
+ &encoder_55,
+ &encoder_56,
+ &encoder_57,
+ &encoder_58,
+ &encoder_59,
+ &encoder_60,
+ &encoder_61,
+ &encoder_62,
+ &encoder_63,
+ &encoder_64,
+ &encoder_65,
+ &encoder_66,
+ &encoder_67,
+ &encoder_68,
+ &encoder_69,
+ &encoder_70,
+ &encoder_71,
+ &encoder_72,
+ &encoder_73,
+ &encoder_74,
+ &encoder_75,
+ &encoder_76,
+ &encoder_77,
+ &encoder_78,
+ &encoder_79,
+ &encoder_80,
+ &encoder_81,
+ &encoder_82,
+ &encoder_83,
+ &encoder_84,
+ &encoder_85,
+ &encoder_86,
+ &encoder_87,
+ &encoder_88,
+ &encoder_89,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+};
+
+const struct Encoder &WideCharToYandex = encoder_09;
+
+const Recoder NCodepagePrivate::TCodePageData::rcdr_to_yandex[] = {
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\246\303\047\343\042\056\052\052\044\052\246\042\246\312\246\246"
+ "\266\047\047\042\042\052\055\055\260\260\266\042\266\352\266\266\240\254"
+ "\274\246\044\216\260\247\250\260\256\042\075\217\260\257\260\075\255\275"
+ "\236\266\052\055\270\267\276\042\266\246\266\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\075\260\075\075\075\075\075\240\075\260\062\055\075\260\260"
+ "\260\270\276\260\275\277\260\260\260\260\260\236\260\260\260\260\260\250"
+ "\256\260\255\257\260\260\260\260\260\216\260\260\376\340\341\366\344\345"
+ "\364\343\365\350\351\352\353\354\355\356\357\377\360\361\362\363\346\342"
+ "\374\373\347\370\375\371\367\372\336\300\301\326\304\305\324\303\325\310"
+ "\311\312\313\314\315\316\317\337\320\321\322\323\306\302\334\333\307\330"
+ "\335\331\327\332"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
+ "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341"
+ "\342\343\344\345\346\347\350\351\352\353\354\355\356\357\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\360\361\362\363\364\365\366\367\370\371"
+ "\372\373\374\375\376\377\250\270\256\276\257\277\254\274\260\075\055\075"
+ "\267\044\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
+ "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\052\260"
+ "\216\044\247\052\052\255\260\260\260\246\266\075\303\343\075\075\075\075"
+ "\275\266\236\246\256\276\257\277\246\266\246\266\266\246\075\075\266\075"
+ "\075\042\042\056\240\246\266\312\352\266\055\055\042\042\047\047\075\042"
+ "\254\274\246\266\267\250\270\377\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\044"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\250"
+ "\246\303\256\246\255\257\246\246\246\246\312\217\254\246\300\301\302\303"
+ "\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325"
+ "\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347"
+ "\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371"
+ "\372\373\374\375\376\377\267\270\266\343\276\266\275\277\266\266\266\266"
+ "\352\247\274\266"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\044\260\047\266\042\056\052\052\266\052\123\042\246\260\132\260"
+ "\260\047\047\042\042\052\055\055\140\260\163\042\266\260\172\131\240\052"
+ "\044\044\044\044\260\247\140\260\141\042\075\217\260\140\260\075\062\063"
+ "\140\266\052\055\140\061\157\042\061\061\063\052\101\101\101\101\201\101"
+ "\246\103\105\105\105\105\111\111\111\111\246\116\117\242\117\117\202\075"
+ "\246\125\125\125\203\131\246\220\210\141\211\141\221\141\266\212\213\214"
+ "\215\230\151\151\231\232\266\156\157\262\233\157\222\075\266\234\165\235"
+ "\223\171\266\171"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\044\260\047\260\042\056\052\052\260\052\123\042\243\124\132\245"
+ "\260\047\047\042\042\052\055\055\260\260\163\042\263\164\172\265\240\055"
+ "\140\207\044\204\260\247\140\260\123\042\075\217\260\244\260\075\140\227"
+ "\140\266\052\055\140\224\163\042\114\140\154\264\122\101\101\101\201\114"
+ "\205\103\103\105\206\105\105\111\111\104\246\241\116\242\117\117\202\075"
+ "\122\125\125\125\203\131\124\220\162\141\211\141\221\154\225\212\143\214"
+ "\226\230\145\151\231\144\266\261\156\262\233\157\222\075\162\165\165\165"
+ "\223\171\164\140"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\204"
+ "\140\207\044\114\243\247\140\123\123\124\245\217\132\244\260\224\140\227"
+ "\140\154\263\055\140\163\163\164\265\140\172\264\122\101\101\101\201\114"
+ "\205\103\103\105\206\105\105\111\111\104\246\241\116\242\117\117\202\075"
+ "\122\125\125\125\203\131\124\220\162\141\211\141\221\154\225\212\143\214"
+ "\226\230\145\151\231\144\266\261\156\262\233\157\222\075\162\165\165\165"
+ "\223\171\164\140"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{},},
+{{},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\266\246\343\303\270\250\276\256\266\246\275\255\277\257\266\246"
+ "\266\246\266\246\266\246\352\312\274\254\266\246\376\336\372\332\340\300"
+ "\341\301\366\326\344\304\345\305\364\324\343\303\042\042\260\260\260\260"
+ "\260\365\325\350\310\260\260\260\260\351\311\260\260\260\260\260\260\260"
+ "\352\312\260\260\260\260\260\260\260\044\353\313\354\314\355\315\356\316"
+ "\357\260\260\260\260\317\377\260\337\360\320\361\321\362\322\363\323\346"
+ "\306\342\302\374\334\267\217\373\333\347\307\370\330\375\335\371\331\367"
+ "\327\247\260\240"},},
+{{},},
+{{"\000\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\246\246\047\266\042\056\052\052\044\052\246\042\246\246\246\246"
+ "\266\047\047\042\042\052\055\055\032\260\266\042\266\266\266\266\240\254"
+ "\274\246\044\246\260\247\250\260\256\042\075\217\260\257\260\075\255\275"
+ "\266\266\052\055\270\267\276\042\266\246\266\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\246\303\047\343\042\056\052\052\044\052\246\042\246\246\246\246"
+ "\266\047\047\042\042\052\055\055\032\260\266\042\266\266\266\266\240\254"
+ "\274\246\044\216\260\247\250\260\256\042\075\217\260\257\260\075\255\275"
+ "\236\266\052\055\270\267\276\042\266\246\266\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\077"
+ "\266\056\051\050\042\042\055\056\052\054\055\055\056\052\052\052\246\266"
+ "\246\266\246\266\246\266\246\266\246\266\246\266\246\266\246\266\246\266"
+ "\246\266\246\266\246\266\246\266\246\266\246\266\246\266\246\266\246\266"
+ "\246\266\246\266\246\266\246\266\246\266\246\266\246\266\246\266\246\266"
+ "\246\266\246\266\246\266\246\266\246\266\246\266\246\266\246\266\246\266"
+ "\246\266\052\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\047\266\042\056\052\052\266\052\123\042\246\032\032\032"
+ "\032\047\047\042\042\052\055\055\140\260\163\042\266\032\032\131\240\052"
+ "\044\044\044\044\260\247\140\260\141\042\075\217\260\140\260\075\062\063"
+ "\140\266\052\055\140\061\157\042\061\061\063\052\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\212\213\214"
+ "\215\230\151\151\231\232\266\156\157\262\233\157\222\075\266\234\165\235"
+ "\223\171\266\171"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\047\266\042\056\052\052\266\052\123\042\246\032\032\032"
+ "\032\047\047\042\042\052\055\055\140\260\163\042\266\032\032\131\240\052"
+ "\044\044\044\044\260\247\140\260\141\042\075\217\260\140\260\075\062\063"
+ "\140\266\052\055\140\061\157\042\061\061\063\052\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\266\212\213\214"
+ "\215\230\151\151\231\232\266\156\157\262\233\157\222\075\266\234\165\235"
+ "\223\171\266\171"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\246"
+ "\140\044\044\260\110\247\140\111\123\107\112\217\260\244\260\266\062\063"
+ "\140\266\150\055\140\266\163\147\152\061\260\264\101\101\101\260\201\103"
+ "\103\103\105\105\105\105\111\111\111\111\260\116\117\242\117\107\202\075"
+ "\107\125\125\125\203\125\123\220\210\141\211\260\221\143\143\212\213\214"
+ "\215\230\151\151\231\232\260\156\157\262\233\147\222\075\147\234\165\235"
+ "\223\165\163\140"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\204"
+ "\266\122\044\111\114\247\140\123\105\107\246\217\132\140\260\224\140\162"
+ "\140\151\154\055\140\163\145\147\266\246\172\266\101\101\101\101\201\101"
+ "\246\111\103\105\206\105\105\111\111\111\246\116\117\113\117\117\202\075"
+ "\246\125\125\125\203\125\125\220\141\141\211\141\221\141\266\151\143\214"
+ "\226\230\145\151\231\151\266\156\157\153\233\157\222\075\266\165\165\235"
+ "\223\165\165\140"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\260\260\214\211\260\210\260\212\215\230\213\232\231\260\260\260"
+ "\260\260\260\233\260\260\235\234\260\260\032\032\032\032\032\032\240\260"
+ "\260\260\044\260\260\260\260\260\260\260\056\260\042\042\260\260\260\260"
+ "\260\260\260\260\260\260\260\056\260\260\260\056\260\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\260\260\260\260\260\055\237\237\237\237\237\237\237\237\237"
+ "\237\200\200\200\200\200\200\200\200\260\260\260\260\260\260\260\260\260"
+ "\266\044\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\047"
+ "\047\044\044\044\260\247\140\260\055\042\075\217\260\055\260\075\062\063"
+ "\140\140\246\055\246\246\246\042\246\061\246\246\266\246\246\246\246\246"
+ "\246\246\246\246\246\246\246\246\246\246\246\246\260\246\246\246\246\246"
+ "\246\246\246\246\266\266\266\266\266\266\266\266\266\266\266\266\266\266"
+ "\266\266\266\266\266\266\266\266\266\266\266\266\266\266\266\266\266\266"
+ "\266\266\266\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\260"
+ "\044\044\044\044\260\247\140\260\075\042\075\217\260\140\260\075\062\063"
+ "\140\266\052\055\140\061\075\042\061\061\063\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\052\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\260"
+ "\260\032\032\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\052"
+ "\044\044\044\044\260\247\140\260\141\042\075\217\260\140\260\075\062\063"
+ "\140\266\052\055\140\061\157\042\061\061\063\052\101\101\101\101\201\101"
+ "\246\103\105\105\105\105\111\111\111\111\107\116\117\242\117\117\202\075"
+ "\246\125\125\125\203\111\123\220\210\141\211\141\221\141\266\212\213\214"
+ "\215\230\151\151\231\232\147\156\157\262\233\157\222\075\266\234\165\235"
+ "\223\266\163\171"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\042"
+ "\044\044\044\042\260\247\246\260\122\042\075\217\260\246\260\075\062\063"
+ "\042\266\052\055\266\061\162\042\061\061\063\266\204\111\101\205\201\101"
+ "\206\105\103\105\245\105\107\113\111\114\123\241\116\242\117\117\202\075"
+ "\125\207\243\125\203\244\132\220\224\151\141\225\221\141\226\145\143\214"
+ "\265\145\147\153\151\154\163\261\156\262\157\157\222\075\165\227\263\165"
+ "\223\264\172\047"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\052"
+ "\044\044\044\044\123\247\163\260\141\042\075\217\260\140\260\075\062\063"
+ "\132\266\052\055\172\061\157\042\246\266\131\052\101\101\101\101\201\101"
+ "\246\103\105\105\105\105\111\111\111\111\246\116\117\242\117\117\202\075"
+ "\246\125\125\125\203\131\246\220\210\141\211\141\221\141\266\212\213\214"
+ "\215\230\151\151\231\232\266\156\157\262\233\157\222\075\266\234\165\235"
+ "\223\171\266\171"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\204"
+ "\224\207\044\042\123\247\163\260\123\042\245\217\265\244\260\075\103\227"
+ "\132\042\052\055\172\143\163\042\246\266\131\264\101\101\101\101\201\205"
+ "\246\103\105\105\105\105\111\111\111\111\246\241\117\242\117\117\202\243"
+ "\125\125\125\125\203\206\124\220\210\141\211\141\221\225\266\212\213\214"
+ "\215\230\151\151\231\232\266\261\157\262\233\157\222\263\165\234\165\235"
+ "\223\226\164\171"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\044\260\047\266\042\056\052\052\260\052\260\042\260\260\260\260"
+ "\260\047\047\042\042\052\055\055\260\260\260\042\260\260\260\260\240\140"
+ "\246\044\044\044\260\247\140\260\260\042\075\217\260\055\260\075\062\063"
+ "\140\266\052\055\246\246\246\042\246\061\246\246\266\246\246\246\246\246"
+ "\246\246\246\246\246\246\246\246\246\246\246\246\260\246\246\246\246\246"
+ "\246\246\246\246\266\266\266\266\266\266\266\266\266\266\266\266\266\266"
+ "\266\266\266\266\266\266\266\266\266\266\266\266\266\266\266\266\266\266"
+ "\266\266\266\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\044\260\047\266\042\056\052\052\266\052\123\042\246\260\260\260"
+ "\260\047\047\042\042\052\055\055\140\260\163\042\266\260\260\131\240\052"
+ "\044\044\044\044\260\247\140\260\141\042\075\217\260\140\260\075\062\063"
+ "\140\266\052\055\140\061\157\042\061\061\063\052\101\101\101\101\201\101"
+ "\246\103\105\105\105\105\111\111\111\111\107\116\117\242\117\117\202\075"
+ "\246\125\125\125\203\111\123\220\210\141\211\141\221\141\266\212\213\214"
+ "\215\230\151\151\231\232\147\156\157\262\233\157\222\075\266\234\165\235"
+ "\223\266\163\171"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\044\260\047\266\042\056\052\052\266\052\260\042\260\260\260\260"
+ "\260\047\047\042\042\052\055\055\140\260\260\042\260\260\260\260\240\052"
+ "\044\044\044\044\260\247\140\260\075\042\075\217\260\140\260\075\062\063"
+ "\140\266\052\055\140\061\075\042\061\061\063\052\200\200\200\200\200\200"
+ "\200\200\200\200\260\200\200\200\055\200\052\200\200\052\237\237\237\052"
+ "\052\260\260\260\260\260\260\260\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\260"
+ "\260\032\032\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\044\237\047\266\042\056\052\052\266\052\237\042\246\237\237\237"
+ "\237\047\047\042\042\052\055\055\237\260\237\042\266\032\032\237\240\056"
+ "\044\044\044\044\260\247\140\260\237\042\075\217\260\140\260\075\062\063"
+ "\140\266\052\055\140\061\056\042\061\061\063\056\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\075"
+ "\237\237\237\237\055\237\237\237\210\237\211\237\237\237\237\212\213\214"
+ "\215\230\237\237\231\232\200\200\200\200\233\200\200\075\200\234\200\235"
+ "\223\032\032\237"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\044\260\047\260\042\056\052\052\260\052\260\042\260\140\055\140"
+ "\260\047\047\042\042\052\055\055\260\260\260\042\260\140\140\260\240\260"
+ "\044\044\044\260\260\247\246\260\122\042\075\217\260\246\260\075\062\063"
+ "\140\266\052\055\266\061\162\042\061\061\063\266\204\111\101\205\201\101"
+ "\206\105\103\105\245\105\107\113\111\114\123\241\116\242\117\117\202\075"
+ "\125\207\243\125\203\244\132\220\224\151\141\225\221\141\226\145\143\214"
+ "\265\145\147\153\151\154\163\261\156\262\157\157\222\075\165\227\263\165"
+ "\223\264\172\140"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\237\075\075\077\077\077\077\237\032\260\260\260\260\260\260\260"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\240\077"
+ "\077\077\044\077\237\237\237\237\237\237\056\217\237\237\071\071\071\071"
+ "\071\071\071\071\071\071\237\056\237\237\237\056\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\055\237\237\237\237\237\237\237\237\237"
+ "\237\200\200\200\200\200\200\200\200\237\237\237\077\237\237\237\237\237"
+ "\237\237\237\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\250"
+ "\246\216\256\246\255\257\246\246\246\246\312\217\254\246\300\301\302\303"
+ "\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325"
+ "\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347"
+ "\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371"
+ "\372\373\374\375\376\377\267\270\266\236\276\266\275\277\266\266\266\266"
+ "\352\247\274\266"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
+ "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341"
+ "\342\343\344\345\346\347\350\351\352\353\354\355\356\357\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\360\361\362\363\364\365\366\367\370\371"
+ "\372\373\374\375\376\377\250\270\216\236\256\276\255\275\257\277\055\075"
+ "\267\044\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\052"
+ "\044\044\044\044\260\247\266\260\141\042\075\217\260\140\260\075\062\063"
+ "\131\266\052\055\246\061\157\042\061\061\063\052\101\101\101\101\201\101"
+ "\246\103\105\105\105\105\200\111\111\111\246\116\200\242\117\117\202\075"
+ "\246\125\125\125\203\125\200\220\210\141\211\141\221\141\266\212\213\214"
+ "\215\230\200\151\231\232\266\156\200\262\233\157\222\075\266\234\165\235"
+ "\223\165\044\171"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
+ "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341"
+ "\342\343\344\345\346\347\350\351\352\353\354\355\356\357\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\360\361\362\363\364\365\366\367\370\371"
+ "\372\373\374\375\376\377\250\270\256\276\257\277\254\274\255\275\055\044"
+ "\216\236\075\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\260\260\260\237\237\237\237\200\200\200"
+ "\200\200\200\200\200\200\237\260\260\260\237\237\237\237\237\200\200\200"
+ "\200\200\200\055\260\237\237\044\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\071\071\071\071\071\071\071\071\071\071\260\260"
+ "\044\075\260\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\200\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\200\237\237\200\200\200\200"
+ "\200\200\200\200\200\200\044\044\237\237\237\237\237\237\055\200\200\200"
+ "\200\200\200\200\200\052\071\071\071\071\071\071\071\071\071\071\052\052"
+ "\044\075\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\044\032\032\032\032\056\032\032\032\032\032\032\032\032\032\032"
+ "\032\047\047\042\042\052\055\055\032\032\032\032\032\032\032\032\240\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\200\237\237\200\200\200\200"
+ "\200\200\200\260\260\260\260\044\237\237\237\237\237\237\055\200\200\200"
+ "\200\200\200\200\200\052\071\071\071\071\071\071\071\071\071\071\052\052"
+ "\260\260\260\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\052"
+ "\044\044\044\044\260\247\266\260\141\042\075\217\260\140\260\075\062\063"
+ "\131\266\052\055\246\061\157\042\061\061\063\052\101\101\101\101\201\101"
+ "\246\103\105\105\105\105\200\111\111\111\246\116\200\242\117\117\202\075"
+ "\246\125\125\125\203\125\200\220\210\141\211\141\221\141\266\212\213\214"
+ "\215\230\200\151\231\232\266\156\200\262\233\157\222\075\266\234\165\235"
+ "\223\165\044\171"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\044\260\047\266\042\056\052\052\266\052\260\042\246\260\260\260"
+ "\260\047\047\042\042\052\055\055\140\260\260\042\266\260\260\131\240\052"
+ "\044\044\044\044\260\247\140\260\141\042\075\217\260\140\260\075\062\063"
+ "\140\266\052\055\140\061\157\042\061\061\063\052\101\101\101\101\201\101"
+ "\246\103\105\105\105\105\200\111\111\111\246\116\200\242\117\117\202\075"
+ "\246\125\125\125\203\125\200\220\210\141\211\141\221\141\266\212\213\214"
+ "\215\230\200\151\231\232\266\156\200\262\233\157\222\075\266\234\165\235"
+ "\223\165\044\171"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\103\223\214\211\221\210\141\212\215\230\213\232\231\151\201\101"
+ "\105\266\246\233\222\157\235\234\171\202\203\044\044\044\044\266\141\151"
+ "\262\165\156\116\141\157\052\260\075\061\061\052\042\042\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\266\220\246\266\246\266\266\266\246\246"
+ "\246\266\075\266\266\075\075\075\075\075\075\075\075\075\260\075\055\075"
+ "\156\062\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\246\246\246\246\246\246\246\246\246\246\246\246\246\246\246\246"
+ "\246\246\246\246\246\246\246\246\266\266\266\266\266\266\266\266\266\266"
+ "\266\266\266\266\266\266\266\266\266\266\266\266\266\266\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\266\266\266\266\266\266\266\266\266\266"
+ "\246\246\246\246\246\246\246\075\075\075\246\246\075\075\260\075\055\075"
+ "\156\062\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\205\223\214\141\221\147\141\225\227\145\122\162\151\245\201\101"
+ "\105\266\246\157\222\107\044\243\263\202\203\266\044\246\075\044\101\111"
+ "\262\244\264\265\042\260\260\260\075\061\061\207\042\042\260\260\260\260"
+ "\260\204\103\206\105\260\260\260\260\111\123\260\260\260\260\260\260\260"
+ "\125\125\260\260\260\260\260\260\260\132\224\143\226\145\151\163\165\165"
+ "\172\260\260\260\260\260\260\260\242\220\117\241\157\117\266\261\113\153"
+ "\114\154\156\105\116\047\217\075\042\063\052\247\075\042\260\075\055\061"
+ "\063\062\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\103\223\214\211\221\210\141\212\215\230\213\232\231\151\201\101"
+ "\105\266\246\233\222\157\235\234\171\202\203\266\044\246\075\266\141\151"
+ "\262\165\156\116\141\157\052\260\075\061\061\052\042\042\260\260\260\260"
+ "\260\101\101\101\260\260\260\260\260\044\044\260\260\260\260\260\260\260"
+ "\141\101\260\260\260\260\260\260\260\044\266\246\105\105\105\266\111\111"
+ "\111\260\260\260\260\260\111\260\242\220\117\117\157\117\266\266\246\125"
+ "\125\125\171\131\140\140\217\075\052\063\052\247\075\140\260\140\055\061"
+ "\063\062\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\103\223\214\211\221\165\225\212\227\230\117\157\231\245\201\205"
+ "\105\114\154\233\222\114\154\243\263\202\203\124\164\207\075\143\141\151"
+ "\262\165\204\224\132\172\206\226\075\265\103\163\042\042\260\260\260\260"
+ "\260\101\101\105\123\260\260\260\260\244\264\260\260\260\260\260\260\260"
+ "\101\141\260\260\260\260\260\260\260\044\266\246\104\105\144\116\111\111"
+ "\145\260\260\260\260\124\125\260\242\220\117\241\261\156\123\163\122\125"
+ "\162\125\171\131\164\140\217\140\140\055\140\247\075\140\260\140\140\165"
+ "\122\162\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\103\223\214\211\221\210\143\212\215\230\213\232\231\151\201\103"
+ "\105\143\103\233\222\157\235\234\111\202\203\147\044\107\075\152\141\151"
+ "\262\165\156\116\107\147\110\150\260\061\112\163\042\042\260\260\260\260"
+ "\260\101\101\101\123\260\260\260\260\244\264\260\260\260\260\260\260\260"
+ "\123\163\260\260\260\260\260\260\260\044\260\260\105\105\105\266\111\111"
+ "\111\260\260\260\260\260\111\260\242\220\117\117\107\147\266\246\266\125"
+ "\125\125\125\165\260\140\217\260\154\266\140\247\075\140\260\140\140\260"
+ "\063\062\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\260\044\260\075\260\260\260"
+ "\260\260\260\260\260\260\260\260\075\061\061\260\042\042\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\044\044\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\044\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\266\260\260\260"
+ "\260\260\260\260\140\140\217\075\052\063\052\247\075\140\260\140\055\061"
+ "\063\062\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\103\223\214\211\221\210\141\212\215\230\213\232\231\266\201\101"
+ "\105\266\246\233\222\157\235\234\111\202\203\266\044\246\123\163\141\151"
+ "\262\165\156\116\107\147\052\260\075\061\061\052\042\042\260\260\260\260"
+ "\260\101\101\101\260\260\260\260\260\044\044\260\260\260\260\260\260\260"
+ "\141\101\260\260\260\260\260\260\260\044\157\141\105\105\105\260\111\111"
+ "\111\260\260\260\260\260\111\260\242\220\117\117\157\117\266\260\075\125"
+ "\125\125\151\171\140\140\217\075\260\063\052\247\075\140\260\140\055\061"
+ "\063\062\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\103\223\214\211\221\210\141\212\215\230\213\232\231\151\201\101"
+ "\105\266\246\233\222\157\235\234\171\202\203\266\044\246\075\266\141\151"
+ "\262\165\156\116\141\157\052\260\075\061\061\052\042\042\260\260\260\260"
+ "\260\101\101\101\260\260\260\260\260\044\044\260\260\260\260\260\260\260"
+ "\141\101\260\260\260\260\260\260\260\044\266\246\105\105\105\044\111\111"
+ "\111\260\260\260\260\260\111\260\242\220\117\117\157\117\266\266\246\125"
+ "\125\125\171\131\140\140\217\075\052\063\052\247\075\140\260\140\055\061"
+ "\063\062\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\103\223\214\211\141\210\101\212\215\105\213\111\117\151\101\101"
+ "\105\101\105\233\157\157\125\234\111\117\203\044\044\125\044\242\141\151"
+ "\262\165\156\116\141\157\052\117\075\061\061\052\042\042\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\266\220\246\266\246\266\266\266\246\246"
+ "\246\266\075\266\266\075\075\075\075\075\075\075\075\075\260\075\055\075"
+ "\156\062\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\103\223\214\211\221\210\141\212\215\230\213\246\266\246\201\101"
+ "\105\266\246\233\222\266\235\131\171\202\203\266\044\246\044\266\141\151"
+ "\262\165\101\111\242\125\052\260\075\061\061\052\042\042\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\266\220\246\266\246\266\266\266\246\246"
+ "\246\266\075\266\266\075\075\075\075\075\075\075\075\075\260\075\055\075"
+ "\156\062\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\044\044\044\044\266\141\151"
+ "\262\165\156\116\141\157\052\260\075\061\061\052\042\042\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\266\220\246\266\246\266\266\266\246\246"
+ "\246\266\075\266\266\075\075\075\075\075\075\075\075\075\260\075\055\075"
+ "\156\062\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\103\223\214\211\101\210\052\212\215\230\213\232\231\052\101\247"
+ "\105\105\105\233\105\111\235\234\044\117\203\044\044\125\125\266\260\140"
+ "\262\165\140\140\063\140\111\260\075\061\061\063\042\042\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\266\220\246\266\246\266\266\266\246\246"
+ "\246\266\075\266\266\075\075\075\075\075\075\075\075\075\260\075\055\075"
+ "\156\062\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\052\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\260\055\075\075\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\266\075\266\075\061\061\075\042\042\237\237\260\260\237\237\260\240\217"
+ "\237\044\044\237\260\260\237\237\237\237\056\237\237\237\071\071\071\071"
+ "\071\071\071\071\071\071\237\056\237\237\237\056\044\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\260\075\075\075\237\055\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\200\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\260\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\103\223\214\211\221\210\141\212\215\230\213\232\231\151\201\101"
+ "\105\266\246\233\222\157\235\234\171\202\203\266\044\246\044\266\141\151"
+ "\262\165\156\116\141\157\052\260\075\061\061\052\042\044\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\266\220\246\266\246\266\266\266\246\246"
+ "\246\266\075\266\266\075\075\075\075\075\075\075\075\075\260\075\055\075"
+ "\156\062\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\260\260\260\260\260\260\246\260\055\075\260\047\047\246\055\246"
+ "\246\246\246\260\260\246\246\260\246\062\063\266\044\266\266\266\266\266"
+ "\266\266\246\246\246\246\246\246\246\061\246\246\042\042\260\260\260\260"
+ "\260\246\246\246\246\260\260\260\260\246\246\260\260\260\260\260\260\260"
+ "\246\246\260\260\260\260\260\260\260\246\246\246\246\246\246\246\266\266"
+ "\266\260\260\260\260\266\266\260\266\266\266\266\266\266\266\266\266\266"
+ "\266\266\266\266\266\140\217\075\266\266\266\247\266\140\260\140\266\266"
+ "\266\266\260\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\044\260\260\260\260\056\260\260\260\260\260\260\260\260\260\260"
+ "\260\047\047\042\042\052\055\055\260\260\260\260\260\260\260\260\240\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\200\237\237\200\200\200\200"
+ "\200\200\200\260\260\260\260\044\237\237\237\237\237\237\055\200\200\200"
+ "\200\200\200\200\200\052\071\071\071\071\071\071\071\071\071\071\052\052"
+ "\260\260\260\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\052"
+ "\044\044\044\044\260\247\140\260\141\042\075\217\260\052\260\075\062\063"
+ "\140\266\052\055\140\061\157\042\061\061\063\052\101\101\101\101\201\101"
+ "\246\103\105\105\105\105\111\111\111\111\123\116\117\242\117\117\202\075"
+ "\246\125\125\125\203\131\132\220\210\141\211\141\221\141\266\212\213\214"
+ "\215\230\151\151\231\232\163\156\157\262\233\157\222\075\266\234\165\235"
+ "\223\171\172\171"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\101"
+ "\101\105\105\105\111\111\140\266\266\140\140\125\125\044\140\131\171\260"
+ "\103\212\116\156\052\052\044\044\044\247\266\044\211\215\233\235\141\214"
+ "\262\165\210\213\157\234\221\230\222\223\101\231\246\246\141\151\266\266"
+ "\201\151\202\203\105\232\220\117\101\101\141\246\266\111\111\242\117\117"
+ "\157\123\163\125\131\171\246\266\055\266\052\063\055\061\061\141\157\042"
+ "\260\042\075\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\052\177\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\044\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\052\177\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\204"
+ "\105\107\111\111\113\247\114\246\123\246\132\217\125\246\260\224\145\147"
+ "\151\151\153\055\154\266\163\266\172\055\165\266\101\101\101\101\201\101"
+ "\246\111\103\105\206\105\105\111\111\111\246\116\117\242\117\117\202\125"
+ "\246\125\125\125\203\131\246\220\141\141\211\141\221\141\266\151\143\214"
+ "\226\230\145\151\231\232\266\156\157\262\233\157\222\165\266\165\165\235"
+ "\223\171\266\266"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\200\237\237\200\200\200\200"
+ "\200\200\200\260\260\260\260\044\237\237\237\237\237\237\055\200\200\200"
+ "\200\200\200\200\200\052\071\071\071\071\071\071\071\071\071\071\052\052"
+ "\260\260\260\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\102"
+ "\142\044\103\143\104\247\127\260\127\144\131\217\260\131\106\146\107\147"
+ "\115\155\052\120\167\160\167\123\171\127\167\163\101\101\101\101\201\101"
+ "\246\103\105\105\105\105\111\111\111\111\127\116\117\242\117\117\202\124"
+ "\246\125\125\125\203\131\131\220\210\141\211\141\221\141\266\212\213\214"
+ "\215\230\151\151\231\232\167\156\157\262\233\157\222\164\266\234\165\235"
+ "\223\171\171\171"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\044\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\052\177\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\056"
+ "\042\042\056\055\237\237\237\237\237\237\237\237\237\237\055\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\055\055\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\266\266\047\246\042\056\052\052\260\052\266\042\246\266\246\260"
+ "\246\047\047\042\042\052\055\055\260\260\260\042\260\260\260\260\260\363"
+ "\323\270\044\350\260\247\260\260\260\042\075\217\260\260\260\075\062\250"
+ "\260\310\052\055\260\267\260\042\260\260\260\260\376\340\341\366\344\345"
+ "\364\343\365\350\351\352\353\354\355\356\357\377\360\361\362\363\346\342"
+ "\374\373\347\370\375\371\367\372\336\300\301\326\304\305\324\303\325\310"
+ "\311\312\313\314\315\316\317\337\320\321\322\323\306\302\334\333\307\330"
+ "\335\331\327\332"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\201\240\103\105\116\202\203\141\210\211\221\237\042\212\214\213"
+ "\215\230\151\056\231\232\156\262\042\233\222\075\165\234\235\223\040\041"
+ "\042\043\044\052\046\047\050\051\052\053\056\055\056\057\071\071\071\071"
+ "\071\071\071\071\071\071\072\056\074\075\076\056\260\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\133\134\135\136\137\055\237\237\237\237\237\237\237\237\237"
+ "\237\200\200\200\200\200\200\200\200\237\237\237\237\237\237\237\237\173"
+ "\174\175\237\237"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\201\101\141\105\204\202\203\141\224\103\221\143\205\225\214\245"
+ "\265\104\151\144\105\145\105\262\145\233\222\157\165\105\145\223\052\260"
+ "\206\044\247\052\052\220\260\260\260\226\140\075\147\111\151\111\075\075"
+ "\151\113\075\075\227\114\154\114\154\114\154\116\156\241\075\075\261\116"
+ "\075\042\042\056\240\156\117\117\157\117\055\055\042\042\047\047\075\260"
+ "\157\122\162\122\042\042\162\122\162\123\047\042\163\243\263\101\124\164"
+ "\111\132\172\125\242\117\165\125\125\165\125\165\125\165\131\171\153\244"
+ "\207\264\107\055"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\201\101\103\105\116\202\203\141\210\211\221\141\141\212\214\213"
+ "\215\230\151\151\231\232\156\262\157\233\222\157\165\234\235\223\052\260"
+ "\044\044\247\052\052\220\260\123\260\140\140\075\132\246\075\075\075\075"
+ "\075\266\075\075\075\163\075\141\157\246\172\266\052\052\075\075\266\075"
+ "\205\042\103\056\240\101\101\117\246\266\246\055\042\042\047\047\075\260"
+ "\077\260\075\044\042\042\246\042\055\055\047\042\052\101\225\101\143\105"
+ "\111\111\111\111\242\117\266\117\125\125\125\266\266\140\140\266\105\140"
+ "\140\105\266\055"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\201\061\062\105\063\202\203\140\210\211\221\140\140\212\214\213"
+ "\215\230\044\260\231\232\052\061\052\233\222\260\044\234\235\223\052\246"
+ "\246\246\246\246\246\220\260\260\246\246\247\075\260\055\246\075\075\075"
+ "\044\246\246\246\246\246\246\246\246\246\246\246\266\246\075\246\246\075"
+ "\246\042\042\056\240\246\246\246\246\266\055\055\042\042\047\047\075\246"
+ "\246\246\246\266\266\266\266\246\266\266\266\266\266\266\266\266\266\266"
+ "\266\266\266\266\266\266\266\266\266\266\266\266\266\266\266\266\266\266"
+ "\266\266\266\217"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\201\237\103\105\116\202\203\141\210\211\221\141\141\212\214\213"
+ "\215\230\151\151\231\232\156\262\157\233\222\157\165\234\235\223\040\041"
+ "\042\043\044\045\044\047\051\050\052\053\054\055\056\057\060\061\062\063"
+ "\064\065\066\067\070\071\072\073\074\075\076\077\237\042\077\077\077\077"
+ "\200\237\237\056\240\200\200\200\200\200\055\055\042\042\047\047\237\237"
+ "\200\200\200\200\200\200\200\200\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\175"
+ "\135\173\133\174"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\201\101\103\105\116\202\203\141\210\211\221\141\141\212\214\213"
+ "\215\230\151\151\231\232\156\262\157\233\222\157\165\234\235\223\131\260"
+ "\044\044\247\052\052\220\260\260\260\140\140\075\246\246\075\075\075\075"
+ "\044\266\075\075\075\266\075\141\157\246\266\266\052\052\075\075\266\075"
+ "\075\042\042\056\240\101\101\117\246\266\055\055\042\042\047\047\075\260"
+ "\171\131\075\044\246\266\246\266\171\055\047\042\052\101\105\101\105\105"
+ "\111\111\111\111\242\117\077\117\125\125\125\266\266\140\140\140\140\140"
+ "\140\140\140\055"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\201\101\103\105\116\202\203\141\210\211\221\141\141\212\214\213"
+ "\215\230\151\151\231\232\156\262\157\233\222\157\165\234\235\223\052\260"
+ "\044\044\247\052\052\220\260\260\260\140\140\075\101\123\075\075\075\075"
+ "\044\266\075\075\075\266\075\141\157\246\141\163\052\052\075\075\266\075"
+ "\075\042\042\056\240\101\101\117\246\266\055\055\042\042\047\047\075\260"
+ "\171\131\075\044\042\042\124\164\052\055\047\042\052\101\105\101\105\105"
+ "\111\111\111\111\242\117\077\117\125\125\125\266\266\140\140\140\140\140"
+ "\140\140\140\055"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\201\101\103\105\116\202\203\141\210\211\221\141\141\212\214\213"
+ "\215\230\151\151\231\232\156\262\157\233\222\157\165\234\235\223\052\260"
+ "\044\044\247\052\052\220\260\260\260\140\140\075\246\246\075\075\075\075"
+ "\044\266\075\075\075\266\075\141\157\246\266\266\052\052\075\075\266\075"
+ "\075\042\042\056\240\101\101\117\246\266\055\055\042\042\047\047\075\260"
+ "\171\131\075\044\042\042\146\146\052\055\047\042\052\101\105\101\105\105"
+ "\111\111\111\111\242\117\077\117\125\125\125\266\266\140\140\140\140\140"
+ "\140\140\140\055"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\042\042\056\200\200\200\200\200\200\200\200\200\200\042\042\200"
+ "\260\052\200\200\200\200\200\200\200\200\200\200\200\047\047\260\240\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\200\237\237\200\200\200\200"
+ "\200\200\200\032\040\055\055\044\237\237\237\237\237\237\055\200\200\200"
+ "\200\200\200\200\260\052\071\071\071\071\071\071\071\071\071\071\260\260"
+ "\260\260\260\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\201\101\103\105\116\202\203\141\210\211\221\141\141\212\214\213"
+ "\215\230\151\151\231\232\156\262\157\233\222\157\165\234\235\223\052\260"
+ "\044\044\247\052\052\220\260\260\260\140\140\075\246\246\075\075\075\075"
+ "\044\266\075\075\075\266\075\141\157\246\266\266\052\052\075\075\266\075"
+ "\075\042\042\056\240\101\101\117\246\266\055\055\042\042\047\047\075\260"
+ "\171\131\107\147\111\266\123\163\052\055\047\042\052\101\105\101\105\105"
+ "\111\111\111\111\242\117\077\117\125\125\125\077\266\140\140\140\140\140"
+ "\140\140\140\055"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
+ "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\052\260"
+ "\216\044\247\052\052\255\260\260\260\246\266\075\303\343\075\075\075\075"
+ "\275\266\236\246\256\276\257\277\246\266\246\266\266\246\075\075\266\075"
+ "\075\042\042\056\240\246\266\312\352\266\055\055\042\042\047\047\075\042"
+ "\254\274\246\266\267\250\270\377\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\044"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032"
+ "\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\032\240\237"
+ "\237\260\237\260\260\237\237\260\237\260\260\237\260\260\260\260\260\260"
+ "\237\237\237\237\260\237\237\237\237\237\237\237\260\237\237\237\260\237"
+ "\260\237\260\260\237\237\260\237\237\237\237\200\237\237\200\200\200\200"
+ "\200\200\260\200\200\237\260\260\237\237\237\237\237\260\055\260\200\200"
+ "\200\200\200\200\260\260\071\071\071\071\071\071\071\071\071\071\260\260"
+ "\237\237\260\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\240\101\101\101\101\201\101\103\105\105\105\105\111\111\111\111"
+ "\246\116\117\242\117\117\202\125\125\125\203\131\246\266\075\075\260\052"
+ "\044\044\075\044\266\247\044\047\042\042\042\042\146\146\260\055\052\052"
+ "\055\260\052\052\047\042\042\042\056\052\075\052\061\266\140\266\140\140"
+ "\140\140\140\062\140\140\063\140\140\055\055\075\061\061\063\210\141\211"
+ "\141\221\141\212\213\214\215\230\151\246\151\141\231\232\266\156\207\246"
+ "\246\157\157\262\233\157\222\266\234\165\235\266\223\171\227\266\266\220"
+ "\266\171\260\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\246\246\323\266\042\056\246\246\246\266\246\310\246\246\246\246"
+ "\266\047\047\042\042\052\055\055\266\266\266\350\266\266\266\266\240\254"
+ "\274\246\246\246\246\247\250\260\246\042\075\363\260\246\260\266\255\275"
+ "\266\266\052\055\270\267\266\042\266\246\266\266\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\075\127\167\032\260\131\171\032\260\260\260\260\056\260\052\052"
+ "\047\047\042\042\042\042\042\055\055\055\246\266\052\052\146\146\240\052"
+ "\044\044\044\044\260\247\140\260\141\042\075\217\260\140\260\075\062\063"
+ "\140\266\052\055\140\061\157\042\061\061\063\052\101\101\101\101\201\101"
+ "\246\103\105\105\105\105\111\111\111\111\246\116\117\242\117\117\202\075"
+ "\246\125\125\125\203\131\246\220\210\141\211\141\221\141\266\212\213\214"
+ "\215\230\151\151\231\232\266\156\157\262\233\157\222\075\266\234\165\235"
+ "\223\171\266\171"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\246\303\047\343\042\056\052\052\044\052\246\042\246\246\246\246"
+ "\266\047\047\042\042\052\055\055\260\260\266\042\266\266\266\266\240\246"
+ "\266\246\044\246\260\247\250\260\246\042\075\217\260\246\260\075\255\275"
+ "\266\266\052\055\270\267\266\042\266\246\266\266\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\125\125\003\125\125\125\007\010\011\012\013\014\015\016\017\020\125"
+ "\125\131\131\131\131\131\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\101\101\101\101\101\101\101\105\105\105\105\105\105\111\111\111"
+ "\111\111\117\117\117\242\117\117\117\117\117\117\117\125\125\125\240\101"
+ "\101\105\117\117\125\246\141\211\215\233\157\165\266\101\200\200\200\200"
+ "\200\210\141\141\141\141\101\141\141\141\141\101\101\101\101\101\101\105"
+ "\141\141\141\141\141\141\213\105\145\145\214\145\145\145\145\145\145\151"
+ "\151\105\105\117\151\151\151\157\117\157\157\262\157\157\157\157\157\157"
+ "\157\157\157\157\157\234\117\165\165\165\165\165\165\165\165\165\171\171"
+ "\171\171\171\117"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\201\106"
+ "\107\110\111\112\132\113\114\115\116\116\117\202\120\122\123\123\124\125"
+ "\203\127\131\131\132\137\267\141\142\212\144\145\221\146\147\150\151\152"
+ "\172\153\154\155\156\156\157\222\160\162\163\163\164\165\223\167\171\171"
+ "\172\177\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260"
+ "\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\260\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237\237"
+ "\237\237\237\237\237\237\237\237\237\237\237\200\237\237\200\200\200\200"
+ "\200\200\200\260\260\260\260\044\237\237\237\237\237\237\055\200\200\200"
+ "\200\200\200\200\200\052\071\071\071\071\071\071\071\071\071\071\052\052"
+ "\260\260\260\260"},},
+{{"\000\001\101\003\004\101\101\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\131\025\026\027\030\131\032\033\034\035\131\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\101\101\101\101\101\101\101\101\105\105\105\105\105\105\105\117"
+ "\117\117\117\117\117\117\117\117\111\117\117\111\125\125\125\131\117\141"
+ "\141\141\141\141\141\141\145\145\145\145\145\145\145\157\157\157\157\117"
+ "\117\157\157\157\151\125\125\125\125\157\157\125\101\101\101\101\101\101"
+ "\141\141\105\105\105\105\111\111\111\171\246\165\117\242\117\141\171\165"
+ "\165\125\125\171\171\131\157\165\210\141\211\141\141\141\165\141\213\214"
+ "\215\145\151\151\151\151\266\165\157\262\233\157\157\157\165\234\165\165"
+ "\165\171\157\125"},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+};
+
+const Recoder NCodepagePrivate::TCodePageData::rcdr_from_yandex[] = {
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\245\255"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\264\077\240\077"
+ "\077\077\077\077\077\247\250\077\077\077\241\262\252\257\260\077\077\077"
+ "\077\077\077\271\270\077\077\077\242\263\272\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\275\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\255\077\232\077"
+ "\077\077\077\077\077\077\263\077\077\077\077\266\264\267\234\077\077\077"
+ "\077\077\077\077\243\077\077\077\077\246\244\247\341\342\367\347\344\345"
+ "\366\372\351\352\353\354\355\356\357\360\362\363\364\365\346\350\343\376"
+ "\373\375\377\371\370\374\340\361\301\302\327\307\304\305\326\332\311\312"
+ "\313\314\315\316\317\320\322\323\324\325\306\310\303\336\333\335\337\331"
+ "\330\334\300\321"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\377\077"
+ "\077\077\077\077\077\077\360\077\077\077\366\077\362\364\370\077\077\077"
+ "\077\077\077\374\361\077\077\077\367\077\363\365\200\201\202\203\204\205"
+ "\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227"
+ "\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251"
+ "\252\253\254\255\256\257\340\341\342\343\344\345\346\347\350\351\352\353"
+ "\354\355\356\357"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\242\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\266\077\312\077"
+ "\077\077\077\077\077\244\335\077\077\077\330\247\270\272\241\077\077\077"
+ "\077\077\077\334\336\077\077\077\331\264\271\273\200\201\202\203\204\205"
+ "\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227"
+ "\230\231\232\233\234\235\236\237\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\337"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\255"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\240\077"
+ "\077\077\077\077\077\375\241\077\077\077\256\246\244\247\077\077\077\077"
+ "\077\077\077\360\361\077\077\077\376\366\364\367\260\261\262\263\264\265"
+ "\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307"
+ "\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331"
+ "\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353"
+ "\354\355\356\357"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\304\326\334\077\077\077\077\340\342\347\350\351\352\077\255"
+ "\337\344\366\374\077\077\077\077\353\356\357\364\371\373\077\077\240\077"
+ "\323\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\363\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\304\326\334\245\306\312\243\077\342\347\077\351\077\077\255"
+ "\337\344\366\374\271\346\352\263\353\356\077\364\077\077\077\077\240\321"
+ "\323\214\257\217\077\247\077\077\077\077\077\077\077\077\260\361\363\234"
+ "\277\237\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\304\326\334\241\306\312\243\077\342\347\077\351\077\077\255"
+ "\337\344\366\374\261\346\352\263\353\356\077\364\077\077\077\077\240\321"
+ "\323\246\257\254\077\247\077\077\077\077\077\077\077\077\260\361\363\266"
+ "\277\274\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{},},
+{{},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\360"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\377\077"
+ "\077\077\077\077\077\375\205\077\077\077\231\213\207\215\077\077\077\077"
+ "\077\077\077\357\204\077\077\077\230\212\206\214\241\243\354\255\247\251"
+ "\352\364\270\276\307\321\323\325\327\335\342\344\346\350\253\266\245\374"
+ "\366\372\237\362\356\370\235\340\240\242\353\254\246\250\351\363\267\275"
+ "\306\320\322\324\326\330\341\343\345\347\252\265\244\373\365\371\236\361"
+ "\355\367\234\336"},},
+{{},},
+{{"\000\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\255"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\240\077"
+ "\077\077\077\077\077\247\250\077\077\077\241\262\252\257\260\077\077\077"
+ "\077\077\077\271\270\077\077\077\242\263\272\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\245\255"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\264\077\240\077"
+ "\077\077\077\077\077\247\250\077\077\077\241\262\252\257\260\077\077\077"
+ "\077\077\077\271\270\077\077\077\242\263\272\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\347\350\351\352\077\255"
+ "\077\077\366\374\077\077\077\077\353\356\357\364\371\373\077\077\240\077"
+ "\077\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\363\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\347\350\351\352\077\255"
+ "\077\077\366\374\077\077\077\077\353\356\357\364\371\373\077\077\240\077"
+ "\077\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\363\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\304\326\334\077\077\077\077\340\342\347\350\351\352\077\255"
+ "\337\344\366\374\077\077\077\077\353\356\357\364\371\373\077\077\240\077"
+ "\323\077\257\077\077\247\077\077\077\077\077\077\077\077\260\077\363\077"
+ "\277\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\304\326\334\241\077\312\077\077\342\077\077\351\077\077\255"
+ "\337\344\366\374\261\077\352\077\353\356\077\364\077\373\077\077\240\077"
+ "\077\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\205\203\207\212\202\210\077\077"
+ "\077\077\077\077\077\077\077\077\211\214\213\223\227\226\077\077\240\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\255"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\240\077"
+ "\077\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\255"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\240\077"
+ "\077\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\304\326\334\077\077\077\077\340\342\347\350\351\352\077\255"
+ "\337\344\366\374\077\077\077\077\353\356\357\364\371\373\077\077\240\077"
+ "\323\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\363\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\304\326\334\300\303\306\331\077\077\077\077\351\077\077\255"
+ "\337\344\366\374\340\343\346\371\077\077\077\077\077\077\077\077\240\321"
+ "\323\332\335\312\077\247\077\077\077\077\077\077\077\077\260\361\363\372"
+ "\375\352\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\304\326\334\077\077\077\077\340\342\347\350\351\352\077\255"
+ "\337\344\366\374\077\077\077\077\353\356\357\364\371\373\077\077\240\077"
+ "\323\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\363\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\304\326\334\241\305\335\243\340\342\347\350\351\352\077\255"
+ "\337\344\366\374\242\345\375\263\353\356\357\364\371\373\077\077\240\321"
+ "\323\327\257\254\077\247\077\077\077\077\077\077\077\077\260\361\363\367"
+ "\277\256\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\255"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\240\077"
+ "\077\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\304\326\334\077\077\077\077\340\342\347\350\351\352\077\255"
+ "\337\344\366\374\077\077\077\077\353\356\357\364\371\373\077\077\240\077"
+ "\323\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\363\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\255"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\240\077"
+ "\077\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\340\342\347\350\351\352\077\255"
+ "\077\077\077\374\077\077\077\077\353\356\357\364\371\373\077\077\240\077"
+ "\077\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\304\326\334\300\303\306\331\077\077\077\077\351\077\077\255"
+ "\337\344\366\374\340\343\346\371\077\077\077\077\077\077\077\077\240\321"
+ "\323\332\335\312\077\247\077\077\077\077\077\077\077\077\260\361\363\372"
+ "\375\352\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\255"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\240\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\243\255"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\363\077\240\077"
+ "\077\077\077\077\077\375\241\077\077\077\256\246\244\247\077\077\077\077"
+ "\077\077\077\360\361\077\077\077\376\366\364\367\260\261\262\263\264\265"
+ "\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307"
+ "\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331"
+ "\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353"
+ "\354\355\356\357"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\362\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\363\077\377\077"
+ "\077\077\077\077\077\077\360\077\077\077\077\366\364\370\077\077\077\077"
+ "\077\077\077\374\361\077\077\077\077\367\365\371\200\201\202\203\204\205"
+ "\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227"
+ "\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251"
+ "\252\253\254\255\256\257\340\341\342\343\344\345\346\347\350\351\352\353"
+ "\354\355\356\357"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\354\304\326\334\077\077\077\077\340\342\347\350\351\352\077\255"
+ "\337\344\366\374\077\077\077\077\353\356\357\364\371\373\077\077\240\077"
+ "\323\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\363\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\374\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\375\077\377\077"
+ "\077\077\077\077\077\077\360\077\077\077\366\370\362\364\077\077\077\077"
+ "\077\077\077\077\361\077\077\077\367\371\363\365\200\201\202\203\204\205"
+ "\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227"
+ "\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251"
+ "\252\253\254\255\256\257\340\341\342\343\344\345\346\347\350\351\352\353"
+ "\354\355\356\357"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\240\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\377\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\240\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\354\304\326\334\077\077\077\077\340\342\347\350\351\352\077\255"
+ "\337\344\366\374\077\077\077\077\353\356\357\364\371\373\077\077\240\077"
+ "\323\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\363\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\354\304\326\334\077\077\077\077\340\342\347\350\351\352\077\255"
+ "\337\344\366\374\077\077\077\077\353\356\357\364\371\373\077\077\240\077"
+ "\323\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\363\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\216\231\232\077\077\077\077\205\203\207\212\202\210\077\077"
+ "\341\204\224\201\077\077\077\077\211\214\213\223\227\226\077\077\377\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\370\077\242\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\377\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\370\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\216\231\232\265\200\267\255\077\077\077\077\202\077\077\360"
+ "\341\204\224\201\320\207\322\210\077\077\077\077\077\077\077\077\377\343"
+ "\340\227\243\215\077\365\077\077\077\077\077\077\077\077\370\347\242\230"
+ "\244\245\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\216\231\232\077\077\077\077\205\203\207\212\202\210\077\360"
+ "\341\204\224\201\077\077\077\077\211\214\213\223\227\226\077\077\377\077"
+ "\340\077\077\077\077\365\077\077\077\077\077\077\077\077\370\077\242\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\216\231\232\244\217\250\235\077\203\207\077\202\077\077\360"
+ "\341\204\224\201\245\206\251\210\211\214\077\223\077\077\077\077\377\343"
+ "\340\227\275\215\077\365\077\077\077\077\077\077\077\077\370\344\242\230"
+ "\276\253\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\216\231\232\077\077\077\077\205\203\207\212\202\210\077\360"
+ "\341\204\224\201\077\077\077\077\211\214\213\223\227\226\077\077\377\077"
+ "\340\077\275\077\077\365\077\077\077\077\077\077\077\077\370\077\242\077"
+ "\276\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\360"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\377\077"
+ "\077\077\077\077\077\365\077\077\077\077\077\077\077\077\370\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\216\231\232\077\077\077\077\205\203\207\212\202\210\077\360"
+ "\341\204\224\201\077\077\077\077\211\214\213\223\227\226\077\077\377\077"
+ "\340\077\077\077\077\365\077\077\077\077\077\077\077\077\370\077\242\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\216\231\232\077\077\077\077\205\203\207\212\202\210\077\360"
+ "\341\204\224\201\077\077\077\077\211\214\213\223\227\226\077\077\377\077"
+ "\340\077\077\077\077\365\077\077\077\077\077\077\077\077\370\077\242\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\232\077\077\077\077\205\203\207\212\202\210\077\077"
+ "\341\077\077\201\077\077\077\077\077\077\077\223\227\077\077\077\377\077"
+ "\237\077\077\077\077\077\077\077\077\077\077\077\077\077\370\077\242\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\216\231\232\077\077\077\077\205\203\207\212\202\210\077\077"
+ "\341\204\224\201\077\077\077\077\211\077\077\223\077\226\077\077\377\077"
+ "\246\077\077\077\077\077\077\077\077\077\077\077\077\077\370\077\242\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\341\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\377\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\370\077\242\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\232\077\077\077\077\205\203\207\212\202\210\077\077"
+ "\341\077\077\201\077\077\077\077\211\214\213\223\227\226\077\077\377\077"
+ "\077\077\077\077\077\217\077\077\077\077\077\077\077\077\370\077\242\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\077\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\241"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\240\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\200\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\216\231\232\077\077\077\077\205\203\207\212\202\210\077\077"
+ "\341\204\224\201\077\077\077\077\211\214\213\223\227\226\077\077\377\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\370\077\242\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\360"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\377\077"
+ "\077\077\077\077\077\365\077\077\077\077\077\077\077\077\370\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\240\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\304\326\334\077\077\077\077\340\342\347\350\351\352\077\255"
+ "\337\344\366\374\077\077\077\077\353\356\357\364\371\373\077\077\240\077"
+ "\323\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\363\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\330\332\333\077\077\077\077\310\300\265\311\305\301\077\077"
+ "\336\314\316\317\077\077\077\077\315\321\335\302\313\303\077\077\240\077"
+ "\347\077\077\077\077\275\077\077\077\077\077\077\077\077\263\077\306\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\077\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\077\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\077\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\077\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\304\326\334\241\077\312\077\077\342\077\077\351\077\077\255"
+ "\337\344\366\374\261\077\352\077\353\356\357\364\077\373\077\077\240\077"
+ "\323\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\363\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\240\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\304\326\334\077\077\077\077\340\342\347\350\351\352\077\255"
+ "\337\344\366\374\077\077\077\077\353\356\357\364\371\373\077\077\240\077"
+ "\323\077\077\077\077\247\077\077\077\077\077\077\077\077\077\077\363\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\077\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\077\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\255"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\247\263\077\077\077\077\077\077\077\260\077\077\077"
+ "\077\077\077\271\243\077\077\077\077\077\077\077\341\342\367\347\344\345"
+ "\366\372\351\352\353\354\355\356\357\360\362\363\364\365\346\350\343\376"
+ "\373\375\377\371\370\374\340\361\301\302\327\307\304\305\326\332\311\312"
+ "\313\314\315\316\317\320\322\323\324\325\306\310\303\336\333\335\337\331"
+ "\330\334\300\321"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\200\205\206\077\077\077\077\210\211\215\217\216\220\077\077"
+ "\077\212\232\237\077\077\077\077\221\224\225\231\235\236\077\077\201\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\227\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\200\205\206\204\214\242\374\077\077\077\077\216\077\077\077"
+ "\247\212\232\237\210\215\253\270\077\077\077\231\077\077\077\077\312\301"
+ "\356\345\373\217\077\244\077\077\077\077\077\077\077\077\241\304\227\346"
+ "\375\220\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\200\205\206\077\306\077\077\210\211\215\217\216\220\077\077"
+ "\247\212\232\237\077\346\077\077\221\224\225\231\235\236\077\077\312\077"
+ "\356\077\077\077\077\244\077\077\077\077\077\077\077\077\241\077\227\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\200\205\206\077\077\077\077\210\211\215\217\216\220\077\377"
+ "\247\212\232\237\077\077\077\077\221\224\225\231\235\236\077\077\312\077"
+ "\077\077\077\077\077\254\077\077\077\077\077\077\077\077\256\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\200\205\206\077\077\077\077\210\211\215\217\216\220\077\077"
+ "\077\212\232\237\077\077\077\077\221\224\225\231\235\236\077\077\312\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\227\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\200\205\206\077\077\077\077\210\211\215\217\216\220\077\077"
+ "\247\212\232\237\077\077\077\077\221\224\225\231\235\236\077\077\312\077"
+ "\356\077\077\077\077\244\077\077\077\077\077\077\077\077\241\077\227\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\200\205\206\077\077\077\077\210\211\215\217\216\220\077\077"
+ "\247\212\232\237\077\077\077\077\221\224\225\231\235\236\077\077\312\077"
+ "\356\077\077\077\077\244\077\077\077\077\077\077\077\077\241\077\227\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\200\205\206\077\077\077\077\210\211\215\217\216\220\077\077"
+ "\247\212\232\237\077\077\077\077\221\224\225\231\235\236\077\077\312\077"
+ "\356\077\077\077\077\244\077\077\077\077\077\077\077\077\241\077\227\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\240\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\200\205\206\077\077\077\077\210\211\215\217\216\220\077\077"
+ "\247\212\232\237\077\077\077\077\221\224\225\231\235\236\077\077\312\077"
+ "\356\077\077\077\077\244\077\077\077\077\077\077\077\077\241\077\227\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\242\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\266\077\312\077"
+ "\077\077\077\077\077\244\335\077\077\077\330\247\270\272\241\077\077\077"
+ "\077\077\077\334\336\077\077\077\331\264\271\273\200\201\202\203\204\205"
+ "\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227"
+ "\230\231\232\233\234\235\236\237\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\337"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\240\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\205\226\232\077\077\077\350\325\327\333\334\335\336\077\077"
+ "\373\331\360\366\077\077\077\370\337\344\345\356\362\364\077\077\200\077"
+ "\223\077\077\077\077\247\077\077\077\077\077\077\077\077\077\077\355\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\240\077"
+ "\077\077\077\077\077\247\250\077\077\077\241\262\077\077\260\077\077\077"
+ "\077\077\077\271\270\077\077\077\242\263\077\077\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\304\326\334\077\077\077\077\340\342\347\350\351\352\077\255"
+ "\337\344\366\374\077\077\077\077\353\356\357\364\371\373\077\077\240\077"
+ "\323\077\077\077\077\247\077\077\077\077\077\077\077\077\260\077\363\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\255"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\240\077"
+ "\077\077\077\077\077\247\250\077\077\077\077\262\077\077\260\077\077\077"
+ "\077\077\077\271\270\077\077\077\077\263\077\077\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\077\077\003\077\077\077\007\010\011\012\013\014\015\016\017\020\077"
+ "\077\077\077\077\077\077\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\263\077\077\077\077\077\077\077\265\251\077\314\320\252\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\253\357\077\077\077\240\077"
+ "\225\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\343\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\077\104\105\107\110"
+ "\111\112\113\115\116\117\120\122\124\077\125\126\130\131\077\133\077\134"
+ "\136\077\077\077\077\137\077\141\142\077\144\145\147\150\151\152\153\155"
+ "\156\157\160\162\164\077\165\166\170\171\077\173\077\174\176\077\077\077"
+ "\077\177\077\106\123\132\077\077\077\077\077\077\143\077\077\077\077\077"
+ "\077\146\163\172\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\140\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{"\000\001\077\003\004\077\077\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\077\025\026\027\030\077\032\033\034\035\077\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\077\077\077\077\077\077\077\077\340\342\077\350\351\352\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\364\371\077\077\077\077\077"
+ "\323\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\363\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077\077"
+ "\077\077\077\077"},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+};
+
+const Recoder NCodepagePrivate::TCodePageData::rcdr_to_lower[] = {
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\220\203\202\203\204\205\206\207\210\211\232\213\234\235\236\237"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\242"
+ "\242\274\244\264\246\247\270\251\272\253\254\255\256\277\260\261\263\263"
+ "\264\265\266\267\270\271\272\273\274\276\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\377\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\243"
+ "\244\265\246\247\270\271\272\273\274\255\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\337"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
+ "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\361\361\363\363\365\365\367\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
+ "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\337\240\241"
+ "\266\243\244\245\246\264\250\251\252\254\254\255\257\257\260\261\262\263"
+ "\264\265\266\300\271\271\273\273\275\275\277\277\300\317\302\303\304\305"
+ "\306\307\310\311\312\314\314\316\316\317\320\321\322\323\324\325\326\327"
+ "\331\331\333\333\334\336\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\361"
+ "\362\363\364\365\366\367\370\371\372\373\374\255\376\377\320\321\322\323"
+ "\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\232\213\234\215\236\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\377\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\327"
+ "\370\371\372\373\374\375\376\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\232\213\234\235\236\237"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\263\244\271\246\247\250\251\272\253\254\255\256\277\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\276\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\327"
+ "\370\371\372\373\374\375\376\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\261"
+ "\242\263\244\265\266\247\250\271\272\273\274\255\276\277\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\327"
+ "\370\371\372\373\374\375\376\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\221\222\223\224\225\226\227\210\211\212\213\214\215\236\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\261"
+ "\262\263\264\265\266\247\270\271\272\273\274\275\276\277\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\377\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{},},
+{{},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\200\202\202\204\204\206\206\210\210\212\212\214\214\216\216"
+ "\220\220\222\222\224\224\226\226\230\230\232\232\234\234\236\236\240\240"
+ "\242\242\244\244\246\246\250\250\252\252\254\254\256\257\260\261\262\263"
+ "\264\265\265\267\267\271\272\273\274\275\275\277\300\301\302\303\304\305"
+ "\306\306\310\311\312\313\314\315\316\317\320\320\322\322\324\324\326\326"
+ "\330\331\332\333\334\330\336\337\336\341\341\343\343\345\345\347\347\351"
+ "\351\353\353\355\355\357\360\361\361\363\363\365\365\367\367\371\371\373"
+ "\373\375\376\377"},},
+{{},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\220\203\202\203\204\205\206\207\210\211\232\213\234\235\236\237"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\242"
+ "\242\274\244\264\246\247\270\251\272\253\254\255\256\277\260\261\263\263"
+ "\264\265\266\267\270\271\272\273\274\276\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\377\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\220\203\202\203\204\205\206\207\210\211\232\213\234\235\236\237"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\242"
+ "\242\274\244\264\246\247\270\251\272\253\254\255\256\277\260\261\263\263"
+ "\264\265\266\267\270\271\272\273\274\276\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\377\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\051\050\246\247\250\056\252\054\055\255\256\257\260\261\263\263"
+ "\265\265\267\267\271\271\273\273\275\275\277\277\301\301\303\303\305\305"
+ "\307\307\311\311\313\313\315\315\317\317\321\321\323\323\325\325\327\327"
+ "\331\331\333\333\335\335\337\337\341\341\343\343\345\345\347\347\351\351"
+ "\353\353\355\355\357\357\361\361\363\363\365\365\367\367\371\371\373\373"
+ "\375\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\232\213\234\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\377\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\232\213\234\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\377\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\261"
+ "\242\243\244\245\266\247\250\151\272\273\274\255\256\277\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\340\341\342\303\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\320\361\362\363\364\365\366\327"
+ "\370\371\372\373\374\375\376\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\261"
+ "\242\263\244\265\266\247\250\271\272\273\274\255\276\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\277\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\327"
+ "\370\371\372\373\374\375\376\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\334\267\335\336\337\273\374\275\375\376\300\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\322\363\364\365\366\367"
+ "\370\371\372\373\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\327"
+ "\370\371\372\373\374\151\376\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\270\251\272\253\254\255\256\277\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\327"
+ "\370\371\372\373\374\375\376\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\250\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\270\265\266\267\270\271\272\273\275\275\377\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\327"
+ "\370\371\372\373\374\375\376\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\242"
+ "\242\263\244\245\250\247\250\251\272\253\256\255\256\277\260\261\271\263"
+ "\270\265\266\267\270\271\272\273\275\275\377\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\334\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\335\336\337\273\374\275\375\376\300\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\322\363\364\365\366\367"
+ "\370\371\372\373\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\232\213\234\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\377\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\327"
+ "\370\371\372\373\374\151\376\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\234\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\270\251\272\253\254\255\256\277\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\327"
+ "\370\371\372\373\374\375\376\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\361"
+ "\362\363\364\365\366\367\370\371\372\373\374\255\376\377\320\321\322\323"
+ "\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
+ "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\361\361\363\363\365\365\367\367\371\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\377\265\266\267\250\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\314\355\356\357\360\361\322\363\364\365\366\327"
+ "\370\371\372\373\374\375\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
+ "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\361\361\363\363\365\365\367\367\371\371\372\373"
+ "\375\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\240\333"
+ "\334\335\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\377\265\266\267\250\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\314\355\356\357\360\361\322\363\364\365\366\327"
+ "\370\371\372\373\374\375\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\234\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\377\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\314\355\356\357\360\361\322\363\364\365\366\327"
+ "\370\371\372\373\374\375\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\207\201\202\203\204\205\206\207\210\211\212\213\214\215\204\206"
+ "\202\221\221\223\224\225\226\227\230\224\201\233\234\235\236\237\240\241"
+ "\242\243\244\244\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\345\345\346\347\355\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247"
+ "\250\251\253\254\255\256\257\340\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\341\342\343\345\346\347\351\361\362\363\344\350\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\207\201\202\203\204\205\206\207\210\211\213\213\214\245\204\206"
+ "\202\221\221\223\224\205\226\230\230\224\201\233\234\233\236\237\203\214"
+ "\242\244\244\245\246\247\250\251\252\253\254\210\256\257\260\261\262\263"
+ "\264\320\321\322\323\271\272\273\274\324\325\277\300\301\302\303\304\305"
+ "\326\327\310\311\312\313\314\315\316\330\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\242\341\223\347\344\344\346\347\351\351"
+ "\353\353\354\211\354\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\207\201\202\203\204\205\206\207\210\211\212\213\214\215\204\206"
+ "\202\221\221\223\224\225\226\227\230\224\201\233\234\233\236\237\240\241"
+ "\242\243\244\244\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\240\203\205\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\306\310\311\312\313\314\315\316\317\320\320\210\211\212\325\241\214"
+ "\213\331\332\333\334\335\215\337\242\341\223\225\344\344\346\347\347\243"
+ "\226\227\354\354\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\207\201\202\203\204\205\206\207\210\211\213\213\214\253\204\206"
+ "\202\222\222\223\224\226\226\230\230\224\201\234\234\210\236\237\240\241"
+ "\242\243\245\245\247\247\251\251\252\253\237\255\256\257\260\261\262\263"
+ "\264\240\203\330\255\271\272\273\274\276\276\277\300\301\302\303\304\305"
+ "\307\307\310\311\312\313\314\315\316\317\320\320\324\211\324\345\241\214"
+ "\330\331\332\333\334\356\205\337\242\341\223\344\344\345\347\347\352\243"
+ "\352\373\354\354\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\375\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\207\201\202\203\204\205\206\207\210\211\212\213\214\215\204\206"
+ "\202\221\221\223\224\225\226\227\151\224\201\233\234\233\236\237\240\241"
+ "\242\243\244\244\247\247\251\251\252\253\237\255\256\257\260\261\262\263"
+ "\264\240\203\205\255\271\272\273\274\276\276\277\300\301\302\303\304\305"
+ "\307\307\310\311\312\313\314\315\316\317\320\321\210\211\212\325\241\214"
+ "\213\331\332\333\334\335\215\337\242\341\223\225\345\345\346\350\350\243"
+ "\226\227\355\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\207\201\202\203\204\205\206\207\210\211\212\213\214\215\204\206"
+ "\202\221\221\223\224\225\226\227\151\224\201\233\234\233\237\237\240\241"
+ "\242\243\244\244\247\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\240\203\205\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\306\310\311\312\313\314\315\316\317\320\321\210\211\212\325\241\214"
+ "\213\331\332\333\334\335\354\337\242\341\223\225\344\344\346\347\350\243"
+ "\226\227\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\207\201\202\203\204\205\206\207\210\211\212\213\214\215\204\206"
+ "\202\221\221\223\224\225\226\227\230\224\201\233\234\233\236\237\240\241"
+ "\242\243\244\244\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\240\203\205\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\306\310\311\312\313\314\315\316\317\320\320\210\211\212\325\241\214"
+ "\213\331\332\333\334\335\215\337\242\341\223\225\344\344\346\347\347\243"
+ "\226\227\354\354\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\207\201\202\203\204\205\240\207\210\210\212\241\223\215\204\203"
+ "\202\205\212\223\224\225\243\227\215\224\201\233\234\227\236\242\240\241"
+ "\242\243\244\244\246\247\250\225\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\345\345\346\347\355\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\207\201\202\203\204\205\206\207\210\211\212\214\214\225\204\206"
+ "\202\221\221\223\224\225\226\230\230\224\201\233\234\233\236\237\240\241"
+ "\242\243\240\241\242\243\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\345\345\346\347\355\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\244\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\345\345\346\347\355\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\207\201\202\203\203\205\206\207\210\211\212\213\214\215\205\217"
+ "\202\212\210\223\211\213\226\227\230\223\201\233\234\227\226\237\240\241"
+ "\242\243\244\245\246\247\214\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\345\345\346\347\355\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\207\201\202\203\204\205\206\207\210\211\212\213\214\215\204\206"
+ "\202\221\221\223\224\225\226\227\230\224\201\233\234\233\236\237\240\241"
+ "\242\243\244\244\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\345\345\346\347\355\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\233\207\210\211\212\213\214\235\216\236"
+ "\237\240\242\223\224\243\373\227\375\231\232\233\234\235\236\237\240\241"
+ "\242\243\326\327\330\335\336\340\341\253\342\343\256\257\260\261\262\263"
+ "\264\344\345\346\347\271\272\273\274\350\351\277\300\301\302\303\304\305"
+ "\352\353\310\311\312\313\314\315\316\354\356\362\363\364\366\372\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\327"
+ "\370\371\372\373\374\375\376\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\310"
+ "\300\311\301\315\321\335\250\251\252\253\254\313\303\257\260\262\262\263"
+ "\265\265\267\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\324\321\326\327\324\325\326\327"
+ "\314\331\316\317\305\335\336\302\304\342\342\344\344\325\331\306\312\352"
+ "\352\354\354\307\357\357\361\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\261"
+ "\262\263\264\265\266\247\270\271\272\273\274\255\276\277\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\242"
+ "\242\243\245\245\253\247\270\251\272\253\274\255\256\377\261\261\263\263"
+ "\265\265\266\271\270\271\272\277\274\276\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\201\204\205\206\207\210\211\212\213\212\215\215\217"
+ "\200\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\241\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\243"
+ "\264\245\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\337"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\212\201\215\216\226\232\237\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\040\041"
+ "\042\043\044\245\046\047\050\051\052\053\254\055\056\057\260\261\262\263"
+ "\264\265\266\267\270\271\072\273\074\075\076\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\133\134\135\136\137\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\173"
+ "\174\175\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\212\202\202\216\210\232\237\207\210\213\212\213\215\215\216\220"
+ "\220\223\222\223\225\225\230\227\230\231\232\233\234\236\236\237\240\241"
+ "\253\243\244\245\246\247\250\251\252\253\254\255\256\260\260\264\262\263"
+ "\264\372\266\267\270\272\272\274\274\276\276\300\300\304\302\303\304\313"
+ "\306\307\310\311\312\313\316\233\316\330\320\321\322\323\324\325\326\327"
+ "\330\332\332\336\334\335\336\340\340\344\342\343\344\346\346\207\351\351"
+ "\222\354\354\360\227\231\360\363\234\363\365\365\367\367\371\371\372\375"
+ "\270\375\256\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\212\214\215\216\226\232\237\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\271\252\253\254\255\276\277\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\346\307\350\311\312\210\213\233\317\317\360\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\376\337\340\341\342\343\344\211\346\207\350\217"
+ "\222\224\225\223\227\231\360\230\234\236\235\365\366\367\370\371\221\373"
+ "\374\220\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\212\201\202\216\204\232\237\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\347"
+ "\344\365\354\352\360\247\250\251\363\373\254\255\256\257\341\261\262\263"
+ "\264\342\345\372\350\351\353\355\346\374\343\366\300\356\302\357\362\305"
+ "\364\307\310\311\312\371\370\300\333\317\320\321\322\323\324\325\326\334"
+ "\335\336\340\333\334\335\336\361\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\212\201\215\216\226\232\237\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\040\041"
+ "\042\043\044\045\246\047\051\050\052\053\054\055\056\057\060\061\062\063"
+ "\064\065\066\067\070\071\072\073\074\075\076\077\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\313\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\300\355\356\357\360\361\362\363\364\365\366\367\370\371\372\175"
+ "\135\173\133\174"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\212\214\215\216\226\232\237\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\340\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\276\277\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\210\213\233\317\317\320\321\322\323\324\325\326\327"
+ "\330\330\332\333\335\335\337\337\340\341\342\343\344\211\220\207\221\217"
+ "\222\224\225\223\227\231\360\230\234\236\235\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\212\214\215\216\226\232\237\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\276\277\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\210\213\233\317\317\320\321\322\323\324\325\326\327"
+ "\330\330\332\333\334\335\337\337\340\341\342\343\344\211\220\207\221\217"
+ "\222\224\225\223\227\231\360\230\234\236\235\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\212\214\215\216\226\232\237\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\276\277\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\210\213\233\317\317\320\321\322\323\324\325\326\327"
+ "\330\330\332\333\334\335\336\337\340\341\342\343\344\211\220\207\221\217"
+ "\222\224\225\223\227\231\360\230\234\236\235\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\203\204\205\206\207\215\216\217"
+ "\220\221\222\223\224\225\226\227\203\204\205\206\207\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\222\322\323\224\225\226\227"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\223\203\204"
+ "\205\206\207\217\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\212\214\215\216\226\232\237\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\276\277\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\210\213\233\317\317\320\321\322\323\324\325\326\327"
+ "\330\330\333\333\151\335\337\337\340\341\342\343\344\211\220\207\221\217"
+ "\222\224\225\223\227\231\360\230\234\236\235\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
+ "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\337\240\241"
+ "\266\243\244\245\246\264\250\251\252\254\254\255\257\257\260\261\262\263"
+ "\264\265\266\300\271\271\273\273\275\275\277\277\300\317\302\303\304\305"
+ "\306\307\310\311\312\314\314\316\316\317\320\321\322\323\324\325\326\327"
+ "\331\331\333\333\334\336\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\325\326\327\330\331\332\333\334\335\336\337\340\342\344\345"
+ "\346\347\354\355\356\357\360\362\363\364\366\367\374\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\361\342\343\344\345\346\347\370\371"
+ "\372\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\220\203\255\203\204\205\231\211\230\211\232\233\234\235\236\237"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\242"
+ "\242\274\265\264\261\247\270\251\272\253\254\255\256\277\260\261\263\263"
+ "\264\265\266\267\270\271\272\273\274\276\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\377\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\202\202\203\204\206\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\233\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\327"
+ "\370\371\372\373\374\375\376\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\220\203\202\203\204\205\206\207\210\211\232\213\234\235\236\237"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\242"
+ "\242\274\244\264\246\247\270\251\272\253\254\255\256\277\260\261\263\263"
+ "\264\265\266\267\270\271\272\273\274\276\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\377\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\363\364\003\365\366\367\007\010\011\012\013\014\015\016\017\020\370"
+ "\371\372\373\374\375\376\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\265\266\267\270\271\306\313\314\316\317\320\321\326\327\330\334"
+ "\335\336\337\341\342\343\344\351\352\353\354\355\356\357\361\362\240\250"
+ "\251\252\253\254\255\256\250\251\252\253\254\255\256\273\260\261\262\263"
+ "\264\265\266\267\270\271\274\273\274\275\276\275\276\307\310\311\312\322"
+ "\306\307\310\311\312\313\314\323\316\317\320\321\322\323\324\325\326\327"
+ "\330\324\325\345\334\335\336\337\346\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\347\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\350"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\173\174\175\176\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\306\003\004\307\347\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\326\025\026\027\030\333\032\033\034\035\334\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\141\142\143\144\145\146\147"
+ "\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
+ "\172\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\325\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
+ "\260\261\262\265\376\276\266\267\270\366\367\357\374\373\370\317\365\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\336"
+ "\275\265\266\267\270\361\321\327\330\275\276\337\340\341\342\343\344\345"
+ "\306\307\350\351\352\353\354\355\356\317\360\321\362\363\364\325\326\327"
+ "\330\371\372\333\334\375\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\346"},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+};
+
+const Recoder NCodepagePrivate::TCodePageData::rcdr_to_upper[] = {
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\201\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\200\221\222\223\224\225\226\227\230\231\212\233\214\215\216\217\240\241"
+ "\241\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\262"
+ "\245\265\266\267\250\271\252\273\243\275\275\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\337"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\263\264\245\266\267\250\251\252\253\254\275\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\377\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\200\201"
+ "\202\203\204\205\206\207\210\211\212\213\214\215\216\217\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\220\221\222\223\224\225\226\227\230\231"
+ "\232\233\234\235\236\237\360\360\362\362\364\364\366\366\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\253\255\256\256\260\261\262\263"
+ "\247\265\242\267\270\270\272\272\274\274\276\276\267\301\302\303\304\305"
+ "\306\307\310\311\312\313\313\315\315\301\320\321\322\323\324\325\326\327"
+ "\330\330\332\332\334\335\335\237\200\201\202\203\204\205\206\207\210\211"
+ "\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233"
+ "\234\235\236\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\260\261\262\263\264\265\266\267"
+ "\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\360\241\242\243\244\245\246\247\250\251\252\253"
+ "\254\375\256\257"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\212\233\214\235\216\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\237"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\212\233\214\215\216\217\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\243"
+ "\264\265\266\267\270\245\252\273\274\275\274\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\241\262\243"
+ "\264\245\246\267\270\251\252\253\254\275\256\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\101\101\103\105\105\105\216\217"
+ "\220\201\202\203\204\205\206\207\105\111\111\117\125\125\216\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\241\242\243"
+ "\244\245\246\267\250\251\252\253\254\255\256\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\337"},},
+{{},},
+{{},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\201\201\203\203\205\205\207\207\211\211\213\213\215\215\217\217"
+ "\221\221\223\223\225\225\227\227\231\231\233\233\235\235\237\237\241\241"
+ "\243\243\245\245\247\247\251\251\253\253\255\255\256\257\260\261\262\263"
+ "\264\266\266\270\270\271\272\273\274\276\276\277\300\301\302\303\304\305"
+ "\307\307\310\311\312\313\314\315\316\317\321\321\323\323\325\325\327\327"
+ "\335\331\332\333\334\335\340\337\340\342\342\344\344\346\346\350\350\352"
+ "\352\354\354\356\356\357\360\362\362\364\364\366\366\370\370\372\372\374"
+ "\374\375\376\377"},},
+{{},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\201\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\200\221\222\223\224\225\226\227\230\231\212\233\214\215\216\217\240\241"
+ "\241\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\262"
+ "\245\265\266\267\250\271\252\273\243\275\275\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\337"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\201\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\200\221\222\223\224\225\226\227\230\231\212\233\214\215\216\217\240\241"
+ "\241\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\262"
+ "\245\265\266\267\250\271\252\273\243\275\275\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\337"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\051\050\246\247\250\056\252\054\055\255\256\257\260\261\262\262"
+ "\264\264\266\266\270\270\272\272\274\274\276\276\300\300\302\302\304\304"
+ "\306\306\310\310\312\312\314\314\316\316\320\320\322\322\324\324\326\326"
+ "\330\330\332\332\334\334\336\336\340\340\342\342\344\344\346\346\350\350"
+ "\352\352\354\354\356\356\360\360\362\362\364\364\366\366\370\370\372\372"
+ "\374\374\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\212\233\214\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\237"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\212\233\214\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\237"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\241\262\263"
+ "\264\265\246\267\270\111\252\253\254\275\276\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\343\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\360\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\241\262\243"
+ "\264\245\246\267\270\251\252\253\254\275\256\275\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\266\270\271\272\340\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\323\323\324\325\326\327\330\331\332\333"
+ "\274\276\277\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\111\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\250\271\252\273\274\275\276\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\246\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\264\271\272\273\274\274\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\276"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\241\243\244\245\246\247\246\251\252\253\254\255\254\257\260\261\262\243"
+ "\264\265\266\267\264\262\252\273\274\274\276\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\276"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\314\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\242\270\271\272\340\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\323\323\324\325\326\327\330\331\332\333"
+ "\274\276\277\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\212\233\214\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\111\336\237"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\214\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\250\271\252\273\274\275\276\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\260\261\262\263\264\265\266\267"
+ "\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\360\241\242\243\244\245\246\247\250\251\252\253"
+ "\254\375\256\257"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\200\201"
+ "\202\203\204\205\206\207\210\211\212\213\214\215\216\217\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\220\221\222\223\224\225\226\227\230\231"
+ "\232\233\234\235\236\237\360\360\362\362\364\364\366\366\370\370\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\270\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\354\315\316\317\320\321\362\323\324\325\326\367\330\331\332\333"
+ "\334\335\376\264"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\200\201"
+ "\202\203\204\205\206\207\210\211\212\213\214\215\216\217\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\220\221\222\223\224\225\226\227\230\231"
+ "\232\233\234\235\236\237\360\360\362\362\364\364\366\366\370\370\372\373"
+ "\374\374\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\240\333"
+ "\334\335\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\270\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\354\315\316\317\320\321\362\323\324\325\326\367\330\331\332\333"
+ "\334\335\376\264"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\214\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\354\315\316\317\320\321\362\323\324\325\326\367\330\331\332\333"
+ "\334\335\376\237"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\203\216\205\217\200\210\211\212\213\214\215\216\217"
+ "\220\222\222\223\231\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\245\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\344\346\347\350\351"
+ "\352\353\354\350\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\200\201\202\203\204\205\206\207\210\211"
+ "\212\213\214\215\216\217\220\221\221\222\223\224\225\226\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\227\352\353\354\364\355\356\357\365\360"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\240\216\225\217\200\255\355\212\212\241\215\216\217"
+ "\220\222\222\342\231\225\226\227\227\231\232\235\234\235\236\237\240\241"
+ "\340\243\243\215\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\265\266\267\270\275\276\306\307"
+ "\317\331\332\333\334\335\336\337\340\341\342\343\345\345\346\343\350\350"
+ "\352\352\356\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\266\216\267\217\200\322\323\324\330\327\336\216\217"
+ "\220\222\222\342\231\343\352\353\230\231\232\235\234\235\236\237\265\326"
+ "\340\351\245\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\307\307\310\311\312\313\314\315\316\317\321\321\322\323\324\111\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\345\345\346\350\350\351"
+ "\352\353\355\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\266\216\336\217\200\235\323\212\212\327\215\216\217"
+ "\220\221\221\342\231\225\225\227\227\231\232\233\233\235\236\254\265\326"
+ "\340\351\244\244\246\246\250\250\252\215\254\270\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\275\277\300\301\302\303\304\305"
+ "\306\306\310\311\312\313\314\315\316\317\321\321\322\323\322\325\326\327"
+ "\267\331\332\333\334\335\336\337\340\341\342\343\343\325\346\346\350\351"
+ "\350\353\355\355\335\357\360\361\362\363\364\365\366\367\370\371\372\353"
+ "\374\374\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\266\216\267\217\200\322\323\324\330\327\336\216\217"
+ "\220\222\222\342\231\343\352\353\230\231\232\235\234\235\236\254\265\326"
+ "\340\351\245\245\246\246\250\250\252\253\254\270\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\275\277\300\301\302\303\304\305"
+ "\306\306\310\311\312\313\314\315\316\317\320\321\322\323\324\111\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\344\346\347\347\351"
+ "\352\353\354\354\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\266\216\267\217\200\322\323\324\330\327\111\216\217"
+ "\220\222\222\342\231\343\352\353\230\231\232\235\234\235\236\236\265\326"
+ "\340\351\245\245\246\246\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\307\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\345\345\346\347\350\351"
+ "\352\353\336\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\266\216\267\217\200\322\323\324\330\327\336\216\217"
+ "\220\222\222\342\231\343\352\353\230\231\232\235\234\235\236\237\265\326"
+ "\340\351\245\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\307\307\310\311\312\313\314\315\316\317\321\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\345\345\346\350\350\351"
+ "\352\353\355\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\217\216\221\206\200\211\211\222\213\214\230\216\217"
+ "\220\221\222\214\231\251\226\235\230\231\232\233\234\235\236\237\206\213"
+ "\237\226\245\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\344\346\347\350\351"
+ "\352\353\354\350\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\203\216\205\217\200\210\211\212\213\213\215\216\217"
+ "\220\222\222\223\231\215\226\227\227\231\232\235\234\235\236\237\244\245"
+ "\246\247\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\344\346\347\350\351"
+ "\352\353\354\350\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\245\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\344\346\347\350\351"
+ "\352\353\354\350\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\204\204\216\206\200\222\224\221\225\250\215\216\217"
+ "\220\221\222\231\224\225\236\235\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\344\346\347\350\351"
+ "\352\353\354\350\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\203\216\205\217\200\210\211\212\213\214\215\216\217"
+ "\220\222\222\223\231\225\226\227\230\231\232\235\234\235\236\237\240\241"
+ "\242\243\245\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\344\346\347\350\351"
+ "\352\353\354\350\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\206\234\215\217\220\221\241"
+ "\222\225\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\244\245"
+ "\246\331\332\333\334\247\250\337\251\252\254\255\265\266\267\270\275\276"
+ "\306\307\317\317\320\357\360\361\321\322\323\365\324\367\370\371\325\226"
+ "\374\230\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\261\263"
+ "\264\264\266\266\270\271\272\273\274\275\276\277\242\244\337\256\340\334"
+ "\347\355\241\243\350\255\330\245\332\333\320\246\322\323\320\345\322\323"
+ "\330\346\332\333\334\247\336\337\340\341\341\343\343\345\346\347\350\351"
+ "\351\353\353\355\356\356\360\360\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\241\242\243"
+ "\244\245\246\267\250\251\252\253\254\275\256\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\241\243\244\244\246\247\250\251\252\246\254\255\256\257\260\260\262\262"
+ "\264\264\266\267\250\267\252\273\254\275\275\273\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\257"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\220\203\202\203\204\205\206\207\210\211\214\213\214\216\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\242"
+ "\242\263\244\265\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\377\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\200\213\214\202\203\217"
+ "\220\221\222\223\224\225\204\227\230\231\205\233\234\235\236\206\040\041"
+ "\042\043\044\245\046\047\050\051\052\053\254\055\056\057\260\261\262\263"
+ "\264\265\266\267\270\271\072\273\074\075\076\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\133\134\135\136\137\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\173"
+ "\174\175\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\201\203\204\205\206\347\204\211\200\211\214\214\203\217"
+ "\217\221\352\221\224\224\226\356\226\357\205\315\362\235\235\206\240\241"
+ "\242\243\244\245\246\247\250\251\252\242\254\255\376\257\257\261\262\263"
+ "\261\265\266\267\374\271\271\273\273\275\275\277\277\301\302\303\301\305"
+ "\306\307\310\311\312\305\314\315\314\317\320\321\322\323\324\325\326\327"
+ "\317\331\331\333\334\335\333\337\337\341\342\343\341\345\345\347\350\350"
+ "\352\353\353\355\356\357\355\361\362\361\364\364\366\366\370\370\265\373"
+ "\374\373\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\347\313\345\200\314\201\202\203\351"
+ "\375\372\352\355\353\354\204\356\361\357\205\315\362\364\363\206\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\251\272\273\274\275\256\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\316\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\306\347\310\351"
+ "\352\353\354\355\356\357\320\361\362\363\364\111\366\367\370\371\372\373"
+ "\374\375\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\200\213\214\215\203\217"
+ "\220\221\222\223\224\225\226\227\230\231\205\233\234\235\236\206\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\315\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\316\327\330\331\337\332\260\265\276\242\266\274\241\270\271"
+ "\245\272\244\273\301\303\246\337\304\252\306\243\277\252\314\313\267\253"
+ "\275\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\200\213\214\202\203\217"
+ "\220\221\222\223\224\225\204\227\230\231\205\233\234\235\236\206\040\041"
+ "\042\043\044\045\246\047\051\050\052\053\054\055\056\057\060\061\062\063"
+ "\064\065\066\067\070\071\072\073\074\075\076\077\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\313\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\300\355\356\357\360\361\362\363\364\365\366\367\370\371\372\175"
+ "\135\173\133\174"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\347\313\345\200\314\201\202\203\351"
+ "\346\350\352\355\353\354\204\356\361\357\205\315\362\364\363\206\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\256\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\316\320\321\322\323\324\325\326\327"
+ "\331\331\332\333\334\334\336\336\240\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\111\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\347\313\345\200\314\201\202\203\351"
+ "\346\350\352\355\353\354\204\356\361\357\205\315\362\364\363\206\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\256\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\316\320\321\322\323\324\325\326\327"
+ "\331\331\332\333\334\335\336\336\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\111\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\347\313\345\200\314\201\202\203\351"
+ "\346\350\352\355\353\354\204\356\361\357\205\315\362\364\363\206\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\256\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\316\320\321\322\323\324\325\326\327"
+ "\331\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\111\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\203\204\205\206\207\215\216\217"
+ "\220\221\222\223\224\225\226\227\203\204\205\206\207\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\222\322\323\224\225\226\227"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\223\203\204"
+ "\205\206\207\217\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\347\313\345\200\314\201\202\203\351"
+ "\346\350\352\355\353\354\204\356\361\357\205\315\362\364\363\206\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\256\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\316\320\321\322\323\324\325\326\327"
+ "\331\331\332\332\334\111\336\336\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\253\255\256\256\260\261\262\263"
+ "\247\265\242\267\270\270\272\272\274\274\276\276\267\301\302\303\304\305"
+ "\306\307\310\311\312\313\313\315\315\301\320\321\322\323\324\325\326\327"
+ "\330\330\332\332\334\335\335\237\200\201\202\203\204\205\206\207\210\211"
+ "\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233"
+ "\234\235\236\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\201\202\203"
+ "\204\205\206\207\210\211\212\213\214\341\215\343\216\217\220\221\350\351"
+ "\352\353\222\223\224\225\226\341\227\230\231\111\232\233\350\351\352\373"
+ "\234\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\201\204\205\206\207\210\207\212\213\214\215\216\217"
+ "\200\221\222\223\224\225\226\227\210\206\212\213\214\215\216\217\240\241"
+ "\241\243\244\245\246\247\250\251\252\253\254\202\256\257\260\246\262\262"
+ "\245\244\266\267\250\271\252\273\243\275\275\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\337"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\201\203\204\205\205\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\232\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\201\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\200\221\222\223\224\225\226\227\230\231\212\233\214\215\216\217\240\241"
+ "\241\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\262"
+ "\245\265\266\267\250\271\252\273\243\275\275\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\337"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\241\242\243\244\245\246\247\257\260\261\262\263"
+ "\264\200\201\202\203\204\272\257\272\277\300\277\300\301\302\303\304\305"
+ "\205\301\302\303\304\206\207\315\210\211\212\213\305\315\331\332\214\215"
+ "\216\331\332\333\217\220\221\222\340\223\224\225\226\333\340\360\377\227"
+ "\230\231\232\233\234\235\360\236\237\001\002\004\005\006\021\022\023\024"
+ "\025\026\027\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\133\134\135"
+ "\136\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\201"
+ "\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\263"
+ "\264\223\226\227\230\271\272\273\274\264\225\277\300\301\302\303\304\305"
+ "\002\005\310\311\312\313\314\315\316\237\320\272\322\323\324\200\024\273"
+ "\274\331\332\031\036\335\263\277\300\301\302\303\304\305\377\006\310\311"
+ "\312\313\314\315\316\233\320\271\322\323\324\240\231\232\236\331\332\235"
+ "\234\335\224\377"},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+};
+
+const Recoder NCodepagePrivate::TCodePageData::rcdr_to_title[] = {
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\201\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\200\221\222\223\224\225\226\227\230\231\212\233\214\215\216\217\240\241"
+ "\241\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\262"
+ "\245\265\266\267\250\271\252\273\243\275\275\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\337"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\263\264\245\266\267\250\251\252\253\254\275\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\377\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\200\201"
+ "\202\203\204\205\206\207\210\211\212\213\214\215\216\217\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\220\221\222\223\224\225\226\227\230\231"
+ "\232\233\234\235\236\237\360\360\362\362\364\364\366\366\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\253\255\256\256\260\261\262\263"
+ "\247\265\242\267\270\270\272\272\274\274\276\276\267\301\302\303\304\305"
+ "\306\307\310\311\312\313\313\315\315\301\320\321\322\323\324\325\326\327"
+ "\330\330\332\332\334\335\335\237\200\201\202\203\204\205\206\207\210\211"
+ "\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233"
+ "\234\235\236\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\260\261\262\263\264\265\266\267"
+ "\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\360\241\242\243\244\245\246\247\250\251\252\253"
+ "\254\375\256\257"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\212\233\214\235\216\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\237"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\212\233\214\215\216\217\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\243"
+ "\264\265\266\267\270\245\252\273\274\275\274\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\241\262\243"
+ "\264\245\246\267\270\251\252\253\254\275\256\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\101\101\103\105\105\105\216\217"
+ "\220\201\202\203\204\205\206\207\105\111\111\117\125\125\216\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\241\242\243"
+ "\244\245\246\267\250\251\252\253\254\255\256\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\337"},},
+{{},},
+{{},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\201\201\203\203\205\205\207\207\211\211\213\213\215\215\217\217"
+ "\221\221\223\223\225\225\227\227\231\231\233\233\235\235\237\237\241\241"
+ "\243\243\245\245\247\247\251\251\253\253\255\255\256\257\260\261\262\263"
+ "\264\266\266\270\270\271\272\273\274\276\276\277\300\301\302\303\304\305"
+ "\307\307\310\311\312\313\314\315\316\317\321\321\323\323\325\325\327\327"
+ "\335\331\332\333\334\335\340\337\340\342\342\344\344\346\346\350\350\352"
+ "\352\354\354\356\356\357\360\362\362\364\364\366\366\370\370\372\372\374"
+ "\374\375\376\377"},},
+{{},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153"
+ "\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\201\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\200\221\222\223\224\225\226\227\230\231\212\233\214\215\216\217\240\241"
+ "\241\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\262"
+ "\245\265\266\267\250\271\252\273\243\275\275\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\337"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\201\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\200\221\222\223\224\225\226\227\230\231\212\233\214\215\216\217\240\241"
+ "\241\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\262"
+ "\245\265\266\267\250\271\252\273\243\275\275\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\337"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\051\050\246\247\250\056\252\054\055\255\256\257\260\261\262\262"
+ "\264\264\266\266\270\270\272\272\274\274\276\276\300\300\302\302\304\304"
+ "\306\306\310\310\312\312\314\314\316\316\320\320\322\322\324\324\326\326"
+ "\330\330\332\332\334\334\336\336\340\340\342\342\344\344\346\346\350\350"
+ "\352\352\354\354\356\356\360\360\362\362\364\364\366\366\370\370\372\372"
+ "\374\374\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\212\233\214\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\237"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\212\233\214\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\237"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\241\262\263"
+ "\264\265\246\267\270\111\252\253\254\275\276\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\343\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\360\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\241\262\243"
+ "\264\245\246\267\270\251\252\253\254\275\256\275\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\240"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\266\270\271\272\340\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\323\323\324\325\326\327\330\331\332\333"
+ "\274\276\277\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\111\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\250\271\252\273\274\275\276\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\246\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\264\271\272\273\274\274\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\276"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\241\243\244\245\246\247\246\251\252\253\254\255\254\257\260\261\262\243"
+ "\264\265\266\267\264\262\252\273\274\274\276\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\276"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\314\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\242\270\271\272\340\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\323\323\324\325\326\327\330\331\332\333"
+ "\274\276\277\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\212\233\214\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\111\336\237"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\214\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\250\271\252\273\274\275\276\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\260\261\262\263\264\265\266\267"
+ "\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\360\241\242\243\244\245\246\247\250\251\252\253"
+ "\254\375\256\257"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\200\201"
+ "\202\203\204\205\206\207\210\211\212\213\214\215\216\217\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\220\221\222\223\224\225\226\227\230\231"
+ "\232\233\234\235\236\237\360\360\362\362\364\364\366\366\370\370\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\270\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\354\315\316\317\320\321\362\323\324\325\326\367\330\331\332\333"
+ "\334\335\376\264"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\200\201"
+ "\202\203\204\205\206\207\210\211\212\213\214\215\216\217\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\220\221\222\223\224\225\226\227\230\231"
+ "\232\233\234\235\236\237\360\360\362\362\364\364\366\366\370\370\372\373"
+ "\374\374\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\240\333"
+ "\334\335\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\270\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\354\315\316\317\320\321\362\323\324\325\326\367\330\331\332\333"
+ "\334\335\376\264"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\214\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\354\315\316\317\320\321\362\323\324\325\326\367\330\331\332\333"
+ "\334\335\376\237"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\203\216\205\217\200\210\211\212\213\214\215\216\217"
+ "\220\222\222\223\231\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\245\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\344\346\347\350\351"
+ "\352\353\354\350\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\200\201\202\203\204\205\206\207\210\211"
+ "\212\213\214\215\216\217\220\221\221\222\223\224\225\226\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\227\352\353\354\364\355\356\357\365\360"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\240\216\225\217\200\255\355\212\212\241\215\216\217"
+ "\220\222\222\342\231\225\226\227\227\231\232\235\234\235\236\237\240\241"
+ "\340\243\243\215\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\265\266\267\270\275\276\306\307"
+ "\317\331\332\333\334\335\336\337\340\341\342\343\345\345\346\343\350\350"
+ "\352\352\356\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\266\216\267\217\200\322\323\324\330\327\336\216\217"
+ "\220\222\222\342\231\343\352\353\230\231\232\235\234\235\236\237\265\326"
+ "\340\351\245\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\307\307\310\311\312\313\314\315\316\317\321\321\322\323\324\111\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\345\345\346\350\350\351"
+ "\352\353\355\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\266\216\336\217\200\235\323\212\212\327\215\216\217"
+ "\220\221\221\342\231\225\225\227\227\231\232\233\233\235\236\254\265\326"
+ "\340\351\244\244\246\246\250\250\252\215\254\270\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\275\277\300\301\302\303\304\305"
+ "\306\306\310\311\312\313\314\315\316\317\321\321\322\323\322\325\326\327"
+ "\267\331\332\333\334\335\336\337\340\341\342\343\343\325\346\346\350\351"
+ "\350\353\355\355\335\357\360\361\362\363\364\365\366\367\370\371\372\353"
+ "\374\374\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\266\216\267\217\200\322\323\324\330\327\336\216\217"
+ "\220\222\222\342\231\343\352\353\230\231\232\235\234\235\236\254\265\326"
+ "\340\351\245\245\246\246\250\250\252\253\254\270\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\275\277\300\301\302\303\304\305"
+ "\306\306\310\311\312\313\314\315\316\317\320\321\322\323\324\111\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\344\346\347\347\351"
+ "\352\353\354\354\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\266\216\267\217\200\322\323\324\330\327\111\216\217"
+ "\220\222\222\342\231\343\352\353\230\231\232\235\234\235\236\236\265\326"
+ "\340\351\245\245\246\246\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\307\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\345\345\346\347\350\351"
+ "\352\353\336\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\266\216\267\217\200\322\323\324\330\327\336\216\217"
+ "\220\222\222\342\231\343\352\353\230\231\232\235\234\235\236\237\265\326"
+ "\340\351\245\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\307\307\310\311\312\313\314\315\316\317\321\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\345\345\346\350\350\351"
+ "\352\353\355\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\217\216\221\206\200\211\211\222\213\214\230\216\217"
+ "\220\221\222\214\231\251\226\235\230\231\232\233\234\235\236\237\206\213"
+ "\237\226\245\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\344\346\347\350\351"
+ "\352\353\354\350\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\203\216\205\217\200\210\211\212\213\213\215\216\217"
+ "\220\222\222\223\231\215\226\227\227\231\232\235\234\235\236\237\244\245"
+ "\246\247\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\344\346\347\350\351"
+ "\352\353\354\350\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\245\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\344\346\347\350\351"
+ "\352\353\354\350\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\204\204\216\206\200\222\224\221\225\250\215\216\217"
+ "\220\221\222\231\224\225\236\235\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\344\346\347\350\351"
+ "\352\353\354\350\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\232\220\203\216\205\217\200\210\211\212\213\214\215\216\217"
+ "\220\222\222\223\231\225\226\227\230\231\232\235\234\235\236\237\240\241"
+ "\242\243\245\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\344\346\347\350\351"
+ "\352\353\354\350\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\206\234\215\217\220\221\241"
+ "\222\225\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\244\245"
+ "\246\331\332\333\334\247\250\337\251\252\254\255\265\266\267\270\275\276"
+ "\306\307\317\317\320\357\360\361\321\322\323\365\324\367\370\371\325\226"
+ "\374\230\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\261\263"
+ "\264\264\266\266\270\271\272\273\274\275\276\277\242\244\337\256\340\334"
+ "\347\355\241\243\350\255\330\245\332\333\320\246\322\323\320\345\322\323"
+ "\330\346\332\333\334\247\336\337\340\341\341\343\343\345\346\347\350\351"
+ "\351\353\353\355\356\356\360\360\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\241\242\243"
+ "\244\245\246\267\250\251\252\253\254\275\256\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\241\243\244\244\246\247\250\251\252\246\254\255\256\257\260\260\262\262"
+ "\264\264\266\267\250\267\252\273\254\275\275\273\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\257"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\220\203\202\203\204\205\206\207\210\211\214\213\214\216\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\242"
+ "\242\263\244\265\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\340\341\342\343\344\345"
+ "\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367"
+ "\370\371\372\373\374\375\376\377\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\200\213\214\202\203\217"
+ "\220\221\222\223\224\225\204\227\230\231\205\233\234\235\236\206\040\041"
+ "\042\043\044\245\046\047\050\051\052\053\254\055\056\057\260\261\262\263"
+ "\264\265\266\267\270\271\072\273\074\075\076\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\133\134\135\136\137\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\173"
+ "\174\175\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\201\203\204\205\206\347\204\211\200\211\214\214\203\217"
+ "\217\221\352\221\224\224\226\356\226\357\205\315\362\235\235\206\240\241"
+ "\242\243\244\245\246\247\250\251\252\242\254\255\376\257\257\261\262\263"
+ "\261\265\266\267\374\271\271\273\273\275\275\277\277\301\302\303\301\305"
+ "\306\307\310\311\312\305\314\315\314\317\320\321\322\323\324\325\326\327"
+ "\317\331\331\333\334\335\333\337\337\341\342\343\341\345\345\347\350\350"
+ "\352\353\353\355\356\357\355\361\362\361\364\364\366\366\370\370\265\373"
+ "\374\373\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\347\313\345\200\314\201\202\203\351"
+ "\375\372\352\355\353\354\204\356\361\357\205\315\362\364\363\206\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\251\272\273\274\275\256\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\316\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\306\347\310\351"
+ "\352\353\354\355\356\357\320\361\362\363\364\111\366\367\370\371\372\373"
+ "\374\375\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\200\213\214\215\203\217"
+ "\220\221\222\223\224\225\226\227\230\231\205\233\234\235\236\206\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\315\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\316\327\330\331\337\332\260\265\276\242\266\274\241\270\271"
+ "\245\272\244\273\301\303\246\337\304\252\306\243\277\252\314\313\267\253"
+ "\275\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\200\213\214\202\203\217"
+ "\220\221\222\223\224\225\204\227\230\231\205\233\234\235\236\206\040\041"
+ "\042\043\044\045\246\047\051\050\052\053\054\055\056\057\060\061\062\063"
+ "\064\065\066\067\070\071\072\073\074\075\076\077\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\313\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\300\355\356\357\360\361\362\363\364\365\366\367\370\371\372\175"
+ "\135\173\133\174"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\347\313\345\200\314\201\202\203\351"
+ "\346\350\352\355\353\354\204\356\361\357\205\315\362\364\363\206\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\256\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\316\320\321\322\323\324\325\326\327"
+ "\331\331\332\333\334\334\336\336\240\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\111\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\347\313\345\200\314\201\202\203\351"
+ "\346\350\352\355\353\354\204\356\361\357\205\315\362\364\363\206\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\256\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\316\320\321\322\323\324\325\326\327"
+ "\331\331\332\333\334\335\336\336\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\111\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\347\313\345\200\314\201\202\203\351"
+ "\346\350\352\355\353\354\204\356\361\357\205\315\362\364\363\206\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\256\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\316\320\321\322\323\324\325\326\327"
+ "\331\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\111\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\203\204\205\206\207\215\216\217"
+ "\220\221\222\223\224\225\226\227\203\204\205\206\207\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\222\322\323\224\225\226\227"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\223\203\204"
+ "\205\206\207\217\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\347\313\345\200\314\201\202\203\351"
+ "\346\350\352\355\353\354\204\356\361\357\205\315\362\364\363\206\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\256\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\316\320\321\322\323\324\325\326\327"
+ "\331\331\332\332\334\111\336\336\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\253\255\256\256\260\261\262\263"
+ "\247\265\242\267\270\270\272\272\274\274\276\276\267\301\302\303\304\305"
+ "\306\307\310\311\312\313\313\315\315\301\320\321\322\323\324\325\326\327"
+ "\330\330\332\332\334\335\335\237\200\201\202\203\204\205\206\207\210\211"
+ "\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233"
+ "\234\235\236\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\201\202\203"
+ "\204\205\206\207\210\211\212\213\214\341\215\343\216\217\220\221\350\351"
+ "\352\353\222\223\224\225\226\341\227\230\231\111\232\233\350\351\352\373"
+ "\234\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\201\204\205\206\207\210\207\212\213\214\215\216\217"
+ "\200\221\222\223\224\225\226\227\210\206\212\213\214\215\216\217\240\241"
+ "\241\243\244\245\246\247\250\251\252\253\254\202\256\257\260\246\262\262"
+ "\245\244\266\267\250\271\252\273\243\275\275\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\337"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\201\203\204\205\205\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\232\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\367\330\331\332\333"
+ "\334\335\336\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\201\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\200\221\222\223\224\225\226\227\230\231\212\233\214\215\216\217\240\241"
+ "\241\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\262"
+ "\245\265\266\267\250\271\252\273\243\275\275\257\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\300\301\302\303\304\305\306\307\310\311"
+ "\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333"
+ "\334\335\336\337"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\241\242\243\244\245\246\247\257\260\261\262\263"
+ "\264\200\201\202\203\204\272\257\272\277\300\277\300\301\302\303\304\305"
+ "\205\301\302\303\304\206\207\315\210\211\212\213\305\315\331\332\214\215"
+ "\216\331\332\333\217\220\221\222\340\223\224\225\226\333\340\360\377\227"
+ "\230\231\232\233\234\235\360\236\237\001\002\004\005\006\021\022\023\024"
+ "\025\026\027\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\133\134\135"
+ "\136\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241"
+ "\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263"
+ "\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305"
+ "\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327"
+ "\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351"
+ "\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373"
+ "\374\375\376\377"},},
+{{"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021"
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043"
+ "\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065"
+ "\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107"
+ "\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131"
+ "\132\133\134\135\136\137\140\101\102\103\104\105\106\107\110\111\112\113"
+ "\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\173\174\175"
+ "\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\201"
+ "\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\263"
+ "\264\223\226\227\230\271\272\273\274\264\225\277\300\301\302\303\304\305"
+ "\002\005\310\311\312\313\314\315\316\237\320\272\322\323\324\200\024\273"
+ "\274\331\332\031\036\335\263\277\300\301\302\303\304\305\377\006\310\311"
+ "\312\313\314\315\316\233\320\271\322\323\324\240\231\232\236\331\332\235"
+ "\234\335\224\377"},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+{{},},
+};
+
diff --git a/library/cpp/charset/iconv.cpp b/library/cpp/charset/iconv.cpp
new file mode 100644
index 0000000000..df43471470
--- /dev/null
+++ b/library/cpp/charset/iconv.cpp
@@ -0,0 +1,94 @@
+#include "iconv.h"
+
+#include <contrib/libs/libiconv/iconv.h>
+
+using namespace NICONVPrivate;
+
+TDescriptor::TDescriptor(const char* from, const char* to)
+ : Descriptor_(libiconv_open(to, from))
+ , From_(from)
+ , To_(to)
+{
+ if (!Invalid()) {
+ int temp = 1;
+
+ libiconvctl(Descriptor_, ICONV_SET_DISCARD_ILSEQ, &temp);
+ }
+}
+
+TDescriptor::~TDescriptor() {
+ if (!Invalid()) {
+ libiconv_close(Descriptor_);
+ }
+}
+
+size_t NICONVPrivate::RecodeImpl(const TDescriptor& descriptor, const char* in, char* out, size_t inSize, size_t outSize, size_t& read, size_t& written) {
+ Y_ASSERT(!descriptor.Invalid());
+ Y_ASSERT(in);
+ Y_ASSERT(out);
+
+ char* inPtr = const_cast<char*>(in);
+ char* outPtr = out;
+ size_t inSizeMod = inSize;
+ size_t outSizeMod = outSize;
+ size_t res = libiconv(descriptor.Get(), &inPtr, &inSizeMod, &outPtr, &outSizeMod);
+
+ read = inSize - inSizeMod;
+ written = outSize - outSizeMod;
+
+ return res;
+}
+
+void NICONVPrivate::DoRecode(const TDescriptor& descriptor, const char* in, char* out, size_t inSize, size_t outSize, size_t& read, size_t& written) {
+ if (descriptor.Invalid()) {
+ ythrow yexception() << "Can not convert from " << descriptor.From() << " to " << descriptor.To();
+ }
+
+ size_t res = RecodeImpl(descriptor, in, out, inSize, outSize, read, written);
+
+ if (res == static_cast<size_t>(-1)) {
+ switch (errno) {
+ case EILSEQ:
+ read = inSize;
+ break;
+
+ case EINVAL:
+ read = inSize;
+ break;
+
+ case E2BIG:
+ ythrow yexception() << "Iconv error: output buffer is too small";
+
+ default:
+ ythrow yexception() << "Unknown iconv error";
+ }
+ }
+}
+
+RECODE_RESULT NICONVPrivate::DoRecodeNoThrow(const TDescriptor& descriptor, const char* in, char* out, size_t inSize, size_t outSize, size_t& read, size_t& written) {
+ if (descriptor.Invalid()) {
+ return RECODE_ERROR;
+ }
+
+ size_t res = RecodeImpl(descriptor, in, out, inSize, outSize, read, written);
+
+ if (res == static_cast<size_t>(-1)) {
+ switch (errno) {
+ case EILSEQ:
+ read = inSize;
+ break;
+
+ case EINVAL:
+ read = inSize;
+ break;
+
+ case E2BIG:
+ return RECODE_EOOUTPUT;
+
+ default:
+ return RECODE_ERROR;
+ }
+ }
+
+ return RECODE_OK;
+}
diff --git a/library/cpp/charset/iconv.h b/library/cpp/charset/iconv.h
new file mode 100644
index 0000000000..ac13539347
--- /dev/null
+++ b/library/cpp/charset/iconv.h
@@ -0,0 +1,136 @@
+#pragma once
+
+#include "codepage.h"
+
+#include <util/generic/noncopyable.h>
+
+// WARNING: Do not use this functions - use functions from wide.h or recyr.hh instead.
+
+namespace NICONVPrivate {
+ inline const char* CharsetName(ECharset code) {
+ return NameByCharset(code);
+ }
+
+ inline const char* CharsetName(const char* code) {
+ return code;
+ }
+
+ template <int size>
+ inline const char* UnicodeNameBySize();
+
+ template <>
+ inline const char* UnicodeNameBySize<1>() {
+ return "UTF-8";
+ }
+
+ template <>
+ inline const char* UnicodeNameBySize<2>() {
+ return "UTF-16LE";
+ }
+
+ template <>
+ inline const char* UnicodeNameBySize<4>() {
+ return "UCS-4LE";
+ }
+
+ template <class C>
+ inline const char* UnicodeName() {
+ return UnicodeNameBySize<sizeof(C)>();
+ }
+
+ class TDescriptor : NNonCopyable::TNonCopyable {
+ private:
+ void* Descriptor_;
+ const char* From_;
+ const char* To_;
+
+ public:
+ template <class TFrom, class TTo>
+ inline TDescriptor(TFrom from, TTo to)
+ : TDescriptor(CharsetName(from), CharsetName(to))
+ {
+ }
+
+ TDescriptor(const char* from, const char* to);
+
+ ~TDescriptor();
+
+ inline void* Get() const {
+ return Descriptor_;
+ }
+
+ inline bool Invalid() const {
+ return Descriptor_ == (void*)(-1);
+ }
+
+ inline const char* From() const noexcept {
+ return From_;
+ }
+
+ inline const char* To() const noexcept {
+ return To_;
+ }
+ };
+
+ template <class TFrom, class TTo>
+ inline bool CanConvert(TFrom from, TTo to) {
+ TDescriptor descriptor(from, to);
+
+ return !descriptor.Invalid();
+ }
+
+ size_t RecodeImpl(const TDescriptor& descriptor, const char* in, char* out, size_t inSize, size_t outSize, size_t& read, size_t& written);
+ void DoRecode(const TDescriptor& descriptor, const char* in, char* out, size_t inSize, size_t outSize, size_t& read, size_t& written);
+
+ template <class TFrom, class TTo>
+ inline void Recode(TFrom from, TTo to, const char* in, char* out, size_t inSize, size_t outSize, size_t& read, size_t& written) {
+ TDescriptor descriptor(from, to);
+
+ DoRecode(descriptor, in, out, inSize, outSize, read, written);
+ }
+
+ template <class TCharType>
+ inline void RecodeToUnicode(ECharset from, const char* in, TCharType* out, size_t inSize, size_t outSize, size_t& read, size_t& written) {
+ const size_t charSize = sizeof(TCharType);
+
+ Recode(from, UnicodeName<TCharType>(), in, reinterpret_cast<char*>(out), inSize, outSize * charSize, read, written);
+ written /= charSize;
+ }
+
+ template <class TCharType>
+ inline void RecodeFromUnicode(ECharset to, const TCharType* in, char* out, size_t inSize, size_t outSize, size_t& read, size_t& written) {
+ const size_t charSize = sizeof(TCharType);
+
+ Recode(UnicodeName<TCharType>(), to, reinterpret_cast<const char*>(in), out, inSize * charSize, outSize, read, written);
+ read /= charSize;
+ }
+
+ RECODE_RESULT DoRecodeNoThrow(const TDescriptor& d, const char* in, char* out, size_t inSize, size_t outSize, size_t& read, size_t& written);
+
+ template <class TFrom, class TTo>
+ inline RECODE_RESULT RecodeNoThrow(TFrom from, TTo to, const char* in, char* out, size_t inSize, size_t outSize, size_t& read, size_t& written) {
+ TDescriptor descriptor(from, to);
+
+ return DoRecodeNoThrow(descriptor, in, out, inSize, outSize, read, written);
+ }
+
+ template <class TCharType>
+ inline RECODE_RESULT RecodeToUnicodeNoThrow(ECharset from, const char* in, TCharType* out, size_t inSize, size_t outSize, size_t& read, size_t& written) {
+ const size_t charSize = sizeof(TCharType);
+
+ RECODE_RESULT res = RecodeNoThrow(from, UnicodeName<TCharType>(), in, reinterpret_cast<char*>(out), inSize, outSize * charSize, read, written);
+ written /= charSize;
+
+ return res;
+ }
+
+ template <class TCharType>
+ inline RECODE_RESULT RecodeFromUnicodeNoThrow(ECharset to, const TCharType* in, char* out, size_t inSize, size_t outSize, size_t& read, size_t& written) {
+ const size_t charSize = sizeof(TCharType);
+
+ RECODE_RESULT res = RecodeNoThrow(UnicodeName<TCharType>(), to, reinterpret_cast<const char*>(in), out, inSize * charSize, outSize, read, written);
+ read /= charSize;
+
+ return res;
+ }
+}
diff --git a/library/cpp/charset/iconv_ut.cpp b/library/cpp/charset/iconv_ut.cpp
new file mode 100644
index 0000000000..e8c56f6d49
--- /dev/null
+++ b/library/cpp/charset/iconv_ut.cpp
@@ -0,0 +1,87 @@
+#include "wide.h"
+#include "recyr.hh"
+#include "codepage.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+static void TestIconv(const TString& utf8, const TString& other, ECharset enc) {
+ TUtf16String wide0 = CharToWide(utf8, CODES_UTF8);
+ TUtf16String wide1 = CharToWide(other, enc);
+
+ UNIT_ASSERT(wide0 == wide1);
+
+ TString temp = WideToUTF8(wide0);
+ UNIT_ASSERT(temp == utf8);
+
+ temp = WideToChar(wide0, enc);
+ UNIT_ASSERT(temp == other);
+
+ temp = Recode(enc, CODES_UTF8, other);
+ UNIT_ASSERT(temp == utf8);
+
+ temp = Recode(CODES_UTF8, enc, utf8);
+ UNIT_ASSERT(temp == other);
+
+ size_t read = 0;
+ size_t written = 0;
+
+ RECODE_RESULT res = RecodeToUnicode(enc, other.c_str(), wide1.begin(), other.size(), wide1.size(), read, written);
+ UNIT_ASSERT(res == RECODE_OK);
+ UNIT_ASSERT(read == other.size());
+ UNIT_ASSERT(written == wide1.size());
+ UNIT_ASSERT(wide0 == wide1);
+
+ res = RecodeFromUnicode(enc, wide0.c_str(), temp.begin(), wide0.size(), temp.size(), read, written);
+ UNIT_ASSERT(res == RECODE_OK);
+ UNIT_ASSERT(read == wide0.size());
+ UNIT_ASSERT(written == other.size());
+ UNIT_ASSERT(temp == other);
+}
+
+class TIconvTest: public TTestBase {
+ static void TestSurrogates(const char* str, const wchar16* wide, size_t wideSize) {
+ size_t sSize = strlen(str);
+ size_t wSize = sSize * 2;
+ TArrayHolder<wchar16> w(new wchar16[wSize]);
+
+ size_t read = 0;
+ size_t written = 0;
+ NICONVPrivate::RecodeToUnicode(CODES_UTF8, str, w.Get(), sSize, wSize, read, written);
+ UNIT_ASSERT(read == sSize);
+ UNIT_ASSERT(written == wideSize);
+ UNIT_ASSERT(!memcmp(w.Get(), wide, wideSize));
+
+ TArrayHolder<char> s(new char[sSize]);
+ NICONVPrivate::RecodeFromUnicode(CODES_UTF8, w.Get(), s.Get(), wideSize, sSize, read, written);
+ UNIT_ASSERT(read == wideSize);
+ UNIT_ASSERT(written == sSize);
+ UNIT_ASSERT(!memcmp(s.Get(), str, sSize));
+ }
+
+private:
+ UNIT_TEST_SUITE(TIconvTest);
+ UNIT_TEST(TestBig5);
+ UNIT_TEST(TestSurrogatePairs);
+ UNIT_TEST_SUITE_END();
+
+public:
+ void TestBig5() {
+ UNIT_ASSERT(!NCodepagePrivate::NativeCodepage(CODES_BIG5));
+ const char* UTF8 = "\xe5\xad\xb8\xe7\x94\x9f\xe7\xb8\xbd\xe4\xba\xba\xe6\x95\xb8\xe6\x99\xae\xe9\x80\x9a\xe7\x8f\xad";
+ const char* BIG5 = "\xbe\xc7\xa5\xcd\xc1\x60\xa4\x48\xbc\xc6\xb4\xb6\xb3\x71\xaf\x5a";
+
+ TestIconv(UTF8, BIG5, CODES_BIG5);
+ }
+
+ void TestSurrogatePairs() {
+ const char* utf8NonBMP = "\xf4\x80\x89\x84\xf4\x80\x89\x87\xf4\x80\x88\xba";
+ wchar16 wNonBMPDummy[] = {0xDBC0, 0xDE44, 0xDBC0, 0xDE47, 0xDBC0, 0xDE3A};
+ TestSurrogates(utf8NonBMP, wNonBMPDummy, Y_ARRAY_SIZE(wNonBMPDummy));
+
+ const char* utf8NonBMP2 = "ab\xf4\x80\x89\x87n";
+ wchar16 wNonBMPDummy2[] = {'a', 'b', 0xDBC0, 0xDE47, 'n'};
+ TestSurrogates(utf8NonBMP2, wNonBMPDummy2, Y_ARRAY_SIZE(wNonBMPDummy2));
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TIconvTest);
diff --git a/library/cpp/charset/recyr.hh b/library/cpp/charset/recyr.hh
new file mode 100644
index 0000000000..5ec8734bcf
--- /dev/null
+++ b/library/cpp/charset/recyr.hh
@@ -0,0 +1,164 @@
+#pragma once
+
+#include <cstdlib>
+
+#include <util/charset/recode_result.h>
+#include <util/generic/ptr.h>
+#include <util/generic/yexception.h>
+
+#include "codepage.h"
+#include "doccodes.h"
+#include "iconv.h"
+#include "recyr_int.hh"
+
+///////////////////////////////////////////////////////////////////////////////////////
+// input buf -> output buf //
+///////////////////////////////////////////////////////////////////////////////////////
+template <class TCharType>
+inline RECODE_RESULT RecodeToUnicode(ECharset from, const char* in, TCharType* out, size_t inSize, size_t outSize, size_t& inRead, size_t& outWritten) {
+ static_assert(sizeof(TCharType) > 1, "expect wide character type");
+
+ return NCodepagePrivate::_recodeToUnicode(from, in, out, inSize, outSize, inRead, outWritten);
+}
+
+template <class TCharType>
+inline RECODE_RESULT RecodeFromUnicode(ECharset to, const TCharType* in, char* out, size_t inSize, size_t outSize, size_t& inRead, size_t& outWritten) {
+ static_assert(sizeof(TCharType) > 1, "expect wide character type");
+
+ return NCodepagePrivate::_recodeFromUnicode(to, in, out, inSize, outSize, inRead, outWritten);
+}
+
+inline RECODE_RESULT RecodeFromUnicode(ECharset to, wchar32 rune, char* out, size_t outSize, size_t& outWritten) {
+ return NCodepagePrivate::_recodeFromUnicode(to, rune, out, outSize, outWritten);
+}
+
+template <class TCharType>
+inline RECODE_RESULT RecodeToUnicode(ECharset from, const char* in, TCharType* out, size_t inSize, size_t outSize) {
+ size_t inRead = 0;
+ size_t outWritten = 0;
+ return RecodeToUnicode(from, in, out, inSize, outSize, inRead, outWritten);
+}
+
+template <class TCharType>
+inline RECODE_RESULT RecodeFromUnicode(ECharset to, const TCharType* in, char* out, size_t inSize, size_t outSize) {
+ size_t inRead = 0;
+ size_t outWritten = 0;
+ return RecodeFromUnicode(to, in, out, inSize, outSize, inRead, outWritten);
+}
+
+inline RECODE_RESULT RecodeFromUnicode(ECharset theEncoding, const wchar16* chars, size_t length,
+ char* bytes, size_t size, size_t* read = nullptr, size_t* written = nullptr) {
+ size_t w = 0, r = 0;
+ RECODE_RESULT rc = ::RecodeFromUnicode(theEncoding, chars, bytes, length, size, r, w);
+ if (read)
+ *read = r;
+ if (written)
+ *written = w;
+ return rc;
+}
+
+inline RECODE_RESULT Recode(ECharset from, ECharset to, const char* in, char* out, size_t inSize, size_t outSize, size_t& inRead, size_t& outWritten) {
+ inRead = 0;
+ outWritten = 0;
+
+ if (!ValidCodepage(to) || !ValidCodepage(from))
+ return RECODE_ERROR;
+
+ if (to == from)
+ return NCodepagePrivate::_recodeCopy(in, out, inSize, outSize, inRead, outWritten);
+
+ if (NCodepagePrivate::NativeCodepage(from) && NCodepagePrivate::NativeCodepage(to)) {
+ if (from == CODES_UTF8)
+ return NCodepagePrivate::_recodeFromUTF8(to, in, out, inSize, outSize, inRead, outWritten);
+ if (to == CODES_UTF8)
+ return NCodepagePrivate::_recodeToUTF8(from, in, out, inSize, outSize, inRead, outWritten);
+ if (from == CODES_YANDEX)
+ return NCodepagePrivate::_recodeFromYandex(to, in, out, inSize, outSize, inRead, outWritten);
+ if (to == CODES_YANDEX)
+ return NCodepagePrivate::_recodeToYandex(from, in, out, inSize, outSize, inRead, outWritten);
+ } else if (NICONVPrivate::CanConvert(from, to)) {
+ return NICONVPrivate::RecodeNoThrow(from, to, in, out, inSize, outSize, inRead, outWritten);
+ }
+
+ size_t wideSize = inSize * 3;
+ TArrayHolder<wchar16> wide(new wchar16[wideSize]);
+
+ size_t wideRead = 0;
+ size_t wideWritten = 0;
+
+ RECODE_RESULT res = RecodeToUnicode(from, in, wide.Get(), inSize, wideSize, inRead, wideWritten);
+ if (res != RECODE_OK)
+ return res;
+
+ res = RecodeFromUnicode(to, wide.Get(), out, wideWritten, outSize, wideRead, outWritten);
+
+ return res;
+}
+
+inline RECODE_RESULT Recode(ECharset from, ECharset to, const char* in, char* out, size_t inSize, size_t outSize) {
+ size_t inRead = 0;
+ size_t outWritten = 0;
+ return Recode(from, to, in, out, inSize, outSize, inRead, outWritten);
+}
+
+/**
+ * Recode from one charset to another; throw an exception if conversion failed
+ * @param[in] from the source character set
+ * @param[in] to the target character set
+ * @param[in] in the input string buffer
+ * @param[out] out the output string object if conversion was successful
+ * @return false if conversion was not attempted (charsets were the same),
+ * true if successful
+ */
+inline bool Recode(ECharset from, ECharset to, const TStringBuf& in, TString& out) {
+ if (to == from)
+ return false;
+
+ const size_t inSize = in.length();
+ const size_t outSize = SingleByteCodepage(to) ? inSize : 3 * inSize;
+ out.clear(); // so we don't copy stuff around when resizing
+ out.ReserveAndResize(outSize);
+
+ size_t inRead = 0;
+ size_t outWritten = 0;
+ const RECODE_RESULT res = Recode(from, to, in.data(), out.begin(), inSize, outSize, inRead, outWritten);
+ Y_ENSURE(RECODE_OK == res, "Recode failed. ");
+ if (outWritten > outSize)
+ ythrow yexception() << "Recode overrun the buffer: size="
+ << outSize << " need=" << outWritten;
+
+ out.remove(outWritten);
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+// TString -> TString //
+///////////////////////////////////////////////////////////////////////////////////////
+inline TString Recode(ECharset from, ECharset to, const TString& in) {
+ TString out;
+ return to != from && Recode(from, to, in, out) ? out : in;
+}
+inline TString RecodeToYandex(ECharset from, const TString& in) {
+ return Recode(from, CODES_YANDEX, in);
+}
+inline TString RecodeFromYandex(ECharset to, const TString& in) {
+ return Recode(CODES_YANDEX, to, in);
+}
+
+inline TString RecodeToHTMLEntities(ECharset from, const TString& in) {
+ RECODE_RESULT res;
+ size_t outWritten, inRead;
+ TString out;
+ out.resize(in.length() * (4 + 4));
+ res = NCodepagePrivate::_recodeToHTMLEntities(from, in.c_str(), out.begin(), in.length(), out.length(), inRead, outWritten);
+ if (res == RECODE_EOOUTPUT) { //input contains many 8-byte characters?
+ out.resize(in.length() * (4 + 8));
+ res = NCodepagePrivate::_recodeToHTMLEntities(from, in.c_str(), out.begin(), in.length(), out.length(), inRead, outWritten);
+ }
+ if (res != RECODE_OK) {
+ ythrow yexception() << "Recode to HTML entities failed";
+ }
+
+ out.resize(outWritten - 1);
+ return out;
+}
diff --git a/library/cpp/charset/recyr_int.hh b/library/cpp/charset/recyr_int.hh
new file mode 100644
index 0000000000..353af53305
--- /dev/null
+++ b/library/cpp/charset/recyr_int.hh
@@ -0,0 +1,336 @@
+#pragma once
+
+#include <util/charset/recode_result.h>
+#include <util/charset/utf8.h>
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+#include <util/system/defaults.h>
+
+#include "codepage.h"
+#include "doccodes.h"
+#include "iconv.h"
+#include "wide.h"
+
+namespace NCodepagePrivate {
+ inline RECODE_RESULT _recodeCopy(const char* in, char* out, size_t in_size, size_t out_size, size_t& in_readed, size_t& out_writed) {
+ in_readed = in_size;
+ RECODE_RESULT res = RECODE_OK;
+ if (in_readed > out_size) {
+ res = RECODE_EOOUTPUT;
+ in_readed = out_size;
+ }
+ if (in != out)
+ memcpy(out, in, in_readed);
+ out_writed = in_readed;
+ return res;
+ }
+
+ inline RECODE_RESULT _recodeToUTF8(ECharset From, const char* in, char* out, size_t in_size, size_t out_size, size_t& in_readed, size_t& out_writed) {
+ if (From == CODES_UTF8)
+ return _recodeCopy(in, out, in_size, out_size, in_readed, out_writed);
+ const CodePage* cp = CodePageByCharset(From);
+
+ const unsigned char* in_start = (const unsigned char*)in;
+ const unsigned char* in_end = in_start + in_size;
+ const unsigned char* out_start = (unsigned char*)out;
+ const unsigned char* out_end = out_start + out_size;
+
+ size_t rune_len;
+ RECODE_RESULT res = RECODE_OK;
+ while ((unsigned char*)in < in_end && res == RECODE_OK) {
+ res = SafeWriteUTF8Char(cp->unicode[(unsigned char)(*in++)], rune_len, (unsigned char*)out, out_end);
+ out += rune_len;
+ }
+ in_readed = (unsigned char*)in - in_start;
+ out_writed = (unsigned char*)out - out_start;
+ return res;
+ }
+
+ inline RECODE_RESULT _recodeFromUTF8(ECharset to, const char* in, char* out, size_t in_size, size_t out_size, size_t& in_readed, size_t& out_writed) {
+ if (to == CODES_UTF8)
+ return _recodeCopy(in, out, in_size, out_size, in_readed, out_writed);
+ Y_ASSERT(CODES_UNKNOWN < to && to < CODES_MAX);
+ const Encoder* enc = &EncoderByCharset(to);
+
+ const unsigned char* in_start = (const unsigned char*)in;
+ const unsigned char* in_end = in_start + in_size;
+ const unsigned char* out_start = (unsigned char*)out;
+ const unsigned char* out_end = out_start + out_size;
+
+ wchar32 rune;
+ size_t rune_len;
+ RECODE_RESULT res = RECODE_OK;
+ while ((const unsigned char*)in < in_end && (res == RECODE_OK || res == RECODE_BROKENSYMBOL)) {
+ res = SafeReadUTF8Char(rune, rune_len, (const unsigned char*)in, in_end);
+ if (res == RECODE_BROKENSYMBOL)
+ rune_len = 1;
+ if (res != RECODE_EOINPUT)
+ *out++ = enc->Tr(rune);
+ in += rune_len;
+ if (res == RECODE_OK && (const unsigned char*)in < in_end && (unsigned char*)out >= out_end)
+ res = RECODE_EOOUTPUT;
+ }
+ in_readed = (unsigned char*)in - in_start;
+ out_writed = (unsigned char*)out - out_start;
+ return res;
+ }
+
+ inline RECODE_RESULT _recodeToYandex(ECharset From, const char* in, char* out, size_t in_size, size_t out_size, size_t& in_readed, size_t& out_writed) {
+ if (From == CODES_YANDEX)
+ return _recodeCopy(in, out, in_size, out_size, in_readed, out_writed);
+ if (From == CODES_UTF8)
+ return _recodeFromUTF8(CODES_YANDEX, in, out, in_size, out_size, in_readed, out_writed);
+ in_readed = (out_size > in_size) ? in_size : out_size;
+ const Recoder& rcdr = NCodepagePrivate::TCodePageData::rcdr_to_yandex[From];
+ rcdr.Tr(in, out, in_readed);
+ out_writed = in_readed;
+ if (out_size < in_size)
+ return RECODE_EOOUTPUT;
+ return RECODE_OK;
+ }
+ inline RECODE_RESULT _recodeFromYandex(ECharset To, const char* in, char* out, size_t in_size, size_t out_size, size_t& in_readed, size_t& out_writed) {
+ if (To == CODES_YANDEX)
+ return _recodeCopy(in, out, in_size, out_size, in_readed, out_writed);
+ if (To == CODES_UTF8)
+ return _recodeToUTF8(CODES_YANDEX, in, out, in_size, out_size, in_readed, out_writed);
+ in_readed = (out_size > in_size) ? in_size : out_size;
+ const Recoder& rcdr = NCodepagePrivate::TCodePageData::rcdr_from_yandex[To];
+ rcdr.Tr(in, out, in_readed);
+ out_writed = in_readed;
+ if (out_size < in_size)
+ return RECODE_EOOUTPUT;
+ return RECODE_OK;
+ }
+
+ template <class TCharType>
+ inline RECODE_RESULT _recodeUTF8ToUnicode(const char* in, TCharType* out, size_t in_size, size_t out_size, size_t& in_readed, size_t& out_writed) {
+ const unsigned char* inp = (const unsigned char*)in;
+ const unsigned char* in_end = inp + in_size;
+ TCharType* outp = out;
+ const TCharType* out_end = outp + out_size;
+ size_t rune_len;
+ wchar32 rune;
+ RECODE_RESULT res = RECODE_OK;
+ while ((res == RECODE_OK || res == RECODE_BROKENSYMBOL) && inp < in_end && outp < out_end) {
+ res = SafeReadUTF8Char(rune, rune_len, inp, in_end);
+ if (res == RECODE_BROKENSYMBOL)
+ rune_len = 1;
+ if (res == RECODE_OK || res == RECODE_BROKENSYMBOL) {
+ if (!WriteSymbol(rune, outp, out_end)) {
+ break;
+ }
+ inp += rune_len;
+ }
+ }
+ in_readed = inp - (const unsigned char*)in;
+ out_writed = outp - out;
+
+ if ((res == RECODE_OK || res == RECODE_BROKENSYMBOL) && in_readed != in_size)
+ return RECODE_EOOUTPUT;
+
+ return res;
+ }
+
+ template <class TCharType>
+ inline RECODE_RESULT _recodeSBToUnicode(ECharset From, const char* in, TCharType* out, size_t in_size, size_t out_size, size_t& in_readed, size_t& out_writed) {
+ const CodePage* cp = CodePageByCharset(From);
+ const unsigned char* inp = (const unsigned char*)in;
+ const unsigned char* in_end = inp + in_size;
+ TCharType* outp = out;
+ const TCharType* out_end = outp + out_size;
+ while (inp < in_end && outp < out_end)
+ *outp++ = static_cast<TCharType>(cp->unicode[*inp++]);
+ in_readed = inp - (const unsigned char*)in;
+ out_writed = outp - out;
+ if (in_readed != in_size)
+ return RECODE_EOOUTPUT;
+ return RECODE_OK;
+ }
+
+ template <class TCharType>
+ inline RECODE_RESULT _recodeUnicodeToUTF8Impl(const TCharType* in, char* out, size_t in_size, size_t out_size, size_t& in_readed, size_t& out_writed) {
+ const TCharType* inp = in;
+ const TCharType* in_end = in + in_size;
+ unsigned char* outp = (unsigned char*)out;
+ const unsigned char* out_end = outp + out_size;
+ size_t rune_len;
+ wchar32 rune;
+ RECODE_RESULT res = RECODE_OK;
+
+ while ((res == RECODE_OK || res == RECODE_BROKENSYMBOL) && inp != in_end) {
+ rune = ReadSymbolAndAdvance(inp, in_end);
+ res = SafeWriteUTF8Char(rune, rune_len, outp, out_end);
+ if (outp >= out_end && (res == RECODE_OK || res == RECODE_BROKENSYMBOL))
+ res = RECODE_EOOUTPUT;
+ outp += rune_len;
+ }
+ in_readed = inp - in;
+ out_writed = outp - (const unsigned char*)out;
+ return res;
+ }
+
+ inline RECODE_RESULT _recodeUnicodeToUTF8(wchar32 rune, char* out, size_t out_size, size_t& nwritten) {
+ return SafeWriteUTF8Char(rune, nwritten, (unsigned char*)out, out_size);
+ }
+
+ template <class TCharType, int Size = sizeof(TCharType)>
+ struct TCharTypeSwitch;
+
+ template <class TCharType>
+ struct TCharTypeSwitch<TCharType, 2> {
+ using TRealCharType = wchar16;
+ };
+
+ template <class TCharType>
+ struct TCharTypeSwitch<TCharType, 4> {
+ using TRealCharType = wchar32;
+ };
+
+ template <class TCharType>
+ inline RECODE_RESULT _recodeUnicodeToUTF8(const TCharType* in, char* out, size_t in_size, size_t out_size, size_t& in_readed, size_t& out_writed) {
+ static_assert(sizeof(TCharType) > 1, "expect some wide type");
+
+ using TRealCharType = typename TCharTypeSwitch<TCharType>::TRealCharType;
+
+ return _recodeUnicodeToUTF8Impl(reinterpret_cast<const TRealCharType*>(in), out, in_size, out_size, in_readed, out_writed);
+ }
+
+ template <class TCharType>
+ inline RECODE_RESULT _recodeUnicodeToSB(ECharset To, const TCharType* in, char* out, size_t in_size, size_t out_size, size_t& in_readed, size_t& out_writed) {
+ const TCharType* inp = in;
+ const TCharType* in_end = in + in_size;
+ const char* out_begin = out;
+ const char* out_end = out + out_size;
+
+ const Encoder* enc = &EncoderByCharset(To);
+ while (inp != in_end && out != out_end) {
+ *out++ = enc->Tr(ReadSymbolAndAdvance(inp, in_end));
+ }
+
+ in_readed = inp - in;
+ out_writed = out - out_begin;
+
+ if (in_readed != in_size)
+ return RECODE_EOOUTPUT;
+
+ return RECODE_OK;
+ }
+
+ inline RECODE_RESULT _recodeUnicodeToSB(ECharset To, wchar32 rune, char* out, size_t out_size, size_t& nwritten) {
+ if (0 == out_size)
+ return RECODE_EOOUTPUT;
+ *out = EncoderByCharset(To).Tr(rune);
+ nwritten = 1;
+ return RECODE_OK;
+ }
+
+ inline RECODE_RESULT _rune2hex(wchar32 in, char* out, size_t out_size, size_t& out_writed) {
+ static const char hex_digs[] = "0123456789ABCDEF";
+ out_writed = 0;
+ RECODE_RESULT res = RECODE_OK;
+ for (int i = 7; i >= 0; i--) {
+ unsigned char h = (unsigned char)(in >> (i * 4) & 0x0F);
+ if (h || i == 0) {
+ if (out_writed + 1 >= out_size) {
+ res = RECODE_EOOUTPUT;
+ break;
+ }
+ out[out_writed++] = hex_digs[h];
+ }
+ }
+ return res;
+ }
+
+ inline RECODE_RESULT _recodeUnicodeToHTMLEntities(const wchar32* in, char* out, size_t in_size, size_t out_size, size_t& in_readed, size_t& out_writed) {
+ const wchar32* in_end = in + in_size;
+ const char* out_beg = out;
+ const wchar32* in_beg = in;
+ RECODE_RESULT res = RECODE_OK;
+
+ const char* out_end = out + out_size - 1;
+ while (in < in_end && out < out_end) {
+ if (*in < 0x80 && *in != '<' && *in != '&' && *in != '>') { //ascii
+ *out++ = char(*in & 0x00FF);
+ } else { //entity
+ char* ent = out;
+ size_t ent_writed;
+ if (ent > out_end - 6) {
+ res = RECODE_EOOUTPUT;
+ break;
+ }
+ memcpy(ent, "&#x", 3);
+ ent += 3;
+ res = _rune2hex(*in, ent, out_end - 1 - ent, ent_writed);
+ if (res != RECODE_OK)
+ break;
+ ent += ent_writed;
+ *ent++ = ';';
+ out = ent;
+ }
+ in++;
+ }
+ *out++ = '\x00';
+ out_writed = out - out_beg;
+ in_readed = in - in_beg;
+ return res;
+ }
+
+ template <class TCharType>
+ inline RECODE_RESULT _recodeToUnicode(ECharset From, const char* in, TCharType* out, size_t in_size, size_t out_size, size_t& in_readed, size_t& out_writed) {
+ if (!ValidCodepage(From))
+ return RECODE_ERROR;
+
+ if (!NCodepagePrivate::NativeCodepage(From))
+ return NICONVPrivate::RecodeToUnicodeNoThrow(From, in, out, in_size, out_size, in_readed, out_writed);
+
+ if (From == CODES_UTF8)
+ return _recodeUTF8ToUnicode(in, out, in_size, out_size, in_readed, out_writed);
+
+ return _recodeSBToUnicode(From, in, out, in_size, out_size, in_readed, out_writed);
+ }
+
+ template <class TCharType>
+ inline RECODE_RESULT _recodeFromUnicode(ECharset To, const TCharType* in, char* out, size_t in_size, size_t out_size, size_t& in_readed, size_t& out_writed) {
+ if (!ValidCodepage(To))
+ return RECODE_ERROR;
+
+ if (!NCodepagePrivate::NativeCodepage(To))
+ return NICONVPrivate::RecodeFromUnicodeNoThrow(To, in, out, in_size, out_size, in_readed, out_writed);
+
+ if (To == CODES_UTF8)
+ return NCodepagePrivate::_recodeUnicodeToUTF8(in, out, in_size, out_size, in_readed, out_writed);
+
+ return NCodepagePrivate::_recodeUnicodeToSB(To, in, out, in_size, out_size, in_readed, out_writed);
+ }
+
+ inline RECODE_RESULT _recodeFromUnicode(ECharset To, wchar32 rune, char* out, size_t out_size, size_t& nwritten) {
+ if (!ValidCodepage(To))
+ return RECODE_ERROR;
+
+ if (!NCodepagePrivate::NativeCodepage(To)) {
+ size_t nread = 0;
+ return NICONVPrivate::RecodeFromUnicodeNoThrow(To, &rune, out, 1, out_size, nread, nwritten);
+ }
+
+ if (To == CODES_UTF8)
+ return NCodepagePrivate::_recodeUnicodeToUTF8(rune, out, out_size, nwritten);
+
+ return NCodepagePrivate::_recodeUnicodeToSB(To, rune, out, out_size, nwritten);
+ }
+
+ inline RECODE_RESULT _recodeToHTMLEntities(ECharset From, const char* in, char* out, size_t in_size, size_t out_size, size_t& in_readed, size_t& out_writed) {
+ TArrayHolder<wchar32> bufHolder(new wchar32[in_size]);
+ wchar32* buf = bufHolder.Get();
+ size_t unicode_size;
+ RECODE_RESULT res1, res2;
+
+ //first pass - to unicode
+ res1 = _recodeToUnicode(From, in, buf, in_size, in_size, in_readed, unicode_size);
+
+ //second pass - to entities
+ res2 = _recodeUnicodeToHTMLEntities(buf, out, in_size, out_size, in_readed, out_writed);
+
+ return (res2 != RECODE_OK) ? res2 : res1;
+ }
+
+}
diff --git a/library/cpp/charset/ut/ya.make b/library/cpp/charset/ut/ya.make
new file mode 100644
index 0000000000..1f9934c712
--- /dev/null
+++ b/library/cpp/charset/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/charset)
+
+OWNER(alzobnin)
+
+SRCS(
+ ci_string_ut.cpp
+ codepage_ut.cpp
+ iconv_ut.cpp
+ wide_ut.cpp
+)
+
+END()
diff --git a/library/cpp/charset/wide.cpp b/library/cpp/charset/wide.cpp
new file mode 100644
index 0000000000..d12b293817
--- /dev/null
+++ b/library/cpp/charset/wide.cpp
@@ -0,0 +1,18 @@
+#include "wide.h"
+
+bool CanBeEncoded(TWtringBuf text, ECharset encoding) {
+ const size_t LEN = 16;
+ const size_t BUFSIZE = LEN * 4;
+ char encodeBuf[BUFSIZE];
+ wchar16 decodeBuf[BUFSIZE];
+
+ while (!text.empty()) {
+ TWtringBuf src = text.NextTokAt(LEN);
+ TStringBuf encoded = NDetail::NBaseOps::Recode(src, encodeBuf, encoding);
+ TWtringBuf decoded = NDetail::NBaseOps::Recode(encoded, decodeBuf, encoding);
+ if (decoded != src)
+ return false;
+ }
+
+ return true;
+}
diff --git a/library/cpp/charset/wide.h b/library/cpp/charset/wide.h
new file mode 100644
index 0000000000..32d30e849e
--- /dev/null
+++ b/library/cpp/charset/wide.h
@@ -0,0 +1,306 @@
+#pragma once
+
+#include "codepage.h"
+#include "iconv.h"
+
+#include <util/charset/recode_result.h>
+#include <util/charset/unidata.h>
+#include <util/charset/utf8.h>
+#include <util/charset/wide.h>
+#include <util/generic/string.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/yexception.h>
+#include <util/memory/tempbuf.h>
+#include <util/system/yassert.h>
+
+//! converts text from unicode to yandex codepage
+//! @attention destination buffer must be long enough to fit all characters of the text
+//! @note @c dest buffer must fit at least @c len number of characters
+template <typename TCharType>
+inline size_t WideToChar(const TCharType* text, size_t len, char* dest, ECharset enc) {
+ Y_ASSERT(SingleByteCodepage(enc));
+
+ const char* start = dest;
+
+ const Encoder* const encoder = &EncoderByCharset(enc);
+ const TCharType* const last = text + len;
+ for (const TCharType* cur = text; cur != last; ++dest) {
+ *dest = encoder->Tr(ReadSymbolAndAdvance(cur, last));
+ }
+
+ return dest - start;
+}
+
+//! converts text to unicode using a codepage object
+//! @attention destination buffer must be long enough to fit all characters of the text
+//! @note @c dest buffer must fit at least @c len number of characters;
+//! if you need convert zero terminated string you should determine length of the
+//! string using the @c strlen function and pass as the @c len parameter;
+//! it does not make sense to create an additional version of this function because
+//! it will call to @c strlen anyway in order to allocate destination buffer
+template <typename TCharType>
+inline void CharToWide(const char* text, size_t len, TCharType* dest, const CodePage& cp) {
+ const unsigned char* cur = reinterpret_cast<const unsigned char*>(text);
+ const unsigned char* const last = cur + len;
+ for (; cur != last; ++cur, ++dest) {
+ *dest = static_cast<TCharType>(cp.unicode[*cur]); // static_cast is safe as no 1char codepage contains non-BMP symbols
+ }
+}
+
+namespace NDetail {
+ namespace NBaseOps {
+ // Template interface base recoding drivers, do not perform any memory management,
+ // do not care about buffer size, so supplied @dst
+ // should have enough room for the result (with proper reserve for the worst case)
+
+ // Depending on template params, perform conversion of single-byte/multi-byte/utf8 string to/from wide string.
+
+ template <typename TCharType>
+ inline TBasicStringBuf<TCharType> RecodeSingleByteChar(const TStringBuf src, TCharType* dst, const CodePage& cp) {
+ Y_ASSERT(cp.SingleByteCodepage());
+ ::CharToWide(src.data(), src.size(), dst, cp);
+ return TBasicStringBuf<TCharType>(dst, src.size());
+ }
+
+ template <typename TCharType>
+ inline TStringBuf RecodeSingleByteChar(const TBasicStringBuf<TCharType> src, char* dst, const CodePage& cp) {
+ Y_ASSERT(cp.SingleByteCodepage());
+ ::WideToChar(src.data(), src.size(), dst, cp.CPEnum);
+ return TStringBuf(dst, src.size());
+ }
+
+ template <typename TCharType>
+ inline TBasicStringBuf<TCharType> RecodeMultiByteChar(const TStringBuf src, TCharType* dst, ECharset encoding) {
+ Y_ASSERT(!NCodepagePrivate::NativeCodepage(encoding));
+ size_t read = 0;
+ size_t written = 0;
+ ::NICONVPrivate::RecodeToUnicode(encoding, src.data(), dst, src.size(), src.size(), read, written);
+ return TBasicStringBuf<TCharType>(dst, written);
+ }
+
+ template <typename TCharType>
+ inline TStringBuf RecodeMultiByteChar(const TBasicStringBuf<TCharType> src, char* dst, ECharset encoding) {
+ Y_ASSERT(!NCodepagePrivate::NativeCodepage(encoding));
+ size_t read = 0;
+ size_t written = 0;
+ ::NICONVPrivate::RecodeFromUnicode(encoding, src.data(), dst, src.size(), src.size() * 3, read, written);
+ return TStringBuf(dst, written);
+ }
+
+ template <typename TCharType>
+ inline TBasicStringBuf<TCharType> RecodeUtf8(const TStringBuf src, TCharType* dst) {
+ size_t len = 0;
+ if (!::UTF8ToWide(src.data(), src.size(), dst, len))
+ ythrow yexception() << "Invalid UTF8: \"" << src.SubStr(0, 50) << (src.size() > 50 ? "...\"" : "\"");
+ return TBasicStringBuf<TCharType>(dst, len);
+ }
+
+ template <typename TCharType>
+ inline TStringBuf RecodeUtf8(const TBasicStringBuf<TCharType> src, char* dst) {
+ size_t len = 0;
+ ::WideToUTF8(src.data(), src.size(), dst, len);
+ return TStringBuf(dst, len);
+ }
+
+ // Select one of re-coding methods from above, based on provided @encoding
+
+ template <typename TCharFrom, typename TCharTo>
+ TBasicStringBuf<TCharTo> Recode(const TBasicStringBuf<TCharFrom> src, TCharTo* dst, ECharset encoding) {
+ if (encoding == CODES_UTF8)
+ return RecodeUtf8(src, dst);
+ else if (SingleByteCodepage(encoding))
+ return RecodeSingleByteChar(src, dst, *CodePageByCharset(encoding));
+ else
+ return RecodeMultiByteChar(src, dst, encoding);
+ }
+
+ }
+
+ template <typename TCharFrom>
+ struct TRecodeTraits;
+
+ template <>
+ struct TRecodeTraits<char> {
+ using TCharTo = wchar16;
+ using TStringBufTo = TWtringBuf;
+ using TStringTo = TUtf16String;
+ enum { ReserveSize = 4 }; // How many TCharFrom characters we should reserve for one TCharTo character in worst case
+ // Here an unicode character can be converted up to 4 bytes of UTF8
+ };
+
+ template <>
+ struct TRecodeTraits<wchar16> {
+ using TCharTo = char;
+ using TStringBufTo = TStringBuf;
+ using TStringTo = TString;
+ enum { ReserveSize = 2 }; // possible surrogate pairs ?
+ };
+
+ // Operations with destination buffer where recoded string will be written
+ template <typename TResult>
+ struct TRecodeResultOps {
+ // default implementation will work with TString and TUtf16String - 99% of usage
+ using TResultChar = typename TResult::char_type;
+
+ static inline size_t Size(const TResult& dst) {
+ return dst.size();
+ }
+
+ static inline TResultChar* Reserve(TResult& dst, size_t len) {
+ dst.ReserveAndResize(len);
+ return dst.begin();
+ }
+
+ static inline void Truncate(TResult& dst, size_t len) {
+ dst.resize(len);
+ }
+ };
+
+ // Main template interface for recoding in both directions
+
+ template <typename TCharFrom, typename TResult>
+ typename TRecodeTraits<TCharFrom>::TStringBufTo Recode(const TBasicStringBuf<TCharFrom> src, TResult& dst, ECharset encoding) {
+ using TCharTo = typename TRecodeTraits<TCharFrom>::TCharTo;
+ // make enough room for re-coded string
+ TCharTo* dstbuf = TRecodeResultOps<TResult>::Reserve(dst, src.size() * TRecodeTraits<TCharTo>::ReserveSize);
+ // do re-coding
+ TBasicStringBuf<TCharTo> res = NBaseOps::Recode(src, dstbuf, encoding);
+ // truncate result back to proper size
+ TRecodeResultOps<TResult>::Truncate(dst, res.size());
+ return res;
+ }
+
+ // appending version of Recode()
+ template <typename TCharFrom, typename TResult>
+ typename TRecodeTraits<TCharFrom>::TStringBufTo RecodeAppend(const TBasicStringBuf<TCharFrom> src, TResult& dst, ECharset encoding) {
+ using TCharTo = typename TRecodeTraits<TCharFrom>::TCharTo;
+ size_t dstOrigSize = TRecodeResultOps<TResult>::Size(dst);
+ TCharTo* dstbuf = TRecodeResultOps<TResult>::Reserve(dst, dstOrigSize + src.size() * TRecodeTraits<TCharTo>::ReserveSize);
+ TBasicStringBuf<TCharTo> appended = NBaseOps::Recode(src, dstbuf + dstOrigSize, encoding);
+ size_t dstFinalSize = dstOrigSize + appended.size();
+ TRecodeResultOps<TResult>::Truncate(dst, dstFinalSize);
+ return TBasicStringBuf<TCharTo>(dstbuf, dstFinalSize);
+ }
+
+ // special implementation for robust utf8 functions
+ template <typename TResult>
+ TWtringBuf RecodeUTF8Robust(const TStringBuf src, TResult& dst) {
+ // make enough room for re-coded string
+ wchar16* dstbuf = TRecodeResultOps<TResult>::Reserve(dst, src.size() * TRecodeTraits<wchar16>::ReserveSize);
+
+ // do re-coding
+ size_t written = 0;
+ UTF8ToWide<true>(src.data(), src.size(), dstbuf, written);
+
+ // truncate result back to proper size
+ TRecodeResultOps<TResult>::Truncate(dst, written);
+ return TWtringBuf(dstbuf, written);
+ }
+
+ template <typename TCharFrom>
+ inline typename TRecodeTraits<TCharFrom>::TStringTo Recode(const TBasicStringBuf<TCharFrom> src, ECharset encoding) {
+ typename TRecodeTraits<TCharFrom>::TStringTo res;
+ Recode<TCharFrom>(src, res, encoding);
+ return res;
+ }
+}
+
+// Write result into @dst. Return string-buffer pointing to re-coded content of @dst.
+
+template <bool robust>
+inline TWtringBuf CharToWide(const TStringBuf src, TUtf16String& dst, ECharset encoding) {
+ if (robust && CODES_UTF8 == encoding)
+ return ::NDetail::RecodeUTF8Robust(src, dst);
+ return ::NDetail::Recode<char>(src, dst, encoding);
+}
+
+inline TWtringBuf CharToWide(const TStringBuf src, TUtf16String& dst, ECharset encoding) {
+ return ::NDetail::Recode<char>(src, dst, encoding);
+}
+
+inline TStringBuf WideToChar(const TWtringBuf src, TString& dst, ECharset encoding) {
+ return ::NDetail::Recode<wchar16>(src, dst, encoding);
+}
+
+//! calls either to @c WideToUTF8 or @c WideToChar depending on the encoding type
+inline TString WideToChar(const wchar16* text, size_t len, ECharset enc) {
+ if (NCodepagePrivate::NativeCodepage(enc)) {
+ if (enc == CODES_UTF8)
+ return WideToUTF8(text, len);
+
+ TString s = TString::Uninitialized(len);
+ s.remove(WideToChar(text, len, s.begin(), enc));
+
+ return s;
+ }
+
+ TString s = TString::Uninitialized(len * 3);
+
+ size_t read = 0;
+ size_t written = 0;
+ NICONVPrivate::RecodeFromUnicode(enc, text, s.begin(), len, s.size(), read, written);
+ s.remove(written);
+
+ return s;
+}
+
+inline TUtf16String CharToWide(const char* text, size_t len, const CodePage& cp) {
+ TUtf16String w = TUtf16String::Uninitialized(len);
+ CharToWide(text, len, w.begin(), cp);
+ return w;
+}
+
+//! calls either to @c UTF8ToWide or @c CharToWide depending on the encoding type
+template <bool robust>
+inline TUtf16String CharToWide(const char* text, size_t len, ECharset enc) {
+ if (NCodepagePrivate::NativeCodepage(enc)) {
+ if (enc == CODES_UTF8)
+ return UTF8ToWide<robust>(text, len);
+
+ return CharToWide(text, len, *CodePageByCharset(enc));
+ }
+
+ TUtf16String w = TUtf16String::Uninitialized(len * 2);
+
+ size_t read = 0;
+ size_t written = 0;
+ NICONVPrivate::RecodeToUnicode(enc, text, w.begin(), len, len, read, written);
+ w.remove(written);
+
+ return w;
+}
+
+//! converts text from UTF8 to unicode, if conversion fails it uses codepage to convert the text
+//! @param text text to be converted
+//! @param len length of the text in characters
+//! @param cp a codepage that is used in case of failed conversion from UTF8
+inline TUtf16String UTF8ToWide(const char* text, size_t len, const CodePage& cp) {
+ TUtf16String w = TUtf16String::Uninitialized(len);
+ size_t written = 0;
+ if (UTF8ToWide(text, len, w.begin(), written))
+ w.remove(written);
+ else
+ CharToWide(text, len, w.begin(), cp);
+ return w;
+}
+
+inline TString WideToChar(const TWtringBuf w, ECharset enc) {
+ return WideToChar(w.data(), w.size(), enc);
+}
+
+inline TUtf16String CharToWide(const TStringBuf s, ECharset enc) {
+ return CharToWide<false>(s.data(), s.size(), enc);
+}
+
+template <bool robust>
+inline TUtf16String CharToWide(const TStringBuf s, ECharset enc) {
+ return CharToWide<robust>(s.data(), s.size(), enc);
+}
+
+inline TUtf16String CharToWide(const TStringBuf s, const CodePage& cp) {
+ return CharToWide(s.data(), s.size(), cp);
+}
+
+// true if @text can be fully encoded to specified @encoding,
+// with possibility to recover exact original text after decoding
+bool CanBeEncoded(TWtringBuf text, ECharset encoding);
diff --git a/library/cpp/charset/wide_ut.cpp b/library/cpp/charset/wide_ut.cpp
new file mode 100644
index 0000000000..78947d51ba
--- /dev/null
+++ b/library/cpp/charset/wide_ut.cpp
@@ -0,0 +1,399 @@
+#include "wide.h"
+#include "codepage.h"
+#include "recyr.hh"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/charset/utf8.h>
+#include <util/digest/numeric.h>
+#include <util/generic/hash_set.h>
+
+#include <algorithm>
+
+namespace {
+ //! three UTF8 encoded russian letters (A, B, V)
+ const char yandexCyrillicAlphabet[] =
+ "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF" // A - P
+ "\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF" // R - YA
+ "\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF" // a - p
+ "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF"; // r - ya
+ const wchar16 wideCyrillicAlphabet[] = {
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0x00};
+ const char utf8CyrillicAlphabet[] =
+ "\xd0\x90\xd0\x91\xd0\x92\xd0\x93\xd0\x94\xd0\x95\xd0\x96\xd0\x97"
+ "\xd0\x98\xd0\x99\xd0\x9a\xd0\x9b\xd0\x9c\xd0\x9d\xd0\x9e\xd0\x9f"
+ "\xd0\xa0\xd0\xa1\xd0\xa2\xd0\xa3\xd0\xa4\xd0\xa5\xd0\xa6\xd0\xa7"
+ "\xd0\xa8\xd0\xa9\xd0\xaa\xd0\xab\xd0\xac\xd0\xad\xd0\xae\xd0\xaf"
+ "\xd0\xb0\xd0\xb1\xd0\xb2\xd0\xb3\xd0\xb4\xd0\xb5\xd0\xb6\xd0\xb7"
+ "\xd0\xb8\xd0\xb9\xd0\xba\xd0\xbb\xd0\xbc\xd0\xbd\xd0\xbe\xd0\xbf"
+ "\xd1\x80\xd1\x81\xd1\x82\xd1\x83\xd1\x84\xd1\x85\xd1\x86\xd1\x87"
+ "\xd1\x88\xd1\x89\xd1\x8a\xd1\x8b\xd1\x8c\xd1\x8d\xd1\x8e\xd1\x8f";
+
+ TString CreateYandexText() {
+ const int len = 256;
+ char text[len] = {0};
+ for (int i = 0; i < len; ++i) {
+ text[i] = static_cast<char>(i);
+ }
+ return TString(text, len);
+ }
+
+ TUtf16String CreateUnicodeText() {
+ const int len = 256;
+ wchar16 text[len] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00 - 0x0F
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x10 - 0x1F
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x20 - 0x2F
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x30 - 0x3F
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x40 - 0x4F
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x50 - 0x5F
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x60 - 0x6F
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x70 - 0x7F
+
+ 0x0301, 0x00C4, 0x00D6, 0x00DC, 0x0104, 0x0106, 0x0118, 0x0141, 0x00E0, 0x00E2, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x0490, 0x00AD, // 0x80 - 0x8F
+ 0x00DF, 0x00E4, 0x00F6, 0x00FC, 0x0105, 0x0107, 0x0119, 0x0142, 0x00EB, 0x00EE, 0x00EF, 0x00F4, 0x00F9, 0x00FB, 0x0491, 0x92CF, // 0x90 - 0x9F
+ 0x00A0, 0x0143, 0x00D3, 0x015A, 0x017B, 0x0179, 0x046C, 0x00A7, 0x0401, 0x0462, 0x0472, 0x0474, 0x040E, 0x0406, 0x0404, 0x0407, // 0xA0 - 0xAF
+ 0x00B0, 0x0144, 0x00F3, 0x015B, 0x017C, 0x017A, 0x046D, 0x2116, 0x0451, 0x0463, 0x0473, 0x0475, 0x045E, 0x0456, 0x0454, 0x0457 // 0xB0 - 0xBF
+ };
+ for (int i = 0; i < len; ++i) {
+ if (i <= 0x7F) { // ASCII characters without 0x7 and 0x1B
+ text[i] = static_cast<wchar16>(i);
+ } else if (i >= 0xC0 && i <= 0xFF) { // russian characters (without YO and yo)
+ text[i] = static_cast<wchar16>(i + 0x0350); // 0x0410 - 0x044F
+ }
+ }
+ return TUtf16String(text, len);
+ }
+
+ TString CreateUTF8Text() {
+ char text[] = {
+ '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
+ '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
+ '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27', '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
+ '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
+ '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47', '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f',
+ '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57', '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
+ '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
+ '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f',
+ '\xcc', '\x81', '\xc3', '\x84', '\xc3', '\x96', '\xc3', '\x9c', '\xc4', '\x84', '\xc4', '\x86', '\xc4', '\x98', '\xc5', '\x81',
+ '\xc3', '\xa0', '\xc3', '\xa2', '\xc3', '\xa7', '\xc3', '\xa8', '\xc3', '\xa9', '\xc3', '\xaa', '\xd2', '\x90', '\xc2', '\xad',
+ '\xc3', '\x9f', '\xc3', '\xa4', '\xc3', '\xb6', '\xc3', '\xbc', '\xc4', '\x85', '\xc4', '\x87', '\xc4', '\x99', '\xc5', '\x82',
+ '\xc3', '\xab', '\xc3', '\xae', '\xc3', '\xaf', '\xc3', '\xb4', '\xc3', '\xb9', '\xc3', '\xbb', '\xd2', '\x91', '\xe9', '\x8b',
+ '\x8f', '\xc2', '\xa0', '\xc5', '\x83', '\xc3', '\x93', '\xc5', '\x9a', '\xc5', '\xbb', '\xc5', '\xb9', '\xd1', '\xac', '\xc2',
+ '\xa7', '\xd0', '\x81', '\xd1', '\xa2', '\xd1', '\xb2', '\xd1', '\xb4', '\xd0', '\x8e', '\xd0', '\x86', '\xd0', '\x84', '\xd0',
+ '\x87', '\xc2', '\xb0', '\xc5', '\x84', '\xc3', '\xb3', '\xc5', '\x9b', '\xc5', '\xbc', '\xc5', '\xba', '\xd1', '\xad', '\xe2',
+ '\x84', '\x96', '\xd1', '\x91', '\xd1', '\xa3', '\xd1', '\xb3', '\xd1', '\xb5', '\xd1', '\x9e', '\xd1', '\x96', '\xd1', '\x94',
+ '\xd1', '\x97', '\xd0', '\x90', '\xd0', '\x91', '\xd0', '\x92', '\xd0', '\x93', '\xd0', '\x94', '\xd0', '\x95', '\xd0', '\x96',
+ '\xd0', '\x97', '\xd0', '\x98', '\xd0', '\x99', '\xd0', '\x9a', '\xd0', '\x9b', '\xd0', '\x9c', '\xd0', '\x9d', '\xd0', '\x9e',
+ '\xd0', '\x9f', '\xd0', '\xa0', '\xd0', '\xa1', '\xd0', '\xa2', '\xd0', '\xa3', '\xd0', '\xa4', '\xd0', '\xa5', '\xd0', '\xa6',
+ '\xd0', '\xa7', '\xd0', '\xa8', '\xd0', '\xa9', '\xd0', '\xaa', '\xd0', '\xab', '\xd0', '\xac', '\xd0', '\xad', '\xd0', '\xae',
+ '\xd0', '\xaf', '\xd0', '\xb0', '\xd0', '\xb1', '\xd0', '\xb2', '\xd0', '\xb3', '\xd0', '\xb4', '\xd0', '\xb5', '\xd0', '\xb6',
+ '\xd0', '\xb7', '\xd0', '\xb8', '\xd0', '\xb9', '\xd0', '\xba', '\xd0', '\xbb', '\xd0', '\xbc', '\xd0', '\xbd', '\xd0', '\xbe',
+ '\xd0', '\xbf', '\xd1', '\x80', '\xd1', '\x81', '\xd1', '\x82', '\xd1', '\x83', '\xd1', '\x84', '\xd1', '\x85', '\xd1', '\x86',
+ '\xd1', '\x87', '\xd1', '\x88', '\xd1', '\x89', '\xd1', '\x8a', '\xd1', '\x8b', '\xd1', '\x8c', '\xd1', '\x8d', '\xd1', '\x8e',
+ '\xd1', '\x8f'};
+ return TString(text, Y_ARRAY_SIZE(text));
+ }
+
+ //! use this function to dump UTF8 text into a file in case of any changes
+ // void DumpUTF8Text() {
+ // TString s = WideToUTF8(UnicodeText);
+ // std::ofstream f("utf8.txt");
+ // f << std::hex;
+ // for (int i = 0; i < (int)s.size(); ++i) {
+ // f << "0x" << std::setw(2) << std::setfill('0') << (int)(ui8)s[i] << ", ";
+ // if ((i + 1) % 16 == 0)
+ // f << std::endl;
+ // }
+ // }
+
+}
+
+//! this unit tests ensure validity of Yandex-Unicode and UTF8-Unicode conversions
+//! @note only those conversions are verified because they are used in index
+class TConversionTest: public TTestBase {
+private:
+ //! @note every of the text can have zeros in the middle
+ const TString YandexText;
+ const TUtf16String UnicodeText;
+ const TString UTF8Text;
+
+private:
+ UNIT_TEST_SUITE(TConversionTest);
+ UNIT_TEST(TestCharToWide);
+ UNIT_TEST(TestWideToChar);
+ UNIT_TEST(TestYandexEncoding);
+ UNIT_TEST(TestRecodeIntoString);
+ UNIT_TEST(TestRecodeAppend);
+ UNIT_TEST(TestRecode);
+ UNIT_TEST(TestUnicodeLimit);
+ UNIT_TEST_SUITE_END();
+
+public:
+ TConversionTest()
+ : YandexText(CreateYandexText())
+ , UnicodeText(CreateUnicodeText())
+ , UTF8Text(CreateUTF8Text())
+ {
+ }
+
+ void TestCharToWide();
+ void TestWideToChar();
+ void TestYandexEncoding();
+ void TestRecodeIntoString();
+ void TestRecodeAppend();
+ void TestRecode();
+ void TestUnicodeLimit();
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TConversionTest);
+
+// test conversions (char -> wchar32), (wchar32 -> char) and (wchar32 -> wchar16)
+#define TEST_WCHAR32(sbuf, wbuf, enc) \
+ do { \
+ /* convert char to wchar32 */ \
+ TTempBuf tmpbuf1(sbuf.length() * sizeof(wchar32)); \
+ const TBasicStringBuf<wchar32> s4buf = NDetail::NBaseOps::Recode<char>(sbuf, reinterpret_cast<wchar32*>(tmpbuf1.Data()), enc); \
+ \
+ /* convert wchar32 to char */ \
+ TTempBuf tmpbuf2(s4buf.length() * 4); \
+ const TStringBuf s1buf = NDetail::NBaseOps::Recode(s4buf, tmpbuf2.Data(), enc); \
+ \
+ /* convert wchar32 to wchar16 */ \
+ const TUtf16String wstr2 = UTF32ToWide(s4buf.data(), s4buf.length()); \
+ \
+ /* test conversions */ \
+ UNIT_ASSERT_VALUES_EQUAL(sbuf, s1buf); \
+ UNIT_ASSERT_VALUES_EQUAL(wbuf, wstr2); \
+ } while (false)
+
+void TConversionTest::TestCharToWide() {
+ TUtf16String w = CharToWide(YandexText, CODES_YANDEX);
+
+ UNIT_ASSERT(w.size() == 256);
+ UNIT_ASSERT(w.size() == UnicodeText.size());
+
+ for (int i = 0; i < 256; ++i) {
+ UNIT_ASSERT_VALUES_EQUAL(w[i], UnicodeText[i]);
+ }
+}
+
+void TConversionTest::TestWideToChar() {
+ TString s = WideToChar(UnicodeText, CODES_YANDEX);
+
+ UNIT_ASSERT(s.size() == 256);
+ UNIT_ASSERT(s.size() == YandexText.size());
+
+ for (int i = 0; i < 256; ++i) {
+ UNIT_ASSERT_VALUES_EQUAL(s[i], YandexText[i]);
+ }
+}
+
+static void TestSurrogates(const char* str, const wchar16* wide, size_t wideSize, ECharset enc) {
+ TUtf16String w = UTF8ToWide(str);
+
+ UNIT_ASSERT(w.size() == wideSize);
+ UNIT_ASSERT(!memcmp(w.c_str(), wide, wideSize));
+
+ TString s = WideToChar(w, enc);
+
+ UNIT_ASSERT(s == str);
+}
+
+void TConversionTest::TestYandexEncoding() {
+ TUtf16String w = UTF8ToWide(utf8CyrillicAlphabet, strlen(utf8CyrillicAlphabet), csYandex);
+ UNIT_ASSERT(w == wideCyrillicAlphabet);
+ w = UTF8ToWide(yandexCyrillicAlphabet, strlen(yandexCyrillicAlphabet), csYandex);
+ UNIT_ASSERT(w == wideCyrillicAlphabet);
+
+ const char* utf8NonBMP2 = "ab\xf4\x80\x89\x87n";
+ wchar16 wNonBMPDummy2[] = {'a', 'b', 0xDBC0, 0xDE47, 'n'};
+ TestSurrogates(utf8NonBMP2, wNonBMPDummy2, Y_ARRAY_SIZE(wNonBMPDummy2), CODES_UTF8);
+
+ {
+ const char* yandexNonBMP2 = "ab?n";
+ UNIT_ASSERT(yandexNonBMP2 == WideToChar(wNonBMPDummy2, Y_ARRAY_SIZE(wNonBMPDummy2), CODES_YANDEX));
+
+ TString temp;
+ temp.resize(Y_ARRAY_SIZE(wNonBMPDummy2));
+ size_t read = 0;
+ size_t written = 0;
+ RecodeFromUnicode(CODES_YANDEX, wNonBMPDummy2, temp.begin(), Y_ARRAY_SIZE(wNonBMPDummy2), temp.size(), read, written);
+ temp.remove(written);
+
+ UNIT_ASSERT(yandexNonBMP2 == temp);
+ }
+}
+
+void TConversionTest::TestRecodeIntoString() {
+ TString sYandex(UnicodeText.size() * 4, 'x');
+ const char* sdata = sYandex.data();
+ TStringBuf sres = NDetail::Recode<wchar16>(UnicodeText, sYandex, CODES_YANDEX);
+ UNIT_ASSERT(sYandex == YandexText); // same content
+ UNIT_ASSERT(sYandex.data() == sdata); // reserved buffer reused
+ UNIT_ASSERT(sYandex.data() == sres.data()); // same buffer
+ UNIT_ASSERT(sYandex.size() == sres.size()); // same size
+ TEST_WCHAR32(sYandex, UnicodeText, CODES_YANDEX);
+
+ TUtf16String sUnicode;
+ sUnicode.reserve(YandexText.size() * 4);
+ const wchar16* wdata = sUnicode.data();
+ TWtringBuf wres = NDetail::Recode<char>(YandexText, sUnicode, CODES_YANDEX);
+ UNIT_ASSERT(sUnicode == UnicodeText); // same content
+ UNIT_ASSERT(sUnicode.data() == wdata); // reserved buffer reused
+ UNIT_ASSERT(sUnicode.data() == wres.data()); // same buffer
+ UNIT_ASSERT(sUnicode.size() == wres.size()); // same size
+
+ TString sUtf8 = " ";
+ size_t scap = sUtf8.capacity();
+ sres = NDetail::Recode<wchar16>(UnicodeText, sUtf8, CODES_UTF8);
+ UNIT_ASSERT(sUtf8 == UTF8Text); // same content
+ UNIT_ASSERT(sUtf8.capacity() > scap); // increased buffer capacity (supplied was too small)
+ UNIT_ASSERT(sUtf8.data() == sres.data()); // same buffer
+ UNIT_ASSERT(sUtf8.size() == sres.size()); // same size
+ TEST_WCHAR32(sUtf8, UnicodeText, CODES_UTF8);
+
+ sUnicode.clear();
+ wdata = sUnicode.data();
+ TUtf16String copy = sUnicode; // increase ref-counter
+ wres = NDetail::Recode<char>(UTF8Text, sUnicode, CODES_UTF8);
+ UNIT_ASSERT(sUnicode == UnicodeText); // same content
+#ifndef TSTRING_IS_STD_STRING
+ UNIT_ASSERT(sUnicode.data() != wdata); // re-allocated (shared buffer supplied)
+ UNIT_ASSERT(sUnicode.data() == wres.data()); // same buffer
+#endif
+ UNIT_ASSERT(sUnicode.size() == wres.size()); // same content
+}
+
+static TString GenerateJunk(size_t seed) {
+ TString res;
+ size_t hash = NumericHash(seed);
+ size_t size = hash % 1024;
+ res.reserve(size);
+ for (size_t i = 0; i < size; ++i)
+ res += static_cast<char>(NumericHash(hash + i) % 256);
+ return res;
+}
+
+void TConversionTest::TestRecodeAppend() {
+ {
+ TString s1, s2;
+ NDetail::RecodeAppend<wchar16>(TUtf16String(), s1, CODES_YANDEX);
+ UNIT_ASSERT(s1.empty());
+
+ NDetail::RecodeAppend<wchar16>(UnicodeText, s1, CODES_WIN);
+ s2 += WideToChar(UnicodeText, CODES_WIN);
+ UNIT_ASSERT_EQUAL(s1, s2);
+
+ NDetail::RecodeAppend<wchar16>(UnicodeText, s1, CODES_YANDEX);
+ s2 += WideToChar(UnicodeText, CODES_YANDEX);
+ UNIT_ASSERT_EQUAL(s1, s2);
+
+ NDetail::RecodeAppend<wchar16>(TUtf16String(), s1, CODES_YANDEX);
+ UNIT_ASSERT_EQUAL(s1, s2);
+
+ NDetail::RecodeAppend<wchar16>(UnicodeText, s1, CODES_UTF8);
+ s2 += WideToUTF8(UnicodeText);
+ UNIT_ASSERT_EQUAL(s1, s2);
+
+ for (size_t i = 0; i < 100; ++i) {
+ TUtf16String junk = CharToWide(GenerateJunk(i), CODES_YANDEX);
+ NDetail::RecodeAppend<wchar16>(junk, s1, CODES_UTF8);
+ s2 += WideToUTF8(junk);
+ UNIT_ASSERT_EQUAL(s1, s2);
+ }
+ }
+
+ {
+ TUtf16String s1, s2;
+ NDetail::RecodeAppend<char>(TString(), s1, CODES_YANDEX);
+ UNIT_ASSERT(s1.empty());
+
+ NDetail::RecodeAppend<char>(YandexText, s1, CODES_WIN);
+ s2 += CharToWide(YandexText, CODES_WIN);
+ UNIT_ASSERT_EQUAL(s1, s2);
+
+ NDetail::RecodeAppend<char>(YandexText, s1, CODES_YANDEX);
+ s2 += CharToWide(YandexText, CODES_YANDEX);
+ UNIT_ASSERT_EQUAL(s1, s2);
+
+ NDetail::RecodeAppend<char>(TString(), s1, CODES_YANDEX);
+ UNIT_ASSERT_EQUAL(s1, s2);
+
+ NDetail::RecodeAppend<char>(UTF8Text, s1, CODES_UTF8);
+ s2 += UTF8ToWide(UTF8Text);
+ UNIT_ASSERT_EQUAL(s1, s2);
+
+ for (size_t i = 0; i < 100; ++i) {
+ TString junk = GenerateJunk(i);
+ NDetail::RecodeAppend<char>(junk, s1, CODES_YANDEX);
+ s2 += CharToWide(junk, CODES_YANDEX);
+ UNIT_ASSERT_EQUAL(s1, s2);
+ }
+ }
+}
+
+template <>
+void Out<RECODE_RESULT>(IOutputStream& out, RECODE_RESULT val) {
+ out << int(val);
+}
+
+void TConversionTest::TestRecode() {
+ for (int c = 0; c != CODES_MAX; ++c) {
+ ECharset enc = static_cast<ECharset>(c);
+ if (!SingleByteCodepage(enc))
+ continue;
+
+ using THash = THashSet<char>;
+ THash hash;
+
+ for (int i = 0; i != 256; ++i) {
+ char ch = static_cast<char>(i);
+
+ wchar32 wch;
+ size_t read = 0;
+ size_t written = 0;
+ RECODE_RESULT res = RECODE_ERROR;
+
+ res = RecodeToUnicode(enc, &ch, &wch, 1, 1, read, written);
+ UNIT_ASSERT(res == RECODE_OK);
+ if (wch == BROKEN_RUNE)
+ continue;
+
+ char rch = 0;
+ res = RecodeFromUnicode(enc, &wch, &rch, 1, 1, read, written);
+ UNIT_ASSERT(res == RECODE_OK);
+
+ char rch2 = 0;
+ UNIT_ASSERT_VALUES_EQUAL(RECODE_OK, RecodeFromUnicode(enc, wch, &rch2, 1, written));
+ UNIT_ASSERT_VALUES_EQUAL(size_t(1), written);
+ UNIT_ASSERT_VALUES_EQUAL(rch2, rch);
+
+ if (hash.contains(rch)) { // there are some stupid encodings with duplicate characters
+ continue;
+ } else {
+ hash.insert(rch);
+ }
+
+ UNIT_ASSERT(ch == rch);
+ }
+ }
+}
+
+void TConversionTest::TestUnicodeLimit() {
+ for (int i = 0; i != CODES_MAX; ++i) {
+ ECharset code = static_cast<ECharset>(i);
+ if (!SingleByteCodepage(code))
+ continue;
+
+ const CodePage* page = CodePageByCharset(code);
+ Y_ASSERT(page);
+
+ for (int c = 0; c < 256; ++c) {
+ UNIT_ASSERT(page->unicode[c] < 1 << 16);
+ }
+ }
+}
diff --git a/library/cpp/charset/ya.make b/library/cpp/charset/ya.make
new file mode 100644
index 0000000000..7565566bf0
--- /dev/null
+++ b/library/cpp/charset/ya.make
@@ -0,0 +1,22 @@
+LIBRARY()
+
+OWNER(alzobnin)
+
+SRCS(
+ generated/cp_data.cpp
+ generated/encrec_data.cpp
+ codepage.cpp
+ cp_encrec.cpp
+ doccodes.cpp
+ iconv.cpp
+ recyr.hh
+ recyr_int.hh
+ ci_string.cpp
+ wide.cpp
+)
+
+PEERDIR(
+ contrib/libs/libiconv
+)
+
+END()
diff --git a/library/cpp/codecs/README.md b/library/cpp/codecs/README.md
new file mode 100644
index 0000000000..42646ccd97
--- /dev/null
+++ b/library/cpp/codecs/README.md
@@ -0,0 +1,46 @@
+This is a library of compression algorithms with a unified interface and serialization.
+See also library/cpp/codecs/static, where a support for statically compiled dictionaries is implemented.
+
+All algorithms have a common `ICodec` interface (described in codecs.h).
+
+The `ICodec` interface has the following methods:\
+    `virtual ui8 ICodec::Encode (TMemoryRegion, TBuffer&) const;`\
+            - Input - memory region. Output - filled buffer and the rest of the last byte, if it was not filled to the end.\
+    `virtual void ICodec::Decode (TMemoryRegion, TBuffer&) const;`\
+            - Input - memory region. Output - filled buffer.\
+    `virtual void Save (TOutputStream*) const;`\
+            - Serialization.\
+    `virtual void Load (TInputStream*);`\
+            - Deserialization.\
+    `virtual bool NeedsTraining() const;`\
+            - Returns if it is necessary or not to teach this codec.\
+    `virtual bool PaddingBit() const;`\
+            - Returns which values should fill the free bits of the last byte.\
+    `virtual size_t ApproximateSizeOnEncode(size_t sz) const;`\
+            - Returns an approximate estimate of the size of the result after encoding.\
+                    For example could be used for a more accurate preallocation of a buffer.\
+    `virtual size_t ApproximateSizeOnDecode(size_t sz) const;`\
+            - Returns an approximate estimate of the size of the result after decoding.\
+                    For example could be used for a more accurate preallocation of a buffer.\
+    `virtual TString GetName() const;`\
+            - The name of the codec. It is required for registration of the codec in the system of serialization/deserialization.\
+                    For example, it allows you to save information about which combination of codecs was in use (see below).\
+    `virtual void Learn(ISequenceReader*);`\
+            - The interface for teaching codecs that use information about the distribution of data.
+
+In addition, the library has a number of utilities that allow a more flexible use of it.
+
+In the `ICodec` class the following methods are available:\
+    `static TCodecPtr GetInstance(const TString& name);`\
+            - Creation of a codec instance by a symbolic name\
+                    (See `GetName()` above)\
+    `static void Store(TOutputStream*, TCodecPtr p);`\
+            - Serialization of the codec along with its name\
+                    Allows you to save information about which particular combination of codecs was used for encoding,\
+                    and then reassemble the same combination for decoding\
+    `static TCodecPtr Restore(TInputStream* in);`\
+            - Serialization of the codec along with its name\
+    `static TCodecPtr RestoreFromString(TStringBuf data);`\
+            - Loads the codec instance from the string\
+    `static TVector<TString> GetCodecsList();`\
+            - The list of registered codecs
diff --git a/library/cpp/codecs/codecs.cpp b/library/cpp/codecs/codecs.cpp
new file mode 100644
index 0000000000..b17a3156d2
--- /dev/null
+++ b/library/cpp/codecs/codecs.cpp
@@ -0,0 +1,190 @@
+#include "codecs.h"
+#include "tls_cache.h"
+
+#include <util/stream/mem.h>
+
+namespace NCodecs {
+ void ICodec::Store(IOutputStream* out, TCodecPtr p) {
+ if (!p.Get()) {
+ ::Save(out, (ui16)0);
+ return;
+ }
+
+ Y_ENSURE_EX(p->AlreadyTrained(), TCodecException() << "untrained codec " << p->GetName());
+ const TString& n = p->GetName();
+ Y_VERIFY(n.size() <= Max<ui16>());
+ ::Save(out, (ui16)n.size());
+ out->Write(n.data(), n.size());
+ p->Save(out);
+ }
+
+ TCodecPtr ICodec::Restore(IInputStream* in) {
+ ui16 l = 0;
+ ::Load(in, l);
+
+ if (!l) {
+ return nullptr;
+ }
+
+ TString n;
+ n.resize(l);
+
+ Y_ENSURE_EX(in->Load(n.begin(), l) == l, TCodecException());
+
+ TCodecPtr p = ICodec::GetInstance(n);
+ p->Load(in);
+ p->Trained = true;
+ return p;
+ }
+
+ TCodecPtr ICodec::RestoreFromString(TStringBuf s) {
+ TMemoryInput minp{s.data(), s.size()};
+ return Restore(&minp);
+ }
+
+ TString ICodec::GetNameSafe(TCodecPtr p) {
+ return !p ? TString("none") : p->GetName();
+ }
+
+ ui8 TPipelineCodec::Encode(TStringBuf in, TBuffer& out) const {
+ size_t res = Traits().ApproximateSizeOnEncode(in.size());
+ out.Reserve(res);
+ out.Clear();
+
+ if (Pipeline.empty()) {
+ out.Append(in.data(), in.size());
+ return 0;
+ } else if (Pipeline.size() == 1) {
+ return Pipeline.front()->Encode(in, out);
+ }
+
+ ui8 freelastbits = 0;
+
+ auto buffer = TBufferTlsCache::TlsInstance().Item();
+ TBuffer& tmp = buffer.Get();
+ tmp.Reserve(res);
+
+ for (auto it = Pipeline.begin(); it != Pipeline.end(); ++it) {
+ if (it != Pipeline.begin()) {
+ tmp.Clear();
+ tmp.Swap(out);
+ in = TStringBuf{tmp.data(), tmp.size()};
+ }
+ freelastbits = (*it)->Encode(in, out);
+ }
+
+ return freelastbits;
+ }
+
+ void TPipelineCodec::Decode(TStringBuf in, TBuffer& out) const {
+ size_t res = Traits().ApproximateSizeOnDecode(in.size());
+ out.Reserve(res);
+ out.Clear();
+
+ if (Pipeline.empty()) {
+ out.Append(in.data(), in.size());
+ return;
+ } else if (Pipeline.size() == 1) {
+ Pipeline.front()->Decode(in, out);
+ return;
+ }
+
+ auto buffer = TBufferTlsCache::TlsInstance().Item();
+
+ TBuffer& tmp = buffer.Get();
+ tmp.Reserve(res);
+
+ for (TPipeline::const_reverse_iterator it = Pipeline.rbegin(); it != Pipeline.rend(); ++it) {
+ if (it != Pipeline.rbegin()) {
+ tmp.Clear();
+ tmp.Swap(out);
+ in = TStringBuf{tmp.data(), tmp.size()};
+ }
+ (*it)->Decode(in, out);
+ }
+ }
+
+ void TPipelineCodec::Save(IOutputStream* out) const {
+ for (const auto& it : Pipeline)
+ it->Save(out);
+ }
+
+ void TPipelineCodec::Load(IInputStream* in) {
+ for (const auto& it : Pipeline) {
+ it->Load(in);
+ it->SetTrained(true);
+ }
+ }
+
+ void TPipelineCodec::SetTrained(bool t) {
+ for (const auto& it : Pipeline) {
+ it->SetTrained(t);
+ }
+ }
+
+ TPipelineCodec& TPipelineCodec::AddCodec(TCodecPtr codec) {
+ if (!codec)
+ return *this;
+
+ TCodecTraits tr = codec->Traits();
+
+ if (!MyName) {
+ MyTraits.AssumesStructuredInput = tr.AssumesStructuredInput;
+ MyTraits.SizeOfInputElement = tr.SizeOfInputElement;
+ } else {
+ MyName.append(':');
+ }
+
+ MyName.append(codec->GetName());
+ MyTraits.PreservesPrefixGrouping &= tr.PreservesPrefixGrouping;
+ MyTraits.PaddingBit = tr.PaddingBit;
+ MyTraits.NeedsTraining |= tr.NeedsTraining;
+ MyTraits.Irreversible |= tr.Irreversible;
+ MyTraits.SizeOnEncodeAddition = MyTraits.SizeOnEncodeAddition * tr.SizeOnEncodeMultiplier + tr.SizeOnEncodeAddition;
+ MyTraits.SizeOnEncodeMultiplier *= tr.SizeOnEncodeMultiplier;
+ MyTraits.SizeOnDecodeMultiplier *= tr.SizeOnDecodeMultiplier;
+ MyTraits.RecommendedSampleSize = Max(MyTraits.RecommendedSampleSize, tr.RecommendedSampleSize);
+
+ Pipeline.push_back(codec);
+ return *this;
+ }
+
+ void TPipelineCodec::DoLearnX(ISequenceReader& in, double sampleSizeMult) {
+ if (!Traits().NeedsTraining) {
+ return;
+ }
+
+ if (Pipeline.size() == 1) {
+ Pipeline.back()->Learn(in);
+ return;
+ }
+
+ TVector<TBuffer> trainingInput;
+
+ TStringBuf r;
+ while (in.NextRegion(r)) {
+ trainingInput.emplace_back(r.data(), r.size());
+ }
+
+ TBuffer buff;
+ for (const auto& it : Pipeline) {
+ it->LearnX(trainingInput.begin(), trainingInput.end(), sampleSizeMult);
+
+ for (auto& bit : trainingInput) {
+ buff.Clear();
+ it->Encode(TStringBuf{bit.data(), bit.size()}, buff);
+ buff.Swap(bit);
+ }
+ }
+ }
+
+ bool TPipelineCodec::AlreadyTrained() const {
+ for (const auto& it : Pipeline) {
+ if (!it->AlreadyTrained())
+ return false;
+ }
+
+ return true;
+ }
+
+}
diff --git a/library/cpp/codecs/codecs.h b/library/cpp/codecs/codecs.h
new file mode 100644
index 0000000000..cc5e72b285
--- /dev/null
+++ b/library/cpp/codecs/codecs.h
@@ -0,0 +1,259 @@
+#pragma once
+
+#include "sample.h"
+
+#include <util/generic/bt_exception.h>
+#include <util/generic/hash.h>
+#include <util/generic/ptr.h>
+#include <util/generic/singleton.h>
+
+#include <util/stream/input.h>
+#include <util/stream/output.h>
+
+#include <util/string/cast.h>
+#include <util/string/vector.h>
+#include <util/system/tls.h>
+#include <util/ysaveload.h>
+
+namespace NCodecs {
+ class TCodecException: public TWithBackTrace<yexception> {};
+
+ class ICodec;
+
+ using TCodecPtr = TIntrusivePtr<ICodec>;
+ using TCodecConstPtr = TIntrusiveConstPtr<ICodec>;
+
+ struct TCodecTraits {
+ ui32 RecommendedSampleSize = 0;
+ ui16 SizeOfInputElement = 1;
+ ui8 SizeOnEncodeMultiplier = 1;
+ ui8 SizeOnEncodeAddition = 0;
+ ui8 SizeOnDecodeMultiplier = 1;
+
+ bool NeedsTraining = false;
+ bool PreservesPrefixGrouping = false;
+ bool Irreversible = false;
+ bool PaddingBit = 0;
+ bool AssumesStructuredInput = false;
+
+ size_t ApproximateSizeOnEncode(size_t sz) const {
+ return sz * SizeOnEncodeMultiplier + SizeOnEncodeAddition;
+ }
+
+ size_t ApproximateSizeOnDecode(size_t sz) const {
+ return sz * SizeOnDecodeMultiplier;
+ }
+ };
+
+ class ICodec: public TAtomicRefCount<ICodec> {
+ protected:
+ bool Trained = false;
+ TCodecTraits MyTraits;
+
+ public:
+ TCodecTraits Traits() const {
+ return MyTraits;
+ }
+
+ // the name of the codec (or its variant) to be used in the codec registry
+ virtual TString GetName() const = 0;
+
+ virtual ui8 /*free bits in last byte*/ Encode(TStringBuf, TBuffer&) const = 0;
+ virtual ui8 Encode(const TBuffer& input, TBuffer& output) const {
+ return Encode(TStringBuf(input.Data(), input.Data() + input.Size()), output);
+ }
+ virtual void Decode(TStringBuf, TBuffer&) const = 0;
+ virtual void Decode(const TBuffer& input, TBuffer& output) const {
+ Decode(TStringBuf(input.Data(), input.Data() + input.Size()), output);
+ }
+
+ virtual ~ICodec() = default;
+
+ virtual bool AlreadyTrained() const {
+ return !Traits().NeedsTraining || Trained;
+ }
+ virtual void SetTrained(bool t) {
+ Trained = t;
+ }
+
+ bool TryToLearn(ISequenceReader& r) {
+ Trained = DoTryToLearn(r);
+ return Trained;
+ }
+
+ void Learn(ISequenceReader& r) {
+ LearnX(r, 1);
+ }
+
+ template <class TIter>
+ void Learn(TIter beg, TIter end) {
+ Learn(beg, end, IterToStringBuf<TIter>);
+ }
+
+ template <class TIter, class TGetter>
+ void Learn(TIter beg, TIter end, TGetter getter) {
+ auto sample = GetSample(beg, end, Traits().RecommendedSampleSize, getter);
+ TSimpleSequenceReader<TBuffer> reader{sample};
+ Learn(reader);
+ }
+
+ static TCodecPtr GetInstance(TStringBuf name);
+
+ static TVector<TString> GetCodecsList();
+
+ static TString GetNameSafe(TCodecPtr p);
+
+ static void Store(IOutputStream* out, TCodecPtr p);
+ static TCodecPtr Restore(IInputStream* in);
+ static TCodecPtr RestoreFromString(TStringBuf);
+
+ protected:
+ virtual void DoLearn(ISequenceReader&) = 0;
+
+ virtual bool DoTryToLearn(ISequenceReader& r) {
+ DoLearn(r);
+ return true;
+ }
+
+ // so the pipeline codec will know to adjust the sample for the subcodecs
+ virtual void DoLearnX(ISequenceReader& r, double /*sampleSizeMultiplier*/) {
+ DoLearn(r);
+ }
+
+ virtual void Save(IOutputStream*) const {
+ }
+ virtual void Load(IInputStream*) {
+ }
+ friend class TPipelineCodec;
+
+ public:
+ // so the pipeline codec will know to adjust the sample for the subcodecs
+ void LearnX(ISequenceReader& r, double sampleSizeMult) {
+ DoLearnX(r, sampleSizeMult);
+ Trained = true;
+ }
+
+ template <class TIter>
+ void LearnX(TIter beg, TIter end, double sampleSizeMult) {
+ auto sample = GetSample(beg, end, Traits().RecommendedSampleSize * sampleSizeMult);
+ TSimpleSequenceReader<TBuffer> reader{sample};
+ LearnX(reader, sampleSizeMult);
+ }
+ };
+
+ class TBasicTrivialCodec: public ICodec {
+ public:
+ ui8 Encode(TStringBuf in, TBuffer& out) const override {
+ out.Assign(in.data(), in.size());
+ return 0;
+ }
+
+ void Decode(TStringBuf in, TBuffer& out) const override {
+ Encode(in, out);
+ }
+
+ protected:
+ void DoLearn(ISequenceReader&) override {
+ }
+ };
+
+ class TTrivialCodec: public TBasicTrivialCodec {
+ public:
+ TTrivialCodec() {
+ MyTraits.PreservesPrefixGrouping = true;
+ }
+
+ static TStringBuf MyName() {
+ return "trivial";
+ }
+
+ TString GetName() const override {
+ return ToString(MyName());
+ }
+ };
+
+ class TTrivialTrainableCodec: public TBasicTrivialCodec {
+ public:
+ TTrivialTrainableCodec() {
+ MyTraits.PreservesPrefixGrouping = true;
+ MyTraits.NeedsTraining = true;
+ }
+
+ static TStringBuf MyName() {
+ return "trivial-trainable";
+ }
+
+ TString GetName() const override {
+ return ToString(MyName());
+ }
+ };
+
+ class TNullCodec: public ICodec {
+ public:
+ TNullCodec() {
+ MyTraits.Irreversible = true;
+ MyTraits.SizeOnDecodeMultiplier = 0;
+ MyTraits.SizeOnEncodeMultiplier = 0;
+ }
+
+ TString GetName() const override {
+ return "null";
+ }
+
+ ui8 Encode(TStringBuf, TBuffer& out) const override {
+ out.Clear();
+ return 0;
+ }
+
+ void Decode(TStringBuf, TBuffer& out) const override {
+ out.Clear();
+ }
+
+ protected:
+ void DoLearn(ISequenceReader&) override {
+ }
+ };
+
+ class TPipelineCodec: public ICodec {
+ typedef TVector<TCodecPtr> TPipeline;
+
+ TPipeline Pipeline;
+ TString MyName;
+
+ public:
+ explicit TPipelineCodec(TCodecPtr c0 = nullptr, TCodecPtr c1 = nullptr, TCodecPtr c2 = nullptr, TCodecPtr c3 = nullptr) {
+ MyTraits.PreservesPrefixGrouping = true;
+ AddCodec(c0);
+ AddCodec(c1);
+ AddCodec(c2);
+ AddCodec(c3);
+ }
+
+ TString GetName() const override {
+ return MyName;
+ }
+
+ ui8 Encode(TStringBuf in, TBuffer& out) const override;
+ void Decode(TStringBuf in, TBuffer& out) const override;
+
+ public:
+ /*
+ * Add codecs in the following order:
+ * uncompressed -> codec0 | codec1 | ... | codecN -> compressed
+ */
+ TPipelineCodec& AddCodec(TCodecPtr codec);
+
+ bool AlreadyTrained() const override;
+ void SetTrained(bool t) override;
+
+ protected:
+ void DoLearn(ISequenceReader& in) override {
+ DoLearnX(in, 1);
+ }
+
+ void DoLearnX(ISequenceReader& in, double sampleSizeMult) override;
+ void Save(IOutputStream* out) const override;
+ void Load(IInputStream* in) override;
+ };
+
+}
diff --git a/library/cpp/codecs/codecs_registry.cpp b/library/cpp/codecs/codecs_registry.cpp
new file mode 100644
index 0000000000..6fd7ff67b0
--- /dev/null
+++ b/library/cpp/codecs/codecs_registry.cpp
@@ -0,0 +1,226 @@
+#include "codecs_registry.h"
+#include "delta_codec.h"
+#include "huffman_codec.h"
+#include "pfor_codec.h"
+#include "solar_codec.h"
+#include "comptable_codec.h"
+#include "zstd_dict_codec.h"
+
+#include <library/cpp/blockcodecs/codecs.h>
+
+#include <util/string/builder.h>
+#include <util/string/cast.h>
+
+namespace NCodecs {
+ TCodecPtr ICodec::GetInstance(TStringBuf name) {
+ return Default<NPrivate::TCodecRegistry>().GetCodec(name);
+ }
+
+ TVector<TString> ICodec::GetCodecsList() {
+ return Default<NPrivate::TCodecRegistry>().GetCodecsList();
+ }
+
+ namespace NPrivate {
+ void TCodecRegistry::RegisterFactory(TFactoryPtr fac) {
+ TVector<TString> names = fac->ListNames();
+ for (const auto& name : names) {
+ Y_VERIFY(!Registry.contains(name), "already has %s", name.data());
+ Registry[name] = fac;
+ }
+ }
+
+ TCodecPtr TCodecRegistry::GetCodec(TStringBuf name) const {
+ using namespace NPrivate;
+
+ if (!name || "none" == name) {
+ return nullptr;
+ }
+
+ if (TStringBuf::npos == name.find(':')) {
+ Y_ENSURE_EX(Registry.contains(name), TNoCodecException(name));
+ return Registry.find(name)->second->MakeCodec(name);
+ } else {
+ TPipelineCodec* pipe = new TPipelineCodec;
+
+ do {
+ TStringBuf v = name.NextTok(':');
+ pipe->AddCodec(GetCodec(v));
+ } while (name);
+
+ return pipe;
+ }
+ }
+
+ TVector<TString> TCodecRegistry::GetCodecsList() const {
+ using namespace NPrivate;
+ TVector<TString> vs;
+ vs.push_back("none");
+
+ for (const auto& it : Registry) {
+ vs.push_back(it.first);
+ }
+
+ Sort(vs.begin(), vs.end());
+ return vs;
+ }
+
+ struct TSolarCodecFactory : ICodecFactory {
+ TCodecPtr MakeCodec(TStringBuf name) const override {
+ if (TSolarCodec::MyNameShortInt() == name) {
+ return new TSolarCodecShortInt();
+ }
+ if (TSolarCodec::MyName() == name) {
+ return new TSolarCodec();
+ }
+ if (name.EndsWith(TStringBuf("-a"))) {
+ return MakeCodecImpl<TAdaptiveSolarCodec>(name, name.SubStr(TSolarCodec::MyName().size()).Chop(2));
+ } else {
+ return MakeCodecImpl<TSolarCodec>(name, name.SubStr(TSolarCodec::MyName().size()));
+ }
+ }
+
+ template <class TCodecCls>
+ TCodecPtr MakeCodecImpl(const TStringBuf& name, const TStringBuf& type) const {
+ if (TStringBuf("-8k") == type) {
+ return new TCodecCls(1 << 13);
+ }
+ if (TStringBuf("-16k") == type) {
+ return new TCodecCls(1 << 14);
+ }
+ if (TStringBuf("-32k") == type) {
+ return new TCodecCls(1 << 15);
+ }
+ if (TStringBuf("-64k") == type) {
+ return new TCodecCls(1 << 16);
+ }
+ if (TStringBuf("-256k") == type) {
+ return new TCodecCls(1 << 18);
+ }
+ ythrow TNoCodecException(name);
+ }
+
+ TVector<TString> ListNames() const override {
+ TVector<TString> vs;
+ vs.push_back(ToString(TSolarCodec::MyName()));
+ vs.push_back(ToString(TSolarCodec::MyName8k()));
+ vs.push_back(ToString(TSolarCodec::MyName16k()));
+ vs.push_back(ToString(TSolarCodec::MyName32k()));
+ vs.push_back(ToString(TSolarCodec::MyName64k()));
+ vs.push_back(ToString(TSolarCodec::MyName256k()));
+ vs.push_back(ToString(TSolarCodec::MyName8kAdapt()));
+ vs.push_back(ToString(TSolarCodec::MyName16kAdapt()));
+ vs.push_back(ToString(TSolarCodec::MyName32kAdapt()));
+ vs.push_back(ToString(TSolarCodec::MyName64kAdapt()));
+ vs.push_back(ToString(TSolarCodec::MyName256kAdapt()));
+ vs.push_back(ToString(TSolarCodec::MyNameShortInt()));
+ return vs;
+ }
+ };
+
+ struct TZStdDictCodecFactory : ICodecFactory {
+ TCodecPtr MakeCodec(TStringBuf name) const override {
+ return new TZStdDictCodec(TZStdDictCodec::ParseCompressionName(name));
+ }
+
+ TVector<TString> ListNames() const override {
+ return TZStdDictCodec::ListCompressionNames();
+ }
+ };
+
+ struct TCompTableCodecFactory : ICodecFactory {
+ TCodecPtr MakeCodec(TStringBuf name) const override {
+ if (TCompTableCodec::MyNameHQ() == name) {
+ return new TCompTableCodec(TCompTableCodec::Q_HIGH);
+ } else if (TCompTableCodec::MyNameLQ() == name) {
+ return new TCompTableCodec(TCompTableCodec::Q_LOW);
+ } else {
+ Y_ENSURE_EX(false, TNoCodecException(name));
+ return nullptr;
+ }
+ }
+
+ TVector<TString> ListNames() const override {
+ TVector<TString> vs;
+ vs.push_back(ToString(TCompTableCodec::MyNameHQ()));
+ vs.push_back(ToString(TCompTableCodec::MyNameLQ()));
+ return vs;
+ }
+ };
+
+ struct TBlockCodec : ICodec {
+ const NBlockCodecs::ICodec* Codec;
+
+ TBlockCodec(TStringBuf name)
+ : Codec(NBlockCodecs::Codec(name))
+ {
+ }
+
+ TString GetName() const override {
+ return ToString(Codec->Name());
+ }
+
+ ui8 Encode(TStringBuf r, TBuffer& b) const override {
+ Codec->Encode(r, b);
+ return 0;
+ }
+
+ void Decode(TStringBuf r, TBuffer& b) const override {
+ // TODO: throws exception that is not TCodecException
+ Codec->Decode(r, b);
+ }
+
+ protected:
+ void DoLearn(ISequenceReader&) override {
+ }
+ };
+
+ struct TBlockCodecsFactory : ICodecFactory {
+ using TRegistry = THashMap<TString, TCodecPtr>;
+ TRegistry Registry;
+
+ TBlockCodecsFactory() {
+ for (TStringBuf codec : NBlockCodecs::ListAllCodecs()) {
+ Register(codec);
+ }
+ }
+
+ void Register(TStringBuf name) {
+ TCodecPtr p = Registry[name] = new TBlockCodec(name);
+ Registry[p->GetName()] = p;
+ }
+
+ TCodecPtr MakeCodec(TStringBuf name) const override {
+ if (!Registry.contains(name)) {
+ ythrow TNoCodecException(name);
+ }
+ return Registry.find(name)->second;
+ }
+
+ TVector<TString> ListNames() const override {
+ TVector<TString> res;
+ for (const auto& it : Registry) {
+ res.push_back(it.first);
+ }
+ return res;
+ }
+ };
+
+ TCodecRegistry::TCodecRegistry() {
+ RegisterFactory(new TInstanceFactory<TTrivialCodec>);
+ RegisterFactory(new TInstanceFactory<TTrivialTrainableCodec>);
+ RegisterFactory(new TInstanceFactory<THuffmanCodec>);
+ RegisterFactory(new TInstanceFactory<TPForCodec<ui64, true>>);
+ RegisterFactory(new TInstanceFactory<TPForCodec<ui32, true>>);
+ RegisterFactory(new TSolarCodecFactory);
+ RegisterFactory(new TZStdDictCodecFactory);
+ RegisterFactory(new TCompTableCodecFactory);
+ RegisterFactory(new TBlockCodecsFactory);
+ }
+
+ }
+
+ void RegisterCodecFactory(TCodecFactoryPtr fact) {
+ Singleton<NPrivate::TCodecRegistry>()->RegisterFactory(fact);
+ }
+
+}
diff --git a/library/cpp/codecs/codecs_registry.h b/library/cpp/codecs/codecs_registry.h
new file mode 100644
index 0000000000..53710310d5
--- /dev/null
+++ b/library/cpp/codecs/codecs_registry.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "codecs.h"
+#include <util/string/cast.h>
+
+namespace NCodecs {
+ struct TNoCodecException : TCodecException {
+ TNoCodecException(TStringBuf name) {
+ (*this) << "unknown codec: " << name;
+ }
+ };
+
+ struct ICodecFactory : TAtomicRefCount<ICodecFactory> {
+ virtual ~ICodecFactory() = default;
+ virtual TCodecPtr MakeCodec(TStringBuf name) const = 0;
+ virtual TVector<TString> ListNames() const = 0;
+ };
+
+ typedef TIntrusivePtr<ICodecFactory> TCodecFactoryPtr;
+
+ namespace NPrivate {
+ template <typename TCodec>
+ struct TInstanceFactory : ICodecFactory {
+ TCodecPtr MakeCodec(TStringBuf) const override {
+ return new TCodec;
+ }
+
+ TVector<TString> ListNames() const override {
+ TVector<TString> vs;
+ vs.push_back(ToString(TCodec::MyName()));
+ return vs;
+ }
+ };
+
+ class TCodecRegistry {
+ using TRegistry = THashMap<TString, TIntrusivePtr<ICodecFactory>>;
+ TRegistry Registry;
+
+ public:
+ using TFactoryPtr = TIntrusivePtr<ICodecFactory>;
+
+ TCodecRegistry();
+
+ void RegisterFactory(TFactoryPtr fac);
+
+ TCodecPtr GetCodec(TStringBuf name) const;
+
+ TVector<TString> GetCodecsList() const;
+ };
+
+ }
+
+ void RegisterCodecFactory(TCodecFactoryPtr fact);
+
+ template <typename TCodec>
+ void RegisterCodec() {
+ RegisterCodecFactory(new NPrivate::TInstanceFactory<TCodec>());
+ }
+
+}
diff --git a/library/cpp/codecs/comptable_codec.cpp b/library/cpp/codecs/comptable_codec.cpp
new file mode 100644
index 0000000000..476b8ada80
--- /dev/null
+++ b/library/cpp/codecs/comptable_codec.cpp
@@ -0,0 +1,108 @@
+#include "comptable_codec.h"
+
+#include <library/cpp/comptable/comptable.h>
+#include <util/string/cast.h>
+
+namespace NCodecs {
+ class TCompTableCodec::TImpl: public TAtomicRefCount<TImpl> {
+ public:
+ TImpl(EQuality q)
+ : Quality(q)
+ {
+ }
+
+ void Init() {
+ Compressor.Reset(new NCompTable::TChunkCompressor{(bool)Quality, Table});
+ Decompressor.Reset(new NCompTable::TChunkDecompressor{(bool)Quality, Table});
+ }
+
+ ui8 Encode(TStringBuf in, TBuffer& out) const {
+ out.Clear();
+ if (!in) {
+ return 0;
+ }
+
+ TVector<char> result;
+ Compressor->Compress(in, &result);
+ out.Assign(&result[0], result.size());
+ return 0;
+ }
+
+ void Decode(TStringBuf in, TBuffer& out) const {
+ out.Clear();
+ if (!in) {
+ return;
+ }
+
+ TVector<char> result;
+ Decompressor->Decompress(in, &result);
+ out.Assign(&result[0], result.size());
+ }
+
+ void DoLearn(ISequenceReader& in) {
+ NCompTable::TDataSampler sampler;
+ TStringBuf region;
+ while (in.NextRegion(region)) {
+ if (!region) {
+ continue;
+ }
+
+ sampler.AddStat(region);
+ }
+
+ sampler.BuildTable(Table);
+ Init();
+ }
+
+ void Save(IOutputStream* out) const {
+ ::Save(out, Table);
+ }
+
+ void Load(IInputStream* in) {
+ ::Load(in, Table);
+ Init();
+ }
+
+ NCompTable::TCompressorTable Table;
+ THolder<NCompTable::TChunkCompressor> Compressor;
+ THolder<NCompTable::TChunkDecompressor> Decompressor;
+ const EQuality Quality;
+ static const ui32 SampleSize = Max(NCompTable::TDataSampler::Size * 4, (1 << 22) * 5);
+ };
+
+ TCompTableCodec::TCompTableCodec(EQuality q)
+ : Impl(new TImpl{q})
+ {
+ MyTraits.NeedsTraining = true;
+ MyTraits.SizeOnEncodeMultiplier = 2;
+ MyTraits.SizeOnDecodeMultiplier = 10;
+ MyTraits.RecommendedSampleSize = TImpl::SampleSize;
+ }
+
+ TCompTableCodec::~TCompTableCodec() = default;
+
+ TString TCompTableCodec::GetName() const {
+ return ToString(Impl->Quality ? MyNameHQ() : MyNameLQ());
+ }
+
+ ui8 TCompTableCodec::Encode(TStringBuf in, TBuffer& out) const {
+ return Impl->Encode(in, out);
+ }
+
+ void TCompTableCodec::Decode(TStringBuf in, TBuffer& out) const {
+ Impl->Decode(in, out);
+ }
+
+ void TCompTableCodec::DoLearn(ISequenceReader& in) {
+ Impl->DoLearn(in);
+ }
+
+ void TCompTableCodec::Save(IOutputStream* out) const {
+ Impl->Save(out);
+ }
+
+ void TCompTableCodec::Load(IInputStream* in) {
+ Impl->Load(in);
+ }
+
+}
diff --git a/library/cpp/codecs/comptable_codec.h b/library/cpp/codecs/comptable_codec.h
new file mode 100644
index 0000000000..7ba4f4c543
--- /dev/null
+++ b/library/cpp/codecs/comptable_codec.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "codecs.h"
+
+#include <util/generic/ptr.h>
+
+namespace NCodecs {
+ class TCompTableCodec: public ICodec {
+ class TImpl;
+ TIntrusivePtr<TImpl> Impl;
+
+ public:
+ enum EQuality {
+ Q_LOW = 0,
+ Q_HIGH = 1
+ };
+
+ explicit TCompTableCodec(EQuality q = Q_HIGH);
+ ~TCompTableCodec() override;
+
+ static TStringBuf MyNameHQ() {
+ return "comptable-hq";
+ }
+ static TStringBuf MyNameLQ() {
+ return "comptable-lq";
+ }
+
+ TString GetName() const override;
+
+ ui8 Encode(TStringBuf in, TBuffer& out) const override;
+
+ void Decode(TStringBuf in, TBuffer& out) const override;
+
+ protected:
+ void DoLearn(ISequenceReader& in) override;
+ void Save(IOutputStream* out) const override;
+ void Load(IInputStream* in) override;
+ };
+
+}
diff --git a/library/cpp/codecs/delta_codec.cpp b/library/cpp/codecs/delta_codec.cpp
new file mode 100644
index 0000000000..61606d6f6f
--- /dev/null
+++ b/library/cpp/codecs/delta_codec.cpp
@@ -0,0 +1,21 @@
+#include "delta_codec.h"
+
+namespace NCodecs {
+ template <>
+ TStringBuf TDeltaCodec<ui64, true>::MyName() {
+ return "delta64-unsigned";
+ }
+ template <>
+ TStringBuf TDeltaCodec<ui32, true>::MyName() {
+ return "delta32-unsigned";
+ }
+ template <>
+ TStringBuf TDeltaCodec<ui64, false>::MyName() {
+ return "delta64-signed";
+ }
+ template <>
+ TStringBuf TDeltaCodec<ui32, false>::MyName() {
+ return "delta32-signed";
+ }
+
+}
diff --git a/library/cpp/codecs/delta_codec.h b/library/cpp/codecs/delta_codec.h
new file mode 100644
index 0000000000..21325825e6
--- /dev/null
+++ b/library/cpp/codecs/delta_codec.h
@@ -0,0 +1,143 @@
+#pragma once
+
+#include "codecs.h"
+
+#include <util/generic/array_ref.h>
+#include <util/generic/typetraits.h>
+#include <util/generic/bitops.h>
+#include <util/string/cast.h>
+
+namespace NCodecs {
+ template <typename T = ui64, bool UnsignedDelta = true>
+ class TDeltaCodec: public ICodec {
+ static_assert(std::is_integral<T>::value, "expect std::is_integral<T>::value");
+
+ public:
+ using TUnsigned = std::make_unsigned_t<T>;
+ using TSigned = std::make_signed_t<T>;
+ using TDelta = std::conditional_t<UnsignedDelta, TUnsigned, TSigned>;
+
+ private:
+ const TDelta MinDelta{Min<TDelta>()};
+ const TDelta MaxDelta{Max<TDelta>() - 1};
+ const TDelta InvalidDelta{MaxDelta + 1};
+
+ Y_FORCE_INLINE static TDelta AddSafe(TUnsigned a, TUnsigned b) {
+ return a + b;
+ }
+
+ Y_FORCE_INLINE static TDelta SubSafe(TUnsigned a, TUnsigned b) {
+ return a - b;
+ }
+
+ public:
+ struct TDecoder {
+ const TDelta InvalidDelta{Max<TDelta>()};
+
+ T Last = 0;
+ T Result = 0;
+
+ bool First = true;
+ bool Invalid = false;
+
+ Y_FORCE_INLINE bool Decode(TDelta t) {
+ if (Y_UNLIKELY(First)) {
+ First = false;
+ Result = Last = t;
+ return true;
+ }
+
+ if (Y_UNLIKELY(Invalid)) {
+ Invalid = false;
+ Last = 0;
+ Result = t;
+ return true;
+ }
+
+ Result = (Last += t);
+ Invalid = t == InvalidDelta;
+
+ return !Invalid;
+ }
+ };
+
+ public:
+ static TStringBuf MyName();
+
+ TDeltaCodec() {
+ MyTraits.SizeOfInputElement = sizeof(T);
+ MyTraits.AssumesStructuredInput = true;
+ }
+
+ TString GetName() const override {
+ return ToString(MyName());
+ }
+
+ template <class TItem>
+ static void AppendTo(TBuffer& b, TItem t) {
+ b.Append((char*)&t, sizeof(t));
+ }
+
+ ui8 Encode(TStringBuf s, TBuffer& b) const override {
+ b.Clear();
+ if (s.empty()) {
+ return 0;
+ }
+
+ b.Reserve(s.size());
+ TArrayRef<const T> tin{(const T*)s.data(), s.size() / sizeof(T)};
+
+ const T* it = tin.begin();
+ TDelta last = *(it++);
+ AppendTo(b, last);
+
+ TDelta maxt = SubSafe(MaxDelta, last);
+ TDelta mint = AddSafe(MinDelta, last);
+
+ for (; it != tin.end(); ++it) {
+ TDelta t = *it;
+
+ if (Y_LIKELY((t >= mint) & (t <= maxt))) {
+ AppendTo(b, t - last);
+ last = t;
+ maxt = SubSafe(MaxDelta, last);
+ mint = AddSafe(MinDelta, last);
+ } else {
+ // delta overflow
+ AppendTo(b, InvalidDelta);
+ AppendTo(b, t);
+ last = 0;
+ maxt = MaxDelta;
+ mint = MinDelta;
+ }
+ }
+
+ return 0;
+ }
+
+ void Decode(TStringBuf s, TBuffer& b) const override {
+ b.Clear();
+ if (s.empty()) {
+ return;
+ }
+
+ b.Reserve(s.size());
+ TArrayRef<const T> tin{(const T*)s.data(), s.size() / sizeof(T)};
+
+ TDecoder dec;
+
+ for (const T* it = tin.begin(); it != tin.end(); ++it) {
+ T tmp;
+ memcpy(&tmp, it, sizeof(tmp));
+ if (dec.Decode(tmp)) {
+ AppendTo(b, dec.Result);
+ }
+ }
+ }
+
+ protected:
+ void DoLearn(ISequenceReader&) override {
+ }
+ };
+
+}
diff --git a/library/cpp/codecs/float_huffman.cpp b/library/cpp/codecs/float_huffman.cpp
new file mode 100644
index 0000000000..c4a8bd228f
--- /dev/null
+++ b/library/cpp/codecs/float_huffman.cpp
@@ -0,0 +1,333 @@
+#include "float_huffman.h"
+
+#include <util/generic/array_ref.h>
+#include <util/generic/bitops.h>
+#include <util/generic/cast.h>
+#include <util/generic/yexception.h>
+#include <util/system/unaligned_mem.h>
+#include <util/system/yassert.h>
+#include <util/stream/format.h>
+
+namespace NCodecs::NFloatHuff {
+ namespace {
+ struct THuffEntry {
+ ui32 CodeBase;
+ ui16 Prefix;
+ int PrefLength;
+ int CodeLength;
+ int TotalLength;
+ ui32 Mask;
+ ui64 Offset;
+
+ THuffEntry() = default;
+
+ constexpr THuffEntry(ui32 codeBase, ui16 prefix, int prefLength, int codeLength)
+ : CodeBase(codeBase)
+ , Prefix(prefix)
+ , PrefLength(prefLength)
+ , CodeLength(codeLength)
+ , TotalLength(prefLength + codeLength)
+ , Mask(Mask64(codeLength))
+ , Offset(-(ui64(codeBase) << prefLength) + prefix)
+ {}
+
+ bool Fit(ui32 code) const {
+ return code >= CodeBase && code < CodeBase + (1ULL << CodeLength);
+ }
+ };
+
+ // NB. There is a typo in the penultimate line (34 instead of 24). It was there from the very
+ // first commit and we cannot fix it without breaking all the clients.
+ constexpr THuffEntry entries[16] = {
+ {0x00000000, 0x01, 1, 0}, // Only +0.0f, 1 bit, prefix [1]
+ {0x3f800000, 0x0e, 4, 0}, // Only +1.0f, 4 bits, prefix [0111]
+ {0x3f700000, 0x08, 5, 20}, // [0.9375, 1.0), 25 bits, prefix [00010]
+ {0x3f000000, 0x00, 5, 20}, // [0.5, 0.5625), 25 bits, prefx [00000]
+ {0x3f400000, 0x06, 6, 20}, // [0.75, 0.8125), 26 bits, prefix [011000]
+ {0x3f500000, 0x22, 6, 20}, // [0.8125, 0.875), 26 bits, prefix [010001]
+ {0x3f200000, 0x02, 6, 20}, // [0.625, 0.6875), 26 bits, prefix [010000]
+ {0x3f100000, 0x38, 6, 20}, // [0.5625, 0.625), 26 bits, prefix [000111]
+ {0x3f600000, 0x18, 6, 20}, // [0.875, 0.9375), 26 bits, prefix [000110]
+ {0x3f300000, 0x30, 6, 20}, // [0.6875, 0.75), 26 bits, prefix [000011]
+ {0x3e800000, 0x10, 6, 20}, // [0.25, 0.28125), 26 bits, prefix [000010]
+ {0x3e000000, 0x04, 3, 24}, // [0.125, 0.5), 27 bits, prefix [001]
+ {0x3d000000, 0x0a, 4, 24}, // [0.03125, 0.125), 28 bits, prefix [0101]
+ {0x3c000000, 0x12, 5, 24}, // [0.0078125, 0.03125), 29 bits, prefix [01001]
+ {0x3b000000, 0x26, 6, 34}, // [0.001953125, end of range), 40 bits, prefix [011001]
+ {0x00000000, 0x16, 5, 32}, // whole range, 37 bits, prefix [01101]
+ };
+
+ [[noreturn]] Y_NO_INLINE void ThrowInvalidOffset(size_t size, size_t byteOffset) {
+ ythrow yexception() <<
+ "Decompression error: requested decoding 8 bytes past end of input buffer of " << size << " bytes size at position " << byteOffset << ". ";
+ }
+
+ struct THuffInfo {
+ constexpr THuffInfo() {
+ for (size_t i = 0; i < 64; ++i) {
+ bool init = false;
+ for (size_t j = 0; j != 16; ++j) {
+ ui16 prefix = i & Mask64(entries[j].PrefLength);
+ if (entries[j].Prefix == prefix) {
+ init = true;
+ DecodeLookup[i] = entries[j];
+ break;
+ }
+ }
+ Y_ASSERT(init);
+ }
+
+ for (ui32 i = 0; i < (1 << 12); ++i) {
+ // First two entries (+0.0f and +1.0f) are not present in the lookup, they are handled separately
+ for (int value = 2; value < 16; ++value) {
+ if (entries[value].Fit(i << 20)) {
+ EncodeLookup[i] = value;
+ break;
+ }
+ }
+ }
+ }
+
+ std::pair<ui64, int> GetCode(ui32 value) const {
+ // Zeros are handled separately in the main loop
+ Y_ASSERT(value != 0);
+
+ if (value == 0x3f800000) {
+ return {0x0e, 4};
+ }
+
+ const auto& entry = entries[EncodeLookup[value >> 20]];
+
+ return {
+ (ui64(value) << entry.PrefLength) + entry.Offset,
+ entry.TotalLength
+ };
+ }
+
+ THuffEntry DecodeLookup[64];
+ ui8 EncodeLookup[1 << 12];
+ };
+
+ const THuffInfo huffInfo;
+ /// End Of Stream
+ const ui32 EOS = ui32(-1);
+ }
+
+ TString Encode(TArrayRef<const float> factors) {
+ TString result;
+ result.resize((factors.size() + 1) * 40 / 8 + 8, 0); // Max code length is 40 bits
+ int usedBits = 0;
+ ui64 buffer = 0;
+ char* writePtr = result.begin();
+
+ auto writeBits = [&](ui64 code, int size) {
+ const auto bitsToTransfer = Min(size, 64 - usedBits);
+ buffer |= (code << usedBits);
+ usedBits += bitsToTransfer;
+ if (usedBits == 64) {
+ memcpy(writePtr, &buffer, 8);
+ usedBits = size - bitsToTransfer;
+ if (bitsToTransfer != 64) {
+ buffer = code >> bitsToTransfer;
+ } else {
+ buffer = 0;
+ }
+ writePtr += 8;
+ }
+ };
+
+ for (size_t i = 0; i != factors.size();) {
+ if (BitCast<ui32>(factors[i]) == 0) {
+ int zeroCount = 1;
+ for (;;) {
+ ++i;
+ if (i == factors.size() || BitCast<ui32>(factors[i]) != 0) {
+ break;
+ }
+ ++zeroCount;
+ }
+ for (; zeroCount >= 64; zeroCount -= 64) {
+ writeBits(ui64(-1), 64);
+ }
+ writeBits(Mask64(zeroCount), zeroCount);
+ } else {
+ const auto [code, codeSize] = huffInfo.GetCode(BitCast<ui32>(factors[i]));
+ writeBits(code, codeSize);
+ ++i;
+ }
+ }
+ // Write EOS.
+ // We use precomputed constants instead of the following:
+ // auto [code, codeSize] = huffInfo.GetCode(EOS);
+ // writeBits(code, codeSize);
+ writeBits(211527139302, 40);
+ memcpy(writePtr, &buffer, 8);
+ result.resize(writePtr - result.begin() + usedBits / 8 + 8);
+
+ return result;
+ }
+
+ TDecoder::TDecoder(TStringBuf data)
+ : State{
+ .Workspace = data.size() < 8 ? ThrowInvalidOffset(data.size(), 0), 0 : ReadUnaligned<ui64>(data.data()),
+ .WorkspaceSize = 64,
+ .Position = 8,
+ .Data = data
+ }
+ {
+ FillDecodeBuffer();
+ }
+
+ TVector<float> TDecoder::DecodeAll(size_t sizeHint) {
+ TVector<float> result;
+ result.reserve(sizeHint);
+
+ while (Begin != End) {
+ result.insert(result.end(), Begin, End);
+ FillDecodeBuffer();
+ }
+ return result;
+ }
+
+ size_t TDecoder::Decode(TArrayRef<float> dest) {
+ size_t count = 0;
+ while (count < dest.size()) {
+ if (dest.size() - count < size_t(End - Begin)) {
+ const auto size = dest.size() - count;
+ std::copy(Begin, Begin + size, dest.data() + count);
+ Begin += size;
+ return dest.size();
+ } else {
+ std::copy(Begin, End, dest.data() + count);
+ count += End - Begin;
+ FillDecodeBuffer();
+ if (Begin == End) {
+ break;
+ }
+ }
+ }
+ return count;
+ }
+
+ size_t TDecoder::Skip(size_t count) {
+ size_t skippedCount = 0;
+ while (skippedCount < count) {
+ if (count - skippedCount < size_t(End - Begin)) {
+ const auto size = count - skippedCount;
+ Begin += size;
+ return count;
+ } else {
+ skippedCount += End - Begin;
+ FillDecodeBuffer();
+ if (Begin == End) {
+ break;
+ }
+ }
+ }
+ return skippedCount;
+ }
+
+ bool TDecoder::HasMore() const {
+ return Begin != End;
+ }
+
+ void TDecoder::FillDecodeBuffer() {
+ Begin = DecodeBuffer.data();
+ End = DecodeBuffer.data();
+
+ if (HitEos) {
+ return;
+ }
+
+ // This helps to keep most of the variables in the registers.
+ float* end = End;
+ TState state = State;
+
+ // It is faster to just zero all the memory here in one go
+ // and then avoid inner loop when writing zeros. There we
+ // can just increment end pointer.
+ std::fill(DecodeBuffer.begin(), DecodeBuffer.end(), 0.0f);
+
+ // Make sure that inside the loop we always have space to put 64 zeros and one other
+ // value.
+ float* cap = DecodeBuffer.data() + DecodeBuffer.size() - 64 - 1;
+
+ while (end < cap) {
+ if (state.Workspace % 2 == 1) {
+ // Decode zeros
+ // There we can just scan whole state.Workspace for ones because it contains
+ // zeros outside of the WorkspaceSize bits.
+ const auto negWorkspace = ~state.Workspace;
+ const int zeroCount = negWorkspace ? CountTrailingZeroBits(negWorkspace) : 64;
+ end += zeroCount;
+ state.SkipBits(zeroCount);
+ continue;
+ }
+ if (state.PeekBits(4) == 0x0e) {
+ *end++ = 1.0f;
+ state.SkipBits(4);
+ continue;
+ }
+ const auto& entry = huffInfo.DecodeLookup[state.PeekBits(6)];
+ const auto code = ui32((state.NextBitsUnmasked(entry.TotalLength) >> entry.PrefLength) & entry.Mask) + entry.CodeBase;
+ if (Y_UNLIKELY(code == EOS)) {
+ HitEos = true;
+ break;
+ }
+ *end++ = BitCast<float>(code);
+ }
+
+ End = end;
+ State = state;
+ }
+
+ ui64 TDecoder::TState::PeekBits(int count) {
+ if (WorkspaceSize > count) {
+ return Workspace & Mask64(count);
+ } else {
+ if (Y_UNLIKELY(Position + 8 > Data.size())) {
+ ThrowInvalidOffset(Data.size(), Position);
+ }
+ return (Workspace | (ReadUnaligned<ui64>(Data.data() + Position) << WorkspaceSize)) & Mask64(count);
+ }
+ }
+
+ ui64 TDecoder::TState::NextBitsUnmasked(int count) {
+ if (WorkspaceSize > count) {
+ const auto result = Workspace;
+ Workspace >>= count;
+ WorkspaceSize -= count;
+ return result;
+ } else {
+ if (Y_UNLIKELY(Position + 8 > Data.size())) {
+ ThrowInvalidOffset(Data.size(), Position);
+ }
+ ui64 result = Workspace;
+ Workspace = ReadUnaligned<ui64>(Data.data() + Position);
+ Position += 8;
+ result |= Workspace << WorkspaceSize;
+ Workspace >>= count - WorkspaceSize;
+ WorkspaceSize += 64 - count;
+ return result;
+ }
+ }
+
+ void TDecoder::TState::SkipBits(int count) {
+ if (WorkspaceSize > count) {
+ Workspace >>= count;
+ WorkspaceSize -= count;
+ } else {
+ if (Y_UNLIKELY(Position + 8 > Data.size())) {
+ ThrowInvalidOffset(Data.size(), Position);
+ }
+ Workspace = ReadUnaligned<ui64>(Data.data() + Position);
+ Position += 8;
+ Workspace >>= count - WorkspaceSize;
+ WorkspaceSize += 64 - count;
+ }
+ }
+
+ TVector<float> Decode(TStringBuf data, size_t sizeHint) {
+ return TDecoder(data).DecodeAll(sizeHint);
+ }
+} // namespace NCodecs::NFloatHuff
diff --git a/library/cpp/codecs/float_huffman.h b/library/cpp/codecs/float_huffman.h
new file mode 100644
index 0000000000..786a8eae1d
--- /dev/null
+++ b/library/cpp/codecs/float_huffman.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <util/generic/array_ref.h>
+#include <util/generic/vector.h>
+#include <util/generic/strbuf.h>
+
+#include <array>
+
+namespace NCodecs::NFloatHuff {
+ TString Encode(TArrayRef<const float> factors);
+
+ class TDecoder {
+ public:
+ explicit TDecoder(TStringBuf data);
+
+ TVector<float> DecodeAll(size_t sizeHint = 0);
+
+ // Returns number of decoded floats. May be fewer than requested if the EOS is found.
+ size_t Decode(TArrayRef<float> dest);
+
+ // Returns the number of skipped values.
+ size_t Skip(size_t count);
+
+ bool HasMore() const;
+
+ private:
+ struct TState {
+ ui64 Workspace = 0;
+ int WorkspaceSize = 0;
+ ui64 Position = 0;
+ TStringBuf Data;
+
+ ui64 NextBitsUnmasked(int count); // The upper 64 - count bits may be arbitrary
+ ui64 PeekBits(int count);
+ void SkipBits(int count);
+ };
+
+ void FillDecodeBuffer();
+
+ TState State;
+ std::array<float, 128> DecodeBuffer;
+ // The range of already decompressed numbers inside the DecodeBuffer.
+ // Always kept non-empty until the EOS is encountered.
+ float* Begin;
+ float* End;
+ bool HitEos = false;
+ };
+
+ TVector<float> Decode(TStringBuf data, size_t sizeHint = 0);
+}
diff --git a/library/cpp/codecs/float_huffman_bench/main.cpp b/library/cpp/codecs/float_huffman_bench/main.cpp
new file mode 100644
index 0000000000..1018c17834
--- /dev/null
+++ b/library/cpp/codecs/float_huffman_bench/main.cpp
@@ -0,0 +1,145 @@
+#include <library/cpp/codecs/float_huffman.h>
+
+#include <benchmark/benchmark.h>
+
+#include <util/generic/vector.h>
+
+const float Factors[] = {
+ 0.340582, 0.000974026, 0.487168, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0.411765, 0.921569,
+ 0.00390625, 0.109371, 0, 1, 0, 0, 0, 0, 0.523322, 0, 1, 0, 0, 0, 0, 0.285714, 1,
+ 0.008253, 1, 0, 0, 0.00993935, 0.450213, 0.000974026, 1, 1, 1, 1, 0, 0, 0.20564,
+ 0.97561, 0.913896, 1, 1, 0, 1, 0, 0, 0.5, 0, 0, 0, 0.1, 1, 0, 0, 0, 0, 0, 0.450923,
+ 0, 0.5, 0, 0, 0.20564, 0, 0.5, 0, 0, 0.20564, 0, 0, 0.0313726, 0, 1, 1, 1, 0.363636,
+ 0.5, 0.686073, 0.45121, 0.00574382, 0.366166, 0.413295, 1, 1, 1, 0, 0, 0, 0, 0.160784,
+ 0, 0.937255, 0.537255, 0.133333, 0, 0, 0, 0, 0.00392157, 0, 0.333333, 0.027451, 0.0156863,
+ 1, 0.105882, 1, 0.00220908, 0.000112501, 0.0111262, 0.102384, 0.00140808, 0.123581,
+ 0.29308, 6.57282e-06, 0.00489498, 2.10209e-05, 0.00140559, 5.907e-06, 0, 0.559322,
+ 0.559322, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0.794765, 0,
+ 0.352648, 0.225904, 1, 0.047619, 0.0107276, 0.399461, 0.0304838, 0.292932, 0.00969929,
+ 0, 0, 0.886904, 0.714693, 0, 0.00223213, 0.000544069, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0.00507403, 0, 0, 0, 0, 0, 0.875, 0, 0, 1, 1, 1, 0, 0.20564, 0, 0.00176048, 0,
+ 0.000440121, 0, 0, 0, 0.000974026, 0.487168, 0, 0, 0.533333, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 1, 0, 0, 0.723187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0.206882, 0.00483367, 0.792983, 0.00126106, 1, 0.0313726, 0.470588,
+ 0.254902, 0.188235, 0.188235, 0.388235, 0.164706, 0, 0.870588, 0.843137, 0.635294,
+ 0.384314, 0.384314, 0.643137, 0, 0, 0, 0, 0, 0, 0, 0, 0.541176, 0, 0.541176, 0, 0,
+ 0.0532634, 1, 0, 0, 0, 0.015044, 1, 0, 1, 1, 1, 0.47451, 0.329412, 0.964706, 0, 0,
+ 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0.0941176, 0.970588, 0.970588, 0, 0.970588, 0.97561,
+ 0, 0.0431373, 0.47451, 0.329412, 0.964706, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0.231373, 0.00392157, 0, 0, 0, 0.054902, 0, 0,
+ 1, 0, 0, 0.0235294, 0, 1, 0, 0, 0, 0, 0.34902, 0.0352941, 0.925379, 0.623681, 0,
+ 0.954543, 0, 0, 0.00102756, 0.709804, 0.498039, 0.0901961, 0.631373, 0.847059, 0.270588,
+ 0.0156863, 0.133333, 0.980392, 1e-12, 1e-12, 1e-12, 1e-12, 0.497159, 0, 0.407487,
+ 0, 0, 0, 0.00392157, 0.00202156, 0.046875, 0.187159, 0.046875, 0.15625, 0.434232,
+ 0.15625, 0, 2.95083e-07, 0.20564, 0.20564, 0.97561, 0.913896, 0, 0, 0, 0, 0, 0, 0.00784314,
+ 0, 0.695525, 1, 0.07205, 0, 0, 0.176471, 0, 0, 0, 1, 1, 0.98, 0.01, 0.01, 0, 0.00690702,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.29078, 0.29078, 1, 0, 0, 0, 0, 0.192157, 0.188235,
+ 0.0941176, 0, 0.0313726, 0, 0.141176, 0.207843, 0.0901961, 0.00784314, 0.0784314,
+ 0, 0, 0, 0, 0, 0.203922, 0.0196078, 0.34902, 0.0235294, 0.0980392, 0.164706, 0.133333,
+ 0.368627, 0, 0.0941176, 0, 1, 0.313726, 0, 0, 0.433582, 0.384508, 0.0532186, 0.0833333,
+ 0.01609, 0, 1, 0, 0, 0, 0.0666667, 0, 0, 0, 0, 1, 0, 0.564706, 0.501961, 0, 0, 0,
+ 0, 0, 0.0516447, 0.000173065, 0, 0, 0, 0, 0, 0, 0, 0.996309, 0, 0, 0.00392157, 1,
+ 0, 0.01, 0, 0, 0, 0, 0, 0.439505, 0.206882, 0.206882, 0.260891, 0, 0.875, 0, 0, 0,
+ 0, 0, 0.185657, 1, 1, 0, 0, 0, 0.0332647, 0.206106, 0.0688878, 0.239216, 0, 0, 0,
+ 0, 0.054902, 0, 0.101961, 0.160784, 0.180392, 0, 0.737828, 0, 0, 0.875, 0.0142566,
+ 0, 0.662745, 1, 0, 0, 0, 0.225806, 0.99992, 0.631373, 0.00392157, 1, 0, 0.143647,
+ 0.00270085, 1, 0.231482, 0.246735, 0.0428062, 0, 0, 1, 0, 0.186441, 0.0115358, 0,
+ 0.221762, 0, 0.2, 0, 0.0156863, 0, 0, 0, 0.976471, 0, 0.231373, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0.00392157, 0.00392157, 0.0666667, 0, 0, 0, 0, 0.0117647, 0.580392, 0.98737,
+ 1, 1, 1, 0, 0, 0, 0.153, 0.847, 0.931373, 0.94697, 0.94697, 0, 0.946294, 0.408118,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0.99992, 0.97561, 0, 0, 0, 0, 0, 0,
+ 0.274677, 0.153017, 0, 0.642356, 0, 0, 0.1, 0, 0, 0, 0, 0.327944, 0.327944, 0, 0,
+ 0.815686, 0, 0, 0, 0, 0.206106, 0.439126, 0, 0, 0, 0, 0, 1, 1, 1, 0.00392157, 0.232788,
+ 0.232465, 0.999899, 0.00309296, 0.0636097, 0.445954, 0.156863, 0, 0, 0, 0, 0, 0,
+ 0.3796, 0.0784, 0.0651664, 0, 0, 0.254902, 0.266667, 1, 0, 0, 0, 0, 0, 0.596073,
+ 0.517876, 0.145833, 0.372549, 0, 0.991667, 0.602125, 0.161979, 0, 0, 0, 0, 0.0255146,
+ 0.947855, 0, 0, 0, 0, 0, 0, 0, 0, 0.847059, 0.679841, 0, 0.156863, 0, 0, 1, 0, 0,
+ 0, 0, 0.969697, 0, 0, 0.564706, 0, 0, 0, 0, 0, 1, 0.0367282, 0.0395228, 0, 0, 0,
+ 0, 0, 0.0470588, 0.141176, 0.054902, 0, 0, 0, 0};
+
+const ui8 CodedFactors[] = {
+ 0x24, 0x06, 0x73, 0xB5, 0xC7, 0x55, 0x7F, 0x3A, 0xB4, 0x70, 0xCB, 0xEF, 0xEE, 0xFE, 0xB3, 0x5B,
+ 0x5A, 0x1A, 0x93, 0x5F, 0x5F, 0x13, 0x00, 0x00, 0x10, 0x00, 0x3D, 0xEF, 0xFF, 0xEE, 0x0F, 0xDC,
+ 0xF0, 0xAB, 0x3F, 0x37, 0x92, 0x24, 0x5D, 0x5E, 0xDE, 0x1C, 0xF8, 0x12, 0x15, 0x5B, 0x84, 0x51,
+ 0x82, 0xE6, 0xF6, 0xB8, 0xEA, 0x4F, 0xC7, 0xDD, 0x7D, 0x2E, 0x4D, 0x4A, 0x21, 0xCA, 0xE0, 0xC4,
+ 0x2E, 0xEA, 0xD3, 0xBD, 0x0F, 0x00, 0x00, 0xE0, 0xDA, 0xCC, 0xCC, 0xEC, 0x9F, 0x61, 0xDF, 0xE6,
+ 0x01, 0x00, 0x00, 0xCC, 0xA5, 0x49, 0xA9, 0x00, 0x00, 0x00, 0xE6, 0xD2, 0xA4, 0xD4, 0xEA, 0x08,
+ 0x08, 0xD0, 0xDD, 0xF9, 0xE7, 0xA2, 0x0B, 0x00, 0x00, 0x40, 0xD8, 0x13, 0x7D, 0xFE, 0x13, 0x9C,
+ 0x9B, 0xA8, 0x36, 0xBC, 0x00, 0x90, 0x43, 0x6F, 0x97, 0x67, 0x9B, 0xD3, 0xEE, 0xFE, 0x84, 0x24,
+ 0x25, 0x89, 0xC9, 0xBF, 0x3F, 0x58, 0x4C, 0x4C, 0xCA, 0x21, 0x22, 0xBC, 0x39, 0x08, 0x08, 0x08,
+ 0x40, 0x7E, 0xAA, 0xAA, 0xCA, 0x75, 0x70, 0x70, 0xE9, 0x08, 0x08, 0xE8, 0x9A, 0x8A, 0x8D, 0xED,
+ 0xA6, 0x8D, 0x31, 0x04, 0x00, 0x96, 0xD0, 0x7D, 0x1D, 0x47, 0xAA, 0x2A, 0xD9, 0x28, 0xAD, 0x6B,
+ 0xB4, 0x9D, 0x7A, 0xC4, 0xD5, 0xD1, 0x04, 0x8C, 0x7E, 0x56, 0x3A, 0x58, 0x5A, 0x0C, 0x46, 0x6E,
+ 0x1B, 0x53, 0xC2, 0x0C, 0x14, 0x00, 0xAB, 0x60, 0x05, 0x7B, 0x63, 0x8D, 0x77, 0x70, 0x75, 0xAC,
+ 0x2F, 0x8D, 0xB1, 0x4D, 0xA0, 0xFB, 0xF2, 0x40, 0xF7, 0xE5, 0x7F, 0xDF, 0xDD, 0xFD, 0xBB, 0x1B,
+ 0xB8, 0x75, 0x9B, 0x47, 0x8E, 0xB4, 0x0C, 0x9B, 0x3A, 0x73, 0x25, 0x61, 0x18, 0x92, 0xD1, 0xC2,
+ 0x2F, 0x3C, 0x31, 0x64, 0x96, 0x2A, 0xB9, 0xF9, 0x7C, 0xD9, 0xAF, 0x94, 0xC5, 0xE9, 0x1E, 0x63,
+ 0x24, 0x0C, 0x03, 0x7F, 0xD8, 0x5B, 0xB3, 0x1D, 0x49, 0x02, 0x00, 0xAB, 0xFD, 0xE9, 0xA0, 0xF3,
+ 0xBF, 0xC9, 0x40, 0x64, 0x0A, 0xC0, 0xC7, 0x00, 0x00, 0x60, 0x77, 0xCF, 0xA5, 0x49, 0xA9, 0x16,
+ 0xFD, 0xD7, 0x5C, 0xA7, 0x55, 0x00, 0x36, 0xCF, 0xB9, 0x3D, 0xAE, 0xFA, 0xD3, 0xA1, 0x85, 0x5B,
+ 0xFE, 0x60, 0x10, 0x11, 0xFF, 0xF7, 0x7D, 0x38, 0x59, 0x24, 0xFF, 0xFF, 0xDF, 0x13, 0x1C, 0x7B,
+ 0xCA, 0x1C, 0x1E, 0xF3, 0x04, 0xC0, 0x78, 0x07, 0x58, 0x7B, 0xA2, 0x54, 0xAA, 0xE3, 0xEA, 0x08,
+ 0x08, 0xC0, 0x74, 0x78, 0x78, 0x88, 0x50, 0x50, 0xD8, 0x0A, 0x0C, 0xC4, 0x56, 0x60, 0x20, 0xF6,
+ 0x1A, 0x1B, 0x33, 0x16, 0x15, 0xA5, 0xB8, 0xED, 0xED, 0x22, 0xF5, 0xF5, 0x09, 0xA1, 0xA2, 0x42,
+ 0x67, 0x62, 0x62, 0x3A, 0x13, 0x13, 0x0B, 0xA0, 0xA4, 0xF4, 0x0F, 0x06, 0x15, 0x35, 0x18, 0x54,
+ 0xD4, 0x35, 0x57, 0x45, 0xCB, 0x2F, 0x39, 0xF6, 0xEC, 0xBC, 0xBB, 0x53, 0x5F, 0x5E, 0x9E, 0xB1,
+ 0xA8, 0xA8, 0x28, 0xDF, 0xDE, 0x3E, 0x00, 0x00, 0x80, 0x5F, 0x75, 0x81, 0x81, 0x51, 0x1D, 0x1E,
+ 0xA2, 0x3A, 0x3C, 0x8C, 0xEA, 0xF0, 0x10, 0x51, 0x06, 0x67, 0xED, 0x85, 0x85, 0xA1, 0xBE, 0xBC,
+ 0x3C, 0x63, 0x51, 0x51, 0x51, 0xBE, 0xBD, 0xFD, 0xFF, 0xFD, 0xFE, 0xCE, 0x85, 0x76, 0x36, 0x73,
+ 0x10, 0x10, 0x10, 0x80, 0xEB, 0x3A, 0x38, 0xD8, 0xBE, 0xD4, 0x05, 0x06, 0xEE, 0x4F, 0x60, 0x59,
+ 0x59, 0x65, 0x84, 0x84, 0xC0, 0x46, 0xCB, 0x19, 0x7F, 0x4C, 0xFD, 0xC8, 0x9D, 0x8B, 0xB6, 0x31,
+ 0xAF, 0x86, 0x3A, 0xF0, 0x6D, 0x6D, 0x11, 0xDF, 0xDF, 0x5F, 0x79, 0x71, 0x71, 0x85, 0xD4, 0xD0,
+ 0x10, 0xB9, 0xB1, 0x11, 0x1A, 0x54, 0x54, 0xE9, 0x08, 0x08, 0x48, 0x39, 0x44, 0x04, 0x84, 0xAF,
+ 0xAF, 0x96, 0x99, 0x97, 0x71, 0xC5, 0x32, 0xF3, 0x32, 0xAE, 0x58, 0x66, 0x5E, 0xC6, 0x15, 0xCB,
+ 0xCC, 0xCB, 0xB8, 0x42, 0xD0, 0x45, 0xFF, 0x1C, 0x11, 0x85, 0xBE, 0x39, 0x08, 0x08, 0x08, 0x80,
+ 0x69, 0xC2, 0x47, 0x00, 0x80, 0x02, 0x00, 0x00, 0x91, 0xD3, 0xF4, 0x47, 0x01, 0x00, 0x80, 0x08,
+ 0x00, 0x00, 0x42, 0xD4, 0x29, 0x6F, 0x02, 0x00, 0x80, 0xB4, 0xE6, 0x6B, 0x9E, 0x34, 0x5C, 0x9A,
+ 0x94, 0xE2, 0xD2, 0xA4, 0x14, 0xA2, 0x0C, 0x4E, 0xEC, 0xA2, 0x3E, 0x7F, 0x39, 0x08, 0x08, 0x10,
+ 0x6E, 0x6F, 0x10, 0xD7, 0x79, 0xC7, 0xC9, 0x09, 0x4D, 0x4B, 0x73, 0x77, 0x84, 0x14, 0xAE, 0x52,
+ 0xE1, 0x7A, 0x44, 0x2A, 0x5C, 0x8F, 0x34, 0x93, 0xA8, 0xC4, 0x01, 0xF8, 0x3F, 0x3D, 0xC2, 0x29,
+ 0xE9, 0x11, 0x4E, 0xE9, 0x4F, 0x67, 0x62, 0x22, 0xB6, 0x02, 0x03, 0xA9, 0x2E, 0x30, 0x70, 0x75,
+ 0x04, 0x04, 0xC8, 0x38, 0x48, 0x08, 0x32, 0x53, 0x53, 0x29, 0x2F, 0x2E, 0xAE, 0x1C, 0x04, 0x04,
+ 0x50, 0x52, 0x50, 0xD0, 0x4F, 0x77, 0x68, 0x28, 0x99, 0x08, 0x0A, 0x4A, 0x60, 0x59, 0x59, 0xA9,
+ 0x0B, 0x0C, 0xAC, 0xC7, 0xC8, 0xC8, 0x8C, 0x45, 0x45, 0xA1, 0x1C, 0x22, 0x02, 0x5D, 0x79, 0x79,
+ 0xAB, 0x2E, 0x30, 0x70, 0xA7, 0x2C, 0x28, 0xE8, 0xB4, 0xF3, 0xEF, 0x26, 0x8F, 0x37, 0xB1, 0xFE,
+ 0xEE, 0x67, 0xA9, 0xA9, 0xAA, 0xAA, 0x6C, 0x79, 0x1E, 0xEC, 0xD7, 0x46, 0x44, 0xC4, 0xF7, 0xF8,
+ 0x24, 0x24, 0x00, 0x42, 0x40, 0xF8, 0x5A, 0x96, 0x38, 0x65, 0x91, 0xF1, 0x6A, 0x72, 0xFE, 0x68,
+ 0xC3, 0xE1, 0x37, 0x07, 0x01, 0x01, 0x01, 0xF0, 0x52, 0xE1, 0x7A, 0xE4, 0xB3, 0xD9, 0x20, 0x9C,
+ 0xE0, 0xD8, 0x53, 0x04, 0xC7, 0x9E, 0x82, 0x02, 0x27, 0x2B, 0x06, 0x00, 0x00, 0x9F, 0xDE, 0x1C,
+ 0x3E, 0xEE, 0xD7, 0x48, 0x20, 0x04, 0xD2, 0x35, 0x4C, 0x29, 0x43, 0x45, 0x23, 0x15, 0xEA, 0xE9,
+ 0x5E, 0xD7, 0xC1, 0xC1, 0xAA, 0x3B, 0x34, 0x34, 0x21, 0x49, 0x49, 0xE8, 0x8A, 0x8B, 0x13, 0x66,
+ 0x12, 0xE7, 0x31, 0x00, 0x00, 0x90, 0x84, 0x94, 0x69, 0x05, 0xD4, 0xD4, 0xF4, 0x13, 0x36, 0xE7,
+ 0x0C, 0x09, 0xEB, 0xBF, 0x90, 0x1A, 0x1A, 0xE6, 0x20, 0x20, 0x20, 0x00, 0x9E, 0x33, 0x18, 0x13,
+ 0xA6, 0x2F, 0x40, 0x0C, 0x00, 0x4E, 0xCF, 0x84, 0x36, 0x6A, 0xA0, 0xF2, 0xA9, 0x63, 0xD5, 0xCB,
+ 0x9E, 0x64, 0xEA, 0x3E, 0xF2, 0x14, 0xA0, 0x27, 0x29, 0x2B, 0xC6, 0xB2, 0x99, 0x99, 0xA9, 0x74,
+ 0x04, 0x04, 0x3C, 0x0A, 0xD0, 0xCF, 0x5C, 0x68, 0x67, 0xFB, 0xDF, 0x1C, 0x04, 0x04, 0x04, 0xC0,
+ 0x1C, 0x04, 0x04, 0x04, 0x40, 0x1B, 0x11, 0x11, 0x5F, 0xEA, 0x02, 0x03, 0xE1, 0x92, 0x94, 0x84,
+ 0x90, 0x88, 0xD9, 0xDD, 0x4F, 0x04, 0x56, 0x0E, 0xD1, 0x9F, 0x1A, 0x31, 0x3B, 0x37, 0x47, 0xA0,
+ 0x6C, 0x82, 0x40, 0xD9, 0x24, 0x9A, 0x02, 0x12, 0x62, 0xD3, 0x43, 0xFF, 0xBF, 0x8F, 0x84, 0xF5,
+ 0x1F, 0x51, 0x06, 0xE7, 0x0F, 0xDD, 0x89, 0x32, 0xFB, 0x60, 0x39, 0x0A, 0x71, 0x71, 0xB4, 0x36,
+ 0x33, 0x33, 0x3F, 0x8F, 0xD0, 0x4F, 0x79, 0x84, 0x7E, 0xBA, 0xC8, 0x0C, 0x0D, 0x4F, 0xBA, 0x86,
+ 0x29, 0x82, 0x54, 0x83, 0x7F, 0x77, 0x37, 0x07, 0x01, 0x01, 0x01, 0xA0, 0xFE, 0x97, 0x1B, 0x9D,
+ 0x16, 0xDC, 0x90, 0x58, 0xFE, 0x9B, 0x42, 0xB3, 0x4A, 0x00, 0x68, 0x73, 0x91, 0x20, 0x2B, 0xA8,
+ 0xC8, 0x29, 0x0B, 0x0A, 0xF2, 0xD3, 0x5D, 0x4B, 0x58, 0x5D, 0x20, 0x41, 0xD5, 0xBE, 0xAE, 0x70,
+ 0x88, 0x50, 0x50, 0x20, 0x4A, 0x44, 0xF4, 0x8F, 0xF7, 0x60, 0x22, 0x30, 0x9C, 0x24, 0xFE, 0x54,
+ 0x55, 0xD0, 0xD7, 0xD7, 0x37, 0x1A, 0xEF, 0x6E, 0xBC, 0x9B, 0x44, 0x39, 0xDD, 0x5D, 0xF2, 0xF2,
+ 0x7F, 0x20, 0x1A, 0x81, 0x9A, 0xCA, 0xBF, 0xC8, 0x8D, 0x8D, 0xC2, 0x83, 0x82, 0xA7, 0x2C, 0x28,
+ 0xC8, 0xFE, 0x08, 0xC2, 0x07, 0xC7, 0x27, 0x21, 0xE1, 0xBB, 0x3E, 0xC1, 0x59, 0x68, 0xAA, 0x78,
+ 0xC8, 0x57, 0x5D, 0x60, 0x20, 0xC6, 0x41, 0x42, 0xE8, 0x3A, 0x38, 0xD8, 0x9B, 0xFF, 0xFF, 0xFF,
+ 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static const TStringBuf CodedFactorsBuf(reinterpret_cast<const char*>(CodedFactors), Y_ARRAY_SIZE(CodedFactors));
+
+void BM_Encode(benchmark::State& state) {
+ for (const auto _ : state) {
+ NCodecs::NFloatHuff::Encode(Factors);
+ }
+}
+
+void BM_Decode(benchmark::State& state) {
+ for (const auto _ : state) {
+ NCodecs::NFloatHuff::Decode(CodedFactorsBuf, Y_ARRAY_SIZE(Factors));
+ }
+}
+
+BENCHMARK(BM_Encode);
+BENCHMARK(BM_Decode);
diff --git a/library/cpp/codecs/float_huffman_bench/ya.make b/library/cpp/codecs/float_huffman_bench/ya.make
new file mode 100644
index 0000000000..c8fae6873a
--- /dev/null
+++ b/library/cpp/codecs/float_huffman_bench/ya.make
@@ -0,0 +1,13 @@
+OWNER(eeight)
+
+G_BENCHMARK()
+
+SRCS(
+ main.cpp
+)
+
+PEERDIR(
+ library/cpp/codecs
+)
+
+END()
diff --git a/library/cpp/codecs/greedy_dict/gd_builder.cpp b/library/cpp/codecs/greedy_dict/gd_builder.cpp
new file mode 100644
index 0000000000..561bfbca01
--- /dev/null
+++ b/library/cpp/codecs/greedy_dict/gd_builder.cpp
@@ -0,0 +1,142 @@
+#include "gd_builder.h"
+
+#include <library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h>
+#include <util/generic/algorithm.h>
+
+#include <util/random/shuffle.h>
+#include <util/stream/output.h>
+#include <util/string/printf.h>
+#include <util/system/rusage.h>
+
+namespace NGreedyDict {
+ void TDictBuilder::RebuildCounts(ui32 maxcand, bool final) {
+ if (!Current) {
+ Current = MakeHolder<TEntrySet>();
+ Current->InitWithAlpha();
+ }
+
+ TEntrySet& set = *Current;
+
+ for (auto& it : set)
+ it.Count = 0;
+
+ CompoundCounts = nullptr;
+ CompoundCountsPool.Clear();
+
+ if (!final) {
+ CompoundCounts = MakeHolder<TCompoundCounts>(&CompoundCountsPool);
+ CompoundCounts->reserve(maxcand);
+ }
+
+ Shuffle(Input.begin(), Input.end(), Rng);
+
+ for (auto str : Input) {
+ if (!final && CompoundCounts->size() > maxcand)
+ break;
+
+ i32 prev = -1;
+
+ while (!!str) {
+ TEntry* e = set.FindPrefix(str);
+ ui32 num = e->Number;
+
+ e->Count += 1;
+ if (!final && prev >= 0) {
+ (*CompoundCounts)[Compose(prev, num)] += 1;
+ }
+
+ prev = num;
+ ++set.TotalCount;
+ }
+ }
+
+ Current->SetModelP();
+ }
+
+ ui32 TDictBuilder::BuildNextGeneration(ui32 maxent) {
+ TAutoPtr<TEntrySet> newset = new TEntrySet;
+ newset->InitWithAlpha();
+ maxent -= newset->size();
+
+ ui32 additions = 0;
+ ui32 deletions = 0;
+
+ {
+ const TEntrySet& set = *Current;
+
+ Candidates.clear();
+ const ui32 total = set.TotalCount;
+ const float minpval = Settings.MinPValue;
+ const EEntryStatTest test = Settings.StatTest;
+ const EEntryScore score = Settings.Score;
+ const ui32 mincnt = Settings.MinAbsCount;
+
+ for (const auto& it : set) {
+ const TEntry& e = it;
+ float modelp = e.ModelP;
+ ui32 cnt = e.Count;
+
+ if (e.HasPrefix() && e.Count > mincnt && StatTest(test, modelp, cnt, total) > minpval)
+ Candidates.push_back(TCandidate(-Score(score, e.Len(), modelp, cnt, total), it.Number));
+ }
+
+ if (!!CompoundCounts) {
+ for (TCompoundCounts::const_iterator it = CompoundCounts->begin(); it != CompoundCounts->end(); ++it) {
+ const TEntry& prev = set.Get(Prev(it->first));
+ const TEntry& next = set.Get(Next(it->first));
+ float modelp = ModelP(prev.Count, next.Count, total);
+ ui32 cnt = it->second;
+ if (cnt > mincnt && StatTest(test, modelp, cnt, total) > minpval)
+ Candidates.push_back(TCandidate(-Score(score, prev.Len() + next.Len(), modelp, cnt, total), it->first));
+ }
+ }
+
+ Sort(Candidates.begin(), Candidates.end());
+
+ if (Candidates.size() > maxent)
+ Candidates.resize(maxent);
+
+ for (const auto& candidate : Candidates) {
+ if (IsCompound(candidate.second)) {
+ additions++;
+ newset->Add(set.Get(Prev(candidate.second)).Str, set.Get(Next(candidate.second)).Str);
+ } else {
+ newset->Add(set.Get(candidate.second).Str);
+ }
+ }
+
+ deletions = set.size() - (newset->size() - additions);
+ }
+
+ Current = newset;
+ Current->BuildHierarchy();
+ return deletions + additions;
+ }
+
+ ui32 TDictBuilder::Build(ui32 maxentries, ui32 maxiters, ui32 mindiff) {
+ size_t totalsz = 0;
+ for (auto it : Input)
+ totalsz += it.size();
+
+ while (maxiters) {
+ maxiters--;
+
+ RebuildCounts(maxentries * Settings.GrowLimit, false);
+
+ if (Settings.Verbose) {
+ TString mess = Sprintf("iter:%" PRIu32 " sz:%" PRIu32 " pend:%" PRIu32, maxiters, (ui32)Current->size(), (ui32)CompoundCounts->size());
+ Clog << Sprintf("%-110s RSS=%" PRIu32 "M", mess.data(), (ui32)(TRusage::Get().MaxRss >> 20)) << Endl;
+ }
+
+ ui32 diff = BuildNextGeneration(maxentries);
+
+ if (Current->size() == maxentries && diff < mindiff)
+ break;
+ }
+
+ RebuildCounts(0, true);
+ Current->SetScores(Settings.Score);
+ return maxiters;
+ }
+
+}
diff --git a/library/cpp/codecs/greedy_dict/gd_builder.h b/library/cpp/codecs/greedy_dict/gd_builder.h
new file mode 100644
index 0000000000..b8e9a5e37b
--- /dev/null
+++ b/library/cpp/codecs/greedy_dict/gd_builder.h
@@ -0,0 +1,94 @@
+#pragma once
+
+#include "gd_entry.h"
+
+#include <util/generic/hash.h>
+#include <util/random/fast.h>
+
+namespace NGreedyDict {
+ struct TBuildSettings {
+ EEntryStatTest StatTest = EST_SIMPLE_NORM;
+ EEntryScore Score = ES_LEN_SIMPLE;
+
+ float MinPValue = 0.75;
+ ui32 MinAbsCount = 10;
+ ui32 GrowLimit = 10; // times of maxentries
+ bool Verbose = false;
+ };
+
+ class TDictBuilder {
+ using TCompoundCounts = THashMap<ui64, ui32, THash<ui64>, TEqualTo<ui64>, TPoolAllocator>;
+ using TCandidate = std::pair<float, ui64>;
+ using TCandidates = TVector<TCandidate>;
+
+ private:
+ TFastRng64 Rng{0x1a5d0ac170565c1c, 0x0be7bc27, 0x6235f6f57820aa0d, 0xafdc7fb};
+ TStringBufs Input;
+
+ THolder<TEntrySet> Current;
+
+ TMemoryPool CompoundCountsPool;
+ THolder<TCompoundCounts> CompoundCounts;
+
+ TCandidates Candidates;
+
+ TBuildSettings Settings;
+
+ public:
+ TDictBuilder(const TBuildSettings& s = TBuildSettings())
+ : CompoundCountsPool(8112, TMemoryPool::TLinearGrow::Instance())
+ , Settings(s)
+ {
+ }
+
+ void SetInput(const TStringBufs& in) {
+ Input = in;
+ }
+
+ const TBuildSettings& GetSettings() const {
+ return Settings;
+ }
+
+ TBuildSettings& GetSettings() {
+ return Settings;
+ }
+
+ void SetSettings(const TBuildSettings& s) {
+ Settings = s;
+ }
+
+ TEntrySet& EntrySet() {
+ return *Current;
+ }
+
+ const TEntrySet& EntrySet() const {
+ return *Current;
+ }
+
+ THolder<TEntrySet> ReleaseEntrySet() {
+ return std::move(Current);
+ }
+
+ ui32 /*iters*/ Build(ui32 maxentries, ui32 maxiters = 16, ui32 mindiff = 10);
+
+ public:
+ void RebuildCounts(ui32 maxcand, bool final);
+ ui32 /*diff size*/ BuildNextGeneration(ui32 maxent);
+
+ static bool IsCompound(ui64 ent) {
+ return ent & 0xFFFFFFFF00000000ULL;
+ }
+
+ static ui32 Next(ui64 ent) {
+ return ent;
+ }
+ static ui32 Prev(ui64 ent) {
+ return (ent >> 32) - 1;
+ }
+
+ static ui64 Compose(ui32 prev, ui32 next) {
+ return ((prev + 1ULL) << 32) | next;
+ }
+ };
+
+}
diff --git a/library/cpp/codecs/greedy_dict/gd_entry.cpp b/library/cpp/codecs/greedy_dict/gd_entry.cpp
new file mode 100644
index 0000000000..2c315c7f7c
--- /dev/null
+++ b/library/cpp/codecs/greedy_dict/gd_entry.cpp
@@ -0,0 +1,98 @@
+#include "gd_entry.h"
+#include "gd_stats.h"
+
+#include <util/generic/algorithm.h>
+#include <util/generic/singleton.h>
+
+namespace NGreedyDict {
+ class TAlphas {
+ char Memory[512];
+
+ public:
+ TStringBufs Alphas;
+
+ TAlphas() {
+ for (ui32 i = 0; i < 256; ++i) {
+ Memory[2 * i] = (char)i;
+ Memory[2 * i + 1] = 0;
+
+ Alphas.push_back(TStringBuf(&Memory[2 * i], 1));
+ }
+ }
+ };
+
+ void TEntrySet::InitWithAlpha() {
+ Pool.ClearKeepFirstChunk();
+ const TStringBufs& a = Singleton<TAlphas>()->Alphas;
+ for (auto it : a) {
+ Add(it);
+ }
+ BuildHierarchy();
+ }
+
+ void TEntrySet::BuildHierarchy() {
+ Sort(begin(), end(), TEntry::StrLess);
+
+ TCompactTrieBuilder<char, ui32, TAsIsPacker<ui32>> builder(CTBF_PREFIX_GROUPED);
+
+ for (iterator it = begin(); it != end(); ++it) {
+ it->Number = (it - begin());
+ TStringBuf suff = it->Str;
+ size_t len = 0;
+ ui32 val = 0;
+
+ if (builder.FindLongestPrefix(suff.data(), suff.size(), &len, &val) && len) {
+ it->NearestPrefix = val;
+ }
+
+ builder.Add(suff.data(), suff.size(), it->Number);
+ }
+
+ TBufferOutput bout;
+ builder.Save(bout);
+ Trie.Init(TBlob::FromBuffer(bout.Buffer()));
+ }
+
+ TEntry* TEntrySet::FindPrefix(TStringBuf& str) {
+ size_t len = 0;
+ ui32 off = 0;
+
+ if (!Trie.FindLongestPrefix(str, &len, &off)) {
+ return nullptr;
+ }
+
+ str.Skip(len);
+ return &Get(off);
+ }
+
+ void TEntrySet::SetModelP() {
+ for (iterator it = begin(); it != end(); ++it) {
+ TEntry& e = *it;
+
+ if (!e.HasPrefix()) {
+ e.ModelP = 0;
+ continue;
+ }
+
+ TStringBuf suff = e.Str;
+ const TEntry& p = Get(e.NearestPrefix);
+ suff.Skip(p.Len());
+
+ float modelp = float(p.Count + e.Count) / TotalCount;
+
+ while (!!suff) {
+ TEntry* pp = FindPrefix(suff);
+ modelp *= float(pp->Count + e.Count) / TotalCount;
+ }
+
+ e.ModelP = modelp;
+ }
+ }
+
+ void TEntrySet::SetScores(EEntryScore s) {
+ for (auto& it : *this) {
+ it.Score = Score(s, it.Len(), it.ModelP, it.Count, TotalCount);
+ }
+ }
+
+}
diff --git a/library/cpp/codecs/greedy_dict/gd_entry.h b/library/cpp/codecs/greedy_dict/gd_entry.h
new file mode 100644
index 0000000000..18b5be0e15
--- /dev/null
+++ b/library/cpp/codecs/greedy_dict/gd_entry.h
@@ -0,0 +1,103 @@
+#pragma once
+
+#include "gd_stats.h"
+
+#include <library/cpp/containers/comptrie/comptrie.h>
+
+#include <util/generic/ptr.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/vector.h>
+
+#include <util/memory/pool.h>
+
+namespace NGreedyDict {
+ using TStringBufs = TVector<TStringBuf>;
+
+ struct TEntry {
+ static const i32 NoPrefix = -1;
+
+ TStringBuf Str;
+
+ i32 NearestPrefix = NoPrefix;
+ ui32 Count = 0;
+ ui32 Number = 0;
+ float ModelP = 0;
+ float Score = 0;
+
+ TEntry(TStringBuf b = TStringBuf(), ui32 cnt = 0)
+ : Str(b)
+ , Count(cnt)
+ {
+ }
+
+ bool HasPrefix() const {
+ return NearestPrefix != NoPrefix;
+ }
+ ui32 Len() const {
+ return Str.size();
+ }
+
+ static bool StrLess(const TEntry& a, const TEntry& b) {
+ return a.Str < b.Str;
+ }
+ static bool NumberLess(const TEntry& a, const TEntry& b) {
+ return a.Number < b.Number;
+ }
+ static bool ScoreMore(const TEntry& a, const TEntry& b) {
+ return a.Score > b.Score;
+ }
+ };
+
+ class TEntrySet: public TVector<TEntry>, TNonCopyable {
+ TMemoryPool Pool{8112};
+ TCompactTrie<char, ui32, TAsIsPacker<ui32>> Trie;
+
+ public:
+ ui32 TotalCount = 0;
+
+ void InitWithAlpha();
+
+ void Add(TStringBuf a) {
+ push_back(TStringBuf(Pool.Append(a.data(), a.size()), a.size()));
+ }
+
+ void Add(TStringBuf a, TStringBuf b) {
+ size_t sz = a.size() + b.size();
+ char* p = (char*)Pool.Allocate(sz);
+ memcpy(p, a.data(), a.size());
+ memcpy(p + a.size(), b.data(), b.size());
+ push_back(TStringBuf(p, sz));
+ }
+
+ TEntry& Get(ui32 idx) {
+ return (*this)[idx];
+ }
+
+ const TEntry& Get(ui32 idx) const {
+ return (*this)[idx];
+ }
+
+ void BuildHierarchy();
+
+ // longest prefix
+ TEntry* FindPrefix(TStringBuf& str);
+
+ const TEntry* FindPrefix(TStringBuf& str) const {
+ return ((TEntrySet*)this)->FindPrefix(str);
+ }
+
+ const TEntry* FirstPrefix(const TEntry& e, TStringBuf& suff) {
+ if (!e.HasPrefix())
+ return nullptr;
+
+ const TEntry& p = Get(e.NearestPrefix);
+ suff = e.Str;
+ suff.Skip(p.Str.size());
+ return &p;
+ }
+
+ void SetModelP();
+ void SetScores(EEntryScore);
+ };
+
+}
diff --git a/library/cpp/codecs/greedy_dict/gd_stats.h b/library/cpp/codecs/greedy_dict/gd_stats.h
new file mode 100644
index 0000000000..b63c4c38d2
--- /dev/null
+++ b/library/cpp/codecs/greedy_dict/gd_stats.h
@@ -0,0 +1,79 @@
+#pragma once
+
+#include <util/generic/ymath.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/yexception.h>
+
+namespace NGreedyDict {
+ enum EEntryScore {
+ ES_COUNT,
+ ES_LEN_COUNT,
+ ES_SIMPLE,
+ ES_LEN_SIMPLE,
+ ES_SOLAR
+ };
+
+ enum EEntryStatTest {
+ EST_NONE = 0,
+ EST_SIMPLE_NORM = 2
+ };
+
+ inline float ModelP(ui32 countA, ui32 countB, ui32 total) {
+ return float(countA) * countB / total / total;
+ }
+
+ // P (ab | dependent)
+ inline float SimpleTest(float modelp, ui32 countAB, ui32 total) {
+ float realp = float(countAB) / total;
+ return modelp >= realp ? 0 : (realp - modelp);
+ }
+
+ inline float SolarTest(float modelp, ui32 countAB, ui32 total) {
+ float realp = float(countAB) / total;
+ return modelp >= realp ? 0 : (modelp + realp * (log(realp / modelp) - 1));
+ }
+
+ // P (ab | dependent) / P (ab)
+ inline float SimpleTestNorm(float modelp, ui32 countAB, ui32 total) {
+ float realp = float(countAB) / total;
+ return modelp >= realp ? 0 : (realp - modelp) / realp;
+ }
+
+ inline float StatTest(EEntryStatTest test, float modelp, ui32 countAB, ui32 total) {
+ if (!total) {
+ return 0;
+ }
+ switch (test) {
+ case EST_NONE:
+ return 1;
+ case EST_SIMPLE_NORM:
+ return SimpleTestNorm(modelp, countAB, total);
+ }
+ Y_FAIL("no way!");
+ return 0;
+ }
+
+ inline float Score(EEntryScore score, ui32 len, float modelp, ui32 count, ui32 total) {
+ if (!total) {
+ return 0;
+ }
+ ui32 m = 1;
+ switch (score) {
+ case ES_LEN_COUNT:
+ m = len;
+ [[fallthrough]];
+ case ES_COUNT:
+ return m * count;
+ case ES_LEN_SIMPLE:
+ m = len;
+ [[fallthrough]];
+ case ES_SIMPLE:
+ return m * SimpleTest(modelp, count, total);
+ case ES_SOLAR:
+ return SolarTest(modelp, count, total);
+ }
+ Y_FAIL("no way!");
+ return 0;
+ }
+
+}
diff --git a/library/cpp/codecs/greedy_dict/ut/greedy_dict_ut.cpp b/library/cpp/codecs/greedy_dict/ut/greedy_dict_ut.cpp
new file mode 100644
index 0000000000..679089a11b
--- /dev/null
+++ b/library/cpp/codecs/greedy_dict/ut/greedy_dict_ut.cpp
@@ -0,0 +1,282 @@
+#include "gd_builder.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h>
+#include <util/string/printf.h>
+#include <util/generic/ymath.h>
+
+class TGreedyDictTest: public TTestBase {
+ UNIT_TEST_SUITE(TGreedyDictTest);
+ UNIT_TEST(TestEntrySet)
+ UNIT_TEST(TestBuilder0)
+ UNIT_TEST(TestBuilder)
+ UNIT_TEST_SUITE_END();
+
+ void TestEntrySet() {
+ using namespace NGreedyDict;
+
+ {
+ TEntrySet d;
+
+ d.InitWithAlpha();
+
+ for (TEntrySet::const_iterator it = d.begin(); it != d.end(); ++it) {
+ UNIT_ASSERT_C(!it->HasPrefix(), Sprintf("%u -> %u", it->Number, it->NearestPrefix));
+ UNIT_ASSERT_VALUES_EQUAL(it->Number, (ui32)(it - d.begin()));
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(d.size(), 256u);
+ TStringBuf s = "aaabbb";
+ UNIT_ASSERT_VALUES_EQUAL(d.FindPrefix(s)->Str, "a");
+ UNIT_ASSERT_VALUES_EQUAL(s, "aabbb");
+ UNIT_ASSERT_VALUES_EQUAL(d.FindPrefix(s)->Str, "a");
+ UNIT_ASSERT_VALUES_EQUAL(s, "abbb");
+ UNIT_ASSERT_VALUES_EQUAL(d.FindPrefix(s)->Str, "a");
+ UNIT_ASSERT_VALUES_EQUAL(s, "bbb");
+ UNIT_ASSERT_VALUES_EQUAL(d.FindPrefix(s)->Str, "b");
+ UNIT_ASSERT_VALUES_EQUAL(s, "bb");
+ UNIT_ASSERT_VALUES_EQUAL(d.FindPrefix(s)->Str, "b");
+ UNIT_ASSERT_VALUES_EQUAL(s, "b");
+ UNIT_ASSERT_VALUES_EQUAL(d.FindPrefix(s)->Str, "b");
+ UNIT_ASSERT_VALUES_EQUAL(s, "");
+ s = TStringBuf("", 1);
+ UNIT_ASSERT_VALUES_EQUAL(d.FindPrefix(s)->Str, TStringBuf("", 1));
+ UNIT_ASSERT_VALUES_EQUAL(s, "");
+ s = "\xFF";
+ UNIT_ASSERT_VALUES_EQUAL(d.FindPrefix(s)->Str, "\xFF");
+ UNIT_ASSERT_VALUES_EQUAL(s, "");
+ }
+ {
+ TEntrySet d;
+ d.Add("a");
+ d.Add("b");
+ d.Add("b", "a");
+ d.BuildHierarchy();
+
+ UNIT_ASSERT_VALUES_EQUAL(d.size(), 3u);
+
+ TStringBuf s = "bab";
+ UNIT_ASSERT_VALUES_EQUAL(d.FindPrefix(s)->Str, "ba");
+ UNIT_ASSERT_VALUES_EQUAL(s, "b");
+ }
+ {
+ TEntrySet d;
+
+ d.Add("a");
+ d.Add("aa");
+ d.Add("aaa");
+ d.Add("aab");
+ d.Add("b");
+ d.Add("ba");
+
+ d.BuildHierarchy();
+
+ UNIT_ASSERT_VALUES_EQUAL(d.size(), 6u);
+ {
+ TStringBuf s = "aaaaa";
+ const TEntry* e = d.FindPrefix(s);
+ UNIT_ASSERT_VALUES_EQUAL(e->Str, "aaa");
+ UNIT_ASSERT_VALUES_EQUAL(e->Number, 2u);
+ UNIT_ASSERT_VALUES_EQUAL(e->NearestPrefix, 1);
+ UNIT_ASSERT_VALUES_EQUAL(s, "aa");
+ }
+
+ {
+ TStringBuf s = "a";
+ const TEntry* e = d.FindPrefix(s);
+ UNIT_ASSERT_VALUES_EQUAL(e->Str, "a");
+ UNIT_ASSERT_VALUES_EQUAL(e->Number, 0u);
+ UNIT_ASSERT_VALUES_EQUAL(e->NearestPrefix, -1);
+ UNIT_ASSERT_VALUES_EQUAL(s, "");
+ }
+
+ {
+ TStringBuf s = "bab";
+ const TEntry* e = d.FindPrefix(s);
+ UNIT_ASSERT_VALUES_EQUAL(e->Str, "ba");
+ UNIT_ASSERT_VALUES_EQUAL(e->Number, 5u);
+ UNIT_ASSERT_VALUES_EQUAL(e->NearestPrefix, 4);
+ UNIT_ASSERT_VALUES_EQUAL(s, "b");
+ }
+
+ {
+ TStringBuf s = "bba";
+ const TEntry* e = d.FindPrefix(s);
+ UNIT_ASSERT_VALUES_EQUAL(e->Str, "b");
+ UNIT_ASSERT_VALUES_EQUAL(e->Number, 4u);
+ UNIT_ASSERT_VALUES_EQUAL(e->NearestPrefix, -1);
+ UNIT_ASSERT_VALUES_EQUAL(s, "ba");
+ }
+ }
+ }
+
+ void TestBuilder0() {
+ using namespace NGreedyDict;
+ ui32 a = 1, b = 11;
+ ui64 ab = TDictBuilder::Compose(a, b);
+ UNIT_ASSERT(TDictBuilder::IsCompound(ab));
+ UNIT_ASSERT_VALUES_EQUAL(TDictBuilder::Prev(ab), a);
+ UNIT_ASSERT_VALUES_EQUAL(TDictBuilder::Next(ab), b);
+ }
+
+ void FillData(NGreedyDict::TStringBufs& data) {
+ static const char* urls[] = {"http://53.ru/car/motors/foreign/opel/tigra/", "http://abakan.24au.ru/tender/85904/", "http://anm15.gulaig.com/", "http://avto-parts.com/mercedes-benz/mercedes-benz-w220-1998-2005/category-442/category-443/", "http://ballooncousin.co.uk/", "http://benzol.ru/equipment/?id=1211&parent=514", "http://blazingseorank.com/blazing-seo-rank-free-website-analysis-to-increase-rank-and-traffic-450.html", "http://blogblaugrana.contadorwebmasters.com/", "http://bristolhash.org.uk/bh3cntct.php", "http://broker.borovichi.ru/category/item/3/1/0/8/28/257", "http://canoncompactcamerax.blogspot.com/", "http://classifieds.smashits.com/p,107881,email-to-friend.htm", "http://conferences.ksde.org/Portals/132/FallAssessment/SAVETHEDAY-FA09.pdf", "http://eway.vn/raovat/325-dien-tu-gia-dung/337-dieu-hoa/98041-b1-sua-may-lanh-quan-binh-tan-sua-may-lanh-quan-binh-chanh-hh-979676119-toan-quoc.html", "http://gallery.e2bn.org/asset73204_8-.html", "http://goplay.nsw.gov.au/activities-for-kids/by/historic-houses-trust/?startdate=2012-07-10", "http://grichards19067.multiply.com/", "http://hotkovo.egent.ru/user/89262269084/", "http://howimetyourself.com/?redirect_to=http://gomiso.com/m/suits/seasons/2/episodes/2", "http://islamqa.com/hi/ref/9014/DEAD%20PEOPLE%20GOOD%20DEEDS", "http://lapras.rutube.ru/", "http://nceluiko.ya.ru/", "http://nyanyanyanyaa.beon.ru/", "http://ozbo.com/Leaf-River-DV-7SS-7-0-MP-Game-Camera-K1-32541.html", "http://sbantom.ru/catalog/chasy/632753.html", "http://shopingoff.com/index.php?option=com_virtuemart&Itemid=65&category_id=&page=shop.browse&manufacturer_id=122&limit=32&limitstart=96", "http://shopingoff.com/katalog-odezhdy/manufacturer/62-christian-audigier.html?limit=32&start=448", "https://webwinkel.ah.nl/process?fh_location=//ecommerce/nl_NL/categories%3C%7Becommerce_shoc1%7D/it_show_product_code_1384%3E%7B10%3B20%7D/pr_startdate%3C20120519/pr_enddate%3E20120519/pr_ltc_allowed%3E%7Bbowi%7D/categories%3C%7Becommerce_shoc1_1al%7D/categories%3C%7Becommerce_shoc1_1al_1ahal%7D&&action=albert_noscript.modules.build", "http://top100.rambler.ru/navi/?theme=208/210/371&rgn=17", "http://volgogradskaya-oblast.extra-m.ru/classifieds/rabota/vakansii/banki-investicii/901467/", "http://wikien4.appspot.com/wiki/Warburg_hypothesis", "http://wola_baranowska.kamerzysta24.com.pl/", "http://www.10dot0dot0dot1.com/", "http://www.anima-redux.ru/index.php?key=gifts+teenage+girls", "http://www.aquaticabyseaworld.com/Calendar.aspx/CP/CP/CP/sp-us/CP/CP/ParkMap/Tickets/Weather.aspx", "http://www.autousa.com/360spin/2012_cadillac_ctssportwagon_3.6awdpremiumcollection.htm", "http://www.booking.com/city/gb/paignton-aireborough.html?inac=0&lang=pl", "http://www.booking.com/city/it/vodo-cadore.en.html", "http://www.booking.com/district/us/new-york/rockefeller-center.html&lang=no", "http://www.booking.com/hotel/bg/crown-fort-club.lv.html", "http://www.booking.com/hotel/ca/gouverneur-rimouski.ar.html", "http://www.booking.com/hotel/ch/l-auberge-du-chalet-a-gobet.fi.html", "http://www.booking.com/hotel/de/mark-garni.ru.html?aid=337384;label=yandex-hotel-mark-garni-68157-%7Bparam1%7D", "http://www.booking.com/hotel/de/mercure-goldschmieding-castrop-rauxel.ro.html", "http://www.booking.com/hotel/de/zollenspieker-fahrhaus.fr.html", "http://www.booking.com/hotel/es/jardin-metropolitano.ca.html", "http://www.booking.com/hotel/fr/clim.fr.html", "http://www.booking.com/hotel/fr/radisson-sas-toulouse-airport.et.html", "http://www.booking.com/hotel/gb/stgileshotel.ro.html?srfid=68c7fe42a03653a8796c84435c5299e4X16?tab=4", "http://www.booking.com/hotel/gr/rodos-park-suites.ru.html", "http://www.booking.com/hotel/id/le-grande-suites-bali.ru.html", "http://www.booking.com/hotel/it/mozart.it.html?aid=321655", "http://www.booking.com/hotel/ni/bahia-del-sol-villas.ru.html?dcid=1;dva=0", "http://www.booking.com/hotel/nl/cpschiphol.ro.html.ro.html?tab=4", "http://www.booking.com/hotel/th/laem-din.en-gb.html", "http://www.booking.com/hotel/th/tinidee-ranong.en.html", "http://www.booking.com/hotel/us/best-western-plus-merrimack-valley.hu.html", "http://www.booking.com/hotel/vn/tan-hai-long.km.html", "http://www.booking.com/landmark/au/royal-brisbane-women-s-hospital.vi.html", "http://www.booking.com/landmark/hk/nam-cheong-station.html&lang=id", "http://www.booking.com/landmark/it/spanish-steps.ca.html", "http://www.booking.com/landmark/sg/asian-civilisations-museum.html&lang=fi", "http://www.booking.com/place/fi-1376029.pt.html", "http://www.booking.com/place/tn257337.pl.html", "http://www.booking.com/region/ca/niagarafalls.ar.html&selected_currency=PLN", "http://www.booking.com/region/mx/queretaro.pt-pt.html&selected_currency=AUD", "http://www.booking.com/searchresults.en.html?city=20063074", "http://www.booking.com/searchresults.et.html?checkin=;checkout=;city=-394632", "http://www.booking.com/searchresults.lv.html?region=3936", "http://www.cevredanismanlari.com/index.php/component/k2/index.php/mevzuat/genel-yazlar/item/dosyalar/index.php?option=com_k2&view=item&id=16:iso-14001-%C3%A7evre-y%C3%B6netim-sistemi&Itemid=132&limitstart=107120", "http://www.dh-wholesaler.com/MENS-POLO-RACING-TEE-RL-p-417.html", "http://www.employabilityonline.net/", "http://www.esso.inc.ru/board/tools.php?event=profile&pname=Invinerrq", "http://www.filesurgery.ru/searchfw/kids_clothes-3.html", "http://www.furnitureandcarpetsource.com/Item.aspx?ItemID=-2107311899&ItemNum=53-T3048", "http://www.gets.cn/product/Gold-Sand-Lampwork-Glass-Beads--Flat-round--28x28x13mm_p260717.html", "http://www.gets.cn/wholesale-Sterling-Silver-Pendant-Findings-3577_S--L-Star-P-1.html?view=1&by=1", "http://www.homeandgardenadvice.com/diy/Mortgages_Loans_and_Financing/9221.html", "http://www.hongkongairport.com/eng/index.html/passenger/passenger/transport/to-from-airport/business/about-the-airport/transport/shopping/entertainment/t2/passenger/interactive-map.html", "http://www.hongkongairport.com/eng/index.html/shopping/insideshopping/all/passenger/transfer-transit/all/airline-information/shopping/entertainment/t2/business/about-the-airport/welcome.html", "http://www.hongkongairport.com/eng/index.html/transport/business/about-the-airport/transport/business/airport-authority/passenger/shopping/dining/all/dining.html", "http://www.idedge.com/index.cfm/fuseaction/category.display/category_id/298/index.cfm", "http://www.istanbulburda.com/aramalar.php", "http://www.jewelryinthenet.com/ads/AdDetail.aspx?AdID=1-0311002490689&stid=22-0111001020877", "http://www.johnnydepp.ru/forum/index.php?showtopic=1629&mode=linearplus&view=findpost&p=186977", "http://www.johnnydepp.ru/forum/index.php?showtopic=476&st=60&p=87379&", "http://www.joseleano.com/joomla/index.php/audio", "http://www.kaplicarehberi.com/tag/sakar-ilicali-kaplicalari/feed", "http://www.khaber.com.tr/arama.html?key=%C3%A7avdar", "http://www.kiz-oyunlari1.com/1783/4437/4363/1056/4170/Bump-Copter2-.html", "http://www.kiz-oyunlari1.com/3752/2612/4175/1166/3649/1047/Angelina-Oyunu.html", "http://www.kiz-oyunlari1.com/4266/3630/3665/3286/4121/301/3274/Sinir-Sinekler-.html", "http://www.kuldiga.lv/index.php?f=8&cat=371", "http://www.kuldiga.lv/index.php/img/index.php?l=lv&art_id=1836&show_c=&cat=85", "http://www.patronessa.ru/remontiruemsya/kuzovnie30raboti.html", "http://www.rapdict.org/Nu_Money?title=Talk:Nu_Money&action=edit", "http://www.serafin-phu.tabor24.com/?page=8", "http://www.shoes-store.org/brand1/Kids/Minnetonka.html", "http://www.shoes-store.org/shoes-store.xml", "http://www.way2allah.com/khotab-download-34695.htm"};
+ data.clear();
+ data.insert(data.begin(), urls, urls + Y_ARRAY_SIZE(urls));
+ }
+
+ typedef THashMap<TStringBuf, NGreedyDict::TEntry> TDict;
+
+ TAutoPtr<NGreedyDict::TEntrySet> DoTestBuilder(const NGreedyDict::TBuildSettings& s,
+ TDict& res) {
+ using namespace NGreedyDict;
+
+ TStringBufs data;
+ FillData(data);
+
+ TDictBuilder b(s);
+ b.SetInput(data);
+ b.Build(256 + 128);
+
+ TEntrySet& set = b.EntrySet();
+
+ for (const auto& it : set) {
+ if (it.Score) {
+ res[it.Str] = it;
+ }
+ }
+
+ return b.ReleaseEntrySet();
+ }
+
+ void DoAssertEntry(TStringBuf entry, ui32 number, i32 parent, float score, const TDict& dict) {
+ TDict::const_iterator it = dict.find(entry);
+ UNIT_ASSERT_C(it != dict.end(), entry);
+ UNIT_ASSERT_VALUES_EQUAL_C(it->second.Number, number, entry);
+ UNIT_ASSERT_VALUES_EQUAL_C(it->second.NearestPrefix, parent, entry);
+ UNIT_ASSERT_VALUES_EQUAL_C(round(it->second.Score * 10000), round(score * 10000), entry);
+ }
+
+ void TestBuilder() {
+ TAutoPtr<NGreedyDict::TEntrySet> set;
+ THashMap<TStringBuf, NGreedyDict::TEntry> res;
+ NGreedyDict::TBuildSettings s;
+ set = DoTestBuilder(s, res);
+
+ UNIT_ASSERT_VALUES_EQUAL(set->size(), 295u);
+ UNIT_ASSERT_VALUES_EQUAL(res.size(), 110u);
+
+ DoAssertEntry("%", 37, -1, 0.00375193, res);
+ DoAssertEntry("%7", 38, 37, 0.00513299, res);
+ DoAssertEntry("&", 39, -1, 0.00794527, res);
+ DoAssertEntry("+", 44, -1, 0.000441404, res);
+ DoAssertEntry(",", 45, -1, 0.000441404, res);
+ DoAssertEntry("-", 46, -1, 0.0417126, res);
+ DoAssertEntry(".", 47, -1, 0.0196425, res);
+ DoAssertEntry(".com/", 48, 47, 0.0374482, res);
+ DoAssertEntry(".html", 49, 47, 0.0496577, res);
+ DoAssertEntry(".html?", 50, 49, 0.0153908, res);
+ DoAssertEntry(".php", 51, 47, 0.0123585, res);
+ DoAssertEntry(".ru/", 52, 47, 0.0150027, res);
+ DoAssertEntry("/", 53, -1, 0.0452439, res);
+ DoAssertEntry("/index", 54, 53, 0.0158905, res);
+ DoAssertEntry("0", 55, -1, 0.00816597, res);
+ DoAssertEntry("1", 56, -1, 0.0167733, res);
+ DoAssertEntry("10", 57, 56, 0.00530474, res);
+ DoAssertEntry("2", 58, -1, 0.0101523, res);
+ DoAssertEntry("20", 59, 58, 0.00674234, res);
+ DoAssertEntry("3", 60, -1, 0.01258, res);
+ DoAssertEntry("32", 61, 60, 0.00490697, res);
+ DoAssertEntry("4", 62, -1, 0.00993158, res);
+ DoAssertEntry("5", 63, -1, 0.00617965, res);
+ DoAssertEntry("6", 64, -1, 0.00971088, res);
+ DoAssertEntry("7", 65, -1, 0.0101523, res);
+ DoAssertEntry("8", 66, -1, 0.00728316, res);
+ DoAssertEntry("9", 67, -1, 0.00728316, res);
+ DoAssertEntry(":", 68, -1, 0.000662106, res);
+ DoAssertEntry(";", 69, -1, 0.000882807, res);
+ DoAssertEntry("=", 71, -1, 0.01258, res);
+ DoAssertEntry("?", 73, -1, 0.00397263, res);
+ DoAssertEntry("A", 75, -1, 0.00264842, res);
+ DoAssertEntry("B", 76, -1, 0.00220702, res);
+ DoAssertEntry("C", 77, -1, 0.00353123, res);
+ DoAssertEntry("D", 78, -1, 0.00375193, res);
+ DoAssertEntry("E", 79, -1, 0.00286912, res);
+ DoAssertEntry("F", 80, -1, 0.00110351, res);
+ DoAssertEntry("G", 81, -1, 0.00110351, res);
+ DoAssertEntry("H", 82, -1, 0.000220702, res);
+ DoAssertEntry("I", 83, -1, 0.00198632, res);
+ DoAssertEntry("K", 85, -1, 0.000441404, res);
+ DoAssertEntry("L", 86, -1, 0.00198632, res);
+ DoAssertEntry("M", 87, -1, 0.00154491, res);
+ DoAssertEntry("N", 88, -1, 0.00154491, res);
+ DoAssertEntry("O", 89, -1, 0.00132421, res);
+ DoAssertEntry("P", 90, -1, 0.00308983, res);
+ DoAssertEntry("R", 92, -1, 0.000662106, res);
+ DoAssertEntry("S", 93, -1, 0.00264842, res);
+ DoAssertEntry("T", 94, -1, 0.00110351, res);
+ DoAssertEntry("U", 95, -1, 0.000220702, res);
+ DoAssertEntry("V", 96, -1, 0.000441404, res);
+ DoAssertEntry("W", 97, -1, 0.000441404, res);
+ DoAssertEntry("X", 98, -1, 0.000220702, res);
+ DoAssertEntry("Y", 99, -1, 0.000220702, res);
+ DoAssertEntry("_", 105, -1, 0.00904877, res);
+ DoAssertEntry("a", 107, -1, 0.0505407, res);
+ DoAssertEntry("an", 108, 107, 0.018273, res);
+ DoAssertEntry("ar", 109, 107, 0.0169385, res);
+ DoAssertEntry("b", 110, -1, 0.0156698, res);
+ DoAssertEntry("c", 111, -1, 0.018539, res);
+ DoAssertEntry("cat", 112, 111, 0.00846732, res);
+ DoAssertEntry("ch", 113, 111, 0.00644872, res);
+ DoAssertEntry("com", 114, 111, 0.00724235, res);
+ DoAssertEntry("ct", 115, 111, 0.00605729, res);
+ DoAssertEntry("d", 116, -1, 0.020746, res);
+ DoAssertEntry("di", 117, 116, 0.00730659, res);
+ DoAssertEntry("e", 118, -1, 0.0624586, res);
+ DoAssertEntry("en", 119, 118, 0.0108999, res);
+ DoAssertEntry("ent", 120, 119, 0.00616002, res);
+ DoAssertEntry("f", 121, -1, 0.00860737, res);
+ DoAssertEntry("fi", 122, 121, 0.00423196, res);
+ DoAssertEntry("g", 123, -1, 0.0180975, res);
+ DoAssertEntry("go", 124, 123, 0.00601862, res);
+ DoAssertEntry("h", 125, -1, 0.010373, res);
+ DoAssertEntry("ho", 126, 125, 0.00570298, res);
+ DoAssertEntry("http://", 127, 125, 0.0494372, res);
+ DoAssertEntry("http://www.", 128, 127, 0.0849702, res);
+ DoAssertEntry("http://www.booking.com/", 129, 128, 0.071066, res);
+ DoAssertEntry("http://www.booking.com/hotel/", 130, 129, 0.121607, res);
+ DoAssertEntry("i", 131, -1, 0.0258221, res);
+ DoAssertEntry("id=", 132, 131, 0.00725369, res);
+ DoAssertEntry("im", 133, 131, 0.00373318, res);
+ DoAssertEntry("in", 134, 131, 0.013625, res);
+ DoAssertEntry("ing", 135, 134, 0.00795491, res);
+ DoAssertEntry("ion", 136, 131, 0.00796149, res);
+ DoAssertEntry("it", 137, 131, 0.00953416, res);
+ DoAssertEntry("j", 138, -1, 0.00132421, res);
+ DoAssertEntry("k", 139, -1, 0.0134628, res);
+ DoAssertEntry("l", 140, -1, 0.0381814, res);
+ DoAssertEntry("m", 141, -1, 0.0174354, res);
+ DoAssertEntry("mer", 142, 141, 0.00711846, res);
+ DoAssertEntry("n", 143, -1, 0.0132421, res);
+ DoAssertEntry("o", 144, -1, 0.0302362, res);
+ DoAssertEntry("on", 145, 144, 0.00802271, res);
+ DoAssertEntry("ou", 146, 144, 0.00414545, res);
+ DoAssertEntry("p", 147, -1, 0.0225116, res);
+ DoAssertEntry("port", 148, 147, 0.0123532, res);
+ DoAssertEntry("q", 149, -1, 0.00176561, res);
+ DoAssertEntry("r", 150, -1, 0.0401677, res);
+ DoAssertEntry("ran", 151, 150, 0.00686918, res);
+ DoAssertEntry("s", 152, -1, 0.0487751, res);
+ DoAssertEntry("sho", 153, 152, 0.0113876, res);
+ DoAssertEntry("t", 154, -1, 0.0379607, res);
+ DoAssertEntry("u", 155, -1, 0.0211874, res);
+ DoAssertEntry("v", 156, -1, 0.00595895, res);
+ DoAssertEntry("vi", 157, 156, 0.00480673, res);
+ DoAssertEntry("w", 158, -1, 0.00816597, res);
+ DoAssertEntry("x", 159, -1, 0.00375193, res);
+ DoAssertEntry("y", 160, -1, 0.0130214, res);
+ DoAssertEntry("z", 161, -1, 0.00353123, res);
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TGreedyDictTest);
diff --git a/library/cpp/codecs/greedy_dict/ut/ya.make b/library/cpp/codecs/greedy_dict/ut/ya.make
new file mode 100644
index 0000000000..bd67d1a452
--- /dev/null
+++ b/library/cpp/codecs/greedy_dict/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/codecs/greedy_dict)
+
+OWNER(velavokr)
+
+SRCS(
+ greedy_dict_ut.cpp
+)
+
+END()
diff --git a/library/cpp/codecs/greedy_dict/ya.make b/library/cpp/codecs/greedy_dict/ya.make
new file mode 100644
index 0000000000..2a57224f7e
--- /dev/null
+++ b/library/cpp/codecs/greedy_dict/ya.make
@@ -0,0 +1,15 @@
+OWNER(velavokr)
+
+LIBRARY()
+
+SRCS(
+ gd_builder.cpp
+ gd_entry.cpp
+)
+
+PEERDIR(
+ library/cpp/containers/comptrie
+ library/cpp/string_utils/relaxed_escaper
+)
+
+END()
diff --git a/library/cpp/codecs/huffman_codec.cpp b/library/cpp/codecs/huffman_codec.cpp
new file mode 100644
index 0000000000..650fe7cdfd
--- /dev/null
+++ b/library/cpp/codecs/huffman_codec.cpp
@@ -0,0 +1,592 @@
+#include "huffman_codec.h"
+#include <library/cpp/bit_io/bitinput.h>
+#include <library/cpp/bit_io/bitoutput.h>
+
+#include <util/generic/algorithm.h>
+#include <util/generic/bitops.h>
+#include <util/stream/buffer.h>
+#include <util/stream/length.h>
+#include <util/string/printf.h>
+
+namespace NCodecs {
+ template <typename T>
+ struct TCanonicalCmp {
+ bool operator()(const T& a, const T& b) const {
+ if (a.CodeLength == b.CodeLength) {
+ return a.Char < b.Char;
+ } else {
+ return a.CodeLength < b.CodeLength;
+ }
+ }
+ };
+
+ template <typename T>
+ struct TByCharCmp {
+ bool operator()(const T& a, const T& b) const {
+ return a.Char < b.Char;
+ }
+ };
+
+ struct TTreeEntry {
+ static const ui32 InvalidBranch = (ui32)-1;
+
+ ui64 Freq = 0;
+ ui32 Branches[2]{InvalidBranch, InvalidBranch};
+
+ ui32 CodeLength = 0;
+ ui8 Char = 0;
+ bool Invalid = false;
+
+ TTreeEntry() = default;
+
+ static bool ByFreq(const TTreeEntry& a, const TTreeEntry& b) {
+ return a.Freq < b.Freq;
+ }
+
+ static bool ByFreqRev(const TTreeEntry& a, const TTreeEntry& b) {
+ return a.Freq > b.Freq;
+ }
+ };
+
+ using TCodeTree = TVector<TTreeEntry>;
+
+ void InitTreeByFreqs(TCodeTree& tree, const ui64 freqs[256]) {
+ tree.reserve(255 * 256 / 2); // worst case - balanced tree
+
+ for (ui32 i = 0; i < 256; ++i) {
+ tree.emplace_back();
+ tree.back().Char = i;
+ tree.back().Freq = freqs[i];
+ }
+
+ StableSort(tree.begin(), tree.end(), TTreeEntry::ByFreq);
+ }
+
+ void InitTree(TCodeTree& tree, ISequenceReader* in) {
+ using namespace NPrivate;
+ ui64 freqs[256];
+ Zero(freqs);
+
+ TStringBuf r;
+ while (in->NextRegion(r)) {
+ for (ui64 i = 0; i < r.size(); ++i)
+ ++freqs[(ui8)r[i]];
+ }
+
+ InitTreeByFreqs(tree, freqs);
+ }
+
+ void CalculateCodeLengths(TCodeTree& tree) {
+ Y_ENSURE(tree.size() == 256, " ");
+ const ui32 firstbranch = tree.size();
+
+ ui32 curleaf = 0;
+ ui32 curbranch = firstbranch;
+
+ // building code tree. two priority queues are combined in one.
+ while (firstbranch - curleaf + tree.size() - curbranch >= 2) {
+ TTreeEntry e;
+
+ for (auto& branche : e.Branches) {
+ ui32 br;
+
+ if (curleaf >= firstbranch)
+ br = curbranch++;
+ else if (curbranch >= tree.size())
+ br = curleaf++;
+ else if (tree[curleaf].Freq < tree[curbranch].Freq)
+ br = curleaf++;
+ else
+ br = curbranch++;
+
+ Y_ENSURE(br < tree.size(), " ");
+ branche = br;
+ e.Freq += tree[br].Freq;
+ }
+
+ tree.push_back(e);
+ PushHeap(tree.begin() + curbranch, tree.end(), TTreeEntry::ByFreqRev);
+ }
+
+ // computing code lengths
+ for (ui64 i = tree.size() - 1; i >= firstbranch; --i) {
+ TTreeEntry e = tree[i];
+
+ for (auto branche : e.Branches)
+ tree[branche].CodeLength = e.CodeLength + 1;
+ }
+
+ // chopping off the branches
+ tree.resize(firstbranch);
+
+ Sort(tree.begin(), tree.end(), TCanonicalCmp<TTreeEntry>());
+
+ // simplification: we are stripping codes longer than 64 bits
+ while (!tree.empty() && tree.back().CodeLength > 64)
+ tree.pop_back();
+
+ // will not compress
+ if (tree.empty())
+ return;
+
+ // special invalid code word
+ tree.back().Invalid = true;
+ }
+
+ struct TEncoderEntry {
+ ui64 Code = 0;
+
+ ui8 CodeLength = 0;
+ ui8 Char = 0;
+ ui8 Invalid = true;
+
+ explicit TEncoderEntry(TTreeEntry e)
+ : CodeLength(e.CodeLength)
+ , Char(e.Char)
+ , Invalid(e.Invalid)
+ {
+ }
+
+ TEncoderEntry() = default;
+ };
+
+ struct TEncoderTable {
+ TEncoderEntry Entries[256];
+
+ void Save(IOutputStream* out) const {
+ ui16 nval = 0;
+
+ for (auto entrie : Entries)
+ nval += !entrie.Invalid;
+
+ ::Save(out, nval);
+
+ for (auto entrie : Entries) {
+ if (!entrie.Invalid) {
+ ::Save(out, entrie.Char);
+ ::Save(out, entrie.CodeLength);
+ }
+ }
+ }
+
+ void Load(IInputStream* in) {
+ ui16 nval = 0;
+ ::Load(in, nval);
+
+ for (ui32 i = 0; i < 256; ++i)
+ Entries[i].Char = i;
+
+ for (ui32 i = 0; i < nval; ++i) {
+ ui8 ch = 0;
+ ui8 len = 0;
+ ::Load(in, ch);
+ ::Load(in, len);
+ Entries[ch].CodeLength = len;
+ Entries[ch].Invalid = false;
+ }
+ }
+ };
+
+ struct TDecoderEntry {
+ ui32 NextTable : 10;
+ ui32 Char : 8;
+ ui32 Invalid : 1;
+ ui32 Bad : 1;
+
+ TDecoderEntry()
+ : NextTable()
+ , Char()
+ , Invalid()
+ , Bad()
+ {
+ }
+ };
+
+ struct TDecoderTable: public TIntrusiveListItem<TDecoderTable> {
+ ui64 Length = 0;
+ ui64 BaseCode = 0;
+
+ TDecoderEntry Entries[256];
+
+ TDecoderTable() {
+ Zero(Entries);
+ }
+ };
+
+ const int CACHE_BITS_COUNT = 16;
+ class THuffmanCodec::TImpl: public TAtomicRefCount<TImpl> {
+ TEncoderTable Encoder;
+ TDecoderTable Decoder[256];
+
+ TEncoderEntry Invalid;
+
+ ui32 SubTablesNum;
+
+ class THuffmanCache {
+ struct TCacheEntry {
+ int EndOffset : 24;
+ int BitsLeft : 8;
+ };
+ TVector<char> DecodeCache;
+ TVector<TCacheEntry> CacheEntries;
+ const TImpl& Original;
+
+ public:
+ THuffmanCache(const THuffmanCodec::TImpl& encoder);
+
+ void Decode(NBitIO::TBitInput& in, TBuffer& out) const;
+ };
+
+ THolder<THuffmanCache> Cache;
+
+ public:
+ TImpl()
+ : SubTablesNum(1)
+ {
+ Invalid.CodeLength = 255;
+ }
+
+ ui8 Encode(TStringBuf in, TBuffer& out) const {
+ out.Clear();
+
+ if (in.empty()) {
+ return 0;
+ }
+
+ out.Reserve(in.size() * 2);
+
+ {
+ NBitIO::TBitOutputVector<TBuffer> bout(&out);
+ TStringBuf tin = in;
+
+ // data is under compression
+ bout.Write(1, 1);
+
+ for (auto t : tin) {
+ const TEncoderEntry& ce = Encoder.Entries[(ui8)t];
+
+ bout.Write(ce.Code, ce.CodeLength);
+
+ if (ce.Invalid) {
+ bout.Write(t, 8);
+ }
+ }
+
+ // in canonical huffman coding there cannot be a code having no 0 in the suffix
+ // and shorter than 8 bits.
+ bout.Write((ui64)-1, bout.GetByteReminder());
+ return bout.GetByteReminder();
+ }
+ }
+
+ void Decode(TStringBuf in, TBuffer& out) const {
+ out.Clear();
+
+ if (in.empty()) {
+ return;
+ }
+
+ NBitIO::TBitInput bin(in);
+ ui64 f = 0;
+ bin.ReadK<1>(f);
+
+ // if data is uncompressed
+ if (!f) {
+ in.Skip(1);
+ out.Append(in.data(), in.size());
+ } else {
+ out.Reserve(in.size() * 8);
+
+ if (Cache.Get()) {
+ Cache->Decode(bin, out);
+ } else {
+ while (ReadNextChar(bin, out)) {
+ }
+ }
+ }
+ }
+
+ Y_FORCE_INLINE int ReadNextChar(NBitIO::TBitInput& bin, TBuffer& out) const {
+ const TDecoderTable* table = Decoder;
+ TDecoderEntry e;
+
+ int bitsRead = 0;
+ while (true) {
+ ui64 code = 0;
+
+ if (Y_UNLIKELY(!bin.Read(code, table->Length)))
+ return 0;
+ bitsRead += table->Length;
+
+ if (Y_UNLIKELY(code < table->BaseCode))
+ return 0;
+
+ code -= table->BaseCode;
+
+ if (Y_UNLIKELY(code > 255))
+ return 0;
+
+ e = table->Entries[code];
+
+ if (Y_UNLIKELY(e.Bad))
+ return 0;
+
+ if (e.NextTable) {
+ table = Decoder + e.NextTable;
+ } else {
+ if (e.Invalid) {
+ code = 0;
+ bin.ReadK<8>(code);
+ bitsRead += 8;
+ out.Append((ui8)code);
+ } else {
+ out.Append((ui8)e.Char);
+ }
+
+ return bitsRead;
+ }
+ }
+
+ Y_ENSURE(false, " could not decode input");
+ return 0;
+ }
+
+ void GenerateEncoder(TCodeTree& tree) {
+ const ui64 sz = tree.size();
+
+ TEncoderEntry lastcode = Encoder.Entries[tree[0].Char] = TEncoderEntry(tree[0]);
+
+ for (ui32 i = 1; i < sz; ++i) {
+ const TTreeEntry& te = tree[i];
+ TEncoderEntry& e = Encoder.Entries[te.Char];
+ e = TEncoderEntry(te);
+
+ e.Code = (lastcode.Code + 1) << (e.CodeLength - lastcode.CodeLength);
+ lastcode = e;
+
+ e.Code = ReverseBits(e.Code, e.CodeLength);
+
+ if (e.Invalid)
+ Invalid = e;
+ }
+
+ for (auto& e : Encoder.Entries) {
+ if (e.Invalid)
+ e = Invalid;
+
+ Y_ENSURE(e.CodeLength, " ");
+ }
+ }
+
+ void RegenerateEncoder() {
+ for (auto& entrie : Encoder.Entries) {
+ if (entrie.Invalid)
+ entrie.CodeLength = Invalid.CodeLength;
+ }
+
+ Sort(Encoder.Entries, Encoder.Entries + 256, TCanonicalCmp<TEncoderEntry>());
+
+ TEncoderEntry lastcode = Encoder.Entries[0];
+
+ for (ui32 i = 1; i < 256; ++i) {
+ TEncoderEntry& e = Encoder.Entries[i];
+ e.Code = (lastcode.Code + 1) << (e.CodeLength - lastcode.CodeLength);
+ lastcode = e;
+
+ e.Code = ReverseBits(e.Code, e.CodeLength);
+ }
+
+ for (auto& entrie : Encoder.Entries) {
+ if (entrie.Invalid) {
+ Invalid = entrie;
+ break;
+ }
+ }
+
+ Sort(Encoder.Entries, Encoder.Entries + 256, TByCharCmp<TEncoderEntry>());
+
+ for (auto& entrie : Encoder.Entries) {
+ if (entrie.Invalid)
+ entrie = Invalid;
+ }
+ }
+
+ void BuildDecoder() {
+ TEncoderTable enc = Encoder;
+ Sort(enc.Entries, enc.Entries + 256, TCanonicalCmp<TEncoderEntry>());
+
+ TEncoderEntry& e1 = enc.Entries[0];
+ Decoder[0].BaseCode = e1.Code;
+ Decoder[0].Length = e1.CodeLength;
+
+ for (auto e2 : enc.Entries) {
+ SetEntry(Decoder, e2.Code, e2.CodeLength, e2);
+ }
+ Cache.Reset(new THuffmanCache(*this));
+ }
+
+ void SetEntry(TDecoderTable* t, ui64 code, ui64 len, TEncoderEntry e) {
+ Y_ENSURE(len >= t->Length, len << " < " << t->Length);
+
+ ui64 idx = (code & MaskLowerBits(t->Length)) - t->BaseCode;
+ TDecoderEntry& d = t->Entries[idx];
+
+ if (len == t->Length) {
+ Y_ENSURE(!d.NextTable, " ");
+
+ d.Char = e.Char;
+ d.Invalid = e.Invalid;
+ return;
+ }
+
+ if (!d.NextTable) {
+ Y_ENSURE(SubTablesNum < Y_ARRAY_SIZE(Decoder), " ");
+ d.NextTable = SubTablesNum++;
+ TDecoderTable* nt = Decoder + d.NextTable;
+ nt->Length = Min<ui64>(8, len - t->Length);
+ nt->BaseCode = (code >> t->Length) & MaskLowerBits(nt->Length);
+ }
+
+ SetEntry(Decoder + d.NextTable, code >> t->Length, len - t->Length, e);
+ }
+
+ void Learn(ISequenceReader* in) {
+ {
+ TCodeTree tree;
+ InitTree(tree, in);
+ CalculateCodeLengths(tree);
+ Y_ENSURE(!tree.empty(), " ");
+ GenerateEncoder(tree);
+ }
+ BuildDecoder();
+ }
+
+ void LearnByFreqs(const TArrayRef<std::pair<char, ui64>>& freqs) {
+ TCodeTree tree;
+
+ ui64 freqsArray[256];
+ Zero(freqsArray);
+
+ for (const auto& freq : freqs)
+ freqsArray[static_cast<ui8>(freq.first)] += freq.second;
+
+ InitTreeByFreqs(tree, freqsArray);
+ CalculateCodeLengths(tree);
+
+ Y_ENSURE(!tree.empty(), " ");
+
+ GenerateEncoder(tree);
+ BuildDecoder();
+ }
+
+ void Save(IOutputStream* out) {
+ ::Save(out, Invalid.CodeLength);
+ Encoder.Save(out);
+ }
+
+ void Load(IInputStream* in) {
+ ::Load(in, Invalid.CodeLength);
+ Encoder.Load(in);
+ RegenerateEncoder();
+ BuildDecoder();
+ }
+ };
+
+ THuffmanCodec::TImpl::THuffmanCache::THuffmanCache(const THuffmanCodec::TImpl& codec)
+ : Original(codec)
+ {
+ CacheEntries.resize(1 << CACHE_BITS_COUNT);
+ DecodeCache.reserve(CacheEntries.size() * 2);
+ char buffer[2];
+ TBuffer decoded;
+ for (size_t i = 0; i < CacheEntries.size(); i++) {
+ buffer[1] = i >> 8;
+ buffer[0] = i;
+ NBitIO::TBitInput bin(buffer, buffer + sizeof(buffer));
+ int totalBits = 0;
+ while (true) {
+ decoded.Resize(0);
+ int bits = codec.ReadNextChar(bin, decoded);
+ if (totalBits + bits > 16 || !bits) {
+ TCacheEntry e = {static_cast<int>(DecodeCache.size()), 16 - totalBits};
+ CacheEntries[i] = e;
+ break;
+ }
+
+ for (TBuffer::TConstIterator it = decoded.Begin(); it != decoded.End(); ++it) {
+ DecodeCache.push_back(*it);
+ }
+ totalBits += bits;
+ }
+ }
+ DecodeCache.push_back(0);
+ CacheEntries.shrink_to_fit();
+ DecodeCache.shrink_to_fit();
+ }
+
+ void THuffmanCodec::TImpl::THuffmanCache::Decode(NBitIO::TBitInput& bin, TBuffer& out) const {
+ int bits = 0;
+ ui64 code = 0;
+ while (!bin.Eof()) {
+ ui64 f = 0;
+ const int toRead = 16 - bits;
+ if (toRead > 0 && bin.Read(f, toRead)) {
+ code = (code >> (16 - bits)) | (f << bits);
+ code &= 0xFFFF;
+ TCacheEntry entry = CacheEntries[code];
+ int start = code > 0 ? CacheEntries[code - 1].EndOffset : 0;
+ out.Append((const char*)&DecodeCache[start], (const char*)&DecodeCache[entry.EndOffset]);
+ bits = entry.BitsLeft;
+ } else { // should never happen until there are exceptions or unaligned input
+ bin.Back(bits);
+ if (!Original.ReadNextChar(bin, out))
+ break;
+
+ code = 0;
+ bits = 0;
+ }
+ }
+ }
+
+ THuffmanCodec::THuffmanCodec()
+ : Impl(new TImpl)
+ {
+ MyTraits.NeedsTraining = true;
+ MyTraits.PreservesPrefixGrouping = true;
+ MyTraits.PaddingBit = 1;
+ MyTraits.SizeOnEncodeMultiplier = 2;
+ MyTraits.SizeOnDecodeMultiplier = 8;
+ MyTraits.RecommendedSampleSize = 1 << 21;
+ }
+
+ THuffmanCodec::~THuffmanCodec() = default;
+
+ ui8 THuffmanCodec::Encode(TStringBuf in, TBuffer& bbb) const {
+ if (Y_UNLIKELY(!Trained))
+ ythrow TCodecException() << " not trained";
+
+ return Impl->Encode(in, bbb);
+ }
+
+ void THuffmanCodec::Decode(TStringBuf in, TBuffer& bbb) const {
+ Impl->Decode(in, bbb);
+ }
+
+ void THuffmanCodec::Save(IOutputStream* out) const {
+ Impl->Save(out);
+ }
+
+ void THuffmanCodec::Load(IInputStream* in) {
+ Impl->Load(in);
+ }
+
+ void THuffmanCodec::DoLearn(ISequenceReader& in) {
+ Impl->Learn(&in);
+ }
+
+ void THuffmanCodec::LearnByFreqs(const TArrayRef<std::pair<char, ui64>>& freqs) {
+ Impl->LearnByFreqs(freqs);
+ Trained = true;
+ }
+
+}
diff --git a/library/cpp/codecs/huffman_codec.h b/library/cpp/codecs/huffman_codec.h
new file mode 100644
index 0000000000..559545b90d
--- /dev/null
+++ b/library/cpp/codecs/huffman_codec.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "codecs.h"
+
+#include <util/generic/ptr.h>
+#include <util/string/cast.h>
+
+namespace NCodecs {
+ // for types greater than char, pipeline with TFreqCodec.
+
+ class THuffmanCodec: public ICodec {
+ class TImpl;
+ TIntrusivePtr<TImpl> Impl;
+
+ public:
+ THuffmanCodec();
+ ~THuffmanCodec() override;
+
+ static TStringBuf MyName() {
+ return "huffman";
+ }
+
+ TString GetName() const override {
+ return ToString(MyName());
+ }
+
+ ui8 Encode(TStringBuf in, TBuffer& bbb) const override;
+
+ void Decode(TStringBuf in, TBuffer& bbb) const override;
+
+ void LearnByFreqs(const TArrayRef<std::pair<char, ui64>>& freqs);
+
+ protected:
+ void DoLearn(ISequenceReader& in) override;
+ void Save(IOutputStream* out) const override;
+ void Load(IInputStream* in) override;
+ };
+
+}
diff --git a/library/cpp/codecs/pfor_codec.cpp b/library/cpp/codecs/pfor_codec.cpp
new file mode 100644
index 0000000000..f6b3b0920b
--- /dev/null
+++ b/library/cpp/codecs/pfor_codec.cpp
@@ -0,0 +1,22 @@
+#include "pfor_codec.h"
+
+namespace NCodecs {
+ template <>
+ TStringBuf TPForCodec<ui64, true>::MyName() {
+ return "pfor-delta64-sorted";
+ }
+ template <>
+ TStringBuf TPForCodec<ui32, true>::MyName() {
+ return "pfor-delta32-sorted";
+ }
+
+ template <>
+ TStringBuf TPForCodec<ui64, false>::MyName() {
+ return "pfor-ui64";
+ }
+ template <>
+ TStringBuf TPForCodec<ui32, false>::MyName() {
+ return "pfor-ui32";
+ }
+
+}
diff --git a/library/cpp/codecs/pfor_codec.h b/library/cpp/codecs/pfor_codec.h
new file mode 100644
index 0000000000..d7d4bb8bf4
--- /dev/null
+++ b/library/cpp/codecs/pfor_codec.h
@@ -0,0 +1,211 @@
+#pragma once
+
+#include "codecs.h"
+
+#include "delta_codec.h"
+#include "tls_cache.h"
+
+#include <library/cpp/bit_io/bitinput.h>
+#include <library/cpp/bit_io/bitoutput.h>
+#include <util/string/cast.h>
+
+namespace NCodecs {
+ template <typename T, bool WithDelta = false>
+ class TPForCodec: public ICodec {
+ using TUnsigned = std::make_unsigned_t<T>;
+ typedef TDeltaCodec<TUnsigned> TDCodec;
+
+ typedef std::conditional_t<WithDelta, typename TDCodec::TDelta, T> TValue;
+ static_assert(std::is_unsigned<TValue>::value, "expect std:is_unsigned<TValue>::value");
+
+ static const ui64 BitsInT = sizeof(TUnsigned) * 8;
+
+ TDCodec DeltaCodec;
+
+ public:
+ static TStringBuf MyName();
+
+ TPForCodec() {
+ MyTraits.AssumesStructuredInput = true;
+ MyTraits.SizeOfInputElement = sizeof(T);
+ MyTraits.SizeOnDecodeMultiplier = sizeof(T);
+ }
+
+ TString GetName() const override {
+ return ToString(MyName());
+ }
+
+ ui8 Encode(TStringBuf s, TBuffer& b) const override {
+ b.Clear();
+ if (s.empty()) {
+ return 0;
+ }
+
+ b.Reserve(2 * s.size() + b.Size());
+
+ if (WithDelta) {
+ auto buffer = TBufferTlsCache::TlsInstance().Item();
+ TBuffer& db = buffer.Get();
+ db.Clear();
+ db.Reserve(2 * s.size());
+ DeltaCodec.Encode(s, db);
+ s = TStringBuf{db.data(), db.size()};
+ }
+
+ TArrayRef<const TValue> tin{(const TValue*)s.data(), s.size() / sizeof(TValue)};
+
+ const ui64 sz = tin.size();
+ ui64 bitcounts[BitsInT + 1];
+ Zero(bitcounts);
+
+ ui32 zeros = 0;
+
+ for (const TValue* it = tin.begin(); it != tin.end(); ++it) {
+ TUnsigned v = 1 + (TUnsigned)*it;
+ ui64 l = MostSignificantBit(v) + 1;
+ ++bitcounts[l];
+
+ if (!v) {
+ ++zeros;
+ }
+ }
+
+ // cumulative bit counts
+ for (ui64 i = 0; i < BitsInT; ++i) {
+ bitcounts[i + 1] += bitcounts[i];
+ }
+
+ bool hasexceptions = zeros;
+ ui64 optimalbits = BitsInT;
+
+ {
+ ui64 excsize = 0;
+ ui64 minsize = sz * BitsInT;
+
+ for (ui64 current = BitsInT; current; --current) {
+ ui64 size = bitcounts[current] * current + (sz - bitcounts[current]) * (current + 6 + excsize) + zeros * (current + 6);
+
+ excsize += current * bitcounts[current];
+
+ if (size < minsize) {
+ minsize = size;
+ optimalbits = current;
+ hasexceptions = zeros || sz - bitcounts[current];
+ }
+ }
+ }
+
+ if (!optimalbits || BitsInT == optimalbits) {
+ b.Append((ui8)-1);
+ b.Append(s.data(), s.size());
+ return 0;
+ } else {
+ NBitIO::TBitOutputVector<TBuffer> bout(&b);
+ bout.Write(0, 1);
+ bout.Write(hasexceptions, 1);
+ bout.Write(optimalbits, 6);
+
+ for (const TValue* it = tin.begin(); it != tin.end(); ++it) {
+ TUnsigned word = 1 + (TUnsigned)*it;
+ ui64 len = MostSignificantBit(word) + 1;
+ if (len > optimalbits || !word) {
+ Y_ENSURE(hasexceptions, " ");
+ bout.Write(0, optimalbits);
+ bout.Write(len, 6);
+ bout.Write(word, len);
+ } else {
+ bout.Write(word, optimalbits);
+ }
+ }
+
+ return bout.GetByteReminder();
+ } // the rest of the last byte is zero padded. BitsInT is always > 7.
+ }
+
+ void Decode(TStringBuf s, TBuffer& b) const override {
+ b.Clear();
+ if (s.empty()) {
+ return;
+ }
+
+ b.Reserve(s.size() * sizeof(T) + b.Size());
+
+ ui64 isplain = 0;
+ ui64 hasexceptions = 0;
+ ui64 bits = 0;
+
+ NBitIO::TBitInput bin(s);
+ bin.ReadK<1>(isplain);
+ bin.ReadK<1>(hasexceptions);
+ bin.ReadK<6>(bits);
+
+ if (Y_UNLIKELY(isplain)) {
+ s.Skip(1);
+
+ if (WithDelta) {
+ DeltaCodec.Decode(s, b);
+ } else {
+ b.Append(s.data(), s.size());
+ }
+ } else {
+ typename TDCodec::TDecoder decoder;
+
+ if (hasexceptions) {
+ ui64 word = 0;
+ while (bin.Read(word, bits)) {
+ if (word || (bin.ReadK<6>(word) && bin.Read(word, word))) {
+ --word;
+
+ TValue t = word;
+
+ if (WithDelta) {
+ if (decoder.Decode(t)) {
+ TStringBuf r{(char*)&decoder.Result, sizeof(decoder.Result)};
+ b.Append(r.data(), r.size());
+ }
+ } else {
+ TStringBuf r{(char*)&t, sizeof(t)};
+ b.Append(r.data(), r.size());
+ }
+ }
+ }
+ } else {
+ ui64 word = 0;
+ T outarr[256 / sizeof(T)];
+ ui32 cnt = 0;
+ while (true) {
+ ui64 v = bin.Read(word, bits);
+
+ if ((!v) | (!word))
+ break;
+
+ --word;
+ TValue t = word;
+
+ if (WithDelta) {
+ if (decoder.Decode(t)) {
+ outarr[cnt++] = decoder.Result;
+ }
+ } else {
+ outarr[cnt++] = t;
+ }
+
+ if (cnt == Y_ARRAY_SIZE(outarr)) {
+ b.Append((const char*)outarr, sizeof(outarr));
+ cnt = 0;
+ }
+ }
+
+ if (cnt) {
+ b.Append((const char*)outarr, cnt * sizeof(T));
+ }
+ }
+ }
+ }
+
+ protected:
+ void DoLearn(ISequenceReader&) override {
+ }
+ };
+
+}
diff --git a/library/cpp/codecs/sample.h b/library/cpp/codecs/sample.h
new file mode 100644
index 0000000000..15f03afcc5
--- /dev/null
+++ b/library/cpp/codecs/sample.h
@@ -0,0 +1,89 @@
+#pragma once
+
+#include <library/cpp/deprecated/accessors/accessors.h>
+
+#include <util/generic/buffer.h>
+#include <util/generic/vector.h>
+#include <util/random/fast.h>
+#include <util/random/shuffle.h>
+
+#include <functional>
+#include <type_traits>
+
+namespace NCodecs {
+ class ISequenceReader {
+ public:
+ virtual bool NextRegion(TStringBuf& s) = 0;
+
+ virtual ~ISequenceReader() = default;
+ };
+
+ template <class TValue>
+ TStringBuf ValueToStringBuf(TValue&& t) {
+ return TStringBuf{NAccessors::Begin(t), NAccessors::End(t)};
+ }
+
+ template <class TIter>
+ TStringBuf IterToStringBuf(TIter iter) {
+ return ValueToStringBuf(*iter);
+ }
+
+ template <class TItem>
+ class TSimpleSequenceReader: public ISequenceReader {
+ const TVector<TItem>& Items;
+ size_t Idx = 0;
+
+ public:
+ TSimpleSequenceReader(const TVector<TItem>& items)
+ : Items(items)
+ {
+ }
+
+ bool NextRegion(TStringBuf& s) override {
+ if (Idx >= Items.size()) {
+ return false;
+ }
+
+ s = ValueToStringBuf(Items[Idx++]);
+ return true;
+ }
+ };
+
+ template <class TIter, class TGetter>
+ size_t GetInputSize(TIter begin, TIter end, TGetter getter) {
+ size_t totalBytes = 0;
+ for (TIter iter = begin; iter != end; ++iter) {
+ totalBytes += getter(iter).size();
+ }
+ return totalBytes;
+ }
+
+ template <class TIter>
+ size_t GetInputSize(TIter begin, TIter end) {
+ return GetInputSize(begin, end, IterToStringBuf<TIter>);
+ }
+
+ template <class TIter, class TGetter>
+ TVector<TBuffer> GetSample(TIter begin, TIter end, size_t sampleSizeBytes, TGetter getter) {
+ TFastRng64 rng{0x1ce1f2e507541a05, 0x07d45659, 0x7b8771030dd9917e, 0x2d6636ce};
+
+ size_t totalBytes = GetInputSize(begin, end, getter);
+ double sampleProb = (double)sampleSizeBytes / Max<size_t>(1, totalBytes);
+
+ TVector<TBuffer> result;
+ for (TIter iter = begin; iter != end; ++iter) {
+ if (sampleProb >= 1 || rng.GenRandReal1() < sampleProb) {
+ TStringBuf reg = getter(iter);
+ result.emplace_back(reg.data(), reg.size());
+ }
+ }
+ Shuffle(result.begin(), result.end(), rng);
+ return result;
+ }
+
+ template <class TIter>
+ TVector<TBuffer> GetSample(TIter begin, TIter end, size_t sampleSizeBytes) {
+ return GetSample(begin, end, sampleSizeBytes, IterToStringBuf<TIter>);
+ }
+
+}
diff --git a/library/cpp/codecs/solar_codec.cpp b/library/cpp/codecs/solar_codec.cpp
new file mode 100644
index 0000000000..d0692fe2a4
--- /dev/null
+++ b/library/cpp/codecs/solar_codec.cpp
@@ -0,0 +1,133 @@
+#include "solar_codec.h"
+
+#include <library/cpp/codecs/greedy_dict/gd_builder.h>
+
+#include <library/cpp/containers/comptrie/comptrie_builder.h>
+#include <library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h>
+#include <util/stream/length.h>
+#include <util/string/printf.h>
+#include <util/ysaveload.h>
+
+namespace NCodecs {
+ static inline ui32 Append(TBuffer& pool, TStringBuf data) {
+ pool.Append(data.data(), data.size());
+ return pool.Size();
+ }
+
+ void TSolarCodec::DoLearn(ISequenceReader& r) {
+ using namespace NGreedyDict;
+
+ Decoder.clear();
+ Pool.Clear();
+
+ THolder<TEntrySet> set;
+
+ {
+ TMemoryPool pool(8112, TMemoryPool::TLinearGrow::Instance());
+ TStringBufs bufs;
+
+ TStringBuf m;
+ while (r.NextRegion(m)) {
+ bufs.push_back(pool.AppendString(m));
+ }
+
+ {
+ TDictBuilder b(Settings);
+ b.SetInput(bufs);
+ b.Build(MaxEntries, MaxIterations);
+
+ set = b.ReleaseEntrySet();
+ }
+ }
+
+ set->SetScores(ES_LEN_COUNT);
+
+ {
+ TVector<std::pair<float, TStringBuf>> tmp;
+ tmp.reserve(set->size());
+
+ for (const auto& it : *set) {
+ tmp.push_back(std::make_pair(-it.Score, TStringBuf(it.Str).Trunc(Max<ui32>() / Max<ui32>(MaxEntries, 1))));
+ }
+
+ Sort(tmp.begin(), tmp.end());
+
+ Decoder.reserve(tmp.size() + 1);
+ Decoder.push_back(0);
+
+ for (const auto& it : tmp) {
+ Y_ENSURE(Decoder.back() == Pool.Size(), "learning invariant failed");
+ ui32 endoff = Append(Pool, it.second);
+ Decoder.push_back(endoff);
+ }
+ }
+
+ Pool.ShrinkToFit();
+ Decoder.shrink_to_fit();
+
+ TBufferOutput bout;
+
+ {
+ TVector<std::pair<TStringBuf, ui32>> tmp2;
+ tmp2.reserve(Decoder.size());
+
+ for (ui32 i = 1, sz = Decoder.size(); i < sz; ++i) {
+ TStringBuf s = DoDecode(i);
+ tmp2.push_back(std::make_pair(s, i - 1));
+ Y_ENSURE(s.size() == (Decoder[i] - Decoder[i - 1]), "learning invariant failed");
+ }
+
+ Sort(tmp2.begin(), tmp2.end());
+
+ {
+ TEncoder::TBuilder builder(CTBF_PREFIX_GROUPED);
+ for (const auto& it : tmp2) {
+ builder.Add(it.first.data(), it.first.size(), it.second);
+ }
+
+ builder.Save(bout);
+ }
+ }
+
+ Encoder.Init(TBlob::FromBuffer(bout.Buffer()));
+ }
+
+ void TSolarCodec::Save(IOutputStream* out) const {
+ TBlob b = Encoder.Data();
+ ::Save(out, (ui32)b.Size());
+ out->Write(b.Data(), b.Size());
+ }
+
+ void TSolarCodec::Load(IInputStream* in) {
+ ui32 sz;
+ ::Load(in, sz);
+ TLengthLimitedInput lin(in, sz);
+ Encoder.Init(TBlob::FromStream(lin));
+ Pool.Clear();
+ Decoder.clear();
+
+ TVector<std::pair<ui32, TString>> tmp;
+
+ ui32 poolsz = 0;
+ for (TEncoder::TConstIterator it = Encoder.Begin(); it != Encoder.End(); ++it) {
+ const TString& s = it.GetKey();
+ tmp.push_back(std::make_pair(it.GetValue(), !s ? TString("\0", 1) : s));
+ poolsz += Max<ui32>(s.size(), 1);
+ }
+
+ Sort(tmp.begin(), tmp.end());
+
+ Pool.Reserve(poolsz);
+ Decoder.reserve(tmp.size() + 1);
+ Decoder.push_back(0);
+
+ for (ui32 i = 0, sz2 = tmp.size(); i < sz2; ++i) {
+ Y_ENSURE(i == tmp[i].first, "oops! " << i << " " << tmp[i].first);
+ Decoder.push_back(Append(Pool, tmp[i].second));
+ }
+
+ Pool.ShrinkToFit();
+ Decoder.shrink_to_fit();
+ }
+
+}
diff --git a/library/cpp/codecs/solar_codec.h b/library/cpp/codecs/solar_codec.h
new file mode 100644
index 0000000000..7158ae7926
--- /dev/null
+++ b/library/cpp/codecs/solar_codec.h
@@ -0,0 +1,244 @@
+#pragma once
+
+#include "codecs.h"
+#include <library/cpp/containers/comptrie/comptrie_trie.h>
+#include <library/cpp/codecs/greedy_dict/gd_builder.h>
+
+#include <util/string/cast.h>
+#include <util/string/escape.h>
+
+namespace NCodecs {
+ // TODO: Попробовать добавлять в словарь вместе с намайненными словами также их суффиксы.
+ // TODO: Возможно удастся, не слишком потеряв в сжатии, выиграть в робастности к небольшим изменениям в корпусе.
+
+ struct TVarIntTraits {
+ static const size_t MAX_VARINT32_BYTES = 5;
+
+ static void Write(ui32 value, TBuffer& b) {
+ while (value > 0x7F) {
+ b.Append(static_cast<ui8>(value) | 0x80);
+ value >>= 7;
+ }
+ b.Append(static_cast<ui8>(value) & 0x7F);
+ }
+
+ static void Read(TStringBuf& r, ui32& value) {
+ ui32 result = 0;
+ for (ui32 count = 0; count < MAX_VARINT32_BYTES; ++count) {
+ const ui32 b = static_cast<ui8>(r[0]);
+ r.Skip(1);
+ result |= static_cast<ui32>(b & 0x7F) << (7 * count);
+ if (!(b & 0x80)) {
+ value = result;
+ return;
+ } else if (Y_UNLIKELY(r.empty())) {
+ break;
+ }
+ }
+ Y_ENSURE_EX(false, TCodecException() << "Bad data");
+ }
+ };
+
+ struct TShortIntTraits {
+ static const size_t SHORTINT_SIZE_LIMIT = 0x8000;
+
+ Y_FORCE_INLINE static void Write(ui32 value, TBuffer& b) {
+ Y_ENSURE_EX(value < SHORTINT_SIZE_LIMIT, TCodecException() << "Bad write method");
+ if (value >= 0x80) {
+ b.Append(static_cast<ui8>(value >> 8) | 0x80);
+ }
+ b.Append(static_cast<ui8>(value));
+ }
+
+ Y_FORCE_INLINE static void Read(TStringBuf& r, ui32& value) {
+ ui32 result = static_cast<ui8>(r[0]);
+ r.Skip(1);
+ if (result >= 0x80) {
+ Y_ENSURE_EX(!r.empty(), TCodecException() << "Bad data");
+ result = ((result << 8) & 0x7FFF) | static_cast<ui8>(r[0]);
+ r.Skip(1);
+ }
+ value = result;
+ }
+ };
+
+ class TSolarCodec: public ICodec {
+ public:
+ static TStringBuf MyName8k() {
+ return TStringBuf("solar-8k");
+ }
+ static TStringBuf MyName16k() {
+ return TStringBuf("solar-16k");
+ }
+ static TStringBuf MyName32k() {
+ return TStringBuf("solar-32k");
+ }
+ static TStringBuf MyName64k() {
+ return TStringBuf("solar-64k");
+ }
+ static TStringBuf MyName256k() {
+ return TStringBuf("solar-256k");
+ }
+ static TStringBuf MyName() {
+ return TStringBuf("solar");
+ }
+ static TStringBuf MyName8kAdapt() {
+ return TStringBuf("solar-8k-a");
+ }
+ static TStringBuf MyName16kAdapt() {
+ return TStringBuf("solar-16k-a");
+ }
+ static TStringBuf MyName32kAdapt() {
+ return TStringBuf("solar-32k-a");
+ }
+ static TStringBuf MyName64kAdapt() {
+ return TStringBuf("solar-64k-a");
+ }
+ static TStringBuf MyName256kAdapt() {
+ return TStringBuf("solar-256k-a");
+ }
+ static TStringBuf MyNameShortInt() {
+ return TStringBuf("solar-si");
+ }
+
+ explicit TSolarCodec(ui32 maxentries = 1 << 14, ui32 maxiter = 16, const NGreedyDict::TBuildSettings& s = NGreedyDict::TBuildSettings())
+ : Settings(s)
+ , MaxEntries(maxentries)
+ , MaxIterations(maxiter)
+ {
+ MyTraits.NeedsTraining = true;
+ MyTraits.SizeOnDecodeMultiplier = 2;
+ MyTraits.RecommendedSampleSize = maxentries * s.GrowLimit * maxiter * 8;
+ }
+
+ ui8 /*free bits in last byte*/ Encode(TStringBuf r, TBuffer& b) const override {
+ EncodeImpl<TVarIntTraits>(r, b);
+ return 0;
+ }
+
+ void Decode(TStringBuf r, TBuffer& b) const override {
+ DecodeImpl<TVarIntTraits>(r, b);
+ }
+
+ TString GetName() const override {
+ return ToString(MyName());
+ }
+
+ protected:
+ void DoLearn(ISequenceReader&) override;
+ void Save(IOutputStream*) const override;
+ void Load(IInputStream*) override;
+
+ Y_FORCE_INLINE TStringBuf SubStr(ui32 begoff, ui32 endoff) const {
+ return TStringBuf(Pool.Data() + begoff, endoff - begoff);
+ }
+
+ Y_FORCE_INLINE TStringBuf DoDecode(ui32 num) const {
+ return SubStr(Decoder[num - 1], Decoder[num]);
+ }
+
+ template <class TTraits>
+ Y_FORCE_INLINE void EncodeImpl(TStringBuf r, TBuffer& b) const {
+ b.Clear();
+ b.Reserve(r.size());
+ while (!r.empty()) {
+ size_t sz = 0;
+ ui32 val = (ui32)-1;
+ Encoder.FindLongestPrefix(r, &sz, &val);
+ TTraits::Write(val + 1, b);
+ r.Skip(Max<size_t>(sz, 1));
+ }
+ }
+
+ template <class TTraits>
+ Y_FORCE_INLINE void DecodeImpl(TStringBuf r, TBuffer& b) const {
+ b.Clear();
+ b.Reserve(r.size());
+ ui32 v = 0;
+ while (!r.empty()) {
+ TTraits::Read(r, v);
+ TStringBuf s = DoDecode(v);
+ b.Append(s.data(), s.size());
+ }
+ }
+
+ inline bool CanUseShortInt() const {
+ return Decoder.size() < TShortIntTraits::SHORTINT_SIZE_LIMIT;
+ }
+
+ private:
+ typedef TCompactTrie<char, ui32> TEncoder;
+ typedef TVector<ui32> TDecoder;
+
+ TBuffer Pool;
+ TEncoder Encoder;
+ TDecoder Decoder;
+
+ NGreedyDict::TBuildSettings Settings;
+ ui32 MaxEntries;
+ ui32 MaxIterations;
+ };
+
+ // Uses varints or shortints depending on the decoder size
+ class TAdaptiveSolarCodec: public TSolarCodec {
+ public:
+ explicit TAdaptiveSolarCodec(ui32 maxentries = 1 << 14, ui32 maxiter = 16, const NGreedyDict::TBuildSettings& s = NGreedyDict::TBuildSettings())
+ : TSolarCodec(maxentries, maxiter, s)
+ {
+ }
+
+ ui8 /*free bits in last byte*/ Encode(TStringBuf r, TBuffer& b) const override {
+ if (CanUseShortInt()) {
+ EncodeImpl<TShortIntTraits>(r, b);
+ } else {
+ EncodeImpl<TVarIntTraits>(r, b);
+ }
+
+ return 0;
+ }
+
+ void Decode(TStringBuf r, TBuffer& b) const override {
+ if (CanUseShortInt()) {
+ DecodeImpl<TShortIntTraits>(r, b);
+ } else {
+ DecodeImpl<TVarIntTraits>(r, b);
+ }
+ }
+
+ TString GetName() const override {
+ if (CanUseShortInt()) {
+ return ToString(MyNameShortInt());
+ } else {
+ return ToString(MyName());
+ }
+ }
+ };
+
+ class TSolarCodecShortInt: public TSolarCodec {
+ public:
+ explicit TSolarCodecShortInt(ui32 maxentries = 1 << 14, ui32 maxiter = 16, const NGreedyDict::TBuildSettings& s = NGreedyDict::TBuildSettings())
+ : TSolarCodec(maxentries, maxiter, s)
+ {
+ }
+
+ ui8 /*free bits in last byte*/ Encode(TStringBuf r, TBuffer& b) const override {
+ EncodeImpl<TShortIntTraits>(r, b);
+ return 0;
+ }
+
+ void Decode(TStringBuf r, TBuffer& b) const override {
+ DecodeImpl<TShortIntTraits>(r, b);
+ }
+
+ TString GetName() const override {
+ return ToString(MyNameShortInt());
+ }
+
+ protected:
+ void Load(IInputStream* in) override {
+ TSolarCodec::Load(in);
+ Y_ENSURE_EX(CanUseShortInt(), TCodecException() << "Bad data");
+ }
+ };
+
+}
diff --git a/library/cpp/codecs/static/README b/library/cpp/codecs/static/README
new file mode 100644
index 0000000000..1b07f02433
--- /dev/null
+++ b/library/cpp/codecs/static/README
@@ -0,0 +1 @@
+Support of static libraries in library/cpp/codecs. See library/cpp/codecs/static/example.
diff --git a/library/cpp/codecs/static/builder.cpp b/library/cpp/codecs/static/builder.cpp
new file mode 100644
index 0000000000..93e34a3edb
--- /dev/null
+++ b/library/cpp/codecs/static/builder.cpp
@@ -0,0 +1,39 @@
+#include "builder.h"
+#include "common.h"
+
+#include <library/cpp/codecs/static/static_codec_info.pb.h>
+
+#include <library/cpp/codecs/codecs.h>
+
+#include <util/generic/yexception.h>
+#include <util/string/subst.h>
+
+namespace NCodecs {
+ TStaticCodecInfo BuildStaticCodec(const TVector<TString>& trainingData, const TCodecBuildInfo& info) {
+ TStaticCodecInfo result;
+ TCodecPtr codec = ICodec::GetInstance(info.CodecName);
+ Y_ENSURE_EX(codec, TCodecException() << "empty codec is not allowed");
+
+ codec->LearnX(trainingData.begin(), trainingData.end(), info.SampleSizeMultiplier);
+ {
+ TStringOutput sout{*result.MutableStoredCodec()};
+ ICodec::Store(&sout, codec);
+ }
+
+ auto& debugInfo = *result.MutableDebugInfo();
+ debugInfo.SetStoredCodecHash(DataSignature(result.GetStoredCodec()));
+ debugInfo.SetCodecName(info.CodecName);
+ debugInfo.SetSampleSizeMultiplier(info.SampleSizeMultiplier);
+ debugInfo.SetTimestamp(info.Timestamp);
+ debugInfo.SetRevisionInfo(info.RevisionInfo);
+ debugInfo.SetTrainingSetComment(info.TrainingSetComment);
+ debugInfo.SetTrainingSetResId(info.TrainingSetResId);
+ return result;
+ }
+
+ TString GetStandardFileName(const TStaticCodecInfo& info) {
+ TString cName = info.GetDebugInfo().GetCodecName();
+ SubstGlobal(cName, ':', '.');
+ return TStringBuilder() << cName << "." << info.GetDebugInfo().GetTimestamp() << ".codec_info";
+ }
+}
diff --git a/library/cpp/codecs/static/builder.h b/library/cpp/codecs/static/builder.h
new file mode 100644
index 0000000000..d7533be4d5
--- /dev/null
+++ b/library/cpp/codecs/static/builder.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "static.h"
+
+#include <library/cpp/svnversion/svnversion.h>
+
+#include <util/datetime/base.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/string/builder.h>
+
+namespace NCodecs {
+ struct TCodecBuildInfo {
+ // optimal values from SEARCH-1655
+ TString CodecName = "solar-8k-a:zstd08d-1";
+ float SampleSizeMultiplier = 1;
+
+ // debug info:
+ time_t Timestamp = TInstant::Now().TimeT();
+ TString RevisionInfo = (TStringBuilder() << "r" << ToString(GetProgramSvnRevision()));
+ TString TrainingSetComment; // a human comment on the training data
+ TString TrainingSetResId; // sandbox resid of the training set
+ };
+
+ TStaticCodecInfo BuildStaticCodec(const TVector<TString>& trainingData, const TCodecBuildInfo&);
+
+ TString GetStandardFileName(const TStaticCodecInfo&);
+
+}
diff --git a/library/cpp/codecs/static/common.h b/library/cpp/codecs/static/common.h
new file mode 100644
index 0000000000..211de2a27d
--- /dev/null
+++ b/library/cpp/codecs/static/common.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <util/string/hex.h>
+#include <util/digest/city.h>
+#include <util/system/byteorder.h>
+
+namespace NCodecs {
+ template <class T>
+ ui64 DataSignature(const T& t) {
+ static_assert(!std::is_scalar<T>::value, "no scalars");
+ return CityHash64(t.data(), t.size());
+ }
+
+ template <class T>
+ TString HexWriteScalar(T t) {
+ static_assert(std::is_scalar<T>::value, "scalars only");
+ t = LittleToBig(t);
+ TString res = HexEncode(&t, sizeof(t));
+ res.to_lower();
+ return res;
+ }
+
+ template <class T>
+ T HexReadScalar(TStringBuf s) {
+ static_assert(std::is_scalar<T>::value, "scalars only");
+ T t = 0;
+ HexDecode(s.data(), Min(s.size(), sizeof(T)), &t);
+ t = BigToLittle(t);
+ return t;
+ }
+
+}
diff --git a/library/cpp/codecs/static/example/example.cpp b/library/cpp/codecs/static/example/example.cpp
new file mode 100644
index 0000000000..5b750b717e
--- /dev/null
+++ b/library/cpp/codecs/static/example/example.cpp
@@ -0,0 +1,43 @@
+#include "example.h"
+
+#include <library/cpp/codecs/static/static.h>
+
+#include <util/generic/yexception.h>
+
+extern "C" {
+extern const ui8 codec_info_huff_20160707[];
+extern const ui32 codec_info_huff_20160707Size;
+extern const ui8 codec_info_sa_huff_20160707[];
+extern const ui32 codec_info_sa_huff_20160707Size;
+};
+
+namespace NStaticCodecExample {
+ static const NCodecs::TCodecConstPtr CODECS[] = {
+ nullptr,
+ NCodecs::RestoreCodecFromArchive(codec_info_huff_20160707, codec_info_huff_20160707Size),
+ NCodecs::RestoreCodecFromArchive(codec_info_sa_huff_20160707, codec_info_sa_huff_20160707Size),
+ };
+
+ static_assert(Y_ARRAY_SIZE(CODECS) == DV_COUNT, "bad array size");
+
+ void Encode(TBuffer& out, TStringBuf in, EDictVersion dv) {
+ Y_ENSURE(dv > DV_NULL && dv < DV_COUNT, "invalid dict version: " << (int)dv);
+ out.Clear();
+ if (!in) {
+ return;
+ }
+ CODECS[dv]->Encode(in, out);
+ out.Append((char)dv);
+ }
+
+ void Decode(TBuffer& out, TStringBuf in) {
+ out.Clear();
+ if (!in) {
+ return;
+ }
+ EDictVersion dv = (EDictVersion)in.back();
+ Y_ENSURE(dv > DV_NULL && dv < DV_COUNT, "invalid dict version: " << (int)dv);
+ in.Chop(1);
+ CODECS[dv]->Decode(in, out);
+ }
+}
diff --git a/library/cpp/codecs/static/example/example.h b/library/cpp/codecs/static/example/example.h
new file mode 100644
index 0000000000..f9b3a7324b
--- /dev/null
+++ b/library/cpp/codecs/static/example/example.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+#include <util/generic/buffer.h>
+
+namespace NStaticCodecExample {
+ enum EDictVersion : ui8 {
+ DV_NULL = 0,
+ DV_HUFF_20160707,
+ DV_SA_HUFF_20160707,
+ DV_COUNT
+ };
+
+ void Encode(TBuffer&, TStringBuf, EDictVersion dv = DV_SA_HUFF_20160707);
+
+ void Decode(TBuffer&, TStringBuf);
+}
diff --git a/library/cpp/codecs/static/example/huffman.1467494385.codec_info b/library/cpp/codecs/static/example/huffman.1467494385.codec_info
new file mode 100644
index 0000000000..5fc18270a6
--- /dev/null
+++ b/library/cpp/codecs/static/example/huffman.1467494385.codec_info
Binary files differ
diff --git a/library/cpp/codecs/static/example/solar-8k-a.huffman.1467494385.codec_info b/library/cpp/codecs/static/example/solar-8k-a.huffman.1467494385.codec_info
new file mode 100644
index 0000000000..d36d8e24ec
--- /dev/null
+++ b/library/cpp/codecs/static/example/solar-8k-a.huffman.1467494385.codec_info
Binary files differ
diff --git a/library/cpp/codecs/static/example/ya.make b/library/cpp/codecs/static/example/ya.make
new file mode 100644
index 0000000000..ca6c5fd900
--- /dev/null
+++ b/library/cpp/codecs/static/example/ya.make
@@ -0,0 +1,24 @@
+LIBRARY()
+
+OWNER(velavokr)
+
+SRCS(
+ GLOBAL example.cpp
+)
+
+PEERDIR(
+ library/cpp/codecs
+ library/cpp/codecs/static
+)
+
+ARCHIVE_ASM(
+ "solar-8k-a.huffman.1467494385.codec_info"
+ NAME codec_info_sa_huff_20160707
+)
+
+ARCHIVE_ASM(
+ "huffman.1467494385.codec_info"
+ NAME codec_info_huff_20160707
+)
+
+END()
diff --git a/library/cpp/codecs/static/static.cpp b/library/cpp/codecs/static/static.cpp
new file mode 100644
index 0000000000..44a07dd73a
--- /dev/null
+++ b/library/cpp/codecs/static/static.cpp
@@ -0,0 +1,98 @@
+#include "static.h"
+#include "common.h"
+
+#include <library/cpp/codecs/static/static_codec_info.pb.h>
+#include <library/cpp/archive/yarchive.h>
+
+#include <util/draft/datetime.h>
+
+#include <util/string/builder.h>
+#include <util/stream/buffer.h>
+#include <util/stream/mem.h>
+#include <util/string/hex.h>
+#include <util/ysaveload.h>
+
+namespace NCodecs {
+ static constexpr TStringBuf STATIC_CODEC_INFO_MAGIC = "CodecInf";
+
+ static TStringBuf GetStaticCodecInfoMagic() {
+ return STATIC_CODEC_INFO_MAGIC;
+ }
+
+ void SaveCodecInfoToStream(IOutputStream& out, const TStaticCodecInfo& info) {
+ TBufferOutput bout;
+ info.SerializeToArcadiaStream(&bout);
+ ui64 hash = DataSignature(bout.Buffer());
+ out.Write(GetStaticCodecInfoMagic());
+ ::Save(&out, hash);
+ ::Save(&out, bout.Buffer());
+ }
+
+ TStaticCodecInfo LoadCodecInfoFromStream(IInputStream& in) {
+ {
+ TBuffer magic;
+ magic.Resize(GetStaticCodecInfoMagic().size());
+ Y_ENSURE_EX(in.Read(magic.Data(), GetStaticCodecInfoMagic().size()) == GetStaticCodecInfoMagic().size(),
+ TCodecException() << "bad codec info");
+ Y_ENSURE_EX(TStringBuf(magic.data(), magic.size()) == GetStaticCodecInfoMagic(),
+ TCodecException() << "bad codec info");
+ }
+
+ ui64 hash;
+ ::Load(&in, hash);
+ TBuffer info;
+ ::Load(&in, info);
+ Y_ENSURE_EX(hash == DataSignature(info), TCodecException() << "bad codec info");
+
+ TStaticCodecInfo result;
+ Y_ENSURE_EX(result.ParseFromArray(info.data(), info.size()), TCodecException() << "bad codec info");
+
+ return result;
+ }
+
+ TString SaveCodecInfoToString(const TStaticCodecInfo& info) {
+ TStringStream s;
+ SaveCodecInfoToStream(s, info);
+ return s.Str();
+ }
+
+ TStaticCodecInfo LoadCodecInfoFromString(TStringBuf data) {
+ TMemoryInput m{data.data(), data.size()};
+ return LoadCodecInfoFromStream(m);
+ }
+
+ TString FormatCodecInfo(const TStaticCodecInfo& ci) {
+ TStringBuilder s;
+ s << "codec name: " << ci.GetDebugInfo().GetCodecName() << Endl;
+ s << "codec hash: " << HexWriteScalar(ci.GetDebugInfo().GetStoredCodecHash()) << Endl;
+ s << "dict size: " << ci.GetStoredCodec().Size() << Endl;
+ s << "sample mult: " << ci.GetDebugInfo().GetSampleSizeMultiplier() << Endl;
+ s << "orig.compress: " << ci.GetDebugInfo().GetCompression() * 100 << " %" << Endl;
+ s << "timestamp: " << ci.GetDebugInfo().GetTimestamp() << " ("
+ << NDatetime::TSimpleTM::NewLocal(ci.GetDebugInfo().GetTimestamp()).ToString()
+ << ")" << Endl;
+ s << "revision: " << ci.GetDebugInfo().GetRevisionInfo() << Endl;
+ s << "training set comment: " << ci.GetDebugInfo().GetTrainingSetComment() << Endl;
+ s << "training set resId: " << ci.GetDebugInfo().GetTrainingSetResId() << Endl;
+ return s;
+ }
+
+ TString LoadStringFromArchive(const ui8* begin, size_t size) {
+ TArchiveReader ar(TBlob::NoCopy(begin, size));
+ Y_VERIFY(ar.Count() == 1, "invalid number of entries");
+ auto blob = ar.ObjectBlobByKey(ar.KeyByIndex(0));
+ return TString{blob.AsCharPtr(), blob.Size()};
+ }
+
+ TCodecConstPtr RestoreCodecFromCodecInfo(const TStaticCodecInfo& info) {
+ return NCodecs::ICodec::RestoreFromString(info.GetStoredCodec());
+ }
+
+ TCodecConstPtr RestoreCodecFromArchive(const ui8* begin, size_t size) {
+ const auto& data = LoadStringFromArchive(begin, size);
+ const auto& info = LoadCodecInfoFromString(data);
+ const auto& codec = RestoreCodecFromCodecInfo(info);
+ Y_ENSURE_EX(codec, TCodecException() << "null codec");
+ return codec;
+ }
+}
diff --git a/library/cpp/codecs/static/static.h b/library/cpp/codecs/static/static.h
new file mode 100644
index 0000000000..c1eaed2a74
--- /dev/null
+++ b/library/cpp/codecs/static/static.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <library/cpp/codecs/codecs.h>
+
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+#include <util/stream/output.h>
+
+namespace NCodecs {
+ class TStaticCodecInfo;
+
+ // load
+
+ TCodecConstPtr RestoreCodecFromCodecInfo(const TStaticCodecInfo&);
+
+ TStaticCodecInfo LoadCodecInfoFromString(TStringBuf data);
+
+ TString LoadStringFromArchive(const ui8* begin, size_t size);
+
+ TCodecConstPtr RestoreCodecFromArchive(const ui8* begin, size_t size);
+
+ // save
+
+ TString SaveCodecInfoToString(const TStaticCodecInfo&);
+
+ void SaveCodecInfoToStream(IOutputStream& out, const TStaticCodecInfo&);
+
+ // misc
+
+ TStaticCodecInfo LoadCodecInfoFromStream(IInputStream& in);
+
+ TString FormatCodecInfo(const TStaticCodecInfo&);
+
+}
diff --git a/library/cpp/codecs/static/static_codec_info.proto b/library/cpp/codecs/static/static_codec_info.proto
new file mode 100644
index 0000000000..362abb4dad
--- /dev/null
+++ b/library/cpp/codecs/static/static_codec_info.proto
@@ -0,0 +1,17 @@
+package NCodecs;
+
+message TStaticCodecInfo {
+ message TDebugInfo {
+ optional string CodecName = 1; // the exact codec variant name
+ optional uint64 Timestamp = 2; // when the codec was built
+ optional string RevisionInfo = 3; // the arcadia revision info
+ optional float SampleSizeMultiplier = 4; // how the default sample size was modified to improve compression
+ optional float Compression = 5; // the compression on the training set ((raw_size - coded_size) / raw_size)
+ optional string TrainingSetComment = 6; // a human readable description of the training set
+ optional string TrainingSetResId = 7; // the training set sandbox resource id
+ optional uint64 StoredCodecHash = 8; // cityhash64(data)
+ }
+
+ optional bytes StoredCodec = 1; // the data of the codec
+ optional TDebugInfo DebugInfo = 2; // misc debug info which could be useful in finding whereabouts later
+}
diff --git a/library/cpp/codecs/static/tools/common/ct_common.cpp b/library/cpp/codecs/static/tools/common/ct_common.cpp
new file mode 100644
index 0000000000..fe77691280
--- /dev/null
+++ b/library/cpp/codecs/static/tools/common/ct_common.cpp
@@ -0,0 +1,74 @@
+#include "ct_common.h"
+
+#include <library/cpp/codecs/codecs.h>
+#include <library/cpp/codecs/static/static_codec_info.pb.h>
+#include <library/cpp/string_utils/base64/base64.h>
+
+#include <util/stream/output.h>
+#include <util/string/builder.h>
+#include <util/system/hp_timer.h>
+
+namespace NCodecs {
+ TString TComprStats::Format(const TStaticCodecInfo& info, bool checkMode) const {
+ TStringBuilder s;
+ s << "raw size/item: " << RawSizePerRecord() << Endl;
+ s << "enc.size/item: " << EncSizePerRecord() << Endl;
+ if (checkMode) {
+ s << "orig.enc.size/item: " << OldEncSizePerRecord(info.GetDebugInfo().GetCompression()) << Endl;
+ }
+ s << "enc time us/item: " << EncTimePerRecordUS() << Endl;
+ s << "dec time us/item: " << DecTimePerRecordUS() << Endl;
+ s << "dict size: " << info.GetStoredCodec().Size() << Endl;
+ s << "compression: " << AsPercent(Compression()) << " %" << Endl;
+ if (checkMode) {
+ s << "orig.compression: " << AsPercent(info.GetDebugInfo().GetCompression()) << " %" << Endl;
+ }
+ return s;
+ }
+
+ TComprStats TestCodec(const ICodec& c, const TVector<TString>& input) {
+ TComprStats stats;
+
+ TBuffer encodeBuffer;
+ TBuffer decodeBuffer;
+ for (const auto& data : input) {
+ encodeBuffer.Clear();
+ decodeBuffer.Clear();
+
+ stats.Records += 1;
+ stats.RawSize += data.size();
+
+ THPTimer timer;
+ c.Encode(data, encodeBuffer);
+ stats.EncSize += encodeBuffer.size();
+ stats.EncSeconds += timer.PassedReset();
+
+ c.Decode(TStringBuf{encodeBuffer.data(), encodeBuffer.size()}, decodeBuffer);
+ stats.DecSeconds += timer.PassedReset();
+ Y_ENSURE(data == TStringBuf(decodeBuffer.data(), decodeBuffer.size()), "invalid encoding at record " << stats.Records);
+ }
+
+ return stats;
+ }
+
+ void ParseBlob(TVector<TString>& result, EDataStreamFormat fmt, const TBlob& blob) {
+ TStringBuf bin(blob.AsCharPtr(), blob.Size());
+ TStringBuf line;
+ TString buffer;
+ while (bin.ReadLine(line)) {
+ if (DSF_BASE64_LF == fmt) {
+ Base64Decode(line, buffer);
+ line = buffer;
+ }
+ if (!line) {
+ continue;
+ }
+ result.emplace_back(line.data(), line.size());
+ }
+ }
+
+ TBlob GetInputBlob(const TString& dataFile) {
+ return dataFile && dataFile != "-" ? TBlob::FromFile(dataFile) : TBlob::FromStream(Cin);
+ }
+
+}
diff --git a/library/cpp/codecs/static/tools/common/ct_common.h b/library/cpp/codecs/static/tools/common/ct_common.h
new file mode 100644
index 0000000000..9d3dcbda93
--- /dev/null
+++ b/library/cpp/codecs/static/tools/common/ct_common.h
@@ -0,0 +1,75 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/memory/blob.h>
+#include <cmath>
+
+namespace NCodecs {
+ class TStaticCodecInfo;
+ class ICodec;
+
+ struct TComprStats {
+ double EncSeconds = 0;
+ double DecSeconds = 0;
+ size_t Records = 0;
+ size_t RawSize = 0;
+ size_t EncSize = 0;
+
+ static double Round(double n, size_t decPlaces = 2) {
+ double p = pow(10, decPlaces);
+ return round(n * p) / p;
+ }
+
+ static double AsPercent(double n) {
+ return Round(n * 100);
+ }
+
+ static double AsMicroSecond(double s) {
+ return s * 1000000;
+ }
+
+ double PerRecord(double n) const {
+ return Round((double)(Records ? n / Records : 0));
+ }
+
+ double Compression() const {
+ return ((double)RawSize - (double)EncSize) / RawSize;
+ }
+
+ double EncTimePerRecordUS() const {
+ return PerRecord(AsMicroSecond(EncSeconds));
+ }
+
+ double DecTimePerRecordUS() const {
+ return PerRecord(AsMicroSecond(DecSeconds));
+ }
+
+ double RawSizePerRecord() const {
+ return PerRecord(RawSize);
+ }
+
+ double EncSizePerRecord() const {
+ return PerRecord(EncSize);
+ }
+
+ double OldEncSizePerRecord(double compr) const {
+ return PerRecord((1 - compr) * RawSize);
+ }
+
+ TString Format(const TStaticCodecInfo&, bool checkMode) const;
+ };
+
+ TComprStats TestCodec(const ICodec&, const TVector<TString>& data);
+
+ enum EDataStreamFormat {
+ DSF_NONE,
+ DSF_PLAIN_LF /* "plain" */,
+ DSF_BASE64_LF /* "base64" */,
+ };
+
+ void ParseBlob(TVector<TString>&, EDataStreamFormat, const TBlob&);
+
+ TBlob GetInputBlob(const TString& dataFile);
+
+}
diff --git a/library/cpp/codecs/static/tools/common/ya.make b/library/cpp/codecs/static/tools/common/ya.make
new file mode 100644
index 0000000000..d624222dad
--- /dev/null
+++ b/library/cpp/codecs/static/tools/common/ya.make
@@ -0,0 +1,19 @@
+LIBRARY()
+
+OWNER(velavokr)
+
+SRCS(
+ ct_common.cpp
+)
+
+PEERDIR(
+ library/cpp/codecs
+ library/cpp/codecs/static
+ library/cpp/getopt/small
+ library/cpp/string_utils/base64
+ util/draft
+)
+
+GENERATE_ENUM_SERIALIZATION(ct_common.h)
+
+END()
diff --git a/library/cpp/codecs/static/tools/static_codec_checker/README b/library/cpp/codecs/static/tools/static_codec_checker/README
new file mode 100644
index 0000000000..723a68300b
--- /dev/null
+++ b/library/cpp/codecs/static/tools/static_codec_checker/README
@@ -0,0 +1,4 @@
+This is a viewer for generated codec and utility for verification of the compression quality on a new data.
+
+Usage:
+static_codec_checker -t -c 029b29ff64a74927.codec_info -f plain samples.txt
diff --git a/library/cpp/codecs/static/tools/static_codec_checker/static_codec_checker.cpp b/library/cpp/codecs/static/tools/static_codec_checker/static_codec_checker.cpp
new file mode 100644
index 0000000000..9c8d568d82
--- /dev/null
+++ b/library/cpp/codecs/static/tools/static_codec_checker/static_codec_checker.cpp
@@ -0,0 +1,73 @@
+#include <library/cpp/codecs/static/tools/common/ct_common.h>
+#include <library/cpp/codecs/static/static.h>
+#include <library/cpp/codecs/static/static_codec_info.pb.h>
+#include <library/cpp/codecs/codecs.h>
+#include <library/cpp/getopt/small/last_getopt.h>
+
+#include <util/digest/city.h>
+#include <util/generic/yexception.h>
+#include <util/stream/file.h>
+#include <util/stream/buffer.h>
+#include <util/stream/format.h>
+#include <util/string/builder.h>
+
+int main(int argc, char** argv) {
+ NCodecs::TCodecPtr codecPtr;
+ NCodecs::EDataStreamFormat fmt = NCodecs::DSF_NONE;
+ TString codecFile;
+ bool testCompression = false;
+
+ auto opts = NLastGetopt::TOpts::Default();
+ opts.SetTitle("Prints a .codec_info file and optionally checks its performance on new data. See also static_codec_generator.");
+ opts.SetCmdLineDescr("-c 9089f3e9b7a0f0d4.codec_info -t -f base64 qtrees.sample.txt");
+ NCodecs::TStaticCodecInfo codec;
+
+ opts.AddLongOption('c', "codec-info").RequiredArgument("codec_info").Handler1T<TString>([&codecFile, &codec, &codecPtr](TString name) {
+ codecFile = name;
+ codec.CopyFrom(NCodecs::LoadCodecInfoFromString(TUnbufferedFileInput(name).ReadAll()));
+ codecPtr = NCodecs::ICodec::RestoreFromString(codec.GetStoredCodec());
+ })
+ .Required()
+ .Help(".codec_info file with serialized static data for codec");
+
+ opts.AddLongOption('t', "test").NoArgument().StoreValue(&testCompression, true).Optional().Help("test current performance");
+
+ opts.AddLongOption('f', "format").RequiredArgument(TStringBuilder() << "(" << NCodecs::DSF_PLAIN_LF << "|" << NCodecs::DSF_BASE64_LF << ")").StoreResult(&fmt).Optional().Help("test set input file format");
+
+ opts.SetFreeArgsMin(0);
+ opts.SetFreeArgTitle(0, "testing_set_input_file", "testing set input files");
+
+ NLastGetopt::TOptsParseResult res(&opts, argc, argv);
+
+ Cout << codecFile << Endl;
+ Cout << NCodecs::FormatCodecInfo(codec) << Endl;
+
+ if (testCompression) {
+ if (NCodecs::DSF_NONE == fmt) {
+ Cerr << "Specify format (-f|--format) for testing set input" << Endl;
+ exit(1);
+ }
+
+ Cout << "Reading testing set data ... " << Flush;
+
+ TVector<TString> allData;
+ for (const auto& freeArg : res.GetFreeArgs()) {
+ NCodecs::ParseBlob(allData, fmt, NCodecs::GetInputBlob(freeArg));
+ }
+
+ if (!res.GetFreeArgs()) {
+ NCodecs::ParseBlob(allData, fmt, NCodecs::GetInputBlob("-"));
+ }
+
+ Cout << "Done" << Endl << Endl;
+
+ Cout << "records: " << allData.size() << Endl;
+ Cout << "raw size: " << NCodecs::GetInputSize(allData.begin(), allData.end()) << " bytes" << Endl << Endl;
+
+ Cout << "Testing compression ... " << Flush;
+ auto stats = NCodecs::TestCodec(*codecPtr, allData);
+ Cout << "Done" << Endl << Endl;
+
+ Cout << stats.Format(codec, true) << Endl;
+ }
+}
diff --git a/library/cpp/codecs/static/tools/static_codec_checker/ya.make b/library/cpp/codecs/static/tools/static_codec_checker/ya.make
new file mode 100644
index 0000000000..90e06ca448
--- /dev/null
+++ b/library/cpp/codecs/static/tools/static_codec_checker/ya.make
@@ -0,0 +1,16 @@
+PROGRAM()
+
+OWNER(velavokr)
+
+SRCS(
+ static_codec_checker.cpp
+)
+
+PEERDIR(
+ library/cpp/codecs
+ library/cpp/codecs/static
+ library/cpp/codecs/static/tools/common
+ library/cpp/getopt/small
+)
+
+END()
diff --git a/library/cpp/codecs/static/tools/static_codec_generator/README b/library/cpp/codecs/static/tools/static_codec_generator/README
new file mode 100644
index 0000000000..e6bb52b959
--- /dev/null
+++ b/library/cpp/codecs/static/tools/static_codec_generator/README
@@ -0,0 +1,4 @@
+This is a utility for reproducible teaching of a codec. And also for saving it into a file with a unique name for a static compilation as a resource.
+
+Usage:
+static_codec_generator -t -m 'the training data description' -f plain samples.txt
diff --git a/library/cpp/codecs/static/tools/static_codec_generator/static_codec_generator.cpp b/library/cpp/codecs/static/tools/static_codec_generator/static_codec_generator.cpp
new file mode 100644
index 0000000000..45fdb5c5fe
--- /dev/null
+++ b/library/cpp/codecs/static/tools/static_codec_generator/static_codec_generator.cpp
@@ -0,0 +1,82 @@
+#include <library/cpp/codecs/static/tools/common/ct_common.h>
+#include <library/cpp/codecs/static/static_codec_info.pb.h>
+#include <library/cpp/codecs/static/builder.h>
+#include <library/cpp/codecs/codecs.h>
+
+#include <library/cpp/getopt/small/last_getopt.h>
+
+#include <util/generic/yexception.h>
+#include <util/stream/file.h>
+#include <util/string/builder.h>
+
+int main(int argc, char** argv) {
+ NCodecs::TCodecBuildInfo info;
+ NCodecs::EDataStreamFormat fmt = NCodecs::DSF_NONE;
+
+ auto opts = NLastGetopt::TOpts::Default();
+ opts.SetCmdLineDescr("-m 'Training set: 100000 qtrees taken from web mmeta logs' -f base64 qtrees.sample.txt");
+ opts.SetTitle("Teaches the codec and serializes it as a file named CODECNAME.hash(CODECDATA).bin");
+
+ opts.AddLongOption('m', "message").RequiredArgument("training_set_comment").StoreResult(&info.TrainingSetComment).Required().Help("a human description for the training set");
+
+ opts.AddLongOption('r', "resource").RequiredArgument("training_set_res_id").StoreResult(&info.TrainingSetResId).Optional().Help("sandbox resource id for the training set");
+
+ opts.AddLongOption('c', "codec").RequiredArgument("codec_name").StoreResult(&info.CodecName).Optional().DefaultValue(info.CodecName);
+
+ opts.AddLongOption('s', "sample-multiplier").RequiredArgument("multiplier").StoreResult(&info.SampleSizeMultiplier).Optional().DefaultValue(ToString(info.SampleSizeMultiplier)).Help("multiplier for default sample size");
+
+ opts.AddLongOption('f', "format").RequiredArgument(TStringBuilder() << "(" << NCodecs::DSF_PLAIN_LF << "|" << NCodecs::DSF_BASE64_LF << ")").StoreResult(&fmt).Required().Help("training set input file format");
+
+ opts.AddLongOption("list-codecs").NoArgument().Handler0([]() {
+ Cout << JoinStrings(NCodecs::ICodec::GetCodecsList(), "\n") << Endl;
+ exit(0);
+ })
+ .Optional()
+ .Help("list available codecs");
+
+ opts.AddLongOption("fake-revision").RequiredArgument("revision").StoreResult(&info.RevisionInfo).Optional().Hidden(); // replace static_codec_generator revision in debug info
+
+ opts.AddLongOption("fake-timestamp").RequiredArgument("timestamp").StoreResult(&info.Timestamp).Optional().Hidden(); // replace generating timestamp in debug info
+
+ opts.SetFreeArgsMin(0);
+ opts.SetFreeArgTitle(0, "training_set_input_file", "training set input files");
+
+ NLastGetopt::TOptsParseResult res(&opts, argc, argv);
+
+ Cout << "Reading training set data ... " << Flush;
+ TVector<TString> allData;
+ for (const auto& freeArg : res.GetFreeArgs()) {
+ NCodecs::ParseBlob(allData, fmt, NCodecs::GetInputBlob(freeArg));
+ }
+
+ if (!res.GetFreeArgs()) {
+ NCodecs::ParseBlob(allData, fmt, NCodecs::GetInputBlob("-"));
+ }
+ Cout << "Done" << Endl << Endl;
+
+ Cout << "records: " << allData.size() << Endl;
+ Cout << "raw size: " << NCodecs::GetInputSize(allData.begin(), allData.end()) << " bytes" << Endl << Endl;
+
+ Cout << "Training " << info.CodecName << " , sample size multiplier is " << info.SampleSizeMultiplier << " ... " << Flush;
+ auto codec = NCodecs::BuildStaticCodec(allData, info);
+ Cout << "Done" << Endl;
+
+ TString codecName = NCodecs::GetStandardFileName(codec);
+ NCodecs::TCodecPtr codecPtr = NCodecs::ICodec::RestoreFromString(codec.GetStoredCodec());
+
+ Cout << "Testing compression ... " << Flush;
+ auto stats = NCodecs::TestCodec(*codecPtr, allData);
+ Cout << "Done" << Endl << Endl;
+
+ codec.MutableDebugInfo()->SetCompression(stats.Compression());
+
+ Cout << stats.Format(codec, false) << Endl;
+
+ Cout << "Saving as " << codecName << " ... " << Flush;
+ {
+ TUnbufferedFileOutput fout{codecName};
+ NCodecs::SaveCodecInfoToStream(fout, codec);
+ fout.Finish();
+ }
+ Cout << "Done" << Endl << Endl;
+}
diff --git a/library/cpp/codecs/static/tools/static_codec_generator/ya.make b/library/cpp/codecs/static/tools/static_codec_generator/ya.make
new file mode 100644
index 0000000000..efbc440dd1
--- /dev/null
+++ b/library/cpp/codecs/static/tools/static_codec_generator/ya.make
@@ -0,0 +1,17 @@
+PROGRAM()
+
+OWNER(velavokr)
+
+SRCS(
+ static_codec_generator.cpp
+)
+
+PEERDIR(
+ library/cpp/codecs
+ library/cpp/codecs/static
+ library/cpp/codecs/static/tools/common
+ library/cpp/digest/md5
+ library/cpp/getopt/small
+)
+
+END()
diff --git a/library/cpp/codecs/static/tools/tests/canondata/result.json b/library/cpp/codecs/static/tools/tests/canondata/result.json
new file mode 100644
index 0000000000..7a637c6763
--- /dev/null
+++ b/library/cpp/codecs/static/tools/tests/canondata/result.json
@@ -0,0 +1,6 @@
+{
+ "static_codec_tools.test_static_codec_tools": {
+ "checksum": "960e3c8c57fb846ab53ccbd07e287233",
+ "uri": "sbr://144512644/static_codec_tools.test_static_codec_tools/solar-8k-a.huffman.1467494385.codec_info"
+ }
+} \ No newline at end of file
diff --git a/library/cpp/codecs/static/tools/tests/static_codec_tools.py b/library/cpp/codecs/static/tools/tests/static_codec_tools.py
new file mode 100644
index 0000000000..db4140e370
--- /dev/null
+++ b/library/cpp/codecs/static/tools/tests/static_codec_tools.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+import yatest.common as tt
+import os.path as op
+
+def test_static_codec_tools():
+ tt.execute([tt.binary_path("library/cpp/codecs/static/tools/static_codec_generator/static_codec_generator")]
+ + ["-m", "test codec", "-r", "sbr://143310406", "-f", "plain", "-c", "solar-8k-a:huffman", "-s", "1",
+ "--fake-revision", "r2385905", "--fake-timestamp", "1467494385", "sample.txt"],
+ timeout=60)
+ assert(op.exists("solar-8k-a.huffman.1467494385.codec_info"))
+ tt.canonical_execute(tt.binary_path("library/cpp/codecs/static/tools/static_codec_checker/static_codec_checker"),
+ args=["-c", "solar-8k-a.huffman.1467494385.codec_info"],
+ timeout=60)
+ tt.execute([tt.binary_path("library/cpp/codecs/static/tools/static_codec_checker/static_codec_checker")]
+ + ["-c", "solar-8k-a.huffman.1467494385.codec_info", "-f", "plain", "-t", "sample.txt"],
+ timeout=60)
+ return tt.canonical_file("solar-8k-a.huffman.1467494385.codec_info")
diff --git a/library/cpp/codecs/static/tools/tests/ya.make b/library/cpp/codecs/static/tools/tests/ya.make
new file mode 100644
index 0000000000..c5324eaf53
--- /dev/null
+++ b/library/cpp/codecs/static/tools/tests/ya.make
@@ -0,0 +1,20 @@
+PY2TEST()
+
+OWNER(velavokr)
+
+TEST_SRCS(static_codec_tools.py)
+
+DATA(sbr://143310406)
+
+TIMEOUT(4200)
+
+TAG(ya:not_autocheck)
+
+DEPENDS(
+ library/cpp/codecs/static/tools/static_codec_checker
+ library/cpp/codecs/static/tools/static_codec_generator
+)
+
+
+
+END()
diff --git a/library/cpp/codecs/static/tools/ya.make b/library/cpp/codecs/static/tools/ya.make
new file mode 100644
index 0000000000..dd3e8437aa
--- /dev/null
+++ b/library/cpp/codecs/static/tools/ya.make
@@ -0,0 +1,5 @@
+RECURSE(
+ common
+ static_codec_generator
+ static_codec_checker
+)
diff --git a/library/cpp/codecs/static/ut/builder_ut.cpp b/library/cpp/codecs/static/ut/builder_ut.cpp
new file mode 100644
index 0000000000..b47c279ed1
--- /dev/null
+++ b/library/cpp/codecs/static/ut/builder_ut.cpp
@@ -0,0 +1,57 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/codecs/static/builder.h>
+#include <library/cpp/codecs/static/static_codec_info.pb.h>
+#include <util/string/vector.h>
+
+class TStaticCodecInfoBuilderTest: public NUnitTest::TTestBase {
+ UNIT_TEST_SUITE(TStaticCodecInfoBuilderTest)
+ UNIT_TEST(TestBuild)
+ UNIT_TEST_SUITE_END();
+
+private:
+ TVector<TString> PrepareData() {
+ TVector<TString> data;
+ for (ui32 i = 'a'; i <= 'z'; ++i) {
+ data.push_back(TString(1, (char)i));
+ }
+ return data;
+ }
+
+ void TestBuild() {
+ TVector<TString> data;
+ NCodecs::TCodecBuildInfo info;
+ info.CodecName = "huffman";
+ info.SampleSizeMultiplier = 2;
+ info.Timestamp = 1467494385;
+ info.RevisionInfo = "r2385905";
+ info.TrainingSetComment = "some dummy data";
+ info.TrainingSetResId = "sbr://1234";
+ auto res = NCodecs::BuildStaticCodec(PrepareData(), info);
+ UNIT_ASSERT_VALUES_EQUAL(res.ShortUtf8DebugString(),
+ "StoredCodec: \"\\007\\000huffman@S\\000a"
+ "\\006b\\005c\\005d\\005e\\005f\\005g\\005h\\005i\\005j\\005k\\005l\\005m\\005n\\005o"
+ "\\005p\\005q\\005r\\005s\\005t\\005u\\004v\\004w\\004x\\004y\\004z\\004\xC7?\xC8>"
+ "\xC9=\xCA<\xCB;\xCC:\3159\3168\3177\3206\3215\3224\3233\3242\3251\3260\xD7/\xD8."
+ "\xD9-\xDA,\xDB+\xDC*\xDD)\xDE(\xDF\\'\xE0&\xE1%\xE2$\xE3#\xE4\\\"\xE5!\xE6 \xE7"
+ "\\037\xE8\\036\xE9\\035\xEA\\034\xEB\\033\xEC\\032\xED\\031\xEE\\030\xEF\\027\xF0"
+ "\\026\xF1\\025\xF2\\024\xF3\\023\xF4\\022\xF5\\021\xF6\\020\xF7\\017\xF8\\016\xF9"
+ "\\r\xFA\\014\xFB\\013\xFC\\n\xFD\\t\xFE\\010\xFF\\007\" "
+ "DebugInfo { "
+ "CodecName: \"huffman\" "
+ "Timestamp: 1467494385 "
+ "RevisionInfo: \"r2385905\" "
+ "SampleSizeMultiplier: 2 "
+ "TrainingSetComment: \"some dummy data\" "
+ "TrainingSetResId: \"sbr://1234\" "
+ "StoredCodecHash: 2509195835471488613 "
+ "}");
+
+ UNIT_ASSERT_VALUES_EQUAL(NCodecs::GetStandardFileName(res), "huffman.1467494385.codec_info");
+ UNIT_ASSERT_VALUES_EQUAL(res.GetDebugInfo().GetStoredCodecHash(), 2509195835471488613ULL);
+
+ auto res1 = NCodecs::LoadCodecInfoFromString(NCodecs::SaveCodecInfoToString(res));
+ UNIT_ASSERT_VALUES_EQUAL(res1.ShortUtf8DebugString(), res.ShortUtf8DebugString());
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TStaticCodecInfoBuilderTest);
diff --git a/library/cpp/codecs/static/ut/static_ut.cpp b/library/cpp/codecs/static/ut/static_ut.cpp
new file mode 100644
index 0000000000..57e1e62887
--- /dev/null
+++ b/library/cpp/codecs/static/ut/static_ut.cpp
@@ -0,0 +1,27 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/codecs/static/example/example.h>
+
+class TStaticCodecUsageTest: public NUnitTest::TTestBase {
+ UNIT_TEST_SUITE(TStaticCodecUsageTest)
+ UNIT_TEST(TestUsage)
+ UNIT_TEST_SUITE_END();
+
+private:
+ void DoTestUsage(NStaticCodecExample::EDictVersion dv, size_t expectedSize) {
+ const TStringBuf letov = "Всё идёт по плану";
+
+ TBuffer outEnc, outDec;
+ NStaticCodecExample::Encode(outEnc, letov, dv);
+ NStaticCodecExample::Decode(outDec, TStringBuf{outEnc.data(), outEnc.size()});
+
+ UNIT_ASSERT_VALUES_EQUAL(outEnc.Size(), expectedSize);
+ UNIT_ASSERT_EQUAL(TStringBuf(outDec.data(), outDec.size()), letov);
+ }
+
+ void TestUsage() {
+ DoTestUsage(NStaticCodecExample::DV_HUFF_20160707, 18u);
+ DoTestUsage(NStaticCodecExample::DV_SA_HUFF_20160707, 22u);
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TStaticCodecUsageTest)
diff --git a/library/cpp/codecs/static/ut/ya.make b/library/cpp/codecs/static/ut/ya.make
new file mode 100644
index 0000000000..b9116097d8
--- /dev/null
+++ b/library/cpp/codecs/static/ut/ya.make
@@ -0,0 +1,14 @@
+UNITTEST_FOR(library/cpp/codecs/static)
+
+OWNER(velavokr)
+
+SRCS(
+ builder_ut.cpp
+ static_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/codecs/static/example
+)
+
+END()
diff --git a/library/cpp/codecs/static/ya.make b/library/cpp/codecs/static/ya.make
new file mode 100644
index 0000000000..00e00fd8d4
--- /dev/null
+++ b/library/cpp/codecs/static/ya.make
@@ -0,0 +1,18 @@
+LIBRARY()
+
+OWNER(velavokr)
+
+SRCS(
+ builder.cpp
+ static_codec_info.proto
+ static.cpp
+)
+
+PEERDIR(
+ library/cpp/codecs
+ library/cpp/archive
+ library/cpp/svnversion
+ util/draft
+)
+
+END()
diff --git a/library/cpp/codecs/tls_cache.cpp b/library/cpp/codecs/tls_cache.cpp
new file mode 100644
index 0000000000..0a1b32bda1
--- /dev/null
+++ b/library/cpp/codecs/tls_cache.cpp
@@ -0,0 +1,4 @@
+#include "tls_cache.h"
+
+namespace NCodecs {
+}
diff --git a/library/cpp/codecs/tls_cache.h b/library/cpp/codecs/tls_cache.h
new file mode 100644
index 0000000000..0184e4bb6c
--- /dev/null
+++ b/library/cpp/codecs/tls_cache.h
@@ -0,0 +1,100 @@
+#pragma once
+
+#include <util/generic/buffer.h>
+#include <util/generic/deque.h>
+#include <util/generic/noncopyable.h>
+#include <util/generic/strbuf.h>
+#include <util/system/tls.h>
+#include <util/thread/singleton.h>
+
+namespace NCodecs {
+ template <class TItem>
+ struct TClear {
+ void operator()(TItem& item) const {
+ item.Clear();
+ }
+ };
+
+ template <class TItem, class TCleaner = TClear<TItem>>
+ class TTlsCache {
+ using TSelf = TTlsCache<TItem, TCleaner>;
+
+ struct TItemHolder: public TIntrusiveListItem<TItemHolder> {
+ TItemHolder(TSelf& factory)
+ : Factory(factory)
+ {
+ }
+
+ void Release() {
+ Factory.Release(*this);
+ }
+
+ TSelf& Factory;
+ TItem Item;
+ };
+
+ class TItemGuard {
+ public:
+ explicit TItemGuard(TSelf& fact)
+ : Holder(fact.Acquire())
+ {
+ }
+
+ TItemGuard(TItemGuard&& other) noexcept {
+ *this = std::move(other);
+ }
+
+ TItemGuard& operator=(TItemGuard&& other) noexcept {
+ if (&other != this) {
+ std::swap(Holder, other.Holder);
+ }
+ return *this;
+ }
+
+ ~TItemGuard() {
+ if (Holder) {
+ Holder->Release();
+ }
+ }
+
+ TItem& Get() & {
+ Y_ASSERT(Holder);
+ return Holder->Item;
+ }
+
+ TItem& Get() && = delete;
+
+ private:
+ TItemHolder* Holder = nullptr;
+ };
+
+ public:
+ TItemGuard Item() {
+ return TItemGuard(*this);
+ }
+
+ static TSelf& TlsInstance() {
+ return *FastTlsSingleton<TSelf>();
+ }
+
+ private:
+ TItemHolder* Acquire() {
+ if (Free.Empty()) {
+ return new TItemHolder(*this);
+ } else {
+ return Free.PopBack();
+ }
+ }
+
+ void Release(TItemHolder& item) {
+ Cleaner(item.Item);
+ Free.PushBack(&item);
+ }
+
+ private:
+ TIntrusiveListWithAutoDelete<TItemHolder, TDelete> Free;
+ TCleaner Cleaner;
+ };
+
+ using TBufferTlsCache = TTlsCache<TBuffer>;
+}
diff --git a/library/cpp/codecs/ut/codecs_ut.cpp b/library/cpp/codecs/ut/codecs_ut.cpp
new file mode 100644
index 0000000000..caf6089aef
--- /dev/null
+++ b/library/cpp/codecs/ut/codecs_ut.cpp
@@ -0,0 +1,1360 @@
+#include <library/cpp/codecs/delta_codec.h>
+#include <library/cpp/codecs/huffman_codec.h>
+#include <library/cpp/codecs/pfor_codec.h>
+#include <library/cpp/codecs/solar_codec.h>
+#include <library/cpp/codecs/zstd_dict_codec.h>
+#include <library/cpp/codecs/comptable_codec.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/buffer.h>
+#include <util/string/util.h>
+#include <util/string/hex.h>
+#include <library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h>
+
+namespace {
+ const char* TextValues[] = {
+ "! сентября газета",
+ "!(возмездие это)!",
+ "!(материнский капитал)",
+ "!(пермь березники)",
+ "!биография | !жизнь / + розинг | зворыгин & изобретение | телевидение | электронно лучевая трубка",
+ "!овсиенко николай павлович",
+ "!путин",
+ "\"i'm on you\" p. diddy тимати клип",
+ "\"билайн\" представит собственный планшет",
+ "\"в особо крупном размере\"",
+ "\"викиликс\" джулиан ассанж",
+ "\"вимм билль данн",
+ "\"газэнергосеть астрахань",
+ "\"газэнергосеть астрахань\"",
+ "\"домодедово\" ту-154",
+ "\"жилина\" \"спартак\" видео",
+ "\"зелёнsq шершнm\"",
+ "\"зелёного шершня\"",
+ "\"золотой граммофон\" марины яблоковой",
+ "\"золотой граммофон-2010\"",
+ "\"калинниковы\"",
+ "\"манчестер юнайтед\" (англия) \"валенсия\" (испания) 1:1 (0:1)",
+ "\"маркер\"",
+ "\"моника\" засыпает москву снегом",
+ "\"моника\" снегопад",
+ "\"о безопасности\",",
+ "\"памятку\" для пассажиров воздушных международных рейсов",
+ "\"петровский парк\" и \"ходынское поле\"",
+ "\"путинская\" трава",
+ "\"пятерочка\"купила \"копейку\"",
+ "\"пятёрочка\" и \"копейка\" объединились",
+ "\"реал\" \"осер\" 4:0",
+ "\"речь мутко\"",
+ "\"российский лес 2010\"",
+ "\"ростехинвентаризация федеральное бти\" рубцов",
+ "\"саня останется с нами\",",
+ "\"следопыт\" реалити шоу",
+ "\"слышишь\" молодые авторы",
+ "\"стадион\"",
+ "\"ходынское поле\" метро",
+ "\"хроники нарнии\"",
+ "\"чистая вода\"",
+ "\"школа деда мороза\"",
+ "# asus -1394",
+ "# сторонники wikileaks",
+ "#106#",
+ "#11",
+ "#8 какой цвет",
+ "#если клиент",
+ "$ 13,79",
+ "$ xnj ,s dct ,skb ljdjkmys !!!",
+ "$ в день",
+ "$ диск компьютера",
+ "$.ajax",
+ "$125 000",
+ "$курс",
+ "% в си",
+ "% влады",
+ "% годовых",
+ "% женщин и % мужчин в россии",
+ "% занятости персонала",
+ "% инфляции 2010",
+ "% инфляции в 2010 г.",
+ "% налога",
+ "% налогов в 2010г.",
+ "% общего количества",
+ "% от числа",
+ "% по налогу на прибыль организации",
+ "%24",
+ "%академия%",
+ "%комарова%татьяна",
+ "& в 1с",
+ "&& (+не существует | !такой проблемы)",
+ "&gt;&gt;&gt;скачать | download c cs strikez.clan.su&lt;&lt;&lt;",
+ "&gt;hbq nbityrjd",
+ "&lt; какой знак",
+ "&lt; лицей | &lt; техническая школа# &lt; история#&lt; лицей сегодня#&lt; перечень профессий#&lt; руководство лицея#&lt; прием учащихся#&lt; контакты#&lt; схема проезда#&lt; фотогалереяистория создания лицея и основные этапы путиулица купчинская дом 28",
+ "&lt;&lt;link&gt;&gt;",
+ "&lt;/storage&gt;",
+ "&lt;bfnkjy",
+ "&lt;bktntd",
+ "&lt;cr",
+ "&lt;ddr3&gt;",
+ "&lt;e[ufknthcrbq abyfycjdsq",
+ "&lt;fcctqys",
+ "&lt;fhcf",
+ "&lt;fhctkjyf he,by",
+ "&lt;firbhbz",
+ "&lt;fyr djphj;ltybt",
+ "&lt;fyr vjcrds",
+ "&lt;fyr резерв",
+ "&lt;fyufkjh",
+ "&lt;index&gt;",
+ "&lt;jkmifz jrhe;yfz rbtd",
+ "&lt;kbpytws",
+ "&lt;megafon&gt; интернет",
+ "&lt;thtpybrb gthvcrbq rhfq",
+ "&lt;tkjxrf",
+ "&lt;беларусь это мы",
+ "&lt;бокс, версия ibf",
+ "designer tree svc",
+ "seriesg810",
+ "doll makers",
+ "rotten.com",
+ "evening gowns",
+ "discover",
+ "south carolina escorts",
+ "forkliftjobsinhousron",
+ "mailbox",
+ "alexis",
+ "espn.com mlb",
+ "gypsy.chat.2k",
+ "the man in the mirror",
+ "azteca",
+ "sebastian telfair - jamel thomas",
+ "kirby",
+ "java",
+ "trike motorcycles",
+ "piasecki helicopter",
+ "wicca binding spells",
+ "pier park panama city beach .com",
+ "continente europeo",
+ "asswatchers.com",
+ "asswatchers.com",
+ "easton stealth stiff flex cnt adult baseball bat - 3",
+ "facesofdeath",
+ "video of 9 11",
+ "profileedit.myspace.com",
+ "georgia snakes",
+ "yahoo.com",
+ "google",
+ "http wwwclassicindustries .corvettes-roadsters.com",
+ "arington training stable",
+ "find bred of dog",
+ "southpark contact tables for myspace",
+ "symptoms of laryngitis",
+ "suzuki stickers",
+ "avianca",
+ "radio shack",
+ "dominican republic pictures",
+ "recent",
+ "mapquest",
+ "http myspace .com",
+ "research chemicals supplies",
+ "winn dixie.com",
+ "drivers 20guide.com",
+ "dylan whitley north carolina",
+ "google com",
+ "order wild horses cigarettes",
+ "yahoocom",
+ "fl runners",
+ "aol companion install",
+ "nbc.comdond 59595 6",
+ "directv.com",
+ "motorsports insurance",
+ "cartoonnetwork",
+ "pop warner-victorville",
+ "black iorn spars",
+ "goog",
+ "the suns",
+ "ebay",
+ "pop warner",
+ "philadelphia cream cheese",
+ "oklahoma",
+ "doudleday books.com",
+ "javascript download",
+ "city of nacogdoches",
+ "sfyl",
+ "myspace.com",
+ "baptism pictures",
+ "games",
+ "depredadores sexuales",
+ "mycl.cravelyrics.com",
+ "become a bone marrow donner",
+ "vintage copies",
+ "ford dealership",
+ "candystand",
+ "smarthairypussyom",
+ "yahoo.com",
+ "vanderbilt.edu",
+ "ebay",
+ "grouper",
+ "mys",
+ "myrsa and birth defects",
+ "hatteras rentals",
+ "female escorts",
+ "ja rule",
+ "meat bluesheet",
+ "yahoo",
+ "american disability act court cases",
+ "clearview cinemas",
+ "hard69.com",
+ "make a living will for free",
+ "fat asses",
+ "flashback concert in atlanta ga",
+ "fucking",
+ "flat abdomen exercises",
+ "big brother facial",
+ "german dictionary",
+ "black dick",
+ "ebonymovies",
+ "airsoft rifles",
+ "best fishing days calander",
+ "tattoo",
+ "impressions",
+ "cs.com",
+ "northwest airlines reservations",
+ "halo 3",
+ "wallbaums",
+ "chat room listings",
+ "waterbury ct warrants",
+ "pictures of chad michael murry",
+ "yahoo",
+ "install wallpaper",
+ "halo 3",
+ "clits and tits",
+ "prothsmouth general circuit courts",
+ "old hawthorne columbia",
+ "jess lee photos",
+ "no deposit casino bonus",
+ "bbc gladiator dressed to kill",
+ "anemagazine.com",
+ "lyrics unfaithful",
+ "gold bars found",
+ "art.comhttp",
+ "free unlock key",
+ "man o war lost a race",
+ "blue cross and blue shield",
+ "phenergan",
+ "myspace.com",
+ "http www.constitutional court.com",
+ "monster trucks",
+ "the breeze fort myers fla.newspaper",
+ "davis origin name",
+ "upper deck.com",
+ "arizona",
+ "akira lane",
+ "ebaumsworld",
+ "union pacific jobs",
+ "google.cm",
+ "free bigt girls nudes",
+ "abcnews.com",
+ "tootse.com",
+ "az lyrics",
+ "freddy",
+ "georgia.com",
+ "johncombest.com",
+ "nelly",
+ "gussi mane",
+ "university of illinois",
+ "oregan valcano's",
+ "mythbusters",
+ "sailormoon hentai",
+ "international cub tractor",
+ "desert sky movie green valley az",
+ "evite",
+ "nelly nud epics",
+ "penndot.com",
+ "first banks",
+ "psp manual",
+ "google",
+ "jackieaudet hotmail.com",
+ "internet",
+ "shootinggames",
+ "shootinggames",
+ "montana western rendezvous of art",
+ "hello kitty layouts",
+ "yahoo",
+ "translation",
+ "glenn scott attorney",
+ "hallofshame",
+ "capitolone.com",
+ "recipe for popovers",
+ "pictures of demons",
+ "barnes and nobles.com",
+ "rbd",
+ "hart and hunnington tattoo shop",
+ "janepowellmovies.com",
+ "ged schools in the military",
+ "kelis",
+ "hvacagent",
+ "neat home organizer television show",
+ "2719 24-2-crime and courts",
+ "fsu",
+ "torpedo bomber games",
+ "love poems",
+ "polly pocket'toys",
+ "yweatherahoo.com",
+ "jungle gin",
+ "flemington new jersey real estate",
+ "milf hunter stories",
+ "budget.com",
+ "chopperstyle",
+ "keno player",
+ "up skirt",
+ "dogs",
+ "beerballers",
+ "phat white butt",
+ "phat white butt",
+ "va licensing for interpeters for the deaf",
+ "white page phone book maiden north carolina",
+ "controlled 20solutions 20corp.com",
+ "friedman jewelery",
+ "kelis",
+ "curtains",
+ "curtains",
+ "fuck me harder",
+ "naked girls",
+ "southwest airlines boarding pass",
+ "mailbox",
+ "1976 mavrick",
+ "adult diapers",
+ "horse nasal discharge",
+ "charles ludlam",
+ "google",
+ "himnos en espanol",
+ "quarter horses for sale in nebraska",
+ "cosmo",
+ "hi",
+ "mattel",
+ "aouto 20trader.com",
+ "sunsetter awnings",
+ "bl.cfm",
+ "at",
+ "tattoo designs",
+ "bubs",
+ "yahoo",
+ "free live gay cam chats",
+ "antibiotics",
+ "upgrade",
+ "aessuccess.org",
+ "yahoo",
+ "boobdex",
+ "the jackle",
+ "plus size lingerie magazines for home",
+ "lehigh valley little league",
+ "ancient trade coins",
+ "pillsbury",
+ "colorado springs",
+ "canada aviation jobs",
+ "free guitar tablature",
+ "kids aol",
+ "capitol community colage",
+ "kevin thomas bermuda",
+ "missouri lotto",
+ "homedepotsportscomplex.com",
+ "dr. franklin schneier",
+ "williamsburg va. hotels",
+ "aim",
+ "morningbuzz",
+ "probusines.com",
+ "wwwalbasoul.com",
+ "w.runehints.com",
+ "yahoo.com",
+ "yahoo.com",
+ "yahoo.com",
+ "fantasy 5",
+ "xxx rape",
+ "hawaiian gift baskets",
+ "madonna.com",
+ "myspace contact tables",
+ "white cock",
+ "safe space",
+ "drinks",
+ "o rly",
+ "dsl",
+ "wwww.uncc.edu",
+ "wwww.uncc.edu",
+ "wwww.uncc.edu",
+ "online overseas checkt.westernunion.com",
+ "angina",
+ "heba technologies",
+ "hebrew ancient coins",
+ "games",
+ "recent",
+ "international male.com",
+ "sex pics",
+ "paul wall layouts for myspace",
+ "health",
+ "wire lamp shade frames",
+ "windows",
+ "top business colleges",
+ "mary jo eustace",
+ "attored",
+ "oklahoma indian legal services",
+ "6arab",
+ "santo nino",
+ "10.1.0.199",
+ "http www.myspace.com daffydonn07",
+ "marine electrical",
+ "sandy creek cabins weekend new york",
+ "onionbutts",
+ "tucson classifieds",
+ "new york times",
+ "recently deleted screen names",
+ "goldeneagle.net",
+ "fta support forums",
+ "low protein in bloos",
+ "datring",
+ "lilwayne",
+ "free billiards games",
+ "yahoo",
+ "ako",
+ "a.tribalfusion.c script language",
+ "dustin davis",
+ "cooking",
+ "yahoo.com",
+ "universal studios",
+ "adult chat",
+ "santa monica flea market",
+ "carpevino.us",
+ "wine vinyard in stewertstown pa",
+ "y",
+ "craigslist",
+ "ups.com",
+ "1-866-347-3292",
+ "renegade boats",
+ "renegade boats",
+ "sunset state beach caping",
+ "artofstanlync.org",
+ "heart-i want make love to you video",
+ "triangles around the world",
+ "mycl.cravelyrics.com",
+ "in the bible what type of persons were forced to walk around in public and say unclean unclean",
+ "providence water fire",
+ "googlecom",
+ "yahoo.com",
+ "b.g",
+ "website de rebelde",
+ "stoplinks",
+ "allison 2000 transmission",
+ "thepriceanduseofgasoline.com",
+ "chamillinaire",
+ "veryspecialhomescom",
+ "crashbandicoot",
+ "a short sex story",
+ "yahoo.com",
+ "music now",
+ "east carolina university",
+ "vandalism in new york",
+ "the bainde soleil company",
+ "dicaprio movies",
+ "xxx dvds",
+ "visual basic scripting support",
+ "english bulldogs",
+ "travelocity.com",
+ "website for asstr.org",
+ "hypnotic slave training",
+ "pogo",
+ "university at buffalo addmissions",
+ "screen name services",
+ "superdrol",
+ "art institute",
+ "online business cards",
+ "aolfinancial",
+ "upgrade shop",
+ "anderson abrasive",
+ "weatherchannel.com",
+ "recent",
+ "ebay",
+ "diagram and xray of a normal shouldercheck out surgicalpoker.comfor more sports medicine and orthopedic information and images check out emedx.com by dr. allan mishranormal diagram normal x-ray",
+ "95 mustang gt chips",
+ "gold grills",
+ "hap housing in portland or",
+ "car sales",
+ "swimming with dolphins",
+ "jennifer lopez nude",
+ "wwwdubcnn.com",
+ "dominicks pizza",
+ "fl studio",
+ "http blackplanet .com",
+ "http blackplanet .com",
+ "http blackplanet .com",
+ "A$AP Rocky",
+ "benie mac",
+ "fujifilm.com",
+ "aol dialup setup",
+ "metal fabrication tools",
+ "internet",
+ "buy my painting",
+ "pulaski va classifieds",
+ "w.coj.net",
+ "postopia.com",
+ "no medical records hydrocodone",
+ "auto completes for deal or no deal contest",
+ "http www. big monster dicks .com",
+ "invacare wheelchairs",
+ "musicdownload.com",
+ "president bush",
+ "heavy equipment",
+ "inmate information",
+ "allina.com",
+ "megan law.gov",
+ "wwwl.eharmony.com",
+ "jobs in colombiaoqx0nq",
+ "beastsex",
+ "ferguisson",
+ "heart-i wanna make love to you vedio",
+ "west georgia university",
+ "west georgia university",
+ "hsn",
+ "bb&t",
+ "midas realty",
+ "yahoo",
+ "mytrip.com",
+ "donna texas mcdonalds",
+ "free picture of our lady",
+ "bubs",
+ "taken chemo for 5 month's cancer can still be seen on ct scan",
+ "porn 20video 20clips",
+ "lake monsters",
+ "freedj mix vibes",
+ "myspace.coim",
+ "la joya school district tx",
+ "colorado bungee jumping",
+ "yahoo",
+ "google.com",
+ "lafayette co vampire grave",
+ "ice cube",
+ "internet",
+ "tccd.edu",
+ "google",
+ "people",
+ "instructions on putting together a filing cabinet",
+ "click.babycenter.com",
+ "90minut",
+ "ramien noodles",
+ "lilwayne",
+ "danni virgin",
+ "nice sexy girls.com",
+ "guttural pouch",
+ "free male masturbating",
+ "good",
+ "rotton 20dot.com",
+ "fox sports",
+ "seth rogen",
+ "desb.mspaceads.com",
+ "betjc.com",
+ "pictures of quebec",
+ "gold in quartz",
+ "evergreen college",
+ "runescape",
+ "gastons white river resort",
+ "sunset beach santa cruz",
+ "auto parts",
+ "travelocity",
+ "myspace.com",
+ "laptops",
+ "beyaonce and j",
+ "free gay ebony knights webcams",
+ "google",
+ "derek watson",
+ "alice in wonderland tshirts",
+ "hippa p rivacy act",
+ "down payment mortgage",
+ "believe it or not",
+ "mys",
+ "datatreca",
+ "onesuite",
+ "names",
+ "lil john",
+ "scales of justice cuff links",
+ "localsales.com",
+ "alametris denise lipsey",
+ "adam for adam",
+ "flip flops crochet",
+ "arbors",
+ "heb hospital",
+ "myspae.com",
+ "midevil breast torture",
+ "askjeeves",
+ "assparade",
+ ".comhttp",
+ "weekly hotels reston virginia",
+ "noiceinparadise.com",
+ "pre diabetic diet",
+ "h.i.m.com",
+ "myspace",
+ "myspace",
+ "wwww.sex.lp.cpm",
+ "mcso mugshots",
+ "roush",
+ "wellfargo",
+ "lilwayne",
+ "hopecherie",
+ "frontgate.com",
+ "barbados registration department",
+ "american pitbull",
+ "free pc full flight simulation game downloads",
+ "google",
+ "vaginal secretion grey stuff",
+ "myspace layouts",
+ "kanye west",
+ "walmart",
+ "pain in hip and leg",
+ "tenneesseeaquarium.com",
+ "suncom.com",
+ "alysseandrachelwerehere",
+ "pimiclo",
+ "starmagazine.com",
+ "classifieds",
+ "mount rushmore in dakota",
+ "sams",
+ "disney com",
+ "beastyality",
+ "chief joseph paintings",
+ "henry scott",
+ "paris hilton",
+ "kb903235",
+ "autotrader",
+ "irish traveller",
+ "ajcobs.com",
+ "art of stanlync.org",
+ "fox news",
+ "freeporn",
+ "depo provera",
+ "air france",
+ "talk city active chats",
+ "codes for the gamecube game resident evil 4",
+ "good food to eat for sugar diabetes",
+ "warpmymind",
+ "arc jacksonville fl",
+ "7fwww.sendspace.com",
+ "j blackfoot",
+ "mcso madison street jail inmate",
+ "macys",
+ "eduscapes",
+ "free picture of our lady",
+ "http www.eastman.org",
+ "minneapolisstartribune localnews",
+ "minneapolisstartribune localnews",
+ "tennessee",
+ "foodtown",
+ "anti virous download",
+ "http www.mdland rec.net",
+ "ed edd eddy",
+ "maryjbilge",
+ "shipping services",
+ "baseball videogames",
+ "egyption ancient coins",
+ "internet",
+ "what is sodomy",
+ "international cub lowboy",
+ "mary j. bilge",
+ "scenic backgrounds",
+ "google.com",
+ "rosettalangueges.com",
+ "titanpoker.net",
+ "titie show",
+ "edelen realtor",
+ "lil cim",
+ "china.com",
+ "boost mobile",
+ "nc eipa",
+ "people's 20pharmacy 20guide 20to",
+ "costco",
+ "charles schultz drawings",
+ "nicisterling",
+ "a picture of author stephen crane",
+ "yahoo.com",
+ "sponge bob myspace layouts",
+ "g",
+ "calendar creator",
+ "careerbuilder.com",
+ "cool tex for web pages",
+ "yahoo.com",
+ "mcdougal littel",
+ "sign on",
+ "superman",
+ "radio",
+ "lajollaindians.com",
+ "mike tyson died",
+ "pink panther",
+ "lolita newgroups",
+ "nude girls",
+ "galveston 20texas",
+ "gerlach meat co.",
+ "thetakeover2006.com",
+ "yahoo",
+ "simpsons movie",
+ "saxy",
+ "yahoo",
+ "21st century realty",
+ "new zealand",
+ "dogs",
+ "weather",
+ "free porn sex",
+ "bugs bunny parties",
+ "mortal kombat 2 fatalities",
+ "sea life park hawaii",
+ "songs for middle school choir",
+ "rocky mountain jeep",
+ "householdbank.com",
+ "birdville isd",
+ "brutal dildo",
+ "brutal dildo",
+ "free live gay cam chats",
+ "wonder woman",
+ "ebay com",
+ "myspace.com",
+ "boost mobile",
+ "desktop themes sex",
+ "myspace.com",
+ "myspace.com",
+ "maroon chevy auto dealership",
+ "beyonce",
+ "cleopatra vii",
+ "accountcentralonline.com",
+ "juvenile",
+ "the game cock",
+ "pics of ashland city tennessee",
+ "coherent deos",
+ "microwsoft wireless connection",
+ "best buy",
+ "southwest airlines",
+ "southwest airlines",
+ "pogo games",
+ "family court record room in brooklyn newyork",
+ "60.ufc.net",
+ "us mint",
+ "people",
+ "firstcitycreditunion",
+ "washington mutual careers",
+ "beyonce",
+ "tab energy drink",
+ "http vemmabuilder.com",
+ "new york state lottery",
+ "yahoo",
+ "tmobile",
+ "yellow pages.com",
+ "az.central.com",
+ "pasco auto salvage",
+ "im help",
+ "home based businesses",
+ "studyisland",
+ "bible study from king james on 1 corinthians chapter 6 verses 18- 20",
+ "bellevue-ne",
+ "msn.com",
+ "aolsignupfree",
+ "the simsons",
+ "nevada",
+ "forsyth central high school",
+ "road state college",
+ "does my child have adhd",
+ "les tucanesde tijuana",
+ "yahoo.com",
+ "mexican pharmacy hyrocodone",
+ "ford motor co year end sales",
+ "google.com",
+ "google.com",
+ "person.com",
+ "marylyn monroe",
+ "nfl",
+ "the hun.net",
+ "nkena anderson",
+ "free netscape download",
+ "top fifty colleges",
+ "wil.",
+ "memphis tennessee",
+ "yahoo mail",
+ "corrections officer of juveniles",
+ "jada pinkett smith",
+ "mapquest.com",
+ "apartments",
+ "msn.com",
+ "msn.com",
+ "wasco state prison",
+ "solitaire",
+ "http",
+ "freeport seaman center",
+ "futbol soccer",
+ "screen names",
+ "kmov.com",
+ "survey.otxresearch.com",
+ "facial shaves",
+ "gle",
+ "flw.com",
+ "seasportboats.com",
+ "toysrus.com",
+ "animated sexy graphics",
+ "colombia",
+ "unitarian univeralist association",
+ "fr",
+ "google video.com",
+ "660-342-1072",
+ "suzan-lori parks",
+ "male facial",
+ "william bouguereau first kiss how much it is worth",
+ "streetfighter",
+ "nick.com",
+ "wonder woman",
+ "pentagram",
+ "mcafee virus protection",
+ "diary",
+ "037f34742140a5f761ad51d95180b4f8",
+ "free porn",
+ "no deposit casino bonus",
+ "spongebob the movie myspace layouts",
+ "on line banking",
+ "equestrian properties for sale",
+ "kazaa free muisc download",
+ "gay truckers",
+ "24",
+ "pay-pal",
+ "www yahoo.com",
+ "phatazz.white hoes",
+ "planets of the universe",
+ "free movies",
+ "budget rentals special",
+ "yahoogames",
+ "talaat pasha",
+ "mariah carey song lyrics don't forget about us",
+ "futbol soccer",
+ "msn groups",
+ "martha steward",
+ "martha steward",
+ "soap opera scoops cbs",
+ "cingular",
+ "stuwie",
+ "womengiving blowjobs",
+ "hear dancing queen by abba",
+ "love song",
+ "fhsaa.org",
+ "any dvd",
+ "any dvd",
+ "gallery.brookeskye.com",
+ "gibson ranch",
+ "wachovia com",
+ "kzg golf information",
+ "skylight curtains",
+ "c",
+ "123freeweblayouts.com",
+ "yahoo.com",
+ "allie.com",
+ "ghosts of bingham cemetery",
+ "resume maker",
+ "resume maker",
+ "resume maker",
+ "lymphomatoid papulosis",
+ "sez.com",
+ };
+}
+
+class TCodecsTest: public TTestBase {
+ UNIT_TEST_SUITE(TCodecsTest);
+ UNIT_TEST(TestPipeline)
+ UNIT_TEST(TestDelta)
+ UNIT_TEST(TestHuffman)
+ UNIT_TEST(TestZStdDict)
+ UNIT_TEST(TestCompTable)
+ UNIT_TEST(TestHuffmanLearnByFreqs)
+ UNIT_TEST(TestSolar)
+ UNIT_TEST(TestPFor)
+ UNIT_TEST(TestRegistry)
+
+ UNIT_TEST_SUITE_END();
+
+private:
+ TString PrintError(TStringBuf learn, TStringBuf test, TStringBuf codec, ui32 i) {
+ TString s;
+ TStringOutput sout(s);
+ sout << codec << ": " << i << ", "
+ << "\n";
+ sout << HexEncode(learn.data(), learn.size()); //NEscJ::EscapeJ<true>(learn, sout);
+ sout << " != \n";
+ sout << HexEncode(test.data(), test.size()); //NEscJ::EscapeJ<true>(test, sout);
+
+ if (s.Size() > 1536) {
+ TString res = s.substr(0, 512);
+ res.append("...<skipped ").append(ToString(s.size() - 1024)).append(">...");
+ res.append(s.substr(s.size() - 512));
+ }
+
+ return s;
+ }
+
+ TStringBuf AsStrBuf(const TBuffer& b) {
+ return TStringBuf(b.data(), b.size());
+ }
+
+ template <typename TCodec, bool testsaveload>
+ void TestCodec(const TVector<TBuffer>& inlearn = TVector<TBuffer>(), const TVector<TBuffer>& in = TVector<TBuffer>(), NCodecs::TCodecPtr c = new TCodec) {
+ using namespace NCodecs;
+
+ TBuffer buff;
+
+ {
+ TVector<TBuffer> out;
+
+ c->Learn(inlearn.begin(), inlearn.end());
+
+ if (testsaveload) {
+ {
+ TBufferOutput bout(buff);
+ ICodec::Store(&bout, c);
+ }
+
+ {
+ TBufferInput bin(buff);
+ c = ICodec::Restore(&bin);
+ UNIT_ASSERT(c->AlreadyTrained());
+ }
+ }
+
+ {
+ size_t insz = 0;
+ size_t outsz = buff.Size();
+
+ for (ui32 i = 0; i < inlearn.size(); ++i) {
+ out.emplace_back();
+ c->Encode(AsStrBuf(inlearn[i]), out[i]);
+
+ insz += inlearn[i].Size();
+ outsz += out[i].Size();
+ }
+
+ TBuffer vecl;
+ for (ui32 i = 0; i < out.size(); ++i) {
+ vecl.Clear();
+ c->Decode(AsStrBuf(out[i]), vecl);
+
+ UNIT_ASSERT_EQUAL_C(AsStrBuf(inlearn[i]), AsStrBuf(vecl),
+ PrintError(TStringBuf(inlearn[i].data(), inlearn[i].size()),
+ TStringBuf(vecl.data(), vecl.size()), c->GetName(), i));
+ }
+ }
+ }
+
+ {
+ if (testsaveload) {
+ TBufferInput bin(buff);
+ c = ICodec::Restore(&bin);
+ }
+
+ size_t insz = 0;
+ size_t outsz = buff.Size();
+
+ TBuffer out, in1;
+ for (ui32 i = 0; i < in.size(); ++i) {
+ out.Clear();
+ in1.Clear();
+ c->Encode(AsStrBuf(in[i]), out);
+ insz += in[i].Size();
+ outsz += out.Size();
+ c->Decode(AsStrBuf(out), in1);
+ UNIT_ASSERT_EQUAL_C(AsStrBuf(in[i]), AsStrBuf(in1),
+ PrintError(TStringBuf(in[i].data(), in[i].size()),
+ TStringBuf(in1.data(), in1.size()), c->GetName(), i));
+ }
+ }
+ }
+
+ template <class T>
+ void AppendTo(TBuffer& b, T t) {
+ b.Append((char*)&t, sizeof(t));
+ }
+
+ void TestDelta() {
+ using namespace NCodecs;
+ TVector<TBuffer> d;
+
+ // 1. common case
+ d.emplace_back();
+ AppendTo(d.back(), 1ULL);
+ AppendTo(d.back(), 10ULL);
+ AppendTo(d.back(), 100ULL);
+ AppendTo(d.back(), 1000ULL);
+ AppendTo(d.back(), 10000ULL);
+ AppendTo(d.back(), 100000ULL);
+
+ // 2. delta overflow
+ d.emplace_back();
+ AppendTo(d.back(), 1ULL);
+ AppendTo(d.back(), 10ULL);
+ AppendTo(d.back(), 100ULL);
+ AppendTo(d.back(), 1000ULL);
+ AppendTo(d.back(), (ui64)-100LL);
+ AppendTo(d.back(), (ui64)-10ULL);
+
+ // 3. bad sorting
+ d.emplace_back();
+ AppendTo(d.back(), 1ULL);
+ AppendTo(d.back(), 10ULL);
+ AppendTo(d.back(), 1000ULL);
+ AppendTo(d.back(), 100ULL);
+ AppendTo(d.back(), 10000ULL);
+ AppendTo(d.back(), 100000ULL);
+
+ // all bad
+ d.emplace_back();
+ AppendTo(d.back(), -1LL);
+ AppendTo(d.back(), -1LL);
+ AppendTo(d.back(), -1LL);
+ AppendTo(d.back(), -1LL);
+
+ TestCodec<TDeltaCodec<ui64, true>, false>(d);
+ TestCodec<TDeltaCodec<ui64, false>, false>(d);
+ }
+
+ void TestPFor() {
+ using namespace NCodecs;
+ {
+ TVector<TBuffer> d;
+ d.emplace_back();
+ AppendTo(d.back(), -1LL);
+ AppendTo(d.back(), -1LL);
+ AppendTo(d.back(), -1LL);
+ AppendTo(d.back(), -1LL);
+ d.emplace_back();
+ AppendTo(d.back(), 0LL);
+ AppendTo(d.back(), 1LL);
+ AppendTo(d.back(), 2LL);
+ AppendTo(d.back(), 1LL);
+ AppendTo(d.back(), 0LL);
+ AppendTo(d.back(), 1LL);
+ AppendTo(d.back(), 2LL);
+ d.emplace_back();
+ AppendTo(d.back(), 0LL);
+ AppendTo(d.back(), 1LL);
+ AppendTo(d.back(), 2LL);
+ AppendTo(d.back(), 1LL);
+ AppendTo(d.back(), -1LL);
+ AppendTo(d.back(), 0LL);
+ AppendTo(d.back(), 1LL);
+ AppendTo(d.back(), 2LL);
+ d.emplace_back();
+ AppendTo(d.back(), 0LL);
+ AppendTo(d.back(), -1LL);
+ AppendTo(d.back(), -2LL);
+ AppendTo(d.back(), -1LL);
+ AppendTo(d.back(), -2LL);
+ AppendTo(d.back(), -1LL);
+ AppendTo(d.back(), 0LL);
+ AppendTo(d.back(), -1LL);
+ AppendTo(d.back(), -2LL);
+
+ TestCodec<TPForCodec<ui64>, false>(d);
+ TestCodec<TPForCodec<ui64, true>, true>(d);
+ }
+ {
+ TVector<TBuffer> d;
+ d.emplace_back();
+ AppendTo(d.back(), -1);
+ AppendTo(d.back(), -1);
+ AppendTo(d.back(), -1);
+ AppendTo(d.back(), -1);
+ d.emplace_back();
+ AppendTo(d.back(), 0);
+ AppendTo(d.back(), 1);
+ AppendTo(d.back(), 2);
+ AppendTo(d.back(), 1);
+ AppendTo(d.back(), -1);
+ AppendTo(d.back(), 0);
+ AppendTo(d.back(), 1);
+ AppendTo(d.back(), 2);
+ d.emplace_back();
+ AppendTo(d.back(), 0);
+ AppendTo(d.back(), -1);
+ AppendTo(d.back(), -2);
+ AppendTo(d.back(), -1);
+ AppendTo(d.back(), -2);
+ AppendTo(d.back(), -1);
+ AppendTo(d.back(), 0);
+ AppendTo(d.back(), -1);
+ AppendTo(d.back(), -2);
+
+ TestCodec<TPForCodec<ui32>, false>(d);
+ TestCodec<TPForCodec<ui32, true>, false>(d);
+ }
+ {
+ TVector<TBuffer> d;
+ d.emplace_back();
+ for (auto& textValue : TextValues) {
+ AppendTo(d.back(), (ui32)strlen(textValue));
+ }
+
+ TestCodec<TPForCodec<ui32>, false>(d);
+ TestCodec<TPForCodec<ui32, true>, false>(d);
+ }
+ {
+ TVector<TBuffer> d;
+ d.emplace_back();
+ for (auto& textValue : TextValues) {
+ AppendTo(d.back(), (ui64)strlen(textValue));
+ }
+
+ TestCodec<TPForCodec<ui64>, false>(d);
+ TestCodec<TPForCodec<ui64, true>, false>(d);
+ }
+ }
+
+ template <class TCodec>
+ void DoTestSimpleCodec() {
+ using namespace NCodecs;
+ {
+ TVector<TBuffer> learn;
+
+ for (auto& textValue : TextValues) {
+ learn.emplace_back(textValue, strlen(textValue));
+ }
+
+ TestCodec<TCodec, true>(learn);
+ }
+ {
+ TestCodec<TCodec, true>();
+ }
+
+ {
+ TVector<TBuffer> learn;
+ learn.emplace_back();
+ learn.back().Append('a');
+
+ TVector<TBuffer> test;
+ test.emplace_back();
+ for (ui32 i = 0; i < 256; ++i) {
+ test.back().Append((ui8)i);
+ }
+
+ TestCodec<TCodec, true>(learn, test);
+ }
+
+ {
+ TVector<TBuffer> learn;
+ learn.emplace_back();
+ for (ui32 i = 0; i < 256; ++i) {
+ for (ui32 j = 0; j < i; ++j) {
+ learn.back().Append((ui8)i);
+ }
+ }
+
+ TVector<TBuffer> test;
+ test.emplace_back();
+ for (ui32 i = 0; i < 256; ++i) {
+ test.back().Append((ui8)i);
+ }
+
+ TestCodec<TCodec, true>(learn, test);
+ }
+
+ {
+ TVector<TBuffer> learn;
+ learn.emplace_back();
+ for (ui32 i = 0; i < 128; ++i) {
+ for (ui32 j = 0; j < i; ++j) {
+ learn.back().Append((ui8)i);
+ }
+ }
+
+ TVector<TBuffer> test;
+ test.emplace_back();
+ for (ui32 i = 128; i < 256; ++i) {
+ test.back().Append((ui8)i);
+ }
+
+ TestCodec<TCodec, true>(learn, test);
+ }
+ }
+
+ void TestHuffman() {
+ DoTestSimpleCodec<NCodecs::THuffmanCodec>();
+ }
+
+ void TestZStdDict() {
+ using namespace NCodecs;
+ {
+ TVector<TBuffer> learn;
+
+ for (auto& textValue : TextValues) {
+ learn.emplace_back(textValue, strlen(textValue));
+ }
+
+ TestCodec<TZStdDictCodec, true>(learn);
+ }
+
+ }
+
+ void TestCompTable() {
+ DoTestSimpleCodec<NCodecs::TCompTableCodec>();
+ }
+
+ void TestHuffmanLearnByFreqs() {
+ using namespace NCodecs;
+
+ TVector<TBuffer> data;
+
+ for (auto& textValue : TextValues) {
+ data.emplace_back(textValue, strlen(textValue));
+ }
+
+ TVector<TBuffer> outLearn;
+
+ {
+ THuffmanCodec codec;
+ static_cast<ICodec&>(codec).Learn(data.begin(), data.end());
+
+ for (ui32 i = 0; i < data.size(); ++i) {
+ outLearn.emplace_back();
+ codec.Encode(AsStrBuf(data[i]), outLearn[i]);
+ }
+ }
+
+ TVector<TBuffer> outLearnByFreqs;
+
+ {
+ THuffmanCodec codec;
+ std::pair<char, ui64> freqs[256];
+
+ for (size_t i = 0; i < Y_ARRAY_SIZE(freqs); ++i) {
+ freqs[i].first = (char)i;
+ freqs[i].second = 0;
+ }
+
+ for (auto& textValue : TextValues) {
+ size_t len = strlen(textValue);
+ for (size_t j = 0; j < len; ++j) {
+ ++freqs[(ui32)(0xFF & textValue[j])].second;
+ }
+ }
+
+ codec.LearnByFreqs(TArrayRef<std::pair<char, ui64>>(freqs, Y_ARRAY_SIZE(freqs)));
+
+ for (ui32 i = 0; i < data.size(); ++i) {
+ outLearnByFreqs.emplace_back();
+ codec.Encode(AsStrBuf(data[i]), outLearnByFreqs[i]);
+ }
+ }
+
+ UNIT_ASSERT_EQUAL(outLearn.size(), outLearnByFreqs.size());
+ const size_t sz = outLearn.size();
+ for (size_t n = 0; n < sz; ++n) {
+ UNIT_ASSERT_EQUAL(AsStrBuf(outLearn[n]), AsStrBuf(outLearnByFreqs[n]));
+ }
+ }
+
+ void TestSolar() {
+ using namespace NCodecs;
+ {
+ TVector<TBuffer> learn;
+
+ for (auto& textValue : TextValues) {
+ learn.emplace_back(textValue, strlen(textValue));
+ }
+
+ TestCodec<TSolarCodec, true>(learn, TVector<TBuffer>(), new TSolarCodec(512, 8));
+ TestCodec<TAdaptiveSolarCodec, false>(learn, TVector<TBuffer>(), new TAdaptiveSolarCodec(512, 8));
+ TestCodec<TAdaptiveSolarCodec, true>(learn, TVector<TBuffer>(), new TAdaptiveSolarCodec(512, 8));
+ TestCodec<TSolarCodecShortInt, true>(learn, TVector<TBuffer>(), new TSolarCodecShortInt(512, 8));
+ }
+ {
+ TestCodec<TSolarCodec, true>(TVector<TBuffer>(), TVector<TBuffer>(), new TSolarCodec(512, 8));
+ TestCodec<TAdaptiveSolarCodec, false>(TVector<TBuffer>(), TVector<TBuffer>(), new TAdaptiveSolarCodec(512, 8));
+ TestCodec<TAdaptiveSolarCodec, true>(TVector<TBuffer>(), TVector<TBuffer>(), new TAdaptiveSolarCodec(512, 8));
+ TestCodec<TSolarCodecShortInt, true>(TVector<TBuffer>(), TVector<TBuffer>(), new TSolarCodecShortInt(512, 8));
+ }
+
+ {
+ TVector<TBuffer> learn;
+ learn.emplace_back();
+ learn.back().Append('a');
+
+ TVector<TBuffer> test;
+ test.emplace_back();
+ for (ui32 i = 0; i < 256; ++i) {
+ test.back().Append((ui8)i);
+ }
+
+ TestCodec<TSolarCodec, true>(learn, test, new TSolarCodec(512, 8));
+ TestCodec<TAdaptiveSolarCodec, false>(learn, test, new TAdaptiveSolarCodec(512, 8));
+ TestCodec<TAdaptiveSolarCodec, true>(learn, test, new TAdaptiveSolarCodec(512, 8));
+ TestCodec<TSolarCodecShortInt, true>(learn, test, new TSolarCodecShortInt(512, 8));
+ }
+
+ {
+ TVector<TBuffer> learn;
+ learn.emplace_back();
+ for (ui32 i = 0; i < 256; ++i) {
+ for (ui32 j = 0; j < i; ++j) {
+ learn.back().Append((ui8)i);
+ }
+ }
+
+ TVector<TBuffer> test;
+ test.emplace_back();
+ for (ui32 i = 0; i < 256; ++i) {
+ test.back().Append((ui8)i);
+ }
+
+ TestCodec<TSolarCodec, true>(learn, test, new TSolarCodec(512, 8));
+ TestCodec<TAdaptiveSolarCodec, false>(learn, test, new TAdaptiveSolarCodec(512, 8));
+ TestCodec<TAdaptiveSolarCodec, true>(learn, test, new TAdaptiveSolarCodec(512, 8));
+ TestCodec<TSolarCodecShortInt, true>(learn, test, new TSolarCodecShortInt(512, 8));
+ }
+ }
+
+ void TestPipeline() {
+ using namespace NCodecs;
+ {
+ TVector<TBuffer> learn;
+ learn.emplace_back();
+ for (ui32 i = 0; i < 256; ++i) {
+ for (i32 j = i; j >= 0; --j) {
+ learn.back().Append((ui8)j);
+ }
+ }
+
+ TVector<TBuffer> test;
+ test.emplace_back();
+ for (ui32 i = 0; i < 256; ++i) {
+ test.back().Append((ui8)i);
+ }
+
+ TestCodec<TPipelineCodec, true>(learn, test,
+ new TPipelineCodec(new TSolarCodec(512, 8), new TSolarCodec(512, 8), new THuffmanCodec));
+ }
+ {
+ TVector<TBuffer> d;
+ d.emplace_back();
+ for (ui32 i = 0; i < 256; ++i) {
+ for (i32 j = i; j >= 0; --j) {
+ d.back().Append(i * i);
+ }
+ }
+
+ TestCodec<TPipelineCodec, false>(d, TVector<TBuffer>(),
+ new TPipelineCodec(new TDeltaCodec<ui32, false>, new TPForCodec<ui32>));
+ }
+ }
+
+ void TestRegistry() {
+ using namespace NCodecs;
+ TVector<TString> vs = ICodec::GetCodecsList();
+ for (const auto& v : vs) {
+ TCodecPtr p = ICodec::GetInstance(v);
+ if (v == "none") {
+ UNIT_ASSERT(!p);
+ continue;
+ }
+ UNIT_ASSERT_C(!!p, v);
+ UNIT_ASSERT_C(TStringBuf(v).Head(3) == TStringBuf(p->GetName()).Head(3), v + " " + p->GetName());
+ }
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TCodecsTest)
diff --git a/library/cpp/codecs/ut/float_huffman_ut.cpp b/library/cpp/codecs/ut/float_huffman_ut.cpp
new file mode 100644
index 0000000000..3156fb1f46
--- /dev/null
+++ b/library/cpp/codecs/ut/float_huffman_ut.cpp
@@ -0,0 +1,237 @@
+#include <library/cpp/codecs/float_huffman.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/format.h>
+#include <util/stream/output.h>
+#include <library/cpp/string_utils/base64/base64.h>
+
+namespace fh = NCodecs::NFloatHuff;
+
+Y_UNIT_TEST_SUITE(FloatHuffmanTest) {
+ static const float Factors[] = {
+ 0.340582, 0.000974026, 0.487168, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0.411765, 0.921569,
+ 0.00390625, 0.109371, 0, 1, 0, 0, 0, 0, 0.523322, 0, 1, 0, 0, 0, 0, 0.285714, 1,
+ 0.008253, 1, 0, 0, 0.00993935, 0.450213, 0.000974026, 1, 1, 1, 1, 0, 0, 0.20564,
+ 0.97561, 0.913896, 1, 1, 0, 1, 0, 0, 0.5, 0, 0, 0, 0.1, 1, 0, 0, 0, 0, 0, 0.450923,
+ 0, 0.5, 0, 0, 0.20564, 0, 0.5, 0, 0, 0.20564, 0, 0, 0.0313726, 0, 1, 1, 1, 0.363636,
+ 0.5, 0.686073, 0.45121, 0.00574382, 0.366166, 0.413295, 1, 1, 1, 0, 0, 0, 0, 0.160784,
+ 0, 0.937255, 0.537255, 0.133333, 0, 0, 0, 0, 0.00392157, 0, 0.333333, 0.027451, 0.0156863,
+ 1, 0.105882, 1, 0.00220908, 0.000112501, 0.0111262, 0.102384, 0.00140808, 0.123581,
+ 0.29308, 6.57282e-06, 0.00489498, 2.10209e-05, 0.00140559, 5.907e-06, 0, 0.559322,
+ 0.559322, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0.794765, 0,
+ 0.352648, 0.225904, 1, 0.047619, 0.0107276, 0.399461, 0.0304838, 0.292932, 0.00969929,
+ 0, 0, 0.886904, 0.714693, 0, 0.00223213, 0.000544069, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0.00507403, 0, 0, 0, 0, 0, 0.875, 0, 0, 1, 1, 1, 0, 0.20564, 0, 0.00176048, 0,
+ 0.000440121, 0, 0, 0, 0.000974026, 0.487168, 0, 0, 0.533333, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 1, 0, 0, 0.723187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0.206882, 0.00483367, 0.792983, 0.00126106, 1, 0.0313726, 0.470588,
+ 0.254902, 0.188235, 0.188235, 0.388235, 0.164706, 0, 0.870588, 0.843137, 0.635294,
+ 0.384314, 0.384314, 0.643137, 0, 0, 0, 0, 0, 0, 0, 0, 0.541176, 0, 0.541176, 0, 0,
+ 0.0532634, 1, 0, 0, 0, 0.015044, 1, 0, 1, 1, 1, 0.47451, 0.329412, 0.964706, 0, 0,
+ 0, 0, 0, 0.5, 0, 0, 0, 0, 0, 0, 0.0941176, 0.970588, 0.970588, 0, 0.970588, 0.97561,
+ 0, 0.0431373, 0.47451, 0.329412, 0.964706, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0.231373, 0.00392157, 0, 0, 0, 0.054902, 0, 0,
+ 1, 0, 0, 0.0235294, 0, 1, 0, 0, 0, 0, 0.34902, 0.0352941, 0.925379, 0.623681, 0,
+ 0.954543, 0, 0, 0.00102756, 0.709804, 0.498039, 0.0901961, 0.631373, 0.847059, 0.270588,
+ 0.0156863, 0.133333, 0.980392, 1e-12, 1e-12, 1e-12, 1e-12, 0.497159, 0, 0.407487,
+ 0, 0, 0, 0.00392157, 0.00202156, 0.046875, 0.187159, 0.046875, 0.15625, 0.434232,
+ 0.15625, 0, 2.95083e-07, 0.20564, 0.20564, 0.97561, 0.913896, 0, 0, 0, 0, 0, 0, 0.00784314,
+ 0, 0.695525, 1, 0.07205, 0, 0, 0.176471, 0, 0, 0, 1, 1, 0.98, 0.01, 0.01, 0, 0.00690702,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.29078, 0.29078, 1, 0, 0, 0, 0, 0.192157, 0.188235,
+ 0.0941176, 0, 0.0313726, 0, 0.141176, 0.207843, 0.0901961, 0.00784314, 0.0784314,
+ 0, 0, 0, 0, 0, 0.203922, 0.0196078, 0.34902, 0.0235294, 0.0980392, 0.164706, 0.133333,
+ 0.368627, 0, 0.0941176, 0, 1, 0.313726, 0, 0, 0.433582, 0.384508, 0.0532186, 0.0833333,
+ 0.01609, 0, 1, 0, 0, 0, 0.0666667, 0, 0, 0, 0, 1, 0, 0.564706, 0.501961, 0, 0, 0,
+ 0, 0, 0.0516447, 0.000173065, 0, 0, 0, 0, 0, 0, 0, 0.996309, 0, 0, 0.00392157, 1,
+ 0, 0.01, 0, 0, 0, 0, 0, 0.439505, 0.206882, 0.206882, 0.260891, 0, 0.875, 0, 0, 0,
+ 0, 0, 0.185657, 1, 1, 0, 0, 0, 0.0332647, 0.206106, 0.0688878, 0.239216, 0, 0, 0,
+ 0, 0.054902, 0, 0.101961, 0.160784, 0.180392, 0, 0.737828, 0, 0, 0.875, 0.0142566,
+ 0, 0.662745, 1, 0, 0, 0, 0.225806, 0.99992, 0.631373, 0.00392157, 1, 0, 0.143647,
+ 0.00270085, 1, 0.231482, 0.246735, 0.0428062, 0, 0, 1, 0, 0.186441, 0.0115358, 0,
+ 0.221762, 0, 0.2, 0, 0.0156863, 0, 0, 0, 0.976471, 0, 0.231373, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0.00392157, 0.00392157, 0.0666667, 0, 0, 0, 0, 0.0117647, 0.580392, 0.98737,
+ 1, 1, 1, 0, 0, 0, 0.153, 0.847, 0.931373, 0.94697, 0.94697, 0, 0.946294, 0.408118,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0.99992, 0.97561, 0, 0, 0, 0, 0, 0,
+ 0.274677, 0.153017, 0, 0.642356, 0, 0, 0.1, 0, 0, 0, 0, 0.327944, 0.327944, 0, 0,
+ 0.815686, 0, 0, 0, 0, 0.206106, 0.439126, 0, 0, 0, 0, 0, 1, 1, 1, 0.00392157, 0.232788,
+ 0.232465, 0.999899, 0.00309296, 0.0636097, 0.445954, 0.156863, 0, 0, 0, 0, 0, 0,
+ 0.3796, 0.0784, 0.0651664, 0, 0, 0.254902, 0.266667, 1, 0, 0, 0, 0, 0, 0.596073,
+ 0.517876, 0.145833, 0.372549, 0, 0.991667, 0.602125, 0.161979, 0, 0, 0, 0, 0.0255146,
+ 0.947855, 0, 0, 0, 0, 0, 0, 0, 0, 0.847059, 0.679841, 0, 0.156863, 0, 0, 1, 0, 0,
+ 0, 0, 0.969697, 0, 0, 0.564706, 0, 0, 0, 0, 0, 1, 0.0367282, 0.0395228, 0, 0, 0,
+ 0, 0, 0.0470588, 0.141176, 0.054902, 0, 0, 0, 0};
+ static const size_t FactorCount = Y_ARRAY_SIZE(Factors);
+
+ static const ui8 CodedFactors[] = {
+ 0x24, 0x06, 0x73, 0xB5, 0xC7, 0x55, 0x7F, 0x3A, 0xB4, 0x70, 0xCB, 0xEF, 0xEE, 0xFE, 0xB3, 0x5B,
+ 0x5A, 0x1A, 0x93, 0x5F, 0x5F, 0x13, 0x00, 0x00, 0x10, 0x00, 0x3D, 0xEF, 0xFF, 0xEE, 0x0F, 0xDC,
+ 0xF0, 0xAB, 0x3F, 0x37, 0x92, 0x24, 0x5D, 0x5E, 0xDE, 0x1C, 0xF8, 0x12, 0x15, 0x5B, 0x84, 0x51,
+ 0x82, 0xE6, 0xF6, 0xB8, 0xEA, 0x4F, 0xC7, 0xDD, 0x7D, 0x2E, 0x4D, 0x4A, 0x21, 0xCA, 0xE0, 0xC4,
+ 0x2E, 0xEA, 0xD3, 0xBD, 0x0F, 0x00, 0x00, 0xE0, 0xDA, 0xCC, 0xCC, 0xEC, 0x9F, 0x61, 0xDF, 0xE6,
+ 0x01, 0x00, 0x00, 0xCC, 0xA5, 0x49, 0xA9, 0x00, 0x00, 0x00, 0xE6, 0xD2, 0xA4, 0xD4, 0xEA, 0x08,
+ 0x08, 0xD0, 0xDD, 0xF9, 0xE7, 0xA2, 0x0B, 0x00, 0x00, 0x40, 0xD8, 0x13, 0x7D, 0xFE, 0x13, 0x9C,
+ 0x9B, 0xA8, 0x36, 0xBC, 0x00, 0x90, 0x43, 0x6F, 0x97, 0x67, 0x9B, 0xD3, 0xEE, 0xFE, 0x84, 0x24,
+ 0x25, 0x89, 0xC9, 0xBF, 0x3F, 0x58, 0x4C, 0x4C, 0xCA, 0x21, 0x22, 0xBC, 0x39, 0x08, 0x08, 0x08,
+ 0x40, 0x7E, 0xAA, 0xAA, 0xCA, 0x75, 0x70, 0x70, 0xE9, 0x08, 0x08, 0xE8, 0x9A, 0x8A, 0x8D, 0xED,
+ 0xA6, 0x8D, 0x31, 0x04, 0x00, 0x96, 0xD0, 0x7D, 0x1D, 0x47, 0xAA, 0x2A, 0xD9, 0x28, 0xAD, 0x6B,
+ 0xB4, 0x9D, 0x7A, 0xC4, 0xD5, 0xD1, 0x04, 0x8C, 0x7E, 0x56, 0x3A, 0x58, 0x5A, 0x0C, 0x46, 0x6E,
+ 0x1B, 0x53, 0xC2, 0x0C, 0x14, 0x00, 0xAB, 0x60, 0x05, 0x7B, 0x63, 0x8D, 0x77, 0x70, 0x75, 0xAC,
+ 0x2F, 0x8D, 0xB1, 0x4D, 0xA0, 0xFB, 0xF2, 0x40, 0xF7, 0xE5, 0x7F, 0xDF, 0xDD, 0xFD, 0xBB, 0x1B,
+ 0xB8, 0x75, 0x9B, 0x47, 0x8E, 0xB4, 0x0C, 0x9B, 0x3A, 0x73, 0x25, 0x61, 0x18, 0x92, 0xD1, 0xC2,
+ 0x2F, 0x3C, 0x31, 0x64, 0x96, 0x2A, 0xB9, 0xF9, 0x7C, 0xD9, 0xAF, 0x94, 0xC5, 0xE9, 0x1E, 0x63,
+ 0x24, 0x0C, 0x03, 0x7F, 0xD8, 0x5B, 0xB3, 0x1D, 0x49, 0x02, 0x00, 0xAB, 0xFD, 0xE9, 0xA0, 0xF3,
+ 0xBF, 0xC9, 0x40, 0x64, 0x0A, 0xC0, 0xC7, 0x00, 0x00, 0x60, 0x77, 0xCF, 0xA5, 0x49, 0xA9, 0x16,
+ 0xFD, 0xD7, 0x5C, 0xA7, 0x55, 0x00, 0x36, 0xCF, 0xB9, 0x3D, 0xAE, 0xFA, 0xD3, 0xA1, 0x85, 0x5B,
+ 0xFE, 0x60, 0x10, 0x11, 0xFF, 0xF7, 0x7D, 0x38, 0x59, 0x24, 0xFF, 0xFF, 0xDF, 0x13, 0x1C, 0x7B,
+ 0xCA, 0x1C, 0x1E, 0xF3, 0x04, 0xC0, 0x78, 0x07, 0x58, 0x7B, 0xA2, 0x54, 0xAA, 0xE3, 0xEA, 0x08,
+ 0x08, 0xC0, 0x74, 0x78, 0x78, 0x88, 0x50, 0x50, 0xD8, 0x0A, 0x0C, 0xC4, 0x56, 0x60, 0x20, 0xF6,
+ 0x1A, 0x1B, 0x33, 0x16, 0x15, 0xA5, 0xB8, 0xED, 0xED, 0x22, 0xF5, 0xF5, 0x09, 0xA1, 0xA2, 0x42,
+ 0x67, 0x62, 0x62, 0x3A, 0x13, 0x13, 0x0B, 0xA0, 0xA4, 0xF4, 0x0F, 0x06, 0x15, 0x35, 0x18, 0x54,
+ 0xD4, 0x35, 0x57, 0x45, 0xCB, 0x2F, 0x39, 0xF6, 0xEC, 0xBC, 0xBB, 0x53, 0x5F, 0x5E, 0x9E, 0xB1,
+ 0xA8, 0xA8, 0x28, 0xDF, 0xDE, 0x3E, 0x00, 0x00, 0x80, 0x5F, 0x75, 0x81, 0x81, 0x51, 0x1D, 0x1E,
+ 0xA2, 0x3A, 0x3C, 0x8C, 0xEA, 0xF0, 0x10, 0x51, 0x06, 0x67, 0xED, 0x85, 0x85, 0xA1, 0xBE, 0xBC,
+ 0x3C, 0x63, 0x51, 0x51, 0x51, 0xBE, 0xBD, 0xFD, 0xFF, 0xFD, 0xFE, 0xCE, 0x85, 0x76, 0x36, 0x73,
+ 0x10, 0x10, 0x10, 0x80, 0xEB, 0x3A, 0x38, 0xD8, 0xBE, 0xD4, 0x05, 0x06, 0xEE, 0x4F, 0x60, 0x59,
+ 0x59, 0x65, 0x84, 0x84, 0xC0, 0x46, 0xCB, 0x19, 0x7F, 0x4C, 0xFD, 0xC8, 0x9D, 0x8B, 0xB6, 0x31,
+ 0xAF, 0x86, 0x3A, 0xF0, 0x6D, 0x6D, 0x11, 0xDF, 0xDF, 0x5F, 0x79, 0x71, 0x71, 0x85, 0xD4, 0xD0,
+ 0x10, 0xB9, 0xB1, 0x11, 0x1A, 0x54, 0x54, 0xE9, 0x08, 0x08, 0x48, 0x39, 0x44, 0x04, 0x84, 0xAF,
+ 0xAF, 0x96, 0x99, 0x97, 0x71, 0xC5, 0x32, 0xF3, 0x32, 0xAE, 0x58, 0x66, 0x5E, 0xC6, 0x15, 0xCB,
+ 0xCC, 0xCB, 0xB8, 0x42, 0xD0, 0x45, 0xFF, 0x1C, 0x11, 0x85, 0xBE, 0x39, 0x08, 0x08, 0x08, 0x80,
+ 0x69, 0xC2, 0x47, 0x00, 0x80, 0x02, 0x00, 0x00, 0x91, 0xD3, 0xF4, 0x47, 0x01, 0x00, 0x80, 0x08,
+ 0x00, 0x00, 0x42, 0xD4, 0x29, 0x6F, 0x02, 0x00, 0x80, 0xB4, 0xE6, 0x6B, 0x9E, 0x34, 0x5C, 0x9A,
+ 0x94, 0xE2, 0xD2, 0xA4, 0x14, 0xA2, 0x0C, 0x4E, 0xEC, 0xA2, 0x3E, 0x7F, 0x39, 0x08, 0x08, 0x10,
+ 0x6E, 0x6F, 0x10, 0xD7, 0x79, 0xC7, 0xC9, 0x09, 0x4D, 0x4B, 0x73, 0x77, 0x84, 0x14, 0xAE, 0x52,
+ 0xE1, 0x7A, 0x44, 0x2A, 0x5C, 0x8F, 0x34, 0x93, 0xA8, 0xC4, 0x01, 0xF8, 0x3F, 0x3D, 0xC2, 0x29,
+ 0xE9, 0x11, 0x4E, 0xE9, 0x4F, 0x67, 0x62, 0x22, 0xB6, 0x02, 0x03, 0xA9, 0x2E, 0x30, 0x70, 0x75,
+ 0x04, 0x04, 0xC8, 0x38, 0x48, 0x08, 0x32, 0x53, 0x53, 0x29, 0x2F, 0x2E, 0xAE, 0x1C, 0x04, 0x04,
+ 0x50, 0x52, 0x50, 0xD0, 0x4F, 0x77, 0x68, 0x28, 0x99, 0x08, 0x0A, 0x4A, 0x60, 0x59, 0x59, 0xA9,
+ 0x0B, 0x0C, 0xAC, 0xC7, 0xC8, 0xC8, 0x8C, 0x45, 0x45, 0xA1, 0x1C, 0x22, 0x02, 0x5D, 0x79, 0x79,
+ 0xAB, 0x2E, 0x30, 0x70, 0xA7, 0x2C, 0x28, 0xE8, 0xB4, 0xF3, 0xEF, 0x26, 0x8F, 0x37, 0xB1, 0xFE,
+ 0xEE, 0x67, 0xA9, 0xA9, 0xAA, 0xAA, 0x6C, 0x79, 0x1E, 0xEC, 0xD7, 0x46, 0x44, 0xC4, 0xF7, 0xF8,
+ 0x24, 0x24, 0x00, 0x42, 0x40, 0xF8, 0x5A, 0x96, 0x38, 0x65, 0x91, 0xF1, 0x6A, 0x72, 0xFE, 0x68,
+ 0xC3, 0xE1, 0x37, 0x07, 0x01, 0x01, 0x01, 0xF0, 0x52, 0xE1, 0x7A, 0xE4, 0xB3, 0xD9, 0x20, 0x9C,
+ 0xE0, 0xD8, 0x53, 0x04, 0xC7, 0x9E, 0x82, 0x02, 0x27, 0x2B, 0x06, 0x00, 0x00, 0x9F, 0xDE, 0x1C,
+ 0x3E, 0xEE, 0xD7, 0x48, 0x20, 0x04, 0xD2, 0x35, 0x4C, 0x29, 0x43, 0x45, 0x23, 0x15, 0xEA, 0xE9,
+ 0x5E, 0xD7, 0xC1, 0xC1, 0xAA, 0x3B, 0x34, 0x34, 0x21, 0x49, 0x49, 0xE8, 0x8A, 0x8B, 0x13, 0x66,
+ 0x12, 0xE7, 0x31, 0x00, 0x00, 0x90, 0x84, 0x94, 0x69, 0x05, 0xD4, 0xD4, 0xF4, 0x13, 0x36, 0xE7,
+ 0x0C, 0x09, 0xEB, 0xBF, 0x90, 0x1A, 0x1A, 0xE6, 0x20, 0x20, 0x20, 0x00, 0x9E, 0x33, 0x18, 0x13,
+ 0xA6, 0x2F, 0x40, 0x0C, 0x00, 0x4E, 0xCF, 0x84, 0x36, 0x6A, 0xA0, 0xF2, 0xA9, 0x63, 0xD5, 0xCB,
+ 0x9E, 0x64, 0xEA, 0x3E, 0xF2, 0x14, 0xA0, 0x27, 0x29, 0x2B, 0xC6, 0xB2, 0x99, 0x99, 0xA9, 0x74,
+ 0x04, 0x04, 0x3C, 0x0A, 0xD0, 0xCF, 0x5C, 0x68, 0x67, 0xFB, 0xDF, 0x1C, 0x04, 0x04, 0x04, 0xC0,
+ 0x1C, 0x04, 0x04, 0x04, 0x40, 0x1B, 0x11, 0x11, 0x5F, 0xEA, 0x02, 0x03, 0xE1, 0x92, 0x94, 0x84,
+ 0x90, 0x88, 0xD9, 0xDD, 0x4F, 0x04, 0x56, 0x0E, 0xD1, 0x9F, 0x1A, 0x31, 0x3B, 0x37, 0x47, 0xA0,
+ 0x6C, 0x82, 0x40, 0xD9, 0x24, 0x9A, 0x02, 0x12, 0x62, 0xD3, 0x43, 0xFF, 0xBF, 0x8F, 0x84, 0xF5,
+ 0x1F, 0x51, 0x06, 0xE7, 0x0F, 0xDD, 0x89, 0x32, 0xFB, 0x60, 0x39, 0x0A, 0x71, 0x71, 0xB4, 0x36,
+ 0x33, 0x33, 0x3F, 0x8F, 0xD0, 0x4F, 0x79, 0x84, 0x7E, 0xBA, 0xC8, 0x0C, 0x0D, 0x4F, 0xBA, 0x86,
+ 0x29, 0x82, 0x54, 0x83, 0x7F, 0x77, 0x37, 0x07, 0x01, 0x01, 0x01, 0xA0, 0xFE, 0x97, 0x1B, 0x9D,
+ 0x16, 0xDC, 0x90, 0x58, 0xFE, 0x9B, 0x42, 0xB3, 0x4A, 0x00, 0x68, 0x73, 0x91, 0x20, 0x2B, 0xA8,
+ 0xC8, 0x29, 0x0B, 0x0A, 0xF2, 0xD3, 0x5D, 0x4B, 0x58, 0x5D, 0x20, 0x41, 0xD5, 0xBE, 0xAE, 0x70,
+ 0x88, 0x50, 0x50, 0x20, 0x4A, 0x44, 0xF4, 0x8F, 0xF7, 0x60, 0x22, 0x30, 0x9C, 0x24, 0xFE, 0x54,
+ 0x55, 0xD0, 0xD7, 0xD7, 0x37, 0x1A, 0xEF, 0x6E, 0xBC, 0x9B, 0x44, 0x39, 0xDD, 0x5D, 0xF2, 0xF2,
+ 0x7F, 0x20, 0x1A, 0x81, 0x9A, 0xCA, 0xBF, 0xC8, 0x8D, 0x8D, 0xC2, 0x83, 0x82, 0xA7, 0x2C, 0x28,
+ 0xC8, 0xFE, 0x08, 0xC2, 0x07, 0xC7, 0x27, 0x21, 0xE1, 0xBB, 0x3E, 0xC1, 0x59, 0x68, 0xAA, 0x78,
+ 0xC8, 0x57, 0x5D, 0x60, 0x20, 0xC6, 0x41, 0x42, 0xE8, 0x3A, 0x38, 0xD8, 0x9B, 0xFF, 0xFF, 0xFF,
+ 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ static const size_t CodedSize = Y_ARRAY_SIZE(CodedFactors);
+ static const TStringBuf CodedFactorsBuf(reinterpret_cast<const char*>(CodedFactors), CodedSize);
+
+ void FillWithGarbage(float* factors, size_t count) {
+ void* data = static_cast<void*>(factors);
+ memset(data, 0xAA, sizeof(float) * count);
+ }
+
+ // Helper for dumping compressed values
+ void PrintCompressed(const TVector<ui8>& codedFactors) {
+ for (size_t i = 0; i < codedFactors.size(); ++i) {
+ if (i % 0x10 == 0)
+ Cerr << Endl;
+ Cerr << Hex(codedFactors[i]) << ", ";
+ }
+ Cerr << Endl;
+ }
+
+ // Helper for dumping decompressed values
+ void PrintDecompressed(const TVector<float>& factors) {
+ TStringStream result;
+ TStringStream line;
+
+ for (size_t i = 0; i < factors.size(); ++i) {
+ line << factors[i] << ", ";
+ if (line.Str().size() > 80) {
+ result << line.Str() << Endl;
+ line.Clear();
+ }
+ }
+ Cerr << result.Str() << Endl;
+ }
+
+ Y_UNIT_TEST(TestCompress) {
+ const auto codedFactors = fh::Encode(Factors);
+ UNIT_ASSERT_VALUES_EQUAL(codedFactors.size(), CodedSize);
+ for (size_t i = 0; i < Min(codedFactors.size(), CodedSize); ++i)
+ UNIT_ASSERT_VALUES_EQUAL((ui8)codedFactors[i], CodedFactors[i]);
+ //PrintCompressed(codedFactors);
+ }
+
+ Y_UNIT_TEST(TestSimpleDecompress) {
+ TVector<float> factors = fh::Decode(CodedFactorsBuf);
+ UNIT_ASSERT_VALUES_EQUAL(factors.size(), FactorCount);
+ for (size_t i = 0; i < Min(factors.size(), FactorCount); ++i)
+ UNIT_ASSERT_VALUES_EQUAL(factors[i], Factors[i]);
+ //PrintDecompressed(factors);
+ }
+
+ Y_UNIT_TEST(TestDecompressInParts) {
+ float factors[FactorCount];
+ FillWithGarbage(factors, FactorCount);
+ fh::TDecoder decoder(CodedFactorsBuf);
+ const size_t firstPack = 100;
+ // unpack first pack
+ UNIT_ASSERT_VALUES_EQUAL(decoder.Decode({factors, firstPack}), firstPack);
+ // unpack all the rest
+ UNIT_ASSERT_VALUES_EQUAL(decoder.Decode({factors + firstPack, FactorCount - firstPack}), FactorCount - firstPack);
+
+ for (size_t i = 0; i < FactorCount; ++i)
+ UNIT_ASSERT_VALUES_EQUAL(factors[i], Factors[i]);
+ //PrintDecompressed(factors);
+ }
+
+ Y_UNIT_TEST(TestSkip) {
+ float factors[FactorCount];
+ FillWithGarbage(factors, FactorCount);
+ fh::TDecoder decoder(CodedFactorsBuf);
+ const size_t firstPack = 100;
+ // unpack first pack
+ UNIT_ASSERT_VALUES_EQUAL(decoder.Decode({factors, firstPack}), firstPack);
+ // skip some factors
+ const size_t skipCount = 60;
+ UNIT_ASSERT_VALUES_EQUAL(decoder.Skip(skipCount / 2), skipCount / 2);
+ // unpack all, except some factors in the end
+ const auto toDecode = FactorCount - firstPack - skipCount;
+ UNIT_ASSERT_VALUES_EQUAL(decoder.Decode({factors + firstPack, toDecode}), toDecode);
+ UNIT_ASSERT_VALUES_EQUAL(decoder.Skip(skipCount / 2), skipCount / 2);
+ for (size_t i = 0; i < FactorCount - skipCount; ++i) {
+ size_t correctedI = i < firstPack ? i : i + skipCount / 2;
+ UNIT_ASSERT_VALUES_EQUAL(factors[i], Factors[correctedI]);
+ }
+ //PrintDecompressed(factors);
+ }
+
+ Y_UNIT_TEST(TestDecompressForgedData) {
+ // this coredumps without end-of-coded-stream check, see SEARCH-1156 for details
+ TString brokenBase64Encoded =
+ "NLjYltUWs5pqnd3d3f05Li4OAwCAEqrP6mv06jDt7PiAUVu7Y+PiMpuZmdzeM"
+ "ArqOLxS2q4FKCII52dktcVs7y0zL+OKgeO9SOzEkFj7uPfFqqoCAAAAAADAtZ"
+ "mZ2fdmICAgANQXhi1WVRUAAAAAAAAGjvcWq6oKAAAAAAAAA8d7qe4rV3Nxcd3"
+ "d4ZfQZrETm3B+OxxB8bbnTPM5+qtbQ92mJ3fHPGj+iH5+8tzcnJuamry1tWUw"
+ "MBD693f07+9+DQQEkIGAgIgPetzN5yEbAGxWpbCNxXK/0JGTKRz2KkIoR7aM";
+ UNIT_ASSERT_EXCEPTION(
+ fh::Decode(Base64Decode(brokenBase64Encoded)),
+ yexception);
+ }
+
+ Y_UNIT_TEST(TestDecompressEmpty) {
+ UNIT_ASSERT_EXCEPTION(fh::Decode({}), yexception);
+ }
+};
diff --git a/library/cpp/codecs/ut/tls_cache_ut.cpp b/library/cpp/codecs/ut/tls_cache_ut.cpp
new file mode 100644
index 0000000000..8101af761f
--- /dev/null
+++ b/library/cpp/codecs/ut/tls_cache_ut.cpp
@@ -0,0 +1,36 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/codecs/tls_cache.h>
+
+Y_UNIT_TEST_SUITE(CodecsBufferFactoryTest){
+ void AssignToBuffer(TBuffer & buf, TStringBuf val){
+ buf.Assign(val.data(), val.size());
+}
+
+TStringBuf AsStringBuf(const TBuffer& b) {
+ return TStringBuf(b.Data(), b.Size());
+}
+
+Y_UNIT_TEST(TestAcquireReleaseReuse) {
+ NCodecs::TBufferTlsCache factory;
+ // acquiring the first buffer
+ auto buf1 = factory.Item();
+ AssignToBuffer(buf1.Get(), "Buffer_01");
+ {
+ // acquiring the second buffer
+ auto buf2 = factory.Item();
+ AssignToBuffer(buf2.Get(), "Buffer_02");
+ }
+ // the first buffer should stay intact
+ UNIT_ASSERT_EQUAL(AsStringBuf(buf1.Get()), "Buffer_01");
+ {
+ // reacquiring the last released buffer
+ // expecting it zero sized but having the same memory
+ auto buf2 = factory.Item();
+ UNIT_ASSERT_VALUES_EQUAL(buf2.Get().Size(), 0u);
+ buf2.Get().Resize(TStringBuf("Buffer_02").Size());
+ UNIT_ASSERT_EQUAL(AsStringBuf(buf2.Get()), "Buffer_02");
+ }
+ // when the factory dies we should see no leaks
+}
+}
+;
diff --git a/library/cpp/codecs/ut/ya.make b/library/cpp/codecs/ut/ya.make
new file mode 100644
index 0000000000..90841b05ef
--- /dev/null
+++ b/library/cpp/codecs/ut/ya.make
@@ -0,0 +1,20 @@
+UNITTEST()
+
+OWNER(
+ g:base
+ velavokr
+)
+
+PEERDIR(
+ library/cpp/string_utils/base64
+ library/cpp/codecs
+ library/cpp/string_utils/relaxed_escaper
+)
+
+SRCS(
+ tls_cache_ut.cpp
+ codecs_ut.cpp
+ float_huffman_ut.cpp
+)
+
+END()
diff --git a/library/cpp/codecs/ya.make b/library/cpp/codecs/ya.make
new file mode 100644
index 0000000000..7e76fb0c9a
--- /dev/null
+++ b/library/cpp/codecs/ya.make
@@ -0,0 +1,33 @@
+LIBRARY()
+
+OWNER(
+ g:base
+ velavokr
+)
+
+SRCS(
+ tls_cache.cpp
+ codecs.cpp
+ codecs_registry.cpp
+ comptable_codec.cpp
+ delta_codec.cpp
+ float_huffman.cpp
+ huffman_codec.cpp
+ pfor_codec.cpp
+ solar_codec.cpp
+ zstd_dict_codec.cpp
+)
+
+PEERDIR(
+ contrib/libs/zstd
+ library/cpp/bit_io
+ library/cpp/blockcodecs
+ library/cpp/codecs/greedy_dict
+ library/cpp/comptable
+ library/cpp/containers/comptrie
+ library/cpp/deprecated/accessors
+ library/cpp/packers
+ library/cpp/string_utils/relaxed_escaper
+)
+
+END()
diff --git a/library/cpp/codecs/zstd_dict_codec.cpp b/library/cpp/codecs/zstd_dict_codec.cpp
new file mode 100644
index 0000000000..c42a2879e6
--- /dev/null
+++ b/library/cpp/codecs/zstd_dict_codec.cpp
@@ -0,0 +1,281 @@
+#include "zstd_dict_codec.h"
+
+#include <library/cpp/packers/packers.h>
+
+#include <util/generic/ptr.h>
+#include <util/generic/refcount.h>
+#include <util/generic/noncopyable.h>
+#include <util/string/builder.h>
+#include <util/system/src_location.h>
+#include <util/ysaveload.h>
+
+#define ZDICT_STATIC_LINKING_ONLY
+
+#include <contrib/libs/zstd/include/zdict.h>
+#include <contrib/libs/zstd/include/zstd.h>
+#include <contrib/libs/zstd/include/zstd_errors.h>
+
+// See IGNIETFERRO-320 for possible bugs
+
+namespace NCodecs {
+ class TZStdDictCodec::TImpl: public TAtomicRefCount<TZStdDictCodec::TImpl> {
+ template <class T, size_t Deleter(T*)>
+ class TPtrHolder : TMoveOnly {
+ T* Ptr = nullptr;
+
+ public:
+ TPtrHolder() = default;
+
+ TPtrHolder(T* dict)
+ : Ptr(dict)
+ {
+ }
+
+ T* Get() {
+ return Ptr;
+ }
+
+ const T* Get() const {
+ return Ptr;
+ }
+
+ void Reset(T* dict) {
+ Dispose();
+ Ptr = dict;
+ }
+
+ void Dispose() {
+ if (Ptr) {
+ Deleter(Ptr);
+ Ptr = nullptr;
+ }
+ }
+
+ ~TPtrHolder() {
+ Dispose();
+ }
+ };
+
+ using TCDict = TPtrHolder<ZSTD_CDict, ZSTD_freeCDict>;
+ using TDDict = TPtrHolder<ZSTD_DDict, ZSTD_freeDDict>;
+ using TCCtx = TPtrHolder<ZSTD_CCtx, ZSTD_freeCCtx>;
+ using TDCtx = TPtrHolder<ZSTD_DCtx, ZSTD_freeDCtx>;
+
+ using TSizePacker = NPackers::TPacker<ui64>;
+
+ public:
+ static const ui32 SampleSize = (1 << 22) * 5;
+
+ explicit TImpl(ui32 comprLevel)
+ : CompressionLevel(comprLevel)
+ {
+ const size_t zeroSz = TSizePacker().MeasureLeaf(0);
+ Zero.Resize(zeroSz);
+ TSizePacker().PackLeaf(Zero.data(), 0, zeroSz);
+ }
+
+ ui32 GetCompressionLevel() const {
+ return CompressionLevel;
+ }
+
+ ui8 Encode(TStringBuf in, TBuffer& outbuf) const {
+ outbuf.Clear();
+
+ if (in.empty()) {
+ return 0;
+ }
+
+ TSizePacker packer;
+
+ const char* rawBeg = in.data();
+ const size_t rawSz = in.size();
+
+ const size_t szSz = packer.MeasureLeaf(rawSz);
+ const size_t maxDatSz = ZSTD_compressBound(rawSz);
+
+ outbuf.Resize(szSz + maxDatSz);
+ packer.PackLeaf(outbuf.data(), rawSz, szSz);
+
+ TCCtx ctx{CheckPtr(ZSTD_createCCtx(), __LOCATION__)};
+ const size_t resSz = CheckSize(ZSTD_compress_usingCDict(
+ ctx.Get(), outbuf.data() + szSz, maxDatSz, rawBeg, rawSz, CDict.Get()),
+ __LOCATION__);
+
+ if (resSz < rawSz) {
+ outbuf.Resize(resSz + szSz);
+ } else {
+ outbuf.Resize(Zero.size() + rawSz);
+ memcpy(outbuf.data(), Zero.data(), Zero.size());
+ memcpy(outbuf.data() + Zero.size(), rawBeg, rawSz);
+ }
+ return 0;
+ }
+
+ void Decode(TStringBuf in, TBuffer& outbuf) const {
+ outbuf.Clear();
+
+ if (in.empty()) {
+ return;
+ }
+
+ TSizePacker packer;
+
+ const char* rawBeg = in.data();
+ size_t rawSz = in.size();
+
+ const size_t szSz = packer.SkipLeaf(rawBeg);
+ ui64 datSz = 0;
+ packer.UnpackLeaf(rawBeg, datSz);
+
+ rawBeg += szSz;
+ rawSz -= szSz;
+
+ if (!datSz) {
+ outbuf.Resize(rawSz);
+ memcpy(outbuf.data(), rawBeg, rawSz);
+ } else {
+ // size_t zSz = ZSTD_getDecompressedSize(rawBeg, rawSz);
+ // Y_ENSURE_EX(datSz == zSz, TCodecException() << datSz << " != " << zSz);
+ outbuf.Resize(datSz);
+ TDCtx ctx{CheckPtr(ZSTD_createDCtx(), __LOCATION__)};
+ CheckSize(ZSTD_decompress_usingDDict(
+ ctx.Get(), outbuf.data(), outbuf.size(), rawBeg, rawSz, DDict.Get()),
+ __LOCATION__);
+ outbuf.Resize(datSz);
+ }
+ }
+
+ bool Learn(ISequenceReader& in, bool throwOnError) {
+ TBuffer data;
+ TVector<size_t> lens;
+
+ data.Reserve(2 * SampleSize);
+ TStringBuf r;
+ while (in.NextRegion(r)) {
+ if (!r) {
+ continue;
+ }
+ data.Append(r.data(), r.size());
+ lens.push_back(r.size());
+ }
+
+ ZDICT_legacy_params_t params;
+ memset(&params, 0, sizeof(params));
+ params.zParams.compressionLevel = 1;
+ params.zParams.notificationLevel = 1;
+ Dict.Resize(Max<size_t>(1 << 20, data.Size() + 16 * lens.size()));
+
+ if (!lens) {
+ Dict.Reset();
+ } else {
+ size_t trainResult = ZDICT_trainFromBuffer_legacy(
+ Dict.data(), Dict.size(), data.Data(), const_cast<const size_t*>(&lens[0]), lens.size(), params);
+ if (ZSTD_isError(trainResult)) {
+ if (!throwOnError) {
+ return false;
+ }
+ CheckSize(trainResult, __LOCATION__);
+ }
+ Dict.Resize(trainResult);
+ Dict.ShrinkToFit();
+ }
+ InitContexts();
+ return true;
+ }
+
+ void Save(IOutputStream* out) const {
+ ::Save(out, Dict);
+ }
+
+ void Load(IInputStream* in) {
+ ::Load(in, Dict);
+ InitContexts();
+ }
+
+ void InitContexts() {
+ CDict.Reset(CheckPtr(ZSTD_createCDict(Dict.data(), Dict.size(), CompressionLevel), __LOCATION__));
+ DDict.Reset(CheckPtr(ZSTD_createDDict(Dict.data(), Dict.size()), __LOCATION__));
+ }
+
+ static size_t CheckSize(size_t sz, TSourceLocation loc) {
+ if (ZSTD_isError(sz)) {
+ ythrow TCodecException() << loc << " " << ZSTD_getErrorName(sz) << " (code " << (int)ZSTD_getErrorCode(sz) << ")";
+ }
+ return sz;
+ }
+
+ template <class T>
+ static T* CheckPtr(T* t, TSourceLocation loc) {
+ Y_ENSURE_EX(t, TCodecException() << loc << " "
+ << "unexpected nullptr");
+ return t;
+ }
+
+ private:
+ ui32 CompressionLevel = 1;
+
+ TBuffer Zero;
+ TBuffer Dict;
+
+ TCDict CDict;
+ TDDict DDict;
+ };
+
+ TZStdDictCodec::TZStdDictCodec(ui32 comprLevel)
+ : Impl(new TImpl(comprLevel))
+ {
+ MyTraits.NeedsTraining = true;
+ MyTraits.SizeOnEncodeMultiplier = 2;
+ MyTraits.SizeOnDecodeMultiplier = 10;
+ MyTraits.RecommendedSampleSize = TImpl::SampleSize; // same as for solar
+ }
+
+ TZStdDictCodec::~TZStdDictCodec() {
+ }
+
+ TString TZStdDictCodec::GetName() const {
+ return TStringBuilder() << MyName() << "-" << Impl->GetCompressionLevel();
+ }
+
+ ui8 TZStdDictCodec::Encode(TStringBuf in, TBuffer& out) const {
+ return Impl->Encode(in, out);
+ }
+
+ void TZStdDictCodec::Decode(TStringBuf in, TBuffer& out) const {
+ Impl->Decode(in, out);
+ }
+
+ void TZStdDictCodec::DoLearn(ISequenceReader& in) {
+ Impl = new TImpl(Impl->GetCompressionLevel());
+ Impl->Learn(in, true/*throwOnError*/);
+ }
+
+ bool TZStdDictCodec::DoTryToLearn(ISequenceReader& in) {
+ Impl = new TImpl(Impl->GetCompressionLevel());
+ return Impl->Learn(in, false/*throwOnError*/);
+ }
+
+ void TZStdDictCodec::Save(IOutputStream* out) const {
+ Impl->Save(out);
+ }
+
+ void TZStdDictCodec::Load(IInputStream* in) {
+ Impl->Load(in);
+ }
+
+ TVector<TString> TZStdDictCodec::ListCompressionNames() {
+ TVector<TString> res;
+ for (int i = 1; i <= ZSTD_maxCLevel(); ++i) {
+ res.emplace_back(TStringBuilder() << MyName() << "-" << i);
+ }
+ return res;
+ }
+
+ int TZStdDictCodec::ParseCompressionName(TStringBuf name) {
+ int c = 0;
+ TryFromString(name.After('-'), c);
+ Y_ENSURE_EX(name.Before('-') == MyName() && c > 0 && c <= ZSTD_maxCLevel(), TCodecException() << "invald codec name" << name);
+ return c;
+ }
+
+}
diff --git a/library/cpp/codecs/zstd_dict_codec.h b/library/cpp/codecs/zstd_dict_codec.h
new file mode 100644
index 0000000000..59c1ad6c60
--- /dev/null
+++ b/library/cpp/codecs/zstd_dict_codec.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "codecs.h"
+
+#include <util/generic/ptr.h>
+
+namespace NCodecs {
+ // benchmarks are here: https://st.yandex-team.ru/SEARCH-1655
+
+ class TZStdDictCodec: public ICodec {
+ class TImpl;
+ TIntrusivePtr<TImpl> Impl;
+
+ public:
+ explicit TZStdDictCodec(ui32 comprLevel = 1);
+ ~TZStdDictCodec() override;
+
+ static TStringBuf MyName() {
+ return "zstd08d";
+ }
+
+ TString GetName() const override;
+
+ ui8 Encode(TStringBuf in, TBuffer& out) const override;
+
+ void Decode(TStringBuf in, TBuffer& out) const override;
+
+ static TVector<TString> ListCompressionNames();
+ static int ParseCompressionName(TStringBuf);
+
+ protected:
+ void DoLearn(ISequenceReader& in) override;
+ bool DoTryToLearn(ISequenceReader& in) final;
+ void Save(IOutputStream* out) const override;
+ void Load(IInputStream* in) override;
+ };
+
+}
diff --git a/library/cpp/colorizer/colors.cpp b/library/cpp/colorizer/colors.cpp
new file mode 100644
index 0000000000..decc5c9847
--- /dev/null
+++ b/library/cpp/colorizer/colors.cpp
@@ -0,0 +1,505 @@
+#include "colors.h"
+
+#include <util/stream/output.h>
+#include <util/generic/singleton.h>
+#include <util/system/env.h>
+
+#include <cstdlib>
+
+#if defined(_unix_)
+#include <unistd.h>
+#endif
+
+using namespace NColorizer;
+
+namespace {
+ constexpr TStringBuf ToStringBufC(NColorizer::EAnsiCode x) {
+ switch(x) {
+ case RESET:
+ return "\033[0m";
+
+ case ST_LIGHT:
+ return "\033[1m";
+ case ST_DARK:
+ return "\033[2m";
+ case ST_NORMAL:
+ return "\033[22m";
+
+ case ITALIC_ON:
+ return "\033[3m";
+ case ITALIC_OFF:
+ return "\033[23m";
+ case UNDERLINE_ON:
+ return "\033[4m";
+ case UNDERLINE_OFF:
+ return "\033[24m";
+
+ case FG_DEFAULT:
+ return "\033[39m";
+ case FG_BLACK:
+ return "\033[30m";
+ case FG_RED:
+ return "\033[31m";
+ case FG_GREEN:
+ return "\033[32m";
+ case FG_YELLOW:
+ return "\033[33m";
+ case FG_BLUE:
+ return "\033[34m";
+ case FG_MAGENTA:
+ return "\033[35m";
+ case FG_CYAN:
+ return "\033[36m";
+ case FG_WHITE:
+ return "\033[37m";
+
+ case BG_DEFAULT:
+ return "\033[49m";
+ case BG_BLACK:
+ return "\033[40m";
+ case BG_RED:
+ return "\033[41m";
+ case BG_GREEN:
+ return "\033[42m";
+ case BG_YELLOW:
+ return "\033[43m";
+ case BG_BLUE:
+ return "\033[44m";
+ case BG_MAGENTA:
+ return "\033[45m";
+ case BG_CYAN:
+ return "\033[46m";
+ case BG_WHITE:
+ return "\033[47m";
+
+ // Note: the following codes are split into two escabe sequences because of how ya.make handles them.
+
+ case DEFAULT:
+ return "\033[0m\033[0;39m";
+ case BLACK:
+ return "\033[0m\033[0;30m";
+ case RED:
+ return "\033[0m\033[0;31m";
+ case GREEN:
+ return "\033[0m\033[0;32m";
+ case YELLOW:
+ return "\033[0m\033[0;33m";
+ case BLUE:
+ return "\033[0m\033[0;34m";
+ case MAGENTA:
+ return "\033[0m\033[0;35m";
+ case CYAN:
+ return "\033[0m\033[0;36m";
+ case WHITE:
+ return "\033[0m\033[0;37m";
+
+ case LIGHT_DEFAULT:
+ return "\033[0m\033[1;39m";
+ case LIGHT_BLACK:
+ return "\033[0m\033[1;30m";
+ case LIGHT_RED:
+ return "\033[0m\033[1;31m";
+ case LIGHT_GREEN:
+ return "\033[0m\033[1;32m";
+ case LIGHT_YELLOW:
+ return "\033[0m\033[1;33m";
+ case LIGHT_BLUE:
+ return "\033[0m\033[1;34m";
+ case LIGHT_MAGENTA:
+ return "\033[0m\033[1;35m";
+ case LIGHT_CYAN:
+ return "\033[0m\033[1;36m";
+ case LIGHT_WHITE:
+ return "\033[0m\033[1;37m";
+
+ case DARK_DEFAULT:
+ return "\033[0m\033[2;39m";
+ case DARK_BLACK:
+ return "\033[0m\033[2;30m";
+ case DARK_RED:
+ return "\033[0m\033[2;31m";
+ case DARK_GREEN:
+ return "\033[0m\033[2;32m";
+ case DARK_YELLOW:
+ return "\033[0m\033[2;33m";
+ case DARK_BLUE:
+ return "\033[0m\033[2;34m";
+ case DARK_MAGENTA:
+ return "\033[0m\033[2;35m";
+ case DARK_CYAN:
+ return "\033[0m\033[2;36m";
+ case DARK_WHITE:
+ return "\033[0m\033[2;37m";
+
+ case INVALID:
+ default:
+ return "";
+ }
+ }
+}
+
+TStringBuf ToStringBuf(NColorizer::EAnsiCode x) {
+ return ToStringBufC(x);
+}
+
+TString ToString(NColorizer::EAnsiCode x) {
+ return TString(ToStringBufC(x));
+}
+
+template<>
+void Out<NColorizer::EAnsiCode>(IOutputStream& os, TTypeTraits<NColorizer::EAnsiCode>::TFuncParam x) {
+ if (AutoColors(os).IsTTY()) {
+ os << ToStringBufC(x);
+ }
+}
+
+bool TColors::CalcIsTTY(FILE* file) {
+ if (GetEnv("ENFORCE_TTY")) {
+ return true;
+ }
+
+#if defined(_unix_)
+ return isatty(fileno(file));
+#else
+ Y_UNUSED(file);
+ return false;
+#endif
+}
+
+TColors::TColors(FILE* f)
+ : IsTTY_(true)
+{
+ SetIsTTY(CalcIsTTY(f));
+}
+
+TColors::TColors(bool ontty)
+ : IsTTY_(true)
+{
+ SetIsTTY(ontty);
+}
+
+TStringBuf TColors::Reset() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::RESET) : ToStringBufC(EAnsiCode::INVALID);
+}
+
+TStringBuf TColors::StyleLight() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::ST_LIGHT) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::StyleDark() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::ST_DARK) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::StyleNormal() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::ST_NORMAL) : ToStringBufC(EAnsiCode::INVALID);
+}
+
+TStringBuf TColors::ItalicOn() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::ITALIC_ON) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::ItalicOff() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::ITALIC_OFF) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::UnderlineOn() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::UNDERLINE_ON) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::UnderlineOff() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::UNDERLINE_OFF) : ToStringBufC(EAnsiCode::INVALID);
+}
+
+TStringBuf TColors::ForeDefault() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::FG_DEFAULT) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::ForeBlack() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::FG_BLACK) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::ForeRed() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::FG_RED) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::ForeGreen() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::FG_GREEN) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::ForeYellow() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::FG_YELLOW) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::ForeBlue() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::FG_BLUE) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::ForeMagenta() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::FG_MAGENTA) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::ForeCyan() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::FG_CYAN) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::ForeWhite() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::FG_WHITE) : ToStringBufC(EAnsiCode::INVALID);
+}
+
+TStringBuf TColors::BackDefault() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::BG_DEFAULT) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::BackBlack() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::BG_BLACK) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::BackRed() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::BG_RED) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::BackGreen() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::BG_GREEN) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::BackYellow() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::BG_YELLOW) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::BackBlue() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::BG_BLUE) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::BackMagenta() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::BG_MAGENTA) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::BackCyan() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::BG_CYAN) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::BackWhite() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::BG_WHITE) : ToStringBufC(EAnsiCode::INVALID);
+}
+
+TStringBuf TColors::Default() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::DEFAULT) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::Black() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::BLACK) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::Red() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::RED) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::Green() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::GREEN) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::Yellow() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::YELLOW) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::Blue() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::BLUE) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::Magenta() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::MAGENTA) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::Cyan() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::CYAN) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::White() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::WHITE) : ToStringBufC(EAnsiCode::INVALID);
+}
+
+TStringBuf TColors::LightDefault() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_DEFAULT) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::LightBlack() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_BLACK) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::LightRed() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_RED) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::LightGreen() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_GREEN) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::LightYellow() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_YELLOW) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::LightBlue() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_BLUE) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::LightMagenta() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_MAGENTA) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::LightCyan() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_CYAN) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::LightWhite() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::LIGHT_WHITE) : ToStringBufC(EAnsiCode::INVALID);
+}
+
+TStringBuf TColors::DarkDefault() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::DARK_DEFAULT) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::DarkBlack() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::DARK_BLACK) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::DarkRed() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::DARK_RED) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::DarkGreen() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::DARK_GREEN) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::DarkYellow() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::DARK_YELLOW) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::DarkBlue() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::DARK_BLUE) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::DarkMagenta() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::DARK_MAGENTA) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::DarkCyan() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::DARK_CYAN) : ToStringBufC(EAnsiCode::INVALID);
+}
+TStringBuf TColors::DarkWhite() const noexcept {
+ return IsTTY() ? ToStringBufC(EAnsiCode::DARK_WHITE) : ToStringBufC(EAnsiCode::INVALID);
+}
+
+TStringBuf TColors::OldColor() const noexcept {
+ return IsTTY() ? "\033[22;39m" : "";
+}
+
+TStringBuf TColors::BoldColor() const noexcept {
+ return IsTTY() ? "\033[1m" : "";
+}
+
+TStringBuf TColors::BlackColor() const noexcept {
+ return IsTTY() ? "\033[22;30m" : "";
+}
+
+TStringBuf TColors::BlueColor() const noexcept {
+ return IsTTY() ? "\033[22;34m" : "";
+}
+
+TStringBuf TColors::GreenColor() const noexcept {
+ return IsTTY() ? "\033[22;32m" : "";
+}
+
+TStringBuf TColors::CyanColor() const noexcept {
+ return IsTTY() ? "\033[22;36m" : "";
+}
+
+TStringBuf TColors::RedColor() const noexcept {
+ return IsTTY() ? "\033[22;31m" : "";
+}
+
+TStringBuf TColors::PurpleColor() const noexcept {
+ return IsTTY() ? "\033[22;35m" : "";
+}
+
+TStringBuf TColors::BrownColor() const noexcept {
+ return IsTTY() ? "\033[22;33m" : "";
+}
+
+TStringBuf TColors::LightGrayColor() const noexcept {
+ return IsTTY() ? "\033[22;37m" : "";
+}
+
+TStringBuf TColors::DarkGrayColor() const noexcept {
+ return IsTTY() ? "\033[1;30m" : "";
+}
+
+TStringBuf TColors::LightBlueColor() const noexcept {
+ return IsTTY() ? "\033[1;34m" : "";
+}
+
+TStringBuf TColors::LightGreenColor() const noexcept {
+ return IsTTY() ? "\033[1;32m" : "";
+}
+
+TStringBuf TColors::LightCyanColor() const noexcept {
+ return IsTTY() ? "\033[1;36m" : "";
+}
+
+TStringBuf TColors::LightRedColor() const noexcept {
+ return IsTTY() ? "\033[1;31m" : "";
+}
+
+TStringBuf TColors::LightPurpleColor() const noexcept {
+ return IsTTY() ? "\033[1;35m" : "";
+}
+
+TStringBuf TColors::YellowColor() const noexcept {
+ return IsTTY() ? "\033[1;33m" : "";
+}
+
+TStringBuf TColors::WhiteColor() const noexcept {
+ return IsTTY() ? "\033[1;37m" : "";
+}
+
+
+namespace {
+ class TStdErrColors: public TColors {
+ public:
+ TStdErrColors()
+ : TColors(stderr)
+ {
+ }
+ };
+
+ class TStdOutColors: public TColors {
+ public:
+ TStdOutColors()
+ : TColors(stdout)
+ {
+ }
+ };
+
+ class TDisabledColors: public TColors {
+ public:
+ TDisabledColors()
+ : TColors(false)
+ {
+ }
+ };
+} // anonymous namespace
+
+TColors& NColorizer::StdErr() {
+ return *Singleton<TStdErrColors>();
+}
+
+TColors& NColorizer::StdOut() {
+ return *Singleton<TStdOutColors>();
+}
+
+TColors& NColorizer::AutoColors(IOutputStream& os) {
+ if (&os == &Cerr) {
+ return StdErr();
+ }
+ if (&os == &Cout) {
+ return StdOut();
+ }
+ return *Singleton<TDisabledColors>();
+}
+
+size_t NColorizer::TotalAnsiEscapeCodeLen(TStringBuf text) {
+ enum {
+ TEXT,
+ BEFORE_CODE,
+ IN_CODE,
+ } state = TEXT;
+
+ size_t totalLen = 0;
+ size_t curLen = 0;
+
+ for (auto it = text.begin(); it < text.end(); ++it) {
+ switch (state) {
+ case TEXT:
+ if (*it == '\033') {
+ state = BEFORE_CODE;
+ curLen = 1;
+ }
+ break;
+ case BEFORE_CODE:
+ if (*it == '[') {
+ state = IN_CODE;
+ curLen++;
+ } else {
+ state = TEXT;
+ }
+ break;
+ case IN_CODE:
+ if (*it == ';' || isdigit(*it)) {
+ curLen++;
+ } else {
+ if (*it == 'm') {
+ totalLen += curLen + 1;
+ }
+ state = TEXT;
+ }
+ break;
+ }
+ }
+
+ return totalLen;
+}
diff --git a/library/cpp/colorizer/colors.h b/library/cpp/colorizer/colors.h
new file mode 100644
index 0000000000..474a918994
--- /dev/null
+++ b/library/cpp/colorizer/colors.h
@@ -0,0 +1,228 @@
+#pragma once
+
+#include "fwd.h"
+
+#include <util/generic/string.h>
+#include <util/generic/strbuf.h>
+
+#include <cstdio>
+
+namespace NColorizer {
+ /**
+ * List of ECMA-48 colors.
+ *
+ * When printing elements of this enum via `operator<<`, `AutoColors()` (see below) function will be used
+ * to produce colors, i.e. nothing will be printed to non-tty streams. When converting elements of this enum
+ * via `ToString`, escape code is always returned.
+ *
+ * Note: as of now (2019-03), `ya make` strips out some escape codes from compiler output.
+ * It also inserts `RESET` before each color code. See https://st.yandex-team.ru/DEVTOOLS-5269 for details.
+ * For now, do not use `OLD`, `ST_*`, `FG_*` and `BG_*` in tools that run through `ya make`.
+ *
+ * Note: refrain from using black colors because there's high chance they'll not be visible on some terminals.
+ * Default windows and ubuntu color schemes shows them as black letters on black background.
+ * Also, white colors are barely visible in default OSX color scheme. Light black is usually fine though.
+ */
+ enum EAnsiCode: i8 {
+ // Note: not using `GENERATE_ENUM_SERIALIZATION` because serialization generator depends on this library.
+
+ /// Does not change anything.
+ INVALID,
+
+ /// Reset all styles and colors. Safe to use in `ya make` tools.
+ RESET,
+
+ /// Change style, don't change anything else.
+ ST_LIGHT,
+ ST_DARK,
+ ST_NORMAL,
+
+ /// Additional styles.
+ ITALIC_ON,
+ ITALIC_OFF,
+ UNDERLINE_ON,
+ UNDERLINE_OFF,
+
+ /// Change foreground color, don't change anything else.
+ FG_DEFAULT,
+ FG_BLACK,
+ FG_RED,
+ FG_GREEN,
+ FG_YELLOW,
+ FG_BLUE,
+ FG_MAGENTA,
+ FG_CYAN,
+ FG_WHITE,
+
+ /// Change background color, don't change anything else.
+ BG_DEFAULT,
+ BG_BLACK,
+ BG_RED,
+ BG_GREEN,
+ BG_YELLOW,
+ BG_BLUE,
+ BG_MAGENTA,
+ BG_CYAN,
+ BG_WHITE,
+
+ /// Reset all styles and colors, then enable a (possibly light or dark) color. Safe to use in `ya make` tools.
+ DEFAULT,
+ BLACK,
+ RED,
+ GREEN,
+ YELLOW,
+ BLUE,
+ MAGENTA,
+ CYAN,
+ WHITE,
+ LIGHT_DEFAULT,
+ LIGHT_BLACK,
+ LIGHT_RED,
+ LIGHT_GREEN,
+ LIGHT_YELLOW,
+ LIGHT_BLUE,
+ LIGHT_MAGENTA,
+ LIGHT_CYAN,
+ LIGHT_WHITE,
+ DARK_DEFAULT,
+ DARK_BLACK,
+ DARK_RED,
+ DARK_GREEN,
+ DARK_YELLOW,
+ DARK_BLUE,
+ DARK_MAGENTA,
+ DARK_CYAN,
+ DARK_WHITE,
+ };
+
+ /**
+ * Produces escape codes or empty stringbuf depending on settings.
+ * All color functions return zero-terminated stringbuf.
+ */
+ class TColors {
+ public:
+ static bool CalcIsTTY(FILE* file);
+
+ public:
+ explicit TColors(FILE* = stderr);
+ explicit TColors(bool ontty);
+
+ TStringBuf Reset() const noexcept;
+
+ TStringBuf StyleLight() const noexcept;
+ TStringBuf StyleDark() const noexcept;
+ TStringBuf StyleNormal() const noexcept;
+
+ TStringBuf ItalicOn() const noexcept;
+ TStringBuf ItalicOff() const noexcept;
+ TStringBuf UnderlineOn() const noexcept;
+ TStringBuf UnderlineOff() const noexcept;
+
+ TStringBuf ForeDefault() const noexcept;
+ TStringBuf ForeBlack() const noexcept;
+ TStringBuf ForeRed() const noexcept;
+ TStringBuf ForeGreen() const noexcept;
+ TStringBuf ForeYellow() const noexcept;
+ TStringBuf ForeBlue() const noexcept;
+ TStringBuf ForeMagenta() const noexcept;
+ TStringBuf ForeCyan() const noexcept;
+ TStringBuf ForeWhite() const noexcept;
+
+ TStringBuf BackDefault() const noexcept;
+ TStringBuf BackBlack() const noexcept;
+ TStringBuf BackRed() const noexcept;
+ TStringBuf BackGreen() const noexcept;
+ TStringBuf BackYellow() const noexcept;
+ TStringBuf BackBlue() const noexcept;
+ TStringBuf BackMagenta() const noexcept;
+ TStringBuf BackCyan() const noexcept;
+ TStringBuf BackWhite() const noexcept;
+
+ TStringBuf Default() const noexcept;
+ TStringBuf Black() const noexcept;
+ TStringBuf Red() const noexcept;
+ TStringBuf Green() const noexcept;
+ TStringBuf Yellow() const noexcept;
+ TStringBuf Blue() const noexcept;
+ TStringBuf Magenta() const noexcept;
+ TStringBuf Cyan() const noexcept;
+ TStringBuf White() const noexcept;
+
+ TStringBuf LightDefault() const noexcept;
+ TStringBuf LightBlack() const noexcept;
+ TStringBuf LightRed() const noexcept;
+ TStringBuf LightGreen() const noexcept;
+ TStringBuf LightYellow() const noexcept;
+ TStringBuf LightBlue() const noexcept;
+ TStringBuf LightMagenta() const noexcept;
+ TStringBuf LightCyan() const noexcept;
+ TStringBuf LightWhite() const noexcept;
+
+ TStringBuf DarkDefault() const noexcept;
+ TStringBuf DarkBlack() const noexcept;
+ TStringBuf DarkRed() const noexcept;
+ TStringBuf DarkGreen() const noexcept;
+ TStringBuf DarkYellow() const noexcept;
+ TStringBuf DarkBlue() const noexcept;
+ TStringBuf DarkMagenta() const noexcept;
+ TStringBuf DarkCyan() const noexcept;
+ TStringBuf DarkWhite() const noexcept;
+
+ /// Compatibility; prefer using methods without `Color` suffix in their names.
+ /// Note: these behave differently from their un-suffixed counterparts.
+ /// While functions declared above will reset colors completely, these will only reset foreground color and
+ /// style, without changing the background color and underline/italic settings. Also, names of these functions
+ /// don't conform with standard, e.g. `YellowColor` actually emits the `lite yellow` escape code.
+ TStringBuf OldColor() const noexcept;
+ TStringBuf BoldColor() const noexcept;
+ TStringBuf BlackColor() const noexcept;
+ TStringBuf BlueColor() const noexcept;
+ TStringBuf GreenColor() const noexcept;
+ TStringBuf CyanColor() const noexcept;
+ TStringBuf RedColor() const noexcept;
+ TStringBuf PurpleColor() const noexcept;
+ TStringBuf BrownColor() const noexcept;
+ TStringBuf LightGrayColor() const noexcept;
+ TStringBuf DarkGrayColor() const noexcept;
+ TStringBuf LightBlueColor() const noexcept;
+ TStringBuf LightGreenColor() const noexcept;
+ TStringBuf LightCyanColor() const noexcept;
+ TStringBuf LightRedColor() const noexcept;
+ TStringBuf LightPurpleColor() const noexcept;
+ TStringBuf YellowColor() const noexcept;
+ TStringBuf WhiteColor() const noexcept;
+
+ inline bool IsTTY() const noexcept {
+ return IsTTY_;
+ }
+
+ inline void SetIsTTY(bool value) noexcept {
+ IsTTY_ = value;
+ }
+
+ inline void Enable() noexcept {
+ SetIsTTY(true);
+ }
+
+ inline void Disable() noexcept {
+ SetIsTTY(false);
+ }
+
+ private:
+ bool IsTTY_;
+ };
+
+ /// Singletone `TColors` instances for stderr/stdout.
+ TColors& StdErr();
+ TColors& StdOut();
+
+ /// Choose `TColors` depending on output stream. If passed stream is stderr/stdout, return a corresponding
+ /// singletone. Otherwise, return a disabled singletone (which you can, but should *not* enable).
+ TColors& AutoColors(IOutputStream& os);
+
+ /// Calculate total length of all ANSI escape codes in the text.
+ size_t TotalAnsiEscapeCodeLen(TStringBuf text);
+}
+
+TStringBuf ToStringBuf(NColorizer::EAnsiCode x);
+TString ToString(NColorizer::EAnsiCode x);
diff --git a/library/cpp/colorizer/fwd.h b/library/cpp/colorizer/fwd.h
new file mode 100644
index 0000000000..d71efdc053
--- /dev/null
+++ b/library/cpp/colorizer/fwd.h
@@ -0,0 +1,11 @@
+#pragma once
+
+class IOutputStream;
+
+namespace NColorizer {
+ class TColors;
+
+ TColors& StdErr();
+ TColors& StdOut();
+ TColors& AutoColors(IOutputStream&);
+}
diff --git a/library/cpp/colorizer/output.cpp b/library/cpp/colorizer/output.cpp
new file mode 100644
index 0000000000..66a5626675
--- /dev/null
+++ b/library/cpp/colorizer/output.cpp
@@ -0,0 +1,10 @@
+#include "output.h"
+
+#include <util/stream/output.h>
+
+using namespace NColorizer;
+
+template <>
+void Out<TColorHandle>(IOutputStream& o, const TColorHandle& h) {
+ o << (*(h.C).*h.F)();
+}
diff --git a/library/cpp/colorizer/output.h b/library/cpp/colorizer/output.h
new file mode 100644
index 0000000000..99afbd3427
--- /dev/null
+++ b/library/cpp/colorizer/output.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include "colors.h"
+
+// Note: this is an old interface for printing colors to stream.
+// Consider printing elements of `EAnsiCode` directly.
+
+namespace NColorizer {
+ typedef TStringBuf (TColors::*TColorFunc)() const;
+
+ struct TColorHandle {
+ const TColors* C;
+ TColorFunc F;
+
+ inline TColorHandle(const TColors* c, TColorFunc f) noexcept
+ : C(c)
+ , F(f)
+ {
+ }
+ };
+
+#define DEF(X) \
+ static inline TColorHandle X() noexcept { \
+ return TColorHandle(&StdErr(), &TColors::X##Color); \
+ }
+
+ DEF(Old)
+ DEF(Black)
+ DEF(Green)
+ DEF(Cyan)
+ DEF(Red)
+ DEF(Purple)
+ DEF(Brown)
+ DEF(LightGray)
+ DEF(DarkGray)
+ DEF(LightBlue)
+ DEF(LightGreen)
+ DEF(LightCyan)
+ DEF(LightRed)
+ DEF(LightPurple)
+ DEF(Yellow)
+ DEF(White)
+
+#undef DEF
+}
diff --git a/library/cpp/colorizer/ut/colorizer_ut.cpp b/library/cpp/colorizer/ut/colorizer_ut.cpp
new file mode 100644
index 0000000000..20341440af
--- /dev/null
+++ b/library/cpp/colorizer/ut/colorizer_ut.cpp
@@ -0,0 +1,63 @@
+#include <library/cpp/colorizer/colors.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/stream/str.h>
+
+#include <util/string/escape.h>
+
+Y_UNIT_TEST_SUITE(ColorizerTest) {
+ Y_UNIT_TEST(BasicTest) {
+ NColorizer::TColors colors;
+ colors.Enable();
+ UNIT_ASSERT_STRINGS_EQUAL(EscapeC(colors.BlueColor()), "\\x1B[22;34m");
+ UNIT_ASSERT_STRINGS_EQUAL(EscapeC(colors.ForeBlue()), "\\x1B[34m");
+ colors.Disable();
+ UNIT_ASSERT(colors.BlueColor().Empty());
+ }
+
+ Y_UNIT_TEST(ResettingTest) {
+ NColorizer::TColors colors;
+ colors.Enable();
+ // 22;39, not 0, should be used so that only foreground changes
+ UNIT_ASSERT_STRINGS_EQUAL(EscapeC(colors.OldColor()), "\\x1B[22;39m");
+ UNIT_ASSERT_STRINGS_EQUAL(EscapeC(colors.Reset()), "\\x1B[0m");
+ // 22, not 0, should be used to reset boldness
+ UNIT_ASSERT_STRINGS_EQUAL(EscapeC(colors.PurpleColor()), "\\x1B[22;35m");
+ }
+
+ Y_UNIT_TEST(PrintAnsi) {
+ UNIT_ASSERT_STRINGS_EQUAL(EscapeC(ToString(NColorizer::BLUE)), "\\x1B[0m\\x1B[0;34m");
+ {
+ TString str;
+ TStringOutput sink{str};
+
+ sink << NColorizer::BLUE << "foo!" << NColorizer::RESET;
+
+ UNIT_ASSERT_STRINGS_EQUAL(EscapeC(str), "foo!"); // TStringOutput is not tty
+ }
+ {
+ TString str;
+ TStringOutput sink{str};
+
+ // Enable this for test purposes. If you're making output of the `AutoColors` constant and this
+ // test does not compile, you're free to remove it.
+ NColorizer::AutoColors(sink).Enable();
+
+ sink << NColorizer::BLUE << "foo!" << NColorizer::RESET;
+
+ UNIT_ASSERT_STRINGS_EQUAL(EscapeC(str), "\\x1B[0m\\x1B[0;34mfoo!\\x1B[0m"); // TStringOutput is not tty
+ }
+ }
+
+ Y_UNIT_TEST(EscapeCodeLen) {
+ UNIT_ASSERT_VALUES_EQUAL(NColorizer::TotalAnsiEscapeCodeLen("some text"), 0);
+ UNIT_ASSERT_VALUES_EQUAL(NColorizer::TotalAnsiEscapeCodeLen("some\033[0m text"), 4);
+ UNIT_ASSERT_VALUES_EQUAL(NColorizer::TotalAnsiEscapeCodeLen("\033[0msome text"), 4);
+ UNIT_ASSERT_VALUES_EQUAL(NColorizer::TotalAnsiEscapeCodeLen("some text\033[0m"), 4);
+ UNIT_ASSERT_VALUES_EQUAL(NColorizer::TotalAnsiEscapeCodeLen("some\033[0;1;2;3m text"), 10);
+ UNIT_ASSERT_VALUES_EQUAL(NColorizer::TotalAnsiEscapeCodeLen("some\033[0;1;2;3 text"), 0);
+ UNIT_ASSERT_VALUES_EQUAL(NColorizer::TotalAnsiEscapeCodeLen("some\0330;1;2;3m text"), 0);
+ UNIT_ASSERT_VALUES_EQUAL(NColorizer::TotalAnsiEscapeCodeLen("some [0;1;2;3m text"), 0);
+ UNIT_ASSERT_VALUES_EQUAL(NColorizer::TotalAnsiEscapeCodeLen("some\033[m text"), 3);
+ }
+}
diff --git a/library/cpp/colorizer/ut/ya.make b/library/cpp/colorizer/ut/ya.make
new file mode 100644
index 0000000000..8a28c189af
--- /dev/null
+++ b/library/cpp/colorizer/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/colorizer)
+
+OWNER(pg)
+
+SRCS(
+ colorizer_ut.cpp
+)
+
+END()
diff --git a/library/cpp/colorizer/ya.make b/library/cpp/colorizer/ya.make
new file mode 100644
index 0000000000..141edb2797
--- /dev/null
+++ b/library/cpp/colorizer/ya.make
@@ -0,0 +1,10 @@
+LIBRARY()
+
+OWNER(pg)
+
+SRCS(
+ colors.cpp
+ output.cpp
+)
+
+END()
diff --git a/library/cpp/compproto/bit.h b/library/cpp/compproto/bit.h
new file mode 100644
index 0000000000..6a421b65f7
--- /dev/null
+++ b/library/cpp/compproto/bit.h
@@ -0,0 +1,348 @@
+#pragma once
+
+#include <util/generic/array_ref.h>
+#include <util/generic/vector.h>
+#include <util/stream/output.h>
+#include <util/stream/input.h>
+
+#include "huff.h"
+#include "compressor.h"
+#include "metainfo.h"
+
+namespace NCompProto {
+ struct TBitBuffer {
+ TVector<ui8> Out;
+ ui64 Position;
+ ui64 Size;
+ ui8 Counter;
+ TBitBuffer() {
+ Clear();
+ }
+
+ static ui64 Read(const ui8* out, ui64 position, size_t size) {
+ const ui8* dst = out + (size_t(position >> 3));
+ ui64 outCode = *reinterpret_cast<const ui64*>(dst);
+ ui8 shift = position & 7;
+ return ((1ULL << size) - 1) & (outCode >> shift);
+ }
+
+ ui64 Read(ui64 position, size_t size) {
+ return Read(&Out[0], position, size);
+ }
+
+ void Code(ui64 value, size_t size) {
+ if (++Counter == 0) {
+ Junk(257 * 64);
+ }
+ Position = Code(value, size, Position);
+ }
+ ui64 Code(ui64 value, size_t size, ui64 position) {
+ ui8* dst = &Out[size_t(position >> 3)];
+ ui64& outCode = *(ui64*)dst;
+ ui8 shift = position & 7;
+ ui64 mask = ((1ULL << size) - 1) << shift;
+ outCode = ((value << shift) & mask) | (outCode & ~mask);
+ return position + size;
+ }
+ void Junk(size_t junk = 1024) {
+ size_t need = size_t(Position >> 3);
+ if (Out.size() * 8 < Position + junk) {
+ Out.resize(((need + junk) * 3) / 2);
+ Size = Out.size();
+ }
+ }
+ void Insert(ui64 value, ui64 position, size_t size) {
+ ui64 newVal = Read(position, 56);
+ position = Code(value, size, position);
+ value = newVal;
+
+ while (position < Position + 64) {
+ newVal = Read(position + 56 - size, 56);
+ position = Code(value, 56, position);
+ value = newVal;
+ }
+
+ Position += size;
+ }
+
+ size_t ByteLength() const {
+ return (Position + 7) / 8;
+ }
+
+ void ResetPosition() {
+ Position = 0;
+ Size = 0;
+ }
+
+ void Clear() {
+ Counter = 0;
+ Position = 0;
+ Size = 0;
+ Out.clear();
+ Junk();
+ }
+
+ TArrayRef<const char> AsDataRegion() const {
+ return TArrayRef<const char>(reinterpret_cast<const char*>(Out.data()), ByteLength());
+ }
+ };
+
+ struct THuff {
+ TCoder Coder;
+ ui64 Position;
+ THuff() {
+ Position = (ui64)(-1);
+ }
+ void Load(IInputStream& stream) {
+ TString name;
+ Coder.InitDefault();
+ Coder.Entries.clear();
+ while (1) {
+ stream >> name;
+ if (name == "end")
+ return;
+ else if (name == "entry") {
+ TCoderEntry entry;
+ ui32 value;
+ stream >> value;
+ entry.MinValue = value;
+ stream >> value;
+ entry.Prefix = value;
+ stream >> value;
+ entry.PrefixBits = value;
+ stream >> value;
+ entry.AllBits = value;
+ Coder.Entries.push_back(entry);
+ }
+ }
+ }
+
+ void Save(IOutputStream& stream, TString offset) {
+ TString step = " ";
+ for (size_t i = 0; i < Coder.Entries.size(); ++i) {
+ stream << offset << step << "entry ";
+ stream << (ui32)Coder.Entries[i].MinValue << " ";
+ stream << (ui32)Coder.Entries[i].Prefix << " ";
+ stream << (ui32)Coder.Entries[i].PrefixBits << " ";
+ stream << (ui32)Coder.Entries[i].AllBits << " ";
+ stream << Endl;
+ }
+ stream << offset << "end" << Endl;
+ }
+
+ void BeginElement(TBitBuffer& out) {
+ Position = out.Position;
+ }
+ void Add(ui32 value, TBitBuffer& out) {
+ size_t val = 0;
+ ui64 code = Coder.Code(value, val);
+ out.Code(code, val);
+ }
+ void AddDelayed(ui32 value, TBitBuffer& out) {
+ size_t val = 0;
+ ui64 code = Coder.Code(value, val);
+ if (Position == (ui64)(-1)) {
+ ythrow yexception() << "Position == (ui64)(-1)";
+ }
+ out.Insert(code, Position, val);
+ out.Junk();
+ }
+ };
+
+ struct THist {
+ TAccum Accum;
+ THist() {
+ }
+
+ void Load(IInputStream& stream) {
+ TString name;
+ while (1) {
+ stream >> name;
+ if (name == "end")
+ return;
+ }
+ }
+ // TODO: why not const TString& ???
+ void Save(IOutputStream& /*stream*/, TString /*offset*/) {
+ }
+
+ void Add(ui32 value, TEmpty& /*empty*/) {
+ Accum.Add(value);
+ }
+ void AddDelayed(ui32 value, TEmpty& /*empty*/) {
+ Accum.Add(value);
+ }
+ void BeginElement(TEmpty& /*empty*/) {
+ }
+ };
+
+ struct THistToHuff {
+ static THistToHuff Instance() {
+ return THistToHuff();
+ }
+ TEmpty Build() const {
+ return TEmpty();
+ }
+ void Build(THuff& info, const THist& hist) const {
+ Analyze(hist.Accum, info.Coder.Entries);
+ info.Coder.Normalize();
+ }
+ };
+
+ struct IDecompressor {
+ // sequentially decompresses whole structure according to metainfo, starts at position offset
+ virtual void Decompress(const TMetaInfo<TTable>* table, const ui8* codes, ui64& offset) = 0;
+ // decompresses one record of outer repeated structure starting at position offset
+ virtual void DecompressOne(const TMetaInfo<TTable>* table, const ui8* codes, ui64& offset, ui32 prevIndex = -1) = 0;
+ virtual ~IDecompressor() = default;
+ };
+
+ template <class X>
+ struct TMetaIterator: public IDecompressor {
+ X Self;
+ TMetaIterator() {
+ Self.Parent = this;
+ }
+
+ private:
+ inline void DecompressSingle(ui32 repeatedIndex, const TMetaInfo<TTable>* table, const ui8* codes, ui64& offset) {
+ Self.BeginElement(repeatedIndex);
+ ui32 mask = table->Mask.Decompress(codes, offset);
+ size_t index = 0;
+ ui32 scalarMask = table->ScalarMask;
+ while (mask || scalarMask) {
+ if (mask & 1) {
+ if (scalarMask & 1) {
+ ui32 val = table->Scalar[index].Decompress(codes, offset);
+ Self.SetScalar(index, val);
+ } else {
+ Self.GetDecompressor(index).Decompress(table->Repeated[index].Get(), codes, offset);
+ }
+ } else if ((scalarMask & 1) && table->Default[index].Type == TScalarDefaultValue::Fixed) {
+ Self.SetScalar(index, table->Default[index].Value);
+ }
+ scalarMask = scalarMask >> 1;
+ mask = mask >> 1;
+ ++index;
+ }
+ Self.EndElement();
+ }
+
+ inline void DecompressSingleScalarsOnly(ui32 repeatedIndex, const TMetaInfo<TTable>* table, const ui8* codes, ui64& offset) {
+ Self.BeginElement(repeatedIndex);
+ ui32 mask = table->Mask.Decompress(codes, offset);
+ ui32 scalarMask = table->ScalarMask;
+ size_t index = 0;
+ while (scalarMask) {
+ if (mask & 1) {
+ ui32 val = table->Scalar[index].Decompress(codes, offset);
+ Self.SetScalar(index, val);
+ } else if (table->Default[index].Type == TScalarDefaultValue::Fixed) {
+ Self.SetScalar(index, table->Default[index].Value);
+ }
+ mask = mask >> 1;
+ scalarMask = scalarMask >> 1;
+ ++index;
+ }
+ Self.EndElement();
+ }
+
+ public:
+ void Decompress(const TMetaInfo<TTable>* table, const ui8* codes, ui64& offset) override {
+ ui64 locOffset = offset;
+ ui32 count = table->Count.Decompress(codes, locOffset);
+ ui32 repeatedIndex = (ui32)(-1);
+ Self.BeginSelf(count, table->Id);
+ if (table->RepeatedMask) {
+ for (ui32 i = 0; i < count; ++i) {
+ repeatedIndex += table->Index.Decompress(codes, locOffset);
+ DecompressSingle(repeatedIndex, table, codes, locOffset);
+ }
+ } else {
+ for (ui32 i = 0; i < count; ++i) {
+ repeatedIndex += table->Index.Decompress(codes, locOffset);
+ DecompressSingleScalarsOnly(repeatedIndex, table, codes, locOffset);
+ }
+ }
+ offset = locOffset;
+ Self.EndSelf();
+ }
+
+ // XXX: iterator needed?
+ //
+ // Following two functions serves the purpose of decompressing outer repeated-structure(such structure is mandatory now).
+ // They can work for inner repeated structures too, if you supply correct table, codes and offset parameters.
+ void DecompressOne(const TMetaInfo<TTable>* table, const ui8* codes, ui64& offset, ui32 prevIndex = -1) override {
+ table->Index.Decompress(codes, offset);
+ DecompressSingle(prevIndex, table, codes, offset);
+ }
+
+ ui32 DecompressCount(const TMetaInfo<TTable>* table, const ui8* codes, ui64& offset) {
+ return table->Count.Decompress(codes, offset);
+ }
+ };
+
+ template <class X>
+ struct TParentHold {
+ TMetaIterator<X>* Parent;
+ TParentHold()
+ : Parent(nullptr)
+ {
+ }
+ };
+
+ struct TEmptyDecompressor: public TParentHold<TEmptyDecompressor> {
+ void BeginSelf(ui32 /*count*/, ui32 /*id*/) {
+ }
+ void EndSelf() {
+ }
+ void BeginElement(ui32 /*element*/) {
+ }
+ void EndElement() {
+ }
+ void SetScalar(size_t /*index*/, ui32 /*val*/) {
+ }
+ TMetaIterator<TEmptyDecompressor>& GetDecompressor(size_t index) {
+ Y_UNUSED(index);
+ return *Parent;
+ }
+ };
+
+ inline TMetaIterator<TEmptyDecompressor>& GetEmptyDecompressor() {
+ static TMetaIterator<TEmptyDecompressor> empty;
+ return empty;
+ }
+
+ struct THuffToTable {
+ static THuffToTable Instance() {
+ return THuffToTable();
+ }
+ void Build(TTable& table, const THuff& huff) const {
+ // can happen if a field was never serialized across whole structure
+ if (huff.Coder.Entries.empty())
+ return;
+ for (ui32 i = 0; i < 64; ++i) {
+ const TCoderEntry& entry = huff.Coder.GetEntry(i, table.Id[i]);
+ table.CodeBase[i] = entry.MinValue;
+ table.PrefLength[i] = entry.PrefixBits;
+ table.CodeMask[i] = (1ULL << (entry.AllBits - entry.PrefixBits)) - 1ULL;
+ table.Length[i] = entry.AllBits;
+ }
+ }
+ };
+
+ struct THuffToTableWithDecompressor: private THuffToTable {
+ TSimpleSharedPtr<IDecompressor> Decompressor;
+ THuffToTableWithDecompressor(TSimpleSharedPtr<IDecompressor> decompressor)
+ : Decompressor(decompressor)
+ {
+ }
+ TSimpleSharedPtr<IDecompressor> Build() const {
+ return Decompressor;
+ }
+ void Build(TTable& table, const THuff& huff) const {
+ THuffToTable::Build(table, huff);
+ }
+ };
+
+}
diff --git a/library/cpp/compproto/compproto_ut.cpp b/library/cpp/compproto/compproto_ut.cpp
new file mode 100644
index 0000000000..9393be967a
--- /dev/null
+++ b/library/cpp/compproto/compproto_ut.cpp
@@ -0,0 +1,543 @@
+#include "huff.h"
+#include "metainfo.h"
+#include "bit.h"
+
+#include <util/generic/vector.h>
+#include <util/generic/map.h>
+#include <util/system/protect.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+static ui64 gSeed = 42;
+
+static void FlushPseudoRandom() {
+ gSeed = 42;
+}
+
+static ui32 PseudoRandom(ui32 max) {
+ // stupid and non-threadsafe, but very predictable chaos generator
+ gSeed += 1;
+ gSeed *= 419;
+ gSeed = gSeed ^ (ui64(max) << 17);
+ return gSeed % max;
+};
+
+enum ECompMode {
+ CM_SINGLEPASS,
+ CM_TWOPASS
+};
+
+struct TTestParams {
+ size_t DataSize;
+ ui32 ValueArraySize;
+};
+
+template <typename X>
+void TestSaveLoadMeta(NCompProto::TMetaInfo<X>& src) {
+ TStringStream ss;
+ src.Save(ss);
+ TString data = ss.Str();
+ NCompProto::TMetaInfo<X> loadedMeta(data);
+ ss = TStringStream();
+ loadedMeta.Save(ss);
+ UNIT_ASSERT_EQUAL(ss.Str(), data);
+}
+
+template <typename TDecompressor, template <typename, typename> class TSerialize>
+void TestWithParams(const TString& metainfo, const ECompMode mode, const TTestParams& params) {
+ using namespace NCompProto;
+ FlushPseudoRandom();
+
+ TStringInput stream(metainfo);
+
+ THolder<TMetaInfo<THuff>> meta;
+ if (mode == CM_TWOPASS) {
+ TMetaInfo<THist> hist(stream);
+ TEmpty empty;
+ TSerialize<THist, TEmpty>::Serialize(hist, empty, params);
+ meta.Reset(new TMetaInfo<THuff>(hist, THistToHuff::Instance()));
+ } else {
+ meta.Reset(new TMetaInfo<THuff>(stream));
+ }
+ TestSaveLoadMeta(*meta.Get());
+
+ TBitBuffer buffer;
+ TSerialize<THuff, TBitBuffer>::Serialize(*meta, buffer, params);
+
+ ui64 codedSize = buffer.Position;
+
+ TMetaInfo<TTable> decompressor(*meta, THuffToTable::Instance());
+
+ // verify that no memory read beyond buffer occurs
+ const size_t byteSize = buffer.ByteLength();
+ const size_t PAGESIZEX = 4096;
+ const size_t busyPages = (byteSize + (PAGESIZEX - 1)) / PAGESIZEX;
+ const size_t allPages = busyPages + 1;
+ const size_t allocSize = (allPages + 1) * PAGESIZEX;
+ TVector<ui8> readBuffer(allocSize);
+ ui8* start = &readBuffer[0];
+ ui8* pageStart = reinterpret_cast<ui8*>((size_t(start) + PAGESIZEX) & ~(PAGESIZEX - 1));
+ // XX DATA DATA DATA DATA PROT
+ // | | | | | pages
+ // calculate dataStart so that data ends exactly at the page end
+ ui8* dataStart = pageStart + busyPages * PAGESIZEX - byteSize;
+ ui8* dataEnd = pageStart + busyPages * PAGESIZEX;
+ ProtectMemory(dataEnd, PAGESIZEX, PM_NONE);
+ // memory copying should be performed without any problems
+ memcpy(dataStart, buffer.Out.data(), byteSize);
+
+ ui64 position = 0;
+ TMetaIterator<TDecompressor> instance;
+ // we should not read beyond dataEnd here
+ instance.Decompress(&decompressor, dataStart, position);
+ const ui64 decodedSize = position;
+ UNIT_ASSERT_EQUAL(codedSize, decodedSize);
+ // unprotect memory
+ ProtectMemory(dataEnd, PAGESIZEX, PM_READ | PM_WRITE | PM_EXEC);
+}
+
+template <typename TDecompressor, template <typename, typename> class TSerialize>
+void Test(const TString& metainfo, const ECompMode mode) {
+ for (size_t ds = 3; ds < 42; ds += (3 + PseudoRandom(5))) {
+ for (size_t vas = 5; vas < 42; vas += (4 + PseudoRandom(10))) {
+ TTestParams params;
+ params.DataSize = ds;
+ params.ValueArraySize = vas;
+ TestWithParams<TDecompressor, TSerialize>(metainfo, mode, params);
+ }
+ }
+}
+
+Y_UNIT_TEST_SUITE(CompProtoTestBasic) {
+ using namespace NCompProto;
+
+ const TString metainfo =
+ "\n\
+ repeated data id 0\n\
+ scalar clicks id 0 default const 0\n\
+ scalar shows id 1 default const 0\n\
+ repeated regClicks id 2\n\
+ scalar clicks id 0 default const 0\n\
+ scalar shows id 1 default const 0\n\
+ end\n\
+ scalar extra id 31 default const 0\n\
+ end\n";
+
+ struct TRegInfo {
+ ui32 Clicks;
+ ui32 Shows;
+ };
+
+ struct TData {
+ ui32 Clicks;
+ ui32 Shows;
+ ui32 Extra;
+ TMap<ui32, TRegInfo> RegClicks;
+ };
+
+ TVector<TData> data;
+
+ template <class TMeta, class TFunctor>
+ struct TSerialize {
+ static void Serialize(TMetaInfo<TMeta>& meta, TFunctor& functor, const TTestParams& params) {
+ FlushPseudoRandom();
+ meta.BeginSelf(functor);
+ data.clear();
+ data.resize(params.DataSize);
+ for (ui32 i = 0; i < params.DataSize; ++i) {
+ meta.BeginElement(i, functor);
+
+ data[i].Clicks = PseudoRandom(16) + 100;
+ data[i].Shows = PseudoRandom(500) * PseudoRandom(16);
+ data[i].Extra = PseudoRandom(500) + (1UL << 31); // test also saving of big values
+ meta.SetScalar(0, data[i].Clicks, functor);
+ meta.SetScalar(1, data[i].Shows, functor);
+
+ TMetaInfo<TMeta>& regClicks = meta.BeginRepeated(2, functor);
+ for (ui32 j = 0; j < PseudoRandom(200); j += 1 + PseudoRandom(10)) {
+ regClicks.BeginElement(j, functor);
+ TRegInfo& r = data[i].RegClicks[j];
+
+ r.Clicks = PseudoRandom(2);
+ r.Shows = PseudoRandom(800) * PseudoRandom(8) + 56;
+ regClicks.SetScalar(0, r.Clicks, functor);
+ regClicks.SetScalar(1, r.Shows, functor);
+
+ regClicks.EndElement(functor);
+ }
+ regClicks.EndRepeated(functor);
+ meta.SetScalar(31, data[i].Extra, functor);
+ meta.EndElement(functor);
+ }
+ meta.EndRepeated(functor);
+ }
+ };
+
+ struct TMultiDecompressor: public TParentHold<TMultiDecompressor> {
+ struct TRegClicks: public TParentHold<TRegClicks> {
+ const TData* Data;
+ const TRegInfo* Elem;
+ TRegClicks()
+ : Data(nullptr)
+ , Elem(nullptr)
+ {
+ }
+ void BeginSelf(ui32 /*count*/, ui32 /*id*/) {
+ }
+ void EndSelf() {
+ }
+ void BeginElement(ui32 element) {
+ TMap<ui32, TRegInfo>::const_iterator it = Data->RegClicks.find(element);
+ if (it == Data->RegClicks.end()) {
+ UNIT_ASSERT(0);
+ }
+ Elem = &it->second;
+ }
+ void EndElement() {
+ }
+ void SetScalar(size_t index, ui32 val) {
+ if (index == 0)
+ UNIT_ASSERT_EQUAL(val, Elem->Clicks);
+ if (index == 1)
+ UNIT_ASSERT_EQUAL(val, Elem->Shows);
+ }
+ IDecompressor& GetDecompressor(size_t) {
+ UNIT_ASSERT(0);
+ return GetEmptyDecompressor();
+ }
+ };
+
+ const TData* Elem;
+ TMetaIterator<TRegClicks> RegClicks;
+ void BeginSelf(ui32 /*count*/, ui32 /*id*/) {
+ }
+ void EndSelf() {
+ }
+ void BeginElement(ui32 element) {
+ UNIT_ASSERT(element < data.size());
+ Elem = &data[element];
+ }
+ void EndElement() {
+ }
+ void SetScalar(size_t index, ui32 val) {
+ if (index == 0)
+ UNIT_ASSERT_EQUAL(val, Elem->Clicks);
+ if (index == 1)
+ UNIT_ASSERT_EQUAL(val, Elem->Shows);
+ if (index == 31)
+ UNIT_ASSERT_EQUAL(val, Elem->Extra);
+ }
+ IDecompressor& GetDecompressor(size_t index) {
+ if (index == 2) {
+ RegClicks.Self.Data = Elem;
+ return RegClicks;
+ }
+ UNIT_ASSERT(0);
+ return GetEmptyDecompressor();
+ }
+ TMultiDecompressor()
+ : Elem(nullptr)
+ {
+ }
+ };
+
+ struct TVerifyingDecompressor: public TParentHold<TVerifyingDecompressor> {
+ enum EState {
+ Startstop,
+ OutDataElem,
+ InDataElem,
+ InRegClicks,
+ };
+ EState State;
+
+ ui32 DataInd;
+ TMap<ui32, TRegInfo>::iterator RegIter;
+
+ TMetaIterator<TVerifyingDecompressor>& GetDecompressor(size_t index) {
+ Y_UNUSED(index);
+ return *Parent;
+ }
+
+ TVerifyingDecompressor()
+ : State(Startstop)
+ , DataInd(0)
+ {
+ }
+ void BeginSelf(ui32 /*count*/, ui32 id) {
+ switch (State) {
+ case Startstop:
+ UNIT_ASSERT_EQUAL(id, 0);
+ State = OutDataElem;
+ break;
+ case OutDataElem:
+ UNIT_ASSERT(0);
+ case InDataElem:
+ UNIT_ASSERT_EQUAL(id, 2);
+ State = InRegClicks;
+ RegIter = data[DataInd].RegClicks.begin();
+ break;
+ case InRegClicks:
+ UNIT_ASSERT(0);
+ default:
+ UNIT_ASSERT(0);
+ }
+ }
+ void EndSelf() {
+ switch (State) {
+ case Startstop:
+ UNIT_ASSERT(0);
+ case OutDataElem:
+ State = Startstop;
+ break;
+ case InDataElem:
+ UNIT_ASSERT(0);
+ case InRegClicks:
+ UNIT_ASSERT_EQUAL(RegIter, data[DataInd].RegClicks.end());
+ State = InDataElem;
+ break;
+ default:
+ UNIT_ASSERT(0);
+ }
+ }
+ void BeginElement(ui32 element) {
+ switch (State) {
+ case Startstop:
+ UNIT_ASSERT(0);
+ case OutDataElem:
+ UNIT_ASSERT(element < data.size());
+ State = InDataElem;
+ break;
+ case InDataElem:
+ UNIT_ASSERT(0);
+ case InRegClicks:
+ UNIT_ASSERT_EQUAL(element, RegIter->first);
+ break;
+ }
+ }
+ void EndElement() {
+ switch (State) {
+ case Startstop:
+ UNIT_ASSERT(0);
+ case OutDataElem:
+ UNIT_ASSERT(0);
+ case InDataElem:
+ State = OutDataElem;
+ ++DataInd;
+ break;
+ case InRegClicks:
+ ++RegIter;
+ break;
+ }
+ }
+
+ void SetScalar(size_t index, ui32 val) {
+ switch (State) {
+ case OutDataElem:
+ UNIT_ASSERT(0);
+ case InDataElem:
+ if (index == 0)
+ UNIT_ASSERT_EQUAL(val, data[DataInd].Clicks);
+ if (index == 1)
+ UNIT_ASSERT_EQUAL(val, data[DataInd].Shows);
+ if (index == 31)
+ UNIT_ASSERT_EQUAL(val, data[DataInd].Extra);
+ break;
+ case InRegClicks:
+ if (index == 0)
+ UNIT_ASSERT_EQUAL(val, RegIter->second.Clicks);
+ if (index == 1)
+ UNIT_ASSERT_EQUAL(val, RegIter->second.Shows);
+ break;
+ default:
+ UNIT_ASSERT(0);
+ }
+ }
+ };
+
+ Y_UNIT_TEST(VerifyDecompression) {
+ Test<TVerifyingDecompressor, TSerialize>(metainfo, CM_SINGLEPASS);
+ }
+
+ Y_UNIT_TEST(VerifyHistDecompression) {
+ Test<TVerifyingDecompressor, TSerialize>(metainfo, CM_TWOPASS);
+ }
+
+ Y_UNIT_TEST(VerifyDecompressionMulti) {
+ Test<TMultiDecompressor, TSerialize>(metainfo, CM_SINGLEPASS);
+ }
+
+ Y_UNIT_TEST(VerifyHistDecompressionMulti) {
+ Test<TMultiDecompressor, TSerialize>(metainfo, CM_TWOPASS);
+ }
+}
+
+Y_UNIT_TEST_SUITE(CompProtoTestExtended) {
+ using namespace NCompProto;
+ const TString metainfo =
+ "\n\
+ repeated data id 0\n\
+ repeated second id 3\n\
+ scalar inner2 id 0 default const 0\n\
+ end\n\
+ repeated first id 2\n\
+ scalar inner id 0 default const 0\n\
+ end\n\
+ end\n";
+ TVector<std::pair<TVector<ui32>, TVector<ui32>>> data;
+
+ template <class TMeta, class TFunctor>
+ struct TSerialize {
+ static void Serialize(TMetaInfo<TMeta>& meta, TFunctor& functor, const TTestParams& params) {
+ FlushPseudoRandom();
+ meta.BeginSelf(functor);
+ data.clear();
+ data.resize(params.DataSize);
+ for (size_t i = 0; i < params.DataSize; ++i) {
+ meta.BeginElement(i, functor);
+ TMetaInfo<TMeta>& first = meta.BeginRepeated(2, functor);
+ data[i].first.resize(params.ValueArraySize);
+ for (ui32 j = 0; j < params.ValueArraySize; j++) {
+ first.BeginElement(j, functor);
+
+ ui32 val = PseudoRandom(42 * 42 * 42);
+ first.SetScalar(0, val, functor);
+ data[i].first[j] = val;
+
+ first.EndElement(functor);
+ }
+ first.EndRepeated(functor);
+
+ TMetaInfo<TMeta>& second = meta.BeginRepeated(3, functor);
+ data[i].second.resize(params.ValueArraySize);
+ for (ui32 j = 0; j < params.ValueArraySize; j++) {
+ second.BeginElement(j, functor);
+
+ ui32 val = PseudoRandom(42 * 42 * 42);
+ second.SetScalar(0, val, functor);
+ data[i].second[j] = val;
+
+ second.EndElement(functor);
+ }
+ second.EndRepeated(functor);
+ meta.EndElement(functor);
+ }
+ meta.EndRepeated(functor);
+ }
+ };
+
+ struct TVerifyingDecompressor: public TParentHold<TVerifyingDecompressor> {
+ enum EState {
+ Startstop,
+ OutDataElem,
+ InDataElemBeforeSecond,
+ InDataElemSecond,
+ InFirst,
+ InSecond,
+ };
+ EState State;
+
+ ui32 DataInd;
+ ui32 ArrayInd;
+
+ TVerifyingDecompressor()
+ : State(Startstop)
+ , DataInd(0)
+ , ArrayInd(0)
+ {
+ }
+
+ TMetaIterator<TVerifyingDecompressor>& GetDecompressor(size_t index) {
+ Y_UNUSED(index);
+ return *Parent;
+ }
+
+ void BeginSelf(ui32 /*count*/, ui32 id) {
+ switch (State) {
+ case Startstop:
+ UNIT_ASSERT_EQUAL(id, 0);
+ State = OutDataElem;
+ break;
+ case InDataElemBeforeSecond:
+ UNIT_ASSERT_EQUAL(id, 2);
+ State = InFirst;
+ ArrayInd = 0;
+ break;
+ case InDataElemSecond:
+ UNIT_ASSERT_EQUAL(id, 3);
+ State = InSecond;
+ ArrayInd = 0;
+ break;
+ default:
+ UNIT_ASSERT(0);
+ }
+ }
+ void EndSelf() {
+ switch (State) {
+ case OutDataElem:
+ State = Startstop;
+ break;
+ case InFirst:
+ State = InDataElemSecond;
+ break;
+ case InSecond:
+ State = InDataElemSecond;
+ break;
+ default:
+ UNIT_ASSERT(0);
+ }
+ }
+ void BeginElement(ui32 element) {
+ switch (State) {
+ case OutDataElem:
+ UNIT_ASSERT(element < data.size());
+ State = InDataElemBeforeSecond;
+ break;
+ case InFirst:
+ UNIT_ASSERT(element < data[DataInd].first.size());
+ break;
+ case InSecond:
+ UNIT_ASSERT(element < data[DataInd].second.size());
+ break;
+ default:
+ Cerr << (ui32)State << Endl;
+ UNIT_ASSERT(0);
+ }
+ }
+ void EndElement() {
+ switch (State) {
+ case InFirst:
+ case InSecond:
+ ++ArrayInd;
+ break;
+ case InDataElemSecond:
+ ++DataInd;
+ State = OutDataElem;
+ break;
+ default:
+ Cerr << (ui32)State << Endl;
+ UNIT_ASSERT(0);
+ }
+ }
+
+ void SetScalar(size_t index, ui32 val) {
+ UNIT_ASSERT_EQUAL(index, 0);
+ switch (State) {
+ case InFirst:
+ UNIT_ASSERT_EQUAL(val, data[DataInd].first[ArrayInd]);
+ break;
+ case InSecond:
+ UNIT_ASSERT_EQUAL(val, data[DataInd].second[ArrayInd]);
+ break;
+ default:
+ UNIT_ASSERT(0);
+ }
+ }
+ };
+ Y_UNIT_TEST(VerifyDecompression) {
+ Test<TVerifyingDecompressor, TSerialize>(metainfo, CM_SINGLEPASS);
+ }
+
+ Y_UNIT_TEST(VerifyHistDecompression) {
+ Test<TVerifyingDecompressor, TSerialize>(metainfo, CM_TWOPASS);
+ }
+}
diff --git a/library/cpp/compproto/compressor.h b/library/cpp/compproto/compressor.h
new file mode 100644
index 0000000000..14b335e13c
--- /dev/null
+++ b/library/cpp/compproto/compressor.h
@@ -0,0 +1,74 @@
+#pragma once
+
+#include <util/system/defaults.h>
+
+namespace NCompProto {
+ struct TEmpty {
+ };
+
+ struct TTable {
+ TTable() {
+ for (size_t i = 0; i < 64; ++i) {
+ CodeBase[i] = 0;
+ CodeMask[i] = 0;
+ Length[i] = 0;
+ PrefLength[i] = 0;
+ Id[i] = 0;
+ }
+ }
+ ui32 CodeBase[64];
+ ui32 CodeMask[64];
+ ui8 Length[64];
+ ui8 PrefLength[64];
+ ui8 Id[64];
+ enum {
+ PAGE_BOUND = 4096,
+#ifdef WITH_VALGRIND
+ SAFE_MODE = 1,
+#else
+#if defined(__has_feature)
+#if __has_feature(address_sanitizer)
+ SAFE_MODE = 1,
+#else
+ SAFE_MODE = 0,
+#endif
+#else
+ SAFE_MODE = 0,
+#endif
+#endif
+ };
+ ui32 inline Decompress(const ui8* codes, ui64& offset) const {
+ codes += (offset >> 3);
+ size_t pageOff = size_t(codes) % PAGE_BOUND;
+ size_t readOff = offset & 7;
+ if (pageOff > PAGE_BOUND - 8 || SAFE_MODE) {
+ size_t off = 8;
+ ui64 res = codes[0];
+ ++codes;
+ ui64 indexCur = ((res + 0x0000) >> readOff) & 63;
+ ui64 indexAlt = ((res + 0xff00) >> readOff) & 63;
+ if (Id[indexCur] != Id[indexAlt]) {
+ res += (ui64(codes[0]) << off);
+ ++codes;
+ off += 8;
+ indexCur = (res >> readOff) & 63;
+ }
+ ui64 index = indexCur;
+ ui64 length = Length[index];
+ while (off < readOff + length) {
+ res += (ui64(codes[0]) << off);
+ ++codes;
+ off += 8;
+ }
+ offset += length;
+ ui64 code = res >> readOff;
+ return (((ui32)(code >> PrefLength[index])) & CodeMask[index]) + CodeBase[index];
+ }
+ ui64 code = ((const ui64*)(codes))[0] >> readOff;
+ ui64 index = code & 63;
+ offset += Length[index];
+ return (((ui32)(code >> PrefLength[index])) & CodeMask[index]) + CodeBase[index];
+ }
+ };
+
+}
diff --git a/library/cpp/compproto/huff.h b/library/cpp/compproto/huff.h
new file mode 100644
index 0000000000..fa5c139189
--- /dev/null
+++ b/library/cpp/compproto/huff.h
@@ -0,0 +1,402 @@
+#pragma once
+
+#include <util/system/defaults.h>
+#include <util/generic/yexception.h>
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+#include <util/generic/algorithm.h>
+#include <utility>
+
+#include <queue>
+
+#include "compressor.h"
+
+namespace NCompProto {
+ template <size_t CacheSize, typename TEntry>
+ struct TCache {
+ ui32 CacheKey[CacheSize];
+ TEntry CacheVal[CacheSize];
+ size_t Hits;
+ size_t Misses;
+ ui32 Hash(ui32 key) {
+ return key % CacheSize;
+ }
+ TCache() {
+ Hits = 0;
+ Misses = 0;
+ Clear();
+ }
+ void Clear() {
+ for (size_t i = 0; i < CacheSize; ++i) {
+ ui32 j = 0;
+ for (; Hash(j) == i; ++j)
+ ;
+ CacheKey[i] = j;
+ }
+ }
+ };
+
+ struct TCode {
+ i64 Probability;
+ ui32 Start;
+ ui32 Bits;
+ ui32 Prefix;
+ ui32 PrefLength;
+ TCode(i64 probability = 0, ui32 start = 0, ui32 bits = 0)
+ : Probability(probability)
+ , Start(start)
+ , Bits(bits)
+ {
+ }
+
+ bool operator<(const TCode& code) const {
+ return Probability < code.Probability;
+ }
+
+ bool operator>(const TCode& code) const {
+ return Probability > code.Probability;
+ }
+ };
+
+ struct TAccum {
+ struct TTable {
+ TAutoPtr<TTable> Tables[16];
+ i64 Counts[16];
+ TTable(const TTable& other) {
+ for (size_t i = 0; i < 16; ++i) {
+ Counts[i] = other.Counts[i];
+ if (other.Tables[i].Get()) {
+ Tables[i].Reset(new TTable(*other.Tables[i].Get()));
+ }
+ }
+ }
+ TTable() {
+ for (auto& count : Counts)
+ count = 0;
+ }
+
+ i64 GetCellCount(size_t i) {
+ i64 count = Counts[i];
+ if (Tables[i].Get()) {
+ for (size_t j = 0; j < 16; ++j) {
+ count += Tables[i]->GetCellCount(j);
+ }
+ }
+ return count;
+ }
+
+ i64 GetCount() {
+ i64 count = 0;
+ for (size_t j = 0; j < 16; ++j) {
+ count += GetCellCount(j);
+ }
+ return count;
+ }
+
+ void GenerateFreqs(TVector<std::pair<i64, TCode>>& codes, int depth, int termDepth, ui32 code, i64 cnt) {
+ if (depth == termDepth) {
+ for (size_t i = 0; i < 16; ++i) {
+ i64 iCount = GetCellCount(i);
+ if (Tables[i].Get()) {
+ Counts[i] = iCount;
+ Tables[i].Reset(nullptr);
+ }
+
+ if (iCount > cnt || (termDepth == 0 && iCount > 0)) {
+ std::pair<i64, TCode> codep;
+ codep.first = iCount;
+ codep.second.Probability = iCount;
+ codep.second.Start = code + (i << (28 - depth));
+ codep.second.Bits = 28 - depth;
+ codes.push_back(codep);
+ Counts[i] = 0;
+ }
+ }
+ }
+ for (size_t i = 0; i < 16; ++i) {
+ if (Tables[i].Get()) {
+ Tables[i]->GenerateFreqs(codes, depth + 4, termDepth, code + (i << (28 - depth)), cnt);
+ }
+ }
+ }
+ };
+
+ TTable Root;
+ int TableCount;
+ i64 Total;
+ ui64 Max;
+
+ TAccum() {
+ TableCount = 0;
+ Total = 0;
+ Max = 0;
+ }
+
+ void GenerateFreqs(TVector<std::pair<i64, TCode>>& codes, int mul) const {
+ TTable root(Root);
+
+ for (int i = 28; i > 0; i -= 4) {
+ root.GenerateFreqs(codes, 0, i, 0, Total / mul);
+ }
+
+ i64 iCount = root.GetCount();
+ if (iCount == 0)
+ return;
+ std::pair<i64, TCode> codep;
+ codep.first = iCount;
+ codep.second.Probability = iCount;
+ codep.second.Start = 0;
+ ui32 bits = 0;
+ while (1) {
+ if ((1ULL << bits) > Max)
+ break;
+ ++bits;
+ }
+ codep.second.Bits = bits;
+ codes.push_back(codep);
+ }
+
+ TCache<256, i64*> Cache;
+
+ void AddMap(ui32 value, i64 weight = 1) {
+ ui32 index = Cache.Hash(value);
+ if (Cache.CacheKey[index] == value) {
+ Cache.CacheVal[index][0] += weight;
+ return;
+ }
+ TTable* root = &Root;
+ for (size_t i = 0; i < 15; ++i) {
+ ui32 index2 = (value >> (28 - i * 4)) & 0xf;
+ if (!root->Tables[index2].Get()) {
+ if (TableCount < 1024) {
+ ++TableCount;
+ root->Tables[index2].Reset(new TTable);
+ } else {
+ Cache.CacheKey[index2] = value;
+ Cache.CacheVal[index2] = &root->Counts[index2];
+ root->Counts[index2] += weight;
+ return;
+ }
+ }
+ root = root->Tables[index2].Get();
+ }
+
+ Cache.CacheKey[index] = value;
+ Cache.CacheVal[index] = &root->Counts[value & 0xf];
+ root->Counts[value & 0xf] += weight;
+ }
+
+ void Add(ui32 value, i64 weight = 1) {
+ Max = ::Max(Max, (ui64)value);
+ Total += weight;
+ AddMap(value, weight);
+ };
+ };
+
+ struct THuffNode {
+ i64 Weight;
+ i64 Priority;
+ THuffNode* Nodes[2];
+ TCode* Code;
+ THuffNode(i64 weight, i64 priority, TCode* code)
+ : Weight(weight)
+ , Priority(priority)
+ , Code(code)
+ {
+ Nodes[0] = nullptr;
+ Nodes[1] = nullptr;
+ }
+
+ void BuildPrefixes(ui32 depth, ui32 prefix) {
+ if (Code) {
+ Code->Prefix = prefix;
+ Code->PrefLength = depth;
+ return;
+ }
+ Nodes[0]->BuildPrefixes(depth + 1, prefix + (0UL << depth));
+ Nodes[1]->BuildPrefixes(depth + 1, prefix + (1UL << depth));
+ }
+
+ i64 Iterate(size_t depth) const {
+ if (Code) {
+ return (depth + Code->Bits) * Code->Probability;
+ }
+ return Nodes[0]->Iterate(depth + 1) + Nodes[1]->Iterate(depth + 1);
+ }
+
+ size_t Depth() const {
+ if (Code) {
+ return 0;
+ }
+ return Max(Nodes[0]->Depth(), Nodes[1]->Depth()) + 1;
+ }
+ };
+
+ struct THLess {
+ bool operator()(const THuffNode* a, const THuffNode* b) {
+ if (a->Weight > b->Weight)
+ return 1;
+ if (a->Weight == b->Weight && a->Priority > b->Priority)
+ return 1;
+ return 0;
+ }
+ };
+
+ inline i64 BuildHuff(TVector<TCode>& codes) {
+ TVector<TSimpleSharedPtr<THuffNode>> hold;
+ std::priority_queue<THuffNode*, TVector<THuffNode*>, THLess> nodes;
+ i64 ret = 0;
+
+ int priority = 0;
+ for (size_t i = 0; i < codes.size(); ++i) {
+ TSimpleSharedPtr<THuffNode> node(new THuffNode(codes[i].Probability, priority++, &codes[i]));
+ hold.push_back(node);
+ nodes.push(node.Get());
+ }
+
+ while (nodes.size() > 1) {
+ THuffNode* nodea = nodes.top();
+ nodes.pop();
+ THuffNode* nodeb = nodes.top();
+ nodes.pop();
+ TSimpleSharedPtr<THuffNode> node(new THuffNode(nodea->Weight + nodeb->Weight, priority++, nullptr));
+ node->Nodes[0] = nodea;
+ node->Nodes[1] = nodeb;
+ hold.push_back(node);
+ nodes.push(node.Get());
+ }
+
+ if (nodes.size()) {
+ THuffNode* node = nodes.top();
+ node->BuildPrefixes(0, 0);
+ ret = node->Iterate(0);
+ }
+
+ return ret;
+ };
+
+ struct TCoderEntry {
+ ui32 MinValue;
+ ui16 Prefix;
+ ui8 PrefixBits;
+ ui8 AllBits;
+
+ ui64 MaxValue() const {
+ return MinValue + (1ULL << (AllBits - PrefixBits));
+ }
+ };
+
+ inline i64 Analyze(const TAccum& acc, TVector<TCoderEntry>& retCodes) {
+ i64 ret;
+ for (int k = 256; k > 0; --k) {
+ retCodes.clear();
+ TVector<std::pair<i64, TCode>> pairs;
+ acc.GenerateFreqs(pairs, k);
+ TVector<TCode> codes;
+ for (size_t i = 0; i < pairs.size(); ++i) {
+ codes.push_back(pairs[i].second);
+ }
+
+ StableSort(codes.begin(), codes.end(), std::greater<TCode>());
+
+ ret = BuildHuff(codes);
+ bool valid = true;
+ for (size_t i = 0; i < codes.size(); ++i) {
+ TCoderEntry code;
+ code.MinValue = codes[i].Start;
+ code.Prefix = codes[i].Prefix;
+ code.PrefixBits = codes[i].PrefLength;
+ if (code.PrefixBits > 6)
+ valid = false;
+ code.AllBits = code.PrefixBits + codes[i].Bits;
+ retCodes.push_back(code);
+ }
+ if (valid)
+ return ret;
+ }
+
+ return ret;
+ }
+
+ struct TComparer {
+ bool operator()(const TCoderEntry& e0, const TCoderEntry& e1) const {
+ return e0.AllBits < e1.AllBits;
+ }
+ };
+
+ struct TCoder {
+ TVector<TCoderEntry> Entries;
+ void Normalize() {
+ TComparer comp;
+ StableSort(Entries.begin(), Entries.end(), comp);
+ }
+ TCoder() {
+ InitDefault();
+ }
+ void InitDefault() {
+ ui64 cum = 0;
+ Cache.Clear();
+ Entries.clear();
+ ui16 b = 1;
+ for (ui16 i = 0; i < 40; ++i) {
+ ui16 bits = Min(b, (ui16)(32));
+ b = (b * 16) / 10 + 1;
+ if (b > 32)
+ b = 32;
+ TCoderEntry entry;
+ entry.PrefixBits = i + 1;
+ entry.AllBits = entry.PrefixBits + bits;
+ entry.MinValue = (ui32)Min(cum, (ui64)(ui32)(-1));
+ cum += (1ULL << bits);
+ entry.Prefix = ((1UL << i) - 1);
+ Entries.push_back(entry);
+ if (cum > (ui32)(-1)) {
+ return;
+ }
+ };
+ }
+
+ TCache<1024, TCoderEntry> Cache;
+
+ ui64 RealCode(ui32 value, const TCoderEntry& entry, size_t& length) {
+ length = entry.AllBits;
+ return (ui64(value - entry.MinValue) << entry.PrefixBits) + entry.Prefix;
+ }
+
+ bool Empty() const {
+ return Entries.empty();
+ }
+ const TCoderEntry& GetEntry(ui32 code, ui8& id) const {
+ for (size_t i = 0; i < Entries.size(); ++i) {
+ const TCoderEntry& entry = Entries[i];
+ ui32 prefMask = (1UL << entry.PrefixBits) - 1UL;
+ if (entry.Prefix == (code & prefMask)) {
+ id = ui8(i);
+ return entry;
+ }
+ }
+ ythrow yexception() << "bad entry";
+ return Entries[0];
+ }
+
+ ui64 Code(ui32 entry, size_t& length) {
+ ui32 index = Cache.Hash(entry);
+ if (Cache.CacheKey[index] == entry) {
+ ++Cache.Hits;
+ return RealCode(entry, Cache.CacheVal[index], length);
+ }
+ ++Cache.Misses;
+ for (size_t i = 0; i < Entries.size(); ++i) {
+ if (entry >= Entries[i].MinValue && entry < Entries[i].MaxValue()) {
+ Cache.CacheKey[index] = entry;
+ Cache.CacheVal[index] = Entries[i];
+ return RealCode(entry, Cache.CacheVal[index], length);
+ }
+ }
+
+ ythrow yexception() << "bad huff tree";
+ return 0;
+ }
+ };
+
+}
diff --git a/library/cpp/compproto/lib.cpp b/library/cpp/compproto/lib.cpp
new file mode 100644
index 0000000000..dd23e5aa11
--- /dev/null
+++ b/library/cpp/compproto/lib.cpp
@@ -0,0 +1,4 @@
+#include "bit.h"
+#include "compressor.h"
+#include "huff.h"
+#include "metainfo.h"
diff --git a/library/cpp/compproto/metainfo.h b/library/cpp/compproto/metainfo.h
new file mode 100644
index 0000000000..6e68f86e12
--- /dev/null
+++ b/library/cpp/compproto/metainfo.h
@@ -0,0 +1,304 @@
+#pragma once
+
+#include <util/system/defaults.h>
+#include <util/generic/yexception.h>
+#include <util/generic/ptr.h>
+#include <util/generic/refcount.h>
+#include <util/stream/input.h>
+#include <util/stream/str.h>
+
+#include "compressor.h"
+
+namespace NCompProto {
+ const size_t MAX_ELEMENTS = 32;
+
+ struct TScalarDefaultValue {
+ TScalarDefaultValue()
+ : Type(None)
+ , Value(0)
+ {
+ }
+ enum EType {
+ None = 0,
+ Fixed = 1,
+ };
+ EType Type;
+ ui32 Value;
+ };
+
+ template <class X>
+ struct TMetaInfo {
+ X Index;
+ X Count;
+ X Mask;
+ X Scalar[MAX_ELEMENTS];
+ TAtomicSharedPtr<TMetaInfo> Repeated[MAX_ELEMENTS];
+ TScalarDefaultValue Default[MAX_ELEMENTS];
+
+ ui32 ScalarMask;
+ ui32 RepeatedMask;
+ size_t Size;
+ TString Name;
+ TString ChildName[MAX_ELEMENTS];
+ size_t Id;
+ TMetaInfo* Parent;
+
+ struct TCheck {
+ ui32 Count;
+ ui32 Mask;
+ ui32 LastIndex;
+ ui32 Check(size_t id, size_t rule) {
+ ui32 mask = 1UL << id;
+ if (Mask & mask) {
+ ythrow yexception() << "Mask & mask";
+ }
+ Mask |= mask;
+ Y_ENSURE(rule & mask, "!(rule & mask)");
+ return mask;
+ }
+ void ClearCount() {
+ Count = 0;
+ }
+ void ClearMask() {
+ Mask = 0;
+ }
+ void ClearIndex() {
+ LastIndex = ui32(-1);
+ }
+ void ClearAll() {
+ ClearCount();
+ ClearIndex();
+ ClearMask();
+ }
+ TCheck() {
+ ClearAll();
+ }
+ };
+
+ TCheck Serializer;
+
+ void SetDefaults(TMetaInfo* parent) {
+ ScalarMask = 0;
+ RepeatedMask = 0;
+ Size = 0;
+ Id = 0;
+ Parent = parent;
+ }
+
+ template <class T, class TBuilder>
+ TMetaInfo(const TMetaInfo<T>& meta, const TBuilder& builder) {
+ SetDefaults(nullptr);
+ Name = meta.Name;
+ builder.Build(Index, meta.Index);
+ builder.Build(Count, meta.Count);
+ builder.Build(Mask, meta.Mask);
+ Size = meta.Size;
+ Id = meta.Id;
+ ScalarMask = meta.ScalarMask;
+ RepeatedMask = meta.RepeatedMask;
+ for (size_t i = 0; i < Size; ++i) {
+ ui32 index = (1UL << i);
+ if (ScalarMask & index) {
+ builder.Build(Scalar[i], meta.Scalar[i]);
+ ChildName[i] = meta.ChildName[i];
+ Default[i] = meta.Default[i];
+ }
+ if (RepeatedMask & index) {
+ THolder<TMetaInfo> info(new TMetaInfo(*meta.Repeated[i], builder));
+ info->Parent = this;
+ Repeated[i].Reset(info.Release());
+ }
+ }
+ }
+
+ TMetaInfo(TMetaInfo* parent) {
+ SetDefaults(parent);
+ }
+
+ template <class T>
+ TMetaInfo& BeginRepeated(size_t id, T& functor) {
+ Serializer.Check(id, RepeatedMask);
+ TMetaInfo& res = *Repeated[id].Get();
+ res.Count.BeginElement(functor);
+ return res;
+ }
+
+ template <class T>
+ void BeginSelf(T& functor) {
+ Serializer.ClearAll();
+ Count.BeginElement(functor);
+ }
+
+ template <class T>
+ void EndRepeated(T& functor) {
+ Count.AddDelayed(Serializer.Count, functor);
+ Serializer.ClearCount();
+ Serializer.ClearIndex();
+ Y_ENSURE(Serializer.Mask == 0, "Serializer.Mask != 0");
+ }
+
+ template <class T>
+ void BeginElement(ui32 index, T& functor) {
+ Y_ENSURE(!(index < Serializer.LastIndex + 1),
+ "Name: " << Name.Quote() << " error: index < Serializer.LastIndex + 1; "
+ << "index: " << index << " LastIndex: " << Serializer.LastIndex);
+ Index.Add(index - Serializer.LastIndex, functor);
+ Mask.BeginElement(functor);
+ Serializer.LastIndex = index;
+ ++Serializer.Count;
+ }
+
+ template <class TFunctor>
+ void Iterate(TFunctor& functor) {
+ Cout << Name << " "
+ << "Index" << Endl;
+ functor.Process(Index);
+ Cout << "Count" << Endl;
+ functor.Process(Count);
+ Cout << "Mask" << Endl;
+ functor.Process(Mask);
+
+ for (size_t i = 0; i < Size; ++i) {
+ ui32 index = (1UL << i);
+ if (ScalarMask & index) {
+ Cout << "scalar"
+ << " " << i << Endl;
+ functor.Process(Scalar[i]);
+ }
+ if (RepeatedMask & index) {
+ Cout << "repeated"
+ << " " << i << Endl;
+ Repeated[i]->Iterate(functor);
+ }
+ }
+ }
+
+ template <class T>
+ void EndElement(T& functor) {
+ Mask.AddDelayed(Serializer.Mask, functor);
+ Serializer.ClearMask();
+ }
+
+ template <class T>
+ void SetScalar(size_t id, ui32 value, T& functor) {
+ if (Default[id].Type != TScalarDefaultValue::Fixed || value != Default[id].Value) {
+ Serializer.Check(id, ScalarMask);
+ Scalar[id].Add(value, functor);
+ }
+ }
+
+ ui32 Check(size_t id) {
+ Y_ENSURE(id < MAX_ELEMENTS, "id >= MAX_ELEMENTS");
+
+ ui32 mask = 1UL << id;
+ if (ScalarMask & mask) {
+ ythrow yexception() << "ScalarMask & mask";
+ }
+ if (RepeatedMask & mask) {
+ ythrow yexception() << "RepeatedMask & mask";
+ }
+ Size = Max(id + 1, Size);
+ return mask;
+ }
+
+ TMetaInfo(IInputStream& stream) {
+ SetDefaults(nullptr);
+ Load(stream);
+ }
+
+ TMetaInfo(const TString& str) {
+ SetDefaults(nullptr);
+ TStringInput stream(str);
+ Load(stream);
+ }
+
+ void Save(IOutputStream& stream, const TString& offset = TString()) {
+ stream << offset << "repeated " << Name << " id " << Id << Endl;
+ TString step = " ";
+ stream << step << offset << "index" << Endl;
+ Index.Save(stream, step + offset);
+ stream << step << offset << "count" << Endl;
+ Count.Save(stream, step + offset);
+ stream << step << offset << "mask" << Endl;
+ Mask.Save(stream, step + offset);
+
+ for (size_t i = 0; i < MAX_ELEMENTS; ++i) {
+ ui32 mask = 1UL << i;
+ if (mask & RepeatedMask) {
+ Repeated[i]->Save(stream, step + offset);
+ } else if (mask & ScalarMask) {
+ stream << step << offset << "scalar " << ChildName[i] << " id " << i;
+ stream << " default " << (Default[i].Type == TScalarDefaultValue::None ? " no " : " const ");
+ if (Default[i].Type == TScalarDefaultValue::Fixed) {
+ stream << Default[i].Value;
+ }
+ stream << Endl;
+ stream << step << offset << "table "
+ << "id " << i << Endl;
+ Scalar[i].Save(stream, step + offset);
+ }
+ }
+ stream << offset << "end" << Endl;
+ }
+
+ void Load(IInputStream& stream) {
+ TString name;
+ stream >> name;
+ if (name == "repeated") {
+ stream >> name;
+ }
+ Name = name;
+ stream >> name;
+ Y_ENSURE(name == "id", "Name mismatch: " << name.Quote() << " != id. ");
+ stream >> Id;
+
+ while (1) {
+ stream >> name;
+ if (name == "index") {
+ Index.Load(stream);
+ } else if (name == "count") {
+ Count.Load(stream);
+ } else if (name == "mask") {
+ Mask.Load(stream);
+ } else if (name == "table") {
+ stream >> name;
+ Y_ENSURE(name == "id", "Name mismatch: " << name.Quote() << " != id. ");
+ size_t id;
+ stream >> id;
+ Scalar[id].Load(stream);
+ } else if (name == "repeated") {
+ THolder<TMetaInfo> info(new TMetaInfo(this));
+ info->Load(stream);
+ size_t id = info->Id;
+ RepeatedMask |= Check(id);
+ Repeated[id].Reset(info.Release());
+ } else if (name == "scalar") {
+ stream >> name;
+ TString childName = name;
+ stream >> name;
+ Y_ENSURE(name == "id", "Name mismatch: " << name.Quote() << " != id. ");
+ size_t id;
+ stream >> id;
+ ScalarMask |= Check(id);
+ ChildName[id] = childName;
+ stream >> name;
+ Y_ENSURE(name == "default", "Name mismatch: " << name.Quote() << " != default. ");
+ stream >> name;
+ if (name == "no") {
+ Default[id].Type = TScalarDefaultValue::None;
+ } else if (name == "const") {
+ ui32 def;
+ stream >> def;
+ Default[id].Type = TScalarDefaultValue::Fixed;
+ Default[id].Value = def;
+ } else {
+ ythrow yexception() << "Unsupported default value specification: " << name.Quote();
+ }
+ } else if (name == "end" /* || stream.IsEOF()*/) {
+ return;
+ }
+ }
+ }
+ };
+
+}
diff --git a/library/cpp/compproto/ut/ya.make b/library/cpp/compproto/ut/ya.make
new file mode 100644
index 0000000000..f197a58269
--- /dev/null
+++ b/library/cpp/compproto/ut/ya.make
@@ -0,0 +1,15 @@
+UNITTEST()
+
+OWNER(ironpeter)
+
+PEERDIR(
+ ADDINCL library/cpp/compproto
+)
+
+SRCDIR(library/cpp/compproto)
+
+SRCS(
+ compproto_ut.cpp
+)
+
+END()
diff --git a/library/cpp/compproto/ya.make b/library/cpp/compproto/ya.make
new file mode 100644
index 0000000000..60d5cfa08d
--- /dev/null
+++ b/library/cpp/compproto/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(ironpeter)
+
+SRCS(
+ bit.h
+ compressor.h
+ huff.h
+ metainfo.h
+ lib.cpp
+)
+
+END()
diff --git a/library/cpp/comptable/comptable.cpp b/library/cpp/comptable/comptable.cpp
new file mode 100644
index 0000000000..8a92d4d1aa
--- /dev/null
+++ b/library/cpp/comptable/comptable.cpp
@@ -0,0 +1,443 @@
+#include <util/system/defaults.h>
+#include <util/system/filemap.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/string/cast.h>
+#include <util/stream/file.h>
+#include <library/cpp/compproto/huff.h>
+
+#include "comptable.h"
+
+#include <cstdlib>
+
+namespace NCompTable {
+ static const ui32 magicHashMul = 0xd077cd1f;
+ static const size_t hashSizeLog = 18;
+ static const size_t hashSize = 1 << hashSizeLog;
+
+ size_t HashIndex(ui32 value, ui32 hashMul) {
+ return (value * hashMul) >> (32 - hashSizeLog);
+ }
+
+ void TCompressorTable::GetHuffCode(const NCompProto::TCoderEntry& entry, ui32 value, ui64& bitCode, ui8& bitLength) const {
+ ui64 code = value - entry.MinValue;
+ bitCode = (code << entry.PrefixBits) | entry.Prefix;
+ bitLength = entry.AllBits;
+ }
+ void TCompressorTable::GetLastHuffCode(ui32 value, ui64& bitCode, ui8& bitLength) const {
+ GetHuffCode(HuffCodes[9], value, bitCode, bitLength);
+ }
+ void TCompressorTable::GetHuffCode(ui32 value, ui64& bitCode, ui8& bitLength) const {
+ for (auto huffCode : HuffCodes) {
+ ui32 minValue = huffCode.MinValue;
+ if (minValue <= value && value < huffCode.MaxValue()) {
+ GetHuffCode(huffCode, value, bitCode, bitLength);
+ return;
+ }
+ }
+ abort();
+ }
+ ui8 TCompressorTable::GetHuffIndex(ui8 prefix) {
+ for (size_t i = 0; i < 10; ++i) {
+ if ((prefix & ((1 << HuffCodes[i].PrefixBits) - 1)) == HuffCodes[i].Prefix) {
+ return i;
+ }
+ }
+ abort();
+ return 0;
+ }
+
+ void TCompressorTable::BuildHuffCodes(i64 totalFreq, i64 freqs[65536]) {
+ i64 add = 1;
+ while (1) {
+ if (BuildHuffCodes(totalFreq, freqs, add)) {
+ return;
+ }
+ add = add * 2;
+ }
+ }
+
+ bool TCompressorTable::BuildHuffCodes(i64 totalFreq, i64 freqs[65536], i64 add) {
+ TVector<NCompProto::TCode> codes;
+ size_t bits[] = {0, 1, 2, 4, 8, 10, 12, 14, 16, 32};
+ size_t off = 0;
+ ui32 total = totalFreq;
+ for (size_t i = 0; i < 9; ++i) {
+ size_t size = 1 << bits[i];
+ ui32 weight = 0;
+ for (size_t j = off; j < off + size && j < 65536; ++j) {
+ weight += freqs[j];
+ }
+ codes.push_back(NCompProto::TCode(weight + add, ui32(off), bits[i]));
+ total = total > weight ? total - weight : 0;
+ off += size;
+ }
+ codes.push_back(NCompProto::TCode(total + add, 0, 32));
+ i64 ret = NCompProto::BuildHuff(codes);
+ Y_UNUSED(ret);
+ for (size_t i = 0; i < codes.size(); ++i) {
+ NCompProto::TCoderEntry& code = HuffCodes[i];
+ code.MinValue = codes[i].Start;
+ code.Prefix = codes[i].Prefix;
+ code.PrefixBits = codes[i].PrefLength;
+ code.AllBits = code.PrefixBits + codes[i].Bits;
+ if (code.PrefixBits > 8) {
+ return false;
+ }
+ }
+ for (size_t i = 0; i < 256; ++i) {
+ HuffIndices[i] = GetHuffIndex(ui8(i));
+ }
+ return true;
+ }
+
+ template <class TIterator>
+ void Iterate(const TStringBuf& data, TIterator& iterator) {
+ size_t i = 0;
+ iterator.Visit(ui32(data.size()));
+ for (; i + 3 < data.size(); i += 4) {
+ iterator.Visit(reinterpret_cast<const ui32*>(data.data() + i)[0]);
+ }
+ if (i != data.size()) {
+ ui32 buffer[1] = {0};
+ memcpy(buffer, data.data() + i, data.size() - i);
+ iterator.Visit(buffer[0]);
+ }
+ }
+
+ class TDataCompressor {
+ ui32 Keys[hashSize];
+ ui32 Vals[hashSize];
+ ui64 BitCodes[hashSize];
+ ui8 BitLengths[hashSize];
+ ui32 HashMul;
+ const TCompressorTable Table;
+
+ public:
+ TDataCompressor(const TCompressorTable& table)
+ : Table(table)
+ {
+ HashMul = table.HashMul;
+ for (size_t i = 0; i < hashSize; ++i) {
+ Keys[i] = 0;
+ Vals[i] = ui32(-1);
+ }
+ for (size_t i = 0; i < 65536; ++i) {
+ size_t index = HashIndex(table.Table[i], table.HashMul);
+ Keys[index] = table.Table[i];
+ Vals[index] = i;
+ table.GetHuffCode(ui32(i), BitCodes[index], BitLengths[index]);
+ }
+ }
+ void GetStat(ui32 val, ui32& stat) const {
+ size_t index = HashIndex(val, HashMul);
+ if (Keys[index] == val) {
+ stat = Vals[index];
+ } else {
+ stat = ui32(-1);
+ }
+ }
+ void GetStat(ui32 val, ui64& bitCode, ui8& bitLength) const {
+ size_t index = HashIndex(val, HashMul);
+ if (Keys[index] == val) {
+ bitCode = BitCodes[index];
+ bitLength = BitLengths[index];
+ } else {
+ Table.GetLastHuffCode(val, bitCode, bitLength);
+ }
+ }
+ size_t Compress4(const ui32* data4, ui8* dataBuff) const {
+ ui8* oldBuff = dataBuff;
+ ++dataBuff;
+ ui32 status = 0;
+ for (size_t i = 0; i < 4; ++i) {
+ status = (status << 2);
+ ui32 data = data4[i];
+ if (data == 0) {
+ continue;
+ }
+ ui32 stat;
+ GetStat(data, stat);
+ if (stat < 256) {
+ memcpy(dataBuff, &stat, 1);
+ dataBuff += 1;
+ status += 1;
+ } else if (stat < 65536) {
+ memcpy(dataBuff, &stat, 2);
+ dataBuff += 2;
+ status += 2;
+ } else {
+ memcpy(dataBuff, &data, 4);
+ dataBuff += 4;
+ status += 3;
+ }
+ }
+ oldBuff[0] = ui8(status);
+ return dataBuff - oldBuff;
+ }
+ struct TCompressorIterator {
+ TVector<char>& Result;
+ const TDataCompressor& Compressor;
+ ui32 Cached[4];
+ size_t Index;
+ size_t RealSize;
+ TCompressorIterator(TVector<char>& result, const TDataCompressor& compressor)
+ : Result(result)
+ , Compressor(compressor)
+ , Index(0)
+ , RealSize(0)
+ {
+ }
+ void Flush() {
+ Result.yresize(RealSize + 32);
+ RealSize += Compressor.Compress4(Cached, reinterpret_cast<ui8*>(Result.data()) + RealSize);
+ Index = 0;
+ }
+ void Visit(const ui32 data) {
+ Cached[Index] = data;
+ ++Index;
+ if (Index == 4) {
+ Flush();
+ }
+ }
+ ~TCompressorIterator() {
+ if (Index != 0) {
+ for (size_t i = Index; i < 4; ++i) {
+ Cached[i] = 0;
+ }
+ Flush();
+ }
+ Result.yresize(RealSize);
+ }
+ };
+ struct THQCompressorIterator {
+ TVector<char>& Result;
+ const TDataCompressor& Compressor;
+ size_t RealSize;
+ ui64 Offset;
+ THQCompressorIterator(TVector<char>& result, const TDataCompressor& compressor)
+ : Result(result)
+ , Compressor(compressor)
+ , RealSize(0)
+ , Offset(0)
+ {
+ }
+ void Visit(const ui32 data) {
+ size_t byteOff = Offset >> 3;
+ Result.yresize(byteOff + 32);
+ ui64 bitCode;
+ ui8 bitLength;
+ Compressor.GetStat(data, bitCode, bitLength);
+ ui64 dst;
+ memcpy(&dst, &Result[byteOff], sizeof(dst));
+ ui64 mask = ((1ULL << (Offset & 7)) - 1ULL);
+ dst = (dst & mask) | (bitCode << (Offset & 7));
+ memcpy(&Result[byteOff], &dst, sizeof(dst));
+ Offset += bitLength;
+ }
+ ~THQCompressorIterator() {
+ Result.yresize((Offset + 7) >> 3);
+ if (Offset & 7)
+ Result.back() &= (1 << (Offset & 7)) - 1;
+ }
+ };
+ template <bool HQ>
+ void Compress(const TStringBuf& stringBuf, TVector<char>& rslt) const {
+ if (!HQ) {
+ TCompressorIterator iterator(rslt, *this);
+ Iterate(stringBuf, iterator);
+ } else {
+ THQCompressorIterator iterator(rslt, *this);
+ Iterate(stringBuf, iterator);
+ }
+ }
+ };
+
+ class TDataDecompressor {
+ const TCompressorTable Table;
+
+ public:
+ TDataDecompressor(const TCompressorTable& table)
+ : Table(table)
+ {
+ }
+ size_t Decompress(ui32* data4, const ui8* dataBuff, ui32 type) const {
+ if (type == 0) {
+ data4[0] = 0;
+ return 0;
+ }
+ if (type == 1) {
+ ui8 masked;
+ memcpy(&masked, dataBuff, sizeof(masked));
+ data4[0] = Table.Table[masked];
+ return 1;
+ } else if (type == 2) {
+ ui16 masked;
+ memcpy(&masked, dataBuff, sizeof(masked));
+ data4[0] = Table.Table[masked];
+ return 2;
+ } else {
+ memcpy(data4, dataBuff, sizeof(*data4));
+ return 4;
+ }
+ }
+ size_t Decompress(ui32* data4, const ui8* dataBuff) const {
+ ui32 status = *dataBuff;
+ const ui8* oldData = dataBuff;
+ ++dataBuff;
+ dataBuff += Decompress(data4 + 0, dataBuff, (status >> 6));
+ dataBuff += Decompress(data4 + 1, dataBuff, (status >> 4) & 0x3);
+ dataBuff += Decompress(data4 + 2, dataBuff, (status >> 2) & 0x3);
+ dataBuff += Decompress(data4 + 3, dataBuff, (status)&0x3);
+ return dataBuff - oldData;
+ }
+ void Decompress(ui32* data, const ui8* dataBuff, ui64& offset, ui64 border) const {
+ size_t off = offset >> 3;
+ ui64 val = 0;
+ if (border - off >= sizeof(val)) {
+ memcpy(&val, dataBuff + off, sizeof(val));
+ } else {
+ memcpy(&val, dataBuff + off, border - off);
+ }
+ val >>= (offset & 7);
+ ui8 index = Table.HuffIndices[ui8(val)];
+ const NCompProto::TCoderEntry& entry = Table.HuffCodes[index];
+ ui8 allBits = entry.AllBits;
+ val = (val & ((1ULL << allBits) - 1ULL)) >> entry.PrefixBits;
+ val = val + entry.MinValue;
+ data[0] = (index == 9) ? val : Table.Table[val];
+ offset += allBits;
+ }
+ size_t GetJunkSize() const {
+ return 8;
+ }
+ template <bool HQ>
+ void Decompress(const TStringBuf& dataBuf, TVector<char>& rslt) const {
+ rslt.clear();
+ if (dataBuf.empty()) {
+ return;
+ }
+ const ui8* src = reinterpret_cast<const ui8*>(dataBuf.data());
+ ui64 border = dataBuf.size();
+ ui32 len = 0;
+ ui32 nullTerm = 1;
+ if (HQ) {
+ ui64 offset = 0;
+ ui32 length = 0;
+ Decompress(&length, src, offset, border);
+ size_t length32 = (length + 3) / 4;
+ rslt.yresize(length32 * 4 + nullTerm);
+ ui32* result = reinterpret_cast<ui32*>(rslt.data());
+ len = length;
+ for (size_t i = 0; i < length32; ++i) {
+ Decompress(&result[i], src, offset, border);
+ }
+ } else {
+ ui32 data[4];
+ src += Decompress(data, src);
+ len = data[0];
+ size_t length32x4 = (4 + len + 15) / 16;
+ rslt.yresize(length32x4 * 16 + nullTerm);
+ ui32* result = reinterpret_cast<ui32*>(rslt.data());
+ for (size_t i = 0; i < 3; ++i) {
+ result[i] = data[i + 1];
+ }
+ for (size_t j = 1; j < length32x4; ++j) {
+ src += Decompress(&result[j * 4 - 1], src);
+ }
+ }
+ rslt.resize(len);
+ }
+ };
+
+ struct TSamplerIterator {
+ TDataSampler& Sampler;
+ TSamplerIterator(TDataSampler& sampler)
+ : Sampler(sampler)
+ {
+ }
+ void Visit(const ui32 data) {
+ Sampler.AddStat(data);
+ }
+ };
+
+ struct TGreaterComparer {
+ //std::greater in arcadia???
+ bool operator()(ui64 a, ui64 b) const {
+ return a > b;
+ }
+ };
+
+ TDataSampler::TDataSampler() {
+ memset(this, 0, sizeof(*this));
+ }
+
+ void TDataSampler::BuildTable(TCompressorTable& table) const {
+ std::vector<ui64> sorted;
+ for (size_t i = 0; i < Size; ++i) {
+ ui64 res = (ui64(EntryHit[i]) << 32) + ui32(i);
+ sorted.push_back(res);
+ }
+ std::vector<ui32> entryTbl(Size);
+ std::sort(sorted.begin(), sorted.end(), TGreaterComparer());
+ table.HashMul = magicHashMul;
+ i64 freqs[65536];
+ for (size_t i = 0; i < 65536; ++i) {
+ ui32 ind = ui32(sorted[i]);
+ table.Table[i] = EntryVal[ind];
+ freqs[i] = EntryHit[ind];
+ }
+ table.BuildHuffCodes(Counter, freqs);
+ }
+
+ void TDataSampler::AddStat(ui32 val) {
+ ++Counter;
+ size_t hashInd = HashIndex(val, magicHashMul);
+ if (EntryVal[hashInd] == val) {
+ ++EntryHit[hashInd];
+ } else if (EntryHit[hashInd] > 1) {
+ --EntryHit[hashInd];
+ } else {
+ EntryHit[hashInd] = 1;
+ EntryVal[hashInd] = val;
+ }
+ }
+
+ void TDataSampler::AddStat(const TStringBuf& stringBuf) {
+ TSamplerIterator iterator(*this);
+ Iterate(stringBuf, iterator);
+ }
+
+ TChunkCompressor::TChunkCompressor(bool highQuality, const TCompressorTable& table)
+ : HighQuality(highQuality)
+ {
+ Compressor.Reset(new TDataCompressor(table));
+ }
+
+ void TChunkCompressor::Compress(TStringBuf data, TVector<char>* rslt) const {
+ if (HighQuality) {
+ Compressor->Compress<1>(data, *rslt);
+ } else {
+ Compressor->Compress<0>(data, *rslt);
+ }
+ }
+
+ TChunkCompressor::~TChunkCompressor() = default;
+
+ TChunkDecompressor::TChunkDecompressor(bool highQuality, const TCompressorTable& table)
+ : HighQuality(highQuality)
+ {
+ Decompressor.Reset(new TDataDecompressor(table));
+ }
+
+ void TChunkDecompressor::Decompress(TStringBuf data, TVector<char>* rslt) const {
+ if (HighQuality) {
+ Decompressor->Decompress<1>(data, *rslt);
+ } else {
+ Decompressor->Decompress<0>(data, *rslt);
+ }
+ }
+
+ TChunkDecompressor::~TChunkDecompressor() = default;
+
+}
diff --git a/library/cpp/comptable/comptable.h b/library/cpp/comptable/comptable.h
new file mode 100644
index 0000000000..d225fed7a0
--- /dev/null
+++ b/library/cpp/comptable/comptable.h
@@ -0,0 +1,75 @@
+#pragma once
+
+#include <util/generic/vector.h>
+#include <util/memory/blob.h>
+#include <util/ysaveload.h>
+
+#include <library/cpp/compproto/huff.h>
+
+namespace NCompTable {
+ struct TCompressorTable {
+ ui32 Table[65536];
+ ui32 HashMul;
+ NCompProto::TCoderEntry HuffCodes[10];
+ ui8 HuffIndices[256];
+
+ void GetHuffCode(const NCompProto::TCoderEntry& entry, ui32 value, ui64& bitCode, ui8& bitLength) const;
+ void GetLastHuffCode(ui32 value, ui64& bitCode, ui8& bitLength) const;
+ void GetHuffCode(ui32 value, ui64& bitCode, ui8& bitLength) const;
+ ui8 GetHuffIndex(ui8 prefix);
+ void BuildHuffCodes(i64 totalFreq, i64 freqs[65536]);
+ bool BuildHuffCodes(i64 totalFreq, i64 freqs[65536], i64 add);
+ };
+
+ struct TDataSampler {
+ enum {
+ Size = 1 << 18,
+ };
+ ui32 EntryVal[Size];
+ i64 EntryHit[Size];
+ i64 Counter;
+
+ public:
+ TDataSampler();
+ void BuildTable(TCompressorTable& table) const;
+ void AddStat(ui32 val);
+ void AddStat(const TStringBuf& stringBuf);
+ };
+
+ class TDataCompressor;
+ class TDataDecompressor;
+
+ class TChunkCompressor {
+ public:
+ TChunkCompressor(bool highQuality, const TCompressorTable& table);
+ void Compress(TStringBuf data, TVector<char>* result) const;
+ ~TChunkCompressor();
+
+ private:
+ bool HighQuality;
+ THolder<TDataCompressor> Compressor;
+ };
+
+ class TChunkDecompressor {
+ public:
+ TChunkDecompressor(bool highQuality, const TCompressorTable& table);
+ void Decompress(TStringBuf data, TVector<char>* result) const;
+ ~TChunkDecompressor();
+
+ private:
+ bool HighQuality;
+ THolder<TDataDecompressor> Decompressor;
+ };
+
+}
+
+template <>
+class TSerializer<NCompTable::TCompressorTable> {
+public:
+ static inline void Save(IOutputStream* out, const NCompTable::TCompressorTable& entry) {
+ SavePodType(out, entry);
+ }
+ static inline void Load(IInputStream* in, NCompTable::TCompressorTable& entry) {
+ LoadPodType(in, entry);
+ }
+};
diff --git a/library/cpp/comptable/usage/usage.cpp b/library/cpp/comptable/usage/usage.cpp
new file mode 100644
index 0000000000..9997c83686
--- /dev/null
+++ b/library/cpp/comptable/usage/usage.cpp
@@ -0,0 +1,75 @@
+#include <library/cpp/comptable/comptable.h>
+
+#include <util/random/random.h>
+#include <util/random/fast.h>
+
+#include <time.h>
+#include <stdlib.h>
+
+using namespace NCompTable;
+
+template <bool HQ>
+void DoTest(const TCompressorTable& table, const TVector<TString>& lines) {
+ TVector<char> compressed;
+ TVector<char> decompressed;
+
+ TChunkCompressor compressor(HQ, table);
+ TChunkDecompressor deCompressor(HQ, table);
+
+ size_t origSize = 0;
+ size_t compSize = 0;
+ float cl1 = clock();
+ for (size_t i = 0; i < lines.size(); ++i) {
+ const TString& line = lines[i];
+ compressor.Compress(line, &compressed);
+ origSize += line.size();
+ compSize += compressed.size();
+ TStringBuf in(compressed.data(), compressed.size());
+ deCompressor.Decompress(in, &decompressed);
+ if (decompressed.size() != line.size() || memcmp(decompressed.data(), line.data(), decompressed.size())) {
+ Cout << i << "\n";
+ Cout << line << "\n"
+ << TString(decompressed.data(), decompressed.size()) << "\n";
+ abort();
+ }
+ }
+ float cl2 = clock();
+ float secs = (cl2 - cl1) / CLOCKS_PER_SEC;
+ Cout << "origSize: " << origSize << "\tcompSize: " << compSize << Endl;
+ Cout << "yep! compression + decompression speed " << origSize / 1024.0f / 1024.0f / secs << " mbps\n";
+ Cout << "yep! compression ratio " << double(origSize) / double(compSize + 1) << "\n";
+}
+
+int main(int argc, const char* argv[]) {
+ TReallyFastRng32 rr(17);
+ TVector<TString> lines;
+ /*FILE *fp = fopen("res", "rb");
+ while (!feof(fp)) {
+ char buff[4096];
+ fscanf(fp, "%s", buff);
+ lines.push_back(TString(buff));
+ }*/
+ //for (size_t i = 0; i < 10000000; ++i) {
+ //for (size_t i = 0; i < 1000000; ++i) {
+ for (size_t i = 0; i < 1000000; ++i) {
+ size_t size = rr.Uniform(32);
+ TString res = "www.yandex.ru/yandsearch?text=";
+ for (size_t j = 0; j < size; ++j) {
+ res += "qwer"[rr.Uniform(4)];
+ }
+ lines.push_back(res);
+ }
+ THolder<TDataSampler> sampler(new TDataSampler);
+ for (size_t i = 0; i < lines.size(); ++i) {
+ sampler->AddStat(lines[i]);
+ }
+ TCompressorTable table;
+ sampler->BuildTable(table);
+
+ DoTest<true>(table, lines);
+ DoTest<false>(table, lines);
+
+ Y_UNUSED(argc);
+ Y_UNUSED(argv);
+ return 0;
+}
diff --git a/library/cpp/comptable/usage/ya.make b/library/cpp/comptable/usage/ya.make
new file mode 100644
index 0000000000..ab31e7528c
--- /dev/null
+++ b/library/cpp/comptable/usage/ya.make
@@ -0,0 +1,13 @@
+PROGRAM()
+
+OWNER(ironpeter)
+
+SRCS(
+ usage.cpp
+)
+
+PEERDIR(
+ library/cpp/comptable
+)
+
+END()
diff --git a/library/cpp/comptable/ut/comptable_ut.cpp b/library/cpp/comptable/ut/comptable_ut.cpp
new file mode 100644
index 0000000000..5901d0246f
--- /dev/null
+++ b/library/cpp/comptable/ut/comptable_ut.cpp
@@ -0,0 +1,64 @@
+#include <library/cpp/comptable/comptable.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/random/random.h>
+#include <util/random/fast.h>
+
+using namespace NCompTable;
+
+template <bool HQ>
+void DoTest(const TCompressorTable& table, const TVector<TString>& lines) {
+ TVector<char> compressed;
+ TVector<char> decompressed;
+
+ TChunkCompressor compressor(HQ, table);
+ TStringStream tmp;
+ Save(&tmp, table);
+ TCompressorTable tableLoaded;
+ Load(&tmp, tableLoaded);
+ UNIT_ASSERT(memcmp(&table, &tableLoaded, sizeof(table)) == 0);
+ TChunkDecompressor deCompressor(HQ, tableLoaded);
+
+ size_t origSize = 0;
+ size_t compSize = 0;
+ for (size_t i = 0; i < lines.size(); ++i) {
+ const TString& line = lines[i];
+ compressor.Compress(line, &compressed);
+ origSize += line.size();
+ compSize += compressed.size();
+ TStringBuf in(compressed.data(), compressed.size());
+ deCompressor.Decompress(in, &decompressed);
+ UNIT_ASSERT(decompressed.size() == line.size() && memcmp(decompressed.data(), line.data(), decompressed.size()) == 0);
+ }
+ UNIT_ASSERT_EQUAL(origSize, 45491584);
+ if (HQ) {
+ UNIT_ASSERT_EQUAL(compSize, 11074583);
+ } else {
+ UNIT_ASSERT_EQUAL(compSize, 17459336);
+ }
+ UNIT_ASSERT(compSize < origSize);
+}
+
+Y_UNIT_TEST_SUITE(TestComptable) {
+ Y_UNIT_TEST(TestComptableCompressDecompress) {
+ TReallyFastRng32 rr(17);
+ TVector<TString> lines;
+ for (size_t i = 0; i < 1000000; ++i) {
+ size_t size = rr.Uniform(32);
+ TString res = "www.yandex.ru/yandsearch?text=";
+ for (size_t j = 0; j < size; ++j) {
+ res += "qwer"[rr.Uniform(4)];
+ }
+ lines.push_back(res);
+ }
+ THolder<TDataSampler> sampler(new TDataSampler);
+ for (size_t i = 0; i < lines.size(); ++i) {
+ sampler->AddStat(lines[i]);
+ }
+ TCompressorTable table;
+ sampler->BuildTable(table);
+
+ DoTest<true>(table, lines);
+ DoTest<false>(table, lines);
+ }
+}
diff --git a/library/cpp/comptable/ut/ya.make b/library/cpp/comptable/ut/ya.make
new file mode 100644
index 0000000000..d0a49793a5
--- /dev/null
+++ b/library/cpp/comptable/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/comptable)
+
+OWNER(ironpeter)
+
+SRCS(
+ comptable_ut.cpp
+)
+
+END()
diff --git a/library/cpp/comptable/ya.make b/library/cpp/comptable/ya.make
new file mode 100644
index 0000000000..314603c62a
--- /dev/null
+++ b/library/cpp/comptable/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(ironpeter)
+
+SRCS(
+ comptable.cpp
+)
+
+PEERDIR(
+ library/cpp/compproto
+)
+
+END()
diff --git a/library/cpp/containers/2d_array/2d_array.cpp b/library/cpp/containers/2d_array/2d_array.cpp
new file mode 100644
index 0000000000..03115c7e2f
--- /dev/null
+++ b/library/cpp/containers/2d_array/2d_array.cpp
@@ -0,0 +1 @@
+#include "2d_array.h"
diff --git a/library/cpp/containers/2d_array/2d_array.h b/library/cpp/containers/2d_array/2d_array.h
new file mode 100644
index 0000000000..9e24650637
--- /dev/null
+++ b/library/cpp/containers/2d_array/2d_array.h
@@ -0,0 +1,125 @@
+#pragma once
+
+#include <util/system/yassert.h>
+#include <util/generic/algorithm.h>
+
+#ifdef _DEBUG
+template <class T>
+struct TBoundCheck {
+ T* Data;
+ size_t Size;
+ TBoundCheck(T* d, size_t s) {
+ Data = d;
+ Size = s;
+ }
+ T& operator[](size_t i) const {
+ Y_ASSERT(i >= 0 && i < Size);
+ return Data[i];
+ }
+};
+#endif
+
+template <class T>
+class TArray2D {
+private:
+ typedef T* PT;
+ T* Data;
+ T** PData;
+ size_t XSize;
+ size_t YSize;
+
+private:
+ void Copy(const TArray2D& a) {
+ XSize = a.XSize;
+ YSize = a.YSize;
+ Create();
+ for (size_t i = 0; i < XSize * YSize; i++)
+ Data[i] = a.Data[i];
+ }
+ void Destroy() {
+ delete[] Data;
+ delete[] PData;
+ }
+ void Create() {
+ Data = new T[XSize * YSize];
+ PData = new PT[YSize];
+ for (size_t i = 0; i < YSize; i++)
+ PData[i] = Data + i * XSize;
+ }
+
+public:
+ TArray2D(size_t xsize = 1, size_t ysize = 1) {
+ XSize = xsize;
+ YSize = ysize;
+ Create();
+ }
+ TArray2D(const TArray2D& a) {
+ Copy(a);
+ }
+ TArray2D& operator=(const TArray2D& a) {
+ Destroy();
+ Copy(a);
+ return *this;
+ }
+ ~TArray2D() {
+ Destroy();
+ }
+ void SetSizes(size_t xsize, size_t ysize) {
+ if (XSize == xsize && YSize == ysize)
+ return;
+ Destroy();
+ XSize = xsize;
+ YSize = ysize;
+ Create();
+ }
+ void Clear() {
+ SetSizes(1, 1);
+ }
+#ifdef _DEBUG
+ TBoundCheck<T> operator[](size_t i) const {
+ Y_ASSERT(i < YSize);
+ return TBoundCheck<T>(PData[i], XSize);
+ }
+#else
+ T* operator[](size_t i) const {
+ Y_ASSERT(i < YSize);
+ return PData[i];
+ }
+#endif
+ size_t GetXSize() const {
+ return XSize;
+ }
+ size_t GetYSize() const {
+ return YSize;
+ }
+ void FillZero() {
+ memset(Data, 0, sizeof(T) * XSize * YSize);
+ }
+ void FillEvery(const T& a) {
+ for (size_t i = 0; i < XSize * YSize; i++)
+ Data[i] = a;
+ }
+ void Swap(TArray2D& a) {
+ std::swap(Data, a.Data);
+ std::swap(PData, a.PData);
+ std::swap(XSize, a.XSize);
+ std::swap(YSize, a.YSize);
+ }
+};
+
+template <class T>
+inline bool operator==(const TArray2D<T>& a, const TArray2D<T>& b) {
+ if (a.GetXSize() != b.GetXSize() || a.GetYSize() != b.GetYSize())
+ return false;
+ for (size_t y = 0; y < a.GetYSize(); ++y) {
+ for (size_t x = 0; x < a.GetXSize(); ++x)
+ if (a[y][x] != b[y][x])
+ return false;
+ }
+ return true;
+}
+
+template <class T>
+inline bool operator!=(const TArray2D<T>& a, const TArray2D<T>& b) {
+ return !(a == b);
+}
diff --git a/library/cpp/containers/2d_array/ya.make b/library/cpp/containers/2d_array/ya.make
new file mode 100644
index 0000000000..71d56b902f
--- /dev/null
+++ b/library/cpp/containers/2d_array/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(kirillovs)
+
+SRCS(
+ 2d_array.cpp
+)
+
+END()
diff --git a/library/cpp/containers/atomizer/atomizer.cpp b/library/cpp/containers/atomizer/atomizer.cpp
new file mode 100644
index 0000000000..7a5f781d99
--- /dev/null
+++ b/library/cpp/containers/atomizer/atomizer.cpp
@@ -0,0 +1 @@
+#include "atomizer.h"
diff --git a/library/cpp/containers/atomizer/atomizer.h b/library/cpp/containers/atomizer/atomizer.h
new file mode 100644
index 0000000000..5e40f47ab9
--- /dev/null
+++ b/library/cpp/containers/atomizer/atomizer.h
@@ -0,0 +1,200 @@
+#pragma once
+
+#include <library/cpp/containers/str_map/str_map.h>
+
+#include <util/generic/vector.h>
+#include <util/generic/utility.h>
+
+#include <utility>
+#include <cstdio>
+
+template <class HashFcn = THash<const char*>, class EqualTo = TEqualTo<const char*>>
+class atomizer;
+
+template <class T, class HashFcn = THash<const char*>, class EqualTo = TEqualTo<const char*>>
+class super_atomizer;
+
+template <class HashFcn, class EqualTo>
+class atomizer: public string_hash<ui32, HashFcn, EqualTo> {
+private:
+ TVector<const char*> order;
+
+public:
+ using iterator = typename string_hash<ui32, HashFcn, EqualTo>::iterator;
+ using const_iterator = typename string_hash<ui32, HashFcn, EqualTo>::const_iterator;
+ using value_type = typename string_hash<ui32, HashFcn, EqualTo>::value_type;
+ using size_type = typename string_hash<ui32, HashFcn, EqualTo>::size_type;
+ using pool_size_type = typename string_hash<ui32, HashFcn, EqualTo>::pool_size_type;
+
+ using string_hash<ui32, HashFcn, EqualTo>::pool;
+ using string_hash<ui32, HashFcn, EqualTo>::size;
+ using string_hash<ui32, HashFcn, EqualTo>::find;
+ using string_hash<ui32, HashFcn, EqualTo>::end;
+ using string_hash<ui32, HashFcn, EqualTo>::insert_copy;
+ using string_hash<ui32, HashFcn, EqualTo>::clear_hash;
+
+ atomizer() {
+ order.reserve(HASH_SIZE_DEFAULT);
+ }
+ atomizer(size_type hash_size, pool_size_type pool_size)
+ : string_hash<ui32, HashFcn, EqualTo>(hash_size, pool_size)
+ {
+ order.reserve(hash_size);
+ }
+ ~atomizer() = default;
+ ui32 string_to_atom(const char* key) {
+ const char* old_begin = pool.Begin();
+ const char* old_end = pool.End();
+ std::pair<iterator, bool> ins = insert_copy(key, ui32(size() + 1));
+ if (ins.second) { // new?
+ if (pool.Begin() != old_begin) // repoint?
+ for (TVector<const char*>::iterator ptr = order.begin(); ptr != order.end(); ++ptr)
+ if (old_begin <= *ptr && *ptr < old_end) // from old pool?
+ *ptr += pool.Begin() - old_begin;
+ order.push_back((*ins.first).first); // copy of 'key'
+ }
+ return (ui32)(*ins.first).second;
+ }
+
+ ui32 perm_string_to_atom(const char* key) {
+ value_type val(key, ui32(size() + 1));
+ std::pair<iterator, bool> ins = this->insert(val);
+ if (ins.second)
+ order.push_back((*ins.first).first); // == copy of 'key'
+ return (ui32)(*ins.first).second; // == size()+1
+ }
+ ui32 find_atom(const char* key) const {
+ const_iterator it = find(key);
+ if (it == end())
+ return 0; // INVALID_ATOM
+ else
+ return (ui32)(*it).second;
+ }
+ const char* get_atom_name(ui32 atom) const {
+ if (atom && atom <= size())
+ return order[atom - 1];
+ return nullptr;
+ }
+ void clear_atomizer() {
+ clear_hash();
+ order.clear();
+ }
+ void SaveC2N(FILE* f) const { // we write sorted file
+ for (ui32 i = 0; i < order.size(); i++)
+ if (order[i])
+ fprintf(f, "%d\t%s\n", i + 1, order[i]);
+ }
+ void LoadC2N(FILE* f) { // but can read unsorted one
+ long k, km = 0;
+ char buf[1000];
+ char* s;
+ while (fgets(buf, 1000, f)) {
+ k = strtol(buf, &s, 10);
+ char* endl = strchr(s, '\n');
+ if (endl)
+ *endl = 0;
+ if (k > 0 && k != LONG_MAX) {
+ km = Max(km, k);
+ insert_copy(++s, ui32(k));
+ }
+ }
+ order.resize(km);
+ memset(&order[0], 0, order.size()); // if some atoms are absent
+ for (const_iterator I = this->begin(); I != end(); ++I)
+ order[(*I).second - 1] = (*I).first;
+ }
+};
+
+template <class T, class HashFcn, class EqualTo>
+class super_atomizer: public string_hash<ui32, HashFcn, EqualTo> {
+private:
+ using TOrder = TVector<std::pair<const char*, T>>;
+ TOrder order;
+
+public:
+ using iterator = typename string_hash<ui32, HashFcn, EqualTo>::iterator;
+ using const_iterator = typename string_hash<ui32, HashFcn, EqualTo>::const_iterator;
+ using value_type = typename string_hash<ui32, HashFcn, EqualTo>::value_type;
+ using size_type = typename string_hash<ui32, HashFcn, EqualTo>::size_type;
+ using pool_size_type = typename string_hash<ui32, HashFcn, EqualTo>::pool_size_type;
+
+ using o_iterator = typename TOrder::iterator;
+ using o_const_iterator = typename TOrder::const_iterator;
+ using o_value_type = typename TOrder::value_type;
+
+ using string_hash<ui32, HashFcn, EqualTo>::pool;
+ using string_hash<ui32, HashFcn, EqualTo>::size;
+ using string_hash<ui32, HashFcn, EqualTo>::find;
+ using string_hash<ui32, HashFcn, EqualTo>::end;
+ using string_hash<ui32, HashFcn, EqualTo>::insert_copy;
+ using string_hash<ui32, HashFcn, EqualTo>::clear_hash;
+
+ super_atomizer() {
+ order.reserve(HASH_SIZE_DEFAULT);
+ }
+ super_atomizer(size_type hash_size, pool_size_type pool_size)
+ : string_hash<ui32, HashFcn, EqualTo>(hash_size, pool_size)
+ {
+ order.reserve(hash_size);
+ }
+ ~super_atomizer() = default;
+ ui32 string_to_atom(const char* key, const T* atom_data = NULL) {
+ const char* old_begin = pool.Begin();
+ const char* old_end = pool.End();
+ std::pair<iterator, bool> ins = insert_copy(key, ui32(size() + 1));
+ if (ins.second) { // new?
+ if (pool.Begin() != old_begin) // repoint?
+ for (typename TOrder::iterator ptr = order.begin(); ptr != order.end(); ++ptr)
+ if (old_begin <= (*ptr).first && (*ptr).first < old_end) // from old pool?
+ (*ptr).first += pool.Begin() - old_begin;
+ order.push_back(std::pair<const char*, T>((*ins.first).first, atom_data ? *atom_data : T()));
+ }
+ return (*ins.first).second;
+ }
+
+ ui32 perm_string_to_atom(const char* key, const T* atom_data = NULL) {
+ value_type val(key, ui32(size() + 1));
+ std::pair<iterator, bool> ins = this->insert(val);
+ if (ins.second)
+ order.push_back(std::pair<const char*, T>((*ins.first).first, atom_data ? *atom_data : T()));
+ return (*ins.first).second; // == size()+1
+ }
+ ui32 find_atom(const char* key) const {
+ const_iterator it = find(key);
+ if (it == end())
+ return 0; // INVALID_ATOM
+ else
+ return (*it).second;
+ }
+ const char* get_atom_name(ui32 atom) const {
+ if (atom && atom <= size())
+ return order[atom - 1].first;
+ return nullptr;
+ }
+ const T* get_atom_data(ui32 atom) const {
+ if (atom && atom <= size())
+ return &order[atom - 1].second;
+ return NULL;
+ }
+ T* get_atom_data(ui32 atom) {
+ if (atom && atom <= size())
+ return &order[atom - 1].second;
+ return NULL;
+ }
+ o_iterator o_begin() {
+ return order.begin();
+ }
+ o_iterator o_end() {
+ return order.end();
+ }
+ o_const_iterator o_begin() const {
+ return order.begin();
+ }
+ o_const_iterator o_end() const {
+ return order.end();
+ }
+ void clear_atomizer() {
+ clear_hash();
+ order.clear();
+ }
+};
diff --git a/library/cpp/containers/atomizer/ya.make b/library/cpp/containers/atomizer/ya.make
new file mode 100644
index 0000000000..55165a3b67
--- /dev/null
+++ b/library/cpp/containers/atomizer/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(g:util)
+
+PEERDIR(
+ library/cpp/containers/str_map
+)
+
+SRCS(
+ atomizer.cpp
+)
+
+END()
diff --git a/library/cpp/containers/bitseq/bititerator.h b/library/cpp/containers/bitseq/bititerator.h
new file mode 100644
index 0000000000..52dadd3798
--- /dev/null
+++ b/library/cpp/containers/bitseq/bititerator.h
@@ -0,0 +1,138 @@
+#pragma once
+
+#include "traits.h"
+
+#include <library/cpp/pop_count/popcount.h>
+
+template <typename T>
+class TBitIterator {
+public:
+ using TWord = T;
+ using TTraits = TBitSeqTraits<TWord>;
+
+public:
+ TBitIterator(const T* data = nullptr)
+ : Current(0)
+ , Mask(0)
+ , Data(data)
+ {
+ }
+
+ /// Get the word next to the one we are currenlty iterating over.
+ const TWord* NextWord() const {
+ return Data;
+ }
+
+ /// Get the next bit without moving the iterator.
+ bool Peek() const {
+ return Mask ? (Current & Mask) : (*Data & 1);
+ }
+
+ /// Get the next bit and move forward.
+ /// TODO: Implement inversed iteration as well.
+ bool Next() {
+ if (!Mask) {
+ Current = *Data++;
+ Mask = 1;
+ }
+ const bool bit = Current & Mask;
+ Mask <<= 1;
+ return bit;
+ }
+
+ /// Get the next count bits without moving the iterator.
+ TWord Peek(ui8 count) const {
+ if (!count)
+ return 0;
+ Y_VERIFY_DEBUG(count <= TTraits::NumBits);
+
+ if (!Mask)
+ return *Data & TTraits::ElemMask(count);
+
+ auto usedBits = (size_t)PopCount(Mask - 1);
+ TWord result = Current >> usedBits;
+ auto leftInCurrent = TTraits::NumBits - usedBits;
+ if (count <= leftInCurrent)
+ return result & TTraits::ElemMask(count);
+
+ count -= leftInCurrent;
+ result |= (*Data & TTraits::ElemMask(count)) << leftInCurrent;
+ return result;
+ }
+
+ /// Get the next count bits and move forward by count bits.
+ TWord Read(ui8 count) {
+ if (!count)
+ return 0;
+ Y_VERIFY_DEBUG(count <= TTraits::NumBits);
+
+ if (!Mask) {
+ Current = *Data++;
+ Mask = 1 << count;
+ return Current & TTraits::ElemMask(count);
+ }
+
+ auto usedBits = (size_t)PopCount(Mask - 1);
+ TWord result = Current >> usedBits;
+ auto leftInCurrent = TTraits::NumBits - usedBits;
+ if (count < leftInCurrent) {
+ Mask <<= count;
+ return result & TTraits::ElemMask(count);
+ }
+
+ count -= leftInCurrent;
+ if (count) {
+ Current = *Data++;
+ Mask = 1 << count;
+ result |= (Current & TTraits::ElemMask(count)) << leftInCurrent;
+ } else {
+ Mask = 0;
+ }
+
+ return result;
+ }
+
+ /// Move the iterator forward by count bits.
+ void Forward(int count) {
+ if (!count)
+ return;
+
+ int leftInCurrent = (size_t)PopCount(~(Mask - 1));
+ if (count < leftInCurrent) {
+ Mask <<= count;
+ return;
+ }
+
+ count -= leftInCurrent;
+ Data += count >> TTraits::DivShift;
+ auto remainder = count & TTraits::ModMask;
+
+ if (remainder) {
+ Current = *Data++;
+ Mask = 1 << remainder;
+ } else {
+ Current = 0;
+ Mask = 0;
+ }
+ }
+
+ /// Skip trailing bits of the current word and move by count words forward.
+ void Align(int count = 0) {
+ Current = 0;
+ if (Mask)
+ Mask = 0;
+ Data += count;
+ }
+
+ /// Initialize the iterator.
+ void Reset(const TWord* data) {
+ Current = 0;
+ Mask = 0;
+ Data = data;
+ }
+
+private:
+ TWord Current;
+ TWord Mask;
+ const TWord* Data;
+};
diff --git a/library/cpp/containers/bitseq/bititerator_ut.cpp b/library/cpp/containers/bitseq/bititerator_ut.cpp
new file mode 100644
index 0000000000..ed0925866f
--- /dev/null
+++ b/library/cpp/containers/bitseq/bititerator_ut.cpp
@@ -0,0 +1,109 @@
+#include "bititerator.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/generic/vector.h>
+
+Y_UNIT_TEST_SUITE(TBitIteratorTest) {
+ TVector<ui16> GenWords() {
+ TVector<ui16> words(1, 0);
+ for (ui16 word = 1; word; ++word)
+ words.push_back(word);
+ return words;
+ }
+
+ template <typename TWord>
+ void AssertPeekRead(TBitIterator<TWord> & iter, ui8 count, TWord expected) {
+ auto peek = iter.Peek(count);
+ auto read = iter.Read(count);
+ UNIT_ASSERT_EQUAL(peek, read);
+ UNIT_ASSERT_EQUAL(peek, expected);
+ }
+
+ Y_UNIT_TEST(TestNextAndPeek) {
+ const auto& words = GenWords();
+
+ TBitIterator<ui16> iter(words.data());
+ ui16 word = 0;
+ for (int i = 0; i != (1 << 16); ++i, ++word) {
+ for (int bit = 0; bit != 16; ++bit) {
+ auto peek = iter.Peek();
+ auto next = iter.Next();
+ UNIT_ASSERT_EQUAL(peek, next);
+ UNIT_ASSERT_EQUAL(peek, (word >> bit) & 1);
+ }
+ UNIT_ASSERT_EQUAL(iter.NextWord(), words.data() + i + 1);
+ }
+
+ UNIT_ASSERT_EQUAL(iter.NextWord(), words.data() + words.size());
+ }
+
+ Y_UNIT_TEST(TestAlignedReadAndPeek) {
+ const auto& words = GenWords();
+
+ TBitIterator<ui16> iter(words.data());
+ ui16 word = 0;
+ for (int i = 0; i != (1 << 16); ++i, ++word) {
+ AssertPeekRead(iter, 16, word);
+ UNIT_ASSERT_EQUAL(iter.NextWord(), words.data() + i + 1);
+ }
+
+ UNIT_ASSERT_EQUAL(iter.NextWord(), words.data() + words.size());
+ }
+
+ Y_UNIT_TEST(TestForward) {
+ TVector<ui32> words;
+ words.push_back((1 << 10) | (1 << 20) | (1 << 25));
+ words.push_back(1 | (1 << 5) | (1 << 6) | (1 << 30));
+ for (int i = 0; i < 3; ++i)
+ words.push_back(0);
+ words.push_back(1 << 10);
+
+ TBitIterator<ui32> iter(words.data());
+ UNIT_ASSERT(!iter.Next());
+ UNIT_ASSERT(!iter.Next());
+ UNIT_ASSERT(!iter.Next());
+ iter.Forward(6);
+ UNIT_ASSERT(!iter.Next());
+ UNIT_ASSERT(iter.Next());
+ UNIT_ASSERT(!iter.Next());
+ iter.Forward(8);
+ UNIT_ASSERT(iter.Next());
+ iter.Forward(4);
+ UNIT_ASSERT(iter.Next());
+ iter.Forward(5);
+ UNIT_ASSERT(!iter.Next());
+ UNIT_ASSERT(iter.Next());
+ iter.Forward(4);
+ UNIT_ASSERT(iter.Next());
+
+ iter.Reset(words.data());
+ iter.Forward(38);
+ UNIT_ASSERT(iter.Next());
+ UNIT_ASSERT(!iter.Next());
+ UNIT_ASSERT_EQUAL(iter.NextWord(), words.data() + 2);
+
+ iter.Forward(24 + 32 * 3 + 9);
+ UNIT_ASSERT(!iter.Next());
+ UNIT_ASSERT(iter.Next());
+ UNIT_ASSERT(!iter.Next());
+ UNIT_ASSERT_EQUAL(iter.NextWord(), words.data() + 6);
+ }
+
+ Y_UNIT_TEST(TestUnalignedReadAndPeek) {
+ TVector<ui32> words;
+ words.push_back((1 << 10) | (1 << 20) | (1 << 25));
+ words.push_back(1 | (1 << 5) | (1 << 6) | (1 << 30));
+ for (int i = 0; i < 5; ++i)
+ words.push_back(1 | (1 << 10));
+
+ TBitIterator<ui32> iter(words.data());
+ AssertPeekRead(iter, 5, ui32(0));
+ AssertPeekRead(iter, 7, ui32(1 << 5));
+ AssertPeekRead(iter, 21, ui32((1 << 8) | (1 << 13) | (1 << 20)));
+ AssertPeekRead(iter, 32, (words[1] >> 1) | (1 << 31));
+ iter.Forward(8);
+ UNIT_ASSERT(!iter.Next());
+ UNIT_ASSERT(iter.Next());
+ UNIT_ASSERT(!iter.Next());
+ }
+}
diff --git a/library/cpp/containers/bitseq/bitvector.cpp b/library/cpp/containers/bitseq/bitvector.cpp
new file mode 100644
index 0000000000..05cb3a881d
--- /dev/null
+++ b/library/cpp/containers/bitseq/bitvector.cpp
@@ -0,0 +1 @@
+#include "bitvector.h"
diff --git a/library/cpp/containers/bitseq/bitvector.h b/library/cpp/containers/bitseq/bitvector.h
new file mode 100644
index 0000000000..3f8fd81ee5
--- /dev/null
+++ b/library/cpp/containers/bitseq/bitvector.h
@@ -0,0 +1,158 @@
+#pragma once
+
+#include "traits.h"
+
+#include <library/cpp/pop_count/popcount.h>
+
+#include <util/generic/vector.h>
+#include <util/ysaveload.h>
+
+template <typename T>
+class TReadonlyBitVector;
+
+template <typename T>
+class TBitVector {
+public:
+ using TWord = T;
+ using TTraits = TBitSeqTraits<TWord>;
+
+private:
+ friend class TReadonlyBitVector<T>;
+ ui64 Size_;
+ TVector<TWord> Data_;
+
+public:
+ TBitVector()
+ : Size_(0)
+ , Data_(0)
+ {
+ }
+
+ TBitVector(ui64 size)
+ : Size_(size)
+ , Data_(static_cast<size_t>((Size_ + TTraits::ModMask) >> TTraits::DivShift), 0)
+ {
+ }
+
+ virtual ~TBitVector() = default;
+
+ void Clear() {
+ Size_ = 0;
+ Data_.clear();
+ }
+
+ void Resize(ui64 size) {
+ Size_ = size;
+ Data_.resize((Size_ + TTraits::ModMask) >> TTraits::DivShift);
+ }
+
+ void Swap(TBitVector& other) {
+ DoSwap(Size_, other.Size_);
+ DoSwap(Data_, other.Data_);
+ }
+
+ bool Set(ui64 pos) {
+ Y_ASSERT(pos < Size_);
+ TWord& val = Data_[pos >> TTraits::DivShift];
+ if (val & TTraits::BitMask(pos & TTraits::ModMask))
+ return false;
+ val |= TTraits::BitMask(pos & TTraits::ModMask);
+ return true;
+ }
+
+ bool Test(ui64 pos) const {
+ return TTraits::Test(Data(), pos, Size_);
+ }
+
+ void Reset(ui64 pos) {
+ Y_ASSERT(pos < Size_);
+ Data_[pos >> TTraits::DivShift] &= ~TTraits::BitMask(pos & TTraits::ModMask);
+ }
+
+ TWord Get(ui64 pos, ui8 width, TWord mask) const {
+ return TTraits::Get(Data(), pos, width, mask, Size_);
+ }
+
+ TWord Get(ui64 pos, ui8 width) const {
+ return Get(pos, width, TTraits::ElemMask(width));
+ }
+
+ void Set(ui64 pos, TWord value, ui8 width, TWord mask) {
+ if (!width)
+ return;
+ Y_ASSERT((pos + width) <= Size_);
+ size_t word = pos >> TTraits::DivShift;
+ TWord shift1 = pos & TTraits::ModMask;
+ TWord shift2 = TTraits::NumBits - shift1;
+ Data_[word] &= ~(mask << shift1);
+ Data_[word] |= (value & mask) << shift1;
+ if (shift2 < width) {
+ Data_[word + 1] &= ~(mask >> shift2);
+ Data_[word + 1] |= (value & mask) >> shift2;
+ }
+ }
+
+ void Set(ui64 pos, TWord value, ui8 width) {
+ Set(pos, value, width, TTraits::ElemMask(width));
+ }
+
+ void Append(TWord value, ui8 width, TWord mask) {
+ if (!width)
+ return;
+ if (Data_.size() * TTraits::NumBits < Size_ + width) {
+ Data_.push_back(0);
+ }
+ Size_ += width;
+ Set(Size_ - width, value, width, mask);
+ }
+
+ void Append(TWord value, ui8 width) {
+ Append(value, width, TTraits::ElemMask(width));
+ }
+
+ size_t Count() const {
+ size_t count = 0;
+ for (size_t i = 0; i < Data_.size(); ++i) {
+ count += (size_t)PopCount(Data_[i]);
+ }
+ return count;
+ }
+
+ ui64 Size() const {
+ return Size_;
+ }
+
+ size_t Words() const {
+ return Data_.size();
+ }
+
+ const TWord* Data() const {
+ return Data_.data();
+ }
+
+ void Save(IOutputStream* out) const {
+ ::Save(out, Size_);
+ ::Save(out, Data_);
+ }
+
+ void Load(IInputStream* inp) {
+ ::Load(inp, Size_);
+ ::Load(inp, Data_);
+ }
+
+ ui64 Space() const {
+ return CHAR_BIT * (sizeof(Size_) +
+ Data_.size() * sizeof(TWord));
+ }
+
+ void Print(IOutputStream& out, size_t truncate = 128) {
+ for (size_t i = 0; i < Data_.size() && i < truncate; ++i) {
+ for (int j = TTraits::NumBits - 1; j >= 0; --j) {
+ size_t pos = TTraits::NumBits * i + j;
+ out << (pos < Size_ && Test(pos) ? '1' : '0');
+ }
+ out << " ";
+ }
+ out << Endl;
+ }
+};
diff --git a/library/cpp/containers/bitseq/bitvector_ut.cpp b/library/cpp/containers/bitseq/bitvector_ut.cpp
new file mode 100644
index 0000000000..6137adab1e
--- /dev/null
+++ b/library/cpp/containers/bitseq/bitvector_ut.cpp
@@ -0,0 +1,86 @@
+#include "bitvector.h"
+#include "readonly_bitvector.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/memory/blob.h>
+#include <util/stream/buffer.h>
+
+Y_UNIT_TEST_SUITE(TBitVectorTest) {
+ Y_UNIT_TEST(TestEmpty) {
+ TBitVector<ui64> v64;
+ UNIT_ASSERT_EQUAL(v64.Size(), 0);
+ UNIT_ASSERT_EQUAL(v64.Words(), 0);
+
+ TBitVector<ui32> v32(0);
+ UNIT_ASSERT_EQUAL(v32.Size(), 0);
+ UNIT_ASSERT_EQUAL(v32.Words(), 0);
+ }
+
+ Y_UNIT_TEST(TestOneWord) {
+ TBitVector<ui32> v;
+ v.Append(1, 1);
+ v.Append(0, 1);
+ v.Append(1, 3);
+ v.Append(10, 4);
+ v.Append(100500, 20);
+
+ UNIT_ASSERT_EQUAL(v.Get(0, 1), 1);
+ UNIT_ASSERT(v.Test(0));
+ UNIT_ASSERT_EQUAL(v.Get(1, 1), 0);
+ UNIT_ASSERT_EQUAL(v.Get(2, 3), 1);
+ UNIT_ASSERT_EQUAL(v.Get(5, 4), 10);
+ UNIT_ASSERT_EQUAL(v.Get(9, 20), 100500);
+
+ v.Reset(0);
+ v.Set(9, 1234, 15);
+ UNIT_ASSERT_EQUAL(v.Get(0, 1), 0);
+ UNIT_ASSERT(!v.Test(0));
+ UNIT_ASSERT_EQUAL(v.Get(9, 15), 1234);
+
+ UNIT_ASSERT_EQUAL(v.Size(), 29);
+ UNIT_ASSERT_EQUAL(v.Words(), 1);
+ }
+
+ Y_UNIT_TEST(TestManyWords) {
+ static const int BITS = 10;
+ TBitVector<ui64> v;
+
+ for (int i = 0, end = (1 << BITS); i < end; ++i)
+ v.Append(i, BITS);
+
+ UNIT_ASSERT_EQUAL(v.Size(), BITS * (1 << BITS));
+ UNIT_ASSERT_EQUAL(v.Words(), (v.Size() + 63) / 64);
+ for (int i = 0, end = (1 << BITS); i < end; ++i)
+ UNIT_ASSERT_EQUAL(v.Get(i * BITS, BITS), (ui64)i);
+ }
+
+ Y_UNIT_TEST(TestMaxWordSize) {
+ TBitVector<ui32> v;
+ for (int i = 0; i < 100; ++i)
+ v.Append(i, 32);
+
+ for (int i = 0; i < 100; ++i)
+ UNIT_ASSERT_EQUAL(v.Get(i * 32, 32), (ui32)i);
+
+ v.Set(10 * 32, 100500, 32);
+ UNIT_ASSERT_EQUAL(v.Get(10 * 32, 32), 100500);
+ }
+
+ Y_UNIT_TEST(TestReadonlyVector) {
+ TBitVector<ui64> v(100);
+ for (ui64 i = 0; i < v.Size(); ++i) {
+ if (i % 3 == 0) {
+ v.Set(i);
+ }
+ }
+ TBufferStream bs;
+ TReadonlyBitVector<ui64>::SaveForReadonlyAccess(&bs, v);
+ const auto blob = TBlob::FromBuffer(bs.Buffer());
+ TReadonlyBitVector<ui64> rv;
+ rv.LoadFromBlob(blob);
+ for (ui64 i = 0; i < rv.Size(); ++i) {
+ UNIT_ASSERT_VALUES_EQUAL(rv.Test(i), i % 3 == 0);
+ }
+ }
+}
diff --git a/library/cpp/containers/bitseq/readonly_bitvector.cpp b/library/cpp/containers/bitseq/readonly_bitvector.cpp
new file mode 100644
index 0000000000..891aa7cde2
--- /dev/null
+++ b/library/cpp/containers/bitseq/readonly_bitvector.cpp
@@ -0,0 +1 @@
+#include "readonly_bitvector.h"
diff --git a/library/cpp/containers/bitseq/readonly_bitvector.h b/library/cpp/containers/bitseq/readonly_bitvector.h
new file mode 100644
index 0000000000..8612739c3f
--- /dev/null
+++ b/library/cpp/containers/bitseq/readonly_bitvector.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#include "bitvector.h"
+#include "traits.h"
+
+#include <util/memory/blob.h>
+
+#include <cstring>
+
+template <typename T>
+class TReadonlyBitVector {
+public:
+ using TWord = T;
+ using TTraits = TBitSeqTraits<TWord>;
+
+ TReadonlyBitVector()
+ : Size_()
+ , Data_()
+ {
+ }
+
+ explicit TReadonlyBitVector(const TBitVector<T>& vector)
+ : Size_(vector.Size_)
+ , Data_(vector.Data_.data())
+ {
+ }
+
+ bool Test(ui64 pos) const {
+ return TTraits::Test(Data_, pos, Size_);
+ }
+
+ TWord Get(ui64 pos, ui8 width, TWord mask) const {
+ return TTraits::Get(Data_, pos, width, mask, Size_);
+ }
+
+ TWord Get(ui64 pos, ui8 width) const {
+ return Get(pos, width, TTraits::ElemMask(width));
+ }
+
+ ui64 Size() const {
+ return Size_;
+ }
+
+ const T* Data() const {
+ return Data_;
+ }
+
+ static void SaveForReadonlyAccess(IOutputStream* out, const TBitVector<T>& bv) {
+ ::Save(out, bv.Size_);
+ ::Save(out, static_cast<ui64>(bv.Data_.size()));
+ ::SavePodArray(out, bv.Data_.data(), bv.Data_.size());
+ }
+
+ virtual TBlob LoadFromBlob(const TBlob& blob) {
+ size_t read = 0;
+ auto cursor = [&]() { return blob.AsUnsignedCharPtr() + read; };
+ auto readToPtr = [&](auto* ptr) {
+ memcpy(ptr, cursor(), sizeof(*ptr));
+ read += sizeof(*ptr);
+ };
+
+ readToPtr(&Size_);
+
+ ui64 wordCount{};
+ readToPtr(&wordCount);
+
+ Data_ = reinterpret_cast<const T*>(cursor());
+ read += wordCount * sizeof(T);
+
+ return blob.SubBlob(read, blob.Size());
+ }
+
+private:
+ ui64 Size_;
+ const T* Data_;
+};
diff --git a/library/cpp/containers/bitseq/traits.h b/library/cpp/containers/bitseq/traits.h
new file mode 100644
index 0000000000..2330b1b4f2
--- /dev/null
+++ b/library/cpp/containers/bitseq/traits.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <util/generic/bitops.h>
+#include <util/generic/typetraits.h>
+#include <util/system/yassert.h>
+
+template <typename TWord>
+struct TBitSeqTraits {
+ static constexpr ui8 NumBits = CHAR_BIT * sizeof(TWord);
+ static constexpr TWord ModMask = static_cast<TWord>(NumBits - 1);
+ static constexpr TWord DivShift = MostSignificantBitCT(NumBits);
+
+ static inline TWord ElemMask(ui8 count) {
+ // NOTE: Shifting by the type's length is UB, so we need this workaround.
+ if (Y_LIKELY(count))
+ return TWord(-1) >> (NumBits - count);
+ return 0;
+ }
+
+ static inline TWord BitMask(ui8 pos) {
+ return TWord(1) << pos;
+ }
+
+ static size_t NumOfWords(size_t bits) {
+ return (bits + NumBits - 1) >> DivShift;
+ }
+
+ static bool Test(const TWord* data, ui64 pos, ui64 size) {
+ Y_ASSERT(pos < size);
+ return data[pos >> DivShift] & BitMask(pos & ModMask);
+ }
+
+ static TWord Get(const TWord* data, ui64 pos, ui8 width, TWord mask, ui64 size) {
+ if (!width)
+ return 0;
+ Y_ASSERT((pos + width) <= size);
+ size_t word = pos >> DivShift;
+ TWord shift1 = pos & ModMask;
+ TWord shift2 = NumBits - shift1;
+ TWord res = data[word] >> shift1 & mask;
+ if (shift2 < width) {
+ res |= data[word + 1] << shift2 & mask;
+ }
+ return res;
+ }
+
+ static_assert(std::is_unsigned<TWord>::value, "Expected std::is_unsigned<T>::value.");
+ static_assert((NumBits & (NumBits - 1)) == 0, "NumBits should be a power of 2.");
+};
diff --git a/library/cpp/containers/bitseq/ut/ya.make b/library/cpp/containers/bitseq/ut/ya.make
new file mode 100644
index 0000000000..7155e82c06
--- /dev/null
+++ b/library/cpp/containers/bitseq/ut/ya.make
@@ -0,0 +1,10 @@
+UNITTEST_FOR(library/cpp/containers/bitseq)
+
+OWNER(g:util)
+
+SRCS(
+ bititerator_ut.cpp
+ bitvector_ut.cpp
+)
+
+END()
diff --git a/library/cpp/containers/bitseq/ya.make b/library/cpp/containers/bitseq/ya.make
new file mode 100644
index 0000000000..7090956c55
--- /dev/null
+++ b/library/cpp/containers/bitseq/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(g:util)
+
+PEERDIR(
+ util/draft
+ library/cpp/pop_count
+)
+
+SRCS(
+ bitvector.cpp
+ readonly_bitvector.cpp
+)
+
+END()
diff --git a/library/cpp/containers/compact_vector/compact_vector.cpp b/library/cpp/containers/compact_vector/compact_vector.cpp
new file mode 100644
index 0000000000..cca77643e9
--- /dev/null
+++ b/library/cpp/containers/compact_vector/compact_vector.cpp
@@ -0,0 +1 @@
+#include "compact_vector.h"
diff --git a/library/cpp/containers/compact_vector/compact_vector.h b/library/cpp/containers/compact_vector/compact_vector.h
new file mode 100644
index 0000000000..dbe7473f0c
--- /dev/null
+++ b/library/cpp/containers/compact_vector/compact_vector.h
@@ -0,0 +1,209 @@
+#pragma once
+
+#include <util/generic/yexception.h>
+#include <util/generic/utility.h>
+#include <util/memory/alloc.h>
+#include <util/stream/output.h>
+#include <util/system/yassert.h>
+
+#include <cstdlib>
+
+// vector that is 8 bytes when empty (TVector is 24 bytes)
+
+template <typename T>
+class TCompactVector {
+private:
+ typedef TCompactVector<T> TThis;
+
+ // XXX: make header independent on T and introduce nullptr
+ struct THeader {
+ size_t Size;
+ size_t Capacity;
+ };
+
+ T* Ptr;
+
+ THeader* Header() {
+ return ((THeader*)Ptr) - 1;
+ }
+
+ const THeader* Header() const {
+ return ((THeader*)Ptr) - 1;
+ }
+
+public:
+ typedef T* TIterator;
+ typedef const T* TConstIterator;
+
+ typedef TIterator iterator;
+ typedef TConstIterator const_iterator;
+
+ TCompactVector()
+ : Ptr(nullptr)
+ {
+ }
+
+ TCompactVector(const TThis& that)
+ : Ptr(nullptr)
+ {
+ Reserve(that.Size());
+ for (TConstIterator i = that.Begin(); i != that.End(); ++i) {
+ PushBack(*i);
+ }
+ }
+
+ ~TCompactVector() {
+ for (size_t i = 0; i < Size(); ++i) {
+ try {
+ (*this)[i].~T();
+ } catch (...) {
+ }
+ }
+ if (Ptr)
+ free(Header());
+ }
+
+ TIterator Begin() {
+ return Ptr;
+ }
+
+ TIterator End() {
+ return Ptr + Size();
+ }
+
+ TConstIterator Begin() const {
+ return Ptr;
+ }
+
+ TConstIterator End() const {
+ return Ptr + Size();
+ }
+
+ iterator begin() {
+ return Begin();
+ }
+
+ const_iterator begin() const {
+ return Begin();
+ }
+
+ iterator end() {
+ return End();
+ }
+
+ const_iterator end() const {
+ return End();
+ }
+
+ void Swap(TThis& that) {
+ DoSwap(Ptr, that.Ptr);
+ }
+
+ void Reserve(size_t newCapacity) {
+ if (newCapacity <= Capacity()) {
+ } else if (Ptr == nullptr) {
+ void* mem = ::malloc(sizeof(THeader) + newCapacity * sizeof(T));
+ if (mem == nullptr)
+ ythrow yexception() << "out of memory";
+ Ptr = (T*)(((THeader*)mem) + 1);
+ Header()->Size = 0;
+ Header()->Capacity = newCapacity;
+ } else {
+ TThis copy;
+ size_t realNewCapacity = Max(Capacity() * 2, newCapacity);
+ copy.Reserve(realNewCapacity);
+ for (TConstIterator it = Begin(); it != End(); ++it) {
+ copy.PushBack(*it);
+ }
+ Swap(copy);
+ }
+ }
+
+ size_t Size() const {
+ return Ptr ? Header()->Size : 0;
+ }
+
+ size_t size() const {
+ return Size();
+ }
+
+ bool Empty() const {
+ return Size() == 0;
+ }
+
+ bool empty() const {
+ return Empty();
+ }
+
+ size_t Capacity() const {
+ return Ptr ? Header()->Capacity : 0;
+ }
+
+ void PushBack(const T& elem) {
+ Reserve(Size() + 1);
+ new (Ptr + Size()) T(elem);
+ ++(Header()->Size);
+ }
+
+ T& Back() {
+ return *(End() - 1);
+ }
+
+ const T& Back() const {
+ return *(End() - 1);
+ }
+
+ T& back() {
+ return Back();
+ }
+
+ const T& back() const {
+ return Back();
+ }
+
+ TIterator Insert(TIterator pos, const T& elem) {
+ Y_ASSERT(pos >= Begin());
+ Y_ASSERT(pos <= End());
+
+ size_t posn = pos - Begin();
+ if (pos == End()) {
+ PushBack(elem);
+ } else {
+ Y_ASSERT(Size() > 0);
+
+ Reserve(Size() + 1);
+
+ PushBack(*(End() - 1));
+
+ for (size_t i = Size() - 2; i + 1 > posn; --i) {
+ (*this)[i + 1] = (*this)[i];
+ }
+
+ (*this)[posn] = elem;
+ }
+ return Begin() + posn;
+ }
+
+ iterator insert(iterator pos, const T& elem) {
+ return Insert(pos, elem);
+ }
+
+ void Clear() {
+ TThis clean;
+ Swap(clean);
+ }
+
+ void clear() {
+ Clear();
+ }
+
+ T& operator[](size_t index) {
+ Y_ASSERT(index < Size());
+ return Ptr[index];
+ }
+
+ const T& operator[](size_t index) const {
+ Y_ASSERT(index < Size());
+ return Ptr[index];
+ }
+};
diff --git a/library/cpp/containers/compact_vector/compact_vector_ut.cpp b/library/cpp/containers/compact_vector/compact_vector_ut.cpp
new file mode 100644
index 0000000000..7d413d6575
--- /dev/null
+++ b/library/cpp/containers/compact_vector/compact_vector_ut.cpp
@@ -0,0 +1,46 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "compact_vector.h"
+
+Y_UNIT_TEST_SUITE(TCompactVectorTest) {
+ Y_UNIT_TEST(TestSimple1) {
+ }
+
+ Y_UNIT_TEST(TestSimple) {
+ TCompactVector<ui32> vector;
+ for (ui32 i = 0; i < 10000; ++i) {
+ vector.PushBack(i + 20);
+ UNIT_ASSERT_VALUES_EQUAL(i + 1, vector.Size());
+ }
+ for (ui32 i = 0; i < 10000; ++i) {
+ UNIT_ASSERT_VALUES_EQUAL(i + 20, vector[i]);
+ }
+ }
+
+ Y_UNIT_TEST(TestInsert) {
+ TCompactVector<ui32> vector;
+
+ for (ui32 i = 0; i < 10; ++i) {
+ vector.PushBack(i + 2);
+ }
+
+ vector.Insert(vector.Begin(), 99);
+
+ UNIT_ASSERT_VALUES_EQUAL(11u, vector.Size());
+ UNIT_ASSERT_VALUES_EQUAL(99u, vector[0]);
+ for (ui32 i = 0; i < 10; ++i) {
+ UNIT_ASSERT_VALUES_EQUAL(i + 2, vector[i + 1]);
+ }
+
+ vector.Insert(vector.Begin() + 3, 77);
+
+ UNIT_ASSERT_VALUES_EQUAL(12u, vector.Size());
+ UNIT_ASSERT_VALUES_EQUAL(99u, vector[0]);
+ UNIT_ASSERT_VALUES_EQUAL(2u, vector[1]);
+ UNIT_ASSERT_VALUES_EQUAL(3u, vector[2]);
+ UNIT_ASSERT_VALUES_EQUAL(77u, vector[3]);
+ UNIT_ASSERT_VALUES_EQUAL(4u, vector[4]);
+ UNIT_ASSERT_VALUES_EQUAL(5u, vector[5]);
+ UNIT_ASSERT_VALUES_EQUAL(11u, vector[11]);
+ }
+}
diff --git a/library/cpp/containers/compact_vector/ut/ya.make b/library/cpp/containers/compact_vector/ut/ya.make
new file mode 100644
index 0000000000..5e655bc619
--- /dev/null
+++ b/library/cpp/containers/compact_vector/ut/ya.make
@@ -0,0 +1,11 @@
+UNITTEST()
+
+OWNER(nga)
+
+SRCDIR(library/cpp/containers/compact_vector)
+
+SRCS(
+ compact_vector_ut.cpp
+)
+
+END()
diff --git a/library/cpp/containers/compact_vector/ya.make b/library/cpp/containers/compact_vector/ya.make
new file mode 100644
index 0000000000..6c23e8d0c1
--- /dev/null
+++ b/library/cpp/containers/compact_vector/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(nga)
+
+SRCS(
+ compact_vector.cpp
+)
+
+END()
diff --git a/library/cpp/containers/comptrie/README.md b/library/cpp/containers/comptrie/README.md
new file mode 100644
index 0000000000..43c298e2c8
--- /dev/null
+++ b/library/cpp/containers/comptrie/README.md
@@ -0,0 +1,232 @@
+Compact trie
+=============
+
+The comptrie library is a fast and very tightly packed
+implementation of a prefix tree (Sedgewick's T-trie, that is a ternary tree,
+see https://www.cs.princeton.edu/~rs/strings/paper.pdf,
+https://www.cs.upc.edu/~ps/downloads/tst/tst.html). It contains tools for creating, optimizing, and serializing trees, accessing by key, and performing
+various searches. Because it is template-based and performance-oriented, a significant
+part of the library consists of inline functions, so if you don't need all the
+features of the library, consider including a more specific header file instead of the top-level
+comptrie.h file.
+
+Description of the data structure
+---------------------------------
+
+A prefix tree is an implementation of the map data structure
+for cases when keys are sequences of characters. The nodes on this tree
+contain characters and values. The key that corresponds to a
+value is a sequence of all the characters on nodes along the path from the root to the
+node with this value. It follows that a tree node can have as many children as
+there are different characters, which is quite a lot. For compact storage and
+quick access, the children are ordered as a binary search tree, which should be
+balanced if possible (characters have a defined order that must be
+preserved). Thus, our tree is ternary: each node has a reference to a subtree
+of all children and two references to subtrees of siblings. One of these subtrees contains the
+younger siblings, and the other contains the elder siblings.
+
+The library implements tree optimization by merging identical subtrees, which means
+the tree becomes a DAG (Directed Acyclic Graph –
+an oriented graph without oriented cycles).
+
+The main class TCompactTrie is defined in comptrie_trie.h and is templatized:
+- The first parameter of the template is the character type. It should be an
+integer type, which means that arithmetical operations must be defined for it.
+- The second parameter of the template is the value type.
+- The third parameter is the packer class, which packs values in order to quickly and compactly
+serialize the value type to a continuous memory buffer, deserialize it
+back, and quickly determine its size using the pointer to the beginning of this
+memory buffer. Good packers have already been written for most types, and they are available in
+library/cpp/packers. For more information, please refer to the documentation for these packers.
+
+The set.h file defines a modification for cases when keys must be stored
+without values.
+
+When a tree is built from scratch, the value corresponding to an empty key is
+assigned to a single-character key '\0'. So in a tree with the 'char' character type,
+the empty key and the '\0' key are bound together. For a subtree received from
+a call to FindTails, this restriction no longer exists.
+
+Creating trees
+--------------
+
+Building a tree from a list of key-value pairs is performed by the
+TCompactTrieBuilder class described in the comptrie_builder.h file.
+
+This class allows you to add words to a tree one at a time, merge a complete
+subtree, and also use an unfinished tree as a map.
+
+An important optimization is the prefix-grouped mode when you need to add keys
+in a certain order (for details, see the comments in the header file). The resulting tree is compactly packed while keys are being added, and the memory consumption is approximately the same as for
+the completed tree. For the default mode, compact stacking is turned on at the
+very end, and the data consumes quite a lot of memory up until that point.
+
+Optimizing trees
+----------------
+
+After a tree is created, there are two optimizing operations that can be applied:
+ - Minimization to a DAG by merging equal subtrees.
+ - Fast memory layout.
+The functions that implement these operations are declared in the comptrie_builder.h file. The first
+optimization is implemented by the CompactTrieMinimize function, and the second is implemented by
+CompactTrieMakeFastLayout. You can perform both at once by calling the
+CompactTrieMinimizeAndMakeFastLayout function.
+
+### Minimization ###
+
+Minimization to a DAG requires quite a lot of time and a large amount of
+memory to store an array of subtrees, but it can reduce the size of the tree several
+times over (an example is a language model that has many low-frequency
+phrases with repeated last words and frequency counts). However, if you know
+in advance that there are no duplicate values in the tree, you don't need to waste time on it, since the minimization
+won't have any effect on the tree.
+
+### Fast memory layout ###
+
+The second optimization function results in fewer cache misses, but it causes the
+tree to grow in size. Our experience has shown a 5% gain
+in speed for some tries. The algorithm consumes about three times more memory than
+the amount required for the source tree. So if the machine has enough memory to
+assemble a tree, it does not neccessarily mean that it has enough memory to run
+the algorithm. To learn about the theory behind this algorithm, read the comments before the declaration of the CompactTrieMinimize function.
+
+Serializing trees
+-----------------
+
+The tree resides in memory as a sequence of nodes. Links to other nodes are always
+counted relative to the position of the current node. This allows you to save a
+tree to disk as it is and then re-load it using mmap(). The TCompactTrie class has the
+TBlob constructor for reading a tree from disk. The TCompactTrieBuilder class has
+Save/SaveToFile methods for writing a built tree to a stream or a file.
+
+Accessing trees
+---------------
+
+As a rule, all methods that accept a key as input have two variants:
+- One takes the key in the format: pointer to the beginning of the key, length.
+- The other takes a high-level type like TStringBuf.
+
+You can get a value for a key in the tree – TCompactTrie::Find returns
+false if there is no key, and TCompactTrie::Get throws an exception. You can use FindPrefix methods to find the longest key prefix in a tree and get the corresponding value for it.
+You can also use a single FindPhrases request to get values for all the beginnings of
+a phrase with a given word delimiter.
+
+An important operation that distinguishes a tree from a simple map is implemented in the FindTails method,
+which allows you to obtain a subtree consisting of all possible extensions of the
+given prefix.
+
+Iterators for trees
+-------------------
+
+First of all, there is a typical map iterator over all key-value pairs called
+TConstIterator. A tree has three methods that return it: Begin, End, and
+UpperBound. The latter takes a key as input and returns an iterator to the
+smallest key that is not smaller than the input key.
+
+The rest of the iterators are not so widely used, and thus are located in
+separate files.
+
+TPrefixIterator is defined in the prefix_iterator.h file. It allows
+iterations over all the prefixes of this key available in the tree.
+
+TSearchIterator is defined in the search_iterator.h file. It allows you to enter
+a key in a tree one character at a time and see where it ends up. The following character can
+be selected depending on the current result. You can also copy the iterator and
+proceed on two different paths. You can actually achieve the same result with
+repeated use of the FindTails method, but the authors of this iterator claim
+that they obtained a performance gain with it.
+
+Appendix. Memory implementation details
+---------------------------------------
+
+*If you are not going to modify the library, then you do not need to read further.*
+
+First, if the character type has a size larger than 1 byte, then all keys that use these characters are converted to byte strings in the big-endian way. This
+means that character bytes are written in a string from the most significant
+to the least significant from left to right. Thus it is reduced to the case when
+the character in use is 'char'.
+
+The tree resides in memory as a series of consecutive nodes. The nodes can have different
+sizes, so the only way to identify the boundaries of nodes is by passing the entire
+tree.
+
+### Node structure ###
+
+The structure of a node, as can be understood from thoughtfully reading the
+LeapByte function in Comptrie_impl.h, is the following:
+- The first byte is for service flags.
+- The second byte is a character (unless it is the ε-link type of node
+ described below, which has from 1 to 7 bytes of offset distance from the
+ beginning of this node to the content node, and nothing else).
+
+Thus, the size of any node is at least 2 bytes. All other elements of a node
+are optional. Next there is from 0 to 7 bytes of the packed offset from the beginning
+of this node to the beginning of the root node of a subtree with the younger
+siblings. It is followed by 0 to 7 bytes of the packed offset from the beginning of this
+node to the beginning of the root node of a subtree with the elder siblings.
+Next comes the packed value in this node. Its size is not limited, but you may
+recall that the packer allows you to quickly determine this size using a pointer
+to the beginning of the packed value. Then, if the service flags indicate
+that the tree has children, there is a root node of the subtree of children.
+
+The packed offset is restricted to 7 bytes, and this gives us a limit on the largest
+possible size of a tree. You need to study the packer code to understand
+the exact limit.
+
+All packed offsets are nonnegative, meaning that roots of subtrees with
+siblings and the node pointed to by the ε-link must be located
+strictly to the right of the current node in memory. This does not allow placement of
+finite state machines with oriented cycles in the comptrie. But it does allow you to
+effectively stack the comptrie from right to left.
+
+### Service flags ###
+
+The byte of service flags contains (as shown by the constants at the beginning of
+the comptrie_impl.h file):
+- 1 bit of MT_NEXT, indicating whether this node has children.
+- 1 bit of MT_FINAL, indicating if there is a value in this node.
+- 3 bits of MT_SIZEMASK, indicating the size of the packed offset to a subtree
+ with elder siblings.
+- 3 bits of MT_SIZEMASK << MT_LEFTSHIFT, indicating the size of the packed
+ offset to a subtree with younger siblings.
+If one of these subtrees is not present, then the size of the corresponding
+packed offset is 0, and vice versa.
+
+### ε-links ###
+
+These nodes only occur if we optimized a tree into a DAG and got two nodes with
+merged subtrees of children. Since the offset to the subtree of children can't be
+specified and the root of this subtree should lie just after the value, we have
+to add a node of the ε-link type, which contains the offset to the root subtree of
+children and nothing more. This applies to all nodes that have equal subtrees of children,
+except the rightmost node. The size of this offset is set in 3 bits of MT_SIZEMASK
+flags for a node.
+
+As the implementation of the IsEpsilonLink function in
+comptrie_impl.h demonstrates, the ε-link differs from other nodes in that it does not have the MT_NEXT flag or the MT_FINAL
+ flag, so it can always be
+identified by the flags. Of course, the best programming practice is to call the
+function itself instead of examining the flags.
+
+Note that the ε-link flags do not use the MT_SIZEMASK <<
+MT_LEFTSHIFT` bits, which allows us to start using ε-links for some other purpose.
+
+Pattern Searcher
+================
+
+This is an implementation of Aho-Corasick algorithm on compact trie structure.
+In order to create a pattern searcher one must fill a TCompactPatternSearcherBuilder
+with patterns and call SaveAsPatternSearcher or SaveToFileAsPatternSearcher.
+Then TCompactPatternSearcher must be created from the builder output.
+
+### Implementation details ###
+
+Aho-Corasick algorithm stores a suffix link in each node.
+A suffix link of a node is the offset (relative to this node) of the largest suffix
+of a string this node represents which is present in a trie.
+Current implementation also stores a shortcut link to the largest suffix
+for which the corresponding node in a trie is a final node.
+These two links are stored as NCompactTrie::TSuffixLink structure of two 64-bit
+integers.
+In a trie layout these links are stored for each node right after the two bytes
+containing service flags and a symbol.
diff --git a/library/cpp/containers/comptrie/array_with_size.h b/library/cpp/containers/comptrie/array_with_size.h
new file mode 100644
index 0000000000..36e61c7410
--- /dev/null
+++ b/library/cpp/containers/comptrie/array_with_size.h
@@ -0,0 +1,67 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/generic/noncopyable.h>
+#include <util/generic/utility.h>
+#include <util/system/sys_alloc.h>
+
+template <typename T>
+class TArrayWithSizeHolder : TNonCopyable {
+ typedef TArrayWithSizeHolder<T> TThis;
+
+ T* Data;
+
+public:
+ TArrayWithSizeHolder()
+ : Data(nullptr)
+ {
+ }
+
+ ~TArrayWithSizeHolder() {
+ if (!Data)
+ return;
+ for (size_t i = 0; i < Size(); ++i) {
+ try {
+ Data[i].~T();
+ } catch (...) {
+ }
+ }
+ y_deallocate(((size_t*)Data) - 1);
+ }
+
+ void Swap(TThis& copy) {
+ DoSwap(Data, copy.Data);
+ }
+
+ void Resize(size_t newSize) {
+ if (newSize == Size())
+ return;
+ TThis copy;
+ copy.Data = (T*)(((size_t*)y_allocate(sizeof(size_t) + sizeof(T) * newSize)) + 1);
+ // does not handle constructor exceptions properly
+ for (size_t i = 0; i < Min(Size(), newSize); ++i) {
+ new (copy.Data + i) T(Data[i]);
+ }
+ for (size_t i = Min(Size(), newSize); i < newSize; ++i) {
+ new (copy.Data + i) T;
+ }
+ ((size_t*)copy.Data)[-1] = newSize;
+ Swap(copy);
+ }
+
+ size_t Size() const {
+ return Data ? ((size_t*)Data)[-1] : 0;
+ }
+
+ bool Empty() const {
+ return Size() == 0;
+ }
+
+ T* Get() {
+ return Data;
+ }
+
+ const T* Get() const {
+ return Data;
+ }
+};
diff --git a/library/cpp/containers/comptrie/benchmark/main.cpp b/library/cpp/containers/comptrie/benchmark/main.cpp
new file mode 100644
index 0000000000..6e42dad18a
--- /dev/null
+++ b/library/cpp/containers/comptrie/benchmark/main.cpp
@@ -0,0 +1,260 @@
+#include <library/cpp/testing/benchmark/bench.h>
+
+#include <library/cpp/containers/comptrie/comptrie_trie.h>
+#include <library/cpp/containers/comptrie/comptrie_builder.h>
+#include <library/cpp/containers/comptrie/search_iterator.h>
+#include <library/cpp/containers/comptrie/pattern_searcher.h>
+
+#include <library/cpp/on_disk/aho_corasick/writer.h>
+#include <library/cpp/on_disk/aho_corasick/reader.h>
+#include <library/cpp/on_disk/aho_corasick/helpers.h>
+
+#include <library/cpp/containers/dense_hash/dense_hash.h>
+
+#include <util/stream/file.h>
+#include <util/generic/algorithm.h>
+#include <util/random/fast.h>
+#include <util/random/shuffle.h>
+
+/////////////////
+// COMMON DATA //
+/////////////////
+
+const size_t MAX_PATTERN_LENGTH = 11;
+
+TVector<TString> letters = {
+ "а", "б", "в", "г", "д", "е", "ё", "ж", "з", "и", "й",
+ "к", "л", "м", "н", "о", "п", "р", "с", "т", "у", "ф",
+ "х", "ц", "ч", "ж", "щ", "ъ", "ы", "ь", "э", "ю", "я"
+};
+
+TString GenerateOneString(
+ TFastRng<ui64>& rng,
+ size_t maxLength,
+ const TVector<TString>& sequences
+) {
+ size_t length = rng.GenRand() % maxLength + 1;
+ TString result;
+ while (result.size() < length) {
+ result += sequences[rng.GenRand() % sequences.size()];
+ }
+ return result;
+}
+
+TVector<TString> GenerateStrings(
+ TFastRng<ui64>& rng,
+ size_t num,
+ size_t maxLength,
+ const TVector<TString>& sequences
+) {
+ TVector<TString> strings;
+ while (strings.size() < num) {
+ strings.push_back(GenerateOneString(rng, maxLength, sequences));
+ }
+ return strings;
+}
+
+struct TDatasetInstance {
+ TDatasetInstance(const TVector<TString>& sequences) {
+ TFastRng<ui64> rng(0);
+
+ TVector<TString> prefixes = GenerateStrings(rng, /*num*/10, /*maxLength*/3, sequences);
+ prefixes.push_back("");
+
+ TVector<TString> roots = GenerateStrings(rng, /*num*/1000, /*maxLength*/5, sequences);
+
+ TVector<TString> suffixes = GenerateStrings(rng, /*num*/10, /*maxLength*/3, sequences);
+ suffixes.push_back("");
+
+ TVector<TString> dictionary;
+ for (const auto& root : roots) {
+ for (const auto& prefix : prefixes) {
+ for (const auto& suffix : suffixes) {
+ dictionary.push_back(prefix + root + suffix);
+ Y_ASSERT(dictionary.back().size() < MAX_PATTERN_LENGTH);
+ }
+ }
+ }
+ Shuffle(dictionary.begin(), dictionary.end());
+
+ Patterns.assign(dictionary.begin(), dictionary.begin() + 10'000);
+
+ for (size_t sampleIdx = 0; sampleIdx < /*samplesNum*/1'000'000; ++sampleIdx) {
+ Samples.emplace_back();
+ size_t wordsNum = rng.GenRand() % 10;
+ for (size_t wordIdx = 0; wordIdx < wordsNum; ++wordIdx) {
+ if (wordIdx > 0) {
+ Samples.back() += " ";
+ }
+ Samples.back() += dictionary[rng.GenRand() % dictionary.size()];
+ }
+ }
+ };
+
+ TString GetSample(size_t iteration) const {
+ TFastRng<ui64> rng(iteration);
+ return Samples[rng.GenRand() % Samples.size()];
+ }
+
+
+ TVector<TString> Patterns;
+ TVector<TString> Samples;
+};
+
+static const TDatasetInstance dataset(letters);
+
+//////////////////////////
+// NEW PATTERN SEARCHER //
+//////////////////////////
+
+struct TPatternSearcherInstance {
+ TPatternSearcherInstance() {
+ TCompactPatternSearcherBuilder<char, ui32> builder;
+
+ for (ui32 patternId = 0; patternId < dataset.Patterns.size(); ++patternId) {
+ builder.Add(dataset.Patterns[patternId], patternId);
+ }
+
+ TBufferOutput buffer;
+ builder.Save(buffer);
+
+ Instance.Reset(
+ new TCompactPatternSearcher<char, ui32>(
+ buffer.Buffer().Data(),
+ buffer.Buffer().Size()
+ )
+ );
+ }
+
+ THolder<TCompactPatternSearcher<char, ui32>> Instance;
+};
+
+static const TPatternSearcherInstance patternSearcherInstance;
+
+Y_CPU_BENCHMARK(PatternSearcher, iface) {
+ TVector<TVector<std::pair<ui32, ui32>>> result;
+ for (size_t iteration = 0; iteration < iface.Iterations(); ++iteration) {
+ result.emplace_back();
+ TString testString = dataset.GetSample(iteration);
+ auto matches = patternSearcherInstance.Instance->SearchMatches(testString);
+ for (auto& match : matches) {
+ result.back().emplace_back(match.End, match.Data);
+ }
+ }
+}
+
+//////////////////////
+// OLD AHO CORASICK //
+//////////////////////
+
+struct TAhoCorasickInstance {
+ TAhoCorasickInstance() {
+ TAhoCorasickBuilder<TString, ui32> builder;
+
+ for (ui32 patternId = 0; patternId < dataset.Patterns.size(); ++patternId) {
+ builder.AddString(dataset.Patterns[patternId], patternId);
+ }
+
+ TBufferOutput buffer;
+ builder.SaveToStream(&buffer);
+
+ Instance.Reset(new TDefaultMappedAhoCorasick(TBlob::FromBuffer(buffer.Buffer())));
+ };
+
+ THolder<TDefaultMappedAhoCorasick> Instance;
+};
+
+static const TAhoCorasickInstance ahoCorasickInstance;
+
+Y_CPU_BENCHMARK(AhoCorasick, iface) {
+ TVector<TDeque<std::pair<ui32, ui32>>> result;
+ for (size_t iteration = 0; iteration < iface.Iterations(); ++iteration) {
+ result.emplace_back();
+ TString testString = dataset.GetSample(iteration);
+ auto matches = ahoCorasickInstance.Instance->AhoSearch(testString);
+ result.push_back(matches);
+ }
+}
+
+////////////////////////////////
+// COMPTRIE + SIMPLE MATCHING //
+////////////////////////////////
+
+struct TCompactTrieInstance {
+ TCompactTrieInstance() {
+ TCompactTrieBuilder<char, ui32> builder;
+
+ for (ui32 patternId = 0; patternId < dataset.Patterns.size(); ++patternId) {
+ builder.Add(dataset.Patterns[patternId], patternId);
+ }
+
+
+ TBufferOutput buffer;
+ CompactTrieMinimizeAndMakeFastLayout(buffer, builder);
+
+ Instance.Reset(new TCompactTrie<char, ui32>(
+ buffer.Buffer().Data(),
+ buffer.Buffer().Size()
+ ));
+ }
+
+ THolder<TCompactTrie<char, ui32>> Instance;
+};
+
+static const TCompactTrieInstance compactTrieInstance;
+
+Y_CPU_BENCHMARK(ComptrieSimple, iface) {
+ TVector<TVector<std::pair<ui32, ui32>>> result;
+ for (size_t iteration = 0; iteration < iface.Iterations(); ++iteration) {
+ result.emplace_back();
+ TString testString = dataset.GetSample(iteration);
+ for (ui32 startPos = 0; startPos < testString.size(); ++startPos) {
+ TSearchIterator<TCompactTrie<char, ui32>> iter(*(compactTrieInstance.Instance));
+ for (ui32 position = startPos; position < testString.size(); ++position) {
+ if (!iter.Advance(testString[position])) {
+ break;
+ }
+ ui32 answer;
+ if (iter.GetValue(&answer)) {
+ result.back().emplace_back(position, answer);
+ }
+ }
+ }
+ }
+}
+
+////////////////
+// DENSE_HASH //
+////////////////
+
+struct TDenseHashInstance {
+ TDenseHashInstance() {
+ for (ui32 patternId = 0; patternId < dataset.Patterns.size(); ++patternId) {
+ Instance[dataset.Patterns[patternId]] = patternId;
+ }
+ }
+
+ TDenseHash<TString, ui32> Instance;
+};
+
+static const TDenseHashInstance denseHashInstance;
+
+Y_CPU_BENCHMARK(DenseHash, iface) {
+ TVector<TVector<std::pair<ui32, ui32>>> result;
+ for (size_t iteration = 0; iteration < iface.Iterations(); ++iteration) {
+ result.emplace_back();
+ TString testString = dataset.GetSample(iteration);
+ for (size_t start = 0; start < testString.size(); ++start) {
+ for (
+ size_t length = 1;
+ length <= MAX_PATTERN_LENGTH && start + length <= testString.size();
+ ++length
+ ) {
+ auto value = denseHashInstance.Instance.find(testString.substr(start, length));
+ if (value != denseHashInstance.Instance.end()) {
+ result.back().emplace_back(start + length - 1, value->second);
+ }
+ }
+ }
+ }
+}
diff --git a/library/cpp/containers/comptrie/benchmark/ya.make b/library/cpp/containers/comptrie/benchmark/ya.make
new file mode 100644
index 0000000000..16fa19530d
--- /dev/null
+++ b/library/cpp/containers/comptrie/benchmark/ya.make
@@ -0,0 +1,14 @@
+Y_BENCHMARK()
+
+OWNER(smirnovpavel)
+
+SRCS(
+ main.cpp
+)
+
+PEERDIR(
+ library/cpp/containers/comptrie
+ util
+)
+
+END()
diff --git a/library/cpp/containers/comptrie/chunked_helpers_trie.h b/library/cpp/containers/comptrie/chunked_helpers_trie.h
new file mode 100644
index 0000000000..cfa35f5ba2
--- /dev/null
+++ b/library/cpp/containers/comptrie/chunked_helpers_trie.h
@@ -0,0 +1,218 @@
+#pragma once
+
+#include <library/cpp/on_disk/chunks/chunked_helpers.h>
+
+#include "comptrie.h"
+
+class TTrieSet {
+private:
+ TCompactTrie<char> Trie;
+
+public:
+ TTrieSet(const TBlob& blob)
+ : Trie(blob)
+ {
+ }
+
+ bool Has(const char* key) const {
+ return Trie.Find(key, strlen(key));
+ }
+
+ bool FindLongestPrefix(const char* key, size_t keylen, size_t* prefixLen) {
+ return Trie.FindLongestPrefix(key, keylen, prefixLen);
+ }
+};
+
+template <bool sorted = false>
+class TTrieSetWriter {
+private:
+ TCompactTrieBuilder<char> Builder;
+
+public:
+ TTrieSetWriter(bool isSorted = sorted)
+ : Builder(isSorted ? CTBF_PREFIX_GROUPED : CTBF_NONE)
+ {
+ }
+
+ void Add(const char* key, size_t keylen) {
+ Builder.Add(key, keylen, 0);
+ assert(Has(((TString)key).substr(0, keylen).data()));
+ }
+
+ void Add(const char* key) {
+ Add(key, strlen(key));
+ }
+
+ bool Has(const char* key) const {
+ ui64 dummy;
+ return Builder.Find(key, strlen(key), &dummy);
+ }
+
+ void Save(IOutputStream& out) const {
+ Builder.Save(out);
+ }
+
+ void Clear() {
+ Builder.Clear();
+ }
+};
+
+template <bool isWriter, bool sorted = false>
+struct TTrieSetG;
+
+template <bool sorted>
+struct TTrieSetG<false, sorted> {
+ typedef TTrieSet T;
+};
+
+template <bool sorted>
+struct TTrieSetG<true, sorted> {
+ typedef TTrieSetWriter<sorted> T;
+};
+
+template <typename T>
+class TTrieMap {
+private:
+ TCompactTrie<char> Trie;
+ static_assert(sizeof(T) <= sizeof(ui64), "expect sizeof(T) <= sizeof(ui64)");
+
+public:
+ TTrieMap(const TBlob& blob)
+ : Trie(blob)
+ {
+ }
+
+ bool Get(const char* key, T* value) const {
+ ui64 trieValue;
+ if (Trie.Find(key, strlen(key), &trieValue)) {
+ *value = ReadUnaligned<T>(&trieValue);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ T Get(const char* key, T def = T()) const {
+ ui64 trieValue;
+ if (Trie.Find(key, strlen(key), &trieValue)) {
+ return ReadUnaligned<T>(&trieValue);
+ } else {
+ return def;
+ }
+ }
+
+ const TCompactTrie<char>& GetTrie() const {
+ return Trie;
+ }
+};
+
+template <typename T, bool sorted = false>
+class TTrieMapWriter {
+private:
+ typedef TCompactTrieBuilder<char> TBuilder;
+ TBuilder Builder;
+ static_assert(sizeof(T) <= sizeof(ui64), "expect sizeof(T) <= sizeof(ui64)");
+#ifndef NDEBUG
+ bool IsSorted;
+#endif
+
+public:
+ TTrieMapWriter(bool isSorted = sorted)
+ : Builder(isSorted ? CTBF_PREFIX_GROUPED : CTBF_NONE)
+#ifndef NDEBUG
+ , IsSorted(isSorted)
+#endif
+ {
+ }
+
+ void Add(const char* key, const T& value) {
+ ui64 intValue = 0;
+ memcpy(&intValue, &value, sizeof(T));
+ Builder.Add(key, strlen(key), intValue);
+#ifndef NDEBUG
+ /*
+ if (!IsSorted) {
+ T test;
+ assert(Get(key, &test) && value == test);
+ }
+ */
+#endif
+ }
+
+ void Add(const TString& s, const T& value) {
+ ui64 intValue = 0;
+ memcpy(&intValue, &value, sizeof(T));
+ Builder.Add(s.data(), s.size(), intValue);
+ }
+
+ bool Get(const char* key, T* value) const {
+ ui64 trieValue;
+ if (Builder.Find(key, strlen(key), &trieValue)) {
+ *value = ReadUnaligned<T>(&trieValue);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ T Get(const char* key, T def = (T)0) const {
+ ui64 trieValue;
+ if (Builder.Find(key, strlen(key), &trieValue)) {
+ return ReadUnaligned<T>(&trieValue);
+ } else {
+ return def;
+ }
+ }
+
+ void Save(IOutputStream& out, bool minimize = false) const {
+ if (minimize) {
+ CompactTrieMinimize<TBuilder>(out, Builder, false);
+ } else {
+ Builder.Save(out);
+ }
+ }
+
+ void Clear() {
+ Builder.Clear();
+ }
+};
+
+template <typename T>
+class TTrieSortedMapWriter {
+private:
+ typedef std::pair<TString, T> TValue;
+ typedef TVector<TValue> TValues;
+ TValues Values;
+
+public:
+ TTrieSortedMapWriter() = default;
+
+ void Add(const char* key, const T& value) {
+ Values.push_back(TValue(key, value));
+ }
+
+ void Save(IOutputStream& out) {
+ Sort(Values.begin(), Values.end());
+ TTrieMapWriter<T, true> writer;
+ for (typename TValues::const_iterator toValue = Values.begin(); toValue != Values.end(); ++toValue)
+ writer.Add(toValue->first.data(), toValue->second);
+ writer.Save(out);
+ }
+
+ void Clear() {
+ Values.clear();
+ }
+};
+
+template <typename X, bool isWriter, bool sorted = false>
+struct TTrieMapG;
+
+template <typename X, bool sorted>
+struct TTrieMapG<X, false, sorted> {
+ typedef TTrieMap<X> T;
+};
+
+template <typename X, bool sorted>
+struct TTrieMapG<X, true, sorted> {
+ typedef TTrieMapWriter<X, sorted> T;
+};
diff --git a/library/cpp/containers/comptrie/comptrie.cpp b/library/cpp/containers/comptrie/comptrie.cpp
new file mode 100644
index 0000000000..4556e5b571
--- /dev/null
+++ b/library/cpp/containers/comptrie/comptrie.cpp
@@ -0,0 +1,8 @@
+#include "comptrie_impl.h"
+#include "comptrie.h"
+#include "array_with_size.h"
+#include "comptrie_trie.h"
+#include "comptrie_builder.h"
+#include "protopacker.h"
+#include "set.h"
+#include "chunked_helpers_trie.h"
diff --git a/library/cpp/containers/comptrie/comptrie.h b/library/cpp/containers/comptrie/comptrie.h
new file mode 100644
index 0000000000..f77024327e
--- /dev/null
+++ b/library/cpp/containers/comptrie/comptrie.h
@@ -0,0 +1,4 @@
+#pragma once
+
+#include "comptrie_trie.h"
+#include "comptrie_builder.h"
diff --git a/library/cpp/containers/comptrie/comptrie_builder.cpp b/library/cpp/containers/comptrie/comptrie_builder.cpp
new file mode 100644
index 0000000000..28a1e41dd2
--- /dev/null
+++ b/library/cpp/containers/comptrie/comptrie_builder.cpp
@@ -0,0 +1 @@
+#include "comptrie_builder.h"
diff --git a/library/cpp/containers/comptrie/comptrie_builder.h b/library/cpp/containers/comptrie/comptrie_builder.h
new file mode 100644
index 0000000000..cf7d2e39a3
--- /dev/null
+++ b/library/cpp/containers/comptrie/comptrie_builder.h
@@ -0,0 +1,159 @@
+#pragma once
+
+#include "comptrie_packer.h"
+#include "minimize.h"
+#include "key_selector.h"
+
+#include <util/stream/file.h>
+
+// --------------------------------------------------------------------------------------
+// Data Builder
+// To build the data buffer, we first create an automaton in memory. The automaton
+// is created incrementally. It actually helps a lot to have the input data prefix-grouped
+// by key; otherwise, memory consumption becomes a tough issue.
+// NOTE: building and serializing the automaton may be lengthy, and takes lots of memory.
+
+// PREFIX_GROUPED means that if we, while constructing a trie, add to the builder two keys with the same prefix,
+// then all the keys that we add between these two also have the same prefix.
+// Actually in this mode the builder can accept even more freely ordered input,
+// but for input as above it is guaranteed to work.
+enum ECompactTrieBuilderFlags {
+ CTBF_NONE = 0,
+ CTBF_PREFIX_GROUPED = 1 << 0,
+ CTBF_VERBOSE = 1 << 1,
+ CTBF_UNIQUE = 1 << 2,
+};
+
+using TCompactTrieBuilderFlags = ECompactTrieBuilderFlags;
+
+inline TCompactTrieBuilderFlags operator|(TCompactTrieBuilderFlags first, TCompactTrieBuilderFlags second) {
+ return static_cast<TCompactTrieBuilderFlags>(static_cast<int>(first) | second);
+}
+
+inline TCompactTrieBuilderFlags& operator|=(TCompactTrieBuilderFlags& first, TCompactTrieBuilderFlags second) {
+ return first = first | second;
+}
+
+template <typename T>
+class TArrayWithSizeHolder;
+
+template <class T = char, class D = ui64, class S = TCompactTriePacker<D>>
+class TCompactTrieBuilder {
+public:
+ typedef T TSymbol;
+ typedef D TData;
+ typedef S TPacker;
+ typedef typename TCompactTrieKeySelector<TSymbol>::TKey TKey;
+ typedef typename TCompactTrieKeySelector<TSymbol>::TKeyBuf TKeyBuf;
+
+ explicit TCompactTrieBuilder(TCompactTrieBuilderFlags flags = CTBF_NONE, TPacker packer = TPacker(), IAllocator* alloc = TDefaultAllocator::Instance());
+
+ // All Add.. methods return true if it was a new key, false if the key already existed.
+
+ bool Add(const TSymbol* key, size_t keylen, const TData& value);
+ bool Add(const TKeyBuf& key, const TData& value) {
+ return Add(key.data(), key.size(), value);
+ }
+
+ // add already serialized data
+ bool AddPtr(const TSymbol* key, size_t keylen, const char* data);
+ bool AddPtr(const TKeyBuf& key, const char* data) {
+ return AddPtr(key.data(), key.size(), data);
+ }
+
+ bool AddSubtreeInFile(const TSymbol* key, size_t keylen, const TString& filename);
+ bool AddSubtreeInFile(const TKeyBuf& key, const TString& filename) {
+ return AddSubtreeInFile(key.data(), key.size(), filename);
+ }
+
+ bool AddSubtreeInBuffer(const TSymbol* key, size_t keylen, TArrayWithSizeHolder<char>&& buffer);
+ bool AddSubtreeInBuffer(const TKeyBuf& key, TArrayWithSizeHolder<char>&& buffer) {
+ return AddSubtreeInBuffer(key.data(), key.size(), std::move(buffer));
+ }
+
+ bool Find(const TSymbol* key, size_t keylen, TData* value) const;
+ bool Find(const TKeyBuf& key, TData* value = nullptr) const {
+ return Find(key.data(), key.size(), value);
+ }
+
+ bool FindLongestPrefix(const TSymbol* key, size_t keylen, size_t* prefixLen, TData* value = nullptr) const;
+ bool FindLongestPrefix(const TKeyBuf& key, size_t* prefixLen, TData* value = nullptr) const {
+ return FindLongestPrefix(key.data(), key.size(), prefixLen, value);
+ }
+
+ size_t Save(IOutputStream& os) const;
+ size_t SaveAndDestroy(IOutputStream& os);
+ size_t SaveToFile(const TString& fileName) const {
+ TFixedBufferFileOutput out(fileName);
+ return Save(out);
+ }
+
+ void Clear(); // Returns all memory to the system and resets the builder state.
+
+ size_t GetEntryCount() const;
+ size_t GetNodeCount() const;
+
+ // Exact output file size in bytes.
+ size_t MeasureByteSize() const {
+ return Impl->MeasureByteSize();
+ }
+
+protected:
+ class TCompactTrieBuilderImpl;
+ THolder<TCompactTrieBuilderImpl> Impl;
+};
+
+//----------------------------------------------------------------------------------------------------------------------
+// Minimize the trie. The result is equivalent to the original
+// trie, except that it takes less space (and has marginally lower
+// performance, because of eventual epsilon links).
+// The algorithm is as follows: starting from the largest pieces, we find
+// nodes that have identical continuations (Daciuk's right language),
+// and repack the trie. Repacking is done in-place, so memory is less
+// of an issue; however, it may take considerable time.
+
+// IMPORTANT: never try to reminimize an already minimized trie or a trie with fast layout.
+// Because of non-local structure and epsilon links, it won't work
+// as you expect it to, and can destroy the trie in the making.
+// If you want both minimization and fast layout, do the minimization first.
+
+template <class TPacker>
+size_t CompactTrieMinimize(IOutputStream& os, const char* data, size_t datalength, bool verbose = false, const TPacker& packer = TPacker(), NCompactTrie::EMinimizeMode mode = NCompactTrie::MM_DEFAULT);
+
+template <class TTrieBuilder>
+size_t CompactTrieMinimize(IOutputStream& os, const TTrieBuilder& builder, bool verbose = false);
+
+//----------------------------------------------------------------------------------------------------------------
+// Lay the trie in memory in such a way that there are less cache misses when jumping from root to leaf.
+// The trie becomes about 2% larger, but the access became about 25% faster in our experiments.
+// Can be called on minimized and non-minimized tries, in the first case in requires half a trie more memory.
+// Calling it the second time on the same trie does nothing.
+//
+// The algorithm is based on van Emde Boas layout as described in the yandex data school lectures on external memory algoritms
+// by Maxim Babenko and Ivan Puzyrevsky. The difference is that when we cut the tree into levels
+// two nodes connected by a forward link are put into the same level (because they usually lie near each other in the original tree).
+// The original paper (describing the layout in Section 2.1) is:
+// Michael A. Bender, Erik D. Demaine, Martin Farach-Colton. Cache-Oblivious B-Trees
+// SIAM Journal on Computing, volume 35, number 2, 2005, pages 341-358.
+// Available on the web: http://erikdemaine.org/papers/CacheObliviousBTrees_SICOMP/
+// Or: Michael A. Bender, Erik D. Demaine, and Martin Farach-Colton. Cache-Oblivious B-Trees
+// Proceedings of the 41st Annual Symposium
+// on Foundations of Computer Science (FOCS 2000), Redondo Beach, California, November 12-14, 2000, pages 399-409.
+// Available on the web: http://erikdemaine.org/papers/FOCS2000b/
+// (there is not much difference between these papers, actually).
+//
+template <class TPacker>
+size_t CompactTrieMakeFastLayout(IOutputStream& os, const char* data, size_t datalength, bool verbose = false, const TPacker& packer = TPacker());
+
+template <class TTrieBuilder>
+size_t CompactTrieMakeFastLayout(IOutputStream& os, const TTrieBuilder& builder, bool verbose = false);
+
+// Composition of minimization and fast layout
+template <class TPacker>
+size_t CompactTrieMinimizeAndMakeFastLayout(IOutputStream& os, const char* data, size_t datalength, bool verbose = false, const TPacker& packer = TPacker());
+
+template <class TTrieBuilder>
+size_t CompactTrieMinimizeAndMakeFastLayout(IOutputStream& os, const TTrieBuilder& builder, bool verbose = false);
+
+// Implementation details moved here.
+#include "comptrie_builder.inl"
diff --git a/library/cpp/containers/comptrie/comptrie_builder.inl b/library/cpp/containers/comptrie/comptrie_builder.inl
new file mode 100644
index 0000000000..f273fa6571
--- /dev/null
+++ b/library/cpp/containers/comptrie/comptrie_builder.inl
@@ -0,0 +1,1121 @@
+#pragma once
+
+#include "comptrie_impl.h"
+#include "comptrie_trie.h"
+#include "make_fast_layout.h"
+#include "array_with_size.h"
+
+#include <library/cpp/containers/compact_vector/compact_vector.h>
+
+#include <util/memory/alloc.h>
+#include <util/memory/blob.h>
+#include <util/memory/pool.h>
+#include <util/memory/tempbuf.h>
+#include <util/memory/smallobj.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/buffer.h>
+#include <util/generic/strbuf.h>
+
+#include <util/system/align.h>
+#include <util/stream/buffer.h>
+
+#define CONSTEXPR_MAX2(a, b) (a) > (b) ? (a) : (b)
+#define CONSTEXPR_MAX3(a, b, c) CONSTEXPR_MAX2(CONSTEXPR_MAX2(a, b), c)
+
+// TCompactTrieBuilder::TCompactTrieBuilderImpl
+
+template <class T, class D, class S>
+class TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl {
+protected:
+ TMemoryPool Pool;
+ size_t PayloadSize;
+ THolder<TFixedSizeAllocator> NodeAllocator;
+ class TNode;
+ class TArc;
+ TNode* Root;
+ TCompactTrieBuilderFlags Flags;
+ size_t EntryCount;
+ size_t NodeCount;
+ TPacker Packer;
+
+ enum EPayload {
+ DATA_ABSENT,
+ DATA_INSIDE,
+ DATA_MALLOCED,
+ DATA_IN_MEMPOOL,
+ };
+
+protected:
+ void ConvertSymbolArrayToChar(const TSymbol* key, size_t keylen, TTempBuf& buf, size_t ckeylen) const;
+ void NodeLinkTo(TNode* thiz, const TBlob& label, TNode* node);
+ TNode* NodeForwardAdd(TNode* thiz, const char* label, size_t len, size_t& passed, size_t* nodeCount);
+ bool FindEntryImpl(const char* key, size_t keylen, TData* value) const;
+ bool FindLongestPrefixImpl(const char* keyptr, size_t keylen, size_t* prefixLen, TData* value) const;
+
+ size_t NodeMeasureSubtree(TNode* thiz) const;
+ ui64 NodeSaveSubtree(TNode* thiz, IOutputStream& os) const;
+ ui64 NodeSaveSubtreeAndDestroy(TNode* thiz, IOutputStream& osy);
+ void NodeBufferSubtree(TNode* thiz);
+
+ size_t NodeMeasureLeafValue(TNode* thiz) const;
+ ui64 NodeSaveLeafValue(TNode* thiz, IOutputStream& os) const;
+
+ virtual ui64 ArcMeasure(const TArc* thiz, size_t leftsize, size_t rightsize) const;
+
+ virtual ui64 ArcSaveSelf(const TArc* thiz, IOutputStream& os) const;
+ ui64 ArcSave(const TArc* thiz, IOutputStream& os) const;
+ ui64 ArcSaveAndDestroy(const TArc* thiz, IOutputStream& os);
+
+public:
+ TCompactTrieBuilderImpl(TCompactTrieBuilderFlags flags, TPacker packer, IAllocator* alloc);
+ virtual ~TCompactTrieBuilderImpl();
+
+ void DestroyNode(TNode* node);
+ void NodeReleasePayload(TNode* thiz);
+
+ char* AddEntryForData(const TSymbol* key, size_t keylen, size_t dataLen, bool& isNewAddition);
+ TNode* AddEntryForSomething(const TSymbol* key, size_t keylen, bool& isNewAddition);
+
+ bool AddEntry(const TSymbol* key, size_t keylen, const TData& value);
+ bool AddEntryPtr(const TSymbol* key, size_t keylen, const char* value);
+ bool AddSubtreeInFile(const TSymbol* key, size_t keylen, const TString& fileName);
+ bool AddSubtreeInBuffer(const TSymbol* key, size_t keylen, TArrayWithSizeHolder<char>&& buffer);
+ bool FindEntry(const TSymbol* key, size_t keylen, TData* value) const;
+ bool FindLongestPrefix(const TSymbol* key, size_t keylen, size_t* prefixlen, TData* value) const;
+
+ size_t Save(IOutputStream& os) const;
+ size_t SaveAndDestroy(IOutputStream& os);
+
+ void Clear();
+
+ // lies if some key was added at least twice
+ size_t GetEntryCount() const;
+ size_t GetNodeCount() const;
+
+ size_t MeasureByteSize() const {
+ return NodeMeasureSubtree(Root);
+ }
+};
+
+template <class T, class D, class S>
+class TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TArc {
+public:
+ TBlob Label;
+ TNode* Node;
+ mutable size_t LeftOffset;
+ mutable size_t RightOffset;
+
+ TArc(const TBlob& lbl, TNode* nd);
+};
+
+template <class T, class D, class S>
+class TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode {
+public:
+ typedef typename TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl TBuilderImpl;
+ typedef typename TBuilderImpl::TArc TArc;
+
+ struct ISubtree {
+ virtual ~ISubtree() = default;
+ virtual bool IsLast() const = 0;
+ virtual ui64 Measure(const TBuilderImpl* builder) const = 0;
+ virtual ui64 Save(const TBuilderImpl* builder, IOutputStream& os) const = 0;
+ virtual ui64 SaveAndDestroy(TBuilderImpl* builder, IOutputStream& os) = 0;
+ virtual void Destroy(TBuilderImpl*) { }
+
+ // Tries to find key in subtree.
+ // Returns next node to find the key in (to avoid recursive calls)
+ // If it has end result, writes it to @value and @result arguments and returns nullptr
+ virtual const TNode* Find(TStringBuf& key, TData* value, bool& result, const TPacker& packer) const = 0;
+ virtual const TNode* FindLongestPrefix(TStringBuf& key, TData* value, bool& result, const TPacker& packer) const = 0;
+ };
+
+ class TArcSet: public ISubtree, public TCompactVector<TArc> {
+ public:
+ typedef typename TCompactVector<TArc>::iterator iterator;
+ typedef typename TCompactVector<TArc>::const_iterator const_iterator;
+
+ TArcSet() {
+ Y_ASSERT(reinterpret_cast<ISubtree*>(this) == static_cast<void*>(this)); // This assumption is used in TNode::Subtree()
+ }
+
+ iterator Find(char ch);
+ const_iterator Find(char ch) const;
+ void Add(const TBlob& s, TNode* node);
+
+ bool IsLast() const override {
+ return this->Empty();
+ }
+
+ const TNode* Find(TStringBuf& key, TData* value, bool& result, const TPacker& packer) const override;
+ const TNode* FindLongestPrefix(TStringBuf& key, TData* value, bool& result, const TPacker& packer) const override {
+ return Find(key, value, result, packer);
+ }
+
+ ui64 Measure(const TBuilderImpl* builder) const override {
+ return MeasureRange(builder, 0, this->size());
+ }
+
+ ui64 MeasureRange(const TBuilderImpl* builder, size_t from, size_t to) const {
+ if (from >= to)
+ return 0;
+
+ size_t median = (from + to) / 2;
+ size_t leftsize = (size_t)MeasureRange(builder, from, median);
+ size_t rightsize = (size_t)MeasureRange(builder, median + 1, to);
+
+ return builder->ArcMeasure(&(*this)[median], leftsize, rightsize);
+ }
+
+ ui64 Save(const TBuilderImpl* builder, IOutputStream& os) const override {
+ return SaveRange(builder, 0, this->size(), os);
+ }
+
+ ui64 SaveAndDestroy(TBuilderImpl* builder, IOutputStream& os) override {
+ ui64 result = SaveRangeAndDestroy(builder, 0, this->size(), os);
+ Destroy(builder);
+ return result;
+ }
+
+ ui64 SaveRange(const TBuilderImpl* builder, size_t from, size_t to, IOutputStream& os) const {
+ if (from >= to)
+ return 0;
+
+ size_t median = (from + to) / 2;
+
+ ui64 written = builder->ArcSave(&(*this)[median], os);
+ written += SaveRange(builder, from, median, os);
+ written += SaveRange(builder, median + 1, to, os);
+ return written;
+ }
+
+ ui64 SaveRangeAndDestroy(TBuilderImpl* builder, size_t from, size_t to, IOutputStream& os) {
+ if (from >= to)
+ return 0;
+
+ size_t median = (from + to) / 2;
+
+ ui64 written = builder->ArcSaveAndDestroy(&(*this)[median], os);
+ written += SaveRangeAndDestroy(builder, from, median, os);
+ written += SaveRangeAndDestroy(builder, median + 1, to, os);
+ return written;
+ }
+
+ void Destroy(TBuilderImpl* builder) override {
+ // Delete all nodes down the stream.
+ for (iterator it = this->begin(); it != this->end(); ++it) {
+ builder->DestroyNode(it->Node);
+ }
+ this->clear();
+ }
+
+ ~TArcSet() override {
+ Y_ASSERT(this->empty());
+ }
+
+ };
+
+ struct TBufferedSubtree: public ISubtree {
+ TArrayWithSizeHolder<char> Buffer;
+
+ TBufferedSubtree() {
+ Y_ASSERT(reinterpret_cast<ISubtree*>(this) == static_cast<void*>(this)); // This assumption is used in TNode::Subtree()
+ }
+
+ bool IsLast() const override {
+ return Buffer.Empty();
+ }
+
+ const TNode* Find(TStringBuf& key, TData* value, bool& result, const TPacker& packer) const override {
+ if (Buffer.Empty()) {
+ result = false;
+ return nullptr;
+ }
+
+ TCompactTrie<char, D, S> trie(Buffer.Get(), Buffer.Size(), packer);
+ result = trie.Find(key.data(), key.size(), value);
+
+ return nullptr;
+ }
+
+ const TNode* FindLongestPrefix(TStringBuf& key, TData* value, bool& result, const TPacker& packer) const override {
+ if (Buffer.Empty()) {
+ result = false;
+ return nullptr;
+ }
+
+ TCompactTrie<char, D, S> trie(Buffer.Get(), Buffer.Size(), packer);
+ size_t prefixLen = 0;
+ result = trie.FindLongestPrefix(key.data(), key.size(), &prefixLen, value);
+ key = key.SubStr(prefixLen);
+
+ return nullptr;
+ }
+
+ ui64 Measure(const TBuilderImpl*) const override {
+ return Buffer.Size();
+ }
+
+ ui64 Save(const TBuilderImpl*, IOutputStream& os) const override {
+ os.Write(Buffer.Get(), Buffer.Size());
+ return Buffer.Size();
+ }
+
+ ui64 SaveAndDestroy(TBuilderImpl* builder, IOutputStream& os) override {
+ ui64 result = Save(builder, os);
+ TArrayWithSizeHolder<char>().Swap(Buffer);
+ return result;
+ }
+ };
+
+ struct TSubtreeInFile: public ISubtree {
+ struct TData {
+ TString FileName;
+ ui64 Size;
+ };
+ THolder<TData> Data;
+
+ TSubtreeInFile(const TString& fileName) {
+ // stupid API
+ TFile file(fileName, RdOnly);
+ i64 size = file.GetLength();
+ if (size < 0)
+ ythrow yexception() << "unable to get file " << fileName.Quote() << " size for unknown reason";
+ Data.Reset(new TData);
+ Data->FileName = fileName;
+ Data->Size = size;
+
+ Y_ASSERT(reinterpret_cast<ISubtree*>(this) == static_cast<void*>(this)); // This assumption is used in TNode::Subtree()
+ }
+
+ bool IsLast() const override {
+ return Data->Size == 0;
+ }
+
+ const TNode* Find(TStringBuf& key, typename TCompactTrieBuilder::TData* value, bool& result, const TPacker& packer) const override {
+ if (!Data) {
+ result = false;
+ return nullptr;
+ }
+
+ TCompactTrie<char, D, S> trie(TBlob::FromFile(Data->FileName), packer);
+ result = trie.Find(key.data(), key.size(), value);
+ return nullptr;
+ }
+
+ const TNode* FindLongestPrefix(TStringBuf& key, typename TCompactTrieBuilder::TData* value, bool& result, const TPacker& packer) const override {
+ if (!Data) {
+ result = false;
+ return nullptr;
+ }
+
+ TCompactTrie<char, D, S> trie(TBlob::FromFile(Data->FileName), packer);
+ size_t prefixLen = 0;
+ result = trie.FindLongestPrefix(key.data(), key.size(), &prefixLen, value);
+ key = key.SubStr(prefixLen);
+
+ return nullptr;
+ }
+
+ ui64 Measure(const TBuilderImpl*) const override {
+ return Data->Size;
+ }
+
+ ui64 Save(const TBuilderImpl*, IOutputStream& os) const override {
+ TUnbufferedFileInput is(Data->FileName);
+ ui64 written = TransferData(&is, &os);
+ if (written != Data->Size)
+ ythrow yexception() << "file " << Data->FileName.Quote() << " size changed";
+ return written;
+ }
+
+ ui64 SaveAndDestroy(TBuilderImpl* builder, IOutputStream& os) override {
+ return Save(builder, os);
+ }
+ };
+
+ union {
+ char ArcsData[CONSTEXPR_MAX3(sizeof(TArcSet), sizeof(TBufferedSubtree), sizeof(TSubtreeInFile))];
+ union {
+ void* Data1;
+ long long int Data2;
+ } Aligner;
+ };
+
+ inline ISubtree* Subtree() {
+ return reinterpret_cast<ISubtree*>(ArcsData);
+ }
+
+ inline const ISubtree* Subtree() const {
+ return reinterpret_cast<const ISubtree*>(ArcsData);
+ }
+
+ EPayload PayloadType;
+
+ inline const char* PayloadPtr() const {
+ return ((const char*) this) + sizeof(TNode);
+ }
+
+ inline char* PayloadPtr() {
+ return ((char*) this) + sizeof(TNode);
+ }
+
+ // *Payload()
+ inline const char*& PayloadAsPtr() const {
+ const char** payload = (const char**) PayloadPtr();
+ return *payload;
+ }
+
+ inline char*& PayloadAsPtr() {
+ char** payload = (char**) PayloadPtr();
+ return *payload;
+ }
+
+ inline const char* GetPayload() const {
+ switch (PayloadType) {
+ case DATA_INSIDE:
+ return PayloadPtr();
+ case DATA_MALLOCED:
+ case DATA_IN_MEMPOOL:
+ return PayloadAsPtr();
+ case DATA_ABSENT:
+ default:
+ abort();
+ }
+ }
+
+ inline char* GetPayload() {
+ const TNode* thiz = this;
+ return const_cast<char*>(thiz->GetPayload()); // const_cast is to avoid copy-paste style
+ }
+
+ bool IsFinal() const {
+ return PayloadType != DATA_ABSENT;
+ }
+
+ bool IsLast() const {
+ return Subtree()->IsLast();
+ }
+
+ inline void* operator new(size_t, TFixedSizeAllocator& pool) {
+ return pool.Allocate();
+ }
+
+ inline void operator delete(void* ptr, TFixedSizeAllocator& pool) noexcept {
+ pool.Release(ptr);
+ }
+
+ TNode()
+ : PayloadType(DATA_ABSENT)
+ {
+ new (Subtree()) TArcSet;
+ }
+
+ ~TNode() {
+ Subtree()->~ISubtree();
+ Y_ASSERT(PayloadType == DATA_ABSENT);
+ }
+
+};
+
+// TCompactTrieBuilder
+
+template <class T, class D, class S>
+TCompactTrieBuilder<T, D, S>::TCompactTrieBuilder(TCompactTrieBuilderFlags flags, TPacker packer, IAllocator* alloc)
+ : Impl(new TCompactTrieBuilderImpl(flags, packer, alloc))
+{
+}
+
+template <class T, class D, class S>
+bool TCompactTrieBuilder<T, D, S>::Add(const TSymbol* key, size_t keylen, const TData& value) {
+ return Impl->AddEntry(key, keylen, value);
+}
+
+template <class T, class D, class S>
+bool TCompactTrieBuilder<T, D, S>::AddPtr(const TSymbol* key, size_t keylen, const char* value) {
+ return Impl->AddEntryPtr(key, keylen, value);
+}
+
+template <class T, class D, class S>
+bool TCompactTrieBuilder<T, D, S>::AddSubtreeInFile(const TSymbol* key, size_t keylen, const TString& fileName) {
+ return Impl->AddSubtreeInFile(key, keylen, fileName);
+}
+
+template <class T, class D, class S>
+bool TCompactTrieBuilder<T, D, S>::AddSubtreeInBuffer(const TSymbol* key, size_t keylen, TArrayWithSizeHolder<char>&& buffer) {
+ return Impl->AddSubtreeInBuffer(key, keylen, std::move(buffer));
+}
+
+template <class T, class D, class S>
+bool TCompactTrieBuilder<T, D, S>::Find(const TSymbol* key, size_t keylen, TData* value) const {
+ return Impl->FindEntry(key, keylen, value);
+}
+
+template <class T, class D, class S>
+bool TCompactTrieBuilder<T, D, S>::FindLongestPrefix(
+ const TSymbol* key, size_t keylen, size_t* prefixlen, TData* value) const {
+ return Impl->FindLongestPrefix(key, keylen, prefixlen, value);
+}
+
+template <class T, class D, class S>
+size_t TCompactTrieBuilder<T, D, S>::Save(IOutputStream& os) const {
+ return Impl->Save(os);
+}
+
+template <class T, class D, class S>
+size_t TCompactTrieBuilder<T, D, S>::SaveAndDestroy(IOutputStream& os) {
+ return Impl->SaveAndDestroy(os);
+}
+
+template <class T, class D, class S>
+void TCompactTrieBuilder<T, D, S>::Clear() {
+ Impl->Clear();
+}
+
+template <class T, class D, class S>
+size_t TCompactTrieBuilder<T, D, S>::GetEntryCount() const {
+ return Impl->GetEntryCount();
+}
+
+template <class T, class D, class S>
+size_t TCompactTrieBuilder<T, D, S>::GetNodeCount() const {
+ return Impl->GetNodeCount();
+}
+
+// TCompactTrieBuilder::TCompactTrieBuilderImpl
+
+template <class T, class D, class S>
+TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TCompactTrieBuilderImpl(TCompactTrieBuilderFlags flags, TPacker packer, IAllocator* alloc)
+ : Pool(1000000, TMemoryPool::TLinearGrow::Instance(), alloc)
+ , PayloadSize(sizeof(void*)) // XXX: find better value
+ , NodeAllocator(new TFixedSizeAllocator(sizeof(TNode) + PayloadSize, alloc))
+ , Flags(flags)
+ , EntryCount(0)
+ , NodeCount(1)
+ , Packer(packer)
+{
+ Root = new (*NodeAllocator) TNode;
+}
+
+template <class T, class D, class S>
+TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::~TCompactTrieBuilderImpl() {
+ DestroyNode(Root);
+}
+
+template <class T, class D, class S>
+void TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::ConvertSymbolArrayToChar(
+ const TSymbol* key, size_t keylen, TTempBuf& buf, size_t buflen) const {
+ char* ckeyptr = buf.Data();
+
+ for (size_t i = 0; i < keylen; ++i) {
+ TSymbol label = key[i];
+ for (int j = (int)NCompactTrie::ExtraBits<TSymbol>(); j >= 0; j -= 8) {
+ Y_ASSERT(ckeyptr < buf.Data() + buflen);
+ *(ckeyptr++) = (char)(label >> j);
+ }
+ }
+
+ buf.Proceed(buflen);
+ Y_ASSERT(ckeyptr == buf.Data() + buf.Filled());
+}
+
+template <class T, class D, class S>
+void TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::DestroyNode(TNode* thiz) {
+ thiz->Subtree()->Destroy(this);
+ NodeReleasePayload(thiz);
+ thiz->~TNode();
+ NodeAllocator->Release(thiz);
+}
+
+template <class T, class D, class S>
+void TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeReleasePayload(TNode* thiz) {
+ switch (thiz->PayloadType) {
+ case DATA_ABSENT:
+ case DATA_INSIDE:
+ case DATA_IN_MEMPOOL:
+ break;
+ case DATA_MALLOCED:
+ delete[] thiz->PayloadAsPtr();
+ break;
+ default:
+ abort();
+ }
+ thiz->PayloadType = DATA_ABSENT;
+}
+
+template <class T, class D, class S>
+bool TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::AddEntry(
+ const TSymbol* key, size_t keylen, const TData& value) {
+ size_t datalen = Packer.MeasureLeaf(value);
+
+ bool isNewAddition = false;
+ char* place = AddEntryForData(key, keylen, datalen, isNewAddition);
+ Packer.PackLeaf(place, value, datalen);
+ return isNewAddition;
+}
+
+template <class T, class D, class S>
+bool TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::AddEntryPtr(
+ const TSymbol* key, size_t keylen, const char* value) {
+ size_t datalen = Packer.SkipLeaf(value);
+
+ bool isNewAddition = false;
+ char* place = AddEntryForData(key, keylen, datalen, isNewAddition);
+ memcpy(place, value, datalen);
+ return isNewAddition;
+}
+
+template <class T, class D, class S>
+bool TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::AddSubtreeInFile(
+ const TSymbol* key, size_t keylen, const TString& fileName) {
+ typedef typename TNode::ISubtree ISubtree;
+ typedef typename TNode::TSubtreeInFile TSubtreeInFile;
+
+ bool isNewAddition = false;
+ TNode* node = AddEntryForSomething(key, keylen, isNewAddition);
+ node->Subtree()->Destroy(this);
+ node->Subtree()->~ISubtree();
+
+ new (node->Subtree()) TSubtreeInFile(fileName);
+ return isNewAddition;
+}
+
+template <class T, class D, class S>
+bool TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::AddSubtreeInBuffer(
+ const TSymbol* key, size_t keylen, TArrayWithSizeHolder<char>&& buffer) {
+
+ typedef typename TNode::TBufferedSubtree TBufferedSubtree;
+
+ bool isNewAddition = false;
+ TNode* node = AddEntryForSomething(key, keylen, isNewAddition);
+ node->Subtree()->Destroy(this);
+ node->Subtree()->~ISubtree();
+
+ auto subtree = new (node->Subtree()) TBufferedSubtree();
+ subtree->Buffer.Swap(buffer);
+
+ return isNewAddition;
+}
+
+template <class T, class D, class S>
+typename TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode*
+ TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::AddEntryForSomething(
+ const TSymbol* key, size_t keylen, bool& isNewAddition) {
+ using namespace NCompactTrie;
+
+ EntryCount++;
+
+ if (Flags & CTBF_VERBOSE)
+ ShowProgress(EntryCount);
+
+ TNode* current = Root;
+ size_t passed;
+
+ // Special case of empty key: replace it by 1-byte "\0" key.
+ size_t ckeylen = keylen ? keylen * sizeof(TSymbol) : 1;
+ TTempBuf ckeybuf(ckeylen);
+ if (keylen == 0) {
+ ckeybuf.Append("\0", 1);
+ } else {
+ ConvertSymbolArrayToChar(key, keylen, ckeybuf, ckeylen);
+ }
+
+ char* ckey = ckeybuf.Data();
+
+ TNode* next;
+ while ((ckeylen > 0) && (next = NodeForwardAdd(current, ckey, ckeylen, passed, &NodeCount)) != nullptr) {
+ current = next;
+ ckeylen -= passed;
+ ckey += passed;
+ }
+
+ if (ckeylen != 0) {
+ //new leaf
+ NodeCount++;
+ TNode* leaf = new (*NodeAllocator) TNode();
+ NodeLinkTo(current, TBlob::Copy(ckey, ckeylen), leaf);
+ current = leaf;
+ }
+ isNewAddition = (current->PayloadType == DATA_ABSENT);
+ if ((Flags & CTBF_UNIQUE) && !isNewAddition)
+ ythrow yexception() << "Duplicate key";
+ return current;
+}
+
+template <class T, class D, class S>
+char* TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::AddEntryForData(const TSymbol* key, size_t keylen,
+ size_t datalen, bool& isNewAddition) {
+ TNode* current = AddEntryForSomething(key, keylen, isNewAddition);
+ NodeReleasePayload(current);
+ if (datalen <= PayloadSize) {
+ current->PayloadType = DATA_INSIDE;
+ } else if (Flags & CTBF_PREFIX_GROUPED) {
+ current->PayloadType = DATA_MALLOCED;
+ current->PayloadAsPtr() = new char[datalen];
+ } else {
+ current->PayloadType = DATA_IN_MEMPOOL;
+ current->PayloadAsPtr() = (char*) Pool.Allocate(datalen); // XXX: allocate unaligned
+ }
+ return current->GetPayload();
+}
+
+template <class T, class D, class S>
+bool TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::FindEntry(const TSymbol* key, size_t keylen, TData* value) const {
+ using namespace NCompactTrie;
+
+ if (!keylen) {
+ const char zero = '\0';
+ return FindEntryImpl(&zero, 1, value);
+ } else {
+ size_t ckeylen = keylen * sizeof(TSymbol);
+ TTempBuf ckeybuf(ckeylen);
+ ConvertSymbolArrayToChar(key, keylen, ckeybuf, ckeylen);
+ return FindEntryImpl(ckeybuf.Data(), ckeylen, value);
+ }
+}
+
+template <class T, class D, class S>
+bool TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::FindEntryImpl(const char* keyptr, size_t keylen, TData* value) const {
+ const TNode* node = Root;
+ bool result = false;
+ TStringBuf key(keyptr, keylen);
+ while (key && (node = node->Subtree()->Find(key, value, result, Packer))) {
+ }
+ return result;
+}
+
+template <class T, class D, class S>
+bool TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::FindLongestPrefix(
+ const TSymbol* key, size_t keylen, size_t* prefixlen, TData* value) const {
+ using namespace NCompactTrie;
+
+ if (!keylen) {
+ const char zero = '\0';
+ const bool ret = FindLongestPrefixImpl(&zero, 1, prefixlen, value);
+ if (ret && prefixlen)
+ *prefixlen = 0; // empty key found
+ return ret;
+ } else {
+ size_t ckeylen = keylen * sizeof(TSymbol);
+ TTempBuf ckeybuf(ckeylen);
+ ConvertSymbolArrayToChar(key, keylen, ckeybuf, ckeylen);
+ bool ret = FindLongestPrefixImpl(ckeybuf.Data(), ckeylen, prefixlen, value);
+ if (ret && prefixlen && *prefixlen == 1 && ckeybuf.Data()[0] == '\0')
+ *prefixlen = 0; // if we have found empty key, set prefixlen to zero
+ else if (!ret) // try to find value with empty key, because empty key is prefix of a every key
+ ret = FindLongestPrefix(nullptr, 0, prefixlen, value);
+
+ if (ret && prefixlen)
+ *prefixlen /= sizeof(TSymbol);
+
+ return ret;
+ }
+}
+
+template <class T, class D, class S>
+bool TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::FindLongestPrefixImpl(const char* keyptr, size_t keylen, size_t* prefixLen, TData* value) const {
+ const TNode* node = Root;
+ const TNode* lastFinalNode = nullptr;
+ bool endResult = false;
+ TStringBuf key(keyptr, keylen);
+ TStringBuf keyTail = key;
+ TStringBuf lastFinalKeyTail;
+ while (keyTail && (node = node->Subtree()->FindLongestPrefix(keyTail, value, endResult, Packer))) {
+ if (endResult) // no more ways to find prefix and prefix has been found
+ break;
+
+ if (node->IsFinal()) {
+ lastFinalNode = node;
+ lastFinalKeyTail = keyTail;
+ }
+ }
+ if (!endResult && lastFinalNode) {
+ if (value)
+ Packer.UnpackLeaf(lastFinalNode->GetPayload(), *value);
+ keyTail = lastFinalKeyTail;
+ endResult = true;
+ }
+ if (endResult && prefixLen)
+ *prefixLen = keyTail ? key.size() - keyTail.size() : key.size();
+ return endResult;
+}
+
+template <class T, class D, class S>
+void TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::Clear() {
+ DestroyNode(Root);
+ Pool.Clear();
+ NodeAllocator.Reset(new TFixedSizeAllocator(sizeof(TNode) + PayloadSize, TDefaultAllocator::Instance()));
+ Root = new (*NodeAllocator) TNode;
+ EntryCount = 0;
+ NodeCount = 1;
+}
+
+template <class T, class D, class S>
+size_t TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::Save(IOutputStream& os) const {
+ const size_t len = NodeMeasureSubtree(Root);
+ if (len != NodeSaveSubtree(Root, os))
+ ythrow yexception() << "something wrong";
+
+ return len;
+}
+
+template <class T, class D, class S>
+size_t TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::SaveAndDestroy(IOutputStream& os) {
+ const size_t len = NodeMeasureSubtree(Root);
+ if (len != NodeSaveSubtreeAndDestroy(Root, os))
+ ythrow yexception() << "something wrong";
+
+ return len;
+}
+
+template <class T, class D, class S>
+size_t TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::GetEntryCount() const {
+ return EntryCount;
+}
+
+template <class T, class D, class S>
+size_t TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::GetNodeCount() const {
+ return NodeCount;
+}
+
+template <class T, class D, class S>
+typename TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode*
+ TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeForwardAdd(
+ TNode* thiz, const char* label, size_t len, size_t& passed, size_t* nodeCount) {
+ typename TNode::TArcSet* arcSet = dynamic_cast<typename TNode::TArcSet*>(thiz->Subtree());
+ if (!arcSet)
+ ythrow yexception() << "Bad input order - expected input strings to be prefix-grouped.";
+
+ typename TNode::TArcSet::iterator it = arcSet->Find(*label);
+
+ if (it != arcSet->end()) {
+ const char* arcLabel = it->Label.AsCharPtr();
+ size_t arcLabelLen = it->Label.Length();
+
+ for (passed = 0; (passed < len) && (passed < arcLabelLen) && (label[passed] == arcLabel[passed]); ++passed) {
+ //just count
+ }
+
+ if (passed < arcLabelLen) {
+ (*nodeCount)++;
+ TNode* node = new (*NodeAllocator) TNode();
+ NodeLinkTo(node, it->Label.SubBlob(passed, arcLabelLen), it->Node);
+
+ it->Node = node;
+ it->Label = it->Label.SubBlob(passed);
+ }
+
+ return it->Node;
+ }
+
+ return nullptr;
+}
+
+template <class T, class D, class S>
+void TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeLinkTo(TNode* thiz, const TBlob& label, TNode* node) {
+ typename TNode::TArcSet* arcSet = dynamic_cast<typename TNode::TArcSet*>(thiz->Subtree());
+ if (!arcSet)
+ ythrow yexception() << "Bad input order - expected input strings to be prefix-grouped.";
+
+ // Buffer the node at the last arc
+ if ((Flags & CTBF_PREFIX_GROUPED) && !arcSet->empty())
+ NodeBufferSubtree(arcSet->back().Node);
+
+ arcSet->Add(label, node);
+}
+
+template <class T, class D, class S>
+size_t TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeMeasureSubtree(TNode* thiz) const {
+ return (size_t)thiz->Subtree()->Measure(this);
+}
+
+template <class T, class D, class S>
+ui64 TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeSaveSubtree(TNode* thiz, IOutputStream& os) const {
+ return thiz->Subtree()->Save(this, os);
+}
+
+template <class T, class D, class S>
+ui64 TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeSaveSubtreeAndDestroy(TNode* thiz, IOutputStream& os) {
+ return thiz->Subtree()->SaveAndDestroy(this, os);
+}
+
+template <class T, class D, class S>
+void TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeBufferSubtree(TNode* thiz) {
+ typedef typename TNode::TArcSet TArcSet;
+
+ TArcSet* arcSet = dynamic_cast<TArcSet*>(thiz->Subtree());
+ if (!arcSet)
+ return;
+
+ size_t bufferLength = (size_t)arcSet->Measure(this);
+ TArrayWithSizeHolder<char> buffer;
+ buffer.Resize(bufferLength);
+
+ TMemoryOutput bufout(buffer.Get(), buffer.Size());
+
+ ui64 written = arcSet->Save(this, bufout);
+ Y_ASSERT(written == bufferLength);
+
+ arcSet->Destroy(this);
+ arcSet->~TArcSet();
+
+ typename TNode::TBufferedSubtree* bufferedArcSet = new (thiz->Subtree()) typename TNode::TBufferedSubtree;
+
+ bufferedArcSet->Buffer.Swap(buffer);
+}
+
+template <class T, class D, class S>
+size_t TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeMeasureLeafValue(TNode* thiz) const {
+ if (!thiz->IsFinal())
+ return 0;
+
+ return Packer.SkipLeaf(thiz->GetPayload());
+}
+
+template <class T, class D, class S>
+ui64 TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeSaveLeafValue(TNode* thiz, IOutputStream& os) const {
+ if (!thiz->IsFinal())
+ return 0;
+
+ size_t len = Packer.SkipLeaf(thiz->GetPayload());
+ os.Write(thiz->GetPayload(), len);
+ return len;
+}
+
+// TCompactTrieBuilder::TCompactTrieBuilderImpl::TNode::TArc
+
+template <class T, class D, class S>
+TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TArc::TArc(const TBlob& lbl, TNode* nd)
+ : Label(lbl)
+ , Node(nd)
+ , LeftOffset(0)
+ , RightOffset(0)
+{}
+
+template <class T, class D, class S>
+ui64 TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::ArcMeasure(
+ const TArc* thiz, size_t leftsize, size_t rightsize) const {
+ using namespace NCompactTrie;
+
+ size_t coresize = 2 + NodeMeasureLeafValue(thiz->Node); // 2 == (char + flags)
+ size_t treesize = NodeMeasureSubtree(thiz->Node);
+
+ if (thiz->Label.Length() > 0)
+ treesize += 2 * (thiz->Label.Length() - 1);
+
+ // Triple measurements are needed because the space needed to store the offset
+ // shall be added to the offset itself. Hence three iterations.
+ size_t leftoffsetsize = leftsize ? MeasureOffset(coresize + treesize) : 0;
+ size_t rightoffsetsize = rightsize ? MeasureOffset(coresize + treesize + leftsize) : 0;
+ leftoffsetsize = leftsize ? MeasureOffset(coresize + treesize + leftoffsetsize + rightoffsetsize) : 0;
+ rightoffsetsize = rightsize ? MeasureOffset(coresize + treesize + leftsize + leftoffsetsize + rightoffsetsize) : 0;
+ leftoffsetsize = leftsize ? MeasureOffset(coresize + treesize + leftoffsetsize + rightoffsetsize) : 0;
+ rightoffsetsize = rightsize ? MeasureOffset(coresize + treesize + leftsize + leftoffsetsize + rightoffsetsize) : 0;
+
+ coresize += leftoffsetsize + rightoffsetsize;
+ thiz->LeftOffset = leftsize ? coresize + treesize : 0;
+ thiz->RightOffset = rightsize ? coresize + treesize + leftsize : 0;
+
+ return coresize + treesize + leftsize + rightsize;
+}
+
+template <class T, class D, class S>
+ui64 TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::ArcSaveSelf(const TArc* thiz, IOutputStream& os) const {
+ using namespace NCompactTrie;
+
+ ui64 written = 0;
+
+ size_t leftoffsetsize = MeasureOffset(thiz->LeftOffset);
+ size_t rightoffsetsize = MeasureOffset(thiz->RightOffset);
+
+ size_t labelLen = thiz->Label.Length();
+
+ for (size_t i = 0; i < labelLen; ++i) {
+ char flags = 0;
+
+ if (i == 0) {
+ flags |= (leftoffsetsize << MT_LEFTSHIFT);
+ flags |= (rightoffsetsize << MT_RIGHTSHIFT);
+ }
+
+ if (i == labelLen-1) {
+ if (thiz->Node->IsFinal())
+ flags |= MT_FINAL;
+
+ if (!thiz->Node->IsLast())
+ flags |= MT_NEXT;
+ } else {
+ flags |= MT_NEXT;
+ }
+
+ os.Write(&flags, 1);
+ os.Write(&thiz->Label.AsCharPtr()[i], 1);
+ written += 2;
+
+ if (i == 0) {
+ written += ArcSaveOffset(thiz->LeftOffset, os);
+ written += ArcSaveOffset(thiz->RightOffset, os);
+ }
+ }
+
+ written += NodeSaveLeafValue(thiz->Node, os);
+ return written;
+}
+
+template <class T, class D, class S>
+ui64 TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::ArcSave(const TArc* thiz, IOutputStream& os) const {
+ ui64 written = ArcSaveSelf(thiz, os);
+ written += NodeSaveSubtree(thiz->Node, os);
+ return written;
+}
+
+template <class T, class D, class S>
+ui64 TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::ArcSaveAndDestroy(const TArc* thiz, IOutputStream& os) {
+ ui64 written = ArcSaveSelf(thiz, os);
+ written += NodeSaveSubtreeAndDestroy(thiz->Node, os);
+ return written;
+}
+
+// TCompactTrieBuilder::TCompactTrieBuilderImpl::TNode::TArcSet
+
+template <class T, class D, class S>
+typename TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode::TArcSet::iterator
+ TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode::TArcSet::Find(char ch) {
+ using namespace NCompTriePrivate;
+ iterator it = LowerBound(this->begin(), this->end(), ch, TCmp());
+
+ if (it != this->end() && it->Label[0] == (unsigned char)ch) {
+ return it;
+ }
+
+ return this->end();
+}
+
+template <class T, class D, class S>
+typename TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode::TArcSet::const_iterator
+ TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode::TArcSet::Find(char ch) const {
+ using namespace NCompTriePrivate;
+ const_iterator it = LowerBound(this->begin(), this->end(), ch, TCmp());
+
+ if (it != this->end() && it->Label[0] == (unsigned char)ch) {
+ return it;
+ }
+
+ return this->end();
+}
+
+template <class T, class D, class S>
+void TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode::TArcSet::Add(const TBlob& s, TNode* node) {
+ using namespace NCompTriePrivate;
+ this->insert(LowerBound(this->begin(), this->end(), s[0], TCmp()), TArc(s, node));
+}
+
+template <class T, class D, class S>
+const typename TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode*
+ TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode::TArcSet::Find(
+ TStringBuf& key, TData* value, bool& result, const TPacker& packer) const {
+ result = false;
+ if (!key)
+ return nullptr;
+
+ const const_iterator it = Find(key[0]);
+ if (it != this->end()) {
+ const char* const arcLabel = it->Label.AsCharPtr();
+ const size_t arcLabelLen = it->Label.Length();
+ if (key.size() >= arcLabelLen && memcmp(key.data(), arcLabel, arcLabelLen) == 0) {
+ const TStringBuf srcKey = key;
+ key = key.SubStr(arcLabelLen);
+ const TNode* const node = it->Node;
+ if (srcKey.size() == arcLabelLen) {
+ // unpack value of it->Node, if it has value
+ if (!node->IsFinal())
+ return nullptr;
+
+ if (value)
+ packer.UnpackLeaf(node->GetPayload(), *value);
+
+ result = true;
+ return nullptr;
+ }
+
+ // find in subtree
+ return node;
+ }
+ }
+
+ return nullptr;
+}
+
+// Different
+
+//----------------------------------------------------------------------------------------------------------------------
+// Minimize the trie. The result is equivalent to the original
+// trie, except that it takes less space (and has marginally lower
+// performance, because of eventual epsilon links).
+// The algorithm is as follows: starting from the largest pieces, we find
+// nodes that have identical continuations (Daciuk's right language),
+// and repack the trie. Repacking is done in-place, so memory is less
+// of an issue; however, it may take considerable time.
+
+// IMPORTANT: never try to reminimize an already minimized trie or a trie with fast layout.
+// Because of non-local structure and epsilon links, it won't work
+// as you expect it to, and can destroy the trie in the making.
+
+template <class TPacker>
+size_t CompactTrieMinimize(IOutputStream& os, const char* data, size_t datalength, bool verbose /*= false*/, const TPacker& packer /*= TPacker()*/, NCompactTrie::EMinimizeMode mode) {
+ using namespace NCompactTrie;
+ return CompactTrieMinimizeImpl(os, data, datalength, verbose, &packer, mode);
+}
+
+template <class TTrieBuilder>
+size_t CompactTrieMinimize(IOutputStream& os, const TTrieBuilder& builder, bool verbose /*=false*/) {
+ TBufferStream buftmp;
+ size_t len = builder.Save(buftmp);
+ return CompactTrieMinimize<typename TTrieBuilder::TPacker>(os, buftmp.Buffer().Data(), len, verbose);
+}
+
+//----------------------------------------------------------------------------------------------------------------
+// Lay the trie in memory in such a way that there are less cache misses when jumping from root to leaf.
+// The trie becomes about 2% larger, but the access became about 25% faster in our experiments.
+// Can be called on minimized and non-minimized tries, in the first case in requires half a trie more memory.
+// Calling it the second time on the same trie does nothing.
+//
+// The algorithm is based on van Emde Boas layout as described in the yandex data school lectures on external memory algoritms
+// by Maxim Babenko and Ivan Puzyrevsky. The difference is that when we cut the tree into levels
+// two nodes connected by a forward link are put into the same level (because they usually lie near each other in the original tree).
+// The original paper (describing the layout in Section 2.1) is:
+// Michael A. Bender, Erik D. Demaine, Martin Farach-Colton. Cache-Oblivious B-Trees
+// SIAM Journal on Computing, volume 35, number 2, 2005, pages 341-358.
+// Available on the web: http://erikdemaine.org/papers/CacheObliviousBTrees_SICOMP/
+// Or: Michael A. Bender, Erik D. Demaine, and Martin Farach-Colton. Cache-Oblivious B-Trees
+// Proceedings of the 41st Annual Symposium
+// on Foundations of Computer Science (FOCS 2000), Redondo Beach, California, November 12-14, 2000, pages 399-409.
+// Available on the web: http://erikdemaine.org/papers/FOCS2000b/
+// (there is not much difference between these papers, actually).
+//
+template <class TPacker>
+size_t CompactTrieMakeFastLayout(IOutputStream& os, const char* data, size_t datalength, bool verbose /*= false*/, const TPacker& packer /*= TPacker()*/) {
+ using namespace NCompactTrie;
+ return CompactTrieMakeFastLayoutImpl(os, data, datalength, verbose, &packer);
+}
+
+template <class TTrieBuilder>
+size_t CompactTrieMakeFastLayout(IOutputStream& os, const TTrieBuilder& builder, bool verbose /*=false*/) {
+ TBufferStream buftmp;
+ size_t len = builder.Save(buftmp);
+ return CompactTrieMakeFastLayout<typename TTrieBuilder::TPacker>(os, buftmp.Buffer().Data(), len, verbose);
+}
+
+template <class TPacker>
+size_t CompactTrieMinimizeAndMakeFastLayout(IOutputStream& os, const char* data, size_t datalength, bool verbose/*=false*/, const TPacker& packer/*= TPacker()*/) {
+ TBufferStream buftmp;
+ size_t len = CompactTrieMinimize(buftmp, data, datalength, verbose, packer);
+ return CompactTrieMakeFastLayout(os, buftmp.Buffer().Data(), len, verbose, packer);
+}
+
+template <class TTrieBuilder>
+size_t CompactTrieMinimizeAndMakeFastLayout(IOutputStream& os, const TTrieBuilder& builder, bool verbose /*=false*/) {
+ TBufferStream buftmp;
+ size_t len = CompactTrieMinimize(buftmp, builder, verbose);
+ return CompactTrieMakeFastLayout<typename TTrieBuilder::TPacker>(os, buftmp.Buffer().Data(), len, verbose);
+}
+
diff --git a/library/cpp/containers/comptrie/comptrie_impl.cpp b/library/cpp/containers/comptrie/comptrie_impl.cpp
new file mode 100644
index 0000000000..a116ab6d1e
--- /dev/null
+++ b/library/cpp/containers/comptrie/comptrie_impl.cpp
@@ -0,0 +1,39 @@
+#include "comptrie_impl.h"
+
+#include <util/system/rusage.h>
+#include <util/stream/output.h>
+
+// Unpack the leaf value. The algorithm can store up to 8 full bytes in leafs.
+
+namespace NCompactTrie {
+ size_t MeasureOffset(size_t offset) {
+ int n = 0;
+
+ while (offset) {
+ offset >>= 8;
+ ++n;
+ }
+
+ return n;
+ }
+
+ size_t PackOffset(char* buffer, size_t offset) {
+ size_t len = MeasureOffset(offset);
+ size_t i = len;
+
+ while (i--) {
+ buffer[i] = (char)(offset & 0xFF);
+ offset >>= 8;
+ }
+
+ return len;
+ }
+
+ void ShowProgress(size_t n) {
+ if (n % 1000000 == 0)
+ Cerr << n << ", RSS=" << (TRusage::Get().MaxRss >> 20) << "mb" << Endl;
+ else if (n % 20000 == 0)
+ Cerr << ".";
+ }
+
+}
diff --git a/library/cpp/containers/comptrie/comptrie_impl.h b/library/cpp/containers/comptrie/comptrie_impl.h
new file mode 100644
index 0000000000..f41c38311a
--- /dev/null
+++ b/library/cpp/containers/comptrie/comptrie_impl.h
@@ -0,0 +1,221 @@
+#pragma once
+
+#include <util/stream/output.h>
+
+#ifndef COMPTRIE_DATA_CHECK
+#define COMPTRIE_DATA_CHECK 1
+#endif
+
+// NCompactTrie
+
+namespace NCompactTrie {
+ const char MT_FINAL = '\x80';
+ const char MT_NEXT = '\x40';
+ const char MT_SIZEMASK = '\x07';
+ const size_t MT_LEFTSHIFT = 3;
+ const size_t MT_RIGHTSHIFT = 0;
+
+ Y_FORCE_INLINE size_t UnpackOffset(const char* p, size_t len);
+ size_t MeasureOffset(size_t offset);
+ size_t PackOffset(char* buffer, size_t offset);
+ static inline ui64 ArcSaveOffset(size_t offset, IOutputStream& os);
+ Y_FORCE_INLINE char LeapByte(const char*& datapos, const char* dataend, char label);
+
+ template <class T>
+ inline static size_t ExtraBits() {
+ return (sizeof(T) - 1) * 8;
+ }
+
+ static inline bool IsEpsilonLink(const char flags) {
+ return !(flags & (MT_FINAL | MT_NEXT));
+ }
+
+ static inline void TraverseEpsilon(const char*& datapos) {
+ const char flags = *datapos;
+ if (!IsEpsilonLink(flags)) {
+ return;
+ }
+ const size_t offsetlength = flags & MT_SIZEMASK;
+ const size_t offset = UnpackOffset(datapos + 1, offsetlength);
+ Y_ASSERT(offset);
+ datapos += offset;
+ }
+
+ static inline size_t LeftOffsetLen(const char flags) {
+ return (flags >> MT_LEFTSHIFT) & MT_SIZEMASK;
+ }
+
+ static inline size_t RightOffsetLen(const char flags) {
+ return flags & MT_SIZEMASK;
+ }
+
+ void ShowProgress(size_t n); // just print dots
+}
+
+namespace NCompTriePrivate {
+ template <typename TChar>
+ struct TStringForChar {
+ };
+
+ template <>
+ struct TStringForChar<char> {
+ typedef TString TResult;
+ };
+
+ template <>
+ struct TStringForChar<wchar16> {
+ typedef TUtf16String TResult;
+ };
+
+ template <>
+ struct TStringForChar<wchar32> {
+ typedef TUtf32String TResult;
+ };
+
+}
+
+namespace NCompTriePrivate {
+ struct TCmp {
+ template <class T>
+ inline bool operator()(const T& l, const T& r) {
+ return (unsigned char)(l.Label[0]) < (unsigned char)(r.Label[0]);
+ }
+
+ template <class T>
+ inline bool operator()(const T& l, char r) {
+ return (unsigned char)(l.Label[0]) < (unsigned char)r;
+ }
+ };
+}
+
+namespace NCompactTrie {
+ static inline ui64 ArcSaveOffset(size_t offset, IOutputStream& os) {
+ using namespace NCompactTrie;
+
+ if (!offset)
+ return 0;
+
+ char buf[16];
+ size_t len = PackOffset(buf, offset);
+ os.Write(buf, len);
+ return len;
+ }
+
+ // Unpack the offset to the next node. The encoding scheme can store offsets
+ // up to 7 bytes; whether they fit into size_t is another issue.
+ Y_FORCE_INLINE size_t UnpackOffset(const char* p, size_t len) {
+ size_t result = 0;
+
+ while (len--)
+ result = ((result << 8) | (*(p++) & 0xFF));
+
+ return result;
+ }
+
+ // Auxiliary function: consumes one character from the input. Advances the data pointer
+ // to the position immediately preceding the value for the link just traversed (if any);
+ // returns flags associated with the link. If no arc with the required label is present,
+ // zeroes the data pointer.
+ Y_FORCE_INLINE char LeapByte(const char*& datapos, const char* dataend, char label) {
+ while (datapos < dataend) {
+ size_t offsetlength, offset;
+ const char* startpos = datapos;
+ char flags = *(datapos++);
+
+ if (IsEpsilonLink(flags)) {
+ // Epsilon link - jump to the specified offset without further checks.
+ // These links are created during minimization: original uncompressed
+ // tree does not need them. (If we find a way to package 3 offset lengths
+ // into 1 byte, we could get rid of them; but it looks like they do no harm.
+ Y_ASSERT(datapos < dataend);
+ offsetlength = flags & MT_SIZEMASK;
+ offset = UnpackOffset(datapos, offsetlength);
+ if (!offset)
+ break;
+ datapos = startpos + offset;
+
+ continue;
+ }
+
+ char ch = *(datapos++);
+
+ // Left branch
+ offsetlength = LeftOffsetLen(flags);
+ if ((unsigned char)label < (unsigned char)ch) {
+ offset = UnpackOffset(datapos, offsetlength);
+ if (!offset)
+ break;
+
+ datapos = startpos + offset;
+
+ continue;
+ }
+
+ datapos += offsetlength;
+
+ // Right branch
+ offsetlength = RightOffsetLen(flags);
+ if ((unsigned char)label > (unsigned char)ch) {
+ offset = UnpackOffset(datapos, offsetlength);
+
+ if (!offset)
+ break;
+
+ datapos = startpos + offset;
+
+ continue;
+ }
+
+ // Got a match; return position right before the contents for the label
+ datapos += offsetlength;
+ return flags;
+ }
+
+ // if we got here, we're past the dataend - bail out ASAP
+ datapos = nullptr;
+ return 0;
+ }
+
+ // Auxiliary function: consumes one (multibyte) symbol from the input.
+ // Advances the data pointer to the root of the subtrie beginning after the symbol,
+ // zeroes it if this subtrie is empty.
+ // If there is a value associated with the symbol, makes the value pointer point to it,
+ // otherwise sets it to nullptr.
+ // Returns true if the symbol was succesfully found in the trie, false otherwise.
+ template <typename TSymbol, class TPacker>
+ Y_FORCE_INLINE bool Advance(const char*& datapos, const char* const dataend, const char*& value,
+ TSymbol label, TPacker packer) {
+ Y_ASSERT(datapos < dataend);
+ char flags = MT_NEXT;
+ for (int i = (int)ExtraBits<TSymbol>(); i >= 0; i -= 8) {
+ flags = LeapByte(datapos, dataend, (char)(label >> i));
+ if (!datapos) {
+ return false; // no such arc
+ }
+
+ value = nullptr;
+
+ Y_ASSERT(datapos <= dataend);
+ if ((flags & MT_FINAL)) {
+ value = datapos;
+ datapos += packer.SkipLeaf(datapos);
+ }
+
+ if (!(flags & MT_NEXT)) {
+ if (i == 0) {
+ datapos = nullptr;
+ return true;
+ }
+ return false; // no further way
+ }
+
+ TraverseEpsilon(datapos);
+ if (i == 0) { // last byte, and got a match
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+}
diff --git a/library/cpp/containers/comptrie/comptrie_packer.h b/library/cpp/containers/comptrie/comptrie_packer.h
new file mode 100644
index 0000000000..0341eeeae3
--- /dev/null
+++ b/library/cpp/containers/comptrie/comptrie_packer.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <library/cpp/packers/packers.h>
+
+template <class T>
+class TCompactTriePacker {
+public:
+ void UnpackLeaf(const char* p, T& t) const {
+ NPackers::TPacker<T>().UnpackLeaf(p, t);
+ }
+ void PackLeaf(char* buffer, const T& data, size_t computedSize) const {
+ NPackers::TPacker<T>().PackLeaf(buffer, data, computedSize);
+ }
+ size_t MeasureLeaf(const T& data) const {
+ return NPackers::TPacker<T>().MeasureLeaf(data);
+ }
+ size_t SkipLeaf(const char* p) const // this function better be fast because it is very frequently used
+ {
+ return NPackers::TPacker<T>().SkipLeaf(p);
+ }
+};
diff --git a/library/cpp/containers/comptrie/comptrie_trie.h b/library/cpp/containers/comptrie/comptrie_trie.h
new file mode 100644
index 0000000000..40ec1e52b3
--- /dev/null
+++ b/library/cpp/containers/comptrie/comptrie_trie.h
@@ -0,0 +1,663 @@
+#pragma once
+
+#include "comptrie_impl.h"
+#include "comptrie_packer.h"
+#include "opaque_trie_iterator.h"
+#include "leaf_skipper.h"
+#include "key_selector.h"
+
+#include <util/generic/buffer.h>
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+#include <util/memory/blob.h>
+#include <util/stream/input.h>
+#include <utility>
+
+template <class T, class D, class S>
+class TCompactTrieBuilder;
+
+namespace NCompactTrie {
+ template <class TTrie>
+ class TFirstSymbolIterator;
+}
+
+template <class TTrie>
+class TSearchIterator;
+
+template <class TTrie>
+class TPrefixIterator;
+
+// in case of <char> specialization cannot distinguish between "" and "\0" keys
+template <class T = char, class D = ui64, class S = TCompactTriePacker<D>>
+class TCompactTrie {
+public:
+ typedef T TSymbol;
+ typedef D TData;
+ typedef S TPacker;
+
+ typedef typename TCompactTrieKeySelector<TSymbol>::TKey TKey;
+ typedef typename TCompactTrieKeySelector<TSymbol>::TKeyBuf TKeyBuf;
+
+ typedef std::pair<TKey, TData> TValueType;
+ typedef std::pair<size_t, TData> TPhraseMatch;
+ typedef TVector<TPhraseMatch> TPhraseMatchVector;
+
+ typedef TCompactTrieBuilder<T, D, S> TBuilder;
+
+protected:
+ TBlob DataHolder;
+ const char* EmptyValue = nullptr;
+ TPacker Packer;
+ NCompactTrie::TPackerLeafSkipper<TPacker> Skipper = &Packer; // This should be true for every constructor.
+
+public:
+ TCompactTrie() = default;
+
+ TCompactTrie(const char* d, size_t len, TPacker packer);
+ TCompactTrie(const char* d, size_t len)
+ : TCompactTrie{d, len, TPacker{}} {
+ }
+
+ TCompactTrie(const TBlob& data, TPacker packer);
+ explicit TCompactTrie(const TBlob& data)
+ : TCompactTrie{data, TPacker{}} {
+ }
+
+ // Skipper should be initialized with &Packer, not with &other.Packer, so you have to redefine these.
+ TCompactTrie(const TCompactTrie& other);
+ TCompactTrie(TCompactTrie&& other) noexcept;
+ TCompactTrie& operator=(const TCompactTrie& other);
+ TCompactTrie& operator=(TCompactTrie&& other) noexcept;
+
+ explicit operator bool() const {
+ return !IsEmpty();
+ }
+
+ void Init(const char* d, size_t len, TPacker packer = TPacker());
+ void Init(const TBlob& data, TPacker packer = TPacker());
+
+ bool IsInitialized() const;
+ bool IsEmpty() const;
+
+ bool Find(const TSymbol* key, size_t keylen, TData* value = nullptr) const;
+ bool Find(const TKeyBuf& key, TData* value = nullptr) const {
+ return Find(key.data(), key.size(), value);
+ }
+
+ TData Get(const TSymbol* key, size_t keylen) const {
+ TData value;
+ if (!Find(key, keylen, &value))
+ ythrow yexception() << "key " << TKey(key, keylen).Quote() << " not found in trie";
+ return value;
+ }
+ TData Get(const TKeyBuf& key) const {
+ return Get(key.data(), key.size());
+ }
+ TData GetDefault(const TKeyBuf& key, const TData& def) const {
+ TData value;
+ if (!Find(key.data(), key.size(), &value))
+ return def;
+ else
+ return value;
+ }
+
+ const TBlob& Data() const {
+ return DataHolder;
+ };
+
+ const NCompactTrie::ILeafSkipper& GetSkipper() const {
+ return Skipper;
+ }
+
+ TPacker GetPacker() const {
+ return Packer;
+ }
+
+ bool HasCorrectSkipper() const {
+ return Skipper.GetPacker() == &Packer;
+ }
+
+ void FindPhrases(const TSymbol* key, size_t keylen, TPhraseMatchVector& matches, TSymbol separator = TSymbol(' ')) const;
+ void FindPhrases(const TKeyBuf& key, TPhraseMatchVector& matches, TSymbol separator = TSymbol(' ')) const {
+ return FindPhrases(key.data(), key.size(), matches, separator);
+ }
+ bool FindLongestPrefix(const TSymbol* key, size_t keylen, size_t* prefixLen, TData* value = nullptr, bool* hasNext = nullptr) const;
+ bool FindLongestPrefix(const TKeyBuf& key, size_t* prefixLen, TData* value = nullptr, bool* hasNext = nullptr) const {
+ return FindLongestPrefix(key.data(), key.size(), prefixLen, value, hasNext);
+ }
+
+ // Return trie, containing all tails for the given key
+ inline TCompactTrie<T, D, S> FindTails(const TSymbol* key, size_t keylen) const;
+ TCompactTrie<T, D, S> FindTails(const TKeyBuf& key) const {
+ return FindTails(key.data(), key.size());
+ }
+ bool FindTails(const TSymbol* key, size_t keylen, TCompactTrie<T, D, S>& res) const;
+ bool FindTails(const TKeyBuf& key, TCompactTrie<T, D, S>& res) const {
+ return FindTails(key.data(), key.size(), res);
+ }
+
+ // same as FindTails(&key, 1), a bit faster
+ // return false, if no arc with @label exists
+ inline bool FindTails(TSymbol label, TCompactTrie<T, D, S>& res) const;
+
+ class TConstIterator {
+ private:
+ typedef NCompactTrie::TOpaqueTrieIterator TOpaqueTrieIterator;
+ typedef NCompactTrie::TOpaqueTrie TOpaqueTrie;
+ friend class TCompactTrie;
+ TConstIterator(const TOpaqueTrie& trie, const char* emptyValue, bool atend, TPacker packer); // only usable from Begin() and End() methods
+ TConstIterator(const TOpaqueTrie& trie, const char* emptyValue, const TKeyBuf& key, TPacker packer); // only usable from UpperBound() method
+
+ public:
+ TConstIterator() = default;
+ bool IsEmpty() const {
+ return !Impl;
+ } // Almost no other method can be called.
+
+ bool operator==(const TConstIterator& other) const;
+ bool operator!=(const TConstIterator& other) const;
+ TConstIterator& operator++();
+ TConstIterator operator++(int /*unused*/);
+ TConstIterator& operator--();
+ TConstIterator operator--(int /*unused*/);
+ TValueType operator*();
+
+ TKey GetKey() const;
+ size_t GetKeySize() const;
+ TData GetValue() const;
+ void GetValue(TData& data) const;
+ const char* GetValuePtr() const;
+
+ private:
+ TPacker Packer;
+ TCopyPtr<TOpaqueTrieIterator> Impl;
+ };
+
+ TConstIterator Begin() const;
+ TConstIterator begin() const;
+ TConstIterator End() const;
+ TConstIterator end() const;
+
+ // Returns an iterator pointing to the smallest key in the trie >= the argument.
+ // TODO: misleading name. Should be called LowerBound for consistency with stl.
+ // No. It is the STL that has a misleading name.
+ // LowerBound of X cannot be greater than X.
+ TConstIterator UpperBound(const TKeyBuf& key) const;
+
+ void Print(IOutputStream& os);
+
+ size_t Size() const;
+
+ friend class NCompactTrie::TFirstSymbolIterator<TCompactTrie>;
+ friend class TSearchIterator<TCompactTrie>;
+ friend class TPrefixIterator<TCompactTrie>;
+
+protected:
+ explicit TCompactTrie(const char* emptyValue);
+ TCompactTrie(const TBlob& data, const char* emptyValue, TPacker packer = TPacker());
+
+ bool LookupLongestPrefix(const TSymbol* key, size_t keylen, size_t& prefixLen, const char*& valuepos, bool& hasNext) const;
+ bool LookupLongestPrefix(const TSymbol* key, size_t keylen, size_t& prefixLen, const char*& valuepos) const {
+ bool hasNext;
+ return LookupLongestPrefix(key, keylen, prefixLen, valuepos, hasNext);
+ }
+ void LookupPhrases(const char* datapos, size_t len, const TSymbol* key, size_t keylen, TVector<TPhraseMatch>& matches, TSymbol separator) const;
+};
+
+template <class T = char, class D = ui64, class S = TCompactTriePacker<D>>
+class TCompactTrieHolder: public TCompactTrie<T, D, S>, NNonCopyable::TNonCopyable {
+private:
+ typedef TCompactTrie<T, D, S> TBase;
+ TArrayHolder<char> Storage;
+
+public:
+ TCompactTrieHolder(IInputStream& is, size_t len);
+};
+
+//------------------------//
+// Implementation section //
+//------------------------//
+
+// TCompactTrie
+
+template <class T, class D, class S>
+TCompactTrie<T, D, S>::TCompactTrie(const TBlob& data, TPacker packer)
+ : DataHolder(data)
+ , Packer(packer)
+{
+ Init(data, packer);
+}
+
+template <class T, class D, class S>
+TCompactTrie<T, D, S>::TCompactTrie(const char* d, size_t len, TPacker packer)
+ : Packer(packer)
+{
+ Init(d, len, packer);
+}
+
+template <class T, class D, class S>
+TCompactTrie<T, D, S>::TCompactTrie(const char* emptyValue)
+ : EmptyValue(emptyValue)
+{
+}
+
+template <class T, class D, class S>
+TCompactTrie<T, D, S>::TCompactTrie(const TBlob& data, const char* emptyValue, TPacker packer)
+ : DataHolder(data)
+ , EmptyValue(emptyValue)
+ , Packer(packer)
+{
+}
+
+template <class T, class D, class S>
+TCompactTrie<T, D, S>::TCompactTrie(const TCompactTrie& other)
+ : DataHolder(other.DataHolder)
+ , EmptyValue(other.EmptyValue)
+ , Packer(other.Packer)
+{
+}
+
+template <class T, class D, class S>
+TCompactTrie<T, D, S>::TCompactTrie(TCompactTrie&& other) noexcept
+ : DataHolder(std::move(other.DataHolder))
+ , EmptyValue(std::move(other.EmptyValue))
+ , Packer(std::move(other.Packer))
+{
+}
+
+template <class T, class D, class S>
+TCompactTrie<T, D, S>& TCompactTrie<T, D, S>::operator=(const TCompactTrie& other) {
+ if (this != &other) {
+ DataHolder = other.DataHolder;
+ EmptyValue = other.EmptyValue;
+ Packer = other.Packer;
+ }
+ return *this;
+}
+
+template <class T, class D, class S>
+TCompactTrie<T, D, S>& TCompactTrie<T, D, S>::operator=(TCompactTrie&& other) noexcept {
+ if (this != &other) {
+ DataHolder = std::move(other.DataHolder);
+ EmptyValue = std::move(other.EmptyValue);
+ Packer = std::move(other.Packer);
+ }
+ return *this;
+}
+
+template <class T, class D, class S>
+void TCompactTrie<T, D, S>::Init(const char* d, size_t len, TPacker packer) {
+ Init(TBlob::NoCopy(d, len), packer);
+}
+
+template <class T, class D, class S>
+void TCompactTrie<T, D, S>::Init(const TBlob& data, TPacker packer) {
+ using namespace NCompactTrie;
+
+ DataHolder = data;
+ Packer = packer;
+
+ const char* datapos = DataHolder.AsCharPtr();
+ size_t len = DataHolder.Length();
+ if (!len)
+ return;
+
+ const char* const dataend = datapos + len;
+
+ const char* emptypos = datapos;
+ char flags = LeapByte(emptypos, dataend, 0);
+ if (emptypos && (flags & MT_FINAL)) {
+ Y_ASSERT(emptypos <= dataend);
+ EmptyValue = emptypos;
+ }
+}
+
+template <class T, class D, class S>
+bool TCompactTrie<T, D, S>::IsInitialized() const {
+ return DataHolder.Data() != nullptr;
+}
+
+template <class T, class D, class S>
+bool TCompactTrie<T, D, S>::IsEmpty() const {
+ return DataHolder.Size() == 0 && EmptyValue == nullptr;
+}
+
+template <class T, class D, class S>
+bool TCompactTrie<T, D, S>::Find(const TSymbol* key, size_t keylen, TData* value) const {
+ size_t prefixLen = 0;
+ const char* valuepos = nullptr;
+ bool hasNext;
+ if (!LookupLongestPrefix(key, keylen, prefixLen, valuepos, hasNext) || prefixLen != keylen)
+ return false;
+ if (value)
+ Packer.UnpackLeaf(valuepos, *value);
+ return true;
+}
+
+template <class T, class D, class S>
+void TCompactTrie<T, D, S>::FindPhrases(const TSymbol* key, size_t keylen, TPhraseMatchVector& matches, TSymbol separator) const {
+ LookupPhrases(DataHolder.AsCharPtr(), DataHolder.Length(), key, keylen, matches, separator);
+}
+
+template <class T, class D, class S>
+inline TCompactTrie<T, D, S> TCompactTrie<T, D, S>::FindTails(const TSymbol* key, size_t keylen) const {
+ TCompactTrie<T, D, S> ret;
+ FindTails(key, keylen, ret);
+ return ret;
+}
+
+template <class T, class D, class S>
+bool TCompactTrie<T, D, S>::FindTails(const TSymbol* key, size_t keylen, TCompactTrie<T, D, S>& res) const {
+ using namespace NCompactTrie;
+
+ size_t len = DataHolder.Length();
+
+ if (!key || !len)
+ return false;
+
+ if (!keylen) {
+ res = *this;
+ return true;
+ }
+
+ const char* datastart = DataHolder.AsCharPtr();
+ const char* datapos = datastart;
+ const char* const dataend = datapos + len;
+
+ const TSymbol* keyend = key + keylen;
+ const char* value = nullptr;
+
+ while (key != keyend) {
+ T label = *(key++);
+ if (!NCompactTrie::Advance(datapos, dataend, value, label, Packer))
+ return false;
+
+ if (key == keyend) {
+ if (datapos) {
+ Y_ASSERT(datapos >= datastart);
+ res = TCompactTrie<T, D, S>(TBlob::NoCopy(datapos, dataend - datapos), value);
+ } else {
+ res = TCompactTrie<T, D, S>(value);
+ }
+ return true;
+ } else if (!datapos) {
+ return false; // No further way
+ }
+ }
+
+ return false;
+}
+
+template <class T, class D, class S>
+inline bool TCompactTrie<T, D, S>::FindTails(TSymbol label, TCompactTrie<T, D, S>& res) const {
+ using namespace NCompactTrie;
+
+ const size_t len = DataHolder.Length();
+ if (!len)
+ return false;
+
+ const char* datastart = DataHolder.AsCharPtr();
+ const char* dataend = datastart + len;
+ const char* datapos = datastart;
+ const char* value = nullptr;
+
+ if (!NCompactTrie::Advance(datapos, dataend, value, label, Packer))
+ return false;
+
+ if (datapos) {
+ Y_ASSERT(datapos >= datastart);
+ res = TCompactTrie<T, D, S>(TBlob::NoCopy(datapos, dataend - datapos), value);
+ } else {
+ res = TCompactTrie<T, D, S>(value);
+ }
+
+ return true;
+}
+
+template <class T, class D, class S>
+typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::Begin() const {
+ NCompactTrie::TOpaqueTrie self(DataHolder.AsCharPtr(), DataHolder.Length(), Skipper);
+ return TConstIterator(self, EmptyValue, false, Packer);
+}
+
+template <class T, class D, class S>
+typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::begin() const {
+ return Begin();
+}
+
+template <class T, class D, class S>
+typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::End() const {
+ NCompactTrie::TOpaqueTrie self(DataHolder.AsCharPtr(), DataHolder.Length(), Skipper);
+ return TConstIterator(self, EmptyValue, true, Packer);
+}
+
+template <class T, class D, class S>
+typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::end() const {
+ return End();
+}
+
+template <class T, class D, class S>
+size_t TCompactTrie<T, D, S>::Size() const {
+ size_t res = 0;
+ for (TConstIterator it = Begin(); it != End(); ++it)
+ ++res;
+ return res;
+}
+
+template <class T, class D, class S>
+typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::UpperBound(const TKeyBuf& key) const {
+ NCompactTrie::TOpaqueTrie self(DataHolder.AsCharPtr(), DataHolder.Length(), Skipper);
+ return TConstIterator(self, EmptyValue, key, Packer);
+}
+
+template <class T, class D, class S>
+void TCompactTrie<T, D, S>::Print(IOutputStream& os) {
+ typedef typename ::TCompactTrieKeySelector<T>::TKeyBuf TSBuffer;
+ for (TConstIterator it = Begin(); it != End(); ++it) {
+ os << TSBuffer((*it).first.data(), (*it).first.size()) << "\t" << (*it).second << Endl;
+ }
+}
+
+template <class T, class D, class S>
+bool TCompactTrie<T, D, S>::FindLongestPrefix(const TSymbol* key, size_t keylen, size_t* prefixLen, TData* value, bool* hasNext) const {
+ const char* valuepos = nullptr;
+ size_t tempPrefixLen = 0;
+ bool tempHasNext;
+ bool found = LookupLongestPrefix(key, keylen, tempPrefixLen, valuepos, tempHasNext);
+ if (prefixLen)
+ *prefixLen = tempPrefixLen;
+ if (found && value)
+ Packer.UnpackLeaf(valuepos, *value);
+ if (hasNext)
+ *hasNext = tempHasNext;
+ return found;
+}
+
+template <class T, class D, class S>
+bool TCompactTrie<T, D, S>::LookupLongestPrefix(const TSymbol* key, size_t keylen, size_t& prefixLen, const char*& valuepos, bool& hasNext) const {
+ using namespace NCompactTrie;
+
+ const char* datapos = DataHolder.AsCharPtr();
+ size_t len = DataHolder.Length();
+
+ prefixLen = 0;
+ hasNext = false;
+ bool found = false;
+
+ if (EmptyValue) {
+ valuepos = EmptyValue;
+ found = true;
+ }
+
+ if (!key || !len)
+ return found;
+
+ const char* const dataend = datapos + len;
+
+ const T* keyend = key + keylen;
+ while (key != keyend) {
+ T label = *(key++);
+ for (i64 i = (i64)ExtraBits<TSymbol>(); i >= 0; i -= 8) {
+ const char flags = LeapByte(datapos, dataend, (char)(label >> i));
+ if (!datapos) {
+ return found; // no such arc
+ }
+
+ Y_ASSERT(datapos <= dataend);
+ if ((flags & MT_FINAL)) {
+ prefixLen = keylen - (keyend - key) - (i ? 1 : 0);
+ valuepos = datapos;
+ hasNext = flags & MT_NEXT;
+ found = true;
+
+ if (!i && key == keyend) { // last byte, and got a match
+ return found;
+ }
+ datapos += Packer.SkipLeaf(datapos); // skip intermediate leaf nodes
+ }
+
+ if (!(flags & MT_NEXT)) {
+ return found; // no further way
+ }
+ }
+ }
+
+ return found;
+}
+
+template <class T, class D, class S>
+void TCompactTrie<T, D, S>::LookupPhrases(
+ const char* datapos, size_t len, const TSymbol* key, size_t keylen,
+ TVector<TPhraseMatch>& matches, TSymbol separator) const {
+ using namespace NCompactTrie;
+
+ matches.clear();
+
+ if (!key || !len)
+ return;
+
+ const T* const keystart = key;
+ const T* const keyend = key + keylen;
+ const char* const dataend = datapos + len;
+ while (datapos && key != keyend) {
+ T label = *(key++);
+ const char* value = nullptr;
+ if (!Advance(datapos, dataend, value, label, Packer)) {
+ return;
+ }
+ if (value && (key == keyend || *key == separator)) {
+ size_t matchlength = (size_t)(key - keystart);
+ D data;
+ Packer.UnpackLeaf(value, data);
+ matches.push_back(TPhraseMatch(matchlength, data));
+ }
+ }
+}
+
+// TCompactTrieHolder
+
+template <class T, class D, class S>
+TCompactTrieHolder<T, D, S>::TCompactTrieHolder(IInputStream& is, size_t len)
+ : Storage(new char[len])
+{
+ if (is.Load(Storage.Get(), len) != len) {
+ ythrow yexception() << "bad data load";
+ }
+ TBase::Init(Storage.Get(), len);
+}
+
+//----------------------------------------------------------------------------------------------------------------
+// TCompactTrie::TConstIterator
+
+template <class T, class D, class S>
+TCompactTrie<T, D, S>::TConstIterator::TConstIterator(const TOpaqueTrie& trie, const char* emptyValue, bool atend, TPacker packer)
+ : Packer(packer)
+ , Impl(new TOpaqueTrieIterator(trie, emptyValue, atend))
+{
+}
+
+template <class T, class D, class S>
+TCompactTrie<T, D, S>::TConstIterator::TConstIterator(const TOpaqueTrie& trie, const char* emptyValue, const TKeyBuf& key, TPacker packer)
+ : Packer(packer)
+ , Impl(new TOpaqueTrieIterator(trie, emptyValue, true))
+{
+ Impl->UpperBound<TSymbol>(key);
+}
+
+template <class T, class D, class S>
+bool TCompactTrie<T, D, S>::TConstIterator::operator==(const TConstIterator& other) const {
+ if (!Impl)
+ return !other.Impl;
+ if (!other.Impl)
+ return false;
+ return *Impl == *other.Impl;
+}
+
+template <class T, class D, class S>
+bool TCompactTrie<T, D, S>::TConstIterator::operator!=(const TConstIterator& other) const {
+ return !operator==(other);
+}
+
+template <class T, class D, class S>
+typename TCompactTrie<T, D, S>::TConstIterator& TCompactTrie<T, D, S>::TConstIterator::operator++() {
+ Impl->Forward();
+ return *this;
+}
+
+template <class T, class D, class S>
+typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::TConstIterator::operator++(int /*unused*/) {
+ TConstIterator copy(*this);
+ Impl->Forward();
+ return copy;
+}
+
+template <class T, class D, class S>
+typename TCompactTrie<T, D, S>::TConstIterator& TCompactTrie<T, D, S>::TConstIterator::operator--() {
+ Impl->Backward();
+ return *this;
+}
+
+template <class T, class D, class S>
+typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::TConstIterator::operator--(int /*unused*/) {
+ TConstIterator copy(*this);
+ Impl->Backward();
+ return copy;
+}
+
+template <class T, class D, class S>
+typename TCompactTrie<T, D, S>::TValueType TCompactTrie<T, D, S>::TConstIterator::operator*() {
+ return TValueType(GetKey(), GetValue());
+}
+
+template <class T, class D, class S>
+typename TCompactTrie<T, D, S>::TKey TCompactTrie<T, D, S>::TConstIterator::GetKey() const {
+ return Impl->GetKey<TSymbol>();
+}
+
+template <class T, class D, class S>
+size_t TCompactTrie<T, D, S>::TConstIterator::GetKeySize() const {
+ return Impl->MeasureKey<TSymbol>();
+}
+
+template <class T, class D, class S>
+const char* TCompactTrie<T, D, S>::TConstIterator::GetValuePtr() const {
+ return Impl->GetValuePtr();
+}
+
+template <class T, class D, class S>
+typename TCompactTrie<T, D, S>::TData TCompactTrie<T, D, S>::TConstIterator::GetValue() const {
+ D data;
+ GetValue(data);
+ return data;
+}
+
+template <class T, class D, class S>
+void TCompactTrie<T, D, S>::TConstIterator::GetValue(typename TCompactTrie<T, D, S>::TData& data) const {
+ const char* ptr = GetValuePtr();
+ if (ptr) {
+ Packer.UnpackLeaf(ptr, data);
+ } else {
+ data = typename TCompactTrie<T, D, S>::TData();
+ }
+}
diff --git a/library/cpp/containers/comptrie/comptrie_ut.cpp b/library/cpp/containers/comptrie/comptrie_ut.cpp
new file mode 100644
index 0000000000..74bee09b5d
--- /dev/null
+++ b/library/cpp/containers/comptrie/comptrie_ut.cpp
@@ -0,0 +1,1791 @@
+#include <util/random/shuffle.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/output.h>
+#include <utility>
+
+#include <util/charset/wide.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/buffer.h>
+#include <util/generic/map.h>
+#include <util/generic/vector.h>
+#include <util/generic/ptr.h>
+#include <util/generic/ylimits.h>
+
+#include <util/folder/dirut.h>
+
+#include <util/random/random.h>
+#include <util/random/fast.h>
+
+#include <util/string/hex.h>
+#include <util/string/cast.h>
+
+#include "comptrie.h"
+#include "set.h"
+#include "first_symbol_iterator.h"
+#include "search_iterator.h"
+#include "pattern_searcher.h"
+
+#include <array>
+#include <iterator>
+
+
+class TCompactTrieTest: public TTestBase {
+private:
+ UNIT_TEST_SUITE(TCompactTrieTest);
+ UNIT_TEST(TestTrie8);
+ UNIT_TEST(TestTrie16);
+ UNIT_TEST(TestTrie32);
+
+ UNIT_TEST(TestFastTrie8);
+ UNIT_TEST(TestFastTrie16);
+ UNIT_TEST(TestFastTrie32);
+
+ UNIT_TEST(TestMinimizedTrie8);
+ UNIT_TEST(TestMinimizedTrie16);
+ UNIT_TEST(TestMinimizedTrie32);
+
+ UNIT_TEST(TestFastMinimizedTrie8);
+ UNIT_TEST(TestFastMinimizedTrie16);
+ UNIT_TEST(TestFastMinimizedTrie32);
+
+ UNIT_TEST(TestTrieIterator8);
+ UNIT_TEST(TestTrieIterator16);
+ UNIT_TEST(TestTrieIterator32);
+
+ UNIT_TEST(TestMinimizedTrieIterator8);
+ UNIT_TEST(TestMinimizedTrieIterator16);
+ UNIT_TEST(TestMinimizedTrieIterator32);
+
+ UNIT_TEST(TestPhraseSearch);
+ UNIT_TEST(TestAddGet);
+ UNIT_TEST(TestEmpty);
+ UNIT_TEST(TestUninitializedNonEmpty);
+ UNIT_TEST(TestRandom);
+ UNIT_TEST(TestFindTails);
+ UNIT_TEST(TestPrefixGrouped);
+ UNIT_TEST(CrashTestPrefixGrouped);
+ UNIT_TEST(TestMergeFromFile);
+ UNIT_TEST(TestMergeFromBuffer);
+ UNIT_TEST(TestUnique);
+ UNIT_TEST(TestAddRetValue);
+ UNIT_TEST(TestClear);
+
+ UNIT_TEST(TestIterateEmptyKey);
+
+ UNIT_TEST(TestTrieSet);
+
+ UNIT_TEST(TestTrieForVectorInt64);
+ UNIT_TEST(TestTrieForListInt64);
+ UNIT_TEST(TestTrieForSetInt64);
+
+ UNIT_TEST(TestTrieForVectorStroka);
+ UNIT_TEST(TestTrieForListStroka);
+ UNIT_TEST(TestTrieForSetStroka);
+
+ UNIT_TEST(TestTrieForVectorWtroka);
+ UNIT_TEST(TestTrieForVectorFloat);
+ UNIT_TEST(TestTrieForVectorDouble);
+
+ UNIT_TEST(TestTrieForListVectorInt64);
+ UNIT_TEST(TestTrieForPairWtrokaVectorInt64);
+
+ UNIT_TEST(TestEmptyValueOutOfOrder);
+ UNIT_TEST(TestFindLongestPrefixWithEmptyValue);
+
+ UNIT_TEST(TestSearchIterChar);
+ UNIT_TEST(TestSearchIterWchar);
+ UNIT_TEST(TestSearchIterWchar32)
+
+ UNIT_TEST(TestCopyAndAssignment);
+
+ UNIT_TEST(TestFirstSymbolIterator8);
+ UNIT_TEST(TestFirstSymbolIterator16);
+ UNIT_TEST(TestFirstSymbolIterator32);
+ UNIT_TEST(TestFirstSymbolIteratorChar32);
+
+ UNIT_TEST(TestArrayPacker);
+
+ UNIT_TEST(TestBuilderFindLongestPrefix);
+ UNIT_TEST(TestBuilderFindLongestPrefixWithEmptyValue);
+
+ UNIT_TEST(TestPatternSearcherEmpty);
+ UNIT_TEST(TestPatternSearcherSimple);
+ UNIT_TEST(TestPatternSearcherRandom);
+
+ UNIT_TEST_SUITE_END();
+
+ static const char* SampleData[];
+
+ template <class T>
+ void CreateTrie(IOutputStream& out, bool minimize, bool useFastLayout);
+
+ template <class T>
+ void CheckData(const char* src, size_t len);
+
+ template <class T>
+ void CheckUpperBound(const char* src, size_t len);
+
+ template <class T>
+ void CheckIterator(const char* src, size_t len);
+
+ template <class T>
+ void TestTrie(bool minimize, bool useFastLayout);
+
+ template <class T>
+ void TestTrieIterator(bool minimize);
+
+ template <class T, bool minimize>
+ void TestRandom(const size_t n, const size_t maxKeySize);
+
+ void TestFindTailsImpl(const TString& prefix);
+
+ void TestUniqueImpl(bool isPrefixGrouped);
+
+ TVector<TUtf16String> GetSampleKeys(size_t nKeys) const;
+ template <class TContainer>
+ TVector<TContainer> GetSampleVectorData(size_t nValues);
+ template <class TContainer>
+ TVector<TContainer> GetSampleTextVectorData(size_t nValues);
+ template <class T>
+ void CheckEquality(const T& value1, const T& value2) const;
+ template <class TContainer>
+ void TestTrieWithContainers(const TVector<TUtf16String>& keys, const TVector<TContainer>& sampleData, TString methodName);
+
+ template <typename TChar>
+ void TestSearchIterImpl();
+
+ template <class TTrie>
+ void TestFirstSymbolIteratorForTrie(const TTrie& trie, const TStringBuf& narrowAnswers);
+
+ template <typename TSymbol>
+ void TestFirstSymbolIterator();
+
+ template <class T>
+ class TIntPacker;
+ template <class T>
+ class TDummyPacker;
+ class TStrokaPacker;
+
+public:
+ void TestPackers();
+
+ void TestTrie8();
+ void TestTrie16();
+ void TestTrie32();
+
+ void TestFastTrie8();
+ void TestFastTrie16();
+ void TestFastTrie32();
+
+ void TestMinimizedTrie8();
+ void TestMinimizedTrie16();
+ void TestMinimizedTrie32();
+
+ void TestFastMinimizedTrie8();
+ void TestFastMinimizedTrie16();
+ void TestFastMinimizedTrie32();
+
+ void TestTrieIterator8();
+ void TestTrieIterator16();
+ void TestTrieIterator32();
+
+ void TestMinimizedTrieIterator8();
+ void TestMinimizedTrieIterator16();
+ void TestMinimizedTrieIterator32();
+
+ void TestPhraseSearch();
+ void TestAddGet();
+ void TestEmpty();
+ void TestUninitializedNonEmpty();
+ void TestRandom();
+ void TestFindTails();
+ void TestPrefixGrouped();
+ void CrashTestPrefixGrouped();
+ void TestMergeFromFile();
+ void TestMergeFromBuffer();
+ void TestUnique();
+ void TestAddRetValue();
+ void TestClear();
+
+ void TestIterateEmptyKey();
+
+ void TestTrieSet();
+
+ void TestTrieForVectorInt64();
+ void TestTrieForListInt64();
+ void TestTrieForSetInt64();
+
+ void TestTrieForVectorStroka();
+ void TestTrieForListStroka();
+ void TestTrieForSetStroka();
+
+ void TestTrieForVectorWtroka();
+ void TestTrieForVectorFloat();
+ void TestTrieForVectorDouble();
+
+ void TestTrieForListVectorInt64();
+ void TestTrieForPairWtrokaVectorInt64();
+
+ void TestEmptyValueOutOfOrder();
+ void TestFindLongestPrefixWithEmptyValue();
+
+ void TestSearchIterChar();
+ void TestSearchIterWchar();
+ void TestSearchIterWchar32();
+
+ void TestCopyAndAssignment();
+
+ void TestFirstSymbolIterator8();
+ void TestFirstSymbolIterator16();
+ void TestFirstSymbolIterator32();
+ void TestFirstSymbolIteratorChar32();
+
+ void TestArrayPacker();
+
+ void TestBuilderFindLongestPrefix();
+ void TestBuilderFindLongestPrefix(size_t keysCount, double branchProbability, bool isPrefixGrouped, bool hasEmptyKey);
+ void TestBuilderFindLongestPrefixWithEmptyValue();
+
+ void TestPatternSearcherOnDataset(
+ const TVector<TString>& patterns,
+ const TVector<TString>& samples
+ );
+ void TestPatternSearcherEmpty();
+ void TestPatternSearcherSimple();
+ void TestPatternSearcherRandom(
+ size_t patternsNum,
+ size_t patternMaxLength,
+ size_t strMaxLength,
+ int maxChar,
+ TFastRng<ui64>& rng
+ );
+ void TestPatternSearcherRandom();
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TCompactTrieTest);
+
+const char* TCompactTrieTest::SampleData[] = {
+ "",
+ "a", "b", "c", "d",
+ "aa", "ab", "ac", "ad",
+ "aaa", "aab", "aac", "aad",
+ "aba", "abb", "abc", "abd",
+ "fba", "fbb", "fbc", "fbd",
+ "fbbaa",
+ "c\x85\xA4\xBF" // Just something outside ASCII.
+};
+
+template <class T>
+typename TCompactTrie<T>::TKey MakeWideKey(const char* str, size_t len) {
+ typename TCompactTrie<T>::TKey buffer;
+ for (size_t i = 0; i < len; i++) {
+ unsigned int ch = (str[i] & 0xFF);
+ buffer.push_back((T)(ch | ch << 8 | ch << 16 | ch << 24));
+ }
+ return buffer;
+}
+
+template <class T>
+typename TCompactTrie<T>::TKey MakeWideKey(const TString& str) {
+ return MakeWideKey<T>(str.c_str(), str.length());
+}
+
+template <class T>
+typename TCompactTrie<T>::TKey MakeWideKey(const TStringBuf& buf) {
+ return MakeWideKey<T>(buf.data(), buf.length());
+}
+
+template <class T>
+void TCompactTrieTest::CreateTrie(IOutputStream& out, bool minimize, bool useFastLayout) {
+ TCompactTrieBuilder<T> builder;
+
+ for (auto& i : SampleData) {
+ size_t len = strlen(i);
+
+ builder.Add(MakeWideKey<T>(i, len), len * 2);
+ }
+
+ TBufferOutput tmp2;
+ IOutputStream& currentOutput = useFastLayout ? tmp2 : out;
+ if (minimize) {
+ TBufferOutput buftmp;
+ builder.Save(buftmp);
+ CompactTrieMinimize<TCompactTriePacker<ui64>>(currentOutput, buftmp.Buffer().Data(), buftmp.Buffer().Size(), false);
+ } else {
+ builder.Save(currentOutput);
+ }
+ if (useFastLayout) {
+ CompactTrieMakeFastLayout<TCompactTriePacker<T>>(out, tmp2.Buffer().Data(), tmp2.Buffer().Size(), false);
+ }
+}
+
+// Iterates over all strings of length <= 4 made of letters a-g.
+static bool LexicographicStep(TString& s) {
+ if (s.length() < 4) {
+ s += "a";
+ return true;
+ }
+ while (!s.empty() && s.back() == 'g')
+ s.pop_back();
+ if (s.empty())
+ return false;
+ char last = s.back();
+ last++;
+ s.pop_back();
+ s.push_back(last);
+ return true;
+}
+
+template <class T>
+void TCompactTrieTest::CheckUpperBound(const char* data, size_t datalen) {
+ TCompactTrie<T> trie(data, datalen);
+ typedef typename TCompactTrie<T>::TKey TKey;
+ typedef typename TCompactTrie<T>::TData TData;
+
+ TString key;
+ do {
+ const TKey wideKey = MakeWideKey<T>(key);
+ typename TCompactTrie<T>::TConstIterator it = trie.UpperBound(wideKey);
+ UNIT_ASSERT_C(it == trie.End() || it.GetKey() >= wideKey, "key=" + key);
+ TData data;
+ const bool found = trie.Find(wideKey, &data);
+ if (found)
+ UNIT_ASSERT_C(it.GetKey() == wideKey && it.GetValue() == data, "key=" + key);
+ if (it != trie.Begin())
+ UNIT_ASSERT_C((--it).GetKey() < wideKey, "key=" + key);
+ } while (LexicographicStep(key));
+}
+
+template <class T>
+void TCompactTrieTest::CheckData(const char* data, size_t datalen) {
+ TCompactTrie<T> trie(data, datalen);
+
+ UNIT_ASSERT_VALUES_EQUAL(Y_ARRAY_SIZE(SampleData), trie.Size());
+
+ for (auto& i : SampleData) {
+ size_t len = strlen(i);
+ ui64 value = 0;
+ size_t prefixLen = 0;
+
+ typename TCompactTrie<T>::TKey key = MakeWideKey<T>(i, len);
+ UNIT_ASSERT(trie.Find(key, &value));
+ UNIT_ASSERT_EQUAL(len * 2, value);
+ UNIT_ASSERT(trie.FindLongestPrefix(key, &prefixLen, &value));
+ UNIT_ASSERT_EQUAL(len, prefixLen);
+ UNIT_ASSERT_EQUAL(len * 2, value);
+
+ TString badkey("bb");
+ badkey += i;
+ key = MakeWideKey<T>(badkey);
+ UNIT_ASSERT(!trie.Find(key));
+ value = 123;
+ UNIT_ASSERT(!trie.Find(key, &value));
+ UNIT_ASSERT_EQUAL(123, value);
+ UNIT_ASSERT(trie.FindLongestPrefix(key, &prefixLen, &value));
+ UNIT_ASSERT_EQUAL(1, prefixLen);
+ UNIT_ASSERT_EQUAL(2, value);
+
+ badkey = i;
+ badkey += "x";
+ key = MakeWideKey<T>(badkey);
+ UNIT_ASSERT(!trie.Find(key));
+ value = 1234;
+ UNIT_ASSERT(!trie.Find(key, &value));
+ UNIT_ASSERT_EQUAL(1234, value);
+ UNIT_ASSERT(trie.FindLongestPrefix(key, &prefixLen, &value));
+ UNIT_ASSERT_EQUAL(len, prefixLen);
+ UNIT_ASSERT_EQUAL(len * 2, value);
+ UNIT_ASSERT(trie.FindLongestPrefix(key, &prefixLen, nullptr));
+ UNIT_ASSERT_EQUAL(len, prefixLen);
+ }
+
+ TString testkey("fbbaa");
+ typename TCompactTrie<T>::TKey key = MakeWideKey<T>(testkey);
+ ui64 value = 0;
+ size_t prefixLen = 0;
+ UNIT_ASSERT(trie.FindLongestPrefix(key.data(), testkey.length() - 1, &prefixLen, &value));
+ UNIT_ASSERT_EQUAL(prefixLen, 3);
+ UNIT_ASSERT_EQUAL(6, value);
+
+ testkey = "fbbax";
+ key = MakeWideKey<T>(testkey);
+ UNIT_ASSERT(trie.FindLongestPrefix(key, &prefixLen, &value));
+ UNIT_ASSERT_EQUAL(prefixLen, 3);
+ UNIT_ASSERT_EQUAL(6, value);
+
+ value = 12345678;
+ UNIT_ASSERT(!trie.Find(key, &value));
+ UNIT_ASSERT_EQUAL(12345678, value); //Failed Find() should not change value
+}
+
+template <class T>
+void TCompactTrieTest::CheckIterator(const char* data, size_t datalen) {
+ typedef typename TCompactTrie<T>::TKey TKey;
+ typedef typename TCompactTrie<T>::TValueType TValue;
+ TMap<TKey, ui64> stored;
+
+ for (auto& i : SampleData) {
+ size_t len = strlen(i);
+
+ stored[MakeWideKey<T>(i, len)] = len * 2;
+ }
+
+ TCompactTrie<T> trie(data, datalen);
+ TVector<TValue> items;
+ typename TCompactTrie<T>::TConstIterator it = trie.Begin();
+ size_t entry_count = 0;
+ TMap<TKey, ui64> received;
+ while (it != trie.End()) {
+ UNIT_ASSERT_VALUES_EQUAL(it.GetKeySize(), it.GetKey().size());
+ received.insert(*it);
+ items.push_back(*it);
+ entry_count++;
+ it++;
+ }
+ TMap<TKey, ui64> received2;
+ for (std::pair<TKey, ui64> x : trie) {
+ received2.insert(x);
+ }
+ UNIT_ASSERT(entry_count == stored.size());
+ UNIT_ASSERT(received == stored);
+ UNIT_ASSERT(received2 == stored);
+
+ std::reverse(items.begin(), items.end());
+ typename TCompactTrie<T>::TConstIterator revIt = trie.End();
+ typename TCompactTrie<T>::TConstIterator const begin = trie.Begin();
+ typename TCompactTrie<T>::TConstIterator emptyIt;
+ size_t pos = 0;
+ while (revIt != begin) {
+ revIt--;
+ UNIT_ASSERT(*revIt == items[pos]);
+ pos++;
+ }
+ // Checking the assignment operator.
+ revIt = begin;
+ UNIT_ASSERT(revIt == trie.Begin());
+ UNIT_ASSERT(!revIt.IsEmpty());
+ UNIT_ASSERT(revIt != emptyIt);
+ UNIT_ASSERT(revIt != trie.End());
+ ++revIt; // Call a method that uses Skipper.
+ revIt = emptyIt;
+ UNIT_ASSERT(revIt == emptyIt);
+ UNIT_ASSERT(revIt.IsEmpty());
+ UNIT_ASSERT(revIt != trie.End());
+ // Checking the move assignment operator.
+ revIt = trie.Begin();
+ UNIT_ASSERT(revIt == trie.Begin());
+ UNIT_ASSERT(!revIt.IsEmpty());
+ UNIT_ASSERT(revIt != emptyIt);
+ UNIT_ASSERT(revIt != trie.End());
+ ++revIt; // Call a method that uses Skipper.
+ revIt = typename TCompactTrie<T>::TConstIterator();
+ UNIT_ASSERT(revIt == emptyIt);
+ UNIT_ASSERT(revIt.IsEmpty());
+ UNIT_ASSERT(revIt != trie.End());
+}
+
+template <class T>
+void TCompactTrieTest::TestTrie(bool minimize, bool useFastLayout) {
+ TBufferOutput bufout;
+ CreateTrie<T>(bufout, minimize, useFastLayout);
+ CheckData<T>(bufout.Buffer().Data(), bufout.Buffer().Size());
+ CheckUpperBound<T>(bufout.Buffer().Data(), bufout.Buffer().Size());
+}
+
+template <class T>
+void TCompactTrieTest::TestTrieIterator(bool minimize) {
+ TBufferOutput bufout;
+ CreateTrie<T>(bufout, minimize, false);
+ CheckIterator<T>(bufout.Buffer().Data(), bufout.Buffer().Size());
+}
+
+void TCompactTrieTest::TestTrie8() {
+ TestTrie<char>(false, false);
+}
+void TCompactTrieTest::TestTrie16() {
+ TestTrie<wchar16>(false, false);
+}
+void TCompactTrieTest::TestTrie32() {
+ TestTrie<wchar32>(false, false);
+}
+
+void TCompactTrieTest::TestFastTrie8() {
+ TestTrie<char>(false, true);
+}
+void TCompactTrieTest::TestFastTrie16() {
+ TestTrie<wchar16>(false, true);
+}
+void TCompactTrieTest::TestFastTrie32() {
+ TestTrie<wchar32>(false, true);
+}
+
+void TCompactTrieTest::TestMinimizedTrie8() {
+ TestTrie<char>(true, false);
+}
+void TCompactTrieTest::TestMinimizedTrie16() {
+ TestTrie<wchar16>(true, false);
+}
+void TCompactTrieTest::TestMinimizedTrie32() {
+ TestTrie<wchar32>(true, false);
+}
+
+void TCompactTrieTest::TestFastMinimizedTrie8() {
+ TestTrie<char>(true, true);
+}
+void TCompactTrieTest::TestFastMinimizedTrie16() {
+ TestTrie<wchar16>(true, true);
+}
+void TCompactTrieTest::TestFastMinimizedTrie32() {
+ TestTrie<wchar32>(true, true);
+}
+
+void TCompactTrieTest::TestTrieIterator8() {
+ TestTrieIterator<char>(false);
+}
+void TCompactTrieTest::TestTrieIterator16() {
+ TestTrieIterator<wchar16>(false);
+}
+void TCompactTrieTest::TestTrieIterator32() {
+ TestTrieIterator<wchar32>(false);
+}
+
+void TCompactTrieTest::TestMinimizedTrieIterator8() {
+ TestTrieIterator<char>(true);
+}
+void TCompactTrieTest::TestMinimizedTrieIterator16() {
+ TestTrieIterator<wchar16>(true);
+}
+void TCompactTrieTest::TestMinimizedTrieIterator32() {
+ TestTrieIterator<wchar32>(true);
+}
+
+void TCompactTrieTest::TestPhraseSearch() {
+ static const char* phrases[] = {"ab", "ab cd", "ab cd ef"};
+ static const char* const goodphrase = "ab cd ef gh";
+ static const char* const badphrase = "cd ef gh ab";
+ TBufferOutput bufout;
+
+ TCompactTrieBuilder<char> builder;
+ for (size_t i = 0; i < Y_ARRAY_SIZE(phrases); i++) {
+ builder.Add(phrases[i], strlen(phrases[i]), i);
+ }
+ builder.Save(bufout);
+
+ TCompactTrie<char> trie(bufout.Buffer().Data(), bufout.Buffer().Size());
+ TVector<TCompactTrie<char>::TPhraseMatch> matches;
+ trie.FindPhrases(goodphrase, strlen(goodphrase), matches);
+
+ UNIT_ASSERT(matches.size() == Y_ARRAY_SIZE(phrases));
+ for (size_t i = 0; i < Y_ARRAY_SIZE(phrases); i++) {
+ UNIT_ASSERT(matches[i].first == strlen(phrases[i]));
+ UNIT_ASSERT(matches[i].second == i);
+ }
+
+ trie.FindPhrases(badphrase, strlen(badphrase), matches);
+ UNIT_ASSERT(matches.size() == 0);
+}
+
+void TCompactTrieTest::TestAddGet() {
+ TCompactTrieBuilder<char> builder;
+ builder.Add("abcd", 4, 1);
+ builder.Add("acde", 4, 2);
+ ui64 dummy;
+ UNIT_ASSERT(builder.Find("abcd", 4, &dummy));
+ UNIT_ASSERT(1 == dummy);
+ UNIT_ASSERT(builder.Find("acde", 4, &dummy));
+ UNIT_ASSERT(2 == dummy);
+ UNIT_ASSERT(!builder.Find("fgdgfacde", 9, &dummy));
+ UNIT_ASSERT(!builder.Find("ab", 2, &dummy));
+}
+
+void TCompactTrieTest::TestEmpty() {
+ TCompactTrieBuilder<char> builder;
+ ui64 dummy = 12345;
+ size_t prefixLen;
+ UNIT_ASSERT(!builder.Find("abc", 3, &dummy));
+ TBufferOutput bufout;
+ builder.Save(bufout);
+
+ TCompactTrie<char> trie(bufout.Buffer().Data(), bufout.Buffer().Size());
+ UNIT_ASSERT(!trie.Find("abc", 3, &dummy));
+ UNIT_ASSERT(!trie.Find("", 0, &dummy));
+ UNIT_ASSERT(!trie.FindLongestPrefix("abc", 3, &prefixLen, &dummy));
+ UNIT_ASSERT(!trie.FindLongestPrefix("", 0, &prefixLen, &dummy));
+ UNIT_ASSERT_EQUAL(12345, dummy);
+
+ UNIT_ASSERT(trie.Begin() == trie.End());
+
+ TCompactTrie<> trieNull;
+
+ UNIT_ASSERT(!trieNull.Find(" ", 1));
+
+ TCompactTrie<>::TPhraseMatchVector matches;
+ trieNull.FindPhrases(" ", 1, matches); // just to be sure it doesn't crash
+
+ UNIT_ASSERT(trieNull.Begin() == trieNull.End());
+}
+
+void TCompactTrieTest::TestUninitializedNonEmpty() {
+ TBufferOutput bufout;
+ CreateTrie<char>(bufout, false, false);
+ TCompactTrie<char> trie(bufout.Buffer().Data(), bufout.Buffer().Size());
+ typedef TCompactTrie<char>::TKey TKey;
+ typedef TCompactTrie<char>::TConstIterator TIter;
+
+ TCompactTrie<char> tails = trie.FindTails("abd", 3); // A trie that has empty value and no data.
+ UNIT_ASSERT(!tails.IsEmpty());
+ UNIT_ASSERT(!tails.IsInitialized());
+ const TKey wideKey = MakeWideKey<char>("c", 1);
+ TIter it = tails.UpperBound(wideKey);
+ UNIT_ASSERT(it == tails.End());
+ UNIT_ASSERT(it != tails.Begin());
+ --it;
+ UNIT_ASSERT(it == tails.Begin());
+ ++it;
+ UNIT_ASSERT(it == tails.End());
+}
+
+static char RandChar() {
+ return char(RandomNumber<size_t>() % 256);
+}
+
+static TString RandStr(const size_t max) {
+ size_t len = RandomNumber<size_t>() % max;
+ TString key;
+ for (size_t j = 0; j < len; ++j)
+ key += RandChar();
+ return key;
+}
+
+template <class T, bool minimize>
+void TCompactTrieTest::TestRandom(const size_t n, const size_t maxKeySize) {
+ const TStringBuf EMPTY_KEY = TStringBuf("", 1);
+ TCompactTrieBuilder<char, typename T::TData, T> builder;
+ typedef TMap<TString, typename T::TData> TKeys;
+ TKeys keys;
+
+ typename T::TData dummy;
+ for (size_t i = 0; i < n; ++i) {
+ const TString key = RandStr(maxKeySize);
+ if (key != EMPTY_KEY && keys.find(key) == keys.end()) {
+ const typename T::TData val = T::Data(key);
+ keys[key] = val;
+ UNIT_ASSERT_C(!builder.Find(key.data(), key.size(), &dummy), "key = " << HexEncode(TString(key)));
+ builder.Add(key.data(), key.size(), val);
+ UNIT_ASSERT_C(builder.Find(key.data(), key.size(), &dummy), "key = " << HexEncode(TString(key)));
+ UNIT_ASSERT(dummy == val);
+ }
+ }
+
+ TBufferStream stream;
+ size_t len = builder.Save(stream);
+ TCompactTrie<char, typename T::TData, T> trie(stream.Buffer().Data(), len);
+
+ TBufferStream buftmp;
+ if (minimize) {
+ CompactTrieMinimize<T>(buftmp, stream.Buffer().Data(), len, false);
+ }
+ TCompactTrie<char, typename T::TData, T> trieMin(buftmp.Buffer().Data(), buftmp.Buffer().Size());
+
+ TCompactTrieBuilder<char, typename T::TData, T> prefixGroupedBuilder(CTBF_PREFIX_GROUPED);
+
+ for (typename TKeys::const_iterator i = keys.begin(), mi = keys.end(); i != mi; ++i) {
+ UNIT_ASSERT(!prefixGroupedBuilder.Find(i->first.c_str(), i->first.size(), &dummy));
+ UNIT_ASSERT(trie.Find(i->first.c_str(), i->first.size(), &dummy));
+ UNIT_ASSERT(dummy == i->second);
+ if (minimize) {
+ UNIT_ASSERT(trieMin.Find(i->first.c_str(), i->first.size(), &dummy));
+ UNIT_ASSERT(dummy == i->second);
+ }
+
+ prefixGroupedBuilder.Add(i->first.c_str(), i->first.size(), dummy);
+ UNIT_ASSERT(prefixGroupedBuilder.Find(i->first.c_str(), i->first.size(), &dummy));
+
+ for (typename TKeys::const_iterator j = keys.begin(), end = keys.end(); j != end; ++j) {
+ typename T::TData valFound;
+ if (j->first <= i->first) {
+ UNIT_ASSERT(prefixGroupedBuilder.Find(j->first.c_str(), j->first.size(), &valFound));
+ UNIT_ASSERT_VALUES_EQUAL(j->second, valFound);
+ } else {
+ UNIT_ASSERT(!prefixGroupedBuilder.Find(j->first.c_str(), j->first.size(), &valFound));
+ }
+ }
+ }
+
+ TBufferStream prefixGroupedBuffer;
+ prefixGroupedBuilder.Save(prefixGroupedBuffer);
+
+ UNIT_ASSERT_VALUES_EQUAL(stream.Buffer().Size(), prefixGroupedBuffer.Buffer().Size());
+ UNIT_ASSERT(0 == memcmp(stream.Buffer().Data(), prefixGroupedBuffer.Buffer().Data(), stream.Buffer().Size()));
+}
+
+void TCompactTrieTest::TestRandom() {
+ TestRandom<TIntPacker<ui64>, true>(1000, 1000);
+ TestRandom<TIntPacker<int>, true>(100, 100);
+ TestRandom<TDummyPacker<ui64>, true>(0, 0);
+ TestRandom<TDummyPacker<ui64>, true>(100, 3);
+ TestRandom<TDummyPacker<ui64>, true>(100, 100);
+ TestRandom<TStrokaPacker, true>(100, 100);
+}
+
+void TCompactTrieTest::TestFindTailsImpl(const TString& prefix) {
+ TCompactTrieBuilder<> builder;
+
+ TMap<TString, ui64> input;
+
+ for (auto& i : SampleData) {
+ TString temp = i;
+ ui64 val = temp.size() * 2;
+ builder.Add(temp.data(), temp.size(), val);
+ if (temp.StartsWith(prefix)) {
+ input[temp.substr(prefix.size())] = val;
+ }
+ }
+
+ typedef TCompactTrie<> TTrie;
+
+ TBufferStream stream;
+ size_t len = builder.Save(stream);
+ TTrie trie(stream.Buffer().Data(), len);
+
+ TTrie subtrie = trie.FindTails(prefix.data(), prefix.size());
+
+ TMap<TString, ui64> output;
+
+ for (TTrie::TConstIterator i = subtrie.Begin(), mi = subtrie.End(); i != mi; ++i) {
+ TTrie::TValueType val = *i;
+ output[TString(val.first.data(), val.first.size())] = val.second;
+ }
+ UNIT_ASSERT(input.size() == output.size());
+ UNIT_ASSERT(input == output);
+
+ TBufferStream buftmp;
+ CompactTrieMinimize<TTrie::TPacker>(buftmp, stream.Buffer().Data(), len, false);
+ TTrie trieMin(buftmp.Buffer().Data(), buftmp.Buffer().Size());
+
+ subtrie = trieMin.FindTails(prefix.data(), prefix.size());
+ output.clear();
+
+ for (TTrie::TConstIterator i = subtrie.Begin(), mi = subtrie.End(); i != mi; ++i) {
+ TTrie::TValueType val = *i;
+ output[TString(val.first.data(), val.first.size())] = val.second;
+ }
+ UNIT_ASSERT(input.size() == output.size());
+ UNIT_ASSERT(input == output);
+}
+
+void TCompactTrieTest::TestPrefixGrouped() {
+ TBuffer b1b;
+ TCompactTrieBuilder<char, ui32> b1(CTBF_PREFIX_GROUPED);
+ const char* data[] = {
+ "Kazan",
+ "Moscow",
+ "Monino",
+ "Murmansk",
+ "Fryanovo",
+ "Fryazino",
+ "Fryazevo",
+ "Tumen",
+ };
+
+ for (size_t i = 0; i < Y_ARRAY_SIZE(data); ++i) {
+ ui32 val = strlen(data[i]) + 1;
+ b1.Add(data[i], strlen(data[i]), val);
+ for (size_t j = 0; j < Y_ARRAY_SIZE(data); ++j) {
+ ui32 mustHave = strlen(data[j]) + 1;
+ ui32 found = 0;
+ if (j <= i) {
+ UNIT_ASSERT(b1.Find(data[j], strlen(data[j]), &found));
+ UNIT_ASSERT_VALUES_EQUAL(mustHave, found);
+ } else {
+ UNIT_ASSERT(!b1.Find(data[j], strlen(data[j]), &found));
+ }
+ }
+ }
+
+ {
+ TBufferOutput b1bo(b1b);
+ b1.Save(b1bo);
+ }
+
+ TCompactTrie<char, ui32> t1(TBlob::FromBuffer(b1b));
+
+ //t1.Print(Cerr);
+
+ for (auto& i : data) {
+ ui32 v;
+ UNIT_ASSERT(t1.Find(i, strlen(i), &v));
+ UNIT_ASSERT_VALUES_EQUAL(strlen(i) + 1, v);
+ }
+}
+
+void TCompactTrieTest::CrashTestPrefixGrouped() {
+ TCompactTrieBuilder<char, ui32> builder(CTBF_PREFIX_GROUPED);
+ const char* data[] = {
+ "Fryazino",
+ "Fryanovo",
+ "Monino",
+ "",
+ "Fryazevo",
+ };
+ bool wasException = false;
+ try {
+ for (size_t i = 0; i < Y_ARRAY_SIZE(data); ++i) {
+ builder.Add(data[i], strlen(data[i]), i + 1);
+ }
+ } catch (const yexception& e) {
+ wasException = true;
+ UNIT_ASSERT(strstr(e.what(), "Bad input order - expected input strings to be prefix-grouped."));
+ }
+ UNIT_ASSERT_C(wasException, "CrashTestPrefixGrouped");
+}
+
+void TCompactTrieTest::TestMergeFromFile() {
+ {
+ TCompactTrieBuilder<> b;
+ b.Add("yandex", 12);
+ b.Add("google", 13);
+ b.Add("mail", 14);
+ TUnbufferedFileOutput out(GetSystemTempDir() + "/TCompactTrieTest-TestMerge-ru");
+ b.Save(out);
+ }
+
+ {
+ TCompactTrieBuilder<> b;
+ b.Add("yandex", 112);
+ b.Add("google", 113);
+ b.Add("yahoo", 114);
+ TUnbufferedFileOutput out(GetSystemTempDir() + "/TCompactTrieTest-TestMerge-com");
+ b.Save(out);
+ }
+
+ {
+ TCompactTrieBuilder<> b;
+ UNIT_ASSERT(b.AddSubtreeInFile("com.", GetSystemTempDir() + "/TCompactTrieTest-TestMerge-com"));
+ UNIT_ASSERT(b.Add("org.kernel", 22));
+ UNIT_ASSERT(b.AddSubtreeInFile("ru.", GetSystemTempDir() + "/TCompactTrieTest-TestMerge-ru"));
+ TUnbufferedFileOutput out(GetSystemTempDir() + "/TCompactTrieTest-TestMerge-res");
+ b.Save(out);
+ }
+
+ TCompactTrie<> trie(TBlob::FromFileSingleThreaded(GetSystemTempDir() + "/TCompactTrieTest-TestMerge-res"));
+ UNIT_ASSERT_VALUES_EQUAL(12u, trie.Get("ru.yandex"));
+ UNIT_ASSERT_VALUES_EQUAL(13u, trie.Get("ru.google"));
+ UNIT_ASSERT_VALUES_EQUAL(14u, trie.Get("ru.mail"));
+ UNIT_ASSERT_VALUES_EQUAL(22u, trie.Get("org.kernel"));
+ UNIT_ASSERT_VALUES_EQUAL(112u, trie.Get("com.yandex"));
+ UNIT_ASSERT_VALUES_EQUAL(113u, trie.Get("com.google"));
+ UNIT_ASSERT_VALUES_EQUAL(114u, trie.Get("com.yahoo"));
+
+ unlink((GetSystemTempDir() + "/TCompactTrieTest-TestMerge-res").data());
+ unlink((GetSystemTempDir() + "/TCompactTrieTest-TestMerge-com").data());
+ unlink((GetSystemTempDir() + "/TCompactTrieTest-TestMerge-ru").data());
+}
+
+void TCompactTrieTest::TestMergeFromBuffer() {
+ TArrayWithSizeHolder<char> buffer1;
+ {
+ TCompactTrieBuilder<> b;
+ b.Add("aaaaa", 1);
+ b.Add("bbbbb", 2);
+ b.Add("ccccc", 3);
+ buffer1.Resize(b.MeasureByteSize());
+ TMemoryOutput out(buffer1.Get(), buffer1.Size());
+ b.Save(out);
+ }
+
+ TArrayWithSizeHolder<char> buffer2;
+ {
+ TCompactTrieBuilder<> b;
+ b.Add("aaaaa", 10);
+ b.Add("bbbbb", 20);
+ b.Add("ccccc", 30);
+ b.Add("xxxxx", 40);
+ b.Add("yyyyy", 50);
+ buffer2.Resize(b.MeasureByteSize());
+ TMemoryOutput out(buffer2.Get(), buffer2.Size());
+ b.Save(out);
+ }
+
+ {
+ TCompactTrieBuilder<> b;
+ UNIT_ASSERT(b.AddSubtreeInBuffer("com.", std::move(buffer1)));
+ UNIT_ASSERT(b.Add("org.upyachka", 42));
+ UNIT_ASSERT(b.AddSubtreeInBuffer("ru.", std::move(buffer2)));
+ TUnbufferedFileOutput out(GetSystemTempDir() + "/TCompactTrieTest-TestMergeFromBuffer-res");
+ b.Save(out);
+ }
+
+ TCompactTrie<> trie(TBlob::FromFileSingleThreaded(GetSystemTempDir() + "/TCompactTrieTest-TestMergeFromBuffer-res"));
+ UNIT_ASSERT_VALUES_EQUAL(10u, trie.Get("ru.aaaaa"));
+ UNIT_ASSERT_VALUES_EQUAL(20u, trie.Get("ru.bbbbb"));
+ UNIT_ASSERT_VALUES_EQUAL(40u, trie.Get("ru.xxxxx"));
+ UNIT_ASSERT_VALUES_EQUAL(42u, trie.Get("org.upyachka"));
+ UNIT_ASSERT_VALUES_EQUAL(1u, trie.Get("com.aaaaa"));
+ UNIT_ASSERT_VALUES_EQUAL(2u, trie.Get("com.bbbbb"));
+ UNIT_ASSERT_VALUES_EQUAL(3u, trie.Get("com.ccccc"));
+
+ unlink((GetSystemTempDir() + "/TCompactTrieTest-TestMergeFromBuffer-res").data());
+}
+
+void TCompactTrieTest::TestUnique() {
+ TestUniqueImpl(false);
+ TestUniqueImpl(true);
+}
+
+void TCompactTrieTest::TestUniqueImpl(bool isPrefixGrouped) {
+ TCompactTrieBuilder<char, ui32> builder(CTBF_UNIQUE | (isPrefixGrouped ? CTBF_PREFIX_GROUPED : CTBF_NONE));
+ const char* data[] = {
+ "Kazan",
+ "Moscow",
+ "Monino",
+ "Murmansk",
+ "Fryanovo",
+ "Fryazino",
+ "Fryazevo",
+ "Fry",
+ "Tumen",
+ };
+ for (size_t i = 0; i < Y_ARRAY_SIZE(data); ++i) {
+ UNIT_ASSERT_C(builder.Add(data[i], strlen(data[i]), i + 1), i);
+ }
+ bool wasException = false;
+ try {
+ builder.Add(data[4], strlen(data[4]), 20);
+ } catch (const yexception& e) {
+ wasException = true;
+ UNIT_ASSERT(strstr(e.what(), "Duplicate key"));
+ }
+ UNIT_ASSERT_C(wasException, "TestUnique");
+}
+
+void TCompactTrieTest::TestAddRetValue() {
+ TCompactTrieBuilder<char, ui32> builder;
+ const char* data[] = {
+ "Kazan",
+ "Moscow",
+ "Monino",
+ "Murmansk",
+ "Fryanovo",
+ "Fryazino",
+ "Fryazevo",
+ "Fry",
+ "Tumen",
+ };
+ for (size_t i = 0; i < Y_ARRAY_SIZE(data); ++i) {
+ UNIT_ASSERT(builder.Add(data[i], strlen(data[i]), i + 1));
+ UNIT_ASSERT(!builder.Add(data[i], strlen(data[i]), i + 2));
+ ui32 value;
+ UNIT_ASSERT(builder.Find(data[i], strlen(data[i]), &value));
+ UNIT_ASSERT(value == i + 2);
+ }
+}
+
+void TCompactTrieTest::TestClear() {
+ TCompactTrieBuilder<char, ui32> builder;
+ const char* data[] = {
+ "Kazan",
+ "Moscow",
+ "Monino",
+ "Murmansk",
+ "Fryanovo",
+ "Fryazino",
+ "Fryazevo",
+ "Fry",
+ "Tumen",
+ };
+ for (size_t i = 0; i < Y_ARRAY_SIZE(data); ++i) {
+ builder.Add(data[i], strlen(data[i]), i + 1);
+ }
+ UNIT_ASSERT(builder.GetEntryCount() == Y_ARRAY_SIZE(data));
+ builder.Clear();
+ UNIT_ASSERT(builder.GetEntryCount() == 0);
+ UNIT_ASSERT(builder.GetNodeCount() == 1);
+}
+
+void TCompactTrieTest::TestFindTails() {
+ TestFindTailsImpl("aa");
+ TestFindTailsImpl("bb");
+ TestFindTailsImpl("fb");
+ TestFindTailsImpl("fbc");
+ TestFindTailsImpl("fbbaa");
+}
+
+template <class T>
+class TCompactTrieTest::TDummyPacker: public TNullPacker<T> {
+public:
+ static T Data(const TString&) {
+ T data;
+ TNullPacker<T>().UnpackLeaf(nullptr, data);
+ return data;
+ }
+
+ typedef T TData;
+};
+
+class TCompactTrieTest::TStrokaPacker: public TCompactTriePacker<TString> {
+public:
+ typedef TString TData;
+
+ static TString Data(const TString& str) {
+ return str;
+ }
+};
+
+template <class T>
+class TCompactTrieTest::TIntPacker: public TCompactTriePacker<T> {
+public:
+ typedef T TData;
+
+ static TData Data(const TString&) {
+ return RandomNumber<std::make_unsigned_t<T>>();
+ }
+};
+
+void TCompactTrieTest::TestIterateEmptyKey() {
+ TBuffer trieBuffer;
+ {
+ TCompactTrieBuilder<char, ui32> builder;
+ UNIT_ASSERT(builder.Add("", 1));
+ TBufferStream trieBufferO(trieBuffer);
+ builder.Save(trieBufferO);
+ }
+ TCompactTrie<char, ui32> trie(TBlob::FromBuffer(trieBuffer));
+ ui32 val;
+ UNIT_ASSERT(trie.Find("", &val));
+ UNIT_ASSERT(val == 1);
+ TCompactTrie<char, ui32>::TConstIterator it = trie.Begin();
+ UNIT_ASSERT(it.GetKey().empty());
+ UNIT_ASSERT(it.GetValue() == 1);
+}
+
+void TCompactTrieTest::TestTrieSet() {
+ TBuffer buffer;
+ {
+ TCompactTrieSet<char>::TBuilder builder;
+ UNIT_ASSERT(builder.Add("a", 0));
+ UNIT_ASSERT(builder.Add("ab", 1));
+ UNIT_ASSERT(builder.Add("abc", 1));
+ UNIT_ASSERT(builder.Add("abcd", 0));
+ UNIT_ASSERT(!builder.Add("abcd", 1));
+
+ TBufferStream stream(buffer);
+ builder.Save(stream);
+ }
+
+ TCompactTrieSet<char> set(TBlob::FromBuffer(buffer));
+ UNIT_ASSERT(set.Has("a"));
+ UNIT_ASSERT(set.Has("ab"));
+ UNIT_ASSERT(set.Has("abc"));
+ UNIT_ASSERT(set.Has("abcd"));
+ UNIT_ASSERT(!set.Has("abcde"));
+ UNIT_ASSERT(!set.Has("aa"));
+ UNIT_ASSERT(!set.Has("b"));
+ UNIT_ASSERT(!set.Has(""));
+
+ TCompactTrieSet<char> tails;
+ UNIT_ASSERT(set.FindTails("a", tails));
+ UNIT_ASSERT(tails.Has("b"));
+ UNIT_ASSERT(tails.Has("bcd"));
+ UNIT_ASSERT(!tails.Has("ab"));
+ UNIT_ASSERT(!set.Has(""));
+
+ TCompactTrieSet<char> empty;
+ UNIT_ASSERT(set.FindTails("abcd", empty));
+ UNIT_ASSERT(!empty.Has("a"));
+ UNIT_ASSERT(!empty.Has("b"));
+ UNIT_ASSERT(!empty.Has("c"));
+ UNIT_ASSERT(!empty.Has("d"));
+ UNIT_ASSERT(!empty.Has("d"));
+
+ UNIT_ASSERT(empty.Has("")); // contains only empty string
+}
+
+// Tests for trie with vector (list, set) values
+
+TVector<TUtf16String> TCompactTrieTest::GetSampleKeys(size_t nKeys) const {
+ Y_ASSERT(nKeys <= 10);
+ TString sampleKeys[] = {"a", "b", "ac", "bd", "abe", "bcf", "deg", "ah", "xy", "abc"};
+ TVector<TUtf16String> result;
+ for (size_t i = 0; i < nKeys; i++)
+ result.push_back(ASCIIToWide(sampleKeys[i]));
+ return result;
+}
+
+template <class TContainer>
+TVector<TContainer> TCompactTrieTest::GetSampleVectorData(size_t nValues) {
+ TVector<TContainer> data;
+ for (size_t i = 0; i < nValues; i++) {
+ data.push_back(TContainer());
+ for (size_t j = 0; j < i; j++)
+ data[i].insert(data[i].end(), (typename TContainer::value_type)((j == 3) ? 0 : (1 << (j * 5))));
+ }
+ return data;
+}
+
+template <class TContainer>
+TVector<TContainer> TCompactTrieTest::GetSampleTextVectorData(size_t nValues) {
+ TVector<TContainer> data;
+ for (size_t i = 0; i < nValues; i++) {
+ data.push_back(TContainer());
+ for (size_t j = 0; j < i; j++)
+ data[i].insert(data[i].end(), TString("abc") + ToString<size_t>(j));
+ }
+ return data;
+}
+
+template <class T>
+void TCompactTrieTest::CheckEquality(const T& value1, const T& value2) const {
+ UNIT_ASSERT_VALUES_EQUAL(value1, value2);
+}
+
+template <>
+void TCompactTrieTest::CheckEquality<TVector<i64>>(const TVector<i64>& value1, const TVector<i64>& value2) const {
+ UNIT_ASSERT_VALUES_EQUAL(value1.size(), value2.size());
+ for (size_t i = 0; i < value1.size(); i++)
+ UNIT_ASSERT_VALUES_EQUAL(value1[i], value2[i]);
+}
+
+template <class TContainer>
+void TCompactTrieTest::TestTrieWithContainers(const TVector<TUtf16String>& keys, const TVector<TContainer>& sampleData, TString methodName) {
+ TString fileName = GetSystemTempDir() + "/TCompactTrieTest-TestTrieWithContainers-" + methodName;
+
+ TCompactTrieBuilder<wchar16, TContainer> b;
+ for (size_t i = 0; i < keys.size(); i++) {
+ b.Add(keys[i], sampleData[i]);
+ }
+ TUnbufferedFileOutput out(fileName);
+ b.Save(out);
+
+ TCompactTrie<wchar16, TContainer> trie(TBlob::FromFileSingleThreaded(fileName));
+ for (size_t i = 0; i < keys.size(); i++) {
+ TContainer value = trie.Get(keys[i]);
+ UNIT_ASSERT_VALUES_EQUAL(value.size(), sampleData[i].size());
+ typename TContainer::const_iterator p = value.begin();
+ typename TContainer::const_iterator p1 = sampleData[i].begin();
+ for (; p != value.end(); p++, p1++)
+ CheckEquality<typename TContainer::value_type>(*p, *p1);
+ }
+
+ unlink(fileName.data());
+}
+
+template <>
+void TCompactTrieTest::TestTrieWithContainers<std::pair<TUtf16String, TVector<i64>>>(const TVector<TUtf16String>& keys, const TVector<std::pair<TUtf16String, TVector<i64>>>& sampleData, TString methodName) {
+ typedef std::pair<TUtf16String, TVector<i64>> TContainer;
+ TString fileName = GetSystemTempDir() + "/TCompactTrieTest-TestTrieWithContainers-" + methodName;
+
+ TCompactTrieBuilder<wchar16, TContainer> b;
+ for (size_t i = 0; i < keys.size(); i++) {
+ b.Add(keys[i], sampleData[i]);
+ }
+ TUnbufferedFileOutput out(fileName);
+ b.Save(out);
+
+ TCompactTrie<wchar16, TContainer> trie(TBlob::FromFileSingleThreaded(fileName));
+ for (size_t i = 0; i < keys.size(); i++) {
+ TContainer value = trie.Get(keys[i]);
+ CheckEquality<TContainer::first_type>(value.first, sampleData[i].first);
+ CheckEquality<TContainer::second_type>(value.second, sampleData[i].second);
+ }
+
+ unlink(fileName.data());
+}
+
+void TCompactTrieTest::TestTrieForVectorInt64() {
+ TestTrieWithContainers<TVector<i64>>(GetSampleKeys(10), GetSampleVectorData<TVector<i64>>(10), "v-i64");
+}
+
+void TCompactTrieTest::TestTrieForListInt64() {
+ TestTrieWithContainers<TList<i64>>(GetSampleKeys(10), GetSampleVectorData<TList<i64>>(10), "l-i64");
+}
+
+void TCompactTrieTest::TestTrieForSetInt64() {
+ TestTrieWithContainers<TSet<i64>>(GetSampleKeys(10), GetSampleVectorData<TSet<i64>>(10), "s-i64");
+}
+
+void TCompactTrieTest::TestTrieForVectorStroka() {
+ TestTrieWithContainers<TVector<TString>>(GetSampleKeys(10), GetSampleTextVectorData<TVector<TString>>(10), "v-str");
+}
+
+void TCompactTrieTest::TestTrieForListStroka() {
+ TestTrieWithContainers<TList<TString>>(GetSampleKeys(10), GetSampleTextVectorData<TList<TString>>(10), "l-str");
+}
+
+void TCompactTrieTest::TestTrieForSetStroka() {
+ TestTrieWithContainers<TSet<TString>>(GetSampleKeys(10), GetSampleTextVectorData<TSet<TString>>(10), "s-str");
+}
+
+void TCompactTrieTest::TestTrieForVectorWtroka() {
+ TVector<TVector<TString>> data = GetSampleTextVectorData<TVector<TString>>(10);
+ TVector<TVector<TUtf16String>> wData;
+ for (size_t i = 0; i < data.size(); i++) {
+ wData.push_back(TVector<TUtf16String>());
+ for (size_t j = 0; j < data[i].size(); j++)
+ wData[i].push_back(UTF8ToWide(data[i][j]));
+ }
+ TestTrieWithContainers<TVector<TUtf16String>>(GetSampleKeys(10), wData, "v-wtr");
+}
+
+void TCompactTrieTest::TestTrieForVectorFloat() {
+ TestTrieWithContainers<TVector<float>>(GetSampleKeys(10), GetSampleVectorData<TVector<float>>(10), "v-float");
+}
+
+void TCompactTrieTest::TestTrieForVectorDouble() {
+ TestTrieWithContainers<TVector<double>>(GetSampleKeys(10), GetSampleVectorData<TVector<double>>(10), "v-double");
+}
+
+void TCompactTrieTest::TestTrieForListVectorInt64() {
+ TVector<i64> tmp;
+ tmp.push_back(0);
+ TList<TVector<i64>> dataElement(5, tmp);
+ TVector<TList<TVector<i64>>> data(10, dataElement);
+ TestTrieWithContainers<TList<TVector<i64>>>(GetSampleKeys(10), data, "l-v-i64");
+}
+
+void TCompactTrieTest::TestTrieForPairWtrokaVectorInt64() {
+ TVector<TUtf16String> keys = GetSampleKeys(10);
+ TVector<TVector<i64>> values = GetSampleVectorData<TVector<i64>>(10);
+ TVector<std::pair<TUtf16String, TVector<i64>>> data;
+ for (size_t i = 0; i < 10; i++)
+ data.push_back(std::pair<TUtf16String, TVector<i64>>(keys[i] + u"_v", values[i]));
+ TestTrieWithContainers<std::pair<TUtf16String, TVector<i64>>>(keys, data, "pair-str-v-i64");
+}
+
+void TCompactTrieTest::TestEmptyValueOutOfOrder() {
+ TBufferOutput buffer;
+ using TSymbol = ui32;
+ {
+ TCompactTrieBuilder<TSymbol, ui32> builder;
+ TSymbol key = 1;
+ builder.Add(&key, 1, 10);
+ builder.Add(nullptr, 0, 14);
+ builder.Save(buffer);
+ }
+ {
+ TCompactTrie<TSymbol, ui32> trie(buffer.Buffer().Data(), buffer.Buffer().Size());
+ UNIT_ASSERT(trie.Find(nullptr, 0));
+ }
+}
+
+void TCompactTrieTest::TestFindLongestPrefixWithEmptyValue() {
+ TBufferOutput buffer;
+ {
+ TCompactTrieBuilder<wchar16, ui32> builder;
+ builder.Add(u"", 42);
+ builder.Add(u"yandex", 271828);
+ builder.Add(u"ya", 31415);
+ builder.Save(buffer);
+ }
+ {
+ TCompactTrie<wchar16, ui32> trie(buffer.Buffer().Data(), buffer.Buffer().Size());
+ size_t prefixLen = 123;
+ ui32 value = 0;
+
+ UNIT_ASSERT(trie.FindLongestPrefix(u"google", &prefixLen, &value));
+ UNIT_ASSERT(prefixLen == 0);
+ UNIT_ASSERT(value == 42);
+
+ UNIT_ASSERT(trie.FindLongestPrefix(u"yahoo", &prefixLen, &value));
+ UNIT_ASSERT(prefixLen == 2);
+ UNIT_ASSERT(value == 31415);
+ }
+}
+
+template <typename TChar>
+struct TConvertKey {
+ static inline TString Convert(const TStringBuf& key) {
+ return ToString(key);
+ }
+};
+
+template <>
+struct TConvertKey<wchar16> {
+ static inline TUtf16String Convert(const TStringBuf& key) {
+ return UTF8ToWide(key);
+ }
+};
+
+template <>
+struct TConvertKey<wchar32> {
+ static inline TUtf32String Convert(const TStringBuf& key) {
+ return TUtf32String::FromUtf8(key);
+ }
+};
+
+template <class TSearchIter, class TKeyBuf>
+static void MoveIter(TSearchIter& iter, const TKeyBuf& key) {
+ for (size_t i = 0; i < key.length(); ++i) {
+ UNIT_ASSERT(iter.Advance(key[i]));
+ }
+}
+
+template <typename TChar>
+void TCompactTrieTest::TestSearchIterImpl() {
+ TBufferOutput buffer;
+ {
+ TCompactTrieBuilder<TChar, ui32> builder;
+ TStringBuf data[] = {
+ TStringBuf("abaab"),
+ TStringBuf("abcdef"),
+ TStringBuf("abbbc"),
+ TStringBuf("bdfaa"),
+ };
+ for (size_t i = 0; i < Y_ARRAY_SIZE(data); ++i) {
+ builder.Add(TConvertKey<TChar>::Convert(data[i]), i + 1);
+ }
+ builder.Save(buffer);
+ }
+
+ TCompactTrie<TChar, ui32> trie(buffer.Buffer().Data(), buffer.Buffer().Size());
+ ui32 value = 0;
+ auto iter(MakeSearchIterator(trie));
+ MoveIter(iter, TConvertKey<TChar>::Convert(TStringBuf("abc")));
+ UNIT_ASSERT(!iter.GetValue(&value));
+
+ iter = MakeSearchIterator(trie);
+ MoveIter(iter, TConvertKey<TChar>::Convert(TStringBuf("abbbc")));
+ UNIT_ASSERT(iter.GetValue(&value));
+ UNIT_ASSERT_EQUAL(value, 3);
+
+ iter = MakeSearchIterator(trie);
+ UNIT_ASSERT(iter.Advance(TConvertKey<TChar>::Convert(TStringBuf("bdfa"))));
+ UNIT_ASSERT(!iter.GetValue(&value));
+
+ iter = MakeSearchIterator(trie);
+ UNIT_ASSERT(iter.Advance(TConvertKey<TChar>::Convert(TStringBuf("bdfaa"))));
+ UNIT_ASSERT(iter.GetValue(&value));
+ UNIT_ASSERT_EQUAL(value, 4);
+
+ UNIT_ASSERT(!MakeSearchIterator(trie).Advance(TChar('z')));
+ UNIT_ASSERT(!MakeSearchIterator(trie).Advance(TConvertKey<TChar>::Convert(TStringBuf("cdf"))));
+ UNIT_ASSERT(!MakeSearchIterator(trie).Advance(TConvertKey<TChar>::Convert(TStringBuf("abca"))));
+}
+
+void TCompactTrieTest::TestSearchIterChar() {
+ TestSearchIterImpl<char>();
+}
+
+void TCompactTrieTest::TestSearchIterWchar() {
+ TestSearchIterImpl<wchar16>();
+}
+
+void TCompactTrieTest::TestSearchIterWchar32() {
+ TestSearchIterImpl<wchar32>();
+}
+
+void TCompactTrieTest::TestCopyAndAssignment() {
+ TBufferOutput bufout;
+ typedef TCompactTrie<> TTrie;
+ CreateTrie<char>(bufout, false, false);
+ TTrie trie(bufout.Buffer().Data(), bufout.Buffer().Size());
+ TTrie copy(trie);
+ UNIT_ASSERT(copy.HasCorrectSkipper());
+ TTrie assign;
+ assign = trie;
+ UNIT_ASSERT(assign.HasCorrectSkipper());
+ TTrie move(std::move(trie));
+ UNIT_ASSERT(move.HasCorrectSkipper());
+ TTrie moveAssign;
+ moveAssign = TTrie(bufout.Buffer().Data(), bufout.Buffer().Size());
+ UNIT_ASSERT(moveAssign.HasCorrectSkipper());
+}
+
+template <class TTrie>
+void TCompactTrieTest::TestFirstSymbolIteratorForTrie(const TTrie& trie, const TStringBuf& narrowAnswers) {
+ NCompactTrie::TFirstSymbolIterator<TTrie> it;
+ it.SetTrie(trie, trie.GetSkipper());
+ typename TTrie::TKey answers = MakeWideKey<typename TTrie::TSymbol>(narrowAnswers);
+ auto answer = answers.begin();
+ for (; !it.AtEnd(); it.MakeStep(), ++answer) {
+ UNIT_ASSERT(answer != answers.end());
+ UNIT_ASSERT(it.GetKey() == *answer);
+ }
+ UNIT_ASSERT(answer == answers.end());
+}
+
+template <class TSymbol>
+void TCompactTrieTest::TestFirstSymbolIterator() {
+ TBufferOutput bufout;
+ typedef TCompactTrie<TSymbol> TTrie;
+ CreateTrie<TSymbol>(bufout, false, false);
+ TTrie trie(bufout.Buffer().Data(), bufout.Buffer().Size());
+ TStringBuf rootAnswers = "abcdf";
+ TestFirstSymbolIteratorForTrie(trie, rootAnswers);
+ TStringBuf aAnswers = "abcd";
+ TestFirstSymbolIteratorForTrie(trie.FindTails(MakeWideKey<TSymbol>("a", 1)), aAnswers);
+}
+
+void TCompactTrieTest::TestFirstSymbolIterator8() {
+ TestFirstSymbolIterator<char>();
+}
+
+void TCompactTrieTest::TestFirstSymbolIterator16() {
+ TestFirstSymbolIterator<wchar16>();
+}
+
+void TCompactTrieTest::TestFirstSymbolIterator32() {
+ TestFirstSymbolIterator<ui32>();
+}
+
+void TCompactTrieTest::TestFirstSymbolIteratorChar32() {
+ TestFirstSymbolIterator<wchar32>();
+}
+
+
+void TCompactTrieTest::TestArrayPacker() {
+ using TDataInt = std::array<int, 2>;
+ const std::pair<TString, TDataInt> dataXxx{"xxx", {{15, 16}}};
+ const std::pair<TString, TDataInt> dataYyy{"yyy", {{20, 30}}};
+
+ TCompactTrieBuilder<char, TDataInt> trieBuilderOne;
+ trieBuilderOne.Add(dataXxx.first, dataXxx.second);
+ trieBuilderOne.Add(dataYyy.first, dataYyy.second);
+
+ TBufferOutput bufferOne;
+ trieBuilderOne.Save(bufferOne);
+
+ const TCompactTrie<char, TDataInt> trieOne(bufferOne.Buffer().Data(), bufferOne.Buffer().Size());
+ UNIT_ASSERT_VALUES_EQUAL(dataXxx.second, trieOne.Get(dataXxx.first));
+ UNIT_ASSERT_VALUES_EQUAL(dataYyy.second, trieOne.Get(dataYyy.first));
+
+ using TDataStroka = std::array<TString, 2>;
+ const std::pair<TString, TDataStroka> dataZzz{"zzz", {{"hello", "there"}}};
+ const std::pair<TString, TDataStroka> dataWww{"www", {{"half", "life"}}};
+
+ TCompactTrieBuilder<char, TDataStroka> trieBuilderTwo;
+ trieBuilderTwo.Add(dataZzz.first, dataZzz.second);
+ trieBuilderTwo.Add(dataWww.first, dataWww.second);
+
+ TBufferOutput bufferTwo;
+ trieBuilderTwo.Save(bufferTwo);
+
+ const TCompactTrie<char, TDataStroka> trieTwo(bufferTwo.Buffer().Data(), bufferTwo.Buffer().Size());
+ UNIT_ASSERT_VALUES_EQUAL(dataZzz.second, trieTwo.Get(dataZzz.first));
+ UNIT_ASSERT_VALUES_EQUAL(dataWww.second, trieTwo.Get(dataWww.first));
+}
+
+void TCompactTrieTest::TestBuilderFindLongestPrefix() {
+ const size_t sizes[] = {10, 100};
+ const double branchProbabilities[] = {0.01, 0.1, 0.5, 0.9, 0.99};
+ for (size_t size : sizes) {
+ for (double branchProbability : branchProbabilities) {
+ TestBuilderFindLongestPrefix(size, branchProbability, false, false);
+ TestBuilderFindLongestPrefix(size, branchProbability, false, true);
+ TestBuilderFindLongestPrefix(size, branchProbability, true, false);
+ TestBuilderFindLongestPrefix(size, branchProbability, true, true);
+ }
+ }
+}
+
+void TCompactTrieTest::TestBuilderFindLongestPrefix(size_t keysCount, double branchProbability, bool isPrefixGrouped, bool hasEmptyKey) {
+ TVector<TString> keys;
+ TString keyToAdd;
+ for (size_t i = 0; i < keysCount; ++i) {
+ const size_t prevKeyLen = keyToAdd.Size();
+ // add two random chars to prev key
+ keyToAdd += RandChar();
+ keyToAdd += RandChar();
+ const bool changeBranch = prevKeyLen && RandomNumber<double>() < branchProbability;
+ if (changeBranch) {
+ const size_t branchPlace = RandomNumber<size_t>(prevKeyLen + 1); // random place in [0, prevKeyLen]
+ *(keyToAdd.begin() + branchPlace) = RandChar();
+ }
+ keys.push_back(keyToAdd);
+ }
+
+ if (isPrefixGrouped)
+ Sort(keys.begin(), keys.end());
+ else
+ Shuffle(keys.begin(), keys.end());
+
+ TCompactTrieBuilder<char, TString> builder(isPrefixGrouped ? CTBF_PREFIX_GROUPED : CTBF_NONE);
+ const TString EMPTY_VALUE = "empty";
+ if (hasEmptyKey)
+ builder.Add(nullptr, 0, EMPTY_VALUE);
+
+ for (size_t i = 0; i < keysCount; ++i) {
+ const TString& key = keys[i];
+
+ for (size_t j = 0; j < keysCount; ++j) {
+ const TString& otherKey = keys[j];
+ const bool exists = j < i;
+ size_t expectedSize = 0;
+ if (exists) {
+ expectedSize = otherKey.size();
+ } else {
+ size_t max = 0;
+ for (size_t k = 0; k < i; ++k)
+ if (keys[k].Size() < otherKey.Size() && keys[k].Size() > max && otherKey.StartsWith(keys[k]))
+ max = keys[k].Size();
+ expectedSize = max;
+ }
+
+ size_t prefixSize = 0xfcfcfc;
+ TString value = "abcd";
+ const bool expectedResult = hasEmptyKey || expectedSize != 0;
+ UNIT_ASSERT_VALUES_EQUAL_C(expectedResult, builder.FindLongestPrefix(otherKey.data(), otherKey.size(), &prefixSize, &value), "otherKey = " << HexEncode(otherKey));
+ if (expectedResult) {
+ UNIT_ASSERT_VALUES_EQUAL(expectedSize, prefixSize);
+ if (expectedSize) {
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuf(otherKey).SubStr(0, prefixSize), value);
+ } else {
+ UNIT_ASSERT_VALUES_EQUAL(EMPTY_VALUE, value);
+ }
+ } else {
+ UNIT_ASSERT_VALUES_EQUAL("abcd", value);
+ UNIT_ASSERT_VALUES_EQUAL(0xfcfcfc, prefixSize);
+ }
+
+ for (int c = 0; c < 10; ++c) {
+ TString extendedKey = otherKey;
+ extendedKey += RandChar();
+ size_t extendedPrefixSize = 0xdddddd;
+ TString extendedValue = "dcba";
+ UNIT_ASSERT_VALUES_EQUAL(expectedResult, builder.FindLongestPrefix(extendedKey.data(), extendedKey.size(), &extendedPrefixSize, &extendedValue));
+ if (expectedResult) {
+ UNIT_ASSERT_VALUES_EQUAL(value, extendedValue);
+ UNIT_ASSERT_VALUES_EQUAL(prefixSize, extendedPrefixSize);
+ } else {
+ UNIT_ASSERT_VALUES_EQUAL("dcba", extendedValue);
+ UNIT_ASSERT_VALUES_EQUAL(0xdddddd, extendedPrefixSize);
+ }
+ }
+ }
+ builder.Add(key.data(), key.size(), key);
+ }
+
+ TBufferOutput buffer;
+ builder.Save(buffer);
+}
+
+void TCompactTrieTest::TestBuilderFindLongestPrefixWithEmptyValue() {
+ TCompactTrieBuilder<wchar16, ui32> builder;
+ builder.Add(u"", 42);
+ builder.Add(u"yandex", 271828);
+ builder.Add(u"ya", 31415);
+
+ size_t prefixLen = 123;
+ ui32 value = 0;
+
+ UNIT_ASSERT(builder.FindLongestPrefix(u"google", &prefixLen, &value));
+ UNIT_ASSERT_VALUES_EQUAL(prefixLen, 0);
+ UNIT_ASSERT_VALUES_EQUAL(value, 42);
+
+ UNIT_ASSERT(builder.FindLongestPrefix(u"yahoo", &prefixLen, &value));
+ UNIT_ASSERT_VALUES_EQUAL(prefixLen, 2);
+ UNIT_ASSERT_VALUES_EQUAL(value, 31415);
+
+ TBufferOutput buffer;
+ builder.Save(buffer);
+}
+
+void TCompactTrieTest::TestPatternSearcherEmpty() {
+ TCompactPatternSearcherBuilder<char, ui32> builder;
+
+ TBufferOutput searcherData;
+ builder.Save(searcherData);
+
+ TCompactPatternSearcher<char, ui32> searcher(
+ searcherData.Buffer().Data(),
+ searcherData.Buffer().Size()
+ );
+
+ UNIT_ASSERT(searcher.SearchMatches("a").empty());
+ UNIT_ASSERT(searcher.SearchMatches("").empty());
+ UNIT_ASSERT(searcher.SearchMatches("abc").empty());
+}
+
+void TCompactTrieTest::TestPatternSearcherOnDataset(
+ const TVector<TString>& patterns,
+ const TVector<TString>& samples
+) {
+ TCompactPatternSearcherBuilder<char, ui32> builder;
+
+ for (size_t patternIdx = 0; patternIdx < patterns.size(); ++patternIdx) {
+ builder.Add(patterns[patternIdx], patternIdx);
+ }
+
+ TBufferOutput searcherData;
+ builder.Save(searcherData);
+
+ TCompactPatternSearcher<char, ui32> searcher(
+ searcherData.Buffer().Data(),
+ searcherData.Buffer().Size()
+ );
+
+ for (const auto& sample : samples) {
+ const auto matches = searcher.SearchMatches(sample);
+
+ size_t matchesNum = 0;
+ THashSet<TString> processedPatterns;
+ for (const auto& pattern : patterns) {
+ if (pattern.Empty() || processedPatterns.contains(pattern)) {
+ continue;
+ }
+ for (size_t start = 0; start + pattern.Size() <= sample.Size(); ++start) {
+ matchesNum += (pattern == sample.substr(start, pattern.Size()));
+ }
+ processedPatterns.insert(pattern);
+ }
+ UNIT_ASSERT_VALUES_EQUAL(matchesNum, matches.size());
+
+
+ TSet<std::pair<size_t, ui32>> foundMatches;
+ for (const auto& match : matches) {
+ std::pair<size_t, ui32> matchParams(match.End, match.Data);
+ UNIT_ASSERT(!foundMatches.contains(matchParams));
+ foundMatches.insert(matchParams);
+
+ const auto& pattern = patterns[match.Data];
+ UNIT_ASSERT_VALUES_EQUAL(
+ sample.substr(match.End - pattern.size() + 1, pattern.size()),
+ pattern
+ );
+ }
+ }
+}
+
+void TCompactTrieTest::TestPatternSearcherSimple() {
+ TestPatternSearcherOnDataset(
+ { // patterns
+ "abcd",
+ "abc",
+ "ab",
+ "a",
+ ""
+ },
+ { // samples
+ "abcde",
+ "abcd",
+ "abc",
+ "ab",
+ "a",
+ ""
+ }
+ );
+ TestPatternSearcherOnDataset(
+ { // patterns
+ "a"
+ "ab",
+ "abcd",
+ },
+ { // samples
+ "abcde",
+ "abcd",
+ "abc",
+ "ab",
+ "a",
+ ""
+ }
+ );
+ TestPatternSearcherOnDataset(
+ { // patterns
+ "aaaa",
+ "aaa",
+ "aa",
+ "a",
+ },
+ { // samples
+ "aaaaaaaaaaaa"
+ }
+ );
+ TestPatternSearcherOnDataset(
+ { // patterns
+ "aa", "ab", "ac", "ad", "ae", "af",
+ "ba", "bb", "bc", "bd", "be", "bf",
+ "ca", "cb", "cc", "cd", "ce", "cf",
+ "da", "db", "dc", "dd", "de", "df",
+ "ea", "eb", "ec", "ed", "ee", "ef",
+ "fa", "fb", "fc", "fd", "fe", "ff"
+ },
+ { // samples
+ "dcabafeebfdcbacddacadbaabecdbaeffecdbfabcdcabcfaefecdfebacfedacefbdcacfeb",
+ "abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefancdefancdef",
+ "fedcbafedcbafedcbafedcbafedcbafedcbafedcbafedcbafedcbafedcbafedcbafedcba",
+ "",
+ "a", "b", "c", "d", "e", "f",
+ "aa", "ab", "ac", "ad", "ae", "af",
+ "ba", "bb", "bc", "bd", "be", "bf",
+ "ca", "cb", "cc", "cd", "ce", "cf",
+ "da", "db", "dc", "dd", "de", "df",
+ "ea", "eb", "ec", "ed", "ee", "ef",
+ "fa", "fb", "fc", "fd", "fe", "ff"
+ }
+ );
+}
+
+static char RandChar(
+ TFastRng<ui64>& rng,
+ int maxChar
+) {
+ return static_cast<char>(rng.GenRand() % (maxChar + 1));
+}
+
+static TString RandStr(
+ TFastRng<ui64>& rng,
+ size_t maxLength,
+ int maxChar,
+ bool nonEmpty = false
+) {
+ Y_ASSERT(maxLength > 0);
+
+ size_t length;
+ if (nonEmpty) {
+ length = rng.GenRand() % maxLength + 1;
+ } else {
+ length = rng.GenRand() % (maxLength + 1);
+ }
+
+ TString result;
+ while (result.size() < length) {
+ result += RandChar(rng, maxChar);
+ }
+
+ return result;
+}
+
+void TCompactTrieTest::TestPatternSearcherRandom(
+ size_t patternsNum,
+ size_t patternMaxLength,
+ size_t strMaxLength,
+ int maxChar,
+ TFastRng<ui64>& rng
+) {
+ auto patternToSearch = RandStr(rng, patternMaxLength, maxChar, /*nonEmpty*/true);
+
+ TVector<TString> patterns = {patternToSearch};
+ while (patterns.size() < patternsNum) {
+ patterns.push_back(RandStr(rng, patternMaxLength, maxChar, /*nonEmpty*/true));
+ }
+
+ auto filler = RandStr(rng, strMaxLength - patternToSearch.Size() + 1, maxChar);
+ size_t leftFillerSize = rng.GenRand() % (filler.size() + 1);
+ auto leftFiller = filler.substr(0, leftFillerSize);
+ auto rightFiller = filler.substr(leftFillerSize, filler.size() - leftFillerSize);
+ auto sample = leftFiller + patternToSearch + rightFiller;
+
+ TestPatternSearcherOnDataset(patterns, {sample});
+}
+
+void TCompactTrieTest::TestPatternSearcherRandom() {
+ TFastRng<ui64> rng(0);
+ for (size_t patternMaxLen : {1, 2, 10}) {
+ for (size_t strMaxLen : TVector<size_t>{patternMaxLen, 2 * patternMaxLen, 10}) {
+ for (int maxChar : {0, 1, 5, 255}) {
+ for (size_t patternsNum : {1, 10}) {
+ for (size_t testIdx = 0; testIdx < 3; ++testIdx) {
+ TestPatternSearcherRandom(
+ patternsNum,
+ patternMaxLen,
+ strMaxLen,
+ maxChar,
+ rng
+ );
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/library/cpp/containers/comptrie/first_symbol_iterator.h b/library/cpp/containers/comptrie/first_symbol_iterator.h
new file mode 100644
index 0000000000..d06135f06f
--- /dev/null
+++ b/library/cpp/containers/comptrie/first_symbol_iterator.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#include "opaque_trie_iterator.h"
+#include <util/generic/ptr.h>
+
+namespace NCompactTrie {
+ // Iterates over possible first symbols in a trie.
+ // Allows one to get the symbol and the subtrie starting from it.
+ template <class TTrie>
+ class TFirstSymbolIterator {
+ public:
+ using TSymbol = typename TTrie::TSymbol;
+ using TData = typename TTrie::TData;
+
+ void SetTrie(const TTrie& trie, const ILeafSkipper& skipper) {
+ Trie = trie;
+ Impl.Reset(new TOpaqueTrieIterator(
+ TOpaqueTrie(Trie.Data().AsCharPtr(), Trie.Data().Size(), skipper),
+ nullptr,
+ false,
+ sizeof(TSymbol)));
+ if (Impl->MeasureKey<TSymbol>() == 0) {
+ MakeStep();
+ }
+ }
+
+ const TTrie& GetTrie() const {
+ return Trie;
+ }
+
+ bool AtEnd() const {
+ return *Impl == TOpaqueTrieIterator(Impl->GetTrie(), nullptr, true, sizeof(TSymbol));
+ }
+
+ TSymbol GetKey() const {
+ return Impl->GetKey<TSymbol>()[0];
+ }
+
+ TTrie GetTails() const {
+ const TNode& node = Impl->GetNode();
+ const size_t forwardOffset = node.GetForwardOffset();
+ const char* emptyValue = node.IsFinal() ? Trie.Data().AsCharPtr() + node.GetLeafOffset() : nullptr;
+ if (forwardOffset) {
+ const char* start = Trie.Data().AsCharPtr() + forwardOffset;
+ TBlob body = TBlob::NoCopy(start, Trie.Data().Size() - forwardOffset);
+ return TTrie(body, emptyValue, Trie.GetPacker());
+ } else {
+ return TTrie(emptyValue);
+ }
+ }
+
+ void MakeStep() {
+ Impl->Forward();
+ }
+
+ private:
+ TTrie Trie;
+ TCopyPtr<TOpaqueTrieIterator> Impl;
+ };
+
+}
diff --git a/library/cpp/containers/comptrie/key_selector.h b/library/cpp/containers/comptrie/key_selector.h
new file mode 100644
index 0000000000..60466cef71
--- /dev/null
+++ b/library/cpp/containers/comptrie/key_selector.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <util/generic/vector.h>
+#include <util/generic/string.h>
+#include <util/generic/strbuf.h>
+
+template <class T>
+struct TCompactTrieKeySelector {
+ typedef TVector<T> TKey;
+ typedef TVector<T> TKeyBuf;
+};
+
+template <class TChar>
+struct TCompactTrieCharKeySelector {
+ typedef TBasicString<TChar> TKey;
+ typedef TBasicStringBuf<TChar> TKeyBuf;
+};
+
+template <>
+struct TCompactTrieKeySelector<char>: public TCompactTrieCharKeySelector<char> {
+};
+
+template <>
+struct TCompactTrieKeySelector<wchar16>: public TCompactTrieCharKeySelector<wchar16> {
+};
+
+template <>
+struct TCompactTrieKeySelector<wchar32>: public TCompactTrieCharKeySelector<wchar32> {
+};
diff --git a/library/cpp/containers/comptrie/leaf_skipper.h b/library/cpp/containers/comptrie/leaf_skipper.h
new file mode 100644
index 0000000000..3959258948
--- /dev/null
+++ b/library/cpp/containers/comptrie/leaf_skipper.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <cstddef>
+
+namespace NCompactTrie {
+ class ILeafSkipper {
+ public:
+ virtual size_t SkipLeaf(const char* p) const = 0;
+ virtual ~ILeafSkipper() = default;
+ };
+
+ template <class TPacker>
+ class TPackerLeafSkipper: public ILeafSkipper {
+ private:
+ const TPacker* Packer;
+
+ public:
+ TPackerLeafSkipper(const TPacker* packer)
+ : Packer(packer)
+ {
+ }
+
+ size_t SkipLeaf(const char* p) const override {
+ return Packer->SkipLeaf(p);
+ }
+
+ // For test purposes.
+ const TPacker* GetPacker() const {
+ return Packer;
+ }
+ };
+
+ // The data you need to traverse the trie without unpacking the values.
+ struct TOpaqueTrie {
+ const char* Data;
+ size_t Length;
+ const ILeafSkipper& SkipFunction;
+
+ TOpaqueTrie(const char* data, size_t dataLength, const ILeafSkipper& skipFunction)
+ : Data(data)
+ , Length(dataLength)
+ , SkipFunction(skipFunction)
+ {
+ }
+
+ bool operator==(const TOpaqueTrie& other) const {
+ return Data == other.Data &&
+ Length == other.Length &&
+ &SkipFunction == &other.SkipFunction;
+ }
+
+ bool operator!=(const TOpaqueTrie& other) const {
+ return !(*this == other);
+ }
+ };
+}
diff --git a/library/cpp/containers/comptrie/loader/loader.cpp b/library/cpp/containers/comptrie/loader/loader.cpp
new file mode 100644
index 0000000000..4811e9d521
--- /dev/null
+++ b/library/cpp/containers/comptrie/loader/loader.cpp
@@ -0,0 +1 @@
+#include "loader.h"
diff --git a/library/cpp/containers/comptrie/loader/loader.h b/library/cpp/containers/comptrie/loader/loader.h
new file mode 100644
index 0000000000..ee10e9b451
--- /dev/null
+++ b/library/cpp/containers/comptrie/loader/loader.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <library/cpp/archive/yarchive.h>
+#include <util/generic/string.h>
+#include <util/generic/ptr.h>
+#include <util/generic/yexception.h>
+#include <util/memory/blob.h>
+
+template <class TrieType, size_t N>
+TrieType LoadTrieFromArchive(const TString& key,
+ const unsigned char (&data)[N],
+ bool ignoreErrors = false) {
+ TArchiveReader archive(TBlob::NoCopy(data, sizeof(data)));
+ if (archive.Has(key)) {
+ TAutoPtr<IInputStream> trie = archive.ObjectByKey(key);
+ return TrieType(TBlob::FromStream(*trie));
+ }
+ if (!ignoreErrors) {
+ ythrow yexception() << "Resource " << key << " not found";
+ }
+ return TrieType();
+}
diff --git a/library/cpp/containers/comptrie/loader/loader_ut.cpp b/library/cpp/containers/comptrie/loader/loader_ut.cpp
new file mode 100644
index 0000000000..345063a31e
--- /dev/null
+++ b/library/cpp/containers/comptrie/loader/loader_ut.cpp
@@ -0,0 +1,30 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/containers/comptrie/comptrie.h>
+#include <library/cpp/containers/comptrie/loader/loader.h>
+
+using TDummyTrie = TCompactTrie<char, i32>;
+
+namespace {
+ const unsigned char DATA[] = {
+#include "data.inc"
+ };
+}
+
+Y_UNIT_TEST_SUITE(ArchiveLoaderTests) {
+ Y_UNIT_TEST(BaseTest) {
+ TDummyTrie trie = LoadTrieFromArchive<TDummyTrie>("/dummy.trie", DATA, true);
+ UNIT_ASSERT_EQUAL(trie.Size(), 3);
+
+ const TString TrieKyes[3] = {
+ "zero", "one", "two"};
+ i32 val = -1;
+ for (i32 i = 0; i < 3; ++i) {
+ UNIT_ASSERT(trie.Find(TrieKyes[i].data(), TrieKyes[i].size(), &val));
+ UNIT_ASSERT_EQUAL(i, val);
+ }
+
+ UNIT_CHECK_GENERATED_EXCEPTION(
+ LoadTrieFromArchive<TDummyTrie>("/noname.trie", DATA),
+ yexception);
+ }
+}
diff --git a/library/cpp/containers/comptrie/loader/ut/dummy.trie b/library/cpp/containers/comptrie/loader/ut/dummy.trie
new file mode 100644
index 0000000000..4af18add2f
--- /dev/null
+++ b/library/cpp/containers/comptrie/loader/ut/dummy.trie
Binary files differ
diff --git a/library/cpp/containers/comptrie/loader/ut/ya.make b/library/cpp/containers/comptrie/loader/ut/ya.make
new file mode 100644
index 0000000000..6c0334d3ea
--- /dev/null
+++ b/library/cpp/containers/comptrie/loader/ut/ya.make
@@ -0,0 +1,18 @@
+UNITTEST_FOR(library/cpp/containers/comptrie/loader)
+
+OWNER(my34)
+
+ARCHIVE(
+ NAME data.inc
+ dummy.trie
+)
+
+SRCS(
+ loader_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/containers/comptrie/loader
+)
+
+END()
diff --git a/library/cpp/containers/comptrie/loader/ya.make b/library/cpp/containers/comptrie/loader/ya.make
new file mode 100644
index 0000000000..1e23e442a0
--- /dev/null
+++ b/library/cpp/containers/comptrie/loader/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(my34)
+
+SRCS(
+ loader.h
+ loader.cpp
+)
+
+PEERDIR(
+ library/cpp/archive
+ library/cpp/containers/comptrie
+)
+
+END()
diff --git a/library/cpp/containers/comptrie/make_fast_layout.cpp b/library/cpp/containers/comptrie/make_fast_layout.cpp
new file mode 100644
index 0000000000..ade78d7899
--- /dev/null
+++ b/library/cpp/containers/comptrie/make_fast_layout.cpp
@@ -0,0 +1,467 @@
+#include "make_fast_layout.h"
+#include "node.h"
+#include "writeable_node.h"
+#include "write_trie_backwards.h"
+#include "comptrie_impl.h"
+
+#include <util/generic/hash.h>
+#include <util/generic/utility.h>
+
+// Lay the trie in memory in such a way that there are less cache misses when jumping from root to leaf.
+// The trie becomes about 2% larger, but the access became about 25% faster in our experiments.
+// Can be called on minimized and non-minimized tries, in the first case in requires half a trie more memory.
+// Calling it the second time on the same trie does nothing.
+//
+// The algorithm is based on van Emde Boas layout as described in the yandex data school lectures on external memory algoritms
+// by Maxim Babenko and Ivan Puzyrevsky. The difference is that when we cut the tree into levels
+// two nodes connected by a forward link are put into the same level (because they usually lie near each other in the original tree).
+// The original paper (describing the layout in Section 2.1) is:
+// Michael A. Bender, Erik D. Demaine, Martin Farach-Colton. Cache-Oblivious B-Trees // SIAM Journal on Computing, volume 35, number 2, 2005, pages 341–358.
+// Available on the web: http://erikdemaine.org/papers/CacheObliviousBTrees_SICOMP/
+// Or: Michael A. Bender, Erik D. Demaine, and Martin Farach-Colton. Cache-Oblivious B-Trees // Proceedings of the 41st Annual Symposium
+// on Foundations of Computer Science (FOCS 2000), Redondo Beach, California, November 12–14, 2000, pages 399–409.
+// Available on the web: http://erikdemaine.org/papers/FOCS2000b/
+// (there is not much difference between these papers, actually).
+//
+namespace NCompactTrie {
+ static size_t FindSupportingPowerOf2(size_t n) {
+ size_t result = 1ull << (8 * sizeof(size_t) - 1);
+ while (result > n) {
+ result >>= 1;
+ }
+ return result;
+ }
+
+ namespace {
+ class TTrieNodeSet {
+ public:
+ TTrieNodeSet() = default;
+
+ explicit TTrieNodeSet(const TOpaqueTrie& trie)
+ : Body(trie.Length / (8 * MinNodeSize) + 1, 0)
+ {
+ }
+
+ bool Has(size_t offset) const {
+ const size_t reducedOffset = ReducedOffset(offset);
+ return OffsetCell(reducedOffset) & OffsetMask(reducedOffset);
+ }
+
+ void Add(size_t offset) {
+ const size_t reducedOffset = ReducedOffset(offset);
+ OffsetCell(reducedOffset) |= OffsetMask(reducedOffset);
+ }
+
+ void Remove(size_t offset) {
+ const size_t reducedOffset = ReducedOffset(offset);
+ OffsetCell(reducedOffset) &= ~OffsetMask(reducedOffset);
+ }
+
+ void Swap(TTrieNodeSet& other) {
+ Body.swap(other.Body);
+ }
+
+ private:
+ static const size_t MinNodeSize = 2;
+ TVector<ui8> Body;
+
+ static size_t ReducedOffset(size_t offset) {
+ return offset / MinNodeSize;
+ }
+ static ui8 OffsetMask(size_t reducedOffset) {
+ return 1 << (reducedOffset % 8);
+ }
+ ui8& OffsetCell(size_t reducedOffset) {
+ return Body.at(reducedOffset / 8);
+ }
+ const ui8& OffsetCell(size_t reducedOffset) const {
+ return Body.at(reducedOffset / 8);
+ }
+ };
+
+ //---------------------------------------------------------------------
+
+ class TTrieNodeCounts {
+ public:
+ TTrieNodeCounts() = default;
+
+ explicit TTrieNodeCounts(const TOpaqueTrie& trie)
+ : Body(trie.Length / MinNodeSize, 0)
+ , IsTree(false)
+ {
+ }
+
+ size_t Get(size_t offset) const {
+ return IsTree ? 1 : Body.at(offset / MinNodeSize);
+ }
+
+ void Inc(size_t offset) {
+ if (IsTree) {
+ return;
+ }
+ ui8& count = Body.at(offset / MinNodeSize);
+ if (count != MaxCount) {
+ ++count;
+ }
+ }
+
+ size_t Dec(size_t offset) {
+ if (IsTree) {
+ return 0;
+ }
+ ui8& count = Body.at(offset / MinNodeSize);
+ Y_ASSERT(count > 0);
+ if (count != MaxCount) {
+ --count;
+ }
+ return count;
+ }
+
+ void Swap(TTrieNodeCounts& other) {
+ Body.swap(other.Body);
+ ::DoSwap(IsTree, other.IsTree);
+ }
+
+ void SetTreeMode() {
+ IsTree = true;
+ Body = TVector<ui8>();
+ }
+
+ private:
+ static const size_t MinNodeSize = 2;
+ static const ui8 MaxCount = 255;
+
+ TVector<ui8> Body;
+ bool IsTree = false;
+ };
+
+ //----------------------------------------------------------
+
+ class TOffsetIndex {
+ public:
+ // In all methods:
+ // Key --- offset from the beginning of the old trie.
+ // Value --- offset from the end of the new trie.
+
+ explicit TOffsetIndex(TTrieNodeCounts& counts) {
+ ParentCounts.Swap(counts);
+ }
+
+ void Add(size_t key, size_t value) {
+ Data[key] = value;
+ }
+
+ size_t Size() const {
+ return Data.size();
+ }
+
+ size_t Get(size_t key) {
+ auto pos = Data.find(key);
+ if (pos == Data.end()) {
+ ythrow yexception() << "Bad node walking order: trying to get node offset too early or too many times!";
+ }
+ size_t result = pos->second;
+ if (ParentCounts.Dec(key) == 0) {
+ // We don't need this offset any more.
+ Data.erase(pos);
+ }
+ return result;
+ }
+
+ private:
+ TTrieNodeCounts ParentCounts;
+ THashMap<size_t, size_t> Data;
+ };
+
+ //---------------------------------------------------------------------------------------
+
+ class TTrieMeasurer {
+ public:
+ TTrieMeasurer(const TOpaqueTrie& trie, bool verbose);
+ void Measure();
+
+ size_t GetDepth() const {
+ return Depth;
+ }
+
+ size_t GetNodeCount() const {
+ return NodeCount;
+ }
+
+ size_t GetUnminimizedNodeCount() const {
+ return UnminimizedNodeCount;
+ }
+
+ bool IsTree() const {
+ return NodeCount == UnminimizedNodeCount;
+ }
+
+ TTrieNodeCounts& GetParentCounts() {
+ return ParentCounts;
+ }
+
+ const TOpaqueTrie& GetTrie() const {
+ return Trie;
+ }
+
+ private:
+ const TOpaqueTrie& Trie;
+ size_t Depth;
+ TTrieNodeCounts ParentCounts;
+ size_t NodeCount;
+ size_t UnminimizedNodeCount;
+ const bool Verbose;
+
+ // returns depth, increments NodeCount.
+ size_t MeasureSubtrie(size_t rootOffset, bool isNewPath);
+ };
+
+ TTrieMeasurer::TTrieMeasurer(const TOpaqueTrie& trie, bool verbose)
+ : Trie(trie)
+ , Depth(0)
+ , ParentCounts(trie)
+ , NodeCount(0)
+ , UnminimizedNodeCount(0)
+ , Verbose(verbose)
+ {
+ Y_ASSERT(Trie.Data);
+ }
+
+ void TTrieMeasurer::Measure() {
+ if (Verbose) {
+ Cerr << "Measuring the trie..." << Endl;
+ }
+ NodeCount = 0;
+ UnminimizedNodeCount = 0;
+ Depth = MeasureSubtrie(0, true);
+ if (IsTree()) {
+ ParentCounts.SetTreeMode();
+ }
+ if (Verbose) {
+ Cerr << "Unminimized node count: " << UnminimizedNodeCount << Endl;
+ Cerr << "Trie depth: " << Depth << Endl;
+ Cerr << "Node count: " << NodeCount << Endl;
+ }
+ }
+
+ // A chain of nodes linked by forward links
+ // is considered one node with many left and right children
+ // for depth measuring here and in
+ // TVanEmdeBoasReverseNodeEnumerator::FindDescendants.
+ size_t TTrieMeasurer::MeasureSubtrie(size_t rootOffset, bool isNewPath) {
+ Y_ASSERT(rootOffset < Trie.Length);
+ TNode node(Trie.Data, rootOffset, Trie.SkipFunction);
+ size_t depth = 0;
+ for (;;) {
+ ++UnminimizedNodeCount;
+ if (Verbose) {
+ ShowProgress(UnminimizedNodeCount);
+ }
+ if (isNewPath) {
+ if (ParentCounts.Get(node.GetOffset()) > 0) {
+ isNewPath = false;
+ } else {
+ ++NodeCount;
+ }
+ ParentCounts.Inc(node.GetOffset());
+ }
+ if (node.GetLeftOffset()) {
+ depth = Max(depth, 1 + MeasureSubtrie(node.GetLeftOffset(), isNewPath));
+ }
+ if (node.GetRightOffset()) {
+ depth = Max(depth, 1 + MeasureSubtrie(node.GetRightOffset(), isNewPath));
+ }
+ if (node.GetForwardOffset()) {
+ node = TNode(Trie.Data, node.GetForwardOffset(), Trie.SkipFunction);
+ } else {
+ break;
+ }
+ }
+ return depth;
+ }
+
+ //--------------------------------------------------------------------------------------
+
+ using TLevelNodes = TVector<size_t>;
+
+ struct TLevel {
+ size_t Depth;
+ TLevelNodes Nodes;
+
+ explicit TLevel(size_t depth)
+ : Depth(depth)
+ {
+ }
+ };
+
+ //----------------------------------------------------------------------------------------
+
+ class TVanEmdeBoasReverseNodeEnumerator: public TReverseNodeEnumerator {
+ public:
+ TVanEmdeBoasReverseNodeEnumerator(TTrieMeasurer& measurer, bool verbose)
+ : Fresh(true)
+ , Trie(measurer.GetTrie())
+ , Depth(measurer.GetDepth())
+ , MaxIndexSize(0)
+ , BackIndex(measurer.GetParentCounts())
+ , ProcessedNodes(measurer.GetTrie())
+ , Verbose(verbose)
+ {
+ }
+
+ bool Move() override {
+ if (!Fresh) {
+ CentralWord.pop_back();
+ }
+ if (CentralWord.empty()) {
+ return MoveCentralWordStart();
+ }
+ return true;
+ }
+
+ const TNode& Get() const {
+ return CentralWord.back();
+ }
+
+ size_t GetLeafLength() const override {
+ return Get().GetLeafLength();
+ }
+
+ // Returns recalculated offset from the end of the current node.
+ size_t PrepareOffset(size_t absoffset, size_t resultLength) {
+ if (!absoffset)
+ return NPOS;
+ return resultLength - BackIndex.Get(absoffset);
+ }
+
+ size_t RecreateNode(char* buffer, size_t resultLength) override {
+ TWriteableNode newNode(Get(), Trie.Data);
+ newNode.ForwardOffset = PrepareOffset(Get().GetForwardOffset(), resultLength);
+ newNode.LeftOffset = PrepareOffset(Get().GetLeftOffset(), resultLength);
+ newNode.RightOffset = PrepareOffset(Get().GetRightOffset(), resultLength);
+
+ const size_t len = newNode.Pack(buffer);
+ ProcessedNodes.Add(Get().GetOffset());
+ BackIndex.Add(Get().GetOffset(), resultLength + len);
+ MaxIndexSize = Max(MaxIndexSize, BackIndex.Size());
+ return len;
+ }
+
+ private:
+ bool Fresh;
+ TOpaqueTrie Trie;
+ size_t Depth;
+ size_t MaxIndexSize;
+
+ TVector<TLevel> Trace;
+ TOffsetIndex BackIndex;
+ TVector<TNode> CentralWord;
+ TTrieNodeSet ProcessedNodes;
+
+ const bool Verbose;
+
+ private:
+ bool IsVisited(size_t offset) const {
+ return ProcessedNodes.Has(offset);
+ }
+
+ void AddCascade(size_t step) {
+ Y_ASSERT(!(step & (step - 1))); // Should be a power of 2.
+ while (step > 0) {
+ size_t root = Trace.back().Nodes.back();
+ TLevel level(Trace.back().Depth + step);
+ Trace.push_back(level);
+ size_t actualStep = FindSupportingPowerOf2(FindDescendants(root, step, Trace.back().Nodes));
+ if (actualStep != step) {
+ // Retry with a smaller step.
+ Y_ASSERT(actualStep < step);
+ step = actualStep;
+ Trace.pop_back();
+ } else {
+ step /= 2;
+ }
+ }
+ }
+
+ void FillCentralWord() {
+ CentralWord.clear();
+ CentralWord.push_back(TNode(Trie.Data, Trace.back().Nodes.back(), Trie.SkipFunction));
+ // Do not check for epsilon links, as the traversal order now is different.
+ while (CentralWord.back().GetForwardOffset() && !IsVisited(CentralWord.back().GetForwardOffset())) {
+ CentralWord.push_back(TNode(Trie.Data, CentralWord.back().GetForwardOffset(), Trie.SkipFunction));
+ }
+ }
+
+ bool MoveCentralWordStart() {
+ do {
+ if (Fresh) {
+ TLevel root(0);
+ Trace.push_back(root);
+ Trace.back().Nodes.push_back(0);
+ const size_t sectionDepth = FindSupportingPowerOf2(Depth);
+ AddCascade(sectionDepth);
+ Fresh = false;
+ } else {
+ Trace.back().Nodes.pop_back();
+ if (Trace.back().Nodes.empty() && Trace.size() == 1) {
+ if (Verbose) {
+ Cerr << "Max index size: " << MaxIndexSize << Endl;
+ Cerr << "Current index size: " << BackIndex.Size() << Endl;
+ }
+ // We just popped the root.
+ return false;
+ }
+ size_t lastStep = Trace.back().Depth - Trace[Trace.size() - 2].Depth;
+ if (Trace.back().Nodes.empty()) {
+ Trace.pop_back();
+ }
+ AddCascade(lastStep / 2);
+ }
+ } while (IsVisited(Trace.back().Nodes.back()));
+ FillCentralWord();
+ return true;
+ }
+
+ // Returns the maximal depth it has reached while searching.
+ // This is a method because it needs OffsetIndex to skip processed nodes.
+ size_t FindDescendants(size_t rootOffset, size_t depth, TLevelNodes& result) const {
+ if (depth == 0) {
+ result.push_back(rootOffset);
+ return 0;
+ }
+ size_t actualDepth = 0;
+ TNode node(Trie.Data, rootOffset, Trie.SkipFunction);
+ for (;;) {
+ if (node.GetLeftOffset() && !IsVisited(node.GetLeftOffset())) {
+ actualDepth = Max(actualDepth,
+ 1 + FindDescendants(node.GetLeftOffset(), depth - 1, result));
+ }
+ if (node.GetRightOffset() && !IsVisited(node.GetRightOffset())) {
+ actualDepth = Max(actualDepth,
+ 1 + FindDescendants(node.GetRightOffset(), depth - 1, result));
+ }
+ if (node.GetForwardOffset() && !IsVisited(node.GetForwardOffset())) {
+ node = TNode(Trie.Data, node.GetForwardOffset(), Trie.SkipFunction);
+ } else {
+ break;
+ }
+ }
+ return actualDepth;
+ }
+ };
+
+ } // Anonymous namespace.
+
+ //-----------------------------------------------------------------------------------
+
+ size_t RawCompactTrieFastLayoutImpl(IOutputStream& os, const TOpaqueTrie& trie, bool verbose) {
+ if (!trie.Data || !trie.Length) {
+ return 0;
+ }
+ TTrieMeasurer mes(trie, verbose);
+ mes.Measure();
+ TVanEmdeBoasReverseNodeEnumerator enumerator(mes, verbose);
+ return WriteTrieBackwards(os, enumerator, verbose);
+ }
+
+}
diff --git a/library/cpp/containers/comptrie/make_fast_layout.h b/library/cpp/containers/comptrie/make_fast_layout.h
new file mode 100644
index 0000000000..b8fab5d65b
--- /dev/null
+++ b/library/cpp/containers/comptrie/make_fast_layout.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "leaf_skipper.h"
+#include <cstddef>
+
+class IOutputStream;
+
+namespace NCompactTrie {
+ // Return value: size of the resulting trie.
+ size_t RawCompactTrieFastLayoutImpl(IOutputStream& os, const NCompactTrie::TOpaqueTrie& trie, bool verbose);
+
+ // Return value: size of the resulting trie.
+ template <class TPacker>
+ size_t CompactTrieMakeFastLayoutImpl(IOutputStream& os, const char* data, size_t datalength, bool verbose, const TPacker* packer) {
+ TPackerLeafSkipper<TPacker> skipper(packer);
+ TOpaqueTrie trie(data, datalength, skipper);
+ return RawCompactTrieFastLayoutImpl(os, trie, verbose);
+ }
+
+}
diff --git a/library/cpp/containers/comptrie/minimize.cpp b/library/cpp/containers/comptrie/minimize.cpp
new file mode 100644
index 0000000000..80d0b25217
--- /dev/null
+++ b/library/cpp/containers/comptrie/minimize.cpp
@@ -0,0 +1,359 @@
+#include "minimize.h"
+#include "node.h"
+#include "writeable_node.h"
+#include "write_trie_backwards.h"
+#include "comptrie_impl.h"
+
+#include <util/generic/hash.h>
+#include <util/generic/algorithm.h>
+
+namespace NCompactTrie {
+ // Minimize the trie. The result is equivalent to the original
+ // trie, except that it takes less space (and has marginally lower
+ // performance, because of eventual epsilon links).
+ // The algorithm is as follows: starting from the largest pieces, we find
+ // nodes that have identical continuations (Daciuk's right language),
+ // and repack the trie. Repacking is done in-place, so memory is less
+ // of an issue; however, it may take considerable time.
+
+ // IMPORTANT: never try to reminimize an already minimized trie or a trie with fast layout.
+ // Because of non-local structure and epsilon links, it won't work
+ // as you expect it to, and can destroy the trie in the making.
+
+ namespace {
+ using TOffsetList = TVector<size_t>;
+ using TPieceIndex = THashMap<size_t, TOffsetList>;
+
+ using TSizePair = std::pair<size_t, size_t>;
+ using TSizePairVector = TVector<TSizePair>;
+ using TSizePairVectorVector = TVector<TSizePairVector>;
+
+ class TOffsetMap {
+ protected:
+ TSizePairVectorVector Data;
+
+ public:
+ TOffsetMap() {
+ Data.reserve(0x10000);
+ }
+
+ void Add(size_t key, size_t value) {
+ size_t hikey = key & 0xFFFF;
+
+ if (Data.size() <= hikey)
+ Data.resize(hikey + 1);
+
+ TSizePairVector& sublist = Data[hikey];
+
+ for (auto& it : sublist) {
+ if (it.first == key) {
+ it.second = value;
+
+ return;
+ }
+ }
+
+ sublist.push_back(TSizePair(key, value));
+ }
+
+ bool Contains(size_t key) const {
+ return (Get(key) != 0);
+ }
+
+ size_t Get(size_t key) const {
+ size_t hikey = key & 0xFFFF;
+
+ if (Data.size() <= hikey)
+ return 0;
+
+ const TSizePairVector& sublist = Data[hikey];
+
+ for (const auto& it : sublist) {
+ if (it.first == key)
+ return it.second;
+ }
+
+ return 0;
+ }
+ };
+
+ class TOffsetDeltas {
+ protected:
+ TSizePairVector Data;
+
+ public:
+ void Add(size_t key, size_t value) {
+ if (Data.empty()) {
+ if (key == value)
+ return; // no offset
+ } else {
+ TSizePair last = Data.back();
+
+ if (key <= last.first) {
+ Cerr << "Trouble: elements to offset delta list added in wrong order" << Endl;
+
+ return;
+ }
+
+ if (last.first + value == last.second + key)
+ return; // same offset
+ }
+
+ Data.push_back(TSizePair(key, value));
+ }
+
+ size_t Get(size_t key) const {
+ if (Data.empty())
+ return key; // difference is zero;
+
+ if (key < Data.front().first)
+ return key;
+
+ // Binary search for the highest entry in the list that does not exceed the key
+ size_t from = 0;
+ size_t to = Data.size() - 1;
+
+ while (from < to) {
+ size_t midpoint = (from + to + 1) / 2;
+
+ if (key < Data[midpoint].first)
+ to = midpoint - 1;
+ else
+ from = midpoint;
+ }
+
+ TSizePair entry = Data[from];
+
+ return key - entry.first + entry.second;
+ }
+ };
+
+ class TPieceComparer {
+ private:
+ const char* Data;
+ const size_t Length;
+
+ public:
+ TPieceComparer(const char* buf, size_t len)
+ : Data(buf)
+ , Length(len)
+ {
+ }
+
+ bool operator()(size_t p1, const size_t p2) {
+ int res = memcmp(Data + p1, Data + p2, Length);
+
+ if (res)
+ return (res > 0);
+
+ return (p1 > p2); // the pieces are sorted in the reverse order of appearance
+ }
+ };
+
+ struct TBranchPoint {
+ TNode Node;
+ int Selector;
+
+ public:
+ TBranchPoint()
+ : Selector(0)
+ {
+ }
+
+ TBranchPoint(const char* data, size_t offset, const ILeafSkipper& skipFunction)
+ : Node(data, offset, skipFunction)
+ , Selector(0)
+ {
+ }
+
+ bool IsFinal() const {
+ return Node.IsFinal();
+ }
+
+ // NextNode returns child nodes, starting from the last node: Right, then Left, then Forward
+ size_t NextNode(const TOffsetMap& mergedNodes) {
+ while (Selector < 3) {
+ size_t nextOffset = 0;
+
+ switch (++Selector) {
+ case 1:
+ if (Node.GetRightOffset())
+ nextOffset = Node.GetRightOffset();
+ break;
+
+ case 2:
+ if (Node.GetLeftOffset())
+ nextOffset = Node.GetLeftOffset();
+ break;
+
+ case 3:
+ if (Node.GetForwardOffset())
+ nextOffset = Node.GetForwardOffset();
+ break;
+
+ default:
+ break;
+ }
+
+ if (nextOffset && !mergedNodes.Contains(nextOffset))
+ return nextOffset;
+ }
+ return 0;
+ }
+ };
+
+ class TMergingReverseNodeEnumerator: public TReverseNodeEnumerator {
+ private:
+ bool Fresh;
+ TOpaqueTrie Trie;
+ const TOffsetMap& MergeMap;
+ TVector<TBranchPoint> Trace;
+ TOffsetDeltas OffsetIndex;
+
+ public:
+ TMergingReverseNodeEnumerator(const TOpaqueTrie& trie, const TOffsetMap& mergers)
+ : Fresh(true)
+ , Trie(trie)
+ , MergeMap(mergers)
+ {
+ }
+
+ bool Move() override {
+ if (Fresh) {
+ Trace.push_back(TBranchPoint(Trie.Data, 0, Trie.SkipFunction));
+ Fresh = false;
+ } else {
+ if (Trace.empty())
+ return false;
+
+ Trace.pop_back();
+
+ if (Trace.empty())
+ return false;
+ }
+
+ size_t nextnode = Trace.back().NextNode(MergeMap);
+
+ while (nextnode) {
+ Trace.push_back(TBranchPoint(Trie.Data, nextnode, Trie.SkipFunction));
+ nextnode = Trace.back().NextNode(MergeMap);
+ }
+
+ return (!Trace.empty());
+ }
+
+ const TNode& Get() const {
+ return Trace.back().Node;
+ }
+ size_t GetLeafLength() const override {
+ return Get().GetLeafLength();
+ }
+
+ // Returns recalculated offset from the end of the current node
+ size_t PrepareOffset(size_t absoffset, size_t minilength) {
+ if (!absoffset)
+ return NPOS;
+
+ if (MergeMap.Contains(absoffset))
+ absoffset = MergeMap.Get(absoffset);
+ return minilength - OffsetIndex.Get(Trie.Length - absoffset);
+ }
+
+ size_t RecreateNode(char* buffer, size_t resultLength) override {
+ TWriteableNode newNode(Get(), Trie.Data);
+ newNode.ForwardOffset = PrepareOffset(Get().GetForwardOffset(), resultLength);
+ newNode.LeftOffset = PrepareOffset(Get().GetLeftOffset(), resultLength);
+ newNode.RightOffset = PrepareOffset(Get().GetRightOffset(), resultLength);
+
+ if (!buffer)
+ return newNode.Measure();
+
+ const size_t len = newNode.Pack(buffer);
+ OffsetIndex.Add(Trie.Length - Get().GetOffset(), resultLength + len);
+
+ return len;
+ }
+ };
+
+ }
+
+ static void AddPiece(TPieceIndex& index, size_t offset, size_t len) {
+ index[len].push_back(offset);
+ }
+
+ static TOffsetMap FindEquivalentSubtries(const TOpaqueTrie& trie, bool verbose, size_t minMergeSize) {
+ // Tree nodes, arranged by span length.
+ // When all nodes of a given size are considered, they pop off the queue.
+ TPieceIndex subtries;
+ TOffsetMap merger;
+ // Start walking the trie from head.
+ AddPiece(subtries, 0, trie.Length);
+
+ size_t counter = 0;
+ // Now consider all nodes with sizeable continuations
+ for (size_t curlen = trie.Length; curlen >= minMergeSize && !subtries.empty(); curlen--) {
+ TPieceIndex::iterator iit = subtries.find(curlen);
+
+ if (iit == subtries.end())
+ continue; // fast forward to the next available length value
+
+ TOffsetList& batch = iit->second;
+ TPieceComparer comparer(trie.Data, curlen);
+ Sort(batch.begin(), batch.end(), comparer);
+
+ TOffsetList::iterator it = batch.begin();
+ while (it != batch.end()) {
+ if (verbose)
+ ShowProgress(++counter);
+
+ size_t offset = *it;
+
+ // Fill the array with the subnodes of the element
+ TNode node(trie.Data, offset, trie.SkipFunction);
+ size_t end = offset + curlen;
+ if (size_t rightOffset = node.GetRightOffset()) {
+ AddPiece(subtries, rightOffset, end - rightOffset);
+ end = rightOffset;
+ }
+ if (size_t leftOffset = node.GetLeftOffset()) {
+ AddPiece(subtries, leftOffset, end - leftOffset);
+ end = leftOffset;
+ }
+ if (size_t forwardOffset = node.GetForwardOffset()) {
+ AddPiece(subtries, forwardOffset, end - forwardOffset);
+ }
+
+ while (++it != batch.end()) {
+ // Find next different; until then, just add the offsets to the list of merged nodes.
+ size_t nextoffset = *it;
+
+ if (memcmp(trie.Data + offset, trie.Data + nextoffset, curlen))
+ break;
+
+ merger.Add(nextoffset, offset);
+ }
+ }
+
+ subtries.erase(curlen);
+ }
+ if (verbose) {
+ Cerr << counter << Endl;
+ }
+ return merger;
+ }
+
+ size_t RawCompactTrieMinimizeImpl(IOutputStream& os, TOpaqueTrie& trie, bool verbose, size_t minMergeSize, EMinimizeMode mode) {
+ if (!trie.Data || !trie.Length) {
+ return 0;
+ }
+
+ TOffsetMap merger = FindEquivalentSubtries(trie, verbose, minMergeSize);
+ TMergingReverseNodeEnumerator enumerator(trie, merger);
+
+ if (mode == MM_DEFAULT)
+ return WriteTrieBackwards(os, enumerator, verbose);
+ else
+ return WriteTrieBackwardsNoAlloc(os, enumerator, trie, mode);
+ }
+
+}
diff --git a/library/cpp/containers/comptrie/minimize.h b/library/cpp/containers/comptrie/minimize.h
new file mode 100644
index 0000000000..baaa431d04
--- /dev/null
+++ b/library/cpp/containers/comptrie/minimize.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "leaf_skipper.h"
+#include <cstddef>
+
+class IOutputStream;
+
+namespace NCompactTrie {
+ size_t MeasureOffset(size_t offset);
+
+ enum EMinimizeMode {
+ MM_DEFAULT, // alollocate new memory for minimized tree
+ MM_NOALLOC, // minimize tree in the same buffer
+ MM_INPLACE // do not write tree to the stream, but move to the buffer beginning
+ };
+
+ // Return value: size of the minimized trie.
+ size_t RawCompactTrieMinimizeImpl(IOutputStream& os, TOpaqueTrie& trie, bool verbose, size_t minMergeSize, EMinimizeMode mode);
+
+ // Return value: size of the minimized trie.
+ template <class TPacker>
+ size_t CompactTrieMinimizeImpl(IOutputStream& os, const char* data, size_t datalength, bool verbose, const TPacker* packer, EMinimizeMode mode) {
+ TPackerLeafSkipper<TPacker> skipper(packer);
+ size_t minmerge = MeasureOffset(datalength);
+ TOpaqueTrie trie(data, datalength, skipper);
+ return RawCompactTrieMinimizeImpl(os, trie, verbose, minmerge, mode);
+ }
+
+}
diff --git a/library/cpp/containers/comptrie/node.cpp b/library/cpp/containers/comptrie/node.cpp
new file mode 100644
index 0000000000..5fd22f15ec
--- /dev/null
+++ b/library/cpp/containers/comptrie/node.cpp
@@ -0,0 +1,79 @@
+#include "node.h"
+#include "leaf_skipper.h"
+#include "comptrie_impl.h"
+
+#include <util/system/yassert.h>
+#include <util/generic/yexception.h>
+
+namespace NCompactTrie {
+ TNode::TNode()
+ : Offset(0)
+ , LeafLength(0)
+ , CoreLength(0)
+ , Label(0)
+ {
+ for (auto& offset : Offsets) {
+ offset = 0;
+ }
+ }
+
+ // We believe that epsilon links are found only on the forward-position and that afer jumping an epsilon link you come to an ordinary node.
+
+ TNode::TNode(const char* data, size_t offset, const ILeafSkipper& skipFunction)
+ : Offset(offset)
+ , LeafLength(0)
+ , CoreLength(0)
+ , Label(0)
+ {
+ for (auto& anOffset : Offsets) {
+ anOffset = 0;
+ }
+ if (!data)
+ return; // empty constructor
+
+ const char* datapos = data + offset;
+ char flags = *(datapos++);
+ Y_ASSERT(!IsEpsilonLink(flags));
+ Label = *(datapos++);
+
+ size_t leftsize = LeftOffsetLen(flags);
+ size_t& leftOffset = Offsets[D_LEFT];
+ leftOffset = UnpackOffset(datapos, leftsize);
+ if (leftOffset) {
+ leftOffset += Offset;
+ }
+ datapos += leftsize;
+
+ size_t rightsize = RightOffsetLen(flags);
+ size_t& rightOffset = Offsets[D_RIGHT];
+ rightOffset = UnpackOffset(datapos, rightsize);
+ if (rightOffset) {
+ rightOffset += Offset;
+ }
+ datapos += rightsize;
+
+ if (flags & MT_FINAL) {
+ Offsets[D_FINAL] = datapos - data;
+ LeafLength = skipFunction.SkipLeaf(datapos);
+ }
+
+ CoreLength = 2 + leftsize + rightsize + LeafLength;
+ if (flags & MT_NEXT) {
+ size_t& forwardOffset = Offsets[D_NEXT];
+ forwardOffset = Offset + CoreLength;
+ // There might be an epsilon link at the forward position.
+ // If so, set the ForwardOffset to the value that points to the link's end.
+ const char* forwardPos = data + forwardOffset;
+ const char forwardFlags = *forwardPos;
+ if (IsEpsilonLink(forwardFlags)) {
+ // Jump through the epsilon link.
+ size_t epsilonOffset = UnpackOffset(forwardPos + 1, forwardFlags & MT_SIZEMASK);
+ if (!epsilonOffset) {
+ ythrow yexception() << "Corrupted epsilon link";
+ }
+ forwardOffset += epsilonOffset;
+ }
+ }
+ }
+
+}
diff --git a/library/cpp/containers/comptrie/node.h b/library/cpp/containers/comptrie/node.h
new file mode 100644
index 0000000000..d6f4317db0
--- /dev/null
+++ b/library/cpp/containers/comptrie/node.h
@@ -0,0 +1,80 @@
+#pragma once
+
+#include <cstddef>
+
+namespace NCompactTrie {
+ class ILeafSkipper;
+
+ enum TDirection {
+ D_LEFT,
+ D_FINAL,
+ D_NEXT,
+ D_RIGHT,
+ D_MAX
+ };
+
+ inline TDirection& operator++(TDirection& direction) {
+ direction = static_cast<TDirection>(direction + 1);
+ return direction;
+ }
+
+ inline TDirection& operator--(TDirection& direction) {
+ direction = static_cast<TDirection>(direction - 1);
+ return direction;
+ }
+
+ class TNode {
+ public:
+ TNode();
+ // Processes epsilon links and sets ForwardOffset to correct value. Assumes an epsilon link doesn't point to an epsilon link.
+ TNode(const char* data, size_t offset, const ILeafSkipper& skipFunction);
+
+ size_t GetOffset() const {
+ return Offset;
+ }
+
+ size_t GetLeafOffset() const {
+ return Offsets[D_FINAL];
+ }
+ size_t GetLeafLength() const {
+ return LeafLength;
+ }
+ size_t GetCoreLength() const {
+ return CoreLength;
+ }
+
+ size_t GetOffsetByDirection(TDirection direction) const {
+ return Offsets[direction];
+ }
+
+ size_t GetForwardOffset() const {
+ return Offsets[D_NEXT];
+ }
+ size_t GetLeftOffset() const {
+ return Offsets[D_LEFT];
+ }
+ size_t GetRightOffset() const {
+ return Offsets[D_RIGHT];
+ }
+ char GetLabel() const {
+ return Label;
+ }
+
+ bool IsFinal() const {
+ return GetLeafOffset() != 0;
+ }
+
+ bool HasEpsilonLinkForward() const {
+ return GetForwardOffset() > Offset + CoreLength;
+ }
+
+ private:
+ size_t Offsets[D_MAX];
+ size_t Offset;
+ size_t LeafLength;
+ size_t CoreLength;
+
+ char Label;
+ };
+
+}
diff --git a/library/cpp/containers/comptrie/opaque_trie_iterator.cpp b/library/cpp/containers/comptrie/opaque_trie_iterator.cpp
new file mode 100644
index 0000000000..5fd3914be6
--- /dev/null
+++ b/library/cpp/containers/comptrie/opaque_trie_iterator.cpp
@@ -0,0 +1,231 @@
+#include "opaque_trie_iterator.h"
+#include "comptrie_impl.h"
+#include "node.h"
+
+namespace NCompactTrie {
+ TOpaqueTrieIterator::TOpaqueTrieIterator(const TOpaqueTrie& trie, const char* emptyValue, bool atend,
+ size_t maxKeyLength)
+ : Trie(trie)
+ , EmptyValue(emptyValue)
+ , AtEmptyValue(emptyValue && !atend)
+ , MaxKeyLength(maxKeyLength)
+ {
+ if (!AtEmptyValue && !atend)
+ Forward();
+ }
+
+ bool TOpaqueTrieIterator::operator==(const TOpaqueTrieIterator& rhs) const {
+ return (Trie == rhs.Trie &&
+ Forks == rhs.Forks &&
+ EmptyValue == rhs.EmptyValue &&
+ AtEmptyValue == rhs.AtEmptyValue &&
+ MaxKeyLength == rhs.MaxKeyLength);
+ }
+
+ bool TOpaqueTrieIterator::HasMaxKeyLength() const {
+ return MaxKeyLength != size_t(-1) && MeasureNarrowKey() == MaxKeyLength;
+ }
+
+ bool TOpaqueTrieIterator::Forward() {
+ if (AtEmptyValue) {
+ AtEmptyValue = false;
+ bool res = Forward(); // TODO delete this after format change
+ if (res && MeasureNarrowKey() != 0) {
+ return res; // there was not "\0" key
+ }
+ // otherwise we are skipping "\0" key
+ }
+
+ if (!Trie.Length)
+ return false;
+
+ if (Forks.Empty()) {
+ TFork fork(Trie.Data, 0, Trie.Length, Trie.SkipFunction);
+ Forks.Push(fork);
+ } else {
+ TFork* topFork = &Forks.Top();
+ while (!topFork->NextDirection()) {
+ if (topFork->Node.GetOffset() >= Trie.Length)
+ return false;
+ Forks.Pop();
+ if (Forks.Empty())
+ return false;
+ topFork = &Forks.Top();
+ }
+ }
+
+ Y_ASSERT(!Forks.Empty());
+ while (Forks.Top().CurrentDirection != D_FINAL && !HasMaxKeyLength()) {
+ TFork nextFork = Forks.Top().NextFork(Trie.SkipFunction);
+ Forks.Push(nextFork);
+ }
+ TFork& top = Forks.Top();
+ static_assert(D_FINAL < D_NEXT, "relative order of NEXT and FINAL directions has changed");
+ if (HasMaxKeyLength() && top.CurrentDirection == D_FINAL && top.HasDirection(D_NEXT)) {
+ top.NextDirection();
+ }
+ return true;
+ }
+
+ bool TOpaqueTrieIterator::Backward() {
+ if (AtEmptyValue)
+ return false;
+
+ if (!Trie.Length) {
+ if (EmptyValue) {
+ // A trie that has only the empty value;
+ // we are not at the empty value, so move to it.
+ AtEmptyValue = true;
+ return true;
+ } else {
+ // Empty trie.
+ return false;
+ }
+ }
+
+ if (Forks.Empty()) {
+ TFork fork(Trie.Data, 0, Trie.Length, Trie.SkipFunction);
+ fork.LastDirection();
+ Forks.Push(fork);
+ } else {
+ TFork* topFork = &Forks.Top();
+ while (!topFork->PrevDirection()) {
+ if (topFork->Node.GetOffset() >= Trie.Length)
+ return false;
+ Forks.Pop();
+ if (!Forks.Empty()) {
+ topFork = &Forks.Top();
+ } else {
+ // When there are no more forks,
+ // we have to iterate over the empty value.
+ if (!EmptyValue)
+ return false;
+ AtEmptyValue = true;
+ return true;
+ }
+ }
+ }
+
+ Y_ASSERT(!Forks.Empty());
+ while (Forks.Top().CurrentDirection != D_FINAL && !HasMaxKeyLength()) {
+ TFork nextFork = Forks.Top().NextFork(Trie.SkipFunction);
+ nextFork.LastDirection();
+ Forks.Push(nextFork);
+ }
+ TFork& top = Forks.Top();
+ static_assert(D_FINAL < D_NEXT, "relative order of NEXT and FINAL directions has changed");
+ if (HasMaxKeyLength() && top.CurrentDirection == D_NEXT && top.HasDirection(D_FINAL)) {
+ top.PrevDirection();
+ }
+ if (MeasureNarrowKey() == 0) {
+ // This is the '\0' key, skip it and get to the EmptyValue.
+ AtEmptyValue = true;
+ Forks.Clear();
+ }
+ return true;
+ }
+
+ const char* TOpaqueTrieIterator::GetValuePtr() const {
+ if (!Forks.Empty()) {
+ const TFork& lastFork = Forks.Top();
+ Y_ASSERT(lastFork.Node.IsFinal() && lastFork.CurrentDirection == D_FINAL);
+ return Trie.Data + lastFork.GetValueOffset();
+ }
+ Y_ASSERT(AtEmptyValue);
+ return EmptyValue;
+ }
+
+ //-------------------------------------------------------------------------
+
+ TString TForkStack::GetKey() const {
+ if (HasEmptyKey()) {
+ return TString();
+ }
+
+ TString result(Key);
+ if (TopHasLabelInKey()) {
+ result.append(Top().GetLabel());
+ }
+ return result;
+ }
+
+ bool TForkStack::HasEmptyKey() const {
+ // Special case: if we get a single zero label, treat it as an empty key
+ // TODO delete this after format change
+ if (TopHasLabelInKey()) {
+ return Key.size() == 0 && Top().GetLabel() == '\0';
+ } else {
+ return Key.size() == 1 && Key[0] == '\0';
+ }
+ }
+
+ size_t TForkStack::MeasureKey() const {
+ size_t result = Key.size() + (TopHasLabelInKey() ? 1 : 0);
+ if (result == 1 && HasEmptyKey()) {
+ return 0;
+ }
+ return result;
+ }
+
+ //-------------------------------------------------------------------------
+
+ TFork::TFork(const char* data, size_t offset, size_t limit, const ILeafSkipper& skipper)
+ : Node(data, offset, skipper)
+ , Data(data)
+ , Limit(limit)
+ , CurrentDirection(TDirection(0))
+ {
+#if COMPTRIE_DATA_CHECK
+ if (Node.GetOffset() >= Limit - 1)
+ ythrow yexception() << "gone beyond the limit, data is corrupted";
+#endif
+ while (CurrentDirection < D_MAX && !HasDirection(CurrentDirection)) {
+ ++CurrentDirection;
+ }
+ }
+
+ bool TFork::operator==(const TFork& rhs) const {
+ return (Data == rhs.Data &&
+ Node.GetOffset() == rhs.Node.GetOffset() &&
+ CurrentDirection == rhs.CurrentDirection);
+ }
+
+ inline bool TFork::NextDirection() {
+ do {
+ ++CurrentDirection;
+ } while (CurrentDirection < D_MAX && !HasDirection(CurrentDirection));
+ return CurrentDirection < D_MAX;
+ }
+
+ inline bool TFork::PrevDirection() {
+ if (CurrentDirection == TDirection(0)) {
+ return false;
+ }
+ do {
+ --CurrentDirection;
+ } while (CurrentDirection > 0 && !HasDirection(CurrentDirection));
+ return HasDirection(CurrentDirection);
+ }
+
+ void TFork::LastDirection() {
+ CurrentDirection = D_MAX;
+ PrevDirection();
+ }
+
+ bool TFork::SetDirection(TDirection direction) {
+ if (!HasDirection(direction)) {
+ return false;
+ }
+ CurrentDirection = direction;
+ return true;
+ }
+
+ char TFork::GetLabel() const {
+ return Node.GetLabel();
+ }
+
+ size_t TFork::GetValueOffset() const {
+ return Node.GetLeafOffset();
+ }
+
+}
diff --git a/library/cpp/containers/comptrie/opaque_trie_iterator.h b/library/cpp/containers/comptrie/opaque_trie_iterator.h
new file mode 100644
index 0000000000..195da3c191
--- /dev/null
+++ b/library/cpp/containers/comptrie/opaque_trie_iterator.h
@@ -0,0 +1,266 @@
+#pragma once
+
+#include "comptrie_impl.h"
+#include "node.h"
+#include "key_selector.h"
+#include "leaf_skipper.h"
+
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+namespace NCompactTrie {
+ class ILeafSkipper;
+
+ class TFork { // Auxiliary class for a branching point in the iterator
+ public:
+ TNode Node;
+ const char* Data;
+ size_t Limit; // valid data is in range [Data + Node.GetOffset(), Data + Limit)
+ TDirection CurrentDirection;
+
+ public:
+ TFork(const char* data, size_t offset, size_t limit, const ILeafSkipper& skipper);
+
+ bool operator==(const TFork& rhs) const;
+
+ bool HasLabelInKey() const {
+ return CurrentDirection == D_NEXT || CurrentDirection == D_FINAL;
+ }
+
+ bool NextDirection();
+ bool PrevDirection();
+ void LastDirection();
+
+ bool HasDirection(TDirection direction) const {
+ return Node.GetOffsetByDirection(direction);
+ }
+ // If the fork doesn't have the specified direction,
+ // leaves the direction intact and returns false.
+ // Otherwise returns true.
+ bool SetDirection(TDirection direction);
+ TFork NextFork(const ILeafSkipper& skipper) const;
+
+ char GetLabel() const;
+ size_t GetValueOffset() const;
+ };
+
+ inline TFork TFork::NextFork(const ILeafSkipper& skipper) const {
+ Y_ASSERT(CurrentDirection != D_FINAL);
+ size_t offset = Node.GetOffsetByDirection(CurrentDirection);
+ return TFork(Data, offset, Limit, skipper);
+ }
+
+ //------------------------------------------------------------------------------------------------
+ class TForkStack {
+ public:
+ void Push(const TFork& fork) {
+ if (TopHasLabelInKey()) {
+ Key.push_back(Top().GetLabel());
+ }
+ Forks.push_back(fork);
+ }
+
+ void Pop() {
+ Forks.pop_back();
+ if (TopHasLabelInKey()) {
+ Key.pop_back();
+ }
+ }
+
+ TFork& Top() {
+ return Forks.back();
+ }
+ const TFork& Top() const {
+ return Forks.back();
+ }
+
+ bool Empty() const {
+ return Forks.empty();
+ }
+
+ void Clear() {
+ Forks.clear();
+ Key.clear();
+ }
+
+ bool operator==(const TForkStack& other) const {
+ return Forks == other.Forks;
+ }
+ bool operator!=(const TForkStack& other) const {
+ return !(*this == other);
+ }
+
+ TString GetKey() const;
+ size_t MeasureKey() const;
+
+ private:
+ TVector<TFork> Forks;
+ TString Key;
+
+ private:
+ bool TopHasLabelInKey() const {
+ return !Empty() && Top().HasLabelInKey();
+ }
+ bool HasEmptyKey() const;
+ };
+
+ //------------------------------------------------------------------------------------------------
+
+ template <class TSymbol>
+ struct TConvertRawKey {
+ typedef typename TCompactTrieKeySelector<TSymbol>::TKey TKey;
+ static TKey Get(const TString& rawkey) {
+ TKey result;
+ const size_t sz = rawkey.size();
+ result.reserve(sz / sizeof(TSymbol));
+ for (size_t i = 0; i < sz; i += sizeof(TSymbol)) {
+ TSymbol sym = 0;
+ for (size_t j = 0; j < sizeof(TSymbol); j++) {
+ if (sizeof(TSymbol) <= 1)
+ sym = 0;
+ else
+ sym <<= 8;
+ if (i + j < sz)
+ sym |= TSymbol(0x00FF & rawkey[i + j]);
+ }
+ result.push_back(sym);
+ }
+ return result;
+ }
+
+ static size_t Size(size_t rawsize) {
+ return rawsize / sizeof(TSymbol);
+ }
+ };
+
+ template <>
+ struct TConvertRawKey<char> {
+ static TString Get(const TString& rawkey) {
+ return rawkey;
+ }
+
+ static size_t Size(size_t rawsize) {
+ return rawsize;
+ }
+ };
+
+ //------------------------------------------------------------------------------------------------
+ class TOpaqueTrieIterator { // Iterator stuff. Stores a stack of visited forks.
+ public:
+ TOpaqueTrieIterator(const TOpaqueTrie& trie, const char* emptyValue, bool atend,
+ size_t maxKeyLength = size_t(-1));
+
+ bool operator==(const TOpaqueTrieIterator& rhs) const;
+ bool operator!=(const TOpaqueTrieIterator& rhs) const {
+ return !(*this == rhs);
+ }
+
+ bool Forward();
+ bool Backward();
+
+ template <class TSymbol>
+ bool UpperBound(const typename TCompactTrieKeySelector<TSymbol>::TKeyBuf& key); // True if matched exactly.
+
+ template <class TSymbol>
+ typename TCompactTrieKeySelector<TSymbol>::TKey GetKey() const {
+ return TConvertRawKey<TSymbol>::Get(GetNarrowKey());
+ }
+
+ template <class TSymbol>
+ size_t MeasureKey() const {
+ return TConvertRawKey<TSymbol>::Size(MeasureNarrowKey());
+ }
+
+ TString GetNarrowKey() const {
+ return Forks.GetKey();
+ }
+ size_t MeasureNarrowKey() const {
+ return Forks.MeasureKey();
+ }
+
+ const char* GetValuePtr() const; // 0 if none
+ const TNode& GetNode() const { // Could be called for non-empty key and not AtEnd.
+ return Forks.Top().Node;
+ }
+ const TOpaqueTrie& GetTrie() const {
+ return Trie;
+ }
+
+ private:
+ TOpaqueTrie Trie;
+ TForkStack Forks;
+ const char* const EmptyValue;
+ bool AtEmptyValue;
+ const size_t MaxKeyLength;
+
+ private:
+ bool HasMaxKeyLength() const;
+
+ template <class TSymbol>
+ int LongestPrefix(const typename TCompactTrieKeySelector<TSymbol>::TKeyBuf& key); // Used in UpperBound.
+ };
+
+ template <class TSymbol>
+ int TOpaqueTrieIterator::LongestPrefix(const typename TCompactTrieKeySelector<TSymbol>::TKeyBuf& key) {
+ Forks.Clear();
+ TFork next(Trie.Data, 0, Trie.Length, Trie.SkipFunction);
+ for (size_t i = 0; i < key.size(); i++) {
+ TSymbol symbol = key[i];
+ const bool isLastSymbol = (i + 1 == key.size());
+ for (i64 shift = (i64)NCompactTrie::ExtraBits<TSymbol>(); shift >= 0; shift -= 8) {
+ const unsigned char label = (unsigned char)(symbol >> shift);
+ const bool isLastByte = (isLastSymbol && shift == 0);
+ do {
+ Forks.Push(next);
+ TFork& top = Forks.Top();
+ if (label < (unsigned char)top.GetLabel()) {
+ if (!top.SetDirection(D_LEFT))
+ return 1;
+ } else if (label > (unsigned char)top.GetLabel()) {
+ if (!top.SetDirection(D_RIGHT)) {
+ Forks.Pop(); // We don't pass this fork on the way to the upper bound.
+ return -1;
+ }
+ } else if (isLastByte) { // Here and below label == top.GetLabel().
+ if (top.SetDirection(D_FINAL)) {
+ return 0; // Skip the NextFork() call at the end of the cycle.
+ } else {
+ top.SetDirection(D_NEXT);
+ return 1;
+ }
+ } else if (!top.SetDirection(D_NEXT)) {
+ top.SetDirection(D_FINAL);
+ return -1;
+ }
+ next = top.NextFork(Trie.SkipFunction);
+ } while (Forks.Top().CurrentDirection != D_NEXT); // Proceed to the next byte.
+ }
+ }
+ // We get here only if the key was empty.
+ Forks.Push(next);
+ return 1;
+ }
+
+ template <class TSymbol>
+ bool TOpaqueTrieIterator::UpperBound(const typename TCompactTrieKeySelector<TSymbol>::TKeyBuf& key) {
+ Forks.Clear();
+ if (key.empty() && EmptyValue) {
+ AtEmptyValue = true;
+ return true;
+ } else {
+ AtEmptyValue = false;
+ }
+ const int defect = LongestPrefix<TSymbol>(key);
+ if (defect > 0) {
+ // Continue the constructed forks with the smallest key possible.
+ while (Forks.Top().CurrentDirection != D_FINAL) {
+ TFork next = Forks.Top().NextFork(Trie.SkipFunction);
+ Forks.Push(next);
+ }
+ } else if (defect < 0) {
+ Forward();
+ }
+ return defect == 0;
+ }
+
+}
diff --git a/library/cpp/containers/comptrie/pattern_searcher.h b/library/cpp/containers/comptrie/pattern_searcher.h
new file mode 100644
index 0000000000..caab51dc1c
--- /dev/null
+++ b/library/cpp/containers/comptrie/pattern_searcher.h
@@ -0,0 +1,606 @@
+#pragma once
+
+#include "comptrie_builder.h"
+#include "comptrie_trie.h"
+#include "comptrie_impl.h"
+#include <library/cpp/packers/packers.h>
+
+#include <util/system/yassert.h>
+#include <util/generic/vector.h>
+#include <util/generic/deque.h>
+#include <util/stream/str.h>
+
+// Aho-Corasick algorithm implementation using CompactTrie implementation of Sedgewick's T-trie
+
+namespace NCompactTrie {
+ struct TSuffixLink {
+ ui64 NextSuffixOffset;
+ ui64 NextSuffixWithDataOffset;
+
+ TSuffixLink(ui64 nextSuffixOffset = 0, ui64 nextSuffixWithDataOffset = 0)
+ : NextSuffixOffset(nextSuffixOffset)
+ , NextSuffixWithDataOffset(nextSuffixWithDataOffset)
+ {
+ }
+ };
+
+ const size_t FLAGS_SIZE = sizeof(char);
+ const size_t SYMBOL_SIZE = sizeof(char);
+};
+
+template <class T = char, class D = ui64, class S = TCompactTriePacker<D>>
+class TCompactPatternSearcherBuilder : protected TCompactTrieBuilder<T, D, S> {
+public:
+ typedef T TSymbol;
+ typedef D TData;
+ typedef S TPacker;
+
+ typedef typename TCompactTrieKeySelector<TSymbol>::TKey TKey;
+ typedef typename TCompactTrieKeySelector<TSymbol>::TKeyBuf TKeyBuf;
+
+ typedef TCompactTrieBuilder<T, D, S> TBase;
+
+public:
+ TCompactPatternSearcherBuilder() {
+ TBase::Impl = MakeHolder<TCompactPatternSearcherBuilderImpl>();
+ }
+
+ bool Add(const TSymbol* key, size_t keyLength, const TData& value) {
+ return TBase::Impl->AddEntry(key, keyLength, value);
+ }
+ bool Add(const TKeyBuf& key, const TData& value) {
+ return Add(key.data(), key.size(), value);
+ }
+
+ bool Find(const TSymbol* key, size_t keyLength, TData* value) const {
+ return TBase::Impl->FindEntry(key, keyLength, value);
+ }
+ bool Find(const TKeyBuf& key, TData* value = nullptr) const {
+ return Find(key.data(), key.size(), value);
+ }
+
+ size_t Save(IOutputStream& os) const {
+ size_t trieSize = TBase::Impl->MeasureByteSize();
+ TBufferOutput serializedTrie(trieSize);
+ TBase::Impl->Save(serializedTrie);
+
+ auto serializedTrieBuffer = serializedTrie.Buffer();
+ CalculateSuffixLinks(
+ serializedTrieBuffer.Data(),
+ serializedTrieBuffer.Data() + serializedTrieBuffer.Size()
+ );
+
+ os.Write(serializedTrieBuffer.Data(), serializedTrieBuffer.Size());
+ return trieSize;
+ }
+
+ TBlob Save() const {
+ TBufferStream buffer;
+ Save(buffer);
+ return TBlob::FromStream(buffer);
+ }
+
+ size_t SaveToFile(const TString& fileName) const {
+ TFileOutput out(fileName);
+ return Save(out);
+ }
+
+ size_t MeasureByteSize() const {
+ return TBase::Impl->MeasureByteSize();
+ }
+
+private:
+ void CalculateSuffixLinks(char* trieStart, const char* trieEnd) const;
+
+protected:
+ class TCompactPatternSearcherBuilderImpl : public TBase::TCompactTrieBuilderImpl {
+ public:
+ typedef typename TBase::TCompactTrieBuilderImpl TImplBase;
+
+ TCompactPatternSearcherBuilderImpl(
+ TCompactTrieBuilderFlags flags = CTBF_NONE,
+ TPacker packer = TPacker(),
+ IAllocator* alloc = TDefaultAllocator::Instance()
+ ) : TImplBase(flags, packer, alloc) {
+ }
+
+ ui64 ArcMeasure(
+ const typename TImplBase::TArc* arc,
+ size_t leftSize,
+ size_t rightSize
+ ) const override {
+ using namespace NCompactTrie;
+
+ size_t coreSize = SYMBOL_SIZE + FLAGS_SIZE +
+ sizeof(TSuffixLink) +
+ this->NodeMeasureLeafValue(arc->Node);
+ size_t treeSize = this->NodeMeasureSubtree(arc->Node);
+
+ if (arc->Label.Length() > 0)
+ treeSize += (SYMBOL_SIZE + FLAGS_SIZE + sizeof(TSuffixLink)) *
+ (arc->Label.Length() - 1);
+
+ // Triple measurements are needed because the space needed to store the offset
+ // shall be added to the offset itself. Hence three iterations.
+ size_t leftOffsetSize = 0;
+ size_t rightOffsetSize = 0;
+ for (size_t iteration = 0; iteration < 3; ++iteration) {
+ leftOffsetSize = leftSize ? MeasureOffset(
+ coreSize + treeSize + leftOffsetSize + rightOffsetSize) : 0;
+ rightOffsetSize = rightSize ? MeasureOffset(
+ coreSize + treeSize + leftSize + leftOffsetSize + rightOffsetSize) : 0;
+ }
+
+ coreSize += leftOffsetSize + rightOffsetSize;
+ arc->LeftOffset = leftSize ? coreSize + treeSize : 0;
+ arc->RightOffset = rightSize ? coreSize + treeSize + leftSize : 0;
+
+ return coreSize + treeSize + leftSize + rightSize;
+ }
+
+ ui64 ArcSaveSelf(const typename TImplBase::TArc* arc, IOutputStream& os) const override {
+ using namespace NCompactTrie;
+
+ ui64 written = 0;
+
+ size_t leftOffsetSize = MeasureOffset(arc->LeftOffset);
+ size_t rightOffsetSize = MeasureOffset(arc->RightOffset);
+
+ size_t labelLen = arc->Label.Length();
+
+ for (size_t labelPos = 0; labelPos < labelLen; ++labelPos) {
+ char flags = 0;
+
+ if (labelPos == 0) {
+ flags |= (leftOffsetSize << MT_LEFTSHIFT);
+ flags |= (rightOffsetSize << MT_RIGHTSHIFT);
+ }
+
+ if (labelPos == labelLen - 1) {
+ if (arc->Node->IsFinal())
+ flags |= MT_FINAL;
+ if (!arc->Node->IsLast())
+ flags |= MT_NEXT;
+ } else {
+ flags |= MT_NEXT;
+ }
+
+ os.Write(&flags, 1);
+ os.Write(&arc->Label.AsCharPtr()[labelPos], 1);
+ written += 2;
+
+ TSuffixLink suffixlink;
+ os.Write(&suffixlink, sizeof(TSuffixLink));
+ written += sizeof(TSuffixLink);
+
+ if (labelPos == 0) {
+ written += ArcSaveOffset(arc->LeftOffset, os);
+ written += ArcSaveOffset(arc->RightOffset, os);
+ }
+ }
+
+ written += this->NodeSaveLeafValue(arc->Node, os);
+ return written;
+ }
+ };
+};
+
+
+template <class T>
+struct TPatternMatch {
+ ui64 End;
+ T Data;
+
+ TPatternMatch(ui64 end, const T& data)
+ : End(end)
+ , Data(data)
+ {
+ }
+};
+
+
+template <class T = char, class D = ui64, class S = TCompactTriePacker<D>>
+class TCompactPatternSearcher {
+public:
+ typedef T TSymbol;
+ typedef D TData;
+ typedef S TPacker;
+
+ typedef typename TCompactTrieKeySelector<TSymbol>::TKey TKey;
+ typedef typename TCompactTrieKeySelector<TSymbol>::TKeyBuf TKeyBuf;
+
+ typedef TCompactTrie<TSymbol, TData, TPacker> TTrie;
+public:
+ TCompactPatternSearcher()
+ {
+ }
+
+ explicit TCompactPatternSearcher(const TBlob& data)
+ : Trie(data)
+ {
+ }
+
+ TCompactPatternSearcher(const char* data, size_t size)
+ : Trie(data, size)
+ {
+ }
+
+ TVector<TPatternMatch<TData>> SearchMatches(const TSymbol* text, size_t textSize) const;
+ TVector<TPatternMatch<TData>> SearchMatches(const TKeyBuf& text) const {
+ return SearchMatches(text.data(), text.size());
+ }
+private:
+ TTrie Trie;
+};
+
+////////////////////
+// Implementation //
+////////////////////
+
+namespace {
+
+template <class TData, class TPacker>
+char ReadNode(
+ char* nodeStart,
+ char*& leftSibling,
+ char*& rightSibling,
+ char*& directChild,
+ NCompactTrie::TSuffixLink*& suffixLink,
+ TPacker packer = TPacker()
+) {
+ char* dataPos = nodeStart;
+ char flags = *(dataPos++);
+
+ Y_ASSERT(!NCompactTrie::IsEpsilonLink(flags)); // Epsilon links are not allowed
+
+ char label = *(dataPos++);
+
+ suffixLink = (NCompactTrie::TSuffixLink*)dataPos;
+ dataPos += sizeof(NCompactTrie::TSuffixLink);
+
+ { // Left branch
+ size_t offsetLength = NCompactTrie::LeftOffsetLen(flags);
+ size_t leftOffset = NCompactTrie::UnpackOffset(dataPos, offsetLength);
+ leftSibling = leftOffset ? (nodeStart + leftOffset) : nullptr;
+
+ dataPos += offsetLength;
+ }
+
+
+ { // Right branch
+ size_t offsetLength = NCompactTrie::RightOffsetLen(flags);
+ size_t rightOffset = NCompactTrie::UnpackOffset(dataPos, offsetLength);
+ rightSibling = rightOffset ? (nodeStart + rightOffset) : nullptr;
+
+ dataPos += offsetLength;
+ }
+
+ directChild = nullptr;
+ if (flags & NCompactTrie::MT_NEXT) {
+ directChild = dataPos;
+ if (flags & NCompactTrie::MT_FINAL) {
+ directChild += packer.SkipLeaf(directChild);
+ }
+ }
+
+ return label;
+}
+
+template <class TData, class TPacker>
+char ReadNodeConst(
+ const char* nodeStart,
+ const char*& leftSibling,
+ const char*& rightSibling,
+ const char*& directChild,
+ const char*& data,
+ NCompactTrie::TSuffixLink& suffixLink,
+ TPacker packer = TPacker()
+) {
+ const char* dataPos = nodeStart;
+ char flags = *(dataPos++);
+
+ Y_ASSERT(!NCompactTrie::IsEpsilonLink(flags)); // Epsilon links are not allowed
+
+ char label = *(dataPos++);
+
+ suffixLink = *((NCompactTrie::TSuffixLink*)dataPos);
+ dataPos += sizeof(NCompactTrie::TSuffixLink);
+
+ { // Left branch
+ size_t offsetLength = NCompactTrie::LeftOffsetLen(flags);
+ size_t leftOffset = NCompactTrie::UnpackOffset(dataPos, offsetLength);
+ leftSibling = leftOffset ? (nodeStart + leftOffset) : nullptr;
+
+ dataPos += offsetLength;
+ }
+
+
+ { // Right branch
+ size_t offsetLength = NCompactTrie::RightOffsetLen(flags);
+ size_t rightOffset = NCompactTrie::UnpackOffset(dataPos, offsetLength);
+ rightSibling = rightOffset ? (nodeStart + rightOffset) : nullptr;
+
+ dataPos += offsetLength;
+ }
+
+ data = nullptr;
+ if (flags & NCompactTrie::MT_FINAL) {
+ data = dataPos;
+ }
+ directChild = nullptr;
+ if (flags & NCompactTrie::MT_NEXT) {
+ directChild = dataPos;
+ if (flags & NCompactTrie::MT_FINAL) {
+ directChild += packer.SkipLeaf(directChild);
+ }
+ }
+
+ return label;
+}
+
+Y_FORCE_INLINE bool Advance(
+ const char*& dataPos,
+ const char* const dataEnd,
+ char label
+) {
+ if (dataPos == nullptr) {
+ return false;
+ }
+
+ while (dataPos < dataEnd) {
+ size_t offsetLength, offset;
+ const char* startPos = dataPos;
+ char flags = *(dataPos++);
+ char symbol = *(dataPos++);
+ dataPos += sizeof(NCompactTrie::TSuffixLink);
+
+ // Left branch
+ offsetLength = NCompactTrie::LeftOffsetLen(flags);
+ if ((unsigned char)label < (unsigned char)symbol) {
+ offset = NCompactTrie::UnpackOffset(dataPos, offsetLength);
+ if (!offset)
+ break;
+
+ dataPos = startPos + offset;
+ continue;
+ }
+
+ dataPos += offsetLength;
+
+ // Right branch
+ offsetLength = NCompactTrie::RightOffsetLen(flags);
+ if ((unsigned char)label > (unsigned char)symbol) {
+ offset = NCompactTrie::UnpackOffset(dataPos, offsetLength);
+ if (!offset)
+ break;
+
+ dataPos = startPos + offset;
+ continue;
+ }
+
+ dataPos = startPos;
+ return true;
+ }
+
+ // if we got here, we're past the dataend - bail out ASAP
+ dataPos = nullptr;
+ return false;
+}
+
+} // anonymous
+
+template <class T, class D, class S>
+void TCompactPatternSearcherBuilder<T, D, S>::CalculateSuffixLinks(
+ char* trieStart,
+ const char* trieEnd
+) const {
+ struct TBfsElement {
+ char* Node;
+ const char* Parent;
+
+ TBfsElement(char* node, const char* parent)
+ : Node(node)
+ , Parent(parent)
+ {
+ }
+ };
+
+ TDeque<TBfsElement> bfsQueue;
+ if (trieStart && trieStart != trieEnd) {
+ bfsQueue.emplace_back(trieStart, nullptr);
+ }
+
+ while (!bfsQueue.empty()) {
+ auto front = bfsQueue.front();
+ char* node = front.Node;
+ const char* parent = front.Parent;
+ bfsQueue.pop_front();
+
+ char* leftSibling;
+ char* rightSibling;
+ char* directChild;
+ NCompactTrie::TSuffixLink* suffixLink;
+
+ char label = ReadNode<TData, TPacker>(
+ node,
+ leftSibling,
+ rightSibling,
+ directChild,
+ suffixLink
+ );
+
+ const char* suffix;
+
+ if (parent == nullptr) {
+ suffix = node;
+ } else {
+ const char* parentOfSuffix = parent;
+ const char* temp;
+ do {
+ NCompactTrie::TSuffixLink parentOfSuffixSuffixLink;
+
+ ReadNodeConst<TData, TPacker>(
+ parentOfSuffix,
+ /*left*/temp,
+ /*right*/temp,
+ /*direct*/temp,
+ /*data*/temp,
+ parentOfSuffixSuffixLink
+ );
+ if (parentOfSuffixSuffixLink.NextSuffixOffset == 0) {
+ suffix = trieStart;
+ if (!Advance(suffix, trieEnd, label)) {
+ suffix = node;
+ }
+ break;
+ }
+ parentOfSuffix += parentOfSuffixSuffixLink.NextSuffixOffset;
+
+ NCompactTrie::TSuffixLink tempSuffixLink;
+ ReadNodeConst<TData, TPacker>(
+ parentOfSuffix,
+ /*left*/temp,
+ /*right*/temp,
+ /*direct*/suffix,
+ /*data*/temp,
+ tempSuffixLink
+ );
+
+ if (suffix == nullptr) {
+ continue;
+ }
+ } while (!Advance(suffix, trieEnd, label));
+ }
+
+ suffixLink->NextSuffixOffset = suffix - node;
+
+ NCompactTrie::TSuffixLink suffixSuffixLink;
+ const char* suffixData;
+ const char* temp;
+ ReadNodeConst<TData, TPacker>(
+ suffix,
+ /*left*/temp,
+ /*right*/temp,
+ /*direct*/temp,
+ suffixData,
+ suffixSuffixLink
+ );
+ suffixLink->NextSuffixWithDataOffset = suffix - node;
+ if (suffixData == nullptr) {
+ suffixLink->NextSuffixWithDataOffset += suffixSuffixLink.NextSuffixWithDataOffset;
+ }
+
+ if (directChild) {
+ bfsQueue.emplace_back(directChild, node);
+ }
+
+ if (leftSibling) {
+ bfsQueue.emplace_front(leftSibling, parent);
+ }
+
+ if (rightSibling) {
+ bfsQueue.emplace_front(rightSibling, parent);
+ }
+ }
+}
+
+
+template<class T, class D, class S>
+TVector<TPatternMatch<D>> TCompactPatternSearcher<T, D, S>::SearchMatches(
+ const TSymbol* text,
+ size_t textSize
+) const {
+ const char* temp;
+ NCompactTrie::TSuffixLink tempSuffixLink;
+
+ const auto& trieData = Trie.Data();
+ const char* trieStart = trieData.AsCharPtr();
+ size_t dataSize = trieData.Length();
+ const char* trieEnd = trieStart + dataSize;
+
+ const char* lastNode = nullptr;
+ const char* currentSubtree = trieStart;
+
+ TVector<TPatternMatch<TData>> matches;
+
+ for (const TSymbol* position = text; position < text + textSize; ++position) {
+ TSymbol symbol = *position;
+ for (i64 i = (i64)NCompactTrie::ExtraBits<TSymbol>(); i >= 0; i -= 8) {
+ char label = (char)(symbol >> i);
+
+ // Find first suffix extendable by label
+ while (true) {
+ const char* nextLastNode = currentSubtree;
+ if (Advance(nextLastNode, trieEnd, label)) {
+ lastNode = nextLastNode;
+ ReadNodeConst<TData, TPacker>(
+ lastNode,
+ /*left*/temp,
+ /*right*/temp,
+ currentSubtree,
+ /*data*/temp,
+ tempSuffixLink
+ );
+ break;
+ } else {
+ if (lastNode == nullptr) {
+ break;
+ }
+ }
+
+ NCompactTrie::TSuffixLink suffixLink;
+ ReadNodeConst<TData, TPacker>(
+ lastNode,
+ /*left*/temp,
+ /*right*/temp,
+ /*direct*/temp,
+ /*data*/temp,
+ suffixLink
+ );
+ if (suffixLink.NextSuffixOffset == 0) {
+ lastNode = nullptr;
+ currentSubtree = trieStart;
+ continue;
+ }
+ lastNode += suffixLink.NextSuffixOffset;
+ ReadNodeConst<TData, TPacker>(
+ lastNode,
+ /*left*/temp,
+ /*right*/temp,
+ currentSubtree,
+ /*data*/temp,
+ tempSuffixLink
+ );
+ }
+
+ // Iterate through all suffixes
+ const char* suffix = lastNode;
+ while (suffix != nullptr) {
+ const char* nodeData;
+ NCompactTrie::TSuffixLink suffixLink;
+ ReadNodeConst<TData, TPacker>(
+ suffix,
+ /*left*/temp,
+ /*right*/temp,
+ /*direct*/temp,
+ nodeData,
+ suffixLink
+ );
+ if (nodeData != nullptr) {
+ TData data;
+ Trie.GetPacker().UnpackLeaf(nodeData, data);
+ matches.emplace_back(
+ position - text,
+ data
+ );
+ }
+ if (suffixLink.NextSuffixOffset == 0) {
+ break;
+ }
+ suffix += suffixLink.NextSuffixWithDataOffset;
+ }
+ }
+ }
+
+ return matches;
+}
diff --git a/library/cpp/containers/comptrie/prefix_iterator.cpp b/library/cpp/containers/comptrie/prefix_iterator.cpp
new file mode 100644
index 0000000000..5d4dfa3500
--- /dev/null
+++ b/library/cpp/containers/comptrie/prefix_iterator.cpp
@@ -0,0 +1 @@
+#include "prefix_iterator.h"
diff --git a/library/cpp/containers/comptrie/prefix_iterator.h b/library/cpp/containers/comptrie/prefix_iterator.h
new file mode 100644
index 0000000000..b369bb4f42
--- /dev/null
+++ b/library/cpp/containers/comptrie/prefix_iterator.h
@@ -0,0 +1,88 @@
+#pragma once
+
+#include "comptrie_trie.h"
+
+// Iterates over all prefixes of the given key in the trie.
+template <class TTrie>
+class TPrefixIterator {
+public:
+ using TSymbol = typename TTrie::TSymbol;
+ using TPacker = typename TTrie::TPacker;
+ using TData = typename TTrie::TData;
+
+private:
+ const TTrie& Trie;
+ const TSymbol* key;
+ size_t keylen;
+ const TSymbol* keyend;
+ size_t prefixLen;
+ const char* valuepos;
+ const char* datapos;
+ const char* dataend;
+ TPacker Packer;
+ const char* EmptyValue;
+ bool result;
+
+ bool Next();
+
+public:
+ TPrefixIterator(const TTrie& trie, const TSymbol* aKey, size_t aKeylen)
+ : Trie(trie)
+ , key(aKey)
+ , keylen(aKeylen)
+ , keyend(aKey + aKeylen)
+ , prefixLen(0)
+ , valuepos(nullptr)
+ , datapos(trie.DataHolder.AsCharPtr())
+ , dataend(datapos + trie.DataHolder.Length())
+ {
+ result = Next();
+ }
+
+ operator bool() const {
+ return result;
+ }
+
+ TPrefixIterator& operator++() {
+ result = Next();
+ return *this;
+ }
+
+ size_t GetPrefixLen() const {
+ return prefixLen;
+ }
+
+ void GetValue(TData& to) const {
+ Trie.Packer.UnpackLeaf(valuepos, to);
+ }
+};
+
+template <class TTrie>
+bool TPrefixIterator<TTrie>::Next() {
+ using namespace NCompactTrie;
+ if (!key || datapos == dataend)
+ return false;
+
+ if ((key == keyend - keylen) && !valuepos && Trie.EmptyValue) {
+ valuepos = Trie.EmptyValue;
+ return true;
+ }
+
+ while (datapos && key != keyend) {
+ TSymbol label = *(key++);
+ if (!Advance(datapos, dataend, valuepos, label, Packer)) {
+ return false;
+ }
+ if (valuepos) { // There is a value at the end of this symbol.
+ prefixLen = keylen - (keyend - key);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+template <class TTrie>
+TPrefixIterator<TTrie> MakePrefixIterator(const TTrie& trie, const typename TTrie::TSymbol* key, size_t keylen) {
+ return TPrefixIterator<TTrie>(trie, key, keylen);
+}
diff --git a/library/cpp/containers/comptrie/protopacker.h b/library/cpp/containers/comptrie/protopacker.h
new file mode 100644
index 0000000000..3e15866dc5
--- /dev/null
+++ b/library/cpp/containers/comptrie/protopacker.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <util/stream/mem.h>
+#include <util/ysaveload.h>
+
+template <class Proto>
+class TProtoPacker {
+public:
+ TProtoPacker() = default;
+
+ void UnpackLeaf(const char* p, Proto& entry) const {
+ TMemoryInput in(p + sizeof(ui32), SkipLeaf(p) - sizeof(ui32));
+ entry.ParseFromArcadiaStream(&in);
+ }
+ void PackLeaf(char* p, const Proto& entry, size_t size) const {
+ TMemoryOutput out(p, size + sizeof(ui32));
+ Save<ui32>(&out, size);
+ entry.SerializeToArcadiaStream(&out);
+ }
+ size_t MeasureLeaf(const Proto& entry) const {
+ return entry.ByteSize() + sizeof(ui32);
+ }
+ size_t SkipLeaf(const char* p) const {
+ TMemoryInput in(p, sizeof(ui32));
+ ui32 size;
+ Load<ui32>(&in, size);
+ return size;
+ }
+};
diff --git a/library/cpp/containers/comptrie/search_iterator.cpp b/library/cpp/containers/comptrie/search_iterator.cpp
new file mode 100644
index 0000000000..eb91523574
--- /dev/null
+++ b/library/cpp/containers/comptrie/search_iterator.cpp
@@ -0,0 +1 @@
+#include "search_iterator.h"
diff --git a/library/cpp/containers/comptrie/search_iterator.h b/library/cpp/containers/comptrie/search_iterator.h
new file mode 100644
index 0000000000..247f7e5936
--- /dev/null
+++ b/library/cpp/containers/comptrie/search_iterator.h
@@ -0,0 +1,140 @@
+#pragma once
+
+#include "comptrie_trie.h"
+#include "first_symbol_iterator.h"
+
+#include <util/str_stl.h>
+#include <util/digest/numeric.h>
+#include <util/digest/multi.h>
+
+// Iterator for incremental searching.
+// All Advance() methods shift the iterator using specifed key/char.
+// The subsequent Advance() call starts searching from the previous state.
+// The Advance() returns 'true' if specified key part exists in the trie and
+// returns 'false' for unsuccessful search. In case of 'false' result
+// all subsequent calls also will return 'false'.
+// If current iterator state is final then GetValue() method returns 'true' and
+// associated value.
+
+template <class TTrie>
+class TSearchIterator {
+public:
+ using TData = typename TTrie::TData;
+ using TSymbol = typename TTrie::TSymbol;
+ using TKeyBuf = typename TTrie::TKeyBuf;
+
+ TSearchIterator() = default;
+
+ explicit TSearchIterator(const TTrie& trie)
+ : Trie(&trie)
+ , DataPos(trie.DataHolder.AsCharPtr())
+ , DataEnd(DataPos + trie.DataHolder.Length())
+ , ValuePos(trie.EmptyValue)
+ {
+ }
+
+ explicit TSearchIterator(const TTrie& trie, const TTrie& subTrie)
+ : Trie(&trie)
+ , DataPos(subTrie.Data().AsCharPtr())
+ , DataEnd(trie.DataHolder.AsCharPtr() + trie.DataHolder.Length())
+ , ValuePos(subTrie.EmptyValue)
+ {
+ }
+
+ bool operator==(const TSearchIterator& other) const {
+ Y_ASSERT(Trie && other.Trie);
+ return Trie == other.Trie &&
+ DataPos == other.DataPos &&
+ DataEnd == other.DataEnd &&
+ ValuePos == other.ValuePos;
+ }
+ bool operator!=(const TSearchIterator& other) const {
+ return !(*this == other);
+ }
+
+ inline bool Advance(TSymbol label) {
+ Y_ASSERT(Trie);
+ if (DataPos == nullptr || DataPos >= DataEnd) {
+ return false;
+ }
+ return NCompactTrie::Advance(DataPos, DataEnd, ValuePos, label, Trie->Packer);
+ }
+ inline bool Advance(const TKeyBuf& key) {
+ return Advance(key.data(), key.size());
+ }
+ bool Advance(const TSymbol* key, size_t keylen);
+ bool GetValue(TData* value = nullptr) const;
+ bool HasValue() const;
+ inline size_t GetHash() const;
+
+private:
+ const TTrie* Trie = nullptr;
+ const char* DataPos = nullptr;
+ const char* DataEnd = nullptr;
+ const char* ValuePos = nullptr;
+};
+
+template <class TTrie>
+inline TSearchIterator<TTrie> MakeSearchIterator(const TTrie& trie) {
+ return TSearchIterator<TTrie>(trie);
+}
+
+template <class TTrie>
+struct THash<TSearchIterator<TTrie>> {
+ inline size_t operator()(const TSearchIterator<TTrie>& item) {
+ return item.GetHash();
+ }
+};
+
+//----------------------------------------------------------------------------
+
+template <class TTrie>
+bool TSearchIterator<TTrie>::Advance(const TSymbol* key, size_t keylen) {
+ Y_ASSERT(Trie);
+ if (!key || DataPos == nullptr || DataPos >= DataEnd) {
+ return false;
+ }
+ if (!keylen) {
+ return true;
+ }
+
+ const TSymbol* keyend = key + keylen;
+ while (key != keyend && DataPos != nullptr) {
+ if (!NCompactTrie::Advance(DataPos, DataEnd, ValuePos, *(key++), Trie->Packer)) {
+ return false;
+ }
+ if (key == keyend) {
+ return true;
+ }
+ }
+ return false;
+}
+
+template <class TTrie>
+bool TSearchIterator<TTrie>::GetValue(TData* value) const {
+ Y_ASSERT(Trie);
+ bool result = false;
+ if (value) {
+ if (ValuePos) {
+ result = true;
+ Trie->Packer.UnpackLeaf(ValuePos, *value);
+ }
+ }
+ return result;
+}
+
+template <class TTrie>
+bool TSearchIterator<TTrie>::HasValue() const {
+ Y_ASSERT(Trie);
+ return ValuePos;
+}
+
+template <class TTrie>
+inline size_t TSearchIterator<TTrie>::GetHash() const {
+ Y_ASSERT(Trie);
+ return MultiHash(
+ static_cast<const void*>(Trie),
+ static_cast<const void*>(DataPos),
+ static_cast<const void*>(DataEnd),
+ static_cast<const void*>(ValuePos));
+}
diff --git a/library/cpp/containers/comptrie/set.h b/library/cpp/containers/comptrie/set.h
new file mode 100644
index 0000000000..acd43338f0
--- /dev/null
+++ b/library/cpp/containers/comptrie/set.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "comptrie_trie.h"
+
+template <typename T = char>
+class TCompactTrieSet: public TCompactTrie<T, ui8, TNullPacker<ui8>> {
+public:
+ typedef TCompactTrie<T, ui8, TNullPacker<ui8>> TBase;
+
+ using typename TBase::TBuilder;
+ using typename TBase::TKey;
+ using typename TBase::TKeyBuf;
+ using typename TBase::TSymbol;
+
+ TCompactTrieSet() = default;
+
+ explicit TCompactTrieSet(const TBlob& data)
+ : TBase(data)
+ {
+ }
+
+ template <typename D>
+ explicit TCompactTrieSet(const TCompactTrie<T, D, TNullPacker<D>>& trie)
+ : TBase(trie.Data()) // should be binary compatible for any D
+ {
+ }
+
+ TCompactTrieSet(const char* data, size_t len)
+ : TBase(data, len)
+ {
+ }
+
+ bool Has(const typename TBase::TKeyBuf& key) const {
+ return TBase::Find(key.data(), key.size());
+ }
+
+ bool FindTails(const typename TBase::TKeyBuf& key, TCompactTrieSet<T>& res) const {
+ return TBase::FindTails(key, res);
+ }
+};
diff --git a/library/cpp/containers/comptrie/ut/ya.make b/library/cpp/containers/comptrie/ut/ya.make
new file mode 100644
index 0000000000..c4f4666009
--- /dev/null
+++ b/library/cpp/containers/comptrie/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/containers/comptrie)
+
+OWNER(alzobnin)
+
+SRCS(
+ comptrie_ut.cpp
+)
+
+END()
diff --git a/library/cpp/containers/comptrie/write_trie_backwards.cpp b/library/cpp/containers/comptrie/write_trie_backwards.cpp
new file mode 100644
index 0000000000..fd8c28b0ed
--- /dev/null
+++ b/library/cpp/containers/comptrie/write_trie_backwards.cpp
@@ -0,0 +1,110 @@
+#include "write_trie_backwards.h"
+
+#include "comptrie_impl.h"
+#include "leaf_skipper.h"
+
+#include <util/generic/buffer.h>
+#include <util/generic/vector.h>
+
+namespace NCompactTrie {
+ size_t WriteTrieBackwards(IOutputStream& os, TReverseNodeEnumerator& enumerator, bool verbose) {
+ if (verbose) {
+ Cerr << "Writing down the trie..." << Endl;
+ }
+
+ // Rewrite everything from the back, removing unused pieces.
+ const size_t chunksize = 0x10000;
+ TVector<char*> resultData;
+
+ resultData.push_back(new char[chunksize]);
+ char* chunkend = resultData.back() + chunksize;
+
+ size_t resultLength = 0;
+ size_t chunkLength = 0;
+
+ size_t counter = 0;
+ TBuffer bufferHolder;
+ while (enumerator.Move()) {
+ if (verbose)
+ ShowProgress(++counter);
+
+ size_t bufferLength = 64 + enumerator.GetLeafLength(); // never know how big leaf data can be
+ bufferHolder.Clear();
+ bufferHolder.Resize(bufferLength);
+ char* buffer = bufferHolder.Data();
+
+ size_t nodelength = enumerator.RecreateNode(buffer, resultLength);
+ Y_ASSERT(nodelength <= bufferLength);
+
+ resultLength += nodelength;
+
+ if (chunkLength + nodelength <= chunksize) {
+ chunkLength += nodelength;
+ memcpy(chunkend - chunkLength, buffer, nodelength);
+ } else { // allocate a new chunk
+ memcpy(chunkend - chunksize, buffer + nodelength - (chunksize - chunkLength), chunksize - chunkLength);
+ chunkLength = chunkLength + nodelength - chunksize;
+
+ resultData.push_back(new char[chunksize]);
+ chunkend = resultData.back() + chunksize;
+
+ while (chunkLength > chunksize) { // allocate a new chunks
+ chunkLength -= chunksize;
+ memcpy(chunkend - chunksize, buffer + chunkLength, chunksize);
+
+ resultData.push_back(new char[chunksize]);
+ chunkend = resultData.back() + chunksize;
+ }
+
+ memcpy(chunkend - chunkLength, buffer, chunkLength);
+ }
+ }
+
+ if (verbose)
+ Cerr << counter << Endl;
+
+ // Write the whole thing down
+ while (!resultData.empty()) {
+ char* chunk = resultData.back();
+ os.Write(chunk + chunksize - chunkLength, chunkLength);
+ chunkLength = chunksize;
+ delete[] chunk;
+ resultData.pop_back();
+ }
+
+ return resultLength;
+ }
+
+ size_t WriteTrieBackwardsNoAlloc(IOutputStream& os, TReverseNodeEnumerator& enumerator, TOpaqueTrie& trie, EMinimizeMode mode) {
+ char* data = const_cast<char*>(trie.Data);
+ char* end = data + trie.Length;
+ char* pos = end;
+
+ TVector<char> buf(64);
+ while (enumerator.Move()) {
+ size_t nodeLength = enumerator.RecreateNode(nullptr, end - pos);
+ if (nodeLength > buf.size())
+ buf.resize(nodeLength);
+
+ size_t realLength = enumerator.RecreateNode(buf.data(), end - pos);
+ Y_ASSERT(realLength == nodeLength);
+
+ pos -= nodeLength;
+ memcpy(pos, buf.data(), nodeLength);
+ }
+
+ switch (mode) {
+ case MM_NOALLOC:
+ os.Write(pos, end - pos);
+ break;
+ case MM_INPLACE:
+ memmove(data, pos, end - pos);
+ break;
+ default:
+ Y_VERIFY(false);
+ }
+
+ return end - pos;
+ }
+
+}
diff --git a/library/cpp/containers/comptrie/write_trie_backwards.h b/library/cpp/containers/comptrie/write_trie_backwards.h
new file mode 100644
index 0000000000..634e6b811a
--- /dev/null
+++ b/library/cpp/containers/comptrie/write_trie_backwards.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "minimize.h"
+
+#include <util/generic/vector.h>
+#include <util/stream/output.h>
+#include <cstddef>
+
+namespace NCompactTrie {
+ class TReverseNodeEnumerator {
+ public:
+ virtual ~TReverseNodeEnumerator() = default;
+ virtual bool Move() = 0;
+ virtual size_t GetLeafLength() const = 0;
+ virtual size_t RecreateNode(char* buffer, size_t resultLength) = 0;
+ };
+
+ struct TOpaqueTrie;
+
+ size_t WriteTrieBackwards(IOutputStream& os, TReverseNodeEnumerator& enumerator, bool verbose);
+ size_t WriteTrieBackwardsNoAlloc(IOutputStream& os, TReverseNodeEnumerator& enumerator, TOpaqueTrie& trie, EMinimizeMode mode);
+
+}
diff --git a/library/cpp/containers/comptrie/writeable_node.cpp b/library/cpp/containers/comptrie/writeable_node.cpp
new file mode 100644
index 0000000000..404003dbbd
--- /dev/null
+++ b/library/cpp/containers/comptrie/writeable_node.cpp
@@ -0,0 +1,96 @@
+#include "writeable_node.h"
+#include "node.h"
+#include "comptrie_impl.h"
+
+namespace NCompactTrie {
+ TWriteableNode::TWriteableNode()
+ : LeafPos(nullptr)
+ , LeafLength(0)
+ , ForwardOffset(NPOS)
+ , LeftOffset(NPOS)
+ , RightOffset(NPOS)
+ , Label(0)
+ {
+ }
+
+ static size_t GetOffsetFromEnd(const TNode& node, size_t absOffset) {
+ return absOffset ? absOffset - node.GetOffset() - node.GetCoreLength() : NPOS;
+ }
+
+ TWriteableNode::TWriteableNode(const TNode& node, const char* data)
+ : LeafPos(node.IsFinal() ? data + node.GetLeafOffset() : nullptr)
+ , LeafLength(node.GetLeafLength())
+ , ForwardOffset(GetOffsetFromEnd(node, node.GetForwardOffset()))
+ , LeftOffset(GetOffsetFromEnd(node, node.GetLeftOffset()))
+ , RightOffset(GetOffsetFromEnd(node, node.GetRightOffset()))
+ , Label(node.GetLabel())
+ {
+ }
+
+ size_t TWriteableNode::Measure() const {
+ size_t len = 2 + LeafLength;
+ size_t fwdLen = 0;
+ size_t lastLen = 0;
+ size_t lastFwdLen = 0;
+ // Now, increase all the offsets by the length and recalculate everything, until it converges
+ do {
+ lastLen = len;
+ lastFwdLen = fwdLen;
+
+ len = 2 + LeafLength;
+ len += MeasureOffset(LeftOffset != NPOS ? LeftOffset + lastLen : 0);
+ len += MeasureOffset(RightOffset != NPOS ? RightOffset + lastLen : 0);
+
+ // Relative forward offset of 0 means we don't need extra length for an epsilon link.
+ // But an epsilon link means we need an extra 1 for the flags and the forward offset is measured
+ // from the start of the epsilon link, not from the start of our node.
+ if (ForwardOffset != NPOS && ForwardOffset != 0) {
+ fwdLen = MeasureOffset(ForwardOffset + lastFwdLen) + 1;
+ len += fwdLen;
+ }
+
+ } while (lastLen != len || lastFwdLen != fwdLen);
+
+ return len;
+ }
+
+ size_t TWriteableNode::Pack(char* buffer) const {
+ const size_t length = Measure();
+
+ char flags = 0;
+ if (LeafPos) {
+ flags |= MT_FINAL;
+ }
+ if (ForwardOffset != NPOS) {
+ flags |= MT_NEXT;
+ }
+
+ const size_t leftOffset = LeftOffset != NPOS ? LeftOffset + length : 0;
+ const size_t rightOffset = RightOffset != NPOS ? RightOffset + length : 0;
+ const size_t leftOffsetSize = MeasureOffset(leftOffset);
+ const size_t rightOffsetSize = MeasureOffset(rightOffset);
+ flags |= (leftOffsetSize << MT_LEFTSHIFT);
+ flags |= (rightOffsetSize << MT_RIGHTSHIFT);
+
+ buffer[0] = flags;
+ buffer[1] = Label;
+ size_t usedLen = 2;
+ usedLen += PackOffset(buffer + usedLen, leftOffset);
+ usedLen += PackOffset(buffer + usedLen, rightOffset);
+
+ if (LeafPos && LeafLength) {
+ memcpy(buffer + usedLen, LeafPos, LeafLength);
+ usedLen += LeafLength;
+ }
+
+ if (ForwardOffset != NPOS && ForwardOffset != 0) {
+ const size_t fwdOffset = ForwardOffset + length - usedLen;
+ size_t fwdOffsetSize = MeasureOffset(fwdOffset);
+ buffer[usedLen++] = (char)(fwdOffsetSize & MT_SIZEMASK);
+ usedLen += PackOffset(buffer + usedLen, fwdOffset);
+ }
+ Y_ASSERT(usedLen == length);
+ return usedLen;
+ }
+
+}
diff --git a/library/cpp/containers/comptrie/writeable_node.h b/library/cpp/containers/comptrie/writeable_node.h
new file mode 100644
index 0000000000..5454e579ef
--- /dev/null
+++ b/library/cpp/containers/comptrie/writeable_node.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <cstddef>
+
+namespace NCompactTrie {
+ class TNode;
+
+ class TWriteableNode {
+ public:
+ const char* LeafPos;
+ size_t LeafLength;
+
+ size_t ForwardOffset;
+ size_t LeftOffset;
+ size_t RightOffset;
+ char Label;
+
+ TWriteableNode();
+ TWriteableNode(const TNode& node, const char* data);
+
+ // When you call this, the offsets should be relative to the end of the node. Use NPOS to indicate an absent offset.
+ size_t Pack(char* buffer) const;
+ size_t Measure() const;
+ };
+
+}
diff --git a/library/cpp/containers/comptrie/ya.make b/library/cpp/containers/comptrie/ya.make
new file mode 100644
index 0000000000..81352da4b2
--- /dev/null
+++ b/library/cpp/containers/comptrie/ya.make
@@ -0,0 +1,35 @@
+LIBRARY()
+
+OWNER(velavokr)
+
+SRCS(
+ array_with_size.h
+ chunked_helpers_trie.h
+ comptrie.h
+ comptrie_packer.h
+ comptrie_trie.h
+ first_symbol_iterator.h
+ key_selector.h
+ leaf_skipper.h
+ set.h
+ comptrie.cpp
+ comptrie_builder.cpp
+ comptrie_impl.cpp
+ make_fast_layout.cpp
+ minimize.cpp
+ node.cpp
+ opaque_trie_iterator.cpp
+ prefix_iterator.cpp
+ search_iterator.cpp
+ write_trie_backwards.cpp
+ writeable_node.cpp
+)
+
+PEERDIR(
+ library/cpp/packers
+ library/cpp/containers/compact_vector
+ library/cpp/on_disk/chunks
+ util/draft
+)
+
+END()
diff --git a/library/cpp/containers/disjoint_interval_tree/disjoint_interval_tree.cpp b/library/cpp/containers/disjoint_interval_tree/disjoint_interval_tree.cpp
new file mode 100644
index 0000000000..7334a43c36
--- /dev/null
+++ b/library/cpp/containers/disjoint_interval_tree/disjoint_interval_tree.cpp
@@ -0,0 +1 @@
+#include "disjoint_interval_tree.h"
diff --git a/library/cpp/containers/disjoint_interval_tree/disjoint_interval_tree.h b/library/cpp/containers/disjoint_interval_tree/disjoint_interval_tree.h
new file mode 100644
index 0000000000..1f899c9991
--- /dev/null
+++ b/library/cpp/containers/disjoint_interval_tree/disjoint_interval_tree.h
@@ -0,0 +1,272 @@
+#pragma once
+
+#include <util/generic/map.h>
+#include <util/system/yassert.h>
+
+#include <type_traits>
+
+template <class T>
+class TDisjointIntervalTree {
+private:
+ static_assert(std::is_integral<T>::value, "expect std::is_integral<T>::value");
+
+ using TTree = TMap<T, T>; // [key, value)
+ using TIterator = typename TTree::iterator;
+ using TConstIterator = typename TTree::const_iterator;
+ using TReverseIterator = typename TTree::reverse_iterator;
+ using TThis = TDisjointIntervalTree<T>;
+
+ TTree Tree;
+ size_t NumElements;
+
+public:
+ TDisjointIntervalTree()
+ : NumElements()
+ {
+ }
+
+ void Insert(const T t) {
+ InsertInterval(t, t + 1);
+ }
+
+ // we assume that none of elements from [begin, end) belong to tree.
+ void InsertInterval(const T begin, const T end) {
+ InsertIntervalImpl(begin, end);
+ NumElements += (size_t)(end - begin);
+ }
+
+ bool Has(const T t) const {
+ return const_cast<TThis*>(this)->FindContaining(t) != Tree.end();
+ }
+
+ bool Intersects(const T begin, const T end) {
+ if (Empty()) {
+ return false;
+ }
+
+ TIterator l = Tree.lower_bound(begin);
+ if (l != Tree.end()) {
+ if (l->first < end) {
+ return true;
+ } else if (l != Tree.begin()) {
+ --l;
+ return l->second > begin;
+ } else {
+ return false;
+ }
+ } else {
+ auto last = Tree.rbegin();
+ return begin < last->second;
+ }
+ }
+
+ TConstIterator FindContaining(const T t) const {
+ return const_cast<TThis*>(this)->FindContaining(t);
+ }
+
+ // Erase element. Returns true when element has been deleted, otherwise false.
+ bool Erase(const T t) {
+ TIterator n = FindContaining(t);
+ if (n == Tree.end()) {
+ return false;
+ }
+
+ --NumElements;
+
+ T& begin = const_cast<T&>(n->first);
+ T& end = const_cast<T&>(n->second);
+
+ // Optimization hack.
+ if (t == begin) {
+ if (++begin == end) { // OK to change key since intervals do not intersect.
+ Tree.erase(n);
+ return true;
+ }
+
+ } else if (t == end - 1) {
+ --end;
+
+ } else {
+ const T e = end;
+ end = t;
+ InsertIntervalImpl(t + 1, e);
+ }
+
+ Y_ASSERT(begin < end);
+ return true;
+ }
+
+ // Erase interval. Returns number of elements removed from set.
+ size_t EraseInterval(const T begin, const T end) {
+ Y_ASSERT(begin < end);
+
+ if (Empty()) {
+ return 0;
+ }
+
+ size_t elementsRemoved = 0;
+
+ TIterator completelyRemoveBegin = Tree.lower_bound(begin);
+ if ((completelyRemoveBegin != Tree.end() && completelyRemoveBegin->first > begin && completelyRemoveBegin != Tree.begin())
+ || completelyRemoveBegin == Tree.end()) {
+ // Look at the interval. It could contain [begin, end).
+ TIterator containingBegin = completelyRemoveBegin;
+ --containingBegin;
+ if (containingBegin->first < begin && begin < containingBegin->second) { // Contains begin.
+ if (containingBegin->second > end) { // Contains end.
+ const T prevEnd = containingBegin->second;
+ Y_ASSERT(containingBegin->second - begin <= NumElements);
+
+ Y_ASSERT(containingBegin->second - containingBegin->first > end - begin);
+ containingBegin->second = begin;
+ InsertIntervalImpl(end, prevEnd);
+
+ elementsRemoved = end - begin;
+ NumElements -= elementsRemoved;
+ return elementsRemoved;
+ } else {
+ elementsRemoved += containingBegin->second - begin;
+ containingBegin->second = begin;
+ }
+ }
+ }
+
+ TIterator completelyRemoveEnd = completelyRemoveBegin != Tree.end() ? Tree.lower_bound(end) : Tree.end();
+ if (completelyRemoveEnd != Tree.end() && completelyRemoveEnd != Tree.begin() && completelyRemoveEnd->first != end) {
+ TIterator containingEnd = completelyRemoveEnd;
+ --containingEnd;
+ if (containingEnd->second > end) {
+ T& leftBorder = const_cast<T&>(containingEnd->first);
+
+ Y_ASSERT(leftBorder < end);
+
+ --completelyRemoveEnd; // Don't remove the whole interval.
+
+ // Optimization hack.
+ elementsRemoved += end - leftBorder;
+ leftBorder = end; // OK to change key since intervals do not intersect.
+ }
+ }
+
+ for (TIterator i = completelyRemoveBegin; i != completelyRemoveEnd; ++i) {
+ elementsRemoved += i->second - i->first;
+ }
+
+ Tree.erase(completelyRemoveBegin, completelyRemoveEnd);
+
+ Y_ASSERT(elementsRemoved <= NumElements);
+ NumElements -= elementsRemoved;
+
+ return elementsRemoved;
+ }
+
+ void Swap(TDisjointIntervalTree& rhv) {
+ Tree.swap(rhv.Tree);
+ std::swap(NumElements, rhv.NumElements);
+ }
+
+ void Clear() {
+ Tree.clear();
+ NumElements = 0;
+ }
+
+ bool Empty() const {
+ return Tree.empty();
+ }
+
+ size_t GetNumElements() const {
+ return NumElements;
+ }
+
+ size_t GetNumIntervals() const {
+ return Tree.size();
+ }
+
+ T Min() const {
+ Y_ASSERT(!Empty());
+ return Tree.begin()->first;
+ }
+
+ T Max() const {
+ Y_ASSERT(!Empty());
+ return Tree.rbegin()->second;
+ }
+
+ TConstIterator begin() const {
+ return Tree.begin();
+ }
+
+ TConstIterator end() const {
+ return Tree.end();
+ }
+
+private:
+ void InsertIntervalImpl(const T begin, const T end) {
+ Y_ASSERT(begin < end);
+ Y_ASSERT(!Intersects(begin, end));
+
+ TIterator l = Tree.lower_bound(begin);
+ TIterator p = Tree.end();
+ if (l != Tree.begin()) {
+ p = l;
+ --p;
+ }
+
+#ifndef NDEBUG
+ TIterator u = Tree.upper_bound(begin);
+ Y_VERIFY_DEBUG(u == Tree.end() || u->first >= end, "Trying to add [%" PRIu64 ", %" PRIu64 ") which intersects with existing [%" PRIu64 ", %" PRIu64 ")", begin, end, u->first, u->second);
+ Y_VERIFY_DEBUG(l == Tree.end() || l == u, "Trying to add [%" PRIu64 ", %" PRIu64 ") which intersects with existing [%" PRIu64 ", %" PRIu64 ")", begin, end, l->first, l->second);
+ Y_VERIFY_DEBUG(p == Tree.end() || p->second <= begin, "Trying to add [%" PRIu64 ", %" PRIu64 ") which intersects with existing [%" PRIu64 ", %" PRIu64 ")", begin, end, p->first, p->second);
+#endif
+
+ // try to extend interval
+ if (p != Tree.end() && p->second == begin) {
+ p->second = end;
+ //Try to merge 2 intervals - p and next one if possible
+ auto next = p;
+ // Next is not Tree.end() here.
+ ++next;
+ if (next != Tree.end() && next->first == end) {
+ p->second = next->second;
+ Tree.erase(next);
+ }
+ // Maybe new interval extends right interval
+ } else if (l != Tree.end() && end == l->first) {
+ T& leftBorder = const_cast<T&>(l->first);
+ // Optimization hack.
+ leftBorder = begin; // OK to change key since intervals do not intersect.
+ } else {
+ Tree.insert(std::make_pair(begin, end));
+ }
+ }
+
+ TIterator FindContaining(const T t) {
+ TIterator l = Tree.lower_bound(t);
+ if (l != Tree.end()) {
+ if (l->first == t) {
+ return l;
+ }
+ Y_ASSERT(l->first > t);
+
+ if (l == Tree.begin()) {
+ return Tree.end();
+ }
+
+ --l;
+ Y_ASSERT(l->first != t);
+
+ if (l->first < t && t < l->second) {
+ return l;
+ }
+
+ } else if (!Tree.empty()) { // l is larger than Begin of any interval, but maybe it belongs to last interval?
+ TReverseIterator last = Tree.rbegin();
+ Y_ASSERT(last->first != t);
+
+ if (last->first < t && t < last->second) {
+ return (++last).base();
+ }
+ }
+ return Tree.end();
+ }
+};
diff --git a/library/cpp/containers/disjoint_interval_tree/ut/disjoint_interval_tree_ut.cpp b/library/cpp/containers/disjoint_interval_tree/ut/disjoint_interval_tree_ut.cpp
new file mode 100644
index 0000000000..8474ae89b0
--- /dev/null
+++ b/library/cpp/containers/disjoint_interval_tree/ut/disjoint_interval_tree_ut.cpp
@@ -0,0 +1,279 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/containers/disjoint_interval_tree/disjoint_interval_tree.h>
+
+Y_UNIT_TEST_SUITE(DisjointIntervalTreeTest) {
+ Y_UNIT_TEST(GenericTest) {
+ TDisjointIntervalTree<ui64> tree;
+ tree.Insert(1);
+ tree.Insert(50);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 2);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 2);
+
+ tree.InsertInterval(10, 30);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 3);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 22);
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.Min(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(tree.Max(), 51);
+
+ tree.Erase(20);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 4);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 21);
+
+ tree.Clear();
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 0);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 0);
+ }
+
+ Y_UNIT_TEST(MergeIntervalsTest) {
+ TDisjointIntervalTree<ui64> tree;
+ tree.Insert(5);
+
+ // Insert interval from right side.
+ tree.Insert(6);
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 2);
+
+ {
+ auto begin = tree.begin();
+ UNIT_ASSERT_VALUES_EQUAL(begin->first, 5);
+ UNIT_ASSERT_VALUES_EQUAL(begin->second, 7);
+
+ ++begin;
+ UNIT_ASSERT_EQUAL(begin, tree.end());
+ }
+
+ // Insert interval from left side.
+ tree.InsertInterval(2, 5);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 5);
+
+ {
+ auto begin = tree.begin();
+ UNIT_ASSERT_VALUES_EQUAL(begin->first, 2);
+ UNIT_ASSERT_VALUES_EQUAL(begin->second, 7);
+ }
+
+ // Merge all intervals.
+ {
+ TDisjointIntervalTree<ui64> tree;
+ tree.InsertInterval(0, 3);
+ tree.InsertInterval(6, 10);
+ tree.InsertInterval(3, 6);
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 10);
+
+ auto begin = tree.begin();
+ UNIT_ASSERT_VALUES_EQUAL(begin->first, 0);
+ UNIT_ASSERT_VALUES_EQUAL(begin->second, 10);
+ }
+
+ }
+
+ Y_UNIT_TEST(EraseIntervalTest) {
+ // 1. Remove from empty tree.
+ {
+ TDisjointIntervalTree<ui64> tree;
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.EraseInterval(1, 3), 0);
+ }
+
+ // 2. No such interval in set.
+ {
+ TDisjointIntervalTree<ui64> tree;
+ tree.InsertInterval(5, 10);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 5);
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.EraseInterval(1, 3), 0);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 5);
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.EraseInterval(20, 30), 0);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 5);
+ }
+
+ // 3. Remove the whole tree.
+ {
+ TDisjointIntervalTree<ui64> tree;
+ tree.InsertInterval(5, 10);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 5);
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.EraseInterval(0, 100), 5);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 0);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 0);
+ UNIT_ASSERT(tree.Empty());
+ }
+
+ // 4. Remove the whole tree with borders specified exactly as in tree.
+ {
+ TDisjointIntervalTree<ui64> tree;
+ tree.InsertInterval(5, 10);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 5);
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.EraseInterval(5, 10), 5);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 0);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 0);
+ UNIT_ASSERT(tree.Empty());
+ }
+
+ // 5. Specify left border exactly as in existing interval.
+ {
+ TDisjointIntervalTree<ui64> tree;
+ tree.InsertInterval(5, 10);
+ tree.InsertInterval(15, 20);
+ tree.InsertInterval(25, 30);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 3);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 15);
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.EraseInterval(15, 100500), 10);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 5);
+ }
+
+ // 6. Specify left border somewhere in existing interval.
+ {
+ TDisjointIntervalTree<ui64> tree;
+ tree.InsertInterval(5, 10);
+ tree.InsertInterval(15, 20);
+ tree.InsertInterval(25, 30);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 3);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 15);
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.EraseInterval(16, 100500), 9);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 2);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 6);
+ }
+
+ // 7. Remove from the center of existing interval.
+ {
+ TDisjointIntervalTree<ui64> tree;
+ tree.InsertInterval(5, 10);
+ tree.InsertInterval(15, 20);
+ tree.InsertInterval(25, 30);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 3);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 15);
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.EraseInterval(17, 19), 2);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 4);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 13);
+
+ UNIT_ASSERT(tree.Has(16));
+ UNIT_ASSERT(tree.Has(19));
+ }
+
+ // 8. Remove from the center of the only existing interval.
+ {
+ TDisjointIntervalTree<ui64> tree;
+ tree.InsertInterval(15, 20);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 5);
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.EraseInterval(17, 19), 2);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 2);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 3);
+
+ UNIT_ASSERT(tree.Has(16));
+ UNIT_ASSERT(tree.Has(19));
+ }
+
+ // 9. Specify borders between existing intervals.
+ {
+ TDisjointIntervalTree<ui64> tree;
+ tree.InsertInterval(5, 10);
+ tree.InsertInterval(15, 20);
+ tree.InsertInterval(25, 30);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 3);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 15);
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.EraseInterval(10, 15), 0);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 3);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 15);
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.EraseInterval(13, 15), 0);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 3);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 15);
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.EraseInterval(10, 13), 0);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 3);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 15);
+ }
+
+ // 10. Specify right border exactly as in existing interval.
+ {
+ TDisjointIntervalTree<ui64> tree;
+ tree.InsertInterval(5, 10);
+ tree.InsertInterval(15, 20);
+ tree.InsertInterval(25, 30);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 3);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 15);
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.EraseInterval(0, 20), 10);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 5);
+ }
+
+ // 11. Specify right border somewhere in existing interval.
+ {
+ TDisjointIntervalTree<ui64> tree;
+ tree.InsertInterval(5, 10);
+ tree.InsertInterval(15, 20);
+ tree.InsertInterval(25, 30);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 3);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 15);
+
+ UNIT_ASSERT_VALUES_EQUAL(tree.EraseInterval(2, 17), 7);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumIntervals(), 2);
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetNumElements(), 8);
+ }
+ }
+
+ Y_UNIT_TEST(IntersectsTest) {
+ {
+ TDisjointIntervalTree<ui64> tree;
+ UNIT_ASSERT(!tree.Intersects(1, 2));
+ }
+
+ {
+ TDisjointIntervalTree<ui64> tree;
+ tree.InsertInterval(5, 10);
+
+ UNIT_ASSERT(tree.Intersects(5, 10));
+ UNIT_ASSERT(tree.Intersects(5, 6));
+ UNIT_ASSERT(tree.Intersects(9, 10));
+ UNIT_ASSERT(tree.Intersects(6, 8));
+ UNIT_ASSERT(tree.Intersects(1, 8));
+ UNIT_ASSERT(tree.Intersects(8, 15));
+ UNIT_ASSERT(tree.Intersects(3, 14));
+
+ UNIT_ASSERT(!tree.Intersects(3, 5));
+ UNIT_ASSERT(!tree.Intersects(10, 13));
+ }
+
+ {
+ TDisjointIntervalTree<ui64> tree;
+ tree.InsertInterval(5, 10);
+ tree.InsertInterval(20, 30);
+
+ UNIT_ASSERT(tree.Intersects(5, 10));
+ UNIT_ASSERT(tree.Intersects(5, 6));
+ UNIT_ASSERT(tree.Intersects(9, 10));
+ UNIT_ASSERT(tree.Intersects(6, 8));
+ UNIT_ASSERT(tree.Intersects(1, 8));
+ UNIT_ASSERT(tree.Intersects(8, 15));
+ UNIT_ASSERT(tree.Intersects(3, 14));
+ UNIT_ASSERT(tree.Intersects(18, 21));
+ UNIT_ASSERT(tree.Intersects(3, 50));
+
+ UNIT_ASSERT(!tree.Intersects(3, 5));
+ UNIT_ASSERT(!tree.Intersects(10, 13));
+ UNIT_ASSERT(!tree.Intersects(15, 18));
+ }
+ }
+}
diff --git a/library/cpp/containers/disjoint_interval_tree/ut/ya.make b/library/cpp/containers/disjoint_interval_tree/ut/ya.make
new file mode 100644
index 0000000000..6736ce0c2b
--- /dev/null
+++ b/library/cpp/containers/disjoint_interval_tree/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/containers/disjoint_interval_tree)
+
+OWNER(
+ dcherednik
+ galaxycrab
+)
+
+SRCS(
+ disjoint_interval_tree_ut.cpp
+)
+
+END()
diff --git a/library/cpp/containers/disjoint_interval_tree/ya.make b/library/cpp/containers/disjoint_interval_tree/ya.make
new file mode 100644
index 0000000000..b4f5a52a67
--- /dev/null
+++ b/library/cpp/containers/disjoint_interval_tree/ya.make
@@ -0,0 +1,10 @@
+OWNER(
+ dcherednik
+ galaxycrab
+)
+
+LIBRARY()
+
+SRCS(disjoint_interval_tree.cpp)
+
+END()
diff --git a/library/cpp/containers/flat_hash/benchmark/flat_hash_benchmark.cpp b/library/cpp/containers/flat_hash/benchmark/flat_hash_benchmark.cpp
new file mode 100644
index 0000000000..040cff3fff
--- /dev/null
+++ b/library/cpp/containers/flat_hash/benchmark/flat_hash_benchmark.cpp
@@ -0,0 +1,180 @@
+#include <library/cpp/containers/flat_hash/flat_hash.h>
+
+#include <library/cpp/containers/dense_hash/dense_hash.h>
+#include <library/cpp/testing/benchmark/bench.h>
+
+#include <util/random/random.h>
+#include <util/generic/xrange.h>
+#include <util/generic/hash.h>
+
+namespace {
+
+template <class Map, size_t elemCount, class... Args>
+void RunLookupPositiveScalarKeysBench(::NBench::NCpu::TParams& iface, Args&&... args) {
+ using key_type = i32;
+ static_assert(std::is_same_v<typename Map::key_type, key_type>);
+ Map hm(std::forward<Args>(args)...);
+
+ TVector<i32> keys(elemCount);
+ for (auto& k : keys) {
+ k = RandomNumber<ui32>(std::numeric_limits<i32>::max());
+ hm.emplace(k, 0);
+ }
+
+ for (const auto i : xrange(iface.Iterations())) {
+ Y_UNUSED(i);
+ for (const auto& k : keys) {
+ Y_DO_NOT_OPTIMIZE_AWAY(hm[k]);
+ }
+ }
+}
+
+constexpr size_t TEST1_ELEM_COUNT = 10;
+constexpr size_t TEST2_ELEM_COUNT = 1000;
+constexpr size_t TEST3_ELEM_COUNT = 1000000;
+
+}
+
+/* *********************************** TEST1 ***********************************
+ * Insert TEST1_ELEM_COUNT positive integers and than make lookup.
+ * No init size provided for tables.
+ * key_type - i32
+ */
+
+Y_CPU_BENCHMARK(Test1_fh_TFlatHashMap_LinearProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TFlatHashMap<i32, int>, TEST1_ELEM_COUNT>(iface);
+}
+
+/*
+Y_CPU_BENCHMARK(Test1_fh_TFlatHashMap_QuadraticProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TFlatHashMap<i32, int, THash<i32>,
+ std::equal_to<i32>, NFlatHash::TQuadraticProbing>, TEST1_ELEM_COUNT>(iface);
+}
+*/
+
+Y_CPU_BENCHMARK(Test1_fh_TFlatHashMap_DenseProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TFlatHashMap<i32, int, THash<i32>,
+ std::equal_to<i32>, NFlatHash::TDenseProbing>, TEST1_ELEM_COUNT>(iface);
+}
+
+
+Y_CPU_BENCHMARK(Test1_fh_TDenseHashMapStaticMarker_LinearProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TDenseHashMapStaticMarker<i32, int, -1, THash<i32>,
+ std::equal_to<i32>, NFlatHash::TLinearProbing>, TEST1_ELEM_COUNT>(iface);
+}
+
+/*
+Y_CPU_BENCHMARK(Test1_fh_TDenseHashMapStaticMarker_QuadraticProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TDenseHashMapStaticMarker<i32, int, -1, THash<i32>,
+ std::equal_to<i32>, NFlatHash::TQuadraticProbing>, TEST1_ELEM_COUNT>(iface);
+}
+*/
+
+Y_CPU_BENCHMARK(Test1_fh_TDenseHashMapStaticMarker_DenseProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TDenseHashMapStaticMarker<i32, int, -1>, TEST1_ELEM_COUNT>(iface);
+}
+
+
+Y_CPU_BENCHMARK(Test1_foreign_TDenseHash, iface) {
+ RunLookupPositiveScalarKeysBench<TDenseHash<i32, int>, TEST1_ELEM_COUNT>(iface, (i32)-1);
+}
+
+Y_CPU_BENCHMARK(Test1_foreign_THashMap, iface) {
+ RunLookupPositiveScalarKeysBench<THashMap<i32, int>, TEST1_ELEM_COUNT>(iface);
+}
+
+/* *********************************** TEST2 ***********************************
+ * Insert TEST2_ELEM_COUNT positive integers and than make lookup.
+ * No init size provided for tables.
+ * key_type - i32
+ */
+
+Y_CPU_BENCHMARK(Test2_fh_TFlatHashMap_LinearProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TFlatHashMap<i32, int>, TEST2_ELEM_COUNT>(iface);
+}
+
+/*
+Y_CPU_BENCHMARK(Test2_fh_TFlatHashMap_QuadraticProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TFlatHashMap<i32, int, THash<i32>,
+ std::equal_to<i32>, NFlatHash::TQuadraticProbing>, TEST2_ELEM_COUNT>(iface);
+}
+*/
+
+Y_CPU_BENCHMARK(Test2_fh_TFlatHashMap_DenseProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TFlatHashMap<i32, int, THash<i32>,
+ std::equal_to<i32>, NFlatHash::TDenseProbing>, TEST2_ELEM_COUNT>(iface);
+}
+
+
+Y_CPU_BENCHMARK(Test2_fh_TDenseHashMapStaticMarker_LinearProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TDenseHashMapStaticMarker<i32, int, -1, THash<i32>,
+ std::equal_to<i32>, NFlatHash::TLinearProbing>, TEST2_ELEM_COUNT>(iface);
+}
+
+/*
+Y_CPU_BENCHMARK(Test2_fh_TDenseHashMapStaticMarker_QuadraticProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TDenseHashMapStaticMarker<i32, int, -1, THash<i32>,
+ std::equal_to<i32>, NFlatHash::TQuadraticProbing>, TEST2_ELEM_COUNT>(iface);
+}
+*/
+
+Y_CPU_BENCHMARK(Test2_fh_TDenseHashMapStaticMarker_DenseProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TDenseHashMapStaticMarker<i32, int, -1>, TEST2_ELEM_COUNT>(iface);
+}
+
+
+Y_CPU_BENCHMARK(Test2_foreign_TDenseHash, iface) {
+ RunLookupPositiveScalarKeysBench<TDenseHash<i32, int>, TEST2_ELEM_COUNT>(iface, (i32)-1);
+}
+
+Y_CPU_BENCHMARK(Test2_foreign_THashMap, iface) {
+ RunLookupPositiveScalarKeysBench<THashMap<i32, int>, TEST2_ELEM_COUNT>(iface);
+}
+
+/* *********************************** TEST3 ***********************************
+ * Insert TEST2_ELEM_COUNT positive integers and than make lookup.
+ * No init size provided for tables.
+ * key_type - i32
+ */
+
+Y_CPU_BENCHMARK(Test3_fh_TFlatHashMap_LinearProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TFlatHashMap<i32, int>, TEST3_ELEM_COUNT>(iface);
+}
+
+/*
+Y_CPU_BENCHMARK(Test3_fh_TFlatHashMap_QuadraticProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TFlatHashMap<i32, int, THash<i32>,
+ std::equal_to<i32>, NFlatHash::TQuadraticProbing>, TEST3_ELEM_COUNT>(iface);
+}
+*/
+
+Y_CPU_BENCHMARK(Test3_fh_TFlatHashMap_DenseProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TFlatHashMap<i32, int, THash<i32>,
+ std::equal_to<i32>, NFlatHash::TDenseProbing>, TEST3_ELEM_COUNT>(iface);
+}
+
+
+Y_CPU_BENCHMARK(Test3_fh_TDenseHashMapStaticMarker_LinearProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TDenseHashMapStaticMarker<i32, int, -1, THash<i32>,
+ std::equal_to<i32>, NFlatHash::TLinearProbing>, TEST3_ELEM_COUNT>(iface);
+}
+
+/*
+Y_CPU_BENCHMARK(Test3_fh_TDenseHashMapStaticMarker_QuadraticProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TDenseHashMapStaticMarker<i32, int, -1, THash<i32>,
+ std::equal_to<i32>, NFlatHash::TQuadraticProbing>, TEST3_ELEM_COUNT>(iface);
+}
+*/
+
+Y_CPU_BENCHMARK(Test3_fh_TDenseHashMapStaticMarker_DenseProbing, iface) {
+ RunLookupPositiveScalarKeysBench<NFH::TDenseHashMapStaticMarker<i32, int, -1>, TEST3_ELEM_COUNT>(iface);
+}
+
+
+Y_CPU_BENCHMARK(Test3_foreign_TDenseHash, iface) {
+ RunLookupPositiveScalarKeysBench<TDenseHash<i32, int>, TEST3_ELEM_COUNT>(iface, (i32)-1);
+}
+
+Y_CPU_BENCHMARK(Test3_foreign_THashMap, iface) {
+ RunLookupPositiveScalarKeysBench<THashMap<i32, int>, TEST3_ELEM_COUNT>(iface);
+}
diff --git a/library/cpp/containers/flat_hash/benchmark/ya.make b/library/cpp/containers/flat_hash/benchmark/ya.make
new file mode 100644
index 0000000000..6f9aedf50d
--- /dev/null
+++ b/library/cpp/containers/flat_hash/benchmark/ya.make
@@ -0,0 +1,13 @@
+Y_BENCHMARK()
+
+OWNER(tender-bum)
+
+SRCS(
+ flat_hash_benchmark.cpp
+)
+
+PEERDIR(
+ library/cpp/containers/flat_hash
+)
+
+END()
diff --git a/library/cpp/containers/flat_hash/flat_hash.cpp b/library/cpp/containers/flat_hash/flat_hash.cpp
new file mode 100644
index 0000000000..2a16398bd4
--- /dev/null
+++ b/library/cpp/containers/flat_hash/flat_hash.cpp
@@ -0,0 +1 @@
+#include "flat_hash.h"
diff --git a/library/cpp/containers/flat_hash/flat_hash.h b/library/cpp/containers/flat_hash/flat_hash.h
new file mode 100644
index 0000000000..582b8ae8f5
--- /dev/null
+++ b/library/cpp/containers/flat_hash/flat_hash.h
@@ -0,0 +1,120 @@
+#pragma once
+
+#include <library/cpp/containers/flat_hash/lib/map.h>
+#include <library/cpp/containers/flat_hash/lib/containers.h>
+#include <library/cpp/containers/flat_hash/lib/probings.h>
+#include <library/cpp/containers/flat_hash/lib/set.h>
+#include <library/cpp/containers/flat_hash/lib/size_fitters.h>
+#include <library/cpp/containers/flat_hash/lib/expanders.h>
+
+#include <util/str_stl.h>
+
+namespace NPrivate {
+
+template <class Key, class T, class Hash, class KeyEqual, class Probing, class Alloc>
+using TFlatHashMapImpl = NFlatHash::TMap<Key, T, Hash, KeyEqual,
+ NFlatHash::TFlatContainer<std::pair<const Key, T>, Alloc>,
+ Probing, NFlatHash::TAndSizeFitter,
+ NFlatHash::TSimpleExpander>;
+
+template <class Key, class T, auto emptyMarker, class Hash, class KeyEqual, class Probing, class Alloc>
+using TDenseHashMapImpl =
+ NFlatHash::TMap<Key, T, Hash, KeyEqual,
+ NFlatHash::TDenseContainer<std::pair<const Key, T>,
+ NFlatHash::NMap::TStaticValueMarker<emptyMarker, T>,
+ Alloc>,
+ Probing, NFlatHash::TAndSizeFitter, NFlatHash::TSimpleExpander>;
+
+
+template <class T, class Hash, class KeyEqual, class Probing, class Alloc>
+using TFlatHashSetImpl = NFlatHash::TSet<T, Hash, KeyEqual,
+ NFlatHash::TFlatContainer<T, Alloc>,
+ Probing, NFlatHash::TAndSizeFitter,
+ NFlatHash::TSimpleExpander>;
+
+template <class T, auto emptyMarker, class Hash, class KeyEqual, class Probing, class Alloc>
+using TDenseHashSetImpl =
+ NFlatHash::TSet<T, Hash, KeyEqual,
+ NFlatHash::TDenseContainer<T, NFlatHash::NSet::TStaticValueMarker<emptyMarker>, Alloc>,
+ Probing, NFlatHash::TAndSizeFitter, NFlatHash::TSimpleExpander>;
+
+} // namespace NPrivate
+
+namespace NFH {
+
+/* flat_map: Fast and highly customizable hash map.
+ *
+ * Most features would be available soon.
+ * Until that time we strongly insist on using only class aliases listed below.
+ */
+
+/* Simpliest open addressing hash map.
+ * Uses additional array to denote status of every bucket.
+ * Default probing is linear.
+ * Currently available probings:
+ * * TLinearProbing
+ * * TQuadraticProbing
+ * * TDenseProbing
+ */
+template <class Key,
+ class T,
+ class Hash = THash<Key>,
+ class KeyEqual = std::equal_to<>,
+ class Probing = NFlatHash::TLinearProbing,
+ class Alloc = std::allocator<std::pair<const Key, T>>>
+using TFlatHashMap = NPrivate::TFlatHashMapImpl<Key, T, Hash, KeyEqual, Probing, Alloc>;
+
+/* Open addressing table with user specified marker for empty buckets.
+ * Currently available probings:
+ * * TLinearProbing
+ * * TQuadraticProbing
+ * * TDenseProbing
+ */
+template <class Key,
+ class T,
+ auto emptyMarker,
+ class Hash = THash<Key>,
+ class KeyEqual = std::equal_to<>,
+ class Probing = NFlatHash::TDenseProbing,
+ class Alloc = std::allocator<std::pair<const Key, T>>>
+using TDenseHashMapStaticMarker = NPrivate::TDenseHashMapImpl<Key, T, emptyMarker,
+ Hash, KeyEqual, Probing, Alloc>;
+
+
+/* flat_set: Fast and highly customizable hash set.
+ *
+ * Most features would be available soon.
+ * Until that time we strongly insist on using only class aliases listed below.
+ */
+
+/* Simpliest open addressing hash map.
+ * Uses additional array to denote status of every bucket.
+ * Default probing is linear.
+ * Currently available probings:
+ * * TLinearProbing
+ * * TQuadraticProbing
+ * * TDenseProbing
+ */
+template <class T,
+ class Hash = THash<T>,
+ class KeyEqual = std::equal_to<>,
+ class Probing = NFlatHash::TLinearProbing,
+ class Alloc = std::allocator<T>>
+using TFlatHashSet = NPrivate::TFlatHashSetImpl<T, Hash, KeyEqual, Probing, Alloc>;
+
+/* Open addressing table with user specified marker for empty buckets.
+ * Currently available probings:
+ * * TLinearProbing
+ * * TQuadraticProbing
+ * * TDenseProbing
+ */
+template <class T,
+ auto emptyMarker,
+ class Hash = THash<T>,
+ class KeyEqual = std::equal_to<>,
+ class Probing = NFlatHash::TDenseProbing,
+ class Alloc = std::allocator<T>>
+using TDenseHashSetStaticMarker = NPrivate::TDenseHashSetImpl<T, emptyMarker,
+ Hash, KeyEqual, Probing, Alloc>;
+
+} // namespace NFH
diff --git a/library/cpp/containers/flat_hash/lib/concepts/concepts.cpp b/library/cpp/containers/flat_hash/lib/concepts/concepts.cpp
new file mode 100644
index 0000000000..63eed9acdd
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/concepts/concepts.cpp
@@ -0,0 +1,4 @@
+#include "container.h"
+#include "iterator.h"
+#include "size_fitter.h"
+#include "value_marker.h"
diff --git a/library/cpp/containers/flat_hash/lib/concepts/container.h b/library/cpp/containers/flat_hash/lib/concepts/container.h
new file mode 100644
index 0000000000..eac1803b59
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/concepts/container.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include <type_traits>
+
+/* Concepts:
+ * Container
+ * RemovalContainer
+ */
+namespace NFlatHash::NConcepts {
+
+#define DCV(type) std::declval<type>()
+#define DCT(object) decltype(object)
+
+template <class T, class = void>
+struct Container : std::false_type {};
+
+template <class T>
+struct Container<T, std::void_t<
+ typename T::value_type,
+ typename T::size_type,
+ typename T::difference_type,
+ DCT(DCV(T).Node(DCV(typename T::size_type))),
+ DCT(DCV(const T).Node(DCV(typename T::size_type))),
+ DCT(DCV(const T).Size()),
+ DCT(DCV(const T).Taken()),
+ DCT(DCV(const T).Empty()),
+ DCT(DCV(const T).IsEmpty(DCV(typename T::size_type))),
+ DCT(DCV(const T).IsTaken(DCV(typename T::size_type))),
+ DCT(DCV(T).Swap(DCV(T&))),
+ DCT(DCV(const T).Clone(DCV(typename T::size_type)))>>
+ : std::conjunction<std::is_same<DCT(DCV(T).Node(DCV(typename T::size_type))),
+ typename T::value_type&>,
+ std::is_same<DCT(DCV(const T).Node(DCV(typename T::size_type))),
+ const typename T::value_type&>,
+ std::is_same<DCT(DCV(const T).Size()), typename T::size_type>,
+ std::is_same<DCT(DCV(const T).Taken()), typename T::size_type>,
+ std::is_same<DCT(DCV(const T).Empty()), typename T::size_type>,
+ std::is_same<DCT(DCV(const T).IsEmpty(DCV(typename T::size_type))), bool>,
+ std::is_same<DCT(DCV(const T).IsTaken(DCV(typename T::size_type))), bool>,
+ std::is_same<DCT(DCV(const T).Clone(DCV(typename T::size_type))), T>,
+ std::is_copy_constructible<T>,
+ std::is_move_constructible<T>,
+ std::is_copy_assignable<T>,
+ std::is_move_assignable<T>> {};
+
+template <class T>
+constexpr bool ContainerV = Container<T>::value;
+
+template <class T, class = void>
+struct RemovalContainer : std::false_type {};
+
+template <class T>
+struct RemovalContainer<T, std::void_t<
+ DCT(DCV(T).DeleteNode(DCV(typename T::size_type))),
+ DCT(DCV(const T).IsDeleted(DCV(typename T::size_type)))>>
+ : std::conjunction<Container<T>,
+ std::is_same<DCT(DCV(const T).IsDeleted(DCV(typename T::size_type))),
+ bool>> {};
+
+template <class T>
+constexpr bool RemovalContainerV = RemovalContainer<T>::value;
+
+#undef DCV
+#undef DCT
+
+} // namespace NFlatHash::NConcepts
diff --git a/library/cpp/containers/flat_hash/lib/concepts/iterator.h b/library/cpp/containers/flat_hash/lib/concepts/iterator.h
new file mode 100644
index 0000000000..b9c1c24c82
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/concepts/iterator.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <iterator>
+
+/* Concepts:
+ * Iterator
+ */
+namespace NFlatHash::NConcepts {
+
+template <class T, class = void>
+struct Iterator : std::false_type {};
+
+template <class T>
+struct Iterator<T, std::void_t<typename std::iterator_traits<T>::iterator_category>>
+ : std::true_type {};
+
+template <class T>
+constexpr bool IteratorV = Iterator<T>::value;
+
+} // namespace NFlatHash::NConcepts
diff --git a/library/cpp/containers/flat_hash/lib/concepts/size_fitter.h b/library/cpp/containers/flat_hash/lib/concepts/size_fitter.h
new file mode 100644
index 0000000000..83d1d31304
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/concepts/size_fitter.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <type_traits>
+
+/* Concepts:
+ * SizeFitter
+ */
+namespace NFlatHash::NConcepts {
+
+#define DCV(type) std::declval<type>()
+#define DCT(object) decltype(object)
+
+template <class T, class = void>
+struct SizeFitter : std::false_type {};
+
+template <class T>
+struct SizeFitter<T, std::void_t<
+ DCT(DCV(const T).EvalIndex(DCV(size_t), DCV(size_t))),
+ DCT(DCV(const T).EvalSize(DCV(size_t))),
+ DCT(DCV(T).Update(DCV(size_t)))>>
+ : std::conjunction<std::is_same<DCT(DCV(const T).EvalIndex(DCV(size_t), DCV(size_t))), size_t>,
+ std::is_same<DCT(DCV(const T).EvalSize(DCV(size_t))), size_t>,
+ std::is_copy_constructible<T>,
+ std::is_move_constructible<T>,
+ std::is_copy_assignable<T>,
+ std::is_move_assignable<T>> {};
+
+template <class T>
+constexpr bool SizeFitterV = SizeFitter<T>::value;
+
+#undef DCV
+#undef DCT
+
+} // namespace NFlatHash::NConcepts
diff --git a/library/cpp/containers/flat_hash/lib/concepts/value_marker.h b/library/cpp/containers/flat_hash/lib/concepts/value_marker.h
new file mode 100644
index 0000000000..9d1e9b210a
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/concepts/value_marker.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <type_traits>
+
+/* Concepts:
+ * ValueMarker
+ */
+namespace NFlatHash::NConcepts {
+
+#define DCV(type) std::declval<type>()
+#define DCT(object) decltype(object)
+
+template <class T, class = void>
+struct ValueMarker : std::false_type {};
+
+template <class T>
+struct ValueMarker<T, std::void_t<
+ typename T::value_type,
+ DCT(DCV(const T).Create()),
+ DCT(DCV(const T).Equals(DCV(const typename T::value_type&)))>>
+ : std::conjunction<std::is_constructible<typename T::value_type, DCT(DCV(const T).Create())>,
+ std::is_same<DCT(DCV(const T).Equals(DCV(const typename T::value_type&))), bool>,
+ std::is_copy_constructible<T>,
+ std::is_move_constructible<T>,
+ std::is_copy_assignable<T>,
+ std::is_move_assignable<T>> {};
+
+template <class T>
+constexpr bool ValueMarkerV = ValueMarker<T>::value;
+
+#undef DCV
+#undef DCT
+
+} // namespace NFlatHash::NConcepts
diff --git a/library/cpp/containers/flat_hash/lib/concepts/ya.make b/library/cpp/containers/flat_hash/lib/concepts/ya.make
new file mode 100644
index 0000000000..f82fc1d51c
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/concepts/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(tender-bum)
+
+SRCS(
+ concepts.cpp
+)
+
+END()
diff --git a/library/cpp/containers/flat_hash/lib/containers.cpp b/library/cpp/containers/flat_hash/lib/containers.cpp
new file mode 100644
index 0000000000..0853c23fc1
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/containers.cpp
@@ -0,0 +1 @@
+#include "containers.h"
diff --git a/library/cpp/containers/flat_hash/lib/containers.h b/library/cpp/containers/flat_hash/lib/containers.h
new file mode 100644
index 0000000000..82008f2f9c
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/containers.h
@@ -0,0 +1,314 @@
+#pragma once
+
+#include "concepts/container.h"
+#include "value_markers.h"
+
+#include <util/system/yassert.h>
+
+#include <util/generic/vector.h>
+#include <util/generic/typetraits.h>
+#include <util/generic/utility.h>
+
+#include <optional>
+
+namespace NFlatHash {
+
+/* FLAT CONTAINER */
+
+template <class T, class Alloc = std::allocator<T>>
+class TFlatContainer {
+public:
+ using value_type = T;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+ using allocator_type = Alloc;
+ using pointer = typename std::allocator_traits<allocator_type>::pointer;
+ using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
+
+private:
+ class TCage {
+ enum ENodeStatus {
+ NS_EMPTY,
+ NS_TAKEN,
+ NS_DELETED
+ };
+
+ public:
+ TCage() noexcept = default;
+
+ TCage(const TCage&) = default;
+ TCage(TCage&&) = default;
+
+ TCage& operator=(const TCage& rhs) {
+ switch (rhs.Status_) {
+ case NS_TAKEN:
+ if constexpr (std::is_copy_assignable_v<value_type>) {
+ Value_ = rhs.Value_;
+ } else {
+ Value_.emplace(rhs.Value());
+ }
+ break;
+ case NS_EMPTY:
+ case NS_DELETED:
+ if (Value_.has_value()) {
+ Value_.reset();
+ }
+ break;
+ default:
+ Y_VERIFY(false, "Not implemented");
+ }
+ Status_ = rhs.Status_;
+ return *this;
+ }
+ // We never call it since all the TCage's are stored in vector
+ TCage& operator=(TCage&& rhs) = delete;
+
+ template <class... Args>
+ void Emplace(Args&&... args) {
+ Y_ASSERT(Status_ == NS_EMPTY);
+ Value_.emplace(std::forward<Args>(args)...);
+ Status_ = NS_TAKEN;
+ }
+
+ void Reset() noexcept {
+ Y_ASSERT(Status_ == NS_TAKEN);
+ Value_.reset();
+ Status_ = NS_DELETED;
+ }
+
+ value_type& Value() {
+ Y_ASSERT(Status_ == NS_TAKEN);
+ return *Value_;
+ }
+
+ const value_type& Value() const {
+ Y_ASSERT(Status_ == NS_TAKEN);
+ return *Value_;
+ }
+
+ bool IsEmpty() const noexcept { return Status_ == NS_EMPTY; }
+ bool IsTaken() const noexcept { return Status_ == NS_TAKEN; }
+ bool IsDeleted() const noexcept { return Status_ == NS_DELETED; }
+
+ ENodeStatus Status() const noexcept { return Status_; }
+
+ private:
+ std::optional<value_type> Value_;
+ ENodeStatus Status_ = NS_EMPTY;
+ };
+
+public:
+ explicit TFlatContainer(size_type initSize, const allocator_type& alloc = {})
+ : Buckets_(initSize, alloc)
+ , Taken_(0)
+ , Empty_(initSize) {}
+
+ TFlatContainer(const TFlatContainer&) = default;
+ TFlatContainer(TFlatContainer&& rhs)
+ : Buckets_(std::move(rhs.Buckets_))
+ , Taken_(rhs.Taken_)
+ , Empty_(rhs.Empty_)
+ {
+ rhs.Taken_ = 0;
+ rhs.Empty_ = 0;
+ }
+
+ TFlatContainer& operator=(const TFlatContainer&) = default;
+ TFlatContainer& operator=(TFlatContainer&&) = default;
+
+ value_type& Node(size_type idx) { return Buckets_[idx].Value(); }
+ const value_type& Node(size_type idx) const { return Buckets_[idx].Value(); }
+
+ size_type Size() const noexcept { return Buckets_.size(); }
+ size_type Taken() const noexcept { return Taken_; }
+ size_type Empty() const noexcept { return Empty_; }
+
+ template <class... Args>
+ void InitNode(size_type idx, Args&&... args) {
+ Buckets_[idx].Emplace(std::forward<Args>(args)...);
+ ++Taken_;
+ --Empty_;
+ }
+
+ void DeleteNode(size_type idx) noexcept {
+ Buckets_[idx].Reset();
+ --Taken_;
+ }
+
+ bool IsEmpty(size_type idx) const { return Buckets_[idx].IsEmpty(); }
+ bool IsTaken(size_type idx) const { return Buckets_[idx].IsTaken(); }
+ bool IsDeleted(size_type idx) const { return Buckets_[idx].IsDeleted(); }
+
+ void Swap(TFlatContainer& rhs) noexcept {
+ DoSwap(Buckets_, rhs.Buckets_);
+ DoSwap(Taken_, rhs.Taken_);
+ DoSwap(Empty_, rhs.Empty_);
+ }
+
+ TFlatContainer Clone(size_type newSize) const { return TFlatContainer(newSize, Buckets_.get_allocator()); }
+
+private:
+ TVector<TCage, allocator_type> Buckets_;
+ size_type Taken_;
+ size_type Empty_;
+};
+
+static_assert(NConcepts::ContainerV<TFlatContainer<int>>);
+static_assert(NConcepts::RemovalContainerV<TFlatContainer<int>>);
+
+/* DENSE CONTAINER */
+
+template <class T, class EmptyMarker = NSet::TEqValueMarker<T>, class Alloc = std::allocator<T>>
+class TDenseContainer {
+ static_assert(NConcepts::ValueMarkerV<EmptyMarker>);
+
+public:
+ using value_type = T;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+ using allocator_type = Alloc;
+ using pointer = typename std::allocator_traits<allocator_type>::pointer;
+ using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
+
+public:
+ TDenseContainer(size_type initSize, EmptyMarker emptyMarker = {}, const allocator_type& alloc = {})
+ : Buckets_(initSize, emptyMarker.Create(), alloc)
+ , Taken_(0)
+ , EmptyMarker_(std::move(emptyMarker)) {}
+
+ TDenseContainer(const TDenseContainer&) = default;
+ TDenseContainer(TDenseContainer&&) = default;
+
+ TDenseContainer& operator=(const TDenseContainer& rhs) {
+ Taken_ = rhs.Taken_;
+ EmptyMarker_ = rhs.EmptyMarker_;
+ if constexpr (std::is_copy_assignable_v<value_type>) {
+ Buckets_ = rhs.Buckets_;
+ } else {
+ auto tmp = rhs.Buckets_;
+ Buckets_.swap(tmp);
+ }
+ return *this;
+ }
+ TDenseContainer& operator=(TDenseContainer&&) = default;
+
+ value_type& Node(size_type idx) { return Buckets_[idx]; }
+ const value_type& Node(size_type idx) const { return Buckets_[idx]; }
+
+ size_type Size() const noexcept { return Buckets_.size(); }
+ size_type Taken() const noexcept { return Taken_; }
+ size_type Empty() const noexcept { return Size() - Taken(); }
+
+ template <class... Args>
+ void InitNode(size_type idx, Args&&... args) {
+ Node(idx).~value_type();
+ new (&Buckets_[idx]) value_type(std::forward<Args>(args)...);
+ ++Taken_;
+ }
+
+ bool IsEmpty(size_type idx) const { return EmptyMarker_.Equals(Buckets_[idx]); }
+ bool IsTaken(size_type idx) const { return !IsEmpty(idx); }
+
+ void Swap(TDenseContainer& rhs)
+ noexcept(noexcept(DoSwap(std::declval<EmptyMarker&>(), std::declval<EmptyMarker&>())))
+ {
+ DoSwap(Buckets_, rhs.Buckets_);
+ DoSwap(EmptyMarker_, rhs.EmptyMarker_);
+ DoSwap(Taken_, rhs.Taken_);
+ }
+
+ TDenseContainer Clone(size_type newSize) const { return { newSize, EmptyMarker_, GetAllocator() }; }
+
+protected:
+ allocator_type GetAllocator() const {
+ return Buckets_.get_allocator();
+ }
+
+protected:
+ TVector<value_type, allocator_type> Buckets_;
+ size_type Taken_;
+ EmptyMarker EmptyMarker_;
+};
+
+static_assert(NConcepts::ContainerV<TDenseContainer<int>>);
+static_assert(!NConcepts::RemovalContainerV<TDenseContainer<int>>);
+
+template <class T, class DeletedMarker = NSet::TEqValueMarker<T>,
+ class EmptyMarker = NSet::TEqValueMarker<T>, class Alloc = std::allocator<T>>
+class TRemovalDenseContainer : private TDenseContainer<T, EmptyMarker, Alloc> {
+private:
+ static_assert(NConcepts::ValueMarkerV<DeletedMarker>);
+
+ using TBase = TDenseContainer<T, EmptyMarker>;
+
+public:
+ using typename TBase::value_type;
+ using typename TBase::size_type;
+ using typename TBase::difference_type;
+ using typename TBase::allocator_type;
+ using typename TBase::pointer;
+ using typename TBase::const_pointer;
+
+public:
+ TRemovalDenseContainer(
+ size_type initSize,
+ DeletedMarker deletedMarker = {},
+ EmptyMarker emptyMarker = {},
+ const allocator_type& alloc = {})
+ : TBase(initSize, std::move(emptyMarker), alloc)
+ , DeletedMarker_(std::move(deletedMarker))
+ , Empty_(initSize) {}
+
+ TRemovalDenseContainer(const TRemovalDenseContainer&) = default;
+ TRemovalDenseContainer(TRemovalDenseContainer&&) = default;
+
+ TRemovalDenseContainer& operator=(const TRemovalDenseContainer&) = default;
+ TRemovalDenseContainer& operator=(TRemovalDenseContainer&&) = default;
+
+ using TBase::Node;
+ using TBase::Size;
+ using TBase::Taken;
+ using TBase::InitNode;
+ using TBase::IsEmpty;
+
+ size_type Empty() const noexcept { return Empty_; }
+
+ template <class... Args>
+ void InitNode(size_type idx, Args&&... args) {
+ TBase::InitNode(idx, std::forward<Args>(args)...);
+ --Empty_;
+ }
+
+ void DeleteNode(size_type idx) {
+ if constexpr (!std::is_trivially_destructible_v<value_type>) {
+ TBase::Node(idx).~value_type();
+ }
+ new (&TBase::Node(idx)) value_type(DeletedMarker_.Create());
+ --TBase::Taken_;
+ }
+
+ bool IsTaken(size_type idx) const { return !IsDeleted(idx) && TBase::IsTaken(idx); }
+ bool IsDeleted(size_type idx) const { return DeletedMarker_.Equals(Node(idx)); }
+
+ void Swap(TRemovalDenseContainer& rhs)
+ noexcept(noexcept(std::declval<TBase>().Swap(std::declval<TBase&>())) &&
+ noexcept(DoSwap(std::declval<DeletedMarker&>(), std::declval<DeletedMarker&>())))
+ {
+ TBase::Swap(rhs);
+ DoSwap(DeletedMarker_, rhs.DeletedMarker_);
+ DoSwap(Empty_, rhs.Empty_);
+ }
+
+ TRemovalDenseContainer Clone(size_type newSize) const {
+ return { newSize, DeletedMarker_, TBase::EmptyMarker_, TBase::GetAllocator() };
+ }
+
+private:
+ DeletedMarker DeletedMarker_;
+ size_type Empty_;
+};
+
+static_assert(NConcepts::ContainerV<TRemovalDenseContainer<int>>);
+static_assert(NConcepts::RemovalContainerV<TRemovalDenseContainer<int>>);
+
+} // namespace NFlatHash
diff --git a/library/cpp/containers/flat_hash/lib/expanders.cpp b/library/cpp/containers/flat_hash/lib/expanders.cpp
new file mode 100644
index 0000000000..6bed3c72f3
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/expanders.cpp
@@ -0,0 +1 @@
+#include "expanders.h"
diff --git a/library/cpp/containers/flat_hash/lib/expanders.h b/library/cpp/containers/flat_hash/lib/expanders.h
new file mode 100644
index 0000000000..25b10e6bf1
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/expanders.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <utility>
+
+namespace NFlatHash {
+
+struct TSimpleExpander {
+ static constexpr bool NeedGrow(size_t size, size_t buckets) noexcept {
+ return size >= buckets / 2;
+ }
+
+ static constexpr bool WillNeedGrow(size_t size, size_t buckets) noexcept {
+ return NeedGrow(size + 1, buckets);
+ }
+
+ static constexpr size_t EvalNewSize(size_t buckets) noexcept {
+ return buckets * 2;
+ }
+
+ static constexpr size_t SuitableSize(size_t size) noexcept {
+ return size * 2 + 1;
+ }
+};
+
+} // namespace NFlatHash
diff --git a/library/cpp/containers/flat_hash/lib/fuzz/dense_map_fuzz/fuzz.cpp b/library/cpp/containers/flat_hash/lib/fuzz/dense_map_fuzz/fuzz.cpp
new file mode 100644
index 0000000000..9b4cb4c983
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/fuzz/dense_map_fuzz/fuzz.cpp
@@ -0,0 +1,60 @@
+#include <library/cpp/containers/flat_hash/lib/map.h>
+#include <library/cpp/containers/flat_hash/lib/containers.h>
+#include <library/cpp/containers/flat_hash/lib/probings.h>
+#include <library/cpp/containers/flat_hash/lib/size_fitters.h>
+#include <library/cpp/containers/flat_hash/lib/expanders.h>
+
+#include <library/cpp/containers/flat_hash/lib/fuzz/fuzz_common/fuzz_common.h>
+
+#include <util/generic/hash.h>
+#include <util/generic/xrange.h>
+#include <util/generic/bt_exception.h>
+
+using namespace NFlatHash;
+
+namespace {
+
+template <class Key, class T>
+using TDenseModMap = NFlatHash::TMap<Key,
+ T,
+ THash<Key>,
+ std::equal_to<Key>,
+ TRemovalDenseContainer<std::pair<const Key, T>,
+ NMap::TEqValueMarker<Key, T>,
+ NMap::TEqValueMarker<Key, T>>,
+ TDenseProbing,
+ TAndSizeFitter,
+ TSimpleExpander>;
+
+NFuzz::EActionType EvalType(ui8 data) {
+ return static_cast<NFuzz::EActionType>((data >> 5) & 0b111);
+}
+
+ui8 EvalKey(ui8 data) {
+ return data & 0b11111;
+}
+
+ui8 EvalValue() {
+ return RandomNumber<ui8>();
+}
+
+} // namespace
+
+#include <util/datetime/base.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const ui8* const wireData, const size_t wireSize) {
+ THashMap<ui8, ui8> etalon;
+ // We assume, that markers can't be produced by EvalKey function.
+ TDenseModMap<ui8, ui8> testee(8,
+ (1 << 5), // Deleted marker
+ (1 << 6)); // Empty marker
+
+ for (auto i : xrange(wireSize)) {
+ auto data = wireData[i];
+
+ NFuzz::MakeAction(etalon, testee, EvalKey(data), EvalValue(), EvalType(data));
+ NFuzz::CheckInvariants(etalon, testee);
+ }
+
+ return 0;
+}
diff --git a/library/cpp/containers/flat_hash/lib/fuzz/dense_map_fuzz/ya.make b/library/cpp/containers/flat_hash/lib/fuzz/dense_map_fuzz/ya.make
new file mode 100644
index 0000000000..3a5d3d6d8c
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/fuzz/dense_map_fuzz/ya.make
@@ -0,0 +1,19 @@
+FUZZ()
+
+OWNER(
+ tender-bum
+)
+
+SRCS(
+ fuzz.cpp
+)
+
+PEERDIR(
+ library/cpp/containers/flat_hash/lib/fuzz/fuzz_common
+)
+
+SIZE(LARGE)
+
+TAG(ya:fat)
+
+END()
diff --git a/library/cpp/containers/flat_hash/lib/fuzz/flat_map_fuzz/fuzz.cpp b/library/cpp/containers/flat_hash/lib/fuzz/flat_map_fuzz/fuzz.cpp
new file mode 100644
index 0000000000..7fb73af0e9
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/fuzz/flat_map_fuzz/fuzz.cpp
@@ -0,0 +1,53 @@
+#include <library/cpp/containers/flat_hash/lib/map.h>
+#include <library/cpp/containers/flat_hash/lib/containers.h>
+#include <library/cpp/containers/flat_hash/lib/probings.h>
+#include <library/cpp/containers/flat_hash/lib/size_fitters.h>
+#include <library/cpp/containers/flat_hash/lib/expanders.h>
+
+#include <library/cpp/containers/flat_hash/lib/fuzz/fuzz_common/fuzz_common.h>
+
+#include <util/generic/hash.h>
+#include <util/generic/xrange.h>
+#include <util/generic/bt_exception.h>
+
+using namespace NFlatHash;
+
+namespace {
+
+template <class Key, class T>
+using TFlatLinearModMap = NFlatHash::TMap<Key,
+ T,
+ THash<Key>,
+ std::equal_to<Key>,
+ TFlatContainer<std::pair<const Key, T>>,
+ TLinearProbing,
+ TAndSizeFitter,
+ TSimpleExpander>;
+
+NFuzz::EActionType EvalType(ui8 data) {
+ return static_cast<NFuzz::EActionType>((data >> 5) & 0b111);
+}
+
+ui8 EvalKey(ui8 data) {
+ return data & 0b11111;
+}
+
+ui8 EvalValue() {
+ return RandomNumber<ui8>();
+}
+
+} // namespace
+
+extern "C" int LLVMFuzzerTestOneInput(const ui8* const wireData, const size_t wireSize) {
+ THashMap<ui8, ui8> etalon;
+ TFlatLinearModMap<ui8, ui8> testee;
+
+ for (auto i : xrange(wireSize)) {
+ auto data = wireData[i];
+
+ NFuzz::MakeAction(etalon, testee, EvalKey(data), EvalValue(), EvalType(data));
+ NFuzz::CheckInvariants(etalon, testee);
+ }
+
+ return 0;
+}
diff --git a/library/cpp/containers/flat_hash/lib/fuzz/flat_map_fuzz/ya.make b/library/cpp/containers/flat_hash/lib/fuzz/flat_map_fuzz/ya.make
new file mode 100644
index 0000000000..3a5d3d6d8c
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/fuzz/flat_map_fuzz/ya.make
@@ -0,0 +1,19 @@
+FUZZ()
+
+OWNER(
+ tender-bum
+)
+
+SRCS(
+ fuzz.cpp
+)
+
+PEERDIR(
+ library/cpp/containers/flat_hash/lib/fuzz/fuzz_common
+)
+
+SIZE(LARGE)
+
+TAG(ya:fat)
+
+END()
diff --git a/library/cpp/containers/flat_hash/lib/fuzz/fuzz_common/fuzz_common.cpp b/library/cpp/containers/flat_hash/lib/fuzz/fuzz_common/fuzz_common.cpp
new file mode 100644
index 0000000000..efc2973d18
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/fuzz/fuzz_common/fuzz_common.cpp
@@ -0,0 +1 @@
+#include "fuzz_common.h"
diff --git a/library/cpp/containers/flat_hash/lib/fuzz/fuzz_common/fuzz_common.h b/library/cpp/containers/flat_hash/lib/fuzz/fuzz_common/fuzz_common.h
new file mode 100644
index 0000000000..71a123d9cf
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/fuzz/fuzz_common/fuzz_common.h
@@ -0,0 +1,223 @@
+#pragma once
+
+#include <util/generic/bt_exception.h>
+#include <util/generic/vector.h>
+#include <util/generic/xrange.h>
+
+#include <util/random/random.h>
+
+namespace NFlatHash::NFuzz {
+
+#define FUZZ_ASSERT(cond) \
+ Y_ENSURE_EX(cond, TWithBackTrace<yexception>() << Y_STRINGIZE(cond) << " assertion failed ")
+
+#define FUZZ_ASSERT_THROW(cond, exc) \
+ try { \
+ cond; \
+ FUZZ_ASSERT(false); \
+ } catch (const exc&) { \
+ } catch (...) { \
+ FUZZ_ASSERT(false); \
+ }
+
+enum EActionType {
+ AT_INSERT,
+ AT_CLEAR,
+ AT_REHASH,
+ AT_ATOP,
+ AT_AT,
+ AT_ITERATORS,
+ AT_ERASE,
+ AT_FIND
+};
+
+template <class EtalonMap, class TesteeMap, class Key, class Value>
+void MakeAction(EtalonMap& etalon, TesteeMap& testee, Key&& key, Value&& value, EActionType type) {
+ switch (type) {
+ case AT_INSERT: {
+ auto itEt = etalon.insert({ key, value });
+ if (itEt.second) {
+ FUZZ_ASSERT(!testee.contains(key));
+ auto size = testee.size();
+ auto bucket_count = testee.bucket_count();
+
+ auto itTs = testee.insert(std::make_pair(key, value));
+ FUZZ_ASSERT(itTs.second);
+ FUZZ_ASSERT(itTs.first->first == key);
+ FUZZ_ASSERT(itTs.first->second == value);
+ FUZZ_ASSERT(size + 1 == testee.size());
+ FUZZ_ASSERT(bucket_count <= testee.bucket_count());
+ } else {
+ FUZZ_ASSERT(testee.contains(key));
+ auto size = testee.size();
+ auto bucket_count = testee.bucket_count();
+
+ auto itTs = testee.insert(std::make_pair(key, value));
+ FUZZ_ASSERT(!itTs.second);
+ FUZZ_ASSERT(itTs.first->first == key);
+ FUZZ_ASSERT(itTs.first->second == itEt.first->second);
+ FUZZ_ASSERT(size == testee.size());
+ FUZZ_ASSERT(bucket_count == testee.bucket_count());
+ }
+ break;
+ }
+ case AT_CLEAR: {
+ auto bucket_count = testee.bucket_count();
+ testee.clear();
+ for (const auto& v : etalon) {
+ FUZZ_ASSERT(!testee.contains(v.first));
+ }
+ FUZZ_ASSERT(testee.empty());
+ FUZZ_ASSERT(testee.size() == 0);
+ FUZZ_ASSERT(testee.bucket_count() == bucket_count);
+ FUZZ_ASSERT(testee.load_factor() < std::numeric_limits<float>::epsilon());
+
+ etalon.clear();
+ break;
+ }
+ case AT_REHASH: {
+ testee.rehash(key);
+ FUZZ_ASSERT(testee.bucket_count() >= key);
+ break;
+ }
+ case AT_ATOP: {
+ if (etalon.contains(key)) {
+ FUZZ_ASSERT(testee.contains(key));
+ auto size = testee.size();
+ auto bucket_count = testee.bucket_count();
+
+ FUZZ_ASSERT(testee[key] == etalon[key]);
+
+ FUZZ_ASSERT(size == testee.size());
+ FUZZ_ASSERT(bucket_count == testee.bucket_count());
+ } else {
+ FUZZ_ASSERT(!testee.contains(key));
+ auto size = testee.size();
+ auto bucket_count = testee.bucket_count();
+
+ FUZZ_ASSERT(testee[key] == etalon[key]);
+
+ FUZZ_ASSERT(size + 1 == testee.size());
+ FUZZ_ASSERT(bucket_count <= testee.bucket_count());
+ }
+ auto size = testee.size();
+ auto bucket_count = testee.bucket_count();
+
+ etalon[key] = value;
+ testee[key] = value;
+ FUZZ_ASSERT(testee[key] == etalon[key]);
+ FUZZ_ASSERT(testee[key] == value);
+
+ FUZZ_ASSERT(size == testee.size());
+ FUZZ_ASSERT(bucket_count == testee.bucket_count());
+ break;
+ }
+ case AT_AT: {
+ auto size = testee.size();
+ auto bucket_count = testee.bucket_count();
+ if (etalon.contains(key)) {
+ FUZZ_ASSERT(testee.contains(key));
+
+ FUZZ_ASSERT(testee.at(key) == etalon.at(key));
+ testee.at(key) = value;
+ etalon.at(key) = value;
+ FUZZ_ASSERT(testee.at(key) == etalon.at(key));
+ } else {
+ FUZZ_ASSERT(!testee.contains(key));
+ FUZZ_ASSERT_THROW(testee.at(key) = value, std::out_of_range);
+ FUZZ_ASSERT(!testee.contains(key));
+ }
+ FUZZ_ASSERT(size == testee.size());
+ FUZZ_ASSERT(bucket_count == testee.bucket_count());
+ break;
+ }
+ case AT_ITERATORS: {
+ auto itBeginTs = testee.begin();
+ auto itEndTs = testee.end();
+ FUZZ_ASSERT((size_t)std::distance(itBeginTs, itEndTs) == testee.size());
+ FUZZ_ASSERT(std::distance(itBeginTs, itEndTs) ==
+ std::distance(etalon.begin(), etalon.end()));
+ FUZZ_ASSERT(std::distance(testee.cbegin(), testee.cend()) ==
+ std::distance(etalon.cbegin(), etalon.cend()));
+ break;
+ }
+ case AT_ERASE: {
+ if (etalon.contains(key)) {
+ FUZZ_ASSERT(testee.contains(key));
+ auto size = testee.size();
+ auto bucket_count = testee.bucket_count();
+
+ auto itTs = testee.find(key);
+ FUZZ_ASSERT(itTs->first == key);
+ FUZZ_ASSERT(itTs->second == etalon.at(key));
+
+ testee.erase(itTs);
+ FUZZ_ASSERT(size - 1 == testee.size());
+ FUZZ_ASSERT(bucket_count == testee.bucket_count());
+ etalon.erase(key);
+ } else {
+ FUZZ_ASSERT(!testee.contains(key));
+ }
+ break;
+ }
+ case AT_FIND: {
+ auto itEt = etalon.find(key);
+ if (itEt != etalon.end()) {
+ FUZZ_ASSERT(testee.contains(key));
+
+ auto itTs = testee.find(key);
+ FUZZ_ASSERT(itTs != testee.end());
+ FUZZ_ASSERT(itTs->first == key);
+ FUZZ_ASSERT(itTs->second == itEt->second);
+
+ itTs->second = value;
+ itEt->second = value;
+ } else {
+ FUZZ_ASSERT(!testee.contains(key));
+
+ auto itTs = testee.find(key);
+ FUZZ_ASSERT(itTs == testee.end());
+ }
+ break;
+ }
+ };
+}
+
+template <class EtalonMap, class TesteeMap>
+void CheckInvariants(const EtalonMap& etalon, const TesteeMap& testee) {
+ using value_type = std::pair<typename TesteeMap::key_type,
+ typename TesteeMap::mapped_type>;
+ using size_type = typename TesteeMap::size_type;
+
+ TVector<value_type> etalonVals{ etalon.begin(), etalon.end() };
+ std::sort(etalonVals.begin(), etalonVals.end());
+ TVector<value_type> testeeVals{ testee.begin(), testee.end() };
+ std::sort(testeeVals.begin(), testeeVals.end());
+
+ FUZZ_ASSERT(testeeVals == etalonVals);
+
+ FUZZ_ASSERT(testee.size() == etalon.size());
+ FUZZ_ASSERT(testee.empty() == etalon.empty());
+ FUZZ_ASSERT(testee.load_factor() < 0.5f + std::numeric_limits<float>::epsilon());
+ FUZZ_ASSERT(testee.bucket_count() > testee.size());
+
+ size_type buckets = 0;
+ for (auto b : xrange(testee.bucket_count())) {
+ buckets += testee.bucket_size(b);
+ }
+ FUZZ_ASSERT(buckets == testee.size());
+
+ for (const auto& v : etalon) {
+ auto key = v.first;
+ auto value = v.second;
+
+ FUZZ_ASSERT(testee.contains(key));
+ FUZZ_ASSERT(testee.count(key) == 1);
+
+ auto it = testee.find(key);
+ FUZZ_ASSERT(it->first == key);
+ FUZZ_ASSERT(it->second == value);
+ }
+}
+
+} // namespace NFlatHash::NFuzz
diff --git a/library/cpp/containers/flat_hash/lib/fuzz/fuzz_common/ya.make b/library/cpp/containers/flat_hash/lib/fuzz/fuzz_common/ya.make
new file mode 100644
index 0000000000..ecb590e116
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/fuzz/fuzz_common/ya.make
@@ -0,0 +1,11 @@
+LIBRARY()
+
+OWNER(tender-bum)
+
+SRCS(fuzz_common.cpp)
+
+PEERDIR(
+ library/cpp/containers/flat_hash/lib
+)
+
+END()
diff --git a/library/cpp/containers/flat_hash/lib/fuzz/ya.make b/library/cpp/containers/flat_hash/lib/fuzz/ya.make
new file mode 100644
index 0000000000..dbf2183be5
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/fuzz/ya.make
@@ -0,0 +1,7 @@
+OWNER(tender-bum)
+
+RECURSE(
+ flat_map_fuzz
+ dense_map_fuzz
+ fuzz_common
+)
diff --git a/library/cpp/containers/flat_hash/lib/iterator.cpp b/library/cpp/containers/flat_hash/lib/iterator.cpp
new file mode 100644
index 0000000000..7c5c206cc3
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/iterator.cpp
@@ -0,0 +1 @@
+#include "iterator.h"
diff --git a/library/cpp/containers/flat_hash/lib/iterator.h b/library/cpp/containers/flat_hash/lib/iterator.h
new file mode 100644
index 0000000000..f6b1e74355
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/iterator.h
@@ -0,0 +1,99 @@
+#pragma once
+
+#include "concepts/container.h"
+
+#include <util/system/yassert.h>
+
+#include <iterator>
+
+namespace NFlatHash {
+
+template <class Container, class T>
+class TIterator {
+private:
+ static_assert(NConcepts::ContainerV<std::decay_t<Container>>);
+
+public:
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = T;
+ using difference_type = ptrdiff_t;
+ using pointer = typename std::add_pointer<T>::type;
+ using reference = typename std::add_lvalue_reference<T>::type;
+
+private:
+ using size_type = typename Container::size_type;
+
+public:
+ TIterator(Container* cont)
+ : Cont_(cont)
+ , Idx_(0)
+ {
+ if (!cont->IsTaken(Idx_)) {
+ Next();
+ }
+ }
+
+ TIterator(Container* cont, size_type idx)
+ : Cont_(cont)
+ , Idx_(idx) {}
+
+ template <class C, class U, class = std::enable_if_t<std::is_convertible<C*, Container*>::value &&
+ std::is_convertible<U, T>::value>>
+ TIterator(const TIterator<C, U>& rhs)
+ : Cont_(rhs.Cont_)
+ , Idx_(rhs.Idx_) {}
+
+ TIterator(const TIterator&) = default;
+
+ TIterator& operator=(const TIterator&) = default;
+
+ TIterator& operator++() {
+ Next();
+ return *this;
+ }
+ TIterator operator++(int) {
+ auto idx = Idx_;
+ Next();
+ return { Cont_, idx };
+ }
+
+ reference operator*() {
+ return Cont_->Node(Idx_);
+ }
+
+ pointer operator->() {
+ return &Cont_->Node(Idx_);
+ }
+
+ const pointer operator->() const {
+ return &Cont_->Node(Idx_);
+ }
+
+ bool operator==(const TIterator& rhs) const noexcept {
+ Y_ASSERT(Cont_ == rhs.Cont_);
+ return Idx_ == rhs.Idx_;
+ }
+
+ bool operator!=(const TIterator& rhs) const noexcept {
+ return !operator==(rhs);
+ }
+
+private:
+ void Next() {
+ // Container provider ensures that it's not empty.
+ do {
+ ++Idx_;
+ } while (Idx_ != Cont_->Size() && !Cont_->IsTaken(Idx_));
+ }
+
+private:
+ template <class C, class U>
+ friend class TIterator;
+
+ Container* Cont_ = nullptr;
+
+protected:
+ size_type Idx_ = 0;
+};
+
+} // namespace NFlatHash
diff --git a/library/cpp/containers/flat_hash/lib/map.cpp b/library/cpp/containers/flat_hash/lib/map.cpp
new file mode 100644
index 0000000000..b323fbb46d
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/map.cpp
@@ -0,0 +1 @@
+#include "map.h"
diff --git a/library/cpp/containers/flat_hash/lib/map.h b/library/cpp/containers/flat_hash/lib/map.h
new file mode 100644
index 0000000000..f77c318a61
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/map.h
@@ -0,0 +1,233 @@
+#pragma once
+
+#include "table.h"
+#include "concepts/iterator.h"
+
+#include <util/generic/algorithm.h>
+#include <util/generic/mapfindptr.h>
+
+namespace NFlatHash {
+
+namespace NPrivate {
+
+struct TMapKeyGetter {
+ template <class T>
+ static constexpr auto& Apply(T& t) noexcept { return t.first; };
+
+ template <class T>
+ static constexpr const auto& Apply(const T& t) noexcept { return t.first; };
+};
+
+} // namespace NPrivate
+
+template <class Key,
+ class T,
+ class Hash,
+ class KeyEqual,
+ class Container,
+ class Probing,
+ class SizeFitter,
+ class Expander>
+class TMap : private TTable<Hash,
+ KeyEqual,
+ Container,
+ NPrivate::TMapKeyGetter,
+ Probing,
+ SizeFitter,
+ Expander>,
+ public TMapOps<TMap<Key,
+ T,
+ Hash,
+ KeyEqual,
+ Container,
+ Probing,
+ SizeFitter,
+ Expander>>
+{
+private:
+ using TBase = TTable<Hash,
+ KeyEqual,
+ Container,
+ NPrivate::TMapKeyGetter,
+ Probing,
+ SizeFitter,
+ Expander>;
+
+ static_assert(std::is_same<std::pair<const Key, T>, typename Container::value_type>::value);
+
+public:
+ using key_type = Key;
+ using mapped_type = T;
+ using typename TBase::value_type;
+ using typename TBase::size_type;
+ using typename TBase::difference_type;
+ using typename TBase::hasher;
+ using typename TBase::key_equal;
+ using typename TBase::reference;
+ using typename TBase::const_reference;
+ using typename TBase::iterator;
+ using typename TBase::const_iterator;
+ using typename TBase::allocator_type;
+ using typename TBase::pointer;
+ using typename TBase::const_pointer;
+
+private:
+ static constexpr size_type INIT_SIZE = 8;
+
+public:
+ TMap() : TBase(INIT_SIZE) {}
+
+ template <class... Rest>
+ TMap(size_type initSize, Rest&&... rest) : TBase(initSize, std::forward<Rest>(rest)...) {}
+
+ template <class I, class... Rest>
+ TMap(I first, I last,
+ std::enable_if_t<NConcepts::IteratorV<I>, size_type> initSize = INIT_SIZE,
+ Rest&&... rest)
+ : TBase(initSize, std::forward<Rest>(rest)...)
+ {
+ insert(first, last);
+ }
+
+ template <class... Rest>
+ TMap(std::initializer_list<value_type> il, size_type initSize = INIT_SIZE, Rest&&... rest)
+ : TBase(initSize, std::forward<Rest>(rest)...)
+ {
+ insert(il.begin(), il.end());
+ }
+
+ TMap(std::initializer_list<value_type> il, size_type initSize = INIT_SIZE)
+ : TBase(initSize)
+ {
+ insert(il.begin(), il.end());
+ }
+
+ TMap(const TMap&) = default;
+ TMap(TMap&&) = default;
+
+ TMap& operator=(const TMap&) = default;
+ TMap& operator=(TMap&&) = default;
+
+ // Iterators
+ using TBase::begin;
+ using TBase::cbegin;
+ using TBase::end;
+ using TBase::cend;
+
+ // Capacity
+ using TBase::empty;
+ using TBase::size;
+
+ // Modifiers
+ using TBase::clear;
+ using TBase::insert;
+ using TBase::emplace;
+ using TBase::emplace_hint;
+ using TBase::erase;
+ using TBase::swap;
+
+ template <class V>
+ std::pair<iterator, bool> insert_or_assign(const key_type& k, V&& v) {
+ return InsertOrAssignImpl(k, std::forward<V>(v));
+ }
+ template <class V>
+ std::pair<iterator, bool> insert_or_assign(key_type&& k, V&& v) {
+ return InsertOrAssignImpl(std::move(k), std::forward<V>(v));
+ }
+
+ template <class V>
+ iterator insert_or_assign(const_iterator, const key_type& k, V&& v) { // TODO(tender-bum)
+ return insert_or_assign(k, std::forward<V>(v)).first;
+ }
+ template <class V>
+ iterator insert_or_assign(const_iterator, key_type&& k, V&& v) { // TODO(tender-bum)
+ return insert_or_assign(std::move(k), std::forward<V>(v)).first;
+ }
+
+ template <class... Args>
+ std::pair<iterator, bool> try_emplace(const key_type& key, Args&&... args) {
+ return TryEmplaceImpl(key, std::forward<Args>(args)...);
+ }
+ template <class... Args>
+ std::pair<iterator, bool> try_emplace(key_type&& key, Args&&... args) {
+ return TryEmplaceImpl(std::move(key), std::forward<Args>(args)...);
+ }
+
+ template <class... Args>
+ iterator try_emplace(const_iterator, const key_type& key, Args&&... args) { // TODO(tender-bum)
+ return try_emplace(key, std::forward<Args>(args)...).first;
+ }
+ template <class... Args>
+ iterator try_emplace(const_iterator, key_type&& key, Args&&... args) { // TODO(tender-bum)
+ return try_emplace(std::move(key), std::forward<Args>(args)...).first;
+ }
+
+ // Lookup
+ using TBase::count;
+ using TBase::find;
+ using TBase::contains;
+
+ template <class K>
+ mapped_type& at(const K& key) {
+ auto it = find(key);
+ if (it == end()) {
+ throw std::out_of_range{ "no such key in map" };
+ }
+ return it->second;
+ }
+
+ template <class K>
+ const mapped_type& at(const K& key) const { return const_cast<TMap*>(this)->at(key); }
+
+ template <class K>
+ Y_FORCE_INLINE mapped_type& operator[](K&& key) {
+ return TBase::TryCreate(key, [&](size_type idx) {
+ TBase::Buckets_.InitNode(idx, std::forward<K>(key), mapped_type{});
+ }).first->second;
+ }
+
+ // Bucket interface
+ using TBase::bucket_count;
+ using TBase::bucket_size;
+
+ // Hash policy
+ using TBase::load_factor;
+ using TBase::rehash;
+ using TBase::reserve;
+
+ // Observers
+ using TBase::hash_function;
+ using TBase::key_eq;
+
+ friend bool operator==(const TMap& lhs, const TMap& rhs) {
+ return lhs.size() == rhs.size() && AllOf(lhs, [&rhs](const auto& v) {
+ auto it = rhs.find(v.first);
+ return it != rhs.end() && *it == v;
+ });
+ }
+
+ friend bool operator!=(const TMap& lhs, const TMap& rhs) { return !(lhs == rhs); }
+
+private:
+ template <class K, class... Args>
+ std::pair<iterator, bool> TryEmplaceImpl(K&& key, Args&&... args) {
+ return TBase::TryCreate(key, [&](size_type idx) {
+ TBase::Buckets_.InitNode(
+ idx,
+ std::piecewise_construct,
+ std::forward_as_tuple(std::forward<K>(key)),
+ std::forward_as_tuple(std::forward<Args>(args)...));
+ });
+ }
+
+ template <class K, class V>
+ std::pair<iterator, bool> InsertOrAssignImpl(K&& key, V&& v) {
+ auto p = try_emplace(std::forward<K>(key), std::forward<V>(v));
+ if (!p.second) {
+ p.first->second = std::forward<V>(v);
+ }
+ return p;
+ }
+};
+
+} // namespace NFlatHash
diff --git a/library/cpp/containers/flat_hash/lib/probings.cpp b/library/cpp/containers/flat_hash/lib/probings.cpp
new file mode 100644
index 0000000000..f10c6af113
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/probings.cpp
@@ -0,0 +1 @@
+#include "probings.h"
diff --git a/library/cpp/containers/flat_hash/lib/probings.h b/library/cpp/containers/flat_hash/lib/probings.h
new file mode 100644
index 0000000000..886be59cff
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/probings.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <type_traits>
+
+namespace NFlatHash {
+
+class TLinearProbing {
+public:
+ template <class SizeFitter, class F>
+ static auto FindBucket(SizeFitter sf, size_t idx, size_t sz, F f) {
+ idx = sf.EvalIndex(idx, sz);
+ while (!f(idx)) {
+ idx = sf.EvalIndex(++idx, sz);
+ }
+ return idx;
+ }
+};
+
+class TQuadraticProbing {
+public:
+ template <class SizeFitter, class F>
+ static auto FindBucket(SizeFitter sf, size_t idx, size_t sz, F f) {
+ idx = sf.EvalIndex(idx, sz);
+ size_t k = 0;
+ while (!f(idx)) {
+ idx = sf.EvalIndex(idx + 2 * ++k - 1, sz);
+ }
+ return idx;
+ }
+};
+
+class TDenseProbing {
+public:
+ template <class SizeFitter, class F>
+ static auto FindBucket(SizeFitter sf, size_t idx, size_t sz, F f) {
+ idx = sf.EvalIndex(idx, sz);
+ size_t k = 0;
+ while (!f(idx)) {
+ idx = sf.EvalIndex(idx + ++k, sz);
+ }
+ return idx;
+ }
+};
+
+} // NFlatHash
diff --git a/library/cpp/containers/flat_hash/lib/set.cpp b/library/cpp/containers/flat_hash/lib/set.cpp
new file mode 100644
index 0000000000..aa2f9c58e1
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/set.cpp
@@ -0,0 +1 @@
+#include "set.h"
diff --git a/library/cpp/containers/flat_hash/lib/set.h b/library/cpp/containers/flat_hash/lib/set.h
new file mode 100644
index 0000000000..5266293c6c
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/set.h
@@ -0,0 +1,147 @@
+#pragma once
+
+#include "table.h"
+#include "concepts/iterator.h"
+
+#include <util/generic/algorithm.h>
+
+namespace NFlatHash {
+
+namespace NPrivate {
+
+struct TSimpleKeyGetter {
+ template <class T>
+ static constexpr auto& Apply(T& t) noexcept { return t; };
+
+ template <class T>
+ static constexpr const auto& Apply(const T& t) noexcept { return t; };
+};
+
+} // namespace NPrivate
+
+template <class Key,
+ class Hash,
+ class KeyEqual,
+ class Container,
+ class Probing,
+ class SizeFitter,
+ class Expander>
+class TSet : private TTable<Hash,
+ KeyEqual,
+ Container,
+ NPrivate::TSimpleKeyGetter,
+ Probing,
+ SizeFitter,
+ Expander,
+ std::add_const>
+{
+private:
+ using TBase = TTable<Hash,
+ KeyEqual,
+ Container,
+ NPrivate::TSimpleKeyGetter,
+ Probing,
+ SizeFitter,
+ Expander,
+ std::add_const>;
+
+ static_assert(std::is_same_v<Key, typename Container::value_type>);
+
+public:
+ using key_type = Key;
+ using typename TBase::value_type;
+ using typename TBase::size_type;
+ using typename TBase::difference_type;
+ using typename TBase::hasher;
+ using typename TBase::key_equal;
+ using typename TBase::reference;
+ using typename TBase::const_reference;
+ using typename TBase::iterator;
+ using typename TBase::const_iterator;
+ using typename TBase::allocator_type;
+ using typename TBase::pointer;
+ using typename TBase::const_pointer;
+
+private:
+ static constexpr size_type INIT_SIZE = 8;
+
+public:
+ TSet() : TBase(INIT_SIZE) {}
+
+ template <class... Rest>
+ TSet(size_type initSize, Rest&&... rest) : TBase(initSize, std::forward<Rest>(rest)...) {}
+
+ template <class I, class... Rest>
+ TSet(I first, I last,
+ std::enable_if_t<NConcepts::IteratorV<I>, size_type> initSize = INIT_SIZE,
+ Rest&&... rest)
+ : TBase(initSize, std::forward<Rest>(rest)...)
+ {
+ insert(first, last);
+ }
+
+ template <class... Rest>
+ TSet(std::initializer_list<value_type> il, size_type initSize = INIT_SIZE, Rest&&... rest)
+ : TBase(initSize, std::forward<Rest>(rest)...)
+ {
+ insert(il.begin(), il.end());
+ }
+
+ TSet(std::initializer_list<value_type> il, size_type initSize = INIT_SIZE)
+ : TBase(initSize)
+ {
+ insert(il.begin(), il.end());
+ }
+
+ TSet(const TSet&) = default;
+ TSet(TSet&&) = default;
+
+ TSet& operator=(const TSet&) = default;
+ TSet& operator=(TSet&&) = default;
+
+ // Iterators
+ using TBase::begin;
+ using TBase::cbegin;
+ using TBase::end;
+ using TBase::cend;
+
+ // Capacity
+ using TBase::empty;
+ using TBase::size;
+
+ // Modifiers
+ using TBase::clear;
+ using TBase::insert;
+ using TBase::emplace;
+ using TBase::emplace_hint;
+ using TBase::erase;
+ using TBase::swap;
+
+ // Lookup
+ using TBase::count;
+ using TBase::find;
+ using TBase::contains;
+
+ // Bucket interface
+ using TBase::bucket_count;
+ using TBase::bucket_size;
+
+ // Hash policy
+ using TBase::load_factor;
+ using TBase::rehash;
+ using TBase::reserve;
+
+ // Observers
+ using TBase::hash_function;
+ using TBase::key_eq;
+
+ friend bool operator==(const TSet& lhs, const TSet& rhs) {
+ return lhs.size() == rhs.size() && AllOf(lhs, [&rhs](const auto& v) {
+ return rhs.contains(v);
+ });
+ }
+
+ friend bool operator!=(const TSet& lhs, const TSet& rhs) { return !(lhs == rhs); }
+};
+
+} // namespace NFlatHash
diff --git a/library/cpp/containers/flat_hash/lib/size_fitters.cpp b/library/cpp/containers/flat_hash/lib/size_fitters.cpp
new file mode 100644
index 0000000000..f1431c27e3
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/size_fitters.cpp
@@ -0,0 +1 @@
+#include "size_fitters.h"
diff --git a/library/cpp/containers/flat_hash/lib/size_fitters.h b/library/cpp/containers/flat_hash/lib/size_fitters.h
new file mode 100644
index 0000000000..86bd617342
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/size_fitters.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "concepts/size_fitter.h"
+
+#include <util/system/yassert.h>
+#include <util/generic/bitops.h>
+
+namespace NFlatHash {
+
+class TAndSizeFitter {
+public:
+ size_t EvalIndex(size_t hs, size_t sz) const noexcept {
+ Y_ASSERT(Mask_ == sz - 1);
+ return (hs & Mask_);
+ }
+
+ size_t EvalSize(size_t sz) const noexcept {
+ return FastClp2(sz);
+ }
+
+ void Update(size_t sz) noexcept {
+ Y_ASSERT((sz & (sz - 1)) == 0);
+ Mask_ = sz - 1;
+ }
+
+private:
+ size_t Mask_ = 0;
+};
+
+static_assert(NConcepts::SizeFitterV<TAndSizeFitter>);
+
+class TModSizeFitter {
+public:
+ constexpr size_t EvalIndex(size_t hs, size_t sz) const noexcept {
+ return hs % sz;
+ }
+
+ constexpr size_t EvalSize(size_t sz) const noexcept {
+ return sz;
+ }
+
+ constexpr void Update(size_t) noexcept {}
+};
+
+static_assert(NConcepts::SizeFitterV<TModSizeFitter>);
+
+} // NFlatHash
diff --git a/library/cpp/containers/flat_hash/lib/table.cpp b/library/cpp/containers/flat_hash/lib/table.cpp
new file mode 100644
index 0000000000..e89d72ad94
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/table.cpp
@@ -0,0 +1 @@
+#include "table.h"
diff --git a/library/cpp/containers/flat_hash/lib/table.h b/library/cpp/containers/flat_hash/lib/table.h
new file mode 100644
index 0000000000..b84a052be7
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/table.h
@@ -0,0 +1,314 @@
+#pragma once
+
+#include "iterator.h"
+#include "concepts/container.h"
+#include "concepts/size_fitter.h"
+
+#include <util/generic/utility.h>
+
+#include <functional>
+
+namespace NFlatHash {
+
+namespace NPrivate {
+
+template <class T>
+struct TTypeIdentity { using type = T; };
+
+} // namespace NPrivate
+
+template <
+ class Hash,
+ class KeyEqual,
+ class Container,
+ class KeyGetter,
+ class Probing,
+ class SizeFitter,
+ class Expander,
+ // Used in the TSet to make iterator behave as const_iterator
+ template <class> class IteratorModifier = NPrivate::TTypeIdentity>
+class TTable {
+private:
+ static_assert(NConcepts::ContainerV<Container>);
+ static_assert(NConcepts::SizeFitterV<SizeFitter>);
+
+ template <class C, class V>
+ class TIteratorImpl : public TIterator<C, V> {
+ private:
+ using TBase = TIterator<C, V>;
+ friend class TTable;
+
+ using TBase::TBase;
+
+ public:
+ TIteratorImpl() : TBase(nullptr, 0) {}
+ };
+
+public:
+ using value_type = typename Container::value_type;
+ using size_type = typename Container::size_type;
+ using difference_type = typename Container::difference_type;
+ using hasher = Hash;
+ using key_equal = KeyEqual;
+
+ using reference = value_type&;
+ using const_reference = const value_type&;
+
+ using iterator = TIteratorImpl<typename IteratorModifier<Container>::type,
+ typename IteratorModifier<value_type>::type>;
+ using const_iterator = TIteratorImpl<const Container, const value_type>;
+ using allocator_type = typename Container::allocator_type;
+ using pointer = typename Container::pointer;
+ using const_pointer = typename Container::const_pointer;
+
+private:
+ TTable(Container buckets)
+ : Buckets_(std::move(buckets))
+ {
+ SizeFitter_.Update(bucket_count());
+ }
+
+ static constexpr size_type INIT_SIZE = 8;
+
+public:
+ template <class... Rest>
+ TTable(size_type initSize, Rest&&... rest)
+ : Buckets_(initSize == 0 ? INIT_SIZE : SizeFitter_.EvalSize(initSize),
+ std::forward<Rest>(rest)...)
+ {
+ SizeFitter_.Update(bucket_count());
+ }
+
+ TTable(const TTable&) = default;
+ TTable(TTable&& rhs)
+ : SizeFitter_(std::move(rhs.SizeFitter_))
+ , Buckets_(std::move(rhs.Buckets_))
+ , Hasher_(std::move(rhs.Hasher_))
+ , KeyEqual_(std::move(rhs.KeyEqual_))
+ {
+ TTable tmp{ Buckets_.Clone(INIT_SIZE) };
+ tmp.swap(rhs);
+ }
+
+ TTable& operator=(const TTable&) = default;
+ TTable& operator=(TTable&& rhs) {
+ TTable tmp(std::move(rhs));
+ swap(tmp);
+ return *this;
+ }
+
+ // Iterators
+ iterator begin() { return &Buckets_; }
+ const_iterator begin() const { return const_cast<TTable*>(this)->begin(); }
+ const_iterator cbegin() const { return begin(); }
+
+ iterator end() { return { &Buckets_, bucket_count() }; }
+ const_iterator end() const { return const_cast<TTable*>(this)->end(); }
+ const_iterator cend() const { return end(); }
+
+ // Capacity
+ bool empty() const noexcept { return size() == 0; }
+ size_type size() const noexcept { return Buckets_.Taken(); }
+
+ // Modifiers
+ void clear() {
+ Container tmp(Buckets_.Clone(bucket_count()));
+ Buckets_.Swap(tmp);
+ }
+
+ std::pair<iterator, bool> insert(const value_type& value) { return InsertImpl(value); }
+ std::pair<iterator, bool> insert(value_type&& value) { return InsertImpl(std::move(value)); }
+
+ template <class T>
+ std::enable_if_t<!std::is_same_v<std::decay_t<T>, value_type>,
+ std::pair<iterator, bool>> insert(T&& value) {
+ return insert(value_type(std::forward<T>(value)));
+ }
+
+ iterator insert(const_iterator, const value_type& value) { // TODO(tender-bum)
+ return insert(value).first;
+ }
+ iterator insert(const_iterator, value_type&& value) { // TODO(tender-bum)
+ return insert(std::move(value)).first;
+ }
+
+ template <class T>
+ iterator insert(const_iterator, T&& value) { // TODO(tender-bum)
+ return insert(value_type(std::forward<T>(value))).first;
+ }
+
+ template <class InputIt>
+ void insert(InputIt first, InputIt last) {
+ while (first != last) {
+ insert(*first++);
+ }
+ }
+
+ void insert(std::initializer_list<value_type> il) {
+ insert(il.begin(), il.end());
+ }
+
+ template <class... Args>
+ std::pair<iterator, bool> emplace(Args&&... args) {
+ return insert(value_type(std::forward<Args>(args)...));
+ }
+
+ template <class... Args>
+ iterator emplace_hint(const_iterator, Args&&... args) { // TODO(tender-bum)
+ return emplace(std::forward<Args>(args)...).first;
+ }
+
+ void erase(const_iterator pos) {
+ static_assert(NConcepts::RemovalContainerV<Container>,
+ "That kind of table doesn't allow erasing. Use another table instead.");
+ if constexpr (NConcepts::RemovalContainerV<Container>) {
+ Buckets_.DeleteNode(pos.Idx_);
+ }
+ }
+
+ void erase(const_iterator f, const_iterator l) {
+ while (f != l) {
+ auto nxt = f;
+ ++nxt;
+ erase(f);
+ f = nxt;
+ }
+ }
+
+ template <class K>
+ std::enable_if_t<!std::is_convertible_v<K, iterator> && !std::is_convertible_v<K, const_iterator>,
+ size_type> erase(const K& key) {
+ auto it = find(key);
+ if (it != end()) {
+ erase(it);
+ return 1;
+ }
+ return 0;
+ }
+
+ void swap(TTable& rhs)
+ noexcept(noexcept(std::declval<Container>().Swap(std::declval<Container&>())))
+ {
+ DoSwap(SizeFitter_, rhs.SizeFitter_);
+ Buckets_.Swap(rhs.Buckets_);
+ DoSwap(Hasher_, rhs.Hasher_);
+ DoSwap(KeyEqual_, rhs.KeyEqual_);
+ }
+
+ // Lookup
+ template <class K>
+ size_type count(const K& key) const { return contains(key); }
+
+ template <class K>
+ iterator find(const K& key) {
+ size_type hs = hash_function()(key);
+ auto idx = FindProperBucket(hs, key);
+ if (Buckets_.IsTaken(idx)) {
+ return { &Buckets_, idx };
+ }
+ return end();
+ }
+
+ template <class K>
+ const_iterator find(const K& key) const { return const_cast<TTable*>(this)->find(key); }
+
+ template <class K>
+ bool contains(const K& key) const {
+ size_type hs = hash_function()(key);
+ return Buckets_.IsTaken(FindProperBucket(hs, key));
+ }
+
+ // Bucket interface
+ size_type bucket_count() const noexcept { return Buckets_.Size(); }
+ size_type bucket_size(size_type idx) const { return Buckets_.IsTaken(idx); }
+
+ // Hash policy
+ float load_factor() const noexcept {
+ return (float)(bucket_count() - Buckets_.Empty()) / bucket_count();
+ }
+
+ void rehash(size_type sz) {
+ if (sz != 0) {
+ auto newBuckets = SizeFitter_.EvalSize(sz);
+ size_type occupied = bucket_count() - Buckets_.Empty();
+ if (Expander::NeedGrow(occupied, newBuckets)) {
+ newBuckets = Max(newBuckets, SizeFitter_.EvalSize(Expander::SuitableSize(size())));
+ }
+ RehashImpl(newBuckets);
+ } else {
+ RehashImpl(SizeFitter_.EvalSize(Expander::SuitableSize(size())));
+ }
+ }
+
+ void reserve(size_type sz) { rehash(sz); } // TODO(tender-bum)
+
+ // Observers
+ constexpr auto hash_function() const noexcept { return Hasher_; }
+ constexpr auto key_eq() const noexcept { return KeyEqual_; }
+
+public:
+ template <class T>
+ std::pair<iterator, bool> InsertImpl(T&& value) {
+ return TryCreate(KeyGetter::Apply(value), [&](size_type idx) {
+ Buckets_.InitNode(idx, std::forward<T>(value));
+ });
+ }
+
+ template <class T, class F>
+ Y_FORCE_INLINE std::pair<iterator, bool> TryCreate(const T& key, F nodeInit) {
+ size_type hs = hash_function()(key);
+ size_type idx = FindProperBucket(hs, key);
+ if (!Buckets_.IsTaken(idx)) {
+ if (Expander::WillNeedGrow(bucket_count() - Buckets_.Empty(), bucket_count())) {
+ RehashImpl();
+ idx = FindProperBucket(hs, key);
+ }
+ nodeInit(idx);
+ return { iterator{ &Buckets_, idx }, true };
+ }
+ return { iterator{ &Buckets_, idx }, false };
+ }
+
+ template <class K>
+ size_type FindProperBucket(size_type hs, const K& key) const {
+ return Probing::FindBucket(SizeFitter_, hs, bucket_count(), [&](size_type idx) {
+ if constexpr (NConcepts::RemovalContainerV<Container>) {
+ return Buckets_.IsEmpty(idx) ||
+ Buckets_.IsTaken(idx) && key_eq()(KeyGetter::Apply(Buckets_.Node(idx)), key);
+ } else {
+ return Buckets_.IsEmpty(idx) || key_eq()(KeyGetter::Apply(Buckets_.Node(idx)), key);
+ }
+ });
+ }
+
+ void RehashImpl() {
+ if constexpr (NConcepts::RemovalContainerV<Container>) {
+ size_type occupied = bucket_count() - Buckets_.Empty();
+ if (size() < occupied / 2) {
+ rehash(bucket_count()); // Just clearing all deleted elements
+ } else {
+ RehashImpl(SizeFitter_.EvalSize(Expander::EvalNewSize(bucket_count())));
+ }
+ } else {
+ RehashImpl(SizeFitter_.EvalSize(Expander::EvalNewSize(bucket_count())));
+ }
+ }
+
+ void RehashImpl(size_type newSize) {
+ TTable tmp = Buckets_.Clone(newSize);
+ for (auto& value : *this) {
+ size_type hs = hash_function()(KeyGetter::Apply(value));
+ tmp.Buckets_.InitNode(
+ tmp.FindProperBucket(hs, KeyGetter::Apply(value)), std::move_if_noexcept(value));
+ }
+ swap(tmp);
+ }
+
+public:
+ SizeFitter SizeFitter_;
+ Container Buckets_;
+ hasher Hasher_;
+ key_equal KeyEqual_;
+};
+
+} // namespace NFlatHash
diff --git a/library/cpp/containers/flat_hash/lib/ut/containers_ut.cpp b/library/cpp/containers/flat_hash/lib/ut/containers_ut.cpp
new file mode 100644
index 0000000000..b17b30fa80
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/ut/containers_ut.cpp
@@ -0,0 +1,410 @@
+#include <library/cpp/containers/flat_hash/lib/containers.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/algorithm.h>
+#include <util/random/random.h>
+#include <util/random/shuffle.h>
+
+using namespace NFlatHash;
+
+namespace {
+ constexpr size_t INIT_SIZE = 128;
+
+ struct TDummy {
+ static size_t Count;
+
+ TDummy() { ++Count; }
+ TDummy(const TDummy&) { ++Count; }
+ ~TDummy() { --Count; }
+ };
+ size_t TDummy::Count = 0;
+
+ struct TAlmostDummy {
+ static size_t Count;
+
+ TAlmostDummy(int j = 0) : Junk(j) { ++Count; }
+ TAlmostDummy(const TAlmostDummy& d) : Junk(d.Junk) { ++Count; }
+ ~TAlmostDummy() { --Count; }
+
+ bool operator==(const TAlmostDummy& r) const { return Junk == r.Junk; };
+ bool operator!=(const TAlmostDummy& r) const { return !operator==(r); };
+
+ int Junk;
+ };
+ size_t TAlmostDummy::Count = 0;
+
+ struct TNotSimple {
+ enum class EType {
+ Value,
+ Empty,
+ Deleted
+ } Type_ = EType::Value;
+
+ TString Junk = "something"; // to prevent triviality propagation
+ int Value = 0;
+
+ static int CtorCalls;
+ static int DtorCalls;
+ static int CopyCtorCalls;
+ static int MoveCtorCalls;
+
+ TNotSimple() {
+ ++CtorCalls;
+ }
+ explicit TNotSimple(int value)
+ : Value(value)
+ {
+ ++CtorCalls;
+ }
+
+ TNotSimple(const TNotSimple& rhs) {
+ ++CopyCtorCalls;
+ Value = rhs.Value;
+ Type_ = rhs.Type_;
+ }
+ TNotSimple(TNotSimple&& rhs) {
+ ++MoveCtorCalls;
+ Value = rhs.Value;
+ Type_ = rhs.Type_;
+ }
+
+ ~TNotSimple() {
+ ++DtorCalls;
+ }
+
+ TNotSimple& operator=(const TNotSimple& rhs) {
+ ++CopyCtorCalls;
+ Value = rhs.Value;
+ Type_ = rhs.Type_;
+ return *this;
+ }
+ TNotSimple& operator=(TNotSimple&& rhs) {
+ ++MoveCtorCalls;
+ Value = rhs.Value;
+ Type_ = rhs.Type_;
+ return *this;
+ }
+
+ static TNotSimple Empty() {
+ TNotSimple ret;
+ ret.Type_ = EType::Empty;
+ return ret;
+ }
+
+ static TNotSimple Deleted() {
+ TNotSimple ret;
+ ret.Type_ = EType::Deleted;
+ return ret;
+ }
+
+ bool operator==(const TNotSimple& rhs) const noexcept {
+ return Value == rhs.Value;
+ }
+
+ static void ResetStats() {
+ CtorCalls = 0;
+ DtorCalls = 0;
+ CopyCtorCalls = 0;
+ MoveCtorCalls = 0;
+ }
+ };
+
+ int TNotSimple::CtorCalls = 0;
+ int TNotSimple::DtorCalls = 0;
+ int TNotSimple::CopyCtorCalls = 0;
+ int TNotSimple::MoveCtorCalls = 0;
+
+ struct TNotSimpleEmptyMarker {
+ using value_type = TNotSimple;
+
+ value_type Create() const {
+ return TNotSimple::Empty();
+ }
+
+ bool Equals(const value_type& rhs) const {
+ return rhs.Type_ == TNotSimple::EType::Empty;
+ }
+ };
+
+ struct TNotSimpleDeletedMarker {
+ using value_type = TNotSimple;
+
+ value_type Create() const {
+ return TNotSimple::Deleted();
+ }
+
+ bool Equals(const value_type& rhs) const {
+ return rhs.Type_ == TNotSimple::EType::Deleted;
+ }
+ };
+
+ template <class Container>
+ void CheckContainersEqual(const Container& a, const Container& b) {
+ UNIT_ASSERT_EQUAL(a.Size(), b.Size());
+ UNIT_ASSERT_EQUAL(a.Taken(), b.Empty());
+ for (typename Container::size_type i = 0; i < a.Size(); ++i) {
+ if (a.IsTaken(i)) {
+ UNIT_ASSERT(b.IsTaken(i));
+ UNIT_ASSERT_EQUAL(a.Node(i), b.Node(i));
+ }
+ }
+ }
+
+ template <class Container, class... Args>
+ void SmokingTest(typename Container::size_type size, Args&&... args) {
+ using size_type = typename Container::size_type;
+ using value_type = typename Container::value_type;
+
+ Container cont(size, std::forward<Args>(args)...);
+ UNIT_ASSERT_EQUAL(cont.Size(), size);
+ UNIT_ASSERT_EQUAL(cont.Taken(), 0);
+
+ for (size_type i = 0; i < cont.Size(); ++i) {
+ UNIT_ASSERT(cont.IsEmpty(i));
+ UNIT_ASSERT(!cont.IsTaken(i));
+ }
+
+ // Filling the container till half
+ TVector<size_type> toInsert(cont.Size());
+ Iota(toInsert.begin(), toInsert.end(), 0);
+ Shuffle(toInsert.begin(), toInsert.end());
+ toInsert.resize(toInsert.size() / 2);
+ for (auto i : toInsert) {
+ UNIT_ASSERT(cont.IsEmpty(i));
+ UNIT_ASSERT(!cont.IsTaken(i));
+ value_type value(RandomNumber<size_type>(cont.Size()));
+ cont.InitNode(i, value);
+ UNIT_ASSERT(!cont.IsEmpty(i));
+ UNIT_ASSERT(cont.IsTaken(i));
+ UNIT_ASSERT_EQUAL(cont.Node(i), value);
+ }
+ UNIT_ASSERT_EQUAL(cont.Taken(), toInsert.size());
+
+ // Copy construction test
+ auto cont2 = cont;
+ CheckContainersEqual(cont, cont2);
+
+ // Copy assignment test
+ cont2 = cont2.Clone(0);
+ UNIT_ASSERT_EQUAL(cont2.Size(), 0);
+ UNIT_ASSERT_EQUAL(cont2.Taken(), 0);
+
+ // Copy assignment test
+ cont2 = cont;
+ CheckContainersEqual(cont, cont2);
+
+ // Move construction test
+ auto cont3 = std::move(cont2);
+ UNIT_ASSERT_EQUAL(cont2.Size(), 0);
+ CheckContainersEqual(cont, cont3);
+
+ // Move assignment test
+ cont2 = std::move(cont3);
+ UNIT_ASSERT_EQUAL(cont3.Size(), 0);
+ CheckContainersEqual(cont, cont2);
+ }
+}
+
+Y_UNIT_TEST_SUITE(TFlatContainerTest) {
+ Y_UNIT_TEST(SmokingTest) {
+ SmokingTest<TFlatContainer<int>>(INIT_SIZE);
+ }
+
+ Y_UNIT_TEST(SmokingTestNotSimpleType) {
+ TNotSimple::ResetStats();
+ SmokingTest<TFlatContainer<TNotSimple>>(INIT_SIZE);
+
+ UNIT_ASSERT_EQUAL(TNotSimple::CtorCalls + TNotSimple::CopyCtorCalls + TNotSimple::MoveCtorCalls,
+ TNotSimple::DtorCalls);
+ UNIT_ASSERT_EQUAL(TNotSimple::CtorCalls, INIT_SIZE / 2 /* created while filling */);
+ UNIT_ASSERT_EQUAL(TNotSimple::DtorCalls, INIT_SIZE / 2 /* removed filling temporary */
+ + INIT_SIZE / 2 /* removed while cloning */
+ + INIT_SIZE /* 3 containers dtors */);
+ UNIT_ASSERT_EQUAL(TNotSimple::CopyCtorCalls, INIT_SIZE / 2 /* 3 created while filling */
+ + INIT_SIZE / 2 /* created while copy constructing */
+ + INIT_SIZE / 2/* created while copy assigning */);
+ UNIT_ASSERT_EQUAL(TNotSimple::MoveCtorCalls, 0);
+ }
+
+ Y_UNIT_TEST(DummyHalfSizeTest) {
+ using TContainer = TFlatContainer<TDummy>;
+ using size_type = typename TContainer::size_type;
+
+ {
+ TContainer cont(INIT_SIZE);
+ UNIT_ASSERT_EQUAL(TDummy::Count, 0);
+
+ TVector<size_type> toInsert(cont.Size());
+ Iota(toInsert.begin(), toInsert.end(), 0);
+ Shuffle(toInsert.begin(), toInsert.end());
+ toInsert.resize(toInsert.size() / 2);
+ for (auto i : toInsert) {
+ UNIT_ASSERT(cont.IsEmpty(i));
+ UNIT_ASSERT(!cont.IsTaken(i));
+ cont.InitNode(i);
+ UNIT_ASSERT_EQUAL(TDummy::Count, cont.Taken());
+ UNIT_ASSERT(!cont.IsEmpty(i));
+ UNIT_ASSERT(cont.IsTaken(i));
+ }
+ UNIT_ASSERT_EQUAL(cont.Taken(), cont.Size() / 2);
+ UNIT_ASSERT_EQUAL(TDummy::Count, cont.Taken());
+ }
+ UNIT_ASSERT_EQUAL(TDummy::Count, 0);
+ }
+
+ Y_UNIT_TEST(DeleteTest) {
+ using TContainer = TFlatContainer<TDummy>;
+ using size_type = typename TContainer::size_type;
+
+ TContainer cont(INIT_SIZE);
+ auto idx = RandomNumber<size_type>(INIT_SIZE);
+ UNIT_ASSERT(!cont.IsTaken(idx));
+ UNIT_ASSERT(!cont.IsDeleted(idx));
+ UNIT_ASSERT_EQUAL(TDummy::Count, 0);
+
+ cont.InitNode(idx);
+ UNIT_ASSERT_EQUAL(cont.Taken(), 1);
+ UNIT_ASSERT(cont.IsTaken(idx));
+ UNIT_ASSERT(!cont.IsDeleted(idx));
+ UNIT_ASSERT_EQUAL(TDummy::Count, 1);
+
+ cont.DeleteNode(idx);
+ UNIT_ASSERT(!cont.IsTaken(idx));
+ UNIT_ASSERT(cont.IsDeleted(idx));
+ UNIT_ASSERT_EQUAL(TDummy::Count, 0);
+ }
+}
+
+Y_UNIT_TEST_SUITE(TDenseContainerTest) {
+ Y_UNIT_TEST(SmokingTest) {
+ SmokingTest<TDenseContainer<int, NSet::TStaticValueMarker<-1>>>(INIT_SIZE);
+ }
+
+ Y_UNIT_TEST(NotSimpleTypeSmokingTest) {
+ TNotSimple::ResetStats();
+ SmokingTest<TDenseContainer<TNotSimple, TNotSimpleEmptyMarker>>(INIT_SIZE);
+
+ UNIT_ASSERT_EQUAL(TNotSimple::CtorCalls + TNotSimple::CopyCtorCalls + TNotSimple::MoveCtorCalls,
+ TNotSimple::DtorCalls);
+ UNIT_ASSERT_EQUAL(TNotSimple::CtorCalls, INIT_SIZE / 2 /* created while filling */
+ + 2 /* created by empty marker */);
+ UNIT_ASSERT_EQUAL(TNotSimple::DtorCalls, 1 /* removed empty marker temporary */
+ + INIT_SIZE /* half removed while resetting in container,
+ half removed inserted temporary */
+ + INIT_SIZE /* removed while cloning */
+ + 1 /* removed empty marker temporary */
+ + INIT_SIZE * 2 /* 3 containers dtors */);
+ UNIT_ASSERT_EQUAL(TNotSimple::CopyCtorCalls, INIT_SIZE /* created while constructing */
+ + INIT_SIZE / 2 /* 3 created while filling */
+ + INIT_SIZE /* created while copy constructing */
+ + INIT_SIZE /* created while copy assigning */);
+ UNIT_ASSERT_EQUAL(TNotSimple::MoveCtorCalls, 0);
+ }
+
+ Y_UNIT_TEST(RemovalContainerSmokingTest) {
+ SmokingTest<TRemovalDenseContainer<int, NSet::TStaticValueMarker<-1>,
+ NSet::TStaticValueMarker<-2>>>(INIT_SIZE);
+ }
+
+ Y_UNIT_TEST(NotSimpleTypeRemovalContainerSmokingTest) {
+ TNotSimple::ResetStats();
+ SmokingTest<TRemovalDenseContainer<TNotSimple, TNotSimpleEmptyMarker,
+ TNotSimpleDeletedMarker>>(INIT_SIZE);
+
+ UNIT_ASSERT_EQUAL(TNotSimple::CtorCalls + TNotSimple::CopyCtorCalls + TNotSimple::MoveCtorCalls,
+ TNotSimple::DtorCalls);
+ UNIT_ASSERT_EQUAL(TNotSimple::CtorCalls, INIT_SIZE / 2 /* created while filling */
+ + 2 /* created by empty marker */);
+ UNIT_ASSERT_EQUAL(TNotSimple::DtorCalls, 1 /* removed empty marker temporary */
+ + INIT_SIZE /* half removed while resetting in container,
+ half removed inserted temporary */
+ + INIT_SIZE /* removed while cloning */
+ + 1 /* removed empty marker temporary */
+ + INIT_SIZE * 2 /* 3 containers dtors */);
+ UNIT_ASSERT_EQUAL(TNotSimple::CopyCtorCalls, INIT_SIZE /* created while constructing */
+ + INIT_SIZE / 2 /* 3 created while filling */
+ + INIT_SIZE /* created while copy constructing */
+ + INIT_SIZE /* created while copy assigning */);
+ UNIT_ASSERT_EQUAL(TNotSimple::MoveCtorCalls, 0);
+ }
+
+ Y_UNIT_TEST(DummyHalfSizeTest) {
+ using TContainer = TDenseContainer<TAlmostDummy, NSet::TEqValueMarker<TAlmostDummy>>;
+ using size_type = typename TContainer::size_type;
+
+ {
+ TContainer cont(INIT_SIZE, TAlmostDummy{-1});
+ UNIT_ASSERT_EQUAL(TAlmostDummy::Count, cont.Size() + 1); // 1 for empty marker
+
+ TVector<size_type> toInsert(cont.Size());
+ Iota(toInsert.begin(), toInsert.end(), 0);
+ Shuffle(toInsert.begin(), toInsert.end());
+ toInsert.resize(toInsert.size() / 2);
+ for (auto i : toInsert) {
+ UNIT_ASSERT(cont.IsEmpty(i));
+ UNIT_ASSERT(!cont.IsTaken(i));
+ cont.InitNode(i, (int)RandomNumber<size_type>(cont.Size()));
+ UNIT_ASSERT_EQUAL(TAlmostDummy::Count, cont.Size() + 1);
+ UNIT_ASSERT(!cont.IsEmpty(i));
+ UNIT_ASSERT(cont.IsTaken(i));
+ }
+ UNIT_ASSERT_EQUAL(cont.Taken(), toInsert.size());
+ UNIT_ASSERT_EQUAL(TAlmostDummy::Count, cont.Size() + 1);
+ }
+ UNIT_ASSERT_EQUAL(TAlmostDummy::Count, 0);
+ }
+
+ Y_UNIT_TEST(DeleteTest) {
+ using TContainer = TRemovalDenseContainer<TAlmostDummy, NSet::TEqValueMarker<TAlmostDummy>,
+ NSet::TEqValueMarker<TAlmostDummy>>;
+ using size_type = typename TContainer::size_type;
+
+ TContainer cont(INIT_SIZE, TAlmostDummy{ -2 }, TAlmostDummy{ -1 });
+ auto idx = RandomNumber<size_type>(cont.Size());
+ UNIT_ASSERT(!cont.IsTaken(idx));
+ UNIT_ASSERT(!cont.IsDeleted(idx));
+ UNIT_ASSERT_EQUAL(TAlmostDummy::Count, cont.Size() + 2); // 2 for markers
+
+ cont.InitNode(idx, (int)RandomNumber<size_type>(cont.Size()));
+ UNIT_ASSERT_EQUAL(cont.Taken(), 1);
+ UNIT_ASSERT(cont.IsTaken(idx));
+ UNIT_ASSERT(!cont.IsDeleted(idx));
+ UNIT_ASSERT_EQUAL(TAlmostDummy::Count, cont.Size() + 2);
+
+ cont.DeleteNode(idx);
+ UNIT_ASSERT(!cont.IsTaken(idx));
+ UNIT_ASSERT(cont.IsDeleted(idx));
+ UNIT_ASSERT_EQUAL(TAlmostDummy::Count, cont.Size() + 2);
+ }
+
+ Y_UNIT_TEST(FancyInitsTest) {
+ {
+ using TContainer = TDenseContainer<int>;
+ TContainer cont{ INIT_SIZE, -1 };
+ }
+ {
+ using TContainer = TDenseContainer<int, NSet::TStaticValueMarker<-1>>;
+ TContainer cont{ INIT_SIZE };
+ static_assert(!std::is_constructible_v<TContainer, size_t, int>);
+ }
+ {
+ using TContainer = TDenseContainer<int, NSet::TEqValueMarker<int>>;
+ TContainer cont{ INIT_SIZE, -1 };
+ TContainer cont2{ INIT_SIZE, NSet::TEqValueMarker<int>{ -1 } };
+ }
+ {
+ using TContainer = TRemovalDenseContainer<int>;
+ TContainer cont{ INIT_SIZE, -1, -2 };
+ TContainer cont2{ INIT_SIZE, NSet::TEqValueMarker<int>{ -1 },
+ NSet::TEqValueMarker<int>{ -2 } };
+ }
+ {
+ using TContainer = TRemovalDenseContainer<int, NSet::TStaticValueMarker<-1>,
+ NSet::TStaticValueMarker<-1>>;
+ TContainer cont{ INIT_SIZE };
+ static_assert(!std::is_constructible_v<TContainer, size_t, int>);
+ static_assert(!std::is_constructible_v<TContainer, size_t, int, int>);
+ }
+ }
+}
diff --git a/library/cpp/containers/flat_hash/lib/ut/iterator_ut.cpp b/library/cpp/containers/flat_hash/lib/ut/iterator_ut.cpp
new file mode 100644
index 0000000000..0b77bf043f
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/ut/iterator_ut.cpp
@@ -0,0 +1,85 @@
+#include <library/cpp/containers/flat_hash/lib/iterator.h>
+#include <library/cpp/containers/flat_hash/lib/containers.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/random/random.h>
+#include <util/generic/algorithm.h>
+
+using namespace NFlatHash;
+
+namespace {
+ constexpr size_t INIT_SIZE = 128;
+
+ template <class Container>
+ void SmokingTest(Container& cont) {
+ using value_type = typename Container::value_type;
+ using iterator = TIterator<Container, value_type>;
+ using size_type = typename Container::size_type;
+
+ iterator f(&cont), l(&cont, cont.Size());
+ UNIT_ASSERT_EQUAL(f, l);
+ UNIT_ASSERT_EQUAL((size_type)std::distance(f, l), cont.Taken());
+
+ TVector<std::pair<size_type, value_type>> toAdd{
+ { 0, (int)RandomNumber<size_type>(INIT_SIZE) },
+ { 1 + RandomNumber<size_type>(INIT_SIZE - 2), (int)RandomNumber<size_type>(INIT_SIZE) },
+ { INIT_SIZE - 1, (int)RandomNumber<size_type>(INIT_SIZE) }
+ };
+
+ for (const auto& p : toAdd) {
+ UNIT_ASSERT(cont.IsEmpty(p.first));
+ cont.InitNode(p.first, p.second);
+ }
+ UNIT_ASSERT_EQUAL(cont.Size(), INIT_SIZE);
+ f = iterator{ &cont };
+ l = iterator{ &cont, INIT_SIZE };
+ UNIT_ASSERT_UNEQUAL(f, l);
+ UNIT_ASSERT_EQUAL((size_type)std::distance(f, l), cont.Taken());
+
+ TVector<value_type> added(f, l);
+ UNIT_ASSERT(::Equal(toAdd.begin(), toAdd.end(), added.begin(), [](const auto& p, auto v) {
+ return p.second == v;
+ }));
+ }
+
+ template <class Container>
+ void ConstTest(Container& cont) {
+ using value_type = typename Container::value_type;
+ using iterator = TIterator<Container, value_type>;
+ using const_iterator = TIterator<const Container, const value_type>;
+
+ iterator it{ &cont, INIT_SIZE / 2 };
+ const_iterator cit1{ it };
+ const_iterator cit2{ &cont, INIT_SIZE / 2 };
+
+ UNIT_ASSERT_EQUAL(cit1, cit2);
+
+ static_assert(std::is_same<decltype(*it), value_type&>::value);
+ static_assert(std::is_same<decltype(*cit1), const value_type&>::value);
+ }
+}
+
+Y_UNIT_TEST_SUITE(TIteratorTest) {
+ Y_UNIT_TEST(SmokingTest) {
+ {
+ TFlatContainer<int> cont(INIT_SIZE);
+ SmokingTest(cont);
+ }
+ {
+ TDenseContainer<int, NSet::TStaticValueMarker<-1>> cont(INIT_SIZE);
+ SmokingTest(cont);
+ }
+ }
+
+ Y_UNIT_TEST(ConstTest) {
+ {
+ TFlatContainer<int> cont(INIT_SIZE);
+ ConstTest(cont);
+ }
+ {
+ TDenseContainer<int, NSet::TStaticValueMarker<-1>> cont(INIT_SIZE);
+ ConstTest(cont);
+ }
+ }
+}
diff --git a/library/cpp/containers/flat_hash/lib/ut/probings_ut.cpp b/library/cpp/containers/flat_hash/lib/ut/probings_ut.cpp
new file mode 100644
index 0000000000..593f8cbb1b
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/ut/probings_ut.cpp
@@ -0,0 +1,34 @@
+#include <library/cpp/containers/flat_hash/lib/probings.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NFlatHash;
+
+namespace {
+ struct TDummySizeFitter {
+ constexpr auto EvalIndex(size_t idx, size_t) const {
+ return idx;
+ }
+ };
+
+ constexpr TDummySizeFitter SIZE_FITTER;
+
+ auto atLeast13 = [](size_t idx) { return idx >= 13; };
+}
+
+Y_UNIT_TEST_SUITE(TProbingsTest) {
+ Y_UNIT_TEST(LinearProbingTest) {
+ using TProbing = TLinearProbing;
+ UNIT_ASSERT_EQUAL(TProbing::FindBucket(SIZE_FITTER, 1, 0, atLeast13), 13);
+ }
+
+ Y_UNIT_TEST(QuadraticProbingTest) {
+ using TProbing = TQuadraticProbing;
+ UNIT_ASSERT_EQUAL(TProbing::FindBucket(SIZE_FITTER, 1, 0, atLeast13), 17);
+ }
+
+ Y_UNIT_TEST(DenseProbingTest) {
+ using TProbing = TDenseProbing;
+ UNIT_ASSERT_EQUAL(TProbing::FindBucket(SIZE_FITTER, 1, 0, atLeast13), 16);
+ }
+}
diff --git a/library/cpp/containers/flat_hash/lib/ut/size_fitters_ut.cpp b/library/cpp/containers/flat_hash/lib/ut/size_fitters_ut.cpp
new file mode 100644
index 0000000000..4167947ece
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/ut/size_fitters_ut.cpp
@@ -0,0 +1,51 @@
+#include <library/cpp/containers/flat_hash/lib/size_fitters.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NFlatHash;
+
+Y_UNIT_TEST_SUITE(TAndSizeFitterTest) {
+ Y_UNIT_TEST(EvalSizeTest) {
+ TAndSizeFitter sf;
+ UNIT_ASSERT_EQUAL(sf.EvalSize(5), 8);
+ UNIT_ASSERT_EQUAL(sf.EvalSize(8), 8);
+ UNIT_ASSERT_EQUAL(sf.EvalSize(13), 16);
+ UNIT_ASSERT_EQUAL(sf.EvalSize(25), 32);
+ for (size_t i = 1; i < 100; ++i) {
+ UNIT_ASSERT_EQUAL(sf.EvalSize(i), FastClp2(i));
+ }
+ }
+
+ Y_UNIT_TEST(EvalIndexTest) {
+ TAndSizeFitter sf;
+ for (size_t j = 1; j < 10; ++j) {
+ sf.Update(1 << j);
+ for (size_t i = 0; i < 100; ++i) {
+ UNIT_ASSERT_EQUAL(sf.EvalIndex(i, 1 << j), i & ((1 << j) - 1));
+ }
+ }
+ }
+}
+
+Y_UNIT_TEST_SUITE(TModSizeFitterTest) {
+ Y_UNIT_TEST(EvalSizeTest) {
+ TModSizeFitter sf;
+ UNIT_ASSERT_EQUAL(sf.EvalSize(5), 5);
+ UNIT_ASSERT_EQUAL(sf.EvalSize(8), 8);
+ UNIT_ASSERT_EQUAL(sf.EvalSize(13), 13);
+ UNIT_ASSERT_EQUAL(sf.EvalSize(25), 25);
+ for (size_t i = 1; i < 100; ++i) {
+ UNIT_ASSERT_EQUAL(sf.EvalSize(i), i);
+ }
+ }
+
+ Y_UNIT_TEST(EvalIndexTest) {
+ TModSizeFitter sf;
+ for (size_t j = 1; j < 10; ++j) {
+ sf.Update(1 << j); // just for integrity
+ for (size_t i = 0; i < 100; ++i) {
+ UNIT_ASSERT_EQUAL(sf.EvalIndex(i, 1 << j), i % (1 << j));
+ }
+ }
+ }
+}
diff --git a/library/cpp/containers/flat_hash/lib/ut/table_ut.cpp b/library/cpp/containers/flat_hash/lib/ut/table_ut.cpp
new file mode 100644
index 0000000000..ea511e2c6a
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/ut/table_ut.cpp
@@ -0,0 +1,411 @@
+#include <library/cpp/containers/flat_hash/lib/containers.h>
+#include <library/cpp/containers/flat_hash/lib/expanders.h>
+#include <library/cpp/containers/flat_hash/lib/probings.h>
+#include <library/cpp/containers/flat_hash/lib/size_fitters.h>
+#include <library/cpp/containers/flat_hash/lib/table.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/algorithm.h>
+#include <util/random/random.h>
+#include <util/random/shuffle.h>
+
+using namespace NFlatHash;
+
+namespace {
+ template <class T>
+ struct TJustType {
+ using type = T;
+ };
+
+ template <class... Ts>
+ struct TTypePack {};
+
+ template <class F, class... Ts>
+ constexpr void ForEachType(F&& f, TTypePack<Ts...>) {
+ ApplyToMany(std::forward<F>(f), TJustType<Ts>{}...);
+ }
+
+/* Usage example:
+ *
+ * TForEachType<int, float, TString>::Apply([](auto t) {
+ * using T = GET_TYPE(t);
+ * });
+ * So T would be:
+ * int on #0 iteration
+ * float on #1 iteration
+ * TString on #2 iteration
+ */
+#define GET_TYPE(ti) typename decltype(ti)::type
+
+ constexpr size_t INIT_SIZE = 32;
+ constexpr size_t BIG_INIT_SIZE = 128;
+
+ template <class T>
+ struct TSimpleKeyGetter {
+ static constexpr T& Apply(T& t) { return t; }
+ static constexpr const T& Apply(const T& t) { return t; }
+ };
+
+ template <class T,
+ class KeyEqual = std::equal_to<T>,
+ class ValueEqual = std::equal_to<T>,
+ class KeyGetter = TSimpleKeyGetter<T>,
+ class F,
+ class... Containers>
+ void ForEachTable(F f, TTypePack<Containers...> cs) {
+ ForEachType([&](auto p) {
+ using TProbing = GET_TYPE(p);
+
+ ForEachType([&](auto sf) {
+ using TSizeFitter = GET_TYPE(sf);
+
+ ForEachType([&](auto t) {
+ using TContainer = GET_TYPE(t);
+ static_assert(std::is_same_v<typename TContainer::value_type, T>);
+
+ using TTable = TTable<THash<T>,
+ KeyEqual,
+ TContainer,
+ KeyGetter,
+ TProbing,
+ TSizeFitter,
+ TSimpleExpander>;
+
+ f(TJustType<TTable>{});
+ }, cs);
+ }, TTypePack<TAndSizeFitter, TModSizeFitter>{});
+ }, TTypePack<TLinearProbing, TQuadraticProbing, TDenseProbing>{});
+ }
+
+ using TAtomContainers = TTypePack<TFlatContainer<int>,
+ TDenseContainer<int, NSet::TStaticValueMarker<-1>>>;
+ using TContainers = TTypePack<TFlatContainer<int>,
+ TDenseContainer<int, NSet::TStaticValueMarker<-1>>>;
+ using TRemovalContainers = TTypePack<TFlatContainer<int>,
+ TRemovalDenseContainer<int, NSet::TStaticValueMarker<-2>,
+ NSet::TStaticValueMarker<-1>>>;
+}
+
+Y_UNIT_TEST_SUITE(TCommonTableAtomsTest) {
+ Y_UNIT_TEST(InitTest) {
+ ForEachTable<int>([](auto t) {
+ GET_TYPE(t) table{ INIT_SIZE };
+
+ UNIT_ASSERT(table.empty());
+ UNIT_ASSERT_EQUAL(table.size(), 0);
+ UNIT_ASSERT_EQUAL(table.bucket_count(), INIT_SIZE);
+ UNIT_ASSERT_EQUAL(table.bucket_size(RandomNumber<size_t>(INIT_SIZE)), 0);
+ }, TAtomContainers{});
+ }
+
+ Y_UNIT_TEST(IteratorTest) {
+ ForEachTable<int>([](auto t) {
+ GET_TYPE(t) table{ INIT_SIZE };
+
+ auto first = table.begin();
+ auto last = table.end();
+ UNIT_ASSERT_EQUAL(first, last);
+ UNIT_ASSERT_EQUAL(std::distance(first, last), 0);
+
+ auto cFirst = table.cbegin();
+ auto cLast = table.cend();
+ UNIT_ASSERT_EQUAL(cFirst, cLast);
+ UNIT_ASSERT_EQUAL(std::distance(cFirst, cLast), 0);
+ }, TAtomContainers{});
+ }
+
+ Y_UNIT_TEST(ContainsAndCountTest) {
+ ForEachTable<int>([](auto t) {
+ GET_TYPE(t) table{ INIT_SIZE };
+
+ for (int i = 0; i < 100; ++i) {
+ UNIT_ASSERT_EQUAL(table.count(i), 0);
+ UNIT_ASSERT(!table.contains(i));
+ }
+ }, TAtomContainers{});
+ }
+
+ Y_UNIT_TEST(FindTest) {
+ ForEachTable<int>([](auto t) {
+ GET_TYPE(t) table{ INIT_SIZE };
+
+ for (int i = 0; i < 100; ++i) {
+ auto it = table.find(i);
+ UNIT_ASSERT_EQUAL(it, table.end());
+ }
+ }, TAtomContainers{});
+ }
+}
+
+Y_UNIT_TEST_SUITE(TCommonTableTest) {
+ Y_UNIT_TEST(InsertTest) {
+ ForEachTable<int>([](auto t) {
+ GET_TYPE(t) table{ INIT_SIZE };
+
+ UNIT_ASSERT(table.empty());
+ UNIT_ASSERT_EQUAL(table.size(), 0);
+
+ int toInsert = RandomNumber<size_t>(100);
+ UNIT_ASSERT_EQUAL(table.count(toInsert), 0);
+ UNIT_ASSERT(!table.contains(toInsert));
+
+ auto p = table.insert(toInsert);
+ UNIT_ASSERT_EQUAL(p.first, table.begin());
+ UNIT_ASSERT(p.second);
+
+ UNIT_ASSERT(!table.empty());
+ UNIT_ASSERT_EQUAL(table.size(), 1);
+ UNIT_ASSERT_EQUAL(table.count(toInsert), 1);
+ UNIT_ASSERT(table.contains(toInsert));
+
+ auto it = table.find(toInsert);
+ UNIT_ASSERT_UNEQUAL(it, table.end());
+ UNIT_ASSERT_EQUAL(it, table.begin());
+ UNIT_ASSERT_EQUAL(*it, toInsert);
+
+ auto p2 = table.insert(toInsert);
+ UNIT_ASSERT_EQUAL(p.first, p2.first);
+ UNIT_ASSERT(!p2.second);
+
+ UNIT_ASSERT_EQUAL(table.size(), 1);
+ UNIT_ASSERT_EQUAL(table.count(toInsert), 1);
+ UNIT_ASSERT(table.contains(toInsert));
+ }, TContainers{});
+ }
+
+ Y_UNIT_TEST(ClearTest) {
+ ForEachTable<int>([](auto t) {
+ GET_TYPE(t) table{ INIT_SIZE };
+
+ TVector<int> toInsert(INIT_SIZE);
+ Iota(toInsert.begin(), toInsert.end(), 0);
+ ShuffleRange(toInsert);
+ toInsert.resize(INIT_SIZE / 3);
+
+ for (auto i : toInsert) {
+ auto p = table.insert(i);
+ UNIT_ASSERT_EQUAL(*p.first, i);
+ UNIT_ASSERT(p.second);
+ }
+ UNIT_ASSERT_EQUAL(table.size(), toInsert.size());
+ UNIT_ASSERT_EQUAL((size_t)std::distance(table.begin(), table.end()), toInsert.size());
+
+ for (auto i : toInsert) {
+ UNIT_ASSERT(table.contains(i));
+ UNIT_ASSERT_EQUAL(table.count(i), 1);
+ }
+
+ auto bc = table.bucket_count();
+ table.clear();
+ UNIT_ASSERT(table.empty());
+ UNIT_ASSERT_EQUAL(table.bucket_count(), bc);
+
+ for (auto i : toInsert) {
+ UNIT_ASSERT(!table.contains(i));
+ UNIT_ASSERT_EQUAL(table.count(i), 0);
+ }
+
+ table.insert(toInsert.front());
+ UNIT_ASSERT(!table.empty());
+ }, TContainers{});
+ }
+
+ Y_UNIT_TEST(CopyMoveTest) {
+ ForEachTable<int>([](auto t) {
+ GET_TYPE(t) table{ INIT_SIZE };
+
+ TVector<int> toInsert(INIT_SIZE);
+ Iota(toInsert.begin(), toInsert.end(), 0);
+ ShuffleRange(toInsert);
+ toInsert.resize(INIT_SIZE / 3);
+
+ for (auto i : toInsert) {
+ auto p = table.insert(i);
+ UNIT_ASSERT_EQUAL(*p.first, i);
+ UNIT_ASSERT(p.second);
+ }
+ UNIT_ASSERT_EQUAL(table.size(), toInsert.size());
+ UNIT_ASSERT_EQUAL((size_t)std::distance(table.begin(), table.end()), toInsert.size());
+
+ for (auto i : toInsert) {
+ UNIT_ASSERT(table.contains(i));
+ UNIT_ASSERT_EQUAL(table.count(i), 1);
+ }
+
+ // Copy construction test
+ auto table2 = table;
+ UNIT_ASSERT_EQUAL(table2.size(), table.size());
+ UNIT_ASSERT_EQUAL((size_t)std::distance(table2.begin(), table2.end()), table.size());
+ for (auto i : table) {
+ UNIT_ASSERT(table2.contains(i));
+ UNIT_ASSERT_EQUAL(table2.count(i), 1);
+ }
+
+ table2.clear();
+ UNIT_ASSERT(table2.empty());
+
+ // Copy assignment test
+ table2 = table;
+ UNIT_ASSERT_EQUAL(table2.size(), table.size());
+ UNIT_ASSERT_EQUAL((size_t)std::distance(table2.begin(), table2.end()), table.size());
+ for (auto i : table) {
+ UNIT_ASSERT(table2.contains(i));
+ UNIT_ASSERT_EQUAL(table2.count(i), 1);
+ }
+
+ // Move construction test
+ auto table3 = std::move(table2);
+ UNIT_ASSERT(table2.empty());
+ UNIT_ASSERT(table2.bucket_count() > 0);
+
+ UNIT_ASSERT_EQUAL(table3.size(), table.size());
+ UNIT_ASSERT_EQUAL((size_t)std::distance(table3.begin(), table3.end()), table.size());
+ for (auto i : table) {
+ UNIT_ASSERT(table3.contains(i));
+ UNIT_ASSERT_EQUAL(table3.count(i), 1);
+ }
+
+ table2.insert(toInsert.front());
+ UNIT_ASSERT(!table2.empty());
+ UNIT_ASSERT_EQUAL(table2.size(), 1);
+ UNIT_ASSERT_UNEQUAL(table2.bucket_count(), 0);
+
+ // Move assignment test
+ table2 = std::move(table3);
+ UNIT_ASSERT(table3.empty());
+ UNIT_ASSERT(table3.bucket_count() > 0);
+
+ UNIT_ASSERT_EQUAL(table2.size(), table.size());
+ UNIT_ASSERT_EQUAL((size_t)std::distance(table2.begin(), table2.end()), table.size());
+ for (auto i : table) {
+ UNIT_ASSERT(table2.contains(i));
+ UNIT_ASSERT_EQUAL(table2.count(i), 1);
+ }
+
+ table3.insert(toInsert.front());
+ UNIT_ASSERT(!table3.empty());
+ UNIT_ASSERT_EQUAL(table3.size(), 1);
+ UNIT_ASSERT_UNEQUAL(table3.bucket_count(), 0);
+ }, TContainers{});
+ }
+
+ Y_UNIT_TEST(RehashTest) {
+ ForEachTable<int>([](auto t) {
+ GET_TYPE(t) table{ INIT_SIZE };
+
+ TVector<int> toInsert(INIT_SIZE);
+ Iota(toInsert.begin(), toInsert.end(), 0);
+ ShuffleRange(toInsert);
+ toInsert.resize(INIT_SIZE / 3);
+
+ for (auto i : toInsert) {
+ table.insert(i);
+ }
+
+ auto bc = table.bucket_count();
+ table.rehash(bc * 2);
+ UNIT_ASSERT(bc * 2 <= table.bucket_count());
+
+ UNIT_ASSERT_EQUAL(table.size(), toInsert.size());
+ UNIT_ASSERT_EQUAL((size_t)std::distance(table.begin(), table.end()), toInsert.size());
+ for (auto i : toInsert) {
+ UNIT_ASSERT(table.contains(i));
+ UNIT_ASSERT_EQUAL(table.count(i), 1);
+ }
+
+ TVector<int> tmp(table.begin(), table.end());
+ Sort(toInsert.begin(), toInsert.end());
+ Sort(tmp.begin(), tmp.end());
+
+ UNIT_ASSERT_VALUES_EQUAL(tmp, toInsert);
+
+ table.rehash(0);
+ UNIT_ASSERT_EQUAL(table.size(), toInsert.size());
+ UNIT_ASSERT(table.bucket_count() > table.size());
+
+ table.clear();
+ UNIT_ASSERT(table.empty());
+ table.rehash(INIT_SIZE);
+ UNIT_ASSERT(table.bucket_count() >= INIT_SIZE);
+
+ table.rehash(0);
+ UNIT_ASSERT(table.bucket_count() > 0);
+ }, TContainers{});
+ }
+
+ Y_UNIT_TEST(EraseTest) {
+ ForEachTable<int>([](auto t) {
+ GET_TYPE(t) table{ INIT_SIZE };
+
+ int value = RandomNumber<ui32>();
+ table.insert(value);
+ UNIT_ASSERT_EQUAL(table.size(), 1);
+ UNIT_ASSERT_EQUAL(table.count(value), 1);
+
+ auto it = table.find(value);
+ table.erase(it);
+
+ UNIT_ASSERT_EQUAL(table.size(), 0);
+ UNIT_ASSERT_EQUAL(table.count(value), 0);
+
+ table.insert(value);
+ UNIT_ASSERT_EQUAL(table.size(), 1);
+ UNIT_ASSERT_EQUAL(table.count(value), 1);
+
+ table.erase(value);
+
+ UNIT_ASSERT_EQUAL(table.size(), 0);
+ UNIT_ASSERT_EQUAL(table.count(value), 0);
+
+ table.insert(value);
+ UNIT_ASSERT_EQUAL(table.size(), 1);
+ UNIT_ASSERT_EQUAL(table.count(value), 1);
+
+ table.erase(table.find(value), table.end());
+
+ UNIT_ASSERT_EQUAL(table.size(), 0);
+ UNIT_ASSERT_EQUAL(table.count(value), 0);
+
+ table.erase(value);
+
+ UNIT_ASSERT_EQUAL(table.size(), 0);
+ UNIT_ASSERT_EQUAL(table.count(value), 0);
+ }, TRemovalContainers{});
+ }
+
+ Y_UNIT_TEST(EraseBigTest) {
+ ForEachTable<int>([](auto t) {
+ GET_TYPE(t) table{ BIG_INIT_SIZE };
+
+ for (int i = 0; i < 1000; ++i) {
+ for (int j = 0; j < static_cast<int>(BIG_INIT_SIZE); ++j) {
+ table.emplace(j);
+ }
+ for (int j = 0; j < static_cast<int>(BIG_INIT_SIZE); ++j) {
+ table.erase(j);
+ }
+ }
+ UNIT_ASSERT(table.bucket_count() <= BIG_INIT_SIZE * 8);
+ }, TRemovalContainers{});
+ }
+
+ Y_UNIT_TEST(ConstructWithSizeTest) {
+ ForEachTable<int>([](auto t) {
+ GET_TYPE(t) table{ 1000 };
+ UNIT_ASSERT(table.bucket_count() >= 1000);
+
+ int value = RandomNumber<ui32>();
+ table.insert(value);
+ UNIT_ASSERT_EQUAL(table.size(), 1);
+ UNIT_ASSERT_EQUAL(table.count(value), 1);
+ UNIT_ASSERT(table.bucket_count() >= 1000);
+
+ table.rehash(10);
+ UNIT_ASSERT_EQUAL(table.size(), 1);
+ UNIT_ASSERT_EQUAL(table.count(value), 1);
+ UNIT_ASSERT(table.bucket_count() < 1000);
+ UNIT_ASSERT(table.bucket_count() >= 10);
+ }, TContainers{});
+ }
+}
diff --git a/library/cpp/containers/flat_hash/lib/ut/ya.make b/library/cpp/containers/flat_hash/lib/ut/ya.make
new file mode 100644
index 0000000000..04d65a8c6e
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/ut/ya.make
@@ -0,0 +1,17 @@
+UNITTEST()
+
+OWNER(tender-bum)
+
+SRCS(
+ size_fitters_ut.cpp
+ probings_ut.cpp
+ containers_ut.cpp
+ iterator_ut.cpp
+ table_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/containers/flat_hash/lib
+)
+
+END()
diff --git a/library/cpp/containers/flat_hash/lib/value_markers.cpp b/library/cpp/containers/flat_hash/lib/value_markers.cpp
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/value_markers.cpp
diff --git a/library/cpp/containers/flat_hash/lib/value_markers.h b/library/cpp/containers/flat_hash/lib/value_markers.h
new file mode 100644
index 0000000000..99351586b5
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/value_markers.h
@@ -0,0 +1,130 @@
+#pragma once
+
+#include "concepts/value_marker.h"
+
+#include <type_traits>
+#include <tuple>
+
+namespace NFlatHash {
+
+namespace NSet {
+
+template <auto Value>
+struct TStaticValueMarker {
+ using value_type = decltype(Value);
+
+ constexpr auto Create() const noexcept {
+ return Value;
+ }
+
+ template <class U>
+ bool Equals(const U& rhs) const {
+ return Value == rhs;
+ }
+};
+
+static_assert(NConcepts::ValueMarkerV<TStaticValueMarker<5>>);
+
+template <class T>
+class TEqValueMarker {
+public:
+ using value_type = T;
+
+ template <class V, class = std::enable_if_t<std::is_constructible_v<T, std::decay_t<V>>>>
+ TEqValueMarker(V&& v) : Value_(std::forward<V>(v)) {}
+
+ TEqValueMarker(const TEqValueMarker&) = default;
+ TEqValueMarker(TEqValueMarker&&) = default;
+
+ TEqValueMarker& operator=(const TEqValueMarker&) = default;
+ TEqValueMarker& operator=(TEqValueMarker&&) = default;
+
+ const T& Create() const noexcept {
+ return Value_;
+ }
+
+ template <class U>
+ bool Equals(const U& rhs) const {
+ return Value_ == rhs;
+ }
+
+private:
+ T Value_;
+};
+
+static_assert(NConcepts::ValueMarkerV<TEqValueMarker<int>>);
+
+} // namespace NSet
+
+namespace NMap {
+
+template <auto Key, class T>
+class TStaticValueMarker {
+ static_assert(std::is_default_constructible_v<T>);
+
+public:
+ using value_type = std::pair<decltype(Key), T>;
+
+ TStaticValueMarker() = default;
+
+ TStaticValueMarker(const TStaticValueMarker&) {}
+ TStaticValueMarker(TStaticValueMarker&&) {}
+
+ TStaticValueMarker& operator=(const TStaticValueMarker&) noexcept { return *this; }
+ TStaticValueMarker& operator=(TStaticValueMarker&&) noexcept { return *this; }
+
+ std::pair<decltype(Key), const T&> Create() const noexcept { return { Key, Value_ }; }
+
+ template <class U>
+ bool Equals(const U& rhs) const {
+ return Key == rhs.first;
+ }
+
+private:
+ T Value_;
+};
+
+static_assert(NConcepts::ValueMarkerV<TStaticValueMarker<5, int>>);
+
+template <class Key, class T>
+class TEqValueMarker {
+ static_assert(std::is_default_constructible_v<T>);
+
+public:
+ using value_type = std::pair<Key, T>;
+
+ template <class V, class = std::enable_if_t<std::is_constructible_v<Key, std::decay_t<V>>>>
+ TEqValueMarker(V&& v) : Key_(std::forward<V>(v)) {}
+
+ TEqValueMarker(const TEqValueMarker& vm)
+ : Key_(vm.Key_) {}
+ TEqValueMarker(TEqValueMarker&& vm) noexcept(std::is_nothrow_move_constructible_v<Key>
+ && std::is_nothrow_constructible_v<T>)
+ : Key_(std::move(vm.Key_)) {}
+
+ TEqValueMarker& operator=(const TEqValueMarker& vm) {
+ Key_ = vm.Key_;
+ return *this;
+ }
+ TEqValueMarker& operator=(TEqValueMarker&& vm) noexcept(std::is_nothrow_move_assignable_v<Key>) {
+ Key_ = std::move(vm.Key_);
+ return *this;
+ }
+
+ auto Create() const noexcept { return std::tie(Key_, Value_); }
+
+ template <class U>
+ bool Equals(const U& rhs) const {
+ return Key_ == rhs.first;
+ }
+
+private:
+ Key Key_;
+ T Value_;
+};
+
+static_assert(NConcepts::ValueMarkerV<TEqValueMarker<int, int>>);
+
+} // namespace NMap
+
+} // namespace NFlatHash
diff --git a/library/cpp/containers/flat_hash/lib/ya.make b/library/cpp/containers/flat_hash/lib/ya.make
new file mode 100644
index 0000000000..afaa69110b
--- /dev/null
+++ b/library/cpp/containers/flat_hash/lib/ya.make
@@ -0,0 +1,17 @@
+LIBRARY()
+
+OWNER(tender-bum)
+
+SRCS(
+ containers.cpp
+ expanders.cpp
+ iterator.cpp
+ map.cpp
+ probings.cpp
+ set.cpp
+ size_fitters.cpp
+ table.cpp
+ value_markers.cpp
+)
+
+END()
diff --git a/library/cpp/containers/flat_hash/ut/flat_hash_ut.cpp b/library/cpp/containers/flat_hash/ut/flat_hash_ut.cpp
new file mode 100644
index 0000000000..2b9d6a1dc2
--- /dev/null
+++ b/library/cpp/containers/flat_hash/ut/flat_hash_ut.cpp
@@ -0,0 +1,272 @@
+#include <library/cpp/containers/flat_hash/flat_hash.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NFH;
+
+namespace {
+
+constexpr size_t TEST_INIT_SIZE = 25;
+constexpr std::initializer_list<int> SET_INPUT_SAMPLE{1, 2, 3, 4, 5};
+const std::initializer_list<std::pair<const int, TString>> MAP_INPUT_SAMPLE{
+ {1, "a"},
+ {2, "b"},
+ {3, "c"},
+ {4, "d"},
+ {5, "e"}
+};
+
+} // namespace
+
+template <class Map>
+class TMapTest : public TTestBase {
+ void AllocatorTest();
+
+ void SmokingTest() {
+ Map mp;
+ mp.emplace(5, "abc");
+
+ UNIT_ASSERT_EQUAL(mp.size(), 1);
+ UNIT_ASSERT(mp.contains(5));
+
+ auto it = mp.find(5);
+ UNIT_ASSERT_EQUAL(mp.begin(), it);
+ UNIT_ASSERT(!mp.empty());
+ }
+
+ void CopyConstructionTest() {
+ Map st(MAP_INPUT_SAMPLE);
+ auto st2 = st;
+
+ UNIT_ASSERT(!st.empty());
+ UNIT_ASSERT(!st2.empty());
+ UNIT_ASSERT_EQUAL(st, st2);
+ }
+
+ void MoveConstructionTest() {
+ Map st(MAP_INPUT_SAMPLE);
+ auto st2 = std::move(st);
+
+ UNIT_ASSERT(st.empty());
+ UNIT_ASSERT(!st2.empty());
+ UNIT_ASSERT_UNEQUAL(st, st2);
+ }
+
+ void CopyAssignmentTest() {
+ Map st(MAP_INPUT_SAMPLE);
+ Map st2;
+ UNIT_ASSERT_UNEQUAL(st, st2);
+ UNIT_ASSERT(st2.empty());
+
+ st2 = st;
+ UNIT_ASSERT_EQUAL(st, st2);
+ UNIT_ASSERT(!st2.empty());
+ }
+
+ void DoubleCopyAssignmentTest() {
+ Map st(MAP_INPUT_SAMPLE);
+ Map st2;
+ UNIT_ASSERT_UNEQUAL(st, st2);
+ UNIT_ASSERT(st2.empty());
+
+ st2 = st;
+ UNIT_ASSERT_EQUAL(st, st2);
+ UNIT_ASSERT(!st2.empty());
+
+ st2 = st;
+ UNIT_ASSERT_EQUAL(st, st2);
+ UNIT_ASSERT(!st2.empty());
+ }
+
+ void MoveAssignmentTest() {
+ Map st(MAP_INPUT_SAMPLE);
+ Map st2;
+ UNIT_ASSERT_UNEQUAL(st, st2);
+ UNIT_ASSERT(st2.empty());
+
+ st2 = std::move(st);
+ UNIT_ASSERT_UNEQUAL(st, st2);
+ UNIT_ASSERT(!st2.empty());
+ UNIT_ASSERT(st.empty());
+ }
+
+ void InsertOrAssignTest() {
+ Map mp;
+
+ auto p = mp.insert_or_assign(5, "abc");
+ UNIT_ASSERT_EQUAL(p.first, mp.begin());
+ UNIT_ASSERT(p.second);
+ UNIT_ASSERT_EQUAL(p.first->first, 5);
+ UNIT_ASSERT_EQUAL(p.first->second, "abc");
+
+ auto p2 = mp.insert_or_assign(5, "def");
+ UNIT_ASSERT_EQUAL(p.first, p2.first);
+ UNIT_ASSERT(!p2.second);
+ UNIT_ASSERT_EQUAL(p2.first->first, 5);
+ UNIT_ASSERT_EQUAL(p2.first->second, "def");
+ }
+
+ void TryEmplaceTest() {
+ Map mp;
+
+ auto p = mp.try_emplace(5, "abc");
+ UNIT_ASSERT_EQUAL(p.first, mp.begin());
+ UNIT_ASSERT(p.second);
+ UNIT_ASSERT_EQUAL(p.first->first, 5);
+ UNIT_ASSERT_EQUAL(p.first->second, "abc");
+
+ auto p2 = mp.try_emplace(5, "def");
+ UNIT_ASSERT_EQUAL(p.first, p2.first);
+ UNIT_ASSERT(!p2.second);
+ UNIT_ASSERT_EQUAL(p2.first->first, 5);
+ UNIT_ASSERT_EQUAL(p.first->second, "abc");
+ }
+
+ UNIT_TEST_SUITE_DEMANGLE(TMapTest);
+ UNIT_TEST(AllocatorTest);
+ UNIT_TEST(SmokingTest);
+ UNIT_TEST(CopyConstructionTest);
+ UNIT_TEST(MoveConstructionTest);
+ UNIT_TEST(CopyAssignmentTest);
+ UNIT_TEST(DoubleCopyAssignmentTest);
+ UNIT_TEST(MoveAssignmentTest);
+ UNIT_TEST(InsertOrAssignTest);
+ UNIT_TEST(TryEmplaceTest);
+ UNIT_TEST_SUITE_END();
+};
+
+template <>
+void TMapTest<TFlatHashMap<int, TString>>::AllocatorTest() {
+ using Map = TFlatHashMap<int, TString>;
+ Map mp(3, typename Map::allocator_type());
+}
+
+template <>
+void TMapTest<TDenseHashMapStaticMarker<int, TString, -1>>::AllocatorTest() {
+ using Map = TDenseHashMapStaticMarker<int, TString, -1>;
+ Map mp(3, NFlatHash::NMap::TStaticValueMarker<-1, TString>(), typename Map::allocator_type());
+}
+
+using TFlatHashMapTest = TMapTest<TFlatHashMap<int, TString>>;
+using TDenseHashMapTest = TMapTest<TDenseHashMapStaticMarker<int, TString, -1>>;
+
+UNIT_TEST_SUITE_REGISTRATION(TFlatHashMapTest);
+UNIT_TEST_SUITE_REGISTRATION(TDenseHashMapTest);
+
+
+template <class Set>
+class TSetTest : public TTestBase {
+ void AllocatorTest();
+ void DefaultConstructTest() {
+ Set st;
+
+ UNIT_ASSERT(st.empty());
+ UNIT_ASSERT_EQUAL(st.size(), 0);
+ UNIT_ASSERT(st.bucket_count() > 0);
+ UNIT_ASSERT_EQUAL(st.begin(), st.end());
+ UNIT_ASSERT(st.load_factor() < std::numeric_limits<float>::epsilon());
+ }
+
+ void InitCapacityConstructTest() {
+ Set st(TEST_INIT_SIZE);
+
+ UNIT_ASSERT(st.empty());
+ UNIT_ASSERT_EQUAL(st.size(), 0);
+ UNIT_ASSERT(st.bucket_count() >= TEST_INIT_SIZE);
+ UNIT_ASSERT_EQUAL(st.begin(), st.end());
+ UNIT_ASSERT(st.load_factor() < std::numeric_limits<float>::epsilon());
+ }
+
+ void IteratorsConstructTest() {
+ Set st(SET_INPUT_SAMPLE.begin(), SET_INPUT_SAMPLE.end());
+
+ UNIT_ASSERT(!st.empty());
+ UNIT_ASSERT_EQUAL(st.size(), SET_INPUT_SAMPLE.size());
+ UNIT_ASSERT(st.bucket_count() >= st.size());
+ UNIT_ASSERT_UNEQUAL(st.begin(), st.end());
+ UNIT_ASSERT_EQUAL(static_cast<size_t>(std::distance(st.begin(), st.end())), st.size());
+ UNIT_ASSERT(st.load_factor() > 0);
+ }
+
+ void InitializerListConstructTest() {
+ Set st(SET_INPUT_SAMPLE);
+
+ UNIT_ASSERT(!st.empty());
+ UNIT_ASSERT(st.size() > 0);
+ UNIT_ASSERT(st.bucket_count() > 0);
+ UNIT_ASSERT_UNEQUAL(st.begin(), st.end());
+ UNIT_ASSERT_EQUAL(static_cast<size_t>(std::distance(st.begin(), st.end())), st.size());
+ UNIT_ASSERT(st.load_factor() > 0);
+ }
+
+ void CopyConstructionTest() {
+ Set st(SET_INPUT_SAMPLE);
+ auto st2 = st;
+
+ UNIT_ASSERT(!st.empty());
+ UNIT_ASSERT(!st2.empty());
+ UNIT_ASSERT_EQUAL(st, st2);
+ }
+
+ void MoveConstructionTest() {
+ Set st(SET_INPUT_SAMPLE);
+ auto st2 = std::move(st);
+
+ UNIT_ASSERT(st.empty());
+ UNIT_ASSERT(!st2.empty());
+ UNIT_ASSERT_UNEQUAL(st, st2);
+ }
+
+ void CopyAssignmentTest() {
+ Set st(SET_INPUT_SAMPLE);
+ Set st2;
+ UNIT_ASSERT_UNEQUAL(st, st2);
+ UNIT_ASSERT(st2.empty());
+
+ st2 = st;
+ UNIT_ASSERT_EQUAL(st, st2);
+ UNIT_ASSERT(!st2.empty());
+ }
+
+ void MoveAssignmentTest() {
+ Set st(SET_INPUT_SAMPLE);
+ Set st2;
+ UNIT_ASSERT_UNEQUAL(st, st2);
+ UNIT_ASSERT(st2.empty());
+
+ st2 = std::move(st);
+ UNIT_ASSERT_UNEQUAL(st, st2);
+ UNIT_ASSERT(!st2.empty());
+ UNIT_ASSERT(st.empty());
+ }
+
+ UNIT_TEST_SUITE_DEMANGLE(TSetTest);
+ UNIT_TEST(AllocatorTest);
+ UNIT_TEST(DefaultConstructTest);
+ UNIT_TEST(InitCapacityConstructTest);
+ UNIT_TEST(IteratorsConstructTest);
+ UNIT_TEST(InitializerListConstructTest);
+ UNIT_TEST(CopyConstructionTest);
+ UNIT_TEST(MoveConstructionTest);
+ UNIT_TEST(CopyAssignmentTest);
+ UNIT_TEST(MoveAssignmentTest);
+ UNIT_TEST_SUITE_END();
+};
+
+template <>
+void TSetTest<TFlatHashSet<int>>::AllocatorTest() {
+ using Map = TFlatHashSet<int>;
+ Map mp(3, typename Map::allocator_type());
+}
+
+template <>
+void TSetTest<TDenseHashSetStaticMarker<int, -1>>::AllocatorTest() {
+ using Map = TDenseHashSetStaticMarker<int, -1>;
+ Map mp(3, NFlatHash::NSet::TStaticValueMarker<-1>(), typename Map::allocator_type());
+}
+
+using TFlatHashSetTest = TSetTest<TFlatHashSet<int, THash<int>>>;
+using TDenseHashSetTest = TSetTest<TDenseHashSetStaticMarker<int, -1>>;
+
+UNIT_TEST_SUITE_REGISTRATION(TFlatHashSetTest);
+UNIT_TEST_SUITE_REGISTRATION(TDenseHashSetTest);
diff --git a/library/cpp/containers/flat_hash/ut/ya.make b/library/cpp/containers/flat_hash/ut/ya.make
new file mode 100644
index 0000000000..1d33d36120
--- /dev/null
+++ b/library/cpp/containers/flat_hash/ut/ya.make
@@ -0,0 +1,13 @@
+UNITTEST()
+
+OWNER(tender-bum)
+
+SRCS(
+ flat_hash_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/containers/flat_hash
+)
+
+END()
diff --git a/library/cpp/containers/flat_hash/ya.make b/library/cpp/containers/flat_hash/ya.make
new file mode 100644
index 0000000000..612e2c1cde
--- /dev/null
+++ b/library/cpp/containers/flat_hash/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(tender-bum)
+
+PEERDIR(
+ library/cpp/containers/flat_hash/lib
+)
+
+SRCS(
+ flat_hash.cpp
+)
+
+END()
diff --git a/library/cpp/containers/intrusive_avl_tree/avltree.cpp b/library/cpp/containers/intrusive_avl_tree/avltree.cpp
new file mode 100644
index 0000000000..dd27c7df41
--- /dev/null
+++ b/library/cpp/containers/intrusive_avl_tree/avltree.cpp
@@ -0,0 +1 @@
+#include "avltree.h"
diff --git a/library/cpp/containers/intrusive_avl_tree/avltree.h b/library/cpp/containers/intrusive_avl_tree/avltree.h
new file mode 100644
index 0000000000..a58c63b07c
--- /dev/null
+++ b/library/cpp/containers/intrusive_avl_tree/avltree.h
@@ -0,0 +1,754 @@
+#pragma once
+
+#include <util/generic/noncopyable.h>
+
+template <class T, class C>
+struct TAvlTreeItem;
+
+template <class T, class C>
+class TAvlTree: public TNonCopyable {
+ using TTreeItem = TAvlTreeItem<T, C>;
+ friend struct TAvlTreeItem<T, C>;
+
+ static inline const T* AsT(const TTreeItem* item) noexcept {
+ return (const T*)item;
+ }
+
+ static inline T* AsT(TTreeItem* item) noexcept {
+ return (T*)item;
+ }
+
+ template <class TTreeItem, class TValue>
+ class TIteratorBase {
+ public:
+ inline TIteratorBase(TTreeItem* p, const TAvlTree* t) noexcept
+ : Ptr_(p)
+ , Tree_(t)
+ {
+ }
+
+ inline bool IsEnd() const noexcept {
+ return Ptr_ == nullptr;
+ }
+
+ inline bool IsBegin() const noexcept {
+ return Ptr_ == nullptr;
+ }
+
+ inline bool IsFirst() const noexcept {
+ return Ptr_ && Ptr_ == Tree_->Head_;
+ }
+
+ inline bool IsLast() const noexcept {
+ return Ptr_ && Ptr_ == Tree_->Tail_;
+ }
+
+ inline TValue& operator*() const noexcept {
+ return *AsT(Ptr_);
+ }
+
+ inline TValue* operator->() const noexcept {
+ return AsT(Ptr_);
+ }
+
+ inline TTreeItem* Inc() noexcept {
+ return Ptr_ = FindNext(Ptr_);
+ }
+
+ inline TTreeItem* Dec() noexcept {
+ return Ptr_ = FindPrev(Ptr_);
+ }
+
+ inline TIteratorBase& operator++() noexcept {
+ Inc();
+ return *this;
+ }
+
+ inline TIteratorBase operator++(int) noexcept {
+ TIteratorBase ret(*this);
+ Inc();
+ return ret;
+ }
+
+ inline TIteratorBase& operator--() noexcept {
+ Dec();
+ return *this;
+ }
+
+ inline TIteratorBase operator--(int) noexcept {
+ TIteratorBase ret(*this);
+ Dec();
+ return ret;
+ }
+
+ inline TIteratorBase Next() const noexcept {
+ return ConstructNext(*this);
+ }
+
+ inline TIteratorBase Prev() const noexcept {
+ return ConstructPrev(*this);
+ }
+
+ inline bool operator==(const TIteratorBase& r) const noexcept {
+ return Ptr_ == r.Ptr_;
+ }
+
+ inline bool operator!=(const TIteratorBase& r) const noexcept {
+ return Ptr_ != r.Ptr_;
+ }
+
+ private:
+ inline static TIteratorBase ConstructNext(const TIteratorBase& i) noexcept {
+ return TIterator(FindNext(i.Ptr_), i.Tree_);
+ }
+
+ inline static TIteratorBase ConstructPrev(const TIteratorBase& i) noexcept {
+ return TIterator(FindPrev(i.Ptr_), i.Tree_);
+ }
+
+ inline static TIteratorBase FindPrev(TTreeItem* el) noexcept {
+ if (el->Left_ != nullptr) {
+ el = el->Left_;
+
+ while (el->Right_ != nullptr) {
+ el = el->Right_;
+ }
+ } else {
+ while (true) {
+ TTreeItem* last = el;
+ el = el->Parent_;
+
+ if (el == nullptr || el->Right_ == last) {
+ break;
+ }
+ }
+ }
+
+ return el;
+ }
+
+ static TTreeItem* FindNext(TTreeItem* el) {
+ if (el->Right_ != nullptr) {
+ el = el->Right_;
+
+ while (el->Left_) {
+ el = el->Left_;
+ }
+ } else {
+ while (true) {
+ TTreeItem* last = el;
+ el = el->Parent_;
+
+ if (el == nullptr || el->Left_ == last) {
+ break;
+ }
+ }
+ }
+
+ return el;
+ }
+
+ private:
+ TTreeItem* Ptr_;
+ const TAvlTree* Tree_;
+ };
+
+ using TConstIterator = TIteratorBase<const TTreeItem, const T>;
+ using TIterator = TIteratorBase<TTreeItem, T>;
+
+ static inline TConstIterator ConstructFirstConst(const TAvlTree* t) noexcept {
+ return TConstIterator(t->Head_, t);
+ }
+
+ static inline TIterator ConstructFirst(const TAvlTree* t) noexcept {
+ return TIterator(t->Head_, t);
+ }
+
+ static inline TConstIterator ConstructLastConst(const TAvlTree* t) noexcept {
+ return TConstIterator(t->Tail_, t);
+ }
+
+ static inline TIterator ConstructLast(const TAvlTree* t) noexcept {
+ return TIterator(t->Tail_, t);
+ }
+
+ static inline bool Compare(const TTreeItem& l, const TTreeItem& r) {
+ return C::Compare(*AsT(&l), *AsT(&r));
+ }
+
+public:
+ using const_iterator = TConstIterator;
+ using iterator = TIterator;
+
+ inline TAvlTree() noexcept
+ : Root_(nullptr)
+ , Head_(nullptr)
+ , Tail_(nullptr)
+ {
+ }
+
+ inline ~TAvlTree() noexcept {
+ Clear();
+ }
+
+ inline void Clear() noexcept {
+ for (iterator it = Begin(); it != End();) {
+ (it++)->TTreeItem::Unlink();
+ }
+ }
+
+ inline T* Insert(TTreeItem* el, TTreeItem** lastFound = nullptr) noexcept {
+ el->Unlink();
+ el->Tree_ = this;
+
+ TTreeItem* curEl = Root_;
+ TTreeItem* parentEl = nullptr;
+ TTreeItem* lastLess = nullptr;
+
+ while (true) {
+ if (curEl == nullptr) {
+ AttachRebal(el, parentEl, lastLess);
+
+ if (lastFound != nullptr) {
+ *lastFound = el;
+ }
+
+ return AsT(el);
+ }
+
+ if (Compare(*el, *curEl)) {
+ parentEl = lastLess = curEl;
+ curEl = curEl->Left_;
+ } else if (Compare(*curEl, *el)) {
+ parentEl = curEl;
+ curEl = curEl->Right_;
+ } else {
+ if (lastFound != nullptr) {
+ *lastFound = curEl;
+ }
+
+ return nullptr;
+ }
+ }
+ }
+
+ inline T* Find(const TTreeItem* el) const noexcept {
+ TTreeItem* curEl = Root_;
+
+ while (curEl) {
+ if (Compare(*el, *curEl)) {
+ curEl = curEl->Left_;
+ } else if (Compare(*curEl, *el)) {
+ curEl = curEl->Right_;
+ } else {
+ return AsT(curEl);
+ }
+ }
+
+ return nullptr;
+ }
+
+ inline T* LowerBound(const TTreeItem* el) const noexcept {
+ TTreeItem* curEl = Root_;
+ TTreeItem* lowerBound = nullptr;
+
+ while (curEl) {
+ if (Compare(*el, *curEl)) {
+ lowerBound = curEl;
+ curEl = curEl->Left_;
+ } else if (Compare(*curEl, *el)) {
+ curEl = curEl->Right_;
+ } else {
+ return AsT(curEl);
+ }
+ }
+
+ return AsT(lowerBound);
+ }
+
+ inline T* Erase(TTreeItem* el) noexcept {
+ if (el->Tree_ == this) {
+ return this->EraseImpl(el);
+ }
+
+ return nullptr;
+ }
+
+ inline T* EraseImpl(TTreeItem* el) noexcept {
+ el->Tree_ = nullptr;
+
+ TTreeItem* replacement;
+ TTreeItem* fixfrom;
+ long lheight, rheight;
+
+ if (el->Right_) {
+ replacement = el->Right_;
+
+ while (replacement->Left_) {
+ replacement = replacement->Left_;
+ }
+
+ if (replacement->Parent_ == el) {
+ fixfrom = replacement;
+ } else {
+ fixfrom = replacement->Parent_;
+ }
+
+ if (el == Head_) {
+ Head_ = replacement;
+ }
+
+ RemoveEl(replacement, replacement->Right_);
+ ReplaceEl(el, replacement);
+ } else if (el->Left_) {
+ replacement = el->Left_;
+
+ while (replacement->Right_) {
+ replacement = replacement->Right_;
+ }
+
+ if (replacement->Parent_ == el) {
+ fixfrom = replacement;
+ } else {
+ fixfrom = replacement->Parent_;
+ }
+
+ if (el == Tail_) {
+ Tail_ = replacement;
+ }
+
+ RemoveEl(replacement, replacement->Left_);
+ ReplaceEl(el, replacement);
+ } else {
+ fixfrom = el->Parent_;
+
+ if (el == Head_) {
+ Head_ = el->Parent_;
+ }
+
+ if (el == Tail_) {
+ Tail_ = el->Parent_;
+ }
+
+ RemoveEl(el, nullptr);
+ }
+
+ if (fixfrom == nullptr) {
+ return AsT(el);
+ }
+
+ RecalcHeights(fixfrom);
+
+ TTreeItem* ub = FindFirstUnbalEl(fixfrom);
+
+ while (ub) {
+ lheight = ub->Left_ ? ub->Left_->Height_ : 0;
+ rheight = ub->Right_ ? ub->Right_->Height_ : 0;
+
+ if (rheight > lheight) {
+ ub = ub->Right_;
+ lheight = ub->Left_ ? ub->Left_->Height_ : 0;
+ rheight = ub->Right_ ? ub->Right_->Height_ : 0;
+
+ if (rheight > lheight) {
+ ub = ub->Right_;
+ } else if (rheight < lheight) {
+ ub = ub->Left_;
+ } else {
+ ub = ub->Right_;
+ }
+ } else {
+ ub = ub->Left_;
+ lheight = ub->Left_ ? ub->Left_->Height_ : 0;
+ rheight = ub->Right_ ? ub->Right_->Height_ : 0;
+ if (rheight > lheight) {
+ ub = ub->Right_;
+ } else if (rheight < lheight) {
+ ub = ub->Left_;
+ } else {
+ ub = ub->Left_;
+ }
+ }
+
+ fixfrom = Rebalance(ub);
+ ub = FindFirstUnbalEl(fixfrom);
+ }
+
+ return AsT(el);
+ }
+
+ inline const_iterator First() const noexcept {
+ return ConstructFirstConst(this);
+ }
+
+ inline const_iterator Last() const noexcept {
+ return ConstructLastConst(this);
+ }
+
+ inline const_iterator Begin() const noexcept {
+ return First();
+ }
+
+ inline const_iterator End() const noexcept {
+ return const_iterator(nullptr, this);
+ }
+
+ inline const_iterator begin() const noexcept {
+ return Begin();
+ }
+
+ inline const_iterator end() const noexcept {
+ return End();
+ }
+
+ inline const_iterator cbegin() const noexcept {
+ return Begin();
+ }
+
+ inline const_iterator cend() const noexcept {
+ return End();
+ }
+
+ inline iterator First() noexcept {
+ return ConstructFirst(this);
+ }
+
+ inline iterator Last() noexcept {
+ return ConstructLast(this);
+ }
+
+ inline iterator Begin() noexcept {
+ return First();
+ }
+
+ inline iterator End() noexcept {
+ return iterator(nullptr, this);
+ }
+
+ inline iterator begin() noexcept {
+ return Begin();
+ }
+
+ inline iterator end() noexcept {
+ return End();
+ }
+
+ inline bool Empty() const noexcept {
+ return const_cast<TAvlTree*>(this)->Begin() == const_cast<TAvlTree*>(this)->End();
+ }
+
+ inline explicit operator bool() const noexcept {
+ return !this->Empty();
+ }
+
+ template <class Functor>
+ inline void ForEach(Functor& f) {
+ iterator it = Begin();
+
+ while (!it.IsEnd()) {
+ iterator next = it;
+ ++next;
+ f(*it);
+ it = next;
+ }
+ }
+
+private:
+ inline TTreeItem* Rebalance(TTreeItem* n) noexcept {
+ long lheight, rheight;
+
+ TTreeItem* a;
+ TTreeItem* b;
+ TTreeItem* c;
+ TTreeItem* t1;
+ TTreeItem* t2;
+ TTreeItem* t3;
+ TTreeItem* t4;
+
+ TTreeItem* p = n->Parent_;
+ TTreeItem* gp = p->Parent_;
+ TTreeItem* ggp = gp->Parent_;
+
+ if (gp->Right_ == p) {
+ if (p->Right_ == n) {
+ a = gp;
+ b = p;
+ c = n;
+ t1 = gp->Left_;
+ t2 = p->Left_;
+ t3 = n->Left_;
+ t4 = n->Right_;
+ } else {
+ a = gp;
+ b = n;
+ c = p;
+ t1 = gp->Left_;
+ t2 = n->Left_;
+ t3 = n->Right_;
+ t4 = p->Right_;
+ }
+ } else {
+ if (p->Right_ == n) {
+ a = p;
+ b = n;
+ c = gp;
+ t1 = p->Left_;
+ t2 = n->Left_;
+ t3 = n->Right_;
+ t4 = gp->Right_;
+ } else {
+ a = n;
+ b = p;
+ c = gp;
+ t1 = n->Left_;
+ t2 = n->Right_;
+ t3 = p->Right_;
+ t4 = gp->Right_;
+ }
+ }
+
+ if (ggp == nullptr) {
+ Root_ = b;
+ } else if (ggp->Left_ == gp) {
+ ggp->Left_ = b;
+ } else {
+ ggp->Right_ = b;
+ }
+
+ b->Parent_ = ggp;
+ b->Left_ = a;
+ a->Parent_ = b;
+ b->Right_ = c;
+ c->Parent_ = b;
+ a->Left_ = t1;
+
+ if (t1 != nullptr) {
+ t1->Parent_ = a;
+ }
+
+ a->Right_ = t2;
+
+ if (t2 != nullptr) {
+ t2->Parent_ = a;
+ }
+
+ c->Left_ = t3;
+
+ if (t3 != nullptr) {
+ t3->Parent_ = c;
+ }
+
+ c->Right_ = t4;
+
+ if (t4 != nullptr) {
+ t4->Parent_ = c;
+ }
+
+ lheight = a->Left_ ? a->Left_->Height_ : 0;
+ rheight = a->Right_ ? a->Right_->Height_ : 0;
+ a->Height_ = (lheight > rheight ? lheight : rheight) + 1;
+
+ lheight = c->Left_ ? c->Left_->Height_ : 0;
+ rheight = c->Right_ ? c->Right_->Height_ : 0;
+ c->Height_ = (lheight > rheight ? lheight : rheight) + 1;
+
+ lheight = a->Height_;
+ rheight = c->Height_;
+ b->Height_ = (lheight > rheight ? lheight : rheight) + 1;
+
+ RecalcHeights(ggp);
+
+ return ggp;
+ }
+
+ inline void RecalcHeights(TTreeItem* el) noexcept {
+ long lheight, rheight, new_height;
+
+ while (el) {
+ lheight = el->Left_ ? el->Left_->Height_ : 0;
+ rheight = el->Right_ ? el->Right_->Height_ : 0;
+
+ new_height = (lheight > rheight ? lheight : rheight) + 1;
+
+ if (new_height == el->Height_) {
+ return;
+ } else {
+ el->Height_ = new_height;
+ }
+
+ el = el->Parent_;
+ }
+ }
+
+ inline TTreeItem* FindFirstUnbalGP(TTreeItem* el) noexcept {
+ long lheight, rheight, balanceProp;
+ TTreeItem* gp;
+
+ if (el == nullptr || el->Parent_ == nullptr || el->Parent_->Parent_ == nullptr) {
+ return nullptr;
+ }
+
+ gp = el->Parent_->Parent_;
+
+ while (gp != nullptr) {
+ lheight = gp->Left_ ? gp->Left_->Height_ : 0;
+ rheight = gp->Right_ ? gp->Right_->Height_ : 0;
+ balanceProp = lheight - rheight;
+
+ if (balanceProp < -1 || balanceProp > 1) {
+ return el;
+ }
+
+ el = el->Parent_;
+ gp = gp->Parent_;
+ }
+
+ return nullptr;
+ }
+
+ inline TTreeItem* FindFirstUnbalEl(TTreeItem* el) noexcept {
+ if (el == nullptr) {
+ return nullptr;
+ }
+
+ while (el) {
+ const long lheight = el->Left_ ? el->Left_->Height_ : 0;
+ const long rheight = el->Right_ ? el->Right_->Height_ : 0;
+ const long balanceProp = lheight - rheight;
+
+ if (balanceProp < -1 || balanceProp > 1) {
+ return el;
+ }
+
+ el = el->Parent_;
+ }
+
+ return nullptr;
+ }
+
+ inline void ReplaceEl(TTreeItem* el, TTreeItem* replacement) noexcept {
+ TTreeItem* parent = el->Parent_;
+ TTreeItem* left = el->Left_;
+ TTreeItem* right = el->Right_;
+
+ replacement->Left_ = left;
+
+ if (left) {
+ left->Parent_ = replacement;
+ }
+
+ replacement->Right_ = right;
+
+ if (right) {
+ right->Parent_ = replacement;
+ }
+
+ replacement->Parent_ = parent;
+
+ if (parent) {
+ if (parent->Left_ == el) {
+ parent->Left_ = replacement;
+ } else {
+ parent->Right_ = replacement;
+ }
+ } else {
+ Root_ = replacement;
+ }
+
+ replacement->Height_ = el->Height_;
+ }
+
+ inline void RemoveEl(TTreeItem* el, TTreeItem* filler) noexcept {
+ TTreeItem* parent = el->Parent_;
+
+ if (parent) {
+ if (parent->Left_ == el) {
+ parent->Left_ = filler;
+ } else {
+ parent->Right_ = filler;
+ }
+ } else {
+ Root_ = filler;
+ }
+
+ if (filler) {
+ filler->Parent_ = parent;
+ }
+
+ return;
+ }
+
+ inline void AttachRebal(TTreeItem* el, TTreeItem* parentEl, TTreeItem* lastLess) {
+ el->Parent_ = parentEl;
+ el->Left_ = nullptr;
+ el->Right_ = nullptr;
+ el->Height_ = 1;
+
+ if (parentEl != nullptr) {
+ if (lastLess == parentEl) {
+ parentEl->Left_ = el;
+ } else {
+ parentEl->Right_ = el;
+ }
+
+ if (Head_->Left_ == el) {
+ Head_ = el;
+ }
+
+ if (Tail_->Right_ == el) {
+ Tail_ = el;
+ }
+ } else {
+ Root_ = el;
+ Head_ = Tail_ = el;
+ }
+
+ RecalcHeights(parentEl);
+
+ TTreeItem* ub = FindFirstUnbalGP(el);
+
+ if (ub != nullptr) {
+ Rebalance(ub);
+ }
+ }
+
+private:
+ TTreeItem* Root_;
+ TTreeItem* Head_;
+ TTreeItem* Tail_;
+};
+
+template <class T, class C>
+struct TAvlTreeItem: public TNonCopyable {
+public:
+ using TTree = TAvlTree<T, C>;
+ friend class TAvlTree<T, C>;
+ friend typename TAvlTree<T, C>::TConstIterator;
+ friend typename TAvlTree<T, C>::TIterator;
+
+ inline TAvlTreeItem() noexcept
+ : Left_(nullptr)
+ , Right_(nullptr)
+ , Parent_(nullptr)
+ , Height_(0)
+ , Tree_(nullptr)
+ {
+ }
+
+ inline ~TAvlTreeItem() noexcept {
+ Unlink();
+ }
+
+ inline void Unlink() noexcept {
+ if (Tree_) {
+ Tree_->EraseImpl(this);
+ }
+ }
+
+private:
+ TAvlTreeItem* Left_;
+ TAvlTreeItem* Right_;
+ TAvlTreeItem* Parent_;
+ long Height_;
+ TTree* Tree_;
+};
diff --git a/library/cpp/containers/intrusive_avl_tree/ut/avltree_ut.cpp b/library/cpp/containers/intrusive_avl_tree/ut/avltree_ut.cpp
new file mode 100644
index 0000000000..cab2365cce
--- /dev/null
+++ b/library/cpp/containers/intrusive_avl_tree/ut/avltree_ut.cpp
@@ -0,0 +1,103 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/containers/intrusive_avl_tree/avltree.h>
+
+class TAvlTreeTest: public TTestBase {
+ UNIT_TEST_SUITE(TAvlTreeTest);
+ UNIT_TEST(TestLowerBound);
+ UNIT_TEST(TestIterator);
+ UNIT_TEST_SUITE_END();
+
+private:
+ void TestLowerBound();
+ void TestIterator();
+
+ class TIt;
+ struct TItCompare {
+ static inline bool Compare(const TIt& l, const TIt& r) noexcept;
+ };
+
+ class TIt: public TAvlTreeItem<TIt, TItCompare> {
+ public:
+ TIt(int val = 0)
+ : Val(val)
+ {
+ }
+
+ int Val;
+ };
+
+ using TIts = TAvlTree<TIt, TItCompare>;
+};
+
+inline bool TAvlTreeTest::TItCompare::Compare(const TIt& l, const TIt& r) noexcept {
+ return l.Val < r.Val;
+}
+
+UNIT_TEST_SUITE_REGISTRATION(TAvlTreeTest);
+
+void TAvlTreeTest::TestLowerBound() {
+ TIts its;
+ TIt it1(5);
+ TIt it2(2);
+ TIt it3(10);
+ TIt it4(879);
+ TIt it5(1);
+ TIt it6(52);
+ TIt it7(4);
+ TIt it8(5);
+ its.Insert(&it1);
+ its.Insert(&it2);
+ its.Insert(&it3);
+ its.Insert(&it4);
+ its.Insert(&it5);
+ its.Insert(&it6);
+ its.Insert(&it7);
+ its.Insert(&it8);
+
+ TIt it_zero(0);
+ TIt it_large(1000);
+ UNIT_ASSERT_EQUAL(its.LowerBound(&it3), &it3);
+ UNIT_ASSERT_EQUAL(its.LowerBound(&it_zero), &it5);
+ UNIT_ASSERT_EQUAL(its.LowerBound(&it_large), nullptr);
+}
+
+void TAvlTreeTest::TestIterator() {
+ TIts its;
+ TIt it1(1);
+ TIt it2(2);
+ TIt it3(3);
+ TIt it4(4);
+ TIt it5(5);
+ TIt it6(6);
+ TIt it7(7);
+
+ its.Insert(&it3);
+ its.Insert(&it1);
+ its.Insert(&it7);
+ its.Insert(&it5);
+ its.Insert(&it4);
+ its.Insert(&it6);
+ its.Insert(&it2);
+
+ TVector<int> res;
+ for (const TIt& i : its) {
+ res.push_back(i.Val);
+ }
+
+ TVector<int> expected{1, 2, 3, 4, 5, 6, 7};
+ UNIT_ASSERT_EQUAL(res, expected);
+
+ res.clear();
+ for (TIt& i : its) {
+ res.push_back(i.Val);
+ }
+ UNIT_ASSERT_EQUAL(res, expected);
+
+ res.clear();
+ const TIts* constIts = &its;
+ for (TIts::const_iterator i = constIts->begin(); i != constIts->end(); ++i) {
+ res.push_back(i->Val);
+ }
+ UNIT_ASSERT_EQUAL(res, expected);
+}
diff --git a/library/cpp/containers/intrusive_avl_tree/ut/ya.make b/library/cpp/containers/intrusive_avl_tree/ut/ya.make
new file mode 100644
index 0000000000..87920306d7
--- /dev/null
+++ b/library/cpp/containers/intrusive_avl_tree/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/containers/intrusive_avl_tree)
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ avltree_ut.cpp
+)
+
+END()
diff --git a/library/cpp/containers/intrusive_avl_tree/ya.make b/library/cpp/containers/intrusive_avl_tree/ya.make
new file mode 100644
index 0000000000..6b061f2760
--- /dev/null
+++ b/library/cpp/containers/intrusive_avl_tree/ya.make
@@ -0,0 +1,12 @@
+LIBRARY()
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ avltree.cpp
+)
+
+END()
diff --git a/library/cpp/containers/intrusive_rb_tree/fuzz/rb_tree_fuzzing.cpp b/library/cpp/containers/intrusive_rb_tree/fuzz/rb_tree_fuzzing.cpp
new file mode 100644
index 0000000000..92370760b5
--- /dev/null
+++ b/library/cpp/containers/intrusive_rb_tree/fuzz/rb_tree_fuzzing.cpp
@@ -0,0 +1,65 @@
+#include <library/cpp/containers/intrusive_rb_tree/rb_tree.h>
+
+#include <util/generic/deque.h>
+#include <stdint.h>
+#include <stddef.h>
+
+struct TCmp {
+ template <class T>
+ static inline bool Compare(const T& l, const T& r) {
+ return l.N < r.N;
+ }
+
+ template <class T>
+ static inline bool Compare(const T& l, ui8 r) {
+ return l.N < r;
+ }
+
+ template <class T>
+ static inline bool Compare(ui8 l, const T& r) {
+ return l < r.N;
+ }
+};
+
+class TNode: public TRbTreeItem<TNode, TCmp> {
+public:
+ inline TNode(ui8 n) noexcept
+ : N(n)
+ {
+ }
+
+ ui8 N;
+};
+
+using TTree = TRbTree<TNode, TCmp>;
+
+extern "C" int LLVMFuzzerTestOneInput(const ui8* data, size_t size) {
+ TDeque<TNode> records;
+ const ui8 half = 128u;
+ TTree tree;
+ for (size_t i = 0; i < size; ++i) {
+ if (data[i] / half == 0) {
+ records.emplace_back(data[i] % half);
+ tree.Insert(&records.back());
+ } else {
+ auto* ptr = tree.Find(data[i] % half);
+ if (ptr != nullptr) {
+ tree.Erase(ptr);
+ }
+ }
+ auto check = [](const TNode& node) {
+ size_t childrens = 1;
+ if (node.Left_) {
+ Y_ENSURE(static_cast<const TNode*>(node.Left_)->N <= node.N);
+ childrens += node.Left_->Children_;
+ }
+ if (node.Right_) {
+ Y_ENSURE(node.N <= static_cast<const TNode*>(node.Right_)->N);
+ childrens += node.Right_->Children_;
+ }
+ Y_ENSURE(childrens == node.Children_);
+ };
+ tree.ForEach(check);
+ }
+ return 0;
+}
diff --git a/library/cpp/containers/intrusive_rb_tree/fuzz/ya.make b/library/cpp/containers/intrusive_rb_tree/fuzz/ya.make
new file mode 100644
index 0000000000..61be9919e6
--- /dev/null
+++ b/library/cpp/containers/intrusive_rb_tree/fuzz/ya.make
@@ -0,0 +1,20 @@
+FUZZ()
+
+OWNER(
+ g:util
+ mikari
+)
+
+SIZE(LARGE)
+
+TAG(ya:fat)
+
+PEERDIR(
+ library/cpp/containers/intrusive_rb_tree
+)
+
+SRCS(
+ rb_tree_fuzzing.cpp
+)
+
+END()
diff --git a/library/cpp/containers/intrusive_rb_tree/rb_tree.cpp b/library/cpp/containers/intrusive_rb_tree/rb_tree.cpp
new file mode 100644
index 0000000000..535b536c41
--- /dev/null
+++ b/library/cpp/containers/intrusive_rb_tree/rb_tree.cpp
@@ -0,0 +1 @@
+#include "rb_tree.h"
diff --git a/library/cpp/containers/intrusive_rb_tree/rb_tree.h b/library/cpp/containers/intrusive_rb_tree/rb_tree.h
new file mode 100644
index 0000000000..0259452a14
--- /dev/null
+++ b/library/cpp/containers/intrusive_rb_tree/rb_tree.h
@@ -0,0 +1,818 @@
+#pragma once
+
+#include <util/generic/utility.h>
+#include <util/generic/yexception.h>
+
+using TRbTreeColorType = bool;
+
+#define RBTreeRed false
+#define RBTreeBlack true
+
+struct TRbTreeNodeBase {
+ using TColorType = TRbTreeColorType;
+ using TBasePtr = TRbTreeNodeBase*;
+
+ TColorType Color_;
+ TBasePtr Parent_;
+ TBasePtr Left_;
+ TBasePtr Right_;
+ size_t Children_;
+
+ inline TRbTreeNodeBase() noexcept {
+ ReInitNode();
+ }
+
+ inline void ReInitNode() noexcept {
+ Color_ = RBTreeBlack;
+ Parent_ = nullptr;
+ Left_ = nullptr;
+ Right_ = nullptr;
+ Children_ = 1;
+ }
+
+ static TBasePtr MinimumNode(TBasePtr x) {
+ while (x->Left_ != nullptr)
+ x = x->Left_;
+
+ return x;
+ }
+
+ static TBasePtr MaximumNode(TBasePtr x) {
+ while (x->Right_ != nullptr)
+ x = x->Right_;
+
+ return x;
+ }
+
+ static TBasePtr ByIndex(TBasePtr x, size_t index) {
+ if (x->Left_ != nullptr) {
+ if (index < x->Left_->Children_)
+ return ByIndex(x->Left_, index);
+ index -= x->Left_->Children_;
+ }
+ if (0 == index)
+ return x;
+ if (!x->Right_)
+ ythrow yexception() << "index not found";
+ return ByIndex(x->Right_, index - 1);
+ }
+};
+
+struct TRbTreeBaseIterator;
+
+template <class TDummy>
+class TRbGlobal {
+public:
+ using TBasePtr = TRbTreeNodeBase*;
+
+ static void Rebalance(TBasePtr x, TBasePtr& root);
+ static TBasePtr RebalanceForErase(TBasePtr z, TBasePtr& root, TBasePtr& leftmost, TBasePtr& rightmost);
+ static void DecrementChildrenUntilRoot(TBasePtr x, TBasePtr root);
+ static void RecalcChildren(TBasePtr x);
+
+ static TBasePtr IncrementNode(TBasePtr);
+ static TBasePtr DecrementNode(TBasePtr);
+ static void RotateLeft(TBasePtr x, TBasePtr& root);
+ static void RotateRight(TBasePtr x, TBasePtr& root);
+};
+
+using TRbGlobalInst = TRbGlobal<bool>;
+
+struct TRbTreeBaseIterator {
+ using TBasePtr = TRbTreeNodeBase*;
+ TBasePtr Node_;
+
+ inline TRbTreeBaseIterator(TBasePtr x = nullptr) noexcept
+ : Node_(x)
+ {
+ }
+};
+
+template <class TValue, class TTraits>
+struct TRbTreeIterator: public TRbTreeBaseIterator {
+ using TReference = typename TTraits::TReference;
+ using TPointer = typename TTraits::TPointer;
+ using TSelf = TRbTreeIterator<TValue, TTraits>;
+ using TBasePtr = TRbTreeNodeBase*;
+
+ inline TRbTreeIterator() noexcept = default;
+
+ template <class T1>
+ inline TRbTreeIterator(const T1& x) noexcept
+ : TRbTreeBaseIterator(x)
+ {
+ }
+
+ inline TReference operator*() const noexcept {
+ return *static_cast<TValue*>(Node_);
+ }
+
+ inline TPointer operator->() const noexcept {
+ return static_cast<TValue*>(Node_);
+ }
+
+ inline TSelf& operator++() noexcept {
+ Node_ = TRbGlobalInst::IncrementNode(Node_);
+ return *this;
+ }
+
+ inline TSelf operator++(int) noexcept {
+ TSelf tmp = *this;
+ ++(*this);
+ return tmp;
+ }
+
+ inline TSelf& operator--() noexcept {
+ Node_ = TRbGlobalInst::DecrementNode(Node_);
+ return *this;
+ }
+
+ inline TSelf operator--(int) noexcept {
+ TSelf tmp = *this;
+ --(*this);
+ return tmp;
+ }
+
+ template <class T1>
+ inline bool operator==(const T1& rhs) const noexcept {
+ return Node_ == rhs.Node_;
+ }
+
+ template <class T1>
+ inline bool operator!=(const T1& rhs) const noexcept {
+ return Node_ != rhs.Node_;
+ }
+};
+
+template <class TValue, class TCmp>
+class TRbTree {
+ struct TCmpAdaptor: public TCmp {
+ inline TCmpAdaptor() noexcept = default;
+
+ inline TCmpAdaptor(const TCmp& cmp) noexcept
+ : TCmp(cmp)
+ {
+ }
+
+ template <class T1, class T2>
+ inline bool operator()(const T1& l, const T2& r) const {
+ return TCmp::Compare(l, r);
+ }
+ };
+
+ struct TNonConstTraits {
+ using TReference = TValue&;
+ using TPointer = TValue*;
+ };
+
+ struct TConstTraits {
+ using TReference = const TValue&;
+ using TPointer = const TValue*;
+ };
+
+ using TNodeBase = TRbTreeNodeBase;
+ using TBasePtr = TRbTreeNodeBase*;
+ using TColorType = TRbTreeColorType;
+
+public:
+ class TRealNode: public TNodeBase {
+ public:
+ inline TRealNode()
+ : Tree_(nullptr)
+ {
+ }
+
+ inline ~TRealNode() {
+ UnLink();
+ }
+
+ inline void UnLink() noexcept {
+ if (Tree_) {
+ Tree_->EraseImpl(this);
+ ReInitNode();
+ Tree_ = nullptr;
+ }
+ }
+
+ inline void SetRbTreeParent(TRbTree* parent) noexcept {
+ Tree_ = parent;
+ }
+
+ inline TRbTree* ParentTree() const noexcept {
+ return Tree_;
+ }
+
+ private:
+ TRbTree* Tree_;
+ };
+
+ using TIterator = TRbTreeIterator<TValue, TNonConstTraits>;
+ using TConstIterator = TRbTreeIterator<TValue, TConstTraits>;
+
+ inline TRbTree() noexcept {
+ Init();
+ }
+
+ inline TRbTree(const TCmp& cmp) noexcept
+ : KeyCompare_(cmp)
+ {
+ Init();
+ }
+
+ inline void Init() noexcept {
+ Data_.Color_ = RBTreeRed;
+ Data_.Parent_ = nullptr;
+ Data_.Left_ = &Data_;
+ Data_.Right_ = &Data_;
+ Data_.Children_ = 0;
+ }
+
+ struct TDestroy {
+ inline void operator()(TValue& v) const noexcept {
+ v.SetRbTreeParent(nullptr);
+ v.ReInitNode();
+ }
+ };
+
+ inline ~TRbTree() {
+ ForEachNoOrder(TDestroy());
+ }
+
+ inline void Clear() noexcept {
+ ForEachNoOrder(TDestroy());
+ Init();
+ }
+
+ template <class F>
+ inline void ForEachNoOrder(const F& f) {
+ ForEachNoOrder(Root(), f);
+ }
+
+ template <class F>
+ inline void ForEachNoOrder(TNodeBase* n, const F& f) {
+ if (n && n != &Data_) {
+ ForEachNoOrder(n->Left_, f);
+ ForEachNoOrder(n->Right_, f);
+ f(ValueNode(n));
+ }
+ }
+
+ inline TIterator Begin() noexcept {
+ return LeftMost();
+ }
+
+ inline TConstIterator Begin() const noexcept {
+ return LeftMost();
+ }
+
+ inline TIterator End() noexcept {
+ return &this->Data_;
+ }
+
+ inline TConstIterator End() const noexcept {
+ return const_cast<TBasePtr>(&this->Data_);
+ }
+
+ inline bool Empty() const noexcept {
+ return this->Begin() == this->End();
+ }
+
+ inline explicit operator bool() const noexcept {
+ return !this->Empty();
+ }
+
+ inline TIterator Insert(TValue* val) {
+ return Insert(*val);
+ }
+
+ inline TIterator Insert(TValue& val) {
+ val.UnLink();
+
+ TBasePtr y = &this->Data_;
+ TBasePtr x = Root();
+
+ while (x != nullptr) {
+ ++(x->Children_);
+ y = x;
+
+ if (KeyCompare_(ValueNode(&val), ValueNode(x))) {
+ x = LeftNode(x);
+ } else {
+ x = RightNode(x);
+ }
+ }
+
+ return InsertImpl(y, &val, x);
+ }
+
+ template <class F>
+ inline void ForEach(F& f) {
+ TIterator it = Begin();
+
+ while (it != End()) {
+ f(*it++);
+ }
+ }
+
+ inline void Erase(TValue& val) noexcept {
+ val.UnLink();
+ }
+
+ inline void Erase(TValue* val) noexcept {
+ Erase(*val);
+ }
+
+ inline void Erase(TIterator pos) noexcept {
+ Erase(*pos);
+ }
+
+ inline void EraseImpl(TNodeBase* val) noexcept {
+ TRbGlobalInst::RebalanceForErase(val, this->Data_.Parent_, this->Data_.Left_, this->Data_.Right_);
+ }
+
+ template <class T1>
+ inline TValue* Find(const T1& k) const {
+ TBasePtr y = nullptr;
+ TBasePtr x = Root(); // Current node.
+
+ while (x != nullptr)
+ if (!KeyCompare_(ValueNode(x), k))
+ y = x, x = LeftNode(x);
+ else
+ x = RightNode(x);
+
+ if (y) {
+ if (KeyCompare_(k, ValueNode(y))) {
+ y = nullptr;
+ }
+ }
+
+ return static_cast<TValue*>(y);
+ }
+
+ size_t GetIndex(TBasePtr x) const {
+ size_t index = 0;
+
+ if (x->Left_ != nullptr) {
+ index += x->Left_->Children_;
+ }
+
+ while (x != nullptr && x->Parent_ != nullptr && x->Parent_ != const_cast<TBasePtr>(&this->Data_)) {
+ if (x->Parent_->Right_ == x && x->Parent_->Left_ != nullptr) {
+ index += x->Parent_->Left_->Children_;
+ }
+ if (x->Parent_->Right_ == x) {
+ index += 1;
+ }
+ x = x->Parent_;
+ }
+
+ return index;
+ }
+
+ template <class T1>
+ inline TBasePtr LowerBound(const T1& k) const {
+ TBasePtr y = const_cast<TBasePtr>(&this->Data_); /* Last node which is not less than k. */
+ TBasePtr x = Root(); /* Current node. */
+
+ while (x != nullptr)
+ if (!KeyCompare_(ValueNode(x), k))
+ y = x, x = LeftNode(x);
+ else
+ x = RightNode(x);
+
+ return y;
+ }
+
+ template <class T1>
+ inline TBasePtr UpperBound(const T1& k) const {
+ TBasePtr y = const_cast<TBasePtr>(&this->Data_); /* Last node which is greater than k. */
+ TBasePtr x = Root(); /* Current node. */
+
+ while (x != nullptr)
+ if (KeyCompare_(k, ValueNode(x)))
+ y = x, x = LeftNode(x);
+ else
+ x = RightNode(x);
+
+ return y;
+ }
+
+ template <class T1>
+ inline size_t LessCount(const T1& k) const {
+ auto x = LowerBound(k);
+ if (x == const_cast<TBasePtr>(&this->Data_)) {
+ if (const auto root = Root()) {
+ return root->Children_;
+ } else {
+ return 0;
+ }
+ } else {
+ return GetIndex(x);
+ }
+ }
+
+ template <class T1>
+ inline size_t NotLessCount(const T1& k) const {
+ return Root()->Children_ - LessCount<T1>(k);
+ }
+
+ template <class T1>
+ inline size_t GreaterCount(const T1& k) const {
+ auto x = UpperBound(k);
+ if (x == const_cast<TBasePtr>(&this->Data_)) {
+ return 0;
+ } else {
+ return Root()->Children_ - GetIndex(x);
+ }
+ }
+
+ template <class T1>
+ inline size_t NotGreaterCount(const T1& k) const {
+ return Root()->Children_ - GreaterCount<T1>(k);
+ }
+
+ TValue* ByIndex(size_t index) {
+ return static_cast<TValue*>(TRbTreeNodeBase::ByIndex(Root(), index));
+ }
+
+private:
+ // CRP 7/10/00 inserted argument on_right, which is another hint (meant to
+ // act like on_left and ignore a portion of the if conditions -- specify
+ // on_right != nullptr to bypass comparison as false or on_left != nullptr to bypass
+ // comparison as true)
+ TIterator InsertImpl(TRbTreeNodeBase* parent, TRbTreeNodeBase* val, TRbTreeNodeBase* on_left = nullptr, TRbTreeNodeBase* on_right = nullptr) {
+ ValueNode(val).SetRbTreeParent(this);
+ TBasePtr new_node = val;
+
+ if (parent == &this->Data_) {
+ LeftNode(parent) = new_node;
+ // also makes LeftMost() = new_node
+ Root() = new_node;
+ RightMost() = new_node;
+ } else if (on_right == nullptr &&
+ // If on_right != nullptr, the remainder fails to false
+ (on_left != nullptr ||
+ // If on_left != nullptr, the remainder succeeds to true
+ KeyCompare_(ValueNode(val), ValueNode(parent))))
+ {
+ LeftNode(parent) = new_node;
+ if (parent == LeftMost())
+ // maintain LeftMost() pointing to min node
+ LeftMost() = new_node;
+ } else {
+ RightNode(parent) = new_node;
+ if (parent == RightMost())
+ // maintain RightMost() pointing to max node
+ RightMost() = new_node;
+ }
+ ParentNode(new_node) = parent;
+ TRbGlobalInst::Rebalance(new_node, this->Data_.Parent_);
+ return new_node;
+ }
+
+ TBasePtr Root() const {
+ return this->Data_.Parent_;
+ }
+
+ TBasePtr LeftMost() const {
+ return this->Data_.Left_;
+ }
+
+ TBasePtr RightMost() const {
+ return this->Data_.Right_;
+ }
+
+ TBasePtr& Root() {
+ return this->Data_.Parent_;
+ }
+
+ TBasePtr& LeftMost() {
+ return this->Data_.Left_;
+ }
+
+ TBasePtr& RightMost() {
+ return this->Data_.Right_;
+ }
+
+ static TBasePtr& LeftNode(TBasePtr x) {
+ return x->Left_;
+ }
+
+ static TBasePtr& RightNode(TBasePtr x) {
+ return x->Right_;
+ }
+
+ static TBasePtr& ParentNode(TBasePtr x) {
+ return x->Parent_;
+ }
+
+ static TValue& ValueNode(TBasePtr x) {
+ return *static_cast<TValue*>(x);
+ }
+
+ static TBasePtr MinimumNode(TBasePtr x) {
+ return TRbTreeNodeBase::MinimumNode(x);
+ }
+
+ static TBasePtr MaximumNode(TBasePtr x) {
+ return TRbTreeNodeBase::MaximumNode(x);
+ }
+
+private:
+ TCmpAdaptor KeyCompare_;
+ TNodeBase Data_;
+};
+
+template <class TValue, class TCmp>
+class TRbTreeItem: public TRbTree<TValue, TCmp>::TRealNode {
+};
+
+template <class TDummy>
+void TRbGlobal<TDummy>::RotateLeft(TRbTreeNodeBase* x, TRbTreeNodeBase*& root) {
+ TRbTreeNodeBase* y = x->Right_;
+ x->Right_ = y->Left_;
+ if (y->Left_ != nullptr)
+ y->Left_->Parent_ = x;
+ y->Parent_ = x->Parent_;
+
+ if (x == root)
+ root = y;
+ else if (x == x->Parent_->Left_)
+ x->Parent_->Left_ = y;
+ else
+ x->Parent_->Right_ = y;
+ y->Left_ = x;
+ x->Parent_ = y;
+ y->Children_ = x->Children_;
+ x->Children_ = ((x->Left_) ? x->Left_->Children_ : 0) + ((x->Right_) ? x->Right_->Children_ : 0) + 1;
+}
+
+template <class TDummy>
+void TRbGlobal<TDummy>::RotateRight(TRbTreeNodeBase* x, TRbTreeNodeBase*& root) {
+ TRbTreeNodeBase* y = x->Left_;
+ x->Left_ = y->Right_;
+ if (y->Right_ != nullptr)
+ y->Right_->Parent_ = x;
+ y->Parent_ = x->Parent_;
+
+ if (x == root)
+ root = y;
+ else if (x == x->Parent_->Right_)
+ x->Parent_->Right_ = y;
+ else
+ x->Parent_->Left_ = y;
+ y->Right_ = x;
+ x->Parent_ = y;
+ y->Children_ = x->Children_;
+ x->Children_ = ((x->Left_) ? x->Left_->Children_ : 0) + ((x->Right_) ? x->Right_->Children_ : 0) + 1;
+}
+
+template <class TDummy>
+void TRbGlobal<TDummy>::Rebalance(TRbTreeNodeBase* x, TRbTreeNodeBase*& root) {
+ x->Color_ = RBTreeRed;
+ while (x != root && x->Parent_->Color_ == RBTreeRed) {
+ if (x->Parent_ == x->Parent_->Parent_->Left_) {
+ TRbTreeNodeBase* y = x->Parent_->Parent_->Right_;
+ if (y && y->Color_ == RBTreeRed) {
+ x->Parent_->Color_ = RBTreeBlack;
+ y->Color_ = RBTreeBlack;
+ x->Parent_->Parent_->Color_ = RBTreeRed;
+ x = x->Parent_->Parent_;
+ } else {
+ if (x == x->Parent_->Right_) {
+ x = x->Parent_;
+ RotateLeft(x, root);
+ }
+ x->Parent_->Color_ = RBTreeBlack;
+ x->Parent_->Parent_->Color_ = RBTreeRed;
+ RotateRight(x->Parent_->Parent_, root);
+ }
+ } else {
+ TRbTreeNodeBase* y = x->Parent_->Parent_->Left_;
+ if (y && y->Color_ == RBTreeRed) {
+ x->Parent_->Color_ = RBTreeBlack;
+ y->Color_ = RBTreeBlack;
+ x->Parent_->Parent_->Color_ = RBTreeRed;
+ x = x->Parent_->Parent_;
+ } else {
+ if (x == x->Parent_->Left_) {
+ x = x->Parent_;
+ RotateRight(x, root);
+ }
+ x->Parent_->Color_ = RBTreeBlack;
+ x->Parent_->Parent_->Color_ = RBTreeRed;
+ RotateLeft(x->Parent_->Parent_, root);
+ }
+ }
+ }
+ root->Color_ = RBTreeBlack;
+}
+
+template <class TDummy>
+void TRbGlobal<TDummy>::RecalcChildren(TRbTreeNodeBase* x) {
+ x->Children_ = ((x->Left_) ? x->Left_->Children_ : 0) + ((x->Right_) ? x->Right_->Children_ : 0) + 1;
+}
+
+template <class TDummy>
+void TRbGlobal<TDummy>::DecrementChildrenUntilRoot(TRbTreeNodeBase* x, TRbTreeNodeBase* root) {
+ auto* ptr = x;
+ --ptr->Children_;
+ while (ptr != root) {
+ ptr = ptr->Parent_;
+ --ptr->Children_;
+ }
+}
+
+template <class TDummy>
+TRbTreeNodeBase* TRbGlobal<TDummy>::RebalanceForErase(TRbTreeNodeBase* z,
+ TRbTreeNodeBase*& root,
+ TRbTreeNodeBase*& leftmost,
+ TRbTreeNodeBase*& rightmost) {
+ TRbTreeNodeBase* y = z;
+ TRbTreeNodeBase* x;
+ TRbTreeNodeBase* x_parent;
+
+ if (y->Left_ == nullptr) // z has at most one non-null child. y == z.
+ x = y->Right_; // x might be null.
+ else {
+ if (y->Right_ == nullptr) // z has exactly one non-null child. y == z.
+ x = y->Left_; // x is not null.
+ else { // z has two non-null children. Set y to
+ y = TRbTreeNodeBase::MinimumNode(y->Right_); // z's successor. x might be null.
+ x = y->Right_;
+ }
+ }
+
+ if (y != z) {
+ // relink y in place of z. y is z's successor
+ z->Left_->Parent_ = y;
+ y->Left_ = z->Left_;
+ if (y != z->Right_) {
+ x_parent = y->Parent_;
+ if (x)
+ x->Parent_ = y->Parent_;
+ y->Parent_->Left_ = x; // y must be a child of mLeft
+ y->Right_ = z->Right_;
+ z->Right_->Parent_ = y;
+ } else
+ x_parent = y;
+ if (root == z)
+ root = y;
+ else if (z->Parent_->Left_ == z)
+ z->Parent_->Left_ = y;
+ else
+ z->Parent_->Right_ = y;
+ y->Parent_ = z->Parent_;
+ DoSwap(y->Color_, z->Color_);
+
+ RecalcChildren(y);
+ if (x_parent != y) {
+ --x_parent->Children_;
+ }
+ if (x_parent != root) {
+ DecrementChildrenUntilRoot(x_parent->Parent_, root);
+ }
+ y = z;
+ // y now points to node to be actually deleted
+ } else {
+ // y == z
+ x_parent = y->Parent_;
+ if (x)
+ x->Parent_ = y->Parent_;
+ if (root == z)
+ root = x;
+ else {
+ if (z->Parent_->Left_ == z)
+ z->Parent_->Left_ = x;
+ else
+ z->Parent_->Right_ = x;
+ DecrementChildrenUntilRoot(z->Parent_, root); // we lost y
+ }
+
+ if (leftmost == z) {
+ if (z->Right_ == nullptr) // z->mLeft must be null also
+ leftmost = z->Parent_;
+ // makes leftmost == _M_header if z == root
+ else
+ leftmost = TRbTreeNodeBase::MinimumNode(x);
+ }
+ if (rightmost == z) {
+ if (z->Left_ == nullptr) // z->mRight must be null also
+ rightmost = z->Parent_;
+ // makes rightmost == _M_header if z == root
+ else // x == z->mLeft
+ rightmost = TRbTreeNodeBase::MaximumNode(x);
+ }
+ }
+
+ if (y->Color_ != RBTreeRed) {
+ while (x != root && (x == nullptr || x->Color_ == RBTreeBlack))
+ if (x == x_parent->Left_) {
+ TRbTreeNodeBase* w = x_parent->Right_;
+ if (w->Color_ == RBTreeRed) {
+ w->Color_ = RBTreeBlack;
+ x_parent->Color_ = RBTreeRed;
+ RotateLeft(x_parent, root);
+ w = x_parent->Right_;
+ }
+ if ((w->Left_ == nullptr ||
+ w->Left_->Color_ == RBTreeBlack) &&
+ (w->Right_ == nullptr ||
+ w->Right_->Color_ == RBTreeBlack))
+ {
+ w->Color_ = RBTreeRed;
+ x = x_parent;
+ x_parent = x_parent->Parent_;
+ } else {
+ if (w->Right_ == nullptr || w->Right_->Color_ == RBTreeBlack) {
+ if (w->Left_)
+ w->Left_->Color_ = RBTreeBlack;
+ w->Color_ = RBTreeRed;
+ RotateRight(w, root);
+ w = x_parent->Right_;
+ }
+ w->Color_ = x_parent->Color_;
+ x_parent->Color_ = RBTreeBlack;
+ if (w->Right_)
+ w->Right_->Color_ = RBTreeBlack;
+ RotateLeft(x_parent, root);
+ break;
+ }
+ } else {
+ // same as above, with mRight <-> mLeft.
+ TRbTreeNodeBase* w = x_parent->Left_;
+ if (w->Color_ == RBTreeRed) {
+ w->Color_ = RBTreeBlack;
+ x_parent->Color_ = RBTreeRed;
+ RotateRight(x_parent, root);
+ w = x_parent->Left_;
+ }
+ if ((w->Right_ == nullptr ||
+ w->Right_->Color_ == RBTreeBlack) &&
+ (w->Left_ == nullptr ||
+ w->Left_->Color_ == RBTreeBlack))
+ {
+ w->Color_ = RBTreeRed;
+ x = x_parent;
+ x_parent = x_parent->Parent_;
+ } else {
+ if (w->Left_ == nullptr || w->Left_->Color_ == RBTreeBlack) {
+ if (w->Right_)
+ w->Right_->Color_ = RBTreeBlack;
+ w->Color_ = RBTreeRed;
+ RotateLeft(w, root);
+ w = x_parent->Left_;
+ }
+ w->Color_ = x_parent->Color_;
+ x_parent->Color_ = RBTreeBlack;
+ if (w->Left_)
+ w->Left_->Color_ = RBTreeBlack;
+ RotateRight(x_parent, root);
+ break;
+ }
+ }
+ if (x)
+ x->Color_ = RBTreeBlack;
+ }
+ return y;
+}
+
+template <class TDummy>
+TRbTreeNodeBase* TRbGlobal<TDummy>::DecrementNode(TRbTreeNodeBase* Node_) {
+ if (Node_->Color_ == RBTreeRed && Node_->Parent_->Parent_ == Node_)
+ Node_ = Node_->Right_;
+ else if (Node_->Left_ != nullptr) {
+ Node_ = TRbTreeNodeBase::MaximumNode(Node_->Left_);
+ } else {
+ TBasePtr y = Node_->Parent_;
+ while (Node_ == y->Left_) {
+ Node_ = y;
+ y = y->Parent_;
+ }
+ Node_ = y;
+ }
+ return Node_;
+}
+
+template <class TDummy>
+TRbTreeNodeBase* TRbGlobal<TDummy>::IncrementNode(TRbTreeNodeBase* Node_) {
+ if (Node_->Right_ != nullptr) {
+ Node_ = TRbTreeNodeBase::MinimumNode(Node_->Right_);
+ } else {
+ TBasePtr y = Node_->Parent_;
+ while (Node_ == y->Right_) {
+ Node_ = y;
+ y = y->Parent_;
+ }
+ // check special case: This is necessary if mNode is the
+ // _M_head and the tree contains only a single node y. In
+ // that case parent, left and right all point to y!
+ if (Node_->Right_ != y)
+ Node_ = y;
+ }
+ return Node_;
+}
+
+#undef RBTreeRed
+#undef RBTreeBlack
diff --git a/library/cpp/containers/intrusive_rb_tree/rb_tree_ut.cpp b/library/cpp/containers/intrusive_rb_tree/rb_tree_ut.cpp
new file mode 100644
index 0000000000..c34ed1fd9b
--- /dev/null
+++ b/library/cpp/containers/intrusive_rb_tree/rb_tree_ut.cpp
@@ -0,0 +1,298 @@
+#include "rb_tree.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/random/fast.h>
+#include <util/random/easy.h>
+#include <util/random/shuffle.h>
+
+class TRedBlackTreeTest: public TTestBase {
+ struct TCmp {
+ template <class T>
+ static inline bool Compare(const T& l, const T& r) {
+ return l.N < r.N;
+ }
+
+ template <class T>
+ static inline bool Compare(const T& l, int r) {
+ return l.N < r;
+ }
+
+ template <class T>
+ static inline bool Compare(int l, const T& r) {
+ return l < r.N;
+ }
+ };
+
+ class TNode: public TRbTreeItem<TNode, TCmp> {
+ public:
+ inline TNode(int n) noexcept
+ : N(n)
+ {
+ }
+
+ int N;
+ };
+
+ using TTree = TRbTree<TNode, TCmp>;
+
+ UNIT_TEST_SUITE(TRedBlackTreeTest);
+ UNIT_TEST(TestEmpty)
+ UNIT_TEST(TestInsert)
+ UNIT_TEST(TestErase)
+ UNIT_TEST(TestFind)
+ UNIT_TEST(TestStress)
+ UNIT_TEST(TestGettingIndexWithDifferentValues)
+ UNIT_TEST(TestCheckChildrenAfterErase)
+ UNIT_TEST(TestGettingIndexWithDifferentValuesAfterErase)
+ UNIT_TEST(TestGettingIndexWithEqualValues)
+ UNIT_TEST(TestLessCountOnEmptyTree)
+ UNIT_TEST_SUITE_END();
+
+private:
+ inline void TestStress() {
+ TVector<TSimpleSharedPtr<TNode>> nodes;
+
+ for (int i = 0; i < 1000; ++i) {
+ nodes.push_back(new TNode(i));
+ }
+
+ TTree tree;
+ TReallyFastRng32 rnd(Random());
+
+ for (size_t i = 0; i < 1000000; ++i) {
+ tree.Insert(nodes[rnd.Uniform(nodes.size())].Get());
+ }
+
+ for (TTree::TConstIterator it = tree.Begin(); it != tree.End();) {
+ const int v1 = it->N;
+
+ if (++it == tree.End()) {
+ break;
+ }
+
+ const int v2 = it->N;
+
+ UNIT_ASSERT(v1 < v2);
+ }
+ }
+
+ inline void TestGettingIndexWithDifferentValues() {
+ TVector<TSimpleSharedPtr<TNode>> nodes;
+ size_t N = 1000;
+
+ for (size_t i = 0; i < N; ++i) {
+ nodes.push_back(new TNode(int(i)));
+ }
+
+ TTree tree;
+ Shuffle(nodes.begin(), nodes.end());
+
+ for (size_t i = 0; i < N; ++i) {
+ tree.Insert(nodes[i].Get());
+ }
+
+ for (size_t i = 0; i < N; ++i) {
+ UNIT_ASSERT_EQUAL(tree.LessCount(i), i);
+ UNIT_ASSERT_EQUAL(tree.NotGreaterCount(i), i + 1);
+ UNIT_ASSERT_EQUAL(tree.GreaterCount(i), N - i - 1);
+ UNIT_ASSERT_EQUAL(tree.NotLessCount(i), N - i);
+
+ auto nodePtr = tree.Find(i);
+ UNIT_ASSERT_EQUAL(tree.GetIndex(nodePtr), i);
+ UNIT_ASSERT_EQUAL(tree.GetIndex(nodes[i].Get()), static_cast<size_t>(nodes[i]->N));
+ }
+ }
+
+ inline void TestCheckChildrenAfterErase() {
+ TVector<TSimpleSharedPtr<TNode>> nodes;
+ size_t N = 1000;
+
+ for (size_t i = 0; i < N; ++i) {
+ nodes.push_back(new TNode(int(i)));
+ }
+
+ TTree tree;
+ Shuffle(nodes.begin(), nodes.end());
+
+ for (size_t i = 0; i < N; ++i) {
+ tree.Insert(nodes[i].Get());
+ }
+ auto checker = [](const TTree& tree) {
+ for (auto node = tree.Begin(); node != tree.End(); ++node) {
+ size_t childrens = 1;
+ if (node->Left_) {
+ childrens += node->Left_->Children_;
+ }
+ if (node->Right_) {
+ childrens += node->Right_->Children_;
+ }
+ UNIT_ASSERT_VALUES_EQUAL(childrens, node->Children_);
+ }
+ };
+
+ for (auto node : nodes) {
+ tree.Erase(node.Get());
+ checker(tree);
+ }
+ }
+
+ inline void TestGettingIndexWithDifferentValuesAfterErase() {
+ TVector<TSimpleSharedPtr<TNode>> nodes;
+ size_t N = 1000;
+
+ for (size_t i = 0; i < N; ++i) {
+ nodes.push_back(new TNode(int(i)));
+ }
+
+ TTree tree;
+ Shuffle(nodes.begin(), nodes.end());
+
+ for (size_t i = 0; i < N; ++i) {
+ tree.Insert(nodes[i].Get());
+ }
+ {
+ size_t index = 0;
+ for (auto node = tree.Begin(); node != tree.End(); ++node, ++index) {
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetIndex(&*node), index);
+ UNIT_ASSERT_VALUES_EQUAL(tree.ByIndex(index)->N, node->N);
+ UNIT_ASSERT_VALUES_EQUAL(node->N, index);
+ }
+ }
+
+ for (size_t i = 1; i < N; i += 2) {
+ auto* node = tree.Find(i);
+ UNIT_ASSERT_VALUES_EQUAL(node->N, i);
+ tree.Erase(node);
+ }
+ {
+ size_t index = 0;
+ for (auto node = tree.Begin(); node != tree.End(); ++node, ++index) {
+ UNIT_ASSERT_VALUES_EQUAL(tree.GetIndex(&*node), index);
+ UNIT_ASSERT_VALUES_EQUAL(tree.ByIndex(index)->N, node->N);
+ UNIT_ASSERT_VALUES_EQUAL(node->N, 2 * index);
+ }
+ }
+ }
+
+ inline void TestGettingIndexWithEqualValues() {
+ TVector<TSimpleSharedPtr<TNode>> nodes;
+ size_t N = 1000;
+
+ for (size_t i = 0; i < N; ++i) {
+ nodes.push_back(new TNode(0));
+ }
+
+ TTree tree;
+
+ for (size_t i = 0; i < N; ++i) {
+ tree.Insert(nodes[i].Get());
+ }
+
+ for (size_t i = 0; i < N; ++i) {
+ UNIT_ASSERT_EQUAL(tree.LessCount(nodes[i]->N), 0);
+ UNIT_ASSERT_EQUAL(tree.NotGreaterCount(nodes[i]->N), N);
+ UNIT_ASSERT_EQUAL(tree.GreaterCount(nodes[i]->N), 0);
+ UNIT_ASSERT_EQUAL(tree.NotLessCount(nodes[i]->N), N);
+
+ UNIT_ASSERT_EQUAL(tree.LessCount(*nodes[i].Get()), 0);
+ UNIT_ASSERT_EQUAL(tree.NotGreaterCount(*nodes[i].Get()), N);
+ UNIT_ASSERT_EQUAL(tree.GreaterCount(*nodes[i].Get()), 0);
+ UNIT_ASSERT_EQUAL(tree.NotLessCount(*nodes[i].Get()), N);
+ }
+ }
+
+ inline void TestFind() {
+ TTree tree;
+
+ {
+ TNode n1(1);
+ TNode n2(2);
+ TNode n3(3);
+
+ tree.Insert(n1);
+ tree.Insert(n2);
+ tree.Insert(n3);
+
+ UNIT_ASSERT_EQUAL(tree.Find(1)->N, 1);
+ UNIT_ASSERT_EQUAL(tree.Find(2)->N, 2);
+ UNIT_ASSERT_EQUAL(tree.Find(3)->N, 3);
+
+ UNIT_ASSERT(!tree.Find(0));
+ UNIT_ASSERT(!tree.Find(4));
+ UNIT_ASSERT(!tree.Find(1234567));
+ }
+
+ UNIT_ASSERT(tree.Empty());
+ }
+
+ inline void TestEmpty() {
+ TTree tree;
+
+ UNIT_ASSERT(tree.Empty());
+ UNIT_ASSERT_EQUAL(tree.Begin(), tree.End());
+ }
+
+ inline void TestInsert() {
+ TTree tree;
+
+ {
+ TNode n1(1);
+ TNode n2(2);
+ TNode n3(3);
+
+ tree.Insert(n1);
+ tree.Insert(n2);
+ tree.Insert(n3);
+
+ TTree::TConstIterator it = tree.Begin();
+
+ UNIT_ASSERT_EQUAL((it++)->N, 1);
+ UNIT_ASSERT_EQUAL((it++)->N, 2);
+ UNIT_ASSERT_EQUAL((it++)->N, 3);
+ UNIT_ASSERT_EQUAL(it, tree.End());
+ }
+
+ UNIT_ASSERT(tree.Empty());
+ }
+
+ inline void TestErase() {
+ TTree tree;
+
+ {
+ TNode n1(1);
+ TNode n2(2);
+ TNode n3(3);
+
+ tree.Insert(n1);
+ tree.Insert(n2);
+ tree.Insert(n3);
+
+ TTree::TIterator it = tree.Begin();
+
+ tree.Erase(it++);
+
+ UNIT_ASSERT_EQUAL(it, tree.Begin());
+ UNIT_ASSERT_EQUAL(it->N, 2);
+
+ tree.Erase(it++);
+
+ UNIT_ASSERT_EQUAL(it, tree.Begin());
+ UNIT_ASSERT_EQUAL(it->N, 3);
+
+ tree.Erase(it++);
+
+ UNIT_ASSERT_EQUAL(it, tree.Begin());
+ UNIT_ASSERT_EQUAL(it, tree.End());
+ }
+
+ UNIT_ASSERT(tree.Empty());
+ }
+
+ inline void TestLessCountOnEmptyTree() {
+ TTree tree;
+ UNIT_ASSERT_VALUES_EQUAL(0, tree.LessCount(TNode(1)));
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TRedBlackTreeTest);
diff --git a/library/cpp/containers/intrusive_rb_tree/ut/ya.make b/library/cpp/containers/intrusive_rb_tree/ut/ya.make
new file mode 100644
index 0000000000..6f1e3b38ee
--- /dev/null
+++ b/library/cpp/containers/intrusive_rb_tree/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/containers/intrusive_rb_tree)
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ rb_tree_ut.cpp
+)
+
+END()
diff --git a/library/cpp/containers/intrusive_rb_tree/ya.make b/library/cpp/containers/intrusive_rb_tree/ya.make
new file mode 100644
index 0000000000..2e5eddcfbe
--- /dev/null
+++ b/library/cpp/containers/intrusive_rb_tree/ya.make
@@ -0,0 +1,12 @@
+LIBRARY()
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ rb_tree.cpp
+)
+
+END()
diff --git a/library/cpp/containers/paged_vector/paged_vector.cpp b/library/cpp/containers/paged_vector/paged_vector.cpp
new file mode 100644
index 0000000000..e354caf09d
--- /dev/null
+++ b/library/cpp/containers/paged_vector/paged_vector.cpp
@@ -0,0 +1 @@
+#include "paged_vector.h"
diff --git a/library/cpp/containers/paged_vector/paged_vector.h b/library/cpp/containers/paged_vector/paged_vector.h
new file mode 100644
index 0000000000..6a3657d3ea
--- /dev/null
+++ b/library/cpp/containers/paged_vector/paged_vector.h
@@ -0,0 +1,432 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+#include <iterator>
+
+namespace NPagedVector {
+ template <class T, ui32 PageSize = 1u << 20, class A = std::allocator<T>>
+ class TPagedVector;
+
+ namespace NPrivate {
+ template <class T, class TT, ui32 PageSize, class A>
+ struct TPagedVectorIterator {
+ private:
+ friend class TPagedVector<TT, PageSize, A>;
+ typedef TPagedVector<TT, PageSize, A> TVec;
+ typedef TPagedVectorIterator<T, TT, PageSize, A> TSelf;
+ size_t Offset;
+ TVec* Vector;
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ friend struct TPagedVectorIterator;
+
+ public:
+ TPagedVectorIterator()
+ : Offset()
+ , Vector()
+ {
+ }
+
+ TPagedVectorIterator(TVec* vector, size_t offset)
+ : Offset(offset)
+ , Vector(vector)
+ {
+ }
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ TPagedVectorIterator(const TPagedVectorIterator<T1, TT1, PageSize1, A1>& it)
+ : Offset(it.Offset)
+ , Vector(it.Vector)
+ {
+ }
+
+ T& operator*() const {
+ return (*Vector)[Offset];
+ }
+
+ T* operator->() const {
+ return &(**this);
+ }
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ bool operator==(const TPagedVectorIterator<T1, TT1, PageSize1, A1>& it) const {
+ return Offset == it.Offset;
+ }
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ bool operator!=(const TPagedVectorIterator<T1, TT1, PageSize1, A1>& it) const {
+ return !(*this == it);
+ }
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ bool operator<(const TPagedVectorIterator<T1, TT1, PageSize1, A1>& it) const {
+ return Offset < it.Offset;
+ }
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ bool operator<=(const TPagedVectorIterator<T1, TT1, PageSize1, A1>& it) const {
+ return Offset <= it.Offset;
+ }
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ bool operator>(const TPagedVectorIterator<T1, TT1, PageSize1, A1>& it) const {
+ return !(*this <= it);
+ }
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ bool operator>=(const TPagedVectorIterator<T1, TT1, PageSize1, A1>& it) const {
+ return !(*this < it);
+ }
+
+ template <class T1, class TT1, ui32 PageSize1, class A1>
+ ptrdiff_t operator-(const TPagedVectorIterator<T1, TT1, PageSize1, A1>& it) const {
+ return Offset - it.Offset;
+ }
+
+ TSelf& operator+=(ptrdiff_t off) {
+ Offset += off;
+ return *this;
+ }
+
+ TSelf& operator-=(ptrdiff_t off) {
+ return this->operator+=(-off);
+ }
+
+ TSelf& operator++() {
+ return this->operator+=(1);
+ }
+
+ TSelf& operator--() {
+ return this->operator+=(-1);
+ }
+
+ TSelf operator++(int) {
+ TSelf it = *this;
+ this->operator+=(1);
+ return it;
+ }
+
+ TSelf operator--(int) {
+ TSelf it = *this;
+ this->operator+=(-1);
+ return it;
+ }
+
+ TSelf operator+(ptrdiff_t off) {
+ TSelf res = *this;
+ res += off;
+ return res;
+ }
+
+ TSelf operator-(ptrdiff_t off) {
+ return this->operator+(-off);
+ }
+
+ size_t GetOffset() {
+ return Offset;
+ }
+ };
+ }
+}
+
+namespace std {
+ template <class T, class TT, ui32 PageSize, class A>
+ struct iterator_traits<NPagedVector::NPrivate::TPagedVectorIterator<T, TT, PageSize, A>> {
+ typedef ptrdiff_t difference_type;
+ typedef T value_type;
+ typedef T* pointer;
+ typedef T& reference;
+ typedef random_access_iterator_tag iterator_category;
+ };
+
+}
+
+namespace NPagedVector {
+ //2-level radix tree
+ template <class T, ui32 PageSize, class A>
+ class TPagedVector: private TVector<TSimpleSharedPtr<TVector<T, A>>, A> {
+ static_assert(PageSize, "expect PageSize");
+
+ typedef TVector<T, A> TPage;
+ typedef TVector<TSimpleSharedPtr<TPage>, A> TPages;
+ typedef TPagedVector<T, PageSize, A> TSelf;
+
+ public:
+ typedef NPrivate::TPagedVectorIterator<T, T, PageSize, A> iterator;
+ typedef NPrivate::TPagedVectorIterator<const T, T, PageSize, A> const_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef T value_type;
+ typedef value_type& reference;
+ typedef const value_type& const_reference;
+
+ TPagedVector() = default;
+
+ template <typename TIter>
+ TPagedVector(TIter b, TIter e) {
+ append(b, e);
+ }
+
+ iterator begin() {
+ return iterator(this, 0);
+ }
+
+ const_iterator begin() const {
+ return const_iterator((TSelf*)this, 0);
+ }
+
+ iterator end() {
+ return iterator(this, size());
+ }
+
+ const_iterator end() const {
+ return const_iterator((TSelf*)this, size());
+ }
+
+ reverse_iterator rbegin() {
+ return reverse_iterator(end());
+ }
+
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator(end());
+ }
+
+ reverse_iterator rend() {
+ return reverse_iterator(begin());
+ }
+
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator(begin());
+ }
+
+ void swap(TSelf& v) {
+ TPages::swap((TPages&)v);
+ }
+
+ private:
+ static size_t PageNumber(size_t idx) {
+ return idx / PageSize;
+ }
+
+ static size_t InPageIndex(size_t idx) {
+ return idx % PageSize;
+ }
+
+ static size_t Index(size_t pnum, size_t poff) {
+ return pnum * PageSize + poff;
+ }
+
+ TPage& PageAt(size_t pnum) const {
+ return *TPages::at(pnum);
+ }
+
+ TPage& CurrentPage() const {
+ return *TPages::back();
+ }
+
+ size_t CurrentPageSize() const {
+ return TPages::empty() ? 0 : CurrentPage().size();
+ }
+
+ size_t NPages() const {
+ return TPages::size();
+ }
+
+ void AllocateNewPage() {
+ TPages::push_back(new TPage());
+ CurrentPage().reserve(PageSize);
+ }
+
+ void MakeNewPage() {
+ AllocateNewPage();
+ CurrentPage().resize(PageSize);
+ }
+
+ void PrepareAppend() {
+ if (TPages::empty() || CurrentPage().size() + 1 > PageSize)
+ AllocateNewPage();
+ }
+
+ public:
+ size_t size() const {
+ return empty() ? 0 : (NPages() - 1) * PageSize + CurrentPage().size();
+ }
+
+ bool empty() const {
+ return TPages::empty() || 1 == NPages() && CurrentPage().empty();
+ }
+
+ explicit operator bool() const noexcept {
+ return !empty();
+ }
+
+ void emplace_back() {
+ PrepareAppend();
+ CurrentPage().emplace_back();
+ }
+
+ void push_back(const_reference t) {
+ PrepareAppend();
+ CurrentPage().push_back(t);
+ }
+
+ void pop_back() {
+ if (CurrentPage().empty())
+ TPages::pop_back();
+ CurrentPage().pop_back();
+ }
+
+ template <typename TIter>
+ void append(TIter b, TIter e) {
+ size_t sz = e - b;
+ size_t sz1 = Min<size_t>(sz, PageSize - CurrentPageSize());
+ size_t sz2 = (sz - sz1) / PageSize;
+ size_t sz3 = (sz - sz1) % PageSize;
+
+ if (sz1) {
+ PrepareAppend();
+ TPage& p = CurrentPage();
+ p.insert(p.end(), b, b + sz1);
+ }
+
+ for (size_t i = 0; i < sz2; ++i) {
+ AllocateNewPage();
+ TPage& p = CurrentPage();
+ p.insert(p.end(), b + sz1 + i * PageSize, b + sz1 + (i + 1) * PageSize);
+ }
+
+ if (sz3) {
+ AllocateNewPage();
+ TPage& p = CurrentPage();
+ p.insert(p.end(), b + sz1 + sz2 * PageSize, e);
+ }
+ }
+
+ iterator erase(iterator it) {
+ size_t pnum = PageNumber(it.Offset);
+ size_t pidx = InPageIndex(it.Offset);
+
+ if (CurrentPage().empty())
+ TPages::pop_back();
+
+ for (size_t p = NPages() - 1; p > pnum; --p) {
+ PageAt(p - 1).push_back(PageAt(p).front());
+ PageAt(p).erase(PageAt(p).begin());
+ }
+
+ PageAt(pnum).erase(PageAt(pnum).begin() + pidx);
+ return it;
+ }
+
+ iterator erase(iterator b, iterator e) {
+ // todo : suboptimal!
+ while (b != e) {
+ b = erase(b);
+ --e;
+ }
+
+ return b;
+ }
+
+ iterator insert(iterator it, const value_type& v) {
+ size_t pnum = PageNumber(it.Offset);
+ size_t pidx = InPageIndex(it.Offset);
+
+ PrepareAppend();
+
+ for (size_t p = NPages() - 1; p > pnum; --p) {
+ PageAt(p).insert(PageAt(p).begin(), PageAt(p - 1).back());
+ PageAt(p - 1).pop_back();
+ }
+
+ PageAt(pnum).insert(PageAt(pnum).begin() + pidx, v);
+ return it;
+ }
+
+ template <typename TIter>
+ void insert(iterator it, TIter b, TIter e) {
+ // todo : suboptimal!
+ for (; b != e; ++b, ++it)
+ it = insert(it, *b);
+ }
+
+ reference front() {
+ return TPages::front()->front();
+ }
+
+ const_reference front() const {
+ return TPages::front()->front();
+ }
+
+ reference back() {
+ return CurrentPage().back();
+ }
+
+ const_reference back() const {
+ return CurrentPage().back();
+ }
+
+ void clear() {
+ TPages::clear();
+ }
+
+ void resize(size_t sz) {
+ if (sz == size())
+ return;
+
+ const size_t npages = NPages();
+ const size_t newwholepages = sz / PageSize;
+ const size_t pagepart = sz % PageSize;
+ const size_t newpages = newwholepages + bool(pagepart);
+
+ if (npages && newwholepages >= npages)
+ CurrentPage().resize(PageSize);
+
+ if (newpages < npages)
+ TPages::resize(newpages);
+ else
+ for (size_t i = npages; i < newpages; ++i)
+ MakeNewPage();
+
+ if (pagepart)
+ CurrentPage().resize(pagepart);
+
+ Y_VERIFY(sz == size(), "%" PRIu64 " %" PRIu64, (ui64)sz, (ui64)size());
+ }
+
+ reference at(size_t idx) {
+ return TPages::at(PageNumber(idx))->at(InPageIndex(idx));
+ }
+
+ const_reference at(size_t idx) const {
+ return TPages::at(PageNumber(idx))->at(InPageIndex(idx));
+ }
+
+ reference operator[](size_t idx) {
+ return TPages::operator[](PageNumber(idx))->operator[](InPageIndex(idx));
+ }
+
+ const_reference operator[](size_t idx) const {
+ return TPages::operator[](PageNumber(idx))->operator[](InPageIndex(idx));
+ }
+
+ friend bool operator==(const TSelf& a, const TSelf& b) {
+ return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
+ }
+
+ friend bool operator<(const TSelf& a, const TSelf& b) {
+ return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
+ }
+ };
+
+ namespace NPrivate {
+ typedef std::is_same<std::random_access_iterator_tag, std::iterator_traits<
+ TPagedVector<ui32>::iterator>::iterator_category>
+ TIteratorCheck;
+ static_assert(TIteratorCheck::value, "expect TIteratorCheck::Result");
+ }
+
+}
diff --git a/library/cpp/containers/paged_vector/ut/paged_vector_ut.cpp b/library/cpp/containers/paged_vector/ut/paged_vector_ut.cpp
new file mode 100644
index 0000000000..e867808ee4
--- /dev/null
+++ b/library/cpp/containers/paged_vector/ut/paged_vector_ut.cpp
@@ -0,0 +1,378 @@
+#include <library/cpp/containers/paged_vector/paged_vector.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <stdexcept>
+
+class TPagedVectorTest: public TTestBase {
+ UNIT_TEST_SUITE(TPagedVectorTest);
+ UNIT_TEST(Test0)
+ UNIT_TEST(Test1)
+ UNIT_TEST(Test2)
+ UNIT_TEST(Test3)
+ UNIT_TEST(Test4)
+ UNIT_TEST(Test5)
+ UNIT_TEST(Test6)
+ UNIT_TEST(Test7)
+ UNIT_TEST(TestAt)
+ UNIT_TEST(TestAutoRef)
+ UNIT_TEST(TestIterators)
+ //UNIT_TEST(TestEbo)
+ UNIT_TEST_SUITE_END();
+
+private:
+ // Copy-paste of STLPort tests
+ void Test0() {
+ using NPagedVector::TPagedVector;
+ TPagedVector<int, 16> v1; // Empty vector of integers.
+
+ UNIT_ASSERT(v1.empty() == true);
+ UNIT_ASSERT(v1.size() == 0);
+
+ for (size_t i = 0; i < 256; ++i) {
+ v1.resize(i + 1);
+ UNIT_ASSERT_VALUES_EQUAL(v1.size(), i + 1);
+ }
+
+ for (size_t i = 256; i-- > 0;) {
+ v1.resize(i);
+ UNIT_ASSERT_VALUES_EQUAL(v1.size(), i);
+ }
+ }
+
+ void Test1() {
+ using NPagedVector::TPagedVector;
+ TPagedVector<int, 3> v1; // Empty vector of integers.
+
+ UNIT_ASSERT(v1.empty() == true);
+ UNIT_ASSERT(v1.size() == 0);
+
+ // UNIT_ASSERT(v1.max_size() == INT_MAX / sizeof(int));
+ // cout << "max_size = " << v1.max_size() << endl;
+ v1.push_back(42); // Add an integer to the vector.
+
+ UNIT_ASSERT(v1.size() == 1);
+
+ UNIT_ASSERT(v1[0] == 42);
+
+ {
+ TPagedVector<TPagedVector<int, 3>, 3> vect;
+ vect.resize(10);
+ UNIT_ASSERT(vect.size() == 10);
+ TPagedVector<TPagedVector<int, 3>, 3>::iterator it(vect.begin()), end(vect.end());
+ for (; it != end; ++it) {
+ UNIT_ASSERT((*it).empty());
+ UNIT_ASSERT((*it).size() == 0);
+ UNIT_ASSERT((*it).begin() == (*it).end());
+ }
+ }
+ }
+
+ void Test2() {
+ using NPagedVector::TPagedVector;
+ TPagedVector<double, 3> v1; // Empty vector of doubles.
+ v1.push_back(32.1);
+ v1.push_back(40.5);
+ v1.push_back(45.5);
+ v1.push_back(33.4);
+ TPagedVector<double, 3> v2; // Another empty vector of doubles.
+ v2.push_back(3.56);
+
+ UNIT_ASSERT(v1.size() == 4);
+ UNIT_ASSERT(v1[0] == 32.1);
+ UNIT_ASSERT(v1[1] == 40.5);
+ UNIT_ASSERT(v1[2] == 45.5);
+ UNIT_ASSERT(v1[3] == 33.4);
+
+ UNIT_ASSERT(v2.size() == 1);
+ UNIT_ASSERT(v2[0] == 3.56);
+ v1.swap(v2); // Swap the vector's contents.
+
+ UNIT_ASSERT(v1.size() == 1);
+ UNIT_ASSERT(v1[0] == 3.56);
+
+ UNIT_ASSERT(v2.size() == 4);
+ UNIT_ASSERT(v2[0] == 32.1);
+ UNIT_ASSERT(v2[1] == 40.5);
+ UNIT_ASSERT(v2[2] == 45.5);
+ UNIT_ASSERT(v2[3] == 33.4);
+
+ v2 = v1; // Assign one vector to another.
+
+ UNIT_ASSERT(v2.size() == 1);
+ UNIT_ASSERT(v2[0] == 3.56);
+
+ v2.pop_back();
+ UNIT_ASSERT(v2.size() == 0);
+ UNIT_ASSERT(v2.empty());
+ }
+
+ void Test3() {
+ using NPagedVector::TPagedVector;
+ TPagedVector<char, 1> v1;
+
+ v1.push_back('h');
+ v1.push_back('i');
+
+ UNIT_ASSERT(v1.size() == 2);
+ UNIT_ASSERT(v1[0] == 'h');
+ UNIT_ASSERT(v1[1] == 'i');
+
+ TPagedVector<char, 1> v2;
+ v2.resize(v1.size());
+
+ for (size_t i = 0; i < v1.size(); ++i)
+ v2[i] = v1[i];
+
+ v2[1] = 'o'; // Replace second character.
+
+ UNIT_ASSERT(v2.size() == 2);
+ UNIT_ASSERT(v2[0] == 'h');
+ UNIT_ASSERT(v2[1] == 'o');
+
+ UNIT_ASSERT((v1 == v2) == false);
+
+ UNIT_ASSERT((v1 < v2) == true);
+ }
+
+ void Test4() {
+ using NPagedVector::TPagedVector;
+ TPagedVector<int, 3> v;
+ v.resize(4);
+
+ v[0] = 1;
+ v[1] = 4;
+ v[2] = 9;
+ v[3] = 16;
+
+ UNIT_ASSERT(v.front() == 1);
+ UNIT_ASSERT(v.back() == 16);
+
+ v.push_back(25);
+
+ UNIT_ASSERT(v.back() == 25);
+ UNIT_ASSERT(v.size() == 5);
+
+ v.pop_back();
+
+ UNIT_ASSERT(v.back() == 16);
+ UNIT_ASSERT(v.size() == 4);
+ }
+
+ void Test5() {
+ int array[] = {1, 4, 9, 16};
+
+ typedef NPagedVector::TPagedVector<int, 3> TVectorType;
+ TVectorType v(array, array + 4);
+
+ UNIT_ASSERT(v.size() == 4);
+
+ UNIT_ASSERT(v[0] == 1);
+ UNIT_ASSERT(v[1] == 4);
+ UNIT_ASSERT(v[2] == 9);
+ UNIT_ASSERT(v[3] == 16);
+ }
+
+ void Test6() {
+ int array[] = {1, 4, 9, 16, 25, 36};
+
+ typedef NPagedVector::TPagedVector<int, 3> TVectorType;
+ TVectorType v(array, array + 6);
+ TVectorType::iterator vit;
+
+ UNIT_ASSERT_VALUES_EQUAL(v.size(), 6u);
+ UNIT_ASSERT(v[0] == 1);
+ UNIT_ASSERT(v[1] == 4);
+ UNIT_ASSERT(v[2] == 9);
+ UNIT_ASSERT(v[3] == 16);
+ UNIT_ASSERT(v[4] == 25);
+ UNIT_ASSERT(v[5] == 36);
+
+ vit = v.erase(v.begin()); // Erase first element.
+ UNIT_ASSERT(*vit == 4);
+
+ UNIT_ASSERT(v.size() == 5);
+ UNIT_ASSERT(v[0] == 4);
+ UNIT_ASSERT(v[1] == 9);
+ UNIT_ASSERT(v[2] == 16);
+ UNIT_ASSERT(v[3] == 25);
+ UNIT_ASSERT(v[4] == 36);
+
+ vit = v.erase(v.end() - 1); // Erase last element.
+ UNIT_ASSERT(vit == v.end());
+
+ UNIT_ASSERT(v.size() == 4);
+ UNIT_ASSERT(v[0] == 4);
+ UNIT_ASSERT(v[1] == 9);
+ UNIT_ASSERT(v[2] == 16);
+ UNIT_ASSERT(v[3] == 25);
+
+ v.erase(v.begin() + 1, v.end() - 1); // Erase all but first and last.
+
+ UNIT_ASSERT(v.size() == 2);
+ UNIT_ASSERT(v[0] == 4);
+ UNIT_ASSERT(v[1] == 25);
+ }
+
+ void Test7() {
+ int array1[] = {1, 4, 25};
+ int array2[] = {9, 16};
+
+ typedef NPagedVector::TPagedVector<int, 3> TVectorType;
+
+ TVectorType v(array1, array1 + 3);
+ TVectorType::iterator vit;
+ vit = v.insert(v.begin(), 0); // Insert before first element.
+ UNIT_ASSERT_VALUES_EQUAL(*vit, 0);
+
+ vit = v.insert(v.end(), 36); // Insert after last element.
+ UNIT_ASSERT(*vit == 36);
+
+ UNIT_ASSERT(v.size() == 5);
+ UNIT_ASSERT(v[0] == 0);
+ UNIT_ASSERT(v[1] == 1);
+ UNIT_ASSERT(v[2] == 4);
+ UNIT_ASSERT(v[3] == 25);
+ UNIT_ASSERT(v[4] == 36);
+
+ // Insert contents of array2 before fourth element.
+ v.insert(v.begin() + 3, array2, array2 + 2);
+
+ UNIT_ASSERT(v.size() == 7);
+
+ UNIT_ASSERT(v[0] == 0);
+ UNIT_ASSERT(v[1] == 1);
+ UNIT_ASSERT(v[2] == 4);
+ UNIT_ASSERT(v[3] == 9);
+ UNIT_ASSERT(v[4] == 16);
+ UNIT_ASSERT(v[5] == 25);
+ UNIT_ASSERT(v[6] == 36);
+
+ v.clear();
+ UNIT_ASSERT(v.empty());
+ }
+
+ void TestAt() {
+ using NPagedVector::TPagedVector;
+ TPagedVector<int, 3> v;
+ TPagedVector<int, 3> const& cv = v;
+
+ v.push_back(10);
+ UNIT_ASSERT(v.at(0) == 10);
+ v.at(0) = 20;
+ UNIT_ASSERT(cv.at(0) == 20);
+
+ for (;;) {
+ try {
+ v.at(1) = 20;
+ UNIT_ASSERT(false);
+ } catch (std::out_of_range const&) {
+ return;
+ } catch (...) {
+ UNIT_ASSERT(false);
+ }
+ }
+ }
+
+ void TestAutoRef() {
+ using NPagedVector::TPagedVector;
+ typedef TPagedVector<int, 3> TVec;
+ TVec ref;
+ for (int i = 0; i < 5; ++i) {
+ ref.push_back(i);
+ }
+
+ TPagedVector<TVec, 3> v_v_int;
+ v_v_int.push_back(ref);
+ v_v_int.push_back(v_v_int[0]);
+ v_v_int.push_back(ref);
+ v_v_int.push_back(v_v_int[0]);
+ v_v_int.push_back(v_v_int[0]);
+ v_v_int.push_back(ref);
+
+ TPagedVector<TVec, 3>::iterator vvit(v_v_int.begin()), vvitEnd(v_v_int.end());
+ for (; vvit != vvitEnd; ++vvit) {
+ UNIT_ASSERT(*vvit == ref);
+ }
+ }
+
+ struct Point {
+ int x, y;
+ };
+
+ struct PointEx: public Point {
+ PointEx()
+ : builtFromBase(false)
+ {
+ }
+ PointEx(const Point&)
+ : builtFromBase(true)
+ {
+ }
+
+ bool builtFromBase;
+ };
+
+ void TestIterators() {
+ using NPagedVector::TPagedVector;
+ TPagedVector<int, 3> vint;
+ vint.resize(10);
+ TPagedVector<int, 3> const& crvint = vint;
+
+ UNIT_ASSERT(vint.begin() == vint.begin());
+ UNIT_ASSERT(crvint.begin() == vint.begin());
+ UNIT_ASSERT(vint.begin() == crvint.begin());
+ UNIT_ASSERT(crvint.begin() == crvint.begin());
+
+ UNIT_ASSERT(vint.begin() != vint.end());
+ UNIT_ASSERT(crvint.begin() != vint.end());
+ UNIT_ASSERT(vint.begin() != crvint.end());
+ UNIT_ASSERT(crvint.begin() != crvint.end());
+
+ UNIT_ASSERT(vint.rbegin() == vint.rbegin());
+ // Not Standard:
+ //UNIT_ASSERT(vint.rbegin() == crvint.rbegin());
+ //UNIT_ASSERT(crvint.rbegin() == vint.rbegin());
+ UNIT_ASSERT(crvint.rbegin() == crvint.rbegin());
+
+ UNIT_ASSERT(vint.rbegin() != vint.rend());
+ // Not Standard:
+ //UNIT_ASSERT(vint.rbegin() != crvint.rend());
+ //UNIT_ASSERT(crvint.rbegin() != vint.rend());
+ UNIT_ASSERT(crvint.rbegin() != crvint.rend());
+ }
+
+ /* This test check a potential issue with empty base class
+ * optimization. Some compilers (VC6) do not implement it
+ * correctly resulting ina wrong behavior. */
+ void TestEbo() {
+ using NPagedVector::TPagedVector;
+ // We use heap memory as test failure can corrupt vector internal
+ // representation making executable crash on vector destructor invocation.
+ // We prefer a simple memory leak, internal corruption should be reveal
+ // by size or capacity checks.
+ typedef TPagedVector<int, 3> V;
+ V* pv1 = new V;
+
+ pv1->resize(1);
+ pv1->at(0) = 1;
+
+ V* pv2 = new V;
+
+ pv2->resize(10);
+ for (int i = 0; i < 10; ++i)
+ pv2->at(i) = 2;
+
+ pv1->swap(*pv2);
+
+ UNIT_ASSERT(pv1->size() == 10);
+ UNIT_ASSERT((*pv1)[5] == 2);
+
+ UNIT_ASSERT(pv2->size() == 1);
+ UNIT_ASSERT((*pv2)[0] == 1);
+
+ delete pv2;
+ delete pv1;
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TPagedVectorTest);
diff --git a/library/cpp/containers/paged_vector/ut/ya.make b/library/cpp/containers/paged_vector/ut/ya.make
new file mode 100644
index 0000000000..74cfe5fb4a
--- /dev/null
+++ b/library/cpp/containers/paged_vector/ut/ya.make
@@ -0,0 +1,13 @@
+UNITTEST()
+
+OWNER(velavokr)
+
+PEERDIR(
+ library/cpp/containers/paged_vector
+)
+
+SRCS(
+ paged_vector_ut.cpp
+)
+
+END()
diff --git a/library/cpp/containers/paged_vector/ya.make b/library/cpp/containers/paged_vector/ya.make
new file mode 100644
index 0000000000..e14548bc2c
--- /dev/null
+++ b/library/cpp/containers/paged_vector/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(velavokr)
+
+SRCS(
+ paged_vector.cpp
+)
+
+END()
diff --git a/library/cpp/containers/ring_buffer/ring_buffer.cpp b/library/cpp/containers/ring_buffer/ring_buffer.cpp
new file mode 100644
index 0000000000..799dad631b
--- /dev/null
+++ b/library/cpp/containers/ring_buffer/ring_buffer.cpp
@@ -0,0 +1 @@
+#include "ring_buffer.h"
diff --git a/library/cpp/containers/ring_buffer/ring_buffer.h b/library/cpp/containers/ring_buffer/ring_buffer.h
new file mode 100644
index 0000000000..41220dcf6b
--- /dev/null
+++ b/library/cpp/containers/ring_buffer/ring_buffer.h
@@ -0,0 +1,81 @@
+#pragma once
+
+#include <util/generic/vector.h>
+#include <util/system/yassert.h>
+
+template <typename T>
+class TSimpleRingBuffer {
+public:
+ TSimpleRingBuffer(size_t maxSize)
+ : MaxSize(maxSize)
+ {
+ Items.reserve(MaxSize);
+ }
+
+ TSimpleRingBuffer(const TSimpleRingBuffer&) = default;
+ TSimpleRingBuffer(TSimpleRingBuffer&&) = default;
+
+ TSimpleRingBuffer& operator=(const TSimpleRingBuffer&) = default;
+ TSimpleRingBuffer& operator=(TSimpleRingBuffer&&) = default;
+
+ // First available item
+ size_t FirstIndex() const {
+ return Begin;
+ }
+
+ size_t AvailSize() const {
+ return Items.size();
+ }
+
+ // Total number of items inserted
+ size_t TotalSize() const {
+ return FirstIndex() + AvailSize();
+ }
+
+ bool IsAvail(size_t index) const {
+ return index >= FirstIndex() && index < TotalSize();
+ }
+
+ const T& operator[](size_t index) const {
+ Y_ASSERT(IsAvail(index));
+ return Items[RealIndex(index)];
+ }
+
+ T& operator[](size_t index) {
+ Y_ASSERT(IsAvail(index));
+ return Items[RealIndex(index)];
+ }
+
+ void PushBack(const T& t) {
+ if (Items.size() < MaxSize) {
+ Items.push_back(t);
+ } else {
+ Items[RealIndex(Begin)] = t;
+ Begin += 1;
+ }
+ }
+
+ void Clear() {
+ Items.clear();
+ Begin = 0;
+ }
+
+private:
+ size_t RealIndex(size_t index) const {
+ return index % MaxSize;
+ }
+
+private:
+ size_t MaxSize;
+ size_t Begin = 0;
+ TVector<T> Items;
+};
+
+template <typename T, size_t maxSize>
+class TStaticRingBuffer: public TSimpleRingBuffer<T> {
+public:
+ TStaticRingBuffer()
+ : TSimpleRingBuffer<T>(maxSize)
+ {
+ }
+};
diff --git a/library/cpp/containers/ring_buffer/ya.make b/library/cpp/containers/ring_buffer/ya.make
new file mode 100644
index 0000000000..51333978f7
--- /dev/null
+++ b/library/cpp/containers/ring_buffer/ya.make
@@ -0,0 +1,9 @@
+OWNER(mowgli)
+
+LIBRARY()
+
+SRCS(
+ ring_buffer.cpp
+)
+
+END()
diff --git a/library/cpp/containers/sorted_vector/sorted_vector.cpp b/library/cpp/containers/sorted_vector/sorted_vector.cpp
new file mode 100644
index 0000000000..56aaf69dde
--- /dev/null
+++ b/library/cpp/containers/sorted_vector/sorted_vector.cpp
@@ -0,0 +1 @@
+#include "sorted_vector.h"
diff --git a/library/cpp/containers/sorted_vector/sorted_vector.h b/library/cpp/containers/sorted_vector/sorted_vector.h
new file mode 100644
index 0000000000..123539af9e
--- /dev/null
+++ b/library/cpp/containers/sorted_vector/sorted_vector.h
@@ -0,0 +1,492 @@
+#pragma once
+
+#include <util/system/defaults.h>
+#include <util/generic/hash.h>
+#include <util/generic/vector.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/mapfindptr.h>
+#include <util/ysaveload.h>
+#include <utility>
+
+#include <initializer_list>
+
+namespace NSorted {
+ namespace NPrivate {
+ template <class TPredicate>
+ struct TEqual {
+ template<typename TValueType1, typename TValueType2>
+ inline bool operator()(const TValueType1& l, const TValueType2& r) const {
+ TPredicate comp;
+ return comp(l, r) == comp(r, l);
+ }
+ };
+
+ template <typename TValueType, class TPredicate, class TKeyExtractor>
+ struct TKeyCompare {
+ inline bool operator()(const TValueType& l, const TValueType& r) const {
+ TKeyExtractor extractKey;
+ return TPredicate()(extractKey(l), extractKey(r));
+ }
+ template<typename TKeyType>
+ inline bool operator()(const TKeyType& l, const TValueType& r) const {
+ return TPredicate()(l, TKeyExtractor()(r));
+ }
+ template<typename TKeyType>
+ inline bool operator()(const TValueType& l, const TKeyType& r) const {
+ return TPredicate()(TKeyExtractor()(l), r);
+ }
+ };
+
+ template <typename TValueType, class TPredicate>
+ struct TKeyCompare<TValueType, TPredicate, TIdentity> {
+ template <typename TValueType1, typename TValueType2>
+ inline bool operator()(const TValueType1& l, const TValueType2& r) const {
+ return TPredicate()(l, r);
+ }
+ };
+
+ }
+
+ // Sorted vector, which is order by the key. The key is extracted from the value by the provided key-extractor
+ template <typename TValueType, typename TKeyType = TValueType, class TKeyExtractor = TIdentity,
+ class TPredicate = TLess<TKeyType>, class A = std::allocator<TValueType>>
+ class TSortedVector: public TVector<TValueType, A> {
+ private:
+ typedef TVector<TValueType, A> TBase;
+ typedef NPrivate::TKeyCompare<TValueType, TPredicate, TKeyExtractor> TKeyCompare;
+ typedef NPrivate::TEqual<TKeyCompare> TValueEqual;
+ typedef NPrivate::TEqual<TPredicate> TKeyEqual;
+
+ public:
+ typedef TValueType value_type;
+ typedef TKeyType key_type;
+ typedef typename TBase::iterator iterator;
+ typedef typename TBase::const_iterator const_iterator;
+ typedef typename TBase::size_type size_type;
+
+ public:
+ inline TSortedVector()
+ : TBase()
+ {
+ }
+
+ inline explicit TSortedVector(size_type count)
+ : TBase(count)
+ {
+ }
+
+ inline TSortedVector(size_type count, const value_type& val)
+ : TBase(count, val)
+ {
+ }
+
+ inline TSortedVector(std::initializer_list<value_type> il)
+ : TBase(il)
+ {
+ Sort();
+ }
+
+ inline TSortedVector(std::initializer_list<value_type> il, const typename TBase::allocator_type& a)
+ : TBase(il, a)
+ {
+ Sort();
+ }
+
+ template <class TIter>
+ inline TSortedVector(TIter first, TIter last)
+ : TBase(first, last)
+ {
+ Sort();
+ }
+
+ // Inserts non-unique value in the proper position according to the key-sort order.
+ // Returns iterator, which points to the inserted value
+ inline iterator Insert(const value_type& value) {
+ return TBase::insert(LowerBound(TKeyExtractor()(value)), value);
+ }
+
+ // STL-compatible synonym
+ Y_FORCE_INLINE iterator insert(const value_type& value) {
+ return this->Insert(value);
+ }
+
+ // Inserts non-unique value range in the proper position according to the key-sort order.
+ template <class TIter>
+ inline void Insert(TIter first, TIter last) {
+ TBase::insert(TBase::end(), first, last);
+ Sort();
+ }
+
+ // STL-compatible synonym
+ template <class TIter>
+ Y_FORCE_INLINE void insert(TIter first, TIter last) {
+ this->Insert(first, last);
+ }
+
+ // Inserts unique value in the proper position according to the key-sort order,
+ // if the value with the same key doesn't exist. Returns <iterator, bool> pair,
+ // where the first member is the pointer to the inserted/existing value, and the
+ // second member indicates either the value is inserted or not.
+ inline std::pair<iterator, bool> InsertUnique(const value_type& value) {
+ iterator i = LowerBound(TKeyExtractor()(value));
+ if (i == TBase::end() || !TValueEqual()(*i, value))
+ return std::pair<iterator, bool>(TBase::insert(i, value), true);
+ else
+ return std::pair<iterator, bool>(i, false);
+ }
+
+ // STL-compatible synonym
+ Y_FORCE_INLINE std::pair<iterator, bool> insert_unique(const value_type& value) {
+ return this->InsertUnique(value);
+ }
+
+ // Inserts unique value range in the proper position according to the key-sort order.
+ template <class TIter>
+ inline void InsertUnique(TIter first, TIter last) {
+ TBase::insert(TBase::end(), first, last);
+ Sort();
+ MakeUnique();
+ }
+
+ // STL-compatible synonym
+ template <class TIter>
+ Y_FORCE_INLINE void insert_unique(TIter first, TIter last) {
+ this->InsertUnique(first, last);
+ }
+
+ // Inserts unique value in the proper position according to the key-sort order.
+ // If the value with the same key already exists, then it is replaced with the new one.
+ // Returns iterator, which points to the inserted value
+ inline iterator InsertOrReplace(const value_type& value) {
+ iterator i = ::LowerBound(TBase::begin(), TBase::end(), value, TKeyCompare());
+ if (i == TBase::end() || !TValueEqual()(*i, value))
+ return TBase::insert(i, value);
+ else
+ return TBase::insert(TBase::erase(i), value);
+ }
+
+ // STL-compatible synonym
+ Y_FORCE_INLINE iterator insert_or_replace(const value_type& value) {
+ return this->InsertOrReplace(value);
+ }
+
+ Y_FORCE_INLINE void Sort() {
+ ::Sort(TBase::begin(), TBase::end(), TKeyCompare());
+ }
+
+ // STL-compatible synonym
+ Y_FORCE_INLINE void sort() {
+ this->Sort();
+ }
+
+ Y_FORCE_INLINE void Sort(iterator from, iterator to) {
+ ::Sort(from, to, TKeyCompare());
+ }
+
+ // STL-compatible synonym
+ Y_FORCE_INLINE void sort(iterator from, iterator to) {
+ this->Sort(from, to);
+ }
+
+ inline void MakeUnique() {
+ TBase::erase(::Unique(TBase::begin(), TBase::end(), TValueEqual()), TBase::end());
+ }
+
+ // STL-compatible synonym
+ Y_FORCE_INLINE void make_unique() {
+ this->MakeUnique();
+ }
+
+ template<class K>
+ inline const_iterator Find(const K& key) const {
+ const_iterator i = LowerBound(key);
+ if (i == TBase::end() || !TKeyEqual()(TKeyExtractor()(*i), key))
+ return TBase::end();
+ else
+ return i;
+ }
+
+ // STL-compatible synonym
+ template<class K>
+ Y_FORCE_INLINE const_iterator find(const K& key) const {
+ return this->Find(key);
+ }
+
+ template<class K>
+ inline iterator Find(const K& key) {
+ iterator i = LowerBound(key);
+ if (i == TBase::end() || !TKeyEqual()(TKeyExtractor()(*i), key))
+ return TBase::end();
+ else
+ return i;
+ }
+
+ // STL-compatible synonym
+ template<class K>
+ Y_FORCE_INLINE iterator find(const K& key) {
+ return this->Find(key);
+ }
+
+ template<class K>
+ Y_FORCE_INLINE bool Has(const K& key) const {
+ return this->find(key) != TBase::end();
+ }
+
+ template<class K>
+ Y_FORCE_INLINE bool has(const K& key) const {
+ return this->Has(key);
+ }
+
+ template<class K>
+ Y_FORCE_INLINE iterator LowerBound(const K& key) {
+ return ::LowerBound(TBase::begin(), TBase::end(), key, TKeyCompare());
+ }
+
+ // STL-compatible synonym
+ template<class K>
+ Y_FORCE_INLINE iterator lower_bound(const K& key) {
+ return this->LowerBound(key);
+ }
+
+ template<class K>
+ Y_FORCE_INLINE const_iterator LowerBound(const K& key) const {
+ return ::LowerBound(TBase::begin(), TBase::end(), key, TKeyCompare());
+ }
+
+ // STL-compatible synonym
+ template<class K>
+ Y_FORCE_INLINE const_iterator lower_bound(const K& key) const {
+ return this->LowerBound(key);
+ }
+
+ template<class K>
+ Y_FORCE_INLINE iterator UpperBound(const K& key) {
+ return ::UpperBound(TBase::begin(), TBase::end(), key, TKeyCompare());
+ }
+
+ // STL-compatible synonym
+ template<class K>
+ Y_FORCE_INLINE iterator upper_bound(const K& key) {
+ return this->UpperBound(key);
+ }
+
+ template<class K>
+ Y_FORCE_INLINE const_iterator UpperBound(const K& key) const {
+ return ::UpperBound(TBase::begin(), TBase::end(), key, TKeyCompare());
+ }
+
+ // STL-compatible synonym
+ template<class K>
+ Y_FORCE_INLINE const_iterator upper_bound(const K& key) const {
+ return this->UpperBound(key);
+ }
+
+ template<class K>
+ Y_FORCE_INLINE std::pair<iterator, iterator> EqualRange(const K& key) {
+ return std::equal_range(TBase::begin(), TBase::end(), key, TKeyCompare());
+ }
+
+ // STL-compatible synonym
+ template<class K>
+ Y_FORCE_INLINE std::pair<iterator, iterator> equal_range(const K& key) {
+ return this->EqualRange(key);
+ }
+
+ template<class K>
+ Y_FORCE_INLINE std::pair<const_iterator, const_iterator> EqualRange(const K& key) const {
+ return std::equal_range(TBase::begin(), TBase::end(), key, TKeyCompare());
+ }
+
+ // STL-compatible synonym
+ template<class K>
+ Y_FORCE_INLINE std::pair<const_iterator, const_iterator> equal_range(const K& key) const {
+ return this->EqualRange(key);
+ }
+
+ template<class K>
+ inline void Erase(const K& key) {
+ std::pair<iterator, iterator> res = EqualRange(key);
+ TBase::erase(res.first, res.second);
+ }
+
+ // STL-compatible synonym
+ Y_FORCE_INLINE void erase(const key_type& key) {
+ this->Erase(key);
+ }
+
+ template<class K>
+ inline size_t count(const K& key) const {
+ const std::pair<const_iterator, const_iterator> range = this->EqualRange(key);
+ return std::distance(range.first, range.second);
+ }
+
+ using TBase::erase;
+ };
+
+ // The simplified map (a.k.a TFlatMap, flat_map), which is implemented by the sorted-vector.
+ // This structure has the side-effect: if you keep a reference to an existing element
+ // and then inserts a new one, the existing reference can be broken (due to reallocation).
+ // Please keep this in mind when using this structure.
+ template <typename TKeyType, typename TValueType, class TPredicate = TLess<TKeyType>, class A = std::allocator<TValueType>>
+ class TSimpleMap:
+ public TSortedVector<std::pair<TKeyType, TValueType>, TKeyType, TSelect1st, TPredicate, A>,
+ public TMapOps<TSimpleMap<TKeyType, TValueType, TPredicate, A>>
+ {
+ private:
+ typedef TSortedVector<std::pair<TKeyType, TValueType>, TKeyType, TSelect1st, TPredicate, A> TBase;
+
+ public:
+ typedef typename TBase::value_type value_type;
+ typedef typename TBase::key_type key_type;
+ typedef typename TBase::iterator iterator;
+ typedef typename TBase::const_iterator const_iterator;
+ typedef typename TBase::size_type size_type;
+
+ public:
+ inline TSimpleMap()
+ : TBase()
+ {
+ }
+
+ template <class TIter>
+ inline TSimpleMap(TIter first, TIter last)
+ : TBase(first, last)
+ {
+ TBase::MakeUnique();
+ }
+
+ inline TSimpleMap(std::initializer_list<value_type> il)
+ : TBase(il)
+ {
+ TBase::MakeUnique();
+ }
+
+ inline TValueType& Get(const TKeyType& key) {
+ typename TBase::iterator i = TBase::LowerBound(key);
+ if (i == TBase::end() || key != i->first)
+ return TVector<std::pair<TKeyType, TValueType>, A>::insert(i, std::make_pair(key, TValueType()))->second;
+ else
+ return i->second;
+ }
+
+ template<class K>
+ inline const TValueType& Get(const K& key, const TValueType& def) const {
+ typename TBase::const_iterator i = TBase::Find(key);
+ return i != TBase::end() ? i->second : def;
+ }
+
+ template<class K>
+ Y_FORCE_INLINE TValueType& operator[](const K& key) {
+ return Get(key);
+ }
+
+ template<class K>
+ const TValueType& at(const K& key) const {
+ const auto i = TBase::Find(key);
+ if (i == TBase::end()) {
+ throw std::out_of_range("NSorted::TSimpleMap: missing key");
+ }
+
+ return i->second;
+ }
+
+ template<class K>
+ TValueType& at(const K& key) {
+ return const_cast<TValueType&>(
+ const_cast<const TSimpleMap<TKeyType, TValueType, TPredicate, A>*>(this)->at(key));
+ }
+ };
+
+ // The simplified set (a.k.a TFlatSet, flat_set), which is implemented by the sorted-vector.
+ // This structure has the same side-effect as TSimpleMap.
+ // The value type must have TValueType(TKeyType) constructor in order to use [] operator
+ template <typename TValueType, typename TKeyType = TValueType, class TKeyExtractor = TIdentity,
+ class TPredicate = TLess<TKeyType>, class A = std::allocator<TValueType>>
+ class TSimpleSet: public TSortedVector<TValueType, TKeyType, TKeyExtractor, TPredicate, A> {
+ private:
+ typedef TSortedVector<TValueType, TKeyType, TKeyExtractor, TPredicate, A> TBase;
+
+ public:
+ typedef typename TBase::value_type value_type;
+ typedef typename TBase::key_type key_type;
+ typedef typename TBase::iterator iterator;
+ typedef typename TBase::const_iterator const_iterator;
+ typedef typename TBase::size_type size_type;
+ typedef NPrivate::TEqual<TPredicate> TKeyEqual;
+
+ public:
+ inline TSimpleSet()
+ : TBase()
+ {
+ }
+
+ template <class TIter>
+ inline TSimpleSet(TIter first, TIter last)
+ : TBase(first, last)
+ {
+ TBase::MakeUnique();
+ }
+
+ inline TSimpleSet(std::initializer_list<value_type> il)
+ : TBase(il)
+ {
+ TBase::MakeUnique();
+ }
+
+ // The method expects that there is a TValueType(TKeyType) constructor available
+ inline TValueType& Get(const TKeyType& key) {
+ typename TBase::iterator i = TBase::LowerBound(key);
+ if (i == TBase::end() || !TKeyEqual()(TKeyExtractor()(*i), key))
+ i = TVector<TValueType, A>::insert(i, TValueType(key));
+ return *i;
+ }
+
+ template<class K>
+ inline const TValueType& Get(const K& key, const TValueType& def) const {
+ typename TBase::const_iterator i = TBase::Find(key);
+ return i != TBase::end() ? *i : def;
+ }
+
+ template<class K>
+ Y_FORCE_INLINE TValueType& operator[](const K& key) {
+ return Get(key);
+ }
+
+ // Inserts value with unique key. Returns <iterator, bool> pair,
+ // where the first member is the pointer to the inserted/existing value, and the
+ // second member indicates either the value is inserted or not.
+ Y_FORCE_INLINE std::pair<iterator, bool> Insert(const TValueType& value) {
+ return TBase::InsertUnique(value);
+ }
+
+ // STL-compatible synonym
+ Y_FORCE_INLINE std::pair<iterator, bool> insert(const TValueType& value) {
+ return TBase::InsertUnique(value);
+ }
+
+ // Inserts value range with unique keys.
+ template <class TIter>
+ Y_FORCE_INLINE void Insert(TIter first, TIter last) {
+ TBase::InsertUnique(first, last);
+ }
+
+ // STL-compatible synonym
+ template <class TIter>
+ Y_FORCE_INLINE void insert(TIter first, TIter last) {
+ TBase::InsertUnique(first, last);
+ }
+ };
+
+}
+
+template <typename V, typename K, class E, class P, class A>
+class TSerializer<NSorted::TSortedVector<V, K, E, P, A>>: public TVectorSerializer<NSorted::TSortedVector<V, K, E, P, A>> {
+};
+
+template <typename K, typename V, class P, class A>
+class TSerializer<NSorted::TSimpleMap<K, V, P, A>>: public TVectorSerializer<NSorted::TSimpleMap<K, V, P, A>> {
+};
+
+template <typename V, typename K, class E, class P, class A>
+class TSerializer<NSorted::TSimpleSet<V, K, E, P, A>>: public TVectorSerializer<NSorted::TSimpleSet<V, K, E, P, A>> {
+};
diff --git a/library/cpp/containers/sorted_vector/sorted_vector_ut.cpp b/library/cpp/containers/sorted_vector/sorted_vector_ut.cpp
new file mode 100644
index 0000000000..893862f098
--- /dev/null
+++ b/library/cpp/containers/sorted_vector/sorted_vector_ut.cpp
@@ -0,0 +1,24 @@
+#include "sorted_vector.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/string.h>
+#include <util/generic/strbuf.h>
+
+Y_UNIT_TEST_SUITE(TestSimpleMap) {
+
+ Y_UNIT_TEST(TestFindPrt) {
+ NSorted::TSimpleMap<TString, TString> map(
+ {std::make_pair(TString("a"), TString("a")), std::make_pair(TString("b"), TString("b"))});
+
+ UNIT_ASSERT_VALUES_UNEQUAL(map.FindPtr(TString("a")), nullptr);
+ UNIT_ASSERT_VALUES_EQUAL(map.FindPtr(TString("c")), nullptr);
+
+ UNIT_ASSERT_VALUES_UNEQUAL(map.FindPtr(TStringBuf("a")), nullptr);
+ UNIT_ASSERT_VALUES_EQUAL(map.FindPtr(TStringBuf("c")), nullptr);
+
+ UNIT_ASSERT_VALUES_UNEQUAL(map.FindPtr("a"), nullptr);
+ UNIT_ASSERT_VALUES_EQUAL(map.FindPtr("c"), nullptr);
+ }
+
+}
diff --git a/library/cpp/containers/sorted_vector/ut/ya.make b/library/cpp/containers/sorted_vector/ut/ya.make
new file mode 100644
index 0000000000..eb8a5b4bef
--- /dev/null
+++ b/library/cpp/containers/sorted_vector/ut/ya.make
@@ -0,0 +1,10 @@
+UNITTEST_FOR(library/cpp/containers/sorted_vector)
+
+OWNER(udovichenko-r)
+
+
+SRCS(
+ sorted_vector_ut.cpp
+)
+
+END()
diff --git a/library/cpp/containers/sorted_vector/ya.make b/library/cpp/containers/sorted_vector/ya.make
new file mode 100644
index 0000000000..1975c5dc90
--- /dev/null
+++ b/library/cpp/containers/sorted_vector/ya.make
@@ -0,0 +1,11 @@
+LIBRARY()
+
+OWNER(udovichenko-r)
+
+SRCS(
+ sorted_vector.cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/containers/stack_array/range_ops.cpp b/library/cpp/containers/stack_array/range_ops.cpp
new file mode 100644
index 0000000000..f1b5e3af0d
--- /dev/null
+++ b/library/cpp/containers/stack_array/range_ops.cpp
@@ -0,0 +1 @@
+#include "range_ops.h"
diff --git a/library/cpp/containers/stack_array/range_ops.h b/library/cpp/containers/stack_array/range_ops.h
new file mode 100644
index 0000000000..1d40341aa1
--- /dev/null
+++ b/library/cpp/containers/stack_array/range_ops.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <util/generic/typetraits.h>
+
+#include <new>
+
+namespace NRangeOps {
+ template <class T, bool isTrivial>
+ struct TRangeOpsBase {
+ static inline void DestroyRange(T* b, T* e) noexcept {
+ while (e > b) {
+ (--e)->~T();
+ }
+ }
+
+ static inline void InitializeRange(T* b, T* e) {
+ T* c = b;
+
+ try {
+ for (; c < e; ++c) {
+ new (c) T();
+ }
+ } catch (...) {
+ DestroyRange(b, c);
+
+ throw;
+ }
+ }
+ };
+
+ template <class T>
+ struct TRangeOpsBase<T, true> {
+ static inline void DestroyRange(T*, T*) noexcept {
+ }
+
+ static inline void InitializeRange(T*, T*) noexcept {
+ }
+ };
+
+ template <class T>
+ using TRangeOps = TRangeOpsBase<T, TTypeTraits<T>::IsPod>;
+
+ template <class T>
+ static inline void DestroyRange(T* b, T* e) noexcept {
+ TRangeOps<T>::DestroyRange(b, e);
+ }
+
+ template <class T>
+ static inline void InitializeRange(T* b, T* e) {
+ TRangeOps<T>::InitializeRange(b, e);
+ }
+}
diff --git a/library/cpp/containers/stack_array/stack_array.cpp b/library/cpp/containers/stack_array/stack_array.cpp
new file mode 100644
index 0000000000..68e8b097ba
--- /dev/null
+++ b/library/cpp/containers/stack_array/stack_array.cpp
@@ -0,0 +1 @@
+#include "stack_array.h"
diff --git a/library/cpp/containers/stack_array/stack_array.h b/library/cpp/containers/stack_array/stack_array.h
new file mode 100644
index 0000000000..28e49bfc3c
--- /dev/null
+++ b/library/cpp/containers/stack_array/stack_array.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "range_ops.h"
+
+#include <util/generic/array_ref.h>
+#include <util/system/defaults.h> /* For alloca. */
+
+namespace NStackArray {
+ /**
+ * A stack-allocated array. Should be used instead of � variable length
+ * arrays that are not part of C++ standard.
+ *
+ * Example usage:
+ * @code
+ * void f(int size) {
+ * // T array[size]; // Wrong!
+ * TStackArray<T> array(ALLOC_ON_STACK(T, size)); // Right!
+ * // ...
+ * }
+ * @endcode
+ *
+ * Note that it is generally a *VERY BAD* idea to use this in inline methods
+ * as those might be called from a loop, and then stack overflow is in the cards.
+ */
+ template <class T>
+ class TStackArray: public TArrayRef<T> {
+ public:
+ inline TStackArray(void* data, size_t len)
+ : TArrayRef<T>((T*)data, len)
+ {
+ NRangeOps::InitializeRange(this->begin(), this->end());
+ }
+
+ inline ~TStackArray() {
+ NRangeOps::DestroyRange(this->begin(), this->end());
+ }
+ };
+}
+
+#define ALLOC_ON_STACK(type, n) alloca(sizeof(type) * (n)), (n)
diff --git a/library/cpp/containers/stack_array/ut/tests_ut.cpp b/library/cpp/containers/stack_array/ut/tests_ut.cpp
new file mode 100644
index 0000000000..3e96384f0e
--- /dev/null
+++ b/library/cpp/containers/stack_array/ut/tests_ut.cpp
@@ -0,0 +1,94 @@
+#include <library/cpp/containers/stack_array/stack_array.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TestStackArray) {
+ using namespace NStackArray;
+
+ static inline void* FillWithTrash(void* d, size_t l) {
+ memset(d, 0xCC, l);
+
+ return d;
+ }
+
+#define ALLOC(type, len) FillWithTrash(alloca(sizeof(type) * len), sizeof(type) * len), len
+
+ Y_UNIT_TEST(Test1) {
+ TStackArray<ui32> s(ALLOC(ui32, 10));
+
+ UNIT_ASSERT_VALUES_EQUAL(s.size(), 10);
+
+ for (size_t i = 0; i < s.size(); ++i) {
+ UNIT_ASSERT_VALUES_EQUAL(s[i], 0xCCCCCCCC);
+ }
+
+ for (auto&& x : s) {
+ UNIT_ASSERT_VALUES_EQUAL(x, 0xCCCCCCCC);
+ }
+
+ for (size_t i = 0; i < s.size(); ++i) {
+ s[i] = i;
+ }
+
+ size_t ss = 0;
+
+ for (auto&& x : s) {
+ ss += x;
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(ss, 45);
+ }
+
+ static int N1 = 0;
+
+ struct TX1 {
+ inline TX1() {
+ ++N1;
+ }
+
+ inline ~TX1() {
+ --N1;
+ }
+ };
+
+ Y_UNIT_TEST(Test2) {
+ {
+ TStackArray<TX1> s(ALLOC(TX1, 10));
+
+ UNIT_ASSERT_VALUES_EQUAL(N1, 10);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(N1, 0);
+ }
+
+ static int N2 = 0;
+ static int N3 = 0;
+
+ struct TX2 {
+ inline TX2() {
+ if (N2 >= 5) {
+ ythrow yexception() << "ups";
+ }
+
+ ++N3;
+ ++N2;
+ }
+
+ inline ~TX2() {
+ --N2;
+ }
+ };
+
+ Y_UNIT_TEST(Test3) {
+ bool haveException = false;
+
+ try {
+ TStackArray<TX2> s(ALLOC_ON_STACK(TX2, 10));
+ } catch (...) {
+ haveException = true;
+ }
+
+ UNIT_ASSERT(haveException);
+ UNIT_ASSERT_VALUES_EQUAL(N2, 0);
+ UNIT_ASSERT_VALUES_EQUAL(N3, 5);
+ }
+}
diff --git a/library/cpp/containers/stack_array/ut/ya.make b/library/cpp/containers/stack_array/ut/ya.make
new file mode 100644
index 0000000000..7db7340073
--- /dev/null
+++ b/library/cpp/containers/stack_array/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/containers/stack_array)
+
+OWNER(pg)
+
+SRCS(
+ tests_ut.cpp
+)
+
+END()
diff --git a/library/cpp/containers/stack_array/ya.make b/library/cpp/containers/stack_array/ya.make
new file mode 100644
index 0000000000..9bc0afc66c
--- /dev/null
+++ b/library/cpp/containers/stack_array/ya.make
@@ -0,0 +1,10 @@
+LIBRARY()
+
+OWNER(pg)
+
+SRCS(
+ range_ops.cpp
+ stack_array.cpp
+)
+
+END()
diff --git a/library/cpp/containers/stack_vector/stack_vec.cpp b/library/cpp/containers/stack_vector/stack_vec.cpp
new file mode 100644
index 0000000000..21c0ab3f11
--- /dev/null
+++ b/library/cpp/containers/stack_vector/stack_vec.cpp
@@ -0,0 +1 @@
+#include "stack_vec.h"
diff --git a/library/cpp/containers/stack_vector/stack_vec.h b/library/cpp/containers/stack_vector/stack_vec.h
new file mode 100644
index 0000000000..fcc5d9a2a5
--- /dev/null
+++ b/library/cpp/containers/stack_vector/stack_vec.h
@@ -0,0 +1,212 @@
+#pragma once
+
+#include <util/generic/vector.h>
+#include <util/ysaveload.h>
+
+#include <type_traits>
+
+// A vector preallocated on the stack.
+// After exceeding the preconfigured stack space falls back to the heap.
+// Publicly inherits TVector, but disallows swap (and hence shrink_to_fit, also operator= is reimplemented via copying).
+//
+// Inspired by: http://qt-project.org/doc/qt-4.8/qvarlengtharray.html#details
+
+template <typename T, size_t CountOnStack = 256, bool UseFallbackAlloc = true, class Alloc = std::allocator<T>>
+class TStackVec;
+
+template <typename T, class Alloc = std::allocator<T>>
+using TSmallVec = TStackVec<T, 16, true, Alloc>;
+
+template <typename T, size_t CountOnStack = 256>
+using TStackOnlyVec = TStackVec<T, CountOnStack, false>;
+
+namespace NPrivate {
+ template <class Alloc, class StackAlloc, typename T, typename U>
+ struct TRebind {
+ typedef TReboundAllocator<Alloc, U> other;
+ };
+
+ template <class Alloc, class StackAlloc, typename T>
+ struct TRebind<Alloc, StackAlloc, T, T> {
+ typedef StackAlloc other;
+ };
+
+ template <typename T, size_t CountOnStack, bool UseFallbackAlloc, class Alloc = std::allocator<T>>
+ class TStackBasedAllocator: public Alloc {
+ public:
+ typedef TStackBasedAllocator<T, CountOnStack, UseFallbackAlloc, Alloc> TSelf;
+
+ using typename Alloc::difference_type;
+ using typename Alloc::size_type;
+ using typename Alloc::value_type;
+
+ template <class U>
+ struct rebind: public ::NPrivate::TRebind<Alloc, TSelf, T, U> {
+ };
+
+ public:
+ TStackBasedAllocator() = default;
+
+ template <
+ typename... TArgs,
+ typename = std::enable_if_t<
+ std::is_constructible_v<Alloc, TArgs...>
+ >
+ >
+ TStackBasedAllocator(TArgs&&... args)
+ : Alloc(std::forward<TArgs>(args)...)
+ {}
+
+ T* allocate(size_type n) {
+ if (!IsStorageUsed && CountOnStack >= n) {
+ IsStorageUsed = true;
+ return reinterpret_cast<T*>(&StackBasedStorage[0]);
+ } else {
+ if constexpr (!UseFallbackAlloc) {
+ Y_FAIL(
+ "Stack storage overflow. Capacity: %d, requested: %d", (int)CountOnStack, int(n));
+ }
+ return FallbackAllocator().allocate(n);
+ }
+ }
+
+ void deallocate(T* p, size_type n) {
+ if (p >= reinterpret_cast<T*>(&StackBasedStorage[0]) &&
+ p < reinterpret_cast<T*>(&StackBasedStorage[CountOnStack])) {
+ Y_VERIFY(IsStorageUsed);
+ IsStorageUsed = false;
+ } else {
+ FallbackAllocator().deallocate(p, n);
+ }
+ }
+
+ private:
+ std::aligned_storage_t<sizeof(T), alignof(T)> StackBasedStorage[CountOnStack];
+ bool IsStorageUsed = false;
+
+ private:
+ Alloc& FallbackAllocator() noexcept {
+ return static_cast<Alloc&>(*this);
+ }
+ };
+}
+
+template <typename T, size_t CountOnStack, bool UseFallbackAlloc, class Alloc>
+class TStackVec: public TVector<T, ::NPrivate::TStackBasedAllocator<T, CountOnStack, UseFallbackAlloc, TReboundAllocator<Alloc, T>>> {
+private:
+ using TBase = TVector<T, ::NPrivate::TStackBasedAllocator<T, CountOnStack, UseFallbackAlloc, TReboundAllocator<Alloc, T>>>;
+ using TAllocator = typename TBase::allocator_type;
+
+public:
+ using typename TBase::const_iterator;
+ using typename TBase::const_reverse_iterator;
+ using typename TBase::iterator;
+ using typename TBase::reverse_iterator;
+ using typename TBase::size_type;
+ using typename TBase::value_type;
+
+public:
+ TStackVec(const TAllocator& alloc = TAllocator())
+ : TBase(alloc)
+ {
+ TBase::reserve(CountOnStack);
+ }
+
+ explicit TStackVec(size_type count, const TAllocator& alloc = TAllocator())
+ : TBase(alloc)
+ {
+ if (count <= CountOnStack) {
+ TBase::reserve(CountOnStack);
+ }
+ TBase::resize(count);
+ }
+
+ TStackVec(size_type count, const T& val, const TAllocator& alloc = TAllocator())
+ : TBase(alloc)
+ {
+ if (count <= CountOnStack) {
+ TBase::reserve(CountOnStack);
+ }
+ TBase::assign(count, val);
+ }
+
+ TStackVec(const TStackVec& src)
+ : TStackVec(src.begin(), src.end())
+ {
+ }
+
+ template <class A>
+ TStackVec(const TVector<T, A>& src)
+ : TStackVec(src.begin(), src.end())
+ {
+ }
+
+ TStackVec(std::initializer_list<T> il, const TAllocator& alloc = TAllocator())
+ : TStackVec(il.begin(), il.end(), alloc)
+ {
+ }
+
+ template <class TIter>
+ TStackVec(TIter first, TIter last, const TAllocator& alloc = TAllocator())
+ : TBase(alloc)
+ {
+ // NB(eeight) Since we want to call 'reserve' here, we cannot just delegate to TVector ctor.
+ // The best way to insert values afterwards is to call TVector::insert. However there is a caveat.
+ // In order to call this ctor of TVector, T needs to be just move-constructible. Insert however
+ // requires T to be move-assignable.
+ TBase::reserve(CountOnStack);
+ if constexpr (std::is_move_assignable_v<T>) {
+ // Fast path
+ TBase::insert(TBase::end(), first, last);
+ } else {
+ // Slow path.
+ for (; first != last; ++first) {
+ TBase::push_back(*first);
+ }
+ }
+ }
+
+public:
+ void swap(TStackVec&) = delete;
+ void shrink_to_fit() = delete;
+
+ TStackVec& operator=(const TStackVec& src) {
+ TBase::assign(src.begin(), src.end());
+ return *this;
+ }
+
+ template <class A>
+ TStackVec& operator=(const TVector<T, A>& src) {
+ TBase::assign(src.begin(), src.end());
+ return *this;
+ }
+
+ TStackVec& operator=(std::initializer_list<T> il) {
+ TBase::assign(il.begin(), il.end());
+ return *this;
+ }
+};
+
+template <typename T, size_t CountOnStack, class Alloc>
+class TSerializer<TStackVec<T, CountOnStack, true, Alloc>>: public TVectorSerializer<TStackVec<T, CountOnStack, true, Alloc>> {
+};
+
+template <typename T, size_t CountOnStack, class Alloc>
+class TSerializer<TStackVec<T, CountOnStack, false, Alloc>> {
+public:
+ static void Save(IOutputStream* rh, const TStackVec<T, CountOnStack, false, Alloc>& v) {
+ if constexpr (CountOnStack < 256) {
+ ::Save(rh, (ui8)v.size());
+ } else {
+ ::Save(rh, v.size());
+ }
+ ::SaveArray(rh, v.data(), v.size());
+ }
+
+ static void Load(IInputStream* rh, TStackVec<T, CountOnStack, false, Alloc>& v) {
+ std::conditional_t<CountOnStack < 256, ui8, size_t> size;
+ ::Load(rh, size);
+ v.resize(size);
+ ::LoadPodArray(rh, v.data(), v.size());
+ }
+};
diff --git a/library/cpp/containers/stack_vector/stack_vec_ut.cpp b/library/cpp/containers/stack_vector/stack_vec_ut.cpp
new file mode 100644
index 0000000000..19f9677781
--- /dev/null
+++ b/library/cpp/containers/stack_vector/stack_vec_ut.cpp
@@ -0,0 +1,144 @@
+#include "stack_vec.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+namespace {
+ struct TNotCopyAssignable {
+ const int Value;
+ };
+
+ static_assert(std::is_copy_constructible_v<TNotCopyAssignable>);
+ static_assert(!std::is_copy_assignable_v<TNotCopyAssignable>);
+
+ template <class T, size_t JunkPayloadSize>
+ struct TThickAlloc: public std::allocator<T> {
+ template <class U>
+ struct rebind {
+ using other = TThickAlloc<U, JunkPayloadSize>;
+ };
+
+ char Junk[JunkPayloadSize]{sizeof(T)};
+ };
+
+ template <class T>
+ struct TStatefulAlloc: public std::allocator<T> {
+ using TBase = std::allocator<T>;
+
+ template <class U>
+ struct rebind {
+ using other = TStatefulAlloc<U>;
+ };
+
+ TStatefulAlloc(size_t* allocCount)
+ : AllocCount(allocCount)
+ {}
+
+ size_t* AllocCount;
+
+ T* allocate(size_t n)
+ {
+ *AllocCount += 1;
+ return TBase::allocate(n);
+ }
+ };
+}
+
+Y_UNIT_TEST_SUITE(TStackBasedVectorTest) {
+ Y_UNIT_TEST(TestCreateEmpty) {
+ TStackVec<int> ints;
+ UNIT_ASSERT_EQUAL(ints.size(), 0);
+ }
+
+ Y_UNIT_TEST(TestCreateNonEmpty) {
+ TStackVec<int> ints(5);
+ UNIT_ASSERT_EQUAL(ints.size(), 5);
+
+ for (size_t i = 0; i < ints.size(); ++i) {
+ UNIT_ASSERT_EQUAL(ints[i], 0);
+ }
+ }
+
+ Y_UNIT_TEST(TestReallyOnStack) {
+ const TStackVec<int> vec(5);
+
+ UNIT_ASSERT(
+ (const char*)&vec <= (const char*)&vec[0] &&
+ (const char*)&vec[0] <= (const char*)&vec + sizeof(vec)
+ );
+ }
+
+ Y_UNIT_TEST(TestFallback) {
+ TSmallVec<int> ints;
+ for (int i = 0; i < 14; ++i) {
+ ints.push_back(i);
+ }
+
+ for (size_t i = 0; i < ints.size(); ++i) {
+ UNIT_ASSERT_EQUAL(ints[i], (int)i);
+ }
+
+ for (int i = 14; i < 20; ++i) {
+ ints.push_back(i);
+ }
+
+ for (size_t i = 0; i < ints.size(); ++i) {
+ UNIT_ASSERT_EQUAL(ints[i], (int)i);
+ }
+
+ TSmallVec<int> ints2 = ints;
+
+ for (size_t i = 0; i < ints2.size(); ++i) {
+ UNIT_ASSERT_EQUAL(ints2[i], (int)i);
+ }
+
+ TSmallVec<int> ints3;
+ ints3 = ints2;
+
+ for (size_t i = 0; i < ints3.size(); ++i) {
+ UNIT_ASSERT_EQUAL(ints3[i], (int)i);
+ }
+ }
+
+ Y_UNIT_TEST(TestCappedSize) {
+ TStackVec<int, 8, false> ints;
+ ints.push_back(1);
+ ints.push_back(2);
+
+ auto intsCopy = ints;
+ UNIT_ASSERT_VALUES_EQUAL(intsCopy.capacity(), 8);
+
+ for (int i = 2; i != 8; ++i) {
+ intsCopy.push_back(i);
+ }
+ // Just verify that the program did not crash.
+ }
+
+ Y_UNIT_TEST(TestCappedSizeWithNotCopyAssignable) {
+ TStackVec<TNotCopyAssignable, 8, false> values;
+ values.push_back({1});
+ values.push_back({2});
+
+ auto valuesCopy = values;
+ UNIT_ASSERT_VALUES_EQUAL(valuesCopy.capacity(), 8);
+
+ for (int i = 2; i != 8; ++i) {
+ valuesCopy.push_back({i});
+ }
+ // Just verify that the program did not crash.
+ }
+
+ Y_UNIT_TEST(TestCustomAllocSize) {
+ constexpr size_t n = 16384;
+ using TVec = TStackVec<size_t, 1, true, TThickAlloc<size_t, n>>;
+ UNIT_ASSERT_LT(sizeof(TVec), 1.5 * n);
+ }
+
+ Y_UNIT_TEST(TestStatefulAlloc) {
+ size_t count = 0;
+ TStackVec<size_t, 1, true, TStatefulAlloc<size_t>> vec{{ &count }};
+ for (size_t i = 0; i < 5; ++i) {
+ vec.push_back(1);
+ }
+ UNIT_ASSERT_VALUES_EQUAL(count, 3);
+ }
+}
diff --git a/library/cpp/containers/stack_vector/ut/ya.make b/library/cpp/containers/stack_vector/ut/ya.make
new file mode 100644
index 0000000000..1d70496954
--- /dev/null
+++ b/library/cpp/containers/stack_vector/ut/ya.make
@@ -0,0 +1,11 @@
+UNITTEST()
+
+OWNER(ilnurkh)
+
+SRCDIR(library/cpp/containers/stack_vector)
+
+SRCS(
+ stack_vec_ut.cpp
+)
+
+END()
diff --git a/library/cpp/containers/stack_vector/ya.make b/library/cpp/containers/stack_vector/ya.make
new file mode 100644
index 0000000000..cfb63295ec
--- /dev/null
+++ b/library/cpp/containers/stack_vector/ya.make
@@ -0,0 +1,11 @@
+LIBRARY()
+
+OWNER(ilnurkh)
+
+SRCS(
+ stack_vec.cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/containers/str_map/str_map.cpp b/library/cpp/containers/str_map/str_map.cpp
new file mode 100644
index 0000000000..58c65babda
--- /dev/null
+++ b/library/cpp/containers/str_map/str_map.cpp
@@ -0,0 +1 @@
+#include "str_map.h"
diff --git a/library/cpp/containers/str_map/str_map.h b/library/cpp/containers/str_map/str_map.h
new file mode 100644
index 0000000000..31b00d1b99
--- /dev/null
+++ b/library/cpp/containers/str_map/str_map.h
@@ -0,0 +1,205 @@
+#pragma once
+
+#include <util/memory/segmented_string_pool.h>
+#include <util/generic/map.h>
+#include <util/generic/hash.h>
+#include <util/generic/buffer.h>
+#include <util/str_stl.h> // less<> and equal_to<> for const char*
+#include <utility>
+#include <util/generic/noncopyable.h>
+
+template <class T, class HashFcn = THash<const char*>, class EqualTo = TEqualTo<const char*>, class Alloc = std::allocator<const char*>>
+class string_hash;
+
+template <class T, class HashFcn = THash<const char*>, class EqualTo = TEqualTo<const char*>>
+class segmented_string_hash;
+
+template <class Map>
+inline std::pair<typename Map::iterator, bool>
+pool_insert(Map* m, const char* key, const typename Map::mapped_type& data, TBuffer& pool) {
+ std::pair<typename Map::iterator, bool> ins = m->insert(typename Map::value_type(key, data));
+ if (ins.second) { // new?
+ size_t buflen = strlen(key) + 1; // strlen???
+ const char* old_pool = pool.Begin();
+ pool.Append(key, buflen);
+ if (pool.Begin() != old_pool) // repoint?
+ for (typename Map::iterator it = m->begin(); it != m->end(); ++it)
+ if ((*it).first != key)
+ const_cast<const char*&>((*it).first) += (pool.Begin() - old_pool);
+ const_cast<const char*&>((*ins.first).first) = pool.End() - buflen;
+ }
+ return ins;
+}
+
+#define HASH_SIZE_DEFAULT 100
+#define AVERAGEWORD_BUF 10
+
+template <class T, class HashFcn, class EqualTo, class Alloc>
+class string_hash: public THashMap<const char*, T, HashFcn, EqualTo, Alloc> {
+protected:
+ TBuffer pool;
+
+public:
+ using yh = THashMap<const char*, T, HashFcn, EqualTo, Alloc>;
+ using iterator = typename yh::iterator;
+ using const_iterator = typename yh::const_iterator;
+ using mapped_type = typename yh::mapped_type;
+ using size_type = typename yh::size_type;
+ using pool_size_type = typename yh::size_type;
+ string_hash() {
+ pool.Reserve(HASH_SIZE_DEFAULT * AVERAGEWORD_BUF); // reserve here
+ }
+ string_hash(size_type hash_size, pool_size_type pool_size)
+ : THashMap<const char*, T, HashFcn, EqualTo, Alloc>(hash_size)
+ {
+ pool.Reserve(pool_size); // reserve here
+ }
+
+ std::pair<iterator, bool> insert_copy(const char* key, const mapped_type& data) {
+ return ::pool_insert(this, key, data, pool);
+ }
+
+ void clear_hash() {
+ yh::clear();
+ pool.Clear();
+ }
+ pool_size_type pool_size() const {
+ return pool.Size();
+ }
+
+ string_hash(const string_hash& sh)
+ : THashMap<const char*, T, HashFcn, EqualTo, Alloc>()
+ {
+ for (const_iterator i = sh.begin(); i != sh.end(); ++i)
+ insert_copy((*i).first, (*i).second);
+ }
+ /* May be faster?
+ string_hash(const string_hash& sh)
+ : THashMap<const char *, T, HashFcn, EqualTo>(sh)
+ {
+ pool = sh.pool;
+ size_t delta = pool.begin() - sh.pool.begin();
+ for (iterator i = begin(); i != end(); ++i)
+ (const char*&)(*i).first += delta;
+ }
+ */
+ string_hash& operator=(const string_hash& sh) {
+ if (&sh != this) {
+ clear_hash();
+ for (const_iterator i = sh.begin(); i != sh.end(); ++i)
+ insert_copy((*i).first, (*i).second);
+ }
+ return *this;
+ }
+
+ mapped_type& operator[](const char* key) {
+ iterator I = yh::find(key);
+ if (I == yh::end())
+ I = insert_copy(key, mapped_type()).first;
+ return (*I).second;
+ }
+};
+
+template <class C, class T, class HashFcn, class EqualTo>
+class THashWithSegmentedPoolForKeys: protected THashMap<const C*, T, HashFcn, EqualTo>, TNonCopyable {
+protected:
+ segmented_pool<C> pool;
+
+public:
+ using yh = THashMap<const C*, T, HashFcn, EqualTo>;
+ using iterator = typename yh::iterator;
+ using const_iterator = typename yh::const_iterator;
+ using mapped_type = typename yh::mapped_type;
+ using size_type = typename yh::size_type;
+ using key_type = typename yh::key_type;
+ using value_type = typename yh::value_type;
+
+ THashWithSegmentedPoolForKeys(size_type hash_size = HASH_SIZE_DEFAULT, size_t segsize = HASH_SIZE_DEFAULT * AVERAGEWORD_BUF, bool afs = false)
+ : yh(hash_size)
+ , pool(segsize)
+ {
+ if (afs)
+ pool.alloc_first_seg();
+ }
+
+ std::pair<iterator, bool> insert_copy(const C* key, size_t keylen, const mapped_type& data) {
+ std::pair<iterator, bool> ins = this->insert(value_type(key, data));
+ if (ins.second) // new?
+ (const C*&)(*ins.first).first = pool.append(key, keylen);
+ return ins;
+ }
+
+ void clear_hash() {
+ yh::clear();
+ pool.restart();
+ }
+
+ size_t pool_size() const {
+ return pool.size();
+ }
+
+ size_t size() const {
+ return yh::size();
+ }
+
+ bool empty() const {
+ return yh::empty();
+ }
+
+ iterator begin() {
+ return yh::begin();
+ }
+
+ iterator end() {
+ return yh::end();
+ }
+
+ const_iterator begin() const {
+ return yh::begin();
+ }
+
+ const_iterator end() const {
+ return yh::end();
+ }
+
+ iterator find(const key_type& key) {
+ return yh::find(key);
+ }
+
+ const_iterator find(const key_type& key) const {
+ return yh::find(key);
+ }
+
+ const yh& get_THashMap() const {
+ return static_cast<const yh&>(*this);
+ }
+};
+
+template <class T, class HashFcn, class EqualTo>
+class segmented_string_hash: public THashWithSegmentedPoolForKeys<char, T, HashFcn, EqualTo> {
+public:
+ using Base = THashWithSegmentedPoolForKeys<char, T, HashFcn, EqualTo>;
+ using iterator = typename Base::iterator;
+ using const_iterator = typename Base::const_iterator;
+ using mapped_type = typename Base::mapped_type;
+ using size_type = typename Base::size_type;
+ using key_type = typename Base::key_type;
+ using value_type = typename Base::value_type;
+
+public:
+ segmented_string_hash(size_type hash_size = HASH_SIZE_DEFAULT, size_t segsize = HASH_SIZE_DEFAULT * AVERAGEWORD_BUF, bool afs = false)
+ : Base(hash_size, segsize, afs)
+ {
+ }
+
+ std::pair<iterator, bool> insert_copy(const char* key, const mapped_type& data) {
+ return Base::insert_copy(key, strlen(key) + 1, data);
+ }
+
+ mapped_type& operator[](const char* key) {
+ iterator I = Base::find(key);
+ if (I == Base::end())
+ I = insert_copy(key, mapped_type()).first;
+ return (*I).second;
+ }
+};
diff --git a/library/cpp/containers/str_map/ya.make b/library/cpp/containers/str_map/ya.make
new file mode 100644
index 0000000000..b834159cda
--- /dev/null
+++ b/library/cpp/containers/str_map/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(pg)
+
+SRCS(
+ str_map.cpp
+)
+
+END()
diff --git a/library/cpp/containers/top_keeper/README.md b/library/cpp/containers/top_keeper/README.md
new file mode 100644
index 0000000000..f160fb1c01
--- /dev/null
+++ b/library/cpp/containers/top_keeper/README.md
@@ -0,0 +1,26 @@
+TopKeeper - структура данных для поддержания "top M from stream"
+Используется для выборки наибольших / наименьших элементов за один проход (полезно при фильтрации)
+
+Пусть входной поток состоит из N элементов, из которых нужно отфильтровать M с наибольшим значением.
+Алгоритм (для случая top max M):
+1) Выделим вектор размера 2 * M
+2а) Если вектор заполнен меньше, чем наполовину - добавляем очередной элемент, обновляем минимум
+2б) Иначе - сравниваем с текущим минимумом, в случае, если новый больше, добавляем его в вектор, минимум не обновляем, иначе - отбрасываем
+3) Если заполнен - делаем Partition Sort с M-ым элементом в качестве сепаратора
+4) Таким образом в левой половине все значения больше оных в правой, в позиции M стоит ровно M-ый элемент сортированной последовательности
+5) Удаляем элементы из правой половины
+
+Трудоёмкость:
+На M добавлений происходит 1 PartitionSort (усреднённая оценка трудоёмкости - О(M)) и удаление M элементов. Таким образом достигается О(1) операций в среднем на 1 добавление. Для алгоритма TLimitedHeap (library/cpp/containers/limited_heap) - эта оценка О(log (M))
+
+Тесты:
+На случайных потоках данных количество сравнений у TopKeeper и LimitedHeap одинаково (происходит потому что минимум у первого обновляется раз в M добавлений, а у второго - при каждом добавлении). Худший случай LimitedHeap - сортированная последовательность (добавляем каждый элемент), на таком потоке для 2 000 000 000 int TopKeeper выигрывает во много раз.
+
+Границы применимости:
+Применять стоит всегда вместо LimitedHeap (т.к. всегда не хуже, а в худшем случае - лучше)
+Ограничение - не поддерживает сценарий использования "чередующиеся добавления / извлечения элементов" (слишком часто будут происходить Partiotion Sortы)
+Для этого, когда добавление элементов закончено, должен вызываться метод Finalize(). Для упрощения использования добавлен автоматический Finalize() на GetNext() / Pop(). Тем не менее явный вызов Finalize() по-прежнему возможен - так можно контроллировать момент выполнения трудоёмкой операции NthElement(). После того, как все элементы извлечены TopKeeper можно переиспользовать (для этого же служит метод Reset()).
+В ситуации когда нужны чередующиеся добавления / извлечения - используйте LimitedHeap
+
+Примеры использования:
+library/cpp/containers/top_keeper/ut
diff --git a/library/cpp/containers/top_keeper/top_keeper.cpp b/library/cpp/containers/top_keeper/top_keeper.cpp
new file mode 100644
index 0000000000..29544bf227
--- /dev/null
+++ b/library/cpp/containers/top_keeper/top_keeper.cpp
@@ -0,0 +1 @@
+#include "top_keeper.h"
diff --git a/library/cpp/containers/top_keeper/top_keeper.h b/library/cpp/containers/top_keeper/top_keeper.h
new file mode 100644
index 0000000000..2f282b5a9e
--- /dev/null
+++ b/library/cpp/containers/top_keeper/top_keeper.h
@@ -0,0 +1,256 @@
+#pragma once
+
+#include <util/generic/vector.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/maybe.h>
+#include <util/str_stl.h>
+
+template <class T, class TComparator = TGreater<T>, bool sort = true, class Alloc = std::allocator<T>>
+class TTopKeeper {
+private:
+ class TVectorWithMin {
+ private:
+ TVector<T, Alloc> Internal;
+ size_t HalfMaxSize;
+ TComparator Comparer;
+ size_t MinElementIndex;
+
+ private:
+ void Reserve() {
+ Internal.reserve(2 * HalfMaxSize);
+ }
+
+ template <class UT>
+ bool Insert(UT&& value) noexcept {
+ if (Y_UNLIKELY(0 == HalfMaxSize)) {
+ return false;
+ }
+
+ if (Internal.size() < HalfMaxSize) {
+ if (Internal.empty() || Comparer(Internal[MinElementIndex], value)) {
+ MinElementIndex = Internal.size();
+ Internal.push_back(std::forward<UT>(value));
+ return true;
+ }
+ } else if (!Comparer(value, Internal[MinElementIndex])) {
+ return false;
+ }
+
+ Internal.push_back(std::forward<UT>(value));
+
+ if (Internal.size() == (HalfMaxSize << 1)) {
+ Partition();
+ }
+
+ return true;
+ }
+
+ public:
+ using value_type = T;
+
+ TVectorWithMin(const size_t halfMaxSize, const TComparator& comp)
+ : HalfMaxSize(halfMaxSize)
+ , Comparer(comp)
+ {
+ Reserve();
+ }
+
+ template <class TAllocParam>
+ TVectorWithMin(const size_t halfMaxSize, const TComparator& comp, TAllocParam&& param)
+ : Internal(std::forward<TAllocParam>(param))
+ , HalfMaxSize(halfMaxSize)
+ , Comparer(comp)
+ {
+ Reserve();
+ }
+
+ void SortAccending() {
+ Sort(Internal.begin(), Internal.end(), Comparer);
+ }
+
+ void Partition() {
+ if (Y_UNLIKELY(HalfMaxSize == 0)) {
+ return;
+ }
+ if (Y_LIKELY(Internal.size() >= HalfMaxSize)) {
+ NthElement(Internal.begin(), Internal.begin() + HalfMaxSize - 1, Internal.end(), Comparer);
+ Internal.erase(Internal.begin() + HalfMaxSize, Internal.end());
+
+ //we should update MinElementIndex cause we just altered Internal
+ MinElementIndex = HalfMaxSize - 1;
+ }
+ }
+
+ bool Push(const T& value) {
+ return Insert(value);
+ }
+
+ bool Push(T&& value) {
+ return Insert(std::move(value));
+ }
+
+ template <class... TArgs>
+ bool Emplace(TArgs&&... args) {
+ return Insert(T(std::forward<TArgs>(args)...)); // TODO: make it "real" emplace, not that fake one
+ }
+
+ void SetMaxSize(size_t newHalfMaxSize) {
+ HalfMaxSize = newHalfMaxSize;
+ Reserve();
+ Partition();
+ }
+
+ size_t GetSize() const {
+ return Internal.size();
+ }
+
+ const auto& GetInternal() const {
+ return Internal;
+ }
+
+ auto Extract() {
+ using std::swap;
+
+ decltype(Internal) values;
+ swap(Internal, values);
+ Reset();
+ return values;
+ }
+
+ const T& Back() const {
+ return Internal.back();
+ }
+
+ void Pop() {
+ Internal.pop_back();
+ }
+
+ void Reset() {
+ Internal.clear();
+ //MinElementIndex will reset itself when we start adding new values
+ }
+ };
+
+ void CheckNotFinalized() {
+ Y_ENSURE(!Finalized, "Cannot insert after finalizing (Pop() / GetNext() / Finalize())! "
+ "Use TLimitedHeap for this scenario");
+ }
+
+ size_t MaxSize;
+ const TComparator Comparer;
+ TVectorWithMin Internal;
+ bool Finalized;
+
+public:
+ TTopKeeper()
+ : MaxSize(0)
+ , Comparer()
+ , Internal(0, Comparer)
+ , Finalized(false)
+ {
+ }
+
+ TTopKeeper(size_t maxSize, const TComparator& comp = TComparator())
+ : MaxSize(maxSize)
+ , Comparer(comp)
+ , Internal(maxSize, comp)
+ , Finalized(false)
+ {
+ }
+
+ template <class TAllocParam>
+ TTopKeeper(size_t maxSize, const TComparator& comp, TAllocParam&& param)
+ : MaxSize(maxSize)
+ , Comparer(comp)
+ , Internal(maxSize, comp, std::forward<TAllocParam>(param))
+ , Finalized(false)
+ {
+ }
+
+ void Finalize() {
+ if (Y_LIKELY(Finalized)) {
+ return;
+ }
+ Internal.Partition();
+ if (sort) {
+ Internal.SortAccending();
+ }
+ Finalized = true;
+ }
+
+ const T& GetNext() {
+ Y_ENSURE(!IsEmpty(), "Trying GetNext from empty heap!");
+ Finalize();
+ return Internal.Back();
+ }
+
+ void Pop() {
+ Y_ENSURE(!IsEmpty(), "Trying Pop from empty heap!");
+ Finalize();
+ Internal.Pop();
+ if (IsEmpty()) {
+ Reset();
+ }
+ }
+
+ T ExtractOne() {
+ Y_ENSURE(!IsEmpty(), "Trying ExtractOne from empty heap!");
+ Finalize();
+ auto value = std::move(Internal.Back());
+ Internal.Pop();
+ if (IsEmpty()) {
+ Reset();
+ }
+ return value;
+ }
+
+ auto Extract() {
+ Finalize();
+ return Internal.Extract();
+ }
+
+ bool Insert(const T& value) {
+ CheckNotFinalized();
+ return Internal.Push(value);
+ }
+
+ bool Insert(T&& value) {
+ CheckNotFinalized();
+ return Internal.Push(std::move(value));
+ }
+
+ template <class... TArgs>
+ bool Emplace(TArgs&&... args) {
+ CheckNotFinalized();
+ return Internal.Emplace(std::forward<TArgs>(args)...);
+ }
+
+ const auto& GetInternal() {
+ Finalize();
+ return Internal.GetInternal();
+ }
+
+ bool IsEmpty() const {
+ return Internal.GetSize() == 0;
+ }
+
+ size_t GetSize() const {
+ return Min(Internal.GetSize(), MaxSize);
+ }
+
+ size_t GetMaxSize() const {
+ return MaxSize;
+ }
+
+ void SetMaxSize(size_t newMaxSize) {
+ Y_ENSURE(!Finalized, "Cannot resize after finalizing (Pop() / GetNext() / Finalize())! "
+ "Use TLimitedHeap for this scenario");
+ MaxSize = newMaxSize;
+ Internal.SetMaxSize(newMaxSize);
+ }
+
+ void Reset() {
+ Internal.Reset();
+ Finalized = false;
+ }
+};
diff --git a/library/cpp/containers/top_keeper/top_keeper/README.md b/library/cpp/containers/top_keeper/top_keeper/README.md
new file mode 100644
index 0000000000..f160fb1c01
--- /dev/null
+++ b/library/cpp/containers/top_keeper/top_keeper/README.md
@@ -0,0 +1,26 @@
+TopKeeper - структура данных для поддержания "top M from stream"
+Используется для выборки наибольших / наименьших элементов за один проход (полезно при фильтрации)
+
+Пусть входной поток состоит из N элементов, из которых нужно отфильтровать M с наибольшим значением.
+Алгоритм (для случая top max M):
+1) Выделим вектор размера 2 * M
+2а) Если вектор заполнен меньше, чем наполовину - добавляем очередной элемент, обновляем минимум
+2б) Иначе - сравниваем с текущим минимумом, в случае, если новый больше, добавляем его в вектор, минимум не обновляем, иначе - отбрасываем
+3) Если заполнен - делаем Partition Sort с M-ым элементом в качестве сепаратора
+4) Таким образом в левой половине все значения больше оных в правой, в позиции M стоит ровно M-ый элемент сортированной последовательности
+5) Удаляем элементы из правой половины
+
+Трудоёмкость:
+На M добавлений происходит 1 PartitionSort (усреднённая оценка трудоёмкости - О(M)) и удаление M элементов. Таким образом достигается О(1) операций в среднем на 1 добавление. Для алгоритма TLimitedHeap (library/cpp/containers/limited_heap) - эта оценка О(log (M))
+
+Тесты:
+На случайных потоках данных количество сравнений у TopKeeper и LimitedHeap одинаково (происходит потому что минимум у первого обновляется раз в M добавлений, а у второго - при каждом добавлении). Худший случай LimitedHeap - сортированная последовательность (добавляем каждый элемент), на таком потоке для 2 000 000 000 int TopKeeper выигрывает во много раз.
+
+Границы применимости:
+Применять стоит всегда вместо LimitedHeap (т.к. всегда не хуже, а в худшем случае - лучше)
+Ограничение - не поддерживает сценарий использования "чередующиеся добавления / извлечения элементов" (слишком часто будут происходить Partiotion Sortы)
+Для этого, когда добавление элементов закончено, должен вызываться метод Finalize(). Для упрощения использования добавлен автоматический Finalize() на GetNext() / Pop(). Тем не менее явный вызов Finalize() по-прежнему возможен - так можно контроллировать момент выполнения трудоёмкой операции NthElement(). После того, как все элементы извлечены TopKeeper можно переиспользовать (для этого же служит метод Reset()).
+В ситуации когда нужны чередующиеся добавления / извлечения - используйте LimitedHeap
+
+Примеры использования:
+library/cpp/containers/top_keeper/ut
diff --git a/library/cpp/containers/top_keeper/top_keeper/top_keeper.cpp b/library/cpp/containers/top_keeper/top_keeper/top_keeper.cpp
new file mode 100644
index 0000000000..29544bf227
--- /dev/null
+++ b/library/cpp/containers/top_keeper/top_keeper/top_keeper.cpp
@@ -0,0 +1 @@
+#include "top_keeper.h"
diff --git a/library/cpp/containers/top_keeper/top_keeper/top_keeper.h b/library/cpp/containers/top_keeper/top_keeper/top_keeper.h
new file mode 100644
index 0000000000..2f282b5a9e
--- /dev/null
+++ b/library/cpp/containers/top_keeper/top_keeper/top_keeper.h
@@ -0,0 +1,256 @@
+#pragma once
+
+#include <util/generic/vector.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/maybe.h>
+#include <util/str_stl.h>
+
+template <class T, class TComparator = TGreater<T>, bool sort = true, class Alloc = std::allocator<T>>
+class TTopKeeper {
+private:
+ class TVectorWithMin {
+ private:
+ TVector<T, Alloc> Internal;
+ size_t HalfMaxSize;
+ TComparator Comparer;
+ size_t MinElementIndex;
+
+ private:
+ void Reserve() {
+ Internal.reserve(2 * HalfMaxSize);
+ }
+
+ template <class UT>
+ bool Insert(UT&& value) noexcept {
+ if (Y_UNLIKELY(0 == HalfMaxSize)) {
+ return false;
+ }
+
+ if (Internal.size() < HalfMaxSize) {
+ if (Internal.empty() || Comparer(Internal[MinElementIndex], value)) {
+ MinElementIndex = Internal.size();
+ Internal.push_back(std::forward<UT>(value));
+ return true;
+ }
+ } else if (!Comparer(value, Internal[MinElementIndex])) {
+ return false;
+ }
+
+ Internal.push_back(std::forward<UT>(value));
+
+ if (Internal.size() == (HalfMaxSize << 1)) {
+ Partition();
+ }
+
+ return true;
+ }
+
+ public:
+ using value_type = T;
+
+ TVectorWithMin(const size_t halfMaxSize, const TComparator& comp)
+ : HalfMaxSize(halfMaxSize)
+ , Comparer(comp)
+ {
+ Reserve();
+ }
+
+ template <class TAllocParam>
+ TVectorWithMin(const size_t halfMaxSize, const TComparator& comp, TAllocParam&& param)
+ : Internal(std::forward<TAllocParam>(param))
+ , HalfMaxSize(halfMaxSize)
+ , Comparer(comp)
+ {
+ Reserve();
+ }
+
+ void SortAccending() {
+ Sort(Internal.begin(), Internal.end(), Comparer);
+ }
+
+ void Partition() {
+ if (Y_UNLIKELY(HalfMaxSize == 0)) {
+ return;
+ }
+ if (Y_LIKELY(Internal.size() >= HalfMaxSize)) {
+ NthElement(Internal.begin(), Internal.begin() + HalfMaxSize - 1, Internal.end(), Comparer);
+ Internal.erase(Internal.begin() + HalfMaxSize, Internal.end());
+
+ //we should update MinElementIndex cause we just altered Internal
+ MinElementIndex = HalfMaxSize - 1;
+ }
+ }
+
+ bool Push(const T& value) {
+ return Insert(value);
+ }
+
+ bool Push(T&& value) {
+ return Insert(std::move(value));
+ }
+
+ template <class... TArgs>
+ bool Emplace(TArgs&&... args) {
+ return Insert(T(std::forward<TArgs>(args)...)); // TODO: make it "real" emplace, not that fake one
+ }
+
+ void SetMaxSize(size_t newHalfMaxSize) {
+ HalfMaxSize = newHalfMaxSize;
+ Reserve();
+ Partition();
+ }
+
+ size_t GetSize() const {
+ return Internal.size();
+ }
+
+ const auto& GetInternal() const {
+ return Internal;
+ }
+
+ auto Extract() {
+ using std::swap;
+
+ decltype(Internal) values;
+ swap(Internal, values);
+ Reset();
+ return values;
+ }
+
+ const T& Back() const {
+ return Internal.back();
+ }
+
+ void Pop() {
+ Internal.pop_back();
+ }
+
+ void Reset() {
+ Internal.clear();
+ //MinElementIndex will reset itself when we start adding new values
+ }
+ };
+
+ void CheckNotFinalized() {
+ Y_ENSURE(!Finalized, "Cannot insert after finalizing (Pop() / GetNext() / Finalize())! "
+ "Use TLimitedHeap for this scenario");
+ }
+
+ size_t MaxSize;
+ const TComparator Comparer;
+ TVectorWithMin Internal;
+ bool Finalized;
+
+public:
+ TTopKeeper()
+ : MaxSize(0)
+ , Comparer()
+ , Internal(0, Comparer)
+ , Finalized(false)
+ {
+ }
+
+ TTopKeeper(size_t maxSize, const TComparator& comp = TComparator())
+ : MaxSize(maxSize)
+ , Comparer(comp)
+ , Internal(maxSize, comp)
+ , Finalized(false)
+ {
+ }
+
+ template <class TAllocParam>
+ TTopKeeper(size_t maxSize, const TComparator& comp, TAllocParam&& param)
+ : MaxSize(maxSize)
+ , Comparer(comp)
+ , Internal(maxSize, comp, std::forward<TAllocParam>(param))
+ , Finalized(false)
+ {
+ }
+
+ void Finalize() {
+ if (Y_LIKELY(Finalized)) {
+ return;
+ }
+ Internal.Partition();
+ if (sort) {
+ Internal.SortAccending();
+ }
+ Finalized = true;
+ }
+
+ const T& GetNext() {
+ Y_ENSURE(!IsEmpty(), "Trying GetNext from empty heap!");
+ Finalize();
+ return Internal.Back();
+ }
+
+ void Pop() {
+ Y_ENSURE(!IsEmpty(), "Trying Pop from empty heap!");
+ Finalize();
+ Internal.Pop();
+ if (IsEmpty()) {
+ Reset();
+ }
+ }
+
+ T ExtractOne() {
+ Y_ENSURE(!IsEmpty(), "Trying ExtractOne from empty heap!");
+ Finalize();
+ auto value = std::move(Internal.Back());
+ Internal.Pop();
+ if (IsEmpty()) {
+ Reset();
+ }
+ return value;
+ }
+
+ auto Extract() {
+ Finalize();
+ return Internal.Extract();
+ }
+
+ bool Insert(const T& value) {
+ CheckNotFinalized();
+ return Internal.Push(value);
+ }
+
+ bool Insert(T&& value) {
+ CheckNotFinalized();
+ return Internal.Push(std::move(value));
+ }
+
+ template <class... TArgs>
+ bool Emplace(TArgs&&... args) {
+ CheckNotFinalized();
+ return Internal.Emplace(std::forward<TArgs>(args)...);
+ }
+
+ const auto& GetInternal() {
+ Finalize();
+ return Internal.GetInternal();
+ }
+
+ bool IsEmpty() const {
+ return Internal.GetSize() == 0;
+ }
+
+ size_t GetSize() const {
+ return Min(Internal.GetSize(), MaxSize);
+ }
+
+ size_t GetMaxSize() const {
+ return MaxSize;
+ }
+
+ void SetMaxSize(size_t newMaxSize) {
+ Y_ENSURE(!Finalized, "Cannot resize after finalizing (Pop() / GetNext() / Finalize())! "
+ "Use TLimitedHeap for this scenario");
+ MaxSize = newMaxSize;
+ Internal.SetMaxSize(newMaxSize);
+ }
+
+ void Reset() {
+ Internal.Reset();
+ Finalized = false;
+ }
+};
diff --git a/library/cpp/containers/top_keeper/top_keeper/ut/top_keeper_ut.cpp b/library/cpp/containers/top_keeper/top_keeper/ut/top_keeper_ut.cpp
new file mode 100644
index 0000000000..a938279025
--- /dev/null
+++ b/library/cpp/containers/top_keeper/top_keeper/ut/top_keeper_ut.cpp
@@ -0,0 +1,222 @@
+#include <library/cpp/containers/limited_heap/limited_heap.h>
+#include <library/cpp/containers/top_keeper/top_keeper.h>
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/random/random.h>
+
+static ui32 seed = 3;
+ui32 Rnd() {
+ seed = seed * 5 + 1;
+ return seed;
+}
+
+/*
+ * Tests for TTopKeeper
+ */
+Y_UNIT_TEST_SUITE(TTopKeeperTest) {
+ // Tests correctness on usual examples
+ Y_UNIT_TEST(CorrectnessTest) {
+ int m = 20000;
+
+ TLimitedHeap<std::pair<int, int>> h1(m);
+ TTopKeeper<std::pair<int, int>> h2(m);
+
+ int n = 20000000;
+ while (n--) {
+ int r = int(Rnd());
+
+ h1.Insert({r, -r});
+ h2.Emplace(r, -r);
+ }
+
+ h2.Finalize();
+
+ UNIT_ASSERT_EQUAL(h1.GetSize(), h2.GetSize());
+
+ while (!h1.IsEmpty()) {
+ UNIT_ASSERT_EQUAL(h1.GetMin(), h2.GetNext());
+ h1.PopMin();
+ h2.Pop();
+ }
+ }
+
+ // Tests on zero-size correctness
+ Y_UNIT_TEST(ZeroSizeCorrectnes) {
+ TTopKeeper<int> h(0);
+ for (int i = 0; i < 100; ++i) {
+ h.Insert(i % 10 + i / 10);
+ }
+ h.Finalize();
+ UNIT_ASSERT(h.IsEmpty());
+ }
+
+ // Tests SetMaxSize behaviour
+ Y_UNIT_TEST(SetMaxSizeTest) {
+ int m = 20000;
+ TLimitedHeap<int> h1(m);
+ TTopKeeper<int> h2(m);
+
+ int n = 20000000;
+ while (n--) {
+ int r = int(Rnd());
+
+ h1.Insert(r);
+ h2.Insert(r);
+ }
+
+ h1.SetMaxSize(m / 3);
+ h2.SetMaxSize(m / 3);
+ h2.Finalize();
+
+ UNIT_ASSERT_EQUAL(h1.GetSize(), h2.GetSize());
+
+ while (!h1.IsEmpty()) {
+ UNIT_ASSERT_EQUAL(h1.GetMin(), h2.GetNext());
+ h1.PopMin();
+ h2.Pop();
+ }
+ }
+
+ // Tests reuse behavior
+ Y_UNIT_TEST(ReuseTest) {
+ int m = 20000;
+ TLimitedHeap<int> h1(m);
+ TTopKeeper<int> h2(m);
+
+ int n = 20000000;
+ while (n--) {
+ int r = int(Rnd());
+
+ h1.Insert(r);
+ h2.Insert(r);
+ }
+
+ UNIT_ASSERT_EQUAL(h1.GetSize(), h2.GetSize());
+
+ while (!h1.IsEmpty()) {
+ UNIT_ASSERT_EQUAL(h1.GetMin(), h2.GetNext());
+ h1.PopMin();
+ h2.Pop();
+ }
+
+ n = 20000000;
+ while (n--) {
+ int r = int(Rnd());
+
+ h1.Insert(r);
+ h2.Insert(r);
+ }
+
+ UNIT_ASSERT_EQUAL(h1.GetSize(), h2.GetSize());
+
+ while (!h1.IsEmpty()) {
+ UNIT_ASSERT_EQUAL(h1.GetMin(), h2.GetNext());
+ h1.PopMin();
+ h2.Pop();
+ }
+ }
+
+ // Tests reset behavior
+ Y_UNIT_TEST(ResetTest) {
+ int m = 20000;
+ TLimitedHeap<int> h1(m);
+ TTopKeeper<int> h2(m);
+
+ int n = 20000000;
+ while (n--) {
+ int r = int(Rnd());
+
+ h1.Insert(r);
+ h2.Insert(r);
+ }
+
+ UNIT_ASSERT_EQUAL(h1.GetSize(), h2.GetSize());
+
+ for (int i = 0; i < m / 2; ++i) {
+ UNIT_ASSERT_EQUAL(h1.GetMin(), h2.GetNext());
+ h1.PopMin();
+ h2.Pop();
+ }
+
+ h2.Reset();
+ while (!h1.IsEmpty()) {
+ h1.PopMin();
+ }
+
+ n = 20000000;
+ while (n--) {
+ int r = int(Rnd());
+
+ h1.Insert(r);
+ h2.Insert(r);
+ }
+
+ UNIT_ASSERT_EQUAL(h1.GetSize(), h2.GetSize());
+
+ while (!h1.IsEmpty()) {
+ UNIT_ASSERT_EQUAL(h1.GetMin(), h2.GetNext());
+ h1.PopMin();
+ h2.Pop();
+ }
+ }
+
+ Y_UNIT_TEST(PreRegressionTest) {
+ typedef std::pair<float, unsigned int> TElementType;
+
+ const size_t randomTriesCount = 128;
+ for (size_t i1 = 0; i1 < randomTriesCount; ++i1) {
+ const size_t desiredElementsCount = RandomNumber<size_t>(5) + 1;
+ TLimitedHeap<TElementType> h1(desiredElementsCount);
+ TTopKeeper<TElementType> h2(desiredElementsCount);
+
+ const size_t elementsToInsert = RandomNumber<size_t>(10) + desiredElementsCount;
+ UNIT_ASSERT_C(desiredElementsCount <= elementsToInsert, "Test internal invariant is broken");
+ for (size_t i2 = 0; i2 < elementsToInsert; ++i2) {
+ const auto f = RandomNumber<float>();
+ const auto id = RandomNumber<unsigned int>();
+
+ h1.Insert(TElementType(f, id));
+ h2.Insert(TElementType(f, id));
+ }
+
+ h2.Finalize();
+
+ //we inserted enough elements to guarantee this outcome
+ UNIT_ASSERT_EQUAL(h1.GetSize(), desiredElementsCount);
+ UNIT_ASSERT_EQUAL(h2.GetSize(), desiredElementsCount);
+
+ const auto n = h2.GetSize();
+ for (size_t i3 = 0; i3 < n; ++i3) {
+ UNIT_ASSERT_EQUAL(h1.GetMin(), h2.GetNext());
+ h1.PopMin();
+ h2.Pop();
+ }
+ }
+ }
+
+ Y_UNIT_TEST(CopyKeeperRegressionCase) {
+ using TKeeper = TTopKeeper<float>;
+ TVector<TKeeper> v(2, TKeeper(200));
+ auto& k = v[1];
+ for (size_t i = 0; i < 100; ++i) {
+ k.Insert(RandomNumber<float>());
+ }
+ k.Finalize();
+ }
+
+ Y_UNIT_TEST(ExtractTest) {
+ TTopKeeper<size_t> keeper(100);
+ for (size_t i = 0; i < 100; ++i) {
+ keeper.Insert(i);
+ }
+
+ auto values = keeper.Extract();
+ UNIT_ASSERT_EQUAL(values.size(), 100);
+ Sort(values);
+
+ for (size_t i = 0; i < 100; ++i) {
+ UNIT_ASSERT_EQUAL(values[i], i);
+ }
+
+ UNIT_ASSERT(keeper.IsEmpty());
+ }
+}
diff --git a/library/cpp/containers/top_keeper/top_keeper/ut/ya.make b/library/cpp/containers/top_keeper/top_keeper/ut/ya.make
new file mode 100644
index 0000000000..8553389e17
--- /dev/null
+++ b/library/cpp/containers/top_keeper/top_keeper/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/containers/top_keeper)
+
+OWNER(
+ mbusel
+ rmplstiltskin
+)
+
+SRCS(
+ top_keeper_ut.cpp
+)
+
+END()
diff --git a/library/cpp/containers/top_keeper/top_keeper/ya.make b/library/cpp/containers/top_keeper/top_keeper/ya.make
new file mode 100644
index 0000000000..79be94ae2b
--- /dev/null
+++ b/library/cpp/containers/top_keeper/top_keeper/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(mbusel)
+
+SRCS(
+ top_keeper.cpp
+)
+
+END()
diff --git a/library/cpp/containers/top_keeper/ut/top_keeper_ut.cpp b/library/cpp/containers/top_keeper/ut/top_keeper_ut.cpp
new file mode 100644
index 0000000000..a938279025
--- /dev/null
+++ b/library/cpp/containers/top_keeper/ut/top_keeper_ut.cpp
@@ -0,0 +1,222 @@
+#include <library/cpp/containers/limited_heap/limited_heap.h>
+#include <library/cpp/containers/top_keeper/top_keeper.h>
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/random/random.h>
+
+static ui32 seed = 3;
+ui32 Rnd() {
+ seed = seed * 5 + 1;
+ return seed;
+}
+
+/*
+ * Tests for TTopKeeper
+ */
+Y_UNIT_TEST_SUITE(TTopKeeperTest) {
+ // Tests correctness on usual examples
+ Y_UNIT_TEST(CorrectnessTest) {
+ int m = 20000;
+
+ TLimitedHeap<std::pair<int, int>> h1(m);
+ TTopKeeper<std::pair<int, int>> h2(m);
+
+ int n = 20000000;
+ while (n--) {
+ int r = int(Rnd());
+
+ h1.Insert({r, -r});
+ h2.Emplace(r, -r);
+ }
+
+ h2.Finalize();
+
+ UNIT_ASSERT_EQUAL(h1.GetSize(), h2.GetSize());
+
+ while (!h1.IsEmpty()) {
+ UNIT_ASSERT_EQUAL(h1.GetMin(), h2.GetNext());
+ h1.PopMin();
+ h2.Pop();
+ }
+ }
+
+ // Tests on zero-size correctness
+ Y_UNIT_TEST(ZeroSizeCorrectnes) {
+ TTopKeeper<int> h(0);
+ for (int i = 0; i < 100; ++i) {
+ h.Insert(i % 10 + i / 10);
+ }
+ h.Finalize();
+ UNIT_ASSERT(h.IsEmpty());
+ }
+
+ // Tests SetMaxSize behaviour
+ Y_UNIT_TEST(SetMaxSizeTest) {
+ int m = 20000;
+ TLimitedHeap<int> h1(m);
+ TTopKeeper<int> h2(m);
+
+ int n = 20000000;
+ while (n--) {
+ int r = int(Rnd());
+
+ h1.Insert(r);
+ h2.Insert(r);
+ }
+
+ h1.SetMaxSize(m / 3);
+ h2.SetMaxSize(m / 3);
+ h2.Finalize();
+
+ UNIT_ASSERT_EQUAL(h1.GetSize(), h2.GetSize());
+
+ while (!h1.IsEmpty()) {
+ UNIT_ASSERT_EQUAL(h1.GetMin(), h2.GetNext());
+ h1.PopMin();
+ h2.Pop();
+ }
+ }
+
+ // Tests reuse behavior
+ Y_UNIT_TEST(ReuseTest) {
+ int m = 20000;
+ TLimitedHeap<int> h1(m);
+ TTopKeeper<int> h2(m);
+
+ int n = 20000000;
+ while (n--) {
+ int r = int(Rnd());
+
+ h1.Insert(r);
+ h2.Insert(r);
+ }
+
+ UNIT_ASSERT_EQUAL(h1.GetSize(), h2.GetSize());
+
+ while (!h1.IsEmpty()) {
+ UNIT_ASSERT_EQUAL(h1.GetMin(), h2.GetNext());
+ h1.PopMin();
+ h2.Pop();
+ }
+
+ n = 20000000;
+ while (n--) {
+ int r = int(Rnd());
+
+ h1.Insert(r);
+ h2.Insert(r);
+ }
+
+ UNIT_ASSERT_EQUAL(h1.GetSize(), h2.GetSize());
+
+ while (!h1.IsEmpty()) {
+ UNIT_ASSERT_EQUAL(h1.GetMin(), h2.GetNext());
+ h1.PopMin();
+ h2.Pop();
+ }
+ }
+
+ // Tests reset behavior
+ Y_UNIT_TEST(ResetTest) {
+ int m = 20000;
+ TLimitedHeap<int> h1(m);
+ TTopKeeper<int> h2(m);
+
+ int n = 20000000;
+ while (n--) {
+ int r = int(Rnd());
+
+ h1.Insert(r);
+ h2.Insert(r);
+ }
+
+ UNIT_ASSERT_EQUAL(h1.GetSize(), h2.GetSize());
+
+ for (int i = 0; i < m / 2; ++i) {
+ UNIT_ASSERT_EQUAL(h1.GetMin(), h2.GetNext());
+ h1.PopMin();
+ h2.Pop();
+ }
+
+ h2.Reset();
+ while (!h1.IsEmpty()) {
+ h1.PopMin();
+ }
+
+ n = 20000000;
+ while (n--) {
+ int r = int(Rnd());
+
+ h1.Insert(r);
+ h2.Insert(r);
+ }
+
+ UNIT_ASSERT_EQUAL(h1.GetSize(), h2.GetSize());
+
+ while (!h1.IsEmpty()) {
+ UNIT_ASSERT_EQUAL(h1.GetMin(), h2.GetNext());
+ h1.PopMin();
+ h2.Pop();
+ }
+ }
+
+ Y_UNIT_TEST(PreRegressionTest) {
+ typedef std::pair<float, unsigned int> TElementType;
+
+ const size_t randomTriesCount = 128;
+ for (size_t i1 = 0; i1 < randomTriesCount; ++i1) {
+ const size_t desiredElementsCount = RandomNumber<size_t>(5) + 1;
+ TLimitedHeap<TElementType> h1(desiredElementsCount);
+ TTopKeeper<TElementType> h2(desiredElementsCount);
+
+ const size_t elementsToInsert = RandomNumber<size_t>(10) + desiredElementsCount;
+ UNIT_ASSERT_C(desiredElementsCount <= elementsToInsert, "Test internal invariant is broken");
+ for (size_t i2 = 0; i2 < elementsToInsert; ++i2) {
+ const auto f = RandomNumber<float>();
+ const auto id = RandomNumber<unsigned int>();
+
+ h1.Insert(TElementType(f, id));
+ h2.Insert(TElementType(f, id));
+ }
+
+ h2.Finalize();
+
+ //we inserted enough elements to guarantee this outcome
+ UNIT_ASSERT_EQUAL(h1.GetSize(), desiredElementsCount);
+ UNIT_ASSERT_EQUAL(h2.GetSize(), desiredElementsCount);
+
+ const auto n = h2.GetSize();
+ for (size_t i3 = 0; i3 < n; ++i3) {
+ UNIT_ASSERT_EQUAL(h1.GetMin(), h2.GetNext());
+ h1.PopMin();
+ h2.Pop();
+ }
+ }
+ }
+
+ Y_UNIT_TEST(CopyKeeperRegressionCase) {
+ using TKeeper = TTopKeeper<float>;
+ TVector<TKeeper> v(2, TKeeper(200));
+ auto& k = v[1];
+ for (size_t i = 0; i < 100; ++i) {
+ k.Insert(RandomNumber<float>());
+ }
+ k.Finalize();
+ }
+
+ Y_UNIT_TEST(ExtractTest) {
+ TTopKeeper<size_t> keeper(100);
+ for (size_t i = 0; i < 100; ++i) {
+ keeper.Insert(i);
+ }
+
+ auto values = keeper.Extract();
+ UNIT_ASSERT_EQUAL(values.size(), 100);
+ Sort(values);
+
+ for (size_t i = 0; i < 100; ++i) {
+ UNIT_ASSERT_EQUAL(values[i], i);
+ }
+
+ UNIT_ASSERT(keeper.IsEmpty());
+ }
+}
diff --git a/library/cpp/containers/top_keeper/ut/ya.make b/library/cpp/containers/top_keeper/ut/ya.make
new file mode 100644
index 0000000000..42cfdd6f13
--- /dev/null
+++ b/library/cpp/containers/top_keeper/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/containers/top_keeper)
+
+OWNER(
+ ilnurkh
+ rmplstiltskin
+)
+
+SRCS(
+ top_keeper_ut.cpp
+)
+
+END()
diff --git a/library/cpp/containers/top_keeper/ya.make b/library/cpp/containers/top_keeper/ya.make
new file mode 100644
index 0000000000..ed206a1df9
--- /dev/null
+++ b/library/cpp/containers/top_keeper/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(ilnurkh)
+
+SRCS(
+ top_keeper.cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
+
+
diff --git a/library/cpp/containers/ya.make b/library/cpp/containers/ya.make
new file mode 100644
index 0000000000..4b1b315e6a
--- /dev/null
+++ b/library/cpp/containers/ya.make
@@ -0,0 +1,71 @@
+RECURSE(
+ 2d_array
+ absl_flat_hash
+ absl_tstring_flat_hash
+ atomizer
+ bitseq
+ bitseq/ut
+ compact_vector
+ compact_vector/ut
+ comptrie
+ comptrie/loader
+ comptrie/loader/ut
+ comptrie/ut
+ comptrie/benchmark
+ concurrent_hash
+ concurrent_hash_set
+ concurrent_hash_set/ut
+ dense_hash
+ dense_hash/dense_hash_benchmark
+ dense_hash/ut
+ dictionary
+ dictionary/ut
+ disjoint_interval_tree
+ disjoint_interval_tree/ut
+ ext_priority_queue
+ ext_priority_queue/ut
+ fast_trie
+ fast_trie/ut
+ flat_hash
+ flat_hash/benchmark
+ flat_hash/lib
+ flat_hash/lib/concepts
+ flat_hash/lib/fuzz
+ flat_hash/lib/ut
+ flat_hash/ut
+ hash_trie
+ heap_dict
+ heap_dict/benchmark
+ heap_dict/ut
+ intrusive_avl_tree
+ intrusive_avl_tree/ut
+ intrusive_hash
+ intrusive_hash/ut
+ intrusive_rb_tree
+ intrusive_rb_tree/fuzz
+ intrusive_rb_tree/ut
+ limited_heap
+ mh_heap
+ mh_heap/ut
+ paged_vector
+ paged_vector/ut
+ rarefied_array
+ ring_buffer
+ safe_vector
+ safe_vector/ut
+ segmented_pool_container
+ sorted_vector
+ sorted_vector/ut
+ spars_ar
+ stack_array
+ stack_array/ut
+ stack_vector
+ str_hash
+ str_map
+ top_keeper
+ top_keeper/ut
+ two_level_hash
+ two_level_hash/ut
+ vp_tree
+ vp_tree/ut
+)
diff --git a/library/cpp/coroutine/engine/callbacks.h b/library/cpp/coroutine/engine/callbacks.h
new file mode 100644
index 0000000000..e81b17344f
--- /dev/null
+++ b/library/cpp/coroutine/engine/callbacks.h
@@ -0,0 +1,18 @@
+#pragma once
+
+class TCont;
+class TContExecutor;
+
+namespace NCoro {
+ class IScheduleCallback {
+ public:
+ virtual void OnSchedule(TContExecutor&, TCont&) = 0;
+ virtual void OnUnschedule(TContExecutor&) = 0;
+ };
+
+ class IEnterPollerCallback {
+ public:
+ virtual void OnEnterPoller() = 0;
+ virtual void OnExitPoller() = 0;
+ };
+}
diff --git a/library/cpp/coroutine/engine/condvar.h b/library/cpp/coroutine/engine/condvar.h
new file mode 100644
index 0000000000..ffceede6fa
--- /dev/null
+++ b/library/cpp/coroutine/engine/condvar.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "events.h"
+#include "mutex.h"
+
+class TContCondVar {
+public:
+ int WaitD(TCont* current, TContMutex* mutex, TInstant deadline) {
+ mutex->UnLock();
+
+ const int ret = WaitQueue_.WaitD(current, deadline);
+
+ if (ret != EWAKEDUP) {
+ return ret;
+ }
+
+ return mutex->LockD(current, deadline);
+ }
+
+ int WaitT(TCont* current, TContMutex* mutex, TDuration timeout) {
+ return WaitD(current, mutex, timeout.ToDeadLine());
+ }
+
+ int WaitI(TCont* current, TContMutex* mutex) {
+ return WaitD(current, mutex, TInstant::Max());
+ }
+
+ void Signal() noexcept {
+ WaitQueue_.Signal();
+ }
+
+ void BroadCast() noexcept {
+ WaitQueue_.BroadCast();
+ }
+
+private:
+ TContWaitQueue WaitQueue_;
+};
diff --git a/library/cpp/coroutine/engine/cont_poller.cpp b/library/cpp/coroutine/engine/cont_poller.cpp
new file mode 100644
index 0000000000..76593d4e9b
--- /dev/null
+++ b/library/cpp/coroutine/engine/cont_poller.cpp
@@ -0,0 +1,70 @@
+#include "cont_poller.h"
+#include "impl.h"
+
+namespace NCoro {
+ namespace {
+ template <class T>
+ int DoExecuteEvent(T* event) noexcept {
+ auto* cont = event->Cont();
+
+ if (cont->Cancelled()) {
+ return ECANCELED;
+ }
+
+ cont->Executor()->ScheduleIoWait(event);
+ cont->Switch();
+
+ if (cont->Cancelled()) {
+ return ECANCELED;
+ }
+
+ return event->Status();
+ }
+ }
+
+ void TContPollEvent::Wake() noexcept {
+ UnLink();
+ Cont()->ReSchedule();
+ }
+
+
+ TInstant TEventWaitQueue::WakeTimedout(TInstant now) noexcept {
+ TIoWait::TIterator it = IoWait_.Begin();
+
+ if (it != IoWait_.End()) {
+ if (it->DeadLine() > now) {
+ return it->DeadLine();
+ }
+
+ do {
+ (it++)->Wake(ETIMEDOUT);
+ } while (it != IoWait_.End() && it->DeadLine() <= now);
+ }
+
+ return now;
+ }
+
+ void TEventWaitQueue::Register(NCoro::TContPollEvent* event) {
+ IoWait_.Insert(event);
+ event->Cont()->Unlink();
+ }
+
+ void TEventWaitQueue::Abort() noexcept {
+ auto visitor = [](TContPollEvent& e) {
+ e.Cont()->Cancel();
+ };
+ IoWait_.ForEach(visitor);
+ }
+}
+
+void TFdEvent::RemoveFromIOWait() noexcept {
+ this->Cont()->Executor()->Poller()->Remove(this);
+}
+
+int ExecuteEvent(TFdEvent* event) noexcept {
+ return NCoro::DoExecuteEvent(event);
+}
+
+int ExecuteEvent(TTimerEvent* event) noexcept {
+ return NCoro::DoExecuteEvent(event);
+}
diff --git a/library/cpp/coroutine/engine/cont_poller.h b/library/cpp/coroutine/engine/cont_poller.h
new file mode 100644
index 0000000000..b638b2df1a
--- /dev/null
+++ b/library/cpp/coroutine/engine/cont_poller.h
@@ -0,0 +1,245 @@
+#pragma once
+
+#include "poller.h"
+#include "sockmap.h"
+
+#include <library/cpp/containers/intrusive_rb_tree/rb_tree.h>
+
+#include <util/datetime/base.h>
+#include <util/memory/pool.h>
+#include <util/memory/smallobj.h>
+#include <util/network/init.h>
+
+#include <cerrno>
+
+
+class TCont;
+class TContExecutor;
+class TFdEvent;
+
+namespace NCoro {
+
+ class IPollEvent;
+
+
+ struct TContPollEventCompare {
+ template <class T>
+ static inline bool Compare(const T& l, const T& r) noexcept {
+ return l.DeadLine() < r.DeadLine() || (l.DeadLine() == r.DeadLine() && &l < &r);
+ }
+ };
+
+
+ class TContPollEvent : public TRbTreeItem<TContPollEvent, TContPollEventCompare> {
+ public:
+ TContPollEvent(TCont* cont, TInstant deadLine) noexcept
+ : Cont_(cont)
+ , DeadLine_(deadLine)
+ {}
+
+ static bool Compare(const TContPollEvent& l, const TContPollEvent& r) noexcept {
+ return l.DeadLine() < r.DeadLine() || (l.DeadLine() == r.DeadLine() && &l < &r);
+ }
+
+ int Status() const noexcept {
+ return Status_;
+ }
+
+ void SetStatus(int status) noexcept {
+ Status_ = status;
+ }
+
+ TCont* Cont() noexcept {
+ return Cont_;
+ }
+
+ TInstant DeadLine() const noexcept {
+ return DeadLine_;
+ }
+
+ void Wake(int status) noexcept {
+ SetStatus(status);
+ Wake();
+ }
+
+ private:
+ void Wake() noexcept;
+
+ private:
+ TCont* Cont_;
+ TInstant DeadLine_;
+ int Status_ = EINPROGRESS;
+ };
+
+
+ class IPollEvent: public TIntrusiveListItem<IPollEvent> {
+ public:
+ IPollEvent(SOCKET fd, ui16 what) noexcept
+ : Fd_(fd)
+ , What_(what)
+ {}
+
+ virtual ~IPollEvent() {}
+
+ SOCKET Fd() const noexcept {
+ return Fd_;
+ }
+
+ int What() const noexcept {
+ return What_;
+ }
+
+ virtual void OnPollEvent(int status) noexcept = 0;
+
+ private:
+ SOCKET Fd_;
+ ui16 What_;
+ };
+
+
+ template <class T>
+ class TBigArray {
+ struct TValue: public T, public TObjectFromPool<TValue> {
+ TValue() {}
+ };
+
+ public:
+ TBigArray()
+ : Pool_(TMemoryPool::TExpGrow::Instance(), TDefaultAllocator::Instance())
+ {}
+
+ T* Get(size_t index) {
+ TRef& ret = Lst_.Get(index);
+ if (!ret) {
+ ret = TRef(new (&Pool_) TValue());
+ }
+ return ret.Get();
+ }
+
+ private:
+ using TRef = THolder<TValue>;
+ typename TValue::TPool Pool_;
+ TSocketMap<TRef> Lst_;
+ };
+
+
+ using TPollEventList = TIntrusiveList<IPollEvent>;
+
+ class TContPoller {
+ public:
+ using TEvent = IPollerFace::TEvent;
+ using TEvents = IPollerFace::TEvents;
+
+ TContPoller()
+ : P_(IPollerFace::Default())
+ {
+ }
+
+ explicit TContPoller(THolder<IPollerFace> poller)
+ : P_(std::move(poller))
+ {}
+
+ void Schedule(IPollEvent* event) {
+ auto* lst = Lists_.Get(event->Fd());
+ const ui16 oldFlags = Flags(*lst);
+ lst->PushFront(event);
+ ui16 newFlags = Flags(*lst);
+
+ if (newFlags != oldFlags) {
+ if (oldFlags) {
+ newFlags |= CONT_POLL_MODIFY;
+ }
+
+ P_->Set(lst, event->Fd(), newFlags);
+ }
+ }
+
+ void Remove(IPollEvent* event) noexcept {
+ auto* lst = Lists_.Get(event->Fd());
+ const ui16 oldFlags = Flags(*lst);
+ event->Unlink();
+ ui16 newFlags = Flags(*lst);
+
+ if (newFlags != oldFlags) {
+ if (newFlags) {
+ newFlags |= CONT_POLL_MODIFY;
+ }
+
+ P_->Set(lst, event->Fd(), newFlags);
+ }
+ }
+
+ void Wait(TEvents& events, TInstant deadLine) {
+ events.clear();
+ P_->Wait(events, deadLine);
+ }
+
+ EContPoller PollEngine() const {
+ return P_->PollEngine();
+ }
+ private:
+ static ui16 Flags(TIntrusiveList<IPollEvent>& lst) noexcept {
+ ui16 ret = 0;
+ for (auto&& item : lst) {
+ ret |= item.What();
+ }
+ return ret;
+ }
+
+ private:
+ TBigArray<TPollEventList> Lists_;
+ THolder<IPollerFace> P_;
+ };
+
+
+ class TEventWaitQueue {
+ using TIoWait = TRbTree<NCoro::TContPollEvent, NCoro::TContPollEventCompare>;
+
+ public:
+ void Register(NCoro::TContPollEvent* event);
+
+ bool Empty() const noexcept {
+ return IoWait_.Empty();
+ }
+
+ void Abort() noexcept;
+
+ TInstant WakeTimedout(TInstant now) noexcept;
+
+ private:
+ TIoWait IoWait_;
+ };
+}
+
+class TFdEvent final:
+ public NCoro::TContPollEvent,
+ public NCoro::IPollEvent
+{
+public:
+ TFdEvent(TCont* cont, SOCKET fd, ui16 what, TInstant deadLine) noexcept
+ : TContPollEvent(cont, deadLine)
+ , IPollEvent(fd, what)
+ {}
+
+ ~TFdEvent() {
+ RemoveFromIOWait();
+ }
+
+ void RemoveFromIOWait() noexcept;
+
+ void OnPollEvent(int status) noexcept override {
+ Wake(status);
+ }
+};
+
+
+class TTimerEvent: public NCoro::TContPollEvent {
+public:
+ TTimerEvent(TCont* cont, TInstant deadLine) noexcept
+ : TContPollEvent(cont, deadLine)
+ {}
+};
+
+int ExecuteEvent(TFdEvent* event) noexcept;
+
+int ExecuteEvent(TTimerEvent* event) noexcept;
diff --git a/library/cpp/coroutine/engine/coroutine_ut.cpp b/library/cpp/coroutine/engine/coroutine_ut.cpp
new file mode 100644
index 0000000000..8b372496a2
--- /dev/null
+++ b/library/cpp/coroutine/engine/coroutine_ut.cpp
@@ -0,0 +1,1007 @@
+#include "impl.h"
+#include "condvar.h"
+#include "network.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/string/cast.h>
+#include <util/system/pipe.h>
+#include <util/system/env.h>
+#include <util/system/info.h>
+#include <util/system/thread.h>
+#include <util/generic/xrange.h>
+#include <util/generic/serialized_enum.h>
+
+// TODO (velavokr): BALANCER-1345 add more tests on pollers
+
+class TCoroTest: public TTestBase {
+ UNIT_TEST_SUITE(TCoroTest);
+ UNIT_TEST(TestSimpleX1);
+ UNIT_TEST(TestSimpleX1MultiThread);
+ UNIT_TEST(TestSimpleX2);
+ UNIT_TEST(TestSimpleX3);
+ UNIT_TEST(TestMemFun);
+ UNIT_TEST(TestMutex);
+ UNIT_TEST(TestCondVar);
+ UNIT_TEST(TestJoinDefault);
+ UNIT_TEST(TestJoinEpoll);
+ UNIT_TEST(TestJoinKqueue);
+ UNIT_TEST(TestJoinPoll);
+ UNIT_TEST(TestJoinSelect);
+ UNIT_TEST(TestException);
+ UNIT_TEST(TestJoinCancelExitRaceBug);
+ UNIT_TEST(TestWaitWakeLivelockBug);
+ UNIT_TEST(TestFastPathWakeDefault)
+ // TODO (velavokr): BALANCER-1338 our epoll wrapper cannot handle pipe eofs
+// UNIT_TEST(TestFastPathWakeEpoll)
+ UNIT_TEST(TestFastPathWakeKqueue)
+ UNIT_TEST(TestFastPathWakePoll)
+ UNIT_TEST(TestFastPathWakeSelect)
+ UNIT_TEST(TestLegacyCancelYieldRaceBug)
+ UNIT_TEST(TestJoinRescheduleBug);
+ UNIT_TEST(TestEventQueue)
+ UNIT_TEST(TestNestedExecutor)
+ UNIT_TEST(TestComputeCoroutineYield)
+ UNIT_TEST(TestPollEngines);
+ UNIT_TEST(TestUserEvent);
+ UNIT_TEST(TestPause);
+ UNIT_TEST(TestOverrideTime);
+ UNIT_TEST_SUITE_END();
+
+public:
+ void TestException();
+ void TestSimpleX1();
+ void TestSimpleX1MultiThread();
+ void TestSimpleX2();
+ void TestSimpleX3();
+ void TestMemFun();
+ void TestMutex();
+ void TestCondVar();
+ void TestJoinDefault();
+ void TestJoinEpoll();
+ void TestJoinKqueue();
+ void TestJoinPoll();
+ void TestJoinSelect();
+ void TestJoinCancelExitRaceBug();
+ void TestWaitWakeLivelockBug();
+ void TestFastPathWakeDefault();
+ void TestFastPathWakeEpoll();
+ void TestFastPathWakeKqueue();
+ void TestFastPathWakePoll();
+ void TestFastPathWakeSelect();
+ void TestLegacyCancelYieldRaceBug();
+ void TestJoinRescheduleBug();
+ void TestEventQueue();
+ void TestNestedExecutor();
+ void TestComputeCoroutineYield();
+ void TestPollEngines();
+ void TestUserEvent();
+ void TestPause();
+ void TestOverrideTime();
+};
+
+void TCoroTest::TestException() {
+ TContExecutor e(1000000);
+
+ bool f2run = false;
+
+ auto f1 = [&f2run](TCont* c) {
+ struct TCtx {
+ ~TCtx() {
+ Y_VERIFY(!*F2);
+
+ C->Yield();
+ }
+
+ TCont* C;
+ bool* F2;
+ };
+
+ try {
+ TCtx ctx = {c, &f2run};
+
+ throw 1;
+ } catch (...) {
+ }
+ };
+
+ bool unc = true;
+
+ auto f2 = [&unc, &f2run](TCont*) {
+ f2run = true;
+ unc = std::uncaught_exception();
+
+ // check segfault
+ try {
+ throw 2;
+ } catch (int) {
+ }
+ };
+
+ e.Create(f1, "f1");
+ e.Create(f2, "f2");
+ e.Execute();
+
+ UNIT_ASSERT(!unc);
+}
+
+static int i0;
+
+static void CoRun(TCont* c, void* /*run*/) {
+ while (i0 < 100000) {
+ ++i0;
+ UNIT_ASSERT(RunningCont() == c);
+ c->Yield();
+ UNIT_ASSERT(RunningCont() == c);
+ }
+}
+
+static void CoMain(TCont* c, void* /*arg*/) {
+ for (volatile size_t i2 = 0; i2 < 10; ++i2) {
+ UNIT_ASSERT(RunningCont() == c);
+ c->Executor()->Create(CoRun, nullptr, "run");
+ UNIT_ASSERT(RunningCont() == c);
+ }
+}
+
+void TCoroTest::TestSimpleX1() {
+ i0 = 0;
+ TContExecutor e(32000);
+
+ UNIT_ASSERT(RunningCont() == nullptr);
+
+ e.Execute(CoMain);
+ UNIT_ASSERT_VALUES_EQUAL(i0, 100000);
+
+ UNIT_ASSERT(RunningCont() == nullptr);
+}
+
+void TCoroTest::TestSimpleX1MultiThread() {
+ TVector<THolder<TThread>> threads;
+ const size_t nThreads = 0;
+ TAtomic c = 0;
+ for (size_t i = 0; i < nThreads; ++i) {
+ threads.push_back(MakeHolder<TThread>([&]() {
+ TestSimpleX1();
+ AtomicIncrement(c);
+ }));
+ }
+
+ for (auto& t : threads) {
+ t->Start();
+ }
+
+ for (auto& t: threads) {
+ t->Join();
+ }
+
+ UNIT_ASSERT_EQUAL(c, nThreads);
+}
+
+struct TTestObject {
+ int i = 0;
+ int j = 0;
+
+public:
+ void RunTask1(TCont*) {
+ i = 1;
+ }
+ void RunTask2(TCont*) {
+ j = 2;
+ }
+};
+
+void TCoroTest::TestMemFun() {
+ i0 = 0;
+ TContExecutor e(32000);
+ TTestObject obj;
+ e.Create<TTestObject, &TTestObject::RunTask1>(&obj, "test1");
+ e.Execute<TTestObject, &TTestObject::RunTask2>(&obj);
+ UNIT_ASSERT_EQUAL(obj.i, 1);
+ UNIT_ASSERT_EQUAL(obj.j, 2);
+}
+
+void TCoroTest::TestSimpleX2() {
+ {
+ i0 = 0;
+
+ {
+ TContExecutor e(32000);
+ e.Execute(CoMain);
+ }
+
+ UNIT_ASSERT_EQUAL(i0, 100000);
+ }
+
+ {
+ i0 = 0;
+
+ {
+ TContExecutor e(32000);
+ e.Execute(CoMain);
+ }
+
+ UNIT_ASSERT_EQUAL(i0, 100000);
+ }
+}
+
+struct TRunner {
+ inline TRunner()
+ : Runs(0)
+ {
+ }
+
+ inline void operator()(TCont* c) {
+ ++Runs;
+ c->Yield();
+ }
+
+ size_t Runs;
+};
+
+void TCoroTest::TestSimpleX3() {
+ TContExecutor e(32000);
+ TRunner runner;
+
+ for (volatile size_t i3 = 0; i3 < 1000; ++i3) {
+ e.Create(runner, "runner");
+ }
+
+ e.Execute();
+
+ UNIT_ASSERT_EQUAL(runner.Runs, 1000);
+}
+
+static TString res;
+static TContMutex mutex;
+
+static void CoMutex(TCont* c, void* /*run*/) {
+ {
+ mutex.LockI(c);
+ c->Yield();
+ res += c->Name();
+ mutex.UnLock();
+ }
+
+ c->Yield();
+
+ {
+ mutex.LockI(c);
+ c->Yield();
+ res += c->Name();
+ mutex.UnLock();
+ }
+}
+
+static void CoMutexTest(TCont* c, void* /*run*/) {
+ c->Executor()->Create(CoMutex, nullptr, "1");
+ c->Executor()->Create(CoMutex, nullptr, "2");
+}
+
+void TCoroTest::TestMutex() {
+ TContExecutor e(32000);
+ e.Execute(CoMutexTest);
+ UNIT_ASSERT_EQUAL(res, "1212");
+ res.clear();
+}
+
+static TContMutex m1;
+static TContCondVar c1;
+
+static void CoCondVar(TCont* c, void* /*run*/) {
+ for (size_t i4 = 0; i4 < 3; ++i4) {
+ UNIT_ASSERT_EQUAL(m1.LockI(c), 0);
+ UNIT_ASSERT_EQUAL(c1.WaitI(c, &m1), 0);
+ res += c->Name();
+ m1.UnLock();
+ }
+}
+
+static void CoCondVarTest(TCont* c, void* /*run*/) {
+ c->Executor()->Create(CoCondVar, nullptr, "1");
+ c->Yield();
+ c->Executor()->Create(CoCondVar, nullptr, "2");
+ c->Yield();
+ c->Executor()->Create(CoCondVar, nullptr, "3");
+ c->Yield();
+ c->Executor()->Create(CoCondVar, nullptr, "4");
+ c->Yield();
+ c->Executor()->Create(CoCondVar, nullptr, "5");
+ c->Yield();
+ c->Executor()->Create(CoCondVar, nullptr, "6");
+ c->Yield();
+
+ for (size_t i5 = 0; i5 < 3; ++i5) {
+ res += ToString((size_t)i5) + "^";
+ c1.BroadCast();
+ c->Yield();
+ }
+}
+
+void TCoroTest::TestCondVar() {
+ TContExecutor e(32000);
+ e.Execute(CoCondVarTest);
+ UNIT_ASSERT_EQUAL(res, "0^1234561^1234562^123456");
+ res.clear();
+}
+
+namespace NCoroTestJoin {
+ struct TSleepCont {
+ const TInstant Deadline;
+ int Result;
+
+ inline void operator()(TCont* c) {
+ Result = c->SleepD(Deadline);
+ }
+ };
+
+ struct TReadCont {
+ const TInstant Deadline;
+ const SOCKET Sock;
+ int Result;
+
+ inline void operator()(TCont* c) {
+ char buf = 0;
+ Result = NCoro::ReadD(c, Sock, &buf, sizeof(buf), Deadline).Status();
+ }
+ };
+
+ struct TJoinCont {
+ const TInstant Deadline;
+ TCont* const Cont;
+ bool Result;
+
+ inline void operator()(TCont* c) {
+ Result = c->Join(Cont, Deadline);
+ }
+ };
+
+ void DoTestJoin(EContPoller pollerType) {
+ auto poller = IPollerFace::Construct(pollerType);
+
+ if (!poller) {
+ return;
+ }
+
+ TContExecutor e(32000, std::move(poller));
+
+ TPipe in, out;
+ TPipe::Pipe(in, out);
+ SetNonBlock(in.GetHandle());
+
+ {
+ TSleepCont sc = {TInstant::Max(), 0};
+ TJoinCont jc = {TDuration::MilliSeconds(100).ToDeadLine(), e.Create(sc, "sc"), true};
+
+ e.Execute(jc);
+
+ UNIT_ASSERT_EQUAL(sc.Result, ECANCELED);
+ UNIT_ASSERT_EQUAL(jc.Result, false);
+ }
+
+ {
+ TSleepCont sc = {TDuration::MilliSeconds(100).ToDeadLine(), 0};
+ TJoinCont jc = {TDuration::MilliSeconds(200).ToDeadLine(), e.Create(sc, "sc"), false};
+
+ e.Execute(jc);
+
+ UNIT_ASSERT_EQUAL(sc.Result, ETIMEDOUT);
+ UNIT_ASSERT_EQUAL(jc.Result, true);
+ }
+
+ {
+ TSleepCont sc = {TDuration::MilliSeconds(200).ToDeadLine(), 0};
+ TJoinCont jc = {TDuration::MilliSeconds(100).ToDeadLine(), e.Create(sc, "sc"), true};
+
+ e.Execute(jc);
+
+ UNIT_ASSERT_EQUAL(sc.Result, ECANCELED);
+ UNIT_ASSERT_EQUAL(jc.Result, false);
+ }
+
+ {
+ TReadCont rc = {TInstant::Max(), in.GetHandle(), 0};
+ TJoinCont jc = {TDuration::MilliSeconds(100).ToDeadLine(), e.Create(rc, "rc"), true};
+
+ e.Execute(jc);
+
+ UNIT_ASSERT_EQUAL(rc.Result, ECANCELED);
+ UNIT_ASSERT_EQUAL(jc.Result, false);
+ }
+
+ {
+ TReadCont rc = {TDuration::MilliSeconds(100).ToDeadLine(), in.GetHandle(), 0};
+ TJoinCont jc = {TDuration::MilliSeconds(200).ToDeadLine(), e.Create(rc, "rc"), false};
+
+ e.Execute(jc);
+
+ UNIT_ASSERT_EQUAL(rc.Result, ETIMEDOUT);
+ UNIT_ASSERT_EQUAL(jc.Result, true);
+ }
+
+ {
+ TReadCont rc = {TDuration::MilliSeconds(200).ToDeadLine(), in.GetHandle(), 0};
+ TJoinCont jc = {TDuration::MilliSeconds(100).ToDeadLine(), e.Create(rc, "rc"), true};
+
+ e.Execute(jc);
+
+ UNIT_ASSERT_EQUAL(rc.Result, ECANCELED);
+ UNIT_ASSERT_EQUAL(jc.Result, false);
+ }
+ }
+}
+
+void TCoroTest::TestJoinDefault() {
+ NCoroTestJoin::DoTestJoin(EContPoller::Default);
+}
+
+void TCoroTest::TestJoinEpoll() {
+ NCoroTestJoin::DoTestJoin(EContPoller::Epoll);
+}
+
+void TCoroTest::TestJoinKqueue() {
+ NCoroTestJoin::DoTestJoin(EContPoller::Kqueue);
+}
+
+void TCoroTest::TestJoinPoll() {
+ NCoroTestJoin::DoTestJoin(EContPoller::Poll);
+}
+
+void TCoroTest::TestJoinSelect() {
+ NCoroTestJoin::DoTestJoin(EContPoller::Select);
+}
+
+namespace NCoroJoinCancelExitRaceBug {
+ struct TState {
+ TCont* Sub = nullptr;
+ };
+
+ static void DoAux(TCont*, void* argPtr) noexcept {
+ TState& state = *(TState*)(argPtr);
+
+ // 06.{Ready:[Sub2]} > {Ready:[Sub2,Sub]}
+ state.Sub->Cancel();
+ }
+
+ static void DoSub2(TCont*, void*) noexcept {
+ // 07.{Ready:[Sub]} > Exit > {Ready:[Sub],ToDelete:[Sub2]}
+ // 08.{Ready:[Sub],ToDelete:[Sub2]} > Release(Sub2) > {Ready:[Sub],Deleted:[Sub2]}
+ }
+
+ static void DoSub(TCont* cont, void* argPtr) noexcept {
+ TState& state = *(TState*)(argPtr);
+ state.Sub = cont;
+
+ // 04.{Ready:[Aux]} > {Ready:[Aux,Sub2]}
+ auto* sub2 = cont->Executor()->Create(DoSub2, argPtr, "Sub2");
+
+ // 05.{Ready:[Aux,Sub2]} > SwitchTo(Aux)
+ // 09.{Ready:[],Deleted:[Sub2]} > Cancel(Sub2) > {Ready:[Sub2],Deleted:[Sub2]}
+ // 10.{Ready:[Sub2],Deleted:[Sub2]} > SwitchTo(Sub2) > FAIL: can not return from exit
+ cont->Join(sub2);
+
+ state.Sub = nullptr;
+ }
+
+ static void DoMain(TCont* cont) noexcept {
+ TState state;
+
+ // 01.{Ready:[]} > {Ready:[Sub]}
+ auto* sub = cont->Executor()->Create(DoSub, &state, "Sub");
+
+ // 02.{Ready:[Sub]} > {Ready:[Sub,Aux]}
+ cont->Executor()->Create(DoAux, &state, "Aux");
+
+ // 03.{Ready:[Sub,Aux]} > SwitchTo(Sub)
+ cont->Join(sub);
+ }
+}
+
+void TCoroTest::TestJoinCancelExitRaceBug() {
+ TContExecutor exec(20000);
+ exec.SetFailOnError(true);
+ exec.Execute(NCoroJoinCancelExitRaceBug::DoMain);
+}
+
+namespace NCoroWaitWakeLivelockBug {
+ struct TState;
+
+ struct TSubState {
+ TSubState(TState& parent, ui32 self)
+ : Parent(parent)
+ , Name(TStringBuilder() << "Sub" << self)
+ , Self(self)
+ {
+ UNIT_ASSERT(self < 2);
+ }
+
+ TSubState& OtherState();
+
+ TState& Parent;
+ TTimerEvent* Event = nullptr;
+ TCont* Cont = nullptr;
+ TString Name;
+ ui32 Self = -1;
+ };
+
+ struct TState {
+ TState()
+ : Subs{{*this, 0}, {*this, 1}}
+ {}
+
+ TSubState Subs[2];
+ bool Stop = false;
+ };
+
+ TSubState& TSubState::OtherState() {
+ return Parent.Subs[1 - Self];
+ }
+
+ static void DoStop(TCont* cont, void* argPtr) {
+ TState& state = *(TState*)(argPtr);
+
+ TTimerEvent event(cont, TInstant::Now());
+ ExecuteEvent(&event);
+ state.Stop = true;
+ for (auto& sub: state.Subs) {
+ if (sub.Event) {
+ sub.Event->Wake(EWAKEDUP);
+ }
+ }
+ }
+
+ static void DoSub(TCont* cont, void* argPtr) {
+ TSubState& state = *(TSubState*)(argPtr);
+
+ while (!state.Parent.Stop) {
+ TTimerEvent event(cont, TInstant::Max());
+ if (state.OtherState().Event) {
+ state.OtherState().Event->Wake(EWAKEDUP);
+ }
+ state.Event = &event;
+ ExecuteEvent(&event);
+ state.Event = nullptr;
+ }
+
+ state.Cont = nullptr;
+ }
+
+ static void DoMain(TCont* cont) noexcept {
+ TState state;
+
+ for (auto& subState : state.Subs) {
+ subState.Cont = cont->Executor()->Create(DoSub, &subState, subState.Name.data());
+ }
+
+ cont->Join(
+ cont->Executor()->Create(DoStop, &state, "Stop")
+ );
+
+ for (auto& subState : state.Subs) {
+ if (subState.Cont) {
+ cont->Join(subState.Cont);
+ }
+ }
+ }
+}
+
+void TCoroTest::TestWaitWakeLivelockBug() {
+ TContExecutor exec(20000);
+ exec.SetFailOnError(true);
+ exec.Execute(NCoroWaitWakeLivelockBug::DoMain);
+}
+
+namespace NCoroTestFastPathWake {
+ struct TState;
+
+ struct TSubState {
+ TSubState(TState& parent, ui32 self)
+ : Parent(parent)
+ , Name(TStringBuilder() << "Sub" << self)
+ {}
+
+ TState& Parent;
+ TInstant Finish;
+ TTimerEvent* Event = nullptr;
+ TCont* Cont = nullptr;
+ TString Name;
+ };
+
+ struct TState {
+ TState()
+ : Subs{{*this, 0}, {*this, 1}}
+ {
+ TPipe::Pipe(In, Out);
+ SetNonBlock(In.GetHandle());
+ }
+
+ TSubState Subs[2];
+ TPipe In, Out;
+ bool IoSleepRunning = false;
+ };
+
+ static void DoIoSleep(TCont* cont, void* argPtr) noexcept {
+ try {
+ TState& state = *(TState*) (argPtr);
+ state.IoSleepRunning = true;
+
+ TTempBuf tmp;
+ // Wait for the event from io
+ auto res = NCoro::ReadD(cont, state.In.GetHandle(), tmp.Data(), 1, TDuration::Seconds(10).ToDeadLine());
+ UNIT_ASSERT_VALUES_EQUAL(res.Checked(), 0);
+ state.IoSleepRunning = false;
+ } catch (const NUnitTest::TAssertException& ex) {
+ Cerr << ex.AsStrBuf() << Endl;
+ ex.BackTrace()->PrintTo(Cerr);
+ throw;
+ } catch (...) {
+ Cerr << CurrentExceptionMessage() << Endl;
+ throw;
+ }
+ }
+
+ static void DoSub(TCont* cont, void* argPtr) noexcept {
+ TSubState& state = *(TSubState*)(argPtr);
+
+ TTimerEvent event(cont, TInstant::Max());
+ state.Event = &event;
+ ExecuteEvent(&event);
+ state.Event = nullptr;
+ state.Cont = nullptr;
+ state.Finish = TInstant::Now();
+ }
+
+ static void DoMain(TCont* cont) noexcept {
+ try {
+ TState state;
+ TInstant start = TInstant::Now();
+
+ // This guy sleeps on io
+ auto sleeper = cont->Executor()->Create(DoIoSleep, &state, "io_sleeper");
+
+ // These guys are to be woken up right away
+ for (auto& subState : state.Subs) {
+ subState.Cont = cont->Executor()->Create(DoSub, &subState, subState.Name.data());
+ }
+
+ // Give way
+ cont->Yield();
+
+ // Check everyone has started, wake those to be woken
+ UNIT_ASSERT(state.IoSleepRunning);
+
+ for (auto& subState : state.Subs) {
+ UNIT_ASSERT(subState.Event);
+ subState.Event->Wake(EWAKEDUP);
+ }
+
+ // Give way again
+ cont->Yield();
+
+ // Check the woken guys have finished and quite soon
+ for (auto& subState : state.Subs) {
+ UNIT_ASSERT(subState.Finish - start < TDuration::MilliSeconds(100));
+ UNIT_ASSERT(!subState.Cont);
+ }
+
+ // Wake the io guy and finish
+ state.Out.Close();
+
+ if (state.IoSleepRunning) {
+ cont->Join(sleeper);
+ }
+
+ // Check everything has ended sooner than the timeout
+ UNIT_ASSERT(TInstant::Now() - start < TDuration::Seconds(1));
+ } catch (const NUnitTest::TAssertException& ex) {
+ Cerr << ex.AsStrBuf() << Endl;
+ ex.BackTrace()->PrintTo(Cerr);
+ throw;
+ } catch (...) {
+ Cerr << CurrentExceptionMessage() << Endl;
+ throw;
+ }
+ }
+
+ static void DoTestFastPathWake(EContPoller pollerType) {
+ if (auto poller = IPollerFace::Construct(pollerType)) {
+ TContExecutor exec(20000, std::move(poller));
+ exec.SetFailOnError(true);
+ exec.Execute(NCoroTestFastPathWake::DoMain);
+ }
+ }
+}
+
+void TCoroTest::TestFastPathWakeDefault() {
+ NCoroTestFastPathWake::DoTestFastPathWake(EContPoller::Default);
+}
+
+void TCoroTest::TestFastPathWakeEpoll() {
+ NCoroTestFastPathWake::DoTestFastPathWake(EContPoller::Epoll);
+}
+
+void TCoroTest::TestFastPathWakeKqueue() {
+ NCoroTestFastPathWake::DoTestFastPathWake(EContPoller::Kqueue);
+}
+
+void TCoroTest::TestFastPathWakePoll() {
+ NCoroTestFastPathWake::DoTestFastPathWake(EContPoller::Poll);
+}
+
+void TCoroTest::TestFastPathWakeSelect() {
+ NCoroTestFastPathWake::DoTestFastPathWake(EContPoller::Select);
+}
+
+namespace NCoroTestLegacyCancelYieldRaceBug {
+ enum class EState {
+ Idle, Running, Finished,
+ };
+
+ struct TState {
+ EState SubState = EState::Idle;
+ };
+
+ static void DoSub(TCont* cont, void* argPtr) {
+ TState& state = *(TState*)argPtr;
+ state.SubState = EState::Running;
+ cont->Yield();
+ cont->Yield();
+ state.SubState = EState::Finished;
+ }
+
+ static void DoMain(TCont* cont, void* argPtr) {
+ TState& state = *(TState*)argPtr;
+ TCont* sub = cont->Executor()->Create(DoSub, argPtr, "Sub");
+ sub->Cancel();
+ cont->Yield();
+ UNIT_ASSERT_EQUAL(state.SubState, EState::Finished);
+ }
+}
+
+void TCoroTest::TestLegacyCancelYieldRaceBug() {
+ NCoroTestLegacyCancelYieldRaceBug::TState state;
+ TContExecutor exec(20000);
+ exec.SetFailOnError(true);
+ exec.Execute(NCoroTestLegacyCancelYieldRaceBug::DoMain, &state);
+}
+
+namespace NCoroTestJoinRescheduleBug {
+ enum class EState {
+ Idle, Running, Finished,
+ };
+
+ struct TState {
+ TCont* volatile SubA = nullptr;
+ volatile EState SubAState = EState::Idle;
+ volatile EState SubBState = EState::Idle;
+ volatile EState SubCState = EState::Idle;
+ };
+
+ static void DoSubC(TCont* cont, void* argPtr) {
+ TState& state = *(TState*)argPtr;
+ state.SubCState = EState::Running;
+ while (state.SubBState != EState::Running) {
+ cont->Yield();
+ }
+ while (cont->SleepD(TInstant::Max()) != ECANCELED) {
+ }
+ state.SubCState = EState::Finished;
+ }
+
+ static void DoSubB(TCont* cont, void* argPtr) {
+ TState& state = *(TState*)argPtr;
+ state.SubBState = EState::Running;
+ while (state.SubAState != EState::Running && state.SubCState != EState::Running) {
+ cont->Yield();
+ }
+ for (auto i : xrange(100)) {
+ Y_UNUSED(i);
+ if (!state.SubA) {
+ break;
+ }
+ state.SubA->ReSchedule();
+ cont->Yield();
+ }
+ state.SubBState = EState::Finished;
+ }
+
+ static void DoSubA(TCont* cont, void* argPtr) {
+ TState& state = *(TState*)argPtr;
+ state.SubAState = EState::Running;
+ TCont* subC = cont->Executor()->Create(DoSubC, argPtr, "SubC");
+ while (state.SubBState != EState::Running && state.SubCState != EState::Running) {
+ cont->Yield();
+ }
+ cont->Join(subC);
+ UNIT_ASSERT_EQUAL(state.SubCState, EState::Finished);
+ state.SubA = nullptr;
+ state.SubAState = EState::Finished;
+ }
+
+ static void DoMain(TCont* cont, void* argPtr) {
+ TState& state = *(TState*)argPtr;
+ TCont* subA = cont->Executor()->Create(DoSubA, argPtr, "SubA");
+ state.SubA = subA;
+ cont->Join(cont->Executor()->Create(DoSubB, argPtr, "SubB"));
+
+ if (state.SubA) {
+ subA->Cancel();
+ cont->Join(subA);
+ }
+ }
+}
+
+void TCoroTest::TestJoinRescheduleBug() {
+ using namespace NCoroTestJoinRescheduleBug;
+ TState state;
+ {
+ TContExecutor exec(20000);
+ exec.Execute(DoMain, &state);
+ }
+ UNIT_ASSERT_EQUAL(state.SubAState, EState::Finished);
+ UNIT_ASSERT_EQUAL(state.SubBState, EState::Finished);
+ UNIT_ASSERT_EQUAL(state.SubCState, EState::Finished);
+}
+
+void TCoroTest::TestEventQueue() {
+ NCoro::TEventWaitQueue queue;
+ UNIT_ASSERT(queue.Empty());
+ UNIT_ASSERT_VALUES_EQUAL(queue.WakeTimedout(TInstant()), TInstant());
+ TContExecutor exec(32000);
+ exec.Execute([](TCont* cont, void* arg) {
+ NCoro::TEventWaitQueue* q = (NCoro::TEventWaitQueue*)arg;
+ TTimerEvent ev(cont, TInstant::Max());
+ TTimerEvent ev2(cont, TInstant::Seconds(12345));
+ q->Register(&ev);
+ UNIT_ASSERT_VALUES_EQUAL(q->WakeTimedout(TInstant::Seconds(12344)), TInstant::Max());
+ UNIT_ASSERT_VALUES_EQUAL(q->WakeTimedout(TInstant::Seconds(12344)), TInstant::Max());
+ q->Register(&ev2);
+ UNIT_ASSERT_VALUES_EQUAL(q->WakeTimedout(TInstant::Seconds(12344)), TInstant::Seconds(12345));
+ UNIT_ASSERT_VALUES_EQUAL(q->WakeTimedout(TInstant::Seconds(12344)), TInstant::Seconds(12345));
+ UNIT_ASSERT_VALUES_EQUAL(q->WakeTimedout(TInstant::Seconds(12345)), TInstant::Seconds(12345));
+ UNIT_ASSERT_VALUES_EQUAL(q->WakeTimedout(TInstant::Seconds(12345)), TInstant::Max());
+ }, &queue);
+}
+
+void TCoroTest::TestNestedExecutor() {
+#ifndef _win_
+ //nested executors actually don't work correctly, but anyway shouldn't break RunningCont() ptr
+ TContExecutor exec(32000);
+ UNIT_ASSERT(!RunningCont());
+
+ exec.Execute([](TCont* cont, void*) {
+ UNIT_ASSERT_VALUES_EQUAL(RunningCont(), cont);
+
+ TContExecutor exec2(32000);
+ exec2.Execute([](TCont* cont2, void*) {
+ UNIT_ASSERT_VALUES_EQUAL(RunningCont(), cont2);
+ TContExecutor exec3(32000);
+ exec3.Execute([](TCont* cont3, void*) {
+ UNIT_ASSERT_VALUES_EQUAL(RunningCont(), cont3);
+ });
+
+ UNIT_ASSERT_VALUES_EQUAL(RunningCont(), cont2);
+ });
+
+ UNIT_ASSERT_VALUES_EQUAL(RunningCont(), cont);
+ });
+
+ UNIT_ASSERT(!RunningCont());
+#endif
+}
+
+void TCoroTest::TestComputeCoroutineYield() {
+//if we have busy (e.g., on cpu) coroutine, when it yields, io must flow
+ TContExecutor exec(32000);
+ exec.SetFailOnError(true);
+
+ TPipe in, out;
+ TPipe::Pipe(in, out);
+ SetNonBlock(in.GetHandle());
+ size_t lastRead = 42;
+
+ auto compute = [&](TCont* cont) {
+ for (size_t i = 0; i < 10; ++i) {
+ write(out.GetHandle(), &i, sizeof i);
+ Sleep(TDuration::MilliSeconds(10));
+ cont->Yield();
+ UNIT_ASSERT(lastRead == i);
+ }
+ };
+
+ auto io = [&](TCont* cont) {
+ for (size_t i = 0; i < 10; ++i) {
+ NCoro::ReadI(cont, in.GetHandle(), &lastRead, sizeof lastRead);
+ }
+ };
+
+ exec.Create(compute, "compute");
+ exec.Create(io, "io");
+
+ exec.Execute();
+}
+
+void TCoroTest::TestPollEngines() {
+ bool defaultChecked = false;
+ for (auto engine : GetEnumAllValues<EContPoller>()) {
+ auto poller = IPollerFace::Construct(engine);
+ if (!poller) {
+ continue;
+ }
+
+ TContExecutor exec(32000, IPollerFace::Construct(engine));
+
+ if (engine == EContPoller::Default) {
+ defaultChecked = true;
+ UNIT_ASSERT_VALUES_EQUAL(exec.Poller()->PollEngine(), EContPoller::Combined);
+ } else {
+ UNIT_ASSERT_VALUES_EQUAL(exec.Poller()->PollEngine(), engine);
+ }
+ }
+
+ UNIT_ASSERT(defaultChecked);
+}
+
+void TCoroTest::TestPause() {
+ TContExecutor executor{1024*1024, IPollerFace::Default(), nullptr, nullptr, NCoro::NStack::EGuard::Canary, Nothing()};
+
+ int i = 0;
+ executor.CreateOwned([&](TCont*) {
+ i++;
+ executor.Pause();
+ i++;
+ }, "coro");
+
+ UNIT_ASSERT_EQUAL(i, 0);
+ executor.Execute();
+ UNIT_ASSERT_EQUAL(i, 1);
+ executor.Execute();
+ UNIT_ASSERT_EQUAL(i, 2);
+}
+
+void TCoroTest::TestUserEvent() {
+ TContExecutor exec(32000);
+
+ struct TUserEvent : public IUserEvent {
+ bool Called = false;
+ void Execute() override {
+ Called = true;
+ }
+ } event;
+
+ auto f = [&](TCont* cont) {
+ UNIT_ASSERT(!event.Called);
+ exec.ScheduleUserEvent(&event);
+ UNIT_ASSERT(!event.Called);
+ cont->Yield();
+ UNIT_ASSERT(event.Called);
+ };
+
+ exec.Execute(f);
+
+ UNIT_ASSERT(event.Called);
+}
+
+void TCoroTest::TestOverrideTime() {
+ class TTime: public NCoro::ITime {
+ public:
+ TInstant Now() override {
+ return Current;
+ }
+
+ TInstant Current = TInstant::Zero();
+ };
+
+ TTime time;
+ TContExecutor executor{1024*1024, IPollerFace::Default(), nullptr, nullptr, NCoro::NStack::EGuard::Canary, Nothing(), &time};
+
+ executor.CreateOwned([&](TCont* cont) {
+ UNIT_ASSERT_EQUAL(cont->Executor()->Now(), TInstant::Zero());
+ time.Current = TInstant::Seconds(1);
+ cont->SleepD(TInstant::Seconds(1));
+ UNIT_ASSERT_EQUAL(cont->Executor()->Now(), TInstant::Seconds(1));
+ }, "coro");
+
+ executor.Execute();
+}
+UNIT_TEST_SUITE_REGISTRATION(TCoroTest);
diff --git a/library/cpp/coroutine/engine/custom_time.h b/library/cpp/coroutine/engine/custom_time.h
new file mode 100644
index 0000000000..0bff0f6a60
--- /dev/null
+++ b/library/cpp/coroutine/engine/custom_time.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include <util/datetime/base.h>
+
+namespace NCoro {
+class ITime {
+ public:
+ virtual TInstant Now() = 0;
+};
+}
diff --git a/library/cpp/coroutine/engine/events.h b/library/cpp/coroutine/engine/events.h
new file mode 100644
index 0000000000..07cc4d25e8
--- /dev/null
+++ b/library/cpp/coroutine/engine/events.h
@@ -0,0 +1,148 @@
+#pragma once
+
+#include "impl.h"
+
+#include <util/datetime/base.h>
+
+class TContEvent {
+public:
+ TContEvent(TCont* current) noexcept
+ : Cont_(current)
+ , Status_(0)
+ {
+ }
+
+ ~TContEvent() {
+ }
+
+ int WaitD(TInstant deadline) {
+ Status_ = 0;
+ const int ret = Cont_->SleepD(deadline);
+
+ return Status_ ? Status_ : ret;
+ }
+
+ int WaitT(TDuration timeout) {
+ return WaitD(timeout.ToDeadLine());
+ }
+
+ int WaitI() {
+ return WaitD(TInstant::Max());
+ }
+
+ void Wake() noexcept {
+ SetStatus(EWAKEDUP);
+ Cont_->ReSchedule();
+ }
+
+ TCont* Cont() noexcept {
+ return Cont_;
+ }
+
+ int Status() const noexcept {
+ return Status_;
+ }
+
+ void SetStatus(int status) noexcept {
+ Status_ = status;
+ }
+
+private:
+ TCont* Cont_;
+ int Status_;
+};
+
+class TContWaitQueue {
+ class TWaiter: public TContEvent, public TIntrusiveListItem<TWaiter> {
+ public:
+ TWaiter(TCont* current) noexcept
+ : TContEvent(current)
+ {
+ }
+
+ ~TWaiter() {
+ }
+ };
+
+public:
+ TContWaitQueue() noexcept {
+ }
+
+ ~TContWaitQueue() {
+ Y_ASSERT(Waiters_.Empty());
+ }
+
+ int WaitD(TCont* current, TInstant deadline) {
+ TWaiter waiter(current);
+
+ Waiters_.PushBack(&waiter);
+
+ return waiter.WaitD(deadline);
+ }
+
+ int WaitT(TCont* current, TDuration timeout) {
+ return WaitD(current, timeout.ToDeadLine());
+ }
+
+ int WaitI(TCont* current) {
+ return WaitD(current, TInstant::Max());
+ }
+
+ void Signal() noexcept {
+ if (!Waiters_.Empty()) {
+ Waiters_.PopFront()->Wake();
+ }
+ }
+
+ void BroadCast() noexcept {
+ while (!Waiters_.Empty()) {
+ Waiters_.PopFront()->Wake();
+ }
+ }
+
+ void BroadCast(size_t number) noexcept {
+ for (size_t i = 0; i < number && !Waiters_.Empty(); ++i) {
+ Waiters_.PopFront()->Wake();
+ }
+ }
+
+private:
+ TIntrusiveList<TWaiter> Waiters_;
+};
+
+
+class TContSimpleEvent {
+public:
+ TContSimpleEvent(TContExecutor* e)
+ : E_(e)
+ {
+ }
+
+ TContExecutor* Executor() const noexcept {
+ return E_;
+ }
+
+ void Signal() noexcept {
+ Q_.Signal();
+ }
+
+ void BroadCast() noexcept {
+ Q_.BroadCast();
+ }
+
+ int WaitD(TInstant deadLine) noexcept {
+ return Q_.WaitD(E_->Running(), deadLine);
+ }
+
+ int WaitT(TDuration timeout) noexcept {
+ return WaitD(timeout.ToDeadLine());
+ }
+
+ int WaitI() noexcept {
+ return WaitD(TInstant::Max());
+ }
+
+private:
+ TContWaitQueue Q_;
+ TContExecutor* E_;
+};
diff --git a/library/cpp/coroutine/engine/helper.cpp b/library/cpp/coroutine/engine/helper.cpp
new file mode 100644
index 0000000000..bffe208dc8
--- /dev/null
+++ b/library/cpp/coroutine/engine/helper.cpp
@@ -0,0 +1,37 @@
+#include "helper.h"
+
+#include "impl.h"
+#include "network.h"
+
+namespace NCoro {
+
+ bool TryConnect(const TString& host, ui16 port, TDuration timeout) {
+ bool connected = false;
+
+ auto f = [&connected, &host, port, timeout](TCont* c) {
+ TSocketHolder socket;
+ TNetworkAddress address(host, port);
+ connected = (0 == NCoro::ConnectT(c, socket, address, timeout));
+ };
+
+ TContExecutor e(128 * 1024);
+ e.Create(f, "try_connect");
+ e.Execute();
+ return connected;
+ }
+
+ bool WaitUntilConnectable(const TString& host, ui16 port, TDuration timeout) {
+ const TInstant deadline = timeout.ToDeadLine();
+
+ for (size_t i = 1; Now() < deadline; ++i) {
+ const TDuration waitTime = TDuration::MilliSeconds(100) * i * i;
+ SleepUntil(Min(Now() + waitTime, deadline));
+
+ if (TryConnect(host, port, waitTime)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/library/cpp/coroutine/engine/helper.h b/library/cpp/coroutine/engine/helper.h
new file mode 100644
index 0000000000..ec2711ba52
--- /dev/null
+++ b/library/cpp/coroutine/engine/helper.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/datetime/base.h>
+
+namespace NCoro {
+
+ // @brief check that address `host`:`port` is connectable
+ bool TryConnect(const TString& host, ui16 port, TDuration timeout = TDuration::Seconds(1));
+
+ // @brief waits until address `host`:`port` became connectable, but not more than timeout
+ // @return true on success, false if timeout exceeded
+ bool WaitUntilConnectable(const TString& host, ui16 port, TDuration timeout);
+
+}
diff --git a/library/cpp/coroutine/engine/impl.cpp b/library/cpp/coroutine/engine/impl.cpp
new file mode 100644
index 0000000000..7ae6f74051
--- /dev/null
+++ b/library/cpp/coroutine/engine/impl.cpp
@@ -0,0 +1,374 @@
+#include "impl.h"
+
+#include "stack/stack_allocator.h"
+#include "stack/stack_guards.h"
+
+#include <util/generic/scope.h>
+#include <util/thread/singleton.h>
+#include <util/stream/format.h>
+#include <util/stream/output.h>
+#include <util/system/yassert.h>
+
+
+TCont::TJoinWait::TJoinWait(TCont& c) noexcept
+ : Cont_(c)
+{}
+
+void TCont::TJoinWait::Wake() noexcept {
+ Cont_.ReSchedule();
+}
+
+TCont::TCont(NCoro::NStack::IAllocator& allocator,
+ uint32_t stackSize,
+ TContExecutor& executor,
+ NCoro::TTrampoline::TFunc func,
+ const char* name) noexcept
+ : Executor_(executor)
+ , Name_(name)
+ , Trampoline_(
+ allocator,
+ stackSize,
+ std::move(func),
+ this
+ )
+{}
+
+
+void TCont::PrintMe(IOutputStream& out) const noexcept {
+ out << "cont("
+ << "name = " << Name_ << ", "
+ << "addr = " << Hex((size_t)this)
+ << ")";
+}
+
+bool TCont::Join(TCont* c, TInstant deadLine) noexcept {
+ TJoinWait ev(*this);
+ c->Waiters_.PushBack(&ev);
+
+ do {
+ if (SleepD(deadLine) == ETIMEDOUT || Cancelled()) {
+ if (!ev.Empty()) {
+ c->Cancel();
+
+ do {
+ Switch();
+ } while (!ev.Empty());
+ }
+
+ return false;
+ }
+ } while (!ev.Empty());
+
+ return true;
+}
+
+int TCont::SleepD(TInstant deadline) noexcept {
+ TTimerEvent event(this, deadline);
+
+ return ExecuteEvent(&event);
+}
+
+void TCont::Switch() noexcept {
+ Executor()->RunScheduler();
+}
+
+void TCont::Yield() noexcept {
+ if (SleepD(TInstant::Zero())) {
+ ReScheduleAndSwitch();
+ }
+}
+
+void TCont::ReScheduleAndSwitch() noexcept {
+ ReSchedule();
+ Switch();
+}
+
+void TCont::Terminate() {
+ while (!Waiters_.Empty()) {
+ Waiters_.PopFront()->Wake();
+ }
+ Executor()->Exit(this);
+}
+
+bool TCont::IAmRunning() const noexcept {
+ return this == Executor()->Running();
+}
+
+void TCont::Cancel() noexcept {
+ if (Cancelled()) {
+ return;
+ }
+
+ Cancelled_ = true;
+
+ if (!IAmRunning()) {
+ ReSchedule();
+ }
+}
+
+void TCont::ReSchedule() noexcept {
+ if (Cancelled()) {
+ // Legacy code may expect a Cancelled coroutine to be scheduled without delay.
+ Executor()->ScheduleExecutionNow(this);
+ } else {
+ Executor()->ScheduleExecution(this);
+ }
+}
+
+
+TContExecutor::TContExecutor(
+ uint32_t defaultStackSize,
+ THolder<IPollerFace> poller,
+ NCoro::IScheduleCallback* scheduleCallback,
+ NCoro::IEnterPollerCallback* enterPollerCallback,
+ NCoro::NStack::EGuard defaultGuard,
+ TMaybe<NCoro::NStack::TPoolAllocatorSettings> poolSettings,
+ NCoro::ITime* time
+)
+ : ScheduleCallback_(scheduleCallback)
+ , EnterPollerCallback_(enterPollerCallback)
+ , DefaultStackSize_(defaultStackSize)
+ , Poller_(std::move(poller))
+ , Time_(time)
+{
+ StackAllocator_ = NCoro::NStack::GetAllocator(poolSettings, defaultGuard);
+}
+
+TContExecutor::~TContExecutor() {
+ Y_VERIFY(Allocated_ == 0, "leaked %u coroutines", (ui32)Allocated_);
+}
+
+void TContExecutor::Execute() noexcept {
+ auto nop = [](void*){};
+ Execute(nop);
+}
+
+void TContExecutor::Execute(TContFunc func, void* arg) noexcept {
+ CreateOwned([=](TCont* cont) {
+ func(cont, arg);
+ }, "sys_main");
+ RunScheduler();
+}
+
+void TContExecutor::WaitForIO() {
+ while (Ready_.Empty() && !WaitQueue_.Empty()) {
+ const auto now = Now();
+
+ // Waking a coroutine puts it into ReadyNext_ list
+ const auto next = WaitQueue_.WakeTimedout(now);
+
+ if (!UserEvents_.Empty()) {
+ TIntrusiveList<IUserEvent> userEvents;
+ userEvents.Swap(UserEvents_);
+ do {
+ userEvents.PopFront()->Execute();
+ } while (!userEvents.Empty());
+ }
+
+ // Polling will return as soon as there is an event to process or a timeout.
+ // If there are woken coroutines we do not want to sleep in the poller
+ // yet still we want to check for new io
+ // to prevent ourselves from locking out of io by constantly waking coroutines.
+
+ if (ReadyNext_.Empty()) {
+ if (EnterPollerCallback_) {
+ EnterPollerCallback_->OnEnterPoller();
+ }
+ Poll(next);
+ if (EnterPollerCallback_) {
+ EnterPollerCallback_->OnExitPoller();
+ }
+ } else if (LastPoll_ + TDuration::MilliSeconds(5) < now) {
+ if (EnterPollerCallback_) {
+ EnterPollerCallback_->OnEnterPoller();
+ }
+ Poll(now);
+ if (EnterPollerCallback_) {
+ EnterPollerCallback_->OnExitPoller();
+ }
+ }
+
+ Ready_.Append(ReadyNext_);
+ }
+}
+
+void TContExecutor::Poll(TInstant deadline) {
+ Poller_.Wait(PollerEvents_, deadline);
+ LastPoll_ = Now();
+
+ // Waking a coroutine puts it into ReadyNext_ list
+ for (auto event : PollerEvents_) {
+ auto* lst = (NCoro::TPollEventList*)event.Data;
+ const int status = event.Status;
+
+ if (status) {
+ for (auto it = lst->Begin(); it != lst->End();) {
+ (it++)->OnPollEvent(status);
+ }
+ } else {
+ const ui16 filter = event.Filter;
+
+ for (auto it = lst->Begin(); it != lst->End();) {
+ if (it->What() & filter) {
+ (it++)->OnPollEvent(0);
+ } else {
+ ++it;
+ }
+ }
+ }
+ }
+}
+
+void TContExecutor::Abort() noexcept {
+ WaitQueue_.Abort();
+ auto visitor = [](TCont* c) {
+ c->Cancel();
+ };
+ Ready_.ForEach(visitor);
+ ReadyNext_.ForEach(visitor);
+}
+
+TCont* TContExecutor::Create(
+ TContFunc func,
+ void* arg,
+ const char* name,
+ TMaybe<ui32> customStackSize
+) noexcept {
+ return CreateOwned([=](TCont* cont) {
+ func(cont, arg);
+ }, name, customStackSize);
+}
+
+TCont* TContExecutor::CreateOwned(
+ NCoro::TTrampoline::TFunc func,
+ const char* name,
+ TMaybe<ui32> customStackSize
+) noexcept {
+ Allocated_ += 1;
+ if (!customStackSize) {
+ customStackSize = DefaultStackSize_;
+ }
+ auto* cont = new TCont(*StackAllocator_, *customStackSize, *this, std::move(func), name);
+ ScheduleExecution(cont);
+ return cont;
+}
+
+NCoro::NStack::TAllocatorStats TContExecutor::GetAllocatorStats() const noexcept {
+ return StackAllocator_->GetStackStats();
+}
+
+void TContExecutor::Release(TCont* cont) noexcept {
+ delete cont;
+ Allocated_ -= 1;
+}
+
+void TContExecutor::ScheduleToDelete(TCont* cont) noexcept {
+ ToDelete_.PushBack(cont);
+}
+
+void TContExecutor::ScheduleExecution(TCont* cont) noexcept {
+ cont->Scheduled_ = true;
+ ReadyNext_.PushBack(cont);
+}
+
+void TContExecutor::ScheduleExecutionNow(TCont* cont) noexcept {
+ cont->Scheduled_ = true;
+ Ready_.PushBack(cont);
+}
+
+namespace {
+ inline TContExecutor*& ThisThreadExecutor() {
+ struct TThisThreadExecutorHolder {
+ TContExecutor* Executor = nullptr;
+ };
+ return FastTlsSingletonWithPriority<TThisThreadExecutorHolder, 0>()->Executor;
+ }
+}
+
+void TContExecutor::DeleteScheduled() noexcept {
+ ToDelete_.ForEach([this](TCont* c) {
+ Release(c);
+ });
+}
+
+TCont* RunningCont() {
+ TContExecutor* thisThreadExecutor = ThisThreadExecutor();
+ return thisThreadExecutor ? thisThreadExecutor->Running() : nullptr;
+}
+
+void TContExecutor::RunScheduler() noexcept {
+ try {
+ TContExecutor* const prev = ThisThreadExecutor();
+ ThisThreadExecutor() = this;
+ TCont* caller = Current_;
+ TExceptionSafeContext* context = caller ? caller->Trampoline_.Context() : &SchedContext_;
+ Y_DEFER {
+ ThisThreadExecutor() = prev;
+ };
+
+ while (true) {
+ if (ScheduleCallback_ && Current_) {
+ ScheduleCallback_->OnUnschedule(*this);
+ }
+
+ WaitForIO();
+ DeleteScheduled();
+ Ready_.Append(ReadyNext_);
+
+ if (Ready_.Empty()) {
+ Current_ = nullptr;
+ if (caller) {
+ context->SwitchTo(&SchedContext_);
+ }
+ break;
+ }
+
+ TCont* cont = Ready_.PopFront();
+
+ if (ScheduleCallback_) {
+ ScheduleCallback_->OnSchedule(*this, *cont);
+ }
+
+ Current_ = cont;
+ cont->Scheduled_ = false;
+ if (cont == caller) {
+ break;
+ }
+ context->SwitchTo(cont->Trampoline_.Context());
+ if (Paused_) {
+ Paused_ = false;
+ Current_ = nullptr;
+ break;
+ }
+ if (caller) {
+ break;
+ }
+ }
+ } catch (...) {
+ TBackTrace::FromCurrentException().PrintTo(Cerr);
+ Y_FAIL("Uncaught exception in the scheduler: %s", CurrentExceptionMessage().c_str());
+ }
+}
+
+void TContExecutor::Pause() {
+ if (auto cont = Running()) {
+ Paused_ = true;
+ ScheduleExecutionNow(cont);
+ cont->SwitchTo(&SchedContext_);
+ }
+}
+
+void TContExecutor::Exit(TCont* cont) noexcept {
+ ScheduleToDelete(cont);
+ cont->SwitchTo(&SchedContext_);
+ Y_FAIL("can not return from exit");
+}
+
+TInstant TContExecutor::Now() {
+ return Y_LIKELY(Time_ == nullptr) ? TInstant::Now() : Time_->Now();
+}
+
+template <>
+void Out<TCont>(IOutputStream& out, const TCont& c) {
+ c.PrintMe(out);
+}
diff --git a/library/cpp/coroutine/engine/impl.h b/library/cpp/coroutine/engine/impl.h
new file mode 100644
index 0000000000..283a96ecf1
--- /dev/null
+++ b/library/cpp/coroutine/engine/impl.h
@@ -0,0 +1,313 @@
+#pragma once
+
+#include "callbacks.h"
+#include "cont_poller.h"
+#include "iostatus.h"
+#include "poller.h"
+#include "stack/stack_common.h"
+#include "trampoline.h"
+#include "custom_time.h"
+
+#include <library/cpp/containers/intrusive_rb_tree/rb_tree.h>
+
+#include <util/system/error.h>
+#include <util/generic/ptr.h>
+#include <util/generic/intrlist.h>
+#include <util/datetime/base.h>
+#include <util/generic/maybe.h>
+#include <util/generic/function.h>
+
+
+#define EWAKEDUP 34567
+
+class TCont;
+struct TContRep;
+class TContExecutor;
+class TContPollEvent;
+
+namespace NCoro::NStack {
+ class IAllocator;
+}
+
+class TCont : private TIntrusiveListItem<TCont> {
+ struct TJoinWait: public TIntrusiveListItem<TJoinWait> {
+ TJoinWait(TCont& c) noexcept;
+
+ void Wake() noexcept;
+
+ public:
+ TCont& Cont_;
+ };
+
+ friend class TContExecutor;
+ friend class TIntrusiveListItem<TCont>;
+ friend class NCoro::TEventWaitQueue;
+ friend class NCoro::TTrampoline;
+
+private:
+ TCont(
+ NCoro::NStack::IAllocator& allocator,
+ uint32_t stackSize,
+ TContExecutor& executor,
+ NCoro::TTrampoline::TFunc func,
+ const char* name
+ ) noexcept;
+
+public:
+ TContExecutor* Executor() noexcept {
+ return &Executor_;
+ }
+
+ const TContExecutor* Executor() const noexcept {
+ return &Executor_;
+ }
+
+ const char* Name() const noexcept {
+ return Name_;
+ }
+
+ void PrintMe(IOutputStream& out) const noexcept;
+
+ void Yield() noexcept;
+
+ void ReScheduleAndSwitch() noexcept;
+
+ /// @return ETIMEDOUT on success
+ int SleepD(TInstant deadline) noexcept;
+
+ int SleepT(TDuration timeout) noexcept {
+ return SleepD(timeout.ToDeadLine());
+ }
+
+ int SleepI() noexcept {
+ return SleepD(TInstant::Max());
+ }
+
+ bool IAmRunning() const noexcept;
+
+ void Cancel() noexcept;
+
+ bool Cancelled() const noexcept {
+ return Cancelled_;
+ }
+
+ bool Scheduled() const noexcept {
+ return Scheduled_;
+ }
+
+ bool Join(TCont* c, TInstant deadLine = TInstant::Max()) noexcept;
+
+ void ReSchedule() noexcept;
+
+ void Switch() noexcept;
+
+ void SwitchTo(TExceptionSafeContext* ctx) {
+ Trampoline_.SwitchTo(ctx);
+ }
+
+private:
+ void Terminate();
+
+private:
+ TContExecutor& Executor_;
+
+ // TODO(velavokr): allow name storage owning (for generated names backed by TString)
+ const char* Name_ = nullptr;
+
+ NCoro::TTrampoline Trampoline_;
+
+ TIntrusiveList<TJoinWait> Waiters_;
+ bool Cancelled_ = false;
+ bool Scheduled_ = false;
+};
+
+TCont* RunningCont();
+
+
+template <class Functor>
+static void ContHelperFunc(TCont* cont, void* arg) {
+ (*((Functor*)(arg)))(cont);
+}
+
+template <typename T, void (T::*M)(TCont*)>
+static void ContHelperMemberFunc(TCont* c, void* arg) {
+ ((reinterpret_cast<T*>(arg))->*M)(c);
+}
+
+class IUserEvent
+ : public TIntrusiveListItem<IUserEvent>
+{
+public:
+ virtual ~IUserEvent() = default;
+
+ virtual void Execute() = 0;
+};
+
+/// Central coroutine class.
+/// Note, coroutines are single-threaded, and all methods must be called from the single thread
+class TContExecutor {
+ friend class TCont;
+ using TContList = TIntrusiveList<TCont>;
+
+public:
+ TContExecutor(
+ uint32_t defaultStackSize,
+ THolder<IPollerFace> poller = IPollerFace::Default(),
+ NCoro::IScheduleCallback* = nullptr,
+ NCoro::IEnterPollerCallback* = nullptr,
+ NCoro::NStack::EGuard stackGuard = NCoro::NStack::EGuard::Canary,
+ TMaybe<NCoro::NStack::TPoolAllocatorSettings> poolSettings = Nothing(),
+ NCoro::ITime* time = nullptr
+ );
+
+ ~TContExecutor();
+
+ // if we already have a coroutine to run
+ void Execute() noexcept;
+
+ void Execute(TContFunc func, void* arg = nullptr) noexcept;
+
+ template <class Functor>
+ void Execute(Functor& f) noexcept {
+ Execute((TContFunc)ContHelperFunc<Functor>, (void*)&f);
+ }
+
+ template <typename T, void (T::*M)(TCont*)>
+ void Execute(T* obj) noexcept {
+ Execute(ContHelperMemberFunc<T, M>, obj);
+ }
+
+ template <class Functor>
+ TCont* Create(
+ Functor& f,
+ const char* name,
+ TMaybe<ui32> customStackSize = Nothing()
+ ) noexcept {
+ return Create((TContFunc)ContHelperFunc<Functor>, (void*)&f, name, customStackSize);
+ }
+
+ template <typename T, void (T::*M)(TCont*)>
+ TCont* Create(
+ T* obj,
+ const char* name,
+ TMaybe<ui32> customStackSize = Nothing()
+ ) noexcept {
+ return Create(ContHelperMemberFunc<T, M>, obj, name, customStackSize);
+ }
+
+ TCont* Create(
+ TContFunc func,
+ void* arg,
+ const char* name,
+ TMaybe<ui32> customStackSize = Nothing()
+ ) noexcept;
+
+ TCont* CreateOwned(
+ NCoro::TTrampoline::TFunc func,
+ const char* name,
+ TMaybe<ui32> customStackSize = Nothing()
+ ) noexcept;
+
+ NCoro::TContPoller* Poller() noexcept {
+ return &Poller_;
+ }
+
+ TCont* Running() noexcept {
+ return Current_;
+ }
+
+ const TCont* Running() const noexcept {
+ return Current_;
+ }
+
+ size_t TotalReadyConts() const noexcept {
+ return Ready_.Size() + TotalScheduledConts();
+ }
+
+ size_t TotalScheduledConts() const noexcept {
+ return ReadyNext_.Size();
+ }
+
+ size_t TotalConts() const noexcept {
+ return Allocated_;
+ }
+
+ size_t TotalWaitingConts() const noexcept {
+ return TotalConts() - TotalReadyConts();
+ }
+
+ NCoro::NStack::TAllocatorStats GetAllocatorStats() const noexcept;
+
+ // TODO(velavokr): rename, it is just CancelAll actually
+ void Abort() noexcept;
+
+ void SetFailOnError(bool fail) noexcept {
+ FailOnError_ = fail;
+ }
+
+ bool FailOnError() const noexcept {
+ return FailOnError_;
+ }
+
+ void RegisterInWaitQueue(NCoro::TContPollEvent* event) {
+ WaitQueue_.Register(event);
+ }
+
+ void ScheduleIoWait(TFdEvent* event) {
+ RegisterInWaitQueue(event);
+ Poller_.Schedule(event);
+ }
+
+ void ScheduleIoWait(TTimerEvent* event) noexcept {
+ RegisterInWaitQueue(event);
+ }
+
+ void ScheduleUserEvent(IUserEvent* event) {
+ UserEvents_.PushBack(event);
+ }
+
+ void Pause();
+ TInstant Now();
+private:
+ void Release(TCont* cont) noexcept;
+
+ void Exit(TCont* cont) noexcept;
+
+ void RunScheduler() noexcept;
+
+ void ScheduleToDelete(TCont* cont) noexcept;
+
+ void ScheduleExecution(TCont* cont) noexcept;
+
+ void ScheduleExecutionNow(TCont* cont) noexcept;
+
+ void DeleteScheduled() noexcept;
+
+ void WaitForIO();
+
+ void Poll(TInstant deadline);
+
+private:
+ NCoro::IScheduleCallback* const ScheduleCallback_ = nullptr;
+ NCoro::IEnterPollerCallback* const EnterPollerCallback_ = nullptr;
+ const uint32_t DefaultStackSize_;
+ THolder<NCoro::NStack::IAllocator> StackAllocator_;
+
+ TExceptionSafeContext SchedContext_;
+
+ TContList ToDelete_;
+ TContList Ready_;
+ TContList ReadyNext_;
+ NCoro::TEventWaitQueue WaitQueue_;
+ NCoro::TContPoller Poller_;
+ NCoro::TContPoller::TEvents PollerEvents_;
+ TInstant LastPoll_;
+
+ TIntrusiveList<IUserEvent> UserEvents_;
+
+ size_t Allocated_ = 0;
+ TCont* Current_ = nullptr;
+ bool FailOnError_ = false;
+ bool Paused_ = false;
+ NCoro::ITime* Time_ = nullptr;
+};
diff --git a/library/cpp/coroutine/engine/iostatus.cpp b/library/cpp/coroutine/engine/iostatus.cpp
new file mode 100644
index 0000000000..8298229b39
--- /dev/null
+++ b/library/cpp/coroutine/engine/iostatus.cpp
@@ -0,0 +1 @@
+#include "iostatus.h"
diff --git a/library/cpp/coroutine/engine/iostatus.h b/library/cpp/coroutine/engine/iostatus.h
new file mode 100644
index 0000000000..bf6036805d
--- /dev/null
+++ b/library/cpp/coroutine/engine/iostatus.h
@@ -0,0 +1,91 @@
+#pragma once
+
+#include <util/generic/yexception.h>
+
+class TIOStatus {
+public:
+ TIOStatus(int status) noexcept
+ : Status_(status)
+ {
+ }
+
+ static TIOStatus Error(int status) noexcept {
+ return TIOStatus(status);
+ }
+
+ static TIOStatus Error() noexcept {
+ return TIOStatus(LastSystemError());
+ }
+
+ static TIOStatus Success() noexcept {
+ return TIOStatus(0);
+ }
+
+ void Check() const {
+ if (Status_) {
+ ythrow TSystemError(Status_) << "io error";
+ }
+ }
+
+ bool Failed() const noexcept {
+ return (bool)Status_;
+ }
+
+ bool Succeed() const noexcept {
+ return !Failed();
+ }
+
+ int Status() const noexcept {
+ return Status_;
+ }
+
+private:
+ int Status_;
+};
+
+
+class TContIOStatus {
+public:
+ TContIOStatus(size_t processed, TIOStatus status) noexcept
+ : Processed_(processed)
+ , Status_(status)
+ {
+ }
+
+ static TContIOStatus Error(TIOStatus status) noexcept {
+ return TContIOStatus(0, status);
+ }
+
+ static TContIOStatus Error() noexcept {
+ return TContIOStatus(0, TIOStatus::Error());
+ }
+
+ static TContIOStatus Success(size_t processed) noexcept {
+ return TContIOStatus(processed, TIOStatus::Success());
+ }
+
+ static TContIOStatus Eof() noexcept {
+ return Success(0);
+ }
+
+ ~TContIOStatus() {
+ }
+
+ size_t Processed() const noexcept {
+ return Processed_;
+ }
+
+ int Status() const noexcept {
+ return Status_.Status();
+ }
+
+ size_t Checked() const {
+ Status_.Check();
+
+ return Processed_;
+ }
+
+private:
+ size_t Processed_;
+ TIOStatus Status_;
+};
diff --git a/library/cpp/coroutine/engine/mutex.h b/library/cpp/coroutine/engine/mutex.h
new file mode 100644
index 0000000000..93e9119503
--- /dev/null
+++ b/library/cpp/coroutine/engine/mutex.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "impl.h"
+#include "events.h"
+
+class TContMutex {
+public:
+ TContMutex() noexcept
+ : Token_(true)
+ {
+ }
+
+ ~TContMutex() {
+ Y_ASSERT(Token_);
+ }
+
+ int LockD(TCont* current, TInstant deadline) {
+ while (!Token_) {
+ const int ret = WaitQueue_.WaitD(current, deadline);
+
+ if (ret != EWAKEDUP) {
+ return ret;
+ }
+ }
+
+ Token_ = false;
+
+ return 0;
+ }
+
+ int LockT(TCont* current, TDuration timeout) {
+ return LockD(current, timeout.ToDeadLine());
+ }
+
+ int LockI(TCont* current) {
+ return LockD(current, TInstant::Max());
+ }
+
+ void UnLock() noexcept {
+ Y_ASSERT(!Token_);
+
+ Token_ = true;
+ WaitQueue_.Signal();
+ }
+
+private:
+ TContWaitQueue WaitQueue_;
+ bool Token_;
+};
diff --git a/library/cpp/coroutine/engine/network.cpp b/library/cpp/coroutine/engine/network.cpp
new file mode 100644
index 0000000000..85b647d210
--- /dev/null
+++ b/library/cpp/coroutine/engine/network.cpp
@@ -0,0 +1,325 @@
+#include "impl.h"
+#include "network.h"
+
+#include <util/generic/scope.h>
+#include <util/generic/xrange.h>
+
+#include <sys/uio.h>
+
+#if defined(_bionic_)
+# define IOV_MAX 1024
+#endif
+
+
+namespace NCoro {
+ namespace {
+ bool IsBlocked(int lasterr) noexcept {
+ return lasterr == EAGAIN || lasterr == EWOULDBLOCK;
+ }
+
+ ssize_t DoReadVector(SOCKET fd, TContIOVector* vec) noexcept {
+ return readv(fd, (const iovec*) vec->Parts(), Min(IOV_MAX, (int) vec->Count()));
+ }
+
+ ssize_t DoWriteVector(SOCKET fd, TContIOVector* vec) noexcept {
+ return writev(fd, (const iovec*) vec->Parts(), Min(IOV_MAX, (int) vec->Count()));
+ }
+ }
+
+
+ int SelectD(TCont* cont, SOCKET fds[], int what[], size_t nfds, SOCKET* outfd, TInstant deadline) noexcept {
+ if (cont->Cancelled()) {
+ return ECANCELED;
+ }
+
+ if (nfds == 0) {
+ return 0;
+ }
+
+ TTempArray<TFdEvent> events(nfds);
+
+ for (auto i : xrange(nfds)) {
+ new(events.Data() + i) TFdEvent(cont, fds[i], (ui16) what[i], deadline);
+ }
+
+ Y_DEFER {
+ for (auto i : xrange(nfds)) {
+ (events.Data() + i)->~TFdEvent();
+ }
+ };
+
+ for (auto i : xrange(nfds)) {
+ cont->Executor()->ScheduleIoWait(events.Data() + i);
+ }
+ cont->Switch();
+
+ if (cont->Cancelled()) {
+ return ECANCELED;
+ }
+
+ TFdEvent* ret = nullptr;
+ int status = EINPROGRESS;
+
+ for (auto i : xrange(nfds)) {
+ auto& ev = *(events.Data() + i);
+ switch (ev.Status()) {
+ case EINPROGRESS:
+ break;
+ case ETIMEDOUT:
+ if (status != EINPROGRESS) {
+ break;
+ }
+ [[fallthrough]];
+ default:
+ status = ev.Status();
+ ret = &ev;
+ }
+ }
+
+ if (ret) {
+ if (outfd) {
+ *outfd = ret->Fd();
+ }
+ return ret->Status();
+ }
+
+ return EINPROGRESS;
+ }
+
+ int SelectT(TCont* cont, SOCKET fds[], int what[], size_t nfds, SOCKET* outfd, TDuration timeout) noexcept {
+ return SelectD(cont, fds, what, nfds, outfd, timeout.ToDeadLine());
+ }
+
+ int SelectI(TCont* cont, SOCKET fds[], int what[], size_t nfds, SOCKET* outfd) {
+ return SelectD(cont, fds, what, nfds, outfd, TInstant::Max());
+ }
+
+
+ int PollD(TCont* cont, SOCKET fd, int what, TInstant deadline) noexcept {
+ TFdEvent event(cont, fd, (ui16)what, deadline);
+ return ExecuteEvent(&event);
+ }
+
+ int PollT(TCont* cont, SOCKET fd, int what, TDuration timeout) noexcept {
+ return PollD(cont, fd, what, timeout.ToDeadLine());
+ }
+
+ int PollI(TCont* cont, SOCKET fd, int what) noexcept {
+ return PollD(cont, fd, what, TInstant::Max());
+ }
+
+
+ TContIOStatus ReadVectorD(TCont* cont, SOCKET fd, TContIOVector* vec, TInstant deadline) noexcept {
+ while (true) {
+ ssize_t res = DoReadVector(fd, vec);
+
+ if (res >= 0) {
+ return TContIOStatus::Success((size_t) res);
+ }
+
+ {
+ const int err = LastSystemError();
+
+ if (!IsBlocked(err)) {
+ return TContIOStatus::Error(err);
+ }
+ }
+
+ if ((res = PollD(cont, fd, CONT_POLL_READ, deadline)) != 0) {
+ return TContIOStatus::Error((int) res);
+ }
+ }
+ }
+
+ TContIOStatus ReadVectorT(TCont* cont, SOCKET fd, TContIOVector* vec, TDuration timeOut) noexcept {
+ return ReadVectorD(cont, fd, vec, timeOut.ToDeadLine());
+ }
+
+ TContIOStatus ReadVectorI(TCont* cont, SOCKET fd, TContIOVector* vec) noexcept {
+ return ReadVectorD(cont, fd, vec, TInstant::Max());
+ }
+
+
+ TContIOStatus ReadD(TCont* cont, SOCKET fd, void* buf, size_t len, TInstant deadline) noexcept {
+ IOutputStream::TPart part(buf, len);
+ TContIOVector vec(&part, 1);
+ return ReadVectorD(cont, fd, &vec, deadline);
+ }
+
+ TContIOStatus ReadT(TCont* cont, SOCKET fd, void* buf, size_t len, TDuration timeout) noexcept {
+ return ReadD(cont, fd, buf, len, timeout.ToDeadLine());
+ }
+
+ TContIOStatus ReadI(TCont* cont, SOCKET fd, void* buf, size_t len) noexcept {
+ return ReadD(cont, fd, buf, len, TInstant::Max());
+ }
+
+
+ TContIOStatus WriteVectorD(TCont* cont, SOCKET fd, TContIOVector* vec, TInstant deadline) noexcept {
+ size_t written = 0;
+
+ while (!vec->Complete()) {
+ ssize_t res = DoWriteVector(fd, vec);
+
+ if (res >= 0) {
+ written += res;
+
+ vec->Proceed((size_t) res);
+ } else {
+ {
+ const int err = LastSystemError();
+
+ if (!IsBlocked(err)) {
+ return TContIOStatus(written, err);
+ }
+ }
+
+ if ((res = PollD(cont, fd, CONT_POLL_WRITE, deadline)) != 0) {
+ return TContIOStatus(written, (int) res);
+ }
+ }
+ }
+
+ return TContIOStatus::Success(written);
+ }
+
+ TContIOStatus WriteVectorT(TCont* cont, SOCKET fd, TContIOVector* vec, TDuration timeOut) noexcept {
+ return WriteVectorD(cont, fd, vec, timeOut.ToDeadLine());
+ }
+
+ TContIOStatus WriteVectorI(TCont* cont, SOCKET fd, TContIOVector* vec) noexcept {
+ return WriteVectorD(cont, fd, vec, TInstant::Max());
+ }
+
+
+ TContIOStatus WriteD(TCont* cont, SOCKET fd, const void* buf, size_t len, TInstant deadline) noexcept {
+ IOutputStream::TPart part(buf, len);
+ TContIOVector vec(&part, 1);
+ return WriteVectorD(cont, fd, &vec, deadline);
+ }
+
+ TContIOStatus WriteT(TCont* cont, SOCKET fd, const void* buf, size_t len, TDuration timeout) noexcept {
+ return WriteD(cont, fd, buf, len, timeout.ToDeadLine());
+ }
+
+ TContIOStatus WriteI(TCont* cont, SOCKET fd, const void* buf, size_t len) noexcept {
+ return WriteD(cont, fd, buf, len, TInstant::Max());
+ }
+
+
+ int ConnectD(TCont* cont, TSocketHolder& s, const struct addrinfo& ai, TInstant deadline) noexcept {
+ TSocketHolder res(Socket(ai));
+
+ if (res.Closed()) {
+ return LastSystemError();
+ }
+
+ const int ret = ConnectD(cont, res, ai.ai_addr, (socklen_t) ai.ai_addrlen, deadline);
+
+ if (!ret) {
+ s.Swap(res);
+ }
+
+ return ret;
+ }
+
+ int ConnectD(TCont* cont, TSocketHolder& s, const TNetworkAddress& addr, TInstant deadline) noexcept {
+ int ret = EHOSTUNREACH;
+
+ for (auto it = addr.Begin(); it != addr.End(); ++it) {
+ ret = ConnectD(cont, s, *it, deadline);
+
+ if (ret == 0 || ret == ETIMEDOUT) {
+ return ret;
+ }
+ }
+
+ return ret;
+ }
+
+ int ConnectT(TCont* cont, TSocketHolder& s, const TNetworkAddress& addr, TDuration timeout) noexcept {
+ return ConnectD(cont, s, addr, timeout.ToDeadLine());
+ }
+
+ int ConnectI(TCont* cont, TSocketHolder& s, const TNetworkAddress& addr) noexcept {
+ return ConnectD(cont, s, addr, TInstant::Max());
+ }
+
+ int ConnectD(TCont* cont, SOCKET s, const struct sockaddr* name, socklen_t namelen, TInstant deadline) noexcept {
+ if (connect(s, name, namelen)) {
+ const int err = LastSystemError();
+
+ if (!IsBlocked(err) && err != EINPROGRESS) {
+ return err;
+ }
+
+ int ret = PollD(cont, s, CONT_POLL_WRITE, deadline);
+
+ if (ret) {
+ return ret;
+ }
+
+ // check if we really connected
+ // FIXME: Unportable ??
+ int serr = 0;
+ socklen_t slen = sizeof(serr);
+
+ ret = getsockopt(s, SOL_SOCKET, SO_ERROR, (char*) &serr, &slen);
+
+ if (ret) {
+ return LastSystemError();
+ }
+
+ if (serr) {
+ return serr;
+ }
+ }
+
+ return 0;
+ }
+
+ int ConnectT(TCont* cont, SOCKET s, const struct sockaddr* name, socklen_t namelen, TDuration timeout) noexcept {
+ return ConnectD(cont, s, name, namelen, timeout.ToDeadLine());
+ }
+
+ int ConnectI(TCont* cont, SOCKET s, const struct sockaddr* name, socklen_t namelen) noexcept {
+ return ConnectD(cont, s, name, namelen, TInstant::Max());
+ }
+
+
+ int AcceptD(TCont* cont, SOCKET s, struct sockaddr* addr, socklen_t* addrlen, TInstant deadline) noexcept {
+ SOCKET ret;
+
+ while ((ret = Accept4(s, addr, addrlen)) == INVALID_SOCKET) {
+ int err = LastSystemError();
+
+ if (!IsBlocked(err)) {
+ return -err;
+ }
+
+ err = PollD(cont, s, CONT_POLL_READ, deadline);
+
+ if (err) {
+ return -err;
+ }
+ }
+
+ return (int) ret;
+ }
+
+ int AcceptT(TCont* cont, SOCKET s, struct sockaddr* addr, socklen_t* addrlen, TDuration timeout) noexcept {
+ return AcceptD(cont, s, addr, addrlen, timeout.ToDeadLine());
+ }
+
+ int AcceptI(TCont* cont, SOCKET s, struct sockaddr* addr, socklen_t* addrlen) noexcept {
+ return AcceptD(cont, s, addr, addrlen, TInstant::Max());
+ }
+
+ SOCKET Socket(int domain, int type, int protocol) noexcept {
+ return Socket4(domain, type, protocol);
+ }
+
+ SOCKET Socket(const struct addrinfo& ai) noexcept {
+ return Socket(ai.ai_family, ai.ai_socktype, ai.ai_protocol);
+ }
+}
diff --git a/library/cpp/coroutine/engine/network.h b/library/cpp/coroutine/engine/network.h
new file mode 100644
index 0000000000..f2c9afe4f8
--- /dev/null
+++ b/library/cpp/coroutine/engine/network.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "iostatus.h"
+
+#include <util/datetime/base.h>
+#include <util/network/init.h>
+#include <util/network/iovec.h>
+#include <util/network/nonblock.h>
+#include <util/network/socket.h>
+
+class TCont;
+
+namespace NCoro {
+
+ int SelectD(TCont* cont, SOCKET fds[], int what[], size_t nfds, SOCKET* outfd, TInstant deadline) noexcept;
+ int SelectT(TCont* cont, SOCKET fds[], int what[], size_t nfds, SOCKET* outfd, TDuration timeout) noexcept;
+ int SelectI(TCont* cont, SOCKET fds[], int what[], size_t nfds, SOCKET* outfd);
+
+ int PollD(TCont* cont, SOCKET fd, int what, TInstant deadline) noexcept;
+ int PollT(TCont* cont, SOCKET fd, int what, TDuration timeout) noexcept;
+ int PollI(TCont* cont, SOCKET fd, int what) noexcept;
+
+ TContIOStatus ReadVectorD(TCont* cont, SOCKET fd, TContIOVector* vec, TInstant deadline) noexcept;
+ TContIOStatus ReadVectorT(TCont* cont, SOCKET fd, TContIOVector* vec, TDuration timeOut) noexcept;
+ TContIOStatus ReadVectorI(TCont* cont, SOCKET fd, TContIOVector* vec) noexcept;
+
+ TContIOStatus ReadD(TCont* cont, SOCKET fd, void* buf, size_t len, TInstant deadline) noexcept;
+ TContIOStatus ReadT(TCont* cont, SOCKET fd, void* buf, size_t len, TDuration timeout) noexcept;
+ TContIOStatus ReadI(TCont* cont, SOCKET fd, void* buf, size_t len) noexcept;
+
+ TContIOStatus WriteVectorD(TCont* cont, SOCKET fd, TContIOVector* vec, TInstant deadline) noexcept;
+ TContIOStatus WriteVectorT(TCont* cont, SOCKET fd, TContIOVector* vec, TDuration timeOut) noexcept;
+ TContIOStatus WriteVectorI(TCont* cont, SOCKET fd, TContIOVector* vec) noexcept;
+
+ TContIOStatus WriteD(TCont* cont, SOCKET fd, const void* buf, size_t len, TInstant deadline) noexcept;
+ TContIOStatus WriteT(TCont* cont, SOCKET fd, const void* buf, size_t len, TDuration timeout) noexcept;
+ TContIOStatus WriteI(TCont* cont, SOCKET fd, const void* buf, size_t len) noexcept;
+
+ int ConnectD(TCont* cont, TSocketHolder& s, const struct addrinfo& ai, TInstant deadline) noexcept;
+
+ int ConnectD(TCont* cont, TSocketHolder& s, const TNetworkAddress& addr, TInstant deadline) noexcept;
+ int ConnectT(TCont* cont, TSocketHolder& s, const TNetworkAddress& addr, TDuration timeout) noexcept;
+ int ConnectI(TCont* cont, TSocketHolder& s, const TNetworkAddress& addr) noexcept;
+
+ int ConnectD(TCont* cont, SOCKET s, const struct sockaddr* name, socklen_t namelen, TInstant deadline) noexcept;
+ int ConnectT(TCont* cont, SOCKET s, const struct sockaddr* name, socklen_t namelen, TDuration timeout) noexcept;
+ int ConnectI(TCont* cont, SOCKET s, const struct sockaddr* name, socklen_t namelen) noexcept;
+
+ int AcceptD(TCont* cont, SOCKET s, struct sockaddr* addr, socklen_t* addrlen, TInstant deadline) noexcept;
+ int AcceptT(TCont* cont, SOCKET s, struct sockaddr* addr, socklen_t* addrlen, TDuration timeout) noexcept;
+ int AcceptI(TCont* cont, SOCKET s, struct sockaddr* addr, socklen_t* addrlen) noexcept;
+
+ SOCKET Socket(int domain, int type, int protocol) noexcept;
+ SOCKET Socket(const struct addrinfo& ai) noexcept;
+}
diff --git a/library/cpp/coroutine/engine/poller.cpp b/library/cpp/coroutine/engine/poller.cpp
new file mode 100644
index 0000000000..61164fa56b
--- /dev/null
+++ b/library/cpp/coroutine/engine/poller.cpp
@@ -0,0 +1,390 @@
+#include "poller.h"
+#include "sockmap.h"
+
+#include <util/memory/smallobj.h>
+#include <util/generic/intrlist.h>
+#include <util/generic/singleton.h>
+#include <util/system/env.h>
+#include <util/string/cast.h>
+
+namespace {
+ using TChange = IPollerFace::TChange;
+ using TEvent = IPollerFace::TEvent;
+ using TEvents = IPollerFace::TEvents;
+
+ template <class T>
+ class TUnsafeBuf {
+ public:
+ TUnsafeBuf() noexcept
+ : L_(0)
+ {
+ }
+
+ T* operator~() const noexcept {
+ return B_.Get();
+ }
+
+ size_t operator+() const noexcept {
+ return L_;
+ }
+
+ void Reserve(size_t len) {
+ len = FastClp2(len);
+
+ if (len > L_) {
+ B_.Reset(new T[len]);
+ L_ = len;
+ }
+ }
+
+ private:
+ TArrayHolder<T> B_;
+ size_t L_;
+ };
+
+
+ template <class T>
+ class TVirtualize: public IPollerFace {
+ public:
+ TVirtualize(EContPoller pollerEngine)
+ : PollerEngine_(pollerEngine)
+ {
+ }
+
+ void Set(const TChange& c) override {
+ P_.Set(c);
+ }
+
+ void Wait(TEvents& events, TInstant deadLine) override {
+ P_.Wait(events, deadLine);
+ }
+
+ EContPoller PollEngine() const override {
+ return PollerEngine_;
+ }
+ private:
+ T P_;
+ const EContPoller PollerEngine_;
+ };
+
+
+ template <class T>
+ class TPoller {
+ using TInternalEvent = typename T::TEvent;
+
+ public:
+ TPoller() {
+ E_.Reserve(1);
+ }
+
+ void Set(const TChange& c) {
+ P_.Set(c.Data, c.Fd, c.Flags);
+ }
+
+ void Reserve(size_t size) {
+ E_.Reserve(size);
+ }
+
+ void Wait(TEvents& events, TInstant deadLine) {
+ const size_t ret = P_.WaitD(~E_, +E_, deadLine);
+
+ events.reserve(ret);
+
+ for (size_t i = 0; i < ret; ++i) {
+ const TInternalEvent* ie = ~E_ + i;
+
+ const TEvent e = {
+ T::ExtractEvent(ie),
+ T::ExtractStatus(ie),
+ (ui16)T::ExtractFilter(ie),
+ };
+
+ events.push_back(e);
+ }
+
+ E_.Reserve(ret + 1);
+ }
+
+ private:
+ T P_;
+ TUnsafeBuf<TInternalEvent> E_;
+ };
+
+
+ template <class T>
+ class TIndexedArray {
+ struct TVal:
+ public T,
+ public TIntrusiveListItem<TVal>,
+ public TObjectFromPool<TVal>
+ {
+ // NOTE Constructor must be user-defined (and not =default) here
+ // because TVal objects are created in the UB-capable placement
+ // TObjectFromPool::new operator that stores data in a memory
+ // allocated for the object. Without user defined constructor
+ // zero-initialization takes place in TVal() expression and the
+ // data is overwritten.
+ TVal() {
+ }
+ };
+
+ typedef TIntrusiveList<TVal> TListType;
+
+ public:
+ typedef typename TListType::TIterator TIterator;
+ typedef typename TListType::TConstIterator TConstIterator;
+
+ TIndexedArray()
+ : P_(TMemoryPool::TExpGrow::Instance(), TDefaultAllocator::Instance())
+ {
+ }
+
+ TIterator Begin() noexcept {
+ return I_.Begin();
+ }
+
+ TIterator End() noexcept {
+ return I_.End();
+ }
+
+ TConstIterator Begin() const noexcept {
+ return I_.Begin();
+ }
+
+ TConstIterator End() const noexcept {
+ return I_.End();
+ }
+
+ T& operator[](size_t i) {
+ return *Get(i);
+ }
+
+ T* Get(size_t i) {
+ TValRef& v = V_.Get(i);
+
+ if (Y_UNLIKELY(!v)) {
+ v.Reset(new (&P_) TVal());
+ I_.PushFront(v.Get());
+ }
+
+ Y_PREFETCH_WRITE(v.Get(), 1);
+
+ return v.Get();
+ }
+
+ void Erase(size_t i) noexcept {
+ V_.Get(i).Destroy();
+ }
+
+ size_t Size() const noexcept {
+ return I_.Size();
+ }
+
+ private:
+ using TValRef = THolder<TVal>;
+ typename TVal::TPool P_;
+ TSocketMap<TValRef> V_;
+ TListType I_;
+ };
+
+
+ inline short PollFlags(ui16 flags) noexcept {
+ short ret = 0;
+
+ if (flags & CONT_POLL_READ) {
+ ret |= POLLIN;
+ }
+
+ if (flags & CONT_POLL_WRITE) {
+ ret |= POLLOUT;
+ }
+
+#if defined(_linux_)
+ if (flags & CONT_POLL_RDHUP) {
+ ret |= POLLRDHUP;
+ }
+#endif
+
+ return ret;
+ }
+
+
+ class TPollPoller {
+ public:
+ size_t Size() const noexcept {
+ return S_.Size();
+ }
+
+ template <class T>
+ void Build(T& t) const {
+ for (TFds::TConstIterator it = S_.Begin(); it != S_.End(); ++it) {
+ t.Set(*it);
+ }
+
+ t.Reserve(Size());
+ }
+
+ void Set(const TChange& c) {
+ if (c.Flags) {
+ S_[c.Fd] = c;
+ } else {
+ S_.Erase(c.Fd);
+ }
+ }
+
+ void Wait(TEvents& events, TInstant deadLine) {
+ T_.clear();
+ T_.reserve(Size());
+
+ for (TFds::TConstIterator it = S_.Begin(); it != S_.End(); ++it) {
+ const pollfd pfd = {
+ it->Fd,
+ PollFlags(it->Flags),
+ 0,
+ };
+
+ T_.push_back(pfd);
+ }
+
+ const ssize_t ret = PollD(T_.data(), (nfds_t) T_.size(), deadLine);
+
+ if (ret <= 0) {
+ return;
+ }
+
+ events.reserve(T_.size());
+
+ for (size_t i = 0; i < T_.size(); ++i) {
+ const pollfd& pfd = T_[i];
+ const short ev = pfd.revents;
+
+ if (!ev) {
+ continue;
+ }
+
+ int status = 0;
+ ui16 filter = 0;
+
+ // We are perfectly fine with an EOF while reading a pipe or a unix socket
+ if ((ev & POLLIN) || (ev & POLLHUP) && (pfd.events & POLLIN)) {
+ filter |= CONT_POLL_READ;
+ }
+
+ if (ev & POLLOUT) {
+ filter |= CONT_POLL_WRITE;
+ }
+
+#if defined(_linux_)
+ if (ev & POLLRDHUP) {
+ filter |= CONT_POLL_RDHUP;
+ }
+#endif
+
+ if (ev & POLLERR) {
+ status = EIO;
+ } else if (ev & POLLHUP && pfd.events & POLLOUT) {
+ // Only write operations may cause EPIPE
+ status = EPIPE;
+ } else if (ev & POLLNVAL) {
+ status = EINVAL;
+ }
+
+ if (status) {
+ filter = CONT_POLL_READ | CONT_POLL_WRITE | CONT_POLL_RDHUP;
+ }
+
+ const TEvent res = {
+ S_[pfd.fd].Data,
+ status,
+ filter,
+ };
+
+ events.push_back(res);
+ }
+ }
+
+ private:
+ typedef TIndexedArray<TChange> TFds;
+ TFds S_;
+ typedef TVector<pollfd> TPollVec;
+ TPollVec T_;
+ };
+
+
+ class TCombinedPoller {
+ typedef TPoller<TPollerImpl<TWithoutLocking>> TDefaultPoller;
+
+ public:
+ TCombinedPoller() {
+ P_.Reset(new TPollPoller());
+ }
+
+ void Set(const TChange& c) {
+ if (!P_) {
+ D_->Set(c);
+ } else {
+ P_->Set(c);
+ }
+ }
+
+ void Wait(TEvents& events, TInstant deadLine) {
+ if (!P_) {
+ D_->Wait(events, deadLine);
+ } else {
+ if (P_->Size() > 200) {
+ D_.Reset(new TDefaultPoller());
+ P_->Build(*D_);
+ P_.Destroy();
+ D_->Wait(events, deadLine);
+ } else {
+ P_->Wait(events, deadLine);
+ }
+ }
+ }
+
+ private:
+ THolder<TPollPoller> P_;
+ THolder<TDefaultPoller> D_;
+ };
+
+ struct TUserPoller: public TString {
+ TUserPoller()
+ : TString(GetEnv("USER_POLLER"))
+ {
+ }
+ };
+}
+
+THolder<IPollerFace> IPollerFace::Default() {
+ return Construct(*SingletonWithPriority<TUserPoller, 0>());
+}
+
+THolder<IPollerFace> IPollerFace::Construct(TStringBuf name) {
+ return Construct(name ? FromString<EContPoller>(name) : EContPoller::Default);
+}
+
+THolder<IPollerFace> IPollerFace::Construct(EContPoller poller) {
+ switch (poller) {
+ case EContPoller::Default:
+ case EContPoller::Combined:
+ return MakeHolder<TVirtualize<TCombinedPoller>>(EContPoller::Combined);
+ case EContPoller::Select:
+ return MakeHolder<TVirtualize<TPoller<TGenericPoller<TSelectPoller<TWithoutLocking>>>>>(poller);
+ case EContPoller::Poll:
+ return MakeHolder<TVirtualize<TPollPoller>>(poller);
+ case EContPoller::Epoll:
+#if defined(HAVE_EPOLL_POLLER)
+ return MakeHolder<TVirtualize<TPoller<TGenericPoller<TEpollPoller<TWithoutLocking>>>>>(poller);
+#else
+ return nullptr;
+#endif
+ case EContPoller::Kqueue:
+#if defined(HAVE_KQUEUE_POLLER)
+ return MakeHolder<TVirtualize<TPoller<TGenericPoller<TKqueuePoller<TWithoutLocking>>>>>(poller);
+#else
+ return nullptr;
+#endif
+ default:
+ Y_FAIL("bad poller type");
+ }
+}
diff --git a/library/cpp/coroutine/engine/poller.h b/library/cpp/coroutine/engine/poller.h
new file mode 100644
index 0000000000..8ea012c0fc
--- /dev/null
+++ b/library/cpp/coroutine/engine/poller.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+#include <util/network/socket.h>
+#include <util/network/pollerimpl.h>
+#include <util/datetime/base.h>
+
+enum class EContPoller {
+ Default /* "default" */,
+ Combined /* "combined" */,
+ Select /* "select" */,
+ Poll /* "poll" */,
+ Epoll /* "epoll" */,
+ Kqueue /* "kqueue" */
+};
+
+class IPollerFace {
+public:
+ struct TChange {
+ SOCKET Fd;
+ void* Data;
+ ui16 Flags;
+ };
+
+ struct TEvent {
+ void* Data;
+ int Status;
+ ui16 Filter;
+ };
+
+ using TEvents = TVector<TEvent>;
+
+ virtual ~IPollerFace() {
+ }
+
+ void Set(void* ptr, SOCKET fd, ui16 flags) {
+ const TChange c = {fd, ptr, flags};
+
+ Set(c);
+ }
+
+ virtual void Set(const TChange& change) = 0;
+ virtual void Wait(TEvents& events, TInstant deadLine) = 0;
+ virtual EContPoller PollEngine() const = 0;
+
+ static THolder<IPollerFace> Default();
+ static THolder<IPollerFace> Construct(TStringBuf name);
+ static THolder<IPollerFace> Construct(EContPoller poller);
+};
diff --git a/library/cpp/coroutine/engine/sockmap.h b/library/cpp/coroutine/engine/sockmap.h
new file mode 100644
index 0000000000..fd189e1774
--- /dev/null
+++ b/library/cpp/coroutine/engine/sockmap.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <util/generic/hash.h>
+#include <util/generic/vector.h>
+
+template <class T>
+class TSocketMap {
+public:
+ T& Get(size_t idx) {
+ if (idx < 128000) {
+ if (V_.size() <= idx) {
+ V_.resize(idx + 1);
+ }
+
+ return V_[idx];
+ }
+
+ return H_[idx];
+ }
+
+private:
+ TVector<T> V_;
+ THashMap<size_t, T> H_;
+};
diff --git a/library/cpp/coroutine/engine/sockpool.cpp b/library/cpp/coroutine/engine/sockpool.cpp
new file mode 100644
index 0000000000..b9482e780f
--- /dev/null
+++ b/library/cpp/coroutine/engine/sockpool.cpp
@@ -0,0 +1,58 @@
+#include "sockpool.h"
+
+void SetCommonSockOpts(SOCKET sock, const struct sockaddr* sa) {
+ SetSockOpt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+
+ if (!sa || sa->sa_family == AF_INET) {
+ sockaddr_in s_in;
+ s_in.sin_family = AF_INET;
+ s_in.sin_addr.s_addr = INADDR_ANY;
+ s_in.sin_port = 0;
+
+ if (bind(sock, (struct sockaddr*)&s_in, sizeof(s_in)) == -1) {
+ warn("bind");
+ }
+ } else if (sa->sa_family == AF_INET6) {
+ sockaddr_in6 s_in6(*(const sockaddr_in6*)sa);
+ Zero(s_in6.sin6_addr);
+ s_in6.sin6_port = 0;
+
+ if (bind(sock, (const struct sockaddr*)&s_in6, sizeof s_in6) == -1) {
+ warn("bind6");
+ }
+ } else {
+ Y_ASSERT(0);
+ }
+
+ SetNoDelay(sock, true);
+}
+
+TPooledSocket TSocketPool::AllocateMore(TConnectData* conn) {
+ TCont* cont = conn->Cont;
+
+ while (true) {
+ TSocketHolder s(NCoro::Socket(Addr_->Addr()->sa_family, SOCK_STREAM, 0));
+
+ if (s == INVALID_SOCKET) {
+ ythrow TSystemError(errno) << TStringBuf("can not create socket");
+ }
+
+ SetCommonSockOpts(s, Addr_->Addr());
+ SetZeroLinger(s);
+
+ const int ret = NCoro::ConnectD(cont, s, Addr_->Addr(), Addr_->Len(), conn->DeadLine);
+
+ if (ret == EINTR) {
+ continue;
+ } else if (ret) {
+ ythrow TSystemError(ret) << TStringBuf("can not connect(") << cont->Name() << ')';
+ }
+
+ THolder<TPooledSocket::TImpl> res(new TPooledSocket::TImpl(s, this));
+ s.Release();
+
+ if (res->IsOpen()) {
+ return res.Release();
+ }
+ }
+}
diff --git a/library/cpp/coroutine/engine/sockpool.h b/library/cpp/coroutine/engine/sockpool.h
new file mode 100644
index 0000000000..1ebb7e7b38
--- /dev/null
+++ b/library/cpp/coroutine/engine/sockpool.h
@@ -0,0 +1,253 @@
+#pragma once
+
+#include "impl.h"
+#include "network.h"
+
+#include <util/network/address.h>
+#include <util/network/socket.h>
+#include <util/system/mutex.h>
+
+extern void SetCommonSockOpts(SOCKET sock, const struct sockaddr* sa = nullptr);
+
+class TSocketPool;
+
+class TPooledSocket {
+ class TImpl: public TIntrusiveListItem<TImpl>, public TSimpleRefCount<TImpl, TImpl> {
+ public:
+ TImpl(SOCKET fd, TSocketPool* pool) noexcept
+ : Pool_(pool)
+ , IsKeepAlive_(false)
+ , Fd_(fd)
+ {
+ Touch();
+ }
+
+ static void Destroy(TImpl* impl) noexcept {
+ impl->DoDestroy();
+ }
+
+ void DoDestroy() noexcept {
+ if (!Closed() && IsKeepAlive() && IsInGoodState()) {
+ ReturnToPool();
+ } else {
+ delete this;
+ }
+ }
+
+ bool IsKeepAlive() const noexcept {
+ return IsKeepAlive_;
+ }
+
+ void SetKeepAlive(bool ka) {
+ ::SetKeepAlive(Fd_, ka);
+ IsKeepAlive_ = ka;
+ }
+
+ SOCKET Socket() const noexcept {
+ return Fd_;
+ }
+
+ bool Closed() const noexcept {
+ return Fd_.Closed();
+ }
+
+ void Close() noexcept {
+ Fd_.Close();
+ }
+
+ bool IsInGoodState() const noexcept {
+ int err = 0;
+ socklen_t len = sizeof(err);
+
+ getsockopt(Fd_, SOL_SOCKET, SO_ERROR, (char*)&err, &len);
+
+ return !err;
+ }
+
+ bool IsOpen() const noexcept {
+ return IsInGoodState() && IsNotSocketClosedByOtherSide(Fd_);
+ }
+
+ void Touch() noexcept {
+ TouchTime_ = TInstant::Now();
+ }
+
+ const TInstant& LastTouch() const noexcept {
+ return TouchTime_;
+ }
+
+ private:
+ inline void ReturnToPool() noexcept;
+
+ private:
+ TSocketPool* Pool_;
+ bool IsKeepAlive_;
+ TSocketHolder Fd_;
+ TInstant TouchTime_;
+ };
+
+ friend class TSocketPool;
+
+public:
+ TPooledSocket()
+ : Impl_(nullptr)
+ {
+ }
+
+ TPooledSocket(TImpl* impl)
+ : Impl_(impl)
+ {
+ }
+
+ ~TPooledSocket() {
+ if (UncaughtException() && !!Impl_) {
+ Close();
+ }
+ }
+
+ operator SOCKET() const noexcept {
+ return Impl_->Socket();
+ }
+
+ void SetKeepAlive(bool ka) {
+ Impl_->SetKeepAlive(ka);
+ }
+
+ void Close() noexcept {
+ Impl_->Close();
+ }
+
+private:
+ TIntrusivePtr<TImpl> Impl_;
+};
+
+struct TConnectData {
+ TConnectData(TCont* cont, const TInstant& deadLine)
+ : Cont(cont)
+ , DeadLine(deadLine)
+ {
+ }
+
+ TConnectData(TCont* cont, const TDuration& timeOut)
+ : Cont(cont)
+ , DeadLine(TInstant::Now() + timeOut)
+ {
+ }
+
+ TCont* Cont;
+ const TInstant DeadLine;
+};
+
+class TSocketPool {
+ friend class TPooledSocket::TImpl;
+
+public:
+ typedef TAtomicSharedPtr<NAddr::IRemoteAddr> TAddrRef;
+
+ TSocketPool(int ip, int port)
+ : Addr_(new NAddr::TIPv4Addr(TIpAddress((ui32)ip, (ui16)port)))
+ {
+ }
+
+ TSocketPool(const TAddrRef& addr)
+ : Addr_(addr)
+ {
+ }
+
+ void EraseStale(const TInstant& maxAge) noexcept {
+ TSockets toDelete;
+
+ {
+ TGuard<TMutex> guard(Mutex_);
+
+ for (TSockets::TIterator it = Pool_.Begin(); it != Pool_.End();) {
+ if (it->LastTouch() < maxAge) {
+ toDelete.PushBack(&*(it++));
+ } else {
+ ++it;
+ }
+ }
+ }
+ }
+
+ TPooledSocket Get(TConnectData* conn) {
+ TPooledSocket ret;
+
+ if (TPooledSocket::TImpl* alive = GetImpl()) {
+ ret = TPooledSocket(alive);
+ } else {
+ ret = AllocateMore(conn);
+ }
+
+ ret.Impl_->Touch();
+
+ return ret;
+ }
+
+ bool GetAlive(TPooledSocket& socket) {
+ if (TPooledSocket::TImpl* alive = GetImpl()) {
+ alive->Touch();
+ socket = TPooledSocket(alive);
+ return true;
+ }
+ return false;
+ }
+
+private:
+ TPooledSocket::TImpl* GetImpl() {
+ TGuard<TMutex> guard(Mutex_);
+
+ while (!Pool_.Empty()) {
+ THolder<TPooledSocket::TImpl> ret(Pool_.PopFront());
+
+ if (ret->IsOpen()) {
+ return ret.Release();
+ }
+ }
+ return nullptr;
+ }
+
+ void Release(TPooledSocket::TImpl* impl) noexcept {
+ TGuard<TMutex> guard(Mutex_);
+
+ Pool_.PushFront(impl);
+ }
+
+ TPooledSocket AllocateMore(TConnectData* conn);
+
+private:
+ TAddrRef Addr_;
+ using TSockets = TIntrusiveListWithAutoDelete<TPooledSocket::TImpl, TDelete>;
+ TSockets Pool_;
+ TMutex Mutex_;
+};
+
+inline void TPooledSocket::TImpl::ReturnToPool() noexcept {
+ Pool_->Release(this);
+}
+
+
+class TContIO: public IInputStream, public IOutputStream {
+public:
+ TContIO(SOCKET fd, TCont* cont)
+ : Fd_(fd)
+ , Cont_(cont)
+ {
+ }
+
+ void DoWrite(const void* buf, size_t len) override {
+ NCoro::WriteI(Cont_, Fd_, buf, len).Checked();
+ }
+
+ size_t DoRead(void* buf, size_t len) override {
+ return NCoro::ReadI(Cont_, Fd_, buf, len).Checked();
+ }
+
+ SOCKET Fd() const noexcept {
+ return Fd_;
+ }
+
+private:
+ SOCKET Fd_;
+ TCont* Cont_;
+};
diff --git a/library/cpp/coroutine/engine/stack/benchmark/alloc_bm.cpp b/library/cpp/coroutine/engine/stack/benchmark/alloc_bm.cpp
new file mode 100644
index 0000000000..38d713d274
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/benchmark/alloc_bm.cpp
@@ -0,0 +1,316 @@
+#include <benchmark/benchmark.h>
+
+#include <util/generic/vector.h>
+#include <util/system/yassert.h>
+
+#include <library/cpp/coroutine/engine/stack/stack_allocator.h>
+#include <library/cpp/coroutine/engine/stack/stack_guards.h>
+#include <library/cpp/coroutine/engine/stack/stack_pool.h>
+#include <library/cpp/coroutine/engine/stack/stack_utils.h>
+
+
+namespace NCoro::NStack::NBenchmark {
+
+ const char* TestCoroName = "any_name";
+ constexpr uint64_t BigCoroSize = PageSize * 25;
+ constexpr uint64_t SmallCoroSize = PageSize * 4;
+ constexpr uint64_t ManyStacks = 4096;
+
+ void BasicOperations(TStackHolder& stack) {
+ Y_VERIFY(!stack.Get().empty());
+ stack.LowerCanaryOk();
+ stack.UpperCanaryOk();
+ }
+
+ void WriteStack(TStackHolder& stack) {
+ auto memory = stack.Get();
+ Y_VERIFY(!memory.empty());
+ stack.LowerCanaryOk();
+ stack.UpperCanaryOk();
+ for (uint64_t i = PageSize / 2; i < memory.size(); i += PageSize * 2) {
+ memory[i] = 42;
+ }
+ }
+
+ static void BM_GetAlignedMemory(benchmark::State& state) {
+ char* raw = nullptr;
+ char* aligned = nullptr;
+ for (auto _ : state) {
+ if (NCoro::NStack::GetAlignedMemory(state.range(0), raw, aligned)) {
+ free(raw);
+ }
+ }
+ }
+ BENCHMARK(BM_GetAlignedMemory)->RangeMultiplier(16)->Range(1, 1024 * 1024);
+
+ static void BM_GetAlignedMemoryReleaseRss(benchmark::State& state) {
+ char* raw = nullptr;
+ char* aligned = nullptr;
+ for (auto _ : state) {
+ if (NCoro::NStack::GetAlignedMemory(state.range(0), raw, aligned)) {
+ const auto toFree = state.range(0) > 2 ? state.range(0) - 2 : 1;
+ ReleaseRss(aligned, toFree);
+ free(raw);
+ }
+ }
+ }
+ BENCHMARK(BM_GetAlignedMemoryReleaseRss)->RangeMultiplier(16)->Range(1, 1024 * 1024);
+
+ static void BM_PoolAllocator(benchmark::State& state) {
+ auto allocator = GetAllocator(TPoolAllocatorSettings{}, (EGuard)state.range(0));
+ for (auto _ : state) {
+ TStackHolder stack(*allocator, state.range(1), TestCoroName);
+ BasicOperations(stack);
+ }
+ }
+ BENCHMARK(BM_PoolAllocator)
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize}) // old version - ArgsProduct() is not supported
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize});
+
+ static void BM_DefaultAllocator(benchmark::State& state) {
+ auto allocator = GetAllocator(Nothing(), (EGuard)state.range(0));
+ for (auto _ : state) {
+ TStackHolder stack(*allocator, state.range(1), TestCoroName);
+ BasicOperations(stack);
+ }
+ }
+ BENCHMARK(BM_DefaultAllocator)
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize}) // old version - ArgsProduct() is not supported
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize});
+
+ static void BM_PoolAllocatorManyStacksOneAtTime(benchmark::State& state) {
+ TPoolAllocatorSettings settings;
+ settings.StacksPerChunk = state.range(2);
+ auto allocator = GetAllocator(settings, (EGuard)state.range(0));
+ for (auto _ : state) {
+ for (uint64_t i = 0; i < ManyStacks; ++i) {
+ TStackHolder stack(*allocator, state.range(1), TestCoroName);
+ BasicOperations(stack);
+ }
+ }
+ }
+ BENCHMARK(BM_PoolAllocatorManyStacksOneAtTime)
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize, 1}) // old version - ArgsProduct() is not supported
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize, 1})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize, 1})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize, 1})
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize, 1024});
+
+ static void BM_DefaultAllocatorManyStacksOneAtTime(benchmark::State& state) {
+ auto allocator = GetAllocator(Nothing(), (EGuard)state.range(0));
+ for (auto _ : state) {
+ for (uint64_t i = 0; i < ManyStacks; ++i) {
+ TStackHolder stack(*allocator, state.range(1), TestCoroName);
+ BasicOperations(stack);
+ }
+ }
+ }
+ BENCHMARK(BM_DefaultAllocatorManyStacksOneAtTime)
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize}) // old version - ArgsProduct() is not supported
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize});
+
+ static void BM_PoolAllocatorManyStacks(benchmark::State& state) {
+ TPoolAllocatorSettings settings;
+ settings.StacksPerChunk = state.range(2);
+ auto allocator = GetAllocator(settings, (EGuard)state.range(0));
+ TVector<TStackHolder> stacks; // store stacks during benchmark
+ stacks.reserve(ManyStacks);
+ for (auto _ : state) {
+ for (uint64_t i = 0; i < ManyStacks; ++i) {
+ stacks.emplace_back(*allocator, state.range(1), TestCoroName);
+ BasicOperations(stacks.back());
+ }
+ }
+ }
+ BENCHMARK(BM_PoolAllocatorManyStacks)
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize, 1}) // old version - ArgsProduct() is not supported
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize, 1})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize, 1})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize, 1})
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize, 1024});
+
+ static void BM_DefaultAllocatorManyStacks(benchmark::State& state) {
+ auto allocator = GetAllocator(Nothing(), (EGuard)state.range(0));
+ TVector<TStackHolder> stacks; // store stacks during benchmark
+ stacks.reserve(ManyStacks);
+ for (auto _ : state) {
+ for (uint64_t i = 0; i < ManyStacks; ++i) {
+ stacks.push_back(TStackHolder(*allocator, state.range(1), TestCoroName));
+ BasicOperations(stacks.back());
+ }
+ }
+ }
+ BENCHMARK(BM_DefaultAllocatorManyStacks)
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize}) // old version - ArgsProduct() is not supported
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize});
+
+ // ------------------------------------------------------------------------
+ static void BM_PoolAllocatorManyStacksReleased(benchmark::State& state) {
+ TPoolAllocatorSettings settings;
+ settings.StacksPerChunk = state.range(2);
+ auto allocator = GetAllocator(settings, (EGuard)state.range(0));
+ TVector<TStackHolder> stacks; // store stacks during benchmark
+ stacks.reserve(ManyStacks);
+ for (auto _ : state) {
+ for (uint64_t i = 0; i < ManyStacks; ++i) {
+ stacks.emplace_back(*allocator, state.range(1), TestCoroName);
+ BasicOperations(stacks.back());
+ }
+ stacks.clear();
+ }
+ }
+ BENCHMARK(BM_PoolAllocatorManyStacksReleased)
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize, 1}) // old version - ArgsProduct() is not supported
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize, 1})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize, 1})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize, 1})
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize, 1024});
+
+ static void BM_DefaultAllocatorManyStacksReleased(benchmark::State& state) {
+ auto allocator = GetAllocator(Nothing(), (EGuard)state.range(0));
+ TVector<TStackHolder> stacks; // store stacks during benchmark
+ stacks.reserve(ManyStacks);
+ for (auto _ : state) {
+ for (uint64_t i = 0; i < ManyStacks; ++i) {
+ stacks.push_back(TStackHolder(*allocator, state.range(1), TestCoroName));
+ BasicOperations(stacks.back());
+ }
+ stacks.clear();
+ }
+ }
+ BENCHMARK(BM_DefaultAllocatorManyStacksReleased)
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize}) // old version - ArgsProduct() is not supported
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize});
+
+ // ------------------------------------------------------------------------
+ static void BM_PoolAllocatorManyStacksReleasedAndRealloc(benchmark::State& state) {
+ TPoolAllocatorSettings settings;
+ settings.StacksPerChunk = state.range(2);
+ auto allocator = GetAllocator(settings, (EGuard)state.range(0));
+ TVector<TStackHolder> stacks; // store stacks during benchmark
+ stacks.reserve(ManyStacks);
+ for (auto _ : state) {
+ for (uint64_t i = 0; i < ManyStacks; ++i) {
+ stacks.emplace_back(*allocator, state.range(1), TestCoroName);
+ BasicOperations(stacks.back());
+ }
+ stacks.clear();
+ for (uint64_t i = 0; i < ManyStacks; ++i) {
+ stacks.emplace_back(*allocator, state.range(1), TestCoroName);
+ BasicOperations(stacks.back());
+ }
+ }
+ }
+ BENCHMARK(BM_PoolAllocatorManyStacksReleasedAndRealloc)
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize, 1}) // old version - ArgsProduct() is not supported
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize, 1})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize, 1})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize, 1})
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize, 8192})
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize, 8192})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize, 8192})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize, 8192});
+
+ static void BM_DefaultAllocatorManyStacksReleasedAndRealloc(benchmark::State& state) {
+ auto allocator = GetAllocator(Nothing(), (EGuard)state.range(0));
+ TVector<TStackHolder> stacks; // store stacks during benchmark
+ stacks.reserve(ManyStacks);
+ for (auto _ : state) {
+ for (uint64_t i = 0; i < ManyStacks; ++i) {
+ stacks.push_back(TStackHolder(*allocator, state.range(1), TestCoroName));
+ BasicOperations(stacks.back());
+ }
+ stacks.clear();
+ for (uint64_t i = 0; i < ManyStacks; ++i) {
+ stacks.push_back(TStackHolder(*allocator, state.range(1), TestCoroName));
+ BasicOperations(stacks.back());
+ }
+ }
+ }
+ BENCHMARK(BM_DefaultAllocatorManyStacksReleasedAndRealloc)
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize}) // old version - ArgsProduct() is not supported
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize});
+
+ // ------------------------------------------------------------------------
+ static void BM_PoolAllocatorManyStacksMemoryWriteReleasedAndRealloc(benchmark::State& state) {
+ TPoolAllocatorSettings settings;
+ settings.StacksPerChunk = state.range(2);
+ auto allocator = GetAllocator(settings, (EGuard)state.range(0));
+ TVector<TStackHolder> stacks; // store stacks during benchmark
+ stacks.reserve(ManyStacks);
+ for (auto _ : state) {
+ for (uint64_t i = 0; i < ManyStacks; ++i) {
+ stacks.emplace_back(*allocator, state.range(1), TestCoroName);
+ WriteStack(stacks.back());
+ }
+ stacks.clear();
+ for (uint64_t i = 0; i < ManyStacks; ++i) {
+ stacks.emplace_back(*allocator, state.range(1), TestCoroName);
+ WriteStack(stacks.back());
+ }
+ }
+ }
+ BENCHMARK(BM_PoolAllocatorManyStacksMemoryWriteReleasedAndRealloc)
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize, 1}) // old version - ArgsProduct() is not supported
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize, 1})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize, 1})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize, 1})
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize, 1024})
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize, 8192})
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize, 8192})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize, 8192})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize, 8192});
+
+ static void BM_DefaultAllocatorManyStacksMemoryWriteReleasedAndRealloc(benchmark::State& state) {
+ auto allocator = GetAllocator(Nothing(), (EGuard)state.range(0));
+ TVector<TStackHolder> stacks; // store stacks during benchmark
+ stacks.reserve(ManyStacks);
+ for (auto _ : state) {
+ for (uint64_t i = 0; i < ManyStacks; ++i) {
+ stacks.push_back(TStackHolder(*allocator, state.range(1), TestCoroName));
+ WriteStack(stacks.back());
+ }
+ stacks.clear();
+ for (uint64_t i = 0; i < ManyStacks; ++i) {
+ stacks.push_back(TStackHolder(*allocator, state.range(1), TestCoroName));
+ WriteStack(stacks.back());
+ }
+ }
+ }
+ BENCHMARK(BM_DefaultAllocatorManyStacksMemoryWriteReleasedAndRealloc)
+ ->Args({(int64_t)EGuard::Canary, BigCoroSize}) // old version - ArgsProduct() is not supported
+ ->Args({(int64_t)EGuard::Canary, SmallCoroSize})
+ ->Args({(int64_t)EGuard::Page, BigCoroSize})
+ ->Args({(int64_t)EGuard::Page, SmallCoroSize});
+
+}
+
+BENCHMARK_MAIN();
diff --git a/library/cpp/coroutine/engine/stack/benchmark/ya.make b/library/cpp/coroutine/engine/stack/benchmark/ya.make
new file mode 100644
index 0000000000..b2942fe8ca
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/benchmark/ya.make
@@ -0,0 +1,13 @@
+G_BENCHMARK()
+
+OWNER(g:balancer)
+
+SRCS(
+ alloc_bm.cpp
+)
+
+PEERDIR(
+ library/cpp/coroutine/engine
+)
+
+END() \ No newline at end of file
diff --git a/library/cpp/coroutine/engine/stack/stack.cpp b/library/cpp/coroutine/engine/stack/stack.cpp
new file mode 100644
index 0000000000..e29450261d
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/stack.cpp
@@ -0,0 +1,67 @@
+#include "stack.h"
+
+#include "stack_allocator.h"
+#include "stack_guards.h"
+
+
+namespace NCoro::NStack {
+
+namespace NDetails {
+
+ TStack::TStack(void* rawMemory, void* alignedMemory, uint64_t alignedSize, const char* /*name*/)
+ : RawMemory_((char*)rawMemory)
+ , AlignedMemory_((char*)alignedMemory)
+ , Size_(alignedSize)
+ {
+ Y_ASSERT(AlignedMemory_ && RawMemory_ && Size_);
+ Y_ASSERT(!(Size_ & PageSizeMask));
+ Y_ASSERT(!((uint64_t)AlignedMemory_ & PageSizeMask));
+ }
+
+ TStack::TStack(TStack&& rhs) noexcept
+ : RawMemory_(rhs.RawMemory_)
+ , AlignedMemory_(rhs.AlignedMemory_)
+ , Size_(rhs.Size_)
+ {
+ rhs.Reset();
+ }
+
+ TStack& TStack::operator=(TStack&& rhs) noexcept {
+ std::swap(*this, rhs);
+ rhs.Reset();
+ return *this;
+ }
+
+ void TStack::Reset() noexcept {
+ Y_ASSERT(AlignedMemory_ && RawMemory_ && Size_);
+
+ RawMemory_ = nullptr;
+ AlignedMemory_ = nullptr;
+ Size_ = 0;
+ }
+
+} // namespace NDetails
+
+
+ TStackHolder::TStackHolder(NStack::IAllocator& allocator, uint32_t size, const char* name) noexcept
+ : Allocator_(allocator)
+ , Stack_(Allocator_.AllocStack(size, name))
+ {}
+
+ TStackHolder::~TStackHolder() {
+ Allocator_.FreeStack(Stack_);
+ }
+
+ TArrayRef<char> TStackHolder::Get() noexcept {
+ return Allocator_.GetStackWorkspace(Stack_.GetAlignedMemory(), Stack_.GetSize());
+ }
+
+ bool TStackHolder::LowerCanaryOk() const noexcept {
+ return Allocator_.CheckStackOverflow(Stack_.GetAlignedMemory());
+ }
+
+ bool TStackHolder::UpperCanaryOk() const noexcept {
+ return Allocator_.CheckStackOverride(Stack_.GetAlignedMemory(), Stack_.GetSize());
+ }
+
+}
diff --git a/library/cpp/coroutine/engine/stack/stack.h b/library/cpp/coroutine/engine/stack/stack.h
new file mode 100644
index 0000000000..7d98ba4c68
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/stack.h
@@ -0,0 +1,77 @@
+#pragma once
+
+#include <util/generic/array_ref.h>
+#include <util/generic/fwd.h>
+#include <util/generic/noncopyable.h>
+
+#include <cstdint>
+
+
+namespace NCoro::NStack {
+
+ class IAllocator;
+
+namespace NDetails {
+
+ //! Do not use directly, use TStackHolder instead
+ class TStack final : private TMoveOnly {
+ public:
+ /*! rawMemory: can be used by unaligned allocator to free stack memory after use
+ * alignedMemory: pointer to aligned memory on which stack workspace and guard are actually placed
+ * alignedSize: size of workspace memory + memory for guard
+ * guard: guard to protect this stack
+ * name: name of coroutine for which this stack is allocated
+ */
+ TStack(void* rawMemory, void* alignedMemory, uint64_t alignedSize, const char* name);
+ TStack(TStack&& rhs) noexcept;
+ TStack& operator=(TStack&& rhs) noexcept;
+
+ char* GetRawMemory() const noexcept {
+ return RawMemory_;
+ }
+
+ char* GetAlignedMemory() const noexcept {
+ return AlignedMemory_;
+ }
+
+ //! Stack size (includes memory for guard)
+ uint64_t GetSize() const noexcept {
+ return Size_;
+ }
+
+ //! Resets parameters, should be called after stack memory is freed
+ void Reset() noexcept;
+
+ private:
+ char* RawMemory_ = nullptr; // not owned
+ char* AlignedMemory_ = nullptr; // not owned
+ uint64_t Size_ = 0;
+ };
+
+} // namespace NDetails
+
+ class TStackHolder final : private TMoveOnly {
+ public:
+ explicit TStackHolder(IAllocator& allocator, uint32_t size, const char* name) noexcept;
+ TStackHolder(TStackHolder&&) = default;
+ TStackHolder& operator=(TStackHolder&&) = default;
+
+ ~TStackHolder();
+
+ char* GetAlignedMemory() const noexcept {
+ return Stack_.GetAlignedMemory();
+ }
+ uint64_t GetSize() const noexcept {
+ return Stack_.GetSize();
+ }
+
+ TArrayRef<char> Get() noexcept;
+ bool LowerCanaryOk() const noexcept;
+ bool UpperCanaryOk() const noexcept;
+
+ private:
+ IAllocator& Allocator_;
+ NDetails::TStack Stack_;
+ };
+
+}
diff --git a/library/cpp/coroutine/engine/stack/stack_allocator.cpp b/library/cpp/coroutine/engine/stack/stack_allocator.cpp
new file mode 100644
index 0000000000..bf12134e6b
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/stack_allocator.cpp
@@ -0,0 +1,26 @@
+#include "stack_allocator.h"
+
+
+namespace NCoro::NStack {
+
+ THolder<IAllocator> GetAllocator(TMaybe<TPoolAllocatorSettings> poolSettings, EGuard guardType) {
+ THolder<IAllocator> allocator;
+ if (poolSettings) {
+ if (guardType == EGuard::Canary) {
+ allocator = MakeHolder<TPoolAllocator<TCanaryGuard>>(*poolSettings);
+ } else {
+ Y_ASSERT(guardType == EGuard::Page);
+ allocator = MakeHolder<TPoolAllocator<TPageGuard>>(*poolSettings);
+ }
+ } else {
+ if (guardType == EGuard::Canary) {
+ allocator = MakeHolder<TSimpleAllocator<TCanaryGuard>>();
+ } else {
+ Y_ASSERT(guardType == EGuard::Page);
+ allocator = MakeHolder<TSimpleAllocator<TPageGuard>>();
+ }
+ }
+ return allocator;
+ }
+
+} \ No newline at end of file
diff --git a/library/cpp/coroutine/engine/stack/stack_allocator.h b/library/cpp/coroutine/engine/stack/stack_allocator.h
new file mode 100644
index 0000000000..da3c3a93a1
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/stack_allocator.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#include "stack.h"
+#include "stack_common.h"
+
+#include <util/generic/maybe.h>
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+
+#include <cstdint>
+
+
+namespace NCoro::NStack {
+
+ class IAllocator : private TNonCopyable {
+ public:
+ virtual ~IAllocator() = default;
+
+ //! Size should be page-aligned. Stack would be protected by guard, thus, actual
+ //! workspace for stack = size - size of guard.
+ NDetails::TStack AllocStack(uint64_t size, const char* name) {
+ uint64_t alignedSize = (size + PageSize - 1) & ~PageSizeMask;
+ Y_ASSERT(alignedSize < 10 * 1024 * PageSize); // more than 10K pages for stack - do you really need it?
+#if defined(_san_enabled_) || !defined(NDEBUG)
+ alignedSize *= DebugOrSanStackMultiplier;
+#endif
+ return DoAllocStack(alignedSize, name);
+ }
+
+ void FreeStack(NDetails::TStack& stack) noexcept {
+ if (stack.GetAlignedMemory()) {
+ DoFreeStack(stack);
+ }
+ };
+
+ virtual TAllocatorStats GetStackStats() const noexcept = 0;
+
+ // Stack helpers
+ virtual TArrayRef<char> GetStackWorkspace(void* stack, uint64_t size) noexcept = 0;
+ virtual bool CheckStackOverflow(void* stack) const noexcept = 0;
+ virtual bool CheckStackOverride(void* stack, uint64_t size) const noexcept = 0;
+
+ private:
+ virtual NDetails::TStack DoAllocStack(uint64_t size, const char* name) = 0;
+ virtual void DoFreeStack(NDetails::TStack& stack) noexcept = 0;
+ };
+
+ THolder<IAllocator> GetAllocator(TMaybe<TPoolAllocatorSettings> poolSettings, EGuard guardType);
+
+}
+
+#include "stack_allocator.inl"
diff --git a/library/cpp/coroutine/engine/stack/stack_allocator.inl b/library/cpp/coroutine/engine/stack/stack_allocator.inl
new file mode 100644
index 0000000000..0f25a4167b
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/stack_allocator.inl
@@ -0,0 +1,138 @@
+#include "stack_guards.h"
+#include "stack_pool.h"
+#include "stack_utils.h"
+
+#include <util/generic/hash.h>
+
+#ifdef _linux_
+#include <unistd.h>
+#endif
+
+
+namespace NCoro::NStack {
+
+ template<typename TGuard>
+ class TPoolAllocator final : public IAllocator {
+ public:
+ explicit TPoolAllocator(const TPoolAllocatorSettings& settings);
+
+ TArrayRef<char> GetStackWorkspace(void* stack, uint64_t size) noexcept override {
+ return Guard_.GetWorkspace(stack, size);
+ }
+ bool CheckStackOverflow(void* stack) const noexcept override {
+ return Guard_.CheckOverflow(stack);
+ }
+ bool CheckStackOverride(void* stack, uint64_t size) const noexcept override {
+ return Guard_.CheckOverride(stack, size);
+ }
+
+ TAllocatorStats GetStackStats() const noexcept override {
+ TAllocatorStats stats;
+ for (const auto& i : Pools_) {
+ stats.ReleasedSize += i.second.GetReleasedSize();
+ stats.NotReleasedSize += i.second.GetFullSize();
+ stats.NumOfAllocated += i.second.GetNumOfAllocated();
+ }
+ return stats;
+ }
+
+ private: // methods
+ NDetails::TStack DoAllocStack(uint64_t size, const char* name) override;
+ void DoFreeStack(NDetails::TStack& stack) noexcept override;
+
+ private: // data
+ const TPoolAllocatorSettings PoolSettings_;
+ const TGuard& Guard_;
+ THashMap<uint64_t, TPool<TGuard>> Pools_; // key - stack size
+ };
+
+ template<typename TGuard>
+ TPoolAllocator<TGuard>::TPoolAllocator(const TPoolAllocatorSettings& settings)
+ : PoolSettings_(settings)
+ , Guard_(GetGuard<TGuard>())
+ {
+#ifdef _linux_
+ Y_VERIFY(sysconf(_SC_PAGESIZE) == PageSize);
+#endif
+ }
+
+ template<typename TGuard>
+ NDetails::TStack TPoolAllocator<TGuard>::DoAllocStack(uint64_t alignedSize, const char* name) {
+ Y_ASSERT(alignedSize > Guard_.GetSize());
+
+ auto pool = Pools_.find(alignedSize);
+ if (pool == Pools_.end()) {
+ Y_ASSERT(Pools_.size() < 1000); // too many different sizes for coroutine stacks
+ auto [newPool, success] = Pools_.emplace(alignedSize, TPool<TGuard>{alignedSize, PoolSettings_, Guard_});
+ Y_VERIFY(success, "Failed to add new coroutine pool");
+ pool = newPool;
+ }
+ return pool->second.AllocStack(name);
+ }
+
+ template<typename TGuard>
+ void TPoolAllocator<TGuard>::DoFreeStack(NDetails::TStack& stack) noexcept {
+ auto pool = Pools_.find(stack.GetSize());
+ Y_VERIFY(pool != Pools_.end(), "Attempt to free stack from another allocator");
+ pool->second.FreeStack(stack);
+ }
+
+ // ------------------------------------------------------------------------
+ //
+ template<typename TGuard>
+ class TSimpleAllocator : public IAllocator {
+ public:
+ explicit TSimpleAllocator();
+
+ TArrayRef<char> GetStackWorkspace(void* stack, uint64_t size) noexcept override {
+ return Guard_.GetWorkspace(stack, size);
+ }
+ bool CheckStackOverflow(void* stack) const noexcept override {
+ return Guard_.CheckOverflow(stack);
+ }
+ bool CheckStackOverride(void* stack, uint64_t size) const noexcept override {
+ return Guard_.CheckOverride(stack, size);
+ }
+
+ TAllocatorStats GetStackStats() const noexcept override { return {}; } // not used for simple allocator
+
+ private: // methods
+ NDetails::TStack DoAllocStack(uint64_t size, const char* name) override;
+ void DoFreeStack(NDetails::TStack& stack) noexcept override;
+
+ private: // data
+ const TGuard& Guard_;
+ };
+
+
+ template<typename TGuard>
+ TSimpleAllocator<TGuard>::TSimpleAllocator()
+ : Guard_(GetGuard<TGuard>())
+ {}
+
+ template<typename TGuard>
+ NDetails::TStack TSimpleAllocator<TGuard>::DoAllocStack(uint64_t alignedSize, const char* name) {
+ Y_ASSERT(alignedSize > Guard_.GetSize());
+
+ char* rawPtr = nullptr;
+ char* alignedPtr = nullptr; // with extra space for previous guard in this type of allocator
+
+ Y_VERIFY(GetAlignedMemory((alignedSize + Guard_.GetPageAlignedSize()) / PageSize, rawPtr, alignedPtr)); // + memory for previous guard
+ char* alignedStackMemory = alignedPtr + Guard_.GetPageAlignedSize(); // after previous guard
+
+ // Default allocator sets both guards, because it doesn't have memory chunk with previous stack and guard on it
+ Guard_.Protect((void*)alignedPtr, Guard_.GetPageAlignedSize(), false); // first guard should be before stack memory
+ Guard_.Protect(alignedStackMemory, alignedSize, true); // second guard is placed on stack memory
+
+ return NDetails::TStack{rawPtr, alignedStackMemory, alignedSize, name};
+ }
+
+ template<typename TGuard>
+ void TSimpleAllocator<TGuard>::DoFreeStack(NDetails::TStack& stack) noexcept {
+ Guard_.RemoveProtection(stack.GetAlignedMemory() - Guard_.GetPageAlignedSize(), Guard_.GetPageAlignedSize());
+ Guard_.RemoveProtection(stack.GetAlignedMemory(), stack.GetSize());
+
+ free(stack.GetRawMemory());
+ stack.Reset();
+ }
+}
diff --git a/library/cpp/coroutine/engine/stack/stack_common.h b/library/cpp/coroutine/engine/stack/stack_common.h
new file mode 100644
index 0000000000..ed2d74d296
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/stack_common.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <cstdint>
+
+class TContExecutor;
+
+namespace NCoro::NStack {
+
+ static constexpr uint64_t PageSize = 4096;
+ static constexpr uint64_t PageSizeMask = PageSize - 1; // for checks
+ static constexpr uint64_t DebugOrSanStackMultiplier = 4; // for debug or sanitizer builds
+ static constexpr uint64_t SmallStackMaxSizeInPages = 6;
+
+ enum class EGuard {
+ Canary, //!< writes some data to check it for corruption
+ Page, //!< prohibits access to page memory
+ };
+
+ struct TPoolAllocatorSettings {
+ uint64_t RssPagesToKeep = 1;
+ uint64_t SmallStackRssPagesToKeep = 1; // for stack less than SmallStackMaxSizeInPages
+ uint64_t ReleaseRate = 2;
+#if !defined(_san_enabled_) && defined(NDEBUG)
+ uint64_t StacksPerChunk = 256;
+#else
+ uint64_t StacksPerChunk = 2;
+#endif
+ };
+
+ struct TAllocatorStats {
+ uint64_t ReleasedSize = 0;
+ uint64_t NotReleasedSize = 0;
+ uint64_t NumOfAllocated = 0;
+ };
+}
diff --git a/library/cpp/coroutine/engine/stack/stack_guards.cpp b/library/cpp/coroutine/engine/stack/stack_guards.cpp
new file mode 100644
index 0000000000..b8bcff039e
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/stack_guards.cpp
@@ -0,0 +1,17 @@
+#include "stack_guards.h"
+
+
+namespace NCoro::NStack {
+
+ template<>
+ const TCanaryGuard& GetGuard<TCanaryGuard>() noexcept {
+ static const TCanaryGuard guard;
+ return guard;
+ }
+
+ template<>
+ const TPageGuard& GetGuard<TPageGuard>() noexcept {
+ static const TPageGuard guard;
+ return guard;
+ }
+} \ No newline at end of file
diff --git a/library/cpp/coroutine/engine/stack/stack_guards.h b/library/cpp/coroutine/engine/stack/stack_guards.h
new file mode 100644
index 0000000000..3a7ef26481
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/stack_guards.h
@@ -0,0 +1,123 @@
+#pragma once
+
+#include "stack_common.h"
+
+#include <util/generic/array_ref.h>
+#include <util/generic/strbuf.h>
+#include <util/system/protect.h>
+
+
+namespace NCoro::NStack {
+
+ /*! Guard detect stack overflow/override, by setting memory before and after stack with predefined values/properties.
+ * Actually, it sets memory only after the end of stack workspace memory - previous guard section should be set
+ * already (for previous stack in case of pool allocator) and can be checked on demand.
+ * Stack pointer should be page-aligned.
+ */
+
+
+ //! Checks integrity by writing a predefined sequence and comparing it with original
+ class TCanaryGuard final {
+ public:
+ //! Size of guard section in bytes
+ static constexpr uint64_t GetSize() { return Canary.size(); }
+ //! Size of page-aligned guard section in bytes
+ static constexpr uint64_t GetPageAlignedSize() { return AlignedSize_; }
+
+ //! Get stack memory between guard sections
+ static TArrayRef<char> GetWorkspace(void* stack, uint64_t size) noexcept {
+ Y_ASSERT( !((uint64_t)stack & PageSizeMask) );
+ Y_ASSERT( !(size & PageSizeMask) );
+ Y_ASSERT(size > Canary.size());
+
+ return {(char*) stack, size - Canary.size()};
+ }
+
+ /*! Set guard section before the end of stack memory (at stack + size - guard size position)
+ * checkPrevious: check guard before stack memory for integrity
+ */
+ static void Protect(void* stack, uint64_t size, bool checkPrevious) noexcept {
+ Y_ASSERT( !((uint64_t)stack & PageSizeMask) ); // stack pointer should be page aligned
+ Y_ASSERT( !(size & PageSizeMask) ); // stack size should be page aligned
+ Y_ASSERT(size >= Canary.size()); // stack should have enough space to place guard
+
+ if (checkPrevious) {
+ Y_VERIFY(CheckOverflow(stack), "Previous stack was corrupted");
+ }
+ auto guardPos = (char*) stack + size - Canary.size();
+ memcpy(guardPos, Canary.data(), Canary.size());
+ }
+
+ //! This guard doesn't change memory flags
+ static constexpr void RemoveProtection(void*, uint64_t) {}
+ //! Should remove protection before returning memory to system
+ static constexpr bool ShouldRemoveProtectionBeforeFree() { return false; }
+
+ static bool CheckOverflow(void* stack) noexcept {
+ Y_ASSERT(stack);
+
+ char* guardPos = (char*) ((uint64_t)stack - Canary.size());
+ return TStringBuf(guardPos, Canary.size()) == Canary;
+ }
+
+ static bool CheckOverride(void* stack, uint64_t size) noexcept {
+ Y_ASSERT(stack);
+ Y_ASSERT(size > Canary.size());
+
+ char* guardPos = (char*) ((uint64_t)stack + size - Canary.size());
+ return TStringBuf(guardPos, Canary.size()) == Canary;
+ }
+
+ private:
+ static constexpr TStringBuf Canary = "[ThisIsACanaryCoroutineStackGuardIfYouReadThisTheStackIsStillOK]";
+ static_assert(Canary.size() == 64);
+ static constexpr uint64_t AlignedSize_ = (Canary.size() + PageSize - 1) & ~PageSizeMask;
+ };
+
+
+ // ------------------------------------------------------------------------
+ //
+ //! Ensures integrity by removing access rights for border pages
+ class TPageGuard final {
+ public:
+ //! Size of guard section in bytes
+ static constexpr uint64_t GetSize() { return PageSize; }
+ //! Size of page-aligned guard section in bytes
+ static constexpr uint64_t GetPageAlignedSize() { return PageSize; }
+
+ static TArrayRef<char> GetWorkspace(void* stack, uint64_t size) noexcept {
+ Y_ASSERT( !((uint64_t)stack & PageSizeMask) );
+ Y_ASSERT( !(size & PageSizeMask) );
+ Y_ASSERT(size > PageSize);
+
+ return {(char*)stack, size - PageSize};
+ }
+
+ static void Protect(void* stack, uint64_t size, bool /*checkPrevious*/) noexcept {
+ Y_ASSERT( !((uint64_t)stack & PageSizeMask) ); // stack pointer should be page aligned
+ Y_ASSERT( !(size & PageSizeMask) ); // stack size should be page aligned
+ Y_ASSERT(size >= PageSize); // stack should have enough space to place guard
+
+ ProtectMemory((char*)stack + size - PageSize, PageSize, PM_NONE);
+ }
+
+ //! Remove protection, to allow stack memory be freed
+ static void RemoveProtection(void* stack, uint64_t size) noexcept {
+ Y_ASSERT( !((uint64_t)stack & PageSizeMask) );
+ Y_ASSERT( !(size & PageSizeMask) );
+ Y_ASSERT(size >= PageSize);
+
+ ProtectMemory((char*)stack + size - PageSize, PageSize, PM_WRITE | PM_READ);
+ }
+ //! Should remove protection before returning memory to system
+ static constexpr bool ShouldRemoveProtectionBeforeFree() { return true; }
+
+ //! For page guard is not used - it crashes process at once in this case.
+ static constexpr bool CheckOverflow(void*) { return true; }
+ static constexpr bool CheckOverride(void*, uint64_t) { return true; }
+ };
+
+
+ template<typename TGuard>
+ const TGuard& GetGuard() noexcept;
+}
diff --git a/library/cpp/coroutine/engine/stack/stack_pool.h b/library/cpp/coroutine/engine/stack/stack_pool.h
new file mode 100644
index 0000000000..27a8e9394b
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/stack_pool.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include "stack.h"
+#include "stack_common.h"
+
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+
+
+namespace NCoro::NStack {
+
+ class IGuard;
+ class TStorage;
+ struct TPoolAllocatorSettings;
+
+ template<typename TGuard>
+ class TPool final : private TMoveOnly {
+ struct TMemory {
+ char* Raw = nullptr;
+ char* Aligned = nullptr; // points to aligned memory, which includes space for first page guard
+ };
+ public:
+ TPool(uint64_t stackSize, const TPoolAllocatorSettings& settings, const TGuard& guard);
+ TPool(TPool&& other) noexcept;
+ ~TPool();
+
+ NDetails::TStack AllocStack(const char* name);
+ void FreeStack(NDetails::TStack& stack);
+
+ uint64_t GetReleasedSize() const noexcept;
+ uint64_t GetFullSize() const noexcept;
+ uint64_t GetNumOfAllocated() const noexcept { return NumOfAllocated_; }
+
+ private:
+ void AllocNewMemoryChunk();
+ bool IsSmallStack() const noexcept;
+ bool IsStackFromThisPool(const NDetails::TStack& stack) const noexcept;
+ NDetails::TStack AllocNewStack(const char* name);
+
+ private:
+ const uint64_t StackSize_ = 0;
+ uint64_t RssPagesToKeep_ = 0;
+ const TGuard& Guard_;
+ TVector<TMemory> Memory_; // memory chunks
+ THolder<TStorage> Storage_;
+ char* NextToAlloc_ = nullptr; // points to next available stack in the last memory chunk
+ const uint64_t ChunkSize_ = 0;
+ uint64_t NumOfAllocated_ = 0;
+ };
+
+}
+
+#include "stack_pool.inl"
diff --git a/library/cpp/coroutine/engine/stack/stack_pool.inl b/library/cpp/coroutine/engine/stack/stack_pool.inl
new file mode 100644
index 0000000000..6e08e05a48
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/stack_pool.inl
@@ -0,0 +1,132 @@
+#include "stack_storage.h"
+#include "stack_utils.h"
+
+
+namespace NCoro::NStack {
+
+ template<typename TGuard>
+ TPool<TGuard>::TPool(uint64_t stackSize, const TPoolAllocatorSettings& settings, const TGuard& guard)
+ : StackSize_(stackSize)
+ , RssPagesToKeep_(IsSmallStack() ? settings.SmallStackRssPagesToKeep : settings.RssPagesToKeep)
+ , Guard_(guard)
+ , ChunkSize_(Guard_.GetPageAlignedSize() + StackSize_ * settings.StacksPerChunk)
+ {
+ Y_ASSERT(RssPagesToKeep_);
+ if (!RssPagesToKeep_) {
+ RssPagesToKeep_ = 1; // at least guard should be kept
+ }
+
+ const uint64_t stackSizeInPages = stackSize / PageSize;
+ Y_ASSERT(stackSizeInPages >= RssPagesToKeep_);
+ if (stackSizeInPages < RssPagesToKeep_) {
+ RssPagesToKeep_ = stackSizeInPages; // keep all stack pages
+ }
+
+ Y_ASSERT(StackSize_ && !(StackSize_ & PageSizeMask)); // stack size is not zero and page aligned
+ Y_ASSERT(Guard_.GetSize() < StackSize_); // stack has enough space to place guard
+ Y_ASSERT(stackSizeInPages >= RssPagesToKeep_);
+
+ Storage_ = MakeHolder<TStorage>(StackSize_, RssPagesToKeep_, settings.ReleaseRate);
+
+ AllocNewMemoryChunk();
+ }
+
+ template<typename TGuard>
+ TPool<TGuard>::TPool(TPool&& other) noexcept = default;
+
+ template<typename TGuard>
+ TPool<TGuard>::~TPool() {
+ if (!Memory_.empty()) {
+ Y_ASSERT(NextToAlloc_ && StackSize_);
+
+ for (const auto& chunk : Memory_) {
+ Y_ASSERT(chunk.Raw && chunk.Aligned);
+
+ if (Guard_.ShouldRemoveProtectionBeforeFree()) {
+ Guard_.RemoveProtection(chunk.Aligned, Guard_.GetPageAlignedSize()); // first page in chunk
+
+ const char* endOfStacksMemory = chunk.Aligned + ChunkSize_;
+ for (char* i = chunk.Aligned + Guard_.GetPageAlignedSize(); i < endOfStacksMemory; i += StackSize_) {
+ Guard_.RemoveProtection(i, StackSize_);
+ }
+ }
+
+ free(chunk.Raw);
+ }
+ }
+ }
+
+ template<typename TGuard>
+ NDetails::TStack TPool<TGuard>::AllocStack(const char* name) {
+ Y_ASSERT(!Memory_.empty());
+
+ if (!Storage_->IsEmpty()) {
+ return Storage_->GetStack(Guard_, name);
+ } else {
+ ++NumOfAllocated_;
+ return AllocNewStack(name);
+ }
+ }
+
+ template<typename TGuard>
+ void TPool<TGuard>::FreeStack(NDetails::TStack& stack) {
+ Y_ASSERT(Storage_->Size() < ((ChunkSize_ - Guard_.GetPageAlignedSize()) / StackSize_) * Memory_.size());
+ Y_ASSERT(IsStackFromThisPool(stack));
+
+ Storage_->ReturnStack(stack);
+ }
+
+ template<typename TGuard>
+ uint64_t TPool<TGuard>::GetReleasedSize() const noexcept {
+ return Storage_->GetReleasedSize();
+ }
+ template<typename TGuard>
+ uint64_t TPool<TGuard>::GetFullSize() const noexcept {
+ return Storage_->GetFullSize();
+ }
+
+ template<typename TGuard>
+ void TPool<TGuard>::AllocNewMemoryChunk() {
+ const uint64_t totalSizeInPages = ChunkSize_ / PageSize;
+
+ TMemory memory;
+ const auto res = GetAlignedMemory(totalSizeInPages, memory.Raw, memory.Aligned);
+ Y_VERIFY(res, "Failed to allocate memory for coro stack pool");
+
+ NextToAlloc_ = memory.Aligned + Guard_.GetPageAlignedSize(); // skip first guard page
+ Guard_.Protect(memory.Aligned, Guard_.GetPageAlignedSize(), false); // protect first guard page
+
+ Memory_.push_back(std::move(memory));
+ }
+
+ template<typename TGuard>
+ bool TPool<TGuard>::IsSmallStack() const noexcept {
+ return StackSize_ / PageSize <= SmallStackMaxSizeInPages;
+ }
+
+ template<typename TGuard>
+ bool TPool<TGuard>::IsStackFromThisPool(const NDetails::TStack& stack) const noexcept {
+ for (const auto& chunk : Memory_) {
+ const char* endOfStacksMemory = chunk.Aligned + ChunkSize_;
+ if (chunk.Raw <= stack.GetRawMemory() && stack.GetRawMemory() < endOfStacksMemory) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ template<typename TGuard>
+ NDetails::TStack TPool<TGuard>::AllocNewStack(const char* name) {
+ if (NextToAlloc_ + StackSize_ > Memory_.rbegin()->Aligned + ChunkSize_) {
+ AllocNewMemoryChunk(); // also sets NextToAlloc_ to first stack position in new allocated chunk of memory
+ }
+ Y_ASSERT(NextToAlloc_ + StackSize_ <= Memory_.rbegin()->Aligned + ChunkSize_);
+
+ char* newStack = NextToAlloc_;
+ NextToAlloc_ += StackSize_;
+
+ Guard_.Protect(newStack, StackSize_, true);
+ return NDetails::TStack{newStack, newStack, StackSize_, name};
+ }
+
+}
diff --git a/library/cpp/coroutine/engine/stack/stack_storage.cpp b/library/cpp/coroutine/engine/stack/stack_storage.cpp
new file mode 100644
index 0000000000..6dc2b2d44b
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/stack_storage.cpp
@@ -0,0 +1,46 @@
+#include "stack_storage.h"
+
+#include "stack.h"
+#include "stack_utils.h"
+
+#include <library/cpp/coroutine/engine/impl.h>
+
+
+namespace NCoro::NStack {
+
+ TStorage::TStorage(uint64_t stackSize, uint64_t rssPagesToKeep, uint64_t releaseRate)
+ : StackSize_(stackSize)
+ , RssPagesToKeep_(rssPagesToKeep)
+ , ReleaseRate_(releaseRate ? releaseRate : 1)
+ {
+ Y_ASSERT(StackSize_ && RssPagesToKeep_);
+ }
+
+ bool TStorage::IsEmpty() const noexcept {
+ return Released_.empty() && Full_.empty();
+ }
+
+ uint64_t TStorage::Size() const noexcept {
+ return Released_.size() + Full_.size();
+ }
+
+ void TStorage::ReturnStack(NDetails::TStack& stack) {
+ thread_local uint64_t i = 0;
+ if (++i % ReleaseRate_ != 0) {
+ Full_.push_back(stack.GetAlignedMemory());
+ } else {
+ ReleaseMemory(stack.GetAlignedMemory(), RssPagesToKeep_);
+ Released_.push_back(stack.GetAlignedMemory());
+ }
+ stack.Reset();
+ }
+
+ void TStorage::ReleaseMemory([[maybe_unused]] char* alignedStackMemory, [[maybe_unused]] uint64_t pagesToKeep) noexcept {
+#if !defined(_san_enabled_) && defined(NDEBUG)
+ uint64_t numOfPagesToFree = StackSize_ / PageSize;
+ numOfPagesToFree -= pagesToKeep;
+ ReleaseRss(alignedStackMemory, numOfPagesToFree);
+#endif
+ }
+
+}
diff --git a/library/cpp/coroutine/engine/stack/stack_storage.h b/library/cpp/coroutine/engine/stack/stack_storage.h
new file mode 100644
index 0000000000..25fe2cfb17
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/stack_storage.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "stack.h"
+
+#include <util/datetime/base.h>
+#include <util/generic/deque.h>
+
+
+class TCont;
+
+namespace NCoro::NStack {
+
+ class IGuard;
+
+ class TStorage final : private TMoveOnly {
+ public:
+ TStorage(uint64_t stackSize, uint64_t rssPagesToKeep, uint64_t releaseRate);
+
+ bool IsEmpty() const noexcept;
+ uint64_t Size() const noexcept;
+
+ uint64_t GetReleasedSize() const noexcept { return Released_.size(); }
+ uint64_t GetFullSize() const noexcept { return Full_.size(); }
+
+ template<typename TGuard>
+ NDetails::TStack GetStack(const TGuard& guard, const char* name);
+ void ReturnStack(NDetails::TStack& stack);
+
+ private:
+ void ReleaseMemory(char* alignedStackMemory, uint64_t pagesToKeep) noexcept;
+
+ private:
+ TDeque<void*> Released_; //!< stacks memory with released RSS memory
+ TDeque<void*> Full_; //!< stacks memory with RSS memory
+ uint64_t StackSize_ = 0;
+ uint64_t RssPagesToKeep_ = 0;
+ const uint64_t ReleaseRate_ = 1;
+ };
+
+
+ template<typename TGuard>
+ NDetails::TStack TStorage::GetStack(const TGuard& guard, const char* name) {
+ Y_VERIFY(!IsEmpty()); // check before call
+
+ void* newStack = nullptr;
+ if (!Full_.empty()) {
+ newStack = Full_.back();
+ Full_.pop_back();
+ } else {
+ Y_ASSERT(!Released_.empty());
+ newStack = Released_.back();
+ Released_.pop_back();
+ }
+
+ Y_VERIFY(guard.CheckOverflow(newStack), "corrupted stack in pool");
+ Y_VERIFY(guard.CheckOverride(newStack, StackSize_), "corrupted stack in pool");
+
+ return NDetails::TStack{newStack, newStack, StackSize_, name};
+ }
+}
diff --git a/library/cpp/coroutine/engine/stack/stack_utils.cpp b/library/cpp/coroutine/engine/stack/stack_utils.cpp
new file mode 100644
index 0000000000..1548529b66
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/stack_utils.cpp
@@ -0,0 +1,84 @@
+#include "stack_utils.h"
+
+#include <contrib/libs/linux-headers/asm-generic/errno-base.h>
+#include <util/generic/scope.h>
+#include <util/system/yassert.h>
+
+#ifdef _linux_
+#include <sys/mman.h>
+#endif
+
+#include <cerrno>
+#include <cstdlib>
+#include <cstring>
+
+
+namespace NCoro::NStack {
+
+#ifdef _linux_
+ bool GetAlignedMemory(uint64_t sizeInPages, char*& rawPtr, char*& alignedPtr) noexcept {
+ Y_ASSERT(sizeInPages);
+
+ void* ptr = nullptr;
+ int error = posix_memalign(&ptr, PageSize, sizeInPages * PageSize);
+ alignedPtr = rawPtr = (char*)ptr;
+ return rawPtr && alignedPtr && !error;
+ }
+#else
+ bool GetAlignedMemory(uint64_t sizeInPages, char*& rawPtr, char*& alignedPtr) noexcept {
+ Y_ASSERT(sizeInPages);
+
+ rawPtr = (char*) malloc((sizeInPages + 1) * PageSize); // +1 in case result would be unaligned
+ alignedPtr = (char*)( ((uint64_t)rawPtr + PageSize - 1) & ~PageSizeMask);
+ return rawPtr && alignedPtr;
+ }
+#endif
+
+#ifdef _linux_
+ void ReleaseRss(char* alignedPtr, uint64_t numOfPages) noexcept {
+ Y_VERIFY( !((uint64_t)alignedPtr & PageSizeMask), "Not aligned pointer to release RSS memory");
+ if (!numOfPages) {
+ return;
+ }
+ if (auto res = madvise((void*) alignedPtr, numOfPages * PageSize, MADV_DONTNEED); res) {
+ Y_VERIFY(errno == EAGAIN || errno == ENOMEM, "Failed to release memory");
+ }
+ }
+#else
+ void ReleaseRss(char*, uint64_t) noexcept {
+ }
+#endif
+
+#ifdef _linux_
+ uint64_t CountMapped(char* alignedPtr, uint64_t numOfPages) noexcept {
+ Y_VERIFY( !((uint64_t)alignedPtr & PageSizeMask) );
+ Y_ASSERT(numOfPages);
+
+ uint64_t result = 0;
+ unsigned char* mappedPages = (unsigned char*) calloc(numOfPages, numOfPages);
+ Y_VERIFY(mappedPages);
+ Y_DEFER {
+ free(mappedPages);
+ };
+
+ if (!mincore((void*)alignedPtr, numOfPages * PageSize, mappedPages)) {
+ for (uint64_t i = 0; i < numOfPages; ++i) {
+ if (mappedPages[i] & 1) {
+ ++result;
+ }
+ }
+ } else {
+ Y_ASSERT(false);
+ return 0;
+ }
+
+ return result;
+ }
+
+#else
+ uint64_t CountMapped(char*, uint64_t) noexcept {
+ return 0; // stub for Windows tests
+ }
+#endif
+
+}
diff --git a/library/cpp/coroutine/engine/stack/stack_utils.h b/library/cpp/coroutine/engine/stack/stack_utils.h
new file mode 100644
index 0000000000..46c65240b5
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/stack_utils.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "stack_common.h"
+
+
+namespace NCoro::NStack {
+ /*! Actual size of allocated memory can exceed size in pages, due to unaligned allocation.
+ * @param sizeInPages : number of pages to allocate
+ * @param rawPtr : pointer to unaligned memory. Should be passed to free() when is not used any more.
+ * @param alignedPtr : pointer to beginning of first fully allocated page
+ * @return : true on success
+ */
+ bool GetAlignedMemory(uint64_t sizeInPages, char*& rawPtr, char*& alignedPtr) noexcept;
+
+ /*! Release mapped RSS memory.
+ * @param alignedPt : page-size aligned memory on which RSS memory should be freed
+ * @param numOfPages : number of pages to free from RSS memory
+ */
+ void ReleaseRss(char* alignedPtr, uint64_t numOfPages) noexcept;
+
+ /*! Count pages with RSS memory
+ * @param alignedPtr : pointer to page-aligned memory for which calculations would be done
+ * @param numOfPages : number of pages to check
+ * @return : number of pages with RSS memory
+ */
+ uint64_t CountMapped(char* alignedPtr, uint64_t numOfPages) noexcept;
+}
diff --git a/library/cpp/coroutine/engine/stack/ut/stack_allocator_ut.cpp b/library/cpp/coroutine/engine/stack/ut/stack_allocator_ut.cpp
new file mode 100644
index 0000000000..a7283d44a3
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/ut/stack_allocator_ut.cpp
@@ -0,0 +1,115 @@
+#include <library/cpp/coroutine/engine/stack/stack_allocator.h>
+#include <library/cpp/coroutine/engine/stack/stack_common.h>
+#include <library/cpp/testing/gtest/gtest.h>
+
+
+using namespace testing;
+
+namespace NCoro::NStack::Tests {
+
+ enum class EAllocator {
+ Pool, // allocates page-size aligned stacks from pools
+ Simple // uses malloc/free for each stack
+ };
+
+ class TAllocatorParamFixture : public TestWithParam< std::tuple<EGuard, EAllocator> > {
+ protected: // methods
+ void SetUp() override {
+ EGuard guardType;
+ EAllocator allocType;
+ std::tie(guardType, allocType) = GetParam();
+
+ TMaybe<TPoolAllocatorSettings> poolSettings;
+ if (allocType == EAllocator::Pool) {
+ poolSettings = TPoolAllocatorSettings{};
+ }
+
+ Allocator_ = GetAllocator(poolSettings, guardType);
+ }
+
+ protected: // data
+ THolder<IAllocator> Allocator_;
+ };
+
+
+ TEST_P(TAllocatorParamFixture, StackAllocationAndRelease) {
+ uint64_t stackSize = PageSize * 12;
+ auto stack = Allocator_->AllocStack(stackSize, "test_stack");
+#if defined(_san_enabled_) || !defined(NDEBUG)
+ stackSize *= DebugOrSanStackMultiplier;
+#endif
+
+ // Correct stack should have
+ EXPECT_EQ(stack.GetSize(), stackSize); // predefined size
+ EXPECT_FALSE((uint64_t)stack.GetAlignedMemory() & PageSizeMask); // aligned pointer
+ // Writable workspace
+ auto workspace = Allocator_->GetStackWorkspace(stack.GetAlignedMemory(), stack.GetSize());
+ for (uint64_t i = 0; i < workspace.size(); i += 512) {
+ workspace[i] = 42;
+ }
+ EXPECT_TRUE(Allocator_->CheckStackOverflow(stack.GetAlignedMemory()));
+ EXPECT_TRUE(Allocator_->CheckStackOverride(stack.GetAlignedMemory(), stack.GetSize()));
+
+ Allocator_->FreeStack(stack);
+ EXPECT_FALSE(stack.GetRawMemory());
+ }
+
+ INSTANTIATE_TEST_SUITE_P(AllocatorTestParams, TAllocatorParamFixture,
+ Combine(Values(EGuard::Canary, EGuard::Page), Values(EAllocator::Pool, EAllocator::Simple)));
+
+
+ // ------------------------------------------------------------------------
+ // Test that allocated stack has guards
+ //
+ template<class AllocatorType>
+ THolder<IAllocator> GetAllocator(EGuard guardType);
+
+ struct TPoolTag {};
+ struct TSimpleTag {};
+
+ template<>
+ THolder<IAllocator> GetAllocator<TPoolTag>(EGuard guardType) {
+ TMaybe<TPoolAllocatorSettings> poolSettings = TPoolAllocatorSettings{};
+ return GetAllocator(poolSettings, guardType);
+ }
+
+ template<>
+ THolder<IAllocator> GetAllocator<TSimpleTag>(EGuard guardType) {
+ TMaybe<TPoolAllocatorSettings> poolSettings;
+ return GetAllocator(poolSettings, guardType);
+ }
+
+
+ template <class AllocatorType>
+ class TAllocatorFixture : public Test {
+ protected:
+ TAllocatorFixture()
+ : Allocator_(GetAllocator<AllocatorType>(EGuard::Page))
+ {}
+
+ const uint64_t StackSize_ = PageSize * 2;
+ THolder<IAllocator> Allocator_;
+ };
+
+ typedef Types<TPoolTag, TSimpleTag> Implementations;
+ TYPED_TEST_SUITE(TAllocatorFixture, Implementations);
+
+ TYPED_TEST(TAllocatorFixture, StackOverflow) {
+ ASSERT_DEATH({
+ auto stack = this->Allocator_->AllocStack(this->StackSize_, "test_stack");
+
+ // Overwrite previous guard, crash is here
+ *(stack.GetAlignedMemory() - 1) = 42;
+ }, "");
+ }
+
+ TYPED_TEST(TAllocatorFixture, StackOverride) {
+ ASSERT_DEATH({
+ auto stack = this->Allocator_->AllocStack(this->StackSize_, "test_stack");
+
+ // Overwrite guard, crash is here
+ *(stack.GetAlignedMemory() + stack.GetSize() - 1) = 42;
+ }, "");
+ }
+
+}
diff --git a/library/cpp/coroutine/engine/stack/ut/stack_guards_ut.cpp b/library/cpp/coroutine/engine/stack/ut/stack_guards_ut.cpp
new file mode 100644
index 0000000000..9da9a9b3d5
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/ut/stack_guards_ut.cpp
@@ -0,0 +1,158 @@
+#include <library/cpp/coroutine/engine/stack/stack_common.h>
+#include <library/cpp/coroutine/engine/stack/stack_guards.h>
+#include <library/cpp/coroutine/engine/stack/stack_utils.h>
+#include <library/cpp/testing/gtest/gtest.h>
+
+
+using namespace testing;
+
+namespace NCoro::NStack::Tests {
+
+ template <class TGuard>
+ class TGuardFixture : public Test {
+ protected:
+ TGuardFixture() : Guard_(GetGuard<TGuard>()) {}
+
+ const TGuard& Guard_;
+ };
+
+ typedef Types<TCanaryGuard, TPageGuard> Implementations;
+ TYPED_TEST_SUITE(TGuardFixture, Implementations);
+
+ TYPED_TEST(TGuardFixture, GuardSize) {
+ const auto size = this->Guard_.GetSize();
+ EXPECT_GE(size, 64ul);
+ EXPECT_FALSE(size & 63ul); // check 64-byte alignment
+ }
+
+ TYPED_TEST(TGuardFixture, GuardAlignedSize) {
+ const auto size = this->Guard_.GetPageAlignedSize();
+ EXPECT_GE(size, PageSize);
+ EXPECT_FALSE(size & PageSizeMask); // check page-alignment
+ }
+
+ TYPED_TEST(TGuardFixture, StackWorkspace) {
+ for (uint64_t sizeInPages : {2, 5, 12}) {
+ char *rawPtr, *alignedPtr = nullptr;
+ ASSERT_TRUE(GetAlignedMemory(sizeInPages, rawPtr, alignedPtr));
+ auto workspace = this->Guard_.GetWorkspace(alignedPtr, sizeInPages * PageSize);
+ EXPECT_EQ(workspace.size(), sizeInPages * PageSize - this->Guard_.GetSize()) << " size in pages " << sizeInPages;
+
+ this->Guard_.Protect(alignedPtr, sizeInPages * PageSize, false);
+ workspace = this->Guard_.GetWorkspace(alignedPtr, sizeInPages * PageSize);
+ EXPECT_EQ(workspace.size(), sizeInPages * PageSize - this->Guard_.GetSize()) << " size in pages " << sizeInPages;
+
+ this->Guard_.RemoveProtection(alignedPtr, sizeInPages * PageSize);
+ workspace = this->Guard_.GetWorkspace(alignedPtr, sizeInPages * PageSize);
+ EXPECT_EQ(workspace.size(), sizeInPages * PageSize - this->Guard_.GetSize()) << " size in pages " << sizeInPages;
+
+ free(rawPtr);
+ }
+ }
+
+ TYPED_TEST(TGuardFixture, SetRemoveProtectionWorks) {
+ char *rawPtr, *alignedPtr = nullptr;
+ constexpr uint64_t sizeInPages = 4;
+ ASSERT_TRUE(GetAlignedMemory(sizeInPages + 1, rawPtr, alignedPtr));
+
+ this->Guard_.Protect(alignedPtr, PageSize, false); // set previous guard
+ alignedPtr += PageSize; // leave first page for previous guard
+ this->Guard_.Protect(alignedPtr, sizeInPages * PageSize, true);
+
+ EXPECT_TRUE(this->Guard_.CheckOverflow(alignedPtr));
+ EXPECT_TRUE(this->Guard_.CheckOverride(alignedPtr, sizeInPages * PageSize));
+
+ this->Guard_.RemoveProtection(alignedPtr, sizeInPages * PageSize);
+ this->Guard_.RemoveProtection(alignedPtr - PageSize, PageSize); // remove previous guard
+
+ free(rawPtr);
+ }
+
+ TEST(StackGuardTest, CanaryGuardTestOverflow) {
+ const auto& guard = GetGuard<TCanaryGuard>();
+
+ char *rawPtr, *alignedPtr = nullptr;
+ constexpr uint64_t sizeInPages = 4;
+ ASSERT_TRUE(GetAlignedMemory(sizeInPages + 1, rawPtr, alignedPtr));
+ guard.Protect(alignedPtr, PageSize, false); // set previous guard
+ alignedPtr += PageSize; // leave first page for previous guard
+ guard.Protect(alignedPtr, sizeInPages * PageSize, true);
+
+ EXPECT_TRUE(guard.CheckOverflow(alignedPtr));
+ EXPECT_TRUE(guard.CheckOverride(alignedPtr, sizeInPages * PageSize));
+
+ // Overwrite previous guard
+ *(alignedPtr - 1) = 42;
+
+ EXPECT_FALSE(guard.CheckOverflow(alignedPtr));
+
+ free(rawPtr);
+ }
+
+ TEST(StackGuardTest, CanaryGuardTestOverride) {
+ const auto& guard = GetGuard<TCanaryGuard>();
+
+ char *rawPtr, *alignedPtr = nullptr;
+ constexpr uint64_t sizeInPages = 4;
+ ASSERT_TRUE(GetAlignedMemory(sizeInPages + 1, rawPtr, alignedPtr));
+ guard.Protect(alignedPtr, PageSize, false); // set previous guard
+ alignedPtr += PageSize; // leave first page for previous guard
+ guard.Protect(alignedPtr, sizeInPages * PageSize, true);
+
+ EXPECT_TRUE(guard.CheckOverflow(alignedPtr));
+ EXPECT_TRUE(guard.CheckOverride(alignedPtr, sizeInPages * PageSize));
+
+ // Overwrite guard
+ *(alignedPtr + sizeInPages * PageSize - 1) = 42;
+
+ EXPECT_FALSE(guard.CheckOverride(alignedPtr, sizeInPages * PageSize));
+
+ free(rawPtr);
+ }
+
+ TEST(StackGuardDeathTest, PageGuardTestOverflow) {
+ ASSERT_DEATH({
+ const auto &guard = GetGuard<TPageGuard>();
+
+ char* rawPtr = nullptr;
+ char* alignedPtr = nullptr;
+ constexpr uint64_t sizeInPages = 4;
+ ASSERT_TRUE(GetAlignedMemory(sizeInPages + 1, rawPtr, alignedPtr));
+
+ guard.Protect(alignedPtr, PageSize, false); // set previous guard
+ alignedPtr += PageSize; // leave first page for previous guard
+ guard.Protect(alignedPtr, sizeInPages * PageSize, true);
+
+ // Overwrite previous guard, crash is here
+ *(alignedPtr - 1) = 42;
+
+ guard.RemoveProtection(alignedPtr, sizeInPages * PageSize);
+ guard.RemoveProtection(alignedPtr - PageSize, PageSize); // remove previous guard
+
+ free(rawPtr);
+ }, "");
+ }
+
+ TEST(StackGuardDeathTest, PageGuardTestOverride) {
+ ASSERT_DEATH({
+ const auto &guard = GetGuard<TPageGuard>();
+
+ char* rawPtr = nullptr;
+ char* alignedPtr = nullptr;
+ constexpr uint64_t sizeInPages = 4;
+ ASSERT_TRUE(GetAlignedMemory(sizeInPages + 1, rawPtr, alignedPtr));
+ guard.Protect(alignedPtr, PageSize, false); // set previous guard
+ alignedPtr += PageSize; // leave first page for previous guard
+ guard.Protect(alignedPtr, sizeInPages * PageSize, true);
+
+ // Overwrite guard, crash is here
+ *(alignedPtr + sizeInPages * PageSize - 1) = 42;
+
+ guard.RemoveProtection(alignedPtr, sizeInPages * PageSize);
+ guard.RemoveProtection(alignedPtr - PageSize, PageSize); // remove previous guard
+
+ free(rawPtr);
+ }, "");
+ }
+
+}
diff --git a/library/cpp/coroutine/engine/stack/ut/stack_pool_ut.cpp b/library/cpp/coroutine/engine/stack/ut/stack_pool_ut.cpp
new file mode 100644
index 0000000000..9e3e5e7117
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/ut/stack_pool_ut.cpp
@@ -0,0 +1,70 @@
+#include <library/cpp/coroutine/engine/stack/stack_common.h>
+#include <library/cpp/coroutine/engine/stack/stack_guards.h>
+#include <library/cpp/coroutine/engine/stack/stack_pool.h>
+#include <library/cpp/testing/gtest/gtest.h>
+
+
+using namespace testing;
+
+namespace NCoro::NStack::Tests {
+
+ template <class TGuard>
+ class TPoolFixture : public Test {
+ protected:
+ TPoolFixture() : Guard_(GetGuard<TGuard>()), Pool_(StackSize_, TPoolAllocatorSettings{1, 1, 8, 32}, Guard_) {}
+
+ const uint64_t StackSize_ = PageSize * 4;
+ const TGuard& Guard_;
+ TPool<TGuard> Pool_;
+ };
+
+ typedef Types<TCanaryGuard, TPageGuard> Implementations;
+ TYPED_TEST_SUITE(TPoolFixture, Implementations);
+
+ TYPED_TEST(TPoolFixture, AllocAndFreeStack) {
+ auto stack = this->Pool_.AllocStack("test_stack");
+ this->Pool_.FreeStack(stack);
+ EXPECT_FALSE(stack.GetRawMemory());
+ }
+
+ TYPED_TEST(TPoolFixture, FreedStackReused) {
+ auto stack = this->Pool_.AllocStack("test_stack");
+ auto rawPtr = stack.GetRawMemory();
+ auto alignedPtr = stack.GetAlignedMemory();
+
+ this->Pool_.FreeStack(stack);
+ EXPECT_FALSE(stack.GetRawMemory());
+
+ auto stack2 = this->Pool_.AllocStack("test_stack");
+ EXPECT_EQ(rawPtr, stack2.GetRawMemory());
+ EXPECT_EQ(alignedPtr, stack2.GetAlignedMemory());
+
+ this->Pool_.FreeStack(stack2);
+ EXPECT_FALSE(stack2.GetRawMemory());
+ }
+
+ TYPED_TEST(TPoolFixture, MruFreedStackReused) {
+ auto stack = this->Pool_.AllocStack("test_stack");
+ auto rawPtr = stack.GetRawMemory();
+ auto alignedPtr = stack.GetAlignedMemory();
+ auto stack2 = this->Pool_.AllocStack("test_stack");
+ auto stack3 = this->Pool_.AllocStack("test_stack");
+
+ this->Pool_.FreeStack(stack2);
+ EXPECT_FALSE(stack2.GetRawMemory());
+
+ this->Pool_.FreeStack(stack);
+ EXPECT_FALSE(stack.GetRawMemory());
+
+ auto stack4 = this->Pool_.AllocStack("test_stack");
+ EXPECT_EQ(rawPtr, stack4.GetRawMemory());
+ EXPECT_EQ(alignedPtr, stack4.GetAlignedMemory());
+
+ this->Pool_.FreeStack(stack3);
+ EXPECT_FALSE(stack.GetRawMemory());
+
+ this->Pool_.FreeStack(stack4);
+ EXPECT_FALSE(stack4.GetRawMemory());
+ }
+
+}
diff --git a/library/cpp/coroutine/engine/stack/ut/stack_ut.cpp b/library/cpp/coroutine/engine/stack/ut/stack_ut.cpp
new file mode 100644
index 0000000000..31f8ad6b61
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/ut/stack_ut.cpp
@@ -0,0 +1,60 @@
+#include <library/cpp/coroutine/engine/stack/stack.h>
+#include <library/cpp/coroutine/engine/stack/stack_common.h>
+#include <library/cpp/coroutine/engine/stack/stack_guards.h>
+#include <library/cpp/coroutine/engine/stack/stack_utils.h>
+#include <library/cpp/testing/gtest/gtest.h>
+
+
+using namespace testing;
+
+namespace NCoro::NStack::Tests {
+
+ constexpr uint64_t StackSizeInPages = 4;
+
+ template <class TGuard>
+ class TStackFixture : public Test {
+ protected: // methods
+ TStackFixture()
+ : Guard_(GetGuard<TGuard>())
+ , StackSize_(StackSizeInPages * PageSize)
+ {}
+
+ void SetUp() override {
+ ASSERT_TRUE(GetAlignedMemory(StackSizeInPages, RawMemory_, AlignedMemory_));
+ Stack_ = MakeHolder<NDetails::TStack>(RawMemory_, AlignedMemory_, StackSize_, "test_stack");
+ Guard_.Protect(AlignedMemory_, StackSize_, false);
+ }
+
+ void TearDown() override {
+ Guard_.RemoveProtection(AlignedMemory_, StackSize_);
+ free(Stack_->GetRawMemory());
+ Stack_->Reset();
+ EXPECT_EQ(Stack_->GetRawMemory(), nullptr);
+ }
+
+ protected: // data
+ const TGuard& Guard_;
+ const uint64_t StackSize_ = 0;
+ char* RawMemory_ = nullptr;
+ char* AlignedMemory_ = nullptr;
+ THolder<NDetails::TStack> Stack_;
+ };
+
+ typedef Types<TCanaryGuard, TPageGuard> Implementations;
+ TYPED_TEST_SUITE(TStackFixture, Implementations);
+
+ TYPED_TEST(TStackFixture, PointersAndSize) {
+ EXPECT_EQ(this->Stack_->GetRawMemory(), this->RawMemory_);
+ EXPECT_EQ(this->Stack_->GetAlignedMemory(), this->AlignedMemory_);
+ EXPECT_EQ(this->Stack_->GetSize(), this->StackSize_);
+ }
+
+ TYPED_TEST(TStackFixture, WriteStack) {
+ auto workspace = this->Guard_.GetWorkspace(this->Stack_->GetAlignedMemory(), this->Stack_->GetSize());
+ for (uint64_t i = 0; i < workspace.size(); i += 512) {
+ workspace[i] = 42;
+ }
+ EXPECT_TRUE(this->Guard_.CheckOverride(this->Stack_->GetAlignedMemory(), this->Stack_->GetSize()));
+ }
+
+}
diff --git a/library/cpp/coroutine/engine/stack/ut/stack_utils_ut.cpp b/library/cpp/coroutine/engine/stack/ut/stack_utils_ut.cpp
new file mode 100644
index 0000000000..dc0593dcf2
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/ut/stack_utils_ut.cpp
@@ -0,0 +1,73 @@
+#include <library/cpp/coroutine/engine/stack/stack_common.h>
+#include <library/cpp/coroutine/engine/stack/stack_utils.h>
+#include <library/cpp/testing/gtest/gtest.h>
+
+
+using namespace testing;
+
+namespace NCoro::NStack::Tests {
+
+ TEST(StackUtilsTest, Allocation) {
+ char *rawPtr, *alignedPtr = nullptr;
+ for (uint64_t i : {1, 2, 3, 4, 11}) {
+ EXPECT_TRUE(GetAlignedMemory(i, rawPtr, alignedPtr));
+ EXPECT_TRUE(rawPtr);
+ EXPECT_TRUE(alignedPtr);
+ EXPECT_FALSE((uint64_t)alignedPtr & PageSizeMask);
+ free(rawPtr);
+ }
+ }
+
+#if !defined(_san_enabled_) && defined(_linux_)
+
+ TEST(StackUtilsTest, RssReleaseOnePage) {
+ char *rawPtr, *alignedPtr = nullptr;
+ for (uint64_t i : {1, 2, 8}) {
+ EXPECT_TRUE(GetAlignedMemory(i, rawPtr, alignedPtr));
+ EXPECT_TRUE(rawPtr);
+ EXPECT_TRUE(alignedPtr);
+ EXPECT_FALSE((uint64_t)alignedPtr & PageSizeMask);
+
+ ReleaseRss(alignedPtr, i); // allocator can provide reused memory with RSS memory on it
+ EXPECT_EQ(CountMapped(alignedPtr, i), 0ul); // no RSS memory allocated
+
+ *(alignedPtr + (i - 1) * PageSize) = 42; // map RSS memory
+ EXPECT_EQ(CountMapped(alignedPtr, i), 1ul);
+
+ ReleaseRss(alignedPtr, i);
+ EXPECT_EQ(CountMapped(alignedPtr, i), 0ul) << "number of pages " << i; // no RSS memory allocated
+
+ free(rawPtr);
+ }
+ }
+
+ TEST(StackUtilsTest, RssReleaseSeveralPages) {
+ char *rawPtr, *alignedPtr = nullptr;
+
+ for (uint64_t i : {1, 2, 5, 8}) {
+ EXPECT_TRUE(GetAlignedMemory(i, rawPtr, alignedPtr));
+ EXPECT_TRUE(rawPtr);
+ EXPECT_TRUE(alignedPtr);
+ EXPECT_FALSE((uint64_t)alignedPtr & PageSizeMask);
+
+ ReleaseRss(alignedPtr, i); // allocator can provide reused memory with RSS memory on it
+ EXPECT_EQ(CountMapped(alignedPtr, i), 0ul); // no RSS memory allocated
+
+ for (uint64_t page = 0; page < i; ++page) {
+ *(alignedPtr + page * PageSize) = 42; // map RSS memory
+ EXPECT_EQ(CountMapped(alignedPtr, page + 1), page + 1);
+ }
+
+ const uint64_t pagesToKeep = (i > 2) ? 2 : i;
+
+ ReleaseRss(alignedPtr, i - pagesToKeep);
+ EXPECT_EQ(CountMapped(alignedPtr, i), pagesToKeep) << "number of pages " << i; // no RSS memory allocated
+
+ free(rawPtr);
+ }
+ }
+
+#endif
+
+}
+
diff --git a/library/cpp/coroutine/engine/stack/ut/ya.make b/library/cpp/coroutine/engine/stack/ut/ya.make
new file mode 100644
index 0000000000..65c5af9b7f
--- /dev/null
+++ b/library/cpp/coroutine/engine/stack/ut/ya.make
@@ -0,0 +1,17 @@
+GTEST()
+
+OWNER(g:balancer)
+
+SRCS(
+ stack_allocator_ut.cpp
+ stack_guards_ut.cpp
+ stack_pool_ut.cpp
+ stack_ut.cpp
+ stack_utils_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/coroutine/engine
+)
+
+END() \ No newline at end of file
diff --git a/library/cpp/coroutine/engine/trampoline.cpp b/library/cpp/coroutine/engine/trampoline.cpp
new file mode 100644
index 0000000000..10ea69ddc3
--- /dev/null
+++ b/library/cpp/coroutine/engine/trampoline.cpp
@@ -0,0 +1,50 @@
+#include "impl.h"
+#include "trampoline.h"
+
+#include "stack/stack_allocator.h"
+
+#include <util/system/info.h>
+#include <util/system/protect.h>
+#include <util/system/valgrind.h>
+#include <util/system/yassert.h>
+
+#include <cstdlib>
+#include <util/stream/format.h>
+
+
+namespace NCoro {
+
+TTrampoline::TTrampoline(NStack::IAllocator& allocator, ui32 stackSize, TFunc f, TCont* cont) noexcept
+ : Stack_(allocator, stackSize, cont->Name())
+ , Clo_{this, Stack_.Get(), cont->Name()}
+ , Ctx_(Clo_)
+ , Func_(std::move(f))
+ , Cont_(cont)
+ {}
+
+ void TTrampoline::DoRun() {
+ if (Cont_->Executor()->FailOnError()) {
+ Func_(Cont_);
+ } else {
+ try {
+ Func_(Cont_);
+ } catch (...) {}
+ }
+
+ Cont_->Terminate();
+ }
+
+ TArrayRef<char> TTrampoline::Stack() noexcept {
+ return Stack_.Get();
+ }
+
+ const char* TTrampoline::ContName() const noexcept {
+ return Cont_->Name();
+ }
+
+ void TTrampoline::DoRunNaked() {
+ DoRun();
+
+ abort();
+ }
+}
diff --git a/library/cpp/coroutine/engine/trampoline.h b/library/cpp/coroutine/engine/trampoline.h
new file mode 100644
index 0000000000..37b61cf015
--- /dev/null
+++ b/library/cpp/coroutine/engine/trampoline.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "stack/stack_common.h"
+#include "stack/stack.h"
+
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/system/context.h>
+#include <util/system/defaults.h>
+
+#if !defined(STACK_GROW_DOWN)
+# error "unsupported"
+#endif
+
+class TCont;
+typedef void (*TContFunc)(TCont*, void*);
+
+namespace NCoro {
+
+ namespace NStack {
+ class IAllocator;
+ }
+
+ class TTrampoline : public ITrampoLine, TNonCopyable {
+ public:
+ typedef std::function<void (TCont*)> TFunc;
+
+ TTrampoline(
+ NCoro::NStack::IAllocator& allocator,
+ uint32_t stackSize,
+ TFunc f,
+ TCont* cont
+ ) noexcept;
+
+ TArrayRef<char> Stack() noexcept;
+
+ TExceptionSafeContext* Context() noexcept {
+ return &Ctx_;
+ }
+
+ void SwitchTo(TExceptionSafeContext* ctx) noexcept {
+ Y_VERIFY(Stack_.LowerCanaryOk(), "Stack overflow (%s)", ContName());
+ Y_VERIFY(Stack_.UpperCanaryOk(), "Stack override (%s)", ContName());
+ Ctx_.SwitchTo(ctx);
+ }
+
+ void DoRun() override;
+
+ void DoRunNaked() override;
+
+ private:
+ const char* ContName() const noexcept;
+ private:
+ NStack::TStackHolder Stack_;
+ const TContClosure Clo_;
+ TExceptionSafeContext Ctx_;
+ TFunc Func_;
+ TCont* const Cont_;
+ };
+}
diff --git a/library/cpp/coroutine/engine/ya.make b/library/cpp/coroutine/engine/ya.make
new file mode 100644
index 0000000000..8c20b9afc3
--- /dev/null
+++ b/library/cpp/coroutine/engine/ya.make
@@ -0,0 +1,36 @@
+LIBRARY()
+
+OWNER(
+ pg
+ g:balancer
+)
+
+GENERATE_ENUM_SERIALIZATION(poller.h)
+GENERATE_ENUM_SERIALIZATION(stack/stack_common.h)
+
+PEERDIR(
+ contrib/libs/libc_compat
+ library/cpp/containers/intrusive_rb_tree
+)
+
+SRCS(
+ cont_poller.cpp
+ helper.cpp
+ impl.cpp
+ iostatus.cpp
+ network.cpp
+ poller.cpp
+ sockpool.cpp
+ stack/stack.cpp
+ stack/stack_allocator.cpp
+ stack/stack_guards.cpp
+ stack/stack_storage.cpp
+ stack/stack_utils.cpp
+ trampoline.cpp
+)
+
+END()
+
+RECURSE(
+ stack/benchmark
+)
diff --git a/library/cpp/coroutine/listener/listen.cpp b/library/cpp/coroutine/listener/listen.cpp
new file mode 100644
index 0000000000..3d4e711d1d
--- /dev/null
+++ b/library/cpp/coroutine/listener/listen.cpp
@@ -0,0 +1,354 @@
+#include "listen.h"
+
+#include <library/cpp/coroutine/engine/impl.h>
+#include <library/cpp/coroutine/engine/network.h>
+
+#include <util/network/ip.h>
+#include <util/network/address.h>
+#include <util/generic/ylimits.h>
+#include <util/generic/intrlist.h>
+
+using namespace NAddr;
+
+namespace {
+ union TSa {
+ const sockaddr* Sa;
+ const sockaddr_in* In;
+ const sockaddr_in6* In6;
+
+ inline TSa(const sockaddr* sa) noexcept
+ : Sa(sa)
+ {
+ }
+
+ inline bool operator==(const TSa& r) const noexcept {
+ if (Sa->sa_family == r.Sa->sa_family) {
+ switch (Sa->sa_family) {
+ case AF_INET:
+ return In->sin_port == r.In->sin_port && In->sin_addr.s_addr == r.In->sin_addr.s_addr;
+ case AF_INET6:
+ return In6->sin6_port == r.In6->sin6_port && !memcmp(&In6->sin6_addr, &r.In6->sin6_addr, sizeof(in6_addr));
+ }
+ }
+
+ return false;
+ }
+
+ inline bool operator!=(const TSa& r) const noexcept {
+ return !(*this == r);
+ }
+ };
+}
+
+class TContListener::TImpl {
+private:
+ struct TStoredAddrInfo: public TAddrInfo, private TNetworkAddress {
+ inline TStoredAddrInfo(const struct addrinfo* ai, const TNetworkAddress& addr) noexcept
+ : TAddrInfo(ai)
+ , TNetworkAddress(addr)
+ {
+ }
+ };
+
+private:
+ class TOneSocketListener: public TIntrusiveListItem<TOneSocketListener> {
+ public:
+ inline TOneSocketListener(TImpl* parent, IRemoteAddrPtr addr)
+ : Parent_(parent)
+ , C_(nullptr)
+ , ListenSocket_(socket(addr->Addr()->sa_family, SOCK_STREAM, 0))
+ , Addr_(std::move(addr))
+ {
+ if (ListenSocket_ == INVALID_SOCKET) {
+ ythrow TSystemError() << "can not create socket";
+ }
+
+ FixIPv6ListenSocket(ListenSocket_);
+ CheckedSetSockOpt(ListenSocket_, SOL_SOCKET, SO_REUSEADDR, 1, "reuse addr");
+
+ const TOptions& opts = Parent_->Opts_;
+ if (opts.SendBufSize) {
+ SetOutputBuffer(ListenSocket_, opts.SendBufSize);
+ }
+ if (opts.RecvBufSize) {
+ SetInputBuffer(ListenSocket_, opts.RecvBufSize);
+ }
+ if (opts.ReusePort) {
+ SetReusePort(ListenSocket_, opts.ReusePort);
+ }
+
+ SetNonBlock(ListenSocket_);
+
+ if (bind(ListenSocket_, Addr_->Addr(), Addr_->Len()) < 0) {
+ ythrow TSystemError() << "bind failed";
+ }
+ }
+
+ inline ~TOneSocketListener() {
+ Stop();
+ }
+
+ public:
+ inline void Run(TCont* cont) noexcept {
+ C_ = cont;
+ DoRun();
+ C_ = nullptr;
+ }
+
+ inline void StartListen() {
+ if (!C_) {
+ const TOptions& opts = Parent_->Opts_;
+
+ if (listen(ListenSocket_, (int)Min<size_t>(Max<int>(), opts.ListenQueue)) < 0) {
+ ythrow TSystemError() << "listen failed";
+ }
+
+ if (opts.EnableDeferAccept) {
+ SetDeferAccept(ListenSocket_);
+ }
+
+ C_ = Parent_->E_->Create<TOneSocketListener, &TOneSocketListener::Run>(this, "listen_job");
+ }
+ }
+
+ inline const IRemoteAddr* Addr() const noexcept {
+ return Addr_.Get();
+ }
+
+ inline void Stop() noexcept {
+ if (C_) {
+ C_->Cancel();
+
+ while (C_) {
+ Parent_->E_->Running()->Yield();
+ }
+ }
+ }
+
+ private:
+ inline void DoRun() noexcept {
+ while (!C_->Cancelled()) {
+ try {
+ TOpaqueAddr remote;
+ const int res = NCoro::AcceptI(C_, ListenSocket_, remote.MutableAddr(), remote.LenPtr());
+
+ if (res < 0) {
+ const int err = -res;
+
+ if (err != ECONNABORTED) {
+ if (err == ECANCELED) {
+ break;
+ }
+ if (errno == EMFILE) {
+ C_->SleepT(TDuration::MilliSeconds(1));
+ }
+
+ ythrow TSystemError(err) << "can not accept";
+ }
+ } else {
+ TSocketHolder c((SOCKET)res);
+
+ const ICallBack::TAcceptFull acc = {
+ &c,
+ &remote,
+ Addr(),
+ };
+
+ Parent_->Cb_->OnAcceptFull(acc);
+ }
+ } catch (...) {
+ try {
+ Parent_->Cb_->OnError();
+ } catch (...) {
+ }
+ }
+ }
+
+ try {
+ Parent_->Cb_->OnStop(&ListenSocket_);
+ } catch (...) {
+ }
+ }
+
+ private:
+ const TImpl* const Parent_;
+ TCont* C_;
+ TSocketHolder ListenSocket_;
+ const IRemoteAddrPtr Addr_;
+ };
+
+private:
+ class TListeners: public TIntrusiveListWithAutoDelete<TOneSocketListener, TDelete> {
+ private:
+ template <class T>
+ using TIt = std::conditional_t<std::is_const<T>::value, typename T::TConstIterator, typename T::TIterator>;
+
+ template <class T>
+ static inline TIt<T> FindImpl(T* t, const IRemoteAddr& addr) {
+ const TSa sa(addr.Addr());
+
+ TIt<T> it = t->Begin();
+ TIt<T> const end = t->End();
+
+ while (it != end && sa != it->Addr()->Addr()) {
+ ++it;
+ }
+
+ return it;
+ }
+
+ public:
+ inline TIterator Find(const IRemoteAddr& addr) {
+ return FindImpl(this, addr);
+ }
+
+ inline TConstIterator Find(const IRemoteAddr& addr) const {
+ return FindImpl(this, addr);
+ }
+ };
+
+public:
+ inline TImpl(ICallBack* cb, TContExecutor* e, const TOptions& opts) noexcept
+ : E_(e)
+ , Cb_(cb)
+ , Opts_(opts)
+ {
+ }
+
+ inline void Listen() {
+ for (TListeners::TIterator it = L_.Begin(); it != L_.End(); ++it) {
+ it->StartListen();
+ }
+ }
+
+ inline void Listen(const IRemoteAddr& addr) {
+ const TListeners::TIterator it = L_.Find(addr);
+
+ if (it != L_.End()) {
+ it->StartListen();
+ }
+ }
+
+ inline void Bind(const IRemoteAddr& addr) {
+ const TSa sa(addr.Addr());
+
+ switch (sa.Sa->sa_family) {
+ case AF_INET:
+ L_.PushBack(new TOneSocketListener(this, MakeHolder<TIPv4Addr>(*sa.In)));
+ break;
+ case AF_INET6:
+ L_.PushBack(new TOneSocketListener(this, MakeHolder<TIPv6Addr>(*sa.In6)));
+ break;
+ default:
+ ythrow yexception() << TStringBuf("unknown protocol");
+ }
+ }
+
+ inline void Bind(const TIpAddress& addr) {
+ L_.PushBack(new TOneSocketListener(this, MakeHolder<TIPv4Addr>(addr)));
+ }
+
+ inline void Bind(const TNetworkAddress& addr) {
+ for (TNetworkAddress::TIterator it = addr.Begin(); it != addr.End(); ++it) {
+ L_.PushBack(new TOneSocketListener(this, MakeHolder<TStoredAddrInfo>(&*it, addr)));
+ }
+ }
+
+ inline void StopListenAddr(const IRemoteAddr& addr) {
+ const TListeners::TIterator it = L_.Find(addr);
+
+ if (it != L_.End()) {
+ delete &*it;
+ }
+ }
+
+private:
+ TContExecutor* const E_;
+ ICallBack* const Cb_;
+ TListeners L_;
+ const TOptions Opts_;
+};
+
+TContListener::TContListener(ICallBack* cb, TContExecutor* e, const TOptions& opts)
+ : Impl_(new TImpl(cb, e, opts))
+{
+}
+
+TContListener::~TContListener() {
+}
+
+namespace {
+ template <class T>
+ static inline T&& CheckImpl(T&& impl) {
+ Y_ENSURE_EX(impl, yexception() << "not running");
+ return std::forward<T>(impl);
+ }
+}
+
+void TContListener::Listen(const IRemoteAddr& addr) {
+ CheckImpl(Impl_)->Listen(addr);
+}
+
+void TContListener::Listen(const TIpAddress& addr) {
+ return Listen(TIPv4Addr(addr));
+}
+
+void TContListener::Listen(const TNetworkAddress& addr) {
+ for (TNetworkAddress::TIterator it = addr.Begin(); it != addr.End(); ++it) {
+ Listen(TAddrInfo(&*it));
+ }
+}
+
+void TContListener::Listen() {
+ CheckImpl(Impl_)->Listen();
+}
+
+void TContListener::Bind(const IRemoteAddr& addr) {
+ CheckImpl(Impl_)->Bind(addr);
+}
+
+void TContListener::Bind(const TIpAddress& addr) {
+ return Bind(TIPv4Addr(addr));
+}
+
+void TContListener::Bind(const TNetworkAddress& addr) {
+ CheckImpl(Impl_)->Bind(addr);
+}
+
+void TContListener::Stop() noexcept {
+ Impl_.Destroy();
+}
+
+void TContListener::StopListenAddr(const IRemoteAddr& addr) {
+ CheckImpl(Impl_)->StopListenAddr(addr);
+}
+
+void TContListener::StopListenAddr(const TIpAddress& addr) {
+ return StopListenAddr(TIPv4Addr(addr));
+}
+
+void TContListener::StopListenAddr(const TNetworkAddress& addr) {
+ for (TNetworkAddress::TIterator it = addr.Begin(); it != addr.End(); ++it) {
+ StopListenAddr(TAddrInfo(&*it));
+ }
+}
+
+void TContListener::ICallBack::OnAcceptFull(const TAcceptFull& params) {
+ const TSa remote(params.Remote->Addr());
+ const TSa local(params.Local->Addr());
+
+ if (local.Sa->sa_family == AF_INET) {
+ const TIpAddress r(*remote.In);
+ const TIpAddress l(*local.In);
+
+ const TAccept a = {
+ params.S, &r, &l};
+
+ OnAccept(a);
+ }
+}
+
+void TContListener::ICallBack::OnStop(TSocketHolder* s) {
+ s->ShutDown(SHUT_RDWR);
+ s->Close();
+}
diff --git a/library/cpp/coroutine/listener/listen.h b/library/cpp/coroutine/listener/listen.h
new file mode 100644
index 0000000000..3a89cd3ecc
--- /dev/null
+++ b/library/cpp/coroutine/listener/listen.h
@@ -0,0 +1,125 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/generic/ylimits.h>
+
+struct TIpAddress;
+class TContExecutor;
+class TSocketHolder;
+class TNetworkAddress;
+
+namespace NAddr {
+ class IRemoteAddr;
+}
+
+class TContListener {
+public:
+ struct TOptions {
+ inline TOptions() noexcept
+ : ListenQueue(Max<size_t>())
+ , SendBufSize(0)
+ , RecvBufSize(0)
+ , EnableDeferAccept(false)
+ , ReusePort(false)
+ {
+ }
+
+ inline TOptions& SetListenQueue(size_t len) noexcept {
+ ListenQueue = len;
+
+ return *this;
+ }
+
+ inline TOptions& SetDeferAccept(bool enable) noexcept {
+ EnableDeferAccept = enable;
+
+ return *this;
+ }
+
+ inline TOptions& SetSendBufSize(unsigned size) noexcept {
+ SendBufSize = size;
+
+ return *this;
+ }
+
+ inline TOptions& SetRecvBufSize(unsigned size) noexcept {
+ RecvBufSize = size;
+
+ return *this;
+ }
+
+ inline TOptions& SetReusePort(bool reusePort) noexcept {
+ ReusePort = reusePort;
+
+ return *this;
+ }
+
+ size_t ListenQueue;
+ unsigned SendBufSize;
+ unsigned RecvBufSize;
+ bool EnableDeferAccept;
+ bool ReusePort;
+ };
+
+ class ICallBack {
+ public:
+ struct TAccept {
+ TSocketHolder* S;
+ const TIpAddress* Remote;
+ const TIpAddress* Local;
+ };
+
+ struct TAcceptFull {
+ TSocketHolder* S;
+ const NAddr::IRemoteAddr* Remote;
+ const NAddr::IRemoteAddr* Local;
+ };
+
+ virtual void OnAccept(const TAccept&) {
+ }
+
+ virtual void OnAcceptFull(const TAcceptFull&);
+
+ /*
+ * will be called from catch (...) {} context
+ * so your can re-throw current exception and work around it
+ */
+ virtual void OnError() = 0;
+
+ virtual void OnStop(TSocketHolder*);
+
+ virtual ~ICallBack() {
+ }
+ };
+
+ TContListener(ICallBack* cb, TContExecutor* e, const TOptions& opts = TOptions());
+ ~TContListener();
+
+ /// start listener threads
+ void Listen();
+
+ void Listen(const NAddr::IRemoteAddr& addr);
+ void Listen(const TIpAddress& addr);
+ void Listen(const TNetworkAddress& addr);
+
+ /// bind server on address. Can be called multiple times to bind on more then one address
+ void Bind(const NAddr::IRemoteAddr& addr);
+ void Bind(const TIpAddress& addr);
+ void Bind(const TNetworkAddress& addr);
+
+ void Stop() noexcept;
+
+ void StopListenAddr(const NAddr::IRemoteAddr& addr);
+ void StopListenAddr(const TIpAddress& addr);
+ void StopListenAddr(const TNetworkAddress& addr);
+
+ template <class T>
+ inline void StartListenAddr(const T& addr) {
+ Bind(addr);
+ Listen(addr);
+ }
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
diff --git a/library/cpp/coroutine/listener/ya.make b/library/cpp/coroutine/listener/ya.make
new file mode 100644
index 0000000000..700c3abe3e
--- /dev/null
+++ b/library/cpp/coroutine/listener/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ library/cpp/coroutine/engine
+)
+
+SRCS(
+ listen.cpp
+)
+
+END()
diff --git a/library/cpp/coroutine/ya.make b/library/cpp/coroutine/ya.make
new file mode 100644
index 0000000000..34e30f2b25
--- /dev/null
+++ b/library/cpp/coroutine/ya.make
@@ -0,0 +1,11 @@
+RECURSE(
+ benchmark
+ dns
+ dns/example
+ engine
+ engine/stack/ut
+ listener
+ test
+ ut
+ util
+)
diff --git a/library/cpp/cppparser/README.md b/library/cpp/cppparser/README.md
new file mode 100644
index 0000000000..a498ef2a0f
--- /dev/null
+++ b/library/cpp/cppparser/README.md
@@ -0,0 +1,3 @@
+A simple parser of C++ codes (only lexical analysis, no semantic checking)
+
+It is similar to a sax-parser by its interface.
diff --git a/library/cpp/cppparser/parser.cpp b/library/cpp/cppparser/parser.cpp
new file mode 100644
index 0000000000..3bd968b459
--- /dev/null
+++ b/library/cpp/cppparser/parser.cpp
@@ -0,0 +1,739 @@
+#include <util/generic/hash.h>
+#include <util/string/cast.h>
+#include <util/generic/hash_set.h>
+#include <util/generic/yexception.h>
+
+#include "parser.h"
+
+//#define DEBUG_ME 1
+
+TCppSaxParser::TText::TText()
+ : Offset(0)
+{
+}
+
+TCppSaxParser::TText::TText(ui64 offset)
+ : Offset(offset)
+{
+}
+
+TCppSaxParser::TText::TText(const TString& data, ui64 offset)
+ : Data(data)
+ , Offset(offset)
+{
+}
+
+TCppSaxParser::TText::~TText() = default;
+
+void TCppSaxParser::TText::Reset() noexcept {
+ Offset += Data.length();
+ Data.clear();
+}
+
+TCppSaxParser::TWorker::TWorker() noexcept = default;
+
+TCppSaxParser::TWorker::~TWorker() = default;
+
+class TCppSaxParser::TImpl {
+ enum EState {
+ Code,
+ CommentBegin,
+ String,
+ Character,
+ OneLineComment,
+ MultiLineComment,
+ MultiLineCommentEnd,
+ Preprocessor
+ };
+
+public:
+ typedef TCppSaxParser::TText TText;
+ typedef TCppSaxParser::TWorker TWorker;
+
+ inline TImpl(TWorker* worker)
+ : State_(Code)
+ , Worker_(worker)
+ , SkipNext_(false)
+ , Line_(0)
+ , Column_(0)
+ {
+ Worker_->DoStart();
+ }
+
+ inline ~TImpl() = default;
+
+ inline void Write(const void* data, size_t len) {
+ ProcessInput((const char*)data, len);
+ }
+
+ inline void Finish() {
+ if (!Text_.Data.empty()) {
+ switch (State_) {
+ case Code:
+ Worker_->DoCode(Text_);
+
+ break;
+
+ case Preprocessor:
+ Worker_->DoPreprocessor(Text_);
+
+ break;
+
+ case OneLineComment:
+ Worker_->DoOneLineComment(Text_);
+
+ break;
+
+ default:
+ ThrowError();
+ }
+ }
+
+ Worker_->DoEnd();
+ }
+
+private:
+ inline void ProcessInput(const char* data, size_t len) {
+ EState savedState = Code;
+ while (len) {
+ const char ch = *data;
+
+ if (ch == '\n') {
+ ++Line_;
+ Column_ = 0;
+ } else {
+ ++Column_;
+ }
+
+#if DEBUG_ME
+ Cerr << "char: " << ch << Endl;
+ Cerr << "state before: " << (unsigned int)State_ << Endl;
+#endif
+
+ retry:
+ switch (State_) {
+ case Code: {
+ savedState = Code;
+ switch (ch) {
+ case '/':
+ State_ = CommentBegin;
+
+ break;
+
+ case '"':
+ Action(ch);
+ State_ = String;
+
+ break;
+
+ case '\'':
+ Action(ch);
+ State_ = Character;
+
+ break;
+
+ case '#':
+ Action(ch);
+ State_ = Preprocessor;
+
+ break;
+
+ default:
+ Text_.Data += ch;
+
+ break;
+ }
+
+ break;
+ }
+
+ case CommentBegin: {
+ switch (ch) {
+ case '/':
+ State_ = savedState;
+ savedState = Code;
+ Action("//");
+ State_ = OneLineComment;
+
+ break;
+
+ case '*':
+ State_ = savedState;
+ Action("/*");
+ State_ = MultiLineComment;
+
+ break;
+
+ default:
+ Text_.Data += '/';
+ State_ = savedState;
+
+ goto retry;
+ }
+
+ break;
+ }
+
+ case OneLineComment: {
+ switch (ch) {
+ case '\n':
+ Action(ch);
+ State_ = Code;
+
+ break;
+
+ default:
+ Text_.Data += ch;
+
+ break;
+ }
+
+ break;
+ }
+
+ case MultiLineComment: {
+ switch (ch) {
+ case '*':
+ Text_.Data += ch;
+ State_ = MultiLineCommentEnd;
+
+ break;
+
+ case '\n':
+ Text_.Data += ch;
+ savedState = Code;
+
+ break;
+ default:
+ Text_.Data += ch;
+
+ break;
+ }
+
+ break;
+ }
+
+ case MultiLineCommentEnd: {
+ switch (ch) {
+ case '/':
+ Text_.Data += ch;
+ Action();
+ State_ = savedState;
+
+ break;
+
+ default:
+ State_ = MultiLineComment;
+
+ goto retry;
+ }
+
+ break;
+ }
+
+ case String: {
+ switch (ch) {
+ case '"':
+ Text_.Data += ch;
+
+ if (SkipNext_) {
+ SkipNext_ = false;
+ } else {
+ if (savedState == Code) {
+ Action();
+ }
+ State_ = savedState;
+ }
+
+ break;
+
+ case '\\':
+ Text_.Data += ch;
+ SkipNext_ = !SkipNext_;
+
+ break;
+
+ default:
+ Text_.Data += ch;
+ SkipNext_ = false;
+
+ break;
+ }
+
+ break;
+ }
+
+ case Character: {
+ switch (ch) {
+ case '\'':
+ Text_.Data += ch;
+
+ if (SkipNext_) {
+ SkipNext_ = false;
+ } else {
+ if (savedState == Code) {
+ Action();
+ }
+ State_ = savedState;
+ }
+
+ break;
+
+ case '\\':
+ Text_.Data += ch;
+ SkipNext_ = !SkipNext_;
+
+ break;
+
+ default:
+ Text_.Data += ch;
+ SkipNext_ = false;
+
+ break;
+ }
+
+ break;
+ }
+
+ case Preprocessor: {
+ savedState = Preprocessor;
+ switch (ch) {
+ case '/':
+ State_ = CommentBegin;
+
+ break;
+
+ case '\'':
+ Text_.Data += ch;
+ State_ = Character;
+
+ break;
+
+ case '"':
+ Text_.Data += ch;
+ State_ = String;
+
+ break;
+ case '\n':
+ Text_.Data += ch;
+
+ if (SkipNext_) {
+ SkipNext_ = false;
+ } else {
+ Action();
+ savedState = Code;
+ State_ = Code;
+ }
+
+ break;
+
+ case '\\':
+ Text_.Data += ch;
+ SkipNext_ = true;
+
+ break;
+
+ default:
+ Text_.Data += ch;
+ SkipNext_ = false;
+
+ break;
+ }
+
+ break;
+ }
+
+ default:
+ ThrowError();
+ }
+
+#if DEBUG_ME
+ Cerr << "state after: " << (unsigned int)State_ << Endl;
+#endif
+
+ ++data;
+ --len;
+ }
+ }
+
+ inline void Action(char ch) {
+ Action();
+ Text_.Data += ch;
+ }
+
+ inline void Action(const char* st) {
+ Action();
+ Text_.Data += st;
+ }
+
+ inline void Action() {
+ switch (State_) {
+ case Code:
+ Worker_->DoCode(Text_);
+
+ break;
+
+ case OneLineComment:
+ Worker_->DoOneLineComment(Text_);
+
+ break;
+
+ case MultiLineCommentEnd:
+ Worker_->DoMultiLineComment(Text_);
+
+ break;
+
+ case Preprocessor:
+ Worker_->DoPreprocessor(Text_);
+
+ break;
+
+ case String:
+ Worker_->DoString(Text_);
+
+ break;
+
+ case Character:
+ Worker_->DoCharacter(Text_);
+
+ break;
+
+ default:
+ ThrowError();
+ }
+
+ Text_.Reset();
+ }
+
+ inline void ThrowError() const {
+ ythrow yexception() << "can not parse source(line = " << (unsigned)Line_ + 1 << ", column = " << (unsigned)Column_ + 1 << ")";
+ }
+
+private:
+ EState State_;
+ TWorker* Worker_;
+ TText Text_;
+ bool SkipNext_;
+ ui64 Line_;
+ ui64 Column_;
+};
+
+TCppSaxParser::TCppSaxParser(TWorker* worker)
+ : Impl_(new TImpl(worker))
+{
+}
+
+TCppSaxParser::~TCppSaxParser() = default;
+
+void TCppSaxParser::DoWrite(const void* data, size_t len) {
+ Impl_->Write(data, len);
+}
+
+void TCppSaxParser::DoFinish() {
+ Impl_->Finish();
+}
+
+TCppSimpleSax::TCppSimpleSax() noexcept {
+}
+
+TCppSimpleSax::~TCppSimpleSax() = default;
+
+void TCppSimpleSax::DoCode(const TText& text) {
+ static const char char_types[] = {
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 0, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1,
+ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
+
+ static const char CWHITESPACE = 0;
+ static const char CIDENTIFIER = 1;
+ static const char CSYNTAX = 2;
+
+ enum EState {
+ WhiteSpace = CWHITESPACE,
+ Identifier = CIDENTIFIER,
+ Syntax = CSYNTAX
+ };
+
+ EState state = Identifier;
+ TText cur(text.Offset);
+
+ for (const auto& it : text.Data) {
+ const unsigned char ch = *(const unsigned char*)(&it);
+ const char type = char_types[ch];
+
+ switch (state) {
+ case Identifier: {
+ switch (type) {
+ case CIDENTIFIER:
+ cur.Data += ch;
+
+ break;
+
+ default:
+ if (!cur.Data.empty()) {
+ DoIdentifier(cur);
+ }
+
+ cur.Reset();
+ cur.Data += ch;
+ state = (EState)type;
+
+ break;
+ }
+
+ break;
+ }
+
+ case WhiteSpace: {
+ switch (type) {
+ case CWHITESPACE:
+ cur.Data += ch;
+
+ break;
+
+ default:
+ DoWhiteSpace(cur);
+ cur.Reset();
+ cur.Data += ch;
+ state = (EState)type;
+
+ break;
+ }
+
+ break;
+ }
+
+ case Syntax: {
+ switch (type) {
+ case CSYNTAX:
+ cur.Data += ch;
+
+ break;
+
+ default:
+ DoSyntax(cur);
+ cur.Reset();
+ cur.Data += ch;
+ state = (EState)type;
+
+ break;
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (!cur.Data.empty()) {
+ switch (state) {
+ case Identifier:
+ DoIdentifier(cur);
+
+ break;
+
+ case WhiteSpace:
+ DoWhiteSpace(cur);
+
+ break;
+
+ case Syntax:
+ DoSyntax(cur);
+
+ break;
+ }
+ }
+}
+
+class TCppFullSax::TImpl {
+ typedef THashSet<TString> TKeyWords;
+
+ class TRegExp {
+ public:
+ inline TRegExp(const char*) {
+ }
+
+ inline bool Match(const TString& /*s*/) const noexcept {
+ return false;
+ }
+ };
+
+public:
+ inline TImpl()
+ : OctNumber_("^[+-]?0[0-7]+$")
+ , HexNumber_("^[+-]?0x[0-9A-Fa-f]+$")
+ , DecNumber_("^[+-]?[0-9]+$")
+ , FltNumber_("^[+-]?[0-9]*\\.[0-9]*$")
+ {
+ AddKeyword("extern");
+ AddKeyword("static");
+ AddKeyword("inline");
+ AddKeyword("volatile");
+ AddKeyword("asm");
+ AddKeyword("const");
+ AddKeyword("mutable");
+ AddKeyword("char");
+ AddKeyword("signed");
+ AddKeyword("unsigned");
+ AddKeyword("int");
+ AddKeyword("short");
+ AddKeyword("long");
+ AddKeyword("double");
+ AddKeyword("float");
+ AddKeyword("bool");
+ AddKeyword("class");
+ AddKeyword("struct");
+ AddKeyword("union");
+ AddKeyword("void");
+ AddKeyword("auto");
+ AddKeyword("throw");
+ AddKeyword("try");
+ AddKeyword("catch");
+ AddKeyword("for");
+ AddKeyword("do");
+ AddKeyword("if");
+ AddKeyword("else");
+ AddKeyword("while");
+ AddKeyword("switch");
+ AddKeyword("case");
+ AddKeyword("default");
+ AddKeyword("goto");
+ AddKeyword("break");
+ AddKeyword("continue");
+ AddKeyword("virtual");
+ AddKeyword("template");
+ AddKeyword("typename");
+ AddKeyword("enum");
+ AddKeyword("public");
+ AddKeyword("private");
+ AddKeyword("protected");
+ AddKeyword("using");
+ AddKeyword("namespace");
+ AddKeyword("typedef");
+ AddKeyword("true");
+ AddKeyword("false");
+ AddKeyword("return");
+ AddKeyword("new");
+ AddKeyword("delete");
+ AddKeyword("operator");
+ AddKeyword("friend");
+ AddKeyword("this");
+ }
+
+ inline ~TImpl() = default;
+
+ inline void AddKeyword(const TString& keyword) {
+ KeyWords_.insert(keyword);
+ }
+
+ inline bool IsKeyword(const TString& s) {
+ return KeyWords_.find(s) != KeyWords_.end();
+ }
+
+ inline bool IsOctNumber(const TString& s) {
+ return OctNumber_.Match(s);
+ }
+
+ inline bool IsHexNumber(const TString& s) {
+ return HexNumber_.Match(s);
+ }
+
+ inline bool IsDecNumber(const TString& s) {
+ return DecNumber_.Match(s);
+ }
+
+ inline bool IsFloatNumber(const TString& s) {
+ return FltNumber_.Match(s);
+ }
+
+private:
+ const TRegExp OctNumber_;
+ const TRegExp HexNumber_;
+ const TRegExp DecNumber_;
+ const TRegExp FltNumber_;
+ TKeyWords KeyWords_;
+};
+
+TCppFullSax::TCppFullSax()
+ : Impl_(new TImpl())
+{
+}
+
+TCppFullSax::~TCppFullSax() = default;
+
+void TCppFullSax::AddKeyword(const TString& keyword) {
+ Impl_->AddKeyword(keyword);
+}
+
+void TCppFullSax::DoIdentifier(const TText& text) {
+ if (Impl_->IsKeyword(text.Data)) {
+ DoKeyword(text);
+ } else if (Impl_->IsOctNumber(text.Data)) {
+ DoOctNumber(text);
+ } else if (Impl_->IsHexNumber(text.Data)) {
+ DoHexNumber(text);
+ } else if (Impl_->IsDecNumber(text.Data)) {
+ DoDecNumber(text);
+ } else if (Impl_->IsFloatNumber(text.Data)) {
+ DoFloatNumber(text);
+ } else {
+ DoName(text);
+ }
+}
+
+void TCppFullSax::DoEnd() {
+}
+
+void TCppFullSax::DoStart() {
+}
+
+void TCppFullSax::DoString(const TText&) {
+}
+
+void TCppFullSax::DoCharacter(const TText&) {
+}
+
+void TCppFullSax::DoWhiteSpace(const TText&) {
+}
+
+void TCppFullSax::DoKeyword(const TText&) {
+}
+
+void TCppFullSax::DoName(const TText&) {
+}
+
+void TCppFullSax::DoOctNumber(const TText&) {
+}
+
+void TCppFullSax::DoHexNumber(const TText&) {
+}
+
+void TCppFullSax::DoDecNumber(const TText&) {
+}
+
+void TCppFullSax::DoFloatNumber(const TText&) {
+}
+
+void TCppFullSax::DoSyntax(const TText&) {
+}
+
+void TCppFullSax::DoOneLineComment(const TText&) {
+}
+
+void TCppFullSax::DoMultiLineComment(const TText&) {
+}
+
+void TCppFullSax::DoPreprocessor(const TText&) {
+}
diff --git a/library/cpp/cppparser/parser.h b/library/cpp/cppparser/parser.h
new file mode 100644
index 0000000000..f3e4bcbadd
--- /dev/null
+++ b/library/cpp/cppparser/parser.h
@@ -0,0 +1,99 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+#include <util/stream/output.h>
+
+class TCppSaxParser: public IOutputStream {
+public:
+ struct TText {
+ TText();
+ TText(ui64 offset);
+ TText(const TString& data, ui64 offset);
+ ~TText();
+
+ void Reset() noexcept;
+
+ TString Data;
+ ui64 Offset;
+ };
+
+ class TWorker {
+ public:
+ typedef TCppSaxParser::TText TText;
+
+ TWorker() noexcept;
+ virtual ~TWorker();
+
+ virtual void DoEnd() = 0;
+ virtual void DoStart() = 0;
+ virtual void DoString(const TText& text) = 0;
+ virtual void DoCharacter(const TText& text) = 0;
+ virtual void DoCode(const TText& text) = 0;
+ virtual void DoOneLineComment(const TText& text) = 0;
+ virtual void DoMultiLineComment(const TText& text) = 0;
+ virtual void DoPreprocessor(const TText& text) = 0;
+ };
+
+ TCppSaxParser(TWorker* worker);
+ ~TCppSaxParser() override;
+
+private:
+ void DoWrite(const void* data, size_t len) override;
+ void DoFinish() override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+class TCppSimpleSax: public TCppSaxParser::TWorker {
+public:
+ TCppSimpleSax() noexcept;
+ ~TCppSimpleSax() override;
+
+ void DoEnd() override = 0;
+ void DoStart() override = 0;
+ void DoString(const TText& text) override = 0;
+ void DoCharacter(const TText& text) override = 0;
+ virtual void DoWhiteSpace(const TText& text) = 0;
+ virtual void DoIdentifier(const TText& text) = 0;
+ virtual void DoSyntax(const TText& text) = 0;
+ void DoOneLineComment(const TText& text) override = 0;
+ void DoMultiLineComment(const TText& text) override = 0;
+ void DoPreprocessor(const TText& text) override = 0;
+
+private:
+ void DoCode(const TText& text) override;
+};
+
+class TCppFullSax: public TCppSimpleSax {
+public:
+ TCppFullSax();
+ ~TCppFullSax() override;
+
+ void DoEnd() override;
+ void DoStart() override;
+ void DoString(const TText& text) override;
+ void DoCharacter(const TText& text) override;
+ void DoWhiteSpace(const TText& text) override;
+ virtual void DoKeyword(const TText& text);
+ virtual void DoName(const TText& text);
+ virtual void DoOctNumber(const TText& text);
+ virtual void DoHexNumber(const TText& text);
+ virtual void DoDecNumber(const TText& text);
+ virtual void DoFloatNumber(const TText& text);
+ void DoSyntax(const TText& text) override;
+ void DoOneLineComment(const TText& text) override;
+ void DoMultiLineComment(const TText& text) override;
+ void DoPreprocessor(const TText& text) override;
+
+ void AddKeyword(const TString& keyword);
+
+private:
+ void DoIdentifier(const TText& text) override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
diff --git a/library/cpp/cppparser/ya.make b/library/cpp/cppparser/ya.make
new file mode 100644
index 0000000000..bbb0bc11cd
--- /dev/null
+++ b/library/cpp/cppparser/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(pg)
+
+SRCS(
+ parser.cpp
+)
+
+END()
diff --git a/library/cpp/cpuid_check/README.md b/library/cpp/cpuid_check/README.md
new file mode 100644
index 0000000000..9c0e8dfa59
--- /dev/null
+++ b/library/cpp/cpuid_check/README.md
@@ -0,0 +1,13 @@
+Simple utility to check base target x86 SIMD exensions at startup.
+
+Program may be built with some SIMD extension enabled (e.g. `-msse4.2`). `PEERDIR` to this library adds statrup check that machine where the program is running supports SIMD extension the program is built for.
+
+Currently supported check are: sse4.2, pclmul, aes, avx, avx2 and fma.
+
+**Note:** the library depends on `util`.
+**Note:** the library adds stratup code and so if `PEERDIR`-ed from `LIBRARY` will do so for all `PROGRAM`-s that (transitively) use the `LIBRARY`. Don't do this!
+
+You normally don't need to `PEERDIR` this library at all. Since making sse4 in Arcadia default this library is used implicitly. It is `PEERDIR`-ed from all `PROGRAM`-s and derived modules (e.g. `PY2_PROGRAM`, but not `GO_PROGRAM` or `JAVA_PROGRAM`).
+It is also not applied to `PROGRAM`-s where `NO_UTIL()`, `NO_PLATFORM()` or `ALLOCATOR(FAKE)` set to avoid undesired dependencied. To disable this implicit check use `NO_CPU_CHECK()` macro or `-DCPU_CHECK=no` ya make flag.
+
+
diff --git a/library/cpp/cpuid_check/cpu_id_check.cpp b/library/cpp/cpuid_check/cpu_id_check.cpp
new file mode 100644
index 0000000000..f19a573567
--- /dev/null
+++ b/library/cpp/cpuid_check/cpu_id_check.cpp
@@ -0,0 +1,64 @@
+#include <util/system/compat.h>
+#include <util/system/compiler.h>
+#include <util/system/cpu_id.h>
+#include <util/system/platform.h>
+
+#define Y_CPU_ID_ENUMERATE_STARTUP_CHECKS(F) \
+ F(SSE42) \
+ F(PCLMUL) \
+ F(AES) \
+ F(AVX) \
+ F(AVX2) \
+ F(FMA)
+
+namespace {
+ [[noreturn]] void ReportISAError(const char* isa) {
+ err(-1, "This program was compiled for %s which is not supported on your system, exiting...", isa);
+ }
+
+#define Y_DEF_NAME(X) \
+ void Assert##X() noexcept { \
+ if (!NX86::Have##X()) { \
+ ReportISAError(#X); \
+ } \
+ }
+
+ Y_CPU_ID_ENUMERATE_STARTUP_CHECKS(Y_DEF_NAME)
+#undef Y_DEF_NAME
+
+ class TBuildCpuChecker {
+ public:
+ TBuildCpuChecker() {
+ Check();
+ }
+
+ private:
+ void Check() const noexcept {
+#if defined(_fma_)
+ AssertFMA();
+#elif defined(_avx2_)
+ AssertAVX2();
+#elif defined(_avx_)
+ AssertAVX();
+#elif defined(_aes_)
+ AssertAES();
+#elif defined(_pclmul_)
+ AssertPCLMUL();
+#elif defined(_sse4_2_)
+ AssertSSE42();
+#endif
+
+#define Y_DEF_NAME(X) Y_UNUSED(Assert##X);
+ Y_CPU_ID_ENUMERATE_STARTUP_CHECKS(Y_DEF_NAME)
+#undef Y_DEF_NAME
+ }
+ };
+}
+
+#if defined(_x86_) && !defined(_MSC_VER)
+#define INIT_PRIORITY(x) __attribute__((init_priority(x)))
+#else
+#define INIT_PRIORITY(x)
+#endif
+
+const static TBuildCpuChecker CheckCpuWeAreRunningOn INIT_PRIORITY(101) ;
diff --git a/library/cpp/cpuid_check/ya.make b/library/cpp/cpuid_check/ya.make
new file mode 100644
index 0000000000..9d794f3edc
--- /dev/null
+++ b/library/cpp/cpuid_check/ya.make
@@ -0,0 +1,7 @@
+LIBRARY()
+
+OWNER(g:util g:ymake)
+
+SRCS(GLOBAL cpu_id_check.cpp)
+
+END()
diff --git a/library/cpp/dbg_output/DONT_COMMIT.h b/library/cpp/dbg_output/DONT_COMMIT.h
new file mode 100644
index 0000000000..e7b3182c20
--- /dev/null
+++ b/library/cpp/dbg_output/DONT_COMMIT.h
@@ -0,0 +1,16 @@
+#pragma once
+
+// Including this file is possible without modifying PEERDIR (for debug purposes).
+// The latter is allowed only locally, so this file is named
+// in such a way that including it prevents from committing the #include via ARC-1205.
+
+#define DBGDUMP_INLINE_IF_INCLUDED inline
+
+#include "dump.cpp"
+#include "dumpers.cpp"
+#include "engine.cpp"
+
+#include <library/cpp/colorizer/colors.cpp>
+#include <library/cpp/colorizer/output.cpp>
+
+#undef DBGDUMP_INLINE_IF_INCLUDED
diff --git a/library/cpp/dbg_output/auto.h b/library/cpp/dbg_output/auto.h
new file mode 100644
index 0000000000..8d96167f6a
--- /dev/null
+++ b/library/cpp/dbg_output/auto.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <util/generic/va_args.h>
+
+// int a = 1, b = 2; Cout << LabeledDump(a, b, 1 + 2); yields {"a": 1, "b": 2, "1 + 2": 3}
+#define LabeledDump(...) \
+ '{' Y_PASS_VA_ARGS(Y_MAP_ARGS_WITH_LAST(__LABELED_DUMP_NONLAST__, __LABELED_DUMP_IMPL__, __VA_ARGS__)) << '}'
+#define __LABELED_DUMP_IMPL__(x) << "\"" #x "\": " << DbgDump(x)
+#define __LABELED_DUMP_NONLAST__(x) __LABELED_DUMP_IMPL__(x) << ", "
+
+// Usage: struct TMyStruct { int A, B; }; DEFINE_DUMPER(TMyStruct, A, B); Cout << TMyStruct{3, 4};
+// yields {"A": 3, "B": 4}
+#define DEFINE_DUMPER(C, ...) \
+ template <> \
+ struct TDumper<C> { \
+ template <class S> \
+ static inline void Dump(S& s, const C& v) { \
+ s << DumpRaw("{") Y_PASS_VA_ARGS(Y_MAP_ARGS_WITH_LAST(__DEFINE_DUMPER_NONLAST__, __DEFINE_DUMPER_IMPL__, __VA_ARGS__)) << DumpRaw("}"); \
+ } \
+ };
+#define __DEFINE_DUMPER_IMPL__(x) << DumpRaw("\"" #x "\": ") << v.x
+#define __DEFINE_DUMPER_NONLAST__(x) __DEFINE_DUMPER_IMPL__(x) << DumpRaw(", ")
diff --git a/library/cpp/dbg_output/colorscheme.h b/library/cpp/dbg_output/colorscheme.h
new file mode 100644
index 0000000000..a5b9cf749a
--- /dev/null
+++ b/library/cpp/dbg_output/colorscheme.h
@@ -0,0 +1,100 @@
+#pragma once
+
+#include "engine.h"
+#include <library/cpp/colorizer/output.h>
+
+#ifndef DBG_OUTPUT_DEFAULT_COLOR_SCHEME
+#define DBG_OUTPUT_DEFAULT_COLOR_SCHEME NDbgDump::NColorScheme::TPlain
+#endif
+
+#define DBG_OUTPUT_COLOR_HANDLER(NAME) \
+ template <class S> \
+ inline void NAME(S& stream)
+
+namespace NDbgDump {
+ namespace NColorScheme {
+ /// Start by copying this one if you want to define a custom color scheme.
+ struct TPlain {
+ // Foreground color modifiers
+ DBG_OUTPUT_COLOR_HANDLER(Markup) {
+ Y_UNUSED(stream);
+ }
+ DBG_OUTPUT_COLOR_HANDLER(String) {
+ Y_UNUSED(stream);
+ }
+ DBG_OUTPUT_COLOR_HANDLER(Literal) {
+ Y_UNUSED(stream);
+ }
+ DBG_OUTPUT_COLOR_HANDLER(ResetType) {
+ Y_UNUSED(stream);
+ }
+
+ // Background color modifiers
+ DBG_OUTPUT_COLOR_HANDLER(Key) {
+ Y_UNUSED(stream);
+ }
+ DBG_OUTPUT_COLOR_HANDLER(Value) {
+ Y_UNUSED(stream);
+ }
+ DBG_OUTPUT_COLOR_HANDLER(ResetRole) {
+ Y_UNUSED(stream);
+ }
+ };
+
+ /// Use this one if you want colors but are lazy enough to define a custom color scheme.
+ /// Be careful enough to use DumpRaw for avoiding an endless recursion.
+ /// Enforce controls whether colors should be applied even if stdout is not a TTY.
+ template <bool Enforce = false>
+ class TEyebleed {
+ public:
+ TEyebleed() {
+ if (Enforce) {
+ Colors.Enable();
+ }
+ }
+
+ // Foreground color modifiers
+ DBG_OUTPUT_COLOR_HANDLER(Markup) {
+ stream << DumpRaw(Colors.LightGreenColor());
+ }
+ DBG_OUTPUT_COLOR_HANDLER(String) {
+ stream << DumpRaw(Colors.YellowColor());
+ }
+ DBG_OUTPUT_COLOR_HANDLER(Literal) {
+ stream << DumpRaw(Colors.LightRedColor());
+ }
+ DBG_OUTPUT_COLOR_HANDLER(ResetType) {
+ stream << DumpRaw(Colors.OldColor());
+ }
+
+ // Background color modifiers
+ // TODO: support backgrounds in library/cpp/colorizer
+ DBG_OUTPUT_COLOR_HANDLER(Key) {
+ if (Depth++ == 0 && Colors.IsTTY()) {
+ stream << DumpRaw(TStringBuf("\033[42m"));
+ }
+ }
+ DBG_OUTPUT_COLOR_HANDLER(Value) {
+ if (Depth++ == 0 && Colors.IsTTY()) {
+ stream << DumpRaw(TStringBuf("\033[44m"));
+ }
+ }
+ DBG_OUTPUT_COLOR_HANDLER(ResetRole) {
+ if (--Depth == 0 && Colors.IsTTY()) {
+ stream << DumpRaw(TStringBuf("\033[49m"));
+ }
+ }
+
+ private:
+ NColorizer::TColors Colors;
+ size_t Depth = 0;
+ };
+ }
+}
+
+namespace NPrivate {
+ template <typename CS>
+ struct TColorSchemeContainer {
+ CS ColorScheme;
+ };
+}
diff --git a/library/cpp/dbg_output/dump.cpp b/library/cpp/dbg_output/dump.cpp
new file mode 100644
index 0000000000..ab09a93822
--- /dev/null
+++ b/library/cpp/dbg_output/dump.cpp
@@ -0,0 +1 @@
+#include "dump.h"
diff --git a/library/cpp/dbg_output/dump.h b/library/cpp/dbg_output/dump.h
new file mode 100644
index 0000000000..c7efa105ee
--- /dev/null
+++ b/library/cpp/dbg_output/dump.h
@@ -0,0 +1,106 @@
+#pragma once
+
+#include "engine.h"
+#include "dumpers.h"
+#include "auto.h"
+#include "colorscheme.h"
+
+#include <util/stream/format.h>
+#include <util/system/type_name.h>
+#include <util/generic/hash_set.h>
+#include <utility>
+
+/*
+ * Cout << DbgDump(any) << Endl;
+ * Cout << DbgDumpDeep(any) << Endl;
+ * Cout << DbgDump(any).SetIndent(true) << Endl;
+ *
+ * specialize TDumper<your type> for extending dumper
+ */
+
+namespace NPrivate {
+ template <class TColorScheme>
+ struct TTraitsShallow {
+ struct TDump: public TDumpBase, public TColorSchemeContainer<TColorScheme> {
+ template <typename... Args>
+ inline TDump(Args&&... args)
+ : TDumpBase(std::forward<Args>(args)...)
+ {
+ }
+
+ template <class V>
+ inline void Pointer(const V* v) {
+ if (v) {
+ *this << DumpRaw("(") << DumpRaw(TypeName(v).data()) << DumpRaw(")") << Hex((size_t)v);
+ } else {
+ *this << DumpRaw("(") << DumpRaw(TypeName<V>().data()) << DumpRaw("*)nullptr");
+ }
+ }
+ };
+ };
+
+ template <class TColorScheme>
+ struct TTraitsDeep {
+ struct TDump: public TDumpBase, public TColorSchemeContainer<TColorScheme> {
+ template <typename... Args>
+ inline TDump(Args&&... args)
+ : TDumpBase(std::forward<Args>(args)...)
+ {
+ }
+
+ template <class V>
+ inline void Pointer(const V* v) {
+ if (v && !Visited.contains((size_t)v)) {
+ Visited.insert((size_t)v);
+ *this << DumpRaw("(") << DumpRaw(TypeName(v).data()) << DumpRaw(")") << Hex((size_t)v) << DumpRaw(" -> ") << *v;
+ Visited.erase((size_t)v);
+ } else {
+ *this << DumpRaw("(") << DumpRaw(TypeName<V>().data()) << DumpRaw("*)nullptr");
+ }
+ }
+
+ THashSet<size_t> Visited;
+ };
+ };
+
+ template <class T, class TTraits>
+ struct TDbgDump {
+ inline TDbgDump(const T* t)
+ : T_(t)
+ , Indent(false)
+ {
+ }
+
+ inline void DumpTo(IOutputStream& out) const {
+ typename TTraits::TDump d(out, Indent);
+
+ d << *T_;
+ }
+
+ inline TDbgDump& SetIndent(bool v) noexcept {
+ Indent = v;
+
+ return *this;
+ }
+
+ const T* T_;
+ bool Indent;
+ };
+
+ template <class T, class TTraits>
+ static inline IOutputStream& operator<<(IOutputStream& out, const TDbgDump<T, TTraits>& d) {
+ d.DumpTo(out);
+
+ return out;
+ }
+}
+
+template <class T, class TColorScheme = DBG_OUTPUT_DEFAULT_COLOR_SCHEME>
+static inline ::NPrivate::TDbgDump<T, ::NPrivate::TTraitsShallow<TColorScheme>> DbgDump(const T& t) {
+ return {std::addressof(t)};
+}
+
+template <class T, class TColorScheme = DBG_OUTPUT_DEFAULT_COLOR_SCHEME>
+static inline ::NPrivate::TDbgDump<T, ::NPrivate::TTraitsDeep<TColorScheme>> DbgDumpDeep(const T& t) {
+ return {std::addressof(t)};
+}
diff --git a/library/cpp/dbg_output/dumpers.cpp b/library/cpp/dbg_output/dumpers.cpp
new file mode 100644
index 0000000000..b85d15755b
--- /dev/null
+++ b/library/cpp/dbg_output/dumpers.cpp
@@ -0,0 +1 @@
+#include "dumpers.h"
diff --git a/library/cpp/dbg_output/dumpers.h b/library/cpp/dbg_output/dumpers.h
new file mode 100644
index 0000000000..4868e97da0
--- /dev/null
+++ b/library/cpp/dbg_output/dumpers.h
@@ -0,0 +1,173 @@
+#pragma once
+
+#include "engine.h"
+
+#include <util/generic/fwd.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+
+//smart pointers
+template <class T, class D>
+struct TDumper<TAutoPtr<T, D>> {
+ template <class S>
+ static inline void Dump(S& s, const TAutoPtr<T, D>& v) {
+ s << DumpRaw("TAutoPtr(") << v.Get() << DumpRaw(")");
+ }
+};
+
+template <class T, class D>
+struct TDumper<THolder<T, D>> {
+ template <class S>
+ static inline void Dump(S& s, const THolder<T, D>& v) {
+ s << DumpRaw("THolder(") << v.Get() << DumpRaw(")");
+ }
+};
+
+template <class T, class Ops>
+struct TDumper<TIntrusivePtr<T, Ops>> {
+ template <class S>
+ static inline void Dump(S& s, const TIntrusivePtr<T, Ops>& v) {
+ s << DumpRaw("TIntrusivePtr(") << v.Get() << DumpRaw(")");
+ }
+};
+
+template <class T, class C, class D>
+struct TDumper<TSharedPtr<T, C, D>> {
+ template <class S>
+ static inline void Dump(S& s, const TSharedPtr<T, C, D>& v) {
+ s << DumpRaw("TSharedPtr(") << v.Get() << DumpRaw(")");
+ }
+};
+
+template <class T, class C, class D>
+struct TDumper<TCopyPtr<T, C, D>> {
+ template <class S>
+ static inline void Dump(S& s, const TCopyPtr<T, C, D>& v) {
+ s << DumpRaw("TCopyPtr(") << v.Get() << DumpRaw(")");
+ }
+};
+
+//small ints
+// Default dumper prints them via IOutputStream << (value), which results in raw
+// chars, not integer values. Cast to a bigger int type to force printing as
+// integers.
+// NB: i8 = signed char != char != unsigned char = ui8
+template <>
+struct TDumper<ui8>: public TDumper<i32> {
+};
+
+template <>
+struct TDumper<i8>: public TDumper<i32> {
+};
+
+//chars
+template <>
+struct TDumper<char>: public TCharDumper {
+};
+
+template <>
+struct TDumper<wchar16>: public TCharDumper {
+};
+
+//pairs
+template <class A, class B>
+struct TDumper<std::pair<A, B>> {
+ template <class S>
+ static inline void Dump(S& s, const std::pair<A, B>& v) {
+ s.ColorScheme.Key(s);
+ s.ColorScheme.Literal(s);
+ s << v.first;
+ s.ColorScheme.ResetType(s);
+ s.ColorScheme.ResetRole(s);
+ s.ColorScheme.Markup(s);
+ s << DumpRaw(" -> ");
+ s.ColorScheme.Value(s);
+ s.ColorScheme.Literal(s);
+ s << v.second;
+ s.ColorScheme.ResetType(s);
+ s.ColorScheme.ResetRole(s);
+ }
+};
+
+//sequences
+template <class T, class A>
+struct TDumper<TVector<T, A>>: public TSeqDumper {
+};
+
+template <class T, class A>
+struct TDumper<std::vector<T, A>>: public TSeqDumper {
+};
+
+template <class T>
+struct TDumper<TArrayRef<T>>: public TSeqDumper {
+};
+
+template <class T, size_t N>
+struct TDumper<std::array<T, N>>: public TSeqDumper {
+};
+
+template <class T, class A>
+struct TDumper<TDeque<T, A>>: public TSeqDumper {
+};
+
+template <class T, class A>
+struct TDumper<TList<T, A>>: public TSeqDumper {
+};
+
+//associatives
+template <class K, class V, class P, class A>
+struct TDumper<TMap<K, V, P, A>>: public TAssocDumper {
+};
+
+template <class K, class V, class P, class A>
+struct TDumper<TMultiMap<K, V, P, A>>: public TAssocDumper {
+};
+
+template <class T, class P, class A>
+struct TDumper<TSet<T, P, A>>: public TAssocDumper {
+};
+
+template <class T, class P, class A>
+struct TDumper<TMultiSet<T, P, A>>: public TAssocDumper {
+};
+
+template <class K, class V, class H, class P, class A>
+struct TDumper<THashMap<K, V, H, P, A>>: public TAssocDumper {
+};
+
+template <class K, class V, class H, class P, class A>
+struct TDumper<THashMultiMap<K, V, H, P, A>>: public TAssocDumper {
+};
+
+template <class T, class H, class P, class A>
+struct TDumper<THashSet<T, H, P, A>>: public TAssocDumper {
+};
+
+template <class T, class H, class P, class A>
+struct TDumper<THashMultiSet<T, H, P, A>>: public TAssocDumper {
+};
+
+//strings
+template <>
+struct TDumper<TString>: public TStrDumper {
+};
+
+template <>
+struct TDumper<const char*>: public TStrDumper {
+};
+
+template <>
+struct TDumper<TUtf16String>: public TStrDumper {
+};
+
+template <>
+struct TDumper<const wchar16*>: public TStrDumper {
+};
+
+template <class C, class T, class A>
+struct TDumper<std::basic_string<C, T, A>>: public TStrDumper {
+};
+
+template <class TChar>
+struct TDumper<TBasicStringBuf<TChar>>: public TStrDumper {
+};
diff --git a/library/cpp/dbg_output/engine.cpp b/library/cpp/dbg_output/engine.cpp
new file mode 100644
index 0000000000..dcb9f02522
--- /dev/null
+++ b/library/cpp/dbg_output/engine.cpp
@@ -0,0 +1,33 @@
+#include "engine.h"
+
+#include <util/string/cast.h>
+#include <util/string/escape.h>
+
+#if !defined(DBGDUMP_INLINE_IF_INCLUDED)
+#define DBGDUMP_INLINE_IF_INCLUDED
+#endif
+
+DBGDUMP_INLINE_IF_INCLUDED void TDumpBase::String(const TStringBuf& s) {
+ if (s) {
+ Raw(TString(s).Quote());
+ } else {
+ Raw("(empty)");
+ }
+}
+
+DBGDUMP_INLINE_IF_INCLUDED void TDumpBase::String(const TWtringBuf& s) {
+ Raw("w");
+ String(ToString(s));
+}
+
+DBGDUMP_INLINE_IF_INCLUDED void TDumpBase::Raw(const TStringBuf& s) {
+ Stream().Write(s.data(), s.size());
+}
+
+DBGDUMP_INLINE_IF_INCLUDED void TDumpBase::Char(char ch) {
+ Raw("'" + EscapeC(&ch, 1) + "'");
+}
+
+DBGDUMP_INLINE_IF_INCLUDED void TDumpBase::Char(wchar16 ch) {
+ Raw("w'" + ToString(EscapeC(&ch, 1)) + "'");
+}
diff --git a/library/cpp/dbg_output/engine.h b/library/cpp/dbg_output/engine.h
new file mode 100644
index 0000000000..f13c728c39
--- /dev/null
+++ b/library/cpp/dbg_output/engine.h
@@ -0,0 +1,180 @@
+#pragma once
+
+#include <util/stream/output.h>
+
+#include <utility>
+#include <util/generic/strbuf.h>
+
+template <class T>
+struct TDumper {
+ template <class S>
+ static inline void Dump(S& s, const T& t) {
+ s.Stream() << t;
+ }
+};
+
+namespace NDumpPrivate {
+ template <class T, class V>
+ inline void Dump(T& t, const V& v) {
+ ::TDumper<V>::Dump(t, v);
+ }
+
+ template <class T, class V>
+ inline T&& operator<<(T&& t, V&& v) {
+ Dump(t, v);
+
+ return std::forward<T>(t);
+ }
+
+ struct TADLBase {
+ };
+}
+
+struct TDumpBase: public ::NDumpPrivate::TADLBase {
+ inline TDumpBase(IOutputStream& out, bool indent) noexcept
+ : Out(&out)
+ , IndentLevel(0)
+ , Indent(indent)
+ {
+ }
+
+ inline IOutputStream& Stream() const noexcept {
+ return *Out;
+ }
+
+ void Char(char ch);
+ void Char(wchar16 ch);
+
+ void String(const TStringBuf& s);
+ void String(const TWtringBuf& s);
+
+ void Raw(const TStringBuf& s);
+
+ IOutputStream* Out;
+ size_t IndentLevel;
+ bool Indent;
+};
+
+struct TIndentScope {
+ inline TIndentScope(TDumpBase& d)
+ : D(&d)
+ {
+ ++(D->IndentLevel);
+ }
+
+ inline ~TIndentScope() {
+ --(D->IndentLevel);
+ }
+
+ TDumpBase* D;
+};
+
+template <class TChar>
+struct TRawLiteral {
+ const TBasicStringBuf<TChar> S;
+};
+
+template <class TChar>
+static inline TRawLiteral<TChar> DumpRaw(const TBasicStringBuf<TChar>& s) noexcept {
+ return {s};
+}
+
+template <class TChar>
+static inline TRawLiteral<TChar> DumpRaw(const TChar* s) noexcept {
+ return {s};
+}
+
+template <class C>
+struct TDumper<TRawLiteral<C>> {
+ template <class S>
+ static inline void Dump(S& s, const TRawLiteral<C>& v) {
+ s.Raw(v.S);
+ }
+};
+
+struct TIndentNewLine {
+};
+
+static inline TIndentNewLine IndentNewLine() noexcept {
+ return {};
+}
+
+template <>
+struct TDumper<TIndentNewLine> {
+ template <class S>
+ static inline void Dump(S& s, const TIndentNewLine&) {
+ if (s.Indent) {
+ s << DumpRaw("\n") << DumpRaw(TString(s.IndentLevel * 4, ' ').data());
+ }
+ }
+};
+
+template <class P>
+struct TDumper<const P*> {
+ template <class S>
+ static inline void Dump(S& s, const P* p) {
+ s.Pointer(p);
+ }
+};
+
+template <class P>
+struct TDumper<P*>: public TDumper<const P*> {
+};
+
+struct TCharDumper {
+ template <class S, class V>
+ static inline void Dump(S& s, const V& v) {
+ s.Char(v);
+ }
+};
+
+template <class S, class V>
+static inline void OutSequence(S& s, const V& v, const char* openTag, const char* closeTag) {
+ s.ColorScheme.Markup(s);
+ s << DumpRaw(openTag);
+
+ {
+ TIndentScope scope(s);
+ size_t cnt = 0;
+
+ for (const auto& x : v) {
+ if (cnt) {
+ s.ColorScheme.Markup(s);
+ s << DumpRaw(", ");
+ }
+
+ s << IndentNewLine();
+ s.ColorScheme.Literal(s);
+ s << x;
+ ++cnt;
+ }
+ }
+
+ s << IndentNewLine();
+ s.ColorScheme.Markup(s);
+ s << DumpRaw(closeTag);
+ s.ColorScheme.ResetType(s);
+}
+
+struct TAssocDumper {
+ template <class S, class V>
+ static inline void Dump(S& s, const V& v) {
+ ::OutSequence(s, v, "{", "}");
+ }
+};
+
+struct TSeqDumper {
+ template <class S, class V>
+ static inline void Dump(S& s, const V& v) {
+ ::OutSequence(s, v, "[", "]");
+ }
+};
+
+struct TStrDumper {
+ template <class S, class V>
+ static inline void Dump(S& s, const V& v) {
+ s.ColorScheme.String(s);
+ s.String(v);
+ s.ColorScheme.ResetType(s);
+ }
+};
diff --git a/library/cpp/dbg_output/ut/dbg_output_ut.cpp b/library/cpp/dbg_output/ut/dbg_output_ut.cpp
new file mode 100644
index 0000000000..7b285c84cb
--- /dev/null
+++ b/library/cpp/dbg_output/ut/dbg_output_ut.cpp
@@ -0,0 +1,106 @@
+#include <library/cpp/dbg_output/dump.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/str.h>
+#include <util/string/builder.h>
+#include <util/string/escape.h>
+#include <util/generic/map.h>
+
+namespace {
+ struct TX {
+ inline TX() {
+ N = this;
+ }
+
+ TX* N;
+ };
+}
+
+template <>
+struct TDumper<TX> {
+ template <class S>
+ static inline void Dump(S& s, const TX& x) {
+ s << DumpRaw("x") << x.N;
+ }
+};
+
+namespace TMyNS {
+ struct TMyStruct {
+ int A, B;
+ };
+}
+DEFINE_DUMPER(TMyNS::TMyStruct, A, B)
+
+Y_UNIT_TEST_SUITE(TContainerPrintersTest) {
+ Y_UNIT_TEST(TestVectorInt) {
+ TStringStream out;
+ out << DbgDump(TVector<int>({1, 2, 3, 4, 5}));
+ UNIT_ASSERT_STRINGS_EQUAL(out.Str(), "[1, 2, 3, 4, 5]");
+ }
+
+ Y_UNIT_TEST(TestMapCharToCharArray) {
+ TStringStream out;
+
+ TMap<char, const char*> m;
+
+ m['a'] = "SMALL LETTER A";
+ m['b'] = nullptr;
+
+ out << DbgDump(m);
+
+ UNIT_ASSERT_STRINGS_EQUAL(out.Str(), "{'a' -> \"SMALL LETTER A\", 'b' -> (empty)}");
+ }
+
+ Y_UNIT_TEST(TestVectorOfVectors) {
+ TStringStream out;
+ TVector<TVector<wchar16>> vec(2);
+ vec[0].push_back(0);
+ vec[1] = {wchar16('a')};
+ out << DbgDump(vec);
+ UNIT_ASSERT_STRINGS_EQUAL(out.Str(), "[[w'\\0'], [w'a']]");
+ }
+
+ Y_UNIT_TEST(TestInfinite) {
+ UNIT_ASSERT(!!(TStringBuilder() << DbgDumpDeep(TX())));
+ }
+
+ Y_UNIT_TEST(TestLabeledDump) {
+ TStringStream out;
+ int a = 1, b = 2;
+ out << LabeledDump(a, b, 1 + 2);
+ UNIT_ASSERT_STRINGS_EQUAL(out.Str(), "{\"a\": 1, \"b\": 2, \"1 + 2\": 3}");
+ }
+
+ Y_UNIT_TEST(TestStructDumper) {
+ TStringStream out;
+ out << DbgDump(TMyNS::TMyStruct{3, 4});
+ UNIT_ASSERT_STRINGS_EQUAL(out.Str(), "{\"A\": 3, \"B\": 4}");
+ }
+
+ Y_UNIT_TEST(TestColors) {
+ using TComplex = TMap<TString, TMap<int, char>>;
+ TComplex test;
+ test["a"][1] = '7';
+ test["b"][2] = '6';
+ TStringStream out;
+ out << DbgDump<TComplex, NDbgDump::NColorScheme::TEyebleed</* Enforce = */ true>>(test);
+ UNIT_ASSERT_STRINGS_EQUAL(
+ EscapeC(out.Str()),
+ "\\x1B[1;32m{\\x1B[1;31m\\x1B[42m\\x1B[1;31m\\x1B[1;33m\\\"a\\\"\\x1B[22;39m\\x1B[22;39m"
+ "\\x1B[49m\\x1B[1;32m -> \\x1B[44m\\x1B[1;31m\\x1B[1;32m{\\x1B[1;31m\\x1B[1;31m1"
+ "\\x1B[22;39m\\x1B[1;32m -> \\x1B[1;31m'7'\\x1B[22;39m\\x1B[1;32m}"
+ "\\x1B[22;39m\\x1B[22;39m\\x1B[49m\\x1B[1;32m, \\x1B[1;31m\\x1B[42m\\x1B[1;31m\\x1B[1;33m"
+ "\\\"b\\\"\\x1B[22;39m\\x1B[22;39m\\x1B[49m\\x1B[1;32m -> "
+ "\\x1B[44m\\x1B[1;31m\\x1B[1;32m{\\x1B[1;31m\\x1B[1;31m2\\x1B[22;39m\\x1B[1;32m -> "
+ "\\x1B[1;31m'6'\\x1B[22;39m\\x1B[1;32m}\\x1B[22;39m\\x1B[22;39m\\x1B[49m\\x1B[1;32m}\\x1B[22;39m");
+ }
+
+ Y_UNIT_TEST(SmallIntOrChar) {
+ char c = 'e';
+ i8 i = -100;
+ ui8 u = 10;
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuilder() << DbgDump(c), "'e'");
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuilder() << DbgDump(i), "-100");
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuilder() << DbgDump(u), "10");
+ }
+}
diff --git a/library/cpp/dbg_output/ut/ya.make b/library/cpp/dbg_output/ut/ya.make
new file mode 100644
index 0000000000..201601295d
--- /dev/null
+++ b/library/cpp/dbg_output/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/dbg_output)
+
+OWNER(pg)
+
+SRCS(
+ dbg_output_ut.cpp
+)
+
+END()
diff --git a/library/cpp/dbg_output/ya.make b/library/cpp/dbg_output/ya.make
new file mode 100644
index 0000000000..7d54108f93
--- /dev/null
+++ b/library/cpp/dbg_output/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ library/cpp/colorizer
+)
+
+SRCS(
+ dump.cpp
+ dumpers.cpp
+ engine.cpp
+)
+
+END()
diff --git a/library/cpp/deprecated/accessors/README.md b/library/cpp/deprecated/accessors/README.md
new file mode 100644
index 0000000000..498f1203e0
--- /dev/null
+++ b/library/cpp/deprecated/accessors/README.md
@@ -0,0 +1,5 @@
+Unified accessors for Arcadia containers and user types.
+
+Accessors implemented here mix different kinds of access at the wrong abstraction level, so they shouldn't be used.
+
+If you want begin/end/size for your containers, use std::begin, std::end, std::size. If you need generic reserve / resize / clear / insert, just use appropriate container methods or do your own overloads in place.
diff --git a/library/cpp/deprecated/accessors/accessors.cpp b/library/cpp/deprecated/accessors/accessors.cpp
new file mode 100644
index 0000000000..7d37e586fa
--- /dev/null
+++ b/library/cpp/deprecated/accessors/accessors.cpp
@@ -0,0 +1 @@
+#include "accessors.h"
diff --git a/library/cpp/deprecated/accessors/accessors.h b/library/cpp/deprecated/accessors/accessors.h
new file mode 100644
index 0000000000..6d4b1da3ad
--- /dev/null
+++ b/library/cpp/deprecated/accessors/accessors.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#include "accessors_impl.h"
+
+namespace NAccessors {
+ /*
+ * Adds API compatibility between different types representing memory regions.
+ *
+ * i.e. this will work:
+ *
+ * TString t;
+ * const char* beg = NAccessors::Begin(t); // t.begin()
+ * const char* end = NAccessors::End(t); // t.end()
+ * size_t sz = NAccessors::Size(t); // t.size()
+ *
+ * as well as this:
+ *
+ * ui64 t;
+ * const ui64* beg = NAccessors::Begin(t); // &t
+ * const ui64* end = NAccessors::End(t); // &t + 1
+ * size_t sz = NAccessors::Size(t); // 1
+ *
+ * Both will give you begin, end and size of the underlying memory region.
+ */
+
+ template <typename T>
+ inline const typename TMemoryTraits<T>::TElementType* Begin(const T& t) {
+ return NPrivate::TBegin<T>::Get(t);
+ }
+
+ template <typename T>
+ inline const typename TMemoryTraits<T>::TElementType* End(const T& t) {
+ return NPrivate::TEnd<T>::Get(t);
+ }
+
+ template <typename T>
+ inline size_t Size(const T& t) {
+ return End(t) - Begin(t);
+ }
+
+ /**
+ * This gives some unification in terms of memory manipulation.
+ */
+
+ template <typename T>
+ inline void Reserve(T& t, size_t sz) {
+ NPrivate::TReserve<T>::Do(t, sz);
+ }
+
+ template <typename T>
+ inline void Resize(T& t, size_t sz) {
+ NPrivate::TResize<T>::Do(t, sz);
+ }
+
+ template <typename T>
+ inline void Clear(T& t) {
+ NPrivate::TClear<T, false>::Do(t);
+ }
+
+ template <typename T>
+ inline void Init(T& t) {
+ NPrivate::TClear<T, true>::Do(t);
+ }
+
+ template <typename T>
+ inline void Append(T& t, const typename TMemoryTraits<T>::TElementType& v) {
+ NPrivate::TAppend<T>::Do(t, v);
+ }
+
+ template <typename T>
+ inline void Append(T& t,
+ const typename TMemoryTraits<T>::TElementType* beg,
+ const typename TMemoryTraits<T>::TElementType* end) {
+ NPrivate::TAppendRegion<T>::Do(t, beg, end);
+ }
+
+ template <typename T>
+ inline void Assign(T& t,
+ const typename TMemoryTraits<T>::TElementType* beg,
+ const typename TMemoryTraits<T>::TElementType* end) {
+ NPrivate::TAssign<T>::Do(t, beg, end);
+ }
+}
diff --git a/library/cpp/deprecated/accessors/accessors_impl.cpp b/library/cpp/deprecated/accessors/accessors_impl.cpp
new file mode 100644
index 0000000000..0bf74cab7b
--- /dev/null
+++ b/library/cpp/deprecated/accessors/accessors_impl.cpp
@@ -0,0 +1 @@
+#include "accessors_impl.h"
diff --git a/library/cpp/deprecated/accessors/accessors_impl.h b/library/cpp/deprecated/accessors/accessors_impl.h
new file mode 100644
index 0000000000..6b2b987351
--- /dev/null
+++ b/library/cpp/deprecated/accessors/accessors_impl.h
@@ -0,0 +1,420 @@
+#pragma once
+
+#include "memory_traits.h"
+
+namespace NAccessors {
+ namespace NPrivate {
+ template <typename Ta>
+ struct TMemoryAccessorBase {
+ enum {
+ SimpleMemory = TMemoryTraits<Ta>::SimpleMemory,
+ ContinuousMemory = TMemoryTraits<Ta>::ContinuousMemory,
+ };
+
+ struct TBadAccessor;
+ };
+
+ template <typename Ta>
+ struct TBegin: public TMemoryAccessorBase<Ta> {
+ using TElementType = typename TMemoryTraits<Ta>::TElementType;
+
+ template <typename Tb>
+ struct TNoMemoryIndirectionBegin {
+ static const TElementType* Get(const Tb& b) {
+ return (const TElementType*)&b;
+ }
+ };
+
+ template <typename Tb>
+ struct TIndirectMemoryRegionBegin {
+ Y_HAS_MEMBER(Begin);
+ Y_HAS_MEMBER(begin);
+
+ template <typename Tc>
+ struct TByBegin {
+ static const TElementType* Get(const Tc& b) {
+ return (const TElementType*)b.Begin();
+ }
+ };
+
+ template <typename Tc>
+ struct TBybegin {
+ static const TElementType* Get(const Tc& b) {
+ return (const TElementType*)b.begin();
+ }
+ };
+
+ using TGet = std::conditional_t<THasBegin<Tb>::value, TByBegin<Tb>, TBybegin<Tb>>;
+
+ static const TElementType* Get(const Tb& b) {
+ return TGet::Get(b);
+ }
+ };
+
+ using TGet = std::conditional_t<
+ TMemoryAccessorBase<Ta>::SimpleMemory,
+ TNoMemoryIndirectionBegin<Ta>,
+ std::conditional_t<
+ TMemoryAccessorBase<Ta>::ContinuousMemory,
+ TIndirectMemoryRegionBegin<Ta>,
+ typename TMemoryAccessorBase<Ta>::TBadAccessor>>;
+
+ static const TElementType* Get(const Ta& b) {
+ return TGet::Get(b);
+ }
+ };
+
+ template <typename Ta>
+ struct TEnd: public TMemoryAccessorBase<Ta> {
+ using TElementType = typename TMemoryTraits<Ta>::TElementType;
+
+ template <typename Tb>
+ struct TNoMemoryIndirectionEnd {
+ static const TElementType* Get(const Tb& b) {
+ return (const TElementType*)(&b + 1);
+ }
+ };
+
+ template <typename Tb>
+ struct TIndirectMemoryRegionEnd {
+ Y_HAS_MEMBER(End);
+ Y_HAS_MEMBER(end);
+
+ template <typename Tc>
+ struct TByEnd {
+ static const TElementType* Get(const Tc& b) {
+ return (const TElementType*)b.End();
+ }
+ };
+
+ template <typename Tc>
+ struct TByend {
+ static const TElementType* Get(const Tc& b) {
+ return (const TElementType*)b.end();
+ }
+ };
+
+ using TGet = std::conditional_t<THasEnd<Tb>::value, TByEnd<Tb>, TByend<Tb>>;
+
+ static const TElementType* Get(const Tb& b) {
+ return TGet::Get(b);
+ }
+ };
+
+ using TGet = std::conditional_t<
+ TMemoryAccessorBase<Ta>::SimpleMemory,
+ TNoMemoryIndirectionEnd<Ta>,
+ std::conditional_t<
+ TMemoryAccessorBase<Ta>::ContinuousMemory,
+ TIndirectMemoryRegionEnd<Ta>,
+ typename TMemoryAccessorBase<Ta>::TBadAccessor>>;
+
+ static const TElementType* Get(const Ta& b) {
+ return TGet::Get(b);
+ }
+ };
+
+ template <typename Ta, bool Init>
+ struct TClear: public TMemoryAccessorBase<Ta> {
+ template <typename Tb>
+ struct TNoMemoryIndirectionClear {
+ static void Do(Tb& b) {
+ Zero(b);
+ }
+ };
+
+ template <typename Tb>
+ struct TIndirectMemoryRegionClear {
+ Y_HAS_MEMBER(Clear);
+ Y_HAS_MEMBER(clear);
+
+ template <typename Tc>
+ struct TByClear {
+ static void Do(Tc& b) {
+ b.Clear();
+ }
+ };
+
+ template <typename Tc>
+ struct TByclear {
+ static void Do(Tc& b) {
+ b.clear();
+ }
+ };
+
+ template <typename Tc>
+ struct TByNone {
+ static void Do(Tc& b) {
+ if (!Init)
+ b = Tc();
+ }
+ };
+
+ using TDo = std::conditional_t<
+ THasClear<Tb>::value,
+ TByClear<Tb>,
+ std::conditional_t<
+ THasclear<Tb>::value,
+ TByclear<Tb>,
+ TByNone<Tb>>>;
+
+ static void Do(Tb& b) {
+ TDo::Do(b);
+ }
+ };
+
+ using TDo = std::conditional_t<TMemoryAccessorBase<Ta>::SimpleMemory, TNoMemoryIndirectionClear<Ta>, TIndirectMemoryRegionClear<Ta>>;
+
+ static void Do(Ta& b) {
+ TDo::Do(b);
+ }
+ };
+
+ template <typename Tb>
+ struct TReserve {
+ Y_HAS_MEMBER(Reserve);
+ Y_HAS_MEMBER(reserve);
+
+ template <typename Tc>
+ struct TByReserve {
+ static void Do(Tc& b, size_t sz) {
+ b.Reserve(sz);
+ }
+ };
+
+ template <typename Tc>
+ struct TByreserve {
+ static void Do(Tc& b, size_t sz) {
+ b.reserve(sz);
+ }
+ };
+
+ template <typename Tc>
+ struct TByNone {
+ static void Do(Tc&, size_t) {
+ }
+ };
+
+ using TDo = std::conditional_t<
+ THasReserve<Tb>::value,
+ TByReserve<Tb>,
+ std::conditional_t<
+ THasreserve<Tb>::value,
+ TByreserve<Tb>,
+ TByNone<Tb>>>;
+
+ static void Do(Tb& b, size_t sz) {
+ TDo::Do(b, sz);
+ }
+ };
+
+ template <typename Tb>
+ struct TResize {
+ Y_HAS_MEMBER(Resize);
+ Y_HAS_MEMBER(resize);
+
+ template <typename Tc>
+ struct TByResize {
+ static void Do(Tc& b, size_t sz) {
+ b.Resize(sz);
+ }
+ };
+
+ template <typename Tc>
+ struct TByresize {
+ static void Do(Tc& b, size_t sz) {
+ b.resize(sz);
+ }
+ };
+
+ using TDo = std::conditional_t<THasResize<Tb>::value, TByResize<Tb>, TByresize<Tb>>;
+
+ static void Do(Tb& b, size_t sz) {
+ TDo::Do(b, sz);
+ }
+ };
+
+ template <typename Tb>
+ struct TAppend {
+ Y_HAS_MEMBER(Append);
+ Y_HAS_MEMBER(append);
+ Y_HAS_MEMBER(push_back);
+
+ template <typename Tc>
+ struct TByAppend {
+ using TElementType = typename TMemoryTraits<Tc>::TElementType;
+
+ static void Do(Tc& b, const TElementType& val) {
+ b.Append(val);
+ }
+ };
+
+ template <typename Tc>
+ struct TByappend {
+ using TElementType = typename TMemoryTraits<Tc>::TElementType;
+
+ static void Do(Tc& b, const TElementType& val) {
+ b.append(val);
+ }
+ };
+
+ template <typename Tc>
+ struct TBypush_back {
+ using TElementType = typename TMemoryTraits<Tc>::TElementType;
+
+ static void Do(Tc& b, const TElementType& val) {
+ b.push_back(val);
+ }
+ };
+
+ using TDo = std::conditional_t<
+ THasAppend<Tb>::value,
+ TByAppend<Tb>,
+ std::conditional_t<
+ THasappend<Tb>::value,
+ TByappend<Tb>,
+ TBypush_back<Tb>>>;
+
+ using TElementType = typename TMemoryTraits<Tb>::TElementType;
+
+ static void Do(Tb& b, const TElementType& val) {
+ TDo::Do(b, val);
+ }
+ };
+
+ template <typename Tb>
+ struct TAppendRegion {
+ Y_HAS_MEMBER(Append);
+ Y_HAS_MEMBER(append);
+ Y_HAS_MEMBER(insert);
+
+ template <typename Tc>
+ struct TByAppend {
+ using TElementType = typename TMemoryTraits<Tc>::TElementType;
+
+ static void Do(Tc& b, const TElementType* beg, const TElementType* end) {
+ b.Append(beg, end);
+ }
+ };
+
+ template <typename Tc>
+ struct TByappend {
+ using TElementType = typename TMemoryTraits<Tc>::TElementType;
+
+ static void Do(Tc& b, const TElementType* beg, const TElementType* end) {
+ b.append(beg, end);
+ }
+ };
+
+ template <typename Tc>
+ struct TByinsert {
+ using TElementType = typename TMemoryTraits<Tc>::TElementType;
+
+ static void Do(Tc& b, const TElementType* beg, const TElementType* end) {
+ b.insert(b.end(), beg, end);
+ }
+ };
+
+ template <typename Tc>
+ struct TByNone {
+ using TElementType = typename TMemoryTraits<Tc>::TElementType;
+
+ static void Do(Tc& b, const TElementType* beg, const TElementType* end) {
+ for (const TElementType* it = beg; it != end; ++it)
+ TAppend<Tc>::Do(b, *it);
+ }
+ };
+
+ using TDo = std::conditional_t<
+ THasAppend<Tb>::value,
+ TByAppend<Tb>,
+ std::conditional_t<
+ THasappend<Tb>::value,
+ TByappend<Tb>,
+ std::conditional_t<
+ THasinsert<Tb>::value,
+ TByinsert<Tb>,
+ TByNone<Tb>>>>;
+
+ using TElementType = typename TMemoryTraits<Tb>::TElementType;
+
+ static void Do(Tb& b, const TElementType* beg, const TElementType* end) {
+ TDo::Do(b, beg, end);
+ }
+ };
+
+ template <typename Ta>
+ struct TAssign: public TMemoryAccessorBase<Ta> {
+ using TElementType = typename TMemoryTraits<Ta>::TElementType;
+
+ template <typename Tb>
+ struct TNoMemoryIndirectionAssign {
+ static void Do(Tb& b, const TElementType* beg, const TElementType* end) {
+ if (sizeof(Tb) == sizeof(TElementType) && end - beg > 0) {
+ memcpy(&b, beg, sizeof(Tb));
+ } else if (end - beg > 0) {
+ memcpy(&b, beg, Min<size_t>((end - beg) * sizeof(TElementType), sizeof(Tb)));
+ } else {
+ Zero(b);
+ }
+ }
+ };
+
+ template <typename Tb>
+ struct TIndirectMemoryRegionAssign {
+ Y_HAS_MEMBER(Assign);
+ Y_HAS_MEMBER(assign);
+
+ template <typename Tc>
+ struct TByAssign {
+ static void Do(Tc& b, const TElementType* beg, const TElementType* end) {
+ b.Assign(beg, end);
+ }
+ };
+
+ template <typename Tc>
+ struct TByassign {
+ static void Do(Tc& b, const TElementType* beg, const TElementType* end) {
+ b.assign(beg, end);
+ }
+ };
+
+ template <typename Tc>
+ struct TByClearAppend {
+ static void Do(Tc& b, const TElementType* beg, const TElementType* end) {
+ TClear<Tc, false>::Do(b);
+ TAppendRegion<Tc>::Do(b, beg, end);
+ }
+ };
+
+ template <typename Tc>
+ struct TByConstruction {
+ static void Do(Tc& b, const TElementType* beg, const TElementType* end) {
+ b = Tc(beg, end);
+ }
+ };
+
+ using TDo = std::conditional_t<
+ THasAssign<Tb>::value,
+ TByAssign<Tb>,
+ std::conditional_t<
+ THasassign<Tb>::value,
+ TByassign<Tb>,
+ std::conditional_t<
+ TMemoryTraits<Tb>::OwnsMemory,
+ TByClearAppend<Tb>,
+ TByConstruction<Tb>>>>;
+
+ static void Do(Tb& b, const TElementType* beg, const TElementType* end) {
+ TDo::Do(b, beg, end);
+ }
+ };
+
+ using TDo = std::conditional_t<TMemoryAccessorBase<Ta>::SimpleMemory, TNoMemoryIndirectionAssign<Ta>, TIndirectMemoryRegionAssign<Ta>>;
+
+ static void Do(Ta& b, const TElementType* beg, const TElementType* end) {
+ TDo::Do(b, beg, end);
+ }
+ };
+ }
+}
diff --git a/library/cpp/deprecated/accessors/accessors_ut.cpp b/library/cpp/deprecated/accessors/accessors_ut.cpp
new file mode 100644
index 0000000000..a9bdc9fcc4
--- /dev/null
+++ b/library/cpp/deprecated/accessors/accessors_ut.cpp
@@ -0,0 +1,92 @@
+#include "accessors.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/buffer.h>
+#include <util/generic/vector.h>
+
+#include <array>
+
+class TAccessorsTest: public TTestBase {
+ UNIT_TEST_SUITE(TAccessorsTest);
+ UNIT_TEST(TestAccessors);
+ UNIT_TEST_SUITE_END();
+
+private:
+ template <typename T>
+ void TestRead(const T& t, const char* comm) {
+ const char* beg = (const char*)NAccessors::Begin(t);
+ const char* end = (const char*)NAccessors::End(t);
+ long sz = NAccessors::Size(t) * sizeof(typename TMemoryTraits<T>::TElementType);
+
+ UNIT_ASSERT_VALUES_EQUAL_C(end - beg, sz, comm);
+ }
+
+ template <typename T>
+ void TestWrite(const char* comm) {
+ typename TMemoryTraits<T>::TElementType val[4] = {'t', 'e', 's', 't'};
+ T t;
+ NAccessors::Init(t);
+ NAccessors::Reserve(t, 6);
+
+ size_t sz = NAccessors::Size(t);
+ UNIT_ASSERT_VALUES_EQUAL_C(0u, sz, comm);
+
+ NAccessors::Append(t, 'a');
+ sz = NAccessors::Size(t);
+ UNIT_ASSERT_VALUES_EQUAL_C(1u, sz, comm);
+
+ NAccessors::Append(t, val, val + 4);
+ sz = NAccessors::Size(t);
+ UNIT_ASSERT_VALUES_EQUAL_C(5u, sz, comm);
+
+ NAccessors::Clear(t);
+
+ sz = NAccessors::Size(t);
+ UNIT_ASSERT_VALUES_EQUAL_C(0u, sz, comm);
+ }
+
+ void TestAccessors() {
+ TestRead('a', "char");
+ TestRead(1, "int");
+
+ int t[4] = {0, 1, 2, 3};
+
+ TestRead(t, "int[4]");
+
+ TStringBuf sbuf = "test";
+
+ TestRead(sbuf, "TStringBuf");
+
+ TUtf16String wtr;
+ wtr.resize(10, 1024);
+
+ TestRead(wtr, "TUtf16String");
+
+ TBuffer buf;
+ buf.Resize(30);
+
+ TestRead(buf, "TBuffer");
+
+ TVector<ui64> vec(10, 100);
+
+ TestRead(vec, "TVector<ui64>");
+
+ TestWrite<TString>("TString");
+ TestWrite<TVector<char>>("TVector<char>");
+ TestWrite<TBuffer>("TBuffer");
+ TestWrite<TVector<ui64>>("TVector<ui64>");
+ TestWrite<TUtf16String>("TUtf16String");
+
+ std::array<TString, 10> sarr;
+ NAccessors::Init(sarr);
+ NAccessors::Clear(sarr);
+
+ std::array<char, 10> carr;
+ NAccessors::Init(carr);
+ NAccessors::Clear(carr);
+ TestRead(carr, "std::array<char, 10>");
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TAccessorsTest)
diff --git a/library/cpp/deprecated/accessors/memory_traits.cpp b/library/cpp/deprecated/accessors/memory_traits.cpp
new file mode 100644
index 0000000000..df53026cf4
--- /dev/null
+++ b/library/cpp/deprecated/accessors/memory_traits.cpp
@@ -0,0 +1 @@
+#include "memory_traits.h"
diff --git a/library/cpp/deprecated/accessors/memory_traits.h b/library/cpp/deprecated/accessors/memory_traits.h
new file mode 100644
index 0000000000..aa837705d3
--- /dev/null
+++ b/library/cpp/deprecated/accessors/memory_traits.h
@@ -0,0 +1,168 @@
+#pragma once
+
+#include <util/generic/array_ref.h>
+#include <util/memory/blob.h>
+#include <util/memory/tempbuf.h>
+#include <util/generic/buffer.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/generic/typetraits.h>
+
+#include <array>
+#include <string>
+#include <utility>
+
+template <typename T>
+struct TMemoryTraits {
+ enum {
+ SimpleMemory = std::is_arithmetic<T>::value,
+ ContinuousMemory = SimpleMemory,
+ OwnsMemory = SimpleMemory,
+ };
+
+ using TElementType = T;
+};
+
+template <typename T, size_t n>
+struct TMemoryTraits<T[n]> {
+ enum {
+ SimpleMemory = TMemoryTraits<T>::SimpleMemory,
+ ContinuousMemory = SimpleMemory,
+ OwnsMemory = SimpleMemory,
+ };
+
+ using TElementType = T;
+};
+
+template <typename T, size_t n>
+struct TMemoryTraits<std::array<T, n>> {
+ enum {
+ SimpleMemory = TMemoryTraits<T>::SimpleMemory,
+ ContinuousMemory = SimpleMemory,
+ OwnsMemory = SimpleMemory,
+ };
+
+ using TElementType = T;
+};
+
+template <typename A, typename B>
+struct TMemoryTraits<std::pair<A, B>> {
+ enum {
+ SimpleMemory = TMemoryTraits<A>::SimpleMemory && TMemoryTraits<B>::SimpleMemory,
+ ContinuousMemory = SimpleMemory,
+ OwnsMemory = SimpleMemory,
+ };
+
+ using TElementType = std::pair<A, B>;
+};
+
+template <>
+struct TMemoryTraits<TBuffer> {
+ enum {
+ SimpleMemory = false,
+ ContinuousMemory = true,
+ OwnsMemory = true,
+ };
+
+ using TElementType = char;
+};
+
+template <>
+struct TMemoryTraits<TTempBuf> {
+ enum {
+ SimpleMemory = false,
+ ContinuousMemory = true,
+ OwnsMemory = true,
+ };
+
+ using TElementType = char;
+};
+
+template <>
+struct TMemoryTraits< ::TBlob> {
+ enum {
+ SimpleMemory = false,
+ ContinuousMemory = true,
+ OwnsMemory = true,
+ };
+
+ using TElementType = char;
+};
+
+template <typename T>
+struct TElementDependentMemoryTraits {
+ enum {
+ SimpleMemory = false,
+ ContinuousMemory = TMemoryTraits<T>::SimpleMemory,
+ };
+
+ using TElementType = T;
+};
+
+template <typename T, typename TAlloc>
+struct TMemoryTraits<std::vector<T, TAlloc>>: public TElementDependentMemoryTraits<T> {
+ enum {
+ OwnsMemory = TMemoryTraits<T>::OwnsMemory
+ };
+};
+
+template <typename T, typename TAlloc>
+struct TMemoryTraits<TVector<T, TAlloc>>: public TMemoryTraits<std::vector<T, TAlloc>> {
+};
+
+template <typename T>
+struct TMemoryTraits<TTempArray<T>>: public TElementDependentMemoryTraits<T> {
+ enum {
+ OwnsMemory = TMemoryTraits<T>::OwnsMemory
+ };
+};
+
+template <typename T, typename TCharTraits, typename TAlloc>
+struct TMemoryTraits<std::basic_string<T, TCharTraits, TAlloc>>: public TElementDependentMemoryTraits<T> {
+ enum {
+ OwnsMemory = TMemoryTraits<T>::OwnsMemory
+ };
+};
+
+template <>
+struct TMemoryTraits<TString>: public TElementDependentMemoryTraits<char> {
+ enum {
+ OwnsMemory = true
+ };
+};
+
+template <>
+struct TMemoryTraits<TUtf16String>: public TElementDependentMemoryTraits<wchar16> {
+ enum {
+ OwnsMemory = true
+ };
+};
+
+template <typename T>
+struct TMemoryTraits<TArrayRef<T>>: public TElementDependentMemoryTraits<T> {
+ enum {
+ OwnsMemory = false
+ };
+};
+
+template <typename TCharType, typename TCharTraits>
+struct TMemoryTraits<TBasicStringBuf<TCharType, TCharTraits>>: public TElementDependentMemoryTraits<TCharType> {
+ enum {
+ OwnsMemory = false
+ };
+};
+
+template <>
+struct TMemoryTraits<TStringBuf>: public TElementDependentMemoryTraits<char> {
+ enum {
+ OwnsMemory = false
+ };
+};
+
+template <>
+struct TMemoryTraits<TWtringBuf>: public TElementDependentMemoryTraits<wchar16> {
+ enum {
+ OwnsMemory = false
+ };
+};
diff --git a/library/cpp/deprecated/accessors/ut/ya.make b/library/cpp/deprecated/accessors/ut/ya.make
new file mode 100644
index 0000000000..5ea976566f
--- /dev/null
+++ b/library/cpp/deprecated/accessors/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/deprecated/accessors)
+
+OWNER(velavokr)
+
+SRCS(
+ accessors_ut.cpp
+)
+
+END()
diff --git a/library/cpp/deprecated/accessors/ya.make b/library/cpp/deprecated/accessors/ya.make
new file mode 100644
index 0000000000..e322026a1c
--- /dev/null
+++ b/library/cpp/deprecated/accessors/ya.make
@@ -0,0 +1,11 @@
+LIBRARY()
+
+OWNER(elric)
+
+SRCS(
+ accessors.cpp
+ accessors_impl.cpp
+ memory_traits.cpp
+)
+
+END()
diff --git a/library/cpp/deprecated/enum_codegen/README.md b/library/cpp/deprecated/enum_codegen/README.md
new file mode 100644
index 0000000000..3bdac29af1
--- /dev/null
+++ b/library/cpp/deprecated/enum_codegen/README.md
@@ -0,0 +1,3 @@
+Some macros for generating enum <-> string conversions.
+
+Just use GENERATE_ENUM_SERIALIZATION. See https://wiki.yandex-team.ru/yatool/HowToWriteYaMakeFiles/#generate-enum
diff --git a/library/cpp/deprecated/enum_codegen/enum_codegen.cpp b/library/cpp/deprecated/enum_codegen/enum_codegen.cpp
new file mode 100644
index 0000000000..3931b05924
--- /dev/null
+++ b/library/cpp/deprecated/enum_codegen/enum_codegen.cpp
@@ -0,0 +1 @@
+#include "enum_codegen.h"
diff --git a/library/cpp/deprecated/enum_codegen/enum_codegen.h b/library/cpp/deprecated/enum_codegen/enum_codegen.h
new file mode 100644
index 0000000000..dfb04ecac2
--- /dev/null
+++ b/library/cpp/deprecated/enum_codegen/enum_codegen.h
@@ -0,0 +1,33 @@
+#pragma once
+
+/// see enum_codegen_ut.cpp for examples
+
+#define ENUM_VALUE_GEN(name, value, ...) name = value,
+#define ENUM_VALUE_GEN_NO_VALUE(name, ...) name,
+
+#define ENUM_TO_STRING_IMPL_ITEM(name, ...) \
+ case name: \
+ return #name;
+#define ENUM_LTLT_IMPL_ITEM(name, ...) \
+ case name: \
+ os << #name; \
+ break;
+
+#define ENUM_TO_STRING(type, MAP) \
+ static inline const char* ToCString(type value) { \
+ switch (value) { \
+ MAP(ENUM_TO_STRING_IMPL_ITEM) \
+ default: \
+ return "UNKNOWN"; \
+ } \
+ } \
+ \
+ static inline IOutputStream& operator<<(IOutputStream& os, type value) { \
+ switch (value) { \
+ MAP(ENUM_LTLT_IMPL_ITEM) \
+ default: \
+ os << int(value); \
+ break; \
+ } \
+ return os; \
+ }
diff --git a/library/cpp/deprecated/enum_codegen/enum_codegen_ut.cpp b/library/cpp/deprecated/enum_codegen/enum_codegen_ut.cpp
new file mode 100644
index 0000000000..f8f1c9b6df
--- /dev/null
+++ b/library/cpp/deprecated/enum_codegen/enum_codegen_ut.cpp
@@ -0,0 +1,40 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "enum_codegen.h"
+
+#include <util/string/builder.h>
+
+#define COLOR_MAP(XX) \
+ XX(RED) \
+ XX(GREEN) \
+ XX(BLUE)
+
+enum EColor {
+ COLOR_MAP(ENUM_VALUE_GEN_NO_VALUE)
+};
+
+ENUM_TO_STRING(EColor, COLOR_MAP)
+
+#define MULTIPLIER_MAP(XX) \
+ XX(GB, 9) \
+ XX(MB, 6) \
+ XX(KB, 3)
+
+enum EMultiplier {
+ MULTIPLIER_MAP(ENUM_VALUE_GEN)
+};
+
+ENUM_TO_STRING(EMultiplier, MULTIPLIER_MAP)
+
+Y_UNIT_TEST_SUITE(EnumCodegen) {
+ Y_UNIT_TEST(GenWithValue) {
+ UNIT_ASSERT_VALUES_EQUAL(6, MB);
+ }
+
+ Y_UNIT_TEST(ToCString) {
+ UNIT_ASSERT_VALUES_EQUAL("RED", ToCString(RED));
+ UNIT_ASSERT_VALUES_EQUAL("BLUE", ToCString(BLUE));
+ UNIT_ASSERT_VALUES_EQUAL("GREEN", (TStringBuilder() << GREEN));
+ UNIT_ASSERT_VALUES_EQUAL("GB", ToCString(GB));
+ }
+}
diff --git a/library/cpp/deprecated/enum_codegen/ut/ya.make b/library/cpp/deprecated/enum_codegen/ut/ya.make
new file mode 100644
index 0000000000..32e7ad77a2
--- /dev/null
+++ b/library/cpp/deprecated/enum_codegen/ut/ya.make
@@ -0,0 +1,15 @@
+UNITTEST()
+
+OWNER(g:util)
+
+SRCDIR(library/cpp/deprecated/enum_codegen)
+
+PEERDIR(
+ library/cpp/deprecated/enum_codegen
+)
+
+SRCS(
+ enum_codegen_ut.cpp
+)
+
+END()
diff --git a/library/cpp/deprecated/enum_codegen/ya.make b/library/cpp/deprecated/enum_codegen/ya.make
new file mode 100644
index 0000000000..1df07d2192
--- /dev/null
+++ b/library/cpp/deprecated/enum_codegen/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(elric)
+
+SRCS(
+ enum_codegen.cpp
+)
+
+END()
diff --git a/library/cpp/deprecated/kmp/kmp.cpp b/library/cpp/deprecated/kmp/kmp.cpp
new file mode 100644
index 0000000000..d02074c94a
--- /dev/null
+++ b/library/cpp/deprecated/kmp/kmp.cpp
@@ -0,0 +1,21 @@
+#include "kmp.h"
+
+#include <util/generic/yexception.h>
+
+TKMPMatcher::TKMPMatcher(const char* patternBegin, const char* patternEnd)
+ : Pattern(patternBegin, patternEnd)
+{
+ ComputePrefixFunction();
+}
+
+TKMPMatcher::TKMPMatcher(const TString& pattern)
+ : Pattern(pattern)
+{
+ ComputePrefixFunction();
+}
+
+void TKMPMatcher::ComputePrefixFunction() {
+ ssize_t* pf;
+ ::ComputePrefixFunction(Pattern.data(), Pattern.data() + Pattern.size(), &pf);
+ PrefixFunction.Reset(pf);
+}
diff --git a/library/cpp/deprecated/kmp/kmp.h b/library/cpp/deprecated/kmp/kmp.h
new file mode 100644
index 0000000000..a7f72eece6
--- /dev/null
+++ b/library/cpp/deprecated/kmp/kmp.h
@@ -0,0 +1,108 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+template <typename T>
+void ComputePrefixFunction(const T* begin, const T* end, ssize_t** result) {
+ Y_ENSURE(begin != end, TStringBuf("empty pattern"));
+ ssize_t len = end - begin;
+ TArrayHolder<ssize_t> resultHolder(new ssize_t[len + 1]);
+ ssize_t i = 0;
+ ssize_t j = -1;
+ resultHolder[0] = -1;
+ while (i < len) {
+ while ((j >= 0) && (begin[j] != begin[i]))
+ j = resultHolder[j];
+ ++i;
+ ++j;
+ Y_ASSERT(i >= 0);
+ Y_ASSERT(j >= 0);
+ Y_ASSERT(j < len);
+ if ((i < len) && (begin[i] == begin[j]))
+ resultHolder[i] = resultHolder[j];
+ else
+ resultHolder[i] = j;
+ }
+ *result = resultHolder.Release();
+}
+
+class TKMPMatcher {
+private:
+ TArrayHolder<ssize_t> PrefixFunction;
+ TString Pattern;
+
+ void ComputePrefixFunction();
+
+public:
+ TKMPMatcher(const char* patternBegin, const char* patternEnd);
+ TKMPMatcher(const TString& pattern);
+
+ bool SubStr(const char* begin, const char* end, const char*& result) const {
+ Y_ASSERT(begin <= end);
+ ssize_t m = Pattern.size();
+ ssize_t n = end - begin;
+ ssize_t i, j;
+ for (i = 0, j = 0; (i < n) && (j < m); ++i, ++j) {
+ while ((j >= 0) && (Pattern[j] != begin[i]))
+ j = PrefixFunction[j];
+ }
+ if (j == m) {
+ result = begin + i - m;
+ return true;
+ } else {
+ return false;
+ }
+ }
+};
+
+template <typename T>
+class TKMPStreamMatcher {
+public:
+ class ICallback {
+ public:
+ virtual void OnMatch(const T* begin, const T* end) = 0;
+ virtual ~ICallback() = default;
+ };
+
+private:
+ ICallback* Callback;
+ TArrayHolder<ssize_t> PrefixFunction;
+ using TTVector = TVector<T>;
+ TTVector Pattern;
+ ssize_t State;
+ TTVector Candidate;
+
+public:
+ TKMPStreamMatcher(const T* patternBegin, const T* patternEnd, ICallback* callback)
+ : Callback(callback)
+ , Pattern(patternBegin, patternEnd)
+ , State(0)
+ , Candidate(Pattern.size())
+ {
+ ssize_t* pf;
+ ComputePrefixFunction(patternBegin, patternEnd, &pf);
+ PrefixFunction.Reset(pf);
+ }
+
+ void Push(const T& symbol) {
+ while ((State >= 0) && (Pattern[State] != symbol)) {
+ Y_ASSERT(State <= (ssize_t) Pattern.size());
+ State = PrefixFunction[State];
+ Y_ASSERT(State <= (ssize_t) Pattern.size());
+ }
+ if (State >= 0)
+ Candidate[State] = symbol;
+ ++State;
+ if (State == (ssize_t) Pattern.size()) {
+ Callback->OnMatch(Candidate.begin(), Candidate.end());
+ State = 0;
+ }
+ }
+
+ void Clear() {
+ State = 0;
+ }
+};
diff --git a/library/cpp/deprecated/kmp/kmp_ut.cpp b/library/cpp/deprecated/kmp/kmp_ut.cpp
new file mode 100644
index 0000000000..c2eda83c57
--- /dev/null
+++ b/library/cpp/deprecated/kmp/kmp_ut.cpp
@@ -0,0 +1,80 @@
+#include "kmp.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/output.h>
+
+static TVector<int> FindAll(const TString& pattern, const TString& string) {
+ TVector<int> result;
+ TKMPMatcher kmp(pattern);
+ const char* pResult;
+ const char* begin = string.begin();
+ const char* end = string.end();
+ while (kmp.SubStr(begin, end, pResult)) {
+ result.push_back(int(pResult - string.data()));
+ begin = pResult + pattern.size();
+ }
+ return result;
+}
+
+class TTestKMP: public TTestBase {
+ UNIT_TEST_SUITE(TTestKMP);
+ UNIT_TEST(Test);
+ UNIT_TEST(TestStream);
+ UNIT_TEST_SUITE_END();
+
+public:
+ void Test() {
+ TVector<int> ans = {0, 2};
+ UNIT_ASSERT_EQUAL(FindAll("a", "aba"), ans);
+ ans = {0};
+ UNIT_ASSERT_EQUAL(FindAll("aba", "aba"), ans);
+ ans.clear();
+ UNIT_ASSERT_EQUAL(FindAll("abad", "aba"), ans);
+ ans = {0, 2};
+ UNIT_ASSERT_EQUAL(FindAll("ab", "abab"), ans);
+ }
+
+ class TKMPSimpleCallback: public TKMPStreamMatcher<int>::ICallback {
+ private:
+ int* Begin;
+ int* End;
+ int Count;
+
+ public:
+ TKMPSimpleCallback(int* begin, int* end)
+ : Begin(begin)
+ , End(end)
+ , Count(0)
+ {
+ }
+
+ void OnMatch(const int* begin, const int* end) override {
+ UNIT_ASSERT_EQUAL(end - begin, End - Begin);
+ const int* p0 = Begin;
+ const int* p1 = begin;
+ while (p0 < End) {
+ UNIT_ASSERT_EQUAL(*p0, *p1);
+ ++p0;
+ ++p1;
+ }
+ ++Count;
+ }
+
+ int GetCount() const {
+ return Count;
+ }
+ };
+
+ void TestStream() {
+ int pattern[] = {2, 3};
+ int data[] = {1, 2, 3, 5, 2, 2, 3, 2, 4, 3, 2};
+ TKMPSimpleCallback callback(pattern, pattern + 2);
+ TKMPStreamMatcher<int> matcher(pattern, pattern + 2, &callback);
+ for (auto& i : data)
+ matcher.Push(i);
+ UNIT_ASSERT_EQUAL(2, callback.GetCount());
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TTestKMP);
diff --git a/library/cpp/deprecated/kmp/ut/ya.make b/library/cpp/deprecated/kmp/ut/ya.make
new file mode 100644
index 0000000000..9c54ee2715
--- /dev/null
+++ b/library/cpp/deprecated/kmp/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/deprecated/kmp)
+
+OWNER(g:util)
+
+SRCS(
+ kmp_ut.cpp
+)
+
+END()
diff --git a/library/cpp/deprecated/kmp/ya.make b/library/cpp/deprecated/kmp/ya.make
new file mode 100644
index 0000000000..7c1c557934
--- /dev/null
+++ b/library/cpp/deprecated/kmp/ya.make
@@ -0,0 +1,10 @@
+LIBRARY()
+
+OWNER(g:util)
+
+SRCS(
+ kmp.cpp
+ kmp.h
+)
+
+END()
diff --git a/library/cpp/deprecated/mapped_file/mapped_file.cpp b/library/cpp/deprecated/mapped_file/mapped_file.cpp
new file mode 100644
index 0000000000..b0e4511299
--- /dev/null
+++ b/library/cpp/deprecated/mapped_file/mapped_file.cpp
@@ -0,0 +1,64 @@
+#include "mapped_file.h"
+
+#include <util/generic/yexception.h>
+#include <util/system/defaults.h>
+#include <util/system/hi_lo.h>
+#include <util/system/filemap.h>
+
+TMappedFile::TMappedFile(TFileMap* map, const char* dbgName) {
+ Map_ = map;
+ i64 len = Map_->Length();
+ if (Hi32(len) != 0 && sizeof(size_t) <= sizeof(ui32))
+ ythrow yexception() << "File '" << dbgName << "' mapping error: " << len << " too large";
+
+ Map_->Map(0, static_cast<size_t>(len));
+}
+
+TMappedFile::TMappedFile(const TFile& file, TFileMap::EOpenMode om, const char* dbgName)
+ : Map_(nullptr)
+{
+ init(file, om, dbgName);
+}
+
+void TMappedFile::precharge(size_t off, size_t size) const {
+ if (!Map_)
+ return;
+
+ Map_->Precharge(off, size);
+}
+
+void TMappedFile::init(const TString& name) {
+ THolder<TFileMap> map(new TFileMap(name));
+ TMappedFile newFile(map.Get(), name.data());
+ Y_UNUSED(map.Release());
+ newFile.swap(*this);
+ newFile.term();
+}
+
+void TMappedFile::init(const TString& name, size_t length, TFileMap::EOpenMode om) {
+ THolder<TFileMap> map(new TFileMap(name, length, om));
+ TMappedFile newFile(map.Get(), name.data());
+ Y_UNUSED(map.Release());
+ newFile.swap(*this);
+ newFile.term();
+}
+
+void TMappedFile::init(const TFile& file, TFileMap::EOpenMode om, const char* dbgName) {
+ THolder<TFileMap> map(new TFileMap(file, om));
+ TMappedFile newFile(map.Get(), dbgName);
+ Y_UNUSED(map.Release());
+ newFile.swap(*this);
+ newFile.term();
+}
+
+void TMappedFile::init(const TString& name, TFileMap::EOpenMode om) {
+ THolder<TFileMap> map(new TFileMap(name, om));
+ TMappedFile newFile(map.Get(), name.data());
+ Y_UNUSED(map.Release());
+ newFile.swap(*this);
+ newFile.term();
+}
+
+void TMappedFile::flush() {
+ Map_->Flush();
+}
diff --git a/library/cpp/deprecated/mapped_file/mapped_file.h b/library/cpp/deprecated/mapped_file/mapped_file.h
new file mode 100644
index 0000000000..45859ed65a
--- /dev/null
+++ b/library/cpp/deprecated/mapped_file/mapped_file.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include <util/generic/flags.h>
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+#include <util/generic/utility.h>
+#include <util/generic/yexception.h>
+#include <util/system/align.h>
+#include <util/system/file.h>
+#include <util/system/filemap.h>
+#include <util/system/yassert.h>
+
+#include <cstdio>
+#include <new>
+
+/// Deprecated (by pg@), use TFileMap or TMemoryMap instead
+class TMappedFile {
+private:
+ TFileMap* Map_;
+
+private:
+ TMappedFile(TFileMap* map, const char* dbgName);
+
+public:
+ TMappedFile() {
+ Map_ = nullptr;
+ }
+
+ ~TMappedFile() {
+ term();
+ }
+
+ explicit TMappedFile(const TString& name) {
+ Map_ = nullptr;
+ init(name, TFileMap::oRdOnly);
+ }
+
+ TMappedFile(const TFile& file, TFileMap::EOpenMode om = TFileMap::oRdOnly, const char* dbgName = "unknown");
+
+ void init(const TString& name);
+
+ void init(const TString& name, TFileMap::EOpenMode om);
+
+ void init(const TString& name, size_t length, TFileMap::EOpenMode om);
+
+ void init(const TFile&, TFileMap::EOpenMode om = TFileMap::oRdOnly, const char* dbgName = "unknown");
+
+ void flush();
+
+ void term() {
+ if (Map_) {
+ Map_->Unmap();
+ delete Map_;
+ Map_ = nullptr;
+ }
+ }
+
+ size_t getSize() const {
+ return (Map_ ? Map_->MappedSize() : 0);
+ }
+
+ void* getData(size_t pos = 0) const {
+ Y_ASSERT(!Map_ || (pos <= getSize()));
+ return (Map_ ? (void*)((unsigned char*)Map_->Ptr() + pos) : nullptr);
+ }
+
+ void precharge(size_t pos = 0, size_t size = (size_t)-1) const;
+
+ void swap(TMappedFile& file) noexcept {
+ DoSwap(Map_, file.Map_);
+ }
+};
diff --git a/library/cpp/deprecated/mapped_file/ut/mapped_file_ut.cpp b/library/cpp/deprecated/mapped_file/ut/mapped_file_ut.cpp
new file mode 100644
index 0000000000..afbd5b3358
--- /dev/null
+++ b/library/cpp/deprecated/mapped_file/ut/mapped_file_ut.cpp
@@ -0,0 +1,18 @@
+#include <library/cpp/deprecated/mapped_file/mapped_file.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/system/fs.h>
+
+Y_UNIT_TEST_SUITE(TMappedFileTest) {
+ static const char* FileName_("./mappped_file");
+ Y_UNIT_TEST(TestFileMapEmpty) {
+ TFile file(FileName_, CreateAlways | WrOnly);
+ file.Close();
+
+ TMappedFile map;
+ map.init(FileName_);
+ map.getData(0);
+
+ NFs::Remove(FileName_);
+ }
+};
diff --git a/library/cpp/deprecated/mapped_file/ya.make b/library/cpp/deprecated/mapped_file/ya.make
new file mode 100644
index 0000000000..415c438382
--- /dev/null
+++ b/library/cpp/deprecated/mapped_file/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(g:util)
+
+SRCS(
+ mapped_file.cpp
+)
+
+END()
diff --git a/library/cpp/deprecated/split/delim_string_iter.cpp b/library/cpp/deprecated/split/delim_string_iter.cpp
new file mode 100644
index 0000000000..af418c5bfb
--- /dev/null
+++ b/library/cpp/deprecated/split/delim_string_iter.cpp
@@ -0,0 +1,45 @@
+#include "delim_string_iter.h"
+
+//
+// TKeyValueDelimStringIter
+//
+
+void TKeyValueDelimStringIter::ReadKeyAndValue() {
+ TStringBuf currentToken(*DelimIter);
+
+ size_t pos = currentToken.find('=');
+ if (pos == TString::npos) {
+ ChunkValue.Clear();
+ ChunkKey = currentToken;
+ } else {
+ ChunkKey = currentToken.SubStr(0, pos);
+ ChunkValue = currentToken.SubStr(pos + 1);
+ }
+}
+
+TKeyValueDelimStringIter::TKeyValueDelimStringIter(const TStringBuf str, const TStringBuf delim)
+ : DelimIter(str, delim)
+{
+ if (DelimIter.Valid())
+ ReadKeyAndValue();
+}
+
+bool TKeyValueDelimStringIter::Valid() const {
+ return DelimIter.Valid();
+}
+
+TKeyValueDelimStringIter& TKeyValueDelimStringIter::operator++() {
+ ++DelimIter;
+ if (DelimIter.Valid())
+ ReadKeyAndValue();
+
+ return *this;
+}
+
+const TStringBuf& TKeyValueDelimStringIter::Key() const {
+ return ChunkKey;
+}
+
+const TStringBuf& TKeyValueDelimStringIter::Value() const {
+ return ChunkValue;
+}
diff --git a/library/cpp/deprecated/split/delim_string_iter.h b/library/cpp/deprecated/split/delim_string_iter.h
new file mode 100644
index 0000000000..8e4ca171a0
--- /dev/null
+++ b/library/cpp/deprecated/split/delim_string_iter.h
@@ -0,0 +1,185 @@
+#pragma once
+
+#include <util/generic/algorithm.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/yexception.h>
+#include <util/string/cast.h>
+#include <util/system/yassert.h>
+
+#include <iterator>
+
+class TDelimStringIter {
+public:
+ using value_type = TStringBuf;
+ using difference_type = ptrdiff_t;
+ using pointer = const TStringBuf*;
+ using reference = const TStringBuf&;
+ using iterator_category = std::forward_iterator_tag;
+
+ inline TDelimStringIter(const char* begin, const char* strEnd, TStringBuf delim)
+ : TDelimStringIter(TStringBuf(begin, strEnd), delim)
+ {
+ }
+
+ inline TDelimStringIter(TStringBuf str, TStringBuf delim)
+ : IsValid(true)
+ , Str(str)
+ , Delim(delim)
+ {
+ UpdateCurrent();
+ }
+
+ inline TDelimStringIter()
+ : IsValid(false)
+ {
+ }
+
+ inline explicit operator bool() const {
+ return IsValid;
+ }
+
+ // NOTE: this is a potentially unsafe operation (no overrun check)
+ inline TDelimStringIter& operator++() {
+ if (Current.end() != Str.end()) {
+ Str.Skip(Current.length() + Delim.length());
+ UpdateCurrent();
+ } else {
+ Str.Clear();
+ Current.Clear();
+ IsValid = false;
+ }
+ return *this;
+ }
+
+ inline void operator+=(size_t n) {
+ for (; n > 0; --n) {
+ ++(*this);
+ }
+ }
+
+ inline bool operator==(const TDelimStringIter& rhs) const {
+ return (IsValid == rhs.IsValid) && (!IsValid || (Current.begin() == rhs.Current.begin()));
+ }
+
+ inline bool operator!=(const TDelimStringIter& rhs) const {
+ return !(*this == rhs);
+ }
+
+ inline TStringBuf operator*() const {
+ return Current;
+ }
+
+ inline const TStringBuf* operator->() const {
+ return &Current;
+ }
+
+ // Get & advance
+ template <class T>
+ inline bool TryNext(T& t) {
+ if (IsValid) {
+ t = FromString<T>(Current);
+ operator++();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ template <class T>
+ inline TDelimStringIter& Next(T& t) // Get & advance
+ {
+ if (!TryNext(t))
+ ythrow yexception() << "No valid field";
+ return *this;
+ }
+
+ template <class T>
+ inline T GetNext() {
+ T res;
+ Next(res);
+ return res;
+ }
+
+ inline const char* GetBegin() const {
+ return Current.begin();
+ }
+
+ inline const char* GetEnd() const {
+ return Current.end();
+ }
+
+ inline bool Valid() const {
+ return IsValid;
+ }
+
+ // contents from next token to the end of string
+ inline TStringBuf Cdr() const {
+ return Str.SubStr(Current.length() + Delim.length());
+ }
+
+ inline TDelimStringIter IterEnd() const {
+ return TDelimStringIter();
+ }
+
+private:
+ inline void UpdateCurrent() {
+ // it is much faster than TStringBuf::find
+ size_t pos = std::search(Str.begin(), Str.end(), Delim.begin(), Delim.end()) - Str.begin();
+ Current = Str.Head(pos);
+ }
+
+private:
+ bool IsValid;
+
+ TStringBuf Str;
+ TStringBuf Current;
+ TStringBuf Delim;
+};
+
+//example: for (TStringBuf field: TDelimStroka(line, "@@")) { ... }
+struct TDelimStroka {
+ TStringBuf S;
+ TStringBuf Delim;
+
+ inline TDelimStroka(TStringBuf s, TStringBuf delim)
+ : S(s)
+ , Delim(delim)
+ {
+ }
+
+ inline TDelimStringIter begin() const {
+ return TDelimStringIter(S, Delim);
+ }
+
+ inline TDelimStringIter end() const {
+ return TDelimStringIter();
+ }
+};
+
+inline TDelimStringIter begin_delim(const TString& str, TStringBuf delim) {
+ return TDelimStringIter(str, delim);
+}
+
+inline TDelimStringIter begin_delim(TStringBuf str, TStringBuf delim) {
+ return TDelimStringIter(str.begin(), str.end(), delim);
+}
+
+inline TDelimStringIter end_delim(const TString& /*str*/, TStringBuf /*delim*/) {
+ return TDelimStringIter();
+}
+
+class TKeyValueDelimStringIter {
+public:
+ TKeyValueDelimStringIter(const TStringBuf str, const TStringBuf delim);
+ bool Valid() const;
+ TKeyValueDelimStringIter& operator++();
+ const TStringBuf& Key() const;
+ const TStringBuf& Value() const;
+
+private:
+ TDelimStringIter DelimIter;
+ TStringBuf ChunkKey, ChunkValue;
+
+private:
+ void ReadKeyAndValue();
+};
diff --git a/library/cpp/deprecated/split/delim_string_iter_ut.cpp b/library/cpp/deprecated/split/delim_string_iter_ut.cpp
new file mode 100644
index 0000000000..18a8b2a160
--- /dev/null
+++ b/library/cpp/deprecated/split/delim_string_iter_ut.cpp
@@ -0,0 +1,99 @@
+#include "delim_string_iter.h"
+#include <util/generic/vector.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+/// Test that TDelimStringIter build on top of given string and delimeter will produce expected sequence
+static void AssertStringSplit(const TString& str, const TString& delim, const TVector<TString>& expected) {
+ TDelimStringIter it(str, delim);
+
+ // test iterator invariants
+ for (const auto& expectedString : expected) {
+ UNIT_ASSERT(it.Valid());
+ UNIT_ASSERT(bool(it));
+ UNIT_ASSERT_STRINGS_EQUAL(it->ToString(), expectedString);
+ ++it;
+ }
+ UNIT_ASSERT(!it.Valid());
+};
+
+Y_UNIT_TEST_SUITE(TDelimStrokaIterTestSuite) {
+ Y_UNIT_TEST(SingleCharacterAsDelimiter) {
+ AssertStringSplit(
+ "Hello words!", " ", {"Hello", "words!"});
+ }
+
+ Y_UNIT_TEST(MultipleCharactersAsDelimiter) {
+ AssertStringSplit(
+ "0, 1, 1, 2, 3, 5, 8, 13, 21, 34", "1, ", {"0, ", "", "2, 3, 5, 8, 13, 2", "34"});
+ }
+
+ Y_UNIT_TEST(NoDelimitersPresent) {
+ AssertStringSplit("This string could be yours", "\t", {"This string could be yours"});
+ }
+
+ Y_UNIT_TEST(Cdr) {
+ TDelimStringIter it("a\tc\t", "\t");
+ UNIT_ASSERT_STRINGS_EQUAL(*it, "a");
+ UNIT_ASSERT_STRINGS_EQUAL(it.Cdr(), "c\t");
+ ++it;
+ UNIT_ASSERT_STRINGS_EQUAL(it.Cdr(), "");
+ }
+
+ Y_UNIT_TEST(ForIter) {
+ TVector<TStringBuf> expected = {"1", "", "3@4", ""};
+ TVector<TStringBuf> got;
+
+ for (TStringBuf x : TDelimStroka("1@@@@3@4@@", "@@")) {
+ got.push_back(x);
+ }
+
+ UNIT_ASSERT_EQUAL(got, expected);
+ }
+}
+
+static void AssertKeyValueStringSplit(
+ const TStringBuf str,
+ const TStringBuf delim,
+ const TVector<std::pair<TStringBuf, TStringBuf>>& expected) {
+ TKeyValueDelimStringIter it(str, delim);
+
+ for (const auto& expectedKeyValue : expected) {
+ UNIT_ASSERT(it.Valid());
+ UNIT_ASSERT_STRINGS_EQUAL(it.Key(), expectedKeyValue.first);
+ UNIT_ASSERT_STRINGS_EQUAL(it.Value(), expectedKeyValue.second);
+ ++it;
+ }
+ UNIT_ASSERT(!it.Valid());
+}
+
+Y_UNIT_TEST_SUITE(TKeyValueDelimStringIterTestSuite) {
+ Y_UNIT_TEST(SingleCharacterAsDelimiter) {
+ AssertKeyValueStringSplit(
+ "abc=123,cde=qwer", ",",
+ {{"abc", "123"},
+ {"cde", "qwer"}});
+ }
+
+ Y_UNIT_TEST(MultipleCharactersAsDelimiter) {
+ AssertKeyValueStringSplit(
+ "abc=xyz@@qwerty=zxcv", "@@",
+ {{"abc", "xyz"},
+ {"qwerty", "zxcv"}});
+ }
+
+ Y_UNIT_TEST(NoDelimiters) {
+ AssertKeyValueStringSplit(
+ "abc=zz", ",",
+ {{"abc", "zz"}});
+ }
+
+ Y_UNIT_TEST(EmptyElements) {
+ AssertKeyValueStringSplit(
+ "@@abc=zxy@@@@qwerty=y@@", "@@",
+ {{"", ""},
+ {"abc", "zxy"},
+ {"", ""},
+ {"qwerty", "y"},
+ {"", ""}});
+ }
+}
diff --git a/library/cpp/deprecated/split/split_iterator.cpp b/library/cpp/deprecated/split/split_iterator.cpp
new file mode 100644
index 0000000000..32262d25bd
--- /dev/null
+++ b/library/cpp/deprecated/split/split_iterator.cpp
@@ -0,0 +1,318 @@
+#include "split_iterator.h"
+
+#include <util/system/yassert.h>
+
+#include <cctype>
+#include <cstring>
+#include <cstdlib>
+
+/****************** TSplitDelimiters2 ******************/
+
+TSplitDelimiters::TSplitDelimiters(const char* s) {
+ memset(Delims, 0, sizeof(Delims));
+ while (*s)
+ Delims[(ui8) * (s++)] = true;
+}
+
+/****************** TSplitBase ******************/
+TSplitBase::TSplitBase(const char* str, size_t length)
+ : Str(str)
+ , Len(length)
+{
+}
+
+TSplitBase::TSplitBase(const TString& s)
+ : Str(s.data())
+ , Len(s.size())
+{
+}
+
+/****************** TDelimitersSplit ******************/
+
+TDelimitersSplit::TDelimitersSplit(const char* str, size_t length, const TSplitDelimiters& delimiters)
+ : TSplitBase(str, length)
+ , Delimiters(delimiters)
+{
+}
+
+TDelimitersSplit::TDelimitersSplit(const TString& s, const TSplitDelimiters& delimiters)
+ : TSplitBase(s)
+ , Delimiters(delimiters)
+{
+}
+
+size_t TDelimitersSplit::Begin() const {
+ size_t pos = 0;
+ while ((pos < Len) && Delimiters.IsDelimiter(Str[pos]))
+ ++pos;
+ return pos;
+}
+
+TSizeTRegion TDelimitersSplit::Next(size_t& pos) const {
+ size_t begin = pos;
+ while ((pos < Len) && !Delimiters.IsDelimiter(Str[pos]))
+ ++pos;
+ TSizeTRegion result(begin, pos);
+
+ while ((pos < Len) && Delimiters.IsDelimiter(Str[pos]))
+ ++pos;
+
+ return result;
+}
+
+TDelimitersSplit::TIterator TDelimitersSplit::Iterator() const {
+ return TIterator(*this);
+}
+
+/****************** TDelimitersStrictSplit ******************/
+
+TDelimitersStrictSplit::TDelimitersStrictSplit(const char* str, size_t length, const TSplitDelimiters& delimiters)
+ : TSplitBase(str, length)
+ , Delimiters(delimiters)
+{
+}
+
+TDelimitersStrictSplit::TDelimitersStrictSplit(const TString& s, const TSplitDelimiters& delimiters)
+ : TSplitBase(s)
+ , Delimiters(delimiters)
+{
+}
+
+TDelimitersStrictSplit::TIterator TDelimitersStrictSplit::Iterator() const {
+ return TIterator(*this);
+}
+
+TSizeTRegion TDelimitersStrictSplit::Next(size_t& pos) const {
+ size_t begin = pos;
+ while ((pos < Len) && !Delimiters.IsDelimiter(Str[pos]))
+ ++pos;
+ TSizeTRegion result(begin, pos);
+
+ if (pos < Len)
+ ++pos;
+
+ return result;
+}
+
+size_t TDelimitersStrictSplit::Begin() const {
+ return 0;
+}
+
+/****************** TScreenedDelimitersSplit ******************/
+
+TScreenedDelimitersSplit::TScreenedDelimitersSplit(const TString& s, const TSplitDelimiters& delimiters, const TSplitDelimiters& screens)
+ : TSplitBase(s)
+ , Delimiters(delimiters)
+ , Screens(screens)
+{
+}
+
+TScreenedDelimitersSplit::TScreenedDelimitersSplit(const char* str, size_t length, const TSplitDelimiters& delimiters, const TSplitDelimiters& screens)
+ : TSplitBase(str, length)
+ , Delimiters(delimiters)
+ , Screens(screens)
+{
+}
+
+TScreenedDelimitersSplit::TIterator TScreenedDelimitersSplit::Iterator() const {
+ return TIterator(*this);
+}
+
+TSizeTRegion TScreenedDelimitersSplit::Next(size_t& pos) const {
+ size_t begin = pos;
+ bool screened = false;
+ while (pos < Len) {
+ if (Screens.IsDelimiter(Str[pos]))
+ screened = !screened;
+ if (Delimiters.IsDelimiter(Str[pos]) && !screened)
+ break;
+ ++pos;
+ }
+ TSizeTRegion result(begin, pos);
+
+ if (pos < Len)
+ ++pos;
+
+ return result;
+}
+
+size_t TScreenedDelimitersSplit::Begin() const {
+ return 0;
+}
+
+/****************** TDelimitersSplitWithoutTags ******************/
+
+TDelimitersSplitWithoutTags::TDelimitersSplitWithoutTags(const char* str, size_t length, const TSplitDelimiters& delimiters)
+ : TSplitBase(str, length)
+ , Delimiters(delimiters)
+{
+}
+
+TDelimitersSplitWithoutTags::TDelimitersSplitWithoutTags(const TString& s, const TSplitDelimiters& delimiters)
+ : TSplitBase(s)
+ , Delimiters(delimiters)
+{
+}
+
+size_t TDelimitersSplitWithoutTags::SkipTag(size_t pos) const {
+ Y_ASSERT('<' == Str[pos]);
+ while ((pos < Len) && ('>' != Str[pos]))
+ ++pos;
+ return pos + 1;
+}
+
+size_t TDelimitersSplitWithoutTags::SkipDelimiters(size_t pos) const {
+ while (true) {
+ while ((pos < Len) && Delimiters.IsDelimiter(Str[pos]) && ('<' != Str[pos]))
+ ++pos;
+ if (pos < Len) {
+ if ('<' != Str[pos])
+ break;
+ else
+ pos = SkipTag(pos);
+ } else
+ break;
+ }
+ return pos;
+}
+
+size_t TDelimitersSplitWithoutTags::Begin() const {
+ size_t pos = 0;
+ pos = SkipDelimiters(pos);
+ return pos;
+}
+
+TSizeTRegion TDelimitersSplitWithoutTags::Next(size_t& pos) const {
+ size_t begin = pos;
+ while ((pos < Len) && !Delimiters.IsDelimiter(Str[pos]) && ('<' != Str[pos]))
+ ++pos;
+ TSizeTRegion result(begin, pos);
+
+ pos = SkipDelimiters(pos);
+
+ return result;
+}
+
+TDelimitersSplitWithoutTags::TIterator TDelimitersSplitWithoutTags::Iterator() const {
+ return TIterator(*this);
+}
+
+/****************** TCharSplit ******************/
+
+TCharSplit::TCharSplit(const char* str, size_t length)
+ : TSplitBase(str, length)
+{
+}
+
+TCharSplit::TCharSplit(const TString& s)
+ : TSplitBase(s)
+{
+}
+
+TCharSplit::TIterator TCharSplit::Iterator() const {
+ return TIterator(*this);
+}
+
+TSizeTRegion TCharSplit::Next(size_t& pos) const {
+ TSizeTRegion result(pos, pos + 1);
+ ++pos;
+ return result;
+}
+
+size_t TCharSplit::Begin() const {
+ return 0;
+}
+
+/****************** TCharSplitWithoutTags ******************/
+
+TCharSplitWithoutTags::TCharSplitWithoutTags(const char* str, size_t length)
+ : TSplitBase(str, length)
+{
+}
+
+TCharSplitWithoutTags::TCharSplitWithoutTags(const TString& s)
+ : TSplitBase(s)
+{
+}
+
+size_t TCharSplitWithoutTags::SkipTag(size_t pos) const {
+ Y_ASSERT('<' == Str[pos]);
+ while ((pos < Len) && ('>' != Str[pos]))
+ ++pos;
+ return pos + 1;
+}
+
+size_t TCharSplitWithoutTags::SkipDelimiters(size_t pos) const {
+ while (true) {
+ if (pos < Len) {
+ if ('<' != Str[pos])
+ break;
+ else
+ pos = SkipTag(pos);
+ } else
+ break;
+ }
+ return pos;
+}
+
+size_t TCharSplitWithoutTags::Begin() const {
+ size_t pos = 0;
+ pos = SkipDelimiters(pos);
+ return pos;
+}
+
+TSizeTRegion TCharSplitWithoutTags::Next(size_t& pos) const {
+ size_t begin = pos++;
+ TSizeTRegion result(begin, pos);
+
+ pos = SkipDelimiters(pos);
+
+ return result;
+}
+
+TCharSplitWithoutTags::TIterator TCharSplitWithoutTags::Iterator() const {
+ return TIterator(*this);
+}
+
+TSubstringSplitDelimiter::TSubstringSplitDelimiter(const TString& s)
+ : Matcher(s)
+ , Len(s.size())
+{
+}
+
+/****************** TSubstringSplit ******************/
+
+TSubstringSplit::TSubstringSplit(const char* str, size_t length, const TSubstringSplitDelimiter& delimiter)
+ : TSplitBase(str, length)
+ , Delimiter(delimiter)
+{
+}
+
+TSubstringSplit::TSubstringSplit(const TString& str, const TSubstringSplitDelimiter& delimiter)
+ : TSplitBase(str)
+ , Delimiter(delimiter)
+{
+}
+
+TSubstringSplit::TIterator TSubstringSplit::Iterator() const {
+ return TIterator(*this);
+}
+
+TSizeTRegion TSubstringSplit::Next(size_t& pos) const {
+ const char* begin = Str + pos;
+ const char* end = Str + Len;
+ const char* delim;
+ if (Delimiter.Matcher.SubStr(begin, end, delim)) {
+ TSizeTRegion result(pos, delim - begin + pos);
+ pos += delim - begin + Delimiter.Len;
+ return result;
+ } else {
+ TSizeTRegion result(pos, end - begin + pos);
+ pos += end - begin;
+ return result;
+ }
+}
+
+size_t TSubstringSplit::Begin() const {
+ return 0;
+}
diff --git a/library/cpp/deprecated/split/split_iterator.h b/library/cpp/deprecated/split/split_iterator.h
new file mode 100644
index 0000000000..0eacc29228
--- /dev/null
+++ b/library/cpp/deprecated/split/split_iterator.h
@@ -0,0 +1,317 @@
+#pragma once
+
+#include <library/cpp/deprecated/kmp/kmp.h>
+#include <util/string/cast.h>
+#include <util/string/util.h>
+#include <util/string/builder.h>
+
+#include <util/system/yassert.h>
+#include <util/system/defaults.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+#include <cstdio>
+
+template <typename T>
+struct TNumPair {
+ T Begin;
+ T End;
+
+ TNumPair() = default;
+
+ TNumPair(T begin, T end)
+ : Begin(begin)
+ , End(end)
+ {
+ Y_ASSERT(begin <= end);
+ }
+
+ T Length() const {
+ return End - Begin + 1;
+ }
+
+ bool operator==(const TNumPair& r) const {
+ return (Begin == r.Begin) && (End == r.End);
+ }
+
+ bool operator!=(const TNumPair& r) const {
+ return (Begin != r.Begin) || (End != r.End);
+ }
+};
+
+using TSizeTRegion = TNumPair<size_t>;
+using TUi32Region = TNumPair<ui32>;
+
+template <>
+inline TString ToString(const TUi32Region& r) {
+ return TStringBuilder() << "(" << r.Begin << ", " << r.End << ")";
+}
+
+template <>
+inline TUi32Region FromString(const TString& s) {
+ TUi32Region result;
+ sscanf(s.data(), "(%" PRIu32 ", %" PRIu32 ")", &result.Begin, &result.End);
+ return result;
+}
+
+class TSplitDelimiters {
+private:
+ bool Delims[256];
+
+public:
+ explicit TSplitDelimiters(const char* s);
+
+ Y_FORCE_INLINE bool IsDelimiter(ui8 ch) const {
+ return Delims[ch];
+ }
+};
+
+template <class Split>
+class TSplitIterator;
+
+class TSplitBase {
+protected:
+ const char* Str;
+ size_t Len;
+
+public:
+ TSplitBase(const char* str, size_t length);
+ TSplitBase(const TString& s);
+
+ Y_FORCE_INLINE const char* GetString() const {
+ return Str;
+ }
+
+ Y_FORCE_INLINE size_t GetLength() const {
+ return Len;
+ }
+
+private:
+ // we don't own Str, make sure that no one calls us with temporary object
+ TSplitBase(TString&&) = delete;
+};
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4512)
+#endif
+
+class TDelimitersSplit: public TSplitBase {
+private:
+ const TSplitDelimiters& Delimiters;
+
+public:
+ using TIterator = TSplitIterator<TDelimitersSplit>;
+ friend class TSplitIterator<TDelimitersSplit>;
+
+ TDelimitersSplit(const char* str, size_t length, const TSplitDelimiters& delimiters);
+ TDelimitersSplit(const TString& s, const TSplitDelimiters& delimiters);
+ TIterator Iterator() const;
+ TSizeTRegion Next(size_t& pos) const;
+ size_t Begin() const;
+
+private:
+ // we don't own Delimiters, make sure that no one calls us with temporary object
+ TDelimitersSplit(const char*, size_t, TSplitDelimiters&&) = delete;
+ TDelimitersSplit(const TString&, TSplitDelimiters&&) = delete;
+ TDelimitersSplit(TString&&, const TSplitDelimiters&) = delete;
+};
+
+class TDelimitersStrictSplit: public TSplitBase {
+private:
+ const TSplitDelimiters& Delimiters;
+
+public:
+ using TIterator = TSplitIterator<TDelimitersStrictSplit>;
+ friend class TSplitIterator<TDelimitersStrictSplit>;
+
+ TDelimitersStrictSplit(const char* str, size_t length, const TSplitDelimiters& delimiters);
+ TDelimitersStrictSplit(const TString& s, const TSplitDelimiters& delimiters);
+ TIterator Iterator() const;
+ TSizeTRegion Next(size_t& pos) const;
+ size_t Begin() const;
+
+private:
+ // we don't own Delimiters, make sure that no one calls us with temporary object
+ TDelimitersStrictSplit(const char*, size_t, TSplitDelimiters&&) = delete;
+ TDelimitersStrictSplit(const TString&, TSplitDelimiters&&) = delete;
+ TDelimitersStrictSplit(TString&&, const TSplitDelimiters&) = delete;
+};
+
+class TScreenedDelimitersSplit: public TSplitBase {
+private:
+ const TSplitDelimiters& Delimiters;
+ const TSplitDelimiters& Screens;
+
+public:
+ using TIterator = TSplitIterator<TScreenedDelimitersSplit>;
+ friend class TSplitIterator<TScreenedDelimitersSplit>;
+
+ TScreenedDelimitersSplit(const char*, size_t, const TSplitDelimiters& delimiters, const TSplitDelimiters& screens);
+ TScreenedDelimitersSplit(const TString& s, const TSplitDelimiters& delimiters, const TSplitDelimiters& screens);
+ TIterator Iterator() const;
+ TSizeTRegion Next(size_t& pos) const;
+ size_t Begin() const;
+
+private:
+ // we don't own Delimiters and Screens, make sure that no one calls us with temporary object
+ TScreenedDelimitersSplit(TString&&, const TSplitDelimiters&, const TSplitDelimiters&) = delete;
+ TScreenedDelimitersSplit(const TString&, TSplitDelimiters&&, const TSplitDelimiters&) = delete;
+ TScreenedDelimitersSplit(const TString&, const TSplitDelimiters&, TSplitDelimiters&&) = delete;
+};
+
+class TDelimitersSplitWithoutTags: public TSplitBase {
+private:
+ const TSplitDelimiters& Delimiters;
+ size_t SkipTag(size_t pos) const;
+ size_t SkipDelimiters(size_t pos) const;
+
+public:
+ using TIterator = TSplitIterator<TDelimitersSplitWithoutTags>;
+ friend class TSplitIterator<TDelimitersSplitWithoutTags>;
+
+ TDelimitersSplitWithoutTags(const char* str, size_t length, const TSplitDelimiters& delimiters);
+ TDelimitersSplitWithoutTags(const TString& s, const TSplitDelimiters& delimiters);
+ TIterator Iterator() const;
+ TSizeTRegion Next(size_t& pos) const;
+ size_t Begin() const;
+
+private:
+ // we don't own Delimiters, make sure that no one calls us with temporary object
+ TDelimitersSplitWithoutTags(const char*, size_t, TSplitDelimiters&&) = delete;
+ TDelimitersSplitWithoutTags(const TString&, TSplitDelimiters&&) = delete;
+ TDelimitersSplitWithoutTags(TString&&, const TSplitDelimiters&) = delete;
+};
+
+class TCharSplit: public TSplitBase {
+public:
+ using TIterator = TSplitIterator<TCharSplit>;
+ friend class TSplitIterator<TCharSplit>;
+
+ TCharSplit(const char* str, size_t length);
+ TCharSplit(const TString& s);
+ TIterator Iterator() const;
+ TSizeTRegion Next(size_t& pos) const;
+ size_t Begin() const;
+
+private:
+ // we don't own Str, make sure that no one calls us with temporary object
+ TCharSplit(TString&&) = delete;
+};
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+class TCharSplitWithoutTags: public TSplitBase {
+private:
+ size_t SkipTag(size_t pos) const;
+ size_t SkipDelimiters(size_t pos) const;
+
+public:
+ using TIterator = TSplitIterator<TCharSplitWithoutTags>;
+ friend class TSplitIterator<TCharSplitWithoutTags>;
+
+ TCharSplitWithoutTags(const char* str, size_t length);
+ TCharSplitWithoutTags(const TString& s);
+ TIterator Iterator() const;
+ TSizeTRegion Next(size_t& pos) const;
+ size_t Begin() const;
+
+private:
+ // we don't own Str, make sure that no one calls us with temporary object
+ TCharSplitWithoutTags(TString&&) = delete;
+};
+
+class TSubstringSplitDelimiter {
+public:
+ TKMPMatcher Matcher;
+ size_t Len;
+
+ TSubstringSplitDelimiter(const TString& s);
+};
+
+class TSubstringSplit: public TSplitBase {
+private:
+ const TSubstringSplitDelimiter& Delimiter;
+
+public:
+ using TIterator = TSplitIterator<TSubstringSplit>;
+ friend class TSplitIterator<TSubstringSplit>;
+
+ TSubstringSplit(const char* str, size_t length, const TSubstringSplitDelimiter& delimiter);
+ TSubstringSplit(const TString& str, const TSubstringSplitDelimiter& delimiter);
+ TIterator Iterator() const;
+ TSizeTRegion Next(size_t& pos) const;
+ size_t Begin() const;
+
+private:
+ // we don't own Delimiters, make sure that no one calls us with temporary object
+ TSubstringSplit(TString&&, const TSubstringSplitDelimiter&) = delete;
+ TSubstringSplit(const TString&, TSubstringSplitDelimiter&&) = delete;
+};
+
+template <class TSplit>
+class TSplitIterator {
+protected:
+ const TSplit& Split;
+ size_t Pos;
+ TString* CurrentStroka;
+
+public:
+ TSplitIterator(const TSplit& split)
+ : Split(split)
+ , Pos(Split.Begin())
+ , CurrentStroka(nullptr)
+ {
+ }
+
+ virtual ~TSplitIterator() {
+ delete CurrentStroka;
+ }
+
+ inline TSizeTRegion Next() {
+ Y_ENSURE(!Eof(), TStringBuf("eof reached"));
+ return Split.Next(Pos);
+ }
+
+ TStringBuf NextTok() {
+ if (Eof())
+ return TStringBuf();
+ TSizeTRegion region = Next();
+ return TStringBuf(Split.Str + region.Begin, region.End - region.Begin);
+ }
+
+ const TString& NextString() {
+ if (!CurrentStroka)
+ CurrentStroka = new TString();
+ TSizeTRegion region = Next();
+ CurrentStroka->assign(Split.Str, region.Begin, region.Length() - 1);
+ return *CurrentStroka;
+ }
+
+ inline bool Eof() const {
+ return Pos >= Split.Len;
+ }
+
+ TString GetTail() const {
+ return TString(Split.Str + Pos);
+ }
+
+ void Skip(size_t count) {
+ for (size_t i = 0; i < count; ++i)
+ Next();
+ }
+};
+
+using TSplitTokens = TVector<TString>;
+
+template <typename TSplit>
+void Split(const TSplit& split, TSplitTokens* words) {
+ words->clear();
+ TSplitIterator<TSplit> it(split);
+ while (!it.Eof())
+ words->push_back(it.NextString());
+}
diff --git a/library/cpp/deprecated/split/split_iterator_ut.cpp b/library/cpp/deprecated/split/split_iterator_ut.cpp
new file mode 100644
index 0000000000..be5069c4be
--- /dev/null
+++ b/library/cpp/deprecated/split/split_iterator_ut.cpp
@@ -0,0 +1,152 @@
+#include "split_iterator.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+class TSplitIteratorTest: public TTestBase {
+ UNIT_TEST_SUITE(TSplitIteratorTest);
+ UNIT_TEST(TestDelimiters);
+ UNIT_TEST(TestDelimitersSplit);
+ UNIT_TEST(TestDelimitersStrictSplit);
+ UNIT_TEST(TestTail);
+ UNIT_TEST(TestScreenedDelimitersSplit);
+ UNIT_TEST(TestSubstringDelimiter);
+ UNIT_TEST_SUITE_END();
+
+public:
+ void TestDelimiters();
+ void TestDelimitersSplit();
+ void TestDelimitersStrictSplit();
+ void TestTail();
+ void TestScreenedDelimitersSplit();
+ void TestSubstringDelimiter();
+};
+
+void TSplitIteratorTest::TestDelimiters() {
+ TSplitDelimiters delims("@");
+ for (int i = 0; i < 256; ++i)
+ if ('@' != i) {
+ UNIT_ASSERT(!delims.IsDelimiter((ui8)i));
+ } else {
+ UNIT_ASSERT(delims.IsDelimiter((ui8)i));
+ }
+}
+
+void TSplitIteratorTest::TestDelimitersSplit() {
+ {
+ TString s = "1a3b45cd";
+ TSplitDelimiters delims("abcd");
+ TDelimitersSplit split(s, delims);
+ TSplitTokens tokens;
+ Split(split, &tokens);
+ TSplitTokens pattern = {"1", "3", "45"};
+ UNIT_ASSERT(tokens == pattern);
+ }
+ {
+ TString s = "aaaaaa";
+ TSplitDelimiters delims("abcd");
+ TDelimitersSplit split(s, delims);
+ TSplitTokens tokens;
+ Split(split, &tokens);
+ TSplitTokens pattern = {};
+ UNIT_ASSERT(tokens == pattern);
+ }
+}
+
+void TSplitIteratorTest::TestDelimitersStrictSplit() {
+ {
+ TString s = "grp@2";
+ TSplitDelimiters delims("@");
+ TDelimitersStrictSplit split(s, delims);
+ TSplitTokens tokens;
+ Split(split, &tokens);
+ TSplitTokens pattern = {"grp", "2"};
+ UNIT_ASSERT(tokens == pattern);
+ }
+
+ {
+ TString s = "@grp@2@@";
+ TSplitDelimiters delims("@");
+ TDelimitersStrictSplit split(s, delims);
+ TSplitTokens tokens;
+ Split(split, &tokens);
+ TSplitTokens pattern = {"", "grp", "2", ""};
+ UNIT_ASSERT(tokens == pattern);
+ }
+}
+
+void TSplitIteratorTest::TestTail() {
+ TString s = "grp@2@4";
+ TSplitDelimiters delims("@");
+ TDelimitersSplit split(s, delims);
+ TDelimitersSplit::TIterator it = split.Iterator();
+ UNIT_ASSERT_EQUAL(it.GetTail(), "grp@2@4");
+ it.Next();
+ UNIT_ASSERT_EQUAL(it.GetTail(), "2@4");
+ it.Next();
+ UNIT_ASSERT_EQUAL(it.GetTail(), "4");
+ it.Next();
+ UNIT_ASSERT_EQUAL(it.GetTail(), "");
+}
+
+void TSplitIteratorTest::TestScreenedDelimitersSplit() {
+ {
+ const TString s = "77.88.58.91 - - [28/Aug/2008:00:08:07 +0400] \"GET /export/mordashka.tgz HTTP/1.1\" 304 - \"-\" \"libwww-perl/5.805\" \"news.yandex.ru,80\" \"-\" \"-\" 1219867687 \"0\" 3283 2";
+ const TSplitDelimiters delims(" ");
+ const TSplitDelimiters screens("\"[]");
+ const TScreenedDelimitersSplit splitter(s, delims, screens);
+ TScreenedDelimitersSplit::TIterator it = splitter.Iterator();
+ UNIT_ASSERT_EQUAL(it.NextString(), "77.88.58.91");
+ UNIT_ASSERT_EQUAL(it.NextString(), "-");
+ UNIT_ASSERT_EQUAL(it.NextString(), "-");
+ UNIT_ASSERT_EQUAL(it.NextString(), "[28/Aug/2008:00:08:07 +0400]");
+ UNIT_ASSERT_EQUAL(it.NextString(), "\"GET /export/mordashka.tgz HTTP/1.1\"");
+ UNIT_ASSERT_EQUAL(it.NextString(), "304");
+ UNIT_ASSERT_EQUAL(it.NextString(), "-");
+ UNIT_ASSERT_EQUAL(it.NextString(), "\"-\"");
+ UNIT_ASSERT_EQUAL(it.NextString(), "\"libwww-perl/5.805\"");
+ UNIT_ASSERT_EQUAL(it.NextString(), "\"news.yandex.ru,80\"");
+ UNIT_ASSERT_EQUAL(it.NextString(), "\"-\"");
+ UNIT_ASSERT_EQUAL(it.NextString(), "\"-\"");
+ UNIT_ASSERT_EQUAL(it.NextString(), "1219867687");
+ UNIT_ASSERT_EQUAL(it.NextString(), "\"0\"");
+ UNIT_ASSERT_EQUAL(it.NextString(), "3283");
+ UNIT_ASSERT_EQUAL(it.NextString(), "2");
+ }
+ {
+ const TString s = "77.88.58.91 - - [28/Aug/2008:00:08:07 +0400] \"GET /export/mordashka.tgz HTTP/1.1\" 304 - \"-\" \"libwww-perl/5.805\" \"news.yandex.ru,80\" \"-\" \"-\" 1219867687 \"0\" 3283 2";
+ const TSplitDelimiters delims(" ");
+ const TSplitDelimiters screens("\"[]");
+ const TScreenedDelimitersSplit splitter(s.Data(), s.Size(), delims, screens);
+ TScreenedDelimitersSplit::TIterator it = splitter.Iterator();
+ UNIT_ASSERT_EQUAL(it.NextString(), "77.88.58.91");
+ UNIT_ASSERT_EQUAL(it.NextString(), "-");
+ UNIT_ASSERT_EQUAL(it.NextString(), "-");
+ UNIT_ASSERT_EQUAL(it.NextString(), "[28/Aug/2008:00:08:07 +0400]");
+ UNIT_ASSERT_EQUAL(it.NextString(), "\"GET /export/mordashka.tgz HTTP/1.1\"");
+ UNIT_ASSERT_EQUAL(it.NextString(), "304");
+ UNIT_ASSERT_EQUAL(it.NextString(), "-");
+ UNIT_ASSERT_EQUAL(it.NextString(), "\"-\"");
+ UNIT_ASSERT_EQUAL(it.NextString(), "\"libwww-perl/5.805\"");
+ UNIT_ASSERT_EQUAL(it.NextString(), "\"news.yandex.ru,80\"");
+ UNIT_ASSERT_EQUAL(it.NextString(), "\"-\"");
+ UNIT_ASSERT_EQUAL(it.NextString(), "\"-\"");
+ UNIT_ASSERT_EQUAL(it.NextString(), "1219867687");
+ UNIT_ASSERT_EQUAL(it.NextString(), "\"0\"");
+ UNIT_ASSERT_EQUAL(it.NextString(), "3283");
+ UNIT_ASSERT_EQUAL(it.NextString(), "2");
+ }
+}
+
+void TSplitIteratorTest::TestSubstringDelimiter() {
+ const TString s = "a@@bb@@cc@c.d@@r";
+ static const TSubstringSplitDelimiter delimiter("@@");
+ const TSubstringSplit splitter(s, delimiter);
+ TSubstringSplit::TIterator it = splitter.Iterator();
+ UNIT_ASSERT_EQUAL(it.NextString(), "a");
+ UNIT_ASSERT_EQUAL(it.NextString(), "bb");
+ UNIT_ASSERT_EQUAL(it.NextString(), "cc@c.d");
+ UNIT_ASSERT_EQUAL(it.NextString(), "r");
+ UNIT_ASSERT(it.Eof());
+}
+
+UNIT_TEST_SUITE_REGISTRATION(TSplitIteratorTest);
diff --git a/library/cpp/deprecated/split/ya.make b/library/cpp/deprecated/split/ya.make
new file mode 100644
index 0000000000..946e685ac8
--- /dev/null
+++ b/library/cpp/deprecated/split/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+OWNER(wrg0ababd)
+
+SRCS(
+ delim_string_iter.cpp
+ split_iterator.cpp
+)
+
+PEERDIR(
+ library/cpp/deprecated/kmp
+)
+
+END()
diff --git a/library/cpp/deprecated/ya.make b/library/cpp/deprecated/ya.make
new file mode 100644
index 0000000000..6c753f68a9
--- /dev/null
+++ b/library/cpp/deprecated/ya.make
@@ -0,0 +1,49 @@
+RECURSE(
+ abstract_iterator
+ abstract_iterator/ut
+ accessors
+ accessors/ut
+ autoarray
+ base64
+ datafile
+ dater_old
+ dater_old/ut
+ enum_codegen
+ enum_codegen/ut
+ fgood
+ fgood/ut
+ histogram
+ ipreg1
+ ipreg1/ut
+ ipreg1/ut_full
+ ipreg1/util
+ iter
+ kmp
+ kmp/ut
+ mapped_file
+ mapped_file/ut
+ mbitmap
+ omni
+ text_norm
+ omni/print_omni
+ omni/usage
+ omni/ut
+ prog_options
+ prog_options/ut
+ sgi_hash
+ threadable
+ transgene
+ datawork
+ datawork/conf
+ calc_module
+ iterators_heap
+ parse_utils
+ parse_utils/ut
+ small_array
+ solartrie
+ solartrie/indexed_region/ut
+ solartrie/test
+ solartrie/test/tests
+ solartrie/ut
+ split
+)
diff --git a/library/cpp/diff/README.md b/library/cpp/diff/README.md
new file mode 100644
index 0000000000..ff68b10eae
--- /dev/null
+++ b/library/cpp/diff/README.md
@@ -0,0 +1 @@
+Note: underlying algorithm `library/cpp/lcs` has complexity of O(r log n) by time and O(r) of additional memory, where r is the number of pairs (i, j) for which S1[i] = S2[j]. When comparing file with itself (or with little modifications) it becomes quadratic on the number of occurences of the most frequent line.
diff --git a/library/cpp/diff/diff.cpp b/library/cpp/diff/diff.cpp
new file mode 100644
index 0000000000..be57da7f39
--- /dev/null
+++ b/library/cpp/diff/diff.cpp
@@ -0,0 +1,87 @@
+#include "diff.h"
+
+#include <util/generic/hash.h>
+#include <util/digest/fnv.h>
+
+#include <iterator>
+
+template <typename T>
+struct TCollectionImpl {
+ TVector<TConstArrayRef<T>> Words;
+ TVector<ui64> Keys;
+
+ inline bool Consume(const T* b, const T* e, const T*) {
+ if (b < e) {
+ Words.push_back(TConstArrayRef<T>(b, e));
+ Keys.push_back(FnvHash<ui64>((const char*)b, (e - b) * sizeof(T)));
+ }
+ return true;
+ }
+
+ TConstArrayRef<T> Remap(const TConstArrayRef<ui64>& keys) const {
+ if (keys.empty()) {
+ return TConstArrayRef<T>();
+ }
+ auto firstWordPos = std::distance(Keys.data(), keys.begin());
+ auto lastWordPos = std::distance(Keys.data(), keys.end()) - 1;
+ Y_ASSERT(firstWordPos >= 0);
+ Y_ASSERT(lastWordPos >= firstWordPos);
+ Y_ASSERT(static_cast<size_t>(lastWordPos) < Words.size());
+
+ return TConstArrayRef<T>(Words[firstWordPos].begin(), Words[lastWordPos].end());
+ }
+
+ TConstArrayRef<ui64> GetKeys() const {
+ return TConstArrayRef<ui64>(Keys);
+ }
+};
+
+template <typename T>
+struct TCollection {
+};
+
+template <>
+struct TCollection<char>: public TCollectionImpl<char> {
+ TCollection(const TStringBuf& str, const TString& delims) {
+ TSetDelimiter<const char> set(delims.data());
+ TKeepDelimiters<TCollection<char>> c(this);
+ SplitString(str.begin(), str.end(), set, c);
+ }
+};
+
+template <>
+struct TCollection<wchar16>: public TCollectionImpl<wchar16> {
+ TCollection(const TWtringBuf& str, const TUtf16String& delims) {
+ TSetDelimiter<const wchar16> set(delims.data());
+ TKeepDelimiters<TCollection<wchar16>> c(this);
+ SplitString(str.begin(), str.end(), set, c);
+ }
+};
+
+size_t NDiff::InlineDiff(TVector<TChunk<char>>& chunks, const TStringBuf& left, const TStringBuf& right, const TString& delims) {
+ if (delims.empty()) {
+ return InlineDiff<char>(chunks, TConstArrayRef<char>(left.data(), left.size()), TConstArrayRef<char>(right.data(), right.size()));
+ }
+ TCollection<char> c1(left, delims);
+ TCollection<char> c2(right, delims);
+ TVector<TChunk<ui64>> diff;
+ const size_t dist = InlineDiff<ui64>(diff, c1.GetKeys(), c2.GetKeys());
+ for (const auto& it : diff) {
+ chunks.push_back(TChunk<char>(c1.Remap(it.Left), c2.Remap(it.Right), c1.Remap(it.Common)));
+ }
+ return dist;
+}
+
+size_t NDiff::InlineDiff(TVector<TChunk<wchar16>>& chunks, const TWtringBuf& left, const TWtringBuf& right, const TUtf16String& delims) {
+ if (delims.empty()) {
+ return InlineDiff<wchar16>(chunks, TConstArrayRef<wchar16>(left.data(), left.size()), TConstArrayRef<wchar16>(right.data(), right.size()));
+ }
+ TCollection<wchar16> c1(left, delims);
+ TCollection<wchar16> c2(right, delims);
+ TVector<TChunk<ui64>> diff;
+ const size_t dist = InlineDiff<ui64>(diff, c1.GetKeys(), c2.GetKeys());
+ for (const auto& it : diff) {
+ chunks.push_back(TChunk<wchar16>(c1.Remap(it.Left), c2.Remap(it.Right), c1.Remap(it.Common)));
+ }
+ return dist;
+}
diff --git a/library/cpp/diff/diff.h b/library/cpp/diff/diff.h
new file mode 100644
index 0000000000..94fb00cd0b
--- /dev/null
+++ b/library/cpp/diff/diff.h
@@ -0,0 +1,112 @@
+#pragma once
+
+#include <library/cpp/lcs/lcs_via_lis.h>
+
+#include <util/generic/algorithm.h>
+#include <util/generic/array_ref.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/vector.h>
+#include <util/stream/output.h>
+#include <util/string/split.h>
+
+namespace NDiff {
+ template <typename T>
+ struct TChunk {
+ TConstArrayRef<T> Left;
+ TConstArrayRef<T> Right;
+ TConstArrayRef<T> Common;
+
+ TChunk() = default;
+
+ TChunk(const TConstArrayRef<T>& left, const TConstArrayRef<T>& right, const TConstArrayRef<T>& common)
+ : Left(left)
+ , Right(right)
+ , Common(common)
+ {
+ }
+ };
+
+ template <typename T>
+ size_t InlineDiff(TVector<TChunk<T>>& chunks, const TConstArrayRef<T>& left, const TConstArrayRef<T>& right) {
+ TConstArrayRef<T> s1(left);
+ TConstArrayRef<T> s2(right);
+
+ bool swapped = false;
+ if (s1.size() < s2.size()) {
+ // NLCS will silently swap strings if second string is longer
+ // So we swap strings here and remember the fact since it is crucial to diff
+ DoSwap(s1, s2);
+ swapped = true;
+ }
+
+ TVector<T> lcs;
+ NLCS::TLCSCtx<T> ctx;
+ NLCS::MakeLCS<T>(s1, s2, &lcs, &ctx);
+
+ // Start points of current common and diff parts
+ const T* c1 = nullptr;
+ const T* c2 = nullptr;
+ const T* d1 = s1.begin();
+ const T* d2 = s2.begin();
+
+ // End points of current common parts
+ const T* e1 = s1.begin();
+ const T* e2 = s2.begin();
+
+ size_t dist = s1.size() - lcs.size();
+
+ const size_t n = ctx.ResultBuffer.size();
+ for (size_t i = 0; i <= n && (e1 != s1.end() || e2 != s2.end());) {
+ if (i < n) {
+ // Common character exists
+ // LCS is marked against positions in s2
+ // Save the beginning of common part in s2
+ c2 = s2.begin() + ctx.ResultBuffer[i];
+ // Find the beginning of common part in s1
+ c1 = Find(e1, s1.end(), *c2);
+ // Follow common substring
+ for (e1 = c1, e2 = c2; i < n && *e1 == *e2; ++e1, ++e2) {
+ ++i;
+ }
+ } else {
+ // No common character, common part is empty
+ c1 = s1.end();
+ c2 = s2.end();
+ e1 = s1.end();
+ e2 = s2.end();
+ }
+
+ TChunk<T> chunk(TConstArrayRef<T>(d1, c1), TConstArrayRef<T>(d2, c2), TConstArrayRef<T>(c1, e1));
+ if (swapped) {
+ DoSwap(chunk.Left, chunk.Right);
+ chunk.Common = TConstArrayRef<T>(c2, e2);
+ }
+ chunks.push_back(chunk);
+
+ d1 = e1;
+ d2 = e2;
+ }
+
+ return dist;
+ }
+
+ template <typename TFormatter, typename T>
+ void PrintChunks(IOutputStream& out, const TFormatter& fmt, const TVector<TChunk<T>>& chunks) {
+ for (typename TVector<TChunk<T>>::const_iterator chunk = chunks.begin(); chunk != chunks.end(); ++chunk) {
+ if (!chunk->Left.empty() || !chunk->Right.empty()) {
+ out << fmt.Special("(");
+ out << fmt.Left(chunk->Left);
+ out << fmt.Special("|");
+ out << fmt.Right(chunk->Right);
+ out << fmt.Special(")");
+ }
+ out << fmt.Common(chunk->Common);
+ }
+ }
+
+ // Without delimiters calculates character-wise diff
+ // With delimiters calculates token-wise diff
+ size_t InlineDiff(TVector<TChunk<char>>& chunks, const TStringBuf& left, const TStringBuf& right, const TString& delims = TString());
+ size_t InlineDiff(TVector<TChunk<wchar16>>& chunks, const TWtringBuf& left, const TWtringBuf& right, const TUtf16String& delims = TUtf16String());
+
+}
diff --git a/library/cpp/diff/diff_ut.cpp b/library/cpp/diff/diff_ut.cpp
new file mode 100644
index 0000000000..b82a7b000e
--- /dev/null
+++ b/library/cpp/diff/diff_ut.cpp
@@ -0,0 +1,197 @@
+#include "diff.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NDiff;
+
+struct TDiffTester {
+ TStringStream Res;
+ TVector<TChunk<char>> Chunks;
+
+ TStringBuf Special(const TStringBuf& str) const {
+ return str;
+ }
+
+ TStringBuf Common(const TConstArrayRef<const char>& str) const {
+ return TStringBuf(str.begin(), str.end());
+ }
+
+ TStringBuf Left(const TConstArrayRef<const char>& str) const {
+ return TStringBuf(str.begin(), str.end());
+ }
+
+ TStringBuf Right(const TConstArrayRef<const char>& str) const {
+ return TStringBuf(str.begin(), str.end());
+ }
+
+ void Test(const TStringBuf& a, const TStringBuf& b, const TString& delims = " \t\n") {
+ Chunks.clear();
+ InlineDiff(Chunks, a, b, delims);
+ Res.clear();
+ PrintChunks(Res, *this, Chunks);
+ }
+
+ const TString& Result() const {
+ return Res.Str();
+ }
+};
+
+Y_UNIT_TEST_SUITE(DiffTokens) {
+ Y_UNIT_TEST(ReturnValue) {
+ TVector<TChunk<char>> res;
+ UNIT_ASSERT_VALUES_EQUAL(InlineDiff(res, "aaa", "aaa"), 0);
+ UNIT_ASSERT_VALUES_EQUAL(InlineDiff(res, "aaa", "aa"), 1);
+ UNIT_ASSERT_VALUES_EQUAL(InlineDiff(res, "aaa", "a"), 2);
+ UNIT_ASSERT_VALUES_EQUAL(InlineDiff(res, "aaa", "abc"), 2);
+ UNIT_ASSERT_VALUES_EQUAL(InlineDiff(res, "aaa", "aba"), 1);
+ UNIT_ASSERT_VALUES_EQUAL(InlineDiff(res, "", "aba"), 3);
+ UNIT_ASSERT_VALUES_EQUAL(InlineDiff(res, "aaa", "aaaa"), 1);
+ UNIT_ASSERT_VALUES_EQUAL(InlineDiff(res, "abc", "xyz"), 3);
+ }
+
+ Y_UNIT_TEST(EqualStringsOneToken) {
+ TDiffTester tester;
+
+ tester.Test("aaa", "aaa");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "aaa");
+ }
+
+ Y_UNIT_TEST(NonCrossingStringsOneToken) {
+ TDiffTester tester;
+
+ tester.Test("aaa", "bbb");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "(aaa|bbb)");
+
+ tester.Test("aaa", "bbbb");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "(aaa|bbbb)");
+ }
+
+ Y_UNIT_TEST(Simple) {
+ TDiffTester tester;
+
+ tester.Test("aaa", "abb", "");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "a(aa|bb)");
+
+ tester.Test("aac", "abc", "");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "a(a|b)c");
+
+ tester.Test("123", "133", "");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "1(2|3)3");
+
+ tester.Test("[1, 2, 3]", "[1, 3, 3]", "");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "[1, (2|3), 3]");
+ }
+
+ Y_UNIT_TEST(CommonCharOneToken) {
+ TDiffTester tester;
+
+ tester.Test("abcde", "accfg");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "(abcde|accfg)");
+ }
+
+ Y_UNIT_TEST(EqualStringsTwoTokens) {
+ TDiffTester tester;
+
+ TStringBuf str("aaa bbb");
+ tester.Test(str, str);
+
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "aaa bbb");
+ }
+
+ Y_UNIT_TEST(NonCrossingStringsTwoTokens) {
+ TDiffTester tester;
+
+ tester.Test("aaa bbb", "ccc ddd");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "(aaa|ccc) (bbb|ddd)");
+
+ tester.Test("aaa bbb", "c d");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "(aaa|c) (bbb|d)");
+ }
+
+ Y_UNIT_TEST(SimpleTwoTokens) {
+ TDiffTester tester;
+
+ tester.Test("aaa ccd", "abb cce");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "(aaa|abb) (ccd|cce)");
+
+ tester.Test("aac cbb", "aa bb");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "(aac|aa) (cbb|bb)");
+ }
+
+ Y_UNIT_TEST(MixedTwoTokens) {
+ TDiffTester tester;
+
+ tester.Test("aaa bbb", "bbb aaa");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "(|bbb )aaa( bbb|)");
+
+ tester.Test("aaa bbb", " bbb aaa");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "(aaa|) bbb(| aaa)");
+
+ tester.Test(" aaa bbb ", " bbb aaa ");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "(| bbb) aaa (bbb |)");
+
+ tester.Test("aaa bb", " bbb aa");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "(aaa|) (bb|bbb aa)");
+ }
+
+ Y_UNIT_TEST(TwoTokensInOneString) {
+ TDiffTester tester;
+
+ tester.Test("aaa bbb", "aaa");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "aaa( bbb|)");
+
+ tester.Test("aaa bbb", "aaa ");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "aaa (bbb|)");
+
+ tester.Test("aaa bbb", " bbb");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "(aaa|) bbb");
+
+ tester.Test("aaa bbb", "bbb");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "(aaa |)bbb");
+ }
+
+ Y_UNIT_TEST(Multiline) {
+ TDiffTester tester;
+
+ tester.Test("aaa\nabc\nbbb", "aaa\nacc\nbbb");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "aaa\n(abc|acc)\nbbb");
+
+ tester.Test("aaa\nabc\nbbb", "aaa\nac\nbbb");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "aaa\n(abc|ac)\nbbb");
+ }
+
+ Y_UNIT_TEST(DifferentDelimiters) {
+ TDiffTester tester;
+
+ tester.Test("aaa bbb", "aaa\tbbb");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "aaa( |\t)bbb");
+
+ tester.Test(" aaa\tbbb\n", "\taaa\nbbb ");
+ //~ Cerr << tester.Result() << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(tester.Result(), "( |\t)aaa(\t|\n)bbb(\n| )");
+ }
+}
diff --git a/library/cpp/diff/ut/ya.make b/library/cpp/diff/ut/ya.make
new file mode 100644
index 0000000000..360134d186
--- /dev/null
+++ b/library/cpp/diff/ut/ya.make
@@ -0,0 +1,15 @@
+UNITTEST()
+
+OWNER(antonovvk)
+
+SRCDIR(library/cpp/diff)
+
+PEERDIR(
+ library/cpp/diff
+)
+
+SRCS(
+ diff_ut.cpp
+)
+
+END()
diff --git a/library/cpp/diff/ya.make b/library/cpp/diff/ya.make
new file mode 100644
index 0000000000..a05b7ccbbc
--- /dev/null
+++ b/library/cpp/diff/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+OWNER(antonovvk)
+
+PEERDIR(
+ library/cpp/lcs
+ library/cpp/containers/stack_array
+)
+
+SRCS(
+ diff.cpp
+)
+
+END()
diff --git a/library/cpp/digest/argonish/AUTHORS b/library/cpp/digest/argonish/AUTHORS
new file mode 100644
index 0000000000..608109b6da
--- /dev/null
+++ b/library/cpp/digest/argonish/AUTHORS
@@ -0,0 +1,3 @@
+The following authors have created the source code of "Argonish" published and distributed by YANDEX LLC as the owner:
+
+Evgeny Sidorov <e-sidorov@yandex-team.ru>
diff --git a/library/cpp/digest/argonish/CONTRIBUTING.md b/library/cpp/digest/argonish/CONTRIBUTING.md
new file mode 100644
index 0000000000..9ebd417e21
--- /dev/null
+++ b/library/cpp/digest/argonish/CONTRIBUTING.md
@@ -0,0 +1,35 @@
+# Notice to external contributors
+
+
+## General info
+
+Hello! In order for us (YANDEX LLC) to accept patches and other contributions from you, you will have to adopt our Yandex Contributor License Agreement (the “**CLA**”). The current version of the CLA you may find here:
+1) https://yandex.ru/legal/cla/?lang=en (in English) and
+2) https://yandex.ru/legal/cla/?lang=ru (in Russian).
+
+By adopting the CLA, you state the following:
+
+* You obviously wish and are willingly licensing your contributions to us for our open source projects under the terms of the CLA,
+* You has read the terms and conditions of the CLA and agree with them in full,
+* You are legally able to provide and license your contributions as stated,
+* We may use your contributions for our open source projects and for any other our project too,
+* We rely on your assurances concerning the rights of third parties in relation to your contributes.
+
+If you agree with these principles, please read and adopt our CLA. By providing us your contributions, you hereby declare that you has already read and adopt our CLA, and we may freely merge your contributions with our corresponding open source project and use it in further in accordance with terms and conditions of the CLA.
+
+## Provide contributions
+
+If you have already adopted terms and conditions of the CLA, you are able to provide your contributes. When you submit your pull request, please add the following information into it:
+
+```
+I hereby agree to the terms of the CLA available at: [link].
+```
+
+Replace the bracketed text as follows:
+* [link] is the link at the current version of the CLA (you may add here a link https://yandex.ru/legal/cla/?lang=en (in English) or a link https://yandex.ru/legal/cla/?lang=ru (in Russian).
+
+It is enough to provide us such notification at once.
+
+## Other questions
+
+If you have any questions, please mail us at opensource@yandex-team.ru.
diff --git a/library/cpp/digest/argonish/LICENSE b/library/cpp/digest/argonish/LICENSE
new file mode 100644
index 0000000000..67fc7b16f8
--- /dev/null
+++ b/library/cpp/digest/argonish/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2017, YANDEX LLC
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and
+the following disclaimer.
+
+2. 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.
+
+3. Neither the name of the copyright holder 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 HOLDER 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/library/cpp/digest/argonish/README.md b/library/cpp/digest/argonish/README.md
new file mode 100644
index 0000000000..7b3ae79cca
--- /dev/null
+++ b/library/cpp/digest/argonish/README.md
@@ -0,0 +1,74 @@
+Argonish
+--------
+
+Implementation of argon2 (i, d, id) algorithms with CPU dispatching. The list of features includes:
+* C++14 interface
+* constexpr and partial templates to get rid of useless branches (give +2% to performance)
+* AVX2 implementation of Argon2 (allows to gain +30..40% to performance)
+* Vectorized Blake2B implementation (including AVX2 version)
+* OpenMP for multithreading in contrast to pthread in the reference implementation
+
+Acknowledgements
+----------------
+
+This project uses some ideas and pieces of code from the following projects licensed under CC0:
+* https://github.com/P-H-C/phc-winner-argon2
+* https://github.com/BLAKE2/BLAKE2
+
+I'm also thankful to the following people whose fruitful feedback improved the project:
+* Igor Klevanets (cerevra@yandex-team.ru)
+
+Benchmark results
+-----------------
+
+On my OS X 10.11, MacBook Pro (Early 2015, Core i5 2,7 GHz, 16 GB 1867 MHz DDR3) for `(Argon2d, 1, 2048, 1)` it gives:
+
+```
+---- REF ----
+Num | Count | Time
+0 | 4555 | 9.93424
+1 | 4556 | 9.94529
+---- SSE2 ---
+Num | Count | Time
+0 | 6606 | 9.93117
+1 | 6594 | 9.93259
+--- SSSE3 ---
+Num | Count | Time
+0 | 7393 | 9.93866
+1 | 7392 | 9.94874
+--- SSE41 ---
+Num | Count | Time
+0 | 7152 | 9.88648
+1 | 7112 | 9.87276
+-----AVX2----
+Num | Count | Time
+0 | 11120 | 9.9273
+1 | 11138 | 9.94308
+```
+
+How to use
+----------
+
+```
+#include <library/cpp/digest/argonish/argon2.h>
+...
+uint32_t tcost = 1; /* one pass */
+uint32_t mcost = 32; /* in KB */
+uint32_t threads = 1; /* one thread version */
+NArgonish::TArgon2Factory afactory;
+THolder<NArgonish::IArgon2Base> argon2 = afactory.Create(NArgonish::EArgon2Type::Argon2d, tcost, mcost, threads);
+argon2->Hash(input, insize, salt, saltsize, out, outlen);
+...
+#include <library/cpp/digest/argonish/blake2b.h>
+...
+NArgonish::TBlake2BFactory bfactory;
+uint32_t outlen = 32;
+THolder<NArgonish::IBlake2Base> blake2b = bfactory.Create(outlen);
+blake2b->Update(in, inlen);
+blake2b->Final(out, outlen);
+```
+
+How to add your own Argon2 configuration
+----------------------------------------
+
+Just modify the `internal/proxy/macro/proxy_macros.h` and add appropriate `ARGON2_INSTANCE_DECL` declaration.
diff --git a/library/cpp/digest/argonish/argon2.h b/library/cpp/digest/argonish/argon2.h
new file mode 100644
index 0000000000..bbe8ad52f3
--- /dev/null
+++ b/library/cpp/digest/argonish/argon2.h
@@ -0,0 +1,147 @@
+#pragma once
+
+#include "common.h"
+
+#include <util/generic/ptr.h>
+#include <util/system/defaults.h>
+
+namespace NArgonish {
+ /**
+ * Type of Argon2 algorithm
+ */
+ enum class EArgon2Type : ui32 {
+ Argon2d = 0, /// Data dependent version of Argon2
+ Argon2i = 1, /// Data independent version of Argon2
+ Argon2id = 2 /// Mixed version of Argon2
+ };
+
+ /**
+ * Interface of all Argon2 instances
+ */
+ class IArgon2Base {
+ public:
+ virtual ~IArgon2Base() {
+ }
+ /**
+ * Applies Argon2 algorithm
+ * @param pwd password
+ * @param pwdlen password length
+ * @param salt salt
+ * @param saltlen salt length
+ * @param out output
+ * @param outlen output length
+ * @param aad additional authenticated data (optional)
+ * @param aadlen additional authenticated data length (optional)
+ */
+ virtual void Hash(const ui8* pwd, ui32 pwdlen, const ui8* salt, ui32 saltlen,
+ ui8* out, ui32 outlen, const ui8* aad = nullptr, ui32 aadlen = 0) const = 0;
+
+ /**
+ * Applies Argon2 algorithm to a password and compares the result with the hash data
+ * @param pwd password
+ * @param pwdlen password length
+ * @param salt salt
+ * @param saltlen salt length
+ * @param hash hash value to compare with the result
+ * @param hashlen hash value length
+ * @param aad additional authenticated data (optional)
+ * @param adadlen additional authenticated data length (optional)
+ * @return true if the Argon2 result equals to the value in hash
+ */
+ virtual bool Verify(const ui8* pwd, ui32 pwdlen, const ui8* salt, ui32 saltlen,
+ const ui8* hash, ui32 hashlen, const ui8* aad = nullptr, ui32 adadlen = 0) const = 0;
+
+ /**
+ * Applies Argon2 algorithms but allows to pass memory buffer for work.
+ * This allows to use external memory allocator or reuse already allocated memory buffer.
+ * @param memory memory buffer for Argon2 calculations
+ * @param mlen memory buffer len (must be at least the value returned by the GetMemorySize method)
+ * @param pwd password to hash
+ * @param pwdlen password length
+ * @param salt salt
+ * @param saltlen salt length
+ * @param out output buffer
+ * @param outlen output length
+ * @param aad additional authenticated data (optional)
+ * @param aadlen additional authenticated data length (optional)
+ */
+ virtual void HashWithCustomMemory(ui8* memory, size_t mlen, const ui8* pwd, ui32 pwdlen,
+ const ui8* salt, ui32 saltlen, ui8* out, ui32 outlen,
+ const ui8* aad = nullptr, ui32 aadlen = 0) const = 0;
+ /**
+ * Applies Argon2 algorithm to a password and compares the result with the hash data.
+ * This method allows to use a custom memory allocator or reuse already allocated memory buffer.
+ * @param memory memory buffer for Argon2 calculations
+ * @param mlen memory buffer length
+ * @param pwd password to hash
+ * @param pwdlen password length
+ * @param salt salt
+ * @param saltlen salt length
+ * @param hash hash value to compare with the result
+ * @param hashlen hash value length
+ * @param aad additional authenticated data (optional)
+ * @param aadlen additional authenticated data length (optional)
+ * @return true if the Argon2 result equals to the value in hash
+ */
+ virtual bool VerifyWithCustomMemory(ui8* memory, size_t mlen, const ui8* pwd, ui32 pwdlen,
+ const ui8* salt, ui32 saltlen, const ui8* hash, ui32 hashlen,
+ const ui8* aad = nullptr, ui32 aadlen = 0) const = 0;
+
+ /**
+ * The function calculates the size of memory required by Argon2 algorithm
+ * @return memory buffer size
+ */
+ virtual size_t GetMemorySize() const = 0;
+ };
+
+ /**
+ * A factory to create Argon2 instances depending on instruction set, tcost, mcost, the number of threads etc.
+ */
+ class TArgon2Factory {
+ public:
+ /**
+ * Constructs a factory object
+ * @param skipTest if true then a simple runtime test will be skipped in the constructor (optional)
+ */
+ TArgon2Factory(bool skipTest = false);
+
+ /**
+ * Creates an instance of Argon2 algorithm.
+ * The particular optimization is chosen automatically based on the cpuid instruction output.
+ * @param atype the type of Argon2 algorithm
+ * @param tcost the number of passes over memory block, must be at least 1
+ * @param mcost the size in kilobytes of memory block used by Argon2
+ * @param threads the number of threads for parallel version of Argon2 (must be 1,2 or 4)
+ * @param key a secret key to use for password hashing (optional)
+ * @param keylen the length of the key (optional)
+ * @return unique_ptr to Argon2 instance. In case of error std::runtime_excetion is thrown
+ */
+ THolder<IArgon2Base> Create(EArgon2Type atype = EArgon2Type::Argon2d, ui32 tcost = 1, ui32 mcost = 1024,
+ ui32 threads = 1, const ui8* key = nullptr, ui32 keylen = 0) const;
+
+ /**
+ * Creates an instance of Argon2 algorithm optimized for the provided instruction set
+ * @param instructionSet instruction set
+ * @param atype the type of Argon2 algorithm
+ * @param tcost the number of passes over memory block, must be at least 1
+ * @param mcost the size in kilobytes of memory block used by Argon2
+ * @param threads the number of threads for parallel version of Argon2 (must be 1,2 or 4)
+ * @param key a secret key to use for password hashing (optional)
+ * @param keylen the length of the key (optional)
+ * @return unique_ptr to Argon2 instance. In case of error std::runtime_excetion is thrown
+ */
+ THolder<IArgon2Base> Create(EInstructionSet instructionSet, EArgon2Type atype = EArgon2Type::Argon2d, ui32 tcost = 1,
+ ui32 mcost = 1024, ui32 threads = 1, const ui8* key = nullptr,
+ ui32 keylen = 0) const;
+
+ /**
+ * The function returns the best instruction set available on the current CPU
+ * @return InstructionSet value
+ */
+ EInstructionSet GetInstructionSet() const;
+
+ protected:
+ EInstructionSet InstructionSet_ = EInstructionSet::REF;
+ void QuickTest_() const;
+ };
+}
diff --git a/library/cpp/digest/argonish/benchmark/mbench.cpp b/library/cpp/digest/argonish/benchmark/mbench.cpp
new file mode 100644
index 0000000000..178c1169c9
--- /dev/null
+++ b/library/cpp/digest/argonish/benchmark/mbench.cpp
@@ -0,0 +1,64 @@
+#include <library/cpp/testing/benchmark/bench.h>
+#include <library/cpp/digest/argonish/argon2.h>
+
+Y_CPU_BENCHMARK(Argon2d_2048_REF, iface) {
+ NArgonish::TArgon2Factory factory;
+ auto argon2 = factory.Create(NArgonish::EInstructionSet::REF, NArgonish::EArgon2Type::Argon2d, 1, 2048, 1);
+ ui8 password[16] = {0x0};
+ ui8 salt[16] = {0x01};
+ ui8 result[16] = {0};
+
+ for (ui64 i = 0; i < iface.Iterations(); ++i) {
+ argon2->Hash(password, sizeof(password), salt, sizeof(salt), result, sizeof(result));
+ }
+}
+
+#if !defined(_arm64_)
+Y_CPU_BENCHMARK(Argon2d_2048_SSE2, iface) {
+ NArgonish::TArgon2Factory factory;
+ auto argon2 = factory.Create(NArgonish::EInstructionSet::SSE2, NArgonish::EArgon2Type::Argon2d, 1, 2048, 1);
+ ui8 password[16] = {0x0};
+ ui8 salt[16] = {0x01};
+ ui8 result[16] = {0};
+
+ for (ui64 i = 0; i < iface.Iterations(); ++i) {
+ argon2->Hash(password, sizeof(password), salt, sizeof(salt), result, sizeof(result));
+ }
+}
+
+Y_CPU_BENCHMARK(Argon2d_2048_SSSE3, iface) {
+ NArgonish::TArgon2Factory factory;
+ auto argon2 = factory.Create(NArgonish::EInstructionSet::SSSE3, NArgonish::EArgon2Type::Argon2d, 1, 2048, 1);
+ ui8 password[16] = {0x0};
+ ui8 salt[16] = {0x01};
+ ui8 result[16] = {0};
+
+ for (ui64 i = 0; i < iface.Iterations(); ++i) {
+ argon2->Hash(password, sizeof(password), salt, sizeof(salt), result, sizeof(result));
+ }
+}
+
+Y_CPU_BENCHMARK(Argon2d_2048_SSE41, iface) {
+ NArgonish::TArgon2Factory factory;
+ auto argon2 = factory.Create(NArgonish::EInstructionSet::SSE41, NArgonish::EArgon2Type::Argon2d, 1, 2048, 1);
+ ui8 password[16] = {0x0};
+ ui8 salt[16] = {0x01};
+ ui8 result[16] = {0};
+
+ for (ui64 i = 0; i < iface.Iterations(); ++i) {
+ argon2->Hash(password, sizeof(password), salt, sizeof(salt), result, sizeof(result));
+ }
+}
+
+Y_CPU_BENCHMARK(Argon2d_2048_AVX2, iface) {
+ NArgonish::TArgon2Factory factory;
+ auto argon2 = factory.Create(NArgonish::EInstructionSet::AVX2, NArgonish::EArgon2Type::Argon2d, 1, 2048, 1);
+ ui8 password[16] = {0x0};
+ ui8 salt[16] = {0x01};
+ ui8 result[16] = {0};
+
+ for (ui64 i = 0; i < iface.Iterations(); ++i) {
+ argon2->Hash(password, sizeof(password), salt, sizeof(salt), result, sizeof(result));
+ }
+}
+#endif
diff --git a/library/cpp/digest/argonish/benchmark/ya.make b/library/cpp/digest/argonish/benchmark/ya.make
new file mode 100644
index 0000000000..5aad1b238f
--- /dev/null
+++ b/library/cpp/digest/argonish/benchmark/ya.make
@@ -0,0 +1,13 @@
+OWNER(e-sidorov)
+
+Y_BENCHMARK()
+
+PEERDIR(
+ library/cpp/digest/argonish
+)
+
+SRCS(
+ mbench.cpp
+)
+
+END()
diff --git a/library/cpp/digest/argonish/blake2b.h b/library/cpp/digest/argonish/blake2b.h
new file mode 100644
index 0000000000..21ca468423
--- /dev/null
+++ b/library/cpp/digest/argonish/blake2b.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include "common.h"
+
+#include <util/generic/ptr.h>
+
+namespace NArgonish {
+ /**
+ * Interface for all Blake2B instances
+ */
+ class IBlake2Base {
+ public:
+ virtual ~IBlake2Base() {
+ }
+ /**
+ * Updates intermediate hash with an ui32 value
+ * @param in integer to hash
+ */
+ virtual void Update(ui32 in) = 0;
+
+ /**
+ * Updates intermediate hash with an array of bytes
+ * @param pin input
+ * @param inlen input length
+ */
+ virtual void Update(const void* pin, size_t inlen) = 0;
+
+ /**
+ * Finalizes the hash calculation and returns the hash value
+ * @param out output buffer
+ * @param outlen output buffer length
+ */
+ virtual void Final(void* out, size_t outlen) = 0;
+ };
+
+ /**
+ * A factory that creates Blake2B instances optimized for different instruction sets
+ */
+ class TBlake2BFactory {
+ public:
+ /**
+ * Constructs the factory object
+ * @param skipTest if true then the constructor skips runtime Blake2B test
+ */
+ TBlake2BFactory(bool skipTest = false);
+
+ /**
+ * Creates an instance of Blake2B hash algorithm.
+ * The optimisation is selected automatically based on the cpuid instruction output.
+ * @param outlen the output buffer length, this value takes part in hashing
+ * @param key a secret key to make Blake2B work as a keyed hash function
+ * @param keylen the secret key length
+ * @return returns an unique_ptr containing Blake2B instance
+ */
+ THolder<IBlake2Base> Create(size_t outlen = 32, const ui8* key = nullptr, size_t keylen = 0) const;
+
+ /**
+ * Creates an instance of Blake2B hash algorithm optimized for the particular instruction set
+ * @param instructionSet instruction set
+ * @param outlen the output buffer length, this value takes part in hashing
+ * @param key a secret key to make Blake2B work as a keyed hash function
+ * @param keylen the secret key length
+ * @return returns an unique_ptr containing Blake2B instance
+ */
+ THolder<IBlake2Base> Create(EInstructionSet instructionSet, size_t outlen = 32,
+ const ui8* key = nullptr, size_t keylen = 0) const;
+
+ /**
+ * The function returns the best instruction set available on the current CPU
+ * @return InstructionSet value
+ */
+ EInstructionSet GetInstructionSet() const;
+
+ protected:
+ EInstructionSet InstructionSet_ = EInstructionSet::REF;
+ void QuickTest_() const;
+ };
+}
diff --git a/library/cpp/digest/argonish/common.h b/library/cpp/digest/argonish/common.h
new file mode 100644
index 0000000000..973d82f13a
--- /dev/null
+++ b/library/cpp/digest/argonish/common.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <util/system/defaults.h>
+
+namespace NArgonish {
+ /**
+ * Instruction sets for which Argon2 is optimized
+ */
+ enum class EInstructionSet : ui32 {
+ REF = 0, /// Reference implementation
+#if !defined(_arm64_)
+ SSE2 = 1, /// SSE2 optimized version
+ SSSE3 = 2, /// SSSE3 optimized version
+ SSE41 = 3, /// SSE4.1 optimized version
+ AVX2 = 4 /// AVX2 optimized version
+#endif
+ };
+}
diff --git a/library/cpp/digest/argonish/factory/factory.cpp b/library/cpp/digest/argonish/factory/factory.cpp
new file mode 100644
index 0000000000..c1f5f5ce79
--- /dev/null
+++ b/library/cpp/digest/argonish/factory/factory.cpp
@@ -0,0 +1,222 @@
+//
+// Created by Evgeny Sidorov on 12/04/17.
+//
+
+#include <library/cpp/digest/argonish/blake2b.h>
+#include <library/cpp/digest/argonish/argon2.h>
+#include <library/cpp/digest/argonish/internal/proxies/ref/proxy_ref.h>
+#if !defined(_arm64_)
+#include <library/cpp/digest/argonish/internal/proxies/sse2/proxy_sse2.h>
+#include <library/cpp/digest/argonish/internal/proxies/ssse3/proxy_ssse3.h>
+#include <library/cpp/digest/argonish/internal/proxies/sse41/proxy_sse41.h>
+#include <library/cpp/digest/argonish/internal/proxies/avx2/proxy_avx2.h>
+#endif
+
+#include <util/system/cpu_id.h>
+#include <util/generic/yexception.h>
+
+namespace NArgonish {
+ static EInstructionSet GetBestSet() {
+#if !defined(_arm64_)
+ if (NX86::HaveAVX2()) {
+ return EInstructionSet::AVX2;
+ }
+
+ if (NX86::HaveSSE41()) {
+ return EInstructionSet::SSE41;
+ }
+
+ if (NX86::HaveSSSE3()) {
+ return EInstructionSet::SSSE3;
+ }
+
+ if (NX86::HaveSSE2()) {
+ return EInstructionSet::SSE2;
+ }
+#endif
+ return EInstructionSet::REF;
+ }
+
+ TArgon2Factory::TArgon2Factory(bool skipTest) {
+ InstructionSet_ = GetBestSet();
+ if (!skipTest)
+ QuickTest_();
+ }
+
+ THolder<IArgon2Base> TArgon2Factory::Create(EInstructionSet instructionSet, EArgon2Type atype, ui32 tcost,
+ ui32 mcost, ui32 threads, const ui8* key, ui32 keylen) const {
+ switch (instructionSet) {
+ case EInstructionSet::REF:
+ return MakeHolder<TArgon2ProxyREF>(atype, tcost, mcost, threads, key, keylen);
+#if !defined(_arm64_)
+ case EInstructionSet::SSE2:
+ return MakeHolder<TArgon2ProxySSE2>(atype, tcost, mcost, threads, key, keylen);
+ case EInstructionSet::SSSE3:
+ return MakeHolder<TArgon2ProxySSSE3>(atype, tcost, mcost, threads, key, keylen);
+ case EInstructionSet::SSE41:
+ return MakeHolder<TArgon2ProxySSSE3>(atype, tcost, mcost, threads, key, keylen);
+ case EInstructionSet::AVX2:
+ return MakeHolder<TArgon2ProxyAVX2>(atype, tcost, mcost, threads, key, keylen);
+#endif
+ }
+
+ /* to avoid gcc warning */
+ ythrow yexception() << "Invalid instruction set value";
+ }
+
+ THolder<IArgon2Base> TArgon2Factory::Create(EArgon2Type atype, ui32 tcost, ui32 mcost, ui32 threads,
+ const ui8* key, ui32 keylen) const {
+ return Create(InstructionSet_, atype, tcost, mcost, threads, key, keylen);
+ }
+
+ EInstructionSet TArgon2Factory::GetInstructionSet() const {
+ return InstructionSet_;
+ }
+
+ void TArgon2Factory::QuickTest_() const {
+ const ui8 password[8] = {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
+ const ui8 salt[8] = {'s', 'o', 'm', 'e', 's', 'a', 'l', 't'};
+ const ui8 test_result[][32] = {
+ {0x2e, 0x2e, 0x5e, 0x05, 0xfe, 0x57, 0xac, 0x2c,
+ 0xf4, 0x72, 0xec, 0xd0, 0x45, 0xef, 0x68, 0x7e,
+ 0x56, 0x2a, 0x98, 0x0f, 0xd5, 0x03, 0x39, 0xb3,
+ 0x89, 0xc8, 0x70, 0xe1, 0x96, 0x2b, 0xbc, 0x45},
+ {0x95, 0x46, 0x6c, 0xc4, 0xf9, 0x2f, 0x87, 0x49,
+ 0x54, 0x61, 0x7e, 0xec, 0x0a, 0xa1, 0x19, 0x5d,
+ 0x22, 0x98, 0x0a, 0xbd, 0x62, 0x5e, 0x5c, 0xac,
+ 0x44, 0x76, 0x3a, 0xe3, 0xa9, 0xcb, 0x6a, 0xb7},
+ {0xc8, 0xe9, 0xae, 0xdc, 0x95, 0x6f, 0x6a, 0x7d,
+ 0xff, 0x0a, 0x4d, 0x42, 0x94, 0x0d, 0xf6, 0x28,
+ 0x62, 0x3f, 0x32, 0x8e, 0xa1, 0x23, 0x50, 0x05,
+ 0xab, 0xac, 0x93, 0x3c, 0x57, 0x09, 0x3e, 0x23}};
+
+ ui8 hash_result[32] = {0};
+ for (ui32 atype = (ui32)EArgon2Type::Argon2d; atype <= (ui32)EArgon2Type::Argon2id; ++atype) {
+ auto argon2d = MakeHolder<TArgon2ProxyREF>((EArgon2Type)atype, 1U, 1024U, 1U);
+ argon2d->Hash(password, sizeof(password), salt, sizeof(salt), hash_result, sizeof(hash_result));
+ if (memcmp(test_result[atype], hash_result, sizeof(hash_result)) != 0)
+ ythrow yexception() << "Argon2: Runtime test failed for reference implementation";
+ }
+#if !defined(_arm64_)
+ if (InstructionSet_ >= EInstructionSet::SSE2) {
+ for (ui32 atype = (ui32)EArgon2Type::Argon2d; atype <= (ui32)EArgon2Type::Argon2id; ++atype) {
+ auto argon2d = MakeHolder<TArgon2ProxySSE2>((EArgon2Type)atype, 1U, 1024U, 1U);
+ argon2d->Hash(password, sizeof(password), salt, sizeof(salt), hash_result, sizeof(hash_result));
+ if (memcmp(test_result[atype], hash_result, sizeof(hash_result)) != 0)
+ ythrow yexception() << "Argon2: Runtime test failed for SSE2 implementation";
+ }
+ }
+
+ if (InstructionSet_ >= EInstructionSet::SSSE3) {
+ for (ui32 atype = (ui32)EArgon2Type::Argon2d; atype <= (ui32)EArgon2Type::Argon2id; ++atype) {
+ auto argon2d = MakeHolder<TArgon2ProxySSSE3>((EArgon2Type)atype, 1U, 1024U, 1U);
+ argon2d->Hash(password, sizeof(password), salt, sizeof(salt), hash_result, sizeof(hash_result));
+ if (memcmp(test_result[atype], hash_result, sizeof(hash_result)) != 0)
+ ythrow yexception() << "Argon2: Runtime test failed for SSSE3 implementation";
+ }
+ }
+
+ if (InstructionSet_ >= EInstructionSet::SSE41) {
+ for (ui32 atype = (ui32)EArgon2Type::Argon2d; atype <= (ui32)EArgon2Type::Argon2id; ++atype) {
+ auto argon2d = MakeHolder<TArgon2ProxySSE41>((EArgon2Type)atype, 1U, 1024U, 1U);
+ argon2d->Hash(password, sizeof(password), salt, sizeof(salt), hash_result, sizeof(hash_result));
+ if (memcmp(test_result[atype], hash_result, sizeof(hash_result)) != 0)
+ ythrow yexception() << "Argon2: Runtime test failed for SSE41 implementation";
+ }
+ }
+
+ if (InstructionSet_ >= EInstructionSet::AVX2) {
+ for (ui32 atype = (ui32)EArgon2Type::Argon2d; atype <= (ui32)EArgon2Type::Argon2id; ++atype) {
+ auto argon2d = MakeHolder<TArgon2ProxyAVX2>((EArgon2Type)atype, 1U, 1024U, 1U);
+ argon2d->Hash(password, sizeof(password), salt, sizeof(salt), hash_result, sizeof(hash_result));
+ if (memcmp(test_result[atype], hash_result, sizeof(hash_result)) != 0)
+ ythrow yexception() << "Argon2: Runtime test failed for AVX2 implementation";
+ }
+ }
+#endif
+ }
+
+ TBlake2BFactory::TBlake2BFactory(bool skipTest) {
+ InstructionSet_ = GetBestSet();
+ if (!skipTest)
+ QuickTest_();
+ }
+
+ THolder<IBlake2Base> TBlake2BFactory::Create(EInstructionSet instructionSet, size_t outlen, const ui8* key,
+ size_t keylen) const {
+ switch (instructionSet) {
+ case EInstructionSet::REF:
+ return MakeHolder<TBlake2BProxyREF>(outlen, key, keylen);
+#if !defined(_arm64_)
+ case EInstructionSet::SSE2:
+ return MakeHolder<TBlake2BProxySSE2>(outlen, key, keylen);
+ case EInstructionSet::SSSE3:
+ return MakeHolder<TBlake2BProxySSSE3>(outlen, key, keylen);
+ case EInstructionSet::SSE41:
+ return MakeHolder<TBlake2BProxySSE41>(outlen, key, keylen);
+ case EInstructionSet::AVX2:
+ return MakeHolder<TBlake2BProxyAVX2>(outlen, key, keylen);
+#endif
+ }
+
+ /* to supress gcc warning */
+ ythrow yexception() << "Invalid instruction set";
+ }
+
+ THolder<IBlake2Base> TBlake2BFactory::Create(size_t outlen, const ui8* key, size_t keylen) const {
+ return Create(InstructionSet_, outlen, key, keylen);
+ }
+
+ EInstructionSet TBlake2BFactory::GetInstructionSet() const {
+ return InstructionSet_;
+ }
+
+ void TBlake2BFactory::QuickTest_() const {
+ const char* test_str = "abc";
+ const ui8 test_result[] = {
+ 0xcf, 0x4a, 0xb7, 0x91, 0xc6, 0x2b, 0x8d, 0x2b,
+ 0x21, 0x09, 0xc9, 0x02, 0x75, 0x28, 0x78, 0x16};
+
+ ui8 hash_val[16];
+ if (InstructionSet_ >= EInstructionSet::REF) {
+ auto blake2 = MakeHolder<TBlake2BProxyREF>(16U);
+ blake2->Update(test_str, 3);
+ blake2->Final(hash_val, 16);
+ if (memcmp(test_result, hash_val, 16) != 0)
+ ythrow yexception() << "Blake2B: Runtime test failed for reference implementation";
+ }
+#if !defined(_arm64_)
+ if (InstructionSet_ >= EInstructionSet::SSE2) {
+ auto blake2 = MakeHolder<TBlake2BProxySSE2>(16U);
+ blake2->Update(test_str, 3);
+ blake2->Final(hash_val, 16);
+ if (memcmp(test_result, hash_val, 16) != 0)
+ ythrow yexception() << "Blake2B: Runtime test failed for SSE2 implementation";
+ }
+
+ if (InstructionSet_ >= EInstructionSet::SSSE3) {
+ auto blake2 = MakeHolder<TBlake2BProxySSSE3>(16U);
+ blake2->Update(test_str, 3);
+ blake2->Final(hash_val, 16);
+ if (memcmp(test_result, hash_val, 16) != 0)
+ ythrow yexception() << "Blake2B: Runtime test failed for SSSE3 implementation";
+ }
+
+ if (InstructionSet_ >= EInstructionSet::SSE41) {
+ auto blake2 = MakeHolder<TBlake2BProxySSE41>(16U);
+ blake2->Update(test_str, 3);
+ blake2->Final(hash_val, 16);
+ if (memcmp(test_result, hash_val, 16) != 0)
+ ythrow yexception() << "Blake2B: Runtime test failed for SSE41 implmenetation";
+ }
+
+ if (InstructionSet_ >= EInstructionSet::AVX2) {
+ auto blake2 = MakeHolder<TBlake2BProxyAVX2>(16U);
+ blake2->Update(test_str, 3);
+ blake2->Final(hash_val, 16);
+ if (memcmp(test_result, hash_val, 16) != 0)
+ ythrow yexception() << "Blake2B: Runtime test failed for AVX2 implementation";
+ }
+#endif
+ }
+}
diff --git a/library/cpp/digest/argonish/internal/argon2/argon2_avx2.h b/library/cpp/digest/argonish/internal/argon2/argon2_avx2.h
new file mode 100644
index 0000000000..8bf5367817
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/argon2/argon2_avx2.h
@@ -0,0 +1,117 @@
+#pragma once
+
+#include <immintrin.h>
+#include "argon2_base.h"
+#include <library/cpp/digest/argonish/internal/blamka/blamka_avx2.h>
+
+namespace NArgonish {
+ template <ui32 mcost, ui32 threads>
+ class TArgon2AVX2 final: public TArgon2<EInstructionSet::AVX2, mcost, threads> {
+ public:
+ TArgon2AVX2(EArgon2Type atype, ui32 tcost, const ui8* key, ui32 keylen)
+ : TArgon2<EInstructionSet::AVX2, mcost, threads>(atype, tcost, key, keylen)
+ {
+ }
+
+ protected:
+ virtual void XorBlock_(TBlock* dst, const TBlock* src) const override {
+ __m256i* mdst = (__m256i*)dst;
+ __m256i* msrc = (__m256i*)src;
+
+ for (ui32 i = 0; i < ARGON2_HWORDS_IN_BLOCK; ++i)
+ XorValues(mdst + i, mdst + i, msrc + i);
+ }
+
+ virtual void CopyBlock_(TBlock* dst, const TBlock* src) const override {
+ memcpy(dst->V, src->V, sizeof(ui64) * ARGON2_QWORDS_IN_BLOCK);
+ }
+
+ virtual void FillBlock_(const TBlock* prevBlock, const TBlock* refBlock, TBlock* nextBlock, bool with_xor) const override {
+ __m256i blockxy[ARGON2_HWORDS_IN_BLOCK];
+ __m256i state[ARGON2_HWORDS_IN_BLOCK];
+
+ memcpy(state, prevBlock, ARGON2_BLOCK_SIZE);
+
+ if (with_xor) {
+ for (ui32 i = 0; i < ARGON2_HWORDS_IN_BLOCK; ++i) {
+ state[i] = _mm256_xor_si256(state[i], _mm256_loadu_si256((const __m256i*)refBlock->V + i));
+ blockxy[i] = _mm256_xor_si256(state[i], _mm256_loadu_si256((const __m256i*)nextBlock->V + i));
+ }
+ } else {
+ for (ui32 i = 0; i < ARGON2_HWORDS_IN_BLOCK; ++i) {
+ blockxy[i] = state[i] = _mm256_xor_si256(
+ state[i], _mm256_loadu_si256((const __m256i*)refBlock->V + i));
+ }
+ }
+
+ /**
+ * state[ 8*i + 0 ] = ( v0_0, v1_0, v2_0, v3_0)
+ * state[ 8*i + 1 ] = ( v4_0, v5_0, v6_0, v7_0)
+ * state[ 8*i + 2 ] = ( v8_0, v9_0, v10_0, v11_0)
+ * state[ 8*i + 3 ] = (v12_0, v13_0, v14_0, v15_0)
+ * state[ 8*i + 4 ] = ( v0_1, v1_1, v2_1, v3_1)
+ * state[ 8*i + 5 ] = ( v4_1, v5_1, v6_1, v7_1)
+ * state[ 8*i + 6 ] = ( v8_1, v9_1, v10_1, v11_1)
+ * state[ 8*i + 7 ] = (v12_1, v13_1, v14_1, v15_1)
+ */
+ for (ui32 i = 0; i < 4; ++i) {
+ BlamkaG1AVX2(
+ state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5],
+ state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]);
+ BlamkaG2AVX2(
+ state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5],
+ state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]);
+ DiagonalizeAVX21(
+ state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
+ BlamkaG1AVX2(
+ state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5],
+ state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]);
+ BlamkaG2AVX2(
+ state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5],
+ state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]);
+ UndiagonalizeAVX21(
+ state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
+ }
+
+ /**
+ * state[ 0 + i] = ( v0_0, v1_0, v0_1, v1_1)
+ * state[ 4 + i] = ( v2_0, v3_0, v2_1, v3_1)
+ * state[ 8 + i] = ( v4_0, v5_0, v4_1, v5_1)
+ * state[12 + i] = ( v6_0, v7_0, v6_1, v7_1)
+ * state[16 + i] = ( v8_0, v9_0, v8_1, v9_1)
+ * state[20 + i] = (v10_0, v11_0, v10_1, v11_1)
+ * state[24 + i] = (v12_0, v13_0, v12_1, v13_1)
+ * state[28 + i] = (v14_0, v15_0, v14_1, v15_1)
+ */
+ for (ui32 i = 0; i < 4; ++i) {
+ BlamkaG1AVX2(
+ state[0 + i], state[4 + i], state[8 + i], state[12 + i],
+ state[16 + i], state[20 + i], state[24 + i], state[28 + i]);
+ BlamkaG2AVX2(
+ state[0 + i], state[4 + i], state[8 + i], state[12 + i],
+ state[16 + i], state[20 + i], state[24 + i], state[28 + i]);
+ DiagonalizeAVX22(
+ state[8 + i], state[12 + i],
+ state[16 + i], state[20 + i],
+ state[24 + i], state[28 + i]);
+ BlamkaG1AVX2(
+ state[0 + i], state[4 + i], state[8 + i], state[12 + i],
+ state[16 + i], state[20 + i], state[24 + i], state[28 + i]);
+ BlamkaG2AVX2(
+ state[0 + i], state[4 + i], state[8 + i], state[12 + i],
+ state[16 + i], state[20 + i], state[24 + i], state[28 + i]);
+ UndiagonalizeAVX22(
+ state[8 + i], state[12 + i],
+ state[16 + i], state[20 + i],
+ state[24 + i], state[28 + i]);
+ }
+
+ for (ui32 i = 0; i < ARGON2_HWORDS_IN_BLOCK; ++i) {
+ state[i] = _mm256_xor_si256(state[i], blockxy[i]);
+ _mm256_storeu_si256((__m256i*)nextBlock->V + i, state[i]);
+ }
+ }
+ };
+}
diff --git a/library/cpp/digest/argonish/internal/argon2/argon2_base.h b/library/cpp/digest/argonish/internal/argon2/argon2_base.h
new file mode 100644
index 0000000000..2385cc947c
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/argon2/argon2_base.h
@@ -0,0 +1,388 @@
+#pragma once
+
+#include <util/generic/yexception.h>
+#include <library/cpp/digest/argonish/argon2.h>
+#include <library/cpp/digest/argonish/internal/blake2b/blake2b.h>
+#include <library/cpp/threading/poor_man_openmp/thread_helper.h>
+
+namespace NArgonish {
+ const ui32 ARGON2_PREHASH_DIGEST_LENGTH = 64;
+ const ui32 ARGON2_SECRET_MAX_LENGTH = 64;
+ const ui32 ARGON2_PREHASH_SEED_LENGTH = 72;
+ const ui32 ARGON2_BLOCK_SIZE = 1024;
+ const ui32 ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8;
+ const ui32 ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16;
+ const ui32 ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32;
+ const ui32 ARGON2_ADDRESSES_IN_BLOCK = 128;
+ const ui32 ARGON2_SYNC_POINTS = 4;
+ const ui32 ARGON2_SALT_MIN_LEN = 8;
+ const ui32 ARGON2_MIN_OUTLEN = 4;
+
+ struct TBlock {
+ ui64 V[ARGON2_QWORDS_IN_BLOCK];
+ };
+
+ template <EInstructionSet instructionSet, ui32 mcost, ui32 threads>
+ class TArgon2: public IArgon2Base {
+ public:
+ TArgon2(EArgon2Type atype, ui32 tcost, const ui8* key, ui32 keylen)
+ : SecretLen_(keylen)
+ , Tcost_(tcost)
+ , Atype_(atype)
+ {
+ if (SecretLen_)
+ memcpy(Secret_, key, keylen);
+ }
+
+ virtual ~TArgon2() override {
+ if (SecretLen_) {
+ SecureZeroMemory_(Secret_, SecretLen_);
+ SecretLen_ = 0;
+ }
+ }
+
+ virtual void Hash(const ui8* pwd, ui32 pwdlen, const ui8* salt, ui32 saltlen,
+ ui8* out, ui32 outlen, const ui8* aad = nullptr, ui32 aadlen = 0) const override {
+ TArrayHolder<TBlock> buffer(new TBlock[MemoryBlocks_]);
+ InternalHash_(buffer.Get(), pwd, pwdlen, salt, saltlen, out, outlen, aad, aadlen);
+ }
+
+ virtual bool Verify(const ui8* pwd, ui32 pwdlen, const ui8* salt, ui32 saltlen,
+ const ui8* hash, ui32 hashlen, const ui8* aad = nullptr, ui32 aadlen = 0) const override {
+ TArrayHolder<ui8> hashResult(new ui8[hashlen]);
+ Hash(pwd, pwdlen, salt, saltlen, hashResult.Get(), hashlen, aad, aadlen);
+
+ return SecureCompare_(hash, hashResult.Get(), hashlen);
+ }
+
+ virtual void HashWithCustomMemory(ui8* memory, size_t mlen, const ui8* pwd, ui32 pwdlen,
+ const ui8* salt, ui32 saltlen, ui8* out, ui32 outlen,
+ const ui8* aad = nullptr, ui32 aadlen = 0) const override {
+ if (memory == nullptr || mlen < sizeof(TBlock) * MemoryBlocks_)
+ ythrow yexception() << "memory is null or its size is not enough";
+
+ InternalHash_((TBlock*)memory, pwd, pwdlen, salt, saltlen, out, outlen, aad, aadlen);
+ }
+
+ virtual bool VerifyWithCustomMemory(ui8* memory, size_t mlen, const ui8* pwd, ui32 pwdlen,
+ const ui8* salt, ui32 saltlen, const ui8* hash, ui32 hashlen,
+ const ui8* aad = nullptr, ui32 aadlen = 0) const override {
+ TArrayHolder<ui8> hashResult(new ui8[hashlen]);
+ HashWithCustomMemory(memory, mlen, pwd, pwdlen, salt, saltlen, hashResult.Get(), hashlen, aad, aadlen);
+
+ return SecureCompare_(hashResult.Get(), hash, hashlen);
+ }
+
+ virtual size_t GetMemorySize() const override {
+ return MemoryBlocks_ * sizeof(TBlock);
+ }
+
+ protected: /* Constants */
+ ui8 Secret_[ARGON2_SECRET_MAX_LENGTH] = {0};
+ ui32 SecretLen_ = 0;
+ ui32 Tcost_;
+ EArgon2Type Atype_;
+
+ static constexpr ui32 Lanes_ = threads;
+ static constexpr ui32 MemoryBlocks_ = (mcost >= 2 * ARGON2_SYNC_POINTS * Lanes_) ? (mcost - mcost % (Lanes_ * ARGON2_SYNC_POINTS)) : 2 * ARGON2_SYNC_POINTS * Lanes_;
+ static constexpr ui32 SegmentLength_ = MemoryBlocks_ / (Lanes_ * ARGON2_SYNC_POINTS);
+ static constexpr ui32 LaneLength_ = SegmentLength_ * ARGON2_SYNC_POINTS;
+
+ protected: /* Prototypes */
+ virtual void FillBlock_(const TBlock* prevBlock, const TBlock* refBlock,
+ TBlock* nextBlock, bool withXor) const = 0;
+
+ virtual void CopyBlock_(TBlock* dst, const TBlock* src) const = 0;
+ virtual void XorBlock_(TBlock* dst, const TBlock* src) const = 0;
+
+ protected: /* Static functions */
+ static bool SecureCompare_(const ui8* buffer1, const ui8* buffer2, ui32 len) {
+ bool result = true;
+ for (ui32 i = 0; i < len; ++i) {
+ result &= (buffer1[i] == buffer2[i]);
+ }
+ return result;
+ }
+
+ static void SecureZeroMemory_(void* src, size_t len) {
+ static void* (*const volatile memset_v)(void*, int, size_t) = &memset;
+ memset_v(src, 0, len);
+ }
+
+ static void Store32_(ui32 value, void* mem) {
+ *((ui32*)mem) = value;
+ }
+
+ static void Blake2BHash64_(ui8 out[BLAKE2B_OUTBYTES], const ui8 in[BLAKE2B_OUTBYTES]) {
+ TBlake2B<instructionSet> hash(BLAKE2B_OUTBYTES);
+ hash.Update(in, BLAKE2B_OUTBYTES);
+ hash.Final(out, BLAKE2B_OUTBYTES);
+ }
+
+ static void ExpandBlockhash_(ui8 expanded[ARGON2_BLOCK_SIZE], const ui8 blockhash[ARGON2_PREHASH_SEED_LENGTH]) {
+ ui8 out_buffer[BLAKE2B_OUTBYTES];
+ ui8 in_buffer[BLAKE2B_OUTBYTES];
+ const ui32 HALF_OUT_BYTES = BLAKE2B_OUTBYTES / 2;
+ const ui32 HASH_BLOCKS_COUNT = ((ARGON2_BLOCK_SIZE / HALF_OUT_BYTES));
+
+ TBlake2B<instructionSet> hash(BLAKE2B_OUTBYTES);
+ hash.Update(ARGON2_BLOCK_SIZE);
+ hash.Update(blockhash, ARGON2_PREHASH_SEED_LENGTH);
+ hash.Final(out_buffer, BLAKE2B_OUTBYTES);
+
+ memcpy(expanded, out_buffer, HALF_OUT_BYTES);
+
+ for (ui32 i = 1; i < HASH_BLOCKS_COUNT - 2; ++i) {
+ memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);
+ Blake2BHash64_(out_buffer, in_buffer);
+ memcpy(expanded + (i * HALF_OUT_BYTES), out_buffer, HALF_OUT_BYTES);
+ }
+
+ Blake2BHash64_(in_buffer, out_buffer);
+ memcpy(expanded + HALF_OUT_BYTES * (HASH_BLOCKS_COUNT - 2), in_buffer, BLAKE2B_OUTBYTES);
+ }
+
+ static void Blake2BLong_(ui8* out, ui32 outlen, const ui8* in, ui32 inlen) {
+ if (outlen < BLAKE2B_OUTBYTES) {
+ TBlake2B<instructionSet> hash(outlen);
+ hash.Update(outlen);
+ hash.Update(in, inlen);
+ hash.Final(out, outlen);
+ } else {
+ ui8 out_buffer[BLAKE2B_OUTBYTES];
+ ui8 in_buffer[BLAKE2B_OUTBYTES];
+ ui32 toproduce = outlen - BLAKE2B_OUTBYTES / 2;
+
+ TBlake2B<instructionSet> hash1(BLAKE2B_OUTBYTES);
+ hash1.Update(outlen);
+ hash1.Update(in, inlen);
+ hash1.Final(out_buffer, BLAKE2B_OUTBYTES);
+
+ memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);
+ out += BLAKE2B_OUTBYTES / 2;
+
+ while (toproduce > BLAKE2B_OUTBYTES) {
+ memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);
+ TBlake2B<instructionSet> hash2(BLAKE2B_OUTBYTES);
+ hash2.Update(in_buffer, BLAKE2B_OUTBYTES);
+ hash2.Final(out_buffer, BLAKE2B_OUTBYTES);
+ memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);
+ out += BLAKE2B_OUTBYTES / 2;
+ toproduce -= BLAKE2B_OUTBYTES / 2;
+ }
+
+ memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);
+ {
+ TBlake2B<instructionSet> hash3(toproduce);
+ hash3.Update(in_buffer, BLAKE2B_OUTBYTES);
+ hash3.Final(out_buffer, toproduce);
+ memcpy(out, out_buffer, toproduce);
+ }
+ }
+ }
+
+ static void InitBlockValue_(TBlock* b, ui8 in) {
+ memset(b->V, in, sizeof(b->V));
+ }
+
+ protected: /* Functions */
+ void InternalHash_(TBlock* memory, const ui8* pwd, ui32 pwdlen,
+ const ui8* salt, ui32 saltlen, ui8* out, ui32 outlen,
+ const ui8* aad, ui32 aadlen) const {
+ /*
+ * all parameters checks are in proxy objects
+ */
+
+ Initialize_(memory, outlen, pwd, pwdlen, salt, saltlen, aad, aadlen);
+ FillMemoryBlocks_(memory);
+ Finalize_(memory, out, outlen);
+ }
+
+ void InitialHash_(ui8 blockhash[ARGON2_PREHASH_DIGEST_LENGTH],
+ ui32 outlen, const ui8* pwd, ui32 pwdlen,
+ const ui8* salt, ui32 saltlen, const ui8* aad, ui32 aadlen) const {
+ TBlake2B<instructionSet> hash(ARGON2_PREHASH_DIGEST_LENGTH);
+ /* lanes, but lanes == threads */
+ hash.Update(Lanes_);
+ /* outlen */
+ hash.Update(outlen);
+ /* m_cost */
+ hash.Update(mcost);
+ /* t_cost */
+ hash.Update(Tcost_);
+ /* version */
+ hash.Update(0x00000013);
+ /* Argon2 type */
+ hash.Update((ui32)Atype_);
+ /* pwdlen */
+ hash.Update(pwdlen);
+ /* pwd */
+ hash.Update(pwd, pwdlen);
+ /* saltlen */
+ hash.Update(saltlen);
+ /* salt */
+ if (saltlen)
+ hash.Update(salt, saltlen);
+ /* secret */
+ hash.Update(SecretLen_);
+ if (SecretLen_)
+ hash.Update((void*)Secret_, SecretLen_);
+ /* aadlen */
+ hash.Update(aadlen);
+ if (aadlen)
+ hash.Update((void*)aad, aadlen);
+ hash.Final(blockhash, ARGON2_PREHASH_DIGEST_LENGTH);
+ }
+
+ void FillFirstBlocks_(TBlock* blocks, ui8* blockhash) const {
+ for (ui32 l = 0; l < Lanes_; l++) {
+ /* fill the first block of the lane */
+ Store32_(l, blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4);
+ Store32_(0, blockhash + ARGON2_PREHASH_DIGEST_LENGTH);
+ ExpandBlockhash_((ui8*)&(blocks[l * LaneLength_]), blockhash);
+
+ /* fill the second block of the lane */
+ Store32_(1, blockhash + ARGON2_PREHASH_DIGEST_LENGTH);
+ ExpandBlockhash_((ui8*)&(blocks[l * LaneLength_ + 1]), blockhash);
+ }
+ }
+
+ /* The 'if' will be optimized out as the number of threads is known at the compile time */
+ void FillMemoryBlocks_(TBlock* memory) const {
+ for (ui32 t = 0; t < Tcost_; ++t) {
+ for (ui32 s = 0; s < ARGON2_SYNC_POINTS; ++s) {
+ if (Lanes_ == 1)
+ FillSegment_(memory, t, 0, s);
+ else {
+ NYmp::SetThreadCount(Lanes_);
+ NYmp::ParallelForStaticAutoChunk<ui32>(0, Lanes_, [this, &memory, s, t](int k) {
+ this->FillSegment_(memory, t, k, s);
+ });
+ }
+ }
+ }
+ }
+
+ void Initialize_(TBlock* memory, ui32 outlen, const ui8* pwd, ui32 pwdlen,
+ const ui8* salt, ui32 saltlen, const ui8* aad, ui32 aadlen) const {
+ ui8 blockhash[ARGON2_PREHASH_SEED_LENGTH];
+ InitialHash_(blockhash, outlen, pwd, pwdlen, salt, saltlen, aad, aadlen);
+ FillFirstBlocks_(memory, blockhash);
+ }
+
+ ui32 ComputeReferenceArea_(ui32 pass, ui32 slice, ui32 index, bool sameLane) const {
+ ui32 passVal = pass == 0 ? (slice * SegmentLength_) : (LaneLength_ - SegmentLength_);
+ return sameLane ? passVal + (index - 1) : passVal + (index == 0 ? -1 : 0);
+ }
+
+ ui32 IndexAlpha_(ui32 pass, ui32 slice, ui32 index, ui32 pseudoRand, bool sameLane) const {
+ ui32 referenceAreaSize = ComputeReferenceArea_(pass, slice, index, sameLane);
+
+ ui64 relativePosition = pseudoRand;
+ relativePosition = relativePosition * relativePosition >> 32;
+ relativePosition = referenceAreaSize - 1 - (referenceAreaSize * relativePosition >> 32);
+
+ ui32 startPosition = 0;
+ if (pass != 0)
+ startPosition = (slice == ARGON2_SYNC_POINTS - 1) ? 0 : (slice + 1) * SegmentLength_;
+
+ return (ui32)((startPosition + relativePosition) % LaneLength_);
+ }
+
+ void NextAddresses_(TBlock* addressBlock, TBlock* inputBlock, const TBlock* zeroBlock) const {
+ inputBlock->V[6]++;
+ FillBlock_(zeroBlock, inputBlock, addressBlock, false);
+ FillBlock_(zeroBlock, addressBlock, addressBlock, false);
+ }
+
+ void Finalize_(const TBlock* memory, ui8* out, ui32 outlen) const {
+ TBlock blockhash;
+ CopyBlock_(&blockhash, memory + LaneLength_ - 1);
+
+ /* XOR the last blocks */
+ for (ui32 l = 1; l < Lanes_; ++l) {
+ ui32 lastBlockInLane = l * LaneLength_ + (LaneLength_ - 1);
+ XorBlock_(&blockhash, memory + lastBlockInLane);
+ }
+
+ Blake2BLong_(out, outlen, (ui8*)blockhash.V, ARGON2_BLOCK_SIZE);
+ }
+
+ /* The switch will be optimized out by the compiler as the type is known at the compile time */
+ void FillSegment_(TBlock* memory, ui32 pass, ui32 lane, ui32 slice) const {
+ switch (Atype_) {
+ case EArgon2Type::Argon2d:
+ FillSegmentD_(memory, pass, lane, slice);
+ return;
+ case EArgon2Type::Argon2i:
+ FillSegmentI_(memory, pass, lane, slice, EArgon2Type::Argon2i);
+ return;
+ case EArgon2Type::Argon2id:
+ if (pass == 0 && slice < ARGON2_SYNC_POINTS / 2)
+ FillSegmentI_(memory, pass, lane, slice, EArgon2Type::Argon2id);
+ else
+ FillSegmentD_(memory, pass, lane, slice);
+ return;
+ }
+ }
+
+ void FillSegmentD_(TBlock* memory, ui32 pass, ui32 lane, ui32 slice) const {
+ ui32 startingIndex = (pass == 0 && slice == 0) ? 2 : 0;
+ ui32 currOffset = lane * LaneLength_ + slice * SegmentLength_ + startingIndex;
+ ui32 prevOffset = currOffset + ((currOffset % LaneLength_ == 0) ? LaneLength_ : 0) - 1;
+
+ for (ui32 i = startingIndex; i < SegmentLength_; ++i, ++currOffset, ++prevOffset) {
+ if (currOffset % LaneLength_ == 1) {
+ prevOffset = currOffset - 1;
+ }
+
+ ui64 pseudoRand = memory[prevOffset].V[0];
+ ui64 refLane = (pass == 0 && slice == 0) ? lane : (((pseudoRand >> 32)) % Lanes_);
+ ui64 refIndex = IndexAlpha_(pass, slice, i, (ui32)(pseudoRand & 0xFFFFFFFF), refLane == lane);
+
+ TBlock* refBlock = memory + LaneLength_ * refLane + refIndex;
+ FillBlock_(memory + prevOffset, refBlock, memory + currOffset, pass != 0);
+ }
+ }
+
+ void FillSegmentI_(TBlock* memory, ui32 pass, ui32 lane, ui32 slice, EArgon2Type atp) const {
+ TBlock addressBlock, inputBlock, zeroBlock;
+ InitBlockValue_(&zeroBlock, 0);
+ InitBlockValue_(&inputBlock, 0);
+
+ inputBlock.V[0] = pass;
+ inputBlock.V[1] = lane;
+ inputBlock.V[2] = slice;
+ inputBlock.V[3] = MemoryBlocks_;
+ inputBlock.V[4] = Tcost_;
+ inputBlock.V[5] = (ui64)atp;
+
+ ui32 startingIndex = 0;
+
+ if (pass == 0 && slice == 0) {
+ startingIndex = 2;
+ NextAddresses_(&addressBlock, &inputBlock, &zeroBlock);
+ }
+
+ ui32 currOffset = lane * LaneLength_ + slice * SegmentLength_ + startingIndex;
+ ui32 prevOffset = currOffset + ((currOffset % LaneLength_ == 0) ? LaneLength_ : 0) - 1;
+
+ for (ui32 i = startingIndex; i < SegmentLength_; ++i, ++currOffset, ++prevOffset) {
+ if (currOffset % LaneLength_ == 1) {
+ prevOffset = currOffset - 1;
+ }
+
+ if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {
+ NextAddresses_(&addressBlock, &inputBlock, &zeroBlock);
+ }
+
+ ui64 pseudoRand = addressBlock.V[i % ARGON2_ADDRESSES_IN_BLOCK];
+ ui64 refLane = (pass == 0 && slice == 0) ? lane : (((pseudoRand >> 32)) % Lanes_);
+ ui64 refIndex = IndexAlpha_(pass, slice, i, (ui32)(pseudoRand & 0xFFFFFFFF), refLane == lane);
+
+ TBlock* refBlock = memory + LaneLength_ * refLane + refIndex;
+ FillBlock_(memory + prevOffset, refBlock, memory + currOffset, pass != 0);
+ }
+ }
+ };
+}
diff --git a/library/cpp/digest/argonish/internal/argon2/argon2_ref.h b/library/cpp/digest/argonish/internal/argon2/argon2_ref.h
new file mode 100644
index 0000000000..8e5e3fa971
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/argon2/argon2_ref.h
@@ -0,0 +1,88 @@
+#pragma once
+
+#include "argon2_base.h"
+#include <library/cpp/digest/argonish/internal/rotations/rotations_ref.h>
+
+namespace NArgonish {
+ static inline ui64 FBlaMka(ui64 x, ui64 y) {
+ const ui64 m = 0xFFFFFFFF;
+ const ui64 xy = (x & m) * (y & m);
+ return x + y + 2 * xy;
+ }
+
+ static inline void BlamkaGRef(ui64& a, ui64& b, ui64& c, ui64& d) {
+ a = FBlaMka(a, b);
+ d = Rotr(d ^ a, 32);
+ c = FBlaMka(c, d);
+ b = Rotr(b ^ c, 24);
+ a = FBlaMka(a, b);
+ d = Rotr(d ^ a, 16);
+ c = FBlaMka(c, d);
+ b = Rotr(b ^ c, 63);
+ }
+
+ static inline void BlamkaRoundRef(
+ ui64& v0, ui64& v1, ui64& v2, ui64& v3,
+ ui64& v4, ui64& v5, ui64& v6, ui64& v7,
+ ui64& v8, ui64& v9, ui64& v10, ui64& v11,
+ ui64& v12, ui64& v13, ui64& v14, ui64& v15) {
+ BlamkaGRef(v0, v4, v8, v12);
+ BlamkaGRef(v1, v5, v9, v13);
+ BlamkaGRef(v2, v6, v10, v14);
+ BlamkaGRef(v3, v7, v11, v15);
+ BlamkaGRef(v0, v5, v10, v15);
+ BlamkaGRef(v1, v6, v11, v12);
+ BlamkaGRef(v2, v7, v8, v13);
+ BlamkaGRef(v3, v4, v9, v14);
+ }
+
+ template <ui32 mcost, ui32 threads>
+ class TArgon2REF final: public TArgon2<EInstructionSet::REF, mcost, threads> {
+ public:
+ TArgon2REF(EArgon2Type atype, ui32 tcost, const ui8* key, ui32 keylen)
+ : TArgon2<EInstructionSet::REF, mcost, threads>(atype, tcost, key, keylen)
+ {
+ }
+
+ protected:
+ virtual void XorBlock_(TBlock* dst, const TBlock* src) const override {
+ for (ui32 i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
+ dst->V[i] ^= src->V[i];
+ }
+ }
+
+ virtual void CopyBlock_(TBlock* dst, const TBlock* src) const override {
+ memcpy(dst->V, src->V, sizeof(ui64) * ARGON2_QWORDS_IN_BLOCK);
+ }
+
+ virtual void FillBlock_(const TBlock* prevBlock, const TBlock* refBlock, TBlock* nextBlock, bool withXor) const override {
+ TBlock blockR, blockTmp;
+ CopyBlock_(&blockR, refBlock);
+ XorBlock_(&blockR, prevBlock);
+ CopyBlock_(&blockTmp, &blockR);
+
+ if (withXor) {
+ XorBlock_(&blockTmp, nextBlock);
+ }
+
+ for (ui32 i = 0; i < 8; ++i) {
+ BlamkaRoundRef(
+ blockR.V[16 * i + 0], blockR.V[16 * i + 1], blockR.V[16 * i + 2], blockR.V[16 * i + 3],
+ blockR.V[16 * i + 4], blockR.V[16 * i + 5], blockR.V[16 * i + 6], blockR.V[16 * i + 7],
+ blockR.V[16 * i + 8], blockR.V[16 * i + 9], blockR.V[16 * i + 10], blockR.V[16 * i + 11],
+ blockR.V[16 * i + 12], blockR.V[16 * i + 13], blockR.V[16 * i + 14], blockR.V[16 * i + 15]);
+ }
+
+ for (ui32 i = 0; i < 8; ++i) {
+ BlamkaRoundRef(
+ blockR.V[2 * i + 0], blockR.V[2 * i + 1], blockR.V[2 * i + 16], blockR.V[2 * i + 17],
+ blockR.V[2 * i + 32], blockR.V[2 * i + 33], blockR.V[2 * i + 48], blockR.V[2 * i + 49],
+ blockR.V[2 * i + 64], blockR.V[2 * i + 65], blockR.V[2 * i + 80], blockR.V[2 * i + 81],
+ blockR.V[2 * i + 96], blockR.V[2 * i + 97], blockR.V[2 * i + 112], blockR.V[2 * i + 113]);
+ }
+
+ CopyBlock_(nextBlock, &blockTmp);
+ XorBlock_(nextBlock, &blockR);
+ }
+ };
+}
diff --git a/library/cpp/digest/argonish/internal/argon2/argon2_sse2.h b/library/cpp/digest/argonish/internal/argon2/argon2_sse2.h
new file mode 100644
index 0000000000..1d2230a657
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/argon2/argon2_sse2.h
@@ -0,0 +1,101 @@
+#pragma once
+
+#include <emmintrin.h>
+#include "argon2_base.h"
+#include <library/cpp/digest/argonish/internal/blamka/blamka_sse2.h>
+
+namespace NArgonish {
+ template <ui32 mcost, ui32 threads>
+ class TArgon2SSE2 final: public TArgon2<EInstructionSet::SSE2, mcost, threads> {
+ public:
+ TArgon2SSE2(EArgon2Type atype, ui32 tcost, const ui8* key, ui32 keylen)
+ : TArgon2<EInstructionSet::SSE2, mcost, threads>(atype, tcost, key, keylen)
+ {
+ }
+
+ protected:
+ virtual void XorBlock_(TBlock* dst, const TBlock* src) const override {
+ __m128i* mdst = (__m128i*)dst->V;
+ __m128i* msrc = (__m128i*)src->V;
+
+ for (ui32 i = 0; i < ARGON2_OWORDS_IN_BLOCK; ++i)
+ XorValues(mdst + i, msrc + i, mdst + i);
+ }
+
+ virtual void CopyBlock_(TBlock* dst, const TBlock* src) const override {
+ memcpy(dst->V, src->V, sizeof(ui64) * ARGON2_QWORDS_IN_BLOCK);
+ }
+
+ virtual void FillBlock_(const TBlock* prevBlock, const TBlock* refBlock, TBlock* nextBlock, bool withXor) const override {
+ __m128i blockxy[ARGON2_OWORDS_IN_BLOCK];
+ __m128i state[ARGON2_OWORDS_IN_BLOCK];
+
+ memcpy(state, prevBlock, ARGON2_BLOCK_SIZE);
+
+ if (withXor) {
+ for (ui32 i = 0; i < ARGON2_OWORDS_IN_BLOCK; ++i) {
+ state[i] = _mm_xor_si128(
+ state[i], _mm_loadu_si128((const __m128i*)refBlock->V + i));
+ blockxy[i] = _mm_xor_si128(
+ state[i], _mm_loadu_si128((const __m128i*)nextBlock->V + i));
+ }
+ } else {
+ for (ui32 i = 0; i < ARGON2_OWORDS_IN_BLOCK; ++i) {
+ blockxy[i] = state[i] = _mm_xor_si128(
+ state[i], _mm_loadu_si128((const __m128i*)refBlock->V + i));
+ }
+ }
+
+ for (ui32 i = 0; i < 8; ++i) {
+ BlamkaG1SSE2(
+ state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
+ BlamkaG2SSE2(
+ state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
+ DiagonalizeSSE2(
+ state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5],
+ state[8 * i + 6], state[8 * i + 7]);
+ BlamkaG1SSE2(
+ state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
+ BlamkaG2SSE2(
+ state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
+ UndiagonalizeSSE2(
+ state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5],
+ state[8 * i + 6], state[8 * i + 7]);
+ }
+
+ for (ui32 i = 0; i < 8; ++i) {
+ BlamkaG1SSE2(
+ state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);
+ BlamkaG2SSE2(
+ state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);
+ DiagonalizeSSE2(
+ state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i],
+ state[8 * 6 + i], state[8 * 7 + i]);
+ BlamkaG1SSE2(
+ state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);
+ BlamkaG2SSE2(
+ state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);
+ UndiagonalizeSSE2(
+ state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i],
+ state[8 * 6 + i], state[8 * 7 + i]);
+ }
+
+ for (ui32 i = 0; i < ARGON2_OWORDS_IN_BLOCK; ++i) {
+ state[i] = _mm_xor_si128(state[i], blockxy[i]);
+ _mm_storeu_si128((__m128i*)nextBlock->V + i, state[i]);
+ }
+ }
+ };
+}
diff --git a/library/cpp/digest/argonish/internal/argon2/argon2_sse41.h b/library/cpp/digest/argonish/internal/argon2/argon2_sse41.h
new file mode 100644
index 0000000000..1ad35048ea
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/argon2/argon2_sse41.h
@@ -0,0 +1,101 @@
+#pragma once
+
+#include <smmintrin.h>
+#include "argon2_base.h"
+#include <library/cpp/digest/argonish/internal/blamka/blamka_ssse3.h>
+
+namespace NArgonish {
+ template <ui32 mcost, ui32 threads>
+ class TArgon2SSE41 final: public TArgon2<EInstructionSet::SSE41, mcost, threads> {
+ public:
+ TArgon2SSE41(EArgon2Type atype, ui32 tcost, const ui8* key, ui32 keylen)
+ : TArgon2<EInstructionSet::SSE41, mcost, threads>(atype, tcost, key, keylen)
+ {
+ }
+
+ protected:
+ virtual void XorBlock_(TBlock* dst, const TBlock* src) const override {
+ __m128i* mdst = (__m128i*)dst->V;
+ __m128i* msrc = (__m128i*)src->V;
+
+ for (ui32 i = 0; i < ARGON2_OWORDS_IN_BLOCK; ++i)
+ XorValues(mdst + i, msrc + i, mdst + i);
+ }
+
+ virtual void CopyBlock_(TBlock* dst, const TBlock* src) const override {
+ memcpy(dst->V, src->V, sizeof(ui64) * ARGON2_QWORDS_IN_BLOCK);
+ }
+
+ virtual void FillBlock_(const TBlock* prevBlock, const TBlock* refBlock, TBlock* nextBlock, bool withXor) const override {
+ __m128i blockxy[ARGON2_OWORDS_IN_BLOCK];
+ __m128i state[ARGON2_OWORDS_IN_BLOCK];
+
+ memcpy(state, prevBlock, ARGON2_BLOCK_SIZE);
+
+ if (withXor) {
+ for (ui32 i = 0; i < ARGON2_OWORDS_IN_BLOCK; ++i) {
+ state[i] = _mm_xor_si128(
+ state[i], _mm_loadu_si128((const __m128i*)refBlock->V + i));
+ blockxy[i] = _mm_xor_si128(
+ state[i], _mm_loadu_si128((const __m128i*)nextBlock->V + i));
+ }
+ } else {
+ for (ui32 i = 0; i < ARGON2_OWORDS_IN_BLOCK; ++i) {
+ blockxy[i] = state[i] = _mm_xor_si128(
+ state[i], _mm_loadu_si128((const __m128i*)refBlock->V + i));
+ }
+ }
+
+ for (ui32 i = 0; i < 8; ++i) {
+ BlamkaG1SSSE3(
+ state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
+ BlamkaG2SSSE3(
+ state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
+ DiagonalizeSSSE3(
+ state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5],
+ state[8 * i + 6], state[8 * i + 7]);
+ BlamkaG1SSSE3(
+ state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
+ BlamkaG2SSSE3(
+ state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
+ UndiagonalizeSSSE3(
+ state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5],
+ state[8 * i + 6], state[8 * i + 7]);
+ }
+
+ for (ui32 i = 0; i < 8; ++i) {
+ BlamkaG1SSSE3(
+ state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);
+ BlamkaG2SSSE3(
+ state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);
+ DiagonalizeSSSE3(
+ state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i],
+ state[8 * 6 + i], state[8 * 7 + i]);
+ BlamkaG1SSSE3(
+ state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);
+ BlamkaG2SSSE3(
+ state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);
+ UndiagonalizeSSSE3(
+ state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i],
+ state[8 * 6 + i], state[8 * 7 + i]);
+ }
+
+ for (ui32 i = 0; i < ARGON2_OWORDS_IN_BLOCK; ++i) {
+ state[i] = _mm_xor_si128(state[i], blockxy[i]);
+ _mm_storeu_si128((__m128i*)nextBlock->V + i, state[i]);
+ }
+ }
+ };
+}
diff --git a/library/cpp/digest/argonish/internal/argon2/argon2_ssse3.h b/library/cpp/digest/argonish/internal/argon2/argon2_ssse3.h
new file mode 100644
index 0000000000..a25a416834
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/argon2/argon2_ssse3.h
@@ -0,0 +1,102 @@
+#pragma once
+
+#include <emmintrin.h>
+#include <tmmintrin.h>
+#include "argon2_base.h"
+#include <library/cpp/digest/argonish/internal/blamka/blamka_ssse3.h>
+
+namespace NArgonish {
+ template <ui32 mcost, ui32 threads>
+ class TArgon2SSSE3 final: public TArgon2<EInstructionSet::SSSE3, mcost, threads> {
+ public:
+ TArgon2SSSE3(EArgon2Type atype, ui32 tcost, const ui8* key, ui32 keylen)
+ : TArgon2<EInstructionSet::SSSE3, mcost, threads>(atype, tcost, key, keylen)
+ {
+ }
+
+ protected:
+ virtual void XorBlock_(TBlock* dst, const TBlock* src) const override {
+ __m128i* mdst = (__m128i*)dst->V;
+ __m128i* msrc = (__m128i*)src->V;
+
+ for (ui32 i = 0; i < ARGON2_OWORDS_IN_BLOCK; ++i)
+ XorValues(mdst + i, msrc + i, mdst + i);
+ }
+
+ virtual void CopyBlock_(TBlock* dst, const TBlock* src) const override {
+ memcpy(dst->V, src->V, sizeof(ui64) * ARGON2_QWORDS_IN_BLOCK);
+ }
+
+ virtual void FillBlock_(const TBlock* prevBlock, const TBlock* refBlock, TBlock* nextBlock, bool withXor) const override {
+ __m128i blockxy[ARGON2_OWORDS_IN_BLOCK];
+ __m128i state[ARGON2_OWORDS_IN_BLOCK];
+
+ memcpy(state, prevBlock, ARGON2_BLOCK_SIZE);
+
+ if (withXor) {
+ for (ui32 i = 0; i < ARGON2_OWORDS_IN_BLOCK; ++i) {
+ state[i] = _mm_xor_si128(
+ state[i], _mm_loadu_si128((const __m128i*)refBlock->V + i));
+ blockxy[i] = _mm_xor_si128(
+ state[i], _mm_loadu_si128((const __m128i*)nextBlock->V + i));
+ }
+ } else {
+ for (ui32 i = 0; i < ARGON2_OWORDS_IN_BLOCK; ++i) {
+ blockxy[i] = state[i] = _mm_xor_si128(
+ state[i], _mm_loadu_si128((const __m128i*)refBlock->V + i));
+ }
+ }
+
+ for (ui32 i = 0; i < 8; ++i) {
+ BlamkaG1SSSE3(
+ state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
+ BlamkaG2SSSE3(
+ state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
+ DiagonalizeSSSE3(
+ state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5],
+ state[8 * i + 6], state[8 * i + 7]);
+ BlamkaG1SSSE3(
+ state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
+ BlamkaG2SSSE3(
+ state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]);
+ UndiagonalizeSSSE3(
+ state[8 * i + 2], state[8 * i + 3],
+ state[8 * i + 4], state[8 * i + 5],
+ state[8 * i + 6], state[8 * i + 7]);
+ }
+
+ for (ui32 i = 0; i < 8; ++i) {
+ BlamkaG1SSSE3(
+ state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);
+ BlamkaG2SSSE3(
+ state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);
+ DiagonalizeSSSE3(
+ state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i],
+ state[8 * 6 + i], state[8 * 7 + i]);
+ BlamkaG1SSSE3(
+ state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);
+ BlamkaG2SSSE3(
+ state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i], state[8 * 6 + i], state[8 * 7 + i]);
+ UndiagonalizeSSSE3(
+ state[8 * 2 + i], state[8 * 3 + i],
+ state[8 * 4 + i], state[8 * 5 + i],
+ state[8 * 6 + i], state[8 * 7 + i]);
+ }
+
+ for (ui32 i = 0; i < ARGON2_OWORDS_IN_BLOCK; ++i) {
+ state[i] = _mm_xor_si128(state[i], blockxy[i]);
+ _mm_storeu_si128((__m128i*)nextBlock->V + i, state[i]);
+ }
+ }
+ };
+}
diff --git a/library/cpp/digest/argonish/internal/argon2/ya.make b/library/cpp/digest/argonish/internal/argon2/ya.make
new file mode 100644
index 0000000000..85459865ba
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/argon2/ya.make
@@ -0,0 +1,10 @@
+LIBRARY()
+
+OWNER(e-sidorov)
+
+PEERDIR(
+ library/cpp/digest/argonish/internal/blamka
+ library/cpp/digest/argonish/internal/blake2b
+)
+
+END()
diff --git a/library/cpp/digest/argonish/internal/blake2b/blake2b.h b/library/cpp/digest/argonish/internal/blake2b/blake2b.h
new file mode 100644
index 0000000000..3dcfc3fc48
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/blake2b/blake2b.h
@@ -0,0 +1,187 @@
+#pragma once
+
+#include <util/generic/yexception.h>
+#include <util/system/compiler.h>
+#include <library/cpp/digest/argonish/blake2b.h>
+
+namespace NArgonish {
+ const ui32 BLAKE2B_BLOCKBYTES = 128;
+ const ui32 BLAKE2B_BLOCKQWORDS = BLAKE2B_BLOCKBYTES / 8;
+ const ui32 BLAKE2B_OUTBYTES = 64;
+ const ui32 BLAKE2B_KEYBYTES = 64;
+ const ui32 BLAKE2B_SALTBYTES = 16;
+ const ui32 BLAKE2B_PERSONALBYTES = 16;
+
+ template <NArgonish::EInstructionSet instructionSet>
+ class TBlake2B final: public IBlake2Base {
+ public:
+ virtual ~TBlake2B<instructionSet>() {
+ SecureZeroMemory_((void*)&State_, sizeof(State_));
+ SecureZeroMemory_((void*)&Param_, sizeof(Param_));
+ }
+
+ EInstructionSet GetInstructionSet() {
+ return instructionSet;
+ }
+
+ protected:
+ struct TBlake2BState {
+ ui64 H[8];
+ ui64 T[2];
+ ui64 F[2];
+ ui64 Buf[BLAKE2B_BLOCKQWORDS];
+ size_t BufLen;
+ size_t OutLen;
+ ui8 LastNode;
+ };
+
+ struct TBlake2BParam {
+ ui8 DigestLen; /* 1 */
+ ui8 KeyLen; /* 2 */
+ ui8 Fanout; /* 3 */
+ ui8 Depth; /* 4 */
+ ui32 LeafLength; /* 8 */
+ ui32 NodeOffset; /* 12 */
+ ui32 XofLength; /* 16 */
+ ui8 NodeDepth; /* 17 */
+ ui8 InnerLength; /* 18 */
+ ui8 Reserved[14]; /* 32 */
+ ui8 Salt[BLAKE2B_SALTBYTES]; /* 48 */
+ ui8 Personal[BLAKE2B_PERSONALBYTES]; /* 64 */
+ } Y_PACKED;
+
+ TBlake2BState State_;
+ TBlake2BParam Param_;
+
+ protected:
+ void Compress_(const ui64 block[BLAKE2B_BLOCKQWORDS]);
+ void InitialXor_(ui8* h, const ui8* p);
+ void* GetIV_() const;
+
+ static void SecureZeroMemory_(void* src, size_t len) {
+ static void* (*const volatile memsetv)(void*, int, size_t) = &memset;
+ memsetv(src, 0, len);
+ }
+
+ void InitParam_() {
+ memset(&State_, 0, sizeof(State_));
+ InitialXor_((ui8*)(State_.H), (const ui8*)(&Param_));
+ State_.OutLen = Param_.DigestLen;
+ }
+
+ void IncrementCounter_(const ui64 inc) {
+ State_.T[0] += inc;
+ State_.T[1] += (State_.T[0] < inc) ? 1 : 0;
+ }
+
+ bool IsLastBlock_() {
+ return State_.F[0] != 0;
+ }
+
+ void SetLastNode_() {
+ State_.F[1] = (ui64)-1;
+ }
+
+ void SetLastBlock_() {
+ if (State_.LastNode)
+ SetLastNode_();
+
+ State_.F[0] = (ui64)-1;
+ }
+
+ public:
+ TBlake2B(size_t outlen) {
+ /*
+ * Note that outlen check was moved to proxy class
+ */
+
+ Param_.DigestLen = (ui8)outlen;
+ Param_.KeyLen = 0;
+ Param_.Fanout = 1;
+ Param_.Depth = 1;
+ Param_.LeafLength = 0;
+ Param_.NodeOffset = 0;
+ Param_.XofLength = 0;
+ Param_.NodeDepth = 0;
+ Param_.InnerLength = 0;
+
+ memset(Param_.Reserved, 0, sizeof(Param_.Reserved));
+ memset(Param_.Salt, 0, sizeof(Param_.Salt));
+ memset(Param_.Personal, 0, sizeof(Param_.Personal));
+
+ InitParam_();
+ }
+
+ TBlake2B(size_t outlen, const void* key, size_t keylen) {
+ /**
+ * Note that key and outlen checks were moved to proxy classes
+ */
+ Param_.DigestLen = (ui8)outlen;
+ Param_.KeyLen = (ui8)keylen;
+ Param_.Fanout = 1;
+ Param_.Depth = 1;
+
+ Param_.LeafLength = 0;
+ Param_.NodeOffset = 0;
+ Param_.XofLength = 0;
+ Param_.NodeDepth = 0;
+ Param_.InnerLength = 0;
+
+ memset(Param_.Reserved, 0, sizeof(Param_.Reserved));
+ memset(Param_.Salt, 0, sizeof(Param_.Salt));
+ memset(Param_.Personal, 0, sizeof(Param_.Personal));
+
+ InitParam_();
+ ui8 block[BLAKE2B_BLOCKBYTES] = {0};
+ memcpy(block, key, keylen);
+ Update(block, BLAKE2B_BLOCKBYTES);
+ SecureZeroMemory_(block, BLAKE2B_BLOCKBYTES);
+ }
+
+ void Update(ui32 in) override {
+ Update((const void*)&in, sizeof(in));
+ }
+
+ void Update(const void* pin, size_t inlen) override {
+ const ui8* in = (ui8*)pin;
+ if (inlen > 0) {
+ size_t left = State_.BufLen;
+ size_t fill = BLAKE2B_BLOCKBYTES - left;
+ if (inlen > fill) {
+ State_.BufLen = 0;
+ memcpy((ui8*)State_.Buf + left, in, fill); /* Fill buffer */
+ IncrementCounter_(BLAKE2B_BLOCKBYTES);
+ Compress_(State_.Buf); /* Compress */
+ in += fill;
+ inlen -= fill;
+ while (inlen > BLAKE2B_BLOCKBYTES) {
+ /* to fix ubsan's unaligned report */
+ ui64 tmpbuf[BLAKE2B_BLOCKQWORDS];
+ memcpy(tmpbuf, in, BLAKE2B_BLOCKBYTES);
+
+ IncrementCounter_(BLAKE2B_BLOCKBYTES);
+ Compress_(tmpbuf);
+ in += BLAKE2B_BLOCKBYTES;
+ inlen -= BLAKE2B_BLOCKBYTES;
+ }
+ }
+ memcpy((ui8*)State_.Buf + State_.BufLen, in, inlen);
+ State_.BufLen += inlen;
+ }
+ }
+
+ void Final(void* out, size_t outlen) override {
+ if (out == nullptr || outlen < State_.OutLen)
+ ythrow yexception() << "out is null or outlen is too long";
+
+ if (IsLastBlock_())
+ ythrow yexception() << "Final can't be called several times";
+
+ IncrementCounter_(State_.BufLen);
+ SetLastBlock_();
+ memset((ui8*)State_.Buf + State_.BufLen, 0, BLAKE2B_BLOCKBYTES - State_.BufLen);
+ Compress_(State_.Buf);
+ memcpy(out, (void*)&State_.H[0], outlen);
+ }
+ };
+}
diff --git a/library/cpp/digest/argonish/internal/blake2b/blake2b_avx2.h b/library/cpp/digest/argonish/internal/blake2b/blake2b_avx2.h
new file mode 100644
index 0000000000..359ca90ebb
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/blake2b/blake2b_avx2.h
@@ -0,0 +1,104 @@
+#pragma once
+
+#include <immintrin.h>
+#include "blake2b.h"
+#include <library/cpp/digest/argonish/internal/rotations/rotations_avx2.h>
+
+namespace NArgonish {
+ template <>
+ void* TBlake2B<EInstructionSet::AVX2>::GetIV_() const {
+ static const __m256i Iv[2] = {
+ _mm256_set_epi64x(0xa54ff53a5f1d36f1ULL, 0x3c6ef372fe94f82bULL, 0xbb67ae8584caa73bULL, 0x6a09e667f3bcc908ULL),
+ _mm256_set_epi64x(0x5be0cd19137e2179ULL, 0x1f83d9abfb41bd6bULL, 0x9b05688c2b3e6c1fULL, 0x510e527fade682d1ULL)};
+ return (void*)Iv;
+ }
+
+ template <>
+ void TBlake2B<EInstructionSet::AVX2>::InitialXor_(ui8* h, const ui8* p) {
+ __m256i* iv = (__m256i*)GetIV_();
+ __m256i* m_res = (__m256i*)h;
+ const __m256i* m_second = (__m256i*)p;
+ _mm256_storeu_si256(m_res, _mm256_xor_si256(iv[0], _mm256_loadu_si256(m_second)));
+ _mm256_storeu_si256(m_res + 1, _mm256_xor_si256(iv[1], _mm256_loadu_si256(m_second + 1)));
+ }
+
+ /*
+ * a = v0, v1, v2, v3
+ * b = v4, v5, v6, v7
+ * c = v8, v9, v10, v11
+ * d = v12, v13, v14, v15
+ */
+ static inline void G1AVX2(ui32 r, __m256i& a, __m256i& b, __m256i& c, __m256i& d, const ui64* blk, const __m128i vindex[12][4]) {
+ a = _mm256_add_epi64(a, _mm256_add_epi64(b, _mm256_i32gather_epi64((const long long int*)blk, vindex[r][0], 8)));
+ d = Rotr32(_mm256_xor_si256(a, d));
+ c = _mm256_add_epi64(c, d);
+ b = Rotr24(_mm256_xor_si256(b, c));
+
+ a = _mm256_add_epi64(a, _mm256_add_epi64(b, _mm256_i32gather_epi64((const long long int*)blk, vindex[r][1], 8)));
+ d = Rotr16(_mm256_xor_si256(a, d));
+ c = _mm256_add_epi64(c, d);
+ b = Rotr63(_mm256_xor_si256(b, c));
+ }
+
+ static inline void G2AVX2(ui32 r, __m256i& a, __m256i& b, __m256i& c, __m256i& d, const ui64* blk, const __m128i vindex[12][4]) {
+ a = _mm256_add_epi64(a, _mm256_add_epi64(b, _mm256_i32gather_epi64((const long long int*)blk, vindex[r][2], 8)));
+ d = Rotr32(_mm256_xor_si256(a, d));
+ c = _mm256_add_epi64(c, d);
+ b = Rotr24(_mm256_xor_si256(b, c));
+
+ a = _mm256_add_epi64(a, _mm256_add_epi64(b, _mm256_i32gather_epi64((const long long int*)blk, vindex[r][3], 8)));
+ d = Rotr16(_mm256_xor_si256(a, d));
+ c = _mm256_add_epi64(c, d);
+ b = Rotr63(_mm256_xor_si256(b, c));
+ }
+
+ static inline void Diagonalize(__m256i& b, __m256i& c, __m256i& d) {
+ b = _mm256_permute4x64_epi64(b, _MM_SHUFFLE(0, 3, 2, 1));
+ c = _mm256_permute4x64_epi64(c, _MM_SHUFFLE(1, 0, 3, 2));
+ d = _mm256_permute4x64_epi64(d, _MM_SHUFFLE(2, 1, 0, 3));
+ }
+
+ static inline void Undiagonalize(__m256i& b, __m256i& c, __m256i& d) {
+ b = _mm256_permute4x64_epi64(b, _MM_SHUFFLE(2, 1, 0, 3));
+ c = _mm256_permute4x64_epi64(c, _MM_SHUFFLE(1, 0, 3, 2));
+ d = _mm256_permute4x64_epi64(d, _MM_SHUFFLE(0, 3, 2, 1));
+ }
+
+ template <>
+ void TBlake2B<EInstructionSet::AVX2>::Compress_(const ui64 block[BLAKE2B_BLOCKQWORDS]) {
+ static const __m128i VIndex[12][4] = {
+ {_mm_set_epi32(6, 4, 2, 0), _mm_set_epi32(7, 5, 3, 1), _mm_set_epi32(14, 12, 10, 8), _mm_set_epi32(15, 13, 11, 9)},
+ {_mm_set_epi32(13, 9, 4, 14), _mm_set_epi32(6, 15, 8, 10), _mm_set_epi32(5, 11, 0, 1), _mm_set_epi32(3, 7, 2, 12)},
+ {_mm_set_epi32(15, 5, 12, 11), _mm_set_epi32(13, 2, 0, 8), _mm_set_epi32(9, 7, 3, 10), _mm_set_epi32(4, 1, 6, 14)},
+ {_mm_set_epi32(11, 13, 3, 7), _mm_set_epi32(14, 12, 1, 9), _mm_set_epi32(15, 4, 5, 2), _mm_set_epi32(8, 0, 10, 6)},
+ {_mm_set_epi32(10, 2, 5, 9), _mm_set_epi32(15, 4, 7, 0), _mm_set_epi32(3, 6, 11, 14), _mm_set_epi32(13, 8, 12, 1)},
+ {_mm_set_epi32(8, 0, 6, 2), _mm_set_epi32(3, 11, 10, 12), _mm_set_epi32(1, 15, 7, 4), _mm_set_epi32(9, 14, 5, 13)},
+ {_mm_set_epi32(4, 14, 1, 12), _mm_set_epi32(10, 13, 15, 5), _mm_set_epi32(8, 9, 6, 0), _mm_set_epi32(11, 2, 3, 7)},
+ {_mm_set_epi32(3, 12, 7, 13), _mm_set_epi32(9, 1, 14, 11), _mm_set_epi32(2, 8, 15, 5), _mm_set_epi32(10, 6, 4, 0)},
+ {_mm_set_epi32(0, 11, 14, 6), _mm_set_epi32(8, 3, 9, 15), _mm_set_epi32(10, 1, 13, 12), _mm_set_epi32(5, 4, 7, 2)},
+ {_mm_set_epi32(1, 7, 8, 10), _mm_set_epi32(5, 6, 4, 2), _mm_set_epi32(13, 3, 9, 15), _mm_set_epi32(0, 12, 14, 11)},
+ {_mm_set_epi32(6, 4, 2, 0), _mm_set_epi32(7, 5, 3, 1), _mm_set_epi32(14, 12, 10, 8), _mm_set_epi32(15, 13, 11, 9)},
+ {_mm_set_epi32(13, 9, 4, 14), _mm_set_epi32(6, 15, 8, 10), _mm_set_epi32(5, 11, 0, 1), _mm_set_epi32(3, 7, 2, 12)},
+ };
+
+ __m256i* iv = (__m256i*)GetIV_();
+ __m256i a = _mm256_loadu_si256((__m256i*)&State_.H[0]);
+ __m256i b = _mm256_loadu_si256((__m256i*)&State_.H[4]);
+ __m256i c = iv[0];
+ __m256i d = _mm256_xor_si256(iv[1], _mm256_loadu_si256((__m256i*)&State_.T[0]));
+
+ for (ui32 r = 0; r < 12; ++r) {
+ G1AVX2(r, a, b, c, d, block, VIndex);
+ Diagonalize(b, c, d);
+ G2AVX2(r, a, b, c, d, block, VIndex);
+ Undiagonalize(b, c, d);
+ }
+
+ _mm256_storeu_si256((__m256i*)State_.H, _mm256_xor_si256(
+ _mm256_loadu_si256((__m256i*)State_.H),
+ _mm256_xor_si256(a, c)));
+ _mm256_storeu_si256(((__m256i*)State_.H) + 1, _mm256_xor_si256(
+ _mm256_loadu_si256(((__m256i*)State_.H) + 1),
+ _mm256_xor_si256(b, d)));
+ }
+}
diff --git a/library/cpp/digest/argonish/internal/blake2b/blake2b_ref.h b/library/cpp/digest/argonish/internal/blake2b/blake2b_ref.h
new file mode 100644
index 0000000000..ef98ed8fc8
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/blake2b/blake2b_ref.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#include "blake2b.h"
+#include <library/cpp/digest/argonish/internal/rotations/rotations_ref.h>
+
+namespace NArgonish {
+ static const ui8 Sigma[12][16] = {
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+ {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
+ {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
+ {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
+ {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
+ {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
+ {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
+ {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
+ {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
+ {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+ {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}};
+
+ static const ui64 Iv[8] = {
+ 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
+ 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
+ 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
+ 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL};
+
+ static inline void GRef(ui64 r, ui64 i, ui64& a, ui64& b, ui64& c, ui64& d, const ui64* m) {
+ a = a + b + m[Sigma[r][2 * i + 0]];
+ d = Rotr(d ^ a, 32);
+ c = c + d;
+ b = Rotr(b ^ c, 24);
+ a = a + b + m[Sigma[r][2 * i + 1]];
+ d = Rotr(d ^ a, 16);
+ c = c + d;
+ b = Rotr(b ^ c, 63);
+ }
+
+ static inline void Round(ui64 r, ui64* v, const ui64* m) {
+ GRef(r, 0, v[0], v[4], v[8], v[12], m);
+ GRef(r, 1, v[1], v[5], v[9], v[13], m);
+ GRef(r, 2, v[2], v[6], v[10], v[14], m);
+ GRef(r, 3, v[3], v[7], v[11], v[15], m);
+ GRef(r, 4, v[0], v[5], v[10], v[15], m);
+ GRef(r, 5, v[1], v[6], v[11], v[12], m);
+ GRef(r, 6, v[2], v[7], v[8], v[13], m);
+ GRef(r, 7, v[3], v[4], v[9], v[14], m);
+ }
+
+ template <>
+ void* TBlake2B<EInstructionSet::REF>::GetIV_() const {
+ return nullptr;
+ }
+
+ template <>
+ void TBlake2B<EInstructionSet::REF>::InitialXor_(ui8* h, const ui8* p) {
+ for (size_t i = 0; i < 8; ++i)
+ ((ui64*)h)[i] = Iv[i] ^ ((ui64*)p)[i];
+ }
+
+ template <>
+ void TBlake2B<EInstructionSet::REF>::Compress_(const ui64 block[BLAKE2B_BLOCKQWORDS]) {
+ ui64 v[16];
+ for (size_t i = 0; i < 8; ++i) {
+ v[i] = State_.H[i];
+ }
+
+ v[8] = Iv[0];
+ v[9] = Iv[1];
+ v[10] = Iv[2];
+ v[11] = Iv[3];
+ v[12] = Iv[4] ^ State_.T[0];
+ v[13] = Iv[5] ^ State_.T[1];
+ v[14] = Iv[6] ^ State_.F[0];
+ v[15] = Iv[7] ^ State_.F[1];
+
+ for (ui64 r = 0; r < 12; ++r)
+ Round(r, v, block);
+
+ for (size_t i = 0; i < 8; ++i) {
+ State_.H[i] = State_.H[i] ^ v[i] ^ v[i + 8];
+ }
+ }
+}
diff --git a/library/cpp/digest/argonish/internal/blake2b/blake2b_sse2.h b/library/cpp/digest/argonish/internal/blake2b/blake2b_sse2.h
new file mode 100644
index 0000000000..e85a78044c
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/blake2b/blake2b_sse2.h
@@ -0,0 +1,163 @@
+#pragma once
+
+#include <emmintrin.h>
+#include "blake2b.h"
+#include <library/cpp/digest/argonish/internal/rotations/rotations_sse2.h>
+
+namespace NArgonish {
+ template <>
+ void* TBlake2B<EInstructionSet::SSE2>::GetIV_() const {
+ static const __m128i Iv[4] = {
+ _mm_set_epi64x(0xbb67ae8584caa73bULL, 0x6a09e667f3bcc908ULL),
+ _mm_set_epi64x(0xa54ff53a5f1d36f1ULL, 0x3c6ef372fe94f82bULL),
+ _mm_set_epi64x(0x9b05688c2b3e6c1fULL, 0x510e527fade682d1ULL),
+ _mm_set_epi64x(0x5be0cd19137e2179ULL, 0x1f83d9abfb41bd6bULL)};
+
+ return (void*)Iv;
+ }
+
+ static const ui32 Sigma[12][16] = {
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+ {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
+ {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
+ {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
+ {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
+ {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
+ {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
+ {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
+ {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
+ {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+ {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}};
+
+ static inline void G1(
+ __m128i& row1l, __m128i& row2l, __m128i& row3l, __m128i& row4l,
+ __m128i& row1h, __m128i& row2h, __m128i& row3h, __m128i& row4h,
+ __m128i& b0, __m128i& b1) {
+ row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l);
+ row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h);
+
+ row4l = _mm_xor_si128(row4l, row1l);
+ row4h = _mm_xor_si128(row4h, row1h);
+
+ row4l = Rotr32(row4l);
+ row4h = Rotr32(row4h);
+
+ row3l = _mm_add_epi64(row3l, row4l);
+ row3h = _mm_add_epi64(row3h, row4h);
+
+ row2l = _mm_xor_si128(row2l, row3l);
+ row2h = _mm_xor_si128(row2h, row3h);
+
+ row2l = Rotr24(row2l);
+ row2h = Rotr24(row2h);
+ }
+
+ static inline void G2(
+ __m128i& row1l, __m128i& row2l, __m128i& row3l, __m128i& row4l,
+ __m128i& row1h, __m128i& row2h, __m128i& row3h, __m128i& row4h,
+ __m128i& b0, __m128i& b1) {
+ row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l);
+ row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h);
+
+ row4l = _mm_xor_si128(row4l, row1l);
+ row4h = _mm_xor_si128(row4h, row1h);
+
+ row4l = Rotr16(row4l);
+ row4h = Rotr16(row4h);
+
+ row3l = _mm_add_epi64(row3l, row4l);
+ row3h = _mm_add_epi64(row3h, row4h);
+
+ row2l = _mm_xor_si128(row2l, row3l);
+ row2h = _mm_xor_si128(row2h, row3h);
+
+ row2l = Rotr63(row2l);
+ row2h = Rotr63(row2h);
+ }
+
+ static inline void Diagonalize(
+ __m128i& row2l, __m128i& row3l, __m128i& row4l,
+ __m128i& row2h, __m128i& row3h, __m128i& row4h) {
+ __m128i t0 = row4l;
+ __m128i t1 = row2l;
+ row4l = row3l;
+ row3l = row3h;
+ row3h = row4l;
+ row4l = _mm_unpackhi_epi64(row4h, _mm_unpacklo_epi64(t0, t0));
+ row4h = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(row4h, row4h));
+ row2l = _mm_unpackhi_epi64(row2l, _mm_unpacklo_epi64(row2h, row2h));
+ row2h = _mm_unpackhi_epi64(row2h, _mm_unpacklo_epi64(t1, t1));
+ }
+
+ static inline void Undiagonalize(
+ __m128i& row2l, __m128i& row3l, __m128i& row4l,
+ __m128i& row2h, __m128i& row3h, __m128i& row4h) {
+ __m128i t0 = row3l;
+ row3l = row3h;
+ row3h = t0;
+ t0 = row2l;
+ __m128i t1 = row4l;
+ row2l = _mm_unpackhi_epi64(row2h, _mm_unpacklo_epi64(row2l, row2l));
+ row2h = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(row2h, row2h));
+ row4l = _mm_unpackhi_epi64(row4l, _mm_unpacklo_epi64(row4h, row4h));
+ row4h = _mm_unpackhi_epi64(row4h, _mm_unpacklo_epi64(t1, t1));
+ }
+
+ static inline void Round(int r, const ui64* block_ptr,
+ __m128i& row1l, __m128i& row2l, __m128i& row3l, __m128i& row4l,
+ __m128i& row1h, __m128i& row2h, __m128i& row3h, __m128i& row4h) {
+ __m128i b0, b1;
+ b0 = _mm_set_epi64x(block_ptr[Sigma[r][2]], block_ptr[Sigma[r][0]]);
+ b1 = _mm_set_epi64x(block_ptr[Sigma[r][6]], block_ptr[Sigma[r][4]]);
+ G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1);
+ b0 = _mm_set_epi64x(block_ptr[Sigma[r][3]], block_ptr[Sigma[r][1]]);
+ b1 = _mm_set_epi64x(block_ptr[Sigma[r][7]], block_ptr[Sigma[r][5]]);
+ G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1);
+ Diagonalize(row2l, row3l, row4l, row2h, row3h, row4h);
+ b0 = _mm_set_epi64x(block_ptr[Sigma[r][10]], block_ptr[Sigma[r][8]]);
+ b1 = _mm_set_epi64x(block_ptr[Sigma[r][14]], block_ptr[Sigma[r][12]]);
+ G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1);
+ b0 = _mm_set_epi64x(block_ptr[Sigma[r][11]], block_ptr[Sigma[r][9]]);
+ b1 = _mm_set_epi64x(block_ptr[Sigma[r][15]], block_ptr[Sigma[r][13]]);
+ G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1);
+ Undiagonalize(row2l, row3l, row4l, row2h, row3h, row4h);
+ }
+
+ template <>
+ void TBlake2B<EInstructionSet::SSE2>::InitialXor_(ui8* h, const ui8* p) {
+ __m128i* m_res = (__m128i*)h;
+ const __m128i* m_p = (__m128i*)p;
+ __m128i* iv = (__m128i*)GetIV_();
+
+ _mm_storeu_si128(m_res + 0, _mm_xor_si128(iv[0], _mm_loadu_si128(m_p + 0)));
+ _mm_storeu_si128(m_res + 1, _mm_xor_si128(iv[1], _mm_loadu_si128(m_p + 1)));
+ _mm_storeu_si128(m_res + 2, _mm_xor_si128(iv[2], _mm_loadu_si128(m_p + 2)));
+ _mm_storeu_si128(m_res + 3, _mm_xor_si128(iv[3], _mm_loadu_si128(m_p + 3)));
+ }
+
+ template <>
+ void TBlake2B<EInstructionSet::SSE2>::Compress_(const ui64 block[BLAKE2B_BLOCKQWORDS]) {
+ __m128i* iv = (__m128i*)GetIV_();
+ __m128i row1l = _mm_loadu_si128((__m128i*)&State_.H[0]);
+ __m128i row1h = _mm_loadu_si128((__m128i*)&State_.H[2]);
+ __m128i row2l = _mm_loadu_si128((__m128i*)&State_.H[4]);
+ __m128i row2h = _mm_loadu_si128((__m128i*)&State_.H[6]);
+ __m128i row3l = iv[0];
+ __m128i row3h = iv[1];
+ __m128i row4l = _mm_xor_si128(iv[2], _mm_loadu_si128((__m128i*)&State_.T[0]));
+ __m128i row4h = _mm_xor_si128(iv[3], _mm_loadu_si128((__m128i*)&State_.F[0]));
+
+ for (int r = 0; r < 12; r++)
+ Round(r, block, row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h);
+
+ _mm_storeu_si128((__m128i*)&State_.H[0],
+ _mm_xor_si128(_mm_loadu_si128((__m128i*)&State_.H[0]), _mm_xor_si128(row3l, row1l)));
+ _mm_storeu_si128((__m128i*)&State_.H[2],
+ _mm_xor_si128(_mm_loadu_si128((__m128i*)&State_.H[2]), _mm_xor_si128(row3h, row1h)));
+ _mm_storeu_si128((__m128i*)&State_.H[4],
+ _mm_xor_si128(_mm_loadu_si128((__m128i*)&State_.H[4]), _mm_xor_si128(row4l, row2l)));
+ _mm_storeu_si128((__m128i*)&State_.H[6],
+ _mm_xor_si128(_mm_loadu_si128((__m128i*)&State_.H[6]), _mm_xor_si128(row4h, row2h)));
+ }
+}
diff --git a/library/cpp/digest/argonish/internal/blake2b/blake2b_sse41.h b/library/cpp/digest/argonish/internal/blake2b/blake2b_sse41.h
new file mode 100644
index 0000000000..1a033bcceb
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/blake2b/blake2b_sse41.h
@@ -0,0 +1,172 @@
+#pragma once
+
+#include <smmintrin.h>
+#include "blake2b.h"
+#include "load_sse41.h"
+#include <library/cpp/digest/argonish/internal/rotations/rotations_ssse3.h>
+
+namespace NArgonish {
+ template <>
+ void* TBlake2B<EInstructionSet::SSE41>::GetIV_() const {
+ static const __m128i Iv[4] = {
+ _mm_set_epi64x(0xbb67ae8584caa73bULL, 0x6a09e667f3bcc908ULL),
+ _mm_set_epi64x(0xa54ff53a5f1d36f1ULL, 0x3c6ef372fe94f82bULL),
+ _mm_set_epi64x(0x9b05688c2b3e6c1fULL, 0x510e527fade682d1ULL),
+ _mm_set_epi64x(0x5be0cd19137e2179ULL, 0x1f83d9abfb41bd6bULL)};
+ return (void*)Iv;
+ }
+
+ static inline void G1(
+ __m128i& row1l, __m128i& row2l, __m128i& row3l, __m128i& row4l,
+ __m128i& row1h, __m128i& row2h, __m128i& row3h, __m128i& row4h,
+ __m128i& b0, __m128i& b1) {
+ row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l);
+ row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h);
+
+ row4l = _mm_xor_si128(row4l, row1l);
+ row4h = _mm_xor_si128(row4h, row1h);
+
+ row4l = Rotr32(row4l);
+ row4h = Rotr32(row4h);
+
+ row3l = _mm_add_epi64(row3l, row4l);
+ row3h = _mm_add_epi64(row3h, row4h);
+
+ row2l = _mm_xor_si128(row2l, row3l);
+ row2h = _mm_xor_si128(row2h, row3h);
+
+ row2l = Rotr24(row2l);
+ row2h = Rotr24(row2h);
+ }
+
+ static inline void G2(
+ __m128i& row1l, __m128i& row2l, __m128i& row3l, __m128i& row4l,
+ __m128i& row1h, __m128i& row2h, __m128i& row3h, __m128i& row4h,
+ __m128i& b0, __m128i& b1) {
+ row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l);
+ row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h);
+
+ row4l = _mm_xor_si128(row4l, row1l);
+ row4h = _mm_xor_si128(row4h, row1h);
+
+ row4l = Rotr16(row4l);
+ row4h = Rotr16(row4h);
+
+ row3l = _mm_add_epi64(row3l, row4l);
+ row3h = _mm_add_epi64(row3h, row4h);
+
+ row2l = _mm_xor_si128(row2l, row3l);
+ row2h = _mm_xor_si128(row2h, row3h);
+
+ row2l = Rotr63(row2l);
+ row2h = Rotr63(row2h);
+ }
+
+ static inline void Diagonalize(
+ __m128i& row2l, __m128i& row3l, __m128i& row4l,
+ __m128i& row2h, __m128i& row3h, __m128i& row4h) {
+ __m128i t0 = _mm_alignr_epi8(row2h, row2l, 8);
+ __m128i t1 = _mm_alignr_epi8(row2l, row2h, 8);
+ row2l = t0;
+ row2h = t1;
+
+ t0 = row3l;
+ row3l = row3h;
+ row3h = t0;
+
+ t0 = _mm_alignr_epi8(row4h, row4l, 8);
+ t1 = _mm_alignr_epi8(row4l, row4h, 8);
+ row4l = t1;
+ row4h = t0;
+ }
+
+ static inline void Undiagonalize(
+ __m128i& row2l, __m128i& row3l, __m128i& row4l,
+ __m128i& row2h, __m128i& row3h, __m128i& row4h) {
+ __m128i t0 = _mm_alignr_epi8(row2l, row2h, 8);
+ __m128i t1 = _mm_alignr_epi8(row2h, row2l, 8);
+ row2l = t0;
+ row2h = t1;
+
+ t0 = row3l;
+ row3l = row3h;
+ row3h = t0;
+
+ t0 = _mm_alignr_epi8(row4l, row4h, 8);
+ t1 = _mm_alignr_epi8(row4h, row4l, 8);
+ row4l = t1;
+ row4h = t0;
+ }
+
+#define ROUND(r) \
+ LOAD_MSG_##r##_1(b0, b1); \
+ G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1); \
+ LOAD_MSG_##r##_2(b0, b1); \
+ G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1); \
+ Diagonalize(row2l, row3l, row4l, row2h, row3h, row4h); \
+ LOAD_MSG_##r##_3(b0, b1); \
+ G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1); \
+ LOAD_MSG_##r##_4(b0, b1); \
+ G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1); \
+ Undiagonalize(row2l, row3l, row4l, row2h, row3h, row4h);
+
+ template <>
+ void TBlake2B<EInstructionSet::SSE41>::InitialXor_(ui8* h, const ui8* p) {
+ __m128i* m_res = (__m128i*)h;
+ const __m128i* m_p = (__m128i*)p;
+ __m128i* iv = (__m128i*)GetIV_();
+
+ _mm_storeu_si128(m_res + 0, _mm_xor_si128(iv[0], _mm_loadu_si128(m_p + 0)));
+ _mm_storeu_si128(m_res + 1, _mm_xor_si128(iv[1], _mm_loadu_si128(m_p + 1)));
+ _mm_storeu_si128(m_res + 2, _mm_xor_si128(iv[2], _mm_loadu_si128(m_p + 2)));
+ _mm_storeu_si128(m_res + 3, _mm_xor_si128(iv[3], _mm_loadu_si128(m_p + 3)));
+ }
+
+ template <>
+ void TBlake2B<EInstructionSet::SSE41>::Compress_(const ui64 block[BLAKE2B_BLOCKQWORDS]) {
+ const __m128i* block_ptr = (__m128i*)block;
+ __m128i* iv = (__m128i*)GetIV_();
+ const __m128i m0 = _mm_loadu_si128(block_ptr + 0);
+ const __m128i m1 = _mm_loadu_si128(block_ptr + 1);
+ const __m128i m2 = _mm_loadu_si128(block_ptr + 2);
+ const __m128i m3 = _mm_loadu_si128(block_ptr + 3);
+ const __m128i m4 = _mm_loadu_si128(block_ptr + 4);
+ const __m128i m5 = _mm_loadu_si128(block_ptr + 5);
+ const __m128i m6 = _mm_loadu_si128(block_ptr + 6);
+ const __m128i m7 = _mm_loadu_si128(block_ptr + 7);
+
+ __m128i row1l = _mm_loadu_si128((__m128i*)&State_.H[0]);
+ __m128i row1h = _mm_loadu_si128((__m128i*)&State_.H[2]);
+ __m128i row2l = _mm_loadu_si128((__m128i*)&State_.H[4]);
+ __m128i row2h = _mm_loadu_si128((__m128i*)&State_.H[6]);
+ __m128i row3l = iv[0];
+ __m128i row3h = iv[1];
+ __m128i row4l = _mm_xor_si128(iv[2], _mm_loadu_si128((__m128i*)&State_.T[0]));
+ __m128i row4h = _mm_xor_si128(iv[3], _mm_loadu_si128((__m128i*)&State_.F[0]));
+ __m128i b0, b1;
+
+ ROUND(0);
+ ROUND(1);
+ ROUND(2);
+ ROUND(3);
+ ROUND(4);
+ ROUND(5);
+ ROUND(6);
+ ROUND(7);
+ ROUND(8);
+ ROUND(9);
+ ROUND(10);
+ ROUND(11);
+
+ _mm_storeu_si128((__m128i*)&State_.H[0],
+ _mm_xor_si128(_mm_loadu_si128((__m128i*)&State_.H[0]), _mm_xor_si128(row3l, row1l)));
+ _mm_storeu_si128((__m128i*)&State_.H[2],
+ _mm_xor_si128(_mm_loadu_si128((__m128i*)&State_.H[2]), _mm_xor_si128(row3h, row1h)));
+ _mm_storeu_si128((__m128i*)&State_.H[4],
+ _mm_xor_si128(_mm_loadu_si128((__m128i*)&State_.H[4]), _mm_xor_si128(row4l, row2l)));
+ _mm_storeu_si128((__m128i*)&State_.H[6],
+ _mm_xor_si128(_mm_loadu_si128((__m128i*)&State_.H[6]), _mm_xor_si128(row4h, row2h)));
+ }
+
+#undef ROUND
+}
diff --git a/library/cpp/digest/argonish/internal/blake2b/blake2b_ssse3.h b/library/cpp/digest/argonish/internal/blake2b/blake2b_ssse3.h
new file mode 100644
index 0000000000..4cca5a5e7f
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/blake2b/blake2b_ssse3.h
@@ -0,0 +1,171 @@
+#pragma once
+
+#include <emmintrin.h>
+#include <tmmintrin.h>
+#include "blake2b.h"
+#include <library/cpp/digest/argonish/internal/rotations/rotations_ssse3.h>
+
+namespace NArgonish {
+ template <>
+ void* TBlake2B<EInstructionSet::SSSE3>::GetIV_() const {
+ static const __m128i Iv[4] = {
+ _mm_set_epi64x(0xbb67ae8584caa73bULL, 0x6a09e667f3bcc908ULL),
+ _mm_set_epi64x(0xa54ff53a5f1d36f1ULL, 0x3c6ef372fe94f82bULL),
+ _mm_set_epi64x(0x9b05688c2b3e6c1fULL, 0x510e527fade682d1ULL),
+ _mm_set_epi64x(0x5be0cd19137e2179ULL, 0x1f83d9abfb41bd6bULL)};
+ return (void*)Iv;
+ }
+
+ static const ui32 Sigma[12][16] = {
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+ {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
+ {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
+ {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
+ {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
+ {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
+ {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
+ {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
+ {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
+ {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+ {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}};
+
+ static inline void G1(
+ __m128i& row1l, __m128i& row2l, __m128i& row3l, __m128i& row4l,
+ __m128i& row1h, __m128i& row2h, __m128i& row3h, __m128i& row4h,
+ __m128i& b0, __m128i& b1) {
+ row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l);
+ row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h);
+
+ row4l = _mm_xor_si128(row4l, row1l);
+ row4h = _mm_xor_si128(row4h, row1h);
+
+ row4l = Rotr32(row4l);
+ row4h = Rotr32(row4h);
+
+ row3l = _mm_add_epi64(row3l, row4l);
+ row3h = _mm_add_epi64(row3h, row4h);
+
+ row2l = _mm_xor_si128(row2l, row3l);
+ row2h = _mm_xor_si128(row2h, row3h);
+
+ row2l = Rotr24(row2l);
+ row2h = Rotr24(row2h);
+ }
+
+ static inline void G2(
+ __m128i& row1l, __m128i& row2l, __m128i& row3l, __m128i& row4l,
+ __m128i& row1h, __m128i& row2h, __m128i& row3h, __m128i& row4h,
+ __m128i& b0, __m128i& b1) {
+ row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l);
+ row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h);
+
+ row4l = _mm_xor_si128(row4l, row1l);
+ row4h = _mm_xor_si128(row4h, row1h);
+
+ row4l = Rotr16(row4l);
+ row4h = Rotr16(row4h);
+
+ row3l = _mm_add_epi64(row3l, row4l);
+ row3h = _mm_add_epi64(row3h, row4h);
+
+ row2l = _mm_xor_si128(row2l, row3l);
+ row2h = _mm_xor_si128(row2h, row3h);
+
+ row2l = Rotr63(row2l);
+ row2h = Rotr63(row2h);
+ }
+
+ static inline void Diagonalize(
+ __m128i& row2l, __m128i& row3l, __m128i& row4l,
+ __m128i& row2h, __m128i& row3h, __m128i& row4h) {
+ __m128i t0 = _mm_alignr_epi8(row2h, row2l, 8);
+ __m128i t1 = _mm_alignr_epi8(row2l, row2h, 8);
+ row2l = t0;
+ row2h = t1;
+
+ t0 = row3l;
+ row3l = row3h;
+ row3h = t0;
+
+ t0 = _mm_alignr_epi8(row4h, row4l, 8);
+ t1 = _mm_alignr_epi8(row4l, row4h, 8);
+ row4l = t1;
+ row4h = t0;
+ }
+
+ static inline void Undiagonalize(
+ __m128i& row2l, __m128i& row3l, __m128i& row4l,
+ __m128i& row2h, __m128i& row3h, __m128i& row4h) {
+ __m128i t0 = _mm_alignr_epi8(row2l, row2h, 8);
+ __m128i t1 = _mm_alignr_epi8(row2h, row2l, 8);
+ row2l = t0;
+ row2h = t1;
+
+ t0 = row3l;
+ row3l = row3h;
+ row3h = t0;
+
+ t0 = _mm_alignr_epi8(row4l, row4h, 8);
+ t1 = _mm_alignr_epi8(row4h, row4l, 8);
+ row4l = t1;
+ row4h = t0;
+ }
+
+ static inline void Round(int r, const ui64* block_ptr,
+ __m128i& row1l, __m128i& row2l, __m128i& row3l, __m128i& row4l,
+ __m128i& row1h, __m128i& row2h, __m128i& row3h, __m128i& row4h) {
+ __m128i b0, b1;
+ b0 = _mm_set_epi64x(block_ptr[Sigma[r][2]], block_ptr[Sigma[r][0]]);
+ b1 = _mm_set_epi64x(block_ptr[Sigma[r][6]], block_ptr[Sigma[r][4]]);
+ G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1);
+ b0 = _mm_set_epi64x(block_ptr[Sigma[r][3]], block_ptr[Sigma[r][1]]);
+ b1 = _mm_set_epi64x(block_ptr[Sigma[r][7]], block_ptr[Sigma[r][5]]);
+ G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1);
+ Diagonalize(row2l, row3l, row4l, row2h, row3h, row4h);
+ b0 = _mm_set_epi64x(block_ptr[Sigma[r][10]], block_ptr[Sigma[r][8]]);
+ b1 = _mm_set_epi64x(block_ptr[Sigma[r][14]], block_ptr[Sigma[r][12]]);
+ G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1);
+ b0 = _mm_set_epi64x(block_ptr[Sigma[r][11]], block_ptr[Sigma[r][9]]);
+ b1 = _mm_set_epi64x(block_ptr[Sigma[r][15]], block_ptr[Sigma[r][13]]);
+ G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1);
+ Undiagonalize(row2l, row3l, row4l, row2h, row3h, row4h);
+ }
+
+ template <>
+ void TBlake2B<EInstructionSet::SSSE3>::InitialXor_(ui8* h, const ui8* p) {
+ __m128i* m_res = (__m128i*)h;
+ const __m128i* m_p = (__m128i*)p;
+ __m128i* iv = (__m128i*)GetIV_();
+
+ _mm_storeu_si128(m_res + 0, _mm_xor_si128(iv[0], _mm_loadu_si128(m_p + 0)));
+ _mm_storeu_si128(m_res + 1, _mm_xor_si128(iv[1], _mm_loadu_si128(m_p + 1)));
+ _mm_storeu_si128(m_res + 2, _mm_xor_si128(iv[2], _mm_loadu_si128(m_p + 2)));
+ _mm_storeu_si128(m_res + 3, _mm_xor_si128(iv[3], _mm_loadu_si128(m_p + 3)));
+ }
+
+ template <>
+ void TBlake2B<EInstructionSet::SSSE3>::Compress_(const ui64 block[BLAKE2B_BLOCKQWORDS]) {
+ __m128i* iv = (__m128i*)GetIV_();
+ __m128i row1l = _mm_loadu_si128((__m128i*)&State_.H[0]);
+ __m128i row1h = _mm_loadu_si128((__m128i*)&State_.H[2]);
+ __m128i row2l = _mm_loadu_si128((__m128i*)&State_.H[4]);
+ __m128i row2h = _mm_loadu_si128((__m128i*)&State_.H[6]);
+ __m128i row3l = iv[0];
+ __m128i row3h = iv[1];
+ __m128i row4l = _mm_xor_si128(iv[2], _mm_loadu_si128((__m128i*)&State_.T[0]));
+ __m128i row4h = _mm_xor_si128(iv[3], _mm_loadu_si128((__m128i*)&State_.F[0]));
+
+ for (int r = 0; r < 12; ++r)
+ Round(r, block, row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h);
+
+ _mm_storeu_si128((__m128i*)&State_.H[0],
+ _mm_xor_si128(_mm_loadu_si128((__m128i*)&State_.H[0]), _mm_xor_si128(row3l, row1l)));
+ _mm_storeu_si128((__m128i*)&State_.H[2],
+ _mm_xor_si128(_mm_loadu_si128((__m128i*)&State_.H[2]), _mm_xor_si128(row3h, row1h)));
+ _mm_storeu_si128((__m128i*)&State_.H[4],
+ _mm_xor_si128(_mm_loadu_si128((__m128i*)&State_.H[4]), _mm_xor_si128(row4l, row2l)));
+ _mm_storeu_si128((__m128i*)&State_.H[6],
+ _mm_xor_si128(_mm_loadu_si128((__m128i*)&State_.H[6]), _mm_xor_si128(row4h, row2h)));
+ }
+}
diff --git a/library/cpp/digest/argonish/internal/blake2b/load_sse41.h b/library/cpp/digest/argonish/internal/blake2b/load_sse41.h
new file mode 100644
index 0000000000..060455aac2
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/blake2b/load_sse41.h
@@ -0,0 +1,301 @@
+#pragma once
+
+/*
+ BLAKE2 reference source code package - optimized C implementations
+ Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
+ terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
+ your option. The terms of these licenses can be found at:
+ - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ - OpenSSL license : https://www.openssl.org/source/license.html
+ - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
+ More information about the BLAKE2 hash function can be found at
+ https://blake2.net.
+*/
+
+#define LOAD_MSG_0_1(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m0, m1); \
+ b1 = _mm_unpacklo_epi64(m2, m3); \
+ } while (0)
+
+#define LOAD_MSG_0_2(b0, b1) \
+ do { \
+ b0 = _mm_unpackhi_epi64(m0, m1); \
+ b1 = _mm_unpackhi_epi64(m2, m3); \
+ } while (0)
+
+#define LOAD_MSG_0_3(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m4, m5); \
+ b1 = _mm_unpacklo_epi64(m6, m7); \
+ } while (0)
+
+#define LOAD_MSG_0_4(b0, b1) \
+ do { \
+ b0 = _mm_unpackhi_epi64(m4, m5); \
+ b1 = _mm_unpackhi_epi64(m6, m7); \
+ } while (0)
+
+#define LOAD_MSG_1_1(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m7, m2); \
+ b1 = _mm_unpackhi_epi64(m4, m6); \
+ } while (0)
+
+#define LOAD_MSG_1_2(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m5, m4); \
+ b1 = _mm_alignr_epi8(m3, m7, 8); \
+ } while (0)
+
+#define LOAD_MSG_1_3(b0, b1) \
+ do { \
+ b0 = _mm_shuffle_epi32(m0, _MM_SHUFFLE(1, 0, 3, 2)); \
+ b1 = _mm_unpackhi_epi64(m5, m2); \
+ } while (0)
+
+#define LOAD_MSG_1_4(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m6, m1); \
+ b1 = _mm_unpackhi_epi64(m3, m1); \
+ } while (0)
+
+#define LOAD_MSG_2_1(b0, b1) \
+ do { \
+ b0 = _mm_alignr_epi8(m6, m5, 8); \
+ b1 = _mm_unpackhi_epi64(m2, m7); \
+ } while (0)
+
+#define LOAD_MSG_2_2(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m4, m0); \
+ b1 = _mm_blend_epi16(m1, m6, 0xF0); \
+ } while (0)
+
+#define LOAD_MSG_2_3(b0, b1) \
+ do { \
+ b0 = _mm_blend_epi16(m5, m1, 0xF0); \
+ b1 = _mm_unpackhi_epi64(m3, m4); \
+ } while (0)
+
+#define LOAD_MSG_2_4(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m7, m3); \
+ b1 = _mm_alignr_epi8(m2, m0, 8); \
+ } while (0)
+
+#define LOAD_MSG_3_1(b0, b1) \
+ do { \
+ b0 = _mm_unpackhi_epi64(m3, m1); \
+ b1 = _mm_unpackhi_epi64(m6, m5); \
+ } while (0)
+
+#define LOAD_MSG_3_2(b0, b1) \
+ do { \
+ b0 = _mm_unpackhi_epi64(m4, m0); \
+ b1 = _mm_unpacklo_epi64(m6, m7); \
+ } while (0)
+
+#define LOAD_MSG_3_3(b0, b1) \
+ do { \
+ b0 = _mm_blend_epi16(m1, m2, 0xF0); \
+ b1 = _mm_blend_epi16(m2, m7, 0xF0); \
+ } while (0)
+
+#define LOAD_MSG_3_4(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m3, m5); \
+ b1 = _mm_unpacklo_epi64(m0, m4); \
+ } while (0)
+
+#define LOAD_MSG_4_1(b0, b1) \
+ do { \
+ b0 = _mm_unpackhi_epi64(m4, m2); \
+ b1 = _mm_unpacklo_epi64(m1, m5); \
+ } while (0)
+
+#define LOAD_MSG_4_2(b0, b1) \
+ do { \
+ b0 = _mm_blend_epi16(m0, m3, 0xF0); \
+ b1 = _mm_blend_epi16(m2, m7, 0xF0); \
+ } while (0)
+
+#define LOAD_MSG_4_3(b0, b1) \
+ do { \
+ b0 = _mm_blend_epi16(m7, m5, 0xF0); \
+ b1 = _mm_blend_epi16(m3, m1, 0xF0); \
+ } while (0)
+
+#define LOAD_MSG_4_4(b0, b1) \
+ do { \
+ b0 = _mm_alignr_epi8(m6, m0, 8); \
+ b1 = _mm_blend_epi16(m4, m6, 0xF0); \
+ } while (0)
+
+#define LOAD_MSG_5_1(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m1, m3); \
+ b1 = _mm_unpacklo_epi64(m0, m4); \
+ } while (0)
+
+#define LOAD_MSG_5_2(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m6, m5); \
+ b1 = _mm_unpackhi_epi64(m5, m1); \
+ } while (0)
+
+#define LOAD_MSG_5_3(b0, b1) \
+ do { \
+ b0 = _mm_blend_epi16(m2, m3, 0xF0); \
+ b1 = _mm_unpackhi_epi64(m7, m0); \
+ } while (0)
+
+#define LOAD_MSG_5_4(b0, b1) \
+ do { \
+ b0 = _mm_unpackhi_epi64(m6, m2); \
+ b1 = _mm_blend_epi16(m7, m4, 0xF0); \
+ } while (0)
+
+#define LOAD_MSG_6_1(b0, b1) \
+ do { \
+ b0 = _mm_blend_epi16(m6, m0, 0xF0); \
+ b1 = _mm_unpacklo_epi64(m7, m2); \
+ } while (0)
+
+#define LOAD_MSG_6_2(b0, b1) \
+ do { \
+ b0 = _mm_unpackhi_epi64(m2, m7); \
+ b1 = _mm_alignr_epi8(m5, m6, 8); \
+ } while (0)
+
+#define LOAD_MSG_6_3(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m0, m3); \
+ b1 = _mm_shuffle_epi32(m4, _MM_SHUFFLE(1, 0, 3, 2)); \
+ } while (0)
+
+#define LOAD_MSG_6_4(b0, b1) \
+ do { \
+ b0 = _mm_unpackhi_epi64(m3, m1); \
+ b1 = _mm_blend_epi16(m1, m5, 0xF0); \
+ } while (0)
+
+#define LOAD_MSG_7_1(b0, b1) \
+ do { \
+ b0 = _mm_unpackhi_epi64(m6, m3); \
+ b1 = _mm_blend_epi16(m6, m1, 0xF0); \
+ } while (0)
+
+#define LOAD_MSG_7_2(b0, b1) \
+ do { \
+ b0 = _mm_alignr_epi8(m7, m5, 8); \
+ b1 = _mm_unpackhi_epi64(m0, m4); \
+ } while (0)
+
+#define LOAD_MSG_7_3(b0, b1) \
+ do { \
+ b0 = _mm_unpackhi_epi64(m2, m7); \
+ b1 = _mm_unpacklo_epi64(m4, m1); \
+ } while (0)
+
+#define LOAD_MSG_7_4(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m0, m2); \
+ b1 = _mm_unpacklo_epi64(m3, m5); \
+ } while (0)
+
+#define LOAD_MSG_8_1(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m3, m7); \
+ b1 = _mm_alignr_epi8(m0, m5, 8); \
+ } while (0)
+
+#define LOAD_MSG_8_2(b0, b1) \
+ do { \
+ b0 = _mm_unpackhi_epi64(m7, m4); \
+ b1 = _mm_alignr_epi8(m4, m1, 8); \
+ } while (0)
+
+#define LOAD_MSG_8_3(b0, b1) \
+ do { \
+ b0 = m6; \
+ b1 = _mm_alignr_epi8(m5, m0, 8); \
+ } while (0)
+
+#define LOAD_MSG_8_4(b0, b1) \
+ do { \
+ b0 = _mm_blend_epi16(m1, m3, 0xF0); \
+ b1 = m2; \
+ } while (0)
+
+#define LOAD_MSG_9_1(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m5, m4); \
+ b1 = _mm_unpackhi_epi64(m3, m0); \
+ } while (0)
+
+#define LOAD_MSG_9_2(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m1, m2); \
+ b1 = _mm_blend_epi16(m3, m2, 0xF0); \
+ } while (0)
+
+#define LOAD_MSG_9_3(b0, b1) \
+ do { \
+ b0 = _mm_unpackhi_epi64(m7, m4); \
+ b1 = _mm_unpackhi_epi64(m1, m6); \
+ } while (0)
+
+#define LOAD_MSG_9_4(b0, b1) \
+ do { \
+ b0 = _mm_alignr_epi8(m7, m5, 8); \
+ b1 = _mm_unpacklo_epi64(m6, m0); \
+ } while (0)
+
+#define LOAD_MSG_10_1(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m0, m1); \
+ b1 = _mm_unpacklo_epi64(m2, m3); \
+ } while (0)
+
+#define LOAD_MSG_10_2(b0, b1) \
+ do { \
+ b0 = _mm_unpackhi_epi64(m0, m1); \
+ b1 = _mm_unpackhi_epi64(m2, m3); \
+ } while (0)
+
+#define LOAD_MSG_10_3(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m4, m5); \
+ b1 = _mm_unpacklo_epi64(m6, m7); \
+ } while (0)
+
+#define LOAD_MSG_10_4(b0, b1) \
+ do { \
+ b0 = _mm_unpackhi_epi64(m4, m5); \
+ b1 = _mm_unpackhi_epi64(m6, m7); \
+ } while (0)
+
+#define LOAD_MSG_11_1(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m7, m2); \
+ b1 = _mm_unpackhi_epi64(m4, m6); \
+ } while (0)
+
+#define LOAD_MSG_11_2(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m5, m4); \
+ b1 = _mm_alignr_epi8(m3, m7, 8); \
+ } while (0)
+
+#define LOAD_MSG_11_3(b0, b1) \
+ do { \
+ b0 = _mm_shuffle_epi32(m0, _MM_SHUFFLE(1, 0, 3, 2)); \
+ b1 = _mm_unpackhi_epi64(m5, m2); \
+ } while (0)
+
+#define LOAD_MSG_11_4(b0, b1) \
+ do { \
+ b0 = _mm_unpacklo_epi64(m6, m1); \
+ b1 = _mm_unpackhi_epi64(m3, m1); \
+ } while (0)
diff --git a/library/cpp/digest/argonish/internal/blake2b/ya.make b/library/cpp/digest/argonish/internal/blake2b/ya.make
new file mode 100644
index 0000000000..0aa6806b31
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/blake2b/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(e-sidorov)
+
+PEERDIR(
+ library/cpp/digest/argonish/internal/rotations
+)
+
+END()
diff --git a/library/cpp/digest/argonish/internal/blamka/blamka_avx2.h b/library/cpp/digest/argonish/internal/blamka/blamka_avx2.h
new file mode 100644
index 0000000000..02c506d6ff
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/blamka/blamka_avx2.h
@@ -0,0 +1,136 @@
+#pragma once
+
+#include <immintrin.h>
+#include <library/cpp/digest/argonish/internal/rotations/rotations_avx2.h>
+
+namespace NArgonish {
+ static inline void BlamkaG1AVX2(
+ __m256i& a0, __m256i& a1, __m256i& b0, __m256i& b1,
+ __m256i& c0, __m256i& c1, __m256i& d0, __m256i& d1) {
+ __m256i ml = _mm256_mul_epu32(a0, b0);
+ ml = _mm256_add_epi64(ml, ml);
+ a0 = _mm256_add_epi64(a0, _mm256_add_epi64(b0, ml));
+ d0 = _mm256_xor_si256(d0, a0);
+ d0 = Rotr32(d0);
+
+ ml = _mm256_mul_epu32(c0, d0);
+ ml = _mm256_add_epi64(ml, ml);
+ c0 = _mm256_add_epi64(c0, _mm256_add_epi64(d0, ml));
+
+ b0 = _mm256_xor_si256(b0, c0);
+ b0 = Rotr24(b0);
+
+ ml = _mm256_mul_epu32(a1, b1);
+ ml = _mm256_add_epi64(ml, ml);
+ a1 = _mm256_add_epi64(a1, _mm256_add_epi64(b1, ml));
+ d1 = _mm256_xor_si256(d1, a1);
+ d1 = Rotr32(d1);
+
+ ml = _mm256_mul_epu32(c1, d1);
+ ml = _mm256_add_epi64(ml, ml);
+ c1 = _mm256_add_epi64(c1, _mm256_add_epi64(d1, ml));
+
+ b1 = _mm256_xor_si256(b1, c1);
+ b1 = Rotr24(b1);
+ }
+
+ static inline void BlamkaG2AVX2(
+ __m256i& a0, __m256i& a1, __m256i& b0, __m256i& b1,
+ __m256i& c0, __m256i& c1, __m256i& d0, __m256i& d1) {
+ __m256i ml = _mm256_mul_epu32(a0, b0);
+ ml = _mm256_add_epi64(ml, ml);
+ a0 = _mm256_add_epi64(a0, _mm256_add_epi64(b0, ml));
+ d0 = _mm256_xor_si256(d0, a0);
+ d0 = Rotr16(d0);
+
+ ml = _mm256_mul_epu32(c0, d0);
+ ml = _mm256_add_epi64(ml, ml);
+ c0 = _mm256_add_epi64(c0, _mm256_add_epi64(d0, ml));
+ b0 = _mm256_xor_si256(b0, c0);
+ b0 = Rotr63(b0);
+
+ ml = _mm256_mul_epu32(a1, b1);
+ ml = _mm256_add_epi64(ml, ml);
+ a1 = _mm256_add_epi64(a1, _mm256_add_epi64(b1, ml));
+ d1 = _mm256_xor_si256(d1, a1);
+ d1 = Rotr16(d1);
+
+ ml = _mm256_mul_epu32(c1, d1);
+ ml = _mm256_add_epi64(ml, ml);
+ c1 = _mm256_add_epi64(c1, _mm256_add_epi64(d1, ml));
+ b1 = _mm256_xor_si256(b1, c1);
+ b1 = Rotr63(b1);
+ }
+
+ /* a = ( v0, v1, v2, v3) */
+ /* b = ( v4, v5, v6, v7) */
+ /* c = ( v8, v9, v10, v11) */
+ /* d = (v12, v13, v14, v15) */
+ static inline void DiagonalizeAVX21(
+ __m256i& b0, __m256i& c0, __m256i& d0, __m256i& b1, __m256i& c1, __m256i& d1) {
+ /* (v4, v5, v6, v7) -> (v5, v6, v7, v4) */
+ b0 = _mm256_permute4x64_epi64(b0, _MM_SHUFFLE(0, 3, 2, 1));
+ /* (v8, v9, v10, v11) -> (v10, v11, v8, v9) */
+ c0 = _mm256_permute4x64_epi64(c0, _MM_SHUFFLE(1, 0, 3, 2));
+ /* (v12, v13, v14, v15) -> (v15, v12, v13, v14) */
+ d0 = _mm256_permute4x64_epi64(d0, _MM_SHUFFLE(2, 1, 0, 3));
+
+ b1 = _mm256_permute4x64_epi64(b1, _MM_SHUFFLE(0, 3, 2, 1));
+ c1 = _mm256_permute4x64_epi64(c1, _MM_SHUFFLE(1, 0, 3, 2));
+ d1 = _mm256_permute4x64_epi64(d1, _MM_SHUFFLE(2, 1, 0, 3));
+ }
+
+ static inline void DiagonalizeAVX22(
+ __m256i& b0, __m256i& b1, __m256i& c0, __m256i& c1, __m256i& d0, __m256i& d1) {
+ /* (v4, v5, v6, v7) -> (v5, v6, v7, v4) */
+ __m256i tmp1 = _mm256_blend_epi32(b0, b1, 0b11001100); /* v4v7 */
+ __m256i tmp2 = _mm256_blend_epi32(b0, b1, 0b00110011); /* v6v5 */
+ b1 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2, 3, 0, 1)); /* v7v4 */
+ b0 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2, 3, 0, 1)); /* v5v6 */
+
+ /* (v8, v9, v10, v11) -> (v10, v11, v8, v9) */
+ tmp1 = c0;
+ c0 = c1;
+ c1 = tmp1;
+
+ /* (v12, v13, v14, v15) -> (v15, v12, v13, v14) */
+ tmp1 = _mm256_blend_epi32(d0, d1, 0b11001100); /* v12v15 */
+ tmp2 = _mm256_blend_epi32(d0, d1, 0b00110011); /* v14v13 */
+ d0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2, 3, 0, 1)); /* v15v12 */
+ d1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2, 3, 0, 1)); /* v13v14 */
+ }
+
+ static inline void UndiagonalizeAVX21(
+ __m256i& b0, __m256i& c0, __m256i& d0, __m256i& b1, __m256i& c1, __m256i& d1) {
+ /* (v5, v6, v7, v4) -> (v4, v5, v6, v7) */
+ b0 = _mm256_permute4x64_epi64(b0, _MM_SHUFFLE(2, 1, 0, 3));
+ /* (v10, v11, v8, v9) -> (v8, v9, v10, v11) */
+ c0 = _mm256_permute4x64_epi64(c0, _MM_SHUFFLE(1, 0, 3, 2));
+ /* (v15, v12, v13, v14) -> (v12, v13, v14, v15) */
+ d0 = _mm256_permute4x64_epi64(d0, _MM_SHUFFLE(0, 3, 2, 1));
+
+ b1 = _mm256_permute4x64_epi64(b1, _MM_SHUFFLE(2, 1, 0, 3));
+ c1 = _mm256_permute4x64_epi64(c1, _MM_SHUFFLE(1, 0, 3, 2));
+ d1 = _mm256_permute4x64_epi64(d1, _MM_SHUFFLE(0, 3, 2, 1));
+ }
+
+ static inline void UndiagonalizeAVX22(
+ __m256i& b0, __m256i& b1, __m256i& c0, __m256i& c1, __m256i& d0, __m256i& d1) {
+ /* (v5, v6, v7, v4) -> (v4, v5, v6, v7) */
+ __m256i tmp1 = _mm256_blend_epi32(b0, b1, 0b11001100); /* v5v4 */
+ __m256i tmp2 = _mm256_blend_epi32(b0, b1, 0b00110011); /* v7v6 */
+ b0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2, 3, 0, 1)); /* v4v5 */
+ b1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2, 3, 0, 1)); /* v6v7 */
+
+ /* (v10,v11,v8,v9) -> (v8,v9,v10,v11) */
+ tmp1 = c0;
+ c0 = c1;
+ c1 = tmp1;
+
+ /* (v15,v12,v13,v14) -> (v12,v13,v14,v15) */
+ tmp1 = _mm256_blend_epi32(d0, d1, 0b00110011); /* v13v12 */
+ tmp2 = _mm256_blend_epi32(d0, d1, 0b11001100); /* v15v14 */
+ d0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2, 3, 0, 1));
+ d1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2, 3, 0, 1));
+ }
+}
diff --git a/library/cpp/digest/argonish/internal/blamka/blamka_sse2.h b/library/cpp/digest/argonish/internal/blamka/blamka_sse2.h
new file mode 100644
index 0000000000..1b55651b34
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/blamka/blamka_sse2.h
@@ -0,0 +1,95 @@
+#pragma once
+
+#include <library/cpp/digest/argonish/internal/rotations/rotations_sse2.h>
+
+namespace NArgonish {
+ static inline void BlamkaG1SSE2(
+ __m128i& a0, __m128i& a1, __m128i& b0, __m128i& b1,
+ __m128i& c0, __m128i& c1, __m128i& d0, __m128i& d1) {
+ __m128i ml = _mm_mul_epu32(a0, b0);
+ ml = _mm_add_epi64(ml, ml);
+ a0 = _mm_add_epi64(a0, _mm_add_epi64(b0, ml));
+
+ ml = _mm_mul_epu32(a1, b1);
+ ml = _mm_add_epi64(ml, ml);
+ a1 = _mm_add_epi64(a1, _mm_add_epi64(b1, ml));
+
+ d0 = _mm_xor_si128(d0, a0);
+ d1 = _mm_xor_si128(d1, a1);
+
+ d0 = Rotr32(d0);
+ d1 = Rotr32(d1);
+
+ ml = _mm_mul_epu32(c0, d0);
+ ml = _mm_add_epi64(ml, ml);
+ c0 = _mm_add_epi64(c0, _mm_add_epi64(d0, ml));
+
+ ml = _mm_mul_epu32(c1, d1);
+ ml = _mm_add_epi64(ml, ml);
+ c1 = _mm_add_epi64(c1, _mm_add_epi64(ml, d1));
+
+ b0 = _mm_xor_si128(b0, c0);
+ b1 = _mm_xor_si128(b1, c1);
+
+ b0 = Rotr24(b0);
+ b1 = Rotr24(b1);
+ }
+
+ static inline void BlamkaG2SSE2(
+ __m128i& a0, __m128i& a1, __m128i& b0, __m128i& b1,
+ __m128i& c0, __m128i& c1, __m128i& d0, __m128i& d1) {
+ __m128i ml = _mm_mul_epu32(a0, b0);
+ ml = _mm_add_epi64(ml, ml);
+ a0 = _mm_add_epi64(a0, _mm_add_epi64(b0, ml));
+
+ ml = _mm_mul_epu32(a1, b1);
+ ml = _mm_add_epi64(ml, ml);
+ a1 = _mm_add_epi64(a1, _mm_add_epi64(b1, ml));
+
+ d0 = _mm_xor_si128(d0, a0);
+ d1 = _mm_xor_si128(d1, a1);
+
+ d0 = Rotr16(d0);
+ d1 = Rotr16(d1);
+
+ ml = _mm_mul_epu32(c0, d0);
+ ml = _mm_add_epi64(ml, ml);
+ c0 = _mm_add_epi64(c0, _mm_add_epi64(d0, ml));
+
+ ml = _mm_mul_epu32(c1, d1);
+ ml = _mm_add_epi64(ml, ml);
+ c1 = _mm_add_epi64(c1, _mm_add_epi64(ml, d1));
+
+ b0 = _mm_xor_si128(b0, c0);
+ b1 = _mm_xor_si128(b1, c1);
+
+ b0 = Rotr63(b0);
+ b1 = Rotr63(b1);
+ }
+
+ static inline void DiagonalizeSSE2(
+ __m128i& b0, __m128i& b1, __m128i& c0, __m128i& c1, __m128i& d0, __m128i& d1) {
+ __m128i tmp0 = d0;
+ __m128i tmp1 = b0;
+ d0 = c0;
+ c0 = c1;
+ c1 = d0;
+ d0 = _mm_unpackhi_epi64(d1, _mm_unpacklo_epi64(tmp0, tmp0));
+ d1 = _mm_unpackhi_epi64(tmp0, _mm_unpacklo_epi64(d1, d1));
+ b0 = _mm_unpackhi_epi64(b0, _mm_unpacklo_epi64(b1, b1));
+ b1 = _mm_unpackhi_epi64(b1, _mm_unpacklo_epi64(tmp1, tmp1));
+ }
+
+ static inline void UndiagonalizeSSE2(
+ __m128i& b0, __m128i& b1, __m128i& c0, __m128i& c1, __m128i& d0, __m128i& d1) {
+ __m128i tmp0 = c0;
+ c0 = c1;
+ c1 = tmp0;
+ tmp0 = b0;
+ __m128i tmp1 = d0;
+ b0 = _mm_unpackhi_epi64(b1, _mm_unpacklo_epi64(b0, b0));
+ b1 = _mm_unpackhi_epi64(tmp0, _mm_unpacklo_epi64(b1, b1));
+ d0 = _mm_unpackhi_epi64(d0, _mm_unpacklo_epi64(d1, d1));
+ d1 = _mm_unpackhi_epi64(d1, _mm_unpacklo_epi64(tmp1, tmp1));
+ }
+}
diff --git a/library/cpp/digest/argonish/internal/blamka/blamka_ssse3.h b/library/cpp/digest/argonish/internal/blamka/blamka_ssse3.h
new file mode 100644
index 0000000000..46e8500cd6
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/blamka/blamka_ssse3.h
@@ -0,0 +1,103 @@
+#pragma once
+
+#include <library/cpp/digest/argonish/internal/rotations/rotations_ssse3.h>
+
+namespace NArgonish {
+ static inline void BlamkaG1SSSE3(
+ __m128i& a0, __m128i& a1, __m128i& b0, __m128i& b1,
+ __m128i& c0, __m128i& c1, __m128i& d0, __m128i& d1) {
+ __m128i ml = _mm_mul_epu32(a0, b0);
+ ml = _mm_add_epi64(ml, ml);
+ a0 = _mm_add_epi64(a0, _mm_add_epi64(b0, ml));
+
+ ml = _mm_mul_epu32(a1, b1);
+ ml = _mm_add_epi64(ml, ml);
+ a1 = _mm_add_epi64(a1, _mm_add_epi64(b1, ml));
+
+ d0 = _mm_xor_si128(d0, a0);
+ d1 = _mm_xor_si128(d1, a1);
+
+ d0 = Rotr32(d0);
+ d1 = Rotr32(d1);
+
+ ml = _mm_mul_epu32(c0, d0);
+ ml = _mm_add_epi64(ml, ml);
+ c0 = _mm_add_epi64(c0, _mm_add_epi64(d0, ml));
+
+ ml = _mm_mul_epu32(c1, d1);
+ ml = _mm_add_epi64(ml, ml);
+ c1 = _mm_add_epi64(c1, _mm_add_epi64(ml, d1));
+
+ b0 = _mm_xor_si128(b0, c0);
+ b1 = _mm_xor_si128(b1, c1);
+
+ b0 = Rotr24(b0);
+ b1 = Rotr24(b1);
+ }
+
+ static inline void BlamkaG2SSSE3(
+ __m128i& a0, __m128i& a1, __m128i& b0, __m128i& b1,
+ __m128i& c0, __m128i& c1, __m128i& d0, __m128i& d1) {
+ __m128i ml = _mm_mul_epu32(a0, b0);
+ ml = _mm_add_epi64(ml, ml);
+ a0 = _mm_add_epi64(a0, _mm_add_epi64(b0, ml));
+
+ ml = _mm_mul_epu32(a1, b1);
+ ml = _mm_add_epi64(ml, ml);
+ a1 = _mm_add_epi64(a1, _mm_add_epi64(b1, ml));
+
+ d0 = _mm_xor_si128(d0, a0);
+ d1 = _mm_xor_si128(d1, a1);
+
+ d0 = Rotr16(d0);
+ d1 = Rotr16(d1);
+
+ ml = _mm_mul_epu32(c0, d0);
+ ml = _mm_add_epi64(ml, ml);
+ c0 = _mm_add_epi64(c0, _mm_add_epi64(d0, ml));
+
+ ml = _mm_mul_epu32(c1, d1);
+ ml = _mm_add_epi64(ml, ml);
+ c1 = _mm_add_epi64(c1, _mm_add_epi64(ml, d1));
+
+ b0 = _mm_xor_si128(b0, c0);
+ b1 = _mm_xor_si128(b1, c1);
+
+ b0 = Rotr63(b0);
+ b1 = Rotr63(b1);
+ }
+
+ static inline void DiagonalizeSSSE3(
+ __m128i& b0, __m128i& b1, __m128i& c0, __m128i& c1, __m128i& d0, __m128i& d1) {
+ __m128i t0 = _mm_alignr_epi8(b1, b0, 8);
+ __m128i t1 = _mm_alignr_epi8(b0, b1, 8);
+ b0 = t0;
+ b1 = t1;
+
+ t0 = c0;
+ c0 = c1;
+ c1 = t0;
+
+ t0 = _mm_alignr_epi8(d1, d0, 8);
+ t1 = _mm_alignr_epi8(d0, d1, 8);
+ d0 = t1;
+ d1 = t0;
+ }
+
+ static inline void UndiagonalizeSSSE3(
+ __m128i& b0, __m128i& b1, __m128i& c0, __m128i& c1, __m128i& d0, __m128i& d1) {
+ __m128i t0 = _mm_alignr_epi8(b0, b1, 8);
+ __m128i t1 = _mm_alignr_epi8(b1, b0, 8);
+ b0 = t0;
+ b1 = t1;
+
+ t0 = c0;
+ c0 = c1;
+ c1 = t0;
+
+ t0 = _mm_alignr_epi8(d0, d1, 8);
+ t1 = _mm_alignr_epi8(d1, d0, 8);
+ d0 = t1;
+ d1 = t0;
+ }
+}
diff --git a/library/cpp/digest/argonish/internal/blamka/ya.make b/library/cpp/digest/argonish/internal/blamka/ya.make
new file mode 100644
index 0000000000..0aa6806b31
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/blamka/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(e-sidorov)
+
+PEERDIR(
+ library/cpp/digest/argonish/internal/rotations
+)
+
+END()
diff --git a/library/cpp/digest/argonish/internal/proxies/avx2/proxy_avx2.cpp b/library/cpp/digest/argonish/internal/proxies/avx2/proxy_avx2.cpp
new file mode 100644
index 0000000000..c1cf004f58
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/avx2/proxy_avx2.cpp
@@ -0,0 +1,18 @@
+//
+// Created by Evgeny Sidorov on 12/04/17.
+//
+
+#include "proxy_avx2.h"
+#include <library/cpp/digest/argonish/internal/argon2/argon2_base.h>
+#include <library/cpp/digest/argonish/internal/argon2/argon2_avx2.h>
+#include <library/cpp/digest/argonish/internal/blake2b/blake2b.h>
+#include <library/cpp/digest/argonish/internal/blake2b/blake2b_avx2.h>
+
+#define ZEROUPPER _mm256_zeroupper();
+
+namespace NArgonish {
+ ARGON2_PROXY_CLASS_IMPL(AVX2)
+ BLAKE2B_PROXY_CLASS_IMPL(AVX2)
+}
+
+#undef ZEROUPPER
diff --git a/library/cpp/digest/argonish/internal/proxies/avx2/proxy_avx2.h b/library/cpp/digest/argonish/internal/proxies/avx2/proxy_avx2.h
new file mode 100644
index 0000000000..eec0094563
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/avx2/proxy_avx2.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <util/generic/yexception.h>
+#include <library/cpp/digest/argonish/argon2.h>
+#include <library/cpp/digest/argonish/blake2b.h>
+#include <library/cpp/digest/argonish/internal/proxies/macro/proxy_macros.h>
+
+namespace NArgonish {
+ ARGON2_PROXY_CLASS_DECL(AVX2)
+ BLAKE2B_PROXY_CLASS_DECL(AVX2)
+}
diff --git a/library/cpp/digest/argonish/internal/proxies/avx2/ya.make b/library/cpp/digest/argonish/internal/proxies/avx2/ya.make
new file mode 100644
index 0000000000..53f814c48d
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/avx2/ya.make
@@ -0,0 +1,18 @@
+OWNER(e-sidorov)
+
+LIBRARY()
+
+NO_UTIL()
+
+IF (ARCH_X86_64 OR ARCH_I386)
+ PEERDIR(
+ library/cpp/digest/argonish/internal/proxies/macro
+ library/cpp/digest/argonish/internal/argon2
+ library/cpp/digest/argonish/internal/blake2b
+ )
+ SRC_CPP_AVX2(
+ proxy_avx2.cpp
+ )
+ENDIF()
+
+END()
diff --git a/library/cpp/digest/argonish/internal/proxies/macro/proxy_macros.h b/library/cpp/digest/argonish/internal/proxies/macro/proxy_macros.h
new file mode 100644
index 0000000000..5ed5f53b4f
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/macro/proxy_macros.h
@@ -0,0 +1,194 @@
+#pragma once
+
+//
+// Created by Evgeny Sidorov on 12/04/17.
+//
+/**
+ * ZEROUPPER macro is only used for AVX2 instruction set to clear up the upper half of YMM registers
+ * It's done to avoid performance penalty when CPU switches to non-AVX2 code (according to Agner)
+ * and the post at https://software.intel.com/en-us/articles/intel-avx-state-transitions-migrating-sse-code-to-avx
+ */
+
+#define ARGON2_PROXY_CLASS_DECL(IS) \
+ class TArgon2Proxy##IS final: public IArgon2Base { \
+ public: \
+ TArgon2Proxy##IS(EArgon2Type atype, ui32 tcost, ui32 mcost, ui32 threads, \
+ const ui8* key = nullptr, ui32 keylen = 0); \
+ virtual ~TArgon2Proxy##IS(); \
+ \
+ virtual void Hash(const ui8* pwd, ui32 pwdlen, const ui8* salt, ui32 saltlen, \
+ ui8* out, ui32 outlen, const ui8* aad = nullptr, ui32 aadlen = 0) const override; \
+ virtual bool Verify(const ui8* pwd, ui32 pwdlen, const ui8* salt, ui32 saltlen, \
+ const ui8* hash, ui32 hashlen, const ui8* aad = nullptr, ui32 aadlen = 0) const override; \
+ virtual void HashWithCustomMemory(ui8* memory, size_t mlen, const ui8* pwd, ui32 pwdlen, \
+ const ui8* salt, ui32 saltlen, ui8* out, ui32 outlen, \
+ const ui8* aad = nullptr, ui32 aadlen = 0) const override; \
+ virtual bool VerifyWithCustomMemory(ui8* memory, size_t mlen, const ui8* pwd, ui32 pwdlen, \
+ const ui8* salt, ui32 saltlen, const ui8* hash, ui32 hashlen, \
+ const ui8* aad = nullptr, ui32 aadlen = 0) const override; \
+ virtual size_t GetMemorySize() const override; \
+ \
+ protected: \
+ THolder<IArgon2Base> argon2; \
+ };
+
+#define ARGON2_INSTANCE_DECL(IS_val, mcost_val, threads_val) \
+ if (mcost == mcost_val && threads == threads_val) { \
+ argon2 = MakeHolder<TArgon2##IS_val<mcost_val, threads_val>>(atype, tcost, key, keylen); \
+ return; \
+ }
+
+#define ARGON2_PROXY_CLASS_IMPL(IS) \
+ TArgon2Proxy##IS::TArgon2Proxy##IS(EArgon2Type atype, ui32 tcost, ui32 mcost, ui32 threads, \
+ const ui8* key, ui32 keylen) { \
+ if ((key == nullptr && keylen > 0) || keylen > ARGON2_SECRET_MAX_LENGTH) \
+ ythrow yexception() << "key is null or keylen equals 0 or key is too long"; \
+ \
+ ARGON2_INSTANCE_DECL(IS, 1, 1) \
+ ARGON2_INSTANCE_DECL(IS, 8, 1) \
+ ARGON2_INSTANCE_DECL(IS, 16, 1) \
+ ARGON2_INSTANCE_DECL(IS, 32, 1) \
+ ARGON2_INSTANCE_DECL(IS, 64, 1) \
+ ARGON2_INSTANCE_DECL(IS, 128, 1) \
+ ARGON2_INSTANCE_DECL(IS, 256, 1) \
+ ARGON2_INSTANCE_DECL(IS, 512, 1) \
+ ARGON2_INSTANCE_DECL(IS, 1024, 1) \
+ ARGON2_INSTANCE_DECL(IS, 2048, 1) \
+ ARGON2_INSTANCE_DECL(IS, 4096, 1) \
+ ARGON2_INSTANCE_DECL(IS, 8192, 1) \
+ ARGON2_INSTANCE_DECL(IS, 16384, 1) \
+ ARGON2_INSTANCE_DECL(IS, 32768, 1) \
+ ARGON2_INSTANCE_DECL(IS, 65536, 1) \
+ ARGON2_INSTANCE_DECL(IS, 131072, 1) \
+ ARGON2_INSTANCE_DECL(IS, 262144, 1) \
+ ARGON2_INSTANCE_DECL(IS, 524288, 1) \
+ ARGON2_INSTANCE_DECL(IS, 1048576, 1) \
+ ARGON2_INSTANCE_DECL(IS, 1, 2) \
+ ARGON2_INSTANCE_DECL(IS, 32, 2) \
+ ARGON2_INSTANCE_DECL(IS, 64, 2) \
+ ARGON2_INSTANCE_DECL(IS, 512, 2) \
+ ARGON2_INSTANCE_DECL(IS, 1024, 2) \
+ ARGON2_INSTANCE_DECL(IS, 2048, 2) \
+ ARGON2_INSTANCE_DECL(IS, 4096, 2) \
+ ARGON2_INSTANCE_DECL(IS, 8192, 2) \
+ ARGON2_INSTANCE_DECL(IS, 16384, 2) \
+ ARGON2_INSTANCE_DECL(IS, 32768, 2) \
+ ARGON2_INSTANCE_DECL(IS, 65536, 2) \
+ ARGON2_INSTANCE_DECL(IS, 131072, 2) \
+ ARGON2_INSTANCE_DECL(IS, 262144, 2) \
+ ARGON2_INSTANCE_DECL(IS, 524288, 2) \
+ ARGON2_INSTANCE_DECL(IS, 1048576, 2) \
+ ARGON2_INSTANCE_DECL(IS, 1, 4) \
+ ARGON2_INSTANCE_DECL(IS, 32, 4) \
+ ARGON2_INSTANCE_DECL(IS, 64, 4) \
+ ARGON2_INSTANCE_DECL(IS, 512, 4) \
+ ARGON2_INSTANCE_DECL(IS, 1024, 4) \
+ ARGON2_INSTANCE_DECL(IS, 2048, 4) \
+ ARGON2_INSTANCE_DECL(IS, 4096, 4) \
+ ARGON2_INSTANCE_DECL(IS, 8192, 4) \
+ ARGON2_INSTANCE_DECL(IS, 16384, 4) \
+ ARGON2_INSTANCE_DECL(IS, 32768, 4) \
+ ARGON2_INSTANCE_DECL(IS, 65536, 4) \
+ ARGON2_INSTANCE_DECL(IS, 131072, 4) \
+ ARGON2_INSTANCE_DECL(IS, 262144, 4) \
+ ARGON2_INSTANCE_DECL(IS, 524288, 4) \
+ ARGON2_INSTANCE_DECL(IS, 1048576, 4) \
+ \
+ ythrow yexception() << "These parameters are not supported. Please add the corresponding ARGON2_INSTANCE_DECL macro"; \
+ } \
+ \
+ TArgon2Proxy##IS::~TArgon2Proxy##IS() { \
+ } \
+ \
+ void TArgon2Proxy##IS::Hash(const ui8* pwd, ui32 pwdlen, const ui8* salt, ui32 saltlen, \
+ ui8* out, ui32 outlen, const ui8* aad, ui32 aadlen) const { \
+ if (saltlen < ARGON2_SALT_MIN_LEN) \
+ ythrow yexception() << "salt is too short"; \
+ if (outlen < ARGON2_MIN_OUTLEN) \
+ ythrow yexception() << "output length is too short"; \
+ \
+ argon2->Hash(pwd, pwdlen, salt, saltlen, out, outlen, aad, aadlen); \
+ ZEROUPPER \
+ } \
+ \
+ bool TArgon2Proxy##IS::Verify(const ui8* pwd, ui32 pwdlen, const ui8* salt, ui32 saltlen, \
+ const ui8* hash, ui32 hashlen, const ui8* aad, ui32 aadlen) const { \
+ if (saltlen < ARGON2_SALT_MIN_LEN) \
+ ythrow yexception() << "salt is too short"; \
+ if (hashlen < ARGON2_MIN_OUTLEN) \
+ ythrow yexception() << "hash length is too short"; \
+ \
+ return argon2->Verify(pwd, pwdlen, salt, saltlen, hash, hashlen, aad, aadlen); \
+ ZEROUPPER \
+ } \
+ \
+ void TArgon2Proxy##IS::HashWithCustomMemory(ui8* memory, size_t mlen, const ui8* pwd, ui32 pwdlen, \
+ const ui8* salt, ui32 saltlen, ui8* out, ui32 outlen, \
+ const ui8* aad, ui32 aadlen) const { \
+ if (saltlen < ARGON2_SALT_MIN_LEN) \
+ ythrow yexception() << "salt is too short"; \
+ if (outlen < ARGON2_MIN_OUTLEN) \
+ ythrow yexception() << "output length is too short"; \
+ \
+ argon2->HashWithCustomMemory(memory, mlen, pwd, pwdlen, salt, saltlen, out, outlen, aad, aadlen); \
+ ZEROUPPER \
+ } \
+ \
+ bool TArgon2Proxy##IS::VerifyWithCustomMemory(ui8* memory, size_t mlen, const ui8* pwd, ui32 pwdlen, \
+ const ui8* salt, ui32 saltlen, const ui8* hash, ui32 hashlen, \
+ const ui8* aad, ui32 aadlen) const { \
+ if (saltlen < ARGON2_SALT_MIN_LEN) \
+ ythrow yexception() << "salt is too short"; \
+ if (hashlen < ARGON2_MIN_OUTLEN) \
+ ythrow yexception() << "hash length is too short"; \
+ \
+ return argon2->VerifyWithCustomMemory(memory, mlen, pwd, pwdlen, salt, saltlen, hash, hashlen, aad, aadlen); \
+ ZEROUPPER \
+ } \
+ \
+ size_t TArgon2Proxy##IS::GetMemorySize() const { \
+ return argon2->GetMemorySize(); \
+ }
+
+#define BLAKE2B_PROXY_CLASS_DECL(IS) \
+ class TBlake2BProxy##IS final: public IBlake2Base { \
+ public: \
+ TBlake2BProxy##IS(size_t outlen, const void* key = nullptr, size_t keylen = 0); \
+ virtual void Update(ui32 in) override; \
+ virtual void Update(const void* pin, size_t inlen) override; \
+ virtual void Final(void* out, size_t outlen) override; \
+ \
+ protected: \
+ THolder<IBlake2Base> blake2; \
+ };
+
+#define BLAKE2B_PROXY_CLASS_IMPL(IS) \
+ TBlake2BProxy##IS::TBlake2BProxy##IS(size_t outlen, const void* key, size_t keylen) { \
+ if (!outlen || outlen > BLAKE2B_OUTBYTES) \
+ ythrow yexception() << "outlen equals 0 or too long"; \
+ \
+ if (key == nullptr) { \
+ blake2 = MakeHolder<TBlake2B<EInstructionSet::IS>>(outlen); \
+ return; \
+ } \
+ \
+ if (!key || !keylen || keylen > BLAKE2B_KEYBYTES) \
+ ythrow yexception() << "key is null or too long"; \
+ \
+ blake2 = MakeHolder<TBlake2B<EInstructionSet::IS>>(outlen, key, keylen); \
+ } \
+ \
+ void TBlake2BProxy##IS::Update(ui32 in) { \
+ blake2->Update(in); \
+ ZEROUPPER \
+ } \
+ \
+ void TBlake2BProxy##IS::Update(const void* pin, size_t inlen) { \
+ blake2->Update(pin, inlen); \
+ ZEROUPPER \
+ } \
+ \
+ void TBlake2BProxy##IS::Final(void* out, size_t outlen) { \
+ blake2->Final(out, outlen); \
+ ZEROUPPER \
+ }
diff --git a/library/cpp/digest/argonish/internal/proxies/macro/ya.make b/library/cpp/digest/argonish/internal/proxies/macro/ya.make
new file mode 100644
index 0000000000..5f639d4571
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/macro/ya.make
@@ -0,0 +1,5 @@
+LIBRARY()
+
+OWNER(e-sidorov)
+
+END()
diff --git a/library/cpp/digest/argonish/internal/proxies/ref/proxy_ref.cpp b/library/cpp/digest/argonish/internal/proxies/ref/proxy_ref.cpp
new file mode 100644
index 0000000000..0bc51866fd
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/ref/proxy_ref.cpp
@@ -0,0 +1,20 @@
+//
+// Created by Evgeny Sidorov on 12/04/17.
+//
+
+#include "proxy_ref.h"
+#include <library/cpp/digest/argonish/internal/argon2/argon2_base.h>
+#include <library/cpp/digest/argonish/internal/argon2/argon2_ref.h>
+#include <library/cpp/digest/argonish/internal/blake2b/blake2b.h>
+#include <library/cpp/digest/argonish/internal/blake2b/blake2b_ref.h>
+
+#include <stdexcept>
+
+#define ZEROUPPER ;
+
+namespace NArgonish {
+ ARGON2_PROXY_CLASS_IMPL(REF)
+ BLAKE2B_PROXY_CLASS_IMPL(REF)
+}
+
+#undef ZEROUPPER
diff --git a/library/cpp/digest/argonish/internal/proxies/ref/proxy_ref.h b/library/cpp/digest/argonish/internal/proxies/ref/proxy_ref.h
new file mode 100644
index 0000000000..821abc50cd
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/ref/proxy_ref.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <util/generic/yexception.h>
+#include <library/cpp/digest/argonish/argon2.h>
+#include <library/cpp/digest/argonish/blake2b.h>
+#include <library/cpp/digest/argonish/internal/proxies/macro/proxy_macros.h>
+
+namespace NArgonish {
+ ARGON2_PROXY_CLASS_DECL(REF)
+ BLAKE2B_PROXY_CLASS_DECL(REF)
+}
diff --git a/library/cpp/digest/argonish/internal/proxies/ref/ya.make b/library/cpp/digest/argonish/internal/proxies/ref/ya.make
new file mode 100644
index 0000000000..7a15f44611
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/ref/ya.make
@@ -0,0 +1,17 @@
+OWNER(e-sidorov)
+
+LIBRARY()
+
+NO_UTIL()
+
+PEERDIR(
+ library/cpp/digest/argonish/internal/proxies/macro
+ library/cpp/digest/argonish/internal/argon2
+ library/cpp/digest/argonish/internal/blake2b
+)
+
+SRCS(
+ proxy_ref.cpp
+)
+
+END()
diff --git a/library/cpp/digest/argonish/internal/proxies/sse2/proxy_sse2.cpp b/library/cpp/digest/argonish/internal/proxies/sse2/proxy_sse2.cpp
new file mode 100644
index 0000000000..3e63c9ad62
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/sse2/proxy_sse2.cpp
@@ -0,0 +1,18 @@
+//
+// Created by Evgeny Sidorov on 12/04/17.
+//
+
+#include "proxy_sse2.h"
+#include <library/cpp/digest/argonish/internal/argon2/argon2_base.h>
+#include <library/cpp/digest/argonish/internal/argon2/argon2_sse2.h>
+#include <library/cpp/digest/argonish/internal/blake2b/blake2b.h>
+#include <library/cpp/digest/argonish/internal/blake2b/blake2b_sse2.h>
+
+#define ZEROUPPER ;
+
+namespace NArgonish {
+ ARGON2_PROXY_CLASS_IMPL(SSE2)
+ BLAKE2B_PROXY_CLASS_IMPL(SSE2)
+}
+
+#undef ZEROUPPER
diff --git a/library/cpp/digest/argonish/internal/proxies/sse2/proxy_sse2.h b/library/cpp/digest/argonish/internal/proxies/sse2/proxy_sse2.h
new file mode 100644
index 0000000000..a2b74cd9a7
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/sse2/proxy_sse2.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <util/generic/yexception.h>
+#include <library/cpp/digest/argonish/argon2.h>
+#include <library/cpp/digest/argonish/blake2b.h>
+#include <library/cpp/digest/argonish/internal/proxies/macro/proxy_macros.h>
+
+namespace NArgonish {
+ ARGON2_PROXY_CLASS_DECL(SSE2)
+ BLAKE2B_PROXY_CLASS_DECL(SSE2)
+}
diff --git a/library/cpp/digest/argonish/internal/proxies/sse2/ya.make b/library/cpp/digest/argonish/internal/proxies/sse2/ya.make
new file mode 100644
index 0000000000..1c752f0dd5
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/sse2/ya.make
@@ -0,0 +1,18 @@
+OWNER(e-sidorov)
+
+LIBRARY()
+
+NO_UTIL()
+
+IF (ARCH_X86_64 OR ARCH_I386)
+ PEERDIR(
+ library/cpp/digest/argonish/internal/proxies/macro
+ library/cpp/digest/argonish/internal/argon2
+ library/cpp/digest/argonish/internal/blake2b
+ )
+ SRC_CPP_SSE2(
+ proxy_sse2.cpp
+ )
+ENDIF()
+
+END()
diff --git a/library/cpp/digest/argonish/internal/proxies/sse41/proxy_sse41.cpp b/library/cpp/digest/argonish/internal/proxies/sse41/proxy_sse41.cpp
new file mode 100644
index 0000000000..b633ad8cbf
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/sse41/proxy_sse41.cpp
@@ -0,0 +1,18 @@
+//
+// Created by Evgeny Sidorov on 12/04/17.
+//
+
+#include "proxy_sse41.h"
+#include <library/cpp/digest/argonish/internal/argon2/argon2_base.h>
+#include <library/cpp/digest/argonish/internal/argon2/argon2_sse41.h>
+#include <library/cpp/digest/argonish/internal/blake2b/blake2b.h>
+#include <library/cpp/digest/argonish/internal/blake2b/blake2b_sse41.h>
+
+#define ZEROUPPER ;
+
+namespace NArgonish {
+ ARGON2_PROXY_CLASS_IMPL(SSE41)
+ BLAKE2B_PROXY_CLASS_IMPL(SSE41)
+}
+
+#undef ZEROUPPER
diff --git a/library/cpp/digest/argonish/internal/proxies/sse41/proxy_sse41.h b/library/cpp/digest/argonish/internal/proxies/sse41/proxy_sse41.h
new file mode 100644
index 0000000000..2a4b6614aa
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/sse41/proxy_sse41.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <util/generic/yexception.h>
+#include <library/cpp/digest/argonish/argon2.h>
+#include <library/cpp/digest/argonish/blake2b.h>
+#include <library/cpp/digest/argonish/internal/proxies/macro/proxy_macros.h>
+
+namespace NArgonish {
+ ARGON2_PROXY_CLASS_DECL(SSE41)
+ BLAKE2B_PROXY_CLASS_DECL(SSE41)
+}
diff --git a/library/cpp/digest/argonish/internal/proxies/sse41/ya.make b/library/cpp/digest/argonish/internal/proxies/sse41/ya.make
new file mode 100644
index 0000000000..16a9922016
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/sse41/ya.make
@@ -0,0 +1,18 @@
+OWNER(e-sidorov)
+
+LIBRARY()
+
+NO_UTIL()
+
+IF (ARCH_X86_64 OR ARCH_I386)
+ PEERDIR(
+ library/cpp/digest/argonish/internal/proxies/macro
+ library/cpp/digest/argonish/internal/argon2
+ library/cpp/digest/argonish/internal/blake2b
+ )
+ SRC_CPP_SSE41(
+ proxy_sse41.cpp
+ )
+ENDIF()
+
+END()
diff --git a/library/cpp/digest/argonish/internal/proxies/ssse3/proxy_ssse3.cpp b/library/cpp/digest/argonish/internal/proxies/ssse3/proxy_ssse3.cpp
new file mode 100644
index 0000000000..d77b55737c
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/ssse3/proxy_ssse3.cpp
@@ -0,0 +1,18 @@
+//
+// Created by Evgeny Sidorov on 12/04/17.
+//
+
+#include "proxy_ssse3.h"
+#include <library/cpp/digest/argonish/internal/argon2/argon2_base.h>
+#include <library/cpp/digest/argonish/internal/argon2/argon2_ssse3.h>
+#include <library/cpp/digest/argonish/internal/blake2b/blake2b.h>
+#include <library/cpp/digest/argonish/internal/blake2b/blake2b_ssse3.h>
+
+#define ZEROUPPER ;
+
+namespace NArgonish {
+ ARGON2_PROXY_CLASS_IMPL(SSSE3)
+ BLAKE2B_PROXY_CLASS_IMPL(SSSE3)
+}
+
+#undef ZEROUPPER
diff --git a/library/cpp/digest/argonish/internal/proxies/ssse3/proxy_ssse3.h b/library/cpp/digest/argonish/internal/proxies/ssse3/proxy_ssse3.h
new file mode 100644
index 0000000000..994133e88e
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/ssse3/proxy_ssse3.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <util/generic/yexception.h>
+#include <library/cpp/digest/argonish/argon2.h>
+#include <library/cpp/digest/argonish/blake2b.h>
+#include <library/cpp/digest/argonish/internal/proxies/macro/proxy_macros.h>
+
+namespace NArgonish {
+ ARGON2_PROXY_CLASS_DECL(SSSE3)
+ BLAKE2B_PROXY_CLASS_DECL(SSSE3)
+}
diff --git a/library/cpp/digest/argonish/internal/proxies/ssse3/ya.make b/library/cpp/digest/argonish/internal/proxies/ssse3/ya.make
new file mode 100644
index 0000000000..82d5116559
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/ssse3/ya.make
@@ -0,0 +1,19 @@
+LIBRARY()
+
+OWNER(e-sidorov)
+
+NO_UTIL()
+
+IF (ARCH_X86_64 OR ARCH_I386)
+ PEERDIR(
+ library/cpp/digest/argonish/internal/proxies/macro
+ library/cpp/digest/argonish/internal/argon2
+ library/cpp/digest/argonish/internal/blake2b
+ )
+
+ SRC_CPP_SSSE3(
+ proxy_ssse3.cpp
+ )
+ENDIF()
+
+END()
diff --git a/library/cpp/digest/argonish/internal/proxies/ya.make b/library/cpp/digest/argonish/internal/proxies/ya.make
new file mode 100644
index 0000000000..62bb1bcc50
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/proxies/ya.make
@@ -0,0 +1,8 @@
+RECURSE(
+ avx2
+ ref
+ sse2
+ sse41
+ ssse3
+ macro
+)
diff --git a/library/cpp/digest/argonish/internal/rotations/rotations_avx2.h b/library/cpp/digest/argonish/internal/rotations/rotations_avx2.h
new file mode 100644
index 0000000000..81cd171f59
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/rotations/rotations_avx2.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <immintrin.h>
+
+namespace NArgonish {
+ static inline void XorValues(__m256i* result, const __m256i* val1, const __m256i* val2) {
+ _mm256_storeu_si256(result, _mm256_xor_si256(
+ _mm256_loadu_si256(val1), _mm256_loadu_si256(val2)));
+ }
+
+ static inline __m256i Rotr32(__m256i x) {
+ return _mm256_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1));
+ }
+
+ static inline __m256i Rotr24(__m256i x) {
+ return _mm256_shuffle_epi8(x, _mm256_setr_epi8(
+ 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10,
+ 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10));
+ }
+
+ static inline __m256i Rotr16(__m256i x) {
+ return _mm256_shuffle_epi8(x, _mm256_setr_epi8(
+ 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9,
+ 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9));
+ }
+
+ static inline __m256i Rotr63(__m256i x) {
+ return _mm256_xor_si256(_mm256_srli_epi64(x, 63), _mm256_add_epi64(x, x));
+ }
+}
diff --git a/library/cpp/digest/argonish/internal/rotations/rotations_ref.h b/library/cpp/digest/argonish/internal/rotations/rotations_ref.h
new file mode 100644
index 0000000000..6f59e233a5
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/rotations/rotations_ref.h
@@ -0,0 +1,7 @@
+#pragma once
+
+namespace NArgonish {
+ static inline ui64 Rotr(const ui64 w, const unsigned c) {
+ return (w >> c) | (w << (64 - c));
+ }
+}
diff --git a/library/cpp/digest/argonish/internal/rotations/rotations_sse2.h b/library/cpp/digest/argonish/internal/rotations/rotations_sse2.h
new file mode 100644
index 0000000000..55a10a31b0
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/rotations/rotations_sse2.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <emmintrin.h>
+
+namespace NArgonish {
+ static inline void XorValues(__m128i* result, const __m128i* val1, const __m128i* val2) {
+ _mm_storeu_si128(result, _mm_xor_si128(
+ _mm_loadu_si128(val1),
+ _mm_loadu_si128(val2)));
+ }
+
+ static inline __m128i Rotr32(__m128i x) {
+ return _mm_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1));
+ }
+
+ static inline __m128i Rotr24(__m128i x) {
+ return _mm_xor_si128(_mm_srli_epi64(x, 24), _mm_slli_epi64(x, 40));
+ }
+
+ static inline __m128i Rotr16(__m128i x) {
+ return _mm_xor_si128(_mm_srli_epi64(x, 16), _mm_slli_epi64(x, 48));
+ }
+
+ static inline __m128i Rotr63(__m128i x) {
+ return _mm_xor_si128(_mm_srli_epi64(x, 63), _mm_add_epi64(x, x));
+ }
+}
diff --git a/library/cpp/digest/argonish/internal/rotations/rotations_ssse3.h b/library/cpp/digest/argonish/internal/rotations/rotations_ssse3.h
new file mode 100644
index 0000000000..39c9c5491b
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/rotations/rotations_ssse3.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <emmintrin.h>
+#include <tmmintrin.h>
+
+namespace NArgonish {
+ static inline void XorValues(__m128i* result, __m128i* val1, __m128i* val2) {
+ _mm_storeu_si128(result, _mm_xor_si128(
+ _mm_loadu_si128(val1),
+ _mm_loadu_si128(val2)));
+ }
+
+ static inline __m128i Rotr32(__m128i x) {
+ return _mm_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1));
+ }
+
+ static inline __m128i Rotr24(__m128i x) {
+ return _mm_shuffle_epi8(x, _mm_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10));
+ }
+
+ static inline __m128i Rotr16(__m128i x) {
+ return _mm_shuffle_epi8(x, _mm_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9));
+ }
+
+ static inline __m128i Rotr63(__m128i x) {
+ return _mm_xor_si128(_mm_srli_epi64(x, 63), _mm_add_epi64(x, x));
+ }
+}
diff --git a/library/cpp/digest/argonish/internal/rotations/ya.make b/library/cpp/digest/argonish/internal/rotations/ya.make
new file mode 100644
index 0000000000..5f639d4571
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/rotations/ya.make
@@ -0,0 +1,5 @@
+LIBRARY()
+
+OWNER(e-sidorov)
+
+END()
diff --git a/library/cpp/digest/argonish/internal/ya.make b/library/cpp/digest/argonish/internal/ya.make
new file mode 100644
index 0000000000..4a69395970
--- /dev/null
+++ b/library/cpp/digest/argonish/internal/ya.make
@@ -0,0 +1,7 @@
+RECURSE(
+ proxies
+ argon2
+ blake2b
+ blamka
+ rotations
+)
diff --git a/library/cpp/digest/argonish/ut/ut.cpp b/library/cpp/digest/argonish/ut/ut.cpp
new file mode 100644
index 0000000000..12ef530a18
--- /dev/null
+++ b/library/cpp/digest/argonish/ut/ut.cpp
@@ -0,0 +1,549 @@
+#include <library/cpp/digest/argonish/argon2.h>
+#include <library/cpp/digest/argonish/blake2b.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(ArgonishTest) {
+ const ui8 GenKatPassword[32] = {
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ };
+
+ const ui8 GenKatSalt[16] = {
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ };
+
+ const ui8 GenKatSecret[8] = {
+ 0x03,
+ 0x03,
+ 0x03,
+ 0x03,
+ 0x03,
+ 0x03,
+ 0x03,
+ 0x03,
+ };
+
+ const ui8 FrPassword[13] = {
+ 'm',
+ 'e',
+ 'g',
+ 'a',
+ '_',
+ 'p',
+ 'a',
+ 's',
+ 's',
+ 'w',
+ 'o',
+ 'r',
+ 'd',
+ };
+
+ const ui8 FrSecret[16] = {
+ 'm',
+ 'e',
+ 'g',
+ 'a',
+ '_',
+ 's',
+ 'e',
+ 'c',
+ 'r',
+ 'e',
+ 't',
+ '_',
+ 'k',
+ 'e',
+ 'y',
+ '2',
+ };
+
+ const ui8 FrSalt[9] = {
+ 'm',
+ 'e',
+ 'g',
+ 'a',
+ '_',
+ 's',
+ 'a',
+ 'l',
+ 't',
+ };
+
+ const ui8 GenKatAAD[12] = {
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ };
+
+ Y_UNIT_TEST(Argon2_Fr_Test) {
+ const ui32 mcost = 16;
+ const ui32 tcost = 1;
+ TArrayHolder<ui8> memory(new ui8[mcost * 1024]);
+ const ui8 TResult[165] = {
+ 0xe6, 0xff, 0x7b, 0xa1, 0xfa, 0x93, 0x0a, 0x51,
+ 0x24, 0xf3, 0xbc, 0xc4, 0x98, 0xe2, 0x32, 0x08,
+ 0x22, 0x7d, 0x4d, 0xf9, 0xe7, 0x2c, 0xd2, 0xd8,
+ 0x21, 0x6b, 0x3f, 0xf3, 0xfc, 0x3d, 0xa2, 0x79,
+ 0xb8, 0xdb, 0xfe, 0xfc, 0x18, 0xfa, 0x33, 0x08,
+ 0x45, 0x03, 0x5f, 0x21, 0x0d, 0xaa, 0x05, 0x5f,
+ 0x57, 0x6f, 0xc5, 0x4c, 0xba, 0xe7, 0xcd, 0xcf,
+ 0x8e, 0xc3, 0xc1, 0xab, 0x40, 0xea, 0x18, 0xca,
+ 0xe4, 0xa1, 0x08, 0x23, 0x54, 0x8d, 0xc0, 0x39,
+ 0x2c, 0xdd, 0x7e, 0x1f, 0x06, 0x6a, 0x2c, 0x25,
+ 0xe3, 0x7b, 0xbd, 0x45, 0xa3, 0xd8, 0xeb, 0x4c,
+ 0x44, 0xc3, 0x00, 0x52, 0x84, 0x35, 0x6c, 0x48,
+ 0xb2, 0xbc, 0x43, 0xd6, 0x58, 0xa9, 0x85, 0x78,
+ 0xe0, 0x2a, 0x6c, 0x0b, 0x42, 0x9a, 0x60, 0x62,
+ 0xc8, 0xe8, 0x62, 0x5d, 0xab, 0x3c, 0xfc, 0xba,
+ 0xe2, 0x84, 0x11, 0xda, 0x68, 0x79, 0x36, 0x13,
+ 0x84, 0x78, 0x6f, 0x47, 0x6a, 0x01, 0xd9, 0x94,
+ 0x8c, 0x6a, 0x81, 0xdc, 0x59, 0x82, 0xcd, 0x99,
+ 0x9b, 0x0a, 0x11, 0x8f, 0x1c, 0x09, 0x25, 0x2f,
+ 0x07, 0xf4, 0x50, 0xf9, 0x3f, 0xd7, 0xe7, 0x7b,
+ 0x0c, 0xc9, 0xe4, 0xc8, 0xe9};
+
+ try {
+ NArgonish::TArgon2Factory factory;
+ NArgonish::EInstructionSet maxInstructionSet = factory.GetInstructionSet();
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)maxInstructionSet; ++i) {
+ auto argon2d = factory.Create((NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2d, tcost, mcost, 1,
+ FrSecret, sizeof(FrSecret));
+ ui8 hashResult[sizeof(TResult)];
+ argon2d->HashWithCustomMemory(memory.Get(), mcost * 1024, FrPassword, sizeof(FrPassword),
+ FrSalt, sizeof(FrSalt), hashResult, sizeof(hashResult));
+ UNIT_ASSERT(memcmp(hashResult, TResult, sizeof(hashResult)) == 0);
+
+ UNIT_ASSERT(argon2d->VerifyWithCustomMemory(memory.Get(), mcost * 1024, FrPassword, sizeof(FrPassword),
+ FrSalt, sizeof(FrSalt), TResult, sizeof(TResult)));
+ }
+ } catch (...) {
+ UNIT_FAIL("Argon2 fraction len test fail");
+ }
+ }
+
+ Y_UNIT_TEST(Argon2_Factory_SelfTest) {
+ try {
+ NArgonish::TArgon2Factory factory;
+ factory.GetInstructionSet();
+ } catch (...) {
+ UNIT_FAIL("Argon2 factory self-test fail");
+ }
+ }
+
+ Y_UNIT_TEST(Blake2B_Factory_SelfTest) {
+ try {
+ NArgonish::TBlake2BFactory factory;
+ factory.GetInstructionSet();
+ } catch (...) {
+ UNIT_FAIL("Blake2B factory self-test fail");
+ }
+ }
+
+ Y_UNIT_TEST(Argon2d) {
+ const ui8 TResult[32] = {
+ 0x7b, 0xa5, 0xa1, 0x7a, 0x72, 0xf7, 0xe5, 0x99,
+ 0x77, 0xf7, 0xf2, 0x3d, 0x10, 0xe6, 0x21, 0x89,
+ 0x8c, 0x63, 0xce, 0xbe, 0xed, 0xda, 0xbd, 0x15,
+ 0xd8, 0xc6, 0x8f, 0x53, 0xea, 0xb2, 0x1a, 0x32};
+
+ NArgonish::TArgon2Factory factory;
+ NArgonish::EInstructionSet maxInstructionSet = factory.GetInstructionSet();
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)maxInstructionSet; ++i) {
+ ui8 result[32];
+ auto argon2d = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2d,
+ 1, 32, 1, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2d->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2d->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2i) {
+ const ui8 TResult[32] = {
+ 0x87, 0x4d, 0x23, 0xfb, 0x9f, 0x55, 0xe2, 0xff,
+ 0x66, 0xbc, 0x19, 0x03, 0x46, 0xe7, 0x01, 0x19,
+ 0x7c, 0x9f, 0x25, 0xd1, 0x1d, 0xa4, 0x5a, 0xad,
+ 0x0d, 0x5d, 0x24, 0x19, 0x8a, 0xac, 0xd2, 0xbb};
+
+ NArgonish::TArgon2Factory factory;
+ NArgonish::EInstructionSet maxInstructionSet = factory.GetInstructionSet();
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)maxInstructionSet; ++i) {
+ ui8 result[32];
+ auto argon2i = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2i,
+ 1, 32, 1, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2i->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2i->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2id) {
+ const ui8 TResult[32] = {
+ 0x99, 0xdf, 0xcf, 0xc2, 0x89, 0x76, 0x93, 0x9d,
+ 0xa2, 0x97, 0x09, 0x44, 0x34, 0xd8, 0x6f, 0xd0,
+ 0x0c, 0x94, 0x9a, 0x0f, 0x31, 0x8c, 0x22, 0xf0,
+ 0xcb, 0xb4, 0x69, 0xaa, 0xa8, 0x72, 0x18, 0xba};
+
+ NArgonish::TArgon2Factory factory;
+ NArgonish::EInstructionSet maxInstructionSet = factory.GetInstructionSet();
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)maxInstructionSet; ++i) {
+ ui8 result[32];
+ auto argon2id = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2id,
+ 1, 32, 1, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2id->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2id->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2d_2p) {
+ const ui8 TResult[32] = {
+ 0x59, 0xb0, 0x94, 0x62, 0xcf, 0xdc, 0xd2, 0xb4,
+ 0x0a, 0xbd, 0x17, 0x81, 0x0a, 0x47, 0x4a, 0x8e,
+ 0xc1, 0xab, 0xb7, 0xc1, 0x8d, 0x07, 0x53, 0x7c,
+ 0xb9, 0x64, 0xa2, 0x59, 0x3f, 0xe9, 0xd9, 0xc5};
+
+ NArgonish::TArgon2Factory factory;
+ NArgonish::EInstructionSet maxInstructionSet = factory.GetInstructionSet();
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)maxInstructionSet; ++i) {
+ ui8 result[32];
+ auto argon2d = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2d,
+ 2, 32, 1, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2d->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2d->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2i_2p) {
+ const ui8 TResult[32] = {
+ 0xc1, 0x0f, 0x00, 0x5e, 0xf8, 0x78, 0xc8, 0x07,
+ 0x0e, 0x2c, 0xc5, 0x2f, 0x57, 0x75, 0x25, 0xc9,
+ 0x71, 0xc7, 0x30, 0xeb, 0x00, 0x64, 0x4a, 0x4e,
+ 0x26, 0xd0, 0x6e, 0xad, 0x75, 0x46, 0xe0, 0x44};
+
+ NArgonish::TArgon2Factory factory;
+ NArgonish::EInstructionSet maxInstructionSet = factory.GetInstructionSet();
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)maxInstructionSet; ++i) {
+ ui8 result[32];
+ auto argon2i = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2i,
+ 2, 32, 1, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2i->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2i->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2id_2p) {
+ const ui8 TResult[32] = {
+ 0x6c, 0x00, 0xb7, 0xa9, 0x00, 0xe5, 0x00, 0x4c,
+ 0x24, 0x46, 0x9e, 0xc1, 0xe7, 0xc0, 0x1a, 0x99,
+ 0xb2, 0xb8, 0xf7, 0x73, 0x75, 0xd4, 0xec, 0xa7,
+ 0xd8, 0x08, 0x42, 0x11, 0xd3, 0x23, 0x6b, 0x7a};
+
+ NArgonish::TArgon2Factory factory;
+ NArgonish::EInstructionSet maxInstructionSet = factory.GetInstructionSet();
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)maxInstructionSet; ++i) {
+ ui8 result[32];
+ auto argon2id = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2id,
+ 2, 32, 1, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2id->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2id->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2d_2p_2th) {
+ const ui8 TResult[32] = {
+ 0x2b, 0x47, 0x35, 0x39, 0x4a, 0x40, 0x3c, 0xc9,
+ 0x05, 0xfb, 0x51, 0x25, 0x96, 0x68, 0x64, 0x43,
+ 0x02, 0x16, 0x38, 0xa6, 0xc1, 0x58, 0xfc, 0x8d,
+ 0xbf, 0x35, 0x73, 0x9a, 0xdb, 0x31, 0x0c, 0x60};
+
+ NArgonish::TArgon2Factory factory;
+ NArgonish::EInstructionSet maxInstructionSet = factory.GetInstructionSet();
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)maxInstructionSet; ++i) {
+ ui8 result[32];
+ auto argon2d = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2d,
+ 2, 32, 2, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2d->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2d->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2id_2p_4th) {
+ const ui8 TResult[32] = {
+ 0x4f, 0x93, 0xb5, 0xad, 0x78, 0xa4, 0xa9, 0x49,
+ 0xfb, 0xe3, 0x55, 0x96, 0xd5, 0xa0, 0xc2, 0xab,
+ 0x6f, 0x52, 0x2d, 0x2d, 0x29, 0xbc, 0x98, 0x49,
+ 0xca, 0x92, 0xaa, 0xae, 0xba, 0x05, 0x29, 0xd8};
+
+ NArgonish::TArgon2Factory factory;
+ NArgonish::EInstructionSet maxInstructionSet = factory.GetInstructionSet();
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)maxInstructionSet; ++i) {
+ ui8 result[32];
+ auto argon2id = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2id,
+ 2, 64, 4, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2id->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2id->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2d_2p_4th) {
+ const ui8 TResult[32] = {
+ 0x8f, 0xa2, 0x7c, 0xed, 0x28, 0x38, 0x79, 0x0f,
+ 0xba, 0x5c, 0x11, 0x85, 0x1c, 0xdf, 0x90, 0x88,
+ 0xb2, 0x18, 0x44, 0xd7, 0xf0, 0x4c, 0x97, 0xb2,
+ 0xca, 0xaf, 0xe4, 0xdc, 0x61, 0x4c, 0xae, 0xb2};
+
+ NArgonish::TArgon2Factory factory;
+ NArgonish::EInstructionSet maxInstructionSet = factory.GetInstructionSet();
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)maxInstructionSet; ++i) {
+ ui8 result[32];
+ auto argon2d = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2d,
+ 2, 64, 4, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2d->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2d->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2i_2p_4th) {
+ const ui8 TResult[32] = {
+ 0x61, 0x1c, 0x99, 0x3c, 0xb0, 0xb7, 0x23, 0x16,
+ 0xbd, 0xa2, 0x6c, 0x4c, 0x2f, 0xe8, 0x2d, 0x39,
+ 0x9c, 0x8f, 0x1c, 0xfd, 0x45, 0xd9, 0x58, 0xa9,
+ 0xb4, 0x9c, 0x6c, 0x64, 0xaf, 0xf0, 0x79, 0x0b};
+
+ NArgonish::TArgon2Factory factory;
+ NArgonish::EInstructionSet maxInstructionSet = factory.GetInstructionSet();
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)maxInstructionSet; ++i) {
+ ui8 result[32];
+ auto argon2i = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2i,
+ 2, 64, 4, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2i->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2i->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2d_128) {
+ const ui8 TResult[128] = {
+ 0x4e, 0xc4, 0x6c, 0x4e, 0x8c, 0x32, 0x89, 0x65,
+ 0xf9, 0x82, 0x2b, 0x00, 0x95, 0x00, 0x50, 0x0a,
+ 0x72, 0x0d, 0xc5, 0x12, 0x8d, 0x6b, 0xbd, 0x84,
+ 0x7a, 0xf0, 0x78, 0x5d, 0xa6, 0x14, 0xe3, 0xf1,
+ 0xac, 0x07, 0x1c, 0xca, 0x12, 0x4d, 0x32, 0xa4,
+ 0x24, 0x08, 0x5e, 0x07, 0x7c, 0x26, 0xb9, 0x1b,
+ 0x5c, 0xc0, 0xff, 0xb8, 0x7a, 0x20, 0x00, 0xcb,
+ 0x07, 0x2b, 0xb4, 0x4d, 0x7b, 0x5b, 0x79, 0x9e,
+ 0xb4, 0x21, 0xcb, 0x63, 0xeb, 0x46, 0xd7, 0x79,
+ 0x44, 0x9c, 0x9f, 0xee, 0xa4, 0x17, 0xb5, 0x01,
+ 0x0f, 0x61, 0x7e, 0xd8, 0xec, 0x1b, 0xe3, 0x8b,
+ 0x9a, 0x74, 0x17, 0x19, 0x9d, 0x80, 0xe9, 0x20,
+ 0xd4, 0x84, 0xdd, 0x07, 0x40, 0xb2, 0x26, 0xdb,
+ 0xf7, 0xbe, 0x79, 0x7f, 0x81, 0x59, 0x86, 0xf3,
+ 0xe9, 0x34, 0xe4, 0x52, 0xcd, 0x33, 0xb9, 0xf8,
+ 0x9e, 0x62, 0x65, 0x89, 0xbb, 0xce, 0x7d, 0x65};
+
+ NArgonish::TArgon2Factory factory;
+ NArgonish::EInstructionSet maxInstructionSet = factory.GetInstructionSet();
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)maxInstructionSet; ++i) {
+ ui8 result[128];
+ auto argon2d = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2d,
+ 1, 32, 1, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2d->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2d->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Blake2B_16_ABC) {
+ const ui8 TResult[16] = {
+ 0xcf, 0x4a, 0xb7, 0x91, 0xc6, 0x2b, 0x8d, 0x2b,
+ 0x21, 0x09, 0xc9, 0x02, 0x75, 0x28, 0x78, 0x16};
+ const ui8 data[] = {'a', 'b', 'c'};
+
+ NArgonish::TBlake2BFactory factory;
+ NArgonish::EInstructionSet maxInstructionSet = factory.GetInstructionSet();
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)maxInstructionSet; ++i) {
+ auto blake2b = factory.Create((NArgonish::EInstructionSet)i, sizeof(TResult));
+ ui8 hashResult[16] = {0};
+
+ blake2b->Update(data, sizeof(data));
+ blake2b->Final(hashResult, sizeof(hashResult));
+
+ UNIT_ASSERT(memcmp(hashResult, TResult, sizeof(TResult)) == 0);
+ }
+ }
+
+ Y_UNIT_TEST(Blake2B_64_ABC) {
+ const ui8 TResult[64] = {
+ 0xba, 0x80, 0xa5, 0x3f, 0x98, 0x1c, 0x4d, 0x0d,
+ 0x6a, 0x27, 0x97, 0xb6, 0x9f, 0x12, 0xf6, 0xe9,
+ 0x4c, 0x21, 0x2f, 0x14, 0x68, 0x5a, 0xc4, 0xb7,
+ 0x4b, 0x12, 0xbb, 0x6f, 0xdb, 0xff, 0xa2, 0xd1,
+ 0x7d, 0x87, 0xc5, 0x39, 0x2a, 0xab, 0x79, 0x2d,
+ 0xc2, 0x52, 0xd5, 0xde, 0x45, 0x33, 0xcc, 0x95,
+ 0x18, 0xd3, 0x8a, 0xa8, 0xdb, 0xf1, 0x92, 0x5a,
+ 0xb9, 0x23, 0x86, 0xed, 0xd4, 0x00, 0x99, 0x23};
+ const ui8 data[] = {'a', 'b', 'c'};
+
+ NArgonish::TBlake2BFactory factory;
+ NArgonish::EInstructionSet maxInstructionSet = factory.GetInstructionSet();
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)maxInstructionSet; ++i) {
+ auto blake2b = factory.Create((NArgonish::EInstructionSet)i, sizeof(TResult));
+ ui8 hashResult[64] = {0};
+
+ blake2b->Update(data, sizeof(data));
+ blake2b->Final(hashResult, sizeof(hashResult));
+
+ UNIT_ASSERT(memcmp(hashResult, TResult, sizeof(TResult)) == 0);
+ }
+ }
+}
diff --git a/library/cpp/digest/argonish/ut/ya.make b/library/cpp/digest/argonish/ut/ya.make
new file mode 100644
index 0000000000..3440908799
--- /dev/null
+++ b/library/cpp/digest/argonish/ut/ya.make
@@ -0,0 +1,13 @@
+UNITTEST_FOR(library/cpp/digest/argonish)
+
+OWNER(e-sidorov)
+
+PEERDIR(
+ library/cpp/digest/argonish
+)
+
+SRCS(
+ ut.cpp
+)
+
+END()
diff --git a/library/cpp/digest/argonish/ut_fat/ut.cpp b/library/cpp/digest/argonish/ut_fat/ut.cpp
new file mode 100644
index 0000000000..41fa001685
--- /dev/null
+++ b/library/cpp/digest/argonish/ut_fat/ut.cpp
@@ -0,0 +1,441 @@
+#include <library/cpp/digest/argonish/argon2.h>
+#include <library/cpp/digest/argonish/blake2b.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(ArgonishTest) {
+ const ui8 GenKatPassword[32] = {
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ 0x01,
+ };
+
+ const ui8 GenKatSalt[16] = {
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ 0x02,
+ };
+
+ const ui8 GenKatSecret[8] = {
+ 0x03,
+ 0x03,
+ 0x03,
+ 0x03,
+ 0x03,
+ 0x03,
+ 0x03,
+ 0x03,
+ };
+
+ const ui8 GenKatAAD[12] = {
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ 0x04,
+ };
+
+ constexpr NArgonish::EInstructionSet MaxArch =
+#if !defined(_arm64_)
+ NArgonish::EInstructionSet::AVX2
+#else
+ NArgonish::EInstructionSet::REF
+#endif
+ ;
+
+ Y_UNIT_TEST(Argon2_Factory_SelfTest) {
+ try {
+ NArgonish::TArgon2Factory factory;
+ } catch (...) {
+ UNIT_FAIL("Argon2 factory self-test fail");
+ }
+ }
+
+ Y_UNIT_TEST(Argon2d) {
+ const ui8 TResult[32] = {
+ 0x7b, 0xa5, 0xa1, 0x7a, 0x72, 0xf7, 0xe5, 0x99,
+ 0x77, 0xf7, 0xf2, 0x3d, 0x10, 0xe6, 0x21, 0x89,
+ 0x8c, 0x63, 0xce, 0xbe, 0xed, 0xda, 0xbd, 0x15,
+ 0xd8, 0xc6, 0x8f, 0x53, 0xea, 0xb2, 0x1a, 0x32};
+
+ NArgonish::TArgon2Factory factory;
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)MaxArch; ++i) {
+ ui8 result[32];
+ auto argon2d = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2d,
+ 1, 32, 1, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2d->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2d->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2i) {
+ const ui8 TResult[32] = {
+ 0x87, 0x4d, 0x23, 0xfb, 0x9f, 0x55, 0xe2, 0xff,
+ 0x66, 0xbc, 0x19, 0x03, 0x46, 0xe7, 0x01, 0x19,
+ 0x7c, 0x9f, 0x25, 0xd1, 0x1d, 0xa4, 0x5a, 0xad,
+ 0x0d, 0x5d, 0x24, 0x19, 0x8a, 0xac, 0xd2, 0xbb};
+
+ NArgonish::TArgon2Factory factory;
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)MaxArch; ++i) {
+ ui8 result[32];
+ auto argon2i = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2i,
+ 1, 32, 1, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2i->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2i->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2id) {
+ const ui8 TResult[32] = {
+ 0x99, 0xdf, 0xcf, 0xc2, 0x89, 0x76, 0x93, 0x9d,
+ 0xa2, 0x97, 0x09, 0x44, 0x34, 0xd8, 0x6f, 0xd0,
+ 0x0c, 0x94, 0x9a, 0x0f, 0x31, 0x8c, 0x22, 0xf0,
+ 0xcb, 0xb4, 0x69, 0xaa, 0xa8, 0x72, 0x18, 0xba};
+
+ NArgonish::TArgon2Factory factory;
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)MaxArch; ++i) {
+ ui8 result[32];
+ auto argon2id = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2id,
+ 1, 32, 1, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2id->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2id->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2d_2p) {
+ const ui8 TResult[32] = {
+ 0x59, 0xb0, 0x94, 0x62, 0xcf, 0xdc, 0xd2, 0xb4,
+ 0x0a, 0xbd, 0x17, 0x81, 0x0a, 0x47, 0x4a, 0x8e,
+ 0xc1, 0xab, 0xb7, 0xc1, 0x8d, 0x07, 0x53, 0x7c,
+ 0xb9, 0x64, 0xa2, 0x59, 0x3f, 0xe9, 0xd9, 0xc5};
+
+ NArgonish::TArgon2Factory factory;
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)MaxArch; ++i) {
+ ui8 result[32];
+ auto argon2d = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2d,
+ 2, 32, 1, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2d->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2d->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2i_2p) {
+ const ui8 TResult[32] = {
+ 0xc1, 0x0f, 0x00, 0x5e, 0xf8, 0x78, 0xc8, 0x07,
+ 0x0e, 0x2c, 0xc5, 0x2f, 0x57, 0x75, 0x25, 0xc9,
+ 0x71, 0xc7, 0x30, 0xeb, 0x00, 0x64, 0x4a, 0x4e,
+ 0x26, 0xd0, 0x6e, 0xad, 0x75, 0x46, 0xe0, 0x44};
+
+ NArgonish::TArgon2Factory factory;
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)MaxArch; ++i) {
+ ui8 result[32];
+ auto argon2i = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2i,
+ 2, 32, 1, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2i->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2i->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2id_2p) {
+ const ui8 TResult[32] = {
+ 0x6c, 0x00, 0xb7, 0xa9, 0x00, 0xe5, 0x00, 0x4c,
+ 0x24, 0x46, 0x9e, 0xc1, 0xe7, 0xc0, 0x1a, 0x99,
+ 0xb2, 0xb8, 0xf7, 0x73, 0x75, 0xd4, 0xec, 0xa7,
+ 0xd8, 0x08, 0x42, 0x11, 0xd3, 0x23, 0x6b, 0x7a};
+
+ NArgonish::TArgon2Factory factory;
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)MaxArch; ++i) {
+ ui8 result[32];
+ auto argon2id = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2id,
+ 2, 32, 1, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2id->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2id->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2d_2p_2th) {
+ const ui8 TResult[32] = {
+ 0x2b, 0x47, 0x35, 0x39, 0x4a, 0x40, 0x3c, 0xc9,
+ 0x05, 0xfb, 0x51, 0x25, 0x96, 0x68, 0x64, 0x43,
+ 0x02, 0x16, 0x38, 0xa6, 0xc1, 0x58, 0xfc, 0x8d,
+ 0xbf, 0x35, 0x73, 0x9a, 0xdb, 0x31, 0x0c, 0x60};
+
+ NArgonish::TArgon2Factory factory;
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)MaxArch; ++i) {
+ ui8 result[32];
+ auto argon2d = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2d,
+ 2, 32, 2, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2d->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2d->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2id_2p_4th) {
+ const ui8 TResult[32] = {
+ 0x4f, 0x93, 0xb5, 0xad, 0x78, 0xa4, 0xa9, 0x49,
+ 0xfb, 0xe3, 0x55, 0x96, 0xd5, 0xa0, 0xc2, 0xab,
+ 0x6f, 0x52, 0x2d, 0x2d, 0x29, 0xbc, 0x98, 0x49,
+ 0xca, 0x92, 0xaa, 0xae, 0xba, 0x05, 0x29, 0xd8};
+
+ NArgonish::TArgon2Factory factory;
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)MaxArch; ++i) {
+ ui8 result[32];
+ auto argon2id = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2id,
+ 2, 64, 4, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2id->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2id->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2d_2p_4th) {
+ const ui8 TResult[32] = {
+ 0x8f, 0xa2, 0x7c, 0xed, 0x28, 0x38, 0x79, 0x0f,
+ 0xba, 0x5c, 0x11, 0x85, 0x1c, 0xdf, 0x90, 0x88,
+ 0xb2, 0x18, 0x44, 0xd7, 0xf0, 0x4c, 0x97, 0xb2,
+ 0xca, 0xaf, 0xe4, 0xdc, 0x61, 0x4c, 0xae, 0xb2};
+
+ NArgonish::TArgon2Factory factory;
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)MaxArch; ++i) {
+ ui8 result[32];
+ auto argon2d = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2d,
+ 2, 64, 4, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2d->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2d->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2i_2p_4th) {
+ const ui8 TResult[32] = {
+ 0x61, 0x1c, 0x99, 0x3c, 0xb0, 0xb7, 0x23, 0x16,
+ 0xbd, 0xa2, 0x6c, 0x4c, 0x2f, 0xe8, 0x2d, 0x39,
+ 0x9c, 0x8f, 0x1c, 0xfd, 0x45, 0xd9, 0x58, 0xa9,
+ 0xb4, 0x9c, 0x6c, 0x64, 0xaf, 0xf0, 0x79, 0x0b};
+
+ NArgonish::TArgon2Factory factory;
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)MaxArch; ++i) {
+ ui8 result[32];
+ auto argon2i = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2i,
+ 2, 64, 4, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2i->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2i->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Argon2d_128) {
+ const ui8 TResult[128] = {
+ 0x4e, 0xc4, 0x6c, 0x4e, 0x8c, 0x32, 0x89, 0x65,
+ 0xf9, 0x82, 0x2b, 0x00, 0x95, 0x00, 0x50, 0x0a,
+ 0x72, 0x0d, 0xc5, 0x12, 0x8d, 0x6b, 0xbd, 0x84,
+ 0x7a, 0xf0, 0x78, 0x5d, 0xa6, 0x14, 0xe3, 0xf1,
+ 0xac, 0x07, 0x1c, 0xca, 0x12, 0x4d, 0x32, 0xa4,
+ 0x24, 0x08, 0x5e, 0x07, 0x7c, 0x26, 0xb9, 0x1b,
+ 0x5c, 0xc0, 0xff, 0xb8, 0x7a, 0x20, 0x00, 0xcb,
+ 0x07, 0x2b, 0xb4, 0x4d, 0x7b, 0x5b, 0x79, 0x9e,
+ 0xb4, 0x21, 0xcb, 0x63, 0xeb, 0x46, 0xd7, 0x79,
+ 0x44, 0x9c, 0x9f, 0xee, 0xa4, 0x17, 0xb5, 0x01,
+ 0x0f, 0x61, 0x7e, 0xd8, 0xec, 0x1b, 0xe3, 0x8b,
+ 0x9a, 0x74, 0x17, 0x19, 0x9d, 0x80, 0xe9, 0x20,
+ 0xd4, 0x84, 0xdd, 0x07, 0x40, 0xb2, 0x26, 0xdb,
+ 0xf7, 0xbe, 0x79, 0x7f, 0x81, 0x59, 0x86, 0xf3,
+ 0xe9, 0x34, 0xe4, 0x52, 0xcd, 0x33, 0xb9, 0xf8,
+ 0x9e, 0x62, 0x65, 0x89, 0xbb, 0xce, 0x7d, 0x65};
+
+ NArgonish::TArgon2Factory factory;
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)MaxArch; ++i) {
+ ui8 result[128];
+ auto argon2d = factory.Create(
+ (NArgonish::EInstructionSet)i, NArgonish::EArgon2Type::Argon2d,
+ 1, 32, 1, GenKatSecret, sizeof(GenKatSecret));
+
+ argon2d->Hash(GenKatPassword, sizeof(GenKatPassword), GenKatSalt, sizeof(GenKatSalt),
+ result, sizeof(result), GenKatAAD, sizeof(GenKatAAD));
+
+ UNIT_ASSERT(memcmp(result, TResult, sizeof(result)) == 0);
+
+ UNIT_ASSERT(argon2d->Verify(GenKatPassword, sizeof(GenKatPassword),
+ GenKatSalt, sizeof(GenKatSalt),
+ TResult, sizeof(TResult),
+ GenKatAAD, sizeof(GenKatAAD)));
+ }
+ }
+
+ Y_UNIT_TEST(Blake2B_16_ABC) {
+ const ui8 TResult[16] = {
+ 0xcf, 0x4a, 0xb7, 0x91, 0xc6, 0x2b, 0x8d, 0x2b,
+ 0x21, 0x09, 0xc9, 0x02, 0x75, 0x28, 0x78, 0x16};
+ const ui8 data[] = {'a', 'b', 'c'};
+
+ NArgonish::TBlake2BFactory factory;
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)MaxArch; ++i) {
+ auto blake2b = factory.Create((NArgonish::EInstructionSet)i, sizeof(TResult));
+ ui8 hashResult[16] = {0};
+
+ blake2b->Update(data, sizeof(data));
+ blake2b->Final(hashResult, sizeof(hashResult));
+
+ UNIT_ASSERT(memcmp(hashResult, TResult, sizeof(TResult)) == 0);
+ }
+ }
+
+ Y_UNIT_TEST(Blake2B_64_ABC) {
+ const ui8 TResult[64] = {
+ 0xba, 0x80, 0xa5, 0x3f, 0x98, 0x1c, 0x4d, 0x0d,
+ 0x6a, 0x27, 0x97, 0xb6, 0x9f, 0x12, 0xf6, 0xe9,
+ 0x4c, 0x21, 0x2f, 0x14, 0x68, 0x5a, 0xc4, 0xb7,
+ 0x4b, 0x12, 0xbb, 0x6f, 0xdb, 0xff, 0xa2, 0xd1,
+ 0x7d, 0x87, 0xc5, 0x39, 0x2a, 0xab, 0x79, 0x2d,
+ 0xc2, 0x52, 0xd5, 0xde, 0x45, 0x33, 0xcc, 0x95,
+ 0x18, 0xd3, 0x8a, 0xa8, 0xdb, 0xf1, 0x92, 0x5a,
+ 0xb9, 0x23, 0x86, 0xed, 0xd4, 0x00, 0x99, 0x23};
+ const ui8 data[] = {'a', 'b', 'c'};
+
+ NArgonish::TBlake2BFactory factory;
+ for (int i = (int)NArgonish::EInstructionSet::REF; i <= (int)(int)MaxArch; ++i) {
+ auto blake2b = factory.Create((NArgonish::EInstructionSet)i, sizeof(TResult));
+ ui8 hashResult[64] = {0};
+
+ blake2b->Update(data, sizeof(data));
+ blake2b->Final(hashResult, sizeof(hashResult));
+
+ UNIT_ASSERT(memcmp(hashResult, TResult, sizeof(TResult)) == 0);
+ }
+ }
+}
diff --git a/library/cpp/digest/argonish/ut_fat/ya.make b/library/cpp/digest/argonish/ut_fat/ya.make
new file mode 100644
index 0000000000..94ebda9225
--- /dev/null
+++ b/library/cpp/digest/argonish/ut_fat/ya.make
@@ -0,0 +1,21 @@
+UNITTEST_FOR(library/cpp/digest/argonish)
+
+OWNER(e-sidorov)
+
+PEERDIR(
+ library/cpp/digest/argonish
+)
+
+SRCS(
+ ut.cpp
+)
+
+TAG(
+ sb:intel_e5_2660v4
+ ya:fat
+ ya:force_sandbox
+)
+
+SIZE(LARGE)
+
+END()
diff --git a/library/cpp/digest/argonish/ya.make b/library/cpp/digest/argonish/ya.make
new file mode 100644
index 0000000000..4a0e937279
--- /dev/null
+++ b/library/cpp/digest/argonish/ya.make
@@ -0,0 +1,25 @@
+LIBRARY()
+
+OWNER(e-sidorov)
+
+IF (ARCH_X86_64 OR ARCH_I386)
+ PEERDIR(
+ library/cpp/threading/poor_man_openmp
+ library/cpp/digest/argonish/internal/proxies/avx2
+ library/cpp/digest/argonish/internal/proxies/ref
+ library/cpp/digest/argonish/internal/proxies/sse2
+ library/cpp/digest/argonish/internal/proxies/sse41
+ library/cpp/digest/argonish/internal/proxies/ssse3
+ )
+ELSE()
+ PEERDIR(
+ library/cpp/threading/poor_man_openmp
+ library/cpp/digest/argonish/internal/proxies/ref
+ )
+ENDIF()
+
+SRCS(
+ factory/factory.cpp
+)
+
+END()
diff --git a/library/cpp/digest/crc32c/crc32c.cpp b/library/cpp/digest/crc32c/crc32c.cpp
new file mode 100644
index 0000000000..369b46a213
--- /dev/null
+++ b/library/cpp/digest/crc32c/crc32c.cpp
@@ -0,0 +1,40 @@
+#include "crc32c.h"
+
+#include <util/generic/singleton.h>
+
+#include <contrib/libs/crcutil/interface.h>
+
+namespace {
+ typedef crcutil_interface::CRC TCrc;
+
+ struct TCrcUtilSse4 {
+ TCrc* const Pimpl;
+
+ TCrcUtilSse4() noexcept
+ : Pimpl(TCrc::Create(0x82f63b78, 0, 32, true, 0, 0, 0, TCrc::IsSSE42Available(), nullptr))
+ {
+ }
+
+ ~TCrcUtilSse4() noexcept {
+ Pimpl->Delete();
+ }
+
+ inline ui32 Extend(ui32 init, const void* data, size_t n) const noexcept {
+ crcutil_interface::UINT64 sum = init;
+ Pimpl->Compute(data, n, &sum);
+ return (ui32)sum;
+ }
+ };
+}
+
+ui32 Crc32c(const void* p, size_t size) noexcept {
+ return Singleton<TCrcUtilSse4>()->Extend(0, p, size);
+}
+
+ui32 Crc32cExtend(ui32 init, const void* data, size_t n) noexcept {
+ return Singleton<TCrcUtilSse4>()->Extend(init, data, n);
+}
+
+bool HaveFastCrc32c() noexcept {
+ return TCrc::IsSSE42Available();
+}
diff --git a/library/cpp/digest/crc32c/crc32c.h b/library/cpp/digest/crc32c/crc32c.h
new file mode 100644
index 0000000000..17b554c8e1
--- /dev/null
+++ b/library/cpp/digest/crc32c/crc32c.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <util/system/types.h>
+
+// Threadsafe
+ui32 Crc32c(const void* p, size_t size) noexcept;
+ui32 Crc32cExtend(ui32 init, const void* data, size_t n) noexcept;
+
+bool HaveFastCrc32c() noexcept;
diff --git a/library/cpp/digest/crc32c/crc32c_ut.cpp b/library/cpp/digest/crc32c/crc32c_ut.cpp
new file mode 100644
index 0000000000..aa31b83422
--- /dev/null
+++ b/library/cpp/digest/crc32c/crc32c_ut.cpp
@@ -0,0 +1,23 @@
+#include "crc32c.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TestCrc32c) {
+ Y_UNIT_TEST(TestCalc) {
+ UNIT_ASSERT_VALUES_EQUAL(Crc32c("abc", 3), ui32(910901175));
+ }
+
+ Y_UNIT_TEST(TestUnaligned) {
+ const TString str(1000, 'a');
+ for (size_t substrLen = 0; substrLen <= str.length(); ++substrLen) {
+ const ui32 crc = Crc32c(str.data(), substrLen);
+ for (size_t offset = 1; offset + substrLen <= str.length(); ++offset) {
+ UNIT_ASSERT_VALUES_EQUAL(Crc32c(str.data() + offset, substrLen), crc);
+ }
+ }
+ }
+
+ Y_UNIT_TEST(TestExtend) {
+ UNIT_ASSERT_VALUES_EQUAL(Crc32cExtend(1, "abc", 3), ui32(2466950601));
+ }
+}
diff --git a/library/cpp/digest/crc32c/ut/ya.make b/library/cpp/digest/crc32c/ut/ya.make
new file mode 100644
index 0000000000..325622e080
--- /dev/null
+++ b/library/cpp/digest/crc32c/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/digest/crc32c)
+
+OWNER(pg)
+
+SRCS(
+ crc32c_ut.cpp
+)
+
+END()
diff --git a/library/cpp/digest/crc32c/ya.make b/library/cpp/digest/crc32c/ya.make
new file mode 100644
index 0000000000..d6faf16c9c
--- /dev/null
+++ b/library/cpp/digest/crc32c/ya.make
@@ -0,0 +1,22 @@
+LIBRARY()
+
+#!!!
+OWNER(
+ ddoarn
+ a-romanov
+ pg
+ gulin
+ dcherednik
+ g:yamr
+ g:rtmr
+)
+
+PEERDIR(
+ contrib/libs/crcutil
+)
+
+SRCS(
+ crc32c.cpp
+)
+
+END()
diff --git a/library/cpp/digest/lower_case/hash_ops.cpp b/library/cpp/digest/lower_case/hash_ops.cpp
new file mode 100644
index 0000000000..3f1746d830
--- /dev/null
+++ b/library/cpp/digest/lower_case/hash_ops.cpp
@@ -0,0 +1,23 @@
+#include "lchash.h"
+#include "lciter.h"
+#include "hash_ops.h"
+
+#include <util/generic/algorithm.h>
+
+size_t TCIOps::operator()(const TStringBuf& s) const noexcept {
+ return FnvCaseLess(s, (size_t)0xBEE);
+}
+
+size_t TCIOps::operator()(const char* s) const noexcept {
+ return operator()(TStringBuf(s));
+}
+
+bool TCIOps::operator()(const TStringBuf& f, const TStringBuf& s) const noexcept {
+ using TIter = TLowerCaseIterator<const char>;
+
+ return (f.size() == s.size()) && Equal(TIter(f.begin()), TIter(f.end()), TIter(s.begin()));
+}
+
+bool TCIOps::operator()(const char* f, const char* s) const noexcept {
+ return operator()(TStringBuf(f), TStringBuf(s));
+}
diff --git a/library/cpp/digest/lower_case/hash_ops.h b/library/cpp/digest/lower_case/hash_ops.h
new file mode 100644
index 0000000000..83ebf7aca4
--- /dev/null
+++ b/library/cpp/digest/lower_case/hash_ops.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+// can be used for caseless hashes like: THashMap<TStringBuf, T, TCIOps, TCIOps>
+
+struct TCIOps {
+ size_t operator()(const char* s) const noexcept;
+ size_t operator()(const TStringBuf& s) const noexcept;
+
+ bool operator()(const char* f, const char* s) const noexcept;
+ bool operator()(const TStringBuf& f, const TStringBuf& s) const noexcept;
+};
diff --git a/library/cpp/digest/lower_case/hash_ops_ut.cpp b/library/cpp/digest/lower_case/hash_ops_ut.cpp
new file mode 100644
index 0000000000..a7ab0b86ea
--- /dev/null
+++ b/library/cpp/digest/lower_case/hash_ops_ut.cpp
@@ -0,0 +1,36 @@
+#include "hash_ops.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TestCIHash) {
+ Y_UNIT_TEST(TestYHash1) {
+ THashMap<TStringBuf, int, TCIOps, TCIOps> h;
+
+ h["Ab"] = 1;
+ h["aB"] = 2;
+
+ UNIT_ASSERT_VALUES_EQUAL(h.size(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(h["ab"], 2);
+ }
+
+ Y_UNIT_TEST(TestYHash2) {
+ THashMap<const char*, int, TCIOps, TCIOps> h;
+
+ h["Ab"] = 1;
+ h["aB"] = 2;
+
+ UNIT_ASSERT_VALUES_EQUAL(h.size(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(h["ab"], 2);
+
+ h["Bc"] = 2;
+ h["bC"] = 3;
+
+ UNIT_ASSERT_VALUES_EQUAL(h.size(), 2);
+ UNIT_ASSERT_VALUES_EQUAL(h["bc"], 3);
+ }
+
+ Y_UNIT_TEST(Test1) {
+ UNIT_ASSERT_VALUES_EQUAL(TCIOps()("aBc3"), TCIOps()(TStringBuf("AbC3")));
+ UNIT_ASSERT(TCIOps()("aBc4", "AbC4"));
+ }
+}
diff --git a/library/cpp/digest/lower_case/lchash.cpp b/library/cpp/digest/lower_case/lchash.cpp
new file mode 100644
index 0000000000..92b4245533
--- /dev/null
+++ b/library/cpp/digest/lower_case/lchash.cpp
@@ -0,0 +1 @@
+#include "lchash.h"
diff --git a/library/cpp/digest/lower_case/lchash.h b/library/cpp/digest/lower_case/lchash.h
new file mode 100644
index 0000000000..6a287d9479
--- /dev/null
+++ b/library/cpp/digest/lower_case/lchash.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "lciter.h"
+
+#include <util/digest/fnv.h>
+#include <util/generic/strbuf.h>
+
+template <class T>
+static inline T FnvCaseLess(const char* b, size_t l, T t = 0) noexcept {
+ using TIter = TLowerCaseIterator<const char>;
+
+ return FnvHash(TIter(b), TIter(b + l), t);
+}
+
+template <class T>
+static inline T FnvCaseLess(const TStringBuf& s, T t = 0) noexcept {
+ return FnvCaseLess(s.data(), s.size(), t);
+}
diff --git a/library/cpp/digest/lower_case/lchash_ut.cpp b/library/cpp/digest/lower_case/lchash_ut.cpp
new file mode 100644
index 0000000000..5711fe7cd7
--- /dev/null
+++ b/library/cpp/digest/lower_case/lchash_ut.cpp
@@ -0,0 +1,21 @@
+#include "lchash.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TWebDaemonHash) {
+ Y_UNIT_TEST(Stability) {
+ UNIT_ASSERT_VALUES_EQUAL(FnvCaseLess<ui64>("blah"), ULL(5923727754379976229));
+ UNIT_ASSERT_VALUES_EQUAL(FnvCaseLess<ui64>("blahminor"), ULL(8755704309003440816));
+ }
+
+ Y_UNIT_TEST(CaseLess) {
+ UNIT_ASSERT_VALUES_EQUAL(FnvCaseLess<ui64>("blah"), FnvCaseLess<ui64>("bLah"));
+ UNIT_ASSERT_VALUES_EQUAL(FnvCaseLess<ui64>("blah"), FnvCaseLess<ui64>("blAh"));
+ UNIT_ASSERT_VALUES_EQUAL(FnvCaseLess<ui64>("blah"), FnvCaseLess<ui64>("BLAH"));
+ }
+
+ Y_UNIT_TEST(Robustness) {
+ UNIT_ASSERT(FnvCaseLess<ui64>("x-real-ip") != FnvCaseLess<ui64>("x-req-id"));
+ UNIT_ASSERT(FnvCaseLess<ui64>("x-real-ip") != FnvCaseLess<ui64>("x-start-time"));
+ }
+}
diff --git a/library/cpp/digest/lower_case/lciter.cpp b/library/cpp/digest/lower_case/lciter.cpp
new file mode 100644
index 0000000000..38d23eb2dd
--- /dev/null
+++ b/library/cpp/digest/lower_case/lciter.cpp
@@ -0,0 +1 @@
+#include "lciter.h"
diff --git a/library/cpp/digest/lower_case/lciter.h b/library/cpp/digest/lower_case/lciter.h
new file mode 100644
index 0000000000..9538e57932
--- /dev/null
+++ b/library/cpp/digest/lower_case/lciter.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <util/generic/typetraits.h>
+#include <util/string/ascii.h>
+
+#include <iterator>
+
+template <class T>
+struct TLowerCaseIterator: public std::iterator<std::input_iterator_tag, T> {
+ using TNonConst = std::remove_const_t<T>;
+
+ inline TLowerCaseIterator(T* c)
+ : C(c)
+ {
+ }
+
+ inline TLowerCaseIterator& operator++() noexcept {
+ ++C;
+
+ return *this;
+ }
+
+ inline TLowerCaseIterator operator++(int) noexcept {
+ return C++;
+ }
+
+ inline TNonConst operator*() const noexcept {
+ return AsciiToLower(*C);
+ }
+
+ T* C;
+};
+
+template <class T>
+inline bool operator==(const TLowerCaseIterator<T>& l, const TLowerCaseIterator<T>& r) noexcept {
+ return l.C == r.C;
+}
+
+template <class T>
+inline bool operator!=(const TLowerCaseIterator<T>& l, const TLowerCaseIterator<T>& r) noexcept {
+ return !(l == r);
+}
diff --git a/library/cpp/digest/lower_case/ut/ya.make b/library/cpp/digest/lower_case/ut/ya.make
new file mode 100644
index 0000000000..f083257b3d
--- /dev/null
+++ b/library/cpp/digest/lower_case/ut/ya.make
@@ -0,0 +1,13 @@
+UNITTEST_FOR(library/cpp/digest/lower_case)
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ lchash_ut.cpp
+ hash_ops_ut.cpp
+)
+
+END()
diff --git a/library/cpp/digest/lower_case/ya.make b/library/cpp/digest/lower_case/ya.make
new file mode 100644
index 0000000000..62cc16556a
--- /dev/null
+++ b/library/cpp/digest/lower_case/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ lciter.cpp
+ lchash.cpp
+ hash_ops.cpp
+)
+
+END()
diff --git a/library/cpp/digest/md5/bench/main.cpp b/library/cpp/digest/md5/bench/main.cpp
new file mode 100644
index 0000000000..8f6386d8a1
--- /dev/null
+++ b/library/cpp/digest/md5/bench/main.cpp
@@ -0,0 +1,20 @@
+#include <library/cpp/testing/benchmark/bench.h>
+#include <library/cpp/digest/md5/md5.h>
+
+#include <util/generic/xrange.h>
+
+#define MD5_DEF(N) \
+ Y_CPU_BENCHMARK(MD5_##N, iface) { \
+ char buf[N]; \
+ for (const auto i : xrange(iface.Iterations())) { \
+ Y_UNUSED(i); \
+ Y_DO_NOT_OPTIMIZE_AWAY(MD5().Update(buf, sizeof(buf))); \
+ } \
+ }
+
+MD5_DEF(32)
+MD5_DEF(64)
+MD5_DEF(128)
+
+MD5_DEF(1024)
+MD5_DEF(2048)
diff --git a/library/cpp/digest/md5/bench/ya.make b/library/cpp/digest/md5/bench/ya.make
new file mode 100644
index 0000000000..ad78159d8e
--- /dev/null
+++ b/library/cpp/digest/md5/bench/ya.make
@@ -0,0 +1,16 @@
+Y_BENCHMARK()
+
+OWNER(
+ pg
+ g:util
+)
+
+PEERDIR(
+ library/cpp/digest/md5
+)
+
+SRCS(
+ main.cpp
+)
+
+END()
diff --git a/library/cpp/digest/md5/md5.cpp b/library/cpp/digest/md5/md5.cpp
new file mode 100644
index 0000000000..27af7f88d7
--- /dev/null
+++ b/library/cpp/digest/md5/md5.cpp
@@ -0,0 +1,268 @@
+#include "md5.h"
+
+#include <contrib/libs/nayuki_md5/md5.h>
+
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+#include <util/stream/input.h>
+#include <util/stream/file.h>
+#include <library/cpp/string_utils/base64/base64.h>
+#include <util/string/hex.h>
+
+#include <cstring>
+#include <cstdlib>
+
+namespace {
+
+ constexpr size_t MD5_HEX_DIGEST_LENGTH = 32;
+
+ struct TMd5Stream: public IOutputStream {
+ inline TMd5Stream(MD5* md5)
+ : M_(md5)
+ {
+ }
+
+ void DoWrite(const void* buf, size_t len) override {
+ M_->Update(buf, len);
+ }
+
+ MD5* M_;
+ };
+}
+
+char* MD5::File(const char* filename, char* buf) {
+ try {
+ TUnbufferedFileInput fi(filename);
+
+ return Stream(&fi, buf);
+ } catch (...) {
+ }
+
+ return nullptr;
+}
+
+TString MD5::File(const TString& filename) {
+ TString buf;
+ buf.ReserveAndResize(MD5_HEX_DIGEST_LENGTH);
+ auto result = MD5::File(filename.data(), buf.begin());
+ if (result == nullptr) {
+ buf.clear();
+ }
+ return buf;
+}
+
+char* MD5::Data(const void* data, size_t len, char* buf) {
+ MD5 md5;
+ md5.Update(data, len);
+ return md5.End(buf);
+}
+
+TString MD5::Data(TArrayRef<ui8> data) {
+ MD5 md5;
+ md5.Update(data.data(), data.size());
+
+ TString buf;
+ buf.ReserveAndResize(MD5_HEX_DIGEST_LENGTH);
+ md5.End(buf.begin());
+ return buf;
+}
+
+TString MD5::Data(TStringBuf data) {
+ MD5 md5;
+ md5.Update(data.data(), data.size());
+
+ TString buf;
+ buf.ReserveAndResize(MD5_HEX_DIGEST_LENGTH);
+ md5.End(buf.begin());
+ return buf;
+}
+
+char* MD5::Stream(IInputStream* in, char* buf) {
+ return MD5().Update(in).End(buf);
+}
+
+MD5& MD5::Update(IInputStream* in) {
+ TMd5Stream md5(this);
+
+ TransferData(in, &md5);
+
+ return *this;
+}
+
+static inline void MD5Transform(ui32 state[4], const unsigned char block[64]) {
+ return md5_compress((uint32_t*)state, (const ui8*)block);
+}
+
+/*
+ * Encodes input (ui32) into output (unsigned char). Assumes len is
+ * a multiple of 4.
+ */
+
+static void Encode(unsigned char* output, ui32* input, unsigned int len) {
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j + 1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j + 2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j + 3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context. */
+
+void MD5::Init() {
+ Count[0] = Count[1] = 0;
+ /* Load magic initialization constants. */
+ State[0] = 0x67452301;
+ State[1] = 0xefcdab89;
+ State[2] = 0x98badcfe;
+ State[3] = 0x10325476;
+}
+
+/*
+ * MD5 block update operation. Continues an MD5 message-digest
+ * operation, processing another message block, and updating the
+ * context.
+ */
+
+void MD5::UpdatePart(const void* inputPtr, unsigned int inputLen) {
+ const unsigned char* input = (const unsigned char*)inputPtr;
+ unsigned int i, index, partLen;
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((Count[0] >> 3) & 0x3F);
+ /* Update number of bits */
+ if ((Count[0] += ((ui32)inputLen << 3)) < ((ui32)inputLen << 3))
+ Count[1]++;
+ Count[1] += ((ui32)inputLen >> 29);
+ partLen = 64 - index;
+ /* Transform as many times as possible. */
+ if (inputLen >= partLen) {
+ memcpy((void*)&Buffer[index], (const void*)input, partLen);
+ MD5Transform(State, Buffer);
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform(State, &input[i]);
+ index = 0;
+ } else
+ i = 0;
+ /* Buffer remaining input */
+ memcpy((void*)&Buffer[index], (const void*)&input[i], inputLen - i);
+}
+
+/*
+ * MD5 padding. Adds padding followed by original length.
+ */
+
+void MD5::Pad() {
+ unsigned char bits[8];
+ unsigned int index, padLen;
+ /* Save number of bits */
+ Encode(bits, Count, 8);
+ /* Pad out to 56 mod 64. */
+ index = (unsigned int)((Count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ Update(PADDING, padLen);
+ /* Append length (before padding) */
+ Update(bits, 8);
+}
+
+/*
+ * MD5 finalization. Ends an MD5 message-digest operation, writing the
+ * the message digest and zeroizing the context.
+ */
+
+unsigned char* MD5::Final(unsigned char digest[16]) {
+ /* Do padding. */
+ Pad();
+ /* Store state in digest */
+ Encode(digest, State, 16);
+ /* Zeroize sensitive information. */
+ memset((void*)this, 0, sizeof(*this));
+
+ return digest;
+}
+
+char* MD5::End(char* buf) {
+ unsigned char digest[16];
+ static const char hex[] = "0123456789abcdef";
+ if (!buf)
+ buf = (char*)malloc(33);
+ if (!buf)
+ return nullptr;
+ Final(digest);
+ int i = 0;
+ for (; i < 16; i++) {
+ buf[i + i] = hex[digest[i] >> 4];
+ buf[i + i + 1] = hex[digest[i] & 0x0f];
+ }
+ buf[i + i] = '\0';
+ return buf;
+}
+
+char* MD5::End_b64(char* buf) {
+ unsigned char digest[16];
+ if (!buf)
+ buf = (char*)malloc(25);
+ if (!buf)
+ return nullptr;
+ Final(digest);
+ Base64Encode(buf, digest, 16);
+ buf[24] = '\0';
+ return buf;
+}
+
+ui64 MD5::EndHalfMix() {
+ unsigned char digest[16];
+ Final(digest);
+ ui64 res = 0;
+ for (int i = 3; i >= 0; i--) {
+ res |= (ui64)(digest[0 + i] ^ digest[8 + i]) << ((3 - i) << 3);
+ res |= (ui64)(digest[4 + i] ^ digest[12 + i]) << ((7 - i) << 3);
+ }
+ return res;
+}
+
+TString MD5::Calc(const TStringBuf& data) {
+ TString result;
+ result.resize(32);
+
+ Data((const unsigned char*)data.data(), data.size(), result.begin());
+
+ return result;
+}
+
+TString MD5::CalcRaw(const TStringBuf& data) {
+ TString result;
+ result.resize(16);
+ MD5 md5;
+ md5.Update(data.data(), data.size());
+ md5.Final(reinterpret_cast<unsigned char*>(result.begin()));
+ return result;
+}
+
+ui64 MD5::CalcHalfMix(const char* data, size_t len) {
+ MD5 md5;
+ md5.Update(data, len);
+ return md5.EndHalfMix();
+}
+
+ui64 MD5::CalcHalfMix(const TStringBuf& data) {
+ return CalcHalfMix(data.data(), data.size());
+}
+
+bool MD5::IsMD5(const TStringBuf& data) {
+ if (data.size() != 32) {
+ return false;
+ }
+ for (const char *p = data.data(), *e = data.data() + data.size(); p != e; ++p) {
+ if (Char2DigitTable[(unsigned char)*p] == '\xff') {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/library/cpp/digest/md5/md5.h b/library/cpp/digest/md5/md5.h
new file mode 100644
index 0000000000..1568567e3c
--- /dev/null
+++ b/library/cpp/digest/md5/md5.h
@@ -0,0 +1,79 @@
+#pragma once
+
+#include <util/system/defaults.h>
+#include <util/generic/string.h>
+#include <util/generic/array_ref.h>
+#include <util/generic/strbuf.h>
+
+class IInputStream;
+
+class MD5 {
+public:
+ MD5() {
+ Init();
+ }
+
+ void Init();
+
+ inline MD5& Update(const void* data, size_t len) {
+ const char* buf = (const char*)data;
+
+ while (len) {
+ // NOTE: we don't want buffSz to be near Max<unsigned int>()
+ // because otherwise integer overflow might happen in UpdatePart
+ const unsigned int buffSz = Min(size_t(Max<unsigned int>() / 2), len);
+
+ UpdatePart(buf, buffSz);
+ buf += buffSz;
+ len -= buffSz;
+ }
+ return *this;
+ }
+
+ inline MD5& Update(const TStringBuf& data) {
+ return Update(data.data(), data.size());
+ }
+
+ void Pad();
+ unsigned char* Final(unsigned char[16]);
+
+ // buf must be char[33];
+ char* End(char* buf);
+
+ // buf must be char[25];
+ char* End_b64(char* buf);
+
+ // 8-byte xor-based mix
+ ui64 EndHalfMix();
+
+ MD5& Update(IInputStream* in);
+
+ /*
+ * Return hex-encoded md5 checksum for given file.
+ *
+ * Return nullptr / empty string if the file does not exist.
+ */
+ static char* File(const char* filename, char* buf);
+ static TString File(const TString& filename);
+
+ static char* Data(const void* data, size_t len, char* buf);
+ static TString Data(TArrayRef<ui8> data);
+ static TString Data(TStringBuf data);
+ static char* Stream(IInputStream* in, char* buf);
+
+ static TString Calc(const TStringBuf& data); // 32-byte hex-encoded
+ static TString CalcRaw(const TStringBuf& data); // 16-byte raw
+
+ static ui64 CalcHalfMix(const TStringBuf& data);
+ static ui64 CalcHalfMix(const char* data, size_t len);
+
+ static bool IsMD5(const TStringBuf& data);
+
+private:
+ void UpdatePart(const void* data, unsigned int len);
+
+private:
+ ui32 State[4]; /* state (ABCD) */
+ ui32 Count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char Buffer[64]; /* input buffer */
+};
diff --git a/library/cpp/digest/md5/md5_medium_ut.cpp b/library/cpp/digest/md5/md5_medium_ut.cpp
new file mode 100644
index 0000000000..a940c5cb66
--- /dev/null
+++ b/library/cpp/digest/md5/md5_medium_ut.cpp
@@ -0,0 +1,25 @@
+#include "md5.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TMD5MediumTest) {
+ Y_UNIT_TEST(TestOverflow) {
+ if (sizeof(size_t) > sizeof(unsigned int)) {
+ const size_t maxUi32 = (size_t)Max<unsigned int>();
+ TArrayHolder<char> buf(new char[maxUi32]);
+
+ memset(buf.Get(), 0, maxUi32);
+
+ MD5 r;
+ for (int i = 0; i < 5; ++i) {
+ r.Update(buf.Get(), maxUi32);
+ }
+
+ char rs[33];
+ TString s(r.End(rs));
+ s.to_lower();
+
+ UNIT_ASSERT_VALUES_EQUAL(s, "34a5a7ed4f0221310084e21a1e599659");
+ }
+ }
+}
diff --git a/library/cpp/digest/md5/md5_ut.cpp b/library/cpp/digest/md5/md5_ut.cpp
new file mode 100644
index 0000000000..fecccca9ba
--- /dev/null
+++ b/library/cpp/digest/md5/md5_ut.cpp
@@ -0,0 +1,66 @@
+#include "md5.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/system/fs.h>
+#include <util/stream/file.h>
+
+Y_UNIT_TEST_SUITE(TMD5Test) {
+ Y_UNIT_TEST(TestMD5) {
+ // echo -n 'qwertyuiopqwertyuiopasdfghjklasdfghjkl' | md5sum
+ constexpr const char* b = "qwertyuiopqwertyuiopasdfghjklasdfghjkl";
+
+ MD5 r;
+ r.Update((const unsigned char*)b, 15);
+ r.Update((const unsigned char*)b + 15, strlen(b) - 15);
+
+ char rs[33];
+ TString s(r.End(rs));
+ s.to_lower();
+
+ UNIT_ASSERT_EQUAL(s, TStringBuf("3ac00dd696b966fd74deee3c35a59d8f"));
+
+ TString result = r.Calc(TStringBuf(b));
+ result.to_lower();
+ UNIT_ASSERT_EQUAL(result, TStringBuf("3ac00dd696b966fd74deee3c35a59d8f"));
+ }
+
+ Y_UNIT_TEST(TestFile) {
+ TString s = NUnitTest::RandomString(1000000, 1);
+ const TString tmpFile = "tmp";
+
+ {
+ TFixedBufferFileOutput fo(tmpFile);
+ fo.Write(s.data(), s.size());
+ }
+
+ char fileBuf[100];
+ char memBuf[100];
+ TString fileHash = MD5::File(tmpFile.data(), fileBuf);
+ TString memoryHash = MD5::Data((const unsigned char*)s.data(), s.size(), memBuf);
+
+ UNIT_ASSERT_EQUAL(fileHash, memoryHash);
+
+ fileHash = MD5::File(tmpFile);
+ UNIT_ASSERT_EQUAL(fileHash, memoryHash);
+
+ NFs::Remove(tmpFile);
+ fileHash = MD5::File(tmpFile);
+ UNIT_ASSERT_EQUAL(fileHash.size(), 0);
+ }
+
+ Y_UNIT_TEST(TestIsMD5) {
+ UNIT_ASSERT_EQUAL(false, MD5::IsMD5(TStringBuf()));
+ UNIT_ASSERT_EQUAL(false, MD5::IsMD5(TStringBuf("4136ebb0e4c45d21e2b09294c75cfa0"))); // length 31
+ UNIT_ASSERT_EQUAL(false, MD5::IsMD5(TStringBuf("4136ebb0e4c45d21e2b09294c75cfa000"))); // length 33
+ UNIT_ASSERT_EQUAL(false, MD5::IsMD5(TStringBuf("4136ebb0e4c45d21e2b09294c75cfa0g"))); // wrong character 'g'
+ UNIT_ASSERT_EQUAL(true, MD5::IsMD5(TStringBuf("4136EBB0E4C45D21E2B09294C75CFA08")));
+ UNIT_ASSERT_EQUAL(true, MD5::IsMD5(TStringBuf("4136ebb0E4C45D21e2b09294C75CfA08")));
+ UNIT_ASSERT_EQUAL(true, MD5::IsMD5(TStringBuf("4136ebb0e4c45d21e2b09294c75cfa08")));
+ }
+
+ Y_UNIT_TEST(TestMd5HalfMix) {
+ UNIT_ASSERT_EQUAL(MD5::CalcHalfMix(""), 7203772011789518145ul);
+ UNIT_ASSERT_EQUAL(MD5::CalcHalfMix("qwertyuiopqwertyuiopasdfghjklasdfghjkl"), 11753545595885642730ul);
+ }
+}
diff --git a/library/cpp/digest/md5/medium_ut/ya.make b/library/cpp/digest/md5/medium_ut/ya.make
new file mode 100644
index 0000000000..418c57f086
--- /dev/null
+++ b/library/cpp/digest/md5/medium_ut/ya.make
@@ -0,0 +1,18 @@
+UNITTEST_FOR(library/cpp/digest/md5)
+
+SIZE(MEDIUM)
+
+TIMEOUT(120)
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ md5_medium_ut.cpp
+)
+
+REQUIREMENTS(ram:10)
+
+END()
diff --git a/library/cpp/digest/md5/ut/ya.make b/library/cpp/digest/md5/ut/ya.make
new file mode 100644
index 0000000000..ad1eddbff2
--- /dev/null
+++ b/library/cpp/digest/md5/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/digest/md5)
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ md5_ut.cpp
+)
+
+END()
diff --git a/library/cpp/digest/md5/ya.make b/library/cpp/digest/md5/ya.make
new file mode 100644
index 0000000000..c09ec1c326
--- /dev/null
+++ b/library/cpp/digest/md5/ya.make
@@ -0,0 +1,17 @@
+LIBRARY()
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ md5.cpp
+)
+
+PEERDIR(
+ contrib/libs/nayuki_md5
+ library/cpp/string_utils/base64
+)
+
+END()
diff --git a/library/cpp/digest/old_crc/crc.cpp b/library/cpp/digest/old_crc/crc.cpp
new file mode 100644
index 0000000000..994755f34d
--- /dev/null
+++ b/library/cpp/digest/old_crc/crc.cpp
@@ -0,0 +1,268 @@
+#include "crc.h"
+
+#include <library/cpp/digest/old_crc/crc.inc>
+
+#include <util/system/defaults.h>
+
+static const ui64 CRCTAB64[256] = {
+ ULL(0x0000000000000000),
+ ULL(0xE543279765927881),
+ ULL(0x2FC568B9AEB68983),
+ ULL(0xCA864F2ECB24F102),
+ ULL(0x5F8AD1735D6D1306),
+ ULL(0xBAC9F6E438FF6B87),
+ ULL(0x704FB9CAF3DB9A85),
+ ULL(0x950C9E5D9649E204),
+ ULL(0xBF15A2E6BADA260C),
+ ULL(0x5A568571DF485E8D),
+ ULL(0x90D0CA5F146CAF8F),
+ ULL(0x7593EDC871FED70E),
+ ULL(0xE09F7395E7B7350A),
+ ULL(0x05DC540282254D8B),
+ ULL(0xCF5A1B2C4901BC89),
+ ULL(0x2A193CBB2C93C408),
+ ULL(0x9B68625A10263499),
+ ULL(0x7E2B45CD75B44C18),
+ ULL(0xB4AD0AE3BE90BD1A),
+ ULL(0x51EE2D74DB02C59B),
+ ULL(0xC4E2B3294D4B279F),
+ ULL(0x21A194BE28D95F1E),
+ ULL(0xEB27DB90E3FDAE1C),
+ ULL(0x0E64FC07866FD69D),
+ ULL(0x247DC0BCAAFC1295),
+ ULL(0xC13EE72BCF6E6A14),
+ ULL(0x0BB8A805044A9B16),
+ ULL(0xEEFB8F9261D8E397),
+ ULL(0x7BF711CFF7910193),
+ ULL(0x9EB4365892037912),
+ ULL(0x5432797659278810),
+ ULL(0xB1715EE13CB5F091),
+ ULL(0xD393E32345DE11B3),
+ ULL(0x36D0C4B4204C6932),
+ ULL(0xFC568B9AEB689830),
+ ULL(0x1915AC0D8EFAE0B1),
+ ULL(0x8C19325018B302B5),
+ ULL(0x695A15C77D217A34),
+ ULL(0xA3DC5AE9B6058B36),
+ ULL(0x469F7D7ED397F3B7),
+ ULL(0x6C8641C5FF0437BF),
+ ULL(0x89C566529A964F3E),
+ ULL(0x4343297C51B2BE3C),
+ ULL(0xA6000EEB3420C6BD),
+ ULL(0x330C90B6A26924B9),
+ ULL(0xD64FB721C7FB5C38),
+ ULL(0x1CC9F80F0CDFAD3A),
+ ULL(0xF98ADF98694DD5BB),
+ ULL(0x48FB817955F8252A),
+ ULL(0xADB8A6EE306A5DAB),
+ ULL(0x673EE9C0FB4EACA9),
+ ULL(0x827DCE579EDCD428),
+ ULL(0x1771500A0895362C),
+ ULL(0xF232779D6D074EAD),
+ ULL(0x38B438B3A623BFAF),
+ ULL(0xDDF71F24C3B1C72E),
+ ULL(0xF7EE239FEF220326),
+ ULL(0x12AD04088AB07BA7),
+ ULL(0xD82B4B2641948AA5),
+ ULL(0x3D686CB12406F224),
+ ULL(0xA864F2ECB24F1020),
+ ULL(0x4D27D57BD7DD68A1),
+ ULL(0x87A19A551CF999A3),
+ ULL(0x62E2BDC2796BE122),
+ ULL(0x4264E1D1EE2E5BE7),
+ ULL(0xA727C6468BBC2366),
+ ULL(0x6DA189684098D264),
+ ULL(0x88E2AEFF250AAAE5),
+ ULL(0x1DEE30A2B34348E1),
+ ULL(0xF8AD1735D6D13060),
+ ULL(0x322B581B1DF5C162),
+ ULL(0xD7687F8C7867B9E3),
+ ULL(0xFD71433754F47DEB),
+ ULL(0x183264A03166056A),
+ ULL(0xD2B42B8EFA42F468),
+ ULL(0x37F70C199FD08CE9),
+ ULL(0xA2FB924409996EED),
+ ULL(0x47B8B5D36C0B166C),
+ ULL(0x8D3EFAFDA72FE76E),
+ ULL(0x687DDD6AC2BD9FEF),
+ ULL(0xD90C838BFE086F7E),
+ ULL(0x3C4FA41C9B9A17FF),
+ ULL(0xF6C9EB3250BEE6FD),
+ ULL(0x138ACCA5352C9E7C),
+ ULL(0x868652F8A3657C78),
+ ULL(0x63C5756FC6F704F9),
+ ULL(0xA9433A410DD3F5FB),
+ ULL(0x4C001DD668418D7A),
+ ULL(0x6619216D44D24972),
+ ULL(0x835A06FA214031F3),
+ ULL(0x49DC49D4EA64C0F1),
+ ULL(0xAC9F6E438FF6B870),
+ ULL(0x3993F01E19BF5A74),
+ ULL(0xDCD0D7897C2D22F5),
+ ULL(0x165698A7B709D3F7),
+ ULL(0xF315BF30D29BAB76),
+ ULL(0x91F702F2ABF04A54),
+ ULL(0x74B42565CE6232D5),
+ ULL(0xBE326A4B0546C3D7),
+ ULL(0x5B714DDC60D4BB56),
+ ULL(0xCE7DD381F69D5952),
+ ULL(0x2B3EF416930F21D3),
+ ULL(0xE1B8BB38582BD0D1),
+ ULL(0x04FB9CAF3DB9A850),
+ ULL(0x2EE2A014112A6C58),
+ ULL(0xCBA1878374B814D9),
+ ULL(0x0127C8ADBF9CE5DB),
+ ULL(0xE464EF3ADA0E9D5A),
+ ULL(0x716871674C477F5E),
+ ULL(0x942B56F029D507DF),
+ ULL(0x5EAD19DEE2F1F6DD),
+ ULL(0xBBEE3E4987638E5C),
+ ULL(0x0A9F60A8BBD67ECD),
+ ULL(0xEFDC473FDE44064C),
+ ULL(0x255A08111560F74E),
+ ULL(0xC0192F8670F28FCF),
+ ULL(0x5515B1DBE6BB6DCB),
+ ULL(0xB056964C8329154A),
+ ULL(0x7AD0D962480DE448),
+ ULL(0x9F93FEF52D9F9CC9),
+ ULL(0xB58AC24E010C58C1),
+ ULL(0x50C9E5D9649E2040),
+ ULL(0x9A4FAAF7AFBAD142),
+ ULL(0x7F0C8D60CA28A9C3),
+ ULL(0xEA00133D5C614BC7),
+ ULL(0x0F4334AA39F33346),
+ ULL(0xC5C57B84F2D7C244),
+ ULL(0x20865C139745BAC5),
+ ULL(0x84C9C3A3DC5CB7CE),
+ ULL(0x618AE434B9CECF4F),
+ ULL(0xAB0CAB1A72EA3E4D),
+ ULL(0x4E4F8C8D177846CC),
+ ULL(0xDB4312D08131A4C8),
+ ULL(0x3E003547E4A3DC49),
+ ULL(0xF4867A692F872D4B),
+ ULL(0x11C55DFE4A1555CA),
+ ULL(0x3BDC6145668691C2),
+ ULL(0xDE9F46D20314E943),
+ ULL(0x141909FCC8301841),
+ ULL(0xF15A2E6BADA260C0),
+ ULL(0x6456B0363BEB82C4),
+ ULL(0x811597A15E79FA45),
+ ULL(0x4B93D88F955D0B47),
+ ULL(0xAED0FF18F0CF73C6),
+ ULL(0x1FA1A1F9CC7A8357),
+ ULL(0xFAE2866EA9E8FBD6),
+ ULL(0x3064C94062CC0AD4),
+ ULL(0xD527EED7075E7255),
+ ULL(0x402B708A91179051),
+ ULL(0xA568571DF485E8D0),
+ ULL(0x6FEE18333FA119D2),
+ ULL(0x8AAD3FA45A336153),
+ ULL(0xA0B4031F76A0A55B),
+ ULL(0x45F724881332DDDA),
+ ULL(0x8F716BA6D8162CD8),
+ ULL(0x6A324C31BD845459),
+ ULL(0xFF3ED26C2BCDB65D),
+ ULL(0x1A7DF5FB4E5FCEDC),
+ ULL(0xD0FBBAD5857B3FDE),
+ ULL(0x35B89D42E0E9475F),
+ ULL(0x575A20809982A67D),
+ ULL(0xB2190717FC10DEFC),
+ ULL(0x789F483937342FFE),
+ ULL(0x9DDC6FAE52A6577F),
+ ULL(0x08D0F1F3C4EFB57B),
+ ULL(0xED93D664A17DCDFA),
+ ULL(0x2715994A6A593CF8),
+ ULL(0xC256BEDD0FCB4479),
+ ULL(0xE84F826623588071),
+ ULL(0x0D0CA5F146CAF8F0),
+ ULL(0xC78AEADF8DEE09F2),
+ ULL(0x22C9CD48E87C7173),
+ ULL(0xB7C553157E359377),
+ ULL(0x528674821BA7EBF6),
+ ULL(0x98003BACD0831AF4),
+ ULL(0x7D431C3BB5116275),
+ ULL(0xCC3242DA89A492E4),
+ ULL(0x2971654DEC36EA65),
+ ULL(0xE3F72A6327121B67),
+ ULL(0x06B40DF4428063E6),
+ ULL(0x93B893A9D4C981E2),
+ ULL(0x76FBB43EB15BF963),
+ ULL(0xBC7DFB107A7F0861),
+ ULL(0x593EDC871FED70E0),
+ ULL(0x7327E03C337EB4E8),
+ ULL(0x9664C7AB56ECCC69),
+ ULL(0x5CE288859DC83D6B),
+ ULL(0xB9A1AF12F85A45EA),
+ ULL(0x2CAD314F6E13A7EE),
+ ULL(0xC9EE16D80B81DF6F),
+ ULL(0x036859F6C0A52E6D),
+ ULL(0xE62B7E61A53756EC),
+ ULL(0xC6AD22723272EC29),
+ ULL(0x23EE05E557E094A8),
+ ULL(0xE9684ACB9CC465AA),
+ ULL(0x0C2B6D5CF9561D2B),
+ ULL(0x9927F3016F1FFF2F),
+ ULL(0x7C64D4960A8D87AE),
+ ULL(0xB6E29BB8C1A976AC),
+ ULL(0x53A1BC2FA43B0E2D),
+ ULL(0x79B8809488A8CA25),
+ ULL(0x9CFBA703ED3AB2A4),
+ ULL(0x567DE82D261E43A6),
+ ULL(0xB33ECFBA438C3B27),
+ ULL(0x263251E7D5C5D923),
+ ULL(0xC3717670B057A1A2),
+ ULL(0x09F7395E7B7350A0),
+ ULL(0xECB41EC91EE12821),
+ ULL(0x5DC540282254D8B0),
+ ULL(0xB88667BF47C6A031),
+ ULL(0x720028918CE25133),
+ ULL(0x97430F06E97029B2),
+ ULL(0x024F915B7F39CBB6),
+ ULL(0xE70CB6CC1AABB337),
+ ULL(0x2D8AF9E2D18F4235),
+ ULL(0xC8C9DE75B41D3AB4),
+ ULL(0xE2D0E2CE988EFEBC),
+ ULL(0x0793C559FD1C863D),
+ ULL(0xCD158A773638773F),
+ ULL(0x2856ADE053AA0FBE),
+ ULL(0xBD5A33BDC5E3EDBA),
+ ULL(0x5819142AA071953B),
+ ULL(0x929F5B046B556439),
+ ULL(0x77DC7C930EC71CB8),
+ ULL(0x153EC15177ACFD9A),
+ ULL(0xF07DE6C6123E851B),
+ ULL(0x3AFBA9E8D91A7419),
+ ULL(0xDFB88E7FBC880C98),
+ ULL(0x4AB410222AC1EE9C),
+ ULL(0xAFF737B54F53961D),
+ ULL(0x6571789B8477671F),
+ ULL(0x80325F0CE1E51F9E),
+ ULL(0xAA2B63B7CD76DB96),
+ ULL(0x4F684420A8E4A317),
+ ULL(0x85EE0B0E63C05215),
+ ULL(0x60AD2C9906522A94),
+ ULL(0xF5A1B2C4901BC890),
+ ULL(0x10E29553F589B011),
+ ULL(0xDA64DA7D3EAD4113),
+ ULL(0x3F27FDEA5B3F3992),
+ ULL(0x8E56A30B678AC903),
+ ULL(0x6B15849C0218B182),
+ ULL(0xA193CBB2C93C4080),
+ ULL(0x44D0EC25ACAE3801),
+ ULL(0xD1DC72783AE7DA05),
+ ULL(0x349F55EF5F75A284),
+ ULL(0xFE191AC194515386),
+ ULL(0x1B5A3D56F1C32B07),
+ ULL(0x314301EDDD50EF0F),
+ ULL(0xD400267AB8C2978E),
+ ULL(0x1E86695473E6668C),
+ ULL(0xFBC54EC316741E0D),
+ ULL(0x6EC9D09E803DFC09),
+ ULL(0x8B8AF709E5AF8488),
+ ULL(0x410CB8272E8B758A),
+ ULL(0xA44F9FB04B190D0B),
+};
+
+const ui32* crctab16 = CRCTAB16;
+const ui32* crctab32 = CRCTAB32;
+const ui64* crctab64 = CRCTAB64;
diff --git a/library/cpp/digest/old_crc/crc.h b/library/cpp/digest/old_crc/crc.h
new file mode 100644
index 0000000000..4a3ce6d05e
--- /dev/null
+++ b/library/cpp/digest/old_crc/crc.h
@@ -0,0 +1,90 @@
+#pragma once
+
+#include <util/system/defaults.h>
+
+#define CRC16INIT 0
+#define CRC32INIT 0
+#define CRC64INIT ULL(0xFFFFFFFFFFFFFFFF)
+
+// CCITT CRC-16
+inline ui16 crc16(const char* buf, size_t buflen, ui32 crcinit = CRC16INIT) {
+ ui32 crc = 0xFFFF & ((crcinit >> 8) ^ (crcinit << 8));
+ const char* end = buf + buflen;
+ extern const ui32* crctab16;
+
+ while (buf < end) {
+ crc = (crc >> 8) ^ crctab16[(crc ^ *buf) & 0xFF];
+ ++buf;
+ }
+ return (ui16)(0xFFFF & ((crc >> 8) ^ (crc << 8)));
+}
+
+struct IdTR {
+ Y_FORCE_INLINE static ui8 T(ui8 a) {
+ return a;
+ }
+};
+
+// CCITT CRC-32
+template <class TR>
+inline ui32 crc32(const char* buf, size_t buflen, ui32 crcinit = CRC32INIT) {
+ ui32 crc = crcinit ^ 0xFFFFFFFF;
+ const char* end = buf + buflen;
+ extern const ui32* crctab32;
+
+ while (buf < end) {
+ crc = (crc >> 8) ^ crctab32[(crc ^ TR::T((ui8)*buf)) & 0xFF];
+ ++buf;
+ }
+
+ return crc ^ 0xFFFFFFFF;
+}
+
+inline ui32 crc32(const char* buf, size_t buflen, ui32 crcinit = CRC32INIT) {
+ return crc32<IdTR>(buf, buflen, crcinit);
+}
+
+inline ui32 crc32(const void* buf, size_t buflen, ui32 crcinit = CRC32INIT) {
+ return crc32((const char*)buf, buflen, crcinit);
+}
+
+// Copyright (C) Sewell Development Corporation, 1994 - 1998.
+inline ui64 crc64(const void* buf, size_t buflen, ui64 crcinit = CRC64INIT) {
+ const unsigned char* ptr = (const unsigned char*)buf;
+ extern const ui64* crctab64;
+
+ while (buflen--) {
+ crcinit = crctab64[((crcinit >> 56) ^ *ptr++)] ^ (crcinit << 8);
+ }
+ return crcinit;
+}
+
+namespace NCrcPrivate {
+ template <unsigned N>
+ struct TCrcHelper;
+
+#define DEF_CRC_FUNC(t) \
+ template <> \
+ struct TCrcHelper<t> { \
+ static const ui##t Init = CRC##t##INIT; \
+ static inline ui##t Crc(const void* buf, size_t buflen, ui##t crcinit) { \
+ return crc##t((const char*)buf, buflen, crcinit); \
+ } \
+ };
+
+ DEF_CRC_FUNC(16)
+ DEF_CRC_FUNC(32)
+ DEF_CRC_FUNC(64)
+
+#undef DEF_CRC_FUNC
+}
+
+template <class T>
+static inline T Crc(const void* buf, size_t len, T init) {
+ return (T)NCrcPrivate::TCrcHelper<8 * sizeof(T)>::Crc(buf, len, init);
+}
+
+template <class T>
+static inline T Crc(const void* buf, size_t len) {
+ return Crc<T>(buf, len, (T)NCrcPrivate::TCrcHelper<8 * sizeof(T)>::Init);
+}
diff --git a/library/cpp/digest/old_crc/crc_ut.cpp b/library/cpp/digest/old_crc/crc_ut.cpp
new file mode 100644
index 0000000000..46e1d5d29b
--- /dev/null
+++ b/library/cpp/digest/old_crc/crc_ut.cpp
@@ -0,0 +1,74 @@
+#include "crc.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/output.h>
+
+class TCrcTest: public TTestBase {
+ UNIT_TEST_SUITE(TCrcTest);
+ UNIT_TEST(TestCrc16)
+ UNIT_TEST(TestCrc32)
+ UNIT_TEST(TestCrc64)
+ UNIT_TEST_SUITE_END();
+
+private:
+ inline void TestCrc16() {
+ const ui16 expected[] = {
+ 41719,
+ 57001,
+ 53722,
+ 3276};
+
+ Run<ui16>(expected);
+ }
+
+ inline void TestCrc32() {
+ const ui32 expected[] = {
+ 688229491UL,
+ 3543112608UL,
+ 4127534015UL,
+ 3009909774UL};
+
+ Run<ui32>(expected);
+ }
+
+ inline void TestCrc64() {
+ const ui64 expected[] = {
+ 12116107829328640258ULL,
+ 18186277744016380552ULL,
+ 249923753044811734ULL,
+ 7852471725963920356ULL};
+
+ Run<ui64>(expected);
+ }
+
+private:
+ template <class T>
+ inline void Run(const T* expected) {
+ ui8 buf[256];
+
+ for (size_t i = 0; i < 256; ++i) {
+ buf[i] = i;
+ }
+
+ Test<T>(buf, 256, expected[0]);
+ Test<T>(buf, 255, expected[1]);
+ Test<T>(buf, 254, expected[2]);
+ Test<T>(buf, 253, expected[3]);
+ }
+
+ template <class T>
+ inline void Test(const void* data, size_t len, T expected) {
+ const T res = Crc<T>(data, len);
+
+ try {
+ UNIT_ASSERT_EQUAL(res, expected);
+ } catch (...) {
+ Cerr << res << Endl;
+
+ throw;
+ }
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TCrcTest);
diff --git a/library/cpp/digest/old_crc/gencrc/main.cpp b/library/cpp/digest/old_crc/gencrc/main.cpp
new file mode 100644
index 0000000000..d5821304ce
--- /dev/null
+++ b/library/cpp/digest/old_crc/gencrc/main.cpp
@@ -0,0 +1,56 @@
+#include <util/stream/output.h>
+
+#define POLY_16 0x1021
+#define POLY_32 0xEDB88320UL
+#define POLY_64 ULL(0xE543279765927881)
+
+static void crc16init() {
+ ui32 CRCTAB16[256];
+ ui32 crc;
+ int i, j;
+
+ for (i = 0; i < 256; CRCTAB16[i++] = 0xFFFF & ((crc << 8) ^ (crc >> 8)))
+ for (crc = i, j = 8; j > 0; j--)
+ if (crc & 1)
+ crc = (crc >> 1) ^ POLY_16;
+ else
+ crc >>= 1;
+
+ for (size_t k = 0; k < 256; ++k) {
+ Cout << " ULL(" << CRCTAB16[k] << ")";
+
+ if (k != 255) {
+ Cout << ",\n";
+ }
+ }
+}
+
+static void crc32init() {
+ ui32 CRCTAB32[256];
+ ui32 crc;
+ int i, j;
+
+ for (i = 0; i < 256; CRCTAB32[i++] = crc)
+ for (crc = i, j = 8; j > 0; j--)
+ if (crc & 1)
+ crc = (crc >> 1) ^ POLY_32;
+ else
+ crc >>= 1;
+
+ for (size_t k = 0; k < 256; ++k) {
+ Cout << " ULL(" << CRCTAB32[k] << ")";
+
+ if (k != 255) {
+ Cout << ",\n";
+ }
+ }
+}
+
+int main() {
+ Cout << "static const ui32 CRCTAB16[] = {\n\n";
+ crc16init();
+ Cout << "\n};\n\n";
+ Cout << "static const ui32 CRCTAB32[] = {\n\n";
+ crc32init();
+ Cout << "\n};\n\n";
+}
diff --git a/library/cpp/digest/old_crc/gencrc/ya.make b/library/cpp/digest/old_crc/gencrc/ya.make
new file mode 100644
index 0000000000..df25863bee
--- /dev/null
+++ b/library/cpp/digest/old_crc/gencrc/ya.make
@@ -0,0 +1,9 @@
+PROGRAM()
+
+OWNER(pg)
+
+SRCS(
+ main.cpp
+)
+
+END()
diff --git a/library/cpp/digest/old_crc/ut/ya.make b/library/cpp/digest/old_crc/ut/ya.make
new file mode 100644
index 0000000000..a783bbae5b
--- /dev/null
+++ b/library/cpp/digest/old_crc/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/digest/old_crc)
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ crc_ut.cpp
+)
+
+END()
diff --git a/library/cpp/digest/old_crc/ya.make b/library/cpp/digest/old_crc/ya.make
new file mode 100644
index 0000000000..aa6ea8f6c5
--- /dev/null
+++ b/library/cpp/digest/old_crc/ya.make
@@ -0,0 +1,17 @@
+LIBRARY()
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ crc.cpp
+)
+
+RUN_PROGRAM(
+ library/cpp/digest/old_crc/gencrc
+ STDOUT crc.inc
+)
+
+END()
diff --git a/library/cpp/digest/sfh/sfh.cpp b/library/cpp/digest/sfh/sfh.cpp
new file mode 100644
index 0000000000..c10062105b
--- /dev/null
+++ b/library/cpp/digest/sfh/sfh.cpp
@@ -0,0 +1 @@
+#include "sfh.h"
diff --git a/library/cpp/digest/sfh/sfh.h b/library/cpp/digest/sfh/sfh.h
new file mode 100644
index 0000000000..372938654c
--- /dev/null
+++ b/library/cpp/digest/sfh/sfh.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <util/system/defaults.h>
+#include <util/system/unaligned_mem.h>
+
+inline ui32 SuperFastHash(const void* d, size_t l) noexcept {
+ ui32 hash = (ui32)l;
+ ui32 tmp;
+
+ if (!l || !d)
+ return 0;
+
+ TUnalignedMemoryIterator<ui16, 4> iter(d, l);
+
+ while (!iter.AtEnd()) {
+ hash += (ui32)iter.Next();
+ tmp = ((ui32)iter.Next() << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ hash += hash >> 11;
+ }
+
+ switch (iter.Left()) {
+ case 3:
+ hash += (ui32)iter.Next();
+ hash ^= hash << 16;
+ hash ^= ((ui32)(i32) * (const i8*)iter.Last()) << 18;
+ hash += hash >> 11;
+ break;
+
+ case 2:
+ hash += (ui32)iter.Cur();
+ hash ^= hash << 11;
+ hash += hash >> 17;
+ break;
+
+ case 1:
+ hash += *((const i8*)iter.Last());
+ hash ^= hash << 10;
+ hash += hash >> 1;
+ }
+
+ /* Force "avalanching" of final 127 bits */
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 4;
+ hash += hash >> 17;
+ hash ^= hash << 25;
+ hash += hash >> 6;
+
+ return hash;
+}
diff --git a/library/cpp/digest/sfh/sfh_ut.cpp b/library/cpp/digest/sfh/sfh_ut.cpp
new file mode 100644
index 0000000000..912999bae7
--- /dev/null
+++ b/library/cpp/digest/sfh/sfh_ut.cpp
@@ -0,0 +1,40 @@
+#include "sfh.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/output.h>
+
+class TSfhTest: public TTestBase {
+ UNIT_TEST_SUITE(TSfhTest);
+ UNIT_TEST(TestSfh)
+ UNIT_TEST_SUITE_END();
+
+private:
+ inline void TestSfh() {
+ ui8 buf[256];
+
+ for (size_t i = 0; i < 256; ++i) {
+ buf[i] = i;
+ }
+
+ Test(buf, 256, 3840866583UL);
+ Test(buf, 255, 325350515UL);
+ Test(buf, 254, 2920741773UL);
+ Test(buf, 253, 3586628615UL);
+ }
+
+private:
+ inline void Test(const void* data, size_t len, ui32 expected) {
+ const ui32 res = SuperFastHash(data, len);
+
+ try {
+ UNIT_ASSERT_EQUAL(res, expected);
+ } catch (...) {
+ Cerr << res << ", " << expected << Endl;
+
+ throw;
+ }
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TSfhTest);
diff --git a/library/cpp/digest/sfh/ut/ya.make b/library/cpp/digest/sfh/ut/ya.make
new file mode 100644
index 0000000000..256a66295a
--- /dev/null
+++ b/library/cpp/digest/sfh/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/digest/sfh)
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ sfh_ut.cpp
+)
+
+END()
diff --git a/library/cpp/digest/sfh/ya.make b/library/cpp/digest/sfh/ya.make
new file mode 100644
index 0000000000..b906cd1577
--- /dev/null
+++ b/library/cpp/digest/sfh/ya.make
@@ -0,0 +1,12 @@
+LIBRARY()
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ sfh.cpp
+)
+
+END()
diff --git a/library/cpp/digest/ya.make b/library/cpp/digest/ya.make
new file mode 100644
index 0000000000..61d4b50903
--- /dev/null
+++ b/library/cpp/digest/ya.make
@@ -0,0 +1,23 @@
+RECURSE(
+ argonish
+ argonish/benchmark
+ argonish/ut_fat
+ argonish/ut
+ benchmark
+ fast
+ lower_case
+ lower_case/ut
+ md5
+ md5/ut
+ md5/medium_ut
+ md5/bench
+ murmur
+ murmur/ut
+ crc32c
+ crc32c/ut
+ old_crc
+ old_crc/ut
+ old_crc/gencrc
+ sfh
+ sfh/ut
+)
diff --git a/library/cpp/dns/README.md b/library/cpp/dns/README.md
new file mode 100644
index 0000000000..6659d73ea2
--- /dev/null
+++ b/library/cpp/dns/README.md
@@ -0,0 +1,9 @@
+Overview
+===
+Библиотека кеширующего resolving-а - изначально писалась для имплементации neh http протокола, использующей корутины.
+Для предотвращения пробоя короткого стека корутин есть метод, предусматривающий вынос в отдельный тред собственно вызов функции резолвинга.
+Для предотвращения обращения к DNS серверам (использования вместо этого заранее заданных ip-адресов),
+предусмотрена ручка добавления alias-ов hosname -> ip-address (требование от метапоискового движка).
+
+Из-за того, что библиотка разрабатывалась под задачу максимально быстрого резолвинга добавлены слои кеширования результатов
+resoving-а, - возможности сбросить кеш для того, чтобы получить более свежие адреса для указанного host-а _нет_.
diff --git a/library/cpp/dns/cache.cpp b/library/cpp/dns/cache.cpp
new file mode 100644
index 0000000000..05c14e82fc
--- /dev/null
+++ b/library/cpp/dns/cache.cpp
@@ -0,0 +1,198 @@
+#include "cache.h"
+
+#include "thread.h"
+
+#include <util/system/tls.h>
+#include <util/system/info.h>
+#include <util/system/rwlock.h>
+#include <util/thread/singleton.h>
+#include <util/generic/singleton.h>
+#include <util/generic/hash.h>
+
+using namespace NDns;
+
+namespace {
+ struct TResolveTask {
+ enum EMethod {
+ Normal,
+ Threaded
+ };
+
+ inline TResolveTask(const TResolveInfo& info, EMethod method)
+ : Info(info)
+ , Method(method)
+ {
+ }
+
+ const TResolveInfo& Info;
+ const EMethod Method;
+ };
+
+ class IDns {
+ public:
+ virtual ~IDns() = default;
+ virtual const TResolvedHost* Resolve(const TResolveTask&) = 0;
+ };
+
+ typedef TAtomicSharedPtr<TResolvedHost> TResolvedHostPtr;
+
+ struct THashResolveInfo {
+ inline size_t operator()(const TResolveInfo& ri) const {
+ return ComputeHash(ri.Host) ^ ri.Port;
+ }
+ };
+
+ struct TCompareResolveInfo {
+ inline bool operator()(const NDns::TResolveInfo& x, const NDns::TResolveInfo& y) const {
+ return x.Host == y.Host && x.Port == y.Port;
+ }
+ };
+
+ class TGlobalCachedDns: public IDns, public TNonCopyable {
+ public:
+ const TResolvedHost* Resolve(const TResolveTask& rt) override {
+ //2. search host in cache
+ {
+ TReadGuard guard(L_);
+
+ TCache::const_iterator it = C_.find(rt.Info);
+
+ if (it != C_.end()) {
+ return it->second.Get();
+ }
+ }
+
+ TResolvedHostPtr res = ResolveA(rt);
+
+ //update cache
+ {
+ TWriteGuard guard(L_);
+
+ std::pair<TCache::iterator, bool> updateResult = C_.insert(std::make_pair(TResolveInfo(res->Host, rt.Info.Port), res));
+ TResolvedHost* rh = updateResult.first->second.Get();
+
+ if (updateResult.second) {
+ //fresh resolved host, set cache record id for it
+ rh->Id = C_.size() - 1;
+ }
+
+ return rh;
+ }
+ }
+
+ void AddAlias(const TString& host, const TString& alias) noexcept {
+ TWriteGuard guard(LA_);
+
+ A_[host] = alias;
+ }
+
+ static inline TGlobalCachedDns* Instance() {
+ return SingletonWithPriority<TGlobalCachedDns, 65530>();
+ }
+
+ private:
+ inline TResolvedHostPtr ResolveA(const TResolveTask& rt) {
+ TString originalHost(rt.Info.Host);
+ TString host(originalHost);
+
+ //3. replace host to alias, if exist
+ if (A_.size()) {
+ TReadGuard guard(LA_);
+ TStringBuf names[] = {"*", host};
+
+ for (const auto& name : names) {
+ TAliases::const_iterator it = A_.find(name);
+
+ if (it != A_.end()) {
+ host = it->second;
+ }
+ }
+ }
+
+ if (host.length() > 2 && host[0] == '[') {
+ TString unbracedIpV6(host.data() + 1, host.size() - 2);
+ host.swap(unbracedIpV6);
+ }
+
+ TAutoPtr<TNetworkAddress> na;
+
+ //4. getaddrinfo (direct or in separate thread)
+ if (rt.Method == TResolveTask::Normal) {
+ na.Reset(new TNetworkAddress(host, rt.Info.Port));
+ } else if (rt.Method == TResolveTask::Threaded) {
+ na = ThreadedResolve(host, rt.Info.Port);
+ } else {
+ Y_ASSERT(0);
+ throw yexception() << TStringBuf("invalid resolve method");
+ }
+
+ return new TResolvedHost(originalHost, *na);
+ }
+
+ typedef THashMap<TResolveInfo, TResolvedHostPtr, THashResolveInfo, TCompareResolveInfo> TCache;
+ TCache C_;
+ TRWMutex L_;
+ typedef THashMap<TString, TString> TAliases;
+ TAliases A_;
+ TRWMutex LA_;
+ };
+
+ class TCachedDns: public IDns {
+ public:
+ inline TCachedDns(IDns* slave)
+ : S_(slave)
+ {
+ }
+
+ const TResolvedHost* Resolve(const TResolveTask& rt) override {
+ //1. search in local thread cache
+ {
+ TCache::const_iterator it = C_.find(rt.Info);
+
+ if (it != C_.end()) {
+ return it->second;
+ }
+ }
+
+ const TResolvedHost* res = S_->Resolve(rt);
+
+ C_[TResolveInfo(res->Host, rt.Info.Port)] = res;
+
+ return res;
+ }
+
+ private:
+ typedef THashMap<TResolveInfo, const TResolvedHost*, THashResolveInfo, TCompareResolveInfo> TCache;
+ TCache C_;
+ IDns* S_;
+ };
+
+ struct TThreadedDns: public TCachedDns {
+ inline TThreadedDns()
+ : TCachedDns(TGlobalCachedDns::Instance())
+ {
+ }
+ };
+
+ inline IDns* ThrDns() {
+ return FastTlsSingleton<TThreadedDns>();
+ }
+}
+
+namespace NDns {
+ const TResolvedHost* CachedResolve(const TResolveInfo& ri) {
+ TResolveTask rt(ri, TResolveTask::Normal);
+
+ return ThrDns()->Resolve(rt);
+ }
+
+ const TResolvedHost* CachedThrResolve(const TResolveInfo& ri) {
+ TResolveTask rt(ri, TResolveTask::Threaded);
+
+ return ThrDns()->Resolve(rt);
+ }
+
+ void AddHostAlias(const TString& host, const TString& alias) {
+ TGlobalCachedDns::Instance()->AddAlias(host, alias);
+ }
+}
diff --git a/library/cpp/dns/cache.h b/library/cpp/dns/cache.h
new file mode 100644
index 0000000000..eda5dc4070
--- /dev/null
+++ b/library/cpp/dns/cache.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <util/network/socket.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+
+namespace NDns {
+ struct TResolveInfo {
+ inline TResolveInfo(const TStringBuf& host, ui16 port)
+ : Host(host)
+ , Port(port)
+ {
+ }
+
+ TStringBuf Host;
+ ui16 Port;
+ };
+
+ struct TResolvedHost {
+ inline TResolvedHost(const TString& host, const TNetworkAddress& addr) noexcept
+ : Host(host)
+ , Addr(addr)
+ , Id(0)
+ {
+ }
+
+ TString Host; //resolved hostname (from TResolveInfo, - before aliasing)
+ TNetworkAddress Addr;
+ size_t Id; //cache record id
+ };
+
+ // Resolving order:
+ // 1. check local thread cache, return if found
+ // 2. check global cache, return if found
+ // 3. search alias for hostname, if found, continue resolving alias
+ // 4. normal resolver
+ const TResolvedHost* CachedResolve(const TResolveInfo& ri);
+
+ //like previous, but at stage 4 use separate thread for resolving (created on first usage)
+ //useful in green-threads with tiny stack
+ const TResolvedHost* CachedThrResolve(const TResolveInfo& ri);
+
+ //create alias for host, which can be used for static resolving (when alias is ip address)
+ void AddHostAlias(const TString& host, const TString& alias);
+}
diff --git a/library/cpp/dns/magic.cpp b/library/cpp/dns/magic.cpp
new file mode 100644
index 0000000000..dfcb1bf202
--- /dev/null
+++ b/library/cpp/dns/magic.cpp
@@ -0,0 +1,29 @@
+#include "magic.h"
+
+#include <util/network/socket.h>
+#include <util/generic/yexception.h>
+
+using namespace NDns;
+
+namespace {
+ namespace NX {
+ struct TError: public IError {
+ inline TError()
+ : E_(std::current_exception())
+ {
+ }
+
+ void Raise() override {
+ std::rethrow_exception(E_);
+ }
+
+ std::exception_ptr E_;
+ };
+ }
+}
+
+IErrorRef NDns::SaveError() {
+ using namespace NX;
+
+ return new NX::TError();
+}
diff --git a/library/cpp/dns/magic.h b/library/cpp/dns/magic.h
new file mode 100644
index 0000000000..d52cde0a6c
--- /dev/null
+++ b/library/cpp/dns/magic.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <util/generic/yexception.h>
+#include <util/generic/ptr.h>
+
+namespace NDns {
+ class IError {
+ public:
+ virtual ~IError() = default;
+
+ virtual void Raise() = 0;
+ };
+
+ typedef TAutoPtr<IError> IErrorRef;
+
+ IErrorRef SaveError();
+}
diff --git a/library/cpp/dns/thread.cpp b/library/cpp/dns/thread.cpp
new file mode 100644
index 0000000000..8b27d2d527
--- /dev/null
+++ b/library/cpp/dns/thread.cpp
@@ -0,0 +1,133 @@
+#include "thread.h"
+
+#include "magic.h"
+
+#include <util/network/socket.h>
+#include <util/thread/factory.h>
+#include <util/thread/lfqueue.h>
+#include <util/system/event.h>
+#include <util/generic/vector.h>
+#include <util/generic/singleton.h>
+
+using namespace NDns;
+
+namespace {
+ class TThreadedResolver: public IThreadFactory::IThreadAble, public TNonCopyable {
+ struct TResolveRequest {
+ inline TResolveRequest(const TString& host, ui16 port)
+ : Host(host)
+ , Port(port)
+ {
+ }
+
+ inline TNetworkAddressPtr Wait() {
+ E.Wait();
+
+ if (!Error) {
+ if (!Result) {
+ ythrow TNetworkResolutionError(EAI_AGAIN) << TStringBuf(": resolver down");
+ }
+
+ return Result;
+ }
+
+ Error->Raise();
+
+ ythrow TNetworkResolutionError(EAI_FAIL) << TStringBuf(": shit happen");
+ }
+
+ inline void Resolve() noexcept {
+ try {
+ Result = new TNetworkAddress(Host, Port);
+ } catch (...) {
+ Error = SaveError();
+ }
+
+ Wake();
+ }
+
+ inline void Wake() noexcept {
+ E.Signal();
+ }
+
+ TString Host;
+ ui16 Port;
+ TManualEvent E;
+ TNetworkAddressPtr Result;
+ IErrorRef Error;
+ };
+
+ public:
+ inline TThreadedResolver()
+ : E_(TSystemEvent::rAuto)
+ {
+ T_.push_back(SystemThreadFactory()->Run(this));
+ }
+
+ inline ~TThreadedResolver() override {
+ Schedule(nullptr);
+
+ for (size_t i = 0; i < T_.size(); ++i) {
+ T_[i]->Join();
+ }
+
+ {
+ TResolveRequest* rr = nullptr;
+
+ while (Q_.Dequeue(&rr)) {
+ if (rr) {
+ rr->Wake();
+ }
+ }
+ }
+ }
+
+ static inline TThreadedResolver* Instance() {
+ return Singleton<TThreadedResolver>();
+ }
+
+ inline TNetworkAddressPtr Resolve(const TString& host, ui16 port) {
+ TResolveRequest rr(host, port);
+
+ Schedule(&rr);
+
+ return rr.Wait();
+ }
+
+ private:
+ inline void Schedule(TResolveRequest* rr) {
+ Q_.Enqueue(rr);
+ E_.Signal();
+ }
+
+ void DoExecute() override {
+ while (true) {
+ TResolveRequest* rr = nullptr;
+
+ while (!Q_.Dequeue(&rr)) {
+ E_.Wait();
+ }
+
+ if (rr) {
+ rr->Resolve();
+ } else {
+ break;
+ }
+ }
+
+ Schedule(nullptr);
+ }
+
+ private:
+ TLockFreeQueue<TResolveRequest*> Q_;
+ TSystemEvent E_;
+ typedef TAutoPtr<IThreadFactory::IThread> IThreadRef;
+ TVector<IThreadRef> T_;
+ };
+}
+
+namespace NDns {
+ TNetworkAddressPtr ThreadedResolve(const TString& host, ui16 port) {
+ return TThreadedResolver::Instance()->Resolve(host, port);
+ }
+}
diff --git a/library/cpp/dns/thread.h b/library/cpp/dns/thread.h
new file mode 100644
index 0000000000..06b41d78ce
--- /dev/null
+++ b/library/cpp/dns/thread.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <util/network/socket.h>
+
+#include <util/generic/string.h>
+#include <util/generic/ptr.h>
+
+namespace NDns {
+ typedef TAutoPtr<TNetworkAddress> TNetworkAddressPtr;
+
+ TNetworkAddressPtr ThreadedResolve(const TString& host, ui16 port);
+}
diff --git a/library/cpp/dns/ut/dns_ut.cpp b/library/cpp/dns/ut/dns_ut.cpp
new file mode 100644
index 0000000000..aae05a742c
--- /dev/null
+++ b/library/cpp/dns/ut/dns_ut.cpp
@@ -0,0 +1,25 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/dns/cache.h>
+#include <util/network/address.h>
+
+Y_UNIT_TEST_SUITE(TestDNS) {
+ using namespace NDns;
+
+ Y_UNIT_TEST(TestMagic) {
+ UNIT_ASSERT_EXCEPTION(CachedThrResolve(TResolveInfo("?", 80)), yexception);
+ }
+
+ Y_UNIT_TEST(TestAsteriskAlias) {
+ AddHostAlias("*", "localhost");
+ const TResolvedHost* rh = CachedThrResolve(TResolveInfo("yandex.ru", 80));
+ UNIT_ASSERT(rh != nullptr);
+
+ const TNetworkAddress& addr = rh->Addr;
+ for (TNetworkAddress::TIterator ai = addr.Begin(); ai != addr.End(); ai++) {
+ if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
+ NAddr::TAddrInfo info(&*ai);
+ UNIT_ASSERT(IsLoopback(info));
+ }
+ }
+ }
+}
diff --git a/library/cpp/dns/ut/ya.make b/library/cpp/dns/ut/ya.make
new file mode 100644
index 0000000000..7cfd0c4c32
--- /dev/null
+++ b/library/cpp/dns/ut/ya.make
@@ -0,0 +1,16 @@
+UNITTEST()
+
+OWNER(
+ and42
+ pg
+)
+
+PEERDIR(
+ library/cpp/dns
+)
+
+SRCS(
+ dns_ut.cpp
+)
+
+END()
diff --git a/library/cpp/dns/ya.make b/library/cpp/dns/ya.make
new file mode 100644
index 0000000000..0cd83332aa
--- /dev/null
+++ b/library/cpp/dns/ya.make
@@ -0,0 +1,11 @@
+LIBRARY()
+
+OWNER(and42)
+
+SRCS(
+ cache.cpp
+ thread.cpp
+ magic.cpp
+)
+
+END()
diff --git a/library/cpp/enumbitset/README.md b/library/cpp/enumbitset/README.md
new file mode 100644
index 0000000000..25bc5b2bca
--- /dev/null
+++ b/library/cpp/enumbitset/README.md
@@ -0,0 +1,2 @@
+Здесь представлен класс [`TEnumBitSet`](https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/enumbitset/enumbitset.h) - шаблонная битовая маска для диапазона значений `enum`.
+Используется, например, в библиотеке битовых масок языков [arcadia/library/cpp/langmask](https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/langmask).
diff --git a/library/cpp/enumbitset/enumbitset.cpp b/library/cpp/enumbitset/enumbitset.cpp
new file mode 100644
index 0000000000..9dbde52cfa
--- /dev/null
+++ b/library/cpp/enumbitset/enumbitset.cpp
@@ -0,0 +1 @@
+#include "enumbitset.h"
diff --git a/library/cpp/enumbitset/enumbitset.h b/library/cpp/enumbitset/enumbitset.h
new file mode 100644
index 0000000000..41864c3a04
--- /dev/null
+++ b/library/cpp/enumbitset/enumbitset.h
@@ -0,0 +1,515 @@
+#pragma once
+
+#include <util/ysaveload.h>
+#include <util/generic/bitmap.h>
+#include <util/generic/serialized_enum.h>
+#include <util/generic/yexception.h>
+#include <util/string/cast.h>
+#include <util/string/printf.h>
+#include <util/system/yassert.h>
+
+// Stack memory bitmask for TEnum values [begin, end).
+// @end value is not included in the mask and is not necessarily defined as enum value.
+// For example: enum EType { A, B, C } ==> TEnumBitSet<EType, A, C + 1>
+template <typename TEnum, int mbegin, int mend>
+class TEnumBitSet: private TBitMap<mend - mbegin> {
+public:
+ static const int BeginIndex = mbegin;
+ static const int EndIndex = mend;
+ static const size_t BitsetSize = EndIndex - BeginIndex;
+
+ typedef TBitMap<BitsetSize> TParent;
+ typedef TEnumBitSet<TEnum, mbegin, mend> TThis;
+
+ TEnumBitSet()
+ : TParent(0)
+ {
+ }
+
+ explicit TEnumBitSet(const TParent& p)
+ : TParent(p)
+ {
+ }
+
+ void Init(TEnum c) {
+ Set(c);
+ }
+
+ template <class... R>
+ void Init(TEnum c1, TEnum c2, R... r) {
+ Set(c1);
+ Init(c2, r...);
+ }
+
+ explicit TEnumBitSet(TEnum c) {
+ Init(c);
+ }
+
+ template <class... R>
+ TEnumBitSet(TEnum c1, TEnum c2, R... r) {
+ Init(c1, c2, r...);
+ }
+
+ template <class TIt>
+ TEnumBitSet(const TIt& begin_, const TIt& end_) {
+ for (TIt p = begin_; p != end_; ++p)
+ Set(*p);
+ }
+
+ static bool IsValid(TEnum c) {
+ return int(c) >= BeginIndex && int(c) < EndIndex;
+ }
+
+ bool Test(TEnum c) const {
+ return TParent::Test(Pos(c));
+ }
+
+ TThis& Flip(TEnum c) {
+ TParent::Flip(Pos(c));
+ return *this;
+ }
+
+ TThis& Flip() {
+ TParent::Flip();
+ return *this;
+ }
+
+ TThis& Reset(TEnum c) {
+ TParent::Reset(Pos(c));
+ return *this;
+ }
+
+ TThis& Reset() {
+ TParent::Clear();
+ return *this;
+ }
+
+ TThis& Set(TEnum c) {
+ TParent::Set(Pos(c));
+ return *this;
+ }
+
+ TThis& Set(TEnum c, bool val) {
+ if (val)
+ Set(c);
+ else
+ Reset(c);
+ return *this;
+ }
+
+ bool SafeTest(TEnum c) const {
+ if (IsValid(c))
+ return Test(c);
+ return false;
+ }
+
+ TThis& SafeFlip(TEnum c) {
+ if (IsValid(c))
+ return Flip(c);
+ return *this;
+ }
+
+ TThis& SafeReset(TEnum c) {
+ if (IsValid(c))
+ return Reset(c);
+ return *this;
+ }
+
+ TThis& SafeSet(TEnum c) {
+ if (IsValid(c))
+ return Set(c);
+ return *this;
+ }
+
+ TThis& SafeSet(TEnum c, bool val) {
+ if (IsValid(c))
+ return Set(c, val);
+ return *this;
+ }
+
+ static TThis SafeConstruct(TEnum c) {
+ TThis ret;
+ ret.SafeSet(c);
+ return ret;
+ }
+
+ bool operator<(const TThis& right) const {
+ Y_ASSERT(this->GetChunkCount() == right.GetChunkCount());
+ for (size_t i = 0; i < this->GetChunkCount(); ++i) {
+ if (this->GetChunks()[i] < right.GetChunks()[i])
+ return true;
+ else if (this->GetChunks()[i] > right.GetChunks()[i])
+ return false;
+ }
+ return false;
+ }
+
+ bool operator!=(const TThis& right) const {
+ return !(TParent::operator==(right));
+ }
+
+ bool operator==(const TThis& right) const {
+ return TParent::operator==(right);
+ }
+
+ TThis& operator&=(const TThis& right) {
+ TParent::operator&=(right);
+ return *this;
+ }
+
+ TThis& operator|=(const TThis& right) {
+ TParent::operator|=(right);
+ return *this;
+ }
+
+ TThis& operator^=(const TThis& right) {
+ TParent::operator^=(right);
+ return *this;
+ }
+
+ TThis operator~() const {
+ TThis r = *this;
+ r.Flip();
+ return r;
+ }
+
+ TThis operator|(const TThis& right) const {
+ TThis ret = *this;
+ ret |= right;
+ return ret;
+ }
+
+ TThis operator&(const TThis& right) const {
+ TThis ret = *this;
+ ret &= right;
+ return ret;
+ }
+
+ TThis operator^(const TThis& right) const {
+ TThis ret = *this;
+ ret ^= right;
+ return ret;
+ }
+
+
+ TThis& operator&=(const TEnum c) {
+ return TThis::operator&=(TThis(c));
+ }
+
+ TThis& operator|=(const TEnum c) {
+ return TThis::operator|=(TThis(c));
+ }
+
+ TThis& operator^=(const TEnum c) {
+ return TThis::operator^=(TThis(c));
+ }
+
+ TThis operator&(const TEnum c) const {
+ return TThis::operator&(TThis(c));
+ }
+
+ TThis operator|(const TEnum c) const {
+ return TThis::operator|(TThis(c));
+ }
+
+ TThis operator^(const TEnum c) const {
+ return TThis::operator^(TThis(c));
+ }
+
+ auto operator[] (TEnum e) {
+ return TParent::operator[](this->Pos(e));
+ }
+
+ auto operator[] (TEnum e) const {
+ return TParent::operator[](this->Pos(e));
+ }
+
+ using TParent::Count;
+ using TParent::Empty;
+
+ explicit operator bool() const {
+ return !Empty();
+ }
+
+ void Swap(TThis& bitmap) {
+ TParent::Swap(bitmap);
+ }
+
+ size_t GetHash() const {
+ return this->Hash();
+ }
+
+ bool HasAny(const TThis& mask) const {
+ return TParent::HasAny(mask);
+ }
+
+ template <class... R>
+ bool HasAny(TEnum c1, R... r) const {
+ return Test(c1) || HasAny(r...);
+ }
+
+ bool HasAll(const TThis& mask) const {
+ return TParent::HasAll(mask);
+ }
+
+ template <class... R>
+ bool HasAll(TEnum c1, R... r) const {
+ return Test(c1) && HasAll(r...);
+ }
+
+ //serialization to/from stream
+ void Save(IOutputStream* buffer) const {
+ ::Save(buffer, (ui32)Count());
+ for (TEnum bit : *this) {
+ ::Save(buffer, (ui32)bit);
+ }
+ }
+
+ void Load(IInputStream* buffer) {
+ Reset();
+
+ ui32 sz = 0;
+ ::Load(buffer, sz);
+
+ for (ui32 t = 0; t < sz; t++) {
+ ui32 bit = 0;
+ ::Load(buffer, bit);
+
+ Set((TEnum)bit);
+ }
+ }
+
+ ui64 Low() const {
+ ui64 t = 0;
+ this->Export(0, t);
+ return t;
+ }
+
+ TString ToString() const {
+ static_assert(sizeof(typename TParent::TChunk) <= sizeof(ui64), "expect sizeof(typename TParent::TChunk) <= sizeof(ui64)");
+ static const size_t chunkSize = sizeof(typename TParent::TChunk) * 8;
+ static const size_t numDig = chunkSize / 4;
+ static const TString templ = Sprintf("%%0%lulX", numDig);
+ static const size_t numOfChunks = (BitsetSize + chunkSize - 1) / chunkSize;
+ TString ret;
+ for (int pos = numOfChunks * chunkSize; pos >= 0; pos -= chunkSize) {
+ ui64 t = 0;
+ this->Export(pos, t);
+ ret += Sprintf(templ.data(), t);
+ }
+
+ size_t n = 0;
+ while (n + 1 < ret.length() && ret[n] == '0')
+ ++n;
+ ret.remove(0, n);
+ return ret;
+ }
+
+ void FromString(TStringBuf s) {
+ static const size_t chunkSize = sizeof(typename TParent::TChunk) * 8;
+ static const size_t numDig = chunkSize / 4;
+ static const size_t highChunkBits = (BitsetSize + chunkSize - 1) % chunkSize + 1;
+ static const typename TParent::TChunk highChunkBitsMask = (typename TParent::TChunk(1) << highChunkBits) - 1;
+
+ Reset();
+ for (size_t prev = s.length(), n = s.length() - numDig, pos = 0; prev; n -= numDig, pos += chunkSize) {
+ if (pos >= BitsetSize)
+ ythrow yexception() << "too many digits";
+ if (n > prev)
+ n = 0;
+ typename TParent::TChunk t = IntFromString<typename TParent::TChunk, 16, TStringBuf>(s.substr(n, prev - n));
+ if (BitsetSize < pos + chunkSize && t > highChunkBitsMask)
+ ythrow yexception() << "digit is too big";
+ this->Or(TParent(t), pos);
+ prev = n;
+ }
+ }
+
+ // TODO: Get rid of exceptions at all
+ bool TryFromString(TStringBuf s) {
+ try {
+ FromString(s);
+ } catch (...) {
+ Reset();
+ return false;
+ }
+ return true;
+ }
+
+ bool any() const { // obsolete
+ return !Empty();
+ }
+
+ bool none() const { // obsolete
+ return Empty();
+ }
+
+ size_t count() const { // obsolete
+ return Count();
+ }
+
+ class TIterator {
+ public:
+ TIterator(TEnum value, const TThis* bitmap) noexcept
+ : Value(static_cast<int>(value))
+ , BitMap(bitmap)
+ {
+ }
+
+ TIterator(const TThis* bitmap) noexcept
+ : Value(EndIndex)
+ , BitMap(bitmap)
+ {
+ }
+
+ TEnum operator*() const noexcept {
+ Y_ASSERT(Value < EndIndex);
+ return static_cast<TEnum>(Value);
+ }
+
+ bool operator!=(const TIterator& other) const noexcept {
+ return Value != other.Value;
+ }
+
+ TIterator& operator++() noexcept {
+ Y_ASSERT(Value < EndIndex);
+ TEnum res;
+ if (BitMap->FindNext(static_cast<TEnum>(Value), res)) {
+ Value = static_cast<int>(res);
+ } else {
+ Value = EndIndex;
+ }
+
+ return *this;
+ }
+
+ private:
+ int Value;
+ const TThis* BitMap;
+ };
+
+ TIterator begin() const {
+ TEnum res;
+ return FindFirst(res) ? TIterator(res, this) : TIterator(this);
+ }
+
+ TIterator end() const {
+ return TIterator(this);
+ }
+
+private:
+ static size_t Pos(TEnum c) {
+ Y_ASSERT(IsValid(c));
+ return static_cast<size_t>(int(c) - BeginIndex);
+ }
+
+ bool HasAny(TEnum c) const {
+ return Test(c);
+ }
+
+ bool HasAll(TEnum c) const {
+ return Test(c);
+ }
+
+ bool FindFirst(TEnum& result) const {
+ // finds first set item in bitset (or End if bitset is empty)
+ const int index = int(this->FirstNonZeroBit()) + BeginIndex;
+ if (index < EndIndex) {
+ result = static_cast<TEnum>(index);
+ return true;
+ }
+ return false;
+ }
+
+ bool FindNext(TEnum current, TEnum& result) const {
+ // finds first set item in bitset (or End if bitset is empty)
+ const int index = int(this->NextNonZeroBit(int(current) - BeginIndex)) + BeginIndex;
+ if (index < EndIndex) {
+ result = static_cast<TEnum>(index);
+ return true;
+ }
+ return false;
+ }
+};
+
+template <typename TEnum, TEnum mbegin, int mend>
+class TSfEnumBitSet: public TEnumBitSet<TEnum, mbegin, mend> {
+public:
+ typedef TEnumBitSet<TEnum, mbegin, mend> TParent;
+
+ TSfEnumBitSet()
+ : TParent()
+ {
+ }
+
+ TSfEnumBitSet(const TParent& p)
+ : TParent(p)
+ {
+ }
+
+ //! unsafe initialization from ui64, value must be shifted according to TParent::Begin
+ explicit TSfEnumBitSet(ui64 val)
+ : TParent(typename TParent::TParent(val))
+ {
+ //static_assert(TParent::BitsetSize <= 64, "expect TParent::BitsetSize <= 64");
+ }
+
+ void Init(TEnum c) {
+ this->SafeSet(c);
+ }
+
+ template <class... R>
+ void Init(TEnum c1, TEnum c2, R... r) {
+ this->SafeSet(c1);
+ Init(c2, r...);
+ }
+
+ TSfEnumBitSet(TEnum c) {
+ Init(c);
+ }
+
+ template <class... R>
+ TSfEnumBitSet(TEnum c1, TEnum c2, R... r) {
+ Init(c1, c2, r...);
+ }
+
+ static TSfEnumBitSet GetFromString(const TString& s) {
+ TSfEnumBitSet ebs;
+ ebs.FromString(s);
+ return ebs;
+ }
+
+ static TSfEnumBitSet TryGetFromString(const TString& s) {
+ TSfEnumBitSet ebs;
+ ebs.TryFromString(s);
+ return ebs;
+ }
+};
+
+/* For Enums with GENERATE_ENUM_SERIALIZATION_WITH_HEADER */
+template <typename TEnum>
+class TGeneratedEnumBitSet : public TEnumBitSet<TEnum, 0, GetEnumItemsCount<TEnum>()> {
+public:
+ using TParent = TEnumBitSet<TEnum, 0, GetEnumItemsCount<TEnum>()>;
+
+ TGeneratedEnumBitSet()
+ : TParent()
+ {
+ }
+
+ explicit TGeneratedEnumBitSet(const TParent& p)
+ : TParent(p)
+ {
+ }
+
+ explicit TGeneratedEnumBitSet(TEnum c1)
+ : TParent(c1)
+ {
+ }
+
+ template <class... R>
+ TGeneratedEnumBitSet(TEnum c1, TEnum c2, R... r)
+ : TParent(c1, c2, r...)
+ {
+ }
+};
diff --git a/library/cpp/enumbitset/enumbitset_ut.cpp b/library/cpp/enumbitset/enumbitset_ut.cpp
new file mode 100644
index 0000000000..e55b3251c3
--- /dev/null
+++ b/library/cpp/enumbitset/enumbitset_ut.cpp
@@ -0,0 +1,83 @@
+#include "enumbitset.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/str.h>
+#include <util/stream/file.h>
+
+enum ETestEnum {
+ TE_FIRST = 0,
+ TE_1,
+ TE_2,
+ TE_3,
+ TE_4,
+ TE_MIDDLE = TE_4 + 64,
+ TE_5,
+ TE_6,
+ TE_7,
+ TE_MAX,
+
+ TE_OVERFLOW, // to test overflow
+};
+using TTestBitSet = TEnumBitSet<ETestEnum, TE_FIRST, TE_MAX>;
+
+Y_UNIT_TEST_SUITE(TEnumBitSetTest) {
+ Y_UNIT_TEST(TestMainFunctions) {
+ auto ebs = TTestBitSet(TE_FIRST, TE_MIDDLE);
+
+ UNIT_ASSERT(ebs.SafeTest(TE_FIRST));
+ UNIT_ASSERT(ebs.SafeTest(TE_MIDDLE));
+
+ ebs.SafeSet(TE_5);
+ UNIT_ASSERT(ebs.SafeTest(TE_5));
+ UNIT_ASSERT(!ebs.SafeTest(TE_7));
+
+ ebs.SafeSet(TE_OVERFLOW);
+ UNIT_ASSERT(!ebs.SafeTest(TE_OVERFLOW));
+ }
+
+ Y_UNIT_TEST(TestEmpty) {
+ TTestBitSet mask;
+ UNIT_ASSERT(mask.Empty());
+ if (mask)
+ UNIT_ASSERT(false && "should be empty");
+
+ mask.Set(TE_FIRST);
+ UNIT_ASSERT(!mask.Empty());
+ UNIT_ASSERT(mask.Count() == 1);
+ if (!mask)
+ UNIT_ASSERT(false && "should not be empty");
+ }
+
+ Y_UNIT_TEST(TestIter) {
+ TTestBitSet mask = TTestBitSet(TE_1, TE_3, TE_7);
+
+ TTestBitSet mask2;
+ for (auto elem : mask) {
+ mask2.Set(elem);
+ }
+
+ UNIT_ASSERT(mask == mask2);
+ }
+
+ Y_UNIT_TEST(TestSerialization) {
+ auto ebs = TTestBitSet(TE_MIDDLE, TE_6, TE_7);
+
+ TStringStream ss;
+ ebs.Save(&ss);
+
+ auto ebs2 = TTestBitSet();
+ ebs2.Load(&ss);
+ UNIT_ASSERT_EQUAL(ebs, ebs2);
+ }
+
+ Y_UNIT_TEST(TestStringRepresentation) {
+ auto ebs = TTestBitSet(TE_MIDDLE, TE_6, TE_7);
+
+ UNIT_ASSERT_EQUAL(ebs.ToString(), "D00000000000000000");
+
+ auto ebs2 = TTestBitSet();
+ ebs2.FromString("D00000000000000000");
+ UNIT_ASSERT_EQUAL(ebs, ebs2);
+ }
+}
diff --git a/library/cpp/enumbitset/ut/ya.make b/library/cpp/enumbitset/ut/ya.make
new file mode 100644
index 0000000000..c893e6eb13
--- /dev/null
+++ b/library/cpp/enumbitset/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/enumbitset)
+
+OWNER(alzobnin)
+
+SRCS(
+ enumbitset_ut.cpp
+)
+
+END()
diff --git a/library/cpp/enumbitset/ya.make b/library/cpp/enumbitset/ya.make
new file mode 100644
index 0000000000..86de91c816
--- /dev/null
+++ b/library/cpp/enumbitset/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(alzobnin)
+
+SRCS(
+ enumbitset.cpp
+)
+
+END()
diff --git a/library/cpp/execprofile/annotate_profile.pl b/library/cpp/execprofile/annotate_profile.pl
new file mode 100644
index 0000000000..1a8c5d65a1
--- /dev/null
+++ b/library/cpp/execprofile/annotate_profile.pl
@@ -0,0 +1,360 @@
+#!/usr/bin/env perl
+
+#
+# Takes profile file as an input and prints out annotated disassmebly
+# Usage:
+# ./annotate_profile.pl <binary_name> <profile_name>
+#
+
+
+# Function to draw bar of the specified length filled up to specified length
+sub DRAW_BAR($$) {
+ my ($length, $filled) = @_;
+ my $bar = "";
+ --$filled;
+ while ($filled > 0) {
+ $bar = $bar . "X";
+ $length--;
+ $filled--;
+ }
+ while ($length > 0) {
+ $bar = $bar . " ";
+ $length--;
+ }
+ return $bar;
+}
+
+my $curFunc = "";
+my $curModule = "";
+my $allHits = 0;
+my %moduleHits;
+my %funcModule;
+my %funcHits;
+my %funcHottestCount;
+my %funcStart;
+my %funcEnd;
+my %funcNames;
+my %funcBaseAddrs;
+my %funcSizes;
+my %addrHits;
+my %addrFunc;
+my %moduleBaseAddr;
+my @funcSortByAddr;
+my %demangledNames;
+my %srcLineHits;
+my %srcFileHits;
+
+# Demagles C++ function name
+sub DEMANGLE($) {
+ my ($name) = @_;
+ if (exists $demangledNames{$name}) {
+ return $demangledNames{$name};
+ }
+ if ($name =~ /^_Z/) {
+ my $cmd = "c++filt -p \'$name\' |";
+ open(my $RES, $cmd ) || die "No c++filt";
+ my $demangled_name = <$RES>;
+ chomp($demangled_name);
+ close $RES;
+ if (length($demangled_name) !=0) {
+ $name = $demangled_name;
+ }
+ }
+ return $name;
+}
+
+# Saves function info
+sub AddFunc($$$$$)
+{
+ my ($func, $bin_file, $baseAddr, $size, $name) = @_;
+ $funcModule{$func} = $bin_file;
+ $funcBaseAddrs{$func} = $baseAddr;
+ # A function with the same base address can be mentioned multiple times with different sizes (0, and non-0, WTF??)
+ if ((! exists $funcSizes{$func}) || ($funcSizes{$func} < $size)) {
+ $funcSizes{$func} = $size;
+ }
+ $funcNames{$func} = $name;
+ $funcStart{$func} = $func;
+# printf "%08x\t%08x\t%016x\t%s\t%s\n",
+# $funcBaseAddrs{$func}, $funcSizes{$func}, $moduleBaseAddr, $funcModule{$func}, $funcNames{$func};
+}
+
+# Reads list of all functions in a module
+sub ReadFunctionList($$) {
+ my ($bin_file, $moduleBaseAddr) = @_;
+ if (! -e $bin_file) {
+ return;
+ }
+ my $readelf_cmd = "readelf -W -s $bin_file |";
+# print "$readelf_cmd\n";
+ my $IN_FILE;
+ open($IN_FILE, $readelf_cmd) || die "couldn't open the file!";
+ while (my $line = <$IN_FILE>) {
+ chomp($line);
+ # " 33: 00000000000a0fc0 433 FUNC GLOBAL DEFAULT 10 getipnodebyaddr@@FBSD_1.0"
+ if ($line =~ m/^\s*\d+:\s+([0-9a-fA-F]+)\s+(\d+)\s+FUNC\s+\w+\s+DEFAULT\s+\d+\s+(.*)$/) {
+ # Read function info
+ my $name = $3;
+ my $baseAddr = hex($1) + $moduleBaseAddr;
+ my $func = $baseAddr;
+ my $size = $2;
+ AddFunc($func, $bin_file, $baseAddr, $size, $name);
+ }
+ }
+ close($IN_FILE);
+ @funcSortByAddr = sort {$funcBaseAddrs{$a} <=> $funcBaseAddrs{$b} } keys %funcBaseAddrs;
+# printf "%016x\t%s\t%d\n", $moduleBaseAddr, $bin_file, $#funcSortByAddr+1;
+}
+
+# Reads the profile and attributes address hits to the functions
+sub ReadSamples() {
+ # First pass saves all samples in a hash-table
+ my $samples_file = $ARGV[1];
+ my $IN_FILE;
+ open($IN_FILE, $samples_file)|| die "couldn't open the file!";
+ my $curFuncInd = 0;
+ my $curFunc = 0;
+ my $curFuncBegin = 0;
+ my $curFuncEnd = 0;
+ my $curModule = "";
+ my $curModuleBase = 0;
+ my $read_samples = 0;
+ my $samplesStarted = 0;
+ while (my $line = <$IN_FILE>) {
+ chomp($line);
+
+ if ($line =~ m/^samples:\s+(\d+)\s+unique:\s+(\d+)\s+dropped:\s+(\d+)\s+searchskips:\s+(\d+)$/) {
+ $total_samples = $1;
+ $unique_samples = $2;
+ $dropped_samples = $3;
+ $search_skips = $4;
+ next;
+ }
+
+ if ($line =~ m/^Samples:$/) {
+ $samplesStarted = 1;
+ next;
+ } elsif (!$samplesStarted) {
+ print "$line\n";
+ next;
+ }
+
+# print "$line\n";
+ if ($line =~ m/^Func\t\d+/) {
+ # "Func 2073 0x803323000 0x803332fd0 /lib/libthr.so.3 pthread_cond_init"
+ my @cols = split(/\t/, $line);
+ $curModule = $cols[4];
+ $curModuleBase = hex($cols[2]);
+ if (0x400000 == $curModuleBase) {
+ $curModuleBase = 0;
+ }
+ $curFunc = hex($cols[3]);
+ if (! exists $moduleBaseAddr{$curModule}) {
+ $moduleBaseAddr{$curModule} = $curModuleBase;
+ ReadFunctionList($curModule, $curModuleBase);
+ }
+ if (! exists $funcNames{$curFunc}) {
+ my $name = sprintf("unknown_0x%08x", $curFunc);
+ AddFunc($curFunc, $curModule, $curFunc, 0, $name);
+ }
+ } elsif ($line =~ m/^\d+\t0x([0-9,a-f,A-F]+)\t(\d+)/) {
+ # Read one sample for the current function
+ $read_samples++;
+ my $addr = hex($1);
+# print "$addr\n";
+ if ($addr >= $curFuncEnd) {
+ # Find the function the current address belongs to
+ while ($curFuncInd <= $#funcSortByAddr) {
+ my $f = $funcSortByAddr[$curFuncInd];
+ my $begin = $funcBaseAddrs{$f};
+ my $end = $funcBaseAddrs{$f} + $funcSizes{$f};
+ if ($begin <= $addr and $addr < $end) {
+ $curFunc = $f;
+ $funcStart{$curFunc} = $addr;
+ $curFuncBegin = $begin;
+ $curFuncEnd = $end;
+ last;
+ } elsif ($addr < $begin) {
+# printf "X3: func:%08x\tname:%s\tbase:%08x\tsize:%08x\t%s\nline:%s\n",
+# $curFunc, $funcNames{$curFunc}, $funcBaseAddrs{$curFunc}, $funcSizes{$curFunc}, $curModule, $line;
+ last;
+ }
+ ++$curFuncInd;
+ }
+ }
+
+ $funcHits{$curFunc} += $2;
+ if ($funcHottestCount{$curFunc} < $2) {
+ $funcHottestCount{$curFunc} = $2;
+ }
+ $addrHits{$addr} = $2;
+ $addrFunc{$addr} = $curFunc;
+ $funcEnd{$curFunc} = $addr;
+ $allHits += $2;
+ $moduleHits{$curModule} += $2;
+
+# printf "%08x\t%08x\t%08x\t%08x\t%s\n", $addr, $curFunc, $curFuncBegin, $curFuncEnd, $funcNames{$curFunc};
+ }
+ }
+ close($IN_FILE);
+
+ printf "\nsamples: %d unique: %d dropped: %d searchskips: %d\n", $total_samples, $unique_samples, $dropped_samples, $search_skips;
+ if ($read_samples != $unique_samples) {
+ printf "\n-----------------------------------------------------------------------------------------------------\n";
+ printf "!!!!WARNING: read %d samples, expected %d samples, profiling results might be not acqurate!!!!", $read_samples, $unique_samples;
+ printf "\n-----------------------------------------------------------------------------------------------------\n";
+ }
+}
+
+# Dumps module stats
+sub DumpModules() {
+ # Sort functions by hit counts and dump the list
+ my @modules = sort {$a <=> $b } keys %moduleHits;
+ for (my $i = 0; $i <= $#modules; ++$i) {
+ my $m = $modules[$i];
+ my $cnt = $moduleHits{$m};
+ my $perc = 100.0 * $cnt / $allHits;
+ printf "%12d\t%6.2f%% |%s %s\n", $cnt, $perc, DRAW_BAR(20, 20*$cnt/$allHits), $m;
+ }
+}
+
+# Dumps top N hot functions
+sub DumpHotFunc($) {
+ my ($maxCnt) = @_;
+ # Sort functions by hit counts and dump the list
+ my @hotFunc = sort {$funcHits{$b} <=> $funcHits{$a} } keys %funcHits;
+# print $#hotFunc;
+ for (my $i = 0; $i <= $#hotFunc && $i < $maxCnt; ++$i) {
+ my $f = $hotFunc[$i];
+ my $cnt = $funcHits{$f};
+ my $perc = 100.0 * $cnt / $allHits;
+ printf "%12d\t%6.2f%% |%s %s\n", $cnt, $perc, DRAW_BAR(20, 20*$cnt/$allHits), DEMANGLE($funcNames{$f});
+ }
+}
+
+# Dumps top N hotspots (hot addresses)
+sub DumpHotSpots($) {
+ my ($maxCnt) = @_;
+ # Sort addresses by hit counts and dump the list
+ my @hotSpots = sort {$addrHits{$b} <=> $addrHits{$a} } keys %addrHits;
+ for (my $i = 0; $i <= $#hotSpots && $i < $maxCnt; ++$i) {
+ my $s = $hotSpots[$i];
+ my $cnt = $addrHits{$s};
+ my $perc = 100.0 * $cnt / $allHits;
+ my $f = $addrFunc{$s};
+ my $fname = $funcNames{$f};
+ printf "%12d\t%6.2f%% |%s 0x%016x\t%s + 0x%x\n",
+ $cnt, $perc, DRAW_BAR(20, 20*$cnt/$allHits), $s, DEMANGLE($fname), $s - $funcBaseAddrs{$f};
+ }
+}
+
+# Adds hit informations to a disassembly line
+sub ANNOTATE_DISASSM($$$$) {
+ my ($address, $disassm, $max_hit_count, $func_hit_count) = @_;
+ my $hit_count = $addrHits{$address};
+ my $perc = sprintf("% 7.2f%%", 100*$hit_count/$func_hit_count);
+ $address = sprintf("% 8x", $address);
+ print $address . " " . $hit_count . "\t" . $perc . " |" .
+ DRAW_BAR(20, 20*$hit_count/$max_hit_count) . "\t" . $disassm . "\n";
+}
+
+# Dumps annotated disassembly of the specified function (actually not the whole function but
+# just the addresses between the first and last hit)
+sub DumpDisasm($) {
+ my ($name) = @_;
+ if (exists $funcStart{$name} && exists $funcEnd{$name} && $funcStart{$name}!=0) {
+ my $module = $funcModule{$name};
+ my $modBase = $moduleBaseAddr{$module};
+ my $start_address = $funcStart{$name} - $modBase;
+ my $stop_address = $funcEnd{$name} - $modBase + 1;
+# print " " . $funcStart{$name} . " " . $funcEnd{$name} . " $modBase ---";
+ my $max_hit_count = $funcHits{$name};
+ my $objdump_cmd = "objdump -C -d -l --start-address=" . $start_address .
+ " --stop-address=" . $stop_address . " " . $module . " |";
+ if ($stop_address - $start_address < 10000000) { # don't try to disaassemble more than 10MB, because most likely it's a bug
+# print STDERR $objdump_cmd . "\n";
+ open(my $OBJDUMP, $objdump_cmd) || die "No objdump";
+ my $srcLine = "func# ". $name;
+ my $srcFile = $module;
+ while (my $objdump_line = <$OBJDUMP>) {
+ # filter disassembly lines
+ if ($objdump_line =~ /^Disassembly of section/) {
+ } elsif ($objdump_line =~ m/^\s*([0-9,a-f,A-F]+):\s*(.*)/) {
+ my $addr = hex($1);
+ my $hit_count = $addrHits{$addr};
+ if ($hit_count > 0) {
+ $srcLineHits{$srcLine} += $hit_count;
+ $srcFileHits{$srcFile} += $hit_count;
+ }
+ ANNOTATE_DISASSM($addr + $modBase, $2, $funcHottestCount{$name}, $max_hit_count);
+ } elsif ($objdump_line =~ m/^(\/.*):(\d+)$/) {
+ $srcLine = $objdump_line;
+ $srcFile = $1;
+ chomp($srcLine);
+ print $objdump_line;
+ } else {
+ print $objdump_line;
+ }
+ }
+ close $OBJDUMP;
+ }
+ }
+}
+
+# Dumps disassemlby for top N hot functions
+sub DumpFuncDissasm($) {
+ (my $maxCnt) = @_;
+ my @funcs = sort {$funcHits{$b} <=> $funcHits{$a} } keys %funcHits;
+ print $#funcs . "\n";
+ for (my $i = 0; $i <= $#funcs && $i < $maxCnt; ++$i) {
+ my $f = $funcs[$i];
+ print "\n--------------------------------------------------------------------------------------------------------------\n";
+ printf "hits:%d\t%7.2f%%\tbase:%08x\tstart:%08x\tend:%08x\t%s\n",
+ $funcHits{$f}, 100*$funcHits{$f}/$allHits, $funcBaseAddrs{$f}, $funcStart{$f}, $funcEnd{$f}, DEMANGLE($funcNames{$f});
+ print "--------------------------------------------------------------------------------------------------------------\n";
+ DumpDisasm($f);
+ }
+}
+
+sub DumpSrcFiles($) {
+ (my $maxCnt) = @_;
+ my @srcFiles = sort {$srcFileHits{$b} <=> $srcFileHits{$a} } keys %srcFileHits;
+ for (my $i = 0; $i <= $#srcFiles && $i < $maxCnt; ++$i) {
+ my $f = $srcFiles[$i];
+ my $cnt = $srcFileHits{$f};
+ printf "%12d\t%6.2f%% |%s %s\n", $cnt, 100*$cnt/$allHits, DRAW_BAR(20, 20*$cnt/$allHits), $f;
+ }
+}
+
+sub DumpSrcLines($) {
+ (my $maxCnt) = @_;
+ my @srcLines = sort {$srcLineHits{$b} <=> $srcLineHits{$a} } keys %srcLineHits;
+ for (my $i = 0; $i <= $#srcLines && $i < $maxCnt; ++$i) {
+ my $l = $srcLines[$i];
+ my $cnt = $srcLineHits{$l};
+ printf "%12d\t%6.2f%% |%s %s\n", $cnt, 100*$cnt/$allHits, DRAW_BAR(20, 20*$cnt/$allHits), $l;
+ }
+}
+
+ReadFunctionList($ARGV[0], 0);
+ReadSamples();
+print "\nModules:\n";
+DumpModules();
+print "\nHot functions:\n";
+DumpHotFunc(100);
+print "\nHotspots:\n";
+DumpHotSpots(100);
+DumpFuncDissasm(100);
+print "\nHot src files:\n";
+DumpSrcFiles(100);
+print "\nHot src lines:\n";
+DumpSrcLines(100);
+
+# my @funcs = sort {$funcBaseAddrs{$a} <=> $funcBaseAddrs{$b} } keys %funcHits;
+# printf "%d\n", $#funcs;
+# for (my $i = 0; $i <= $#funcs; ++$i) {
+# my $f = $funcs[$i];
+# printf "%s\t%d\tbase:%08x\tstart:%08x\tend:%08x\t%s\n",
+# $funcNames{$f}, $funcHits{$f}, $funcBaseAddrs{$f}, $funcStart{$f}, $funcEnd{$f}, $funcModule{$f};
+# #DumpDisasm($f);
+# }
diff --git a/library/cpp/execprofile/autostart/start.cpp b/library/cpp/execprofile/autostart/start.cpp
new file mode 100644
index 0000000000..4fffb03ae1
--- /dev/null
+++ b/library/cpp/execprofile/autostart/start.cpp
@@ -0,0 +1,15 @@
+#include <library/cpp/execprofile/profile.h>
+
+namespace {
+ struct TInit {
+ inline TInit() {
+ BeginProfiling();
+ }
+
+ inline ~TInit() {
+ EndProfiling();
+ }
+ };
+
+ const TInit initer;
+}
diff --git a/library/cpp/execprofile/autostart/ya.make b/library/cpp/execprofile/autostart/ya.make
new file mode 100644
index 0000000000..a5b61f075f
--- /dev/null
+++ b/library/cpp/execprofile/autostart/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ library/cpp/execprofile
+)
+
+SRCS(
+ GLOBAL start.cpp
+)
+
+END()
diff --git a/library/cpp/execprofile/profile.cpp b/library/cpp/execprofile/profile.cpp
new file mode 100644
index 0000000000..d05de20203
--- /dev/null
+++ b/library/cpp/execprofile/profile.cpp
@@ -0,0 +1,417 @@
+#include <util/system/defaults.h>
+
+#include "profile.h"
+
+#if defined(_unix_) && !defined(_bionic_) && !defined(_cygwin_)
+
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#if defined(_darwin_)
+#include <sys/ucontext.h>
+#else
+#include <ucontext.h>
+#endif
+#include <dlfcn.h>
+
+#include <util/system/platform.h>
+#include <util/generic/hash.h>
+#include <util/generic/map.h>
+#include <util/generic/noncopyable.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/vector.h>
+#include <util/stream/file.h>
+#include <util/string/util.h>
+#include <util/system/datetime.h>
+
+// This class sets SIGPROF handler and captures instruction pointer in it.
+class TExecutionSampler : TNonCopyable {
+public:
+ typedef TVector<std::pair<void*, size_t>> TSampleVector;
+
+ struct TStats {
+ ui64 SavedSamples;
+ ui64 DroppedSamples;
+ ui64 SearchSkipCount;
+ };
+
+ // NOTE: There is no synchronization here as the instance is supposed to be
+ // created on the main thread.
+ static TExecutionSampler* Instance() {
+ if (SInstance == nullptr) {
+ SInstance = new TExecutionSampler();
+ }
+
+ return SInstance;
+ }
+
+ void Start() {
+ // Set signal handler
+ struct sigaction sa;
+ sa.sa_sigaction = ProfilerSignalHandler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_SIGINFO;
+ if (sigaction(SIGPROF, &sa, &OldSignalHandler) != 0)
+ return;
+
+ // Set interval timer
+ itimerval tv;
+ tv.it_interval.tv_sec = tv.it_value.tv_sec = 0;
+ tv.it_interval.tv_usec = tv.it_value.tv_usec = SAMPLE_INTERVAL;
+ setitimer(ITIMER_PROF, &tv, &OldTimerValue);
+
+ Started = true;
+ }
+
+ void Stop(TSampleVector& sampleVector, TStats& stats) {
+ // Reset signal handler and timer
+ if (Started) {
+ setitimer(ITIMER_PROF, &OldTimerValue, nullptr);
+ sleep(1);
+ }
+
+ WaitForWriteFlag();
+
+ if (Started) {
+ sigaction(SIGPROF, &OldSignalHandler, nullptr);
+ Started = false;
+ }
+
+ TExecutionSampler::TSampleVector hits;
+ hits.reserve(Samples);
+ for (size_t i = 0; i < SZ; ++i) {
+ if (Ips[i].first != nullptr) {
+ hits.push_back(Ips[i]);
+ }
+ }
+ stats.SavedSamples = Samples;
+ stats.DroppedSamples = AtomicGet(DroppedSamples);
+ stats.SearchSkipCount = SearchSkipCount;
+ AtomicUnlock(&WriteFlag);
+
+ Sort(hits.begin(), hits.end(), TCompareFirst());
+
+ sampleVector.swap(hits);
+ }
+
+ void ResetStats() {
+ WaitForWriteFlag();
+ Clear();
+ AtomicUnlock(&WriteFlag);
+ }
+
+private:
+ static const size_t SZ = 2 * 1024 * 1024; // size of the hash table
+ // inserts work faster if it's a power of 2
+ static const int SAMPLE_INTERVAL = 1000; // in microseconds
+
+ struct TCompareFirst {
+ bool operator()(const std::pair<void*, size_t>& a, const std::pair<void*, size_t>& b) const {
+ return a.first < b.first;
+ }
+ };
+
+ TExecutionSampler()
+ : Started(false)
+ , Ips(SZ)
+ , WriteFlag(0)
+ , DroppedSamples(0)
+ , Samples(0)
+ , UniqueSamples(0)
+ , SearchSkipCount(0)
+ {
+ }
+
+ ~TExecutionSampler() = default;
+
+ // Signal handler is not allowed to do anything that can deadlock with activity
+ // on the thread to which the signal is delivered or corrupt data structures that
+ // were in process of update.
+ // One such thing is memory allocation. That's why a fixed size vector is
+ // preallocated at start.
+ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
+ (void)info;
+ if (signal != SIGPROF) {
+ return;
+ }
+
+ ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
+ Y_ASSERT(SInstance != nullptr);
+
+ SInstance->CaptureIP(GetIp(&ucontext->uc_mcontext));
+ }
+
+ void WaitForWriteFlag() {
+ // Wait for write flag to be reset
+ ui32 delay = 100;
+ while (!AtomicTryLock(&WriteFlag)) {
+ usleep(delay);
+ delay += delay;
+ delay = Min(delay, (ui32)5000);
+ }
+ }
+
+ void CaptureIP(void* rip) {
+ // Check if the handler on another thread is in the process of adding a sample
+ // If this is the case, we just drop the current sample as this should happen
+ // rarely.
+ if (AtomicTryLock(&WriteFlag)) {
+ AddSample(rip);
+ AtomicUnlock(&WriteFlag);
+ } else {
+ AtomicIncrement(DroppedSamples);
+ }
+ }
+
+ // Hash function applied to the addresses
+ static inline ui32 Hash(void* key) {
+ return ((size_t)key + (size_t)key / SZ) % SZ;
+ }
+
+ // Get instruction pointer from the context
+ static inline void* GetIp(const mcontext_t* mctx) {
+#if defined _freebsd_
+#if defined _64_
+ return (void*)mctx->mc_rip;
+#else
+ return (void*)mctx->mc_eip;
+#endif
+#elif defined _linux_
+#if defined _64_
+#if defined(_arm_)
+ return (void*)mctx->pc;
+#else
+ return (void*)mctx->gregs[REG_RIP];
+#endif
+#else
+ return (void*)mctx->gregs[REG_EIP];
+#endif
+#elif defined _darwin_
+#if defined _64_
+#if defined(_arm_)
+ return (void*)(*mctx)->__ss.__pc;
+#else
+ return (void*)(*mctx)->__ss.__rip;
+#endif
+#else
+#if defined(__IOS__)
+ return (void*)(*mctx)->__ss.__pc;
+#else
+ return (void*)(*mctx)->__ss.__eip;
+#endif
+#endif
+#endif
+ }
+
+ inline bool AddSample(void* key) {
+ ui32 slot = Hash(key);
+ ui32 prevSlot = (slot - 1) % SZ;
+
+ while (key != Ips[slot].first && !IsSlotEmpty(slot) && slot != prevSlot) {
+ slot = (slot + 1) % SZ;
+ SearchSkipCount++;
+ }
+
+ if (key == Ips[slot].first) {
+ // increment the count
+ Ips[slot].second++;
+ ++Samples;
+ } else if (InsertsAllowed()) {
+ // add new sample and set the count to 1
+ Ips[slot].first = key;
+ Ips[slot].second = 1;
+ ++UniqueSamples;
+ ++Samples;
+ } else {
+ // don't insert new sample if the search is becoming too slow
+ AtomicIncrement(DroppedSamples);
+ return false;
+ }
+
+ return true;
+ }
+
+ inline bool IsSlotEmpty(ui32 slot) const {
+ return Ips[slot].first == nullptr;
+ }
+
+ inline bool InsertsAllowed() const {
+ return UniqueSamples < SZ / 2;
+ }
+
+ void
+ Clear() {
+ Y_ASSERT(WriteFlag == 1);
+
+ for (size_t i = 0; i < SZ; ++i) {
+ Ips[i] = std::make_pair((void*)nullptr, (size_t)0);
+ }
+ Samples = 0;
+ AtomicSet(DroppedSamples, 0);
+ UniqueSamples = 0;
+ SearchSkipCount = 0;
+ }
+
+ bool Started;
+ struct sigaction OldSignalHandler;
+ itimerval OldTimerValue;
+
+ TVector<std::pair<void*, size_t>>
+ Ips; // The hash table storing addresses and their hitcounts
+
+ // TODO: on a big multiproc cache line false sharing by the flag and count might become an issue
+ TAtomic WriteFlag; // Is used to syncronize access to the hash table
+ TAtomic DroppedSamples; // "dropped sample" count will show how many times
+ // a sample was dropped either because of write conflict
+ // or because of the hash table had become too filled up
+ ui64 Samples; // Saved samples count
+ ui64 UniqueSamples; // Number of unique addresses
+ ui64 SearchSkipCount; // Total number of linear hash table probes due to collisions
+
+ static TExecutionSampler* SInstance;
+};
+
+// Performs analysis of samples captured by TExecutionSampler
+class TSampleAnalyser : TNonCopyable {
+public:
+ TSampleAnalyser(TExecutionSampler::TSampleVector& samples, const TExecutionSampler::TStats& stats, bool putTimeStamps = false)
+ : Samples()
+ , Stats(stats)
+ , PutTimestamps(putTimeStamps)
+ {
+ Samples.swap(samples);
+ }
+
+ ~TSampleAnalyser() = default;
+
+ void Analyze(FILE* out) const;
+
+private:
+ TExecutionSampler::TSampleVector Samples;
+ TExecutionSampler::TStats Stats;
+ bool PutTimestamps;
+};
+
+void TSampleAnalyser::Analyze(FILE* out) const {
+ fprintf(out, "samples: %" PRIu64 " unique: %" PRIu64 " dropped: %" PRIu64 " searchskips: %" PRIu64 "\n",
+ (ui64)Stats.SavedSamples, (ui64)Samples.size(),
+ (ui64)Stats.DroppedSamples, (ui64)Stats.SearchSkipCount);
+
+ fprintf(out, "\nSamples:\n");
+ size_t funcCnt = 0;
+ void* prevModBase = (void*)-1;
+ void* prevFunc = (void*)-1;
+ for (size_t i = 0; i < Samples.size(); ++i) {
+ // print cycle count once in a while to estimate time consumed by
+ // dumping the samples
+ if (PutTimestamps && (i % 1000 == 0)) {
+ ui64 tm = GetCycleCount();
+ fprintf(out, "TM: %" PRIu64 "\n", tm);
+ }
+
+ Dl_info addrInfo;
+ if (dladdr(Samples[i].first, &addrInfo)) {
+ if (addrInfo.dli_fbase != prevModBase || addrInfo.dli_saddr != prevFunc) {
+ fprintf(out, "Func\t%" PRISZT "\t%p\t%p\t%s\t%s\n",
+ funcCnt,
+ addrInfo.dli_fbase,
+ addrInfo.dli_saddr,
+ addrInfo.dli_fname,
+ addrInfo.dli_sname);
+ prevModBase = addrInfo.dli_fbase;
+ prevFunc = addrInfo.dli_saddr;
+ ++funcCnt;
+ }
+ } else {
+ fprintf(out, "[dladdr failed]\n");
+ }
+ fprintf(out, "%" PRISZT "\t%p\t%lu\n", i, Samples[i].first, Samples[i].second);
+ }
+}
+
+TExecutionSampler* TExecutionSampler::SInstance = nullptr;
+
+// Starts capturing execution samples
+void BeginProfiling() {
+ TExecutionSampler::Instance()->Start();
+}
+
+// Resets captured execution samples
+void ResetProfile() {
+ TExecutionSampler::Instance()->ResetStats();
+}
+
+void DumpRUsage(FILE* out) {
+ rusage ru;
+ int e = getrusage(RUSAGE_SELF, &ru);
+ if (e != 0)
+ return;
+
+ fprintf(out,
+ "user time: %lf\n"
+ "system time: %lf\n"
+ "max RSS: %ld\n"
+ "shared text: %ld\n"
+ "unshared data: %ld\n"
+ "unshared stack: %ld\n"
+ "page reclaims: %ld\n"
+ "page faults: %ld\n"
+ "swaps: %ld\n"
+ "block input ops: %ld\n"
+ "block output ops: %ld\n"
+ "msg sent: %ld\n"
+ "msg received: %ld\n"
+ "signals: %ld\n"
+ "voluntary ctx switches: %ld\n"
+ "involuntary ctx switches: %ld\n\n",
+ ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec * 0.000001),
+ ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec * 0.000001),
+ ru.ru_maxrss, ru.ru_ixrss, ru.ru_idrss, ru.ru_isrss,
+ ru.ru_minflt, ru.ru_majflt, ru.ru_nswap,
+ ru.ru_inblock, ru.ru_oublock,
+ ru.ru_msgsnd, ru.ru_msgrcv,
+ ru.ru_nsignals,
+ ru.ru_nvcsw, ru.ru_nivcsw);
+}
+
+// Pauses capturing execution samples and dumps them to the file
+// Samples are not cleared so that profiling can be continued by calling BeginProfiling()
+// or it can be started from scratch by calling ResetProfile() and then BeginProfiling()
+void EndProfiling(FILE* out) {
+ DumpRUsage(out);
+
+ TExecutionSampler::TSampleVector samples;
+ TExecutionSampler::TStats stats;
+ TExecutionSampler::Instance()->Stop(samples, stats);
+
+ TSampleAnalyser analyzer(samples, stats);
+ analyzer.Analyze(out);
+}
+
+void EndProfiling() {
+ static unsigned cnt = 0;
+ char nameBuf[256];
+ snprintf(nameBuf, sizeof(nameBuf), "./%s.%d.%u.profile", getprogname(), (int)getpid(), cnt);
+ FILE* out = fopen(nameBuf, "a");
+ EndProfiling(out);
+ fclose(out);
+ ++cnt;
+}
+
+#else
+
+// NOTE: not supported on Windows
+
+void BeginProfiling() {
+}
+
+void ResetProfile() {
+}
+
+void EndProfiling(FILE*) {
+}
+
+void EndProfiling() {
+}
+
+#endif
diff --git a/library/cpp/execprofile/profile.h b/library/cpp/execprofile/profile.h
new file mode 100644
index 0000000000..ccb8866656
--- /dev/null
+++ b/library/cpp/execprofile/profile.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <stdio.h>
+
+// Starts capturing execution samples
+void BeginProfiling();
+
+// Resets captured execution samples
+void ResetProfile();
+
+// Pauses capturing execution samples and dumps them to the file
+// Samples are not cleared so that profiling can be continued by calling BeginProfiling()
+// or it can be started from scratch by calling ResetProfile() and then BeginProfiling()
+void EndProfiling(FILE* out);
+
+// Dumps the profile to default file (basename.pid.N.profile)
+void EndProfiling();
diff --git a/library/cpp/execprofile/ya.make b/library/cpp/execprofile/ya.make
new file mode 100644
index 0000000000..9d202ac4eb
--- /dev/null
+++ b/library/cpp/execprofile/ya.make
@@ -0,0 +1,9 @@
+OWNER(g:cpp-contrib)
+
+LIBRARY()
+
+SRCS(
+ profile.cpp
+)
+
+END()
diff --git a/library/cpp/getopt/last_getopt.h b/library/cpp/getopt/last_getopt.h
new file mode 100644
index 0000000000..d14f05cc5b
--- /dev/null
+++ b/library/cpp/getopt/last_getopt.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include <library/cpp/getopt/small/last_getopt.h>
diff --git a/library/cpp/getopt/last_getopt_demo/demo.cpp b/library/cpp/getopt/last_getopt_demo/demo.cpp
new file mode 100644
index 0000000000..79426a9cc9
--- /dev/null
+++ b/library/cpp/getopt/last_getopt_demo/demo.cpp
@@ -0,0 +1,242 @@
+#include <library/cpp/getopt/last_getopt.h>
+#include <library/cpp/getopt/modchooser.h>
+#include <library/cpp/colorizer/colors.h>
+
+// For the sake of this example, let's implement Wget
+
+Y_COMPLETER(HeaderCompleter) {
+ AddCompletion("Host");
+ AddCompletion("Referer");
+
+ bool addPostHeaders = false;
+
+ for (int i = 0; i < argc; ++i) {
+ if (argv[i] == TStringBuf("--method") && i + 1 < argc) {
+ auto method = TString(argv[i + 1]);
+ method.to_upper();
+ addPostHeaders = method == "POST" || method == "PUT";
+ break;
+ } else if (argv[i] == TStringBuf("--post-data") || argv[i] == TStringBuf("--post-file")) {
+ addPostHeaders = true;
+ break;
+ }
+ }
+
+ if (addPostHeaders) {
+ AddCompletion("Content-Type");
+ AddCompletion("Content-Encoding");
+ AddCompletion("Content-Language");
+ AddCompletion("Content-Length");
+ AddCompletion("Content-Location");
+ AddCompletion("Content-MD5");
+ AddCompletion("Content-Range");
+ }
+}
+
+class TMain: public TMainClassArgs {
+ bool Background_;
+ size_t Timeout_;
+ TString ExplicitMethod_;
+ TString ImplicitMethod_ = "GET";
+ TString UserAgent_;
+ TMaybe<TString> PostData_;
+ TMaybe<TString> PostFile_;
+ TVector<TString> Headers_;
+
+protected:
+ void RegisterOptions(NLastGetopt::TOpts& opts) override {
+ // Brief description for the whole program, will appear in the beginning of a help message.
+ opts.SetTitle("last_getopt_demo -- like wget, but doesn't actually do anything");
+
+ // Built-in options.
+ opts.AddHelpOption('h');
+ opts.AddCompletionOption("last_getopt_demo");
+
+ // Custom options.
+
+ opts.AddLongOption('V', "version")
+ .Help("print version and exit")
+ .IfPresentDisableCompletion()
+ .NoArgument()
+ .Handler([]() {
+ Cerr << "last_getopt_demo 1.0.0" << Endl;
+ exit(0);
+ });
+
+ opts.AddLongOption('b', "background")
+ .Help("go to background immediately after startup")
+ .StoreTrue(&Background_);
+
+ opts.AddLongOption("timeout")
+ .RequiredArgument("timeout")
+ .DefaultValue("60000")
+ .Help("specify timeout in milliseconds for each request")
+ .CompletionHelp("specify timeout for each request")
+ .CompletionArgHelp("timeout (ms)")
+ .StoreResult(&Timeout_)
+ .Completer(NLastGetopt::NComp::Choice({{"1000"}, {"5000"}, {"10000"}, {"60000"}}));
+
+ opts.AddLongOption("method")
+ .RequiredArgument("http-method")
+ .Help("specify HTTP method")
+ .CompletionArgHelp("http method")
+ .StoreResult(&ExplicitMethod_)
+ .Completer(
+ NLastGetopt::NComp::Choice(
+ {{"GET", "request representation of the specified resource"},
+ {"HEAD", "request response identical to that of GET, but without response body"},
+ {"POST", "submit an entry to the specified resource"},
+ {"PUT", "replace representation of the specified resource with the request body"},
+ {"DELETE", "delete the specified resource"},
+ {"CONNECT", "establish a tunnel to the server identified by the target resource"},
+ {"OPTIONS", "describe the communication options for the target resource"},
+ {"TRACE", "perform a message loop-back test"},
+ {"PATCH", "apply partial modifications to the specified resource"}}));
+
+ opts.AddLongOption('U', "user-agent")
+ .RequiredArgument("agent-string")
+ .DefaultValue("LastGetoptDemo/1.0.0")
+ .Help("identify as `agent-string` to the HTTP server")
+ .CompletionHelp("set custom user agent for each HTTP request")
+ .CompletionArgHelp("user agent string")
+ .StoreResult(&UserAgent_);
+
+ opts.AddLongOption("post-data")
+ .RequiredArgument("string")
+ .Help("use POST method and send the specified data in the request body (cannot be used with --post-file)")
+ .CompletionHelp("use POST method and send the specified data in the request body")
+ .CompletionArgHelp("POST data string")
+ .StoreResultT<TString>(&PostData_)
+ .Handler0([this]() {
+ ImplicitMethod_ = "POST";
+ });
+
+ opts.AddLongOption("post-file")
+ .RequiredArgument("file")
+ .Help("use POST method and send contents of the specified file in the request body (cannot be used with --post-data)")
+ .CompletionHelp("use POST method and send contents of the specified file in the request body")
+ .CompletionArgHelp("POST file")
+ .StoreResultT<TString>(&PostFile_)
+ .Handler0([this]() {
+ ImplicitMethod_ = "POST";
+ })
+ .Completer(NLastGetopt::NComp::File());
+
+ // These two options can't be together.
+ opts.MutuallyExclusive("post-file", "post-data");
+
+ opts.AddLongOption("header")
+ .RequiredArgument("header-line")
+ .Help("send `header-line` along with the rest of the headers in each HTTP request")
+ .CompletionHelp("add header to each HTTP request")
+ .CompletionArgHelp("header string")
+ .AppendTo(&Headers_)
+ .AllowMultipleCompletion()
+ .Completer(NLastGetopt::NComp::LaunchSelf(HeaderCompleter));
+
+ // Setting up free arguments.
+
+ // We are going to have one mandatory argument and unlimited number of optional arguments.
+ opts.SetFreeArgsMin(1);
+ opts.SetFreeArgsMax(NLastGetopt::TOpts::UNLIMITED_ARGS);
+
+ // Configuration for the first argument.
+ opts.GetFreeArgSpec(0)
+ .Title("URL")
+ .Help("URL for download")
+ .CompletionArgHelp("URL for download")
+ .Completer(NLastGetopt::NComp::Url());
+
+ // Configuration for optional arguments.
+ opts.GetTrailingArgSpec()
+ .Title("URL")
+ .CompletionArgHelp("URL for download")
+ .Completer(NLastGetopt::NComp::Url());
+
+ // Let's add more text to our help. A nice description and examples.
+
+ opts.AddSection(
+ "Description",
+
+ "LastGetoptDemo is a showcase of library/cpp/getopt capabilities. It mimics interface of Wget "
+ "but doesn't actually do anything."
+ "\n\n"
+ "GNU Wget, on the other hand, is a free utility for non-interactive download of files from the Web."
+ "It supports HTTP, HTTPS, and FTP protocols, as well as retrieval through HTTP proxies."
+ "\n\n"
+ "Wget is non-interactive, meaning that it can work in the background, while the user is not logged on. "
+ "This allows you to start a retrieval and disconnect from the system, letting Wget finish the work. "
+ "By contrast, most of the Web browsers require constant user's presence, "
+ "which can be a great hindrance when transferring a lot of data."
+ "\n\n"
+ "Wget can follow links in HTML, XHTML, and CSS pages, to create local versions of remote web sites, "
+ "fully recreating the directory structure of the original site. "
+ "This is sometimes referred to as \"recursive downloading.\" "
+ "While doing that, Wget respects the Robot Exclusion Standard (/robots.txt). "
+ "Wget can be instructed to convert the links in downloaded files to point at the local files, "
+ "for offline viewing."
+ "\n\n"
+ "Wget has been designed for robustness over slow or unstable network connections; "
+ "if a download fails due to a network problem, "
+ "it will keep retrying until the whole file has been retrieved. "
+ "If the server supports regetting, "
+ "it will instruct the server to continue the download from where it left off."
+ "\n\n"
+ "Wget does not support Client Revocation Lists (CRLs) so the HTTPS certificate "
+ "you are connecting to might be revoked by the siteowner.");
+
+ // We will use colors for this one.
+ auto& colors = NColorizer::StdErr();
+ opts.AddSection(
+ "Examples",
+
+ TStringBuilder()
+ << "Download a file:"
+ << "\n"
+ << colors.Cyan()
+ << " $ last_getopt_demo https://wordpress.org/latest.zip"
+ << colors.Reset()
+ << "\n"
+ << "Download a file in background, set custom user agent:"
+ << "\n"
+ << colors.Cyan()
+ << " $ last_getopt_demo -b -U 'Wget/1.0.0' https://wordpress.org/latest.zip"
+ << colors.Reset());
+ }
+
+ int DoRun(NLastGetopt::TOptsParseResult&& parsedOptions) override {
+ using namespace NColorizer;
+
+ TString method = ExplicitMethod_ ? ExplicitMethod_ : ImplicitMethod_;
+
+ Cerr << ST_LIGHT << "Settings:" << RESET << Endl;
+ Cerr << GREEN << " Background: " << RESET << Background_ << Endl;
+ Cerr << GREEN << " Timeout: " << RESET << Timeout_ << Endl;
+ Cerr << GREEN << " Method: " << RESET << method.Quote() << Endl;
+ Cerr << GREEN << " UserAgent: " << RESET << UserAgent_.Quote() << Endl;
+ Cerr << GREEN << " PostData: " << RESET << (PostData_ ? PostData_->Quote() : "Nothing") << Endl;
+ Cerr << GREEN << " PostFile: " << RESET << (PostFile_ ? PostFile_->Quote() : "Nothing") << Endl;
+
+ Cerr << ST_LIGHT << "Headers:" << RESET << Endl;
+ for (auto& header : Headers_) {
+ Cerr << " " << header.Quote() << Endl;
+ }
+ if (!Headers_) {
+ Cerr << GREEN << " no headers" << RESET << Endl;
+ }
+
+ Cerr << ST_LIGHT << "Will download the following URLs:" << RESET << Endl;
+ for (auto& arg : parsedOptions.GetFreeArgs()) {
+ Cerr << " " << arg.Quote() << Endl;
+ }
+ if (!parsedOptions.GetFreeArgs()) {
+ Cerr << " no urls" << Endl;
+ }
+ return 0;
+ }
+};
+
+int main(int argc, const char** argv) {
+ NLastGetopt::NComp::TCustomCompleter::FireCustomCompleter(argc, argv);
+ TMain().Run(argc, argv);
+}
diff --git a/library/cpp/getopt/last_getopt_demo/ya.make b/library/cpp/getopt/last_getopt_demo/ya.make
new file mode 100644
index 0000000000..53f1cfc122
--- /dev/null
+++ b/library/cpp/getopt/last_getopt_demo/ya.make
@@ -0,0 +1,13 @@
+PROGRAM(last_getopt_demo)
+
+OWNER(amatanhead)
+
+PEERDIR(
+ library/cpp/getopt
+)
+
+SRCS(
+ demo.cpp
+)
+
+END()
diff --git a/library/cpp/getopt/last_getopt_support.h b/library/cpp/getopt/last_getopt_support.h
new file mode 100644
index 0000000000..b71c7045b1
--- /dev/null
+++ b/library/cpp/getopt/last_getopt_support.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include <library/cpp/getopt/small/last_getopt_support.h>
diff --git a/library/cpp/getopt/modchooser.h b/library/cpp/getopt/modchooser.h
new file mode 100644
index 0000000000..9bf73daf13
--- /dev/null
+++ b/library/cpp/getopt/modchooser.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include <library/cpp/getopt/small/modchooser.h>
diff --git a/library/cpp/getopt/opt.h b/library/cpp/getopt/opt.h
new file mode 100644
index 0000000000..d2a85075bd
--- /dev/null
+++ b/library/cpp/getopt/opt.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include <library/cpp/getopt/small/opt.h>
diff --git a/library/cpp/getopt/opt2.h b/library/cpp/getopt/opt2.h
new file mode 100644
index 0000000000..2d35bc7b29
--- /dev/null
+++ b/library/cpp/getopt/opt2.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include <library/cpp/getopt/small/opt2.h>
diff --git a/library/cpp/getopt/posix_getopt.h b/library/cpp/getopt/posix_getopt.h
new file mode 100644
index 0000000000..8cb7ece624
--- /dev/null
+++ b/library/cpp/getopt/posix_getopt.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include <library/cpp/getopt/small/posix_getopt.h>
diff --git a/library/cpp/getopt/print.cpp b/library/cpp/getopt/print.cpp
new file mode 100644
index 0000000000..8cf1c62e4d
--- /dev/null
+++ b/library/cpp/getopt/print.cpp
@@ -0,0 +1,40 @@
+#include "last_getopt.h"
+#include "last_getopt_support.h"
+#include "modchooser.h"
+#include "opt.h"
+#include "opt2.h"
+#include "posix_getopt.h"
+#include "ygetopt.h"
+
+#include <library/cpp/svnversion/svnversion.h>
+#include <library/cpp/build_info/build_info.h>
+
+namespace NLastGetoptPrivate {
+ TString InitVersionString() {
+ TString ts = GetProgramSvnVersion();
+ ts += "\n";
+ ts += GetBuildInfo();
+ TString sandboxTaskId = GetSandboxTaskId();
+ if (sandboxTaskId != TString("0")) {
+ ts += "\nSandbox task id: ";
+ ts += sandboxTaskId;
+ }
+ return ts;
+ }
+
+ TString InitShortVersionString() {
+ TString ts = GetProgramShortVersionData();
+ return ts;
+ }
+
+ TString& VersionString();
+ TString& ShortVersionString();
+
+ struct TInit {
+ TInit() {
+ VersionString() = InitVersionString();
+ ShortVersionString() = InitShortVersionString();
+ }
+ } Init;
+
+}
diff --git a/library/cpp/getopt/small/completer.cpp b/library/cpp/getopt/small/completer.cpp
new file mode 100644
index 0000000000..3fff684adb
--- /dev/null
+++ b/library/cpp/getopt/small/completer.cpp
@@ -0,0 +1,367 @@
+#include "completer.h"
+
+#include "completion_generator.h"
+
+#include <util/string/cast.h>
+#include <util/generic/fwd.h>
+
+using NLastGetopt::NEscaping::Q;
+using NLastGetopt::NEscaping::QQ;
+using NLastGetopt::NEscaping::C;
+using NLastGetopt::NEscaping::CC;
+using NLastGetopt::NEscaping::S;
+using NLastGetopt::NEscaping::SS;
+using NLastGetopt::NEscaping::B;
+using NLastGetopt::NEscaping::BB;
+
+namespace NLastGetopt::NComp {
+#define L out.Line()
+#define I auto Y_GENERATE_UNIQUE_ID(indent) = out.Indent()
+
+ TCompleterManager::TCompleterManager(TStringBuf command)
+ : Command_(command)
+ , Id_(0)
+ {
+ }
+
+ TStringBuf TCompleterManager::GetCompleterID(const ICompleter* completer) {
+ return Queue_.emplace_back(TStringBuilder() << "_" << Command_ << "__completer_" << ++Id_, completer).first;
+ }
+
+ void TCompleterManager::GenerateZsh(TFormattedOutput& out) {
+ while (!Queue_.empty()) {
+ auto[name, completer] = Queue_.back();
+ Queue_.pop_back();
+
+ L << "(( $+functions[" << name << "] )) ||";
+ L << name << "() {";
+ {
+ I;
+ completer->GenerateZsh(out, *this);
+ }
+ L << "}";
+ L;
+ }
+ }
+
+ class TAlternativeCompleter: public ICompleter {
+ public:
+ TAlternativeCompleter(TVector<TAlternative> alternatives)
+ : Alternatives_(std::move(alternatives))
+ {
+ }
+
+ void GenerateBash(TFormattedOutput& out) const override {
+ for (auto& alternative: Alternatives_) {
+ if (alternative.Completer != nullptr) {
+ alternative.Completer->GenerateBash(out);
+ }
+ }
+ }
+
+ TStringBuf GenerateZshAction(TCompleterManager& manager) const override {
+ return manager.GetCompleterID(this);
+ }
+
+ void GenerateZsh(TFormattedOutput& out, TCompleterManager& manager) const override {
+ // We should use '_alternative' here, but it doesn't process escape codes in group descriptions,
+ // so we dispatch alternatives ourselves.
+
+ L << "local expl action";
+
+ size_t i = 0;
+ for (auto& alternative: Alternatives_) {
+ auto tag = "alt-" + ToString(++i);
+ auto action = alternative.Completer ? alternative.Completer->GenerateZshAction(manager) : TStringBuf();
+
+ L;
+
+ if (action.empty()) {
+ L << "_message -e " << SS(tag) << " " << SS(alternative.Description);
+ } else if (action.StartsWith("((") && action.EndsWith("))")) {
+ L << "action=" << action.substr(1, action.size() - 2);
+ L << "_describe -t " << SS(tag) << " " << SS(alternative.Description) << " action -M 'r:|[_-]=* r:|=*'";
+ } else if (action.StartsWith("(") && action.EndsWith(")")) {
+ L << "action=" << action << "";
+ L << "_describe -t " << SS(tag) << " " << SS(alternative.Description) << " action -M 'r:|[_-]=* r:|=*'";
+ } else if (action.StartsWith(' ')) {
+ L << action.substr(1);
+ } else {
+ L << "_description " << SS(tag) << " expl " << SS(alternative.Description);
+ TStringBuf word, args;
+ action.Split(' ', word, args);
+ L << word << " \"${expl[@]}\" " << args;
+ }
+ }
+ }
+
+ private:
+ TVector<TAlternative> Alternatives_;
+ };
+
+ ICompleterPtr Alternative(TVector<TAlternative> alternatives) {
+ return MakeSimpleShared<TAlternativeCompleter>(std::move(alternatives));
+ }
+
+ class TSimpleCompleter: public ICompleter {
+ public:
+ TSimpleCompleter(TString bashCode, TString action)
+ : BashCode(std::move(bashCode))
+ , Action(std::move(action))
+ {
+ }
+
+ void GenerateBash(TFormattedOutput& out) const override {
+ if (BashCode) {
+ L << BashCode;
+ }
+ }
+
+ TStringBuf GenerateZshAction(TCompleterManager&) const override {
+ return Action;
+ }
+
+ void GenerateZsh(TFormattedOutput&, TCompleterManager&) const override {
+ Y_FAIL("unreachable");
+ }
+
+ private:
+ TString BashCode;
+ TString Action;
+ };
+
+ ICompleterPtr Choice(TVector<TChoice> choices) {
+ auto bash = TStringBuilder() << "COMPREPLY+=( $(compgen -W '";
+ TStringBuf sep = "";
+ for (auto& choice : choices) {
+ bash << sep << B(choice.Choice);
+ sep = " ";
+ }
+ bash << "' -- ${cur}) )";
+
+ auto action = TStringBuilder();
+ action << "((";
+ for (auto& choice: choices) {
+ action << " " << SS(choice.Choice);
+ if (choice.Description) {{
+ action << ":" << SS(choice.Description);
+ }}
+ }
+ action << "))";
+ return MakeSimpleShared<TSimpleCompleter>(bash, action);
+ }
+
+ TString Compgen(TStringBuf flags) {
+ return TStringBuilder() << "COMPREPLY+=( $(compgen " << flags << " -- ${cur}) )";
+ }
+
+ ICompleterPtr Default() {
+ return MakeSimpleShared<TSimpleCompleter>("", "_default");
+ }
+
+ ICompleterPtr File(TString pattern) {
+ if (pattern) {
+ pattern = " -g " + SS(pattern);
+ }
+ return MakeSimpleShared<TSimpleCompleter>("", "_files" + pattern);
+ }
+
+ ICompleterPtr Directory() {
+ return MakeSimpleShared<TSimpleCompleter>("", "_files -/");
+ }
+
+ ICompleterPtr Host() {
+ return MakeSimpleShared<TSimpleCompleter>(Compgen("-A hostname"), "_hosts");
+ }
+
+ ICompleterPtr Pid() {
+ return MakeSimpleShared<TSimpleCompleter>("", "_pids");
+ }
+
+ ICompleterPtr User() {
+ return MakeSimpleShared<TSimpleCompleter>(Compgen("-A user"), "_users");
+ }
+
+ ICompleterPtr Group() {
+ // For some reason, OSX freezes when trying to perform completion for groups.
+ // You can try removing this ifdef and debugging it, but be prepared to force-shutdown your machine
+ // (and possibly reinstall OSX if force-shutdown breaks anything).
+#ifdef _darwin_
+ return MakeSimpleShared<TSimpleCompleter>("", "");
+#else
+ return MakeSimpleShared<TSimpleCompleter>(Compgen("-A group"), "_groups");
+#endif
+ }
+
+ ICompleterPtr Url() {
+ return MakeSimpleShared<TSimpleCompleter>("", "_urls");
+ }
+
+ ICompleterPtr Tty() {
+ return MakeSimpleShared<TSimpleCompleter>("", "_ttys");
+ }
+
+ ICompleterPtr NetInterface() {
+ return MakeSimpleShared<TSimpleCompleter>("", "_net_interfaces");
+ }
+
+ ICompleterPtr TimeZone() {
+ return MakeSimpleShared<TSimpleCompleter>("", "_time_zone");
+ }
+
+ ICompleterPtr Signal() {
+ return MakeSimpleShared<TSimpleCompleter>(Compgen("-A signal"), "_signals");
+ }
+
+ ICompleterPtr Domain() {
+ return MakeSimpleShared<TSimpleCompleter>("", "_domains");
+ }
+
+ namespace {
+ TCustomCompleter* Head = nullptr;
+ TStringBuf SpecialFlag = "---CUSTOM-COMPLETION---";
+ }
+
+ void TCustomCompleter::FireCustomCompleter(int argc, const char** argv) {
+ if (!argc) {
+ return;
+ }
+
+ for (int i = 1; i < argc - 4; ++i) {
+ if (SpecialFlag == argv[i]) {
+ auto name = TStringBuf(argv[i + 1]);
+ auto curIdx = FromString<int>(argv[i + 2]);
+ auto prefix = TStringBuf(argv[i + 3]);
+ auto suffix = TStringBuf(argv[i + 4]);
+
+ auto cur = TStringBuf();
+ if (0 <= curIdx && curIdx < i) {
+ cur = TStringBuf(argv[curIdx]);
+ }
+ if (cur && !prefix && !suffix) {
+ prefix = cur; // bash does not send prefix and suffix
+ }
+
+ auto head = Head;
+ while (head) {
+ if (head->GetUniqueName() == name) {
+ head->GenerateCompletions(i, argv, curIdx, cur, prefix, suffix);
+ }
+ head = head->Next_;
+ }
+
+ exit(0);
+ }
+ }
+ }
+
+ void TCustomCompleter::RegisterCustomCompleter(TCustomCompleter* completer) noexcept {
+ Y_VERIFY(completer);
+ completer->Next_ = Head;
+ Head = completer;
+ }
+
+ void TCustomCompleter::AddCompletion(TStringBuf completion) {
+ Cout << completion << Endl; // this was easy =)
+ // TODO: support option descriptions and messages
+ }
+
+ void TMultipartCustomCompleter::GenerateCompletions(int argc, const char** argv, int curIdx, TStringBuf cur, TStringBuf prefix, TStringBuf suffix) {
+ auto root = TStringBuf();
+ if (prefix.Contains(Sep_)) {
+ auto tmp = TStringBuf();
+ prefix.RSplit(Sep_, root, tmp);
+ }
+
+ if (root) {
+ Cout << root << Sep_ << Endl;
+ } else {
+ Cout << Endl;
+ }
+
+ Cout << Sep_ << Endl;
+
+ GenerateCompletionParts(argc, argv, curIdx, cur, prefix, suffix, root);
+ }
+
+ class TLaunchSelf: public ICompleter {
+ public:
+ TLaunchSelf(TCustomCompleter* completer)
+ : Completer_(completer)
+ {
+ }
+
+ void GenerateBash(TFormattedOutput& out) const override {
+ L << "IFS=$'\\n'";
+ L << "COMPREPLY+=( $(compgen -W \"$(${words[@]} " << SpecialFlag << " " << Completer_->GetUniqueName() << " \"${cword}\" \"\" \"\" 2> /dev/null)\" -- ${cur}) )";
+ L << "IFS=$' \\t\\n'";
+ }
+
+ TStringBuf GenerateZshAction(TCompleterManager& manager) const override {
+ return manager.GetCompleterID(this);
+ }
+
+ void GenerateZsh(TFormattedOutput& out, TCompleterManager&) const override {
+ L << "compadd ${@} ${expl[@]} -- \"${(@f)$(${words_orig[@]} " << SpecialFlag << " " << Completer_->GetUniqueName() << " \"${current_orig}\" \"${prefix_orig}\" \"${suffix_orig}\" 2> /dev/null)}\"";
+ }
+
+ private:
+ TCustomCompleter* Completer_;
+ };
+
+ ICompleterPtr LaunchSelf(TCustomCompleter& completer) {
+ return MakeSimpleShared<TLaunchSelf>(&completer);
+ }
+
+ class TLaunchSelfMultiPart: public ICompleter {
+ public:
+ TLaunchSelfMultiPart(TCustomCompleter* completer)
+ : Completer_(completer)
+ {
+ }
+
+ void GenerateBash(TFormattedOutput& out) const override {
+ L << "IFS=$'\\n'";
+ L << "items=( $(${words[@]} " << SpecialFlag << " " << Completer_->GetUniqueName() << " \"${cword}\" \"\" \"\" 2> /dev/null) )";
+ L << "candidates=$(compgen -W \"${items[*]:1}\" -- \"$cur\")";
+ L << "COMPREPLY+=( $candidates )";
+ L << "[[ $candidates == *\"${items[1]}\" ]] && need_space=\"\"";
+ L << "IFS=$' \\t\\n'";
+ }
+
+ TStringBuf GenerateZshAction(TCompleterManager& manager) const override {
+ return manager.GetCompleterID(this);
+ }
+
+ void GenerateZsh(TFormattedOutput& out, TCompleterManager&) const override {
+ L << "local items=( \"${(@f)$(${words_orig[@]} " << SpecialFlag << " " << Completer_->GetUniqueName() << " \"${current_orig}\" \"${prefix_orig}\" \"${suffix_orig}\" 2> /dev/null)}\" )";
+ L;
+ L << "local rempat=${items[1]}";
+ L << "shift items";
+ L;
+ L << "local sep=${items[1]}";
+ L << "shift items";
+ L;
+ L << "local files=( ${items:#*\"${sep}\"} )";
+ L << "local filenames=( ${files#\"${rempat}\"} )";
+ L << "local dirs=( ${(M)items:#*\"${sep}\"} )";
+ L << "local dirnames=( ${dirs#\"${rempat}\"} )";
+ L;
+ L << "local need_suf";
+ L << "compset -S \"${sep}*\" || need_suf=\"1\"";
+ L;
+ L << "compadd ${@} ${expl[@]} -d filenames -- ${(q)files}";
+ L << "compadd ${@} ${expl[@]} ${need_suf:+-S\"${sep}\"} -q -d dirnames -- ${(q)dirs%\"${sep}\"}";
+ }
+
+ private:
+ TCustomCompleter* Completer_;
+ };
+
+ ICompleterPtr LaunchSelfMultiPart(TCustomCompleter& completer) {
+ return MakeSimpleShared<TLaunchSelfMultiPart>(&completer);
+ }
+
+#undef I
+#undef L
+}
diff --git a/library/cpp/getopt/small/completer.h b/library/cpp/getopt/small/completer.h
new file mode 100644
index 0000000000..4136f13add
--- /dev/null
+++ b/library/cpp/getopt/small/completer.h
@@ -0,0 +1,306 @@
+#pragma once
+
+#include "formatted_output.h"
+
+#include <util/generic/strbuf.h>
+#include <util/generic/hash.h>
+
+#include <utility>
+#include <util/generic/fwd.h>
+
+namespace NLastGetopt::NComp {
+ class ICompleter;
+
+ class TCompleterManager {
+ public:
+ TCompleterManager(TStringBuf command);
+
+ /// Register new completer and get its function name.
+ TStringBuf GetCompleterID(const ICompleter* completer);
+
+ /// Generate zsh code for all collected completers.
+ void GenerateZsh(TFormattedOutput& out);
+
+ private:
+ TStringBuf Command_;
+ size_t Id_;
+ TVector<std::pair<TString, const ICompleter*>> Queue_;
+ };
+
+ class ICompleter {
+ public:
+ virtual ~ICompleter() = default;
+
+ public:
+ /// Generate arbitrary bash code that modifies `COMPREPLY`.
+ virtual void GenerateBash(TFormattedOutput& out) const = 0;
+
+ /// Generate action that will be used with `_arguments`. If this completer requires a separate function,
+ /// register it in the given manager and return function name assigned by manager.
+ /// Supported forms are '()', '(items...)', '((items...))', 'command ...' and ' command ...'.
+ /// Other forms, such as '{eval-string}', '->state', '=action' are not supported.
+ virtual TStringBuf GenerateZshAction(TCompleterManager& manager) const = 0;
+
+ /// Generate body of a zsh function (if Action points to a custom function).
+ virtual void GenerateZsh(TFormattedOutput& out, TCompleterManager& manager) const = 0;
+ };
+
+ using ICompleterPtr = TSimpleSharedPtr<ICompleter>;
+
+ /// Generate default completions.
+ /// Output of this completer depends on shell settings.
+ /// Usually ut generates file paths.
+ ICompleterPtr Default();
+
+ struct TAlternative {
+ /// Description for this group of completions. Leave empty to use completer's default description.
+ TString Description;
+
+ /// Completer that generates values
+ ICompleterPtr Completer;
+
+ TAlternative(ICompleterPtr completer)
+ : Description("")
+ , Completer(std::move(completer))
+ {
+ }
+
+ TAlternative(TString description, ICompleterPtr completer)
+ : Description(std::move(description))
+ , Completer(std::move(completer))
+ {
+ }
+ };
+
+ /// Run multiple completers and unite their output.
+ /// Each completer's output placed in a separate group with its own description.
+ ICompleterPtr Alternative(TVector<TAlternative> alternatives);
+
+ struct TChoice {
+ /// Option value.
+ TString Choice;
+
+ /// Description for a value.
+ TString Description = "";
+
+ TChoice(TString choice)
+ : Choice(std::move(choice))
+ {
+ }
+
+ TChoice(TString choice, TString description)
+ : Choice(std::move(choice))
+ , Description(std::move(description))
+ {
+ }
+ };
+
+ /// Complete items from a predefined list of choices.
+ ICompleterPtr Choice(TVector<TChoice> choices);
+
+ /// Complete files and directories. May filter results by pattern, e.g. `*.txt`.
+ ICompleterPtr File(TString pattern= "");
+
+ /// Complete directories.
+ ICompleterPtr Directory();
+
+ /// Complete hosts.
+ ICompleterPtr Host();
+
+ /// Complete process IDs.
+ ICompleterPtr Pid();
+
+ /// Complete users that're found in the system.
+ ICompleterPtr User();
+
+ /// Complete user groups that're found in the system.
+ /// N: for some reason,
+ ICompleterPtr Group();
+
+ /// Complete URLs.
+ ICompleterPtr Url();
+
+ /// Complete TTY interfaces.
+ ICompleterPtr Tty();
+
+ /// Complete network interfaces.
+ ICompleterPtr NetInterface();
+
+ /// Complete timezone identifiers.
+ ICompleterPtr TimeZone();
+
+ /// Complete unix signal identifiers, e.g. `ABRT` or `KILL`.
+ ICompleterPtr Signal();
+
+ /// Complete domains.
+ ICompleterPtr Domain();
+
+ /// Custom completer. See `LaunchSelf` below.
+ class TCustomCompleter {
+ public:
+ static void FireCustomCompleter(int argc, const char** argv);
+ static void RegisterCustomCompleter(TCustomCompleter* completer) noexcept;
+
+ struct TReg {
+ TReg(TCustomCompleter* completer) noexcept {
+ TCustomCompleter::RegisterCustomCompleter(completer);
+ }
+ };
+
+ public:
+ virtual ~TCustomCompleter() = default;
+
+ public:
+ /// @param argc total number of command line arguments.
+ /// @param argv array of command line arguments.
+ /// @param curIdx index of the currently completed argument, may be equal to `argc` if cursor is at the end
+ /// of line.
+ /// @param cur currently completed argument.
+ /// @param prefix part of the currently completed argument before the cursor.
+ /// @param suffix part of the currently completed argument after the cursor.
+ virtual void GenerateCompletions(int argc, const char** argv, int curIdx, TStringBuf cur, TStringBuf prefix, TStringBuf suffix) = 0;
+ virtual TStringBuf GetUniqueName() const = 0;
+
+ protected:
+ void AddCompletion(TStringBuf completion);
+
+ private:
+ TCustomCompleter* Next_ = nullptr;
+ };
+
+ /// Custom completer for objects that consist of multiple parts split by a common separator, such as file paths.
+ class TMultipartCustomCompleter: public TCustomCompleter {
+ public:
+ TMultipartCustomCompleter(TStringBuf sep)
+ : Sep_(sep)
+ {
+ Y_VERIFY(!Sep_.empty());
+ }
+
+ public:
+ void GenerateCompletions(int argc, const char** argv, int curIdx, TStringBuf cur, TStringBuf prefix, TStringBuf suffix) final;
+
+ public:
+ /// @param argc same as in `GenerateCompletions`.
+ /// @param argv same as in `GenerateCompletions`.
+ /// @param curIdx same as in `GenerateCompletions`.
+ /// @param cur same as in `GenerateCompletions`.
+ /// @param prefix same as in `GenerateCompletions`.
+ /// @param suffix same as in `GenerateCompletions`.
+ /// @param root part of the currently completed argument before the last separator.
+ virtual void GenerateCompletionParts(int argc, const char** argv, int curIdx, TStringBuf cur, TStringBuf prefix, TStringBuf suffix, TStringBuf root) = 0;
+
+ protected:
+ TStringBuf Sep_;
+ };
+
+#define Y_COMPLETER(N) \
+class T##N: public ::NLastGetopt::NComp::TCustomCompleter { \
+ public: \
+ void GenerateCompletions(int, const char**, int, TStringBuf, TStringBuf, TStringBuf) override; \
+ TStringBuf GetUniqueName() const override { return #N; } \
+ }; \
+ T##N N = T##N(); \
+ ::NLastGetopt::NComp::TCustomCompleter::TReg _Reg_##N = &N; \
+ void T##N::GenerateCompletions( \
+ Y_DECLARE_UNUSED int argc, \
+ Y_DECLARE_UNUSED const char** argv, \
+ Y_DECLARE_UNUSED int curIdx, \
+ Y_DECLARE_UNUSED TStringBuf cur, \
+ Y_DECLARE_UNUSED TStringBuf prefix, \
+ Y_DECLARE_UNUSED TStringBuf suffix)
+
+#define Y_MULTIPART_COMPLETER(N, SEP) \
+class T##N: public ::NLastGetopt::NComp::TMultipartCustomCompleter { \
+ public: \
+ T##N() : ::NLastGetopt::NComp::TMultipartCustomCompleter(SEP) {} \
+ void GenerateCompletionParts(int, const char**, int, TStringBuf, TStringBuf, TStringBuf, TStringBuf) override; \
+ TStringBuf GetUniqueName() const override { return #N; } \
+ }; \
+ T##N N = T##N(); \
+ ::NLastGetopt::NComp::TCustomCompleter::TReg _Reg_##N = &N; \
+ void T##N::GenerateCompletionParts( \
+ Y_DECLARE_UNUSED int argc, \
+ Y_DECLARE_UNUSED const char** argv, \
+ Y_DECLARE_UNUSED int curIdx, \
+ Y_DECLARE_UNUSED TStringBuf cur, \
+ Y_DECLARE_UNUSED TStringBuf prefix, \
+ Y_DECLARE_UNUSED TStringBuf suffix, \
+ Y_DECLARE_UNUSED TStringBuf root)
+
+ /// Launches this binary with a specially formed flags and retrieves completions from stdout.
+ ///
+ /// Your application must be set up in a certain way for this to work.
+ ///
+ /// First, create a custom completer:
+ ///
+ /// ```
+ /// Y_COMPLETER(SomeUniqueName) {
+ /// AddCompletion("foo");
+ /// AddCompletion("bar");
+ /// AddCompletion("baz");
+ /// }
+ /// ```
+ ///
+ /// Then, use it with this function.
+ ///
+ /// On completion attempt, completer will call your binary with some special arguments.
+ ///
+ /// In your main, before any other logic, call `TCustomCompleter::FireCustomCompleter`. This function will
+ /// check for said special arguments and invoke the right completer:
+ ///
+ /// ```
+ /// int main(int argc, const char** argv) {
+ /// TCustomCompleter::FireCustomCompleter(argc, argv);
+ /// ...
+ /// }
+ /// ```
+ ICompleterPtr LaunchSelf(TCustomCompleter& completer);
+
+ /// Launches this binary with a specially formed flags and retrieves completions from stdout.
+ ///
+ /// Your application must be set up in a certain way for this to work. See `LaunchSelf` for more info.
+ ///
+ /// Multipart completion is designed for objects that consist of multiple parts split by a common separator.
+ /// It is ideal for completing remote file paths, for example.
+ ///
+ /// Multipart completers format stdout in the following way.
+ ///
+ /// On the first line, they print a common prefix that should be stripped from all completions. For example,
+ /// if you complete paths, this prefix would be a common directory.
+ ///
+ /// On the second line, they print a separator. If some completion ends with this separator, shell will not add
+ /// a whitespace after the item is completed. For example, if you complete paths, the separator would be a slash.
+ ///
+ /// On the following lines, they print completions, as formed by the `AddCompletion` function.
+ ///
+ /// For example, if a user invokes completion like this:
+ ///
+ /// ```
+ /// $ program //home/logs/<tab><tab>
+ /// ```
+ ///
+ /// The stdout might look like this:
+ ///
+ /// ```
+ /// //home/logs/
+ /// /
+ /// //home/logs/access-log
+ /// //home/logs/redir-log
+ /// //home/logs/blockstat-log
+ /// ```
+ ///
+ /// Then autocompletion will look like this:
+ ///
+ /// ```
+ /// $ program //home/logs/<tab><tab>
+ /// -- yt path --
+ /// access-log redir-log blockstat-log
+ /// ```
+ ///
+ /// Note: stdout lines with completion suggestions *must* be formatted by the `AddCompletion` function
+ /// because their format may change in the future.
+ ///
+ /// Note: we recommend using `Y_MULTIPART_COMPLETER` because it will handle all stdout printing for you.
+ ICompleterPtr LaunchSelfMultiPart(TCustomCompleter& completer);
+}
diff --git a/library/cpp/getopt/small/completer_command.cpp b/library/cpp/getopt/small/completer_command.cpp
new file mode 100644
index 0000000000..5e593eec7e
--- /dev/null
+++ b/library/cpp/getopt/small/completer_command.cpp
@@ -0,0 +1,165 @@
+#include "completer_command.h"
+
+#include "completion_generator.h"
+#include "last_getopt.h"
+#include "wrap.h"
+
+#include <library/cpp/colorizer/colors.h>
+
+#include <util/string/subst.h>
+
+namespace NLastGetopt {
+ TString MakeInfo(TStringBuf command, TStringBuf flag) {
+ TString info = (
+ "This command generates shell script with completion function and prints it to `stdout`, "
+ "allowing one to re-direct the output to the file of their choosing. "
+ "Where you place the file will depend on which shell and operating system you are using."
+ "\n"
+ "\n"
+ "\n"
+ "{B}BASH (Linux){R}:"
+ "\n"
+ "\n"
+ "For system-wide commands, completion files are stored in `/etc/bash_completion.d/`. "
+ "For user commands, they are stored in `~/.local/share/bash-completion/completions`. "
+ "So, pipe output of this script to a file in one of these directories:"
+ "\n"
+ "\n"
+ " $ mkdir -p ~/.local/share/bash-completion/completions"
+ "\n"
+ " $ {command} {completion} bash >"
+ "\n"
+ " ~/.local/share/bash-completion/completions/{command}"
+ "\n"
+ "\n"
+ "You'll need to restart your shell for changes to take effect."
+ "\n"
+ "\n"
+ "\n"
+ "{B}BASH (OSX){R}:"
+ "\n"
+ "\n"
+ "You'll need `bash-completion` (or `bash-completion@2` if you're using non-default, newer bash) "
+ "homebrew formula. Completion files are stored in `/usr/local/etc/bash_completion.d`:"
+ "\n"
+ "\n"
+ " $ mkdir -p $(brew --prefix)/etc/bash_completion.d"
+ "\n"
+ " $ {command} {completion} bash >"
+ "\n"
+ " $(brew --prefix)/etc/bash_completion.d/{command}"
+ "\n"
+ "\n"
+ "Alternatively, just source the script in your `~/.bash_profile`."
+ "\n"
+ "\n"
+ "You'll need to restart your shell for changes to take effect."
+ "\n"
+ "\n"
+ "\n"
+ "{B}ZSH{R}:"
+ "\n"
+ "\n"
+ "Zsh looks for completion scripts in any directory listed in `$fpath` variable. We recommend placing "
+ "completions to `~/.zfunc`:"
+ "\n"
+ "\n"
+ " $ mkdir -p ~/.zfunc"
+ "\n"
+ " $ {command} {completion} zsh > ~/.zfunc/_{command}"
+ "\n"
+ "\n"
+ "Add the following lines to your `.zshrc` just before `compinit`:"
+ "\n"
+ "\n"
+ " fpath+=~/.zfunc"
+ "\n"
+ "\n"
+ "You'll need to restart your shell for changes to take effect.");
+ SubstGlobal(info, "{command}", command);
+ SubstGlobal(info, "{completion}", flag);
+ SubstGlobal(info, "{B}", NColorizer::StdErr().LightDefault());
+ SubstGlobal(info, "{R}", NColorizer::StdErr().Reset());
+ return info;
+ }
+
+ NComp::ICompleterPtr ShellChoiceCompleter() {
+ return NComp::Choice({{"zsh"}, {"bash"}});
+ }
+
+ TOpt MakeCompletionOpt(const TOpts* opts, TString command, TString name) {
+ return TOpt()
+ .AddLongName(name)
+ .Help("generate tab completion script for zsh or bash")
+ .CompletionHelp("generate tab completion script")
+ .OptionalArgument("shell-syntax")
+ .CompletionArgHelp("shell syntax for completion script")
+ .IfPresentDisableCompletion()
+ .Completer(ShellChoiceCompleter())
+ .Handler1T<TString>([opts, command, name](TStringBuf shell) {
+ if (shell.empty()) {
+ Cerr << Wrap(80, MakeInfo(command, "--" + name)) << Endl;
+ } else if (shell == "bash") {
+ TBashCompletionGenerator(opts).Generate(command, Cout);
+ } else if (shell == "zsh") {
+ TZshCompletionGenerator(opts).Generate(command, Cout);
+ } else {
+ Cerr << "Unknown shell name " << TString{shell}.Quote() << Endl;
+ exit(1);
+ }
+ exit(0);
+ });
+ }
+
+ class TCompleterMode: public TMainClassArgs {
+ public:
+ TCompleterMode(const TModChooser* modChooser, TString command, TString modName)
+ : Command_(std::move(command))
+ , Modes_(modChooser)
+ , ModName_(std::move(modName))
+ {
+ }
+
+ protected:
+ void RegisterOptions(NLastGetopt::TOpts& opts) override {
+ TMainClassArgs::RegisterOptions(opts);
+
+ opts.SetTitle("Generate tab completion scripts for zsh or bash");
+
+ opts.AddSection("Description", MakeInfo(Command_, ModName_));
+
+ opts.SetFreeArgsNum(1);
+ opts.GetFreeArgSpec(0)
+ .Title("<shell-syntax>")
+ .Help("shell syntax for completion script (bash or zsh)")
+ .CompletionArgHelp("shell syntax for completion script")
+ .Completer(ShellChoiceCompleter());
+ }
+
+ int DoRun(NLastGetopt::TOptsParseResult&& parsedOptions) override {
+ auto arg = parsedOptions.GetFreeArgs()[0];
+ arg.to_lower();
+
+ if (arg == "bash") {
+ TBashCompletionGenerator(Modes_).Generate(Command_, Cout);
+ } else if (arg == "zsh") {
+ TZshCompletionGenerator(Modes_).Generate(Command_, Cout);
+ } else {
+ Cerr << "Unknown shell name " << arg.Quote() << Endl;
+ parsedOptions.PrintUsage();
+ return 1;
+ }
+
+ return 0;
+ }
+
+ private:
+ TString Command_;
+ const TModChooser* Modes_;
+ TString ModName_;
+ };
+
+ THolder<TMainClassArgs> MakeCompletionMod(const TModChooser* modChooser, TString command, TString modName) {
+ return MakeHolder<TCompleterMode>(modChooser, std::move(command), std::move(modName));
+ }
+}
diff --git a/library/cpp/getopt/small/completer_command.h b/library/cpp/getopt/small/completer_command.h
new file mode 100644
index 0000000000..974cc4617c
--- /dev/null
+++ b/library/cpp/getopt/small/completer_command.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "modchooser.h"
+
+namespace NLastGetopt {
+ /// Create an option that generates completion.
+ TOpt MakeCompletionOpt(const TOpts* opts, TString command, TString optName = "completion");
+
+ /// Create a mode that generates completion.
+ THolder<TMainClassArgs> MakeCompletionMod(const TModChooser* modChooser, TString command, TString modName = "completion");
+}
diff --git a/library/cpp/getopt/small/completion_generator.cpp b/library/cpp/getopt/small/completion_generator.cpp
new file mode 100644
index 0000000000..ac41988217
--- /dev/null
+++ b/library/cpp/getopt/small/completion_generator.cpp
@@ -0,0 +1,791 @@
+#include "completion_generator.h"
+
+#include <util/generic/overloaded.h>
+
+#include <util/string/ascii.h>
+#include <util/generic/hash_set.h>
+
+#include "last_getopt_parse_result.h"
+
+using NLastGetopt::NEscaping::Q;
+using NLastGetopt::NEscaping::QQ;
+using NLastGetopt::NEscaping::C;
+using NLastGetopt::NEscaping::CC;
+using NLastGetopt::NEscaping::S;
+using NLastGetopt::NEscaping::SS;
+using NLastGetopt::NEscaping::B;
+using NLastGetopt::NEscaping::BB;
+
+namespace NLastGetopt {
+
+#define L out.Line()
+#define I auto Y_GENERATE_UNIQUE_ID(indent) = out.Indent()
+
+ TCompletionGenerator::TCompletionGenerator(const TModChooser* modChooser)
+ : Options_(modChooser)
+ {
+ Y_VERIFY(modChooser != nullptr);
+ }
+
+ TCompletionGenerator::TCompletionGenerator(const TOpts* opts)
+ : Options_(opts)
+ {
+ Y_VERIFY(opts != nullptr);
+ }
+
+ void TZshCompletionGenerator::Generate(TStringBuf command, IOutputStream& stream) {
+ TFormattedOutput out;
+ NComp::TCompleterManager manager{command};
+
+ L << "#compdef " << command;
+ L;
+ L << "_" << command << "() {";
+ {
+ I;
+ L << "local state line desc modes context curcontext=\"$curcontext\" ret=1";
+ L << "local words_orig=(\"${words[@]}\")";
+ L << "local current_orig=\"$((CURRENT - 1))\"";
+ L << "local prefix_orig=\"$PREFIX\"";
+ L << "local suffix_orig=\"$SUFFIX\"";
+ L;
+ std::visit(TOverloaded{
+ [&out, &manager](const TModChooser* modChooser) {
+ GenerateModesCompletion(out, *modChooser, manager);
+ },
+ [&out, &manager](const TOpts* opts) {
+ GenerateOptsCompletion(out, *opts, manager);
+ }
+ }, Options_);
+ L;
+ L << "return ret";
+ }
+ L << "}";
+ L;
+ manager.GenerateZsh(out);
+
+ out.Print(stream);
+ }
+
+ void TZshCompletionGenerator::GenerateModesCompletion(TFormattedOutput& out, const TModChooser& chooser, NComp::TCompleterManager& manager) {
+ auto modes = chooser.GetUnsortedModes();
+
+ L << "_arguments -C \\";
+ L << " '(- : *)'{-h,--help}'[show help information]' \\";
+ if (chooser.GetVersionHandler() != nullptr) {
+ L << " '(- : *)'{-v,--version}'[display version information]' \\";
+ }
+ if (!chooser.IsSvnRevisionOptionDisabled()) {
+ L << " '(- : *)--svnrevision[show build information]' \\";
+ }
+ L << " '(-v --version -h --help --svnrevision)1: :->modes' \\";
+ L << " '(-v --version -h --help --svnrevision)*:: :->args' \\";
+ L << " && ret=0";
+ L;
+ L << "case $state in";
+ {
+ I;
+
+ L << "modes)";
+ {
+ I;
+
+ size_t tag = 0;
+ bool empty = true;
+
+ L << "desc='modes'";
+ L << "modes=(";
+ for (auto& mode : modes) {
+ if (mode->Hidden) {
+ continue;
+ }
+ if (!mode->Name.empty()) {
+ I;
+ if (!mode->Description.empty()) {
+ L << QQ(mode->Name) << ":" << QQ(mode->Description);
+ } else {
+ L << QQ(mode->Name);
+ }
+ empty = false;
+ } else {
+ L << ")";
+ if (!empty) {
+ L << "_describe -t 'mode-group-" << tag << "' $desc modes";
+ }
+ L;
+ if (mode->Description.empty()) {
+ L << "desc='modes'";
+ } else {
+ L << "desc=" << SS(mode->Description);
+ }
+ L << "modes=(";
+ empty = true;
+ ++tag;
+ }
+ }
+ L << ")";
+ if (!empty) {
+ L << "_describe -t 'mode-group-" << tag << "' $desc modes";
+ }
+ L;
+
+ L << ";;";
+ }
+
+ L << "args)";
+ {
+ I;
+
+ L << "case $line[1] in";
+ {
+ I;
+
+ for (auto& mode : modes) {
+ if (mode->Name.empty() || mode->Hidden) {
+ continue;
+ }
+
+ auto& line = L << SS(mode->Name);
+ for (auto& alias : mode->Aliases) {
+ line << "|" << SS(alias);
+ }
+ line << ")";
+
+ {
+ I;
+
+ if (auto mainArgs = dynamic_cast<TMainClassArgs*>(mode->Main)) {
+ GenerateOptsCompletion(out, mainArgs->GetOptions(), manager);
+ } else if (auto mainModes = dynamic_cast<TMainClassModes*>(mode->Main)) {
+ GenerateModesCompletion(out, mainModes->GetSubModes(), manager);
+ } else {
+ GenerateDefaultOptsCompletion(out, manager);
+ }
+
+ L << ";;";
+ }
+ }
+ }
+ L << "esac";
+ L << ";;";
+ }
+ }
+ L << "esac";
+ }
+
+ void TZshCompletionGenerator::GenerateOptsCompletion(TFormattedOutput& out, const TOpts& opts, NComp::TCompleterManager& manager) {
+ L << "_arguments -s \\";
+ {
+ I;
+
+ if (opts.ArgPermutation_ == EArgPermutation::REQUIRE_ORDER) {
+ L << "-S \\";
+ }
+
+ for (auto opt: opts.GetOpts()) {
+ if (!opt->Hidden_) {
+ GenerateOptCompletion(out, opts, *opt, manager);
+ }
+ }
+
+ auto argSpecs = opts.GetFreeArgSpecs();
+ size_t numFreeArgs = opts.GetFreeArgsMax();
+ bool unlimitedArgs = false;
+ if (numFreeArgs == TOpts::UNLIMITED_ARGS) {
+ numFreeArgs = argSpecs.empty() ? 0 : (argSpecs.rbegin()->first + 1);
+ unlimitedArgs = true;
+ }
+
+ for (size_t i = 0; i < numFreeArgs; ++i) {
+ auto& spec = argSpecs[i];
+ auto& line = L << "'" << (i + 1) << ":";
+ if (spec.IsOptional()) {
+ line << ":";
+ }
+ auto argHelp = spec.GetCompletionArgHelp(opts.GetDefaultFreeArgTitle());
+ if (argHelp) {
+ line << Q(argHelp);
+ } else {
+ line << " ";
+ }
+ line << ":";
+ if (spec.Completer_) {
+ line << spec.Completer_->GenerateZshAction(manager);
+ } else {
+ line << "_default";
+ }
+ line << "' \\";
+ }
+
+ if (unlimitedArgs) {
+ auto& spec = opts.GetTrailingArgSpec();
+ auto& line = L << "'*:";
+ auto argHelp = spec.GetCompletionArgHelp(opts.GetDefaultFreeArgTitle());
+ if (argHelp) {
+ line << Q(argHelp);
+ } else {
+ line << " ";
+ }
+ line << ":";
+ if (spec.Completer_) {
+ line << spec.Completer_->GenerateZshAction(manager);
+ } else {
+ line << "_default";
+ }
+ line << "' \\";
+ }
+
+ L << "&& ret=0";
+ }
+ }
+
+ void TZshCompletionGenerator::GenerateDefaultOptsCompletion(TFormattedOutput& out, NComp::TCompleterManager&) {
+ L << "_arguments \\";
+ L << " '(- *)'{-h,--help}'[show help information]' \\";
+ L << " '(- *)--svnrevision[show build information]' \\";
+ L << " '(-h --help --svnrevision)*: :_files' \\";
+ L << " && ret=0";
+ }
+
+ void TZshCompletionGenerator::GenerateOptCompletion(TFormattedOutput& out, const TOpts& opts, const TOpt& opt, NComp::TCompleterManager& manager) {
+ auto& line = L;
+
+ THashSet<TString> disableOptions;
+ if (opt.DisableCompletionForOptions_) {
+ disableOptions.insert("-");
+ } else {
+ if (!opt.AllowMultipleCompletion_) {
+ for (auto shortName: opt.GetShortNames()) {
+ disableOptions.insert(TString("-") + shortName);
+ }
+ for (auto& longName: opt.GetLongNames()) {
+ disableOptions.insert("--" + longName);
+ }
+ }
+ for (auto disabledShortName : opt.DisableCompletionForChar_) {
+ auto disabledOpt = opts.FindCharOption(disabledShortName);
+ if (disabledOpt) {
+ for (auto shortName: disabledOpt->GetShortNames()) {
+ disableOptions.insert(TString("-") + shortName);
+ }
+ for (auto& longName: disabledOpt->GetLongNames()) {
+ disableOptions.insert("--" + longName);
+ }
+ } else {
+ disableOptions.insert(TString("-") + disabledShortName);
+ }
+ }
+ for (auto& disabledLongName : opt.DisableCompletionForLongName_) {
+ auto disabledOpt = opts.FindLongOption(disabledLongName);
+ if (disabledOpt) {
+ for (auto shortName: disabledOpt->GetShortNames()) {
+ disableOptions.insert(TString("-") + shortName);
+ }
+ for (auto& longName: disabledOpt->GetLongNames()) {
+ disableOptions.insert("--" + longName);
+ }
+ } else {
+ disableOptions.insert("--" + disabledLongName);
+ }
+ }
+ }
+ if (opt.DisableCompletionForFreeArgs_) {
+ disableOptions.insert(":");
+ disableOptions.insert("*");
+ } else {
+ for (auto i : opt.DisableCompletionForFreeArg_) {
+ disableOptions.insert(ToString(i + 1));
+ }
+ }
+
+ TStringBuf sep = "";
+
+ if (!disableOptions.empty()) {
+ line << "'(";
+ for (auto& disableOption : disableOptions) {
+ line << sep << disableOption;
+ sep = " ";
+ }
+ line << ")";
+ }
+
+ sep = "";
+ TStringBuf mul = "";
+ TStringBuf quot = "";
+
+ if (opt.GetShortNames().size() + opt.GetLongNames().size() > 1) {
+ if (!disableOptions.empty()) {
+ line << "'";
+ }
+ line << "{";
+ quot = "'";
+ } else {
+ if (disableOptions.empty()) {
+ line << "'";
+ }
+ }
+
+ if (opt.AllowMultipleCompletion_) {
+ mul = "*";
+ }
+
+ for (auto& flag : opt.GetShortNames()) {
+ line << sep << quot << mul << "-" << Q(TStringBuf(&flag, 1)) << quot;
+ sep = ",";
+ }
+
+ for (auto& flag : opt.GetLongNames()) {
+ line << sep << quot << mul << "--" << Q(flag) << quot;
+ sep = ",";
+ }
+
+ if (opt.GetShortNames().size() + opt.GetLongNames().size() > 1) {
+ line << "}'";
+ }
+
+ if (opt.GetCompletionHelp()) {
+ line << "[";
+ line << Q(opt.GetCompletionHelp());
+ line << "]";
+ }
+
+ if (opt.HasArg_ != EHasArg::NO_ARGUMENT) {
+ if (opt.HasArg_ == EHasArg::OPTIONAL_ARGUMENT) {
+ line << ":";
+ }
+
+ line << ":";
+
+ if (opt.GetCompletionArgHelp()) {
+ line << C(opt.GetCompletionArgHelp());
+ } else {
+ line << " ";
+ }
+
+ line << ":";
+
+ if (opt.Completer_) {
+ line << C(opt.Completer_->GenerateZshAction(manager));
+ } else {
+ line << "_default";
+ }
+ }
+
+ line << "' \\";
+ }
+
+ void TBashCompletionGenerator::Generate(TStringBuf command, IOutputStream& stream) {
+ TFormattedOutput out;
+ NComp::TCompleterManager manager{command};
+
+ L << "_" << command << "() {";
+ {
+ I;
+ L << "COMPREPLY=()";
+ L;
+ L << "local i args opts items candidates";
+ L;
+ L << "local cur prev words cword";
+ L << "_get_comp_words_by_ref -n \"\\\"'><=;|&(:\" cur prev words cword";
+ L;
+ L << "local need_space=\"1\"";
+ L << "local IFS=$' \\t\\n'";
+ L;
+ std::visit(TOverloaded{
+ [&out, &manager](const TModChooser* modChooser) {
+ GenerateModesCompletion(out, *modChooser, manager, 1);
+ },
+ [&out, &manager](const TOpts* opts) {
+ GenerateOptsCompletion(out, *opts, manager, 1);
+ }
+ }, Options_);
+ L;
+ L;
+ L << "__ltrim_colon_completions \"$cur\"";
+ L;
+ L << "IFS=$'\\n'";
+ L << "if [ ${#COMPREPLY[@]} -ne 0 ]; then";
+ {
+ I;
+ L << "if [[ -z $need_space ]]; then";
+ {
+ I;
+ L << "COMPREPLY=( $(printf \"%q\\n\" \"${COMPREPLY[@]}\") )";
+ }
+ L << "else";
+ {
+ I;
+ L << "COMPREPLY=( $(printf \"%q \\n\" \"${COMPREPLY[@]}\") )";
+ }
+ L << "fi";
+ }
+ L << "fi";
+ L;
+ L << "return 0";
+ }
+ L << "}";
+ L;
+ L << "complete -o nospace -o default -F _" << command << " " << command;
+
+ out.Print(stream);
+ }
+
+ void TBashCompletionGenerator::GenerateModesCompletion(TFormattedOutput& out, const TModChooser& chooser, NComp::TCompleterManager& manager, size_t level) {
+ auto modes = chooser.GetUnsortedModes();
+
+ L << "if [[ ${cword} == " << level << " ]] ; then";
+ {
+ I;
+ L << "if [[ ${cur} == -* ]] ; then";
+ {
+ I;
+ auto& line = L << "COMPREPLY+=( $(compgen -W '-h --help";
+ if (chooser.GetVersionHandler() != nullptr) {
+ line << " -v --version";
+ }
+ if (!chooser.IsSvnRevisionOptionDisabled()) {
+ line << " --svnrevision";
+ }
+ line << "' -- ${cur}) )";
+ }
+ L << "else";
+ {
+ I;
+ auto& line = L << "COMPREPLY+=( $(compgen -W '";
+ TStringBuf sep = "";
+ for (auto& mode : modes) {
+ if (!mode->Hidden && !mode->NoCompletion) {
+ line << sep << B(mode->Name);
+ sep = " ";
+ }
+ }
+ line << "' -- ${cur}) )";
+ }
+ L << "fi";
+ }
+ L << "else";
+ {
+ I;
+ L << "case \"${words[" << level << "]}\" in";
+ {
+ I;
+
+ for (auto& mode : modes) {
+ if (mode->Name.empty() || mode->Hidden || mode->NoCompletion) {
+ continue;
+ }
+
+ auto& line = L << BB(mode->Name);
+ for (auto& alias : mode->Aliases) {
+ line << "|" << BB(alias);
+ }
+ line << ")";
+
+ {
+ I;
+
+ if (auto mainArgs = dynamic_cast<TMainClassArgs*>(mode->Main)) {
+ GenerateOptsCompletion(out, mainArgs->GetOptions(), manager, level + 1);
+ } else if (auto mainModes = dynamic_cast<TMainClassModes*>(mode->Main)) {
+ GenerateModesCompletion(out, mainModes->GetSubModes(), manager, level + 1);
+ } else {
+ GenerateDefaultOptsCompletion(out, manager);
+ }
+
+ L << ";;";
+ }
+ }
+ }
+ L << "esac";
+ }
+ L << "fi";
+ }
+
+ void TBashCompletionGenerator::GenerateOptsCompletion(TFormattedOutput& out, const TOpts& opts, NComp::TCompleterManager&, size_t level) {
+ auto unorderedOpts = opts.GetOpts();
+
+ L << "if [[ ${cur} == -* ]] ; then";
+ {
+ I;
+ auto& line = L << "COMPREPLY+=( $(compgen -W '";
+ TStringBuf sep = "";
+ for (auto& opt : unorderedOpts) {
+ if (opt->IsHidden()) {
+ continue;
+ }
+
+ for (auto& shortName : opt->GetShortNames()) {
+ line << sep << "-" << B(TStringBuf(&shortName, 1));
+ sep = " ";
+ }
+ for (auto& longName: opt->GetLongNames()) {
+ line << sep << "--" << B(longName);
+ sep = " ";
+ }
+ }
+ line << "' -- ${cur}) )";
+ }
+ L << "else";
+ {
+ I;
+ L << "case ${prev} in";
+ {
+ I;
+ for (auto& opt : unorderedOpts) {
+ if (opt->HasArg_ == EHasArg::NO_ARGUMENT || opt->IsHidden()) {
+ continue;
+ }
+
+ auto& line = L;
+ TStringBuf sep = "";
+ for (auto& shortName : opt->GetShortNames()) {
+ line << sep << "'-" << B(TStringBuf(&shortName, 1)) << "'";
+ sep = "|";
+ }
+ for (auto& longName: opt->GetLongNames()) {
+ line << sep << "'--" << B(longName) << "'";
+ sep = "|";
+ }
+ line << ")";
+ {
+ I;
+ if (opt->Completer_ != nullptr) {
+ opt->Completer_->GenerateBash(out);
+ }
+ L << ";;";
+ }
+ }
+
+ L << "*)";
+ {
+ I;
+
+ L << "args=0";
+ auto& line = L << "opts='@(";
+ TStringBuf sep = "";
+ for (auto& opt : unorderedOpts) {
+ if (opt->HasArg_ == EHasArg::NO_ARGUMENT || opt->IsHidden()) {
+ continue;
+ }
+ for (auto& shortName : opt->GetShortNames()) {
+ line << sep << "-" << B(TStringBuf(&shortName, 1));
+ sep = "|";
+ }
+ for (auto& longName: opt->GetLongNames()) {
+ line << sep << "--" << B(longName);
+ sep = "|";
+ }
+ }
+ line << ")'";
+ L << "for (( i=" << level << "; i < cword; i++ )); do";
+ {
+ I;
+ L << "if [[ ${words[i]} != -* && ${words[i-1]} != $opts ]]; then";
+ {
+ I;
+ L << "(( args++ ))";
+ }
+ L << "fi";
+ }
+ L << "done";
+ L;
+
+ auto argSpecs = opts.GetFreeArgSpecs();
+ size_t numFreeArgs = opts.GetFreeArgsMax();
+ bool unlimitedArgs = false;
+ if (numFreeArgs == TOpts::UNLIMITED_ARGS) {
+ numFreeArgs = argSpecs.empty() ? 0 : (argSpecs.rbegin()->first + 1);
+ unlimitedArgs = true;
+ }
+
+ L << "case ${args} in";
+ {
+ I;
+
+ for (size_t i = 0; i < numFreeArgs; ++i) {
+ L << i << ")";
+ {
+ I;
+ auto& spec = argSpecs[i];
+ if (spec.Completer_ != nullptr) {
+ spec.Completer_->GenerateBash(out);
+ }
+ L << ";;";
+ }
+ }
+ if (unlimitedArgs) {
+ L << "*)";
+ {
+ I;
+ auto& spec = opts.GetTrailingArgSpec();
+ if (spec.Completer_ != nullptr) {
+ spec.Completer_->GenerateBash(out);
+ }
+ L << ";;";
+ }
+ }
+ }
+ L << "esac";
+ L << ";;";
+ }
+ }
+ L << "esac";
+ }
+ L << "fi";
+ }
+
+ void TBashCompletionGenerator::GenerateDefaultOptsCompletion(TFormattedOutput& out, NComp::TCompleterManager&) {
+ L << "if [[ ${cur} == -* ]] ; then";
+ {
+ I;
+ L << "COMPREPLY+=( $(compgen -W '-h --help --svnrevision' -- ${cur}) )";
+ }
+ L << "fi";
+ }
+
+#undef I
+#undef L
+
+ TString NEscaping::Q(TStringBuf string) {
+ TStringBuilder out;
+ out.reserve(string.size());
+ for (auto c: string) {
+ switch (c) {
+ case '\a':
+ case '\b':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ case '\v':
+ out << " ";
+ break;
+ case '\\':
+ out << "\\\\";
+ break;
+ case '\'':
+ out << "''";
+ break;
+ case '\"':
+ out << "\\\"";
+ break;
+ case '[':
+ out << "\\[";
+ break;
+ case ']':
+ out << "\\]";
+ break;
+ case ':':
+ out << "\\:";
+ break;
+ case '+':
+ out << "\\+";
+ break;
+ case '=':
+ out << "\\=";
+ break;
+ default:
+ out << c;
+ break;
+ }
+ }
+ return out;
+ }
+
+ TString NEscaping::QQ(TStringBuf string) {
+ auto q = Q(string);
+ return "'" + q + "'";
+ }
+
+ TString NEscaping::C(TStringBuf string) {
+ TStringBuilder out;
+ out.reserve(string.size() + 1);
+ for (auto c: string) {
+ switch (c) {
+ case '\a':
+ case '\b':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ case '\v':
+ out << " ";
+ break;
+ case '\'':
+ out << "''";
+ break;
+ case ':':
+ out << "\\:";
+ break;
+ default:
+ out << c;
+ break;
+ }
+ }
+ return out;
+ }
+
+ TString NEscaping::CC(TStringBuf string) {
+ auto c = C(string);
+ return "'" + c + "'";
+ }
+
+ TString NEscaping::S(TStringBuf string) {
+ TStringBuilder out;
+ out.reserve(string.size() + 1);
+ for (auto c: string) {
+ switch (c) {
+ case '\a':
+ case '\b':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ case '\v':
+ out << " ";
+ break;
+ case '\'':
+ out << "''";
+ break;
+ default:
+ out << c;
+ break;
+ }
+ }
+ return out;
+ }
+
+ TString NEscaping::SS(TStringBuf string) {
+ auto s = S(string);
+ return "'" + s + "'";
+ }
+
+ TString NEscaping::B(TStringBuf string) {
+ TStringBuilder out;
+ out.reserve(string.size() + 1);
+ for (auto c: string) {
+ switch (c) {
+ case '\a':
+ case '\b':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ case '\v':
+ out << " ";
+ break;
+ case '\'':
+ out << "'\"'\"'";
+ break;
+ default:
+ out << c;
+ break;
+ }
+ }
+ return out;
+ }
+
+ TString NEscaping::BB(TStringBuf string) {
+ auto b = B(string);
+ return "'" + b + "'";
+ }
+}
diff --git a/library/cpp/getopt/small/completion_generator.h b/library/cpp/getopt/small/completion_generator.h
new file mode 100644
index 0000000000..4241bb7d6c
--- /dev/null
+++ b/library/cpp/getopt/small/completion_generator.h
@@ -0,0 +1,69 @@
+#pragma once
+
+#include "completer.h"
+#include "formatted_output.h"
+#include "last_getopt_opts.h"
+#include "modchooser.h"
+
+#include <util/generic/variant.h>
+#include <util/string/builder.h>
+
+namespace NLastGetopt {
+ class TCompletionGenerator {
+ public:
+ explicit TCompletionGenerator(const TModChooser* modChooser);
+ explicit TCompletionGenerator(const TOpts* opts);
+ virtual ~TCompletionGenerator() = default;
+
+ public:
+ virtual void Generate(TStringBuf command, IOutputStream& stream) = 0;
+
+ protected:
+ std::variant<const TModChooser*, const TOpts*> Options_;
+ };
+
+ class TZshCompletionGenerator: public TCompletionGenerator {
+ public:
+ using TCompletionGenerator::TCompletionGenerator;
+
+ public:
+ void Generate(TStringBuf command, IOutputStream& stream) override;
+
+ private:
+ static void GenerateModesCompletion(TFormattedOutput& out, const TModChooser& chooser, NComp::TCompleterManager& manager);
+ static void GenerateOptsCompletion(TFormattedOutput& out, const TOpts& opts, NComp::TCompleterManager& manager);
+ static void GenerateDefaultOptsCompletion(TFormattedOutput& out, NComp::TCompleterManager& manager);
+ static void GenerateOptCompletion(TFormattedOutput& out, const TOpts& opts, const TOpt& opt, NComp::TCompleterManager& manager);
+ };
+
+ class TBashCompletionGenerator: public TCompletionGenerator {
+ public:
+ using TCompletionGenerator::TCompletionGenerator;
+
+ public:
+ void Generate(TStringBuf command, IOutputStream& stream) override;
+
+ private:
+ static void GenerateModesCompletion(TFormattedOutput& out, const TModChooser& chooser, NComp::TCompleterManager& manager, size_t level);
+ static void GenerateOptsCompletion(TFormattedOutput& out, const TOpts& opts, NComp::TCompleterManager& manager, size_t level);
+ static void GenerateDefaultOptsCompletion(TFormattedOutput& out, NComp::TCompleterManager& manager);
+ };
+
+ namespace NEscaping {
+ /// Escape ':', '-', '=', '[', ']' for use in zsh _arguments
+ TString Q(TStringBuf string);
+ TString QQ(TStringBuf string);
+
+ /// Escape colons for use in zsh _alternative and _arguments
+ TString C(TStringBuf string);
+ TString CC(TStringBuf string);
+
+ /// Simple escape for use in zsh single-quoted strings
+ TString S(TStringBuf string);
+ TString SS(TStringBuf string);
+
+ /// Simple escape for use in bash single-quoted strings
+ TString B(TStringBuf string);
+ TString BB(TStringBuf string);
+ }
+}
diff --git a/library/cpp/getopt/small/formatted_output.cpp b/library/cpp/getopt/small/formatted_output.cpp
new file mode 100644
index 0000000000..bf1b366f25
--- /dev/null
+++ b/library/cpp/getopt/small/formatted_output.cpp
@@ -0,0 +1,36 @@
+#include "formatted_output.h"
+
+namespace NLastGetopt {
+
+ TFormattedOutput::IndentGuard::IndentGuard(TFormattedOutput* output)
+ : Output(output)
+ {
+ Output->IndentLevel_ += 2;
+ }
+
+ TFormattedOutput::IndentGuard::~IndentGuard() {
+ Output->IndentLevel_ -= 2;
+ }
+
+ TFormattedOutput::IndentGuard TFormattedOutput::Indent() {
+ return IndentGuard(this);
+ }
+
+ TStringBuilder& TFormattedOutput::Line() {
+ return Lines_.emplace_back(IndentLevel_, TStringBuilder()).second;
+ }
+
+ void TFormattedOutput::Print(IOutputStream& out) {
+ for (auto&[indent, line] : Lines_) {
+ if (indent && !line.empty()) {
+ TTempBuf buf(indent);
+ Fill(buf.Data(), buf.Data() + indent, ' ');
+ out.Write(buf.Data(), indent);
+ }
+ out << line;
+ if (!line.EndsWith('\n')) {
+ out << Endl;
+ }
+ }
+ }
+}
diff --git a/library/cpp/getopt/small/formatted_output.h b/library/cpp/getopt/small/formatted_output.h
new file mode 100644
index 0000000000..6fd16b73f9
--- /dev/null
+++ b/library/cpp/getopt/small/formatted_output.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <util/generic/algorithm.h>
+#include <util/generic/vector.h>
+#include <util/string/builder.h>
+#include <util/memory/tempbuf.h>
+
+namespace NLastGetopt {
+ /// Utility for printing indented lines. Used by completion generators.
+ class TFormattedOutput {
+ public:
+ struct IndentGuard {
+ explicit IndentGuard(TFormattedOutput* output);
+ virtual ~IndentGuard();
+ TFormattedOutput* Output;
+ };
+
+ public:
+ /// Increase indentation and return a RAII object that'll decrease it back automatically.
+ IndentGuard Indent();
+
+ /// Append a new indented line to the stream.
+ TStringBuilder& Line();
+
+ /// Collect all lines into a stream.
+ void Print(IOutputStream& out);
+
+ private:
+ int IndentLevel_ = 0;
+ TVector<std::pair<int, TStringBuilder>> Lines_;
+ };
+}
diff --git a/library/cpp/getopt/small/last_getopt.cpp b/library/cpp/getopt/small/last_getopt.cpp
new file mode 100644
index 0000000000..30669b2c5a
--- /dev/null
+++ b/library/cpp/getopt/small/last_getopt.cpp
@@ -0,0 +1,9 @@
+#include "last_getopt.h"
+
+namespace NLastGetopt {
+ void PrintUsageAndExit(const TOptsParser* parser) {
+ parser->PrintUsage();
+ exit(0);
+ }
+
+}
diff --git a/library/cpp/getopt/small/last_getopt.h b/library/cpp/getopt/small/last_getopt.h
new file mode 100644
index 0000000000..07687bc914
--- /dev/null
+++ b/library/cpp/getopt/small/last_getopt.h
@@ -0,0 +1,132 @@
+#pragma once
+
+#include "last_getopt_opts.h"
+#include "last_getopt_easy_setup.h"
+#include "last_getopt_parse_result.h"
+
+#include <util/generic/function.h>
+#include <util/string/split.h>
+
+/// see some documentation in
+/// https://wiki.yandex-team.ru/development/poisk/arcadia/util/lastgetopt/
+/// https://wiki.yandex-team.ru/development/poisk/arcadia/library/getopt/
+/// see examples in library/cpp/getopt/last_getopt_demo
+
+//TODO: in most cases this include is unnecessary, but needed THandlerFunctor1<TpFunc, TpArg>::HandleOpt
+#include "last_getopt_parser.h"
+
+namespace NLastGetopt {
+ /// Handler to split option value by delimiter into a target container and allow ranges.
+ template <class Container>
+ struct TOptRangeSplitHandler: public IOptHandler {
+ public:
+ using TContainer = Container;
+ using TValue = typename TContainer::value_type;
+
+ explicit TOptRangeSplitHandler(TContainer* target, const char elementsDelim, const char rangesDelim)
+ : Target(target)
+ , ElementsDelim(elementsDelim)
+ , RangesDelim(rangesDelim)
+ {
+ }
+
+ void HandleOpt(const TOptsParser* parser) override {
+ const TStringBuf curval(parser->CurValOrDef());
+ if (curval.IsInited()) {
+ StringSplitter(curval).Split(ElementsDelim).Consume([&](const TStringBuf& val) {
+ TStringBuf mutableValue = val;
+
+ TValue first = NPrivate::OptFromString<TValue>(mutableValue.NextTok(RangesDelim), parser->CurOpt());
+ TValue last = mutableValue ? NPrivate::OptFromString<TValue>(mutableValue, parser->CurOpt()) : first;
+
+ if (last < first) {
+ throw TUsageException() << "failed to parse opt " << NPrivate::OptToString(parser->CurOpt()) << " value " << TString(val).Quote() << ": the second argument is less than the first one";
+ }
+
+ for (++last; first < last; ++first) {
+ Target->insert(Target->end(), first);
+ }
+ });
+ }
+ }
+
+ private:
+ TContainer* Target;
+ char ElementsDelim;
+ char RangesDelim;
+ };
+
+ template <class Container>
+ struct TOptSplitHandler: public IOptHandler {
+ public:
+ using TContainer = Container;
+ using TValue = typename TContainer::value_type;
+
+ explicit TOptSplitHandler(TContainer* target, const char delim)
+ : Target(target)
+ , Delim(delim)
+ {
+ }
+
+ void HandleOpt(const TOptsParser* parser) override {
+ const TStringBuf curval(parser->CurValOrDef());
+ if (curval.IsInited()) {
+ StringSplitter(curval).Split(Delim).Consume([&](const TStringBuf& val) {
+ Target->insert(Target->end(), NPrivate::OptFromString<TValue>(val, parser->CurOpt()));
+ });
+ }
+ }
+
+ private:
+ TContainer* Target;
+ char Delim;
+ };
+
+ template <class TpFunc>
+ struct TOptKVHandler: public IOptHandler {
+ public:
+ using TKey = typename TFunctionArgs<TpFunc>::template TGet<0>;
+ using TValue = typename TFunctionArgs<TpFunc>::template TGet<1>;
+
+ explicit TOptKVHandler(TpFunc func, const char kvdelim = '=')
+ : Func(func)
+ , KVDelim(kvdelim)
+ {
+ }
+
+ void HandleOpt(const TOptsParser* parser) override {
+ const TStringBuf curval(parser->CurValOrDef());
+ const TOpt* curOpt(parser->CurOpt());
+ if (curval.IsInited()) {
+ TStringBuf key, value;
+ if (!curval.TrySplit(KVDelim, key, value)) {
+ throw TUsageException() << "failed to parse opt " << NPrivate::OptToString(curOpt)
+ << " value " << TString(curval).Quote() << ": expected key" << KVDelim << "value format";
+ }
+ Func(NPrivate::OptFromString<TKey>(key, curOpt), NPrivate::OptFromString<TValue>(value, curOpt));
+ }
+ }
+
+ private:
+ TpFunc Func;
+ char KVDelim;
+ };
+
+ namespace NPrivate {
+ template <typename TpFunc, typename TpArg>
+ void THandlerFunctor1<TpFunc, TpArg>::HandleOpt(const TOptsParser* parser) {
+ const TStringBuf curval = parser->CurValOrDef(!HasDef_);
+ const TpArg& arg = curval.IsInited() ? OptFromString<TpArg>(curval, parser->CurOpt()) : Def_;
+ try {
+ Func_(arg);
+ } catch (const TUsageException&) {
+ throw;
+ } catch (...) {
+ throw TUsageException() << "failed to handle opt " << OptToString(parser->CurOpt())
+ << " value " << TString(curval).Quote() << ": " << CurrentExceptionMessage();
+ }
+ }
+
+ }
+
+}
diff --git a/library/cpp/getopt/small/last_getopt_easy_setup.cpp b/library/cpp/getopt/small/last_getopt_easy_setup.cpp
new file mode 100644
index 0000000000..c87dedf95e
--- /dev/null
+++ b/library/cpp/getopt/small/last_getopt_easy_setup.cpp
@@ -0,0 +1,47 @@
+#include "last_getopt_easy_setup.h"
+
+namespace NLastGetopt {
+ TEasySetup::TEasySetup(const TStringBuf& optstring)
+ : TOpts(optstring)
+ {
+ AddHelpOption();
+ }
+
+ TOpt& TEasySetup::AdjustParam(const char* longName, const char* help, const char* argName, bool required) {
+ Y_ASSERT(longName);
+ TOpt& o = AddLongOption(longName);
+ if (help) {
+ o.Help(help);
+ }
+ if (argName) {
+ o.RequiredArgument(argName);
+ } else {
+ o.HasArg(NO_ARGUMENT);
+ }
+ if (required) {
+ o.Required();
+ }
+ return o;
+ }
+
+ TEasySetup& TEasySetup::operator()(char shortName, const char* longName, const char* help, bool required) {
+ AdjustParam(longName, help, nullptr, required).AddShortName(shortName);
+ return *this;
+ }
+
+ TEasySetup& TEasySetup::operator()(char shortName, const char* longName, const char* argName, const char* help, bool required) {
+ AdjustParam(longName, help, argName, required).AddShortName(shortName);
+ return *this;
+ }
+
+ TEasySetup& TEasySetup::operator()(const char* longName, const char* help, bool required) {
+ AdjustParam(longName, help, nullptr, required);
+ return *this;
+ }
+
+ TEasySetup& TEasySetup::operator()(const char* longName, const char* argName, const char* help, bool required) {
+ AdjustParam(longName, help, argName, required);
+ return *this;
+ }
+
+}
diff --git a/library/cpp/getopt/small/last_getopt_easy_setup.h b/library/cpp/getopt/small/last_getopt_easy_setup.h
new file mode 100644
index 0000000000..60dddda225
--- /dev/null
+++ b/library/cpp/getopt/small/last_getopt_easy_setup.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include "last_getopt_opts.h"
+
+namespace NLastGetopt {
+ /**
+ * Wrapper for TOpts class to make the life a bit easier.
+ * Usual usage:
+ * TEasySetup opts;
+ * opts('s', "server", "MR_SERVER", "MapReduce server name in format server:port", true)
+ * ('u', "user", "MR_USER", "MapReduce user name", true)
+ * ('o', "output", "MR_TABLE", "Name of MR table which will contain results", true)
+ * ('r', "rules", "FILE", "Filename for .rules output file") //!< This parameter is optional and has a required argument
+ * ('v', "version", &PrintSvnVersionAndExit0, "Print version information") //!< Parameter with handler can't get any argument
+ * ("verbose", "Be verbose") //!< You may not specify short param name
+ *
+ * NLastGetopt::TOptsParseResult r(&opts, argc, argv);
+ */
+ class TEasySetup: public TOpts {
+ public:
+ TEasySetup(const TStringBuf& optstring = TStringBuf());
+ TEasySetup& operator()(char shortName, const char* longName, const char* help, bool required = false);
+ TEasySetup& operator()(char shortName, const char* longName, const char* argName, const char* help, bool required = false);
+
+ template <class TpFunc>
+ TEasySetup& operator()(char shortName, const char* longName, TpFunc handler, const char* help, bool required = false) {
+ AdjustParam(longName, help, nullptr, handler, required).AddShortName(shortName);
+ return *this;
+ }
+
+ TEasySetup& operator()(const char* longName, const char* help, bool required = false);
+ TEasySetup& operator()(const char* longName, const char* argName, const char* help, bool required = false);
+
+ template <class TpFunc>
+ TEasySetup& operator()(const char* longName, TpFunc handler, const char* help, bool required = false) {
+ AdjustParam(longName, help, nullptr, handler, required);
+ return *this;
+ }
+
+ private:
+ TOpt& AdjustParam(const char* longName, const char* help, const char* argName, bool required);
+
+ template <class TpFunc>
+ TOpt& AdjustParam(const char* longName, const char* help, const char* argName, TpFunc handler, bool required) {
+ TOpt& o = AdjustParam(longName, help, argName, required);
+ o.Handler0(handler);
+ return o;
+ }
+ };
+
+}
diff --git a/library/cpp/getopt/small/last_getopt_handlers.h b/library/cpp/getopt/small/last_getopt_handlers.h
new file mode 100644
index 0000000000..d35456ef34
--- /dev/null
+++ b/library/cpp/getopt/small/last_getopt_handlers.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "last_getopt_support.h"
+
+#include <util/string/split.h>
+#include <util/system/compiler.h>
+
+namespace NLastGetopt {
+ /// Handler to split option value by delimiter into a target container.
+ template <class Container>
+ struct TOptSplitHandler;
+
+ /// Handler to split option value by delimiter into a target container and allow ranges.
+ template <class Container>
+ struct TOptRangeSplitHandler;
+
+ /// Handler to parse key-value pairs (default delimiter is '=') and apply user-supplied handler to each pair
+ template <class TpFunc>
+ struct TOptKVHandler;
+
+ [[noreturn]] void PrintUsageAndExit(const TOptsParser* parser);
+ [[noreturn]] void PrintVersionAndExit(const TOptsParser* parser);
+ [[noreturn]] void PrintShortVersionAndExit(const TString& appName);
+}
diff --git a/library/cpp/getopt/small/last_getopt_opt.cpp b/library/cpp/getopt/small/last_getopt_opt.cpp
new file mode 100644
index 0000000000..9a99437f4b
--- /dev/null
+++ b/library/cpp/getopt/small/last_getopt_opt.cpp
@@ -0,0 +1,113 @@
+#include "last_getopt_opt.h"
+
+#include <util/stream/format.h>
+#include <util/string/escape.h>
+#include <util/generic/ylimits.h>
+#include <util/generic/utility.h>
+#include <util/generic/algorithm.h>
+#include <ctype.h>
+
+namespace NLastGetopt {
+ static const TStringBuf ExcludedShortNameChars = "= -\t\n";
+ static const TStringBuf ExcludedLongNameChars = "= \t\n";
+
+ bool TOpt::NameIs(const TString& name) const {
+ for (const auto& next : LongNames_) {
+ if (next == name)
+ return true;
+ }
+ return false;
+ }
+
+ bool TOpt::CharIs(char c) const {
+ for (auto next : Chars_) {
+ if (next == c)
+ return true;
+ }
+ return false;
+ }
+
+ char TOpt::GetChar() const {
+ ;
+ if (Chars_.empty())
+ ythrow TConfException() << "no char for option " << this->ToShortString();
+ return Chars_.at(0);
+ }
+
+ char TOpt::GetCharOr0() const {
+ if (Chars_.empty())
+ return 0;
+ return GetChar();
+ }
+
+ TString TOpt::GetName() const {
+ ;
+ if (LongNames_.empty())
+ ythrow TConfException() << "no name for option " << this->ToShortString();
+ return LongNames_.at(0);
+ }
+
+ bool TOpt::IsAllowedShortName(unsigned char c) {
+ return isprint(c) && TStringBuf::npos == ExcludedShortNameChars.find(c);
+ }
+
+ TOpt& TOpt::AddShortName(unsigned char c) {
+ ;
+ if (!IsAllowedShortName(c))
+ throw TUsageException() << "option char '" << c << "' is not allowed";
+ Chars_.push_back(c);
+ return *this;
+ }
+
+ bool TOpt::IsAllowedLongName(const TString& name, unsigned char* out) {
+ for (size_t i = 0; i != name.size(); ++i) {
+ const unsigned char c = name[i];
+ if (!isprint(c) || TStringBuf::npos != ExcludedLongNameChars.find(c)) {
+ if (nullptr != out)
+ *out = c;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ TOpt& TOpt::AddLongName(const TString& name) {
+ ;
+ unsigned char c = 0;
+ if (!IsAllowedLongName(name, &c))
+ throw TUsageException() << "option char '" << c
+ << "' in long '" << name << "' is not allowed";
+ LongNames_.push_back(name);
+ return *this;
+ }
+
+ namespace NPrivate {
+ TString OptToString(char c);
+
+ TString OptToString(const TString& longOption);
+ }
+
+ TString TOpt::ToShortString() const {
+ ;
+ if (!LongNames_.empty())
+ return NPrivate::OptToString(LongNames_.front());
+ if (!Chars_.empty())
+ return NPrivate::OptToString(Chars_.front());
+ return "?";
+ }
+
+ void TOpt::FireHandlers(const TOptsParser* parser) const {
+ for (const auto& handler : Handlers_) {
+ handler->HandleOpt(parser);
+ }
+ }
+
+ TOpt& TOpt::IfPresentDisableCompletionFor(const TOpt& opt) {
+ if (opt.GetLongNames()) {
+ IfPresentDisableCompletionFor(opt.GetName());
+ } else {
+ IfPresentDisableCompletionFor(opt.GetChar());
+ }
+ return *this;
+ }
+}
diff --git a/library/cpp/getopt/small/last_getopt_opt.h b/library/cpp/getopt/small/last_getopt_opt.h
new file mode 100644
index 0000000000..a8dd5adca9
--- /dev/null
+++ b/library/cpp/getopt/small/last_getopt_opt.h
@@ -0,0 +1,812 @@
+#pragma once
+
+#include "completer.h"
+#include "last_getopt_handlers.h"
+
+#include <util/string/split.h>
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+#include <util/generic/maybe.h>
+#include <util/generic/vector.h>
+#include <util/string/cast.h>
+
+#include <stdarg.h>
+
+namespace NLastGetopt {
+ enum EHasArg {
+ NO_ARGUMENT,
+ REQUIRED_ARGUMENT,
+ OPTIONAL_ARGUMENT,
+ DEFAULT_HAS_ARG = REQUIRED_ARGUMENT
+ };
+
+ /**
+ * NLastGetopt::TOpt is a storage of data about exactly one program option.
+ * The data is: parse politics and help information.
+ *
+ * The help information consists of following:
+ * hidden or visible in help information
+ * help string
+ * argument name
+ *
+ * Parse politics is determined by following parameters:
+ * argument parse politics: no/optional/required/
+ * option existence: required or optional
+ * handlers. See detailed documentation: <TODO:link>
+ * default value: if the option has argument, but the option is ommited,
+ * then the <default value> is used as the value of the argument
+ * optional value: if the option has optional-argument, the option is present in parsed string,
+ * but the argument is omitted, then <optional value is used>
+ * in case of "not given <optional value>, omited optional argument" the <default value> is used
+ * user value: allows to store arbitary pointer for handlers
+ */
+ class TOpt {
+ public:
+ typedef TVector<char> TShortNames;
+ typedef TVector<TString> TLongNames;
+
+ protected:
+ TShortNames Chars_;
+ TLongNames LongNames_;
+
+ private:
+ typedef TMaybe<TString> TdOptVal;
+ typedef TVector<TSimpleSharedPtr<IOptHandler>> TOptHandlers;
+
+ public:
+ bool Hidden_ = false; // is visible in help
+ TString ArgTitle_; // the name of argument in help output
+ TString Help_; // the help string
+ TString CompletionHelp_; // the help string that's used in completion script, a shorter version of Help_
+ TString CompletionArgHelp_; // the description of argument in completion script
+
+ EHasArg HasArg_ = DEFAULT_HAS_ARG; // the argument parsing politics
+ bool Required_ = false; // option existence politics
+
+ bool AllowMultipleCompletion_ = false; // let the completer know that this option can occur more than once
+
+ bool DisableCompletionForOptions_ = false;
+ bool DisableCompletionForFreeArgs_ = false;
+ TShortNames DisableCompletionForChar_;
+ TLongNames DisableCompletionForLongName_;
+ TVector<size_t> DisableCompletionForFreeArg_;
+ NComp::ICompleterPtr Completer_;
+
+ private:
+ //Handlers information
+ const void* UserValue_ = nullptr;
+ TdOptVal OptionalValue_;
+ TdOptVal DefaultValue_;
+ TOptHandlers Handlers_;
+
+ public:
+ /**
+ * Checks if given char can be a short name
+ * @param c char to check
+ */
+ static bool IsAllowedShortName(unsigned char c);
+
+ /**
+ * Checks if given string can be a long name
+ * @param name string to check
+ * @param c if given, the first bad charecter will be saved in c
+ */
+ static bool IsAllowedLongName(const TString& name, unsigned char* c = nullptr);
+
+ /**
+ * @return one of the expected representations of the option.
+ * If the option has short names, will return "-<char>"
+ * Otherwise will return "--<long name>"
+ */
+ TString ToShortString() const;
+
+ /**
+ * check if given string is one of the long names
+ *
+ * @param name string to check
+ */
+ bool NameIs(const TString& name) const;
+
+ /**
+ * check if given char is one of the short names
+ *
+ * @param c char to check
+ */
+ bool CharIs(char c) const;
+
+ /**
+ * If string has long names - will return one of them
+ * Otherwise will throw
+ */
+ TString GetName() const;
+
+ /**
+ * adds short alias for the option
+ *
+ * @param c new short name
+ *
+ * @return self
+ */
+ TOpt& AddShortName(unsigned char c);
+
+ /**
+ * return all short names of the option
+ */
+ const TShortNames& GetShortNames() const {
+ return Chars_;
+ }
+
+ /**
+ * adds long alias for the option
+ *
+ * @param name new long name
+ *
+ * @return self
+ */
+ TOpt& AddLongName(const TString& name);
+
+ /**
+ * return all long names of the option
+ */
+ const TLongNames& GetLongNames() const {
+ return LongNames_;
+ }
+
+ /**
+ * @return one of short names of the opt. If there is no short names exception is raised.
+ */
+ char GetChar() const;
+
+ /**
+ * @return one of short names of the opt. If there is no short names '\0' returned.
+ */
+ char GetCharOr0() const;
+
+ /**
+ * @returns argument parsing politics
+ */
+ const EHasArg& GetHasArg() const {
+ return HasArg_;
+ }
+
+ /**
+ * sets argument parsing politics
+ *
+ * Note: its better use one of RequiredArgument/NoArgument/OptionalArgument methods
+ *
+ * @param hasArg new argument parsing mode
+ * @return self
+ */
+ TOpt& HasArg(EHasArg hasArg) {
+ HasArg_ = hasArg;
+ return *this;
+ }
+
+ /**
+ * @returns argument title
+ */
+ TString GetArgTitle() const {
+ return ArgTitle_;
+ }
+
+ /**
+ * sets argument parsing politics into REQUIRED_ARGUMENT
+ *
+ * @param title the new name of argument in help output
+ * @return self
+ */
+ TOpt& RequiredArgument(const TString& title = "") {
+ ArgTitle_ = title;
+ return HasArg(REQUIRED_ARGUMENT);
+ }
+
+ /**
+ * sets argument parsing politics into NO_ARGUMENT
+ *
+ * @return self
+ */
+ TOpt& NoArgument() {
+ return HasArg(NO_ARGUMENT);
+ }
+
+ /**
+ * sets argument parsing politics into OPTIONAL_ARGUMENT
+ * for details see NLastGetopt::TOpt
+ *
+ * @param title the new name of argument in help output
+ * @return self
+ */
+ TOpt& OptionalArgument(const TString& title = "") {
+ ArgTitle_ = title;
+ return HasArg(OPTIONAL_ARGUMENT);
+ }
+
+ /**
+ * sets argument parsing politics into OPTIONAL_ARGUMENT
+ * sets the <optional value> into given
+ *
+ * for details see NLastGetopt::TOpt
+ *
+ * @param val the new <optional value>
+ * @param title the new name of argument in help output
+ * @return self
+ */
+ TOpt& OptionalValue(const TString& val, const TString& title = "") {
+ OptionalValue_ = val;
+ return OptionalArgument(title);
+ }
+
+ /**
+ * checks if "argument parsing politics" is OPTIONAL_ARGUMENT and the <optional value> is set.
+ */
+ bool HasOptionalValue() const {
+ return OPTIONAL_ARGUMENT == HasArg_ && OptionalValue_;
+ }
+
+ /**
+ * @return optional value
+ * throws exception if optional value wasn't set
+ */
+ const TString& GetOptionalValue() const {
+ return *OptionalValue_;
+ }
+
+ /**
+ * sets <default value>
+ * @return self
+ */
+ template <typename T>
+ TOpt& DefaultValue(const T& val) {
+ DefaultValue_ = ToString(val);
+ return *this;
+ }
+
+ /**
+ * checks if default value is set.
+ */
+ bool HasDefaultValue() const {
+ return DefaultValue_.Defined();
+ }
+
+ /**
+ * @return default value
+ * throws exception if <default value> wasn't set
+ */
+ const TString& GetDefaultValue() const {
+ return *DefaultValue_;
+ }
+
+ /**
+ * sets the option to be required
+ * @return self
+ */
+ TOpt& Required() {
+ Required_ = true;
+ return *this;
+ }
+
+ /**
+ * sets the option to be optional
+ * @return self
+ */
+ TOpt& Optional() {
+ Required_ = false;
+ return *this;
+ }
+
+ /**
+ * @return true if the option is required
+ */
+ bool IsRequired() const {
+ return Required_;
+ }
+
+ /**
+ * sets the option to be hidden (invisible in help)
+ * @return self
+ */
+ TOpt& Hidden() {
+ Hidden_ = true;
+ return *this;
+ }
+
+ /**
+ * @return true if the option is hidden
+ */
+ bool IsHidden() const {
+ return Hidden_;
+ }
+
+ /**
+ * sets the <user value>
+ * @return self
+ * for details see NLastGetopt::TOpt
+ */
+ TOpt& UserValue(const void* userval) {
+ UserValue_ = userval;
+ return *this;
+ }
+
+ /**
+ * @return user value
+ */
+ const void* UserValue() const {
+ return UserValue_;
+ }
+
+ /**
+ * Set help string that appears with `--help`. Unless `CompletionHelp` is given, this message will also be used
+ * in completion script. In this case, don't make it too long, don't start it with a capital letter and don't
+ * end it with a full stop.
+ *
+ * Note that `Help`, `CompletionHelp` and `CompletionArgHelp` are not the same. `Help` is printed in program
+ * usage (when you call `program --help`), `CompletionHelp` is printed when completer lists available
+ * options, and `CompletionArgHelp` is printed when completer shows available values for the option.
+ *
+ * Example of good help message:
+ *
+ * ```
+ * opts.AddLongOption('t', "timeout")
+ * .Help("specify query timeout in milliseconds")
+ * .CompletionHelp("specify query timeout")
+ * .CompletionArgHelp("query timeout (ms) [default=500]");
+ * ```
+ *
+ * Notice how `Help` and `CompletionArgHelp` have units in them, but `CompletionHelp` don't.
+ *
+ * Another good example is the help option:
+ *
+ * ```
+ * opts.AddLongOption('h', "help")
+ * .Help("print this message and exit")
+ * .CompletionHelp("print help message and exit");
+ * ```
+ *
+ * Notice how `Help` mentions 'this message', but `CompletionHelp` mentions just 'help message'.
+ *
+ * See more on completion descriptions codestyle:
+ * https://github.com/zsh-users/zsh/blob/master/Etc/completion-style-guide#L43
+ */
+ TOpt& Help(const TString& help) {
+ Help_ = help;
+ return *this;
+ }
+
+ /**
+ * Get help string.
+ */
+ const TString& GetHelp() const {
+ return Help_;
+ }
+
+ /**
+ * Set help string that appears when argument completer lists available options.
+ *
+ * See `Help` function for info on how this is different from setting `Help` and `CompletionArgHelp`.
+ *
+ * Use shorter messages for this message. Don't start them with a capital letter and don't end them
+ * with a full stop. De aware that argument name and default value will not be printed by completer.
+ *
+ * In zsh, these messages will look like this:
+ *
+ * ```
+ * $ program -<tab><tab>
+ * -- option --
+ * --help -h -- print help message and exit
+ * --timeout -t -- specify query timeout
+ * ```
+ */
+ TOpt& CompletionHelp(const TString& help) {
+ CompletionHelp_ = help;
+ return *this;
+ }
+
+ /**
+ * Get help string that appears when argument completer lists available options.
+ */
+ const TString& GetCompletionHelp() const {
+ return CompletionHelp_ ? CompletionHelp_ : Help_;
+ }
+
+ /**
+ * Set help string that appears when completer suggests available values.
+ *
+ * See `Help` function for info on how this is different from setting `Help` and `CompletionHelp`.
+ *
+ * In zsh, these messages will look like this:
+ *
+ * ```
+ * $ program --timeout <tab><tab>
+ * -- query timeout (ms) [default=500] --
+ * 50 100 250 500 1000
+ * ```
+ */
+ TOpt& CompletionArgHelp(const TString& help) {
+ CompletionArgHelp_ = help;
+ return *this;
+ }
+
+ /**
+ * @return argument help string for use in completion script.
+ */
+ const TString& GetCompletionArgHelp() const {
+ return CompletionArgHelp_ ? CompletionArgHelp_ : ArgTitle_;
+ }
+
+ /**
+ * Let the completer know that this option can occur more than once.
+ */
+ TOpt& AllowMultipleCompletion(bool allowMultipleCompletion = true) {
+ AllowMultipleCompletion_ = allowMultipleCompletion;
+ return *this;
+ }
+
+ /**
+ * @return true if completer will offer completion for this option multiple times.
+ */
+ bool MultipleCompletionAllowed() const {
+ return AllowMultipleCompletion_;
+ }
+
+ /**
+ * Tell the completer to disable further completion if this option is present.
+ * This is useful for options like `--help`.
+ *
+ * Note: this only works in zsh.
+ *
+ * @return self
+ */
+ TOpt& IfPresentDisableCompletion(bool value = true) {
+ IfPresentDisableCompletionForOptions(value);
+ IfPresentDisableCompletionForFreeArgs(value);
+ return *this;
+ }
+
+ /**
+ * Tell the completer to disable completion for all options if this option is already present in the input.
+ * Free arguments will still be completed.
+ *
+ * Note: this only works in zsh.
+ *
+ * @return self
+ */
+ TOpt& IfPresentDisableCompletionForOptions(bool value = true) {
+ DisableCompletionForOptions_ = value;
+ return *this;
+ }
+
+ /**
+ * Tell the completer to disable option `c` if this option is already present in the input.
+ * For example, if you have two options `-a` and `-r` that are mutually exclusive, disable `-r` for `-a` and
+ * disable `-a` for `-r`, like this:
+ *
+ * ```
+ * opts.AddLongOption('a', "acquire").IfPresentDisableCompletionFor('r');
+ * opts.AddLongOption('r', "release").IfPresentDisableCompletionFor('a');
+ * ```
+ *
+ * This way, if user enabled option `-a`, completer will not suggest option `-r`.
+ *
+ * Note that we don't have to disable all flags for a single option. That is, disabling `-r` in the above
+ * example disables `--release` automatically.
+ *
+ * Note: this only works in zsh.
+ *
+ * @param c char option that should be disabled when completer hits this option.
+ */
+ TOpt& IfPresentDisableCompletionFor(char c) {
+ DisableCompletionForChar_.push_back(c);
+ return *this;
+ }
+
+ /**
+ * Like `IfPresentDisableCompletionFor(char c)`, but for long options.
+ */
+ TOpt& IfPresentDisableCompletionFor(const TString& name) {
+ DisableCompletionForLongName_.push_back(name);
+ return *this;
+ }
+
+ /**
+ * Like `IfPresentDisableCompletionFor(char c)`, but for long options.
+ */
+ TOpt& IfPresentDisableCompletionFor(const TOpt& opt);
+
+ /**
+ * Tell the completer to disable completion for the given free argument if this option is present.
+ *
+ * Note: this only works in zsh.
+ *
+ * @param arg index of free arg
+ */
+ TOpt& IfPresentDisableCompletionForFreeArg(size_t index) {
+ DisableCompletionForFreeArg_.push_back(index);
+ return *this;
+ }
+
+ /**
+ * Assign a completer for this option.
+ */
+ TOpt& Completer(NComp::ICompleterPtr completer) {
+ Completer_ = std::move(completer);
+ return *this;
+ }
+
+ /**
+ * Tell the completer to disable completion for the all free arguments if this option is present.
+ *
+ * Note: this only works in zsh.
+ */
+ TOpt& IfPresentDisableCompletionForFreeArgs(bool value = true) {
+ DisableCompletionForFreeArgs_ = value;
+ return *this;
+ }
+
+ /**
+ * Run handlers for this option.
+ */
+ void FireHandlers(const TOptsParser* parser) const;
+
+ private:
+ TOpt& HandlerImpl(IOptHandler* handler) {
+ Handlers_.push_back(handler);
+ return *this;
+ }
+
+ public:
+ template <typename TpFunc>
+ TOpt& Handler0(TpFunc func) { // functor taking no parameters
+ return HandlerImpl(new NPrivate::THandlerFunctor0<TpFunc>(func));
+ }
+
+ template <typename TpFunc>
+ TOpt& Handler1(TpFunc func) { // functor taking one parameter
+ return HandlerImpl(new NPrivate::THandlerFunctor1<TpFunc>(func));
+ }
+ template <typename TpArg, typename TpFunc>
+ TOpt& Handler1T(TpFunc func) {
+ return HandlerImpl(new NPrivate::THandlerFunctor1<TpFunc, TpArg>(func));
+ }
+ template <typename TpArg, typename TpFunc>
+ TOpt& Handler1T(const TpArg& def, TpFunc func) {
+ return HandlerImpl(new NPrivate::THandlerFunctor1<TpFunc, TpArg>(func, def));
+ }
+ template <typename TpArg, typename TpArg2, typename TpFunc>
+ TOpt& Handler1T2(const TpArg2& def, TpFunc func) {
+ return HandlerImpl(new NPrivate::THandlerFunctor1<TpFunc, TpArg>(func, def));
+ }
+
+ TOpt& Handler(void (*f)()) {
+ return Handler0(f);
+ }
+ TOpt& Handler(void (*f)(const TOptsParser*)) {
+ return Handler1(f);
+ }
+
+ TOpt& Handler(TAutoPtr<IOptHandler> handler) {
+ return HandlerImpl(handler.Release());
+ }
+
+ template <typename T> // T extends IOptHandler
+ TOpt& Handler(TAutoPtr<T> handler) {
+ return HandlerImpl(handler.Release());
+ }
+
+ // Stores FromString<T>(arg) in *target
+ // T maybe anything with FromString<T>(const TStringBuf&) defined
+ template <typename TpVal, typename T>
+ TOpt& StoreResultT(T* target) {
+ return Handler1T<TpVal>(NPrivate::TStoreResultFunctor<T, TpVal>(target));
+ }
+
+ template <typename T>
+ TOpt& StoreResult(T* target) {
+ return StoreResultT<T>(target);
+ }
+
+ // Uses TMaybe<T> to store FromString<T>(arg)
+ template <typename T>
+ TOpt& StoreResult(TMaybe<T>* target) {
+ return StoreResultT<T>(target);
+ }
+
+ template <typename TpVal, typename T, typename TpDef>
+ TOpt& StoreResultT(T* target, const TpDef& def) {
+ return Handler1T<TpVal>(def, NPrivate::TStoreResultFunctor<T, TpVal>(target));
+ }
+
+ template <typename T, typename TpDef>
+ TOpt& StoreResult(T* target, const TpDef& def) {
+ return StoreResultT<T>(target, def);
+ }
+
+ template <typename T>
+ TOpt& StoreResultDef(T* target) {
+ DefaultValue_ = ToString(*target);
+ return StoreResultT<T>(target, *target);
+ }
+
+ template <typename T, typename TpDef>
+ TOpt& StoreResultDef(T* target, const TpDef& def) {
+ DefaultValue_ = ToString(def);
+ return StoreResultT<T>(target, def);
+ }
+
+ // Sugar for storing flags (option without arguments) to boolean vars
+ TOpt& SetFlag(bool* target) {
+ return DefaultValue("0").StoreResult(target, true);
+ }
+
+ // Similar to store_true in Python's argparse
+ TOpt& StoreTrue(bool* target) {
+ return NoArgument().SetFlag(target);
+ }
+
+ template <typename TpVal, typename T, typename TpFunc>
+ TOpt& StoreMappedResultT(T* target, const TpFunc& func) {
+ return Handler1T<TpVal>(NPrivate::TStoreMappedResultFunctor<T, TpFunc, TpVal>(target, func));
+ }
+
+ template <typename T, typename TpFunc>
+ TOpt& StoreMappedResult(T* target, const TpFunc& func) {
+ return StoreMappedResultT<T>(target, func);
+ }
+
+ // Stores given value in *target if the option is present.
+ // TValue must be a copyable type, constructible from TParam.
+ // T must be a copyable type, assignable from TValue.
+ template <typename TValue, typename T, typename TParam>
+ TOpt& StoreValueT(T* target, const TParam& value) {
+ return Handler1(NPrivate::TStoreValueFunctor<T, TValue>(target, value));
+ }
+
+ // save value as target type
+ template <typename T, typename TParam>
+ TOpt& StoreValue(T* target, const TParam& value) {
+ return StoreValueT<T>(target, value);
+ }
+
+ // save value as its original type (2nd template parameter)
+ template <typename T, typename TValue>
+ TOpt& StoreValue2(T* target, const TValue& value) {
+ return StoreValueT<TValue>(target, value);
+ }
+
+ // Appends FromString<T>(arg) to *target for each argument
+ template <typename T>
+ TOpt& AppendTo(TVector<T>* target) {
+ return Handler1T<T>([target](auto&& value) { target->push_back(std::move(value)); });
+ }
+
+ // Appends FromString<T>(arg) to *target for each argument
+ template <typename T>
+ TOpt& InsertTo(THashSet<T>* target) {
+ return Handler1T<T>([target](auto&& value) { target->insert(std::move(value)); });
+ }
+
+ // Emplaces TString arg to *target for each argument
+ template <typename T>
+ TOpt& EmplaceTo(TVector<T>* target) {
+ return Handler1T<TString>([target](TString arg) { target->emplace_back(std::move(arg)); } );
+ }
+
+ template <class Container>
+ TOpt& SplitHandler(Container* target, const char delim) {
+ return Handler(new NLastGetopt::TOptSplitHandler<Container>(target, delim));
+ }
+
+ template <class Container>
+ TOpt& RangeSplitHandler(Container* target, const char elementsDelim, const char rangesDelim) {
+ return Handler(new NLastGetopt::TOptRangeSplitHandler<Container>(target, elementsDelim, rangesDelim));
+ }
+
+ template <class TpFunc>
+ TOpt& KVHandler(TpFunc func, const char kvdelim = '=') {
+ return Handler(new NLastGetopt::TOptKVHandler<TpFunc>(func, kvdelim));
+ }
+ };
+
+ /**
+ * NLastGetopt::TFreeArgSpec is a storage of data about free argument.
+ * The data is help information and (maybe) linked named argument.
+ *
+ * The help information consists of following:
+ * help string
+ * argument name (title)
+ */
+ struct TFreeArgSpec {
+ TFreeArgSpec() = default;
+ TFreeArgSpec(const TString& title, const TString& help = TString(), bool optional = false)
+ : Title_(title)
+ , Help_(help)
+ , Optional_(optional)
+ {
+ }
+
+ TString Title_;
+ TString Help_;
+ TString CompletionArgHelp_;
+
+ bool Optional_ = false;
+ NComp::ICompleterPtr Completer_ = nullptr;
+
+ /**
+ * Check if this argument have default values for its title and help.
+ */
+ bool IsDefault() const {
+ return Title_.empty() && Help_.empty();
+ }
+
+ /**
+ * Set argument title.
+ */
+ TFreeArgSpec& Title(TString title) {
+ Title_ = std::move(title);
+ return *this;
+ }
+
+ /**
+ * Get argument title. If title is empty, returns a default one.
+ */
+ TStringBuf GetTitle(TStringBuf defaultTitle) const {
+ return Title_ ? TStringBuf(Title_) : defaultTitle;
+ }
+
+ /**
+ * Set help string that appears with `--help`. Unless `CompletionHelp` is given, this message will also be used
+ * in completion script. In this case, don't make it too long, don't start it with a capital letter and don't
+ * end it with a full stop.
+ *
+ * See `TOpt::Help` function for more on how `Help` and `CompletionArgHelp` differ one from another.
+ */
+ TFreeArgSpec& Help(TString help) {
+ Help_ = std::move(help);
+ return *this;
+ }
+
+ /**
+ * Get help string that appears with `--help`.
+ */
+ TStringBuf GetHelp() const {
+ return Help_;
+ }
+
+ /**
+ * Set help string that appears when completer suggests values fot this argument.
+ */
+ TFreeArgSpec& CompletionArgHelp(TString completionArgHelp) {
+ CompletionArgHelp_ = std::move(completionArgHelp);
+ return *this;
+ }
+
+ /**
+ * Get help string that appears when completer suggests values fot this argument.
+ */
+ TStringBuf GetCompletionArgHelp(TStringBuf defaultTitle) const {
+ return CompletionArgHelp_ ? TStringBuf(CompletionArgHelp_) : GetTitle(defaultTitle);
+ }
+
+ /**
+ * Mark this argument as optional. This setting only affects help printing, it doesn't affect parsing.
+ */
+ TFreeArgSpec& Optional(bool optional = true) {
+ Optional_ = optional;
+ return *this;
+ }
+
+ /**
+ * Check if this argument is optional.
+ */
+ bool IsOptional() const {
+ return Optional_;
+ }
+
+ /**
+ * Set completer for this argument.
+ */
+ TFreeArgSpec& Completer(NComp::ICompleterPtr completer) {
+ Completer_ = std::move(completer);
+ return *this;
+ }
+ };
+}
diff --git a/library/cpp/getopt/small/last_getopt_opts.cpp b/library/cpp/getopt/small/last_getopt_opts.cpp
new file mode 100644
index 0000000000..03c432849f
--- /dev/null
+++ b/library/cpp/getopt/small/last_getopt_opts.cpp
@@ -0,0 +1,519 @@
+#include "completer_command.h"
+#include "last_getopt_opts.h"
+#include "wrap.h"
+#include "last_getopt_parser.h"
+
+#include <library/cpp/colorizer/colors.h>
+
+#include <util/stream/format.h>
+#include <util/charset/utf8.h>
+
+#include <stdlib.h>
+
+namespace NLastGetoptPrivate {
+ TString& VersionString() {
+ static TString data;
+ return data;
+ }
+ TString& ShortVersionString() {
+ static TString data;
+ return data;
+ }
+}
+
+namespace NLastGetopt {
+ static const TStringBuf SPad = " ";
+
+ void PrintVersionAndExit(const TOptsParser*) {
+ Cout << (NLastGetoptPrivate::VersionString() ? NLastGetoptPrivate::VersionString() : "program version: not linked with library/cpp/getopt") << Endl;
+ exit(NLastGetoptPrivate::VersionString().empty());
+ }
+
+ void PrintShortVersionAndExit(const TString& appName) {
+ Cout << appName << " version " << (NLastGetoptPrivate::ShortVersionString() ? NLastGetoptPrivate::ShortVersionString() : "not linked with library/cpp/getopt") << Endl;
+ exit(NLastGetoptPrivate::ShortVersionString().empty());
+ }
+
+ // Like TString::Quote(), but does not quote digits-only string
+ static TString QuoteForHelp(const TString& str) {
+ if (str.empty())
+ return str.Quote();
+ for (size_t i = 0; i < str.size(); ++i) {
+ if (!isdigit(str[i]))
+ return str.Quote();
+ }
+ return str;
+ }
+
+ namespace NPrivate {
+ TString OptToString(char c) {
+ TStringStream ss;
+ ss << "-" << c;
+ return ss.Str();
+ }
+
+ TString OptToString(const TString& longOption) {
+ TStringStream ss;
+ ss << "--" << longOption;
+ return ss.Str();
+ }
+
+ TString OptToString(const TOpt* opt) {
+ return opt->ToShortString();
+ }
+ }
+
+ TOpts::TOpts(const TStringBuf& optstring)
+ : ArgPermutation_(DEFAULT_ARG_PERMUTATION)
+ , AllowSingleDashForLong_(false)
+ , AllowPlusForLong_(false)
+ , AllowUnknownCharOptions_(false)
+ , AllowUnknownLongOptions_(false)
+ , FreeArgsMin_(0)
+ , FreeArgsMax_(UNLIMITED_ARGS)
+ {
+ if (!optstring.empty()) {
+ AddCharOptions(optstring);
+ }
+ AddVersionOption(0);
+ }
+
+ void TOpts::AddCharOptions(const TStringBuf& optstring) {
+ size_t p = 0;
+ if (optstring[p] == '+') {
+ ArgPermutation_ = REQUIRE_ORDER;
+ ++p;
+ } else if (optstring[p] == '-') {
+ ArgPermutation_ = RETURN_IN_ORDER;
+ ++p;
+ }
+
+ while (p < optstring.size()) {
+ char c = optstring[p];
+ p++;
+ EHasArg ha = NO_ARGUMENT;
+ if (p < optstring.size() && optstring[p] == ':') {
+ ha = REQUIRED_ARGUMENT;
+ p++;
+ }
+ if (p < optstring.size() && optstring[p] == ':') {
+ ha = OPTIONAL_ARGUMENT;
+ p++;
+ }
+ AddCharOption(c, ha);
+ }
+ }
+
+ const TOpt* TOpts::FindLongOption(const TStringBuf& name) const {
+ for (const auto& Opt : Opts_) {
+ const TOpt* opt = Opt.Get();
+ if (IsIn(opt->GetLongNames(), name))
+ return opt;
+ }
+ return nullptr;
+ }
+
+ TOpt* TOpts::FindLongOption(const TStringBuf& name) {
+ for (auto& Opt : Opts_) {
+ TOpt* opt = Opt.Get();
+ if (IsIn(opt->GetLongNames(), name))
+ return opt;
+ }
+ return nullptr;
+ }
+
+ const TOpt* TOpts::FindCharOption(char c) const {
+ for (const auto& Opt : Opts_) {
+ const TOpt* opt = Opt.Get();
+ if (IsIn(opt->GetShortNames(), c))
+ return opt;
+ }
+ return nullptr;
+ }
+
+ TOpt* TOpts::FindCharOption(char c) {
+ for (auto& Opt : Opts_) {
+ TOpt* opt = Opt.Get();
+ if (IsIn(opt->GetShortNames(), c))
+ return opt;
+ }
+ return nullptr;
+ }
+
+ const TOpt& TOpts::GetCharOption(char c) const {
+ const TOpt* option = FindCharOption(c);
+ if (!option)
+ ythrow TException() << "unknown char option '" << c << "'";
+ return *option;
+ }
+
+ TOpt& TOpts::GetCharOption(char c) {
+ TOpt* option = FindCharOption(c);
+ if (!option)
+ ythrow TException() << "unknown char option '" << c << "'";
+ return *option;
+ }
+
+ const TOpt& TOpts::GetLongOption(const TStringBuf& name) const {
+ const TOpt* option = FindLongOption(name);
+ if (!option)
+ ythrow TException() << "unknown option " << name;
+ return *option;
+ }
+
+ TOpt& TOpts::GetLongOption(const TStringBuf& name) {
+ TOpt* option = FindLongOption(name);
+ if (!option)
+ ythrow TException() << "unknown option " << name;
+ return *option;
+ }
+
+ bool TOpts::HasAnyShortOption() const {
+ for (const auto& Opt : Opts_) {
+ const TOpt* opt = Opt.Get();
+ if (!opt->GetShortNames().empty())
+ return true;
+ }
+ return false;
+ }
+
+ bool TOpts::HasAnyLongOption() const {
+ for (const auto& Opt : Opts_) {
+ TOpt* opt = Opt.Get();
+ if (!opt->GetLongNames().empty())
+ return true;
+ }
+ return false;
+ }
+
+ void TOpts::Validate() const {
+ for (TOptsVector::const_iterator i = Opts_.begin(); i != Opts_.end(); ++i) {
+ TOpt* opt = i->Get();
+ const TOpt::TShortNames& shortNames = opt->GetShortNames();
+ for (auto c : shortNames) {
+ for (TOptsVector::const_iterator j = i + 1; j != Opts_.end(); ++j) {
+ TOpt* nextOpt = j->Get();
+ if (nextOpt->CharIs(c))
+ ythrow TConfException() << "option "
+ << NPrivate::OptToString(c)
+ << " is defined more than once";
+ }
+ }
+ const TOpt::TLongNames& longNames = opt->GetLongNames();
+ for (const auto& longName : longNames) {
+ for (TOptsVector::const_iterator j = i + 1; j != Opts_.end(); ++j) {
+ TOpt* nextOpt = j->Get();
+ if (nextOpt->NameIs(longName))
+ ythrow TConfException() << "option "
+ << NPrivate::OptToString(longName)
+ << " is defined more than once";
+ }
+ }
+ }
+ if (FreeArgsMax_ < FreeArgsMin_) {
+ ythrow TConfException() << "FreeArgsMax must be >= FreeArgsMin";
+ }
+ if (!FreeArgSpecs_.empty() && FreeArgSpecs_.rbegin()->first >= FreeArgsMax_) {
+ ythrow TConfException() << "Described args count is greater than FreeArgsMax. Either increase FreeArgsMax or remove unreachable descriptions";
+ }
+ }
+
+ TOpt& TOpts::AddOption(const TOpt& option) {
+ if (option.GetShortNames().empty() && option.GetLongNames().empty())
+ ythrow TConfException() << "bad option: no chars, no long names";
+ Opts_.push_back(new TOpt(option));
+ return *Opts_.back();
+ }
+
+ TOpt& TOpts::AddCompletionOption(TString command, TString longName) {
+ if (TOpt* o = FindLongOption(longName)) {
+ return *o;
+ }
+
+ return AddOption(MakeCompletionOpt(this, std::move(command), std::move(longName)));
+ }
+
+ namespace {
+ auto MutuallyExclusiveHandler(const TOpt* cur, const TOpt* other) {
+ return [cur, other](const TOptsParser* p) {
+ if (p->Seen(other)) {
+ throw TUsageException()
+ << "option " << cur->ToShortString()
+ << " can't appear together with option " << other->ToShortString();
+ }
+ };
+ }
+ }
+
+ void TOpts::MutuallyExclusiveOpt(TOpt& opt1, TOpt& opt2) {
+ opt1.Handler1(MutuallyExclusiveHandler(&opt1, &opt2))
+ .IfPresentDisableCompletionFor(opt2);
+ opt2.Handler1(MutuallyExclusiveHandler(&opt2, &opt1))
+ .IfPresentDisableCompletionFor(opt1);
+ }
+
+ size_t TOpts::IndexOf(const TOpt* opt) const {
+ TOptsVector::const_iterator it = std::find(Opts_.begin(), Opts_.end(), opt);
+ if (it == Opts_.end())
+ ythrow TException() << "unknown option";
+ return it - Opts_.begin();
+ }
+
+ TStringBuf TOpts::GetFreeArgTitle(size_t pos) const {
+ if (FreeArgSpecs_.contains(pos)) {
+ return FreeArgSpecs_.at(pos).GetTitle(DefaultFreeArgTitle_);
+ }
+ return DefaultFreeArgTitle_;
+ }
+
+ void TOpts::SetFreeArgTitle(size_t pos, const TString& title, const TString& help, bool optional) {
+ FreeArgSpecs_[pos] = TFreeArgSpec(title, help, optional);
+ }
+
+ TFreeArgSpec& TOpts::GetFreeArgSpec(size_t pos) {
+ return FreeArgSpecs_[pos];
+ }
+
+ static TString FormatOption(const TOpt* option, const NColorizer::TColors& colors) {
+ TStringStream result;
+ const TOpt::TShortNames& shorts = option->GetShortNames();
+ const TOpt::TLongNames& longs = option->GetLongNames();
+
+ const size_t nopts = shorts.size() + longs.size();
+ const bool multiple = 1 < nopts;
+ if (multiple)
+ result << '{';
+ for (size_t i = 0; i < nopts; ++i) {
+ if (multiple && 0 != i)
+ result << '|';
+
+ if (i < shorts.size()) // short
+ result << colors.GreenColor() << '-' << shorts[i] << colors.OldColor();
+ else
+ result << colors.GreenColor() << "--" << longs[i - shorts.size()] << colors.OldColor();
+ }
+ if (multiple)
+ result << '}';
+
+ static const TString metavarDef("VAL");
+ const TString& title = option->GetArgTitle();
+ const TString& metavar = title.empty() ? metavarDef : title;
+
+ if (option->GetHasArg() == OPTIONAL_ARGUMENT) {
+ result << " [" << metavar;
+ if (option->HasOptionalValue())
+ result << ':' << option->GetOptionalValue();
+ result << ']';
+ } else if (option->GetHasArg() == REQUIRED_ARGUMENT)
+ result << ' ' << metavar;
+ else
+ Y_ASSERT(option->GetHasArg() == NO_ARGUMENT);
+
+ return result.Str();
+ }
+
+ void TOpts::PrintCmdLine(const TStringBuf& program, IOutputStream& os, const NColorizer::TColors& colors) const {
+ os << colors.BoldColor() << "Usage" << colors.OldColor() << ": ";
+ if (CustomUsage) {
+ os << CustomUsage;
+ } else {
+ os << program << " ";
+ }
+ if (CustomCmdLineDescr) {
+ os << CustomCmdLineDescr << Endl;
+ return;
+ }
+ os << "[OPTIONS]";
+
+ ui32 numDescribedFlags = FreeArgSpecs_.empty() ? 0 : FreeArgSpecs_.rbegin()->first + 1;
+ ui32 numArgsToShow = Max(FreeArgsMin_, FreeArgsMax_ == UNLIMITED_ARGS ? numDescribedFlags : FreeArgsMax_);
+
+ for (ui32 i = 0, nonOptionalFlagsPrinted = 0; i < numArgsToShow; ++i) {
+ bool isOptional = nonOptionalFlagsPrinted >= FreeArgsMin_ || FreeArgSpecs_.Value(i, TFreeArgSpec()).Optional_;
+
+ nonOptionalFlagsPrinted += !isOptional;
+
+ os << " ";
+
+ if (isOptional)
+ os << "[";
+
+ os << GetFreeArgTitle(i);
+
+ if (isOptional)
+ os << "]";
+ }
+
+ if (FreeArgsMax_ == UNLIMITED_ARGS) {
+ os << " [" << TrailingArgSpec_.GetTitle(DefaultFreeArgTitle_) << "]...";
+ }
+
+ os << Endl;
+ }
+
+ void TOpts::PrintUsage(const TStringBuf& program, IOutputStream& osIn, const NColorizer::TColors& colors) const {
+ TStringStream os;
+
+ if (!Title.empty())
+ os << Title << "\n\n";
+
+ PrintCmdLine(program, os, colors);
+
+ TVector<TString> leftColumn(Opts_.size());
+ TVector<size_t> leftColumnSizes(leftColumn.size());
+ const size_t kMaxLeftWidth = 25;
+ size_t leftWidth = 0;
+ size_t requiredOptionsCount = 0;
+ NColorizer::TColors disabledColors(false);
+
+ for (size_t i = 0; i < Opts_.size(); i++) {
+ const TOpt* opt = Opts_[i].Get();
+ if (opt->IsHidden())
+ continue;
+ leftColumn[i] = FormatOption(opt, colors);
+ size_t leftColumnSize = leftColumn[i].size();
+ if (colors.IsTTY()) {
+ leftColumnSize -= NColorizer::TotalAnsiEscapeCodeLen(leftColumn[i]);
+ }
+ leftColumnSizes[i] = leftColumnSize;
+ if (leftColumnSize <= kMaxLeftWidth) {
+ leftWidth = Max(leftWidth, leftColumnSize);
+ }
+ if (opt->IsRequired())
+ requiredOptionsCount++;
+ }
+
+ const TString leftPadding(leftWidth, ' ');
+
+ for (size_t sectionId = 0; sectionId <= 1; sectionId++) {
+ bool requiredOptionsSection = (sectionId == 0);
+
+ if (requiredOptionsSection) {
+ if (requiredOptionsCount == 0)
+ continue;
+ os << Endl << colors.BoldColor() << "Required parameters" << colors.OldColor() << ":" << Endl;
+ } else {
+ if (requiredOptionsCount == Opts_.size())
+ continue;
+ if (requiredOptionsCount == 0)
+ os << Endl << colors.BoldColor() << "Options" << colors.OldColor() << ":" << Endl;
+ else
+ os << Endl << colors.BoldColor() << "Optional parameters" << colors.OldColor() << ":" << Endl; // optional options would be a tautology
+ }
+
+ for (size_t i = 0; i < Opts_.size(); i++) {
+ const TOpt* opt = Opts_[i].Get();
+
+ if (opt->IsHidden())
+ continue;
+ if (opt->IsRequired() != requiredOptionsSection)
+ continue;
+
+ if (leftColumnSizes[i] > leftWidth && !opt->GetHelp().empty()) {
+ os << SPad << leftColumn[i] << Endl << SPad << leftPadding << ' ';
+ } else {
+ os << SPad << leftColumn[i] << ' ';
+ if (leftColumnSizes[i] < leftWidth)
+ os << TStringBuf(leftPadding.data(), leftWidth - leftColumnSizes[i]);
+ }
+
+ TStringBuf help = opt->GetHelp();
+ while (help && isspace(help.back())) {
+ help.Chop(1);
+ }
+ size_t lastLineLength = 0;
+ bool helpHasParagraphs = false;
+ if (help) {
+ os << Wrap(Wrap_, help, SPad + leftPadding + " ", &lastLineLength, &helpHasParagraphs);
+ }
+
+ if (opt->HasDefaultValue()) {
+ auto quotedDef = QuoteForHelp(opt->GetDefaultValue());
+ if (helpHasParagraphs) {
+ os << Endl << Endl << SPad << leftPadding << " ";
+ os << "Default: " << colors.CyanColor() << quotedDef << colors.OldColor() << ".";
+ } else if (help.EndsWith('.')) {
+ os << Endl << SPad << leftPadding << " ";
+ os << "Default: " << colors.CyanColor() << quotedDef << colors.OldColor() << ".";
+ } else if (help) {
+ if (SPad.size() + leftWidth + 1 + lastLineLength + 12 + quotedDef.size() > Wrap_) {
+ os << Endl << SPad << leftPadding << " ";
+ } else {
+ os << " ";
+ }
+ os << "(default: " << colors.CyanColor() << quotedDef << colors.OldColor() << ")";
+ } else {
+ os << "default: " << colors.CyanColor() << quotedDef << colors.OldColor();
+ }
+ }
+
+ os << Endl;
+
+ if (helpHasParagraphs) {
+ os << Endl;
+ }
+ }
+ }
+
+ PrintFreeArgsDesc(os, colors);
+
+ for (auto& [heading, text] : Sections) {
+ os << Endl << colors.BoldColor() << heading << colors.OldColor() << ":" << Endl;
+
+ os << SPad << Wrap(Wrap_, text, SPad) << Endl;
+ }
+
+ osIn << os.Str();
+ }
+
+ void TOpts::PrintUsage(const TStringBuf& program, IOutputStream& os) const {
+ PrintUsage(program, os, NColorizer::AutoColors(os));
+ }
+
+ void TOpts::PrintFreeArgsDesc(IOutputStream& os, const NColorizer::TColors& colors) const {
+ if (0 == FreeArgsMax_)
+ return;
+
+ size_t leftFreeWidth = 0;
+ for (size_t i = 0; i < FreeArgSpecs_.size(); ++i) {
+ leftFreeWidth = Max(leftFreeWidth, GetFreeArgTitle(i).size());
+ }
+
+ if (!TrailingArgSpec_.IsDefault()) {
+ leftFreeWidth = Max(leftFreeWidth, TrailingArgSpec_.GetTitle(DefaultFreeArgTitle_).size());
+ }
+
+ leftFreeWidth = Min(leftFreeWidth, size_t(30));
+ os << Endl << colors.BoldColor() << "Free args" << colors.OldColor() << ":";
+
+ os << " min: " << colors.GreenColor() << FreeArgsMin_ << colors.OldColor() << ",";
+ os << " max: " << colors.GreenColor();
+ if (FreeArgsMax_ != UNLIMITED_ARGS) {
+ os << FreeArgsMax_;
+ } else {
+ os << "unlimited";
+ }
+ os << colors.OldColor() << Endl;
+
+ const size_t limit = FreeArgSpecs_.empty() ? 0 : FreeArgSpecs_.rbegin()->first;
+ for (size_t i = 0; i <= limit; ++i) {
+ if (!FreeArgSpecs_.contains(i)) {
+ continue;
+ }
+
+ if (auto help = FreeArgSpecs_.at(i).GetHelp()) {
+ auto title = GetFreeArgTitle(i);
+ os << SPad << colors.GreenColor() << RightPad(title, leftFreeWidth, ' ') << colors.OldColor()
+ << SPad << help << Endl;
+ }
+ }
+
+ if (FreeArgsMax_ == UNLIMITED_ARGS) {
+ auto title = TrailingArgSpec_.GetTitle(DefaultFreeArgTitle_);
+ if (auto help = TrailingArgSpec_.GetHelp()) {
+ os << SPad << colors.GreenColor() << RightPad(title, leftFreeWidth, ' ') << colors.OldColor()
+ << SPad << help << Endl;
+ }
+ }
+ }
+}
diff --git a/library/cpp/getopt/small/last_getopt_opts.h b/library/cpp/getopt/small/last_getopt_opts.h
new file mode 100644
index 0000000000..825b99c871
--- /dev/null
+++ b/library/cpp/getopt/small/last_getopt_opts.h
@@ -0,0 +1,643 @@
+#pragma once
+
+#include "last_getopt_opt.h"
+
+#include <library/cpp/colorizer/fwd.h>
+
+#include <util/generic/map.h>
+
+namespace NLastGetopt {
+ enum EArgPermutation {
+ REQUIRE_ORDER,
+ PERMUTE,
+ RETURN_IN_ORDER,
+ DEFAULT_ARG_PERMUTATION = PERMUTE
+ };
+
+ /**
+ * NLastGetopt::TOpts is a storage of program options' parse rules.
+ * It contains information about all options, free args, some parsing options
+ * and rules about interaction between options.
+ *
+ * The main point for defining program options.
+ *
+ * The parsing rules determined by the following parts:
+ * - Arguments permutation. It is expected free args be after named args.
+ * This point adjusts how to treat breaking this expectation.
+ * if REQUIRE_ORDER is choosen, the exception during parsing will be raised,
+ * the special string " -- " will be treated as end of named
+ * options: all options after it will be parsed as free args
+ * if PERMUTE is choosen, arguments will be rearranged in correct order,
+ * if RETURN_IN_ORDER is choosen, all free args will be ommited (TODO: looks very strange)
+ * - Using '+' as a prefix instead '--' for long names
+ * - Using "-" as a prefix for both short and long names
+ * - Allowing unknown options
+ *
+ */
+ class TOpts {
+ friend class TOptsParseResult;
+ friend class TOptsParser;
+
+ public:
+ static constexpr const ui32 UNLIMITED_ARGS = Max<ui32>();
+
+ typedef TVector<TSimpleSharedPtr<TOpt>> TOptsVector;
+ TOptsVector Opts_; // infomation about named (short and long) options
+ TVector<std::function<void(TStringBuf)>> ArgBindings_;
+
+ EArgPermutation ArgPermutation_ = DEFAULT_ARG_PERMUTATION; // determines how to parse positions of named and free options. See information below.
+ bool AllowSingleDashForLong_ = false; //
+ bool AllowPlusForLong_ = false; // using '+' instead '--' for long options
+
+ //Allows unknwon options:
+ bool AllowUnknownCharOptions_ = false;
+ bool AllowUnknownLongOptions_ = false;
+
+ ui32 Wrap_ = 80;
+
+ private:
+ ui32 FreeArgsMin_; // minimal number of free args
+ ui32 FreeArgsMax_; // maximal number of free args
+
+ TMap<ui32, TFreeArgSpec> FreeArgSpecs_; // mapping [free arg position] -> [free arg specification]
+ TFreeArgSpec TrailingArgSpec_; // spec for the trailing argument (when arguments are unlimited)
+ TString DefaultFreeArgTitle_ = "ARG"; // title that's used for free args without a title
+
+ TString Title; // title of the help string
+ TString CustomCmdLineDescr; // user defined help string
+ TString CustomUsage; // user defined usage string
+
+ TVector<std::pair<TString, TString>> Sections; // additional help entries to print after usage
+
+ public:
+ /**
+ * Constructs TOpts from string as in getopt(3)
+ */
+ TOpts(const TStringBuf& optstring = TStringBuf());
+
+ /**
+ * Constructs TOpts from string as in getopt(3) and
+ * additionally adds help option (for '?') and svn-verstion option (for 'V')
+ */
+ static TOpts Default(const TStringBuf& optstring = TStringBuf()) {
+ TOpts opts(optstring);
+ opts.AddHelpOption();
+ opts.AddVersionOption();
+ return opts;
+ }
+
+ /**
+ * Checks correctness of options' descriptions.
+ * Throws TConfException if validation failed.
+ * Check consist of:
+ * -not intersecting of names
+ * -compability of settings, that responsable for freeArgs parsing
+ */
+ void Validate() const;
+
+ /**
+ * Search for the option with given long name
+ * @param name long name for search
+ * @return ptr on result (nullptr if not found)
+ */
+ const TOpt* FindLongOption(const TStringBuf& name) const;
+
+ /**
+ * Search for the option with given short name
+ * @param c short name for search
+ * @return ptr on result (nullptr if not found)
+ */
+ const TOpt* FindCharOption(char c) const;
+
+ /**
+ * Search for the option with given long name
+ * @param name long name for search
+ * @return ptr on result (nullptr if not found)
+ */
+ TOpt* FindLongOption(const TStringBuf& name);
+
+ /**
+ * Search for the option with given short name
+ * @param c short name for search
+ * @return ptr on result (nullptr if not found)
+ */
+ TOpt* FindCharOption(char c);
+
+ /**
+ * Search for the option with given name
+ * @param name name for search
+ * @return ptr on result (nullptr if not found)
+ */
+ /// @{
+
+ const TOpt* FindOption(const TStringBuf& name) const {
+ return FindLongOption(name);
+ }
+
+ TOpt* FindOption(const TStringBuf& name) {
+ return FindLongOption(name);
+ }
+
+ const TOpt* FindOption(char c) const {
+ return FindCharOption(c);
+ }
+
+ TOpt* FindOption(char c) {
+ return FindCharOption(c);
+ }
+
+ /// @}
+
+ /**
+ * Sets title of the help string
+ * @param title title to set
+ */
+ void SetTitle(const TString& title) {
+ Title = title;
+ }
+
+ /**
+ * @return true if there is an option with given long name
+ *
+ * @param name long name for search
+ */
+ bool HasLongOption(const TString& name) const {
+ return FindLongOption(name) != nullptr;
+ }
+
+ /**
+ * @return true if there is an option with given short name
+ *
+ * @param char short name for search
+ */
+ bool HasCharOption(char c) const {
+ return FindCharOption(c) != nullptr;
+ }
+
+ /**
+ * Search for the option with given long name
+ * @param name long name for search
+ * @return ref on result (throw exception if not found)
+ */
+ const TOpt& GetLongOption(const TStringBuf& name) const;
+
+ /**
+ * Search for the option with given long name
+ * @param name long name for search
+ * @return ref on result (throw exception if not found)
+ */
+ TOpt& GetLongOption(const TStringBuf& name);
+
+ /**
+ * Search for the option with given short name
+ * @param c short name for search
+ * @return ref on result (throw exception if not found)
+ */
+ const TOpt& GetCharOption(char c) const;
+
+ /**
+ * Search for the option with given short name
+ * @param c short name for search
+ * @return ref on result (throw exception if not found)
+ */
+ TOpt& GetCharOption(char c);
+
+ /**
+ * Search for the option with given name
+ * @param name name for search
+ * @return ref on result (throw exception if not found)
+ */
+ /// @{
+
+ const TOpt& GetOption(const TStringBuf& name) const {
+ return GetLongOption(name);
+ }
+
+ TOpt& GetOption(const TStringBuf& name) {
+ return GetLongOption(name);
+ }
+
+ const TOpt& GetOption(char c) const {
+ return GetCharOption(c);
+ }
+
+ TOpt& GetOption(char c) {
+ return GetCharOption(c);
+ }
+
+ /// @}
+
+ /**
+ * @return true if short options exist
+ */
+ bool HasAnyShortOption() const;
+
+ /**
+ * @return true if long options exist
+ */
+ bool HasAnyLongOption() const;
+
+ /**
+ * Creates new [option description (TOpt)] as a copy of given one
+ * @param option source
+ * @return reference for created option
+ */
+ TOpt& AddOption(const TOpt& option);
+
+ /**
+ * Creates new free argument handling
+ * @param name name of free arg to show in help
+ * @param target variable address to store parsing result into
+ * @param help help string to show in help
+ */
+ template <typename T>
+ void AddFreeArgBinding(const TString& name, T& target, const TString& help = "") {
+ ArgBindings_.emplace_back([&target](TStringBuf value) {
+ target = FromString<T>(value);
+ });
+
+ FreeArgsMax_ = Max<ui32>(FreeArgsMax_, ArgBindings_.size());
+ SetFreeArgTitle(ArgBindings_.size() - 1, name, help);
+ }
+
+ /**
+ * Creates options list from string as in getopt(3)
+ *
+ * @param optstring source
+ */
+ void AddCharOptions(const TStringBuf& optstring);
+
+ /**
+ * Creates new [option description (TOpt)] with given short name and given help string
+ *
+ * @param c short name
+ * @param help help string
+ * @return reference for created option
+ */
+ TOpt& AddCharOption(char c, const TString& help = "") {
+ return AddCharOption(c, DEFAULT_HAS_ARG, help);
+ }
+
+ /**
+ * Creates new [option description (TOpt)] with given short name and given help string
+ *
+ * @param c short name
+ * @param help help string
+ * @return reference for created option
+ */
+ TOpt& AddCharOption(char c, EHasArg hasArg, const TString& help = "") {
+ TOpt option;
+ option.AddShortName(c);
+ option.Help(help);
+ option.HasArg(hasArg);
+ return AddOption(option);
+ }
+
+ /**
+ * Creates new [option description (TOpt)] with given long name and given help string
+ *
+ * @param name long name
+ * @param help help string
+ * @return reference for created option
+ */
+ TOpt& AddLongOption(const TString& name, const TString& help = "") {
+ return AddLongOption(0, name, help);
+ }
+
+ /**
+ * Creates new [option description (TOpt)] with given long and short names and given help string
+ *
+ * @param c short name
+ * @param name long name
+ * @param help help string
+ * @return reference for created option
+ */
+ TOpt& AddLongOption(char c, const TString& name, const TString& help = "") {
+ TOpt option;
+ if (c != 0)
+ option.AddShortName(c);
+ option.AddLongName(name);
+ option.Help(help);
+ return AddOption(option);
+ }
+
+ /**
+ * Creates new [option description (TOpt)] for help printing,
+ * adds appropriate handler for it
+ * If "help" option already exist, will add given short name to it.
+ *
+ * @param c new short name for help option
+ */
+ TOpt& AddHelpOption(char c = '?') {
+ if (TOpt* o = FindLongOption("help")) {
+ if (!o->CharIs(c))
+ o->AddShortName(c);
+ return *o;
+ }
+ return AddLongOption(c, "help", "print usage")
+ .HasArg(NO_ARGUMENT)
+ .IfPresentDisableCompletion()
+ .Handler(&PrintUsageAndExit);
+ }
+
+ /**
+ * Creates new [option description (TOpt)] for svn-revision printing,
+ * adds appropriate handler for it.
+ * If "svnversion" option already exist, will add given short name to it.
+ *
+ * @param c new short name for "svnversion" option
+ */
+ TOpt& AddVersionOption(char c = 'V') {
+ if (TOpt* o = FindLongOption("svnrevision")) {
+ if (!o->CharIs(c))
+ o->AddShortName(c);
+ return *o;
+ }
+ return AddLongOption(c, "svnrevision", "print svn version")
+ .HasArg(NO_ARGUMENT)
+ .IfPresentDisableCompletion()
+ .Handler(&PrintVersionAndExit);
+ }
+
+ /**
+ * Creates new option for generating completion shell scripts.
+ *
+ * @param command name of command that should be completed (typically corresponds to the executable name).
+ */
+ TOpt& AddCompletionOption(TString command, TString longName = "completion");
+
+ /**
+ * Creates or finds option with given short name
+ *
+ * @param c new short name for search/create
+ */
+ TOpt& CharOption(char c) {
+ const TOpt* opt = FindCharOption(c);
+ if (opt != nullptr) {
+ return const_cast<TOpt&>(*opt);
+ } else {
+ AddCharOption(c);
+ return const_cast<TOpt&>(GetCharOption(c));
+ }
+ }
+
+ /**
+ * Indicate that some options can't appear together.
+ *
+ * Note: this is not transitive.
+ *
+ * Note: don't use this on options with default values. If option with default value wasn't specified,
+ * parser will run handlers for default value, thus triggering a false-positive exclusivity check.
+ */
+ template <typename T1, typename T2>
+ void MutuallyExclusive(T1&& opt1, T2&& opt2) {
+ MutuallyExclusiveOpt(GetOption(std::forward<T1>(opt1)), GetOption(std::forward<T2>(opt2)));
+ }
+
+ /**
+ * Like `MutuallyExclusive`, but accepts `TOpt`s instead of option names.
+ */
+ void MutuallyExclusiveOpt(TOpt& opt1, TOpt& opt2);
+
+ /**
+ * @return index of option
+ *
+ * @param opt pointer of option to search
+ */
+ size_t IndexOf(const TOpt* opt) const;
+
+ /**
+ * Replace help string with given
+ *
+ * @param decr new help string
+ */
+ void SetCmdLineDescr(const TString& descr) {
+ CustomCmdLineDescr = descr;
+ }
+
+ /**
+ * Replace usage string with given
+ *
+ * @param usage new usage string
+ */
+ void SetCustomUsage(const TString& usage) {
+ CustomUsage = usage;
+ }
+
+ /**
+ * Add a section to print after the main usage spec.
+ */
+ void AddSection(TString title, TString text) {
+ Sections.emplace_back(std::move(title), std::move(text));
+ }
+
+ /**
+ * Add section with examples.
+ *
+ * @param examples text of this section
+ */
+ void SetExamples(TString examples) {
+ AddSection("Examples", std::move(examples));
+ }
+
+ /**
+ * Set minimal number of free args
+ *
+ * @param min new value
+ */
+ void SetFreeArgsMin(size_t min) {
+ FreeArgsMin_ = ui32(min);
+ }
+
+
+ /**
+ * Get current minimal number of free args
+ */
+ ui32 GetFreeArgsMin() const {
+ return FreeArgsMin_;
+ }
+
+ /**
+ * Set maximal number of free args
+ *
+ * @param max new value
+ */
+ void SetFreeArgsMax(size_t max) {
+ FreeArgsMax_ = ui32(max);
+ FreeArgsMax_ = Max<ui32>(FreeArgsMax_, ArgBindings_.size());
+ }
+
+ /**
+ * Get current maximal number of free args
+ */
+ ui32 GetFreeArgsMax() const {
+ return FreeArgsMax_;
+ }
+
+ /**
+ * Get mapping for free args
+ */
+ const TMap<ui32, TFreeArgSpec>& GetFreeArgSpecs() const {
+ return FreeArgSpecs_;
+ }
+
+ /**
+ * Set exact expected number of free args
+ *
+ * @param count new value
+ */
+ void SetFreeArgsNum(size_t count) {
+ FreeArgsMin_ = ui32(count);
+ FreeArgsMax_ = ui32(count);
+ }
+
+ /**
+ * Set minimal and maximal number of free args
+ *
+ * @param min new value for minimal
+ * @param max new value for maximal
+ */
+ void SetFreeArgsNum(size_t min, size_t max) {
+ FreeArgsMin_ = ui32(min);
+ FreeArgsMax_ = ui32(max);
+ }
+
+ /**
+ * Set title and help string of free argument
+ *
+ * @param pos index of argument
+ * @param title new value for argument title
+ * @param help new value for help string
+ * @param optional indicates that the flag's help string should be rendered as for optional flag;
+ * does not affect actual flags parsing
+ */
+ void SetFreeArgTitle(size_t pos, const TString& title, const TString& help = TString(), bool optional = false);
+
+ /**
+ * Get free argument's spec for further modification.
+ */
+ TFreeArgSpec& GetFreeArgSpec(size_t pos);
+
+ /**
+ * Legacy, don't use. Same as `SetTrailingArgTitle`.
+ * Older versions of lastgetopt didn't have destinction between default title and title
+ * for the trailing argument.
+ */
+ void SetFreeArgDefaultTitle(const TString& title, const TString& help = TString()) {
+ SetTrailingArgTitle(title, help);
+ }
+
+ /**
+ * Set default title that will be used for all arguments that have no title.
+ */
+ void SetDefaultFreeArgTitle(TString title) {
+ DefaultFreeArgTitle_ = std::move(title);
+ }
+
+ /**
+ * Set default title that will be used for all arguments that have no title.
+ */
+ const TString& GetDefaultFreeArgTitle() const {
+ return DefaultFreeArgTitle_;
+ }
+
+ /**
+ * Set title and help for the trailing argument.
+ *
+ * This title and help are used to render the last repeated argument when max number of arguments is unlimited.
+ */
+ /// @{
+ void SetTrailingArgTitle(TString title) {
+ TrailingArgSpec_.Title(std::move(title));
+ }
+ void SetTrailingArgTitle(TString title, TString help) {
+ TrailingArgSpec_.Title(std::move(title));
+ TrailingArgSpec_.Help(std::move(help));
+ }
+ /// @}
+
+ /**
+ * Get spec for the trailing argument.
+ *
+ * This spec is used to render the last repeated argument when max number of arguments is unlimited.
+ */
+ /// @{
+ TFreeArgSpec& GetTrailingArgSpec() {
+ return TrailingArgSpec_;
+ }
+ const TFreeArgSpec& GetTrailingArgSpec() const {
+ return TrailingArgSpec_;
+ }
+ /// @}
+
+ /**
+ * Set the rule of parsing single dash as prefix of long names
+ *
+ * @param value new value of the option
+ */
+ void SetAllowSingleDashForLong(bool value) {
+ AllowSingleDashForLong_ = value;
+ }
+
+ /**
+ * Wrap help text at this number of characters. 0 to disable wrapping.
+ */
+ void SetWrap(ui32 wrap = 80) {
+ Wrap_ = wrap;
+ }
+
+ /**
+ * Print usage string
+ *
+ * @param program prefix of result (path to the program)
+ * @param os destination stream
+ * @param colors colorizer
+ */
+ void PrintUsage(const TStringBuf& program, IOutputStream& os, const NColorizer::TColors& colors) const;
+
+ /**
+ * Print usage string
+ *
+ * @param program prefix of result (path to the program)
+ * @param os destination stream
+ */
+ void PrintUsage(const TStringBuf& program, IOutputStream& os = Cout) const;
+
+ /**
+ * Get list of options in order of definition.
+ */
+ TVector<const TOpt*> GetOpts() const {
+ auto ret = TVector<const TOpt*>(Reserve(Opts_.size()));
+ for (auto& opt : Opts_) {
+ ret.push_back(opt.Get());
+ }
+ return ret;
+ }
+
+ private:
+ /**
+ * @return argument title of a free argument
+ *
+ * @param pos position of the argument
+ */
+ TStringBuf GetFreeArgTitle(size_t pos) const;
+
+ /**
+ * Print usage helper
+ *
+ * @param program prefix of result (path to the program)
+ * @param os destination stream
+ * @param colors colorizer
+ */
+ void PrintCmdLine(const TStringBuf& program, IOutputStream& os, const NColorizer::TColors& colors) const;
+
+ /**
+ * Print usage helper
+ *
+ * @param os destination stream
+ * @param colors colorizer
+ */
+ void PrintFreeArgsDesc(IOutputStream& os, const NColorizer::TColors& colors) const;
+ };
+
+}
diff --git a/library/cpp/getopt/small/last_getopt_parse_result.cpp b/library/cpp/getopt/small/last_getopt_parse_result.cpp
new file mode 100644
index 0000000000..f4b5607a90
--- /dev/null
+++ b/library/cpp/getopt/small/last_getopt_parse_result.cpp
@@ -0,0 +1,160 @@
+#include "last_getopt_parse_result.h"
+
+namespace NLastGetopt {
+ const TOptParseResult* TOptsParseResult::FindParseResult(const TdVec& vec, const TOpt* opt) {
+ for (const auto& r : vec) {
+ if (r.OptPtr() == opt)
+ return &r;
+ }
+ return nullptr;
+ }
+
+ const TOptParseResult* TOptsParseResult::FindOptParseResult(const TOpt* opt, bool includeDefault) const {
+ const TOptParseResult* r = FindParseResult(Opts_, opt);
+ if (nullptr == r && includeDefault)
+ r = FindParseResult(OptsDef_, opt);
+ return r;
+ }
+
+ const TOptParseResult* TOptsParseResult::FindLongOptParseResult(const TString& name, bool includeDefault) const {
+ return FindOptParseResult(&Parser_->Opts_->GetLongOption(name), includeDefault);
+ }
+
+ const TOptParseResult* TOptsParseResult::FindCharOptParseResult(char c, bool includeDefault) const {
+ return FindOptParseResult(&Parser_->Opts_->GetCharOption(c), includeDefault);
+ }
+
+ bool TOptsParseResult::Has(const TOpt* opt, bool includeDefault) const {
+ Y_ASSERT(opt);
+ return FindOptParseResult(opt, includeDefault) != nullptr;
+ }
+
+ bool TOptsParseResult::Has(const TString& name, bool includeDefault) const {
+ return FindLongOptParseResult(name, includeDefault) != nullptr;
+ }
+
+ bool TOptsParseResult::Has(char c, bool includeDefault) const {
+ return FindCharOptParseResult(c, includeDefault) != nullptr;
+ }
+
+ const char* TOptsParseResult::Get(const TOpt* opt, bool includeDefault) const {
+ Y_ASSERT(opt);
+ const TOptParseResult* r = FindOptParseResult(opt, includeDefault);
+ if (!r || r->Empty()) {
+ try {
+ throw TUsageException() << "option " << opt->ToShortString() << " is unspecified";
+ } catch (...) {
+ HandleError();
+ // unreachable
+ throw;
+ }
+ } else {
+ return r->Back();
+ }
+ }
+
+ const char* TOptsParseResult::GetOrElse(const TOpt* opt, const char* defaultValue) const {
+ Y_ASSERT(opt);
+ const TOptParseResult* r = FindOptParseResult(opt);
+ if (!r || r->Empty()) {
+ return defaultValue;
+ } else {
+ return r->Back();
+ }
+ }
+
+ const char* TOptsParseResult::Get(const TString& name, bool includeDefault) const {
+ return Get(&Parser_->Opts_->GetLongOption(name), includeDefault);
+ }
+
+ const char* TOptsParseResult::Get(char c, bool includeDefault) const {
+ return Get(&Parser_->Opts_->GetCharOption(c), includeDefault);
+ }
+
+ const char* TOptsParseResult::GetOrElse(const TString& name, const char* defaultValue) const {
+ if (!Has(name))
+ return defaultValue;
+ return Get(name);
+ }
+
+ const char* TOptsParseResult::GetOrElse(char c, const char* defaultValue) const {
+ if (!Has(c))
+ return defaultValue;
+ return Get(c);
+ }
+
+ TOptParseResult& TOptsParseResult::OptParseResult() {
+ const TOpt* opt = Parser_->CurOpt();
+ Y_ASSERT(opt);
+ TdVec& opts = Parser_->IsExplicit() ? Opts_ : OptsDef_;
+ if (Parser_->IsExplicit()) // default options won't appear twice
+ for (auto& it : opts)
+ if (it.OptPtr() == opt)
+ return it;
+ opts.push_back(TOptParseResult(opt));
+ return opts.back();
+ }
+
+ TString TOptsParseResult::GetProgramName() const {
+ return Parser_->ProgramName_;
+ }
+
+ void TOptsParseResult::PrintUsage(IOutputStream& os) const {
+ Parser_->Opts_->PrintUsage(Parser_->ProgramName_, os);
+ }
+
+ size_t TOptsParseResult::GetFreeArgsPos() const {
+ return Parser_->Pos_;
+ }
+
+ TVector<TString> TOptsParseResult::GetFreeArgs() const {
+ TVector<TString> v;
+ for (size_t i = GetFreeArgsPos(); i < Parser_->Argc_; ++i) {
+ v.push_back(Parser_->Argv_[i]);
+ }
+ return v;
+ }
+
+ size_t TOptsParseResult::GetFreeArgCount() const {
+ return Parser_->Argc_ - GetFreeArgsPos();
+ }
+
+ void TOptsParseResult::Init(const TOpts* options, int argc, const char** argv) {
+ try {
+ Parser_.Reset(new TOptsParser(options, argc, argv));
+ while (Parser_->Next()) {
+ TOptParseResult& r = OptParseResult();
+ r.AddValue(Parser_->CurValOrOpt().data());
+ }
+
+ Y_ENSURE(options);
+ const auto freeArgs = GetFreeArgs();
+ for (size_t i = 0; i < freeArgs.size(); ++i) {
+ if (i >= options->ArgBindings_.size()) {
+ break;
+ }
+
+ options->ArgBindings_[i](freeArgs[i]);
+ }
+ } catch (...) {
+ HandleError();
+ }
+ }
+
+ void TOptsParseResult::HandleError() const {
+ Cerr << CurrentExceptionMessage() << Endl;
+ if (Parser_.Get()) { // parser initializing can fail (and we get here, see Init)
+ if (Parser_->Opts_->FindLongOption("help") != nullptr) {
+ Cerr << "Try '" << Parser_->ProgramName_ << " --help' for more information." << Endl;
+ } else {
+ PrintUsage();
+ }
+ }
+ exit(1);
+ }
+
+ void TOptsParseResultException::HandleError() const {
+ throw;
+ }
+
+}
diff --git a/library/cpp/getopt/small/last_getopt_parse_result.h b/library/cpp/getopt/small/last_getopt_parse_result.h
new file mode 100644
index 0000000000..1ab6f598c9
--- /dev/null
+++ b/library/cpp/getopt/small/last_getopt_parse_result.h
@@ -0,0 +1,321 @@
+#pragma once
+
+#include "last_getopt_opts.h"
+#include "last_getopt_parser.h"
+
+namespace NLastGetopt {
+ /**
+ * NLastGetopt::TOptParseResult contains all arguments for exactly one TOpt,
+ * that have been fetched during parsing
+ *
+ * The class is a wraper over a vector of nil-terminated strings.
+ */
+ class TOptParseResult {
+ public:
+ typedef TVector<const char*> TValues;
+
+ public:
+ TOptParseResult(const TOpt* opt = nullptr)
+ : Opt_(opt)
+ {
+ }
+
+ public:
+ const TOpt& Opt() const {
+ return *Opt_;
+ }
+ const TOpt* OptPtr() const {
+ return Opt_;
+ }
+ const TValues& Values() const {
+ return Values_;
+ }
+ bool Empty() const {
+ return Values().empty();
+ }
+ size_t Count() const {
+ return Values_.size();
+ }
+ void AddValue(const char* val) {
+ if (nullptr != val)
+ Values_.push_back(val);
+ }
+ const char* DefVal(const char* def = nullptr) const {
+ return Opt().HasDefaultValue() ? Opt().GetDefaultValue().c_str() : def;
+ }
+ const char* Front(const char* def = nullptr) const {
+ return Empty() ? DefVal(def) : Values().front();
+ }
+ const char* Back(const char* def = nullptr) const {
+ return Empty() ? DefVal(def) : Values().back();
+ }
+
+ private:
+ const TOpt* Opt_;
+ TValues Values_;
+ };
+
+ /**
+ * NLastGetopt::TOptsParseResult contains result of parsing argc,argv be parser.
+ *
+ * In most common case constructed by argc,argv pair and rules (TOpts).
+ * The instance being constructed validates rules and performs parsing, stores result for futher access.
+ *
+ * If error during parsing occures, the program aborts with exit code 1.
+ * Note, that if PERMUTE mode is on, then data, pointed by argv can be changed.
+ */
+ class TOptsParseResult {
+ private:
+ THolder<TOptsParser> Parser_; //The instance of parser.
+
+ // XXX: make argc, argv
+ typedef TVector<TOptParseResult> TdVec;
+
+ TdVec Opts_; //Parsing result for all options, that have been explicitly defined in argc/argv
+ TdVec OptsDef_; //Parsing result for options, that have been defined by default values only
+
+ private:
+ TOptParseResult& OptParseResult();
+
+ /**
+ * Searchs for object in given container
+ *
+ * @param vec container
+ * @param opt ptr for required object
+ *
+ * @retunr ptr on corresponding TOptParseResult
+ */
+ static const TOptParseResult* FindParseResult(const TdVec& vec, const TOpt* opt);
+
+ protected:
+ /**
+ * Performs parsing of comand line arguments.
+ */
+ void Init(const TOpts* options, int argc, const char** argv);
+
+ TOptsParseResult() = default;
+
+ public:
+ /**
+ * The action in case of parser failure.
+ * Allows to asjust behavior in derived classes.
+ * By default prints error string and aborts the program
+ */
+ virtual void HandleError() const;
+
+ /**
+ * Constructs object by parsing arguments with given rules
+ *
+ * @param options ptr on parsing rules
+ * @param argc
+ * @param argv
+ */
+ TOptsParseResult(const TOpts* options, int argc, const char* argv[]) {
+ Init(options, argc, argv);
+ }
+
+ /**
+ * Constructs object by parsing arguments with given rules
+ *
+ * @param options ptr on parsing rules
+ * @param argc
+ * @param argv
+ */
+ TOptsParseResult(const TOpts* options, int argc, char* argv[]) {
+ Init(options, argc, const_cast<const char**>(argv));
+ }
+
+ virtual ~TOptsParseResult() = default;
+
+ /**
+ * Search for TOptParseResult that corresponds to given option (TOpt)
+ *
+ * @param opt ptr on required object
+ * @param includeDefault search in results obtained from default values
+ *
+ * @return ptr on result
+ */
+ const TOptParseResult* FindOptParseResult(const TOpt* opt, bool includeDefault = false) const;
+
+ /**
+ * Search for TOptParseResult that corresponds to given long name
+ *
+ * @param name long name of required object
+ * @param includeDefault search in results obtained from default values
+ *
+ * @return ptr on result
+ */
+ const TOptParseResult* FindLongOptParseResult(const TString& name, bool includeDefault = false) const;
+
+ /**
+ * Search for TOptParseResult that corresponds to given short name
+ *
+ * @param c short name of required object
+ * @param includeDefault search in results obtained from default values
+ *
+ * @return ptr on result
+ */
+ const TOptParseResult* FindCharOptParseResult(char c, bool includeDefault = false) const;
+
+ /**
+ * @return argv[0]
+ */
+ TString GetProgramName() const;
+
+ /**
+ * Print usage string.
+ */
+ void PrintUsage(IOutputStream& os = Cout) const;
+
+ /**
+ * @return position in [premuted argv] of the first free argument
+ */
+ size_t GetFreeArgsPos() const;
+
+ /**
+ * @return number of fetched free arguments
+ */
+ size_t GetFreeArgCount() const;
+
+ /**
+ * @return all fetched free arguments
+ */
+ TVector<TString> GetFreeArgs() const;
+
+ /**
+ * @return true if given option exist in results of parsing
+ *
+ * @param opt ptr on required object
+ * @param includeDefault search in results obtained from default values
+ *
+ */
+ bool Has(const TOpt* opt, bool includeDefault = false) const;
+
+ /**
+ * @return nil terminated string on the last fetched argument of givne option
+ *
+ * @param opt ptr on required object
+ * @param includeDefault search in results obtained from default values
+ */
+ const char* Get(const TOpt* opt, bool includeDefault = true) const;
+
+ /**
+ * @return nil terminated string on the last fetched argument of givne option
+ * if option haven't been fetched, given defaultValue will be returned
+ *
+ * @param opt ptr on required object
+ * @param defaultValue
+ */
+ const char* GetOrElse(const TOpt* opt, const char* defaultValue) const;
+
+ /**
+ * @return true if given option exist in results of parsing
+ *
+ * @param name long name of required object
+ * @param includeDefault search in results obtained from default values
+ *
+ */
+ bool Has(const TString& name, bool includeDefault = false) const;
+
+ /**
+ * @return nil terminated string on the last fetched argument of givne option
+ *
+ * @param name long name of required object
+ * @param includeDefault search in results obtained from default values
+ */
+ const char* Get(const TString& name, bool includeDefault = true) const;
+
+ /**
+ * @return nil terminated string on the last fetched argument of givne option
+ * if option haven't been fetched, given defaultValue will be returned
+ *
+ * @param name long name of required object
+ * @param defaultValue
+ */
+ const char* GetOrElse(const TString& name, const char* defaultValue) const;
+
+ /**
+ * @return true if given option exist in results of parsing
+ *
+ * @param c short name of required object
+ * @param includeDefault search in results obtained from default values
+ *
+ */
+ bool Has(char name, bool includeDefault = false) const;
+
+ /**
+ * @return nil terminated string on the last fetched argument of givne option
+ *
+ * @param c short name of required object
+ * @param includeDefault search in results obtained from default values
+ */
+ const char* Get(char name, bool includeDefault = true) const;
+
+ /**
+ * @return nil terminated string on the last fetched argument of givne option
+ * if option haven't been fetched, given defaultValue will be returned
+ *
+ * @param c short name of required object
+ * @param defaultValue
+ */
+ const char* GetOrElse(char name, const char* defaultValue) const;
+
+ /**
+ * for givne option return parsed value of the last fetched argument
+ * if option haven't been fetched, HandleError action is called
+ *
+ * @param opt required option (one of: ptr, short name, long name).
+ *
+ * @return FromString<T>(last feteched argument)
+ */
+ template <typename T, typename TKey>
+ T Get(const TKey opt) const {
+ const char* value = Get(opt);
+ try {
+ return NPrivate::OptFromString<T>(value, opt);
+ } catch (...) {
+ HandleError();
+ throw;
+ }
+ }
+
+ /**
+ * for givne option return parsed value of the last fetched argument
+ * if option haven't been fetched, given defaultValue will be returned
+ *
+ * @param opt required option (one of: ptr, short name, long name).
+ * @param defaultValue
+ *
+ * @return FromString<T>(last feteched argument)
+ */
+ template <typename T, typename TKey>
+ T GetOrElse(const TKey opt, const T& defaultValue) const {
+ if (Has(opt))
+ return Get<T>(opt);
+ else
+ return defaultValue;
+ }
+ };
+
+ /**
+ * NLastGetopt::TOptsParseResultException contains result of parsing argc,argv be parser.
+ *
+ * Unlike TOptsParseResult, if error during parsing occures, an exception is thrown.
+ *
+ */
+ class TOptsParseResultException: public TOptsParseResult {
+ public:
+ TOptsParseResultException(const TOpts* options, int argc, const char* argv[]) {
+ Init(options, argc, argv);
+ }
+ TOptsParseResultException(const TOpts* options, int argc, char* argv[]) {
+ Init(options, argc, const_cast<const char**>(argv));
+ }
+ virtual ~TOptsParseResultException() = default;
+ void HandleError() const override;
+
+ protected:
+ TOptsParseResultException() = default;
+ };
+
+}
diff --git a/library/cpp/getopt/small/last_getopt_parser.cpp b/library/cpp/getopt/small/last_getopt_parser.cpp
new file mode 100644
index 0000000000..7668b12a03
--- /dev/null
+++ b/library/cpp/getopt/small/last_getopt_parser.cpp
@@ -0,0 +1,389 @@
+#include "last_getopt_parser.h"
+
+#include <library/cpp/colorizer/colors.h>
+
+#include <util/string/escape.h>
+
+namespace NLastGetopt {
+ void TOptsParser::Init(const TOpts* opts, int argc, const char* argv[]) {
+ opts->Validate();
+
+ Opts_ = opts;
+
+ if (argc < 1)
+ throw TUsageException() << "argv must have at least one argument";
+
+ Argc_ = argc;
+ Argv_ = argv;
+
+ ProgramName_ = argv[0];
+
+ Pos_ = 1;
+ Sop_ = 0;
+ CurrentOpt_ = nullptr;
+ CurrentValue_ = nullptr;
+ GotMinusMinus_ = false;
+ Stopped_ = false;
+ OptsSeen_.clear();
+ OptsDefault_.clear();
+ }
+
+ void TOptsParser::Init(const TOpts* opts, int argc, char* argv[]) {
+ Init(opts, argc, const_cast<const char**>(argv));
+ }
+
+ void TOptsParser::Swap(TOptsParser& that) {
+ DoSwap(Opts_, that.Opts_);
+ DoSwap(Argc_, that.Argc_);
+ DoSwap(Argv_, that.Argv_);
+ DoSwap(TempCurrentOpt_, that.TempCurrentOpt_);
+ DoSwap(ProgramName_, that.ProgramName_);
+ DoSwap(Pos_, that.Pos_);
+ DoSwap(Sop_, that.Sop_);
+ DoSwap(Stopped_, that.Stopped_);
+ DoSwap(CurrentOpt_, that.CurrentOpt_);
+ DoSwap(CurrentValue_, that.CurrentValue_);
+ DoSwap(GotMinusMinus_, that.GotMinusMinus_);
+ DoSwap(OptsSeen_, that.OptsSeen_);
+ }
+
+ bool TOptsParser::Commit(const TOpt* currentOpt, const TStringBuf& currentValue, size_t pos, size_t sop) {
+ Pos_ = pos;
+ Sop_ = sop;
+ CurrentOpt_ = currentOpt;
+ CurrentValue_ = currentValue;
+ if (nullptr != currentOpt)
+ OptsSeen_.insert(currentOpt);
+ return true;
+ }
+
+ bool TOptsParser::CommitEndOfOptions(size_t pos) {
+ Pos_ = pos;
+ Sop_ = 0;
+ Y_ASSERT(!CurOpt());
+ Y_ASSERT(!CurVal());
+
+ Y_ASSERT(!Stopped_);
+
+ if (Opts_->FreeArgsMin_ == Opts_->FreeArgsMax_ && Argc_ - Pos_ != Opts_->FreeArgsMin_)
+ throw TUsageException() << "required exactly " << Opts_->FreeArgsMin_ << " free args";
+ else if (Argc_ - Pos_ < Opts_->FreeArgsMin_)
+ throw TUsageException() << "required at least " << Opts_->FreeArgsMin_ << " free args";
+ else if (Argc_ - Pos_ > Opts_->FreeArgsMax_)
+ throw TUsageException() << "required at most " << Opts_->FreeArgsMax_ << " free args";
+
+ return false;
+ }
+
+ bool TOptsParser::ParseUnknownShortOptWithinArg(size_t pos, size_t sop) {
+ Y_ASSERT(pos < Argc_);
+ const TStringBuf arg(Argv_[pos]);
+ Y_ASSERT(sop > 0);
+ Y_ASSERT(sop < arg.length());
+ Y_ASSERT(EIO_NONE != IsOpt(arg));
+
+ if (!Opts_->AllowUnknownCharOptions_)
+ throw TUsageException() << "unknown option '" << EscapeC(arg[sop])
+ << "' in '" << arg << "'";
+
+ TempCurrentOpt_.Reset(new TOpt);
+ TempCurrentOpt_->AddShortName(arg[sop]);
+
+ sop += 1;
+
+ // mimic behavior of Opt: unknown option has arg only if char is last within arg
+ if (sop < arg.length()) {
+ return Commit(TempCurrentOpt_.Get(), nullptr, pos, sop);
+ }
+
+ pos += 1;
+ sop = 0;
+ if (pos == Argc_ || EIO_NONE != IsOpt(Argv_[pos])) {
+ return Commit(TempCurrentOpt_.Get(), nullptr, pos, 0);
+ }
+
+ return Commit(TempCurrentOpt_.Get(), Argv_[pos], pos + 1, 0);
+ }
+
+ bool TOptsParser::ParseShortOptWithinArg(size_t pos, size_t sop) {
+ Y_ASSERT(pos < Argc_);
+ const TStringBuf arg(Argv_[pos]);
+ Y_ASSERT(sop > 0);
+ Y_ASSERT(sop < arg.length());
+ Y_ASSERT(EIO_NONE != IsOpt(arg));
+
+ size_t p = sop;
+ char c = arg[p];
+ const TOpt* opt = Opts_->FindCharOption(c);
+ if (!opt)
+ return ParseUnknownShortOptWithinArg(pos, sop);
+ p += 1;
+ if (p == arg.length()) {
+ return ParseOptParam(opt, pos + 1);
+ }
+ if (opt->GetHasArg() == NO_ARGUMENT) {
+ return Commit(opt, nullptr, pos, p);
+ }
+ return Commit(opt, arg.SubStr(p), pos + 1, 0);
+ }
+
+ bool TOptsParser::ParseShortOptArg(size_t pos) {
+ Y_ASSERT(pos < Argc_);
+ const TStringBuf arg(Argv_[pos]);
+ Y_ASSERT(EIO_NONE != IsOpt(arg));
+ Y_ASSERT(!arg.StartsWith("--"));
+ return ParseShortOptWithinArg(pos, 1);
+ }
+
+ bool TOptsParser::ParseOptArg(size_t pos) {
+ Y_ASSERT(pos < Argc_);
+ TStringBuf arg(Argv_[pos]);
+ const EIsOpt eio = IsOpt(arg);
+ Y_ASSERT(EIO_NONE != eio);
+ if (EIO_DDASH == eio || EIO_PLUS == eio || (Opts_->AllowSingleDashForLong_ || !Opts_->HasAnyShortOption())) {
+ // long option
+ bool singleCharPrefix = EIO_DDASH != eio;
+ arg.Skip(singleCharPrefix ? 1 : 2);
+ TStringBuf optionName = arg.NextTok('=');
+ const TOpt* option = Opts_->FindLongOption(optionName);
+ if (!option) {
+ if (singleCharPrefix && !arg.IsInited()) {
+ return ParseShortOptArg(pos);
+ } else if (Opts_->AllowUnknownLongOptions_) {
+ return false;
+ } else {
+ throw TUsageException() << "unknown option '" << optionName
+ << "' in '" << Argv_[pos] << "'";
+ }
+ }
+ if (arg.IsInited()) {
+ if (option->GetHasArg() == NO_ARGUMENT)
+ throw TUsageException() << "option " << optionName << " must have no arg";
+ return Commit(option, arg, pos + 1, 0);
+ }
+ ++pos;
+ return ParseOptParam(option, pos);
+ } else {
+ return ParseShortOptArg(pos);
+ }
+ }
+
+ bool TOptsParser::ParseOptParam(const TOpt* opt, size_t pos) {
+ Y_ASSERT(opt);
+ if (opt->GetHasArg() == NO_ARGUMENT) {
+ return Commit(opt, nullptr, pos, 0);
+ }
+ if (pos == Argc_) {
+ if (opt->GetHasArg() == REQUIRED_ARGUMENT)
+ throw TUsageException() << "option " << opt->ToShortString() << " must have arg";
+ return Commit(opt, nullptr, pos, 0);
+ }
+ const TStringBuf arg(Argv_[pos]);
+ if (!arg.StartsWith('-') || opt->GetHasArg() == REQUIRED_ARGUMENT) {
+ return Commit(opt, arg, pos + 1, 0);
+ }
+ return Commit(opt, nullptr, pos, 0);
+ }
+
+ TOptsParser::EIsOpt TOptsParser::IsOpt(const TStringBuf& arg) const {
+ EIsOpt eio = EIO_NONE;
+ if (1 < arg.length()) {
+ switch (arg[0]) {
+ default:
+ break;
+ case '-':
+ if ('-' != arg[1])
+ eio = EIO_SDASH;
+ else if (2 < arg.length())
+ eio = EIO_DDASH;
+ break;
+ case '+':
+ if (Opts_->AllowPlusForLong_)
+ eio = EIO_PLUS;
+ break;
+ }
+ }
+ return eio;
+ }
+
+ static void memrotate(void* ptr, size_t size, size_t shift) {
+ TTempBuf buf(shift);
+ memcpy(buf.Data(), (char*)ptr + size - shift, shift);
+ memmove((char*)ptr + shift, ptr, size - shift);
+ memcpy(ptr, buf.Data(), shift);
+ }
+
+ bool TOptsParser::ParseWithPermutation() {
+ Y_ASSERT(Sop_ == 0);
+ Y_ASSERT(Opts_->ArgPermutation_ == PERMUTE);
+
+ const size_t p0 = Pos_;
+
+ size_t pc = Pos_;
+
+ for (; pc < Argc_ && EIO_NONE == IsOpt(Argv_[pc]); ++pc) {
+ // count non-args
+ }
+
+ if (pc == Argc_) {
+ return CommitEndOfOptions(Pos_);
+ }
+
+ Pos_ = pc;
+
+ bool r = ParseOptArg(Pos_);
+ Y_ASSERT(r);
+ while (Pos_ == pc) {
+ Y_ASSERT(Sop_ > 0);
+ r = ParseShortOptWithinArg(Pos_, Sop_);
+ Y_ASSERT(r);
+ }
+
+ size_t p2 = Pos_;
+
+ Y_ASSERT(p2 - pc >= 1);
+ Y_ASSERT(p2 - pc <= 2);
+
+ memrotate(Argv_ + p0, (p2 - p0) * sizeof(void*), (p2 - pc) * sizeof(void*));
+
+ bool r2 = ParseOptArg(p0);
+ Y_ASSERT(r2);
+ return r2;
+ }
+
+ bool TOptsParser::DoNext() {
+ Y_ASSERT(Pos_ <= Argc_);
+
+ if (Pos_ == Argc_)
+ return CommitEndOfOptions(Pos_);
+
+ if (GotMinusMinus_ && Opts_->ArgPermutation_ == RETURN_IN_ORDER) {
+ Y_ASSERT(Sop_ == 0);
+ return Commit(nullptr, Argv_[Pos_], Pos_ + 1, 0);
+ }
+
+ if (Sop_ > 0)
+ return ParseShortOptWithinArg(Pos_, Sop_);
+
+ size_t pos = Pos_;
+ const TStringBuf arg(Argv_[pos]);
+ if (EIO_NONE != IsOpt(arg)) {
+ return ParseOptArg(pos);
+ } else if (arg == "--") {
+ if (Opts_->ArgPermutation_ == RETURN_IN_ORDER) {
+ pos += 1;
+ if (pos == Argc_)
+ return CommitEndOfOptions(pos);
+ GotMinusMinus_ = true;
+ return Commit(nullptr, Argv_[pos], pos + 1, 0);
+ } else {
+ return CommitEndOfOptions(pos + 1);
+ }
+ } else if (Opts_->ArgPermutation_ == RETURN_IN_ORDER) {
+ return Commit(nullptr, arg, pos + 1, 0);
+ } else if (Opts_->ArgPermutation_ == REQUIRE_ORDER) {
+ return CommitEndOfOptions(Pos_);
+ } else {
+ return ParseWithPermutation();
+ }
+ }
+
+ bool TOptsParser::Next() {
+ bool r = false;
+
+ if (OptsDefault_.empty()) {
+ CurrentOpt_ = nullptr;
+ TempCurrentOpt_.Destroy();
+
+ CurrentValue_ = nullptr;
+
+ if (Stopped_)
+ return false;
+
+ TOptsParser copy = *this;
+
+ r = copy.DoNext();
+
+ Swap(copy);
+
+ if (!r) {
+ Stopped_ = true;
+ // we are done; check for missing options
+ Finish();
+ }
+ }
+
+ if (!r && !OptsDefault_.empty()) {
+ CurrentOpt_ = OptsDefault_.front();
+ CurrentValue_ = CurrentOpt_->GetDefaultValue();
+ OptsDefault_.pop_front();
+ r = true;
+ }
+
+ if (r) {
+ if (CurOpt())
+ CurOpt()->FireHandlers(this);
+ }
+
+ return r;
+ }
+
+ void TOptsParser::Finish() {
+ const TOpts::TOptsVector& optvec = Opts_->Opts_;
+ if (optvec.size() == OptsSeen_.size())
+ return;
+
+ TVector<TString> missingLong;
+ TVector<char> missingShort;
+
+ TOpts::TOptsVector::const_iterator it;
+ for (it = optvec.begin(); it != optvec.end(); ++it) {
+ const TOpt* opt = (*it).Get();
+ if (nullptr == opt)
+ continue;
+ if (OptsSeen_.contains(opt))
+ continue;
+
+ if (opt->IsRequired()) {
+ const TOpt::TLongNames& optnames = opt->GetLongNames();
+ if (!optnames.empty())
+ missingLong.push_back(optnames[0]);
+ else {
+ const char ch = opt->GetCharOr0();
+ if (0 != ch)
+ missingShort.push_back(ch);
+ }
+ continue;
+ }
+
+ if (opt->HasDefaultValue())
+ OptsDefault_.push_back(opt);
+ }
+
+ // also indicates subsequent options, if any, haven't been seen actually
+ OptsSeen_.clear();
+
+ const size_t nmissing = missingLong.size() + missingShort.size();
+ if (0 == nmissing)
+ return;
+
+ TUsageException usage;
+ usage << "The following option";
+ usage << ((1 == nmissing) ? " is" : "s are");
+ usage << " required:";
+ for (size_t i = 0; i != missingLong.size(); ++i)
+ usage << " --" << missingLong[i];
+ for (size_t i = 0; i != missingShort.size(); ++i)
+ usage << " -" << missingShort[i];
+ throw usage; // don't need lineinfo, just the message
+ }
+
+ void TOptsParser::PrintUsage(IOutputStream& os, const NColorizer::TColors& colors) const {
+ Opts_->PrintUsage(ProgramName(), os, colors);
+ }
+
+ void TOptsParser::PrintUsage(IOutputStream& os) const {
+ PrintUsage(os, NColorizer::AutoColors(os));
+ }
+
+}
diff --git a/library/cpp/getopt/small/last_getopt_parser.h b/library/cpp/getopt/small/last_getopt_parser.h
new file mode 100644
index 0000000000..2cf8a6c308
--- /dev/null
+++ b/library/cpp/getopt/small/last_getopt_parser.h
@@ -0,0 +1,154 @@
+#pragma once
+
+#include "last_getopt_opts.h"
+
+#include <library/cpp/colorizer/fwd.h>
+
+#include <util/generic/hash_set.h>
+#include <util/generic/list.h>
+
+namespace NLastGetopt {
+ /**
+* NLastGetopt::TOptsParser is an implementation of parsing
+* argv/argv into TOptsParseResult by rules of TOpts.
+*
+* The class allows to make complicated handlers.
+* Note, that if PERMUTE mode is on, then data, pointed by argv can be changed.
+*/
+ class TOptsParser {
+ enum EIsOpt {
+ EIO_NONE, //is not an option name
+ EIO_SDASH, //single-dashed ('-c') option name
+ EIO_DDASH, //double-dashed ("--opt") option name
+ EIO_PLUS, //plus prefix ("+opt") option name
+ };
+
+ public: // TODO: make private
+ const TOpts* Opts_; //rules of parsing
+
+ // argc/argv pair
+ size_t Argc_;
+ const char** Argv_;
+
+ private:
+ //the storage of last unkown options. TODO: can be moved to local-method scope
+ TCopyPtr<TOpt> TempCurrentOpt_;
+
+ public:
+ //storage of argv[0]
+ TString ProgramName_;
+
+ //state of parsing:
+
+ size_t Pos_; // current element withing argv
+ size_t Sop_; // current char within arg
+ bool Stopped_;
+ bool GotMinusMinus_; //true if "--" have been seen in argv
+
+ protected:
+ const TOpt* CurrentOpt_; // ptr on the last meeted option
+ TStringBuf CurrentValue_; // the value of the last met argument (corresponding to CurrentOpt_)
+
+ private:
+ typedef THashSet<const TOpt*> TdOptSet;
+ TdOptSet OptsSeen_; //the set of options that have been met during parsing
+
+ TList<const TOpt*> OptsDefault_;
+
+ private:
+ void Init(const TOpts* options, int argc, const char* argv[]);
+ void Init(const TOpts* options, int argc, char* argv[]);
+
+ bool CommitEndOfOptions(size_t pos);
+ bool Commit(const TOpt* currentOption, const TStringBuf& currentValue, size_t pos, size_t sop);
+
+ bool ParseShortOptArg(size_t pos);
+ bool ParseOptArg(size_t pos);
+ bool ParseOptParam(const TOpt* opt, size_t pos);
+ bool ParseUnknownShortOptWithinArg(size_t pos, size_t sop);
+ bool ParseShortOptWithinArg(size_t pos, size_t sop);
+ bool ParseWithPermutation();
+
+ bool DoNext();
+ void Finish();
+
+ EIsOpt IsOpt(const TStringBuf& arg) const;
+
+ void Swap(TOptsParser& that);
+
+ public:
+ TOptsParser(const TOpts* options, int argc, const char* argv[]) {
+ Init(options, argc, argv);
+ }
+
+ TOptsParser(const TOpts* options, int argc, char* argv[]) {
+ Init(options, argc, argv);
+ }
+
+ /// fetch next argument, false if no more arguments left
+ bool Next();
+
+ bool Seen(const TOpt* opt) const {
+ return OptsSeen_.contains(opt);
+ }
+
+ bool Seen(TStringBuf name) const {
+ if (auto opt = Opts_->FindLongOption(name)) {
+ return Seen(opt);
+ } else {
+ return false;
+ }
+ }
+
+ bool Seen(char name) const {
+ if (auto opt = Opts_->FindCharOption(name)) {
+ return Seen(opt);
+ } else {
+ return false;
+ }
+ }
+
+ const TOpt* CurOpt() const {
+ return CurrentOpt_;
+ }
+
+ const char* CurVal() const {
+ return CurrentValue_.data();
+ }
+
+ const TStringBuf& CurValStr() const {
+ return CurrentValue_;
+ }
+
+ TStringBuf CurValOrOpt() const {
+ TStringBuf val(CurValStr());
+ if (!val.IsInited() && CurOpt()->HasOptionalValue())
+ val = CurOpt()->GetOptionalValue();
+ return val;
+ }
+
+ TStringBuf CurValOrDef(bool useDef = true) const {
+ TStringBuf val(CurValOrOpt());
+ if (!val.IsInited() && useDef && CurOpt()->HasDefaultValue())
+ val = CurOpt()->GetDefaultValue();
+ return val;
+ }
+
+ // true if this option was actually specified by the user
+ bool IsExplicit() const {
+ return nullptr == CurrentOpt_ || !OptsSeen_.empty();
+ }
+
+ bool CurrentIs(const TString& name) const {
+ return CurOpt()->NameIs(name);
+ }
+
+ const TString& ProgramName() const {
+ return ProgramName_;
+ }
+
+ void PrintUsage(IOutputStream& os = Cout) const;
+
+ void PrintUsage(IOutputStream& os, const NColorizer::TColors& colors) const;
+ };
+} //namespace NLastGetopt
diff --git a/library/cpp/getopt/small/last_getopt_support.h b/library/cpp/getopt/small/last_getopt_support.h
new file mode 100644
index 0000000000..17bed3e614
--- /dev/null
+++ b/library/cpp/getopt/small/last_getopt_support.h
@@ -0,0 +1,178 @@
+#pragma once
+
+#include <util/string/cast.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/generic/utility.h>
+#include <util/generic/yexception.h>
+
+namespace NLastGetopt {
+ class TOpt;
+ class TOpts;
+ class TOptsParser;
+ class TOptsParseResult;
+
+ /// base of all getopt exceptions
+ class TException: public yexception {
+ };
+
+ /// TOpts configuration is incorrect
+ class TConfException: public TException {
+ };
+
+ /// User passed incorrect arguments, parsing failed
+ /// Note: use `throw TUsageException()` instead of `ythrow TUsageException()` to prevent appearence of stacktrace
+ /// and location of the `ythrow` statment in error messages.
+ class TUsageException: public TException {
+ };
+
+ struct IOptHandler {
+ virtual void HandleOpt(const TOptsParser* parser) = 0;
+ virtual ~IOptHandler() = default;
+ };
+
+ namespace NPrivate {
+ template <typename TpFunc>
+ class THandlerFunctor0
+ : public IOptHandler {
+ TpFunc Func_;
+
+ public:
+ THandlerFunctor0(TpFunc func)
+ : Func_(func)
+ {
+ }
+
+ void HandleOpt(const TOptsParser*) override {
+ Func_();
+ }
+ };
+
+ template <typename TpFunc, typename TpArg = const TOptsParser*>
+ class THandlerFunctor1
+ : public IOptHandler {
+ TpFunc Func_;
+ const TpArg Def_;
+ const bool HasDef_;
+
+ public:
+ THandlerFunctor1(TpFunc func)
+ : Func_(func)
+ , Def_()
+ , HasDef_(false)
+ {
+ }
+
+ template <typename T>
+ THandlerFunctor1(const TpFunc& func, const T& def)
+ : Func_(func)
+ , Def_(def)
+ , HasDef_(true)
+ {
+ }
+
+ void HandleOpt(const TOptsParser* parser) override;
+ };
+
+ template <typename TpFunc>
+ class THandlerFunctor1<TpFunc, const TOptsParser*>
+ : public IOptHandler {
+ TpFunc Func_;
+
+ public:
+ THandlerFunctor1(TpFunc func)
+ : Func_(func)
+ {
+ }
+
+ void HandleOpt(const TOptsParser* parser) override {
+ Func_(parser);
+ }
+ };
+
+ template <typename T, typename TpVal = T>
+ class TStoreResultFunctor {
+ private:
+ T* Target_;
+
+ public:
+ TStoreResultFunctor(T* target)
+ : Target_(target)
+ {
+ }
+
+ void operator()(const TpVal& val) {
+ *Target_ = val;
+ }
+ };
+
+ template <typename TpTarget, typename TpFunc, typename TpVal = TpTarget>
+ class TStoreMappedResultFunctor {
+ private:
+ TpTarget* Target_;
+ const TpFunc Func_;
+
+ public:
+ TStoreMappedResultFunctor(TpTarget* target, const TpFunc& func)
+ : Target_(target)
+ , Func_(func)
+ {
+ }
+
+ void operator()(const TpVal& val) {
+ *Target_ = Func_(val);
+ }
+ };
+
+ template <typename T, typename TpVal = T>
+ class TStoreValueFunctor {
+ T* Target;
+ const TpVal Value;
+
+ public:
+ template <typename TpArg>
+ TStoreValueFunctor(T* target, const TpArg& value)
+ : Target(target)
+ , Value(value)
+ {
+ }
+
+ void operator()(const TOptsParser*) {
+ *Target = Value;
+ }
+ };
+
+ TString OptToString(char c);
+ TString OptToString(const TString& longOption);
+ TString OptToString(const TOpt* opt);
+
+ template <typename T>
+ inline T OptFromStringImpl(const TStringBuf& value) {
+ return FromString<T>(value);
+ }
+
+ template <>
+ inline TStringBuf OptFromStringImpl<TStringBuf>(const TStringBuf& value) {
+ return value;
+ }
+
+ template <>
+ inline const char* OptFromStringImpl<const char*>(const TStringBuf& value) {
+ return value.data();
+ }
+
+ template <typename T, typename TSomeOpt>
+ T OptFromString(const TStringBuf& value, const TSomeOpt opt) {
+ try {
+ return OptFromStringImpl<T>(value);
+ } catch (...) {
+ throw TUsageException() << "failed to parse opt " << OptToString(opt) << " value " << TString(value).Quote() << ": " << CurrentExceptionMessage();
+ }
+ }
+
+ // wrapper of FromString<T> that prints nice message about option used
+ template <typename T, typename TSomeOpt>
+ T OptFromString(const TStringBuf& value, const TSomeOpt opt);
+
+ }
+}
diff --git a/library/cpp/getopt/small/modchooser.cpp b/library/cpp/getopt/small/modchooser.cpp
new file mode 100644
index 0000000000..2fa5cfd070
--- /dev/null
+++ b/library/cpp/getopt/small/modchooser.cpp
@@ -0,0 +1,372 @@
+#include "completer.h"
+#include "completer_command.h"
+#include "completion_generator.h"
+#include "last_getopt.h"
+#include "modchooser.h"
+
+#include <library/cpp/colorizer/colors.h>
+
+#include <util/stream/output.h>
+#include <util/stream/format.h>
+#include <util/generic/yexception.h>
+#include <util/generic/ptr.h>
+#include <util/string/builder.h>
+#include <util/string/join.h>
+
+class PtrWrapper: public TMainClass {
+public:
+ explicit PtrWrapper(const TMainFunctionPtr main)
+ : Main(main)
+ {
+ }
+
+ int operator()(const int argc, const char** argv) override {
+ return Main(argc, argv);
+ }
+
+private:
+ TMainFunctionPtr Main;
+};
+
+class PtrvWrapper: public TMainClass {
+public:
+ explicit PtrvWrapper(const TMainFunctionPtrV main)
+ : Main(main)
+ {
+ }
+
+ int operator()(const int argc, const char** argv) override {
+ TVector<TString> nargv(argv, argv + argc);
+ return Main(nargv);
+ }
+
+private:
+ TMainFunctionPtrV Main;
+};
+
+class ClassWrapper: public TMainClass {
+public:
+ explicit ClassWrapper(TMainClassV* main)
+ : Main(main)
+ {
+ }
+
+ int operator()(const int argc, const char** argv) override {
+ TVector<TString> nargv(argv, argv + argc);
+ return (*Main)(nargv);
+ }
+
+private:
+ TMainClassV* Main;
+};
+
+TModChooser::TMode::TMode(const TString& name, TMainClass* main, const TString& descr, bool hidden, bool noCompletion)
+ : Name(name)
+ , Main(main)
+ , Description(descr)
+ , Hidden(hidden)
+ , NoCompletion(noCompletion)
+{
+}
+
+TModChooser::TModChooser()
+ : ModesHelpOption("-?") // Default help option in last_getopt
+ , VersionHandler(nullptr)
+ , ShowSeparated(true)
+ , SvnRevisionOptionDisabled(false)
+ , PrintShortCommandInUsage(false)
+{
+}
+
+TModChooser::~TModChooser() = default;
+
+void TModChooser::AddMode(const TString& mode, const TMainFunctionRawPtr func, const TString& description, bool hidden, bool noCompletion) {
+ AddMode(mode, TMainFunctionPtr(func), description, hidden, noCompletion);
+}
+
+void TModChooser::AddMode(const TString& mode, const TMainFunctionRawPtrV func, const TString& description, bool hidden, bool noCompletion) {
+ AddMode(mode, TMainFunctionPtrV(func), description, hidden, noCompletion);
+}
+
+void TModChooser::AddMode(const TString& mode, const TMainFunctionPtr func, const TString& description, bool hidden, bool noCompletion) {
+ Wrappers.push_back(MakeHolder<PtrWrapper>(func));
+ AddMode(mode, Wrappers.back().Get(), description, hidden, noCompletion);
+}
+
+void TModChooser::AddMode(const TString& mode, const TMainFunctionPtrV func, const TString& description, bool hidden, bool noCompletion) {
+ Wrappers.push_back(MakeHolder<PtrvWrapper>(func));
+ AddMode(mode, Wrappers.back().Get(), description, hidden, noCompletion);
+}
+
+void TModChooser::AddMode(const TString& mode, TMainClass* func, const TString& description, bool hidden, bool noCompletion) {
+ if (Modes.FindPtr(mode)) {
+ ythrow yexception() << "TMode '" << mode << "' already exists in TModChooser.";
+ }
+
+ Modes[mode] = UnsortedModes.emplace_back(MakeHolder<TMode>(mode, func, description, hidden, noCompletion)).Get();
+}
+
+void TModChooser::AddMode(const TString& mode, TMainClassV* func, const TString& description, bool hidden, bool noCompletion) {
+ Wrappers.push_back(MakeHolder<ClassWrapper>(func));
+ AddMode(mode, Wrappers.back().Get(), description, hidden, noCompletion);
+}
+
+void TModChooser::AddGroupModeDescription(const TString& description, bool hidden, bool noCompletion) {
+ UnsortedModes.push_back(MakeHolder<TMode>(TString(), nullptr, description.data(), hidden, noCompletion));
+}
+
+void TModChooser::SetDefaultMode(const TString& mode) {
+ DefaultMode = mode;
+}
+
+void TModChooser::AddAlias(const TString& alias, const TString& mode) {
+ if (!Modes.FindPtr(mode)) {
+ ythrow yexception() << "TMode '" << mode << "' not found in TModChooser.";
+ }
+
+ Modes[mode]->Aliases.push_back(alias);
+ Modes[alias] = Modes[mode];
+}
+
+void TModChooser::SetDescription(const TString& descr) {
+ Description = descr;
+}
+
+void TModChooser::SetModesHelpOption(const TString& helpOption) {
+ ModesHelpOption = helpOption;
+}
+
+void TModChooser::SetVersionHandler(TVersionHandlerPtr handler) {
+ VersionHandler = handler;
+}
+
+void TModChooser::SetSeparatedMode(bool separated) {
+ ShowSeparated = separated;
+}
+
+void TModChooser::SetSeparationString(const TString& str) {
+ SeparationString = str;
+}
+
+void TModChooser::SetPrintShortCommandInUsage(bool printShortCommandInUsage = false) {
+ PrintShortCommandInUsage = printShortCommandInUsage;
+}
+
+void TModChooser::DisableSvnRevisionOption() {
+ SvnRevisionOptionDisabled = true;
+}
+
+void TModChooser::AddCompletions(TString progName, const TString& name, bool hidden, bool noCompletion) {
+ if (CompletionsGenerator == nullptr) {
+ CompletionsGenerator = NLastGetopt::MakeCompletionMod(this, std::move(progName), name);
+ AddMode(name, CompletionsGenerator.Get(), "generate autocompletion files", hidden, noCompletion);
+ }
+}
+
+int TModChooser::Run(const int argc, const char** argv) const {
+ Y_ENSURE(argc, "Can't run TModChooser with empty list of arguments.");
+
+ bool shiftArgs = true;
+ TString modeName;
+ if (argc == 1) {
+ if (DefaultMode.empty()) {
+ PrintHelp(argv[0]);
+ return 0;
+ } else {
+ modeName = DefaultMode;
+ shiftArgs = false;
+ }
+ } else {
+ modeName = argv[1];
+ }
+
+ if (modeName == "-h" || modeName == "--help" || modeName == "-?") {
+ PrintHelp(argv[0]);
+ return 0;
+ }
+ if (VersionHandler && (modeName == "-v" || modeName == "--version")) {
+ VersionHandler();
+ return 0;
+ }
+ if (!SvnRevisionOptionDisabled && modeName == "--svnrevision") {
+ NLastGetopt::PrintVersionAndExit(nullptr);
+ }
+
+ auto modeIter = Modes.find(modeName);
+ if (modeIter == Modes.end() && !DefaultMode.empty()) {
+ modeIter = Modes.find(DefaultMode);
+ shiftArgs = false;
+ }
+
+ if (modeIter == Modes.end()) {
+ Cerr << "Unknown mode " << modeName.Quote() << "." << Endl;
+ PrintHelp(argv[0]);
+ return 1;
+ }
+
+ if (shiftArgs) {
+ TString firstArg;
+ TVector<const char*> nargv(Reserve(argc));
+
+ if (PrintShortCommandInUsage) {
+ firstArg = modeIter->second->Name;
+ } else {
+ firstArg = argv[0] + TString(" ") + modeIter->second->Name;
+ }
+
+ nargv.push_back(firstArg.data());
+
+ for (int i = 2; i < argc; ++i) {
+ nargv.push_back(argv[i]);
+ }
+ // According to the standard, "argv[argc] shall be a null pointer" (5.1.2.2.1).
+ // http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1336
+ nargv.push_back(nullptr);
+
+ return (*modeIter->second->Main)(nargv.size() - 1, nargv.data());
+ } else {
+ return (*modeIter->second->Main)(argc, argv);
+ }
+}
+
+int TModChooser::Run(const TVector<TString>& argv) const {
+ TVector<const char*> nargv(Reserve(argv.size() + 1));
+ for (auto& arg : argv) {
+ nargv.push_back(arg.c_str());
+ }
+ // According to the standard, "argv[argc] shall be a null pointer" (5.1.2.2.1).
+ // http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1336
+ nargv.push_back(nullptr);
+
+ return Run(nargv.size() - 1, nargv.data());
+}
+
+size_t TModChooser::TMode::CalculateFullNameLen() const {
+ size_t len = Name.size();
+ if (Aliases) {
+ len += 2;
+ for (auto& alias : Aliases) {
+ len += alias.size() + 1;
+ }
+ }
+ return len;
+}
+
+TString TModChooser::TMode::FormatFullName(size_t pad) const {
+ TStringBuilder name;
+ if (Aliases) {
+ name << "{";
+ }
+
+ name << NColorizer::StdErr().GreenColor();
+ name << Name;
+ name << NColorizer::StdErr().OldColor();
+
+ if (Aliases) {
+ for (const auto& alias : Aliases) {
+ name << "|" << NColorizer::StdErr().GreenColor() << alias << NColorizer::StdErr().OldColor();
+ }
+ name << "}";
+ }
+
+ auto len = CalculateFullNameLen();
+ if (pad > len) {
+ name << TString(" ") * (pad - len);
+ }
+
+ return name;
+}
+
+void TModChooser::PrintHelp(const TString& progName) const {
+ Cerr << Description << Endl << Endl;
+ Cerr << NColorizer::StdErr().BoldColor() << "Usage" << NColorizer::StdErr().OldColor() << ": " << progName << " MODE [MODE_OPTIONS]" << Endl;
+ Cerr << Endl;
+ Cerr << NColorizer::StdErr().BoldColor() << "Modes" << NColorizer::StdErr().OldColor() << ":" << Endl;
+ size_t maxModeLen = 0;
+ for (const auto& [name, mode] : Modes) {
+ if (name != mode->Name)
+ continue; // this is an alias
+ maxModeLen = Max(maxModeLen, mode->CalculateFullNameLen());
+ }
+
+ if (ShowSeparated) {
+ for (const auto& unsortedMode : UnsortedModes)
+ if (!unsortedMode->Hidden) {
+ if (unsortedMode->Name.size()) {
+ Cerr << " " << unsortedMode->FormatFullName(maxModeLen + 4) << unsortedMode->Description << Endl;
+ } else {
+ Cerr << SeparationString << Endl;
+ Cerr << unsortedMode->Description << Endl;
+ }
+ }
+ } else {
+ for (const auto& mode : Modes) {
+ if (mode.first != mode.second->Name)
+ continue; // this is an alias
+
+ if (!mode.second->Hidden) {
+ Cerr << " " << mode.second->FormatFullName(maxModeLen + 4) << mode.second->Description << Endl;
+ }
+ }
+ }
+
+ Cerr << Endl;
+ Cerr << "To get help for specific mode type '" << progName << " MODE " << ModesHelpOption << "'" << Endl;
+ if (VersionHandler)
+ Cerr << "To print program version type '" << progName << " --version'" << Endl;
+ if (!SvnRevisionOptionDisabled) {
+ Cerr << "To print svn revision type --svnrevision" << Endl;
+ }
+ return;
+}
+
+TVersionHandlerPtr TModChooser::GetVersionHandler() const {
+ return VersionHandler;
+}
+
+bool TModChooser::IsSvnRevisionOptionDisabled() const {
+ return SvnRevisionOptionDisabled;
+}
+
+int TMainClassArgs::Run(int argc, const char** argv) {
+ return DoRun(NLastGetopt::TOptsParseResult(&GetOptions(), argc, argv));
+}
+
+const NLastGetopt::TOpts& TMainClassArgs::GetOptions() {
+ if (Opts_.Empty()) {
+ Opts_ = NLastGetopt::TOpts();
+ RegisterOptions(Opts_.GetRef());
+ }
+
+ return Opts_.GetRef();
+}
+
+void TMainClassArgs::RegisterOptions(NLastGetopt::TOpts& opts) {
+ opts.AddHelpOption('h');
+}
+
+int TMainClassArgs::operator()(const int argc, const char** argv) {
+ return Run(argc, argv);
+}
+
+int TMainClassModes::operator()(const int argc, const char** argv) {
+ return Run(argc, argv);
+}
+
+int TMainClassModes::Run(int argc, const char** argv) {
+ auto& chooser = GetSubModes();
+ return chooser.Run(argc, argv);
+}
+
+const TModChooser& TMainClassModes::GetSubModes() {
+ if (Modes_.Empty()) {
+ Modes_.ConstructInPlace();
+ RegisterModes(Modes_.GetRef());
+ }
+
+ return Modes_.GetRef();
+}
+
+void TMainClassModes::RegisterModes(TModChooser& modes) {
+ modes.SetModesHelpOption("-h");
+}
diff --git a/library/cpp/getopt/small/modchooser.h b/library/cpp/getopt/small/modchooser.h
new file mode 100644
index 0000000000..0a8de6d50b
--- /dev/null
+++ b/library/cpp/getopt/small/modchooser.h
@@ -0,0 +1,215 @@
+#pragma once
+
+#include "last_getopt_opts.h"
+
+#include <util/generic/map.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+
+#include <functional>
+
+//! Mode function with vector of cli arguments.
+using TMainFunctionPtrV = std::function<int(const TVector<TString>&)> ;
+using TMainFunctionRawPtrV = int (*)(const TVector<TString>& argv);
+
+//! Mode function with classic argc and argv arguments.
+using TMainFunctionPtr = std::function<int(int, const char**)> ;
+using TMainFunctionRawPtr = int (*)(const int argc, const char** argv);
+
+//! Mode class with vector of cli arguments.
+class TMainClassV {
+public:
+ virtual int operator()(const TVector<TString>& argv) = 0;
+ virtual ~TMainClassV() = default;
+};
+
+//! Mode class with classic argc and argv arguments.
+class TMainClass {
+public:
+ virtual int operator()(int argc, const char** argv) = 0;
+ virtual ~TMainClass() = default;
+};
+
+//! Function to handle '--version' parameter
+typedef void (*TVersionHandlerPtr)();
+
+/*! Main class for handling different modes in single tool.
+ *
+ * You can add modes for this class, use autogenerated help with
+ * list of modes and automaticly call necessary mode in run().
+ *
+ * In first argv element mode get joined by space tool name and
+ * current mode name.
+ */
+class TModChooser {
+public:
+ TModChooser();
+ ~TModChooser();
+
+public:
+ void AddMode(const TString& mode, TMainFunctionRawPtr func, const TString& description, bool hidden = false, bool noCompletion = false);
+ void AddMode(const TString& mode, TMainFunctionRawPtrV func, const TString& description, bool hidden = false, bool noCompletion = false);
+ void AddMode(const TString& mode, TMainFunctionPtr func, const TString& description, bool hidden = false, bool noCompletion = false);
+ void AddMode(const TString& mode, TMainFunctionPtrV func, const TString& description, bool hidden = false, bool noCompletion = false);
+ void AddMode(const TString& mode, TMainClass* func, const TString& description, bool hidden = false, bool noCompletion = false);
+ void AddMode(const TString& mode, TMainClassV* func, const TString& description, bool hidden = false, bool noCompletion = false);
+
+ //! Hidden groups won't be displayed in 'help' block
+ void AddGroupModeDescription(const TString& description, bool hidden = false, bool noCompletion = false);
+
+ //! Set default mode (if not specified explicitly)
+ void SetDefaultMode(const TString& mode);
+
+ void AddAlias(const TString& alias, const TString& mode);
+
+ //! Set main program description.
+ void SetDescription(const TString& descr);
+
+ //! Set modes help option name (-? is by default)
+ void SetModesHelpOption(const TString& helpOption);
+
+ //! Specify handler for '--version' parameter
+ void SetVersionHandler(TVersionHandlerPtr handler);
+
+ //! Set description show mode
+ void SetSeparatedMode(bool separated = true);
+
+ //! Set separation string
+ void SetSeparationString(const TString& str);
+
+ //! Set short command representation in Usage block
+ void SetPrintShortCommandInUsage(bool printShortCommandInUsage);
+
+ void DisableSvnRevisionOption();
+
+ void AddCompletions(TString progName, const TString& name = "completion", bool hidden = false, bool noCompletion = false);
+
+ /*! Run appropriate mode.
+ *
+ * In this method following things happen:
+ * 1) If first argument is -h/--help/-? then print short description of
+ * all modes and exit with zero code.
+ * 2) If first argument is -v/--version and version handler is specified,
+ * then call it and exit with zero code.
+ * 3) Find mode with the same name as first argument. If it's found then
+ * call it and return its return code.
+ * 4) If appropriate mode is not found - return non-zero code.
+ */
+ int Run(int argc, const char** argv) const;
+
+ //! Run appropriate mode. Same as Run(const int, const char**)
+ int Run(const TVector<TString>& argv) const;
+
+ void PrintHelp(const TString& progName) const;
+
+ struct TMode {
+ TString Name;
+ TMainClass* Main;
+ TString Description;
+ bool Hidden;
+ bool NoCompletion;
+ TVector<TString> Aliases;
+
+ TMode()
+ : Main(nullptr)
+ {
+ }
+
+ TMode(const TString& name, TMainClass* main, const TString& descr, bool hidden, bool noCompletion);
+
+ // Full name includes primary name and aliases. Also, will add ANSI colors.
+ size_t CalculateFullNameLen() const;
+ TString FormatFullName(size_t pad) const;
+ };
+
+ TVector<const TMode*> GetUnsortedModes() const {
+ auto ret = TVector<const TMode*>(Reserve(UnsortedModes.size()));
+ for (auto& mode : UnsortedModes) {
+ ret.push_back(mode.Get());
+ }
+ return ret;
+ }
+
+ TVersionHandlerPtr GetVersionHandler() const;
+
+ bool IsSvnRevisionOptionDisabled() const;
+
+private:
+ //! Main program description.
+ TString Description;
+
+ //! Help option for modes.
+ TString ModesHelpOption;
+
+ //! Wrappers around all modes.
+ TVector<THolder<TMainClass>> Wrappers;
+
+ //! Modes
+ TMap<TString, TMode*> Modes;
+
+ TString DefaultMode;
+
+ //! Handler for '--version' parameter
+ TVersionHandlerPtr VersionHandler;
+
+ //! When set to true, show descriptions unsorted and display separators
+ bool ShowSeparated;
+
+ //! When set to true, disables --svnrevision option, useful for opensource (git hosted) projects
+ bool SvnRevisionOptionDisabled;
+
+ //! When true - will print only 'mode name' in 'Usage' block
+ bool PrintShortCommandInUsage;
+
+ //! Text string used when displaying each separator
+ TString SeparationString;
+
+ //! Unsorted list of options
+ TVector<THolder<TMode>> UnsortedModes;
+
+ //! Mode that generates completions
+ THolder<TMainClass> CompletionsGenerator;
+};
+
+//! Mode class that allows introspecting its console arguments.
+class TMainClassArgs: public TMainClass {
+public:
+ int operator()(int argc, const char** argv) final;
+
+public:
+ //! Run this mode.
+ int Run(int argc, const char** argv);
+
+ //! Get console arguments for this mode.
+ const NLastGetopt::TOpts& GetOptions();
+
+protected:
+ //! Fill given empty `TOpts` with options.
+ virtual void RegisterOptions(NLastGetopt::TOpts& opts);
+
+ //! Actual mode logic. Takes parsed options and returns exit code.
+ virtual int DoRun(NLastGetopt::TOptsParseResult&& parsedOptions) = 0;
+
+private:
+ TMaybe<NLastGetopt::TOpts> Opts_;
+};
+
+//! Mode class that uses sub-modes to dispatch commands further.
+class TMainClassModes: public TMainClass {
+public:
+ int operator()(int argc, const char** argv) final;
+
+public:
+ //! Run this mode.
+ int Run(int argc, const char** argv);
+
+ //! Get sub-modes for this mode.
+ const TModChooser& GetSubModes();
+
+protected:
+ //! Fill given modchooser with sub-modes.
+ virtual void RegisterModes(TModChooser& modes);
+
+private:
+ TMaybe<TModChooser> Modes_;
+};
diff --git a/library/cpp/getopt/small/opt.cpp b/library/cpp/getopt/small/opt.cpp
new file mode 100644
index 0000000000..744501765c
--- /dev/null
+++ b/library/cpp/getopt/small/opt.cpp
@@ -0,0 +1,119 @@
+#include "opt.h"
+
+#include <util/system/progname.h>
+
+#include <ctype.h>
+
+using namespace NLastGetopt;
+
+namespace {
+ struct TOptsNoDefault: public TOpts {
+ TOptsNoDefault(const TStringBuf& optstring = TStringBuf())
+ : TOpts(optstring)
+ {
+ }
+ };
+
+}
+
+void Opt::Init(int argc, char* argv[], const char* optString, const Ion* longOptions, bool longOnly, bool isOpen) {
+ Ions_ = longOptions;
+ Err = true;
+ GotError_ = false;
+ Ind = argc;
+
+ Opts_.Reset(new TOptsNoDefault(optString));
+ for (const Ion* o = longOptions; o != nullptr && o->name != nullptr; ++o) {
+ TOpt* opt;
+ if ((unsigned)o->val < 0x80 && isalnum(o->val)) {
+ opt = &Opts_->CharOption(char(o->val));
+ opt->AddLongName(o->name);
+ } else {
+ Opts_->AddLongOption(o->name);
+ opt = const_cast<TOpt*>(&Opts_->GetLongOption(o->name));
+ }
+ opt->HasArg_ = EHasArg(o->has_arg);
+ opt->UserValue(o);
+ }
+ Opts_->AllowSingleDashForLong_ = longOnly;
+ Opts_->AllowPlusForLong_ = true;
+ Opts_->AllowUnknownCharOptions_ = isOpen;
+ Opts_->AllowUnknownLongOptions_ = false;
+
+ OptsParser_.Reset(new TOptsParser(Opts_.Get(), argc, argv));
+}
+
+Opt::Opt(int argc, char* argv[], const char* optString, const Ion* longOptions, bool longOnly, bool isOpen) {
+ Init(argc, argv, optString, longOptions, longOnly, isOpen);
+}
+
+Opt::Opt(int argc, const char* argv[], const char* optString, const Ion* longOptions, bool longOnly, bool isOpen) {
+ Init(argc, (char**)argv, optString, longOptions, longOnly, isOpen);
+}
+
+int Opt::Get() {
+ return Get(nullptr);
+}
+
+int Opt::Get(int* longOptionIndex) {
+ if (GotError_)
+ return EOF;
+
+ Arg = nullptr;
+
+ try {
+ bool r = OptsParser_->Next();
+ Ind = (int)OptsParser_->Pos_;
+ if (!r) {
+ return EOF;
+ } else {
+ Arg = (char*)OptsParser_->CurVal();
+ if (!OptsParser_->CurOpt()) {
+ // possible if RETURN_IN_ORDER
+ return 1;
+ } else {
+ const Ion* ion = (const Ion*)OptsParser_->CurOpt()->UserValue();
+ if (longOptionIndex) {
+ *longOptionIndex = int(ion - Ions_);
+ }
+ char c = OptsParser_->CurOpt()->GetCharOr0();
+ return c != 0 ? c : ion->val;
+ }
+ }
+ } catch (const NLastGetopt::TException&) {
+ GotError_ = true;
+ if (Err)
+ Cerr << CurrentExceptionMessage() << Endl;
+ return '?';
+ }
+}
+
+void Opt::DummyHelp(IOutputStream& os) {
+ Opts_->PrintUsage(GetProgramName(), os);
+}
+
+int Opt::GetArgC() const {
+ return (int)OptsParser_->Argc_;
+}
+
+const char** Opt::GetArgV() const {
+ return OptsParser_->Argv_;
+}
+
+int opt_get_number(int& argc, char* argv[]) {
+ int num = -1;
+ for (int a = 1; a < argc; a++) {
+ if (*argv[a] == '-' && isdigit((ui8)argv[a][1])) {
+ char* ne;
+ num = strtol(argv[a] + 1, &ne, 10);
+ if (*ne) {
+ memmove(argv[a] + 1, ne, strlen(ne) + 1);
+ } else {
+ for (argc--; a < argc; a++)
+ argv[a] = argv[a + 1];
+ }
+ break;
+ }
+ }
+ return num;
+}
diff --git a/library/cpp/getopt/small/opt.h b/library/cpp/getopt/small/opt.h
new file mode 100644
index 0000000000..ecb57439bc
--- /dev/null
+++ b/library/cpp/getopt/small/opt.h
@@ -0,0 +1,142 @@
+#pragma once
+
+#include "last_getopt.h"
+
+#include <util/generic/ptr.h>
+#include <util/generic/noncopyable.h>
+
+// implementation of Opt class using last getopt
+
+/*
+ short-options syntax:
+
+ opt-letter ::=
+ [^: ]
+
+ opt-string ::=
+ '+'|'-'?({opt-letter}':'{0,2})*
+
+ example: "AbCx:y:z::"
+ {A,b,C} options without argument
+ {x,y} options with argument
+ {z} option with optional argument
+
+ 1. shortopts begins with '-' :=> RETURN_IN_ORDER
+ == non-option forces getopt to return 1 and to place non-option into optarg
+
+ 2. shortopts begins with '+' :=> REQUIRE_ORDER
+ GetEnv(_POSIX_OPTION_ORDER) :=> REQUIRE_ORDER
+ == 1st non-option forces getopt to return EOF
+
+ 3. default :=> PERMUTE
+ == exchange options with non-options and place all options first
+
+ 4. '--' command line argument forces getopt to stop parsing and to return EOF
+ in any case
+
+ long options should begin by '+' sign
+ or when (_getopt_long_only = 1) by '-' sign
+
+ struct option {
+ char *name : option name
+ int has_arg: 0 | 1 | 2 = without | with | optional argument
+ int *flag : if (flag != 0) then getopt returns 0 and stores val into *flag
+ int val : if (flag == 0) then getopt returns val
+ }
+
+ Example:
+
+ struct option my_opts[] = {
+ { "delete", 0, &deletion_flag, DEL }, -- returns 0, deletion_flag := DEL
+ { "add", 1, NULL, 'a' }, -- returns 'a', argument in optarg
+ { NULL }
+ }
+*/
+
+#define OPT_RETURN_IN_ORDER "-"
+#define OPT_REQUIRE_ORDER "+"
+#define OPT_DONT_STORE_ARG ((void*)0)
+
+class Opt : TNonCopyable {
+public:
+ enum HasArg { WithoutArg,
+ WithArg,
+ PossibleArg };
+
+ struct Ion {
+ const char* name;
+ HasArg has_arg;
+ int* flag;
+ int val;
+ };
+
+private:
+ THolder<NLastGetopt::TOpts> Opts_;
+ THolder<NLastGetopt::TOptsParser> OptsParser_;
+ const Ion* Ions_;
+ bool GotError_;
+
+ void Init(int argc, char* argv[], const char* optString, const Ion* longOptions = nullptr, bool longOnly = false, bool isOpen = false);
+
+public:
+ Opt(int argc, char* argv[], const char* optString, const Ion* longOptions = nullptr, bool longOnly = false, bool isOpen = false);
+ Opt(int argc, const char* argv[], const char* optString, const Ion* longOptions = nullptr, bool longOnly = false, bool isOpen = false);
+
+ // Get() means next
+ int Get();
+ int Get(int* longOptionIndex);
+ int operator()() {
+ return Get();
+ }
+
+ const char* GetArg() const {
+ return Arg;
+ }
+
+ TVector<TString> GetFreeArgs() const {
+ return NLastGetopt::TOptsParseResult(&*Opts_, GetArgC(), GetArgV()).GetFreeArgs();
+ }
+
+ // obsolete, use GetArg() instead
+ char* Arg; /* option argument if any or NULL */
+
+ int Ind; /* command line index */
+ bool Err; /* flag to print error messages */
+
+ int GetArgC() const;
+ const char** GetArgV() const;
+
+ void DummyHelp(IOutputStream& os = Cerr);
+};
+
+// call before getopt. returns non-negative int, removing it from arguments (not found: -1)
+// Example: returns 11 for "progname -11abc", -1 for "progname -a11"
+int opt_get_number(int& argc, char* argv[]);
+
+#define OPTION_HANDLING_PROLOG \
+ { \
+ int optlet; \
+ while (EOF != (optlet = opt.Get())) { \
+ switch (optlet) {
+#define OPTION_HANDLING_PROLOG_ANON(S) \
+ { \
+ Opt opt(argc, argv, (S)); \
+ int optlet; \
+ while (EOF != (optlet = opt.Get())) { \
+ switch (optlet) {
+#define OPTION_HANDLE_BEGIN(opt) case opt: {
+#define OPTION_HANDLE_END \
+ } \
+ break;
+
+#define OPTION_HANDLE(opt, handle) \
+ OPTION_HANDLE_BEGIN(opt) \
+ handle; \
+ OPTION_HANDLE_END
+
+#define OPTION_HANDLING_EPILOG \
+ default: \
+ ythrow yexception() << "unknown optlet"; \
+ } \
+ } \
+ }
diff --git a/library/cpp/getopt/small/opt2.cpp b/library/cpp/getopt/small/opt2.cpp
new file mode 100644
index 0000000000..0cdc774e78
--- /dev/null
+++ b/library/cpp/getopt/small/opt2.cpp
@@ -0,0 +1,384 @@
+#include "opt2.h"
+
+#include <util/generic/hash.h>
+#include <util/generic/utility.h>
+#include <util/generic/yexception.h>
+#include <util/str_stl.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+
+void Opt2::Clear() {
+ Specs.clear();
+ memset(SpecsMap, 0, sizeof(SpecsMap));
+ Pos.clear();
+}
+
+void Opt2::Init(int argc, char* const* argv, const char* optspec, IntRange free_args_num, const char* long_alias) {
+ Clear();
+ Argc = argc;
+ Argv = argv;
+ HasErrors = false, BadPosCount = false, UnknownOption = 0, OptionMissingArg = 0;
+ UnknownLongOption = nullptr;
+ OptionWrongArg = 0, RequiredOptionMissing = 0;
+ EatArgv(optspec, long_alias);
+ MinArgs = Min<int>(free_args_num.Left, free_args_num.Right);
+ MaxArgs = Max<int>(free_args_num.Left, free_args_num.Right);
+ if (!HasErrors && MinArgs != -1 && ((int)Pos.size() < MinArgs || (int)Pos.size() > MaxArgs))
+ BadPosCount = HasErrors = true;
+}
+
+void Opt2::EatArgv(const char* optspec, const char* long_alias) {
+ // some flags
+ bool require_order = false;
+ if (*optspec == '+') {
+ require_order = true;
+ optspec++;
+ }
+ if (*optspec == '-')
+ ythrow yexception() << "Flag '-' can not be used in Opt2's optspec";
+ // step 1 - parse optspec
+ for (const char* s = optspec; *s; s++) {
+ if (SpecsMap[(ui8)*s])
+ ythrow yexception() << "Symbol '" << *s << "' is met twice in Opt2's optspec";
+ if (*s == '?' || *s == '-')
+ ythrow yexception() << "Opt2: Symbol '" << *s << "' can not be used in optspec because it is reserved";
+ Specs.push_back(Opt2Param());
+ SpecsMap[(ui8)*s] = (ui8)Specs.size(); // actual index + 1
+ Specs.back().opt = *s;
+ if (s[1] == ':') {
+ Specs.back().HasArg = true;
+ if (s[2] == ':')
+ ythrow yexception() << "Opt2 does not accept optional parameters (e.g. \"a::\") in optspec";
+ s++;
+ }
+ }
+ // long_alias has a form "long-name1=A,long-name2=B", etc.
+ // This implementation is limited to aliasing a single long option
+ // with single short option (extend it if you really need).
+ THashMap<const char*, char> long2short;
+ long2short["help"] = '?';
+ long_alias = long_alias ? long_alias : "";
+ alias_copy = long_alias;
+ for (char* s = alias_copy.begin(); s && *s;) {
+ char* eq = strchr(s, '=');
+ char* comma = strchr(s, ',');
+ if (comma)
+ *comma = 0;
+ if (!eq || (comma && comma < eq))
+ ythrow yexception() << "Opt2, long_alias: '=' is expected after " << s;
+ *eq++ = 0;
+ if (!*eq || eq[1])
+ ythrow yexception() << "Opt2, long_alias: single letter must be assigned to " << s;
+ if (!SpecsMap[(ui8)*eq])
+ ythrow yexception() << "Opt2, long_alias: trying to assign unknown option '" << *eq << "' to " << s;
+ Opt2Param& p = Specs[SpecsMap[(ui8)*eq] - 1];
+ // If several long options aliased to some letter, only last one is shown in usage
+ p.LongOptName = s;
+ if (long2short.find(s) != long2short.end())
+ ythrow yexception() << "Opt2, long_alias: " << s << " specified twice";
+ long2short[s] = *eq;
+ s = comma ? comma + 1 : nullptr;
+ }
+
+ if (Argc < 1) {
+ HasErrors = true;
+ return;
+ }
+
+ // step 2 - parse argv
+ int ind = 1;
+ for (; ind != Argc; ind++) {
+ if (*Argv[ind] != '-') {
+ if (require_order) // everything now goes to Pos
+ break;
+ Pos.push_back(Argv[ind]);
+ continue;
+ }
+ const char* s = Argv[ind] + 1;
+
+ if (*s == '-') {
+ if (!*++s) { // `--' terminates the list of options
+ ind++;
+ break;
+ }
+ // long option always spans one argv (--switch or --option-name=value)
+ const char* eq = strchr(s, '=');
+ TString lname(s, eq ? (size_t)(eq - s) : (size_t)strlen(s));
+ THashMap<const char*, char>::iterator i = long2short.find(lname.data());
+ if (i == long2short.end()) {
+ UnknownLongOption = strdup(lname.data()); // free'd in AutoUsage()
+ HasErrors = true;
+ return;
+ }
+ if (i->second == '?') {
+ UnknownOption = '?';
+ HasErrors = true;
+ continue;
+ }
+ Opt2Param& p = Specs[SpecsMap[(ui8)i->second] - 1];
+ p.IsFound = true;
+ if (p.HasArg && !eq) {
+ HasErrors = true;
+ OptionMissingArg = p.opt; // short option, indeed
+ return;
+ }
+ if (!p.HasArg && eq) {
+ HasErrors = true;
+ OptionWrongArg = p.opt; // short option, indeed
+ return;
+ }
+ if (eq)
+ p.ActualValue.push_back(eq + 1);
+ continue;
+ }
+
+ for (; *s; s++) {
+ if (!SpecsMap[(ui8)*s]) {
+ UnknownOption = *s;
+ HasErrors = true;
+ if (*s == '?')
+ continue;
+ return;
+ }
+ Opt2Param& p = Specs[SpecsMap[(ui8)*s] - 1];
+ p.IsFound = true;
+ if (p.HasArg) {
+ if (s[1])
+ p.ActualValue.push_back(s + 1);
+ else {
+ ind++;
+ if (ind == Argc) {
+ HasErrors = true;
+ OptionMissingArg = *s;
+ p.IsFound = false;
+ return;
+ }
+ p.ActualValue.push_back(Argv[ind]);
+ }
+ break;
+ }
+ }
+ }
+ for (; ind != Argc; ind++)
+ Pos.push_back(Argv[ind]);
+}
+
+Opt2Param& Opt2::GetInternal(char opt, const char* defValue, const char* helpUsage, bool requred) {
+ if (!SpecsMap[(ui8)opt])
+ ythrow yexception() << "Unspecified option character '" << opt << "' asked from Opt2::Get";
+ Opt2Param& p = Specs[SpecsMap[(ui8)opt] - 1];
+ p.DefValue = defValue;
+ p.HelpUsage = helpUsage;
+ p.IsRequired = requred;
+ if (!p.IsFound && requred && !HasErrors) {
+ RequiredOptionMissing = opt;
+ HasErrors = true;
+ }
+ return p;
+}
+
+// For options with parameters
+const char* Opt2::Arg(char opt, const char* help, const char* def, bool required) {
+ Opt2Param& p = GetInternal(opt, def, help, required);
+ if (!p.HasArg)
+ ythrow yexception() << "Opt2::Arg called for '" << opt << "' which is an option without argument";
+ return p.IsFound ? p.ActualValue.empty() ? nullptr : p.ActualValue.back() : def;
+}
+
+// For options with parameters
+const char* Opt2::Arg(char opt, const char* help, TString def, bool required) {
+ Opt2Param& p = GetInternal(opt, nullptr, help, required);
+ if (!p.HasArg)
+ ythrow yexception() << "Opt2::Arg called for '" << opt << "' which is an option without argument";
+ p.DefValueStr = def;
+ p.DefValue = p.DefValueStr.begin();
+ return p.IsFound ? p.ActualValue.empty() ? nullptr : p.ActualValue.back() : p.DefValue;
+}
+
+// Options with parameters that can be specified several times
+const TVector<const char*>& Opt2::MArg(char opt, const char* help) {
+ Opt2Param& p = GetInternal(opt, nullptr, help, false);
+ p.MultipleUse = true;
+ if (!p.HasArg)
+ ythrow yexception() << "Opt2::Arg called for '" << opt << "' which is an option without argument";
+ return p.ActualValue;
+}
+
+/// For options w/o parameters
+bool Opt2::Has(char opt, const char* help) {
+ Opt2Param& p = GetInternal(opt, nullptr, help, false);
+ if (p.HasArg)
+ ythrow yexception() << "Opt2::Has called for '" << opt << "' which is an option with argument";
+ return p.IsFound;
+}
+
+// Get() + strtol, may set up HasErrors
+long Opt2::Int(char opt, const char* help, long def, bool required) {
+ Opt2Param& p = GetInternal(opt, (char*)(uintptr_t)def, help, required);
+ if (!p.HasArg)
+ ythrow yexception() << "Opt2::Int called for '" << opt << "' which is an option without argument";
+ p.IsNumeric = true;
+ if (!p.IsFound || p.ActualValue.empty() || !p.ActualValue.back())
+ return def;
+ char* e;
+ long rv = strtol(p.ActualValue.back(), &e, 10);
+ if (e == p.ActualValue.back() || *e) {
+ OptionWrongArg = opt;
+ HasErrors = true;
+ }
+ return rv;
+}
+
+// Get() + strtoul, may set up HasErrors
+unsigned long Opt2::UInt(char opt, const char* help, unsigned long def, bool required) {
+ Opt2Param& p = GetInternal(opt, (char*)(uintptr_t)def, help, required);
+ if (!p.HasArg)
+ ythrow yexception() << "Opt2::UInt called for '" << opt << "' which is an option without argument";
+ p.IsNumeric = true;
+ if (!p.IsFound || p.ActualValue.empty() || !p.ActualValue.back())
+ return def;
+ char* e;
+ unsigned long rv = strtoul(p.ActualValue.back(), &e, 10);
+ if (e == p.ActualValue.back() || *e) {
+ OptionWrongArg = opt;
+ HasErrors = true;
+ }
+ return rv;
+}
+
+// Add user defined error message and set error flag
+void Opt2::AddError(const char* message) {
+ HasErrors = true;
+ if (message)
+ UserErrorMessages.push_back(message);
+}
+
+int Opt2::AutoUsage(const char* free_arg_names) {
+ if (!HasErrors)
+ return 0;
+ FILE* where = UnknownOption == '?' ? stdout : stderr;
+ char req_str[256], nreq_str[256];
+ int req = 0, nreq = 0;
+ for (int n = 0; n < (int)Specs.size(); n++)
+ if (Specs[n].IsRequired)
+ req_str[req++] = Specs[n].opt;
+ else
+ nreq_str[nreq++] = Specs[n].opt;
+ req_str[req] = 0, nreq_str[nreq] = 0;
+ const char* prog = strrchr(Argv[0], LOCSLASH_C);
+ prog = prog ? prog + 1 : Argv[0];
+ fprintf(where, "Usage: %s%s%s%s%s%s%s%s\n", prog, req ? " -" : "", req_str,
+ nreq ? " [-" : "", nreq_str, nreq ? "]" : "",
+ free_arg_names && *free_arg_names ? " " : "", free_arg_names);
+ for (auto& spec : Specs) {
+ const char* hlp = !spec.HelpUsage.empty() ? spec.HelpUsage.data() : spec.HasArg ? "<arg>" : "";
+ if (!spec.HasArg || spec.IsRequired)
+ fprintf(where, " -%c %s\n", spec.opt, hlp);
+ else if (!spec.IsNumeric)
+ fprintf(where, " -%c %s [Default: %s]\n", spec.opt, hlp, spec.DefValue);
+ else
+ fprintf(where, " -%c %s [Def.val: %li]\n", spec.opt, hlp, (long)(uintptr_t)spec.DefValue);
+ if (spec.LongOptName)
+ fprintf(where, " --%s%s - same as -%c\n", spec.LongOptName, spec.HasArg ? "=<argument>" : "", spec.opt);
+ }
+ if (OptionMissingArg)
+ fprintf(where, " *** Option '%c' is missing required argument\n", OptionMissingArg);
+ if (OptionWrongArg)
+ fprintf(where, " *** Incorrect argument for option '%c'\n", OptionWrongArg);
+ if (UnknownOption && UnknownOption != '?')
+ fprintf(where, " *** Unknown option '%c'\n", UnknownOption);
+ if (UnknownLongOption) {
+ fprintf(where, " *** Unknown long option '%s'\n", UnknownLongOption);
+ free(UnknownLongOption);
+ UnknownLongOption = nullptr;
+ }
+ if (RequiredOptionMissing)
+ fprintf(where, " *** Required option '%c' missing\n", RequiredOptionMissing);
+ if (BadPosCount && MinArgs != MaxArgs)
+ fprintf(where, " *** %i free argument(s) supplied, expected %i to %i\n", (int)Pos.size(), MinArgs, MaxArgs);
+ if (BadPosCount && MinArgs == MaxArgs)
+ fprintf(where, " *** %i free argument(s) supplied, expected %i\n", (int)Pos.size(), MinArgs);
+ for (const auto& userErrorMessage : UserErrorMessages)
+ fprintf(where, " *** %s\n", userErrorMessage.data());
+ return UnknownOption == '?' ? 1 : 2;
+}
+
+void Opt2::AutoUsageErr(const char* free_arg_names) {
+ if (AutoUsage(free_arg_names))
+ exit(1);
+}
+
+#ifdef OPT2_TEST
+// TODO: convert it to unittest
+
+bool opt2_ut_fail = false, opt_ut_verbose = false;
+const char* ut_optspec;
+int ut_real(TString args, bool err_exp, const char* A_exp, int b_exp, bool a_exp, const char* p1_exp, const char* p2_exp) {
+ char* argv[32];
+ int argc = sf(' ', argv, args.begin());
+ Opt2 opt(argc, argv, ut_optspec, 2, "option-1=A,option-2=a,");
+ const char* A = opt.Arg('A', "<qqq> - blah");
+ int b = opt.Int('b', "<rrr> - blah", 2);
+ bool a = opt.Has('a', "- blah");
+ /*const char *C = */ opt.Arg('C', "<ccc> - blah", 0);
+
+ if (opt_ut_verbose)
+ opt.AutoUsage("");
+ if (opt.HasErrors != err_exp)
+ return 1;
+ if (err_exp)
+ return false;
+ if (!A && A_exp || A && !A_exp || A && A_exp && strcmp(A, A_exp))
+ return 2;
+ if (b != b_exp)
+ return 3;
+ if (a != a_exp)
+ return 4;
+ if (strcmp(opt.Pos[0], p1_exp))
+ return 5;
+ if (strcmp(opt.Pos[1], p2_exp))
+ return 6;
+ return false;
+}
+
+void ut(const char* args, bool err_exp, const char* A_exp, int b_exp, bool a_exp, const char* p1_exp, const char* p2_exp) {
+ if (opt_ut_verbose)
+ fprintf(stderr, "Testing: %s\n", args);
+ if (int rv = ut_real(args, err_exp, A_exp, b_exp, a_exp, p1_exp, p2_exp)) {
+ opt2_ut_fail = true;
+ fprintf(stderr, "Test %i failed for: %s\n", rv, args);
+ } else {
+ if (opt_ut_verbose)
+ fprintf(stderr, "OK\n");
+ }
+}
+
+int main(int argc, char* argv[]) {
+ Opt2 opt(argc, argv, "v", 0);
+ opt_ut_verbose = opt.Has('v', "- some verboseness");
+ opt.AutoUsageErr("");
+ ut_optspec = "A:ab:C:";
+ ut("prog -A argA -a -b 22 -C argC Pos1 Pos2", false, "argA", 22, true, "Pos1", "Pos2");
+ ut("prog Pos1 -A argA -a -C argC Pos2", false, "argA", 2, true, "Pos1", "Pos2");
+ ut("prog -A argA Pos1 -b22 Pos2 -C argC", false, "argA", 22, false, "Pos1", "Pos2");
+ ut("prog -A argA Pos1 -b 22 Pos2 -C", true, "argA", 22, false, "Pos1", "Pos2");
+ ut("prog -A argA -a -b 22 -C Pos1 Pos2", true, "argA", 22, true, "Pos1", "Pos2");
+ ut("prog -A argA -a -b two -C argC Pos1 Pos2", true, "argA", 2, true, "Pos1", "Pos2");
+ ut("prog -a -b 22 -C argC Pos1 Pos2", true, "argA", 22, true, "Pos1", "Pos2");
+ ut("prog Pos1 --option-1=argA -a -C argC Pos2", false, "argA", 2, true, "Pos1", "Pos2");
+ ut("prog Pos1 -A argA --option-1 -a -C argC Pos2", true, "argA", 2, true, "Pos1", "Pos2");
+ ut("prog -A argA --option-2 -b -22 -C argC Pos1 Pos2", false, "argA", -22, true, "Pos1", "Pos2");
+ ut("prog -A argA --option-2 -b -22 -- -C argC", false, "argA", -22, true, "-C", "argC");
+ ut("prog -A argA --option-2=1 -b -22 -C argC Pos1 Pos2", true, "argA", -22, true, "Pos1", "Pos2");
+
+ ut_optspec = "+A:ab:C:";
+ ut("prog -A argA --option-2 v1 -C", false, "argA", 2, true, "v1", "-C");
+ ut("prog -A argA --option-2 v1 -C argC", true, "argA", 2, true, "v1", "-C");
+ if (!opt2_ut_fail)
+ fprintf(stderr, "All OK\n");
+ return opt2_ut_fail;
+}
+
+#endif // OPT2_TEST
diff --git a/library/cpp/getopt/small/opt2.h b/library/cpp/getopt/small/opt2.h
new file mode 100644
index 0000000000..4d9d943237
--- /dev/null
+++ b/library/cpp/getopt/small/opt2.h
@@ -0,0 +1,137 @@
+#pragma once
+
+#include <util/system/defaults.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+
+// simplified options parser
+// No 'optional argument' (e.g. "a::" in spec.) support;
+// Supports '+' switch (see opt.h), does not support '-';
+
+/** Typical use
+ Opt2 opt(argc, argv, "A:b:c", 3); <- 3 more arguments expected, opt.Pos[0], etc.
+ ** Usage description for options is provided through functions that query values **
+ const char *a = opt.Arg('A', "<var_name> - usage of -A"); <- This option is required
+ int b = opt.Int('b', "<var_name> - usage of -b", 2); <- This option has default value, not required
+ bool c = opt.Has('c', "- usage of -c"); <- switches are always optional
+
+ ** Additional argument names are provided in AutoUsage call **
+ ** AutoUsage generages 'USAGE' text automatically **
+ if (opt.AutoUsage("<L> <M>")) <- Returns 1 if there was any error in getopt
+ return 1;
+ OR: opt.AutoUsageErr("<L> <M>"); <- Will terminate program for you :)
+*/
+
+// Note: struct Opt2Param can be moved to cpp-file
+struct Opt2Param {
+ char opt;
+ bool HasArg;
+ bool IsFound;
+ bool IsNumeric;
+ bool IsRequired;
+ bool MultipleUse;
+ const char* DefValue;
+ TString DefValueStr;
+ TString HelpUsage;
+ TVector<const char*> ActualValue;
+ const char* LongOptName;
+ Opt2Param()
+ : HasArg(false)
+ , IsFound(0)
+ , IsNumeric(0)
+ , IsRequired(0)
+ , MultipleUse(0)
+ , DefValue(nullptr)
+ , LongOptName(nullptr)
+ {
+ }
+};
+
+struct IntRange {
+ int Left, Right;
+ IntRange() = delete;
+ IntRange(int both)
+ : Left(both)
+ , Right(both)
+ {
+ }
+
+ IntRange(int left, int right)
+ : Left(left)
+ , Right(right)
+ {
+ }
+};
+
+class Opt2 {
+public:
+ Opt2() = default;
+
+ Opt2(int argc, char* const* argv, const char* optspec, IntRange free_args_num = -1, const char* long_alias = nullptr) {
+ Init(argc, argv, optspec, free_args_num, long_alias);
+ }
+
+ // Init throws exception only in case of incorrect optspec.
+ // In other cases, consult HasErrors or call AutoUsage()
+ void Init(int argc, char* const* argv, const char* optspec, IntRange free_args_num = -1, const char* long_alias = nullptr);
+
+ // In case of incorrect options, constructs and prints Usage text,
+ // usually to stderr (however, to stdout if '-?' switch was used), and returns 1.
+ int AutoUsage(const char* free_arg_names = "");
+
+ // same as AutoUsage but calls exit(1) instead of error code
+ void AutoUsageErr(const char* free_arg_names = "");
+
+ // For options with parameters
+ const char* Arg(char opt, const char* helpUsage, const char* defValue, bool required = false);
+ const char* Arg(char opt, const char* helpUsage) {
+ return Arg(opt, helpUsage, nullptr, true);
+ }
+ const char* Arg(char opt, const char* helpUsage, TString defValue, bool required = false);
+
+ // Options with parameters that can be specified several times
+ const TVector<const char*>& MArg(char opt, const char* helpUsage);
+
+ // Get() + strtol, may set up HasErrors
+ long Int(char opt, const char* helpUsage, long defValue, bool required = false);
+ long Int(char opt, const char* helpUsage) {
+ return Int(opt, helpUsage, 0, true);
+ }
+
+ // Get() + strtoul, may set up HasErrors
+ unsigned long UInt(char opt, const char* helpUsage, unsigned long defValue, bool required = false);
+ unsigned long UInt(char opt, const char* helpUsage) {
+ return UInt(opt, helpUsage, 0, true);
+ }
+
+ // For options w/o parameters
+ bool Has(char opt, const char* helpUsage);
+
+ // Add user defined error message and set error flag
+ void AddError(const char* message = nullptr);
+
+public:
+ // non-option args
+ TVector<char*> Pos;
+ bool HasErrors;
+
+private:
+ bool BadPosCount;
+ char UnknownOption;
+ char* UnknownLongOption;
+ char OptionMissingArg;
+ char OptionWrongArg;
+ char RequiredOptionMissing;
+ TVector<TString> UserErrorMessages;
+
+protected:
+ int Argc;
+ char* const* Argv;
+ int MinArgs, MaxArgs;
+ ui8 SpecsMap[256];
+ TVector<Opt2Param> Specs;
+ TString alias_copy;
+ void EatArgv(const char* optspec, const char* long_alias);
+ void Clear();
+ Opt2Param& GetInternal(char opt, const char* defValue, const char* helpUsage, bool required);
+};
diff --git a/library/cpp/getopt/small/posix_getopt.cpp b/library/cpp/getopt/small/posix_getopt.cpp
new file mode 100644
index 0000000000..bd06f3499f
--- /dev/null
+++ b/library/cpp/getopt/small/posix_getopt.cpp
@@ -0,0 +1,77 @@
+#include "posix_getopt.h"
+
+#include <util/generic/ptr.h>
+
+#include <ctype.h>
+
+namespace NLastGetopt {
+ char* optarg;
+ int optind;
+ int optopt;
+ int opterr;
+ int optreset;
+
+ static THolder<TOpts> Opts;
+ static THolder<TOptsParser> OptsParser;
+
+ int getopt_long_impl(int argc, char* const* argv, const char* optstring,
+ const struct option* longopts, int* longindex, bool long_only) {
+ if (!Opts || optreset == 1) {
+ optarg = nullptr;
+ optind = 1;
+ opterr = 1;
+ optreset = 0;
+ Opts.Reset(new TOpts(TOpts::Default(optstring)));
+
+ Opts->AllowSingleDashForLong_ = long_only;
+
+ for (const struct option* o = longopts; o != nullptr && o->name != nullptr; ++o) {
+ TOpt* opt;
+ if ((unsigned)o->val < 0x80 && isalnum(o->val)) {
+ opt = &Opts->CharOption(char(o->val));
+ opt->AddLongName(o->name);
+ } else {
+ Opts->AddLongOption(o->name);
+ opt = const_cast<TOpt*>(&Opts->GetLongOption(o->name));
+ }
+ opt->HasArg_ = EHasArg(o->has_arg);
+ opt->UserValue(o->flag);
+ }
+
+ OptsParser.Reset(new TOptsParser(&*Opts, argc, (const char**)argv));
+ }
+
+ optarg = nullptr;
+
+ try {
+ if (!OptsParser->Next()) {
+ return -1;
+ } else {
+ optarg = (char*)OptsParser->CurVal();
+ optind = (int)OptsParser->Pos_;
+ if (longindex && OptsParser->CurOpt())
+ *longindex = (int)Opts->IndexOf(OptsParser->CurOpt());
+ return OptsParser->CurOpt() ? OptsParser->CurOpt()->GetCharOr0() : 1;
+ }
+ } catch (const NLastGetopt::TException&) {
+ return '?';
+ }
+ }
+
+ int getopt_long(int argc, char* const* argv, const char* optstring,
+ const struct option* longopts, int* longindex) {
+ return getopt_long_impl(argc, argv, optstring, longopts, longindex, false);
+ }
+
+ int getopt_long_only(int argc, char* const* argv, const char* optstring,
+ const struct option* longopts, int* longindex) {
+ return getopt_long_impl(argc, argv, optstring, longopts, longindex, true);
+ }
+
+ // XXX: leading colon is not supported
+ // XXX: updating optind by client is not supported
+ int getopt(int argc, char* const* argv, const char* optstring) {
+ return getopt_long(argc, argv, optstring, nullptr, nullptr);
+ }
+
+}
diff --git a/library/cpp/getopt/small/posix_getopt.h b/library/cpp/getopt/small/posix_getopt.h
new file mode 100644
index 0000000000..e6af1e0284
--- /dev/null
+++ b/library/cpp/getopt/small/posix_getopt.h
@@ -0,0 +1,32 @@
+#pragma once
+
+// implementation of posix getopt using last getopt for demonstration purposes
+
+#include "last_getopt.h"
+
+namespace NLastGetopt {
+ extern char* optarg;
+ extern int optind;
+ extern int optopt;
+ extern int opterr;
+ extern int optreset;
+
+ enum {
+ no_argument = NO_ARGUMENT,
+ required_argument = REQUIRED_ARGUMENT,
+ optional_argument = OPTIONAL_ARGUMENT,
+ };
+
+ struct option {
+ const char* name;
+ int has_arg;
+ int* flag;
+ int val;
+ };
+
+ int getopt(int argc, char* const* argv, const char* optstring);
+ int getopt_long(int argc, char* const* argv, const char* optstring,
+ const struct option* longopts, int* longindex);
+ int getopt_long_only(int argc, char* const* argv, const char* optstring,
+ const struct option* longopts, int* longindex);
+}
diff --git a/library/cpp/getopt/small/wrap.cpp b/library/cpp/getopt/small/wrap.cpp
new file mode 100644
index 0000000000..9fbd38842a
--- /dev/null
+++ b/library/cpp/getopt/small/wrap.cpp
@@ -0,0 +1,99 @@
+#include "wrap.h"
+
+#include <library/cpp/colorizer/colors.h>
+
+#include <util/generic/string.h>
+#include <util/stream/str.h>
+#include <util/charset/utf8.h>
+
+#include <cctype>
+
+namespace NLastGetopt {
+ TString Wrap(ui32 width, TStringBuf text, TStringBuf indent, size_t* lastLineLen, bool* hasParagraphs) {
+ if (width == 0) {
+ return TString(text);
+ }
+
+ if (width >= indent.size()) {
+ width -= indent.size();
+ }
+
+ if (hasParagraphs) {
+ *hasParagraphs = false;
+ }
+
+ TString res;
+ auto os = TStringOutput(res);
+
+ const char* spaceBegin = text.begin();
+ const char* wordBegin = text.begin();
+ const char* wordEnd = text.begin();
+ const char* end = text.end();
+
+ size_t lenSoFar = 0;
+
+ bool isPreParagraph = false;
+
+ do {
+ spaceBegin = wordBegin = wordEnd;
+
+ while (wordBegin < end && *wordBegin == ' ') {
+ wordBegin++;
+ }
+
+ if (wordBegin == end) {
+ break;
+ }
+
+ wordEnd = wordBegin;
+
+ while (wordEnd < end && *wordEnd != ' ' && *wordEnd != '\n') {
+ wordEnd++;
+ }
+
+ auto spaces = TStringBuf(spaceBegin, wordBegin);
+ auto word = TStringBuf(wordBegin, wordEnd);
+
+ size_t spaceLen = spaces.size();
+
+ size_t wordLen = 0;
+ if (!GetNumberOfUTF8Chars(word.data(), word.size(), wordLen)) {
+ wordLen = word.size(); // not a utf8 string -- just use its binary size
+ }
+ wordLen -= NColorizer::TotalAnsiEscapeCodeLen(word);
+
+ // Empty word means we've found a bunch of whitespaces followed by newline.
+ // We don't want to print trailing whitespaces.
+ if (word) {
+ // We can't fit this word into the line -- insert additional line break.
+ // We shouldn't insert line breaks if we're at the beginning of a line, hence `lenSoFar` check.
+ if (lenSoFar && lenSoFar + spaceLen + wordLen > width) {
+ os << Endl << indent << word;
+ lenSoFar = wordLen;
+ } else {
+ os << spaces << word;
+ lenSoFar += spaceLen + wordLen;
+ }
+ isPreParagraph = false;
+ }
+
+ if (wordEnd != end && *wordEnd == '\n') {
+ os << Endl << indent;
+ lenSoFar = 0;
+ wordEnd++;
+ if (hasParagraphs && isPreParagraph) {
+ *hasParagraphs = true;
+ } else {
+ isPreParagraph = true;
+ }
+ continue;
+ }
+ } while (wordEnd < end);
+
+ if (lastLineLen) {
+ *lastLineLen = lenSoFar;
+ }
+
+ return res;
+ }
+}
diff --git a/library/cpp/getopt/small/wrap.h b/library/cpp/getopt/small/wrap.h
new file mode 100644
index 0000000000..e98028688d
--- /dev/null
+++ b/library/cpp/getopt/small/wrap.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <util/generic/fwd.h>
+#include <util/generic/strbuf.h>
+
+namespace NLastGetopt {
+ /**
+ * Split text to multiple lines so that each line fits the given width.
+ * Can work with UTF8, understands ANSI escape codes.
+ *
+ * @param indent will print this string after each newline.
+ * @param lastLineLen output: will set to number of unicode codepoints in the last printed line.
+ * @param hasParagraphs output: will set to true if there are two consecutive newlines in the text.
+ */
+ TString Wrap(ui32 width, TStringBuf text, TStringBuf indent = "", size_t* lastLineLen = nullptr, bool* hasParagraphs = nullptr);
+}
diff --git a/library/cpp/getopt/small/ya.make b/library/cpp/getopt/small/ya.make
new file mode 100644
index 0000000000..96de0f04b1
--- /dev/null
+++ b/library/cpp/getopt/small/ya.make
@@ -0,0 +1,28 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ library/cpp/colorizer
+)
+
+SRCS(
+ completer.cpp
+ completer_command.cpp
+ completion_generator.cpp
+ formatted_output.cpp
+ last_getopt.cpp
+ last_getopt_easy_setup.cpp
+ last_getopt_opt.cpp
+ last_getopt_opts.cpp
+ last_getopt_parser.cpp
+ last_getopt_parse_result.cpp
+ modchooser.cpp
+ opt.cpp
+ opt2.cpp
+ posix_getopt.cpp
+ wrap.cpp
+ ygetopt.cpp
+)
+
+END()
diff --git a/library/cpp/getopt/small/ygetopt.cpp b/library/cpp/getopt/small/ygetopt.cpp
new file mode 100644
index 0000000000..1f52827f74
--- /dev/null
+++ b/library/cpp/getopt/small/ygetopt.cpp
@@ -0,0 +1,108 @@
+#include "opt.h"
+#include "ygetopt.h"
+
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+class TGetOpt::TImpl: public TSimpleRefCount<TImpl> {
+public:
+ inline TImpl(int argc, const char* const* argv, const TString& fmt)
+ : args(argv, argv + argc)
+ , format(fmt)
+ {
+ if (argc == 0) {
+ ythrow yexception() << "zero argc";
+ }
+ }
+
+ inline ~TImpl() = default;
+
+ TVector<TString> args;
+ const TString format;
+};
+
+class TGetOpt::TIterator::TIterImpl: public TSimpleRefCount<TIterImpl> {
+public:
+ inline TIterImpl(const TGetOpt* parent)
+ : Args_(parent->Impl_->args)
+ , ArgsPtrs_(new char*[Args_.size() + 1])
+ , Format_(parent->Impl_->format)
+ , OptLet_(0)
+ , Arg_(nullptr)
+ {
+ for (size_t i = 0; i < Args_.size(); ++i) {
+ ArgsPtrs_.Get()[i] = Args_[i].begin();
+ }
+
+ ArgsPtrs_.Get()[Args_.size()] = nullptr;
+ Opt_.Reset(new Opt((int)Args_.size(), ArgsPtrs_.Get(), Format_.data()));
+ }
+
+ inline ~TIterImpl() = default;
+
+ inline void Next() {
+ OptLet_ = Opt_->Get();
+ Arg_ = Opt_->Arg;
+ }
+
+ inline char Key() const noexcept {
+ return (char)OptLet_;
+ }
+
+ inline const char* Arg() const noexcept {
+ return Arg_;
+ }
+
+ inline bool AtEnd() const noexcept {
+ return OptLet_ == EOF;
+ }
+
+private:
+ TVector<TString> Args_;
+ TArrayHolder<char*> ArgsPtrs_;
+ const TString Format_;
+ THolder<Opt> Opt_;
+ int OptLet_;
+ const char* Arg_;
+};
+
+TGetOpt::TIterator::TIterator() noexcept
+ : Impl_(nullptr)
+{
+}
+
+TGetOpt::TIterator::TIterator(const TGetOpt* parent)
+ : Impl_(new TIterImpl(parent))
+{
+ Next();
+}
+
+void TGetOpt::TIterator::Next() {
+ Impl_->Next();
+}
+
+char TGetOpt::TIterator::Key() const noexcept {
+ return Impl_->Key();
+}
+
+bool TGetOpt::TIterator::AtEnd() const noexcept {
+ if (Impl_.Get()) {
+ return Impl_->AtEnd();
+ }
+
+ return true;
+}
+
+const char* TGetOpt::TIterator::Arg() const noexcept {
+ if (Impl_.Get()) {
+ return Impl_->Arg();
+ }
+
+ return nullptr;
+}
+
+TGetOpt::TGetOpt(int argc, const char* const* argv, const TString& format)
+ : Impl_(new TImpl(argc, argv, format))
+{
+}
diff --git a/library/cpp/getopt/small/ygetopt.h b/library/cpp/getopt/small/ygetopt.h
new file mode 100644
index 0000000000..615d3dd18e
--- /dev/null
+++ b/library/cpp/getopt/small/ygetopt.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include <util/generic/fwd.h>
+#include <util/generic/ptr.h>
+
+class TGetOpt {
+public:
+ class TIterator {
+ friend class TGetOpt;
+
+ public:
+ char Key() const noexcept;
+ const char* Arg() const noexcept;
+
+ inline bool HaveArg() const noexcept {
+ return Arg();
+ }
+
+ inline void operator++() {
+ Next();
+ }
+
+ inline bool operator==(const TIterator& r) const noexcept {
+ return AtEnd() == r.AtEnd();
+ }
+
+ inline bool operator!=(const TIterator& r) const noexcept {
+ return !(*this == r);
+ }
+
+ inline TIterator& operator*() noexcept {
+ return *this;
+ }
+
+ inline const TIterator& operator*() const noexcept {
+ return *this;
+ }
+
+ inline TIterator* operator->() noexcept {
+ return this;
+ }
+
+ inline const TIterator* operator->() const noexcept {
+ return this;
+ }
+
+ private:
+ TIterator() noexcept;
+ TIterator(const TGetOpt* parent);
+
+ void Next();
+ bool AtEnd() const noexcept;
+
+ private:
+ class TIterImpl;
+ TSimpleIntrusivePtr<TIterImpl> Impl_;
+ };
+
+ TGetOpt(int argc, const char* const* argv, const TString& format);
+
+ inline TIterator Begin() const {
+ return TIterator(this);
+ }
+
+ inline TIterator End() const noexcept {
+ return TIterator();
+ }
+
+private:
+ class TImpl;
+ TSimpleIntrusivePtr<TImpl> Impl_;
+};
diff --git a/library/cpp/getopt/ut/last_getopt_ut.cpp b/library/cpp/getopt/ut/last_getopt_ut.cpp
new file mode 100644
index 0000000000..c99a1d053d
--- /dev/null
+++ b/library/cpp/getopt/ut/last_getopt_ut.cpp
@@ -0,0 +1,794 @@
+#include <library/cpp/getopt/last_getopt.h>
+
+#include <library/cpp/colorizer/colors.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/array_size.h>
+#include <util/string/subst.h>
+#include <util/string/vector.h>
+#include <util/string/split.h>
+
+using namespace NLastGetopt;
+
+namespace {
+ struct TOptsNoDefault: public TOpts {
+ TOptsNoDefault(const TStringBuf& optstring = TStringBuf())
+ : TOpts(optstring)
+ {
+ }
+ };
+
+ class TOptsParseResultTestWrapper: public TOptsParseResultException {
+ TVector<const char*> Argv_;
+
+ public:
+ TOptsParseResultTestWrapper(const TOpts* opts, TVector<const char*> argv)
+ : Argv_(argv)
+ {
+ Init(opts, (int)Argv_.size(), Argv_.data());
+ }
+ };
+
+ using V = TVector<const char*>;
+}
+
+struct TOptsParserTester {
+ TOptsNoDefault Opts_;
+ TVector<const char*> Argv_;
+
+ THolder<TOptsParser> Parser_;
+
+ void Initialize() {
+ if (!Parser_)
+ Parser_.Reset(new TOptsParser(&Opts_, (int)Argv_.size(), Argv_.data()));
+ }
+
+ void Accept() {
+ Initialize();
+ UNIT_ASSERT(Parser_->Next());
+ }
+
+ void AcceptOption() {
+ Accept();
+ UNIT_ASSERT(!!Parser_->CurOpt());
+ }
+
+ void AcceptOption(char c) {
+ AcceptOption();
+ UNIT_ASSERT(Parser_->CurOpt()->CharIs(c));
+ }
+
+ void AcceptOption(const TString& optName) {
+ AcceptOption();
+ UNIT_ASSERT(Parser_->CurOpt()->NameIs(optName));
+ }
+
+ template <typename TOpt>
+ void AcceptOptionWithValue(TOpt optName, const TString& value) {
+ AcceptOption(optName);
+ UNIT_ASSERT_VALUES_EQUAL_C(value, Parser_->CurValStr(), "; option " << optName);
+ }
+
+ template <typename TOpt>
+ void AcceptOptionWithoutValue(TOpt optName) {
+ AcceptOption(optName);
+ UNIT_ASSERT_C(!Parser_->CurVal(), ": opt " << optName << " must have no param");
+ }
+
+ void AcceptFreeArgInOrder(const TString& expected) {
+ Accept();
+ UNIT_ASSERT(!Parser_->CurOpt());
+ UNIT_ASSERT_VALUES_EQUAL(expected, Parser_->CurValStr());
+ }
+
+ size_t Pos_;
+
+ void AcceptEndOfOptions() {
+ Initialize();
+ UNIT_ASSERT(!Parser_->Next());
+ Pos_ = Parser_->Pos_;
+
+ // pos must not be changed after last meaningful invocation of Next()
+ UNIT_ASSERT(!Parser_->Next());
+ UNIT_ASSERT_VALUES_EQUAL(Pos_, Parser_->Pos_);
+ UNIT_ASSERT(!Parser_->Next());
+ UNIT_ASSERT_VALUES_EQUAL(Pos_, Parser_->Pos_);
+ }
+
+ void AcceptError() {
+ Initialize();
+ try {
+ Parser_->Next();
+ UNIT_FAIL("expecting exception");
+ } catch (const TUsageException&) {
+ // expecting
+ }
+ }
+
+ void AcceptUnexpectedOption() {
+ Initialize();
+ size_t pos = Parser_->Pos_;
+ size_t sop = Parser_->Sop_;
+ AcceptError();
+ UNIT_ASSERT_VALUES_EQUAL(pos, Parser_->Pos_);
+ UNIT_ASSERT_VALUES_EQUAL(sop, Parser_->Sop_);
+ }
+
+ void AcceptFreeArg(const TString& expected) {
+ UNIT_ASSERT(Pos_ < Parser_->Argc_);
+ UNIT_ASSERT_VALUES_EQUAL(expected, Parser_->Argv_[Pos_]);
+ ++Pos_;
+ }
+
+ void AcceptEndOfFreeArgs() {
+ UNIT_ASSERT_VALUES_EQUAL(Argv_.size(), Pos_);
+ }
+};
+
+namespace {
+ bool gSimpleFlag = false;
+ void SimpleHander(void) {
+ gSimpleFlag = true;
+ }
+}
+
+Y_UNIT_TEST_SUITE(TLastGetoptTests) {
+ Y_UNIT_TEST(TestEqual) {
+ TOptsNoDefault opts;
+ opts.AddLongOption("from");
+ opts.AddLongOption("to");
+ TOptsParseResultTestWrapper r(&opts, V({"copy", "--from=/", "--to=/etc"}));
+
+ UNIT_ASSERT_VALUES_EQUAL("copy", r.GetProgramName());
+ UNIT_ASSERT_VALUES_EQUAL("/", r.Get("from"));
+ UNIT_ASSERT_VALUES_EQUAL("/etc", r.Get("to"));
+ UNIT_ASSERT_VALUES_EQUAL("/etc", r.GetOrElse("to", "trash"));
+ UNIT_ASSERT(r.Has("from"));
+ UNIT_ASSERT(r.Has("to"));
+
+ UNIT_ASSERT_EXCEPTION(r.Get("left"), TException);
+ }
+
+ Y_UNIT_TEST(TestCharOptions) {
+ TOptsNoDefault opts;
+ opts.AddCharOption('R', NO_ARGUMENT);
+ opts.AddCharOption('l', NO_ARGUMENT);
+ opts.AddCharOption('h', NO_ARGUMENT);
+ TOptsParseResultTestWrapper r(&opts, V({"cp", "/etc", "-Rl", "/tmp/etc"}));
+ UNIT_ASSERT(r.Has('R'));
+ UNIT_ASSERT(r.Has('l'));
+ UNIT_ASSERT(!r.Has('h'));
+
+ UNIT_ASSERT_VALUES_EQUAL(2u, r.GetFreeArgs().size());
+ UNIT_ASSERT_VALUES_EQUAL(2u, r.GetFreeArgCount());
+ UNIT_ASSERT_VALUES_EQUAL("/etc", r.GetFreeArgs()[0]);
+ UNIT_ASSERT_VALUES_EQUAL("/tmp/etc", r.GetFreeArgs()[1]);
+ }
+
+ Y_UNIT_TEST(TestFreeArgs) {
+ TOptsNoDefault opts;
+ opts.SetFreeArgsNum(1, 3);
+ TOptsParseResultTestWrapper r11(&opts, V({"cp", "/etc"}));
+ TOptsParseResultTestWrapper r12(&opts, V({"cp", "/etc", "/tmp/etc"}));
+ TOptsParseResultTestWrapper r13(&opts, V({"cp", "/etc", "/tmp/etc", "verbose"}));
+
+ UNIT_ASSERT_EXCEPTION(
+ TOptsParseResultTestWrapper(&opts, V({"cp", "/etc", "/tmp/etc", "verbose", "nosymlink"})),
+ yexception);
+
+ UNIT_ASSERT_EXCEPTION(
+ TOptsParseResultTestWrapper(&opts, V({"cp"})),
+ yexception);
+
+ opts.SetFreeArgsNum(2);
+ TOptsParseResultTestWrapper r22(&opts, V({"cp", "/etc", "/var/tmp"}));
+ }
+
+ Y_UNIT_TEST(TestCharOptionsRequiredOptional) {
+ TOptsNoDefault opts;
+ opts.AddCharOption('d', REQUIRED_ARGUMENT);
+ opts.AddCharOption('e', REQUIRED_ARGUMENT);
+ opts.AddCharOption('x', REQUIRED_ARGUMENT);
+ opts.AddCharOption('y', REQUIRED_ARGUMENT);
+ opts.AddCharOption('l', NO_ARGUMENT);
+ TOptsParseResultTestWrapper r(&opts, V({"cmd", "-ld11", "-e", "22", "-lllx33", "-y", "44"}));
+ UNIT_ASSERT_VALUES_EQUAL("11", r.Get('d'));
+ UNIT_ASSERT_VALUES_EQUAL("22", r.Get('e'));
+ UNIT_ASSERT_VALUES_EQUAL("33", r.Get('x'));
+ UNIT_ASSERT_VALUES_EQUAL("44", r.Get('y'));
+ }
+
+ Y_UNIT_TEST(TestReturnInOrder) {
+ TOptsParserTester tester;
+ tester.Opts_.AddLongOption('v', "value");
+ tester.Opts_.ArgPermutation_ = RETURN_IN_ORDER;
+
+ tester.Argv_.push_back("cmd");
+ tester.Argv_.push_back("--value=11");
+ tester.Argv_.push_back("xx");
+ tester.Argv_.push_back("-v12");
+ tester.Argv_.push_back("yy");
+ tester.Argv_.push_back("--");
+ tester.Argv_.push_back("-v13");
+ tester.Argv_.push_back("--");
+
+ tester.AcceptOptionWithValue("value", "11");
+ tester.AcceptFreeArgInOrder("xx");
+ tester.AcceptOptionWithValue('v', "12");
+ tester.AcceptFreeArgInOrder("yy");
+ tester.AcceptFreeArgInOrder("-v13");
+ tester.AcceptFreeArgInOrder("--");
+ tester.AcceptEndOfOptions();
+ tester.AcceptEndOfFreeArgs();
+ }
+
+ Y_UNIT_TEST(TestRequireOrder) {
+ TOptsParserTester tester;
+ tester.Opts_.ArgPermutation_ = REQUIRE_ORDER;
+ tester.Opts_.AddLongOption('v', "value");
+
+ tester.Argv_.push_back("cmd");
+ tester.Argv_.push_back("--value=11");
+ tester.Argv_.push_back("xx");
+ tester.Argv_.push_back("-v12");
+ tester.Argv_.push_back("yy");
+
+ tester.AcceptOptionWithValue("value", "11");
+ tester.AcceptEndOfOptions();
+
+ tester.AcceptFreeArg("xx");
+ tester.AcceptFreeArg("-v12");
+ tester.AcceptFreeArg("yy");
+ tester.AcceptEndOfFreeArgs();
+ }
+
+ Y_UNIT_TEST(TestPlusForLongOption) {
+ TOptsParserTester tester;
+ tester.Opts_.AddLongOption('v', "value");
+ tester.Opts_.AllowPlusForLong_ = true;
+ tester.Argv_.push_back("cmd");
+ tester.Argv_.push_back("+value=11");
+ tester.Argv_.push_back("xx");
+ tester.Argv_.push_back("-v12");
+ tester.Argv_.push_back("yy");
+
+ tester.AcceptOptionWithValue("value", "11");
+ tester.AcceptOptionWithValue("value", "12");
+ tester.AcceptEndOfOptions();
+
+ tester.AcceptFreeArg("xx");
+ tester.AcceptFreeArg("yy");
+ tester.AcceptEndOfFreeArgs();
+ }
+
+ Y_UNIT_TEST(TestBug1) {
+ TOptsParserTester tester;
+ tester.Opts_.AddCharOptions("A:b:cd:");
+
+ tester.Argv_.push_back("cmd");
+ tester.Argv_.push_back("-A");
+ tester.Argv_.push_back("aaaa");
+ tester.Argv_.push_back("zz");
+ tester.Argv_.push_back("-c");
+ tester.Argv_.push_back("-d8");
+ tester.Argv_.push_back("ww");
+
+ tester.AcceptOptionWithValue('A', "aaaa");
+ tester.AcceptOptionWithoutValue('c');
+ tester.AcceptOptionWithValue('d', "8");
+ tester.AcceptEndOfOptions();
+
+ tester.AcceptFreeArg("zz");
+ tester.AcceptFreeArg("ww");
+ tester.AcceptEndOfFreeArgs();
+ }
+
+ Y_UNIT_TEST(TestPermuteComplex) {
+ TOptsParserTester tester;
+
+ tester.Opts_.AddCharOption('x').NoArgument();
+ tester.Opts_.AddCharOption('y').RequiredArgument();
+ tester.Opts_.AddCharOption('z').NoArgument();
+ tester.Opts_.AddCharOption('w').RequiredArgument();
+ tester.Opts_.ArgPermutation_ = PERMUTE;
+
+ tester.Argv_.push_back("cmd");
+ tester.Argv_.push_back("-x");
+ tester.Argv_.push_back("-y");
+ tester.Argv_.push_back("val");
+ tester.Argv_.push_back("freearg1");
+ tester.Argv_.push_back("-zw");
+ tester.Argv_.push_back("val2");
+ tester.Argv_.push_back("freearg2");
+
+ tester.AcceptOptionWithoutValue('x');
+ tester.AcceptOptionWithValue('y', "val");
+ tester.AcceptOptionWithoutValue('z');
+ tester.AcceptOptionWithValue('w', "val2");
+ tester.AcceptEndOfOptions();
+ tester.AcceptFreeArg("freearg1");
+ tester.AcceptFreeArg("freearg2");
+ tester.AcceptEndOfFreeArgs();
+ }
+
+ Y_UNIT_TEST(TestFinalDashDash) {
+ TOptsParserTester tester;
+ tester.Opts_.AddLongOption("size");
+
+ tester.Argv_.push_back("cmd");
+ tester.Argv_.push_back("--");
+
+ tester.AcceptEndOfOptions();
+ tester.AcceptEndOfFreeArgs();
+ }
+
+ Y_UNIT_TEST(TestDashDashAfterDashDash) {
+ TOptsParserTester tester;
+ tester.Opts_.AddLongOption("size");
+
+ tester.Argv_.push_back("cmd");
+ tester.Argv_.push_back("--");
+ tester.Argv_.push_back("--");
+ tester.Argv_.push_back("--");
+
+ tester.AcceptEndOfOptions();
+ tester.AcceptFreeArg("--");
+ tester.AcceptFreeArg("--");
+ tester.AcceptEndOfFreeArgs();
+ }
+
+ Y_UNIT_TEST(TestUnexpectedUnknownOption) {
+ TOptsParserTester tester;
+
+ tester.Argv_.push_back("cmd");
+ tester.Argv_.push_back("-x");
+
+ tester.AcceptUnexpectedOption();
+ }
+
+ Y_UNIT_TEST(TestDuplicatedOptionCrash) {
+ // this test is broken, cause UNIT_ASSERT(false) always throws
+ return;
+
+ bool exception = false;
+ try {
+ TOpts opts;
+ opts.AddLongOption('x', "one");
+ opts.AddLongOption('x', "two");
+ UNIT_ASSERT(false);
+ } catch (...) {
+ // we should go here, duplicating options are forbidden
+ exception = true;
+ }
+ UNIT_ASSERT(exception);
+ }
+
+ Y_UNIT_TEST(TestPositionWhenNoArgs) {
+ TOptsParserTester tester;
+
+ tester.Argv_.push_back("cmd");
+
+ tester.Opts_.AddCharOption('c');
+
+ tester.AcceptEndOfOptions();
+
+ UNIT_ASSERT_VALUES_EQUAL(1u, tester.Parser_->Pos_);
+ }
+
+ Y_UNIT_TEST(TestExpectedUnknownCharOption) {
+ TOptsParserTester tester;
+
+ tester.Argv_.push_back("cmd");
+ tester.Argv_.push_back("-x");
+ tester.Argv_.push_back("-y");
+ tester.Argv_.push_back("val");
+ tester.Argv_.push_back("freearg1");
+ tester.Argv_.push_back("-zw");
+ tester.Argv_.push_back("val2");
+ tester.Argv_.push_back("freearg2");
+
+ tester.Opts_.AllowUnknownCharOptions_ = true;
+
+ tester.AcceptOptionWithoutValue('x');
+ tester.AcceptOptionWithValue('y', "val");
+ tester.AcceptOptionWithoutValue('z');
+ tester.AcceptOptionWithValue('w', "val2");
+ tester.AcceptEndOfOptions();
+ tester.AcceptFreeArg("freearg1");
+ tester.AcceptFreeArg("freearg2");
+ tester.AcceptEndOfFreeArgs();
+ }
+
+#if 0
+ Y_UNIT_TEST(TestRequiredParams) {
+ TOptsParserTester tester;
+
+ tester.Argv_.push_back("cmd");
+ tester.Argv_.push_back("--port=1231");
+ tester.Argv_.push_back("asas");
+
+ tester.Opts_.AddLongOption("port");
+ tester.Opts_.AddLongOption("home").Required();
+
+ tester.AcceptOptionWithValue("port", "1231");
+ tester.AcceptError();
+ }
+#endif
+
+ Y_UNIT_TEST(TestStoreResult) {
+ TOptsNoDefault opts;
+ TString data;
+ int number;
+ TMaybe<TString> optionalString0, optionalString1;
+ TMaybe<int> optionalNumber0, optionalNumber1;
+ opts.AddLongOption('d', "data").StoreResult(&data);
+ opts.AddLongOption('n', "number").StoreResult(&number);
+ opts.AddLongOption("optional-string-0").StoreResult(&optionalString0);
+ opts.AddLongOption("optional-number-0").StoreResult(&optionalNumber0);
+ opts.AddLongOption("optional-string-1").StoreResult(&optionalString1);
+ opts.AddLongOption("optional-number-1").StoreResult(&optionalNumber1);
+ TOptsParseResultTestWrapper r(&opts, V({"cmd", "--data=jjhh", "-n", "11", "--optional-number-1=8", "--optional-string-1=os1"}));
+ UNIT_ASSERT_VALUES_EQUAL("jjhh", data);
+ UNIT_ASSERT_VALUES_EQUAL(11, number);
+ UNIT_ASSERT(!optionalString0.Defined());
+ UNIT_ASSERT(!optionalNumber0.Defined());
+ UNIT_ASSERT_VALUES_EQUAL(*optionalString1, "os1");
+ UNIT_ASSERT_VALUES_EQUAL(*optionalNumber1, 8);
+ }
+
+ Y_UNIT_TEST(TestStoreValue) {
+ int a = 0, b = 0;
+ size_t c = 0;
+ EHasArg e = NO_ARGUMENT;
+
+ TOptsNoDefault opts;
+ opts.AddLongOption('a', "alpha").NoArgument().StoreValue(&a, 42);
+ opts.AddLongOption('b', "beta").NoArgument().StoreValue(&b, 24);
+ opts.AddLongOption('e', "enum").NoArgument().StoreValue(&e, REQUIRED_ARGUMENT).StoreValue(&c, 12345);
+
+ TOptsParseResultTestWrapper r(&opts, V({"cmd", "-a", "-e"}));
+
+ UNIT_ASSERT_VALUES_EQUAL(42, a);
+ UNIT_ASSERT_VALUES_EQUAL(0, b);
+ UNIT_ASSERT(e == REQUIRED_ARGUMENT);
+ UNIT_ASSERT_VALUES_EQUAL(12345u, c);
+ }
+
+ Y_UNIT_TEST(TestSetFlag) {
+ bool a = false, b = true, c = false, d = true;
+
+ TOptsNoDefault opts;
+ opts.AddLongOption('a', "alpha").NoArgument().SetFlag(&a);
+ opts.AddLongOption('b', "beta").NoArgument().SetFlag(&b);
+ opts.AddCharOption('c').StoreTrue(&c);
+ opts.AddCharOption('d').StoreTrue(&d);
+
+ TOptsParseResultTestWrapper r(&opts, V({"cmd", "-a", "-c"}));
+
+ UNIT_ASSERT(a);
+ UNIT_ASSERT(!b);
+ UNIT_ASSERT(c);
+ UNIT_ASSERT(!d);
+ }
+
+ Y_UNIT_TEST(TestDefaultValue) {
+ TOptsNoDefault opts;
+ opts.AddLongOption("path").DefaultValue("/etc");
+ int value = 42;
+ opts.AddLongOption("value").StoreResult(&value).DefaultValue(32);
+ TOptsParseResultTestWrapper r(&opts, V({"cmd", "dfdf"}));
+ UNIT_ASSERT_VALUES_EQUAL("/etc", r.Get("path"));
+ UNIT_ASSERT_VALUES_EQUAL(32, value);
+ }
+
+ Y_UNIT_TEST(TestSplitValue) {
+ TOptsNoDefault opts;
+ TVector<TString> vals;
+ opts.AddLongOption('s', "split").SplitHandler(&vals, ',');
+ TOptsParseResultTestWrapper r(&opts, V({"prog", "--split=a,b,c"}));
+ UNIT_ASSERT_EQUAL(vals.size(), 3);
+ UNIT_ASSERT_EQUAL(vals[0], "a");
+ UNIT_ASSERT_EQUAL(vals[1], "b");
+ UNIT_ASSERT_EQUAL(vals[2], "c");
+ }
+
+ Y_UNIT_TEST(TestRangeSplitValue) {
+ TOptsNoDefault opts;
+ TVector<ui32> vals;
+ opts.AddLongOption('s', "split").RangeSplitHandler(&vals, ',', '-');
+ TOptsParseResultTestWrapper r(&opts, V({"prog", "--split=1,8-10", "--split=12-14"}));
+ UNIT_ASSERT_EQUAL(vals.size(), 7);
+ UNIT_ASSERT_EQUAL(vals[0], 1);
+ UNIT_ASSERT_EQUAL(vals[1], 8);
+ UNIT_ASSERT_EQUAL(vals[2], 9);
+ UNIT_ASSERT_EQUAL(vals[3], 10);
+ UNIT_ASSERT_EQUAL(vals[4], 12);
+ UNIT_ASSERT_EQUAL(vals[5], 13);
+ UNIT_ASSERT_EQUAL(vals[6], 14);
+ }
+
+ Y_UNIT_TEST(TestParseArgs) {
+ TOptsNoDefault o("AbCx:y:z::");
+ UNIT_ASSERT_EQUAL(o.GetCharOption('A').HasArg_, NO_ARGUMENT);
+ UNIT_ASSERT_EQUAL(o.GetCharOption('b').HasArg_, NO_ARGUMENT);
+ UNIT_ASSERT_EQUAL(o.GetCharOption('C').HasArg_, NO_ARGUMENT);
+ UNIT_ASSERT_EQUAL(o.GetCharOption('x').HasArg_, REQUIRED_ARGUMENT);
+ UNIT_ASSERT_EQUAL(o.GetCharOption('y').HasArg_, REQUIRED_ARGUMENT);
+ UNIT_ASSERT_EQUAL(o.GetCharOption('z').HasArg_, OPTIONAL_ARGUMENT);
+ }
+
+ Y_UNIT_TEST(TestRequiredOpts) {
+ TOptsNoDefault opts;
+ TOpt& opt_d = opts.AddCharOption('d');
+
+ // test 'not required'
+ // makes sure that the problem will only be in 'required'
+ TOptsParseResultTestWrapper r1(&opts, V({"cmd"}));
+
+ // test 'required'
+ opt_d.Required();
+ UNIT_ASSERT_EXCEPTION(
+ TOptsParseResultTestWrapper(&opts, V({"cmd"})),
+ TUsageException);
+
+ TOptsParseResultTestWrapper r3(&opts, V({"cmd", "-d11"}));
+ UNIT_ASSERT_VALUES_EQUAL("11", r3.Get('d'));
+ }
+
+ class HandlerStoreTrue {
+ bool* Flag;
+
+ public:
+ HandlerStoreTrue(bool* flag)
+ : Flag(flag)
+ {
+ }
+ void operator()() {
+ *Flag = true;
+ }
+ };
+ Y_UNIT_TEST(TestHandlers) {
+ {
+ TOptsNoDefault opts;
+ bool flag = false;
+ opts.AddLongOption("flag").Handler0(HandlerStoreTrue(&flag)).NoArgument();
+ TOptsParseResultTestWrapper r(&opts, V({"cmd", "--flag"}));
+ UNIT_ASSERT(flag);
+ }
+ {
+ TOptsNoDefault opts;
+ unsigned uval = 5;
+ double fval = 0.0;
+ opts.AddLongOption("flag1").RequiredArgument().StoreResult(&uval);
+ opts.AddLongOption("flag2").RequiredArgument().StoreResultT<int>(&uval);
+ opts.AddLongOption("flag3").RequiredArgument().StoreMappedResult(&fval, (double (*)(double))fabs);
+ opts.AddLongOption("flag4").RequiredArgument().StoreMappedResult(&fval, (double (*)(double))sqrt);
+ UNIT_ASSERT_EXCEPTION(
+ TOptsParseResultTestWrapper(&opts, V({"cmd", "--flag3", "-2.0", "--flag1", "-1"})),
+ yexception);
+ UNIT_ASSERT_VALUES_EQUAL(uval, 5u);
+ UNIT_ASSERT_VALUES_EQUAL(fval, 2.0);
+ TOptsParseResultTestWrapper r1(&opts, V({"cmd", "--flag4", "9.0", "--flag2", "-1"}));
+ UNIT_ASSERT_VALUES_EQUAL(uval, Max<unsigned>());
+ UNIT_ASSERT_VALUES_EQUAL(fval, 3.0);
+ }
+ }
+
+ Y_UNIT_TEST(TestTitleAndPrintUsage) {
+ TOpts opts;
+ const char* prog = "my_program";
+ TString title = TString("Sample ") + TString(prog).Quote() + " application";
+ opts.SetTitle(title);
+ int argc = 2;
+ const char* cmd[] = {prog};
+ TOptsParser parser(&opts, argc, cmd);
+ TStringStream out;
+ parser.PrintUsage(out);
+ // find title
+ UNIT_ASSERT(out.Str().find(title) != TString::npos);
+ // find usage
+ UNIT_ASSERT(out.Str().find(" " + TString(prog) + " ") != TString::npos);
+ }
+
+ Y_UNIT_TEST(TestCustomCmdLineDescr) {
+ TOpts opts;
+ const char* prog = "my_program";
+ TString customDescr = "<FILE|TABLE> USER [OPTIONS]";
+ int argc = 2;
+ const char* cmd[] = {prog};
+ opts.SetCmdLineDescr(customDescr);
+ TOptsParser parser(&opts, argc, cmd);
+ TStringStream out;
+ parser.PrintUsage(out);
+ // find custom usage
+ UNIT_ASSERT(out.Str().find(customDescr) != TString::npos);
+ }
+
+ Y_UNIT_TEST(TestColorPrint) {
+ TOpts opts;
+ const char* prog = "my_program";
+ opts.AddLongOption("long_option").Required();
+ opts.AddLongOption('o', "other");
+ opts.AddCharOption('d').DefaultValue("42");
+ opts.AddCharOption('s').DefaultValue("str_default");
+ opts.SetFreeArgsNum(123, 456);
+ opts.SetFreeArgTitle(0, "first_free_arg", "help");
+ opts.SetFreeArgTitle(2, "second_free_arg");
+ opts.AddSection("Section", "Section\n text");
+ const char* cmd[] = {prog};
+ TOptsParser parser(&opts, Y_ARRAY_SIZE(cmd), cmd);
+ TStringStream out;
+ NColorizer::TColors colors(true);
+ parser.PrintUsage(out, colors);
+
+ // find options and green color
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "--long_option" << colors.OldColor()) != TString::npos);
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "--other" << colors.OldColor()) != TString::npos);
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "-o" << colors.OldColor()) != TString::npos);
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "-d" << colors.OldColor()) != TString::npos);
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "-s" << colors.OldColor()) != TString::npos);
+
+ // find default values
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.CyanColor() << "42" << colors.OldColor()) != TString::npos);
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.CyanColor() << "\"str_default\"" << colors.OldColor()) != TString::npos);
+
+ // find free args
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "123" << colors.OldColor()) != TString::npos);
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "456" << colors.OldColor()) != TString::npos);
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "first_free_arg" << colors.OldColor()) != TString::npos);
+ // free args without help not rendered even if they have custom title
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.GreenColor() << "second_free_arg" << colors.OldColor()) == TString::npos);
+
+ // find signatures
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.BoldColor() << "Usage" << colors.OldColor()) != TString::npos);
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.BoldColor() << "Required parameters" << colors.OldColor()) != TString::npos);
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.BoldColor() << "Optional parameters" << colors.OldColor()) != TString::npos);
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.BoldColor() << "Free args" << colors.OldColor()) != TString::npos);
+
+ // find sections
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << colors.BoldColor() << "Section" << colors.OldColor() << ":") != TString::npos);
+ UNIT_ASSERT(out.Str().find(TStringBuilder() << " Section\n text") != TString::npos);
+
+ // print without colors
+ TStringStream out2;
+ opts.PrintUsage(prog, out2);
+ UNIT_ASSERT(out2.Str().find(colors.GreenColor()) == TString::npos);
+ UNIT_ASSERT(out2.Str().find(colors.CyanColor()) == TString::npos);
+ UNIT_ASSERT(out2.Str().find(colors.BoldColor()) == TString::npos);
+ UNIT_ASSERT(out2.Str().find(colors.OldColor()) == TString::npos);
+ }
+
+ Y_UNIT_TEST(TestPadding) {
+ const bool withColorsOpt[] = {false, true};
+ for (bool withColors : withColorsOpt) {
+ TOpts opts;
+ const char* prog = "my_program";
+ opts.AddLongOption("option", "description 1").Required(); // long option
+ opts.AddLongOption('o', "other", "description 2"); // char and long option
+ opts.AddCharOption('d', "description 3").RequiredArgument("DD"); // char option
+ opts.AddCharOption('s', "description 4\ndescription 5\ndescription 6"); // multiline desc
+ opts.AddLongOption('l', "very_very_very_loooong_ooooption", "description 7").RequiredArgument("LONG_ARGUMENT");
+ const char* cmd[] = {prog};
+ TOptsParser parser(&opts, Y_ARRAY_SIZE(cmd), cmd);
+
+ TStringStream out;
+ NColorizer::TColors colors(withColors);
+ parser.PrintUsage(out, colors);
+
+ TString printed = out.Str();
+ if (withColors) {
+ // remove not printable characters
+ SubstGlobal(printed, TString(colors.BoldColor()), "");
+ SubstGlobal(printed, TString(colors.GreenColor()), "");
+ SubstGlobal(printed, TString(colors.CyanColor()), "");
+ SubstGlobal(printed, TString(colors.OldColor()), "");
+ }
+ TVector<TString> lines;
+ StringSplitter(printed).Split('\n').SkipEmpty().Collect(&lines);
+ UNIT_ASSERT(!lines.empty());
+ TVector<size_t> indents;
+ for (const TString& line : lines) {
+ const size_t indent = line.find("description ");
+ if (indent != TString::npos)
+ indents.push_back(indent);
+ }
+ UNIT_ASSERT_VALUES_EQUAL(indents.size(), 7);
+ const size_t theOnlyIndent = indents[0];
+ for (size_t indent : indents) {
+ UNIT_ASSERT_VALUES_EQUAL_C(indent, theOnlyIndent, printed);
+ }
+ }
+ }
+
+ Y_UNIT_TEST(TestAppendTo) {
+ TVector<int> ints;
+
+ TOptsNoDefault opts;
+ opts.AddLongOption("size").AppendTo(&ints);
+
+ TOptsParseResultTestWrapper r(&opts, V({"cmd", "--size=17", "--size=19"}));
+
+ UNIT_ASSERT_VALUES_EQUAL(size_t(2), ints.size());
+ UNIT_ASSERT_VALUES_EQUAL(17, ints.at(0));
+ UNIT_ASSERT_VALUES_EQUAL(19, ints.at(1));
+ }
+
+ Y_UNIT_TEST(TestEmplaceTo) {
+ TVector<std::tuple<TString>> richPaths;
+
+ TOptsNoDefault opts;
+ opts.AddLongOption("path").EmplaceTo(&richPaths);
+
+ TOptsParseResultTestWrapper r(&opts, V({"cmd", "--path=<a=b>//cool", "--path=//nice"}));
+
+ UNIT_ASSERT_VALUES_EQUAL(size_t(2), richPaths.size());
+ UNIT_ASSERT_VALUES_EQUAL("<a=b>//cool", std::get<0>(richPaths.at(0)));
+ UNIT_ASSERT_VALUES_EQUAL("//nice", std::get<0>(richPaths.at(1)));
+ }
+
+ Y_UNIT_TEST(TestKVHandler) {
+ TStringBuilder keyvals;
+
+ TOptsNoDefault opts;
+ opts.AddLongOption("set").KVHandler([&keyvals](TString k, TString v) { keyvals << k << ":" << v << ","; });
+
+ TOptsParseResultTestWrapper r(&opts, V({"cmd", "--set", "x=1", "--set", "y=2", "--set=z=3"}));
+
+ UNIT_ASSERT_VALUES_EQUAL(keyvals, "x:1,y:2,z:3,");
+ }
+
+ Y_UNIT_TEST(TestEasySetup) {
+ TEasySetup opts;
+ bool flag = false;
+ opts('v', "version", "print version information")('a', "abstract", "some abstract param", true)('b', "buffer", "SIZE", "some param with argument")('c', "count", "SIZE", "some param with required argument")('t', "true", HandlerStoreTrue(&flag), "Some arg with handler")("global", SimpleHander, "Another arg with handler");
+
+ {
+ gSimpleFlag = false;
+ TOptsParseResultTestWrapper r(&opts, V({"cmd", "--abstract"}));
+ UNIT_ASSERT(!flag);
+ UNIT_ASSERT(!gSimpleFlag);
+ }
+
+ {
+ TOptsParseResultTestWrapper r(&opts, V({"cmd", "--abstract", "--global", "-t"}));
+ UNIT_ASSERT(flag);
+ UNIT_ASSERT(gSimpleFlag);
+ }
+
+ {
+ UNIT_ASSERT_EXCEPTION(
+ TOptsParseResultTestWrapper(&opts, V({"cmd", "--true"})),
+ TUsageException);
+ }
+
+ {
+ TOptsParseResultTestWrapper r(&opts, V({"cmd", "--abstract", "--buffer=512"}));
+ UNIT_ASSERT(r.Has('b'));
+ UNIT_ASSERT_VALUES_EQUAL(r.Get('b', 0), "512");
+ }
+ }
+
+ Y_UNIT_TEST(TestTOptsParseResultException) {
+ // verify that TOptsParseResultException actually throws a TUsageException instead of exit()
+ // not using wrapper here because it can hide bugs (see review #243810 and r2737774)
+ TOptsNoDefault opts;
+ opts.AddLongOption("required-opt").Required();
+ const char* argv[] = {"cmd"};
+ // Should throw TUsageException. Other exception types, no exceptions at all and exit(1) are failures
+ UNIT_ASSERT_EXCEPTION(
+ TOptsParseResultException(&opts, Y_ARRAY_SIZE(argv), argv),
+ TUsageException);
+ }
+
+ Y_UNIT_TEST(TestFreeArgsStoreResult) {
+ TOptsNoDefault opts;
+ TString data;
+ int number = 0;
+ opts.AddFreeArgBinding("data", data);
+ opts.AddFreeArgBinding("number", number);
+ TOptsParseResultTestWrapper r(&opts, V({"cmd", "hello", "25"}));
+ UNIT_ASSERT_VALUES_EQUAL("hello", data);
+ UNIT_ASSERT_VALUES_EQUAL(25, number);
+ UNIT_ASSERT_VALUES_EQUAL(2, r.GetFreeArgCount());
+ }
+}
diff --git a/library/cpp/getopt/ut/modchooser_ut.cpp b/library/cpp/getopt/ut/modchooser_ut.cpp
new file mode 100644
index 0000000000..a14c8a5853
--- /dev/null
+++ b/library/cpp/getopt/ut/modchooser_ut.cpp
@@ -0,0 +1,71 @@
+#include <library/cpp/getopt/modchooser.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/str.h>
+
+void ValidateArgcArgv(int argc, const char** argv) {
+ UNIT_ASSERT_EQUAL(argc, 1);
+ UNIT_ASSERT_EQUAL(argv[argc], nullptr);
+}
+
+int One(int argc, const char** argv) {
+ ValidateArgcArgv(argc, argv);
+ return 1;
+}
+
+int Two(int argc, const char** argv) {
+ ValidateArgcArgv(argc, argv);
+ return 2;
+}
+
+int Three(int argc, const char** argv) {
+ ValidateArgcArgv(argc, argv);
+ return 3;
+}
+
+int Four(int argc, const char** argv) {
+ ValidateArgcArgv(argc, argv);
+ return 4;
+}
+
+int Five(int argc, const char** argv) {
+ ValidateArgcArgv(argc, argv);
+ return 5;
+}
+
+typedef int (*F_PTR)(int, const char**);
+static const F_PTR FUNCTIONS[] = {One, Two, Three, Four, Five};
+static const char* NAMES[] = {"one", "two", "three", "four", "five"};
+static_assert(Y_ARRAY_SIZE(FUNCTIONS) == Y_ARRAY_SIZE(NAMES), "Incorrect input tests data");
+
+Y_UNIT_TEST_SUITE(TModChooserTest) {
+ Y_UNIT_TEST(TestModesSimpleRunner) {
+ TModChooser chooser;
+ for (size_t idx = 0; idx < Y_ARRAY_SIZE(NAMES); ++idx) {
+ chooser.AddMode(NAMES[idx], FUNCTIONS[idx], NAMES[idx]);
+ }
+
+ // test argc, argv
+ for (size_t idx = 0; idx < Y_ARRAY_SIZE(NAMES); ++idx) {
+ int argc = 2;
+ const char* argv[] = {"UNITTEST", NAMES[idx], nullptr};
+ UNIT_ASSERT_EQUAL(static_cast<int>(idx) + 1, chooser.Run(argc, argv));
+ }
+
+ // test TVector<TString> argv
+ for (size_t idx = 0; idx < Y_ARRAY_SIZE(NAMES); ++idx) {
+ const TVector<TString> argv = {"UNITTEST", NAMES[idx]};
+ UNIT_ASSERT_EQUAL(static_cast<int>(idx) + 1, chooser.Run(argv));
+ }
+ }
+
+ Y_UNIT_TEST(TestHelpMessage) {
+ TModChooser chooser;
+
+ int argc = 2;
+ const char* argv[] = {"UNITTEST", "-?", nullptr};
+
+ chooser.Run(argc, argv);
+ }
+}
diff --git a/library/cpp/getopt/ut/opt2_ut.cpp b/library/cpp/getopt/ut/opt2_ut.cpp
new file mode 100644
index 0000000000..0e7464747c
--- /dev/null
+++ b/library/cpp/getopt/ut/opt2_ut.cpp
@@ -0,0 +1,63 @@
+#include <library/cpp/getopt/opt2.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+//using namespace NLastGetopt;
+
+Y_UNIT_TEST_SUITE(Opt2Test) {
+ Y_UNIT_TEST(TestSimple) {
+ int argc = 8;
+ char* argv[] = {
+ (char*)"cmd",
+ (char*)"--aaaa=aaaa",
+ (char*)"zz",
+ (char*)"-x1",
+ (char*)"-x2",
+ (char*)"-c",
+ (char*)"-d8",
+ (char*)"ww",
+ };
+
+ Opt2 opt(argc, argv, "A:b:cd:e:x:", 2, "aaaa=A");
+
+ const char* edef = "edef";
+ const char* a = opt.Arg('A', "<var_name> - usage of -A");
+ int b = opt.Int('b', "<var_name> - usage of -b", 2);
+ bool c = opt.Has('c', "usage of -c");
+ int d = opt.Int('d', "<var_name> - usage of -d", 13);
+ const char* e = opt.Arg('e', "<unused> - only default is really used", edef);
+ const TVector<const char*>& x = opt.MArg('x', "<var_name> - usage of -x");
+
+ UNIT_ASSERT(!opt.AutoUsage("<L> <M>"));
+ UNIT_ASSERT_VALUES_EQUAL("aaaa", a);
+ UNIT_ASSERT_VALUES_EQUAL(2, b);
+ UNIT_ASSERT(c);
+ UNIT_ASSERT_VALUES_EQUAL(8, d);
+ UNIT_ASSERT_VALUES_EQUAL((void*)edef, e);
+
+ UNIT_ASSERT_VALUES_EQUAL(2u, opt.Pos.size());
+ UNIT_ASSERT_STRINGS_EQUAL("zz", opt.Pos.at(0));
+ UNIT_ASSERT_VALUES_EQUAL((void*)argv[2], opt.Pos.at(0));
+ UNIT_ASSERT_STRINGS_EQUAL("ww", opt.Pos.at(1));
+ UNIT_ASSERT_STRINGS_EQUAL("1", x.at(0));
+ UNIT_ASSERT_STRINGS_EQUAL("2", x.at(1));
+ }
+
+ Y_UNIT_TEST(TestErrors1) {
+ int argc = 4;
+ char* argv[] = {
+ (char*)"cmd",
+ (char*)"zz",
+ (char*)"-c",
+ (char*)"-e",
+ };
+
+ Opt2 opt(argc, argv, "ce:", 2);
+
+ const char* edef = "edef";
+ bool c = opt.Has('c', "usage of -c");
+ const char* e = opt.Arg('e', "<unused> - only default is really used", edef);
+ UNIT_ASSERT(c);
+ UNIT_ASSERT_VALUES_EQUAL((void*)edef, e);
+ }
+}
diff --git a/library/cpp/getopt/ut/opt_ut.cpp b/library/cpp/getopt/ut/opt_ut.cpp
new file mode 100644
index 0000000000..441aa493a0
--- /dev/null
+++ b/library/cpp/getopt/ut/opt_ut.cpp
@@ -0,0 +1,52 @@
+#include <library/cpp/getopt/opt.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/string/vector.h>
+
+Y_UNIT_TEST_SUITE(OptTest) {
+ Y_UNIT_TEST(TestSimple) {
+ int argc = 3;
+ char* argv[] = {
+ (char*)"cmd", (char*)"-x"};
+ Opt opt(argc, argv, "");
+ opt.Err = false; // be quiet
+ UNIT_ASSERT_VALUES_EQUAL('?', opt.Get());
+ UNIT_ASSERT_VALUES_EQUAL(EOF, opt.Get());
+ UNIT_ASSERT_VALUES_EQUAL(EOF, opt.Get());
+ UNIT_ASSERT_VALUES_EQUAL(EOF, opt.Get());
+ }
+
+ Y_UNIT_TEST(TestFreeArguments) {
+ Opt::Ion options[] = {
+ {"some-option", Opt::WithArg, nullptr, 123},
+ {nullptr, Opt::WithoutArg, nullptr, 0}};
+ const char* argv[] = {"cmd", "ARG1", "-some-option", "ARG2", "ARG3", nullptr};
+ int argc = 5;
+ Opt opts(argc, argv, "", options);
+
+ UNIT_ASSERT_VALUES_EQUAL(JoinStrings(opts.GetFreeArgs(), ", "), "ARG1, ARG3");
+ }
+
+ Y_UNIT_TEST(TestLongOption) {
+ const int SOME_OPTION_ID = 12345678;
+ Opt::Ion options[] = {
+ {"some-option", Opt::WithArg, nullptr, SOME_OPTION_ID},
+ {nullptr, Opt::WithoutArg, nullptr, 0}};
+ for (int doubleDash = 0; doubleDash <= 1; ++doubleDash) {
+ const char* argv[] = {"cmd", "ARG1", (doubleDash ? "--some-option" : "-some-option"), "ARG2", "ARG3", nullptr};
+ int argc = 5;
+ Opt opts(argc, argv, "", options);
+
+ TString optionValue = "";
+ int optlet = 0;
+ while ((optlet = opts.Get()) != EOF) {
+ if (optlet == SOME_OPTION_ID) {
+ optionValue = opts.GetArg();
+ } else {
+ UNIT_FAIL("don't expected any options, except -some-option");
+ }
+ }
+ UNIT_ASSERT_VALUES_EQUAL(optionValue, "ARG2");
+ }
+ }
+}
diff --git a/library/cpp/getopt/ut/posix_getopt_ut.cpp b/library/cpp/getopt/ut/posix_getopt_ut.cpp
new file mode 100644
index 0000000000..b6d374bf28
--- /dev/null
+++ b/library/cpp/getopt/ut/posix_getopt_ut.cpp
@@ -0,0 +1,119 @@
+#include <library/cpp/getopt/posix_getopt.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NLastGetopt;
+
+Y_UNIT_TEST_SUITE(TPosixGetoptTest) {
+ Y_UNIT_TEST(TestSimple) {
+ int argc = 6;
+ const char* argv0[] = {"program", "-b", "-f1", "-f", "2", "zzzz"};
+ char** const argv = (char**)argv0;
+
+ NLastGetopt::optreset = 1;
+ UNIT_ASSERT_VALUES_EQUAL('b', NLastGetopt::getopt(argc, argv, "bf:"));
+ UNIT_ASSERT_VALUES_EQUAL('f', NLastGetopt::getopt(argc, argv, "bf:"));
+ UNIT_ASSERT_VALUES_EQUAL(NLastGetopt::optarg, TString("1"));
+ UNIT_ASSERT_VALUES_EQUAL('f', NLastGetopt::getopt(argc, argv, "bf:"));
+ UNIT_ASSERT_VALUES_EQUAL(NLastGetopt::optarg, TString("2"));
+ UNIT_ASSERT_VALUES_EQUAL(-1, NLastGetopt::getopt(argc, argv, "bf:"));
+
+ UNIT_ASSERT_VALUES_EQUAL(5, NLastGetopt::optind);
+ }
+
+ Y_UNIT_TEST(TestLong) {
+ int daggerset = 0;
+ /* options descriptor */
+ const NLastGetopt::option longopts[] = {
+ {"buffy", no_argument, nullptr, 'b'},
+ {"fluoride", required_argument, nullptr, 'f'},
+ {"daggerset", no_argument, &daggerset, 1},
+ {nullptr, 0, nullptr, 0}};
+
+ int argc = 7;
+ const char* argv0[] = {"program", "-b", "--buffy", "-f1", "--fluoride=2", "--daggerset", "zzzz"};
+ char** const argv = (char**)argv0;
+
+ int longIndex;
+
+ NLastGetopt::optreset = 1;
+ UNIT_ASSERT_VALUES_EQUAL('b', NLastGetopt::getopt_long(argc, argv, "bf:", longopts, &longIndex));
+ UNIT_ASSERT_VALUES_EQUAL(0, longIndex);
+ UNIT_ASSERT_VALUES_EQUAL('b', NLastGetopt::getopt_long(argc, argv, "bf:", longopts, nullptr));
+ UNIT_ASSERT_VALUES_EQUAL('f', NLastGetopt::getopt_long(argc, argv, "bf:", longopts, &longIndex));
+ UNIT_ASSERT_VALUES_EQUAL(1, longIndex);
+ UNIT_ASSERT_VALUES_EQUAL('f', NLastGetopt::getopt_long(argc, argv, "bf:", longopts, nullptr));
+ UNIT_ASSERT_VALUES_EQUAL(0, NLastGetopt::getopt_long(argc, argv, "bf:", longopts, nullptr));
+ UNIT_ASSERT_VALUES_EQUAL(-1, NLastGetopt::getopt_long(argc, argv, "bf:", longopts, nullptr));
+
+ UNIT_ASSERT_VALUES_EQUAL(6, NLastGetopt::optind);
+ }
+
+ Y_UNIT_TEST(TestLongPermutation) {
+ int daggerset = 0;
+ /* options descriptor */
+ const NLastGetopt::option longopts[] = {
+ {"buffy", no_argument, nullptr, 'b'},
+ {"fluoride", required_argument, nullptr, 'f'},
+ {"daggerset", no_argument, &daggerset, 1},
+ {nullptr, 0, nullptr, 0}};
+
+ int argc = 7;
+ const char* argv0[] = {"program", "aa", "-b", "bb", "cc", "--buffy", "dd"};
+ char** const argv = (char**)argv0;
+
+ NLastGetopt::optreset = 1;
+ UNIT_ASSERT_VALUES_EQUAL('b', NLastGetopt::getopt_long(argc, argv, "bf:", longopts, nullptr));
+ UNIT_ASSERT_VALUES_EQUAL('b', NLastGetopt::getopt_long(argc, argv, "bf:", longopts, nullptr));
+ UNIT_ASSERT_VALUES_EQUAL(-1, NLastGetopt::getopt_long(argc, argv, "bf:", longopts, nullptr));
+
+ UNIT_ASSERT_VALUES_EQUAL(3, NLastGetopt::optind);
+ }
+
+ Y_UNIT_TEST(TestNoOptionsOptionsWithDoubleDash) {
+ const NLastGetopt::option longopts[] = {
+ {"buffy", no_argument, nullptr, 'b'},
+ {"fluoride", no_argument, nullptr, 'f'},
+ {nullptr, 0, nullptr, 0}};
+
+ int argc = 2;
+ const char* argv0[] = {"program", "--bf"};
+ char** const argv = (char**)argv0;
+
+ NLastGetopt::optreset = 1;
+ UNIT_ASSERT_VALUES_EQUAL('?', NLastGetopt::getopt_long(argc, argv, "bf", longopts, nullptr));
+ }
+
+ Y_UNIT_TEST(TestLongOnly) {
+ const NLastGetopt::option longopts[] = {
+ {"foo", no_argument, nullptr, 'F'},
+ {"fluoride", no_argument, nullptr, 'f'},
+ {"ogogo", no_argument, nullptr, 'o'},
+ {nullptr, 0, nullptr, 0}};
+
+ int argc = 4;
+ const char* argv0[] = {"program", "--foo", "-foo", "-fo"};
+ char** const argv = (char**)argv0;
+
+ NLastGetopt::optreset = 1;
+ UNIT_ASSERT_VALUES_EQUAL('F', NLastGetopt::getopt_long_only(argc, argv, "fo", longopts, nullptr));
+ UNIT_ASSERT_VALUES_EQUAL('F', NLastGetopt::getopt_long_only(argc, argv, "fo", longopts, nullptr));
+ UNIT_ASSERT_VALUES_EQUAL('f', NLastGetopt::getopt_long_only(argc, argv, "fo", longopts, nullptr));
+ UNIT_ASSERT_VALUES_EQUAL('o', NLastGetopt::getopt_long_only(argc, argv, "fo", longopts, nullptr));
+ UNIT_ASSERT_VALUES_EQUAL(-1, NLastGetopt::getopt_long_only(argc, argv, "fo", longopts, nullptr));
+ }
+
+ Y_UNIT_TEST(TestLongWithoutOnlySingleDashNowAllowed) {
+ const NLastGetopt::option longopts[] = {
+ {"foo", no_argument, nullptr, 'F'},
+ {"zoo", no_argument, nullptr, 'z'},
+ {nullptr, 0, nullptr, 0}};
+
+ int argc = 2;
+ const char* argv0[] = {"program", "-foo"};
+ char** const argv = (char**)argv0;
+
+ NLastGetopt::optreset = 1;
+ UNIT_ASSERT_VALUES_EQUAL('?', NLastGetopt::getopt_long(argc, argv, "z", longopts, nullptr));
+ }
+}
diff --git a/library/cpp/getopt/ut/wrap.cpp b/library/cpp/getopt/ut/wrap.cpp
new file mode 100644
index 0000000000..3444eea102
--- /dev/null
+++ b/library/cpp/getopt/ut/wrap.cpp
@@ -0,0 +1,96 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/getopt/small/wrap.h>
+
+Y_UNIT_TEST_SUITE(Wrap) {
+ Y_UNIT_TEST(TestWrapping) {
+ UNIT_ASSERT_STRINGS_EQUAL(
+ NLastGetopt::Wrap(5, "a b c d eeffeff").Quote(),
+ TString("a b c\nd\neeffeff").Quote()
+ );
+
+ UNIT_ASSERT_STRINGS_EQUAL(
+ NLastGetopt::Wrap(5, "a b\nc d\neeffeff").Quote(),
+ TString("a b\nc d\neeffeff").Quote()
+ );
+
+ UNIT_ASSERT_STRINGS_EQUAL(
+ NLastGetopt::Wrap(5, "a b\n c d\neeffeff").Quote(),
+ TString("a b\n c\nd\neeffeff").Quote()
+ );
+
+ UNIT_ASSERT_STRINGS_EQUAL(
+ NLastGetopt::Wrap(5, "a b\nx c d\neeffeff").Quote(),
+ TString("a b\nx\nc d\neeffeff").Quote()
+ );
+
+ UNIT_ASSERT_STRINGS_EQUAL(
+ NLastGetopt::Wrap(5, "a b\nx \n c d\neeffeff").Quote(),
+ TString("a b\nx\n c\nd\neeffeff").Quote()
+ );
+
+ UNIT_ASSERT_STRINGS_EQUAL(
+ NLastGetopt::Wrap(5, "a b\nx \n c d\neeffeff").Quote(),
+ TString("a b\nx\n c\nd\neeffeff").Quote()
+ );
+ }
+
+ Y_UNIT_TEST(TestWrappingIndent) {
+ UNIT_ASSERT_STRINGS_EQUAL(
+ NLastGetopt::Wrap(5, "a b c d", "|>").Quote(),
+ TString("a b\n|>c d").Quote()
+ );
+
+ UNIT_ASSERT_STRINGS_EQUAL(
+ NLastGetopt::Wrap(5, "a b\n\nc d", "|>").Quote(),
+ TString("a b\n|>\n|>c d").Quote()
+ );
+ }
+
+ Y_UNIT_TEST(TestWrappingAnsi) {
+ UNIT_ASSERT_STRINGS_EQUAL(
+ NLastGetopt::Wrap(5, "\033[1;2;3;4;5mx\033[1;2;3;4;5mx\033[1;2;3;4;5mx\033[1;2;3;4;5mx\033[1;2;3;4;5m").Quote(),
+ TString("\033[1;2;3;4;5mx\033[1;2;3;4;5mx\033[1;2;3;4;5mx\033[1;2;3;4;5mx\033[1;2;3;4;5m").Quote()
+ );
+
+ UNIT_ASSERT_STRINGS_EQUAL(
+ NLastGetopt::Wrap(5, "a \033[1;2;3;4;5mb c\033[1;2;3;4;5m \033[1;2;3;4;5md e f").Quote(),
+ TString("a \033[1;2;3;4;5mb c\033[1;2;3;4;5m\n\033[1;2;3;4;5md e f").Quote()
+ );
+
+ UNIT_ASSERT_STRINGS_EQUAL(
+ NLastGetopt::Wrap(5, "a b \033[1;2;3;4;5m c d").Quote(),
+ TString("a b \033[1;2;3;4;5m\nc d").Quote()
+ );
+
+ UNIT_ASSERT_STRINGS_EQUAL(
+ NLastGetopt::Wrap(5, "a b \033[1;2;3;4;5m c d").Quote(),
+ TString("a b\n\033[1;2;3;4;5m c d").Quote()
+ );
+ }
+
+ Y_UNIT_TEST(TestTextInfo) {
+ size_t lastLineLen;
+ bool hasParagraphs;
+
+ NLastGetopt::Wrap(5, "a b c d e", "", &lastLineLen, &hasParagraphs);
+ UNIT_ASSERT_VALUES_EQUAL(lastLineLen, 3);
+ UNIT_ASSERT_VALUES_EQUAL(hasParagraphs, false);
+
+ NLastGetopt::Wrap(5, "a b c\n\nd e f h", "", &lastLineLen, &hasParagraphs);
+ UNIT_ASSERT_VALUES_EQUAL(lastLineLen, 1);
+ UNIT_ASSERT_VALUES_EQUAL(hasParagraphs, true);
+
+ NLastGetopt::Wrap(5, "a b c\n\n", "", &lastLineLen, &hasParagraphs);
+ UNIT_ASSERT_VALUES_EQUAL(lastLineLen, 0);
+ UNIT_ASSERT_VALUES_EQUAL(hasParagraphs, true);
+
+ NLastGetopt::Wrap(5, "\n \na b c", "", &lastLineLen, &hasParagraphs);
+ UNIT_ASSERT_VALUES_EQUAL(lastLineLen, 5);
+ UNIT_ASSERT_VALUES_EQUAL(hasParagraphs, true);
+
+ NLastGetopt::Wrap(5, "\nx\na b c", "", &lastLineLen, &hasParagraphs);
+ UNIT_ASSERT_VALUES_EQUAL(lastLineLen, 5);
+ UNIT_ASSERT_VALUES_EQUAL(hasParagraphs, false);
+ }
+}
diff --git a/library/cpp/getopt/ut/ya.make b/library/cpp/getopt/ut/ya.make
new file mode 100644
index 0000000000..8d00669efb
--- /dev/null
+++ b/library/cpp/getopt/ut/ya.make
@@ -0,0 +1,15 @@
+UNITTEST_FOR(library/cpp/getopt)
+
+OWNER(pg)
+
+SRCS(
+ last_getopt_ut.cpp
+ modchooser_ut.cpp
+ opt2_ut.cpp
+ opt_ut.cpp
+ posix_getopt_ut.cpp
+ wrap.cpp
+ ygetopt_ut.cpp
+)
+
+END()
diff --git a/library/cpp/getopt/ut/ygetopt_ut.cpp b/library/cpp/getopt/ut/ygetopt_ut.cpp
new file mode 100644
index 0000000000..a76f117216
--- /dev/null
+++ b/library/cpp/getopt/ut/ygetopt_ut.cpp
@@ -0,0 +1,45 @@
+#include <library/cpp/getopt/ygetopt.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+class TGetOptTest: public TTestBase {
+ UNIT_TEST_SUITE(TGetOptTest);
+ UNIT_TEST(TestGetOpt);
+ UNIT_TEST_EXCEPTION(TestZeroArgC, yexception);
+ UNIT_TEST_SUITE_END();
+
+public:
+ void TestGetOpt();
+ void TestZeroArgC();
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TGetOptTest);
+
+void TGetOptTest::TestZeroArgC() {
+ TGetOpt opt(0, nullptr, "");
+}
+
+void TGetOptTest::TestGetOpt() {
+ const char* argv[] = {
+ "/usr/bin/bash",
+ "-f",
+ "-p",
+ "qwerty123",
+ "-z",
+ "-q",
+ nullptr};
+
+ TString res;
+ const TString format = "qzp:f";
+ TGetOpt opt(sizeof(argv) / sizeof(*argv) - 1, argv, format);
+
+ for (TGetOpt::TIterator it = opt.Begin(); it != opt.End(); ++it) {
+ res += it->Key();
+
+ if (it->HaveArg()) {
+ res += it->Arg();
+ }
+ }
+
+ UNIT_ASSERT_EQUAL(res, "fpqwerty123zq");
+}
diff --git a/library/cpp/getopt/ya.make b/library/cpp/getopt/ya.make
new file mode 100644
index 0000000000..6df23b22b2
--- /dev/null
+++ b/library/cpp/getopt/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ library/cpp/getopt/small
+ library/cpp/svnversion
+ library/cpp/build_info
+)
+
+SRCS(
+ GLOBAL print.cpp
+)
+
+END()
diff --git a/library/cpp/getopt/ygetopt.h b/library/cpp/getopt/ygetopt.h
new file mode 100644
index 0000000000..fd018b3128
--- /dev/null
+++ b/library/cpp/getopt/ygetopt.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include <library/cpp/getopt/small/ygetopt.h>
diff --git a/library/cpp/grpc/client/grpc_client_low.cpp b/library/cpp/grpc/client/grpc_client_low.cpp
new file mode 100644
index 0000000000..73cc908ef8
--- /dev/null
+++ b/library/cpp/grpc/client/grpc_client_low.cpp
@@ -0,0 +1,586 @@
+#include "grpc_client_low.h"
+#include <contrib/libs/grpc/src/core/lib/iomgr/socket_mutator.h>
+#include <contrib/libs/grpc/include/grpc/support/log.h>
+
+#include <library/cpp/containers/stack_vector/stack_vec.h>
+
+#include <util/string/printf.h>
+#include <util/system/thread.h>
+#include <util/random/random.h>
+
+#if !defined(_WIN32) && !defined(_WIN64)
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#endif
+
+namespace NGrpc {
+
+void EnableGRpcTracing() {
+ grpc_tracer_set_enabled("tcp", true);
+ grpc_tracer_set_enabled("client_channel", true);
+ grpc_tracer_set_enabled("channel", true);
+ grpc_tracer_set_enabled("api", true);
+ grpc_tracer_set_enabled("connectivity_state", true);
+ grpc_tracer_set_enabled("handshaker", true);
+ grpc_tracer_set_enabled("http", true);
+ grpc_tracer_set_enabled("http2_stream_state", true);
+ grpc_tracer_set_enabled("op_failure", true);
+ grpc_tracer_set_enabled("timer", true);
+ gpr_set_log_verbosity(GPR_LOG_SEVERITY_DEBUG);
+}
+
+class TGRpcKeepAliveSocketMutator : public grpc_socket_mutator {
+public:
+ TGRpcKeepAliveSocketMutator(int idle, int count, int interval)
+ : Idle_(idle)
+ , Count_(count)
+ , Interval_(interval)
+ {
+ grpc_socket_mutator_init(this, &VTable);
+ }
+private:
+ static TGRpcKeepAliveSocketMutator* Cast(grpc_socket_mutator* mutator) {
+ return static_cast<TGRpcKeepAliveSocketMutator*>(mutator);
+ }
+
+ template<typename TVal>
+ bool SetOption(int fd, int level, int optname, const TVal& value) {
+ return setsockopt(fd, level, optname, reinterpret_cast<const char*>(&value), sizeof(value)) == 0;
+ }
+ bool SetOption(int fd) {
+ if (!SetOption(fd, SOL_SOCKET, SO_KEEPALIVE, 1)) {
+ Cerr << Sprintf("Failed to set SO_KEEPALIVE option: %s", strerror(errno)) << Endl;
+ return false;
+ }
+#ifdef _linux_
+ if (Idle_ && !SetOption(fd, IPPROTO_TCP, TCP_KEEPIDLE, Idle_)) {
+ Cerr << Sprintf("Failed to set TCP_KEEPIDLE option: %s", strerror(errno)) << Endl;
+ return false;
+ }
+ if (Count_ && !SetOption(fd, IPPROTO_TCP, TCP_KEEPCNT, Count_)) {
+ Cerr << Sprintf("Failed to set TCP_KEEPCNT option: %s", strerror(errno)) << Endl;
+ return false;
+ }
+ if (Interval_ && !SetOption(fd, IPPROTO_TCP, TCP_KEEPINTVL, Interval_)) {
+ Cerr << Sprintf("Failed to set TCP_KEEPINTVL option: %s", strerror(errno)) << Endl;
+ return false;
+ }
+#endif
+ return true;
+ }
+ static bool Mutate(int fd, grpc_socket_mutator* mutator) {
+ auto self = Cast(mutator);
+ return self->SetOption(fd);
+ }
+ static int Compare(grpc_socket_mutator* a, grpc_socket_mutator* b) {
+ const auto* selfA = Cast(a);
+ const auto* selfB = Cast(b);
+ auto tupleA = std::make_tuple(selfA->Idle_, selfA->Count_, selfA->Interval_);
+ auto tupleB = std::make_tuple(selfB->Idle_, selfB->Count_, selfB->Interval_);
+ return tupleA < tupleB ? -1 : tupleA > tupleB ? 1 : 0;
+ }
+ static void Destroy(grpc_socket_mutator* mutator) {
+ delete Cast(mutator);
+ }
+
+ static grpc_socket_mutator_vtable VTable;
+ const int Idle_;
+ const int Count_;
+ const int Interval_;
+};
+
+grpc_socket_mutator_vtable TGRpcKeepAliveSocketMutator::VTable =
+ {
+ &TGRpcKeepAliveSocketMutator::Mutate,
+ &TGRpcKeepAliveSocketMutator::Compare,
+ &TGRpcKeepAliveSocketMutator::Destroy
+ };
+
+TChannelPool::TChannelPool(const TTcpKeepAliveSettings& tcpKeepAliveSettings, const TDuration& expireTime)
+ : TcpKeepAliveSettings_(tcpKeepAliveSettings)
+ , ExpireTime_(expireTime)
+ , UpdateReUseTime_(ExpireTime_ * 0.3 < TDuration::Seconds(20) ? ExpireTime_ * 0.3 : TDuration::Seconds(20))
+{}
+
+void TChannelPool::GetStubsHolderLocked(
+ const TString& channelId,
+ const TGRpcClientConfig& config,
+ std::function<void(TStubsHolder&)> cb)
+{
+ {
+ std::shared_lock readGuard(RWMutex_);
+ const auto it = Pool_.find(channelId);
+ if (it != Pool_.end()) {
+ if (!it->second.IsChannelBroken() && !(Now() > it->second.GetLastUseTime() + UpdateReUseTime_)) {
+ return cb(it->second);
+ }
+ }
+ }
+ {
+ std::unique_lock writeGuard(RWMutex_);
+ {
+ auto it = Pool_.find(channelId);
+ if (it != Pool_.end()) {
+ if (!it->second.IsChannelBroken()) {
+ EraseFromQueueByTime(it->second.GetLastUseTime(), channelId);
+ auto now = Now();
+ LastUsedQueue_.emplace(now, channelId);
+ it->second.SetLastUseTime(now);
+ return cb(it->second);
+ } else {
+ // This channel can't be used. Remove from pool to create new one
+ EraseFromQueueByTime(it->second.GetLastUseTime(), channelId);
+ Pool_.erase(it);
+ }
+ }
+ }
+ TGRpcKeepAliveSocketMutator* mutator = nullptr;
+ // will be destroyed inside grpc
+ if (TcpKeepAliveSettings_.Enabled) {
+ mutator = new TGRpcKeepAliveSocketMutator(
+ TcpKeepAliveSettings_.Idle,
+ TcpKeepAliveSettings_.Count,
+ TcpKeepAliveSettings_.Interval
+ );
+ }
+ cb(Pool_.emplace(channelId, CreateChannelInterface(config, mutator)).first->second);
+ LastUsedQueue_.emplace(Pool_.at(channelId).GetLastUseTime(), channelId);
+ }
+}
+
+void TChannelPool::DeleteChannel(const TString& channelId) {
+ std::unique_lock writeLock(RWMutex_);
+ auto poolIt = Pool_.find(channelId);
+ if (poolIt != Pool_.end()) {
+ EraseFromQueueByTime(poolIt->second.GetLastUseTime(), channelId);
+ Pool_.erase(poolIt);
+ }
+}
+
+void TChannelPool::DeleteExpiredStubsHolders() {
+ std::unique_lock writeLock(RWMutex_);
+ auto lastExpired = LastUsedQueue_.lower_bound(Now() - ExpireTime_);
+ for (auto i = LastUsedQueue_.begin(); i != lastExpired; ++i){
+ Pool_.erase(i->second);
+ }
+ LastUsedQueue_.erase(LastUsedQueue_.begin(), lastExpired);
+}
+
+void TChannelPool::EraseFromQueueByTime(const TInstant& lastUseTime, const TString& channelId) {
+ auto [begin, end] = LastUsedQueue_.equal_range(lastUseTime);
+ auto pos = std::find_if(begin, end, [&](auto a){return a.second == channelId;});
+ Y_VERIFY(pos != LastUsedQueue_.end(), "data corruption at TChannelPool");
+ LastUsedQueue_.erase(pos);
+}
+
+static void PullEvents(grpc::CompletionQueue* cq) {
+ TThread::SetCurrentThreadName("grpc_client");
+ while (true) {
+ void* tag;
+ bool ok;
+
+ if (!cq->Next(&tag, &ok)) {
+ break;
+ }
+
+ if (auto* ev = static_cast<IQueueClientEvent*>(tag)) {
+ if (!ev->Execute(ok)) {
+ ev->Destroy();
+ }
+ }
+ }
+}
+
+class TGRpcClientLow::TContextImpl final
+ : public std::enable_shared_from_this<TContextImpl>
+ , public IQueueClientContext
+{
+ friend class TGRpcClientLow;
+
+ using TCallback = std::function<void()>;
+ using TContextPtr = std::shared_ptr<TContextImpl>;
+
+public:
+ ~TContextImpl() override {
+ Y_VERIFY(CountChildren() == 0,
+ "Destructor called with non-empty children");
+
+ if (Parent) {
+ Parent->ForgetContext(this);
+ } else if (Y_LIKELY(Owner)) {
+ Owner->ForgetContext(this);
+ }
+ }
+
+ /**
+ * Helper for locking child pointer from a parent container
+ */
+ static TContextPtr LockChildPtr(TContextImpl* ptr) {
+ if (ptr) {
+ // N.B. it is safe to do as long as it's done under a mutex and
+ // pointer is among valid children. When that's the case we
+ // know that TContextImpl destructor has not finished yet, so
+ // the object is valid. The lock() method may return nullptr
+ // though, if the object is being destructed right now.
+ return ptr->weak_from_this().lock();
+ } else {
+ return nullptr;
+ }
+ }
+
+ void ForgetContext(TContextImpl* child) {
+ std::unique_lock<std::mutex> guard(Mutex);
+
+ auto removed = RemoveChild(child);
+ Y_VERIFY(removed, "Unexpected ForgetContext(%p)", child);
+ }
+
+ IQueueClientContextPtr CreateContext() override {
+ auto self = shared_from_this();
+ auto child = std::make_shared<TContextImpl>();
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+
+ AddChild(child.get());
+
+ // It's now safe to initialize parent and owner
+ child->Parent = std::move(self);
+ child->Owner = Owner;
+ child->CQ = CQ;
+
+ // Propagate cancellation to a child context
+ if (Cancelled.load(std::memory_order_relaxed)) {
+ child->Cancelled.store(true, std::memory_order_relaxed);
+ }
+ }
+
+ return child;
+ }
+
+ grpc::CompletionQueue* CompletionQueue() override {
+ Y_VERIFY(Owner, "Uninitialized context");
+ return CQ;
+ }
+
+ bool IsCancelled() const override {
+ return Cancelled.load(std::memory_order_acquire);
+ }
+
+ bool Cancel() override {
+ TStackVec<TCallback, 1> callbacks;
+ TStackVec<TContextPtr, 2> children;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+
+ if (Cancelled.load(std::memory_order_relaxed)) {
+ // Already cancelled in another thread
+ return false;
+ }
+
+ callbacks.reserve(Callbacks.size());
+ children.reserve(CountChildren());
+
+ for (auto& callback : Callbacks) {
+ callbacks.emplace_back().swap(callback);
+ }
+ Callbacks.clear();
+
+ // Collect all children we need to cancel
+ // N.B. we don't clear children links (cleared by destructors)
+ // N.B. some children may be stuck in destructors at the moment
+ for (TContextImpl* ptr : InlineChildren) {
+ if (auto child = LockChildPtr(ptr)) {
+ children.emplace_back(std::move(child));
+ }
+ }
+ for (auto* ptr : Children) {
+ if (auto child = LockChildPtr(ptr)) {
+ children.emplace_back(std::move(child));
+ }
+ }
+
+ Cancelled.store(true, std::memory_order_release);
+ }
+
+ // Call directly subscribed callbacks
+ if (callbacks) {
+ RunCallbacksNoExcept(callbacks);
+ }
+
+ // Cancel all children
+ for (auto& child : children) {
+ child->Cancel();
+ child.reset();
+ }
+
+ return true;
+ }
+
+ void SubscribeCancel(TCallback callback) override {
+ Y_VERIFY(callback, "SubscribeCancel called with an empty callback");
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+
+ if (!Cancelled.load(std::memory_order_relaxed)) {
+ Callbacks.emplace_back().swap(callback);
+ return;
+ }
+ }
+
+ // Already cancelled, run immediately
+ callback();
+ }
+
+private:
+ void AddChild(TContextImpl* child) {
+ for (TContextImpl*& slot : InlineChildren) {
+ if (!slot) {
+ slot = child;
+ return;
+ }
+ }
+
+ Children.insert(child);
+ }
+
+ bool RemoveChild(TContextImpl* child) {
+ for (TContextImpl*& slot : InlineChildren) {
+ if (slot == child) {
+ slot = nullptr;
+ return true;
+ }
+ }
+
+ return Children.erase(child);
+ }
+
+ size_t CountChildren() {
+ size_t count = 0;
+
+ for (TContextImpl* ptr : InlineChildren) {
+ if (ptr) {
+ ++count;
+ }
+ }
+
+ return count + Children.size();
+ }
+
+ template<class TCallbacks>
+ static void RunCallbacksNoExcept(TCallbacks& callbacks) noexcept {
+ for (auto& callback : callbacks) {
+ if (callback) {
+ callback();
+ callback = nullptr;
+ }
+ }
+ }
+
+private:
+ // We want a simple lock here, without extra memory allocations
+ std::mutex Mutex;
+
+ // These fields are initialized on successful registration
+ TContextPtr Parent;
+ TGRpcClientLow* Owner = nullptr;
+ grpc::CompletionQueue* CQ = nullptr;
+
+ // Some children are stored inline, others are in a set
+ std::array<TContextImpl*, 2> InlineChildren{ { nullptr, nullptr } };
+ std::unordered_set<TContextImpl*> Children;
+
+ // Single callback is stored without extra allocations
+ TStackVec<TCallback, 1> Callbacks;
+
+ // Atomic flag for a faster IsCancelled() implementation
+ std::atomic<bool> Cancelled;
+};
+
+TGRpcClientLow::TGRpcClientLow(size_t numWorkerThread, bool useCompletionQueuePerThread)
+ : UseCompletionQueuePerThread_(useCompletionQueuePerThread)
+{
+ Init(numWorkerThread);
+}
+
+void TGRpcClientLow::Init(size_t numWorkerThread) {
+ SetCqState(WORKING);
+ if (UseCompletionQueuePerThread_) {
+ for (size_t i = 0; i < numWorkerThread; i++) {
+ CQS_.push_back(std::make_unique<grpc::CompletionQueue>());
+ auto* cq = CQS_.back().get();
+ WorkerThreads_.emplace_back(SystemThreadFactory()->Run([cq]() {
+ PullEvents(cq);
+ }).Release());
+ }
+ } else {
+ CQS_.push_back(std::make_unique<grpc::CompletionQueue>());
+ auto* cq = CQS_.back().get();
+ for (size_t i = 0; i < numWorkerThread; i++) {
+ WorkerThreads_.emplace_back(SystemThreadFactory()->Run([cq]() {
+ PullEvents(cq);
+ }).Release());
+ }
+ }
+}
+
+void TGRpcClientLow::AddWorkerThreadForTest() {
+ if (UseCompletionQueuePerThread_) {
+ CQS_.push_back(std::make_unique<grpc::CompletionQueue>());
+ auto* cq = CQS_.back().get();
+ WorkerThreads_.emplace_back(SystemThreadFactory()->Run([cq]() {
+ PullEvents(cq);
+ }).Release());
+ } else {
+ auto* cq = CQS_.back().get();
+ WorkerThreads_.emplace_back(SystemThreadFactory()->Run([cq]() {
+ PullEvents(cq);
+ }).Release());
+ }
+}
+
+TGRpcClientLow::~TGRpcClientLow() {
+ StopInternal(true);
+ WaitInternal();
+}
+
+void TGRpcClientLow::Stop(bool wait) {
+ StopInternal(false);
+
+ if (wait) {
+ WaitInternal();
+ }
+}
+
+void TGRpcClientLow::StopInternal(bool silent) {
+ bool shutdown;
+
+ TVector<TContextImpl::TContextPtr> cancelQueue;
+
+ {
+ std::unique_lock<std::mutex> guard(Mtx_);
+
+ auto allowStateChange = [&]() {
+ switch (GetCqState()) {
+ case WORKING:
+ return true;
+ case STOP_SILENT:
+ return !silent;
+ case STOP_EXPLICIT:
+ return false;
+ }
+
+ Y_UNREACHABLE();
+ };
+
+ if (!allowStateChange()) {
+ // Completion queue is already stopping
+ return;
+ }
+
+ SetCqState(silent ? STOP_SILENT : STOP_EXPLICIT);
+
+ if (!silent && !Contexts_.empty()) {
+ cancelQueue.reserve(Contexts_.size());
+ for (auto* ptr : Contexts_) {
+ // N.B. some contexts may be stuck in destructors
+ if (auto context = TContextImpl::LockChildPtr(ptr)) {
+ cancelQueue.emplace_back(std::move(context));
+ }
+ }
+ }
+
+ shutdown = Contexts_.empty();
+ }
+
+ for (auto& context : cancelQueue) {
+ context->Cancel();
+ context.reset();
+ }
+
+ if (shutdown) {
+ for (auto& cq : CQS_) {
+ cq->Shutdown();
+ }
+ }
+}
+
+void TGRpcClientLow::WaitInternal() {
+ std::unique_lock<std::mutex> guard(JoinMutex_);
+
+ for (auto& ti : WorkerThreads_) {
+ ti->Join();
+ }
+}
+
+void TGRpcClientLow::WaitIdle() {
+ std::unique_lock<std::mutex> guard(Mtx_);
+
+ while (!Contexts_.empty()) {
+ ContextsEmpty_.wait(guard);
+ }
+}
+
+std::shared_ptr<IQueueClientContext> TGRpcClientLow::CreateContext() {
+ std::unique_lock<std::mutex> guard(Mtx_);
+
+ auto allowCreateContext = [&]() {
+ switch (GetCqState()) {
+ case WORKING:
+ return true;
+ case STOP_SILENT:
+ case STOP_EXPLICIT:
+ return false;
+ }
+
+ Y_UNREACHABLE();
+ };
+
+ if (!allowCreateContext()) {
+ // New context creation is forbidden
+ return nullptr;
+ }
+
+ auto context = std::make_shared<TContextImpl>();
+ Contexts_.insert(context.get());
+ context->Owner = this;
+ if (UseCompletionQueuePerThread_) {
+ context->CQ = CQS_[RandomNumber(CQS_.size())].get();
+ } else {
+ context->CQ = CQS_[0].get();
+ }
+ return context;
+}
+
+void TGRpcClientLow::ForgetContext(TContextImpl* context) {
+ bool shutdown = false;
+
+ {
+ std::unique_lock<std::mutex> guard(Mtx_);
+
+ if (!Contexts_.erase(context)) {
+ Y_FAIL("Unexpected ForgetContext(%p)", context);
+ }
+
+ if (Contexts_.empty()) {
+ if (IsStopping()) {
+ shutdown = true;
+ }
+
+ ContextsEmpty_.notify_all();
+ }
+ }
+
+ if (shutdown) {
+ // This was the last context, shutdown CQ
+ for (auto& cq : CQS_) {
+ cq->Shutdown();
+ }
+ }
+}
+
+} // namespace NGRpc
diff --git a/library/cpp/grpc/client/grpc_client_low.h b/library/cpp/grpc/client/grpc_client_low.h
new file mode 100644
index 0000000000..ab0a0627be
--- /dev/null
+++ b/library/cpp/grpc/client/grpc_client_low.h
@@ -0,0 +1,1399 @@
+#pragma once
+
+#include "grpc_common.h"
+
+#include <util/thread/factory.h>
+#include <grpc++/grpc++.h>
+#include <grpc++/support/async_stream.h>
+#include <grpc++/support/async_unary_call.h>
+
+#include <deque>
+#include <typeindex>
+#include <typeinfo>
+#include <variant>
+#include <vector>
+#include <unordered_map>
+#include <unordered_set>
+#include <mutex>
+#include <shared_mutex>
+
+/*
+ * This file contains low level logic for grpc
+ * This file should not be used in high level code without special reason
+ */
+namespace NGrpc {
+
+const size_t DEFAULT_NUM_THREADS = 2;
+
+////////////////////////////////////////////////////////////////////////////////
+
+void EnableGRpcTracing();
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct TTcpKeepAliveSettings {
+ bool Enabled;
+ size_t Idle;
+ size_t Count;
+ size_t Interval;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Common interface used to execute action from grpc cq routine
+class IQueueClientEvent {
+public:
+ virtual ~IQueueClientEvent() = default;
+
+ //! Execute an action defined by implementation
+ virtual bool Execute(bool ok) = 0;
+
+ //! Finish and destroy event
+ virtual void Destroy() = 0;
+};
+
+// Implementation of IQueueClientEvent that reduces allocations
+template<class TSelf>
+class TQueueClientFixedEvent : private IQueueClientEvent {
+ using TCallback = void (TSelf::*)(bool);
+
+public:
+ TQueueClientFixedEvent(TSelf* self, TCallback callback)
+ : Self(self)
+ , Callback(callback)
+ { }
+
+ IQueueClientEvent* Prepare() {
+ Self->Ref();
+ return this;
+ }
+
+private:
+ bool Execute(bool ok) override {
+ ((*Self).*Callback)(ok);
+ return false;
+ }
+
+ void Destroy() override {
+ Self->UnRef();
+ }
+
+private:
+ TSelf* const Self;
+ TCallback const Callback;
+};
+
+class IQueueClientContext;
+using IQueueClientContextPtr = std::shared_ptr<IQueueClientContext>;
+
+// Provider of IQueueClientContext instances
+class IQueueClientContextProvider {
+public:
+ virtual ~IQueueClientContextProvider() = default;
+
+ virtual IQueueClientContextPtr CreateContext() = 0;
+};
+
+// Activity context for a low-level client
+class IQueueClientContext : public IQueueClientContextProvider {
+public:
+ virtual ~IQueueClientContext() = default;
+
+ //! Returns CompletionQueue associated with the client
+ virtual grpc::CompletionQueue* CompletionQueue() = 0;
+
+ //! Returns true if context has been cancelled
+ virtual bool IsCancelled() const = 0;
+
+ //! Tries to cancel context, calling all registered callbacks
+ virtual bool Cancel() = 0;
+
+ //! Subscribes callback to cancellation
+ //
+ // Note there's no way to unsubscribe, if subscription is temporary
+ // make sure you create a new context with CreateContext and release
+ // it as soon as it's no longer needed.
+ virtual void SubscribeCancel(std::function<void()> callback) = 0;
+
+ //! Subscribes callback to cancellation
+ //
+ // This alias is for compatibility with older code.
+ void SubscribeStop(std::function<void()> callback) {
+ SubscribeCancel(std::move(callback));
+ }
+};
+
+// Represents grpc status and error message string
+struct TGrpcStatus {
+ TString Msg;
+ TString Details;
+ int GRpcStatusCode;
+ bool InternalError;
+
+ TGrpcStatus()
+ : GRpcStatusCode(grpc::StatusCode::OK)
+ , InternalError(false)
+ { }
+
+ TGrpcStatus(TString msg, int statusCode, bool internalError)
+ : Msg(std::move(msg))
+ , GRpcStatusCode(statusCode)
+ , InternalError(internalError)
+ { }
+
+ TGrpcStatus(grpc::StatusCode status, TString msg, TString details = {})
+ : Msg(std::move(msg))
+ , Details(std::move(details))
+ , GRpcStatusCode(status)
+ , InternalError(false)
+ { }
+
+ TGrpcStatus(const grpc::Status& status)
+ : TGrpcStatus(status.error_code(), TString(status.error_message()), TString(status.error_details()))
+ { }
+
+ TGrpcStatus& operator=(const grpc::Status& status) {
+ Msg = TString(status.error_message());
+ Details = TString(status.error_details());
+ GRpcStatusCode = status.error_code();
+ InternalError = false;
+ return *this;
+ }
+
+ static TGrpcStatus Internal(TString msg) {
+ return { std::move(msg), -1, true };
+ }
+
+ bool Ok() const {
+ return !InternalError && GRpcStatusCode == grpc::StatusCode::OK;
+ }
+};
+
+bool inline IsGRpcStatusGood(const TGrpcStatus& status) {
+ return status.Ok();
+}
+
+// Response callback type - this callback will be called when request is finished
+// (or after getting each chunk in case of streaming mode)
+template<typename TResponse>
+using TResponseCallback = std::function<void (TGrpcStatus&&, TResponse&&)>;
+
+template<typename TResponse>
+using TAdvancedResponseCallback = std::function<void (const grpc::ClientContext&, TGrpcStatus&&, TResponse&&)>;
+
+// Call associated metadata
+struct TCallMeta {
+ std::shared_ptr<grpc::CallCredentials> CallCredentials;
+ std::vector<std::pair<TString, TString>> Aux;
+ std::variant<TDuration, TInstant> Timeout; // timeout as duration from now or time point in future
+};
+
+class TGRpcRequestProcessorCommon {
+protected:
+ void ApplyMeta(const TCallMeta& meta) {
+ for (const auto& rec : meta.Aux) {
+ Context.AddMetadata(rec.first, rec.second);
+ }
+ if (meta.CallCredentials) {
+ Context.set_credentials(meta.CallCredentials);
+ }
+ if (const TDuration* timeout = std::get_if<TDuration>(&meta.Timeout)) {
+ if (*timeout) {
+ auto deadline = gpr_time_add(
+ gpr_now(GPR_CLOCK_MONOTONIC),
+ gpr_time_from_micros(timeout->MicroSeconds(), GPR_TIMESPAN));
+ Context.set_deadline(deadline);
+ }
+ } else if (const TInstant* deadline = std::get_if<TInstant>(&meta.Timeout)) {
+ if (*deadline) {
+ Context.set_deadline(gpr_time_from_micros(deadline->MicroSeconds(), GPR_CLOCK_MONOTONIC));
+ }
+ }
+ }
+
+ void GetInitialMetadata(std::unordered_multimap<TString, TString>* metadata) {
+ for (const auto& [key, value] : Context.GetServerInitialMetadata()) {
+ metadata->emplace(
+ TString(key.begin(), key.end()),
+ TString(value.begin(), value.end())
+ );
+ }
+ }
+
+ grpc::Status Status;
+ grpc::ClientContext Context;
+ std::shared_ptr<IQueueClientContext> LocalContext;
+};
+
+template<typename TStub, typename TRequest, typename TResponse>
+class TSimpleRequestProcessor
+ : public TThrRefBase
+ , public IQueueClientEvent
+ , public TGRpcRequestProcessorCommon {
+ using TAsyncReaderPtr = std::unique_ptr<grpc::ClientAsyncResponseReader<TResponse>>;
+ template<typename> friend class TServiceConnection;
+public:
+ using TPtr = TIntrusivePtr<TSimpleRequestProcessor>;
+ using TAsyncRequest = TAsyncReaderPtr (TStub::*)(grpc::ClientContext*, const TRequest&, grpc::CompletionQueue*);
+
+ explicit TSimpleRequestProcessor(TResponseCallback<TResponse>&& callback)
+ : Callback_(std::move(callback))
+ { }
+
+ ~TSimpleRequestProcessor() {
+ if (!Replied_ && Callback_) {
+ Callback_(TGrpcStatus::Internal("request left unhandled"), std::move(Reply_));
+ Callback_ = nullptr; // free resources as early as possible
+ }
+ }
+
+ bool Execute(bool ok) override {
+ {
+ std::unique_lock<std::mutex> guard(Mutex_);
+ LocalContext.reset();
+ }
+ TGrpcStatus status;
+ if (ok) {
+ status = Status;
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+ Replied_ = true;
+ Callback_(std::move(status), std::move(Reply_));
+ Callback_ = nullptr; // free resources as early as possible
+ return false;
+ }
+
+ void Destroy() override {
+ UnRef();
+ }
+
+private:
+ IQueueClientEvent* FinishedEvent() {
+ Ref();
+ return this;
+ }
+
+ void Start(TStub& stub, TAsyncRequest asyncRequest, const TRequest& request, IQueueClientContextProvider* provider) {
+ auto context = provider->CreateContext();
+ if (!context) {
+ Replied_ = true;
+ Callback_(TGrpcStatus(grpc::StatusCode::CANCELLED, "Client is shutting down"), std::move(Reply_));
+ Callback_ = nullptr;
+ return;
+ }
+ {
+ std::unique_lock<std::mutex> guard(Mutex_);
+ LocalContext = context;
+ Reader_ = (stub.*asyncRequest)(&Context, request, context->CompletionQueue());
+ Reader_->Finish(&Reply_, &Status, FinishedEvent());
+ }
+ context->SubscribeStop([self = TPtr(this)] {
+ self->Stop();
+ });
+ }
+
+ void Stop() {
+ Context.TryCancel();
+ }
+
+ TResponseCallback<TResponse> Callback_;
+ TResponse Reply_;
+ std::mutex Mutex_;
+ TAsyncReaderPtr Reader_;
+
+ bool Replied_ = false;
+};
+
+template<typename TStub, typename TRequest, typename TResponse>
+class TAdvancedRequestProcessor
+ : public TThrRefBase
+ , public IQueueClientEvent
+ , public TGRpcRequestProcessorCommon {
+ using TAsyncReaderPtr = std::unique_ptr<grpc::ClientAsyncResponseReader<TResponse>>;
+ template<typename> friend class TServiceConnection;
+public:
+ using TPtr = TIntrusivePtr<TAdvancedRequestProcessor>;
+ using TAsyncRequest = TAsyncReaderPtr (TStub::*)(grpc::ClientContext*, const TRequest&, grpc::CompletionQueue*);
+
+ explicit TAdvancedRequestProcessor(TAdvancedResponseCallback<TResponse>&& callback)
+ : Callback_(std::move(callback))
+ { }
+
+ ~TAdvancedRequestProcessor() {
+ if (!Replied_ && Callback_) {
+ Callback_(Context, TGrpcStatus::Internal("request left unhandled"), std::move(Reply_));
+ Callback_ = nullptr; // free resources as early as possible
+ }
+ }
+
+ bool Execute(bool ok) override {
+ {
+ std::unique_lock<std::mutex> guard(Mutex_);
+ LocalContext.reset();
+ }
+ TGrpcStatus status;
+ if (ok) {
+ status = Status;
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+ Replied_ = true;
+ Callback_(Context, std::move(status), std::move(Reply_));
+ Callback_ = nullptr; // free resources as early as possible
+ return false;
+ }
+
+ void Destroy() override {
+ UnRef();
+ }
+
+private:
+ IQueueClientEvent* FinishedEvent() {
+ Ref();
+ return this;
+ }
+
+ void Start(TStub& stub, TAsyncRequest asyncRequest, const TRequest& request, IQueueClientContextProvider* provider) {
+ auto context = provider->CreateContext();
+ if (!context) {
+ Replied_ = true;
+ Callback_(Context, TGrpcStatus(grpc::StatusCode::CANCELLED, "Client is shutting down"), std::move(Reply_));
+ Callback_ = nullptr;
+ return;
+ }
+ {
+ std::unique_lock<std::mutex> guard(Mutex_);
+ LocalContext = context;
+ Reader_ = (stub.*asyncRequest)(&Context, request, context->CompletionQueue());
+ Reader_->Finish(&Reply_, &Status, FinishedEvent());
+ }
+ context->SubscribeStop([self = TPtr(this)] {
+ self->Stop();
+ });
+ }
+
+ void Stop() {
+ Context.TryCancel();
+ }
+
+ TAdvancedResponseCallback<TResponse> Callback_;
+ TResponse Reply_;
+ std::mutex Mutex_;
+ TAsyncReaderPtr Reader_;
+
+ bool Replied_ = false;
+};
+
+template<class TResponse>
+class IStreamRequestReadProcessor : public TThrRefBase {
+public:
+ using TPtr = TIntrusivePtr<IStreamRequestReadProcessor>;
+ using TReadCallback = std::function<void(TGrpcStatus&&)>;
+
+ /**
+ * Asynchronously cancel the request
+ */
+ virtual void Cancel() = 0;
+
+ /**
+ * Scheduled initial server metadata read from the stream
+ */
+ virtual void ReadInitialMetadata(std::unordered_multimap<TString, TString>* metadata, TReadCallback callback) = 0;
+
+ /**
+ * Scheduled response read from the stream
+ * Callback will be called with the status if it failed
+ * Only one Read or Finish call may be active at a time
+ */
+ virtual void Read(TResponse* response, TReadCallback callback) = 0;
+
+ /**
+ * Stop reading and gracefully finish the stream
+ * Only one Read or Finish call may be active at a time
+ */
+ virtual void Finish(TReadCallback callback) = 0;
+
+ /**
+ * Additional callback to be called when stream has finished
+ */
+ virtual void AddFinishedCallback(TReadCallback callback) = 0;
+};
+
+template<class TRequest, class TResponse>
+class IStreamRequestReadWriteProcessor : public IStreamRequestReadProcessor<TResponse> {
+public:
+ using TPtr = TIntrusivePtr<IStreamRequestReadWriteProcessor>;
+ using TWriteCallback = std::function<void(TGrpcStatus&&)>;
+
+ /**
+ * Scheduled request write to the stream
+ */
+ virtual void Write(TRequest&& request, TWriteCallback callback = { }) = 0;
+};
+
+class TGRpcKeepAliveSocketMutator;
+
+// Class to hold stubs allocated on channel.
+// It is poor documented part of grpc. See KIKIMR-6109 and comment to this commit
+
+// Stub holds shared_ptr<ChannelInterface>, so we can destroy this holder even if
+// request processor using stub
+class TStubsHolder : public TNonCopyable {
+ using TypeInfoRef = std::reference_wrapper<const std::type_info>;
+
+ struct THasher {
+ std::size_t operator()(TypeInfoRef code) const {
+ return code.get().hash_code();
+ }
+ };
+
+ struct TEqualTo {
+ bool operator()(TypeInfoRef lhs, TypeInfoRef rhs) const {
+ return lhs.get() == rhs.get();
+ }
+ };
+public:
+ TStubsHolder(std::shared_ptr<grpc::ChannelInterface> channel)
+ : ChannelInterface_(channel)
+ {}
+
+ // Returns true if channel can't be used to perform request now
+ bool IsChannelBroken() const {
+ auto state = ChannelInterface_->GetState(false);
+ return state == GRPC_CHANNEL_SHUTDOWN ||
+ state == GRPC_CHANNEL_TRANSIENT_FAILURE;
+ }
+
+ template<typename TStub>
+ std::shared_ptr<TStub> GetOrCreateStub() {
+ const auto& stubId = typeid(TStub);
+ {
+ std::shared_lock readGuard(RWMutex_);
+ const auto it = Stubs_.find(stubId);
+ if (it != Stubs_.end()) {
+ return std::static_pointer_cast<TStub>(it->second);
+ }
+ }
+ {
+ std::unique_lock writeGuard(RWMutex_);
+ auto it = Stubs_.emplace(stubId, nullptr);
+ if (!it.second) {
+ return std::static_pointer_cast<TStub>(it.first->second);
+ } else {
+ it.first->second = std::make_shared<TStub>(ChannelInterface_);
+ return std::static_pointer_cast<TStub>(it.first->second);
+ }
+ }
+ }
+
+ const TInstant& GetLastUseTime() const {
+ return LastUsed_;
+ }
+
+ void SetLastUseTime(const TInstant& time) {
+ LastUsed_ = time;
+ }
+private:
+ TInstant LastUsed_ = Now();
+ std::shared_mutex RWMutex_;
+ std::unordered_map<TypeInfoRef, std::shared_ptr<void>, THasher, TEqualTo> Stubs_;
+ std::shared_ptr<grpc::ChannelInterface> ChannelInterface_;
+};
+
+class TChannelPool {
+public:
+ TChannelPool(const TTcpKeepAliveSettings& tcpKeepAliveSettings, const TDuration& expireTime = TDuration::Minutes(6));
+ //Allows to CreateStub from TStubsHolder under lock
+ //The callback will be called just during GetStubsHolderLocked call
+ void GetStubsHolderLocked(const TString& channelId, const TGRpcClientConfig& config, std::function<void(TStubsHolder&)> cb);
+ void DeleteChannel(const TString& channelId);
+ void DeleteExpiredStubsHolders();
+private:
+ std::shared_mutex RWMutex_;
+ std::unordered_map<TString, TStubsHolder> Pool_;
+ std::multimap<TInstant, TString> LastUsedQueue_;
+ TTcpKeepAliveSettings TcpKeepAliveSettings_;
+ TDuration ExpireTime_;
+ TDuration UpdateReUseTime_;
+ void EraseFromQueueByTime(const TInstant& lastUseTime, const TString& channelId);
+};
+
+template<class TResponse>
+using TStreamReaderCallback = std::function<void(TGrpcStatus&&, typename IStreamRequestReadProcessor<TResponse>::TPtr)>;
+
+template<typename TStub, typename TRequest, typename TResponse>
+class TStreamRequestReadProcessor
+ : public IStreamRequestReadProcessor<TResponse>
+ , public TGRpcRequestProcessorCommon {
+ template<typename> friend class TServiceConnection;
+public:
+ using TSelf = TStreamRequestReadProcessor;
+ using TAsyncReaderPtr = std::unique_ptr<grpc::ClientAsyncReader<TResponse>>;
+ using TAsyncRequest = TAsyncReaderPtr (TStub::*)(grpc::ClientContext*, const TRequest&, grpc::CompletionQueue*, void*);
+ using TReaderCallback = TStreamReaderCallback<TResponse>;
+ using TPtr = TIntrusivePtr<TSelf>;
+ using TBase = IStreamRequestReadProcessor<TResponse>;
+ using TReadCallback = typename TBase::TReadCallback;
+
+ explicit TStreamRequestReadProcessor(TReaderCallback&& callback)
+ : Callback(std::move(callback))
+ {
+ Y_VERIFY(Callback, "Missing connected callback");
+ }
+
+ void Cancel() override {
+ Context.TryCancel();
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ Cancelled = true;
+ if (Started && !ReadFinished) {
+ if (!ReadActive) {
+ ReadFinished = true;
+ }
+ if (ReadFinished) {
+ Stream->Finish(&Status, OnFinishedTag.Prepare());
+ }
+ }
+ }
+ }
+
+ void ReadInitialMetadata(std::unordered_multimap<TString, TString>* metadata, TReadCallback callback) override {
+ TGrpcStatus status;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ Y_VERIFY(!ReadActive, "Multiple Read/Finish calls detected");
+ if (!Finished && !HasInitialMetadata) {
+ ReadActive = true;
+ ReadCallback = std::move(callback);
+ InitialMetadata = metadata;
+ if (!ReadFinished) {
+ Stream->ReadInitialMetadata(OnReadDoneTag.Prepare());
+ }
+ return;
+ }
+ if (!HasInitialMetadata) {
+ if (FinishedOk) {
+ status = Status;
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+ } else {
+ GetInitialMetadata(metadata);
+ }
+ }
+
+ callback(std::move(status));
+ }
+
+ void Read(TResponse* message, TReadCallback callback) override {
+ TGrpcStatus status;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ Y_VERIFY(!ReadActive, "Multiple Read/Finish calls detected");
+ if (!Finished) {
+ ReadActive = true;
+ ReadCallback = std::move(callback);
+ if (!ReadFinished) {
+ Stream->Read(message, OnReadDoneTag.Prepare());
+ }
+ return;
+ }
+ if (FinishedOk) {
+ status = Status;
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+ }
+
+ if (status.Ok()) {
+ status = TGrpcStatus(grpc::StatusCode::OUT_OF_RANGE, "Read EOF");
+ }
+
+ callback(std::move(status));
+ }
+
+ void Finish(TReadCallback callback) override {
+ TGrpcStatus status;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ Y_VERIFY(!ReadActive, "Multiple Read/Finish calls detected");
+ if (!Finished) {
+ ReadActive = true;
+ FinishCallback = std::move(callback);
+ if (!ReadFinished) {
+ ReadFinished = true;
+ }
+ Stream->Finish(&Status, OnFinishedTag.Prepare());
+ return;
+ }
+ if (FinishedOk) {
+ status = Status;
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+ }
+
+ callback(std::move(status));
+ }
+
+ void AddFinishedCallback(TReadCallback callback) override {
+ Y_VERIFY(callback, "Unexpected empty callback");
+
+ TGrpcStatus status;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ if (!Finished) {
+ FinishedCallbacks.emplace_back().swap(callback);
+ return;
+ }
+
+ if (FinishedOk) {
+ status = Status;
+ } else if (Cancelled) {
+ status = TGrpcStatus(grpc::StatusCode::CANCELLED, "Stream cancelled");
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+ }
+
+ callback(std::move(status));
+ }
+
+private:
+ void Start(TStub& stub, const TRequest& request, TAsyncRequest asyncRequest, IQueueClientContextProvider* provider) {
+ auto context = provider->CreateContext();
+ if (!context) {
+ auto callback = std::move(Callback);
+ TGrpcStatus status(grpc::StatusCode::CANCELLED, "Client is shutting down");
+ callback(std::move(status), nullptr);
+ return;
+ }
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ LocalContext = context;
+ Stream = (stub.*asyncRequest)(&Context, request, context->CompletionQueue(), OnStartDoneTag.Prepare());
+ }
+
+ context->SubscribeStop([self = TPtr(this)] {
+ self->Cancel();
+ });
+ }
+
+ void OnReadDone(bool ok) {
+ TGrpcStatus status;
+ TReadCallback callback;
+ std::unordered_multimap<TString, TString>* initialMetadata = nullptr;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ Y_VERIFY(ReadActive, "Unexpected Read done callback");
+ Y_VERIFY(!ReadFinished, "Unexpected ReadFinished flag");
+
+ if (!ok || Cancelled) {
+ ReadFinished = true;
+
+ Stream->Finish(&Status, OnFinishedTag.Prepare());
+ if (!ok) {
+ // Keep ReadActive=true, so callback is called
+ // after the call is finished with an error
+ return;
+ }
+ }
+
+ callback = std::move(ReadCallback);
+ ReadCallback = nullptr;
+ ReadActive = false;
+ initialMetadata = InitialMetadata;
+ InitialMetadata = nullptr;
+ HasInitialMetadata = true;
+ }
+
+ if (initialMetadata) {
+ GetInitialMetadata(initialMetadata);
+ }
+
+ callback(std::move(status));
+ }
+
+ void OnStartDone(bool ok) {
+ TReaderCallback callback;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ Started = true;
+ if (!ok || Cancelled) {
+ ReadFinished = true;
+ Stream->Finish(&Status, OnFinishedTag.Prepare());
+ return;
+ }
+ callback = std::move(Callback);
+ Callback = nullptr;
+ }
+
+ callback({ }, typename TBase::TPtr(this));
+ }
+
+ void OnFinished(bool ok) {
+ TGrpcStatus status;
+ std::vector<TReadCallback> finishedCallbacks;
+ TReaderCallback startCallback;
+ TReadCallback readCallback;
+ TReadCallback finishCallback;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+
+ Finished = true;
+ FinishedOk = ok;
+ LocalContext.reset();
+
+ if (ok) {
+ status = Status;
+ } else if (Cancelled) {
+ status = TGrpcStatus(grpc::StatusCode::CANCELLED, "Stream cancelled");
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+
+ finishedCallbacks.swap(FinishedCallbacks);
+
+ if (Callback) {
+ Y_VERIFY(!ReadActive);
+ startCallback = std::move(Callback);
+ Callback = nullptr;
+ } else if (ReadActive) {
+ if (ReadCallback) {
+ readCallback = std::move(ReadCallback);
+ ReadCallback = nullptr;
+ } else {
+ finishCallback = std::move(FinishCallback);
+ FinishCallback = nullptr;
+ }
+ ReadActive = false;
+ }
+ }
+
+ for (auto& finishedCallback : finishedCallbacks) {
+ auto statusCopy = status;
+ finishedCallback(std::move(statusCopy));
+ }
+
+ if (startCallback) {
+ if (status.Ok()) {
+ status = TGrpcStatus(grpc::StatusCode::UNKNOWN, "Unknown stream failure");
+ }
+ startCallback(std::move(status), nullptr);
+ } else if (readCallback) {
+ if (status.Ok()) {
+ status = TGrpcStatus(grpc::StatusCode::OUT_OF_RANGE, "Read EOF");
+ }
+ readCallback(std::move(status));
+ } else if (finishCallback) {
+ finishCallback(std::move(status));
+ }
+ }
+
+ TReaderCallback Callback;
+ TAsyncReaderPtr Stream;
+ using TFixedEvent = TQueueClientFixedEvent<TSelf>;
+ std::mutex Mutex;
+ TFixedEvent OnReadDoneTag = { this, &TSelf::OnReadDone };
+ TFixedEvent OnStartDoneTag = { this, &TSelf::OnStartDone };
+ TFixedEvent OnFinishedTag = { this, &TSelf::OnFinished };
+
+ TReadCallback ReadCallback;
+ TReadCallback FinishCallback;
+ std::vector<TReadCallback> FinishedCallbacks;
+ std::unordered_multimap<TString, TString>* InitialMetadata = nullptr;
+ bool Started = false;
+ bool HasInitialMetadata = false;
+ bool ReadActive = false;
+ bool ReadFinished = false;
+ bool Finished = false;
+ bool Cancelled = false;
+ bool FinishedOk = false;
+};
+
+template<class TRequest, class TResponse>
+using TStreamConnectedCallback = std::function<void(TGrpcStatus&&, typename IStreamRequestReadWriteProcessor<TRequest, TResponse>::TPtr)>;
+
+template<class TStub, class TRequest, class TResponse>
+class TStreamRequestReadWriteProcessor
+ : public IStreamRequestReadWriteProcessor<TRequest, TResponse>
+ , public TGRpcRequestProcessorCommon {
+public:
+ using TSelf = TStreamRequestReadWriteProcessor;
+ using TBase = IStreamRequestReadWriteProcessor<TRequest, TResponse>;
+ using TPtr = TIntrusivePtr<TSelf>;
+ using TConnectedCallback = TStreamConnectedCallback<TRequest, TResponse>;
+ using TReadCallback = typename TBase::TReadCallback;
+ using TWriteCallback = typename TBase::TWriteCallback;
+ using TAsyncReaderWriterPtr = std::unique_ptr<grpc::ClientAsyncReaderWriter<TRequest, TResponse>>;
+ using TAsyncRequest = TAsyncReaderWriterPtr (TStub::*)(grpc::ClientContext*, grpc::CompletionQueue*, void*);
+
+ explicit TStreamRequestReadWriteProcessor(TConnectedCallback&& callback)
+ : ConnectedCallback(std::move(callback))
+ {
+ Y_VERIFY(ConnectedCallback, "Missing connected callback");
+ }
+
+ void Cancel() override {
+ Context.TryCancel();
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ Cancelled = true;
+ if (Started && !(ReadFinished && WriteFinished)) {
+ if (!ReadActive) {
+ ReadFinished = true;
+ }
+ if (!WriteActive) {
+ WriteFinished = true;
+ }
+ if (ReadFinished && WriteFinished) {
+ Stream->Finish(&Status, OnFinishedTag.Prepare());
+ }
+ }
+ }
+ }
+
+ void Write(TRequest&& request, TWriteCallback callback) override {
+ TGrpcStatus status;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ if (Cancelled || ReadFinished || WriteFinished) {
+ status = TGrpcStatus(grpc::StatusCode::CANCELLED, "Write request dropped");
+ } else if (WriteActive) {
+ auto& item = WriteQueue.emplace_back();
+ item.Callback.swap(callback);
+ item.Request.Swap(&request);
+ } else {
+ WriteActive = true;
+ WriteCallback.swap(callback);
+ Stream->Write(request, OnWriteDoneTag.Prepare());
+ }
+ }
+
+ if (!status.Ok() && callback) {
+ callback(std::move(status));
+ }
+ }
+
+ void ReadInitialMetadata(std::unordered_multimap<TString, TString>* metadata, TReadCallback callback) override {
+ TGrpcStatus status;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ Y_VERIFY(!ReadActive, "Multiple Read/Finish calls detected");
+ if (!Finished && !HasInitialMetadata) {
+ ReadActive = true;
+ ReadCallback = std::move(callback);
+ InitialMetadata = metadata;
+ if (!ReadFinished) {
+ Stream->ReadInitialMetadata(OnReadDoneTag.Prepare());
+ }
+ return;
+ }
+ if (!HasInitialMetadata) {
+ if (FinishedOk) {
+ status = Status;
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+ } else {
+ GetInitialMetadata(metadata);
+ }
+ }
+
+ callback(std::move(status));
+ }
+
+ void Read(TResponse* message, TReadCallback callback) override {
+ TGrpcStatus status;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ Y_VERIFY(!ReadActive, "Multiple Read/Finish calls detected");
+ if (!Finished) {
+ ReadActive = true;
+ ReadCallback = std::move(callback);
+ if (!ReadFinished) {
+ Stream->Read(message, OnReadDoneTag.Prepare());
+ }
+ return;
+ }
+ if (FinishedOk) {
+ status = Status;
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+ }
+
+ if (status.Ok()) {
+ status = TGrpcStatus(grpc::StatusCode::OUT_OF_RANGE, "Read EOF");
+ }
+
+ callback(std::move(status));
+ }
+
+ void Finish(TReadCallback callback) override {
+ TGrpcStatus status;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ Y_VERIFY(!ReadActive, "Multiple Read/Finish calls detected");
+ if (!Finished) {
+ ReadActive = true;
+ FinishCallback = std::move(callback);
+ if (!ReadFinished) {
+ ReadFinished = true;
+ if (!WriteActive) {
+ WriteFinished = true;
+ }
+ if (WriteFinished) {
+ Stream->Finish(&Status, OnFinishedTag.Prepare());
+ }
+ }
+ return;
+ }
+ if (FinishedOk) {
+ status = Status;
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+ }
+
+ callback(std::move(status));
+ }
+
+ void AddFinishedCallback(TReadCallback callback) override {
+ Y_VERIFY(callback, "Unexpected empty callback");
+
+ TGrpcStatus status;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ if (!Finished) {
+ FinishedCallbacks.emplace_back().swap(callback);
+ return;
+ }
+
+ if (FinishedOk) {
+ status = Status;
+ } else if (Cancelled) {
+ status = TGrpcStatus(grpc::StatusCode::CANCELLED, "Stream cancelled");
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+ }
+
+ callback(std::move(status));
+ }
+
+private:
+ template<typename> friend class TServiceConnection;
+
+ void Start(TStub& stub, TAsyncRequest asyncRequest, IQueueClientContextProvider* provider) {
+ auto context = provider->CreateContext();
+ if (!context) {
+ auto callback = std::move(ConnectedCallback);
+ TGrpcStatus status(grpc::StatusCode::CANCELLED, "Client is shutting down");
+ callback(std::move(status), nullptr);
+ return;
+ }
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ LocalContext = context;
+ Stream = (stub.*asyncRequest)(&Context, context->CompletionQueue(), OnConnectedTag.Prepare());
+ }
+
+ context->SubscribeStop([self = TPtr(this)] {
+ self->Cancel();
+ });
+ }
+
+private:
+ void OnConnected(bool ok) {
+ TConnectedCallback callback;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ Started = true;
+ if (!ok || Cancelled) {
+ ReadFinished = true;
+ WriteFinished = true;
+ Stream->Finish(&Status, OnFinishedTag.Prepare());
+ return;
+ }
+
+ callback = std::move(ConnectedCallback);
+ ConnectedCallback = nullptr;
+ }
+
+ callback({ }, typename TBase::TPtr(this));
+ }
+
+ void OnReadDone(bool ok) {
+ TGrpcStatus status;
+ TReadCallback callback;
+ std::unordered_multimap<TString, TString>* initialMetadata = nullptr;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ Y_VERIFY(ReadActive, "Unexpected Read done callback");
+ Y_VERIFY(!ReadFinished, "Unexpected ReadFinished flag");
+
+ if (!ok || Cancelled || WriteFinished) {
+ ReadFinished = true;
+ if (!WriteActive) {
+ WriteFinished = true;
+ }
+ if (WriteFinished) {
+ Stream->Finish(&Status, OnFinishedTag.Prepare());
+ }
+ if (!ok) {
+ // Keep ReadActive=true, so callback is called
+ // after the call is finished with an error
+ return;
+ }
+ }
+
+ callback = std::move(ReadCallback);
+ ReadCallback = nullptr;
+ ReadActive = false;
+ initialMetadata = InitialMetadata;
+ InitialMetadata = nullptr;
+ HasInitialMetadata = true;
+ }
+
+ if (initialMetadata) {
+ GetInitialMetadata(initialMetadata);
+ }
+
+ callback(std::move(status));
+ }
+
+ void OnWriteDone(bool ok) {
+ TWriteCallback okCallback;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ Y_VERIFY(WriteActive, "Unexpected Write done callback");
+ Y_VERIFY(!WriteFinished, "Unexpected WriteFinished flag");
+
+ if (ok) {
+ okCallback.swap(WriteCallback);
+ } else if (WriteCallback) {
+ // Put callback back on the queue until OnFinished
+ auto& item = WriteQueue.emplace_front();
+ item.Callback.swap(WriteCallback);
+ }
+
+ if (!ok || Cancelled) {
+ WriteActive = false;
+ WriteFinished = true;
+ if (!ReadActive) {
+ ReadFinished = true;
+ }
+ if (ReadFinished) {
+ Stream->Finish(&Status, OnFinishedTag.Prepare());
+ }
+ } else if (!WriteQueue.empty()) {
+ WriteCallback.swap(WriteQueue.front().Callback);
+ Stream->Write(WriteQueue.front().Request, OnWriteDoneTag.Prepare());
+ WriteQueue.pop_front();
+ } else {
+ WriteActive = false;
+ if (ReadFinished) {
+ WriteFinished = true;
+ Stream->Finish(&Status, OnFinishedTag.Prepare());
+ }
+ }
+ }
+
+ if (okCallback) {
+ okCallback(TGrpcStatus());
+ }
+ }
+
+ void OnFinished(bool ok) {
+ TGrpcStatus status;
+ std::deque<TWriteItem> writesDropped;
+ std::vector<TReadCallback> finishedCallbacks;
+ TConnectedCallback connectedCallback;
+ TReadCallback readCallback;
+ TReadCallback finishCallback;
+
+ {
+ std::unique_lock<std::mutex> guard(Mutex);
+ Finished = true;
+ FinishedOk = ok;
+ LocalContext.reset();
+
+ if (ok) {
+ status = Status;
+ } else if (Cancelled) {
+ status = TGrpcStatus(grpc::StatusCode::CANCELLED, "Stream cancelled");
+ } else {
+ status = TGrpcStatus::Internal("Unexpected error");
+ }
+
+ writesDropped.swap(WriteQueue);
+ finishedCallbacks.swap(FinishedCallbacks);
+
+ if (ConnectedCallback) {
+ Y_VERIFY(!ReadActive);
+ connectedCallback = std::move(ConnectedCallback);
+ ConnectedCallback = nullptr;
+ } else if (ReadActive) {
+ if (ReadCallback) {
+ readCallback = std::move(ReadCallback);
+ ReadCallback = nullptr;
+ } else {
+ finishCallback = std::move(FinishCallback);
+ FinishCallback = nullptr;
+ }
+ ReadActive = false;
+ }
+ }
+
+ for (auto& item : writesDropped) {
+ if (item.Callback) {
+ TGrpcStatus writeStatus = status;
+ if (writeStatus.Ok()) {
+ writeStatus = TGrpcStatus(grpc::StatusCode::CANCELLED, "Write request dropped");
+ }
+ item.Callback(std::move(writeStatus));
+ }
+ }
+
+ for (auto& finishedCallback : finishedCallbacks) {
+ TGrpcStatus statusCopy = status;
+ finishedCallback(std::move(statusCopy));
+ }
+
+ if (connectedCallback) {
+ if (status.Ok()) {
+ status = TGrpcStatus(grpc::StatusCode::UNKNOWN, "Unknown stream failure");
+ }
+ connectedCallback(std::move(status), nullptr);
+ } else if (readCallback) {
+ if (status.Ok()) {
+ status = TGrpcStatus(grpc::StatusCode::OUT_OF_RANGE, "Read EOF");
+ }
+ readCallback(std::move(status));
+ } else if (finishCallback) {
+ finishCallback(std::move(status));
+ }
+ }
+
+private:
+ struct TWriteItem {
+ TWriteCallback Callback;
+ TRequest Request;
+ };
+
+private:
+ using TFixedEvent = TQueueClientFixedEvent<TSelf>;
+
+ TFixedEvent OnConnectedTag = { this, &TSelf::OnConnected };
+ TFixedEvent OnReadDoneTag = { this, &TSelf::OnReadDone };
+ TFixedEvent OnWriteDoneTag = { this, &TSelf::OnWriteDone };
+ TFixedEvent OnFinishedTag = { this, &TSelf::OnFinished };
+
+private:
+ std::mutex Mutex;
+ TAsyncReaderWriterPtr Stream;
+ TConnectedCallback ConnectedCallback;
+ TReadCallback ReadCallback;
+ TReadCallback FinishCallback;
+ std::vector<TReadCallback> FinishedCallbacks;
+ std::deque<TWriteItem> WriteQueue;
+ TWriteCallback WriteCallback;
+ std::unordered_multimap<TString, TString>* InitialMetadata = nullptr;
+ bool Started = false;
+ bool HasInitialMetadata = false;
+ bool ReadActive = false;
+ bool ReadFinished = false;
+ bool WriteActive = false;
+ bool WriteFinished = false;
+ bool Finished = false;
+ bool Cancelled = false;
+ bool FinishedOk = false;
+};
+
+class TGRpcClientLow;
+
+template<typename TGRpcService>
+class TServiceConnection {
+ using TStub = typename TGRpcService::Stub;
+ friend class TGRpcClientLow;
+
+public:
+ /*
+ * Start simple request
+ */
+ template<typename TRequest, typename TResponse>
+ void DoRequest(const TRequest& request,
+ TResponseCallback<TResponse> callback,
+ typename TSimpleRequestProcessor<TStub, TRequest, TResponse>::TAsyncRequest asyncRequest,
+ const TCallMeta& metas = { },
+ IQueueClientContextProvider* provider = nullptr)
+ {
+ auto processor = MakeIntrusive<TSimpleRequestProcessor<TStub, TRequest, TResponse>>(std::move(callback));
+ processor->ApplyMeta(metas);
+ processor->Start(*Stub_, asyncRequest, request, provider ? provider : Provider_);
+ }
+
+ /*
+ * Start simple request
+ */
+ template<typename TRequest, typename TResponse>
+ void DoAdvancedRequest(const TRequest& request,
+ TAdvancedResponseCallback<TResponse> callback,
+ typename TAdvancedRequestProcessor<TStub, TRequest, TResponse>::TAsyncRequest asyncRequest,
+ const TCallMeta& metas = { },
+ IQueueClientContextProvider* provider = nullptr)
+ {
+ auto processor = MakeIntrusive<TAdvancedRequestProcessor<TStub, TRequest, TResponse>>(std::move(callback));
+ processor->ApplyMeta(metas);
+ processor->Start(*Stub_, asyncRequest, request, provider ? provider : Provider_);
+ }
+
+ /*
+ * Start bidirectional streamming
+ */
+ template<typename TRequest, typename TResponse>
+ void DoStreamRequest(TStreamConnectedCallback<TRequest, TResponse> callback,
+ typename TStreamRequestReadWriteProcessor<TStub, TRequest, TResponse>::TAsyncRequest asyncRequest,
+ const TCallMeta& metas = { },
+ IQueueClientContextProvider* provider = nullptr)
+ {
+ auto processor = MakeIntrusive<TStreamRequestReadWriteProcessor<TStub, TRequest, TResponse>>(std::move(callback));
+ processor->ApplyMeta(metas);
+ processor->Start(*Stub_, std::move(asyncRequest), provider ? provider : Provider_);
+ }
+
+ /*
+ * Start streaming response reading (one request, many responses)
+ */
+ template<typename TRequest, typename TResponse>
+ void DoStreamRequest(const TRequest& request,
+ TStreamReaderCallback<TResponse> callback,
+ typename TStreamRequestReadProcessor<TStub, TRequest, TResponse>::TAsyncRequest asyncRequest,
+ const TCallMeta& metas = { },
+ IQueueClientContextProvider* provider = nullptr)
+ {
+ auto processor = MakeIntrusive<TStreamRequestReadProcessor<TStub, TRequest, TResponse>>(std::move(callback));
+ processor->ApplyMeta(metas);
+ processor->Start(*Stub_, request, std::move(asyncRequest), provider ? provider : Provider_);
+ }
+
+private:
+ TServiceConnection(std::shared_ptr<grpc::ChannelInterface> ci,
+ IQueueClientContextProvider* provider)
+ : Stub_(TGRpcService::NewStub(ci))
+ , Provider_(provider)
+ {
+ Y_VERIFY(Provider_, "Connection does not have a queue provider");
+ }
+
+ TServiceConnection(TStubsHolder& holder,
+ IQueueClientContextProvider* provider)
+ : Stub_(holder.GetOrCreateStub<TStub>())
+ , Provider_(provider)
+ {
+ Y_VERIFY(Provider_, "Connection does not have a queue provider");
+ }
+
+ std::shared_ptr<TStub> Stub_;
+ IQueueClientContextProvider* Provider_;
+};
+
+class TGRpcClientLow
+ : public IQueueClientContextProvider
+{
+ class TContextImpl;
+ friend class TContextImpl;
+
+ enum ECqState : TAtomicBase {
+ WORKING = 0,
+ STOP_SILENT = 1,
+ STOP_EXPLICIT = 2,
+ };
+
+public:
+ explicit TGRpcClientLow(size_t numWorkerThread = DEFAULT_NUM_THREADS, bool useCompletionQueuePerThread = false);
+ ~TGRpcClientLow();
+
+ // Tries to stop all currently running requests (via their stop callbacks)
+ // Will shutdown CQ and drain events once all requests have finished
+ // No new requests may be started after this call
+ void Stop(bool wait = false);
+
+ // Waits until all currently running requests finish execution
+ void WaitIdle();
+
+ inline bool IsStopping() const {
+ switch (GetCqState()) {
+ case WORKING:
+ return false;
+ case STOP_SILENT:
+ case STOP_EXPLICIT:
+ return true;
+ }
+
+ Y_UNREACHABLE();
+ }
+
+ IQueueClientContextPtr CreateContext() override;
+
+ template<typename TGRpcService>
+ std::unique_ptr<TServiceConnection<TGRpcService>> CreateGRpcServiceConnection(const TGRpcClientConfig& config) {
+ return std::unique_ptr<TServiceConnection<TGRpcService>>(new TServiceConnection<TGRpcService>(CreateChannelInterface(config), this));
+ }
+
+ template<typename TGRpcService>
+ std::unique_ptr<TServiceConnection<TGRpcService>> CreateGRpcServiceConnection(TStubsHolder& holder) {
+ return std::unique_ptr<TServiceConnection<TGRpcService>>(new TServiceConnection<TGRpcService>(holder, this));
+ }
+
+ // Tests only, not thread-safe
+ void AddWorkerThreadForTest();
+
+private:
+ using IThreadRef = std::unique_ptr<IThreadFactory::IThread>;
+ using CompletionQueueRef = std::unique_ptr<grpc::CompletionQueue>;
+ void Init(size_t numWorkerThread);
+
+ inline ECqState GetCqState() const { return (ECqState) AtomicGet(CqState_); }
+ inline void SetCqState(ECqState state) { AtomicSet(CqState_, state); }
+
+ void StopInternal(bool silent);
+ void WaitInternal();
+
+ void ForgetContext(TContextImpl* context);
+
+private:
+ bool UseCompletionQueuePerThread_;
+ std::vector<CompletionQueueRef> CQS_;
+ std::vector<IThreadRef> WorkerThreads_;
+ TAtomic CqState_ = -1;
+
+ std::mutex Mtx_;
+ std::condition_variable ContextsEmpty_;
+ std::unordered_set<TContextImpl*> Contexts_;
+
+ std::mutex JoinMutex_;
+};
+
+} // namespace NGRpc
diff --git a/library/cpp/grpc/client/grpc_common.h b/library/cpp/grpc/client/grpc_common.h
new file mode 100644
index 0000000000..ffcdafe045
--- /dev/null
+++ b/library/cpp/grpc/client/grpc_common.h
@@ -0,0 +1,84 @@
+#pragma once
+
+#include <grpc++/grpc++.h>
+#include <grpc++/resource_quota.h>
+
+#include <util/datetime/base.h>
+#include <unordered_map>
+#include <util/generic/string.h>
+
+constexpr ui64 DEFAULT_GRPC_MESSAGE_SIZE_LIMIT = 64000000;
+
+namespace NGrpc {
+
+struct TGRpcClientConfig {
+ TString Locator; // format host:port
+ TDuration Timeout = TDuration::Max(); // request timeout
+ ui64 MaxMessageSize = DEFAULT_GRPC_MESSAGE_SIZE_LIMIT; // Max request and response size
+ ui64 MaxInboundMessageSize = 0; // overrides MaxMessageSize for incoming requests
+ ui64 MaxOutboundMessageSize = 0; // overrides MaxMessageSize for outgoing requests
+ ui32 MaxInFlight = 0;
+ bool EnableSsl = false;
+ TString SslCaCert; //Implicitly enables Ssl if not empty
+ grpc_compression_algorithm CompressionAlgoritm = GRPC_COMPRESS_NONE;
+ ui64 MemQuota = 0;
+ std::unordered_map<TString, TString> StringChannelParams;
+ std::unordered_map<TString, int> IntChannelParams;
+ TString LoadBalancingPolicy = { };
+ TString SslTargetNameOverride = { };
+
+ TGRpcClientConfig() = default;
+ TGRpcClientConfig(const TGRpcClientConfig&) = default;
+ TGRpcClientConfig(TGRpcClientConfig&&) = default;
+ TGRpcClientConfig& operator=(const TGRpcClientConfig&) = default;
+ TGRpcClientConfig& operator=(TGRpcClientConfig&&) = default;
+
+ TGRpcClientConfig(const TString& locator, TDuration timeout = TDuration::Max(),
+ ui64 maxMessageSize = DEFAULT_GRPC_MESSAGE_SIZE_LIMIT, ui32 maxInFlight = 0, TString caCert = "",
+ grpc_compression_algorithm compressionAlgorithm = GRPC_COMPRESS_NONE, bool enableSsl = false)
+ : Locator(locator)
+ , Timeout(timeout)
+ , MaxMessageSize(maxMessageSize)
+ , MaxInFlight(maxInFlight)
+ , EnableSsl(enableSsl)
+ , SslCaCert(caCert)
+ , CompressionAlgoritm(compressionAlgorithm)
+ {}
+};
+
+inline std::shared_ptr<grpc::ChannelInterface> CreateChannelInterface(const TGRpcClientConfig& config, grpc_socket_mutator* mutator = nullptr){
+ grpc::ChannelArguments args;
+ args.SetMaxReceiveMessageSize(config.MaxInboundMessageSize ? config.MaxInboundMessageSize : config.MaxMessageSize);
+ args.SetMaxSendMessageSize(config.MaxOutboundMessageSize ? config.MaxOutboundMessageSize : config.MaxMessageSize);
+ args.SetCompressionAlgorithm(config.CompressionAlgoritm);
+
+ for (const auto& kvp: config.StringChannelParams) {
+ args.SetString(kvp.first, kvp.second);
+ }
+
+ for (const auto& kvp: config.IntChannelParams) {
+ args.SetInt(kvp.first, kvp.second);
+ }
+
+ if (config.MemQuota) {
+ grpc::ResourceQuota quota;
+ quota.Resize(config.MemQuota);
+ args.SetResourceQuota(quota);
+ }
+ if (mutator) {
+ args.SetSocketMutator(mutator);
+ }
+ if (!config.LoadBalancingPolicy.empty()) {
+ args.SetLoadBalancingPolicyName(config.LoadBalancingPolicy);
+ }
+ if (!config.SslTargetNameOverride.empty()) {
+ args.SetSslTargetNameOverride(config.SslTargetNameOverride);
+ }
+ if (config.EnableSsl || config.SslCaCert) {
+ return grpc::CreateCustomChannel(config.Locator, grpc::SslCredentials(grpc::SslCredentialsOptions{config.SslCaCert, "", ""}), args);
+ } else {
+ return grpc::CreateCustomChannel(config.Locator, grpc::InsecureChannelCredentials(), args);
+ }
+}
+
+} // namespace NGRpc
diff --git a/library/cpp/grpc/client/ut/grpc_client_low_ut.cpp b/library/cpp/grpc/client/ut/grpc_client_low_ut.cpp
new file mode 100644
index 0000000000..b8af2a518f
--- /dev/null
+++ b/library/cpp/grpc/client/ut/grpc_client_low_ut.cpp
@@ -0,0 +1,61 @@
+#include <library/cpp/grpc/client/grpc_client_low.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NGrpc;
+
+class TTestStub {
+public:
+ std::shared_ptr<grpc::ChannelInterface> ChannelInterface;
+ TTestStub(std::shared_ptr<grpc::ChannelInterface> channelInterface)
+ : ChannelInterface(channelInterface)
+ {}
+};
+
+Y_UNIT_TEST_SUITE(ChannelPoolTests) {
+ Y_UNIT_TEST(UnusedStubsHoldersDeletion) {
+ TGRpcClientConfig clientConfig("invalid_host:invalid_port");
+ TTcpKeepAliveSettings tcpKeepAliveSettings =
+ {
+ true,
+ 30, // NYdb::TCP_KEEPALIVE_IDLE, unused in UT, but is necessary in constructor
+ 5, // NYdb::TCP_KEEPALIVE_COUNT, unused in UT, but is necessary in constructor
+ 10 // NYdb::TCP_KEEPALIVE_INTERVAL, unused in UT, but is necessary in constructor
+ };
+ auto channelPool = TChannelPool(tcpKeepAliveSettings, TDuration::MilliSeconds(250));
+ std::vector<std::weak_ptr<grpc::ChannelInterface>> ChannelInterfacesWeak;
+
+ {
+ std::vector<std::shared_ptr<TTestStub>> stubsHoldersShared;
+ auto storeStubsHolders = [&](TStubsHolder& stubsHolder) {
+ stubsHoldersShared.emplace_back(stubsHolder.GetOrCreateStub<TTestStub>());
+ ChannelInterfacesWeak.emplace_back((*stubsHoldersShared.rbegin())->ChannelInterface);
+ return;
+ };
+ for (int i = 0; i < 10; ++i) {
+ channelPool.GetStubsHolderLocked(
+ ToString(i),
+ clientConfig,
+ storeStubsHolders
+ );
+ }
+ }
+
+ auto now = Now();
+ while (Now() < now + TDuration::MilliSeconds(500)){
+ Sleep(TDuration::MilliSeconds(100));
+ }
+
+ channelPool.DeleteExpiredStubsHolders();
+
+ bool allDeleted = true;
+ for (auto i = ChannelInterfacesWeak.begin(); i != ChannelInterfacesWeak.end(); ++i) {
+ allDeleted = allDeleted && i->expired();
+ }
+
+ // assertion is made for channel interfaces instead of stubs, because after stub deletion
+ // TStubsHolder has the only shared_ptr for channel interface.
+ UNIT_ASSERT_C(allDeleted, "expired stubsHolders were not deleted after timeout");
+
+ }
+} // ChannelPoolTests ut suite \ No newline at end of file
diff --git a/library/cpp/grpc/client/ut/ya.make b/library/cpp/grpc/client/ut/ya.make
new file mode 100644
index 0000000000..eac779a99e
--- /dev/null
+++ b/library/cpp/grpc/client/ut/ya.make
@@ -0,0 +1,11 @@
+UNITTEST_FOR(library/cpp/grpc/client)
+
+OWNER(
+ g:kikimr
+)
+
+SRCS(
+ grpc_client_low_ut.cpp
+)
+
+END()
diff --git a/library/cpp/grpc/client/ya.make b/library/cpp/grpc/client/ya.make
new file mode 100644
index 0000000000..a4e74b067c
--- /dev/null
+++ b/library/cpp/grpc/client/ya.make
@@ -0,0 +1,20 @@
+LIBRARY()
+
+OWNER(
+ ddoarn
+ g:kikimr
+)
+
+SRCS(
+ grpc_client_low.cpp
+)
+
+PEERDIR(
+ contrib/libs/grpc
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ ut
+) \ No newline at end of file
diff --git a/library/cpp/grpc/server/actors/logger.cpp b/library/cpp/grpc/server/actors/logger.cpp
new file mode 100644
index 0000000000..d8b2042576
--- /dev/null
+++ b/library/cpp/grpc/server/actors/logger.cpp
@@ -0,0 +1,45 @@
+#include "logger.h"
+
+namespace NGrpc {
+namespace {
+
+static_assert(
+ ui16(TLOG_EMERG) == ui16(NActors::NLog::PRI_EMERG) &&
+ ui16(TLOG_DEBUG) == ui16(NActors::NLog::PRI_DEBUG),
+ "log levels in the library/log and library/cpp/actors don't match");
+
+class TActorSystemLogger final: public TLogger {
+public:
+ TActorSystemLogger(NActors::TActorSystem& as, NActors::NLog::EComponent component) noexcept
+ : ActorSystem_{as}
+ , Component_{component}
+ {
+ }
+
+protected:
+ bool DoIsEnabled(ELogPriority p) const noexcept override {
+ const auto* settings = static_cast<::NActors::NLog::TSettings*>(ActorSystem_.LoggerSettings());
+ const auto priority = static_cast<::NActors::NLog::EPriority>(p);
+
+ return settings && settings->Satisfies(priority, Component_, 0);
+ }
+
+ void DoWrite(ELogPriority p, const char* format, va_list args) noexcept override {
+ Y_VERIFY_DEBUG(DoIsEnabled(p));
+
+ const auto priority = static_cast<::NActors::NLog::EPriority>(p);
+ ::NActors::MemLogAdapter(ActorSystem_, priority, Component_, format, args);
+ }
+
+private:
+ NActors::TActorSystem& ActorSystem_;
+ NActors::NLog::EComponent Component_;
+};
+
+} // namespace
+
+TLoggerPtr CreateActorSystemLogger(NActors::TActorSystem& as, NActors::NLog::EComponent component) {
+ return MakeIntrusive<TActorSystemLogger>(as, component);
+}
+
+} // namespace NGrpc
diff --git a/library/cpp/grpc/server/actors/logger.h b/library/cpp/grpc/server/actors/logger.h
new file mode 100644
index 0000000000..abf9270f7b
--- /dev/null
+++ b/library/cpp/grpc/server/actors/logger.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <library/cpp/actors/core/actorsystem.h>
+#include <library/cpp/actors/core/log.h>
+#include <library/cpp/grpc/server/logger.h>
+
+namespace NGrpc {
+
+TLoggerPtr CreateActorSystemLogger(NActors::TActorSystem& as, NActors::NLog::EComponent component);
+
+} // namespace NGrpc
diff --git a/library/cpp/grpc/server/actors/ya.make b/library/cpp/grpc/server/actors/ya.make
new file mode 100644
index 0000000000..6c9d80aa45
--- /dev/null
+++ b/library/cpp/grpc/server/actors/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(g:kikimr g:solomon)
+
+SRCS(
+ logger.cpp
+)
+
+PEERDIR(
+ library/cpp/actors/core
+)
+
+END()
diff --git a/library/cpp/grpc/server/event_callback.cpp b/library/cpp/grpc/server/event_callback.cpp
new file mode 100644
index 0000000000..f423836bd6
--- /dev/null
+++ b/library/cpp/grpc/server/event_callback.cpp
@@ -0,0 +1 @@
+#include "event_callback.h"
diff --git a/library/cpp/grpc/server/event_callback.h b/library/cpp/grpc/server/event_callback.h
new file mode 100644
index 0000000000..d0b700b3c9
--- /dev/null
+++ b/library/cpp/grpc/server/event_callback.h
@@ -0,0 +1,80 @@
+#pragma once
+
+#include "grpc_server.h"
+
+namespace NGrpc {
+
+enum class EQueueEventStatus {
+ OK,
+ ERROR
+};
+
+template<class TCallback>
+class TQueueEventCallback: public IQueueEvent {
+public:
+ TQueueEventCallback(const TCallback& callback)
+ : Callback(callback)
+ {}
+
+ TQueueEventCallback(TCallback&& callback)
+ : Callback(std::move(callback))
+ {}
+
+ bool Execute(bool ok) override {
+ Callback(ok ? EQueueEventStatus::OK : EQueueEventStatus::ERROR);
+ return false;
+ }
+
+ void DestroyRequest() override {
+ delete this;
+ }
+
+private:
+ TCallback Callback;
+};
+
+// Implementation of IQueueEvent that reduces allocations
+template<class TSelf>
+class TQueueFixedEvent: private IQueueEvent {
+ using TCallback = void (TSelf::*)(EQueueEventStatus);
+
+public:
+ TQueueFixedEvent(TSelf* self, TCallback callback)
+ : Self(self)
+ , Callback(callback)
+ { }
+
+ IQueueEvent* Prepare() {
+ Self->Ref();
+ return this;
+ }
+
+private:
+ bool Execute(bool ok) override {
+ ((*Self).*Callback)(ok ? EQueueEventStatus::OK : EQueueEventStatus::ERROR);
+ return false;
+ }
+
+ void DestroyRequest() override {
+ Self->UnRef();
+ }
+
+private:
+ TSelf* const Self;
+ TCallback const Callback;
+};
+
+template<class TCallback>
+inline IQueueEvent* MakeQueueEventCallback(TCallback&& callback) {
+ return new TQueueEventCallback<TCallback>(std::forward<TCallback>(callback));
+}
+
+template<class T>
+inline IQueueEvent* MakeQueueEventCallback(T* self, void (T::*method)(EQueueEventStatus)) {
+ using TPtr = TIntrusivePtr<T>;
+ return MakeQueueEventCallback([self = TPtr(self), method] (EQueueEventStatus status) {
+ ((*self).*method)(status);
+ });
+}
+
+} // namespace NGrpc
diff --git a/library/cpp/grpc/server/grpc_async_ctx_base.h b/library/cpp/grpc/server/grpc_async_ctx_base.h
new file mode 100644
index 0000000000..51356d4ce5
--- /dev/null
+++ b/library/cpp/grpc/server/grpc_async_ctx_base.h
@@ -0,0 +1,94 @@
+#pragma once
+
+#include "grpc_server.h"
+
+#include <util/generic/vector.h>
+#include <util/generic/string.h>
+#include <util/system/yassert.h>
+#include <util/generic/set.h>
+
+#include <grpc++/server.h>
+#include <grpc++/server_context.h>
+
+#include <chrono>
+
+namespace NGrpc {
+
+template<typename TService>
+class TBaseAsyncContext: public ICancelableContext {
+public:
+ TBaseAsyncContext(typename TService::TCurrentGRpcService::AsyncService* service, grpc::ServerCompletionQueue* cq)
+ : Service(service)
+ , CQ(cq)
+ {
+ }
+
+ TString GetPeerName() const {
+ return TString(Context.peer());
+ }
+
+ TInstant Deadline() const {
+ // The timeout transferred in "grpc-timeout" header [1] and calculated from the deadline
+ // right before the request is getting to be send.
+ // 1. https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md
+ //
+ // After this timeout calculated back to the deadline on the server side
+ // using server grpc GPR_CLOCK_MONOTONIC time (raw_deadline() method).
+ // deadline() method convert this to epoch related deadline GPR_CLOCK_REALTIME
+ //
+
+ std::chrono::system_clock::time_point t = Context.deadline();
+ if (t == std::chrono::system_clock::time_point::max()) {
+ return TInstant::Max();
+ }
+ auto us = std::chrono::time_point_cast<std::chrono::microseconds>(t);
+ return TInstant::MicroSeconds(us.time_since_epoch().count());
+ }
+
+ TSet<TStringBuf> GetPeerMetaKeys() const {
+ TSet<TStringBuf> keys;
+ for (const auto& [key, _]: Context.client_metadata()) {
+ keys.emplace(key.data(), key.size());
+ }
+ return keys;
+ }
+
+ TVector<TStringBuf> GetPeerMetaValues(TStringBuf key) const {
+ const auto& clientMetadata = Context.client_metadata();
+ const auto range = clientMetadata.equal_range(grpc::string_ref{key.data(), key.size()});
+ if (range.first == range.second) {
+ return {};
+ }
+
+ TVector<TStringBuf> values;
+ values.reserve(std::distance(range.first, range.second));
+
+ for (auto it = range.first; it != range.second; ++it) {
+ values.emplace_back(it->second.data(), it->second.size());
+ }
+ return values;
+ }
+
+ grpc_compression_level GetCompressionLevel() const {
+ return Context.compression_level();
+ }
+
+ void Shutdown() override {
+ // Shutdown may only be called after request has started successfully
+ if (Context.c_call())
+ Context.TryCancel();
+ }
+
+protected:
+ //! The means of communication with the gRPC runtime for an asynchronous
+ //! server.
+ typename TService::TCurrentGRpcService::AsyncService* const Service;
+ //! The producer-consumer queue where for asynchronous server notifications.
+ grpc::ServerCompletionQueue* const CQ;
+ //! Context for the rpc, allowing to tweak aspects of it such as the use
+ //! of compression, authentication, as well as to send metadata back to the
+ //! client.
+ grpc::ServerContext Context;
+};
+
+} // namespace NGrpc
diff --git a/library/cpp/grpc/server/grpc_counters.cpp b/library/cpp/grpc/server/grpc_counters.cpp
new file mode 100644
index 0000000000..fa96e0100b
--- /dev/null
+++ b/library/cpp/grpc/server/grpc_counters.cpp
@@ -0,0 +1,45 @@
+#include "grpc_counters.h"
+
+namespace NGrpc {
+namespace {
+
+class TFakeCounterBlock final: public ICounterBlock {
+private:
+ void CountNotOkRequest() override {
+ }
+
+ void CountNotOkResponse() override {
+ }
+
+ void CountNotAuthenticated() override {
+ }
+
+ void CountResourceExhausted() override {
+ }
+
+ void CountRequestBytes(ui32 /*requestSize*/) override {
+ }
+
+ void CountResponseBytes(ui32 /*responseSize*/) override {
+ }
+
+ void StartProcessing(ui32 /*requestSize*/) override {
+ }
+
+ void FinishProcessing(
+ ui32 /*requestSize*/,
+ ui32 /*responseSize*/,
+ bool /*ok*/,
+ ui32 /*status*/,
+ TDuration /*requestDuration*/) override
+ {
+ }
+};
+
+} // namespace
+
+ICounterBlockPtr FakeCounterBlock() {
+ return MakeIntrusive<TFakeCounterBlock>();
+}
+
+} // namespace NGrpc
diff --git a/library/cpp/grpc/server/grpc_counters.h b/library/cpp/grpc/server/grpc_counters.h
new file mode 100644
index 0000000000..0b6c36c84c
--- /dev/null
+++ b/library/cpp/grpc/server/grpc_counters.h
@@ -0,0 +1,136 @@
+#pragma once
+
+#include <library/cpp/monlib/dynamic_counters/percentile/percentile.h>
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+#include <util/generic/ptr.h>
+
+namespace NGrpc {
+
+struct ICounterBlock : public TThrRefBase {
+ virtual void CountNotOkRequest() = 0;
+ virtual void CountNotOkResponse() = 0;
+ virtual void CountNotAuthenticated() = 0;
+ virtual void CountResourceExhausted() = 0;
+ virtual void CountRequestBytes(ui32 requestSize) = 0;
+ virtual void CountResponseBytes(ui32 responseSize) = 0;
+ virtual void StartProcessing(ui32 requestSize) = 0;
+ virtual void FinishProcessing(ui32 requestSize, ui32 responseSize, bool ok, ui32 status, TDuration requestDuration) = 0;
+ virtual void CountRequestsWithoutDatabase() {}
+ virtual void CountRequestsWithoutToken() {}
+ virtual void CountRequestWithoutTls() {}
+
+ virtual TIntrusivePtr<ICounterBlock> Clone() { return this; }
+ virtual void UseDatabase(const TString& database) { Y_UNUSED(database); }
+};
+
+using ICounterBlockPtr = TIntrusivePtr<ICounterBlock>;
+
+class TCounterBlock final : public ICounterBlock {
+ NMonitoring::TDynamicCounters::TCounterPtr TotalCounter;
+ NMonitoring::TDynamicCounters::TCounterPtr InflyCounter;
+ NMonitoring::TDynamicCounters::TCounterPtr NotOkRequestCounter;
+ NMonitoring::TDynamicCounters::TCounterPtr NotOkResponseCounter;
+ NMonitoring::TDynamicCounters::TCounterPtr RequestBytes;
+ NMonitoring::TDynamicCounters::TCounterPtr InflyRequestBytes;
+ NMonitoring::TDynamicCounters::TCounterPtr ResponseBytes;
+ NMonitoring::TDynamicCounters::TCounterPtr NotAuthenticated;
+ NMonitoring::TDynamicCounters::TCounterPtr ResourceExhausted;
+ bool Percentile = false;
+ NMonitoring::TPercentileTracker<4, 512, 15> RequestHistMs;
+ std::array<NMonitoring::TDynamicCounters::TCounterPtr, 2> GRpcStatusCounters;
+
+public:
+ TCounterBlock(NMonitoring::TDynamicCounters::TCounterPtr totalCounter,
+ NMonitoring::TDynamicCounters::TCounterPtr inflyCounter,
+ NMonitoring::TDynamicCounters::TCounterPtr notOkRequestCounter,
+ NMonitoring::TDynamicCounters::TCounterPtr notOkResponseCounter,
+ NMonitoring::TDynamicCounters::TCounterPtr requestBytes,
+ NMonitoring::TDynamicCounters::TCounterPtr inflyRequestBytes,
+ NMonitoring::TDynamicCounters::TCounterPtr responseBytes,
+ NMonitoring::TDynamicCounters::TCounterPtr notAuthenticated,
+ NMonitoring::TDynamicCounters::TCounterPtr resourceExhausted,
+ TIntrusivePtr<NMonitoring::TDynamicCounters> group)
+ : TotalCounter(std::move(totalCounter))
+ , InflyCounter(std::move(inflyCounter))
+ , NotOkRequestCounter(std::move(notOkRequestCounter))
+ , NotOkResponseCounter(std::move(notOkResponseCounter))
+ , RequestBytes(std::move(requestBytes))
+ , InflyRequestBytes(std::move(inflyRequestBytes))
+ , ResponseBytes(std::move(responseBytes))
+ , NotAuthenticated(std::move(notAuthenticated))
+ , ResourceExhausted(std::move(resourceExhausted))
+ {
+ if (group) {
+ RequestHistMs.Initialize(group, "event", "request", "ms", {0.5f, 0.9f, 0.99f, 0.999f, 1.0f});
+ Percentile = true;
+ }
+ }
+
+ void CountNotOkRequest() override {
+ NotOkRequestCounter->Inc();
+ }
+
+ void CountNotOkResponse() override {
+ NotOkResponseCounter->Inc();
+ }
+
+ void CountNotAuthenticated() override {
+ NotAuthenticated->Inc();
+ }
+
+ void CountResourceExhausted() override {
+ ResourceExhausted->Inc();
+ }
+
+ void CountRequestBytes(ui32 requestSize) override {
+ *RequestBytes += requestSize;
+ }
+
+ void CountResponseBytes(ui32 responseSize) override {
+ *ResponseBytes += responseSize;
+ }
+
+ void StartProcessing(ui32 requestSize) override {
+ TotalCounter->Inc();
+ InflyCounter->Inc();
+ *RequestBytes += requestSize;
+ *InflyRequestBytes += requestSize;
+ }
+
+ void FinishProcessing(ui32 requestSize, ui32 responseSize, bool ok, ui32 status,
+ TDuration requestDuration) override
+ {
+ Y_UNUSED(status);
+
+ InflyCounter->Dec();
+ *InflyRequestBytes -= requestSize;
+ *ResponseBytes += responseSize;
+ if (!ok) {
+ NotOkResponseCounter->Inc();
+ }
+ if (Percentile) {
+ RequestHistMs.Increment(requestDuration.MilliSeconds());
+ }
+ }
+
+ ICounterBlockPtr Clone() override {
+ return this;
+ }
+
+ void Update() {
+ if (Percentile) {
+ RequestHistMs.Update();
+ }
+ }
+};
+
+using TCounterBlockPtr = TIntrusivePtr<TCounterBlock>;
+
+/**
+ * Creates new instance of ICounterBlock implementation which does nothing.
+ *
+ * @return new instance
+ */
+ICounterBlockPtr FakeCounterBlock();
+
+} // namespace NGrpc
diff --git a/library/cpp/grpc/server/grpc_request.cpp b/library/cpp/grpc/server/grpc_request.cpp
new file mode 100644
index 0000000000..d18a32776f
--- /dev/null
+++ b/library/cpp/grpc/server/grpc_request.cpp
@@ -0,0 +1,59 @@
+#include "grpc_request.h"
+
+namespace NGrpc {
+
+const char* GRPC_USER_AGENT_HEADER = "user-agent";
+
+class TStreamAdaptor: public IStreamAdaptor {
+public:
+ TStreamAdaptor()
+ : StreamIsReady_(true)
+ {}
+
+ void Enqueue(std::function<void()>&& fn, bool urgent) override {
+ with_lock(Mtx_) {
+ if (!UrgentQueue_.empty() || !NormalQueue_.empty()) {
+ Y_VERIFY(!StreamIsReady_);
+ }
+ auto& queue = urgent ? UrgentQueue_ : NormalQueue_;
+ if (StreamIsReady_ && queue.empty()) {
+ StreamIsReady_ = false;
+ } else {
+ queue.push_back(std::move(fn));
+ return;
+ }
+ }
+ fn();
+ }
+
+ size_t ProcessNext() override {
+ size_t left = 0;
+ std::function<void()> fn;
+ with_lock(Mtx_) {
+ Y_VERIFY(!StreamIsReady_);
+ auto& queue = UrgentQueue_.empty() ? NormalQueue_ : UrgentQueue_;
+ if (queue.empty()) {
+ // Both queues are empty
+ StreamIsReady_ = true;
+ } else {
+ fn = std::move(queue.front());
+ queue.pop_front();
+ left = UrgentQueue_.size() + NormalQueue_.size();
+ }
+ }
+ if (fn)
+ fn();
+ return left;
+ }
+private:
+ bool StreamIsReady_;
+ TList<std::function<void()>> NormalQueue_;
+ TList<std::function<void()>> UrgentQueue_;
+ TMutex Mtx_;
+};
+
+IStreamAdaptor::TPtr CreateStreamAdaptor() {
+ return std::make_unique<TStreamAdaptor>();
+}
+
+} // namespace NGrpc
diff --git a/library/cpp/grpc/server/grpc_request.h b/library/cpp/grpc/server/grpc_request.h
new file mode 100644
index 0000000000..5bd8d3902b
--- /dev/null
+++ b/library/cpp/grpc/server/grpc_request.h
@@ -0,0 +1,543 @@
+#pragma once
+
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/message.h>
+
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+#include <library/cpp/logger/priority.h>
+
+#include "grpc_response.h"
+#include "event_callback.h"
+#include "grpc_async_ctx_base.h"
+#include "grpc_counters.h"
+#include "grpc_request_base.h"
+#include "grpc_server.h"
+#include "logger.h"
+
+#include <util/system/hp_timer.h>
+
+#include <grpc++/server.h>
+#include <grpc++/server_context.h>
+#include <grpc++/support/async_stream.h>
+#include <grpc++/support/async_unary_call.h>
+#include <grpc++/support/byte_buffer.h>
+#include <grpc++/impl/codegen/async_stream.h>
+
+namespace NGrpc {
+
+class IStreamAdaptor {
+public:
+ using TPtr = std::unique_ptr<IStreamAdaptor>;
+ virtual void Enqueue(std::function<void()>&& fn, bool urgent) = 0;
+ virtual size_t ProcessNext() = 0;
+ virtual ~IStreamAdaptor() = default;
+};
+
+IStreamAdaptor::TPtr CreateStreamAdaptor();
+
+///////////////////////////////////////////////////////////////////////////////
+template<typename TIn, typename TOut, typename TService, typename TInProtoPrinter, typename TOutProtoPrinter>
+class TGRpcRequestImpl
+ : public TBaseAsyncContext<TService>
+ , public IQueueEvent
+ , public IRequestContextBase
+{
+ using TThis = TGRpcRequestImpl<TIn, TOut, TService, TInProtoPrinter, TOutProtoPrinter>;
+
+public:
+ using TOnRequest = std::function<void (IRequestContextBase* ctx)>;
+ using TRequestCallback = void (TService::TCurrentGRpcService::AsyncService::*)(grpc::ServerContext*, TIn*,
+ grpc::ServerAsyncResponseWriter<TOut>*, grpc::CompletionQueue*, grpc::ServerCompletionQueue*, void*);
+ using TStreamRequestCallback = void (TService::TCurrentGRpcService::AsyncService::*)(grpc::ServerContext*, TIn*,
+ grpc::ServerAsyncWriter<TOut>*, grpc::CompletionQueue*, grpc::ServerCompletionQueue*, void*);
+
+ TGRpcRequestImpl(TService* server,
+ typename TService::TCurrentGRpcService::AsyncService* service,
+ grpc::ServerCompletionQueue* cq,
+ TOnRequest cb,
+ TRequestCallback requestCallback,
+ const char* name,
+ TLoggerPtr logger,
+ ICounterBlockPtr counters,
+ IGRpcRequestLimiterPtr limiter)
+ : TBaseAsyncContext<TService>(service, cq)
+ , Server_(server)
+ , Cb_(cb)
+ , RequestCallback_(requestCallback)
+ , StreamRequestCallback_(nullptr)
+ , Name_(name)
+ , Logger_(std::move(logger))
+ , Counters_(std::move(counters))
+ , RequestLimiter_(std::move(limiter))
+ , Writer_(new grpc::ServerAsyncResponseWriter<TUniversalResponseRef<TOut>>(&this->Context))
+ , StateFunc_(&TThis::SetRequestDone)
+ {
+ AuthState_ = Server_->NeedAuth() ? TAuthState(true) : TAuthState(false);
+ Request_ = google::protobuf::Arena::CreateMessage<TIn>(&Arena_);
+ Y_VERIFY(Request_);
+ GRPC_LOG_DEBUG(Logger_, "[%p] created request Name# %s", this, Name_);
+ FinishPromise_ = NThreading::NewPromise<EFinishStatus>();
+ }
+
+ TGRpcRequestImpl(TService* server,
+ typename TService::TCurrentGRpcService::AsyncService* service,
+ grpc::ServerCompletionQueue* cq,
+ TOnRequest cb,
+ TStreamRequestCallback requestCallback,
+ const char* name,
+ TLoggerPtr logger,
+ ICounterBlockPtr counters,
+ IGRpcRequestLimiterPtr limiter)
+ : TBaseAsyncContext<TService>(service, cq)
+ , Server_(server)
+ , Cb_(cb)
+ , RequestCallback_(nullptr)
+ , StreamRequestCallback_(requestCallback)
+ , Name_(name)
+ , Logger_(std::move(logger))
+ , Counters_(std::move(counters))
+ , RequestLimiter_(std::move(limiter))
+ , StreamWriter_(new grpc::ServerAsyncWriter<TUniversalResponse<TOut>>(&this->Context))
+ , StateFunc_(&TThis::SetRequestDone)
+ {
+ AuthState_ = Server_->NeedAuth() ? TAuthState(true) : TAuthState(false);
+ Request_ = google::protobuf::Arena::CreateMessage<TIn>(&Arena_);
+ Y_VERIFY(Request_);
+ GRPC_LOG_DEBUG(Logger_, "[%p] created streaming request Name# %s", this, Name_);
+ FinishPromise_ = NThreading::NewPromise<EFinishStatus>();
+ StreamAdaptor_ = CreateStreamAdaptor();
+ }
+
+ TAsyncFinishResult GetFinishFuture() override {
+ return FinishPromise_.GetFuture();
+ }
+
+ TString GetPeer() const override {
+ return TString(this->Context.peer());
+ }
+
+ bool SslServer() const override {
+ return Server_->SslServer();
+ }
+
+ void Run() {
+ // Start request unless server is shutting down
+ if (auto guard = Server_->ProtectShutdown()) {
+ Ref(); //For grpc c runtime
+ this->Context.AsyncNotifyWhenDone(OnFinishTag.Prepare());
+ if (RequestCallback_) {
+ (this->Service->*RequestCallback_)
+ (&this->Context, Request_,
+ reinterpret_cast<grpc::ServerAsyncResponseWriter<TOut>*>(Writer_.Get()), this->CQ, this->CQ, GetGRpcTag());
+ } else {
+ (this->Service->*StreamRequestCallback_)
+ (&this->Context, Request_,
+ reinterpret_cast<grpc::ServerAsyncWriter<TOut>*>(StreamWriter_.Get()), this->CQ, this->CQ, GetGRpcTag());
+ }
+ }
+ }
+
+ ~TGRpcRequestImpl() {
+ // No direct dtor call allowed
+ Y_ASSERT(RefCount() == 0);
+ }
+
+ bool Execute(bool ok) override {
+ return (this->*StateFunc_)(ok);
+ }
+
+ void DestroyRequest() override {
+ if (RequestRegistered_) {
+ Server_->DeregisterRequestCtx(this);
+ RequestRegistered_ = false;
+ }
+ UnRef();
+ }
+
+ TInstant Deadline() const override {
+ return TBaseAsyncContext<TService>::Deadline();
+ }
+
+ TSet<TStringBuf> GetPeerMetaKeys() const override {
+ return TBaseAsyncContext<TService>::GetPeerMetaKeys();
+ }
+
+ TVector<TStringBuf> GetPeerMetaValues(TStringBuf key) const override {
+ return TBaseAsyncContext<TService>::GetPeerMetaValues(key);
+ }
+
+ grpc_compression_level GetCompressionLevel() const override {
+ return TBaseAsyncContext<TService>::GetCompressionLevel();
+ }
+
+ //! Get pointer to the request's message.
+ const NProtoBuf::Message* GetRequest() const override {
+ return Request_;
+ }
+
+ TAuthState& GetAuthState() override {
+ return AuthState_;
+ }
+
+ void Reply(NProtoBuf::Message* resp, ui32 status) override {
+ ResponseStatus = status;
+ WriteDataOk(resp);
+ }
+
+ void Reply(grpc::ByteBuffer* resp, ui32 status) override {
+ ResponseStatus = status;
+ WriteByteDataOk(resp);
+ }
+
+ void ReplyError(grpc::StatusCode code, const TString& msg) override {
+ FinishGrpcStatus(code, msg, false);
+ }
+
+ void ReplyUnauthenticated(const TString& in) override {
+ const TString message = in.empty() ? TString("unauthenticated") : TString("unauthenticated, ") + in;
+ FinishGrpcStatus(grpc::StatusCode::UNAUTHENTICATED, message, false);
+ }
+
+ void SetNextReplyCallback(TOnNextReply&& cb) override {
+ NextReplyCb_ = cb;
+ }
+
+ void AddTrailingMetadata(const TString& key, const TString& value) override {
+ this->Context.AddTrailingMetadata(key, value);
+ }
+
+ void FinishStreamingOk() override {
+ GRPC_LOG_DEBUG(Logger_, "[%p] finished streaming Name# %s peer# %s (enqueued)", this, Name_,
+ this->Context.peer().c_str());
+ auto cb = [this]() {
+ StateFunc_ = &TThis::SetFinishDone;
+ GRPC_LOG_DEBUG(Logger_, "[%p] finished streaming Name# %s peer# %s (pushed to grpc)", this, Name_,
+ this->Context.peer().c_str());
+
+ StreamWriter_->Finish(grpc::Status::OK, GetGRpcTag());
+ };
+ StreamAdaptor_->Enqueue(std::move(cb), false);
+ }
+
+ google::protobuf::Arena* GetArena() override {
+ return &Arena_;
+ }
+
+ void UseDatabase(const TString& database) override {
+ Counters_->UseDatabase(database);
+ }
+
+private:
+ void Clone() {
+ if (!Server_->IsShuttingDown()) {
+ if (RequestCallback_) {
+ MakeIntrusive<TThis>(
+ Server_, this->Service, this->CQ, Cb_, RequestCallback_, Name_, Logger_, Counters_->Clone(), RequestLimiter_)->Run();
+ } else {
+ MakeIntrusive<TThis>(
+ Server_, this->Service, this->CQ, Cb_, StreamRequestCallback_, Name_, Logger_, Counters_->Clone(), RequestLimiter_)->Run();
+ }
+ }
+ }
+
+ void WriteDataOk(NProtoBuf::Message* resp) {
+ auto makeResponseString = [&] {
+ TString x;
+ TOutProtoPrinter printer;
+ printer.SetSingleLineMode(true);
+ printer.PrintToString(*resp, &x);
+ return x;
+ };
+
+ auto sz = (size_t)resp->ByteSize();
+ if (Writer_) {
+ GRPC_LOG_DEBUG(Logger_, "[%p] issuing response Name# %s data# %s peer# %s", this, Name_,
+ makeResponseString().data(), this->Context.peer().c_str());
+ StateFunc_ = &TThis::SetFinishDone;
+ ResponseSize = sz;
+ Y_VERIFY(this->Context.c_call());
+ Writer_->Finish(TUniversalResponseRef<TOut>(resp), grpc::Status::OK, GetGRpcTag());
+ } else {
+ GRPC_LOG_DEBUG(Logger_, "[%p] issuing response Name# %s data# %s peer# %s (enqueued)",
+ this, Name_, makeResponseString().data(), this->Context.peer().c_str());
+
+ // because of std::function cannot hold move-only captured object
+ // we allocate shared object on heap to avoid message copy
+ auto uResp = MakeIntrusive<TUniversalResponse<TOut>>(resp);
+ auto cb = [this, uResp = std::move(uResp), sz, &makeResponseString]() {
+ GRPC_LOG_DEBUG(Logger_, "[%p] issuing response Name# %s data# %s peer# %s (pushed to grpc)",
+ this, Name_, makeResponseString().data(), this->Context.peer().c_str());
+ StateFunc_ = &TThis::NextReply;
+ ResponseSize += sz;
+ StreamWriter_->Write(*uResp, GetGRpcTag());
+ };
+ StreamAdaptor_->Enqueue(std::move(cb), false);
+ }
+ }
+
+ void WriteByteDataOk(grpc::ByteBuffer* resp) {
+ auto sz = resp->Length();
+ if (Writer_) {
+ GRPC_LOG_DEBUG(Logger_, "[%p] issuing response Name# %s data# byteString peer# %s", this, Name_,
+ this->Context.peer().c_str());
+ StateFunc_ = &TThis::SetFinishDone;
+ ResponseSize = sz;
+ Writer_->Finish(TUniversalResponseRef<TOut>(resp), grpc::Status::OK, GetGRpcTag());
+ } else {
+ GRPC_LOG_DEBUG(Logger_, "[%p] issuing response Name# %s data# byteString peer# %s (enqueued)", this, Name_,
+ this->Context.peer().c_str());
+
+ // because of std::function cannot hold move-only captured object
+ // we allocate shared object on heap to avoid buffer copy
+ auto uResp = MakeIntrusive<TUniversalResponse<TOut>>(resp);
+ auto cb = [this, uResp = std::move(uResp), sz]() {
+ GRPC_LOG_DEBUG(Logger_, "[%p] issuing response Name# %s data# byteString peer# %s (pushed to grpc)",
+ this, Name_, this->Context.peer().c_str());
+ StateFunc_ = &TThis::NextReply;
+ ResponseSize += sz;
+ StreamWriter_->Write(*uResp, GetGRpcTag());
+ };
+ StreamAdaptor_->Enqueue(std::move(cb), false);
+ }
+ }
+
+ void FinishGrpcStatus(grpc::StatusCode code, const TString& msg, bool urgent) {
+ Y_VERIFY(code != grpc::OK);
+ if (code == grpc::StatusCode::UNAUTHENTICATED) {
+ Counters_->CountNotAuthenticated();
+ } else if (code == grpc::StatusCode::RESOURCE_EXHAUSTED) {
+ Counters_->CountResourceExhausted();
+ }
+
+ if (Writer_) {
+ GRPC_LOG_DEBUG(Logger_, "[%p] issuing response Name# %s nodata (%s) peer# %s, grpc status# (%d)", this,
+ Name_, msg.c_str(), this->Context.peer().c_str(), (int)code);
+ StateFunc_ = &TThis::SetFinishError;
+ TOut resp;
+ Writer_->Finish(TUniversalResponseRef<TOut>(&resp), grpc::Status(code, msg), GetGRpcTag());
+ } else {
+ GRPC_LOG_DEBUG(Logger_, "[%p] issuing response Name# %s nodata (%s) peer# %s, grpc status# (%d)"
+ " (enqueued)", this, Name_, msg.c_str(), this->Context.peer().c_str(), (int)code);
+ auto cb = [this, code, msg]() {
+ GRPC_LOG_DEBUG(Logger_, "[%p] issuing response Name# %s nodata (%s) peer# %s, grpc status# (%d)"
+ " (pushed to grpc)", this, Name_, msg.c_str(),
+ this->Context.peer().c_str(), (int)code);
+ StateFunc_ = &TThis::SetFinishError;
+ StreamWriter_->Finish(grpc::Status(code, msg), GetGRpcTag());
+ };
+ StreamAdaptor_->Enqueue(std::move(cb), urgent);
+ }
+ }
+
+ bool SetRequestDone(bool ok) {
+ auto makeRequestString = [&] {
+ TString resp;
+ if (ok) {
+ TInProtoPrinter printer;
+ printer.SetSingleLineMode(true);
+ printer.PrintToString(*Request_, &resp);
+ } else {
+ resp = "<not ok>";
+ }
+ return resp;
+ };
+ GRPC_LOG_DEBUG(Logger_, "[%p] received request Name# %s ok# %s data# %s peer# %s", this, Name_,
+ ok ? "true" : "false", makeRequestString().data(), this->Context.peer().c_str());
+
+ if (this->Context.c_call() == nullptr) {
+ Y_VERIFY(!ok);
+ // One ref by OnFinishTag, grpc will not call this tag if no request received
+ UnRef();
+ } else if (!(RequestRegistered_ = Server_->RegisterRequestCtx(this))) {
+ // Request cannot be registered due to shutdown
+ // It's unsafe to continue, so drop this request without processing
+ GRPC_LOG_DEBUG(Logger_, "[%p] dropping request Name# %s due to shutdown", this, Name_);
+ this->Context.TryCancel();
+ return false;
+ }
+
+ Clone(); // TODO: Request pool?
+ if (!ok) {
+ Counters_->CountNotOkRequest();
+ return false;
+ }
+
+ if (IncRequest()) {
+ // Adjust counters.
+ RequestSize = Request_->ByteSize();
+ Counters_->StartProcessing(RequestSize);
+ RequestTimer.Reset();
+
+ if (!SslServer()) {
+ Counters_->CountRequestWithoutTls();
+ }
+
+ //TODO: Move this in to grpc_request_proxy
+ auto maybeDatabase = GetPeerMetaValues(TStringBuf("x-ydb-database"));
+ if (maybeDatabase.empty()) {
+ Counters_->CountRequestsWithoutDatabase();
+ }
+ auto maybeToken = GetPeerMetaValues(TStringBuf("x-ydb-auth-ticket"));
+ if (maybeToken.empty() || maybeToken[0].empty()) {
+ TString db{maybeDatabase ? maybeDatabase[0] : TStringBuf{}};
+ Counters_->CountRequestsWithoutToken();
+ GRPC_LOG_DEBUG(Logger_, "[%p] received request without user token "
+ "Name# %s data# %s peer# %s database# %s", this, Name_,
+ makeRequestString().data(), this->Context.peer().c_str(), db.c_str());
+ }
+
+ // Handle current request.
+ Cb_(this);
+ } else {
+ //This request has not been counted
+ SkipUpdateCountersOnError = true;
+ FinishGrpcStatus(grpc::StatusCode::RESOURCE_EXHAUSTED, "no resource", true);
+ }
+ return true;
+ }
+
+ bool NextReply(bool ok) {
+ auto logCb = [this, ok](int left) {
+ GRPC_LOG_DEBUG(Logger_, "[%p] ready for next reply Name# %s ok# %s peer# %s left# %d", this, Name_,
+ ok ? "true" : "false", this->Context.peer().c_str(), left);
+ };
+
+ if (!ok) {
+ logCb(-1);
+ DecRequest();
+ Counters_->FinishProcessing(RequestSize, ResponseSize, ok, ResponseStatus,
+ TDuration::Seconds(RequestTimer.Passed()));
+ return false;
+ }
+
+ Ref(); // To prevent destroy during this call in case of execution Finish
+ size_t left = StreamAdaptor_->ProcessNext();
+ logCb(left);
+ if (NextReplyCb_) {
+ NextReplyCb_(left);
+ }
+ // Now it is safe to destroy even if Finish was called
+ UnRef();
+ return true;
+ }
+
+ bool SetFinishDone(bool ok) {
+ GRPC_LOG_DEBUG(Logger_, "[%p] finished request Name# %s ok# %s peer# %s", this, Name_,
+ ok ? "true" : "false", this->Context.peer().c_str());
+ //PrintBackTrace();
+ DecRequest();
+ Counters_->FinishProcessing(RequestSize, ResponseSize, ok, ResponseStatus,
+ TDuration::Seconds(RequestTimer.Passed()));
+ return false;
+ }
+
+ bool SetFinishError(bool ok) {
+ GRPC_LOG_DEBUG(Logger_, "[%p] finished request with error Name# %s ok# %s peer# %s", this, Name_,
+ ok ? "true" : "false", this->Context.peer().c_str());
+ if (!SkipUpdateCountersOnError) {
+ DecRequest();
+ Counters_->FinishProcessing(RequestSize, ResponseSize, ok, ResponseStatus,
+ TDuration::Seconds(RequestTimer.Passed()));
+ }
+ return false;
+ }
+
+ // Returns pointer to IQueueEvent to pass into grpc c runtime
+ // Implicit C style cast from this to void* is wrong due to multiple inheritance
+ void* GetGRpcTag() {
+ return static_cast<IQueueEvent*>(this);
+ }
+
+ void OnFinish(EQueueEventStatus evStatus) {
+ if (this->Context.IsCancelled()) {
+ FinishPromise_.SetValue(EFinishStatus::CANCEL);
+ } else {
+ FinishPromise_.SetValue(evStatus == EQueueEventStatus::OK ? EFinishStatus::OK : EFinishStatus::ERROR);
+ }
+ }
+
+ bool IncRequest() {
+ if (!Server_->IncRequest())
+ return false;
+
+ if (!RequestLimiter_)
+ return true;
+
+ if (!RequestLimiter_->IncRequest()) {
+ Server_->DecRequest();
+ return false;
+ }
+
+ return true;
+ }
+
+ void DecRequest() {
+ if (RequestLimiter_) {
+ RequestLimiter_->DecRequest();
+ }
+ Server_->DecRequest();
+ }
+
+ using TStateFunc = bool (TThis::*)(bool);
+ TService* Server_;
+ TOnRequest Cb_;
+ TRequestCallback RequestCallback_;
+ TStreamRequestCallback StreamRequestCallback_;
+ const char* const Name_;
+ TLoggerPtr Logger_;
+ ICounterBlockPtr Counters_;
+ IGRpcRequestLimiterPtr RequestLimiter_;
+
+ THolder<grpc::ServerAsyncResponseWriter<TUniversalResponseRef<TOut>>> Writer_;
+ THolder<grpc::ServerAsyncWriterInterface<TUniversalResponse<TOut>>> StreamWriter_;
+ TStateFunc StateFunc_;
+ TIn* Request_;
+
+ google::protobuf::Arena Arena_;
+ TOnNextReply NextReplyCb_;
+ ui32 RequestSize = 0;
+ ui32 ResponseSize = 0;
+ ui32 ResponseStatus = 0;
+ THPTimer RequestTimer;
+ TAuthState AuthState_ = 0;
+ bool RequestRegistered_ = false;
+
+ using TFixedEvent = TQueueFixedEvent<TGRpcRequestImpl>;
+ TFixedEvent OnFinishTag = { this, &TGRpcRequestImpl::OnFinish };
+ NThreading::TPromise<EFinishStatus> FinishPromise_;
+ bool SkipUpdateCountersOnError = false;
+ IStreamAdaptor::TPtr StreamAdaptor_;
+};
+
+template<typename TIn, typename TOut, typename TService, typename TInProtoPrinter=google::protobuf::TextFormat::Printer, typename TOutProtoPrinter=google::protobuf::TextFormat::Printer>
+class TGRpcRequest: public TGRpcRequestImpl<TIn, TOut, TService, TInProtoPrinter, TOutProtoPrinter> {
+ using TBase = TGRpcRequestImpl<TIn, TOut, TService, TInProtoPrinter, TOutProtoPrinter>;
+public:
+ TGRpcRequest(TService* server,
+ typename TService::TCurrentGRpcService::AsyncService* service,
+ grpc::ServerCompletionQueue* cq,
+ typename TBase::TOnRequest cb,
+ typename TBase::TRequestCallback requestCallback,
+ const char* name,
+ TLoggerPtr logger,
+ ICounterBlockPtr counters,
+ IGRpcRequestLimiterPtr limiter = nullptr)
+ : TBase{server, service, cq, std::move(cb), std::move(requestCallback), name, std::move(logger), std::move(counters), std::move(limiter)}
+ {
+ }
+
+ TGRpcRequest(TService* server,
+ typename TService::TCurrentGRpcService::AsyncService* service,
+ grpc::ServerCompletionQueue* cq,
+ typename TBase::TOnRequest cb,
+ typename TBase::TStreamRequestCallback requestCallback,
+ const char* name,
+ TLoggerPtr logger,
+ ICounterBlockPtr counters)
+ : TBase{server, service, cq, std::move(cb), std::move(requestCallback), name, std::move(logger), std::move(counters), nullptr}
+ {
+ }
+};
+
+} // namespace NGrpc
diff --git a/library/cpp/grpc/server/grpc_request_base.h b/library/cpp/grpc/server/grpc_request_base.h
new file mode 100644
index 0000000000..fcfce1c181
--- /dev/null
+++ b/library/cpp/grpc/server/grpc_request_base.h
@@ -0,0 +1,116 @@
+#pragma once
+
+#include <google/protobuf/message.h>
+#include <library/cpp/threading/future/future.h>
+
+#include <grpc++/server_context.h>
+
+namespace grpc {
+class ByteBuffer;
+}
+
+namespace NGrpc {
+
+extern const char* GRPC_USER_AGENT_HEADER;
+
+struct TAuthState {
+ enum EAuthState {
+ AS_NOT_PERFORMED,
+ AS_OK,
+ AS_FAIL,
+ AS_UNAVAILABLE
+ };
+ TAuthState(bool needAuth)
+ : NeedAuth(needAuth)
+ , State(AS_NOT_PERFORMED)
+ {}
+ bool NeedAuth;
+ EAuthState State;
+};
+
+
+//! An interface that may be used to limit concurrency of requests
+class IGRpcRequestLimiter: public TThrRefBase {
+public:
+ virtual bool IncRequest() = 0;
+ virtual void DecRequest() = 0;
+};
+
+using IGRpcRequestLimiterPtr = TIntrusivePtr<IGRpcRequestLimiter>;
+
+//! State of current request
+class IRequestContextBase: public TThrRefBase {
+public:
+ enum class EFinishStatus {
+ OK,
+ ERROR,
+ CANCEL
+ };
+ using TAsyncFinishResult = NThreading::TFuture<EFinishStatus>;
+
+ using TOnNextReply = std::function<void (size_t left)>;
+
+ //! Get pointer to the request's message.
+ virtual const NProtoBuf::Message* GetRequest() const = 0;
+
+ //! Get current auth state
+ virtual TAuthState& GetAuthState() = 0;
+
+ //! Send common response (The request shoult be created for protobuf response type)
+ //! Implementation can swap protobuf message
+ virtual void Reply(NProtoBuf::Message* resp, ui32 status = 0) = 0;
+
+ //! Send serialised response (The request shoult be created for bytes response type)
+ //! Implementation can swap ByteBuffer
+ virtual void Reply(grpc::ByteBuffer* resp, ui32 status = 0) = 0;
+
+ //! Send grpc UNAUTHENTICATED status
+ virtual void ReplyUnauthenticated(const TString& in) = 0;
+
+ //! Send grpc error
+ virtual void ReplyError(grpc::StatusCode code, const TString& msg) = 0;
+
+ //! Returns deadline (server epoch related) if peer set it on its side, or Instanse::Max() otherwise
+ virtual TInstant Deadline() const = 0;
+
+ //! Returns available peer metadata keys
+ virtual TSet<TStringBuf> GetPeerMetaKeys() const = 0;
+
+ //! Returns peer optional metavalue
+ virtual TVector<TStringBuf> GetPeerMetaValues(TStringBuf key) const = 0;
+
+ //! Returns request compression level
+ virtual grpc_compression_level GetCompressionLevel() const = 0;
+
+ //! Returns protobuf arena allocator associated with current request
+ //! Lifetime of the arena is lifetime of the context
+ virtual google::protobuf::Arena* GetArena() = 0;
+
+ //! Add trailing metadata in to grpc context
+ //! The metadata will be send at the time of rpc finish
+ virtual void AddTrailingMetadata(const TString& key, const TString& value) = 0;
+
+ //! Use validated database name for counters
+ virtual void UseDatabase(const TString& database) = 0;
+
+ // Streaming part
+
+ //! Set callback. The callback will be called when response deliverid to the client
+ //! after that we can call Reply again in streaming mode. Yes, GRpc says there is only one
+ //! reply in flight
+ virtual void SetNextReplyCallback(TOnNextReply&& cb) = 0;
+
+ //! Finish streaming reply
+ virtual void FinishStreamingOk() = 0;
+
+ //! Returns future to get cancel of finish notification
+ virtual TAsyncFinishResult GetFinishFuture() = 0;
+
+ //! Returns peer address
+ virtual TString GetPeer() const = 0;
+
+ //! Returns true if server is using ssl
+ virtual bool SslServer() const = 0;
+};
+
+} // namespace NGrpc
diff --git a/library/cpp/grpc/server/grpc_response.h b/library/cpp/grpc/server/grpc_response.h
new file mode 100644
index 0000000000..8e9afe44d5
--- /dev/null
+++ b/library/cpp/grpc/server/grpc_response.h
@@ -0,0 +1,90 @@
+#pragma once
+
+#include <grpc++/impl/codegen/byte_buffer.h>
+#include <grpc++/impl/codegen/proto_utils.h>
+
+#include <variant>
+
+namespace NGrpc {
+
+/**
+ * Universal response that owns underlying message or buffer.
+ */
+template <typename TMsg>
+class TUniversalResponse: public TAtomicRefCount<TUniversalResponse<TMsg>>, public TMoveOnly {
+ friend class grpc::SerializationTraits<TUniversalResponse<TMsg>>;
+
+public:
+ explicit TUniversalResponse(NProtoBuf::Message* msg) noexcept
+ : Data_{TMsg{}}
+ {
+ std::get<TMsg>(Data_).Swap(static_cast<TMsg*>(msg));
+ }
+
+ explicit TUniversalResponse(grpc::ByteBuffer* buffer) noexcept
+ : Data_{grpc::ByteBuffer{}}
+ {
+ std::get<grpc::ByteBuffer>(Data_).Swap(buffer);
+ }
+
+private:
+ std::variant<TMsg, grpc::ByteBuffer> Data_;
+};
+
+/**
+ * Universal response that only keeps reference to underlying message or buffer.
+ */
+template <typename TMsg>
+class TUniversalResponseRef: private TMoveOnly {
+ friend class grpc::SerializationTraits<TUniversalResponseRef<TMsg>>;
+
+public:
+ explicit TUniversalResponseRef(const NProtoBuf::Message* msg)
+ : Data_{msg}
+ {
+ }
+
+ explicit TUniversalResponseRef(const grpc::ByteBuffer* buffer)
+ : Data_{buffer}
+ {
+ }
+
+private:
+ std::variant<const NProtoBuf::Message*, const grpc::ByteBuffer*> Data_;
+};
+
+} // namespace NGrpc
+
+namespace grpc {
+
+template <typename TMsg>
+class SerializationTraits<NGrpc::TUniversalResponse<TMsg>> {
+public:
+ static Status Serialize(
+ const NGrpc::TUniversalResponse<TMsg>& resp,
+ ByteBuffer* buffer,
+ bool* ownBuffer)
+ {
+ return std::visit([&](const auto& data) {
+ using T = std::decay_t<decltype(data)>;
+ return SerializationTraits<T>::Serialize(data, buffer, ownBuffer);
+ }, resp.Data_);
+ }
+};
+
+template <typename TMsg>
+class SerializationTraits<NGrpc::TUniversalResponseRef<TMsg>> {
+public:
+ static Status Serialize(
+ const NGrpc::TUniversalResponseRef<TMsg>& resp,
+ ByteBuffer* buffer,
+ bool* ownBuffer)
+ {
+ return std::visit([&](const auto* data) {
+ using T = std::decay_t<std::remove_pointer_t<decltype(data)>>;
+ return SerializationTraits<T>::Serialize(*data, buffer, ownBuffer);
+ }, resp.Data_);
+ }
+};
+
+} // namespace grpc
diff --git a/library/cpp/grpc/server/grpc_server.cpp b/library/cpp/grpc/server/grpc_server.cpp
new file mode 100644
index 0000000000..7437b7a8f5
--- /dev/null
+++ b/library/cpp/grpc/server/grpc_server.cpp
@@ -0,0 +1,240 @@
+#include "grpc_server.h"
+
+#include <util/string/join.h>
+#include <util/generic/yexception.h>
+#include <util/system/thread.h>
+
+#include <grpc++/resource_quota.h>
+#include <contrib/libs/grpc/src/core/lib/iomgr/socket_mutator.h>
+
+#if !defined(_WIN32) && !defined(_WIN64)
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#endif
+
+namespace NGrpc {
+
+using NThreading::TFuture;
+
+static void PullEvents(grpc::ServerCompletionQueue* cq) {
+ TThread::SetCurrentThreadName("grpc_server");
+ while (true) {
+ void* tag; // uniquely identifies a request.
+ bool ok;
+
+ if (cq->Next(&tag, &ok)) {
+ IQueueEvent* const ev(static_cast<IQueueEvent*>(tag));
+
+ if (!ev->Execute(ok)) {
+ ev->DestroyRequest();
+ }
+ } else {
+ break;
+ }
+ }
+}
+
+TGRpcServer::TGRpcServer(const TServerOptions& opts)
+ : Options_(opts)
+ , Limiter_(Options_.MaxGlobalRequestInFlight)
+ {}
+
+TGRpcServer::~TGRpcServer() {
+ Y_VERIFY(Ts.empty());
+ Services_.clear();
+}
+
+void TGRpcServer::AddService(IGRpcServicePtr service) {
+ Services_.push_back(service);
+}
+
+void TGRpcServer::Start() {
+ TString server_address(Join(":", Options_.Host, Options_.Port)); // https://st.yandex-team.ru/DTCC-695
+ using grpc::ServerBuilder;
+ using grpc::ResourceQuota;
+ ServerBuilder builder;
+ auto credentials = grpc::InsecureServerCredentials();
+ if (Options_.SslData) {
+ grpc::SslServerCredentialsOptions::PemKeyCertPair keycert;
+ keycert.cert_chain = std::move(Options_.SslData->Cert);
+ keycert.private_key = std::move(Options_.SslData->Key);
+ grpc::SslServerCredentialsOptions sslOps;
+ sslOps.pem_root_certs = std::move(Options_.SslData->Root);
+ sslOps.pem_key_cert_pairs.push_back(keycert);
+ credentials = grpc::SslServerCredentials(sslOps);
+ }
+ if (Options_.ExternalListener) {
+ Options_.ExternalListener->Init(builder.experimental().AddExternalConnectionAcceptor(
+ ServerBuilder::experimental_type::ExternalConnectionType::FROM_FD,
+ credentials
+ ));
+ } else {
+ builder.AddListeningPort(server_address, credentials);
+ }
+ builder.SetMaxReceiveMessageSize(Options_.MaxMessageSize);
+ builder.SetMaxSendMessageSize(Options_.MaxMessageSize);
+ for (IGRpcServicePtr service : Services_) {
+ service->SetServerOptions(Options_);
+ builder.RegisterService(service->GetService());
+ service->SetGlobalLimiterHandle(&Limiter_);
+ }
+
+ class TKeepAliveOption: public grpc::ServerBuilderOption {
+ public:
+ TKeepAliveOption(int idle, int interval)
+ : Idle(idle)
+ , Interval(interval)
+ , KeepAliveEnabled(true)
+ {}
+
+ TKeepAliveOption()
+ : Idle(0)
+ , Interval(0)
+ , KeepAliveEnabled(false)
+ {}
+
+ void UpdateArguments(grpc::ChannelArguments *args) override {
+ args->SetInt(GRPC_ARG_HTTP2_MAX_PING_STRIKES, 0);
+ args->SetInt(GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS, 1000);
+ if (KeepAliveEnabled) {
+ args->SetInt(GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA, 0);
+ args->SetInt(GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS, 1);
+ args->SetInt(GRPC_ARG_HTTP2_MIN_SENT_PING_INTERVAL_WITHOUT_DATA_MS, Idle * 1000);
+ args->SetInt(GRPC_ARG_KEEPALIVE_TIME_MS, Idle * 1000);
+ args->SetInt(GRPC_ARG_KEEPALIVE_TIMEOUT_MS, Interval * 1000);
+ }
+ }
+
+ void UpdatePlugins(std::vector<std::unique_ptr<grpc::ServerBuilderPlugin>>* /*plugins*/) override
+ {}
+ private:
+ const int Idle;
+ const int Interval;
+ const bool KeepAliveEnabled;
+ };
+
+ if (Options_.KeepAliveEnable) {
+ builder.SetOption(std::make_unique<TKeepAliveOption>(
+ Options_.KeepAliveIdleTimeoutTriggerSec,
+ Options_.KeepAliveProbeIntervalSec));
+ } else {
+ builder.SetOption(std::make_unique<TKeepAliveOption>());
+ }
+
+ if (Options_.UseCompletionQueuePerThread) {
+ for (size_t i = 0; i < Options_.WorkerThreads; ++i) {
+ CQS_.push_back(builder.AddCompletionQueue());
+ }
+ } else {
+ CQS_.push_back(builder.AddCompletionQueue());
+ }
+
+ if (Options_.GRpcMemoryQuotaBytes) {
+ // See details KIKIMR-6932
+ /*
+ grpc::ResourceQuota quota("memory_bound");
+ quota.Resize(Options_.GRpcMemoryQuotaBytes);
+
+ builder.SetResourceQuota(quota);
+ */
+ Cerr << "GRpc memory quota temporarily disabled due to issues with grpc quoter" << Endl;
+ }
+ Options_.ServerBuilderMutator(builder);
+ builder.SetDefaultCompressionLevel(Options_.DefaultCompressionLevel);
+
+ Server_ = builder.BuildAndStart();
+ if (!Server_) {
+ ythrow yexception() << "can't start grpc server on " << server_address;
+ }
+
+ size_t index = 0;
+ for (IGRpcServicePtr service : Services_) {
+ // TODO: provide something else for services instead of ServerCompletionQueue
+ service->InitService(CQS_[index++ % CQS_.size()].get(), Options_.Logger);
+ }
+
+ if (Options_.UseCompletionQueuePerThread) {
+ for (size_t i = 0; i < Options_.WorkerThreads; ++i) {
+ auto* cq = &CQS_[i];
+ Ts.push_back(SystemThreadFactory()->Run([cq] {
+ PullEvents(cq->get());
+ }));
+ }
+ } else {
+ for (size_t i = 0; i < Options_.WorkerThreads; ++i) {
+ auto* cq = &CQS_[0];
+ Ts.push_back(SystemThreadFactory()->Run([cq] {
+ PullEvents(cq->get());
+ }));
+ }
+ }
+
+ if (Options_.ExternalListener) {
+ Options_.ExternalListener->Start();
+ }
+}
+
+void TGRpcServer::Stop() {
+ for (auto& service : Services_) {
+ service->StopService();
+ }
+
+ auto now = TInstant::Now();
+
+ if (Server_) {
+ i64 sec = Options_.GRpcShutdownDeadline.Seconds();
+ Y_VERIFY(Options_.GRpcShutdownDeadline.NanoSecondsOfSecond() <= Max<i32>());
+ i32 nanosecOfSec = Options_.GRpcShutdownDeadline.NanoSecondsOfSecond();
+ Server_->Shutdown(gpr_timespec{sec, nanosecOfSec, GPR_TIMESPAN});
+ }
+
+ for (ui64 attempt = 0; ; ++attempt) {
+ bool unsafe = false;
+ size_t infly = 0;
+ for (auto& service : Services_) {
+ unsafe |= service->IsUnsafeToShutdown();
+ infly += service->RequestsInProgress();
+ }
+
+ if (!unsafe && !infly)
+ break;
+
+ auto spent = (TInstant::Now() - now).SecondsFloat();
+ if (attempt % 300 == 0) {
+ // don't log too much
+ Cerr << "GRpc shutdown warning: left infly: " << infly << ", spent: " << spent << " sec" << Endl;
+ }
+
+ if (!unsafe && spent > Options_.GRpcShutdownDeadline.SecondsFloat())
+ break;
+ Sleep(TDuration::MilliSeconds(10));
+ }
+
+ // Always shutdown the completion queue after the server.
+ for (auto& cq : CQS_) {
+ cq->Shutdown();
+ }
+
+ for (auto ti = Ts.begin(); ti != Ts.end(); ++ti) {
+ (*ti)->Join();
+ }
+
+ Ts.clear();
+
+ if (Options_.ExternalListener) {
+ Options_.ExternalListener->Stop();
+ }
+}
+
+ui16 TGRpcServer::GetPort() const {
+ return Options_.Port;
+}
+
+TString TGRpcServer::GetHost() const {
+ return Options_.Host;
+}
+
+} // namespace NGrpc
diff --git a/library/cpp/grpc/server/grpc_server.h b/library/cpp/grpc/server/grpc_server.h
new file mode 100644
index 0000000000..d6814a90a0
--- /dev/null
+++ b/library/cpp/grpc/server/grpc_server.h
@@ -0,0 +1,356 @@
+#pragma once
+
+#include "grpc_request_base.h"
+#include "logger.h"
+
+#include <library/cpp/threading/future/future.h>
+
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/generic/maybe.h>
+#include <util/generic/queue.h>
+#include <util/generic/hash_set.h>
+#include <util/system/types.h>
+#include <util/system/mutex.h>
+#include <util/thread/factory.h>
+
+#include <grpc++/grpc++.h>
+
+namespace NGrpc {
+
+constexpr ui64 DEFAULT_GRPC_MESSAGE_SIZE_LIMIT = 64000000;
+
+struct TSslData {
+ TString Cert;
+ TString Key;
+ TString Root;
+};
+
+struct IExternalListener
+ : public TThrRefBase
+{
+ using TPtr = TIntrusivePtr<IExternalListener>;
+ virtual void Init(std::unique_ptr<grpc::experimental::ExternalConnectionAcceptor> acceptor) = 0;
+ virtual void Start() = 0;
+ virtual void Stop() = 0;
+};
+
+//! Server's options.
+struct TServerOptions {
+#define DECLARE_FIELD(name, type, default) \
+ type name{default}; \
+ inline TServerOptions& Set##name(const type& value) { \
+ name = value; \
+ return *this; \
+ }
+
+ //! Hostname of server to bind to.
+ DECLARE_FIELD(Host, TString, "[::]");
+ //! Service port.
+ DECLARE_FIELD(Port, ui16, 0);
+
+ //! Number of worker threads.
+ DECLARE_FIELD(WorkerThreads, size_t, 2);
+
+ //! Create one completion queue per thread
+ DECLARE_FIELD(UseCompletionQueuePerThread, bool, false);
+
+ //! Memory quota size for grpc server in bytes. Zero means unlimited.
+ DECLARE_FIELD(GRpcMemoryQuotaBytes, size_t, 0);
+
+ //! How long to wait until pending rpcs are forcefully terminated.
+ DECLARE_FIELD(GRpcShutdownDeadline, TDuration, TDuration::Seconds(30));
+
+ //! In/Out message size limit
+ DECLARE_FIELD(MaxMessageSize, size_t, DEFAULT_GRPC_MESSAGE_SIZE_LIMIT);
+
+ //! Use GRpc keepalive
+ DECLARE_FIELD(KeepAliveEnable, TMaybe<bool>, TMaybe<bool>());
+
+ //! GRPC_ARG_KEEPALIVE_TIME_MS setting
+ DECLARE_FIELD(KeepAliveIdleTimeoutTriggerSec, int, 0);
+
+ //! Deprecated, ths option ignored. Will be removed soon.
+ DECLARE_FIELD(KeepAliveMaxProbeCount, int, 0);
+
+ //! GRPC_ARG_KEEPALIVE_TIMEOUT_MS setting
+ DECLARE_FIELD(KeepAliveProbeIntervalSec, int, 0);
+
+ //! Max number of requests processing by services (global limit for grpc server)
+ DECLARE_FIELD(MaxGlobalRequestInFlight, size_t, 100000);
+
+ //! SSL server data
+ DECLARE_FIELD(SslData, TMaybe<TSslData>, TMaybe<TSslData>());
+
+ //! GRPC auth
+ DECLARE_FIELD(UseAuth, bool, false);
+
+ //! Default compression level. Used when no compression options provided by client.
+ // Mapping to particular compression algorithm depends on client.
+ DECLARE_FIELD(DefaultCompressionLevel, grpc_compression_level, GRPC_COMPRESS_LEVEL_NONE);
+
+ //! Custom configurator for ServerBuilder.
+ DECLARE_FIELD(ServerBuilderMutator, std::function<void(grpc::ServerBuilder&)>, [](grpc::ServerBuilder&){});
+
+ DECLARE_FIELD(ExternalListener, IExternalListener::TPtr, nullptr);
+
+ //! Logger which will be used to write logs about requests handling (iff appropriate log level is enabled).
+ DECLARE_FIELD(Logger, TLoggerPtr, nullptr);
+
+#undef DECLARE_FIELD
+};
+
+class IQueueEvent {
+public:
+ virtual ~IQueueEvent() = default;
+
+ //! Execute an action defined by implementation.
+ virtual bool Execute(bool ok) = 0;
+
+ //! It is time to perform action requested by AcquireToken server method. It will be called under lock which is also
+ // used in ReturnToken/AcquireToken methods. Default implementation does nothing assuming that request processor does
+ // not implement in flight management.
+ virtual void Process() {}
+
+ //! Finish and destroy request.
+ virtual void DestroyRequest() = 0;
+};
+
+class ICancelableContext {
+public:
+ virtual void Shutdown() = 0;
+ virtual ~ICancelableContext() = default;
+};
+
+template <class TLimit>
+class TInFlightLimiterImpl {
+public:
+ explicit TInFlightLimiterImpl(const TLimit& limit)
+ : Limit_(limit)
+ {}
+
+ bool Inc() {
+ i64 newVal;
+ i64 prev;
+ do {
+ prev = AtomicGet(CurInFlightReqs_);
+ Y_VERIFY(prev >= 0);
+ if (Limit_ && prev > Limit_) {
+ return false;
+ }
+ newVal = prev + 1;
+ } while (!AtomicCas(&CurInFlightReqs_, newVal, prev));
+ return true;
+ }
+
+ void Dec() {
+ i64 newVal = AtomicDecrement(CurInFlightReqs_);
+ Y_VERIFY(newVal >= 0);
+ }
+
+ i64 GetCurrentInFlight() const {
+ return AtomicGet(CurInFlightReqs_);
+ }
+
+private:
+ const TLimit Limit_;
+ TAtomic CurInFlightReqs_ = 0;
+};
+
+using TGlobalLimiter = TInFlightLimiterImpl<i64>;
+
+
+class IGRpcService: public TThrRefBase {
+public:
+ virtual grpc::Service* GetService() = 0;
+ virtual void StopService() noexcept = 0;
+ virtual void InitService(grpc::ServerCompletionQueue* cq, TLoggerPtr logger) = 0;
+ virtual void SetGlobalLimiterHandle(TGlobalLimiter* limiter) = 0;
+ virtual bool IsUnsafeToShutdown() const = 0;
+ virtual size_t RequestsInProgress() const = 0;
+
+ /**
+ * Called before service is added to the server builder. This allows
+ * service to inspect server options and initialize accordingly.
+ */
+ virtual void SetServerOptions(const TServerOptions& options) = 0;
+};
+
+template<typename T>
+class TGrpcServiceBase: public IGRpcService {
+public:
+ class TShutdownGuard {
+ using TOwner = TGrpcServiceBase<T>;
+ friend class TGrpcServiceBase<T>;
+
+ public:
+ TShutdownGuard()
+ : Owner(nullptr)
+ { }
+
+ ~TShutdownGuard() {
+ Release();
+ }
+
+ TShutdownGuard(TShutdownGuard&& other)
+ : Owner(other.Owner)
+ {
+ other.Owner = nullptr;
+ }
+
+ TShutdownGuard& operator=(TShutdownGuard&& other) {
+ if (Y_LIKELY(this != &other)) {
+ Release();
+ Owner = other.Owner;
+ other.Owner = nullptr;
+ }
+ return *this;
+ }
+
+ explicit operator bool() const {
+ return bool(Owner);
+ }
+
+ void Release() {
+ if (Owner) {
+ AtomicDecrement(Owner->GuardCount_);
+ Owner = nullptr;
+ }
+ }
+
+ TShutdownGuard(const TShutdownGuard&) = delete;
+ TShutdownGuard& operator=(const TShutdownGuard&) = delete;
+
+ private:
+ explicit TShutdownGuard(TOwner* owner)
+ : Owner(owner)
+ { }
+
+ private:
+ TOwner* Owner;
+ };
+
+public:
+ using TCurrentGRpcService = T;
+
+ void StopService() noexcept override {
+ with_lock(Lock_) {
+ AtomicSet(ShuttingDown_, 1);
+
+ // Send TryCansel to event (can be send after finishing).
+ // Actual dtors will be called from grpc thread, so deadlock impossible
+ for (auto* request : Requests_) {
+ request->Shutdown();
+ }
+ }
+ }
+
+ TShutdownGuard ProtectShutdown() noexcept {
+ AtomicIncrement(GuardCount_);
+ if (IsShuttingDown()) {
+ AtomicDecrement(GuardCount_);
+ return { };
+ }
+
+ return TShutdownGuard(this);
+ };
+
+ bool IsUnsafeToShutdown() const override {
+ return AtomicGet(GuardCount_) > 0;
+ }
+
+ size_t RequestsInProgress() const override {
+ size_t c = 0;
+ with_lock(Lock_) {
+ c = Requests_.size();
+ }
+ return c;
+ }
+
+ void SetServerOptions(const TServerOptions& options) override {
+ SslServer_ = bool(options.SslData);
+ NeedAuth_ = options.UseAuth;
+ }
+
+ void SetGlobalLimiterHandle(TGlobalLimiter* /*limiter*/) override {}
+
+ //! Check if the server is going to shut down.
+ bool IsShuttingDown() const {
+ return AtomicGet(ShuttingDown_);
+ }
+
+ bool SslServer() const {
+ return SslServer_;
+ }
+
+ bool NeedAuth() const {
+ return NeedAuth_;
+ }
+
+ bool RegisterRequestCtx(ICancelableContext* req) {
+ with_lock(Lock_) {
+ auto r = Requests_.emplace(req);
+ Y_VERIFY(r.second, "Ctx already registered");
+
+ if (IsShuttingDown()) {
+ // Server is already shutting down
+ Requests_.erase(r.first);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ void DeregisterRequestCtx(ICancelableContext* req) {
+ with_lock(Lock_) {
+ Y_VERIFY(Requests_.erase(req), "Ctx is not registered");
+ }
+ }
+
+protected:
+ using TGrpcAsyncService = typename TCurrentGRpcService::AsyncService;
+ TGrpcAsyncService Service_;
+
+ TGrpcAsyncService* GetService() override {
+ return &Service_;
+ }
+
+private:
+ TAtomic ShuttingDown_ = 0;
+ TAtomic GuardCount_ = 0;
+
+ bool SslServer_ = false;
+ bool NeedAuth_ = false;
+
+ THashSet<ICancelableContext*> Requests_;
+ TAdaptiveLock Lock_;
+};
+
+class TGRpcServer {
+public:
+ using IGRpcServicePtr = TIntrusivePtr<IGRpcService>;
+ TGRpcServer(const TServerOptions& opts);
+ ~TGRpcServer();
+ void AddService(IGRpcServicePtr service);
+ void Start();
+ // Send stop to registred services and call Shutdown on grpc server
+ // This method MUST be called before destroying TGRpcServer
+ void Stop();
+ ui16 GetPort() const;
+ TString GetHost() const;
+
+private:
+ using IThreadRef = TAutoPtr<IThreadFactory::IThread>;
+
+ const TServerOptions Options_;
+ std::unique_ptr<grpc::Server> Server_;
+ std::vector<std::unique_ptr<grpc::ServerCompletionQueue>> CQS_;
+ TVector<IThreadRef> Ts;
+
+ TVector<IGRpcServicePtr> Services_;
+ TGlobalLimiter Limiter_;
+};
+
+} // namespace NGrpc
diff --git a/library/cpp/grpc/server/logger.h b/library/cpp/grpc/server/logger.h
new file mode 100644
index 0000000000..53af26be9c
--- /dev/null
+++ b/library/cpp/grpc/server/logger.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include <library/cpp/logger/priority.h>
+
+#include <util/generic/ptr.h>
+
+namespace NGrpc {
+
+class TLogger: public TThrRefBase {
+protected:
+ TLogger() = default;
+
+public:
+ [[nodiscard]]
+ bool IsEnabled(ELogPriority priority) const noexcept {
+ return DoIsEnabled(priority);
+ }
+
+ void Y_PRINTF_FORMAT(3, 4) Write(ELogPriority priority, const char* format, ...) noexcept {
+ va_list args;
+ va_start(args, format);
+ DoWrite(priority, format, args);
+ va_end(args);
+ }
+
+protected:
+ virtual bool DoIsEnabled(ELogPriority priority) const noexcept = 0;
+ virtual void DoWrite(ELogPriority p, const char* format, va_list args) noexcept = 0;
+};
+
+using TLoggerPtr = TIntrusivePtr<TLogger>;
+
+#define GRPC_LOG_DEBUG(logger, format, ...) \
+ if (logger && logger->IsEnabled(ELogPriority::TLOG_DEBUG)) { \
+ logger->Write(ELogPriority::TLOG_DEBUG, format, __VA_ARGS__); \
+ } else { }
+
+#define GRPC_LOG_INFO(logger, format, ...) \
+ if (logger && logger->IsEnabled(ELogPriority::TLOG_INFO)) { \
+ logger->Write(ELogPriority::TLOG_INFO, format, __VA_ARGS__); \
+ } else { }
+
+} // namespace NGrpc
diff --git a/library/cpp/grpc/server/ut/grpc_response_ut.cpp b/library/cpp/grpc/server/ut/grpc_response_ut.cpp
new file mode 100644
index 0000000000..8abc4e4e0e
--- /dev/null
+++ b/library/cpp/grpc/server/ut/grpc_response_ut.cpp
@@ -0,0 +1,88 @@
+#include <library/cpp/grpc/server/grpc_response.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <google/protobuf/duration.pb.h>
+#include <grpc++/impl/codegen/proto_utils.h>
+#include <grpc++/impl/grpc_library.h>
+
+static ::grpc::internal::GrpcLibraryInitializer grpcInitializer;
+
+using namespace NGrpc;
+
+using google::protobuf::Duration;
+
+Y_UNIT_TEST_SUITE(ResponseTest) {
+
+ template <typename T>
+ grpc::ByteBuffer Serialize(T resp) {
+ grpc::ByteBuffer buf;
+ bool ownBuf = false;
+ grpc::Status status = grpc::SerializationTraits<T>::Serialize(resp, &buf, &ownBuf);
+ UNIT_ASSERT(status.ok());
+ return buf;
+ }
+
+ template <typename T>
+ T Deserialize(grpc::ByteBuffer* buf) {
+ T message;
+ auto status = grpc::SerializationTraits<T>::Deserialize(buf, &message);
+ UNIT_ASSERT(status.ok());
+ return message;
+ }
+
+ Y_UNIT_TEST(UniversalResponseMsg) {
+ Duration d1;
+ d1.set_seconds(12345);
+ d1.set_nanos(67890);
+
+ auto buf = Serialize(TUniversalResponse<Duration>(&d1));
+ Duration d2 = Deserialize<Duration>(&buf);
+
+ UNIT_ASSERT_VALUES_EQUAL(d2.seconds(), 12345);
+ UNIT_ASSERT_VALUES_EQUAL(d2.nanos(), 67890);
+ }
+
+ Y_UNIT_TEST(UniversalResponseBuf) {
+ Duration d1;
+ d1.set_seconds(123);
+ d1.set_nanos(456);
+
+ TString data = d1.SerializeAsString();
+ grpc::Slice dataSlice{data.data(), data.size()};
+ grpc::ByteBuffer dataBuf{&dataSlice, 1};
+
+ auto buf = Serialize(TUniversalResponse<Duration>(&dataBuf));
+ Duration d2 = Deserialize<Duration>(&buf);
+
+ UNIT_ASSERT_VALUES_EQUAL(d2.seconds(), 123);
+ UNIT_ASSERT_VALUES_EQUAL(d2.nanos(), 456);
+ }
+
+ Y_UNIT_TEST(UniversalResponseRefMsg) {
+ Duration d1;
+ d1.set_seconds(12345);
+ d1.set_nanos(67890);
+
+ auto buf = Serialize(TUniversalResponseRef<Duration>(&d1));
+ Duration d2 = Deserialize<Duration>(&buf);
+
+ UNIT_ASSERT_VALUES_EQUAL(d2.seconds(), 12345);
+ UNIT_ASSERT_VALUES_EQUAL(d2.nanos(), 67890);
+ }
+
+ Y_UNIT_TEST(UniversalResponseRefBuf) {
+ Duration d1;
+ d1.set_seconds(123);
+ d1.set_nanos(456);
+
+ TString data = d1.SerializeAsString();
+ grpc::Slice dataSlice{data.data(), data.size()};
+ grpc::ByteBuffer dataBuf{&dataSlice, 1};
+
+ auto buf = Serialize(TUniversalResponseRef<Duration>(&dataBuf));
+ Duration d2 = Deserialize<Duration>(&buf);
+
+ UNIT_ASSERT_VALUES_EQUAL(d2.seconds(), 123);
+ UNIT_ASSERT_VALUES_EQUAL(d2.nanos(), 456);
+ }
+}
diff --git a/library/cpp/grpc/server/ut/stream_adaptor_ut.cpp b/library/cpp/grpc/server/ut/stream_adaptor_ut.cpp
new file mode 100644
index 0000000000..c34d3b8c2b
--- /dev/null
+++ b/library/cpp/grpc/server/ut/stream_adaptor_ut.cpp
@@ -0,0 +1,121 @@
+#include <library/cpp/grpc/server/grpc_request.h>
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/testing/unittest/tests_data.h>
+
+#include <util/system/thread.h>
+#include <util/thread/pool.h>
+
+using namespace NGrpc;
+
+// Here we emulate stream data producer
+class TOrderedProducer: public TThread {
+public:
+ TOrderedProducer(IStreamAdaptor* adaptor, ui64 max, bool withSleep, std::function<void(ui64)>&& consumerOp)
+ : TThread(&ThreadProc, this)
+ , Adaptor_(adaptor)
+ , Max_(max)
+ , WithSleep_(withSleep)
+ , ConsumerOp_(std::move(consumerOp))
+ {}
+
+ static void* ThreadProc(void* _this) {
+ SetCurrentThreadName("OrderedProducerThread");
+ static_cast<TOrderedProducer*>(_this)->Exec();
+ return nullptr;
+ }
+
+ void Exec() {
+ for (ui64 i = 0; i < Max_; i++) {
+ auto cb = [i, this]() mutable {
+ ConsumerOp_(i);
+ };
+ Adaptor_->Enqueue(std::move(cb), false);
+ if (WithSleep_ && (i % 256 == 0)) {
+ Sleep(TDuration::MilliSeconds(10));
+ }
+ }
+ }
+
+private:
+ IStreamAdaptor* Adaptor_;
+ const ui64 Max_;
+ const bool WithSleep_;
+ std::function<void(ui64)> ConsumerOp_;
+};
+
+Y_UNIT_TEST_SUITE(StreamAdaptor) {
+ static void OrderingTest(size_t threads, bool withSleep) {
+
+ auto adaptor = CreateStreamAdaptor();
+
+ const i64 max = 10000;
+
+ // Here we will emulate grpc stream (NextReply call after writing)
+ std::unique_ptr<IThreadPool> consumerQueue(new TThreadPool(TThreadPool::TParams().SetBlocking(false).SetCatching(false)));
+ // And make sure only one request inflight (see UNIT_ASSERT on adding to the queue)
+ consumerQueue->Start(threads, 1);
+
+ // Non atomic!!! Stream adaptor must protect us
+ ui64 curVal = 0;
+
+ // Used just to wait in the main thread
+ TAtomic finished = false;
+ auto consumerOp = [&finished, &curVal, ptr{adaptor.get()}, queue{consumerQueue.get()}](ui64 i) {
+ // Check no reordering inside stream adaptor
+ // and no simultanious consumer Op call
+ UNIT_ASSERT_VALUES_EQUAL(curVal, i);
+ curVal++;
+ // We must set finished flag after last ProcessNext, but we can`t compare curVal and max after ProcessNext
+ // so compare here and set after
+ bool tmp = curVal == max;
+ bool res = queue->AddFunc([ptr, &finished, tmp, &curVal, i]() {
+ // Additional check the value still same
+ // run under tsan makes sure no consumer Op call before we call ProcessNext
+ UNIT_ASSERT_VALUES_EQUAL(curVal, i + 1);
+ ptr->ProcessNext();
+ // Reordering after ProcessNext is possible, so check tmp and set finished to true
+ if (tmp)
+ AtomicSet(finished, true);
+ });
+ UNIT_ASSERT(res);
+ };
+
+ TOrderedProducer producer(adaptor.get(), max, withSleep, std::move(consumerOp));
+
+ producer.Start();
+ producer.Join();
+
+ while (!AtomicGet(finished))
+ {
+ Sleep(TDuration::MilliSeconds(100));
+ }
+
+ consumerQueue->Stop();
+
+ UNIT_ASSERT_VALUES_EQUAL(curVal, max);
+ }
+
+ Y_UNIT_TEST(OrderingOneThread) {
+ OrderingTest(1, false);
+ }
+
+ Y_UNIT_TEST(OrderingTwoThreads) {
+ OrderingTest(2, false);
+ }
+
+ Y_UNIT_TEST(OrderingManyThreads) {
+ OrderingTest(10, false);
+ }
+
+ Y_UNIT_TEST(OrderingOneThreadWithSleep) {
+ OrderingTest(1, true);
+ }
+
+ Y_UNIT_TEST(OrderingTwoThreadsWithSleep) {
+ OrderingTest(2, true);
+ }
+
+ Y_UNIT_TEST(OrderingManyThreadsWithSleep) {
+ OrderingTest(10, true);
+ }
+}
diff --git a/library/cpp/grpc/server/ut/ya.make b/library/cpp/grpc/server/ut/ya.make
new file mode 100644
index 0000000000..feb3291af9
--- /dev/null
+++ b/library/cpp/grpc/server/ut/ya.make
@@ -0,0 +1,21 @@
+UNITTEST_FOR(library/cpp/grpc/server)
+
+OWNER(
+ dcherednik
+ g:kikimr
+)
+
+TIMEOUT(600)
+SIZE(MEDIUM)
+
+PEERDIR(
+ library/cpp/grpc/server
+)
+
+SRCS(
+ grpc_response_ut.cpp
+ stream_adaptor_ut.cpp
+)
+
+END()
+
diff --git a/library/cpp/grpc/server/ya.make b/library/cpp/grpc/server/ya.make
new file mode 100644
index 0000000000..356a1b6793
--- /dev/null
+++ b/library/cpp/grpc/server/ya.make
@@ -0,0 +1,25 @@
+LIBRARY()
+
+OWNER(
+ dcherednik
+ g:kikimr
+)
+
+SRCS(
+ event_callback.cpp
+ grpc_request.cpp
+ grpc_server.cpp
+ grpc_counters.cpp
+)
+
+GENERATE_ENUM_SERIALIZATION(grpc_request_base.h)
+
+PEERDIR(
+ contrib/libs/grpc
+ library/cpp/monlib/dynamic_counters/percentile
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
+
diff --git a/library/cpp/grpc/ya.make b/library/cpp/grpc/ya.make
new file mode 100644
index 0000000000..3635124115
--- /dev/null
+++ b/library/cpp/grpc/ya.make
@@ -0,0 +1,5 @@
+RECURSE(
+ client
+ common
+ server
+)
diff --git a/library/cpp/histogram/adaptive/README.md b/library/cpp/histogram/adaptive/README.md
new file mode 100644
index 0000000000..17a4edbe64
--- /dev/null
+++ b/library/cpp/histogram/adaptive/README.md
@@ -0,0 +1 @@
+See https://wiki.yandex-team.ru/robot/newdesign/histograms/
diff --git a/library/cpp/histogram/adaptive/adaptive_histogram.cpp b/library/cpp/histogram/adaptive/adaptive_histogram.cpp
new file mode 100644
index 0000000000..cbfc494021
--- /dev/null
+++ b/library/cpp/histogram/adaptive/adaptive_histogram.cpp
@@ -0,0 +1,637 @@
+#include "adaptive_histogram.h"
+
+#include <util/generic/algorithm.h>
+#include <util/generic/yexception.h>
+#include <util/generic/ymath.h>
+#include <util/string/printf.h>
+
+#include <util/system/backtrace.h>
+
+namespace NKiwiAggr {
+ TAdaptiveHistogram::TAdaptiveHistogram(size_t intervals, ui64 id, TQualityFunction qualityFunc)
+ : Id(id)
+ , Sum(0.0)
+ , Intervals(intervals)
+ , CalcQuality(qualityFunc)
+ {
+ }
+
+ TAdaptiveHistogram::TAdaptiveHistogram(const THistogram& histo, size_t defaultIntervals, ui64 defaultId, TQualityFunction qualityFunc)
+ : TAdaptiveHistogram(defaultIntervals, defaultId, qualityFunc)
+ {
+ FromProto(histo);
+ }
+
+ TAdaptiveHistogram::TAdaptiveHistogram(IHistogram* histo, size_t defaultIntervals, ui64 defaultId, TQualityFunction qualityFunc)
+ : TAdaptiveHistogram(defaultIntervals, defaultId, qualityFunc)
+ {
+ TAdaptiveHistogram* adaptiveHisto = dynamic_cast<TAdaptiveHistogram*>(histo);
+ if (!adaptiveHisto) {
+ FromIHistogram(histo);
+ return;
+ }
+ Id = adaptiveHisto->Id;
+ MinValue = adaptiveHisto->MinValue;
+ MaxValue = adaptiveHisto->MaxValue;
+ Sum = adaptiveHisto->Sum;
+ Intervals = adaptiveHisto->Intervals;
+ Bins = adaptiveHisto->Bins;
+ BinsByQuality = adaptiveHisto->BinsByQuality;
+ if (CalcQuality == nullptr) {
+ CalcQuality = adaptiveHisto->CalcQuality;
+ }
+ }
+
+ TQualityFunction TAdaptiveHistogram::GetQualityFunc() {
+ return CalcQuality;
+ }
+
+ void TAdaptiveHistogram::Clear() {
+ Sum = 0.0;
+ Bins.clear();
+ BinsByQuality.clear();
+ }
+
+ void TAdaptiveHistogram::Add(const THistoRec& histoRec) {
+ if (!histoRec.HasId() || histoRec.GetId() == Id) {
+ Add(histoRec.GetValue(), histoRec.GetWeight());
+ }
+ }
+
+ void TAdaptiveHistogram::Add(double value, double weight) {
+ if (!IsValidFloat(value) || !IsValidFloat(weight)) {
+ ythrow yexception() << Sprintf("Histogram id %lu: bad value %f weight %f", Id, value, weight);
+ }
+ TWeightedValue weightedValue(value, weight);
+ Add(weightedValue, true);
+ PrecomputedBins.clear();
+ }
+
+ void TAdaptiveHistogram::Merge(const THistogram& histo, double multiplier) {
+ if (!IsValidFloat(histo.GetMinValue()) || !IsValidFloat(histo.GetMaxValue())) {
+ fprintf(stderr, "Merging in histogram id %lu: skip bad histo with minvalue %f maxvalue %f\n", Id, histo.GetMinValue(), histo.GetMaxValue());
+ return;
+ }
+ if (histo.FreqSize() == 0) {
+ return; // skip empty histos
+ }
+ if (histo.GetType() == HT_ADAPTIVE_DISTANCE_HISTOGRAM ||
+ histo.GetType() == HT_ADAPTIVE_WEIGHT_HISTOGRAM ||
+ histo.GetType() == HT_ADAPTIVE_WARD_HISTOGRAM ||
+ histo.GetType() == HT_ADAPTIVE_HISTOGRAM)
+ {
+ Y_VERIFY(histo.FreqSize() == histo.PositionSize(), "Corrupted histo");
+ for (size_t j = 0; j < histo.FreqSize(); ++j) {
+ double value = histo.GetPosition(j);
+ double weight = histo.GetFreq(j);
+ if (!IsValidFloat(value) || !IsValidFloat(weight)) {
+ fprintf(stderr, "Merging in histogram id %lu: skip bad value %f weight %f\n", Id, value, weight);
+ continue;
+ }
+ Add(value, weight * multiplier);
+ }
+
+ MinValue = Min(MinValue, histo.GetMinValue());
+ MaxValue = Max(MaxValue, histo.GetMaxValue());
+ } else if (histo.GetType() == HT_FIXED_BIN_HISTOGRAM) {
+ double pos = histo.GetMinValue() + histo.GetBinRange() / 2.0;
+ for (size_t j = 0; j < histo.FreqSize(); ++j) {
+ double weight = histo.GetFreq(j);
+ if (!IsValidFloat(pos) || !IsValidFloat(weight)) {
+ fprintf(stderr, "Merging in histogram id %lu: skip bad value %f weight %f\n", Id, pos, weight);
+ pos += histo.GetBinRange();
+ continue;
+ }
+ Add(pos, weight * multiplier);
+ pos += histo.GetBinRange();
+ }
+
+ MinValue = Min(MinValue, histo.GetMinValue());
+ MaxValue = Max(MaxValue, histo.GetMaxValue());
+ } else {
+ ythrow yexception() << "Unknown THistogram type";
+ }
+ }
+
+ void TAdaptiveHistogram::Merge(const TVector<THistogram>& histogramsToMerge) {
+ for (size_t i = 0; i < histogramsToMerge.size(); ++i) {
+ Merge(histogramsToMerge[i], 1.0);
+ }
+ }
+
+ void TAdaptiveHistogram::Merge(TVector<IHistogramPtr> histogramsToMerge) {
+ TVector<IHistogramPtr> histogramsToMergeRepacked(0);
+ TVector<TAdaptiveHistogram*> histograms(0);
+ for (size_t i = 0; i < histogramsToMerge.size(); ++i) {
+ if (!histogramsToMerge[i] || histogramsToMerge[i]->Empty()) {
+ continue;
+ }
+ TAdaptiveHistogram* adaptiveHisto = dynamic_cast<TAdaptiveHistogram*>(histogramsToMerge[i].Get());
+ if (adaptiveHisto) {
+ histogramsToMergeRepacked.push_back(histogramsToMerge[i]);
+ } else {
+ histogramsToMergeRepacked.push_back(IHistogramPtr(new TAdaptiveHistogram(histogramsToMerge[i].Get(), Intervals, Id, CalcQuality))); // Convert histograms that are not of TFixedBinHistogram type
+ }
+ if (histogramsToMergeRepacked.back()->Empty()) {
+ continue;
+ }
+ histograms.push_back(dynamic_cast<TAdaptiveHistogram*>(histogramsToMergeRepacked.back().Get()));
+ }
+
+ if (histograms.size() == 0) {
+ return;
+ }
+
+ for (size_t histoIndex = 0; histoIndex < histograms.size(); ++histoIndex) {
+ TAdaptiveHistogram* histo = histograms[histoIndex];
+ for (TPairSet::const_iterator it = histo->Bins.begin(); it != histo->Bins.end(); ++it) {
+ Add(*it, true);
+ }
+ }
+
+ for (size_t i = 0; i < histograms.size(); ++i) {
+ MinValue = Min(MinValue, histograms[i]->MinValue);
+ MaxValue = Max(MaxValue, histograms[i]->MaxValue);
+ }
+ }
+
+ void TAdaptiveHistogram::Multiply(double factor) {
+ if (!IsValidFloat(factor) || factor <= 0) {
+ ythrow yexception() << "Not valid factor in IHistogram::Multiply(): " << factor;
+ }
+ Sum *= factor;
+
+ TPairSet newBins;
+ for (TPairSet::iterator it = Bins.begin(); it != Bins.end(); ++it) {
+ newBins.insert(TWeightedValue(it->first, it->second * factor));
+ }
+ Bins = newBins;
+
+ TPairSet newBinsByQuality;
+ for (TPairSet::iterator it = Bins.begin(); it != Bins.end(); ++it) {
+ TPairSet::iterator rightBin = it;
+ ++rightBin;
+ if (rightBin == Bins.end()) {
+ break;
+ }
+ newBinsByQuality.insert(CalcQuality(*it, *rightBin));
+ }
+ BinsByQuality = newBinsByQuality;
+ }
+
+ void TAdaptiveHistogram::FromProto(const THistogram& histo) {
+ Y_VERIFY(histo.HasType(), "Attempt to parse TAdaptiveHistogram from THistogram protobuf with no Type field set");
+ ;
+ switch (histo.GetType()) { // check that histogram type could be deduced
+ case HT_ADAPTIVE_DISTANCE_HISTOGRAM:
+ case HT_ADAPTIVE_WEIGHT_HISTOGRAM:
+ case HT_ADAPTIVE_WARD_HISTOGRAM:
+ break; // ok
+ case HT_ADAPTIVE_HISTOGRAM:
+ if (CalcQuality != nullptr)
+ break; // ok
+ [[fallthrough]];
+ default: // not ok
+ ythrow yexception() << "Attempt to parse TAdaptiveHistogram from THistogram protobuf record of type = " << (ui32)histo.GetType();
+ }
+
+ if (histo.FreqSize() != histo.PositionSize()) {
+ ythrow yexception() << "Attempt to parse TAdaptiveHistogram from THistogram protobuf record where FreqSize != PositionSize. FreqSize == " << (ui32)histo.FreqSize() << ", PositionSize == " << (ui32)histo.PositionSize();
+ }
+ if (CalcQuality == nullptr) {
+ if (histo.GetType() == HT_ADAPTIVE_DISTANCE_HISTOGRAM) {
+ CalcQuality = CalcDistanceQuality;
+ } else if (histo.GetType() == HT_ADAPTIVE_WEIGHT_HISTOGRAM) {
+ CalcQuality = CalcWeightQuality;
+ } else if (histo.GetType() == HT_ADAPTIVE_WARD_HISTOGRAM) {
+ CalcQuality = CalcWardQuality;
+ } else {
+ ythrow yexception() << "Attempt to parse an HT_ADAPTIVE_HISTOGRAM without default quality function";
+ }
+ }
+ Id = histo.GetId();
+ Sum = 0.0;
+ Intervals = Max(Intervals, histo.FreqSize());
+ for (size_t i = 0; i < histo.FreqSize(); ++i) {
+ double value = histo.GetPosition(i);
+ double weight = histo.GetFreq(i);
+ if (!IsValidFloat(value) || !IsValidFloat(weight)) {
+ fprintf(stderr, "FromProto in histogram id %lu: skip bad value %f weight %f\n", Id, value, weight);
+ continue;
+ }
+ Add(value, weight);
+ }
+
+ if (!IsValidFloat(histo.GetMinValue()) || !IsValidFloat(histo.GetMaxValue())) {
+ ythrow yexception() << Sprintf("FromProto in histogram id %lu: skip bad histo with minvalue %f maxvalue %f", Id, histo.GetMinValue(), histo.GetMaxValue());
+ }
+
+ MinValue = histo.GetMinValue();
+ MaxValue = histo.GetMaxValue();
+ }
+
+ void TAdaptiveHistogram::ToProto(THistogram& histo) {
+ histo.Clear();
+ if (CalcQuality == CalcDistanceQuality) {
+ histo.SetType(HT_ADAPTIVE_DISTANCE_HISTOGRAM);
+ } else if (CalcQuality == CalcWeightQuality) {
+ histo.SetType(HT_ADAPTIVE_WEIGHT_HISTOGRAM);
+ } else if (CalcQuality == CalcWardQuality) {
+ histo.SetType(HT_ADAPTIVE_WARD_HISTOGRAM);
+ } else {
+ histo.SetType(HT_ADAPTIVE_HISTOGRAM);
+ }
+ histo.SetId(Id);
+ if (Empty()) {
+ return;
+ }
+ histo.SetMinValue(MinValue);
+ histo.SetMaxValue(MaxValue);
+ for (TPairSet::const_iterator it = Bins.begin(); it != Bins.end(); ++it) {
+ histo.AddFreq(it->second);
+ histo.AddPosition(it->first);
+ }
+ }
+
+ void TAdaptiveHistogram::SetId(ui64 id) {
+ Id = id;
+ }
+
+ ui64 TAdaptiveHistogram::GetId() {
+ return Id;
+ }
+
+ bool TAdaptiveHistogram::Empty() {
+ return Bins.size() == 0;
+ }
+
+ double TAdaptiveHistogram::GetMinValue() {
+ return MinValue;
+ }
+
+ double TAdaptiveHistogram::GetMaxValue() {
+ return MaxValue;
+ }
+
+ double TAdaptiveHistogram::GetSum() {
+ return Sum;
+ }
+
+ double TAdaptiveHistogram::GetSumInRange(double leftBound, double rightBound) {
+ if (leftBound > rightBound) {
+ return 0.0;
+ }
+ return GetSumAboveBound(leftBound) + GetSumBelowBound(rightBound) - Sum;
+ }
+
+ double TAdaptiveHistogram::GetSumAboveBound(double bound) {
+ if (Empty()) {
+ return 0.0;
+ }
+ if (bound < MinValue) {
+ return Sum;
+ }
+ if (bound > MaxValue) {
+ return 0.0;
+ }
+
+ if (!PrecomputedBins.empty()) {
+ return GetSumAboveBoundImpl(
+ bound,
+ PrecomputedBins,
+ LowerBound(PrecomputedBins.begin(), PrecomputedBins.end(), TFastBin{bound, -1.0, 0, 0}),
+ [](const auto& it) { return it->SumAbove; });
+ } else {
+ return GetSumAboveBoundImpl(
+ bound,
+ Bins,
+ Bins.lower_bound(TWeightedValue(bound, -1.0)),
+ [this](TPairSet::const_iterator rightBin) {
+ ++rightBin;
+ double sum = 0;
+ for (TPairSet::const_iterator it = rightBin; it != Bins.end(); ++it) {
+ sum += it->second;
+ }
+ return sum;
+ });
+ }
+ }
+
+ double TAdaptiveHistogram::GetSumBelowBound(double bound) {
+ if (Empty()) {
+ return 0.0;
+ }
+ if (bound < MinValue) {
+ return 0.0;
+ }
+ if (bound > MaxValue) {
+ return Sum;
+ }
+
+ if (!PrecomputedBins.empty()) {
+ return GetSumBelowBoundImpl(
+ bound,
+ PrecomputedBins,
+ LowerBound(PrecomputedBins.begin(), PrecomputedBins.end(), TFastBin{bound, -1.0, 0, 0}),
+ [](const auto& it) { return it->SumBelow; });
+ } else {
+ return GetSumBelowBoundImpl(
+ bound,
+ Bins,
+ Bins.lower_bound(TWeightedValue(bound, -1.0)),
+ [this](TPairSet::const_iterator rightBin) {
+ double sum = 0;
+ for (TPairSet::iterator it = Bins.begin(); it != rightBin; ++it) {
+ sum += it->second;
+ }
+ return sum;
+ });
+ }
+ }
+
+ double TAdaptiveHistogram::CalcUpperBound(double sum) {
+ Y_VERIFY(sum >= 0, "Sum must be >= 0");
+ if (sum == 0.0) {
+ return MinValue;
+ }
+ if (Empty()) {
+ return MaxValue;
+ }
+ TPairSet::iterator current = Bins.begin();
+ double gatheredSum = 0.0;
+ while (current != Bins.end() && gatheredSum < sum) {
+ gatheredSum += current->second;
+ ++current;
+ }
+ --current;
+ if (gatheredSum < sum) {
+ return MaxValue;
+ }
+ TWeightedValue left(MinValue, 0.0);
+ TWeightedValue right(MaxValue, 0.0);
+ if (current != Bins.begin()) {
+ TPairSet::iterator leftBin = current;
+ --leftBin;
+ left = *leftBin;
+ }
+ {
+ TPairSet::iterator rightBin = current;
+ ++rightBin;
+ if (rightBin != Bins.end()) {
+ right = *rightBin;
+ }
+ }
+ double sumToAdd = sum - (gatheredSum - current->second - left.second / 2);
+ if (sumToAdd <= ((current->second + left.second) / 2)) {
+ return left.first + 2 * sumToAdd * (current->first - left.first) / (current->second + left.second);
+ } else {
+ sumToAdd -= (current->second + left.second) / 2;
+ return current->first + 2 * sumToAdd * (right.first - current->first) / (right.second + current->second);
+ }
+ }
+
+ double TAdaptiveHistogram::CalcLowerBound(double sum) {
+ Y_VERIFY(sum >= 0, "Sum must be >= 0");
+ if (sum == 0.0) {
+ return MaxValue;
+ }
+ if (Empty()) {
+ return MinValue;
+ }
+ TPairSet::iterator current = Bins.end();
+ double gatheredSum = 0.0;
+ while (current != Bins.begin() && gatheredSum < sum) {
+ --current;
+ gatheredSum += current->second;
+ }
+ if (gatheredSum < sum) {
+ return MinValue;
+ }
+ TWeightedValue left(MinValue, 0.0);
+ TWeightedValue right(MaxValue, 0.0);
+ if (current != Bins.begin()) {
+ TPairSet::iterator leftBin = current;
+ --leftBin;
+ left = *leftBin;
+ }
+ {
+ TPairSet::iterator rightBin = current;
+ ++rightBin;
+ if (rightBin != Bins.end()) {
+ right = *rightBin;
+ }
+ }
+ double sumToAdd = sum - (gatheredSum - current->second - right.second / 2);
+ if (sumToAdd <= ((current->second + right.second) / 2)) {
+ return right.first - 2 * sumToAdd * (right.first - current->first) / (current->second + right.second);
+ } else {
+ sumToAdd -= (current->second + right.second) / 2;
+ return current->first - 2 * sumToAdd * (current->first - left.first) / (left.second + current->second);
+ }
+ }
+
+ double TAdaptiveHistogram::CalcUpperBoundSafe(double sum) {
+ if (!Empty()) {
+ sum = Max(Bins.begin()->second, sum);
+ }
+ return CalcUpperBound(sum);
+ }
+
+ double TAdaptiveHistogram::CalcLowerBoundSafe(double sum) {
+ if (!Empty()) {
+ sum = Max(Bins.rbegin()->second, sum);
+ }
+ return CalcLowerBound(sum);
+ }
+
+ void TAdaptiveHistogram::FromIHistogram(IHistogram* histo) {
+ if (!histo) {
+ ythrow yexception() << "Attempt to create TAdaptiveHistogram from a NULL pointer";
+ }
+ if (CalcQuality == CalcWardQuality) {
+ ythrow yexception() << "Not implemented";
+ } else if (CalcQuality != CalcDistanceQuality && CalcQuality != CalcWeightQuality) {
+ ythrow yexception() << "Attempt to create TAdaptiveHistogram from a pointer without default CalcQuality";
+ }
+ Id = histo->GetId();
+ if (histo->Empty()) {
+ return;
+ }
+ double sum = histo->GetSum();
+ double minValue = histo->GetMinValue();
+ double maxValue = histo->GetMaxValue();
+ if (minValue == maxValue) {
+ Add(minValue, sum);
+ return;
+ }
+ if (CalcQuality == CalcDistanceQuality) {
+ double binRange = (maxValue - minValue) / (Intervals);
+ for (size_t i = 0; i < Intervals; ++i) {
+ Add(minValue + binRange * (i + 0.5), histo->GetSumInRange(minValue + binRange * i, minValue + binRange * (i + 1)));
+ }
+ } else if (CalcQuality == CalcWeightQuality && sum != 0.0) {
+ double slab = sum / Intervals;
+ double prevBound = minValue;
+ for (size_t i = 0; i < Intervals; ++i) {
+ double bound = histo->CalcUpperBound(slab * (i + 1));
+ Add((bound + prevBound) / 2, slab);
+ prevBound = bound;
+ }
+ }
+ MinValue = minValue;
+ MaxValue = maxValue;
+ }
+
+ void TAdaptiveHistogram::Add(const TWeightedValue& weightedValue, bool initial) {
+ const double& value = weightedValue.first;
+ const double& weight = weightedValue.second;
+ if (weight <= 0.0) {
+ return; // all zero-weighted values should be skipped because they don't affect the distribution, negative weights are forbidden
+ }
+ if (initial) {
+ Sum += weight;
+ }
+ if (Bins.size() == 0) {
+ MinValue = value;
+ MaxValue = value;
+ Bins.insert(weightedValue);
+ return;
+ }
+ if (value < MinValue) {
+ MinValue = value;
+ }
+ if (value > MaxValue) {
+ MaxValue = value;
+ }
+ TPairSet::iterator rightBin = Bins.lower_bound(TWeightedValue(value, -1.0));
+ if (rightBin != Bins.end() && rightBin->first == value) {
+ TPairSet::iterator currentBin = rightBin;
+ ++rightBin;
+ TWeightedValue newBin(value, weight + currentBin->second);
+ if (rightBin != Bins.end()) {
+ Y_VERIFY(BinsByQuality.erase(CalcQuality(*currentBin, *rightBin)) == 1, "Erase failed");
+ BinsByQuality.insert(CalcQuality(newBin, *rightBin));
+ }
+ if (currentBin != Bins.begin()) {
+ TPairSet::iterator leftBin = currentBin;
+ --leftBin;
+ Y_VERIFY(BinsByQuality.erase(CalcQuality(*leftBin, *currentBin)) == 1, "Erase failed");
+ BinsByQuality.insert(CalcQuality(*leftBin, newBin));
+ }
+ Bins.erase(currentBin);
+ Bins.insert(newBin);
+ return;
+ }
+ if (rightBin == Bins.begin()) {
+ BinsByQuality.insert(CalcQuality(weightedValue, *rightBin));
+ } else {
+ TPairSet::iterator leftBin = rightBin;
+ --leftBin;
+ if (rightBin == Bins.end()) {
+ BinsByQuality.insert(CalcQuality(*leftBin, weightedValue));
+ } else {
+ Y_VERIFY(BinsByQuality.erase(CalcQuality(*leftBin, *rightBin)) == 1, "Erase failed");
+ BinsByQuality.insert(CalcQuality(*leftBin, weightedValue));
+ BinsByQuality.insert(CalcQuality(weightedValue, *rightBin));
+ }
+ }
+ Bins.insert(weightedValue);
+ if (Bins.size() > Intervals) {
+ Shrink();
+ }
+ }
+
+ void TAdaptiveHistogram::Erase(double value) {
+ TPairSet::iterator currentBin = Bins.lower_bound(TWeightedValue(value, -1.0));
+ Y_VERIFY(currentBin != Bins.end() && currentBin->first == value, "Can't find bin that should be erased");
+ TPairSet::iterator rightBin = currentBin;
+ ++rightBin;
+ if (currentBin == Bins.begin()) {
+ Y_VERIFY(rightBin != Bins.end(), "No right bin for the first bin");
+ Y_VERIFY(BinsByQuality.erase(CalcQuality(*currentBin, *rightBin)) != 0, "Erase failed");
+ } else {
+ TPairSet::iterator leftBin = currentBin;
+ --leftBin;
+ if (rightBin == Bins.end()) {
+ Y_VERIFY(BinsByQuality.erase(CalcQuality(*leftBin, *currentBin)) != 0, "Erase failed");
+ } else {
+ Y_VERIFY(BinsByQuality.erase(CalcQuality(*leftBin, *currentBin)) != 0, "Erase failed");
+ Y_VERIFY(BinsByQuality.erase(CalcQuality(*currentBin, *rightBin)) != 0, "Erase failed");
+ BinsByQuality.insert(CalcQuality(*leftBin, *rightBin));
+ }
+ }
+ Bins.erase(currentBin);
+ }
+
+ void TAdaptiveHistogram::Shrink() {
+ TPairSet::iterator worstBin = BinsByQuality.begin();
+ Y_VERIFY(worstBin != BinsByQuality.end(), "No right bin for the first bin");
+ TPairSet::iterator leftBin = Bins.lower_bound(TWeightedValue(worstBin->second, -1.0));
+ Y_VERIFY(leftBin != Bins.end() && leftBin->first == worstBin->second, "Can't find worst bin");
+ TPairSet::iterator rightBin = leftBin;
+ ++rightBin;
+ Y_VERIFY(rightBin != Bins.end(), "Can't find right bin");
+
+ TWeightedValue newBin((leftBin->first * leftBin->second + rightBin->first * rightBin->second) / (leftBin->second + rightBin->second), leftBin->second + rightBin->second);
+ if (Bins.size() > 2) {
+ Erase(leftBin->first);
+ Erase(rightBin->first);
+ } else {
+ Bins.clear();
+ BinsByQuality.clear();
+ }
+ Add(newBin, false);
+ }
+
+ void TAdaptiveHistogram::PrecomputePartialSums() {
+ PrecomputedBins.clear();
+ PrecomputedBins.reserve(Bins.size());
+ double currentSum = 0;
+ for (const auto& bin : Bins) {
+ PrecomputedBins.emplace_back(bin.first, bin.second, currentSum, Sum - currentSum - bin.second);
+ currentSum += bin.second;
+ }
+ }
+
+ template <typename TBins, typename TGetSumAbove>
+ double TAdaptiveHistogram::GetSumAboveBoundImpl(double bound, const TBins& bins, typename TBins::const_iterator rightBin, const TGetSumAbove& getSumAbove) const {
+ typename TBins::value_type left(MinValue, 0.0);
+ typename TBins::value_type right(MaxValue, 0.0);
+ if (rightBin != bins.end()) {
+ right = *rightBin;
+ }
+ if (rightBin != bins.begin()) {
+ typename TBins::const_iterator leftBin = rightBin;
+ --leftBin;
+ left = *leftBin;
+ }
+ double sum = (right.second / 2) + ((right.first == left.first) ? ((left.second + right.second) / 2) : (((left.second + right.second) / 2) * (right.first - bound) / (right.first - left.first)));
+ if (rightBin == bins.end()) {
+ return sum;
+ }
+ sum += getSumAbove(rightBin);
+ return sum;
+ }
+
+ template <typename TBins, typename TGetSumBelow>
+ double TAdaptiveHistogram::GetSumBelowBoundImpl(double bound, const TBins& bins, typename TBins::const_iterator rightBin, const TGetSumBelow& getSumBelow) const {
+ typename TBins::value_type left(MinValue, 0.0);
+ typename TBins::value_type right(MaxValue, 0.0);
+ if (rightBin != bins.end()) {
+ right = *rightBin;
+ }
+ if (rightBin != bins.begin()) {
+ typename TBins::const_iterator leftBin = rightBin;
+ --leftBin;
+ left = *leftBin;
+ }
+ double sum = (left.second / 2) + ((right.first == left.first) ? ((left.second + right.second) / 2) : (((left.second + right.second) / 2) * (bound - left.first) / (right.first - left.first)));
+ if (rightBin == bins.begin()) {
+ return sum;
+ }
+ --rightBin;
+ sum += getSumBelow(rightBin);
+ return sum;
+ }
+
+}
diff --git a/library/cpp/histogram/adaptive/adaptive_histogram.h b/library/cpp/histogram/adaptive/adaptive_histogram.h
new file mode 100644
index 0000000000..fa8f48433f
--- /dev/null
+++ b/library/cpp/histogram/adaptive/adaptive_histogram.h
@@ -0,0 +1,131 @@
+#pragma once
+
+#include "histogram.h"
+#include "common.h"
+
+#include <library/cpp/histogram/adaptive/protos/histo.pb.h>
+
+#include <util/generic/ptr.h>
+#include <util/generic/set.h>
+#include <util/generic/vector.h>
+
+namespace NKiwiAggr {
+ class TAdaptiveHistogram: private TNonCopyable, public IHistogram {
+ protected:
+ static const size_t DEFAULT_INTERVALS = 100;
+
+ private:
+ using TPairSet = TSet<TWeightedValue>;
+
+ struct TFastBin {
+ // these names are for compatibility with TWeightedValue
+ double first;
+ double second;
+ // both sums do not include current bin
+ double SumBelow;
+ double SumAbove;
+
+ TFastBin(double first_, double second_, double sumBelow = 0, double sumAbove = 0)
+ : first(first_)
+ , second(second_)
+ , SumBelow(sumBelow)
+ , SumAbove(sumAbove)
+ {
+ }
+
+ bool operator<(const TFastBin& rhs) const {
+ return first < rhs.first;
+ }
+ };
+
+ ui64 Id;
+ double MinValue;
+ double MaxValue;
+ double Sum;
+ size_t Intervals;
+ TPairSet Bins;
+ TPairSet BinsByQuality;
+ TQualityFunction CalcQuality;
+
+ TVector<TFastBin> PrecomputedBins;
+
+ public:
+ TAdaptiveHistogram(size_t intervals, ui64 id = 0, TQualityFunction qualityFunc = CalcWeightQuality);
+ TAdaptiveHistogram(const THistogram& histo, size_t defaultIntervals = DEFAULT_INTERVALS, ui64 defaultId = 0, TQualityFunction qualityFunc = nullptr);
+ TAdaptiveHistogram(IHistogram* histo, size_t defaultIntervals = DEFAULT_INTERVALS, ui64 defaultId = 0, TQualityFunction qualityFunc = CalcWeightQuality);
+
+ ~TAdaptiveHistogram() override {
+ }
+
+ TQualityFunction GetQualityFunc();
+
+ void Clear() override;
+
+ void Add(double value, double weight) override;
+ void Add(const THistoRec& histoRec) override;
+
+ void Merge(const THistogram& histo, double multiplier) final;
+ void Merge(const TVector<THistogram>& histogramsToMerge) final;
+ void Merge(TVector<IHistogramPtr> histogramsToMerge) final;
+
+ void Multiply(double factor) final;
+
+ void FromProto(const THistogram& histo) final;
+ void ToProto(THistogram& histo) final;
+
+ void SetId(ui64 id) final;
+ ui64 GetId() final;
+ bool Empty() final;
+ double GetMinValue() final;
+ double GetMaxValue() final;
+ double GetSum() final;
+ double GetSumInRange(double leftBound, double rightBound) final;
+ double GetSumAboveBound(double bound) final;
+ double GetSumBelowBound(double bound) final;
+ double CalcUpperBound(double sum) final;
+ double CalcLowerBound(double sum) final;
+ double CalcUpperBoundSafe(double sum) final;
+ double CalcLowerBoundSafe(double sum) final;
+
+ void PrecomputePartialSums() final;
+
+ private:
+ void FromIHistogram(IHistogram* histo);
+ void Add(const TWeightedValue& weightedValue, bool initial);
+ void Erase(double value);
+ void Shrink();
+
+ template <typename TBins, typename TGetSumAbove>
+ double GetSumAboveBoundImpl(double bound, const TBins& bins, typename TBins::const_iterator rightBin, const TGetSumAbove& getSumAbove) const;
+
+ template <typename TBins, typename TGetSumBelow>
+ double GetSumBelowBoundImpl(double bound, const TBins& bins, typename TBins::const_iterator rightBin, const TGetSumBelow& getSumBelow) const;
+ };
+
+ template <TQualityFunction QualityFunction>
+ class TDefinedAdaptiveHistogram: public TAdaptiveHistogram {
+ public:
+ TDefinedAdaptiveHistogram(size_t intervals, ui64 id = 0)
+ : TAdaptiveHistogram(intervals, id, QualityFunction)
+ {
+ }
+
+ TDefinedAdaptiveHistogram(const THistogram& histo, size_t defaultIntervals = DEFAULT_INTERVALS, ui64 defaultId = 0)
+ : TAdaptiveHistogram(histo, defaultIntervals, defaultId, QualityFunction)
+ {
+ }
+
+ TDefinedAdaptiveHistogram(IHistogram* histo, size_t defaultIntervals = DEFAULT_INTERVALS, ui64 defaultId = 0)
+ : TAdaptiveHistogram(histo, defaultIntervals, defaultId, QualityFunction)
+ {
+ }
+
+ ~TDefinedAdaptiveHistogram() override {
+ }
+ };
+
+ typedef TDefinedAdaptiveHistogram<CalcDistanceQuality> TAdaptiveDistanceHistogram;
+ typedef TDefinedAdaptiveHistogram<CalcWeightQuality> TAdaptiveWeightHistogram;
+ typedef TDefinedAdaptiveHistogram<CalcWardQuality> TAdaptiveWardHistogram;
+
+}
diff --git a/library/cpp/histogram/adaptive/auto_histogram.h b/library/cpp/histogram/adaptive/auto_histogram.h
new file mode 100644
index 0000000000..9fdf0b9abe
--- /dev/null
+++ b/library/cpp/histogram/adaptive/auto_histogram.h
@@ -0,0 +1,148 @@
+#pragma once
+
+#include "adaptive_histogram.h"
+#include "fixed_bin_histogram.h"
+#include "histogram.h"
+
+#include <library/cpp/histogram/adaptive/protos/histo.pb.h>
+
+#include <util/generic/ptr.h>
+#include <util/generic/yexception.h>
+
+namespace NKiwiAggr {
+ class TAutoHistogram: private TNonCopyable, public IHistogram {
+ private:
+ static const size_t DEFAULT_INTERVALS = 100;
+
+ ui64 Id;
+ size_t Intervals;
+ THolder<IHistogram> HistogramImpl;
+
+ public:
+ TAutoHistogram(size_t intervals, ui64 id = 0) {
+ Y_UNUSED(intervals);
+ Y_UNUSED(id);
+ ythrow yexception() << "Empty constructor is not defined for TAutoHistogram";
+ }
+
+ TAutoHistogram(const THistogram& histo, size_t defaultIntervals = DEFAULT_INTERVALS, ui64 defaultId = 0)
+ : Id(defaultId)
+ , Intervals(defaultIntervals)
+ {
+ FromProto(histo);
+ }
+
+ TAutoHistogram(IHistogram* histo, size_t defaultIntervals = DEFAULT_INTERVALS, ui64 defaultId = 0) {
+ Y_UNUSED(histo);
+ Y_UNUSED(defaultIntervals);
+ Y_UNUSED(defaultId);
+ ythrow yexception() << "IHistogram constructor is not defined for TAutoHistogram";
+ }
+
+ virtual ~TAutoHistogram() {
+ }
+
+ virtual void Clear() {
+ HistogramImpl->Clear();
+ }
+
+ virtual void Add(double value, double weight) {
+ HistogramImpl->Add(value, weight);
+ }
+
+ virtual void Add(const THistoRec& histoRec) {
+ HistogramImpl->Add(histoRec);
+ }
+
+ virtual void Merge(const THistogram& histo, double multiplier) {
+ HistogramImpl->Merge(histo, multiplier);
+ }
+
+ virtual void Merge(const TVector<THistogram>& histogramsToMerge) {
+ HistogramImpl->Merge(histogramsToMerge);
+ }
+
+ virtual void Merge(TVector<IHistogramPtr> histogramsToMerge) {
+ HistogramImpl->Merge(histogramsToMerge);
+ }
+
+ virtual void Multiply(double factor) {
+ HistogramImpl->Multiply(factor);
+ }
+
+ virtual void FromProto(const THistogram& histo) {
+ if (!histo.HasType() || histo.GetType() == HT_FIXED_BIN_HISTOGRAM) {
+ HistogramImpl.Reset(new TFixedBinHistogram(histo, Intervals, Id));
+ } else if (histo.GetType() == HT_ADAPTIVE_DISTANCE_HISTOGRAM) {
+ HistogramImpl.Reset(new TAdaptiveDistanceHistogram(histo, Intervals, Id));
+ } else if (histo.GetType() == HT_ADAPTIVE_WEIGHT_HISTOGRAM) {
+ HistogramImpl.Reset(new TAdaptiveWeightHistogram(histo, Intervals, Id));
+ } else if (histo.GetType() == HT_ADAPTIVE_WARD_HISTOGRAM) {
+ HistogramImpl.Reset(new TAdaptiveWardHistogram(histo, Intervals, Id));
+ } else {
+ ythrow yexception() << "Can't parse TAutoHistogram from a THistogram of type " << (ui32)histo.GetType();
+ }
+ }
+
+ virtual void ToProto(THistogram& histo) {
+ HistogramImpl->ToProto(histo);
+ }
+
+ virtual void SetId(ui64 id) {
+ HistogramImpl->SetId(id);
+ }
+
+ virtual ui64 GetId() {
+ return HistogramImpl->GetId();
+ }
+
+ virtual bool Empty() {
+ return HistogramImpl->Empty();
+ }
+
+ virtual double GetMinValue() {
+ return HistogramImpl->GetMinValue();
+ }
+
+ virtual double GetMaxValue() {
+ return HistogramImpl->GetMaxValue();
+ }
+
+ virtual double GetSum() {
+ return HistogramImpl->GetSum();
+ }
+
+ virtual double GetSumInRange(double leftBound, double rightBound) {
+ return HistogramImpl->GetSumInRange(leftBound, rightBound);
+ }
+
+ virtual double GetSumAboveBound(double bound) {
+ return HistogramImpl->GetSumAboveBound(bound);
+ }
+
+ virtual double GetSumBelowBound(double bound) {
+ return HistogramImpl->GetSumBelowBound(bound);
+ }
+
+ virtual double CalcUpperBound(double sum) {
+ return HistogramImpl->CalcUpperBound(sum);
+ }
+
+ virtual double CalcLowerBound(double sum) {
+ return HistogramImpl->CalcLowerBound(sum);
+ }
+
+ virtual double CalcUpperBoundSafe(double sum) {
+ return HistogramImpl->CalcUpperBoundSafe(sum);
+ }
+
+ virtual double CalcLowerBoundSafe(double sum) {
+ return HistogramImpl->CalcLowerBoundSafe(sum);
+ }
+
+ virtual void PrecomputePartialSums() {
+ return HistogramImpl->PrecomputePartialSums();
+ }
+ };
+
+}
diff --git a/library/cpp/histogram/adaptive/block_histogram.cpp b/library/cpp/histogram/adaptive/block_histogram.cpp
new file mode 100644
index 0000000000..6586d13ff6
--- /dev/null
+++ b/library/cpp/histogram/adaptive/block_histogram.cpp
@@ -0,0 +1,593 @@
+#include "block_histogram.h"
+
+#include <library/cpp/histogram/adaptive/protos/histo.pb.h>
+
+#include <util/generic/algorithm.h>
+#include <util/generic/yexception.h>
+#include <util/generic/intrlist.h>
+#include <util/generic/ptr.h>
+#include <util/generic/queue.h>
+#include <util/generic/ymath.h>
+#include <util/string/printf.h>
+
+namespace {
+ struct TEmpty {
+ };
+
+ class TSmartHeap {
+ private:
+ TVector<ui32> A;
+ TVector<ui32> Pos;
+ const TVector<double>& Weights;
+
+ public:
+ TSmartHeap(const TVector<double>& weights)
+ : A(weights.size())
+ , Pos(weights.size())
+ , Weights(weights)
+ {
+ for (ui32 i = 0; i < weights.size(); ++i) {
+ A[i] = i;
+ Pos[i] = i;
+ }
+ for (ui32 i = weights.size() / 2; i > 0; --i) {
+ Down(i - 1);
+ }
+ }
+
+ ui32 IdOfMin() {
+ return A[0];
+ }
+
+ void Pop() {
+ A[0] = A.back();
+ Pos[A[0]] = 0;
+ A.pop_back();
+ Down(0);
+ }
+
+ void DownElement(ui32 id) {
+ Down(Pos[id]);
+ }
+
+ private:
+ void SwapPositions(ui32 x, ui32 y) {
+ std::swap(A[x], A[y]);
+ Pos[A[x]] = x;
+ Pos[A[y]] = y;
+ }
+
+ void Down(ui32 pos) {
+ while (1) {
+ ui32 left = pos * 2 + 1;
+ ui32 right = pos * 2 + 2;
+ ui32 min = pos;
+ if (left < A.size() && Weights[A[min]] > Weights[A[left]])
+ min = left;
+ if (right < A.size() && Weights[A[min]] > Weights[A[right]])
+ min = right;
+ if (pos == min)
+ break;
+ SwapPositions(min, pos);
+ pos = min;
+ }
+ }
+ };
+
+}
+
+namespace NKiwiAggr {
+ ///////////////////
+ // TBlockHistogram
+ ///////////////////
+
+ TBlockHistogram::TBlockHistogram(EHistogramType type, TQualityFunction calcQuality,
+ size_t intervals, ui64 id, size_t shrinkSize)
+ : Type(type)
+ , CalcQuality(calcQuality)
+ , Intervals(intervals)
+ , ShrinkSize(shrinkSize)
+ , PrevSize(0)
+ , Id(id)
+ , Sum(0)
+ , MinValue(0)
+ , MaxValue(0)
+ {
+ CorrectShrinkSize();
+ }
+
+ void TBlockHistogram::Clear() {
+ PrevSize = 0;
+ Sum = 0.0;
+ MinValue = 0.0;
+ MaxValue = 0.0;
+ Bins.clear();
+ }
+
+ void TBlockHistogram::Add(const THistoRec& rec) {
+ if (!rec.HasId() || rec.GetId() == Id) {
+ Add(rec.GetValue(), rec.GetWeight());
+ }
+ }
+
+ void TBlockHistogram::Add(double value, double weight) {
+ if (!IsValidFloat(value) || !IsValidFloat(weight)) {
+ ythrow yexception() << Sprintf("Histogram id %lu: bad value %f weight %f", Id, value, weight);
+ }
+
+ if (weight <= 0.0) {
+ return; // all zero-weighted values should be skipped because they don't affect the distribution, negative weights are forbidden
+ }
+
+ if (Bins.empty()) {
+ MinValue = value;
+ MaxValue = value;
+ } else {
+ MinValue = Min(MinValue, value);
+ MaxValue = Max(MaxValue, value);
+ }
+
+ Sum += weight;
+
+ if (Bins.size() > ShrinkSize) {
+ SortAndShrink(Intervals * SHRINK_MULTIPLIER);
+ }
+
+ Bins.push_back(TWeightedValue(value, weight));
+ }
+
+ void TBlockHistogram::Merge(const THistogram& histo, double multiplier) {
+ if (!IsValidFloat(histo.GetMinValue()) || !IsValidFloat(histo.GetMaxValue())) {
+ fprintf(stderr, "Merging in histogram id %lu: skip bad histo with minvalue %f maxvalue %f\n", Id, histo.GetMinValue(), histo.GetMaxValue());
+ return;
+ }
+ if (histo.FreqSize() == 0) {
+ return; // skip empty histos
+ }
+ if (histo.GetType() == HT_ADAPTIVE_DISTANCE_HISTOGRAM ||
+ histo.GetType() == HT_ADAPTIVE_WEIGHT_HISTOGRAM ||
+ histo.GetType() == HT_ADAPTIVE_WARD_HISTOGRAM ||
+ histo.GetType() == HT_ADAPTIVE_HISTOGRAM)
+ {
+ Y_VERIFY(histo.FreqSize() == histo.PositionSize(), "Corrupted histo");
+ for (size_t j = 0; j < histo.FreqSize(); ++j) {
+ double value = histo.GetPosition(j);
+ double weight = histo.GetFreq(j);
+ if (!IsValidFloat(value) || !IsValidFloat(weight)) {
+ fprintf(stderr, "Merging in histogram id %lu: skip bad value %f weight %f\n", Id, value, weight);
+ continue;
+ }
+ Add(value, weight * multiplier);
+ }
+
+ MinValue = Min(MinValue, histo.GetMinValue());
+ MaxValue = Max(MaxValue, histo.GetMaxValue());
+ } else if (histo.GetType() == HT_FIXED_BIN_HISTOGRAM) {
+ double pos = histo.GetMinValue() + histo.GetBinRange() / 2.0;
+ for (size_t j = 0; j < histo.FreqSize(); ++j) {
+ double weight = histo.GetFreq(j);
+ if (!IsValidFloat(pos) || !IsValidFloat(weight)) {
+ fprintf(stderr, "Merging in histogram id %lu: skip bad value %f weight %f\n", Id, pos, weight);
+ pos += histo.GetBinRange();
+ continue;
+ }
+ Add(pos, weight * multiplier);
+ pos += histo.GetBinRange();
+ }
+
+ MinValue = Min(MinValue, histo.GetMinValue());
+ MaxValue = Max(MaxValue, histo.GetMaxValue());
+ } else {
+ ythrow yexception() << "Unknown THistogram type";
+ }
+ }
+
+ void TBlockHistogram::Merge(const TVector<THistogram>& histogramsToMerge) {
+ for (size_t i = 0; i < histogramsToMerge.size(); ++i) {
+ Merge(histogramsToMerge[i], 1.0);
+ }
+ }
+
+ void TBlockHistogram::Merge(TVector<IHistogramPtr> histogramsToMerge) {
+ Y_UNUSED(histogramsToMerge);
+ ythrow yexception() << "IHistogram::Merge(TVector<IHistogramPtr>) is not defined for TBlockHistogram";
+ }
+
+ void TBlockHistogram::Multiply(double factor) {
+ if (!IsValidFloat(factor) || factor <= 0) {
+ ythrow yexception() << "Not valid factor in IHistogram::Multiply(): " << factor;
+ }
+ Sum *= factor;
+ for (TVector<TWeightedValue>::iterator it = Bins.begin(); it != Bins.end(); ++it) {
+ it->second *= factor;
+ }
+ }
+
+ void TBlockHistogram::FromProto(const THistogram& histo) {
+ Y_VERIFY(histo.HasType(), "Attempt to parse TBlockHistogram from THistogram protobuf with no Type field set");
+ ;
+ switch (histo.GetType()) { // check that histogram type is correct
+ case HT_ADAPTIVE_DISTANCE_HISTOGRAM:
+ case HT_ADAPTIVE_WEIGHT_HISTOGRAM:
+ case HT_ADAPTIVE_WARD_HISTOGRAM:
+ case HT_ADAPTIVE_HISTOGRAM:
+ break; // ok
+ default: // not ok
+ ythrow yexception() << "Attempt to parse TBlockHistogram from THistogram protobuf record of type = " << (ui32)histo.GetType();
+ }
+
+ if (histo.FreqSize() != histo.PositionSize()) {
+ ythrow yexception() << "Attempt to parse TBlockHistogram from THistogram protobuf record where FreqSize != PositionSize. FreqSize == " << (ui32)histo.FreqSize() << ", PositionSize == " << (ui32)histo.PositionSize();
+ }
+ Id = histo.GetId();
+ Sum = 0;
+ Intervals = Max(Intervals, histo.FreqSize());
+ CorrectShrinkSize();
+ Bins.resize(histo.FreqSize());
+ PrevSize = Bins.size();
+ for (size_t i = 0; i < histo.FreqSize(); ++i) {
+ double value = histo.GetPosition(i);
+ double weight = histo.GetFreq(i);
+ if (!IsValidFloat(value) || !IsValidFloat(weight)) {
+ fprintf(stderr, "FromProto in histogram id %lu: skip bad value %f weight %f\n", Id, value, weight);
+ continue;
+ }
+ Bins[i].first = value;
+ Bins[i].second = weight;
+ Sum += Bins[i].second;
+ }
+
+ if (!IsValidFloat(histo.GetMinValue()) || !IsValidFloat(histo.GetMaxValue())) {
+ ythrow yexception() << Sprintf("FromProto in histogram id %lu: skip bad histo with minvalue %f maxvalue %f", Id, histo.GetMinValue(), histo.GetMaxValue());
+ }
+ MinValue = histo.GetMinValue();
+ MaxValue = histo.GetMaxValue();
+ }
+
+ void TBlockHistogram::ToProto(THistogram& histo) {
+ histo.Clear();
+ histo.SetType(Type);
+ histo.SetId(Id);
+ if (Empty()) {
+ return;
+ }
+
+ SortAndShrink(Intervals, true);
+ histo.SetMinValue(MinValue);
+ histo.SetMaxValue(MaxValue);
+ for (TVector<TWeightedValue>::const_iterator it = Bins.begin(); it != Bins.end(); ++it) {
+ histo.AddFreq(it->second);
+ histo.AddPosition(it->first);
+ }
+ }
+
+ void TBlockHistogram::SetId(ui64 id) {
+ Id = id;
+ }
+
+ ui64 TBlockHistogram::GetId() {
+ return Id;
+ }
+
+ bool TBlockHistogram::Empty() {
+ return Bins.empty();
+ }
+
+ double TBlockHistogram::GetMinValue() {
+ return MinValue;
+ }
+
+ double TBlockHistogram::GetMaxValue() {
+ return MaxValue;
+ }
+
+ double TBlockHistogram::GetSum() {
+ return Sum;
+ }
+
+ void TBlockHistogram::SortAndShrink(size_t intervals, bool final) {
+ Y_VERIFY(intervals > 0);
+
+ if (Bins.size() <= intervals) {
+ return;
+ }
+
+ if (Bins.size() >= Intervals * GREEDY_SHRINK_MULTIPLIER) {
+ SortBins();
+ UniquifyBins();
+ FastGreedyShrink(intervals);
+
+ if (final) {
+ SlowShrink(intervals);
+ }
+
+ } else {
+ SortBins();
+ UniquifyBins();
+ SlowShrink(intervals);
+ }
+ }
+
+ void TBlockHistogram::SortBins() {
+ Sort(Bins.begin() + PrevSize, Bins.end());
+ if (PrevSize != 0) {
+ TVector<TWeightedValue> temp(Bins.begin(), Bins.begin() + PrevSize);
+ std::merge(temp.begin(), temp.end(), Bins.begin() + PrevSize, Bins.end(), Bins.begin());
+ }
+ }
+
+ void TBlockHistogram::UniquifyBins() {
+ if (Bins.empty())
+ return;
+
+ auto it1 = Bins.begin();
+ auto it2 = Bins.begin();
+ while (++it2 != Bins.end()) {
+ if (it1->first == it2->first) {
+ it1->second += it2->second;
+ } else {
+ *(++it1) = *it2;
+ }
+ }
+
+ Bins.erase(++it1, Bins.end());
+ }
+
+ void TBlockHistogram::CorrectShrinkSize() {
+ ShrinkSize = Max(ShrinkSize, Intervals * (SHRINK_MULTIPLIER + GREEDY_SHRINK_MULTIPLIER));
+ }
+
+ void TBlockHistogram::SlowShrink(size_t intervals) {
+ {
+ size_t pos = 0;
+ for (size_t i = 1; i < Bins.size(); ++i)
+ if (Bins[i].first - Bins[pos].first < 1e-9) {
+ Bins[pos].second += Bins[i].second;
+ } else {
+ ++pos;
+ Bins[pos] = Bins[i];
+ }
+ Bins.resize(pos + 1);
+ PrevSize = pos + 1;
+ }
+
+ if (Bins.size() <= intervals) {
+ return;
+ }
+
+ typedef TIntrusiveListItem<TEmpty> TListItem;
+
+ ui32 n = Bins.size() - 1;
+ const ui32 end = (ui32)Bins.size();
+
+ TArrayHolder<TListItem> listElementsHolder(new TListItem[end + 1]);
+ TListItem* const bins = listElementsHolder.Get();
+
+ for (ui32 i = 1; i <= end; ++i) {
+ bins[i].LinkAfter(&bins[i - 1]);
+ }
+
+ TVector<double> pairWeights(n);
+
+ for (ui32 i = 0; i < n; ++i) {
+ pairWeights[i] = CalcQuality(Bins[i], Bins[i + 1]).first;
+ }
+
+ TSmartHeap heap(pairWeights);
+
+ while (n + 1 > intervals) {
+ ui32 b = heap.IdOfMin();
+ heap.Pop();
+
+ ui32 a = (ui32)(bins[b].Prev() - bins);
+ ui32 c = (ui32)(bins[b].Next() - bins);
+ ui32 d = (ui32)(bins[b].Next()->Next() - bins);
+ Y_VERIFY(Bins[c].second != -1);
+
+ double mass = Bins[b].second + Bins[c].second;
+ Bins[c].first = (Bins[b].first * Bins[b].second + Bins[c].first * Bins[c].second) / mass;
+ Bins[c].second = mass;
+
+ bins[b].Unlink();
+ Bins[b].second = -1;
+
+ if (a != end) {
+ pairWeights[a] = CalcQuality(Bins[a], Bins[c]).first;
+ heap.DownElement(a);
+ }
+
+ if (d != end && c + 1 != Bins.size()) {
+ pairWeights[c] = CalcQuality(Bins[c], Bins[d]).first;
+ heap.DownElement(c);
+ }
+
+ --n;
+ }
+
+ size_t pos = 0;
+ for (TListItem* it = bins[end].Next(); it != &bins[end]; it = it->Next()) {
+ Bins[pos++] = Bins[it - bins];
+ }
+
+ Bins.resize(pos);
+ PrevSize = pos;
+ Y_VERIFY(pos == intervals);
+ }
+
+ double TBlockHistogram::GetSumInRange(double leftBound, double rightBound) {
+ Y_UNUSED(leftBound);
+ Y_UNUSED(rightBound);
+ ythrow yexception() << "Method is not implemented for TBlockHistogram";
+ return 0;
+ }
+
+ double TBlockHistogram::GetSumAboveBound(double bound) {
+ Y_UNUSED(bound);
+ ythrow yexception() << "Method is not implemented for TBlockHistogram";
+ return 0;
+ }
+
+ double TBlockHistogram::GetSumBelowBound(double bound) {
+ Y_UNUSED(bound);
+ ythrow yexception() << "Method is not implemented for TBlockHistogram";
+ return 0;
+ }
+
+ double TBlockHistogram::CalcUpperBound(double sum) {
+ Y_UNUSED(sum);
+ ythrow yexception() << "Method is not implemented for TBlockHistogram";
+ return 0;
+ }
+
+ double TBlockHistogram::CalcLowerBound(double sum) {
+ Y_UNUSED(sum);
+ ythrow yexception() << "Method is not implemented for TBlockHistogram";
+ return 0;
+ }
+
+ double TBlockHistogram::CalcUpperBoundSafe(double sum) {
+ Y_UNUSED(sum);
+ ythrow yexception() << "Method is not implemented for TBlockHistogram";
+ return 0;
+ }
+
+ double TBlockHistogram::CalcLowerBoundSafe(double sum) {
+ Y_UNUSED(sum);
+ ythrow yexception() << "Method is not implemented for TBlockHistogram";
+ return 0;
+ }
+
+ /////////////////////////
+ // TBlockWeightHistogram
+ /////////////////////////
+
+ TBlockWeightHistogram::TBlockWeightHistogram(size_t intervals, ui64 id, size_t shrinkSize)
+ : TBlockHistogram(HT_ADAPTIVE_WEIGHT_HISTOGRAM, CalcWeightQuality, intervals, id, shrinkSize)
+ {
+ }
+
+ void TBlockWeightHistogram::FastGreedyShrink(size_t intervals) {
+ if (Bins.size() <= intervals)
+ return;
+
+ double slab = Sum / intervals;
+
+ size_t i = 0;
+ size_t pos = 0;
+ while (i < Bins.size()) {
+ double curW = Bins[i].second;
+ double curMul = Bins[i].first * Bins[i].second;
+ ++i;
+ while (i < Bins.size() && curW + Bins[i].second <= slab && pos + Bins.size() - i >= intervals) {
+ curW += Bins[i].second;
+ curMul += Bins[i].first * Bins[i].second;
+ ++i;
+ }
+ Bins[pos++] = TWeightedValue(curMul / curW, curW);
+ }
+
+ Bins.resize(pos);
+ PrevSize = pos;
+ }
+
+ ///////////////////////
+ // TBlockWardHistogram
+ ///////////////////////
+
+ TBlockWardHistogram::TBlockWardHistogram(size_t intervals, ui64 id, size_t shrinkSize)
+ : TBlockHistogram(HT_ADAPTIVE_WARD_HISTOGRAM, CalcWardQuality, intervals, id, shrinkSize)
+ {
+ }
+
+ bool TBlockWardHistogram::CalcSplitInfo(
+ const TCumulatives::const_iterator beg,
+ const TCumulatives::const_iterator end, // (!) points to the final element
+ TSplitInfo& splitInfo // out
+ ) {
+ if (end - beg < 2) {
+ return false;
+ }
+
+ TCumulatives::const_iterator mid = LowerBound(beg, end + 1, TCumulative{(beg->first + end->first) / 2, 0.});
+
+ if (mid == beg) {
+ mid++;
+ } else if (mid == end) {
+ mid--;
+ }
+
+ // derived from Ward's minimum variance criterion
+ double profit = 0.0;
+ profit += (mid->second - beg->second) * (mid->second - beg->second) / (mid->first - beg->first);
+ profit += (end->second - mid->second) * (end->second - mid->second) / (end->first - mid->first);
+ profit -= (end->second - beg->second) * (end->second - beg->second) / (end->first - beg->first);
+
+ splitInfo = {profit, beg, mid, end};
+
+ return true;
+ }
+
+ void TBlockWardHistogram::FastGreedyShrink(size_t intervals) {
+ Y_VERIFY(intervals > 0);
+
+ if (Bins.size() <= intervals) {
+ return;
+ }
+
+ // fill cumulative sums
+ // sum at index i equals to the sum of all values before i
+ // sum at index i+1 equals to the sum of all values before i with the value at i added
+ TCumulatives cumulatives;
+ cumulatives.reserve(Bins.size() + 1);
+
+ TCumulative cumulative = {0., 0.};
+ cumulatives.push_back(cumulative);
+ for (size_t i = 0; i < Bins.size(); i++) {
+ cumulative.first += Bins[i].second;
+ cumulative.second += Bins[i].second * Bins[i].first;
+ cumulatives.push_back(cumulative);
+ }
+
+ TVector<TCumulatives::const_iterator> splits;
+ splits.reserve(intervals + 1);
+ splits.push_back(cumulatives.begin());
+ splits.push_back(cumulatives.end() - 1);
+
+ TPriorityQueue<TSplitInfo> candidates;
+
+ // explicitly add first split
+ TSplitInfo newSplitInfo;
+ if (CalcSplitInfo(cumulatives.begin(), cumulatives.end() - 1, newSplitInfo)) {
+ candidates.push(newSplitInfo);
+ }
+
+ // recursively split until done
+ for (size_t split = 0; split < intervals - 1 && !candidates.empty(); split++) {
+ TSplitInfo curSplitInfo = candidates.top();
+ candidates.pop();
+
+ splits.push_back(curSplitInfo.mid);
+
+ if (CalcSplitInfo(curSplitInfo.beg, curSplitInfo.mid, newSplitInfo)) {
+ candidates.push(newSplitInfo);
+ }
+ if (CalcSplitInfo(curSplitInfo.mid, curSplitInfo.end, newSplitInfo)) {
+ candidates.push(newSplitInfo);
+ }
+ }
+
+ // calclate new bin centers and weights
+ Sort(splits.begin(), splits.end());
+
+ Bins.clear();
+ for (auto it = splits.begin(); it + 1 != splits.end(); ++it) {
+ auto splitBeg = *it;
+ auto splitEnd = *(it + 1);
+ double cnt = (splitEnd->first - splitBeg->first);
+ double mu = (splitEnd->second - splitBeg->second) / cnt;
+
+ Bins.push_back(TWeightedValue(mu, cnt));
+ }
+ }
+
+}
diff --git a/library/cpp/histogram/adaptive/block_histogram.h b/library/cpp/histogram/adaptive/block_histogram.h
new file mode 100644
index 0000000000..266bb2f2b2
--- /dev/null
+++ b/library/cpp/histogram/adaptive/block_histogram.h
@@ -0,0 +1,148 @@
+#pragma once
+
+#include "histogram.h"
+#include "common.h"
+
+#include <library/cpp/histogram/adaptive/protos/histo.pb.h>
+
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+#include <utility>
+
+namespace NKiwiAggr {
+ ///////////////////
+ // TBlockHistogram
+ ///////////////////
+
+ /**
+ * Contrary to adaptive histogram, block histogram doesn't rebuild bins
+ * after the addition of each point. Instead, it accumulates points and in case the amount
+ * of points overflows specified limits, it shrinks all the points at once to produce histogram
+ * Indeed, there exist two limits and two shrinkage operations:
+ * 1) FastGreedyShrink is fast but coarse. It is used to shrink from upper limit to intermediate limit
+ * (override FastGreedyShrink to set specific behaviour)
+ * 2) SlowShrink is slow, but produces finer histogram. It shrinks from the intermediate limit to the
+ * actual number of bins in a manner similar to that in adaptive histogram (set CalcQuality in constuctor)
+ * While FastGreedyShrink is used most of the time, SlowShrink is mostly used for histogram finalization
+ */
+ class TBlockHistogram: private TNonCopyable, public IHistogram {
+ protected:
+ static const size_t SHRINK_MULTIPLIER = 2;
+ static const size_t GREEDY_SHRINK_MULTIPLIER = 4;
+ static const size_t DEFAULT_INTERVALS = 100;
+ static const size_t DEFAULT_SHRINK_SIZE = DEFAULT_INTERVALS * (SHRINK_MULTIPLIER + GREEDY_SHRINK_MULTIPLIER);
+
+ const EHistogramType Type;
+ const TQualityFunction CalcQuality;
+
+ size_t Intervals;
+ size_t ShrinkSize;
+ size_t PrevSize;
+
+ ui64 Id;
+
+ double Sum;
+ double MinValue;
+ double MaxValue;
+
+ TVector<TWeightedValue> Bins;
+
+ public:
+ TBlockHistogram(EHistogramType type, TQualityFunction calcQuality,
+ size_t intervals, ui64 id = 0, size_t shrinkSize = DEFAULT_SHRINK_SIZE);
+
+ virtual ~TBlockHistogram() {
+ }
+
+ virtual void Clear();
+
+ virtual void Add(double value, double weight);
+ virtual void Add(const THistoRec& histoRec);
+
+ virtual void Merge(const THistogram& histo, double multiplier);
+ virtual void Merge(const TVector<THistogram>& histogramsToMerge);
+ virtual void Merge(TVector<IHistogramPtr> histogramsToMerge); // not implemented
+
+ virtual void Multiply(double factor);
+
+ virtual void FromProto(const THistogram& histo);
+ virtual void ToProto(THistogram& histo);
+
+ virtual void SetId(ui64 id);
+ virtual ui64 GetId();
+ virtual bool Empty();
+ virtual double GetMinValue();
+ virtual double GetMaxValue();
+ virtual double GetSum();
+
+ // methods below are not implemented
+ virtual double GetSumInRange(double leftBound, double rightBound);
+ virtual double GetSumAboveBound(double bound);
+ virtual double GetSumBelowBound(double bound);
+ virtual double CalcUpperBound(double sum);
+ virtual double CalcLowerBound(double sum);
+ virtual double CalcUpperBoundSafe(double sum);
+ virtual double CalcLowerBoundSafe(double sum);
+
+ private:
+ void SortBins();
+ void UniquifyBins();
+ void CorrectShrinkSize();
+
+ void SortAndShrink(size_t intervals, bool final = false);
+
+ void SlowShrink(size_t intervals);
+ virtual void FastGreedyShrink(size_t intervals) = 0;
+ };
+
+ /////////////////////////
+ // TBlockWeightHistogram
+ /////////////////////////
+
+ class TBlockWeightHistogram: public TBlockHistogram {
+ public:
+ TBlockWeightHistogram(size_t intervals, ui64 id = 0, size_t shrinkSize = DEFAULT_SHRINK_SIZE);
+
+ virtual ~TBlockWeightHistogram() {
+ }
+
+ private:
+ virtual void FastGreedyShrink(size_t intervals) final;
+ };
+
+ ///////////////////////
+ // TBlockWardHistogram
+ ///////////////////////
+
+ class TBlockWardHistogram: public TBlockHistogram {
+ public:
+ TBlockWardHistogram(size_t intervals, ui64 id = 0, size_t shrinkSize = DEFAULT_SHRINK_SIZE);
+
+ virtual ~TBlockWardHistogram() {
+ }
+
+ private:
+ using TCumulative = std::pair<double, double>; // cumulative sum of (weights, weighted centers)
+ using TCumulatives = TVector<TCumulative>;
+
+ struct TSplitInfo {
+ double profit;
+
+ TCumulatives::const_iterator beg;
+ TCumulatives::const_iterator mid;
+ TCumulatives::const_iterator end;
+
+ bool operator<(const TSplitInfo& other) const {
+ return profit < other.profit;
+ }
+ };
+
+ private:
+ virtual void FastGreedyShrink(size_t intervals) final;
+
+ static bool CalcSplitInfo(const TCumulatives::const_iterator beg,
+ const TCumulatives::const_iterator end,
+ TSplitInfo& splitInfo);
+ };
+
+}
diff --git a/library/cpp/histogram/adaptive/common.cpp b/library/cpp/histogram/adaptive/common.cpp
new file mode 100644
index 0000000000..afc6322fce
--- /dev/null
+++ b/library/cpp/histogram/adaptive/common.cpp
@@ -0,0 +1,19 @@
+#include "common.h"
+
+namespace NKiwiAggr {
+ TWeightedValue CalcDistanceQuality(const TWeightedValue& left, const TWeightedValue& right) {
+ return TWeightedValue(right.first - left.first, left.first);
+ }
+
+ TWeightedValue CalcWeightQuality(const TWeightedValue& left, const TWeightedValue& right) {
+ return TWeightedValue(right.second + left.second, left.first);
+ }
+
+ TWeightedValue CalcWardQuality(const TWeightedValue& left, const TWeightedValue& right) {
+ const double N1 = left.second;
+ const double N2 = right.second;
+ const double mu1 = left.first;
+ const double mu2 = right.first;
+ return TWeightedValue(N1 * N2 / (N1 + N2) * (mu1 - mu2) * (mu1 - mu2), left.first);
+ }
+}
diff --git a/library/cpp/histogram/adaptive/common.h b/library/cpp/histogram/adaptive/common.h
new file mode 100644
index 0000000000..c0f7dfb26b
--- /dev/null
+++ b/library/cpp/histogram/adaptive/common.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <utility>
+
+namespace NKiwiAggr {
+ using TWeightedValue = std::pair<double, double>; // value, weight
+ using TQualityFunction = TWeightedValue (*)(const TWeightedValue&, const TWeightedValue&);
+
+ TWeightedValue CalcDistanceQuality(const TWeightedValue& left, const TWeightedValue& right);
+ TWeightedValue CalcWeightQuality(const TWeightedValue& left, const TWeightedValue& right);
+ TWeightedValue CalcWardQuality(const TWeightedValue& left, const TWeightedValue& right);
+}
diff --git a/library/cpp/histogram/adaptive/fixed_bin_histogram.cpp b/library/cpp/histogram/adaptive/fixed_bin_histogram.cpp
new file mode 100644
index 0000000000..558aba9e2d
--- /dev/null
+++ b/library/cpp/histogram/adaptive/fixed_bin_histogram.cpp
@@ -0,0 +1,538 @@
+#include "fixed_bin_histogram.h"
+#include "auto_histogram.h"
+
+#include <library/cpp/histogram/adaptive/protos/histo.pb.h>
+
+#include <util/generic/algorithm.h>
+#include <util/generic/yexception.h>
+#include <util/generic/ymath.h>
+#include <util/string/printf.h>
+
+namespace NKiwiAggr {
+ TFixedBinHistogram::TFixedBinHistogram(size_t intervals, ui64 id, size_t trainingSetSize)
+ : TrainingSetSize(trainingSetSize)
+ , IsInitialized(false)
+ , IsEmpty(true)
+ , Id(id)
+ , Sum(0.0)
+ , Freqs(0)
+ , ReserveFreqs(0)
+ , BinRange(0.0)
+ , Intervals(intervals)
+ , BaseIndex(intervals / 2)
+ {
+ }
+
+ TFixedBinHistogram::TFixedBinHistogram(const THistogram& histo, size_t defaultIntervals, ui64 defaultId, size_t trainingSetSize)
+ : TrainingSetSize(trainingSetSize)
+ , IsInitialized(false)
+ , IsEmpty(true)
+ , Id(defaultId)
+ , Sum(0.0)
+ , Freqs(0)
+ , ReserveFreqs(0)
+ , BinRange(0.0)
+ , Intervals(defaultIntervals)
+ , BaseIndex(defaultIntervals / 2)
+ {
+ FromProto(histo);
+ }
+
+ TFixedBinHistogram::TFixedBinHistogram(IHistogram* histo, size_t defaultIntervals, ui64 defaultId, size_t trainingSetSize)
+ : TrainingSetSize(trainingSetSize)
+ , IsInitialized(false)
+ , IsEmpty(true)
+ , Id(defaultId)
+ , Sum(0.0)
+ , Freqs(0)
+ , ReserveFreqs(0)
+ , BinRange(0.0)
+ , Intervals(defaultIntervals)
+ , BaseIndex(defaultIntervals / 2)
+ {
+ TFixedBinHistogram* fixedBinHisto = dynamic_cast<TFixedBinHistogram*>(histo);
+ if (!fixedBinHisto) {
+ FromIHistogram(histo);
+ return;
+ }
+ fixedBinHisto->Initialize();
+ TrainingSetSize = fixedBinHisto->TrainingSetSize;
+ IsInitialized = fixedBinHisto->IsInitialized;
+ IsEmpty = fixedBinHisto->IsEmpty;
+ Id = fixedBinHisto->Id;
+ MinValue = fixedBinHisto->MinValue;
+ MaxValue = fixedBinHisto->MaxValue;
+ Sum = fixedBinHisto->Sum;
+ Freqs.assign(fixedBinHisto->Freqs.begin(), fixedBinHisto->Freqs.end());
+ ReserveFreqs.assign(fixedBinHisto->ReserveFreqs.begin(), fixedBinHisto->ReserveFreqs.end());
+ ReferencePoint = fixedBinHisto->ReferencePoint;
+ BinRange = fixedBinHisto->BinRange;
+ Intervals = fixedBinHisto->Intervals;
+ FirstUsedBin = fixedBinHisto->FirstUsedBin;
+ LastUsedBin = fixedBinHisto->LastUsedBin;
+ BaseIndex = fixedBinHisto->BaseIndex;
+ }
+
+ void TFixedBinHistogram::Clear() {
+ TrainingSet.Destroy();
+ IsInitialized = false;
+ IsEmpty = true;
+ Sum = 0.0;
+ Freqs.clear();
+ ReserveFreqs.clear();
+ BinRange = 0.0;
+ }
+
+ void TFixedBinHistogram::Add(const THistoRec& rec) {
+ if (!rec.HasId() || rec.GetId() == Id) {
+ Add(rec.GetValue(), rec.GetWeight());
+ }
+ }
+
+ void TFixedBinHistogram::Add(double value, double weight) {
+ if (!IsValidFloat(value) || !IsValidFloat(weight)) {
+ ythrow yexception() << Sprintf("Histogram id %lu: bad value %f weight %f", Id, value, weight);
+ }
+
+ if (weight <= 0.0) {
+ return; // all zero-weighted values should be skipped because they don't affect the distribution, negative weights are forbidden
+ }
+
+ Sum += weight;
+
+ if (!IsInitialized) {
+ if (!TrainingSet) {
+ TrainingSet.Reset(new TVector<TWeightedValue>(0));
+ }
+ TrainingSet->push_back(TWeightedValue(value, weight));
+ if (TrainingSet->size() >= TrainingSetSize) {
+ Initialize();
+ }
+ return;
+ }
+
+ i32 bin = CalcBin(value);
+ if (bin < 0 || bin >= (i32)Freqs.size() || (BinRange == 0.0 && value != ReferencePoint)) {
+ Shrink(Min(value, MinValue), Max(value, MaxValue));
+ Freqs[CalcBin(value)] += weight;
+ } else {
+ MinValue = Min(value, MinValue);
+ MaxValue = Max(value, MaxValue);
+ FirstUsedBin = Min(FirstUsedBin, bin);
+ LastUsedBin = Max(LastUsedBin, bin);
+ Freqs[bin] += weight;
+ }
+ }
+
+ void TFixedBinHistogram::Merge(const THistogram& /*histo*/, double /*multiplier*/) {
+ ythrow yexception() << "Method is not implemented for TFixedBinHistogram";
+ }
+
+ void TFixedBinHistogram::Merge(const TVector<THistogram>& histogramsToMerge) {
+ TVector<IHistogramPtr> parsedHistogramsToMerge;
+ for (size_t i = 0; i < histogramsToMerge.size(); ++i) {
+ parsedHistogramsToMerge.push_back(IHistogramPtr(new TAutoHistogram(histogramsToMerge[i], Intervals, Id)));
+ }
+ Merge(parsedHistogramsToMerge);
+ }
+
+ void TFixedBinHistogram::Merge(TVector<IHistogramPtr> histogramsToMerge) {
+ TVector<IHistogramPtr> histogramsToMergeRepacked(0);
+ TVector<TFixedBinHistogram*> histograms(0);
+
+ // put current histogram to the vector of histograms to merge and clear self
+ if (!Empty()) {
+ histogramsToMergeRepacked.push_back(IHistogramPtr(new TFixedBinHistogram(this, Intervals, Id, TrainingSetSize)));
+ histograms.push_back(dynamic_cast<TFixedBinHistogram*>(histogramsToMergeRepacked.back().Get()));
+ }
+ Clear();
+
+ for (size_t i = 0; i < histogramsToMerge.size(); ++i) {
+ if (!histogramsToMerge[i] || histogramsToMerge[i]->Empty()) {
+ continue;
+ }
+ TFixedBinHistogram* fixedBinHisto = dynamic_cast<TFixedBinHistogram*>(histogramsToMerge[i].Get());
+ if (fixedBinHisto) {
+ fixedBinHisto->Initialize();
+ histogramsToMergeRepacked.push_back(histogramsToMerge[i]);
+ } else {
+ histogramsToMergeRepacked.push_back(IHistogramPtr(new TFixedBinHistogram(histogramsToMerge[i].Get(), Intervals, Id, TrainingSetSize))); // Convert histograms that are not of TFixedBinHistogram type
+ }
+ histograms.push_back(dynamic_cast<TFixedBinHistogram*>(histogramsToMergeRepacked.back().Get()));
+ }
+
+ if (histograms.size() == 0) {
+ return;
+ }
+
+ double minValue = histograms[0]->MinValue;
+ double maxValue = histograms[0]->MaxValue;
+ Sum = histograms[0]->Sum;
+ for (size_t i = 1; i < histograms.size(); ++i) {
+ minValue = Min(minValue, histograms[i]->MinValue);
+ maxValue = Max(maxValue, histograms[i]->MaxValue);
+ Sum += histograms[i]->Sum;
+ }
+ SetFrame(minValue, maxValue, true);
+
+ if (BinRange == 0.0) {
+ Freqs[BaseIndex] = Sum;
+ return;
+ }
+
+ for (size_t histoIndex = 0; histoIndex < histograms.size(); ++histoIndex) {
+ TFixedBinHistogram* histo = histograms[histoIndex];
+ for (i32 bin = histo->FirstUsedBin; bin <= histo->LastUsedBin; ++bin) {
+ double binStart = histo->BinStart(bin);
+ double binEnd = histo->BinEnd(bin);
+ double freq = histo->Freqs[bin];
+ if (binStart == binEnd) {
+ Freqs[CalcBin(binStart)] += freq;
+ continue;
+ }
+ size_t firstCross = CalcBin(binStart);
+ size_t lastCross = CalcBin(binEnd);
+ for (size_t i = firstCross; i <= lastCross; ++i) {
+ double mergedBinStart = BinStart(i);
+ double mergedBinEnd = BinEnd(i);
+ double crossStart = Max(mergedBinStart, binStart);
+ double crossEnd = Min(mergedBinEnd, binEnd);
+ if (binStart == binEnd) {
+ }
+ Freqs[i] += freq * (crossEnd - crossStart) / (binEnd - binStart);
+ }
+ }
+ }
+ }
+
+ void TFixedBinHistogram::Multiply(double factor) {
+ if (!IsValidFloat(factor) || factor <= 0) {
+ ythrow yexception() << "Not valid factor in IHistogram::Multiply(): " << factor;
+ }
+ if (!IsInitialized) {
+ Initialize();
+ }
+ Sum *= factor;
+ for (i32 i = FirstUsedBin; i <= LastUsedBin; ++i) {
+ Freqs[i] *= factor;
+ }
+ }
+
+ void TFixedBinHistogram::FromProto(const THistogram& histo) {
+ if (histo.HasType() && histo.GetType() != HT_FIXED_BIN_HISTOGRAM) {
+ ythrow yexception() << "Attempt to parse TFixedBinHistogram from THistogram protobuf record of wrong type = " << (ui32)histo.GetType();
+ }
+ TrainingSet.Destroy();
+ IsInitialized = false;
+ Sum = 0.0;
+
+ Id = histo.GetId();
+ size_t intervals = histo.FreqSize();
+ if (intervals == 0) {
+ IsEmpty = true;
+ return;
+ }
+ Intervals = intervals;
+ TrainingSetSize = Intervals;
+ BaseIndex = Intervals / 2;
+
+ if (!IsValidFloat(histo.GetMinValue()) || !IsValidFloat(histo.GetMaxValue()) || !IsValidFloat(histo.GetBinRange())) {
+ ythrow yexception() << Sprintf("FromProto in histogram id %lu: skip bad histo with minvalue %f maxvalue %f binrange %f", Id, histo.GetMinValue(), histo.GetMaxValue(), histo.GetBinRange());
+ }
+
+ double minValue = histo.GetMinValue();
+ double binRange = histo.GetBinRange();
+ double maxValue = histo.HasMaxValue() ? histo.GetMaxValue() : minValue + binRange * Intervals;
+ SetFrame(minValue, maxValue, true);
+ BinRange = binRange;
+ for (i32 i = FirstUsedBin; i <= LastUsedBin; ++i) {
+ Freqs[i] = histo.GetFreq(i - BaseIndex);
+ if (!IsValidFloat(Freqs[i])) {
+ ythrow yexception() << Sprintf("FromProto in histogram id %lu: bad value %f", Id, Freqs[i]);
+ }
+ Sum += Freqs[i];
+ }
+ }
+
+ void TFixedBinHistogram::ToProto(THistogram& histo) {
+ histo.Clear();
+ if (!IsInitialized) {
+ Initialize();
+ }
+ histo.SetType(HT_FIXED_BIN_HISTOGRAM);
+ histo.SetId(Id);
+ if (IsEmpty) {
+ return;
+ }
+ if (FirstUsedBin < (i32)BaseIndex || (LastUsedBin - FirstUsedBin + 1) > (i32)Intervals) {
+ Shrink(MinValue, MaxValue);
+ }
+ histo.SetMinValue(MinValue);
+ histo.SetMaxValue(MaxValue);
+ histo.SetBinRange(BinRange);
+ for (ui32 i = BaseIndex; i < BaseIndex + Intervals; ++i) {
+ histo.AddFreq(Freqs[i]);
+ }
+ }
+
+ void TFixedBinHistogram::SetId(ui64 id) {
+ Id = id;
+ }
+
+ ui64 TFixedBinHistogram::GetId() {
+ return Id;
+ }
+
+ bool TFixedBinHistogram::Empty() {
+ if (!IsInitialized) {
+ Initialize();
+ }
+ return IsEmpty;
+ }
+
+ double TFixedBinHistogram::GetMinValue() {
+ if (!IsInitialized) {
+ Initialize();
+ }
+ return MinValue;
+ }
+
+ double TFixedBinHistogram::GetMaxValue() {
+ if (!IsInitialized) {
+ Initialize();
+ }
+ return MaxValue;
+ }
+
+ double TFixedBinHistogram::GetSum() {
+ return Sum;
+ }
+
+ double TFixedBinHistogram::GetSumInRange(double leftBound, double rightBound) {
+ if (!IsInitialized) {
+ Initialize();
+ }
+ if (leftBound > rightBound) {
+ return 0.0;
+ }
+ return GetSumAboveBound(leftBound) + GetSumBelowBound(rightBound) - Sum;
+ }
+
+ double TFixedBinHistogram::GetSumAboveBound(double bound) {
+ if (!IsInitialized) {
+ Initialize();
+ }
+ if (IsEmpty) {
+ return 0.0;
+ }
+ if (BinRange == 0.0) { // special case - all values added to histogram are the same
+ return (bound <= ReferencePoint) ? Sum : 0.0;
+ }
+ i32 bin = CalcBin(bound);
+ if (bin < FirstUsedBin) {
+ return Sum;
+ }
+ if (bin > LastUsedBin) {
+ return 0.0;
+ }
+ double binStart = BinStart(bin);
+ double binEnd = BinEnd(bin);
+ double result = (bound < binStart) ? Freqs[bin] : Freqs[bin] * (binEnd - bound) / (binEnd - binStart);
+ for (i32 i = bin + 1; i <= LastUsedBin; ++i) {
+ result += Freqs[i];
+ }
+ return result;
+ }
+
+ double TFixedBinHistogram::GetSumBelowBound(double bound) {
+ if (!IsInitialized) {
+ Initialize();
+ }
+ if (IsEmpty) {
+ return 0.0;
+ }
+ if (BinRange == 0.0) { // special case - all values added to histogram are the same
+ return (bound > ReferencePoint) ? Sum : 0.0;
+ }
+ i32 bin = CalcBin(bound);
+ if (bin < FirstUsedBin) {
+ return 0.0;
+ }
+ if (bin > LastUsedBin) {
+ return Sum;
+ }
+ double binStart = BinStart(bin);
+ double binEnd = BinEnd(bin);
+ double result = (bound > binEnd) ? Freqs[bin] : Freqs[bin] * (bound - binStart) / (binEnd - binStart);
+ for (i32 i = bin - 1; i >= FirstUsedBin; --i) {
+ result += Freqs[i];
+ }
+ return result;
+ }
+
+ double TFixedBinHistogram::CalcUpperBound(double sum) {
+ if (!IsInitialized) {
+ Initialize();
+ }
+ if (sum == 0.0) {
+ return MinValue;
+ }
+ if (IsEmpty) {
+ return MaxValue;
+ }
+ i32 currentBin = FirstUsedBin;
+ double gatheredSum = 0.0;
+ while (gatheredSum < sum && currentBin <= LastUsedBin) {
+ gatheredSum += Freqs[currentBin];
+ ++currentBin;
+ }
+ --currentBin;
+ if ((gatheredSum <= sum && currentBin == LastUsedBin) || (Freqs[currentBin] == 0)) {
+ return MaxValue;
+ }
+ double binStart = BinStart(currentBin);
+ double binEnd = BinEnd(currentBin);
+ return binEnd - (binEnd - binStart) * (gatheredSum - sum) / Freqs[currentBin];
+ }
+
+ double TFixedBinHistogram::CalcLowerBound(double sum) {
+ if (!IsInitialized) {
+ Initialize();
+ }
+ if (sum == 0.0) {
+ return MaxValue;
+ }
+ if (IsEmpty) {
+ return MinValue;
+ }
+ i32 currentBin = LastUsedBin;
+ double gatheredSum = 0.0;
+ while (gatheredSum < sum && currentBin >= FirstUsedBin) {
+ gatheredSum += Freqs[currentBin];
+ --currentBin;
+ }
+ ++currentBin;
+ if ((gatheredSum <= sum && currentBin == FirstUsedBin) || (Freqs[currentBin] == 0)) {
+ return MinValue;
+ }
+ double binStart = BinStart(currentBin);
+ double binEnd = BinEnd(currentBin);
+ return binStart + (binEnd - binStart) * (gatheredSum - sum) / Freqs[currentBin];
+ }
+
+ double TFixedBinHistogram::CalcUpperBoundSafe(double sum) {
+ if (!Empty()) {
+ sum = Max(Freqs[FirstUsedBin], sum);
+ }
+ return CalcUpperBound(sum);
+ }
+
+ double TFixedBinHistogram::CalcLowerBoundSafe(double sum) {
+ if (!Empty()) {
+ sum = Max(Freqs[LastUsedBin], sum);
+ }
+ return CalcLowerBound(sum);
+ }
+
+ double TFixedBinHistogram::CalcBinRange(double referencePoint, double maxValue) {
+ return (maxValue - referencePoint) / ((double)Intervals - 0.02);
+ }
+
+ void TFixedBinHistogram::SetFrame(double minValue, double maxValue, bool clear) {
+ MinValue = minValue;
+ MaxValue = maxValue;
+ ReferencePoint = MinValue;
+ BinRange = CalcBinRange(ReferencePoint, MaxValue);
+ FirstUsedBin = BaseIndex;
+ LastUsedBin = (BinRange == 0.0) ? BaseIndex : BaseIndex + Intervals - 1;
+ if (clear) {
+ Freqs.assign(2 * Intervals, 0.0);
+ ReserveFreqs.assign(2 * Intervals, 0.0);
+ IsEmpty = false;
+ IsInitialized = true;
+ }
+ }
+
+ void TFixedBinHistogram::FromIHistogram(IHistogram* histo) {
+ if (!histo) {
+ ythrow yexception() << "Attempt to create TFixedBinFistogram from a NULL pointer";
+ }
+ Id = histo->GetId();
+ if (histo->Empty()) {
+ IsInitialized = false;
+ IsEmpty = true;
+ return;
+ }
+ SetFrame(histo->GetMinValue(), histo->GetMaxValue(), true);
+ Sum = histo->GetSum();
+ if (BinRange == 0.0) {
+ Freqs[BaseIndex] = Sum;
+ return;
+ }
+ for (i32 i = FirstUsedBin; i <= LastUsedBin; ++i) {
+ Freqs[i] = histo->GetSumInRange(BinStart(i), BinEnd(i));
+ }
+ return;
+ }
+
+ void TFixedBinHistogram::Initialize() {
+ if (IsInitialized) {
+ return;
+ }
+ if (!TrainingSet || TrainingSet->size() == 0) {
+ IsEmpty = true;
+ return;
+ }
+ SetFrame(MinElement(TrainingSet->begin(), TrainingSet->end(), CompareWeightedValue)->first,
+ MaxElement(TrainingSet->begin(), TrainingSet->end(), CompareWeightedValue)->first, true);
+ for (TVector<TWeightedValue>::const_iterator it = TrainingSet->begin(); it != TrainingSet->end(); ++it) {
+ Freqs[CalcBin(it->first)] += it->second;
+ }
+ TrainingSet.Destroy();
+ }
+
+ i32 TFixedBinHistogram::CalcBin(double value) {
+ return (BinRange == 0.0) ? BaseIndex : static_cast<i32>(BaseIndex + (value - ReferencePoint) / BinRange);
+ }
+
+ double TFixedBinHistogram::CalcDensity(double value) {
+ i32 bin = CalcBin(value);
+ if (bin < 0 || bin >= (i32)Freqs.size() || BinRange == 0.0 || GetSum() == 0) {
+ return 0.0;
+ }
+ return Freqs[bin] / GetSum() / BinRange;
+ }
+
+ double TFixedBinHistogram::BinStart(i32 i) {
+ return Max(ReferencePoint + (i - BaseIndex) * BinRange, MinValue);
+ }
+
+ double TFixedBinHistogram::BinEnd(i32 i) {
+ return Min(ReferencePoint + (i + 1 - BaseIndex) * BinRange, MaxValue);
+ }
+
+ void TFixedBinHistogram::Shrink(double newReferencePoint, double newMaxValue) {
+ Y_VERIFY(newReferencePoint < newMaxValue, "Invalid Shrink()");
+ memset(&(ReserveFreqs[0]), 0, ReserveFreqs.size() * sizeof(double));
+
+ double newBinRange = CalcBinRange(newReferencePoint, newMaxValue);
+ for (i32 i = FirstUsedBin; i <= LastUsedBin; ++i) {
+ double binStart = BinStart(i);
+ double binEnd = BinEnd(i);
+ double freq = Freqs[i];
+ i32 firstCross = static_cast<i32>(BaseIndex + (binStart - newReferencePoint) / newBinRange);
+ i32 lastCross = static_cast<i32>(BaseIndex + (binEnd - newReferencePoint) / newBinRange);
+ for (i32 j = firstCross; j <= lastCross; ++j) {
+ double newBinStart = newReferencePoint + (j - BaseIndex) * newBinRange;
+ double newBinEnd = newReferencePoint + (j + 1 - BaseIndex) * newBinRange;
+ double crossStart = Max(newBinStart, binStart);
+ double crossEnd = Min(newBinEnd, binEnd);
+ ReserveFreqs[j] += (binStart == binEnd) ? freq : freq * (crossEnd - crossStart) / (binEnd - binStart);
+ }
+ }
+
+ Freqs.swap(ReserveFreqs);
+ SetFrame(newReferencePoint, newMaxValue, false);
+ }
+
+}
diff --git a/library/cpp/histogram/adaptive/fixed_bin_histogram.h b/library/cpp/histogram/adaptive/fixed_bin_histogram.h
new file mode 100644
index 0000000000..bd380bd94a
--- /dev/null
+++ b/library/cpp/histogram/adaptive/fixed_bin_histogram.h
@@ -0,0 +1,91 @@
+#pragma once
+
+#include "histogram.h"
+
+#include <library/cpp/histogram/adaptive/protos/histo.pb.h>
+
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+#include <utility>
+
+namespace NKiwiAggr {
+ class TFixedBinHistogram: private TNonCopyable, public IHistogram {
+ private:
+ static const size_t DEFAULT_TRAINING_SET_SIZE = 10000;
+ static const size_t DEFAULT_INTERVALS = 100;
+
+ typedef std::pair<double, double> TWeightedValue; // value, weight
+ THolder<TVector<TWeightedValue>> TrainingSet;
+ size_t TrainingSetSize;
+
+ bool IsInitialized;
+ bool IsEmpty;
+
+ ui64 Id;
+ double MinValue;
+ double MaxValue;
+ double Sum;
+
+ TVector<double> Freqs;
+ TVector<double> ReserveFreqs;
+ double ReferencePoint;
+ double BinRange;
+ size_t Intervals;
+ i32 FirstUsedBin;
+ i32 LastUsedBin;
+ i32 BaseIndex;
+
+ public:
+ TFixedBinHistogram(size_t intervals, ui64 id = 0, size_t trainingSetSize = DEFAULT_TRAINING_SET_SIZE);
+ TFixedBinHistogram(const THistogram& histo, size_t defaultIntervals = DEFAULT_INTERVALS, ui64 defaultId = 0, size_t trainingSetSize = DEFAULT_TRAINING_SET_SIZE);
+ TFixedBinHistogram(IHistogram* histo, size_t defaultIntervals = DEFAULT_INTERVALS, ui64 defaultId = 0, size_t trainingSetSize = DEFAULT_TRAINING_SET_SIZE);
+
+ virtual ~TFixedBinHistogram() {
+ }
+
+ virtual void Clear();
+
+ virtual void Add(double value, double weight);
+ virtual void Add(const THistoRec& histoRec);
+
+ virtual void Merge(const THistogram& histo, double multiplier);
+ virtual void Merge(const TVector<THistogram>& histogramsToMerge);
+ virtual void Merge(TVector<IHistogramPtr> histogramsToMerge);
+
+ virtual void Multiply(double factor);
+
+ virtual void FromProto(const THistogram& histo);
+ virtual void ToProto(THistogram& histo);
+
+ virtual void SetId(ui64 id);
+ virtual ui64 GetId();
+ virtual bool Empty();
+ virtual double GetMinValue();
+ virtual double GetMaxValue();
+ virtual double GetSum();
+ virtual double GetSumInRange(double leftBound, double rightBound);
+ virtual double GetSumAboveBound(double bound);
+ virtual double GetSumBelowBound(double bound);
+ virtual double CalcUpperBound(double sum);
+ virtual double CalcLowerBound(double sum);
+ virtual double CalcUpperBoundSafe(double sum);
+ virtual double CalcLowerBoundSafe(double sum);
+
+ double CalcDensity(double value);
+
+ private:
+ double CalcBinRange(double referencePoint, double maxValue);
+ void SetFrame(double minValue, double maxValue, bool clear);
+ void FromIHistogram(IHistogram* histo);
+ void Initialize();
+ i32 CalcBin(double value);
+ double BinStart(i32 i);
+ double BinEnd(i32 i);
+ void Shrink(double newMinValue, double newMaxValue);
+
+ static bool CompareWeightedValue(const TWeightedValue& left, const TWeightedValue& right) {
+ return left.first < right.first;
+ }
+ };
+
+}
diff --git a/library/cpp/histogram/adaptive/histogram.h b/library/cpp/histogram/adaptive/histogram.h
new file mode 100644
index 0000000000..360fd9a693
--- /dev/null
+++ b/library/cpp/histogram/adaptive/histogram.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+
+namespace NKiwiAggr {
+ class THistogram;
+ class THistoRec;
+
+ class IHistogram;
+ typedef TAtomicSharedPtr<IHistogram> IHistogramPtr;
+
+ class IHistogram {
+ public:
+ // Supposed constructors:
+ //
+ // TSomeHistogram(size_t intervals, ui64 id = 0); // where intervals is some constant that defines histogram accuracy
+ // TSomeHistogram(const THistogram& histo); // histo must be acceptable for TSomeHistogram, for example, only with HT_FIXED_BIN_HISTOGRAM for TFixedBinHistogram
+ // TSomeHistogram(IHistogram* histo); // any kind of IHistogram
+
+ virtual ~IHistogram() {
+ }
+
+ virtual void Clear() = 0;
+
+ // zero- or negative-weighted values are skipped
+ virtual void Add(double value, double weight) = 0;
+ virtual void Add(const THistoRec& histoRec) = 0;
+
+ // Merge some other histos into current
+ virtual void Merge(const THistogram& histo, double multiplier) = 0;
+ virtual void Merge(const TVector<THistogram>& histogramsToMerge) = 0;
+ virtual void Merge(TVector<IHistogramPtr> histogramsToMerge) = 0;
+
+ // factor should be greater then zero
+ virtual void Multiply(double factor) = 0;
+
+ virtual void FromProto(const THistogram& histo) = 0; // throws exception in case of wrong histogram type of histo
+ virtual void ToProto(THistogram& histo) = 0;
+
+ virtual void SetId(ui64 id) = 0;
+ virtual ui64 GetId() = 0;
+ virtual bool Empty() = 0;
+ virtual double GetMinValue() = 0;
+ virtual double GetMaxValue() = 0;
+ virtual double GetSum() = 0;
+ virtual double GetSumInRange(double leftBound, double rightBound) = 0;
+ virtual double GetSumAboveBound(double bound) = 0;
+ virtual double GetSumBelowBound(double bound) = 0;
+ virtual double CalcUpperBound(double sum) = 0;
+ virtual double CalcLowerBound(double sum) = 0;
+ virtual double CalcUpperBoundSafe(double sum) = 0;
+ virtual double CalcLowerBoundSafe(double sum) = 0;
+ double GetValueAtPercentile(double percentile) {
+ return CalcUpperBound(percentile * GetSum());
+ }
+ double GetValueAtPercentileSafe(double percentile) {
+ return CalcUpperBoundSafe(percentile * GetSum());
+ }
+
+ // Histogram implementation is supposed to clear all precomputed values() if Add() is called after PrecomputePartialSums()
+ virtual void PrecomputePartialSums() {
+ }
+ };
+
+}
diff --git a/library/cpp/histogram/adaptive/merger.h b/library/cpp/histogram/adaptive/merger.h
new file mode 100644
index 0000000000..fc9a6b6a4f
--- /dev/null
+++ b/library/cpp/histogram/adaptive/merger.h
@@ -0,0 +1,68 @@
+#pragma once
+
+#include <util/generic/buffer.h>
+
+namespace NKiwiAggr {
+ class IMerger {
+ private:
+ bool IsMerged;
+ ui32 AutoMergeInterval; // Call Merge() after each AutoMergeInterval calls of Add(); zero means no autoMerge
+ ui32 NotMergedCount;
+
+ public:
+ IMerger(ui32 autoMergeInterval = 0)
+ : IsMerged(true)
+ , AutoMergeInterval(autoMergeInterval)
+ , NotMergedCount(0)
+ {
+ }
+
+ virtual ~IMerger() {
+ }
+
+ // returns true if something is added
+ virtual bool Add(const void* data, size_t size) {
+ if (AddImpl(data, size)) {
+ AutoMerge();
+ return true;
+ }
+ return false;
+ }
+
+ virtual void Merge() {
+ if (!IsMerged) {
+ MergeImpl();
+ IsMerged = true;
+ }
+ }
+
+ virtual void Reset() {
+ ResetImpl();
+ IsMerged = true;
+ }
+
+ // You can add some more result-getters if you want.
+ // Do not forget to call Merge() in the beginning of each merger.
+ virtual void GetResult(TBuffer& buffer) = 0;
+
+ protected:
+ // AutoMerge() is called in Add() after each AddImpl()
+ void AutoMerge() {
+ IsMerged = false;
+ if (AutoMergeInterval) {
+ ++NotMergedCount;
+ if (NotMergedCount >= AutoMergeInterval) {
+ MergeImpl();
+ IsMerged = true;
+ NotMergedCount = 0;
+ }
+ }
+ }
+
+ // Implementation of merger: define it in derivatives
+ virtual bool AddImpl(const void* data, size_t size) = 0; // returns true if something is added
+ virtual void MergeImpl() = 0;
+ virtual void ResetImpl() = 0;
+ };
+
+}
diff --git a/library/cpp/histogram/adaptive/multi_histogram.h b/library/cpp/histogram/adaptive/multi_histogram.h
new file mode 100644
index 0000000000..41caac5ba6
--- /dev/null
+++ b/library/cpp/histogram/adaptive/multi_histogram.h
@@ -0,0 +1,143 @@
+#pragma once
+
+#include "histogram.h"
+#include "auto_histogram.h"
+
+#include <library/cpp/histogram/adaptive/protos/histo.pb.h>
+
+#include <util/generic/hash.h>
+#include <util/generic/ptr.h>
+#include <utility>
+
+namespace NKiwiAggr {
+ template <class TMyHistogram>
+ class TMultiHistogram {
+ private:
+ static const size_t DEFAULT_INTERVALS = 100;
+
+ typedef THashMap<ui64, IHistogramPtr> THistogramsMap;
+ THistogramsMap Histograms;
+ size_t Intervals;
+
+ public:
+ TMultiHistogram(size_t intervals = DEFAULT_INTERVALS)
+ : Intervals(intervals)
+ {
+ }
+
+ TMultiHistogram(const THistograms& histograms, size_t defaultIntervals = DEFAULT_INTERVALS)
+ : Intervals(defaultIntervals)
+ {
+ FromProto(histograms);
+ }
+
+ virtual ~TMultiHistogram() {
+ }
+
+ void Clear() {
+ Histograms.clear();
+ }
+
+ void Add(const THistoRecs& histoRecs) {
+ for (size_t i = 0; i < histoRecs.HistoRecsSize(); ++i) {
+ Add(histoRecs.GetHistoRecs(i).GetId(), histoRecs.GetHistoRecs(i).GetValue(), histoRecs.GetHistoRecs(i).GetWeight());
+ }
+ }
+
+ void Add(const THistoRec& histoRec) {
+ Add(histoRec.GetId(), histoRec.GetValue(), histoRec.GetWeight());
+ }
+
+ void Add(ui64 id, double value, double weight) {
+ THistogramsMap::const_iterator it = Histograms.find(id);
+ if (it == Histograms.end()) {
+ it = Histograms.insert(std::make_pair(id, IHistogramPtr(new TMyHistogram(Intervals, id)))).first;
+ }
+ it->second->Add(value, weight);
+ }
+
+ void Multiply(double factor) {
+ for (THistogramsMap::iterator it = Histograms.begin(); it != Histograms.end(); ++it) {
+ it->second->Multiply(factor);
+ }
+ }
+
+ TVector<ui64> GetIds() const {
+ TVector<ui64> result(0);
+ for (THistogramsMap::const_iterator it = Histograms.begin(); it != Histograms.end(); ++it) {
+ result.push_back(it->first);
+ }
+ return result;
+ }
+
+ IHistogramPtr GetHistogram(ui64 id) const {
+ THistogramsMap::const_iterator it = Histograms.find(id);
+ if (it != Histograms.end()) {
+ return it->second;
+ }
+ return IHistogramPtr();
+ }
+
+ double GetMaxHistoSum() const {
+ double sum = 0.0;
+ for (THistogramsMap::const_iterator it = Histograms.begin(); it != Histograms.end(); ++it) {
+ sum = std::max(sum, it->second->GetSum());
+ }
+ return sum;
+ }
+
+ bool Empty() {
+ for (THistogramsMap::iterator it = Histograms.begin(); it != Histograms.end(); ++it) {
+ if (!it->second->Empty()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ virtual double OverallSum() {
+ double sum = 0.0;
+ for (THistogramsMap::iterator it = Histograms.begin(); it != Histograms.end(); ++it) {
+ sum += it->second->GetSum();
+ }
+ return sum;
+ }
+
+ void FromProto(const THistograms& histograms) {
+ for (size_t i = 0; i < histograms.HistoRecsSize(); ++i) {
+ IHistogramPtr newHisto(new TMyHistogram(histograms.GetHistoRecs(i), Intervals));
+ if (!newHisto->Empty()) {
+ Histograms[newHisto->GetId()] = newHisto;
+ }
+ }
+ }
+
+ void ToProto(THistograms& histograms) {
+ histograms.Clear();
+ for (THistogramsMap::iterator it = Histograms.begin(); it != Histograms.end(); ++it) {
+ THistogram* histo = histograms.AddHistoRecs();
+ it->second->ToProto(*histo);
+ }
+ }
+
+ void PrecomputePartialSums() {
+ for (auto& it : Histograms) {
+ it.second->PrecomputePartialSums();
+ }
+ }
+ };
+
+ template <class TMerger, class TSomeMultiHistogram>
+ static void MergeToMultiHistogram(const void* data, size_t size, TSomeMultiHistogram& multiHistogram, ui32 intervals = 300) {
+ TMerger merger(intervals);
+ merger.Add(data, size);
+ THistograms histograms;
+ merger.GetResult(histograms);
+ multiHistogram.FromProto(histograms);
+ }
+
+ // Good for parsing from THistograms protobuf
+ typedef TMultiHistogram<TAutoHistogram> TAutoMultiHistogram;
+ typedef TAtomicSharedPtr<TAutoMultiHistogram> TAutoMultiHistogramPtr;
+
+}
diff --git a/library/cpp/histogram/adaptive/protos/histo.proto b/library/cpp/histogram/adaptive/protos/histo.proto
new file mode 100644
index 0000000000..8961fef022
--- /dev/null
+++ b/library/cpp/histogram/adaptive/protos/histo.proto
@@ -0,0 +1,36 @@
+package NKiwiAggr;
+
+
+// THistoRec represents a value record added to a multihistogram
+message THistoRec {
+ optional uint64 Id = 1; // Current histogram identifier
+ optional double Value = 2;
+ optional double Weight = 3 [default = 1.0]; // You can set a certain weight to each record or just skip records using Weight=0
+}
+
+message THistoRecs {
+ repeated THistoRec HistoRecs = 1;
+}
+
+enum EHistogramType {
+ HT_FIXED_BIN_HISTOGRAM = 1;
+ HT_ADAPTIVE_DISTANCE_HISTOGRAM = 2;
+ HT_ADAPTIVE_WEIGHT_HISTOGRAM = 3;
+ HT_ADAPTIVE_HISTOGRAM = 4; // if the quality function is unknown
+ HT_ADAPTIVE_WARD_HISTOGRAM = 5;
+}
+
+message THistogram {
+ optional uint64 Id = 1;
+ optional double MinValue = 2;
+ optional double BinRange = 4; // for FIXED_BIN_HISTOGRAM only. And it's OK that it is 4 after 2
+ repeated float Freq = 5;
+ repeated float Position = 6; // for ADAPTIVE histograms only
+ optional double MaxValue = 7;
+ optional EHistogramType Type = 8; // Empty field means FIXED_BIN_HISTOGRAM
+}
+
+// Multihistogam
+message THistograms {
+ repeated THistogram HistoRecs = 1;
+}
diff --git a/library/cpp/histogram/adaptive/protos/python/ya.make b/library/cpp/histogram/adaptive/protos/python/ya.make
new file mode 100644
index 0000000000..3328c27965
--- /dev/null
+++ b/library/cpp/histogram/adaptive/protos/python/ya.make
@@ -0,0 +1,3 @@
+OWNER(abogutskiy)
+
+PY_PROTOS_FOR(library/cpp/histogram/adaptive/protos)
diff --git a/library/cpp/histogram/adaptive/protos/ya.make b/library/cpp/histogram/adaptive/protos/ya.make
new file mode 100644
index 0000000000..7635cfcb8c
--- /dev/null
+++ b/library/cpp/histogram/adaptive/protos/ya.make
@@ -0,0 +1,13 @@
+PROTO_LIBRARY()
+
+OWNER(g:crawl)
+
+SRCS(
+ histo.proto
+)
+
+IF (NOT PY_PROTOS_FOR)
+ EXCLUDE_TAGS(GO_PROTO)
+ENDIF()
+
+END()
diff --git a/library/cpp/histogram/adaptive/ya.make b/library/cpp/histogram/adaptive/ya.make
new file mode 100644
index 0000000000..b589801b27
--- /dev/null
+++ b/library/cpp/histogram/adaptive/ya.make
@@ -0,0 +1,20 @@
+LIBRARY()
+
+OWNER(
+ zosimov
+ svirg
+)
+
+SRCS(
+ common.cpp
+ adaptive_histogram.cpp
+ block_histogram.cpp
+ fixed_bin_histogram.cpp
+)
+
+PEERDIR(
+ contrib/libs/protobuf
+ library/cpp/histogram/adaptive/protos
+)
+
+END()
diff --git a/library/cpp/histogram/ya.make b/library/cpp/histogram/ya.make
new file mode 100644
index 0000000000..77cfd96902
--- /dev/null
+++ b/library/cpp/histogram/ya.make
@@ -0,0 +1,9 @@
+RECURSE(
+ adaptive
+ hdr
+ hdr/ut
+ simple
+ simple/ut
+ rt
+ rt/ut
+)
diff --git a/library/cpp/html/escape/escape.cpp b/library/cpp/html/escape/escape.cpp
new file mode 100644
index 0000000000..5b8ed60f04
--- /dev/null
+++ b/library/cpp/html/escape/escape.cpp
@@ -0,0 +1,66 @@
+#include "escape.h"
+
+#include <util/generic/array_size.h>
+#include <util/generic/strbuf.h>
+
+namespace NHtml {
+ namespace {
+ struct TReplace {
+ char Char;
+ bool ForText;
+ TStringBuf Entity;
+ };
+
+ TReplace Escapable[] = {
+ {'"', false, TStringBuf("&quot;")},
+ {'&', true, TStringBuf("&amp;")},
+ {'<', true, TStringBuf("&lt;")},
+ {'>', true, TStringBuf("&gt;")},
+ };
+
+ TString EscapeImpl(const TString& value, bool isText) {
+ auto ci = value.begin();
+ // Looking for escapable characters.
+ for (; ci != value.end(); ++ci) {
+ for (size_t i = (isText ? 1 : 0); i < Y_ARRAY_SIZE(Escapable); ++i) {
+ if (*ci == Escapable[i].Char) {
+ goto escape;
+ }
+ }
+ }
+
+ // There is no escapable characters, so return original value.
+ return value;
+
+ escape:
+ TString tmp = TString(value.begin(), ci);
+
+ for (; ci != value.end(); ++ci) {
+ size_t i = (isText ? 1 : 0);
+
+ for (; i < Y_ARRAY_SIZE(Escapable); ++i) {
+ if (*ci == Escapable[i].Char) {
+ tmp += Escapable[i].Entity;
+ break;
+ }
+ }
+
+ if (i == Y_ARRAY_SIZE(Escapable)) {
+ tmp += *ci;
+ }
+ }
+
+ return tmp;
+ }
+
+ }
+
+ TString EscapeAttributeValue(const TString& value) {
+ return EscapeImpl(value, false);
+ }
+
+ TString EscapeText(const TString& value) {
+ return EscapeImpl(value, true);
+ }
+
+}
diff --git a/library/cpp/html/escape/escape.h b/library/cpp/html/escape/escape.h
new file mode 100644
index 0000000000..1c45fc5193
--- /dev/null
+++ b/library/cpp/html/escape/escape.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <util/generic/string.h>
+
+namespace NHtml {
+ TString EscapeAttributeValue(const TString& value);
+ TString EscapeText(const TString& value);
+
+}
diff --git a/library/cpp/html/escape/ut/escape_ut.cpp b/library/cpp/html/escape/ut/escape_ut.cpp
new file mode 100644
index 0000000000..cd7b955138
--- /dev/null
+++ b/library/cpp/html/escape/ut/escape_ut.cpp
@@ -0,0 +1,16 @@
+#include <library/cpp/html/escape/escape.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NHtml;
+
+Y_UNIT_TEST_SUITE(TEscapeHtml) {
+ Y_UNIT_TEST(Escape) {
+ UNIT_ASSERT_EQUAL(EscapeText("in & out"), "in &amp; out");
+ UNIT_ASSERT_EQUAL(EscapeText("&&"), "&amp;&amp;");
+ UNIT_ASSERT_EQUAL(EscapeText("&amp;"), "&amp;amp;");
+
+ UNIT_ASSERT_EQUAL(EscapeText("<script>"), "&lt;script&gt;");
+
+ UNIT_ASSERT_EQUAL(EscapeText("text"), "text");
+ }
+}
diff --git a/library/cpp/html/escape/ut/ya.make b/library/cpp/html/escape/ut/ya.make
new file mode 100644
index 0000000000..27d3a3d65a
--- /dev/null
+++ b/library/cpp/html/escape/ut/ya.make
@@ -0,0 +1,13 @@
+UNITTEST()
+
+OWNER(stanly)
+
+SRCS(
+ escape_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/html/escape
+)
+
+END()
diff --git a/library/cpp/html/escape/ya.make b/library/cpp/html/escape/ya.make
new file mode 100644
index 0000000000..93a31e33d6
--- /dev/null
+++ b/library/cpp/html/escape/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(stanly)
+
+SRCS(
+ escape.cpp
+)
+
+END()
diff --git a/library/cpp/html/pcdata/pcdata.cpp b/library/cpp/html/pcdata/pcdata.cpp
new file mode 100644
index 0000000000..740c240fd2
--- /dev/null
+++ b/library/cpp/html/pcdata/pcdata.cpp
@@ -0,0 +1,81 @@
+#include "pcdata.h"
+
+#include <util/string/strspn.h>
+
+static TCompactStrSpn sspn("\"<>&'");
+
+static void EncodeHtmlPcdataAppendInternal(const TStringBuf str, TString& strout, bool qAmp) {
+ const char* s = str.data();
+ const char* e = s + str.length();
+
+ for (;;) {
+ const char* next = sspn.FindFirstOf(s, e);
+
+ strout.AppendNoAlias(s, next - s);
+ s = next;
+
+ if (s == e)
+ break;
+
+ switch (*s) {
+ case '\"':
+ strout += TStringBuf("&quot;");
+ ++s;
+ break;
+
+ case '<':
+ strout += TStringBuf("&lt;");
+ ++s;
+ break;
+
+ case '>':
+ strout += TStringBuf("&gt;");
+ ++s;
+ break;
+
+ case '\'':
+ strout += TStringBuf("&#39;");
+ ++s;
+ break;
+
+ case '&':
+ if (qAmp)
+ strout += TStringBuf("&amp;");
+ else
+ strout += TStringBuf("&");
+ ++s;
+ break;
+ }
+ }
+}
+
+void EncodeHtmlPcdataAppend(const TStringBuf str, TString& strout) {
+ EncodeHtmlPcdataAppendInternal(str, strout, true);
+}
+
+TString EncodeHtmlPcdata(const TStringBuf str, bool qAmp) {
+ TString strout;
+ EncodeHtmlPcdataAppendInternal(str, strout, qAmp);
+ return strout;
+}
+
+TString DecodeHtmlPcdata(const TString& sz) {
+ TString res;
+ const char* codes[] = {"&quot;", "&lt;", "&gt;", "&#39;", "&#039;", "&amp;", "&apos;", nullptr};
+ const char chars[] = {'\"', '<', '>', '\'', '\'', '&', '\''};
+ for (size_t i = 0; i < sz.length(); ++i) {
+ char c = sz[i];
+ if (c == '&') {
+ for (const char** p = codes; *p; ++p) {
+ size_t len = strlen(*p);
+ if (strncmp(sz.c_str() + i, *p, len) == 0) {
+ i += len - 1;
+ c = chars[p - codes];
+ break;
+ }
+ }
+ }
+ res += c;
+ }
+ return res;
+}
diff --git a/library/cpp/html/pcdata/pcdata.h b/library/cpp/html/pcdata/pcdata.h
new file mode 100644
index 0000000000..7dd741f53d
--- /dev/null
+++ b/library/cpp/html/pcdata/pcdata.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include <util/generic/fwd.h>
+
+/// Converts a text into HTML-code. Special characters of HTML («<», «>», ...) replaced with entities.
+TString EncodeHtmlPcdata(const TStringBuf str, bool qAmp = true);
+void EncodeHtmlPcdataAppend(const TStringBuf str, TString& strout);
+
+/// Reverse of EncodeHtmlPcdata()
+TString DecodeHtmlPcdata(const TString& sz);
diff --git a/library/cpp/html/pcdata/pcdata_ut.cpp b/library/cpp/html/pcdata/pcdata_ut.cpp
new file mode 100644
index 0000000000..5833f8bc59
--- /dev/null
+++ b/library/cpp/html/pcdata/pcdata_ut.cpp
@@ -0,0 +1,48 @@
+#include "pcdata.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TPcdata) {
+ Y_UNIT_TEST(TestStress) {
+ {
+ ui64 key = 0x000017C0B76C4E87ull;
+ TString res = EncodeHtmlPcdata(TStringBuf((const char*)&key, sizeof(key)));
+ }
+
+ for (size_t i = 0; i < 1000; ++i) {
+ const TString s = NUnitTest::RandomString(i, i);
+
+ UNIT_ASSERT_VALUES_EQUAL(DecodeHtmlPcdata(EncodeHtmlPcdata(s)), s);
+ }
+ }
+
+ Y_UNIT_TEST(Test1) {
+ const TString tests[] = {
+ "qw&qw",
+ "&<",
+ ">&qw",
+ "\'&aaa"};
+
+ for (auto s : tests) {
+ UNIT_ASSERT_VALUES_EQUAL(DecodeHtmlPcdata(EncodeHtmlPcdata(s)), s);
+ }
+ }
+
+ Y_UNIT_TEST(Test2) {
+ UNIT_ASSERT_VALUES_EQUAL(EncodeHtmlPcdata("&qqq"), "&amp;qqq");
+ }
+
+ Y_UNIT_TEST(TestEncodeHtmlPcdataAppend) {
+ TString s;
+ EncodeHtmlPcdataAppend("m&m", s);
+ EncodeHtmlPcdataAppend("'s", s);
+ UNIT_ASSERT_VALUES_EQUAL(EncodeHtmlPcdata("m&m's"), s);
+ UNIT_ASSERT_VALUES_EQUAL("m&amp;m&#39;s", s);
+ }
+
+ Y_UNIT_TEST(TestStrangeAmpParameter) {
+ UNIT_ASSERT_VALUES_EQUAL(EncodeHtmlPcdata("m&m's", true), "m&amp;m&#39;s");
+ UNIT_ASSERT_VALUES_EQUAL(EncodeHtmlPcdata("m&m's"), "m&amp;m&#39;s"); //default
+ UNIT_ASSERT_VALUES_EQUAL(EncodeHtmlPcdata("m&m's", false), "m&m&#39;s");
+ }
+}
diff --git a/library/cpp/html/pcdata/ut/ya.make b/library/cpp/html/pcdata/ut/ya.make
new file mode 100644
index 0000000000..bc947baa89
--- /dev/null
+++ b/library/cpp/html/pcdata/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/html/pcdata)
+
+OWNER(vladon)
+
+SRCS(
+ pcdata_ut.cpp
+)
+
+END()
diff --git a/library/cpp/html/pcdata/ya.make b/library/cpp/html/pcdata/ya.make
new file mode 100644
index 0000000000..637220e706
--- /dev/null
+++ b/library/cpp/html/pcdata/ya.make
@@ -0,0 +1,10 @@
+LIBRARY()
+
+OWNER(vladon)
+
+SRCS(
+ pcdata.cpp
+ pcdata.h
+)
+
+END()
diff --git a/library/cpp/html/ya.make b/library/cpp/html/ya.make
new file mode 100644
index 0000000000..ab904be3b9
--- /dev/null
+++ b/library/cpp/html/ya.make
@@ -0,0 +1,32 @@
+RECURSE(
+ dehtml
+ dehtml/ut
+ detect
+ blob
+ entity
+ entity/ut
+ escape
+ escape/ut
+ face
+ face/blob
+ html5
+ html5/tests
+ html5/ut
+ lexer
+ lexer/ut
+ pcdata
+ pcdata/ut
+ pdoc
+ print
+ relalternate
+ relalternate/ut
+ sanitize
+ spec
+ storage
+ storage/ut
+ strip
+ tree
+ url
+ zoneconf
+ zoneconf/ut
+)
diff --git a/library/cpp/http/fetch/exthttpcodes.cpp b/library/cpp/http/fetch/exthttpcodes.cpp
new file mode 100644
index 0000000000..acc05650c8
--- /dev/null
+++ b/library/cpp/http/fetch/exthttpcodes.cpp
@@ -0,0 +1,266 @@
+#include "exthttpcodes.h"
+
+#include <cstring>
+
+const ui16 CrazyServer = ShouldDelete | MarkSuspect;
+
+struct http_flag {
+ ui16 http;
+ ui16 flag;
+};
+static http_flag HTTP_FLAG[] = {
+ {HTTP_CONTINUE, MarkSuspect}, // 100
+ {HTTP_SWITCHING_PROTOCOLS, CrazyServer}, // 101
+ {HTTP_PROCESSING, CrazyServer}, // 102
+
+ {HTTP_OK, ShouldReindex}, // 200
+ {HTTP_CREATED, CrazyServer}, // 201
+ {HTTP_ACCEPTED, ShouldDelete}, // 202
+ {HTTP_NON_AUTHORITATIVE_INFORMATION, ShouldReindex}, // 203
+ {HTTP_NO_CONTENT, ShouldDelete}, // 204
+ {HTTP_RESET_CONTENT, ShouldDelete}, // 205
+ {HTTP_PARTIAL_CONTENT, ShouldReindex}, // 206
+ {HTTP_MULTI_STATUS, CrazyServer}, // 207
+ {HTTP_ALREADY_REPORTED, CrazyServer}, // 208
+ {HTTP_IM_USED, CrazyServer}, // 226
+
+ {HTTP_MULTIPLE_CHOICES, CheckLinks | ShouldDelete}, // 300
+ {HTTP_MOVED_PERMANENTLY, CheckLocation | ShouldDelete | MoveRedir}, // 301
+ {HTTP_FOUND, CheckLocation | ShouldDelete | MoveRedir}, // 302
+ {HTTP_SEE_OTHER, CheckLocation | ShouldDelete | MoveRedir}, // 303
+ {HTTP_NOT_MODIFIED, 0}, // 304
+ {HTTP_USE_PROXY, ShouldDelete}, // 305
+ {HTTP_TEMPORARY_REDIRECT, CheckLocation | ShouldDelete | MoveRedir}, // 307
+ {HTTP_PERMANENT_REDIRECT, CheckLocation | ShouldDelete | MoveRedir}, // 308
+
+ {HTTP_BAD_REQUEST, CrazyServer}, // 400
+ {HTTP_UNAUTHORIZED, ShouldDelete}, // 401
+ {HTTP_PAYMENT_REQUIRED, ShouldDelete}, // 402
+ {HTTP_FORBIDDEN, ShouldDelete}, // 403
+ {HTTP_NOT_FOUND, ShouldDelete}, // 404
+ {HTTP_METHOD_NOT_ALLOWED, ShouldDelete}, // 405
+ {HTTP_NOT_ACCEPTABLE, ShouldDelete}, // 406
+ {HTTP_PROXY_AUTHENTICATION_REQUIRED, CrazyServer}, // 407
+ {HTTP_REQUEST_TIME_OUT, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 408
+ {HTTP_CONFLICT, MarkSuspect}, // 409
+ {HTTP_GONE, ShouldDelete}, // 410
+ {HTTP_LENGTH_REQUIRED, CrazyServer}, // 411
+ {HTTP_PRECONDITION_FAILED, CrazyServer}, // 412
+ {HTTP_REQUEST_ENTITY_TOO_LARGE, CrazyServer}, // 413
+ {HTTP_REQUEST_URI_TOO_LARGE, ShouldDelete}, // 414
+ {HTTP_UNSUPPORTED_MEDIA_TYPE, CrazyServer}, // 415
+ {HTTP_REQUESTED_RANGE_NOT_SATISFIABLE, CrazyServer}, // 416
+ {HTTP_EXPECTATION_FAILED, ShouldDelete}, // 417
+ {HTTP_I_AM_A_TEAPOT, CrazyServer}, // 418
+ {HTTP_AUTHENTICATION_TIMEOUT, ShouldDelete}, // 419
+
+ {HTTP_MISDIRECTED_REQUEST, CrazyServer}, // 421
+ {HTTP_UNPROCESSABLE_ENTITY, CrazyServer}, // 422
+ {HTTP_LOCKED, ShouldDelete}, // 423
+ {HTTP_FAILED_DEPENDENCY, CrazyServer}, // 424
+ {HTTP_UPGRADE_REQUIRED, ShouldDelete}, // 426
+ {HTTP_PRECONDITION_REQUIRED, ShouldDelete}, // 428
+ {HTTP_TOO_MANY_REQUESTS, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 429
+ {HTTP_UNAVAILABLE_FOR_LEGAL_REASONS, ShouldDelete}, // 451
+
+ {HTTP_INTERNAL_SERVER_ERROR, MarkSuspect}, // 500
+ {HTTP_NOT_IMPLEMENTED, ShouldDelete | ShouldDisconnect}, // 501
+ {HTTP_BAD_GATEWAY, MarkSuspect}, // 502
+ {HTTP_SERVICE_UNAVAILABLE, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 503
+ {HTTP_GATEWAY_TIME_OUT, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 504
+ {HTTP_HTTP_VERSION_NOT_SUPPORTED, CrazyServer | ShouldDisconnect}, // 505
+
+ {HTTP_VARIANT_ALSO_NEGOTIATES, CrazyServer | ShouldDisconnect}, // 506
+ {HTTP_INSUFFICIENT_STORAGE, CrazyServer | ShouldDisconnect}, // 507
+ {HTTP_LOOP_DETECTED, CrazyServer | ShouldDisconnect}, // 508
+ {HTTP_BANDWIDTH_LIMIT_EXCEEDED, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 509
+ {HTTP_NOT_EXTENDED, ShouldDelete}, // 510
+ {HTTP_NETWORK_AUTHENTICATION_REQUIRED, ShouldDelete}, // 511
+
+ // custom
+ {HTTP_BAD_RESPONSE_HEADER, CrazyServer}, // 1000
+ {HTTP_CONNECTION_LOST, ShouldRetry}, // 1001
+ {HTTP_BODY_TOO_LARGE, ShouldDelete | CanBeFake}, // 1002
+ {HTTP_ROBOTS_TXT_DISALLOW, ShouldDelete}, // 1003
+ {HTTP_BAD_URL, ShouldDelete}, // 1004
+ {HTTP_BAD_MIME, ShouldDelete}, // 1005
+ {HTTP_DNS_FAILURE, ShouldDisconnect | MarkSuspect}, // 1006
+ {HTTP_BAD_STATUS_CODE, CrazyServer}, // 1007
+ {HTTP_BAD_HEADER_STRING, CrazyServer}, // 1008
+ {HTTP_BAD_CHUNK, CrazyServer}, // 1009
+ {HTTP_CONNECT_FAILED, ShouldDisconnect | ShouldRetry | MarkSuspect}, // 1010
+ {HTTP_FILTER_DISALLOW, ShouldDelete}, // 1011
+ {HTTP_LOCAL_EIO, ShouldRetry}, // 1012
+ {HTTP_BAD_CONTENT_LENGTH, ShouldDelete}, // 1013
+ {HTTP_BAD_ENCODING, ShouldDelete}, // 1014
+ {HTTP_LENGTH_UNKNOWN, ShouldDelete}, // 1015
+ {HTTP_HEADER_EOF, ShouldRetry | CanBeFake}, // 1016
+ {HTTP_MESSAGE_EOF, ShouldRetry | CanBeFake}, // 1017
+ {HTTP_CHUNK_EOF, ShouldRetry | CanBeFake}, // 1018
+ {HTTP_PAST_EOF, ShouldRetry | ShouldDelete | CanBeFake}, // 1019
+ {HTTP_HEADER_TOO_LARGE, ShouldDelete}, // 1020
+ {HTTP_URL_TOO_LARGE, ShouldDelete}, // 1021
+ {HTTP_INTERRUPTED, 0}, // 1022
+ {HTTP_CUSTOM_NOT_MODIFIED, 0}, // 1023
+ {HTTP_BAD_CONTENT_ENCODING, ShouldDelete}, // 1024
+ {HTTP_PROXY_UNKNOWN, 0}, // 1030
+ {HTTP_PROXY_REQUEST_TIME_OUT, 0}, // 1031
+ {HTTP_PROXY_INTERNAL_ERROR, 0}, // 1032
+ {HTTP_PROXY_CONNECT_FAILED, 0}, // 1033
+ {HTTP_PROXY_CONNECTION_LOST, 0}, // 1034
+ {HTTP_PROXY_NO_PROXY, 0}, // 1035
+ {HTTP_PROXY_ERROR, 0}, // 1036
+ {HTTP_SSL_ERROR, 0}, // 1037
+ {HTTP_CACHED_COPY_NOT_FOUND, 0}, // 1038
+ {HTTP_TIMEDOUT_WHILE_BYTES_RECEIVING, ShouldRetry}, // 1039
+ {HTTP_FETCHER_BAD_RESPONSE, 0}, // 1040
+ {HTTP_FETCHER_MB_ERROR, 0}, // 1041
+ {HTTP_SSL_CERT_ERROR, 0}, // 1042
+
+ // Custom (replace HTTP 200/304)
+ {EXT_HTTP_MIRRMOVE, 0}, // 2000
+ {EXT_HTTP_MANUAL_DELETE, ShouldDelete}, // 2001
+ {EXT_HTTP_NOTUSED2, ShouldDelete}, // 2002
+ {EXT_HTTP_NOTUSED3, ShouldDelete}, // 2003
+ {EXT_HTTP_REFRESH, ShouldDelete | CheckLinks | MoveRedir}, // 2004
+ {EXT_HTTP_NOINDEX, ShouldDelete | CheckLinks}, // 2005
+ {EXT_HTTP_BADCODES, ShouldDelete}, // 2006
+ {EXT_HTTP_SITESTAT, ShouldDelete}, // 2007
+ {EXT_HTTP_IOERROR, ShouldDelete}, // 2008
+ {EXT_HTTP_BASEERROR, ShouldDelete}, // 2009
+ {EXT_HTTP_PARSERROR, ShouldDelete | CanBeFake}, // 2010
+ {EXT_HTTP_BAD_CHARSET, ShouldDelete | CheckLinks}, // 2011
+ {EXT_HTTP_BAD_LANGUAGE, ShouldDelete | CheckLinks}, // 2012
+ {EXT_HTTP_NUMERERROR, ShouldDelete}, // 2013
+ {EXT_HTTP_EMPTYDOC, ShouldDelete | CheckLinks}, // 2014
+ {EXT_HTTP_HUGEDOC, ShouldDelete}, // 2015
+ {EXT_HTTP_LINKGARBAGE, ShouldDelete}, // 2016
+ {EXT_HTTP_PARSERFAIL, ShouldDelete}, // 2019
+ {EXT_HTTP_GZIPERROR, ShouldDelete}, // 2020
+ {EXT_HTTP_MANUAL_DELETE_URL, ShouldDelete}, // 2022
+ {EXT_HTTP_CUSTOM_PARTIAL_CONTENT, ShouldReindex}, // 2023
+ {EXT_HTTP_EMPTY_RESPONSE, ShouldDelete}, // 2024
+ {EXT_HTTP_REL_CANONICAL, ShouldDelete | CheckLinks | MoveRedir}, // 2025
+ {0, 0}};
+
+static ui16* prepare_flags(http_flag* arg) {
+ static ui16 flags[EXT_HTTP_CODE_MAX];
+ http_flag* ptr;
+ size_t i;
+
+ // устанавливаем значение по умолчанию для кодов не перечисленных в таблице выше
+ for (i = 0; i < EXT_HTTP_CODE_MAX; ++i)
+ flags[i] = CrazyServer;
+
+ // устанавливаем флаги для перечисленных кодов
+ for (ptr = arg; ptr->http; ++ptr)
+ flags[ptr->http & (EXT_HTTP_CODE_MAX - 1)] = ptr->flag;
+
+ // для стандартных кодов ошибок берем флаги из первого кода каждой группы и проставляем их
+ // всем кодам не перечисленным в таблице выше
+ for (size_t group = 0; group < 1000; group += 100)
+ for (size_t j = group + 1; j < group + 100; ++j)
+ flags[j] = flags[group];
+
+ // предыдущий цикл затер некоторые флаги перечисленные в таблице выше
+ // восстанавливаем их
+ for (ptr = arg; ptr->http; ++ptr)
+ flags[ptr->http & (EXT_HTTP_CODE_MAX - 1)] = ptr->flag;
+
+ return flags;
+}
+
+ui16* http2status = prepare_flags(HTTP_FLAG);
+
+TStringBuf ExtHttpCodeStr(int code) noexcept {
+ if (code < HTTP_CODE_MAX) {
+ return HttpCodeStr(code);
+ }
+ switch (code) {
+ case HTTP_BAD_RESPONSE_HEADER:
+ return TStringBuf("Bad response header");
+ case HTTP_CONNECTION_LOST:
+ return TStringBuf("Connection lost");
+ case HTTP_BODY_TOO_LARGE:
+ return TStringBuf("Body too large");
+ case HTTP_ROBOTS_TXT_DISALLOW:
+ return TStringBuf("robots.txt disallow");
+ case HTTP_BAD_URL:
+ return TStringBuf("Bad url");
+ case HTTP_BAD_MIME:
+ return TStringBuf("Bad mime type");
+ case HTTP_DNS_FAILURE:
+ return TStringBuf("Dns failure");
+ case HTTP_BAD_STATUS_CODE:
+ return TStringBuf("Bad status code");
+ case HTTP_BAD_HEADER_STRING:
+ return TStringBuf("Bad header string");
+ case HTTP_BAD_CHUNK:
+ return TStringBuf("Bad chunk");
+ case HTTP_CONNECT_FAILED:
+ return TStringBuf("Connect failed");
+ case HTTP_FILTER_DISALLOW:
+ return TStringBuf("Filter disallow");
+ case HTTP_LOCAL_EIO:
+ return TStringBuf("Local eio");
+ case HTTP_BAD_CONTENT_LENGTH:
+ return TStringBuf("Bad content length");
+ case HTTP_BAD_ENCODING:
+ return TStringBuf("Bad encoding");
+ case HTTP_LENGTH_UNKNOWN:
+ return TStringBuf("Length unknown");
+ case HTTP_HEADER_EOF:
+ return TStringBuf("Header EOF");
+ case HTTP_MESSAGE_EOF:
+ return TStringBuf("Message EOF");
+ case HTTP_CHUNK_EOF:
+ return TStringBuf("Chunk EOF");
+ case HTTP_PAST_EOF:
+ return TStringBuf("Past EOF");
+ case HTTP_HEADER_TOO_LARGE:
+ return TStringBuf("Header is too large");
+ case HTTP_URL_TOO_LARGE:
+ return TStringBuf("Url is too large");
+ case HTTP_INTERRUPTED:
+ return TStringBuf("Interrupted");
+ case HTTP_CUSTOM_NOT_MODIFIED:
+ return TStringBuf("Signature detector thinks that doc is not modified");
+ case HTTP_BAD_CONTENT_ENCODING:
+ return TStringBuf("Bad content encoding");
+ case HTTP_NO_RESOURCES:
+ return TStringBuf("No resources");
+ case HTTP_FETCHER_SHUTDOWN:
+ return TStringBuf("Fetcher shutdown");
+ case HTTP_CHUNK_TOO_LARGE:
+ return TStringBuf("Chunk size is too big");
+ case HTTP_SERVER_BUSY:
+ return TStringBuf("Server is busy");
+ case HTTP_SERVICE_UNKNOWN:
+ return TStringBuf("Service is unknown");
+ case HTTP_PROXY_UNKNOWN:
+ return TStringBuf("Zora: unknown error");
+ case HTTP_PROXY_REQUEST_TIME_OUT:
+ return TStringBuf("Zora: request time out");
+ case HTTP_PROXY_INTERNAL_ERROR:
+ return TStringBuf("Zora: internal server error");
+ case HTTP_PROXY_CONNECT_FAILED:
+ return TStringBuf("Spider proxy connect failed");
+ case HTTP_PROXY_CONNECTION_LOST:
+ return TStringBuf("Spider proxy connection lost");
+ case HTTP_PROXY_NO_PROXY:
+ return TStringBuf("Spider proxy no proxy alive in region");
+ case HTTP_PROXY_ERROR:
+ return TStringBuf("Spider proxy returned custom error");
+ case HTTP_SSL_ERROR:
+ return TStringBuf("Ssl library returned error");
+ case HTTP_CACHED_COPY_NOT_FOUND:
+ return TStringBuf("Cached copy for the url is not available");
+ case HTTP_TIMEDOUT_WHILE_BYTES_RECEIVING:
+ return TStringBuf("Timed out while bytes receiving");
+
+ // TODO: messages for >2000 codes
+
+ default:
+ return TStringBuf("Unknown HTTP code");
+ }
+}
diff --git a/library/cpp/http/fetch/exthttpcodes.h b/library/cpp/http/fetch/exthttpcodes.h
new file mode 100644
index 0000000000..6b525052cd
--- /dev/null
+++ b/library/cpp/http/fetch/exthttpcodes.h
@@ -0,0 +1,141 @@
+#pragma once
+
+#include <util/system/defaults.h>
+#include <library/cpp/http/misc/httpcodes.h>
+
+enum ExtHttpCodes {
+ // Custom
+ HTTP_EXTENDED = 1000,
+ HTTP_BAD_RESPONSE_HEADER = 1000,
+ HTTP_CONNECTION_LOST = 1001,
+ HTTP_BODY_TOO_LARGE = 1002,
+ HTTP_ROBOTS_TXT_DISALLOW = 1003,
+ HTTP_BAD_URL = 1004,
+ HTTP_BAD_MIME = 1005,
+ HTTP_DNS_FAILURE = 1006,
+ HTTP_BAD_STATUS_CODE = 1007,
+ HTTP_BAD_HEADER_STRING = 1008,
+ HTTP_BAD_CHUNK = 1009,
+ HTTP_CONNECT_FAILED = 1010,
+ HTTP_FILTER_DISALLOW = 1011,
+ HTTP_LOCAL_EIO = 1012,
+ HTTP_BAD_CONTENT_LENGTH = 1013,
+ HTTP_BAD_ENCODING = 1014,
+ HTTP_LENGTH_UNKNOWN = 1015,
+ HTTP_HEADER_EOF = 1016,
+ HTTP_MESSAGE_EOF = 1017,
+ HTTP_CHUNK_EOF = 1018,
+ HTTP_PAST_EOF = 1019,
+ HTTP_HEADER_TOO_LARGE = 1020,
+ HTTP_URL_TOO_LARGE = 1021,
+ HTTP_INTERRUPTED = 1022,
+ HTTP_CUSTOM_NOT_MODIFIED = 1023,
+ HTTP_BAD_CONTENT_ENCODING = 1024,
+ HTTP_NO_RESOURCES = 1025,
+ HTTP_FETCHER_SHUTDOWN = 1026,
+ HTTP_CHUNK_TOO_LARGE = 1027,
+ HTTP_SERVER_BUSY = 1028,
+ HTTP_SERVICE_UNKNOWN = 1029,
+ HTTP_PROXY_UNKNOWN = 1030,
+ HTTP_PROXY_REQUEST_TIME_OUT = 1031,
+ HTTP_PROXY_INTERNAL_ERROR = 1032,
+ HTTP_PROXY_CONNECT_FAILED = 1033,
+ HTTP_PROXY_CONNECTION_LOST = 1034,
+ HTTP_PROXY_NO_PROXY = 1035,
+ HTTP_PROXY_ERROR = 1036,
+ HTTP_SSL_ERROR = 1037,
+ HTTP_CACHED_COPY_NOT_FOUND = 1038,
+ HTTP_TIMEDOUT_WHILE_BYTES_RECEIVING = 1039,
+ HTTP_FETCHER_BAD_RESPONSE = 1040,
+ HTTP_FETCHER_MB_ERROR = 1041,
+ HTTP_SSL_CERT_ERROR = 1042,
+ HTTP_PROXY_REQUEST_CANCELED = 1051,
+
+ // Custom (replace HTTP 200/304)
+ EXT_HTTP_EXT_SUCCESS_BEGIN = 2000, // to check if code variable is in success interval
+ EXT_HTTP_MIRRMOVE = 2000,
+ EXT_HTTP_MANUAL_DELETE = 2001,
+ EXT_HTTP_NOTUSED2 = 2002,
+ EXT_HTTP_NOTUSED3 = 2003,
+ EXT_HTTP_REFRESH = 2004,
+ EXT_HTTP_NOINDEX = 2005,
+ EXT_HTTP_BADCODES = 2006,
+ EXT_HTTP_SITESTAT = 2007,
+ EXT_HTTP_IOERROR = 2008,
+ EXT_HTTP_BASEERROR = 2009,
+ EXT_HTTP_PARSERROR = 2010,
+ EXT_HTTP_BAD_CHARSET = 2011,
+ EXT_HTTP_BAD_LANGUAGE = 2012,
+ EXT_HTTP_NUMERERROR = 2013,
+ EXT_HTTP_EMPTYDOC = 2014,
+ EXT_HTTP_HUGEDOC = 2015,
+ EXT_HTTP_LINKGARBAGE = 2016,
+ EXT_HTTP_EXDUPLICATE = 2017,
+ EXT_HTTP_FILTERED = 2018,
+ EXT_HTTP_PARSERFAIL = 2019, // parser crashed (in this case image spider will redownload such document)
+ EXT_HTTP_GZIPERROR = 2020,
+ EXT_HTTP_CLEANPARAM = 2021,
+ EXT_HTTP_MANUAL_DELETE_URL = 2022,
+ EXT_HTTP_CUSTOM_PARTIAL_CONTENT = 2023,
+ EXT_HTTP_EMPTY_RESPONSE = 2024,
+ EXT_HTTP_REL_CANONICAL = 2025,
+
+ EXT_HTTP_EXT_SUCCESS_END = 3000, // to check if code variable is in success interval
+ EXT_HTTP_HOSTFILTER = 3001,
+ EXT_HTTP_URLFILTER = 3002,
+ EXT_HTTP_SUFFIXFILTER = 3003,
+ EXT_HTTP_DOMAINFILTER = 3004,
+ EXT_HTTP_EXTDOMAINFILTER = 3005,
+ EXT_HTTP_PORTFILTER = 3006,
+ EXT_HTTP_MIRROR = 3007,
+ EXT_HTTP_DEEPDIR = 3008,
+ EXT_HTTP_DUPDIRS = 3009,
+ EXT_HTTP_REGEXP = 3010,
+ EXT_HTTP_OLDDELETED = 3012,
+ EXT_HTTP_PENALTY = 3013,
+ EXT_HTTP_POLICY = 3015,
+ EXT_HTTP_TOOOLD = 3016,
+ EXT_HTTP_GARBAGE = 3017,
+ EXT_HTTP_FOREIGN = 3018,
+ EXT_HTTP_EXT_REGEXP = 3019,
+ EXT_HTTP_HOPS = 3020,
+ EXT_HTTP_SELRANK = 3021,
+ EXT_HTTP_NOLINKS = 3022,
+ EXT_HTTP_WRONGMULTILANG = 3023,
+ EXT_HTTP_SOFTMIRRORS = 3024,
+ EXT_HTTP_BIGLEVEL = 3025,
+
+ // fast robot codes
+
+ EXT_HTTP_FASTHOPS = 4000,
+ EXT_HTTP_NODOC = 4001,
+
+ EXT_HTTP_MAX
+};
+
+enum HttpFlags {
+ // connection
+ ShouldDisconnect = 1,
+ ShouldRetry = 2,
+ // UNUSED 4
+
+ // indexer
+ ShouldReindex = 8,
+ ShouldDelete = 16,
+ CheckLocation = 32,
+ CheckLinks = 64,
+ MarkSuspect = 128,
+ // UNUSED 256
+ // UNUSED 512
+ MoveRedir = 1024,
+ CanBeFake = 2048,
+};
+
+const size_t EXT_HTTP_CODE_MAX = 1 << 12;
+
+static inline int Http2Status(int code) {
+ extern ui16* http2status;
+ return http2status[code & (EXT_HTTP_CODE_MAX - 1)];
+}
+
+TStringBuf ExtHttpCodeStr(int code) noexcept;
diff --git a/library/cpp/http/fetch/http_digest.cpp b/library/cpp/http/fetch/http_digest.cpp
new file mode 100644
index 0000000000..1eaa02b7f2
--- /dev/null
+++ b/library/cpp/http/fetch/http_digest.cpp
@@ -0,0 +1,206 @@
+#include "http_digest.h"
+
+#include <library/cpp/digest/md5/md5.h>
+#include <util/stream/output.h>
+#include <util/stream/str.h>
+
+/************************************************************/
+/************************************************************/
+static const char* WWW_PREFIX = "Authorization: Digest ";
+
+/************************************************************/
+httpDigestHandler::httpDigestHandler()
+ : User_(nullptr)
+ , Password_(nullptr)
+ , Nonce_(nullptr)
+ , NonceCount_(0)
+ , HeaderInstruction_(nullptr)
+{
+}
+
+/************************************************************/
+httpDigestHandler::~httpDigestHandler() {
+ clear();
+}
+
+/************************************************************/
+void httpDigestHandler::clear() {
+ free(Nonce_);
+ free(HeaderInstruction_);
+ User_ = Password_ = nullptr;
+ Nonce_ = HeaderInstruction_ = nullptr;
+ NonceCount_ = 0;
+}
+
+/************************************************************/
+void httpDigestHandler::setAuthorization(const char* user, const char* password) {
+ clear();
+ if (user && password) {
+ User_ = user;
+ Password_ = password;
+ }
+}
+
+/************************************************************/
+const char* httpDigestHandler::getHeaderInstruction() const {
+ return HeaderInstruction_;
+}
+
+/************************************************************/
+void httpDigestHandler::generateCNonce(char* outCNonce) {
+ if (!*outCNonce)
+ sprintf(outCNonce, "%ld", (long)time(nullptr));
+}
+
+/************************************************************/
+inline void addMD5(MD5& ctx, const char* value) {
+ ctx.Update((const unsigned char*)(value), strlen(value));
+}
+
+inline void addMD5(MD5& ctx, const char* value, int len) {
+ ctx.Update((const unsigned char*)(value), len);
+}
+
+inline void addMD5Sep(MD5& ctx) {
+ addMD5(ctx, ":", 1);
+}
+
+/************************************************************/
+/* calculate H(A1) as per spec */
+void httpDigestHandler::digestCalcHA1(const THttpAuthHeader& hd,
+ char* outSessionKey,
+ char* outCNonce) {
+ MD5 ctx;
+ ctx.Init();
+ addMD5(ctx, User_);
+ addMD5Sep(ctx);
+ addMD5(ctx, hd.realm);
+ addMD5Sep(ctx);
+ addMD5(ctx, Password_);
+
+ if (hd.algorithm == 1) { //MD5-sess
+ unsigned char digest[16];
+ ctx.Final(digest);
+
+ generateCNonce(outCNonce);
+
+ ctx.Init();
+ ctx.Update(digest, 16);
+ addMD5Sep(ctx);
+ addMD5(ctx, hd.nonce);
+ addMD5Sep(ctx);
+ addMD5(ctx, outCNonce);
+ ctx.End(outSessionKey);
+ }
+
+ ctx.End(outSessionKey);
+};
+
+/************************************************************/
+/* calculate request-digest/response-digest as per HTTP Digest spec */
+void httpDigestHandler::digestCalcResponse(const THttpAuthHeader& hd,
+ const char* path,
+ const char* method,
+ const char* nonceCount,
+ char* outResponse,
+ char* outCNonce) {
+ char HA1[33];
+ digestCalcHA1(hd, HA1, outCNonce);
+
+ char HA2[33];
+ MD5 ctx;
+ ctx.Init();
+ addMD5(ctx, method);
+ addMD5Sep(ctx);
+ addMD5(ctx, path);
+ //ignore auth-int
+ ctx.End(HA2);
+
+ ctx.Init();
+ addMD5(ctx, HA1, 32);
+ addMD5Sep(ctx);
+ addMD5(ctx, Nonce_);
+ addMD5Sep(ctx);
+
+ if (hd.qop_auth) {
+ if (!*outCNonce)
+ generateCNonce(outCNonce);
+
+ addMD5(ctx, nonceCount, 8);
+ addMD5Sep(ctx);
+ addMD5(ctx, outCNonce);
+ addMD5Sep(ctx);
+ addMD5(ctx, "auth", 4);
+ addMD5Sep(ctx);
+ }
+ addMD5(ctx, HA2, 32);
+ ctx.End(outResponse);
+}
+
+/************************************************************/
+bool httpDigestHandler::processHeader(const THttpAuthHeader* header,
+ const char* path,
+ const char* method,
+ const char* cnonce) {
+ if (!User_ || !header || !header->use_auth || !header->realm || !header->nonce)
+ return false;
+
+ if (Nonce_) {
+ if (strcmp(Nonce_, header->nonce)) {
+ free(Nonce_);
+ Nonce_ = nullptr;
+ NonceCount_ = 0;
+ }
+ }
+ if (!Nonce_) {
+ Nonce_ = strdup(header->nonce);
+ NonceCount_ = 0;
+ }
+ free(HeaderInstruction_);
+ HeaderInstruction_ = nullptr;
+ NonceCount_++;
+
+ char nonceCount[20];
+ sprintf(nonceCount, "%08d", NonceCount_);
+
+ char CNonce[50];
+ if (cnonce)
+ strcpy(CNonce, cnonce);
+ else
+ CNonce[0] = 0;
+
+ char response[33];
+ digestCalcResponse(*header, path, method, nonceCount, response, CNonce);
+
+ //digest-response = 1#( username | realm | nonce | digest-uri
+ // | response | [ algorithm ] | [cnonce] |
+ // [opaque] | [message-qop] |
+ // [nonce-count] | [auth-param] )
+
+ TStringStream out;
+ out << WWW_PREFIX << "username=\"" << User_ << "\"";
+ out << ", realm=\"" << header->realm << "\"";
+ out << ", nonce=\"" << header->nonce << "\"";
+ out << ", uri=\"" << path << "\"";
+ if (header->algorithm == 1)
+ out << ", algorithm=MD5-sess";
+ else
+ out << ", algorithm=MD5";
+ if (header->qop_auth)
+ out << ", qop=auth";
+ out << ", nc=" << nonceCount;
+ if (CNonce[0])
+ out << ", cnonce=\"" << CNonce << "\"";
+ out << ", response=\"" << response << "\"";
+ if (header->opaque)
+ out << ", opaque=\"" << header->opaque << "\"";
+ out << "\r\n";
+
+ TString s_out = out.Str();
+ HeaderInstruction_ = strdup(s_out.c_str());
+
+ return true;
+}
+
+/************************************************************/
+/************************************************************/
diff --git a/library/cpp/http/fetch/http_digest.h b/library/cpp/http/fetch/http_digest.h
new file mode 100644
index 0000000000..3b1872d70b
--- /dev/null
+++ b/library/cpp/http/fetch/http_digest.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "httpheader.h"
+
+#include <util/system/compat.h>
+#include <library/cpp/http/misc/httpcodes.h>
+
+class httpDigestHandler {
+protected:
+ const char* User_;
+ const char* Password_;
+ char* Nonce_;
+ int NonceCount_;
+ char* HeaderInstruction_;
+
+ void clear();
+
+ void generateCNonce(char* outCNonce);
+
+ void digestCalcHA1(const THttpAuthHeader& hd,
+ char* outSessionKey,
+ char* outCNonce);
+
+ void digestCalcResponse(const THttpAuthHeader& hd,
+ const char* method,
+ const char* path,
+ const char* nonceCount,
+ char* outResponse,
+ char* outCNonce);
+
+public:
+ httpDigestHandler();
+ ~httpDigestHandler();
+
+ void setAuthorization(const char* user,
+ const char* password);
+ bool processHeader(const THttpAuthHeader* header,
+ const char* path,
+ const char* method,
+ const char* cnonce = nullptr);
+
+ bool empty() const {
+ return (!User_);
+ }
+
+ const char* getHeaderInstruction() const;
+};
diff --git a/library/cpp/http/fetch/http_socket.cpp b/library/cpp/http/fetch/http_socket.cpp
new file mode 100644
index 0000000000..1524ef04a8
--- /dev/null
+++ b/library/cpp/http/fetch/http_socket.cpp
@@ -0,0 +1,206 @@
+#include "httpload.h"
+#include "http_digest.h"
+
+/************************************************************/
+
+#ifdef USE_GNUTLS
+
+#include <gcrypt.h>
+#include <gnutls/gnutls.h>
+#include <util/network/init.h>
+#include <util/network/socket.h>
+#include <util/system/mutex.h>
+
+/********************************************************/
+// HTTPS handler is used as implementation of
+// socketAbstractHandler for work through HTTPS protocol
+
+class socketSecureHandler: public socketRegularHandler {
+protected:
+ bool IsValid_;
+ gnutls_session Session_;
+ gnutls_certificate_credentials Credits_;
+
+public:
+ socketSecureHandler();
+ virtual ~socketSecureHandler();
+
+ virtual bool Good();
+ virtual int Connect(const TAddrList& addrs, TDuration Timeout);
+ virtual void Disconnect();
+ virtual void shutdown();
+ virtual bool send(const char* message, ssize_t messlen);
+ virtual bool peek();
+ virtual ssize_t read(void* buffer, ssize_t buflen);
+};
+
+/********************************************************/
+/********************************************************/
+static int gcry_pthread_mutex_init(void** priv) {
+ int err = 0;
+
+ try {
+ TMutex* lock = new TMutex;
+ *priv = lock;
+ } catch (...) {
+ err = -1;
+ }
+
+ return err;
+}
+
+static int gcry_pthread_mutex_destroy(void** lock) {
+ delete static_cast<TMutex*>(*lock);
+
+ return 0;
+}
+
+static int gcry_pthread_mutex_lock(void** lock) {
+ static_cast<TMutex*>(*lock)->Acquire();
+
+ return 0;
+}
+
+static int gcry_pthread_mutex_unlock(void** lock) {
+ static_cast<TMutex*>(*lock)->Release();
+
+ return 0;
+}
+
+static struct gcry_thread_cbs gcry_threads_pthread =
+ {
+ GCRY_THREAD_OPTION_PTHREAD, NULL,
+ gcry_pthread_mutex_init, gcry_pthread_mutex_destroy,
+ gcry_pthread_mutex_lock, gcry_pthread_mutex_unlock,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL};
+
+/********************************************************/
+struct https_initor {
+ https_initor() {
+ gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
+ gnutls_global_init();
+ InitNetworkSubSystem();
+ }
+
+ ~https_initor() {
+ gnutls_global_deinit();
+ }
+};
+
+static https_initor _initor;
+
+/********************************************************/
+socketSecureHandler::socketSecureHandler()
+ : socketRegularHandler()
+ , IsValid_(false)
+ , Session_()
+ , Credits_()
+{
+}
+
+/********************************************************/
+socketSecureHandler::~socketSecureHandler() {
+ if (IsValid_)
+ Disconnect();
+}
+
+/********************************************************/
+bool socketSecureHandler::Good() {
+ return Socket_.Good() && IsValid_;
+}
+
+/********************************************************/
+int socketSecureHandler::Connect(const TAddrList& addrs, TDuration Timeout) {
+ IsValid_ = false;
+
+ int ret = socketRegularHandler::Connect(addrs, Timeout);
+ if (ret)
+ return ret;
+
+ gnutls_certificate_allocate_credentials(&Credits_);
+ gnutls_init(&Session_, GNUTLS_CLIENT);
+ gnutls_set_default_priority(Session_);
+ gnutls_credentials_set(Session_, GNUTLS_CRD_CERTIFICATE, Credits_);
+
+ SOCKET fd = Socket_;
+ gnutls_transport_set_ptr(Session_, (gnutls_transport_ptr)fd);
+
+ ret = gnutls_handshake(Session_);
+
+ if (ret < 0) {
+ fprintf(stderr, "*** Handshake failed\n");
+ gnutls_perror(ret);
+
+ gnutls_deinit(Session_);
+ if (Credits_) {
+ gnutls_certificate_free_credentials(Credits_);
+ Credits_ = 0;
+ }
+ return 1;
+ }
+
+ IsValid_ = true;
+ return !IsValid_;
+}
+
+/********************************************************/
+void socketSecureHandler::Disconnect() {
+ if (IsValid_) {
+ gnutls_bye(Session_, GNUTLS_SHUT_RDWR);
+ IsValid_ = false;
+ gnutls_deinit(Session_);
+ }
+
+ if (Credits_) {
+ gnutls_certificate_free_credentials(Credits_);
+ Credits_ = 0;
+ }
+
+ socketRegularHandler::Disconnect();
+}
+
+/********************************************************/
+void socketSecureHandler::shutdown() {
+}
+
+/********************************************************/
+bool socketSecureHandler::send(const char* message, ssize_t messlen) {
+ if (!IsValid_)
+ return false;
+ ssize_t rv = gnutls_record_send(Session_, message, messlen);
+ return rv >= 0;
+}
+
+/********************************************************/
+bool socketSecureHandler::peek() {
+ //ssize_t rv = gnutls_record_check_pending(mSession);
+ //return rv>0;
+ return true;
+}
+
+/********************************************************/
+ssize_t socketSecureHandler::read(void* buffer, ssize_t buflen) {
+ if (!IsValid_)
+ return false;
+ return gnutls_record_recv(Session_, (char*)buffer, buflen);
+}
+
+#endif
+
+/************************************************************/
+socketAbstractHandler* socketHandlerFactory::chooseHandler(const THttpURL& url) {
+ if (url.IsValidGlobal() && url.GetScheme() == THttpURL::SchemeHTTP)
+ return new socketRegularHandler;
+
+#ifdef USE_GNUTLS
+ if (url.IsValidGlobal() && url.GetScheme() == THttpURL::SchemeHTTPS)
+ return new socketSecureHandler;
+#endif
+
+ return nullptr;
+}
+
+/************************************************************/
+socketHandlerFactory socketHandlerFactory::sInstance;
+/************************************************************/
diff --git a/library/cpp/http/fetch/httpagent.h b/library/cpp/http/fetch/httpagent.h
new file mode 100644
index 0000000000..96475cc05d
--- /dev/null
+++ b/library/cpp/http/fetch/httpagent.h
@@ -0,0 +1,316 @@
+#pragma once
+
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+
+#include <library/cpp/uri/http_url.h>
+#include <util/datetime/base.h>
+#include <util/network/hostip.h>
+#include <util/network/ip.h>
+#include <util/network/sock.h>
+#include <util/generic/scope.h>
+#include <util/generic/utility.h>
+#include <util/string/cast.h>
+
+#include "exthttpcodes.h"
+#include "sockhandler.h"
+
+class TIpResolver {
+public:
+ TAddrList Resolve(const char* host, TIpPort port) const {
+ try {
+ TAddrList result;
+ TNetworkAddress na(host, port);
+ for (auto i = na.Begin(); i != na.End(); ++i) {
+ const struct addrinfo& ai = *i;
+ switch (ai.ai_family) {
+ case AF_INET:
+ result.push_back(new NAddr::TIPv4Addr(*(sockaddr_in*)ai.ai_addr));
+ break;
+ case AF_INET6:
+ result.push_back(new NAddr::TIPv6Addr(*(sockaddr_in6*)ai.ai_addr));
+ break;
+ }
+ }
+ return result;
+ } catch (const TNetworkResolutionError&) {
+ }
+ return TAddrList();
+ }
+};
+
+namespace NResolverHelpers {
+ Y_HAS_MEMBER(Resolve);
+
+ template <typename TResolver>
+ std::enable_if_t<TClassHasResolve<TResolver>::value, TAddrList> Resolve(const TResolver& r, const char* host, TIpPort port) {
+ return r.Resolve(host, port);
+ }
+
+ template <typename TResolver>
+ std::enable_if_t<!TClassHasResolve<TResolver>::value, TAddrList> Resolve(const TResolver& r, const char* host, TIpPort port) {
+ ui32 ip = 0;
+ if (r.GetHostIP(host, &ip)) {
+ // error
+ return TAddrList();
+ }
+ if (!ip) {
+ return TAddrList();
+ }
+
+ return TAddrList::MakeV4Addr(ip, port);
+ }
+}
+
+template <typename TBase>
+class TIpResolverWrapper {
+private:
+ TBase Base;
+
+public:
+ TIpResolverWrapper() = default;
+
+ template <typename T>
+ TIpResolverWrapper(T&& base)
+ : Base(std::forward(base))
+ {
+ }
+
+ TAddrList Resolve(const char* host, TIpPort port) const {
+ return NResolverHelpers::Resolve(Base, host, port);
+ }
+};
+
+template <class TSocketHandler = TSimpleSocketHandler, class TDnsClient = TIpResolver>
+class THttpAgent {
+public:
+ THttpAgent()
+ : Persistent(0)
+ , Timeout(TDuration::MicroSeconds(150))
+ , Hostheader(nullptr)
+ , Footer(nullptr)
+ , AltFooter(nullptr)
+ , PostData(nullptr)
+ , PostDataLen(0)
+ , Method(nullptr)
+ , MethodLen(0)
+ , HostheaderLen(0)
+ {
+ SetIdentification("YandexSomething/1.0", "webadmin@yandex.ru");
+ }
+
+ ~THttpAgent() {
+ Disconnect();
+ free(Hostheader);
+ free(Footer);
+ }
+
+ void SetIdentification(const char* user_agent, const char* http_from) {
+ free(Footer);
+ size_t len = user_agent ? strlen(user_agent) + 15 : 0;
+ len += http_from ? strlen(http_from) + 9 : 0;
+ len += 3;
+ Footer = (char*)malloc(len);
+ if (user_agent)
+ strcat(strcat(strcpy(Footer, "User-Agent: "), user_agent), "\r\n");
+ if (http_from)
+ strcat(strcat(strcat(Footer, "From: "), http_from), "\r\n");
+ }
+
+ void SetUserAgentFooter(const char* altFooter) {
+ AltFooter = altFooter;
+ }
+
+ void SetPostData(const char* postData, size_t postDataLen) {
+ PostData = postData;
+ PostDataLen = postDataLen;
+ }
+
+ void SetMethod(const char* method, size_t methodLen) {
+ Method = method;
+ MethodLen = methodLen;
+ }
+
+ // deprecated
+ ui32 GetIp() const {
+ return Addrs.GetV4Addr().first;
+ }
+
+ int GetScheme() const {
+ return THttpURL::SchemeHTTP;
+ }
+ void SetTimeout(TDuration tim) {
+ Timeout = tim;
+ }
+
+ void SetConnectTimeout(TDuration timeout) {
+ ConnectTimeout = timeout;
+ }
+
+ int Disconnected() {
+ return !Persistent || !Socket.Good();
+ }
+
+ int SetHost(const char* hostname, TIpPort port) {
+ Disconnect();
+ TAddrList addrs = DnsClient.Resolve(hostname, port);
+ if (!addrs.size()) {
+ return 1;
+ }
+
+ SetHost(hostname, port, addrs);
+ return 0;
+ }
+
+ int SetHost(const char* hostname, TIpPort port, const TAddrList& addrs) {
+ Disconnect();
+ Addrs = addrs;
+ size_t reqHostheaderLen = strlen(hostname) + 20;
+ if (HostheaderLen < reqHostheaderLen) {
+ free(Hostheader);
+ Hostheader = (char*)malloc((HostheaderLen = reqHostheaderLen));
+ }
+ if (port == 80)
+ sprintf(Hostheader, "Host: %s\r\n", hostname);
+ else
+ sprintf(Hostheader, "Host: %s:%u\r\n", hostname, port);
+ pHostBeg = strchr(Hostheader, ' ') + 1;
+ pHostEnd = strchr(pHostBeg, '\r');
+ // convert hostname to lower case since some web server don't like
+ // uppper case (Task ROBOT-562)
+ for (char* p = pHostBeg; p < pHostEnd; p++)
+ *p = tolower(*p);
+ return 0;
+ }
+
+ // deprecated v4-only
+ int SetHost(const char* hostname, TIpPort port, ui32 ip) {
+ return SetHost(hostname, port, TAddrList::MakeV4Addr(ip, port));
+ }
+
+ void SetHostHeader(const char* host) {
+ size_t reqHostheaderLen = strlen(host) + 20;
+ if (HostheaderLen < reqHostheaderLen) {
+ delete[] Hostheader;
+ Hostheader = new char[(HostheaderLen = reqHostheaderLen)];
+ }
+ sprintf(Hostheader, "Host: %s\r\n", host);
+ }
+
+ void SetSocket(SOCKET fd) {
+ Socket.SetSocket(fd);
+ }
+
+ SOCKET PickOutSocket() {
+ return Socket.PickOutSocket();
+ }
+
+ void Disconnect() {
+ Socket.Disconnect();
+ }
+
+ ssize_t read(void* buffer, size_t buflen) {
+ return Socket.read(buffer, buflen);
+ }
+
+ int RequestGet(const char* url, const char* const* headers, int persistent = 1, bool head_request = false) {
+ if (!Addrs.size())
+ return HTTP_DNS_FAILURE;
+ char message[MessageMax];
+ ssize_t messlen = 0;
+ if (Method) {
+ strncpy(message, Method, MethodLen);
+ message[MethodLen] = ' ';
+ messlen = MethodLen + 1;
+ } else if (PostData) {
+ strcpy(message, "POST ");
+ messlen = 5;
+ } else if (head_request) {
+ strcpy(message, "HEAD ");
+ messlen = 5;
+ } else {
+ strcpy(message, "GET ");
+ messlen = 4;
+ }
+#define _AppendMessage(mes) messlen += Min(MessageMax - messlen, \
+ (ssize_t)strlcpy(message + messlen, (mes), MessageMax - messlen))
+ _AppendMessage(url);
+ _AppendMessage(" HTTP/1.1\r\n");
+ if (*url == '/') //if not then Host is a proxy
+ _AppendMessage(Hostheader);
+ _AppendMessage("Connection: ");
+ _AppendMessage(persistent ? "Keep-Alive\r\n" : "Close\r\n");
+ while (headers && *headers)
+ _AppendMessage(*headers++);
+ if (AltFooter)
+ _AppendMessage(AltFooter);
+ else
+ _AppendMessage(Footer);
+ _AppendMessage("\r\n");
+#undef _AppendMessage
+ if (messlen >= MessageMax)
+ return HTTP_HEADER_TOO_LARGE;
+
+ if (!Persistent)
+ Disconnect();
+ Persistent = persistent;
+ int connected = Socket.Good();
+ for (int attempt = !connected; attempt < 2; attempt++) {
+ const auto connectTimeout = ConnectTimeout ? ConnectTimeout : Timeout;
+ if (!Socket.Good() && Socket.Connect(Addrs, connectTimeout))
+ return HTTP_CONNECT_FAILED;
+
+ int sendOk = Socket.send(message, messlen);
+ if (sendOk && PostData && PostDataLen)
+ sendOk = Socket.send(PostData, PostDataLen);
+ if (!sendOk) {
+ int err = errno;
+ Disconnect();
+ errno = err;
+ continue;
+ }
+
+ if (!Socket.peek()) {
+ int err = errno;
+ Disconnect();
+ if (err == EINTR) {
+ errno = err;
+ return HTTP_INTERRUPTED;
+ }
+ } else {
+ if (!persistent)
+ Socket.shutdown();
+ return 0;
+ }
+ }
+ return connected ? HTTP_CONNECTION_LOST : HTTP_CONNECT_FAILED;
+ }
+
+protected:
+ TSocketHandler Socket;
+ TIpResolverWrapper<TDnsClient> DnsClient;
+ TAddrList Addrs;
+ int Persistent;
+ TDuration Timeout;
+ TDuration ConnectTimeout;
+ char *Hostheader, *Footer, *pHostBeg, *pHostEnd;
+ const char* AltFooter; // alternative footer can be set by the caller
+ const char* PostData;
+ size_t PostDataLen;
+ const char* Method;
+ size_t MethodLen;
+ unsigned short HostheaderLen;
+ static const ssize_t MessageMax = 32768;
+};
+
+struct TNoTimer {
+ inline void OnBeforeSend() {
+ }
+ inline void OnAfterSend() {
+ }
+ inline void OnBeforeRecv() {
+ }
+ inline void OnAfterRecv() {
+ }
+};
diff --git a/library/cpp/http/fetch/httpfetcher.h b/library/cpp/http/fetch/httpfetcher.h
new file mode 100644
index 0000000000..7fc251afd2
--- /dev/null
+++ b/library/cpp/http/fetch/httpfetcher.h
@@ -0,0 +1,171 @@
+#pragma once
+
+#ifdef _MSC_VER
+#include <io.h>
+#endif
+
+#include <library/cpp/http/misc/httpdate.h>
+
+#include "httpagent.h"
+#include "httpparser.h"
+
+struct TFakeBackup {
+ int Write(void* /*buf*/, size_t /*size*/) {
+ return 0;
+ }
+};
+
+template <size_t bufsize = 5000>
+struct TFakeAlloc {
+ void Shrink(void* /*buf*/, size_t /*size*/) {
+ }
+ void* Grab(size_t /*min*/, size_t* real) {
+ *real = bufsize;
+ return buf;
+ }
+ char buf[bufsize];
+};
+
+template <typename TAlloc = TFakeAlloc<>,
+ typename TCheck = TFakeCheck<>,
+ typename TWriter = TFakeBackup,
+ typename TAgent = THttpAgent<>>
+class THttpFetcher: public THttpParser<TCheck>, public TAlloc, public TWriter, public TAgent {
+public:
+ static const size_t TCP_MIN = 1500;
+ static int TerminateNow;
+
+ THttpFetcher()
+ : THttpParser<TCheck>()
+ , TAlloc()
+ , TWriter()
+ , TAgent()
+ {
+ }
+
+ virtual ~THttpFetcher() {
+ }
+
+ int Fetch(THttpHeader* header, const char* path, const char* const* headers, int persistent, bool head_request = false) {
+ int ret = 0;
+ int fetcherr = 0;
+
+ THttpParser<TCheck>::Init(header, head_request);
+ const char* scheme = HttpUrlSchemeKindToString((THttpURL::TSchemeKind)TAgent::GetScheme());
+ size_t schemelen = strlen(scheme);
+ if (*path == '/') {
+ header->base = TStringBuf(scheme, schemelen);
+ header->base += TStringBuf("://", 3);
+ header->base += TStringBuf(TAgent::pHostBeg, TAgent::pHostEnd - TAgent::pHostBeg);
+ header->base += path;
+ } else {
+ if (strlen(path) >= FETCHER_URL_MAX) {
+ header->error = HTTP_URL_TOO_LARGE;
+ return 0;
+ }
+ header->base = path;
+ }
+
+ if ((ret = TAgent::RequestGet(path, headers, persistent, head_request))) {
+ header->error = (i16)ret;
+ return 0;
+ }
+
+ bool inheader = 1;
+ void *bufptr = nullptr, *buf = nullptr, *parsebuf = nullptr;
+ ssize_t got;
+ size_t buffree = 0, bufsize = 0, buflen = 0;
+ size_t maxsize = TCheck::GetMaxHeaderSize();
+ do {
+ if (buffree < TCP_MIN) {
+ if (buf) {
+ TAlloc::Shrink(buf, buflen - buffree);
+ if (TWriter::Write(buf, buflen - buffree) < 0) {
+ buf = nullptr;
+ ret = EIO;
+ break;
+ }
+ }
+ if (!(buf = TAlloc::Grab(TCP_MIN, &buflen))) {
+ ret = ENOMEM;
+ break;
+ }
+ bufptr = buf;
+ buffree = buflen;
+ }
+ if ((got = TAgent::read(bufptr, buffree)) < 0) {
+ fetcherr = errno;
+ if (errno == EINTR)
+ header->error = HTTP_INTERRUPTED;
+ else if (errno == ETIMEDOUT)
+ header->error = HTTP_TIMEDOUT_WHILE_BYTES_RECEIVING;
+ else
+ header->error = HTTP_CONNECTION_LOST;
+
+ break;
+ }
+
+ parsebuf = bufptr;
+ bufptr = (char*)bufptr + got;
+ bufsize += got;
+ buffree -= got;
+
+ THttpParser<TCheck>::Parse(parsebuf, got);
+
+ if (header->error)
+ break; //if ANY error ocurred we will stop download that file or will have unprognosed stream position until MAX size reached
+
+ if (inheader && THttpParser<TCheck>::GetState() != THttpParser<TCheck>::hp_in_header) {
+ inheader = 0;
+ if (TCheck::Check(header))
+ break;
+ if (header->header_size > (long)maxsize) {
+ header->error = HTTP_HEADER_TOO_LARGE;
+ break;
+ }
+ }
+ if (!inheader) {
+ maxsize = TCheck::GetMaxBodySize(header);
+ }
+ if (header->http_status >= HTTP_EXTENDED)
+ break;
+ if (bufsize > maxsize) {
+ header->error = inheader ? HTTP_HEADER_TOO_LARGE : HTTP_BODY_TOO_LARGE;
+ break;
+ }
+ if (TerminateNow) {
+ header->error = HTTP_INTERRUPTED;
+ break;
+ }
+ } while (THttpParser<TCheck>::GetState() > THttpParser<TCheck>::hp_eof);
+
+ i64 Adjustment = 0;
+ if (!header->error) {
+ if (header->transfer_chunked) {
+ Adjustment = header->header_size + header->entity_size - bufsize - 1;
+ } else if (header->content_length >= 0) {
+ Adjustment = header->header_size + header->content_length - bufsize;
+ }
+ if (Adjustment > 0)
+ Adjustment = 0;
+ }
+
+ if (buf) {
+ TAlloc::Shrink(buf, buflen - buffree + Adjustment);
+
+ if (TWriter::Write(buf, buflen - buffree) < 0)
+ ret = EIO;
+ }
+ TCheck::CheckEndDoc(header);
+ if (ret || header->error || header->http_status >= HTTP_EXTENDED || header->connection_closed) {
+ TAgent::Disconnect();
+ if (!fetcherr)
+ fetcherr = errno;
+ }
+ errno = fetcherr;
+ return ret;
+ }
+};
+
+template <typename TAlloc, typename TCheck, typename TWriter, typename TAgent>
+int THttpFetcher<TAlloc, TCheck, TWriter, TAgent>::TerminateNow = 0;
diff --git a/library/cpp/http/fetch/httpfsm.h b/library/cpp/http/fetch/httpfsm.h
new file mode 100644
index 0000000000..c4abdcd0d2
--- /dev/null
+++ b/library/cpp/http/fetch/httpfsm.h
@@ -0,0 +1,104 @@
+#pragma once
+
+#include "httpheader.h"
+
+#include <util/system/maxlen.h>
+#include <util/datetime/parser.h>
+
+#include <time.h>
+
+struct THttpHeaderParser {
+ static constexpr int ErrFirstlineTypeMismatch = -3;
+ static constexpr int ErrHeader = -2;
+ static constexpr int Err = -1;
+ static constexpr int Final = 0;
+ static constexpr int NeedMore = 1;
+ static constexpr int Accepted = 2;
+
+ int Execute(const void* inBuf, size_t len) {
+ return execute((unsigned char*)inBuf, (int)len);
+ }
+
+ int Execute(TStringBuf str) {
+ return Execute(str.data(), str.size());
+ }
+
+ int Init(THttpHeader* h) {
+ int ret = Init((THttpBaseHeader*)(h));
+ hd = h;
+ hd->Init();
+ hreflangpos = hd->hreflangs;
+ hreflangspace = HREFLANG_MAX;
+ return ret;
+ }
+
+ int Init(THttpAuthHeader* h) {
+ int ret = Init((THttpHeader*)(h));
+ auth_hd = h;
+ return ret;
+ }
+ int Init(THttpRequestHeader* h) {
+ int ret = Init((THttpBaseHeader*)(h));
+ request_hd = h;
+ request_hd->Init();
+ return ret;
+ }
+
+ THttpHeader* hd;
+ long I;
+ int Dc;
+ TDateTimeFieldsDeprecated DateTimeFields;
+ char buf[FETCHER_URL_MAX];
+ size_t buflen;
+ char* lastchar;
+
+ const unsigned char* langstart;
+ size_t langlen;
+
+ char* hreflangpos;
+ size_t hreflangspace;
+
+ bool AcceptingXRobots;
+
+ THttpAuthHeader* auth_hd;
+ THttpRequestHeader* request_hd;
+
+private:
+ THttpBaseHeader* base_hd;
+ int cs;
+
+private:
+ int Init(THttpBaseHeader* header) {
+ base_hd = header;
+ auth_hd = nullptr;
+ request_hd = nullptr;
+ hd = nullptr;
+ init();
+ return 0;
+ }
+
+ int execute(unsigned char* inBuf, int len);
+ void init();
+};
+
+struct THttpChunkParser {
+ int Execute(const void* inBuf, int len) {
+ return execute((unsigned char*)inBuf, len);
+ }
+
+ int Init() {
+ init();
+ return 0;
+ }
+
+ int chunk_length;
+ char* lastchar;
+ long I;
+ int Dc;
+ i64 cnt64;
+
+private:
+ int cs;
+ int execute(unsigned char* inBuf, int len);
+ void init();
+};
diff --git a/library/cpp/http/fetch/httpfsm.rl6 b/library/cpp/http/fetch/httpfsm.rl6
new file mode 100644
index 0000000000..eab0328b18
--- /dev/null
+++ b/library/cpp/http/fetch/httpfsm.rl6
@@ -0,0 +1,684 @@
+#include <stdio.h>
+#include <time.h>
+
+#include <library/cpp/charset/doccodes.h>
+#include <library/cpp/charset/codepage.h>
+#include <library/cpp/http/misc/httpcodes.h>
+#include <util/datetime/base.h>
+#include <util/generic/ylimits.h>
+#include <algorithm> // max
+
+#include <library/cpp/http/fetch/httpheader.h>
+#include <library/cpp/http/fetch/httpfsm.h>
+
+#ifdef _MSC_VER
+#pragma warning(disable: 4702) // unreachable code
+#endif
+
+#define c(i) I = i;
+#define m(i) I = std::max(I, (long)i);
+
+static inline int X(unsigned char c) {
+ return (c >= 'A' ? ((c & 0xdf) - 'A' + 10) : (c - '0'));
+}
+
+template <typename x>
+static inline void guard(x &val) {
+ val = (val >= -1) ? -4 - val : -2; // f(-2) = -2
+}
+
+template <typename x>
+static inline void setguarded(x &val, long cnt) {
+ val = (val == -4 - -1 || cnt == -4 -val) ? cnt : -2;
+}
+
+////////////////////////////////////////////////////////////////////
+/// HTTP PARSER
+////////////////////////////////////////////////////////////////////
+
+%%{
+machine http_header_parser;
+
+include HttpDateTimeParser "../../../../util/datetime/parser.rl6";
+
+alphtype unsigned char;
+
+################# 2.2 Basic Rules #################
+eol = '\r'? '\n';
+ws = [ \t];
+lw = '\r'? '\n'? ws;
+separator = [()<>@,;:\\"/\[\]?={}];
+token_char = [!-~] - separator; # http tokens chars
+url_char = [!-~] - ["<>\[\]\\^`{}|]; # uric chars
+text_char = ws | 33..126 | 128..255;
+any_text_char = any - [\r\n];
+
+lws = lw*;
+eoh = lws eol;
+token = token_char+;
+ex_token = (token_char | ws)* token_char;
+text = (text_char | lw)*;
+any_text = (any_text_char | lw)*;
+def = lws ':' lws;
+
+action clear_buf { buflen = 0; }
+action update_buf { if (buflen < sizeof(buf)) buf[buflen++] = fc; }
+
+###################################################
+############ response status line #################
+action set_minor { base_hd->http_minor = I; }
+action set_status {
+ if (hd) {
+ hd->http_status = I;
+ }
+ if (request_hd) {
+ return -3;
+ }
+}
+
+status_code = int3;
+http_major = int;
+http_minor = int;
+reason_phrase = ws+ text_char*;
+http_version = "http/"i http_major '.' http_minor %set_minor;
+response_status_line = http_version ws+ status_code reason_phrase? eol %set_status;
+
+############ request status line #################
+action set_request_uri {
+ if (request_hd && buflen < FETCHER_URL_MAX) {
+ if (!request_hd->request_uri.empty()) {
+ return -2;
+ }
+ request_hd->request_uri =TStringBuf(buf, buflen);
+ }
+}
+action set_http_method {
+ if (request_hd) {
+ request_hd->http_method = I;
+ }
+ if (hd) {
+ return -3;
+ }
+}
+
+http_extension_method = token;
+http_method = ("options"i %{c(0)} @1
+ | "get"i %{c(1)} @1
+ | "head"i %{c(2)} @1
+ | "post"i %{c(3)} @1
+ | "put"i %{c(4)} @1
+ | "delete"i %{c(5)} @1
+ | "trace"i %{c(6)} @1
+ | "connect"i %{c(7)} @1
+ | http_extension_method %{c(8)} $0)
+ %set_http_method;
+request_uri = (token_char | separator)+ >clear_buf $update_buf
+ %set_request_uri;
+request_status_line = http_method ws+ request_uri ws+ http_version eoh;
+
+################# connection ######################
+action beg_connection { guard(base_hd->connection_closed); I = -1; }
+action set_connection { setguarded(base_hd->connection_closed, I); }
+
+c_token = "close"i %{m(1)}
+ | "keep-alive"i %{m(0)};
+c_tokenlist = c_token (lws ',' lws c_token)?;
+connection = "connection"i def %beg_connection c_tokenlist eoh %set_connection;
+
+################# content-encoding ################
+action beg_content_encoding { I = HTTP_COMPRESSION_ERROR; }
+action set_content_encoding { base_hd->compression_method =
+ ((base_hd->compression_method == HTTP_COMPRESSION_UNSET ||
+ base_hd->compression_method == I) ?
+ I : (int)HTTP_COMPRESSION_ERROR); }
+
+ce_tokenlist = "identity"i %{c(HTTP_COMPRESSION_IDENTITY)}
+ | "gzip"i %{c(HTTP_COMPRESSION_GZIP)}
+ | "x-gzip"i %{c(HTTP_COMPRESSION_GZIP)}
+ | "deflate"i %{c(HTTP_COMPRESSION_DEFLATE)}
+ | "compress"i %{c(HTTP_COMPRESSION_COMPRESS)}
+ | "x-compress"i %{c(HTTP_COMPRESSION_COMPRESS)};
+content_encoding = "content-encoding"i def %beg_content_encoding ce_tokenlist eoh %set_content_encoding;
+
+################# transfer-encoding ###############
+action beg_encoding { guard(base_hd->transfer_chunked); }
+action set_encoding { setguarded(base_hd->transfer_chunked, I); }
+
+e_tokenlist = "identity"i %{c(0)}
+ | "chunked"i %{c(1)};
+transfer_encoding = "transfer-encoding"i def %beg_encoding e_tokenlist eoh %set_encoding;
+
+################# content-length ##################
+action beg_content_length { guard(base_hd->content_length); }
+action set_content_length { setguarded(base_hd->content_length, I); }
+
+content_length = "content-length"i def %beg_content_length int eoh %set_content_length;
+
+################# content-range ###################
+action beg_content_range_start { guard(base_hd->content_range_start); I = -1; }
+action set_content_range_start { setguarded(base_hd->content_range_start, I); }
+action beg_content_range_end { guard(base_hd->content_range_end); I = -1; }
+action set_content_range_end { setguarded(base_hd->content_range_end, I); }
+action beg_content_range_el { guard(base_hd->content_range_entity_length); I = -1; }
+action set_content_range_el { setguarded(base_hd->content_range_entity_length, I); }
+
+content_range = "content-range"i def "bytes"i sp %beg_content_range_start int '-' %set_content_range_start
+ %beg_content_range_end int '/' %set_content_range_end
+ %beg_content_range_el int eoh %set_content_range_el;
+
+################# accept-ranges ###################
+action beg_accept_ranges {
+ if (hd) {
+ guard(hd->accept_ranges);
+ I = -1;
+ }
+}
+action set_accept_ranges { if (hd) setguarded(hd->accept_ranges, I); }
+
+ar_tokenlist = "bytes"i %{c(1)}
+ | "none"i %{c(0)};
+accept_ranges = "accept-ranges"i def %beg_accept_ranges ar_tokenlist eoh %set_accept_ranges;
+
+################# content-type ####################
+action beg_mime { guard(base_hd->mime_type); }
+action set_mime { setguarded(base_hd->mime_type, I); }
+action set_charset {
+ if (buflen < FETCHER_URL_MAX) {
+ buf[buflen++] = 0;
+ base_hd->charset = EncodingHintByName((const char*)buf);
+ }
+}
+
+mime_type = "text/plain"i %{c(MIME_TEXT)}
+ | "text/html"i %{c(MIME_HTML)}
+ | "application/pdf"i %{c(MIME_PDF)}
+ | "application/rtf"i %{c(MIME_RTF)}
+ | "text/rtf"i %{c(MIME_RTF)}
+ | "application/msword"i %{c(MIME_DOC)}
+ | "audio/mpeg"i %{c(MIME_MPEG)}
+ | "text/xml"i %{c(MIME_XML)}
+ | "application/xml"i %{c(MIME_XML)}
+ | "application/rss+xml"i %{c(MIME_RSS)}
+ | "application/rdf+xml"i %{c(MIME_RSS)}
+ | "application/atom+xml"i %{c(MIME_RSS)}
+ | "text/vnd.wap.wml"i %{c(MIME_WML)}
+ | "application/x-shockwave-flash"i %{c(MIME_SWF)}
+ | "application/vnd.ms-excel"i %{c(MIME_XLS)}
+ | "application/vnd.ms-powerpoint"i %{c(MIME_PPT)}
+ | "image/jpeg"i %{c(MIME_IMAGE_JPG)}
+ | "image/jpg"i %{c(MIME_IMAGE_JPG)}
+ | "image/pjpeg"i %{c(MIME_IMAGE_PJPG)}
+ | "image/png"i %{c(MIME_IMAGE_PNG)}
+ | "image/gif"i %{c(MIME_IMAGE_GIF)}
+ | "application/xhtml+xml"i %{c(MIME_XHTMLXML)}
+ | "application/vnd.openxmlformats-officedocument.wordprocessingml.document"i %{c(MIME_DOCX)}
+ | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"i %{c(MIME_XLSX)}
+ | "application/vnd.openxmlformats-officedocument.presentationml.presentation"i %{c(MIME_PPTX)}
+ | "application/vnd.oasis.opendocument.text"i %{c(MIME_ODT)}
+ | "application/vnd.oasis.opendocument.presentation"i %{c(MIME_ODP)}
+ | "application/vnd.oasis.opendocument.spreadsheet"i %{c(MIME_ODS)}
+ | "application/vnd.oasis.opendocument.graphics"i %{c(MIME_ODG)}
+ | "image/x-ms-bmp"i %{c(MIME_IMAGE_BMP)}
+ | "image/bmp"i %{c(MIME_IMAGE_BMP)}
+ | "audio/x-wav"i %{c(MIME_WAV)}
+ | ( "application/x-tar"i | "application/x-ustar"i | "application/x-gtar"i | "application/zip"i | "application/x-archive"i
+ | "application/x-bzip2"i | "application/x-rar"i ) %{c(MIME_ARCHIVE)}
+ | "application/x-dosexec"i %{c(MIME_EXE)}
+ | "application/x-gzip"i %{c(MIME_GZIP)}
+ | "application/json"i %{c(MIME_JSON)}
+ | ("application/javascript"i | "text/javascript"i) %{c(MIME_JAVASCRIPT)}
+ | "application/vnd.android.package-archive"i %{c(MIME_APK)}
+ | ("image/x-icon"i | "image/vnd.microsoft.icon"i) %{c(MIME_IMAGE_ICON)}
+ ;
+
+
+charset_name = token_char+ >clear_buf $update_buf;
+mime_param = "charset"i ws* '=' ws* '"'? charset_name '"'? %set_charset @2
+ | token ws* '=' ws* '"'? token '"'? @1
+ | text $0;
+mime_parms = (lws ';' lws mime_param)*;
+content_type = "content-type"i def %beg_mime mime_type mime_parms eoh %set_mime;
+
+################# last modified ###################
+action beg_modtime { guard(base_hd->http_time); }
+action set_modtime {
+ setguarded(base_hd->http_time, DateTimeFields.ToTimeT(-1));
+}
+
+last_modified = "last-modified"i def %beg_modtime http_date eoh %set_modtime;
+
+################# location ########################
+action set_location {
+ while (buflen > 0 && (buf[buflen - 1] == ' ' || buf[buflen - 1] == '\t')) {
+ buflen --;
+ }
+ if (hd && buflen < FETCHER_URL_MAX) {
+ hd->location = TStringBuf(buf, buflen);
+ }
+}
+
+action set_status_303{ if (hd) hd->http_status = 303; }
+
+url = url_char+ >clear_buf $update_buf;
+loc_url = any_text_char+ >clear_buf $update_buf;
+location = "location"i def loc_url eoh %set_location;
+refresh = "refresh"i def int ';' lws "url="i loc_url eoh %set_location;
+
+################# x-robots-tag ################
+action set_x_robots {
+ if (hd && AcceptingXRobots) {
+ if (I > 0)
+ hd->x_robots_tag |= I;
+
+ int pos = (I > 0 ? I : -I);
+ for (size_t i = 0; i < 5; ++i)
+ if (abs(pos) & (1 << i)) // permissive flags take priority
+ hd->x_robots_state[i] = (I < 0) ? '1' : (hd->x_robots_state[i] != '1') ? '0' : '1';
+ }
+}
+
+action accept_x_robots {
+ AcceptingXRobots = (bool)I;
+}
+
+x_robots_directive = "none"i %{c(3)} | "all"i %{c(-3)}
+ | "noindex"i %{c(1)} | "index"i %{c(-1)}
+ | "nofollow"i %{c(2)} | "follow"i %{c(-2)}
+ | "noarchive"i %{c(4)} | "archive"i %{c(-4)}
+ | "noyaca"i %{c(16)}
+ | "noodp"i %{c(8)};
+
+any_value = (any_text_char - [, \t])+ (lws (any_text_char - [, \t])+)*;
+any_key = (any_text_char - [:, \t])+ (lws (any_text_char - [:, \t])+)*;
+
+unavailable_after_directive = "unavailable_after"i def any_value;
+
+yandex_robot = "yandex"i | "yandexbot"i;
+other_robot = any_key - "unavailable_after"i - yandex_robot;
+robot_specifier = yandex_robot %{c(1)} | other_robot %{c(0)};
+
+x_robots_value = (robot_specifier def %accept_x_robots)? (unavailable_after_directive | (x_robots_directive %set_x_robots) | any_value? );
+
+x_robots_tag = "x-robots-tag"i def >{ AcceptingXRobots = true; } x_robots_value (lws ',' lws x_robots_value)* eoh;
+
+################# rel_canonical ###############
+action set_canonical {
+ if (hd && buflen < FETCHER_URL_MAX) {
+ hd->rel_canonical = TStringBuf(buf, buflen);
+ }
+}
+
+rel_canonical = "link"i def '<' url ">;"i lws "rel"i lws '=' lws "\"canonical\"" eoh %set_canonical;
+################# hreflang ###############
+action set_hreflang {
+ bool first = (hreflangpos == hd->hreflangs);
+ size_t len2 = (first ? 0 : 1) + langlen + 1 + buflen;
+ if (langlen && len2 < hreflangspace) {
+ if (!first) {
+ *(hreflangpos++) = '\t';
+ }
+ memcpy(hreflangpos, langstart, langlen);
+ hreflangpos += langlen;
+ *(hreflangpos++) = ' ';
+ memcpy(hreflangpos, buf, buflen);
+ hreflangpos += buflen;
+ *(hreflangpos) = 0;
+ hreflangspace -= len2;
+ }
+}
+
+action start_lang {
+ langstart = fpc;
+ langlen = 0;
+}
+action end_lang {
+ langlen = fpc - langstart;
+}
+hreflang_token = (token_char - ['])+;
+quote = ['"]?; #"
+lang = hreflang_token >start_lang %end_lang;
+
+hreflang = "link"i def '<' url '>' lws ";" lws
+ ( ( "rel"i lws '=' lws quote "alternate" quote lws ';' lws "hreflang"i lws '=' lws quote lang quote )
+ | ( "hreflang"i lws '=' lws quote lang quote lws ';' lws "rel"i lws '=' lws quote "alternate" quote ) )
+ eoh %set_hreflang;
+################# squid_error #################
+action set_squid_error {
+ hd->squid_error = 1;
+}
+
+squid_error = "X-Yandex-Squid-Error"i def any_text eoh %set_squid_error;
+
+################# auth ########################
+action init_auth {
+ if (auth_hd)
+ auth_hd->use_auth=true;
+}
+
+action update_auth_buf
+ { if (auth_hd && buflen < sizeof(buf)) buf[buflen++] = *fpc; }
+
+quoted_str = /"/ (text_char - /"/)* /"/ >2;
+auth_quoted_str = ( /"/ ( ( text_char - /"/ )* >clear_buf $update_auth_buf ) /"/ ) > 2;
+
+# do not support auth-int, too heavy procedure
+
+qop_auth_option = "auth"i @1 %{if(auth_hd) auth_hd->qop_auth = true; };
+
+qop_option = ( qop_auth_option @1 ) | (( token-"auth"i) $0 );
+
+auth_good_param = ( "nonce"i /=/ auth_quoted_str )
+ %{if (auth_hd && buflen < FETCHER_URL_MAX-1) {
+ buf[buflen++] = 0;
+ auth_hd->nonce = strdup((const char*)buf);
+ }}
+ | ( "realm"i /=/ auth_quoted_str )
+ %{if (auth_hd && buflen < FETCHER_URL_MAX-1) {
+ buf[buflen++] = 0;
+ auth_hd->realm = strdup((const char*)buf);
+ }}
+ | ( "opaque"i /=/ auth_quoted_str )
+ %{if (auth_hd && buflen < FETCHER_URL_MAX-1) {
+ buf[buflen++] = 0;
+ auth_hd->opaque = strdup((const char*)buf);
+ }}
+ | "stale"i /=/ "true"i
+ %{if (auth_hd) auth_hd->stale = true; }
+ | "algorithm"i /=/ "md5"i /-/ "sess"i
+ %{if (auth_hd) auth_hd->algorithm = 1; }
+ | ( "qop"i /="/ qop_option (ws* "," ws* qop_option)* /"/);
+
+auth_param = auth_good_param @1 |
+ ( (token - ( "nonce"i | "opaque"i | "realm"i | "qop"i ) )
+ /=/ (token | quoted_str ) ) $0;
+
+auth_params = auth_param ( ws* /,/ ws* auth_param )*;
+
+digest_challenge = ("digest"i %init_auth ws+ auth_params) |
+ ((token-"digest"i) text);
+
+auth = "www-authenticate"i def digest_challenge eoh;
+
+###################### host #######################
+action set_host {
+ if (request_hd && buflen < HOST_MAX) {
+ buf[buflen++] = 0;
+ if (request_hd->host[0] != 0) {
+ return -2;
+ }
+ memcpy(request_hd->host, buf, buflen);
+ }
+}
+
+host = (url_char | [:])* >clear_buf $update_buf;
+host_header = "host"i def host eoh %set_host;
+
+###################### from #######################
+action set_from {
+ if (request_hd && buflen < MAXWORD_LEN) {
+ buf[buflen++] = 0;
+ if (request_hd->from[0] != 0) {
+ return -2;
+ }
+ memcpy(request_hd->from, buf, buflen);
+ }
+}
+
+mailbox = (token "@" token) >clear_buf $update_buf;
+from_header = "from"i def mailbox eoh %set_from;
+
+################### user-agent ####################
+action set_user_agent {
+ if (request_hd && buflen < MAXWORD_LEN) {
+ buf[buflen++] = 0;
+ if (request_hd->user_agent[0] != 0) {
+ return -2;
+ }
+ memcpy(request_hd->user_agent, buf, buflen);
+ }
+}
+
+user_agent = any_text_char* >clear_buf $update_buf;
+user_agent_header = "user-agent"i def user_agent eoh %set_user_agent;
+
+############### x-yandex-langregion ################
+action set_langregion {
+ if (request_hd && buflen < MAX_LANGREGION_LEN) {
+ buf[buflen++] = 0;
+ if (request_hd->x_yandex_langregion[0] != 0) {
+ return -2;
+ }
+ memcpy(request_hd->x_yandex_langregion, buf, buflen);
+ }
+}
+
+langregion = any_text_char* >clear_buf $update_buf;
+langregion_header = "x-yandex-langregion"i def langregion eoh %set_langregion;
+
+############### x-yandex-sourcename ################
+action set_sourcename {
+ if (request_hd && buflen < MAXWORD_LEN) {
+ buf[buflen++] = 0;
+ if (request_hd->x_yandex_sourcename[0] != 0) {
+ return -2;
+ }
+ memcpy(request_hd->x_yandex_sourcename, buf, buflen);
+ }
+}
+
+sourcename = any_text_char* >clear_buf $update_buf;
+sourcename_header = "x-yandex-sourcename"i def sourcename eoh %set_sourcename;
+
+############### x-yandex-requesttype ###############
+action set_requesttype {
+ if (request_hd && buflen < MAXWORD_LEN) {
+ buf[buflen++] = 0;
+ if (request_hd->x_yandex_requesttype[0] != 0) {
+ return -2;
+ }
+ memcpy(request_hd->x_yandex_requesttype, buf, buflen);
+ }
+}
+
+requesttype = any_text_char* >clear_buf $update_buf;
+requesttype_header = "x-yandex-requesttype"i def requesttype eoh %set_requesttype;
+
+################ x-yandex-fetchoptions ###############
+action set_fetchoptions {
+ if (request_hd && buflen < MAXWORD_LEN) {
+ buf[buflen++] = 0;
+ if (request_hd->x_yandex_fetchoptions[0] != 0) {
+ return -2;
+ }
+ memcpy(request_hd->x_yandex_fetchoptions, buf, buflen);
+ }
+}
+
+fetchoptions = any_text_char* >clear_buf $update_buf;
+fetchoptions_header = "x-yandex-fetchoptions"i def fetchoptions eoh %set_fetchoptions;
+
+################ if-modified-since ################
+action set_if_modified_since {
+ if (request_hd) {
+ request_hd->if_modified_since = DateTimeFields.ToTimeT(-1);
+ }
+}
+
+if_modified_since = "if-modified-since"i def http_date eoh
+ %set_if_modified_since;
+
+################ retry-after ################
+action set_retry_after_withdate {
+ if (hd) {
+ hd->retry_after = DateTimeFields.ToTimeT(-1);
+ }
+}
+
+action set_retry_after_withdelta {
+ if (hd) {
+ hd->retry_after = TInstant::Now().Seconds() + I;
+ }
+}
+
+retry_after_withdate = "retry-after"i def http_date eoh
+ %set_retry_after_withdate;
+retry_after_withdelta = "retry-after"i def int eoh
+ %set_retry_after_withdelta;
+
+############## request-cache-control ##############
+action SETMAXAGE { if (request_hd) request_hd->max_age = I; }
+
+delta_seconds = int;
+cache_extension = token ("=" (token | quoted_str))?;
+request_cache_directive = "no-cache"i
+ | "no-store"i
+ | ("max-age"i "=" delta_seconds %SETMAXAGE)
+ | ("max-stale"i ("=" delta_seconds)?)
+ | ("min-fresh"i "=" delta_seconds)
+ | "non-transform"i
+ | "only-if-cached"i
+ | cache_extension;
+request_cache_control = "cache-control"i def request_cache_directive eoh;
+
+############ x-yandex-response-timeout #############
+
+action set_response_timeout {
+ if (request_hd) {
+ request_hd->x_yandex_response_timeout = I;
+ }
+}
+
+response_timeout = "x-yandex-response-timeout"i def int eoh
+ %set_response_timeout;
+
+############ x-yandex-request-priority #############
+
+action set_request_priority {
+ if (request_hd) {
+ request_hd->x_yandex_request_priority = I;
+ }
+}
+
+request_priority = "x-yandex-request-priority"i def int eoh
+ %set_request_priority;
+
+################# message header ##################
+other_header = ( ex_token - "www-authenticate"i ) def any_text eoh;
+message_header = other_header $0
+ | connection @1
+ | content_encoding @1
+ | transfer_encoding @1
+ | content_length @1
+ | content_type @1
+ | last_modified @1
+ | refresh @1
+ | content_range @1;
+response_header = message_header $0
+ | auth @1
+ | accept_ranges @1
+ | location @1
+ | x_robots_tag @1
+ | rel_canonical @1
+ | hreflang @1
+ | squid_error @1
+ | retry_after_withdate @1
+ | retry_after_withdelta @1;
+request_header = message_header $0
+ | from_header @1
+ | host_header @1
+ | user_agent_header @1
+ | sourcename_header @1
+ | requesttype_header @1
+ | langregion_header @1
+ | fetchoptions_header @1
+ | if_modified_since @1
+ | request_cache_control @1
+ | response_timeout @1
+ | request_priority @1;
+
+################# main ############################
+action accepted { lastchar = (char*)fpc; return 2; }
+
+main := ((response_status_line ('\r'? response_header)*)
+ | (request_status_line ('\r' ? request_header)*))
+ eol @accepted;
+
+}%%
+
+%% write data;
+
+int THttpHeaderParser::execute(unsigned char *inBuf, int len) {
+ const unsigned char *p = inBuf;
+ const unsigned char *pe = p + len;
+ %% write exec;
+ if (cs == http_header_parser_error)
+ return -1;
+ else if (cs == http_header_parser_first_final)
+ return 0;
+ else
+ return 1;
+}
+
+void THttpHeaderParser::init() {
+ %% write init;
+}
+
+%%{
+machine http_chunk_parser;
+
+alphtype unsigned char;
+
+action clear_hex { cnt64 = 0; }
+action update_hex { cnt64 = 16 * cnt64 + X(fc); if(cnt64 > Max<int>()) return -2; }
+action set_chunk { chunk_length = static_cast<int>(cnt64); }
+action accepted { lastchar = (char*)fpc; return 2; }
+
+eol = '\r'? '\n';
+ws = [ \t];
+sp = ' ';
+lw = '\r'? '\n'? ws;
+separator = [()<>@,;:\\"/\[\]?={}];
+token_char = [!-~] - separator; # http tokens chars
+url_char = [!-~] - ["<>\[\]\\^`{}|]; # uric chars
+text_char = ws | 33..127 | 160..255;
+
+lws = lw*;
+eoh = lws eol;
+token = token_char+;
+text = (text_char | lw)*;
+def = lws ':' lws;
+
+hex = (xdigit+) >clear_hex $update_hex;
+quoted_string = '"' ((text_char - '"') $0 | '\\"' @1)* '"';
+
+chunk_ext_val = token | quoted_string;
+chunk_ext_name = token;
+chunk_extension = ws* (';' chunk_ext_name ws* '=' ws* chunk_ext_val ws*)*;
+
+entity_header = token def text eoh;
+trailer = entity_header*;
+
+chunk = (hex - '0'+) chunk_extension? %set_chunk;
+last_chunk = '0'+ chunk_extension? eol trailer;
+main := eol (chunk $0 | last_chunk @1) eol @accepted;
+
+}%%
+
+%% write data;
+
+int THttpChunkParser::execute(unsigned char *inBuf, int len) {
+ const unsigned char *p = inBuf;
+ const unsigned char *pe = p + len;
+ %% write exec;
+ if (cs == http_chunk_parser_error)
+ return -1;
+ else if (cs == http_chunk_parser_first_final)
+ return 0;
+ else
+ return 1;
+}
+
+void THttpChunkParser::init() {
+ chunk_length = 0;
+ %% write init;
+}
diff --git a/library/cpp/http/fetch/httpfsm_ut.cpp b/library/cpp/http/fetch/httpfsm_ut.cpp
new file mode 100644
index 0000000000..b018e80101
--- /dev/null
+++ b/library/cpp/http/fetch/httpfsm_ut.cpp
@@ -0,0 +1,591 @@
+#include "httpfsm.h"
+#include "library-htfetch_ut_hreflang_in.h"
+#include "library-htfetch_ut_hreflang_out.h"
+
+#include <util/generic/ptr.h>
+#include <library/cpp/charset/doccodes.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+class THttpHeaderParserTestSuite: public TTestBase {
+ UNIT_TEST_SUITE(THttpHeaderParserTestSuite);
+ UNIT_TEST(TestRequestHeader);
+ UNIT_TEST(TestSplitRequestHeader);
+ UNIT_TEST(TestTrailingData);
+ UNIT_TEST(TestProxyRequestHeader);
+ UNIT_TEST(TestIncorrectRequestHeader);
+ UNIT_TEST(TestLastModified);
+ UNIT_TEST(TestLastModifiedCorrupted);
+ UNIT_TEST(TestResponseHeaderOnRequest);
+ UNIT_TEST(TestRequestHeaderOnResponse);
+ UNIT_TEST(TestXRobotsTagUnknownTags);
+ UNIT_TEST(TestXRobotsTagMyBot);
+ UNIT_TEST(TestXRobotsTagOtherBot);
+ UNIT_TEST(TestXRobotsTagUnavailableAfterAware);
+ UNIT_TEST(TestXRobotsTagUnavailableAfterWorks);
+ UNIT_TEST(TestXRobotsTagOverridePriority);
+ UNIT_TEST(TestXRobotsTagDoesNotBreakCharset);
+ UNIT_TEST(TestXRobotsTagAllowsMultiline);
+ UNIT_TEST(TestRelCanonical);
+ UNIT_TEST(TestHreflang);
+ UNIT_TEST(TestHreflangOnLongInput);
+ UNIT_TEST(TestMimeType);
+ UNIT_TEST(TestRepeatedContentEncoding);
+ UNIT_TEST_SUITE_END();
+
+private:
+ THolder<THttpHeaderParser> httpHeaderParser;
+
+private:
+ void TestStart();
+ void TestFinish();
+
+public:
+ void TestRequestHeader();
+ void TestSplitRequestHeader();
+ void TestTrailingData();
+ void TestProxyRequestHeader();
+ void TestIncorrectRequestHeader();
+ void TestLastModified();
+ void TestLastModifiedCorrupted();
+ void TestResponseHeaderOnRequest();
+ void TestRequestHeaderOnResponse();
+ void TestXRobotsTagUnknownTags();
+ void TestXRobotsTagMyBot();
+ void TestXRobotsTagOtherBot();
+ void TestXRobotsTagUnavailableAfterAware();
+ void TestXRobotsTagUnavailableAfterWorks();
+ void TestXRobotsTagOverridePriority();
+ void TestXRobotsTagDoesNotBreakCharset();
+ void TestXRobotsTagAllowsMultiline();
+ void TestRelCanonical();
+ void TestHreflang();
+ void TestHreflangOnLongInput();
+ void TestMimeType();
+ void TestRepeatedContentEncoding();
+};
+
+void THttpHeaderParserTestSuite::TestStart() {
+ httpHeaderParser.Reset(new THttpHeaderParser());
+}
+
+void THttpHeaderParserTestSuite::TestFinish() {
+ httpHeaderParser.Reset();
+}
+
+void THttpHeaderParserTestSuite::TestRequestHeader() {
+ TestStart();
+ THttpRequestHeader httpRequestHeader;
+ httpHeaderParser->Init(&httpRequestHeader);
+ const char* request = "GET /search?q=hi HTTP/1.1\r\n"
+ "Host: www.google.ru:8080\r\n\r\n";
+ i32 result = httpHeaderParser->Execute(request, strlen(request));
+ UNIT_ASSERT_EQUAL(result, 2);
+ UNIT_ASSERT_EQUAL(httpRequestHeader.http_method, HTTP_METHOD_GET);
+ UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.host, "www.google.ru:8080"), 0);
+ UNIT_ASSERT_EQUAL(httpRequestHeader.request_uri, "/search?q=hi");
+ UNIT_ASSERT_EQUAL(httpRequestHeader.GetUrl(), "http://www.google.ru:8080/search?q=hi");
+ UNIT_ASSERT_EQUAL(httpHeaderParser->lastchar - request + 1,
+ (i32)strlen(request));
+ UNIT_ASSERT_EQUAL(httpRequestHeader.x_yandex_response_timeout,
+ DEFAULT_RESPONSE_TIMEOUT);
+ UNIT_ASSERT_EQUAL(httpRequestHeader.x_yandex_request_priority,
+ DEFAULT_REQUEST_PRIORITY);
+ UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.x_yandex_sourcename, ""), 0);
+ UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.x_yandex_requesttype, ""), 0);
+ UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.x_yandex_fetchoptions, ""), 0);
+ TestFinish();
+ UNIT_ASSERT_EQUAL(httpRequestHeader.max_age, DEFAULT_MAX_AGE);
+}
+
+void THttpHeaderParserTestSuite::TestSplitRequestHeader() {
+ TestStart();
+ const char* request =
+ "GET /search?q=hi HTTP/1.1\r\n"
+ "Host: www.google.ru:8080 \r\n"
+ "\r\n";
+ const size_t rlen = strlen(request);
+
+ for (size_t n1 = 0; n1 < rlen; n1++) {
+ for (size_t n2 = n1; n2 < rlen; n2++) {
+ TString s1{request, 0, n1};
+ TString s2{request, n1, n2 - n1};
+ TString s3{request, n2, rlen - n2};
+ UNIT_ASSERT_EQUAL(s1 + s2 + s3, request);
+
+ THttpRequestHeader httpRequestHeader;
+ UNIT_ASSERT(0 == httpHeaderParser->Init(&httpRequestHeader));
+ i32 result = httpHeaderParser->Execute(s1);
+ UNIT_ASSERT_EQUAL(result, 1);
+ result = httpHeaderParser->Execute(s2);
+ UNIT_ASSERT_EQUAL(result, 1);
+ result = httpHeaderParser->Execute(s3);
+ UNIT_ASSERT_EQUAL(result, 2);
+
+ UNIT_ASSERT_EQUAL(httpRequestHeader.http_method, HTTP_METHOD_GET);
+ UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.host, "www.google.ru:8080"), 0);
+ UNIT_ASSERT_EQUAL(httpRequestHeader.request_uri, "/search?q=hi");
+ }
+ }
+
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestTrailingData() {
+ TestStart();
+ THttpRequestHeader httpRequestHeader;
+ UNIT_ASSERT(0 == httpHeaderParser->Init(&httpRequestHeader));
+ const char* request =
+ "GET /search?q=hi HTTP/1.1\r\n"
+ "Host: www.google.ru:8080\r\n"
+ "\r\n"
+ "high.ru";
+ i32 result = httpHeaderParser->Execute(request, strlen(request));
+ UNIT_ASSERT_EQUAL(result, 2);
+ UNIT_ASSERT_EQUAL(httpRequestHeader.http_method, HTTP_METHOD_GET);
+ UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.host, "www.google.ru:8080"), 0);
+ UNIT_ASSERT_EQUAL(httpRequestHeader.request_uri, "/search?q=hi");
+ UNIT_ASSERT_EQUAL(TString(httpHeaderParser->lastchar + 1), "high.ru");
+ UNIT_ASSERT_EQUAL(httpRequestHeader.http_minor, 1);
+ UNIT_ASSERT_EQUAL(httpRequestHeader.transfer_chunked, -1);
+ UNIT_ASSERT_EQUAL(httpRequestHeader.content_length, -1);
+ UNIT_ASSERT_EQUAL(httpRequestHeader.connection_closed, -1);
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestProxyRequestHeader() {
+ TestStart();
+ THttpRequestHeader httpRequestHeader;
+ httpHeaderParser->Init(&httpRequestHeader);
+ const char* request =
+ "GET http://www.google.ru:8080/search?q=hi HTTP/1.1\r\n"
+ "X-Yandex-Response-Timeout: 1000\r\n"
+ "X-Yandex-Request-Priority: 2\r\n"
+ "X-Yandex-Sourcename: orange\r\n"
+ "X-Yandex-Requesttype: userproxy\r\n"
+ "X-Yandex-FetchOptions: d;c\r\n"
+ "Cache-control: max-age=100\r\n"
+ "If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT\r\n"
+ "User-Agent: Yandex/1.01.001 (compatible; Win16; I)\r\n"
+ "From: webadmin@yandex.ru\r\n\r\n";
+ i32 result = httpHeaderParser->Execute(request, strlen(request));
+ UNIT_ASSERT_EQUAL(result, 2);
+ UNIT_ASSERT_EQUAL(httpRequestHeader.http_method, HTTP_METHOD_GET);
+ UNIT_ASSERT_EQUAL(httpRequestHeader.x_yandex_response_timeout, 1000);
+ UNIT_ASSERT_EQUAL(httpRequestHeader.x_yandex_request_priority, 2);
+ UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.x_yandex_sourcename, "orange"), 0);
+ UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.x_yandex_requesttype, "userproxy"), 0);
+ UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.x_yandex_fetchoptions, "d;c"), 0);
+ UNIT_ASSERT_EQUAL(httpRequestHeader.max_age, 100);
+ UNIT_ASSERT_VALUES_EQUAL(httpRequestHeader.if_modified_since,
+ TInstant::ParseIso8601Deprecated("1994-10-29 19:43:31Z").TimeT());
+ UNIT_ASSERT_EQUAL(httpRequestHeader.request_uri,
+ "http://www.google.ru:8080/search?q=hi");
+ UNIT_ASSERT(httpRequestHeader.GetUrl() ==
+ "http://www.google.ru:8080/search?q=hi");
+ UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.host, ""), 0);
+ UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.from, "webadmin@yandex.ru"), 0);
+ UNIT_ASSERT_EQUAL(strcmp(httpRequestHeader.user_agent,
+ "Yandex/1.01.001 (compatible; Win16; I)"),
+ 0);
+ UNIT_ASSERT_EQUAL(httpHeaderParser->lastchar - request + 1,
+ (i32)strlen(request));
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestIncorrectRequestHeader() {
+ TestStart();
+ THttpRequestHeader httpRequestHeader;
+ httpHeaderParser->Init(&httpRequestHeader);
+ const char* request = "GET /search?q=hi HTP/1.1\r\n"
+ "Host: www.google.ru:8080\r\n\r\n";
+ i32 result = httpHeaderParser->Execute(request, strlen(request));
+ UNIT_ASSERT(result != 2);
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestLastModified() {
+ TestStart();
+ THttpHeader h;
+ UNIT_ASSERT(0 == httpHeaderParser->Init(&h));
+ const char* headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html\r\n"
+ "Last-Modified: Thu, 13 Aug 2009 14:27:08 GMT\r\n\r\n";
+ UNIT_ASSERT(2 == httpHeaderParser->Execute(headers, strlen(headers)));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TInstant::ParseIso8601Deprecated("2009-08-13 14:27:08Z").TimeT(),
+ h.http_time);
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestLastModifiedCorrupted() {
+ TestStart();
+ THttpHeader h;
+ UNIT_ASSERT(0 == httpHeaderParser->Init(&h));
+ const char* headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html\r\n"
+ "Last-Modified: Thu, 13 Aug 2009 14:\r\n\r\n";
+ UNIT_ASSERT(2 == httpHeaderParser->Execute(headers, strlen(headers)));
+ UNIT_ASSERT(h.http_time < 0); // XXX: don't understand what is the proper value
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestXRobotsTagUnknownTags() {
+ TestStart();
+ THttpHeader httpHeader;
+ httpHeaderParser->Init(&httpHeader);
+ const char* headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html\r\n"
+ "x-robots-tag: asdfasdf asdf asdf,,, , noindex,noodpXXX , NOFOLLOW ,noodpnofollow\r\n\r\n";
+ i32 result = httpHeaderParser->Execute(headers, strlen(headers));
+ UNIT_ASSERT_EQUAL(result, 2);
+ UNIT_ASSERT_EQUAL(httpHeader.x_robots_tag, 3);
+ UNIT_ASSERT_EQUAL(httpHeader.x_robots_state, "00xxx");
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestXRobotsTagMyBot() {
+ TestStart();
+ THttpHeader httpHeader;
+ httpHeaderParser->Init(&httpHeader);
+ const char* headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html\r\n"
+ "x-robots-tag: yandex: noindex, nofollow\r\n"
+ "x-robots-tag: yandexbot: noarchive, noodp\r\n\r\n";
+ i32 result = httpHeaderParser->Execute(headers, strlen(headers));
+ UNIT_ASSERT_EQUAL(result, 2);
+ UNIT_ASSERT_EQUAL(httpHeader.x_robots_tag, 15);
+ UNIT_ASSERT_EQUAL(httpHeader.x_robots_state, "0000x");
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestXRobotsTagOtherBot() {
+ TestStart();
+ THttpHeader httpHeader;
+ httpHeaderParser->Init(&httpHeader);
+ const char* headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html\r\n"
+ "x-robots-tag: google: noindex, nofollow\r\n"
+ "x-robots-tag: googlebot: noarchive, noodp\r\n"
+ "x-robots-tag: !still(-other) bot_: foo, noyaca\r\n\r\n";
+ i32 result = httpHeaderParser->Execute(headers, strlen(headers));
+ UNIT_ASSERT_EQUAL(result, 2);
+ UNIT_ASSERT_EQUAL(httpHeader.x_robots_tag, 0);
+ UNIT_ASSERT_EQUAL(httpHeader.x_robots_state, "xxxxx");
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestXRobotsTagUnavailableAfterAware() {
+ TestStart();
+ THttpHeader httpHeader;
+ httpHeaderParser->Init(&httpHeader);
+ // проверяем только что unavailable_after ничего не ломает
+ const char* headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html\r\n"
+ "x-robots-tag: unavailable_after: 01 Jan 2999 00:00 UTC, noindex, nofollow\r\n"
+ "x-robots-tag: yandex: unavailable_after: 01 Jan 2999 00:00 UTC, noarchive, noodp\r\n\r\n";
+ i32 result = httpHeaderParser->Execute(headers, strlen(headers));
+ UNIT_ASSERT_EQUAL(result, 2);
+ UNIT_ASSERT_EQUAL(httpHeader.x_robots_tag, 15);
+ UNIT_ASSERT_EQUAL(httpHeader.x_robots_state, "0000x");
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestXRobotsTagUnavailableAfterWorks() {
+ TestStart();
+ THttpHeader httpHeader;
+ httpHeaderParser->Init(&httpHeader);
+ // пока не поддерживается
+ const char* headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html\r\n"
+ "x-robots-tag: unavailable_after: 01 Jan 2000 00:00 UTC\r\n\r\n";
+ i32 result = httpHeaderParser->Execute(headers, strlen(headers));
+ UNIT_ASSERT_EQUAL(result, 2);
+ //UNIT_ASSERT_EQUAL(httpHeader.x_robots_tag, 1);
+ //UNIT_ASSERT_EQUAL(httpHeader.x_robots_state, "0xxxx");
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestXRobotsTagOverridePriority() {
+ TestStart();
+ THttpHeader httpHeader;
+ httpHeaderParser->Init(&httpHeader);
+ const char* headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html\r\n"
+ "x-robots-tag: all, none\r\n\r\n";
+ i32 result = httpHeaderParser->Execute(headers, strlen(headers));
+ UNIT_ASSERT_EQUAL(result, 2);
+ UNIT_ASSERT_EQUAL(httpHeader.x_robots_state, "11xxx");
+ UNIT_ASSERT_EQUAL(httpHeader.x_robots_tag, 3); // NOTE legacy behavior, should be 0 as `all` overrides
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestXRobotsTagDoesNotBreakCharset() {
+ TestStart();
+ THttpHeader httpHeader;
+ httpHeaderParser->Init(&httpHeader);
+ const char* headers =
+ "HTTP/1.1 200 OK\r\n"
+ "X-Robots-Tag: noarchive\r\n"
+ "Content-Type: application/json; charset=utf-8\r\n\r\n";
+ i32 result = httpHeaderParser->Execute(headers, strlen(headers));
+ UNIT_ASSERT_EQUAL(result, 2);
+ UNIT_ASSERT_EQUAL(httpHeader.mime_type, static_cast<ui8>(MIME_JSON));
+ UNIT_ASSERT_EQUAL(httpHeader.charset, static_cast<ui8>(CODES_UTF8));
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestXRobotsTagAllowsMultiline() {
+ TestStart();
+ THttpHeader httpHeader;
+ httpHeaderParser->Init(&httpHeader);
+ const char* headers =
+ "HTTP/1.1 200 OK\r\n"
+ "X-Robots-Tag\r\n"
+ " :\r\n"
+ " unavailable_since\r\n"
+ " :\r\n"
+ " ,\r\n"
+ " unavailable_since\r\n"
+ " :\r\n"
+ " 01 Jan 2000\r\n"
+ " 00:00 UTC\r\n"
+ " ,\r\n"
+ " yandexbot\r\n"
+ " :\r\n"
+ " noindex\r\n"
+ " ,\r\n"
+ " garbage\r\n"
+ " ,\r\n"
+ " nofollow\r\n"
+ " ,\r\n"
+ " other\r\n"
+ " bot\r\n"
+ " :\r\n"
+ " noarchive\r\n"
+ " ,\r\n"
+ "Content-Type: application/json; charset=utf-8\r\n\r\n";
+ i32 result = httpHeaderParser->Execute(headers, strlen(headers));
+ UNIT_ASSERT_EQUAL(result, 2);
+ UNIT_ASSERT_EQUAL(httpHeader.x_robots_state, "00xxx");
+ UNIT_ASSERT_EQUAL(httpHeader.mime_type, static_cast<ui8>(MIME_JSON));
+ UNIT_ASSERT_EQUAL(httpHeader.charset, static_cast<ui8>(CODES_UTF8));
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestHreflang() {
+ TestStart();
+ THttpHeader httpHeader;
+ httpHeaderParser->Init(&httpHeader);
+ const char* headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html\r\n"
+ "link: <http://www.high.ru/>; rel='alternate'; hreflang='x-default'\r\n"
+ "link: <http://www.high.ru/en.html> ;rel = 'alternate' ;hreflang = en_GB \r\n"
+ "link: <http://www.high.ru/ru.html>;hreflang = ru_RU.KOI8-r ;rel = 'alternate' \r\n"
+ "\r\n";
+ i32 result = httpHeaderParser->Execute(headers, strlen(headers));
+ UNIT_ASSERT_VALUES_EQUAL(result, 2);
+ // UNIT_ASSERT_VALUES_EQUAL(strcmp(httpHeader.hreflangs, "x-default http://www.high.ru/;"), 0);
+ UNIT_ASSERT_VALUES_EQUAL(httpHeader.hreflangs, "x-default http://www.high.ru/\ten_GB http://www.high.ru/en.html\tru_RU.KOI8-r http://www.high.ru/ru.html");
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestHreflangOnLongInput() {
+ TestStart();
+ THttpHeader httpHeader;
+ httpHeaderParser->Init(&httpHeader);
+ TStringBuf testInput(hreflang_ut_in);
+ TStringBuf testOut(hreflang_ut_out);
+ i32 result = httpHeaderParser->Execute(testInput.data(), testInput.size());
+ UNIT_ASSERT_VALUES_EQUAL(result, 2);
+ UNIT_ASSERT_VALUES_EQUAL(httpHeader.hreflangs, testOut);
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestRelCanonical() {
+ TestStart();
+ THttpHeader httpHeader;
+ httpHeaderParser->Init(&httpHeader);
+ const char* headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html\r\n"
+ "Link: <http://yandex.ru>; rel = \"canonical\"\r\n\r\n";
+ i32 result = httpHeaderParser->Execute(headers, strlen(headers));
+ UNIT_ASSERT_EQUAL(result, 2);
+ UNIT_ASSERT_EQUAL(httpHeader.rel_canonical, "http://yandex.ru");
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestResponseHeaderOnRequest() {
+ TestStart();
+ THttpHeader httpHeader;
+ httpHeaderParser->Init(&httpHeader);
+ const char* request = "GET /search?q=hi HTP/1.1\r\n"
+ "Host: www.google.ru:8080\r\n\r\n";
+ i32 result = httpHeaderParser->Execute(request, strlen(request));
+ UNIT_ASSERT_EQUAL(result, -3);
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestRequestHeaderOnResponse() {
+ TestStart();
+ THttpRequestHeader httpRequestHeader;
+ httpHeaderParser->Init(&httpRequestHeader);
+ const char* response = "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html\r\n"
+ "Last-Modified: Thu, 13 Aug 2009 14:\r\n\r\n";
+ i32 result = httpHeaderParser->Execute(response, strlen(response));
+ UNIT_ASSERT_EQUAL(result, -3);
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestMimeType() {
+ TestStart();
+ THttpHeader httpHeader;
+ httpHeaderParser->Init(&httpHeader);
+ const char* headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: application/json; charset=utf-8\r\n\r\n";
+ i32 result = httpHeaderParser->Execute(headers, strlen(headers));
+ UNIT_ASSERT_EQUAL(result, 2);
+ UNIT_ASSERT_EQUAL(httpHeader.mime_type, static_cast<ui8>(MIME_JSON));
+ UNIT_ASSERT_EQUAL(httpHeader.charset, static_cast<ui8>(CODES_UTF8));
+ TestFinish();
+}
+
+void THttpHeaderParserTestSuite::TestRepeatedContentEncoding() {
+ TestStart();
+ THttpHeader httpHeader;
+ httpHeaderParser->Init(&httpHeader);
+ const char *headers =
+ "HTTP/1.1 200 OK\r\n"
+ "Server: nginx\r\n"
+ "Date: Mon, 15 Oct 2018 10:40:44 GMT\r\n"
+ "Content-Type: text/plain\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "Connection: keep-alive\r\n"
+ "Last-Modified: Mon, 15 Oct 2018 03:48:54 GMT\r\n"
+ "ETag: W/\"5bc40e26-a956d\"\r\n"
+ "X-Autoru-LB: lb-03-sas.prod.vertis.yandex.net\r\n"
+ "Content-Encoding: gzip\r\n"
+ "Content-Encoding: gzip\r\n"
+ "X-UA-Bot: 1\r\n"
+ "\r\n";
+ i32 result = httpHeaderParser->Execute(headers, strlen(headers));
+ UNIT_ASSERT_EQUAL(result, 2);
+ UNIT_ASSERT_EQUAL(httpHeader.error, 0);
+ UNIT_ASSERT_EQUAL(httpHeader.compression_method, 3);
+ TestFinish();
+}
+
+UNIT_TEST_SUITE_REGISTRATION(THttpHeaderParserTestSuite);
+
+Y_UNIT_TEST_SUITE(TestHttpChunkParser) {
+ static THttpChunkParser initParser() {
+ THttpChunkParser parser;
+ parser.Init();
+ return parser;
+ }
+
+ static THttpChunkParser parseByteByByte(const TStringBuf& blob, const TVector<int>& states) {
+ UNIT_ASSERT(states.size() <= blob.size());
+ THttpChunkParser parser{initParser()};
+ for (size_t n = 0; n < states.size(); n++) {
+ const TStringBuf d{blob, n, 1};
+ int code = parser.Execute(d.data(), d.size());
+ Cout << TString(d).Quote() << " " << code << Endl;
+ UNIT_ASSERT_EQUAL(code, states[n]);
+ }
+ return parser;
+ }
+
+ static THttpChunkParser parseBytesWithLastState(const TStringBuf& blob, const int last_state) {
+ TVector<int> states(blob.size() - 1, 1);
+ states.push_back(last_state);
+ return parseByteByByte(blob, states);
+ }
+
+ Y_UNIT_TEST(TestWithoutEolHead) {
+ const TStringBuf blob{
+ "4\r\n"
+ "____\r\n"};
+ TVector<int> states{
+ -1, /* 1, -1,
+ 1, -1, 1, -1, 1, -1 */};
+ // as soon as error happens parser state should be considered
+ // undefined, state is meaningless after the very first `-1`
+ // moreover, testenv produces `states[1] == -1` for this input and
+ // my local build produces `states[1] == 1`.
+ parseByteByByte(blob, states);
+ }
+
+ Y_UNIT_TEST(TestTrivialChunk) {
+ const TStringBuf blob{
+ "\r\n"
+ "4\r\n"};
+ THttpChunkParser parser(parseBytesWithLastState(blob, 2));
+ UNIT_ASSERT_EQUAL(parser.chunk_length, 4);
+ UNIT_ASSERT_EQUAL(parser.cnt64, 4);
+ }
+
+ Y_UNIT_TEST(TestNegative) {
+ const TStringBuf blob{
+ "\r\n"
+ "-1"};
+ TVector<int> states{
+ 1, 1,
+ -1,
+ /* 1 */};
+ parseByteByByte(blob, states);
+ }
+
+ Y_UNIT_TEST(TestLeadingZero) {
+ const TStringBuf blob{
+ "\r\n"
+ "042\r\n"};
+ THttpChunkParser parser(parseBytesWithLastState(blob, 2));
+ UNIT_ASSERT_EQUAL(parser.chunk_length, 0x42);
+ }
+
+ Y_UNIT_TEST(TestIntOverflow) {
+ const TStringBuf blob{
+ "\r\n"
+ "deadbeef"};
+ THttpChunkParser parser(parseBytesWithLastState(blob, -2));
+ UNIT_ASSERT_EQUAL(parser.chunk_length, 0);
+ UNIT_ASSERT_EQUAL(parser.cnt64, 0xdeadbeef);
+ }
+
+ Y_UNIT_TEST(TestTrivialChunkWithTail) {
+ const TStringBuf blob{
+ "\r\n"
+ "4\r\n"
+ "_" // first byte of the chunk
+ };
+ TVector<int> states{
+ 1, 1,
+ 1, 1, 2,
+ -1};
+ parseByteByByte(blob, states);
+ }
+
+ Y_UNIT_TEST(TestLastChunk) {
+ // NB: current parser does not permit whitespace before `foo`,
+ // but I've never seen the feature in real-life traffic
+ const TStringBuf blob{
+ "\r\n"
+ "000 ;foo = bar \r\n"
+ "Trailer: bar\r\n"
+ "\r\n"};
+ THttpChunkParser parser(parseBytesWithLastState(blob, 2));
+ UNIT_ASSERT_EQUAL(parser.chunk_length, 0);
+ }
+}
diff --git a/library/cpp/http/fetch/httpheader.cpp b/library/cpp/http/fetch/httpheader.cpp
new file mode 100644
index 0000000000..7d2225b8b7
--- /dev/null
+++ b/library/cpp/http/fetch/httpheader.cpp
@@ -0,0 +1,7 @@
+#include "httpheader.h"
+
+const i64 DEFAULT_RETRY_AFTER = -1;
+const i64 DEFAULT_IF_MODIFIED_SINCE = -1;
+const i32 DEFAULT_MAX_AGE = -1;
+const i8 DEFAULT_REQUEST_PRIORITY = -1;
+const i32 DEFAULT_RESPONSE_TIMEOUT = -1;
diff --git a/library/cpp/http/fetch/httpheader.h b/library/cpp/http/fetch/httpheader.h
new file mode 100644
index 0000000000..b2810bbd41
--- /dev/null
+++ b/library/cpp/http/fetch/httpheader.h
@@ -0,0 +1,287 @@
+#pragma once
+
+#include "exthttpcodes.h"
+
+#include <library/cpp/mime/types/mime.h>
+
+#include <util/system/defaults.h>
+#include <util/system/compat.h>
+#include <util/generic/string.h>
+#include <util/generic/ylimits.h>
+#include <util/system/maxlen.h>
+
+#include <ctime>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <algorithm>
+
+// This is ugly solution but here a lot of work to do it the right way.
+#define FETCHER_URL_MAX 8192
+
+extern const i64 DEFAULT_RETRY_AFTER; /// == -1
+extern const i64 DEFAULT_IF_MODIFIED_SINCE; /// == -1
+extern const i32 DEFAULT_MAX_AGE; /// == -1
+extern const i8 DEFAULT_REQUEST_PRIORITY; /// == -1
+extern const i32 DEFAULT_RESPONSE_TIMEOUT; /// == -1
+
+#define HTTP_PREFIX "http://"
+#define MAX_LANGREGION_LEN 4
+#define MAXWORD_LEN 55
+
+enum HTTP_COMPRESSION {
+ HTTP_COMPRESSION_UNSET = 0,
+ HTTP_COMPRESSION_ERROR = 1,
+ HTTP_COMPRESSION_IDENTITY = 2,
+ HTTP_COMPRESSION_GZIP = 3,
+ HTTP_COMPRESSION_DEFLATE = 4,
+ HTTP_COMPRESSION_COMPRESS = 5,
+ HTTP_COMPRESSION_MAX = 6
+};
+
+enum HTTP_METHOD {
+ HTTP_METHOD_UNDEFINED = -1,
+ HTTP_METHOD_OPTIONS,
+ HTTP_METHOD_GET,
+ HTTP_METHOD_HEAD,
+ HTTP_METHOD_POST,
+ HTTP_METHOD_PUT,
+ HTTP_METHOD_DELETE,
+ HTTP_METHOD_TRACE,
+ HTTP_METHOD_CONNECT,
+ HTTP_METHOD_EXTENSION
+};
+
+enum HTTP_CONNECTION {
+ HTTP_CONNECTION_UNDEFINED = -1,
+ HTTP_CONNECTION_KEEP_ALIVE = 0,
+ HTTP_CONNECTION_CLOSE = 1
+};
+
+/// Class represents general http header fields.
+struct THttpBaseHeader {
+public:
+ i16 error;
+ i32 header_size;
+ i32 entity_size;
+ i64 content_length;
+ i64 http_time; // seconds since epoch
+ i64 content_range_start; // Content-Range: first-byte-pos
+ i64 content_range_end; // Content-Range: last-byte-pos
+ i64 content_range_entity_length; // Content-Range: entity-length
+ i8 http_minor;
+ i8 mime_type;
+ i8 charset;
+ i8 compression_method;
+ i8 transfer_chunked;
+ i8 connection_closed;
+ TString base;
+
+public:
+ void Init() {
+ error = 0;
+ header_size = 0;
+ entity_size = 0;
+ content_length = -1;
+ http_time = -1;
+ http_minor = -1;
+ mime_type = -1;
+ charset = -1;
+ compression_method = HTTP_COMPRESSION_UNSET;
+ transfer_chunked = -1;
+ connection_closed = HTTP_CONNECTION_UNDEFINED;
+ content_range_start = -1;
+ content_range_end = -1;
+ content_range_entity_length = -1;
+ base.clear();
+ }
+
+ void Print() const {
+ printf("content_length: %" PRIi64 "\n", content_length);
+ printf("http_time: %" PRIi64 "\n", http_time);
+ printf("http_minor: %" PRIi8 "\n", http_minor);
+ printf("mime_type: %" PRIi8 "\n", mime_type);
+ printf("charset: %" PRIi8 "\n", charset);
+ printf("compression_method: %" PRIi8 "\n", compression_method);
+ printf("transfer_chunked: %" PRIi8 "\n", transfer_chunked);
+ printf("connection_closed: %" PRIi8 "\n", connection_closed);
+ printf("content_range_start: %" PRIi64 "\n", content_range_start);
+ printf("content_range_end: %" PRIi64 "\n", content_range_end);
+ printf("content_range_entity_length: %" PRIi64 "\n", content_range_entity_length);
+ printf("base: \"%s\"\n", base.c_str());
+ printf("error: %" PRIi16 "\n", error);
+ }
+
+ int SetBase(const char* path,
+ const char* hostNamePtr = nullptr,
+ int hostNameLength = 0) {
+ if (*path == '/') {
+ base = "http://";
+ base += TStringBuf(hostNamePtr, hostNameLength);
+ base += path;
+ } else {
+ base = path;
+ }
+ return error;
+ }
+};
+
+enum { HREFLANG_MAX = FETCHER_URL_MAX * 2 };
+/// Class represents Http Response Header.
+struct THttpHeader: public THttpBaseHeader {
+public:
+ i8 accept_ranges;
+ i8 squid_error;
+ i8 x_robots_tag; // deprecated, use x_robots_state instead
+ i16 http_status;
+ TString location;
+ TString rel_canonical;
+ char hreflangs[HREFLANG_MAX];
+ i64 retry_after;
+ TString x_robots_state; // 'xxxxx' format, see `library/html/zoneconf/parsefunc.cpp`
+
+public:
+ void Init() {
+ THttpBaseHeader::Init();
+ accept_ranges = -1;
+ squid_error = 0;
+ x_robots_tag = 0;
+ rel_canonical.clear();
+ http_status = -1;
+ location.clear();
+ hreflangs[0] = 0;
+ retry_after = DEFAULT_RETRY_AFTER;
+ x_robots_state = "xxxxx";
+ }
+
+ void Print() const {
+ THttpBaseHeader::Print();
+ printf("http_status: %" PRIi16 "\n", http_status);
+ printf("squid_error: %" PRIi8 "\n", squid_error);
+ printf("accept_ranges: %" PRIi8 "\n", accept_ranges);
+ printf("location: \"%s\"\n", location.c_str());
+ printf("retry_after: %" PRIi64 "\n", retry_after);
+ }
+};
+
+struct THttpRequestHeader: public THttpBaseHeader {
+public:
+ TString request_uri;
+ char host[HOST_MAX];
+ char from[MAXWORD_LEN];
+ char user_agent[MAXWORD_LEN];
+ char x_yandex_langregion[MAX_LANGREGION_LEN];
+ char x_yandex_sourcename[MAXWORD_LEN];
+ char x_yandex_requesttype[MAXWORD_LEN];
+ char x_yandex_fetchoptions[MAXWORD_LEN];
+ i8 http_method;
+ i8 x_yandex_request_priority;
+ i32 x_yandex_response_timeout;
+ i32 max_age;
+ i64 if_modified_since;
+
+public:
+ THttpRequestHeader() {
+ Init();
+ }
+
+ void Init() {
+ request_uri.clear();
+ host[0] = 0;
+ from[0] = 0;
+ user_agent[0] = 0;
+ x_yandex_langregion[0] = 0;
+ x_yandex_sourcename[0] = 0;
+ x_yandex_requesttype[0] = 0;
+ x_yandex_fetchoptions[0] = 0;
+ http_method = HTTP_METHOD_UNDEFINED;
+ x_yandex_request_priority = DEFAULT_REQUEST_PRIORITY;
+ x_yandex_response_timeout = DEFAULT_RESPONSE_TIMEOUT;
+ max_age = DEFAULT_MAX_AGE;
+ if_modified_since = DEFAULT_IF_MODIFIED_SINCE;
+ THttpBaseHeader::Init();
+ }
+
+ void Print() const {
+ THttpBaseHeader::Print();
+ printf("request_uri: \"%s\"\n", request_uri.c_str());
+ printf("host: \"%s\"\n", host);
+ printf("from: \"%s\"\n", from);
+ printf("user_agent: \"%s\"\n", user_agent);
+ printf("http_method: %" PRIi8 "\n", http_method);
+ printf("response_timeout: %" PRIi32 "\n", x_yandex_response_timeout);
+ printf("max_age: %" PRIi32 "\n", max_age);
+ printf("if_modified_since: %" PRIi64 "\n", if_modified_since);
+ }
+
+ /// It doesn't care about errors in request or headers, where
+ /// request_uri equals to '*'.
+ /// This returns copy of the string, which you have to delete.
+ TString GetUrl() {
+ TString url;
+ if (host[0] == 0 || !strcmp(host, "")) {
+ url = request_uri;
+ } else {
+ url = HTTP_PREFIX;
+ url += host;
+ url += request_uri;
+ }
+ return url;
+ }
+
+ char* GetUrl(char* buffer, size_t size) {
+ if (host[0] == 0 || !strcmp(host, "")) {
+ strlcpy(buffer, request_uri.c_str(), size);
+ } else {
+ snprintf(buffer, size, "http://%s%s", host, request_uri.c_str());
+ }
+ return buffer;
+ }
+};
+
+class THttpAuthHeader: public THttpHeader {
+public:
+ char* realm;
+ char* nonce;
+ char* opaque;
+ bool stale;
+ int algorithm;
+ bool qop_auth;
+ bool use_auth;
+
+ //we do not provide auth-int variant as too heavy
+ //bool qop_auth_int;
+
+ THttpAuthHeader()
+ : realm(nullptr)
+ , nonce(nullptr)
+ , opaque(nullptr)
+ , stale(false)
+ , algorithm(0)
+ , qop_auth(false)
+ , use_auth(true)
+ {
+ THttpHeader::Init();
+ }
+
+ ~THttpAuthHeader() {
+ free(realm);
+ free(nonce);
+ free(opaque);
+ }
+
+ void Print() {
+ THttpHeader::Print();
+ if (use_auth) {
+ if (realm)
+ printf("realm: \"%s\"\n", realm);
+ if (nonce)
+ printf("nonce: \"%s\"\n", nonce);
+ if (opaque)
+ printf("opaque: \"%s\"\n", opaque);
+ printf("stale: %d\n", stale);
+ printf("algorithm: %d\n", algorithm);
+ printf("qop_auth: %d\n", qop_auth);
+ }
+ }
+};
diff --git a/library/cpp/http/fetch/httpload.cpp b/library/cpp/http/fetch/httpload.cpp
new file mode 100644
index 0000000000..82ea8900b5
--- /dev/null
+++ b/library/cpp/http/fetch/httpload.cpp
@@ -0,0 +1,373 @@
+#include "httpload.h"
+
+/************************************************************/
+/************************************************************/
+httpAgentReader::httpAgentReader(httpSpecialAgent& agent,
+ const char* baseUrl,
+ bool assumeConnectionClosed,
+ bool use_auth,
+ int bufSize)
+ : Header_()
+ , Agent_(agent)
+ , Buffer_(new char[bufSize])
+ , BufPtr_(Buffer_)
+ , BufSize_(bufSize)
+ , BufRest_(0)
+{
+ HeadRequest = false;
+ Header = &Header_;
+ if (use_auth)
+ HeaderParser.Init(&Header_);
+ else
+ HeaderParser.Init(Header);
+ setAssumeConnectionClosed(assumeConnectionClosed ? 1 : 0);
+ Header_.SetBase(baseUrl);
+
+ if (Header_.error)
+ State = hp_error;
+ else
+ State = hp_in_header;
+}
+
+/************************************************************/
+httpAgentReader::~httpAgentReader() {
+ delete[] Buffer_;
+}
+
+/************************************************************/
+void httpAgentReader::readBuf() {
+ assert(BufRest_ == 0);
+ if (!BufPtr_) {
+ BufRest_ = -1;
+ return;
+ }
+
+ BufRest_ = Agent_.read(Buffer_, BufSize_);
+ if (BufRest_ <= 0) {
+ BufRest_ = -1;
+ BufPtr_ = nullptr;
+ } else {
+ BufPtr_ = Buffer_;
+
+ //cout << "BUF: " << mBuffer << endl << endl;
+ }
+}
+
+/************************************************************/
+const THttpHeader* httpAgentReader::readHeader() {
+ while (State == hp_in_header) {
+ if (!step()) {
+ Header_.error = HTTP_CONNECTION_LOST;
+ return nullptr;
+ }
+ ParseGeneric(BufPtr_, BufRest_);
+ }
+ if (State == hp_eof || State == hp_error) {
+ BufPtr_ = nullptr;
+ BufRest_ = -1;
+ }
+ if (State == hp_error || Header_.error)
+ return nullptr;
+ return &Header_;
+}
+
+/************************************************************/
+long httpAgentReader::readPortion(void*& buf) {
+ assert(State != hp_in_header);
+
+ long Chunk = 0;
+ do {
+ if (BufSize_ == 0 && !BufPtr_)
+ return 0;
+
+ if (!step())
+ return 0;
+
+ Chunk = ParseGeneric(BufPtr_, BufRest_);
+ buf = BufPtr_;
+
+ if (State == hp_error && Header_.entity_size > Header_.content_length) {
+ Chunk -= (Header_.entity_size - Header_.content_length);
+ BufPtr_ = (char*)BufPtr_ + Chunk;
+ BufRest_ = 0;
+ State = hp_eof;
+ Header_.error = 0;
+ break;
+ }
+
+ BufPtr_ = (char*)BufPtr_ + Chunk;
+ BufRest_ -= Chunk;
+
+ if (State == hp_eof || State == hp_error) {
+ BufRest_ = -1;
+ BufPtr_ = nullptr;
+ }
+ } while (!Chunk);
+ return Chunk;
+}
+
+/************************************************************/
+bool httpAgentReader::skipTheRest() {
+ void* b;
+ while (!eof())
+ readPortion(b);
+ return (State == hp_eof);
+}
+
+/************************************************************/
+/************************************************************/
+httpLoadAgent::httpLoadAgent(bool handleAuthorization,
+ socketHandlerFactory& factory)
+ : Factory_(factory)
+ , HandleAuthorization_(handleAuthorization)
+ , URL_()
+ , PersistentConn_(false)
+ , Reader_(nullptr)
+ , Headers_()
+ , ErrCode_(0)
+ , RealHost_(nullptr)
+{
+}
+
+/************************************************************/
+httpLoadAgent::~httpLoadAgent() {
+ delete Reader_;
+ free(RealHost_);
+}
+
+/************************************************************/
+void httpLoadAgent::clearReader() {
+ if (Reader_) {
+ bool opened = false;
+ if (PersistentConn_) {
+ const THttpHeader* H = Reader_->readHeader();
+ if (H && !H->connection_closed) {
+ Reader_->skipTheRest();
+ opened = true;
+ }
+ }
+ if (!opened)
+ Disconnect();
+ delete Reader_;
+ Reader_ = nullptr;
+ }
+ ErrCode_ = 0;
+}
+/************************************************************/
+void httpLoadAgent::setRealHost(const char* hostname) {
+ free(RealHost_);
+ if (hostname)
+ RealHost_ = strdup(hostname);
+ else
+ RealHost_ = nullptr;
+ ErrCode_ = 0;
+}
+
+/************************************************************/
+void httpLoadAgent::setIMS(const char* ifModifiedSince) {
+ char ims_buf[100];
+ snprintf(ims_buf, 100, "If-Modified-Since: %s\r\n",
+ ifModifiedSince);
+ Headers_.push_back(ims_buf);
+}
+
+/************************************************************/
+void httpLoadAgent::addHeaderInstruction(const char* instr) {
+ Headers_.push_back(instr);
+}
+
+/************************************************************/
+void httpLoadAgent::dropHeaderInstructions() {
+ Headers_.clear();
+}
+
+/************************************************************/
+bool httpLoadAgent::startRequest(const THttpURL& url,
+ bool persistent,
+ const TAddrList& addrs)
+
+{
+ clearReader();
+ ErrCode_ = 0;
+
+ URL_.Clear();
+ URL_ = url;
+ PersistentConn_ = persistent;
+ if (!URL_.IsValidAbs())
+ return false;
+ if (!HandleAuthorization_ && !URL_.IsNull(THttpURL::FlagAuth))
+ return false;
+
+ return doSetHost(addrs) && doStartRequest();
+}
+
+/************************************************************/
+bool httpLoadAgent::startRequest(const char* url,
+ const char* url_to_merge,
+ bool persistent,
+ const TAddrList& addrs) {
+ clearReader();
+
+ URL_.Clear();
+ PersistentConn_ = persistent;
+
+ long flags = THttpURL::FeatureSchemeKnown | THttpURL::FeaturesNormalizeSet;
+ if (HandleAuthorization_)
+ flags |= THttpURL::FeatureAuthSupported;
+
+ if (URL_.Parse(url, flags, url_to_merge) || !URL_.IsValidGlobal())
+ return false;
+
+ return doSetHost(addrs) && doStartRequest();
+}
+
+/************************************************************/
+bool httpLoadAgent::startRequest(const char* url,
+ const char* url_to_merge,
+ bool persistent,
+ ui32 ip) {
+ clearReader();
+
+ URL_.Clear();
+ PersistentConn_ = persistent;
+
+ long flags = THttpURL::FeatureSchemeKnown | THttpURL::FeaturesNormalizeSet;
+ if (HandleAuthorization_)
+ flags |= THttpURL::FeatureAuthSupported;
+
+ if (URL_.Parse(url, flags, url_to_merge) || !URL_.IsValidGlobal())
+ return false;
+
+ return doSetHost(TAddrList::MakeV4Addr(ip, URL_.GetPort())) && doStartRequest();
+}
+
+/************************************************************/
+bool httpLoadAgent::doSetHost(const TAddrList& addrs) {
+ socketAbstractHandler* h = Factory_.chooseHandler(URL_);
+ if (!h)
+ return false;
+ Socket.setHandler(h);
+
+ if (addrs.size()) {
+ ErrCode_ = SetHost(URL_.Get(THttpURL::FieldHost),
+ URL_.GetPort(), addrs);
+ } else {
+ ErrCode_ = SetHost(URL_.Get(THttpURL::FieldHost),
+ URL_.GetPort());
+ }
+ if (ErrCode_)
+ return false;
+
+ if (RealHost_) {
+ free(Hostheader);
+ Hostheader = (char*)malloc(strlen(RealHost_) + 20);
+ sprintf(Hostheader, "Host: %s\r\n", RealHost_);
+ }
+
+ if (!URL_.IsNull(THttpURL::FlagAuth)) {
+ if (!HandleAuthorization_) {
+ ErrCode_ = HTTP_UNAUTHORIZED;
+ return false;
+ }
+
+ Digest_.setAuthorization(URL_.Get(THttpURL::FieldUsername),
+ URL_.Get(THttpURL::FieldPassword));
+ }
+
+ return true;
+}
+
+/************************************************************/
+bool httpLoadAgent::setHost(const char* host_url,
+ const TAddrList& addrs) {
+ clearReader();
+
+ URL_.Clear();
+ PersistentConn_ = true;
+
+ long flags = THttpURL::FeatureSchemeKnown | THttpURL::FeaturesNormalizeSet;
+ if (HandleAuthorization_)
+ flags |= THttpURL::FeatureAuthSupported;
+
+ if (URL_.Parse(host_url, flags) || !URL_.IsValidGlobal())
+ return false;
+
+ return doSetHost(addrs);
+}
+
+/************************************************************/
+bool httpLoadAgent::startOneRequest(const char* local_url) {
+ clearReader();
+
+ THttpURL lURL;
+ if (lURL.Parse(local_url, THttpURL::FeaturesNormalizeSet) || lURL.IsValidGlobal())
+ return false;
+
+ URL_.SetInMemory(THttpURL::FieldPath, lURL.Get(THttpURL::FieldPath));
+ URL_.SetInMemory(THttpURL::FieldQuery, lURL.Get(THttpURL::FieldQuery));
+ URL_.Rewrite();
+
+ return doStartRequest();
+}
+
+/************************************************************/
+bool httpLoadAgent::doStartRequest() {
+ TString urlStr = URL_.PrintS(THttpURL::FlagPath | THttpURL::FlagQuery);
+ if (!urlStr)
+ urlStr = "/";
+
+ for (int step = 0; step < 10; step++) {
+ const char* digestHeader = Digest_.getHeaderInstruction();
+
+ unsigned i = (digestHeader) ? 2 : 1;
+ const char** headers =
+ (const char**)(alloca((i + Headers_.size()) * sizeof(char*)));
+
+ for (i = 0; i < Headers_.size(); i++)
+ headers[i] = Headers_[i].c_str();
+ if (digestHeader)
+ headers[i++] = digestHeader;
+ headers[i] = nullptr;
+
+ ErrCode_ = RequestGet(urlStr.c_str(), headers, PersistentConn_);
+
+ if (ErrCode_) {
+ Disconnect();
+ return false;
+ }
+
+ TString urlBaseStr = URL_.PrintS(THttpURL::FlagNoFrag);
+
+ clearReader();
+ Reader_ = new httpAgentReader(*this, urlBaseStr.c_str(),
+ !PersistentConn_, !Digest_.empty());
+
+ if (Reader_->readHeader()) {
+ //mReader->getHeader()->Print();
+ if (getHeader()->http_status == HTTP_UNAUTHORIZED &&
+ step < 1 &&
+ Digest_.processHeader(getAuthHeader(),
+ urlStr.c_str(),
+ "GET")) {
+ //mReader->skipTheRest();
+ delete Reader_;
+ Reader_ = nullptr;
+ ErrCode_ = 0;
+ Disconnect();
+ continue;
+ }
+
+ return true;
+ }
+ Disconnect();
+ clearReader();
+
+ return false;
+ }
+
+ ErrCode_ = HTTP_UNAUTHORIZED;
+ return false;
+}
+
+/************************************************************/
+/************************************************************/
diff --git a/library/cpp/http/fetch/httpload.h b/library/cpp/http/fetch/httpload.h
new file mode 100644
index 0000000000..e22e4b809e
--- /dev/null
+++ b/library/cpp/http/fetch/httpload.h
@@ -0,0 +1,307 @@
+#pragma once
+
+#include "httpagent.h"
+#include "httpparser.h"
+#include "http_digest.h"
+
+#include <util/system/compat.h>
+#include <util/string/vector.h>
+#include <util/network/ip.h>
+#include <library/cpp/uri/http_url.h>
+#include <library/cpp/http/misc/httpcodes.h>
+
+/********************************************************/
+// Section 1: socket handlers
+/********************************************************/
+// The following classes allows to adopt template scheme
+// THttpAgent for work with socket by flexible
+// object-style scheme.
+
+/********************************************************/
+// This class is used as a base one for flexible
+// socket handling
+class socketAbstractHandler {
+public:
+ virtual bool Good() = 0;
+
+ virtual int Connect(const TAddrList& addrs, TDuration Timeout) = 0;
+
+ virtual void Disconnect() = 0;
+
+ virtual void shutdown() = 0;
+
+ virtual bool send(const char* message, ssize_t messlen) = 0;
+
+ virtual bool peek() = 0;
+
+ virtual ssize_t read(void* buffer, ssize_t buflen) = 0;
+
+ virtual ~socketAbstractHandler() {
+ }
+
+protected:
+ socketAbstractHandler() {
+ }
+};
+
+/********************************************************/
+// This class is used as a proxy between THttpAgent and
+// socketAbstractHandler
+// (it is used by template scheme,
+// so it does not have virtual methods)
+class TSocketHandlerPtr {
+protected:
+ socketAbstractHandler* Handler_;
+
+public:
+ TSocketHandlerPtr()
+ : Handler_(nullptr)
+ {
+ }
+
+ virtual ~TSocketHandlerPtr() {
+ delete Handler_;
+ }
+
+ int Good() {
+ return (Handler_ && Handler_->Good());
+ }
+
+ int Connect(const TAddrList& addrs, TDuration Timeout) {
+ return (Handler_) ? Handler_->Connect(addrs, Timeout) : 1;
+ }
+
+ void Disconnect() {
+ if (Handler_)
+ Handler_->Disconnect();
+ }
+
+ void shutdown() {
+ if (Handler_)
+ Handler_->shutdown();
+ }
+
+ bool send(const char* message, ssize_t messlen) {
+ return (Handler_) ? Handler_->send(message, messlen) : false;
+ }
+
+ virtual bool peek() {
+ return (Handler_) ? Handler_->peek() : false;
+ }
+
+ virtual ssize_t read(void* buffer, ssize_t buflen) {
+ return (Handler_) ? Handler_->read(buffer, buflen) : 0;
+ }
+
+ void setHandler(socketAbstractHandler* handler) {
+ if (Handler_)
+ delete Handler_;
+ Handler_ = handler;
+ }
+};
+
+/********************************************************/
+// Here is httpAgent that uses socketAbstractHandler class
+// ant its derivatives
+using httpSpecialAgent = THttpAgent<TSocketHandlerPtr>;
+
+/********************************************************/
+// Regular handler is used as implementation of
+// socketAbstractHandler for work through HTTP protocol
+class socketRegularHandler: public socketAbstractHandler {
+protected:
+ TSimpleSocketHandler Socket_;
+
+public:
+ socketRegularHandler()
+ : Socket_()
+ {
+ }
+
+ bool Good() override {
+ return Socket_.Good();
+ }
+
+ int Connect(const TAddrList& addrs, TDuration Timeout) override {
+ return Socket_.Connect(addrs, Timeout);
+ }
+
+ void Disconnect() override {
+ Socket_.Disconnect();
+ }
+
+ void shutdown() override {
+ //Do not block writing to socket
+ //There are servers that works in a bad way with this
+ //mSocket.shutdown();
+ }
+
+ bool send(const char* message, ssize_t messlen) override {
+ return Socket_.send(message, messlen);
+ }
+
+ bool peek() override {
+ return Socket_.peek();
+ }
+
+ ssize_t read(void* buffer, ssize_t buflen) override {
+ return Socket_.read(buffer, buflen);
+ }
+};
+
+/********************************************************/
+// The base factory that allows to choose an appropriate
+// socketAbstractHandler implementation by url schema
+
+class socketHandlerFactory {
+public:
+ virtual ~socketHandlerFactory() {
+ }
+
+ //returns mHandler_HTTP for correct HTTP-based url
+ virtual socketAbstractHandler* chooseHandler(const THttpURL& url);
+
+ static socketHandlerFactory sInstance;
+};
+
+/********************************************************/
+// Section 2: the configurates tool to parse an HTTP-response
+/********************************************************/
+
+class httpAgentReader: public THttpParserGeneric<1> {
+protected:
+ THttpAuthHeader Header_;
+ httpSpecialAgent& Agent_;
+
+ char* Buffer_;
+ void* BufPtr_;
+ int BufSize_;
+ long BufRest_;
+
+ void readBuf();
+
+ bool step() {
+ if (BufRest_ == 0)
+ readBuf();
+ if (eof())
+ return false;
+ return true;
+ }
+
+public:
+ httpAgentReader(httpSpecialAgent& agent,
+ const char* baseUrl,
+ bool assumeConnectionClosed,
+ bool use_auth = false,
+ int bufSize = 0x1000);
+
+ ~httpAgentReader();
+
+ bool eof() {
+ return BufRest_ < 0;
+ }
+
+ int error() {
+ return Header_.error;
+ }
+
+ void setError(int errCode) {
+ Header_.error = errCode;
+ }
+
+ const THttpAuthHeader* getAuthHeader() {
+ return &Header_;
+ }
+
+ const THttpHeader* readHeader();
+ long readPortion(void*& buf);
+ bool skipTheRest();
+};
+
+/********************************************************/
+// Section 3: the main class
+/********************************************************/
+class httpLoadAgent: public httpSpecialAgent {
+protected:
+ socketHandlerFactory& Factory_;
+ bool HandleAuthorization_;
+ THttpURL URL_;
+ bool PersistentConn_;
+ httpAgentReader* Reader_;
+ TVector<TString> Headers_;
+ int ErrCode_;
+ char* RealHost_;
+ httpDigestHandler Digest_;
+
+ void clearReader();
+ bool doSetHost(const TAddrList& addrs);
+ bool doStartRequest();
+
+public:
+ httpLoadAgent(bool handleAuthorization = false,
+ socketHandlerFactory& factory = socketHandlerFactory::sInstance);
+ ~httpLoadAgent();
+
+ void setRealHost(const char* host);
+ void setIMS(const char* ifModifiedSince);
+ void addHeaderInstruction(const char* instr);
+ void dropHeaderInstructions();
+
+ bool startRequest(const char* url,
+ const char* url_to_merge = nullptr,
+ bool persistent = false,
+ const TAddrList& addrs = TAddrList());
+
+ // deprecated v4-only
+ bool startRequest(const char* url,
+ const char* url_to_merge,
+ bool persistent,
+ ui32 ip);
+
+ bool startRequest(const THttpURL& url,
+ bool persistent = false,
+ const TAddrList& addrs = TAddrList());
+
+ bool setHost(const char* host_url,
+ const TAddrList& addrs = TAddrList());
+
+ bool startOneRequest(const char* local_url);
+
+ const THttpAuthHeader* getAuthHeader() {
+ if (Reader_ && Reader_->getAuthHeader()->use_auth)
+ return Reader_->getAuthHeader();
+ return nullptr;
+ }
+
+ const THttpHeader* getHeader() {
+ if (Reader_)
+ return Reader_->getAuthHeader();
+ return nullptr;
+ }
+
+ const THttpURL& getURL() {
+ return URL_;
+ }
+
+ bool eof() {
+ if (Reader_)
+ return Reader_->eof();
+ return true;
+ }
+
+ int error() {
+ if (ErrCode_)
+ return ErrCode_;
+ if (Reader_)
+ return Reader_->error();
+ return HTTP_BAD_URL;
+ }
+
+ long readPortion(void*& buf) {
+ if (Reader_)
+ return Reader_->readPortion(buf);
+ return -1;
+ }
+};
+
+/********************************************************/
diff --git a/library/cpp/http/fetch/httpparser.h b/library/cpp/http/fetch/httpparser.h
new file mode 100644
index 0000000000..769828e4ae
--- /dev/null
+++ b/library/cpp/http/fetch/httpparser.h
@@ -0,0 +1,372 @@
+#pragma once
+
+#include "httpfsm.h"
+#include "httpheader.h"
+
+#include <library/cpp/mime/types/mime.h>
+#include <util/system/yassert.h>
+#include <library/cpp/http/misc/httpcodes.h>
+
+template <size_t headermax = 100 << 10, size_t bodymax = 1 << 20>
+struct TFakeCheck {
+ bool Check(THttpHeader* /*header*/) {
+ return false;
+ }
+ void CheckDocPart(void* /*buf*/, size_t /*len*/, THttpHeader* /*header*/) {
+ } //for every part of DocumentBody will be called
+ void CheckEndDoc(THttpHeader* /*header*/) {
+ }
+ size_t GetMaxHeaderSize() {
+ return headermax;
+ }
+ size_t GetMaxBodySize(THttpHeader*) {
+ return bodymax;
+ }
+};
+
+class THttpParserBase {
+public:
+ enum States {
+ hp_error,
+ hp_eof,
+ hp_in_header,
+ hp_read_alive,
+ hp_read_closed,
+ hp_begin_chunk_header,
+ hp_chunk_header,
+ hp_read_chunk
+ };
+
+ States GetState() {
+ return State;
+ }
+
+ void setAssumeConnectionClosed(int value) {
+ AssumeConnectionClosed = value;
+ }
+
+ THttpHeader* GetHttpHeader() const {
+ return Header;
+ }
+
+protected:
+ int CheckHeaders() {
+ if (Header->http_status < HTTP_OK || Header->http_status == HTTP_NO_CONTENT || Header->http_status == HTTP_NOT_MODIFIED) {
+ Header->content_length = 0;
+ Header->transfer_chunked = 0;
+ }
+ if (Header->transfer_chunked < -1) {
+ Header->error = HTTP_BAD_ENCODING;
+ return 1;
+ } else if (Header->transfer_chunked == -1) {
+ Header->transfer_chunked = 0;
+ }
+ if (!Header->transfer_chunked && Header->content_length < -1) {
+ Header->error = HTTP_BAD_CONTENT_LENGTH;
+ return 1;
+ }
+ if (Header->http_status == HTTP_OK) {
+ if (Header->compression_method != HTTP_COMPRESSION_UNSET &&
+ Header->compression_method != HTTP_COMPRESSION_IDENTITY &&
+ Header->compression_method != HTTP_COMPRESSION_GZIP &&
+ Header->compression_method != HTTP_COMPRESSION_DEFLATE)
+ {
+ Header->error = HTTP_BAD_CONTENT_ENCODING;
+ return 1;
+ }
+ }
+ if (Header->connection_closed == -1)
+ Header->connection_closed = (Header->http_minor == 0 ||
+ AssumeConnectionClosed);
+ if (!Header->transfer_chunked && !Header->connection_closed && Header->content_length < 0 && !HeadRequest) {
+ Header->error = HTTP_LENGTH_UNKNOWN;
+ return 1;
+ }
+ if (Header->http_time < 0)
+ Header->http_time = 0;
+ if (Header->mime_type < 0)
+ Header->mime_type = MIME_UNKNOWN;
+ return 0;
+ }
+
+ THttpHeaderParser HeaderParser;
+ THttpChunkParser ChunkParser;
+ States State;
+ long ChunkSize;
+ THttpHeader* Header;
+ int AssumeConnectionClosed;
+ bool HeadRequest;
+};
+
+template <int isReader, typename TCheck = TFakeCheck<>>
+class THttpParserGeneric: public THttpParserBase, public TCheck {
+protected:
+ long ParseGeneric(void*& buf, long& size) {
+ if (!size) {
+ switch (State) {
+ case hp_error:
+ case hp_eof:
+ break;
+ case hp_read_closed:
+ State = hp_eof;
+ break;
+ case hp_in_header:
+ Header->error = HTTP_HEADER_EOF;
+ State = hp_error;
+ break;
+ case hp_read_alive:
+ case hp_read_chunk:
+ if (HeadRequest)
+ State = hp_eof;
+ else {
+ Header->error = HTTP_MESSAGE_EOF;
+ State = hp_error;
+ }
+ break;
+ case hp_begin_chunk_header:
+ case hp_chunk_header:
+ if (HeadRequest)
+ State = hp_eof;
+ else {
+ Header->error = HTTP_CHUNK_EOF;
+ State = hp_error;
+ }
+ break;
+ }
+ return 0;
+ }
+ while (size) {
+ int ret;
+
+ switch (State) {
+ case hp_error:
+ return 0;
+
+ case hp_eof:
+ return 0;
+
+ case hp_in_header:
+ if ((ret = HeaderParser.Execute(buf, size)) < 0) {
+ Header->error = HTTP_BAD_HEADER_STRING;
+ State = hp_error;
+ return 0;
+ } else if (ret == 2) {
+ Header->header_size += i32(HeaderParser.lastchar - (char*)buf + 1);
+ size -= long(HeaderParser.lastchar - (char*)buf + 1);
+ buf = HeaderParser.lastchar + 1;
+ State = CheckHeaders() ? hp_error
+ : Header->transfer_chunked ? hp_begin_chunk_header
+ : Header->content_length == 0 ? hp_eof
+ : Header->content_length > 0 ? hp_read_alive
+ : hp_read_closed;
+ if (State == hp_begin_chunk_header) {
+ // unget \n for chunk reader
+ buf = (char*)buf - 1;
+ size++;
+ }
+ if (isReader)
+ return size;
+ } else {
+ Header->header_size += size;
+ size = 0;
+ }
+ break;
+
+ case hp_read_alive:
+ Header->entity_size += size;
+ if (Header->entity_size >= Header->content_length) {
+ State = hp_eof;
+ }
+
+ TCheck::CheckDocPart(buf, size, Header);
+ if (isReader)
+ return size;
+ size = 0;
+ break;
+
+ case hp_read_closed:
+ Header->entity_size += size;
+ TCheck::CheckDocPart(buf, size, Header);
+ if (isReader)
+ return size;
+ size = 0;
+ break;
+
+ case hp_begin_chunk_header:
+ ChunkParser.Init();
+ State = hp_chunk_header;
+ [[fallthrough]];
+
+ case hp_chunk_header:
+ if ((ret = ChunkParser.Execute(buf, size)) < 0) {
+ Header->error = i16(ret == -2 ? HTTP_CHUNK_TOO_LARGE : HTTP_BAD_CHUNK);
+ State = hp_error;
+ return 0;
+ } else if (ret == 2) {
+ Header->entity_size += i32(ChunkParser.lastchar - (char*)buf + 1);
+ size -= long(ChunkParser.lastchar - (char*)buf + 1);
+ buf = ChunkParser.lastchar + 1;
+ ChunkSize = ChunkParser.chunk_length;
+ Y_ASSERT(ChunkSize >= 0);
+ State = ChunkSize ? hp_read_chunk : hp_eof;
+ } else {
+ Header->entity_size += size;
+ size = 0;
+ }
+ break;
+
+ case hp_read_chunk:
+ if (size >= ChunkSize) {
+ Header->entity_size += ChunkSize;
+ State = hp_begin_chunk_header;
+ TCheck::CheckDocPart(buf, ChunkSize, Header);
+ if (isReader)
+ return ChunkSize;
+ size -= ChunkSize;
+ buf = (char*)buf + ChunkSize;
+ } else {
+ Header->entity_size += size;
+ ChunkSize -= size;
+ TCheck::CheckDocPart(buf, size, Header);
+ if (isReader)
+ return size;
+ size = 0;
+ }
+ break;
+ }
+ }
+ return size;
+ }
+};
+
+template <class TCheck = TFakeCheck<>>
+class THttpParser: public THttpParserGeneric<0, TCheck> {
+ typedef THttpParserGeneric<0, TCheck> TBaseT; //sorry avoiding gcc 3.4.6 BUG!
+public:
+ void Init(THttpHeader* H, bool head_request = false) {
+ TBaseT::Header = H;
+ TBaseT::HeaderParser.Init(TBaseT::Header);
+ TBaseT::State = TBaseT::hp_in_header;
+ TBaseT::AssumeConnectionClosed = 0;
+ TBaseT::HeadRequest = head_request;
+ }
+
+ void Parse(void* buf, long size) {
+ TBaseT::ParseGeneric(buf, size);
+ }
+};
+
+class TMemoReader {
+public:
+ int Init(void* buf, long bufsize) {
+ Buf = buf;
+ Bufsize = bufsize;
+ return 0;
+ }
+ long Read(void*& buf) {
+ Y_ASSERT(Bufsize >= 0);
+ if (!Bufsize) {
+ Bufsize = -1;
+ return 0;
+ }
+ buf = Buf;
+ long ret = Bufsize;
+ Bufsize = 0;
+ return ret;
+ }
+
+protected:
+ long Bufsize;
+ void* Buf;
+};
+
+template <class Reader>
+class THttpReader: public THttpParserGeneric<1>, public Reader {
+ typedef THttpParserGeneric<1> TBaseT;
+
+public:
+ using TBaseT::AssumeConnectionClosed;
+ using TBaseT::Header;
+ using TBaseT::ParseGeneric;
+ using TBaseT::State;
+
+ int Init(THttpHeader* H, int parsHeader, int assumeConnectionClosed = 0, bool headRequest = false) {
+ Header = H;
+ Eoferr = 1;
+ Size = 0;
+ AssumeConnectionClosed = assumeConnectionClosed;
+ HeadRequest = headRequest;
+ return parsHeader ? ParseHeader() : SkipHeader();
+ }
+
+ long Read(void*& buf) {
+ long Chunk;
+ do {
+ if (!Size) {
+ if (Eoferr != 1)
+ return Eoferr;
+ else if ((Size = (long)Reader::Read(Ptr)) < 0) {
+ Header->error = HTTP_CONNECTION_LOST;
+ return Eoferr = -1;
+ }
+ }
+ Chunk = ParseGeneric(Ptr, Size);
+ buf = Ptr;
+ Ptr = (char*)Ptr + Chunk;
+ Size -= Chunk;
+ if (State == hp_eof) {
+ Size = 0;
+ Eoferr = 0;
+ } else if (State == hp_error)
+ return Eoferr = -1;
+ } while (!Chunk);
+ return Chunk;
+ }
+
+protected:
+ int ParseHeader() {
+ HeaderParser.Init(Header);
+ State = hp_in_header;
+ while (State == hp_in_header) {
+ if ((Size = (long)Reader::Read(Ptr)) < 0)
+ return Eoferr = -1;
+ ParseGeneric(Ptr, Size);
+ }
+ if (State == hp_error)
+ return Eoferr = -1;
+ if (State == hp_eof)
+ Eoferr = 0;
+ return 0;
+ }
+
+ int SkipHeader() {
+ long hdrsize = Header->header_size;
+ while (hdrsize) {
+ if ((Size = (long)Reader::Read(Ptr)) <= 0)
+ return Eoferr = -1;
+ if (Size >= hdrsize) {
+ Size -= hdrsize;
+ Ptr = (char*)Ptr + hdrsize;
+ break;
+ }
+ hdrsize -= Size;
+ }
+ State = Header->transfer_chunked ? hp_begin_chunk_header
+ : Header->content_length == 0 ? hp_eof
+ : Header->content_length > 0 ? hp_read_alive
+ : hp_read_closed;
+ Header->entity_size = 0;
+ if (State == hp_eof)
+ Eoferr = 0;
+ else if (State == hp_begin_chunk_header) {
+ // unget \n for chunk reader
+ Ptr = (char*)Ptr - 1;
+ ++Size;
+ }
+ return 0;
+ }
+
+ void* Ptr;
+ long Size;
+ int Eoferr;
+};
diff --git a/library/cpp/http/fetch/httpparser_ut.cpp b/library/cpp/http/fetch/httpparser_ut.cpp
new file mode 100644
index 0000000000..3b3b938e7a
--- /dev/null
+++ b/library/cpp/http/fetch/httpparser_ut.cpp
@@ -0,0 +1,231 @@
+#include "httpparser.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#define ENUM_OUT(arg) \
+ case type ::arg: { \
+ out << #arg; \
+ return; \
+ }
+
+template <>
+void Out<THttpParserBase::States>(IOutputStream& out, THttpParserBase::States st) {
+ using type = THttpParserBase::States;
+ switch (st) {
+ ENUM_OUT(hp_error)
+ ENUM_OUT(hp_eof)
+ ENUM_OUT(hp_in_header)
+ ENUM_OUT(hp_read_alive)
+ ENUM_OUT(hp_read_closed)
+ ENUM_OUT(hp_begin_chunk_header)
+ ENUM_OUT(hp_chunk_header)
+ ENUM_OUT(hp_read_chunk)
+ }
+}
+
+namespace {
+ class TSomethingLikeFakeCheck;
+
+ using TTestHttpParser = THttpParser<TSomethingLikeFakeCheck>;
+
+ class TSomethingLikeFakeCheck {
+ TString Body_;
+
+ public:
+ const TString& Body() const {
+ return Body_;
+ }
+
+ // other functions are not really called by THttpParser
+ void CheckDocPart(const void* buf, size_t len, THttpHeader* /* header */) {
+ TString s(static_cast<const char*>(buf), len);
+ Cout << "State = " << static_cast<TTestHttpParser*>(this)->GetState() << ", CheckDocPart(" << s.Quote() << ")\n";
+ Body_ += s;
+ }
+ };
+
+}
+
+Y_UNIT_TEST_SUITE(TestHttpParser) {
+ Y_UNIT_TEST(TestTrivialRequest) {
+ const TString blob{
+ "GET /search?q=hi HTTP/1.1\r\n"
+ "Host: www.google.ru:8080 \r\n"
+ "\r\n"};
+ THttpHeader hdr;
+ THttpParser<> parser;
+ parser.Init(&hdr);
+ parser.Parse((void*)blob.data(), blob.size());
+ UNIT_ASSERT_EQUAL(parser.GetState(), parser.hp_error); // can't parse request as response
+ }
+
+ // XXX: `entity_size` is i32 and `content_length` is i64!
+ Y_UNIT_TEST(TestTrivialResponse) {
+ const TString blob{
+ "HTTP/1.1 200 Ok\r\n"
+ "Content-Length: 2\r\n"
+ "\r\n"
+ "OK"};
+ THttpHeader hdr;
+ TTestHttpParser parser;
+ parser.Init(&hdr);
+ parser.Parse((void*)blob.data(), blob.size());
+ UNIT_ASSERT_EQUAL(parser.GetState(), parser.hp_eof);
+ UNIT_ASSERT_EQUAL(parser.Body(), "OK");
+ UNIT_ASSERT_EQUAL(hdr.header_size, strlen(
+ "HTTP/1.1 200 Ok\r\n"
+ "Content-Length: 2\r\n"
+ "\r\n"));
+ UNIT_ASSERT_EQUAL(hdr.entity_size, strlen("OK"));
+ }
+
+ // XXX: `entity_size` is off by one in TE:chunked case.
+ Y_UNIT_TEST(TestChunkedResponse) {
+ const TString blob{
+ "HTTP/1.1 200 OK\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n"
+ "2\r\n"
+ "Ok\r\n"
+ "8\r\n"
+ "AllRight\r\n"
+ "0\r\n"
+ "\r\n"};
+ THttpHeader hdr;
+ TTestHttpParser parser;
+ parser.Init(&hdr);
+ parser.Parse((void*)blob.data(), blob.size());
+ UNIT_ASSERT_EQUAL(parser.GetState(), parser.hp_eof);
+ UNIT_ASSERT_EQUAL(parser.Body(), "OkAllRight");
+ UNIT_ASSERT_EQUAL(hdr.header_size, strlen(
+ "HTTP/1.1 200 OK\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n"));
+ const int off_by_one_err = -1; // XXX: it really looks so
+ UNIT_ASSERT_EQUAL(hdr.entity_size + off_by_one_err, strlen(
+ "2\r\n"
+ "Ok\r\n"
+ "8\r\n"
+ "AllRight\r\n"
+ "0\r\n"
+ "\r\n"));
+ }
+
+ static const TString PipelineClenBlob_{
+ "HTTP/1.1 200 Ok\r\n"
+ "Content-Length: 4\r\n"
+ "\r\n"
+ "OK\r\n"
+ "HTTP/1.1 200 Zz\r\n"
+ "Content-Length: 4\r\n"
+ "\r\n"
+ "ZZ\r\n"};
+
+ void AssertPipelineClen(TTestHttpParser & parser, const THttpHeader& hdr) {
+ UNIT_ASSERT_EQUAL(parser.GetState(), parser.hp_eof);
+ UNIT_ASSERT_EQUAL(4, hdr.content_length);
+ UNIT_ASSERT_EQUAL(hdr.header_size, strlen(
+ "HTTP/1.1 200 Ok\r\n"
+ "Content-Length: 4\r\n"
+ "\r\n"));
+ }
+
+ Y_UNIT_TEST(TestPipelineClenByteByByte) {
+ const TString& blob = PipelineClenBlob_;
+ THttpHeader hdr;
+ TTestHttpParser parser;
+ parser.Init(&hdr);
+ for (size_t i = 0; i < blob.size(); ++i) {
+ const TStringBuf d{blob, i, 1};
+ parser.Parse((void*)d.data(), d.size());
+ Cout << TString(d).Quote() << " -> " << parser.GetState() << Endl;
+ }
+ AssertPipelineClen(parser, hdr);
+ UNIT_ASSERT_EQUAL(parser.Body(), "OK\r\n");
+ UNIT_ASSERT_EQUAL(hdr.entity_size, hdr.content_length);
+ }
+
+ // XXX: Content-Length is ignored, Body() looks unexpected!
+ Y_UNIT_TEST(TestPipelineClenOneChunk) {
+ const TString& blob = PipelineClenBlob_;
+ THttpHeader hdr;
+ TTestHttpParser parser;
+ parser.Init(&hdr);
+ parser.Parse((void*)blob.data(), blob.size());
+ AssertPipelineClen(parser, hdr);
+ UNIT_ASSERT_EQUAL(parser.Body(),
+ "OK\r\n"
+ "HTTP/1.1 200 Zz\r\n"
+ "Content-Length: 4\r\n"
+ "\r\n"
+ "ZZ\r\n");
+ UNIT_ASSERT_EQUAL(hdr.entity_size, strlen(
+ "OK\r\n"
+ "HTTP/1.1 200 Zz\r\n"
+ "Content-Length: 4\r\n"
+ "\r\n"
+ "ZZ\r\n"));
+ }
+
+ static const TString PipelineChunkedBlob_{
+ "HTTP/1.1 200 OK\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n"
+ "2\r\n"
+ "Ok\r\n"
+ "8\r\n"
+ "AllRight\r\n"
+ "0\r\n"
+ "\r\n"
+ "HTTP/1.1 200 OK\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n"
+ "2\r\n"
+ "Yo\r\n"
+ "8\r\n"
+ "uWin!Iam\r\n"
+ "0\r\n"
+ "\r\n"};
+
+ void AssertPipelineChunked(TTestHttpParser & parser, const THttpHeader& hdr) {
+ UNIT_ASSERT_EQUAL(parser.GetState(), parser.hp_eof);
+ UNIT_ASSERT_EQUAL(parser.Body(), "OkAllRight");
+ UNIT_ASSERT_EQUAL(-1, hdr.content_length);
+ UNIT_ASSERT_EQUAL(hdr.header_size, strlen(
+ "HTTP/1.1 200 OK\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n"));
+ const int off_by_one_err = -1;
+ UNIT_ASSERT_EQUAL(hdr.entity_size + off_by_one_err, strlen(
+ "2\r\n"
+ "Ok\r\n"
+ "8\r\n"
+ "AllRight\r\n"
+ "0\r\n"
+ "\r\n"));
+ }
+
+ Y_UNIT_TEST(TestPipelineChunkedByteByByte) {
+ const TString& blob = PipelineChunkedBlob_;
+ THttpHeader hdr;
+ TTestHttpParser parser;
+ parser.Init(&hdr);
+ for (size_t i = 0; i < blob.size(); ++i) {
+ const TStringBuf d{blob, i, 1};
+ parser.Parse((void*)d.data(), d.size());
+ Cout << TString(d).Quote() << " -> " << parser.GetState() << Endl;
+ if (blob.size() / 2 - 1 <= i) // last \n sets EOF
+ UNIT_ASSERT_EQUAL(parser.GetState(), parser.hp_eof);
+ }
+ AssertPipelineChunked(parser, hdr);
+ }
+
+ Y_UNIT_TEST(TestPipelineChunkedOneChunk) {
+ const TString& blob = PipelineChunkedBlob_;
+ THttpHeader hdr;
+ TTestHttpParser parser;
+ parser.Init(&hdr);
+ parser.Parse((void*)blob.data(), blob.size());
+ AssertPipelineChunked(parser, hdr);
+ }
+}
diff --git a/library/cpp/http/fetch/httpzreader.h b/library/cpp/http/fetch/httpzreader.h
new file mode 100644
index 0000000000..68eb00853d
--- /dev/null
+++ b/library/cpp/http/fetch/httpzreader.h
@@ -0,0 +1,295 @@
+#pragma once
+
+#include "httpheader.h"
+#include "httpparser.h"
+#include "exthttpcodes.h"
+
+#include <util/system/defaults.h>
+#include <util/generic/yexception.h>
+
+#include <contrib/libs/zlib/zlib.h>
+
+#include <errno.h>
+
+#ifndef ENOTSUP
+#define ENOTSUP 45
+#endif
+
+template <class Reader>
+class TCompressedHttpReader: public THttpReader<Reader> {
+ typedef THttpReader<Reader> TBase;
+
+public:
+ using TBase::AssumeConnectionClosed;
+ using TBase::Header;
+ using TBase::ParseGeneric;
+ using TBase::State;
+
+ static constexpr size_t DefaultBufSize = 64 << 10;
+ static constexpr unsigned int DefaultWinSize = 15;
+
+ TCompressedHttpReader()
+ : CompressedInput(false)
+ , BufSize(0)
+ , CurContSize(0)
+ , MaxContSize(0)
+ , Buf(nullptr)
+ , ZErr(0)
+ , ConnectionClosed(0)
+ , IgnoreTrailingGarbage(true)
+ {
+ memset(&Stream, 0, sizeof(Stream));
+ }
+
+ ~TCompressedHttpReader() {
+ ClearStream();
+
+ if (Buf) {
+ free(Buf);
+ Buf = nullptr;
+ }
+ }
+
+ void SetConnectionClosed(int cc) {
+ ConnectionClosed = cc;
+ }
+
+ void SetIgnoreTrailingGarbage(bool ignore) {
+ IgnoreTrailingGarbage = ignore;
+ }
+
+ int Init(
+ THttpHeader* H,
+ int parsHeader,
+ const size_t maxContSize = Max<size_t>(),
+ const size_t bufSize = DefaultBufSize,
+ const unsigned int winSize = DefaultWinSize,
+ bool headRequest = false)
+ {
+ ZErr = 0;
+ CurContSize = 0;
+ MaxContSize = maxContSize;
+
+ int ret = TBase::Init(H, parsHeader, ConnectionClosed, headRequest);
+ if (ret)
+ return ret;
+
+ ret = SetCompression(H->compression_method, bufSize, winSize);
+ return ret;
+ }
+
+ long Read(void*& buf) {
+ if (!CompressedInput) {
+ long res = TBase::Read(buf);
+ if (res > 0) {
+ CurContSize += (size_t)res;
+ if (CurContSize > MaxContSize) {
+ ZErr = E2BIG;
+ return -1;
+ }
+ }
+ return res;
+ }
+
+ while (true) {
+ if (Stream.avail_in == 0) {
+ void* tmpin = Stream.next_in;
+ long res = TBase::Read(tmpin);
+ Stream.next_in = (Bytef*)tmpin;
+ if (res <= 0)
+ return res;
+ Stream.avail_in = (uInt)res;
+ }
+
+ Stream.next_out = Buf;
+ Stream.avail_out = (uInt)BufSize;
+ buf = Buf;
+
+ int err = inflate(&Stream, Z_SYNC_FLUSH);
+
+ //Y_ASSERT(Stream.avail_in == 0);
+
+ switch (err) {
+ case Z_OK:
+ // there is no data in next_out yet
+ if (BufSize == Stream.avail_out)
+ continue;
+ [[fallthrough]]; // don't break or return; continue with Z_STREAM_END case
+
+ case Z_STREAM_END:
+ if (Stream.total_out > MaxContSize) {
+ ZErr = E2BIG;
+ return -1;
+ }
+ if (!IgnoreTrailingGarbage && BufSize == Stream.avail_out && Stream.avail_in > 0) {
+ Header->error = EXT_HTTP_GZIPERROR;
+ ZErr = EFAULT;
+ Stream.msg = (char*)"trailing garbage";
+ return -1;
+ }
+ return long(BufSize - Stream.avail_out);
+
+ case Z_NEED_DICT:
+ case Z_DATA_ERROR:
+ Header->error = EXT_HTTP_GZIPERROR;
+ ZErr = EFAULT;
+ return -1;
+
+ case Z_MEM_ERROR:
+ ZErr = ENOMEM;
+ return -1;
+
+ default:
+ ZErr = EINVAL;
+ return -1;
+ }
+ }
+
+ return -1;
+ }
+
+ const char* ZMsg() const {
+ return Stream.msg;
+ }
+
+ int ZError() const {
+ return ZErr;
+ }
+
+ size_t GetCurContSize() const {
+ return CompressedInput ? Stream.total_out : CurContSize;
+ }
+
+protected:
+ int SetCompression(const int compression, const size_t bufSize,
+ const unsigned int winSize) {
+ ClearStream();
+
+ int winsize = winSize;
+ switch ((enum HTTP_COMPRESSION)compression) {
+ case HTTP_COMPRESSION_UNSET:
+ case HTTP_COMPRESSION_IDENTITY:
+ CompressedInput = false;
+ return 0;
+ case HTTP_COMPRESSION_GZIP:
+ CompressedInput = true;
+ winsize += 16; // 16 indicates gzip, see zlib.h
+ break;
+ case HTTP_COMPRESSION_DEFLATE:
+ CompressedInput = true;
+ winsize = -winsize; // negative indicates raw deflate stream, see zlib.h
+ break;
+ case HTTP_COMPRESSION_COMPRESS:
+ case HTTP_COMPRESSION_ERROR:
+ default:
+ CompressedInput = false;
+ ZErr = ENOTSUP;
+ return -1;
+ }
+
+ if (bufSize != BufSize) {
+ if (Buf)
+ free(Buf);
+ Buf = (ui8*)malloc(bufSize);
+ if (!Buf) {
+ ZErr = ENOMEM;
+ return -1;
+ }
+ BufSize = bufSize;
+ }
+
+ int err = inflateInit2(&Stream, winsize);
+ switch (err) {
+ case Z_OK:
+ Stream.total_in = 0;
+ Stream.total_out = 0;
+ Stream.avail_in = 0;
+ return 0;
+
+ case Z_DATA_ERROR: // never happens, see zlib.h
+ CompressedInput = false;
+ ZErr = EFAULT;
+ return -1;
+
+ case Z_MEM_ERROR:
+ CompressedInput = false;
+ ZErr = ENOMEM;
+ return -1;
+
+ default:
+ CompressedInput = false;
+ ZErr = EINVAL;
+ return -1;
+ }
+ }
+
+ void ClearStream() {
+ if (CompressedInput) {
+ inflateEnd(&Stream);
+ CompressedInput = false;
+ }
+ }
+
+ z_stream Stream;
+ bool CompressedInput;
+ size_t BufSize;
+ size_t CurContSize, MaxContSize;
+ ui8* Buf;
+ int ZErr;
+ int ConnectionClosed;
+ bool IgnoreTrailingGarbage;
+};
+
+class zlib_exception: public yexception {
+};
+
+template <class Reader>
+class SCompressedHttpReader: public TCompressedHttpReader<Reader> {
+ typedef TCompressedHttpReader<Reader> TBase;
+
+public:
+ using TBase::ZError;
+ using TBase::ZMsg;
+
+ SCompressedHttpReader()
+ : TBase()
+ {
+ }
+
+ int Init(
+ THttpHeader* H,
+ int parsHeader,
+ const size_t maxContSize = Max<size_t>(),
+ const size_t bufSize = TBase::DefaultBufSize,
+ const unsigned int winSize = TBase::DefaultWinSize,
+ bool headRequest = false)
+ {
+ int ret = TBase::Init(H, parsHeader, maxContSize, bufSize, winSize, headRequest);
+ return (int)HandleRetValue((long)ret);
+ }
+
+ long Read(void*& buf) {
+ long ret = TBase::Read(buf);
+ return HandleRetValue(ret);
+ }
+
+protected:
+ long HandleRetValue(long ret) {
+ switch (ZError()) {
+ case 0:
+ return ret;
+ case ENOMEM:
+ ythrow yexception() << "SCompressedHttpReader: not enough memory";
+ case EINVAL:
+ ythrow yexception() << "SCompressedHttpReader: zlib error: " << ZMsg();
+ case ENOTSUP:
+ ythrow yexception() << "SCompressedHttpReader: unsupported compression method";
+ case EFAULT:
+ ythrow zlib_exception() << "SCompressedHttpReader: " << ZMsg();
+ case E2BIG:
+ ythrow zlib_exception() << "SCompressedHttpReader: Content exceeds maximum length";
+ default:
+ ythrow yexception() << "SCompressedHttpReader: unknown error";
+ }
+ }
+};
diff --git a/library/cpp/http/fetch/library-htfetch_ut_hreflang_in.h b/library/cpp/http/fetch/library-htfetch_ut_hreflang_in.h
new file mode 100644
index 0000000000..0df89bdc79
--- /dev/null
+++ b/library/cpp/http/fetch/library-htfetch_ut_hreflang_in.h
@@ -0,0 +1,155 @@
+#pragma once
+
+char hreflang_ut_in[] = "HTTP/1.1 200 OK\n"
+ "Date: Thu, 15 Nov 2012 22:38:28 GMT\n"
+ "Server: Apache/2\n"
+ "X-Powered-By: PHP/5.2.17\n"
+ "Set-Cookie: PHPSESSID=6d69474d1cc019d7d82714c9472bc6d6; path=/\n"
+ "Expires: Thu, 19 Nov 1981 08:52:00 GMT\n"
+ "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\n"
+ "Pragma: no-cache\n"
+ "Link: <http://www.forexticket.cn.com/zh/currency/converter-EEK-XAG>; rel='alternate'; hreflang='zh-CN'\n"
+ "Link: <http://www.forexticket.tw/zh/currency/converter-EEK-XAG>; rel='alternate'; hreflang='zh-TW'\n"
+ "Link: <http://www.forexticket.hk/zh/currency/converter-EEK-XAG>; rel='alternate'; hreflang='zh-HK'\n"
+ "Link: <http://www.forexticket.sg/zh/currency/converter-EEK-XAG>; rel='alternate'; hreflang='zh-SG'\n"
+ "Link: <http://www.forexticket.in/hi/currency/converter-EEK-XAG>; rel='alternate'; hreflang='hi-IN'\n"
+ "Link: <http://www.forexticket.com.fj/hi/currency/converter-EEK-XAG>; rel='alternate'; hreflang='hi-FJ'\n"
+ "Link: <http://www.forexticket.in/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-IN'\n"
+ "Link: <http://www.forexticket.us/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-US'\n"
+ "Link: <http://www.forexticket.com.pk/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-PK'\n"
+ "Link: <http://www.forexticket-bd.com/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-BD'\n"
+ "Link: <http://www.forexticket-ng.com/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-NG'\n"
+ "Link: <http://www.forexticket.co.uk/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-GB'\n"
+ "Link: <http://www.forexticket.co.za/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-ZA'\n"
+ "Link: <http://www.forexticket.co.ke/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-KE'\n"
+ "Link: <http://www.forexticket.com/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-CA'\n"
+ "Link: <http://www.forexticket-gh.com/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-GH'\n"
+ "Link: <http://www.forexticket.biz/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-AU'\n"
+ "Link: <http://www.forexticket.cm/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-CM'\n"
+ "Link: <http://www.forexticket-kh.com/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-KH'\n"
+ "Link: <http://www.forexticket.hk/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-HK'\n"
+ "Link: <http://www.forexticket.la/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-LA'\n"
+ "Link: <http://www.forexticket.sg/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-SG'\n"
+ "Link: <http://www.forexticket.co.nz/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-NZ'\n"
+ "Link: <http://www.forexticket.com.pr/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-PR'\n"
+ "Link: <http://www.forexticket.com.fj/en/currency/converter-EEK-XAG>; rel='alternate'; hreflang='en-FJ'\n"
+ "Link: <http://www.forexticket.us/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-US'\n"
+ "Link: <http://www.forexticket.mx/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-MX'\n"
+ "Link: <http://www.forexticket.co/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-CO'\n"
+ "Link: <http://www.forexticket.com.ar/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-AR'\n"
+ "Link: <http://www.forexticket-pe.com/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-PE'\n"
+ "Link: <http://www.forexticket.co.ve/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-VE'\n"
+ "Link: <http://www.forexticket.cl/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-CL'\n"
+ "Link: <http://www.forexticket.ec/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-EC'\n"
+ "Link: <http://www.forexticket.com.gt/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-GT'\n"
+ "Link: <http://www.forexticket.bo/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-BO'\n"
+ "Link: <http://www.forexticket.hn/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-HN'\n"
+ "Link: <http://www.forexticket.com.py/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-PY'\n"
+ "Link: <http://www.forexticket.es/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-ES'\n"
+ "Link: <http://www.forexticket.com.sv/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-SV'\n"
+ "Link: <http://www.forexticket.com.ni/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-NI'\n"
+ "Link: <http://www.forexticket.co.cr/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-CR'\n"
+ "Link: <http://www.forexticket.com.pr/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-PR'\n"
+ "Link: <http://www.forexticket.com.uy/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-UY'\n"
+ "Link: <http://www.forexticket.com.pa/es/cambio/divisas-EEK-XAG>; rel='alternate'; hreflang='es-PA'\n"
+ "Link: <http://www.forexticket.asia.com/id/currency/converter-EEK-XAG>; rel='alternate'; hreflang='id-ID'\n"
+ "Link: <http://www.forexticket.com.br/pt/moeda/conversor-EEK-XAG>; rel='alternate'; hreflang='pt-BR'\n"
+ "Link: <http://www.forexticket-mz.com/pt/moeda/conversor-EEK-XAG>; rel='alternate'; hreflang='pt-MZ'\n"
+ "Link: <http://www.forexticket.com.pt/pt/moeda/conversor-EEK-XAG>; rel='alternate'; hreflang='pt-PT'\n"
+ "Link: <http://www.forexticket.tl/pt/moeda/conversor-EEK-XAG>; rel='alternate'; hreflang='pt-TL'\n"
+ "Link: <http://www.forexticket.ru/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-RU'\n"
+ "Link: <http://www.forexticket-kz.com/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-KZ'\n"
+ "Link: <http://www.forexticket-tj.com/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-TJ'\n"
+ "Link: <http://www.forexticket-kg.com/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-KG'\n"
+ "Link: <http://www.forexticket-ge.com/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-GE'\n"
+ "Link: <http://www.forexticket.mn/ru/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ru-MN'\n"
+ "Link: <http://www.forexticket.jp/ja/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ja-JP'\n"
+ "Link: <http://www.forexticket-ph.com/tl/currency/converter-EEK-XAG>; rel='alternate'; hreflang='tl-PH'\n"
+ "Link: <http://www.forexticket.vn/vi/currency/converter-EEK-XAG>; rel='alternate'; hreflang='vi-VN'\n"
+ "Link: <http://www.forexticket.de/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-DE'\n"
+ "Link: <http://www.forexticket.be/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-BE'\n"
+ "Link: <http://www.forexticket.at/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-AT'\n"
+ "Link: <http://www.forexticket.ch/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-CH'\n"
+ "Link: <http://www.forexticket.lu/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-LU'\n"
+ "Link: <http://www.forexticket.li/de/waehrungsumrechner/devisen-EEK-XAG>; rel='alternate'; hreflang='de-LI'\n"
+ "Link: <http://www.forexticket.de/de/waehrungsumrechner/devisen-EEK-XAG>; rel='canonical'\n"
+ "Link: <http://www.forexticket-eg.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-EG'\n"
+ "Link: <http://www.forexticket-dz.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-DZ'\n"
+ "Link: <http://www.forexticket-ma.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-MA'\n"
+ "Link: <http://www.forexticket-iq.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-IQ'\n"
+ "Link: <http://www.forexticket-sa.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-SA'\n"
+ "Link: <http://www.forexticket-sy.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-SY'\n"
+ "Link: <http://www.forexticket-tn.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-TN'\n"
+ "Link: <http://www.forexticket-td.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-TD'\n"
+ "Link: <http://www.forexticket-so.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-SO'\n"
+ "Link: <http://www.forexticket.co.il/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-IL'\n"
+ "Link: <http://www.forexticket-jo.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-JO'\n"
+ "Link: <http://www.forexticket.ae/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-AE'\n"
+ "Link: <http://www.forexticket-lb.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-LB'\n"
+ "Link: <http://www.forexticket-om.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-OM'\n"
+ "Link: <http://www.forexticket-kw.com/ar/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ar-KW'\n"
+ "Link: <http://www.forexticket-tr.com/tr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='tr-TR'\n"
+ "Link: <http://www.forexticket-bg.com/tr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='tr-BG'\n"
+ "Link: <http://www.forexticket-cy.com/tr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='tr-CY'\n"
+ "Link: <http://www.forexticket.ir/fa/currency/converter-EEK-XAG>; rel='alternate'; hreflang='fa-IR'\n"
+ "Link: <http://www.forexticket.af/fa/currency/converter-EEK-XAG>; rel='alternate'; hreflang='fa-AF'\n"
+ "Link: <http://www.forexticket.cd/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-CD'\n"
+ "Link: <http://www.forexticket.fr/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-FR'\n"
+ "Link: <http://www.forexticket.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-CA'\n"
+ "Link: <http://www.forexticket.mg/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-MG'\n"
+ "Link: <http://www.forexticket.cm/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-CM'\n"
+ "Link: <http://www.forexticket-kh.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-KH'\n"
+ "Link: <http://www.forexticket-ml.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-ML'\n"
+ "Link: <http://www.forexticket-sn.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-SN'\n"
+ "Link: <http://www.forexticket-tn.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-TN'\n"
+ "Link: <http://www.forexticket-td.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-TD'\n"
+ "Link: <http://www.forexticket.be/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-BE'\n"
+ "Link: <http://www.forexticket-gn.com/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-GN'\n"
+ "Link: <http://www.forexticket.ht/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-HT'\n"
+ "Link: <http://www.forexticket.ch/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-CH'\n"
+ "Link: <http://www.forexticket.la/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-LA'\n"
+ "Link: <http://www.forexticket.lu/fr/conversion/monnaie-EEK-XAG>; rel='alternate'; hreflang='fr-LU'\n"
+ "Link: <http://www.forexticket-th.com/th/currency/converter-EEK-XAG>; rel='alternate'; hreflang='th-TH'\n"
+ "Link: <http://www.forexticket.co.uk/cy/currency/converter-EEK-XAG>; rel='alternate'; hreflang='cy-GB'\n"
+ "Link: <http://www.forexticket.co.uk/ga/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ga-GB'\n"
+ "Link: <http://www.forexticket.it/it/convertitore/valuta-EEK-XAG>; rel='alternate'; hreflang='it-IT'\n"
+ "Link: <http://www.forexticket.ch/it/convertitore/valuta-EEK-XAG>; rel='alternate'; hreflang='it-CH'\n"
+ "Link: <http://www.forexticket.co.za/af/currency/converter-EEK-XAG>; rel='alternate'; hreflang='af-ZA'\n"
+ "Link: <http://www.forexticket.kr/ko/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ko-KR'\n"
+ "Link: <http://www.forexticket-ua.com/uk/currency/converter-EEK-XAG>; rel='alternate'; hreflang='uk-UA'\n"
+ "Link: <http://www.forexticket-tz.com/sw/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sw-TZ'\n"
+ "Link: <http://www.forexticket.co.ke/sw/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sw-KE'\n"
+ "Link: <http://www.forexticket.pl/pl/currency/converter-EEK-XAG>; rel='alternate'; hreflang='pl-PL'\n"
+ "Link: <http://www.forexticket.com.my/ms/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ms-MY'\n"
+ "Link: <http://www.forexticket.sg/ms/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ms-SG'\n"
+ "Link: <http://www.forexticket.ro/ro/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ro-RO'\n"
+ "Link: <http://www.forexticket.nl/nl/currency/converter-EEK-XAG>; rel='alternate'; hreflang='nl-NL'\n"
+ "Link: <http://www.forexticket.be/nl/currency/converter-EEK-XAG>; rel='alternate'; hreflang='nl-BE'\n"
+ "Link: <http://www.forexticket.gr/el/currency/converter-EEK-XAG>; rel='alternate'; hreflang='el-GR'\n"
+ "Link: <http://www.forexticket-al.com/el/currency/converter-EEK-XAG>; rel='alternate'; hreflang='el-AL'\n"
+ "Link: <http://www.forexticket-cy.com/el/currency/converter-EEK-XAG>; rel='alternate'; hreflang='el-CY'\n"
+ "Link: <http://www.forexticket.cz/cs/currency/converter-EEK-XAG>; rel='alternate'; hreflang='cs-CZ'\n"
+ "Link: <http://www.forexticket.hu/hu/currency/converter-EEK-XAG>; rel='alternate'; hreflang='hu-HU'\n"
+ "Link: <http://www.forexticket.se/sv/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sv-SE'\n"
+ "Link: <http://www.forexticket.eu/sv/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sv-FI'\n"
+ "Link: <http://www.forexticket.co.il/iw/currency/converter-EEK-XAG>; rel='alternate'; hreflang='iw-IL'\n"
+ "Link: <http://www.forexticket.co.il/yi/currency/converter-EEK-XAG>; rel='alternate'; hreflang='yi-IL'\n"
+ "Link: <http://www.forexticket-bg.com/bg/currency/converter-EEK-XAG>; rel='alternate'; hreflang='bg-BG'\n"
+ "Link: <http://www.forexticket.es/ca/currency/converter-EEK-XAG>; rel='alternate'; hreflang='ca-ES'\n"
+ "Link: <http://www.forexticket.es/gl/currency/converter-EEK-XAG>; rel='alternate'; hreflang='gl-ES'\n"
+ "Link: <http://www.forexticket.dk/da/currency/converter-EEK-XAG>; rel='alternate'; hreflang='da-DK'\n"
+ "Link: <http://www.forexticket.eu/fi/currency/converter-EEK-XAG>; rel='alternate'; hreflang='fi-FI'\n"
+ "Link: <http://www.forexticket-hr.com/hr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='hr-HR'\n"
+ "Link: <http://www.forexticket-hr.com/sr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sr-HR'\n"
+ "Link: <http://www.forexticket.me/sr/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sr-ME'\n"
+ "Link: <http://www.forexticket.lt/lt/currency/converter-EEK-XAG>; rel='alternate'; hreflang='lt-LT'\n"
+ "Link: <http://www.forexticket-al.com/sq/currency/converter-EEK-XAG>; rel='alternate'; hreflang='sq-AL'\n"
+ "Link: <http://www.forexticket.lv/lv/currency/converter-EEK-XAG>; rel='alternate'; hreflang='lv-LV'\n"
+ "Link: <http://www.forexticket.co.ee/et/currency/converter-EEK-XAG>; rel='alternate'; hreflang='et-EE'\n"
+ "Vary: Accept-Encoding,User-Agent\n"
+ "Content-Encoding: gzip\n"
+ "Keep-Alive: timeout=1, max=100\n"
+ "Connection: Keep-Alive\n"
+ "Transfer-Encoding: chunked\n"
+ "Content-Type: text/html\n"
+ "\n";
diff --git a/library/cpp/http/fetch/library-htfetch_ut_hreflang_out.h b/library/cpp/http/fetch/library-htfetch_ut_hreflang_out.h
new file mode 100644
index 0000000000..bef8bacff5
--- /dev/null
+++ b/library/cpp/http/fetch/library-htfetch_ut_hreflang_out.h
@@ -0,0 +1,3 @@
+#pragma once
+
+char hreflang_ut_out[] = "zh-CN http://www.forexticket.cn.com/zh/currency/converter-EEK-XAG\tzh-TW http://www.forexticket.tw/zh/currency/converter-EEK-XAG\tzh-HK http://www.forexticket.hk/zh/currency/converter-EEK-XAG\tzh-SG http://www.forexticket.sg/zh/currency/converter-EEK-XAG\thi-IN http://www.forexticket.in/hi/currency/converter-EEK-XAG\thi-FJ http://www.forexticket.com.fj/hi/currency/converter-EEK-XAG\ten-IN http://www.forexticket.in/en/currency/converter-EEK-XAG\ten-US http://www.forexticket.us/en/currency/converter-EEK-XAG\ten-PK http://www.forexticket.com.pk/en/currency/converter-EEK-XAG\ten-BD http://www.forexticket-bd.com/en/currency/converter-EEK-XAG\ten-NG http://www.forexticket-ng.com/en/currency/converter-EEK-XAG\ten-GB http://www.forexticket.co.uk/en/currency/converter-EEK-XAG\ten-ZA http://www.forexticket.co.za/en/currency/converter-EEK-XAG\ten-KE http://www.forexticket.co.ke/en/currency/converter-EEK-XAG\ten-CA http://www.forexticket.com/en/currency/converter-EEK-XAG\ten-GH http://www.forexticket-gh.com/en/currency/converter-EEK-XAG\ten-AU http://www.forexticket.biz/en/currency/converter-EEK-XAG\ten-CM http://www.forexticket.cm/en/currency/converter-EEK-XAG\ten-KH http://www.forexticket-kh.com/en/currency/converter-EEK-XAG\ten-HK http://www.forexticket.hk/en/currency/converter-EEK-XAG\ten-LA http://www.forexticket.la/en/currency/converter-EEK-XAG\ten-SG http://www.forexticket.sg/en/currency/converter-EEK-XAG\ten-NZ http://www.forexticket.co.nz/en/currency/converter-EEK-XAG\ten-PR http://www.forexticket.com.pr/en/currency/converter-EEK-XAG\ten-FJ http://www.forexticket.com.fj/en/currency/converter-EEK-XAG\tes-US http://www.forexticket.us/es/cambio/divisas-EEK-XAG\tes-MX http://www.forexticket.mx/es/cambio/divisas-EEK-XAG\tes-CO http://www.forexticket.co/es/cambio/divisas-EEK-XAG\tes-AR http://www.forexticket.com.ar/es/cambio/divisas-EEK-XAG\tes-PE http://www.forexticket-pe.com/es/cambio/divisas-EEK-XAG\tes-VE http://www.forexticket.co.ve/es/cambio/divisas-EEK-XAG\tes-CL http://www.forexticket.cl/es/cambio/divisas-EEK-XAG\tes-EC http://www.forexticket.ec/es/cambio/divisas-EEK-XAG\tes-GT http://www.forexticket.com.gt/es/cambio/divisas-EEK-XAG\tes-BO http://www.forexticket.bo/es/cambio/divisas-EEK-XAG\tes-HN http://www.forexticket.hn/es/cambio/divisas-EEK-XAG\tes-PY http://www.forexticket.com.py/es/cambio/divisas-EEK-XAG\tes-ES http://www.forexticket.es/es/cambio/divisas-EEK-XAG\tes-SV http://www.forexticket.com.sv/es/cambio/divisas-EEK-XAG\tes-NI http://www.forexticket.com.ni/es/cambio/divisas-EEK-XAG\tes-CR http://www.forexticket.co.cr/es/cambio/divisas-EEK-XAG\tes-PR http://www.forexticket.com.pr/es/cambio/divisas-EEK-XAG\tes-UY http://www.forexticket.com.uy/es/cambio/divisas-EEK-XAG\tes-PA http://www.forexticket.com.pa/es/cambio/divisas-EEK-XAG\tid-ID http://www.forexticket.asia.com/id/currency/converter-EEK-XAG\tpt-BR http://www.forexticket.com.br/pt/moeda/conversor-EEK-XAG\tpt-MZ http://www.forexticket-mz.com/pt/moeda/conversor-EEK-XAG\tpt-PT http://www.forexticket.com.pt/pt/moeda/conversor-EEK-XAG\tpt-TL http://www.forexticket.tl/pt/moeda/conversor-EEK-XAG\tru-RU http://www.forexticket.ru/ru/currency/converter-EEK-XAG\tru-KZ http://www.forexticket-kz.com/ru/currency/converter-EEK-XAG\tru-TJ http://www.forexticket-tj.com/ru/currency/converter-EEK-XAG\tru-KG http://www.forexticket-kg.com/ru/currency/converter-EEK-XAG\tru-GE http://www.forexticket-ge.com/ru/currency/converter-EEK-XAG\tru-MN http://www.forexticket.mn/ru/currency/converter-EEK-XAG\tja-JP http://www.forexticket.jp/ja/currency/converter-EEK-XAG\ttl-PH http://www.forexticket-ph.com/tl/currency/converter-EEK-XAG\tvi-VN http://www.forexticket.vn/vi/currency/converter-EEK-XAG\tde-DE http://www.forexticket.de/de/waehrungsumrechner/devisen-EEK-XAG\tde-BE http://www.forexticket.be/de/waehrungsumrechner/devisen-EEK-XAG\tde-AT http://www.forexticket.at/de/waehrungsumrechner/devisen-EEK-XAG\tde-CH http://www.forexticket.ch/de/waehrungsumrechner/devisen-EEK-XAG\tde-LU http://www.forexticket.lu/de/waehrungsumrechner/devisen-EEK-XAG\tde-LI http://www.forexticket.li/de/waehrungsumrechner/devisen-EEK-XAG\tar-EG http://www.forexticket-eg.com/ar/currency/converter-EEK-XAG\tar-DZ http://www.forexticket-dz.com/ar/currency/converter-EEK-XAG\tar-MA http://www.forexticket-ma.com/ar/currency/converter-EEK-XAG\tar-IQ http://www.forexticket-iq.com/ar/currency/converter-EEK-XAG\tar-SA http://www.forexticket-sa.com/ar/currency/converter-EEK-XAG\tar-SY http://www.forexticket-sy.com/ar/currency/converter-EEK-XAG\tar-TN http://www.forexticket-tn.com/ar/currency/converter-EEK-XAG\tar-TD http://www.forexticket-td.com/ar/currency/converter-EEK-XAG\tar-SO http://www.forexticket-so.com/ar/currency/converter-EEK-XAG\tar-IL http://www.forexticket.co.il/ar/currency/converter-EEK-XAG\tar-JO http://www.forexticket-jo.com/ar/currency/converter-EEK-XAG\tar-AE http://www.forexticket.ae/ar/currency/converter-EEK-XAG\tar-LB http://www.forexticket-lb.com/ar/currency/converter-EEK-XAG\tar-OM http://www.forexticket-om.com/ar/currency/converter-EEK-XAG\tar-KW http://www.forexticket-kw.com/ar/currency/converter-EEK-XAG\ttr-TR http://www.forexticket-tr.com/tr/currency/converter-EEK-XAG\ttr-BG http://www.forexticket-bg.com/tr/currency/converter-EEK-XAG\ttr-CY http://www.forexticket-cy.com/tr/currency/converter-EEK-XAG\tfa-IR http://www.forexticket.ir/fa/currency/converter-EEK-XAG\tfa-AF http://www.forexticket.af/fa/currency/converter-EEK-XAG\tfr-CD http://www.forexticket.cd/fr/conversion/monnaie-EEK-XAG\tfr-FR http://www.forexticket.fr/fr/conversion/monnaie-EEK-XAG\tfr-CA http://www.forexticket.com/fr/conversion/monnaie-EEK-XAG\tfr-MG http://www.forexticket.mg/fr/conversion/monnaie-EEK-XAG\tfr-CM http://www.forexticket.cm/fr/conversion/monnaie-EEK-XAG\tfr-KH http://www.forexticket-kh.com/fr/conversion/monnaie-EEK-XAG\tfr-ML http://www.forexticket-ml.com/fr/conversion/monnaie-EEK-XAG\tfr-SN http://www.forexticket-sn.com/fr/conversion/monnaie-EEK-XAG\tfr-TN http://www.forexticket-tn.com/fr/conversion/monnaie-EEK-XAG\tfr-TD http://www.forexticket-td.com/fr/conversion/monnaie-EEK-XAG\tfr-BE http://www.forexticket.be/fr/conversion/monnaie-EEK-XAG\tfr-GN http://www.forexticket-gn.com/fr/conversion/monnaie-EEK-XAG\tfr-HT http://www.forexticket.ht/fr/conversion/monnaie-EEK-XAG\tfr-CH http://www.forexticket.ch/fr/conversion/monnaie-EEK-XAG\tfr-LA http://www.forexticket.la/fr/conversion/monnaie-EEK-XAG\tfr-LU http://www.forexticket.lu/fr/conversion/monnaie-EEK-XAG\tth-TH http://www.forexticket-th.com/th/currency/converter-EEK-XAG\tcy-GB http://www.forexticket.co.uk/cy/currency/converter-EEK-XAG\tga-GB http://www.forexticket.co.uk/ga/currency/converter-EEK-XAG\tit-IT http://www.forexticket.it/it/convertitore/valuta-EEK-XAG\tit-CH http://www.forexticket.ch/it/convertitore/valuta-EEK-XAG\taf-ZA http://www.forexticket.co.za/af/currency/converter-EEK-XAG\tko-KR http://www.forexticket.kr/ko/currency/converter-EEK-XAG\tuk-UA http://www.forexticket-ua.com/uk/currency/converter-EEK-XAG\tsw-TZ http://www.forexticket-tz.com/sw/currency/converter-EEK-XAG\tsw-KE http://www.forexticket.co.ke/sw/currency/converter-EEK-XAG\tpl-PL http://www.forexticket.pl/pl/currency/converter-EEK-XAG\tms-MY http://www.forexticket.com.my/ms/currency/converter-EEK-XAG\tms-SG http://www.forexticket.sg/ms/currency/converter-EEK-XAG\tro-RO http://www.forexticket.ro/ro/currency/converter-EEK-XAG\tnl-NL http://www.forexticket.nl/nl/currency/converter-EEK-XAG\tnl-BE http://www.forexticket.be/nl/currency/converter-EEK-XAG\tel-GR http://www.forexticket.gr/el/currency/converter-EEK-XAG\tel-AL http://www.forexticket-al.com/el/currency/converter-EEK-XAG\tel-CY http://www.forexticket-cy.com/el/currency/converter-EEK-XAG\tcs-CZ http://www.forexticket.cz/cs/currency/converter-EEK-XAG\thu-HU http://www.forexticket.hu/hu/currency/converter-EEK-XAG\tsv-SE http://www.forexticket.se/sv/currency/converter-EEK-XAG\tsv-FI http://www.forexticket.eu/sv/currency/converter-EEK-XAG\tiw-IL http://www.forexticket.co.il/iw/currency/converter-EEK-XAG\tyi-IL http://www.forexticket.co.il/yi/currency/converter-EEK-XAG\tbg-BG http://www.forexticket-bg.com/bg/currency/converter-EEK-XAG\tca-ES http://www.forexticket.es/ca/currency/converter-EEK-XAG\tgl-ES http://www.forexticket.es/gl/currency/converter-EEK-XAG\tda-DK http://www.forexticket.dk/da/currency/converter-EEK-XAG\tfi-FI http://www.forexticket.eu/fi/currency/converter-EEK-XAG\thr-HR http://www.forexticket-hr.com/hr/currency/converter-EEK-XAG\tsr-HR http://www.forexticket-hr.com/sr/currency/converter-EEK-XAG\tsr-ME http://www.forexticket.me/sr/currency/converter-EEK-XAG\tlt-LT http://www.forexticket.lt/lt/currency/converter-EEK-XAG\tsq-AL http://www.forexticket-al.com/sq/currency/converter-EEK-XAG\tlv-LV http://www.forexticket.lv/lv/currency/converter-EEK-XAG\tet-EE http://www.forexticket.co.ee/et/currency/converter-EEK-XAG";
diff --git a/library/cpp/http/fetch/sockhandler.h b/library/cpp/http/fetch/sockhandler.h
new file mode 100644
index 0000000000..e18149f657
--- /dev/null
+++ b/library/cpp/http/fetch/sockhandler.h
@@ -0,0 +1,130 @@
+#pragma once
+
+#include <library/cpp/logger/all.h>
+
+#include <util/generic/buffer.h>
+#include <util/generic/map.h>
+#include <util/generic/vector.h>
+#include <util/network/address.h>
+#include <util/network/ip.h>
+#include <util/network/socket.h>
+#include <util/system/mutex.h>
+#include <util/system/yassert.h>
+
+#include <cerrno>
+#include <util/generic/noncopyable.h>
+
+class TAddrList: public TVector<NAddr::IRemoteAddrRef> {
+private:
+ using TBase = TVector<NAddr::IRemoteAddrRef>;
+
+public:
+ //msvc doesn't support base class constructor inheritance
+ TAddrList() = default;
+
+ template <typename T>
+ TAddrList(T&& arg)
+ : TBase(std::forward<T>(arg))
+ {
+ }
+
+ template <typename T1, typename T2>
+ TAddrList(T1&& arg1, T2&& arg2)
+ : TBase(std::forward<T1>(arg1), std::forward<T2>(arg2))
+ {
+ }
+
+ TAddrList(std::initializer_list<NAddr::IRemoteAddrRef> list)
+ : TBase(list)
+ {
+ }
+
+ static TAddrList MakeV4Addr(ui32 ip, TIpPort port) {
+ return TAddrList({new NAddr::TIPv4Addr(TIpAddress(htonl(ip), htons(port)))});
+ }
+
+ std::pair<ui32, TIpPort> GetV4Addr() const {
+ for (const auto& addrRef : *this) {
+ const sockaddr* sa = addrRef->Addr();
+ if (sa->sa_family == AF_INET) {
+ const sockaddr_in* sin = reinterpret_cast<const sockaddr_in*>(sa);
+ return std::make_pair(ntohl(sin->sin_addr.s_addr), ntohs(sin->sin_port));
+ }
+ }
+ return std::make_pair(0, 0);
+ }
+};
+
+class TSimpleSocketHandler {
+public:
+ TSimpleSocketHandler() = default;
+
+ int Good() const {
+ return static_cast<bool>(Socket);
+ }
+
+ int Connect(const TAddrList& addrs, TDuration timeout) {
+ try {
+ for (const auto& item : addrs) {
+ const sockaddr* sa = item->Addr();
+ TSocketHolder s(socket(sa->sa_family, SOCK_STREAM, 0));
+ if (s.Closed()) {
+ continue;
+ }
+
+#ifndef WIN32
+ if (fcntl(s, F_SETFD, FD_CLOEXEC)) // no inherit on fork()/exec()
+ return errno ? errno : EBADF;
+#endif
+ if (connect(s, sa, item->Len())) {
+ s.Close();
+ continue;
+ }
+
+ Socket.Reset(new TSocket(s.Release()));
+ Socket->SetSocketTimeout(timeout.Seconds(), timeout.MilliSecondsOfSecond());
+ Socket->SetZeroLinger();
+ Socket->SetKeepAlive(true);
+ return 0;
+ }
+ } catch (...) {
+ return EBADF;
+ }
+ return errno ? errno : EBADF;
+ }
+
+ void Disconnect() {
+ if (!Socket)
+ return;
+ Socket->ShutDown(SHUT_RDWR);
+ Socket.Destroy();
+ }
+
+ void SetSocket(SOCKET fd) {
+ Socket.Reset(new TSocket(fd));
+ }
+
+ void shutdown() {
+ Socket->ShutDown(SHUT_WR);
+ }
+
+ int send(const void* message, size_t messlen) {
+ return ((ssize_t)messlen == Socket->Send(message, messlen));
+ }
+
+ int peek() {
+ char buf[1];
+ return (1 == recv(*Socket, buf, 1, MSG_PEEK));
+ }
+
+ ssize_t read(void* buffer, size_t buflen) {
+ return Socket->Recv(buffer, buflen);
+ }
+
+ THolder<TSocket> PickOutSocket() {
+ return std::move(Socket);
+ }
+
+protected:
+ THolder<TSocket> Socket;
+};
diff --git a/library/cpp/http/fetch/ut/ya.make b/library/cpp/http/fetch/ut/ya.make
new file mode 100644
index 0000000000..7486986b36
--- /dev/null
+++ b/library/cpp/http/fetch/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/http/fetch)
+
+OWNER(
+ g:zora
+)
+
+SRCS(
+ httpfsm_ut.cpp
+ httpparser_ut.cpp
+)
+
+END()
diff --git a/library/cpp/http/fetch/ya.make b/library/cpp/http/fetch/ya.make
new file mode 100644
index 0000000000..7737127463
--- /dev/null
+++ b/library/cpp/http/fetch/ya.make
@@ -0,0 +1,38 @@
+LIBRARY()
+
+OWNER(
+ g:zora
+)
+
+PEERDIR(
+ contrib/libs/zlib
+ library/cpp/charset
+ library/cpp/digest/md5
+ library/cpp/http/misc
+ library/cpp/logger
+ library/cpp/mime/types
+ library/cpp/uri
+)
+
+SRCS(
+ http_digest.cpp
+ http_socket.cpp
+ httpheader.cpp
+ httpload.cpp
+ exthttpcodes.cpp
+ httpfsm.rl6
+ httpagent.h
+ httpfetcher.h
+ httpheader.h
+ httpparser.h
+ httpzreader.h
+ sockhandler.h
+)
+
+GENERATE_ENUM_SERIALIZATION(httpheader.h)
+
+SET(RAGEL6_FLAGS -CF1)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/http/io/chunk.cpp b/library/cpp/http/io/chunk.cpp
new file mode 100644
index 0000000000..6975d9eac1
--- /dev/null
+++ b/library/cpp/http/io/chunk.cpp
@@ -0,0 +1,246 @@
+#include "chunk.h"
+
+#include "headers.h"
+
+#include <util/string/cast.h>
+#include <util/generic/utility.h>
+#include <util/generic/yexception.h>
+
+static inline size_t ParseHex(const TString& s) {
+ if (s.empty()) {
+ ythrow yexception() << "can not parse chunk length(empty string)";
+ }
+
+ size_t ret = 0;
+
+ for (TString::const_iterator c = s.begin(); c != s.end(); ++c) {
+ const char ch = *c;
+
+ if (ch >= '0' && ch <= '9') {
+ ret *= 16;
+ ret += ch - '0';
+ } else if (ch >= 'a' && ch <= 'f') {
+ ret *= 16;
+ ret += 10 + ch - 'a';
+ } else if (ch >= 'A' && ch <= 'F') {
+ ret *= 16;
+ ret += 10 + ch - 'A';
+ } else if (ch == ';') {
+ break;
+ } else if (isspace(ch)) {
+ continue;
+ } else {
+ ythrow yexception() << "can not parse chunk length(" << s.data() << ")";
+ }
+ }
+
+ return ret;
+}
+
+static inline char* ToHex(size_t len, char* buf) {
+ do {
+ const size_t val = len % 16;
+
+ *--buf = (val < 10) ? (val + '0') : (val - 10 + 'a');
+ len /= 16;
+ } while (len);
+
+ return buf;
+}
+
+class TChunkedInput::TImpl {
+public:
+ inline TImpl(IInputStream* slave, TMaybe<THttpHeaders>* trailers)
+ : Slave_(slave)
+ , Trailers_(trailers)
+ , Pending_(0)
+ , LastChunkReaded_(false)
+ {
+ if (Trailers_) {
+ Trailers_->Clear();
+ }
+ }
+
+ inline ~TImpl() {
+ }
+
+ inline size_t Read(void* buf, size_t len) {
+ return Perform(len, [this, buf](size_t toRead) { return Slave_->Read(buf, toRead); });
+ }
+
+ inline size_t Skip(size_t len) {
+ return Perform(len, [this](size_t toSkip) { return Slave_->Skip(toSkip); });
+ }
+
+private:
+ template <class Operation>
+ inline size_t Perform(size_t len, const Operation& operation) {
+ if (!HavePendingData()) {
+ return 0;
+ }
+
+ const size_t toProcess = Min(Pending_, len);
+
+ if (toProcess) {
+ const size_t processed = operation(toProcess);
+
+ if (!processed) {
+ ythrow yexception() << "malformed http chunk";
+ }
+
+ Pending_ -= processed;
+
+ return processed;
+ }
+
+ return 0;
+ }
+
+ inline bool HavePendingData() {
+ if (LastChunkReaded_) {
+ return false;
+ }
+
+ if (!Pending_) {
+ if (!ProceedToNextChunk()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ inline bool ProceedToNextChunk() {
+ TString len(Slave_->ReadLine());
+
+ if (len.empty()) {
+ /*
+ * skip crlf from previous chunk
+ */
+
+ len = Slave_->ReadLine();
+ }
+
+ Pending_ = ParseHex(len);
+
+ if (Pending_) {
+ return true;
+ }
+
+ if (Trailers_) {
+ Trailers_->ConstructInPlace(Slave_);
+ }
+ LastChunkReaded_ = true;
+
+ return false;
+ }
+
+private:
+ IInputStream* Slave_;
+ TMaybe<THttpHeaders>* Trailers_;
+ size_t Pending_;
+ bool LastChunkReaded_;
+};
+
+TChunkedInput::TChunkedInput(IInputStream* slave, TMaybe<THttpHeaders>* trailers)
+ : Impl_(new TImpl(slave, trailers))
+{
+}
+
+TChunkedInput::~TChunkedInput() {
+}
+
+size_t TChunkedInput::DoRead(void* buf, size_t len) {
+ return Impl_->Read(buf, len);
+}
+
+size_t TChunkedInput::DoSkip(size_t len) {
+ return Impl_->Skip(len);
+}
+
+class TChunkedOutput::TImpl {
+ typedef IOutputStream::TPart TPart;
+
+public:
+ inline TImpl(IOutputStream* slave)
+ : Slave_(slave)
+ {
+ }
+
+ inline ~TImpl() {
+ }
+
+ inline void Write(const void* buf, size_t len) {
+ const char* ptr = (const char*)buf;
+
+ while (len) {
+ const size_t portion = Min<size_t>(len, 1024 * 16);
+
+ WriteImpl(ptr, portion);
+
+ ptr += portion;
+ len -= portion;
+ }
+ }
+
+ inline void WriteImpl(const void* buf, size_t len) {
+ char tmp[32];
+ char* e = tmp + sizeof(tmp);
+ char* b = ToHex(len, e);
+
+ const TPart parts[] = {
+ TPart(b, e - b),
+ TPart::CrLf(),
+ TPart(buf, len),
+ TPart::CrLf(),
+ };
+
+ Slave_->Write(parts, sizeof(parts) / sizeof(*parts));
+ }
+
+ inline void Flush() {
+ Slave_->Flush();
+ }
+
+ inline void Finish() {
+ Slave_->Write("0\r\n\r\n", 5);
+
+ Flush();
+ }
+
+private:
+ IOutputStream* Slave_;
+};
+
+TChunkedOutput::TChunkedOutput(IOutputStream* slave)
+ : Impl_(new TImpl(slave))
+{
+}
+
+TChunkedOutput::~TChunkedOutput() {
+ try {
+ Finish();
+ } catch (...) {
+ }
+}
+
+void TChunkedOutput::DoWrite(const void* buf, size_t len) {
+ if (Impl_.Get()) {
+ Impl_->Write(buf, len);
+ } else {
+ ythrow yexception() << "can not write to finished stream";
+ }
+}
+
+void TChunkedOutput::DoFlush() {
+ if (Impl_.Get()) {
+ Impl_->Flush();
+ }
+}
+
+void TChunkedOutput::DoFinish() {
+ if (Impl_.Get()) {
+ Impl_->Finish();
+ Impl_.Destroy();
+ }
+}
diff --git a/library/cpp/http/io/chunk.h b/library/cpp/http/io/chunk.h
new file mode 100644
index 0000000000..88d89fafda
--- /dev/null
+++ b/library/cpp/http/io/chunk.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <util/stream/output.h>
+#include <util/generic/maybe.h>
+#include <util/generic/ptr.h>
+
+class THttpHeaders;
+
+/// @addtogroup Streams_Chunked
+/// @{
+/// Ввод данных порциями.
+/// @details Последовательное чтение блоков данных. Предполагается, что
+/// данные записаны в виде <длина блока><блок данных>.
+class TChunkedInput: public IInputStream {
+public:
+ /// Если передан указатель на trailers, то туда будут записаны HTTP trailer'ы (возможно пустые),
+ /// которые идут после чанков.
+ TChunkedInput(IInputStream* slave, TMaybe<THttpHeaders>* trailers = nullptr);
+ ~TChunkedInput() override;
+
+private:
+ size_t DoRead(void* buf, size_t len) override;
+ size_t DoSkip(size_t len) override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+/// Вывод данных порциями.
+/// @details Вывод данных блоками в виде <длина блока><блок данных>. Если объем
+/// данных превышает 64K, они записываются в виде n блоков по 64K + то, что осталось.
+class TChunkedOutput: public IOutputStream {
+public:
+ TChunkedOutput(IOutputStream* slave);
+ ~TChunkedOutput() override;
+
+private:
+ void DoWrite(const void* buf, size_t len) override;
+ void DoFlush() override;
+ void DoFinish() override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+/// @}
diff --git a/library/cpp/http/io/chunk_ut.cpp b/library/cpp/http/io/chunk_ut.cpp
new file mode 100644
index 0000000000..da283f8568
--- /dev/null
+++ b/library/cpp/http/io/chunk_ut.cpp
@@ -0,0 +1,105 @@
+#include "chunk.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/file.h>
+#include <util/system/tempfile.h>
+#include <util/stream/null.h>
+
+#define CDATA "./chunkedio"
+
+Y_UNIT_TEST_SUITE(TestChunkedIO) {
+ static const char test_data[] = "87s6cfbsudg cuisg s igasidftasiy tfrcua6s";
+
+ TString CombString(const TString& s, size_t chunkSize) {
+ TString result;
+ for (size_t pos = 0; pos < s.size(); pos += 2 * chunkSize)
+ result += s.substr(pos, chunkSize);
+ return result;
+ }
+
+ void WriteTestData(IOutputStream * stream, TString * contents) {
+ contents->clear();
+ for (size_t i = 0; i < sizeof(test_data); ++i) {
+ stream->Write(test_data, i);
+ contents->append(test_data, i);
+ }
+ }
+
+ void ReadInSmallChunks(IInputStream * stream, TString * contents) {
+ char buf[11];
+ size_t read = 0;
+
+ contents->clear();
+ do {
+ read = stream->Read(buf, sizeof(buf));
+ contents->append(buf, read);
+ } while (read > 0);
+ }
+
+ void ReadCombed(IInputStream * stream, TString * contents, size_t chunkSize) {
+ Y_ASSERT(chunkSize < 128);
+ char buf[128];
+
+ contents->clear();
+ while (true) {
+ size_t read = stream->Load(buf, chunkSize);
+ contents->append(buf, read);
+ if (read == 0)
+ break;
+
+ size_t toSkip = chunkSize;
+ size_t skipped = 0;
+ do {
+ skipped = stream->Skip(toSkip);
+ toSkip -= skipped;
+ } while (skipped != 0 && toSkip != 0);
+ }
+ }
+
+ Y_UNIT_TEST(TestChunkedIo) {
+ TTempFile tmpFile(CDATA);
+ TString tmp;
+
+ {
+ TUnbufferedFileOutput fo(CDATA);
+ TChunkedOutput co(&fo);
+ WriteTestData(&co, &tmp);
+ }
+
+ {
+ TUnbufferedFileInput fi(CDATA);
+ TChunkedInput ci(&fi);
+ TString r;
+
+ ReadInSmallChunks(&ci, &r);
+
+ UNIT_ASSERT_EQUAL(r, tmp);
+ }
+
+ {
+ TUnbufferedFileInput fi(CDATA);
+ TChunkedInput ci(&fi);
+ TString r;
+
+ ReadCombed(&ci, &r, 11);
+
+ UNIT_ASSERT_EQUAL(r, CombString(tmp, 11));
+ }
+ }
+
+ Y_UNIT_TEST(TestBadChunk) {
+ bool hasError = false;
+
+ try {
+ TString badChunk = "10\r\nqwerty";
+ TMemoryInput mi(badChunk.data(), badChunk.size());
+ TChunkedInput ci(&mi);
+ TransferData(&ci, &Cnull);
+ } catch (...) {
+ hasError = true;
+ }
+
+ UNIT_ASSERT(hasError);
+ }
+}
diff --git a/library/cpp/http/io/compression.cpp b/library/cpp/http/io/compression.cpp
new file mode 100644
index 0000000000..8fa1f62ae6
--- /dev/null
+++ b/library/cpp/http/io/compression.cpp
@@ -0,0 +1,66 @@
+#include "compression.h"
+
+#if defined(ENABLE_GPL)
+#include <library/cpp/streams/lz/lz.h>
+#endif
+
+#include <library/cpp/streams/brotli/brotli.h>
+#include <library/cpp/streams/lzma/lzma.h>
+#include <library/cpp/streams/bzip2/bzip2.h>
+
+#include <library/cpp/blockcodecs/stream.h>
+#include <library/cpp/blockcodecs/codecs.h>
+
+#include <util/stream/zlib.h>
+
+
+TCompressionCodecFactory::TCompressionCodecFactory() {
+ auto gzip = [](auto s) {
+ return MakeHolder<TZLibDecompress>(s);
+ };
+
+ Add("gzip", gzip, [](auto s) { return MakeHolder<TZLibCompress>(s, ZLib::GZip); });
+ Add("deflate", gzip, [](auto s) { return MakeHolder<TZLibCompress>(s, ZLib::ZLib); });
+ Add("br", [](auto s) { return MakeHolder<TBrotliDecompress>(s); }, [](auto s) { return MakeHolder<TBrotliCompress>(s, 4); });
+ Add("x-gzip", gzip, [](auto s) { return MakeHolder<TZLibCompress>(s, ZLib::GZip); });
+ Add("x-deflate", gzip, [](auto s) { return MakeHolder<TZLibCompress>(s, ZLib::ZLib); });
+
+#if defined(ENABLE_GPL)
+ const ui16 bs = 32 * 1024;
+
+ Add("y-lzo", [](auto s) { return MakeHolder<TLzoDecompress>(s); }, [bs](auto s) { return MakeHolder<TLazy<TLzoCompress> >(s, bs); });
+ Add("y-lzf", [](auto s) { return MakeHolder<TLzfDecompress>(s); }, [bs](auto s) { return MakeHolder<TLazy<TLzfCompress> >(s, bs); });
+ Add("y-lzq", [](auto s) { return MakeHolder<TLzqDecompress>(s); }, [bs](auto s) { return MakeHolder<TLazy<TLzqCompress> >(s, bs); });
+#endif
+
+ Add("y-bzip2", [](auto s) { return MakeHolder<TBZipDecompress>(s); }, [](auto s) { return MakeHolder<TBZipCompress>(s); });
+ Add("y-lzma", [](auto s) { return MakeHolder<TLzmaDecompress>(s); }, [](auto s) { return MakeHolder<TLzmaCompress>(s); });
+
+ for (auto codecName : NBlockCodecs::ListAllCodecs()) {
+ if (codecName.StartsWith("zstd06")) {
+ continue;
+ }
+
+ if (codecName.StartsWith("zstd08")) {
+ continue;
+ }
+
+ auto codec = NBlockCodecs::Codec(codecName);
+
+ auto enc = [codec](auto s) {
+ return MakeHolder<NBlockCodecs::TCodedOutput>(s, codec, 32 * 1024);
+ };
+
+ auto dec = [codec](auto s) {
+ return MakeHolder<NBlockCodecs::TDecodedInput>(s, codec);
+ };
+
+ Add(TString("z-") + codecName, dec, enc);
+ }
+}
+
+void TCompressionCodecFactory::Add(TStringBuf name, TDecoderConstructor d, TEncoderConstructor e) {
+ Strings_.emplace_back(name);
+ Codecs_[Strings_.back()] = TCodec{d, e};
+ BestCodecs_.emplace_back(Strings_.back());
+}
diff --git a/library/cpp/http/io/compression.h b/library/cpp/http/io/compression.h
new file mode 100644
index 0000000000..f16c4a18eb
--- /dev/null
+++ b/library/cpp/http/io/compression.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include "stream.h"
+
+#include <util/generic/deque.h>
+#include <util/generic/hash.h>
+
+class TCompressionCodecFactory {
+public:
+ using TDecoderConstructor = std::function<THolder<IInputStream>(IInputStream*)>;
+ using TEncoderConstructor = std::function<THolder<IOutputStream>(IOutputStream*)>;
+
+ TCompressionCodecFactory();
+
+ static inline TCompressionCodecFactory& Instance() noexcept {
+ return *SingletonWithPriority<TCompressionCodecFactory, 0>();
+ }
+
+ inline const TDecoderConstructor* FindDecoder(TStringBuf name) const {
+ if (auto codec = Codecs_.FindPtr(name)) {
+ return &codec->Decoder;
+ }
+
+ return nullptr;
+ }
+
+ inline const TEncoderConstructor* FindEncoder(TStringBuf name) const {
+ if (auto codec = Codecs_.FindPtr(name)) {
+ return &codec->Encoder;
+ }
+
+ return nullptr;
+ }
+
+ inline TArrayRef<const TStringBuf> GetBestCodecs() const {
+ return BestCodecs_;
+ }
+
+private:
+ void Add(TStringBuf name, TDecoderConstructor d, TEncoderConstructor e);
+
+ struct TCodec {
+ TDecoderConstructor Decoder;
+ TEncoderConstructor Encoder;
+ };
+
+ TDeque<TString> Strings_;
+ THashMap<TStringBuf, TCodec> Codecs_;
+ TVector<TStringBuf> BestCodecs_;
+};
+
+namespace NHttp {
+ template <typename F>
+ TString ChooseBestCompressionScheme(F accepted, TArrayRef<const TStringBuf> available) {
+ if (available.empty()) {
+ return "identity";
+ }
+
+ if (accepted("*")) {
+ return TString(available[0]);
+ }
+
+ for (const auto& coding : available) {
+ TString s(coding);
+ if (accepted(s)) {
+ return s;
+ }
+ }
+
+ return "identity";
+ }
+}
diff --git a/library/cpp/http/io/compression_ut.cpp b/library/cpp/http/io/compression_ut.cpp
new file mode 100644
index 0000000000..2f3d131f8c
--- /dev/null
+++ b/library/cpp/http/io/compression_ut.cpp
@@ -0,0 +1,60 @@
+#include "stream.h"
+#include "compression.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/testing/unittest/tests_data.h>
+
+#include <util/stream/zlib.h>
+#include <util/generic/hash_set.h>
+
+Y_UNIT_TEST_SUITE(THttpCompressionTest) {
+ static const TString DATA = "I'm a teapot";
+
+ Y_UNIT_TEST(TestGetBestCodecs) {
+ UNIT_ASSERT(TCompressionCodecFactory::Instance().GetBestCodecs().size() > 0);
+ }
+
+ Y_UNIT_TEST(TestEncoder) {
+ TStringStream buffer;
+
+ {
+ auto encoder = TCompressionCodecFactory::Instance().FindEncoder("gzip");
+ UNIT_ASSERT(encoder);
+
+ auto encodedStream = (*encoder)(&buffer);
+ encodedStream->Write(DATA);
+ }
+
+ TZLibDecompress decompressor(&buffer);
+ UNIT_ASSERT_EQUAL(decompressor.ReadAll(), DATA);
+ }
+
+ Y_UNIT_TEST(TestDecoder) {
+ TStringStream buffer;
+
+ {
+ TZLibCompress compressor(TZLibCompress::TParams(&buffer).SetType(ZLib::GZip));
+ compressor.Write(DATA);
+ }
+
+ auto decoder = TCompressionCodecFactory::Instance().FindDecoder("gzip");
+ UNIT_ASSERT(decoder);
+
+ auto decodedStream = (*decoder)(&buffer);
+ UNIT_ASSERT_EQUAL(decodedStream->ReadAll(), DATA);
+ }
+
+ Y_UNIT_TEST(TestChooseBestCompressionScheme) {
+ THashSet<TString> accepted;
+
+ auto checkAccepted = [&accepted](const TString& v) {
+ return accepted.contains(v);
+ };
+
+ UNIT_ASSERT_VALUES_EQUAL("identity", NHttp::ChooseBestCompressionScheme(checkAccepted, {"gzip", "deflate"}));
+ accepted.insert("deflate");
+ UNIT_ASSERT_VALUES_EQUAL("deflate", NHttp::ChooseBestCompressionScheme(checkAccepted, {"gzip", "deflate"}));
+ accepted.insert("*");
+ UNIT_ASSERT_VALUES_EQUAL("gzip", NHttp::ChooseBestCompressionScheme(checkAccepted, {"gzip", "deflate"}));
+ }
+} // THttpCompressionTest suite
diff --git a/library/cpp/http/io/fuzz/main.cpp b/library/cpp/http/io/fuzz/main.cpp
new file mode 100644
index 0000000000..8ded9c7e32
--- /dev/null
+++ b/library/cpp/http/io/fuzz/main.cpp
@@ -0,0 +1,15 @@
+#include <library/cpp/http/io/stream.h>
+
+#include <util/generic/vector.h>
+#include <util/stream/mem.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const ui8* data, size_t size) {
+ TMemoryInput mi(data, size);
+
+ try {
+ THttpInput(&mi).ReadAll();
+ } catch (...) {
+ }
+
+ return 0; // Non-zero return values are reserved for future use.
+}
diff --git a/library/cpp/http/io/fuzz/ya.make b/library/cpp/http/io/fuzz/ya.make
new file mode 100644
index 0000000000..8b3ccb1969
--- /dev/null
+++ b/library/cpp/http/io/fuzz/ya.make
@@ -0,0 +1,18 @@
+FUZZ()
+
+OWNER(
+ pg
+ g:util
+)
+
+PEERDIR(
+ library/cpp/http/io
+)
+
+SIZE(MEDIUM)
+
+SRCS(
+ main.cpp
+)
+
+END()
diff --git a/library/cpp/http/io/headers.cpp b/library/cpp/http/io/headers.cpp
new file mode 100644
index 0000000000..4ec27a29e8
--- /dev/null
+++ b/library/cpp/http/io/headers.cpp
@@ -0,0 +1,108 @@
+#include "headers.h"
+#include "stream.h"
+
+#include <util/generic/strbuf.h>
+#include <util/generic/yexception.h>
+#include <util/stream/output.h>
+#include <util/string/ascii.h>
+#include <util/string/cast.h>
+#include <util/string/strip.h>
+
+static inline TStringBuf Trim(const char* b, const char* e) noexcept {
+ return StripString(TStringBuf(b, e));
+}
+
+THttpInputHeader::THttpInputHeader(const TStringBuf header) {
+ size_t pos = header.find(':');
+
+ if (pos == TString::npos) {
+ ythrow THttpParseException() << "can not parse http header(" << TString{header}.Quote() << ")";
+ }
+
+ Name_ = TString(header.cbegin(), header.cbegin() + pos);
+ Value_ = ::ToString(Trim(header.cbegin() + pos + 1, header.cend()));
+}
+
+THttpInputHeader::THttpInputHeader(TString name, TString value)
+ : Name_(std::move(name))
+ , Value_(std::move(value))
+{
+}
+
+void THttpInputHeader::OutTo(IOutputStream* stream) const {
+ typedef IOutputStream::TPart TPart;
+
+ const TPart parts[] = {
+ TPart(Name_),
+ TPart(": ", 2),
+ TPart(Value_),
+ TPart::CrLf(),
+ };
+
+ stream->Write(parts, sizeof(parts) / sizeof(*parts));
+}
+
+THttpHeaders::THttpHeaders(IInputStream* stream) {
+ TString header;
+ TString line;
+
+ bool rdOk = stream->ReadLine(header);
+ while (rdOk && !header.empty()) {
+ rdOk = stream->ReadLine(line);
+
+ if (rdOk && ((line[0] == ' ') || (line[0] == '\t'))) {
+ header += line;
+ } else {
+ AddHeader(THttpInputHeader(header));
+ header = line;
+ }
+ }
+}
+
+bool THttpHeaders::HasHeader(const TStringBuf header) const {
+ return FindHeader(header);
+}
+
+const THttpInputHeader* THttpHeaders::FindHeader(const TStringBuf header) const {
+ for (const auto& hdr : Headers_) {
+ if (AsciiCompareIgnoreCase(hdr.Name(), header) == 0) {
+ return &hdr;
+ }
+ }
+ return nullptr;
+}
+
+void THttpHeaders::RemoveHeader(const TStringBuf header) {
+ for (auto h = Headers_.begin(); h != Headers_.end(); ++h) {
+ if (AsciiCompareIgnoreCase(h->Name(), header) == 0) {
+ Headers_.erase(h);
+ return;
+ }
+ }
+}
+
+void THttpHeaders::AddOrReplaceHeader(const THttpInputHeader& header) {
+ for (auto& hdr : Headers_) {
+ if (AsciiCompareIgnoreCase(hdr.Name(), header.Name()) == 0) {
+ hdr = header;
+ return;
+ }
+ }
+
+ AddHeader(header);
+}
+
+void THttpHeaders::AddHeader(THttpInputHeader header) {
+ Headers_.push_back(std::move(header));
+}
+
+void THttpHeaders::OutTo(IOutputStream* stream) const {
+ for (TConstIterator header = Begin(); header != End(); ++header) {
+ header->OutTo(stream);
+ }
+}
+
+template <>
+void Out<THttpHeaders>(IOutputStream& out, const THttpHeaders& h) {
+ h.OutTo(&out);
+}
diff --git a/library/cpp/http/io/headers.h b/library/cpp/http/io/headers.h
new file mode 100644
index 0000000000..a71793d1c6
--- /dev/null
+++ b/library/cpp/http/io/headers.h
@@ -0,0 +1,125 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/deque.h>
+#include <util/generic/vector.h>
+#include <util/string/cast.h>
+
+class IInputStream;
+class IOutputStream;
+
+/// @addtogroup Streams_HTTP
+/// @{
+/// Объект, содержащий информацию о HTTP-заголовке.
+class THttpInputHeader {
+public:
+ /// @param[in] header - строка вида 'параметр: значение'.
+ THttpInputHeader(TStringBuf header);
+ /// @param[in] name - имя параметра.
+ /// @param[in] value - значение параметра.
+ THttpInputHeader(TString name, TString value);
+
+ /// Возвращает имя параметра.
+ inline const TString& Name() const noexcept {
+ return Name_;
+ }
+
+ /// Возвращает значение параметра.
+ inline const TString& Value() const noexcept {
+ return Value_;
+ }
+
+ /// Записывает заголовок вида "имя параметра: значение\r\n" в поток.
+ void OutTo(IOutputStream* stream) const;
+
+ /// Возвращает строку "имя параметра: значение".
+ inline TString ToString() const {
+ return Name_ + TStringBuf(": ") + Value_;
+ }
+
+private:
+ TString Name_;
+ TString Value_;
+};
+
+/// Контейнер для хранения HTTP-заголовков
+class THttpHeaders {
+ using THeaders = TDeque<THttpInputHeader>;
+
+public:
+ using TConstIterator = THeaders::const_iterator;
+
+ THttpHeaders() = default;
+
+ /// Добавляет каждую строку из потока в контейнер, считая ее правильным заголовком.
+ THttpHeaders(IInputStream* stream);
+
+ /// Стандартный итератор.
+ inline TConstIterator Begin() const noexcept {
+ return Headers_.begin();
+ }
+ inline TConstIterator begin() const noexcept {
+ return Headers_.begin();
+ }
+
+ /// Стандартный итератор.
+ inline TConstIterator End() const noexcept {
+ return Headers_.end();
+ }
+ inline TConstIterator end() const noexcept {
+ return Headers_.end();
+ }
+
+ /// Возвращает количество заголовков в контейнере.
+ inline size_t Count() const noexcept {
+ return Headers_.size();
+ }
+
+ /// Проверяет, содержит ли контейнер хотя бы один заголовок.
+ inline bool Empty() const noexcept {
+ return Headers_.empty();
+ }
+
+ /// Добавляет заголовок в контейнер.
+ void AddHeader(THttpInputHeader header);
+
+ template <typename ValueType>
+ void AddHeader(TString name, const ValueType& value) {
+ AddHeader(THttpInputHeader(std::move(name), ToString(value)));
+ }
+
+ /// Добавляет заголовок в контейнер, если тот не содержит заголовка
+ /// c таким же параметром. В противном случае, заменяет существующий
+ /// заголовок на новый.
+ void AddOrReplaceHeader(const THttpInputHeader& header);
+
+ template <typename ValueType>
+ void AddOrReplaceHeader(TString name, const ValueType& value) {
+ AddOrReplaceHeader(THttpInputHeader(std::move(name), ToString(value)));
+ }
+
+ // Проверяет, есть ли такой заголовок
+ bool HasHeader(TStringBuf header) const;
+
+ /// Удаляет заголовок, если он есть.
+ void RemoveHeader(TStringBuf header);
+
+ /// Ищет заголовок по указанному имени
+ /// Возвращает nullptr, если не нашел
+ const THttpInputHeader* FindHeader(TStringBuf header) const;
+
+ /// Записывает все заголовки контейнера в поток.
+ /// @details Каждый заголовк записывается в виде "имя параметра: значение\r\n".
+ void OutTo(IOutputStream* stream) const;
+
+ /// Обменивает наборы заголовков двух контейнеров.
+ void Swap(THttpHeaders& headers) noexcept {
+ Headers_.swap(headers.Headers_);
+ }
+
+private:
+ THeaders Headers_;
+};
+
+/// @}
diff --git a/library/cpp/http/io/headers_ut.cpp b/library/cpp/http/io/headers_ut.cpp
new file mode 100644
index 0000000000..1d23ef8fdc
--- /dev/null
+++ b/library/cpp/http/io/headers_ut.cpp
@@ -0,0 +1,176 @@
+#include <util/generic/set.h>
+#include <util/generic/string.h>
+#include <util/generic/strbuf.h>
+#include <utility>
+
+#include <library/cpp/http/io/headers.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+namespace {
+ class THeadersExistence {
+ public:
+ THeadersExistence() = default;
+
+ THeadersExistence(const THttpHeaders& headers) {
+ for (THttpHeaders::TConstIterator it = headers.Begin();
+ it != headers.End();
+ ++it) {
+ Add(it->Name(), it->Value());
+ }
+ }
+
+ public:
+ void Add(TStringBuf name, TStringBuf value) {
+ Impl.emplace(TString(name), TString(value));
+ }
+
+ bool operator==(const THeadersExistence& rhs) const {
+ return Impl == rhs.Impl;
+ }
+
+ private:
+ typedef TMultiSet<std::pair<TString, TString>> TImpl;
+ TImpl Impl;
+ };
+}
+
+bool operator==(const THeadersExistence& lhs, const THttpHeaders& rhs) {
+ return lhs == THeadersExistence(rhs);
+}
+
+bool operator==(const THttpHeaders& lhs, const THeadersExistence& rhs) {
+ return THeadersExistence(lhs) == rhs;
+}
+
+class THttpHeadersTest: public TTestBase {
+ UNIT_TEST_SUITE(THttpHeadersTest);
+ UNIT_TEST(TestAddOperation1Arg);
+ UNIT_TEST(TestAddOperation2Args);
+ UNIT_TEST(TestAddOrReplaceOperation1Arg);
+ UNIT_TEST(TestAddOrReplaceOperation2Args);
+ UNIT_TEST(TestAddHeaderTemplateness);
+ UNIT_TEST(TestFindHeader);
+ UNIT_TEST_SUITE_END();
+
+private:
+ typedef void (*TAddHeaderFunction)(THttpHeaders&, TStringBuf name, TStringBuf value);
+ typedef void (*TAddOrReplaceHeaderFunction)(THttpHeaders&, TStringBuf name, TStringBuf value);
+
+public:
+ void TestAddOperation1Arg();
+ void TestAddOperation2Args();
+ void TestAddOrReplaceOperation1Arg();
+ void TestAddOrReplaceOperation2Args();
+ void TestAddHeaderTemplateness();
+ void TestFindHeader();
+
+private:
+ static void AddHeaderImpl1Arg(THttpHeaders& headers, TStringBuf name, TStringBuf value) {
+ headers.AddHeader(THttpInputHeader(TString(name), TString(value)));
+ }
+
+ static void AddHeaderImpl2Args(THttpHeaders& headers, TStringBuf name, TStringBuf value) {
+ headers.AddHeader(TString(name), TString(value));
+ }
+
+ static void AddOrReplaceHeaderImpl1Arg(THttpHeaders& headers, TStringBuf name, TStringBuf value) {
+ headers.AddOrReplaceHeader(THttpInputHeader(TString(name), TString(value)));
+ }
+
+ static void AddOrReplaceHeaderImpl2Args(THttpHeaders& headers, TStringBuf name, TStringBuf value) {
+ headers.AddOrReplaceHeader(TString(name), TString(value));
+ }
+
+ void DoTestAddOperation(TAddHeaderFunction);
+ void DoTestAddOrReplaceOperation(TAddHeaderFunction, TAddOrReplaceHeaderFunction);
+};
+
+UNIT_TEST_SUITE_REGISTRATION(THttpHeadersTest);
+
+void THttpHeadersTest::TestAddOperation1Arg() {
+ DoTestAddOperation(AddHeaderImpl1Arg);
+}
+void THttpHeadersTest::TestAddOperation2Args() {
+ DoTestAddOperation(AddHeaderImpl2Args);
+}
+
+void THttpHeadersTest::TestAddOrReplaceOperation1Arg() {
+ DoTestAddOrReplaceOperation(AddHeaderImpl1Arg, AddOrReplaceHeaderImpl1Arg);
+}
+void THttpHeadersTest::TestAddOrReplaceOperation2Args() {
+ DoTestAddOrReplaceOperation(AddHeaderImpl2Args, AddOrReplaceHeaderImpl2Args);
+}
+
+void THttpHeadersTest::DoTestAddOperation(TAddHeaderFunction addHeader) {
+ THttpHeaders h1;
+
+ addHeader(h1, "h1", "v1");
+ addHeader(h1, "h2", "v1");
+
+ addHeader(h1, "h3", "v1");
+ addHeader(h1, "h3", "v2");
+ addHeader(h1, "h3", "v2");
+
+ THeadersExistence h2;
+
+ h2.Add("h1", "v1");
+ h2.Add("h2", "v1");
+
+ h2.Add("h3", "v1");
+ h2.Add("h3", "v2");
+ h2.Add("h3", "v2");
+
+ UNIT_ASSERT(h2 == h1);
+}
+
+// Sorry, but AddOrReplaceHeader replaces only first occurence
+void THttpHeadersTest::DoTestAddOrReplaceOperation(TAddHeaderFunction addHeader, TAddOrReplaceHeaderFunction addOrReplaceHeader) {
+ THttpHeaders h1;
+
+ addHeader(h1, "h1", "v1");
+
+ addOrReplaceHeader(h1, "h2", "v1");
+ addOrReplaceHeader(h1, "h2", "v2");
+ addOrReplaceHeader(h1, "h2", "v3");
+ addHeader(h1, "h2", "v4");
+
+ addHeader(h1, "h3", "v1");
+ addHeader(h1, "h3", "v2");
+ addOrReplaceHeader(h1, "h3", "v3");
+
+ THeadersExistence h2;
+
+ h2.Add("h1", "v1");
+
+ h2.Add("h2", "v3");
+ h2.Add("h2", "v4");
+
+ h2.Add("h3", "v2");
+ h2.Add("h3", "v3");
+
+ UNIT_ASSERT(h2 == h1);
+}
+
+void THttpHeadersTest::TestAddHeaderTemplateness() {
+ THttpHeaders h1;
+ h1.AddHeader("h1", "v1");
+ h1.AddHeader("h2", TString("v2"));
+ h1.AddHeader("h3", TStringBuf("v3"));
+ h1.AddHeader("h4", TStringBuf("v4"));
+
+ THeadersExistence h2;
+ h2.Add("h1", "v1");
+ h2.Add("h2", "v2");
+ h2.Add("h3", "v3");
+ h2.Add("h4", "v4");
+
+ UNIT_ASSERT(h1 == h2);
+}
+
+void THttpHeadersTest::TestFindHeader() {
+ THttpHeaders sut;
+ sut.AddHeader("NaMe", "Value");
+
+ UNIT_ASSERT(sut.FindHeader("name"));
+ UNIT_ASSERT(sut.FindHeader("name")->Value() == "Value");
+}
diff --git a/library/cpp/http/io/list_codings/main.cpp b/library/cpp/http/io/list_codings/main.cpp
new file mode 100644
index 0000000000..9818d02bdf
--- /dev/null
+++ b/library/cpp/http/io/list_codings/main.cpp
@@ -0,0 +1,8 @@
+#include <library/cpp/http/io/stream.h>
+#include <util/stream/output.h>
+
+int main() {
+ for (auto codec : SupportedCodings()) {
+ Cout << codec << Endl;
+ }
+}
diff --git a/library/cpp/http/io/list_codings/ya.make b/library/cpp/http/io/list_codings/ya.make
new file mode 100644
index 0000000000..e5c5fed6dc
--- /dev/null
+++ b/library/cpp/http/io/list_codings/ya.make
@@ -0,0 +1,13 @@
+PROGRAM()
+
+OWNER(pg)
+
+PEERDIR(
+ library/cpp/http/io
+)
+
+SRCS(
+ main.cpp
+)
+
+END()
diff --git a/library/cpp/http/io/stream.cpp b/library/cpp/http/io/stream.cpp
new file mode 100644
index 0000000000..6689be684f
--- /dev/null
+++ b/library/cpp/http/io/stream.cpp
@@ -0,0 +1,1005 @@
+#include "stream.h"
+
+#include "compression.h"
+#include "chunk.h"
+
+#include <util/stream/buffered.h>
+#include <util/stream/length.h>
+#include <util/stream/multi.h>
+#include <util/stream/null.h>
+#include <util/stream/tee.h>
+
+#include <util/system/compat.h>
+#include <util/system/yassert.h>
+
+#include <util/network/socket.h>
+
+#include <util/string/cast.h>
+#include <util/string/strip.h>
+
+#include <util/generic/string.h>
+#include <util/generic/utility.h>
+#include <util/generic/hash_set.h>
+#include <util/generic/yexception.h>
+
+#define HEADERCMP(header, str) \
+ case sizeof(str) - 1: \
+ if (!stricmp((header).Name().data(), str))
+
+namespace {
+ inline size_t SuggestBufferSize() {
+ return 8192;
+ }
+
+ inline TStringBuf Trim(const char* b, const char* e) noexcept {
+ return StripString(TStringBuf(b, e));
+ }
+
+ inline TStringBuf RmSemiColon(const TStringBuf& s) {
+ return s.Before(';');
+ }
+
+ template <class T, size_t N>
+ class TStreams: private TNonCopyable {
+ struct TDelete {
+ inline void operator()(T* t) noexcept {
+ delete t;
+ }
+ };
+
+ typedef T* TPtr;
+
+ public:
+ inline TStreams() noexcept
+ : Beg_(T_ + N)
+ {
+ }
+
+ inline ~TStreams() {
+ TDelete f;
+
+ ForEach(f);
+ }
+
+ template <class S>
+ inline S* Add(S* t) noexcept {
+ return (S*)AddImpl((T*)t);
+ }
+
+ template <class Functor>
+ inline void ForEach(Functor& f) {
+ const TPtr* end = T_ + N;
+
+ for (TPtr* cur = Beg_; cur != end; ++cur) {
+ f(*cur);
+ }
+ }
+
+ TPtr Top() {
+ const TPtr* end = T_ + N;
+ return end == Beg_ ? nullptr : *Beg_;
+ }
+
+ private:
+ inline T* AddImpl(T* t) noexcept {
+ Y_ASSERT(Beg_ > T_);
+
+ return (*--Beg_ = t);
+ }
+
+ private:
+ TPtr T_[N];
+ TPtr* Beg_;
+ };
+
+ template <class TStream>
+ class TLazy: public IOutputStream {
+ public:
+ TLazy(IOutputStream* out, ui16 bs)
+ : Output_(out)
+ , BlockSize_(bs)
+ {
+ }
+
+ void DoWrite(const void* buf, size_t len) override {
+ ConstructSlave();
+ Slave_->Write(buf, len);
+ }
+
+ void DoFlush() override {
+ ConstructSlave();
+ Slave_->Flush();
+ }
+
+ void DoFinish() override {
+ ConstructSlave();
+ Slave_->Finish();
+ }
+
+ private:
+ inline void ConstructSlave() {
+ if (!Slave_) {
+ Slave_.Reset(new TStream(Output_, BlockSize_));
+ }
+ }
+
+ private:
+ IOutputStream* Output_;
+ ui16 BlockSize_;
+ THolder<IOutputStream> Slave_;
+ };
+}
+
+class THttpInput::TImpl {
+ typedef THashSet<TString> TAcceptCodings;
+
+public:
+ inline TImpl(IInputStream* slave)
+ : Slave_(slave)
+ , Buffered_(Slave_, SuggestBufferSize())
+ , ChunkedInput_(nullptr)
+ , Input_(nullptr)
+ , FirstLine_(ReadFirstLine(Buffered_))
+ , Headers_(&Buffered_)
+ , KeepAlive_(false)
+ , HasContentLength_(false)
+ , ContentLength_(0)
+ , ContentEncoded_(false)
+ , Expect100Continue_(false)
+ {
+ BuildInputChain();
+ Y_ASSERT(Input_);
+ }
+
+ static TString ReadFirstLine(TBufferedInput& in) {
+ TString s;
+ Y_ENSURE_EX(in.ReadLine(s), THttpReadException() << "Failed to get first line");
+ return s;
+ }
+
+ inline ~TImpl() {
+ }
+
+ inline size_t Read(void* buf, size_t len) {
+ return Perform(len, [this, buf](size_t toRead) { return Input_->Read(buf, toRead); });
+ }
+
+ inline size_t Skip(size_t len) {
+ return Perform(len, [this](size_t toSkip) { return Input_->Skip(toSkip); });
+ }
+
+ inline const TString& FirstLine() const noexcept {
+ return FirstLine_;
+ }
+
+ inline const THttpHeaders& Headers() const noexcept {
+ return Headers_;
+ }
+
+ inline const TMaybe<THttpHeaders>& Trailers() const noexcept {
+ return Trailers_;
+ }
+
+ inline bool IsKeepAlive() const noexcept {
+ return KeepAlive_;
+ }
+
+ inline bool AcceptEncoding(const TString& s) const {
+ return Codings_.find(to_lower(s)) != Codings_.end();
+ }
+
+ inline bool GetContentLength(ui64& value) const noexcept {
+ if (HasContentLength_) {
+ value = ContentLength_;
+ return true;
+ }
+ return false;
+ }
+
+ inline bool ContentEncoded() const noexcept {
+ return ContentEncoded_;
+ }
+
+ inline bool HasContent() const noexcept {
+ return HasContentLength_ || ChunkedInput_;
+ }
+
+ inline bool HasExpect100Continue() const noexcept {
+ return Expect100Continue_;
+ }
+
+private:
+ template <class Operation>
+ inline size_t Perform(size_t len, const Operation& operation) {
+ size_t processed = operation(len);
+ if (processed == 0 && len > 0) {
+ if (!ChunkedInput_) {
+ Trailers_.ConstructInPlace();
+ } else {
+ // Read the header of the trailing chunk. It remains in
+ // the TChunkedInput stream if the HTTP response is compressed.
+ char symbol;
+ if (ChunkedInput_->Read(&symbol, 1) != 0) {
+ ythrow THttpParseException() << "some data remaining in TChunkedInput";
+ }
+ }
+ }
+ return processed;
+ }
+
+ struct TParsedHeaders {
+ bool Chunked = false;
+ bool KeepAlive = false;
+ TStringBuf LZipped;
+ };
+
+ struct TTrEnc {
+ inline void operator()(const TStringBuf& s) {
+ if (s == TStringBuf("chunked")) {
+ p->Chunked = true;
+ }
+ }
+
+ TParsedHeaders* p;
+ };
+
+ struct TAccCoding {
+ inline void operator()(const TStringBuf& s) {
+ c->insert(ToString(s));
+ }
+
+ TAcceptCodings* c;
+ };
+
+ template <class Functor>
+ inline void ForEach(TString in, Functor& f) {
+ in.to_lower();
+
+ const char* b = in.begin();
+ const char* c = b;
+ const char* e = in.end();
+
+ while (c != e) {
+ if (*c == ',') {
+ f(RmSemiColon(Trim(b, c)));
+ b = c + 1;
+ }
+
+ ++c;
+ }
+
+ if (b != c) {
+ f(RmSemiColon(Trim(b, c)));
+ }
+ }
+
+ inline bool IsRequest() const {
+ return strnicmp(FirstLine().data(), "get", 3) == 0 ||
+ strnicmp(FirstLine().data(), "post", 4) == 0 ||
+ strnicmp(FirstLine().data(), "put", 3) == 0 ||
+ strnicmp(FirstLine().data(), "patch", 5) == 0 ||
+ strnicmp(FirstLine().data(), "head", 4) == 0 ||
+ strnicmp(FirstLine().data(), "delete", 6) == 0;
+ }
+
+ inline void BuildInputChain() {
+ TParsedHeaders p;
+
+ size_t pos = FirstLine_.rfind(' ');
+ // In HTTP/1.1 Keep-Alive is turned on by default
+ if (pos != TString::npos && strcmp(FirstLine_.c_str() + pos + 1, "HTTP/1.1") == 0) {
+ p.KeepAlive = true; //request
+ } else if (strnicmp(FirstLine_.data(), "HTTP/1.1", 8) == 0) {
+ p.KeepAlive = true; //reply
+ }
+
+ for (THttpHeaders::TConstIterator h = Headers_.Begin(); h != Headers_.End(); ++h) {
+ const THttpInputHeader& header = *h;
+ switch (header.Name().size()) {
+ HEADERCMP(header, "transfer-encoding") {
+ TTrEnc f = {&p};
+ ForEach(header.Value(), f);
+ }
+ break;
+ HEADERCMP(header, "content-encoding") {
+ p.LZipped = header.Value();
+ }
+ break;
+ HEADERCMP(header, "accept-encoding") {
+ TAccCoding f = {&Codings_};
+ ForEach(header.Value(), f);
+ }
+ break;
+ HEADERCMP(header, "content-length") {
+ HasContentLength_ = true;
+ ContentLength_ = FromString(header.Value());
+ }
+ break;
+ HEADERCMP(header, "connection") {
+ // accept header "Connection: Keep-Alive, TE"
+ if (strnicmp(header.Value().data(), "keep-alive", 10) == 0) {
+ p.KeepAlive = true;
+ } else if (stricmp(header.Value().data(), "close") == 0) {
+ p.KeepAlive = false;
+ }
+ }
+ [[fallthrough]];
+ HEADERCMP(header, "expect") {
+ auto findContinue = [&](const TStringBuf& s) {
+ if (strnicmp(s.data(), "100-continue", 13) == 0) {
+ Expect100Continue_ = true;
+ }
+ };
+ ForEach(header.Value(), findContinue);
+ }
+ break;
+ }
+ }
+
+ if (p.Chunked) {
+ ChunkedInput_ = Streams_.Add(new TChunkedInput(&Buffered_, &Trailers_));
+ Input_ = ChunkedInput_;
+ } else {
+ // disable buffering
+ Buffered_.Reset(&Cnull);
+ Input_ = Streams_.Add(new TMultiInput(&Buffered_, Slave_));
+
+ if (IsRequest() || HasContentLength_) {
+ /*
+ * TODO - we have other cases
+ */
+ Input_ = Streams_.Add(new TLengthLimitedInput(Input_, ContentLength_));
+ }
+ }
+
+ if (auto decoder = TCompressionCodecFactory::Instance().FindDecoder(p.LZipped)) {
+ ContentEncoded_ = true;
+ Input_ = Streams_.Add((*decoder)(Input_).Release());
+ }
+
+ KeepAlive_ = p.KeepAlive;
+ }
+
+private:
+ IInputStream* Slave_;
+
+ /*
+ * input helpers
+ */
+ TBufferedInput Buffered_;
+ TStreams<IInputStream, 8> Streams_;
+ IInputStream* ChunkedInput_;
+
+ /*
+ * final input stream
+ */
+ IInputStream* Input_;
+
+ TString FirstLine_;
+ THttpHeaders Headers_;
+ TMaybe<THttpHeaders> Trailers_;
+ bool KeepAlive_;
+
+ TAcceptCodings Codings_;
+
+ bool HasContentLength_;
+ ui64 ContentLength_;
+
+ bool ContentEncoded_;
+ bool Expect100Continue_;
+};
+
+THttpInput::THttpInput(IInputStream* slave)
+ : Impl_(new TImpl(slave))
+{
+}
+
+THttpInput::THttpInput(THttpInput&& httpInput) = default;
+
+THttpInput::~THttpInput() {
+}
+
+size_t THttpInput::DoRead(void* buf, size_t len) {
+ return Impl_->Read(buf, len);
+}
+
+size_t THttpInput::DoSkip(size_t len) {
+ return Impl_->Skip(len);
+}
+
+const THttpHeaders& THttpInput::Headers() const noexcept {
+ return Impl_->Headers();
+}
+
+const TMaybe<THttpHeaders>& THttpInput::Trailers() const noexcept {
+ return Impl_->Trailers();
+}
+
+const TString& THttpInput::FirstLine() const noexcept {
+ return Impl_->FirstLine();
+}
+
+bool THttpInput::IsKeepAlive() const noexcept {
+ return Impl_->IsKeepAlive();
+}
+
+bool THttpInput::AcceptEncoding(const TString& coding) const {
+ return Impl_->AcceptEncoding(coding);
+}
+
+TString THttpInput::BestCompressionScheme(TArrayRef<const TStringBuf> codings) const {
+ return NHttp::ChooseBestCompressionScheme(
+ [this](const TString& coding) {
+ return AcceptEncoding(coding);
+ },
+ codings
+ );
+}
+
+TString THttpInput::BestCompressionScheme() const {
+ return BestCompressionScheme(TCompressionCodecFactory::Instance().GetBestCodecs());
+}
+
+bool THttpInput::GetContentLength(ui64& value) const noexcept {
+ return Impl_->GetContentLength(value);
+}
+
+bool THttpInput::ContentEncoded() const noexcept {
+ return Impl_->ContentEncoded();
+}
+
+bool THttpInput::HasContent() const noexcept {
+ return Impl_->HasContent();
+}
+
+bool THttpInput::HasExpect100Continue() const noexcept {
+ return Impl_->HasExpect100Continue();
+}
+
+class THttpOutput::TImpl {
+ class TSizeCalculator: public IOutputStream {
+ public:
+ inline TSizeCalculator() noexcept {
+ }
+
+ ~TSizeCalculator() override {
+ }
+
+ void DoWrite(const void* /*buf*/, size_t len) override {
+ Length_ += len;
+ }
+
+ inline size_t Length() const noexcept {
+ return Length_;
+ }
+
+ private:
+ size_t Length_ = 0;
+ };
+
+ enum TState {
+ Begin = 0,
+ FirstLineSent = 1,
+ HeadersSent = 2
+ };
+
+ struct TFlush {
+ inline void operator()(IOutputStream* s) {
+ s->Flush();
+ }
+ };
+
+ struct TFinish {
+ inline void operator()(IOutputStream* s) {
+ s->Finish();
+ }
+ };
+
+public:
+ inline TImpl(IOutputStream* slave, THttpInput* request)
+ : Slave_(slave)
+ , State_(Begin)
+ , Output_(Slave_)
+ , Request_(request)
+ , Version_(1100)
+ , KeepAliveEnabled_(false)
+ , BodyEncodingEnabled_(true)
+ , CompressionHeaderEnabled_(true)
+ , Finished_(false)
+ {
+ }
+
+ inline ~TImpl() {
+ }
+
+ inline void SendContinue() {
+ Output_->Write("HTTP/1.1 100 Continue\r\n\r\n");
+ Output_->Flush();
+ }
+
+ inline void Write(const void* buf, size_t len) {
+ if (Finished_) {
+ ythrow THttpException() << "can not write to finished stream";
+ }
+
+ if (State_ == HeadersSent) {
+ Output_->Write(buf, len);
+
+ return;
+ }
+
+ const char* b = (const char*)buf;
+ const char* e = b + len;
+ const char* c = b;
+
+ while (c != e) {
+ if (*c == '\n') {
+ Line_.append(b, c);
+
+ if (!Line_.empty() && Line_.back() == '\r') {
+ Line_.pop_back();
+ }
+
+ b = c + 1;
+
+ Process(Line_);
+
+ if (State_ == HeadersSent) {
+ Output_->Write(b, e - b);
+
+ return;
+ }
+
+ Line_.clear();
+ }
+
+ ++c;
+ }
+
+ if (b != c) {
+ Line_.append(b, c);
+ }
+ }
+
+ inline void Flush() {
+ TFlush f;
+ Streams_.ForEach(f);
+ Slave_->Flush(); // see SEARCH-1030
+ }
+
+ inline void Finish() {
+ if (Finished_) {
+ return;
+ }
+
+ TFinish f;
+ Streams_.ForEach(f);
+ Slave_->Finish(); // see SEARCH-1030
+
+ Finished_ = true;
+ }
+
+ inline const THttpHeaders& SentHeaders() const noexcept {
+ return Headers_;
+ }
+
+ inline void EnableCompression(TArrayRef<const TStringBuf> schemas) {
+ ComprSchemas_ = schemas;
+ }
+
+ inline void EnableKeepAlive(bool enable) {
+ KeepAliveEnabled_ = enable;
+ }
+
+ inline void EnableBodyEncoding(bool enable) {
+ BodyEncodingEnabled_ = enable;
+ }
+
+ inline void EnableCompressionHeader(bool enable) {
+ CompressionHeaderEnabled_ = enable;
+ }
+
+ inline bool IsCompressionEnabled() const noexcept {
+ return !ComprSchemas_.empty();
+ }
+
+ inline bool IsKeepAliveEnabled() const noexcept {
+ return KeepAliveEnabled_;
+ }
+
+ inline bool IsBodyEncodingEnabled() const noexcept {
+ return BodyEncodingEnabled_;
+ }
+
+ inline bool IsCompressionHeaderEnabled() const noexcept {
+ return CompressionHeaderEnabled_;
+ }
+
+ inline bool CanBeKeepAlive() const noexcept {
+ return SupportChunkedTransfer() && IsKeepAliveEnabled() && (Request_ ? Request_->IsKeepAlive() : true);
+ }
+
+ inline const TString& FirstLine() const noexcept {
+ return FirstLine_;
+ }
+
+ inline size_t SentSize() const noexcept {
+ return SizeCalculator_.Length();
+ }
+
+private:
+ static inline bool IsResponse(const TString& s) noexcept {
+ return strnicmp(s.data(), "HTTP/", 5) == 0;
+ }
+
+ static inline bool IsRequest(const TString& s) noexcept {
+ return !IsResponse(s);
+ }
+
+ inline bool IsHttpRequest() const noexcept {
+ return IsRequest(FirstLine_);
+ }
+
+ inline bool HasResponseBody() const noexcept {
+ if (IsHttpResponse()) {
+ if (Request_ && Request_->FirstLine().StartsWith(TStringBuf("HEAD")))
+ return false;
+ if (FirstLine_.size() > 9 && strncmp(FirstLine_.data() + 9, "204", 3) == 0)
+ return false;
+ return true;
+ }
+ return false;
+ }
+
+ inline bool IsHttpResponse() const noexcept {
+ return IsResponse(FirstLine_);
+ }
+
+ inline bool HasRequestBody() const noexcept {
+ return strnicmp(FirstLine_.data(), "POST", 4) == 0 ||
+ strnicmp(FirstLine_.data(), "PATCH", 5) == 0 ||
+ strnicmp(FirstLine_.data(), "PUT", 3) == 0;
+ }
+ static inline size_t ParseHttpVersion(const TString& s) {
+ if (s.empty()) {
+ ythrow THttpParseException() << "malformed http stream";
+ }
+
+ size_t parsed_version = 0;
+
+ if (IsResponse(s)) {
+ const char* b = s.data() + 5;
+
+ while (*b && *b != ' ') {
+ if (*b != '.') {
+ parsed_version *= 10;
+ parsed_version += (*b - '0');
+ }
+
+ ++b;
+ }
+ } else {
+ /*
+ * s not empty here
+ */
+ const char* e = s.end() - 1;
+ const char* b = s.begin();
+ size_t mult = 1;
+
+ while (e != b && *e != '/') {
+ if (*e != '.') {
+ parsed_version += (*e - '0') * mult;
+ mult *= 10;
+ }
+
+ --e;
+ }
+ }
+
+ return parsed_version * 100;
+ }
+
+ inline void ParseHttpVersion() {
+ size_t parsed_version = ParseHttpVersion(FirstLine_);
+
+ if (Request_) {
+ parsed_version = Min(parsed_version, ParseHttpVersion(Request_->FirstLine()));
+ }
+
+ Version_ = parsed_version;
+ }
+
+ inline void Process(const TString& s) {
+ Y_ASSERT(State_ != HeadersSent);
+
+ if (State_ == Begin) {
+ FirstLine_ = s;
+ ParseHttpVersion();
+ State_ = FirstLineSent;
+ } else {
+ if (s.empty()) {
+ BuildOutputStream();
+ WriteCached();
+ State_ = HeadersSent;
+ } else {
+ AddHeader(THttpInputHeader(s));
+ }
+ }
+ }
+
+ inline void WriteCachedImpl(IOutputStream* s) const {
+ s->Write(FirstLine_.data(), FirstLine_.size());
+ s->Write("\r\n", 2);
+ Headers_.OutTo(s);
+ s->Write("\r\n", 2);
+ s->Finish();
+ }
+
+ inline void WriteCached() {
+ size_t buflen = 0;
+
+ {
+ TSizeCalculator out;
+
+ WriteCachedImpl(&out);
+ buflen = out.Length();
+ }
+
+ {
+ TBufferedOutput out(Slave_, buflen);
+
+ WriteCachedImpl(&out);
+ }
+
+ if (IsHttpRequest() && !HasRequestBody()) {
+ /*
+ * if this is http request, then send it now
+ */
+
+ Slave_->Flush();
+ }
+ }
+
+ inline bool SupportChunkedTransfer() const noexcept {
+ return Version_ >= 1100;
+ }
+
+ inline void BuildOutputStream() {
+ if (CanBeKeepAlive()) {
+ AddOrReplaceHeader(THttpInputHeader("Connection", "Keep-Alive"));
+ } else {
+ AddOrReplaceHeader(THttpInputHeader("Connection", "Close"));
+ }
+
+ if (IsHttpResponse()) {
+ if (Request_ && IsCompressionEnabled() && HasResponseBody()) {
+ TString scheme = Request_->BestCompressionScheme(ComprSchemas_);
+ if (scheme != "identity") {
+ AddOrReplaceHeader(THttpInputHeader("Content-Encoding", scheme));
+ RemoveHeader("Content-Length");
+ }
+ }
+
+ RebuildStream();
+ } else {
+ if (IsCompressionEnabled()) {
+ AddOrReplaceHeader(THttpInputHeader("Accept-Encoding", BuildAcceptEncoding()));
+ }
+ if (HasRequestBody()) {
+ RebuildStream();
+ }
+ }
+ }
+
+ inline TString BuildAcceptEncoding() const {
+ TString ret;
+
+ for (const auto& coding : ComprSchemas_) {
+ if (ret) {
+ ret += ", ";
+ }
+
+ ret += coding;
+ }
+
+ return ret;
+ }
+
+ inline void RebuildStream() {
+ bool keepAlive = false;
+ const TCompressionCodecFactory::TEncoderConstructor* encoder = nullptr;
+ bool chunked = false;
+ bool haveContentLength = false;
+
+ for (THttpHeaders::TConstIterator h = Headers_.Begin(); h != Headers_.End(); ++h) {
+ const THttpInputHeader& header = *h;
+ const TString hl = to_lower(header.Name());
+
+ if (hl == TStringBuf("connection")) {
+ keepAlive = to_lower(header.Value()) == TStringBuf("keep-alive");
+ } else if (IsCompressionHeaderEnabled() && hl == TStringBuf("content-encoding")) {
+ encoder = TCompressionCodecFactory::Instance().FindEncoder(to_lower(header.Value()));
+ } else if (hl == TStringBuf("transfer-encoding")) {
+ chunked = to_lower(header.Value()) == TStringBuf("chunked");
+ } else if (hl == TStringBuf("content-length")) {
+ haveContentLength = true;
+ }
+ }
+
+ if (!haveContentLength && !chunked && (IsHttpRequest() || HasResponseBody()) && SupportChunkedTransfer() && (keepAlive || encoder || IsHttpRequest())) {
+ AddHeader(THttpInputHeader("Transfer-Encoding", "chunked"));
+ chunked = true;
+ }
+
+ if (IsBodyEncodingEnabled() && chunked) {
+ Output_ = Streams_.Add(new TChunkedOutput(Output_));
+ }
+
+ Output_ = Streams_.Add(new TTeeOutput(Output_, &SizeCalculator_));
+
+ if (IsBodyEncodingEnabled() && encoder) {
+ Output_ = Streams_.Add((*encoder)(Output_).Release());
+ }
+ }
+
+ inline void AddHeader(const THttpInputHeader& hdr) {
+ Headers_.AddHeader(hdr);
+ }
+
+ inline void AddOrReplaceHeader(const THttpInputHeader& hdr) {
+ Headers_.AddOrReplaceHeader(hdr);
+ }
+
+ inline void RemoveHeader(const TString& hdr) {
+ Headers_.RemoveHeader(hdr);
+ }
+
+private:
+ IOutputStream* Slave_;
+ TState State_;
+ IOutputStream* Output_;
+ TStreams<IOutputStream, 8> Streams_;
+ TString Line_;
+ TString FirstLine_;
+ THttpHeaders Headers_;
+ THttpInput* Request_;
+ size_t Version_;
+
+ TArrayRef<const TStringBuf> ComprSchemas_;
+
+ bool KeepAliveEnabled_;
+ bool BodyEncodingEnabled_;
+ bool CompressionHeaderEnabled_;
+
+ bool Finished_;
+
+ TSizeCalculator SizeCalculator_;
+};
+
+THttpOutput::THttpOutput(IOutputStream* slave)
+ : Impl_(new TImpl(slave, nullptr))
+{
+}
+
+THttpOutput::THttpOutput(IOutputStream* slave, THttpInput* request)
+ : Impl_(new TImpl(slave, request))
+{
+}
+
+THttpOutput::~THttpOutput() {
+ try {
+ Finish();
+ } catch (...) {
+ }
+}
+
+void THttpOutput::DoWrite(const void* buf, size_t len) {
+ Impl_->Write(buf, len);
+}
+
+void THttpOutput::DoFlush() {
+ Impl_->Flush();
+}
+
+void THttpOutput::DoFinish() {
+ Impl_->Finish();
+}
+
+const THttpHeaders& THttpOutput::SentHeaders() const noexcept {
+ return Impl_->SentHeaders();
+}
+
+void THttpOutput::EnableCompression(bool enable) {
+ if (enable) {
+ EnableCompression(TCompressionCodecFactory::Instance().GetBestCodecs());
+ } else {
+ TArrayRef<TStringBuf> codings;
+ EnableCompression(codings);
+ }
+}
+
+void THttpOutput::EnableCompression(TArrayRef<const TStringBuf> schemas) {
+ Impl_->EnableCompression(schemas);
+}
+
+void THttpOutput::EnableKeepAlive(bool enable) {
+ Impl_->EnableKeepAlive(enable);
+}
+
+void THttpOutput::EnableBodyEncoding(bool enable) {
+ Impl_->EnableBodyEncoding(enable);
+}
+
+void THttpOutput::EnableCompressionHeader(bool enable) {
+ Impl_->EnableCompressionHeader(enable);
+}
+
+bool THttpOutput::IsKeepAliveEnabled() const noexcept {
+ return Impl_->IsKeepAliveEnabled();
+}
+
+bool THttpOutput::IsBodyEncodingEnabled() const noexcept {
+ return Impl_->IsBodyEncodingEnabled();
+}
+
+bool THttpOutput::IsCompressionEnabled() const noexcept {
+ return Impl_->IsCompressionEnabled();
+}
+
+bool THttpOutput::IsCompressionHeaderEnabled() const noexcept {
+ return Impl_->IsCompressionHeaderEnabled();
+}
+
+bool THttpOutput::CanBeKeepAlive() const noexcept {
+ return Impl_->CanBeKeepAlive();
+}
+
+void THttpOutput::SendContinue() {
+ Impl_->SendContinue();
+}
+
+const TString& THttpOutput::FirstLine() const noexcept {
+ return Impl_->FirstLine();
+}
+
+size_t THttpOutput::SentSize() const noexcept {
+ return Impl_->SentSize();
+}
+
+unsigned ParseHttpRetCode(const TStringBuf& ret) {
+ const TStringBuf code = StripString(StripString(ret.After(' ')).Before(' '));
+
+ return FromString<unsigned>(code.data(), code.size());
+}
+
+void SendMinimalHttpRequest(TSocket& s, const TStringBuf& host, const TStringBuf& request, const TStringBuf& agent, const TStringBuf& from) {
+ TSocketOutput so(s);
+ THttpOutput output(&so);
+
+ output.EnableKeepAlive(false);
+ output.EnableCompression(false);
+
+ const IOutputStream::TPart parts[] = {
+ IOutputStream::TPart(TStringBuf("GET ")),
+ IOutputStream::TPart(request),
+ IOutputStream::TPart(TStringBuf(" HTTP/1.1")),
+ IOutputStream::TPart::CrLf(),
+ IOutputStream::TPart(TStringBuf("Host: ")),
+ IOutputStream::TPart(host),
+ IOutputStream::TPart::CrLf(),
+ IOutputStream::TPart(TStringBuf("User-Agent: ")),
+ IOutputStream::TPart(agent),
+ IOutputStream::TPart::CrLf(),
+ IOutputStream::TPart(TStringBuf("From: ")),
+ IOutputStream::TPart(from),
+ IOutputStream::TPart::CrLf(),
+ IOutputStream::TPart::CrLf(),
+ };
+
+ output.Write(parts, sizeof(parts) / sizeof(*parts));
+ output.Finish();
+}
+
+TArrayRef<const TStringBuf> SupportedCodings() {
+ return TCompressionCodecFactory::Instance().GetBestCodecs();
+}
diff --git a/library/cpp/http/io/stream.h b/library/cpp/http/io/stream.h
new file mode 100644
index 0000000000..78ca4fc814
--- /dev/null
+++ b/library/cpp/http/io/stream.h
@@ -0,0 +1,178 @@
+#pragma once
+
+#include "headers.h"
+
+#include <util/stream/output.h>
+#include <util/generic/maybe.h>
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/yexception.h>
+#include <util/generic/array_ref.h>
+
+class TSocket;
+
+struct THttpException: public yexception {
+};
+
+struct THttpParseException: public THttpException {
+};
+
+struct THttpReadException: public THttpException {
+};
+
+/// Чтение ответа HTTP-сервера.
+class THttpInput: public IInputStream {
+public:
+ THttpInput(IInputStream* slave);
+ THttpInput(THttpInput&& httpInput);
+ ~THttpInput() override;
+
+ /*
+ * parsed http headers
+ */
+ /// Возвращает контейнер с заголовками ответа HTTP-сервера.
+ const THttpHeaders& Headers() const noexcept;
+
+ /*
+ * parsed http trailers
+ */
+ /// Возвращает контейнер (возможно пустой) с trailer'ами ответа HTTP-сервера.
+ /// Поток должен быть вычитан полностью прежде чем trailer'ы будут доступны.
+ /// Пока поток не вычитан до конца возвращается Nothing.
+ /// https://tools.ietf.org/html/rfc7230#section-4.1.2
+ const TMaybe<THttpHeaders>& Trailers() const noexcept;
+
+ /*
+ * first line - response or request
+ */
+ /// Возвращает первую строку ответа HTTP-сервера.
+ /// @details Первая строка HTTP-сервера - строка состояния,
+ /// содержащая три поля: версию HTTP, код состояния и описание.
+ const TString& FirstLine() const noexcept;
+
+ /*
+ * connection can be keep-alive
+ */
+ /// Проверяет, не завершено ли соединение с сервером.
+ /// @details Транзакция считается завершенной, если не передан заголовок
+ /// "Connection: Keep Alive".
+ bool IsKeepAlive() const noexcept;
+
+ /*
+ * output data can be encoded
+ */
+ /// Проверяет, поддерживается ли данный тип кодирования содержимого
+ /// ответа HTTP-сервера.
+ bool AcceptEncoding(const TString& coding) const;
+
+ /// Пытается определить наилучший тип кодирования ответа HTTP-сервера.
+ /// @details Если ответ сервера говорит о том, что поддерживаются
+ /// любые типы кодирования, выбирается gzip. В противном случае
+ /// из списка типов кодирования выбирается лучший из поддерживаемых сервером.
+ TString BestCompressionScheme() const;
+ TString BestCompressionScheme(TArrayRef<const TStringBuf> codings) const;
+
+ /// Если заголовки содержат Content-Length, возвращает true и
+ /// записывает значение из заголовка в value
+ bool GetContentLength(ui64& value) const noexcept;
+
+ /// Признак запакованности данных, - если выставлен, то Content-Length, при наличии в заголовках,
+ /// показывает объём запакованных данных, а из THttpInput мы будем вычитывать уже распакованные.
+ bool ContentEncoded() const noexcept;
+
+ /// Returns true if Content-Length or Transfer-Encoding header received
+ bool HasContent() const noexcept;
+
+ bool HasExpect100Continue() const noexcept;
+
+private:
+ size_t DoRead(void* buf, size_t len) override;
+ size_t DoSkip(size_t len) override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+/// Передача запроса HTTP-серверу.
+class THttpOutput: public IOutputStream {
+public:
+ THttpOutput(IOutputStream* slave);
+ THttpOutput(IOutputStream* slave, THttpInput* request);
+ ~THttpOutput() override;
+
+ /*
+ * sent http headers
+ */
+ /// Возвращает контейнер с заголовками запроса к HTTP-серверу.
+ const THttpHeaders& SentHeaders() const noexcept;
+
+ /// Устанавливает режим, при котором сервер выдает ответ в упакованном виде.
+ void EnableCompression(bool enable);
+ void EnableCompression(TArrayRef<const TStringBuf> schemas);
+
+ /// Устанавливает режим, при котором соединение с сервером не завершается
+ /// после окончания транзакции.
+ void EnableKeepAlive(bool enable);
+
+ /// Устанавливает режим, при котором тело HTTP-запроса/ответа преобразуется в соответствии
+ /// с заголовками Content-Encoding и Transfer-Encoding (включен по умолчанию)
+ void EnableBodyEncoding(bool enable);
+
+ /// Устанавливает режим, при котором тело HTTP-ответа сжимается кодеком
+ /// указанным в Content-Encoding (включен по умолчанию)
+ void EnableCompressionHeader(bool enable);
+
+ /// Проверяет, производится ли выдача ответов в упакованном виде.
+ bool IsCompressionEnabled() const noexcept;
+
+ /// Проверяет, не завершается ли соединение с сервером после окончания транзакции.
+ bool IsKeepAliveEnabled() const noexcept;
+
+ /// Проверяет, преобразуется ли тело HTTP-запроса/ответа в соответствии
+ /// с заголовками Content-Encoding и Transfer-Encoding
+ bool IsBodyEncodingEnabled() const noexcept;
+
+ /// Проверяет, сжимается ли тело HTTP-ответа кодеком
+ /// указанным в Content-Encoding
+ bool IsCompressionHeaderEnabled() const noexcept;
+
+ /*
+ * is this connection can be really keep-alive
+ */
+ /// Проверяет, можно ли установить режим, при котором соединение с сервером
+ /// не завершается после окончания транзакции.
+ bool CanBeKeepAlive() const noexcept;
+
+ void SendContinue();
+
+ /*
+ * first line - response or request
+ */
+ /// Возвращает первую строку HTTP-запроса/ответа
+ const TString& FirstLine() const noexcept;
+
+ /// Возвращает размер отправленных данных (без заголовков, с учётом сжатия, без
+ /// учёта chunked transfer encoding)
+ size_t SentSize() const noexcept;
+
+private:
+ void DoWrite(const void* buf, size_t len) override;
+ void DoFlush() override;
+ void DoFinish() override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+/// Возвращает код состояния из ответа сервера.
+unsigned ParseHttpRetCode(const TStringBuf& ret);
+
+/// Отправляет HTTP-серверу запрос с минимумом необходимых заголовков.
+void SendMinimalHttpRequest(TSocket& s, const TStringBuf& host, const TStringBuf& request, const TStringBuf& agent = "YandexSomething/1.0", const TStringBuf& from = "webadmin@yandex.ru");
+
+TArrayRef<const TStringBuf> SupportedCodings();
+
+/// @}
diff --git a/library/cpp/http/io/stream_ut.cpp b/library/cpp/http/io/stream_ut.cpp
new file mode 100644
index 0000000000..1ea35df675
--- /dev/null
+++ b/library/cpp/http/io/stream_ut.cpp
@@ -0,0 +1,732 @@
+#include "stream.h"
+#include "chunk.h"
+
+#include <library/cpp/http/server/http_ex.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/testing/unittest/tests_data.h>
+
+#include <util/string/printf.h>
+#include <util/network/socket.h>
+#include <util/stream/file.h>
+#include <util/stream/output.h>
+#include <util/stream/tee.h>
+#include <util/stream/zlib.h>
+#include <util/stream/null.h>
+
+Y_UNIT_TEST_SUITE(THttpStreamTest) {
+ class TTestHttpServer: public THttpServer::ICallBack {
+ class TRequest: public THttpClientRequestEx {
+ public:
+ inline TRequest(TTestHttpServer* parent)
+ : Parent_(parent)
+ {
+ }
+
+ bool Reply(void* /*tsr*/) override {
+ if (!ProcessHeaders()) {
+ return true;
+ }
+
+ // Check that function will not hang on
+ Input().ReadAll();
+
+ // "lo" is for "local"
+ if (RD.ServerName() == "yandex.lo") {
+ // do redirect
+ Output() << "HTTP/1.1 301 Moved permanently\r\n"
+ "Location: http://www.yandex.lo\r\n"
+ "\r\n";
+ } else if (RD.ServerName() == "www.yandex.lo") {
+ Output() << "HTTP/1.1 200 Ok\r\n"
+ "\r\n";
+ } else {
+ Output() << "HTTP/1.1 200 Ok\r\n\r\n";
+ if (Buf.Size()) {
+ Output().Write(Buf.AsCharPtr(), Buf.Size());
+ } else {
+ Output() << Parent_->Res_;
+ }
+ }
+ Output().Finish();
+
+ Parent_->LastRequestSentSize_ = Output().SentSize();
+
+ return true;
+ }
+
+ private:
+ TTestHttpServer* Parent_ = nullptr;
+ };
+
+ public:
+ inline TTestHttpServer(const TString& res)
+ : Res_(res)
+ {
+ }
+
+ TClientRequest* CreateClient() override {
+ return new TRequest(this);
+ }
+
+ size_t LastRequestSentSize() const {
+ return LastRequestSentSize_;
+ }
+
+ private:
+ TString Res_;
+ size_t LastRequestSentSize_ = 0;
+ };
+
+ Y_UNIT_TEST(TestCodings1) {
+ UNIT_ASSERT(SupportedCodings().size() > 0);
+ }
+
+ Y_UNIT_TEST(TestHttpInput) {
+ TString res = "I'm a teapot";
+ TPortManager pm;
+ const ui16 port = pm.GetPort();
+
+ TTestHttpServer serverImpl(res);
+ THttpServer server(&serverImpl, THttpServer::TOptions(port).EnableKeepAlive(true).EnableCompression(true));
+
+ UNIT_ASSERT(server.Start());
+
+ TNetworkAddress addr("localhost", port);
+ TSocket s(addr);
+
+ //TDebugOutput dbg;
+ TNullOutput dbg;
+
+ {
+ TSocketOutput so(s);
+ TTeeOutput out(&so, &dbg);
+ THttpOutput output(&out);
+
+ output.EnableKeepAlive(true);
+ output.EnableCompression(true);
+
+ TString r;
+ r += "GET / HTTP/1.1";
+ r += "\r\n";
+ r += "Host: yandex.lo";
+ r += "\r\n";
+ r += "\r\n";
+
+ output.Write(r.data(), r.size());
+ output.Finish();
+ }
+
+ {
+ TSocketInput si(s);
+ THttpInput input(&si);
+ unsigned httpCode = ParseHttpRetCode(input.FirstLine());
+ UNIT_ASSERT_VALUES_EQUAL(httpCode / 10, 30u);
+
+ TransferData(&input, &dbg);
+ }
+ server.Stop();
+ }
+
+ Y_UNIT_TEST(TestHttpInputDelete) {
+ TString res = "I'm a teapot";
+ TPortManager pm;
+ const ui16 port = pm.GetPort();
+
+ TTestHttpServer serverImpl(res);
+ THttpServer server(&serverImpl, THttpServer::TOptions(port).EnableKeepAlive(true).EnableCompression(true));
+
+ UNIT_ASSERT(server.Start());
+
+ TNetworkAddress addr("localhost", port);
+ TSocket s(addr);
+
+ //TDebugOutput dbg;
+ TNullOutput dbg;
+
+ {
+ TSocketOutput so(s);
+ TTeeOutput out(&so, &dbg);
+ THttpOutput output(&out);
+
+ output.EnableKeepAlive(true);
+ output.EnableCompression(true);
+
+ TString r;
+ r += "DELETE / HTTP/1.1";
+ r += "\r\n";
+ r += "Host: yandex.lo";
+ r += "\r\n";
+ r += "\r\n";
+
+ output.Write(r.data(), r.size());
+ output.Finish();
+ }
+
+ {
+ TSocketInput si(s);
+ THttpInput input(&si);
+ unsigned httpCode = ParseHttpRetCode(input.FirstLine());
+ UNIT_ASSERT_VALUES_EQUAL(httpCode / 10, 30u);
+
+ TransferData(&input, &dbg);
+ }
+ server.Stop();
+ }
+
+ Y_UNIT_TEST(TestParseHttpRetCode) {
+ UNIT_ASSERT_VALUES_EQUAL(ParseHttpRetCode("HTTP/1.1 301"), 301u);
+ }
+
+ Y_UNIT_TEST(TestKeepAlive) {
+ {
+ TString s = "GET / HTTP/1.0\r\n\r\n";
+ TStringInput si(s);
+ THttpInput in(&si);
+ UNIT_ASSERT(!in.IsKeepAlive());
+ }
+
+ {
+ TString s = "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n";
+ TStringInput si(s);
+ THttpInput in(&si);
+ UNIT_ASSERT(in.IsKeepAlive());
+ }
+
+ {
+ TString s = "GET / HTTP/1.1\r\n\r\n";
+ TStringInput si(s);
+ THttpInput in(&si);
+ UNIT_ASSERT(in.IsKeepAlive());
+ }
+
+ {
+ TString s = "GET / HTTP/1.1\r\nConnection: close\r\n\r\n";
+ TStringInput si(s);
+ THttpInput in(&si);
+ UNIT_ASSERT(!in.IsKeepAlive());
+ }
+
+ {
+ TString s = "HTTP/1.0 200 Ok\r\n\r\n";
+ TStringInput si(s);
+ THttpInput in(&si);
+ UNIT_ASSERT(!in.IsKeepAlive());
+ }
+
+ {
+ TString s = "HTTP/1.0 200 Ok\r\nConnection: keep-alive\r\n\r\n";
+ TStringInput si(s);
+ THttpInput in(&si);
+ UNIT_ASSERT(in.IsKeepAlive());
+ }
+
+ {
+ TString s = "HTTP/1.1 200 Ok\r\n\r\n";
+ TStringInput si(s);
+ THttpInput in(&si);
+ UNIT_ASSERT(in.IsKeepAlive());
+ }
+
+ {
+ TString s = "HTTP/1.1 200 Ok\r\nConnection: close\r\n\r\n";
+ TStringInput si(s);
+ THttpInput in(&si);
+ UNIT_ASSERT(!in.IsKeepAlive());
+ }
+ }
+
+ Y_UNIT_TEST(TestMinRequest) {
+ TString res = "qqqqqq";
+ TPortManager pm;
+ const ui16 port = pm.GetPort();
+
+ TTestHttpServer serverImpl(res);
+ THttpServer server(&serverImpl, THttpServer::TOptions(port).EnableKeepAlive(true).EnableCompression(true));
+
+ UNIT_ASSERT(server.Start());
+
+ TNetworkAddress addr("localhost", port);
+
+ TSocket s(addr);
+ TNullOutput dbg;
+
+ SendMinimalHttpRequest(s, "www.yandex.lo", "/");
+
+ TSocketInput si(s);
+ THttpInput input(&si);
+ unsigned httpCode = ParseHttpRetCode(input.FirstLine());
+ UNIT_ASSERT_VALUES_EQUAL(httpCode, 200u);
+
+ TransferData(&input, &dbg);
+ server.Stop();
+ }
+
+ Y_UNIT_TEST(TestResponseWithBlanks) {
+ TString res = "qqqqqq\r\n\r\nsdasdsad\r\n";
+ TPortManager pm;
+ const ui16 port = pm.GetPort();
+
+ TTestHttpServer serverImpl(res);
+ THttpServer server(&serverImpl, THttpServer::TOptions(port).EnableKeepAlive(true).EnableCompression(true));
+
+ UNIT_ASSERT(server.Start());
+
+ TNetworkAddress addr("localhost", port);
+
+ TSocket s(addr);
+
+ SendMinimalHttpRequest(s, "www.yandex.ru", "/");
+
+ TSocketInput si(s);
+ THttpInput input(&si);
+ unsigned httpCode = ParseHttpRetCode(input.FirstLine());
+ UNIT_ASSERT_VALUES_EQUAL(httpCode, 200u);
+ TString reply = input.ReadAll();
+ UNIT_ASSERT_VALUES_EQUAL(reply, res);
+ server.Stop();
+ }
+
+ Y_UNIT_TEST(TestOutputFlush) {
+ TString str;
+ TStringOutput strOut(str);
+ TBufferedOutput bufOut(&strOut, 8192);
+ THttpOutput httpOut(&bufOut);
+
+ httpOut.EnableKeepAlive(true);
+ httpOut.EnableCompression(true);
+
+ const char* header = "GET / HTTP/1.1\r\nHost: yandex.ru\r\n\r\n";
+ httpOut << header;
+
+ unsigned curLen = str.size();
+ const char* body = "<html>Hello</html>";
+ httpOut << body;
+ UNIT_ASSERT_VALUES_EQUAL(curLen, str.size());
+ httpOut.Flush();
+ UNIT_ASSERT_VALUES_EQUAL(curLen + strlen(body), str.size());
+ }
+
+ Y_UNIT_TEST(TestOutputPostFlush) {
+ TString str;
+ TString checkStr;
+ TStringOutput strOut(str);
+ TStringOutput checkOut(checkStr);
+ TBufferedOutput bufOut(&strOut, 8192);
+ TTeeOutput teeOut(&bufOut, &checkOut);
+ THttpOutput httpOut(&teeOut);
+
+ httpOut.EnableKeepAlive(true);
+ httpOut.EnableCompression(true);
+
+ const char* header = "POST / HTTP/1.1\r\nHost: yandex.ru\r\n\r\n";
+ httpOut << header;
+
+ UNIT_ASSERT_VALUES_EQUAL(str.size(), 0u);
+
+ const char* body = "<html>Hello</html>";
+ httpOut << body;
+ UNIT_ASSERT_VALUES_EQUAL(str.size(), 0u);
+
+ httpOut.Flush();
+ UNIT_ASSERT_VALUES_EQUAL(checkStr.size(), str.size());
+ }
+
+ TString MakeHttpOutputBody(const char* body, bool encodingEnabled) {
+ TString str;
+ TStringOutput strOut(str);
+ {
+ TBufferedOutput bufOut(&strOut, 8192);
+ THttpOutput httpOut(&bufOut);
+
+ httpOut.EnableKeepAlive(true);
+ httpOut.EnableCompression(true);
+ httpOut.EnableBodyEncoding(encodingEnabled);
+
+ httpOut << "POST / HTTP/1.1\r\n";
+ httpOut << "Host: yandex.ru\r\n";
+ httpOut << "Content-Encoding: gzip\r\n";
+ httpOut << "\r\n";
+
+ UNIT_ASSERT_VALUES_EQUAL(str.size(), 0u);
+ httpOut << body;
+ }
+ const char* bodyDelimiter = "\r\n\r\n";
+ size_t bodyPos = str.find(bodyDelimiter);
+ UNIT_ASSERT(bodyPos != TString::npos);
+ return str.substr(bodyPos + strlen(bodyDelimiter));
+ };
+
+ TString SimulateBodyEncoding(const char* body) {
+ TString bodyStr;
+ TStringOutput bodyOut(bodyStr);
+ TChunkedOutput chunkOut(&bodyOut);
+ TZLibCompress comprOut(&chunkOut, ZLib::GZip);
+ comprOut << body;
+ return bodyStr;
+ };
+
+ Y_UNIT_TEST(TestRebuildStreamOnPost) {
+ const char* body = "<html>Hello</html>";
+ UNIT_ASSERT(MakeHttpOutputBody(body, false) == body);
+ UNIT_ASSERT(MakeHttpOutputBody(body, true) == SimulateBodyEncoding(body));
+ }
+
+ Y_UNIT_TEST(TestOutputFinish) {
+ TString str;
+ TStringOutput strOut(str);
+ TBufferedOutput bufOut(&strOut, 8192);
+ THttpOutput httpOut(&bufOut);
+
+ httpOut.EnableKeepAlive(true);
+ httpOut.EnableCompression(true);
+
+ const char* header = "GET / HTTP/1.1\r\nHost: yandex.ru\r\n\r\n";
+ httpOut << header;
+
+ unsigned curLen = str.size();
+ const char* body = "<html>Hello</html>";
+ httpOut << body;
+ UNIT_ASSERT_VALUES_EQUAL(curLen, str.size());
+ httpOut.Finish();
+ UNIT_ASSERT_VALUES_EQUAL(curLen + strlen(body), str.size());
+ }
+
+ Y_UNIT_TEST(TestMultilineHeaders) {
+ const char* headerLine0 = "HTTP/1.1 200 OK";
+ const char* headerLine1 = "Content-Language: en";
+ const char* headerLine2 = "Vary: Accept-Encoding, ";
+ const char* headerLine3 = "\tAccept-Language";
+ const char* headerLine4 = "Content-Length: 18";
+
+ TString endLine("\r\n");
+ TString r;
+ r += headerLine0 + endLine;
+ r += headerLine1 + endLine;
+ r += headerLine2 + endLine;
+ r += headerLine3 + endLine;
+ r += headerLine4 + endLine + endLine;
+ r += "<html>Hello</html>";
+ TStringInput stringInput(r);
+ THttpInput input(&stringInput);
+
+ const THttpHeaders& httpHeaders = input.Headers();
+ UNIT_ASSERT_VALUES_EQUAL(httpHeaders.Count(), 3u);
+
+ THttpHeaders::TConstIterator it = httpHeaders.Begin();
+ UNIT_ASSERT_VALUES_EQUAL(it->ToString(), TString(headerLine1));
+ UNIT_ASSERT_VALUES_EQUAL((++it)->ToString(), TString::Join(headerLine2, headerLine3));
+ UNIT_ASSERT_VALUES_EQUAL((++it)->ToString(), TString(headerLine4));
+ }
+
+ Y_UNIT_TEST(ContentLengthRemoval) {
+ TMemoryInput request("GET / HTTP/1.1\r\nAccept-Encoding: gzip\r\n\r\n");
+ THttpInput i(&request);
+ TString result;
+ TStringOutput out(result);
+ THttpOutput httpOut(&out, &i);
+
+ httpOut.EnableKeepAlive(true);
+ httpOut.EnableCompression(true);
+ httpOut << "HTTP/1.1 200 OK\r\n";
+ char answer[] = "Mary had a little lamb.";
+ httpOut << "Content-Length: " << strlen(answer) << "\r\n"
+ "\r\n";
+ httpOut << answer;
+ httpOut.Finish();
+
+ Cdbg << result;
+ result.to_lower();
+ UNIT_ASSERT(result.Contains("content-encoding: gzip"));
+ UNIT_ASSERT(!result.Contains("content-length"));
+ }
+
+ Y_UNIT_TEST(CodecsPriority) {
+ TMemoryInput request("GET / HTTP/1.1\r\nAccept-Encoding: gzip, br\r\n\r\n");
+ TVector<TStringBuf> codecs = {"br", "gzip"};
+
+ THttpInput i(&request);
+ TString result;
+ TStringOutput out(result);
+ THttpOutput httpOut(&out, &i);
+
+ httpOut.EnableKeepAlive(true);
+ httpOut.EnableCompression(codecs);
+ httpOut << "HTTP/1.1 200 OK\r\n";
+ char answer[] = "Mary had a little lamb.";
+ httpOut << "Content-Length: " << strlen(answer) << "\r\n"
+ "\r\n";
+ httpOut << answer;
+ httpOut.Finish();
+
+ Cdbg << result;
+ result.to_lower();
+ UNIT_ASSERT(result.Contains("content-encoding: br"));
+ }
+
+ Y_UNIT_TEST(CodecsPriority2) {
+ TMemoryInput request("GET / HTTP/1.1\r\nAccept-Encoding: gzip, br\r\n\r\n");
+ TVector<TStringBuf> codecs = {"gzip", "br"};
+
+ THttpInput i(&request);
+ TString result;
+ TStringOutput out(result);
+ THttpOutput httpOut(&out, &i);
+
+ httpOut.EnableKeepAlive(true);
+ httpOut.EnableCompression(codecs);
+ httpOut << "HTTP/1.1 200 OK\r\n";
+ char answer[] = "Mary had a little lamb.";
+ httpOut << "Content-Length: " << strlen(answer) << "\r\n"
+ "\r\n";
+ httpOut << answer;
+ httpOut.Finish();
+
+ Cdbg << result;
+ result.to_lower();
+ UNIT_ASSERT(result.Contains("content-encoding: gzip"));
+ }
+
+ Y_UNIT_TEST(HasTrailers) {
+ TMemoryInput response(
+ "HTTP/1.1 200 OK\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n"
+ "3\r\n"
+ "foo"
+ "0\r\n"
+ "Bar: baz\r\n"
+ "\r\n");
+ THttpInput i(&response);
+ TMaybe<THttpHeaders> trailers = i.Trailers();
+ UNIT_ASSERT(!trailers.Defined());
+ i.ReadAll();
+ trailers = i.Trailers();
+ UNIT_ASSERT_VALUES_EQUAL(trailers.GetRef().Count(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(trailers.GetRef().Begin()->ToString(), "Bar: baz");
+ }
+
+ Y_UNIT_TEST(NoTrailersWithChunks) {
+ TMemoryInput response(
+ "HTTP/1.1 200 OK\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "\r\n"
+ "3\r\n"
+ "foo"
+ "0\r\n"
+ "\r\n");
+ THttpInput i(&response);
+ TMaybe<THttpHeaders> trailers = i.Trailers();
+ UNIT_ASSERT(!trailers.Defined());
+ i.ReadAll();
+ trailers = i.Trailers();
+ UNIT_ASSERT_VALUES_EQUAL(trailers.GetRef().Count(), 0);
+ }
+
+ Y_UNIT_TEST(NoTrailersNoChunks) {
+ TMemoryInput response(
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Length: 3\r\n"
+ "\r\n"
+ "bar");
+ THttpInput i(&response);
+ TMaybe<THttpHeaders> trailers = i.Trailers();
+ UNIT_ASSERT(!trailers.Defined());
+ i.ReadAll();
+ trailers = i.Trailers();
+ UNIT_ASSERT_VALUES_EQUAL(trailers.GetRef().Count(), 0);
+ }
+
+ Y_UNIT_TEST(RequestWithoutContentLength) {
+ TStringStream request;
+ {
+ THttpOutput httpOutput(&request);
+ httpOutput << "POST / HTTP/1.1\r\n"
+ "Host: yandex.ru\r\n"
+ "\r\n";
+ httpOutput << "GGLOL";
+ }
+ {
+ TStringInput input(request.Str());
+ THttpInput httpInput(&input);
+ bool chunkedOrHasContentLength = false;
+ for (const auto& header : httpInput.Headers()) {
+ if (header.Name() == "Transfer-Encoding" && header.Value() == "chunked" || header.Name() == "Content-Length") {
+ chunkedOrHasContentLength = true;
+ }
+ }
+
+ // If request doesn't contain neither Content-Length header nor Transfer-Encoding header
+ // then server considers message body length to be zero.
+ // (See https://tools.ietf.org/html/rfc7230#section-3.3.3)
+ UNIT_ASSERT(chunkedOrHasContentLength);
+
+ UNIT_ASSERT_VALUES_EQUAL(httpInput.ReadAll(), "GGLOL");
+ }
+ }
+
+ Y_UNIT_TEST(TestInputHasContent) {
+ {
+ TStringStream request;
+ request << "POST / HTTP/1.1\r\n"
+ "Host: yandex.ru\r\n"
+ "\r\n";
+ request << "HTTPDATA";
+
+ TStringInput input(request.Str());
+ THttpInput httpInput(&input);
+
+ UNIT_ASSERT(!httpInput.HasContent());
+ UNIT_ASSERT_VALUES_EQUAL(httpInput.ReadAll(), "");
+ }
+
+ {
+ TStringStream request;
+ request << "POST / HTTP/1.1\r\n"
+ "Host: yandex.ru\r\n"
+ "Content-Length: 8"
+ "\r\n\r\n";
+ request << "HTTPDATA";
+
+ TStringInput input(request.Str());
+ THttpInput httpInput(&input);
+
+ UNIT_ASSERT(httpInput.HasContent());
+ UNIT_ASSERT_VALUES_EQUAL(httpInput.ReadAll(), "HTTPDATA");
+ }
+
+ {
+ TStringStream request;
+ request << "POST / HTTP/1.1\r\n"
+ "Host: yandex.ru\r\n"
+ "Transfer-Encoding: chunked"
+ "\r\n\r\n";
+ request << "8\r\nHTTPDATA\r\n0\r\n";
+
+ TStringInput input(request.Str());
+ THttpInput httpInput(&input);
+
+ UNIT_ASSERT(httpInput.HasContent());
+ UNIT_ASSERT_VALUES_EQUAL(httpInput.ReadAll(), "HTTPDATA");
+ }
+ }
+
+ Y_UNIT_TEST(TestHttpInputHeadRequest) {
+ class THeadOnlyInput: public IInputStream {
+ public:
+ THeadOnlyInput() = default;
+
+ private:
+ size_t DoRead(void* buf, size_t len) override {
+ if (Eof_) {
+ ythrow yexception() << "should not read after EOF";
+ }
+
+ const size_t toWrite = Min(len, Data_.size() - Pos_);
+ if (toWrite == 0) {
+ Eof_ = true;
+ return 0;
+ }
+
+ memcpy(buf, Data_.data() + Pos_, toWrite);
+ Pos_ += toWrite;
+ return toWrite;
+ }
+
+ private:
+ TString Data_{TStringBuf("HEAD / HTTP/1.1\r\nHost: yandex.ru\r\n\r\n")};
+ size_t Pos_{0};
+ bool Eof_{false};
+ };
+ THeadOnlyInput input;
+ THttpInput httpInput(&input);
+
+ UNIT_ASSERT(!httpInput.HasContent());
+ UNIT_ASSERT_VALUES_EQUAL(httpInput.ReadAll(), "");
+ }
+
+ Y_UNIT_TEST(TestHttpOutputResponseToHeadRequestNoZeroChunk) {
+ TStringStream request;
+ request << "HEAD / HTTP/1.1\r\n"
+ "Host: yandex.ru\r\n"
+ "Connection: Keep-Alive\r\n"
+ "\r\n";
+
+ TStringInput input(request.Str());
+ THttpInput httpInput(&input);
+
+ TStringStream outBuf;
+ THttpOutput out(&outBuf, &httpInput);
+ out.EnableKeepAlive(true);
+ out << "HTTP/1.1 200 OK\r\nConnection: Keep-Alive\r\n\r\n";
+ out << "";
+ out.Finish();
+ TString result = outBuf.Str();
+ UNIT_ASSERT(!result.Contains(TStringBuf("0\r\n")));
+ }
+
+ Y_UNIT_TEST(TestHttpOutputDisableCompressionHeader) {
+ TMemoryInput request("GET / HTTP/1.1\r\nAccept-Encoding: gzip\r\n\r\n");
+ const TString data = "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqq";
+
+ THttpInput httpInput(&request);
+ TString result;
+
+ {
+ TStringOutput output(result);
+ THttpOutput httpOutput(&output, &httpInput);
+ httpOutput.EnableCompressionHeader(false);
+ httpOutput << "HTTP/1.1 200 OK\r\n"
+ "content-encoding: gzip\r\n"
+ "\r\n" + data;
+ httpOutput.Finish();
+ }
+
+ UNIT_ASSERT(result.Contains("content-encoding: gzip"));
+ UNIT_ASSERT(result.Contains(data));
+ }
+
+ size_t DoTestHttpOutputSize(const TString& res, bool enableCompession) {
+ TTestHttpServer serverImpl(res);
+ TPortManager pm;
+
+ const ui16 port = pm.GetPort();
+ THttpServer server(&serverImpl,
+ THttpServer::TOptions(port)
+ .EnableKeepAlive(true)
+ .EnableCompression(enableCompession));
+ UNIT_ASSERT(server.Start());
+
+ TNetworkAddress addr("localhost", port);
+ TSocket s(addr);
+
+ {
+ TSocketOutput so(s);
+ THttpOutput out(&so);
+ out << "GET / HTTP/1.1\r\n"
+ "Host: www.yandex.ru\r\n"
+ "Connection: Keep-Alive\r\n"
+ "Accept-Encoding: gzip\r\n"
+ "\r\n";
+ out.Finish();
+ }
+
+ TSocketInput si(s);
+ THttpInput input(&si);
+
+ unsigned httpCode = ParseHttpRetCode(input.FirstLine());
+ UNIT_ASSERT_VALUES_EQUAL(httpCode, 200u);
+
+ UNIT_ASSERT_VALUES_EQUAL(res, input.ReadAll());
+
+ server.Stop();
+
+ return serverImpl.LastRequestSentSize();
+ }
+
+ Y_UNIT_TEST(TestHttpOutputSize) {
+ TString res = "qqqqqq";
+ UNIT_ASSERT_VALUES_EQUAL(res.size(), DoTestHttpOutputSize(res, false));
+ UNIT_ASSERT_VALUES_UNEQUAL(res.size(), DoTestHttpOutputSize(res, true));
+ }
+} // THttpStreamTest suite
diff --git a/library/cpp/http/io/stream_ut_medium.cpp b/library/cpp/http/io/stream_ut_medium.cpp
new file mode 100644
index 0000000000..2c125eb21e
--- /dev/null
+++ b/library/cpp/http/io/stream_ut_medium.cpp
@@ -0,0 +1,54 @@
+#include "stream.h"
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/stream/zlib.h>
+
+Y_UNIT_TEST_SUITE(THttpTestMedium) {
+ Y_UNIT_TEST(TestCodings2) {
+ TStringBuf data = "aaaaaaaaaaaaaaaaaaaaaaa";
+
+ for (auto codec : SupportedCodings()) {
+ if (codec == TStringBuf("z-zlib-0")) {
+ continue;
+ }
+
+ if (codec == TStringBuf("z-null")) {
+ continue;
+ }
+
+ TString s;
+
+ {
+ TStringOutput so(s);
+ THttpOutput ho(&so);
+ TBufferedOutput bo(&ho, 10000);
+
+ bo << "HTTP/1.1 200 Ok\r\n"
+ << "Connection: close\r\n"
+ << "Content-Encoding: " << codec << "\r\n\r\n";
+
+ for (size_t i = 0; i < 100; ++i) {
+ bo << data;
+ }
+ }
+
+ try {
+ UNIT_ASSERT(s.size() > 10);
+ UNIT_ASSERT(s.find(data) == TString::npos);
+ } catch (...) {
+ Cerr << codec << " " << s << Endl;
+
+ throw;
+ }
+
+ {
+ TStringInput si(s);
+ THttpInput hi(&si);
+
+ auto res = hi.ReadAll();
+
+ UNIT_ASSERT(res.find(data) == 0);
+ }
+ }
+ }
+
+} // THttpTestMedium suite
diff --git a/library/cpp/http/io/ut/medium/ya.make b/library/cpp/http/io/ut/medium/ya.make
new file mode 100644
index 0000000000..235a23dcd7
--- /dev/null
+++ b/library/cpp/http/io/ut/medium/ya.make
@@ -0,0 +1,11 @@
+UNITTEST_FOR(library/cpp/http/io)
+
+SIZE(MEDIUM)
+
+OWNER(g:util)
+
+SRCS(
+ stream_ut_medium.cpp
+)
+
+END()
diff --git a/library/cpp/http/io/ut/ya.make b/library/cpp/http/io/ut/ya.make
new file mode 100644
index 0000000000..84f6949db3
--- /dev/null
+++ b/library/cpp/http/io/ut/ya.make
@@ -0,0 +1,16 @@
+UNITTEST_FOR(library/cpp/http/io)
+
+OWNER(g:util)
+
+PEERDIR(
+ library/cpp/http/server
+)
+
+SRCS(
+ chunk_ut.cpp
+ compression_ut.cpp
+ headers_ut.cpp
+ stream_ut.cpp
+)
+
+END()
diff --git a/library/cpp/http/io/ya.make b/library/cpp/http/io/ya.make
new file mode 100644
index 0000000000..dcfbd79885
--- /dev/null
+++ b/library/cpp/http/io/ya.make
@@ -0,0 +1,22 @@
+LIBRARY()
+
+OWNER(
+ g:util
+ mvel
+)
+
+PEERDIR(
+ library/cpp/blockcodecs
+ library/cpp/streams/brotli
+ library/cpp/streams/bzip2
+ library/cpp/streams/lzma
+)
+
+SRCS(
+ chunk.cpp
+ compression.cpp
+ headers.cpp
+ stream.cpp
+)
+
+END()
diff --git a/library/cpp/http/misc/http_headers.h b/library/cpp/http/misc/http_headers.h
new file mode 100644
index 0000000000..ff359937fa
--- /dev/null
+++ b/library/cpp/http/misc/http_headers.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+
+/* Taken from SpringFramework's HttpHeaders. Docs:
+ * https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/HttpHeaders.html
+ * Source:
+ * https://github.com/spring-projects/spring-framework/blob/816bbee8de584676250e2bc5dcff6da6cd81623f/spring-web/src/main/java/org/springframework/http/HttpHeaders.java
+ */
+namespace NHttpHeaders {
+ constexpr TStringBuf ACCEPT = "Accept";
+ constexpr TStringBuf ACCEPT_CHARSET = "Accept-Charset";
+ constexpr TStringBuf ACCEPT_ENCODING = "Accept-Encoding";
+ constexpr TStringBuf ACCEPT_LANGUAGE = "Accept-Language";
+ constexpr TStringBuf ACCEPT_RANGES = "Accept-Ranges";
+ constexpr TStringBuf ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
+ constexpr TStringBuf ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
+ constexpr TStringBuf ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
+ constexpr TStringBuf ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
+ constexpr TStringBuf ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
+ constexpr TStringBuf ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age";
+ constexpr TStringBuf ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers";
+ constexpr TStringBuf ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method";
+ constexpr TStringBuf AGE = "Age";
+ constexpr TStringBuf ALLOW = "Allow";
+ constexpr TStringBuf AUTHORIZATION = "Authorization";
+ constexpr TStringBuf CACHE_CONTROL = "Cache-Control";
+ constexpr TStringBuf CONNECTION = "Connection";
+ constexpr TStringBuf CONTENT_ENCODING = "Content-Encoding";
+ constexpr TStringBuf CONTENT_DISPOSITION = "Content-Disposition";
+ constexpr TStringBuf CONTENT_LANGUAGE = "Content-Language";
+ constexpr TStringBuf CONTENT_LENGTH = "Content-Length";
+ constexpr TStringBuf CONTENT_LOCATION = "Content-Location";
+ constexpr TStringBuf CONTENT_RANGE = "Content-Range";
+ constexpr TStringBuf CONTENT_TYPE = "Content-Type";
+ constexpr TStringBuf COOKIE = "Cookie";
+ constexpr TStringBuf DATE = "Date";
+ constexpr TStringBuf ETAG = "ETag";
+ constexpr TStringBuf EXPECT = "Expect";
+ constexpr TStringBuf EXPIRES = "Expires";
+ constexpr TStringBuf FROM = "From";
+ constexpr TStringBuf HOST = "Host";
+ constexpr TStringBuf IF_MATCH = "If-Match";
+ constexpr TStringBuf IF_MODIFIED_SINCE = "If-Modified-Since";
+ constexpr TStringBuf IF_NONE_MATCH = "If-None-Match";
+ constexpr TStringBuf IF_RANGE = "If-Range";
+ constexpr TStringBuf IF_UNMODIFIED_SINCE = "If-Unmodified-Since";
+ constexpr TStringBuf LAST_MODIFIED = "Last-Modified";
+ constexpr TStringBuf LINK = "Link";
+ constexpr TStringBuf LOCATION = "Location";
+ constexpr TStringBuf MAX_FORWARDS = "Max-Forwards";
+ constexpr TStringBuf ORIGIN = "Origin";
+ constexpr TStringBuf PRAGMA = "Pragma";
+ constexpr TStringBuf PROXY_AUTHENTICATE = "Proxy-Authenticate";
+ constexpr TStringBuf PROXY_AUTHORIZATION = "Proxy-Authorization";
+ constexpr TStringBuf RANGE = "Range";
+ constexpr TStringBuf REFERER = "Referer";
+ constexpr TStringBuf RETRY_AFTER = "Retry-After";
+ constexpr TStringBuf SERVER = "Server";
+ constexpr TStringBuf SET_COOKIE = "Set-Cookie";
+ constexpr TStringBuf SET_COOKIE2 = "Set-Cookie2";
+ constexpr TStringBuf TE = "TE";
+ constexpr TStringBuf TRAILER = "Trailer";
+ constexpr TStringBuf TRANSFER_ENCODING = "Transfer-Encoding";
+ constexpr TStringBuf UPGRADE = "Upgrade";
+ constexpr TStringBuf USER_AGENT = "User-Agent";
+ constexpr TStringBuf VARY = "Vary";
+ constexpr TStringBuf VIA = "Via";
+ constexpr TStringBuf WARNING = "Warning";
+ constexpr TStringBuf WWW_AUTHENTICATE = "WWW-Authenticate";
+} // namespace HttpHeaders
diff --git a/library/cpp/http/misc/httpcodes.cpp b/library/cpp/http/misc/httpcodes.cpp
new file mode 100644
index 0000000000..ad8c80ac1e
--- /dev/null
+++ b/library/cpp/http/misc/httpcodes.cpp
@@ -0,0 +1,141 @@
+#include "httpcodes.h"
+
+TStringBuf HttpCodeStrEx(int code) noexcept {
+ switch (code) {
+ case HTTP_CONTINUE:
+ return TStringBuf("100 Continue");
+ case HTTP_SWITCHING_PROTOCOLS:
+ return TStringBuf("101 Switching protocols");
+ case HTTP_PROCESSING:
+ return TStringBuf("102 Processing");
+
+ case HTTP_OK:
+ return TStringBuf("200 Ok");
+ case HTTP_CREATED:
+ return TStringBuf("201 Created");
+ case HTTP_ACCEPTED:
+ return TStringBuf("202 Accepted");
+ case HTTP_NON_AUTHORITATIVE_INFORMATION:
+ return TStringBuf("203 None authoritative information");
+ case HTTP_NO_CONTENT:
+ return TStringBuf("204 No content");
+ case HTTP_RESET_CONTENT:
+ return TStringBuf("205 Reset content");
+ case HTTP_PARTIAL_CONTENT:
+ return TStringBuf("206 Partial content");
+ case HTTP_MULTI_STATUS:
+ return TStringBuf("207 Multi status");
+ case HTTP_ALREADY_REPORTED:
+ return TStringBuf("208 Already reported");
+ case HTTP_IM_USED:
+ return TStringBuf("226 IM used");
+
+ case HTTP_MULTIPLE_CHOICES:
+ return TStringBuf("300 Multiple choices");
+ case HTTP_MOVED_PERMANENTLY:
+ return TStringBuf("301 Moved permanently");
+ case HTTP_FOUND:
+ return TStringBuf("302 Moved temporarily");
+ case HTTP_SEE_OTHER:
+ return TStringBuf("303 See other");
+ case HTTP_NOT_MODIFIED:
+ return TStringBuf("304 Not modified");
+ case HTTP_USE_PROXY:
+ return TStringBuf("305 Use proxy");
+ case HTTP_TEMPORARY_REDIRECT:
+ return TStringBuf("307 Temporarily redirect");
+ case HTTP_PERMANENT_REDIRECT:
+ return TStringBuf("308 Permanent redirect");
+
+ case HTTP_BAD_REQUEST:
+ return TStringBuf("400 Bad request");
+ case HTTP_UNAUTHORIZED:
+ return TStringBuf("401 Unauthorized");
+ case HTTP_PAYMENT_REQUIRED:
+ return TStringBuf("402 Payment required");
+ case HTTP_FORBIDDEN:
+ return TStringBuf("403 Forbidden");
+ case HTTP_NOT_FOUND:
+ return TStringBuf("404 Not found");
+ case HTTP_METHOD_NOT_ALLOWED:
+ return TStringBuf("405 Method not allowed");
+ case HTTP_NOT_ACCEPTABLE:
+ return TStringBuf("406 Not acceptable");
+ case HTTP_PROXY_AUTHENTICATION_REQUIRED:
+ return TStringBuf("407 Proxy Authentication required");
+ case HTTP_REQUEST_TIME_OUT:
+ return TStringBuf("408 Request time out");
+ case HTTP_CONFLICT:
+ return TStringBuf("409 Conflict");
+ case HTTP_GONE:
+ return TStringBuf("410 Gone");
+ case HTTP_LENGTH_REQUIRED:
+ return TStringBuf("411 Length required");
+ case HTTP_PRECONDITION_FAILED:
+ return TStringBuf("412 Precondition failed");
+ case HTTP_REQUEST_ENTITY_TOO_LARGE:
+ return TStringBuf("413 Request entity too large");
+ case HTTP_REQUEST_URI_TOO_LARGE:
+ return TStringBuf("414 Request uri too large");
+ case HTTP_UNSUPPORTED_MEDIA_TYPE:
+ return TStringBuf("415 Unsupported media type");
+ case HTTP_REQUESTED_RANGE_NOT_SATISFIABLE:
+ return TStringBuf("416 Requested Range Not Satisfiable");
+ case HTTP_EXPECTATION_FAILED:
+ return TStringBuf("417 Expectation Failed");
+ case HTTP_I_AM_A_TEAPOT:
+ return TStringBuf("418 I Am A Teapot");
+ case HTTP_AUTHENTICATION_TIMEOUT:
+ return TStringBuf("419 Authentication Timeout");
+ case HTTP_MISDIRECTED_REQUEST:
+ return TStringBuf("421 Misdirected Request");
+ case HTTP_UNPROCESSABLE_ENTITY:
+ return TStringBuf("422 Unprocessable Entity");
+ case HTTP_LOCKED:
+ return TStringBuf("423 Locked");
+ case HTTP_FAILED_DEPENDENCY:
+ return TStringBuf("424 Failed Dependency");
+ case HTTP_UNORDERED_COLLECTION:
+ return TStringBuf("425 Unordered Collection");
+ case HTTP_UPGRADE_REQUIRED:
+ return TStringBuf("426 Upgrade Required");
+ case HTTP_PRECONDITION_REQUIRED:
+ return TStringBuf("428 Precondition Required");
+ case HTTP_TOO_MANY_REQUESTS:
+ return TStringBuf("429 Too Many Requests");
+ case HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE:
+ return TStringBuf("431 Request Header Fields Too Large");
+ case HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
+ return TStringBuf("451 Unavailable For Legal Reason");
+
+ case HTTP_INTERNAL_SERVER_ERROR:
+ return TStringBuf("500 Internal server error");
+ case HTTP_NOT_IMPLEMENTED:
+ return TStringBuf("501 Not implemented");
+ case HTTP_BAD_GATEWAY:
+ return TStringBuf("502 Bad gateway");
+ case HTTP_SERVICE_UNAVAILABLE:
+ return TStringBuf("503 Service unavailable");
+ case HTTP_GATEWAY_TIME_OUT:
+ return TStringBuf("504 Gateway time out");
+ case HTTP_HTTP_VERSION_NOT_SUPPORTED:
+ return TStringBuf("505 HTTP version not supported");
+ case HTTP_VARIANT_ALSO_NEGOTIATES:
+ return TStringBuf("506 Variant also negotiates");
+ case HTTP_INSUFFICIENT_STORAGE:
+ return TStringBuf("507 Insufficient storage");
+ case HTTP_LOOP_DETECTED:
+ return TStringBuf("508 Loop Detected");
+ case HTTP_BANDWIDTH_LIMIT_EXCEEDED:
+ return TStringBuf("509 Bandwidth Limit Exceeded");
+ case HTTP_NOT_EXTENDED:
+ return TStringBuf("510 Not Extended");
+ case HTTP_NETWORK_AUTHENTICATION_REQUIRED:
+ return TStringBuf("511 Network Authentication Required");
+ case HTTP_UNASSIGNED_512:
+ return TStringBuf("512 Unassigned");
+
+ default:
+ return TStringBuf("000 Unknown HTTP code");
+ }
+}
diff --git a/library/cpp/http/misc/httpcodes.h b/library/cpp/http/misc/httpcodes.h
new file mode 100644
index 0000000000..cbfbaa1188
--- /dev/null
+++ b/library/cpp/http/misc/httpcodes.h
@@ -0,0 +1,94 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+enum HttpCodes {
+ HTTP_CONTINUE = 100,
+ HTTP_SWITCHING_PROTOCOLS = 101,
+ HTTP_PROCESSING = 102,
+
+ HTTP_OK = 200,
+ HTTP_CREATED = 201,
+ HTTP_ACCEPTED = 202,
+ HTTP_NON_AUTHORITATIVE_INFORMATION = 203,
+ HTTP_NO_CONTENT = 204,
+ HTTP_RESET_CONTENT = 205,
+ HTTP_PARTIAL_CONTENT = 206,
+ HTTP_MULTI_STATUS = 207,
+ HTTP_ALREADY_REPORTED = 208,
+ HTTP_IM_USED = 226,
+
+ HTTP_MULTIPLE_CHOICES = 300,
+ HTTP_MOVED_PERMANENTLY = 301,
+ HTTP_FOUND = 302,
+ HTTP_SEE_OTHER = 303,
+ HTTP_NOT_MODIFIED = 304,
+ HTTP_USE_PROXY = 305,
+ HTTP_TEMPORARY_REDIRECT = 307,
+ HTTP_PERMANENT_REDIRECT = 308,
+
+ HTTP_BAD_REQUEST = 400,
+ HTTP_UNAUTHORIZED = 401,
+ HTTP_PAYMENT_REQUIRED = 402,
+ HTTP_FORBIDDEN = 403,
+ HTTP_NOT_FOUND = 404,
+ HTTP_METHOD_NOT_ALLOWED = 405,
+ HTTP_NOT_ACCEPTABLE = 406,
+ HTTP_PROXY_AUTHENTICATION_REQUIRED = 407,
+ HTTP_REQUEST_TIME_OUT = 408,
+ HTTP_CONFLICT = 409,
+ HTTP_GONE = 410,
+ HTTP_LENGTH_REQUIRED = 411,
+ HTTP_PRECONDITION_FAILED = 412,
+ HTTP_REQUEST_ENTITY_TOO_LARGE = 413,
+ HTTP_REQUEST_URI_TOO_LARGE = 414,
+ HTTP_UNSUPPORTED_MEDIA_TYPE = 415,
+ HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416,
+ HTTP_EXPECTATION_FAILED = 417,
+ HTTP_I_AM_A_TEAPOT = 418,
+ HTTP_AUTHENTICATION_TIMEOUT = 419,
+ HTTP_MISDIRECTED_REQUEST = 421,
+ HTTP_UNPROCESSABLE_ENTITY = 422,
+ HTTP_LOCKED = 423,
+ HTTP_FAILED_DEPENDENCY = 424,
+ HTTP_UNORDERED_COLLECTION = 425,
+ HTTP_UPGRADE_REQUIRED = 426,
+ HTTP_PRECONDITION_REQUIRED = 428,
+ HTTP_TOO_MANY_REQUESTS = 429,
+ HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
+ HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451,
+
+ HTTP_INTERNAL_SERVER_ERROR = 500,
+ HTTP_NOT_IMPLEMENTED = 501,
+ HTTP_BAD_GATEWAY = 502,
+ HTTP_SERVICE_UNAVAILABLE = 503,
+ HTTP_GATEWAY_TIME_OUT = 504,
+ HTTP_HTTP_VERSION_NOT_SUPPORTED = 505,
+ HTTP_VARIANT_ALSO_NEGOTIATES = 506,
+ HTTP_INSUFFICIENT_STORAGE = 507,
+ HTTP_LOOP_DETECTED = 508,
+ HTTP_BANDWIDTH_LIMIT_EXCEEDED = 509,
+ HTTP_NOT_EXTENDED = 510,
+ HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511,
+ HTTP_UNASSIGNED_512 = 512,
+
+ HTTP_CODE_MAX
+};
+
+TStringBuf HttpCodeStrEx(int code) noexcept;
+
+inline TStringBuf HttpCodeStr(int code) noexcept {
+ return HttpCodeStrEx(code).Skip(4);
+}
+
+inline bool IsHttpCode(int code) noexcept {
+ return HttpCodeStrEx(code).data() != HttpCodeStrEx(0).data();
+}
+
+inline bool IsUserError(int code) noexcept {
+ return code >= 400 && code < 500;
+}
+
+inline bool IsServerError(int code) noexcept {
+ return code >= 500;
+}
diff --git a/library/cpp/http/misc/httpdate.cpp b/library/cpp/http/misc/httpdate.cpp
new file mode 100644
index 0000000000..4a3031bbf4
--- /dev/null
+++ b/library/cpp/http/misc/httpdate.cpp
@@ -0,0 +1,83 @@
+/*-
+* Copyright 1997 Massachusetts Institute of Technology
+*
+* Permission to use, copy, modify, and distribute this software and
+* its documentation for any purpose and without fee is hereby
+* granted, provided that both the above copyright notice and this
+* permission notice appear in all copies, that both the above
+* copyright notice and this permission notice appear in all
+* supporting documentation, and that the name of M.I.T. not be used
+* in advertising or publicity pertaining to distribution of the
+* software without specific, written prior permission. M.I.T. makes
+* no representations about the suitability of this software for any
+* purpose. It is provided "as is" without express or implied
+* warranty.
+*
+* THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+* ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+* SHALL M.I.T. 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 <util/system/defaults.h>
+
+#include <sys/types.h>
+#include <cctype>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+
+#include <util/system/compat.h> /* stricmp */
+#include <util/system/yassert.h>
+#include "httpdate.h"
+#include <util/datetime/base.h>
+
+static const char *wkdays[] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+
+static const char *months[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
+ "Nov", "Dec"
+};
+
+int format_http_date(char buf[], size_t size, time_t when) {
+ struct tm tms;
+ GmTimeR(&when, &tms);
+
+#ifndef HTTP_DATE_ISO_8601
+ return snprintf(buf, size, "%s, %02d %s %04d %02d:%02d:%02d GMT",
+ wkdays[tms.tm_wday], tms.tm_mday, months[tms.tm_mon],
+ tms.tm_year + 1900, tms.tm_hour, tms.tm_min, tms.tm_sec);
+#else /* ISO 8601 */
+ return snprintf(buf, size, "%04d%02d%02dT%02d%02d%02d+0000",
+ tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday,
+ tms.tm_hour, tms.tm_min, tms.tm_sec);
+#endif
+}
+
+char* format_http_date(time_t when, char* buf, size_t buflen) {
+ const int len = format_http_date(buf, buflen, when);
+
+ if (len == 0) {
+ return nullptr;
+ }
+
+ Y_ASSERT(len > 0 && size_t(len) < buflen);
+
+ return buf;
+}
+
+TString FormatHttpDate(time_t when) {
+ char str[64] = {0};
+ format_http_date(str, Y_ARRAY_SIZE(str), when);
+ return TString(str);
+}
diff --git a/library/cpp/http/misc/httpdate.h b/library/cpp/http/misc/httpdate.h
new file mode 100644
index 0000000000..04876f38fe
--- /dev/null
+++ b/library/cpp/http/misc/httpdate.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <util/datetime/base.h>
+#include <util/generic/string.h>
+
+#include <ctime>
+
+#define BAD_DATE ((time_t)-1)
+
+inline time_t parse_http_date(const TStringBuf& datestring) {
+ try {
+ return TInstant::ParseHttpDeprecated(datestring).TimeT();
+ } catch (const TDateTimeParseException&) {
+ return BAD_DATE;
+ }
+}
+
+int format_http_date(char buf[], size_t size, time_t when);
+char* format_http_date(time_t when, char* buf, size_t len);
+
+TString FormatHttpDate(time_t when);
diff --git a/library/cpp/http/misc/httpdate_ut.cpp b/library/cpp/http/misc/httpdate_ut.cpp
new file mode 100644
index 0000000000..c1a0103501
--- /dev/null
+++ b/library/cpp/http/misc/httpdate_ut.cpp
@@ -0,0 +1,15 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "httpdate.h"
+
+Y_UNIT_TEST_SUITE(TestHttpDate) {
+ Y_UNIT_TEST(Test1) {
+ char buf1[100];
+ char buf2[100];
+
+ UNIT_ASSERT((int)strlen(format_http_date(0, buf1, sizeof(buf1))) == format_http_date(buf2, sizeof(buf2), 0));
+ }
+ Y_UNIT_TEST(Test2) {
+ UNIT_ASSERT_STRINGS_EQUAL(FormatHttpDate(1234567890), "Fri, 13 Feb 2009 23:31:30 GMT");
+ }
+}
diff --git a/library/cpp/http/misc/httpreqdata.cpp b/library/cpp/http/misc/httpreqdata.cpp
new file mode 100644
index 0000000000..f6951f68cd
--- /dev/null
+++ b/library/cpp/http/misc/httpreqdata.cpp
@@ -0,0 +1,196 @@
+#include "httpreqdata.h"
+
+#include <util/stream/mem.h>
+
+TBaseServerRequestData::TBaseServerRequestData(SOCKET s)
+ : Addr(nullptr)
+ , Host()
+ , Port()
+ , Path(nullptr)
+ , Search(nullptr)
+ , SearchLength(0)
+ , Socket(s)
+ , BeginTime(MicroSeconds())
+{
+}
+
+TBaseServerRequestData::TBaseServerRequestData(const char* qs, SOCKET s)
+ : Addr(nullptr)
+ , Host()
+ , Port()
+ , Path(nullptr)
+ , Search((char*)qs)
+ , SearchLength(qs ? strlen(qs) : 0)
+ , OrigSearch(Search, SearchLength)
+ , Socket(s)
+ , BeginTime(MicroSeconds())
+{
+}
+
+void TBaseServerRequestData::AppendQueryString(const char* str, size_t length) {
+ if (Y_UNLIKELY(Search)) {
+ Y_ASSERT(strlen(Search) == SearchLength);
+ ModifiedQueryString.Reserve(SearchLength + length + 2);
+ ModifiedQueryString.Assign(Search, SearchLength);
+ if (SearchLength > 0 && Search[SearchLength - 1] != '&' &&
+ length > 0 && str[0] != '&') {
+ ModifiedQueryString.Append('&');
+ }
+ ModifiedQueryString.Append(str, length);
+ } else {
+ ModifiedQueryString.Reserve(length + 1);
+ ModifiedQueryString.Assign(str, length);
+ }
+ ModifiedQueryString.Append('\0');
+ Search = ModifiedQueryString.data();
+ SearchLength = ModifiedQueryString.size() - 1; // ignore terminator
+}
+
+void TBaseServerRequestData::SetRemoteAddr(TStringBuf addr) {
+ TMemoryOutput out(AddrData, Y_ARRAY_SIZE(AddrData) - 1);
+ out.Write(addr.substr(0, Y_ARRAY_SIZE(AddrData) - 1));
+ *out.Buf() = '\0';
+
+ Addr = AddrData;
+}
+
+const char* TBaseServerRequestData::RemoteAddr() const {
+ if (!Addr) {
+ *AddrData = 0;
+ GetRemoteAddr(Socket, AddrData, sizeof(AddrData));
+ Addr = AddrData;
+ }
+
+ return Addr;
+}
+
+const char* TBaseServerRequestData::HeaderIn(TStringBuf key) const {
+ auto it = HeadersIn_.find(key);
+
+ if (it == HeadersIn_.end()) {
+ return nullptr;
+ }
+
+ return it->second.data();
+}
+
+TString TBaseServerRequestData::HeaderByIndex(size_t n) const noexcept {
+ if (n >= HeadersCount()) {
+ return nullptr;
+ }
+
+ THttpHeadersContainer::const_iterator i = HeadersIn_.begin();
+
+ while (n) {
+ ++i;
+ --n;
+ }
+
+ return TString(i->first) + TStringBuf(": ") + i->second;
+}
+
+const char* TBaseServerRequestData::Environment(const char* key) const {
+ if (stricmp(key, "REMOTE_ADDR") == 0) {
+ const char* ip = HeaderIn("X-Real-IP");
+ if (ip)
+ return ip;
+ return RemoteAddr();
+ } else if (stricmp(key, "QUERY_STRING") == 0) {
+ return QueryString();
+ } else if (stricmp(key, "SERVER_NAME") == 0) {
+ return ServerName().data();
+ } else if (stricmp(key, "SERVER_PORT") == 0) {
+ return ServerPort().data();
+ } else if (stricmp(key, "SCRIPT_NAME") == 0) {
+ return ScriptName();
+ }
+ return nullptr;
+}
+
+void TBaseServerRequestData::Clear() {
+ HeadersIn_.clear();
+ Addr = Path = Search = nullptr;
+ OrigSearch = {};
+ SearchLength = 0;
+ Host.clear();
+ Port.clear();
+ CurPage.remove();
+ ParseBuf.Clear();
+ BeginTime = MicroSeconds();
+}
+
+const char* TBaseServerRequestData::GetCurPage() const {
+ if (!CurPage && Host) {
+ CurPage = "http://";
+ CurPage += Host;
+ if (Port) {
+ CurPage += ':';
+ CurPage += Port;
+ }
+ CurPage += Path;
+ if (Search) {
+ CurPage += '?';
+ CurPage += Search;
+ }
+ }
+ return CurPage.data();
+}
+
+bool TBaseServerRequestData::Parse(const char* origReq) {
+ size_t origReqLength = strlen(origReq);
+ ParseBuf.Assign(origReq, origReqLength + 1);
+ char* req = ParseBuf.Data();
+
+ while (*req == ' ' || *req == '\t')
+ req++;
+ if (*req != '/')
+ return false; // we are not a proxy
+ while (req[1] == '/') // remove redundant slashes
+ req++;
+
+ // detect url end (can contain some garbage after whitespace, e.g. 'HTTP 1.1')
+ char* urlEnd = req;
+ while (*urlEnd && *urlEnd != ' ' && *urlEnd != '\t')
+ urlEnd++;
+ if (*urlEnd)
+ *urlEnd = 0;
+
+ // cut fragment if exists
+ char* fragment = strchr(req, '#');
+ if (fragment)
+ *fragment = 0; // ignore fragment
+ else
+ fragment = urlEnd;
+ Path = req;
+
+ // calculate Search length without additional strlen-ing
+ Search = strchr(Path, '?');
+ if (Search) {
+ *Search++ = 0;
+ ptrdiff_t delta = fragment - Search;
+ // indeed, second case is a parse error
+ SearchLength = (delta >= 0) ? delta : (urlEnd - Search);
+ Y_ASSERT(strlen(Search) == SearchLength);
+ } else {
+ SearchLength = 0;
+ }
+ OrigSearch = {Search, SearchLength};
+
+ return true;
+}
+
+void TBaseServerRequestData::AddHeader(const TString& name, const TString& value) {
+ HeadersIn_[name] = value;
+
+ if (stricmp(name.data(), "Host") == 0) {
+ size_t hostLen = strcspn(value.data(), ":");
+ if (value[hostLen] == ':')
+ Port = value.substr(hostLen + 1);
+ Host = value.substr(0, hostLen);
+ }
+}
+
+void TBaseServerRequestData::SetPath(const TString& path) {
+ PathStorage = TBuffer(path.data(), path.size() + 1);
+ Path = PathStorage.Data();
+}
diff --git a/library/cpp/http/misc/httpreqdata.h b/library/cpp/http/misc/httpreqdata.h
new file mode 100644
index 0000000000..16e59c4d78
--- /dev/null
+++ b/library/cpp/http/misc/httpreqdata.h
@@ -0,0 +1,125 @@
+#pragma once
+
+#include <library/cpp/digest/lower_case/hash_ops.h>
+
+#include <util/str_stl.h>
+
+#include <util/system/defaults.h>
+#include <util/string/cast.h>
+#include <library/cpp/cgiparam/cgiparam.h>
+#include <util/network/address.h>
+#include <util/network/socket.h>
+#include <util/generic/hash.h>
+#include <util/system/yassert.h>
+#include <util/generic/string.h>
+#include <util/datetime/base.h>
+#include <util/generic/buffer.h>
+
+using THttpHeadersContainer = THashMap<TString, TString, TCIOps, TCIOps>;
+
+class TBaseServerRequestData {
+public:
+ TBaseServerRequestData(SOCKET s = INVALID_SOCKET);
+ TBaseServerRequestData(const char* qs, SOCKET s = INVALID_SOCKET);
+
+ void SetHost(const TString& host, ui16 port) {
+ Host = host;
+ Port = ToString(port);
+ }
+
+ const TString& ServerName() const {
+ return Host;
+ }
+
+ NAddr::IRemoteAddrPtr ServerAddress() const {
+ return NAddr::GetSockAddr(Socket);
+ }
+
+ const TString& ServerPort() const {
+ return Port;
+ }
+
+ const char* ScriptName() const {
+ return Path;
+ }
+
+ const char* QueryString() const {
+ return Search;
+ }
+
+ TStringBuf QueryStringBuf() const {
+ return TStringBuf(Search, SearchLength);
+ }
+
+ TStringBuf OrigQueryStringBuf() const {
+ return OrigSearch;
+ }
+
+ void AppendQueryString(const char* str, size_t length);
+ const char* RemoteAddr() const;
+ void SetRemoteAddr(TStringBuf addr);
+ const char* HeaderIn(TStringBuf key) const;
+
+ const THttpHeadersContainer& HeadersIn() const {
+ return HeadersIn_;
+ }
+
+ inline size_t HeadersCount() const noexcept {
+ return HeadersIn_.size();
+ }
+
+ TString HeaderByIndex(size_t n) const noexcept;
+ const char* Environment(const char* key) const;
+
+ void Clear();
+
+ void SetSocket(SOCKET s) noexcept {
+ Socket = s;
+ }
+
+ ui64 RequestBeginTime() const noexcept {
+ return BeginTime;
+ }
+
+ void SetPath(const TString& path);
+ const char* GetCurPage() const;
+ bool Parse(const char* req);
+ void AddHeader(const TString& name, const TString& value);
+
+private:
+ TBuffer PathStorage;
+ mutable char* Addr;
+ TString Host;
+ TString Port;
+ char* Path;
+ char* Search;
+ size_t SearchLength; // length of Search
+ TStringBuf OrigSearch;
+ THttpHeadersContainer HeadersIn_;
+ mutable char AddrData[INET6_ADDRSTRLEN];
+ SOCKET Socket;
+ ui64 BeginTime;
+ mutable TString CurPage;
+ TBuffer ParseBuf;
+ TBuffer ModifiedQueryString;
+};
+
+class TServerRequestData: public TBaseServerRequestData {
+public:
+ TServerRequestData(SOCKET s = INVALID_SOCKET)
+ : TBaseServerRequestData(s)
+ {
+ }
+ TServerRequestData(const char* qs, SOCKET s = INVALID_SOCKET)
+ : TBaseServerRequestData(qs, s)
+ {
+ Scan();
+ }
+
+ void Scan() {
+ CgiParam.Scan(QueryStringBuf());
+ }
+
+public:
+ TCgiParameters CgiParam;
+};
diff --git a/library/cpp/http/misc/httpreqdata_ut.cpp b/library/cpp/http/misc/httpreqdata_ut.cpp
new file mode 100644
index 0000000000..e7f16ef27c
--- /dev/null
+++ b/library/cpp/http/misc/httpreqdata_ut.cpp
@@ -0,0 +1,154 @@
+#include "httpreqdata.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TRequestServerDataTest) {
+ Y_UNIT_TEST(Headers) {
+ TServerRequestData sd;
+
+ sd.AddHeader("x-xx", "y-yy");
+ sd.AddHeader("x-Xx", "y-yy");
+
+ UNIT_ASSERT_VALUES_EQUAL(sd.HeadersCount(), 1);
+
+ sd.AddHeader("x-XxX", "y-yyy");
+ UNIT_ASSERT_VALUES_EQUAL(sd.HeadersCount(), 2);
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuf(sd.HeaderIn("X-XX")), TStringBuf("y-yy"));
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuf(sd.HeaderIn("X-XXX")), TStringBuf("y-yyy"));
+ }
+
+ Y_UNIT_TEST(ComplexHeaders) {
+ TServerRequestData sd;
+ sd.SetHost("zzz", 1);
+
+ sd.AddHeader("x-Xx", "y-yy");
+ UNIT_ASSERT_VALUES_EQUAL(sd.HeadersCount(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuf(sd.HeaderIn("X-XX")), TStringBuf("y-yy"));
+
+ sd.AddHeader("x-Xz", "y-yy");
+ UNIT_ASSERT_VALUES_EQUAL(sd.HeadersCount(), 2);
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuf(sd.HeaderIn("X-Xz")), TStringBuf("y-yy"));
+
+ UNIT_ASSERT_VALUES_EQUAL(sd.ServerName(), "zzz");
+ UNIT_ASSERT_VALUES_EQUAL(sd.ServerPort(), "1");
+ sd.AddHeader("Host", "1234");
+ UNIT_ASSERT_VALUES_EQUAL(sd.HeadersCount(), 3);
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuf(sd.HeaderIn("Host")), TStringBuf("1234"));
+ UNIT_ASSERT_VALUES_EQUAL(sd.ServerName(), "1234");
+ sd.AddHeader("Host", "12345:678");
+ UNIT_ASSERT_VALUES_EQUAL(sd.HeadersCount(), 3);
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuf(sd.HeaderIn("Host")), TStringBuf("12345:678"));
+ UNIT_ASSERT_VALUES_EQUAL(sd.ServerName(), "12345");
+ UNIT_ASSERT_VALUES_EQUAL(sd.ServerPort(), "678");
+ }
+
+ Y_UNIT_TEST(ParseScan) {
+ TServerRequestData rd;
+
+ // Parse parses url without host
+ UNIT_ASSERT(!rd.Parse(" http://yandex.ru/yandsearch?&gta=fake&haha=da HTTP 1.1 OK"));
+
+ // This should work
+ UNIT_ASSERT(rd.Parse(" /yandsearch?&gta=fake&haha=da HTTP 1.1 OK"));
+
+ UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), "&gta=fake&haha=da");
+ UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), rd.OrigQueryStringBuf());
+
+ rd.Scan();
+ UNIT_ASSERT(rd.CgiParam.Has("gta", "fake"));
+ UNIT_ASSERT(rd.CgiParam.Has("haha", "da"));
+ UNIT_ASSERT(!rd.CgiParam.Has("no-param"));
+
+ rd.Clear();
+ }
+
+ Y_UNIT_TEST(Ctor) {
+ const TString qs("gta=fake&haha=da");
+ TServerRequestData rd(qs.c_str());
+
+ UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), qs);
+ UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQueryStringBuf(), qs);
+
+ UNIT_ASSERT(rd.CgiParam.Has("gta"));
+ UNIT_ASSERT(rd.CgiParam.Has("haha"));
+ UNIT_ASSERT(!rd.CgiParam.Has("no-param"));
+ }
+
+ Y_UNIT_TEST(HashCut) {
+ const TString qs("&gta=fake&haha=da");
+ const TString header = " /yandsearch?" + qs + "#&uberParam=yes&q=? HTTP 1.1 OK";
+
+ TServerRequestData rd;
+ rd.Parse(header.c_str());
+
+ UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), qs);
+ UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQueryStringBuf(), qs);
+
+ rd.Scan();
+ UNIT_ASSERT(rd.CgiParam.Has("gta"));
+ UNIT_ASSERT(rd.CgiParam.Has("haha"));
+ UNIT_ASSERT(!rd.CgiParam.Has("uberParam"));
+ }
+
+ Y_UNIT_TEST(MisplacedHashCut) {
+ TServerRequestData rd;
+ rd.Parse(" /y#ndsearch?&gta=fake&haha=da&uberParam=yes&q=? HTTP 1.1 OK");
+
+ UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), "");
+ UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQueryStringBuf(), "");
+
+ rd.Scan();
+ UNIT_ASSERT(rd.CgiParam.empty());
+ }
+
+ Y_UNIT_TEST(CornerCase) {
+ TServerRequestData rd;
+ rd.Parse(" /yandsearch?#");
+
+ UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), "");
+ UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQueryStringBuf(), "");
+
+ rd.Scan();
+ UNIT_ASSERT(rd.CgiParam.empty());
+ }
+
+ Y_UNIT_TEST(AppendQueryString) {
+ const TString qs("gta=fake&haha=da");
+ TServerRequestData rd(qs.c_str());
+
+ UNIT_ASSERT(rd.CgiParam.Has("gta", "fake"));
+ UNIT_ASSERT(rd.CgiParam.Has("haha", "da"));
+
+ UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), qs);
+ UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), rd.OrigQueryStringBuf());
+
+ constexpr TStringBuf appendix = "gta=true&gta=new";
+ rd.AppendQueryString(appendix.data(), appendix.size());
+
+ UNIT_ASSERT_STRINGS_EQUAL(rd.QueryStringBuf(), qs + '&' + appendix);
+ UNIT_ASSERT_STRINGS_EQUAL(rd.OrigQueryStringBuf(), qs);
+
+ rd.Scan();
+
+ UNIT_ASSERT(rd.CgiParam.Has("gta", "true"));
+ UNIT_ASSERT(rd.CgiParam.Has("gta", "new"));
+ }
+
+ Y_UNIT_TEST(SetRemoteAddrSimple) {
+ static const TString TEST = "abacaba.search.yandex.net";
+
+ TServerRequestData rd;
+ rd.SetRemoteAddr(TEST);
+ UNIT_ASSERT_STRINGS_EQUAL(TEST, rd.RemoteAddr());
+ }
+
+ Y_UNIT_TEST(SetRemoteAddrRandom) {
+ for (size_t size = 0; size < 2 * INET6_ADDRSTRLEN; ++size) {
+ const TString test = NUnitTest::RandomString(size, size);
+ TServerRequestData rd;
+ rd.SetRemoteAddr(test);
+ UNIT_ASSERT_STRINGS_EQUAL(test.substr(0, INET6_ADDRSTRLEN - 1), rd.RemoteAddr());
+ }
+ }
+
+} // TRequestServerDataTest
diff --git a/library/cpp/http/misc/parsed_request.cpp b/library/cpp/http/misc/parsed_request.cpp
new file mode 100644
index 0000000000..e332a24e91
--- /dev/null
+++ b/library/cpp/http/misc/parsed_request.cpp
@@ -0,0 +1,32 @@
+#include "parsed_request.h"
+
+#include <util/string/strip.h>
+#include <util/generic/yexception.h>
+#include <util/string/cast.h>
+
+static inline TStringBuf StripLeft(const TStringBuf& s) noexcept {
+ const char* b = s.begin();
+ const char* e = s.end();
+
+ StripRangeBegin(b, e);
+
+ return TStringBuf(b, e);
+}
+
+TParsedHttpRequest::TParsedHttpRequest(const TStringBuf& str) {
+ TStringBuf tmp;
+
+ if (!StripLeft(str).TrySplit(' ', Method, tmp)) {
+ ythrow yexception() << "bad request(" << ToString(str).Quote() << ")";
+ }
+
+ if (!StripLeft(tmp).TrySplit(' ', Request, Proto)) {
+ ythrow yexception() << "bad request(" << ToString(str).Quote() << ")";
+ }
+
+ Proto = StripLeft(Proto);
+}
+
+TParsedHttpLocation::TParsedHttpLocation(const TStringBuf& req) {
+ req.Split('?', Path, Cgi);
+}
diff --git a/library/cpp/http/misc/parsed_request.h b/library/cpp/http/misc/parsed_request.h
new file mode 100644
index 0000000000..d4df705495
--- /dev/null
+++ b/library/cpp/http/misc/parsed_request.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+struct TParsedHttpRequest {
+ TParsedHttpRequest(const TStringBuf& str);
+
+ TStringBuf Method;
+ TStringBuf Request;
+ TStringBuf Proto;
+};
+
+struct TParsedHttpLocation {
+ TParsedHttpLocation(const TStringBuf& req);
+
+ TStringBuf Path;
+ TStringBuf Cgi;
+};
+
+struct TParsedHttpFull: public TParsedHttpRequest, public TParsedHttpLocation {
+ inline TParsedHttpFull(const TStringBuf& line)
+ : TParsedHttpRequest(line)
+ , TParsedHttpLocation(Request)
+ {
+ }
+};
diff --git a/library/cpp/http/misc/parsed_request_ut.cpp b/library/cpp/http/misc/parsed_request_ut.cpp
new file mode 100644
index 0000000000..da6d95c6ab
--- /dev/null
+++ b/library/cpp/http/misc/parsed_request_ut.cpp
@@ -0,0 +1,28 @@
+#include "parsed_request.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(THttpParse) {
+ Y_UNIT_TEST(TestParse) {
+ TParsedHttpFull h("GET /yandsearch?text=nokia HTTP/1.1");
+
+ UNIT_ASSERT_EQUAL(h.Method, "GET");
+ UNIT_ASSERT_EQUAL(h.Request, "/yandsearch?text=nokia");
+ UNIT_ASSERT_EQUAL(h.Proto, "HTTP/1.1");
+
+ UNIT_ASSERT_EQUAL(h.Path, "/yandsearch");
+ UNIT_ASSERT_EQUAL(h.Cgi, "text=nokia");
+ }
+
+ Y_UNIT_TEST(TestError) {
+ bool wasError = false;
+
+ try {
+ TParsedHttpFull("GET /yandsearch?text=nokiaHTTP/1.1");
+ } catch (...) {
+ wasError = true;
+ }
+
+ UNIT_ASSERT(wasError);
+ }
+}
diff --git a/library/cpp/http/misc/ut/ya.make b/library/cpp/http/misc/ut/ya.make
new file mode 100644
index 0000000000..f4bdd35662
--- /dev/null
+++ b/library/cpp/http/misc/ut/ya.make
@@ -0,0 +1,11 @@
+UNITTEST_FOR(library/cpp/http/misc)
+
+OWNER(g:util)
+
+SRCS(
+ httpdate_ut.cpp
+ httpreqdata_ut.cpp
+ parsed_request_ut.cpp
+)
+
+END()
diff --git a/library/cpp/http/misc/ya.make b/library/cpp/http/misc/ya.make
new file mode 100644
index 0000000000..fceb3cf79c
--- /dev/null
+++ b/library/cpp/http/misc/ya.make
@@ -0,0 +1,24 @@
+LIBRARY()
+
+OWNER(
+ g:util
+ mvel
+)
+
+GENERATE_ENUM_SERIALIZATION(httpcodes.h)
+
+SRCS(
+ httpcodes.cpp
+ httpdate.cpp
+ httpreqdata.cpp
+ parsed_request.cpp
+)
+
+PEERDIR(
+ library/cpp/cgiparam
+ library/cpp/digest/lower_case
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/http/server/conn.cpp b/library/cpp/http/server/conn.cpp
new file mode 100644
index 0000000000..38a76c4c30
--- /dev/null
+++ b/library/cpp/http/server/conn.cpp
@@ -0,0 +1,69 @@
+#include "conn.h"
+
+#include <util/network/socket.h>
+#include <util/stream/buffered.h>
+
+class THttpServerConn::TImpl {
+public:
+ inline TImpl(const TSocket& s, size_t outputBufferSize)
+ : S_(s)
+ , SI_(S_)
+ , SO_(S_)
+ , BO_(&SO_, outputBufferSize)
+ , HI_(&SI_)
+ , HO_(&BO_, &HI_)
+ {
+ }
+
+ inline ~TImpl() {
+ }
+
+ inline THttpInput* Input() noexcept {
+ return &HI_;
+ }
+
+ inline THttpOutput* Output() noexcept {
+ return &HO_;
+ }
+
+ inline void Reset() {
+ if (S_ != INVALID_SOCKET) {
+ // send RST packet to client
+ S_.SetLinger(true, 0);
+ S_.Close();
+ }
+ }
+
+private:
+ TSocket S_;
+ TSocketInput SI_;
+ TSocketOutput SO_;
+ TBufferedOutput BO_;
+ THttpInput HI_;
+ THttpOutput HO_;
+};
+
+THttpServerConn::THttpServerConn(const TSocket& s)
+ : THttpServerConn(s, s.MaximumTransferUnit())
+{
+}
+
+THttpServerConn::THttpServerConn(const TSocket& s, size_t outputBufferSize)
+ : Impl_(new TImpl(s, outputBufferSize))
+{
+}
+
+THttpServerConn::~THttpServerConn() {
+}
+
+THttpInput* THttpServerConn::Input() noexcept {
+ return Impl_->Input();
+}
+
+THttpOutput* THttpServerConn::Output() noexcept {
+ return Impl_->Output();
+}
+
+void THttpServerConn::Reset() {
+ return Impl_->Reset();
+}
diff --git a/library/cpp/http/server/conn.h b/library/cpp/http/server/conn.h
new file mode 100644
index 0000000000..3aa5329af4
--- /dev/null
+++ b/library/cpp/http/server/conn.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include <library/cpp/http/io/stream.h>
+#include <util/generic/ptr.h>
+
+class TSocket;
+
+/// Потоки ввода/вывода для получения запросов и отправки ответов HTTP-сервера.
+class THttpServerConn {
+public:
+ explicit THttpServerConn(const TSocket& s);
+ THttpServerConn(const TSocket& s, size_t outputBufferSize);
+ ~THttpServerConn();
+
+ THttpInput* Input() noexcept;
+ THttpOutput* Output() noexcept;
+
+ inline const THttpInput* Input() const noexcept {
+ return const_cast<THttpServerConn*>(this)->Input();
+ }
+
+ inline const THttpOutput* Output() const noexcept {
+ return const_cast<THttpServerConn*>(this)->Output();
+ }
+
+ /// Проверяет, можно ли установить режим, при котором соединение с сервером
+ /// не завершается после окончания транзакции.
+ inline bool CanBeKeepAlive() const noexcept {
+ return Output()->CanBeKeepAlive();
+ }
+
+ void Reset();
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
diff --git a/library/cpp/http/server/http.cpp b/library/cpp/http/server/http.cpp
new file mode 100644
index 0000000000..128583bdd7
--- /dev/null
+++ b/library/cpp/http/server/http.cpp
@@ -0,0 +1,843 @@
+#include "http.h"
+#include "http_ex.h"
+
+#include <library/cpp/threading/equeue/equeue.h>
+
+#include <util/generic/buffer.h>
+#include <util/generic/cast.h>
+#include <util/generic/intrlist.h>
+#include <util/generic/yexception.h>
+#include <util/network/address.h>
+#include <util/network/socket.h>
+#include <util/network/poller.h>
+#include <util/system/atomic.h>
+#include <util/system/compat.h> // stricmp, strnicmp, strlwr, strupr, stpcpy
+#include <util/system/defaults.h>
+#include <util/system/event.h>
+#include <util/system/mutex.h>
+#include <util/system/pipe.h>
+#include <util/system/thread.h>
+#include <util/thread/factory.h>
+
+#include <cerrno>
+#include <cstring>
+#include <ctime>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+using namespace NAddr;
+
+namespace {
+ class IPollAble {
+ public:
+ inline IPollAble() noexcept {
+ }
+
+ virtual ~IPollAble() {
+ }
+
+ virtual void OnPollEvent(TInstant now) = 0;
+ };
+
+ struct TShouldStop {
+ };
+
+ struct TWakeupPollAble: public IPollAble {
+ void OnPollEvent(TInstant) override {
+ throw TShouldStop();
+ }
+ };
+}
+
+class TClientConnection: public IPollAble, public TIntrusiveListItem<TClientConnection> {
+public:
+ TClientConnection(const TSocket& s, THttpServer::TImpl* serv, NAddr::IRemoteAddrRef listenerSockAddrRef);
+ ~TClientConnection() override;
+
+ void OnPollEvent(TInstant now) override;
+
+ inline void Activate(TInstant now) noexcept;
+ inline void DeActivate();
+ inline void Reject();
+
+public:
+ TSocket Socket_;
+ NAddr::IRemoteAddrRef ListenerSockAddrRef_;
+ THttpServer::TImpl* HttpServ_ = nullptr;
+ bool Reject_ = false;
+ TInstant LastUsed;
+ TInstant AcceptMoment;
+ size_t ReceivedRequests = 0;
+};
+
+class THttpServer::TImpl {
+public:
+ class TConnections {
+ public:
+ inline TConnections(TSocketPoller* poller, const THttpServerOptions& options)
+ : Poller_(poller)
+ , Options(options)
+ {
+ }
+
+ inline ~TConnections() {
+ }
+
+ inline void Add(TClientConnection* c) noexcept {
+ TGuard<TMutex> g(Mutex_);
+
+ Conns_.PushBack(c);
+ Poller_->WaitRead(c->Socket_, (void*)static_cast<const IPollAble*>(c));
+ }
+
+ inline void Erase(TClientConnection* c, TInstant now) noexcept {
+ TGuard<TMutex> g(Mutex_);
+ EraseUnsafe(c);
+ if (Options.ExpirationTimeout > TDuration::Zero()) {
+ TryRemovingUnsafe(now - Options.ExpirationTimeout);
+ }
+ }
+
+ inline void Clear() noexcept {
+ TGuard<TMutex> g(Mutex_);
+
+ Conns_.Clear();
+ }
+
+ inline bool RemoveOld(TInstant border) noexcept {
+ TGuard<TMutex> g(Mutex_);
+ return TryRemovingUnsafe(border);
+ }
+
+ bool TryRemovingUnsafe(TInstant border) noexcept {
+ if (Conns_.Empty()) {
+ return false;
+ }
+ TClientConnection* c = &*(Conns_.Begin());
+ if (c->LastUsed > border) {
+ return false;
+ }
+ EraseUnsafe(c);
+ delete c;
+ return true;
+ }
+
+ void EraseUnsafe(TClientConnection* c) noexcept {
+ Poller_->Unwait(c->Socket_);
+ c->Unlink();
+ }
+
+ public:
+ TMutex Mutex_;
+ TIntrusiveListWithAutoDelete<TClientConnection, TDelete> Conns_;
+ TSocketPoller* Poller_ = nullptr;
+ const THttpServerOptions& Options;
+ };
+
+ static void* ListenSocketFunction(void* param) {
+ try {
+ ((TImpl*)param)->ListenSocket();
+ } catch (...) {
+
+ }
+
+ return nullptr;
+ }
+
+ TAutoPtr<TClientRequest> CreateRequest(TAutoPtr<TClientConnection> c) {
+ THolder<TClientRequest> obj(Cb_->CreateClient());
+
+ obj->Conn_.Reset(c.Release());
+
+ return obj;
+ }
+
+ void AddRequestFromSocket(const TSocket& s, TInstant now, NAddr::IRemoteAddrRef listenerSockAddrRef) {
+ if (MaxRequestsReached()) {
+ Cb_->OnMaxConn();
+ bool wasRemoved = Connections->RemoveOld(TInstant::Max());
+ if (!wasRemoved && Options_.RejectExcessConnections) {
+ (new TClientConnection(s, this, listenerSockAddrRef))->Reject();
+ return;
+ }
+ }
+
+ auto connection = new TClientConnection(s, this, listenerSockAddrRef);
+ connection->LastUsed = now;
+ connection->DeActivate();
+ }
+
+ void SaveErrorCode() {
+ ErrorCode = WSAGetLastError();
+ }
+
+ int GetErrorCode() const {
+ return ErrorCode;
+ }
+
+ const char* GetError() const {
+ return LastSystemErrorText(ErrorCode);
+ }
+
+ bool Start() {
+ Poller.Reset(new TSocketPoller());
+ Connections.Reset(new TConnections(Poller.Get(), Options_));
+
+ // Start the listener thread
+ ListenerRunningOK = false;
+
+ // throws on error
+ TPipeHandle::Pipe(ListenWakeupReadFd, ListenWakeupWriteFd);
+
+ SetNonBlock(ListenWakeupWriteFd, true);
+ SetNonBlock(ListenWakeupReadFd, true);
+
+ Poller->WaitRead(ListenWakeupReadFd, &WakeupPollAble);
+
+ ListenStartEvent.Reset();
+ try {
+ ListenThread.Reset(new TThread(ListenSocketFunction, this));
+ ListenThread->Start();
+ } catch (const yexception&) {
+ SaveErrorCode();
+ return false;
+ }
+
+ // Wait until the thread has completely started and return the success indicator
+ ListenStartEvent.Wait();
+
+ return ListenerRunningOK;
+ }
+
+ void Wait() {
+ Cb_->OnWait();
+ TGuard<TMutex> g(StopMutex);
+ if (ListenThread) {
+ ListenThread->Join();
+ ListenThread.Reset(nullptr);
+ }
+ }
+
+ void Stop() {
+ Shutdown();
+
+ TGuard<TMutex> g(StopMutex);
+ if (ListenThread) {
+ ListenThread->Join();
+ ListenThread.Reset(nullptr);
+ }
+
+ while (ConnectionCount) {
+ usleep(10000);
+ Connections->Clear();
+ }
+
+ Connections.Destroy();
+ Poller.Destroy();
+ }
+
+ void Shutdown() {
+ ListenWakeupWriteFd.Write("", 1);
+ // ignore result
+ }
+
+ void AddRequest(TAutoPtr<TClientRequest> req, bool fail) {
+ struct TFailRequest: public THttpClientRequestEx {
+ inline TFailRequest(TAutoPtr<TClientRequest> parent) {
+ Conn_.Reset(parent->Conn_.Release());
+ HttpConn_.Reset(parent->HttpConn_.Release());
+ }
+
+ bool Reply(void*) override {
+ if (!ProcessHeaders()) {
+ return true;
+ }
+
+ ProcessFailRequest(0);
+ return true;
+ }
+ };
+
+ if (!fail && Requests->Add(req.Get())) {
+ Y_UNUSED(req.Release());
+ } else {
+ req = new TFailRequest(req);
+
+ if (FailRequests->Add(req.Get())) {
+ Y_UNUSED(req.Release());
+ } else {
+ Cb_->OnFailRequest(-1);
+ }
+ }
+ }
+
+ size_t GetRequestQueueSize() const {
+ return Requests->Size();
+ }
+
+ size_t GetFailQueueSize() const {
+ return FailRequests->Size();
+ }
+
+ const IThreadPool& GetRequestQueue() const {
+ return *Requests;
+ }
+
+ const IThreadPool& GetFailQueue() const {
+ return *FailRequests;
+ }
+
+ class TListenSocket: public IPollAble, public TIntrusiveListItem<TListenSocket> {
+ public:
+ inline TListenSocket(const TSocket& s, TImpl* parent)
+ : S_(s)
+ , Server_(parent)
+ , SockAddrRef_(GetSockAddr(S_))
+ {
+ }
+
+ ~TListenSocket() override {
+ }
+
+ void OnPollEvent(TInstant) override {
+ SOCKET s = ::accept(S_, nullptr, nullptr);
+
+ if (s == INVALID_SOCKET) {
+ ythrow yexception() << "accept: " << LastSystemErrorText();
+ }
+
+ Server_->AddRequestFromSocket(s, TInstant::Now(), SockAddrRef_);
+ }
+
+ SOCKET GetSocket() const noexcept {
+ return S_;
+ }
+
+ private:
+ TSocket S_;
+ TImpl* Server_ = nullptr;
+ NAddr::IRemoteAddrRef SockAddrRef_;
+ };
+
+ void ListenSocket() {
+ TThread::SetCurrentThreadName(Options_.ListenThreadName.c_str());
+
+ ErrorCode = 0;
+ TIntrusiveListWithAutoDelete<TListenSocket, TDelete> Reqs;
+
+ std::function<void(TSocket)> callback = [&](TSocket socket) {
+ THolder<TListenSocket> ls(new TListenSocket(socket, this));
+ Poller->WaitRead(socket, static_cast<IPollAble*>(ls.Get()));
+ Reqs.PushBack(ls.Release());
+ };
+ bool addressesBound = TryToBindAddresses(Options_, &callback);
+ if (!addressesBound) {
+ SaveErrorCode();
+ ListenStartEvent.Signal();
+
+ return;
+ }
+
+ Requests->Start(Options_.nThreads, Options_.MaxQueueSize);
+ FailRequests->Start(Options_.nFThreads, Options_.MaxFQueueSize);
+ Cb_->OnListenStart();
+ ListenerRunningOK = true;
+ ListenStartEvent.Signal();
+
+ TVector<void*> events;
+ events.resize(1);
+
+ TInstant now = TInstant::Now();
+ for (;;) {
+ try {
+ const TInstant deadline = Options_.PollTimeout == TDuration::Zero() ? TInstant::Max() : now + Options_.PollTimeout;
+ const size_t ret = Poller->WaitD(events.data(), events.size(), deadline);
+
+ now = TInstant::Now();
+ for (size_t i = 0; i < ret; ++i) {
+ ((IPollAble*)events[i])->OnPollEvent(now);
+ }
+
+ if (ret == 0 && Options_.ExpirationTimeout > TDuration::Zero()) {
+ Connections->RemoveOld(now - Options_.ExpirationTimeout);
+ }
+
+ // When MaxConnections is limited or ExpirationTimeout is set, OnPollEvent can call
+ // RemoveOld and destroy other IPollAble* objects in the
+ // poller. Thus in this case we can safely process only one
+ // event from the poller at a time.
+ if (!Options_.MaxConnections && Options_.ExpirationTimeout == TDuration::Zero()) {
+ if (ret >= events.size()) {
+ events.resize(ret * 2);
+ }
+ }
+ } catch (const TShouldStop&) {
+ break;
+ } catch (...) {
+ Cb_->OnException();
+ }
+ }
+
+ while (!Reqs.Empty()) {
+ THolder<TListenSocket> ls(Reqs.PopFront());
+
+ Poller->Unwait(ls->GetSocket());
+ }
+
+ Requests->Stop();
+ FailRequests->Stop();
+ Cb_->OnListenStop();
+ }
+
+ void RestartRequestThreads(ui32 nTh, ui32 maxQS) {
+ Requests->Stop();
+ Options_.nThreads = nTh;
+ Options_.MaxQueueSize = maxQS;
+ Requests->Start(Options_.nThreads, Options_.MaxQueueSize);
+ }
+
+ TImpl(THttpServer* parent, ICallBack* cb, TMtpQueueRef mainWorkers, TMtpQueueRef failWorkers, const TOptions& options_)
+ : Requests(mainWorkers)
+ , FailRequests(failWorkers)
+ , Options_(options_)
+ , Cb_(cb)
+ , Parent_(parent)
+ {
+ }
+
+ TImpl(THttpServer* parent, ICallBack* cb, const TOptions& options, IThreadFactory* factory)
+ : TImpl(
+ parent,
+ cb,
+ MakeThreadPool<TSimpleThreadPool>(factory, options.UseElasticQueues, cb, options.RequestsThreadName),
+ MakeThreadPool<TThreadPool>(factory, options.UseElasticQueues, nullptr, options.FailRequestsThreadName),
+ options) {
+ }
+
+ ~TImpl() {
+ try {
+ Stop();
+ } catch (...) {
+ }
+ }
+
+ inline const TOptions& Options() const noexcept {
+ return Options_;
+ }
+
+ inline void DecreaseConnections() noexcept {
+ AtomicDecrement(ConnectionCount);
+ }
+
+ inline void IncreaseConnections() noexcept {
+ AtomicIncrement(ConnectionCount);
+ }
+
+ inline i64 GetClientCount() const {
+ return AtomicGet(ConnectionCount);
+ }
+
+ inline bool MaxRequestsReached() const {
+ return Options_.MaxConnections && ((size_t)GetClientCount() >= Options_.MaxConnections);
+ }
+
+ THolder<TThread> ListenThread;
+ TPipeHandle ListenWakeupReadFd;
+ TPipeHandle ListenWakeupWriteFd;
+ TSystemEvent ListenStartEvent;
+ TMtpQueueRef Requests;
+ TMtpQueueRef FailRequests;
+ TAtomic ConnectionCount = 0;
+ THolder<TSocketPoller> Poller;
+ THolder<TConnections> Connections;
+ bool ListenerRunningOK = false;
+ int ErrorCode = 0;
+ TOptions Options_;
+ ICallBack* Cb_ = nullptr;
+ THttpServer* Parent_ = nullptr;
+ TWakeupPollAble WakeupPollAble;
+ TMutex StopMutex;
+
+private:
+ template <class TThreadPool_>
+ static THolder<IThreadPool> MakeThreadPool(IThreadFactory* factory, bool elastic, ICallBack* callback = nullptr, const TString& threadName = {}) {
+ if (!factory) {
+ factory = SystemThreadFactory();
+ }
+
+ THolder<IThreadPool> pool;
+ const auto params = IThreadPool::TParams().SetFactory(factory).SetThreadName(threadName);
+ if (callback) {
+ pool = MakeHolder<TThreadPoolBinder<TThreadPool_, THttpServer::ICallBack>>(callback, params);
+ } else {
+ pool = MakeHolder<TThreadPool_>(params);
+ }
+
+ if (elastic) {
+ pool = MakeHolder<TElasticQueue>(std::move(pool));
+ }
+
+ return pool;
+ }
+};
+
+THttpServer::THttpServer(ICallBack* cb, const TOptions& options, IThreadFactory* pool)
+ : Impl_(new TImpl(this, cb, options, pool))
+{
+}
+
+THttpServer::THttpServer(ICallBack* cb, TMtpQueueRef mainWorkers, TMtpQueueRef failWorkers, const TOptions& options)
+ : Impl_(new TImpl(this, cb, mainWorkers, failWorkers, options))
+{
+}
+
+THttpServer::~THttpServer() {
+}
+
+i64 THttpServer::GetClientCount() const {
+ return Impl_->GetClientCount();
+}
+
+bool THttpServer::Start() {
+ return Impl_->Start();
+}
+
+void THttpServer::Stop() {
+ Impl_->Stop();
+}
+
+void THttpServer::Shutdown() {
+ Impl_->Shutdown();
+}
+
+void THttpServer::Wait() {
+ Impl_->Wait();
+}
+
+int THttpServer::GetErrorCode() {
+ return Impl_->GetErrorCode();
+}
+
+const char* THttpServer::GetError() {
+ return Impl_->GetError();
+}
+
+void THttpServer::RestartRequestThreads(ui32 n, ui32 queue) {
+ Impl_->RestartRequestThreads(n, queue);
+}
+
+const THttpServer::TOptions& THttpServer::Options() const noexcept {
+ return Impl_->Options();
+}
+
+size_t THttpServer::GetRequestQueueSize() const {
+ return Impl_->GetRequestQueueSize();
+}
+
+size_t THttpServer::GetFailQueueSize() const {
+ return Impl_->GetFailQueueSize();
+}
+
+const IThreadPool& THttpServer::GetRequestQueue() const {
+ return Impl_->GetRequestQueue();
+}
+
+const IThreadPool& THttpServer::GetFailQueue() const {
+ return Impl_->GetFailQueue();
+}
+
+bool THttpServer::MaxRequestsReached() const {
+ return Impl_->MaxRequestsReached();
+}
+
+TClientConnection::TClientConnection(const TSocket& s, THttpServer::TImpl* serv, NAddr::IRemoteAddrRef listenerSockAddrRef)
+ : Socket_(s)
+ , ListenerSockAddrRef_(listenerSockAddrRef)
+ , HttpServ_(serv)
+{
+ SetNoDelay(Socket_, true);
+
+ const TDuration& clientTimeout = HttpServ_->Options().ClientTimeout;
+ if (clientTimeout != TDuration::Zero()) {
+ SetSocketTimeout(Socket_, (long)clientTimeout.Seconds(), clientTimeout.MilliSecondsOfSecond());
+ }
+
+ HttpServ_->IncreaseConnections();
+}
+
+TClientConnection::~TClientConnection() {
+ HttpServ_->DecreaseConnections();
+}
+
+void TClientConnection::OnPollEvent(TInstant now) {
+ THolder<TClientConnection> this_(this);
+ Activate(now);
+
+ {
+ char tmp[1];
+
+ if (::recv(Socket_, tmp, 1, MSG_PEEK) < 1) {
+ /*
+ * We can received a FIN so our socket was moved to
+ * TCP_CLOSE_WAIT state. Check it before adding work
+ * for this socket.
+ */
+
+ return;
+ }
+ }
+
+ THolder<TClientRequest> obj(HttpServ_->CreateRequest(this_));
+ AcceptMoment = now;
+
+ HttpServ_->AddRequest(obj, Reject_);
+}
+
+void TClientConnection::Activate(TInstant now) noexcept {
+ HttpServ_->Connections->Erase(this, now);
+ LastUsed = now;
+ ++ReceivedRequests;
+}
+
+void TClientConnection::DeActivate() {
+ HttpServ_->Connections->Add(this);
+}
+
+void TClientConnection::Reject() {
+ Reject_ = true;
+
+ HttpServ_->Connections->Add(this);
+}
+
+TClientRequest::TClientRequest() {
+}
+
+TClientRequest::~TClientRequest() {
+}
+
+bool TClientRequest::Reply(void* /*ThreadSpecificResource*/) {
+ if (strnicmp(RequestString.data(), "GET ", 4)) {
+ Output() << "HTTP/1.0 501 Not Implemented\r\n\r\n";
+ } else {
+ Output() << "HTTP/1.0 200 OK\r\n"
+ "Content-Type: text/html\r\n"
+ "\r\n"
+ "Hello World!\r\n";
+ }
+
+ return true;
+}
+
+bool TClientRequest::IsLocal() const {
+ return HasLocalAddress(Socket());
+}
+
+bool TClientRequest::CheckLoopback() {
+ bool isLocal = false;
+
+ try {
+ isLocal = IsLocal();
+ } catch (const yexception& e) {
+ Output() << "HTTP/1.0 500 Oops\r\n\r\n"
+ << e.what() << "\r\n";
+ return false;
+ }
+
+ if (!isLocal) {
+ Output() << "HTTP/1.0 403 Permission denied\r\n"
+ "Content-Type: text/html; charset=windows-1251\r\n"
+ "Connection: close\r\n"
+ "\r\n"
+ "<html><head><title>Permission denied</title></head>"
+ "<body><h1>Permission denied</h1>"
+ "<p>This request must be sent from the localhost.</p>"
+ "</body></html>\r\n";
+
+ return false;
+ }
+
+ return true;
+}
+
+void TClientRequest::ReleaseConnection() {
+ if (Conn_ && HttpConn_ && HttpServ()->Options().KeepAliveEnabled && HttpConn_->CanBeKeepAlive() && (!HttpServ()->Options().RejectExcessConnections || !HttpServ()->MaxRequestsReached())) {
+ Output().Finish();
+ Conn_->DeActivate();
+ Y_UNUSED(Conn_.Release());
+ }
+}
+
+void TClientRequest::ResetConnection() {
+ if (HttpConn_) {
+ // send RST packet to client
+ HttpConn_->Reset();
+ HttpConn_.Destroy();
+ }
+}
+
+void TClientRequest::Process(void* ThreadSpecificResource) {
+ THolder<TClientRequest> this_(this);
+
+ auto* serverImpl = Conn_->HttpServ_;
+
+ try {
+ if (!HttpConn_) {
+ const size_t outputBufferSize = HttpServ()->Options().OutputBufferSize;
+ if (outputBufferSize) {
+ HttpConn_.Reset(new THttpServerConn(Socket(), outputBufferSize));
+ } else {
+ HttpConn_.Reset(new THttpServerConn(Socket()));
+ }
+
+ auto maxRequestsPerConnection = HttpServ()->Options().MaxRequestsPerConnection;
+ HttpConn_->Output()->EnableKeepAlive(HttpServ()->Options().KeepAliveEnabled && (!maxRequestsPerConnection || Conn_->ReceivedRequests < maxRequestsPerConnection));
+ HttpConn_->Output()->EnableCompression(HttpServ()->Options().CompressionEnabled);
+ }
+
+ if (ParsedHeaders.empty()) {
+ RequestString = Input().FirstLine();
+
+ const THttpHeaders& h = Input().Headers();
+ ParsedHeaders.reserve(h.Count());
+ for (THttpHeaders::TConstIterator it = h.Begin(); it != h.End(); ++it) {
+ ParsedHeaders.emplace_back(it->Name(), it->Value());
+ }
+ }
+
+ if (Reply(ThreadSpecificResource)) {
+ ReleaseConnection();
+
+ /*
+ * *this will be destroyed...
+ */
+
+ return;
+ }
+ } catch (...) {
+ serverImpl->Cb_->OnException();
+
+ throw;
+ }
+
+ Y_UNUSED(this_.Release());
+}
+
+void TClientRequest::ProcessFailRequest(int failstate) {
+ Output() << "HTTP/1.1 503 Service Unavailable\r\n"
+ "Content-Type: text/plain\r\n"
+ "Content-Length: 21\r\n"
+ "\r\n"
+ "Service Unavailable\r\n";
+
+ TString url;
+
+ if (!strnicmp(RequestString.data(), "GET ", 4)) {
+ // Trying to extract url...
+ const char* str = RequestString.data();
+
+ // Skipping spaces before url...
+ size_t start = 3;
+ while (str[start] == ' ') {
+ ++start;
+ }
+
+ if (str[start]) {
+ // Traversing url...
+ size_t idx = start;
+
+ while (str[idx] != ' ' && str[idx]) {
+ ++idx;
+ }
+
+ url = RequestString.substr(start, idx - start);
+ }
+ }
+
+ const THttpServer::ICallBack::TFailLogData d = {
+ failstate,
+ url,
+ };
+
+ // Handling failure...
+ Conn_->HttpServ_->Cb_->OnFailRequestEx(d);
+ Output().Flush();
+}
+
+THttpServer* TClientRequest::HttpServ() const noexcept {
+ return Conn_->HttpServ_->Parent_;
+}
+
+const TSocket& TClientRequest::Socket() const noexcept {
+ return Conn_->Socket_;
+}
+
+NAddr::IRemoteAddrRef TClientRequest::GetListenerSockAddrRef() const noexcept {
+ return Conn_->ListenerSockAddrRef_;
+}
+
+TInstant TClientRequest::AcceptMoment() const noexcept {
+ return Conn_->AcceptMoment;
+}
+
+/*
+ * TRequestReplier
+ */
+TRequestReplier::TRequestReplier() {
+}
+
+TRequestReplier::~TRequestReplier() {
+}
+
+bool TRequestReplier::Reply(void* threadSpecificResource) {
+ const TReplyParams params = {
+ threadSpecificResource, Input(), Output()};
+
+ return DoReply(params);
+}
+
+bool TryToBindAddresses(const THttpServerOptions& options, const std::function<void(TSocket)>* callbackOnBoundAddress) {
+ THttpServerOptions::TBindAddresses addrs;
+ try {
+ options.BindAddresses(addrs);
+ } catch (const std::exception&) {
+ return false;
+ }
+
+ for (const auto& na : addrs) {
+ for (TNetworkAddress::TIterator ai = na.Begin(); ai != na.End(); ++ai) {
+ NAddr::TAddrInfo addr(&*ai);
+
+ TSocket socket(::socket(addr.Addr()->sa_family, SOCK_STREAM, 0));
+
+ if (socket == INVALID_SOCKET) {
+ return false;
+ }
+
+ FixIPv6ListenSocket(socket);
+
+ if (options.ReuseAddress) {
+ int yes = 1;
+ ::setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&yes, sizeof(yes));
+ }
+
+ if (options.ReusePort) {
+ SetReusePort(socket, true);
+ }
+
+ if (::bind(socket, addr.Addr(), addr.Len()) == SOCKET_ERROR) {
+ return false;
+ }
+
+ if (::listen(socket, options.ListenBacklog) == SOCKET_ERROR) {
+ return false;
+ }
+
+ if (callbackOnBoundAddress != nullptr) {
+ (*callbackOnBoundAddress)(socket);
+ }
+ }
+ }
+
+ return true;
+}
diff --git a/library/cpp/http/server/http.h b/library/cpp/http/server/http.h
new file mode 100644
index 0000000000..b292d38f27
--- /dev/null
+++ b/library/cpp/http/server/http.h
@@ -0,0 +1,176 @@
+#pragma once
+
+#include "conn.h"
+#include "options.h"
+
+#include <util/thread/pool.h>
+#include <library/cpp/http/io/stream.h>
+#include <util/memory/blob.h>
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+#include <util/system/atomic.h>
+
+class IThreadFactory;
+class TClientRequest;
+class TClientConnection;
+
+class THttpServer {
+ friend class TClientRequest;
+ friend class TClientConnection;
+
+public:
+ class ICallBack {
+ public:
+ struct TFailLogData {
+ int failstate;
+ TString url;
+ };
+
+ virtual ~ICallBack() {
+ }
+
+ virtual void OnFailRequest(int /*failstate*/) {
+ }
+
+ virtual void OnFailRequestEx(const TFailLogData& d) {
+ OnFailRequest(d.failstate);
+ }
+
+ virtual void OnException() {
+ }
+
+ virtual void OnMaxConn() {
+ }
+
+ virtual TClientRequest* CreateClient() = 0;
+
+ virtual void OnListenStart() {
+ }
+
+ virtual void OnListenStop() {
+ }
+
+ virtual void OnWait() {
+ }
+
+ virtual void* CreateThreadSpecificResource() {
+ return nullptr;
+ }
+
+ virtual void DestroyThreadSpecificResource(void*) {
+ }
+ };
+
+ typedef THttpServerOptions TOptions;
+ typedef TSimpleSharedPtr<IThreadPool> TMtpQueueRef;
+
+ THttpServer(ICallBack* cb, const TOptions& options = TOptions(), IThreadFactory* pool = nullptr);
+ THttpServer(ICallBack* cb, TMtpQueueRef mainWorkers, TMtpQueueRef failWorkers, const TOptions& options = TOptions());
+ virtual ~THttpServer();
+
+ bool Start();
+
+ // shutdown a.s.a.p.
+ void Stop();
+
+ // graceful shutdown with serving all already open connections
+ void Shutdown();
+
+ void Wait();
+ int GetErrorCode();
+ const char* GetError();
+ void RestartRequestThreads(ui32 nTh, ui32 maxQS);
+ const TOptions& Options() const noexcept;
+ i64 GetClientCount() const;
+
+ class TImpl;
+ size_t GetRequestQueueSize() const;
+ size_t GetFailQueueSize() const;
+
+ const IThreadPool& GetRequestQueue() const;
+ const IThreadPool& GetFailQueue() const;
+
+ static TAtomicBase AcceptReturnsInvalidSocketCounter();
+
+private:
+ bool MaxRequestsReached() const;
+
+private:
+ THolder<TImpl> Impl_;
+};
+
+/**
+ * @deprecated Use TRequestReplier instead
+ */
+class TClientRequest: public IObjectInQueue {
+ friend class THttpServer::TImpl;
+
+public:
+ TClientRequest();
+ ~TClientRequest() override;
+
+ inline THttpInput& Input() noexcept {
+ return *HttpConn_->Input();
+ }
+
+ inline THttpOutput& Output() noexcept {
+ return *HttpConn_->Output();
+ }
+
+ THttpServer* HttpServ() const noexcept;
+ const TSocket& Socket() const noexcept;
+ NAddr::IRemoteAddrRef GetListenerSockAddrRef() const noexcept;
+ TInstant AcceptMoment() const noexcept;
+
+ bool IsLocal() const;
+ bool CheckLoopback();
+ void ProcessFailRequest(int failstate);
+
+ void ReleaseConnection();
+
+ void ResetConnection();
+
+private:
+ /*
+ * Processes the request after 'connection' been created and 'Headers' been read
+ * Returns 'false' if the processing must be continued by the next handler,
+ * 'true' otherwise ('this' will be deleted)
+ */
+ virtual bool Reply(void* ThreadSpecificResource);
+ void Process(void* ThreadSpecificResource) override;
+
+public:
+ TVector<std::pair<TString, TString>> ParsedHeaders;
+ TString RequestString;
+
+private:
+ THolder<TClientConnection> Conn_;
+ THolder<THttpServerConn> HttpConn_;
+};
+
+class TRequestReplier: public TClientRequest {
+public:
+ TRequestReplier();
+ ~TRequestReplier() override;
+
+ struct TReplyParams {
+ void* ThreadSpecificResource;
+ THttpInput& Input;
+ THttpOutput& Output;
+ };
+
+ /*
+ * Processes the request after 'connection' been created and 'Headers' been read
+ * Returns 'false' if the processing must be continued by the next handler,
+ * 'true' otherwise ('this' will be deleted)
+ */
+ virtual bool DoReply(const TReplyParams& params) = 0;
+
+private:
+ bool Reply(void* threadSpecificResource) final;
+
+ using TClientRequest::Input;
+ using TClientRequest::Output;
+};
+
+bool TryToBindAddresses(const THttpServerOptions& options, const std::function<void(TSocket)>* callbackOnBoundAddress = nullptr);
diff --git a/library/cpp/http/server/http_ex.cpp b/library/cpp/http/server/http_ex.cpp
new file mode 100644
index 0000000000..e07db22bfc
--- /dev/null
+++ b/library/cpp/http/server/http_ex.cpp
@@ -0,0 +1,107 @@
+#include "http_ex.h"
+
+#include <util/generic/buffer.h>
+#include <util/generic/cast.h>
+#include <util/stream/null.h>
+
+bool THttpClientRequestExtension::Parse(char* req, TBaseServerRequestData& rd) {
+ rd.SetSocket(Socket());
+
+ if (!rd.Parse(req)) {
+ Output() << "HTTP/1.1 403 Forbidden\r\n"
+ "Content-Type: text/plain\r\n"
+ "Content-Length: 39\r\n"
+ "\r\n"
+ "The server cannot be used as a proxy.\r\n";
+
+ return false;
+ }
+
+ return true;
+}
+
+bool THttpClientRequestExtension::ProcessHeaders(TBaseServerRequestData& rd, TBlob& postData) {
+ for (const auto& header : ParsedHeaders) {
+ rd.AddHeader(header.first, header.second);
+ }
+
+ char* s = RequestString.begin();
+
+ enum EMethod {
+ NotImplemented,
+ Get,
+ Post,
+ Put,
+ Patch,
+ Delete,
+ };
+
+ enum EMethod foundMethod;
+ char* urlStart;
+
+ if (strnicmp(s, "GET ", 4) == 0) {
+ foundMethod = Get;
+ urlStart = s + 4;
+ } else if (strnicmp(s, "POST ", 5) == 0) {
+ foundMethod = Post;
+ urlStart = s + 5;
+ } else if (strnicmp(s, "PUT ", 4) == 0) {
+ foundMethod = Put;
+ urlStart = s + 4;
+ } else if (strnicmp(s, "PATCH ", 6) == 0) {
+ foundMethod = Patch;
+ urlStart = s + 6;
+ } else if (strnicmp(s, "DELETE ", 7) == 0) {
+ foundMethod = Delete;
+ urlStart = s + 7;
+ } else {
+ foundMethod = NotImplemented;
+ }
+
+ switch (foundMethod) {
+ case Get:
+ case Delete:
+ if (!Parse(urlStart, rd)) {
+ return false;
+ }
+ break;
+
+ case Post:
+ case Put:
+ case Patch:
+ try {
+ ui64 contentLength = 0;
+ if (Input().HasExpect100Continue()) {
+ Output().SendContinue();
+ }
+
+ if (!Input().ContentEncoded() && Input().GetContentLength(contentLength)) {
+ if (contentLength > HttpServ()->Options().MaxInputContentLength) {
+ Output() << "HTTP/1.1 413 Payload Too Large\r\nContent-Length:0\r\n\r\n";
+ Output().Finish();
+ return false;
+ }
+
+ TBuffer buf(SafeIntegerCast<size_t>(contentLength));
+ buf.Resize(Input().Load(buf.Data(), (size_t)contentLength));
+ postData = TBlob::FromBuffer(buf);
+ } else {
+ postData = TBlob::FromStream(Input());
+ }
+ } catch (...) {
+ Output() << "HTTP/1.1 400 Bad request\r\n\r\n";
+ return false;
+ }
+
+ if (!Parse(urlStart, rd)) {
+ return false;
+ }
+ break;
+
+ case NotImplemented:
+ Output() << "HTTP/1.1 501 Not Implemented\r\n\r\n";
+ return false;
+ }
+
+ return true;
+}
diff --git a/library/cpp/http/server/http_ex.h b/library/cpp/http/server/http_ex.h
new file mode 100644
index 0000000000..1ef43ea4fd
--- /dev/null
+++ b/library/cpp/http/server/http_ex.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "http.h"
+
+#include <library/cpp/http/misc/httpreqdata.h>
+
+class THttpClientRequestExtension: public TClientRequest {
+public:
+ bool Parse(char* req, TBaseServerRequestData& rd);
+ bool ProcessHeaders(TBaseServerRequestData& rd, TBlob& postData);
+};
+
+template <class TRequestData>
+class THttpClientRequestExtImpl: public THttpClientRequestExtension {
+protected:
+ bool Parse(char* req) {
+ return THttpClientRequestExtension::Parse(req, RD);
+ }
+ bool ProcessHeaders() {
+ return THttpClientRequestExtension::ProcessHeaders(RD, Buf);
+ }
+
+protected:
+ TRequestData RD;
+ TBlob Buf;
+};
+
+using THttpClientRequestEx = THttpClientRequestExtImpl<TServerRequestData>;
diff --git a/library/cpp/http/server/http_ut.cpp b/library/cpp/http/server/http_ut.cpp
new file mode 100644
index 0000000000..cc62bb988e
--- /dev/null
+++ b/library/cpp/http/server/http_ut.cpp
@@ -0,0 +1,739 @@
+#include "http.h"
+#include "http_ex.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/testing/unittest/tests_data.h>
+
+#include <util/generic/cast.h>
+#include <util/stream/output.h>
+#include <util/stream/zlib.h>
+#include <util/system/datetime.h>
+#include <util/system/sem.h>
+
+Y_UNIT_TEST_SUITE(THttpServerTest) {
+ class TEchoServer: public THttpServer::ICallBack {
+ class TRequest: public THttpClientRequestEx {
+ public:
+ inline TRequest(TEchoServer* parent)
+ : Parent_(parent)
+ {
+ }
+
+ bool Reply(void* /*tsr*/) override {
+ if (!ProcessHeaders()) {
+ return true;
+ }
+
+ Output() << "HTTP/1.1 200 Ok\r\n\r\n";
+ if (Buf.Size()) {
+ Output().Write(Buf.AsCharPtr(), Buf.Size());
+ } else {
+ Output() << Parent_->Res_;
+ }
+ Output().Finish();
+
+ return true;
+ }
+
+ private:
+ TEchoServer* Parent_ = nullptr;
+ };
+
+ public:
+ inline TEchoServer(const TString& res)
+ : Res_(res)
+ {
+ }
+
+ TClientRequest* CreateClient() override {
+ return new TRequest(this);
+ }
+
+ private:
+ TString Res_;
+ };
+
+ class TSleepingServer: public THttpServer::ICallBack {
+ class TReplier: public TRequestReplier {
+ public:
+ inline TReplier(TSleepingServer* server)
+ : Server(server)
+ {
+ }
+
+ bool DoReply(const TReplyParams& params) override {
+ Server->FreeThread();
+ Server->Busy(1);
+ params.Output.Write("HTTP/1.0 201 Created\nX-Server: sleeping server\n\nZoooo");
+ params.Output.Finish();
+ Server->Replies->Inc();
+ return true;
+ }
+
+ private:
+ TSleepingServer* Server = nullptr;
+ };
+
+ public:
+ inline TSleepingServer(unsigned int size)
+ : Semaphore("conns", size)
+ , Semaphore2("threads", 1)
+ , Replies(new TAtomicCounter())
+ , MaxConns(new TAtomicCounter())
+ {
+ }
+
+ void ResetCounters() {
+ Replies.Reset(new TAtomicCounter());
+ MaxConns.Reset(new TAtomicCounter());
+ }
+
+ long RepliesCount() const {
+ return Replies->Val();
+ }
+
+ long MaxConnsCount() const {
+ return MaxConns->Val();
+ }
+
+ TClientRequest* CreateClient() override {
+ return new TReplier(this);
+ }
+
+ void OnMaxConn() override {
+ MaxConns->Inc();
+ }
+
+ void OnFailRequest(int) override {
+ FreeThread();
+ Busy(1);
+ }
+
+ void Busy(int count) {
+ while (count-- > 0) {
+ Semaphore.Acquire();
+ }
+ }
+
+ void BusyThread() {
+ Semaphore2.Acquire();
+ }
+
+ void Free(int count) {
+ while (count-- > 0) {
+ Semaphore.Release();
+ }
+ }
+
+ void FreeThread() {
+ Semaphore2.Release();
+ }
+
+ private:
+ TSemaphore Semaphore;
+ TSemaphore Semaphore2;
+ THolder<TAtomicCounter> Replies;
+ THolder<TAtomicCounter> MaxConns;
+ };
+
+ static const TString CrLf = "\r\n";
+
+ struct TTestRequest {
+ TTestRequest(ui16 port, TString content = TString())
+ : Port(port)
+ , Content(std::move(content))
+ {
+ }
+
+ void CheckContinue(TSocketInput& si) {
+ if (Expect100Continue) {
+ TStringStream ss;
+ TString firstLine;
+ si.ReadLine(firstLine);
+ for (;;) {
+ TString buf;
+ si.ReadLine(buf);
+ if (buf.size() == 0) {
+ break;
+ }
+ ss << buf << CrLf;
+ }
+ UNIT_ASSERT_EQUAL(firstLine, "HTTP/1.1 100 Continue");
+ }
+ }
+
+ TString Execute() {
+ TSocket* s = nullptr;
+ THolder<TSocket> singleReqSocket;
+ if (KeepAliveConnection) {
+ if (!KeepAlivedSocket) {
+ KeepAlivedSocket = MakeHolder<TSocket>(TNetworkAddress("localhost", Port), TDuration::Seconds(10));
+ }
+ s = KeepAlivedSocket.Get();
+ } else {
+ TNetworkAddress addr("localhost", Port);
+ singleReqSocket.Reset(new TSocket(addr, TDuration::Seconds(10)));
+ s = singleReqSocket.Get();
+ }
+ bool isPost = Type == "POST";
+ TSocketInput si(*s);
+
+ if (UseHttpOutput) {
+ TSocketOutput so(*s);
+ THttpOutput output(&so);
+
+ output.EnableKeepAlive(KeepAliveConnection);
+ output.EnableCompression(EnableResponseEncoding);
+
+ TStringStream r;
+ r << Type << " / HTTP/1.1" << CrLf;
+ r << "Host: localhost:" + ToString(Port) << CrLf;
+ if (isPost) {
+ if (ContentEncoding.size()) {
+ r << "Content-Encoding: " << ContentEncoding << CrLf;
+ } else {
+ r << "Transfer-Encoding: chunked" << CrLf;
+ }
+ if (Expect100Continue) {
+ r << "Expect: 100-continue" << CrLf;
+ }
+ }
+
+ r << CrLf;
+ if (isPost) {
+ output.Write(r.Str());
+ output.Flush();
+ CheckContinue(si);
+ output.Write(Content);
+ output.Finish();
+ } else {
+ output.Write(r.Str());
+ output.Finish();
+ }
+ } else {
+ TStringStream r;
+ r << Type << " / HTTP/1.1" << CrLf;
+ r << "Host: localhost:" + ToString(Port) << CrLf;
+ if (KeepAliveConnection) {
+ r << "Connection: Keep-Alive" << CrLf;
+ } else {
+ r << "Connection: Close" << CrLf;
+ }
+ if (EnableResponseEncoding) {
+ r << "Accept-Encoding: gzip, deflate, x-gzip, x-deflate, y-lzo, y-lzf, y-lzq, y-bzip2, y-lzma" << CrLf;
+ }
+ if (isPost && Expect100Continue) {
+ r << "Expect: 100-continue" << CrLf;
+ }
+ if (isPost && ContentEncoding.size() && Content.size()) {
+ r << "Content-Encoding: " << ContentEncoding << CrLf;
+ TStringStream compressedContent;
+ {
+ TZLibCompress zlib(&compressedContent);
+ zlib.Write(Content.data(), Content.size());
+ zlib.Flush();
+ zlib.Finish();
+ }
+ r << "Content-Length: " << compressedContent.Size() << CrLf;
+ r << CrLf;
+ s->Send(r.Data(), r.Size());
+ CheckContinue(si);
+ Hdr = r.Str();
+ TString tosend = compressedContent.Str();
+ s->Send(tosend.data(), tosend.size());
+ } else {
+ if (isPost) {
+ r << "Content-Length: " << Content.size() << CrLf;
+ r << CrLf;
+ s->Send(r.Data(), r.Size());
+ CheckContinue(si);
+ Hdr = r.Str();
+ s->Send(Content.data(), Content.size());
+ } else {
+ r << CrLf;
+ Hdr = r.Str();
+ s->Send(r.Data(), r.Size());
+ }
+ }
+ }
+
+ THttpInput input(&si);
+ TStringStream ss;
+ TransferData(&input, &ss);
+
+ return ss.Str();
+ }
+
+ TString GetDescription() const {
+ if (UseHttpOutput) {
+ TStringStream ss;
+ ss << (KeepAliveConnection ? "keep-alive " : "") << Type;
+ if (ContentEncoding.size()) {
+ ss << " with encoding=" << ContentEncoding;
+ }
+ return ss.Str();
+ } else {
+ return Hdr;
+ }
+ }
+
+ ui16 Port = 0;
+ bool UseHttpOutput = true;
+ TString Type = "GET";
+ TString ContentEncoding;
+ TString Content;
+ bool KeepAliveConnection = false;
+ THolder<TSocket> KeepAlivedSocket;
+ bool EnableResponseEncoding = false;
+ TString Hdr;
+ bool Expect100Continue = false;
+ };
+
+ class TFailingMtpQueue: public TSimpleThreadPool {
+ private:
+ bool FailOnAdd_ = false;
+
+ public:
+ void SetFailOnAdd(bool fail = true) {
+ FailOnAdd_ = fail;
+ }
+ [[nodiscard]] bool Add(IObjectInQueue* pObj) override {
+ if (FailOnAdd_) {
+ return false;
+ }
+
+ return TSimpleThreadPool::Add(pObj);
+ }
+ TFailingMtpQueue() = default;
+ TFailingMtpQueue(IThreadFactory* pool)
+ : TSimpleThreadPool(pool)
+ {
+ }
+ };
+
+ TString TestData(size_t size = 5 * 4096) {
+ TString res;
+
+ for (size_t i = 0; i < size; ++i) {
+ res += (char)i;
+ }
+ return res;
+ }
+
+ Y_UNIT_TEST(TestEchoServer) {
+ TString res = TestData();
+ TPortManager pm;
+ const ui16 port = pm.GetPort();
+ const bool trueFalse[] = {true, false};
+
+ TEchoServer serverImpl(res);
+ THttpServer server(&serverImpl, THttpServer::TOptions(port).EnableKeepAlive(true).EnableCompression(true));
+
+ for (int i = 0; i < 2; ++i) {
+ UNIT_ASSERT(server.Start());
+
+ TTestRequest r(port);
+ r.Content = res;
+
+ for (bool keepAlive : trueFalse) {
+ r.KeepAliveConnection = keepAlive;
+
+ // THttpOutput use chunked stream, else use Content-Length
+ for (bool useHttpOutput : trueFalse) {
+ r.UseHttpOutput = useHttpOutput;
+
+ for (bool enableResponseEncoding : trueFalse) {
+ r.EnableResponseEncoding = enableResponseEncoding;
+
+ const TString reqTypes[] = {"GET", "POST"};
+ for (const TString& reqType : reqTypes) {
+ r.Type = reqType;
+
+ const TString encoders[] = {"", "deflate"};
+ for (const TString& encoder : encoders) {
+ r.ContentEncoding = encoder;
+
+ for (bool expect100Continue : trueFalse) {
+ r.Expect100Continue = expect100Continue;
+ TString resp = r.Execute();
+ UNIT_ASSERT_C(resp == res, "diff echo response for request:\n" + r.GetDescription());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ server.Stop();
+ }
+ }
+
+ Y_UNIT_TEST(TestReusePortEnabled) {
+ if (!IsReusePortAvailable()) {
+ return; // skip test
+ }
+ TString res = TestData();
+ TPortManager pm;
+ const ui16 port = pm.GetPort();
+
+ TEchoServer serverImpl(res);
+ TVector<THolder<THttpServer>> servers;
+ for (ui32 i = 0; i < 10; i++) {
+ servers.push_back(MakeHolder<THttpServer>(&serverImpl, THttpServer::TOptions(port).EnableReusePort(true)));
+ }
+
+ for (ui32 testRun = 0; testRun < 3; testRun++) {
+ for (auto& server : servers) {
+ // start servers one at a time and check at least one of them is replying
+ UNIT_ASSERT(server->Start());
+
+ TTestRequest r(port, res);
+ UNIT_ASSERT_C(r.Execute() == res, "diff echo response for request:\n" + r.GetDescription());
+ }
+
+ for (auto& server : servers) {
+ // ping servers and stop them one at a time
+ // at the last iteration only one server is still working and then gets stopped as well
+
+ TTestRequest r(port, res);
+ UNIT_ASSERT_C(r.Execute() == res, "diff echo response for request:\n" + r.GetDescription());
+
+ server->Stop();
+ }
+ }
+ }
+
+ Y_UNIT_TEST(TestReusePortDisabled) {
+ // check that with the ReusePort option disabled it's impossible to start two servers on the same port
+ // check that ReusePort option is disabled by default (don't set it explicitly in the test)
+ TPortManager pm;
+ const ui16 port = pm.GetPort();
+
+ TEchoServer serverImpl(TString{});
+ THttpServer server1(&serverImpl, THttpServer::TOptions(port));
+ THttpServer server2(&serverImpl, THttpServer::TOptions(port));
+
+ UNIT_ASSERT(true == server1.Start());
+ UNIT_ASSERT(false == server2.Start());
+
+ server1.Stop();
+ // Stop() is a sync call, port should be free by now
+ UNIT_ASSERT(true == server2.Start());
+ UNIT_ASSERT(false == server1.Start());
+ }
+
+ Y_UNIT_TEST(TestFailServer) {
+ /**
+ * Emulate request processing failures
+ * Data should be large enough not to fit into socket buffer
+ **/
+ TString res = TestData(10 * 1024 * 1024);
+ TPortManager portManager;
+ const ui16 port = portManager.GetPort();
+ TEchoServer serverImpl(res);
+ THttpServer::TOptions options(port);
+ options.EnableKeepAlive(true);
+ options.EnableCompression(true);
+ using TFailingServerMtpQueue = TThreadPoolBinder<TFailingMtpQueue, THttpServer::ICallBack>;
+ THttpServer::TMtpQueueRef mainWorkers = new TFailingServerMtpQueue(&serverImpl, SystemThreadFactory());
+ THttpServer::TMtpQueueRef failWorkers = new TThreadPool(SystemThreadFactory());
+ THttpServer server(&serverImpl, mainWorkers, failWorkers, options);
+
+ UNIT_ASSERT(server.Start());
+ for (size_t i = 0; i < 3; ++i) {
+ // should fail on 2nd request
+ static_cast<TFailingMtpQueue*>(mainWorkers.Get())->SetFailOnAdd(i == 1);
+ TTestRequest r(port);
+ r.Content = res;
+ r.Type = "POST";
+ TString resp = r.Execute();
+ if (i == 1) {
+ UNIT_ASSERT(resp.Contains("Service Unavailable"));
+ } else {
+ UNIT_ASSERT_C(resp == res, "diff echo response for request:\n" + r.GetDescription());
+ }
+ }
+ server.Stop();
+ }
+
+ class TReleaseConnectionServer: public THttpServer::ICallBack {
+ class TRequest: public THttpClientRequestEx {
+ public:
+ bool Reply(void* /*tsr*/) override {
+ Output() << "HTTP/1.1 200 Ok\r\n\r\n";
+ Output() << "reply";
+ Output().Finish();
+
+ ReleaseConnection();
+
+ throw yexception() << "some error";
+
+ return true;
+ }
+ };
+
+ public:
+ TClientRequest* CreateClient() override {
+ return new TRequest();
+ }
+
+ void OnException() override {
+ ExceptionMessage = CurrentExceptionMessage();
+ }
+
+ TString ExceptionMessage;
+ };
+
+ class TResetConnectionServer: public THttpServer::ICallBack {
+ class TRequest: public TClientRequest {
+ public:
+ bool Reply(void* /*tsr*/) override {
+ Output() << "HTTP/1.1";
+ ResetConnection();
+
+ return true;
+ }
+ };
+
+ public:
+ TClientRequest* CreateClient() override {
+ return new TRequest();
+ }
+
+ void OnException() override {
+ ExceptionMessage = CurrentExceptionMessage();
+ }
+
+ TString ExceptionMessage;
+ };
+
+ class TListenerSockAddrReplyServer: public THttpServer::ICallBack {
+ class TRequest: public TClientRequest {
+ public:
+ bool Reply(void* /*tsr*/) override {
+ Output() << "HTTP/1.1 200 Ok\r\n\r\n";
+ Output() << PrintHostAndPort(*GetListenerSockAddrRef());
+
+ Output().Finish();
+
+ return true;
+ }
+ };
+
+ public:
+ TClientRequest* CreateClient() override {
+ return new TRequest();
+ }
+ };
+
+ Y_UNIT_TEST(TTestResetConnection) {
+ TPortManager pm;
+ const ui16 port = pm.GetPort();
+
+ TResetConnectionServer serverImpl;
+ THttpServer server(&serverImpl, THttpServer::TOptions(port));
+ UNIT_ASSERT(server.Start());
+
+ TTestRequest r(port, "request");
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(r.Execute(), TSystemError, "Connection reset by peer");
+
+ server.Stop();
+ };
+
+ Y_UNIT_TEST(TTestReleaseConnection) {
+ TPortManager pm;
+ const ui16 port = pm.GetPort();
+
+ TReleaseConnectionServer serverImpl;
+ THttpServer server(&serverImpl, THttpServer::TOptions(port).EnableKeepAlive(true));
+ UNIT_ASSERT(server.Start());
+
+ TTestRequest r(port, "request");
+ r.KeepAliveConnection = true;
+
+ UNIT_ASSERT_C(r.Execute() == "reply", "diff echo response for request:\n" + r.GetDescription());
+
+ server.Stop();
+
+ UNIT_ASSERT_STRINGS_EQUAL(serverImpl.ExceptionMessage, "(yexception) some error");
+ };
+
+ THttpInput SendRequest(TSocket& socket, ui16 port) {
+ TSocketInput si(socket);
+ TSocketOutput so(socket);
+ THttpOutput out(&so);
+ out.EnableKeepAlive(true);
+ out << "GET / HTTP/1.1" << CrLf;
+ out << "Host: localhost:" + ToString(port) << CrLf;
+ out << CrLf;
+ out.Flush();
+
+ THttpInput input(&si);
+ input.ReadAll();
+ return input;
+ }
+
+ THttpInput SendRequestWithBody(TSocket& socket, ui16 port, TString body) {
+ TSocketInput si(socket);
+ TSocketOutput so(socket);
+ THttpOutput out(&so);
+ out << "POST / HTTP/1.1" << CrLf;
+ out << "Host: localhost:" + ToString(port) << CrLf;
+ out << "Content-Length: " + ToString(body.size()) << CrLf;
+ out << CrLf;
+ out << body;
+ out.Flush();
+
+ THttpInput input(&si);
+ input.ReadAll();
+ return input;
+ }
+
+ Y_UNIT_TEST(TTestExpirationTimeout) {
+ TPortManager pm;
+ const ui16 port = pm.GetPort();
+
+ TEchoServer serverImpl("test_data");
+ THttpServer::TOptions options(port);
+ options.nThreads = 1;
+ options.MaxQueueSize = 0;
+ options.MaxConnections = 0;
+ options.KeepAliveEnabled = true;
+ options.ExpirationTimeout = TDuration::Seconds(1);
+ options.PollTimeout = TDuration::MilliSeconds(100);
+ THttpServer server(&serverImpl, options);
+ UNIT_ASSERT(server.Start());
+
+ TSocket socket(TNetworkAddress("localhost", port), TDuration::Seconds(10));
+
+ SendRequest(socket, port);
+ SendRequest(socket, port);
+
+ Sleep(TDuration::Seconds(5));
+ UNIT_ASSERT_EXCEPTION(SendRequest(socket, port), THttpReadException);
+
+ server.Stop();
+ }
+
+ Y_UNIT_TEST(TTestContentLengthTooLarge) {
+ TPortManager pm;
+ const ui16 port = pm.GetPort();
+
+ TEchoServer serverImpl("test_data");
+ THttpServer::TOptions options(port);
+ options.nThreads = 1;
+ options.MaxQueueSize = 0;
+ options.MaxInputContentLength = 2_KB;
+ options.MaxConnections = 0;
+ options.KeepAliveEnabled = false;
+ options.ExpirationTimeout = TDuration::Seconds(1);
+ options.PollTimeout = TDuration::MilliSeconds(100);
+ THttpServer server(&serverImpl, options);
+ UNIT_ASSERT(server.Start());
+
+ TSocket socket(TNetworkAddress("localhost", port), TDuration::Seconds(5));
+ UNIT_ASSERT_STRING_CONTAINS(SendRequestWithBody(socket, port, TString(1_KB, 'a')).FirstLine(), "HTTP/1.1 200 Ok");
+
+ TSocket socket2(TNetworkAddress("localhost", port), TDuration::Seconds(5));
+ UNIT_ASSERT_STRING_CONTAINS(SendRequestWithBody(socket2, port, TString(10_KB, 'a')).FirstLine(), "HTTP/1.1 413 Payload Too Large");
+
+ server.Stop();
+ }
+
+
+ Y_UNIT_TEST(TTestCloseConnectionOnRequestLimit) {
+ TPortManager pm;
+ const ui16 port = pm.GetPort();
+
+ TEchoServer serverImpl("test_data");
+ THttpServer server(&serverImpl, THttpServer::TOptions(port).EnableKeepAlive(true).SetMaxRequestsPerConnection(2));
+ UNIT_ASSERT(server.Start());
+
+ TSocket socket(TNetworkAddress("localhost", port), TDuration::Seconds(10));
+
+ UNIT_ASSERT(SendRequest(socket, port).IsKeepAlive());
+ UNIT_ASSERT(!SendRequest(socket, port).IsKeepAlive());
+
+ UNIT_ASSERT_EXCEPTION(SendRequest(socket, port), THttpReadException);
+
+ server.Stop();
+ }
+
+ Y_UNIT_TEST(TTestListenerSockAddrConnection) {
+ TPortManager pm;
+ const ui16 port1 = pm.GetPort();
+ const ui16 port2 = pm.GetPort();
+
+ TListenerSockAddrReplyServer serverImpl;
+ THttpServer server(&serverImpl, THttpServer::TOptions().EnableKeepAlive(true).AddBindAddress("127.0.0.1", port1).AddBindAddress("127.0.0.1", port2));
+ UNIT_ASSERT(server.Start());
+
+ TTestRequest r1(port1);
+ r1.KeepAliveConnection = true;
+
+ TString resp = r1.Execute();
+ UNIT_ASSERT(resp == TString::Join("127.0.0.1", ":", ToString(port1)));
+
+ TTestRequest r2(port2);
+ r2.KeepAliveConnection = true;
+
+ resp = r2.Execute();
+ UNIT_ASSERT(resp == TString::Join("127.0.0.1", ":", ToString(port2)));
+
+ server.Stop();
+ };
+
+#if 0
+ Y_UNIT_TEST(TestSocketsLeak) {
+ const bool trueFalse[] = {true, false};
+ TPortManager portManager;
+ const ui16 port = portManager.GetPort();
+ TString res = TestData(25);
+ TSleepingServer server(3);
+ THttpServer::TOptions options(port);
+ options.MaxConnections = 1;
+ options.MaxQueueSize = 1;
+ options.MaxFQueueSize = 2;
+ options.nFThreads = 2;
+ options.KeepAliveEnabled = true;
+ options.RejectExcessConnections = true;
+ THttpServer srv(&server, options);
+ UNIT_ASSERT(srv.Start());
+
+ for (bool keepAlive : trueFalse) {
+ server.ResetCounters();
+ TVector<TAutoPtr<IThreadFactory::IThread>> threads;
+
+ server.Busy(3);
+ server.BusyThread();
+
+ for (size_t i = 0; i < 3; ++i) {
+ auto func = [&server, port, keepAlive]() {
+ server.BusyThread();
+ THolder<TTestRequest> r = MakeHolder<TTestRequest>(port);
+ r->KeepAliveConnection = keepAlive;
+ r->Execute();
+ };
+ threads.push_back(SystemThreadFactory()->Run(func));
+ }
+
+ server.FreeThread(); // all threads get connection & go to processing
+ Sleep(TDuration::MilliSeconds(100));
+ server.BusyThread(); // we wait while connections are established by the
+ // system and accepted by the server
+ server.Free(3); // we release all connections processing
+
+ for (auto&& thread : threads) {
+ thread->Join();
+ }
+
+ server.Free(3);
+ server.FreeThread();
+
+ UNIT_ASSERT_EQUAL_C(server.MaxConnsCount(), 2, "we should get MaxConn notification 2 times, got " + ToString(server.MaxConnsCount()));
+ UNIT_ASSERT_EQUAL_C(server.RepliesCount(), 1, "only one request should have been processed, got " + ToString(server.RepliesCount()));
+ }
+ }
+#endif
+}
diff --git a/library/cpp/http/server/options.cpp b/library/cpp/http/server/options.cpp
new file mode 100644
index 0000000000..05c954384a
--- /dev/null
+++ b/library/cpp/http/server/options.cpp
@@ -0,0 +1,43 @@
+#include "options.h"
+
+#include <util/string/cast.h>
+#include <util/digest/numeric.h>
+#include <util/network/ip.h>
+#include <util/network/socket.h>
+#include <util/generic/hash_set.h>
+#include <util/generic/yexception.h>
+
+using TAddr = THttpServerOptions::TAddr;
+
+static inline TString AddrToString(const TAddr& addr) {
+ return addr.Addr + ":" + ToString(addr.Port);
+}
+
+static inline TNetworkAddress ToNetworkAddr(const TString& address, ui16 port) {
+ if (address.empty() || address == TStringBuf("*")) {
+ return TNetworkAddress(port);
+ }
+
+ return TNetworkAddress(address, port);
+}
+
+void THttpServerOptions::BindAddresses(TBindAddresses& ret) const {
+ THashSet<TString> check;
+
+ for (auto addr : BindSockaddr) {
+ if (!addr.Port) {
+ addr.Port = Port;
+ }
+
+ const TString straddr = AddrToString(addr);
+
+ if (check.find(straddr) == check.end()) {
+ check.insert(straddr);
+ ret.push_back(ToNetworkAddr(addr.Addr, addr.Port));
+ }
+ }
+
+ if (ret.empty()) {
+ ret.push_back(Host ? TNetworkAddress(Host, Port) : TNetworkAddress(Port));
+ }
+}
diff --git a/library/cpp/http/server/options.h b/library/cpp/http/server/options.h
new file mode 100644
index 0000000000..38eda0e5e7
--- /dev/null
+++ b/library/cpp/http/server/options.h
@@ -0,0 +1,176 @@
+#pragma once
+
+#include <util/network/ip.h>
+#include <util/network/init.h>
+#include <util/network/address.h>
+#include <util/generic/size_literals.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/datetime/base.h>
+
+class THttpServerOptions {
+public:
+ inline THttpServerOptions(ui16 port = 17000) noexcept
+ : Port(port)
+ {
+ }
+
+ using TBindAddresses = TVector<TNetworkAddress>;
+ void BindAddresses(TBindAddresses& ret) const;
+
+ inline THttpServerOptions& AddBindAddress(const TString& address, ui16 port) {
+ const TAddr addr = {
+ address,
+ port,
+ };
+
+ BindSockaddr.push_back(addr);
+ return *this;
+ }
+
+ inline THttpServerOptions& AddBindAddress(const TString& address) {
+ return AddBindAddress(address, 0);
+ }
+
+ inline THttpServerOptions& EnableKeepAlive(bool enable) noexcept {
+ KeepAliveEnabled = enable;
+
+ return *this;
+ }
+
+ inline THttpServerOptions& EnableCompression(bool enable) noexcept {
+ CompressionEnabled = enable;
+
+ return *this;
+ }
+
+ inline THttpServerOptions& EnableRejectExcessConnections(bool enable) noexcept {
+ RejectExcessConnections = enable;
+
+ return *this;
+ }
+
+ inline THttpServerOptions& EnableReusePort(bool enable) noexcept {
+ ReusePort = enable;
+
+ return *this;
+ }
+
+ inline THttpServerOptions& EnableReuseAddress(bool enable) noexcept {
+ ReuseAddress = enable;
+
+ return *this;
+ }
+
+ inline THttpServerOptions& SetThreads(ui32 threads) noexcept {
+ nThreads = threads;
+
+ return *this;
+ }
+
+ /// Default interface name to bind the server. Used when none of BindAddress are provided.
+ inline THttpServerOptions& SetHost(const TString& host) noexcept {
+ Host = host;
+
+ return *this;
+ }
+
+ /// Default port to bind the server. Used when none of BindAddress are provided.
+ inline THttpServerOptions& SetPort(ui16 port) noexcept {
+ Port = port;
+
+ return *this;
+ }
+
+ inline THttpServerOptions& SetMaxConnections(ui32 mc = 0) noexcept {
+ MaxConnections = mc;
+
+ return *this;
+ }
+
+ inline THttpServerOptions& SetMaxQueueSize(ui32 mqs = 0) noexcept {
+ MaxQueueSize = mqs;
+
+ return *this;
+ }
+
+ inline THttpServerOptions& SetClientTimeout(const TDuration& timeout) noexcept {
+ ClientTimeout = timeout;
+
+ return *this;
+ }
+
+ inline THttpServerOptions& SetListenBacklog(int val) noexcept {
+ ListenBacklog = val;
+
+ return *this;
+ }
+
+ inline THttpServerOptions& SetOutputBufferSize(size_t val) noexcept {
+ OutputBufferSize = val;
+
+ return *this;
+ }
+
+ inline THttpServerOptions& SetMaxInputContentLength(ui64 val) noexcept {
+ MaxInputContentLength = val;
+
+ return *this;
+ }
+
+ inline THttpServerOptions& SetMaxRequestsPerConnection(size_t val) noexcept {
+ MaxRequestsPerConnection = val;
+
+ return *this;
+ }
+
+ /// Use TElasticQueue instead of TThreadPool for request queues
+ inline THttpServerOptions& EnableElasticQueues(bool enable) noexcept {
+ UseElasticQueues = enable;
+
+ return *this;
+ }
+
+ inline THttpServerOptions& SetThreadsName(const TString& listenThreadName, const TString& requestsThreadName, const TString& failRequestsThreadName) noexcept {
+ ListenThreadName = listenThreadName;
+ RequestsThreadName = requestsThreadName;
+ FailRequestsThreadName = failRequestsThreadName;
+
+ return *this;
+ }
+
+ struct TAddr {
+ TString Addr;
+ ui16 Port;
+ };
+
+ typedef TVector<TAddr> TAddrs;
+
+ bool KeepAliveEnabled = true;
+ bool CompressionEnabled = false;
+ bool RejectExcessConnections = false;
+ bool ReusePort = false; // set SO_REUSEPORT socket option
+ bool ReuseAddress = true; // set SO_REUSEADDR socket option
+ TAddrs BindSockaddr;
+ ui16 Port = 17000; // The port on which to run the web server
+ TString Host; // DNS entry
+ const char* ServerName = "YWS/1.0"; // The Web server name to return in HTTP headers
+ ui32 nThreads = 0; // Thread count for requests processing
+ ui32 MaxQueueSize = 0; // Max allowed request count in queue
+ ui32 nFThreads = 1;
+ ui32 MaxFQueueSize = 0;
+ ui32 MaxConnections = 100;
+ int ListenBacklog = SOMAXCONN;
+ TDuration ClientTimeout;
+ size_t OutputBufferSize = 0;
+ ui64 MaxInputContentLength = sizeof(size_t) <= 4 ? 2_GB : 64_GB;
+ size_t MaxRequestsPerConnection = 0; // If keep-alive is enabled, request limit before connection is closed
+ bool UseElasticQueues = false;
+
+ TDuration PollTimeout; // timeout of TSocketPoller::WaitT call
+ TDuration ExpirationTimeout; // drop inactive connections after ExpirationTimeout (should be > 0)
+
+ TString ListenThreadName = "HttpListen";
+ TString RequestsThreadName = "HttpServer";
+ TString FailRequestsThreadName = "HttpServer";
+};
diff --git a/library/cpp/http/server/response.cpp b/library/cpp/http/server/response.cpp
new file mode 100644
index 0000000000..52d64c91ce
--- /dev/null
+++ b/library/cpp/http/server/response.cpp
@@ -0,0 +1,65 @@
+#include "response.h"
+
+#include <util/stream/output.h>
+#include <util/stream/mem.h>
+#include <util/string/cast.h>
+
+THttpResponse& THttpResponse::AddMultipleHeaders(const THttpHeaders& headers) {
+ for (THttpHeaders::TConstIterator i = headers.Begin(); i != headers.End(); ++i) {
+ this->Headers.AddHeader(*i);
+ }
+ return *this;
+}
+
+THttpResponse& THttpResponse::SetContentType(const TStringBuf& contentType) {
+ Headers.AddOrReplaceHeader(THttpInputHeader("Content-Type", ToString(contentType)));
+
+ return *this;
+}
+
+void THttpResponse::OutTo(IOutputStream& os) const {
+ TVector<IOutputStream::TPart> parts;
+ const size_t FIRST_LINE_PARTS = 3;
+ const size_t HEADERS_PARTS = Headers.Count() * 4;
+ const size_t CONTENT_PARTS = 5;
+ parts.reserve(FIRST_LINE_PARTS + HEADERS_PARTS + CONTENT_PARTS);
+
+ // first line
+ parts.push_back(IOutputStream::TPart(TStringBuf("HTTP/1.1 ")));
+ parts.push_back(IOutputStream::TPart(HttpCodeStrEx(Code)));
+ parts.push_back(IOutputStream::TPart::CrLf());
+
+ // headers
+ for (THttpHeaders::TConstIterator i = Headers.Begin(); i != Headers.End(); ++i) {
+ parts.push_back(IOutputStream::TPart(i->Name()));
+ parts.push_back(IOutputStream::TPart(TStringBuf(": ")));
+ parts.push_back(IOutputStream::TPart(i->Value()));
+ parts.push_back(IOutputStream::TPart::CrLf());
+ }
+
+ char buf[50];
+
+ if (!Content.empty()) {
+ TMemoryOutput mo(buf, sizeof(buf));
+
+ mo << Content.size();
+
+ parts.push_back(IOutputStream::TPart(TStringBuf("Content-Length: ")));
+ parts.push_back(IOutputStream::TPart(buf, mo.Buf() - buf));
+ parts.push_back(IOutputStream::TPart::CrLf());
+ }
+
+ // content
+ parts.push_back(IOutputStream::TPart::CrLf());
+
+ if (!Content.empty()) {
+ parts.push_back(IOutputStream::TPart(Content));
+ }
+
+ os.Write(parts.data(), parts.size());
+}
+
+template <>
+void Out<THttpResponse>(IOutputStream& os, const THttpResponse& resp) {
+ resp.OutTo(os);
+}
diff --git a/library/cpp/http/server/response.h b/library/cpp/http/server/response.h
new file mode 100644
index 0000000000..a75cb85605
--- /dev/null
+++ b/library/cpp/http/server/response.h
@@ -0,0 +1,82 @@
+#pragma once
+
+#include <library/cpp/http/misc/httpcodes.h>
+#include <library/cpp/http/io/stream.h>
+
+#include <util/generic/strbuf.h>
+#include <util/string/cast.h>
+
+class THttpHeaders;
+class IOutputStream;
+
+class THttpResponse {
+public:
+ THttpResponse() noexcept
+ : Code(HTTP_OK)
+ {
+ }
+
+ explicit THttpResponse(HttpCodes code) noexcept
+ : Code(code)
+ {
+ }
+
+ template <typename ValueType>
+ THttpResponse& AddHeader(const TString& name, const ValueType& value) {
+ return AddHeader(THttpInputHeader(name, ToString(value)));
+ }
+
+ THttpResponse& AddHeader(const THttpInputHeader& header) {
+ Headers.AddHeader(header);
+
+ return *this;
+ }
+
+ THttpResponse& AddMultipleHeaders(const THttpHeaders& headers);
+
+ const THttpHeaders& GetHeaders() const {
+ return Headers;
+ }
+
+ THttpResponse& SetContentType(const TStringBuf& contentType);
+
+ /**
+ * @note If @arg content isn't empty its size is automatically added as a
+ * "Content-Length" header during output to IOutputStream.
+ * @see IOutputStream& operator << (IOutputStream&, const THttpResponse&)
+ */
+ THttpResponse& SetContent(const TString& content) {
+ Content = content;
+
+ return *this;
+ }
+
+ TString GetContent() const {
+ return Content;
+ }
+
+ /**
+ * @note If @arg content isn't empty its size is automatically added as a
+ * "Content-Length" header during output to IOutputStream.
+ * @see IOutputStream& operator << (IOutputStream&, const THttpResponse&)
+ */
+ THttpResponse& SetContent(const TString& content, const TStringBuf& contentType) {
+ return SetContent(content).SetContentType(contentType);
+ }
+
+ HttpCodes HttpCode() const {
+ return Code;
+ }
+
+ THttpResponse& SetHttpCode(HttpCodes code) {
+ Code = code;
+ return *this;
+ }
+
+ void OutTo(IOutputStream& out) const;
+
+private:
+ HttpCodes Code;
+ THttpHeaders Headers;
+ TString Content;
+};
diff --git a/library/cpp/http/server/response_ut.cpp b/library/cpp/http/server/response_ut.cpp
new file mode 100644
index 0000000000..73e2112ad3
--- /dev/null
+++ b/library/cpp/http/server/response_ut.cpp
@@ -0,0 +1,142 @@
+#include "response.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/string/cast.h>
+
+Y_UNIT_TEST_SUITE(TestHttpResponse) {
+ Y_UNIT_TEST(TestCodeOnly) {
+ UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse()), "HTTP/1.1 200 Ok\r\n\r\n");
+ UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse(HTTP_NOT_FOUND)), "HTTP/1.1 404 Not found\r\n\r\n");
+ }
+
+ Y_UNIT_TEST(TestRedirect) {
+ THttpResponse resp = THttpResponse(HTTP_FOUND).AddHeader("Location", "yandex.ru");
+ UNIT_ASSERT_STRINGS_EQUAL(ToString(resp), "HTTP/1.1 302 Moved temporarily\r\n"
+ "Location: yandex.ru\r\n"
+ "\r\n");
+ }
+
+ Y_UNIT_TEST(TestAddHeader) {
+ THttpResponse resp(HTTP_FORBIDDEN);
+ resp.AddHeader(THttpInputHeader("X-Header-1", "ValueOne"));
+ resp.AddHeader("X-Header-2", 10);
+ resp.AddHeader("X-Header-3", true);
+
+ const char* EXPECTED = "HTTP/1.1 403 Forbidden\r\n"
+ "X-Header-1: ValueOne\r\n"
+ "X-Header-2: 10\r\n"
+ "X-Header-3: 1\r\n"
+ "\r\n";
+ UNIT_ASSERT_STRINGS_EQUAL(ToString(resp), EXPECTED);
+ }
+
+ Y_UNIT_TEST(TestAddMultipleHeaders) {
+ THttpHeaders headers;
+ headers.AddHeader(THttpInputHeader("X-Header-1", "ValueOne"));
+ headers.AddHeader(THttpInputHeader("X-Header-2", "ValueTwo"));
+ headers.AddHeader(THttpInputHeader("X-Header-3", "ValueThree"));
+
+ const char* EXPECTED = "HTTP/1.1 403 Forbidden\r\n"
+ "X-Header-1: ValueOne\r\n"
+ "X-Header-2: ValueTwo\r\n"
+ "X-Header-3: ValueThree\r\n"
+ "\r\n";
+ UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse(HTTP_FORBIDDEN).AddMultipleHeaders(headers)),
+ EXPECTED);
+ }
+
+ Y_UNIT_TEST(TestGetHeaders) {
+ THttpResponse resp(HTTP_FORBIDDEN);
+
+ THttpHeaders headers;
+ headers.AddHeader(THttpInputHeader("X-Header-1", "ValueOne"));
+ headers.AddHeader(THttpInputHeader("X-Header-2", "ValueTwo"));
+ headers.AddHeader(THttpInputHeader("X-Header-3", "ValueThree"));
+ resp.AddMultipleHeaders(headers);
+ resp.AddHeader("X-Header-4", "ValueFour");
+
+ const THttpHeaders& gotHeaders = resp.GetHeaders();
+ UNIT_ASSERT_VALUES_EQUAL(gotHeaders.Count(), 4);
+ UNIT_ASSERT(gotHeaders.HasHeader("X-Header-1"));
+ UNIT_ASSERT_STRINGS_EQUAL(gotHeaders.FindHeader("X-Header-1")->Value(), "ValueOne");
+ UNIT_ASSERT(gotHeaders.HasHeader("X-Header-4"));
+ UNIT_ASSERT_STRINGS_EQUAL(gotHeaders.FindHeader("X-Header-4")->Value(), "ValueFour");
+ }
+
+
+ Y_UNIT_TEST(TestSetContent) {
+ const char* EXPECTED = "HTTP/1.1 200 Ok\r\n"
+ "Content-Length: 10\r\n"
+ "\r\n"
+ "0123456789";
+ UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse().SetContent("0123456789")),
+ EXPECTED);
+ }
+
+ Y_UNIT_TEST(TestSetContentWithContentType) {
+ const char* EXPECTED = "HTTP/1.1 200 Ok\r\n"
+ "Content-Type: text/xml\r\n"
+ "Content-Length: 28\r\n"
+ "\r\n"
+ "<xml><tag value=\"1\" /></xml>";
+ THttpResponse resp;
+ resp.SetContent("<xml><tag value=\"1\" /></xml>").SetContentType("text/xml");
+ UNIT_ASSERT_STRINGS_EQUAL(ToString(resp), EXPECTED);
+ }
+
+ Y_UNIT_TEST(TestCopyConstructor) {
+ THttpResponse resp(HTTP_FORBIDDEN);
+ resp.AddHeader(THttpInputHeader("X-Header-1", "ValueOne"))
+ .AddHeader("X-Header-2", "ValueTwo")
+ .AddHeader(THttpInputHeader("X-Header-3", "ValueThree"))
+ .SetContent("Some stuff")
+ .SetContentType("text/plain");
+
+ THttpResponse copy = resp;
+ UNIT_ASSERT_STRINGS_EQUAL(ToString(copy), ToString(resp));
+ }
+
+ Y_UNIT_TEST(TestAssignment) {
+ THttpResponse resp(HTTP_FORBIDDEN);
+ resp.AddHeader(THttpInputHeader("X-Header-1", "ValueOne"));
+ resp.AddHeader(THttpInputHeader("X-Header-2", "ValueTwo"));
+ resp.AddHeader(THttpInputHeader("X-Header-3", "ValueThree"));
+ resp.SetContent("Some stuff").SetContentType("text/plain");
+
+ THttpResponse copy;
+ copy = resp;
+ UNIT_ASSERT_STRINGS_EQUAL(ToString(copy), ToString(resp));
+ }
+
+ Y_UNIT_TEST(TestEmptyContent) {
+ UNIT_ASSERT_STRINGS_EQUAL(ToString(THttpResponse().SetContent("")), "HTTP/1.1 200 Ok\r\n\r\n");
+ }
+
+ Y_UNIT_TEST(TestReturnReference) {
+ THttpResponse resp;
+ UNIT_ASSERT_EQUAL(&resp, &resp.AddHeader("Header1", 1));
+ UNIT_ASSERT_EQUAL(&resp, &resp.AddHeader(THttpInputHeader("Header2", "2")));
+
+ THttpHeaders headers;
+ headers.AddHeader(THttpInputHeader("Header3", "3"));
+ headers.AddHeader(THttpInputHeader("Header4", "4"));
+ UNIT_ASSERT_EQUAL(&resp, &resp.AddMultipleHeaders(headers));
+
+ UNIT_ASSERT_EQUAL(&resp, &resp.SetContent("some stuff"));
+ UNIT_ASSERT_EQUAL(&resp, &resp.SetContent("some other stuff").SetContentType("text/plain"));
+ }
+
+ Y_UNIT_TEST(TestSetContentType) {
+ const char* EXPECTED = "HTTP/1.1 200 Ok\r\n"
+ "Content-Type: text/xml\r\n"
+ "Content-Length: 28\r\n"
+ "\r\n"
+ "<xml><tag value=\"1\" /></xml>";
+ THttpResponse resp;
+ resp.SetContent("<xml><tag value=\"1\" /></xml>")
+ .SetContentType("application/json")
+ .SetContentType("text/xml");
+ UNIT_ASSERT_STRINGS_EQUAL(ToString(resp), EXPECTED);
+ }
+}
diff --git a/library/cpp/http/server/ut/ya.make b/library/cpp/http/server/ut/ya.make
new file mode 100644
index 0000000000..bcb4d4c0b8
--- /dev/null
+++ b/library/cpp/http/server/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/http/server)
+
+OWNER(pg)
+
+SIZE(MEDIUM)
+
+SRCS(
+ http_ut.cpp
+ response_ut.cpp
+)
+
+END()
diff --git a/library/cpp/http/server/ya.make b/library/cpp/http/server/ya.make
new file mode 100644
index 0000000000..bae6f33306
--- /dev/null
+++ b/library/cpp/http/server/ya.make
@@ -0,0 +1,27 @@
+LIBRARY()
+
+OWNER(
+ pg
+ mvel
+ kulikov
+ g:base
+ g:middle
+)
+
+SRCS(
+ conn.cpp
+ http.cpp
+ http_ex.cpp
+ options.cpp
+ response.cpp
+)
+
+PEERDIR(
+ library/cpp/http/misc
+ library/cpp/http/io
+ library/cpp/threading/equeue
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/http/ya.make b/library/cpp/http/ya.make
new file mode 100644
index 0000000000..fa2d1edef6
--- /dev/null
+++ b/library/cpp/http/ya.make
@@ -0,0 +1,25 @@
+RECURSE(
+ client
+ client/cookies
+ cookies
+ coro
+ examples
+ fetch
+ fetch_gpl
+ io
+ io/fuzz
+ io/list_codings
+ misc
+ multipart
+ push_parser
+ server
+ simple
+ static
+)
+
+IF (NOT OS_WINDOWS)
+ RECURSE_FOR_TESTS(
+ io/ut
+ io/ut/medium
+ )
+ENDIF()
diff --git a/library/cpp/hyperloglog/README.md b/library/cpp/hyperloglog/README.md
new file mode 100644
index 0000000000..4f29676d61
--- /dev/null
+++ b/library/cpp/hyperloglog/README.md
@@ -0,0 +1,3 @@
+Library for set cardinality estimation.
+
+See https://static.googleusercontent.com/media/research.google.com/ru//pubs/archive/40671.pdf
diff --git a/library/cpp/hyperloglog/hyperloglog.cpp b/library/cpp/hyperloglog/hyperloglog.cpp
new file mode 100644
index 0000000000..ec8352abe1
--- /dev/null
+++ b/library/cpp/hyperloglog/hyperloglog.cpp
@@ -0,0 +1,137 @@
+#include "hyperloglog.h"
+
+#include <util/generic/bitops.h>
+#include <util/generic/yexception.h>
+#include <util/stream/output.h>
+
+#include <algorithm>
+#include <array>
+#include <cmath>
+#include <functional>
+
+namespace {
+ using TLookup = std::array<double, 256>;
+
+ struct TCorrection {
+ TLookup Estimations;
+ TLookup Biases;
+
+ double GetBias(double e) const {
+ for (size_t idx = 0;; ++idx) {
+ const auto estr = Estimations[idx];
+ if (estr >= e) {
+ if (idx == 0) {
+ return Biases[0];
+ }
+ const auto estl = Estimations[idx - 1];
+ const auto biasl = Biases[idx - 1];
+ const auto biasr = Biases[idx];
+ const auto de = estr - estl;
+ const auto db = biasr - biasl;
+ const auto scale = e - estl;
+ return biasl + scale * db / de;
+ } else if (std::fabs(estr) < 1e-4) {
+ //limiter
+ return Biases[idx - 1];
+ }
+ }
+ }
+ };
+
+ double EstimateBias(double e, unsigned precision) {
+ static const TCorrection CORRECTIONS[1 + THyperLogLog::PRECISION_MAX - THyperLogLog::PRECISION_MIN] = {
+#include "hyperloglog_corrections.inc"
+ };
+ if (precision < THyperLogLog::PRECISION_MIN || precision > THyperLogLog::PRECISION_MAX) {
+ return 0.;
+ }
+
+ return CORRECTIONS[precision - THyperLogLog::PRECISION_MIN].GetBias(e);
+ }
+
+ double GetThreshold(unsigned precision) {
+ static const double THRESHOLD_DATA[1 + THyperLogLog::PRECISION_MAX - THyperLogLog::PRECISION_MIN] = {
+ 10, // Precision 4
+ 20, // Precision 5
+ 40, // Precision 6
+ 80, // Precision 7
+ 220, // Precision 8
+ 400, // Precision 9
+ 900, // Precision 10
+ 1800, // Precision 11
+ 3100, // Precision 12
+ 6500, // Precision 13
+ 11500, // Precision 14
+ 20000, // Precision 15
+ 50000, // Precision 16
+ 120000, // Precision 17
+ 350000 // Precision 18
+ };
+ if (precision < THyperLogLog::PRECISION_MIN || precision > THyperLogLog::PRECISION_MAX) {
+ return 0.;
+ }
+
+ return THRESHOLD_DATA[precision - THyperLogLog::PRECISION_MIN];
+ }
+
+ double EmpiricAlpha(size_t m) {
+ switch (m) {
+ case 16:
+ return 0.673;
+ case 32:
+ return 0.697;
+ case 64:
+ return 0.709;
+ default:
+ return 0.7213 / (1.0 + 1.079 / m);
+ }
+ }
+
+ double RawEstimate(const ui8* counts, size_t size) {
+ double sum = {};
+ for (size_t i = 0; i < size; ++i) {
+ sum += std::pow(2.0, -counts[i]);
+ }
+ return EmpiricAlpha(size) * size * size / sum;
+ }
+
+ double LinearCounting(size_t registers, size_t zeroed) {
+ return std::log(double(registers) / zeroed) * registers;
+ }
+}
+
+THyperLogLogBase::THyperLogLogBase(unsigned precision)
+ : Precision(precision) {
+ Y_ENSURE(precision >= PRECISION_MIN && precision <= PRECISION_MAX);
+}
+
+void THyperLogLogBase::Update(ui64 hash) {
+ const unsigned subHashBits = 8 * sizeof(hash) - Precision;
+ const auto subHash = hash & MaskLowerBits(subHashBits);
+ const auto leadingZeroes = subHash ? (subHashBits - GetValueBitCount(subHash)) : subHashBits;
+ const ui8 weight = static_cast<ui8>(leadingZeroes + 1);
+
+ const size_t reg = static_cast<size_t>(hash >> subHashBits);
+ RegistersRef[reg] = std::max(RegistersRef[reg], weight);
+}
+
+void THyperLogLogBase::Merge(const THyperLogLogBase& rh) {
+ Y_ENSURE(Precision == rh.Precision);
+
+ std::transform(RegistersRef.begin(), RegistersRef.end(), rh.RegistersRef.begin(), RegistersRef.begin(), [](ui8 l, ui8 r) { return std::max(l, r); });
+}
+
+ui64 THyperLogLogBase::Estimate() const {
+ const auto m = RegistersRef.size();
+ const auto e = RawEstimate(RegistersRef.data(), m);
+
+ const auto e_ = e <= 5 * m ? (e - EstimateBias(e, Precision)) : e;
+ const auto v = std::count(RegistersRef.begin(), RegistersRef.end(), ui8(0));
+ const auto h = v != 0 ? LinearCounting(m, v) : e_;
+ return h <= GetThreshold(Precision) ? h : e_;
+}
+
+void THyperLogLogBase::Save(IOutputStream& out) const {
+ out.Write(static_cast<char>(Precision));
+ out.Write(RegistersRef.data(), RegistersRef.size() * sizeof(RegistersRef.front()));
+}
diff --git a/library/cpp/hyperloglog/hyperloglog.h b/library/cpp/hyperloglog/hyperloglog.h
new file mode 100644
index 0000000000..e79ee0ed77
--- /dev/null
+++ b/library/cpp/hyperloglog/hyperloglog.h
@@ -0,0 +1,64 @@
+#pragma once
+
+#include <util/system/types.h>
+#include <util/stream/input.h>
+#include <util/generic/array_ref.h>
+
+#include <vector>
+
+class IOutputStream;
+
+class THyperLogLogBase {
+protected:
+ explicit THyperLogLogBase(unsigned precision);
+
+public:
+ static const constexpr unsigned PRECISION_MIN = 4;
+
+ static const constexpr unsigned PRECISION_MAX = 18;
+
+ void Update(ui64 hash);
+
+ void Merge(const THyperLogLogBase& rh);
+
+ ui64 Estimate() const;
+
+ void Save(IOutputStream& out) const;
+
+protected:
+ unsigned Precision;
+
+ TArrayRef<ui8> RegistersRef;
+};
+
+template <typename Alloc>
+class THyperLogLogWithAlloc : public THyperLogLogBase {
+private:
+ explicit THyperLogLogWithAlloc(unsigned precision)
+ : THyperLogLogBase(precision) {
+ Registers.resize(1u << precision);
+ RegistersRef = MakeArrayRef(Registers);
+ }
+
+public:
+ THyperLogLogWithAlloc(THyperLogLogWithAlloc&&) = default;
+
+ THyperLogLogWithAlloc& operator=(THyperLogLogWithAlloc&&) = default;
+
+ static THyperLogLogWithAlloc Create(unsigned precision) {
+ return THyperLogLogWithAlloc(precision);
+ }
+
+ static THyperLogLogWithAlloc Load(IInputStream& in) {
+ char precision = {};
+ Y_ENSURE(in.ReadChar(precision));
+ auto res = Create(precision);
+ in.LoadOrFail(res.Registers.data(), res.Registers.size() * sizeof(res.Registers.front()));
+ return res;
+ }
+
+private:
+ std::vector<ui8, Alloc> Registers;
+};
+
+using THyperLogLog = THyperLogLogWithAlloc<std::allocator<ui8>>;
diff --git a/library/cpp/hyperloglog/hyperloglog_corrections.inc b/library/cpp/hyperloglog/hyperloglog_corrections.inc
new file mode 100644
index 0000000000..28c57157e7
--- /dev/null
+++ b/library/cpp/hyperloglog/hyperloglog_corrections.inc
@@ -0,0 +1,1220 @@
+// Precision 4
+{
+ {{
+ 11.000000, 11.717000, 12.207000, 12.789600, 13.288200, 13.820400,
+ 14.377200, 14.934200, 15.520200, 16.161000, 16.772200, 17.463600,
+ 18.039600, 18.676600, 19.356600, 20.045400, 20.793600, 21.485600,
+ 22.266600, 22.994600, 23.766000, 24.469200, 25.363800, 26.076400,
+ 26.786400, 27.760200, 28.481400, 29.433000, 30.292600, 31.066400,
+ 31.999600, 32.795600, 33.536600, 34.589400, 35.573800, 36.269800,
+ 37.368200, 38.054400, 39.234200, 40.010800, 40.796600, 41.929800,
+ 42.870400, 43.635800, 44.519400, 45.773000, 46.677200, 47.617400,
+ 48.488800, 49.330400, 50.250600, 51.499600, 52.382400, 53.307800,
+ 54.398400, 55.583800, 56.661800, 57.217400, 58.351400, 59.080200,
+ 60.148200, 61.037600, 62.359800, 62.807800, 63.974400, 64.914000,
+ 65.781000, 67.180600, 68.059400, 68.844600, 69.792800, 70.824800,
+ 71.832400, 72.859800, 73.624600, 74.701400, 75.393000, 76.670800,
+ 77.239400
+ }},
+ {{
+ 10.000000, 9.717000, 9.207000, 8.789600, 8.288200, 7.820400,
+ 7.377200, 6.934200, 6.520200, 6.161000, 5.772200, 5.463600,
+ 5.039600, 4.676600, 4.356600, 4.045400, 3.793600, 3.485600,
+ 3.266600, 2.994600, 2.766000, 2.469200, 2.363800, 2.076400,
+ 1.786400, 1.760200, 1.481400, 1.433000, 1.292600, 1.066400,
+ 0.999600, 0.795600, 0.536600, 0.589400, 0.573800, 0.269800,
+ 0.368200, 0.054400, 0.234200, 0.010800, -0.203400, -0.070200,
+ -0.129600, -0.364200, -0.480600, -0.227000, -0.322800, -0.382600,
+ -0.511200, -0.669600, -0.749400, -0.500400, -0.617600, -0.692200,
+ -0.601600, -0.416200, -0.338200, -0.782600, -0.648600, -0.919800,
+ -0.851800, -0.962400, -0.640200, -1.192200, -1.025600, -1.086000,
+ -1.219000, -0.819400, -0.940600, -1.155400, -1.207200, -1.175200,
+ -1.167600, -1.140200, -1.375400, -1.298600, -1.607000, -1.329200,
+ -1.760600
+ }}
+},
+
+// Precision 5
+{
+ {{
+ 23.000000, 23.119400, 23.820800, 24.231800, 24.770000, 25.243600,
+ 25.777400, 26.284800, 26.822400, 27.374200, 27.933600, 28.503000,
+ 29.049400, 29.629200, 30.212400, 30.798000, 31.367000, 31.972800,
+ 32.594400, 33.217000, 33.843800, 34.369600, 35.095600, 35.704400,
+ 36.324000, 37.066800, 37.669800, 38.364400, 39.049000, 39.691800,
+ 40.414600, 41.082000, 41.687000, 42.539800, 43.246200, 43.857000,
+ 44.660600, 45.416800, 46.124800, 46.922200, 47.680400, 48.447000,
+ 49.345400, 49.959400, 50.763600, 51.577600, 52.331000, 53.190000,
+ 53.967600, 54.756400, 55.531400, 56.444200, 57.370800, 57.977400,
+ 58.962400, 59.879600, 60.755000, 61.472000, 62.207600, 63.102400,
+ 63.890800, 64.733800, 65.772800, 66.629000, 67.413000, 68.326600,
+ 69.152400, 70.264200, 71.180600, 72.056600, 72.919200, 73.759800,
+ 74.351600, 75.580200, 76.438600, 77.491600, 78.152400, 79.189200,
+ 79.841400, 80.879800, 81.837600, 82.469800, 83.765600, 84.331000,
+ 85.591400, 86.601200, 87.701600, 88.558200, 89.339400, 90.354400,
+ 91.491200, 92.308000, 93.355200, 93.974600, 95.205200, 95.727000,
+ 97.132200, 98.394400, 98.758800, 100.242000, 101.191400, 102.253800,
+ 102.877600, 103.629200, 105.193200, 105.915200, 107.086800, 107.672800,
+ 108.714400, 110.311400, 110.871600, 111.245000, 112.790800, 113.706400,
+ 114.636000, 115.746400, 116.178800, 117.746400, 118.489600, 119.616600,
+ 120.508200, 121.779800, 122.902800, 123.442600, 124.885400, 125.705000,
+ 126.465200, 128.346200, 128.346400, 130.039800, 131.004200, 131.034200,
+ 132.476600, 133.511000, 134.725200, 135.425000, 136.517200, 138.057200,
+ 138.669400, 139.371200, 140.859800, 141.459400, 142.554000, 143.400600,
+ 144.737400, 146.163400, 146.899400, 147.605000, 147.930400, 149.163600,
+ 150.246800, 151.587600, 152.209600, 153.703200, 154.714600, 155.807000,
+ 156.922800, 157.037200, 158.585200
+ }},
+ {{
+ 22.000000, 21.119400, 20.820800, 20.231800, 19.770000, 19.243600,
+ 18.777400, 18.284800, 17.822400, 17.374200, 16.933600, 16.503000,
+ 16.049400, 15.629200, 15.212400, 14.798000, 14.367000, 13.972800,
+ 13.594400, 13.217000, 12.843800, 12.369600, 12.095600, 11.704400,
+ 11.324000, 11.066800, 10.669800, 10.364400, 10.049000, 9.691800,
+ 9.414600, 9.082000, 8.687000, 8.539800, 8.246200, 7.857000,
+ 7.660600, 7.416800, 7.124800, 6.922200, 6.680400, 6.447000,
+ 6.345400, 5.959400, 5.763600, 5.577600, 5.331000, 5.190000,
+ 4.967600, 4.756400, 4.531400, 4.444200, 4.370800, 3.977400,
+ 3.962400, 3.879600, 3.755000, 3.472000, 3.207600, 3.102400,
+ 2.890800, 2.733800, 2.772800, 2.629000, 2.413000, 2.326600,
+ 2.152400, 2.264200, 2.180600, 2.056600, 1.919200, 1.759800,
+ 1.351600, 1.580200, 1.438600, 1.491600, 1.152400, 1.189200,
+ 0.841400, 0.879800, 0.837600, 0.469800, 0.765600, 0.331000,
+ 0.591400, 0.601200, 0.701600, 0.558200, 0.339400, 0.354400,
+ 0.491200, 0.308000, 0.355200, -0.025400, 0.205200, -0.273000,
+ 0.132200, 0.394400, -0.241200, 0.242000, 0.191400, 0.253800,
+ -0.122400, -0.370800, 0.193200, -0.084800, 0.086800, -0.327200,
+ -0.285600, 0.311400, -0.128400, -0.755000, -0.209200, -0.293600,
+ -0.364000, -0.253600, -0.821200, -0.253600, -0.510400, -0.383400,
+ -0.491800, -0.220200, -0.097200, -0.557400, -0.114600, -0.295000,
+ -0.534800, -0.653800, 0.346400, 0.039800, -0.995800, 0.034200,
+ -0.523400, -0.489000, -0.274800, -0.575000, -0.482800, 0.057200,
+ -0.330600, -0.628800, -0.140200, -0.540600, -0.446000, -0.599400,
+ -0.262600, 0.163400, -0.100600, -0.395000, -1.069600, -0.836400,
+ -0.753200, -0.412400, -0.790400, -0.296800, -0.285400, -0.193000,
+ -0.077200, -0.962800, -0.414800
+ }}
+},
+
+// Precision 6
+{
+ {{
+ 46.000000, 46.190200, 47.271000, 47.835800, 48.814200, 49.285400,
+ 50.317000, 51.354000, 51.892400, 52.943600, 53.459600, 54.526200,
+ 55.624800, 56.157400, 57.282200, 57.837000, 58.963600, 60.074000,
+ 60.704200, 61.797600, 62.477200, 63.656400, 64.794200, 65.500400,
+ 66.686000, 67.291000, 68.567200, 69.855600, 70.498200, 71.820400,
+ 72.425200, 73.774400, 75.078600, 75.834400, 77.029400, 77.809800,
+ 79.079400, 80.573200, 81.187800, 82.564800, 83.290200, 84.678400,
+ 85.335200, 86.894600, 88.371200, 89.085200, 90.499000, 91.268600,
+ 92.684400, 94.223400, 94.973200, 96.335600, 97.228600, 98.726200,
+ 100.328400, 101.104800, 102.596200, 103.356200, 105.127200, 106.418400,
+ 107.497400, 109.082200, 109.856000, 111.480000, 113.283400, 114.020800,
+ 115.637000, 116.517400, 118.057600, 119.747600, 120.427000, 122.132600,
+ 123.237200, 125.278800, 126.677600, 127.792600, 129.195200, 129.956400,
+ 131.645400, 133.870000, 134.542800, 136.200000, 137.029400, 138.627800,
+ 139.678200, 141.792000, 143.351600, 144.283200, 146.039400, 147.074800,
+ 148.491200, 150.849000, 151.696000, 153.540400, 154.073000, 156.371400,
+ 157.721600, 158.732800, 160.420800, 161.418400, 163.942400, 165.277200,
+ 166.411000, 168.130800, 168.769000, 170.925800, 172.682800, 173.750200,
+ 175.706000, 176.388600, 179.018600, 180.451800, 181.927000, 183.417200,
+ 184.411400, 186.033000, 188.512400, 189.556400, 191.600800, 192.417200,
+ 193.804400, 194.997000, 197.454800, 198.894800, 200.234600, 202.308600,
+ 203.154800, 204.884200, 206.650800, 206.677200, 209.725400, 210.475200,
+ 212.722800, 214.661400, 215.167600, 217.793000, 218.000600, 219.905200,
+ 221.660000, 223.558800, 225.163600, 225.688200, 227.712600, 229.450200,
+ 231.197800, 232.975600, 233.165400, 236.727000, 237.747400, 238.197400,
+ 241.134600, 242.304800, 244.194800, 245.313400, 246.879000, 249.120400,
+ 249.853000, 252.679200, 253.857000, 254.448600, 257.236200, 257.953400,
+ 260.028600, 260.563200, 262.663000, 264.723000, 265.756600, 267.162400,
+ 267.256600, 270.620000, 272.821600, 273.216600, 275.205600, 276.220200,
+ 278.372600, 280.334400, 281.928400, 283.972800, 284.192400, 286.487200,
+ 287.587000, 289.807000, 291.120600, 292.769000, 294.870800, 296.665000,
+ 297.118200, 299.401200, 300.635200, 302.135400, 304.175600, 306.160600,
+ 307.346200, 308.521400, 309.413400, 310.835200, 313.968400, 315.837000,
+ 316.779600, 318.985800
+ }},
+ {{
+ 45.000000, 44.190200, 43.271000, 42.835800, 41.814200, 41.285400,
+ 40.317000, 39.354000, 38.892400, 37.943600, 37.459600, 36.526200,
+ 35.624800, 35.157400, 34.282200, 33.837000, 32.963600, 32.074000,
+ 31.704200, 30.797600, 30.477200, 29.656400, 28.794200, 28.500400,
+ 27.686000, 27.291000, 26.567200, 25.855600, 25.498200, 24.820400,
+ 24.425200, 23.774400, 23.078600, 22.834400, 22.029400, 21.809800,
+ 21.079400, 20.573200, 20.187800, 19.564800, 19.290200, 18.678400,
+ 18.335200, 17.894600, 17.371200, 17.085200, 16.499000, 16.268600,
+ 15.684400, 15.223400, 14.973200, 14.335600, 14.228600, 13.726200,
+ 13.328400, 13.104800, 12.596200, 12.356200, 12.127200, 11.418400,
+ 11.497400, 11.082200, 10.856000, 10.480000, 10.283400, 10.020800,
+ 9.637000, 9.517400, 9.057600, 8.747600, 8.427000, 8.132600,
+ 8.237200, 8.278800, 7.677600, 7.792600, 7.195200, 6.956400,
+ 6.645400, 6.870000, 6.542800, 6.200000, 6.029400, 5.627800,
+ 5.678200, 5.792000, 5.351600, 5.283200, 5.039400, 5.074800,
+ 4.491200, 4.849000, 4.696000, 4.540400, 4.073000, 4.371400,
+ 3.721600, 3.732800, 3.420800, 3.418400, 3.942400, 3.277200,
+ 3.411000, 3.130800, 2.769000, 2.925800, 2.682800, 2.750200,
+ 2.706000, 2.388600, 3.018600, 2.451800, 2.927000, 2.417200,
+ 2.411400, 2.033000, 2.512400, 2.556400, 2.600800, 2.417200,
+ 1.804400, 1.997000, 2.454800, 1.894800, 2.234600, 2.308600,
+ 2.154800, 1.884200, 1.650800, 0.677200, 1.725400, 1.475200,
+ 1.722800, 1.661400, 1.167600, 1.793000, 1.000600, 0.905200,
+ 0.660000, 1.558800, 1.163600, 0.688200, 0.712600, 0.450200,
+ 1.197800, 0.975600, 0.165400, 1.727000, -0.252600, 1.197400,
+ 1.134600, 1.304800, 1.194800, 0.313400, 0.879000, 1.120400,
+ 0.853000, 1.679200, 0.857000, 0.448600, 1.236200, 0.953400,
+ 1.028600, 0.563200, 0.663000, 0.723000, 0.756600, -0.837600,
+ 0.256600, 0.620000, 0.821600, 0.216600, 0.205600, 0.220200,
+ 0.372600, 0.334400, 0.928400, 0.972800, 0.192400, 0.487200,
+ -0.413000, 0.807000, 0.120600, 0.769000, 0.870800, 0.665000,
+ 0.118200, 0.401200, 0.635200, 0.135400, 0.175600, 1.160600,
+ 0.346200, 0.521400, -0.586600, -1.164800, 0.968400, 0.837000,
+ 0.779600, 0.985800
+ }}
+},
+
+// Precision 7
+{
+ {{
+ 92.000000, 93.493400, 94.975800, 96.457400, 97.971800, 99.495400,
+ 101.530200, 103.075600, 104.637400, 106.178200, 107.788800, 109.952200,
+ 111.592000, 113.253200, 114.908600, 116.593800, 118.947400, 120.679600,
+ 122.439400, 124.217600, 125.976800, 128.421400, 130.252800, 132.010200,
+ 133.865800, 135.727800, 138.304400, 140.131600, 142.093000, 144.003200,
+ 145.909200, 148.630600, 150.529400, 152.575600, 154.650800, 156.662000,
+ 159.552000, 161.372400, 163.617000, 165.575400, 167.787200, 169.844400,
+ 172.798800, 174.860600, 177.211800, 179.356600, 181.447600, 184.588200,
+ 186.681600, 189.082400, 191.025800, 193.604800, 196.443600, 198.727400,
+ 200.957000, 203.147000, 205.436400, 208.759200, 211.338600, 213.781000,
+ 215.802800, 218.656000, 221.654400, 223.996000, 226.471800, 229.154400,
+ 231.609800, 234.595600, 237.061600, 239.575800, 242.487800, 244.524400,
+ 248.214600, 250.724000, 252.872200, 255.519800, 258.041400, 261.941000,
+ 264.904800, 266.870000, 269.430400, 272.028000, 274.470800, 278.370000,
+ 281.062400, 283.466800, 286.553200, 289.435200, 293.256400, 295.274400,
+ 298.211800, 300.747200, 304.145600, 307.292800, 309.750400, 312.552800,
+ 315.979000, 318.210200, 322.183400, 324.349400, 327.325000, 330.661400,
+ 332.903000, 337.254400, 339.904200, 343.215000, 345.286400, 348.081400,
+ 352.676400, 355.301000, 357.139000, 360.658000, 363.173200, 366.590200,
+ 369.953800, 373.082800, 375.922000, 378.990200, 382.732800, 386.453800,
+ 388.113600, 391.223400, 394.087800, 396.708000, 401.155600, 404.185200,
+ 406.637200, 409.682200, 412.779600, 416.607800, 418.491600, 422.131000,
+ 424.537600, 428.198800, 432.211000, 434.450200, 438.528200, 440.912000,
+ 444.044800, 447.743200, 450.852400, 453.798800, 456.785800, 458.886800,
+ 463.988600, 466.506400, 468.912400, 472.661600, 475.468200, 478.582000,
+ 481.304000, 485.273800, 488.689400, 490.329000, 496.106000, 497.690800,
+ 501.137400, 504.532200, 506.884800, 510.332400, 513.451200, 516.179000,
+ 520.441200, 522.606600, 526.167000, 528.779400, 533.379000, 536.067000,
+ 538.460000, 542.911600, 545.692000, 547.954600, 552.493000, 555.272200,
+ 557.335000, 562.449000, 564.201400, 569.073800, 571.097400, 574.856400,
+ 578.299600, 581.409000, 583.970400, 585.809800, 589.652800, 594.599800,
+ 595.958000, 600.068000, 603.327800, 608.201600, 609.963200, 612.864000,
+ 615.430000, 620.779400, 621.272000, 625.864400, 629.206000, 633.219000,
+ 634.515400, 638.610200
+ }},
+ {{
+ 91.000000, 89.493400, 87.975800, 86.457400, 84.971800, 83.495400,
+ 81.530200, 80.075600, 78.637400, 77.178200, 75.788800, 73.952200,
+ 72.592000, 71.253200, 69.908600, 68.593800, 66.947400, 65.679600,
+ 64.439400, 63.217600, 61.976800, 60.421400, 59.252800, 58.010200,
+ 56.865800, 55.727800, 54.304400, 53.131600, 52.093000, 51.003200,
+ 49.909200, 48.630600, 47.529400, 46.575600, 45.650800, 44.662000,
+ 43.552000, 42.372400, 41.617000, 40.575400, 39.787200, 38.844400,
+ 37.798800, 36.860600, 36.211800, 35.356600, 34.447600, 33.588200,
+ 32.681600, 32.082400, 31.025800, 30.604800, 29.443600, 28.727400,
+ 27.957000, 27.147000, 26.436400, 25.759200, 25.338600, 24.781000,
+ 23.802800, 23.656000, 22.654400, 21.996000, 21.471800, 21.154400,
+ 20.609800, 19.595600, 19.061600, 18.575800, 18.487800, 17.524400,
+ 17.214600, 16.724000, 15.872200, 15.519800, 15.041400, 14.941000,
+ 14.904800, 13.870000, 13.430400, 13.028000, 12.470800, 12.370000,
+ 12.062400, 11.466800, 11.553200, 11.435200, 11.256400, 10.274400,
+ 10.211800, 9.747200, 10.145600, 9.292800, 8.750400, 8.552800,
+ 8.979000, 8.210200, 8.183400, 7.349400, 7.325000, 7.661400,
+ 6.903000, 7.254400, 6.904200, 7.215000, 6.286400, 6.081400,
+ 6.676400, 6.301000, 5.139000, 5.658000, 5.173200, 4.590200,
+ 4.953800, 5.082800, 4.922000, 4.990200, 4.732800, 5.453800,
+ 4.113600, 4.223400, 4.087800, 3.708000, 4.155600, 4.185200,
+ 3.637200, 3.682200, 3.779600, 3.607800, 2.491600, 3.131000,
+ 2.537600, 3.198800, 3.211000, 2.450200, 3.528200, 2.912000,
+ 3.044800, 2.743200, 2.852400, 2.798800, 2.785800, 1.886800,
+ 2.988600, 2.506400, 1.912400, 2.661600, 2.468200, 1.582000,
+ 1.304000, 2.273800, 2.689400, 1.329000, 3.106000, 1.690800,
+ 2.137400, 2.532200, 1.884800, 1.332400, 1.451200, 1.179000,
+ 2.441200, 1.606600, 2.167000, 0.779400, 2.379000, 2.067000,
+ 1.460000, 2.911600, 1.692000, 0.954600, 2.493000, 2.272200,
+ 1.335000, 2.449000, 1.201400, 3.073800, 2.097400, 2.856400,
+ 2.299600, 2.409000, 1.970400, 0.809800, 1.652800, 2.599800,
+ 0.958000, 2.068000, 2.327800, 4.201600, 1.963200, 1.864000,
+ 1.430000, 3.779400, 1.272000, 1.864400, 2.206000, 3.219000,
+ 1.515400, 2.610200
+ }}
+},
+
+// Precision 8
+{
+ {{
+ 184.215200, 187.245400, 190.209600, 193.665200, 196.631200,
+ 199.682200, 203.249000, 206.329600, 210.003800, 213.207400,
+ 216.461200, 220.270000, 223.517800, 227.441200, 230.803200,
+ 234.163400, 238.168800, 241.607400, 245.694600, 249.266400,
+ 252.822800, 257.043200, 260.682400, 264.946400, 268.626800,
+ 272.262600, 276.837600, 280.403400, 284.895600, 288.852200,
+ 292.763800, 297.355200, 301.355600, 305.752600, 309.929200,
+ 313.895400, 318.819800, 322.766800, 327.298000, 331.668800,
+ 335.946600, 340.974600, 345.167200, 349.347400, 354.302800,
+ 358.891200, 364.114000, 368.464600, 372.974400, 378.409200,
+ 382.602200, 387.843000, 392.568400, 397.165200, 402.542600,
+ 407.415200, 412.538800, 417.359200, 422.136600, 427.486000,
+ 432.391800, 437.507600, 442.509000, 447.383400, 453.349800,
+ 458.066800, 463.734600, 469.122800, 473.452800, 479.700000,
+ 484.644000, 491.051800, 495.577400, 500.906800, 506.432000,
+ 512.166600, 517.434000, 522.664400, 527.489400, 533.631200,
+ 538.380400, 544.292000, 550.549600, 556.023400, 562.820600,
+ 566.614600, 572.418800, 579.117000, 583.676200, 590.657600,
+ 595.786400, 601.509000, 607.533400, 612.920400, 619.772000,
+ 624.292400, 630.865400, 636.183600, 642.745000, 649.131600,
+ 655.038600, 660.013600, 666.634200, 671.619600, 678.186600,
+ 684.428200, 689.332400, 695.479400, 702.503800, 708.129000,
+ 713.528000, 720.320400, 726.463000, 732.792800, 739.123000,
+ 744.741800, 751.219200, 756.510200, 762.606600, 769.018400,
+ 775.222400, 781.401400, 787.761800, 794.143600, 798.650600,
+ 805.637800, 811.766000, 819.751400, 824.577600, 828.732200,
+ 837.804800, 843.630200, 849.933600, 854.479800, 861.338800,
+ 867.989400, 873.819600, 880.313600, 886.230800, 892.458800,
+ 899.081600, 905.407600, 912.006400, 917.387800, 923.619000,
+ 929.998000, 937.348200, 943.950600, 947.991000, 955.114400,
+ 962.203000, 968.822200, 975.732400, 981.782600, 988.766600,
+ 994.264800, 1000.312800, 1007.408200, 1013.753600, 1020.337600,
+ 1026.715600, 1031.747800, 1037.429200, 1045.393000, 1051.227800,
+ 1058.343400, 1062.872600, 1071.884000, 1076.806000, 1082.917600,
+ 1089.167800, 1095.503200, 1102.525000, 1107.226400, 1115.315000,
+ 1120.930000, 1127.252000, 1134.149600, 1139.040800, 1147.544800,
+ 1153.329600, 1158.197400, 1166.526200, 1174.332800, 1175.657000,
+ 1184.422200, 1190.917200, 1197.129200, 1204.460600, 1210.457800,
+ 1218.872800, 1225.333600, 1226.659200, 1236.576800, 1241.363000,
+ 1249.407400, 1254.656600, 1260.801400, 1266.545400, 1274.519200
+ }},
+ {{
+ 183.215200, 180.245400, 177.209600, 173.665200, 170.631200, 167.682200,
+ 164.249000, 161.329600, 158.003800, 155.207400, 152.461200, 149.270000,
+ 146.517800, 143.441200, 140.803200, 138.163400, 135.168800, 132.607400,
+ 129.694600, 127.266400, 124.822800, 122.043200, 119.682400, 116.946400,
+ 114.626800, 112.262600, 109.837600, 107.403400, 104.895600, 102.852200,
+ 100.763800, 98.355200, 96.355600, 93.752600, 91.929200, 89.895400,
+ 87.819800, 85.766800, 83.298000, 81.668800, 79.946600, 77.974600,
+ 76.167200, 74.347400, 72.302800, 70.891200, 69.114000, 67.464600,
+ 65.974400, 64.409200, 62.602200, 60.843000, 59.568400, 58.165200,
+ 56.542600, 55.415200, 53.538800, 52.359200, 51.136600, 49.486000,
+ 48.391800, 46.507600, 45.509000, 44.383400, 43.349800, 42.066800,
+ 40.734600, 40.122800, 38.452800, 37.700000, 36.644000, 36.051800,
+ 34.577400, 33.906800, 32.432000, 32.166600, 30.434000, 29.664400,
+ 28.489400, 27.631200, 26.380400, 26.292000, 25.549600, 25.023400,
+ 24.820600, 22.614600, 22.418800, 22.117000, 20.676200, 20.657600,
+ 19.786400, 19.509000, 18.533400, 17.920400, 17.772000, 16.292400,
+ 16.865400, 15.183600, 15.745000, 15.131600, 15.038600, 14.013600,
+ 13.634200, 12.619600, 12.186600, 12.428200, 11.332400, 10.479400,
+ 11.503800, 10.129000, 9.528000, 10.320400, 9.463000, 9.792800,
+ 9.123000, 8.741800, 9.219200, 7.510200, 7.606600, 7.018400,
+ 7.222400, 7.401400, 6.761800, 7.143600, 5.650600, 5.637800,
+ 5.766000, 6.751400, 5.577600, 3.732200, 5.804800, 5.630200,
+ 4.933600, 3.479800, 4.338800, 3.989400, 3.819600, 3.313600,
+ 3.230800, 3.458800, 3.081600, 3.407600, 3.006400, 2.387800,
+ 2.619000, 1.998000, 3.348200, 2.950600, 0.991000, 2.114400,
+ 2.203000, 2.822200, 2.732400, 2.782600, 3.766600, 2.264800,
+ 2.312800, 2.408200, 2.753600, 3.337600, 2.715600, 1.747800,
+ 1.429200, 2.393000, 2.227800, 2.343400, 0.872600, 3.884000,
+ 1.806000, 1.917600, 1.167800, 1.503200, 2.525000, 0.226400,
+ 2.315000, 0.930000, 1.252000, 2.149600, 0.040800, 2.544800,
+ 1.329600, 0.197400, 2.526200, 3.332800, -1.343000, 0.422200,
+ 0.917200, 1.129200, 1.460600, 1.457800, 2.872800, 3.333600,
+ -1.340800, 1.576800, 0.363000, 1.407400, 0.656600, 0.801400,
+ -0.454600, 1.519200
+ }}
+},
+
+// Precision 9
+{
+ {{
+ 369.000000, 374.829400, 381.245200, 387.669800, 394.146400,
+ 400.202400, 406.878200, 413.659800, 420.462000, 427.282600,
+ 433.710200, 440.741600, 447.936600, 455.104600, 462.285000,
+ 469.066800, 476.306000, 483.844800, 491.301000, 498.988600,
+ 506.242200, 513.813800, 521.707400, 529.742800, 537.840200,
+ 545.166400, 553.353400, 561.594000, 569.688600, 577.787600,
+ 585.650000, 594.228000, 602.803600, 611.166600, 620.081800,
+ 628.082400, 637.257400, 646.302000, 655.164400, 664.005600,
+ 672.380200, 681.719200, 690.523400, 700.208400, 708.831000,
+ 718.485000, 728.111200, 737.476400, 746.760000, 756.336800,
+ 766.553800, 775.505800, 785.264600, 795.590200, 804.381800,
+ 814.899800, 824.953200, 835.206200, 845.279800, 854.472800,
+ 864.958200, 875.329200, 886.171000, 896.781000, 906.571600,
+ 916.704800, 927.532200, 937.875000, 949.397200, 958.346400,
+ 969.727400, 980.283400, 992.144400, 1003.426400, 1013.016600,
+ 1024.018000, 1035.043800, 1046.340000, 1057.685600, 1068.983600,
+ 1079.031200, 1091.677000, 1102.318800, 1113.484600, 1124.442400,
+ 1135.739000, 1147.148800, 1158.920200, 1169.406000, 1181.534200,
+ 1193.283400, 1203.895400, 1216.328600, 1226.214600, 1239.668400,
+ 1251.994600, 1262.123000, 1275.433800, 1285.737800, 1296.076000,
+ 1308.969200, 1320.496400, 1333.099800, 1343.986400, 1357.775400,
+ 1368.320800, 1380.483800, 1392.738800, 1406.075800, 1416.909800,
+ 1428.972800, 1440.922800, 1453.929200, 1462.617000, 1476.050000,
+ 1490.299600, 1500.612800, 1513.739200, 1524.517400, 1536.632200,
+ 1548.258400, 1562.376600, 1572.423000, 1587.123200, 1596.516400,
+ 1610.593800, 1622.597200, 1633.122200, 1647.767400, 1658.504400,
+ 1671.570000, 1683.704400, 1695.414200, 1708.710200, 1720.609400,
+ 1732.652200, 1747.841000, 1756.407200, 1769.978600, 1782.327600,
+ 1797.521600, 1808.318600, 1819.069400, 1834.354000, 1844.575000,
+ 1856.280800, 1871.128800, 1880.785200, 1893.962200, 1906.341800,
+ 1920.654800, 1932.930200, 1945.858400, 1955.473000, 1968.824800,
+ 1980.644600, 1995.959800, 2008.349000, 2019.855600, 2033.033400,
+ 2044.020600, 2059.395600, 2069.917400, 2082.608400, 2093.703600,
+ 2106.610800, 2118.912400, 2132.301000, 2144.762800, 2159.842200,
+ 2171.021200, 2183.101000, 2193.511200, 2208.052000, 2221.319400,
+ 2233.328200, 2247.295000, 2257.722200, 2273.342000, 2286.563800,
+ 2299.678600, 2310.811400, 2322.331200, 2335.516000, 2349.874000,
+ 2363.596800, 2373.865000, 2387.191800, 2401.832800, 2414.849600,
+ 2424.544000, 2436.759200, 2447.168200, 2464.195800, 2474.343800,
+ 2489.000600, 2497.452600, 2513.658600, 2527.190000, 2540.702800,
+ 2553.768000
+ }},
+ {{
+ 368.000000, 361.829400, 355.245200, 348.669800, 342.146400, 336.202400,
+ 329.878200, 323.659800, 317.462000, 311.282600, 305.710200, 299.741600,
+ 293.936600, 288.104600, 282.285000, 277.066800, 271.306000, 265.844800,
+ 260.301000, 254.988600, 250.242200, 244.813800, 239.707400, 234.742800,
+ 229.840200, 225.166400, 220.353400, 215.594000, 210.688600, 205.787600,
+ 201.650000, 197.228000, 192.803600, 188.166600, 184.081800, 180.082400,
+ 176.257400, 172.302000, 168.164400, 164.005600, 160.380200, 156.719200,
+ 152.523400, 149.208400, 145.831000, 142.485000, 139.111200, 135.476400,
+ 131.760000, 129.336800, 126.553800, 122.505800, 119.264600, 116.590200,
+ 113.381800, 110.899800, 107.953200, 105.206200, 102.279800, 99.472800,
+ 96.958200, 94.329200, 92.171000, 89.781000, 87.571600, 84.704800,
+ 82.532200, 79.875000, 78.397200, 75.346400, 73.727400, 71.283400,
+ 70.144400, 68.426400, 66.016600, 64.018000, 62.043800, 60.340000,
+ 58.685600, 57.983600, 55.031200, 54.677000, 52.318800, 51.484600,
+ 49.442400, 47.739000, 46.148800, 44.920200, 43.406000, 42.534200,
+ 41.283400, 38.895400, 38.328600, 36.214600, 36.668400, 35.994600,
+ 33.123000, 33.433800, 31.737800, 29.076000, 28.969200, 27.496400,
+ 27.099800, 25.986400, 26.775400, 24.320800, 23.483800, 22.738800,
+ 24.075800, 21.909800, 20.972800, 19.922800, 19.929200, 16.617000,
+ 17.050000, 18.299600, 15.612800, 15.739200, 14.517400, 13.632200,
+ 12.258400, 13.376600, 11.423000, 13.123200, 9.516400, 10.593800,
+ 9.597200, 8.122200, 9.767400, 7.504400, 7.570000, 6.704400,
+ 6.414200, 6.710200, 5.609400, 4.652200, 6.841000, 3.407200,
+ 3.978600, 3.327600, 5.521600, 3.318600, 2.069400, 4.354000,
+ 1.575000, 0.280800, 2.128800, -0.214800, -0.037800, -0.658200,
+ 0.654800, -0.069800, 0.858400, -2.527000, -2.175200, -3.355400,
+ -1.040200, -0.651000, -2.144400, -1.966600, -3.979400, -0.604400,
+ -3.082600, -3.391600, -5.296400, -5.389200, -5.087600, -4.699000,
+ -5.237200, -3.157800, -4.978800, -4.899000, -7.488800, -5.948000,
+ -5.680600, -6.671800, -4.705000, -7.277800, -4.658000, -4.436200,
+ -4.321400, -5.188600, -6.668800, -6.484000, -5.126000, -4.403200,
+ -6.135000, -5.808200, -4.167200, -4.150400, -7.456000, -7.240800,
+ -9.831800, -5.804200, -8.656200, -6.999400, -10.547400, -7.341400,
+ -6.810000, -6.297200, -6.232000
+ }}
+},
+
+// Precision 10
+{
+ {{
+ 738.125600, 750.423400, 763.106400, 775.473200, 788.463600,
+ 801.064400, 814.488000, 827.965400, 841.083200, 854.786400,
+ 868.199200, 882.217600, 896.522800, 910.171600, 924.775200,
+ 938.899000, 953.612600, 968.649200, 982.947400, 998.521400,
+ 1013.106400, 1028.636400, 1044.246800, 1059.458800, 1075.383200,
+ 1091.058400, 1106.860600, 1123.386800, 1139.506200, 1156.186200,
+ 1172.463000, 1189.339000, 1206.193600, 1223.129200, 1240.185400,
+ 1257.290800, 1275.332400, 1292.851800, 1310.520400, 1328.485400,
+ 1345.931800, 1364.552000, 1381.465800, 1400.425600, 1419.849000,
+ 1438.152000, 1456.895600, 1474.879200, 1494.118000, 1513.620000,
+ 1532.513200, 1551.932200, 1570.772600, 1590.608600, 1610.533200,
+ 1630.591800, 1650.429400, 1669.766200, 1690.410600, 1710.733800,
+ 1730.901200, 1750.448600, 1770.155600, 1791.633800, 1812.731200,
+ 1833.626400, 1853.952600, 1874.874200, 1896.832600, 1918.196600,
+ 1939.559400, 1961.070000, 1983.037000, 2003.180400, 2026.071000,
+ 2047.488400, 2070.084800, 2091.294400, 2114.333000, 2135.962600,
+ 2158.290200, 2181.081400, 2202.033400, 2224.483200, 2246.390000,
+ 2269.720200, 2292.171400, 2314.235800, 2338.934600, 2360.891000,
+ 2384.026400, 2408.383400, 2430.154400, 2454.868400, 2476.989600,
+ 2501.436800, 2522.870200, 2548.040800, 2570.673800, 2593.520800,
+ 2617.015800, 2640.230200, 2664.096200, 2687.498600, 2714.258800,
+ 2735.391400, 2759.624400, 2781.837800, 2808.007200, 2830.651600,
+ 2856.245400, 2877.213600, 2903.454600, 2926.785000, 2951.229400,
+ 2976.468000, 3000.867000, 3023.650800, 3049.910000, 3073.598400,
+ 3098.162000, 3121.556400, 3146.232800, 3170.948400, 3195.590200,
+ 3221.334600, 3242.703200, 3271.611200, 3296.554600, 3317.737600,
+ 3345.072000, 3369.951800, 3394.326000, 3418.181800, 3444.692600,
+ 3469.086000, 3494.275400, 3517.869800, 3544.248000, 3565.376800,
+ 3588.723400, 3616.979000, 3643.750400, 3668.681200, 3695.720000,
+ 3719.739200, 3742.622400, 3770.445600, 3795.660200, 3819.905800,
+ 3844.002000, 3869.517000, 3895.682400, 3920.862200, 3947.136400,
+ 3973.985000, 3995.477200, 4021.620000, 4046.628000, 4074.650000,
+ 4096.225600, 4121.831000, 4146.640600, 4173.276000, 4195.074400,
+ 4223.969600, 4251.370800, 4272.996600, 4300.804600, 4326.302000,
+ 4353.124800, 4374.312000, 4403.032200, 4426.819000, 4450.059800,
+ 4478.520600, 4504.811600, 4528.892800, 4553.958400, 4578.871200,
+ 4603.838400, 4632.387200, 4655.512800, 4675.821000, 4704.622200,
+ 4731.986200, 4755.417400, 4781.262800, 4804.332000, 4832.304800,
+ 4862.875200, 4883.414800, 4906.954400, 4935.351600, 4954.353200,
+ 4984.024800, 5011.217000, 5035.325800, 5057.367200, 5084.182800
+ }},
+ {{
+ 737.125600, 724.423400, 711.106400, 698.473200, 685.463600, 673.064400,
+ 660.488000, 647.965400, 636.083200, 623.786400, 612.199200, 600.217600,
+ 588.522800, 577.171600, 565.775200, 554.899000, 543.612600, 532.649200,
+ 521.947400, 511.521400, 501.106400, 490.636400, 480.246800, 470.458800,
+ 460.383200, 451.058400, 440.860600, 431.386800, 422.506200, 413.186200,
+ 404.463000, 395.339000, 386.193600, 378.129200, 369.185400, 361.290800,
+ 353.332400, 344.851800, 337.520400, 329.485400, 321.931800, 314.552000,
+ 306.465800, 299.425600, 292.849000, 286.152000, 278.895600, 271.879200,
+ 265.118000, 258.620000, 252.513200, 245.932200, 239.772600, 233.608600,
+ 227.533200, 222.591800, 216.429400, 210.766200, 205.410600, 199.733800,
+ 194.901200, 188.448600, 183.155600, 178.633800, 173.731200, 169.626400,
+ 163.952600, 159.874200, 155.832600, 151.196600, 147.559400, 143.070000,
+ 140.037000, 134.180400, 131.071000, 127.488400, 124.084800, 120.294400,
+ 117.333000, 112.962600, 110.290200, 107.081400, 103.033400, 99.483200,
+ 96.390000, 93.720200, 90.171400, 87.235800, 85.934600, 82.891000,
+ 80.026400, 78.383400, 75.154400, 73.868400, 70.989600, 69.436800,
+ 64.870200, 65.040800, 61.673800, 59.520800, 57.015800, 54.230200,
+ 53.096200, 50.498600, 52.258800, 47.391400, 45.624400, 42.837800,
+ 43.007200, 40.651600, 40.245400, 35.213600, 36.454600, 33.785000,
+ 33.229400, 32.468000, 30.867000, 28.650800, 28.910000, 27.598400,
+ 26.162000, 24.556400, 23.232800, 21.948400, 21.590200, 21.334600,
+ 17.703200, 20.611200, 19.554600, 15.737600, 17.072000, 16.951800,
+ 15.326000, 13.181800, 14.692600, 13.086000, 13.275400, 10.869800,
+ 11.248000, 7.376800, 4.723400, 7.979000, 8.750400, 7.681200,
+ 9.720000, 7.739200, 5.622400, 7.445600, 6.660200, 5.905800,
+ 4.002000, 4.517000, 4.682400, 3.862200, 5.136400, 5.985000,
+ 2.477200, 2.620000, 1.628000, 4.650000, 0.225600, 0.831000,
+ -0.359400, 1.276000, -2.925600, -0.030400, 2.370800, -2.003400,
+ 0.804600, 0.302000, 1.124800, -2.688000, 0.032200, -1.181000,
+ -3.940200, -1.479400, -0.188400, -2.107200, -2.041600, -3.128800,
+ -4.161600, -0.612800, -3.487200, -8.179000, -5.377800, -4.013800,
+ -5.582600, -5.737200, -7.668000, -5.695200, -1.124800, -5.585200,
+ -8.045600, -4.648400, -11.646800, -7.975200, -5.783000, -7.674200,
+ -10.632800, -9.817200
+ }}
+},
+
+// Precision 11
+{
+ {{
+ 1477.000000, 1501.601400, 1526.580200, 1551.794200, 1577.304200,
+ 1603.206200, 1629.840200, 1656.229200, 1682.946200, 1709.992600,
+ 1737.302600, 1765.425200, 1793.057800, 1821.609200, 1849.626000,
+ 1878.556800, 1908.527000, 1937.515400, 1967.187400, 1997.387800,
+ 2027.370000, 2058.197200, 2089.572800, 2120.101200, 2151.966800,
+ 2183.292000, 2216.077200, 2247.857800, 2280.656200, 2313.041000,
+ 2345.714000, 2380.311200, 2414.180600, 2447.985400, 2481.656000,
+ 2516.346000, 2551.515400, 2586.837800, 2621.744800, 2656.672200,
+ 2693.572200, 2729.146200, 2765.412400, 2802.872800, 2838.898000,
+ 2876.408000, 2913.492600, 2951.493800, 2989.677600, 3026.282000,
+ 3065.770400, 3104.101200, 3143.738800, 3181.687600, 3221.187200,
+ 3261.504800, 3300.021400, 3339.806000, 3381.409000, 3421.414400,
+ 3461.429400, 3502.228600, 3544.651000, 3586.615600, 3627.337000,
+ 3670.083000, 3711.153800, 3753.509400, 3797.010000, 3838.668600,
+ 3882.167800, 3922.811600, 3967.997800, 4009.920400, 4054.328600,
+ 4097.570600, 4140.601400, 4185.544000, 4229.597600, 4274.583000,
+ 4316.943800, 4361.672000, 4406.278600, 4451.862800, 4496.183400,
+ 4543.505000, 4589.181600, 4632.518800, 4678.229400, 4724.890800,
+ 4769.019400, 4817.052000, 4861.458800, 4910.159600, 4956.434400,
+ 5002.523800, 5048.130000, 5093.637400, 5142.816200, 5187.789400,
+ 5237.398400, 5285.607800, 5331.085800, 5379.103600, 5428.625800,
+ 5474.601800, 5522.761800, 5571.582200, 5618.590000, 5667.999200,
+ 5714.880000, 5763.454000, 5808.698200, 5860.364400, 5910.291400,
+ 5953.571000, 6005.923200, 6055.191400, 6104.588200, 6154.570200,
+ 6199.703600, 6251.176400, 6298.759600, 6350.030200, 6398.061000,
+ 6448.469400, 6495.933000, 6548.047400, 6597.716600, 6646.941600,
+ 6695.920800, 6742.632800, 6793.527600, 6842.193400, 6894.237200,
+ 6945.386400, 6996.922800, 7044.237200, 7094.137400, 7142.227200,
+ 7192.294200, 7238.833800, 7288.900600, 7344.090800, 7394.854400,
+ 7443.517600, 7490.414800, 7542.931400, 7595.673800, 7641.987800,
+ 7694.368800, 7743.044800, 7797.522000, 7845.530000, 7899.594000,
+ 7950.313200, 7996.455000, 8050.944200, 8092.911400, 8153.137400,
+ 8197.447200, 8252.827800, 8301.872800, 8348.677600, 8401.469800,
+ 8453.551000, 8504.659800, 8553.894400, 8604.127600, 8657.651400,
+ 8710.306200, 8758.908000, 8807.870600, 8862.170200, 8910.466800,
+ 8960.770000, 9007.276600, 9063.164000, 9121.053400, 9164.135400,
+ 9218.159400, 9267.767000, 9319.059400, 9372.155000, 9419.712600,
+ 9474.372200, 9520.133800, 9572.368000, 9622.770200, 9675.844800,
+ 9726.539600, 9778.737800, 9827.655400, 9878.192200, 9928.778200,
+ 9978.398400, 10026.578000, 10076.562600, 10137.161800, 10177.524400,
+ 10229.917600
+ }},
+ {{
+ 1476.000000, 1449.601400, 1423.580200, 1397.794200, 1372.304200,
+ 1347.206200, 1321.840200, 1297.229200, 1272.946200, 1248.992600,
+ 1225.302600, 1201.425200, 1178.057800, 1155.609200, 1132.626000,
+ 1110.556800, 1088.527000, 1066.515400, 1045.187400, 1024.387800,
+ 1003.370000, 982.197200, 962.572800, 942.101200, 922.966800,
+ 903.292000, 884.077200, 864.857800, 846.656200, 828.041000,
+ 809.714000, 792.311200, 775.180600, 757.985400, 740.656000,
+ 724.346000, 707.515400, 691.837800, 675.744800, 659.672200,
+ 645.572200, 630.146200, 614.412400, 600.872800, 585.898000,
+ 572.408000, 558.492600, 544.493800, 531.677600, 517.282000,
+ 505.770400, 493.101200, 480.738800, 467.687600, 456.187200,
+ 445.504800, 433.021400, 420.806000, 411.409000, 400.414400,
+ 389.429400, 379.228600, 369.651000, 360.615600, 350.337000,
+ 342.083000, 332.153800, 322.509400, 315.010000, 305.668600,
+ 298.167800, 287.811600, 280.997800, 271.920400, 265.328600,
+ 257.570600, 249.601400, 242.544000, 235.597600, 229.583000,
+ 220.943800, 214.672000, 208.278600, 201.862800, 195.183400,
+ 191.505000, 186.181600, 178.518800, 172.229400, 167.890800,
+ 161.019400, 158.052000, 151.458800, 148.159600, 143.434400,
+ 138.523800, 133.130000, 127.637400, 124.816200, 118.789400,
+ 117.398400, 114.607800, 109.085800, 105.103600, 103.625800,
+ 98.601800, 95.761800, 93.582200, 88.590000, 86.999200,
+ 82.880000, 80.454000, 74.698200, 74.364400, 73.291400,
+ 65.571000, 66.923200, 65.191400, 62.588200, 61.570200,
+ 55.703600, 56.176400, 52.759600, 53.030200, 49.061000,
+ 48.469400, 44.933000, 46.047400, 44.716600, 41.941600,
+ 39.920800, 35.632800, 35.527600, 33.193400, 33.237200,
+ 33.386400, 33.922800, 30.237200, 29.137400, 25.227200,
+ 24.294200, 19.833800, 18.900600, 23.090800, 21.854400,
+ 19.517600, 15.414800, 16.931400, 18.673800, 12.987800,
+ 14.368800, 12.044800, 15.522000, 12.530000, 14.594000,
+ 14.313200, 9.455000, 12.944200, 3.911400, 13.137400,
+ 5.447200, 9.827800, 7.872800, 3.677600, 5.469800,
+ 5.551000, 5.659800, 3.894400, 3.127600, 5.651400,
+ 6.306200, 3.908000, 1.870600, 5.170200, 2.466800,
+ 0.770000, -3.723400, 1.164000, 8.053400, 0.135400,
+ 2.159400, 0.767000, 1.059400, 3.155000, -0.287400,
+ 2.372200, -2.866200, -1.632000, -2.229800, -0.155200,
+ -1.460400, -0.262200, -2.344600, -2.807800, -3.221800,
+ -5.601600, -8.422000, -9.437400, 0.161800, -10.475600,
+ -10.082400
+ }}
+},
+
+// Precision 12
+{
+ {{
+ 2954.000000, 3003.478200, 3053.356800, 3104.366600, 3155.324000,
+ 3206.959800, 3259.648000, 3312.539000, 3366.147400, 3420.257600,
+ 3474.837600, 3530.607600, 3586.451000, 3643.380000, 3700.410400,
+ 3757.563800, 3815.967600, 3875.193000, 3934.838000, 3994.854800,
+ 4055.018000, 4117.174200, 4178.448200, 4241.129400, 4304.477600,
+ 4367.404400, 4431.872400, 4496.373200, 4561.430400, 4627.532600,
+ 4693.949000, 4761.553200, 4828.725600, 4897.618200, 4965.518600,
+ 5034.452800, 5104.865000, 5174.716400, 5244.682800, 5316.670800,
+ 5387.831200, 5459.903600, 5532.476000, 5604.865200, 5679.671800,
+ 5753.757000, 5830.207200, 5905.282800, 5980.043400, 6056.626400,
+ 6134.319200, 6211.574600, 6290.081600, 6367.117600, 6447.979600,
+ 6526.557600, 6606.185800, 6686.914400, 6766.114200, 6847.081800,
+ 6927.966400, 7010.909600, 7091.081600, 7175.396200, 7260.345400,
+ 7344.018000, 7426.421400, 7511.310600, 7596.068600, 7679.809400,
+ 7765.818000, 7852.424800, 7936.834000, 8022.363000, 8109.506600,
+ 8200.455400, 8288.583200, 8373.366000, 8463.480800, 8549.768200,
+ 8642.052200, 8728.328800, 8820.952800, 8907.727000, 9001.079400,
+ 9091.252200, 9179.988000, 9269.852000, 9362.639400, 9453.642000,
+ 9546.902400, 9640.661600, 9732.662200, 9824.325400, 9917.748400,
+ 10007.939200, 10106.750800, 10196.215200, 10289.811400, 10383.549400,
+ 10482.306400, 10576.873400, 10668.787200, 10764.715600, 10862.019600,
+ 10952.793000, 11049.974800, 11146.070200, 11241.449200, 11339.277200,
+ 11434.233600, 11530.741000, 11627.613600, 11726.311000, 11821.596400,
+ 11918.837000, 12015.372400, 12113.016200, 12213.042400, 12306.980400,
+ 12408.451800, 12504.896800, 12604.586000, 12700.933200, 12798.705000,
+ 12898.514200, 12997.048800, 13094.788000, 13198.475000, 13292.776400,
+ 13392.969800, 13486.857400, 13590.161600, 13686.583800, 13783.626400,
+ 13887.263800, 13992.097800, 14081.084400, 14189.995600, 14280.091200,
+ 14382.495600, 14486.438400, 14588.108200, 14686.239200, 14782.276000,
+ 14888.028400, 14985.186400, 15088.859600, 15187.099800, 15285.027000,
+ 15383.669400, 15495.826600, 15591.373600, 15694.200800, 15790.324600,
+ 15898.411600, 15997.452200, 16095.501400, 16198.851400, 16291.749200,
+ 16402.642400, 16499.126600, 16606.243600, 16697.718600, 16796.394600,
+ 16902.337600, 17005.767200, 17100.814000, 17206.828200, 17305.826200,
+ 17416.074400, 17508.409200, 17617.017800, 17715.455400, 17816.758000,
+ 17920.174800, 18012.923600, 18119.798400, 18223.224800, 18324.248200,
+ 18426.627600, 18525.093200, 18629.897600, 18733.258800, 18831.046600,
+ 18940.136600, 19032.269600, 19131.729000, 19243.486400, 19349.693200,
+ 19442.866000, 19547.944800, 19653.279800, 19754.403400, 19854.069200,
+ 19965.122400, 20065.177400, 20158.221200, 20253.353000, 20366.326400,
+ 20463.220000
+ }},
+ {{
+ 2953.000000, 2900.478200, 2848.356800, 2796.366600, 2745.324000,
+ 2694.959800, 2644.648000, 2595.539000, 2546.147400, 2498.257600,
+ 2450.837600, 2403.607600, 2357.451000, 2311.380000, 2266.410400,
+ 2221.563800, 2176.967600, 2134.193000, 2090.838000, 2048.854800,
+ 2007.018000, 1966.174200, 1925.448200, 1885.129400, 1846.477600,
+ 1807.404400, 1768.872400, 1731.373200, 1693.430400, 1657.532600,
+ 1621.949000, 1586.553200, 1551.725600, 1517.618200, 1483.518600,
+ 1450.452800, 1417.865000, 1385.716400, 1352.682800, 1322.670800,
+ 1291.831200, 1260.903600, 1231.476000, 1201.865200, 1173.671800,
+ 1145.757000, 1119.207200, 1092.282800, 1065.043400, 1038.626400,
+ 1014.319200, 988.574600, 965.081600, 940.117600, 917.979600,
+ 894.557600, 871.185800, 849.914400, 827.114200, 805.081800,
+ 783.966400, 763.909600, 742.081600, 724.396200, 706.345400,
+ 688.018000, 667.421400, 650.310600, 633.068600, 613.809400,
+ 597.818000, 581.424800, 563.834000, 547.363000, 531.506600,
+ 520.455400, 505.583200, 488.366000, 476.480800, 459.768200,
+ 450.052200, 434.328800, 423.952800, 408.727000, 399.079400,
+ 387.252200, 373.988000, 360.852000, 351.639400, 339.642000,
+ 330.902400, 322.661600, 311.662200, 301.325400, 291.748400,
+ 279.939200, 276.750800, 263.215200, 254.811400, 245.549400,
+ 242.306400, 234.873400, 223.787200, 217.715600, 212.019600,
+ 200.793000, 195.974800, 189.070200, 182.449200, 177.277200,
+ 170.233600, 164.741000, 158.613600, 155.311000, 147.596400,
+ 142.837000, 137.372400, 132.016200, 130.042400, 121.980400,
+ 120.451800, 114.896800, 111.586000, 105.933200, 101.705000,
+ 98.514200, 95.048800, 89.788000, 91.475000, 83.776400,
+ 80.969800, 72.857400, 73.161600, 67.583800, 62.626400,
+ 63.263800, 66.097800, 52.084400, 58.995600, 47.091200,
+ 46.495600, 48.438400, 47.108200, 43.239200, 37.276000,
+ 40.028400, 35.186400, 35.859600, 32.099800, 28.027000,
+ 23.669400, 33.826600, 26.373600, 27.200800, 21.324600,
+ 26.411600, 23.452200, 19.501400, 19.851400, 10.749200,
+ 18.642400, 13.126600, 18.243600, 6.718600, 3.394600,
+ 6.337600, 7.767200, 0.814000, 3.828200, 0.826200,
+ 8.074400, -1.590800, 5.017800, 0.455400, -0.242000,
+ 0.174800, -9.076400, -4.201600, -3.775200, -4.751800,
+ -5.372400, -8.906800, -6.102400, -5.741200, -9.953400,
+ -3.863400, -13.730400, -16.271000, -7.513600, -3.306800,
+ -13.134000, -10.055200, -6.720200, -8.596600, -10.930800,
+ -1.877600, -4.822600, -13.778800, -21.647000, -10.673600,
+ -15.780000
+ }}
+},
+
+// Precision 13
+{
+ {{
+ 5908.505200, 6007.267200, 6107.347000, 6208.579400, 6311.262200,
+ 6414.551400, 6519.337600, 6625.695200, 6732.598800, 6841.355200,
+ 6950.597200, 7061.308200, 7173.564600, 7287.109000, 7401.821600,
+ 7516.434400, 7633.380200, 7751.296200, 7870.378400, 7990.292000,
+ 8110.790000, 8233.457400, 8356.603600, 8482.271200, 8607.770800,
+ 8735.099000, 8863.185800, 8993.474600, 9123.849600, 9255.679400,
+ 9388.544800, 9522.751600, 9657.310600, 9792.609400, 9930.564200,
+ 10068.794000, 10206.725600, 10347.810000, 10490.319600, 10632.077800,
+ 10775.991600, 10920.466200, 11066.124000, 11213.073000, 11358.036200,
+ 11508.100600, 11659.171600, 11808.751400, 11959.488400, 12112.131400,
+ 12265.037000, 12420.375600, 12578.933000, 12734.311000, 12890.000600,
+ 13047.214400, 13207.309600, 13368.514400, 13528.024000, 13689.847000,
+ 13852.752800, 14018.316800, 14180.537200, 14346.966800, 14513.507400,
+ 14677.867000, 14846.218600, 15017.418600, 15184.971600, 15356.339000,
+ 15529.297200, 15697.357800, 15871.868600, 16042.187000, 16216.409400,
+ 16389.418800, 16565.912600, 16742.327200, 16919.004200, 17094.759200,
+ 17273.965000, 17451.834200, 17634.425400, 17810.598400, 17988.924200,
+ 18171.051000, 18354.793800, 18539.466000, 18721.040800, 18904.997200,
+ 19081.867000, 19271.911800, 19451.869400, 19637.981600, 19821.292200,
+ 20013.129200, 20199.385800, 20387.872600, 20572.951400, 20770.776400,
+ 20955.171400, 21144.751000, 21329.995200, 21520.709000, 21712.701600,
+ 21906.386800, 22096.262600, 22286.052400, 22475.051000, 22665.509800,
+ 22862.849200, 23055.529400, 23249.613800, 23437.848000, 23636.273000,
+ 23826.093000, 24020.329600, 24213.389600, 24411.739200, 24602.961400,
+ 24805.795200, 24998.155200, 25193.958800, 25389.016600, 25585.839200,
+ 25780.697600, 25981.272800, 26175.977000, 26376.525200, 26570.196400,
+ 26773.387000, 26962.981200, 27163.058600, 27368.164000, 27565.053400,
+ 27758.742800, 27961.127600, 28163.232400, 28362.381600, 28565.766800,
+ 28758.644000, 28956.976800, 29163.472200, 29354.702600, 29561.118600,
+ 29767.994800, 29959.998600, 30164.049200, 30366.981800, 30562.533800,
+ 30762.992800, 30976.159200, 31166.274000, 31376.722000, 31570.373400,
+ 31770.809000, 31974.893400, 32179.528600, 32387.544200, 32582.350400,
+ 32794.076000, 32989.952800, 33191.842000, 33392.468400, 33595.659000,
+ 33801.867200, 34000.341400, 34200.092200, 34402.679200, 34610.063800,
+ 34804.008400, 35011.130000, 35218.669000, 35418.663400, 35619.079200,
+ 35830.653400, 36028.496600, 36229.790200, 36438.642200, 36630.776400,
+ 36833.310200, 37048.672800, 37247.391600, 37453.590400, 37669.361400,
+ 37854.552600, 38059.305000, 38268.093600, 38470.251600, 38674.706400,
+ 38876.167000, 39068.379400, 39281.914400, 39492.856600, 39684.862800,
+ 39898.410800, 40093.183600, 40297.685800, 40489.708600, 40717.242400
+ }},
+ {{
+ 5907.505200, 5802.267200, 5697.347000, 5593.579400, 5491.262200,
+ 5390.551400, 5290.337600, 5191.695200, 5093.598800, 4997.355200,
+ 4902.597200, 4808.308200, 4715.564600, 4624.109000, 4533.821600,
+ 4444.434400, 4356.380200, 4269.296200, 4183.378400, 4098.292000,
+ 4014.790000, 3932.457400, 3850.603600, 3771.271200, 3691.770800,
+ 3615.099000, 3538.185800, 3463.474600, 3388.849600, 3315.679400,
+ 3244.544800, 3173.751600, 3103.310600, 3033.609400, 2966.564200,
+ 2900.794000, 2833.725600, 2769.810000, 2707.319600, 2644.077800,
+ 2583.991600, 2523.466200, 2464.124000, 2406.073000, 2347.036200,
+ 2292.100600, 2238.171600, 2182.751400, 2128.488400, 2077.131400,
+ 2025.037000, 1975.375600, 1928.933000, 1879.311000, 1831.000600,
+ 1783.214400, 1738.309600, 1694.514400, 1649.024000, 1606.847000,
+ 1564.752800, 1525.316800, 1482.537200, 1443.966800, 1406.507400,
+ 1365.867000, 1329.218600, 1295.418600, 1257.971600, 1225.339000,
+ 1193.297200, 1156.357800, 1125.868600, 1091.187000, 1061.409400,
+ 1029.418800, 1000.912600, 972.327200, 944.004200, 915.759200,
+ 889.965000, 862.834200, 840.425400, 812.598400, 785.924200,
+ 763.051000, 741.793800, 721.466000, 699.040800, 677.997200,
+ 649.867000, 634.911800, 609.869400, 591.981600, 570.292200,
+ 557.129200, 538.385800, 521.872600, 502.951400, 495.776400,
+ 475.171400, 459.751000, 439.995200, 426.709000, 413.701600,
+ 402.386800, 387.262600, 372.052400, 357.051000, 342.509800,
+ 334.849200, 322.529400, 311.613800, 295.848000, 289.273000,
+ 274.093000, 263.329600, 251.389600, 245.739200, 231.961400,
+ 229.795200, 217.155200, 208.958800, 199.016600, 190.839200,
+ 180.697600, 176.272800, 166.977000, 162.525200, 151.196400,
+ 149.387000, 133.981200, 130.058600, 130.164000, 122.053400,
+ 110.742800, 108.127600, 106.232400, 100.381600, 98.766800,
+ 86.644000, 79.976800, 82.472200, 68.702600, 70.118600,
+ 71.994800, 58.998600, 59.049200, 56.981800, 47.533800,
+ 42.992800, 51.159200, 37.274000, 42.722000, 31.373400,
+ 26.809000, 25.893400, 26.528600, 29.544200, 19.350400,
+ 26.076000, 17.952800, 14.842000, 10.468400, 8.659000,
+ 9.867200, 4.341400, -0.907800, -3.320800, -0.936200,
+ -11.991600, -8.870000, -6.331000, -11.336600, -15.920800,
+ -9.346600, -15.503400, -19.209800, -15.357800, -28.223600,
+ -30.689800, -19.327200, -25.608400, -24.409600, -13.638600,
+ -33.447400, -32.695000, -28.906400, -31.748400, -32.293600,
+ -35.833000, -47.620600, -39.085600, -33.143400, -46.137200,
+ -37.589200, -46.816400, -47.314200, -60.291400, -37.757600
+ }}
+},
+
+// Precision 14
+{
+ {{
+ 11817.475000, 12015.004600, 12215.379200, 12417.750400, 12623.181400,
+ 12830.008600, 13040.007200, 13252.503000, 13466.178000, 13683.273800,
+ 13902.034400, 14123.979800, 14347.394000, 14573.778400, 14802.689400,
+ 15033.682400, 15266.913400, 15502.862400, 15741.494400, 15980.795600,
+ 16223.891600, 16468.631600, 16715.733000, 16965.572600, 17217.204000,
+ 17470.666000, 17727.851600, 17986.788600, 18247.690200, 18510.963200,
+ 18775.304000, 19044.748600, 19314.440800, 19587.202000, 19862.257600,
+ 20135.924000, 20417.032400, 20697.978800, 20979.611200, 21265.027400,
+ 21550.723000, 21841.690600, 22132.162000, 22428.140600, 22722.127000,
+ 23020.560600, 23319.739400, 23620.401400, 23925.272800, 24226.922400,
+ 24535.581000, 24845.505000, 25155.961800, 25470.382800, 25785.970200,
+ 26103.776400, 26420.413200, 26742.018600, 27062.885200, 27388.415000,
+ 27714.602400, 28042.296000, 28365.449400, 28701.152600, 29031.800800,
+ 29364.215600, 29704.497000, 30037.145800, 30380.111000, 30723.816800,
+ 31059.511400, 31404.949800, 31751.675200, 32095.268600, 32444.779200,
+ 32794.767000, 33145.204000, 33498.422600, 33847.650200, 34209.006000,
+ 34560.849000, 34919.483800, 35274.977800, 35635.132200, 35996.326600,
+ 36359.139400, 36722.826600, 37082.851600, 37447.735400, 37815.960600,
+ 38191.069200, 38559.410600, 38924.811200, 39294.672600, 39663.973000,
+ 40042.261000, 40416.203600, 40779.203600, 41161.643600, 41540.901400,
+ 41921.199800, 42294.769800, 42678.526400, 43061.346400, 43432.375000,
+ 43818.432000, 44198.659800, 44583.013800, 44970.479400, 45353.924000,
+ 45729.858000, 46118.222400, 46511.572400, 46900.738600, 47280.696400,
+ 47668.147200, 48055.679600, 48446.943600, 48838.714600, 49217.729600,
+ 49613.779600, 50010.750800, 50410.020800, 50793.788600, 51190.245600,
+ 51583.188200, 51971.079600, 52376.533800, 52763.319000, 53165.553400,
+ 53556.559400, 53948.270200, 54346.352000, 54748.791400, 55138.577000,
+ 55543.482400, 55941.174800, 56333.774600, 56745.155200, 57142.794400,
+ 57545.223600, 57935.995600, 58348.526800, 58737.547400, 59158.596200,
+ 59542.689600, 59958.800400, 60349.378800, 60755.021200, 61147.614400,
+ 61548.194000, 61946.069600, 62348.604200, 62763.603000, 63162.781000,
+ 63560.635000, 63974.348200, 64366.490800, 64771.587600, 65176.734600,
+ 65597.391600, 65995.915000, 66394.038400, 66822.939600, 67203.633600,
+ 67612.203200, 68019.007800, 68420.038800, 68821.220000, 69235.838800,
+ 69640.072400, 70055.155000, 70466.357000, 70863.426600, 71276.248200,
+ 71677.030600, 72080.200600, 72493.021400, 72893.595200, 73314.585600,
+ 73714.985200, 74125.302200, 74521.212200, 74933.681400, 75341.590400,
+ 75743.024400, 76166.027800, 76572.132200, 76973.102800, 77381.628400,
+ 77800.609200, 78189.328000, 78607.096200, 79012.250800, 79407.835800,
+ 79825.725000, 80238.701000, 80646.891000, 81035.643600, 81460.044800,
+ 81876.388400
+ }},
+ {{
+ 11816.475000, 11605.004600, 11395.379200, 11188.750400, 10984.181400,
+ 10782.008600, 10582.007200, 10384.503000, 10189.178000, 9996.273800,
+ 9806.034400, 9617.979800, 9431.394000, 9248.778400, 9067.689400,
+ 8889.682400, 8712.913400, 8538.862400, 8368.494400, 8197.795600,
+ 8031.891600, 7866.631600, 7703.733000, 7544.572600, 7386.204000,
+ 7230.666000, 7077.851600, 6926.788600, 6778.690200, 6631.963200,
+ 6487.304000, 6346.748600, 6206.440800, 6070.202000, 5935.257600,
+ 5799.924000, 5671.032400, 5541.978800, 5414.611200, 5290.027400,
+ 5166.723000, 5047.690600, 4929.162000, 4815.140600, 4699.127000,
+ 4588.560600, 4477.739400, 4369.401400, 4264.272800, 4155.922400,
+ 4055.581000, 3955.505000, 3856.961800, 3761.382800, 3666.970200,
+ 3575.776400, 3482.413200, 3395.018600, 3305.885200, 3221.415000,
+ 3138.602400, 3056.296000, 2970.449400, 2896.152600, 2816.800800,
+ 2740.215600, 2670.497000, 2594.145800, 2527.111000, 2460.816800,
+ 2387.511400, 2322.949800, 2260.675200, 2194.268600, 2133.779200,
+ 2074.767000, 2015.204000, 1959.422600, 1898.650200, 1850.006000,
+ 1792.849000, 1741.483800, 1687.977800, 1638.132200, 1589.326600,
+ 1543.139400, 1496.826600, 1447.851600, 1402.735400, 1361.960600,
+ 1327.069200, 1285.410600, 1241.811200, 1201.672600, 1161.973000,
+ 1130.261000, 1094.203600, 1048.203600, 1020.643600, 990.901400,
+ 961.199800, 924.769800, 899.526400, 872.346400, 834.375000,
+ 810.432000, 780.659800, 756.013800, 733.479400, 707.924000,
+ 673.858000, 652.222400, 636.572400, 615.738600, 586.696400,
+ 564.147200, 541.679600, 523.943600, 505.714600, 475.729600,
+ 461.779600, 449.750800, 439.020800, 412.788600, 400.245600,
+ 383.188200, 362.079600, 357.533800, 334.319000, 327.553400,
+ 308.559400, 291.270200, 279.352000, 271.791400, 252.577000,
+ 247.482400, 236.174800, 218.774600, 220.155200, 208.794400,
+ 201.223600, 182.995600, 185.526800, 164.547400, 176.596200,
+ 150.689600, 157.800400, 138.378800, 134.021200, 117.614400,
+ 108.194000, 97.069600, 89.604200, 95.603000, 84.781000,
+ 72.635000, 77.348200, 59.490800, 55.587600, 50.734600,
+ 61.391600, 50.915000, 39.038400, 58.939600, 29.633600,
+ 28.203200, 26.007800, 17.038800, 9.220000, 13.838800,
+ 8.072400, 14.155000, 15.357000, 3.426600, 6.248200,
+ -2.969400, -8.799400, -5.978600, -14.404800, -3.414400,
+ -13.014800, -11.697800, -25.787800, -22.318600, -24.409600,
+ -31.975600, -18.972200, -22.867800, -30.897200, -32.371600,
+ -22.390800, -43.672000, -35.903800, -39.749200, -54.164200,
+ -45.275000, -42.299000, -44.109000, -64.356400, -49.955200,
+ -42.611600
+ }}
+},
+
+// Precision 15
+{
+ {{
+ 23635.003600, 24030.803400, 24431.474400, 24837.152400, 25246.792800,
+ 25661.326000, 26081.353200, 26505.280600, 26933.989200, 27367.709800,
+ 27805.318000, 28248.799000, 28696.438200, 29148.824400, 29605.513800,
+ 30066.866800, 30534.234400, 31006.320000, 31480.778000, 31962.241800,
+ 32447.332400, 32938.023200, 33432.731000, 33930.728000, 34433.989600,
+ 34944.140200, 35457.558800, 35974.595800, 36497.329600, 37021.909600,
+ 37554.326000, 38088.082600, 38628.881600, 39171.319200, 39723.232600,
+ 40274.555400, 40832.314200, 41390.613000, 41959.590800, 42532.546600,
+ 43102.034400, 43683.507200, 44266.694000, 44851.282200, 45440.786200,
+ 46038.058600, 46640.316400, 47241.064000, 47846.155000, 48454.739600,
+ 49076.916800, 49692.542000, 50317.477800, 50939.650000, 51572.559600,
+ 52210.290600, 52843.739600, 53481.399600, 54127.236000, 54770.406000,
+ 55422.659800, 56078.795800, 56736.717400, 57397.678400, 58064.578400,
+ 58730.308000, 59404.978400, 60077.086400, 60751.915800, 61444.138600,
+ 62115.817000, 62808.774200, 63501.477400, 64187.545400, 64883.662200,
+ 65582.746800, 66274.531800, 66976.927600, 67688.776400, 68402.138000,
+ 69109.627400, 69822.970600, 70543.610800, 71265.520200, 71983.384800,
+ 72708.465600, 73433.384000, 74158.466400, 74896.486800, 75620.956400,
+ 76362.143400, 77098.320400, 77835.766200, 78582.611400, 79323.990200,
+ 80067.865800, 80814.924600, 81567.013600, 82310.853600, 83061.995200,
+ 83821.409600, 84580.860800, 85335.547000, 86092.580200, 86851.650600,
+ 87612.311000, 88381.201600, 89146.329600, 89907.897400, 90676.846000,
+ 91451.415200, 92224.551800, 92995.868600, 93763.506600, 94551.279600,
+ 95315.194400, 96096.180600, 96881.091800, 97665.679000, 98442.680000,
+ 99229.300200, 100011.099400, 100790.638600, 101580.156400, 102377.748400,
+ 103152.139200, 103944.271200, 104730.216000, 105528.633600, 106324.939800,
+ 107117.670600, 107890.398800, 108695.226600, 109485.238000, 110294.787600,
+ 111075.095800, 111878.049600, 112695.286400, 113464.548600, 114270.047400,
+ 115068.608000, 115884.362600, 116673.258800, 117483.371600, 118275.097000,
+ 119085.409200, 119879.280800, 120687.586800, 121499.994400, 122284.916000,
+ 123095.925400, 123912.503800, 124709.045400, 125503.718200, 126323.259000,
+ 127138.941200, 127943.829400, 128755.646000, 129556.535400, 130375.329800,
+ 131161.473400, 131971.196200, 132787.545800, 133588.105600, 134431.351000,
+ 135220.290600, 136023.398000, 136846.655800, 137667.000400, 138463.663000,
+ 139283.715400, 140074.614600, 140901.307200, 141721.854800, 142543.232200,
+ 143356.109600, 144173.741200, 144973.094800, 145794.316200, 146609.571400,
+ 147420.003000, 148237.978400, 149050.569600, 149854.761000, 150663.196600,
+ 151494.075400, 152313.141600, 153112.690200, 153935.720600, 154746.926200,
+ 155559.547000, 156401.974600, 157228.703600, 158008.725400, 158820.750000,
+ 159646.918400, 160470.445800, 161279.534800, 162093.311400, 162918.542000,
+ 163729.284200
+ }},
+ {{
+ 23634.003600, 23210.803400, 22792.474400, 22379.152400, 21969.792800,
+ 21565.326000, 21165.353200, 20770.280600, 20379.989200, 19994.709800,
+ 19613.318000, 19236.799000, 18865.438200, 18498.824400, 18136.513800,
+ 17778.866800, 17426.234400, 17079.320000, 16734.778000, 16397.241800,
+ 16063.332400, 15734.023200, 15409.731000, 15088.728000, 14772.989600,
+ 14464.140200, 14157.558800, 13855.595800, 13559.329600, 13264.909600,
+ 12978.326000, 12692.082600, 12413.881600, 12137.319200, 11870.232600,
+ 11602.555400, 11340.314200, 11079.613000, 10829.590800, 10583.546600,
+ 10334.034400, 10095.507200, 9859.694000, 9625.282200, 9395.786200,
+ 9174.058600, 8957.316400, 8738.064000, 8524.155000, 8313.739600,
+ 8116.916800, 7913.542000, 7718.477800, 7521.650000, 7335.559600,
+ 7154.290600, 6968.739600, 6786.399600, 6613.236000, 6437.406000,
+ 6270.659800, 6107.795800, 5945.717400, 5787.678400, 5635.578400,
+ 5482.308000, 5337.978400, 5190.086400, 5045.915800, 4919.138600,
+ 4771.817000, 4645.774200, 4518.477400, 4385.545400, 4262.662200,
+ 4142.746800, 4015.531800, 3897.927600, 3790.776400, 3685.138000,
+ 3573.627400, 3467.970600, 3368.610800, 3271.520200, 3170.384800,
+ 3076.465600, 2982.384000, 2888.466400, 2806.486800, 2711.956400,
+ 2634.143400, 2551.320400, 2469.766200, 2396.611400, 2318.990200,
+ 2243.865800, 2171.924600, 2105.013600, 2028.853600, 1960.995200,
+ 1901.409600, 1841.860800, 1777.547000, 1714.580200, 1654.650600,
+ 1596.311000, 1546.201600, 1492.329600, 1433.897400, 1383.846000,
+ 1339.415200, 1293.551800, 1245.868600, 1193.506600, 1162.279600,
+ 1107.194400, 1069.180600, 1035.091800, 999.679000, 957.680000,
+ 925.300200, 888.099400, 848.638600, 818.156400, 796.748400,
+ 752.139200, 725.271200, 692.216000, 671.633600, 647.939800,
+ 621.670600, 575.398800, 561.226600, 532.238000, 521.787600,
+ 483.095800, 467.049600, 465.286400, 415.548600, 401.047400,
+ 380.608000, 377.362600, 347.258800, 338.371600, 310.097000,
+ 301.409200, 276.280800, 265.586800, 258.994400, 223.916000,
+ 215.925400, 213.503800, 191.045400, 166.718200, 166.259000,
+ 162.941200, 148.829400, 141.646000, 123.535400, 122.329800,
+ 89.473400, 80.196200, 77.545800, 59.105600, 83.351000,
+ 52.290600, 36.398000, 40.655800, 42.000400, 19.663000,
+ 19.715400, -8.385400, -0.692800, 0.854800, 3.232200,
+ -3.890400, -5.258800, -24.905200, -22.683800, -26.428600,
+ -34.997000, -37.021600, -43.430400, -58.239000, -68.803400,
+ -56.924600, -57.858400, -77.309800, -73.279400, -81.073800,
+ -87.453000, -65.025400, -57.296400, -96.274600, -103.250000,
+ -96.081600, -91.554200, -102.465200, -107.688600, -101.458000,
+ -109.715800
+ }}
+},
+
+// Precision 16
+{
+ {{
+ 47271.000000, 48062.358400, 48862.707400, 49673.152000, 50492.841600,
+ 51322.951400, 52161.030000, 53009.407000, 53867.634800, 54734.206000,
+ 55610.514400, 56496.209600, 57390.795000, 58297.268000, 59210.644800,
+ 60134.665000, 61068.024800, 62010.447200, 62962.520400, 63923.574200,
+ 64895.019400, 65876.418200, 66862.613600, 67862.696800, 68868.890800,
+ 69882.854400, 70911.271000, 71944.092400, 72990.032600, 74040.692000,
+ 75100.633600, 76174.782600, 77252.599800, 78340.297400, 79438.257200,
+ 80545.497600, 81657.279600, 82784.633600, 83915.515000, 85059.736200,
+ 86205.936800, 87364.442400, 88530.335800, 89707.374400, 90885.963800,
+ 92080.197000, 93275.573800, 94479.391000, 95695.918000, 96919.223600,
+ 98148.460200, 99382.347400, 100625.697400, 101878.028400, 103141.627800,
+ 104409.458800, 105686.288200, 106967.540200, 108261.603200, 109548.157800,
+ 110852.072800, 112162.231000, 113479.007200, 114806.262600, 116137.907200,
+ 117469.504800, 118813.518600, 120165.487600, 121516.255600, 122875.766000,
+ 124250.544400, 125621.222200, 127003.235200, 128387.848000, 129775.264400,
+ 131181.777600, 132577.308600, 133979.945800, 135394.113200, 136800.907800,
+ 138233.217000, 139668.530800, 141085.212000, 142535.212200, 143969.068400,
+ 145420.287200, 146878.154200, 148332.757200, 149800.320200, 151269.660000,
+ 152743.610400, 154213.094800, 155690.288000, 157169.424600, 158672.175600,
+ 160160.059000, 161650.685400, 163145.777200, 164645.672600, 166159.195200,
+ 167682.157800, 169177.332800, 170700.011800, 172228.896400, 173732.666400,
+ 175265.555600, 176787.799000, 178317.111000, 179856.691400, 181400.865000,
+ 182943.461200, 184486.742000, 186033.469800, 187583.788600, 189148.186800,
+ 190688.452600, 192250.192600, 193810.904200, 195354.297200, 196938.768200,
+ 198493.589800, 200079.282400, 201618.912000, 203205.549200, 204765.579800,
+ 206356.112400, 207929.306400, 209498.719600, 211086.229000, 212675.132400,
+ 214256.789200, 215826.239200, 217412.847400, 218995.672400, 220618.603800,
+ 222207.116600, 223781.036400, 225387.433200, 227005.792800, 228590.433600,
+ 230217.873800, 231805.105400, 233408.900000, 234995.343200, 236601.495600,
+ 238190.790400, 239817.254800, 241411.283200, 243002.406600, 244640.188400,
+ 246255.312800, 247849.350800, 249479.973400, 251106.882200, 252705.027000,
+ 254332.924200, 255935.129000, 257526.901400, 259154.772000, 260777.625000,
+ 262390.253000, 264004.490600, 265643.590000, 267255.407600, 268873.426000,
+ 270470.725200, 272106.480400, 273722.445600, 275337.794000, 276945.703800,
+ 278592.915400, 280204.372600, 281841.160600, 283489.171000, 285130.171600,
+ 286735.336200, 288364.716400, 289961.181400, 291595.552400, 293285.683000,
+ 294899.666800, 296499.343400, 298128.046200, 299761.894600, 301394.242400,
+ 302997.674800, 304615.147800, 306269.772400, 307886.114000, 309543.102800,
+ 311153.286200, 312782.854600, 314421.200800, 316033.243800, 317692.963600,
+ 319305.264800, 320948.740600, 322566.336400, 324228.422400, 325847.154200
+ }},
+ {{
+ 47270.000000, 46423.358400, 45585.707400, 44757.152000, 43938.841600,
+ 43130.951400, 42330.030000, 41540.407000, 40759.634800, 39988.206000,
+ 39226.514400, 38473.209600, 37729.795000, 36997.268000, 36272.644800,
+ 35558.665000, 34853.024800, 34157.447200, 33470.520400, 32793.574200,
+ 32127.019400, 31469.418200, 30817.613600, 30178.696800, 29546.890800,
+ 28922.854400, 28312.271000, 27707.092400, 27114.032600, 26526.692000,
+ 25948.633600, 25383.782600, 24823.599800, 24272.297400, 23732.257200,
+ 23201.497600, 22674.279600, 22163.633600, 21656.515000, 21161.736200,
+ 20669.936800, 20189.442400, 19717.335800, 19256.374400, 18795.963800,
+ 18352.197000, 17908.573800, 17474.391000, 17052.918000, 16637.223600,
+ 16228.460200, 15823.347400, 15428.697400, 15043.028400, 14667.627800,
+ 14297.458800, 13935.288200, 13578.540200, 13234.603200, 12882.157800,
+ 12548.072800, 12219.231000, 11898.007200, 11587.262600, 11279.907200,
+ 10973.504800, 10678.518600, 10392.487600, 10105.255600, 9825.766000,
+ 9562.544400, 9294.222200, 9038.235200, 8784.848000, 8533.264400,
+ 8301.777600, 8058.308600, 7822.945800, 7599.113200, 7366.907800,
+ 7161.217000, 6957.530800, 6736.212000, 6548.212200, 6343.068400,
+ 6156.287200, 5975.154200, 5791.757200, 5621.320200, 5451.660000,
+ 5287.610400, 5118.094800, 4957.288000, 4798.424600, 4662.175600,
+ 4512.059000, 4364.685400, 4220.777200, 4082.672600, 3957.195200,
+ 3842.157800, 3699.332800, 3583.011800, 3473.896400, 3338.666400,
+ 3233.555600, 3117.799000, 3008.111000, 2909.691400, 2814.865000,
+ 2719.461200, 2624.742000, 2532.469800, 2444.788600, 2370.186800,
+ 2272.452600, 2196.192600, 2117.904200, 2023.297200, 1969.768200,
+ 1885.589800, 1833.282400, 1733.912000, 1682.549200, 1604.579800,
+ 1556.112400, 1491.306400, 1421.719600, 1371.229000, 1322.132400,
+ 1264.789200, 1196.239200, 1143.847400, 1088.672400, 1073.603800,
+ 1023.116600, 959.036400, 927.433200, 906.792800, 853.433600,
+ 841.873800, 791.105400, 756.900000, 704.343200, 672.495600,
+ 622.790400, 611.254800, 567.283200, 519.406600, 519.188400,
+ 495.312800, 451.350800, 443.973400, 431.882200, 392.027000,
+ 380.924200, 345.129000, 298.901400, 287.772000, 272.625000,
+ 247.253000, 222.490600, 223.590000, 196.407600, 176.426000,
+ 134.725200, 132.480400, 110.445600, 86.794000, 56.703800,
+ 64.915400, 38.372600, 37.160600, 46.171000, 49.171600,
+ 15.336200, 6.716400, -34.818600, -39.447600, 12.683000,
+ -12.333200, -50.656600, -59.953800, -65.105400, -70.757600,
+ -106.325200, -126.852200, -110.227600, -132.886000, -113.897200,
+ -142.713800, -151.145400, -150.799200, -177.756200, -156.036400,
+ -182.735200, -177.259400, -198.663600, -174.577600, -193.845800
+ }}
+},
+
+// Precision 17
+{
+ {{
+ 94542.000000, 96125.811000, 97728.019000, 99348.558000, 100987.970500,
+ 102646.756500, 104324.512500, 106021.743500, 107736.786500, 109469.272000,
+ 111223.946500, 112995.219000, 114787.432000, 116593.152000, 118422.710000,
+ 120267.234500, 122134.676500, 124020.937000, 125927.270500, 127851.255000,
+ 129788.948500, 131751.016000, 133726.822500, 135722.592000, 137736.789000,
+ 139770.568000, 141821.518000, 143891.343000, 145982.141500, 148095.387000,
+ 150207.526000, 152355.649000, 154515.641500, 156696.050000, 158887.757500,
+ 161098.159000, 163329.852000, 165569.053000, 167837.400500, 170121.616500,
+ 172420.459500, 174732.626500, 177062.770000, 179412.502000, 181774.035000,
+ 184151.939000, 186551.689500, 188965.691000, 191402.809500, 193857.949000,
+ 196305.077500, 198774.671500, 201271.258500, 203764.780000, 206299.369500,
+ 208818.136500, 211373.115000, 213946.746500, 216532.076000, 219105.541000,
+ 221714.537500, 224337.513500, 226977.512500, 229613.065500, 232270.268500,
+ 234952.206500, 237645.355500, 240331.192500, 243034.517000, 245756.072500,
+ 248517.686500, 251232.737000, 254011.395500, 256785.995000, 259556.440000,
+ 262368.335000, 265156.911000, 267965.266000, 270785.583000, 273616.049500,
+ 276487.483500, 279346.639000, 282202.509000, 285074.388500, 287942.285500,
+ 290856.018000, 293774.034500, 296678.514500, 299603.635500, 302552.657500,
+ 305492.978500, 308466.860500, 311392.581000, 314347.538000, 317319.429500,
+ 320285.978500, 323301.732500, 326298.323500, 329301.310500, 332301.987000,
+ 335309.791000, 338370.762000, 341382.923000, 344431.126500, 347464.154500,
+ 350507.280000, 353619.234500, 356631.200500, 359685.203000, 362776.784500,
+ 365886.488000, 368958.225500, 372060.682500, 375165.433500, 378237.935000,
+ 381328.311000, 384430.522500, 387576.425000, 390683.242000, 393839.648000,
+ 396977.842500, 400101.980500, 403271.296000, 406409.842500, 409529.548500,
+ 412678.700000, 415847.423000, 419020.803500, 422157.081000, 425337.749000,
+ 428479.616500, 431700.902000, 434893.191500, 438049.582000, 441210.541500,
+ 444379.254500, 447577.356000, 450741.931000, 453959.548000, 457137.093500,
+ 460329.846000, 463537.481500, 466732.334500, 469960.561500, 473164.681000,
+ 476347.634500, 479496.173000, 482813.164500, 486025.699500, 489249.488500,
+ 492460.194500, 495675.880500, 498908.007500, 502131.802000, 505374.385500,
+ 508550.991500, 511806.730500, 515026.776000, 518217.000500, 521523.985500,
+ 524705.985500, 527950.997000, 531210.026500, 534472.497000, 537750.731500,
+ 540926.922000, 544207.094000, 547429.434500, 550666.374500, 553975.347500,
+ 557150.718500, 560399.616500, 563662.697000, 566916.739500, 570146.121500,
+ 573447.425000, 576689.624500, 579874.574500, 583202.337000, 586503.025500,
+ 589715.635000, 592910.161000, 596214.388500, 599488.035000, 602740.920000,
+ 605983.068500, 609248.670000, 612491.360500, 615787.912000, 619107.524500,
+ 622307.955500, 625577.333000, 628840.438500, 632085.215500, 635317.613500,
+ 638691.719500, 641887.467000, 645139.940500, 648441.546000, 651666.252000,
+ 654941.845000
+ }},
+ {{
+ 94541.000000, 92848.811000, 91174.019000, 89517.558000, 87879.970500,
+ 86262.756500, 84663.512500, 83083.743500, 81521.786500, 79977.272000,
+ 78455.946500, 76950.219000, 75465.432000, 73994.152000, 72546.710000,
+ 71115.234500, 69705.676500, 68314.937000, 66944.270500, 65591.255000,
+ 64252.948500, 62938.016000, 61636.822500, 60355.592000, 59092.789000,
+ 57850.568000, 56624.518000, 55417.343000, 54231.141500, 53067.387000,
+ 51903.526000, 50774.649000, 49657.641500, 48561.050000, 47475.757500,
+ 46410.159000, 45364.852000, 44327.053000, 43318.400500, 42325.616500,
+ 41348.459500, 40383.626500, 39436.770000, 38509.502000, 37594.035000,
+ 36695.939000, 35818.689500, 34955.691000, 34115.809500, 33293.949000,
+ 32465.077500, 31657.671500, 30877.258500, 30093.780000, 29351.369500,
+ 28594.136500, 27872.115000, 27168.746500, 26477.076000, 25774.541000,
+ 25106.537500, 24452.513500, 23815.512500, 23174.065500, 22555.268500,
+ 21960.206500, 21376.355500, 20785.192500, 20211.517000, 19657.072500,
+ 19141.686500, 18579.737000, 18081.395500, 17578.995000, 17073.440000,
+ 16608.335000, 16119.911000, 15651.266000, 15194.583000, 14749.049500,
+ 14343.483500, 13925.639000, 13504.509000, 13099.388500, 12691.285500,
+ 12328.018000, 11969.034500, 11596.514500, 11245.635500, 10917.657500,
+ 10580.978500, 10277.860500, 9926.581000, 9605.538000, 9300.429500,
+ 8989.978500, 8728.732500, 8448.323500, 8175.310500, 7898.987000,
+ 7629.791000, 7413.762000, 7149.923000, 6921.126500, 6677.154500,
+ 6443.280000, 6278.234500, 6014.200500, 5791.203000, 5605.784500,
+ 5438.488000, 5234.225500, 5059.682500, 4887.433500, 4682.935000,
+ 4496.311000, 4322.522500, 4191.425000, 4021.242000, 3900.648000,
+ 3762.842500, 3609.980500, 3502.296000, 3363.842500, 3206.548500,
+ 3079.700000, 2971.423000, 2867.803500, 2727.081000, 2630.749000,
+ 2496.616500, 2440.902000, 2356.191500, 2235.582000, 2120.541500,
+ 2012.254500, 1933.356000, 1820.931000, 1761.548000, 1663.093500,
+ 1578.846000, 1509.481500, 1427.334500, 1379.561500, 1306.681000,
+ 1212.634500, 1084.173000, 1124.164500, 1060.699500, 1007.488500,
+ 941.194500, 879.880500, 836.007500, 782.802000, 748.385500,
+ 647.991500, 626.730500, 570.776000, 484.000500, 513.985500,
+ 418.985500, 386.997000, 370.026500, 355.497000, 356.731500,
+ 255.922000, 259.094000, 205.434500, 165.374500, 197.347500,
+ 95.718500, 67.616500, 54.697000, 31.739500, -15.878500,
+ 8.425000, -26.375500, -118.425500, -66.663000, -42.974500,
+ -107.365000, -189.839000, -162.611500, -164.965000, -189.080000,
+ -223.931500, -235.330000, -269.639500, -249.088000, -206.475500,
+ -283.044500, -290.667000, -304.561500, -336.784500, -380.386500,
+ -283.280500, -364.533000, -389.059500, -364.454000, -415.748000,
+ -417.155000
+ }}
+},
+
+// Precision 18
+{
+ {{
+ 189084.000000, 192250.913000, 195456.774000, 198696.946000,
+ 201977.762000, 205294.444000, 208651.754000, 212042.099000,
+ 215472.269000, 218941.910000, 222443.912000, 225996.845000,
+ 229568.199000, 233193.568000, 236844.457000, 240543.233000,
+ 244279.475000, 248044.270000, 251854.588000, 255693.200000,
+ 259583.619000, 263494.621000, 267445.385000, 271454.061000,
+ 275468.769000, 279549.456000, 283646.446000, 287788.198000,
+ 291966.099000, 296181.164000, 300431.469000, 304718.618000,
+ 309024.004000, 313393.508000, 317760.803000, 322209.731000,
+ 326675.061000, 331160.627000, 335654.470000, 340241.442000,
+ 344841.833000, 349467.132000, 354130.629000, 358819.432000,
+ 363574.626000, 368296.587000, 373118.482000, 377914.930000,
+ 382782.301000, 387680.669000, 392601.981000, 397544.323000,
+ 402529.115000, 407546.018000, 412593.658000, 417638.657000,
+ 422762.865000, 427886.169000, 433017.167000, 438213.273000,
+ 443441.254000, 448692.421000, 453937.533000, 459239.049000,
+ 464529.569000, 469910.083000, 475274.030000, 480684.473000,
+ 486070.260000, 491515.237000, 496995.651000, 502476.617000,
+ 507973.609000, 513497.190000, 519083.233000, 524726.509000,
+ 530305.505000, 535945.728000, 541584.404000, 547274.055000,
+ 552967.236000, 558667.862000, 564360.216000, 570128.148000,
+ 575965.080000, 581701.952000, 587532.523000, 593361.144000,
+ 599246.128000, 605033.418000, 610958.779000, 616837.117000,
+ 622772.818000, 628672.040000, 634675.369000, 640574.831000,
+ 646585.739000, 652574.547000, 658611.217000, 664642.684000,
+ 670713.914000, 676737.681000, 682797.313000, 688837.897000,
+ 694917.874000, 701009.882000, 707173.648000, 713257.254000,
+ 719415.392000, 725636.761000, 731710.697000, 737906.209000,
+ 744103.074000, 750313.390000, 756504.185000, 762712.579000,
+ 768876.985000, 775167.859000, 781359.000000, 787615.959000,
+ 793863.597000, 800245.477000, 806464.582000, 812785.294000,
+ 819005.925000, 825403.057000, 831676.197000, 837936.284000,
+ 844266.968000, 850642.711000, 856959.756000, 863322.774000,
+ 869699.931000, 876102.478000, 882355.787000, 888694.463000,
+ 895159.952000, 901536.143000, 907872.631000, 914293.672000,
+ 920615.140000, 927130.974000, 933409.404000, 939922.178000,
+ 946331.470000, 952745.930000, 959209.264000, 965590.224000,
+ 972077.284000, 978501.961000, 984953.190000, 991413.271000,
+ 997817.479000, 1004222.658000, 1010725.676000, 1017177.138000,
+ 1023612.529000, 1030098.236000, 1036493.719000, 1043112.207000,
+ 1049537.036000, 1056008.096000, 1062476.184000, 1068942.337000,
+ 1075524.950000, 1081932.864000, 1088426.025000, 1094776.005000,
+ 1101327.448000, 1107901.673000, 1114423.639000, 1120884.602000,
+ 1127324.923000, 1133794.240000, 1140328.886000, 1146849.376000,
+ 1153346.682000, 1159836.502000, 1166478.703000, 1172953.304000,
+ 1179391.502000, 1185950.982000, 1192544.052000, 1198913.410000,
+ 1205430.994000, 1212015.525000, 1218674.042000, 1225121.683000,
+ 1231551.101000, 1238126.379000, 1244673.795000, 1251260.649000,
+ 1257697.860000, 1264320.983000, 1270736.319000, 1277274.694000,
+ 1283804.950000, 1290211.514000, 1296858.568000, 1303455.691000
+ }},
+ {{
+ 189083.000000, 185696.913000, 182348.774000, 179035.946000, 175762.762000,
+ 172526.444000, 169329.754000, 166166.099000, 163043.269000, 159958.910000,
+ 156907.912000, 153906.845000, 150924.199000, 147996.568000, 145093.457000,
+ 142239.233000, 139421.475000, 136632.270000, 133889.588000, 131174.200000,
+ 128511.619000, 125868.621000, 123265.385000, 120721.061000, 118181.769000,
+ 115709.456000, 113252.446000, 110840.198000, 108465.099000, 106126.164000,
+ 103823.469000, 101556.618000, 99308.004000, 97124.508000, 94937.803000,
+ 92833.731000, 90745.061000, 88677.627000, 86617.470000, 84650.442000,
+ 82697.833000, 80769.132000, 78879.629000, 77014.432000, 75215.626000,
+ 73384.587000, 71652.482000, 69895.930000, 68209.301000, 66553.669000,
+ 64921.981000, 63310.323000, 61742.115000, 60205.018000, 58698.658000,
+ 57190.657000, 55760.865000, 54331.169000, 52908.167000, 51550.273000,
+ 50225.254000, 48922.421000, 47614.533000, 46362.049000, 45098.569000,
+ 43926.083000, 42736.030000, 41593.473000, 40425.260000, 39316.237000,
+ 38243.651000, 37170.617000, 36114.609000, 35084.190000, 34117.233000,
+ 33206.509000, 32231.505000, 31318.728000, 30403.404000, 29540.055000,
+ 28679.236000, 27825.862000, 26965.216000, 26179.148000, 25462.080000,
+ 24645.952000, 23922.523000, 23198.144000, 22529.128000, 21762.418000,
+ 21134.779000, 20459.117000, 19840.818000, 19187.040000, 18636.369000,
+ 17982.831000, 17439.739000, 16874.547000, 16358.217000, 15835.684000,
+ 15352.914000, 14823.681000, 14329.313000, 13816.897000, 13342.874000,
+ 12880.882000, 12491.648000, 12021.254000, 11625.392000, 11293.761000,
+ 10813.697000, 10456.209000, 10099.074000, 9755.390000, 9393.185000,
+ 9047.579000, 8657.985000, 8395.859000, 8033.000000, 7736.959000,
+ 7430.597000, 7258.477000, 6924.582000, 6691.294000, 6357.925000,
+ 6202.057000, 5921.197000, 5628.284000, 5404.968000, 5226.711000,
+ 4990.756000, 4799.774000, 4622.931000, 4472.478000, 4171.787000,
+ 3957.463000, 3868.952000, 3691.143000, 3474.631000, 3341.672000,
+ 3109.140000, 3071.974000, 2796.404000, 2756.178000, 2611.470000,
+ 2471.930000, 2382.264000, 2209.224000, 2142.284000, 2013.961000,
+ 1911.190000, 1818.271000, 1668.479000, 1519.658000, 1469.676000,
+ 1367.138000, 1248.529000, 1181.236000, 1022.719000, 1088.207000,
+ 959.036000, 876.096000, 791.184000, 703.337000, 731.950000,
+ 586.864000, 526.025000, 323.005000, 320.448000, 340.673000,
+ 309.639000, 216.602000, 102.923000, 19.240000, -0.114000,
+ -32.624000, -89.318000, -153.498000, -64.297000, -143.696000,
+ -259.498000, -253.018000, -213.948000, -397.590000, -434.006000,
+ -403.475000, -297.958000, -404.317000, -528.899000, -506.621000,
+ -513.205000, -479.351000, -596.140000, -527.017000, -664.681000,
+ -680.306000, -704.050000, -850.486000, -757.432000, -713.309000
+ }}
+}
diff --git a/library/cpp/hyperloglog/hyperloglog_ut.cpp b/library/cpp/hyperloglog/hyperloglog_ut.cpp
new file mode 100644
index 0000000000..b987aa0fa4
--- /dev/null
+++ b/library/cpp/hyperloglog/hyperloglog_ut.cpp
@@ -0,0 +1,67 @@
+#include "hyperloglog.h"
+
+#include <util/generic/buffer.h>
+#include <util/random/mersenne.h>
+#include <util/stream/buffer.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <cmath>
+
+Y_UNIT_TEST_SUITE(THyperLogLog) {
+ Y_UNIT_TEST(TestPrecision18) {
+ TMersenne<ui64> rand;
+
+ auto counter = THyperLogLog::Create(18);
+
+ static const std::pair<ui64, ui64> POINTS[] = {
+ {10, 10},
+ {100, 100},
+ {1000, 998},
+ {10000, 9978},
+ {100000, 99995},
+ {1000000, 997017},
+ {10000000, 9983891},
+ {100000000, 100315572},
+ {1000000000, 998791445},
+ //1:37: {10000000000, 10015943904}
+ };
+ ui64 unique = 0;
+ for (const auto& pnt : POINTS) {
+ while (unique < pnt.first) {
+ const auto val = rand();
+ counter.Update(val);
+ ++unique;
+ }
+ const auto estimation = counter.Estimate();
+ const auto delta = i64(estimation) - i64(unique);
+ const auto error = double(delta) / unique;
+ UNIT_ASSERT(std::abs(error) < 0.0032);
+ UNIT_ASSERT_EQUAL(estimation, pnt.second);
+ }
+ {
+ auto counter2 = THyperLogLog::Create(18);
+ while (unique < 2000000000) {
+ const auto val = rand();
+ counter2.Update(val);
+ ++unique;
+ }
+ const auto estimation = counter2.Estimate();
+ UNIT_ASSERT_EQUAL(estimation, 1000013484);
+
+ counter.Merge(counter2);
+ UNIT_ASSERT_EQUAL(counter.Estimate(), 1998488794);
+ }
+
+ {
+ TBufferStream stream;
+ counter.Save(stream);
+ UNIT_ASSERT_EQUAL(stream.Buffer().Size(), 1 + (1 << 18));
+
+ stream.Rewind();
+ const auto copy = THyperLogLog::Load(stream);
+
+ UNIT_ASSERT_EQUAL(counter.Estimate(), copy.Estimate());
+ }
+ }
+}
diff --git a/library/cpp/hyperloglog/ut/ya.make b/library/cpp/hyperloglog/ut/ya.make
new file mode 100644
index 0000000000..f5f1c0d25a
--- /dev/null
+++ b/library/cpp/hyperloglog/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/hyperloglog)
+
+OWNER(
+ anskor
+ g:images-followers g:images-robot g:images-search-quality g:images-nonsearch-quality
+)
+
+SRCS(
+ hyperloglog_ut.cpp
+)
+
+END()
diff --git a/library/cpp/hyperloglog/ya.make b/library/cpp/hyperloglog/ya.make
new file mode 100644
index 0000000000..98dbb68c48
--- /dev/null
+++ b/library/cpp/hyperloglog/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(
+ anskor
+ g:images-followers g:images-robot g:images-search-quality g:images-nonsearch-quality
+)
+
+SRCS(
+ hyperloglog.h
+ hyperloglog.cpp
+)
+
+END()
diff --git a/library/cpp/int128/README.md b/library/cpp/int128/README.md
new file mode 100644
index 0000000000..e1c4dcbb78
--- /dev/null
+++ b/library/cpp/int128/README.md
@@ -0,0 +1,6 @@
+https://st.yandex-team.ru/IGNIETFERRO-697
+
+(Объединение разрозненных по Аркадии библиотек для поддержки 128-битного целого)
+
+Идея классов ui128 / i128 в том, чтобы они работали так, как будто это компиляторные интовые типы.
+Т.е. у этих классов не должно быть публичных функций типа ui128::GetHigh(), конструкторов из нескольких параметров и так далее.
diff --git a/library/cpp/int128/bench/main.cpp b/library/cpp/int128/bench/main.cpp
new file mode 100644
index 0000000000..be4f8d1500
--- /dev/null
+++ b/library/cpp/int128/bench/main.cpp
@@ -0,0 +1,45 @@
+#include <library/cpp/int128/int128.h>
+#include <library/cpp/testing/benchmark/bench.h>
+
+#include <util/generic/xrange.h>
+#include <util/system/compiler.h>
+
+Y_CPU_BENCHMARK(LibraryDivisionUnsigned128, iface) {
+ ui128 b = {0, 10'000'000};
+ for (const auto i : xrange(iface.Iterations())) {
+ ui128 a = i * 10'000'000;
+ ui128 c = a / b;
+ Y_FAKE_READ(c);
+ }
+}
+
+#if defined(Y_HAVE_INT128)
+Y_CPU_BENCHMARK(IntrinsicDivisionUnsigned128, iface) {
+ unsigned __int128 b = 10'000'000;
+ for (const auto i : xrange(iface.Iterations())) {
+ unsigned __int128 a = i * 10'000'000;
+ unsigned __int128 c = a / b;
+ Y_FAKE_READ(c);
+ }
+}
+#endif // Y_HAVE_INT128
+
+Y_CPU_BENCHMARK(LibraryDivisionSigned128, iface) {
+ i128 b = {0, 10'000'000};
+ for (const auto i : xrange(iface.Iterations())) {
+ i128 a = i * 10'000'000;
+ i128 c = a / b;
+ Y_FAKE_READ(c);
+ }
+}
+
+#if defined(Y_HAVE_INT128)
+Y_CPU_BENCHMARK(IntrinsicDivisionSigned128, iface) {
+ signed __int128 b = 10'000'000;
+ for (const auto i : xrange(iface.Iterations())) {
+ signed __int128 a = i * 10'000'000;
+ signed __int128 c = a / b;
+ Y_FAKE_READ(c);
+ }
+}
+#endif // Y_HAVE_INT128
diff --git a/library/cpp/int128/bench/ya.make b/library/cpp/int128/bench/ya.make
new file mode 100644
index 0000000000..4800e7883d
--- /dev/null
+++ b/library/cpp/int128/bench/ya.make
@@ -0,0 +1,15 @@
+OWNER(
+ vladon
+)
+
+Y_BENCHMARK()
+
+SRCS(
+ main.cpp
+)
+
+PEERDIR(
+ library/cpp/int128
+)
+
+END()
diff --git a/library/cpp/int128/int128.cpp b/library/cpp/int128/int128.cpp
new file mode 100644
index 0000000000..a28a389fe8
--- /dev/null
+++ b/library/cpp/int128/int128.cpp
@@ -0,0 +1,62 @@
+#include "int128.h"
+
+#include <tuple>
+
+IOutputStream& operator<<(IOutputStream& out, const ui128& other) {
+ // see http://stackoverflow.com/questions/4361441/c-print-a-biginteger-in-base-10
+ // and http://stackoverflow.com/questions/8023414/how-to-convert-a-128-bit-integer-to-a-decimal-ascii-string-in-c
+ int d[39] = {0};
+ int i;
+ int j;
+ for (i = 63; i > -1; i--) {
+ if ((other.High_ >> i) & 1)
+ ++d[0];
+ for (j = 0; j < 39; j++)
+ d[j] *= 2;
+ for (j = 0; j < 38; j++) {
+ d[j + 1] += d[j] / 10;
+ d[j] %= 10;
+ }
+ }
+ for (i = 63; i > -1; i--) {
+ if ((other.Low_ >> i) & 1)
+ ++d[0];
+ if (i > 0)
+ for (j = 0; j < 39; j++)
+ d[j] *= 2;
+ for (j = 0; j < 38; j++) {
+ d[j + 1] += d[j] / 10;
+ d[j] %= 10;
+ }
+ }
+ for (i = 38; i > 0; i--)
+ if (d[i] > 0)
+ break;
+ for (; i > -1; i--)
+ out << static_cast<char>('0' + d[i]);
+
+ return out;
+}
+
+void TSerializer<ui128>::Save(IOutputStream* out, const ui128& Number) {
+ ::Save(out, GetHigh(Number));
+ ::Save(out, GetLow(Number));
+}
+
+void TSerializer<ui128>::Load(IInputStream* in, ui128& Number) {
+ ui64 High;
+ ui64 Low;
+ ::Load(in, High);
+ ::Load(in, Low);
+ Number = ui128(High, Low);
+}
+
+IOutputStream& operator<<(IOutputStream& out, const i128& other)
+{
+ if (other >= 0) {
+ out << ui128{other};
+ } else {
+ out << '-' << ui128{-other};
+ }
+ return out;
+}
diff --git a/library/cpp/int128/int128.h b/library/cpp/int128/int128.h
new file mode 100644
index 0000000000..f1121fc0c6
--- /dev/null
+++ b/library/cpp/int128/int128.h
@@ -0,0 +1,1278 @@
+#pragma once
+
+#include "int128_util.h"
+
+#include <util/generic/bitops.h>
+#include <util/system/compiler.h>
+#include <util/system/defaults.h>
+#include <util/stream/output.h>
+#include <util/string/cast.h>
+#include <util/string/builder.h>
+#include <util/str_stl.h>
+#include <util/ysaveload.h>
+
+#include <cfenv>
+#include <climits>
+#include <cmath>
+#include <limits>
+#include <type_traits>
+
+#if !defined(_little_endian_) && !defined(_big_endian_)
+ static_assert(false, "Platform endianness is not supported");
+#endif
+
+template <bool IsSigned>
+class TInteger128 {
+public:
+ TInteger128() noexcept = default;
+
+#if defined(_little_endian_)
+ constexpr TInteger128(const ui64 high, const ui64 low) noexcept
+ : Low_(low)
+ , High_(high)
+ {
+ }
+#elif defined(_big_endian_)
+ constexpr TInteger128(const ui64 high, const ui64 low) noexcept
+ : High_(high)
+ , Low_(low)
+ {
+ }
+#endif
+
+ constexpr TInteger128(const TInteger128<!IsSigned> other) noexcept
+ : TInteger128{GetHigh(other), GetLow(other)}
+ {
+ }
+
+#if defined(_little_endian_)
+ constexpr TInteger128(const char other) noexcept
+ : Low_{static_cast<ui64>(other)}
+ , High_{0}
+ {
+ }
+
+ constexpr TInteger128(const ui8 other) noexcept
+ : Low_{other}
+ , High_{0}
+ {
+ }
+
+ constexpr TInteger128(const ui16 other) noexcept
+ : Low_{other}
+ , High_{0}
+ {
+ }
+
+ constexpr TInteger128(const ui32 other) noexcept
+ : Low_{other}
+ , High_{0}
+ {
+ }
+
+ constexpr TInteger128(const ui64 other) noexcept
+ : Low_{other}
+ , High_{0}
+ {
+ }
+
+#if defined(Y_HAVE_INT128)
+ constexpr TInteger128(const unsigned __int128 other) noexcept
+ : Low_{static_cast<ui64>(other & ~ui64{0})}
+ , High_{static_cast<ui64>(other >> 64)}
+ {
+ }
+#endif
+
+ constexpr TInteger128(const i8 other) noexcept
+ : Low_{static_cast<ui64>(other)}
+ , High_{other < 0 ? std::numeric_limits<ui64>::max() : 0}
+ {
+ }
+
+ constexpr TInteger128(const i16 other) noexcept
+ : Low_{static_cast<ui64>(other)}
+ , High_{other < 0 ? std::numeric_limits<ui64>::max() : 0}
+ {
+ }
+
+ constexpr TInteger128(const i32 other) noexcept
+ : Low_(static_cast<ui64>(other))
+ , High_{other < 0 ? std::numeric_limits<ui64>::max() : 0}
+ {
+ }
+
+ constexpr TInteger128(const i64 other) noexcept
+ : Low_(static_cast<ui64>(other))
+ , High_{other < 0 ? std::numeric_limits<ui64>::max() : 0}
+ {
+ }
+
+#if defined(Y_HAVE_INT128)
+ template <bool IsSigned2 = IsSigned, std::enable_if_t<!IsSigned2, bool> = false>
+ constexpr TInteger128(const signed __int128 other) noexcept
+ : Low_{static_cast<ui64>(other & ~ui64{0})}
+ , High_{static_cast<ui64>(static_cast<unsigned __int128>(other) >> 64)}
+ {
+ }
+
+ template <bool IsSigned2 = IsSigned, typename std::enable_if_t<IsSigned2, bool> = false>
+ constexpr TInteger128(const signed __int128 other) noexcept
+ : Low_{static_cast<ui64>(other & ~ui64(0))}
+ , High_{static_cast<ui64>(other >> 64)}
+ {
+ }
+#endif
+
+#elif defined(_big_endian_)
+ static_assert(false, "Big-endian will be later");
+#endif // _little_endian_ or _big_endian_
+
+ constexpr TInteger128& operator=(const char other) noexcept {
+ *this = TInteger128{other};
+ return *this;
+ }
+
+ constexpr TInteger128& operator=(const ui8 other) noexcept {
+ *this = TInteger128{other};
+ return *this;
+ }
+
+ constexpr TInteger128& operator=(const ui16 other) noexcept {
+ *this = TInteger128{other};
+ return *this;
+ }
+
+ constexpr TInteger128& operator=(const ui32 other) noexcept {
+ *this = TInteger128{other};
+ return *this;
+ }
+
+ constexpr TInteger128& operator=(const ui64 other) noexcept {
+ *this = TInteger128{other};
+ return *this;
+ }
+
+#if defined(Y_HAVE_INT128)
+ constexpr TInteger128& operator=(const unsigned __int128 other) noexcept {
+ *this = TInteger128{other};
+ return *this;
+ }
+#endif
+
+ constexpr TInteger128& operator=(const i8 other) noexcept {
+ *this = TInteger128{other};
+ return *this;
+ }
+
+ constexpr TInteger128& operator=(const i16 other) noexcept {
+ *this = TInteger128{other};
+ return *this;
+ }
+
+ constexpr TInteger128& operator=(const i32 other) noexcept {
+ *this = TInteger128{other};
+ return *this;
+ }
+
+ constexpr TInteger128& operator=(const i64 other) noexcept {
+ *this = TInteger128{other};
+ return *this;
+ }
+
+#if defined(Y_HAVE_INT128)
+ constexpr TInteger128& operator=(const signed __int128 other) noexcept {
+ *this = TInteger128{other};
+ return *this;
+ }
+#endif // Y_HAVE_INT128
+
+ constexpr TInteger128& operator+=(const TInteger128 other) noexcept {
+ return *this = *this + other;
+ }
+
+ constexpr TInteger128& operator-=(const TInteger128 other) noexcept {
+ return *this = *this - other;
+ }
+
+ constexpr TInteger128& operator*=(const TInteger128 other) noexcept {
+ return *this = *this * other;
+ }
+
+ constexpr TInteger128& operator&=(const TInteger128 other) noexcept {
+ return *this = *this & other;
+ }
+
+ constexpr TInteger128& operator^=(const TInteger128 other) noexcept {
+ return *this = *this ^ other;
+ }
+
+ constexpr TInteger128& operator|=(const TInteger128 other) noexcept {
+ return *this = *this | other;
+ }
+
+ constexpr TInteger128& operator<<=(int n) noexcept {
+ *this = *this << n;
+ return *this;
+ }
+
+ constexpr TInteger128& operator>>=(int n) noexcept {
+ *this = *this >> n;
+ return *this;
+ }
+
+ constexpr TInteger128& operator++() noexcept {
+ *this += 1;
+ return *this;
+ }
+
+ constexpr TInteger128 operator++(int) noexcept {
+ const TInteger128 ret{*this};
+ this->operator++();
+ return ret;
+ }
+
+ constexpr TInteger128& operator--() noexcept {
+ *this -= 1;
+ return *this;
+ }
+
+ constexpr TInteger128 operator--(int) noexcept {
+ const TInteger128 ret{*this};
+ this->operator--();
+ return ret;
+ }
+
+ explicit constexpr operator bool() const noexcept {
+ return Low_ || High_;
+ }
+
+ explicit constexpr operator char() const noexcept {
+ return static_cast<char>(Low_);
+ }
+
+ explicit constexpr operator ui8() const noexcept {
+ return static_cast<ui8>(Low_);
+ }
+
+ explicit constexpr operator i8() const noexcept {
+ return static_cast<i8>(Low_);
+ }
+
+ explicit constexpr operator ui16() const noexcept {
+ return static_cast<ui16>(Low_);
+ }
+
+ explicit constexpr operator i16() const noexcept {
+ return static_cast<i16>(Low_);
+ }
+
+ explicit constexpr operator ui32() const noexcept {
+ return static_cast<ui32>(Low_);
+ }
+
+ explicit constexpr operator i32() const noexcept {
+ return static_cast<i32>(Low_);
+ }
+
+ explicit constexpr operator ui64() const noexcept {
+ return static_cast<ui64>(Low_);
+ }
+
+ explicit constexpr operator i64() const noexcept {
+ return static_cast<i64>(Low_);
+ }
+
+#if defined(Y_HAVE_INT128)
+ explicit constexpr operator unsigned __int128() const noexcept {
+ return (static_cast<unsigned __int128>(High_) << 64) + Low_;
+ }
+
+ explicit constexpr operator signed __int128() const noexcept {
+ return (static_cast<__int128>(High_) << 64) + Low_;
+ }
+#endif
+
+private:
+#if defined(_little_endian_)
+ ui64 Low_;
+ ui64 High_;
+#elif defined(_big_endian_)
+ ui64 High_;
+ ui64 Low_;
+#endif
+ template <bool IsSigned2>
+ friend constexpr ui64 GetHigh(TInteger128<IsSigned2> value) noexcept;
+
+ template <bool IsSigned2>
+ friend constexpr ui64 GetLow(TInteger128<IsSigned2> value) noexcept;
+
+ friend IOutputStream& operator<<(IOutputStream& out, const TInteger128& other);
+}; // class TInteger128
+
+using ui128 = TInteger128<false>;
+using i128 = TInteger128<true>;
+
+constexpr ui128 operator+(ui128 lhs, ui128 rhs) noexcept;
+constexpr i128 operator+( i128 lhs, i128 rhs) noexcept;
+constexpr ui128 operator-(ui128 lhs, ui128 rhs) noexcept;
+constexpr i128 operator-( i128 lhs, i128 rhs) noexcept;
+constexpr ui128 operator-(ui128 num) noexcept;
+constexpr i128 operator-( i128 num) noexcept;
+constexpr ui128 operator*(ui128 lhs, ui128 rhs) noexcept;
+constexpr i128 operator*( i128 lhs, i128 rhs) noexcept;
+constexpr ui128 operator/(ui128 lhs, ui128 rhs) noexcept;
+constexpr i128 operator/( i128 lhs, i128 rhs) noexcept;
+constexpr ui128 operator%(ui128 lhs, ui128 rhs) noexcept;
+constexpr i128 operator%( i128 lhs, i128 rhs) noexcept;
+constexpr ui128 operator|(ui128 lhs, ui128 rhs) noexcept;
+constexpr i128 operator|( i128 lhs, i128 rhs) noexcept;
+constexpr ui128 operator&(ui128 lhs, ui128 rhs) noexcept;
+constexpr i128 operator&( i128 lhs, i128 rhs) noexcept;
+constexpr ui128 operator^(ui128 lhs, ui128 rhs) noexcept;
+constexpr i128 operator^( i128 lhs, i128 rhs) noexcept;
+constexpr ui128 operator<<(ui128 lhs, int n) noexcept;
+constexpr i128 operator<<( i128 lhs, int n) noexcept;
+constexpr ui128 operator>>(ui128 lhs, int n) noexcept;
+constexpr i128 operator>>( i128 lhs, int n) noexcept;
+
+template <bool IsSigned>
+size_t MostSignificantBit(const TInteger128<IsSigned> v);
+
+namespace std {
+ //// type traits
+ template <bool IsSigned>
+ struct is_integral<TInteger128<IsSigned>> : public std::true_type{};
+
+ template <bool IsSigned>
+ struct is_class<TInteger128<IsSigned>> : public std::false_type{};
+
+ template <>
+ struct is_signed<ui128> : public std::false_type{};
+
+ template <>
+ struct is_signed<i128> : public std::true_type{};
+}
+
+template <bool IsSigned>
+constexpr ui64 GetHigh(const TInteger128<IsSigned> value) noexcept {
+ return value.High_;
+}
+
+template <bool IsSigned>
+constexpr ui64 GetLow(const TInteger128<IsSigned> value) noexcept {
+ return value.Low_;
+}
+
+template <class T, std::enable_if_t<std::is_same_v<std::remove_cv_t<T>, i128>>* = nullptr>
+constexpr ui128 operator-(const ui128 lhs, const T rhs) noexcept {
+ return lhs - static_cast<ui128>(rhs);
+}
+
+template <class T, std::enable_if_t<std::is_same_v<std::remove_cv_t<T>, ui128>>* = nullptr>
+constexpr ui128 operator-(const i128 lhs, const T rhs) noexcept {
+ return static_cast<ui128>(lhs) - rhs;
+}
+
+// specialize std templates
+namespace std {
+ // numeric limits
+ // see full list at https://en.cppreference.com/w/cpp/types/numeric_limits
+ template <bool IsSigned>
+ struct numeric_limits<TInteger128<IsSigned>> {
+ static constexpr bool is_specialized = true;
+ static constexpr bool is_signed = IsSigned;
+ static constexpr bool is_integer = true;
+ static constexpr bool is_exact = true;
+ static constexpr bool has_infinity = false;
+ static constexpr bool has_quiet_NAN = false;
+ static constexpr bool has_signaling_NAN = false;
+ static constexpr float_denorm_style has_denorm = std::denorm_absent;
+ static constexpr bool has_denorm_loss = false;
+ static constexpr float_round_style round_style = std::round_toward_zero;
+ static constexpr bool is_iec559 = false;
+ static constexpr bool is_bounded = true;
+ static constexpr bool is_modulo = true;
+ static constexpr int digits = CHAR_BIT * sizeof(ui128) - (IsSigned ? 1 : 0);
+ static constexpr int digits10 = 38; // std::numeric_limits<ui128>::digits * std::log10(2);
+ static constexpr int max_digits10 = 0;
+ static constexpr int radix = 2;
+ static constexpr int min_exponent = 0;
+ static constexpr int min_exponent10 = 0;
+ static constexpr int max_exponent = 0;
+ static constexpr int max_exponent10 = 0;
+ static constexpr bool traps = std::numeric_limits<ui64>::traps; // same as of any other ui*
+ static constexpr bool tinyness_before = false;
+
+ static constexpr TInteger128<IsSigned> min() noexcept {
+ if constexpr (IsSigned) {
+ return TInteger128<IsSigned>{
+ static_cast<ui64>(std::numeric_limits<i64>::min()),
+ 0
+ };
+ }
+ else {
+ return 0;
+ }
+ }
+
+ static constexpr TInteger128<IsSigned> lowest() noexcept {
+ return min();
+ }
+
+ static constexpr TInteger128<IsSigned> max() noexcept {
+ if constexpr (IsSigned) {
+ return TInteger128<IsSigned>{
+ static_cast<ui64>(std::numeric_limits<i64>::max()),
+ std::numeric_limits<ui64>::max()
+ };
+ }
+ else {
+ return TInteger128<IsSigned>{
+ std::numeric_limits<ui64>::max(),
+ std::numeric_limits<ui64>::max()
+ };
+ }
+ }
+
+ static constexpr TInteger128<IsSigned> epsilon() noexcept {
+ return 0;
+ }
+
+ static constexpr TInteger128<IsSigned> round_error() noexcept {
+ return 0;
+ }
+
+ static constexpr TInteger128<IsSigned> infinity() noexcept {
+ return 0;
+ }
+
+ static constexpr TInteger128<IsSigned> quiet_NAN() noexcept {
+ return 0;
+ }
+
+ static constexpr TInteger128<IsSigned> signaling_NAN() noexcept {
+ return 0;
+ }
+
+ static constexpr TInteger128<IsSigned> denorm_min() noexcept {
+ return 0;
+ }
+ };
+
+ constexpr bool signbit(const ui128 arg) noexcept {
+ Y_UNUSED(arg);
+ return false;
+ }
+
+ constexpr bool signbit(const i128 arg) noexcept {
+ return GetHigh(arg) & 0x8000000000000000;
+ }
+
+ constexpr ui128 abs(const ui128 arg) noexcept {
+ return arg;
+ }
+
+ constexpr i128 abs(const i128 arg) noexcept {
+ return signbit(arg) ? (-arg) : arg;
+ }
+}
+
+constexpr bool operator==(const ui128 lhs, const ui128 rhs) noexcept {
+ return GetLow(lhs) == GetLow(rhs) && GetHigh(lhs) == GetHigh(rhs);
+}
+
+constexpr bool operator==(const i128 lhs, const i128 rhs) noexcept {
+ return GetLow(lhs) == GetLow(rhs) && GetHigh(lhs) == GetHigh(rhs);
+}
+
+constexpr bool operator!=(const ui128 lhs, const ui128 rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+constexpr bool operator!=(const i128 lhs, const i128 rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+constexpr bool operator<(const ui128 lhs, const ui128 rhs) noexcept {
+ if (GetHigh(lhs) != GetHigh(rhs)) {
+ return GetHigh(lhs) < GetHigh(rhs);
+ }
+
+ return GetLow(lhs) < GetLow(rhs);
+}
+
+constexpr bool operator<(const i128 lhs, const i128 rhs) noexcept {
+ if (lhs == 0 && rhs == 0) {
+ return false;
+ }
+
+ const bool lhsIsNegative = std::signbit(lhs);
+ const bool rhsIsNegative = std::signbit(rhs);
+
+ if (lhsIsNegative && !rhsIsNegative) {
+ return true;
+ }
+
+ if (!lhsIsNegative && rhsIsNegative) {
+ return false;
+ }
+
+ // both are negative or both are positive
+ if (GetHigh(lhs) != GetHigh(rhs)) {
+ return GetHigh(lhs) < GetHigh(rhs);
+ }
+
+ return GetLow(lhs) < GetLow(rhs);
+}
+
+constexpr bool operator>(const ui128 lhs, const ui128 rhs) noexcept {
+ return rhs < lhs;
+}
+
+constexpr bool operator>(const i128 lhs, const i128 rhs) noexcept {
+ return rhs < lhs;
+}
+
+constexpr bool operator<=(const ui128 lhs, const ui128 rhs) noexcept {
+ return !(rhs < lhs);
+}
+
+constexpr bool operator<=(const i128 lhs, const i128 rhs) noexcept {
+ return !(rhs < lhs);
+}
+
+constexpr bool operator>=(const ui128 lhs, const ui128 rhs) noexcept {
+ return !(lhs < rhs);
+}
+
+constexpr bool operator>=(const i128 lhs, const i128 rhs) noexcept {
+ return !(lhs < rhs);
+}
+
+constexpr ui128 operator+(const ui128 lhs, const ui128 rhs) noexcept {
+ const ui128 result{GetHigh(lhs) + GetHigh(rhs), GetLow(lhs) + GetLow(rhs)};
+ if (GetLow(result) < GetLow(lhs)) {
+ return ui128{GetHigh(result) + 1, GetLow(result)};
+ }
+ return result;
+}
+
+constexpr i128 operator+(const i128 lhs, const i128 rhs) noexcept {
+ const i128 result{GetHigh(lhs) + GetHigh(rhs), GetLow(lhs) + GetLow(rhs)};
+ if (GetLow(result) < GetLow(lhs)) {
+ return i128{GetHigh(result) + 1, GetLow(result)};
+ }
+ return result;
+}
+
+constexpr ui128 operator-(const ui128 lhs, const ui128 rhs) noexcept {
+ const ui128 result{GetHigh(lhs) - GetHigh(rhs), GetLow(lhs) - GetLow(rhs)};
+ if (GetLow(result) > GetLow(lhs)) { // underflow
+ return ui128{GetHigh(result) - 1, GetLow(result)};
+ }
+ return result;
+}
+
+constexpr i128 operator-(const i128 lhs, const i128 rhs) noexcept {
+ const i128 result{GetHigh(lhs) - GetHigh(rhs), GetLow(lhs) - GetLow(rhs)};
+ if (GetLow(result) > GetLow(lhs)) { // underflow
+ return i128{GetHigh(result) - 1, GetLow(result)};
+ }
+ return result;
+}
+
+constexpr ui128 operator-(const ui128 num) noexcept {
+ const ui128 result{~GetHigh(num), ~GetLow(num) + 1};
+ if (GetLow(result) == 0) {
+ return ui128{GetHigh(result) + 1, GetLow(result)};
+ }
+ return result;
+}
+
+constexpr i128 operator-(const i128 num) noexcept {
+ const i128 result{~GetHigh(num), ~GetLow(num) + 1};
+ if (GetLow(result) == 0) {
+ return i128{GetHigh(result) + 1, GetLow(result)};
+ }
+ return result;
+}
+
+constexpr ui128 operator*(const ui128 lhs, const ui128 rhs) noexcept {
+ if (rhs == 0) {
+ return 0;
+ }
+ if (rhs == 1) {
+ return lhs;
+ }
+
+ ui128 result{};
+ ui128 t = rhs;
+
+ for (size_t i = 0; i < 128; ++i) {
+ if ((t & 1) != 0) {
+ result += (lhs << i);
+ }
+
+ t = t >> 1;
+ }
+
+ return result;
+}
+
+constexpr i128 operator*(const i128 lhs, const i128 rhs) noexcept {
+ if (rhs == 0) {
+ return 0;
+ }
+ if (rhs == 1) {
+ return lhs;
+ }
+
+ i128 result{};
+ i128 t = rhs;
+
+ for (size_t i = 0; i < 128; ++i) {
+ if ((t & 1) != 0) {
+ result += (lhs << i);
+ }
+
+ t = t >> 1;
+ }
+
+ return result;
+}
+
+namespace NPrivateInt128 {
+ // NOTE: division by zero is UB and can be changed in future
+ constexpr void DivMod128(const ui128 lhs, const ui128 rhs, ui128* const quo, ui128* const rem) {
+ if (!quo && !rem) {
+ return;
+ }
+
+ constexpr size_t n_udword_bits = sizeof(ui64) * CHAR_BIT;
+ constexpr size_t n_utword_bits = sizeof(ui128) * CHAR_BIT;
+
+ ui128 q{};
+ ui128 r{};
+
+ unsigned sr{};
+
+ /* special cases, X is unknown, K != 0 */
+ if (GetHigh(lhs) == 0)
+ {
+ if (GetHigh(rhs) == 0)
+ {
+ /* 0 X
+ * ---
+ * 0 X
+ */
+ if (rem) {
+ *rem = GetLow(lhs) % GetLow(rhs);
+ }
+ if (quo) {
+ *quo = GetLow(lhs) / GetLow(rhs);
+ }
+ return;
+ }
+ /* 0 X
+ * ---
+ * K X
+ */
+ if (rem) {
+ *rem = GetLow(lhs);
+ }
+ if (quo) {
+ *quo = 0;
+ }
+ return;
+ }
+ /* n.s.high != 0 */
+ if (GetLow(rhs) == 0)
+ {
+ if (GetHigh(rhs) == 0)
+ {
+ /* K X
+ * ---
+ * 0 0
+ */
+ if (rem) {
+ *rem = GetHigh(lhs) % GetLow(rhs);
+ }
+ if (quo) {
+ *quo = GetHigh(lhs) / GetLow(rhs);
+ }
+ return;
+ }
+ /* d.s.high != 0 */
+ if (GetLow(lhs) == 0)
+ {
+ /* K 0
+ * ---
+ * K 0
+ */
+ if (rem) {
+ *rem = ui128{GetHigh(lhs) % GetHigh(rhs), 0};
+ }
+ if (quo) {
+ *quo = GetHigh(lhs) / GetHigh(rhs);
+ }
+ return;
+ }
+ /* K K
+ * ---
+ * K 0
+ */
+ if ((GetHigh(rhs) & (GetHigh(rhs) - 1)) == 0) /* if d is a power of 2 */
+ {
+ if (rem) {
+ *rem = ui128{GetHigh(lhs) & (GetHigh(rhs) - 1), GetLow(lhs)};
+ }
+ if (quo) {
+ *quo = GetHigh(lhs) >> CountLeadingZeroBits(GetHigh(rhs));
+ }
+ return;
+ }
+ /* K K
+ * ---
+ * K 0
+ */
+ sr = CountLeadingZeroBits(GetHigh(rhs)) - CountLeadingZeroBits(GetHigh(lhs));
+ /* 0 <= sr <= n_udword_bits - 2 or sr large */
+ if (sr > n_udword_bits - 2)
+ {
+ if (rem) {
+ *rem = lhs;
+ }
+ if (quo) {
+ *quo = 0;
+ }
+ return;
+ }
+ ++sr;
+ /* 1 <= sr <= n_udword_bits - 1 */
+ /* q.all = n.all << (n_utword_bits - sr); */
+ q = ui128{
+ GetLow(lhs) << (n_udword_bits - sr),
+ 0
+ };
+ r = ui128{
+ GetHigh(lhs) >> sr,
+ (GetHigh(lhs) << (n_udword_bits - sr)) | (GetLow(lhs) >> sr)
+ };
+ }
+ else /* d.s.low != 0 */
+ {
+ if (GetHigh(rhs) == 0)
+ {
+ /* K X
+ * ---
+ * 0 K
+ */
+ if ((GetLow(rhs) & (GetLow(rhs) - 1)) == 0) /* if d is a power of 2 */
+ {
+ if (rem) {
+ *rem = ui128{0, GetLow(lhs) & (GetLow(rhs) - 1)};
+ }
+ if (GetLow(rhs) == 1) {
+ if (quo) {
+ *quo = lhs;
+ }
+ return;
+ }
+ sr = CountTrailingZeroBits(GetLow(rhs));
+ if (quo) {
+ *quo = ui128{
+ GetHigh(lhs) >> sr,
+ (GetHigh(lhs) << (n_udword_bits - sr)) | (GetLow(lhs) >> sr)
+ };
+ return;
+ }
+ }
+ /* K X
+ * ---
+ * 0 K
+ */
+ sr = 1 + n_udword_bits + CountLeadingZeroBits(GetLow(rhs))
+ - CountLeadingZeroBits(GetHigh(lhs));
+ /* 2 <= sr <= n_utword_bits - 1
+ * q.all = n.all << (n_utword_bits - sr);
+ * r.all = n.all >> sr;
+ */
+ if (sr == n_udword_bits)
+ {
+ q = ui128{GetLow(lhs), 0};
+ r = ui128{0, GetHigh(lhs)};
+ }
+ else if (sr < n_udword_bits) // 2 <= sr <= n_udword_bits - 1
+ {
+ q = ui128{
+ GetLow(lhs) << (n_udword_bits - sr),
+ 0
+ };
+ r = ui128{
+ GetHigh(lhs) >> sr,
+ (GetHigh(lhs) << (n_udword_bits - sr)) | (GetLow(lhs) >> sr)
+ };
+ }
+ else // n_udword_bits + 1 <= sr <= n_utword_bits - 1
+ {
+ q = ui128{
+ (GetHigh(lhs) << (n_utword_bits - sr)) | (GetLow(lhs) >> (sr - n_udword_bits)),
+ GetLow(lhs) << (n_utword_bits - sr)
+ };
+ r = ui128{
+ 0,
+ GetHigh(lhs) >> (sr - n_udword_bits)
+ };
+ }
+ }
+ else
+ {
+ /* K X
+ * ---
+ * K K
+ */
+ sr = CountLeadingZeroBits(GetHigh(rhs)) - CountLeadingZeroBits(GetHigh(lhs));
+ /*0 <= sr <= n_udword_bits - 1 or sr large */
+ if (sr > n_udword_bits - 1)
+ {
+ if (rem) {
+ *rem = lhs;
+ }
+ if (quo) {
+ *quo = 0;
+ }
+ return;
+ }
+ ++sr;
+ /* 1 <= sr <= n_udword_bits
+ * q.all = n.all << (n_utword_bits - sr);
+ * r.all = n.all >> sr;
+ */
+ if (sr == n_udword_bits)
+ {
+ q = ui128{
+ GetLow(lhs),
+ 0
+ };
+ r = ui128{
+ 0,
+ GetHigh(lhs)
+ };
+ }
+ else
+ {
+ r = ui128{
+ GetHigh(lhs) >> sr,
+ (GetHigh(lhs) << (n_udword_bits - sr)) | (GetLow(lhs) >> sr)
+ };
+ q = ui128{
+ GetLow(lhs) << (n_udword_bits - sr),
+ 0
+ };
+ }
+ }
+ }
+ /* Not a special case
+ * q and r are initialized with:
+ * q = n << (128 - sr);
+ * r = n >> sr;
+ * 1 <= sr <= 128 - 1
+ */
+ ui32 carry = 0;
+ for (; sr > 0; --sr)
+ {
+ /* r:q = ((r:q) << 1) | carry */
+ r = ui128{
+ (GetHigh(r) << 1) | (GetLow(r) >> (n_udword_bits - 1)),
+ (GetLow(r) << 1) | (GetHigh(q) >> (n_udword_bits - 1))
+ };
+ q = ui128{
+ (GetHigh(q) << 1) | (GetLow(q) >> (n_udword_bits - 1)),
+ (GetLow(q) << 1) | carry
+ };
+ carry = 0;
+ if (r >= rhs) {
+ r -= rhs;
+ carry = 1;
+ }
+ }
+ q = (q << 1) | carry;
+ if (rem) {
+ *rem = r;
+ }
+ if (quo) {
+ *quo = q;
+ }
+ }
+
+ struct TSignedDivisionResult {
+ i128 Quotient;
+ i128 Remainder;
+ };
+
+ constexpr TSignedDivisionResult Divide(i128 lhs, i128 rhs) noexcept;
+}
+
+constexpr ui128 operator/(const ui128 lhs, const ui128 rhs) noexcept {
+ ui128 quotient{};
+ NPrivateInt128::DivMod128(lhs, rhs, &quotient, nullptr);
+ return quotient;
+}
+
+constexpr i128 operator/(const i128 lhs, const i128 rhs) noexcept {
+ i128 a = std::abs(lhs);
+ i128 b = std::abs(rhs);
+
+ ui128 quotient{};
+ NPrivateInt128::DivMod128(a, b, &quotient, nullptr);
+ if (std::signbit(lhs) ^ std::signbit(rhs)) {
+ quotient = -quotient;
+ }
+ return quotient;
+}
+
+constexpr ui128 operator%(const ui128 lhs, const ui128 rhs) noexcept {
+ ui128 remainder{};
+ NPrivateInt128::DivMod128(lhs, rhs, nullptr, &remainder);
+ return remainder;
+}
+
+constexpr i128 operator%(const i128 lhs, const i128 rhs) noexcept {
+ i128 a = std::abs(lhs);
+ i128 b = std::abs(rhs);
+ ui128 remainder{};
+ NPrivateInt128::DivMod128(a, b, nullptr, &remainder);
+ if (std::signbit(lhs)) {
+ remainder = -remainder;
+ }
+ return remainder;
+}
+
+constexpr ui128 operator<<(const ui128 lhs, int n) noexcept {
+ if (n < 64) {
+ if (n != 0) {
+ return
+ ui128{
+ (GetHigh(lhs) << n) | (GetLow(lhs) >> (64 - n)),
+ GetLow(lhs) << n
+ };
+ }
+ return lhs;
+ }
+ return ui128{GetLow(lhs) << (n - 64), 0};
+}
+
+constexpr ui128 operator>>(const ui128 lhs, int n) noexcept {
+ if (n < 64) {
+ if (n != 0) {
+ return
+ ui128{
+ GetHigh(lhs) >> n,
+ (GetLow(lhs) >> n) | (GetHigh(lhs) << (64 - n))
+ };
+ }
+ return lhs;
+ }
+ return ui128{0, GetHigh(lhs) >> (n - 64)};
+}
+
+
+constexpr bool operator!(const ui128 num) noexcept {
+ return !GetHigh(num) && !GetLow(num);
+}
+
+constexpr ui128 operator~(const ui128 num) noexcept {
+ return ui128{~GetHigh(num), ~GetLow(num)};
+}
+
+constexpr ui128 operator|(const ui128 lhs, const ui128 rhs) noexcept {
+ return ui128{GetHigh(lhs) | GetHigh(rhs), GetLow(lhs) | GetLow(rhs)};
+}
+
+constexpr ui128 operator&(const ui128 lhs, const ui128 rhs) noexcept {
+ return ui128{GetHigh(lhs) & GetHigh(rhs), GetLow(lhs) & GetLow(rhs)};
+}
+
+constexpr ui128 operator^(const ui128 lhs, const ui128 rhs) noexcept {
+ return ui128{GetHigh(lhs) ^ GetHigh(rhs), GetLow(lhs) ^ GetLow(rhs)};
+}
+
+
+IOutputStream& operator<<(IOutputStream& out, const ui128& other);
+
+// For THashMap
+template <>
+struct THash<ui128> {
+ inline size_t operator()(const ui128& num) const {
+ return THash<ui64>()(GetHigh(num)) + THash<ui64>()(GetLow(num));
+ }
+};
+
+template <>
+class TSerializer<ui128> {
+public:
+ static void Save(IOutputStream* out, const ui128& Number);
+ static void Load(IInputStream* in, ui128& Number);
+};
+
+template <>
+inline TString ToString<ui128>(const ui128& number) {
+ return TStringBuilder{} << number;
+}
+
+template <>
+inline ui128 FromStringImpl<ui128>(const char* data, size_t length) {
+ if (length < 20) {
+ return ui128{ FromString<ui64>(data, length) };
+ } else {
+ ui128 result = 0;
+ const TStringBuf string(data, length);
+ for (auto&& c : string) {
+ if (!std::isdigit(c)) {
+ ythrow TFromStringException() << "Unexpected symbol \""sv << c << "\""sv;
+ }
+
+ ui128 x1 = result;
+ ui128 x2 = x1 + x1;
+ ui128 x4 = x2 + x2;
+ ui128 x8 = x4 + x4;
+ ui128 x10 = x8 + x2;
+ ui128 s = c - '0';
+ result = x10 + s;
+
+ if (GetHigh(result) < GetHigh(x1)) {
+ ythrow TFromStringException() << TStringBuf("Integer overflow");
+ }
+ }
+
+ return result;
+ }
+}
+
+#if defined(Y_HAVE_INT128)
+template <>
+inline TString ToString<unsigned __int128>(const unsigned __int128& number) {
+ return ToString(ui128{number});
+}
+
+template <>
+inline unsigned __int128 FromStringImpl<unsigned __int128>(const char* data, size_t length) {
+ return static_cast<unsigned __int128>(FromString<ui128>(data, length));
+}
+#endif
+
+// operators
+
+
+namespace NPrivateInt128 {
+ // very naive algorithm of division
+ // no contract for divide by zero (i.e. it is UB) (may be changed in future)
+ constexpr TSignedDivisionResult Divide(i128 lhs, i128 rhs) noexcept {
+ TSignedDivisionResult result {};
+
+ // check trivial cases
+ // X/0 = +/- inf, X%0 = X
+ if (rhs == 0) {
+ // UB, let's return: `X / 0 = +inf`, and `X % 0 = X`
+ result.Quotient = std::signbit(lhs) ? std::numeric_limits<i128>::min() : std::numeric_limits<i128>::max();
+ result.Remainder = lhs;
+ }
+
+ // 0/Y = 0, 0%Y = 0
+ else if (lhs == 0) {
+ result.Quotient = 0;
+ result.Remainder = 0;
+ }
+
+ // X/1 = X, X%1 = 0
+ else if (rhs == 1) {
+ result.Quotient = lhs;
+ result.Remainder = 0;
+ }
+
+ // X/-1 = -X, X%(-1) = 0
+ else if (rhs == -1) {
+ result.Quotient = -lhs;
+ result.Remainder = 0;
+ }
+
+ // abs(X)<abs(Y), X/Y = 0, X%Y = X
+ else if (std::abs(lhs) < std::abs(rhs)) {
+ result.Quotient = 0;
+ result.Remainder = lhs;
+ }
+
+ else if (lhs == rhs) {
+ result.Quotient = 1;
+ result.Remainder = 0;
+ }
+
+ else if (lhs == -rhs) {
+ result.Quotient = -1;
+ result.Remainder = 0;
+ }
+
+ else if (std::abs(lhs) > std::abs(rhs)) {
+ const bool quotientMustBeNegative = std::signbit(lhs) ^ std::signbit(rhs);
+ const bool remainderMustBeNegative = std::signbit(lhs);
+
+ lhs = std::abs(lhs);
+ rhs = std::abs(rhs);
+
+ // result is division of two ui64
+ if (GetHigh(lhs) == 0 && GetHigh(rhs) == 0) {
+ result.Quotient = GetLow(lhs) / GetLow(rhs);
+ result.Remainder = GetLow(lhs) % GetLow(rhs);
+ }
+
+ // naive shift-and-subtract
+ // https://stackoverflow.com/questions/5386377/division-without-using
+ i128 denominator = rhs;
+ result.Quotient = 0;
+ result.Remainder = lhs;
+
+ const size_t shift = MostSignificantBit(lhs) - MostSignificantBit(denominator);
+ denominator <<= shift;
+
+ for (size_t i = 0; i <= shift; ++i) {
+ result.Quotient <<= 1;
+ if (result.Remainder >= denominator) {
+ result.Remainder -= denominator;
+ result.Quotient |= 1;
+ }
+ denominator >>= 1;
+ }
+
+ if (quotientMustBeNegative) {
+ result.Quotient = -result.Quotient;
+ }
+
+ if (remainderMustBeNegative) {
+ result.Remainder = -result.Remainder;
+ }
+ }
+
+ return result;
+ }
+} // namespace NPrivateInt128
+
+constexpr i128 operator<<(const i128 lhs, int n) noexcept {
+ if (n < 64) {
+ if (n != 0) {
+ return
+ i128{
+ (GetHigh(lhs) << n) | (GetLow(lhs) >> (64 - n)),
+ GetLow(lhs) << n
+ };
+ }
+ return lhs;
+ }
+ return i128{GetLow(lhs) << (n - 64), 0};
+}
+
+constexpr i128 operator>>(const i128 lhs, int n) noexcept {
+ if (n < 64) {
+ if (n != 0) {
+ return
+ i128{
+ GetHigh(lhs) >> n,
+ (GetLow(lhs) >> n) | (GetHigh(lhs) << (64 - n))
+ };
+ }
+ return lhs;
+ }
+ return i128{0, GetHigh(lhs) >> (n - 64)};
+}
+
+constexpr bool operator!(const i128 num) noexcept {
+ return !GetHigh(num) && !GetLow(num);
+}
+
+constexpr i128 operator~(const i128 num) noexcept {
+ return i128{~GetHigh(num), ~GetLow(num)};
+}
+
+constexpr i128 operator|(const i128 lhs, const i128 rhs) noexcept {
+ return i128{GetHigh(lhs) | GetHigh(rhs), GetLow(lhs) | GetLow(rhs)};
+}
+
+constexpr i128 operator&(const i128 lhs, const i128 rhs) noexcept {
+ return i128{GetHigh(lhs) & GetHigh(rhs), GetLow(lhs) & GetLow(rhs)};
+}
+
+constexpr i128 operator^(const i128 lhs, const i128 rhs) noexcept {
+ return i128{GetHigh(lhs) ^ GetHigh(rhs), GetLow(lhs) ^ GetLow(rhs)};
+}
+
+
+IOutputStream& operator<<(IOutputStream& out, const i128& other);
+
+// For THashMap
+template <>
+struct THash<i128> {
+ inline size_t operator()(const i128& num) const {
+ return THash<ui64>()(GetHigh(num)) + THash<ui64>()(GetLow(num));
+ }
+};
+
+template <>
+class TSerializer<i128> {
+public:
+ static void Save(IOutputStream* out, const i128& Number);
+ static void Load(IInputStream* in, i128& Number);
+};
+
+template <>
+inline TString ToString<i128>(const i128& number) {
+ return TStringBuilder{} << number;
+}
+
+template <>
+inline i128 FromStringImpl<i128>(const char* data, size_t length) {
+ if (length < 20) {
+ return i128{ FromString<ui64>(data, length) };
+ } else {
+ i128 result = 0;
+ const TStringBuf string(data, length);
+ for (auto&& c : string) {
+ if (!std::isdigit(c)) {
+ ythrow TFromStringException() << "Unexpected symbol \""sv << c << "\""sv;
+ }
+
+ i128 x1 = result;
+ i128 x2 = x1 + x1;
+ i128 x4 = x2 + x2;
+ i128 x8 = x4 + x4;
+ i128 x10 = x8 + x2;
+ i128 s = c - '0';
+ result = x10 + s;
+
+ if (GetHigh(result) < GetHigh(x1)) {
+ ythrow TFromStringException() << TStringBuf("Integer overflow");
+ }
+ }
+
+ return result;
+ }
+}
+
+#if defined(Y_HAVE_INT128)
+template <>
+inline TString ToString<signed __int128>(const signed __int128& number) {
+ return ToString(i128{number});
+}
+
+template <>
+inline signed __int128 FromStringImpl<signed __int128>(const char* data, size_t length) {
+ return static_cast<signed __int128>(FromString<i128>(data, length));
+}
+#endif
+
+template <bool IsSigned>
+Y_FORCE_INLINE size_t MostSignificantBit(const TInteger128<IsSigned> v) {
+ if (ui64 hi = GetHigh(v)) {
+ return MostSignificantBit(hi) + 64;
+ }
+ return MostSignificantBit(GetLow(v));
+}
diff --git a/library/cpp/int128/int128_common.h b/library/cpp/int128/int128_common.h
new file mode 100644
index 0000000000..6f70f09bee
--- /dev/null
+++ b/library/cpp/int128/int128_common.h
@@ -0,0 +1 @@
+#pragma once
diff --git a/library/cpp/int128/int128_util.h b/library/cpp/int128/int128_util.h
new file mode 100644
index 0000000000..7a5ca2c250
--- /dev/null
+++ b/library/cpp/int128/int128_util.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <util/generic/bitops.h>
+#include <limits>
+
+namespace NPrivateInt128 {
+ // will be moved to util/ later
+ template <typename T>
+ constexpr unsigned CountLeadingZeroBits(const T value) {
+ if (value == 0) {
+ return std::numeric_limits<std::make_unsigned_t<T>>::digits;
+ }
+ return std::numeric_limits<std::make_unsigned_t<T>>::digits - GetValueBitCount(value);
+ }
+}
diff --git a/library/cpp/int128/ut/.gitignore b/library/cpp/int128/ut/.gitignore
new file mode 100644
index 0000000000..36abcb2a2c
--- /dev/null
+++ b/library/cpp/int128/ut/.gitignore
@@ -0,0 +1,2 @@
+library-int128-ut
+
diff --git a/library/cpp/int128/ut/i128_and_intrinsic_identity_ut.cpp b/library/cpp/int128/ut/i128_and_intrinsic_identity_ut.cpp
new file mode 100644
index 0000000000..dbb7507a73
--- /dev/null
+++ b/library/cpp/int128/ut/i128_and_intrinsic_identity_ut.cpp
@@ -0,0 +1,598 @@
+#include "int128_ut_helpers.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/int128/int128.h>
+
+#include <util/generic/cast.h>
+
+#include <array>
+#include <type_traits>
+
+#if defined(Y_HAVE_INT128)
+bool IsIdentical(const i128 a, const signed __int128 b) {
+ const std::array<ui8, 16> arrayA = NInt128Private::GetAsArray(a);
+ const std::array<ui8, 16> arrayB = NInt128Private::GetAsArray(b);
+ return arrayA == arrayB;
+}
+
+Y_UNIT_TEST_SUITE(i128_And_i8_BitwiseIdentity) {
+ Y_UNIT_TEST(i128_from_i8_Zero) {
+ i8 n = 0;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i8_Minus1) {
+ i8 n = -1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i8_Plus1) {
+ i8 n = 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i8_Minus42) {
+ i8 n = -42;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i8_Plus42) {
+ i8 n = 42;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i8_Min) {
+ i8 n = std::numeric_limits<i8>::min();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i8_Max) {
+ i8 n = std::numeric_limits<i8>::max();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i8_MinPlus1) {
+ i8 n = std::numeric_limits<i8>::min() + 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i8_MaxMinus1) {
+ i8 n = std::numeric_limits<i8>::max() - 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+}
+
+Y_UNIT_TEST_SUITE(i128_And_i16_BitwiseIdentity) {
+ Y_UNIT_TEST(i128_from_i16_Zero) {
+ i16 n = 0;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i16_Minus1) {
+ i16 n = -1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i16_Plus1) {
+ i16 n = 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i16_Minus42) {
+ i16 n = -42;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i16_Plus42) {
+ i16 n = 42;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i16_Min) {
+ i16 n = std::numeric_limits<i16>::min();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i16_Max) {
+ i16 n = std::numeric_limits<i16>::max();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i16_MinPlus1) {
+ i16 n = std::numeric_limits<i16>::min() + 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i16_MaxMinus1) {
+ i16 n = std::numeric_limits<i16>::max() - 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+}
+
+Y_UNIT_TEST_SUITE(i128_And_i32_BitwiseIdentity) {
+ Y_UNIT_TEST(i128_from_i32_Zero) {
+ i32 n = 0;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i32_Minus1) {
+ i32 n = -1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i32_Plus1) {
+ i32 n = 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i32_Minus42) {
+ i32 n = -42;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i32_Plus42) {
+ i32 n = 42;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i32_Min) {
+ i32 n = std::numeric_limits<i32>::min();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i32_Max) {
+ i32 n = std::numeric_limits<i32>::max();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i32_MinPlus1) {
+ i32 n = std::numeric_limits<i32>::min() + 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i32_MaxMinus1) {
+ i32 n = std::numeric_limits<i32>::max() - 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+}
+
+Y_UNIT_TEST_SUITE(i128_And_i64_BitwiseIdentity) {
+ Y_UNIT_TEST(i128_from_i64_Zero) {
+ i64 n = 0;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i64_Minus1) {
+ i64 n = -1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i64_Plus1) {
+ i64 n = 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i64_Minus42) {
+ i64 n = -42;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i64_Plus42) {
+ i64 n = 42;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i64_Min) {
+ i64 n = std::numeric_limits<i64>::min();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i64_Max) {
+ i64 n = std::numeric_limits<i64>::max();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i64_MinPlus1) {
+ i64 n = std::numeric_limits<i64>::min() + 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_i64_MaxMinus1) {
+ i64 n = std::numeric_limits<i64>::max() - 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+}
+
+Y_UNIT_TEST_SUITE(i128_And_signed_int128_BitwiseIdentity) {
+ Y_UNIT_TEST(i128_from_signed_int128_Zero) {
+ signed __int128 n = 0;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_signed_int128_Minus1) {
+ signed __int128 n = -1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_signed_int128_Plus1) {
+ signed __int128 n = 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_signed_int128_Minus42) {
+ signed __int128 n = -42;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_signed_int128_Plus42) {
+ signed __int128 n = 42;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_signed_int128_Min) {
+ signed __int128 n = std::numeric_limits<signed __int128>::min();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_signed_int128_Max) {
+ signed __int128 n = std::numeric_limits<signed __int128>::max();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_signed_int128_MinPlus1) {
+ signed __int128 n = std::numeric_limits<signed __int128>::min() + 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_signed_int128_MaxMinus1) {
+ signed __int128 n = std::numeric_limits<signed __int128>::max() - 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+}
+
+Y_UNIT_TEST_SUITE(i128_And_ui8_BitwiseIdentity) {
+ Y_UNIT_TEST(i128_from_ui8_Zero) {
+ ui8 n = 0;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui8_Plus1) {
+ ui8 n = 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui8_Plus42) {
+ ui8 n = 42;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui8_Min) {
+ ui8 n = std::numeric_limits<i8>::min();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui8_Max) {
+ ui8 n = std::numeric_limits<i8>::max();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui8_MinPlus1) {
+ ui8 n = std::numeric_limits<i8>::min() + 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui8_MaxMinus1) {
+ ui8 n = std::numeric_limits<i8>::max() - 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+}
+
+Y_UNIT_TEST_SUITE(i128_And_ui16_BitwiseIdentity) {
+ Y_UNIT_TEST(i128_from_ui16_Zero) {
+ ui16 n = 0;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui16_Plus1) {
+ ui16 n = 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui16_Plus42) {
+ ui16 n = 42;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui16_Min) {
+ ui16 n = std::numeric_limits<i8>::min();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui16_Max) {
+ ui16 n = std::numeric_limits<i8>::max();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui16_MinPlus1) {
+ ui16 n = std::numeric_limits<i8>::min() + 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui16_MaxMinus1) {
+ ui16 n = std::numeric_limits<i8>::max() - 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+}
+
+Y_UNIT_TEST_SUITE(i128_And_ui32_BitwiseIdentity) {
+ Y_UNIT_TEST(i128_from_ui32_Zero) {
+ ui32 n = 0;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui32_Plus1) {
+ ui32 n = 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui32_Plus42) {
+ ui32 n = 42;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui32_Min) {
+ ui32 n = std::numeric_limits<i8>::min();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui32_Max) {
+ ui32 n = std::numeric_limits<i8>::max();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui32_MinPlus1) {
+ ui32 n = std::numeric_limits<i8>::min() + 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui32_MaxMinus1) {
+ ui32 n = std::numeric_limits<i8>::max() - 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+}
+
+Y_UNIT_TEST_SUITE(i128_And_ui64_BitwiseIdentity) {
+ Y_UNIT_TEST(i128_from_ui64_Zero) {
+ ui64 n = 0;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui64_Plus1) {
+ ui64 n = 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui64_Plus42) {
+ ui64 n = 42;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui64_Min) {
+ ui64 n = std::numeric_limits<i8>::min();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui64_Max) {
+ ui64 n = std::numeric_limits<i8>::max();
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui64_MinPlus1) {
+ ui64 n = std::numeric_limits<i8>::min() + 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_ui64_MaxMinus1) {
+ ui64 n = std::numeric_limits<i8>::max() - 1;
+ i128 t1{n};
+ signed __int128 t2{n};
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+}
+
+Y_UNIT_TEST_SUITE(i128_And_unsigned_int128_BitwiseIdentity) {
+ Y_UNIT_TEST(i128_from_unsigned_int128_Zero) {
+ unsigned __int128 n = 0;
+ i128 t1{n};
+ signed __int128 t2 = static_cast<signed __int128>(n);
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_unsigned_int128_Plus1) {
+ unsigned __int128 n = 1;
+ i128 t1{n};
+ signed __int128 t2 = static_cast<signed __int128>(n);
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_unsigned_int128_Plus42) {
+ unsigned __int128 n = 42;
+ i128 t1{n};
+ signed __int128 t2 = static_cast<signed __int128>(n);
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_unsigned_int128_Min) {
+ unsigned __int128 n = std::numeric_limits<i8>::min();
+ i128 t1{n};
+ signed __int128 t2 = static_cast<signed __int128>(n);
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_unsigned_int128_Max) {
+ unsigned __int128 n = std::numeric_limits<i8>::max();
+ i128 t1{n};
+ signed __int128 t2 = static_cast<signed __int128>(n);
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_unsigned_int128_MinPlus1) {
+ unsigned __int128 n = std::numeric_limits<i8>::min() + 1;
+ i128 t1{n};
+ signed __int128 t2 = static_cast<signed __int128>(n);
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+
+ Y_UNIT_TEST(i128_from_unsigned_int128_MaxMinus1) {
+ unsigned __int128 n = std::numeric_limits<i8>::max() - 1;
+ i128 t1{n};
+ signed __int128 t2 = static_cast<signed __int128>(n);
+ UNIT_ASSERT(IsIdentical(t1, t2));
+ }
+}
+#endif
diff --git a/library/cpp/int128/ut/i128_comparison_ut.cpp b/library/cpp/int128/ut/i128_comparison_ut.cpp
new file mode 100644
index 0000000000..7b8d508815
--- /dev/null
+++ b/library/cpp/int128/ut/i128_comparison_ut.cpp
@@ -0,0 +1,145 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/int128/int128.h>
+
+#include <util/generic/cast.h>
+
+Y_UNIT_TEST_SUITE(I128ComparisonPositiveWithPositiveSuite) {
+ Y_UNIT_TEST(PositivePositiveGreater) {
+ UNIT_ASSERT(i128{1} > i128{0});
+ UNIT_ASSERT(i128{2} > i128{1});
+ UNIT_ASSERT(i128{42} > i128{0});
+ UNIT_ASSERT(i128{42} > i128{1});
+ i128 big = i128{1, 0};
+ UNIT_ASSERT(big > i128{1});
+ UNIT_ASSERT(std::numeric_limits<i128>::max() > i128{0});
+ }
+
+ Y_UNIT_TEST(PositivePositiveGreaterOrEqual) {
+ UNIT_ASSERT(i128{1} >= i128{0});
+ UNIT_ASSERT(i128{2} >= i128{1});
+ UNIT_ASSERT(i128{42} >= i128{0});
+ UNIT_ASSERT(i128{42} >= i128{1});
+ i128 big = i128{1, 0};
+ UNIT_ASSERT(big >= i128{1});
+ UNIT_ASSERT(std::numeric_limits<i128>::max() >= i128{0});
+
+ UNIT_ASSERT(i128{0} >= i128{0});
+ UNIT_ASSERT(i128{1} >= i128{1});
+ UNIT_ASSERT(i128{2} >= i128{2});
+ UNIT_ASSERT(i128{42} >= i128{42});
+ UNIT_ASSERT(big >= big);
+ UNIT_ASSERT(std::numeric_limits<i128>::max() >= std::numeric_limits<i128>::max());
+ }
+
+ Y_UNIT_TEST(PositivePositiveLess) {
+ UNIT_ASSERT(i128{0} < i128{1});
+ UNIT_ASSERT(i128{1} < i128{2});
+ UNIT_ASSERT(i128{0} < i128{42});
+ UNIT_ASSERT(i128{1} < i128{42});
+ i128 big = i128{1, 0};
+ UNIT_ASSERT(i128{1} < big);
+ UNIT_ASSERT(i128{0} < std::numeric_limits<i128>::max());
+ }
+
+ Y_UNIT_TEST(PositivePositiveLessOrEqual) {
+ UNIT_ASSERT(i128{0} <= i128{1});
+ UNIT_ASSERT(i128{1} <= i128{2});
+ UNIT_ASSERT(i128{0} <= i128{42});
+ UNIT_ASSERT(i128{1} <= i128{42});
+ i128 big = i128{1, 0};
+ UNIT_ASSERT(i128{1} <= big);
+ UNIT_ASSERT(i128{0} <= std::numeric_limits<i128>::max());
+
+ UNIT_ASSERT(i128{0} <= i128{0});
+ UNIT_ASSERT(i128{1} <= i128{1});
+ UNIT_ASSERT(i128{2} <= i128{2});
+ UNIT_ASSERT(i128{42} <= i128{42});
+ UNIT_ASSERT(big <= big);
+ UNIT_ASSERT(std::numeric_limits<i128>::max() <= std::numeric_limits<i128>::max());
+ }
+}
+
+Y_UNIT_TEST_SUITE(I128ComparisonPositiveWithNegativeSuite) {
+ Y_UNIT_TEST(PositiveNegativeGreater) {
+ UNIT_ASSERT(i128{0} > i128{-1});
+ UNIT_ASSERT(i128{2} > i128{-1});
+ UNIT_ASSERT(i128{0} > i128{-42});
+ UNIT_ASSERT(i128{42} > i128{-1});
+ i128 big = i128{1, 0};
+ UNIT_ASSERT(big > i128{-1});
+ UNIT_ASSERT(std::numeric_limits<i128>::max() > i128{-1});
+ }
+
+ Y_UNIT_TEST(PositiveNegativeGreaterOrEqual) {
+ UNIT_ASSERT(i128{0} >= i128{-1});
+ UNIT_ASSERT(i128{2} >= i128{-1});
+ UNIT_ASSERT(i128{0} >= i128{-42});
+ UNIT_ASSERT(i128{42} >= i128{-1});
+ i128 big = i128{1, 0};
+ UNIT_ASSERT(big >= i128{-1});
+ UNIT_ASSERT(std::numeric_limits<i128>::max() >= i128{-1});
+ }
+
+ Y_UNIT_TEST(NegativePositiveLess) {
+ UNIT_ASSERT(i128{-1} < i128{0});
+ UNIT_ASSERT(i128{-1} < i128{2});
+ UNIT_ASSERT(i128{-42} < i128{0});
+ UNIT_ASSERT(i128{-1} < i128{42});
+ i128 big = i128{1, 0};
+ UNIT_ASSERT(i128{-1} < big);
+ UNIT_ASSERT(i128{-1} < std::numeric_limits<i128>::max());
+ }
+
+ Y_UNIT_TEST(NegativePositiveLessOrEqual) {
+ UNIT_ASSERT(i128{-1} <= i128{0});
+ UNIT_ASSERT(i128{-1} <= i128{2});
+ UNIT_ASSERT(i128{-42} <= i128{0});
+ UNIT_ASSERT(i128{-1} <= i128{42});
+ i128 big = i128{1, 0};
+ UNIT_ASSERT(i128{-1} <= big);
+ UNIT_ASSERT(i128{-1} <= std::numeric_limits<i128>::max());
+ }
+}
+
+Y_UNIT_TEST_SUITE(I128ComparisonNegativeWithNegativeSuite) {
+ Y_UNIT_TEST(NegativeNegativeGreater) {
+ UNIT_ASSERT(i128{-1} > i128{-2});
+ UNIT_ASSERT(i128{-2} > i128{-3});
+ UNIT_ASSERT(i128{-1} > i128{-42});
+ UNIT_ASSERT(i128{-42} > i128{-142});
+ i128 big = -i128{1, 0};
+ UNIT_ASSERT(i128{-1} > big);
+ UNIT_ASSERT(i128{-1} > std::numeric_limits<i128>::min());
+ }
+
+ Y_UNIT_TEST(NegativeNegativeGreaterOrEqual) {
+ UNIT_ASSERT(i128{-1} >= i128{-2});
+ UNIT_ASSERT(i128{-2} >= i128{-3});
+ UNIT_ASSERT(i128{-1} >= i128{-42});
+ UNIT_ASSERT(i128{-42} >= i128{-142});
+ i128 big = -i128{1, 0};
+ UNIT_ASSERT(i128{-1} >= big);
+ UNIT_ASSERT(i128{-1} >= std::numeric_limits<i128>::min());
+ }
+
+ Y_UNIT_TEST(NegativeNegativeLess) {
+ UNIT_ASSERT(i128{-2} < i128{-1});
+ UNIT_ASSERT(i128{-3} < i128{-2});
+ UNIT_ASSERT(i128{-42} < i128{-1});
+ UNIT_ASSERT(i128{-142} < i128{42});
+ i128 big = -i128{1, 0};
+ UNIT_ASSERT(big < i128{-1});
+ UNIT_ASSERT(std::numeric_limits<i128>::min() < i128{-1});
+ }
+
+ Y_UNIT_TEST(NegativeNegativeLessOrEqual) {
+ UNIT_ASSERT(i128{-2} <= i128{-1});
+ UNIT_ASSERT(i128{-3} <= i128{-2});
+ UNIT_ASSERT(i128{-42} <= i128{-1});
+ UNIT_ASSERT(i128{-142} <= i128{42});
+ i128 big = -i128{1, 0};
+ UNIT_ASSERT(big <= i128{-1});
+ UNIT_ASSERT(std::numeric_limits<i128>::min() <= i128{-1});
+ }
+}
diff --git a/library/cpp/int128/ut/i128_division_ut.cpp b/library/cpp/int128/ut/i128_division_ut.cpp
new file mode 100644
index 0000000000..46b0ca27f5
--- /dev/null
+++ b/library/cpp/int128/ut/i128_division_ut.cpp
@@ -0,0 +1,413 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/int128/int128.h>
+
+#include <util/generic/cast.h>
+
+Y_UNIT_TEST_SUITE(I128DivisionBy1Suite) {
+ Y_UNIT_TEST(I128Divide0By1) {
+ i128 dividend = 0;
+ i128 divider = 1;
+ i128 expectedQuotient = 0;
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128Divide1By1) {
+ i128 dividend = 1;
+ i128 divider = 1;
+ i128 expectedQuotient = 1;
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128Divide2By1) {
+ i128 dividend = 2;
+ i128 divider = 1;
+ i128 expectedQuotient = 2;
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128Divide42By1) {
+ i128 dividend = 42;
+ i128 divider = 1;
+ i128 expectedQuotient = 42;
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128DivideMaxUi64By1) {
+ i128 dividend = std::numeric_limits<ui64>::max();
+ i128 divider = 1;
+ i128 expectedQuotient = std::numeric_limits<ui64>::max();
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128DivideMaxUi64Plus1By1) {
+ i128 dividend = i128{std::numeric_limits<ui64>::max()} + i128{1};
+ i128 divider = 1;
+ i128 expectedQuotient = i128{std::numeric_limits<ui64>::max()} + i128{1};
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128DivideMaxUi64Plus42By1) {
+ i128 dividend = i128{std::numeric_limits<ui64>::max()} + i128{42};
+ i128 divider = 1;
+ i128 expectedQuotient = i128{std::numeric_limits<ui64>::max()} + i128{42};
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128DivideMaxI128By1) {
+ i128 dividend = std::numeric_limits<i128>::max();
+ i128 divider = 1;
+ i128 expectedQuotient = std::numeric_limits<i128>::max();
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128DivideMaxI128Minus1By1) {
+ i128 dividend = std::numeric_limits<i128>::max() - 1;
+ i128 divider = 1;
+ i128 expectedQuotient = std::numeric_limits<i128>::max() - 1;
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+}
+
+Y_UNIT_TEST_SUITE(I128DivisionByEqualSuite) {
+ Y_UNIT_TEST(I128Divide1ByEqual) {
+ i128 dividend = 1;
+ i128 divider = dividend;
+ i128 expectedQuotient = 1;
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128Divide2ByEqual) {
+ i128 dividend = 2;
+ i128 divider = dividend;
+ i128 expectedQuotient = 1;
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128Divide42ByEqual) {
+ i128 dividend = 42;
+ i128 divider = dividend;
+ i128 expectedQuotient = 1;
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128DivideMaxUi64ByEqual) {
+ i128 dividend = std::numeric_limits<ui64>::max();
+ i128 divider = dividend;
+ i128 expectedQuotient = 1;
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128DivideMaxUi64Plus1ByEqual) {
+ i128 dividend = i128{std::numeric_limits<ui64>::max()} + i128{1};
+ i128 divider = dividend;
+ i128 expectedQuotient = 1;
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128DivideMaxUi64Plus42ByEqual) {
+ i128 dividend = i128{std::numeric_limits<ui64>::max()} + i128{42};
+ i128 divider = dividend;
+ i128 expectedQuotient = 1;
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128DivideMaxI128ByEqual) {
+ i128 dividend = std::numeric_limits<i128>::max();
+ i128 divider = dividend;
+ i128 expectedQuotient = 1;
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128DivideMaxI128Minus1ByEqual) {
+ i128 dividend = std::numeric_limits<i128>::max() - 1;
+ i128 divider = dividend;
+ i128 expectedQuotient = 1;
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+}
+
+Y_UNIT_TEST_SUITE(I128DivisionLessByHigherSuite) {
+ Y_UNIT_TEST(I128Divide42By84) {
+ i128 dividend = 42;
+ i128 divider = 84;
+ i128 expectedQuotient = 0;
+ i128 expectedRemainder = 42;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128Divide42ByMaxUi64) {
+ i128 dividend = 42;
+ i128 divider = std::numeric_limits<ui64>::max();
+ i128 expectedQuotient = 0;
+ i128 expectedRemainder = 42;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128Divide42ByMaxUi64Plus1) {
+ i128 dividend = 42;
+ i128 divider = i128{std::numeric_limits<ui64>::max()} + i128{1};
+ i128 expectedQuotient = 0;
+ i128 expectedRemainder = 42;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(I128DivideMaxUi64ByMaxUi64Plus1) {
+ i128 dividend = i128{std::numeric_limits<ui64>::max()};
+ i128 divider = i128{std::numeric_limits<ui64>::max()} + i128{1};
+ i128 expectedQuotient = 0;
+ i128 expectedRemainder = i128{std::numeric_limits<ui64>::max()};
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+}
+
+Y_UNIT_TEST_SUITE(I128DivisionWithDifferentSigns) {
+ Y_UNIT_TEST(DivisionPositiveByNegative) {
+ i128 dividend = i128{100};
+ i128 divider = i128{-33};
+ i128 expectedQuotient = -3;
+ i128 expectedRemainder = 1;
+ i128 quotient = dividend / divider;
+ i128 remainder = dividend % divider;
+
+ UNIT_ASSERT_EQUAL(quotient, expectedQuotient);
+ UNIT_ASSERT_EQUAL(remainder, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(DivisionNegativeByPositive) {
+ i128 dividend = i128{-100};
+ i128 divider = i128{33};
+ i128 expectedQuotient = -3;
+ i128 expectedRemainder = -1;
+ i128 quotient = dividend / divider;
+ i128 remainder = dividend % divider;
+
+ UNIT_ASSERT_EQUAL(quotient, expectedQuotient);
+ UNIT_ASSERT_EQUAL(remainder, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(DivisionNegativeByNegative) {
+ i128 dividend = i128{-100};
+ i128 divider = i128{-33};
+ i128 expectedQuotient = 3;
+ i128 expectedRemainder = -1;
+ i128 quotient = dividend / divider;
+ i128 remainder = dividend % divider;
+
+ UNIT_ASSERT_EQUAL(quotient, expectedQuotient);
+ UNIT_ASSERT_EQUAL(remainder, expectedRemainder);
+ }
+}
+
+Y_UNIT_TEST_SUITE(i128DivisionBigByBigSuite) {
+ Y_UNIT_TEST(i128DivideBigByBig1) {
+ i128 dividend = {64, 0};
+ i128 divider = {1, 0};
+ i128 expectedQuotient = 64;
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(i128DivideBigByBig1_PosByNeg) {
+ i128 dividend = i128{64, 0};
+ i128 divider = -i128{1, 0};
+ i128 expectedQuotient = -i128{64};
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(i128DivideBigByBig1_NegByPos) {
+ i128 dividend = -i128{64, 0};
+ i128 divider = i128{1, 0};
+ i128 expectedQuotient = -i128{64};
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(i128DivideBigByBig1_NegByNeg) {
+ i128 dividend = -i128{64, 0};
+ i128 divider = -i128{1, 0};
+ i128 expectedQuotient = i128{64};
+ i128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(i128DivideBigByBig2) {
+ i128 dividend = {64, 0};
+ i128 divider = {12, 5};
+ i128 expectedQuotient = 5;
+ i128 expectedRemainder = i128{3, 18446744073709551591ull}; // plz don't ask
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(i128DivideBigByBig2_PosByNeg) {
+ i128 dividend = i128{64, 0};
+ i128 divider = -i128{12, 5};
+ i128 expectedQuotient = -5;
+ i128 expectedRemainder = i128{3, 18446744073709551591ull};
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(i128DivideBigByBig2_NegByPos) {
+ i128 dividend = -i128{64, 0};
+ i128 divider = i128{12, 5};
+ i128 expectedQuotient = -5;
+ i128 expectedRemainder = -i128{3, 18446744073709551591ull};
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(i128DivideBigByBig2_NegByNeg) {
+ i128 dividend = -i128{64, 0};
+ i128 divider = -i128{12, 5};
+ i128 expectedQuotient = 5;
+ i128 expectedRemainder = -i128{3, 18446744073709551591ull};
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+}
+
+Y_UNIT_TEST_SUITE(i128DivisionAlgo) {
+ Y_UNIT_TEST(ii128DivideAlgoCheck_PosByPos) {
+ /*
+ 49672666804009505000000 / 10000000 == 4967266680400950
+ 49672666804009505000000 % 10000000 == 5000000
+ */
+ i128 dividend = {2692ull, 14031757583392049728ull};
+ i64 divider = 10000000;
+ i128 expectedQuotient = {0, 4967266680400950ull};
+ i128 expectedRemainder = {0, 5000000ull};
+
+ i128 quotient = dividend / divider;
+ i128 reminder = dividend % divider;
+
+ UNIT_ASSERT_EQUAL(quotient, expectedQuotient);
+ UNIT_ASSERT_EQUAL(reminder, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(ii128DivideAlgoCheck_PosByNeg) {
+ /*
+ 49672666804009505000000 / -10000000 == -4967266680400950
+ 49672666804009505000000 % -10000000 == 5000000
+ */
+ i128 dividend = {2692ull, 14031757583392049728ull};
+ i64 divider = -10000000;
+ i128 expectedQuotient = -i128{0, 4967266680400950ull};
+ i128 expectedRemainder = {0, 5000000ull};
+
+ i128 quotient = dividend / divider;
+ i128 reminder = dividend % divider;
+
+ UNIT_ASSERT_EQUAL(quotient, expectedQuotient);
+ UNIT_ASSERT_EQUAL(reminder, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(ii128DivideAlgoCheck_NegByPos) {
+ /*
+ -49672666804009505000000 / 10000000 == -4967266680400950
+ -49672666804009505000000 % 10000000 == -5000000
+ */
+ i128 dividend = -i128{2692ull, 14031757583392049728ull};
+ i64 divider = 10000000;
+ i128 expectedQuotient = -i128{0, 4967266680400950ull};
+ i128 expectedRemainder = -i128{0, 5000000ull};
+
+ i128 quotient = dividend / divider;
+ i128 reminder = dividend % divider;
+
+ UNIT_ASSERT_EQUAL(quotient, expectedQuotient);
+ UNIT_ASSERT_EQUAL(reminder, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(ii128DivideAlgoCheck_NegByNeg) {
+ /*
+ -49672666804009505000000 / -10000000 == 4967266680400950
+ -49672666804009505000000 % -10000000 == -5000000
+ */
+ i128 dividend = -i128{2692ull, 14031757583392049728ull};
+ i64 divider = -10000000;
+ i128 expectedQuotient = {0, 4967266680400950ull};
+ i128 expectedRemainder = -i128{0, 5000000ull};
+
+ i128 quotient = dividend / divider;
+ i128 reminder = dividend % divider;
+
+ UNIT_ASSERT_EQUAL(quotient, expectedQuotient);
+ UNIT_ASSERT_EQUAL(reminder, expectedRemainder);
+ }
+
+}
diff --git a/library/cpp/int128/ut/i128_type_traits_ut.cpp b/library/cpp/int128/ut/i128_type_traits_ut.cpp
new file mode 100644
index 0000000000..4ed87bf229
--- /dev/null
+++ b/library/cpp/int128/ut/i128_type_traits_ut.cpp
@@ -0,0 +1,68 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/int128/int128.h>
+
+#include <util/generic/cast.h>
+
+Y_UNIT_TEST_SUITE(I128TypeTraitsSuite) {
+ Y_UNIT_TEST(OperatorNegate0) {
+ const i128 n = 0;
+ const i128 m = -n;
+ UNIT_ASSERT(n == m);
+ }
+
+ Y_UNIT_TEST(OperatorNegate1) {
+ const i128 n = 1;
+ const i128 m = -n;
+ const i128 expected = -1;
+ UNIT_ASSERT(m == expected);
+ }
+
+ Y_UNIT_TEST(OperatorNegate2Pow64) {
+ const i128 n = i128{1, 0};
+ const i128 m = -n;
+ const i128 expected = {static_cast<ui64>(-1), 0};
+ UNIT_ASSERT(m == expected);
+ }
+
+ Y_UNIT_TEST(OperatorNegateNegate) {
+ const i128 x = 1;
+ const i128 y = -x;
+ const i128 z = -y;
+ UNIT_ASSERT(z == x);
+ }
+
+ Y_UNIT_TEST(AbsFromPositive) {
+ const i128 n = 1;
+ const i128 m = std::abs(n);
+ UNIT_ASSERT(m == n);
+ }
+
+ Y_UNIT_TEST(AbsFromNegative) {
+ const i128 n = -1;
+ const i128 m = std::abs(n);
+ const i128 expected = 1;
+ UNIT_ASSERT(m == expected);
+ }
+
+ Y_UNIT_TEST(AbsFromZero) {
+ const i128 n = 0;
+ const i128 m = std::abs(n);
+ UNIT_ASSERT(m == n);
+ }
+
+ Y_UNIT_TEST(SignbitOfPositive) {
+ const i128 n = 1;
+ UNIT_ASSERT(!std::signbit(n));
+ }
+
+ Y_UNIT_TEST(SignbitOfNegative) {
+ const i128 n = -1;
+ UNIT_ASSERT(std::signbit(n));
+ }
+
+ Y_UNIT_TEST(SignbitOfZero) {
+ const i128 n = 0;
+ UNIT_ASSERT(!std::signbit(n));
+ }
+}
diff --git a/library/cpp/int128/ut/i128_ut.cpp b/library/cpp/int128/ut/i128_ut.cpp
new file mode 100644
index 0000000000..c196d132a2
--- /dev/null
+++ b/library/cpp/int128/ut/i128_ut.cpp
@@ -0,0 +1,12 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/int128/int128.h>
+
+#include <util/generic/cast.h>
+
+Y_UNIT_TEST_SUITE(I128Suite) {
+ Y_UNIT_TEST(CreateI128FromUnsigned) {
+ i128 v{ui64(1)};
+ Y_UNUSED(v);
+ }
+}
diff --git a/library/cpp/int128/ut/int128_old_ut.cpp b/library/cpp/int128/ut/int128_old_ut.cpp
new file mode 100644
index 0000000000..2c5b9e9610
--- /dev/null
+++ b/library/cpp/int128/ut/int128_old_ut.cpp
@@ -0,0 +1,179 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/int128/int128.h>
+
+#include "int128_ut_helpers.h"
+
+class TUInt128Test: public TTestBase {
+ UNIT_TEST_SUITE(TUInt128Test);
+ UNIT_TEST(Create);
+ UNIT_TEST(Minus);
+ UNIT_TEST(Plus);
+ UNIT_TEST(Shift)
+ UNIT_TEST(Overflow);
+ UNIT_TEST(Underflow);
+ UNIT_TEST(ToStringTest);
+ UNIT_TEST(FromStringTest);
+#if defined(Y_HAVE_INT128)
+ UNIT_TEST(FromSystemUint128);
+#endif
+ UNIT_TEST_SUITE_END();
+
+private:
+ void Create();
+ void Minus();
+ void Plus();
+ void Shift();
+ void Overflow();
+ void Underflow();
+ void ToStringTest();
+ void FromStringTest();
+#if defined(Y_HAVE_INT128)
+ void FromSystemUint128();
+#endif
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TUInt128Test);
+
+void TUInt128Test::Create() {
+ const ui128 n1 = 10;
+ UNIT_ASSERT_EQUAL(n1, 10);
+
+ const ui128 n2 = n1;
+ UNIT_ASSERT_EQUAL(n2, 10);
+
+ const ui128 n3(10);
+ UNIT_ASSERT_EQUAL(n3, 10);
+}
+void TUInt128Test::Minus() {
+ const ui128 n2 = 20;
+ const ui128 n3 = 30;
+
+ ui128 n4 = n3 - n2;
+ UNIT_ASSERT_EQUAL(n4, 10);
+
+ n4 = n4 - 2;
+ UNIT_ASSERT_EQUAL(n4, 8);
+
+ n4 -= 2;
+ UNIT_ASSERT_EQUAL(n4, 6);
+
+ n4 = 10 - n4;
+ UNIT_ASSERT_EQUAL(n4, 4);
+}
+void TUInt128Test::Plus() {
+ const ui128 n2 = 20;
+ const ui128 n3 = 30;
+
+ ui128 n4 = n3 + n2;
+ UNIT_ASSERT_EQUAL(n4, 50);
+
+ n4 = n4 + 2;
+ UNIT_ASSERT_EQUAL(n4, 52);
+
+ n4 += 2;
+ UNIT_ASSERT_EQUAL(n4, 54);
+
+ n4 = 10 + n4;
+ UNIT_ASSERT_EQUAL(n4, 64);
+}
+void TUInt128Test::Shift() {
+ ui128 n = 1;
+
+ const ui128 n4 = n << 4;
+ UNIT_ASSERT_EQUAL(n4, ui128(0x0, 0x0000000000000010));
+ UNIT_ASSERT_EQUAL(n4 >> 4, 1);
+
+ const ui128 n8 = n << 8;
+ UNIT_ASSERT_EQUAL(n8, ui128(0x0, 0x0000000000000100));
+ UNIT_ASSERT_EQUAL(n8 >> 8, 1);
+
+ const ui128 n60 = n << 60;
+ UNIT_ASSERT_EQUAL(n60, ui128(0x0, 0x1000000000000000));
+ UNIT_ASSERT_EQUAL(n60 >> 60, 1);
+
+ const ui128 n64 = n << 64;
+ UNIT_ASSERT_EQUAL(n64, ui128(0x1, 0x0000000000000000));
+ UNIT_ASSERT_EQUAL(n64 >> 64, 1);
+
+ const ui128 n124 = n << 124;
+ UNIT_ASSERT_EQUAL(n124, ui128(0x1000000000000000, 0x0000000000000000));
+ UNIT_ASSERT_EQUAL(n124 >> 124, 1);
+}
+
+void TUInt128Test::Overflow() {
+ ui128 n = ui128(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF);
+ const ui128 n2 = n + 2;
+ UNIT_ASSERT_EQUAL(n2, 1);
+}
+void TUInt128Test::Underflow() {
+ ui128 n = 1;
+ const ui128 n128 = n - 2;
+ UNIT_ASSERT_EQUAL(n128, ui128(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF));
+}
+
+void TUInt128Test::ToStringTest() {
+ ui128 n(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF);
+ TString correct = "340282366920938463463374607431768211455";
+ UNIT_ASSERT_EQUAL(correct, ::ToString(n));
+}
+
+void TUInt128Test::FromStringTest() {
+ {
+ const TString originalString = "37778931862957161709568";
+ const ui128 number = FromString<ui128>(originalString);
+ UNIT_ASSERT_EQUAL(ToString(number), originalString);
+ }
+
+ {
+ const TString originalString = "1024";
+ const ui128 number = FromString<ui128>(originalString);
+ UNIT_ASSERT_EQUAL(ToString(number), originalString);
+ UNIT_ASSERT_EQUAL(GetHigh(number), 0);
+ UNIT_ASSERT_EQUAL(GetLow(number), 1024);
+ }
+
+ {
+ const TString originalString = "18446744073709551616"; // 2^64, i.e. UINT64_MAX + 1
+ const ui128 number = FromString<ui128>(originalString);
+ UNIT_ASSERT_EQUAL(ToString(number), originalString);
+ UNIT_ASSERT_EQUAL(GetHigh(number), 1);
+ UNIT_ASSERT_EQUAL(GetLow(number), 0);
+ }
+
+ {
+ const TString originalString = "340282366920938463463374607431768211455"; // 2^128-1, i.e. UINT128_MAX
+ const ui128 number = FromString<ui128>(originalString);
+ UNIT_ASSERT_EQUAL(ToString(number), originalString);
+ UNIT_ASSERT_EQUAL(GetHigh(number), 0xFFFFFFFFFFFFFFFF);
+ UNIT_ASSERT_EQUAL(GetLow(number), 0xFFFFFFFFFFFFFFFF);
+ }
+}
+
+#if defined(Y_HAVE_INT128)
+void TUInt128Test::FromSystemUint128() {
+ unsigned __int128 n = 1;
+ ui128 number{n};
+
+ UNIT_ASSERT_EQUAL(GetLow(number), 1);
+ UNIT_ASSERT_EQUAL(GetHigh(number), 0);
+
+ auto byteArray = NInt128Private::GetAsArray(number);
+#ifdef _little_endian_
+ UNIT_ASSERT_EQUAL(byteArray[0], 1);
+ for (size_t i = 1; i < 16; i++) {
+ UNIT_ASSERT_EQUAL(byteArray[i], 0);
+ }
+#elif defined(_big_endian_)
+ UNIT_ASSERT_EQUAL(byteArray[15], 1);
+ for (size_t i = 0; i < 15; i++) {
+ UNIT_ASSERT_EQUAL(byteArray[i], 0);
+ }
+#endif
+
+ UNIT_ASSERT_EQUAL(std::memcmp((void*)&n, (void*)&number, 16), 0);
+
+ UNIT_ASSERT_EQUAL(ToString(n), "1");
+
+ UNIT_ASSERT_EQUAL(FromString<unsigned __int128>(ToString(n)), n);
+}
+#endif
diff --git a/library/cpp/int128/ut/int128_typetraits_ut.cpp b/library/cpp/int128/ut/int128_typetraits_ut.cpp
new file mode 100644
index 0000000000..fd5f19d7b8
--- /dev/null
+++ b/library/cpp/int128/ut/int128_typetraits_ut.cpp
@@ -0,0 +1,306 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/int128/int128.h>
+
+#include <type_traits>
+
+Y_UNIT_TEST_SUITE(TypeTraitsSuite) {
+ Y_UNIT_TEST(Uint128TypeTraits) {
+ // checks that all type traits of ui128 are the same as of ui64
+ // https://en.cppreference.com/w/cpp/header/type_traits
+ UNIT_ASSERT_EQUAL(
+ std::is_void<ui128>::value,
+ std::is_void<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_null_pointer<ui128>::value,
+ std::is_null_pointer<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_integral<ui128>::value,
+ std::is_integral<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_floating_point<ui128>::value,
+ std::is_floating_point<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_array<ui128>::value,
+ std::is_array<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_enum<ui128>::value,
+ std::is_enum<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_union<ui128>::value,
+ std::is_union<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_class<ui128>::value,
+ std::is_class<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_function<ui128>::value,
+ std::is_function<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_pointer<ui128>::value,
+ std::is_pointer<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_lvalue_reference<ui128>::value,
+ std::is_lvalue_reference<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_rvalue_reference<ui128>::value,
+ std::is_rvalue_reference<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_member_object_pointer<ui128>::value,
+ std::is_member_object_pointer<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_member_function_pointer<ui128>::value,
+ std::is_member_function_pointer<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_fundamental<ui128>::value,
+ std::is_fundamental<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_arithmetic<ui128>::value,
+ std::is_arithmetic<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_scalar<ui128>::value,
+ std::is_scalar<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_object<ui128>::value,
+ std::is_object<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_compound<ui128>::value,
+ std::is_compound<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_reference<ui128>::value,
+ std::is_reference<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_member_pointer<ui128>::value,
+ std::is_member_pointer<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_const<ui128>::value,
+ std::is_const<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_volatile<ui128>::value,
+ std::is_volatile<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_trivial<ui128>::value,
+ std::is_trivial<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_standard_layout<ui128>::value,
+ std::is_standard_layout<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_pod<ui128>::value,
+ std::is_pod<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_literal_type<ui128>::value,
+ std::is_literal_type<ui64>::value
+ );
+#ifndef _MSC_VER
+ UNIT_ASSERT_EQUAL(
+ std::has_unique_object_representations<ui128>::value,
+ std::has_unique_object_representations<ui64>::value
+ );
+#endif
+ UNIT_ASSERT_EQUAL(
+ std::is_empty<ui128>::value,
+ std::is_empty<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_polymorphic<ui128>::value,
+ std::is_polymorphic<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_abstract<ui128>::value,
+ std::is_abstract<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_final<ui128>::value,
+ std::is_final<ui64>::value
+ );
+#ifndef _MSC_VER
+ UNIT_ASSERT_EQUAL(
+ std::is_aggregate<ui128>::value,
+ std::is_aggregate<ui64>::value
+ );
+#endif
+ UNIT_ASSERT_EQUAL(
+ std::is_signed<ui128>::value,
+ std::is_signed<ui64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_unsigned<ui128>::value,
+ std::is_unsigned<ui64>::value
+ );
+ }
+
+ Y_UNIT_TEST(Int128TypeTraits) {
+ // checks that all type traits of i128 are the same as of i64
+ // https://en.cppreference.com/w/cpp/header/type_traits
+ UNIT_ASSERT_EQUAL(
+ std::is_void<i128>::value,
+ std::is_void<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_null_pointer<i128>::value,
+ std::is_null_pointer<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_integral<i128>::value,
+ std::is_integral<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_floating_point<i128>::value,
+ std::is_floating_point<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_array<i128>::value,
+ std::is_array<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_enum<i128>::value,
+ std::is_enum<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_union<i128>::value,
+ std::is_union<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_class<i128>::value,
+ std::is_class<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_function<i128>::value,
+ std::is_function<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_pointer<i128>::value,
+ std::is_pointer<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_lvalue_reference<i128>::value,
+ std::is_lvalue_reference<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_rvalue_reference<i128>::value,
+ std::is_rvalue_reference<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_member_object_pointer<i128>::value,
+ std::is_member_object_pointer<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_member_function_pointer<i128>::value,
+ std::is_member_function_pointer<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_fundamental<i128>::value,
+ std::is_fundamental<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_arithmetic<i128>::value,
+ std::is_arithmetic<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_scalar<i128>::value,
+ std::is_scalar<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_object<i128>::value,
+ std::is_object<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_compound<i128>::value,
+ std::is_compound<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_reference<i128>::value,
+ std::is_reference<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_member_pointer<i128>::value,
+ std::is_member_pointer<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_const<i128>::value,
+ std::is_const<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_volatile<i128>::value,
+ std::is_volatile<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_trivial<i128>::value,
+ std::is_trivial<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_standard_layout<i128>::value,
+ std::is_standard_layout<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_pod<i128>::value,
+ std::is_pod<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_literal_type<i128>::value,
+ std::is_literal_type<i64>::value
+ );
+#ifndef _MSC_VER
+ UNIT_ASSERT_EQUAL(
+ std::has_unique_object_representations<i128>::value,
+ std::has_unique_object_representations<i64>::value
+ );
+#endif
+ UNIT_ASSERT_EQUAL(
+ std::is_empty<i128>::value,
+ std::is_empty<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_polymorphic<i128>::value,
+ std::is_polymorphic<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_abstract<i128>::value,
+ std::is_abstract<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_final<i128>::value,
+ std::is_final<i64>::value
+ );
+#ifndef _MSC_VER
+ UNIT_ASSERT_EQUAL(
+ std::is_aggregate<i128>::value,
+ std::is_aggregate<i64>::value
+ );
+#endif
+ UNIT_ASSERT_EQUAL(
+ std::is_signed<i128>::value,
+ std::is_signed<i64>::value
+ );
+ UNIT_ASSERT_EQUAL(
+ std::is_unsigned<i128>::value,
+ std::is_unsigned<i64>::value
+ );
+ }
+}
+
diff --git a/library/cpp/int128/ut/int128_ut.cpp b/library/cpp/int128/ut/int128_ut.cpp
new file mode 100644
index 0000000000..7339264017
--- /dev/null
+++ b/library/cpp/int128/ut/int128_ut.cpp
@@ -0,0 +1,83 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/int128/int128.h>
+
+#include <util/generic/cast.h>
+
+#include <type_traits>
+
+Y_UNIT_TEST_SUITE(Uint128Suite) {
+ Y_UNIT_TEST(Uint128DefaultCtor) {
+ const ui128 value{};
+ UNIT_ASSERT_EQUAL(GetLow(value), 0);
+ UNIT_ASSERT_EQUAL(GetHigh(value), 0);
+ }
+
+ Y_UNIT_TEST(Uint128NumericLimits) {
+ UNIT_ASSERT_EQUAL(std::numeric_limits<ui128>::digits, 128);
+ UNIT_ASSERT_EQUAL(std::numeric_limits<ui128>::max() + 1, ui128{0});
+ }
+
+ Y_UNIT_TEST(Uint128Sizeof) {
+ UNIT_ASSERT_EQUAL(sizeof(ui128), sizeof(ui64) * 2);
+ }
+
+ Y_UNIT_TEST(Uint128Cast) {
+ // see util/generic/cast.h
+ const auto underlyingTypeIsSelf = std::is_same<::NPrivate::TUnderlyingTypeOrSelf<ui128>, ui128>::value;
+ UNIT_ASSERT_EQUAL(underlyingTypeIsSelf, true);
+
+ const auto convertibleUi128Ui128 = ::NPrivate::TSafelyConvertible<ui128, ui128>::Result;
+ const auto convertibleUi64Ui128 = ::NPrivate::TSafelyConvertible<ui64, ui128>::Result;
+ const auto convertibleUi128Ui64 = ::NPrivate::TSafelyConvertible<ui128, ui64>::Result;
+ UNIT_ASSERT_EQUAL(convertibleUi128Ui128, true); // from ui128 to ui128 => safe
+ UNIT_ASSERT_EQUAL(convertibleUi64Ui128, false); // from ui128 to ui64 => not safe
+ UNIT_ASSERT_EQUAL(convertibleUi128Ui64, true); // from ui64 to ui128 => safe
+ }
+
+ Y_UNIT_TEST(SafeIntegerCastTest) {
+ ui128 narrowNumber = 1;
+
+ UNIT_ASSERT_NO_EXCEPTION(SafeIntegerCast<ui64>(narrowNumber));
+
+ ui128 wideNumber{0};
+ wideNumber -= 1;
+ UNIT_ASSERT_EXCEPTION(SafeIntegerCast<ui64>(wideNumber), yexception);
+ }
+
+ Y_UNIT_TEST(SignbitTest) {
+ UNIT_ASSERT(!std::signbit(ui128{0}));
+ UNIT_ASSERT(!std::signbit(ui128{-1}));
+ UNIT_ASSERT(!std::signbit(i128{0}));
+ UNIT_ASSERT(std::signbit(i128{-1}));
+ }
+
+ Y_UNIT_TEST(ToStringTest) {
+ // int128
+ UNIT_ASSERT_VALUES_EQUAL(ToString(i128(0)), "0");
+ UNIT_ASSERT_VALUES_EQUAL(ToString(i128(42)), "42");
+ UNIT_ASSERT_VALUES_EQUAL(ToString(i128(-142)), "-142");
+ UNIT_ASSERT_VALUES_EQUAL(ToString(std::numeric_limits<i128>::min()), "-170141183460469231731687303715884105728");
+ UNIT_ASSERT_VALUES_EQUAL(ToString(std::numeric_limits<i128>::max()), "170141183460469231731687303715884105727");
+
+ // Just random number
+ UNIT_ASSERT_VALUES_EQUAL(
+ ToString(
+ - ((i128(8741349088318632894ul) << 64) | i128(1258331728153556511ul))
+ ),
+ "-161249429491168133245752281683002013215");
+
+ // uint128
+ UNIT_ASSERT_VALUES_EQUAL(ToString(ui128(0)), "0");
+ UNIT_ASSERT_VALUES_EQUAL(ToString(ui128(42)), "42");
+ UNIT_ASSERT_VALUES_EQUAL(ToString(std::numeric_limits<ui128>::min()), "0");
+ UNIT_ASSERT_VALUES_EQUAL(ToString(std::numeric_limits<ui128>::max()), "340282366920938463463374607431768211455");
+
+ // Just random number
+ UNIT_ASSERT_VALUES_EQUAL(
+ ToString(
+ ((ui128(12745260439834612983ul) << 64) | ui128(10970669179777569799ul))
+ ),
+ "235108557486403940296800289353599800327");
+ }
+}
diff --git a/library/cpp/int128/ut/int128_ut_helpers.cpp b/library/cpp/int128/ut/int128_ut_helpers.cpp
new file mode 100644
index 0000000000..e6c3e24d10
--- /dev/null
+++ b/library/cpp/int128/ut/int128_ut_helpers.cpp
@@ -0,0 +1,56 @@
+#include "int128_ut_helpers.h"
+
+namespace NInt128Private {
+#if defined(_little_endian_)
+ std::array<ui8, 16> GetAsArray(const ui128 value) {
+ std::array<ui8, 16> result;
+ const ui64 low = GetLow(value);
+ const ui64 high = GetHigh(value);
+ MemCopy(result.data(), reinterpret_cast<const ui8*>(&low), sizeof(low));
+ MemCopy(result.data() + sizeof(low), reinterpret_cast<const ui8*>(&high), sizeof(high));
+ return result;
+ }
+
+ std::array<ui8, 16> GetAsArray(const i128 value) {
+ std::array<ui8, 16> result;
+ const ui64 low = GetLow(value);
+ const ui64 high = GetHigh(value);
+ MemCopy(result.data(), reinterpret_cast<const ui8*>(&low), sizeof(low));
+ MemCopy(result.data() + sizeof(low), reinterpret_cast<const ui8*>(&high), sizeof(high));
+ return result;
+ }
+#elif defined(_big_endian_)
+ std::array<ui8, 16> GetAsArray(const i128 value) {
+ std::array<ui8, 16> result;
+ const ui64 low = GetLow(value);
+ const ui64 high = GetHigh(value);
+ MemCopy(result.data(), reinterpret_cast<const ui8*>(&high), sizeof(high));
+ MemCopy(result.data() + sizeof(high), reinterpret_cast<const ui8*>(&low), sizeof(low));
+ return result;
+ }
+
+ std::array<ui8, 16> GetAsArray(const ui128 value) {
+ std::array<ui8, 16> result;
+ const ui64 low = GetLow(value);
+ const ui64 high = GetHigh(value);
+ MemCopy(result.data(), reinterpret_cast<const ui8*>(&high), sizeof(high));
+ MemCopy(result.data() + sizeof(high), reinterpret_cast<const ui8*>(&low), sizeof(low));
+ return result;
+ }
+#endif
+
+#if defined(Y_HAVE_INT128)
+ std::array<ui8, 16> GetAsArray(const unsigned __int128 value) {
+ std::array<ui8, 16> result;
+ MemCopy(result.data(), reinterpret_cast<const ui8*>(&value), sizeof(value));
+ return result;
+ }
+
+ std::array<ui8, 16> GetAsArray(const signed __int128 value) {
+ std::array<ui8, 16> result;
+ MemCopy(result.data(), reinterpret_cast<const ui8*>(&value), sizeof(value));
+ return result;
+ }
+#endif
+
+}
diff --git a/library/cpp/int128/ut/int128_ut_helpers.h b/library/cpp/int128/ut/int128_ut_helpers.h
new file mode 100644
index 0000000000..b7778c3f32
--- /dev/null
+++ b/library/cpp/int128/ut/int128_ut_helpers.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <library/cpp/int128/int128.h>
+
+#include <array>
+
+namespace NInt128Private {
+ std::array<ui8, 16> GetAsArray(const ui128 value);
+ std::array<ui8, 16> GetAsArray(const i128 value);
+
+#if defined(Y_HAVE_INT128)
+ std::array<ui8, 16> GetAsArray(const unsigned __int128 value);
+ std::array<ui8, 16> GetAsArray(const signed __int128 value);
+#endif
+}
diff --git a/library/cpp/int128/ut/int128_via_intrinsic_ut.cpp b/library/cpp/int128/ut/int128_via_intrinsic_ut.cpp
new file mode 100644
index 0000000000..9decc2fd48
--- /dev/null
+++ b/library/cpp/int128/ut/int128_via_intrinsic_ut.cpp
@@ -0,0 +1,34 @@
+#include <library/cpp/int128/int128.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+// from https://a.yandex-team.ru/arc/trunk/arcadia/library/ticket_parser/c/src/ut/utils_ut.cpp?rev=4221861
+
+#if defined(Y_HAVE_INT128)
+Y_UNIT_TEST_SUITE(Int128ViaIntrinsicSuite) {
+ using guint128_t = unsigned __int128;
+ guint128_t toGcc(ui128 num) {
+ guint128_t res = 0;
+ res |= GetLow(num);
+ res |= guint128_t(GetHigh(num)) << 64;
+ return res;
+ }
+
+ Y_UNIT_TEST(bigintTest) {
+ UNIT_ASSERT(guint128_t(127) == toGcc(ui128(127)));
+ UNIT_ASSERT(guint128_t(127) * guint128_t(127) == toGcc(ui128(127) * ui128(127)));
+ UNIT_ASSERT(guint128_t(127) + guint128_t(127) == toGcc(ui128(127) + ui128(127)));
+ UNIT_ASSERT(guint128_t(127) << 3 == toGcc(ui128(127) << 3));
+ UNIT_ASSERT(guint128_t(127) >> 1 == toGcc(ui128(127) >> 1));
+
+ UNIT_ASSERT(guint128_t(1000000000027UL) * guint128_t(1000000000027UL) == toGcc(ui128(1000000000027UL) * ui128(1000000000027UL)));
+ UNIT_ASSERT(guint128_t(1000000000027UL) + guint128_t(1000000000027UL) == toGcc(ui128(1000000000027UL) + ui128(1000000000027UL)));
+ UNIT_ASSERT(guint128_t(1000000000027UL) << 3 == toGcc(ui128(1000000000027UL) << 3));
+ UNIT_ASSERT(guint128_t(1000000000027UL) >> 1 == toGcc(ui128(1000000000027UL) >> 1));
+ UNIT_ASSERT((guint128_t(1000000000027UL) * guint128_t(1000000000027UL)) << 3 == toGcc((ui128(1000000000027UL) * ui128(1000000000027UL)) << 3));
+ UNIT_ASSERT((guint128_t(1000000000027UL) + guint128_t(1000000000027UL)) >> 1 == toGcc((ui128(1000000000027UL) + ui128(1000000000027UL)) >> 1));
+
+ UNIT_ASSERT((ui64)(guint128_t(1000000000027UL) * guint128_t(1000000000027UL)) == GetLow(ui128(1000000000027UL) * ui128(1000000000027UL)));
+ }
+}
+#endif
diff --git a/library/cpp/int128/ut/ui128_division_ut.cpp b/library/cpp/int128/ut/ui128_division_ut.cpp
new file mode 100644
index 0000000000..4826a531e0
--- /dev/null
+++ b/library/cpp/int128/ut/ui128_division_ut.cpp
@@ -0,0 +1,262 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/int128/int128.h>
+
+#include <util/generic/cast.h>
+
+Y_UNIT_TEST_SUITE(Ui128DivisionBy1Suite) {
+ Y_UNIT_TEST(Ui128Divide0By1) {
+ ui128 dividend = 0;
+ ui128 divider = 1;
+ ui128 expectedQuotient = 0;
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128Divide1By1) {
+ ui128 dividend = 1;
+ ui128 divider = 1;
+ ui128 expectedQuotient = 1;
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128Divide2By1) {
+ ui128 dividend = 2;
+ ui128 divider = 1;
+ ui128 expectedQuotient = 2;
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128Divide42By1) {
+ ui128 dividend = 42;
+ ui128 divider = 1;
+ ui128 expectedQuotient = 42;
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128DivideMaxUi64By1) {
+ ui128 dividend = std::numeric_limits<ui64>::max();
+ ui128 divider = 1;
+ ui128 expectedQuotient = std::numeric_limits<ui64>::max();
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128DivideMaxUi64Plus1By1) {
+ ui128 dividend = ui128{std::numeric_limits<ui64>::max()} + ui128{1};
+ ui128 divider = 1;
+ ui128 expectedQuotient = ui128{std::numeric_limits<ui64>::max()} + ui128{1};
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128DivideMaxUi64Plus42By1) {
+ ui128 dividend = ui128{std::numeric_limits<ui64>::max()} + ui128{42};
+ ui128 divider = 1;
+ ui128 expectedQuotient = ui128{std::numeric_limits<ui64>::max()} + ui128{42};
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128DivideMaxUi128By1) {
+ ui128 dividend = std::numeric_limits<ui128>::max();
+ ui128 divider = 1;
+ ui128 expectedQuotient = std::numeric_limits<ui128>::max();
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128DivideMaxUi128Minus1By1) {
+ ui128 dividend = std::numeric_limits<ui128>::max() - 1;
+ ui128 divider = 1;
+ ui128 expectedQuotient = std::numeric_limits<ui128>::max() - 1;
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+}
+
+Y_UNIT_TEST_SUITE(Ui128DivisionByEqualSuite) {
+ Y_UNIT_TEST(Ui128Divide1ByEqual) {
+ ui128 dividend = 1;
+ ui128 divider = dividend;
+ ui128 expectedQuotient = 1;
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128Divide2ByEqual) {
+ ui128 dividend = 2;
+ ui128 divider = dividend;
+ ui128 expectedQuotient = 1;
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128Divide42ByEqual) {
+ ui128 dividend = 42;
+ ui128 divider = dividend;
+ ui128 expectedQuotient = 1;
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128DivideMaxUi64ByEqual) {
+ ui128 dividend = std::numeric_limits<ui64>::max();
+ ui128 divider = dividend;
+ ui128 expectedQuotient = 1;
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128DivideMaxUi64Plus1ByEqual) {
+ ui128 dividend = ui128{std::numeric_limits<ui64>::max()} + ui128{1};
+ ui128 divider = dividend;
+ ui128 expectedQuotient = 1;
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128DivideMaxUi64Plus42ByEqual) {
+ ui128 dividend = ui128{std::numeric_limits<ui64>::max()} + ui128{42};
+ ui128 divider = dividend;
+ ui128 expectedQuotient = 1;
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128DivideMaxUi128ByEqual) {
+ ui128 dividend = std::numeric_limits<ui128>::max();
+ ui128 divider = dividend;
+ ui128 expectedQuotient = 1;
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128DivideMaxUi128Minus1ByEqual) {
+ ui128 dividend = std::numeric_limits<ui128>::max() - 1;
+ ui128 divider = dividend;
+ ui128 expectedQuotient = 1;
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+}
+
+Y_UNIT_TEST_SUITE(Ui128DivisionLessByHigherSuite) {
+ Y_UNIT_TEST(Ui128Divide42By84) {
+ ui128 dividend = 42;
+ ui128 divider = 84;
+ ui128 expectedQuotient = 0;
+ ui128 expectedRemainder = 42;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128Divide42ByMaxUi64) {
+ ui128 dividend = 42;
+ ui128 divider = std::numeric_limits<ui64>::max();
+ ui128 expectedQuotient = 0;
+ ui128 expectedRemainder = 42;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128Divide42ByMaxUi64Plus1) {
+ ui128 dividend = 42;
+ ui128 divider = ui128{std::numeric_limits<ui64>::max()} + ui128{1};
+ ui128 expectedQuotient = 0;
+ ui128 expectedRemainder = 42;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128DivideMaxUi64ByMaxUi64Plus1) {
+ ui128 dividend = ui128{std::numeric_limits<ui64>::max()};
+ ui128 divider = ui128{std::numeric_limits<ui64>::max()} + ui128{1};
+ ui128 expectedQuotient = 0;
+ ui128 expectedRemainder = ui128{std::numeric_limits<ui64>::max()};
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+}
+
+Y_UNIT_TEST_SUITE(Ui128DivisionBigByBigSuite) {
+ Y_UNIT_TEST(Ui128DivideBigByBig1) {
+ ui128 dividend = {64, 0};
+ ui128 divider = {1, 0};
+ ui128 expectedQuotient = 64;
+ ui128 expectedRemainder = 0;
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+
+ Y_UNIT_TEST(Ui128DivideBigByBig2) {
+ ui128 dividend = {64, 0};
+ ui128 divider = {12, 5};
+ ui128 expectedQuotient = 5;
+ ui128 expectedRemainder = ui128{3, 18446744073709551591ull}; // plz don't ask
+
+ UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient);
+ UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder);
+ }
+}
+
+Y_UNIT_TEST_SUITE(Ui128DivisionAlgo) {
+ Y_UNIT_TEST(Ui128DivideAlgoCheck) {
+ /*
+ 49672666804009505000000 / 10000000 == 4967266680400950
+ 49672666804009505000000 % 10000000 == 5000000
+ */
+ ui128 dividend = {2692ull, 14031757583392049728ull};
+ ui64 divider = 10000000;
+ ui128 expectedQuotient = {0, 4967266680400950ull};
+ ui128 expectedRemainder = {0, 5000000ull};
+
+ ui128 quotient = dividend / divider;
+ ui128 reminder = dividend % divider;
+
+ UNIT_ASSERT_EQUAL(quotient, expectedQuotient);
+ UNIT_ASSERT_EQUAL(reminder, expectedRemainder);
+ }
+}
diff --git a/library/cpp/int128/ut/ya.make b/library/cpp/int128/ut/ya.make
new file mode 100644
index 0000000000..fd43531c5f
--- /dev/null
+++ b/library/cpp/int128/ut/ya.make
@@ -0,0 +1,20 @@
+UNITTEST_FOR(library/cpp/int128)
+
+OWNER(vladon)
+
+SRCS(
+ int128_ut_helpers.cpp
+ int128_ut_helpers.h
+ int128_ut.cpp
+ int128_typetraits_ut.cpp
+ int128_old_ut.cpp
+ int128_via_intrinsic_ut.cpp
+ i128_ut.cpp
+ i128_and_intrinsic_identity_ut.cpp
+ i128_comparison_ut.cpp
+ i128_division_ut.cpp
+ i128_type_traits_ut.cpp
+ ui128_division_ut.cpp
+)
+
+END()
diff --git a/library/cpp/int128/ya.make b/library/cpp/int128/ya.make
new file mode 100644
index 0000000000..95e453e6f1
--- /dev/null
+++ b/library/cpp/int128/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(
+ vladon
+ # g:zora
+)
+
+SRCS(
+ int128.cpp
+ int128.h
+)
+
+END()
diff --git a/library/cpp/ipmath/ipmath.cpp b/library/cpp/ipmath/ipmath.cpp
new file mode 100644
index 0000000000..b8cca00c80
--- /dev/null
+++ b/library/cpp/ipmath/ipmath.cpp
@@ -0,0 +1,357 @@
+#include "ipmath.h"
+
+namespace {
+ constexpr auto IPV4_BITS = 32;
+ constexpr auto IPV6_BITS = 128;
+
+ const ui128 MAX_IPV4_ADDR = Max<ui32>();
+ const ui128 MAX_IPV6_ADDR = Max<ui128>();
+
+ TStringBuf TypeToString(TIpv6Address::TIpType type) {
+ switch (type) {
+ case TIpv6Address::Ipv4:
+ return TStringBuf("IPv4");
+ case TIpv6Address::Ipv6:
+ return TStringBuf("IPv6");
+ default:
+ return TStringBuf("UNKNOWN");
+ }
+ }
+
+ size_t MaxPrefixLenForType(TIpv6Address::TIpType type) {
+ switch (type) {
+ case TIpv6Address::Ipv4:
+ return IPV4_BITS;
+ case TIpv6Address::Ipv6:
+ return IPV6_BITS;
+ case TIpv6Address::LAST:
+ ythrow yexception() << "invalid type";
+ }
+ }
+
+ template <ui8 ADDR_LEN>
+ ui128 LowerBoundForPrefix(ui128 value, ui8 prefixLen) {
+ const int shift = ADDR_LEN - prefixLen;
+ const ui128 shifted = (shift < 128) ? (ui128{1} << shift) : 0;
+ ui128 mask = ~(shifted - 1);
+ return value & mask;
+ }
+
+ template <ui8 ADDR_LEN>
+ ui128 UpperBoundForPrefix(ui128 value, ui8 prefixLen) {
+ const int shift = ADDR_LEN - prefixLen;
+ const ui128 shifted = (shift < 128) ? (ui128{1} << shift) : 0;
+ ui128 mask = shifted - 1;
+ return value | mask;
+ }
+
+ auto LowerBoundForPrefix4 = LowerBoundForPrefix<IPV4_BITS>;
+ auto LowerBoundForPrefix6 = LowerBoundForPrefix<IPV6_BITS>;
+ auto UpperBoundForPrefix4 = UpperBoundForPrefix<IPV4_BITS>;
+ auto UpperBoundForPrefix6 = UpperBoundForPrefix<IPV6_BITS>;
+
+ TIpv6Address IpFromStringSafe(const TString& s) {
+ bool ok{};
+ auto addr = TIpv6Address::FromString(s, ok);
+ Y_ENSURE(ok, "Failed to parse an IP address from " << s);
+ return addr;
+ }
+
+ /// it's different from TIpv6Address::IsValid for 0.0.0.0
+ bool IsValid(TIpv6Address addr) {
+ switch (addr.Type()) {
+ case TIpv6Address::Ipv4:
+ case TIpv6Address::Ipv6:
+ return true;
+
+ case TIpv6Address::LAST:
+ return false;
+ }
+ }
+
+ bool HasNext(TIpv6Address addr) {
+ switch (addr.Type()) {
+ case TIpv6Address::Ipv4:
+ return ui128(addr) != MAX_IPV4_ADDR;
+ case TIpv6Address::Ipv6:
+ return ui128(addr) != MAX_IPV6_ADDR;
+ case TIpv6Address::LAST:
+ return false;
+ }
+ }
+
+ TIpv6Address Next(TIpv6Address addr) {
+ return {ui128(addr) + 1, addr.Type()};
+ }
+} // namespace
+
+TIpv6Address LowerBoundForPrefix(TIpv6Address value, ui8 prefixLen) {
+ auto type = value.Type();
+ switch (type) {
+ case TIpv6Address::Ipv4:
+ return {LowerBoundForPrefix4(value, prefixLen), type};
+ case TIpv6Address::Ipv6:
+ return {LowerBoundForPrefix6(value, prefixLen), type};
+ default:
+ ythrow yexception() << "invalid type";
+ }
+}
+
+TIpv6Address UpperBoundForPrefix(TIpv6Address value, ui8 prefixLen) {
+ auto type = value.Type();
+ switch (type) {
+ case TIpv6Address::Ipv4:
+ return {UpperBoundForPrefix4(value, prefixLen), type};
+ case TIpv6Address::Ipv6:
+ return {UpperBoundForPrefix6(value, prefixLen), type};
+ default:
+ ythrow yexception() << "invalid type";
+ }
+}
+
+TIpAddressRange::TIpAddressRangeBuilder::operator TIpAddressRange() {
+ return Build();
+}
+
+TIpAddressRange TIpAddressRange::TIpAddressRangeBuilder::Build() {
+ return TIpAddressRange{Start_, End_};
+}
+
+TIpAddressRange::TIpAddressRangeBuilder::TIpAddressRangeBuilder(const TString& from)
+ : TIpAddressRangeBuilder{IpFromStringSafe(from)}
+{
+}
+
+TIpAddressRange::TIpAddressRangeBuilder::TIpAddressRangeBuilder(TIpv6Address from) {
+ Y_ENSURE_EX(IsValid(from), TInvalidIpRangeException() << "Address " << from.ToString() << " is invalid");
+ Start_ = from;
+ End_ = Start_;
+}
+
+TIpAddressRange::TIpAddressRangeBuilder& TIpAddressRange::TIpAddressRangeBuilder::To(const TString& to) {
+ End_ = IpFromStringSafe(to);
+ return *this;
+}
+
+TIpAddressRange::TIpAddressRangeBuilder& TIpAddressRange::TIpAddressRangeBuilder::To(TIpv6Address to) {
+ Y_ENSURE_EX(IsValid(to), TInvalidIpRangeException() << "Address " << to.ToString() << " is invalid");
+ Start_ = to;
+ return *this;
+}
+
+TIpAddressRange::TIpAddressRangeBuilder& TIpAddressRange::TIpAddressRangeBuilder::WithPrefix(ui8 len) {
+ Y_ENSURE_EX(IsValid(Start_), TInvalidIpRangeException() << "Start value must be set before prefix");
+ const auto type = Start_.Type();
+ const auto maxLen = MaxPrefixLenForType(type);
+ Y_ENSURE_EX(len <= maxLen, TInvalidIpRangeException() << "Maximum prefix length for this address type is "
+ << maxLen << ", but requested " << (ui32)len);
+
+ const auto lowerBound = LowerBoundForPrefix(Start_, len);
+ Y_ENSURE_EX(Start_ == lowerBound, TInvalidIpRangeException() << "Cannot create IP range from start address "
+ << Start_ << " with prefix length " << (ui32)len);
+
+ End_ = UpperBoundForPrefix(Start_, len);
+
+ return *this;
+}
+
+void TIpAddressRange::Init(TIpv6Address from, TIpv6Address to) {
+ Start_ = from;
+ End_ = to;
+
+ Y_ENSURE_EX(Start_ <= End_, TInvalidIpRangeException() << "Invalid IP address range: from " << Start_ << " to " << End_);
+ Y_ENSURE_EX(Start_.Type() == End_.Type(), TInvalidIpRangeException()
+ << "Address type mismtach: start address type is " << TypeToString(Start_.Type())
+ << " end type is " << TypeToString(End_.Type()));
+}
+
+TIpAddressRange::TIpAddressRange(TIpv6Address start, TIpv6Address end) {
+ Y_ENSURE_EX(IsValid(start), TInvalidIpRangeException() << "start address " << start.ToString() << " is invalid");
+ Y_ENSURE_EX(IsValid(end), TInvalidIpRangeException() << "end address " << end.ToString() << " is invalid");
+ Init(start, end);
+}
+
+TIpAddressRange::TIpAddressRange(const TString& start, const TString& end) {
+ auto startAddr = IpFromStringSafe(start);
+ auto endAddr = IpFromStringSafe(end);
+ Init(startAddr, endAddr);
+}
+
+TIpAddressRange::~TIpAddressRange() {
+}
+
+TIpAddressRange::TIpType TIpAddressRange::Type() const {
+ return Start_.Type();
+}
+
+ui128 TIpAddressRange::Size() const {
+ return ui128(End_) - ui128(Start_) + 1;
+}
+
+bool TIpAddressRange::IsSingle() const {
+ return Start_ == End_;
+}
+
+bool TIpAddressRange::Contains(const TIpAddressRange& other) const {
+ return Start_ <= other.Start_ && End_ >= other.End_;
+}
+
+bool TIpAddressRange::Contains(const TIpv6Address& addr) const {
+ return Start_ <= addr && End_ >= addr;
+}
+
+bool TIpAddressRange::Overlaps(const TIpAddressRange& other) const {
+ return Start_ <= other.End_ && other.Start_ <= End_;
+}
+
+bool TIpAddressRange::IsConsecutive(const TIpAddressRange& other) const {
+ return (HasNext(End_) && Next(End_) == other.Start_)
+ || (HasNext(other.End_) && Next(other.End_) == Start_);
+}
+
+TIpAddressRange TIpAddressRange::Union(const TIpAddressRange& other) const {
+ Y_ENSURE(IsConsecutive(other) || Overlaps(other), "Can merge only consecutive or overlapping ranges");
+ Y_ENSURE(other.Start_.Type() == Start_.Type(), "Cannot merge ranges of addresses of different types");
+
+ auto s = Start_;
+ auto e = End_;
+
+ s = {Min<ui128>(Start_, other.Start_), Start_.Type()};
+ e = {Max<ui128>(End_, other.End_), End_.Type()};
+
+ return {s, e};
+}
+
+TIpAddressRange TIpAddressRange::FromCidrString(const TString& str) {
+ if (auto result = TryFromCidrString(str)) {
+ return *result;
+ }
+
+ ythrow TInvalidIpRangeException() << "Cannot parse " << str << " as a CIDR string";
+}
+
+TMaybe<TIpAddressRange> TIpAddressRange::TryFromCidrString(const TString& str) {
+ auto idx = str.rfind('/');
+ if (idx == TString::npos) {
+ return Nothing();
+ }
+
+ TStringBuf sb{str};
+ TStringBuf address, prefix;
+ sb.SplitAt(idx, address, prefix);
+ prefix.Skip(1);
+
+ ui8 prefixLen{};
+ if (!::TryFromString(prefix, prefixLen)) {
+ return Nothing();
+ }
+
+ return TIpAddressRange::From(TString{address})
+ .WithPrefix(prefixLen);
+}
+
+TIpAddressRange TIpAddressRange::FromRangeString(const TString& str) {
+ if (auto result = TryFromRangeString(str)) {
+ return *result;
+ }
+
+ ythrow TInvalidIpRangeException() << "Cannot parse " << str << " as a range string";
+}
+
+TMaybe<TIpAddressRange> TIpAddressRange::TryFromRangeString(const TString& str) {
+ auto idx = str.find('-');
+ if (idx == TString::npos) {
+ return Nothing();
+ }
+
+ TStringBuf sb{str};
+ TStringBuf start, end;
+ sb.SplitAt(idx, start, end);
+ end.Skip(1);
+
+ return TIpAddressRange::From(TString{start}).To(TString{end});
+}
+
+TIpAddressRange TIpAddressRange::FromString(const TString& str) {
+ if (auto result = TryFromString(str)) {
+ return *result;
+ }
+
+ ythrow TInvalidIpRangeException() << "Cannot parse an IP address from " << str;
+}
+
+TMaybe<TIpAddressRange> TIpAddressRange::TryFromString(const TString& str) {
+ if (auto idx = str.find('/'); idx != TString::npos) {
+ return TryFromCidrString(str);
+ } else if (idx = str.find('-'); idx != TString::npos) {
+ return TryFromRangeString(str);
+ } else {
+ bool ok{};
+ auto addr = TIpv6Address::FromString(str, ok);
+ if (!ok) {
+ return Nothing();
+ }
+
+ return TIpAddressRange::From(addr);
+ }
+}
+
+TString TIpAddressRange::ToRangeString() const {
+ bool ok{};
+ return TStringBuilder() << Start_.ToString(ok) << "-" << End_.ToString(ok);
+}
+
+TIpAddressRange::TIterator TIpAddressRange::begin() const {
+ return Begin();
+}
+
+TIpAddressRange::TIterator TIpAddressRange::Begin() const {
+ return TIpAddressRange::TIterator{Start_};
+}
+
+TIpAddressRange::TIterator TIpAddressRange::end() const {
+ return End();
+}
+
+TIpAddressRange::TIterator TIpAddressRange::End() const {
+ return TIpAddressRange::TIterator{{ui128(End_) + 1, End_.Type()}};
+}
+
+TIpAddressRange::TIpAddressRangeBuilder TIpAddressRange::From(TIpv6Address from) {
+ return TIpAddressRangeBuilder{from};
+};
+
+TIpAddressRange::TIpAddressRangeBuilder TIpAddressRange::From(const TString& from) {
+ return TIpAddressRangeBuilder{from};
+};
+
+bool operator==(const TIpAddressRange& lhs, const TIpAddressRange& rhs) {
+ return lhs.Start_ == rhs.Start_ && lhs.End_ == rhs.End_;
+}
+
+bool operator!=(const TIpAddressRange& lhs, const TIpAddressRange& rhs) {
+ return !(lhs == rhs);
+}
+
+TIpAddressRange::TIterator::TIterator(TIpv6Address val) noexcept
+ : Current_{val}
+{
+}
+
+bool TIpAddressRange::TIterator::operator==(const TIpAddressRange::TIterator& other) noexcept {
+ return Current_ == other.Current_;
+}
+
+bool TIpAddressRange::TIterator::operator!=(const TIpAddressRange::TIterator& other) noexcept {
+ return !(*this == other);
+}
+
+TIpAddressRange::TIterator& TIpAddressRange::TIterator::operator++() noexcept {
+ ui128 numeric = Current_;
+ Current_ = {numeric + 1, Current_.Type()};
+ return *this;
+}
+
+const TIpv6Address& TIpAddressRange::TIterator::operator*() noexcept {
+ return Current_;
+}
diff --git a/library/cpp/ipmath/ipmath.h b/library/cpp/ipmath/ipmath.h
new file mode 100644
index 0000000000..b6df5416f8
--- /dev/null
+++ b/library/cpp/ipmath/ipmath.h
@@ -0,0 +1,160 @@
+#pragma once
+
+#include <library/cpp/ipv6_address/ipv6_address.h>
+
+#include <util/generic/maybe.h>
+#include <util/ysaveload.h>
+
+struct TInvalidIpRangeException: public virtual yexception {
+};
+
+class TIpAddressRange {
+ friend bool operator==(const TIpAddressRange& lhs, const TIpAddressRange& rhs);
+ friend bool operator!=(const TIpAddressRange& lhs, const TIpAddressRange& rhs);
+
+ class TIpAddressRangeBuilder;
+public:
+ class TIterator;
+ using TIpType = TIpv6Address::TIpType;
+
+ TIpAddressRange() = default;
+ TIpAddressRange(TIpv6Address start, TIpv6Address end);
+ TIpAddressRange(const TString& start, const TString& end);
+ ~TIpAddressRange();
+
+ static TIpAddressRangeBuilder From(TIpv6Address from);
+ static TIpAddressRangeBuilder From(const TString& from);
+
+ /**
+ * Parses a string tormatted in Classless Iter-Domain Routing (CIDR) notation.
+ * @param str a CIDR-formatted string, e.g. "192.168.0.0/16"
+ * @return a new TIpAddressRange
+ * @throws TInvalidIpRangeException if the string cannot be parsed.
+ */
+ static TIpAddressRange FromCidrString(const TString& str);
+ static TMaybe<TIpAddressRange> TryFromCidrString(const TString& str);
+
+ /**
+ * Parses a string formatted as two dash-separated addresses.
+ * @param str a CIDR-formatted string, e.g. "192.168.0.0-192.168.0.2"
+ * @return a new TIpAddressRange
+ * @throws TInvalidIpRangeException if the string cannot be parsed.
+ */
+ static TIpAddressRange FromRangeString(const TString& str);
+ static TMaybe<TIpAddressRange> TryFromRangeString(const TString& str);
+
+ TString ToRangeString() const;
+
+ /**
+ * Tries to guess the format and parse it. Format must be one of: CIDR ("10.0.0.0/24"), range ("10.0.0.0-10.0.0.10") or a single address.
+ * @return a new TIpAddressRange
+ * @throws TInvlidIpRangeException if the string doesn't match any known format or if parsing failed.
+ */
+ static TIpAddressRange FromString(const TString& str);
+ static TMaybe<TIpAddressRange> TryFromString(const TString& str);
+
+ TIpType Type() const;
+
+ // XXX: uint128 cannot hold size of the complete range of IPv6 addresses. Use IsComplete to determine whether this is the case.
+ ui128 Size() const;
+
+ /**
+ * Determines whether this range contains only one address.
+ * @return true if contains only one address, otherwise false.
+ */
+ bool IsSingle() const;
+ bool IsComplete() const;
+
+ bool Contains(const TIpAddressRange& other) const;
+ bool Contains(const TIpv6Address& addr) const;
+
+ bool Overlaps(const TIpAddressRange& other) const;
+
+ /**
+ * Determines whether two ranges follow one after another without any gaps.
+ * @return true if either this range follows the given one or vice versa, otherwise false.
+ */
+ bool IsConsecutive(const TIpAddressRange& other) const;
+
+ /**
+ * Concatenates another range into this one.
+ * Note, that ranges must be either consecutive or overlapping.
+ * @throws yexception if ranges are neither consecutive nor overlapping.
+ */
+ TIpAddressRange Union(const TIpAddressRange& other) const;
+
+ template <typename TFunction>
+ void ForEach(TFunction func);
+
+ // for-each compliance interface
+ TIterator begin() const;
+ TIterator end() const;
+
+ // Arcadia style-guide friendly
+ TIterator Begin() const;
+ TIterator End() const;
+
+ Y_SAVELOAD_DEFINE(Start_, End_);
+
+private:
+ void Init(TIpv6Address, TIpv6Address);
+
+ TIpv6Address Start_;
+ TIpv6Address End_;
+};
+
+bool operator==(const TIpAddressRange& lhs, const TIpAddressRange& rhs);
+bool operator!=(const TIpAddressRange& lhs, const TIpAddressRange& rhs);
+
+TIpv6Address LowerBoundForPrefix(TIpv6Address value, ui8 prefixLen);
+TIpv6Address UpperBoundForPrefix(TIpv6Address value, ui8 prefixLen);
+
+
+class TIpAddressRange::TIpAddressRangeBuilder {
+ friend class TIpAddressRange;
+ TIpAddressRangeBuilder() = default;
+ TIpAddressRangeBuilder(TIpv6Address from);
+ TIpAddressRangeBuilder(const TString& from);
+ TIpAddressRangeBuilder(const TIpAddressRangeBuilder&) = default;
+ TIpAddressRangeBuilder& operator=(const TIpAddressRangeBuilder&) = default;
+
+ TIpAddressRangeBuilder(TIpAddressRangeBuilder&&) = default;
+ TIpAddressRangeBuilder& operator=(TIpAddressRangeBuilder&&) = default;
+
+public:
+ operator TIpAddressRange();
+ TIpAddressRange Build();
+
+ TIpAddressRangeBuilder& To(const TString&);
+ TIpAddressRangeBuilder& To(TIpv6Address);
+
+ TIpAddressRangeBuilder& WithPrefix(ui8 len);
+
+private:
+ TIpv6Address Start_;
+ TIpv6Address End_;
+};
+
+
+class TIpAddressRange::TIterator {
+public:
+ TIterator(TIpv6Address val) noexcept;
+
+ bool operator==(const TIpAddressRange::TIterator& other) noexcept;
+ bool operator!=(const TIpAddressRange::TIterator& other) noexcept;
+
+ TIterator& operator++() noexcept;
+ const TIpv6Address& operator*() noexcept;
+
+private:
+ TIpv6Address Current_;
+};
+
+
+template <typename TFunction>
+void TIpAddressRange::ForEach(TFunction func) {
+ static_assert(std::is_invocable<TFunction, TIpv6Address>::value, "function must take single address argument");
+ for (auto addr : *this) {
+ func(addr);
+ }
+}
diff --git a/library/cpp/ipmath/ipmath_ut.cpp b/library/cpp/ipmath/ipmath_ut.cpp
new file mode 100644
index 0000000000..5fe459ecc8
--- /dev/null
+++ b/library/cpp/ipmath/ipmath_ut.cpp
@@ -0,0 +1,507 @@
+#include "ipmath.h"
+#include "range_set.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/testing/gmock_in_unittest/gmock.h>
+
+#include <library/cpp/ipv6_address/ipv6_address.h>
+
+using namespace testing;
+
+static constexpr auto MIN_IPV6_ADDR = "::";
+static constexpr auto MAX_IPV6_ADDR = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
+
+std::ostream& operator<<(std::ostream& os, const TIpAddressRange& r) {
+ auto s = r.ToRangeString();
+ os.write(s.data(), s.size());
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os, const TIpRangeSet& rangeSet) {
+ os << "{\n";
+
+ for (auto&& r : rangeSet) {
+ os << r << '\n';
+ }
+
+ os << "}\n";
+ return os;
+}
+
+class TIpRangeTests: public TTestBase {
+public:
+ UNIT_TEST_SUITE(TIpRangeTests);
+ UNIT_TEST(IpRangeFromIpv4);
+ UNIT_TEST(IpRangeFromIpv6);
+ UNIT_TEST(FullIpRange);
+ UNIT_TEST(IpRangeFromCidr);
+ UNIT_TEST(IpRangeFromIpv4Builder);
+ UNIT_TEST(IpRangeFromInvalidIpv4);
+ UNIT_TEST(IpRangeFromInvalidIpv6);
+ UNIT_TEST(RangeFromSingleAddress);
+ UNIT_TEST(RangeFromRangeString);
+ UNIT_TEST(ManualIteration);
+ UNIT_TEST(RangeRelations);
+ UNIT_TEST(RangeUnion);
+ UNIT_TEST_SUITE_END();
+
+ void RangeFromSingleAddress() {
+ for (auto addrStr : {"192.168.0.1", "::2"}) {
+ auto range = TIpAddressRange::From(addrStr).Build();
+ ASSERT_THAT(range.Size(), Eq(1));
+ ASSERT_TRUE(range.IsSingle());
+
+ auto range2 = TIpAddressRange{addrStr, addrStr};
+ ASSERT_THAT(range2, Eq(range));
+
+ TVector<ui128> result;
+ range.ForEach([&result] (TIpv6Address addr) {
+ result.push_back(addr);
+ });
+
+ bool ok{};
+ ASSERT_THAT(result, ElementsAre(TIpv6Address::FromString(addrStr, ok)));
+ }
+
+ }
+
+ void IpRangeFromIpv4() {
+ bool ok{};
+
+ auto s = TIpv6Address::FromString("192.168.0.0", ok);
+ ASSERT_TRUE(ok);
+ auto e = TIpv6Address::FromString("192.168.0.255", ok);
+ ASSERT_TRUE(ok);
+
+ TIpAddressRange range{s, e};
+
+ ASSERT_THAT(range.Size(), Eq(256));
+ ASSERT_THAT(range.Type(), Eq(TIpAddressRange::TIpType::Ipv4));
+
+ TIpAddressRange range2{"192.168.0.0", "192.168.0.255"};
+ ASSERT_THAT(range2.Size(), Eq(256));
+ ASSERT_THAT(range2, Eq(range));
+ }
+
+ void IpRangeFromIpv6() {
+ bool ok{};
+
+ auto s = TIpv6Address::FromString("ffce:abcd::", ok);
+ ASSERT_TRUE(ok);
+ auto e = TIpv6Address::FromString("ffce:abcd::00ff", ok);
+ ASSERT_TRUE(ok);
+
+ TIpAddressRange range{s, e};
+
+ ASSERT_THAT(range.Size(), Eq(256));
+
+ TIpAddressRange range2{"ffce:abcd::", "ffce:abcd::00ff"};
+ ASSERT_THAT(range2.Size(), Eq(256));
+ ASSERT_THAT(range.Type(), Eq(TIpAddressRange::TIpType::Ipv6));
+ ASSERT_THAT(range2, Eq(range));
+ }
+
+
+ void FullIpRange() {
+ auto check = [] (auto start, auto end, ui128 expectedSize) {
+ auto range = TIpAddressRange::From(start).To(end).Build();
+ ASSERT_THAT(range.Size(), Eq(expectedSize));
+ };
+
+ check("0.0.0.0", "255.255.255.255", ui128(Max<ui32>()) + 1);
+ // XXX
+ // check(MIN_IPV6_ADDR, MAX_IPV6_ADDR, ui128(Max<ui128>() + 1));
+ }
+
+ void IpRangeFromCidr() {
+ auto range = TIpAddressRange::FromCidrString("10.0.0.0/30");
+
+ ASSERT_THAT(range.Size(), Eq(4));
+ TVector<TIpv6Address> result;
+ Copy(range.begin(), range.end(), std::back_inserter(result));
+
+ bool ok;
+ TVector<TIpv6Address> expected {
+ TIpv6Address::FromString("10.0.0.0", ok),
+ TIpv6Address::FromString("10.0.0.1", ok),
+ TIpv6Address::FromString("10.0.0.2", ok),
+ TIpv6Address::FromString("10.0.0.3", ok),
+ };
+
+ ASSERT_THAT(result, ElementsAreArray(expected));
+
+ // single host
+ ASSERT_THAT(TIpAddressRange::FromCidrString("ffce:abcd::/128"), Eq(TIpAddressRange::From("ffce:abcd::").Build()));
+ ASSERT_THAT(TIpAddressRange::FromCidrString("192.168.0.1/32"), Eq(TIpAddressRange::From("192.168.0.1").Build()));
+
+ // full range
+ ASSERT_THAT(TIpAddressRange::FromCidrString("::/0"), Eq(TIpAddressRange::From(MIN_IPV6_ADDR).To(MAX_IPV6_ADDR).Build()));
+ ASSERT_THAT(TIpAddressRange::FromCidrString("0.0.0.0/0"), Eq(TIpAddressRange::From("0.0.0.0").To("255.255.255.255").Build()));
+
+ // illformed
+ ASSERT_THROW(TIpAddressRange::FromCidrString("::/"), TInvalidIpRangeException);
+ ASSERT_THROW(TIpAddressRange::FromCidrString("::"), TInvalidIpRangeException);
+ ASSERT_THROW(TIpAddressRange::FromCidrString("/::"), TInvalidIpRangeException);
+ ASSERT_THROW(TIpAddressRange::FromCidrString("::/150"), TInvalidIpRangeException);
+ }
+
+ void RangeFromRangeString() {
+ {
+ auto range = TIpAddressRange::FromRangeString("10.0.0.0-10.0.0.3");
+
+ TVector<TIpv6Address> result;
+ Copy(range.begin(), range.end(), std::back_inserter(result));
+
+ bool ok;
+ TVector<TIpv6Address> expected {
+ TIpv6Address::FromString("10.0.0.0", ok),
+ TIpv6Address::FromString("10.0.0.1", ok),
+ TIpv6Address::FromString("10.0.0.2", ok),
+ TIpv6Address::FromString("10.0.0.3", ok),
+ };
+
+ ASSERT_THAT(result, ElementsAreArray(expected));
+ }
+ {
+ auto range = TIpAddressRange::FromRangeString("10.0.0.0-10.0.0.3");
+
+ TVector<TIpv6Address> result;
+ Copy(range.begin(), range.end(), std::back_inserter(result));
+
+ bool ok;
+ TVector<TIpv6Address> expected {
+ TIpv6Address::FromString("10.0.0.0", ok),
+ TIpv6Address::FromString("10.0.0.1", ok),
+ TIpv6Address::FromString("10.0.0.2", ok),
+ TIpv6Address::FromString("10.0.0.3", ok),
+ };
+
+ ASSERT_THAT(result, ElementsAreArray(expected));
+ }
+ }
+
+ void IpRangeFromIpv4Builder() {
+ auto range = TIpAddressRange::From("192.168.0.0")
+ .To("192.168.0.255")
+ .Build();
+
+ ASSERT_THAT(range.Size(), Eq(256));
+ }
+
+ void IpRangeFromInvalidIpv4() {
+ auto build = [] (auto from, auto to) {
+ return TIpAddressRange::From(from).To(to).Build();
+ };
+
+ ASSERT_THROW(build("192.168.0.255", "192.168.0.0"), yexception);
+ ASSERT_THROW(build("192.168.0.0", "192.168.0.300"), yexception);
+ ASSERT_THROW(build("192.168.0.300", "192.168.0.330"), yexception);
+ ASSERT_THROW(build("192.168.0.0", "::1"), yexception);
+ ASSERT_THROW(build(TIpv6Address{}, TIpv6Address{}), yexception);
+ }
+
+ void IpRangeFromInvalidIpv6() {
+ auto build = [] (auto from, auto to) {
+ return TIpAddressRange::From(from).To(to).Build();
+ };
+
+ ASSERT_THROW(build("ffce:abcd::00ff", "ffce:abcd::"), yexception);
+ ASSERT_THROW(build("ffce:abcd::", "ffce:abcd::fffff"), yexception);
+ ASSERT_THROW(build("ffce:abcd::10000", "ffce:abcd::ffff"), yexception);
+ ASSERT_THROW(build("ffce:abcd::", TIpv6Address{}), yexception);
+
+ auto ctor = [] (auto s, auto e) {
+ return TIpAddressRange{s, e};
+ };
+
+ ASSERT_THROW(ctor(TIpv6Address{}, TIpv6Address{}), yexception);
+ ASSERT_THROW(ctor("", ""), yexception);
+ }
+
+ void ManualIteration() {
+ {
+ TIpAddressRange range{"::", "::"};
+ auto it = range.Begin();
+ ++it;
+ bool ok;
+ ASSERT_THAT(*it, Eq(TIpv6Address::FromString("::1", ok)));
+
+ for (auto i = 0; i < 254; ++i, ++it) {
+ }
+
+ ASSERT_THAT(*it, Eq(TIpv6Address::FromString("::ff", ok)));
+ }
+
+ {
+ TIpAddressRange range{"0.0.0.0", "0.0.0.0"};
+ auto it = range.Begin();
+ ++it;
+ bool ok;
+ ASSERT_THAT(*it, Eq(TIpv6Address::FromString("0.0.0.1", ok)));
+
+ for (auto i = 0; i < 254; ++i, ++it) {
+ }
+
+ ASSERT_THAT(*it, Eq(TIpv6Address::FromString("0.0.0.255", ok)));
+ }
+ }
+
+ void RangeRelations() {
+ {
+ auto range = TIpAddressRange::From(MIN_IPV6_ADDR)
+ .To(MAX_IPV6_ADDR)
+ .Build();
+
+ ASSERT_TRUE(range.Overlaps(range));
+ ASSERT_TRUE(range.Contains(range));
+ // XXX
+ //ASSERT_FALSE(range.IsConsecutive(range));
+ }
+ {
+ auto range = TIpAddressRange::From("0.0.0.1").To("0.0.0.4").Build();
+ auto range0 = TIpAddressRange::From("0.0.0.0").Build();
+ auto range1 = TIpAddressRange::From("0.0.0.1").Build();
+ auto range2 = TIpAddressRange::From("0.0.0.5").Build();
+ auto range4 = TIpAddressRange::From("0.0.0.4").Build();
+
+ ASSERT_FALSE(range.Overlaps(range0));
+ ASSERT_TRUE(range.IsConsecutive(range0));
+ ASSERT_FALSE(range.Contains(range0));
+
+ ASSERT_TRUE(range.Overlaps(range1));
+ ASSERT_FALSE(range.IsConsecutive(range1));
+ ASSERT_TRUE(range.Contains(range1));
+
+ ASSERT_TRUE(range.Overlaps(range4));
+ ASSERT_FALSE(range.IsConsecutive(range4));
+ ASSERT_TRUE(range.Contains(range4));
+ }
+ {
+ auto range = TIpAddressRange::From("0.0.0.1").To("0.0.0.4").Build();
+ auto range2 = TIpAddressRange::From("0.0.0.0").To("0.0.0.2").Build();
+
+ ASSERT_TRUE(range.Overlaps(range2));
+ ASSERT_FALSE(range.IsConsecutive(range2));
+ ASSERT_FALSE(range.Contains(range2));
+
+ bool ok;
+ ASSERT_TRUE(range.Contains(TIpv6Address::FromString("0.0.0.1", ok)));
+ ASSERT_TRUE(range.Contains(TIpv6Address::FromString("0.0.0.2", ok)));
+ ASSERT_FALSE(range.Contains(TIpv6Address::FromString("0.0.0.5", ok)));
+ }
+ }
+
+ void RangeUnion() {
+ {
+ auto range = TIpAddressRange::From(MIN_IPV6_ADDR)
+ .To(MAX_IPV6_ADDR)
+ .Build();
+
+ ASSERT_THAT(range.Union(range), Eq(range));
+ ASSERT_THAT(range.Union(TIpAddressRange::From("::")), range);
+ ASSERT_THAT(range.Union(TIpAddressRange::From("::1")), range);
+
+ ASSERT_THROW(range.Union(TIpAddressRange::From("0.0.0.0")), yexception);
+ }
+
+ {
+ auto expected = TIpAddressRange::From("0.0.0.1").To("0.0.0.10").Build();
+
+ auto range = TIpAddressRange{"0.0.0.1", "0.0.0.3"}.Union({"0.0.0.4", "0.0.0.10"});
+ ASSERT_THAT(range, Eq(expected));
+
+ auto range2 = TIpAddressRange{"0.0.0.1", "0.0.0.3"}.Union({"0.0.0.2", "0.0.0.10"});
+ ASSERT_THAT(range2, Eq(expected));
+
+ auto range3 = TIpAddressRange{"0.0.0.2", "0.0.0.3"}.Union({"0.0.0.1", "0.0.0.10"});
+ ASSERT_THAT(range2, Eq(expected));
+
+ auto range4 = TIpAddressRange{"0.0.0.1", "0.0.0.10"}.Union({"0.0.0.2", "0.0.0.3"});
+ ASSERT_THAT(range2, Eq(expected));
+
+ ASSERT_THROW(range.Union(TIpAddressRange::From("10.0.0.0")), yexception);
+ }
+ }
+};
+
+class TRangeSetTests: public TTestBase {
+public:
+ UNIT_TEST_SUITE(TRangeSetTests);
+ UNIT_TEST(AddDisjoint);
+ UNIT_TEST(AddOverlapping);
+ UNIT_TEST(AddConsecutive);
+ UNIT_TEST(DisallowsMixingTypes);
+ UNIT_TEST(MembershipTest);
+ UNIT_TEST_SUITE_END();
+
+ void AddDisjoint() {
+ TIpRangeSet set;
+ TVector<TIpAddressRange> expected {
+ TIpAddressRange::From("0.0.0.0").To("0.0.0.2").Build(),
+ TIpAddressRange::From("0.0.0.4").To("255.255.255.255").Build(),
+ };
+
+ for (auto&& r : expected) {
+ set.Add(r);
+ }
+
+ ASSERT_THAT(set, ElementsAreArray(expected));
+ }
+
+ void TestAdding(const TVector<TIpAddressRange>& toInsert, const TVector<TIpAddressRange>& expected) {
+ TIpRangeSet set;
+ {
+ set.Add(toInsert);
+
+ ASSERT_THAT(set, ElementsAreArray(expected));
+ }
+
+ {
+ for (auto it = toInsert.rbegin(); it != toInsert.rend(); ++it) {
+ set.Add(*it);
+ }
+
+ ASSERT_THAT(set, ElementsAreArray(expected));
+ }
+ }
+
+ void AddOverlapping() {
+ {
+ TVector<TIpAddressRange> toInsert {
+ TIpAddressRange::From("0.0.0.0").To("0.0.0.2").Build(),
+ TIpAddressRange::From("0.0.0.2").To("0.0.0.4").Build(),
+ TIpAddressRange::From("0.0.0.4").To("255.255.255.255").Build(),
+ };
+
+ TVector<TIpAddressRange> expected {
+ TIpAddressRange::From("0.0.0.0").To("255.255.255.255").Build(),
+ };
+
+ TestAdding(toInsert, expected);
+ }
+ {
+ TVector<TIpAddressRange> toInsert {
+ TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
+ TIpAddressRange::From("0.0.0.8").To("0.0.0.10").Build(),
+ TIpAddressRange::From("0.0.0.7").To("0.0.0.12").Build(),
+ };
+
+ TVector<TIpAddressRange> expected {
+ TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
+ TIpAddressRange::From("0.0.0.7").To("0.0.0.12").Build(),
+ };
+
+ TestAdding(toInsert, expected);
+ }
+ {
+ TVector<TIpAddressRange> toInsert {
+ TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
+ TIpAddressRange::From("0.0.0.7").To("0.0.0.12").Build(),
+ TIpAddressRange::From("0.0.0.8").To("0.0.0.10").Build(),
+ };
+
+ TVector<TIpAddressRange> expected {
+ TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
+ TIpAddressRange::From("0.0.0.7").To("0.0.0.12").Build(),
+ };
+
+ TestAdding(toInsert, expected);
+ }
+ {
+ TVector<TIpAddressRange> toInsert {
+ TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
+ TIpAddressRange::From("0.0.0.3").To("0.0.0.10").Build(),
+ };
+
+ TVector<TIpAddressRange> expected {
+ TIpAddressRange::From("0.0.0.0").To("0.0.0.10").Build(),
+ };
+
+ TestAdding(toInsert, expected);
+ }
+ }
+
+ void DisallowsMixingTypes() {
+ TVector<TIpAddressRange> toInsert {
+ TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
+ TIpAddressRange::From("::1").Build(),
+ };
+
+ TIpRangeSet rangeSet;
+
+ ASSERT_THROW([&] { rangeSet.Add(toInsert); }(), yexception);
+ ASSERT_THROW([&] { rangeSet.Add(toInsert[1]); rangeSet.Add(toInsert[0]); }(), yexception);
+ }
+
+ void AddConsecutive() {
+ {
+ TVector<TIpAddressRange> toInsert {
+ TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
+ TIpAddressRange::From("0.0.0.6").To("0.0.0.7").Build(),
+ TIpAddressRange::From("0.0.0.8").To("0.0.0.10").Build(),
+ };
+
+ TVector<TIpAddressRange> expected {
+ TIpAddressRange::From("0.0.0.0").To("0.0.0.10").Build(),
+ };
+
+ TestAdding(toInsert, expected);
+ }
+ {
+ TVector<TIpAddressRange> toInsert {
+ TIpAddressRange::From("0.0.0.0").To("255.255.255.255").Build(),
+ TIpAddressRange::From("0.0.0.0").To("255.255.255.255").Build(),
+ };
+
+ TVector<TIpAddressRange> expected {
+ TIpAddressRange::From("0.0.0.0").To("255.255.255.255").Build(),
+ };
+
+ TestAdding(toInsert, expected);
+ }
+ }
+
+ void MembershipTest() {
+ TVector<TIpAddressRange> toInsert {
+ TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
+ TIpAddressRange::From("0.0.0.7").To("0.0.0.12").Build(),
+ TIpAddressRange::From("0.0.0.8").To("0.0.0.10").Build(),
+ };
+
+ TIpRangeSet rangeSet;
+ rangeSet.Add(toInsert);
+
+ TVector<TIpAddressRange> in {
+ TIpAddressRange::From("0.0.0.0").To("0.0.0.5").Build(),
+ TIpAddressRange::From("0.0.0.7").To("0.0.0.12").Build(),
+ };
+
+ TVector<TIpAddressRange> notIn {
+ TIpAddressRange::From("0.0.0.6").Build(),
+ TIpAddressRange::From("0.0.0.13").To("0.0.0.255").Build(),
+ // enumerating full range is slow and makes little sense
+ TIpAddressRange::From("255.255.255.0").To("255.255.255.255").Build(),
+ };
+
+ for (auto&& range : in) {
+ for (auto&& addr : range) {
+ ASSERT_TRUE(rangeSet.Contains(addr));
+ ASSERT_THAT(*rangeSet.Find(addr), Eq(range));
+ }
+ }
+
+ for (auto&& range : notIn) {
+ for (auto&& addr : range) {
+ ASSERT_FALSE(rangeSet.Contains(addr));
+ ASSERT_THAT(rangeSet.Find(addr), rangeSet.End());
+ }
+ }
+
+ bool ok{};
+ ASSERT_THAT(rangeSet.Find(TIpv6Address::FromString("::1", ok)), Eq(rangeSet.End()));
+ ASSERT_FALSE(rangeSet.Contains(TIpv6Address::FromString("::1", ok)));
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TIpRangeTests);
+UNIT_TEST_SUITE_REGISTRATION(TRangeSetTests);
diff --git a/library/cpp/ipmath/range_set.cpp b/library/cpp/ipmath/range_set.cpp
new file mode 100644
index 0000000000..55f42e451d
--- /dev/null
+++ b/library/cpp/ipmath/range_set.cpp
@@ -0,0 +1,99 @@
+#include "range_set.h"
+
+#include <util/generic/algorithm.h>
+
+namespace {
+ bool ShouldJoin(const TIpAddressRange& lhs, const TIpAddressRange& rhs) {
+ return lhs.Overlaps(rhs) || lhs.IsConsecutive(rhs);
+ }
+}
+
+bool TIpRangeSet::TRangeLess::operator()(const TIpAddressRange& lhs, const TIpAddressRange& rhs) const {
+ return *lhs.Begin() < *rhs.Begin();
+}
+
+TIpRangeSet::TIpRangeSet() = default;
+TIpRangeSet::~TIpRangeSet() = default;
+
+void TIpRangeSet::Add(TIpAddressRange r) {
+ Y_ENSURE(IsEmpty() || r.Type() == Type(), "Mixing IPv4 and IPv6 ranges is disallowed");
+
+ auto lowerIt = Ranges_.lower_bound(r);
+
+ // still may overlap the last interval in our tree
+ if (IsEmpty()) {
+ Ranges_.insert(r);
+ return;
+ } else if (lowerIt == Ranges_.end()) {
+ if (auto it = Ranges_.rbegin(); ShouldJoin(*it, r)) {
+ auto unitedRange = it->Union(r);
+ Ranges_.erase(--it.base());
+ Ranges_.insert(unitedRange);
+ } else {
+ Ranges_.insert(r);
+ }
+
+ return;
+ }
+
+
+ TIpAddressRange unitedRange{r};
+
+ auto joined = lowerIt;
+ if (lowerIt != Ranges_.begin()) {
+ if (ShouldJoin(unitedRange, *(--joined))) {
+ unitedRange = unitedRange.Union(*joined);
+ } else {
+ ++joined;
+ }
+ }
+
+ auto it = lowerIt;
+ for (; it != Ranges_.end() && ShouldJoin(*it, unitedRange); ++it) {
+ unitedRange = unitedRange.Union(*it);
+ }
+
+ Ranges_.erase(joined, it);
+ Ranges_.insert(unitedRange);
+}
+
+TIpAddressRange::TIpType TIpRangeSet::Type() const {
+ return IsEmpty()
+ ? TIpAddressRange::TIpType::LAST
+ : Ranges_.begin()->Type();
+}
+
+bool TIpRangeSet::IsEmpty() const {
+ return Ranges_.empty();
+}
+
+TIpRangeSet::TIterator TIpRangeSet::Find(TIpv6Address addr) const {
+ if (IsEmpty() || addr.Type() != Type()) {
+ return End();
+ }
+
+ auto lowerIt = Ranges_.lower_bound(TIpAddressRange(addr, addr));
+
+ if (lowerIt == Ranges_.begin()) {
+ return lowerIt->Contains(addr)
+ ? lowerIt
+ : End();
+ } else if (lowerIt == Ranges_.end()) {
+ auto rbegin = Ranges_.crbegin();
+ return rbegin->Contains(addr)
+ ? (++rbegin).base()
+ : End();
+ } else if (lowerIt->Contains(addr)) {
+ return lowerIt;
+ }
+
+ --lowerIt;
+
+ return lowerIt->Contains(addr)
+ ? lowerIt
+ : End();
+}
+
+bool TIpRangeSet::Contains(TIpv6Address addr) const {
+ return Find(addr) != End();
+}
diff --git a/library/cpp/ipmath/range_set.h b/library/cpp/ipmath/range_set.h
new file mode 100644
index 0000000000..d9e2451822
--- /dev/null
+++ b/library/cpp/ipmath/range_set.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include "ipmath.h"
+
+#include <util/generic/set.h>
+#include <util/ysaveload.h>
+
+
+/// @brief Maintains a disjoint set of added ranges. Allows for efficient membership queries
+/// for an address in a set of IP ranges.
+class TIpRangeSet {
+ struct TRangeLess {
+ bool operator()(const TIpAddressRange& lhs, const TIpAddressRange& rhs) const;
+ };
+
+ using TTree = TSet<TIpAddressRange, TRangeLess>;
+
+public:
+ using iterator = TTree::iterator;
+ using const_iterator = TTree::const_iterator;
+ using value_type = TTree::value_type;
+ using TIterator = TTree::iterator;
+ using TConstIterator = TTree::const_iterator;
+
+ TIpRangeSet();
+ ~TIpRangeSet();
+
+ void Add(TIpAddressRange range);
+
+ template <typename TContainer>
+ void Add(TContainer&& addrs) {
+ using T = typename std::decay<TContainer>::type::value_type;
+ static_assert(std::is_convertible<T, TIpAddressRange>::value);
+
+ for (auto&& addr : addrs) {
+ Add(addr);
+ }
+ }
+
+ TIpAddressRange::TIpType Type() const;
+
+ bool IsEmpty() const;
+ bool Contains(TIpv6Address addr) const;
+ TConstIterator Find(TIpv6Address addr) const;
+
+ TConstIterator Begin() const {
+ return Ranges_.begin();
+ }
+
+ TConstIterator End() const {
+ return Ranges_.end();
+ }
+
+ TConstIterator begin() const {
+ return Begin();
+ }
+
+ TConstIterator end() const {
+ return End();
+ }
+
+ Y_SAVELOAD_DEFINE(Ranges_);
+
+private:
+ TTree Ranges_;
+};
diff --git a/library/cpp/ipmath/ut/ya.make b/library/cpp/ipmath/ut/ya.make
new file mode 100644
index 0000000000..b860cefd03
--- /dev/null
+++ b/library/cpp/ipmath/ut/ya.make
@@ -0,0 +1,16 @@
+UNITTEST_FOR(library/cpp/ipmath)
+
+OWNER(
+ msherbakov
+ g:solomon
+)
+
+SRCS(
+ ipmath_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/testing/gmock_in_unittest
+)
+
+END()
diff --git a/library/cpp/ipmath/ya.make b/library/cpp/ipmath/ya.make
new file mode 100644
index 0000000000..244838962e
--- /dev/null
+++ b/library/cpp/ipmath/ya.make
@@ -0,0 +1,17 @@
+LIBRARY()
+
+OWNER(
+ msherbakov
+ g:solomon
+)
+
+SRCS(
+ ipmath.cpp
+ range_set.cpp
+)
+
+PEERDIR(library/cpp/ipv6_address)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/ipv6_address/ipv6_address.cpp b/library/cpp/ipv6_address/ipv6_address.cpp
new file mode 100644
index 0000000000..be8fcbae13
--- /dev/null
+++ b/library/cpp/ipv6_address/ipv6_address.cpp
@@ -0,0 +1,437 @@
+#include "ipv6_address.h"
+#include "ipv6_address_p.h"
+
+#ifdef _unix_
+#include <netinet/in.h>
+#endif
+
+#include <util/network/address.h>
+#include <util/network/init.h>
+#include <util/string/cast.h>
+#include <util/string/split.h>
+#include <util/system/byteorder.h>
+#include <util/ysaveload.h>
+
+#include <array>
+
+namespace {
+ // reinterpret_cast from memory, where most significant bit is first
+ inline ui128 FromMemMSF(const char* memPtr) {
+ Y_VERIFY(memPtr, " ");
+ return ui128{
+ *reinterpret_cast<const ui64*>(memPtr),
+ *(reinterpret_cast<const ui64*>(memPtr) + 1)
+ };
+ }
+
+ // zero-terminated copy of address string
+ template <size_t N>
+ inline auto AddrBuf(TStringBuf str) noexcept {
+ std::array<char, N+1> res;
+ auto len = Min(str.size(), N);
+ CopyN(str.begin(), len, res.begin());
+ res[len] = '\0';
+ return res;
+ }
+}
+
+void TIpv6Address::InitFrom(const in6_addr& addr) {
+ const ui64* const ui64Ptr = reinterpret_cast<const ui64*>(&addr);
+ const ui64 raw[2] = {SwapBytes(*ui64Ptr), SwapBytes(*(ui64Ptr + 1))};
+ Ip = FromMemMSF(reinterpret_cast<const char*>(raw));
+ Type_ = Ipv6;
+}
+void TIpv6Address::InitFrom(const in_addr& addr) {
+ unsigned long swapped = SwapBytes(addr.s_addr);
+ Ip = ui128{0, swapped};
+ Type_ = Ipv4;
+}
+
+void TIpv6Address::InitFrom(const sockaddr_in6& Addr) {
+ InitFrom(Addr.sin6_addr);
+ ScopeId_ = Addr.sin6_scope_id;
+}
+void TIpv6Address::InitFrom(const sockaddr_in& Addr) {
+ InitFrom(Addr.sin_addr);
+}
+
+TIpv6Address::TIpv6Address(const NAddr::IRemoteAddr& addr) {
+ if (addr.Addr()->sa_family == AF_INET) { // IPv4
+ const sockaddr_in* Tmp = reinterpret_cast<const sockaddr_in*>(addr.Addr());
+ InitFrom(*Tmp);
+ } else { // IPv6
+ const sockaddr_in6* Tmp = reinterpret_cast<const sockaddr_in6*>(addr.Addr());
+ InitFrom(*Tmp);
+ }
+}
+TIpv6Address::TIpv6Address(const sockaddr_in6& Addr) {
+ InitFrom(Addr);
+}
+TIpv6Address::TIpv6Address(const sockaddr_in& Addr) {
+ InitFrom(Addr);
+}
+TIpv6Address::TIpv6Address(const in6_addr& addr, ui32 Scope) {
+ InitFrom(addr);
+ ScopeId_ = Scope;
+}
+TIpv6Address::TIpv6Address(const in_addr& addr) {
+ InitFrom(addr);
+}
+
+TIpv6Address TIpv6Address::FromString(TStringBuf str, bool& ok) noexcept {
+ const TIpType ipType = FigureOutType(str);
+
+ if (ipType == Ipv6) {
+ ui32 scopeId = 0;
+ if (size_t pos = str.find('%'); pos != TStringBuf::npos) {
+ ::TryFromString(str.substr(pos + 1), scopeId);
+ str.Trunc(pos);
+ }
+
+ const auto buf = AddrBuf<INET6_ADDRSTRLEN>(str);
+ in6_addr addr;
+ if (inet_pton(AF_INET6, buf.data(), &addr) != 1) {
+ ok = false;
+ return TIpv6Address();
+ }
+
+ ok = true;
+ return TIpv6Address(addr, scopeId);
+ } else { // if (ipType == Ipv4) {
+ const auto buf = AddrBuf<INET_ADDRSTRLEN>(str);
+ in_addr addr;
+ if (inet_pton(AF_INET, buf.data(), &addr) != 1) {
+ ok = false;
+ return TIpv6Address();
+ }
+
+ ok = true;
+ return TIpv6Address(addr);
+ }
+}
+
+TString TIpv6Address::ToString(bool* ok) const noexcept {
+ return ToString(true, ok);
+}
+TString TIpv6Address::ToString(bool PrintScopeId, bool* ok) const noexcept {
+ TString result;
+ bool isOk = true;
+
+ if (Type_ == TIpv6Address::Ipv4) {
+ result.resize(INET_ADDRSTRLEN + 2);
+ in_addr addr;
+ ToInAddr(addr);
+ isOk = inet_ntop(AF_INET, &addr, result.begin(), INET_ADDRSTRLEN);
+ result.resize(result.find('\0'));
+ } else if (Type_ == TIpv6Address::Ipv6) {
+ result.resize(INET6_ADDRSTRLEN + 2);
+ in6_addr addr;
+ ToIn6Addr(addr);
+ isOk = inet_ntop(AF_INET6, &addr, result.begin(), INET6_ADDRSTRLEN);
+ result.resize(result.find('\0'));
+ if (PrintScopeId)
+ result += "%" + ::ToString(ScopeId_);
+ } else {
+ result = "null";
+ isOk = true;
+ }
+
+ if (ok) {
+ *ok = isOk;
+ }
+
+ return result;
+}
+
+void TIpv6Address::ToSockaddrAndSocklen(sockaddr_in& sockAddrIPv4,
+ sockaddr_in6& sockAddrIPv6, // in
+ const sockaddr*& sockAddrPtr,
+ socklen_t& sockAddrSize,
+ ui16 Port) const { // out
+
+ if (Type_ == Ipv4) {
+ memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
+ sockAddrIPv4.sin_family = AF_INET;
+ sockAddrIPv4.sin_port = htons(Port);
+ ToInAddr(sockAddrIPv4.sin_addr);
+
+ sockAddrSize = sizeof(sockAddrIPv4);
+ sockAddrPtr = reinterpret_cast<sockaddr*>(&sockAddrIPv4);
+
+ } else if (Type_ == Ipv6) {
+ memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
+ sockAddrIPv6.sin6_family = AF_INET6;
+ sockAddrIPv6.sin6_port = htons(Port);
+ ToIn6Addr(sockAddrIPv6.sin6_addr);
+ sockAddrIPv6.sin6_scope_id = ScopeId_;
+ sockAddrIPv6.sin6_flowinfo = 0;
+
+ sockAddrSize = sizeof(sockAddrIPv6);
+ sockAddrPtr = reinterpret_cast<sockaddr*>(&sockAddrIPv6);
+ } else
+ Y_VERIFY(false);
+}
+
+void TIpv6Address::ToInAddr(in_addr& Addr4) const {
+ Y_VERIFY(Type_ == TIpv6Address::Ipv4);
+
+ Zero(Addr4);
+ ui32 Value = GetLow(Ip);
+ Y_VERIFY(Value == GetLow(Ip), " ");
+ Y_VERIFY(GetHigh(Ip) == 0, " ");
+ Addr4.s_addr = SwapBytes(Value);
+}
+void TIpv6Address::ToIn6Addr(in6_addr& Addr6) const {
+ Y_VERIFY(Type_ == TIpv6Address::Ipv6);
+
+ Zero(Addr6);
+ ui64 Raw[2] = {GetHigh(Ip), GetLow(Ip)};
+ *Raw = SwapBytes(*Raw);
+ Raw[1] = SwapBytes(1 [Raw]);
+ memcpy(&Addr6, Raw, sizeof(Raw));
+}
+
+void TIpv6Address::Save(IOutputStream* out) const {
+ ::Save(out, Ip);
+ ::Save(out, static_cast<ui8>(Type_));
+ ::Save(out, ScopeId_);
+}
+void TIpv6Address::Load(IInputStream* in) {
+ ::Load(in, Ip);
+ ui8 num;
+ ::Load(in, num);
+ Type_ = static_cast<TIpType>(num);
+ ::Load(in, ScopeId_);
+}
+
+bool TIpv6Address::Isv4MappedTov6() const noexcept {
+ /// http://en.wikipedia.org/wiki/IPv6
+ /// Hybrid dual-stack IPv6/IPv4 implementations recognize a special class of addresses,
+ /// the IPv4-mapped IPv6 addresses. In these addresses, the first 80 bits are zero, the next 16 bits are one,
+ /// and the remaining 32 bits are the IPv4 address.
+
+ if (Type_ != Ipv6)
+ return false;
+
+ if (GetHigh(Ip) != 0)
+ return false; // First 64 bit are not zero -> it is not ipv4-mapped-ipv6 address
+
+ const ui64 Low = GetLow(Ip) >> 32;
+ if (Low != 0x0000ffff)
+ return false;
+
+ return true;
+}
+
+TIpv6Address TIpv6Address::TryToExtractIpv4From6() const noexcept {
+ if (Isv4MappedTov6() == false)
+ return TIpv6Address();
+
+ const ui64 NewLow = GetLow(Ip) & 0x00000000ffffffff;
+ TIpv6Address Result(ui128(0, NewLow), Ipv4);
+ return Result;
+}
+
+TIpv6Address TIpv6Address::Normalized() const noexcept {
+ if (Isv4MappedTov6() == false)
+ return *this;
+
+ TIpv6Address Result = TryToExtractIpv4From6();
+ Y_VERIFY(Result.IsNull() == false);
+ return Result;
+}
+
+IOutputStream& operator<<(IOutputStream& Out, const TIpv6Address::TIpType Type) noexcept {
+ switch (Type) {
+ case TIpv6Address::Ipv4:
+ Out << "Ipv4";
+ return Out;
+ case TIpv6Address::Ipv6:
+ Out << "Ipv6";
+ return Out;
+ default:
+ Out << "UnknownType";
+ return Out;
+ }
+}
+
+IOutputStream& operator<<(IOutputStream& out, const TIpv6Address& ipv6Address) noexcept {
+ bool ok;
+ const TString& strIp = ipv6Address.ToString(&ok);
+ if (!ok) {
+ return out << "Can not convert ip to string";
+ } else {
+ return out << strIp;
+ }
+}
+
+TString THostAddressAndPort::ToString() const noexcept {
+ TStringStream Str;
+ Str << *this;
+ return Str.Str();
+}
+
+IOutputStream& operator<<(IOutputStream& Out, const THostAddressAndPort& HostAddressAndPort) noexcept {
+ Out << HostAddressAndPort.Ip << ":" << HostAddressAndPort.Port;
+ return Out;
+}
+
+namespace {
+ class TRemoteAddr: public NAddr::IRemoteAddr {
+ public:
+ TRemoteAddr(const TIpv6Address& Address, TIpPort Port);
+ const sockaddr* Addr() const override;
+ socklen_t Len() const override;
+
+ private:
+ sockaddr_in SockAddrIPv4;
+ sockaddr_in6 SockAddrIPv6;
+ const sockaddr* SockAddrPtr = nullptr;
+ socklen_t SockAddrSize = 0;
+ };
+
+ TRemoteAddr::TRemoteAddr(const TIpv6Address& Address, TIpPort Port) {
+ Address.ToSockaddrAndSocklen(SockAddrIPv4, SockAddrIPv6, SockAddrPtr, SockAddrSize, Port);
+ }
+ const sockaddr* TRemoteAddr::Addr() const {
+ return SockAddrPtr;
+ }
+ socklen_t TRemoteAddr::Len() const {
+ return SockAddrSize;
+ }
+}
+
+NAddr::IRemoteAddr* ToIRemoteAddr(const TIpv6Address& Address, TIpPort Port) {
+ return new TRemoteAddr(Address, Port);
+}
+
+std::tuple<THostAddressAndPort, TString, TIpPort> ParseHostAndMayBePortFromString(const TString& RawStr,
+ TIpPort DefaultPort,
+ bool& Ok) noexcept {
+ // Cout << "ParseHostAndMayBePortFromString: " << RawStr << ", Port: " << DefaultPort << Endl;
+
+ using TRes = std::tuple<THostAddressAndPort, TString, TIpPort>;
+
+ // ---------------------------------------------------------------------
+
+ const size_t BracketColPos = RawStr.find("]:");
+ if (BracketColPos != TString::npos) {
+ // [ipv6]:port
+ if (!RawStr.StartsWith('[')) {
+ Ok = false;
+ return {};
+ }
+ const TStringBuf StrIpv6(RawStr.begin() + 1, RawStr.begin() + BracketColPos);
+ const TStringBuf StrPort(RawStr.begin() + BracketColPos + 2, RawStr.end());
+
+ bool IpConverted;
+ const TIpv6Address Ip = TIpv6Address::FromString(StrIpv6, IpConverted);
+ if (!IpConverted) {
+ Ok = false;
+ return {};
+ }
+ if (Ip.Type() != TIpv6Address::Ipv6) {
+ Ok = false;
+ return {};
+ }
+ TIpPort Port {};
+ if (!::TryFromString(StrPort, Port)) {
+ Ok = false;
+ return {};
+ }
+
+ Ok = true;
+ TRes Res{{Ip, Port}, {}, {}};
+ return Res;
+ }
+
+ // ---------------------------------------------------------------------
+
+ if (RawStr.StartsWith('[')) {
+ // [ipv6]
+ if (!RawStr.EndsWith(']')) {
+ Ok = false;
+ return {};
+ }
+ const TStringBuf StrIpv6(RawStr.begin() + 1, RawStr.end() - 1);
+
+ bool IpConverted;
+ const TIpv6Address Ip = TIpv6Address::FromString(StrIpv6, IpConverted);
+ if (!IpConverted || Ip.Type() != TIpv6Address::Ipv6) {
+ Ok = false;
+ return {};
+ }
+
+ Ok = true;
+ TRes Res{{Ip, DefaultPort}, {}, {}};
+ return Res;
+ }
+
+ // ---------------------------------------------------------------------
+
+ const size_t ColPos = RawStr.find(':');
+ if (ColPos != TString::npos) {
+ // host:port
+ // ipv4:port
+ // ipv6
+
+ {
+ bool IpConverted;
+ const TIpv6Address Ipv6 = TIpv6Address::FromString(RawStr, IpConverted);
+ if (IpConverted && Ipv6.Type() == TIpv6Address::Ipv6) {
+ // ipv6
+ Ok = true;
+ TRes Res{{Ipv6, DefaultPort}, {}, {}};
+ return Res;
+ }
+ }
+
+ const TStringBuf StrPort(RawStr.begin() + ColPos + 1, RawStr.end());
+ TIpPort Port {};
+ if (!::TryFromString(StrPort, Port)) {
+ Ok = false;
+ return {};
+ }
+
+ const TStringBuf StrIpv4OrHost(RawStr.begin(), RawStr.begin() + ColPos);
+ {
+ bool IpConverted;
+ const TIpv6Address Ipv4 = TIpv6Address::FromString(StrIpv4OrHost, IpConverted);
+ if (IpConverted && Ipv4.Type() == TIpv6Address::Ipv4) {
+ // ipv4:port
+ Ok = true;
+ TRes Res{{Ipv4, Port}, {}, {}};
+ return Res;
+ }
+ }
+
+ {
+ // host:port
+ Ok = true;
+ TRes Res{THostAddressAndPort{}, TString(StrIpv4OrHost), Port};
+ return Res;
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ {
+ // ipv4
+ bool IpConverted;
+ const TIpv6Address Ipv4 = TIpv6Address::FromString(RawStr, IpConverted);
+ if (IpConverted && Ipv4.Type() == TIpv6Address::Ipv4) {
+ Ok = true;
+ TRes Res{{Ipv4, DefaultPort}, {}, {}};
+ return Res;
+ }
+ }
+
+ // ---------------------------------------------------------------------
+
+ {
+ // host
+ Ok = true;
+ TRes Res{THostAddressAndPort{}, TString(RawStr), DefaultPort};
+ return Res;
+ }
+}
diff --git a/library/cpp/ipv6_address/ipv6_address.h b/library/cpp/ipv6_address/ipv6_address.h
new file mode 100644
index 0000000000..1d7eb0b65f
--- /dev/null
+++ b/library/cpp/ipv6_address/ipv6_address.h
@@ -0,0 +1,238 @@
+#pragma once
+
+#include <util/generic/hash_set.h>
+#include <util/network/ip.h>
+#include <util/stream/input.h>
+
+#include <library/cpp/int128/int128.h>
+
+#if defined(_freebsd_)
+// #include required to avoid problem with undefined 'socklen_t' on FreeBSD
+#include <sys/socket.h>
+#endif
+
+#if defined(_win_)
+// #include required to avoid problem with undefined 'socklen_t' on Windows
+#include <util/network/socket.h>
+#endif
+
+namespace NAddr {
+ class IRemoteAddr;
+}
+struct in6_addr;
+struct in_addr;
+struct sockaddr;
+struct sockaddr_in;
+struct sockaddr_in6;
+
+// TODO (dimanne): rename to something like TIntInetAddress or THostAddress
+class TIpv6Address {
+public:
+ enum TIpType { Ipv6,
+ Ipv4,
+ LAST };
+
+ constexpr TIpv6Address() noexcept = default;
+ constexpr TIpv6Address(const TIpv6Address&) noexcept = default;
+ constexpr TIpv6Address& operator=(const TIpv6Address&) noexcept = default;
+
+ constexpr TIpv6Address(const ui128& ip, TIpType Type) noexcept
+ : Ip(ip), Type_(Type)
+ {}
+
+ constexpr TIpv6Address(ui8 a, ui8 b, ui8 c, ui8 d) noexcept
+ : Ip((ui32(a) << 24) | (ui32(b) << 16) | (ui32(c) << 8) | ui32(d))
+ , Type_(TIpv6Address::Ipv4)
+ {}
+
+ constexpr TIpv6Address(ui16 a, ui16 b, ui16 c, ui16 d, ui16 e, ui16 f, ui16 g, ui16 h, ui32 scope = 0) noexcept
+ : Type_(TIpv6Address::Ipv6)
+ , ScopeId_(scope)
+ {
+ auto hi = (ui64(a) << 48) | (ui64(b) << 32) | (ui64(c) << 16) | ui64(d);
+ auto lo = (ui64(e) << 48) | (ui64(f) << 32) | (ui64(g) << 16) | ui64(h);
+ Ip = {hi, lo};
+ }
+
+ explicit TIpv6Address(const NAddr::IRemoteAddr& addr);
+ explicit TIpv6Address(const sockaddr_in6& Addr);
+ explicit TIpv6Address(const sockaddr_in& Addr);
+ explicit TIpv6Address(const in6_addr& addr, ui32 Scope);
+ explicit TIpv6Address(const in_addr& addr);
+
+ static TIpv6Address FromString(TStringBuf srcStr, bool& ok) noexcept;
+
+ constexpr bool IsNull() const noexcept {
+ return Ip == 0;
+ }
+
+ constexpr bool IsValid() const noexcept {
+ return Ip != 0 && (Type_ == Ipv6 || Type_ == Ipv4);
+ }
+
+ explicit constexpr operator bool() const noexcept {
+ return IsValid();
+ }
+
+ constexpr bool operator ! () const noexcept {
+ return !IsValid();
+ }
+
+ bool Isv4MappedTov6() const noexcept;
+ TIpv6Address TryToExtractIpv4From6() const noexcept;
+ TIpv6Address Normalized() const noexcept;
+
+ TString ToString(bool* ok = nullptr) const noexcept;
+ TString ToString(bool PrintScopeId, bool* ok = nullptr) const noexcept;
+
+ void ToSockaddrAndSocklen(sockaddr_in& sockAddrIPv4,
+ sockaddr_in6& sockAddrIPv6, // in
+ const sockaddr*& sockAddrPtr,
+ socklen_t& sockAddrSize,
+ ui16 Port) const; // out
+
+ void ToInAddr(in_addr& Addr4) const;
+ void ToIn6Addr(in6_addr& Addr6) const;
+ // int SocketFamily() const;
+
+ constexpr bool operator<(const TIpv6Address& other) const noexcept {
+ if (Type_ != other.Type_)
+ return Type_ > other.Type_;
+ else
+ return Ip < other.Ip;
+ }
+ constexpr bool operator>(const TIpv6Address& other) const noexcept {
+ if (Type_ != other.Type_)
+ return Type_ < other.Type_;
+ else
+ return Ip > other.Ip;
+ }
+ constexpr bool operator==(const TIpv6Address& other) const noexcept {
+ return Type_ == other.Type_ && Ip == other.Ip;
+ }
+ constexpr bool operator!=(const TIpv6Address& other) const noexcept {
+ return Type_ != other.Type_ || Ip != other.Ip;
+ }
+
+ constexpr bool operator<=(const TIpv6Address& other) const noexcept {
+ return !(*this > other);
+ }
+
+ constexpr bool operator>=(const TIpv6Address& other) const noexcept {
+ return !(*this < other);
+ }
+
+ constexpr operator ui128() const noexcept {
+ return Ip;
+ }
+
+ constexpr TIpType Type() const noexcept {
+ return Type_;
+ }
+
+ void SetScopeId(ui32 New) noexcept {
+ ScopeId_ = New;
+ }
+ constexpr ui32 ScopeId() const noexcept {
+ return ScopeId_;
+ }
+
+ void Save(IOutputStream* out) const;
+ void Load(IInputStream* in);
+
+private:
+ void InitFrom(const in6_addr& addr);
+ void InitFrom(const in_addr& addr);
+
+ void InitFrom(const sockaddr_in6& Addr);
+ void InitFrom(const sockaddr_in& Addr);
+
+ ui128 Ip{};
+ TIpType Type_ = LAST;
+ ui32 ScopeId_ = 0;
+};
+IOutputStream& operator<<(IOutputStream& Out, const TIpv6Address::TIpType Type) noexcept;
+IOutputStream& operator<<(IOutputStream& Out, const TIpv6Address& ipv6Address) noexcept;
+
+constexpr TIpv6Address Get127001() noexcept {
+ return {127, 0, 0, 1};
+}
+
+constexpr TIpv6Address Get1() noexcept {
+ return {1, TIpv6Address::Ipv6};
+}
+
+struct THostAddressAndPort {
+ constexpr THostAddressAndPort() noexcept = default;
+ constexpr THostAddressAndPort(const TIpv6Address& i, TIpPort p) noexcept {
+ Ip = i;
+ Port = p;
+ }
+
+ constexpr bool operator==(const THostAddressAndPort& Other) const noexcept {
+ return Ip == Other.Ip && Port == Other.Port;
+ }
+ constexpr bool operator!=(const THostAddressAndPort& Other) const noexcept {
+ return !(*this == Other);
+ }
+ constexpr bool IsValid() const noexcept {
+ return Ip.IsValid() && Port != 0;
+ }
+
+ TString ToString() const noexcept;
+
+ TIpv6Address Ip {};
+ TIpPort Port {0};
+};
+IOutputStream& operator<<(IOutputStream& Out, const THostAddressAndPort& HostAddressAndPort) noexcept;
+
+///
+/// Returns
+/// 1. either valid THostAddressAndPort
+/// 2. or TString with hostname (which you should resolve) and TIpPort with port
+/// 3. or error, if Ok == false
+///
+/// Supported RawStrs are
+/// 1.2.3.4 // port wil be equal to DefaultPort
+/// 1.2.3.4:80
+/// [2001::7348] // port wil be equal to DefaultPort
+/// 2001::7348 // port wil be equal to DefaultPort
+/// [2001::7348]:80
+///
+std::tuple<THostAddressAndPort, TString, TIpPort> ParseHostAndMayBePortFromString(const TString& RawStr,
+ TIpPort DefaultPort,
+ bool& Ok) noexcept;
+
+using TIpv6AddressesSet = THashSet<TIpv6Address>;
+
+template <>
+struct THash<TIpv6Address> {
+ inline size_t operator()(const TIpv6Address& ip) const {
+ const ui128& Tmp = static_cast<ui128>(ip);
+ return CombineHashes(THash<ui128>()(Tmp), THash<ui8>()(static_cast<ui8>(ip.Type())));
+ }
+};
+template <>
+struct THash<THostAddressAndPort> {
+ inline size_t operator()(const THostAddressAndPort& IpAndPort) const {
+ return CombineHashes(THash<TIpv6Address>()(IpAndPort.Ip), THash<TIpPort>()(IpAndPort.Port));
+ }
+};
+
+namespace std {
+ template <>
+ struct hash<TIpv6Address> {
+ std::size_t operator()(const TIpv6Address& Ip) const noexcept {
+ return THash<TIpv6Address>()(Ip);
+ }
+ };
+}
+
+NAddr::IRemoteAddr* ToIRemoteAddr(const TIpv6Address& Address, TIpPort Port);
+
+// template <>
+// class TSerializer<TIpv6Address> {
+// public:
+// static void Save(IOutputStream *out, const TIpv6Address &ip);
+// static void Load(IInputStream *in, TIpv6Address &ip);
+//};
diff --git a/library/cpp/ipv6_address/ipv6_address_p.h b/library/cpp/ipv6_address/ipv6_address_p.h
new file mode 100644
index 0000000000..44bec74579
--- /dev/null
+++ b/library/cpp/ipv6_address/ipv6_address_p.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "ipv6_address.h"
+
+inline TIpv6Address::TIpType FigureOutType(TStringBuf srcStr) noexcept {
+ return srcStr.Contains(':') ? TIpv6Address::Ipv6 : TIpv6Address::Ipv4;
+}
diff --git a/library/cpp/ipv6_address/ut/ipv6_address_ut.cpp b/library/cpp/ipv6_address/ut/ipv6_address_ut.cpp
new file mode 100644
index 0000000000..73bb7cffdd
--- /dev/null
+++ b/library/cpp/ipv6_address/ut/ipv6_address_ut.cpp
@@ -0,0 +1,112 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/ipv6_address/ipv6_address.h>
+#include <unordered_set>
+
+class TIpv6AddressTest: public TTestBase {
+ UNIT_TEST_SUITE(TIpv6AddressTest);
+ UNIT_TEST(ParseHostAndMayBePortFromString_data);
+ UNIT_TEST(CheckAddressValidity)
+ UNIT_TEST_SUITE_END();
+
+private:
+ void ParseHostAndMayBePortFromString_data();
+ void CheckAddressValidity();
+ void HashCompileTest();
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TIpv6AddressTest);
+
+using TResult = std::tuple<THostAddressAndPort, TString, TIpPort>;
+
+TResult IpRes(TString Ip, TIpPort Port) {
+ bool Ok;
+ THostAddressAndPort HostAddressAndPort;
+ HostAddressAndPort.Ip = TIpv6Address::FromString(Ip, Ok);
+ Y_VERIFY(Ok);
+ HostAddressAndPort.Port = Port;
+ return TResult(HostAddressAndPort, {}, {});
+}
+TResult HostRes(TString HostName, TIpPort Port) {
+ return TResult({}, HostName, Port);
+}
+
+void ParseHostAndMayBePortFromString(TString RawStr,
+ TIpPort DefaultPort,
+ const TResult ExpectedResult,
+ const bool ExpectedOk) {
+ bool Ok = false;
+ const TResult ActualResult = ParseHostAndMayBePortFromString(RawStr, DefaultPort, Ok);
+
+ UNIT_ASSERT(Ok == ExpectedOk);
+ if (Ok == false)
+ return;
+
+ UNIT_ASSERT(ActualResult == ExpectedResult);
+}
+
+void CheckIpDefPortAgainstIpPortDefPort_v4OrHost(TString Ip,
+ TIpPort Port,
+ const TResult ExpectedResult,
+ const bool ExpectedOk) {
+ ParseHostAndMayBePortFromString(Ip, Port, ExpectedResult, ExpectedOk);
+
+ TString New = Ip + ":" + ToString(Port);
+ ParseHostAndMayBePortFromString(New, Port + 12, ExpectedResult, ExpectedOk);
+}
+
+void CheckIpDefPortAgainstIpPortDefPort_v6(TString Ip, TIpPort Port, const TResult ExpectedResult, const bool ExpectedOk) {
+ ParseHostAndMayBePortFromString(Ip, Port, ExpectedResult, ExpectedOk);
+
+ TString New = "[" + Ip + "]" + ":" + ToString(Port);
+ ParseHostAndMayBePortFromString(New, Port + 12, ExpectedResult, ExpectedOk);
+}
+
+void CheckIpDefPortAgainstIpPortDefPort(TString Ip, TIpPort Port, const TResult ExpectedResult, const bool ExpectedOk) {
+ if (Ip.find(':') == TString::npos) {
+ CheckIpDefPortAgainstIpPortDefPort_v4OrHost(Ip, Port, ExpectedResult, ExpectedOk);
+ } else {
+ CheckIpDefPortAgainstIpPortDefPort_v6(Ip, Port, ExpectedResult, ExpectedOk);
+ }
+}
+
+void TIpv6AddressTest::ParseHostAndMayBePortFromString_data() {
+ CheckIpDefPortAgainstIpPortDefPort("1.2.3.4", 123, IpRes("1.2.3.4", 123), true);
+ ParseHostAndMayBePortFromString("[1.2.3.4]", 123, {}, false);
+
+ ParseHostAndMayBePortFromString("[2001::7348]", 123, IpRes("2001::7348", 123), true);
+ CheckIpDefPortAgainstIpPortDefPort("2001::7348", 123, IpRes("2001::7348", 123), true);
+
+ CheckIpDefPortAgainstIpPortDefPort("ya.ru", 123, HostRes("ya.ru", 123), true);
+}
+
+void TIpv6AddressTest::CheckAddressValidity() {
+ bool Ok;
+
+ constexpr TIpv6Address partsV4 {12, 34, 56, 78};
+ static_assert(partsV4.Type() == TIpv6Address::Ipv4);
+
+ constexpr TIpv6Address intV4 {0x0C22384E, TIpv6Address::Ipv4};
+ static_assert(partsV4 == intV4);
+
+ const auto parsedV4 = TIpv6Address::FromString("12.34.56.78", Ok);
+ UNIT_ASSERT(Ok);
+ UNIT_ASSERT_EQUAL(parsedV4, partsV4);
+
+ constexpr TIpv6Address partsV6 {0xFB, 0x1634, 0x19, 0xABED, 0, 0x8001, 0x1670, 0x742};
+ static_assert(partsV6.Type() == TIpv6Address::Ipv6);
+
+ constexpr TIpv6Address intV6 {{0x00FB16340019ABED, 0x0000800116700742}, TIpv6Address::Ipv6};
+ static_assert(partsV6 == intV6);
+
+ const auto parsedV6 = TIpv6Address::FromString("FB:1634:19:ABED:0:8001:1670:742", Ok);
+ UNIT_ASSERT(Ok);
+ UNIT_ASSERT_EQUAL(parsedV6, partsV6);
+
+ static_assert(Get127001() == TIpv6Address(0x7F000001, TIpv6Address::Ipv4));
+ static_assert(Get1() == TIpv6Address(0, 0, 0, 0, 0, 0, 0, 1));
+}
+
+void TIpv6AddressTest::HashCompileTest() {
+ std::unordered_set<TIpv6Address> test;
+ Y_UNUSED(test);
+}
diff --git a/library/cpp/ipv6_address/ut/ya.make b/library/cpp/ipv6_address/ut/ya.make
new file mode 100644
index 0000000000..bd22899379
--- /dev/null
+++ b/library/cpp/ipv6_address/ut/ya.make
@@ -0,0 +1,9 @@
+OWNER(g:zora)
+
+UNITTEST_FOR(library/cpp/ipv6_address)
+
+SRCS(
+ ipv6_address_ut.cpp
+)
+
+END()
diff --git a/library/cpp/ipv6_address/ya.make b/library/cpp/ipv6_address/ya.make
new file mode 100644
index 0000000000..5c9bf7e383
--- /dev/null
+++ b/library/cpp/ipv6_address/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(g:zora)
+
+SRCS(
+ ipv6_address.cpp
+ ipv6_address.h
+ ipv6_address_p.h
+)
+
+PEERDIR(
+ library/cpp/int128
+)
+
+END()
diff --git a/library/cpp/iterator/README.md b/library/cpp/iterator/README.md
new file mode 100644
index 0000000000..cd92a284c9
--- /dev/null
+++ b/library/cpp/iterator/README.md
@@ -0,0 +1,100 @@
+# Functools library
+
+Эта библиотека предоставляет функции `Enumerate`, `Zip`, `Map`, `Filter`, `Concatenate` и `CartesianProduct`.
+
+`Enumerate`, `Zip`, `Map`, `Filter` повторяют логику одноименных функций из python.
+
+Важный момент:
+ * Итераторы данных view почти во всех случаях (кроме Map, там зависит от маппера) возвращают `std::tuple` **по значению** (при этом шаблонные параметры всегда, когда это уместно, ссылки).
+ <br> Так что нет никакого смысла делать `for (const auto& [i, x] : Enumerate(c))`.
+ <br> Лучше всегда `for (auto [i, x] : Enumerate(c))` (`x` в этом случае будет ссылкой и работать с ним можно как со ссылкой) или `for (const auto [i, x] : Enumerate(c))`.
+
+Предоставляемые гарантии:
+ * Работа для всех контейнеров, для которых работает range-based for (для `Enumerate`, `Zip`, `Concatenate`, `CartesianProduct`).
+ Для `Map` и `Filter` есть требование на то, что первый и последний итераторы контейнера имеют один тип
+ * В том числе работает для обычных массивов (`int a[] = {1, 2, 3}; Enumerate(a)`).
+ * Поддержка rvalue для контейнеров, предикатов и функций-мапперов (`Filter([](auto x){...}, TVector{1, 2, 3})`).
+ В этом случае объекты сохраняются внутри view.
+ * Проброс элементов контейнеров по неконстантной ссылке
+ * `TView::iterator` - можно полагаться, что этот тип есть и корректен
+ * `TIterator::iterator_category` - можно полагаться, что этот тип есть и определен.
+
+
+На что гарантий нет:
+ * Любые изменения контейнеров, меняющие размер или инвалидирующие их итераторы, инвалидируют созданные view
+ * Не принимает списки инициализации (`Enumerate({1, 2, 3})`), так как неизвестен желаемый тип контейнера.
+ * В классах реализации оставлены публичные члены вида `.Field_`, чтобы не загромождать реализацию
+ Тем не менее эти поля не гарантированы, могут стать приватными или исчезнуть
+ * Для всех итераторов определены вложенные типы: `value_type`, `pointer`, `reference`.
+ Тем не менее не рекомендуется их использовать в связи с их неоднозначностью.
+ `value_type` может быть как обычным типом, так и ссылкой. Может быть `std::tuple<T1, T2>`,
+ а может `std::tuple<T1&, const T2&>`.
+ Если возникает необходимость в этих типах, то возможно, стоит упростить код и вообще не использовать эти view.
+ Если очень хочется можно использовать `delctype(*container.begin())`.
+
+
+Производительность:
+ * Бенчмарки времени компиляции и скорости выполнения, а так же сравнение с range-v3 и другими существующими реализациями
+ доступны в [репозитории где ведется разработка](https://github.com/yuri-pechatnov/cpp_functools/tree/master "functools").
+
+
+
+Q: Оверхед?
+A: По выполнению: на Enumerate, Zip, Map - нулевой. Где-то x1.5 на Filter, и x3 на Concatenate и CartesianProduct. Но если в теле цикла происходит хоть что-то существенное, то это пренебрежимо мало.
+ По компиляции: сложно рассчитать как оно скажется в реальном большом проекте, но приблизительно не более x1.5 на один цикл.
+
+Q: А зачем свой велосипед?
+A: ((https://pechatnov.at.yandex-team.ru/67 Ответ в этом посте)).
+
+Q: А почему вот здесь плохо написано, надо же по-другому?
+A: Код несколько раз переписывался и согласовывался ((https://st.yandex-team.ru/IGNIETFERRO-973 более полугода)). А допиливать его внутреннюю реализацию после коммита никто не мешает и дальше.
+
+
+Сигнатуры и эквиваленты:
+
+
+```cpp
+//! In all comments variables ending with '_'
+//! are considered as invisible for {...} block.
+
+//! Usage: for (auto [i, x] : Enumerate(container)) {...}
+//! Equivalent: { std::size_t i_ = 0; for (auto& x : container) { const std::size_t i = i_; {...}; ++i_; }}
+template <typename TContainerOrRef>
+auto Enumerate(TContainerOrRef&& container);
+
+//! Usage: for (auto x : Map(mapperFunc, container)) {...}
+//! Equivalent: for (auto iter_ = std::begin(container); iter_ != std::end(container); ++iter_) {
+//! auto x = mapperFunc(*iter_); {...}; }
+template <typename TMapper, typename TContainerOrRef>
+auto Map(TMapper&& mapper, TContainerOrRef&& container);
+
+//! Usage: for (auto x : Filter(predicate, container)) {...}
+//! Equivalent: for (auto x : container) { if (predicate(x)) {...}}
+template <typename TPredicate, typename TContainerOrRef>
+auto Filter(TPredicate&& predicate, TContainerOrRef&& container);
+
+//! Usage: for (auto [ai, bi] : Zip(a, b)) {...}
+//! Equivalent: { auto ia_ = std::begin(a); auto ib_ = std::begin(b);
+//! for (; ia_ != std::end(a) && ib_ != std::end(b); ++ia_, ++ib_) {
+//! auto&& ai = *ia_; auto&& bi = *ib_; {...}
+//! }}
+template <typename... TContainers>
+auto Zip(TContainers&&... containers);
+
+//! Usage: for (auto x : Reversed(container)) {...}
+//! Equivalent: for (auto iter_ = std::rbegin(container); iter_ != std::rend(container); ++iter_) {
+//! auto x = *iter_; {...}}
+template <typename TContainerOrRef>
+auto Reversed(TContainerOrRef&& container);
+
+//! Usage: for (auto x : Concatenate(a, b)) {...}
+//! Equivalent: { for (auto x : a) {...} for (auto x : b) {...} }
+//! (if there is no static variables in {...})
+template <typename TFirstContainer, typename... TContainers>
+auto Concatenate(TFirstContainer&& container, TContainers&&... containers);
+
+//! Usage: for (auto [ai, bi] : CartesianProduct(a, b)) {...}
+//! Equivalent: for (auto& ai : a) { for (auto& bi : b) {...} }
+template <typename... TContainers>
+auto CartesianProduct(TContainers&&... containers);
+```
diff --git a/library/cpp/iterator/cartesian_product.cpp b/library/cpp/iterator/cartesian_product.cpp
new file mode 100644
index 0000000000..c3ebfdcc33
--- /dev/null
+++ b/library/cpp/iterator/cartesian_product.cpp
@@ -0,0 +1 @@
+#include "cartesian_product.h"
diff --git a/library/cpp/iterator/cartesian_product.h b/library/cpp/iterator/cartesian_product.h
new file mode 100644
index 0000000000..3ef70339a2
--- /dev/null
+++ b/library/cpp/iterator/cartesian_product.h
@@ -0,0 +1,115 @@
+#pragma once
+
+#include <util/generic/store_policy.h>
+
+#include <tuple>
+
+
+namespace NPrivate {
+
+ template <typename... TContainers>
+ struct TCartesianMultiplier {
+ template <std::size_t... I>
+ struct TCartesianMultiplierWithIndex {
+ private:
+ using THolders = std::tuple<TAutoEmbedOrPtrPolicy<TContainers>...>;
+ using TValue = std::tuple<decltype(*std::begin(std::declval<TContainers&>()))...>;
+ using TIteratorState = std::tuple<int, decltype(std::begin(std::declval<TContainers&>()))...>;
+ using TSentinelState = std::tuple<int, decltype(std::end(std::declval<TContainers&>()))...>;
+
+ struct TIterator;
+ struct TSentinelCandidate {
+ TSentinelState Iterators_;
+ THolders* HoldersPtr_;
+ };
+ using TSentinel = std::conditional_t<std::is_same_v<TIteratorState, TSentinelState>,
+ TIterator, TSentinelCandidate>;
+
+ struct TIterator {
+ private:
+ //! Return value is true when iteration is not finished
+ template <std::size_t position = sizeof...(TContainers)>
+ void IncrementIteratorsTuple() {
+ auto& currentIterator = std::get<position>(Iterators_);
+ ++currentIterator;
+
+ if (currentIterator != std::end(*std::get<position - 1>(*HoldersPtr_).Ptr())) {
+ return;
+ } else {
+ currentIterator = std::begin(*std::get<position - 1>(*HoldersPtr_).Ptr());
+ if constexpr (position != 1) {
+ IncrementIteratorsTuple<position - 1>();
+ } else {
+ std::get<0>(Iterators_) = 1;
+ }
+ }
+ }
+ public:
+ using difference_type = std::ptrdiff_t;
+ using value_type = TValue;
+ using pointer = TValue*;
+ using reference = TValue&;
+ using iterator_category = std::input_iterator_tag;
+
+ TValue operator*() {
+ return {*std::get<I + 1>(Iterators_)...};
+ }
+ TValue operator*() const {
+ return {*std::get<I + 1>(Iterators_)...};
+ }
+ void operator++() {
+ IncrementIteratorsTuple();
+ }
+ bool operator!=(const TSentinel& other) const {
+ // not finished iterator VS sentinel (most frequent case)
+ if (std::get<0>(Iterators_) != std::get<0>(other.Iterators_)) {
+ return true;
+ }
+ // do not compare sentinels and finished iterators
+ if (std::get<0>(other.Iterators_)) {
+ return false;
+ }
+ // compare not finished iterators
+ return ((std::get<I + 1>(Iterators_) != std::get<I + 1>(other.Iterators_)) || ...);
+ }
+ bool operator==(const TSentinel& other) const {
+ return !(*this != other);
+ }
+
+ TIteratorState Iterators_;
+ THolders* HoldersPtr_;
+ };
+ public:
+ using iterator = TIterator;
+ using const_iterator = TIterator;
+ using value_type = typename TIterator::value_type;
+ using reference = typename TIterator::reference;
+ using const_reference = typename TIterator::reference;
+
+ TIterator begin() const {
+ bool isEmpty = !((std::begin(*std::get<I>(Holders_).Ptr()) != std::end(*std::get<I>(Holders_).Ptr())) && ...);
+ return {TIteratorState{int(isEmpty), std::begin(*std::get<I>(Holders_).Ptr())...}, &Holders_};
+ }
+
+ TSentinel end() const {
+ return {TSentinelState{1, std::end(*std::get<I>(Holders_).Ptr())...}, &Holders_};
+ }
+
+ mutable THolders Holders_;
+ };
+
+ template <std::size_t... I>
+ static auto CartesianMultiply(TContainers&&... containers, std::index_sequence<I...>) {
+ return TCartesianMultiplierWithIndex<I...>{{std::forward<TContainers>(containers)...}};
+ }
+ };
+
+}
+
+//! Usage: for (auto [ai, bi] : CartesianProduct(a, b)) {...}
+//! Equivalent: for (auto& ai : a) { for (auto& bi : b) {...} }
+template <typename... TContainers>
+auto CartesianProduct(TContainers&&... containers) {
+ return NPrivate::TCartesianMultiplier<TContainers...>::CartesianMultiply(
+ std::forward<TContainers>(containers)..., std::make_index_sequence<sizeof...(TContainers)>{});
+}
diff --git a/library/cpp/iterator/concatenate.cpp b/library/cpp/iterator/concatenate.cpp
new file mode 100644
index 0000000000..4ca8e2e82d
--- /dev/null
+++ b/library/cpp/iterator/concatenate.cpp
@@ -0,0 +1 @@
+#include "concatenate.h"
diff --git a/library/cpp/iterator/concatenate.h b/library/cpp/iterator/concatenate.h
new file mode 100644
index 0000000000..64d2cd451a
--- /dev/null
+++ b/library/cpp/iterator/concatenate.h
@@ -0,0 +1,136 @@
+#pragma once
+
+#include <util/generic/store_policy.h>
+
+#include <iterator>
+#include <tuple>
+
+
+namespace NPrivate {
+
+ template <typename TValue_, typename... TContainers>
+ struct TConcatenator {
+ template <std::size_t... I>
+ struct TConcatenatorWithIndex {
+ private:
+ using THolders = std::tuple<TAutoEmbedOrPtrPolicy<TContainers>...>;
+ using TValue = TValue_;
+ using TIteratorState = std::tuple<decltype(std::begin(std::declval<TContainers&>()))...>;
+ using TSentinelState = std::tuple<decltype(std::end(std::declval<TContainers&>()))...>;
+
+ struct TIterator;
+ struct TSentinelCandidate {
+ TSentinelState Iterators_;
+ std::size_t Position_;
+ THolders* HoldersPtr_;
+ };
+ using TSentinel = std::conditional_t<std::is_same_v<TIteratorState, TSentinelState>,
+ TIterator, TSentinelCandidate>;
+
+ struct TIterator {
+ private:
+ friend struct TConcatenatorWithIndex<I...>;
+
+ // important, that it is a static function, compiler better optimizes such code
+ template <std::size_t index = 0, typename TMaybeConstIteratorState>
+ static TValue GetCurrentValue(std::size_t position, TMaybeConstIteratorState& iterators) {
+ if constexpr (index >= sizeof...(TContainers)) {
+ // never happened when use of iterator is correct
+ return *std::get<0>(iterators);
+ } else {
+ if (position == index) {
+ return *std::get<index>(iterators);
+ } else {
+ return GetCurrentValue<index + 1>(position, iterators);
+ }
+ }
+ }
+
+ template <bool needIncrement, std::size_t index = 0>
+ void MaybeIncrementIteratorAndSkipExhaustedContainers() {
+ if constexpr (index >= sizeof...(TContainers)) {
+ return;
+ } else {
+ if (Position_ == index) {
+ if constexpr (needIncrement) {
+ ++std::get<index>(Iterators_);
+ }
+ if (!(std::get<index>(Iterators_) != std::end(*std::get<index>(*HoldersPtr_).Ptr()))) {
+ ++Position_;
+ MaybeIncrementIteratorAndSkipExhaustedContainers<false, index + 1>();
+ }
+ } else {
+ MaybeIncrementIteratorAndSkipExhaustedContainers<needIncrement, index + 1>();
+ }
+ }
+ }
+ public:
+ using difference_type = std::ptrdiff_t;
+ using value_type = TValue;
+ using pointer = std::remove_reference_t<TValue>*;
+ using reference = std::remove_reference_t<TValue>&;
+ using iterator_category = std::input_iterator_tag;
+
+ TValue operator*() {
+ return GetCurrentValue(Position_, Iterators_);
+ }
+ TValue operator*() const {
+ return GetCurrentValue(Position_, Iterators_);
+ }
+ TIterator& operator++() {
+ MaybeIncrementIteratorAndSkipExhaustedContainers<true>();
+ return *this;
+ }
+ bool operator!=(const TSentinel& other) const {
+ // give compiler an opportunity to optimize sentinel case (-70% of time)
+ if (other.Position_ == sizeof...(TContainers)) {
+ return Position_ < sizeof...(TContainers);
+ } else {
+ return (Position_ != other.Position_ ||
+ ((std::get<I>(Iterators_) != std::get<I>(other.Iterators_)) || ...));
+ }
+ }
+ bool operator==(const TSentinel& other) const {
+ return !(*this != other);
+ }
+
+ TIteratorState Iterators_;
+ std::size_t Position_;
+ THolders* HoldersPtr_;
+ };
+ public:
+ using iterator = TIterator;
+ using const_iterator = TIterator;
+ using value_type = typename TIterator::value_type;
+ using reference = typename TIterator::reference;
+ using const_reference = typename TIterator::reference;
+
+ TIterator begin() const {
+ TIterator iterator{TIteratorState{std::begin(*std::get<I>(Holders_).Ptr())...}, 0, &Holders_};
+ iterator.template MaybeIncrementIteratorAndSkipExhaustedContainers<false>();
+ return iterator;
+ }
+
+ TSentinel end() const {
+ return {TSentinelState{std::end(*std::get<I>(Holders_).Ptr())...}, sizeof...(TContainers), &Holders_};
+ }
+
+ mutable THolders Holders_;
+ };
+
+ template <std::size_t... I>
+ static auto Concatenate(TContainers&&... containers, std::index_sequence<I...>) {
+ return TConcatenatorWithIndex<I...>{{std::forward<TContainers>(containers)...}};
+ }
+ };
+
+}
+
+
+//! Usage: for (auto x : Concatenate(a, b)) {...}
+template <typename TFirstContainer, typename... TContainers>
+auto Concatenate(TFirstContainer&& container, TContainers&&... containers) {
+ return NPrivate::TConcatenator<decltype(*std::begin(container)), TFirstContainer, TContainers...>::Concatenate(
+ std::forward<TFirstContainer>(container), std::forward<TContainers>(containers)...,
+ std::make_index_sequence<sizeof...(TContainers) + 1>{});
+}
diff --git a/library/cpp/iterator/enumerate.cpp b/library/cpp/iterator/enumerate.cpp
new file mode 100644
index 0000000000..b195f0b31d
--- /dev/null
+++ b/library/cpp/iterator/enumerate.cpp
@@ -0,0 +1 @@
+#include "enumerate.h"
diff --git a/library/cpp/iterator/enumerate.h b/library/cpp/iterator/enumerate.h
new file mode 100644
index 0000000000..2c83fb41bf
--- /dev/null
+++ b/library/cpp/iterator/enumerate.h
@@ -0,0 +1,82 @@
+#pragma once
+
+#include <util/generic/store_policy.h>
+
+#include <limits>
+#include <tuple>
+
+
+namespace NPrivate {
+
+ template <typename TContainer>
+ struct TEnumerator {
+ private:
+ using TStorage = TAutoEmbedOrPtrPolicy<TContainer>;
+ using TValue = std::tuple<const std::size_t, decltype(*std::begin(std::declval<TContainer&>()))>;
+ using TIteratorState = decltype(std::begin(std::declval<TContainer&>()));
+ using TSentinelState = decltype(std::end(std::declval<TContainer&>()));
+
+ static constexpr bool TrivialSentinel = std::is_same_v<TIteratorState, TSentinelState>;
+
+ struct TIterator;
+ struct TSentinelCandidate {
+ TSentinelState Iterator_;
+ };
+ using TSentinel = std::conditional_t<TrivialSentinel, TIterator, TSentinelCandidate>;
+
+ struct TIterator {
+ using difference_type = std::ptrdiff_t;
+ using value_type = TValue;
+ using pointer = TValue*;
+ using reference = TValue&;
+ using iterator_category = std::input_iterator_tag;
+
+ TValue operator*() {
+ return {Index_, *Iterator_};
+ }
+ TValue operator*() const {
+ return {Index_, *Iterator_};
+ }
+ void operator++() {
+ ++Index_;
+ ++Iterator_;
+ }
+ bool operator!=(const TSentinel& other) const {
+ return Iterator_ != other.Iterator_;
+ }
+ bool operator==(const TSentinel& other) const {
+ return Iterator_ == other.Iterator_;
+ }
+
+ std::size_t Index_;
+ TIteratorState Iterator_;
+ };
+ public:
+ using iterator = TIterator;
+ using const_iterator = TIterator;
+ using value_type = typename TIterator::value_type;
+ using reference = typename TIterator::reference;
+ using const_reference = typename TIterator::reference;
+
+ TIterator begin() const {
+ return {0, std::begin(*Storage_.Ptr())};
+ }
+
+ TSentinel end() const {
+ if constexpr (TrivialSentinel) {
+ return TIterator{std::numeric_limits<std::size_t>::max(), std::end(*Storage_.Ptr())};
+ } else {
+ return TSentinel{std::end(*Storage_.Ptr())};
+ }
+ }
+
+ mutable TStorage Storage_;
+ };
+
+}
+
+//! Usage: for (auto [i, x] : Enumerate(container)) {...}
+template <typename TContainerOrRef>
+auto Enumerate(TContainerOrRef&& container) {
+ return NPrivate::TEnumerator<TContainerOrRef>{std::forward<TContainerOrRef>(container)};
+}
diff --git a/library/cpp/iterator/filtering.cpp b/library/cpp/iterator/filtering.cpp
new file mode 100644
index 0000000000..8e1542f61b
--- /dev/null
+++ b/library/cpp/iterator/filtering.cpp
@@ -0,0 +1 @@
+#include "filtering.h"
diff --git a/library/cpp/iterator/filtering.h b/library/cpp/iterator/filtering.h
new file mode 100644
index 0000000000..c28e3bc6c4
--- /dev/null
+++ b/library/cpp/iterator/filtering.h
@@ -0,0 +1,102 @@
+#pragma once
+
+#include <util/generic/iterator_range.h>
+#include <util/generic/store_policy.h>
+#include <iterator>
+
+
+template <class TIterator, class TCondition>
+class TFilteringIterator {
+public:
+ using TSelf = TFilteringIterator<TIterator, TCondition>;
+
+ using difference_type = typename std::iterator_traits<TIterator>::difference_type;
+ using value_type = typename std::iterator_traits<TIterator>::value_type;
+ using reference = typename std::iterator_traits<TIterator>::reference;
+ using pointer = typename std::iterator_traits<TIterator>::pointer;
+ using iterator_category = std::forward_iterator_tag;
+
+ TFilteringIterator(TIterator it, TIterator last, const TCondition& condition)
+ : Iter(it)
+ , Last(last)
+ , Condition(condition)
+ {
+ Grep();
+ }
+
+ TSelf& operator++() {
+ ++Iter;
+ Grep();
+ return *this;
+ }
+
+ decltype(auto) operator*() const {
+ return *Iter;
+ }
+
+ pointer operator->() const {
+ return &*Iter;
+ }
+
+ bool operator==(const TSelf& other) const {
+ return Iter == other.Iter;
+ }
+ bool operator!=(const TSelf& other) const {
+ return Iter != other.Iter;
+ }
+
+private:
+ void Grep() {
+ while (Iter != Last && !Condition(*Iter)) {
+ ++Iter;
+ }
+ }
+ TIterator Iter;
+ TIterator Last;
+ TCondition Condition;
+};
+
+
+template <class TContainer, class TCondition>
+class TFilteringRange {
+ using TContainerStorage = TAutoEmbedOrPtrPolicy<TContainer>;
+ using TConditionStorage = TAutoEmbedOrPtrPolicy<TCondition>;
+ using TRawIterator = decltype(std::begin(std::declval<TContainer&>()));
+ using TConditionWrapper = std::reference_wrapper<std::remove_reference_t<TCondition>>;
+public:
+ //TODO: make TIterator typedef private
+ using TIterator = TFilteringIterator<TRawIterator, TConditionWrapper>;
+
+ using iterator = TIterator;
+ using const_iterator = TIterator;
+ using value_type = typename TIterator::value_type;
+ using reference = typename TIterator::reference;
+
+ TFilteringRange(TContainer&& container, TCondition&& predicate)
+ : Container(std::forward<TContainer>(container))
+ , Condition(std::forward<TCondition>(predicate))
+ {}
+
+ TIterator begin() const {
+ return {std::begin(*Container.Ptr()), std::end(*Container.Ptr()), {*Condition.Ptr()}};
+ }
+
+ TIterator end() const {
+ return {std::end(*Container.Ptr()), std::end(*Container.Ptr()), {*Condition.Ptr()}};
+ }
+
+private:
+ mutable TContainerStorage Container;
+ mutable TConditionStorage Condition;
+};
+
+
+template <class TIterator, class TCondition>
+auto MakeFilteringRange(TIterator begin, TIterator end, const TCondition& condition) {
+ return MakeIteratorRange(TFilteringIterator<TIterator, TCondition>(begin, end, condition), TFilteringIterator<TIterator, TCondition>(end, end, condition));
+}
+
+template <class TContainer, class TCondition>
+auto MakeFilteringRange(TContainer&& container, TCondition&& condition) {
+ return TFilteringRange<TContainer, TCondition>(std::forward<TContainer>(container), std::forward<TCondition>(condition));
+}
diff --git a/library/cpp/iterator/functools.cpp b/library/cpp/iterator/functools.cpp
new file mode 100644
index 0000000000..da2d0757ce
--- /dev/null
+++ b/library/cpp/iterator/functools.cpp
@@ -0,0 +1 @@
+#include "functools.h"
diff --git a/library/cpp/iterator/functools.h b/library/cpp/iterator/functools.h
new file mode 100644
index 0000000000..57a0d66373
--- /dev/null
+++ b/library/cpp/iterator/functools.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#include "cartesian_product.h"
+#include "concatenate.h"
+#include "enumerate.h"
+#include "filtering.h"
+#include "mapped.h"
+#include "zip.h"
+
+#include <util/generic/adaptor.h>
+#include <util/generic/xrange.h>
+
+#include <tuple>
+#include <algorithm>
+
+
+namespace NFuncTools {
+ using ::Enumerate;
+ using ::Reversed;
+ using ::Zip;
+ using ::Concatenate;
+ using ::CartesianProduct;
+
+ template <typename TValue>
+ auto Range(TValue from, TValue to, TValue step) {
+ return xrange(from, to, step);
+ }
+
+ template <typename TValue>
+ auto Range(TValue from, TValue to) {
+ return xrange(from, to);
+ }
+
+ template <typename TValue>
+ auto Range(TValue to) {
+ return xrange(to);
+ }
+
+ //! Usage: for (i32 x : Map([](i32 x) { return x * x; }, a)) {...}
+ template <typename TMapper, typename TContainerOrRef>
+ auto Map(TMapper&& mapper, TContainerOrRef&& container) {
+ return ::MakeMappedRange(std::forward<TContainerOrRef>(container), std::forward<TMapper>(mapper));
+ }
+
+ //! Usage: for (auto i : Map<int>(floats)) {...}
+ template <typename TMapResult, typename TContainerOrRef>
+ auto Map(TContainerOrRef&& container) {
+ return Map([](const auto& x) { return TMapResult(x); }, std::forward<TContainerOrRef>(container));
+ }
+
+ //! Usage: for (i32 x : Filter(predicate, container)) {...}
+ template <typename TPredicate, typename TContainerOrRef>
+ auto Filter(TPredicate&& predicate, TContainerOrRef&& container) {
+ return ::MakeFilteringRange(std::forward<TContainerOrRef>(container), std::forward<TPredicate>(predicate));
+ }
+
+}
diff --git a/library/cpp/iterator/iterate_keys.cpp b/library/cpp/iterator/iterate_keys.cpp
new file mode 100644
index 0000000000..6556d39af7
--- /dev/null
+++ b/library/cpp/iterator/iterate_keys.cpp
@@ -0,0 +1 @@
+#include "iterate_keys.h"
diff --git a/library/cpp/iterator/iterate_keys.h b/library/cpp/iterator/iterate_keys.h
new file mode 100644
index 0000000000..75362a6bd6
--- /dev/null
+++ b/library/cpp/iterator/iterate_keys.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "mapped.h"
+
+template<typename TMapping>
+auto IterateKeys(TMapping&& map) {
+ return ::MakeMappedRange(
+ std::forward<TMapping>(map),
+ [](const auto& x) -> decltype((x.first)) {
+ return x.first;
+ }
+ );
+}
diff --git a/library/cpp/iterator/iterate_values.cpp b/library/cpp/iterator/iterate_values.cpp
new file mode 100644
index 0000000000..5607e58ecb
--- /dev/null
+++ b/library/cpp/iterator/iterate_values.cpp
@@ -0,0 +1 @@
+#include "iterate_values.h"
diff --git a/library/cpp/iterator/iterate_values.h b/library/cpp/iterator/iterate_values.h
new file mode 100644
index 0000000000..ac6f2f04ce
--- /dev/null
+++ b/library/cpp/iterator/iterate_values.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "mapped.h"
+
+template<typename TMapping>
+auto IterateValues(TMapping&& map) {
+ return ::MakeMappedRange(
+ std::forward<TMapping>(map),
+ [](auto& x) -> decltype((x.second)) {
+ return x.second;
+ }
+ );
+}
diff --git a/library/cpp/iterator/mapped.cpp b/library/cpp/iterator/mapped.cpp
new file mode 100644
index 0000000000..047f38c58f
--- /dev/null
+++ b/library/cpp/iterator/mapped.cpp
@@ -0,0 +1 @@
+#include "mapped.h"
diff --git a/library/cpp/iterator/mapped.h b/library/cpp/iterator/mapped.h
new file mode 100644
index 0000000000..6c5e763184
--- /dev/null
+++ b/library/cpp/iterator/mapped.h
@@ -0,0 +1,193 @@
+#pragma once
+
+#include <util/generic/iterator_range.h>
+#include <util/generic/store_policy.h>
+
+#include <iterator>
+
+
+namespace NIteratorPrivate {
+ template <class TIterator>
+ constexpr bool HasRandomAccess() {
+ return std::is_same_v<typename std::iterator_traits<TIterator>::iterator_category,
+ std::random_access_iterator_tag>;
+ }
+};
+
+
+template <class TIterator, class TMapper>
+class TMappedIterator {
+protected:
+ using TSelf = TMappedIterator<TIterator, TMapper>;
+ using TSrcPointerType = typename std::iterator_traits<TIterator>::reference;
+ using TValue = typename std::invoke_result_t<TMapper, TSrcPointerType>;
+public:
+ using difference_type = std::ptrdiff_t;
+ using value_type = TValue;
+ using reference = TValue&;
+ using pointer = std::remove_reference_t<TValue>*;
+ using iterator_category = std::conditional_t<NIteratorPrivate::HasRandomAccess<TIterator>(),
+ std::random_access_iterator_tag, std::input_iterator_tag>;
+
+ TMappedIterator(TIterator it, TMapper mapper)
+ : Iter(it)
+ , Mapper(std::move(mapper))
+ {
+ }
+
+ TSelf& operator++() {
+ ++Iter;
+ return *this;
+ }
+ TSelf& operator--() {
+ --Iter;
+ return *this;
+ }
+ TValue operator*() {
+ return Mapper((*Iter));
+ }
+ TValue operator*() const {
+ return Mapper((*Iter));
+ }
+
+ pointer operator->() const {
+ return &(Mapper((*Iter)));
+ }
+
+ TValue operator[](difference_type n) const {
+ return Mapper(*(Iter + n));
+ }
+ TSelf& operator+=(difference_type n) {
+ Iter += n;
+ return *this;
+ }
+ TSelf& operator-=(difference_type n) {
+ Iter -= n;
+ return *this;
+ }
+ TSelf operator+(difference_type n) const {
+ return TSelf(Iter + n, Mapper);
+ }
+ TSelf operator-(difference_type n) const {
+ return TSelf(Iter - n, Mapper);
+ }
+ difference_type operator-(const TSelf& other) const {
+ return Iter - other.Iter;
+ }
+ bool operator==(const TSelf& other) const {
+ return Iter == other.Iter;
+ }
+ bool operator!=(const TSelf& other) const {
+ return Iter != other.Iter;
+ }
+ bool operator>(const TSelf& other) const {
+ return Iter > other.Iter;
+ }
+ bool operator<(const TSelf& other) const {
+ return Iter < other.Iter;
+ }
+
+private:
+ TIterator Iter;
+ TMapper Mapper;
+};
+
+
+template <class TContainer, class TMapper>
+class TInputMappedRange {
+protected:
+ using TContainerStorage = TAutoEmbedOrPtrPolicy<TContainer>;
+ using TMapperStorage = TAutoEmbedOrPtrPolicy<TMapper>;
+ using TMapperWrapper = std::reference_wrapper<std::remove_reference_t<TMapper>>;
+ using TInternalIterator = decltype(std::begin(std::declval<TContainer&>()));
+ using TIterator = TMappedIterator<TInternalIterator, TMapperWrapper>;
+public:
+ using iterator = TIterator;
+ using const_iterator = TIterator;
+ using value_type = typename TIterator::value_type;
+ using reference = typename TIterator::reference;
+ using const_reference = typename TIterator::reference;
+
+ TInputMappedRange(TContainer&& container, TMapper&& mapper)
+ : Container(std::forward<TContainer>(container))
+ , Mapper(std::forward<TMapper>(mapper))
+ {
+ }
+
+ TIterator begin() const {
+ return {std::begin(*Container.Ptr()), {*Mapper.Ptr()}};
+ }
+
+ TIterator end() const {
+ return {std::end(*Container.Ptr()), {*Mapper.Ptr()}};
+ }
+
+ bool empty() const {
+ return std::begin(*Container.Ptr()) == std::end(*Container.Ptr());
+ }
+
+protected:
+ mutable TContainerStorage Container;
+ mutable TMapperStorage Mapper;
+};
+
+
+template <class TContainer, class TMapper>
+class TRandomAccessMappedRange : public TInputMappedRange<TContainer, TMapper> {
+ using TBase = TInputMappedRange<TContainer, TMapper>;
+ using TInternalIterator = typename TBase::TInternalIterator;
+ using TIterator = typename TBase::TIterator;
+public:
+ using iterator = typename TBase::iterator;
+ using const_iterator = typename TBase::const_iterator;
+ using value_type = typename TBase::value_type;
+ using reference = typename TBase::reference;
+ using const_reference = typename TBase::const_reference;
+
+ using difference_type = typename std::iterator_traits<iterator>::difference_type;
+ using size_type = std::size_t;
+
+ TRandomAccessMappedRange(TContainer&& container, TMapper&& mapper)
+ : TBase(std::forward<TContainer>(container), std::forward<TMapper>(mapper))
+ {
+ }
+
+ using TBase::begin;
+ using TBase::end;
+ using TBase::empty;
+
+ size_type size() const {
+ return std::end(*this->Container.Ptr()) - std::begin(*this->Container.Ptr());
+ }
+
+ const_reference operator[](size_t at) const {
+ Y_ASSERT(at < this->size());
+
+ return *(this->begin() + at);
+ }
+
+ reference operator[](size_t at) {
+ Y_ASSERT(at < this->size());
+
+ return *(this->begin() + at);
+ }
+};
+
+template <class TIterator, class TMapper>
+TMappedIterator<TIterator, TMapper> MakeMappedIterator(TIterator iter, TMapper mapper) {
+ return {iter, mapper};
+}
+
+template <class TIterator, class TMapper>
+auto MakeMappedRange(TIterator begin, TIterator end, TMapper mapper) {
+ return MakeIteratorRange(MakeMappedIterator(begin, mapper), MakeMappedIterator(end, mapper));
+}
+
+template <class TContainer, class TMapper>
+auto MakeMappedRange(TContainer&& container, TMapper&& mapper) {
+ if constexpr (NIteratorPrivate::HasRandomAccess<decltype(std::begin(container))>()) {
+ return TRandomAccessMappedRange<TContainer, TMapper>(std::forward<TContainer>(container), std::forward<TMapper>(mapper));
+ } else {
+ return TInputMappedRange<TContainer, TMapper>(std::forward<TContainer>(container), std::forward<TMapper>(mapper));
+ }
+}
diff --git a/library/cpp/iterator/ut/filtering_ut.cpp b/library/cpp/iterator/ut/filtering_ut.cpp
new file mode 100644
index 0000000000..60c2044698
--- /dev/null
+++ b/library/cpp/iterator/ut/filtering_ut.cpp
@@ -0,0 +1,41 @@
+#include <library/cpp/iterator/filtering.h>
+
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <util/generic/vector.h>
+
+using namespace testing;
+
+TEST(Filtering, TFilteringRangeTest) {
+ const TVector<int> x = {1, 2, 3, 4, 5};
+
+ EXPECT_THAT(
+ MakeFilteringRange(
+ x,
+ [](int x) { return x % 2 == 0; }
+ ),
+ ElementsAre(2, 4)
+ );
+}
+
+TEST(Filtering, TEmptyFilteringRangeTest) {
+ TVector<int> x = {1, 2, 3, 4, 5};
+ EXPECT_THAT(
+ MakeFilteringRange(
+ x,
+ [](int x) { return x > 100; }
+ ),
+ ElementsAre()
+ );
+}
+
+TEST(Filtering, TMutableFilteringRangeTest) {
+ TVector<int> x = {1, 2, 3, 4, 5};
+ for (auto& y : MakeFilteringRange(x, [](int x) { return x % 2 == 0; })) {
+ y = 7;
+ }
+ EXPECT_THAT(
+ x,
+ ElementsAre(1, 7, 3, 7, 5)
+ );
+}
diff --git a/library/cpp/iterator/ut/functools_ut.cpp b/library/cpp/iterator/ut/functools_ut.cpp
new file mode 100644
index 0000000000..2dee9a55c8
--- /dev/null
+++ b/library/cpp/iterator/ut/functools_ut.cpp
@@ -0,0 +1,603 @@
+#include <library/cpp/iterator/functools.h>
+
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <util/generic/vector.h>
+#include <util/generic/xrange.h>
+#include <util/generic/adaptor.h>
+
+#include <set>
+
+// default-win-x86_64-release compiler can't decompose tuple to structure binding (02.03.2019)
+#ifndef _WINDOWS
+# define FOR_DISPATCH_2(i, j, r) \
+ for (auto [i, j] : r)
+# define FOR_DISPATCH_3(i, j, k, r) \
+ for (auto [i, j, k] : r)
+#else
+# define FOR_DISPATCH_2(i, j, r) \
+ for (auto __t_##i##_##j : r) \
+ if (auto& i = std::get<0>(__t_##i##_##j); true) \
+ if (auto& j = std::get<1>(__t_##i##_##j); true)
+# define FOR_DISPATCH_3(i, j, k, r) \
+ for (auto __t_##i##_##j##_##k : r) \
+ if (auto& i = std::get<0>(__t_##i##_##j##_##k); true) \
+ if (auto& j = std::get<1>(__t_##i##_##j##_##k); true) \
+ if (auto& k = std::get<2>(__t_##i##_##j##_##k); true)
+#endif
+
+using namespace NFuncTools;
+
+
+ template <typename TContainer>
+ auto ToVector(TContainer&& container) {
+ return std::vector{container.begin(), container.end()};
+ }
+
+ template <typename TContainerObjOrRef>
+ void TestViewCompileability(TContainerObjOrRef&& container) {
+ using TContainer = std::decay_t<TContainerObjOrRef>;
+ using TIterator = typename TContainer::iterator;
+
+ static_assert(std::is_same_v<decltype(container.begin()), TIterator>);
+
+ // iterator_traits must work!
+ using difference_type = typename std::iterator_traits<TIterator>::difference_type;
+ using value_type = typename std::iterator_traits<TIterator>::value_type;
+ using reference = typename std::iterator_traits<TIterator>::reference;
+ using pointer = typename std::iterator_traits<TIterator>::pointer;
+
+ {
+ // operator assignment
+ auto it = container.begin();
+ it = container.end();
+ it = std::move(container.begin());
+ // operator copying
+ auto it2 = it;
+ Y_UNUSED(it2);
+ auto it3 = std::move(it);
+ Y_UNUSED(it3);
+ Y_UNUSED(*it3);
+ EXPECT_TRUE(it3 == it3);
+ EXPECT_FALSE(it3 != it3);
+ // const TIterator
+ const auto it4 = it3;
+ Y_UNUSED(*it4);
+ EXPECT_TRUE(it4 == it4);
+ EXPECT_FALSE(it4 != it4);
+ EXPECT_TRUE(it3 == it4);
+ EXPECT_TRUE(it4 == it3);
+ EXPECT_FALSE(it3 != it4);
+ EXPECT_FALSE(it4 != it3);
+ }
+
+ auto it = container.begin();
+
+ // sanity check for types
+ using TConstReference = const std::remove_reference_t<reference>&;
+ TConstReference ref = *it;
+ Y_UNUSED(ref);
+ (void) static_cast<value_type>(*it);
+ (void) static_cast<difference_type>(1);
+ if constexpr (std::is_reference_v<decltype(*it)>) {
+ pointer ptr = &*it;
+ Y_UNUSED(ptr);
+ }
+
+ // std compatibility
+ ToVector(container);
+
+ // const iterators
+ [](const auto& cont) {
+ auto constBeginIterator = cont.begin();
+ auto constEndIterator = cont.end();
+ static_assert(std::is_same_v<decltype(constBeginIterator), typename TContainer::const_iterator>);
+ Y_UNUSED(constBeginIterator);
+ Y_UNUSED(constEndIterator);
+ }(container);
+ }
+
+ struct TTestSentinel {};
+ struct TTestIterator {
+ int operator*() {
+ return X;
+ }
+ void operator++() {
+ ++X;
+ }
+ bool operator!=(const TTestSentinel&) const {
+ return X < 3;
+ }
+
+ int X;
+ };
+
+ // container with minimal interface
+ auto MakeMinimalisticContainer() {
+ return MakeIteratorRange(TTestIterator{}, TTestSentinel{});
+ }
+
+
+ TEST(FuncTools, CompileRange) {
+ TestViewCompileability(Range(19));
+ TestViewCompileability(Range(10, 19));
+ TestViewCompileability(Range(10, 19, 2));
+ }
+
+
+ TEST(FuncTools, Enumerate) {
+ TVector<size_t> a = {1, 2, 4};
+ TVector<size_t> b;
+ TVector<size_t> c = {1};
+ for (auto& v : {a, b, c}) {
+ size_t j = 0;
+ FOR_DISPATCH_2(i, x, Enumerate(v)) {
+ EXPECT_EQ(v[i], x);
+ EXPECT_EQ(i, j++);
+ EXPECT_LT(i, v.size());
+ }
+ EXPECT_EQ(j, v.size());
+ }
+
+ TVector<size_t> d = {0, 0, 0};
+ FOR_DISPATCH_2(i, x, Enumerate(d)) {
+ x = i;
+ }
+ EXPECT_THAT(
+ d,
+ testing::ElementsAre(0u, 1u, 2u)
+ );
+ }
+
+ TEST(FuncTools, EnumerateTemporary) {
+ TVector<size_t> a = {1, 2, 4};
+ TVector<size_t> b;
+ TVector<size_t> c = {1};
+ for (auto& v : {a, b, c}) {
+ size_t j = 0;
+ FOR_DISPATCH_2(i, x, Enumerate(TVector(v))) {
+ EXPECT_EQ(v[i], x);
+ EXPECT_EQ(i, j++);
+ EXPECT_LT(i, v.size());
+ }
+ EXPECT_EQ(j, v.size());
+ }
+
+ FOR_DISPATCH_2(i, x, Enumerate(TVector<size_t>{1, 2, 3})) {
+ EXPECT_EQ(i + 1, x);
+ }
+ }
+
+ TEST(FuncTools, CompileEnumerate) {
+ auto container = std::vector{1, 2, 3};
+ TestViewCompileability(Enumerate(container));
+ const auto constContainer = std::vector{1, 2, 3};
+ TestViewCompileability(Enumerate(constContainer));
+ const int arrayContainer[] = {1, 2, 3};
+ TestViewCompileability(Enumerate(arrayContainer));
+
+ std::vector<std::pair<int, int>> res;
+ FOR_DISPATCH_2(i, x, Enumerate(MakeMinimalisticContainer())) {
+ res.push_back({i, x});
+ }
+ EXPECT_EQ(res, (std::vector<std::pair<int, int>>{
+ {0, 0}, {1, 1}, {2, 2},
+ }));
+ }
+
+ TEST(FuncTools, Zip) {
+ TVector<std::pair<TVector<size_t>, TVector<size_t>>> ts = {
+ {{1, 2, 3}, {4, 5, 6}},
+ {{1, 2, 3}, {4, 5, 6, 7}},
+ {{1, 2, 3, 4}, {4, 5, 6}},
+ {{1, 2, 3, 4}, {}},
+ };
+
+ FOR_DISPATCH_2(a, b, ts) {
+ size_t k = 0;
+ FOR_DISPATCH_2(i, j, Zip(a, b)) {
+ EXPECT_EQ(++k, i);
+ EXPECT_EQ(i + 3, j);
+ }
+ EXPECT_EQ(k, Min(a.size(), b.size()));
+ }
+ }
+
+ TEST(FuncTools, ZipReference) {
+ TVector a = {0, 1, 2};
+ TVector b = {2, 1, 0, -1};
+ FOR_DISPATCH_2(ai, bi, Zip(a, b)) {
+ ai = bi;
+ }
+ EXPECT_THAT(
+ a,
+ testing::ElementsAre(2u, 1u, 0u)
+ );
+ }
+
+ TEST(FuncTools, Zip3) {
+ TVector<std::tuple<TVector<i32>, TVector<i32>, TVector<i32>>> ts = {
+ {{1, 2, 3}, {4, 5, 6}, {11, 3}},
+ {{1, 2, 3}, {4, 5, 6, 7}, {9, 0}},
+ {{1, 2, 3, 4}, {9}, {4, 5, 6}},
+ {{1, 2, 3, 4}, {1}, {}},
+ {{}, {1}, {1, 2, 3, 4}},
+ };
+
+ FOR_DISPATCH_3(a, b, c, ts) {
+ TVector<std::tuple<i32, i32, i32>> e;
+ for (size_t j = 0; j < a.size() && j < b.size() && j < c.size(); ++j) {
+ e.push_back({a[j], b[j], c[j]});
+ }
+
+ TVector<std::tuple<i32, i32, i32>> f;
+ FOR_DISPATCH_3(ai, bi, ci, Zip(a, b, c)) {
+ f.push_back({ai, bi, ci});
+ }
+
+ EXPECT_EQ(e, f);
+ }
+ }
+
+ TEST(FuncTools, CompileZip) {
+ auto container = std::vector{1, 2, 3};
+ TestViewCompileability(Zip(container));
+ TestViewCompileability(Zip(container, container, container));
+ const auto constContainer = std::vector{1, 2, 3};
+ TestViewCompileability(Zip(constContainer, constContainer));
+ const int arrayContainer[] = {1, 2, 3};
+ TestViewCompileability(Zip(arrayContainer, arrayContainer));
+
+ std::vector<std::pair<int, int>> res;
+ FOR_DISPATCH_2(a, b, Zip(MakeMinimalisticContainer(), container)) {
+ res.push_back({a, b});
+ }
+ EXPECT_EQ(res, (std::vector<std::pair<int, int>>{
+ {0, 1}, {1, 2}, {2, 3},
+ }));
+ }
+
+ TEST(FuncTools, Filter) {
+ TVector<TVector<i32>> ts = {
+ {},
+ {1},
+ {2},
+ {1, 2},
+ {2, 1},
+ {1, 2, 3, 4, 5, 6, 7},
+ };
+
+ auto pred = [](i32 x) -> bool { return x & 1; };
+
+ for (auto& a : ts) {
+ TVector<i32> b;
+ for (i32 x : a) {
+ if (pred(x)) {
+ b.push_back(x);
+ }
+ }
+
+ TVector<i32> c;
+ for (i32 x : Filter(pred, a)) {
+ c.push_back(x);
+ }
+
+ EXPECT_EQ(b, c);
+ }
+ }
+
+ TEST(FuncTools, CompileFilter) {
+ auto container = std::vector{1, 2, 3};
+ auto isOdd = [](int x) { return bool(x & 1); };
+ TestViewCompileability(Filter(isOdd, container));
+ const int arrayContainer[] = {1, 2, 3};
+ TestViewCompileability(Filter(isOdd, arrayContainer));
+ }
+
+ TEST(FuncTools, Map) {
+ TVector<TVector<i32>> ts = {
+ {},
+ {1},
+ {1, 2},
+ {1, 2, 3, 4, 5, 6, 7},
+ };
+
+ auto f = [](i32 x) { return x * x; };
+
+ for (auto& a : ts) {
+ TVector<i32> b;
+ for (i32 x : a) {
+ b.push_back(f(x));
+ }
+
+ TVector<i32> c;
+ for (i32 x : Map(f, a)) {
+ c.push_back(x);
+ }
+
+ EXPECT_EQ(b, c);
+ }
+
+ TVector floats = {1.4, 4.1, 13.9};
+ TVector ints = {1, 4, 13};
+ TVector<float> roundedFloats = {1, 4, 13};
+ TVector<int> res;
+ TVector<float> resFloat;
+ for (auto i : Map<int>(floats)) {
+ res.push_back(i);
+ }
+ for (auto i : Map<float>(Map<int>(floats))) {
+ resFloat.push_back(i);
+ }
+ EXPECT_EQ(ints, res);
+ EXPECT_EQ(roundedFloats, resFloat);
+ }
+
+ TEST(FuncTools, CompileMap) {
+ auto container = std::vector{1, 2, 3};
+ auto sqr = [](int x) { return x * x; };
+ TestViewCompileability(Map(sqr, container));
+ const int arrayContainer[] = {1, 2, 3};
+ TestViewCompileability(Map(sqr, arrayContainer));
+ }
+
+ TEST(FuncTools, MapRandomAccess) {
+ auto sqr = [](int x) { return x * x; };
+ {
+ auto container = std::vector{1, 2, 3};
+ auto mapped = Map(sqr, container);
+ static_assert(
+ std::is_same_v<decltype(mapped)::iterator::iterator_category, std::random_access_iterator_tag>
+ );
+ }
+ {
+ auto container = std::set<int>{1, 2, 3};
+ auto mapped = Map(sqr, container);
+ static_assert(
+ std::is_same_v<decltype(mapped)::iterator::iterator_category, std::input_iterator_tag>
+ );
+ }
+ }
+
+ TEST(FuncTools, CartesianProduct) {
+ TVector<std::pair<TVector<i32>, TVector<i32>>> ts = {
+ {{1, 2, 3}, {4, 5, 6}},
+ {{1, 2, 3}, {4, 5, 6, 7}},
+ {{1, 2, 3, 4}, {4, 5, 6}},
+ {{1, 2, 3, 4}, {}},
+ {{}, {1, 2, 3, 4}},
+ };
+
+ for (auto [a, b] : ts) {
+ TVector<std::pair<i32, i32>> c;
+ for (auto ai : a) {
+ for (auto bi : b) {
+ c.push_back({ai, bi});
+ }
+ }
+
+ TVector<std::pair<i32, i32>> d;
+ FOR_DISPATCH_2(ai, bi, CartesianProduct(a, b)) {
+ d.push_back({ai, bi});
+ }
+
+ EXPECT_EQ(c, d);
+ }
+
+ {
+ TVector<TVector<int>> g = {{}, {}};
+ TVector h = {10, 11, 12};
+ FOR_DISPATCH_2(gi, i, CartesianProduct(g, h)) {
+ gi.push_back(i);
+ }
+ EXPECT_EQ(g[0], h);
+ EXPECT_EQ(g[1], h);
+ }
+ }
+
+ TEST(FuncTools, CartesianProduct3) {
+ TVector<std::tuple<TVector<i32>, TVector<i32>, TVector<i32>>> ts = {
+ {{1, 2, 3}, {4, 5, 6}, {11, 3}},
+ {{1, 2, 3}, {4, 5, 6, 7}, {9}},
+ {{1, 2, 3, 4}, {9}, {4, 5, 6}},
+ {{1, 2, 3, 4}, {1}, {}},
+ {{}, {1}, {1, 2, 3, 4}},
+ };
+
+ FOR_DISPATCH_3(a, b, c, ts) {
+ TVector<std::tuple<i32, i32, i32>> e;
+ for (auto ai : a) {
+ for (auto bi : b) {
+ for (auto ci : c) {
+ e.push_back({ai, bi, ci});
+ }
+ }
+ }
+
+ TVector<std::tuple<i32, i32, i32>> f;
+ FOR_DISPATCH_3(ai, bi, ci, CartesianProduct(a, b, c)) {
+ f.push_back({ai, bi, ci});
+ }
+
+ EXPECT_EQ(e, f);
+ }
+ }
+
+ TEST(FuncTools, CompileCartesianProduct) {
+ auto container = std::vector{1, 2, 3};
+ TestViewCompileability(CartesianProduct(container, container));
+ const auto constContainer = std::vector{1, 2, 3};
+ TestViewCompileability(CartesianProduct(constContainer, constContainer));
+ const int arrayContainer[] = {1, 2, 3};
+ TestViewCompileability(CartesianProduct(arrayContainer, arrayContainer));
+
+ std::vector<std::pair<int, int>> res;
+ FOR_DISPATCH_2(a, b, CartesianProduct(MakeMinimalisticContainer(), MakeMinimalisticContainer())) {
+ res.push_back({a, b});
+ }
+ EXPECT_EQ(res, (std::vector<std::pair<int, int>>{
+ {0, 0}, {0, 1}, {0, 2},
+ {1, 0}, {1, 1}, {1, 2},
+ {2, 0}, {2, 1}, {2, 2},
+ }));
+ }
+
+ TEST(FuncTools, Concatenate2) {
+ TVector<std::pair<TVector<i32>, TVector<i32>>> ts = {
+ {{1, 2, 3}, {4, 5, 6}},
+ {{1, 2, 3}, {4, 5, 6, 7}},
+ {{1, 2, 3, 4}, {4, 5, 6}},
+ {{1, 2, 3, 4}, {}},
+ {{}, {1, 2, 3, 4}},
+ };
+
+ for (auto [a, b] : ts) {
+ TVector<i32> c;
+ for (auto ai : a) {
+ c.push_back(ai);
+ }
+ for (auto bi : b) {
+ c.push_back(bi);
+ }
+
+ TVector<i32> d;
+ for (auto x : Concatenate(a, b)) {
+ d.push_back(x);
+ }
+
+ EXPECT_EQ(c, d);
+ }
+
+ {
+ TVector<i32> a = {1, 2, 3, 4};
+ TVector<i32> c;
+ for (auto x : Concatenate(a, TVector<i32>{5, 6})) {
+ c.push_back(x);
+ }
+ EXPECT_EQ(c, (TVector<i32>{1, 2, 3, 4, 5, 6}));
+ }
+ }
+
+ TEST(FuncTools, CompileConcatenate) {
+ auto container = std::vector{1, 2, 3};
+ TestViewCompileability(Concatenate(container, container));
+ const auto constContainer = std::vector{1, 2, 3};
+ TestViewCompileability(Concatenate(constContainer, constContainer));
+ const int arrayContainer[] = {1, 2, 3};
+ TestViewCompileability(Concatenate(arrayContainer, arrayContainer));
+
+ std::vector<int> res;
+ for (auto a : Concatenate(MakeMinimalisticContainer(), MakeMinimalisticContainer())) {
+ res.push_back(a);
+ }
+ EXPECT_EQ(res, (std::vector{0, 1, 2, 0, 1, 2}));
+ }
+
+ TEST(FuncTools, Combo) {
+ FOR_DISPATCH_2(i, j, Enumerate(xrange(10u))) {
+ EXPECT_EQ(i, j);
+ }
+
+ FOR_DISPATCH_2(i, jk, Enumerate(Enumerate(xrange(10u)))) {
+ EXPECT_EQ(i, std::get<0>(jk));
+ EXPECT_EQ(std::get<0>(jk), std::get<1>(jk));
+ }
+
+ TVector<size_t> a = {0, 1, 2};
+ FOR_DISPATCH_2(i, j, Enumerate(Reversed(a))) {
+ EXPECT_EQ(i, 2 - j);
+ }
+
+ FOR_DISPATCH_2(i, j, Enumerate(Map<float>(a))) {
+ EXPECT_EQ(i, (size_t)j);
+ }
+
+ FOR_DISPATCH_2(i, j, Zip(a, Map<float>(a))) {
+ EXPECT_EQ(i, (size_t)j);
+ }
+
+ auto mapper = [](auto&& x) {
+ return std::get<0>(x) + std::get<1>(x);
+ };
+ FOR_DISPATCH_2(i, j, Zip(a, Map(mapper, Zip(a, a)))) {
+ EXPECT_EQ(j, 2 * i);
+ }
+ }
+
+
+ TEST(FuncTools, CopyIterator) {
+ TVector a = {1, 2, 3, 4};
+ TVector b = {4, 5, 6, 7};
+
+ // calls f on 2nd, 3d and 4th positions (numeration from 1st)
+ auto testIterator = [](auto it, auto f) {
+ ++it;
+ auto it2 = it;
+ ++it2;
+ ++it2;
+ auto it3 = it;
+ ++it3;
+ f(*it, *it3, *it2);
+ };
+
+ {
+ auto iterable = Enumerate(a);
+ testIterator(std::begin(iterable),
+ [](auto p2, auto p3, auto p4) {
+ EXPECT_EQ(std::get<0>(p2), 1u);
+ EXPECT_EQ(std::get<1>(p2), 2);
+ EXPECT_EQ(std::get<0>(p3), 2u);
+ EXPECT_EQ(std::get<1>(p3), 3);
+ EXPECT_EQ(std::get<0>(p4), 3u);
+ EXPECT_EQ(std::get<1>(p4), 4);
+ });
+ }
+
+ {
+ auto iterable = Map([](i32 x) { return x*x; }, a);
+ testIterator(std::begin(iterable),
+ [](auto p2, auto p3, auto p4) {
+ EXPECT_EQ(p2, 4);
+ EXPECT_EQ(p3, 9);
+ EXPECT_EQ(p4, 16);
+ });
+ }
+
+ {
+ auto iterable = Zip(a, b);
+ testIterator(std::begin(iterable),
+ [](auto p2, auto p3, auto p4) {
+ EXPECT_EQ(std::get<0>(p2), 2);
+ EXPECT_EQ(std::get<1>(p2), 5);
+ EXPECT_EQ(std::get<0>(p3), 3);
+ EXPECT_EQ(std::get<1>(p3), 6);
+ EXPECT_EQ(std::get<0>(p4), 4);
+ EXPECT_EQ(std::get<1>(p4), 7);
+ });
+ }
+
+ {
+ auto c = {1, 2, 3, 4, 5, 6, 7, 8};
+ auto iterable = Filter([](i32 x) { return !(x & 1); }, c);
+ testIterator(std::begin(iterable),
+ [](auto p2, auto p3, auto p4) {
+ EXPECT_EQ(p2, 4);
+ EXPECT_EQ(p3, 6);
+ EXPECT_EQ(p4, 8);
+ });
+ }
+
+ {
+ auto iterable = CartesianProduct(TVector{0, 1}, TVector{2, 3});
+ // (0, 2), (0, 3), (1, 2), (1, 3)
+ testIterator(std::begin(iterable),
+ [](auto p2, auto p3, auto p4) {
+ EXPECT_EQ(std::get<0>(p2), 0);
+ EXPECT_EQ(std::get<1>(p2), 3);
+ EXPECT_EQ(std::get<0>(p3), 1);
+ EXPECT_EQ(std::get<1>(p3), 2);
+ EXPECT_EQ(std::get<0>(p4), 1);
+ EXPECT_EQ(std::get<1>(p4), 3);
+ });
+ }
+ }
diff --git a/library/cpp/iterator/ut/iterate_keys_ut.cpp b/library/cpp/iterator/ut/iterate_keys_ut.cpp
new file mode 100644
index 0000000000..49eb866b6e
--- /dev/null
+++ b/library/cpp/iterator/ut/iterate_keys_ut.cpp
@@ -0,0 +1,37 @@
+#include <library/cpp/iterator/iterate_keys.h>
+
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <map>
+
+using namespace testing;
+
+TEST(IterateKeys, ConstMappingIteration) {
+ const std::map<int, int> squares{
+ {1, 1},
+ {2, 4},
+ {3, 9},
+ };
+ EXPECT_THAT(
+ IterateKeys(squares),
+ ElementsAre(1, 2, 3)
+ );
+}
+
+TEST(IterateKeys, ConstMultiMappingIteration) {
+ const std::multimap<int, int> primesBelow{
+ {2, 2},
+ {5, 3},
+ {5, 5},
+ {11, 7},
+ {11, 11},
+ {23, 13},
+ {23, 17},
+ {23, 23},
+ };
+
+ EXPECT_THAT(
+ IterateKeys(primesBelow),
+ ElementsAre(2, 5, 5, 11, 11, 23, 23, 23)
+ );
+}
diff --git a/library/cpp/iterator/ut/iterate_values_ut.cpp b/library/cpp/iterator/ut/iterate_values_ut.cpp
new file mode 100644
index 0000000000..ed099e560d
--- /dev/null
+++ b/library/cpp/iterator/ut/iterate_values_ut.cpp
@@ -0,0 +1,106 @@
+#include <library/cpp/iterator/iterate_values.h>
+
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <util/generic/algorithm.h>
+
+#include <map>
+#include <unordered_map>
+
+using namespace testing;
+
+TEST(IterateValues, ConstMappingIteration) {
+ const std::map<int, int> squares{
+ {1, 1},
+ {2, 4},
+ {3, 9},
+ };
+ EXPECT_THAT(
+ IterateValues(squares),
+ ElementsAre(1, 4, 9)
+ );
+
+ const std::unordered_map<int, int> roots{
+ {49, 7},
+ {36, 6},
+ {25, 5},
+ };
+ EXPECT_THAT(
+ IterateValues(roots),
+ UnorderedElementsAre(5, 6, 7)
+ );
+
+ const std::map<int, std::string> translations{
+ {1, "one"},
+ {2, "two"},
+ {3, "three"},
+ };
+ EXPECT_EQ(
+ Accumulate(IterateValues(translations), std::string{}),
+ "onetwothree"
+ );
+}
+
+TEST(IterateValues, NonConstMappingIteration) {
+ std::map<int, int> squares{
+ {1, 1},
+ {2, 4},
+ {3, 9},
+ };
+ for (auto& value: IterateValues(squares)) {
+ value *= value;
+ }
+ EXPECT_THAT(
+ IterateValues(squares),
+ ElementsAre(1, 16, 81)
+ );
+}
+
+TEST(IterateValues, ConstMultiMappingIteration) {
+ const std::multimap<int, int> primesBelow{
+ {2, 2},
+ {5, 3},
+ {5, 5},
+ {11, 7},
+ {11, 11},
+ {23, 13},
+ {23, 17},
+ {23, 23},
+ };
+
+ EXPECT_THAT(
+ IterateValues(primesBelow),
+ ElementsAre(2, 3, 5, 7, 11, 13, 17, 23)
+ );
+ auto [begin, end] = primesBelow.equal_range(11);
+ EXPECT_EQ(std::distance(begin, end), 2);
+ EXPECT_THAT(
+ IterateValues(std::vector(begin, end)),
+ ElementsAre(7, 11)
+ );
+}
+
+TEST(IterateValues, ConstUnorderedMultiMappingIteration) {
+ const std::unordered_multimap<int, int> primesBelow{
+ {2, 2},
+ {5, 3},
+ {5, 5},
+ {11, 7},
+ {11, 11},
+ {23, 13},
+ {23, 17},
+ {23, 23},
+ };
+
+ EXPECT_THAT(
+ IterateValues(primesBelow),
+ UnorderedElementsAre(2, 3, 5, 7, 11, 13, 17, 23)
+ );
+
+ auto [begin, end] = primesBelow.equal_range(11);
+ EXPECT_EQ(std::distance(begin, end), 2);
+ EXPECT_THAT(
+ IterateValues(std::vector(begin, end)),
+ UnorderedElementsAre(7, 11)
+ );
+}
diff --git a/library/cpp/iterator/ut/mapped_ut.cpp b/library/cpp/iterator/ut/mapped_ut.cpp
new file mode 100644
index 0000000000..440cd37945
--- /dev/null
+++ b/library/cpp/iterator/ut/mapped_ut.cpp
@@ -0,0 +1,61 @@
+#include <library/cpp/iterator/mapped.h>
+
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <util/generic/map.h>
+#include <util/generic/vector.h>
+
+using namespace testing;
+
+TEST(TIterator, TMappedIteratorTest) {
+ TVector<int> x = {1, 2, 3, 4, 5};
+ auto it = MakeMappedIterator(x.begin(), [](int x) { return x + 7; });
+
+ EXPECT_EQ(*it, 8);
+ EXPECT_EQ(it[2], 10);
+}
+
+TEST(TIterator, TMappedRangeTest) {
+ TVector<int> x = {1, 2, 3, 4, 5};
+
+ EXPECT_THAT(
+ MakeMappedRange(
+ x,
+ [](int x) { return x + 3; }
+ ),
+ ElementsAre(4, 5, 6, 7, 8)
+ );
+}
+
+//TODO: replace with dedicated IterateKeys / IterateValues methods
+TEST(TIterator, TMutableMappedRangeTest) {
+ TMap<int, int> points = {{1, 2}, {3, 4}};
+
+ EXPECT_THAT(
+ MakeMappedRange(
+ points.begin(), points.end(),
+ [](TMap<int, int>::value_type& kv) -> int& { return kv.second; }
+ ),
+ ElementsAre(2, 4)
+ );
+}
+
+TEST(TIterator, TOwningMappedMethodTest) {
+ auto range = MakeMappedRange(
+ TVector<std::pair<int, int>>{std::make_pair(1, 2), std::make_pair(3, 4)},
+ [](auto& point) -> int& {
+ return point.first;
+ }
+ );
+ EXPECT_EQ(range[0], 1);
+ range[0] += 1;
+ EXPECT_EQ(range[0], 2);
+ (*range.begin()) += 1;
+ EXPECT_EQ(range[0], 3);
+ for (int& y : range) {
+ y += 7;
+ }
+
+ EXPECT_EQ(*range.begin(), 10);
+ EXPECT_EQ(*(range.begin() + 1), 10);
+}
diff --git a/library/cpp/iterator/ut/ya.make b/library/cpp/iterator/ut/ya.make
new file mode 100644
index 0000000000..601e5663b9
--- /dev/null
+++ b/library/cpp/iterator/ut/ya.make
@@ -0,0 +1,18 @@
+GTEST()
+
+PEERDIR(
+ library/cpp/iterator
+)
+
+OWNER(g:util)
+
+SRCS(
+ filtering_ut.cpp
+ functools_ut.cpp
+ iterate_keys_ut.cpp
+ iterate_values_ut.cpp
+ mapped_ut.cpp
+ zip_ut.cpp
+)
+
+END()
diff --git a/library/cpp/iterator/ut/zip_ut.cpp b/library/cpp/iterator/ut/zip_ut.cpp
new file mode 100644
index 0000000000..68d496515c
--- /dev/null
+++ b/library/cpp/iterator/ut/zip_ut.cpp
@@ -0,0 +1,28 @@
+#include <library/cpp/iterator/zip.h>
+
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <util/generic/vector.h>
+
+TEST(TIterator, ZipSimplePostIncrement) {
+ TVector<int> left{1, 2, 3};
+ TVector<int> right{4, 5, 6};
+
+ auto zipped = Zip(left, right);
+ auto cur = zipped.begin();
+ auto last = zipped.end();
+
+ {
+ auto first = *(cur++);
+ EXPECT_EQ(std::get<0>(first), 1);
+ EXPECT_EQ(std::get<1>(first), 4);
+ }
+ {
+ auto second = *(cur++);
+ EXPECT_EQ(std::get<0>(second), 2);
+ EXPECT_EQ(std::get<1>(second), 5);
+ }
+
+ EXPECT_EQ(std::next(cur), last);
+}
+
diff --git a/library/cpp/iterator/ya.make b/library/cpp/iterator/ya.make
new file mode 100644
index 0000000000..1ba1ffb411
--- /dev/null
+++ b/library/cpp/iterator/ya.make
@@ -0,0 +1,19 @@
+OWNER(g:util)
+
+LIBRARY()
+
+SRCS(
+ cartesian_product.cpp
+ concatenate.cpp
+ enumerate.cpp
+ iterate_keys.cpp
+ iterate_values.cpp
+ filtering.cpp
+ functools.cpp
+ mapped.cpp
+ zip.cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/iterator/zip.cpp b/library/cpp/iterator/zip.cpp
new file mode 100644
index 0000000000..36338ea527
--- /dev/null
+++ b/library/cpp/iterator/zip.cpp
@@ -0,0 +1 @@
+#include "zip.h"
diff --git a/library/cpp/iterator/zip.h b/library/cpp/iterator/zip.h
new file mode 100644
index 0000000000..ac12ed35fe
--- /dev/null
+++ b/library/cpp/iterator/zip.h
@@ -0,0 +1,128 @@
+#pragma once
+
+#include <util/generic/store_policy.h>
+
+#include <algorithm>
+#include <tuple>
+
+
+namespace NPrivate {
+
+ template <typename TContainer, typename TIteratorCategory = typename std::iterator_traits<decltype(std::begin(std::declval<TContainer>()))>::iterator_category>
+ static constexpr bool HasRandomAccessIterator(int32_t) {
+ return std::is_same_v<TIteratorCategory, std::random_access_iterator_tag>;
+ }
+
+ template <typename TContainer>
+ static constexpr bool HasRandomAccessIterator(uint32_t) {
+ return false;
+ }
+
+ template <typename... TContainers>
+ struct TZipper {
+ template <std::size_t... I>
+ struct TZipperWithIndex {
+ private:
+ using THolders = std::tuple<TAutoEmbedOrPtrPolicy<TContainers>...>;
+ using TValue = std::tuple<decltype(*std::begin(std::declval<TContainers&>()))...>;
+ using TIteratorState = std::tuple<decltype(std::begin(std::declval<TContainers&>()))...>;
+ using TSentinelState = std::tuple<decltype(std::end(std::declval<TContainers&>()))...>;
+
+ static constexpr bool TrivialSentinel = std::is_same_v<TIteratorState, TSentinelState>;
+
+ struct TIterator;
+ struct TSentinelCandidate {
+ TSentinelState Iterators_;
+ };
+ using TSentinel = std::conditional_t<TrivialSentinel, TIterator, TSentinelCandidate>;
+
+#ifndef _MSC_VER
+ // windows compiler crashes here
+ static constexpr bool LimitByFirstContainer = TrivialSentinel &&
+ ((HasRandomAccessIterator<TContainers>(0)) && ...);
+#else
+ static constexpr bool LimitByFirstContainer = false;
+#endif
+
+ struct TIterator {
+ using difference_type = std::ptrdiff_t;
+ using value_type = TValue;
+ using pointer = TValue*;
+ using reference = TValue&;
+ using const_reference = const TValue&;
+ using iterator_category = std::input_iterator_tag;
+
+ TValue operator*() {
+ return {*std::get<I>(Iterators_)...};
+ }
+ TValue operator*() const {
+ return {*std::get<I>(Iterators_)...};
+ }
+
+ TIterator& operator++() {
+ (++std::get<I>(Iterators_), ...);
+ return *this;
+ }
+
+ TIterator operator++(int) {
+ return TIterator{TIteratorState{std::get<I>(Iterators_)++...}};
+ }
+
+ bool operator!=(const TSentinel& other) const {
+ if constexpr (LimitByFirstContainer) {
+ return std::get<0>(Iterators_) != std::get<0>(other.Iterators_);
+ } else {
+ // yes, for all correct iterators but end() it is a correct way to compare
+ return ((std::get<I>(Iterators_) != std::get<I>(other.Iterators_)) && ...);
+ }
+ }
+ bool operator==(const TSentinel& other) const {
+ return !(*this != other);
+ }
+
+ TIteratorState Iterators_;
+ };
+ public:
+ using iterator = TIterator;
+ using const_iterator = TIterator;
+ using value_type = typename TIterator::value_type;
+ using reference = typename TIterator::reference;
+ using const_reference = typename TIterator::const_reference;
+
+ TIterator begin() const {
+ return {TIteratorState{std::begin(*std::get<I>(Holders_).Ptr())...}};
+ }
+
+ TSentinel end() const {
+ if constexpr (LimitByFirstContainer) {
+ auto endOfFirst = std::begin(*std::get<0>(Holders_).Ptr()) + std::min({
+ std::end(*std::get<I>(Holders_).Ptr()) - std::begin(*std::get<I>(Holders_).Ptr())...});
+ TIterator iter{TSentinelState{std::end(*std::get<I>(Holders_).Ptr())...}};
+ std::get<0>(iter.Iterators_) = endOfFirst;
+ return iter;
+ } else {
+ return {TSentinelState{std::end(*std::get<I>(Holders_).Ptr())...}};
+ }
+ }
+
+ mutable THolders Holders_;
+ };
+
+ template <std::size_t... I>
+ static auto Zip(TContainers&&... containers, std::index_sequence<I...>) {
+ return TZipperWithIndex<I...>{{std::forward<TContainers>(containers)...}};
+ }
+ };
+
+}
+
+
+//! Acts as pythonic zip, BUT result length is equal to shortest length of input containers
+//! Usage: for (auto [ai, bi, ci] : Zip(a, b, c)) {...}
+template <typename... TContainers>
+auto Zip(TContainers&&... containers) {
+ return ::NPrivate::TZipper<TContainers...>::Zip(
+ std::forward<TContainers>(containers)...,
+ std::make_index_sequence<sizeof...(TContainers)>{}
+ );
+}
diff --git a/library/cpp/json/common/defs.cpp b/library/cpp/json/common/defs.cpp
new file mode 100644
index 0000000000..da86da82e4
--- /dev/null
+++ b/library/cpp/json/common/defs.cpp
@@ -0,0 +1,68 @@
+#include "defs.h"
+
+using namespace NJson;
+
+TJsonCallbacks::~TJsonCallbacks() {
+}
+
+bool TJsonCallbacks::OnNull() {
+ return true;
+}
+
+bool TJsonCallbacks::OnBoolean(bool) {
+ return true;
+}
+
+bool TJsonCallbacks::OnInteger(long long) {
+ return true;
+}
+
+bool TJsonCallbacks::OnUInteger(unsigned long long) {
+ return true;
+}
+
+bool TJsonCallbacks::OnDouble(double) {
+ return true;
+}
+
+bool TJsonCallbacks::OnString(const TStringBuf&) {
+ return true;
+}
+
+bool TJsonCallbacks::OnOpenMap() {
+ return true;
+}
+
+bool TJsonCallbacks::OnMapKey(const TStringBuf&) {
+ return true;
+}
+
+bool TJsonCallbacks::OnCloseMap() {
+ return true;
+}
+
+bool TJsonCallbacks::OnOpenArray() {
+ return true;
+}
+
+bool TJsonCallbacks::OnCloseArray() {
+ return true;
+}
+
+bool TJsonCallbacks::OnStringNoCopy(const TStringBuf& s) {
+ return OnString(s);
+}
+
+bool TJsonCallbacks::OnMapKeyNoCopy(const TStringBuf& s) {
+ return OnMapKey(s);
+}
+
+bool TJsonCallbacks::OnEnd() {
+ return true;
+}
+
+void TJsonCallbacks::OnError(size_t off, TStringBuf reason) {
+ if (ThrowException) {
+ ythrow TJsonException() << "JSON error at offset " << off << " (" << reason << ")";
+ }
+}
diff --git a/library/cpp/json/common/defs.h b/library/cpp/json/common/defs.h
new file mode 100644
index 0000000000..d3c8761bcc
--- /dev/null
+++ b/library/cpp/json/common/defs.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+#include <util/generic/yexception.h>
+
+namespace NJson {
+ class TJsonException: public yexception {
+ };
+
+ class TJsonCallbacks {
+ public:
+ explicit TJsonCallbacks(bool throwException = false)
+ : ThrowException(throwException)
+ {
+ }
+
+ virtual ~TJsonCallbacks();
+
+ virtual bool OnNull();
+ virtual bool OnBoolean(bool);
+ virtual bool OnInteger(long long);
+ virtual bool OnUInteger(unsigned long long);
+ virtual bool OnDouble(double);
+ virtual bool OnString(const TStringBuf&);
+ virtual bool OnOpenMap();
+ virtual bool OnMapKey(const TStringBuf&);
+ virtual bool OnCloseMap();
+ virtual bool OnOpenArray();
+ virtual bool OnCloseArray();
+ virtual bool OnStringNoCopy(const TStringBuf& s);
+ virtual bool OnMapKeyNoCopy(const TStringBuf& s);
+ virtual bool OnEnd();
+ virtual void OnError(size_t off, TStringBuf reason);
+
+ protected:
+ bool ThrowException;
+ };
+}
diff --git a/library/cpp/json/common/ya.make b/library/cpp/json/common/ya.make
new file mode 100644
index 0000000000..5bbd3b0792
--- /dev/null
+++ b/library/cpp/json/common/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(pg)
+
+SRCS(
+ defs.cpp
+)
+
+END()
diff --git a/library/cpp/json/domscheme_traits.h b/library/cpp/json/domscheme_traits.h
new file mode 100644
index 0000000000..a5a99cd8cf
--- /dev/null
+++ b/library/cpp/json/domscheme_traits.h
@@ -0,0 +1,216 @@
+#pragma once
+
+#include "json_value.h"
+#include "json_reader.h"
+#include "json_writer.h"
+#include <util/generic/algorithm.h>
+
+struct TJsonTraits {
+ using TValue = NJson::TJsonValue;
+ using TValueRef = TValue*;
+ using TConstValueRef = const TValue*;
+ using TStringType = TStringBuf;
+
+ // anyvalue defaults
+ template <class T>
+ static inline TValue Value(T&& t) {
+ return TValue(std::forward<T>(t));
+ }
+
+ template <class T>
+ static inline TValue Value(std::initializer_list<T> t) {
+ TValue result(NJson::JSON_ARRAY);
+ result.GetArraySafe() = NJson::TJsonValue::TArray(t.begin(), t.end());
+ return result;
+ }
+
+ static inline TValueRef Ref(TValue& v) {
+ return &v;
+ }
+
+ static inline TConstValueRef Ref(const TValue& v) {
+ return &v;
+ }
+
+ // common ops
+ static inline bool IsNull(TConstValueRef v) {
+ return v->GetType() == NJson::JSON_UNDEFINED || v->IsNull();
+ }
+
+ static inline TString ToJson(TConstValueRef v) {
+ return NJson::WriteJson(v, false);
+ }
+
+ // struct ops
+ static inline TValueRef GetField(TValueRef v, const TStringBuf& name) {
+ return &(*v)[name];
+ }
+
+ static inline TConstValueRef GetField(TConstValueRef v, const TStringBuf& name) {
+ return &(*v)[name];
+ }
+
+ // array ops
+ static bool IsArray(TConstValueRef v) {
+ return v->IsArray();
+ }
+
+ static inline void ArrayClear(TValueRef v) {
+ v->SetType(NJson::JSON_NULL);
+ v->SetType(NJson::JSON_ARRAY);
+ }
+
+ using TArrayIterator = size_t;
+
+ static inline TValueRef ArrayElement(TValueRef v, TArrayIterator n) {
+ return &(*v)[n];
+ }
+
+ static inline TConstValueRef ArrayElement(TConstValueRef v, TArrayIterator n) {
+ return &(*v)[n];
+ }
+
+ static inline size_t ArraySize(TConstValueRef v) {
+ return v->GetArray().size();
+ }
+
+ static inline TArrayIterator ArrayBegin(TConstValueRef) {
+ return 0;
+ }
+
+ static inline TArrayIterator ArrayEnd(TConstValueRef v) {
+ return ArraySize(v);
+ }
+
+ // dict ops
+ static bool IsDict(TConstValueRef v) {
+ return v->IsMap();
+ }
+
+ static inline void DictClear(TValueRef v) {
+ v->SetType(NJson::JSON_NULL);
+ v->SetType(NJson::JSON_MAP);
+ }
+
+ static inline TValueRef DictElement(TValueRef v, TStringBuf key) {
+ return &(*v)[key];
+ }
+
+ static inline TConstValueRef DictElement(TConstValueRef v, TStringBuf key) {
+ return &(*v)[key];
+ }
+
+ static inline size_t DictSize(TConstValueRef v) {
+ return v->GetMap().size();
+ }
+
+ using TDictIterator = NJson::TJsonValue::TMapType::const_iterator;
+
+ static inline TDictIterator DictBegin(TConstValueRef v) {
+ return v->GetMap().begin();
+ }
+
+ static inline TDictIterator DictEnd(TConstValueRef v) {
+ return v->GetMap().end();
+ }
+
+ static inline TStringBuf DictIteratorKey(TConstValueRef /*dict*/, const TDictIterator& it) {
+ return it->first;
+ }
+
+ static inline TConstValueRef DictIteratorValue(TConstValueRef /*dict*/, const TDictIterator& it) {
+ return &it->second;
+ }
+
+ // boolean ops
+ static inline void Get(TConstValueRef v, bool def, bool& b) {
+ b =
+ v->GetType() == NJson::JSON_UNDEFINED ? def : v->IsNull() ? def : v->GetBooleanRobust();
+ }
+
+ static inline void Get(TConstValueRef v, bool& b) {
+ Get(v, false, b);
+ }
+
+ static inline bool IsValidPrimitive(const bool&, TConstValueRef v) {
+ return v->IsBoolean();
+ }
+
+#define INTEGER_OPS(type, checkOp, getOp) \
+ static inline void Get(TConstValueRef v, type def, type& i) { \
+ i = v->checkOp() ? v->getOp() : def; \
+ } \
+ static inline void Get(TConstValueRef v, type& i) { \
+ i = v->getOp(); \
+ } \
+ static inline bool IsValidPrimitive(const type&, TConstValueRef v) { \
+ return v->checkOp() && v->getOp() >= Min<type>() && v->getOp() <= Max<type>(); \
+ }
+
+ INTEGER_OPS(i8, IsInteger, GetInteger)
+ INTEGER_OPS(i16, IsInteger, GetInteger)
+ INTEGER_OPS(i32, IsInteger, GetInteger)
+ INTEGER_OPS(i64, IsInteger, GetInteger)
+ INTEGER_OPS(ui8, IsUInteger, GetUInteger)
+ INTEGER_OPS(ui16, IsUInteger, GetUInteger)
+ INTEGER_OPS(ui32, IsUInteger, GetUInteger)
+ INTEGER_OPS(ui64, IsUInteger, GetUInteger)
+
+#undef INTEGER_OPS
+
+ // double ops
+ static inline bool Get(TConstValueRef v, double def, double& d) {
+ if (v->IsDouble()) {
+ d = v->GetDouble();
+ return true;
+ }
+ d = def;
+ return false;
+ }
+
+ static inline void Get(TConstValueRef v, double& d) {
+ d = v->GetDouble();
+ }
+
+ static inline bool IsValidPrimitive(const double&, TConstValueRef v) {
+ return v->IsDouble();
+ }
+
+ // string ops
+ static inline void Get(TConstValueRef v, TStringBuf def, TStringBuf& s) {
+ s = v->IsString() ? v->GetString() : def;
+ }
+
+ static inline void Get(TConstValueRef v, TStringBuf& s) {
+ s = v->GetString();
+ }
+
+ static inline bool IsValidPrimitive(const TStringBuf&, TConstValueRef v) {
+ return v->IsString();
+ }
+
+ // generic set
+ template <class T>
+ static inline void Set(TValueRef v, T&& t) {
+ v->SetValue(t);
+ }
+
+ static inline void Clear(TValueRef v) {
+ v->SetType(NJson::JSON_NULL);
+ }
+
+ // validation ops
+ static inline TVector<TString> GetKeys(TConstValueRef v) {
+ TVector<TString> res;
+ for (const auto& it : v->GetMap()) {
+ res.push_back(it.first);
+ }
+ Sort(res.begin(), res.end());
+ return res;
+ }
+
+ template <typename T>
+ static inline bool IsValidPrimitive(const T&, TConstValueRef) {
+ return false;
+ }
+};
diff --git a/library/cpp/json/easy_parse/json_easy_parser.cpp b/library/cpp/json/easy_parse/json_easy_parser.cpp
new file mode 100644
index 0000000000..3c781f544b
--- /dev/null
+++ b/library/cpp/json/easy_parse/json_easy_parser.cpp
@@ -0,0 +1,236 @@
+#include "json_easy_parser.h"
+#include <library/cpp/json/json_reader.h>
+#include <util/string/cast.h>
+#include <util/string/split.h>
+#include <util/string/strip.h>
+
+namespace NJson {
+ static TString MAP_IDENTIFIER = "{}";
+ static TString ARRAY_IDENTIFIER = "[]";
+ static TString ANY_IDENTIFIER = "*";
+
+ static void ParsePath(TString path, TVector<TPathElem>* res) {
+ TVector<const char*> parts;
+ Split(path.begin(), '/', &parts);
+ for (size_t n = 0; n < parts.size(); ++n) {
+ TString part = Strip(parts[n]);
+ if (!part.empty()) {
+ if (part[0] != '[') {
+ res->push_back(TPathElem(NImpl::MAP));
+ res->push_back(TPathElem(part));
+ } else {
+ int arrayCounter;
+ try {
+ arrayCounter = FromString<int>(part.substr(1, part.length() - 2));
+ } catch (yexception&) {
+ arrayCounter = -1;
+ }
+ res->push_back(TPathElem(arrayCounter));
+ }
+ }
+ }
+ }
+
+ void TJsonParser::AddField(const TString& path, bool nonEmpty) {
+ Fields.emplace_back();
+ Fields.back().NonEmpty = nonEmpty;
+ ParsePath(path, &Fields.back().Path);
+ }
+
+ TString TJsonParser::ConvertToTabDelimited(const TString& json) const {
+ TStringInput in(json);
+ TStringStream out;
+ ConvertToTabDelimited(in, out);
+ return out.Str();
+ }
+
+ class TRewriteJsonImpl: public NJson::TJsonCallbacks {
+ const TJsonParser& Parent;
+ TVector<TString> FieldValues;
+ TVector<TPathElem> Stack;
+ bool ShouldUpdateOnArrayChange;
+ int CurrentFieldIdx;
+ bool HasFormatError;
+
+ private:
+ static bool PathElementMatch(const TPathElem& templ, const TPathElem& real) {
+ if (templ.Type != real.Type)
+ return false;
+ if (templ.Type == NImpl::ARRAY)
+ return templ.ArrayCounter == -1 || templ.ArrayCounter == real.ArrayCounter;
+ if (templ.Type == NImpl::MAP_KEY)
+ return templ.Key == ANY_IDENTIFIER || templ.Key == real.Key;
+ return true;
+ }
+
+ bool CheckFilter(const TVector<TPathElem>& path) const {
+ if (Stack.size() < path.size())
+ return false;
+ for (size_t n = 0; n < path.size(); ++n) {
+ if (!PathElementMatch(path[n], Stack[n]))
+ return false;
+ }
+ return true;
+ }
+
+ void UpdateRule() {
+ for (size_t n = 0; n < Parent.Fields.size(); ++n) {
+ if (FieldValues[n].empty() && CheckFilter(Parent.Fields[n].Path)) {
+ CurrentFieldIdx = n;
+ return;
+ }
+ }
+ CurrentFieldIdx = -1;
+ }
+
+ void Pop() {
+ Stack.pop_back();
+ }
+
+ void IncreaseArrayCounter() {
+ if (!Stack.empty() && Stack.back().Type == NImpl::ARRAY) {
+ ++Stack.back().ArrayCounter;
+ if (ShouldUpdateOnArrayChange)
+ UpdateRule();
+ }
+ }
+
+ template <class T>
+ bool OnValue(const T& val) {
+ IncreaseArrayCounter();
+ if (CurrentFieldIdx >= 0) {
+ FieldValues[CurrentFieldIdx] = ToString(val);
+ UpdateRule();
+ }
+ return true;
+ }
+
+ public:
+ TRewriteJsonImpl(const TJsonParser& parent)
+ : Parent(parent)
+ , FieldValues(parent.Fields.size())
+ , ShouldUpdateOnArrayChange(false)
+ , CurrentFieldIdx(-1)
+ , HasFormatError(false)
+ {
+ for (size_t n = 0; n < Parent.Fields.size(); ++n) {
+ if (!Parent.Fields[n].Path.empty() && Parent.Fields[n].Path.back().Type == NImpl::ARRAY)
+ ShouldUpdateOnArrayChange = true;
+ }
+ }
+
+ bool OnOpenMap() override {
+ IncreaseArrayCounter();
+ Stack.push_back(TPathElem(NImpl::MAP));
+ if (CurrentFieldIdx >= 0)
+ HasFormatError = true;
+ else
+ UpdateRule();
+ return true;
+ }
+
+ bool OnOpenArray() override {
+ IncreaseArrayCounter();
+ Stack.push_back(TPathElem(-1));
+ if (CurrentFieldIdx >= 0)
+ HasFormatError = true;
+ else
+ UpdateRule();
+ return true;
+ }
+
+ bool OnCloseMap() override {
+ while (!Stack.empty() && Stack.back().Type != NImpl::MAP)
+ Pop();
+ if (!Stack.empty())
+ Pop();
+ UpdateRule();
+ return true;
+ }
+
+ bool OnCloseArray() override {
+ if (!Stack.empty())
+ Pop();
+ UpdateRule();
+ return true;
+ }
+
+ bool OnMapKey(const TStringBuf& key) override {
+ if (!Stack.empty() && Stack.back().Type == NImpl::MAP_KEY) {
+ Pop();
+ UpdateRule();
+ }
+ Stack.push_back(TPathElem(TString{key}));
+ if (CurrentFieldIdx >= 0)
+ HasFormatError = true;
+ else
+ UpdateRule();
+ return true;
+ }
+
+ bool OnBoolean(bool b) override {
+ return OnValue(b);
+ }
+
+ bool OnInteger(long long i) override {
+ return OnValue(i);
+ }
+
+ bool OnDouble(double f) override {
+ return OnValue(f);
+ }
+
+ bool OnString(const TStringBuf& str) override {
+ return OnValue(str);
+ }
+
+ bool IsOK() const {
+ if (HasFormatError)
+ return false;
+ for (size_t n = 0; n < FieldValues.size(); ++n)
+ if (Parent.Fields[n].NonEmpty && FieldValues[n].empty())
+ return false;
+ return true;
+ }
+
+ void WriteTo(IOutputStream& out) const {
+ for (size_t n = 0; n < FieldValues.size(); ++n)
+ out << "\t" << FieldValues[n];
+ }
+
+ void WriteTo(TVector<TString>* res) const {
+ *res = FieldValues;
+ }
+ };
+
+ void TJsonParser::ConvertToTabDelimited(IInputStream& in, IOutputStream& out) const {
+ TRewriteJsonImpl impl(*this);
+ ReadJson(&in, &impl);
+ if (impl.IsOK()) {
+ out << Prefix;
+ impl.WriteTo(out);
+ out.Flush();
+ }
+ }
+
+ bool TJsonParser::Parse(const TString& json, TVector<TString>* res) const {
+ TRewriteJsonImpl impl(*this);
+ TStringInput in(json);
+ ReadJson(&in, &impl);
+ if (impl.IsOK()) {
+ impl.WriteTo(res);
+ return true;
+ } else
+ return false;
+ }
+
+ //struct TTestMe {
+ // TTestMe() {
+ // TJsonParser worker;
+ // worker.AddField("/x/y/z", true);
+ // TString ret1 = worker.ConvertToTabDelimited("{ \"x\" : { \"y\" : { \"w\" : 1, \"z\" : 2 } } }");
+ // TString ret2 = worker.ConvertToTabDelimited(" [1, 2, 3, 4, 5] ");
+ // }
+ //} testMe;
+
+}
diff --git a/library/cpp/json/easy_parse/json_easy_parser.h b/library/cpp/json/easy_parse/json_easy_parser.h
new file mode 100644
index 0000000000..59d7791ab1
--- /dev/null
+++ b/library/cpp/json/easy_parse/json_easy_parser.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/stream/input.h>
+#include <util/stream/output.h>
+#include "json_easy_parser_impl.h"
+
+namespace NJson {
+ /* This class filters out nodes from a source JSON by a xpath-style description. It represent these nodes as a tab-delimited string (or a vector).
+ * It is useful if you need to parse a data which comes into JSON in a known and fixed format.
+ * Fields are set as a list of keys separated by slash, for example:
+ * Field x/y/z in JSON { "x" : { "y" : { "w" : 1, "z" : 2 } } contains number 2.
+ * In a path to a field you can also provide a special array identifier "[]", identifier of a particular field in an array (for example "[4]") or wildcard "*".
+ *
+ * The parser of the class supports parsing of several fields. Each of them could be marked as mandatory or as optional.
+ * If a mandatory field is not found in JSON, then Parse() returns false and ConvertToTabDelimited() returns an empty string.
+ * If an optional field is not found in JSON, then it's value in Parse()/ConvertToTabDelimited() is an empty string.
+ * In particular ConvertToTabDelimited() always returns either an empty string, or a string of the same number of tab-delimited fields starting from the same Prefix.
+ *
+ * NB! Library can not extract values of not a simple type (namely it doesn't support the case when a result is a vocabulary or an array) from JSON.
+ * If you expect such a case, please check json_value.h.
+ */
+
+ class TJsonParser {
+ TString Prefix;
+
+ struct TField {
+ TVector<TPathElem> Path;
+ bool NonEmpty;
+ };
+ TVector<TField> Fields;
+
+ friend class TRewriteJsonImpl;
+
+ void ConvertToTabDelimited(IInputStream& in, IOutputStream& out) const;
+
+ public:
+ void SetPrefix(const TString& prefix) {
+ Prefix = prefix;
+ }
+ void AddField(const TString& path, bool mustExist);
+ TString ConvertToTabDelimited(const TString& json) const;
+ bool Parse(const TString& json, TVector<TString>* res) const;
+ };
+}
diff --git a/library/cpp/json/easy_parse/json_easy_parser_impl.h b/library/cpp/json/easy_parse/json_easy_parser_impl.h
new file mode 100644
index 0000000000..ec55d838b3
--- /dev/null
+++ b/library/cpp/json/easy_parse/json_easy_parser_impl.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <util/generic/string.h>
+
+namespace NJson {
+ namespace NImpl {
+ enum EType {
+ ARRAY,
+ MAP,
+ MAP_KEY
+ };
+ }
+ template <class TStringType>
+ struct TPathElemImpl {
+ NImpl::EType Type;
+ TStringType Key;
+ int ArrayCounter;
+
+ TPathElemImpl(NImpl::EType type)
+ : Type(type)
+ , ArrayCounter()
+ {
+ }
+
+ TPathElemImpl(const TStringType& key)
+ : Type(NImpl::MAP_KEY)
+ , Key(key)
+ , ArrayCounter()
+ {
+ }
+
+ TPathElemImpl(int arrayCounter)
+ : Type(NImpl::ARRAY)
+ , ArrayCounter(arrayCounter)
+ {
+ }
+ };
+
+ typedef TPathElemImpl<TString> TPathElem;
+}
diff --git a/library/cpp/json/easy_parse/ya.make b/library/cpp/json/easy_parse/ya.make
new file mode 100644
index 0000000000..2304c542f2
--- /dev/null
+++ b/library/cpp/json/easy_parse/ya.make
@@ -0,0 +1,13 @@
+OWNER(finder)
+
+LIBRARY()
+
+SRCS(
+ json_easy_parser.cpp
+)
+
+PEERDIR(
+ library/cpp/json
+)
+
+END()
diff --git a/library/cpp/json/fast_sax/parser.h b/library/cpp/json/fast_sax/parser.h
new file mode 100644
index 0000000000..b5f031dd9e
--- /dev/null
+++ b/library/cpp/json/fast_sax/parser.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <library/cpp/json/common/defs.h>
+
+namespace NJson {
+ bool ReadJsonFast(TStringBuf in, TJsonCallbacks* callbacks);
+
+ inline bool ValidateJsonFast(TStringBuf in, bool throwOnError = false) {
+ Y_ASSERT(false); // this method is broken, see details in IGNIETFERRO-1243. Use NJson::ValidateJson instead, or fix this one before using
+ TJsonCallbacks c(throwOnError);
+ return ReadJsonFast(in, &c);
+ }
+}
diff --git a/library/cpp/json/fast_sax/parser.rl6 b/library/cpp/json/fast_sax/parser.rl6
new file mode 100644
index 0000000000..edb4e9ee1b
--- /dev/null
+++ b/library/cpp/json/fast_sax/parser.rl6
@@ -0,0 +1,314 @@
+#include <library/cpp/json/fast_sax/unescape.h>
+#include <library/cpp/json/fast_sax/parser.h>
+
+#include <util/string/cast.h>
+#include <util/generic/buffer.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/ymath.h>
+
+namespace NJson {
+
+enum EStoredStr {
+ SS_NONE = 0, SS_NOCOPY, SS_MUSTCOPY
+};
+
+struct TParserCtx {
+ TJsonCallbacks& Hndl;
+
+ TBuffer Buffer;
+ TStringBuf String;
+ EStoredStr Stored = SS_NONE;
+ bool ExpectValue = true;
+
+ const char* p0 = nullptr;
+ const char* p = nullptr;
+ const char* pe = nullptr;
+ const char* eof = nullptr;
+ const char* ts = nullptr;
+ const char* te = nullptr;
+ int cs = 0;
+ int act = 0;
+
+ TParserCtx(TJsonCallbacks& h, TStringBuf data)
+ : Hndl(h)
+ , p0(data.data())
+ , p(data.data())
+ , pe(data.end())
+ , eof(data.end())
+ {}
+
+ static inline bool GoodPtrs(const char* b, const char* e) {
+ return b && e && b <= e;
+ }
+
+ bool OnError(TStringBuf reason = TStringBuf(""), bool end = false) const {
+ size_t off = 0;
+ TStringBuf token;
+
+ if (GoodPtrs(p0, ts)) {
+ off = ts - p0;
+ } else if (end && GoodPtrs(p0, pe)) {
+ off = pe - p0;
+ }
+
+ if (GoodPtrs(ts, te)) {
+ token = TStringBuf(ts, te);
+ }
+
+ if (!token) {
+ Hndl.OnError(off, reason);
+ } else {
+ Hndl.OnError(off, TString::Join(reason, " at token: '", token, "'"));
+ }
+
+ return false;
+ }
+
+ bool OnVal() {
+ if (Y_UNLIKELY(!ExpectValue)) {
+ return false;
+ }
+ ExpectValue = false;
+ return true;
+ }
+
+ bool OnNull() {
+ return Y_LIKELY(OnVal())
+ && Hndl.OnNull();
+ }
+
+ bool OnTrue() {
+ return Y_LIKELY(OnVal())
+ && Hndl.OnBoolean(true);
+ }
+
+ bool OnFalse() {
+ return Y_LIKELY(OnVal())
+ && Hndl.OnBoolean(false);
+ }
+
+ bool OnPInt() {
+ unsigned long long res = 0;
+ return Y_LIKELY(OnVal())
+ && TryFromString<unsigned long long>(TStringBuf(ts, te), res)
+ && Hndl.OnUInteger(res);
+ }
+
+ bool OnNInt() {
+ long long res = 0;
+ return Y_LIKELY(OnVal())
+ && TryFromString<long long>(TStringBuf(ts, te), res)
+ && Hndl.OnInteger(res);
+ }
+
+ bool OnFlt() {
+ double res = 0;
+ return Y_LIKELY(OnVal())
+ && TryFromString<double>(TStringBuf(ts, te), res)
+ && IsFinite(res)
+ && Hndl.OnDouble(res);
+ }
+
+ bool OnMapOpen() {
+ bool res = Y_LIKELY(OnVal())
+ && Hndl.OnOpenMap();
+ ExpectValue = true;
+ return res;
+ }
+
+ bool OnArrOpen() {
+ bool res = Y_LIKELY(OnVal())
+ && Hndl.OnOpenArray();
+ ExpectValue = true;
+ return res;
+ }
+
+ bool OnString(TStringBuf s, EStoredStr t) {
+ if (Y_LIKELY(OnVal())) {
+ String = s;
+ Stored = t;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ bool OnStrU() {
+ return OnString(TStringBuf(ts, te), SS_NOCOPY);
+ }
+
+ bool OnStrQ() {
+ return OnString(TStringBuf(ts + 1, te - 1), SS_NOCOPY);
+ }
+
+ bool OnStrE() {
+ Buffer.Clear();
+ Buffer.Reserve(2 * (te - ts));
+
+ return OnString(UnescapeJsonUnicode(TStringBuf(ts + 1, te - ts - 2), Buffer.data()), SS_MUSTCOPY);
+ }
+
+ bool OnMapClose() {
+ ExpectValue = false;
+ return Y_LIKELY(OnAfterVal())
+ && Hndl.OnCloseMap();
+ }
+
+ bool OnArrClose() {
+ ExpectValue = false;
+ return Y_LIKELY(OnAfterVal())
+ && Hndl.OnCloseArray();
+ }
+
+ bool OnColon() {
+ if (ExpectValue) {
+ return false;
+ }
+
+ ExpectValue = true;
+ const auto stored = Stored;
+ Stored = SS_NONE;
+
+ switch (stored) {
+ default:
+ return false;
+ case SS_NOCOPY:
+ return Hndl.OnMapKeyNoCopy(String);
+ case SS_MUSTCOPY:
+ return Hndl.OnMapKey(String);
+ }
+ }
+
+ bool OnAfterVal() {
+ const auto stored = Stored;
+ Stored = SS_NONE;
+
+ switch (stored) {
+ default:
+ return true;
+ case SS_NOCOPY:
+ return Hndl.OnStringNoCopy(String);
+ case SS_MUSTCOPY:
+ return Hndl.OnString(String);
+ }
+ }
+
+ bool OnComma() {
+ if (Y_UNLIKELY(ExpectValue)) {
+ return false;
+ }
+ ExpectValue = true;
+ return OnAfterVal();
+ }
+
+ bool Parse();
+};
+
+#if 0
+%%{
+machine fastjson;
+
+alphtype char;
+
+action OnNull { if (Y_UNLIKELY(!OnNull())) goto TOKEN_ERROR; }
+action OnTrue { if (Y_UNLIKELY(!OnTrue())) goto TOKEN_ERROR; }
+action OnFalse { if (Y_UNLIKELY(!OnFalse())) goto TOKEN_ERROR; }
+action OnPInt { if (Y_UNLIKELY(!OnPInt())) goto TOKEN_ERROR; }
+action OnNInt { if (Y_UNLIKELY(!OnNInt())) goto TOKEN_ERROR; }
+action OnFlt { if (Y_UNLIKELY(!OnFlt())) goto TOKEN_ERROR; }
+action OnStrU { if (Y_UNLIKELY(!OnStrU())) goto TOKEN_ERROR; }
+action OnStrQ { if (Y_UNLIKELY(!OnStrQ())) goto TOKEN_ERROR; }
+action OnStrE { if (Y_UNLIKELY(!OnStrE())) goto TOKEN_ERROR; }
+action OnDictO { if (Y_UNLIKELY(!OnMapOpen())) goto TOKEN_ERROR; }
+action OnDictC { if (Y_UNLIKELY(!OnMapClose())) goto TOKEN_ERROR; }
+action OnArrO { if (Y_UNLIKELY(!OnArrOpen())) goto TOKEN_ERROR; }
+action OnArrC { if (Y_UNLIKELY(!OnArrClose())) goto TOKEN_ERROR; }
+action OnComma { if (Y_UNLIKELY(!OnComma())) goto TOKEN_ERROR; }
+action OnColon { if (Y_UNLIKELY(!OnColon())) goto TOKEN_ERROR; }
+action OnError { goto TOKEN_ERROR; }
+
+comment1 = "/*" (any* -- "*/") "*/";
+
+pint = [0-9]+;
+nint = '-'[0-9]+;
+flt = '-'?[0-9.][0-9.eE+\-]+;
+
+uchar0 = [a-zA-Z_@$] | (0x80 .. 0xFF);
+uchar = uchar0 | digit | [.\-];
+
+qchar = [^'\\]; #';
+dchar = [^"\\]; #";
+
+echar = "\\" any;
+
+qechar = qchar | echar;
+dechar = dchar | echar;
+
+strq = "'" qchar* "'";
+strd = '"' dchar* '"';
+
+strqe = "'" qechar* "'";
+strde = '"' dechar* '"';
+
+strU = uchar0 uchar*;
+strQ = strq | strd;
+strE = strqe | strde;
+
+ws = (0x00 .. 0x20) | 0x7F;
+sp = ws+;
+
+main := |*
+ 'null' => OnNull;
+ 'true' => OnTrue;
+ 'false' => OnFalse;
+
+ pint => OnPInt;
+ nint => OnNInt;
+ flt => OnFlt;
+
+ strU => OnStrU;
+ strQ => OnStrQ;
+ strE => OnStrE;
+
+ ',' => OnComma;
+ ':' => OnColon;
+
+ '{' => OnDictO;
+ '}' => OnDictC;
+ '[' => OnArrO;
+ ']' => OnArrC;
+
+ sp;
+ comment1;
+
+ (flt | pint | nint) (any - (ws | ',' | ':' | '{' | '}' | '[' | ']')) => OnError;
+
+ any => OnError;
+ *|;
+}%%
+#endif
+
+bool TParserCtx::Parse() {
+ try {
+ %%{
+ write data noerror nofinal;
+ write init;
+ write exec;
+ }%%
+ ;
+ Y_UNUSED(fastjson_en_main);
+ } catch (const TFromStringException& e) {
+ return OnError(e.what());
+ }
+
+ return OnAfterVal() && Hndl.OnEnd() || OnError("invalid or truncated", true);
+
+ TOKEN_ERROR:
+ return OnError("invalid syntax");
+}
+
+bool ReadJsonFast(TStringBuf data, TJsonCallbacks* h) {
+ return TParserCtx(*h, data).Parse();
+}
+
+}
diff --git a/library/cpp/json/fast_sax/unescape.cpp b/library/cpp/json/fast_sax/unescape.cpp
new file mode 100644
index 0000000000..72109b0b5e
--- /dev/null
+++ b/library/cpp/json/fast_sax/unescape.cpp
@@ -0,0 +1,7 @@
+#include "unescape.h"
+
+#include <util/string/escape.h>
+
+TStringBuf UnescapeJsonUnicode(TStringBuf data, char* scratch) {
+ return TStringBuf(scratch, UnescapeC(data.data(), data.size(), scratch));
+}
diff --git a/library/cpp/json/fast_sax/unescape.h b/library/cpp/json/fast_sax/unescape.h
new file mode 100644
index 0000000000..5e40e1e866
--- /dev/null
+++ b/library/cpp/json/fast_sax/unescape.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+TStringBuf UnescapeJsonUnicode(TStringBuf data, char* scratch);
diff --git a/library/cpp/json/fast_sax/ya.make b/library/cpp/json/fast_sax/ya.make
new file mode 100644
index 0000000000..c6447ab6ac
--- /dev/null
+++ b/library/cpp/json/fast_sax/ya.make
@@ -0,0 +1,17 @@
+LIBRARY()
+
+OWNER(
+ pg
+ velavokr
+)
+
+PEERDIR(
+ library/cpp/json/common
+)
+
+SRCS(
+ parser.rl6
+ unescape.cpp
+)
+
+END()
diff --git a/library/cpp/json/flex_buffers/cvt.cpp b/library/cpp/json/flex_buffers/cvt.cpp
new file mode 100644
index 0000000000..fee0cea0b8
--- /dev/null
+++ b/library/cpp/json/flex_buffers/cvt.cpp
@@ -0,0 +1,139 @@
+#include "cvt.h"
+
+#include <flatbuffers/flexbuffers.h>
+
+#include <library/cpp/json/fast_sax/parser.h>
+#include <library/cpp/json/json_reader.h>
+
+#include <util/generic/vector.h>
+#include <util/stream/output.h>
+#include <util/stream/input.h>
+#include <util/memory/pool.h>
+
+using namespace NJson;
+
+namespace {
+ struct TJsonToFlexCallbacks: public TJsonCallbacks {
+ inline TJsonToFlexCallbacks()
+ : P(8192)
+ {
+ }
+
+ bool OnNull() override {
+ B.Null();
+
+ return true;
+ }
+
+ bool OnBoolean(bool v) override {
+ B.Bool(v);
+
+ return true;
+ }
+
+ bool OnInteger(long long v) override {
+ B.Int(v);
+
+ return true;
+ }
+
+ bool OnUInteger(unsigned long long v) override {
+ B.UInt(v);
+
+ return true;
+ }
+
+ bool OnDouble(double v) override {
+ B.Double(v);
+
+ return true;
+ }
+
+ bool OnString(const TStringBuf& v) override {
+ B.String(v.data(), v.size());
+
+ return true;
+ }
+
+ bool OnOpenMap() override {
+ S.push_back(B.StartMap());
+
+ return true;
+ }
+
+ bool OnMapKey(const TStringBuf& v) override {
+ auto iv = P.AppendCString(v);
+
+ B.Key(iv.data(), iv.size());
+
+ return true;
+ }
+
+ bool OnCloseMap() override {
+ B.EndMap(PopOffset());
+
+ return true;
+ }
+
+ bool OnOpenArray() override {
+ S.push_back(B.StartVector());
+
+ return true;
+ }
+
+ bool OnCloseArray() override {
+ B.EndVector(PopOffset(), false, false);
+
+ return true;
+ }
+
+ bool OnStringNoCopy(const TStringBuf& s) override {
+ return OnString(s);
+ }
+
+ bool OnMapKeyNoCopy(const TStringBuf& s) override {
+ return OnMapKey(s);
+ }
+
+ bool OnEnd() override {
+ B.Finish();
+
+ Y_ENSURE(S.empty());
+
+ return true;
+ }
+
+ void OnError(size_t, TStringBuf reason) override {
+ ythrow yexception() << reason;
+ }
+
+ inline size_t PopOffset() {
+ auto res = S.back();
+
+ S.pop_back();
+
+ return res;
+ }
+
+ inline auto& Buffer() {
+ return B.GetBuffer();
+ }
+
+ flexbuffers::Builder B;
+ TVector<size_t> S;
+ TMemoryPool P;
+ };
+}
+
+void NJson::ConvertJsonToFlexBuffers(TStringBuf input, TFlexBuffersData& result) {
+ TJsonToFlexCallbacks cb;
+
+ ReadJsonFast(input, &cb);
+ result.swap(const_cast<std::vector<ui8>&>(cb.Buffer()));
+}
+
+TString NJson::FlexToString(const TFlexBuffersData& v) {
+ auto root = flexbuffers::GetRoot(v.data(), v.size());
+
+ return TString(root.ToString());
+}
diff --git a/library/cpp/json/flex_buffers/cvt.h b/library/cpp/json/flex_buffers/cvt.h
new file mode 100644
index 0000000000..82d2874268
--- /dev/null
+++ b/library/cpp/json/flex_buffers/cvt.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <util/generic/vector.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+
+namespace NJson {
+ using TFlexBuffersData = TVector<ui8>;
+
+ TString FlexToString(const TFlexBuffersData& v);
+ void ConvertJsonToFlexBuffers(TStringBuf input, TFlexBuffersData& result);
+
+ inline TFlexBuffersData ConvertJsonToFlexBuffers(TStringBuf input) {
+ TFlexBuffersData result;
+
+ ConvertJsonToFlexBuffers(input, result);
+
+ return result;
+ }
+}
diff --git a/library/cpp/json/flex_buffers/ut/cvt_ut.cpp b/library/cpp/json/flex_buffers/ut/cvt_ut.cpp
new file mode 100644
index 0000000000..9fffef4d38
--- /dev/null
+++ b/library/cpp/json/flex_buffers/ut/cvt_ut.cpp
@@ -0,0 +1,21 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/json/flex_buffers/cvt.h>
+
+using namespace NJson;
+
+static auto JSON = R"({
+ "a": {
+ "b": [1, 2, 3],
+ "c": ["x", "y", 3, "z"]
+ }
+})";
+
+static auto RES = R"({ a: { b: [ 1, 2, 3 ], c: [ "x", "y", 3, "z" ] } })";
+
+Y_UNIT_TEST_SUITE(JsonToFlex) {
+ Y_UNIT_TEST(Test1) {
+ auto buf = ConvertJsonToFlexBuffers(JSON);
+
+ UNIT_ASSERT_VALUES_EQUAL(FlexToString(buf), RES);
+ }
+}
diff --git a/library/cpp/json/flex_buffers/ut/ya.make b/library/cpp/json/flex_buffers/ut/ya.make
new file mode 100644
index 0000000000..3fdc93f88e
--- /dev/null
+++ b/library/cpp/json/flex_buffers/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/json/flex_buffers)
+
+OWNER(pg)
+
+SRCS(
+ cvt_ut.cpp
+)
+
+END()
diff --git a/library/cpp/json/flex_buffers/ya.make b/library/cpp/json/flex_buffers/ya.make
new file mode 100644
index 0000000000..3ece5e3703
--- /dev/null
+++ b/library/cpp/json/flex_buffers/ya.make
@@ -0,0 +1,16 @@
+LIBRARY()
+
+OWNER(pg)
+
+ADDINCL(contrib/libs/flatbuffers/include)
+
+PEERDIR(
+ library/cpp/json
+ contrib/libs/flatbuffers
+)
+
+SRCS(
+ cvt.cpp
+)
+
+END()
diff --git a/library/cpp/json/fuzzy_test/main.cpp b/library/cpp/json/fuzzy_test/main.cpp
new file mode 100644
index 0000000000..29a53aac14
--- /dev/null
+++ b/library/cpp/json/fuzzy_test/main.cpp
@@ -0,0 +1,30 @@
+#include <library/cpp/json/json_reader.h>
+
+#include <util/random/random.h>
+#include <util/stream/str.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const ui8* data, size_t size) {
+ const auto json = TString((const char*)data, size);
+
+ try {
+ NJson::TJsonValue value;
+ NJson::ReadJsonFastTree(json, &value, true);
+ } catch (...) {
+ //Cout << json << " -> " << CurrentExceptionMessage() << Endl;
+ }
+
+ try {
+ NJson::TJsonCallbacks cb;
+ NJson::ReadJsonFast(json, &cb);
+ } catch (...) {
+ //Cout << json << " -> " << CurrentExceptionMessage() << Endl;
+ }
+
+ try {
+ NJson::ValidateJson(json);
+ } catch (...) {
+ //Cout << json << " -> " << CurrentExceptionMessage() << Endl;
+ }
+
+ return 0;
+}
diff --git a/library/cpp/json/fuzzy_test/ya.make b/library/cpp/json/fuzzy_test/ya.make
new file mode 100644
index 0000000000..ff50bc1f62
--- /dev/null
+++ b/library/cpp/json/fuzzy_test/ya.make
@@ -0,0 +1,13 @@
+FUZZ()
+
+OWNER(pg)
+
+PEERDIR(
+ library/cpp/json
+)
+
+SRCS(
+ main.cpp
+)
+
+END()
diff --git a/library/cpp/json/json_prettifier.cpp b/library/cpp/json/json_prettifier.cpp
new file mode 100644
index 0000000000..bb16aab44e
--- /dev/null
+++ b/library/cpp/json/json_prettifier.cpp
@@ -0,0 +1,277 @@
+#include "json_prettifier.h"
+
+#include <util/generic/deque.h>
+#include <util/generic/algorithm.h>
+#include <util/memory/pool.h>
+#include <util/string/util.h>
+
+#include <library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h>
+
+namespace NJson {
+ struct TRewritableOut {
+ IOutputStream& Slave;
+
+ char Last = 0;
+ bool Dirty = false;
+
+ TRewritableOut(IOutputStream& sl)
+ : Slave(sl)
+ {
+ }
+
+ template <typename T>
+ void Write(const T& t) {
+ Flush();
+ Slave << t;
+ }
+
+ void Hold(char c) {
+ if (Dirty)
+ Flush();
+ Last = c;
+ Dirty = true;
+ }
+
+ void Flush() {
+ if (Dirty) {
+ Slave << Last;
+ Dirty = false;
+ }
+ }
+
+ void Revert() {
+ Dirty = false;
+ }
+ };
+
+ struct TSpaces {
+ char S[256];
+
+ TSpaces() {
+ memset(&S, ' ', sizeof(S));
+ }
+
+ TStringBuf Get(ui8 sz) const {
+ return TStringBuf(S, sz);
+ }
+ };
+
+ bool TJsonPrettifier::MayUnquoteNew(TStringBuf s) {
+ static str_spn alpha("a-zA-Z_@$", true);
+ static str_spn alnum("a-zA-Z_@$0-9.-", true);
+ static TStringBuf true0("true");
+ static TStringBuf false0("false");
+ static TStringBuf null0("null");
+
+ return !!s && alpha.chars_table[(ui8)s[0]] && alnum.cbrk(s.begin() + 1, s.end()) == s.end() && !EqualToOneOf(s, null0, true0, false0);
+ }
+
+ // to keep arcadia tests happy
+ bool TJsonPrettifier::MayUnquoteOld(TStringBuf s) {
+ static str_spn alpha("a-zA-Z_@$", true);
+ static str_spn alnum("a-zA-Z_@$0-9", true);
+ static TStringBuf true0("true");
+ static TStringBuf false0("false");
+ static TStringBuf true1("on");
+ static TStringBuf false1("off");
+ static TStringBuf true2("da");
+ static TStringBuf false2("net");
+ static TStringBuf null0("null");
+
+ return !!s && alpha.chars_table[(ui8)s[0]] && alnum.cbrk(s.begin() + 1, s.end()) == s.end() && !EqualToOneOf(s, null0, true0, false0, true1, false1, true2, false2);
+ }
+
+ class TPrettifier: public TJsonCallbacks {
+ TRewritableOut Out;
+ TStringBuf Spaces;
+ TStringBuf Quote;
+ TStringBuf Unsafe;
+ TStringBuf Safe;
+
+ ui32 Level = 0;
+ ui32 MaxPaddingLevel;
+
+ bool Unquote = false;
+ bool Compactify = false;
+ bool NewUnquote = false;
+
+ public:
+ TPrettifier(IOutputStream& out, const TJsonPrettifier& p)
+ : Out(out)
+ , MaxPaddingLevel(p.MaxPaddingLevel)
+ , Unquote(p.Unquote)
+ , Compactify(p.Compactify)
+ , NewUnquote(p.NewUnquote)
+ {
+ static TSpaces spaces;
+ Spaces = spaces.Get(p.Padding);
+ if (p.SingleQuotes) {
+ Quote = Unsafe = "'";
+ Safe = "\"";
+ } else {
+ Quote = Unsafe = "\"";
+ Safe = "'";
+ }
+ }
+
+ void Pad(bool close = false) {
+ if (Compactify) {
+ Out.Flush();
+ return;
+ }
+ if (Level > MaxPaddingLevel || (Level == MaxPaddingLevel && close)) {
+ Out.Write(" ");
+ return;
+ }
+ if (Level || close) {
+ Out.Write(Spaces ? "\n" : " ");
+ }
+ for (ui32 i = 0; i < Level; ++i) {
+ Out.Write(Spaces);
+ }
+ }
+
+ void WriteSpace(char sp) {
+ if (Compactify) {
+ Out.Flush();
+ return;
+ }
+
+ Out.Write(sp);
+ }
+
+ void OnVal() {
+ if (Out.Dirty && ':' == Out.Last) {
+ WriteSpace(' ');
+ } else {
+ Pad();
+ }
+ }
+
+ void AfterVal() {
+ Out.Hold(',');
+ }
+
+ template <typename T>
+ bool WriteVal(const T& t) {
+ OnVal();
+ Out.Write(t);
+ AfterVal();
+ return true;
+ }
+
+ bool OnNull() override {
+ return WriteVal(TStringBuf("null"));
+ }
+
+ bool OnBoolean(bool v) override {
+ return WriteVal(v ? TStringBuf("true") : TStringBuf("false"));
+ }
+
+ bool OnInteger(long long i) override {
+ return WriteVal(i);
+ }
+
+ bool OnUInteger(unsigned long long i) override {
+ return WriteVal(i);
+ }
+
+ bool OnDouble(double d) override {
+ return WriteVal(d);
+ }
+
+ void WriteString(TStringBuf s) {
+ if (Unquote && (NewUnquote ? TJsonPrettifier::MayUnquoteNew(s) : TJsonPrettifier::MayUnquoteOld(s))) {
+ Out.Slave << s;
+ } else {
+ Out.Slave << Quote;
+ NEscJ::EscapeJ<false, true>(s, Out.Slave, Safe, Unsafe);
+ Out.Slave << Quote;
+ }
+ }
+
+ bool OnString(const TStringBuf& s) override {
+ OnVal();
+ WriteString(s);
+ AfterVal();
+ return true;
+ }
+
+ bool OnOpen(char c) {
+ OnVal();
+ Level++;
+ Out.Hold(c);
+ return true;
+ }
+
+ bool OnOpenMap() override {
+ return OnOpen('{');
+ }
+
+ bool OnOpenArray() override {
+ return OnOpen('[');
+ }
+
+ bool OnMapKey(const TStringBuf& k) override {
+ OnVal();
+ WriteString(k);
+ WriteSpace(' ');
+ Out.Hold(':');
+ return true;
+ }
+
+ bool OnClose(char c) {
+ if (!Level)
+ return false;
+
+ Level--;
+
+ if (Out.Dirty && c == Out.Last) {
+ WriteSpace(' ');
+ } else {
+ Out.Revert();
+ Pad(true);
+ }
+
+ return true;
+ }
+
+ bool OnCloseMap() override {
+ if (!OnClose('{'))
+ return false;
+ Out.Write("}");
+ AfterVal();
+ return true;
+ }
+
+ bool OnCloseArray() override {
+ if (!OnClose('['))
+ return false;
+ Out.Write("]");
+ AfterVal();
+ return true;
+ }
+
+ bool OnEnd() override {
+ return !Level;
+ }
+ };
+
+ bool TJsonPrettifier::Prettify(TStringBuf in, IOutputStream& out) const {
+ TPrettifier p(out, *this);
+ if (Strict) {
+ TMemoryInput mIn(in.data(), in.size());
+ return ReadJson(&mIn, &p);
+ } else {
+ return ReadJsonFast(in, &p);
+ }
+ }
+
+ TString TJsonPrettifier::Prettify(TStringBuf in) const {
+ TStringStream s;
+ if (Prettify(in, s))
+ return s.Str();
+ return TString();
+ }
+
+}
diff --git a/library/cpp/json/json_prettifier.h b/library/cpp/json/json_prettifier.h
new file mode 100644
index 0000000000..27d611b0b4
--- /dev/null
+++ b/library/cpp/json/json_prettifier.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#include "json_reader.h"
+
+#include <util/generic/ylimits.h>
+
+namespace NJson {
+ struct TJsonPrettifier {
+ bool Unquote = false;
+ ui8 Padding = 4;
+ bool SingleQuotes = false;
+ bool Compactify = false;
+ bool Strict = false;
+ bool NewUnquote = false; // use new unquote, may break old tests
+ ui32 MaxPaddingLevel = Max<ui32>();
+
+ static TJsonPrettifier Prettifier(bool unquote = false, ui8 padding = 4, bool singlequotes = false) {
+ TJsonPrettifier p;
+ p.Unquote = unquote;
+ p.Padding = padding;
+ p.SingleQuotes = singlequotes;
+ return p;
+ }
+
+ static TJsonPrettifier Compactifier(bool unquote = false, bool singlequote = false) {
+ TJsonPrettifier p;
+ p.Unquote = unquote;
+ p.Padding = 0;
+ p.Compactify = true;
+ p.SingleQuotes = singlequote;
+ return p;
+ }
+
+ bool Prettify(TStringBuf in, IOutputStream& out) const;
+
+ TString Prettify(TStringBuf in) const;
+
+ static bool MayUnquoteNew(TStringBuf in);
+ static bool MayUnquoteOld(TStringBuf in);
+ };
+
+ inline TString PrettifyJson(TStringBuf in, bool unquote = false, ui8 padding = 4, bool sq = false) {
+ return TJsonPrettifier::Prettifier(unquote, padding, sq).Prettify(in);
+ }
+
+ inline bool PrettifyJson(TStringBuf in, IOutputStream& out, bool unquote = false, ui8 padding = 4, bool sq = false) {
+ return TJsonPrettifier::Prettifier(unquote, padding, sq).Prettify(in, out);
+ }
+
+ inline bool CompactifyJson(TStringBuf in, IOutputStream& out, bool unquote = false, bool sq = false) {
+ return TJsonPrettifier::Compactifier(unquote, sq).Prettify(in, out);
+ }
+
+ inline TString CompactifyJson(TStringBuf in, bool unquote = false, bool sq = false) {
+ return TJsonPrettifier::Compactifier(unquote, sq).Prettify(in);
+ }
+
+}
diff --git a/library/cpp/json/json_reader.cpp b/library/cpp/json/json_reader.cpp
new file mode 100644
index 0000000000..072c8deafe
--- /dev/null
+++ b/library/cpp/json/json_reader.cpp
@@ -0,0 +1,567 @@
+#include "json_reader.h"
+
+#include "rapidjson_helpers.h"
+
+#include <contrib/libs/rapidjson/include/rapidjson/error/en.h>
+#include <contrib/libs/rapidjson/include/rapidjson/error/error.h>
+#include <contrib/libs/rapidjson/include/rapidjson/reader.h>
+
+#include <util/generic/stack.h>
+#include <util/string/cast.h>
+#include <util/system/yassert.h>
+#include <util/string/builder.h>
+
+namespace NJson {
+ namespace {
+ TString PrintError(const rapidjson::ParseResult& result) {
+ return TStringBuilder() << TStringBuf("Offset: ") << result.Offset()
+ << TStringBuf(", Code: ") << (int)result.Code()
+ << TStringBuf(", Error: ") << GetParseError_En(result.Code());
+ }
+ }
+
+ static const size_t DEFAULT_BUFFER_LEN = 65536;
+
+ bool TParserCallbacks::OpenComplexValue(EJsonValueType type) {
+ TJsonValue* pvalue;
+ switch (CurrentState) {
+ case START:
+ Value.SetType(type);
+ ValuesStack.push_back(&Value);
+ break;
+ case IN_ARRAY:
+ pvalue = &ValuesStack.back()->AppendValue(type);
+ ValuesStack.push_back(pvalue);
+ break;
+ case AFTER_MAP_KEY:
+ pvalue = &ValuesStack.back()->InsertValue(Key, type);
+ ValuesStack.push_back(pvalue);
+ CurrentState = IN_MAP;
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ bool TParserCallbacks::CloseComplexValue() {
+ if (ValuesStack.empty()) {
+ return false;
+ }
+
+ ValuesStack.pop_back();
+ if (!ValuesStack.empty()) {
+ switch (ValuesStack.back()->GetType()) {
+ case JSON_ARRAY:
+ CurrentState = IN_ARRAY;
+ break;
+ case JSON_MAP:
+ CurrentState = IN_MAP;
+ break;
+ default:
+ return false;
+ }
+ } else {
+ CurrentState = FINISH;
+ }
+ return true;
+ }
+
+ TParserCallbacks::TParserCallbacks(TJsonValue& value, bool throwOnError, bool notClosedBracketIsError)
+ : TJsonCallbacks(throwOnError)
+ , Value(value)
+ , NotClosedBracketIsError(notClosedBracketIsError)
+ , CurrentState(START)
+ {
+ }
+
+ bool TParserCallbacks::OnNull() {
+ return SetValue(JSON_NULL);
+ }
+
+ bool TParserCallbacks::OnBoolean(bool val) {
+ return SetValue(val);
+ }
+
+ bool TParserCallbacks::OnInteger(long long val) {
+ return SetValue(val);
+ }
+
+ bool TParserCallbacks::OnUInteger(unsigned long long val) {
+ return SetValue(val);
+ }
+
+ bool TParserCallbacks::OnString(const TStringBuf& val) {
+ return SetValue(val);
+ }
+
+ bool TParserCallbacks::OnDouble(double val) {
+ return SetValue(val);
+ }
+
+ bool TParserCallbacks::OnOpenArray() {
+ bool res = OpenComplexValue(JSON_ARRAY);
+ if (res)
+ CurrentState = IN_ARRAY;
+ return res;
+ }
+
+ bool TParserCallbacks::OnCloseArray() {
+ return CloseComplexValue();
+ }
+
+ bool TParserCallbacks::OnOpenMap() {
+ bool res = OpenComplexValue(JSON_MAP);
+ if (res)
+ CurrentState = IN_MAP;
+ return res;
+ }
+
+ bool TParserCallbacks::OnCloseMap() {
+ return CloseComplexValue();
+ }
+
+ bool TParserCallbacks::OnMapKey(const TStringBuf& val) {
+ switch (CurrentState) {
+ case IN_MAP:
+ Key = val;
+ CurrentState = AFTER_MAP_KEY;
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ bool TParserCallbacks::OnEnd() {
+ if (NotClosedBracketIsError){
+ return ValuesStack.empty();
+ }
+ return true;
+ }
+
+ TJsonReaderConfig::TJsonReaderConfig()
+ : BufferSize(DEFAULT_BUFFER_LEN)
+ {
+ }
+
+ void TJsonReaderConfig::SetBufferSize(size_t bufferSize) {
+ BufferSize = Max((size_t)1, Min(bufferSize, DEFAULT_BUFFER_LEN));
+ }
+
+ size_t TJsonReaderConfig::GetBufferSize() const {
+ return BufferSize;
+ }
+
+ namespace {
+ struct TJsonValueBuilder {
+#ifdef NDEBUG
+ using TItem = TJsonValue*;
+
+ inline TJsonValue& Access(TItem& item) const {
+ return *item;
+ }
+#else
+ struct TItem {
+ TJsonValue* V;
+ size_t DuplicateKeyCount;
+
+ TItem(TJsonValue* v)
+ : V(v)
+ , DuplicateKeyCount(0)
+ {
+ }
+ };
+
+ inline TJsonValue& Access(TItem& item) const {
+ return *item.V;
+ }
+#endif
+
+ NJson::TJsonValue& V;
+
+ TStack<TItem> S;
+
+ TJsonValueBuilder(NJson::TJsonValue& v)
+ : V(v)
+ {
+ S.emplace(&V);
+ }
+
+ template <class T>
+ void Set(const T& t) {
+ if (Access(S.top()).IsArray()) {
+ Access(S.top()).AppendValue(t);
+ } else {
+ Access(S.top()) = t;
+ S.pop();
+ }
+ }
+
+ bool Null() {
+ Set(NJson::JSON_NULL);
+ return true;
+ }
+
+ bool Bool(bool b) {
+ Set(b);
+ return true;
+ }
+
+ bool Int(int i) {
+ Set(i);
+ return true;
+ }
+
+ template <class U>
+ bool ProcessUint(U u) {
+ if (Y_LIKELY(u <= static_cast<ui64>(Max<i64>()))) {
+ Set(i64(u));
+ } else {
+ Set(u);
+ }
+ return true;
+ }
+
+ bool Uint(unsigned u) {
+ return ProcessUint(u);
+ }
+
+ bool Int64(i64 i) {
+ Set(i);
+ return true;
+ }
+
+ bool Uint64(ui64 u) {
+ return ProcessUint(u);
+ }
+
+ bool Double(double d) {
+ Set(d);
+ return true;
+ }
+
+ bool RawNumber(const char* str, rapidjson::SizeType length, bool copy) {
+ Y_ASSERT(false && "this method should never be called");
+ Y_UNUSED(str);
+ Y_UNUSED(length);
+ Y_UNUSED(copy);
+ return true;
+ }
+
+ bool String(const char* str, rapidjson::SizeType length, bool copy) {
+ Y_ASSERT(copy);
+ Set(TStringBuf(str, length));
+ return true;
+ }
+
+ bool StartObject() {
+ if (Access(S.top()).IsArray()) {
+ S.emplace(&Access(S.top()).AppendValue(NJson::JSON_MAP));
+ } else {
+ Access(S.top()).SetType(NJson::JSON_MAP);
+ }
+ return true;
+ }
+
+ bool Key(const char* str, rapidjson::SizeType length, bool copy) {
+ Y_ASSERT(copy);
+ auto& value = Access(S.top())[TStringBuf(str, length)];
+ if (Y_UNLIKELY(value.GetType() != JSON_UNDEFINED)) {
+#ifndef NDEBUG
+ ++S.top().DuplicateKeyCount;
+#endif
+ value.SetType(JSON_UNDEFINED);
+ }
+ S.emplace(&value);
+ return true;
+ }
+
+ inline int GetDuplicateKeyCount() const {
+#ifdef NDEBUG
+ return 0;
+#else
+ return S.top().DuplicateKeyCount;
+#endif
+ }
+
+ bool EndObject(rapidjson::SizeType memberCount) {
+ Y_ASSERT(memberCount == Access(S.top()).GetMap().size() + GetDuplicateKeyCount());
+ S.pop();
+ return true;
+ }
+
+ bool StartArray() {
+ if (Access(S.top()).IsArray()) {
+ S.emplace(&Access(S.top()).AppendValue(NJson::JSON_ARRAY));
+ } else {
+ Access(S.top()).SetType(NJson::JSON_ARRAY);
+ }
+ return true;
+ }
+
+ bool EndArray(rapidjson::SizeType elementCount) {
+ Y_ASSERT(elementCount == Access(S.top()).GetArray().size());
+ S.pop();
+ return true;
+ }
+ };
+
+ template <class TRapidJsonCompliantInputStream, class THandler>
+ auto Read(const TJsonReaderConfig& config,
+ rapidjson::Reader& reader,
+ TRapidJsonCompliantInputStream& is,
+ THandler& handler) {
+
+ ui8 flags = ReaderConfigToRapidJsonFlags::NOCOMMENTS_VALID_NOESCAPE;
+
+ if (config.AllowComments) {
+ flags |= ReaderConfigFlags::COMMENTS;
+ }
+
+ if (config.DontValidateUtf8) {
+ flags &= ~(ReaderConfigFlags::VALIDATE);
+ }
+
+ if (config.AllowEscapedApostrophe) {
+ flags |= ReaderConfigFlags::ESCAPE;
+ }
+
+ switch (flags) {
+ case ReaderConfigToRapidJsonFlags::COMMENTS_NOVALID_NOESCAPE:
+ return reader.Parse<rapidjson::kParseCommentsFlag>(is, handler);
+ case ReaderConfigToRapidJsonFlags::COMMENTS_VALID_NOESCAPE:
+ return reader.Parse<rapidjson::kParseCommentsFlag | rapidjson::kParseValidateEncodingFlag>(is, handler);
+ case ReaderConfigToRapidJsonFlags::COMMENTS_VALID_ESCAPE:
+ return reader.Parse<rapidjson::kParseCommentsFlag | rapidjson::kParseValidateEncodingFlag | rapidjson::kParseEscapedApostropheFlag>(is, handler);
+ case ReaderConfigToRapidJsonFlags::COMMENTS_NOVALID_ESCAPE:
+ return reader.Parse<rapidjson::kParseCommentsFlag | rapidjson::kParseEscapedApostropheFlag>(is, handler);
+ case ReaderConfigToRapidJsonFlags::NOCOMMENTS_VALID_NOESCAPE:
+ return reader.Parse<rapidjson::kParseValidateEncodingFlag>(is, handler);
+ case ReaderConfigToRapidJsonFlags::NOCOMMENTS_VALID_ESCAPE:
+ return reader.Parse<rapidjson::kParseValidateEncodingFlag | rapidjson::kParseEscapedApostropheFlag>(is, handler);
+ case ReaderConfigToRapidJsonFlags::NOCOMMENTS_NOVALID_ESCAPE:
+ return reader.Parse<rapidjson::kParseEscapedApostropheFlag>(is, handler);
+ default:
+ return reader.Parse<rapidjson::kParseNoFlags>(is, handler);
+ }
+ }
+
+ template <class TRapidJsonCompliantInputStream, class THandler>
+ bool ReadJson(TRapidJsonCompliantInputStream& is, const TJsonReaderConfig* config, THandler& handler, bool throwOnError) {
+ rapidjson::Reader reader;
+
+ auto result = Read(*config, reader, is, handler);
+
+ if (result.IsError()) {
+ if (throwOnError) {
+ ythrow TJsonException() << PrintError(result);
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ template <class TRapidJsonCompliantInputStream>
+ bool ReadJsonTree(TRapidJsonCompliantInputStream& is, const TJsonReaderConfig* config, TJsonValue* out, bool throwOnError) {
+ out->SetType(NJson::JSON_NULL);
+
+ TJsonValueBuilder handler(*out);
+
+ return ReadJson(is, config, handler, throwOnError);
+ }
+
+ template <class TData>
+ bool ReadJsonTreeImpl(TData* in, const TJsonReaderConfig* config, TJsonValue* out, bool throwOnError) {
+ std::conditional_t<std::is_same<TData, TStringBuf>::value, TStringBufStreamWrapper, TInputStreamWrapper> is(*in);
+ return ReadJsonTree(is, config, out, throwOnError);
+ }
+
+ template <class TData>
+ bool ReadJsonTreeImpl(TData* in, bool allowComments, TJsonValue* out, bool throwOnError) {
+ TJsonReaderConfig config;
+ config.AllowComments = allowComments;
+ return ReadJsonTreeImpl(in, &config, out, throwOnError);
+ }
+
+ template <class TData>
+ bool ReadJsonTreeImpl(TData* in, TJsonValue* out, bool throwOnError) {
+ return ReadJsonTreeImpl(in, false, out, throwOnError);
+ }
+ } //namespace
+
+ bool ReadJsonTree(TStringBuf in, TJsonValue* out, bool throwOnError) {
+ return ReadJsonTreeImpl(&in, out, throwOnError);
+ }
+
+ bool ReadJsonTree(TStringBuf in, bool allowComments, TJsonValue* out, bool throwOnError) {
+ return ReadJsonTreeImpl(&in, allowComments, out, throwOnError);
+ }
+
+ bool ReadJsonTree(TStringBuf in, const TJsonReaderConfig* config, TJsonValue* out, bool throwOnError) {
+ return ReadJsonTreeImpl(&in, config, out, throwOnError);
+ }
+
+ bool ReadJsonTree(IInputStream* in, TJsonValue* out, bool throwOnError) {
+ return ReadJsonTreeImpl(in, out, throwOnError);
+ }
+
+ bool ReadJsonTree(IInputStream* in, bool allowComments, TJsonValue* out, bool throwOnError) {
+ return ReadJsonTreeImpl(in, allowComments, out, throwOnError);
+ }
+
+ bool ReadJsonTree(IInputStream* in, const TJsonReaderConfig* config, TJsonValue* out, bool throwOnError) {
+ return ReadJsonTreeImpl(in, config, out, throwOnError);
+ }
+
+ bool ReadJsonFastTree(TStringBuf in, TJsonValue* out, bool throwOnError, bool notClosedBracketIsError) {
+ TParserCallbacks cb(*out, throwOnError, notClosedBracketIsError);
+
+ return ReadJsonFast(in, &cb);
+ }
+
+ TJsonValue ReadJsonFastTree(TStringBuf in, bool notClosedBracketIsError) {
+ TJsonValue value;
+ // There is no way to report an error apart from throwing an exception when we return result by value.
+ ReadJsonFastTree(in, &value, /* throwOnError = */ true, notClosedBracketIsError);
+ return value;
+ }
+
+ namespace {
+ struct TJsonCallbacksWrapper {
+ TJsonCallbacks& Impl;
+
+ TJsonCallbacksWrapper(TJsonCallbacks& impl)
+ : Impl(impl)
+ {
+ }
+
+ bool Null() {
+ return Impl.OnNull();
+ }
+
+ bool Bool(bool b) {
+ return Impl.OnBoolean(b);
+ }
+
+ template <class U>
+ bool ProcessUint(U u) {
+ if (Y_LIKELY(u <= ui64(Max<i64>()))) {
+ return Impl.OnInteger(i64(u));
+ } else {
+ return Impl.OnUInteger(u);
+ }
+ }
+
+ bool Int(int i) {
+ return Impl.OnInteger(i);
+ }
+
+ bool Uint(unsigned u) {
+ return ProcessUint(u);
+ }
+
+ bool Int64(i64 i) {
+ return Impl.OnInteger(i);
+ }
+
+ bool Uint64(ui64 u) {
+ return ProcessUint(u);
+ }
+
+ bool Double(double d) {
+ return Impl.OnDouble(d);
+ }
+
+ bool RawNumber(const char* str, rapidjson::SizeType length, bool copy) {
+ Y_ASSERT(false && "this method should never be called");
+ Y_UNUSED(str);
+ Y_UNUSED(length);
+ Y_UNUSED(copy);
+ return true;
+ }
+
+ bool String(const char* str, rapidjson::SizeType length, bool copy) {
+ Y_ASSERT(copy);
+ return Impl.OnString(TStringBuf(str, length));
+ }
+
+ bool StartObject() {
+ return Impl.OnOpenMap();
+ }
+
+ bool Key(const char* str, rapidjson::SizeType length, bool copy) {
+ Y_ASSERT(copy);
+ return Impl.OnMapKey(TStringBuf(str, length));
+ }
+
+ bool EndObject(rapidjson::SizeType memberCount) {
+ Y_UNUSED(memberCount);
+ return Impl.OnCloseMap();
+ }
+
+ bool StartArray() {
+ return Impl.OnOpenArray();
+ }
+
+ bool EndArray(rapidjson::SizeType elementCount) {
+ Y_UNUSED(elementCount);
+ return Impl.OnCloseArray();
+ }
+ };
+ }
+
+ bool ReadJson(IInputStream* in, TJsonCallbacks* cbs) {
+ return ReadJson(in, false, cbs);
+ }
+
+ bool ReadJson(IInputStream* in, bool allowComments, TJsonCallbacks* cbs) {
+ TJsonReaderConfig config;
+ config.AllowComments = allowComments;
+ return ReadJson(in, &config, cbs);
+ }
+
+ bool ReadJson(IInputStream* in, bool allowComments, bool allowEscapedApostrophe, TJsonCallbacks* cbs) {
+ TJsonReaderConfig config;
+ config.AllowComments = allowComments;
+ config.AllowEscapedApostrophe = allowEscapedApostrophe;
+ return ReadJson(in, &config, cbs);
+ }
+
+ bool ReadJson(IInputStream* in, const TJsonReaderConfig* config, TJsonCallbacks* cbs) {
+ TJsonCallbacksWrapper wrapper(*cbs);
+ TInputStreamWrapper is(*in);
+
+ rapidjson::Reader reader;
+ auto result = Read(*config, reader, is, wrapper);
+
+ if (result.IsError()) {
+ cbs->OnError(result.Offset(), PrintError(result));
+
+ return false;
+ }
+
+ return cbs->OnEnd();
+ }
+
+ TJsonValue ReadJsonTree(IInputStream* in, bool throwOnError) {
+ TJsonValue out;
+ ReadJsonTree(in, &out, throwOnError);
+ return out;
+ }
+
+ TJsonValue ReadJsonTree(IInputStream* in, bool allowComments, bool throwOnError) {
+ TJsonValue out;
+ ReadJsonTree(in, allowComments, &out, throwOnError);
+ return out;
+ }
+
+ TJsonValue ReadJsonTree(IInputStream* in, const TJsonReaderConfig* config, bool throwOnError) {
+ TJsonValue out;
+ ReadJsonTree(in, config, &out, throwOnError);
+ return out;
+ }
+
+}
diff --git a/library/cpp/json/json_reader.h b/library/cpp/json/json_reader.h
new file mode 100644
index 0000000000..b673788330
--- /dev/null
+++ b/library/cpp/json/json_reader.h
@@ -0,0 +1,140 @@
+#pragma once
+
+#include "json_value.h"
+
+#include <library/cpp/json/common/defs.h>
+#include <library/cpp/json/fast_sax/parser.h>
+
+#include <util/generic/yexception.h>
+
+#include <util/stream/input.h>
+#include <util/stream/str.h>
+#include <util/stream/mem.h>
+
+namespace NJson {
+ struct TJsonReaderConfig {
+ TJsonReaderConfig();
+
+ // js-style comments (both // and /**/)
+ bool AllowComments = false;
+ bool DontValidateUtf8 = false;
+ bool AllowEscapedApostrophe = false;
+
+ void SetBufferSize(size_t bufferSize);
+ size_t GetBufferSize() const;
+
+ private:
+ size_t BufferSize;
+ };
+
+ bool ReadJsonTree(TStringBuf in, TJsonValue* out, bool throwOnError = false);
+ bool ReadJsonTree(TStringBuf in, bool allowComments, TJsonValue* out, bool throwOnError = false);
+ bool ReadJsonTree(TStringBuf in, const TJsonReaderConfig* config, TJsonValue* out, bool throwOnError = false);
+
+ bool ReadJsonTree(IInputStream* in, TJsonValue* out, bool throwOnError = false);
+ bool ReadJsonTree(IInputStream* in, bool allowComments, TJsonValue* out, bool throwOnError = false);
+ bool ReadJsonTree(IInputStream* in, const TJsonReaderConfig* config, TJsonValue* out, bool throwOnError = false);
+
+ TJsonValue ReadJsonTree(IInputStream* in, bool throwOnError = false);
+ TJsonValue ReadJsonTree(IInputStream* in, bool allowComments, bool throwOnError);
+ TJsonValue ReadJsonTree(IInputStream* in, const TJsonReaderConfig* config, bool throwOnError = false);
+
+ bool ReadJson(IInputStream* in, TJsonCallbacks* callbacks);
+ bool ReadJson(IInputStream* in, bool allowComments, TJsonCallbacks* callbacks);
+ bool ReadJson(IInputStream* in, bool allowComments, bool allowEscapedApostrophe, TJsonCallbacks* callbacks);
+ bool ReadJson(IInputStream* in, const TJsonReaderConfig* config, TJsonCallbacks* callbacks);
+
+ enum ReaderConfigFlags {
+ COMMENTS = 0b100,
+ VALIDATE = 0b010,
+ ESCAPE = 0b001,
+ };
+
+ enum ReaderConfigToRapidJsonFlags {
+ COMMENTS_NOVALID_NOESCAPE = 0b100,
+ COMMENTS_VALID_NOESCAPE = 0b110,
+ COMMENTS_VALID_ESCAPE = 0b111,
+ COMMENTS_NOVALID_ESCAPE = 0b101,
+ NOCOMMENTS_VALID_NOESCAPE = 0b010,
+ NOCOMMENTS_VALID_ESCAPE = 0b011,
+ NOCOMMENTS_NOVALID_ESCAPE = 0b001,
+ };
+
+ inline bool ValidateJson(IInputStream* in, const TJsonReaderConfig* config, bool throwOnError = false) {
+ TJsonCallbacks c(throwOnError);
+ return ReadJson(in, config, &c);
+ }
+
+ inline bool ValidateJson(TStringBuf in, const TJsonReaderConfig& config = TJsonReaderConfig(), bool throwOnError = false) {
+ TMemoryInput min(in.data(), in.size());
+ return ValidateJson(&min, &config, throwOnError);
+ }
+
+ inline bool ValidateJsonThrow(IInputStream* in, const TJsonReaderConfig* config) {
+ return ValidateJson(in, config, true);
+ }
+
+ inline bool ValidateJsonThrow(TStringBuf in, const TJsonReaderConfig& config = TJsonReaderConfig()) {
+ return ValidateJson(in, config, true);
+ }
+
+ class TParserCallbacks: public TJsonCallbacks {
+ public:
+ TParserCallbacks(TJsonValue& value, bool throwOnError = false, bool notClosedBracketIsError = false);
+ bool OnNull() override;
+ bool OnBoolean(bool val) override;
+ bool OnInteger(long long val) override;
+ bool OnUInteger(unsigned long long val) override;
+ bool OnString(const TStringBuf& val) override;
+ bool OnDouble(double val) override;
+ bool OnOpenArray() override;
+ bool OnCloseArray() override;
+ bool OnOpenMap() override;
+ bool OnCloseMap() override;
+ bool OnMapKey(const TStringBuf& val) override;
+ bool OnEnd() override;
+
+ protected:
+ TJsonValue& Value;
+ TString Key;
+ TVector<TJsonValue*> ValuesStack;
+ bool NotClosedBracketIsError;
+
+ enum {
+ START,
+ AFTER_MAP_KEY,
+ IN_MAP,
+ IN_ARRAY,
+ FINISH
+ } CurrentState;
+
+ template <class T>
+ bool SetValue(const T& value) {
+ switch (CurrentState) {
+ case START:
+ Value.SetValue(value);
+ break;
+ case AFTER_MAP_KEY:
+ ValuesStack.back()->InsertValue(Key, value);
+ CurrentState = IN_MAP;
+ break;
+ case IN_ARRAY:
+ ValuesStack.back()->AppendValue(value);
+ break;
+ case IN_MAP:
+ case FINISH:
+ return false;
+ default:
+ ythrow yexception() << "TParserCallbacks::SetValue invalid enum";
+ }
+ return true;
+ }
+
+ bool OpenComplexValue(EJsonValueType type);
+ bool CloseComplexValue();
+ };
+
+ //// relaxed json, used in library/cpp/scheme
+ bool ReadJsonFastTree(TStringBuf in, TJsonValue* out, bool throwOnError = false, bool notClosedBracketIsError = false);
+ TJsonValue ReadJsonFastTree(TStringBuf in, bool notClosedBracketIsError = false);
+}
diff --git a/library/cpp/json/json_value.h b/library/cpp/json/json_value.h
new file mode 100644
index 0000000000..f70f4d2ee8
--- /dev/null
+++ b/library/cpp/json/json_value.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include <library/cpp/json/writer/json_value.h>
diff --git a/library/cpp/json/json_writer.cpp b/library/cpp/json/json_writer.cpp
new file mode 100644
index 0000000000..3d058bae36
--- /dev/null
+++ b/library/cpp/json/json_writer.cpp
@@ -0,0 +1,149 @@
+#include "json_writer.h"
+
+#include <util/charset/utf8.h>
+#include <util/generic/algorithm.h>
+#include <util/string/cast.h>
+#include <util/system/yassert.h>
+
+namespace NJson {
+ TJsonWriter::TJsonWriter(IOutputStream* out, bool formatOutput, bool sortkeys, bool validateUtf8)
+ : Out(out)
+ , Buf(NJsonWriter::HEM_UNSAFE)
+ , DoubleNDigits(TJsonWriterConfig::DefaultDoubleNDigits)
+ , FloatNDigits(TJsonWriterConfig::DefaultFloatNDigits)
+ , FloatToStringMode(TJsonWriterConfig::DefaultFloatToStringMode)
+ , SortKeys(sortkeys)
+ , ValidateUtf8(validateUtf8)
+ , DontEscapeStrings(false)
+ , DontFlushInDestructor(false)
+ {
+ Buf.SetIndentSpaces(formatOutput ? 2 : 0);
+ }
+
+ TJsonWriter::TJsonWriter(IOutputStream* out, const TJsonWriterConfig& config, bool DFID)
+ : Out(config.Unbuffered ? nullptr : out)
+ , Buf(NJsonWriter::HEM_UNSAFE, config.Unbuffered ? out : nullptr)
+ , DoubleNDigits(config.DoubleNDigits)
+ , FloatNDigits(config.FloatNDigits)
+ , FloatToStringMode(config.FloatToStringMode)
+ , SortKeys(config.SortKeys)
+ , ValidateUtf8(config.ValidateUtf8)
+ , DontEscapeStrings(config.DontEscapeStrings)
+ , DontFlushInDestructor(DFID)
+ {
+ Buf.SetIndentSpaces(config.FormatOutput ? 2 : 0);
+ Buf.SetWriteNanAsString(config.WriteNanAsString);
+ }
+
+ TJsonWriter::~TJsonWriter() {
+ // if we write to socket it's possible to get exception here
+ // don't use exceptions in destructors
+ if (!DontFlushInDestructor) {
+ try {
+ Flush();
+ } catch (...) {
+ }
+ }
+ }
+
+ void TJsonWriter::Flush() {
+ if (Out) {
+ Buf.FlushTo(Out);
+ }
+ }
+
+ void TJsonWriter::OpenMap() {
+ Buf.BeginObject();
+ }
+
+ void TJsonWriter::CloseMap() {
+ Buf.EndObject();
+ }
+
+ void TJsonWriter::OpenArray() {
+ Buf.BeginList();
+ }
+
+ void TJsonWriter::CloseArray() {
+ Buf.EndList();
+ }
+
+ void TJsonWriter::Write(const TStringBuf& value) {
+ if (ValidateUtf8 && !IsUtf(value))
+ throw yexception() << "JSON writer: invalid UTF-8";
+ if (Buf.KeyExpected()) {
+ Buf.WriteKey(value);
+ } else {
+ if (DontEscapeStrings) {
+ Buf.UnsafeWriteValue(TString("\"") + value + '"');
+ } else {
+ Buf.WriteString(value);
+ }
+ }
+ }
+
+ void TJsonWriter::WriteNull() {
+ Buf.WriteNull();
+ }
+
+ void TJsonWriter::Write(float value) {
+ Buf.WriteFloat(value, FloatToStringMode, FloatNDigits);
+ }
+
+ void TJsonWriter::Write(double value) {
+ Buf.WriteDouble(value, FloatToStringMode, DoubleNDigits);
+ }
+
+ void TJsonWriter::Write(long long value) {
+ Buf.WriteLongLong(value);
+ }
+
+ void TJsonWriter::Write(unsigned long long value) {
+ Buf.WriteULongLong(value);
+ }
+
+ void TJsonWriter::Write(bool value) {
+ Buf.WriteBool(value);
+ }
+
+ namespace {
+ struct TLessStrPtr {
+ bool operator()(const TString* a, const TString* b) const {
+ return *a < *b;
+ }
+ };
+ }
+
+ void TJsonWriter::Write(const TJsonValue* v) {
+ Buf.WriteJsonValue(v, SortKeys, FloatToStringMode, DoubleNDigits);
+ }
+
+ void TJsonWriter::Write(const TJsonValue& v) {
+ Buf.WriteJsonValue(&v, SortKeys, FloatToStringMode, DoubleNDigits);
+ }
+
+ TString WriteJson(const TJsonValue* value, bool formatOutput, bool sortkeys, bool validateUtf8) {
+ TStringStream ss;
+ WriteJson(&ss, value, formatOutput, sortkeys, validateUtf8);
+ return ss.Str();
+ }
+
+ TString WriteJson(const TJsonValue& value, bool formatOutput, bool sortkeys, bool validateUtf8) {
+ TStringStream ss;
+ WriteJson(&ss, &value, formatOutput, sortkeys, validateUtf8);
+ return ss.Str();
+ }
+
+ void WriteJson(IOutputStream* out, const TJsonValue* val, bool formatOutput, bool sortkeys, bool validateUtf8) {
+ TJsonWriter w(out, formatOutput, sortkeys, validateUtf8);
+ w.Write(val);
+ w.Flush();
+ }
+
+ void WriteJson(IOutputStream* out, const TJsonValue* val, const TJsonWriterConfig& config) {
+ TJsonWriter w(out, config, true);
+ w.Write(val);
+ w.Flush();
+ }
+
+}
diff --git a/library/cpp/json/json_writer.h b/library/cpp/json/json_writer.h
new file mode 100644
index 0000000000..c7f5c9499a
--- /dev/null
+++ b/library/cpp/json/json_writer.h
@@ -0,0 +1,196 @@
+#pragma once
+
+// Deprecated. Use library/cpp/json/writer in new code.
+
+#include "json_value.h"
+
+#include <library/cpp/json/writer/json.h>
+
+#include <util/stream/output.h>
+#include <util/generic/hash.h>
+#include <util/generic/maybe.h>
+#include <util/generic/strbuf.h>
+
+namespace NJson {
+ struct TJsonWriterConfig {
+ constexpr static ui32 DefaultDoubleNDigits = 10;
+ constexpr static ui32 DefaultFloatNDigits = 6;
+ constexpr static EFloatToStringMode DefaultFloatToStringMode = PREC_NDIGITS;
+
+ inline TJsonWriterConfig& SetUnbuffered(bool v) noexcept {
+ Unbuffered = v;
+
+ return *this;
+ }
+
+ inline TJsonWriterConfig& SetValidateUtf8(bool v) noexcept {
+ ValidateUtf8 = v;
+
+ return *this;
+ }
+
+ inline TJsonWriterConfig& SetFormatOutput(bool v) noexcept {
+ FormatOutput = v;
+
+ return *this;
+ }
+
+ ui32 DoubleNDigits = DefaultDoubleNDigits;
+ ui32 FloatNDigits = DefaultFloatNDigits;
+ EFloatToStringMode FloatToStringMode = DefaultFloatToStringMode;
+ bool FormatOutput = false;
+ bool SortKeys = false;
+ bool ValidateUtf8 = true;
+ bool DontEscapeStrings = false;
+ bool Unbuffered = false;
+ bool WriteNanAsString = false; // NaN and Inf are not valid json values, so if WriteNanAsString is set, writer would write string intead of throwing exception (default case)
+ };
+
+ class TJsonWriter {
+ IOutputStream* Out;
+ NJsonWriter::TBuf Buf;
+ const ui32 DoubleNDigits;
+ const ui32 FloatNDigits;
+ const EFloatToStringMode FloatToStringMode;
+ const bool SortKeys;
+ const bool ValidateUtf8;
+ const bool DontEscapeStrings;
+ const bool DontFlushInDestructor;
+
+ public:
+ TJsonWriter(IOutputStream* out, bool formatOutput, bool sortkeys = false, bool validateUtf8 = true);
+ TJsonWriter(IOutputStream* out, const TJsonWriterConfig& config, bool DontFlushInDestructor = false);
+ ~TJsonWriter();
+
+ void Flush();
+
+ void OpenMap();
+ void OpenMap(const TStringBuf& key) {
+ Buf.WriteKey(key);
+ OpenMap();
+ }
+ void CloseMap();
+
+ void OpenArray();
+ void OpenArray(const TStringBuf& key) {
+ Buf.WriteKey(key);
+ OpenArray();
+ }
+ void CloseArray();
+
+ void WriteNull();
+
+ void Write(const TStringBuf& value);
+ void Write(float value);
+ void Write(double value);
+ void Write(bool value);
+ void Write(const TJsonValue* value);
+ void Write(const TJsonValue& value);
+
+ // must use all variations of integer types since long
+ // and long long are different types but with same size
+ void Write(long long value);
+ void Write(unsigned long long value);
+ void Write(long value) {
+ Write((long long)value);
+ }
+ void Write(unsigned long value) {
+ Write((unsigned long long)value);
+ }
+ void Write(int value) {
+ Write((long long)value);
+ }
+ void Write(unsigned int value) {
+ Write((unsigned long long)value);
+ }
+ void Write(short value) {
+ Write((long long)value);
+ }
+ void Write(unsigned short value) {
+ Write((unsigned long long)value);
+ }
+
+ void Write(const unsigned char* value) {
+ Write((const char*)value);
+ }
+ void Write(const char* value) {
+ Write(TStringBuf(value));
+ }
+ void Write(const TString& value) {
+ Write(TStringBuf(value));
+ }
+ void Write(const std::string& value) {
+ Write(TStringBuf(value));
+ }
+
+ // write raw json without checks
+ void UnsafeWrite(const TStringBuf& value) {
+ Buf.UnsafeWriteValue(value);
+ }
+
+ template <typename T>
+ void Write(const TStringBuf& key, const T& value) {
+ Buf.WriteKey(key);
+ Write(value);
+ }
+
+ // write raw json without checks
+ void UnsafeWrite(const TStringBuf& key, const TStringBuf& value) {
+ Buf.WriteKey(key);
+ UnsafeWrite(value);
+ }
+
+ void WriteNull(const TStringBuf& key) {
+ Buf.WriteKey(key);
+ WriteNull();
+ }
+
+ template <typename T>
+ void WriteOptional(const TStringBuf& key, const TMaybe<T>& value) {
+ if (value) {
+ Write(key, *value);
+ }
+ }
+
+ void WriteOptional(const TStringBuf&, const TNothing&) {
+ // nothing to do
+ }
+
+ void WriteKey(const TStringBuf key) {
+ Buf.WriteKey(key);
+ }
+
+ void WriteKey(const unsigned char* key) {
+ WriteKey((const char*)key);
+ }
+
+ void WriteKey(const char* key) {
+ WriteKey(TStringBuf{key});
+ }
+
+ void WriteKey(const TString& key) {
+ WriteKey(TStringBuf{key});
+ }
+
+ void WriteKey(const std::string& key) {
+ WriteKey(TStringBuf{key});
+ }
+
+ NJsonWriter::TBufState State() const {
+ return Buf.State();
+ }
+
+ void Reset(const NJsonWriter::TBufState& from) {
+ return Buf.Reset(from);
+ }
+
+ void Reset(NJsonWriter::TBufState&& from) {
+ return Buf.Reset(std::move(from));
+ }
+ };
+
+ void WriteJson(IOutputStream*, const TJsonValue*, bool formatOutput = false, bool sortkeys = false, bool validateUtf8 = true);
+ TString WriteJson(const TJsonValue*, bool formatOutput = true, bool sortkeys = false, bool validateUtf8 = false);
+ TString WriteJson(const TJsonValue&, bool formatOutput = true, bool sortkeys = false, bool validateUtf8 = false);
+ void WriteJson(IOutputStream*, const TJsonValue*, const TJsonWriterConfig& config);
+}
diff --git a/library/cpp/json/rapidjson_helpers.cpp b/library/cpp/json/rapidjson_helpers.cpp
new file mode 100644
index 0000000000..2e8159a103
--- /dev/null
+++ b/library/cpp/json/rapidjson_helpers.cpp
@@ -0,0 +1 @@
+#include "rapidjson_helpers.h"
diff --git a/library/cpp/json/rapidjson_helpers.h b/library/cpp/json/rapidjson_helpers.h
new file mode 100644
index 0000000000..aeb96ff670
--- /dev/null
+++ b/library/cpp/json/rapidjson_helpers.h
@@ -0,0 +1,104 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+#include <util/stream/input.h>
+
+namespace NJson {
+ struct TReadOnlyStreamBase {
+ using Ch = char;
+
+ Ch* PutBegin() {
+ Y_ASSERT(false);
+ return nullptr;
+ }
+
+ void Put(Ch) {
+ Y_ASSERT(false);
+ }
+
+ void Flush() {
+ Y_ASSERT(false);
+ }
+
+ size_t PutEnd(Ch*) {
+ Y_ASSERT(false);
+ return 0;
+ }
+ };
+
+ struct TInputStreamWrapper : TReadOnlyStreamBase {
+ Ch Peek() const {
+ if (!Eof) {
+ if (Pos >= Sz) {
+ if (Sz < BUF_SIZE) {
+ Sz += Helper.Read(Buf + Sz, BUF_SIZE - Sz);
+ } else {
+ Sz = Helper.Read(Buf, BUF_SIZE);
+ Pos = 0;
+ }
+ }
+
+ if (Pos < Sz) {
+ return Buf[Pos];
+ }
+ }
+
+ Eof = true;
+ return 0;
+ }
+
+ Ch Take() {
+ auto c = Peek();
+ ++Pos;
+ ++Count;
+ return c;
+ }
+
+ size_t Tell() const {
+ return Count;
+ }
+
+ TInputStreamWrapper(IInputStream& helper)
+ : Helper(helper)
+ , Eof(false)
+ , Sz(0)
+ , Pos(0)
+ , Count(0)
+ {
+ }
+
+ static const size_t BUF_SIZE = 1 << 12;
+
+ IInputStream& Helper;
+ mutable char Buf[BUF_SIZE];
+ mutable bool Eof;
+ mutable size_t Sz;
+ mutable size_t Pos;
+ size_t Count;
+ };
+
+ struct TStringBufStreamWrapper : TReadOnlyStreamBase {
+ Ch Peek() const {
+ return Pos < Data.size() ? Data[Pos] : 0;
+ }
+
+ Ch Take() {
+ auto c = Peek();
+ ++Pos;
+ return c;
+ }
+
+ size_t Tell() const {
+ return Pos;
+ }
+
+ TStringBufStreamWrapper(TStringBuf data)
+ : Data(data)
+ , Pos(0)
+ {
+ }
+
+ TStringBuf Data;
+ size_t Pos;
+ };
+}
diff --git a/library/cpp/json/ut/json_prettifier_ut.cpp b/library/cpp/json/ut/json_prettifier_ut.cpp
new file mode 100644
index 0000000000..ae5f8dd81a
--- /dev/null
+++ b/library/cpp/json/ut/json_prettifier_ut.cpp
@@ -0,0 +1,204 @@
+#include <library/cpp/json/json_prettifier.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(JsonPrettifier) {
+ Y_UNIT_TEST(PrettifyJsonShort) {
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson(""), "");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("null"), "null");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("true"), "true");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("false"), "false");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("1.5"), "1.5");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("test", false, 2, true), "'test'");
+
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("[]"), "[ ]");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("[a]", false, 2), "[\n \"a\"\n]");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("[a,b]", false, 2, true), "[\n 'a',\n 'b'\n]");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("[{},b]", false, 2, true), "[\n { },\n 'b'\n]");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("[a,{}]", false, 2, true), "[\n 'a',\n { }\n]");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("[{},{}]"), "[\n { },\n { }\n]");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("{}"), "{ }");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("{}"), "{ }");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("{k:v}", false, 2, true), "{\n 'k' : 'v'\n}");
+
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("Test545", true, 2), "Test545");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("'null'", true, 2, true), "'null'");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("'true'", true, 2, true), "'true'");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("'false'", true, 2, true), "'false'");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("'\"'", true, 2, true), "'\"'");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("'\"'", true, 2, false), "\"\\\"\"");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("'\\\''", true, 2, true), "'\\u0027'");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("'\\\''", true, 2, false), "\"'\"");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("'1b'", true, 2, true), "'1b'");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("'Test*545'", true, 2, true), "'Test*545'");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("{k:v}", true, 2), "{\n k : v\n}");
+ }
+
+ Y_UNIT_TEST(PrettifyJsonLong) {
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("[{k:v},{a:b}]", false, 2, true),
+ "[\n"
+ " {\n"
+ " 'k' : 'v'\n"
+ " },\n"
+ " {\n"
+ " 'a' : 'b'\n"
+ " }\n"
+ "]");
+
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("{k:v,a:b,x:[1,2,3]}", false, 2, true),
+ "{\n"
+ " 'k' : 'v',\n"
+ " 'a' : 'b',\n"
+ " 'x' : [\n"
+ " 1,\n"
+ " 2,\n"
+ " 3\n"
+ " ]\n"
+ "}");
+
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("{k:v,a:b,x:[1,{f:b},3],m:n}", false, 2, true),
+ "{\n"
+ " 'k' : 'v',\n"
+ " 'a' : 'b',\n"
+ " 'x' : [\n"
+ " 1,\n"
+ " {\n"
+ " 'f' : 'b'\n"
+ " },\n"
+ " 3\n"
+ " ],\n"
+ " 'm' : 'n'\n"
+ "}");
+
+ NJson::TJsonPrettifier prettifierMaxLevel1 = NJson::TJsonPrettifier::Prettifier(false, 2, true);
+ prettifierMaxLevel1.MaxPaddingLevel = 1;
+ UNIT_ASSERT_STRINGS_EQUAL(prettifierMaxLevel1.Prettify("{k:v,a:b,x:[1,{f:b},3],m:n}"),
+ "{\n"
+ " 'k' : 'v',\n"
+ " 'a' : 'b',\n"
+ " 'x' : [ 1, { 'f' : 'b' }, 3 ],\n"
+ " 'm' : 'n'\n"
+ "}");
+
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("{g:{x:{a:{b:c,e:f},q:{x:y}},y:fff}}", true, 2),
+ "{\n"
+ " g : {\n"
+ " x : {\n"
+ " a : {\n"
+ " b : c,\n"
+ " e : f\n"
+ " },\n"
+ " q : {\n"
+ " x : y\n"
+ " }\n"
+ " },\n"
+ " y : fff\n"
+ " }\n"
+ "}");
+
+ NJson::TJsonPrettifier prettifierMaxLevel3 = NJson::TJsonPrettifier::Prettifier(true, 2);
+ prettifierMaxLevel3.MaxPaddingLevel = 3;
+ UNIT_ASSERT_STRINGS_EQUAL(prettifierMaxLevel3.Prettify("{g:{x:{a:{b:c,e:f},q:{x:y}},y:fff}}"),
+ "{\n"
+ " g : {\n"
+ " x : {\n"
+ " a : { b : c, e : f },\n"
+ " q : { x : y }\n"
+ " },\n"
+ " y : fff\n"
+ " }\n"
+ "}");
+ }
+
+ Y_UNIT_TEST(PrettifyJsonInvalid) {
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("}"), "");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("}}"), "");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("{}}"), "");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("{}}}"), "");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("]"), "");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("]]"), "");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("[]]"), "");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("[]]]"), "");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("[,,,]"), "");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::PrettifyJson("{,,,}"), "");
+ }
+
+ Y_UNIT_TEST(CompactifyJsonShort) {
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson(""), "");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson("null"), "null");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson("true"), "true");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson("false"), "false");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson("1.5"), "1.5");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson("test", true), "test");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson("test", false), "\"test\"");
+
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson("[ ]"), "[]");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson("[\n \"a\"\n]", true), "[a]");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson("[\n 'a',\n 'b'\n]", true), "[a,b]");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson("[\n { },\n 'b'\n]", true), "[{},b]");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson("[\n 'a',\n { }\n]", true), "[a,{}]");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson("[\n { },\n { }\n]", true), "[{},{}]");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson("{ }"), "{}");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson("{\n 'k' : 'v'\n}", true), "{k:v}");
+ }
+
+ Y_UNIT_TEST(CompactifyJsonLong) {
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson(
+ "[\n"
+ " {\n"
+ " 'k' : 'v'\n"
+ " },\n"
+ " {\n"
+ " 'a' : 'b'\n"
+ " }\n"
+ "]",
+ true),
+ "[{k:v},{a:b}]");
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson(
+ "{\n"
+ " 'k' : 'v',\n"
+ " 'a' : 'b',\n"
+ " 'x' : [\n"
+ " 1,\n"
+ " 2,\n"
+ " 3\n"
+ " ]\n"
+ "}",
+ true),
+ "{k:v,a:b,x:[1,2,3]}");
+
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson(
+ "{\n"
+ " 'k' : 'v',\n"
+ " 'a' : 'b',\n"
+ " 'x' : [\n"
+ " 1,\n"
+ " {\n"
+ " 'f' : 'b'\n"
+ " },\n"
+ " 3\n"
+ " ],\n"
+ " 'm' : 'n'\n"
+ "}",
+ true),
+ "{k:v,a:b,x:[1,{f:b},3],m:n}");
+
+ UNIT_ASSERT_STRINGS_EQUAL(NJson::CompactifyJson(
+ "{\n"
+ " g : {\n"
+ " x : {\n"
+ " a : {\n"
+ " b : c,\n"
+ " e : f\n"
+ " },\n"
+ " q : {\n"
+ " x : y\n"
+ " }\n"
+ " },\n"
+ " y : fff\n"
+ " }\n"
+ "}",
+ true),
+ "{g:{x:{a:{b:c,e:f},q:{x:y}},y:fff}}");
+ }
+}
diff --git a/library/cpp/json/ut/json_reader_fast_ut.cpp b/library/cpp/json/ut/json_reader_fast_ut.cpp
new file mode 100644
index 0000000000..60dffc91c7
--- /dev/null
+++ b/library/cpp/json/ut/json_reader_fast_ut.cpp
@@ -0,0 +1,304 @@
+#include <library/cpp/json/json_reader.h>
+#include <library/cpp/json/json_prettifier.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h>
+#include <util/string/cast.h>
+#include <util/string/printf.h>
+
+namespace NJson {
+ namespace NTest {
+ enum ETestEvent {
+ E_NO_EVENT = 0,
+ E_ERROR = 1,
+ E_DICT_OPEN,
+ E_DICT_CLOSE,
+ E_ARR_OPEN,
+ E_ARR_CLOSE,
+ E_NULL,
+ E_BOOL,
+ E_FLT,
+ E_INT,
+ E_LONG_LONG,
+ E_STR,
+ E_KEY
+ };
+
+ struct TEvent {
+ ETestEvent Type = E_NO_EVENT;
+
+ i64 INum = 0;
+ double DNum = 0;
+ TString Str;
+
+ TEvent(ETestEvent e = E_NO_EVENT)
+ : Type(e)
+ {
+ }
+
+ TEvent(double v, ETestEvent e)
+ : Type(e)
+ , DNum(v)
+ {
+ }
+
+ TEvent(i64 v, ETestEvent e)
+ : Type(e)
+ , INum(v)
+ {
+ }
+
+ TEvent(TStringBuf t, ETestEvent e)
+ : Type(e)
+ , Str(NEscJ::EscapeJ<true, false>(t))
+ {
+ }
+
+ TString ToString() const {
+ switch (Type) {
+ default:
+ return "YOUFAILED";
+ case E_ERROR:
+ return Sprintf("error: %s", Str.data());
+ case E_DICT_OPEN:
+ return "{";
+ case E_DICT_CLOSE:
+ return "}";
+ case E_ARR_OPEN:
+ return "[";
+ case E_ARR_CLOSE:
+ return "]";
+ case E_NULL:
+ return "null";
+ case E_BOOL:
+ return INum ? "true" : "false";
+ case E_INT:
+ return ::ToString(INum);
+ case E_FLT:
+ return ::ToString(DNum);
+ case E_STR:
+ return Sprintf("%s", Str.data());
+ case E_KEY:
+ return Sprintf("key: %s", Str.data());
+ }
+ }
+ };
+
+ using TEvents = TVector<TEvent>;
+
+ struct TTestHandler : TJsonCallbacks {
+ TEvents Events;
+
+ bool OnOpenMap() override {
+ Events.push_back(E_DICT_OPEN);
+ return true;
+ }
+
+ bool OnCloseMap() override {
+ Events.push_back(E_DICT_CLOSE);
+ return true;
+ }
+
+ bool OnOpenArray() override {
+ Events.push_back(E_ARR_OPEN);
+ return true;
+ }
+
+ bool OnCloseArray() override {
+ Events.push_back(E_ARR_CLOSE);
+ return true;
+ }
+
+ bool OnNull() override {
+ Events.push_back(E_NULL);
+ return true;
+ }
+
+ bool OnBoolean(bool v) override {
+ Events.push_back(TEvent((i64)v, E_BOOL));
+ return true;
+ }
+
+ bool OnInteger(long long v) override {
+ Events.push_back(TEvent((i64)v, E_INT));
+ return true;
+ }
+
+ bool OnUInteger(unsigned long long v) override {
+ return OnInteger(v);
+ }
+
+ bool OnDouble(double v) override {
+ Events.push_back(TEvent(v, E_FLT));
+ return true;
+ }
+
+ bool OnString(const TStringBuf& v) override {
+ Events.push_back(TEvent(v, E_STR));
+ return true;
+ }
+
+ bool OnMapKey(const TStringBuf& v) override {
+ Events.push_back(TEvent(v, E_KEY));
+ return true;
+ }
+
+ void OnError(size_t, TStringBuf token) override {
+ Events.push_back(TEvent(token, E_ERROR));
+ }
+
+ void Assert(const TEvents& e, TString str) {
+ try {
+ UNIT_ASSERT_VALUES_EQUAL_C(e.size(), Events.size(), str);
+
+ for (ui32 i = 0, sz = e.size(); i < sz; ++i) {
+ UNIT_ASSERT_VALUES_EQUAL_C((int)e[i].Type, (int)Events[i].Type, Sprintf("'%s' %u", str.data(), i));
+ UNIT_ASSERT_VALUES_EQUAL_C(e[i].INum, Events[i].INum, Sprintf("'%s' %u", str.data(), i));
+ UNIT_ASSERT_VALUES_EQUAL_C(e[i].DNum, Events[i].DNum, Sprintf("'%s' %u", str.data(), i));
+ UNIT_ASSERT_VALUES_EQUAL_C(e[i].Str, Events[i].Str, Sprintf("'%s' %u", str.data(), i));
+ }
+ } catch (const yexception&) {
+ Clog << "Exception at '" << str << "'" << Endl;
+ for (const auto& event : Events) {
+ Clog << event.ToString() << Endl;
+ }
+
+ throw;
+ }
+ }
+ };
+ }
+}
+
+class TFastJsonTest: public TTestBase {
+ UNIT_TEST_SUITE(TFastJsonTest)
+ UNIT_TEST(TestParse)
+ UNIT_TEST(TestReadJsonFastTree)
+ UNIT_TEST(TestNoInlineComment)
+ UNIT_TEST_SUITE_END();
+
+public:
+ template <bool accept>
+ void DoTestParse(TStringBuf json, ui32 amount, ...) {
+ using namespace NJson::NTest;
+ TEvents evs;
+ va_list vl;
+ va_start(vl, amount);
+ for (ui32 i = 0; i < amount; i++) {
+ ETestEvent e = (ETestEvent)va_arg(vl, int);
+
+ switch ((int)e) {
+ case E_NO_EVENT:
+ case E_DICT_OPEN:
+ case E_DICT_CLOSE:
+ case E_ARR_OPEN:
+ case E_ARR_CLOSE:
+ case E_NULL:
+ evs.push_back(e);
+ break;
+ case E_BOOL: {
+ bool v = va_arg(vl, int);
+ evs.push_back(TEvent((i64)v, E_BOOL));
+ break;
+ }
+ case E_INT: {
+ i64 i = va_arg(vl, int);
+ evs.push_back(TEvent(i, E_INT));
+ break;
+ }
+ case E_LONG_LONG: {
+ i64 i = va_arg(vl, long long);
+ evs.push_back(TEvent(i, E_INT));
+ break;
+ }
+ case E_FLT: {
+ double f = va_arg(vl, double);
+ evs.push_back(TEvent(f, E_FLT));
+ break;
+ }
+ case E_STR: {
+ const char* s = va_arg(vl, const char*);
+ evs.push_back(TEvent(TStringBuf(s), E_STR));
+ break;
+ }
+ case E_KEY:
+ case E_ERROR: {
+ const char* s = va_arg(vl, const char*);
+ evs.push_back(TEvent(TStringBuf(s), e));
+ break;
+ }
+ }
+ }
+ va_end(vl);
+
+ TTestHandler h;
+ const bool res = ReadJsonFast(json, &h);
+ UNIT_ASSERT_VALUES_EQUAL_C(res, accept, Sprintf("%s (%s)", ToString(json).data(), h.Events.back().Str.data()));
+ h.Assert(evs, ToString(json));
+ }
+
+ void TestParse() {
+ using namespace NJson::NTest;
+
+ DoTestParse<true>("", 0);
+ DoTestParse<true>(" \t \t ", 0);
+ DoTestParse<true>("a-b-c@аб_вгд909AБ", 1, E_STR, "a-b-c@аб_вгд909AБ");
+ DoTestParse<true>("'я тестовая строка'", 1, E_STR, "я тестовая строка");
+ DoTestParse<true>("\"я тестовая строка\"", 1, E_STR, "я тестовая строка");
+ DoTestParse<true>("'\\xA\\xA\\xA'", 1, E_STR, "\n\n\n");
+ DoTestParse<true>("12.15", 1, E_FLT, 12.15);
+ DoTestParse<true>("null", 1, E_NULL);
+ DoTestParse<true>("true", 1, E_BOOL, true);
+ DoTestParse<true>("false", 1, E_BOOL, false);
+ DoTestParse<true>("[]", 2, E_ARR_OPEN, E_ARR_CLOSE);
+ DoTestParse<true>("[ a ]", 3, E_ARR_OPEN, E_STR, "a", E_ARR_CLOSE);
+ DoTestParse<true>("[ a, b ]", 4, E_ARR_OPEN, E_STR, "a", E_STR, "b", E_ARR_CLOSE);
+ DoTestParse<true>("[a,b]", 4, E_ARR_OPEN, E_STR, "a", E_STR, "b", E_ARR_CLOSE);
+ DoTestParse<false>("[a,b][a,b]", 5, E_ARR_OPEN, E_STR, "a", E_STR, "b", E_ARR_CLOSE, E_ERROR, "invalid syntax at token: '['");
+ DoTestParse<false>("[a,,b]", 3, E_ARR_OPEN, E_STR, "a", E_ERROR, "invalid syntax at token: ','");
+ DoTestParse<true>("{ k : v }", 4, E_DICT_OPEN, E_KEY, "k", E_STR, "v", E_DICT_CLOSE);
+ DoTestParse<true>("{a:'\\b'/*comment*/, k /*comment*/\n : v }", 6, E_DICT_OPEN, E_KEY, "a", E_STR, "\b", E_KEY, "k", E_STR, "v", E_DICT_CLOSE);
+ DoTestParse<true>("{a:.15, k : v }", 6, E_DICT_OPEN, E_KEY, "a", E_FLT, .15, E_KEY, "k", E_STR, "v", E_DICT_CLOSE);
+ DoTestParse<true>("[ a, -.1e+5, 1E-7]", 5, E_ARR_OPEN, E_STR, "a", E_FLT, -.1e+5, E_FLT, 1e-7, E_ARR_CLOSE);
+ DoTestParse<true>("{}", 2, E_DICT_OPEN, E_DICT_CLOSE);
+ DoTestParse<true>("{ a : x, b : [ c, d, ] }", 9, E_DICT_OPEN, E_KEY, "a", E_STR, "x", E_KEY, "b", E_ARR_OPEN, E_STR, "c", E_STR, "d", E_ARR_CLOSE, E_DICT_CLOSE);
+ DoTestParse<false>("{ a : x, b : [ c, d,, ] }", 8, E_DICT_OPEN, E_KEY, "a", E_STR, "x", E_KEY, "b", E_ARR_OPEN, E_STR, "c", E_STR, "d", E_ERROR, "invalid syntax at token: ','");
+ // DoTestParse<false>("{ a : x : y }", 4, E_DICT_OPEN
+ // , E_KEY, "a", E_STR, "x"
+ // , E_ERROR
+ // , ":");
+ // DoTestParse<false>("{queries:{ref:[]},{nonref:[]}}", 8, E_DICT_OPEN
+ // , E_KEY, "queries", E_DICT_OPEN
+ // , E_KEY, "ref", E_ARR_OPEN, E_ARR_CLOSE
+ // , E_DICT_CLOSE, E_ERROR, "");
+ DoTestParse<true>("'100x00'", 1, E_STR, "100x00");
+ DoTestParse<true>("-1", 1, E_INT, -1);
+ DoTestParse<true>("-9223372036854775808", 1, E_LONG_LONG, (long long)Min<i64>());
+ DoTestParse<false>("100x00", 1, E_ERROR, "invalid syntax at token: '100x'");
+ DoTestParse<false>("100 200", 2, E_INT, 100, E_ERROR, "invalid syntax at token: '200'");
+ DoTestParse<true>("{g:{x:{a:{b:c,e:f},q:{x:y}},y:fff}}", 22, E_DICT_OPEN, E_KEY, "g", E_DICT_OPEN, E_KEY, "x", E_DICT_OPEN, E_KEY, "a", E_DICT_OPEN, E_KEY, "b", E_STR, "c", E_KEY, "e", E_STR, "f", E_DICT_CLOSE, E_KEY, "q", E_DICT_OPEN, E_KEY, "x", E_STR, "y", E_DICT_CLOSE, E_DICT_CLOSE, E_KEY, "y", E_STR, "fff", E_DICT_CLOSE, E_DICT_CLOSE);
+ }
+
+ void TestReadJsonFastTree() {
+ const TString json = R"(
+ {
+ "a": {
+ "b": {}
+ }
+ }}
+ )";
+ NJson::TJsonValue value;
+ UNIT_ASSERT(!ReadJsonFastTree(json, &value));
+ }
+
+ void TestNoInlineComment() {
+ using namespace NJson::NTest;
+ DoTestParse<false>("{\"a\":1}//d{\"b\":2}", 5, E_DICT_OPEN, E_KEY, "a", E_INT, 1, E_DICT_CLOSE, E_ERROR, "invalid syntax at token: '/'");
+ DoTestParse<false>("{\"a\":1}//d{\"b\":2}\n", 5, E_DICT_OPEN, E_KEY, "a", E_INT, 1, E_DICT_CLOSE, E_ERROR, "invalid syntax at token: '/'");
+ DoTestParse<false>("{\"a\":{//d{\"b\":2}\n}}", 4, E_DICT_OPEN, E_KEY, "a", E_DICT_OPEN, E_ERROR, "invalid syntax at token: '/'");
+ DoTestParse<false>("{\"a\":{//d{\"b\":2}}}\n", 4, E_DICT_OPEN, E_KEY, "a", E_DICT_OPEN, E_ERROR, "invalid syntax at token: '/'");
+ DoTestParse<false>("{\"a\":{//d{\"b\":2}}}", 4, E_DICT_OPEN, E_KEY, "a", E_DICT_OPEN, E_ERROR, "invalid syntax at token: '/'");
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TFastJsonTest)
diff --git a/library/cpp/json/ut/json_reader_ut.cpp b/library/cpp/json/ut/json_reader_ut.cpp
new file mode 100644
index 0000000000..cd31afa0b8
--- /dev/null
+++ b/library/cpp/json/ut/json_reader_ut.cpp
@@ -0,0 +1,430 @@
+#include <library/cpp/json/json_reader.h>
+#include <library/cpp/json/json_writer.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/stream/str.h>
+
+using namespace NJson;
+
+class TReformatCallbacks: public TJsonCallbacks {
+ TJsonWriter& Writer;
+
+public:
+ TReformatCallbacks(TJsonWriter& writer)
+ : Writer(writer)
+ {
+ }
+
+ bool OnBoolean(bool val) override {
+ Writer.Write(val);
+ return true;
+ }
+
+ bool OnInteger(long long val) override {
+ Writer.Write(val);
+ return true;
+ }
+
+ bool OnUInteger(unsigned long long val) override {
+ Writer.Write(val);
+ return true;
+ }
+
+ bool OnString(const TStringBuf& val) override {
+ Writer.Write(val);
+ return true;
+ }
+
+ bool OnDouble(double val) override {
+ Writer.Write(val);
+ return true;
+ }
+
+ bool OnOpenArray() override {
+ Writer.OpenArray();
+ return true;
+ }
+
+ bool OnCloseArray() override {
+ Writer.CloseArray();
+ return true;
+ }
+
+ bool OnOpenMap() override {
+ Writer.OpenArray();
+ return true;
+ }
+
+ bool OnCloseMap() override {
+ Writer.CloseArray();
+ return true;
+ }
+
+ bool OnMapKey(const TStringBuf& val) override {
+ Writer.Write(val);
+ return true;
+ }
+};
+
+Y_UNIT_TEST_SUITE(TJsonReaderTest) {
+ Y_UNIT_TEST(JsonReformatTest) {
+ TString data = "{\"null value\": null, \"intkey\": 10, \"double key\": 11.11, \"string key\": \"string\", \"array\": [1,2,3,\"TString\"], \"bool key\": true}";
+
+ TString result1, result2;
+ {
+ TStringStream in;
+ in << data;
+ TStringStream out;
+ TJsonWriter writer(&out, false);
+ TReformatCallbacks cb(writer);
+ ReadJson(&in, &cb);
+ writer.Flush();
+ result1 = out.Str();
+ }
+
+ {
+ TStringStream in;
+ in << result1;
+ TStringStream out;
+ TJsonWriter writer(&out, false);
+ TReformatCallbacks cb(writer);
+ ReadJson(&in, &cb);
+ writer.Flush();
+ result2 = out.Str();
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(result1, result2);
+ }
+
+ Y_UNIT_TEST(TJsonEscapedApostrophe) {
+ TString jsonString = "{ \"foo\" : \"bar\\'buzz\" }";
+ {
+ TStringStream in;
+ in << jsonString;
+ TStringStream out;
+ TJsonWriter writer(&out, false);
+ TReformatCallbacks cb(writer);
+ UNIT_ASSERT(!ReadJson(&in, &cb));
+ }
+
+ {
+ TStringStream in;
+ in << jsonString;
+ TStringStream out;
+ TJsonWriter writer(&out, false);
+ TReformatCallbacks cb(writer);
+ UNIT_ASSERT(ReadJson(&in, false, true, &cb));
+ writer.Flush();
+ UNIT_ASSERT_EQUAL(out.Str(), "[\"foo\",\"bar'buzz\"]");
+ }
+ }
+
+ Y_UNIT_TEST(TJsonTreeTest) {
+ TString data = "{\"intkey\": 10, \"double key\": 11.11, \"null value\":null, \"string key\": \"string\", \"array\": [1,2,3,\"TString\"], \"bool key\": true}";
+ TStringStream in;
+ in << data;
+ TJsonValue value;
+ ReadJsonTree(&in, &value);
+
+ UNIT_ASSERT_VALUES_EQUAL(value["intkey"].GetInteger(), 10);
+ UNIT_ASSERT_DOUBLES_EQUAL(value["double key"].GetDouble(), 11.11, 0.001);
+ UNIT_ASSERT_VALUES_EQUAL(value["bool key"].GetBoolean(), true);
+ UNIT_ASSERT_VALUES_EQUAL(value["absent string key"].GetString(), TString(""));
+ UNIT_ASSERT_VALUES_EQUAL(value["string key"].GetString(), TString("string"));
+ UNIT_ASSERT_VALUES_EQUAL(value["array"][0].GetInteger(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(value["array"][1].GetInteger(), 2);
+ UNIT_ASSERT_VALUES_EQUAL(value["array"][2].GetInteger(), 3);
+ UNIT_ASSERT_VALUES_EQUAL(value["array"][3].GetString(), TString("TString"));
+ UNIT_ASSERT(value["null value"].IsNull());
+
+ // AsString
+ UNIT_ASSERT_VALUES_EQUAL(value["intkey"].GetStringRobust(), "10");
+ UNIT_ASSERT_VALUES_EQUAL(value["double key"].GetStringRobust(), "11.11");
+ UNIT_ASSERT_VALUES_EQUAL(value["bool key"].GetStringRobust(), "true");
+ UNIT_ASSERT_VALUES_EQUAL(value["string key"].GetStringRobust(), "string");
+ UNIT_ASSERT_VALUES_EQUAL(value["array"].GetStringRobust(), "[1,2,3,\"TString\"]");
+ UNIT_ASSERT_VALUES_EQUAL(value["null value"].GetStringRobust(), "null");
+
+ const TJsonValue::TArray* array;
+ UNIT_ASSERT(GetArrayPointer(value, "array", &array));
+ UNIT_ASSERT_VALUES_EQUAL(value["array"].GetArray().size(), array->size());
+ UNIT_ASSERT_VALUES_EQUAL(value["array"][0].GetInteger(), (*array)[0].GetInteger());
+ UNIT_ASSERT_VALUES_EQUAL(value["array"][1].GetInteger(), (*array)[1].GetInteger());
+ UNIT_ASSERT_VALUES_EQUAL(value["array"][2].GetInteger(), (*array)[2].GetInteger());
+ UNIT_ASSERT_VALUES_EQUAL(value["array"][3].GetString(), (*array)[3].GetString());
+ }
+
+ Y_UNIT_TEST(TJsonRomaTest) {
+ TString data = "{\"test\": [ {\"name\": \"A\"} ]}";
+
+ TStringStream in;
+ in << data;
+ TJsonValue value;
+ ReadJsonTree(&in, &value);
+
+ UNIT_ASSERT_VALUES_EQUAL(value["test"][0]["name"].GetString(), TString("A"));
+ }
+
+ Y_UNIT_TEST(TJsonReadTreeWithComments) {
+ {
+ TString leadingCommentData = "{ // \"test\" : 1 \n}";
+ {
+ // No comments allowed
+ TStringStream in;
+ in << leadingCommentData;
+ TJsonValue value;
+ UNIT_ASSERT(!ReadJsonTree(&in, false, &value));
+ }
+
+ {
+ // Comments allowed
+ TStringStream in;
+ in << leadingCommentData;
+ TJsonValue value;
+ UNIT_ASSERT(ReadJsonTree(&in, true, &value));
+ UNIT_ASSERT(!value.Has("test"));
+ }
+ }
+
+ {
+ TString trailingCommentData = "{ \"test1\" : 1 // \"test2\" : 2 \n }";
+ {
+ // No comments allowed
+ TStringStream in;
+ in << trailingCommentData;
+ TJsonValue value;
+ UNIT_ASSERT(!ReadJsonTree(&in, false, &value));
+ }
+
+ {
+ // Comments allowed
+ TStringStream in;
+ in << trailingCommentData;
+ TJsonValue value;
+ UNIT_ASSERT(ReadJsonTree(&in, true, &value));
+ UNIT_ASSERT(value.Has("test1"));
+ UNIT_ASSERT_EQUAL(value["test1"].GetInteger(), 1);
+ UNIT_ASSERT(!value.Has("test2"));
+ }
+ }
+ }
+
+ Y_UNIT_TEST(TJsonSignedIntegerTest) {
+ {
+ TStringStream in;
+ in << "{ \"test\" : " << Min<i64>() << " }";
+ TJsonValue value;
+ UNIT_ASSERT(ReadJsonTree(&in, &value));
+ UNIT_ASSERT(value.Has("test"));
+ UNIT_ASSERT(value["test"].IsInteger());
+ UNIT_ASSERT(!value["test"].IsUInteger());
+ UNIT_ASSERT_EQUAL(value["test"].GetInteger(), Min<i64>());
+ UNIT_ASSERT_EQUAL(value["test"].GetIntegerRobust(), Min<i64>());
+ } // Min<i64>()
+
+ {
+ TStringStream in;
+ in << "{ \"test\" : " << Max<i64>() + 1ull << " }";
+ TJsonValue value;
+ UNIT_ASSERT(ReadJsonTree(&in, &value));
+ UNIT_ASSERT(value.Has("test"));
+ UNIT_ASSERT(!value["test"].IsInteger());
+ UNIT_ASSERT(value["test"].IsUInteger());
+ UNIT_ASSERT_EQUAL(value["test"].GetIntegerRobust(), (i64)(Max<i64>() + 1ull));
+ } // Max<i64>() + 1
+ }
+
+ Y_UNIT_TEST(TJsonUnsignedIntegerTest) {
+ {
+ TStringStream in;
+ in << "{ \"test\" : 1 }";
+ TJsonValue value;
+ UNIT_ASSERT(ReadJsonTree(&in, &value));
+ UNIT_ASSERT(value.Has("test"));
+ UNIT_ASSERT(value["test"].IsInteger());
+ UNIT_ASSERT(value["test"].IsUInteger());
+ UNIT_ASSERT_EQUAL(value["test"].GetInteger(), 1);
+ UNIT_ASSERT_EQUAL(value["test"].GetIntegerRobust(), 1);
+ UNIT_ASSERT_EQUAL(value["test"].GetUInteger(), 1);
+ UNIT_ASSERT_EQUAL(value["test"].GetUIntegerRobust(), 1);
+ } // 1
+
+ {
+ TStringStream in;
+ in << "{ \"test\" : -1 }";
+ TJsonValue value;
+ UNIT_ASSERT(ReadJsonTree(&in, &value));
+ UNIT_ASSERT(value.Has("test"));
+ UNIT_ASSERT(value["test"].IsInteger());
+ UNIT_ASSERT(!value["test"].IsUInteger());
+ UNIT_ASSERT_EQUAL(value["test"].GetInteger(), -1);
+ UNIT_ASSERT_EQUAL(value["test"].GetIntegerRobust(), -1);
+ UNIT_ASSERT_EQUAL(value["test"].GetUInteger(), 0);
+ UNIT_ASSERT_EQUAL(value["test"].GetUIntegerRobust(), static_cast<unsigned long long>(-1));
+ } // -1
+
+ {
+ TStringStream in;
+ in << "{ \"test\" : 18446744073709551615 }";
+ TJsonValue value;
+ UNIT_ASSERT(ReadJsonTree(&in, &value));
+ UNIT_ASSERT(value.Has("test"));
+ UNIT_ASSERT(!value["test"].IsInteger());
+ UNIT_ASSERT(value["test"].IsUInteger());
+ UNIT_ASSERT_EQUAL(value["test"].GetInteger(), 0);
+ UNIT_ASSERT_EQUAL(value["test"].GetIntegerRobust(), static_cast<long long>(18446744073709551615ull));
+ UNIT_ASSERT_EQUAL(value["test"].GetUInteger(), 18446744073709551615ull);
+ UNIT_ASSERT_EQUAL(value["test"].GetUIntegerRobust(), 18446744073709551615ull);
+ } // 18446744073709551615
+
+ {
+ TStringStream in;
+ in << "{ \"test\" : 1.1 }";
+ TJsonValue value;
+ UNIT_ASSERT(ReadJsonTree(&in, &value));
+ UNIT_ASSERT(value.Has("test"));
+ UNIT_ASSERT(!value["test"].IsInteger());
+ UNIT_ASSERT(!value["test"].IsUInteger());
+ UNIT_ASSERT_EQUAL(value["test"].GetInteger(), 0);
+ UNIT_ASSERT_EQUAL(value["test"].GetIntegerRobust(), static_cast<long long>(1.1));
+ UNIT_ASSERT_EQUAL(value["test"].GetUInteger(), 0);
+ UNIT_ASSERT_EQUAL(value["test"].GetUIntegerRobust(), static_cast<unsigned long long>(1.1));
+ } // 1.1
+
+ {
+ TStringStream in;
+ in << "{ \"test\" : [1, 18446744073709551615] }";
+ TJsonValue value;
+ UNIT_ASSERT(ReadJsonTree(&in, &value));
+ UNIT_ASSERT(value.Has("test"));
+ UNIT_ASSERT(value["test"].IsArray());
+ UNIT_ASSERT_EQUAL(value["test"].GetArray().size(), 2);
+ UNIT_ASSERT(value["test"][0].IsInteger());
+ UNIT_ASSERT(value["test"][0].IsUInteger());
+ UNIT_ASSERT_EQUAL(value["test"][0].GetInteger(), 1);
+ UNIT_ASSERT_EQUAL(value["test"][0].GetUInteger(), 1);
+ UNIT_ASSERT(!value["test"][1].IsInteger());
+ UNIT_ASSERT(value["test"][1].IsUInteger());
+ UNIT_ASSERT_EQUAL(value["test"][1].GetUInteger(), 18446744073709551615ull);
+ }
+ } // TJsonUnsignedIntegerTest
+
+ Y_UNIT_TEST(TJsonDoubleTest) {
+ {
+ TStringStream in;
+ in << "{ \"test\" : 1.0 }";
+ TJsonValue value;
+ UNIT_ASSERT(ReadJsonTree(&in, &value));
+ UNIT_ASSERT(value.Has("test"));
+ UNIT_ASSERT(value["test"].IsDouble());
+ UNIT_ASSERT_EQUAL(value["test"].GetDouble(), 1.0);
+ UNIT_ASSERT_EQUAL(value["test"].GetDoubleRobust(), 1.0);
+ } // 1.0
+
+ {
+ TStringStream in;
+ in << "{ \"test\" : 1 }";
+ TJsonValue value;
+ UNIT_ASSERT(ReadJsonTree(&in, &value));
+ UNIT_ASSERT(value.Has("test"));
+ UNIT_ASSERT(value["test"].IsDouble());
+ UNIT_ASSERT_EQUAL(value["test"].GetDouble(), 1.0);
+ UNIT_ASSERT_EQUAL(value["test"].GetDoubleRobust(), 1.0);
+ } // 1
+
+ {
+ TStringStream in;
+ in << "{ \"test\" : -1 }";
+ TJsonValue value;
+ UNIT_ASSERT(ReadJsonTree(&in, &value));
+ UNIT_ASSERT(value.Has("test"));
+ UNIT_ASSERT(value["test"].IsDouble());
+ UNIT_ASSERT_EQUAL(value["test"].GetDouble(), -1.0);
+ UNIT_ASSERT_EQUAL(value["test"].GetDoubleRobust(), -1.0);
+ } // -1
+
+ {
+ TStringStream in;
+ in << "{ \"test\" : " << Max<ui64>() << " }";
+ TJsonValue value;
+ UNIT_ASSERT(ReadJsonTree(&in, &value));
+ UNIT_ASSERT(value.Has("test"));
+ UNIT_ASSERT(!value["test"].IsDouble());
+ UNIT_ASSERT_EQUAL(value["test"].GetDouble(), 0.0);
+ UNIT_ASSERT_EQUAL(value["test"].GetDoubleRobust(), static_cast<double>(Max<ui64>()));
+ } // Max<ui64>()
+ } // TJsonDoubleTest
+
+ Y_UNIT_TEST(TJsonInvalidTest) {
+ {
+ // No exceptions mode.
+ TStringStream in;
+ in << "{ \"test\" : }";
+ TJsonValue value;
+ UNIT_ASSERT(!ReadJsonTree(&in, &value));
+ }
+
+ {
+ // Exception throwing mode.
+ TStringStream in;
+ in << "{ \"test\" : }";
+ TJsonValue value;
+ UNIT_ASSERT_EXCEPTION(ReadJsonTree(&in, &value, true), TJsonException);
+ }
+ }
+
+ Y_UNIT_TEST(TJsonMemoryLeakTest) {
+ // after https://clubs.at.yandex-team.ru/stackoverflow/3691
+ TString s = ".";
+ NJson::TJsonValue json;
+ try {
+ TStringInput in(s);
+ NJson::ReadJsonTree(&in, &json, true);
+ } catch (...) {
+ }
+ } // TJsonMemoryLeakTest
+
+ Y_UNIT_TEST(TJsonDuplicateKeysWithNullValuesTest) {
+ const TString json = "{\"\":null,\"\":\"\"}";
+
+ TStringInput in(json);
+ NJson::TJsonValue v;
+ UNIT_ASSERT(ReadJsonTree(&in, &v));
+ UNIT_ASSERT(v.IsMap());
+ UNIT_ASSERT_VALUES_EQUAL(1, v.GetMap().size());
+ UNIT_ASSERT_VALUES_EQUAL("", v.GetMap().begin()->first);
+ UNIT_ASSERT(v.GetMap().begin()->second.IsString());
+ UNIT_ASSERT_VALUES_EQUAL("", v.GetMap().begin()->second.GetString());
+ }
+}
+
+
+static const TString YANDEX_STREAMING_JSON("{\"a\":1}//d{\"b\":2}");
+
+
+Y_UNIT_TEST_SUITE(TCompareReadJsonFast) {
+ Y_UNIT_TEST(NoEndl) {
+ NJson::TJsonValue parsed;
+
+ bool success = NJson::ReadJsonTree(YANDEX_STREAMING_JSON, &parsed, false);
+ bool fast_success = NJson::ReadJsonFastTree(YANDEX_STREAMING_JSON, &parsed, false);
+ UNIT_ASSERT(success == fast_success);
+ }
+ Y_UNIT_TEST(WithEndl) {
+ NJson::TJsonValue parsed1;
+ NJson::TJsonValue parsed2;
+
+ bool success = NJson::ReadJsonTree(YANDEX_STREAMING_JSON + "\n", &parsed1, false);
+ bool fast_success = NJson::ReadJsonFastTree(YANDEX_STREAMING_JSON + "\n", &parsed2, false);
+
+ UNIT_ASSERT_VALUES_EQUAL(success, fast_success);
+ }
+ Y_UNIT_TEST(NoQuotes) {
+ TString streamingJson = "{a:1}";
+ NJson::TJsonValue parsed;
+
+ bool success = NJson::ReadJsonTree(streamingJson, &parsed, false);
+ bool fast_success = NJson::ReadJsonFastTree(streamingJson, &parsed, false);
+ UNIT_ASSERT(success != fast_success);
+ }
+}
diff --git a/library/cpp/json/ut/json_saveload_ut.cpp b/library/cpp/json/ut/json_saveload_ut.cpp
new file mode 100644
index 0000000000..b480a80fe4
--- /dev/null
+++ b/library/cpp/json/ut/json_saveload_ut.cpp
@@ -0,0 +1,36 @@
+#include <library/cpp/json/json_value.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/stream/buffer.h>
+#include <util/generic/buffer.h>
+#include <util/ysaveload.h>
+
+Y_UNIT_TEST_SUITE(JsonSaveLoad) {
+ Y_UNIT_TEST(Serialize) {
+
+ NJson::TJsonValue expected;
+
+ expected["ui64"] = ui64(1);
+ expected["i64"] = i64(2);
+ expected["double"] = 2.0;
+ expected["string"] = "text";
+ expected["map"] = expected;
+ expected["array"].SetType(NJson::JSON_ARRAY).GetArraySafe().emplace_back(expected);
+ expected["null"].SetType(NJson::JSON_NULL);
+ expected["undefined"].SetType(NJson::JSON_UNDEFINED);
+
+ TBuffer buffer;
+ {
+ TBufferOutput output(buffer);
+ ::Save(&output, expected);
+ }
+
+ NJson::TJsonValue load;
+ {
+ TBufferInput input(buffer);
+ ::Load(&input, load);
+ }
+
+ UNIT_ASSERT_EQUAL_C(expected, load, "expected: " << expected << ", got: " << load);
+ }
+}
diff --git a/library/cpp/json/ut/json_writer_ut.cpp b/library/cpp/json/ut/json_writer_ut.cpp
new file mode 100644
index 0000000000..ca11d34dad
--- /dev/null
+++ b/library/cpp/json/ut/json_writer_ut.cpp
@@ -0,0 +1,228 @@
+#include <library/cpp/json/json_writer.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/str.h>
+
+using namespace NJson;
+
+Y_UNIT_TEST_SUITE(TJsonWriterTest) {
+ Y_UNIT_TEST(SimpleWriteTest) {
+ TString expected1 = "{\"key1\":1,\"key2\":2,\"key3\":3";
+ TString expected2 = expected1 + ",\"array\":[\"stroka\",false]";
+ TString expected3 = expected2 + "}";
+
+ TStringStream out;
+
+ TJsonWriter json(&out, false);
+ json.OpenMap();
+ json.Write("key1", (ui16)1);
+ json.WriteKey("key2");
+ json.Write((i32)2);
+ json.Write("key3", (ui64)3);
+
+ UNIT_ASSERT(out.Empty());
+ json.Flush();
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), expected1);
+
+ json.Write("array");
+ json.OpenArray();
+ json.Write("stroka");
+ json.Write(false);
+ json.CloseArray();
+
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), expected1);
+ json.Flush();
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), expected2);
+
+ json.CloseMap();
+
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), expected2);
+ json.Flush();
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), expected3);
+ }
+
+ Y_UNIT_TEST(SimpleWriteValueTest) {
+ TString expected = "{\"key1\":null,\"key2\":{\"subkey1\":[1,{\"subsubkey\":\"test2\"},null,true],\"subkey2\":\"test\"}}";
+ TJsonValue v;
+ v["key1"] = JSON_NULL;
+ v["key2"]["subkey1"].AppendValue(1);
+ v["key2"]["subkey1"].AppendValue(JSON_MAP)["subsubkey"] = "test2";
+ v["key2"]["subkey1"].AppendValue(JSON_NULL);
+ v["key2"]["subkey1"].AppendValue(true);
+ v["key2"]["subkey2"] = "test";
+ TStringStream out;
+ WriteJson(&out, &v);
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), expected);
+ }
+
+ Y_UNIT_TEST(FormatOutput) {
+ TString expected = "{\n \"key1\":null,\n \"key2\":\n {\n \"subkey1\":\n [\n 1,\n {\n \"subsubkey\":\"test2\"\n },\n null,\n true\n ],\n \"subkey2\":\"test\"\n }\n}";
+ TJsonValue v;
+ v["key1"] = JSON_NULL;
+ v["key2"]["subkey1"].AppendValue(1);
+ v["key2"]["subkey1"].AppendValue(JSON_MAP)["subsubkey"] = "test2";
+ v["key2"]["subkey1"].AppendValue(JSON_NULL);
+ v["key2"]["subkey1"].AppendValue(true);
+ v["key2"]["subkey2"] = "test";
+ TStringStream out;
+ WriteJson(&out, &v, true);
+ UNIT_ASSERT_STRINGS_EQUAL(out.Str(), expected);
+ }
+
+ Y_UNIT_TEST(SortKeys) {
+ TString expected = "{\"a\":null,\"j\":null,\"n\":null,\"y\":null,\"z\":null}";
+ TJsonValue v;
+ v["z"] = JSON_NULL;
+ v["n"] = JSON_NULL;
+ v["a"] = JSON_NULL;
+ v["y"] = JSON_NULL;
+ v["j"] = JSON_NULL;
+ TStringStream out;
+ WriteJson(&out, &v, false, true);
+ UNIT_ASSERT_STRINGS_EQUAL(out.Str(), expected);
+ }
+
+ Y_UNIT_TEST(SimpleUnsignedIntegerWriteTest) {
+ {
+ TString expected = "{\"test\":1}";
+ TJsonValue v;
+ v.InsertValue("test", 1ull);
+ TStringStream out;
+ WriteJson(&out, &v);
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), expected);
+ } // 1
+
+ {
+ TString expected = "{\"test\":-1}";
+ TJsonValue v;
+ v.InsertValue("test", -1);
+ TStringStream out;
+ WriteJson(&out, &v);
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), expected);
+ } // -1
+
+ {
+ TString expected = "{\"test\":18446744073709551615}";
+ TJsonValue v;
+ v.InsertValue("test", 18446744073709551615ull);
+ TStringStream out;
+ WriteJson(&out, &v);
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), expected);
+ } // 18446744073709551615
+
+ {
+ TString expected = "{\"test\":[1,18446744073709551615]}";
+ TJsonValue v;
+ v.InsertValue("test", TJsonValue());
+ v["test"].AppendValue(1);
+ v["test"].AppendValue(18446744073709551615ull);
+ TStringStream out;
+ WriteJson(&out, &v);
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), expected);
+ } // 18446744073709551615
+ } // SimpleUnsignedIntegerWriteTest
+
+ Y_UNIT_TEST(WriteOptionalTest) {
+ {
+ TString expected = "{\"test\":1}";
+
+ TStringStream out;
+
+ TJsonWriter json(&out, false);
+ json.OpenMap();
+ json.WriteOptional("test", MakeMaybe<int>(1));
+ json.CloseMap();
+ json.Flush();
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), expected);
+ }
+
+ {
+ TString expected = "{}";
+
+ TStringStream out;
+
+ TMaybe<int> nothing = Nothing();
+
+ TJsonWriter json(&out, false);
+ json.OpenMap();
+ json.WriteOptional("test", nothing);
+ json.CloseMap();
+ json.Flush();
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), expected);
+ }
+
+ {
+ TString expected = "{}";
+
+ TStringStream out;
+
+ TMaybe<int> empty;
+
+ TJsonWriter json(&out, false);
+ json.OpenMap();
+ json.WriteOptional("test", empty);
+ json.CloseMap();
+ json.Flush();
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), expected);
+ }
+
+ {
+ TString expected = "{}";
+
+ TStringStream out;
+
+ TJsonWriter json(&out, false);
+ json.OpenMap();
+ json.WriteOptional("test", Nothing());
+ json.CloseMap();
+ json.Flush();
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), expected);
+ }
+ }
+
+ Y_UNIT_TEST(Callback) {
+ NJsonWriter::TBuf json;
+ json.WriteString("A");
+ UNIT_ASSERT_VALUES_EQUAL(json.Str(), "\"A\"");
+ UNIT_ASSERT_VALUES_EQUAL(WrapJsonToCallback(json, ""), "\"A\"");
+ UNIT_ASSERT_VALUES_EQUAL(WrapJsonToCallback(json, "Foo"), "Foo(\"A\")");
+ }
+
+ Y_UNIT_TEST(FloatPrecision) {
+ const double value = 1517933989.4242;
+ const NJson::TJsonValue json(value);
+ NJson::TJsonWriterConfig config;
+ {
+ TString expected = "1517933989";
+ TString actual = NJson::WriteJson(json);
+ UNIT_ASSERT_VALUES_EQUAL(actual, expected);
+ }
+ {
+ TString expected = "1517933989";
+
+ TStringStream ss;
+ NJson::WriteJson(&ss, &json, config);
+ TString actual = ss.Str();
+ UNIT_ASSERT_VALUES_EQUAL(actual, expected);
+ }
+ {
+ config.DoubleNDigits = 13;
+ TString expected = "1517933989.424";
+
+ TStringStream ss;
+ NJson::WriteJson(&ss, &json, config);
+ TString actual = ss.Str();
+ UNIT_ASSERT_VALUES_EQUAL(actual, expected);
+ }
+ {
+ config.DoubleNDigits = 6;
+ config.FloatToStringMode = PREC_POINT_DIGITS;
+ TString expected = "1517933989.424200";
+
+ TStringStream ss;
+ NJson::WriteJson(&ss, &json, config);
+ TString actual = ss.Str();
+ UNIT_ASSERT_VALUES_EQUAL(actual, expected);
+ }
+ }
+}
diff --git a/library/cpp/json/ut/ya.make b/library/cpp/json/ut/ya.make
new file mode 100644
index 0000000000..8e0362d84b
--- /dev/null
+++ b/library/cpp/json/ut/ya.make
@@ -0,0 +1,17 @@
+OWNER(velavokr)
+
+UNITTEST_FOR(library/cpp/json)
+
+PEERDIR(
+ library/cpp/string_utils/relaxed_escaper
+)
+
+SRCS(
+ json_reader_fast_ut.cpp
+ json_reader_ut.cpp
+ json_prettifier_ut.cpp
+ json_writer_ut.cpp
+ json_saveload_ut.cpp
+)
+
+END()
diff --git a/library/cpp/json/writer/README b/library/cpp/json/writer/README
new file mode 100644
index 0000000000..a20489f32e
--- /dev/null
+++ b/library/cpp/json/writer/README
@@ -0,0 +1,23 @@
+JSON writer with no external dependencies, producing output
+where HTML special characters are always escaped.
+
+Use it like this:
+
+ #include <library/cpp/json/writer/json.h>
+ ...
+
+ NJsonWriter::TBuf json;
+ json.BeginList()
+ .WriteString("<script>")
+ .EndList();
+ Cout << json.Str(); // output: ["\u003Cscript\u003E"]
+
+For compatibility with legacy formats where object keys
+are not quoted, use CompatWriteKeyWithoutQuotes:
+
+ NJsonWriter::TBuf json;
+ json.BeginObject()
+ .CompatWriteKeyWithoutQuotes("r").WriteInt(1)
+ .CompatWriteKeyWithoutQuotes("n").WriteInt(0)
+ .EndObject();
+ Cout << json.Str(); // output: {r:1,n:0}
diff --git a/library/cpp/json/writer/json.cpp b/library/cpp/json/writer/json.cpp
new file mode 100644
index 0000000000..02370c2d79
--- /dev/null
+++ b/library/cpp/json/writer/json.cpp
@@ -0,0 +1,517 @@
+#include "json.h"
+
+#include <library/cpp/json/json_value.h>
+
+#include <util/string/cast.h>
+#include <util/string/strspn.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/ymath.h>
+#include <util/generic/singleton.h>
+
+namespace NJsonWriter {
+ TBuf::TBuf(EHtmlEscapeMode mode, IOutputStream* stream)
+ : Stream(stream)
+ , NeedComma(false)
+ , NeedNewline(false)
+ , EscapeMode(mode)
+ , IndentSpaces(0)
+ , WriteNanAsString(false)
+ {
+ Y_ASSERT(mode == HEM_DONT_ESCAPE_HTML ||
+ mode == HEM_ESCAPE_HTML ||
+ mode == HEM_RELAXED ||
+ mode == HEM_UNSAFE);
+ if (!Stream) {
+ StringStream.Reset(new TStringStream);
+ Stream = StringStream.Get();
+ }
+
+ Stack.reserve(64); // should be enough for most cases
+ StackPush(JE_OUTER_SPACE);
+ }
+
+ static const char* EntityToStr(EJsonEntity e) {
+ switch (e) {
+ case JE_OUTER_SPACE:
+ return "JE_OUTER_SPACE";
+ case JE_LIST:
+ return "JE_LIST";
+ case JE_OBJECT:
+ return "JE_OBJECT";
+ case JE_PAIR:
+ return "JE_PAIR";
+ default:
+ return "JE_unknown";
+ }
+ }
+
+ inline void TBuf::StackPush(EJsonEntity e) {
+ Stack.push_back(e);
+ }
+
+ inline EJsonEntity TBuf::StackTop() const {
+ return Stack.back();
+ }
+
+ inline void TBuf::StackPop() {
+ Y_ASSERT(!Stack.empty());
+ const EJsonEntity current = StackTop();
+ Stack.pop_back();
+ switch (current) {
+ case JE_OUTER_SPACE:
+ ythrow TError() << "JSON writer: stack empty";
+ case JE_LIST:
+ PrintIndentation(true);
+ RawWriteChar(']');
+ break;
+ case JE_OBJECT:
+ PrintIndentation(true);
+ RawWriteChar('}');
+ break;
+ case JE_PAIR:
+ break;
+ }
+ NeedComma = true;
+ NeedNewline = true;
+ }
+
+ inline void TBuf::CheckAndPop(EJsonEntity e) {
+ if (Y_UNLIKELY(StackTop() != e)) {
+ ythrow TError() << "JSON writer: unexpected value "
+ << EntityToStr(StackTop()) << " on the stack";
+ }
+ StackPop();
+ }
+
+ void TBuf::PrintIndentation(bool closing) {
+ if (!IndentSpaces)
+ return;
+ const int indentation = IndentSpaces * (Stack.size() - 1);
+ if (!indentation && !closing)
+ return;
+
+ PrintWhitespaces(Max(0, indentation), true);
+ }
+
+ void TBuf::PrintWhitespaces(size_t count, bool prependWithNewLine) {
+ static constexpr TStringBuf whitespacesTemplate = "\n ";
+ static_assert(whitespacesTemplate[0] == '\n');
+ static_assert(whitespacesTemplate[1] == ' ');
+
+ count += (prependWithNewLine);
+ do {
+ const TStringBuf buffer = whitespacesTemplate.SubString(prependWithNewLine ? 0 : 1, count);
+ count -= buffer.size();
+ UnsafeWriteRawBytes(buffer);
+ prependWithNewLine = false; // skip '\n' in subsequent writes
+ } while (count > 0);
+ }
+
+ inline void TBuf::WriteComma() {
+ if (NeedComma) {
+ RawWriteChar(',');
+ }
+ NeedComma = true;
+
+ if (NeedNewline) {
+ PrintIndentation(false);
+ }
+ NeedNewline = true;
+ }
+
+ inline void TBuf::BeginValue() {
+ if (Y_UNLIKELY(KeyExpected())) {
+ ythrow TError() << "JSON writer: value written, "
+ "but expected a key:value pair";
+ }
+ WriteComma();
+ }
+
+ inline void TBuf::BeginKey() {
+ if (Y_UNLIKELY(!KeyExpected())) {
+ ythrow TError() << "JSON writer: key written outside of an object";
+ }
+ WriteComma();
+ StackPush(JE_PAIR);
+ NeedComma = false;
+ NeedNewline = false;
+ }
+
+ inline void TBuf::EndValue() {
+ if (StackTop() == JE_PAIR) {
+ StackPop();
+ }
+ }
+
+ TValueContext TBuf::BeginList() {
+ NeedNewline = true;
+ BeginValue();
+ RawWriteChar('[');
+ StackPush(JE_LIST);
+ NeedComma = false;
+ return TValueContext(*this);
+ }
+
+ TPairContext TBuf::BeginObject() {
+ NeedNewline = true;
+ BeginValue();
+ RawWriteChar('{');
+ StackPush(JE_OBJECT);
+ NeedComma = false;
+ return TPairContext(*this);
+ }
+
+ TAfterColonContext TBuf::UnsafeWriteKey(const TStringBuf& s) {
+ BeginKey();
+ RawWriteChar('"');
+ UnsafeWriteRawBytes(s);
+ UnsafeWriteRawBytes("\":", 2);
+ return TAfterColonContext(*this);
+ }
+
+ TAfterColonContext TBuf::WriteKey(const TStringBuf& s) {
+ // use the default escaping mode for this object
+ return WriteKey(s, EscapeMode);
+ }
+
+ TAfterColonContext TBuf::WriteKey(const TStringBuf& s, EHtmlEscapeMode hem) {
+ BeginKey();
+ WriteBareString(s, hem);
+ RawWriteChar(':');
+ return TAfterColonContext(*this);
+ }
+
+ TAfterColonContext TBuf::CompatWriteKeyWithoutQuotes(const TStringBuf& s) {
+ BeginKey();
+ Y_ASSERT(AllOf(s, [](char x) { return 'a' <= x && x <= 'z'; }));
+ UnsafeWriteRawBytes(s);
+ RawWriteChar(':');
+ return TAfterColonContext(*this);
+ }
+
+ TBuf& TBuf::EndList() {
+ CheckAndPop(JE_LIST);
+ EndValue();
+ return *this;
+ }
+
+ TBuf& TBuf::EndObject() {
+ CheckAndPop(JE_OBJECT);
+ EndValue();
+ return *this;
+ }
+
+ TValueContext TBuf::WriteString(const TStringBuf& s) {
+ // use the default escaping mode for this object
+ return WriteString(s, EscapeMode);
+ }
+
+ TValueContext TBuf::WriteString(const TStringBuf& s, EHtmlEscapeMode hem) {
+ BeginValue();
+ WriteBareString(s, hem);
+ EndValue();
+ return TValueContext(*this);
+ }
+
+ TValueContext TBuf::WriteNull() {
+ UnsafeWriteValue(TStringBuf("null"));
+ return TValueContext(*this);
+ }
+
+ TValueContext TBuf::WriteBool(bool b) {
+ constexpr TStringBuf trueVal = "true";
+ constexpr TStringBuf falseVal = "false";
+ UnsafeWriteValue(b ? trueVal : falseVal);
+ return TValueContext(*this);
+ }
+
+ TValueContext TBuf::WriteInt(int i) {
+ char buf[22]; // enough to hold any 64-bit number
+ size_t len = ToString(i, buf, sizeof(buf));
+ UnsafeWriteValue(buf, len);
+ return TValueContext(*this);
+ }
+
+ TValueContext TBuf::WriteLongLong(long long i) {
+ static_assert(sizeof(long long) <= 8, "expect sizeof(long long) <= 8");
+ char buf[22]; // enough to hold any 64-bit number
+ size_t len = ToString(i, buf, sizeof(buf));
+ UnsafeWriteValue(buf, len);
+ return TValueContext(*this);
+ }
+
+ TValueContext TBuf::WriteULongLong(unsigned long long i) {
+ char buf[22]; // enough to hold any 64-bit number
+ size_t len = ToString(i, buf, sizeof(buf));
+ UnsafeWriteValue(buf, len);
+ return TValueContext(*this);
+ }
+
+ template <class TFloat>
+ TValueContext TBuf::WriteFloatImpl(TFloat f, EFloatToStringMode mode, int ndigits) {
+ char buf[512]; // enough to hold most floats, the same buffer is used in FloatToString implementation
+ if (Y_UNLIKELY(!IsValidFloat(f))) {
+ if (WriteNanAsString) {
+ const size_t size = FloatToString(f, buf, Y_ARRAY_SIZE(buf));
+ WriteString(TStringBuf(buf, size));
+ return TValueContext(*this);
+ } else {
+ ythrow TError() << "JSON writer: invalid float value: " << FloatToString(f);
+ }
+ }
+ size_t len = FloatToString(f, buf, Y_ARRAY_SIZE(buf), mode, ndigits);
+ UnsafeWriteValue(buf, len);
+ return TValueContext(*this);
+ }
+
+ TValueContext TBuf::WriteFloat(float f, EFloatToStringMode mode, int ndigits) {
+ return WriteFloatImpl(f, mode, ndigits);
+ }
+
+ TValueContext TBuf::WriteDouble(double f, EFloatToStringMode mode, int ndigits) {
+ return WriteFloatImpl(f, mode, ndigits);
+ }
+
+ namespace {
+ struct TFinder: public TCompactStrSpn {
+ inline TFinder()
+ : TCompactStrSpn("\xe2\\\"\b\n\f\r\t<>&\'/")
+ {
+ for (ui8 ch = 0; ch < 0x20; ++ch) {
+ Set(ch);
+ }
+ }
+ };
+ }
+
+ inline void TBuf::WriteBareString(const TStringBuf s, EHtmlEscapeMode hem) {
+ RawWriteChar('"');
+ const auto& specialChars = *Singleton<TFinder>();
+ const char* b = s.begin();
+ const char* e = s.end();
+ const char* i = b;
+ while ((i = specialChars.FindFirstOf(i, e)) != e) {
+ // U+2028 (line separator) and U+2029 (paragraph separator) are valid string
+ // contents in JSON, but are treated as line breaks in JavaScript, breaking JSONP.
+ // In UTF-8, U+2028 is "\xe2\x80\xa8" and U+2029 is "\xe2\x80\xa9".
+ if (Y_UNLIKELY(e - i >= 3 && i[0] == '\xe2' && i[1] == '\x80' && (i[2] | 1) == '\xa9')) {
+ UnsafeWriteRawBytes(b, i - b);
+ UnsafeWriteRawBytes(i[2] == '\xa9' ? "\\u2029" : "\\u2028", 6);
+ b = i = i + 3;
+ } else if (EscapedWriteChar(b, i, hem)) {
+ b = ++i;
+ } else {
+ ++i;
+ }
+ }
+ UnsafeWriteRawBytes(b, e - b);
+ RawWriteChar('"');
+ }
+
+ inline void TBuf::RawWriteChar(char c) {
+ Stream->Write(c);
+ }
+
+ void TBuf::WriteHexEscape(unsigned char c) {
+ Y_ASSERT(c < 0x80);
+ UnsafeWriteRawBytes("\\u00", 4);
+ static const char hexDigits[] = "0123456789ABCDEF";
+ RawWriteChar(hexDigits[(c & 0xf0) >> 4]);
+ RawWriteChar(hexDigits[(c & 0x0f)]);
+ }
+
+#define MATCH(sym, string) \
+ case sym: \
+ UnsafeWriteRawBytes(beg, cur - beg); \
+ UnsafeWriteRawBytes(TStringBuf(string)); \
+ return true
+
+ inline bool TBuf::EscapedWriteChar(const char* beg, const char* cur, EHtmlEscapeMode hem) {
+ unsigned char c = *cur;
+ if (hem == HEM_ESCAPE_HTML) {
+ switch (c) {
+ MATCH('"', "&quot;");
+ MATCH('\'', "&#39;");
+ MATCH('<', "&lt;");
+ MATCH('>', "&gt;");
+ MATCH('&', "&amp;");
+ }
+ //for other characters, we fall through to the non-HTML-escaped part
+ }
+
+ if (hem == HEM_RELAXED && c == '/')
+ return false;
+
+ if (hem != HEM_UNSAFE) {
+ switch (c) {
+ case '/':
+ UnsafeWriteRawBytes(beg, cur - beg);
+ UnsafeWriteRawBytes("\\/", 2);
+ return true;
+ case '<':
+ case '>':
+ case '\'':
+ UnsafeWriteRawBytes(beg, cur - beg);
+ WriteHexEscape(c);
+ return true;
+ }
+ // for other characters, fall through to the non-escaped part
+ }
+
+ switch (c) {
+ MATCH('"', "\\\"");
+ MATCH('\\', "\\\\");
+ MATCH('\b', "\\b");
+ MATCH('\f', "\\f");
+ MATCH('\n', "\\n");
+ MATCH('\r', "\\r");
+ MATCH('\t', "\\t");
+ }
+ if (c < 0x20) {
+ UnsafeWriteRawBytes(beg, cur - beg);
+ WriteHexEscape(c);
+ return true;
+ }
+
+ return false;
+ }
+
+#undef MATCH
+
+ static bool LessStrPtr(const TString* a, const TString* b) {
+ return *a < *b;
+ }
+
+ TValueContext TBuf::WriteJsonValue(const NJson::TJsonValue* v, bool sortKeys, EFloatToStringMode mode, int ndigits) {
+ using namespace NJson;
+ switch (v->GetType()) {
+ default:
+ case JSON_NULL:
+ WriteNull();
+ break;
+ case JSON_BOOLEAN:
+ WriteBool(v->GetBoolean());
+ break;
+ case JSON_DOUBLE:
+ WriteDouble(v->GetDouble(), mode, ndigits);
+ break;
+ case JSON_INTEGER:
+ WriteLongLong(v->GetInteger());
+ break;
+ case JSON_UINTEGER:
+ WriteULongLong(v->GetUInteger());
+ break;
+ case JSON_STRING:
+ WriteString(v->GetString());
+ break;
+ case JSON_ARRAY: {
+ BeginList();
+ const TJsonValue::TArray& arr = v->GetArray();
+ for (const auto& it : arr)
+ WriteJsonValue(&it, sortKeys, mode, ndigits);
+ EndList();
+ break;
+ }
+ case JSON_MAP: {
+ BeginObject();
+ const TJsonValue::TMapType& map = v->GetMap();
+ if (sortKeys) {
+ const size_t oldsz = Keys.size();
+ Keys.reserve(map.size() + oldsz);
+ for (const auto& it : map) {
+ Keys.push_back(&(it.first));
+ }
+ Sort(Keys.begin() + oldsz, Keys.end(), LessStrPtr);
+ for (size_t i = oldsz, sz = Keys.size(); i < sz; ++i) {
+ TJsonValue::TMapType::const_iterator kv = map.find(*Keys[i]);
+ WriteKey(kv->first);
+ WriteJsonValue(&kv->second, sortKeys, mode, ndigits);
+ }
+ Keys.resize(oldsz);
+ } else {
+ for (const auto& it : map) {
+ WriteKey(it.first);
+ WriteJsonValue(&it.second, sortKeys, mode, ndigits);
+ }
+ }
+ EndObject();
+ break;
+ }
+ }
+ return TValueContext(*this);
+ }
+
+ TPairContext TBuf::UnsafeWritePair(const TStringBuf& s) {
+ if (Y_UNLIKELY(StackTop() != JE_OBJECT)) {
+ ythrow TError() << "JSON writer: key:value pair written outside of an object";
+ }
+ WriteComma();
+ UnsafeWriteRawBytes(s);
+ return TPairContext(*this);
+ }
+
+ void TBuf::UnsafeWriteValue(const TStringBuf& s) {
+ BeginValue();
+ UnsafeWriteRawBytes(s);
+ EndValue();
+ }
+
+ void TBuf::UnsafeWriteValue(const char* s, size_t len) {
+ BeginValue();
+ UnsafeWriteRawBytes(s, len);
+ EndValue();
+ }
+
+ void TBuf::UnsafeWriteRawBytes(const char* src, size_t len) {
+ Stream->Write(src, len);
+ }
+
+ void TBuf::UnsafeWriteRawBytes(const TStringBuf& s) {
+ UnsafeWriteRawBytes(s.data(), s.size());
+ }
+
+ const TString& TBuf::Str() const {
+ if (!StringStream) {
+ ythrow TError() << "JSON writer: Str() called "
+ "but writing to an external stream";
+ }
+ if (!(Stack.size() == 1 && StackTop() == JE_OUTER_SPACE)) {
+ ythrow TError() << "JSON writer: incomplete object converted to string";
+ }
+ return StringStream->Str();
+ }
+
+ void TBuf::FlushTo(IOutputStream* stream) {
+ if (!StringStream) {
+ ythrow TError() << "JSON writer: FlushTo() called "
+ "but writing to an external stream";
+ }
+ stream->Write(StringStream->Str());
+ StringStream->Clear();
+ }
+
+ TString WrapJsonToCallback(const TBuf& buf, TStringBuf callback) {
+ if (!callback) {
+ return buf.Str();
+ } else {
+ return TString::Join(callback, "(", buf.Str(), ")");
+ }
+ }
+
+ TBufState TBuf::State() const {
+ return TBufState{NeedComma, NeedNewline, Stack};
+ }
+
+ void TBuf::Reset(const TBufState& from) {
+ NeedComma = from.NeedComma;
+ NeedNewline = from.NeedNewline;
+ Stack = from.Stack;
+ }
+
+ void TBuf::Reset(TBufState&& from) {
+ NeedComma = from.NeedComma;
+ NeedNewline = from.NeedNewline;
+ Stack.swap(from.Stack);
+ }
+
+}
diff --git a/library/cpp/json/writer/json.h b/library/cpp/json/writer/json.h
new file mode 100644
index 0000000000..0aae2531b9
--- /dev/null
+++ b/library/cpp/json/writer/json.h
@@ -0,0 +1,289 @@
+#pragma once
+
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+#include <util/stream/str.h>
+#include <util/string/cast.h>
+
+namespace NJson {
+ class TJsonValue;
+}
+
+namespace NJsonWriter {
+ enum EJsonEntity : ui8 {
+ JE_OUTER_SPACE = 1,
+ JE_LIST,
+ JE_OBJECT,
+ JE_PAIR,
+ };
+
+ enum EHtmlEscapeMode {
+ HEM_ESCAPE_HTML = 1, // Use HTML escaping: &lt; &gt; &amp; \/
+ HEM_DONT_ESCAPE_HTML, // Use JSON escaping: \u003C \u003E \u0026 \/
+ HEM_RELAXED, // Use JSON escaping: \u003C \u003E \u0026 /
+ HEM_UNSAFE, // Turn escaping off: < > & /
+ };
+
+ class TError: public yexception {};
+
+ class TValueContext;
+ class TPairContext;
+ class TAfterColonContext;
+
+ struct TBufState {
+ bool NeedComma;
+ bool NeedNewline;
+ TVector<EJsonEntity> Stack;
+ };
+
+ class TBuf : TNonCopyable {
+ public:
+ TBuf(EHtmlEscapeMode mode = HEM_DONT_ESCAPE_HTML, IOutputStream* stream = nullptr);
+
+ TValueContext WriteString(const TStringBuf& s, EHtmlEscapeMode hem);
+ TValueContext WriteString(const TStringBuf& s);
+ TValueContext WriteInt(int i);
+ TValueContext WriteLongLong(long long i);
+ TValueContext WriteULongLong(unsigned long long i);
+ TValueContext WriteFloat(float f, EFloatToStringMode mode = PREC_NDIGITS, int ndigits = 6);
+ TValueContext WriteDouble(double f, EFloatToStringMode mode = PREC_NDIGITS, int ndigits = 10);
+ TValueContext WriteBool(bool b);
+ TValueContext WriteNull();
+ TValueContext WriteJsonValue(const NJson::TJsonValue* value, bool sortKeys = false, EFloatToStringMode mode = PREC_NDIGITS, int ndigits = 10);
+
+ TValueContext BeginList();
+ TBuf& EndList();
+
+ TPairContext BeginObject();
+ TAfterColonContext WriteKey(const TStringBuf& key, EHtmlEscapeMode hem);
+ TAfterColonContext WriteKey(const TStringBuf& key);
+ TAfterColonContext UnsafeWriteKey(const TStringBuf& key);
+ bool KeyExpected() const {
+ return Stack.back() == JE_OBJECT;
+ }
+
+ //! deprecated, do not use in new code
+ TAfterColonContext CompatWriteKeyWithoutQuotes(const TStringBuf& key);
+
+ TBuf& EndObject();
+
+ /*** Indent the resulting JSON with spaces.
+ * By default (spaces==0) no formatting is done. */
+ TBuf& SetIndentSpaces(int spaces) {
+ IndentSpaces = spaces;
+ return *this;
+ }
+
+ /*** NaN and Inf are not valid json values,
+ * so if WriteNanAsString is set, writer would write string
+ * intead of throwing exception (default case) */
+ TBuf& SetWriteNanAsString(bool writeNanAsString = true) {
+ WriteNanAsString = writeNanAsString;
+ return *this;
+ }
+
+ /*** Return the string formed in the internal TStringStream.
+ * You may only call it if the `stream' parameter was NULL
+ * at construction time. */
+ const TString& Str() const;
+
+ /*** Dump and forget the string constructed so far.
+ * You may only call it if the `stream' parameter was NULL
+ * at construction time. */
+ void FlushTo(IOutputStream* stream);
+
+ /*** Write a literal string that represents a JSON value
+ * (string, number, object, array, bool, or null).
+ *
+ * Example:
+ * j.UnsafeWriteValue("[1, 2, 3, \"o'clock\", 4, \"o'clock rock\"]");
+ *
+ * As in all of the Unsafe* functions, no escaping is done. */
+ void UnsafeWriteValue(const TStringBuf& s);
+ void UnsafeWriteValue(const char* s, size_t len);
+
+ /*** When in the context of an object, write a literal string
+ * that represents a key:value pair (or several pairs).
+ *
+ * Example:
+ * j.BeginObject();
+ * j.UnsafeWritePair("\"adam\": \"male\", \"eve\": \"female\"");
+ * j.EndObject();
+ *
+ * As in all of the Unsafe* functions, no escaping is done. */
+ TPairContext UnsafeWritePair(const TStringBuf& s);
+
+ /*** Copy the supplied string directly into the output stream. */
+ void UnsafeWriteRawBytes(const TStringBuf& s);
+ void UnsafeWriteRawBytes(const char* c, size_t len);
+
+ TBufState State() const;
+ void Reset(const TBufState& from);
+ void Reset(TBufState&& from);
+
+ private:
+ void BeginValue();
+ void EndValue();
+ void BeginKey();
+ void RawWriteChar(char c);
+ bool EscapedWriteChar(const char* b, const char* c, EHtmlEscapeMode hem);
+ void WriteBareString(const TStringBuf s, EHtmlEscapeMode hem);
+ void WriteComma();
+ void PrintIndentation(bool closing);
+ void PrintWhitespaces(size_t count, bool prependWithNewLine);
+ void WriteHexEscape(unsigned char c);
+
+ void StackPush(EJsonEntity e);
+ void StackPop();
+ void CheckAndPop(EJsonEntity e);
+ EJsonEntity StackTop() const;
+
+ template <class TFloat>
+ TValueContext WriteFloatImpl(TFloat f, EFloatToStringMode mode, int ndigits);
+
+ private:
+ IOutputStream* Stream;
+ THolder<TStringStream> StringStream;
+ typedef TVector<const TString*> TKeys;
+ TKeys Keys;
+
+ TVector<EJsonEntity> Stack;
+ bool NeedComma;
+ bool NeedNewline;
+ const EHtmlEscapeMode EscapeMode;
+ int IndentSpaces;
+ bool WriteNanAsString;
+ };
+
+ // Please don't try to instantiate the classes declared below this point.
+
+ template <typename TOutContext>
+ class TValueWriter {
+ public:
+ TOutContext WriteNull();
+ TOutContext WriteString(const TStringBuf&);
+ TOutContext WriteString(const TStringBuf& s, EHtmlEscapeMode hem);
+ TOutContext WriteInt(int);
+ TOutContext WriteLongLong(long long);
+ TOutContext WriteULongLong(unsigned long long);
+ TOutContext WriteBool(bool);
+ TOutContext WriteFloat(float);
+ TOutContext WriteFloat(float, EFloatToStringMode, int ndigits);
+ TOutContext WriteDouble(double);
+ TOutContext WriteDouble(double, EFloatToStringMode, int ndigits);
+ TOutContext WriteJsonValue(const NJson::TJsonValue* value, bool sortKeys = false);
+ TOutContext UnsafeWriteValue(const TStringBuf&);
+
+ TValueContext BeginList();
+ TPairContext BeginObject();
+
+ protected:
+ TValueWriter(TBuf& buf)
+ : Buf(buf)
+ {
+ }
+ friend class TBuf;
+
+ protected:
+ TBuf& Buf;
+ };
+
+ class TValueContext: public TValueWriter<TValueContext> {
+ public:
+ TBuf& EndList() {
+ return Buf.EndList();
+ }
+ TString Str() const {
+ return Buf.Str();
+ }
+
+ private:
+ TValueContext(TBuf& buf)
+ : TValueWriter<TValueContext>(buf)
+ {
+ }
+ friend class TBuf;
+ friend class TValueWriter<TValueContext>;
+ };
+
+ class TAfterColonContext: public TValueWriter<TPairContext> {
+ private:
+ TAfterColonContext(TBuf& iBuf)
+ : TValueWriter<TPairContext>(iBuf)
+ {
+ }
+ friend class TBuf;
+ friend class TPairContext;
+ };
+
+ class TPairContext {
+ public:
+ TAfterColonContext WriteKey(const TStringBuf& s, EHtmlEscapeMode hem) {
+ return Buf.WriteKey(s, hem);
+ }
+ TAfterColonContext WriteKey(const TStringBuf& s) {
+ return Buf.WriteKey(s);
+ }
+ TAfterColonContext UnsafeWriteKey(const TStringBuf& s) {
+ return Buf.UnsafeWriteKey(s);
+ }
+ TAfterColonContext CompatWriteKeyWithoutQuotes(const TStringBuf& s) {
+ return Buf.CompatWriteKeyWithoutQuotes(s);
+ }
+ TPairContext UnsafeWritePair(const TStringBuf& s) {
+ return Buf.UnsafeWritePair(s);
+ }
+ TBuf& EndObject() {
+ return Buf.EndObject();
+ }
+
+ private:
+ TPairContext(TBuf& buf)
+ : Buf(buf)
+ {
+ }
+
+ friend class TBuf;
+ friend class TValueWriter<TPairContext>;
+
+ private:
+ TBuf& Buf;
+ };
+
+#define JSON_VALUE_WRITER_WRAP(function, params, args) \
+ template <typename TOutContext> \
+ TOutContext TValueWriter<TOutContext>::function params { \
+ Buf.function args; \
+ return TOutContext(Buf); \
+ }
+
+ JSON_VALUE_WRITER_WRAP(WriteNull, (), ())
+ JSON_VALUE_WRITER_WRAP(WriteString, (const TStringBuf& arg), (arg))
+ JSON_VALUE_WRITER_WRAP(WriteString, (const TStringBuf& s, EHtmlEscapeMode hem), (s, hem))
+ JSON_VALUE_WRITER_WRAP(WriteInt, (int arg), (arg))
+ JSON_VALUE_WRITER_WRAP(WriteLongLong, (long long arg), (arg))
+ JSON_VALUE_WRITER_WRAP(WriteULongLong, (unsigned long long arg), (arg))
+ JSON_VALUE_WRITER_WRAP(WriteBool, (bool arg), (arg))
+ JSON_VALUE_WRITER_WRAP(WriteFloat, (float arg), (arg))
+ JSON_VALUE_WRITER_WRAP(WriteFloat, (float arg, EFloatToStringMode mode, int ndigits), (arg, mode, ndigits))
+ JSON_VALUE_WRITER_WRAP(WriteDouble, (double arg), (arg))
+ JSON_VALUE_WRITER_WRAP(WriteDouble, (double arg, EFloatToStringMode mode, int ndigits), (arg, mode, ndigits))
+ JSON_VALUE_WRITER_WRAP(WriteJsonValue, (const NJson::TJsonValue* value, bool sortKeys), (value, sortKeys))
+ JSON_VALUE_WRITER_WRAP(UnsafeWriteValue, (const TStringBuf& arg), (arg))
+#undef JSON_VALUE_WRITER_WRAP
+
+ template <typename TOutContext>
+ TValueContext TValueWriter<TOutContext>::BeginList() {
+ return Buf.BeginList();
+ }
+
+ template <typename TOutContext>
+ TPairContext TValueWriter<TOutContext>::BeginObject() {
+ return Buf.BeginObject();
+ }
+
+ TString WrapJsonToCallback(const TBuf& buf, TStringBuf callback);
+}
diff --git a/library/cpp/json/writer/json_ut.cpp b/library/cpp/json/writer/json_ut.cpp
new file mode 100644
index 0000000000..9980555683
--- /dev/null
+++ b/library/cpp/json/writer/json_ut.cpp
@@ -0,0 +1,307 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/system/sanitizers.h>
+
+#include "json.h"
+#include <library/cpp/json/json_value.h>
+
+#include <limits>
+
+Y_UNIT_TEST_SUITE(JsonWriter) {
+ Y_UNIT_TEST(Struct) {
+ NJsonWriter::TBuf w;
+ w.BeginList();
+ w.BeginObject()
+ .WriteKey("key")
+ .WriteString("value")
+ .UnsafeWritePair("\"xk\":13")
+ .WriteKey("key2")
+ .BeginList()
+ .BeginObject()
+ .EndObject()
+ .BeginObject()
+ .EndObject()
+ .EndList()
+ .EndObject();
+ w.WriteInt(43);
+ w.UnsafeWriteValue("\"x\"");
+ w.WriteString("...");
+ w.EndList();
+ const char* exp = "[{\"key\":\"value\",\"xk\":13,\"key2\":[{},{}]},43,\"x\",\"...\"]";
+ UNIT_ASSERT_EQUAL(w.Str(), exp);
+ }
+ Y_UNIT_TEST(EscapedString) {
+ NJsonWriter::TBuf w(NJsonWriter::HEM_ESCAPE_HTML);
+ w.WriteString(" \n \r \t \007 \b \f ' <tag> &ent; \"txt\" ");
+ TString ws = w.Str();
+ const char* exp = "\" \\n \\r \\t \\u0007 \\b \\f &#39; &lt;tag&gt; &amp;ent; &quot;txt&quot; \"";
+ UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp);
+ }
+ Y_UNIT_TEST(UnescapedString) {
+ NJsonWriter::TBuf w;
+ w.WriteString(" \n \r \t \b \f '; -- <tag> &ent; \"txt\"", NJsonWriter::HEM_DONT_ESCAPE_HTML);
+ TString ws = w.Str();
+ const char* exp = "\" \\n \\r \\t \\b \\f \\u0027; -- \\u003Ctag\\u003E &ent; \\\"txt\\\"\"";
+ UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp);
+ }
+ Y_UNIT_TEST(UnescapedChaining) {
+ NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML);
+ w.UnsafeWriteRawBytes("(", 1);
+ w.BeginList().WriteString("<>&'\\").BeginList();
+ w.EndList().EndList();
+ TString ws = w.Str();
+ const char* exp = "([\"\\u003C\\u003E&\\u0027\\\\\",[]]";
+ UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp);
+ }
+ Y_UNIT_TEST(Utf8) {
+ TString ws = NJsonWriter::TBuf().WriteString("яЯ σΣ ש א").Str();
+ const char* exp = "\"яЯ σΣ ש א\"";
+ UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp);
+ }
+ Y_UNIT_TEST(WrongObject) {
+ NJsonWriter::TBuf w;
+ w.BeginObject();
+ UNIT_ASSERT_EXCEPTION(w.WriteString("hehe"), NJsonWriter::TError);
+ }
+ Y_UNIT_TEST(WrongList) {
+ NJsonWriter::TBuf w;
+ w.BeginList();
+ UNIT_ASSERT_EXCEPTION(w.WriteKey("hehe"), NJsonWriter::TError);
+ }
+ Y_UNIT_TEST(Incomplete) {
+ NJsonWriter::TBuf w;
+ w.BeginList();
+ UNIT_ASSERT_EXCEPTION(w.Str(), NJsonWriter::TError);
+ }
+ Y_UNIT_TEST(BareKey) {
+ NJsonWriter::TBuf w;
+ w.BeginObject()
+ .CompatWriteKeyWithoutQuotes("p")
+ .WriteInt(1)
+ .CompatWriteKeyWithoutQuotes("n")
+ .WriteInt(0)
+ .EndObject();
+ TString ws = w.Str();
+ const char* exp = "{p:1,n:0}";
+ UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp);
+ }
+ Y_UNIT_TEST(UnescapedStringInObject) {
+ NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML);
+ w.BeginObject().WriteKey("key").WriteString("</&>'").EndObject();
+ TString ws = w.Str();
+ const char* exp = "{\"key\":\"\\u003C\\/&\\u003E\\u0027\"}";
+ UNIT_ASSERT_STRINGS_EQUAL(ws.c_str(), exp);
+ }
+ Y_UNIT_TEST(ForeignStreamStr) {
+ NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML, &Cerr);
+ UNIT_ASSERT_EXCEPTION(w.Str(), NJsonWriter::TError);
+ }
+ Y_UNIT_TEST(ForeignStreamValue) {
+ TStringStream ss;
+ NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML, &ss);
+ w.WriteInt(1543);
+ UNIT_ASSERT_STRINGS_EQUAL(ss.Str(), "1543");
+ }
+ Y_UNIT_TEST(Indentation) {
+ NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML);
+ w.SetIndentSpaces(2);
+ w.BeginList()
+ .WriteInt(1)
+ .WriteString("hello")
+ .BeginObject()
+ .WriteKey("abc")
+ .WriteInt(3)
+ .WriteKey("def")
+ .WriteInt(4)
+ .EndObject()
+ .EndList();
+ const char* exp = "[\n"
+ " 1,\n"
+ " \"hello\",\n"
+ " {\n"
+ " \"abc\":3,\n"
+ " \"def\":4\n"
+ " }\n"
+ "]";
+ UNIT_ASSERT_STRINGS_EQUAL(exp, w.Str());
+ }
+ Y_UNIT_TEST(WriteJsonValue) {
+ using namespace NJson;
+ TJsonValue val;
+ val.AppendValue(1);
+ val.AppendValue("2");
+ val.AppendValue(3.5);
+ TJsonValue obj;
+ obj.InsertValue("key", TJsonValue("value"));
+
+ val.AppendValue(obj);
+ val.AppendValue(TJsonValue(JSON_NULL));
+
+ NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML);
+ w.WriteJsonValue(&val);
+
+ const char exp[] = "[1,\"2\",3.5,{\"key\":\"value\"},null]";
+ UNIT_ASSERT_STRINGS_EQUAL(exp, w.Str());
+ }
+ Y_UNIT_TEST(WriteJsonValueSorted) {
+ using namespace NJson;
+ TJsonValue val;
+ val.InsertValue("1", TJsonValue(1));
+ val.InsertValue("2", TJsonValue(2));
+
+ TJsonValue obj;
+ obj.InsertValue("zero", TJsonValue(0));
+ obj.InsertValue("succ", TJsonValue(1));
+ val.InsertValue("0", obj);
+
+ NJsonWriter::TBuf w(NJsonWriter::HEM_DONT_ESCAPE_HTML);
+ w.WriteJsonValue(&val, true);
+
+ const char exp[] = "{\"0\":{\"succ\":1,\"zero\":0},\"1\":1,\"2\":2}";
+ UNIT_ASSERT_STRINGS_EQUAL(exp, w.Str());
+ }
+ Y_UNIT_TEST(Unescaped) {
+ NJsonWriter::TBuf buf(NJsonWriter::HEM_UNSAFE);
+ buf.WriteString("</security>'");
+ UNIT_ASSERT_STRINGS_EQUAL("\"</security>'\"", buf.Str());
+ }
+ Y_UNIT_TEST(LittleBobbyJsonp) {
+ NJsonWriter::TBuf buf;
+ buf.WriteString("hello\xe2\x80\xa8\xe2\x80\xa9stranger");
+ UNIT_ASSERT_STRINGS_EQUAL("\"hello\\u2028\\u2029stranger\"", buf.Str());
+ }
+ Y_UNIT_TEST(LittleBobbyInvalid) {
+ NJsonWriter::TBuf buf;
+ TStringBuf incomplete("\xe2\x80\xa8", 2);
+ buf.WriteString(incomplete);
+ // garbage in - garbage out
+ UNIT_ASSERT_STRINGS_EQUAL("\"\xe2\x80\"", buf.Str());
+ }
+ Y_UNIT_TEST(OverlyZealous) {
+ NJsonWriter::TBuf buf;
+ buf.WriteString("—");
+ UNIT_ASSERT_STRINGS_EQUAL("\"—\"", buf.Str());
+ }
+ Y_UNIT_TEST(RelaxedEscaping) {
+ NJsonWriter::TBuf buf(NJsonWriter::HEM_RELAXED);
+ buf.WriteString("</>");
+ UNIT_ASSERT_STRINGS_EQUAL("\"\\u003C/\\u003E\"", buf.Str());
+ }
+
+ Y_UNIT_TEST(FloatFormatting) {
+ NJsonWriter::TBuf buf(NJsonWriter::HEM_DONT_ESCAPE_HTML);
+ buf.BeginList()
+ .WriteFloat(0.12345678987654321f)
+ .WriteDouble(0.12345678987654321)
+ .WriteFloat(0.315501, PREC_NDIGITS, 3)
+ .WriteFloat(244.13854, PREC_NDIGITS, 4)
+ .WriteFloat(10385.8324, PREC_POINT_DIGITS, 2)
+ .BeginObject()
+ .WriteKey("1")
+ .WriteDouble(1111.71, PREC_POINT_DIGITS, 0)
+ .WriteKey("2")
+ .WriteDouble(1111.71, PREC_NDIGITS, 1)
+ .EndObject()
+ .EndList();
+ const char exp[] = "[0.123457,0.1234567899,0.316,244.1,10385.83,{\"1\":1112,\"2\":1e+03}]";
+ UNIT_ASSERT_STRINGS_EQUAL(exp, buf.Str());
+ }
+
+ Y_UNIT_TEST(NanFormatting) {
+ {
+ NJsonWriter::TBuf buf;
+ buf.BeginObject();
+ buf.WriteKey("nanvalue");
+ UNIT_ASSERT_EXCEPTION(buf.WriteFloat(std::numeric_limits<double>::quiet_NaN()), yexception);
+ }
+
+ {
+ NJsonWriter::TBuf buf;
+ buf.BeginObject();
+ buf.WriteKey("infvalue");
+ UNIT_ASSERT_EXCEPTION(buf.WriteFloat(std::numeric_limits<double>::infinity()), yexception);
+ }
+
+ {
+ NJsonWriter::TBuf buf;
+ buf.BeginList();
+ UNIT_ASSERT_EXCEPTION(buf.WriteFloat(std::numeric_limits<double>::quiet_NaN()), yexception);
+ }
+
+ {
+ NJsonWriter::TBuf buf;
+ buf.BeginList();
+ UNIT_ASSERT_EXCEPTION(buf.WriteFloat(std::numeric_limits<double>::infinity()), yexception);
+ }
+
+ {
+ NJsonWriter::TBuf buf;
+ buf.SetWriteNanAsString();
+
+ buf.BeginObject()
+ .WriteKey("nanvalue")
+ .WriteFloat(std::numeric_limits<double>::quiet_NaN())
+ .WriteKey("infvalue")
+ .WriteFloat(std::numeric_limits<double>::infinity())
+ .WriteKey("minus_infvalue")
+ .WriteFloat(-std::numeric_limits<float>::infinity())
+ .WriteKey("l")
+ .BeginList()
+ .WriteFloat(std::numeric_limits<float>::quiet_NaN())
+ .EndList()
+ .EndObject();
+
+ UNIT_ASSERT_STRINGS_EQUAL(buf.Str(), R"raw_json({"nanvalue":"nan","infvalue":"inf","minus_infvalue":"-inf","l":["nan"]})raw_json");
+ }
+
+ {
+ NJsonWriter::TBuf buf;
+ buf.BeginObject()
+ .WriteKey("<>&")
+ .WriteString("Ololo")
+ .UnsafeWriteKey("<>&")
+ .WriteString("Ololo2")
+ .EndObject();
+
+ UNIT_ASSERT_STRINGS_EQUAL(buf.Str(), R"({"\u003C\u003E&":"Ololo","<>&":"Ololo2"})");
+ }
+ }
+
+ Y_UNIT_TEST(WriteUninitializedBoolDoesntCrashProgram) {
+ // makes sense only in release build w/ address sanitizer
+ //
+ // passing uninitialized boolean into WriteBool can make cleverly optimized code which is emitted by compiler crash program
+ // https://stackoverflow.com/questions/54120862/does-the-c-standard-allow-for-an-uninitialized-bool-to-crash-a-program
+
+ // looks like compiler can detect UB at compile time in simple cases, but not in this one
+ class TSensorConf {
+ public:
+ class TAggrRuleItem {
+ public:
+ TVector<TString> Cond;
+ TVector<TString> Target;
+ };
+
+ TString ToString() const {
+ NJson::TJsonValue jsonValue;
+ NJsonWriter::TBuf jsonOutput;
+ jsonOutput.BeginObject()
+ .WriteKey("rawDataMemOnly").WriteBool(RawDataMemOnly)
+ .WriteKey("aggrRules").BeginList();
+
+ jsonOutput.EndList()
+ .EndObject();
+
+ return jsonOutput.Str();
+ }
+
+ TVector<TAggrRuleItem> AggrRules;
+ bool RawDataMemOnly;
+ };
+
+ TSensorConf s;
+ NSan::Unpoison(&s.RawDataMemOnly, sizeof(s.RawDataMemOnly));
+ auto p = s.ToString();
+ // doesn't really matter
+ UNIT_ASSERT(!p.empty());
+ }
+}
diff --git a/library/cpp/json/writer/json_value.cpp b/library/cpp/json/writer/json_value.cpp
new file mode 100644
index 0000000000..c61e8d1dc4
--- /dev/null
+++ b/library/cpp/json/writer/json_value.cpp
@@ -0,0 +1,1105 @@
+#include "json_value.h"
+#include "json.h"
+
+#include <util/generic/ymath.h>
+#include <util/generic/ylimits.h>
+#include <util/generic/utility.h>
+#include <util/generic/singleton.h>
+#include <util/stream/str.h>
+#include <util/stream/output.h>
+#include <util/string/cast.h>
+#include <util/string/type.h>
+#include <util/string/vector.h>
+#include <util/system/yassert.h>
+#include <util/ysaveload.h>
+#include <util/generic/bt_exception.h>
+
+static bool
+AreJsonMapsEqual(const NJson::TJsonValue& lhs, const NJson::TJsonValue& rhs) {
+ using namespace NJson;
+
+ Y_VERIFY(lhs.GetType() == JSON_MAP, "lhs has not a JSON_MAP type.");
+
+ if (rhs.GetType() != JSON_MAP)
+ return false;
+
+ typedef TJsonValue::TMapType TMapType;
+ const TMapType& lhsMap = lhs.GetMap();
+ const TMapType& rhsMap = rhs.GetMap();
+
+ if (lhsMap.size() != rhsMap.size())
+ return false;
+
+ for (const auto& lhsIt : lhsMap) {
+ TMapType::const_iterator rhsIt = rhsMap.find(lhsIt.first);
+ if (rhsIt == rhsMap.end())
+ return false;
+
+ if (lhsIt.second != rhsIt->second)
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+AreJsonArraysEqual(const NJson::TJsonValue& lhs, const NJson::TJsonValue& rhs) {
+ using namespace NJson;
+
+ Y_VERIFY(lhs.GetType() == JSON_ARRAY, "lhs has not a JSON_ARRAY type.");
+
+ if (rhs.GetType() != JSON_ARRAY)
+ return false;
+
+ typedef TJsonValue::TArray TArray;
+ const TArray& lhsArray = lhs.GetArray();
+ const TArray& rhsArray = rhs.GetArray();
+
+ if (lhsArray.size() != rhsArray.size())
+ return false;
+
+ for (TArray::const_iterator lhsIt = lhsArray.begin(), rhsIt = rhsArray.begin();
+ lhsIt != lhsArray.end(); ++lhsIt, ++rhsIt) {
+ if (*lhsIt != *rhsIt)
+ return false;
+ }
+
+ return true;
+}
+
+namespace NJson {
+ const TJsonValue TJsonValue::UNDEFINED{};
+
+ TJsonValue::TJsonValue(const EJsonValueType type) {
+ SetType(type);
+ }
+
+ TJsonValue::TJsonValue(TJsonValue&& vval) noexcept
+ : Type(JSON_UNDEFINED)
+ {
+ vval.SwapWithUndefined(*this);
+ Zero(vval.Value);
+ }
+
+ TJsonValue::TJsonValue(const TJsonValue& val)
+ : Type(val.Type)
+ {
+ switch (Type) {
+ case JSON_STRING:
+ new (&Value.String) TString(val.GetString());
+ break;
+ case JSON_MAP:
+ Value.Map = new TMapType(val.GetMap());
+ break;
+ case JSON_ARRAY:
+ Value.Array = new TArray(val.GetArray());
+ break;
+ case JSON_UNDEFINED:
+ case JSON_NULL:
+ case JSON_BOOLEAN:
+ case JSON_INTEGER:
+ case JSON_UINTEGER:
+ case JSON_DOUBLE:
+ std::memcpy(&Value, &val.Value, sizeof(Value));
+ break;
+ }
+ }
+
+ TJsonValue& TJsonValue::operator=(const TJsonValue& val) {
+ if (this == &val)
+ return *this;
+ TJsonValue tmp(val);
+ tmp.Swap(*this);
+ return *this;
+ }
+
+ TJsonValue& TJsonValue::operator=(TJsonValue&& val) noexcept {
+ if (this == &val)
+ return *this;
+ TJsonValue tmp(std::move(val));
+ tmp.Swap(*this);
+ return *this;
+ }
+
+ TJsonValue::TJsonValue(const bool value) noexcept {
+ SetType(JSON_BOOLEAN);
+ Value.Boolean = value;
+ }
+
+ TJsonValue::TJsonValue(const long long value) noexcept {
+ SetType(JSON_INTEGER);
+ Value.Integer = value;
+ }
+
+ TJsonValue::TJsonValue(const unsigned long long value) noexcept {
+ SetType(JSON_UINTEGER);
+ Value.UInteger = value;
+ }
+
+ TJsonValue::TJsonValue(const int value) noexcept {
+ SetType(JSON_INTEGER);
+ Value.Integer = value;
+ }
+
+ TJsonValue::TJsonValue(const unsigned int value) noexcept {
+ SetType(JSON_UINTEGER);
+ Value.UInteger = value;
+ }
+
+ TJsonValue::TJsonValue(const long value) noexcept {
+ SetType(JSON_INTEGER);
+ Value.Integer = value;
+ }
+
+ TJsonValue::TJsonValue(const unsigned long value) noexcept {
+ SetType(JSON_UINTEGER);
+ Value.UInteger = value;
+ }
+
+ TJsonValue::TJsonValue(const double value) noexcept {
+ SetType(JSON_DOUBLE);
+ Value.Double = value;
+ }
+
+ TJsonValue::TJsonValue(TString value) {
+ SetType(JSON_STRING);
+ Value.String = std::move(value);
+ }
+
+ TJsonValue::TJsonValue(const TStringBuf value) {
+ SetType(JSON_STRING);
+ Value.String = value;
+ }
+
+ TJsonValue::TJsonValue(const char* value) {
+ SetType(JSON_STRING);
+ Value.String = value;
+ }
+
+ EJsonValueType TJsonValue::GetType() const noexcept {
+ return Type;
+ }
+
+ TJsonValue& TJsonValue::SetType(const EJsonValueType type) {
+ if (Type == type)
+ return *this;
+
+ Clear();
+ Type = type;
+
+ switch (Type) {
+ case JSON_STRING:
+ new (&Value.String) TString();
+ break;
+ case JSON_MAP:
+ Value.Map = new TMapType();
+ break;
+ case JSON_ARRAY:
+ Value.Array = new TArray();
+ break;
+ case JSON_UNDEFINED:
+ case JSON_NULL:
+ case JSON_BOOLEAN:
+ case JSON_INTEGER:
+ case JSON_UINTEGER:
+ case JSON_DOUBLE:
+ break;
+ }
+
+ return *this;
+ }
+
+ TJsonValue& TJsonValue::SetValue(const TJsonValue& value) {
+ return *this = value;
+ }
+
+ TJsonValue& TJsonValue::SetValue(TJsonValue&& value) {
+ *this = std::move(value);
+ return *this;
+ }
+
+ TJsonValue& TJsonValue::InsertValue(const TString& key, const TJsonValue& value) {
+ SetType(JSON_MAP);
+ return (*Value.Map)[key] = value;
+ }
+
+ TJsonValue& TJsonValue::InsertValue(const TStringBuf key, const TJsonValue& value) {
+ SetType(JSON_MAP);
+ return (*Value.Map)[key] = value;
+ }
+
+ TJsonValue& TJsonValue::InsertValue(const char* key, const TJsonValue& value) {
+ SetType(JSON_MAP);
+ return (*Value.Map)[key] = value;
+ }
+
+ TJsonValue& TJsonValue::InsertValue(const TString& key, TJsonValue&& value) {
+ SetType(JSON_MAP);
+ return (*Value.Map)[key] = std::move(value);
+ }
+
+ TJsonValue& TJsonValue::InsertValue(const TStringBuf key, TJsonValue&& value) {
+ SetType(JSON_MAP);
+ return (*Value.Map)[key] = std::move(value);
+ }
+
+ TJsonValue& TJsonValue::InsertValue(const char* key, TJsonValue&& value) {
+ SetType(JSON_MAP);
+ return (*Value.Map)[key] = std::move(value);
+ }
+
+ TJsonValue& TJsonValue::Back() {
+ BackChecks();
+ return Value.Array->back();
+ }
+
+ const TJsonValue& TJsonValue::Back() const {
+ BackChecks();
+ return Value.Array->back();
+ }
+
+ TJsonValue& TJsonValue::AppendValue(const TJsonValue& value) {
+ SetType(JSON_ARRAY);
+ Value.Array->push_back(value);
+ return Value.Array->back();
+ }
+
+ TJsonValue& TJsonValue::AppendValue(TJsonValue&& value) {
+ SetType(JSON_ARRAY);
+ Value.Array->push_back(std::move(value));
+ return Value.Array->back();
+ }
+
+ void TJsonValue::EraseValue(const TStringBuf key) {
+ if (IsMap()) {
+ TMapType::iterator it = Value.Map->find(key);
+ if (it != Value.Map->end())
+ Value.Map->erase(it);
+ }
+ }
+
+ void TJsonValue::EraseValue(const size_t index) {
+ if (IsArray()) {
+ if (index >= Value.Array->size()) {
+ return;
+ }
+ TArray::iterator it = Value.Array->begin() + index;
+ Value.Array->erase(it);
+ }
+ }
+
+ void TJsonValue::Clear() noexcept {
+ switch (Type) {
+ case JSON_STRING:
+ Value.String.~TString();
+ break;
+ case JSON_MAP:
+ delete Value.Map;
+ break;
+ case JSON_ARRAY:
+ delete Value.Array;
+ break;
+ case JSON_UNDEFINED:
+ case JSON_NULL:
+ case JSON_BOOLEAN:
+ case JSON_INTEGER:
+ case JSON_UINTEGER:
+ case JSON_DOUBLE:
+ break;
+ }
+ Zero(Value);
+ Type = JSON_UNDEFINED;
+ }
+
+ TJsonValue& TJsonValue::operator[](const size_t idx) {
+ SetType(JSON_ARRAY);
+ if (Value.Array->size() <= idx)
+ Value.Array->resize(idx + 1);
+ return (*Value.Array)[idx];
+ }
+
+ TJsonValue& TJsonValue::operator[](const TStringBuf& key) {
+ SetType(JSON_MAP);
+ return (*Value.Map)[key];
+ }
+
+ namespace {
+ struct TDefaultsHolder {
+ const TString String{};
+ const TJsonValue::TMapType Map{};
+ const TJsonValue::TArray Array{};
+ const TJsonValue Value{};
+ };
+ }
+
+ const TJsonValue& TJsonValue::operator[](const size_t idx) const noexcept {
+ const TJsonValue* ret = nullptr;
+ if (GetValuePointer(idx, &ret))
+ return *ret;
+
+ return Singleton<TDefaultsHolder>()->Value;
+ }
+
+ const TJsonValue& TJsonValue::operator[](const TStringBuf& key) const noexcept {
+ const TJsonValue* ret = nullptr;
+ if (GetValuePointer(key, &ret))
+ return *ret;
+
+ return Singleton<TDefaultsHolder>()->Value;
+ }
+
+ bool TJsonValue::GetBoolean() const {
+ return Type != JSON_BOOLEAN ? false : Value.Boolean;
+ }
+
+ long long TJsonValue::GetInteger() const {
+ if (!IsInteger())
+ return 0;
+
+ switch (Type) {
+ case JSON_INTEGER:
+ return Value.Integer;
+
+ case JSON_UINTEGER:
+ return Value.UInteger;
+
+ case JSON_DOUBLE:
+ return Value.Double;
+
+ default:
+ Y_ASSERT(false && "Unexpected type.");
+ return 0;
+ }
+ }
+
+ unsigned long long TJsonValue::GetUInteger() const {
+ if (!IsUInteger())
+ return 0;
+
+ switch (Type) {
+ case JSON_UINTEGER:
+ return Value.UInteger;
+
+ case JSON_INTEGER:
+ return Value.Integer;
+
+ case JSON_DOUBLE:
+ return Value.Double;
+
+ default:
+ Y_ASSERT(false && "Unexpected type.");
+ return 0;
+ }
+ }
+
+ double TJsonValue::GetDouble() const {
+ if (!IsDouble())
+ return 0.0;
+
+ switch (Type) {
+ case JSON_DOUBLE:
+ return Value.Double;
+
+ case JSON_INTEGER:
+ return Value.Integer;
+
+ case JSON_UINTEGER:
+ return Value.UInteger;
+
+ default:
+ Y_ASSERT(false && "Unexpected type.");
+ return 0.0;
+ }
+ }
+
+ const TString& TJsonValue::GetString() const {
+ return Type != JSON_STRING ? Singleton<TDefaultsHolder>()->String : Value.String;
+ }
+
+ const TJsonValue::TMapType& TJsonValue::GetMap() const {
+ return Type != JSON_MAP ? Singleton<TDefaultsHolder>()->Map : *Value.Map;
+ }
+
+ const TJsonValue::TArray& TJsonValue::GetArray() const {
+ return (Type != JSON_ARRAY) ? Singleton<TDefaultsHolder>()->Array : *Value.Array;
+ }
+
+ bool TJsonValue::GetBooleanSafe() const {
+ if (Type != JSON_BOOLEAN)
+ ythrow TJsonException() << "Not a boolean";
+
+ return Value.Boolean;
+ }
+
+ long long TJsonValue::GetIntegerSafe() const {
+ if (!IsInteger())
+ ythrow TJsonException() << "Not an integer";
+
+ return GetInteger();
+ }
+
+ unsigned long long TJsonValue::GetUIntegerSafe() const {
+ if (!IsUInteger())
+ ythrow TJsonException() << "Not an unsigned integer";
+
+ return GetUInteger();
+ }
+
+ double TJsonValue::GetDoubleSafe() const {
+ if (!IsDouble())
+ ythrow TJsonException() << "Not a double";
+
+ return GetDouble();
+ }
+
+ const TString& TJsonValue::GetStringSafe() const {
+ if (Type != JSON_STRING)
+ ythrow TJsonException() << "Not a string";
+
+ return Value.String;
+ }
+
+ bool TJsonValue::GetBooleanSafe(const bool defaultValue) const {
+ if (Type == JSON_UNDEFINED)
+ return defaultValue;
+
+ return GetBooleanSafe();
+ }
+
+ long long TJsonValue::GetIntegerSafe(const long long defaultValue) const {
+ if (Type == JSON_UNDEFINED)
+ return defaultValue;
+
+ return GetIntegerSafe();
+ }
+
+ unsigned long long TJsonValue::GetUIntegerSafe(const unsigned long long defaultValue) const {
+ if (Type == JSON_UNDEFINED)
+ return defaultValue;
+
+ return GetUIntegerSafe();
+ }
+
+ double TJsonValue::GetDoubleSafe(const double defaultValue) const {
+ if (Type == JSON_UNDEFINED)
+ return defaultValue;
+
+ return GetDoubleSafe();
+ }
+
+ TString TJsonValue::GetStringSafe(const TString& defaultValue) const {
+ if (Type == JSON_UNDEFINED)
+ return defaultValue;
+
+ return GetStringSafe();
+ }
+
+ const TJsonValue::TMapType& TJsonValue::GetMapSafe() const {
+ if (Type != JSON_MAP)
+ ythrow TJsonException() << "Not a map";
+
+ return *Value.Map;
+ }
+
+ TJsonValue::TMapType& TJsonValue::GetMapSafe() {
+ return const_cast<TJsonValue::TMapType&>(const_cast<const TJsonValue*>(this)->GetMapSafe());
+ }
+
+ const TJsonValue::TArray& TJsonValue::GetArraySafe() const {
+ if (Type != JSON_ARRAY)
+ ythrow TJsonException() << "Not an array";
+
+ return *Value.Array;
+ }
+
+ TJsonValue::TArray& TJsonValue::GetArraySafe() {
+ return const_cast<TJsonValue::TArray&>(const_cast<const TJsonValue*>(this)->GetArraySafe());
+ }
+
+ bool TJsonValue::GetBooleanRobust() const noexcept {
+ switch (Type) {
+ case JSON_ARRAY:
+ return !Value.Array->empty();
+ case JSON_MAP:
+ return !Value.Map->empty();
+ case JSON_INTEGER:
+ case JSON_UINTEGER:
+ case JSON_DOUBLE:
+ return GetIntegerRobust();
+ case JSON_STRING:
+ return GetIntegerRobust() || IsTrue(Value.String);
+ case JSON_NULL:
+ case JSON_UNDEFINED:
+ default:
+ return false;
+ case JSON_BOOLEAN:
+ return Value.Boolean;
+ }
+ }
+
+ long long TJsonValue::GetIntegerRobust() const noexcept {
+ switch (Type) {
+ case JSON_ARRAY:
+ return Value.Array->size();
+ case JSON_MAP:
+ return Value.Map->size();
+ case JSON_BOOLEAN:
+ return Value.Boolean;
+ case JSON_DOUBLE:
+ return GetDoubleRobust();
+ case JSON_STRING:
+ try {
+ i64 res = 0;
+ if (Value.String && TryFromString(Value.String, res)) {
+ return res;
+ }
+ } catch (const yexception&) {
+ }
+ return 0;
+ case JSON_NULL:
+ case JSON_UNDEFINED:
+ default:
+ return 0;
+ case JSON_INTEGER:
+ case JSON_UINTEGER:
+ return Value.Integer;
+ }
+ }
+
+ unsigned long long TJsonValue::GetUIntegerRobust() const noexcept {
+ switch (Type) {
+ case JSON_ARRAY:
+ return Value.Array->size();
+ case JSON_MAP:
+ return Value.Map->size();
+ case JSON_BOOLEAN:
+ return Value.Boolean;
+ case JSON_DOUBLE:
+ return GetDoubleRobust();
+ case JSON_STRING:
+ try {
+ ui64 res = 0;
+ if (Value.String && TryFromString(Value.String, res)) {
+ return res;
+ }
+ } catch (const yexception&) {
+ }
+ return 0;
+ case JSON_NULL:
+ case JSON_UNDEFINED:
+ default:
+ return 0;
+ case JSON_INTEGER:
+ case JSON_UINTEGER:
+ return Value.UInteger;
+ }
+ }
+
+ double TJsonValue::GetDoubleRobust() const noexcept {
+ switch (Type) {
+ case JSON_ARRAY:
+ return Value.Array->size();
+ case JSON_MAP:
+ return Value.Map->size();
+ case JSON_BOOLEAN:
+ return Value.Boolean;
+ case JSON_INTEGER:
+ return Value.Integer;
+ case JSON_UINTEGER:
+ return Value.UInteger;
+ case JSON_STRING:
+ try {
+ double res = 0;
+ if (Value.String && TryFromString(Value.String, res)) {
+ return res;
+ }
+ } catch (const yexception&) {
+ }
+ return 0;
+ case JSON_NULL:
+ case JSON_UNDEFINED:
+ default:
+ return 0;
+ case JSON_DOUBLE:
+ return Value.Double;
+ }
+ }
+
+ TString TJsonValue::GetStringRobust() const {
+ switch (Type) {
+ case JSON_ARRAY:
+ case JSON_MAP:
+ case JSON_BOOLEAN:
+ case JSON_DOUBLE:
+ case JSON_INTEGER:
+ case JSON_UINTEGER:
+ case JSON_NULL:
+ case JSON_UNDEFINED:
+ default: {
+ NJsonWriter::TBuf sout;
+ sout.WriteJsonValue(this);
+ return sout.Str();
+ }
+ case JSON_STRING:
+ return Value.String;
+ }
+ }
+
+ bool TJsonValue::GetBoolean(bool* value) const noexcept {
+ if (Type != JSON_BOOLEAN)
+ return false;
+
+ *value = Value.Boolean;
+ return true;
+ }
+
+ bool TJsonValue::GetInteger(long long* value) const noexcept {
+ if (!IsInteger())
+ return false;
+
+ *value = GetInteger();
+ return true;
+ }
+
+ bool TJsonValue::GetUInteger(unsigned long long* value) const noexcept {
+ if (!IsUInteger())
+ return false;
+
+ *value = GetUInteger();
+ return true;
+ }
+
+ bool TJsonValue::GetDouble(double* value) const noexcept {
+ if (!IsDouble())
+ return false;
+
+ *value = GetDouble();
+ return true;
+ }
+
+ bool TJsonValue::GetString(TString* value) const {
+ if (Type != JSON_STRING)
+ return false;
+
+ *value = Value.String;
+ return true;
+ }
+
+ bool TJsonValue::GetMap(TJsonValue::TMapType* value) const {
+ if (Type != JSON_MAP)
+ return false;
+
+ *value = *Value.Map;
+ return true;
+ }
+
+ bool TJsonValue::GetArray(TJsonValue::TArray* value) const {
+ if (Type != JSON_ARRAY)
+ return false;
+
+ *value = *Value.Array;
+ return true;
+ }
+
+ bool TJsonValue::GetMapPointer(const TJsonValue::TMapType** value) const noexcept {
+ if (Type != JSON_MAP)
+ return false;
+
+ *value = Value.Map;
+ return true;
+ }
+
+ bool TJsonValue::GetArrayPointer(const TJsonValue::TArray** value) const noexcept {
+ if (Type != JSON_ARRAY)
+ return false;
+
+ *value = Value.Array;
+ return true;
+ }
+
+ bool TJsonValue::GetValue(const size_t index, TJsonValue* value) const {
+ const TJsonValue* tmp = nullptr;
+ if (GetValuePointer(index, &tmp)) {
+ *value = *tmp;
+ return true;
+ }
+ return false;
+ }
+
+ bool TJsonValue::GetValue(const TStringBuf key, TJsonValue* value) const {
+ const TJsonValue* tmp = nullptr;
+ if (GetValuePointer(key, &tmp)) {
+ *value = *tmp;
+ return true;
+ }
+ return false;
+ }
+
+ bool TJsonValue::GetValuePointer(const size_t index, const TJsonValue** value) const noexcept {
+ if (Type == JSON_ARRAY && index < Value.Array->size()) {
+ *value = &(*Value.Array)[index];
+ return true;
+ }
+ return false;
+ }
+
+ bool TJsonValue::GetValuePointer(const TStringBuf key, const TJsonValue** value) const noexcept {
+ if (Type == JSON_MAP) {
+ const TMapType::const_iterator it = Value.Map->find(key);
+ if (it != Value.Map->end()) {
+ *value = &(it->second);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool TJsonValue::GetValuePointer(const TStringBuf key, TJsonValue** value) noexcept {
+ return static_cast<const TJsonValue*>(this)->GetValuePointer(key, const_cast<const TJsonValue**>(value));
+ }
+
+ bool TJsonValue::IsNull() const noexcept {
+ return Type == JSON_NULL;
+ }
+
+ bool TJsonValue::IsBoolean() const noexcept {
+ return Type == JSON_BOOLEAN;
+ }
+
+ bool TJsonValue::IsInteger() const noexcept {
+ switch (Type) {
+ case JSON_INTEGER:
+ return true;
+
+ case JSON_UINTEGER:
+ return (Value.UInteger <= static_cast<unsigned long long>(Max<long long>()));
+
+ case JSON_DOUBLE:
+ return ((long long)Value.Double == Value.Double);
+
+ default:
+ return false;
+ }
+ }
+
+ bool TJsonValue::IsUInteger() const noexcept {
+ switch (Type) {
+ case JSON_UINTEGER:
+ return true;
+
+ case JSON_INTEGER:
+ return (Value.Integer >= 0);
+
+ case JSON_DOUBLE:
+ return ((unsigned long long)Value.Double == Value.Double);
+
+ default:
+ return false;
+ }
+ }
+
+ bool TJsonValue::IsDouble() const noexcept {
+ // Check whether we can convert integer to floating-point
+ // without precision loss.
+ switch (Type) {
+ case JSON_DOUBLE:
+ return true;
+
+ case JSON_INTEGER:
+ return (1ll << std::numeric_limits<double>::digits) >= Abs(Value.Integer);
+
+ case JSON_UINTEGER:
+ return (1ull << std::numeric_limits<double>::digits) >= Value.UInteger;
+
+ default:
+ return false;
+ }
+ }
+
+ namespace {
+ template <class TPtr, class T>
+ TPtr* CreateOrNullptr(TPtr* p, T key, std::true_type /*create*/) {
+ return &(*p)[key];
+ }
+
+ template <class TPtr, class T>
+ TPtr* CreateOrNullptr(const TPtr* p, T key, std::false_type /*create*/) noexcept {
+ const TPtr* const next = &(*p)[key];
+ return next->IsDefined() ? const_cast<TPtr*>(next) : nullptr;
+ }
+
+ template <bool Create, class TJsonPtr>
+ TJsonPtr GetValuePtrByPath(TJsonPtr currentJson, TStringBuf path, char delimiter) noexcept(!Create) {
+ static_assert(
+ !(Create && std::is_const<std::remove_pointer_t<TJsonPtr>>::value),
+ "TJsonPtr must be a `TJsonValue*` if `Create` is true");
+ constexpr std::integral_constant<bool, Create> create_tag{};
+
+ while (!path.empty()) {
+ size_t index = 0;
+ const TStringBuf step = path.NextTok(delimiter);
+ if (step.size() > 2 && *step.begin() == '[' && step.back() == ']' && TryFromString(step.substr(1, step.size() - 2), index)) {
+ currentJson = CreateOrNullptr(currentJson, index, create_tag);
+ } else {
+ currentJson = CreateOrNullptr(currentJson, step, create_tag);
+ }
+
+ if (!currentJson) {
+ return nullptr;
+ }
+ }
+
+ return currentJson;
+ }
+ } // anonymous namespace
+
+ bool TJsonValue::GetValueByPath(const TStringBuf path, TJsonValue& result, char delimiter) const {
+ const TJsonValue* const ptr = GetValuePtrByPath<false>(this, path, delimiter);
+ if (ptr) {
+ result = *ptr;
+ return true;
+ }
+ return false;
+ }
+
+ bool TJsonValue::SetValueByPath(const TStringBuf path, const TJsonValue& value, char delimiter) {
+ TJsonValue* const ptr = GetValuePtrByPath<true>(this, path, delimiter);
+ if (ptr) {
+ *ptr = value;
+ return true;
+ }
+ return false;
+ }
+
+ bool TJsonValue::SetValueByPath(const TStringBuf path, TJsonValue&& value, char delimiter) {
+ TJsonValue* const ptr = GetValuePtrByPath<true>(this, path, delimiter);
+ if (ptr) {
+ *ptr = std::move(value);
+ return true;
+ }
+ return false;
+ }
+
+ const TJsonValue* TJsonValue::GetValueByPath(const TStringBuf key, char delim) const noexcept {
+ return GetValuePtrByPath<false>(this, key, delim);
+ }
+
+ TJsonValue* TJsonValue::GetValueByPath(const TStringBuf key, char delim) noexcept {
+ return GetValuePtrByPath<false>(this, key, delim);
+ }
+
+ void TJsonValue::DoScan(const TString& path, TJsonValue* parent, IScanCallback& callback) {
+ if (!callback.Do(path, parent, *this)) {
+ return;
+ }
+
+ if (Type == JSON_MAP) {
+ for (auto&& i : *Value.Map) {
+ i.second.DoScan(!!path ? TString::Join(path, ".", i.first) : i.first, this, callback);
+ }
+ } else if (Type == JSON_ARRAY) {
+ for (ui32 i = 0; i < Value.Array->size(); ++i) {
+ (*Value.Array)[i].DoScan(TString::Join(path, "[", ToString(i), "]"), this, callback);
+ }
+ }
+ }
+
+ void TJsonValue::Scan(IScanCallback& callback) {
+ DoScan("", nullptr, callback);
+ }
+
+ bool TJsonValue::IsString() const noexcept {
+ return Type == JSON_STRING;
+ }
+
+ bool TJsonValue::IsMap() const noexcept {
+ return Type == JSON_MAP;
+ }
+
+ bool TJsonValue::IsArray() const noexcept {
+ return Type == JSON_ARRAY;
+ }
+
+ bool TJsonValue::Has(const TStringBuf& key) const noexcept {
+ return Type == JSON_MAP && Value.Map->contains(key);
+ }
+
+ bool TJsonValue::Has(size_t key) const noexcept {
+ return Type == JSON_ARRAY && Value.Array->size() > key;
+ }
+
+ bool TJsonValue::operator==(const TJsonValue& rhs) const {
+ switch (Type) {
+ case JSON_UNDEFINED: {
+ return (rhs.GetType() == JSON_UNDEFINED);
+ }
+
+ case JSON_NULL: {
+ return rhs.IsNull();
+ }
+
+ case JSON_BOOLEAN: {
+ return (rhs.IsBoolean() && Value.Boolean == rhs.Value.Boolean);
+ }
+
+ case JSON_INTEGER: {
+ return (rhs.IsInteger() && GetInteger() == rhs.GetInteger());
+ }
+
+ case JSON_UINTEGER: {
+ return (rhs.IsUInteger() && GetUInteger() == rhs.GetUInteger());
+ }
+
+ case JSON_STRING: {
+ return (rhs.IsString() && Value.String == rhs.Value.String);
+ }
+
+ case JSON_DOUBLE: {
+ return (rhs.IsDouble() && fabs(GetDouble() - rhs.GetDouble()) <= FLT_EPSILON);
+ }
+
+ case JSON_MAP:
+ return AreJsonMapsEqual(*this, rhs);
+
+ case JSON_ARRAY:
+ return AreJsonArraysEqual(*this, rhs);
+
+ default:
+ Y_ASSERT(false && "Unknown type.");
+ return false;
+ }
+ }
+
+ void TJsonValue::SwapWithUndefined(TJsonValue& output) noexcept {
+ if (Type == JSON_STRING) {
+ static_assert(std::is_nothrow_move_constructible<TString>::value, "noexcept violation! Add some try {} catch (...) logic");
+ new (&output.Value.String) TString(std::move(Value.String));
+ Value.String.~TString();
+ } else {
+ std::memcpy(&output.Value, &Value, sizeof(Value));
+ }
+
+ output.Type = Type;
+ Type = JSON_UNDEFINED;
+ }
+
+ void TJsonValue::Swap(TJsonValue& rhs) noexcept {
+ TJsonValue tmp(std::move(*this));
+ rhs.SwapWithUndefined(*this);
+ tmp.SwapWithUndefined(rhs);
+ }
+
+ void TJsonValue::Save(IOutputStream* s) const {
+ ::Save(s, static_cast<ui8>(Type));
+ switch (Type) {
+ case JSON_UNDEFINED:break;
+ case JSON_NULL:break;
+ case JSON_BOOLEAN:
+ ::Save(s, Value.Boolean);
+ break;
+ case JSON_INTEGER:
+ ::Save(s, Value.Integer);
+ break;
+ case JSON_UINTEGER:
+ ::Save(s, Value.UInteger);
+ break;
+ case JSON_DOUBLE:
+ ::Save(s, Value.Double);
+ break;
+ case JSON_STRING:
+ ::Save(s, Value.String);
+ break;
+ case JSON_MAP:
+ ::Save(s, *Value.Map);
+ break;
+ case JSON_ARRAY:
+ ::Save(s, *Value.Array);
+ break;
+ }
+ }
+
+ void TJsonValue::Load(IInputStream* s) {
+ {
+ ui8 loadedType = {};
+ ::Load(s, loadedType);
+ SetType(static_cast<EJsonValueType>(loadedType));
+ }
+ switch (Type) {
+ case JSON_UNDEFINED:break;
+ case JSON_NULL:break;
+ case JSON_BOOLEAN:
+ ::Load(s, Value.Boolean);
+ break;
+ case JSON_INTEGER:
+ ::Load(s, Value.Integer);
+ break;
+ case JSON_UINTEGER:
+ ::Load(s, Value.UInteger);
+ break;
+ case JSON_DOUBLE:
+ ::Load(s, Value.Double);
+ break;
+ case JSON_STRING:
+ ::Load(s, Value.String);
+ break;
+ case JSON_MAP:
+ ::Load(s, *Value.Map);
+ break;
+ case JSON_ARRAY:
+ ::Load(s, *Value.Array);
+ break;
+ }
+ }
+
+ //****************************************************************
+
+ bool GetMapPointer(const TJsonValue& jv, const size_t index, const TJsonValue::TMapType** value) {
+ const TJsonValue* v;
+ if (!jv.GetValuePointer(index, &v) || !v->IsMap())
+ return false;
+
+ *value = &v->GetMap();
+ return true;
+ }
+
+ bool GetArrayPointer(const TJsonValue& jv, const size_t index, const TJsonValue::TArray** value) {
+ const TJsonValue* v;
+ if (!jv.GetValuePointer(index, &v) || !v->IsArray())
+ return false;
+
+ *value = &v->GetArray();
+ return true;
+ }
+
+ bool GetMapPointer(const TJsonValue& jv, const TStringBuf key, const TJsonValue::TMapType** value) {
+ const TJsonValue* v;
+ if (!jv.GetValuePointer(key, &v) || !v->IsMap())
+ return false;
+
+ *value = &v->GetMap();
+ return true;
+ }
+
+ bool GetArrayPointer(const TJsonValue& jv, const TStringBuf key, const TJsonValue::TArray** value) {
+ const TJsonValue* v;
+ if (!jv.GetValuePointer(key, &v) || !v->IsArray())
+ return false;
+
+ *value = &v->GetArray();
+ return true;
+ }
+
+ void TJsonValue::BackChecks() const {
+ if (Type != JSON_ARRAY)
+ ythrow TJsonException() << "Not an array";
+
+ if (Value.Array->empty())
+ ythrow TJsonException() << "Get back on empty array";
+ }
+}
+
+template <>
+void Out<NJson::TJsonValue>(IOutputStream& out, const NJson::TJsonValue& v) {
+ NJsonWriter::TBuf buf(NJsonWriter::HEM_DONT_ESCAPE_HTML, &out);
+ buf.WriteJsonValue(&v);
+}
diff --git a/library/cpp/json/writer/json_value.h b/library/cpp/json/writer/json_value.h
new file mode 100644
index 0000000000..3f0f50bc4c
--- /dev/null
+++ b/library/cpp/json/writer/json_value.h
@@ -0,0 +1,294 @@
+#pragma once
+
+#include <library/cpp/json/common/defs.h>
+
+#include <util/generic/string.h>
+#include <util/generic/hash.h>
+#include <util/generic/vector.h>
+#include <util/generic/deque.h>
+#include <util/generic/utility.h>
+#include <util/generic/yexception.h>
+
+namespace NJson {
+ enum EJsonValueType {
+ JSON_UNDEFINED /* "Undefined" */,
+ JSON_NULL /* "Null" */,
+ JSON_BOOLEAN /* "Boolean" */,
+ JSON_INTEGER /* "Integer" */,
+ JSON_DOUBLE /* "Double" */,
+ JSON_STRING /* "String" */,
+ JSON_MAP /* "Map" */,
+ JSON_ARRAY /* "Array" */,
+ JSON_UINTEGER /* "UInteger" */
+ };
+
+ class TJsonValue;
+
+ class IScanCallback {
+ public:
+ virtual ~IScanCallback() = default;
+
+ virtual bool Do(const TString& path, TJsonValue* parent, TJsonValue& value) = 0;
+ };
+
+ class TJsonValue {
+ void Clear() noexcept;
+
+ public:
+ typedef THashMap<TString, TJsonValue> TMapType;
+ typedef TDeque<TJsonValue> TArray;
+
+ TJsonValue() noexcept = default;
+ TJsonValue(EJsonValueType type);
+ TJsonValue(bool value) noexcept;
+ TJsonValue(int value) noexcept;
+ TJsonValue(unsigned int value) noexcept;
+ TJsonValue(long value) noexcept;
+ TJsonValue(unsigned long value) noexcept;
+ TJsonValue(long long value) noexcept;
+ TJsonValue(unsigned long long value) noexcept;
+ TJsonValue(double value) noexcept;
+ TJsonValue(TString value);
+ TJsonValue(const char* value);
+ template <class T>
+ TJsonValue(const T*) = delete;
+ TJsonValue(TStringBuf value);
+
+ TJsonValue(const std::string& s)
+ : TJsonValue(TStringBuf(s))
+ {
+ }
+
+ TJsonValue(const TJsonValue& vval);
+ TJsonValue(TJsonValue&& vval) noexcept;
+
+ TJsonValue& operator=(const TJsonValue& val);
+ TJsonValue& operator=(TJsonValue&& val) noexcept;
+
+ ~TJsonValue() {
+ Clear();
+ }
+
+ EJsonValueType GetType() const noexcept;
+ TJsonValue& SetType(EJsonValueType type);
+
+ TJsonValue& SetValue(const TJsonValue& value);
+ TJsonValue& SetValue(TJsonValue&& value);
+
+ // for Map
+ TJsonValue& InsertValue(const TString& key, const TJsonValue& value);
+ TJsonValue& InsertValue(TStringBuf key, const TJsonValue& value);
+ TJsonValue& InsertValue(const char* key, const TJsonValue& value);
+ TJsonValue& InsertValue(const TString& key, TJsonValue&& value);
+ TJsonValue& InsertValue(TStringBuf key, TJsonValue&& value);
+ TJsonValue& InsertValue(const char* key, TJsonValue&& value);
+
+ // for Array
+ TJsonValue& AppendValue(const TJsonValue& value);
+ TJsonValue& AppendValue(TJsonValue&& value);
+ TJsonValue& Back();
+ const TJsonValue& Back() const;
+
+ bool GetValueByPath(TStringBuf path, TJsonValue& result, char delimiter = '.') const;
+ bool SetValueByPath(TStringBuf path, const TJsonValue& value, char delimiter = '.');
+ bool SetValueByPath(TStringBuf path, TJsonValue&& value, char delimiter = '.');
+
+ // returns NULL on failure
+ const TJsonValue* GetValueByPath(TStringBuf path, char delimiter = '.') const noexcept;
+ TJsonValue* GetValueByPath(TStringBuf path, char delimiter = '.') noexcept;
+
+ void EraseValue(TStringBuf key);
+ void EraseValue(size_t index);
+
+ TJsonValue& operator[](size_t idx);
+ TJsonValue& operator[](const TStringBuf& key);
+ const TJsonValue& operator[](size_t idx) const noexcept;
+ const TJsonValue& operator[](const TStringBuf& key) const noexcept;
+
+ bool GetBoolean() const;
+ long long GetInteger() const;
+ unsigned long long GetUInteger() const;
+ double GetDouble() const;
+ const TString& GetString() const;
+ const TMapType& GetMap() const;
+ const TArray& GetArray() const;
+
+ //throwing TJsonException possible
+ bool GetBooleanSafe() const;
+ long long GetIntegerSafe() const;
+ unsigned long long GetUIntegerSafe() const;
+ double GetDoubleSafe() const;
+ const TString& GetStringSafe() const;
+ const TMapType& GetMapSafe() const;
+ TMapType& GetMapSafe();
+ const TArray& GetArraySafe() const;
+ TArray& GetArraySafe();
+
+ bool GetBooleanSafe(bool defaultValue) const;
+ long long GetIntegerSafe(long long defaultValue) const;
+ unsigned long long GetUIntegerSafe(unsigned long long defaultValue) const;
+ double GetDoubleSafe(double defaultValue) const;
+ TString GetStringSafe(const TString& defaultValue) const;
+
+ bool GetBooleanRobust() const noexcept;
+ long long GetIntegerRobust() const noexcept;
+ unsigned long long GetUIntegerRobust() const noexcept;
+ double GetDoubleRobust() const noexcept;
+ TString GetStringRobust() const;
+
+ // Exception-free accessors
+ bool GetBoolean(bool* value) const noexcept;
+ bool GetInteger(long long* value) const noexcept;
+ bool GetUInteger(unsigned long long* value) const noexcept;
+ bool GetDouble(double* value) const noexcept;
+ bool GetMapPointer(const TMapType** value) const noexcept;
+ bool GetArrayPointer(const TArray** value) const noexcept;
+
+ bool GetString(TString* value) const;
+ bool GetMap(TMapType* value) const;
+ bool GetArray(TArray* value) const;
+ bool GetValue(size_t index, TJsonValue* value) const;
+ bool GetValue(TStringBuf key, TJsonValue* value) const;
+ bool GetValuePointer(size_t index, const TJsonValue** value) const noexcept;
+ bool GetValuePointer(TStringBuf key, const TJsonValue** value) const noexcept;
+ bool GetValuePointer(TStringBuf key, TJsonValue** value) noexcept;
+
+ // Checking for defined non-null value
+ bool IsDefined() const noexcept {
+ return Type != JSON_UNDEFINED && Type != JSON_NULL;
+ }
+
+ bool IsNull() const noexcept;
+ bool IsBoolean() const noexcept;
+ bool IsDouble() const noexcept;
+ bool IsString() const noexcept;
+ bool IsMap() const noexcept;
+ bool IsArray() const noexcept;
+
+ /// @return true if JSON_INTEGER or (JSON_UINTEGER and Value <= Max<long long>)
+ bool IsInteger() const noexcept;
+
+ /// @return true if JSON_UINTEGER or (JSON_INTEGER and Value >= 0)
+ bool IsUInteger() const noexcept;
+
+ bool Has(const TStringBuf& key) const noexcept;
+ bool Has(size_t key) const noexcept;
+
+ void Scan(IScanCallback& callback);
+
+ /// Non-robust comparison.
+ bool operator==(const TJsonValue& rhs) const;
+
+ bool operator!=(const TJsonValue& rhs) const {
+ return !(*this == rhs);
+ }
+
+ void Swap(TJsonValue& rhs) noexcept;
+
+ // save using util/ysaveload.h serialization (not to JSON stream)
+ void Save(IOutputStream* s) const;
+
+ // load using util/ysaveload.h serialization (not as JSON stream)
+ void Load(IInputStream* s);
+
+ static const TJsonValue UNDEFINED;
+
+ private:
+ EJsonValueType Type = JSON_UNDEFINED;
+ union TValueUnion {
+ bool Boolean;
+ long long Integer;
+ unsigned long long UInteger;
+ double Double;
+ TString String;
+ TMapType* Map;
+ TArray* Array;
+
+ TValueUnion() noexcept {
+ Zero(*this);
+ }
+ ~TValueUnion() noexcept {
+ }
+ };
+ TValueUnion Value;
+ void DoScan(const TString& path, TJsonValue* parent, IScanCallback& callback);
+ void SwapWithUndefined(TJsonValue& output) noexcept;
+
+ /**
+ @throw yexception if Back shouldn't be called on the object.
+ */
+ void BackChecks() const;
+ };
+
+ inline bool GetBoolean(const TJsonValue& jv, size_t index, bool* value) noexcept {
+ return jv[index].GetBoolean(value);
+ }
+
+ inline bool GetInteger(const TJsonValue& jv, size_t index, long long* value) noexcept {
+ return jv[index].GetInteger(value);
+ }
+
+ inline bool GetUInteger(const TJsonValue& jv, size_t index, unsigned long long* value) noexcept {
+ return jv[index].GetUInteger(value);
+ }
+
+ inline bool GetDouble(const TJsonValue& jv, size_t index, double* value) noexcept {
+ return jv[index].GetDouble(value);
+ }
+
+ inline bool GetString(const TJsonValue& jv, size_t index, TString* value) {
+ return jv[index].GetString(value);
+ }
+
+ bool GetMapPointer(const TJsonValue& jv, size_t index, const TJsonValue::TMapType** value);
+ bool GetArrayPointer(const TJsonValue& jv, size_t index, const TJsonValue::TArray** value);
+
+ inline bool GetBoolean(const TJsonValue& jv, TStringBuf key, bool* value) noexcept {
+ return jv[key].GetBoolean(value);
+ }
+
+ inline bool GetInteger(const TJsonValue& jv, TStringBuf key, long long* value) noexcept {
+ return jv[key].GetInteger(value);
+ }
+
+ inline bool GetUInteger(const TJsonValue& jv, TStringBuf key, unsigned long long* value) noexcept {
+ return jv[key].GetUInteger(value);
+ }
+
+ inline bool GetDouble(const TJsonValue& jv, TStringBuf key, double* value) noexcept {
+ return jv[key].GetDouble(value);
+ }
+
+ inline bool GetString(const TJsonValue& jv, TStringBuf key, TString* value) {
+ return jv[key].GetString(value);
+ }
+
+ bool GetMapPointer(const TJsonValue& jv, const TStringBuf key, const TJsonValue::TMapType** value);
+ bool GetArrayPointer(const TJsonValue& jv, const TStringBuf key, const TJsonValue::TArray** value);
+
+ class TJsonMap: public TJsonValue {
+ public:
+ TJsonMap()
+ : TJsonValue(NJson::JSON_MAP)
+ {}
+
+ TJsonMap(const std::initializer_list<std::pair<TString, TJsonValue>>& list)
+ : TJsonValue(NJson::JSON_MAP)
+ {
+ GetMapSafe() = THashMap<TString, TJsonValue>(list);
+ }
+ };
+
+ class TJsonArray: public TJsonValue {
+ public:
+ TJsonArray()
+ : TJsonValue(NJson::JSON_ARRAY)
+ {}
+
+ TJsonArray(const std::initializer_list<TJsonValue>& list)
+ : TJsonValue(NJson::JSON_ARRAY)
+ {
+ GetArraySafe() = TJsonValue::TArray(list);
+ }
+ };
+}
diff --git a/library/cpp/json/writer/json_value_ut.cpp b/library/cpp/json/writer/json_value_ut.cpp
new file mode 100644
index 0000000000..dc7f6affdf
--- /dev/null
+++ b/library/cpp/json/writer/json_value_ut.cpp
@@ -0,0 +1,650 @@
+#include "json_value.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/input.h>
+
+using namespace NJson;
+
+Y_UNIT_TEST_SUITE(TJsonValueTest) {
+ Y_UNIT_TEST(UndefTest) {
+ TJsonValue undef;
+ TJsonValue null(JSON_NULL);
+ TJsonValue _false(false);
+ TJsonValue zeroInt(0);
+ TJsonValue zeroDouble(0.0);
+ TJsonValue emptyStr("");
+ TJsonValue emptyArray(JSON_ARRAY);
+ TJsonValue emptyMap(JSON_MAP);
+
+ UNIT_ASSERT(!undef.IsDefined());
+ UNIT_ASSERT(!null.IsDefined()); // json NULL is undefined too!
+ UNIT_ASSERT(_false.IsDefined());
+ UNIT_ASSERT(zeroInt.IsDefined());
+ UNIT_ASSERT(zeroDouble.IsDefined());
+ UNIT_ASSERT(emptyStr.IsDefined());
+ UNIT_ASSERT(emptyArray.IsDefined());
+ UNIT_ASSERT(emptyMap.IsDefined());
+
+ UNIT_ASSERT(undef == TJsonValue());
+ UNIT_ASSERT(undef != null);
+ UNIT_ASSERT(undef != _false);
+ UNIT_ASSERT(undef != zeroInt);
+ UNIT_ASSERT(undef != zeroDouble);
+ UNIT_ASSERT(undef != emptyStr);
+ UNIT_ASSERT(undef != emptyArray);
+ UNIT_ASSERT(undef != emptyMap);
+ }
+
+ Y_UNIT_TEST(DefaultCompareTest) {
+ {
+ TJsonValue lhs;
+ TJsonValue rhs;
+ UNIT_ASSERT(lhs == rhs);
+ UNIT_ASSERT(rhs == lhs);
+ }
+
+ {
+ TJsonValue lhs;
+ TJsonValue rhs(JSON_NULL);
+ UNIT_ASSERT(lhs != rhs);
+ UNIT_ASSERT(rhs != lhs);
+ }
+ }
+
+ Y_UNIT_TEST(NullCompareTest) {
+ TJsonValue lhs(JSON_NULL);
+ TJsonValue rhs(JSON_NULL);
+ UNIT_ASSERT(lhs == rhs);
+ UNIT_ASSERT(rhs == lhs);
+ }
+
+ Y_UNIT_TEST(StringCompareTest) {
+ {
+ TJsonValue lhs(JSON_STRING);
+ TJsonValue rhs(JSON_STRING);
+ UNIT_ASSERT(lhs == rhs);
+ UNIT_ASSERT(rhs == lhs);
+ }
+
+ {
+ TJsonValue lhs("");
+ TJsonValue rhs("");
+ UNIT_ASSERT(lhs == rhs);
+ UNIT_ASSERT(rhs == lhs);
+ }
+
+ {
+ TJsonValue lhs("abc");
+ TJsonValue rhs("abc");
+ UNIT_ASSERT(lhs == rhs);
+ UNIT_ASSERT(rhs == lhs);
+ }
+
+ {
+ TJsonValue lhs("1");
+ TJsonValue rhs(1);
+ UNIT_ASSERT(lhs != rhs);
+ UNIT_ASSERT(rhs != lhs);
+ }
+ }
+
+ Y_UNIT_TEST(ArrayCompareTest) {
+ {
+ TJsonValue lhs(JSON_ARRAY);
+ TJsonValue rhs(JSON_ARRAY);
+ UNIT_ASSERT(lhs == rhs);
+ UNIT_ASSERT(rhs == lhs);
+ }
+
+ {
+ TJsonValue lhs;
+ TJsonValue rhs;
+
+ lhs.AppendValue(TJsonValue());
+
+ UNIT_ASSERT(lhs != rhs);
+ UNIT_ASSERT(rhs != lhs);
+ }
+
+ {
+ TJsonValue lhs;
+ TJsonValue rhs;
+
+ lhs.AppendValue(1);
+ lhs.AppendValue("2");
+ lhs.AppendValue(3.0);
+ lhs.AppendValue(TJsonValue());
+ lhs.AppendValue(TJsonValue(JSON_NULL));
+
+ rhs.AppendValue(1);
+ rhs.AppendValue("2");
+ rhs.AppendValue(3.0);
+ rhs.AppendValue(TJsonValue());
+ rhs.AppendValue(TJsonValue(JSON_NULL));
+
+ UNIT_ASSERT(lhs == rhs);
+ UNIT_ASSERT(rhs == lhs);
+ }
+
+ {
+ TJsonValue lhs;
+ TJsonValue rhs;
+
+ lhs.AppendValue(1);
+ rhs.AppendValue("1");
+
+ UNIT_ASSERT(lhs != rhs);
+ UNIT_ASSERT(rhs != lhs);
+ }
+ }
+
+ Y_UNIT_TEST(CompareTest) {
+ {
+ TJsonValue lhs;
+ lhs.InsertValue("null value", TJsonValue(JSON_NULL));
+ lhs.InsertValue("int key", TJsonValue(10));
+ lhs.InsertValue("double key", TJsonValue(11.11));
+ lhs.InsertValue("string key", TJsonValue("string"));
+
+ TJsonValue array;
+ array.AppendValue(1);
+ array.AppendValue(2);
+ array.AppendValue(3);
+ array.AppendValue("string");
+ lhs.InsertValue("array", array);
+
+ lhs.InsertValue("bool key", TJsonValue(true));
+
+ TJsonValue rhs;
+ rhs = lhs;
+
+ UNIT_ASSERT(lhs == rhs);
+ UNIT_ASSERT(rhs == lhs);
+ }
+
+ {
+ // Insert keys in different orders
+ const int NUM_KEYS = 1000;
+
+ TJsonValue lhs;
+ for (int i = 0; i < NUM_KEYS; ++i)
+ lhs.InsertValue(ToString(i), i);
+
+ TJsonValue rhs;
+ for (int i = 0; i < NUM_KEYS; i += 2)
+ rhs.InsertValue(ToString(i), i);
+ for (int i = 1; i < NUM_KEYS; i += 2)
+ rhs.InsertValue(ToString(i), i);
+
+ UNIT_ASSERT(lhs == rhs);
+ UNIT_ASSERT(rhs == lhs);
+ }
+
+ {
+ TJsonValue lhs;
+ lhs.InsertValue("null value", TJsonValue(JSON_NULL));
+ lhs.InsertValue("int key", TJsonValue(10));
+ lhs.InsertValue("double key", TJsonValue(11.11));
+ lhs.InsertValue("string key", TJsonValue("string"));
+
+ TJsonValue array;
+ array.AppendValue(1);
+ array.AppendValue(2);
+ array.AppendValue(3);
+ array.AppendValue("string");
+ lhs.InsertValue("array", array);
+
+ lhs.InsertValue("bool key", TJsonValue(true));
+
+ TJsonValue rhs;
+ rhs.InsertValue("null value", TJsonValue(JSON_NULL));
+ rhs.InsertValue("int key", TJsonValue(10));
+ rhs.InsertValue("double key", TJsonValue(11.11));
+ rhs.InsertValue("string key", TJsonValue("string"));
+ rhs.InsertValue("bool key", TJsonValue(true));
+
+ UNIT_ASSERT(lhs != rhs);
+ UNIT_ASSERT(rhs != lhs);
+ }
+ }
+
+ Y_UNIT_TEST(SwapTest) {
+ {
+ TJsonValue lhs;
+ lhs.InsertValue("a", "b");
+ TJsonValue lhsCopy = lhs;
+
+ TJsonValue rhs(JSON_NULL);
+ TJsonValue rhsCopy = rhs;
+
+ UNIT_ASSERT(lhs == lhsCopy);
+ UNIT_ASSERT(rhs == rhsCopy);
+
+ lhs.Swap(rhs);
+
+ UNIT_ASSERT(rhs == lhsCopy);
+ UNIT_ASSERT(lhs == rhsCopy);
+
+ lhs.Swap(rhs);
+
+ UNIT_ASSERT(lhs == lhsCopy);
+ UNIT_ASSERT(rhs == rhsCopy);
+ }
+ }
+
+ Y_UNIT_TEST(GetValueByPathTest) {
+ {
+ TJsonValue lhs;
+ TJsonValue first;
+ TJsonValue second;
+ TJsonValue last;
+ first.InsertValue("e", "f");
+ second.InsertValue("c", first);
+ last.InsertValue("a", second);
+ lhs.InsertValue("l", last);
+
+ TJsonValue result;
+ UNIT_ASSERT(lhs.GetValueByPath("l/a/c/e", result, '/'));
+ UNIT_ASSERT(result.GetStringRobust() == "f");
+ UNIT_ASSERT(!lhs.GetValueByPath("l/a/c/se", result, '/'));
+ UNIT_ASSERT(lhs.GetValueByPath("l/a/c", result, '/'));
+ UNIT_ASSERT(result.GetStringRobust() == "{\"e\":\"f\"}");
+
+ // faster TStringBuf version
+ UNIT_ASSERT_EQUAL(*lhs.GetValueByPath("l", '/'), last);
+ UNIT_ASSERT_EQUAL(*lhs.GetValueByPath("l/a", '/'), second);
+ UNIT_ASSERT_EQUAL(*lhs.GetValueByPath("l/a/c", '/'), first);
+ UNIT_ASSERT_EQUAL(*lhs.GetValueByPath("l.a.c.e", '.'), "f");
+ UNIT_ASSERT_EQUAL(lhs.GetValueByPath("l/a/c/e/x", '/'), NULL);
+ UNIT_ASSERT_EQUAL(lhs.GetValueByPath("a/c/e/x", '/'), NULL);
+ UNIT_ASSERT_EQUAL(lhs.GetValueByPath("nokey", '/'), NULL);
+ UNIT_ASSERT_EQUAL(*lhs.GetValueByPath("", '/'), lhs); // itself
+
+ TJsonValue array;
+ TJsonValue third;
+ array[0] = first;
+ array[1] = second;
+ third["t"] = array;
+
+ UNIT_ASSERT(array.GetValueByPath("[0].e", result));
+ UNIT_ASSERT(result.GetStringRobust() == "f");
+ UNIT_ASSERT(third.GetValueByPath("t.[0].e", result));
+ UNIT_ASSERT(result.GetStringRobust() == "f");
+ UNIT_ASSERT(third.GetValueByPath("t.[1].c.e", result));
+ UNIT_ASSERT(result.GetStringRobust() == "f");
+ UNIT_ASSERT(!third.GetValueByPath("t.[2]", result));
+
+ UNIT_ASSERT(third.SetValueByPath("t.[2]", "g"));
+ UNIT_ASSERT(third.GetValueByPath("t.[2]", result));
+ UNIT_ASSERT(result.GetStringRobust() == "g");
+
+ UNIT_ASSERT(lhs.SetValueByPath("l/a/c/se", "h", '/'));
+ UNIT_ASSERT(lhs.GetValueByPath("l/a/c/se", result, '/'));
+ UNIT_ASSERT(result.GetStringRobust() == "h");
+ }
+ }
+
+ Y_UNIT_TEST(GetValueByPathConstTest) {
+ TJsonValue lhs;
+ TJsonValue first;
+ TJsonValue second;
+ TJsonValue last;
+ first.InsertValue("e", "f");
+ second.InsertValue("c", first);
+ last.InsertValue("a", second);
+ lhs.InsertValue("l", last);
+
+ {
+ const TJsonValue* result = lhs.GetValueByPath("l", '/');
+ UNIT_ASSERT_EQUAL(*result, last);
+ }
+ {
+ const TJsonValue* result = lhs.GetValueByPath("l/a", '/');
+ UNIT_ASSERT_EQUAL(*result, second);
+ }
+ {
+ const TJsonValue* result = lhs.GetValueByPath("l/a/c", '/');
+ UNIT_ASSERT_EQUAL(*result, first);
+ }
+ {
+ const TJsonValue* result = lhs.GetValueByPath("l.a.c.e", '.');
+ UNIT_ASSERT_EQUAL(*result, "f");
+ }
+ {
+ const TJsonValue* result = lhs.GetValueByPath("l/a/c/e/x", '/');
+ UNIT_ASSERT_EQUAL(result, nullptr);
+ }
+ {
+ const TJsonValue* result = lhs.GetValueByPath("a/c/e/x", '/');
+ UNIT_ASSERT_EQUAL(result, nullptr);
+ }
+ {
+ const TJsonValue* result = lhs.GetValueByPath("nokey", '/');
+ UNIT_ASSERT_EQUAL(result, nullptr);
+ }
+ {
+ const TJsonValue* result = lhs.GetValueByPath("", '/');
+ UNIT_ASSERT_EQUAL(*result, lhs); // itself
+ }
+
+ TJsonValue array;
+ TJsonValue third;
+ array[0] = first;
+ array[1] = second;
+ third["t"] = array;
+
+ UNIT_ASSERT(array.GetValueByPath("[0].e", '.')->GetStringRobust() == "f");
+ UNIT_ASSERT(third.GetValueByPath("t.[0].e", '.')->GetStringRobust() == "f");
+ UNIT_ASSERT(third.GetValueByPath("t.[1].c.e", '.')->GetStringRobust() == "f");
+ }
+
+ Y_UNIT_TEST(EraseValueFromArray) {
+ {
+ TJsonValue vec;
+ vec.AppendValue(TJsonValue(0));
+ vec.AppendValue(TJsonValue(1));
+ vec.AppendValue(TJsonValue("2"));
+ vec.AppendValue(TJsonValue("3.14"));
+
+ TJsonValue vec1;
+ vec1.AppendValue(TJsonValue(0));
+ vec1.AppendValue(TJsonValue("2"));
+ vec1.AppendValue(TJsonValue("3.14"));
+
+ TJsonValue vec2;
+ vec2.AppendValue(TJsonValue(0));
+ vec2.AppendValue(TJsonValue("2"));
+
+ TJsonValue vec3;
+ vec3.AppendValue(TJsonValue("2"));
+
+ TJsonValue vec4(JSON_ARRAY);
+
+ UNIT_ASSERT(vec.IsArray());
+ UNIT_ASSERT(vec.GetArray().size() == 4);
+ vec.EraseValue(1);
+ UNIT_ASSERT(vec.GetArray().size() == 3);
+ UNIT_ASSERT(vec == vec1);
+ vec.EraseValue(2);
+ UNIT_ASSERT(vec.GetArray().size() == 2);
+ UNIT_ASSERT(vec == vec2);
+ vec.EraseValue(0);
+ UNIT_ASSERT(vec.GetArray().size() == 1);
+ UNIT_ASSERT(vec == vec3);
+ vec.EraseValue(0);
+ UNIT_ASSERT(vec.GetArray().size() == 0);
+ UNIT_ASSERT(vec == vec4);
+ }
+ }
+
+ Y_UNIT_TEST(NonConstMethodsTest) {
+ {
+ TJsonValue src;
+ TJsonValue value1;
+ value1.AppendValue(1);
+ value1.AppendValue(2);
+ src.InsertValue("key", value1);
+ src.InsertValue("key1", "HI!");
+
+ TJsonValue dst;
+ TJsonValue value2;
+ value2.AppendValue(1);
+ value2.AppendValue(2);
+ value2.AppendValue(3);
+ dst.InsertValue("key", value2);
+
+ src.GetValueByPath("key", '.')->AppendValue(3);
+ src.EraseValue("key1");
+ UNIT_ASSERT(src == dst);
+
+ dst.GetValueByPath("key", '.')->EraseValue(0);
+ UNIT_ASSERT(src != dst);
+ src.GetValueByPath("key", '.')->EraseValue(0);
+ UNIT_ASSERT(src == dst);
+ }
+
+ {
+ TJsonValue src;
+ TJsonValue value1;
+ TJsonValue arr1;
+ value1.InsertValue("key", "value");
+ arr1.AppendValue(value1);
+ arr1.AppendValue(value1);
+ arr1.AppendValue(value1);
+ src.InsertValue("arr", arr1);
+
+ TJsonValue dst;
+ TJsonValue value2;
+ TJsonValue arr2;
+ value2.InsertValue("key", "value");
+ value2.InsertValue("yek", "eulav");
+ arr2.AppendValue(value2);
+ arr2.AppendValue(value2);
+ arr2.AppendValue(value2);
+ arr2.AppendValue(value2);
+ dst.InsertValue("arr", arr2);
+
+ src["arr"].AppendValue(value1);
+ for (auto& node : src["arr"].GetArraySafe()) {
+ node.InsertValue("yek", "eulav");
+ }
+ UNIT_ASSERT(src == dst);
+ }
+
+ {
+ TJsonValue src;
+ TJsonValue value1;
+ TJsonValue arr1;
+ value1.InsertValue("key", "value");
+ arr1.AppendValue(value1);
+ arr1.AppendValue(value1);
+ arr1.AppendValue(value1);
+ src.InsertValue("arr", arr1);
+
+ TJsonValue dst;
+ TJsonValue value2;
+ TJsonValue arr2;
+ value2.InsertValue("key", "value");
+ value2.InsertValue("yek", "eulav");
+ arr2.AppendValue(value2);
+ arr2.AppendValue(value2);
+ arr2.AppendValue(value2);
+ arr2.AppendValue(value2);
+ dst.InsertValue("arr", arr2);
+
+ src["arr"].AppendValue(value1);
+ for (auto& node : src.GetValueByPath("arr", '.')->GetArraySafe()) {
+ node.InsertValue("yek", "eulav");
+ }
+ UNIT_ASSERT(src == dst);
+ }
+
+ {
+ TJsonValue json;
+ json.InsertValue("key", "value");
+ try {
+ json.GetArraySafe();
+ UNIT_ASSERT(false);
+ } catch (const TJsonException&) {
+ }
+
+ const TJsonValue constJson(json);
+ try {
+ constJson.GetArray();
+ } catch (...) {
+ UNIT_ASSERT(false);
+ }
+ }
+
+ {
+ // Check non-const GetArraySafe()
+ TJsonValue json{JSON_ARRAY};
+ json.GetArraySafe().push_back(TJsonValue{"foo"});
+
+ TJsonValue expectedJson;
+ expectedJson.AppendValue(TJsonValue{"foo"});
+ UNIT_ASSERT(json == expectedJson);
+
+ TJsonValue::TArray jsonArray = std::move(json.GetArraySafe());
+ TJsonValue::TArray expectedArray = {TJsonValue{"foo"}};
+ UNIT_ASSERT(jsonArray == expectedArray);
+ }
+
+ {
+ // Check non-const GetMap()
+ TJsonValue json{JSON_MAP};
+ json.GetMapSafe()["foo"] = "bar";
+
+ TJsonValue expectedJson;
+ expectedJson.InsertValue("foo", "bar");
+ UNIT_ASSERT(json == expectedJson);
+
+ TJsonValue::TMapType jsonMap = std::move(json.GetMapSafe());
+ TJsonValue::TMapType expectedMap = {{"foo", TJsonValue{"bar"}}};
+ UNIT_ASSERT(jsonMap == expectedMap);
+ }
+ }
+
+ Y_UNIT_TEST(NonexistentFieldAccessTest) {
+ {
+ TJsonValue json;
+ json.InsertValue("some", "key");
+
+ UNIT_ASSERT(!json["some"]["weird"]["access"]["sequence"].Has("value"));
+ UNIT_ASSERT(!json["some"]["weird"]["access"]["sequence"].IsDefined());
+
+ UNIT_ASSERT(json["some"].GetType() == JSON_MAP);
+ }
+ }
+
+ Y_UNIT_TEST(DefaultValuesTest) {
+ {
+ TJsonValue json;
+ json.InsertValue("some", "key");
+ json.InsertValue("existing", 1.2);
+
+ UNIT_ASSERT_VALUES_EQUAL(json["existing"].GetDoubleSafe(), 1.2);
+ UNIT_ASSERT_VALUES_EQUAL(json["existing"].GetDoubleSafe(15), 1.2);
+
+ UNIT_ASSERT_EXCEPTION(json["some"].GetUIntegerSafe(), yexception);
+ UNIT_ASSERT_EXCEPTION(json["some"].GetUIntegerSafe(12), yexception);
+
+ UNIT_ASSERT_EXCEPTION(json["nonexistent"].GetUIntegerSafe(), yexception);
+ UNIT_ASSERT_VALUES_EQUAL(json["nonexistent"].GetUIntegerSafe(12), 12);
+ UNIT_ASSERT_VALUES_EQUAL(json["nonexistent"]["more_nonexistent"].GetUIntegerSafe(12), 12);
+
+ json.InsertValue("map", TJsonValue(JSON_MAP));
+
+ UNIT_ASSERT_VALUES_EQUAL(json["map"]["nonexistent"].GetUIntegerSafe(12), 12);
+ }
+ }
+
+ Y_UNIT_TEST(GetArrayPointerInArrayTest) {
+ TJsonValue outer;
+ {
+ TJsonValue json;
+ json.AppendValue(1);
+ json.AppendValue(2);
+ json.AppendValue(3);
+
+ outer.AppendValue(json);
+ }
+ const TJsonValue::TArray* array = nullptr;
+ GetArrayPointer(outer, 0, &array);
+ UNIT_ASSERT_VALUES_EQUAL((*array)[1], 2);
+ }
+
+ Y_UNIT_TEST(GetArrayPointerInMapTest) {
+ TJsonValue outer;
+ {
+ TJsonValue json;
+ json.AppendValue(1);
+ json.AppendValue(2);
+ json.AppendValue(3);
+
+ outer.InsertValue("x", json);
+ }
+ const TJsonValue::TArray* array = nullptr;
+ GetArrayPointer(outer, "x", &array);
+ UNIT_ASSERT_VALUES_EQUAL((*array)[1], 2);
+ }
+
+ Y_UNIT_TEST(GetMapPointerInArrayTest) {
+ TJsonValue outer;
+ {
+ TJsonValue json;
+ json.InsertValue("a", 1);
+ json.InsertValue("b", 2);
+ json.InsertValue("c", 3);
+
+ outer.AppendValue(json);
+ }
+ const TJsonValue::TMapType* map = nullptr;
+ GetMapPointer(outer, 0, &map);
+ UNIT_ASSERT_VALUES_EQUAL((*map).at("b"), 2);
+ }
+
+ Y_UNIT_TEST(GetMapPointerInMapTest) {
+ TJsonValue outer;
+ {
+ TJsonValue json;
+ json.InsertValue("a", 1);
+ json.InsertValue("b", 2);
+ json.InsertValue("c", 3);
+
+ outer.InsertValue("x", json);
+ }
+ const TJsonValue::TMapType* map = nullptr;
+ GetMapPointer(outer, "x", &map);
+ UNIT_ASSERT_VALUES_EQUAL((*map).at("b"), 2);
+ }
+
+ Y_UNIT_TEST(GetIntegerRobustBignumStringTest) {
+ TString value = "1626862681464633683";
+ TJsonValue json(value);
+ UNIT_ASSERT_VALUES_EQUAL(json.GetUIntegerRobust(), FromString<ui64>(value));
+ UNIT_ASSERT_VALUES_EQUAL(json.GetIntegerRobust(), FromString<i64>(value));
+ }
+
+ Y_UNIT_TEST(MoveSubpartToSelf) {
+ TJsonValue json;
+ json[0] = "testing 0";
+ json[1] = "testing 1";
+ json[2] = "testing 2";
+ json = std::move(json[1]);
+ UNIT_ASSERT_VALUES_EQUAL(json.GetString(), "testing 1");
+
+ const char* longTestString =
+ "Testing TJsonValue& operator=(TJsonValue&&) subpart self moving "
+ "after TJsonValue was constrcuted from TString&&.";
+
+ json["hello"] = TString{longTestString};
+ json = std::move(json["hello"]);
+ UNIT_ASSERT_VALUES_EQUAL(json.GetString(), longTestString);
+ }
+
+ Y_UNIT_TEST(TJsonArrayMapConstructor) {
+ TJsonMap emptyMap;
+ UNIT_ASSERT_VALUES_EQUAL(emptyMap.GetType(), JSON_MAP);
+ UNIT_ASSERT_VALUES_EQUAL(emptyMap.GetMapSafe().size(), 0);
+
+ TJsonArray emptyArray;
+ UNIT_ASSERT_VALUES_EQUAL(emptyArray.GetType(), JSON_ARRAY);
+ UNIT_ASSERT_VALUES_EQUAL(emptyArray.GetArraySafe().size(), 0);
+
+ TJsonMap filled = {
+ {"1", 1},
+ {"2", "2"},
+ {"3", TJsonArray{3}},
+ {"4", TJsonMap{{"5", 5}}},
+ };
+ UNIT_ASSERT_VALUES_EQUAL(filled.GetType(), JSON_MAP);
+ UNIT_ASSERT_VALUES_EQUAL(filled["1"], TJsonValue{1});
+ UNIT_ASSERT_VALUES_EQUAL(filled["2"], TJsonValue{"2"});
+ UNIT_ASSERT_VALUES_EQUAL(filled["3"].GetArraySafe().size(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(filled["3"][0], TJsonValue{3});
+ UNIT_ASSERT_VALUES_EQUAL(filled["4"].GetMapSafe().size(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(filled["4"]["5"], TJsonValue{5});
+ }
+} // TJsonValueTest
diff --git a/library/cpp/json/writer/ut/ya.make b/library/cpp/json/writer/ut/ya.make
new file mode 100644
index 0000000000..1e39dae6a1
--- /dev/null
+++ b/library/cpp/json/writer/ut/ya.make
@@ -0,0 +1,16 @@
+UNITTEST()
+
+OWNER(myltsev)
+
+PEERDIR(
+ ADDINCL library/cpp/json/writer
+)
+
+SRCDIR(library/cpp/json/writer)
+
+SRCS(
+ json_ut.cpp
+ json_value_ut.cpp
+)
+
+END()
diff --git a/library/cpp/json/writer/ya.make b/library/cpp/json/writer/ya.make
new file mode 100644
index 0000000000..3989ff3504
--- /dev/null
+++ b/library/cpp/json/writer/ya.make
@@ -0,0 +1,20 @@
+LIBRARY()
+
+OWNER(
+ mvel
+ myltsev
+ pg
+)
+
+PEERDIR(
+ library/cpp/json/common
+)
+
+SRCS(
+ json_value.cpp
+ json.cpp
+)
+
+GENERATE_ENUM_SERIALIZATION(json_value.h)
+
+END()
diff --git a/library/cpp/json/ya.make b/library/cpp/json/ya.make
new file mode 100644
index 0000000000..d58eead8ec
--- /dev/null
+++ b/library/cpp/json/ya.make
@@ -0,0 +1,23 @@
+LIBRARY()
+
+OWNER(
+ pg
+ velavokr
+)
+
+SRCS(
+ json_writer.cpp
+ json_reader.cpp
+ json_prettifier.cpp
+ rapidjson_helpers.cpp
+)
+
+PEERDIR(
+ contrib/libs/rapidjson
+ library/cpp/json/common
+ library/cpp/json/fast_sax
+ library/cpp/json/writer
+ library/cpp/string_utils/relaxed_escaper
+)
+
+END()
diff --git a/library/cpp/json/yson/json2yson.cpp b/library/cpp/json/yson/json2yson.cpp
new file mode 100644
index 0000000000..f72cb7a9ef
--- /dev/null
+++ b/library/cpp/json/yson/json2yson.cpp
@@ -0,0 +1,108 @@
+#include "json2yson.h"
+
+#include <library/cpp/yson/parser.h>
+#include <library/cpp/yson/json/json_writer.h>
+#include <library/cpp/yson/json/yson2json_adapter.h>
+
+namespace NJson2Yson {
+ static void WriteJsonValue(const NJson::TJsonValue& jsonValue, NYT::TYson2JsonCallbacksAdapter* adapter) {
+ switch (jsonValue.GetType()) {
+ default:
+ case NJson::JSON_NULL:
+ adapter->OnNull();
+ break;
+ case NJson::JSON_BOOLEAN:
+ adapter->OnBoolean(jsonValue.GetBoolean());
+ break;
+ case NJson::JSON_DOUBLE:
+ adapter->OnDouble(jsonValue.GetDouble());
+ break;
+ case NJson::JSON_INTEGER:
+ adapter->OnInteger(jsonValue.GetInteger());
+ break;
+ case NJson::JSON_UINTEGER:
+ adapter->OnUInteger(jsonValue.GetUInteger());
+ break;
+ case NJson::JSON_STRING:
+ adapter->OnString(jsonValue.GetString());
+ break;
+ case NJson::JSON_ARRAY: {
+ adapter->OnOpenArray();
+ const NJson::TJsonValue::TArray& arr = jsonValue.GetArray();
+ for (const auto& it : arr)
+ WriteJsonValue(it, adapter);
+ adapter->OnCloseArray();
+ break;
+ }
+ case NJson::JSON_MAP: {
+ adapter->OnOpenMap();
+ const NJson::TJsonValue::TMapType& map = jsonValue.GetMap();
+ for (const auto& it : map) {
+ adapter->OnMapKey(it.first);
+ WriteJsonValue(it.second, adapter);
+ }
+ adapter->OnCloseMap();
+ break;
+ }
+ }
+ }
+
+ void SerializeJsonValueAsYson(const NJson::TJsonValue& inputValue, NYson::TYsonWriter* ysonWriter) {
+ NYT::TYson2JsonCallbacksAdapter adapter(ysonWriter);
+ WriteJsonValue(inputValue, &adapter);
+ }
+
+ void SerializeJsonValueAsYson(const NJson::TJsonValue& inputValue, IOutputStream* outputStream) {
+ NYson::TYsonWriter ysonWriter(outputStream, NYson::EYsonFormat::Binary, ::NYson::EYsonType::Node, false);
+ SerializeJsonValueAsYson(inputValue, &ysonWriter);
+ }
+
+ void SerializeJsonValueAsYson(const NJson::TJsonValue& inputValue, TString& result) {
+ TStringOutput resultStream(result);
+ SerializeJsonValueAsYson(inputValue, &resultStream);
+ }
+
+ TString SerializeJsonValueAsYson(const NJson::TJsonValue& inputValue) {
+ TString result;
+ SerializeJsonValueAsYson(inputValue, result);
+ return result;
+ }
+
+ bool DeserializeYsonAsJsonValue(IInputStream* inputStream, NJson::TJsonValue* outputValue, bool throwOnError) {
+ NJson::TParserCallbacks parser(*outputValue);
+ NJson2Yson::TJsonBuilder consumer(&parser);
+ NYson::TYsonParser ysonParser(&consumer, inputStream, ::NYson::EYsonType::Node);
+ try {
+ ysonParser.Parse();
+ } catch (...) {
+ if (throwOnError) {
+ throw;
+ }
+ return false;
+ }
+ return true;
+ }
+
+ bool DeserializeYsonAsJsonValue(TStringBuf str, NJson::TJsonValue* outputValue, bool throwOnError) {
+ TMemoryInput inputStream(str);
+ return DeserializeYsonAsJsonValue(&inputStream, outputValue, throwOnError);
+ }
+
+ void ConvertYson2Json(IInputStream* inputStream, IOutputStream* outputStream) {
+ NYT::TJsonWriter writer(outputStream, ::NYson::EYsonType::Node, NYT::JF_TEXT, NYT::JAM_ON_DEMAND, NYT::SBF_BOOLEAN);
+ NYson::TYsonParser ysonParser(&writer, inputStream, ::NYson::EYsonType::Node);
+ ysonParser.Parse();
+ }
+
+ void ConvertYson2Json(TStringBuf yson, IOutputStream* outputStream) {
+ TMemoryInput inputStream(yson);
+ ConvertYson2Json(&inputStream, outputStream);
+ }
+
+ TString ConvertYson2Json(TStringBuf yson) {
+ TString json;
+ TStringOutput outputStream(json);
+ ConvertYson2Json(yson, &outputStream);
+ return json;
+ }
+}
diff --git a/library/cpp/json/yson/json2yson.h b/library/cpp/json/yson/json2yson.h
new file mode 100644
index 0000000000..758eb6d0cf
--- /dev/null
+++ b/library/cpp/json/yson/json2yson.h
@@ -0,0 +1,179 @@
+#pragma once
+
+#include <library/cpp/json/json_reader.h>
+#include <library/cpp/json/json_value.h>
+#include <library/cpp/yson/writer.h>
+
+namespace NJson2Yson {
+ class TJsonBuilderImpl: public NYson::TYsonConsumerBase {
+ public:
+ TJsonBuilderImpl(NJson::TJsonCallbacks* parserCallbacks)
+ : ParserCallbacks_(parserCallbacks)
+ {
+ }
+
+ void OnStringScalar(TStringBuf value) override {
+ ParserCallbacks_->OnString(value);
+ }
+
+ void OnInt64Scalar(i64 value) override {
+ ParserCallbacks_->OnInteger(value);
+ }
+
+ void OnUint64Scalar(ui64 value) override {
+ ParserCallbacks_->OnUInteger(value);
+ }
+
+ void OnDoubleScalar(double value) override {
+ ParserCallbacks_->OnDouble(value);
+ }
+
+ void OnBooleanScalar(bool value) override {
+ ParserCallbacks_->OnBoolean(value);
+ }
+
+ void OnEntity() override {
+ ParserCallbacks_->OnNull();
+ }
+
+ void OnBeginList() override {
+ ParserCallbacks_->OnOpenArray();
+ }
+
+ void OnListItem() override {
+ }
+
+ void OnEndList() override {
+ ParserCallbacks_->OnCloseArray();
+ }
+
+ void OnBeginMap() override {
+ ParserCallbacks_->OnOpenMap();
+ }
+
+ void OnKeyedItem(TStringBuf key) override {
+ ParserCallbacks_->OnMapKey(key);
+ }
+
+ void OnEndMap() override {
+ ParserCallbacks_->OnCloseMap();
+ }
+
+ void OnBeginAttributes() override {
+ }
+
+ void OnEndAttributes() override {
+ }
+
+ private:
+ NJson::TJsonCallbacks* ParserCallbacks_;
+ };
+
+ template <typename TBase>
+ class TSkipAttributesProxy: public TBase {
+ public:
+ template <typename... TArgs>
+ TSkipAttributesProxy<TBase>(TArgs&&... args)
+ : TBase(std::forward<TArgs>(args)...)
+ {
+ }
+
+ void OnStringScalar(TStringBuf value) override {
+ if (AttributesDepth == 0) {
+ TBase::OnStringScalar(value);
+ }
+ }
+
+ void OnInt64Scalar(i64 value) override {
+ if (AttributesDepth == 0) {
+ TBase::OnInt64Scalar(value);
+ }
+ }
+
+ void OnUint64Scalar(ui64 value) override {
+ if (AttributesDepth == 0) {
+ TBase::OnUint64Scalar(value);
+ }
+ }
+
+ void OnDoubleScalar(double value) override {
+ if (AttributesDepth == 0) {
+ TBase::OnDoubleScalar(value);
+ }
+ }
+
+ void OnBooleanScalar(bool value) override {
+ if (AttributesDepth == 0) {
+ TBase::OnBooleanScalar(value);
+ }
+ }
+
+ void OnEntity() override {
+ if (AttributesDepth == 0) {
+ TBase::OnEntity();
+ }
+ }
+
+ void OnBeginList() override {
+ if (AttributesDepth == 0) {
+ TBase::OnBeginList();
+ }
+ }
+
+ void OnListItem() override {
+ if (AttributesDepth == 0) {
+ TBase::OnListItem();
+ }
+ }
+
+ void OnEndList() override {
+ if (AttributesDepth == 0) {
+ TBase::OnEndList();
+ }
+ }
+
+ void OnBeginMap() override {
+ if (AttributesDepth == 0) {
+ TBase::OnBeginMap();
+ }
+ }
+
+ void OnKeyedItem(TStringBuf key) override {
+ if (AttributesDepth == 0) {
+ TBase::OnKeyedItem(key);
+ }
+ }
+
+ void OnEndMap() override {
+ if (AttributesDepth == 0) {
+ TBase::OnEndMap();
+ }
+ }
+
+ void OnBeginAttributes() override {
+ ++AttributesDepth;
+ }
+
+ void OnEndAttributes() override {
+ --AttributesDepth;
+ Y_ASSERT(AttributesDepth >= 0);
+ }
+
+ private:
+ int AttributesDepth = 0;
+ };
+
+ using TJsonBuilder = TSkipAttributesProxy<TJsonBuilderImpl>;
+
+ void ConvertYson2Json(IInputStream* inputStream, IOutputStream* outputStream);
+ void ConvertYson2Json(TStringBuf yson, IOutputStream* outputStream);
+ TString ConvertYson2Json(TStringBuf yson);
+
+ bool DeserializeYsonAsJsonValue(IInputStream* inputStream, NJson::TJsonValue* outputValue, bool throwOnError = false);
+ bool DeserializeYsonAsJsonValue(TStringBuf str, NJson::TJsonValue* outputValue, bool throwOnError = false);
+
+ void SerializeJsonValueAsYson(const NJson::TJsonValue& inputValue, NYson::TYsonWriter* ysonWriter);
+ void SerializeJsonValueAsYson(const NJson::TJsonValue& inputValue, IOutputStream* outputStream);
+ void SerializeJsonValueAsYson(const NJson::TJsonValue& inputValue, TString& result);
+ TString SerializeJsonValueAsYson(const NJson::TJsonValue& inputValue);
+}
diff --git a/library/cpp/json/yson/json2yson_ut.cpp b/library/cpp/json/yson/json2yson_ut.cpp
new file mode 100644
index 0000000000..9eb23354cf
--- /dev/null
+++ b/library/cpp/json/yson/json2yson_ut.cpp
@@ -0,0 +1,107 @@
+#include "library/cpp/json/yson/json2yson.h"
+
+#include <library/cpp/blockcodecs/codecs.h>
+#include <library/cpp/histogram/simple/histogram.h>
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/testing/unittest/tests_data.h>
+
+#include <util/datetime/cputimer.h>
+#include <util/stream/file.h>
+
+template <typename TCallBack>
+ui64 Run(TCallBack&& callBack) {
+ TSimpleTimer timer;
+ callBack();
+ return timer.Get().MicroSeconds();
+}
+
+static TString GetRequestsWithDecoding(const TString& inputPath, const NBlockCodecs::ICodec* codec) {
+ TIFStream inputFileStream(inputPath);
+ TString encodedRequests = inputFileStream.ReadAll();
+ TString requests;
+ codec->Decode(encodedRequests, requests);
+ return requests;
+}
+
+Y_UNIT_TEST_SUITE(Json2Yson) {
+ Y_UNIT_TEST(NOAPACHE_REQUESTS) {
+ const ui32 warmUpRetries = 5;
+ const TVector<double> percentiles = {0.25, 0.5, 0.6, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 0.97, 0.99, 1.0};
+
+ NSimpleHistogram::TMultiHistogramCalcer<ui64> calcer;
+
+ TString requests = GetRequestsWithDecoding(GetWorkPath() + "/noapache_requests_sample_lz4", NBlockCodecs::Codec("lz4"));
+ TStringInput inputStream(requests);
+
+ for (TString jsonRequest, jsonString, ysonString; inputStream.ReadLine(jsonRequest);) {
+ TStringInput jsonInput(jsonRequest);
+ NJson::TJsonValue readedJson;
+ NJson::ReadJsonTree(&jsonInput, &readedJson, true);
+ jsonRequest.clear();
+
+ ui64 writeTime = Max<ui64>();
+ ui64 readTime = Max<ui64>();
+
+ for (ui32 i = 0; i < warmUpRetries; ++i) {
+ NJson::TJsonValue Json2Json;
+ TStringOutput jsonWriteOutput(jsonString);
+ NJsonWriter::TBuf jsonBuf(NJsonWriter::HEM_UNSAFE, &jsonWriteOutput);
+
+ writeTime = Min(writeTime, Run([&]() {
+ jsonBuf.WriteJsonValue(&readedJson);
+ }));
+
+ TStringInput jsonInput(jsonString);
+ NJson::TJsonReaderConfig config;
+ config.DontValidateUtf8 = true;
+ readTime = Min(readTime, Run([&]() {
+ NJson::ReadJsonTree(&jsonInput, &config, &Json2Json, true);
+ }));
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ NJsonWriter::TBuf().WriteJsonValue(&readedJson, true).Str(),
+ NJsonWriter::TBuf().WriteJsonValue(&Json2Json, true).Str());
+
+ jsonString.clear();
+ }
+
+ calcer.RecordValue("read_json", readTime);
+ calcer.RecordValue("write_json", writeTime);
+ calcer.RecordValue("read_and_write_json", readTime + writeTime);
+
+ writeTime = Max<ui64>();
+ readTime = Max<ui64>();
+
+ for (ui32 i = 0; i < warmUpRetries; ++i) {
+ NJson::TJsonValue convertedJson;
+ TStringOutput ysonOutput(ysonString);
+
+ writeTime = Min(writeTime, Run([&]() {
+ NJson2Yson::SerializeJsonValueAsYson(readedJson, &ysonOutput);
+ }));
+
+ TStringInput ysonInput(ysonString);
+ readTime = Min(readTime, Run([&]() {
+ NJson2Yson::DeserializeYsonAsJsonValue(&ysonInput, &convertedJson);
+ }));
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ NJsonWriter::TBuf().WriteJsonValue(&convertedJson, true).Str(),
+ NJsonWriter::TBuf().WriteJsonValue(&readedJson, true).Str());
+
+ ysonString.clear();
+ }
+
+ calcer.RecordValue("read_yson", readTime);
+ calcer.RecordValue("write_yson", writeTime);
+ calcer.RecordValue("read_and_write_yson", readTime + writeTime);
+ }
+
+ NJson::TJsonValue histogramJson = NSimpleHistogram::ToJson(calcer.Calc(), percentiles);
+ for (const auto& it : histogramJson.GetMap()) {
+ for (const auto& percentileValue : it.second.GetMap()) {
+ UNIT_ADD_METRIC(it.first + "_" + percentileValue.first, percentileValue.second.GetUInteger() / 1000.0);
+ }
+ }
+ }
+}
diff --git a/library/cpp/json/yson/ut/ya.make b/library/cpp/json/yson/ut/ya.make
new file mode 100644
index 0000000000..4ceb65b279
--- /dev/null
+++ b/library/cpp/json/yson/ut/ya.make
@@ -0,0 +1,28 @@
+OWNER(
+ avitella
+ elshiko
+)
+
+UNITTEST_FOR(library/cpp/json/yson)
+
+ALLOCATOR(LF)
+
+DATA(sbr://363537653)
+
+PEERDIR(
+ library/cpp/blockcodecs
+ library/cpp/histogram/simple
+ library/cpp/testing/unittest
+)
+
+SIZE(LARGE)
+
+TAG(ya:fat)
+
+TIMEOUT(600)
+
+SRCS(
+ json2yson_ut.cpp
+)
+
+END()
diff --git a/library/cpp/json/yson/ya.make b/library/cpp/json/yson/ya.make
new file mode 100644
index 0000000000..9b289d674f
--- /dev/null
+++ b/library/cpp/json/yson/ya.make
@@ -0,0 +1,18 @@
+LIBRARY()
+
+OWNER(
+ avitella
+ elshiko
+)
+
+PEERDIR(
+ library/cpp/json
+ library/cpp/yson
+ library/cpp/yson/json
+)
+
+SRCS(
+ json2yson.cpp
+)
+
+END()
diff --git a/library/cpp/lcs/README.md b/library/cpp/lcs/README.md
new file mode 100644
index 0000000000..7ed3d946d6
--- /dev/null
+++ b/library/cpp/lcs/README.md
@@ -0,0 +1,33 @@
+A set of algorithms for approximate string matching.
+====================================================
+
+**Lcs_via_lis.h**
+Combinatorial algorithm LCS (Longest common subsequence) through LIS (Longest increasing subsequence) for rows S1 and S2 of lengths n and m respectively (we assume that n < m).
+
+Complexity is O(r log n) by time and O(r) of additional memory, where r is the number of pairs (i, j) for which S1[i] = S2[j]. Thus for the uniform distribution of letters of an alphabet of s elements the estimate is O(nm / s * log n).
+
+Effective for large alphabets s = O(n) (like hashes of words in a text). If only the LCS length is needed, the LCS itself will not be built.
+See Gusfield, Algorithms on Strings, Trees and Sequences, 1997, Chapt.12.5
+Or here: http://www.cs.ucf.edu/courses/cap5937/fall2004/Longest%20common%20subsequence.pdf
+
+#### Summary of the idea:
+Let's suppose we have a sequence of numbers.
+
+Denote by:
+- IS is a subsequence strictly increasing from left to right.
+- LIS is the largest IS of the original sequence.
+- DS is a subsequence that does not decrease from left to right.
+- C is a covering of disjoint DS of the original sequence.
+- SC is the smallest such covering.
+
+It is easy to prove the theorem that the dimensions of SC and LIS are the same, and it is possible to construct LIS from SC.
+
+Next, let's suppose we have 2 strings of S1 and S2. It can be shown that if for each symbol in S1 we take the list of its appearances in S2 in the reverse order, and concatenate all such lists keeping order, then any IS in the resulting list will be equivalent to some common subsequence S1 and S2 of the same length. And, consequently, LIS will be equivalent to LCS.
+
+The idea of the algorithm for constructing DS:
+- Going along the original sequence, for the current member x in the list of its DS we find the leftmost, such that its last term is not less than x.
+- If there is one, then add x to the end.
+- If not, add a new DS consisting of x to the DS list.
+
+It can be shown that the DS list constructed this way will be SC.
+
diff --git a/library/cpp/lcs/lcs_via_lis.cpp b/library/cpp/lcs/lcs_via_lis.cpp
new file mode 100644
index 0000000000..1a52608aed
--- /dev/null
+++ b/library/cpp/lcs/lcs_via_lis.cpp
@@ -0,0 +1 @@
+#include "lcs_via_lis.h"
diff --git a/library/cpp/lcs/lcs_via_lis.h b/library/cpp/lcs/lcs_via_lis.h
new file mode 100644
index 0000000000..d26733d94e
--- /dev/null
+++ b/library/cpp/lcs/lcs_via_lis.h
@@ -0,0 +1,193 @@
+#pragma once
+
+#include <library/cpp/containers/paged_vector/paged_vector.h>
+
+#include <util/generic/ptr.h>
+#include <util/generic/hash.h>
+#include <util/generic/vector.h>
+#include <util/generic/algorithm.h>
+#include <util/memory/pool.h>
+
+namespace NLCS {
+ template <typename TVal>
+ struct TLCSCtx {
+ typedef TVector<ui32> TSubsequence;
+ typedef THashMap<TVal, TSubsequence, THash<TVal>, TEqualTo<TVal>, ::TPoolAllocator> TEncounterIndex;
+ typedef TVector<std::pair<ui32, ui32>> TLastIndex;
+ typedef NPagedVector::TPagedVector<TSubsequence, 4096> TCover;
+
+ TMemoryPool Pool;
+ THolder<TEncounterIndex> Encounters;
+ TLastIndex LastIndex;
+ TCover Cover;
+
+ TSubsequence ResultBuffer;
+
+ TLCSCtx()
+ : Pool(16 * 1024 - 64, TMemoryPool::TExpGrow::Instance())
+ {
+ Reset();
+ }
+
+ void Reset() {
+ Encounters.Reset(nullptr);
+ Pool.Clear();
+ Encounters.Reset(new TEncounterIndex(&Pool));
+ LastIndex.clear();
+ Cover.clear();
+ ResultBuffer.clear();
+ }
+ };
+
+ namespace NPrivate {
+ template <typename TIt, typename TVl>
+ struct TSequence {
+ typedef TIt TIter;
+ typedef TVl TVal;
+
+ const TIter Begin;
+ const TIter End;
+ const size_t Size;
+
+ TSequence(TIter beg, TIter end)
+ : Begin(beg)
+ , End(end)
+ , Size(end - beg)
+ {
+ }
+ };
+
+ template <typename TVal, typename TSequence, typename TResult>
+ size_t MakeLCS(TSequence s1, TSequence s2, TResult* res = nullptr, TLCSCtx<TVal>* ctx = nullptr) {
+ typedef TLCSCtx<TVal> TCtx;
+
+ THolder<TCtx> ctxhld;
+
+ if (!ctx) {
+ ctxhld.Reset(new TCtx());
+ ctx = ctxhld.Get();
+ } else {
+ ctx->Reset();
+ }
+
+ size_t maxsize = Max(s1.Size, s2.Size);
+ auto& index = *(ctx->Encounters);
+
+ for (auto it = s1.Begin; it != s1.End; ++it) {
+ index[*it];
+ }
+
+ for (auto it = s2.Begin; it != s2.End; ++it) {
+ auto hit = index.find(*it);
+
+ if (hit != index.end()) {
+ hit->second.push_back(it - s2.Begin);
+ }
+ }
+
+ if (!res) {
+ auto& lastindex = ctx->ResultBuffer;
+ lastindex.reserve(maxsize);
+
+ for (auto it1 = s1.Begin; it1 != s1.End; ++it1) {
+ const auto& sub2 = index[*it1];
+
+ for (auto it2 = sub2.rbegin(); it2 != sub2.rend(); ++it2) {
+ ui32 x = *it2;
+
+ auto lit = LowerBound(lastindex.begin(), lastindex.end(), x);
+
+ if (lit == lastindex.end()) {
+ lastindex.push_back(x);
+ } else {
+ *lit = x;
+ }
+ }
+ }
+
+ return lastindex.size();
+ } else {
+ auto& lastindex = ctx->LastIndex;
+ auto& cover = ctx->Cover;
+
+ lastindex.reserve(maxsize);
+
+ for (auto it1 = s1.Begin; it1 != s1.End; ++it1) {
+ const auto& sub2 = index[*it1];
+
+ for (auto it2 = sub2.rbegin(); it2 != sub2.rend(); ++it2) {
+ ui32 x = *it2;
+
+ auto lit = LowerBound(lastindex.begin(), lastindex.end(), std::make_pair(x, (ui32)0u));
+
+ if (lit == lastindex.end()) {
+ lastindex.push_back(std::make_pair(x, cover.size()));
+ cover.emplace_back();
+ cover.back().push_back(x);
+ } else {
+ *lit = std::make_pair(x, lit->second);
+ cover[lit->second].push_back(x);
+ }
+ }
+ }
+
+ if (cover.empty()) {
+ return 0;
+ }
+
+ std::reverse(cover.begin(), cover.end());
+
+ auto& resbuf = ctx->ResultBuffer;
+
+ resbuf.push_back(cover.front().front());
+
+ for (auto it = cover.begin() + 1; it != cover.end(); ++it) {
+ auto pit = UpperBound(it->begin(), it->end(), resbuf.back(), std::greater<ui32>());
+
+ Y_VERIFY(pit != it->end(), " ");
+
+ resbuf.push_back(*pit);
+ }
+
+ std::reverse(resbuf.begin(), resbuf.end());
+
+ for (auto it = resbuf.begin(); it != resbuf.end(); ++it) {
+ res->push_back(*(s2.Begin + *it));
+ }
+
+ return lastindex.size();
+ }
+ }
+ }
+
+ template <typename TVal, typename TIter, typename TResult>
+ size_t MakeLCS(TIter beg1, TIter end1, TIter beg2, TIter end2, TResult* res = nullptr, TLCSCtx<TVal>* ctx = nullptr) {
+ typedef NPrivate::TSequence<TIter, TVal> TSeq;
+
+ size_t sz1 = end1 - beg1;
+ size_t sz2 = end2 - beg2;
+
+ if (sz2 > sz1) {
+ DoSwap(beg1, beg2);
+ DoSwap(end1, end2);
+ DoSwap(sz1, sz2);
+ }
+
+ return NPrivate::MakeLCS<TVal>(TSeq(beg1, end1), TSeq(beg2, end2), res, ctx);
+ }
+
+ template <typename TVal, typename TColl, typename TRes>
+ size_t MakeLCS(const TColl& coll1, const TColl& coll2, TRes* res = nullptr, TLCSCtx<TVal>* ctx = nullptr) {
+ return MakeLCS<TVal>(coll1.begin(), coll1.end(), coll2.begin(), coll2.end(), res, ctx);
+ }
+
+ template <typename TVal, typename TIter>
+ size_t MeasureLCS(TIter beg1, TIter end1, TIter beg2, TIter end2, TLCSCtx<TVal>* ctx = nullptr) {
+ return MakeLCS<TVal>(beg1, end1, beg2, end2, (TVector<TVal>*)nullptr, ctx);
+ }
+
+ template <typename TVal, typename TColl>
+ size_t MeasureLCS(const TColl& coll1, const TColl& coll2, TLCSCtx<TVal>* ctx = nullptr) {
+ return MeasureLCS<TVal>(coll1.begin(), coll1.end(), coll2.begin(), coll2.end(), ctx);
+ }
+}
diff --git a/library/cpp/lcs/lcs_via_lis_ut.cpp b/library/cpp/lcs/lcs_via_lis_ut.cpp
new file mode 100644
index 0000000000..f6ad5152b6
--- /dev/null
+++ b/library/cpp/lcs/lcs_via_lis_ut.cpp
@@ -0,0 +1,120 @@
+#include <util/generic/utility.h>
+#include <util/string/util.h>
+#include <library/cpp/testing/unittest/registar.h>
+#include "lcs_via_lis.h"
+
+class TLCSTest: public TTestBase {
+ UNIT_TEST_SUITE(TLCSTest);
+ UNIT_TEST(LCSTest);
+ UNIT_TEST_SUITE_END();
+
+private:
+ size_t Length(TStringBuf s1, TStringBuf s2) {
+ TVector<TVector<size_t>> c;
+ c.resize(s1.size() + 1);
+
+ for (size_t i = 0; i < c.size(); ++i) {
+ c[i].resize(s2.size() + 1);
+ }
+
+ for (size_t i = 0; i < s1.size(); ++i) {
+ for (size_t j = 0; j < s2.size(); ++j) {
+ if (s1[i] == s2[j])
+ c[i + 1][j + 1] = c[i][j] + 1;
+ else
+ c[i + 1][j + 1] = Max(c[i + 1][j], c[i][j + 1]);
+ }
+ }
+
+ return c[s1.size()][s2.size()];
+ }
+
+ void CheckLCSLength(TStringBuf s1, TStringBuf s2, size_t size) {
+ size_t len = NLCS::MeasureLCS<char>(s1, s2);
+
+ UNIT_ASSERT_VALUES_EQUAL(len, Length(s1, s2));
+ UNIT_ASSERT_VALUES_EQUAL(len, size);
+ }
+
+ void CheckLCSString(TStringBuf s1, TStringBuf s2, TStringBuf reflcs) {
+ TString lcs;
+ size_t len = NLCS::MakeLCS<char>(s1, s2, &lcs);
+ const char* comment = Sprintf("%s & %s = %s", s1.data(), s2.data(), reflcs.data()).c_str();
+
+ UNIT_ASSERT_VALUES_EQUAL_C(Length(s1, s2), len, comment);
+ UNIT_ASSERT_VALUES_EQUAL_C(lcs.size(), len, comment);
+ UNIT_ASSERT_VALUES_EQUAL_C(NLCS::MeasureLCS<char>(s1, s2), len, comment);
+ UNIT_ASSERT_VALUES_EQUAL_C(reflcs, TStringBuf(lcs), comment);
+ }
+
+ void LCSTest() {
+ CheckLCSString("abacx", "baabca", "bac");
+ const char* m = "mama_myla_ramu";
+ const char* n = "papa_lubil_mamu";
+ const char* s = "aa_l_amu";
+ CheckLCSString(m, n, s);
+ CheckLCSString(n, m, s);
+ CheckLCSString(m, m, m);
+ CheckLCSString(m, "", "");
+ CheckLCSString("", m, "");
+ CheckLCSString("", "", "");
+ {
+ const char* s1 =
+ "atmwuaoccmgirveexxtbkkmioclarskvicyesddirlrgflnietcagkswbvsdnxksipfndmusnuee"
+ "tojygyjyobdfiutsbruuspvibmywhokxsarwbyirsqqnxxnbtkmucmdafaogwmobuuhejspgurpe"
+ "ceokhgdubqewnyqtwwqfibydbcbxhofvcjsftamhvnbdwxdqnphcdiowplcmguxmnpcufrahjagv"
+ "cpjqsyqurrhyghkasnodqqktldyfomgabrxdxpubenfscamoodgpocilewqtbsncggwvkkpuasdl"
+ "cltxywovqjligwhjxnmmtgeuujphgtdjrnxcnmwwbgxnpiotgnhyrxuvxkxdlgmpfeyocaviuhec"
+ "ydecqmttjictnpptoblxqgcrsojrymakgdjvcnppinymdrlgdfpyuykwpmdeifqwupojsgmruyxs"
+ "qijwnxngaxnppxgusyfnaelccytxwrkhxxirhnsastdlyejslrivkrpovnhbwxcdmpqbnjthjtlj"
+ "wnoayakfnpcwdnlgnrghjhiianhsncbjehlsoldjykymduytyiygrdreicjvghdibyjsmxnwvrqb"
+ "jjkjfrtlonfarbwhovladadlbyeygvuxcutxjqhosuxbemtwsqjlvvyegsfgeladiovecfxfymct"
+ "ulofkcogguantmicfrhpnauetejktkhamfuwirjvlyfgjrobywbbitbnckiegbiwbtmapqrbbqws"
+ "wviuplyprwwqoekiuxsmwgwyuwgeurvxempguwmgtadvrkxykffjxfdyxmsibmdlqhldlfbiaegt"
+ "kswcmfidnrhaibuscoyukwhdtoqwlpwnfgamvfqjpfklgurcwvgsluyoyiuumrwwsqgxatxnxhil"
+ "ywpkeaugfaahmchjruavepvnygcmcjdnvulwcuhlolsfxcsrjciwajbhdahpldcfggubcxalqxrl"
+ "coaiyeawxyxujtynodhnxbhs";
+ const char* s2 =
+ "yjufxfeiifhrmydpmsqqgjwtpcxbhqmfpnvsvsapqvsmqmugpqehbdsiiqhcrasxuhcvswcwanwb"
+ "knesbuhtbaitcwebsdbbxwyubjoroekjxweeqnqmydbdbgbnfymcermhpbikocpsfccwjemxjpmc"
+ "hkhtfaoqgvvtpipujsxesiglgnpsdwfjhcawkfpffuyltqqhdkeqwkfpqjhnjdsnxlevyvydikbr"
+ "hnicihnevsofgouxjcnjjknxwwgaaaikdcxmhxfowadqudrapvwlcuwatrmiweijljdehxiwqrnq"
+ "tnhgukbwmadcjpfnxtswhmwnvvnwsllkyshfobrdmukswpgwunysxpnnlmccolvqyjsvagulpcda"
+ "ctsnyjleqgttcgpnhlnagxenuknpxiramgeshhjyoesupkcfcvvpwyweuvcwrawsgvfshppijuug"
+ "hdnujdqjtcdissmlnjgibdljjxntxrgytxlbgvsrrusatqelspeoyvndjifjqxqrpduwbyojjbhi"
+ "tmondbbnuuhpkglmfykeheddwkxjyapfniqoic";
+ CheckLCSLength(s1, s2, 247);
+ }
+ {
+ const char* s1 =
+ "ssyrtvllktbhijkyckviokukaodexiykxcvlvninoasblpuujnqnilnhmacsulaulskphkccnfop"
+ "jlhejqhemdpnihasouinuceugkfkaifdepvffntbkfivsddtxyslnlwiyfbbpnrwlkryetncahih"
+ "vqcrdvvehvrxgnitghbomkprdngrqdswypwfvpdrvqnavxnprakkgoibsxybngvenlbfcghcyldn"
+ "kssfuxvpvfhaawqiandxpsrkyqtiltmojmmwygevhodvsuvdojvwpvvbwpbbnerriufrwgwcjlgx"
+ "jcjchsfiomtkowihdtcyewknlvdeankladmdhwqxokmunttgaqdsbuyhekkxatpydfgquyxuucda"
+ "dllepofxoirmaablfyyibcnqkdbnsaygkqkbvupdhajfshouofnokwlbdtglrbklpgknyuiedppl"
+ "chxbnnmbumdtrsgwitjlmkkdxysvmsvcdulmanmsdeqkmwgfthmntdbthdthdodnubqajpfyssea"
+ "hwxymiyubkhhxlbmjptujiemrdljqkskdkuokvimencavihwqdaqtcljrgwvxpuegnoecobfllwu"
+ "upsfhjrrpiqtjlwigjkpltwfpoqxsdrojtawpaximslojqtadsactemuhpnshkgyoyouldanktcg"
+ "dhxdpwawabxwjhnjdmewrwtciquuiqnwdsbdvnuvjyewmjppkwvcotptmyrsqaovmaysjuvtenuy"
+ "orvdsssgjgcgksdwaaladocotgveuscwauawdhqlkqsjtmltvkkcfkgwpdtormkefkigkppwpvsy"
+ "fpblccsbyboouahotiifixsjuxlvqpqmpmkcgbvsefkqasearilhlxuqdfqqxxohhbdyiudqsree"
+ "btwfxdtxlaynrusgbffhltthkejitseuqyeqvhqgyobijwmspwbsisghsarji";
+ const char* s2 =
+ "lcnygawhsrprxafwnwxnrxurpnqwwtwuciuexxvswckwopnmhhmhvdwmxtgceitqofivvavnqlmo"
+ "hbieyaxcysagyqcvijxyowiognsntxcdlmueoafqvqwafyhgyoewhwxvqswvwfkqohtutawwnmhr"
+ "pjmhyiygdekonlxhkbeaheqvnqbwhambhrrhkyfcehjfblgriumapavbcxxdqytiuylxmhtjjloa"
+ "fvnyhqsgalacknksxxxilgfcankxreaburvmxukmfprfpmfqgqhmirlnltkjxslumhtamtndaffh"
+ "ybfywiwjlafnsgsvywflsfkeeidwptigidvhnqdjiwvgkfynncyujodsjiglubptsdofftfxayno"
+ "txoykiivbvvipdpcgjadvbanaeljdbxxynlqqpdphirrbjqfqtnxabitncafatbosjnlimxfxlrh"
+ "thlfsdyfbhtwywewqubjcvskmwxwjyhesqbviflihnjfejcgjtkgicgmmcurynmdaoifojmedcqb"
+ "aeqalxnljvglnvyverrtosfeeuajyxkmmpjgcioqxnnqpjokxaenfoudondtahjduymwsyxpbvrf"
+ "kpgiavuihdliphwojgjobafhjshjnmhufciepexevtfwcybtripqmnekkirxmljumyxjpqbvmftt"
+ "xmfwokjskummmkaksbeoowfgjwiumpbkdujexectnghqjjuotofwuwvcgtluephymdkrscbfiaeg"
+ "aaypnclkstfqimisanikjxocmhcrotkntprwjbuudswuyuujfawjucwgifhqgepxeidmvcwqsqrv"
+ "karuvpnxhmrvdcocidgtuxasdqkwsdvijmnpmayhfiva";
+ CheckLCSLength(s1, s2, 288);
+ }
+ }
+};
+UNIT_TEST_SUITE_REGISTRATION(TLCSTest)
diff --git a/library/cpp/lcs/ut/ya.make b/library/cpp/lcs/ut/ya.make
new file mode 100644
index 0000000000..3d12898788
--- /dev/null
+++ b/library/cpp/lcs/ut/ya.make
@@ -0,0 +1,15 @@
+OWNER(velavokr)
+
+UNITTEST()
+
+PEERDIR(
+ ADDINCL library/cpp/lcs
+)
+
+SRCDIR(library/cpp/lcs)
+
+SRCS(
+ lcs_via_lis_ut.cpp
+)
+
+END()
diff --git a/library/cpp/lcs/ya.make b/library/cpp/lcs/ya.make
new file mode 100644
index 0000000000..3a7caafc88
--- /dev/null
+++ b/library/cpp/lcs/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(velavokr)
+
+PEERDIR(
+ library/cpp/containers/paged_vector
+)
+
+SRCS(
+ lcs_via_lis.cpp
+)
+
+END()
diff --git a/library/cpp/lfalloc/alloc_profiler/align_ut.cpp b/library/cpp/lfalloc/alloc_profiler/align_ut.cpp
new file mode 100644
index 0000000000..db9b17b95b
--- /dev/null
+++ b/library/cpp/lfalloc/alloc_profiler/align_ut.cpp
@@ -0,0 +1,23 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/scope.h>
+
+Y_UNIT_TEST_SUITE(MemAlign) {
+ Y_UNIT_TEST(ShouldAlign)
+ {
+ for (ui64 size = 8; size <= 32 * 1024; size *= 8) {
+ for (ui64 align = 8; align <= 4096; align *=2) {
+ void* ptr = nullptr;
+
+ int res = posix_memalign(&ptr, align, size);
+ UNIT_ASSERT_C(res == 0 && ptr != nullptr, "memalign failed");
+
+ Y_DEFER {
+ free(ptr);
+ };
+
+ UNIT_ASSERT_C((uintptr_t)ptr % align == 0, "non aligned memory");
+ }
+ }
+ }
+}
diff --git a/library/cpp/lfalloc/alloc_profiler/profiler.cpp b/library/cpp/lfalloc/alloc_profiler/profiler.cpp
new file mode 100644
index 0000000000..0e30927a5a
--- /dev/null
+++ b/library/cpp/lfalloc/alloc_profiler/profiler.cpp
@@ -0,0 +1,81 @@
+#include "profiler.h"
+
+#include "stackcollect.h"
+
+#include <util/generic/algorithm.h>
+#include <util/generic/singleton.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/stream/str.h>
+
+namespace NAllocProfiler {
+
+namespace {
+
+static TAllocationStackCollector& AllocationStackCollector()
+{
+ return *Singleton<TAllocationStackCollector>();
+}
+
+int AllocationCallback(int tag, size_t size, int sizeIdx)
+{
+ Y_UNUSED(sizeIdx);
+
+ static const size_t STACK_FRAMES_COUNT = 32;
+ static const size_t STACK_FRAMES_SKIP = 1;
+
+ void* frames[STACK_FRAMES_COUNT];
+ size_t frameCount = BackTrace(frames, Y_ARRAY_SIZE(frames));
+ if (frameCount <= STACK_FRAMES_SKIP) {
+ return -1;
+ }
+
+ void** stack = &frames[STACK_FRAMES_SKIP];
+ frameCount -= STACK_FRAMES_SKIP;
+
+ auto& collector = AllocationStackCollector();
+ return collector.Alloc(stack, frameCount, tag, size);
+}
+
+void DeallocationCallback(int stackId, int tag, size_t size, int sizeIdx)
+{
+ Y_UNUSED(tag);
+ Y_UNUSED(sizeIdx);
+
+ auto& collector = AllocationStackCollector();
+ collector.Free(stackId, size);
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool StartAllocationSampling(bool profileAllThreads)
+{
+ auto& collector = AllocationStackCollector();
+ collector.Clear();
+
+ NAllocDbg::SetProfileAllThreads(profileAllThreads);
+ NAllocDbg::SetAllocationCallback(AllocationCallback);
+ NAllocDbg::SetDeallocationCallback(DeallocationCallback);
+ NAllocDbg::SetAllocationSamplingEnabled(true);
+ return true;
+}
+
+bool StopAllocationSampling(IAllocationStatsDumper &out, int count)
+{
+ NAllocDbg::SetAllocationCallback(nullptr);
+ NAllocDbg::SetDeallocationCallback(nullptr);
+ NAllocDbg::SetAllocationSamplingEnabled(false);
+
+ auto& collector = AllocationStackCollector();
+ collector.Dump(count, out);
+ return true;
+}
+
+bool StopAllocationSampling(IOutputStream& out, int count) {
+ TAllocationStatsDumper dumper(out);
+ return StopAllocationSampling(dumper, count);
+}
+
+} // namespace NProfiler
diff --git a/library/cpp/lfalloc/alloc_profiler/profiler.h b/library/cpp/lfalloc/alloc_profiler/profiler.h
new file mode 100644
index 0000000000..4ea49b9dcc
--- /dev/null
+++ b/library/cpp/lfalloc/alloc_profiler/profiler.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include "stackcollect.h"
+
+#include <library/cpp/lfalloc/dbg_info/dbg_info.h>
+
+#include <util/generic/noncopyable.h>
+#include <util/stream/output.h>
+
+namespace NAllocProfiler {
+
+////////////////////////////////////////////////////////////////////////////////
+
+inline int SetCurrentScopeTag(int value)
+{
+ return NAllocDbg::SetThreadAllocTag(value);
+}
+
+inline bool SetProfileCurrentThread(bool value)
+{
+ return NAllocDbg::SetProfileCurrentThread(value);
+}
+
+bool StartAllocationSampling(bool profileAllThreads = false);
+bool StopAllocationSampling(IAllocationStatsDumper& out, int count = 100);
+bool StopAllocationSampling(IOutputStream& out, int count = 100);
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TProfilingScope: private TNonCopyable {
+private:
+ const int Prev;
+
+public:
+ explicit TProfilingScope(int value)
+ : Prev(SetCurrentScopeTag(value))
+ {}
+
+ ~TProfilingScope()
+ {
+ SetCurrentScopeTag(Prev);
+ }
+};
+
+} // namespace NAllocProfiler
diff --git a/library/cpp/lfalloc/alloc_profiler/profiler_ut.cpp b/library/cpp/lfalloc/alloc_profiler/profiler_ut.cpp
new file mode 100644
index 0000000000..4341dda6ed
--- /dev/null
+++ b/library/cpp/lfalloc/alloc_profiler/profiler_ut.cpp
@@ -0,0 +1,76 @@
+#include "profiler.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+namespace NAllocProfiler {
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_UNIT_TEST_SUITE(Profiler) {
+ Y_UNIT_TEST(StackCollection)
+ {
+ TStringStream str;
+
+ NAllocProfiler::StartAllocationSampling(true);
+ TVector<TAutoPtr<int>> test;
+ // Do many allocations and no deallocations
+ for (int i = 0; i < 10000; ++i) {
+ test.push_back(new int);
+ }
+ NAllocProfiler::StopAllocationSampling(str);
+ //Cout << str.Str() << Endl;
+
+#if !defined(ARCH_AARCH64)
+ /* Check that output resembles this:
+
+ STACK #2: 0 Allocs: 10 Frees: 0 CurrentSize: 40
+ 0000000000492353 ??
+ 000000000048781F operator new(unsigned long) +1807
+ 00000000003733FA NAllocProfiler::NTestSuiteProfiler::TTestCaseStackCollection::Execute_(NUnitTest::TTestContext&) +218
+ 00000000004A1938 NUnitTest::TTestBase::Run(std::__y1::function<void ()>, TString, char const*, bool) +120
+ 0000000000375656 NAllocProfiler::NTestSuiteProfiler::TCurrentTest::Execute() +342
+ 00000000004A20CF NUnitTest::TTestFactory::Execute() +847
+ 000000000049922D NUnitTest::RunMain(int, char**) +1965
+ 00007FF665778F45 __libc_start_main +245
+ */
+
+ UNIT_ASSERT_STRING_CONTAINS(str.Str(), "StackCollection");
+ UNIT_ASSERT_STRING_CONTAINS(str.Str(), "NUnitTest::TTestBase::Run");
+ UNIT_ASSERT_STRING_CONTAINS(str.Str(), "NAllocProfiler::NTestSuiteProfiler::TCurrentTest::Execute");
+ UNIT_ASSERT_STRING_CONTAINS(str.Str(), "NUnitTest::TTestFactory::Execute");
+ UNIT_ASSERT_STRING_CONTAINS(str.Str(), "NUnitTest::RunMain");
+#endif
+ }
+
+ class TAllocDumper : public NAllocProfiler::TAllocationStatsDumper {
+ public:
+ explicit TAllocDumper(IOutputStream& out) : NAllocProfiler::TAllocationStatsDumper(out) {}
+
+ TString FormatTag(int tag) override {
+ UNIT_ASSERT_VALUES_EQUAL(tag, 42);
+ return "TAG_NAME_42";
+ }
+ };
+
+ Y_UNIT_TEST(TagNames)
+ {
+ TStringStream str;
+
+ NAllocProfiler::StartAllocationSampling(true);
+ TVector<TAutoPtr<int>> test;
+ NAllocProfiler::TProfilingScope scope(42);
+ // Do many allocations and no deallocations
+ for (int i = 0; i < 10000; ++i) {
+ test.push_back(new int);
+ }
+
+ TAllocDumper dumper(str);
+ NAllocProfiler::StopAllocationSampling(dumper);
+
+#if !defined(ARCH_AARCH64)
+ UNIT_ASSERT_STRING_CONTAINS(str.Str(), "TAG_NAME_42");
+#endif
+ }
+}
+
+}
diff --git a/library/cpp/lfalloc/alloc_profiler/stackcollect.cpp b/library/cpp/lfalloc/alloc_profiler/stackcollect.cpp
new file mode 100644
index 0000000000..fded4e2fd1
--- /dev/null
+++ b/library/cpp/lfalloc/alloc_profiler/stackcollect.cpp
@@ -0,0 +1,332 @@
+#include "stackcollect.h"
+
+#include "profiler.h"
+
+#include <util/generic/algorithm.h>
+#include <util/generic/vector.h>
+#include <util/stream/format.h>
+#include <util/stream/str.h>
+#include <util/string/cast.h>
+#include <util/string/printf.h>
+#include <util/system/backtrace.h>
+#include <util/system/spinlock.h>
+#include <util/system/yassert.h>
+
+
+namespace NAllocProfiler {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+class TStackCollector: private TNonCopyable {
+public:
+ struct TFrameInfo {
+ int PrevInd;
+ void* Addr;
+ int Tag;
+ T Stats;
+
+ void Clear()
+ {
+ PrevInd = 0;
+ Addr = nullptr;
+ Tag = 0;
+ Stats.Clear();
+ }
+ };
+
+private:
+ static const size_t STACKS_HASH_MAP_SIZE = 256 * 1024;
+ TFrameInfo Frames[STACKS_HASH_MAP_SIZE];
+
+ ui64 Samples; // Saved samples count
+ ui64 UniqueSamples; // Number of unique addresses
+ ui64 UsedSlots; // Number of occupied slots in the hashtable
+ ui64 DroppedSamples; // Number of unsaved addresses
+ ui64 SearchSkipCount; // Total number of linear hash table probes due to collisions
+
+ TAdaptiveLock Lock;
+
+public:
+ TStackCollector()
+ {
+ Clear();
+ }
+
+ int AddStack(void** stack, size_t frameCount, int tag)
+ {
+ Y_ASSERT(frameCount > 0);
+
+ int prevInd = -1;
+ with_lock (Lock) {
+ for (int i = frameCount - 1; i >= 0; --i) {
+ prevInd = AddFrame(stack[i], prevInd, ((i == 0) ? tag : 0), (i == 0));
+ if (prevInd == -1) {
+ break;
+ }
+ }
+ }
+ return prevInd;
+ }
+
+ T& GetStats(int stackId)
+ {
+ Y_ASSERT(stackId >= 0 && (size_t)stackId < Y_ARRAY_SIZE(Frames));
+ Y_ASSERT(!IsSlotEmpty(stackId));
+
+ return Frames[stackId].Stats;
+ }
+
+ const TFrameInfo* GetFrames() const
+ {
+ return Frames;
+ }
+
+ size_t GetFramesCount() const
+ {
+ return Y_ARRAY_SIZE(Frames);
+ }
+
+ void BackTrace(const TFrameInfo* stack, TStackVec<void*, 64>& frames) const
+ {
+ frames.clear();
+ for (size_t i = 0; i < 100; ++i) {
+ frames.push_back(stack->Addr);
+ int prevInd = stack->PrevInd;
+ if (prevInd == -1) {
+ break;
+ }
+ stack = &Frames[prevInd];
+ }
+ }
+
+ void Clear()
+ {
+ for (auto& frame: Frames) {
+ frame.Clear();
+ }
+
+ Samples = 0;
+ DroppedSamples = 0;
+ UniqueSamples = 0;
+ UsedSlots = 0;
+ SearchSkipCount = 0;
+ }
+
+private:
+ // Hash function applied to the addresses
+ static ui32 Hash(void* addr, int prevInd, int tag)
+ {
+ return (((size_t)addr + ((size_t)addr / STACKS_HASH_MAP_SIZE)) + prevInd + tag) % STACKS_HASH_MAP_SIZE;
+ }
+
+ static bool EqualFrame(const TFrameInfo& frame, void* addr, int prevInd, int tag)
+ {
+ return (frame.Addr == addr && frame.PrevInd == prevInd && frame.Tag == tag);
+ }
+
+ bool IsSlotEmpty(ui32 slot) const
+ {
+ return Frames[slot].Addr == 0;
+ }
+
+ bool InsertsAllowed() const
+ {
+ return UsedSlots < STACKS_HASH_MAP_SIZE / 2;
+ }
+
+ // returns the index in the hashmap
+ int AddFrame(void* addr, int prevFrameIndex, int tag, bool last)
+ {
+ ui32 slot = Hash(addr, prevFrameIndex, tag);
+ ui32 prevSlot = (slot - 1) % STACKS_HASH_MAP_SIZE;
+
+ while (!EqualFrame(Frames[slot], addr, prevFrameIndex, tag) && !IsSlotEmpty(slot) && slot != prevSlot) {
+ slot = (slot + 1) % STACKS_HASH_MAP_SIZE;
+ SearchSkipCount++;
+ }
+
+ if (EqualFrame(Frames[slot], addr, prevFrameIndex, tag)) {
+ if (last) {
+ ++Samples;
+ }
+ } else if (InsertsAllowed() && IsSlotEmpty(slot)) {
+ // add new sample
+ Frames[slot].Clear();
+ Frames[slot].Addr = addr;
+ Frames[slot].PrevInd = prevFrameIndex;
+ Frames[slot].Tag = tag;
+ ++UsedSlots;
+ if (last) {
+ ++UniqueSamples;
+ ++Samples;
+ }
+ } else {
+ // don't insert new sample if the search is becoming too slow
+ ++DroppedSamples;
+ return -1;
+ }
+
+ return slot;
+ }
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TAllocationStackCollector::TImpl: public TStackCollector<TStats> {
+ using TBase = TStackCollector<TStats>;
+
+private:
+ TStats Total;
+
+public:
+ int Alloc(void** stack, size_t frameCount, int tag, size_t size)
+ {
+ int stackId = TBase::AddStack(stack, frameCount, tag);
+ if (stackId >= 0) {
+ TBase::GetStats(stackId).Alloc(size);
+ Total.Alloc(size);
+ }
+ return stackId;
+ }
+
+ void Free(int stackId, size_t size)
+ {
+ TBase::GetStats(stackId).Free(size);
+ Total.Free(size);
+ }
+
+ void Clear()
+ {
+ TBase::Clear();
+ Total.Clear();
+ }
+
+ void Dump(int count, IAllocationStatsDumper& out) const
+ {
+ const TFrameInfo* frames = TBase::GetFrames();
+ size_t framesCount = TBase::GetFramesCount();
+
+ TVector<const TFrameInfo*> stacks;
+ for (size_t i = 0; i < framesCount; ++i) {
+ if (frames[i].Stats.Allocs) {
+ stacks.push_back(&frames[i]);
+ }
+ }
+
+ Sort(stacks, [] (const TFrameInfo* l, const TFrameInfo* r) {
+ const auto& ls = l->Stats;
+ const auto& rs = r->Stats;
+ return ls.CurrentSize != rs.CurrentSize
+ ? ls.CurrentSize > rs.CurrentSize
+ : ls.Allocs != rs.Allocs
+ ? ls.Allocs > rs.Allocs
+ : ls.Frees > rs.Frees;
+ });
+
+ out.DumpTotal(Total);
+
+ TAllocationInfo allocInfo;
+ int printedCount = 0;
+ for (const TFrameInfo* stack: stacks) {
+ allocInfo.Clear();
+ allocInfo.Tag = stack->Tag;
+ allocInfo.Stats = stack->Stats;
+ TBase::BackTrace(stack, allocInfo.Stack);
+
+ out.DumpEntry(allocInfo);
+
+ if (++printedCount >= count) {
+ break;
+ }
+ }
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+TAllocationStackCollector::TAllocationStackCollector()
+ : Impl(new TImpl())
+{}
+
+TAllocationStackCollector::~TAllocationStackCollector()
+{}
+
+int TAllocationStackCollector::Alloc(void** stack, size_t frameCount, int tag, size_t size)
+{
+ return Impl->Alloc(stack, frameCount, tag, size);
+}
+
+void TAllocationStackCollector::Free(int stackId, size_t size)
+{
+ Impl->Free(stackId, size);
+}
+
+void TAllocationStackCollector::Clear()
+{
+ Impl->Clear();
+}
+
+void TAllocationStackCollector::Dump(int count, IAllocationStatsDumper &out) const
+{
+ Impl->Dump(count, out);
+}
+
+
+TString IAllocationStatsDumper::FormatTag(int tag) {
+ return ToString(tag);
+}
+
+TString IAllocationStatsDumper::FormatSize(intptr_t sz) {
+ return ToString(sz);
+}
+
+
+TAllocationStatsDumper::TAllocationStatsDumper(IOutputStream& out)
+ : PrintedCount(0)
+ , Out(out)
+ , SymbolCache(2048)
+{}
+
+void TAllocationStatsDumper::DumpTotal(const TStats& total) {
+ Out << "TOTAL"
+ << "\tAllocs: " << total.Allocs
+ << "\tFrees: " << total.Frees
+ << "\tCurrentSize: " << FormatSize(total.CurrentSize)
+ << Endl;
+}
+
+void TAllocationStatsDumper::DumpEntry(const TAllocationInfo& allocInfo) {
+ Out << Endl
+ << "STACK #" << PrintedCount+1 << ": " << FormatTag(allocInfo.Tag)
+ << "\tAllocs: " << allocInfo.Stats.Allocs
+ << "\tFrees: " << allocInfo.Stats.Frees
+ << "\tCurrentSize: " << FormatSize(allocInfo.Stats.CurrentSize)
+ << Endl;
+ FormatBackTrace(allocInfo.Stack.data(), allocInfo.Stack.size());
+ PrintedCount++;
+}
+
+void TAllocationStatsDumper::FormatBackTrace(void* const* stack, size_t sz) {
+ char name[1024];
+ for (size_t i = 0; i < sz; ++i) {
+ TSymbol symbol;
+ auto it = SymbolCache.Find(stack[i]);
+ if (it != SymbolCache.End()) {
+ symbol = it.Value();
+ } else {
+ TResolvedSymbol rs = ResolveSymbol(stack[i], name, sizeof(name));
+ symbol = {rs.NearestSymbol, rs.Name};
+ SymbolCache.Insert(stack[i], symbol);
+ }
+
+ Out << Hex((intptr_t)stack[i], HF_FULL) << "\t" << symbol.Name;
+ intptr_t offset = (intptr_t)stack[i] - (intptr_t)symbol.Address;
+ if (offset)
+ Out << " +" << offset;
+ Out << Endl;
+ }
+}
+
+} // namespace NAllocProfiler
diff --git a/library/cpp/lfalloc/alloc_profiler/stackcollect.h b/library/cpp/lfalloc/alloc_profiler/stackcollect.h
new file mode 100644
index 0000000000..80715ed7cb
--- /dev/null
+++ b/library/cpp/lfalloc/alloc_profiler/stackcollect.h
@@ -0,0 +1,107 @@
+#pragma once
+
+#include <library/cpp/containers/stack_vector/stack_vec.h>
+#include <library/cpp/cache/cache.h>
+
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/stream/output.h>
+
+namespace NAllocProfiler {
+
+struct TStats {
+ intptr_t Allocs = 0;
+ intptr_t Frees = 0;
+ intptr_t CurrentSize = 0;
+
+ void Clear()
+ {
+ Allocs = 0;
+ Frees = 0;
+ CurrentSize = 0;
+ }
+
+ void Alloc(size_t size)
+ {
+ AtomicIncrement(Allocs);
+ AtomicAdd(CurrentSize, size);
+ }
+
+ void Free(size_t size)
+ {
+ AtomicIncrement(Frees);
+ AtomicSub(CurrentSize, size);
+ }
+};
+
+struct TAllocationInfo {
+ int Tag;
+ TStats Stats;
+ TStackVec<void*, 64> Stack;
+
+ void Clear() {
+ Tag = 0;
+ Stats.Clear();
+ Stack.clear();
+ }
+};
+
+
+class IAllocationStatsDumper {
+public:
+ virtual ~IAllocationStatsDumper() = default;
+
+ // Total stats
+ virtual void DumpTotal(const TStats& total) = 0;
+
+ // Stats for individual stack
+ virtual void DumpEntry(const TAllocationInfo& allocInfo) = 0;
+
+ // App-specific tag printer
+ virtual TString FormatTag(int tag);
+
+ // Size printer (e.g. "10KB", "100MB", "over 9000")
+ virtual TString FormatSize(intptr_t sz);
+};
+
+// Default implementation
+class TAllocationStatsDumper: public IAllocationStatsDumper {
+public:
+ explicit TAllocationStatsDumper(IOutputStream& out);
+ void DumpTotal(const TStats& total) override;
+ void DumpEntry(const TAllocationInfo& allocInfo) override;
+
+private:
+ void FormatBackTrace(void* const* stack, size_t sz);
+
+private:
+ struct TSymbol {
+ const void* Address;
+ TString Name;
+ };
+
+ size_t PrintedCount;
+ IOutputStream& Out;
+ TLFUCache<void*, TSymbol> SymbolCache;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TAllocationStackCollector: private TNonCopyable {
+private:
+ class TImpl;
+ THolder<TImpl> Impl;
+
+public:
+ TAllocationStackCollector();
+ ~TAllocationStackCollector();
+
+ int Alloc(void** stack, size_t frameCount, int tag, size_t size);
+ void Free(int stackId, size_t size);
+
+ void Clear();
+
+ void Dump(int count, IAllocationStatsDumper& out) const;
+};
+
+} // namespace NAllocProfiler
diff --git a/library/cpp/lfalloc/alloc_profiler/ut/ya.make b/library/cpp/lfalloc/alloc_profiler/ut/ya.make
new file mode 100644
index 0000000000..8a7daa74af
--- /dev/null
+++ b/library/cpp/lfalloc/alloc_profiler/ut/ya.make
@@ -0,0 +1,22 @@
+UNITTEST_FOR(library/cpp/lfalloc/alloc_profiler)
+
+OWNER(g:rtmr g:kikimr)
+
+PEERDIR(
+ library/cpp/testing/unittest
+)
+
+IF (ARCH_AARCH64)
+ PEERDIR(
+ contrib/libs/jemalloc
+ )
+ELSE()
+ ALLOCATOR(LF_DBG)
+ENDIF()
+
+SRCS(
+ profiler_ut.cpp
+ align_ut.cpp
+)
+
+END()
diff --git a/library/cpp/lfalloc/alloc_profiler/ya.make b/library/cpp/lfalloc/alloc_profiler/ya.make
new file mode 100644
index 0000000000..0f58d91767
--- /dev/null
+++ b/library/cpp/lfalloc/alloc_profiler/ya.make
@@ -0,0 +1,17 @@
+LIBRARY()
+
+OWNER(g:rtmr g:kikimr)
+
+SRCS(
+ profiler.cpp
+ stackcollect.cpp
+)
+
+PEERDIR(
+ library/cpp/lfalloc/dbg_info
+ library/cpp/cache
+)
+
+END()
+
+RECURSE(ut)
diff --git a/library/cpp/lfalloc/dbg/ya.make b/library/cpp/lfalloc/dbg/ya.make
new file mode 100644
index 0000000000..3dce653a8c
--- /dev/null
+++ b/library/cpp/lfalloc/dbg/ya.make
@@ -0,0 +1,32 @@
+LIBRARY()
+
+OWNER(vskipin)
+
+NO_UTIL()
+
+NO_COMPILER_WARNINGS()
+
+IF (ARCH_AARCH64)
+ PEERDIR(
+ contrib/libs/jemalloc
+ )
+ELSE()
+ IF ("${YMAKE}" MATCHES "devtools")
+ CFLAGS(-DYMAKE=1)
+ ENDIF()
+ CXXFLAGS(
+ -DLFALLOC_DBG
+ -DLFALLOC_YT
+ )
+ SRCS(
+ ../lf_allocX64.cpp
+ )
+ENDIF()
+
+PEERDIR(
+ library/cpp/malloc/api
+)
+
+SET(IDE_FOLDER "util")
+
+END()
diff --git a/library/cpp/lfalloc/dbg_info/dbg_info.cpp b/library/cpp/lfalloc/dbg_info/dbg_info.cpp
new file mode 100644
index 0000000000..1fb9f7ad93
--- /dev/null
+++ b/library/cpp/lfalloc/dbg_info/dbg_info.cpp
@@ -0,0 +1,124 @@
+#include "dbg_info.h"
+
+#include <library/cpp/malloc/api/malloc.h>
+
+namespace NAllocDbg {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ using TGetAllocationCounter = i64(int counter);
+
+ using TSetThreadAllocTag = int(int tag);
+ using TGetPerTagAllocInfo = void(
+ bool flushPerThreadCounters,
+ TPerTagAllocInfo* info,
+ int& maxTag,
+ int& numSizes);
+
+ using TSetProfileCurrentThread = bool(bool newVal);
+ using TSetProfileAllThreads = bool(bool newVal);
+ using TSetAllocationSamplingEnabled = bool(bool newVal);
+
+ using TSetAllocationSampleRate = size_t(size_t newVal);
+ using TSetAllocationSampleMaxSize = size_t(size_t newVal);
+
+ using TSetAllocationCallback = TAllocationCallback*(TAllocationCallback* newVal);
+ using TSetDeallocationCallback = TDeallocationCallback*(TDeallocationCallback* newVal);
+
+ struct TAllocFn {
+ TGetAllocationCounter* GetAllocationCounterFast = nullptr;
+ TGetAllocationCounter* GetAllocationCounterFull = nullptr;
+
+ TSetThreadAllocTag* SetThreadAllocTag = nullptr;
+ TGetPerTagAllocInfo* GetPerTagAllocInfo = nullptr;
+
+ TSetProfileCurrentThread* SetProfileCurrentThread = nullptr;
+ TSetProfileAllThreads* SetProfileAllThreads = nullptr;
+ TSetAllocationSamplingEnabled* SetAllocationSamplingEnabled = nullptr;
+
+ TSetAllocationSampleRate* SetAllocationSampleRate = nullptr;
+ TSetAllocationSampleMaxSize* SetAllocationSampleMaxSize = nullptr;
+
+ TSetAllocationCallback* SetAllocationCallback = nullptr;
+ TSetDeallocationCallback* SetDeallocationCallback = nullptr;
+
+ TAllocFn() {
+ auto mallocInfo = NMalloc::MallocInfo();
+
+ GetAllocationCounterFast = (TGetAllocationCounter*)mallocInfo.GetParam("GetLFAllocCounterFast");
+ GetAllocationCounterFull = (TGetAllocationCounter*)mallocInfo.GetParam("GetLFAllocCounterFull");
+
+ SetThreadAllocTag = (TSetThreadAllocTag*)mallocInfo.GetParam("SetThreadAllocTag");
+ GetPerTagAllocInfo = (TGetPerTagAllocInfo*)mallocInfo.GetParam("GetPerTagAllocInfo");
+
+ SetProfileCurrentThread = (TSetProfileCurrentThread*)mallocInfo.GetParam("SetProfileCurrentThread");
+ SetProfileAllThreads = (TSetProfileAllThreads*)mallocInfo.GetParam("SetProfileAllThreads");
+ SetAllocationSamplingEnabled = (TSetAllocationSamplingEnabled*)mallocInfo.GetParam("SetAllocationSamplingEnabled");
+
+ SetAllocationSampleRate = (TSetAllocationSampleRate*)mallocInfo.GetParam("SetAllocationSampleRate");
+ SetAllocationSampleMaxSize = (TSetAllocationSampleMaxSize*)mallocInfo.GetParam("SetAllocationSampleMaxSize");
+
+ SetAllocationCallback = (TSetAllocationCallback*)mallocInfo.GetParam("SetAllocationCallback");
+ SetDeallocationCallback = (TSetDeallocationCallback*)mallocInfo.GetParam("SetDeallocationCallback");
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static TAllocFn AllocFn;
+
+ i64 GetAllocationCounterFast(ELFAllocCounter counter) {
+ return AllocFn.GetAllocationCounterFast ? AllocFn.GetAllocationCounterFast(counter) : 0;
+ }
+
+ i64 GetAllocationCounterFull(ELFAllocCounter counter) {
+ return AllocFn.GetAllocationCounterFull ? AllocFn.GetAllocationCounterFull(counter) : 0;
+ }
+
+ int SetThreadAllocTag(int tag) {
+ return AllocFn.SetThreadAllocTag ? AllocFn.SetThreadAllocTag(tag) : 0;
+ }
+
+ TArrayPtr<TPerTagAllocInfo> GetPerTagAllocInfo(
+ bool flushPerThreadCounters,
+ int& maxTag,
+ int& numSizes) {
+ if (AllocFn.GetPerTagAllocInfo) {
+ AllocFn.GetPerTagAllocInfo(flushPerThreadCounters, nullptr, maxTag, numSizes);
+ TArrayPtr<TPerTagAllocInfo> info = new TPerTagAllocInfo[maxTag * numSizes];
+ AllocFn.GetPerTagAllocInfo(flushPerThreadCounters, info.Get(), maxTag, numSizes);
+ return info;
+ }
+ maxTag = 0;
+ numSizes = 0;
+ return nullptr;
+ }
+
+ bool SetProfileCurrentThread(bool newVal) {
+ return AllocFn.SetProfileCurrentThread ? AllocFn.SetProfileCurrentThread(newVal) : false;
+ }
+
+ bool SetProfileAllThreads(bool newVal) {
+ return AllocFn.SetProfileAllThreads ? AllocFn.SetProfileAllThreads(newVal) : false;
+ }
+
+ bool SetAllocationSamplingEnabled(bool newVal) {
+ return AllocFn.SetAllocationSamplingEnabled ? AllocFn.SetAllocationSamplingEnabled(newVal) : false;
+ }
+
+ size_t SetAllocationSampleRate(size_t newVal) {
+ return AllocFn.SetAllocationSampleRate ? AllocFn.SetAllocationSampleRate(newVal) : 0;
+ }
+
+ size_t SetAllocationSampleMaxSize(size_t newVal) {
+ return AllocFn.SetAllocationSampleMaxSize ? AllocFn.SetAllocationSampleMaxSize(newVal) : 0;
+ }
+
+ TAllocationCallback* SetAllocationCallback(TAllocationCallback* newVal) {
+ return AllocFn.SetAllocationCallback ? AllocFn.SetAllocationCallback(newVal) : nullptr;
+ }
+
+ TDeallocationCallback* SetDeallocationCallback(TDeallocationCallback* newVal) {
+ return AllocFn.SetDeallocationCallback ? AllocFn.SetDeallocationCallback(newVal) : nullptr;
+ }
+
+}
diff --git a/library/cpp/lfalloc/dbg_info/dbg_info.h b/library/cpp/lfalloc/dbg_info/dbg_info.h
new file mode 100644
index 0000000000..071562a81a
--- /dev/null
+++ b/library/cpp/lfalloc/dbg_info/dbg_info.h
@@ -0,0 +1,77 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/system/types.h>
+
+namespace NAllocDbg {
+ ////////////////////////////////////////////////////////////////////////////////
+ // Allocation statistics
+
+ enum ELFAllocCounter {
+ CT_USER_ALLOC, // accumulated size requested by user code
+ CT_MMAP, // accumulated mmapped size
+ CT_MMAP_CNT, // number of mmapped regions
+ CT_MUNMAP, // accumulated unmmapped size
+ CT_MUNMAP_CNT, // number of munmaped regions
+ CT_SYSTEM_ALLOC, // accumulated allocated size for internal lfalloc needs
+ CT_SYSTEM_FREE, // accumulated deallocated size for internal lfalloc needs
+ CT_SMALL_ALLOC, // accumulated allocated size for fixed-size blocks
+ CT_SMALL_FREE, // accumulated deallocated size for fixed-size blocks
+ CT_LARGE_ALLOC, // accumulated allocated size for large blocks
+ CT_LARGE_FREE, // accumulated deallocated size for large blocks
+ CT_SLOW_ALLOC_CNT, // number of slow (not LF) allocations
+ CT_DEGRAGMENT_CNT, // number of memory defragmentations
+ CT_MAX
+ };
+
+ i64 GetAllocationCounterFast(ELFAllocCounter counter);
+ i64 GetAllocationCounterFull(ELFAllocCounter counter);
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Allocation statistics could be tracked on per-tag basis
+
+ int SetThreadAllocTag(int tag);
+
+ class TScopedTag {
+ private:
+ int PrevTag;
+
+ public:
+ explicit TScopedTag(int tag) {
+ PrevTag = SetThreadAllocTag(tag);
+ }
+
+ ~TScopedTag() {
+ SetThreadAllocTag(PrevTag);
+ }
+ };
+
+ struct TPerTagAllocInfo {
+ ssize_t Count;
+ ssize_t Size;
+ };
+
+ TArrayPtr<TPerTagAllocInfo> GetPerTagAllocInfo(
+ bool flushPerThreadCounters,
+ int& maxTag,
+ int& numSizes);
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Allocation sampling could be used to collect detailed information
+
+ bool SetProfileCurrentThread(bool newVal);
+ bool SetProfileAllThreads(bool newVal);
+ bool SetAllocationSamplingEnabled(bool newVal);
+
+ size_t SetAllocationSampleRate(size_t newVal);
+ size_t SetAllocationSampleMaxSize(size_t newVal);
+
+#define DBG_ALLOC_INVALID_COOKIE (-1)
+
+ using TAllocationCallback = int(int tag, size_t size, int sizeIdx);
+ using TDeallocationCallback = void(int cookie, int tag, size_t size, int sizeIdx);
+
+ TAllocationCallback* SetAllocationCallback(TAllocationCallback* newVal);
+ TDeallocationCallback* SetDeallocationCallback(TDeallocationCallback* newVal);
+
+}
diff --git a/library/cpp/lfalloc/dbg_info/ya.make b/library/cpp/lfalloc/dbg_info/ya.make
new file mode 100644
index 0000000000..efecba5993
--- /dev/null
+++ b/library/cpp/lfalloc/dbg_info/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(vskipin)
+
+PEERDIR(
+ library/cpp/malloc/api
+)
+
+SRCS(
+ dbg_info.cpp
+)
+
+SET(IDE_FOLDER "util")
+
+END()
diff --git a/library/cpp/lfalloc/lf_allocX64.cpp b/library/cpp/lfalloc/lf_allocX64.cpp
new file mode 100644
index 0000000000..2eb90761fe
--- /dev/null
+++ b/library/cpp/lfalloc/lf_allocX64.cpp
@@ -0,0 +1,144 @@
+#include "lf_allocX64.h"
+
+//////////////////////////////////////////////////////////////////////////
+// hooks
+#if defined(USE_INTELCC) || defined(_darwin_) || defined(_freebsd_) || defined(_STLPORT_VERSION)
+#define OP_THROWNOTHING noexcept
+#else
+#define OP_THROWNOTHING
+#endif
+
+#ifndef _darwin_
+#if !defined(YMAKE)
+void* operator new(size_t size) {
+ return LFAlloc(size);
+}
+
+void* operator new(size_t size, const std::nothrow_t&) OP_THROWNOTHING {
+ return LFAlloc(size);
+}
+
+void operator delete(void* p)OP_THROWNOTHING {
+ LFFree(p);
+}
+
+void operator delete(void* p, const std::nothrow_t&)OP_THROWNOTHING {
+ LFFree(p);
+}
+
+void* operator new[](size_t size) {
+ return LFAlloc(size);
+}
+
+void* operator new[](size_t size, const std::nothrow_t&) OP_THROWNOTHING {
+ return LFAlloc(size);
+}
+
+void operator delete[](void* p) OP_THROWNOTHING {
+ LFFree(p);
+}
+
+void operator delete[](void* p, const std::nothrow_t&) OP_THROWNOTHING {
+ LFFree(p);
+}
+#endif
+
+//#ifndef _MSC_VER
+
+extern "C" void* malloc(size_t size) {
+ return LFAlloc(size);
+}
+
+extern "C" void* valloc(size_t size) {
+ return LFVAlloc(size);
+}
+
+extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size) {
+ return LFPosixMemalign(memptr, alignment, size);
+}
+
+extern "C" void* memalign(size_t alignment, size_t size) {
+ void* ptr;
+ int res = LFPosixMemalign(&ptr, alignment, size);
+ return res ? nullptr : ptr;
+}
+
+extern "C" void* aligned_alloc(size_t alignment, size_t size) {
+ return memalign(alignment, size);
+}
+
+#if !defined(_MSC_VER) && !defined(_freebsd_)
+// Workaround for pthread_create bug in linux.
+extern "C" void* __libc_memalign(size_t alignment, size_t size) {
+ return memalign(alignment, size);
+}
+#endif
+
+extern "C" void free(void* ptr) {
+ LFFree(ptr);
+}
+
+extern "C" void* calloc(size_t n, size_t elem_size) {
+ // Overflow check
+ const size_t size = n * elem_size;
+ if (elem_size != 0 && size / elem_size != n)
+ return nullptr;
+
+ void* result = LFAlloc(size);
+ if (result != nullptr) {
+ memset(result, 0, size);
+ }
+ return result;
+}
+
+extern "C" void cfree(void* ptr) {
+ LFFree(ptr);
+}
+
+extern "C" void* realloc(void* old_ptr, size_t new_size) {
+ if (old_ptr == nullptr) {
+ void* result = LFAlloc(new_size);
+ return result;
+ }
+ if (new_size == 0) {
+ LFFree(old_ptr);
+ return nullptr;
+ }
+
+ void* new_ptr = LFAlloc(new_size);
+ if (new_ptr == nullptr) {
+ return nullptr;
+ }
+ size_t old_size = LFGetSize(old_ptr);
+ memcpy(new_ptr, old_ptr, ((old_size < new_size) ? old_size : new_size));
+ LFFree(old_ptr);
+ return new_ptr;
+}
+
+extern "C" size_t malloc_usable_size(void* ptr) {
+ if (ptr == nullptr) {
+ return 0;
+ }
+ return LFGetSize(ptr);
+}
+
+NMalloc::TMallocInfo NMalloc::MallocInfo() {
+ NMalloc::TMallocInfo r;
+#if defined(LFALLOC_DBG)
+ r.Name = "lfalloc_dbg";
+#elif defined(LFALLOC_YT)
+ r.Name = "lfalloc_yt";
+#else
+ r.Name = "lfalloc";
+#endif
+ r.SetParam = &LFAlloc_SetParam;
+ r.GetParam = &LFAlloc_GetParam;
+ return r;
+}
+#else
+NMalloc::TMallocInfo NMalloc::MallocInfo() {
+ NMalloc::TMallocInfo r;
+ r.Name = "system-darwin";
+ return r;
+}
+#endif
diff --git a/library/cpp/lfalloc/lf_allocX64.h b/library/cpp/lfalloc/lf_allocX64.h
new file mode 100644
index 0000000000..fd2a906d6f
--- /dev/null
+++ b/library/cpp/lfalloc/lf_allocX64.h
@@ -0,0 +1,1926 @@
+#pragma once
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <library/cpp/malloc/api/malloc.h>
+
+#include <util/system/compat.h>
+#include <util/system/compiler.h>
+#include <util/system/types.h>
+
+#ifdef _MSC_VER
+#ifndef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+#ifdef _M_X64
+#define _64_
+#endif
+#include <intrin.h>
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#pragma intrinsic(_InterlockedCompareExchange)
+#pragma intrinsic(_InterlockedExchangeAdd)
+
+#include <new>
+#include <assert.h>
+#include <errno.h>
+
+#define PERTHREAD __declspec(thread)
+#define _win_
+#define Y_FORCE_INLINE __forceinline
+
+using TAtomic = volatile long;
+
+static inline long AtomicAdd(TAtomic& a, long b) {
+ return _InterlockedExchangeAdd(&a, b) + b;
+}
+
+static inline long AtomicSub(TAtomic& a, long b) {
+ return AtomicAdd(a, -b);
+}
+
+#pragma comment(lib, "synchronization.lib")
+
+#ifndef NDEBUG
+#define Y_ASSERT_NOBT(x) \
+ { \
+ if (IsDebuggerPresent()) { \
+ if (!(x)) \
+ __debugbreak(); \
+ } else \
+ assert(x); \
+ }
+#else
+#define Y_ASSERT_NOBT(x) ((void)0)
+#endif
+
+#else
+
+#include <util/system/defaults.h>
+#include <util/system/atomic.h>
+#include <util/system/yassert.h>
+
+#if !defined(NDEBUG) && !defined(__GCCXML__)
+#define Y_ASSERT_NOBT(a) \
+ do { \
+ try { \
+ if (Y_UNLIKELY(!(a))) { \
+ if (YaIsDebuggerPresent()) \
+ __debugbreak(); \
+ else { \
+ assert(false && (a)); \
+ } \
+ } \
+ } catch (...) { \
+ if (YaIsDebuggerPresent()) \
+ __debugbreak(); \
+ else { \
+ assert(false && "Exception during assert"); \
+ } \
+ } \
+ } while (0)
+#else
+#define Y_ASSERT_NOBT(a) \
+ do { \
+ if (false) { \
+ bool __xxx = static_cast<bool>(a); \
+ Y_UNUSED(__xxx); \
+ } \
+ } while (0)
+#endif
+
+#include <pthread.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <new>
+#include <errno.h>
+
+#if defined(_linux_)
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#if !defined(MADV_HUGEPAGE)
+#define MADV_HUGEPAGE 14
+#endif
+#if !defined(MAP_HUGETLB)
+#define MAP_HUGETLB 0x40000
+#endif
+#endif
+
+#define PERTHREAD __thread
+
+#endif
+
+#ifndef _darwin_
+
+#ifndef Y_ARRAY_SIZE
+#define Y_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+#ifndef NDEBUG
+#define DBG_FILL_MEMORY
+static bool FillMemoryOnAllocation = true;
+#endif
+
+static bool TransparentHugePages = false; // force MADV_HUGEPAGE for large allocs
+static bool MapHugeTLB = false; // force MAP_HUGETLB for small allocs
+static bool EnableDefrag = true;
+
+// Buffers that are larger than this size will not be filled with 0xcf
+#ifndef DBG_FILL_MAX_SIZE
+#define DBG_FILL_MAX_SIZE 0x01000000000000ULL
+#endif
+
+template <class T>
+inline T* DoCas(T* volatile* target, T* exchange, T* compare) {
+#if defined(__has_builtin) && __has_builtin(__sync_val_compare_and_swap)
+ return __sync_val_compare_and_swap(target, compare, exchange);
+#elif defined(_WIN32)
+#ifdef _64_
+ return (T*)_InterlockedCompareExchange64((__int64*)target, (__int64)exchange, (__int64)compare);
+#else
+ //return (T*)InterlockedCompareExchangePointer(targetVoidP, exchange, compare);
+ return (T*)_InterlockedCompareExchange((LONG*)target, (LONG)exchange, (LONG)compare);
+#endif
+#elif defined(__i386) || defined(__x86_64__)
+ union {
+ T* volatile* NP;
+ void* volatile* VoidP;
+ } gccSucks;
+ gccSucks.NP = target;
+ void* volatile* targetVoidP = gccSucks.VoidP;
+
+ __asm__ __volatile__(
+ "lock\n\t"
+ "cmpxchg %2,%0\n\t"
+ : "+m"(*(targetVoidP)), "+a"(compare)
+ : "r"(exchange)
+ : "cc", "memory");
+ return compare;
+#else
+#error inline_cas not defined for this platform
+#endif
+}
+
+#ifdef _64_
+const uintptr_t N_MAX_WORKSET_SIZE = 0x100000000ll * 200;
+const uintptr_t N_HUGE_AREA_FINISH = 0x700000000000ll;
+#ifndef _freebsd_
+const uintptr_t LINUX_MMAP_AREA_START = 0x100000000ll;
+static uintptr_t volatile linuxAllocPointer = LINUX_MMAP_AREA_START;
+static uintptr_t volatile linuxAllocPointerHuge = LINUX_MMAP_AREA_START + N_MAX_WORKSET_SIZE;
+#endif
+#else
+const uintptr_t N_MAX_WORKSET_SIZE = 0xffffffff;
+#endif
+#define ALLOC_START ((char*)0)
+
+const size_t N_CHUNK_SIZE = 1024 * 1024;
+const size_t N_CHUNKS = N_MAX_WORKSET_SIZE / N_CHUNK_SIZE;
+const size_t N_LARGE_ALLOC_SIZE = N_CHUNK_SIZE * 128;
+
+// map size idx to size in bytes
+#ifdef LFALLOC_YT
+const int N_SIZES = 27;
+#else
+const int N_SIZES = 25;
+#endif
+const int nSizeIdxToSize[N_SIZES] = {
+ -1,
+#if defined(_64_)
+ 16, 16, 32, 32, 48, 64, 96, 128,
+#else
+ 8,
+ 16,
+ 24,
+ 32,
+ 48,
+ 64,
+ 96,
+ 128,
+#endif
+ 192, 256, 384, 512, 768, 1024, 1536, 2048,
+ 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768,
+#ifdef LFALLOC_YT
+ 49152, 65536
+#endif
+};
+#ifdef LFALLOC_YT
+const size_t N_MAX_FAST_SIZE = 65536;
+#else
+const size_t N_MAX_FAST_SIZE = 32768;
+#endif
+const unsigned char size2idxArr1[64 + 1] = {
+ 1,
+#if defined(_64_)
+ 2, 2, 4, 4, // 16, 16, 32, 32
+#else
+ 1, 2, 3, 4, // 8, 16, 24, 32
+#endif
+ 5, 5, 6, 6, // 48, 64
+ 7, 7, 7, 7, 8, 8, 8, 8, // 96, 128
+ 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, // 192, 256
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, // 384
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 // 512
+};
+#ifdef LFALLOC_YT
+const unsigned char size2idxArr2[256] = {
+#else
+const unsigned char size2idxArr2[128] = {
+#endif
+ 12, 12, 13, 14, // 512, 512, 768, 1024
+ 15, 15, 16, 16, // 1536, 2048
+ 17, 17, 17, 17, 18, 18, 18, 18, // 3072, 4096
+ 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, // 6144, 8192
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, // 12288
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, // 16384
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, // 24576
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, // 32768
+#ifdef LFALLOC_YT
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, // 49152
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, // 65536
+#endif
+};
+
+// map entry number to size idx
+// special size idx's: 0 = not used, -1 = mem locked, but not allocated
+static volatile char chunkSizeIdx[N_CHUNKS];
+const int FREE_CHUNK_ARR_BUF = 0x20000; // this is effectively 128G of free memory (with 1M chunks), should not be exhausted actually
+static volatile uintptr_t freeChunkArr[FREE_CHUNK_ARR_BUF];
+static volatile int freeChunkCount;
+
+static void AddFreeChunk(uintptr_t chunkId) {
+ chunkSizeIdx[chunkId] = -1;
+ if (Y_UNLIKELY(freeChunkCount == FREE_CHUNK_ARR_BUF))
+ NMalloc::AbortFromCorruptedAllocator("free chunks array overflowed");
+ freeChunkArr[freeChunkCount++] = chunkId;
+}
+
+static bool GetFreeChunk(uintptr_t* res) {
+ if (freeChunkCount == 0) {
+ *res = 0;
+ return false;
+ }
+ *res = freeChunkArr[--freeChunkCount];
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////
+enum ELFAllocCounter {
+ CT_USER_ALLOC, // accumulated size requested by user code
+ CT_MMAP, // accumulated mmapped size
+ CT_MMAP_CNT, // number of mmapped regions
+ CT_MUNMAP, // accumulated unmmapped size
+ CT_MUNMAP_CNT, // number of munmaped regions
+ CT_SYSTEM_ALLOC, // accumulated allocated size for internal lfalloc needs
+ CT_SYSTEM_FREE, // accumulated deallocated size for internal lfalloc needs
+ CT_SMALL_ALLOC, // accumulated allocated size for fixed-size blocks
+ CT_SMALL_FREE, // accumulated deallocated size for fixed-size blocks
+ CT_LARGE_ALLOC, // accumulated allocated size for large blocks
+ CT_LARGE_FREE, // accumulated deallocated size for large blocks
+ CT_SLOW_ALLOC_CNT, // number of slow (not LF) allocations
+ CT_DEGRAGMENT_CNT, // number of memory defragmentations
+ CT_MAX
+};
+
+static Y_FORCE_INLINE void IncrementCounter(ELFAllocCounter counter, size_t value);
+
+//////////////////////////////////////////////////////////////////////////
+enum EMMapMode {
+ MM_NORMAL, // memory for small allocs
+ MM_HUGE // memory for large allocs
+};
+
+#ifndef _MSC_VER
+inline void VerifyMmapResult(void* result) {
+ if (Y_UNLIKELY(result == MAP_FAILED))
+ NMalloc::AbortFromCorruptedAllocator("negative size requested? or just out of mem");
+}
+#endif
+
+#if !defined(_MSC_VER) && !defined(_freebsd_) && defined(_64_)
+static char* AllocWithMMapLinuxImpl(uintptr_t sz, EMMapMode mode) {
+ char* volatile* areaPtr;
+ char* areaStart;
+ uintptr_t areaFinish;
+
+ int mapProt = PROT_READ | PROT_WRITE;
+ int mapFlags = MAP_PRIVATE | MAP_ANON;
+
+ if (mode == MM_HUGE) {
+ areaPtr = reinterpret_cast<char* volatile*>(&linuxAllocPointerHuge);
+ areaStart = reinterpret_cast<char*>(LINUX_MMAP_AREA_START + N_MAX_WORKSET_SIZE);
+ areaFinish = N_HUGE_AREA_FINISH;
+ } else {
+ areaPtr = reinterpret_cast<char* volatile*>(&linuxAllocPointer);
+ areaStart = reinterpret_cast<char*>(LINUX_MMAP_AREA_START);
+ areaFinish = N_MAX_WORKSET_SIZE;
+
+ if (MapHugeTLB) {
+ mapFlags |= MAP_HUGETLB;
+ }
+ }
+
+ bool wrapped = false;
+ for (;;) {
+ char* prevAllocPtr = *areaPtr;
+ char* nextAllocPtr = prevAllocPtr + sz;
+ if (uintptr_t(nextAllocPtr - (char*)nullptr) >= areaFinish) {
+ if (Y_UNLIKELY(wrapped)) {
+ NMalloc::AbortFromCorruptedAllocator("virtual memory is over fragmented");
+ }
+ // wrap after all area is used
+ DoCas(areaPtr, areaStart, prevAllocPtr);
+ wrapped = true;
+ continue;
+ }
+
+ if (DoCas(areaPtr, nextAllocPtr, prevAllocPtr) != prevAllocPtr)
+ continue;
+
+ char* largeBlock = (char*)mmap(prevAllocPtr, sz, mapProt, mapFlags, -1, 0);
+ VerifyMmapResult(largeBlock);
+ if (largeBlock == prevAllocPtr)
+ return largeBlock;
+ if (largeBlock)
+ munmap(largeBlock, sz);
+
+ if (sz < 0x80000) {
+ // skip utilized area with big steps
+ DoCas(areaPtr, nextAllocPtr + 0x10 * 0x10000, nextAllocPtr);
+ }
+ }
+}
+#endif
+
+static char* AllocWithMMap(uintptr_t sz, EMMapMode mode) {
+ (void)mode;
+#ifdef _MSC_VER
+ char* largeBlock = (char*)VirtualAlloc(0, sz, MEM_RESERVE, PAGE_READWRITE);
+ if (Y_UNLIKELY(largeBlock == nullptr))
+ NMalloc::AbortFromCorruptedAllocator("out of memory");
+ if (Y_UNLIKELY(uintptr_t(((char*)largeBlock - ALLOC_START) + sz) >= N_MAX_WORKSET_SIZE))
+ NMalloc::AbortFromCorruptedAllocator("out of working set, something has broken");
+#else
+#if defined(_freebsd_) || !defined(_64_)
+ char* largeBlock = (char*)mmap(0, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+ VerifyMmapResult(largeBlock);
+ if (Y_UNLIKELY(uintptr_t(((char*)largeBlock - ALLOC_START) + sz) >= N_MAX_WORKSET_SIZE))
+ NMalloc::AbortFromCorruptedAllocator("out of working set, something has broken");
+#else
+ char* largeBlock = AllocWithMMapLinuxImpl(sz, mode);
+ if (TransparentHugePages) {
+ madvise(largeBlock, sz, MADV_HUGEPAGE);
+ }
+#endif
+#endif
+ Y_ASSERT_NOBT(largeBlock);
+ IncrementCounter(CT_MMAP, sz);
+ IncrementCounter(CT_MMAP_CNT, 1);
+ return largeBlock;
+}
+
+enum class ELarge : ui8 {
+ Free = 0, // block in free cache
+ Alloc = 1, // block is allocated
+ Gone = 2, // block was unmapped
+};
+
+struct TLargeBlk {
+
+ static TLargeBlk* As(void *raw) {
+ return reinterpret_cast<TLargeBlk*>((char*)raw - 4096ll);
+ }
+
+ static const TLargeBlk* As(const void *raw) {
+ return reinterpret_cast<const TLargeBlk*>((const char*)raw - 4096ll);
+ }
+
+ void SetSize(size_t bytes, size_t pages) {
+ Pages = pages;
+ Bytes = bytes;
+ }
+
+ void Mark(ELarge state) {
+ const ui64 marks[] = {
+ 0x8b38aa5ca4953c98, // ELarge::Free
+ 0xf916d33584eb5087, // ELarge::Alloc
+ 0xd33b0eca7651bc3f // ELarge::Gone
+ };
+
+ Token = size_t(marks[ui8(state)]);
+ }
+
+ size_t Pages; // Total pages allocated with mmap like call
+ size_t Bytes; // Actually requested bytes by user
+ size_t Token; // Block state token, see ELarge enum.
+};
+
+
+static void LargeBlockUnmap(void* p, size_t pages) {
+ const auto bytes = (pages + 1) * uintptr_t(4096);
+
+ IncrementCounter(CT_MUNMAP, bytes);
+ IncrementCounter(CT_MUNMAP_CNT, 1);
+#ifdef _MSC_VER
+ Y_ASSERT_NOBT(0);
+#else
+ TLargeBlk::As(p)->Mark(ELarge::Gone);
+ munmap((char*)p - 4096ll, bytes);
+#endif
+}
+
+//////////////////////////////////////////////////////////////////////////
+const size_t LB_BUF_SIZE = 250;
+const size_t LB_BUF_HASH = 977;
+static int LB_LIMIT_TOTAL_SIZE = 500 * 1024 * 1024 / 4096; // do not keep more then this mem total in lbFreePtrs[]
+static void* volatile lbFreePtrs[LB_BUF_HASH][LB_BUF_SIZE];
+static TAtomic lbFreePageCount;
+
+
+static void* LargeBlockAlloc(size_t _nSize, ELFAllocCounter counter) {
+ size_t pgCount = (_nSize + 4095) / 4096;
+#ifdef _MSC_VER
+ char* pRes = (char*)VirtualAlloc(0, (pgCount + 1) * 4096ll, MEM_COMMIT, PAGE_READWRITE);
+ if (Y_UNLIKELY(pRes == 0)) {
+ NMalloc::AbortFromCorruptedAllocator("out of memory");
+ }
+#else
+
+ IncrementCounter(counter, pgCount * 4096ll);
+ IncrementCounter(CT_SYSTEM_ALLOC, 4096ll);
+
+ int lbHash = pgCount % LB_BUF_HASH;
+ for (int i = 0; i < LB_BUF_SIZE; ++i) {
+ void* p = lbFreePtrs[lbHash][i];
+ if (p == nullptr)
+ continue;
+ if (DoCas(&lbFreePtrs[lbHash][i], (void*)nullptr, p) == p) {
+ size_t realPageCount = TLargeBlk::As(p)->Pages;
+ if (realPageCount == pgCount) {
+ AtomicAdd(lbFreePageCount, -pgCount);
+ TLargeBlk::As(p)->Mark(ELarge::Alloc);
+ return p;
+ } else {
+ if (DoCas(&lbFreePtrs[lbHash][i], p, (void*)nullptr) != (void*)nullptr) {
+ // block was freed while we were busy
+ AtomicAdd(lbFreePageCount, -realPageCount);
+ LargeBlockUnmap(p, realPageCount);
+ --i;
+ }
+ }
+ }
+ }
+ char* pRes = AllocWithMMap((pgCount + 1) * 4096ll, MM_HUGE);
+#endif
+ pRes += 4096ll;
+ TLargeBlk::As(pRes)->SetSize(_nSize, pgCount);
+ TLargeBlk::As(pRes)->Mark(ELarge::Alloc);
+
+ return pRes;
+}
+
+#ifndef _MSC_VER
+static void FreeAllLargeBlockMem() {
+ for (auto& lbFreePtr : lbFreePtrs) {
+ for (int i = 0; i < LB_BUF_SIZE; ++i) {
+ void* p = lbFreePtr[i];
+ if (p == nullptr)
+ continue;
+ if (DoCas(&lbFreePtr[i], (void*)nullptr, p) == p) {
+ int pgCount = TLargeBlk::As(p)->Pages;
+ AtomicAdd(lbFreePageCount, -pgCount);
+ LargeBlockUnmap(p, pgCount);
+ }
+ }
+ }
+}
+#endif
+
+static void LargeBlockFree(void* p, ELFAllocCounter counter) {
+ if (p == nullptr)
+ return;
+#ifdef _MSC_VER
+ VirtualFree((char*)p - 4096ll, 0, MEM_RELEASE);
+#else
+ size_t pgCount = TLargeBlk::As(p)->Pages;
+
+ TLargeBlk::As(p)->Mark(ELarge::Free);
+ IncrementCounter(counter, pgCount * 4096ll);
+ IncrementCounter(CT_SYSTEM_FREE, 4096ll);
+
+ if (lbFreePageCount > LB_LIMIT_TOTAL_SIZE)
+ FreeAllLargeBlockMem();
+ int lbHash = pgCount % LB_BUF_HASH;
+ for (int i = 0; i < LB_BUF_SIZE; ++i) {
+ if (lbFreePtrs[lbHash][i] == nullptr) {
+ if (DoCas(&lbFreePtrs[lbHash][i], p, (void*)nullptr) == nullptr) {
+ AtomicAdd(lbFreePageCount, pgCount);
+ return;
+ }
+ }
+ }
+
+ LargeBlockUnmap(p, pgCount);
+#endif
+}
+
+static void* SystemAlloc(size_t _nSize) {
+ //HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, _nSize);
+ return LargeBlockAlloc(_nSize, CT_SYSTEM_ALLOC);
+}
+static void SystemFree(void* p) {
+ //HeapFree(GetProcessHeap(), 0, p);
+ LargeBlockFree(p, CT_SYSTEM_FREE);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char* const LF_LOCK_FREE = ((char*)0) + 0;
+char* const LF_LOCK_LOCKED = ((char*)0) + 1;
+char* const LF_LOCK_FUTEX_WAIT = ((char*)0) + 2;
+static bool LFHasFutex = true;
+static bool LFCheckedWinVersion = false;
+
+// TLFLockData has to be zero-initialized explicitly https://en.cppreference.com/w/cpp/language/zero_initialization
+// otherwise constructor TLFLockData() for global var might be called after first use
+struct TLFLockData
+{
+ char* Pad1[15];
+ char* volatile LockVar; // = LF_LOCK_FREE; // no constructor, zero-initialize manually
+ char* Pad2[15];
+
+ bool TryLock()
+ {
+ return (LockVar == LF_LOCK_FREE && DoCas(&LockVar, LF_LOCK_LOCKED, LF_LOCK_FREE) == LF_LOCK_FREE);
+ }
+
+ void FutexWait()
+ {
+#ifdef _win_
+ if (!LFCheckedWinVersion) {
+ OSVERSIONINFOA ver;
+ memset(&ver, 0, sizeof(ver));
+ ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
+ GetVersionExA(&ver);
+ LFHasFutex = (ver.dwMajorVersion > 6) || (ver.dwMajorVersion == 6 && ver.dwMinorVersion >= 2);
+ LFCheckedWinVersion = true;
+ }
+ if (LFHasFutex) {
+ if (LockVar == LF_LOCK_LOCKED) {
+ DoCas(&LockVar, LF_LOCK_FUTEX_WAIT, LF_LOCK_LOCKED);
+ }
+ if (LockVar == LF_LOCK_FUTEX_WAIT) {
+ char* lockedValue = LF_LOCK_FUTEX_WAIT;
+ WaitOnAddress(&LockVar, &lockedValue, sizeof(LockVar), INFINITE);
+ }
+ } else {
+ SwitchToThread();
+ }
+#elif defined(_linux_)
+ if (LFHasFutex) {
+ if (LockVar == LF_LOCK_LOCKED) {
+ DoCas(&LockVar, LF_LOCK_FUTEX_WAIT, LF_LOCK_LOCKED);
+ }
+ if (LockVar == LF_LOCK_FUTEX_WAIT) {
+ // linux allow only int variables checks, here we pretend low bits of LockVar are int
+ syscall(SYS_futex, &LockVar, FUTEX_WAIT_PRIVATE, *(int*)&LF_LOCK_FUTEX_WAIT, 0, 0, 0);
+ }
+ } else {
+ sched_yield();
+ }
+#else
+ sched_yield();
+#endif
+ }
+
+ void Unlock()
+ {
+ Y_ASSERT_NOBT(LockVar != LF_LOCK_FREE);
+ if (DoCas(&LockVar, LF_LOCK_FREE, LF_LOCK_LOCKED) != LF_LOCK_LOCKED) {
+ Y_ASSERT_NOBT(LockVar == LF_LOCK_FUTEX_WAIT && LFHasFutex);
+ LockVar = LF_LOCK_FREE;
+#ifdef _win_
+ WakeByAddressAll((PVOID)&LockVar);
+#elif defined(_linux_)
+ syscall(SYS_futex, &LockVar, FUTEX_WAKE_PRIVATE, INT_MAX, 0, 0, 0);
+#endif
+ }
+ }
+};
+
+static TLFLockData LFGlobalLock;
+
+
+class TLFLockHolder {
+ TLFLockData *LockData = nullptr;
+ int Attempt = 0;
+ int SleepMask = 0x7f;
+
+public:
+ TLFLockHolder() {}
+ TLFLockHolder(TLFLockData *lk) {
+ while (!TryLock(lk));
+ }
+ bool TryLock(TLFLockData *lk)
+ {
+ Y_ASSERT_NOBT(LockData == nullptr);
+ if (lk->TryLock()) {
+ LockData = lk;
+ return true;
+ }
+ if ((++Attempt & SleepMask) == 0) {
+ lk->FutexWait();
+ SleepMask = (SleepMask * 2 + 1) & 0x7fff;
+ } else {
+#ifdef _MSC_VER
+ _mm_pause();
+#elif defined(__i386) || defined(__x86_64__)
+ __asm__ __volatile__("pause");
+#endif
+ }
+ return false;
+ }
+ ~TLFLockHolder() {
+ if (LockData) {
+ LockData->Unlock();
+ }
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////
+class TLFAllocFreeList {
+ struct TNode {
+ TNode* Next;
+ };
+
+ TNode* volatile Head;
+ TNode* volatile Pending;
+ TAtomic PendingToFreeListCounter;
+ TAtomic AllocCount;
+ void* Padding;
+
+ static Y_FORCE_INLINE void Enqueue(TNode* volatile* headPtr, TNode* n) {
+ for (;;) {
+ TNode* volatile prevHead = *headPtr;
+ n->Next = prevHead;
+ if (DoCas(headPtr, n, prevHead) == prevHead)
+ break;
+ }
+ }
+ Y_FORCE_INLINE void* DoAlloc() {
+ TNode* res;
+ for (res = Head; res; res = Head) {
+ TNode* keepNext = res->Next;
+ if (DoCas(&Head, keepNext, res) == res) {
+ //Y_VERIFY(keepNext == res->Next);
+ break;
+ }
+ }
+ return res;
+ }
+ void FreeList(TNode* fl) {
+ if (!fl)
+ return;
+ TNode* flTail = fl;
+ while (flTail->Next)
+ flTail = flTail->Next;
+ for (;;) {
+ TNode* volatile prevHead = Head;
+ flTail->Next = prevHead;
+ if (DoCas(&Head, fl, prevHead) == prevHead)
+ break;
+ }
+ }
+
+public:
+ Y_FORCE_INLINE void Free(void* ptr) {
+ TNode* newFree = (TNode*)ptr;
+ if (AtomicAdd(AllocCount, 0) == 0)
+ Enqueue(&Head, newFree);
+ else
+ Enqueue(&Pending, newFree);
+ }
+ Y_FORCE_INLINE void* Alloc() {
+ TAtomic keepCounter = AtomicAdd(PendingToFreeListCounter, 0);
+ TNode* fl = Pending;
+ if (AtomicAdd(AllocCount, 1) == 1) {
+ // No other allocs in progress.
+ // If (keepCounter == PendingToFreeListCounter) then Pending was not freed by other threads.
+ // Hence Pending is not used in any concurrent DoAlloc() atm and can be safely moved to FreeList
+ if (fl && keepCounter == AtomicAdd(PendingToFreeListCounter, 0) && DoCas(&Pending, (TNode*)nullptr, fl) == fl) {
+ // pick first element from Pending and return it
+ void* res = fl;
+ fl = fl->Next;
+ // if there are other elements in Pending list, add them to main free list
+ FreeList(fl);
+ AtomicAdd(PendingToFreeListCounter, 1);
+ AtomicAdd(AllocCount, -1);
+ return res;
+ }
+ }
+ void* res = DoAlloc();
+ AtomicAdd(AllocCount, -1);
+ return res;
+ }
+ void* GetWholeList() {
+ TNode* res;
+ for (res = Head; res; res = Head) {
+ if (DoCas(&Head, (TNode*)nullptr, res) == res)
+ break;
+ }
+ return res;
+ }
+ void ReturnWholeList(void* ptr) {
+ while (AtomicAdd(AllocCount, 0) != 0) // theoretically can run into problems with parallel DoAlloc()
+ ; //ThreadYield();
+ for (;;) {
+ TNode* prevHead = Head;
+ if (DoCas(&Head, (TNode*)ptr, prevHead) == prevHead) {
+ FreeList(prevHead);
+ break;
+ }
+ }
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////
+static TLFAllocFreeList globalFreeLists[N_SIZES];
+static char* volatile globalCurrentPtr[N_SIZES];
+static TLFAllocFreeList blockFreeList;
+
+// globalFreeLists[] contains TFreeListGroup, each of them points up to 15 free blocks
+const int FL_GROUP_SIZE = 15;
+struct TFreeListGroup {
+ TFreeListGroup* Next;
+ char* Ptrs[FL_GROUP_SIZE];
+};
+#ifdef _64_
+const int FREE_LIST_GROUP_SIZEIDX = 8;
+#else
+const int FREE_LIST_GROUP_SIZEIDX = 6;
+#endif
+
+//////////////////////////////////////////////////////////////////////////
+// find free chunks and reset chunk size so they can be reused by different sized allocations
+// do not look at blockFreeList (TFreeListGroup has same size for any allocations)
+static bool DefragmentMem() {
+ if (!EnableDefrag) {
+ return false;
+ }
+
+ IncrementCounter(CT_DEGRAGMENT_CNT, 1);
+
+ int* nFreeCount = (int*)SystemAlloc(N_CHUNKS * sizeof(int));
+ if (Y_UNLIKELY(!nFreeCount)) {
+ //__debugbreak();
+ NMalloc::AbortFromCorruptedAllocator("debugbreak");
+ }
+ memset(nFreeCount, 0, N_CHUNKS * sizeof(int));
+
+ TFreeListGroup* wholeLists[N_SIZES];
+ for (int nSizeIdx = 0; nSizeIdx < N_SIZES; ++nSizeIdx) {
+ wholeLists[nSizeIdx] = (TFreeListGroup*)globalFreeLists[nSizeIdx].GetWholeList();
+ for (TFreeListGroup* g = wholeLists[nSizeIdx]; g; g = g->Next) {
+ for (auto pData : g->Ptrs) {
+ if (pData) {
+ uintptr_t nChunk = (pData - ALLOC_START) / N_CHUNK_SIZE;
+ ++nFreeCount[nChunk];
+ Y_ASSERT_NOBT(chunkSizeIdx[nChunk] == nSizeIdx);
+ }
+ }
+ }
+ }
+
+ bool bRes = false;
+ for (size_t nChunk = 0; nChunk < N_CHUNKS; ++nChunk) {
+ int fc = nFreeCount[nChunk];
+ nFreeCount[nChunk] = 0;
+ if (chunkSizeIdx[nChunk] <= 0)
+ continue;
+ int nEntries = N_CHUNK_SIZE / nSizeIdxToSize[static_cast<int>(chunkSizeIdx[nChunk])];
+ Y_ASSERT_NOBT(fc <= nEntries); // can not have more free blocks then total count
+ if (fc == nEntries) {
+ bRes = true;
+ nFreeCount[nChunk] = 1;
+ }
+ }
+ if (bRes) {
+ for (auto& wholeList : wholeLists) {
+ TFreeListGroup** ppPtr = &wholeList;
+ while (*ppPtr) {
+ TFreeListGroup* g = *ppPtr;
+ int dst = 0;
+ for (auto pData : g->Ptrs) {
+ if (pData) {
+ uintptr_t nChunk = (pData - ALLOC_START) / N_CHUNK_SIZE;
+ if (nFreeCount[nChunk] == 0)
+ g->Ptrs[dst++] = pData; // block is not freed, keep pointer
+ }
+ }
+ if (dst == 0) {
+ // no valid pointers in group, free it
+ *ppPtr = g->Next;
+ blockFreeList.Free(g);
+ } else {
+ // reset invalid pointers to 0
+ for (int i = dst; i < FL_GROUP_SIZE; ++i)
+ g->Ptrs[i] = nullptr;
+ ppPtr = &g->Next;
+ }
+ }
+ }
+ for (uintptr_t nChunk = 0; nChunk < N_CHUNKS; ++nChunk) {
+ if (!nFreeCount[nChunk])
+ continue;
+ char* pStart = ALLOC_START + nChunk * N_CHUNK_SIZE;
+#ifdef _win_
+ VirtualFree(pStart, N_CHUNK_SIZE, MEM_DECOMMIT);
+#elif defined(_freebsd_)
+ madvise(pStart, N_CHUNK_SIZE, MADV_FREE);
+#else
+ madvise(pStart, N_CHUNK_SIZE, MADV_DONTNEED);
+#endif
+ AddFreeChunk(nChunk);
+ }
+ }
+
+ for (int nSizeIdx = 0; nSizeIdx < N_SIZES; ++nSizeIdx)
+ globalFreeLists[nSizeIdx].ReturnWholeList(wholeLists[nSizeIdx]);
+
+ SystemFree(nFreeCount);
+ return bRes;
+}
+
+static Y_FORCE_INLINE void* LFAllocFromCurrentChunk(int nSizeIdx, int blockSize, int count) {
+ char* volatile* pFreeArray = &globalCurrentPtr[nSizeIdx];
+ while (char* newBlock = *pFreeArray) {
+ char* nextFree = newBlock + blockSize * count;
+
+ // check if there is space in chunk
+ char* globalEndPtr = ALLOC_START + ((newBlock - ALLOC_START) & ~((uintptr_t)N_CHUNK_SIZE - 1)) + N_CHUNK_SIZE;
+ if (nextFree >= globalEndPtr) {
+ if (nextFree > globalEndPtr)
+ break;
+ nextFree = nullptr; // it was last block in chunk
+ }
+ if (DoCas(pFreeArray, nextFree, newBlock) == newBlock)
+ return newBlock;
+ }
+ return nullptr;
+}
+
+enum EDefrag {
+ MEM_DEFRAG,
+ NO_MEM_DEFRAG,
+};
+
+static void* SlowLFAlloc(int nSizeIdx, int blockSize, EDefrag defrag) {
+ IncrementCounter(CT_SLOW_ALLOC_CNT, 1);
+
+ TLFLockHolder ls;
+ for (;;) {
+ bool locked = ls.TryLock(&LFGlobalLock);
+ void* res = LFAllocFromCurrentChunk(nSizeIdx, blockSize, 1);
+ if (res) {
+ return res; // might happen when other thread allocated new current chunk
+ }
+ if (locked) {
+ break;
+ }
+ }
+ for (;;) {
+ uintptr_t nChunk;
+ if (GetFreeChunk(&nChunk)) {
+ char* newPlace = ALLOC_START + nChunk * N_CHUNK_SIZE;
+#ifdef _MSC_VER
+ void* pTest = VirtualAlloc(newPlace, N_CHUNK_SIZE, MEM_COMMIT, PAGE_READWRITE);
+ Y_ASSERT_NOBT(pTest == newPlace);
+#endif
+ chunkSizeIdx[nChunk] = (char)nSizeIdx;
+ globalCurrentPtr[nSizeIdx] = newPlace + blockSize;
+ return newPlace;
+ }
+
+ // out of luck, try to defrag
+ if (defrag == MEM_DEFRAG && DefragmentMem()) {
+ continue;
+ }
+
+ char* largeBlock = AllocWithMMap(N_LARGE_ALLOC_SIZE, MM_NORMAL);
+ uintptr_t addr = ((largeBlock - ALLOC_START) + N_CHUNK_SIZE - 1) & (~(N_CHUNK_SIZE - 1));
+ uintptr_t endAddr = ((largeBlock - ALLOC_START) + N_LARGE_ALLOC_SIZE) & (~(N_CHUNK_SIZE - 1));
+ for (uintptr_t p = addr; p < endAddr; p += N_CHUNK_SIZE) {
+ uintptr_t chunk = p / N_CHUNK_SIZE;
+ Y_ASSERT_NOBT(chunk * N_CHUNK_SIZE == p);
+ Y_ASSERT_NOBT(chunkSizeIdx[chunk] == 0);
+ AddFreeChunk(chunk);
+ }
+ }
+ return nullptr;
+}
+
+// allocate single block
+static Y_FORCE_INLINE void* LFAllocNoCache(int nSizeIdx, EDefrag defrag) {
+ int blockSize = nSizeIdxToSize[nSizeIdx];
+ void* res = LFAllocFromCurrentChunk(nSizeIdx, blockSize, 1);
+ if (res)
+ return res;
+
+ return SlowLFAlloc(nSizeIdx, blockSize, defrag);
+}
+
+// allocate multiple blocks, returns number of blocks allocated (max FL_GROUP_SIZE)
+// buf should have space for at least FL_GROUP_SIZE elems
+static Y_FORCE_INLINE int LFAllocNoCacheMultiple(int nSizeIdx, char** buf) {
+ int blockSize = nSizeIdxToSize[nSizeIdx];
+ void* res = LFAllocFromCurrentChunk(nSizeIdx, blockSize, FL_GROUP_SIZE);
+ if (res) {
+ char* resPtr = (char*)res;
+ for (int k = 0; k < FL_GROUP_SIZE; ++k) {
+ buf[k] = resPtr;
+ resPtr += blockSize;
+ }
+ return FL_GROUP_SIZE;
+ }
+ buf[0] = (char*)SlowLFAlloc(nSizeIdx, blockSize, MEM_DEFRAG);
+ return 1;
+}
+
+// take several blocks from global free list (max FL_GROUP_SIZE blocks), returns number of blocks taken
+// buf should have space for at least FL_GROUP_SIZE elems
+static Y_FORCE_INLINE int TakeBlocksFromGlobalFreeList(int nSizeIdx, char** buf) {
+ TLFAllocFreeList& fl = globalFreeLists[nSizeIdx];
+ TFreeListGroup* g = (TFreeListGroup*)fl.Alloc();
+ if (g) {
+ int resCount = 0;
+ for (auto& ptr : g->Ptrs) {
+ if (ptr)
+ buf[resCount++] = ptr;
+ else
+ break;
+ }
+ blockFreeList.Free(g);
+ return resCount;
+ }
+ return 0;
+}
+
+// add several blocks to global free list
+static Y_FORCE_INLINE void PutBlocksToGlobalFreeList(ptrdiff_t nSizeIdx, char** buf, int count) {
+ for (int startIdx = 0; startIdx < count;) {
+ TFreeListGroup* g = (TFreeListGroup*)blockFreeList.Alloc();
+ Y_ASSERT_NOBT(sizeof(TFreeListGroup) == nSizeIdxToSize[FREE_LIST_GROUP_SIZEIDX]);
+ if (!g) {
+ g = (TFreeListGroup*)LFAllocNoCache(FREE_LIST_GROUP_SIZEIDX, NO_MEM_DEFRAG);
+ }
+
+ int groupSize = count - startIdx;
+ if (groupSize > FL_GROUP_SIZE)
+ groupSize = FL_GROUP_SIZE;
+ for (int i = 0; i < groupSize; ++i)
+ g->Ptrs[i] = buf[startIdx + i];
+ for (int i = groupSize; i < FL_GROUP_SIZE; ++i)
+ g->Ptrs[i] = nullptr;
+
+ // add free group to the global list
+ TLFAllocFreeList& fl = globalFreeLists[nSizeIdx];
+ fl.Free(g);
+
+ startIdx += groupSize;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+static TAtomic GlobalCounters[CT_MAX];
+const int MAX_LOCAL_UPDATES = 100;
+const intptr_t MAX_LOCAL_DELTA = 1*1024*1024;
+
+struct TLocalCounter {
+ intptr_t Value;
+ int Updates;
+ TAtomic* Parent;
+
+ Y_FORCE_INLINE void Init(TAtomic* parent) {
+ Parent = parent;
+ Value = 0;
+ Updates = 0;
+ }
+
+ Y_FORCE_INLINE void Increment(size_t value) {
+ Value += value;
+ if (++Updates > MAX_LOCAL_UPDATES || Value > MAX_LOCAL_DELTA) {
+ Flush();
+ }
+ }
+
+ Y_FORCE_INLINE void Flush() {
+ AtomicAdd(*Parent, Value);
+ Value = 0;
+ Updates = 0;
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// DBG stuff
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(LFALLOC_DBG)
+
+struct TPerTagAllocCounter {
+ TAtomic Size;
+ TAtomic Count;
+
+ Y_FORCE_INLINE void Alloc(size_t size) {
+ AtomicAdd(Size, size);
+ AtomicAdd(Count, 1);
+ }
+
+ Y_FORCE_INLINE void Free(size_t size) {
+ AtomicSub(Size, size);
+ AtomicSub(Count, 1);
+ }
+};
+
+struct TLocalPerTagAllocCounter {
+ intptr_t Size;
+ int Count;
+ int Updates;
+
+ Y_FORCE_INLINE void Init() {
+ Size = 0;
+ Count = 0;
+ Updates = 0;
+ }
+
+ Y_FORCE_INLINE void Alloc(TPerTagAllocCounter& parent, size_t size) {
+ Size += size;
+ ++Count;
+ if (++Updates > MAX_LOCAL_UPDATES) {
+ Flush(parent);
+ }
+ }
+
+ Y_FORCE_INLINE void Free(TPerTagAllocCounter& parent, size_t size) {
+ Size -= size;
+ --Count;
+ if (++Updates > MAX_LOCAL_UPDATES) {
+ Flush(parent);
+ }
+ }
+
+ Y_FORCE_INLINE void Flush(TPerTagAllocCounter& parent) {
+ AtomicAdd(parent.Size, Size);
+ Size = 0;
+ AtomicAdd(parent.Count, Count);
+ Count = 0;
+ Updates = 0;
+ }
+};
+
+static const int DBG_ALLOC_MAX_TAG = 1000;
+static const int DBG_ALLOC_ALIGNED_TAG = 0xF0000000;
+static const int DBG_ALLOC_NUM_SIZES = 30;
+static TPerTagAllocCounter GlobalPerTagAllocCounters[DBG_ALLOC_MAX_TAG][DBG_ALLOC_NUM_SIZES];
+
+#endif // LFALLOC_DBG
+
+//////////////////////////////////////////////////////////////////////////
+const int THREAD_BUF = 256;
+static int borderSizes[N_SIZES];
+const int MAX_MEM_PER_SIZE_PER_THREAD = 512 * 1024;
+struct TThreadAllocInfo {
+ // FreePtrs - pointers to first free blocks in per thread block list
+ // LastFreePtrs - pointers to last blocks in lists, may be invalid if FreePtr is zero
+ char* FreePtrs[N_SIZES][THREAD_BUF];
+ int FreePtrIndex[N_SIZES];
+ TThreadAllocInfo* pNextInfo;
+ TLocalCounter LocalCounters[CT_MAX];
+
+#if defined(LFALLOC_DBG)
+ TLocalPerTagAllocCounter LocalPerTagAllocCounters[DBG_ALLOC_MAX_TAG][DBG_ALLOC_NUM_SIZES];
+#endif
+#ifdef _win_
+ HANDLE hThread;
+#endif
+
+ void Init(TThreadAllocInfo** pHead) {
+ memset(this, 0, sizeof(*this));
+ for (auto& i : FreePtrIndex)
+ i = THREAD_BUF;
+#ifdef _win_
+ BOOL b = DuplicateHandle(
+ GetCurrentProcess(), GetCurrentThread(),
+ GetCurrentProcess(), &hThread,
+ 0, FALSE, DUPLICATE_SAME_ACCESS);
+ Y_ASSERT_NOBT(b);
+#endif
+ pNextInfo = *pHead;
+ *pHead = this;
+ for (int k = 0; k < N_SIZES; ++k) {
+ int maxCount = MAX_MEM_PER_SIZE_PER_THREAD / nSizeIdxToSize[k];
+ if (maxCount > THREAD_BUF)
+ maxCount = THREAD_BUF;
+ borderSizes[k] = THREAD_BUF - maxCount;
+ }
+ for (int i = 0; i < CT_MAX; ++i) {
+ LocalCounters[i].Init(&GlobalCounters[i]);
+ }
+#if defined(LFALLOC_DBG)
+ for (int tag = 0; tag < DBG_ALLOC_MAX_TAG; ++tag) {
+ for (int sizeIdx = 0; sizeIdx < DBG_ALLOC_NUM_SIZES; ++sizeIdx) {
+ auto& local = LocalPerTagAllocCounters[tag][sizeIdx];
+ local.Init();
+ }
+ }
+#endif
+ }
+ void Done() {
+ for (auto sizeIdx : FreePtrIndex) {
+ Y_ASSERT_NOBT(sizeIdx == THREAD_BUF);
+ }
+ for (auto& localCounter : LocalCounters) {
+ localCounter.Flush();
+ }
+#if defined(LFALLOC_DBG)
+ for (int tag = 0; tag < DBG_ALLOC_MAX_TAG; ++tag) {
+ for (int sizeIdx = 0; sizeIdx < DBG_ALLOC_NUM_SIZES; ++sizeIdx) {
+ auto& local = LocalPerTagAllocCounters[tag][sizeIdx];
+ auto& global = GlobalPerTagAllocCounters[tag][sizeIdx];
+ local.Flush(global);
+ }
+ }
+#endif
+#ifdef _win_
+ if (hThread)
+ CloseHandle(hThread);
+#endif
+ }
+};
+PERTHREAD TThreadAllocInfo* pThreadInfo;
+static TThreadAllocInfo* pThreadInfoList;
+
+static TLFLockData LFLockThreadInfo;
+
+static Y_FORCE_INLINE void IncrementCounter(ELFAllocCounter counter, size_t value) {
+#ifdef LFALLOC_YT
+ TThreadAllocInfo* thr = pThreadInfo;
+ if (thr) {
+ thr->LocalCounters[counter].Increment(value);
+ } else {
+ AtomicAdd(GlobalCounters[counter], value);
+ }
+#endif
+}
+
+extern "C" i64 GetLFAllocCounterFast(int counter) {
+#ifdef LFALLOC_YT
+ return GlobalCounters[counter];
+#else
+ return 0;
+#endif
+}
+
+extern "C" i64 GetLFAllocCounterFull(int counter) {
+#ifdef LFALLOC_YT
+ i64 ret = GlobalCounters[counter];
+ {
+ TLFLockHolder ll(&LFLockThreadInfo);
+ for (TThreadAllocInfo** p = &pThreadInfoList; *p;) {
+ TThreadAllocInfo* pInfo = *p;
+ ret += pInfo->LocalCounters[counter].Value;
+ p = &pInfo->pNextInfo;
+ }
+ }
+ return ret;
+#else
+ return 0;
+#endif
+}
+
+static void MoveSingleThreadFreeToGlobal(TThreadAllocInfo* pInfo) {
+ for (int sizeIdx = 0; sizeIdx < N_SIZES; ++sizeIdx) {
+ int& freePtrIdx = pInfo->FreePtrIndex[sizeIdx];
+ char** freePtrs = pInfo->FreePtrs[sizeIdx];
+ PutBlocksToGlobalFreeList(sizeIdx, freePtrs + freePtrIdx, THREAD_BUF - freePtrIdx);
+ freePtrIdx = THREAD_BUF;
+ }
+}
+
+#ifdef _win_
+static bool IsDeadThread(TThreadAllocInfo* pInfo) {
+ DWORD dwExit;
+ bool isDead = !GetExitCodeThread(pInfo->hThread, &dwExit) || dwExit != STILL_ACTIVE;
+ return isDead;
+}
+
+static void CleanupAfterDeadThreads() {
+ TLFLockHolder ll(&LFLockThreadInfo);
+ for (TThreadAllocInfo** p = &pThreadInfoList; *p;) {
+ TThreadAllocInfo* pInfo = *p;
+ if (IsDeadThread(pInfo)) {
+ MoveSingleThreadFreeToGlobal(pInfo);
+ pInfo->Done();
+ *p = pInfo->pNextInfo;
+ SystemFree(pInfo);
+ } else
+ p = &pInfo->pNextInfo;
+ }
+}
+#endif
+
+#ifndef _win_
+static pthread_key_t ThreadCacheCleaner;
+static void* volatile ThreadCacheCleanerStarted; // 0 = not started, -1 = started, -2 = is starting
+static PERTHREAD bool IsStoppingThread;
+
+static void FreeThreadCache(void*) {
+ TThreadAllocInfo* pToDelete = nullptr;
+ {
+ TLFLockHolder ll(&LFLockThreadInfo);
+ pToDelete = pThreadInfo;
+ if (pToDelete == nullptr)
+ return;
+
+ // remove from the list
+ for (TThreadAllocInfo** p = &pThreadInfoList; *p; p = &(*p)->pNextInfo) {
+ if (*p == pToDelete) {
+ *p = pToDelete->pNextInfo;
+ break;
+ }
+ }
+ IsStoppingThread = true;
+ pThreadInfo = nullptr;
+ }
+
+ // free per thread buf
+ MoveSingleThreadFreeToGlobal(pToDelete);
+ pToDelete->Done();
+ SystemFree(pToDelete);
+}
+#endif
+
+static void AllocThreadInfo() {
+#ifndef _win_
+ if (DoCas(&ThreadCacheCleanerStarted, (void*)-2, (void*)nullptr) == (void*)nullptr) {
+ pthread_key_create(&ThreadCacheCleaner, FreeThreadCache);
+ ThreadCacheCleanerStarted = (void*)-1;
+ }
+ if (ThreadCacheCleanerStarted != (void*)-1)
+ return; // do not use ThreadCacheCleaner until it is constructed
+
+ {
+ if (IsStoppingThread)
+ return;
+ TLFLockHolder ll(&LFLockThreadInfo);
+ if (IsStoppingThread) // better safe than sorry
+ return;
+
+ pThreadInfo = (TThreadAllocInfo*)SystemAlloc(sizeof(TThreadAllocInfo));
+ pThreadInfo->Init(&pThreadInfoList);
+ }
+ pthread_setspecific(ThreadCacheCleaner, (void*)-1); // without value destructor will not be called
+#else
+ CleanupAfterDeadThreads();
+ {
+ pThreadInfo = (TThreadAllocInfo*)SystemAlloc(sizeof(TThreadAllocInfo));
+ TLFLockHolder ll(&LFLockThreadInfo);
+ pThreadInfo->Init(&pThreadInfoList);
+ }
+#endif
+}
+
+ //////////////////////////////////////////////////////////////////////////
+ // DBG stuff
+ //////////////////////////////////////////////////////////////////////////
+
+#if defined(LFALLOC_DBG)
+
+struct TAllocHeader {
+ uint64_t Size;
+ int Tag;
+ int Cookie;
+};
+
+// should be power of 2
+static_assert(sizeof(TAllocHeader) == 16);
+
+static inline void* GetAllocPtr(TAllocHeader* p) {
+ return p + 1;
+}
+
+static inline TAllocHeader* GetAllocHeader(void* p) {
+ auto* header = ((TAllocHeader*)p) - 1;
+ if (header->Tag == DBG_ALLOC_ALIGNED_TAG) {
+ return (TAllocHeader*)header->Size;
+ }
+
+ return header;
+}
+
+PERTHREAD int AllocationTag;
+extern "C" int SetThreadAllocTag(int tag) {
+ int prevTag = AllocationTag;
+ if (tag < DBG_ALLOC_MAX_TAG && tag >= 0) {
+ AllocationTag = tag;
+ }
+ return prevTag;
+}
+
+PERTHREAD bool ProfileCurrentThread;
+extern "C" bool SetProfileCurrentThread(bool newVal) {
+ bool prevVal = ProfileCurrentThread;
+ ProfileCurrentThread = newVal;
+ return prevVal;
+}
+
+static volatile bool ProfileAllThreads;
+extern "C" bool SetProfileAllThreads(bool newVal) {
+ bool prevVal = ProfileAllThreads;
+ ProfileAllThreads = newVal;
+ return prevVal;
+}
+
+static volatile bool AllocationSamplingEnabled;
+extern "C" bool SetAllocationSamplingEnabled(bool newVal) {
+ bool prevVal = AllocationSamplingEnabled;
+ AllocationSamplingEnabled = newVal;
+ return prevVal;
+}
+
+static size_t AllocationSampleRate = 1000;
+extern "C" size_t SetAllocationSampleRate(size_t newVal) {
+ size_t prevVal = AllocationSampleRate;
+ AllocationSampleRate = newVal;
+ return prevVal;
+}
+
+static size_t AllocationSampleMaxSize = N_MAX_FAST_SIZE;
+extern "C" size_t SetAllocationSampleMaxSize(size_t newVal) {
+ size_t prevVal = AllocationSampleMaxSize;
+ AllocationSampleMaxSize = newVal;
+ return prevVal;
+}
+
+using TAllocationCallback = int(int tag, size_t size, int sizeIdx);
+static TAllocationCallback* AllocationCallback;
+extern "C" TAllocationCallback* SetAllocationCallback(TAllocationCallback* newVal) {
+ TAllocationCallback* prevVal = AllocationCallback;
+ AllocationCallback = newVal;
+ return prevVal;
+}
+
+using TDeallocationCallback = void(int cookie, int tag, size_t size, int sizeIdx);
+static TDeallocationCallback* DeallocationCallback;
+extern "C" TDeallocationCallback* SetDeallocationCallback(TDeallocationCallback* newVal) {
+ TDeallocationCallback* prevVal = DeallocationCallback;
+ DeallocationCallback = newVal;
+ return prevVal;
+}
+
+PERTHREAD TAtomic AllocationsCount;
+PERTHREAD bool InAllocationCallback;
+
+static const int DBG_ALLOC_INVALID_COOKIE = -1;
+static inline int SampleAllocation(TAllocHeader* p, int sizeIdx) {
+ int cookie = DBG_ALLOC_INVALID_COOKIE;
+ if (AllocationSamplingEnabled && (ProfileCurrentThread || ProfileAllThreads) && !InAllocationCallback) {
+ if (p->Size > AllocationSampleMaxSize || ++AllocationsCount % AllocationSampleRate == 0) {
+ if (AllocationCallback) {
+ InAllocationCallback = true;
+ cookie = AllocationCallback(p->Tag, p->Size, sizeIdx);
+ InAllocationCallback = false;
+ }
+ }
+ }
+ return cookie;
+}
+
+static inline void SampleDeallocation(TAllocHeader* p, int sizeIdx) {
+ if (p->Cookie != DBG_ALLOC_INVALID_COOKIE && !InAllocationCallback) {
+ if (DeallocationCallback) {
+ InAllocationCallback = true;
+ DeallocationCallback(p->Cookie, p->Tag, p->Size, sizeIdx);
+ InAllocationCallback = false;
+ }
+ }
+}
+
+static inline void TrackPerTagAllocation(TAllocHeader* p, int sizeIdx) {
+ if (p->Tag < DBG_ALLOC_MAX_TAG && p->Tag >= 0) {
+ Y_ASSERT_NOBT(sizeIdx < DBG_ALLOC_NUM_SIZES);
+ auto& global = GlobalPerTagAllocCounters[p->Tag][sizeIdx];
+
+ TThreadAllocInfo* thr = pThreadInfo;
+ if (thr) {
+ auto& local = thr->LocalPerTagAllocCounters[p->Tag][sizeIdx];
+ local.Alloc(global, p->Size);
+ } else {
+ global.Alloc(p->Size);
+ }
+ }
+}
+
+static inline void TrackPerTagDeallocation(TAllocHeader* p, int sizeIdx) {
+ if (p->Tag < DBG_ALLOC_MAX_TAG && p->Tag >= 0) {
+ Y_ASSERT_NOBT(sizeIdx < DBG_ALLOC_NUM_SIZES);
+ auto& global = GlobalPerTagAllocCounters[p->Tag][sizeIdx];
+
+ TThreadAllocInfo* thr = pThreadInfo;
+ if (thr) {
+ auto& local = thr->LocalPerTagAllocCounters[p->Tag][sizeIdx];
+ local.Free(global, p->Size);
+ } else {
+ global.Free(p->Size);
+ }
+ }
+}
+
+static void* TrackAllocation(void* ptr, size_t size, int sizeIdx) {
+ TAllocHeader* p = (TAllocHeader*)ptr;
+ p->Size = size;
+ p->Tag = AllocationTag;
+ p->Cookie = SampleAllocation(p, sizeIdx);
+ TrackPerTagAllocation(p, sizeIdx);
+ return GetAllocPtr(p);
+}
+
+static void TrackDeallocation(void* ptr, int sizeIdx) {
+ TAllocHeader* p = (TAllocHeader*)ptr;
+ SampleDeallocation(p, sizeIdx);
+ TrackPerTagDeallocation(p, sizeIdx);
+}
+
+struct TPerTagAllocInfo {
+ ssize_t Count;
+ ssize_t Size;
+};
+
+extern "C" void GetPerTagAllocInfo(
+ bool flushPerThreadCounters,
+ TPerTagAllocInfo* info,
+ int& maxTag,
+ int& numSizes) {
+ maxTag = DBG_ALLOC_MAX_TAG;
+ numSizes = DBG_ALLOC_NUM_SIZES;
+
+ if (info) {
+ if (flushPerThreadCounters) {
+ TLFLockHolder ll(&LFLockThreadInfo);
+ for (TThreadAllocInfo** p = &pThreadInfoList; *p;) {
+ TThreadAllocInfo* pInfo = *p;
+ for (int tag = 0; tag < DBG_ALLOC_MAX_TAG; ++tag) {
+ for (int sizeIdx = 0; sizeIdx < DBG_ALLOC_NUM_SIZES; ++sizeIdx) {
+ auto& local = pInfo->LocalPerTagAllocCounters[tag][sizeIdx];
+ auto& global = GlobalPerTagAllocCounters[tag][sizeIdx];
+ local.Flush(global);
+ }
+ }
+ p = &pInfo->pNextInfo;
+ }
+ }
+
+ for (int tag = 0; tag < DBG_ALLOC_MAX_TAG; ++tag) {
+ for (int sizeIdx = 0; sizeIdx < DBG_ALLOC_NUM_SIZES; ++sizeIdx) {
+ auto& global = GlobalPerTagAllocCounters[tag][sizeIdx];
+ auto& res = info[tag * DBG_ALLOC_NUM_SIZES + sizeIdx];
+ res.Count = global.Count;
+ res.Size = global.Size;
+ }
+ }
+ }
+}
+
+#endif // LFALLOC_DBG
+
+//////////////////////////////////////////////////////////////////////////
+static Y_FORCE_INLINE void* LFAllocImpl(size_t _nSize) {
+#if defined(LFALLOC_DBG)
+ size_t size = _nSize;
+ _nSize += sizeof(TAllocHeader);
+#endif
+
+ IncrementCounter(CT_USER_ALLOC, _nSize);
+
+ int nSizeIdx;
+ if (_nSize > 512) {
+ if (_nSize > N_MAX_FAST_SIZE) {
+ void* ptr = LargeBlockAlloc(_nSize, CT_LARGE_ALLOC);
+#if defined(LFALLOC_DBG)
+ ptr = TrackAllocation(ptr, size, N_SIZES);
+#endif
+ return ptr;
+ }
+ nSizeIdx = size2idxArr2[(_nSize - 1) >> 8];
+ } else
+ nSizeIdx = size2idxArr1[1 + (((int)_nSize - 1) >> 3)];
+
+ IncrementCounter(CT_SMALL_ALLOC, nSizeIdxToSize[nSizeIdx]);
+
+ // check per thread buffer
+ TThreadAllocInfo* thr = pThreadInfo;
+ if (!thr) {
+ AllocThreadInfo();
+ thr = pThreadInfo;
+ if (!thr) {
+ void* ptr = LFAllocNoCache(nSizeIdx, MEM_DEFRAG);
+#if defined(LFALLOC_DBG)
+ ptr = TrackAllocation(ptr, size, nSizeIdx);
+#endif
+ return ptr;
+ }
+ }
+ {
+ int& freePtrIdx = thr->FreePtrIndex[nSizeIdx];
+ if (freePtrIdx < THREAD_BUF) {
+ void* ptr = thr->FreePtrs[nSizeIdx][freePtrIdx++];
+#if defined(LFALLOC_DBG)
+ ptr = TrackAllocation(ptr, size, nSizeIdx);
+#endif
+ return ptr;
+ }
+
+ // try to alloc from global free list
+ char* buf[FL_GROUP_SIZE];
+ int count = TakeBlocksFromGlobalFreeList(nSizeIdx, buf);
+ if (count == 0) {
+ count = LFAllocNoCacheMultiple(nSizeIdx, buf);
+ if (count == 0) {
+ NMalloc::AbortFromCorruptedAllocator("no way LFAllocNoCacheMultiple() can fail");
+ }
+ }
+ char** dstBuf = thr->FreePtrs[nSizeIdx] + freePtrIdx - 1;
+ for (int i = 0; i < count - 1; ++i)
+ dstBuf[-i] = buf[i];
+ freePtrIdx -= count - 1;
+ void* ptr = buf[count - 1];
+#if defined(LFALLOC_DBG)
+ ptr = TrackAllocation(ptr, size, nSizeIdx);
+#endif
+ return ptr;
+ }
+}
+
+static Y_FORCE_INLINE void* LFAlloc(size_t _nSize) {
+ void* res = LFAllocImpl(_nSize);
+#ifdef DBG_FILL_MEMORY
+ if (FillMemoryOnAllocation && res && (_nSize <= DBG_FILL_MAX_SIZE)) {
+ memset(res, 0xcf, _nSize);
+ }
+#endif
+ return res;
+}
+
+static Y_FORCE_INLINE void LFFree(void* p) {
+#if defined(LFALLOC_DBG)
+ if (p == nullptr)
+ return;
+ p = GetAllocHeader(p);
+#endif
+
+ uintptr_t chkOffset = ((char*)p - ALLOC_START) - 1ll;
+ if (chkOffset >= N_MAX_WORKSET_SIZE) {
+ if (p == nullptr)
+ return;
+#if defined(LFALLOC_DBG)
+ TrackDeallocation(p, N_SIZES);
+#endif
+ LargeBlockFree(p, CT_LARGE_FREE);
+ return;
+ }
+
+ uintptr_t chunk = ((char*)p - ALLOC_START) / N_CHUNK_SIZE;
+ ptrdiff_t nSizeIdx = chunkSizeIdx[chunk];
+ if (nSizeIdx <= 0) {
+#if defined(LFALLOC_DBG)
+ TrackDeallocation(p, N_SIZES);
+#endif
+ LargeBlockFree(p, CT_LARGE_FREE);
+ return;
+ }
+
+#if defined(LFALLOC_DBG)
+ TrackDeallocation(p, nSizeIdx);
+#endif
+
+#ifdef DBG_FILL_MEMORY
+ memset(p, 0xfe, nSizeIdxToSize[nSizeIdx]);
+#endif
+
+ IncrementCounter(CT_SMALL_FREE, nSizeIdxToSize[nSizeIdx]);
+
+ // try to store info to per thread buf
+ TThreadAllocInfo* thr = pThreadInfo;
+ if (thr) {
+ int& freePtrIdx = thr->FreePtrIndex[nSizeIdx];
+ if (freePtrIdx > borderSizes[nSizeIdx]) {
+ thr->FreePtrs[nSizeIdx][--freePtrIdx] = (char*)p;
+ return;
+ }
+
+ // move several pointers to global free list
+ int freeCount = FL_GROUP_SIZE;
+ if (freeCount > THREAD_BUF - freePtrIdx)
+ freeCount = THREAD_BUF - freePtrIdx;
+ char** freePtrs = thr->FreePtrs[nSizeIdx];
+ PutBlocksToGlobalFreeList(nSizeIdx, freePtrs + freePtrIdx, freeCount);
+ freePtrIdx += freeCount;
+
+ freePtrs[--freePtrIdx] = (char*)p;
+
+ } else {
+ AllocThreadInfo();
+ PutBlocksToGlobalFreeList(nSizeIdx, (char**)&p, 1);
+ }
+}
+
+static size_t LFGetSize(const void* p) {
+#if defined(LFALLOC_DBG)
+ if (p == nullptr)
+ return 0;
+ return GetAllocHeader(const_cast<void*>(p))->Size;
+#endif
+
+ uintptr_t chkOffset = ((const char*)p - ALLOC_START);
+ if (chkOffset >= N_MAX_WORKSET_SIZE) {
+ if (p == nullptr)
+ return 0;
+ return TLargeBlk::As(p)->Pages * 4096ll;
+ }
+ uintptr_t chunk = ((const char*)p - ALLOC_START) / N_CHUNK_SIZE;
+ ptrdiff_t nSizeIdx = chunkSizeIdx[chunk];
+ if (nSizeIdx <= 0)
+ return TLargeBlk::As(p)->Pages * 4096ll;
+ return nSizeIdxToSize[nSizeIdx];
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Output mem alloc stats
+const int N_PAGE_SIZE = 4096;
+static void DebugTraceMMgr(const char* pszFormat, ...) // __cdecl
+{
+ static char buff[20000];
+ va_list va;
+ //
+ va_start(va, pszFormat);
+ vsprintf(buff, pszFormat, va);
+ va_end(va);
+//
+#ifdef _win_
+ OutputDebugStringA(buff);
+#else
+ fputs(buff, stderr);
+#endif
+}
+
+struct TChunkStats {
+ char *Start, *Finish;
+ i64 Size;
+ char* Entries;
+ i64 FreeCount;
+
+ TChunkStats(size_t chunk, i64 size, char* entries)
+ : Size(size)
+ , Entries(entries)
+ , FreeCount(0)
+ {
+ Start = ALLOC_START + chunk * N_CHUNK_SIZE;
+ Finish = Start + N_CHUNK_SIZE;
+ }
+ void CheckBlock(char* pBlock) {
+ if (pBlock && pBlock >= Start && pBlock < Finish) {
+ ++FreeCount;
+ i64 nShift = pBlock - Start;
+ i64 nOffsetInStep = nShift & (N_CHUNK_SIZE - 1);
+ Entries[nOffsetInStep / Size] = 1;
+ }
+ }
+ void SetGlobalFree(char* ptr) {
+ i64 nShift = ptr - Start;
+ i64 nOffsetInStep = nShift & (N_CHUNK_SIZE - 1);
+ while (nOffsetInStep + Size <= N_CHUNK_SIZE) {
+ ++FreeCount;
+ Entries[nOffsetInStep / Size] = 1;
+ nOffsetInStep += Size;
+ }
+ }
+};
+
+static void DumpMemoryBlockUtilizationLocked() {
+ TFreeListGroup* wholeLists[N_SIZES];
+ for (int nSizeIdx = 0; nSizeIdx < N_SIZES; ++nSizeIdx) {
+ wholeLists[nSizeIdx] = (TFreeListGroup*)globalFreeLists[nSizeIdx].GetWholeList();
+ }
+ char* bfList = (char*)blockFreeList.GetWholeList();
+
+ DebugTraceMMgr("memory blocks utilisation stats:\n");
+ i64 nTotalAllocated = 0, nTotalFree = 0, nTotalBadPages = 0, nTotalPages = 0, nTotalUsed = 0, nTotalLocked = 0;
+ i64 nTotalGroupBlocks = 0;
+ char* entries;
+ entries = (char*)SystemAlloc((N_CHUNK_SIZE / 4));
+ for (size_t k = 0; k < N_CHUNKS; ++k) {
+ if (chunkSizeIdx[k] <= 0) {
+ if (chunkSizeIdx[k] == -1)
+ nTotalLocked += N_CHUNK_SIZE;
+ continue;
+ }
+ i64 nSizeIdx = chunkSizeIdx[k];
+ i64 nSize = nSizeIdxToSize[nSizeIdx];
+ TChunkStats cs(k, nSize, entries);
+ int nEntriesTotal = N_CHUNK_SIZE / nSize;
+ memset(entries, 0, nEntriesTotal);
+ for (TFreeListGroup* g = wholeLists[nSizeIdx]; g; g = g->Next) {
+ for (auto& ptr : g->Ptrs)
+ cs.CheckBlock(ptr);
+ }
+ TChunkStats csGB(k, nSize, entries);
+ if (nSizeIdx == FREE_LIST_GROUP_SIZEIDX) {
+ for (auto g : wholeLists) {
+ for (; g; g = g->Next)
+ csGB.CheckBlock((char*)g);
+ }
+ for (char* blk = bfList; blk; blk = *(char**)blk)
+ csGB.CheckBlock(blk);
+ nTotalGroupBlocks += csGB.FreeCount * nSize;
+ }
+ if (((globalCurrentPtr[nSizeIdx] - ALLOC_START) / N_CHUNK_SIZE) == k)
+ cs.SetGlobalFree(globalCurrentPtr[nSizeIdx]);
+ nTotalUsed += (nEntriesTotal - cs.FreeCount - csGB.FreeCount) * nSize;
+
+ char pages[N_CHUNK_SIZE / N_PAGE_SIZE];
+ memset(pages, 0, sizeof(pages));
+ for (int i = 0, nShift = 0; i < nEntriesTotal; ++i, nShift += nSize) {
+ int nBit = 0;
+ if (entries[i])
+ nBit = 1; // free entry
+ else
+ nBit = 2; // used entry
+ for (i64 nDelta = nSize - 1; nDelta >= 0; nDelta -= N_PAGE_SIZE)
+ pages[(nShift + nDelta) / N_PAGE_SIZE] |= nBit;
+ }
+ i64 nBadPages = 0;
+ for (auto page : pages) {
+ nBadPages += page == 3;
+ nTotalPages += page != 1;
+ }
+ DebugTraceMMgr("entry = %lld; size = %lld; free = %lld; system %lld; utilisation = %g%%, fragmentation = %g%%\n",
+ k, nSize, cs.FreeCount * nSize, csGB.FreeCount * nSize,
+ (N_CHUNK_SIZE - cs.FreeCount * nSize) * 100.0f / N_CHUNK_SIZE, 100.0f * nBadPages / Y_ARRAY_SIZE(pages));
+ nTotalAllocated += N_CHUNK_SIZE;
+ nTotalFree += cs.FreeCount * nSize;
+ nTotalBadPages += nBadPages;
+ }
+ SystemFree(entries);
+ DebugTraceMMgr("Total allocated = %llu, free = %lld, system = %lld, locked for future use %lld, utilisation = %g, fragmentation = %g\n",
+ nTotalAllocated, nTotalFree, nTotalGroupBlocks, nTotalLocked,
+ 100.0f * (nTotalAllocated - nTotalFree) / nTotalAllocated, 100.0f * nTotalBadPages / nTotalPages);
+ DebugTraceMMgr("Total %lld bytes used, %lld bytes in used pages\n", nTotalUsed, nTotalPages * N_PAGE_SIZE);
+
+ for (int nSizeIdx = 0; nSizeIdx < N_SIZES; ++nSizeIdx)
+ globalFreeLists[nSizeIdx].ReturnWholeList(wholeLists[nSizeIdx]);
+ blockFreeList.ReturnWholeList(bfList);
+}
+
+void FlushThreadFreeList() {
+ if (pThreadInfo)
+ MoveSingleThreadFreeToGlobal(pThreadInfo);
+}
+
+void DumpMemoryBlockUtilization() {
+ // move current thread free to global lists to get better statistics
+ FlushThreadFreeList();
+ {
+ TLFLockHolder ls(&LFGlobalLock);
+ DumpMemoryBlockUtilizationLocked();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// malloc api
+
+static bool LFAlloc_SetParam(const char* param, const char* value) {
+ if (!strcmp(param, "LB_LIMIT_TOTAL_SIZE")) {
+ LB_LIMIT_TOTAL_SIZE = atoi(value);
+ return true;
+ }
+ if (!strcmp(param, "LB_LIMIT_TOTAL_SIZE_BYTES")) {
+ LB_LIMIT_TOTAL_SIZE = (atoi(value) + N_PAGE_SIZE - 1) / N_PAGE_SIZE;
+ return true;
+ }
+#ifdef DBG_FILL_MEMORY
+ if (!strcmp(param, "FillMemoryOnAllocation")) {
+ FillMemoryOnAllocation = !strcmp(value, "true");
+ return true;
+ }
+#endif
+ if (!strcmp(param, "TransparentHugePages")) {
+ TransparentHugePages = !strcmp(value, "true");
+ return true;
+ }
+ if (!strcmp(param, "MapHugeTLB")) {
+ MapHugeTLB = !strcmp(value, "true");
+ return true;
+ }
+ if (!strcmp(param, "EnableDefrag")) {
+ EnableDefrag = !strcmp(value, "true");
+ return true;
+ }
+ return false;
+};
+
+static const char* LFAlloc_GetParam(const char* param) {
+ struct TParam {
+ const char* Name;
+ const char* Value;
+ };
+
+ static const TParam Params[] = {
+ {"GetLFAllocCounterFast", (const char*)&GetLFAllocCounterFast},
+ {"GetLFAllocCounterFull", (const char*)&GetLFAllocCounterFull},
+#if defined(LFALLOC_DBG)
+ {"SetThreadAllocTag", (const char*)&SetThreadAllocTag},
+ {"SetProfileCurrentThread", (const char*)&SetProfileCurrentThread},
+ {"SetProfileAllThreads", (const char*)&SetProfileAllThreads},
+ {"SetAllocationSamplingEnabled", (const char*)&SetAllocationSamplingEnabled},
+ {"SetAllocationSampleRate", (const char*)&SetAllocationSampleRate},
+ {"SetAllocationSampleMaxSize", (const char*)&SetAllocationSampleMaxSize},
+ {"SetAllocationCallback", (const char*)&SetAllocationCallback},
+ {"SetDeallocationCallback", (const char*)&SetDeallocationCallback},
+ {"GetPerTagAllocInfo", (const char*)&GetPerTagAllocInfo},
+#endif // LFALLOC_DBG
+ };
+
+ for (int i = 0; i < Y_ARRAY_SIZE(Params); ++i) {
+ if (strcmp(param, Params[i].Name) == 0) {
+ return Params[i].Value;
+ }
+ }
+ return nullptr;
+}
+
+static Y_FORCE_INLINE int LFPosixMemalign(void** memptr, size_t alignment, size_t size) {
+ if (Y_UNLIKELY(alignment > 4096)) {
+ const char* error = "Larger alignment are not guaranteed with this implementation\n";
+#ifdef _win_
+ OutputDebugStringA(error);
+#endif
+ NMalloc::AbortFromCorruptedAllocator(error);
+ }
+ size_t bigsize = size;
+ if (bigsize <= alignment) {
+ bigsize = alignment;
+ } else if (bigsize < 2 * alignment) {
+ bigsize = 2 * alignment;
+ }
+#if defined(LFALLOC_DBG)
+ if (alignment > sizeof(TAllocHeader)) {
+ bigsize += alignment;
+ }
+#endif
+
+ *memptr = LFAlloc(bigsize);
+
+#if defined(LFALLOC_DBG)
+ if (alignment > sizeof(TAllocHeader)) {
+ // memptr isn't aligned due to alloc header
+ const auto* header = GetAllocHeader(*memptr);
+ *memptr = (void*)((const char*) (*memptr) + alignment - sizeof(TAllocHeader));
+
+ // make fake header to retrieve original header ptr on dealloc
+ auto* next = GetAllocHeader(*memptr);
+ next->Tag = DBG_ALLOC_ALIGNED_TAG;
+ next->Size = (uint64_t)header;
+ next->Cookie = 0;
+ }
+#endif
+
+ Y_ASSERT_NOBT((intptr_t)*memptr % alignment == 0);
+ return 0;
+}
+
+static Y_FORCE_INLINE void* LFVAlloc(size_t size) {
+ const size_t pg = N_PAGE_SIZE;
+ void* p = nullptr;
+
+#if defined(LFALLOC_DBG)
+ LFPosixMemalign(&p, pg, size);
+#else
+ size_t bigsize = (size + pg - 1) & (~(pg - 1));
+ p = LFAlloc(bigsize);
+#endif
+
+ Y_ASSERT_NOBT((intptr_t)p % N_PAGE_SIZE == 0);
+ return p;
+}
+
+#endif
diff --git a/library/cpp/lfalloc/ya.make b/library/cpp/lfalloc/ya.make
new file mode 100644
index 0000000000..cace05f9d8
--- /dev/null
+++ b/library/cpp/lfalloc/ya.make
@@ -0,0 +1,25 @@
+LIBRARY()
+
+OWNER(gulin)
+
+NO_UTIL()
+
+NO_COMPILER_WARNINGS()
+
+IF (ARCH_AARCH64)
+ PEERDIR(
+ contrib/libs/jemalloc
+ )
+ELSE()
+ SRCS(
+ lf_allocX64.cpp
+ )
+ENDIF()
+
+PEERDIR(
+ library/cpp/malloc/api
+)
+
+SET(IDE_FOLDER "util")
+
+END()
diff --git a/library/cpp/lfalloc/yt/ya.make b/library/cpp/lfalloc/yt/ya.make
new file mode 100644
index 0000000000..8c1a4f8a72
--- /dev/null
+++ b/library/cpp/lfalloc/yt/ya.make
@@ -0,0 +1,29 @@
+LIBRARY()
+
+OWNER(a-romanov)
+
+NO_UTIL()
+
+NO_COMPILER_WARNINGS()
+
+IF (ARCH_AARCH64)
+ PEERDIR(
+ contrib/libs/jemalloc
+ )
+ELSE()
+ IF ("${YMAKE}" MATCHES "devtools")
+ CFLAGS(-DYMAKE=1)
+ ENDIF()
+ CXXFLAGS(-DLFALLOC_YT)
+ SRCS(
+ ../lf_allocX64.cpp
+ )
+ENDIF()
+
+PEERDIR(
+ library/cpp/malloc/api
+)
+
+SET(IDE_FOLDER "util")
+
+END()
diff --git a/library/cpp/linear_regression/benchmark/cpu_act.features b/library/cpp/linear_regression/benchmark/cpu_act.features
new file mode 100644
index 0000000000..b3bc8e340c
--- /dev/null
+++ b/library/cpp/linear_regression/benchmark/cpu_act.features
@@ -0,0 +1,8192 @@
+1 90 1 1 6 2 1036 103 114 1.00 1.00 172076 355965 0.00 0.00 0.00 0.00 0.00 2.00 4.00 73.60 89.00 2.0 6527 1851864
+1 88 1 1 1 0 2165 205 101 0.40 1.20 43107 44139 4.80 42.20 75.80 181.40 0.20 85.40 88.20 19.40 161.80 3.0 130 1131931
+1 85 1 1 62 77 3806 258 166 1.40 1.40 492142 268706 4.80 19.40 44.00 79.20 2.20 7.60 12.20 68.00 218.80 5.2 256 1314590
+1 81 1 1 5 0 4721 256 177 0.99 2.58 524787 174964 14.51 51.49 88.47 189.86 1.99 4.17 24.85 95.63 248.91 1.0 233 972606
+1 79 1 1 42 55 3949 249 244 2.60 4.60 197289 529200 4.20 6.80 6.60 0.00 1.40 1.80 2.20 219.60 297.20 3.4 331 1013805
+1 92 1 1 5 1 1692 132 87 0.40 1.80 220194 107031 0.00 0.00 0.00 0.00 0.00 3.81 4.01 23.65 42.08 2.2 2291 1010703
+1 82 1 1 3 0 635 65 47 3.00 3.00 87465 40740 8.60 8.80 8.80 0.00 0.00 1.60 2.20 227.60 226.40 1.0 289 1806587
+1 90 1 1 7 5 1341 240 120 0.40 0.60 718437 672290 0.00 0.00 0.00 0.00 0.00 7.60 15.00 42.80 52.80 4.8 2532 1037078
+1 87 1 1 159 40 2443 299 262 1.00 1.00 240375 209450 0.00 0.00 0.00 0.00 0.20 18.20 34.00 80.40 154.60 2.8 536 1069565
+1 86 1 1 1 0 3322 271 170 1.00 3.20 399277 128680 0.00 0.00 0.00 0.00 0.00 6.40 9.20 32.80 93.60 1.0 579 1120168
+1 87 1 1 9 3 1626 106 100 1.20 1.20 261018 111663 0.00 0.00 0.00 0.00 0.20 10.20 10.20 72.60 134.00 1.0 615 1073621
+1 93 1 1 11 2 1687 76 115 0.40 0.40 76103 93789 0.00 0.00 0.00 0.00 0.60 9.22 9.22 42.89 83.57 1.0 631 1068366
+1 84 1 1 2 1 5402 406 274 0.20 0.20 22609 155154 2.20 3.60 6.60 8.00 0.40 7.40 7.40 33.00 54.20 2.5 152 1015040
+1 92 1 1 6 2 2040 121 112 0.60 0.60 38688 60507 0.00 0.00 0.00 0.00 0.00 11.58 14.57 43.91 74.85 1.0 1201 1111232
+1 0 1 1 172 113 1427 171 134 0.60 3.39 261636 103649 0.00 0.00 0.00 0.00 0.80 4.99 5.39 62.28 152.10 744 92 8
+1 94 1 1 82 44 2342 156 323 0.60 0.60 97904 75368 0.00 0.00 0.00 0.00 0.00 8.00 12.60 114.80 85.60 3.2 487 1320070
+1 81 1 1 37 49 4667 673 457 2.60 0.80 262181 220110 0.20 4.00 6.60 9.20 0.20 3.40 3.40 130.80 212.80 1.4 287 1073834
+1 91 1 1 13 12 2859 459 215 0.60 2.00 652144 585464 0.60 0.60 0.60 0.00 1.00 5.00 5.40 28.60 89.40 3.2 220 1043795
+1 83 1 1 24 32 419 41 27 2.00 2.00 91694 34919 0.00 0.00 0.00 0.00 0.00 2.20 3.40 181.20 160.40 1.2 3733 1819309
+1 90 1 1 67 90 1850 131 61 1.20 2.20 40316 23559 0.00 0.00 0.00 0.00 0.00 3.20 5.20 78.60 116.80 1.3 694 1020261
+1 88 1 1 15 5 1795 343 209 1.00 1.00 91247 93705 4.20 24.20 74.80 145.20 1.60 11.20 18.40 69.60 119.80 2.0 112 1527192
+1 89 1 1 4 0 1969 209 200 2.40 0.80 131479 48942 0.00 0.00 0.00 0.00 0.20 0.80 1.40 125.05 179.36 1.3 1126 1053153
+1 87 1 1 10 4 3734 212 168 1.20 1.00 197813 112160 0.00 0.00 0.00 0.00 5.99 17.37 19.56 106.99 142.12 2.0 1446 1110237
+1 76 1 1 11 6 4515 185 165 3.79 4.99 85634 65019 0.00 0.00 0.00 0.00 0.00 0.40 0.60 276.25 316.17 4.4 890 1537031
+1 92 1 1 5 4 1568 68 102 0.20 0.20 42053 30000 3.20 4.20 3.20 0.00 1.20 7.60 12.40 15.20 102.20 1.5 313 1016542
+1 83 1 1 8 3 3942 702 244 1.00 0.80 463837 166875 5.20 21.20 43.00 66.80 0.60 20.20 29.40 75.20 237.00 6.6 159 1295243
+1 90 1 1 2 0 457 48 37 2.00 2.00 65518 74456 0.00 0.00 0.00 0.00 0.00 3.00 5.00 187.40 160.20 1.0 6493 1851952
+1 89 1 1 5 0 3300 395 219 2.00 0.80 133693 89066 0.00 0.00 0.00 0.00 0.00 1.80 2.40 112.40 177.40 4.8 2230 1555064
+1 98 1 1 0 0 408 62 45 0.20 0.20 1635 17161 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 3.0 626 1711344
+1 90 1 1 1 0 2596 211 195 0.20 0.20 299110 67609 8.20 14.40 12.60 0.00 0.80 1.20 2.00 16.00 23.20 2.8 266 1715549
+1 96 1 1 1 1 963 90 62 0.60 0.60 91754 14319 0.00 0.00 0.00 0.00 0.00 0.00 0.00 28.20 38.80 2.2 3125 1707618
+1 92 1 1 6 5 1860 128 103 0.60 0.80 118921 56765 19.40 23.20 23.20 0.00 15.60 2.40 3.40 55.60 90.40 2.2 238 982450
+1 91 1 1 3 2 1710 131 122 0.60 1.00 68306 103547 0.00 0.00 0.00 0.00 0.00 2.80 4.20 51.80 89.80 3.2 493 1063110
+1 87 1 1 5 0 4901 508 330 2.00 0.60 165967 155044 0.00 0.00 0.00 0.00 0.00 0.40 0.40 96.60 146.40 2.8 2560 1646453
+1 83 1 1 13 8 4349 300 191 2.80 3.00 96009 70467 0.00 0.00 0.00 0.00 0.00 2.80 3.20 129.00 236.80 2.2 772 993909
+1 73 1 1 622 543 5572 480 297 1.20 3.80 166930 128473 0.00 0.00 0.00 0.00 0.00 12.20 14.60 73.80 197.60 3.0 527 1061819
+1 72 1 1 28 23 6465 408 177 4.20 5.00 454491 41075 0.40 0.60 0.60 0.00 0.20 1.80 4.40 285.60 460.40 2.8 437 999322
+1 90 1 1 12 10 1783 102 78 1.40 0.80 118290 25482 0.00 0.00 0.00 0.00 0.00 4.00 5.20 122.20 136.20 3.2 512 989838
+1 81 1 1 8 2 3309 503 365 4.17 2.78 827279 223918 0.00 0.00 0.00 0.00 0.00 2.39 2.39 222.66 334.39 2.0 747 1112439
+1 96 1 1 2 1 253 22 24 0.80 0.80 34552 22677 0.00 0.00 0.00 0.00 0.00 2.20 4.40 56.40 63.60 1.2 7091 1846198
+1 97 1 1 1 0 1276 29 31 0.60 4.20 47728 9473 0.00 0.00 0.00 0.00 0.00 0.60 0.80 28.00 46.60 2.2 4590 1829136
+1 93 1 1 57 55 1123 107 79 0.20 0.20 20746 36718 0.00 0.00 0.00 0.00 0.00 1.40 8.20 23.40 34.00 1.4 941 972674
+1 82 1 1 22 15 4679 409 258 2.40 3.20 542748 293954 0.00 0.00 0.00 0.00 0.00 8.20 13.60 145.00 241.00 3.8 876 1343698
+1 71 1 1 38 30 5991 289 193 5.80 6.00 401075 205417 4.40 9.00 15.80 21.00 6.20 6.20 9.40 344.40 664.60 2.3 213 1015771
+1 67 1 1 26 2 5404 475 246 6.20 16.40 328399 196650 5.40 32.60 78.20 149.20 0.20 27.80 45.80 222.00 438.20 3.8 122 1091184
+1 87 1 1 5 3 3786 167 149 1.20 1.20 172744 161033 0.00 0.00 0.00 0.00 1.80 4.60 4.60 105.20 171.00 1.0 700 986394
+1 83 1 1 32 42 2331 242 212 4.00 1.60 158546 34270 2.40 2.40 2.40 0.00 3.00 1.20 1.60 218.00 339.00 1.0 205 1023574
+1 90 1 1 1 0 1816 155 99 0.80 1.00 44286 56277 0.00 0.00 0.00 0.00 0.00 5.39 5.99 67.66 82.04 1.0 1259 1048148
+1 86 1 1 2 0 4228 206 186 1.80 0.60 84452 45749 0.00 0.00 0.00 0.00 0.00 0.20 0.20 96.00 135.00 2.2 600 1740986
+1 96 1 1 2 1 986 73 54 0.20 0.20 5562 23881 0.60 0.60 0.60 0.00 0.40 2.60 2.60 12.80 43.80 2.3 217 1013784
+1 91 1 1 0 0 255 32 32 0.20 0.20 1430 7410 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.6 1196 1767021
+1 86 1 1 40 11 3402 283 202 2.80 4.20 225184 28672 0.00 0.00 0.00 0.00 0.00 1.20 3.40 157.40 279.20 1.0 1025 1092723
+1 52 1 1 55 0 4652 302 223 16.17 36.93 180995 29681 3.39 9.98 22.16 42.51 0.00 21.16 25.55 628.74 1134.53 1.0 187 1102798
+1 88 1 1 14 4 1575 358 236 2.20 1.80 468846 173574 2.40 2.80 2.40 0.00 0.80 5.40 8.40 143.00 268.00 1.0 362 1070280
+1 95 1 1 1 0 928 115 89 0.40 1.40 4969 17251 0.00 0.00 0.00 0.00 0.20 9.38 9.58 26.35 54.09 5.0 889 1063856
+1 76 1 1 7 1 2319 207 94 0.60 1.20 1132227 33317 31.40 99.60 270.20 584.40 1.20 114.60 244.60 60.40 157.20 2.8 98 984424
+1 89 1 1 2 1 2133 134 90 0.80 1.00 100812 83681 0.00 0.00 0.00 0.00 1.20 12.38 21.76 51.90 126.75 1.8 405 987278
+1 94 1 1 1 0 1372 66 41 0.20 0.20 17950 17530 0.00 0.00 0.00 0.00 0.00 0.20 0.40 66.20 30.00 1.4 986 1066130
+1 96 1 1 9 8 470 129 81 0.20 0.20 291365 51259 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 28.80 1.2 1302 1760490
+1 80 1 1 32 26 3205 350 245 1.00 1.40 109372 69986 4.20 10.40 21.80 29.80 1.60 5.80 6.40 80.60 209.40 2.6 405 1315331
+1 76 1 1 25 0 3346 198 131 6.21 18.04 211729 48291 2.40 20.64 48.70 193.99 0.00 23.05 35.47 207.82 405.61 2.7 133 1099542
+1 87 1 1 16 14 1363 121 82 0.80 0.60 321356 183286 0.00 0.00 0.00 0.00 0.60 0.40 0.40 71.20 58.00 3.2 753 1511563
+1 97 1 1 0 0 431 39 72 0.80 0.60 13226 49176 0.40 3.01 7.21 15.03 0.00 0.60 0.60 37.47 44.89 1.0 172 1746309
+1 97 1 1 0 0 183 38 21 0.20 0.20 255771 228527 0.00 0.00 0.00 0.00 0.00 0.00 0.00 12.80 16.80 2.8 3652 1819990
+1 91 1 1 13 21 324 19 14 0.20 0.20 644 4682 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.97 17.56 1.8 1230 1750204
+1 0 1 1 2 0 1240 87 83 0.40 0.60 21455 50048 0.60 0.80 0.80 0.00 0.00 3.99 6.39 75.45 104.99 679 93 7
+1 91 1 1 13 3 1651 78 60 0.80 3.00 56684 21286 0.00 0.00 0.00 0.00 0.60 1.40 1.40 64.40 157.80 1.0 590 1032789
+1 92 1 1 33 43 1613 161 110 0.20 0.20 11850 28651 2.00 2.80 2.40 0.00 1.40 4.00 4.80 18.20 120.40 1.0 253 1021384
+1 76 1 1 9 1 3326 383 177 6.20 19.20 34844 28865 6.00 26.60 31.80 46.80 0.40 9.00 10.80 214.60 442.00 1.5 188 1103072
+1 80 1 1 41 32 5200 185 121 2.79 7.19 59209 63458 6.19 7.78 7.78 0.00 3.59 0.00 0.00 179.64 217.76 2.4 209 1623562
+1 99 1 1 2 1 174 11 24 0.20 0.20 10271 8797 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6442 1871299
+1 85 1 1 2 0 534 75 53 2.20 2.20 57506 28455 0.40 0.40 0.40 0.00 0.00 0.80 0.80 170.60 157.60 1.2 359 1813328
+1 92 1 1 31 38 1145 143 124 3.19 1.00 81774 6003 0.00 0.00 0.00 0.00 0.00 0.00 0.00 160.08 226.35 1.6 7313 1860552
+1 99 1 1 0 0 159 15 16 0.20 0.20 454 5323 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.0 7226 1859904
+1 86 1 1 8 0 2956 409 371 3.60 3.00 254532 197621 0.00 0.00 0.00 0.00 0.00 0.60 1.00 176.60 240.00 2.8 5037 1672027
+1 90 1 1 2 1 3735 279 143 0.40 1.00 387812 214397 0.00 0.00 0.00 0.00 0.00 6.20 12.00 31.40 86.20 4.0 3768 1333251
+1 80 1 1 11 4 3794 340 304 4.00 2.20 174498 141499 0.60 1.00 0.80 0.00 2.40 26.40 26.80 192.00 427.40 1.2 466 1079363
+1 82 1 1 56 62 1929 146 97 1.80 3.60 319479 97895 8.60 16.80 19.00 6.00 0.40 17.60 21.20 130.80 229.80 1.8 553 1085286
+1 95 1 1 2 2 1424 133 101 0.20 0.20 210413 16994 0.00 0.00 0.00 0.00 0.00 2.00 3.20 16.20 28.80 2.0 342 979099
+1 88 1 1 23 32 3355 234 111 1.20 3.00 155241 126756 0.00 0.00 0.00 0.00 0.00 2.00 2.00 122.80 119.80 5.4 4018 1606019
+1 97 1 1 0 0 393 162 57 0.20 0.20 210929 207090 0.00 0.00 0.00 0.00 0.00 0.60 0.60 15.60 16.80 2.4 1323 1745669
+1 76 1 1 17 9 1048 124 69 1.00 1.40 683931 188394 21.36 78.24 113.57 227.15 2.20 25.15 49.10 122.16 249.90 1.0 309 1051283
+1 96 1 1 1 0 958 117 45 0.60 0.60 215753 27639 0.00 0.00 0.00 0.00 0.00 2.80 5.60 39.80 43.40 2.0 6280 1845344
+1 88 1 1 3 3 1941 427 173 0.80 0.80 658879 844732 0.00 0.00 0.00 0.00 0.20 0.60 1.20 49.20 69.00 1.8 635 1045738
+1 79 1 1 7 0 3758 508 978 5.80 1.60 233257 87134 0.00 0.00 0.00 0.00 0.00 7.40 14.20 273.20 418.60 4.2 981 1705043
+1 96 1 1 1 1 857 90 44 0.20 0.20 46735 82746 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.54 16.73 1.0 6709 1818845
+1 96 1 1 40 54 844 28 33 0.20 0.20 817 11451 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 4707 1727696
+1 97 1 1 0 0 222 30 22 0.20 0.20 84896 5119 0.00 0.00 0.00 0.00 0.00 0.00 0.00 22.36 17.17 1.6 7302 1860350
+1 86 1 1 4 0 2921 248 205 3.80 1.40 140416 21712 3.00 5.00 5.00 0.00 0.40 1.00 1.40 208.80 328.60 3.0 177 1437750
+1 90 1 1 6 4 2573 189 118 0.60 0.60 107287 30575 0.00 0.00 0.00 0.00 0.00 11.40 13.00 31.40 173.40 1.4 1107 975696
+1 90 1 1 16 14 2131 116 84 0.80 1.20 26886 41641 0.00 0.00 0.00 0.00 0.20 18.00 18.20 140.60 132.60 3.0 793 990656
+1 79 1 1 30 13 3962 617 514 4.20 1.20 326797 265654 2.20 11.40 17.40 42.00 0.60 10.00 17.80 221.20 394.40 1.2 191 1082230
+1 79 1 1 9 2 3750 280 226 1.20 4.00 194798 362338 4.40 8.40 11.80 21.40 3.80 7.00 26.20 83.60 188.60 2.8 402 984866
+1 80 1 1 37 4 3499 388 117 4.19 5.99 288035 14367 0.00 0.00 0.00 0.00 0.00 19.76 34.93 289.62 526.95 4.2 766 1305325
+1 88 1 1 60 71 2647 289 300 1.00 3.20 32797 37359 0.00 0.00 0.00 0.00 0.00 17.20 17.40 58.00 100.60 1.0 505 1101470
+1 93 1 1 6 3 1005 63 60 0.20 0.20 134728 76858 0.00 0.00 0.00 0.00 0.00 5.60 5.60 33.40 52.20 2.2 1789 1525715
+1 89 1 1 10 10 3224 222 100 0.60 0.60 95098 46440 3.99 5.59 4.99 0.00 1.40 1.20 3.79 27.54 53.89 1.5 211 996805
+1 93 1 1 15 1 643 60 19 1.20 1.40 361682 5234 0.00 0.00 0.00 0.00 0.00 16.20 31.00 96.60 147.40 2.2 7005 1876323
+1 84 1 1 8 3 4100 391 383 1.20 1.60 259796 75883 0.00 0.00 0.00 0.00 0.00 28.40 55.40 100.00 96.60 2.8 2054 1551126
+1 82 1 1 68 77 2774 217 152 3.61 6.21 180351 57275 1.80 3.81 3.81 0.00 1.20 4.61 8.22 236.07 415.83 2.7 324 1055946
+1 81 1 1 3 0 583 53 68 2.60 3.20 62950 258017 34.00 62.60 60.60 0.00 0.40 2.40 2.80 207.60 204.80 1.8 270 1807019
+1 91 1 1 132 105 2007 177 139 0.40 0.40 95309 82017 0.00 0.00 0.00 0.00 0.00 1.20 1.20 35.20 56.60 1.0 794 1008800
+1 81 1 1 10 6 3249 555 526 2.39 4.38 469560 380797 0.00 0.00 0.00 0.00 0.00 0.80 0.80 121.31 181.08 1.4 870 1126010
+1 91 1 1 2 0 3099 180 116 0.20 0.20 526898 35032 7.60 8.20 10.60 8.20 0.20 5.00 5.00 16.00 109.40 2.2 198 1080638
+1 95 1 1 4 3 1887 144 93 0.20 0.20 48118 58743 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.60 17.80 2.4 2097 1720363
+1 90 1 1 0 0 2772 148 221 0.20 0.20 95025 96367 8.00 15.60 13.40 0.00 0.80 1.20 1.20 15.60 19.20 2.0 226 1708712
+1 88 1 1 64 82 2442 456 192 1.20 0.80 584516 567421 0.00 0.00 0.00 0.00 0.00 1.00 1.00 98.60 148.60 2.0 555 1041030
+1 95 1 1 0 0 1162 230 83 0.40 1.80 227587 216272 0.00 0.00 0.00 0.00 0.00 0.00 0.00 34.40 40.40 4.8 2576 1602462
+1 82 1 1 4 0 4562 201 149 0.20 0.20 61399 41637 0.00 0.00 0.00 0.00 0.00 5.00 48.60 16.00 27.20 2.8 1076 1770294
+1 0 1 1 81 45 1479 180 199 0.80 2.00 110797 88252 3.01 12.83 12.83 0.00 1.40 10.62 11.02 61.52 123.65 335 90 10
+1 87 1 1 1 0 2361 286 183 0.20 0.20 154222 94948 8.78 18.96 52.50 87.03 0.80 2.99 4.99 17.56 132.93 1.5 132 993843
+1 80 1 1 4 2 2421 581 170 2.20 3.79 1029143 278592 4.99 22.36 48.70 120.96 0.40 2.00 2.40 324.75 215.77 1.3 163 1111235
+1 91 1 1 26 39 1722 139 114 0.20 0.20 163304 47725 14.60 18.40 18.00 0.00 13.40 0.40 0.40 21.60 37.00 1.0 229 1016514
+1 76 1 1 12 2 2763 366 256 6.20 4.80 310712 49538 0.60 0.60 0.60 0.00 0.60 3.00 15.40 309.60 602.00 1.8 498 1122262
+1 87 1 1 3 1 2072 262 241 1.40 1.40 330763 387350 2.00 12.20 34.60 77.00 6.80 10.00 14.40 122.00 155.80 2.6 137 1374699
+1 80 1 1 3 1 3662 256 187 1.80 3.79 360623 160015 19.76 27.35 55.49 95.01 8.38 7.19 10.98 117.17 202.99 3.2 159 989493
+1 89 1 1 8 6 2336 206 90 0.40 1.00 136627 53677 0.00 0.00 0.00 0.00 0.00 2.40 2.40 35.20 61.40 5.4 2869 1584662
+1 92 1 1 31 27 366 80 62 0.20 0.20 412220 287099 0.00 0.00 0.00 0.00 0.60 3.00 5.60 15.60 17.80 3.4 4179 1824024
+1 85 1 1 7 2 4133 222 154 1.40 1.40 15783 9833 0.00 0.00 0.00 0.00 0.00 1.60 1.80 83.00 139.00 2.8 1297 1523251
+1 88 1 1 0 0 3896 199 156 0.60 2.79 130609 63759 2.79 4.99 4.99 0.00 0.80 4.39 4.39 22.95 79.44 2.7 146 983954
+1 95 1 1 9 9 383 122 43 0.20 0.20 361823 114595 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 17.80 2.0 1390 1745830
+1 90 1 1 7 2 2128 183 166 0.80 2.20 89713 240084 0.00 0.00 0.00 0.00 0.00 2.80 3.60 70.00 109.00 3.2 406 1527165
+1 72 1 1 18 1 5654 1130 1089 5.20 4.00 967478 900948 0.00 0.00 0.00 0.00 0.60 4.20 5.80 287.80 429.00 1.7 740 1055050
+1 93 1 1 21 29 1670 28 49 0.20 0.20 19096 28284 2.20 2.60 39.80 65.80 0.60 52.60 52.60 15.60 74.80 2.4 124 1759971
+1 95 1 1 7 2 1305 89 108 0.60 2.20 121604 89237 0.00 0.00 0.00 0.00 0.00 0.60 0.80 87.00 66.00 1.0 482 1065374
+1 99 1 1 2 1 158 8 9 0.20 0.20 7007 3677 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 7739 1880280
+1 75 1 1 14 8 5333 193 128 3.58 11.93 46335 36128 0.00 0.00 0.00 0.00 0.00 0.40 0.80 275.94 295.43 3.4 997 1530475
+1 86 1 1 1 0 4748 256 168 0.80 3.00 11643 46726 0.00 0.00 0.00 0.00 0.00 2.80 2.80 32.20 70.80 1.3 726 1116712
+1 72 1 1 33 28 5504 439 253 3.40 4.20 395654 70646 9.40 24.00 29.60 126.80 4.20 6.40 9.80 220.80 424.40 2.0 204 1134814
+1 87 1 1 5 2 3841 194 189 0.80 1.99 12984 96970 0.00 0.00 0.00 0.00 0.00 2.98 4.97 44.93 93.44 2.0 436 1064942
+1 99 1 1 1 1 458 21 17 0.20 0.20 8171 5971 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 1.0 8968 1872928
+1 62 1 1 88 104 5849 473 441 8.40 16.00 241603 199394 7.40 13.60 28.40 33.20 0.00 8.80 11.80 337.80 560.20 1.0 153 1090811
+1 84 1 1 5 1 2481 219 153 1.40 3.00 276794 210452 11.60 16.20 16.20 0.00 9.40 23.20 51.60 193.00 231.40 3.8 449 1383576
+1 85 1 1 0 0 964 94 50 0.20 0.20 307373 17623 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 2.0 666 1757760
+1 89 1 1 15 12 1664 109 79 1.20 1.00 62620 31710 5.79 6.39 7.19 3.79 2.59 9.38 10.18 67.86 173.85 5.0 244 1059291
+1 89 1 1 12 3 2857 159 132 1.60 3.00 126476 116554 0.00 0.00 0.00 0.00 0.00 1.40 2.60 92.80 214.20 2.2 2989 1547434
+1 92 1 1 0 0 1657 43 29 0.20 0.20 9241 12063 0.00 0.00 0.00 0.00 0.00 0.60 1.00 15.00 18.00 2.0 1050 1762933
+1 91 1 1 4 3 2938 148 127 0.60 3.40 18373 38276 0.00 0.00 0.00 0.00 0.00 7.80 8.20 25.20 80.60 2.0 376 994544
+1 91 1 1 5 1 1965 207 125 0.40 1.00 193174 22877 3.80 9.20 16.00 25.80 9.40 41.80 42.40 31.40 122.80 3.8 172 1085874
+1 81 1 1 7 0 2107 235 154 7.21 3.81 132739 29310 3.61 6.21 7.62 6.41 0.20 2.40 3.81 312.63 594.39 1.0 318 1022535
+1 90 1 1 6 4 1932 66 85 1.00 0.80 67203 79964 13.60 23.00 27.80 18.80 6.20 11.80 13.60 91.80 147.80 3.5 165 1128728
+1 85 1 1 15 10 3781 346 168 2.40 3.21 307016 76305 3.81 4.21 8.62 18.44 5.21 1.40 1.40 154.91 296.99 5.2 155 1004704
+1 81 1 1 18 11 4068 280 140 3.00 4.60 320517 55276 0.00 0.00 0.00 0.00 5.80 9.20 32.40 264.40 381.60 1.0 489 1014958
+1 97 1 1 0 0 237 11 24 0.40 0.40 3108 58724 0.00 0.00 0.00 0.00 0.00 0.00 0.00 34.67 33.47 1.0 6855 1857699
+1 63 1 1 45 0 3575 217 131 11.60 35.00 197409 41178 6.00 20.40 41.20 70.60 0.00 15.40 28.20 378.40 740.20 2.2 135 1091397
+1 85 1 1 7 4 3338 734 110 1.00 1.40 2408325 41666 0.00 0.00 0.00 0.00 0.80 10.20 15.20 82.20 172.20 1.7 2443 1088307
+1 96 1 1 3 2 537 22 28 0.20 0.20 11166 12932 0.00 0.00 0.00 0.00 0.00 1.80 2.79 16.17 53.29 1.0 755 1036805
+1 0 1 1 47 64 1364 432 273 0.60 0.60 965273 950976 26.60 83.00 209.80 433.20 0.00 54.80 107.40 51.80 83.80 52 75 25
+1 91 1 1 21 20 1949 232 153 0.20 0.20 17171 29878 6.20 12.20 12.20 0.00 0.00 1.20 1.20 24.60 28.80 1.0 508 1070658
+1 94 1 1 36 55 4085 156 137 0.20 0.20 8149 6247 0.00 0.00 0.00 0.00 0.00 1.80 1.80 16.00 45.80 2.2 794 1447821
+1 96 1 1 0 0 367 62 43 0.40 0.60 38562 12342 0.00 0.00 0.00 0.00 0.00 1.60 2.40 30.60 41.00 1.2 710 1753534
+1 97 1 1 1 0 443 54 25 0.20 0.20 31996 16345 0.40 0.40 3.00 7.20 0.00 0.60 1.00 16.00 24.40 3.0 132 1711738
+1 72 1 1 53 71 4201 461 384 4.20 2.80 185684 64437 5.80 10.20 10.20 0.00 0.40 7.20 7.80 214.40 361.00 1.6 240 984506
+1 91 1 1 1 1 600 158 41 0.60 1.00 476298 133721 0.00 0.00 0.00 0.00 0.00 3.60 3.60 51.20 68.20 3.0 6006 1835992
+1 86 1 1 11 2 2485 265 147 1.40 2.80 496095 18723 0.60 0.60 0.60 0.00 1.00 5.80 8.80 101.40 209.20 1.5 460 1131946
+1 97 1 1 15 15 419 189 62 0.20 0.20 322341 310319 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 2.4 5333 1825789
+1 96 1 1 2 1 542 89 65 0.40 0.40 2453 16876 0.00 0.00 0.00 0.00 0.00 0.00 0.00 29.40 40.60 2.2 667 1721728
+1 91 1 1 2 1 1125 124 78 0.80 2.40 225895 24254 0.00 0.00 0.00 0.00 0.00 0.60 1.00 80.24 168.26 2.0 2190 1007462
+1 81 1 1 14 3 3542 360 259 3.40 1.20 458811 147720 10.80 19.00 22.20 16.40 1.40 11.00 11.40 173.80 342.00 2.0 225 1077714
+1 91 1 1 3 2 2656 162 110 1.20 2.00 110401 28047 0.00 0.00 0.00 0.00 5.01 3.21 4.21 114.03 198.80 2.0 542 1018144
+1 87 1 1 17 2 2614 208 113 0.60 1.80 560315 22349 0.00 0.00 0.00 0.00 0.00 2.59 3.19 54.29 160.08 1.8 608 1103864
+1 85 1 1 5 2 4313 364 218 0.60 0.60 195525 90675 9.60 11.60 15.60 7.60 0.60 3.40 3.80 56.00 115.20 1.6 170 1066182
+1 91 1 1 0 0 1977 256 133 0.60 2.61 225802 37213 1.20 2.00 2.00 0.00 2.81 6.61 8.22 46.49 113.63 2.2 299 1105616
+1 0 1 1 54 69 1720 143 105 0.80 1.20 175782 34995 0.00 0.00 0.00 0.00 0.00 17.40 24.20 55.40 75.40 594 88 12
+1 95 1 1 1 0 2381 118 119 0.20 0.20 17002 111682 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 16.80 2.4 640 1645008
+1 0 1 1 24 7 1248 173 105 0.80 2.59 308625 114117 20.36 31.54 45.71 30.14 8.98 23.95 33.13 76.85 254.29 181 87 13
+1 93 1 1 8 6 1572 121 123 0.40 0.40 25373 68247 2.79 4.59 4.39 0.00 0.20 12.18 13.57 30.74 82.04 4.8 360 1101980
+1 83 1 1 20 2 3229 197 115 4.80 5.20 270106 85338 0.00 0.00 0.00 0.00 0.00 0.20 0.20 253.80 443.80 3.8 1491 1547806
+1 92 1 1 51 71 1824 161 118 0.60 0.60 78411 94050 0.60 0.60 0.60 0.00 0.20 0.60 0.60 44.60 65.40 1.5 302 989306
+1 91 1 1 41 61 956 101 82 1.60 4.60 49004 29774 0.00 0.00 0.00 0.00 0.00 1.20 1.20 86.80 98.80 6.0 573 1056264
+1 89 1 1 14 12 4004 225 142 0.40 0.40 149008 89163 3.80 7.40 7.20 0.00 0.40 10.60 13.00 29.80 70.20 4.6 218 1337400
+1 90 1 1 1 0 414 37 34 0.60 1.00 72460 10038 0.00 0.00 0.00 0.00 0.00 8.20 15.80 59.40 96.20 1.4 4024 1779862
+1 89 1 1 29 6 2375 146 123 2.00 3.19 109539 39984 0.00 0.00 0.00 0.00 0.00 8.98 9.98 116.57 226.75 1.0 663 1018837
+1 89 1 1 35 51 4033 193 155 0.20 0.20 53695 33261 0.00 0.00 0.00 0.00 0.00 10.02 17.84 15.83 83.17 1.5 1038 1081435
+1 91 1 1 2 0 3599 227 124 0.40 0.40 247883 214426 0.00 0.00 0.00 0.00 0.00 8.20 12.80 32.80 70.20 3.8 4180 1344790
+1 69 1 1 12 0 4951 579 495 9.40 4.40 329231 42171 0.00 0.00 0.00 0.00 0.00 0.40 0.40 462.20 711.00 2.2 984 1056850
+1 86 1 1 1 0 2370 216 165 0.60 2.59 91492 123945 3.59 5.79 5.79 0.00 0.00 11.78 15.57 25.55 60.68 1.5 285 1102248
+1 96 1 1 2 0 1567 133 137 0.20 0.20 41338 73068 0.00 0.00 0.00 0.00 0.00 1.60 2.40 18.80 23.60 2.0 6175 1727312
+1 83 1 1 26 7 3681 262 137 1.60 3.40 202491 143767 4.40 23.00 97.80 170.40 2.20 22.00 39.40 113.80 322.80 6.2 164 1536462
+1 73 1 1 18 0 5276 681 528 8.00 2.20 353135 151126 1.60 1.60 1.60 0.00 0.20 2.20 3.80 375.80 566.00 6.2 231 1544432
+1 93 1 1 18 14 1405 97 75 0.80 0.80 281552 44324 0.00 0.00 0.00 0.00 0.00 1.00 1.40 66.80 66.60 3.4 613 1514861
+1 95 1 1 0 0 1425 92 53 0.20 0.20 214550 15664 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.80 31.60 1.0 2191 1009408
+1 97 1 1 0 0 182 16 30 0.20 0.20 10672 35469 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 2698 1771613
+1 98 1 1 0 0 802 28 31 0.20 0.20 4235 54696 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 1.0 6799 1853384
+1 93 1 1 0 0 1369 245 109 0.20 0.20 27830 389081 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 19.40 2.2 5713 1817542
+1 89 1 1 48 68 3283 134 125 0.40 0.40 33832 23626 4.20 9.00 9.00 0.00 0.60 1.80 2.20 36.40 56.20 1.0 461 1129531
+1 97 1 1 0 0 184 11 25 0.20 0.20 2065 10058 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7733 1881032
+1 81 1 1 2 1 2675 143 94 0.20 0.20 304215 19274 0.00 0.00 0.00 0.00 0.00 2.00 3.80 106.00 22.40 3.0 690 1757880
+1 79 1 1 10 0 3003 447 383 9.00 2.80 273594 10059 0.00 0.00 0.00 0.00 0.00 0.00 0.00 460.00 649.20 3.4 8659 1865656
+1 91 1 1 37 37 3127 266 193 0.60 1.80 21713 134601 0.00 0.00 0.00 0.00 0.20 1.00 1.40 39.40 93.20 2.8 360 1025109
+1 82 1 1 9 0 2079 316 256 4.41 3.01 158458 40402 0.00 0.00 0.00 0.00 1.20 2.40 2.40 198.80 316.43 2.2 550 1024770
+1 92 1 1 0 0 2611 286 167 0.20 0.20 82615 83485 0.00 0.00 0.00 0.00 0.20 0.20 0.20 16.00 21.80 5.2 3047 1601744
+1 93 1 1 4 0 973 130 120 0.80 4.00 56826 40037 0.00 0.00 0.00 0.00 0.00 0.40 5.60 61.40 166.80 2.2 2071 1732128
+1 88 1 1 33 42 2995 183 140 0.40 0.40 41711 69821 0.00 0.00 0.00 0.00 0.20 0.20 0.20 31.40 60.40 1.0 598 1077210
+1 84 1 1 116 52 1417 197 142 3.60 6.20 165098 108109 3.00 12.80 12.80 0.00 1.60 23.80 33.80 190.80 343.20 1.0 311 982754
+1 93 1 1 5 3 842 52 30 1.00 1.20 118262 20988 0.00 0.00 0.00 0.00 0.00 0.40 0.40 87.80 111.60 1.4 6699 1840197
+1 89 1 1 8 0 1803 367 300 0.20 0.20 516137 229603 5.61 41.88 118.04 216.23 3.01 43.09 88.78 14.23 94.99 1.2 130 1044431
+1 86 1 1 9 1 2783 391 223 2.00 3.99 561054 53145 0.00 0.00 0.00 0.00 0.00 4.59 7.98 141.32 201.60 2.8 2783 1732179
+1 76 1 1 22 0 2209 254 166 4.80 4.20 145759 100835 5.40 11.20 51.40 86.00 0.00 19.20 22.80 235.80 471.40 2.6 150 1061107
+1 92 1 1 4 0 2822 248 157 0.40 0.40 293231 118889 0.00 0.00 0.00 0.00 0.00 4.61 4.61 34.87 116.23 3.2 624 1083872
+1 93 1 1 2 2 1447 134 115 0.40 0.40 9940 25644 0.00 0.00 0.00 0.00 0.00 1.60 1.60 37.27 41.68 3.2 1054 1130742
+1 94 1 1 2 0 2040 230 91 0.20 0.20 65806 28087 0.00 0.00 0.00 0.00 0.40 19.16 24.15 14.77 79.64 3.4 3917 1715626
+1 0 1 1 9 5 1879 318 195 1.20 0.80 1598065 1456441 1.20 1.60 1.60 0.00 0.40 1.60 2.00 70.06 120.36 216 89 11
+1 81 1 1 37 20 4736 409 305 4.39 2.20 186131 124064 0.00 0.00 0.00 0.00 0.00 2.59 2.79 269.06 392.81 3.6 3551 1544251
+1 72 1 1 10 1 3851 489 415 7.80 2.20 371419 94611 0.00 0.00 0.00 0.00 0.00 0.00 0.00 389.00 553.40 2.0 8226 1835470
+1 0 1 1 6 3 1480 84 80 0.40 0.80 3808 46665 0.00 0.00 0.00 0.00 0.00 2.40 3.01 47.49 86.37 502 94 6
+1 88 1 1 52 60 1367 165 91 1.20 2.00 40521 32978 1.00 4.00 6.80 9.20 0.40 2.40 2.80 77.40 243.40 1.6 362 966408
+1 95 1 1 13 11 1092 85 46 0.60 3.00 23660 15429 0.00 0.00 0.00 0.00 0.00 0.40 0.80 35.60 42.60 2.2 4908 1673408
+1 89 1 1 0 0 3197 108 72 0.20 0.20 6617 20668 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.20 16.80 1.8 1399 1753960
+1 90 1 1 1 0 725 92 77 0.60 0.60 35358 12244 0.00 0.00 0.00 0.00 0.00 0.00 0.00 42.40 49.60 1.2 673 1760488
+1 73 1 1 22 8 6630 202 115 3.80 9.40 279697 9693 0.00 0.00 0.00 0.00 0.00 10.40 10.80 261.20 363.60 5.8 821 1529410
+1 97 1 1 0 0 1431 44 55 0.20 0.20 12448 19666 0.00 0.00 0.00 0.00 0.00 1.00 1.20 13.20 16.80 1.0 566 1752792
+1 86 1 1 4 0 2965 268 197 2.81 0.80 352731 28323 1.40 1.60 1.60 0.00 0.20 2.81 3.01 142.69 224.05 2.0 264 1068253
+1 94 1 1 10 9 1339 81 74 1.00 0.60 13140 25936 1.20 1.20 1.20 0.00 0.40 6.20 6.40 48.00 95.40 1.8 150 1059384
+1 0 1 1 39 56 1053 41 40 0.20 0.20 4447 14290 0.00 0.00 0.00 0.00 0.00 0.60 0.60 16.23 32.67 372 95 5
+1 79 1 1 13 9 1946 223 174 3.79 10.98 526411 33407 8.78 56.49 132.53 226.55 0.40 75.65 130.74 131.94 261.28 1.5 119 1103984
+1 98 1 1 0 0 246 46 17 0.20 0.20 252455 4969 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.97 16.97 1.2 7290 1860126
+1 79 1 1 28 36 2862 193 101 3.80 4.20 217700 62552 0.00 0.00 0.00 0.00 0.00 1.20 1.20 219.60 331.40 2.4 390 1767661
+1 80 1 1 7 0 5339 364 240 1.40 1.40 671122 426880 0.00 0.00 0.00 0.00 0.20 13.60 26.40 121.00 189.80 6.2 1256 1337077
+1 88 1 1 1 0 2967 188 134 0.60 0.60 155568 54454 0.00 0.00 0.00 0.00 0.00 8.00 11.80 40.80 84.20 3.8 802 1064942
+1 78 1 1 30 24 1655 106 74 4.41 5.41 139219 47304 3.21 7.41 21.84 30.46 1.00 14.63 27.66 292.99 612.83 3.0 346 1015801
+1 94 1 1 27 37 882 92 71 0.40 0.40 38612 31518 2.99 5.59 8.78 15.97 0.00 10.38 11.58 31.54 66.47 1.0 148 1011275
+1 80 1 1 20 13 4257 403 298 3.01 3.21 236001 145168 0.00 0.00 0.00 0.00 0.00 11.82 14.03 182.77 350.30 2.5 2384 1094818
+1 94 1 1 1 0 3017 136 112 0.20 0.20 59665 113330 0.00 0.00 0.00 0.00 0.00 3.40 5.00 15.80 39.40 2.4 434 1630134
+1 79 1 1 19 14 3392 577 572 2.00 2.60 483123 507757 0.00 0.00 0.00 0.00 0.00 9.20 13.80 368.60 225.40 1.0 546 1059475
+1 60 1 1 86 78 6870 484 356 8.20 15.00 344994 151519 0.00 0.00 0.00 0.00 0.20 28.60 33.20 469.00 725.40 5.4 512 1539402
+1 90 1 1 5 2 2561 198 169 3.00 1.00 129015 29495 3.00 3.00 2.60 0.00 0.80 0.60 1.20 140.20 208.60 1.6 230 1750422
+1 95 1 1 1 1 1693 143 147 0.20 0.20 20310 27719 0.00 0.00 0.00 0.00 0.00 2.20 4.00 16.20 25.60 1.5 521 1066154
+1 0 1 1 26 23 2344 421 181 0.60 2.20 635411 590079 0.00 0.00 0.00 0.00 0.00 27.80 53.40 54.20 161.20 816 85 14
+1 69 1 1 234 88 3259 483 287 6.39 17.17 1023657 222304 1.20 11.18 11.18 0.00 0.20 32.34 53.89 275.25 547.90 4.2 425 1088819
+1 80 1 1 14 10 2275 312 228 3.21 1.20 565950 400919 0.00 0.00 0.00 0.00 0.00 45.89 90.78 171.54 352.10 3.4 3791 1041151
+1 94 1 1 4 2 1817 240 71 0.20 0.20 21627 10457 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.40 17.00 2.0 2560 1701149
+1 79 1 1 12 8 775 71 37 3.80 4.20 125517 40041 0.00 0.00 0.00 0.00 0.00 4.20 6.00 309.40 331.00 1.4 2613 1794333
+1 91 1 1 2 0 2590 167 248 0.80 0.40 117072 179675 0.00 0.00 0.00 0.00 0.20 0.00 0.00 58.20 78.80 2.4 539 1759701
+1 86 1 1 4 0 2139 192 76 2.80 4.00 254183 69772 5.20 5.80 5.80 0.00 1.00 3.20 6.00 237.00 321.00 1.8 218 1752714
+1 86 1 1 50 62 2562 239 181 1.00 3.00 171071 86083 0.00 0.00 0.00 0.00 0.00 0.60 1.00 101.20 159.40 4.0 2551 1537406
+1 82 1 1 44 56 3665 275 231 1.60 0.80 227554 39676 0.00 0.00 0.00 0.00 0.00 2.40 2.40 172.85 163.27 1.2 2016 966448
+1 94 1 1 2 0 1368 136 75 0.20 0.20 51529 59177 0.00 0.00 0.00 0.00 0.00 6.20 6.80 18.60 45.60 1.2 698 1062493
+1 78 1 1 14 5 5744 583 274 3.39 2.59 389123 235864 0.00 0.00 0.00 0.00 0.00 26.95 29.74 165.47 371.66 5.4 1434 1615471
+1 97 1 1 1 1 960 51 40 0.20 0.20 108053 44913 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.4 6930 1879101
+1 78 1 1 12 5 5935 356 199 1.40 0.80 173332 74812 0.60 0.60 0.60 0.00 0.00 4.20 6.20 79.60 138.00 5.2 315 1296418
+1 0 1 1 9 6 1538 145 100 0.20 0.20 240721 48736 0.60 0.60 0.80 0.20 0.20 7.80 10.00 27.80 33.40 355 93 7
+1 88 1 1 28 40 2957 261 164 0.20 0.20 201445 80840 7.00 9.60 16.60 16.20 4.00 26.80 27.40 20.60 69.40 4.4 167 1014187
+1 97 1 1 0 0 1006 44 41 0.60 0.80 3325 8798 0.00 0.00 0.00 0.00 0.00 0.20 0.40 34.40 45.80 1.0 1377 1746506
+1 91 1 1 4 0 2148 108 77 2.60 8.00 130916 26669 2.40 3.60 3.60 0.00 2.20 2.00 2.40 129.00 214.80 2.4 267 1751203
+1 89 1 1 9 1 3357 149 145 1.00 1.20 122904 40944 0.00 0.00 0.00 0.00 0.00 6.19 6.59 62.67 104.79 5.2 3092 1538472
+1 96 1 1 1 0 1132 32 30 0.20 0.20 5381 22916 1.40 1.40 1.40 0.00 0.00 0.60 0.80 16.60 18.80 3.2 172 1714160
+1 91 1 1 0 0 765 81 62 0.20 0.20 34390 36627 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.63 16.83 1.2 1723 1771888
+1 96 1 1 24 31 489 61 133 0.20 0.20 38044 33334 0.00 0.00 0.00 0.00 0.20 0.80 0.80 17.20 24.60 2.2 1099 1717939
+1 86 1 1 5 0 5291 298 214 0.80 1.00 250499 60387 0.00 0.00 0.00 0.00 0.20 17.00 18.80 67.20 289.00 1.0 654 995230
+1 90 1 1 10 9 1548 137 95 0.60 0.60 30463 36164 0.00 0.00 0.00 0.00 0.00 3.41 3.81 51.50 129.66 2.0 676 980412
+1 96 1 1 27 38 1292 67 46 0.20 0.20 2864 18973 0.00 0.00 0.00 0.00 0.00 1.80 2.00 15.63 31.86 1.2 1153 1748641
+1 86 1 1 14 2 3735 239 226 3.00 1.40 159807 115748 0.00 0.00 0.00 0.00 0.00 9.80 18.60 144.60 232.40 3.8 3534 1551085
+1 98 1 1 0 0 615 40 24 0.20 0.20 17074 9089 0.00 0.00 0.00 0.00 0.00 0.60 1.00 15.60 17.00 2.0 4592 1731704
+1 88 1 1 0 0 770 204 56 0.20 0.20 1299349 304151 0.00 0.00 0.00 0.00 0.00 2.00 3.20 15.40 23.20 3.2 3516 1810597
+1 91 1 1 10 6 2698 154 95 0.60 2.00 41837 23966 0.80 0.80 0.80 0.00 0.40 3.00 6.00 56.20 68.60 2.8 313 1111091
+1 93 1 1 8 2 1116 81 91 1.20 1.40 59686 95337 0.00 0.00 0.00 0.00 0.20 3.40 5.60 81.00 134.00 2.2 1714 1538925
+1 86 1 1 3 1 572 120 31 2.80 2.80 90781 61249 0.00 0.00 0.00 0.00 0.00 6.00 10.40 225.00 220.60 1.2 5759 1847078
+1 90 1 1 54 62 1101 104 81 1.80 1.60 241932 82941 5.80 8.20 11.20 10.60 3.60 4.20 4.80 98.00 193.60 2.8 262 1536664
+1 0 1 1 81 111 1175 112 75 0.20 0.20 18837 37417 4.40 6.60 6.60 0.80 1.80 1.20 1.20 18.40 82.80 240 89 11
+1 82 1 1 8 2 4089 280 160 2.79 2.79 227209 17217 0.00 0.00 0.00 0.00 0.00 10.78 15.97 172.46 257.88 3.4 1356 1443235
+1 83 1 1 10 0 4261 527 266 1.80 3.00 330811 87989 0.00 0.00 0.00 0.00 0.00 11.80 16.80 190.20 323.20 6.2 2497 1338315
+1 97 1 1 0 0 368 41 34 0.20 0.20 1460 13058 0.80 0.80 0.80 0.00 0.00 1.40 1.40 15.60 17.40 3.0 323 1711816
+1 90 1 1 3 1 714 34 15 2.61 2.81 70079 17335 0.00 0.00 0.00 0.00 0.00 2.00 3.41 206.21 210.22 1.0 11420 1884933
+1 95 1 1 36 47 387 40 42 0.80 0.60 2166 11034 0.00 0.00 0.00 0.00 0.00 0.80 0.80 34.80 45.00 3.0 1551 1718331
+1 85 1 1 3 0 2881 164 361 2.20 4.20 32995 180178 0.00 0.00 0.00 0.00 0.00 2.20 2.60 203.20 223.40 1.6 1258 1055720
+1 57 1 1 9 1 8351 1486 1359 8.18 6.79 1327527 1052853 0.20 0.20 0.20 0.00 0.00 2.00 3.39 326.95 514.77 1.2 509 1092029
+1 91 1 1 10 7 1696 133 109 1.80 2.59 104247 20545 5.19 12.38 19.56 27.54 2.00 1.40 3.39 102.20 162.48 2.4 207 1063586
+1 99 1 1 0 0 470 18 32 0.20 0.20 5392 7117 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6938 1879152
+1 93 1 1 16 14 1384 95 123 0.20 0.20 16407 93892 1.80 8.18 14.17 22.55 0.60 2.00 2.20 42.51 71.26 1.0 662 1069851
+1 85 1 1 22 13 2865 177 161 1.60 5.00 119291 193151 0.00 0.00 0.00 0.00 0.00 4.80 8.00 107.00 178.80 4.0 536 1642779
+1 76 1 1 43 48 5537 438 394 2.40 2.00 304814 237643 0.00 0.00 0.00 0.00 0.00 4.80 4.80 183.80 210.80 4.0 2487 1645728
+1 86 1 1 8 7 4561 204 127 0.20 0.20 68904 64251 1.20 1.80 1.60 0.00 0.20 8.78 10.98 21.36 69.66 2.5 574 1004773
+1 92 1 1 36 54 1470 182 142 0.20 0.20 16784 40472 0.00 0.00 0.00 0.00 0.00 0.20 0.20 16.40 32.60 1.5 648 1120458
+1 84 1 1 16 3 5681 371 174 2.59 2.40 106232 22285 0.20 0.20 0.20 0.00 0.40 1.20 1.20 122.16 219.56 2.0 774 1075843
+1 83 1 1 6 1 4010 486 243 1.60 0.80 433441 19761 0.00 0.00 0.00 0.00 0.20 0.40 0.60 98.20 194.60 5.6 2238 1370315
+1 87 1 1 5 0 1184 110 41 4.80 4.80 134210 80919 0.00 0.00 0.00 0.00 0.00 0.80 1.20 238.20 443.00 3.6 1366 1756885
+1 96 1 1 1 0 1253 47 47 0.40 0.40 29848 18075 1.00 7.20 23.00 37.00 0.00 1.00 1.40 32.40 66.60 3.2 159 1713203
+1 98 1 1 0 0 303 116 30 0.20 0.20 22296 10299 0.00 0.00 0.00 0.00 0.00 3.00 6.00 15.80 16.80 1.0 5245 1856600
+1 87 1 1 7 2 2536 229 184 4.20 1.20 125918 20744 0.00 0.00 0.00 0.00 0.00 0.00 0.00 202.00 287.00 1.4 8331 1864683
+1 84 1 1 17 6 3577 316 238 3.00 1.20 217323 49595 0.00 0.00 0.00 0.00 0.00 5.60 5.80 154.80 263.20 3.6 879 974328
+1 90 1 1 47 36 1401 140 112 1.79 3.17 113759 41443 2.98 11.31 16.07 17.86 2.18 10.71 10.71 160.52 279.96 2.0 269 982138
+1 92 1 1 37 52 2114 213 122 0.40 0.40 51742 61601 10.60 43.80 59.00 79.60 2.20 63.40 67.80 33.20 123.40 3.0 157 1102712
+1 92 1 1 23 7 1277 149 121 1.20 1.80 22772 19460 0.00 0.00 0.00 0.00 0.00 0.00 0.00 79.80 131.40 2.8 670 977107
+1 88 1 1 3 0 917 74 268 0.60 1.20 80639 66461 0.00 0.00 0.00 0.00 0.00 0.40 0.40 58.60 71.20 1.8 1718 1816878
+1 92 1 1 3 0 598 32 29 4.40 3.00 69002 14794 0.00 0.00 0.00 0.00 0.00 0.00 0.00 176.40 278.80 1.2 7715 1880747
+1 78 1 1 14 4 1954 130 114 6.19 17.76 80423 44906 2.79 9.38 18.16 52.30 1.40 10.78 12.97 250.90 481.44 3.0 148 1088251
+1 91 1 1 15 2 2374 132 121 0.40 0.80 30493 41061 11.42 29.26 57.11 164.73 0.40 15.83 26.45 55.11 184.37 3.0 150 1018368
+1 78 1 1 6 1 4009 260 187 2.20 3.40 57483 172118 12.80 28.60 32.40 10.00 1.20 15.40 56.40 150.60 278.00 1.2 255 988248
+1 89 1 1 6 1 1390 78 95 0.20 0.20 30162 17666 2.00 10.20 42.80 98.60 0.00 11.20 40.20 16.00 37.00 1.5 132 1055062
+1 70 1 1 17 8 4051 662 579 6.40 4.00 565623 421622 0.00 0.00 0.00 0.00 0.00 10.00 13.80 298.40 507.60 1.2 756 1117955
+1 88 1 1 20 7 1878 151 75 2.40 2.40 245550 72088 6.60 18.60 85.80 200.40 1.20 3.40 3.80 87.20 228.00 3.2 171 1635587
+1 84 1 1 11 6 3739 243 172 0.60 0.80 112671 124393 0.00 0.00 0.00 0.00 0.00 11.20 14.60 53.20 89.80 2.5 1092 1022466
+1 70 1 1 7 1 2492 255 123 1.80 1.60 1433061 37231 22.00 152.60 364.80 610.80 1.60 27.40 38.40 99.00 563.80 2.5 102 1091614
+1 93 1 1 0 0 1939 108 92 0.20 0.20 11959 114457 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.60 17.00 3.2 545 1643384
+1 80 1 1 8 6 3296 326 204 1.00 1.80 296167 47802 1.00 1.20 1.20 0.00 0.60 32.20 52.80 113.80 221.60 2.0 374 994989
+1 85 1 1 55 84 5106 321 215 0.20 0.20 29564 40148 0.00 0.00 0.00 0.00 0.20 23.55 23.55 20.76 84.43 2.5 1119 981289
+1 90 1 1 30 43 2588 202 132 0.40 0.40 76060 35619 0.00 0.00 0.00 0.00 0.00 1.20 1.20 34.40 41.80 1.0 1484 1113149
+1 97 1 1 3 2 501 94 102 0.20 0.20 56336 70980 9.00 17.20 18.40 15.40 2.80 0.00 0.00 19.20 22.80 2.6 159 1712456
+1 97 1 1 23 34 1857 103 88 0.20 0.20 3525 44989 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 17.00 2.4 3387 1657034
+1 92 1 1 6 2 1456 106 64 0.60 2.20 110222 27276 0.00 0.00 0.00 0.00 0.60 3.40 5.40 65.80 141.60 1.0 356 1021286
+1 83 1 1 49 63 3638 189 170 0.60 1.99 20954 238296 0.00 0.00 0.00 0.00 0.00 17.33 17.73 37.85 86.06 3.2 1215 1389978
+1 93 1 1 0 0 1313 96 42 0.40 2.20 370096 44139 0.00 0.00 0.00 0.00 0.00 0.20 0.40 35.40 36.40 1.4 6675 1825160
+1 92 1 1 22 33 1157 59 50 0.20 0.20 87024 13503 0.00 0.00 0.00 0.00 0.00 0.00 0.00 22.20 17.20 1.6 953 1760301
+1 95 1 1 0 0 1190 71 77 0.20 0.20 3692 88505 1.40 2.00 1.80 0.00 0.00 1.00 1.00 15.60 17.80 3.2 267 1719112
+1 98 1 1 1 1 163 12 12 0.20 0.20 27322 15675 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 2.0 3598 1821480
+1 93 1 1 2 1 2834 164 134 0.20 0.20 120572 50152 0.00 0.00 0.00 0.00 0.00 3.80 7.40 13.00 23.80 3.4 3404 1551894
+1 78 1 1 74 100 4606 831 206 2.79 3.99 1379703 54436 0.40 0.60 0.60 0.00 2.00 3.59 3.79 231.14 405.39 1.0 425 1014860
+1 98 1 1 2 1 444 42 38 0.20 0.20 9668 7034 0.00 0.00 0.00 0.00 0.00 0.60 1.00 15.60 16.80 1.0 5543 1860558
+1 93 1 1 14 21 616 65 60 0.40 1.20 4531 36791 0.00 0.00 0.00 0.00 0.20 1.20 1.20 35.00 53.40 3.4 992 1716653
+1 77 1 1 6 1 2650 190 129 0.60 0.60 121239 67627 4.20 7.80 17.80 41.40 0.40 6.20 8.80 42.40 109.00 4.6 276 1504933
+1 92 1 1 5 1 1139 116 125 3.00 1.80 93344 31653 0.00 0.00 0.00 0.00 0.00 0.00 0.00 165.20 224.00 1.0 7534 1869998
+1 90 1 1 12 11 1150 120 81 1.00 2.40 74466 22798 0.00 0.00 0.00 0.00 0.00 7.60 9.60 108.00 191.00 2.0 895 1016090
+1 94 1 1 4 2 2764 146 145 0.20 0.20 5556 30468 0.00 0.00 0.00 0.00 0.00 0.80 0.80 27.20 34.60 1.6 553 977181
+1 93 1 1 6 2 2361 121 78 0.40 0.40 196740 83650 0.20 0.80 0.40 0.00 0.00 3.40 3.80 30.40 58.20 3.0 2043 988526
+1 86 1 1 22 4 1650 223 205 1.80 1.60 33024 29856 6.60 24.60 75.80 196.20 1.60 20.00 105.80 92.60 167.80 4.5 158 1058141
+1 78 1 1 19 13 2317 340 164 5.60 17.20 946400 24496 0.00 0.00 0.00 0.00 0.00 7.40 9.20 201.00 368.60 3.0 705 1098512
+1 98 1 1 1 1 233 17 36 0.20 0.20 7626 33913 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.97 16.77 1.0 9203 1863840
+1 92 1 1 9 6 1408 147 111 0.80 0.80 94565 20446 0.00 0.00 0.00 0.00 0.00 6.80 6.80 41.20 100.40 1.4 1994 969677
+1 84 1 1 24 19 1059 67 56 3.79 4.19 72920 34992 0.00 0.00 0.00 0.00 0.00 4.59 6.99 231.14 481.04 3.2 635 1019530
+1 81 1 1 9 4 4370 122 115 2.80 8.00 153788 121639 0.00 0.00 0.00 0.00 0.00 0.60 0.60 238.40 294.80 2.6 551 1536366
+1 98 1 1 1 1 353 154 41 0.20 0.20 263443 245749 0.00 0.00 0.00 0.00 0.00 0.40 0.60 15.60 16.80 2.2 5757 1834560
+1 90 1 1 2 1 2080 124 97 0.80 5.39 40902 39442 4.99 12.38 14.97 20.76 0.20 6.19 7.19 41.32 80.24 1.0 172 1026095
+1 88 1 1 29 38 397 45 14 2.20 2.20 82212 8322 0.00 0.00 0.00 0.00 0.00 2.00 2.20 212.77 172.26 1.4 11431 1877507
+1 98 1 1 0 0 162 10 23 0.20 0.20 2817 12502 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7385 1874944
+1 86 1 1 2 0 3953 356 135 0.20 0.40 311951 205296 14.40 27.40 27.20 0.00 0.00 1.00 1.20 102.20 46.00 2.4 762 1547232
+1 94 1 1 3 1 2494 115 124 0.20 0.40 7864 20509 0.20 0.20 0.20 0.00 0.20 1.00 1.00 23.20 32.40 2.0 1095 1719574
+1 98 1 1 1 1 188 10 26 0.20 0.20 3035 26836 0.00 0.00 0.00 0.00 0.00 0.00 0.00 19.76 16.77 1.0 9288 1865677
+1 78 1 1 49 48 4918 402 238 2.39 3.98 202001 157198 10.56 21.71 39.84 86.85 0.80 11.95 20.32 162.55 271.91 3.0 169 1005745
+1 91 1 1 41 56 1349 84 55 1.19 4.97 110507 21563 0.60 0.80 0.80 0.00 2.58 1.19 1.19 68.39 127.44 1.0 181 1018360
+1 91 1 1 18 16 4364 331 233 0.40 2.00 149096 201763 0.00 0.00 0.00 0.00 0.00 7.20 13.00 37.40 56.60 3.4 3910 1340325
+1 86 1 1 84 95 617 100 95 0.20 0.20 22235 94110 13.60 19.80 24.60 20.80 8.40 5.00 13.20 13.00 27.80 2.0 136 1752424
+1 77 1 1 6 1 5226 473 353 4.20 1.20 148787 53090 5.60 8.40 8.00 0.00 0.40 1.80 2.40 201.00 327.40 5.0 233 1136888
+1 93 1 1 4 1 2439 183 114 0.60 0.60 171077 108093 0.00 0.00 0.00 0.00 0.20 0.40 0.40 46.40 83.00 2.4 2113 1539048
+1 87 1 1 38 28 3514 87 70 2.00 2.80 33738 46921 0.00 0.00 0.00 0.00 0.00 0.20 0.20 174.20 183.40 2.2 3372 1657336
+1 97 1 1 35 34 331 58 48 0.20 0.20 22293 29719 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 1812 1763360
+1 96 1 1 21 27 227 25 26 0.20 0.20 7626 4544 0.00 0.00 0.00 0.00 0.00 0.00 0.00 18.76 22.16 1.0 7373 1862322
+1 89 1 1 2 0 2612 226 119 0.40 1.20 166206 51370 0.00 0.00 0.00 0.00 0.00 12.00 12.20 51.20 206.80 4.8 7187 1406219
+1 82 1 1 19 14 3750 288 141 1.80 3.60 236686 96856 0.00 0.00 0.00 0.00 0.20 7.80 11.40 105.80 199.20 1.5 557 1016558
+1 87 1 1 56 86 1426 119 70 0.40 0.40 444790 147764 0.00 0.00 0.00 0.00 0.00 24.80 45.00 31.40 47.00 3.4 1246 1714448
+1 88 1 1 24 21 1833 114 94 0.60 0.40 180856 37117 0.00 0.00 0.00 0.00 0.00 33.40 41.20 75.40 139.80 3.2 6754 1404261
+1 92 1 1 7 2 1474 146 112 0.60 2.80 90868 28777 0.00 0.00 0.00 0.00 0.00 6.20 8.20 40.20 90.20 1.7 1005 1133701
+1 64 1 1 42 9 6663 186 86 7.60 21.80 284749 160378 7.40 8.20 13.40 10.80 7.00 3.80 5.80 546.00 688.80 5.6 198 1538224
+1 79 1 1 7 1 4102 396 179 2.20 6.19 1173991 69739 5.39 19.96 43.11 55.49 0.20 21.56 27.15 119.16 271.06 3.2 141 1079395
+1 89 1 1 2 1 1803 238 58 0.80 2.00 544311 22882 0.00 0.00 0.00 0.00 0.00 0.20 0.20 61.20 259.20 2.6 6500 1823640
+1 95 1 1 36 57 453 42 34 0.60 0.60 27437 19314 0.00 0.00 0.00 0.00 0.00 0.00 0.00 117.60 42.00 2.8 1019 1717410
+1 0 1 1 121 92 2108 256 194 6.80 20.80 377607 105842 9.00 20.80 38.40 48.80 5.60 7.60 12.60 210.40 433.80 184 76 23
+1 94 1 1 6 2 2029 93 83 0.60 0.60 93053 46509 1.60 3.20 3.20 0.00 0.80 0.80 1.20 40.80 89.40 5.0 363 1521069
+1 77 1 1 78 78 3726 204 189 6.40 5.00 163664 109771 6.40 16.40 91.40 142.60 0.40 4.40 5.00 270.60 503.40 1.0 158 1072146
+1 80 1 1 27 18 3714 220 99 2.80 7.00 460247 29730 2.00 17.60 44.00 96.20 0.00 50.80 84.80 175.80 274.20 3.7 265 1021035
+1 76 1 1 33 3 3388 493 263 3.80 5.20 402655 354612 1.80 8.40 22.20 59.40 1.00 0.20 0.20 516.60 415.40 2.0 132 1119445
+1 83 1 1 3 1 3167 348 163 1.40 1.40 91118 37133 2.80 13.60 38.40 56.00 1.60 5.00 8.20 112.20 191.40 2.0 157 1099906
+1 93 1 1 0 0 195 42 23 0.00 0.00 10043 15587 0.00 0.00 0.00 0.00 0.00 0.00 0.00 4.40 3.80 1.4 1387 1753355
+1 91 1 1 4 0 2176 371 139 0.60 0.80 655593 48384 0.80 1.40 1.40 0.00 4.41 23.65 24.65 61.92 116.23 1.8 571 1063064
+1 92 1 1 6 0 2623 112 112 2.20 0.80 105701 61083 1.00 1.00 2.80 5.40 0.00 4.80 9.20 110.80 183.80 2.4 169 1626877
+1 0 1 1 7 2 1251 129 91 0.60 0.80 100872 17439 1.00 1.00 8.82 12.22 18.84 1.60 1.80 46.69 86.37 134 93 7
+1 94 1 1 3 1 1395 113 60 0.80 1.40 92509 18384 0.00 0.00 0.00 0.00 0.00 0.80 1.20 82.60 111.60 3.0 812 1067821
+1 83 1 1 7 2 3244 182 137 1.00 5.80 130854 23562 1.80 2.80 2.40 0.00 2.00 4.40 5.80 46.20 79.80 5.6 217 1309640
+1 88 1 1 127 51 1934 207 198 0.60 0.80 125735 166302 0.00 0.00 0.00 0.00 0.00 2.80 4.20 57.20 74.80 1.0 1015 1009613
+1 94 1 1 1 0 1295 124 122 0.20 0.20 2544 19444 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.57 33.93 2.7 635 1101223
+1 88 1 1 21 10 3862 239 266 2.40 2.40 111286 94229 1.40 12.80 8.40 0.80 4.80 17.80 22.20 96.80 223.80 7.2 343 1310246
+1 77 1 1 8 0 3193 442 385 8.02 2.00 278616 17581 0.00 0.00 0.00 0.00 0.00 0.00 0.00 388.38 552.71 2.0 7216 1866756
+1 83 1 1 3 0 3473 132 137 0.60 0.60 9715 26776 10.22 20.24 20.24 0.00 1.00 78.16 92.18 51.70 267.74 5.2 370 1021517
+1 82 1 1 4 1 720 104 58 3.00 10.00 428343 242223 0.00 0.00 0.00 0.00 41.80 7.80 13.20 155.40 226.00 3.8 3709 1807547
+1 98 1 1 0 0 156 9 17 0.20 0.20 2056 2898 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6472 1871632
+1 89 1 1 4 2 1819 118 223 0.20 0.20 111430 579085 0.00 0.00 0.00 0.00 0.00 8.20 9.00 15.60 47.40 1.8 1520 1041522
+1 81 1 1 10 1 3579 745 751 3.00 3.00 619936 638238 0.00 0.00 0.00 0.00 0.00 1.20 1.40 159.80 255.80 2.2 636 1059296
+1 96 1 1 2 0 1962 118 103 1.00 1.00 42992 11098 0.00 0.00 0.00 0.00 0.00 0.40 0.40 80.80 108.20 3.2 1212 1723749
+1 89 1 1 6 2 1046 98 40 3.00 12.40 66120 22817 3.80 4.00 3.80 0.00 1.20 1.20 1.40 176.00 251.40 1.0 198 1036710
+1 82 1 1 89 104 2799 177 127 1.80 1.60 251073 47060 0.00 0.00 0.00 0.00 0.00 3.99 5.59 104.39 165.87 2.8 3792 1767829
+1 92 1 1 16 12 3007 178 134 0.60 0.60 39887 66967 0.80 0.80 0.80 0.00 2.00 1.20 1.80 63.40 78.40 2.4 361 1628362
+1 97 1 1 0 0 750 76 69 0.20 0.20 49826 50394 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 1.0 572 1752952
+1 93 1 1 4 0 1134 102 19 2.20 2.60 291175 13298 0.00 0.00 0.00 0.00 0.00 0.80 1.00 155.20 220.20 1.6 7226 1876670
+1 0 1 1 14 7 1443 221 109 1.79 5.57 716801 563258 0.00 0.00 0.00 0.00 98.61 4.37 6.16 117.10 313.72 2390 84 16
+1 91 1 1 36 47 345 26 20 1.80 1.80 51659 26403 0.00 0.00 0.00 0.00 0.00 2.20 3.60 159.20 144.60 1.2 8807 1871341
+1 93 1 1 5 2 1809 75 29 2.20 6.40 72824 7166 0.00 0.00 0.00 0.00 0.00 1.20 1.40 164.40 206.40 1.2 4894 1827627
+1 97 1 1 3 1 411 53 16 1.20 4.60 294255 7831 0.00 0.00 0.00 0.00 1.20 0.20 0.20 79.60 96.40 2.2 3741 1821334
+1 89 1 1 1 0 5527 192 147 0.20 0.20 265066 88570 4.78 9.56 25.10 58.37 3.19 12.75 20.52 16.14 138.45 1.5 126 1010410
+1 97 1 1 0 0 194 25 24 0.20 0.20 616 9071 0.00 0.00 0.00 0.00 0.00 0.80 0.80 15.60 16.80 1.0 1363 1761824
+1 89 1 1 16 15 1984 157 90 1.40 3.41 57962 43602 0.00 0.00 0.00 0.00 0.00 0.60 2.40 132.67 249.30 2.3 1121 1084952
+1 97 1 1 1 1 394 208 51 0.20 0.20 379080 332905 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.6 5746 1834560
+1 88 1 1 3 1 650 83 43 2.20 2.20 317214 129335 0.00 0.00 0.00 0.00 0.00 1.60 1.60 200.80 168.60 1.6 5350 1840486
+1 90 1 1 7 1 3253 265 138 2.00 1.80 220922 120526 0.00 0.00 0.00 0.00 0.00 1.40 1.60 96.00 164.00 4.8 1562 1334029
+1 83 1 1 19 16 3002 194 123 1.80 2.20 300654 71750 0.00 0.00 0.00 0.00 0.00 5.80 7.60 99.80 288.20 2.4 1202 1014886
+1 90 1 1 12 1 3220 146 141 1.80 4.40 124696 61614 0.00 0.00 0.00 0.00 0.20 11.80 12.60 128.40 225.60 4.4 508 1445163
+1 94 1 1 1 0 781 60 64 1.00 2.00 8478 16249 0.00 0.00 0.00 0.00 0.20 0.20 0.20 63.40 86.80 1.5 2160 1072765
+1 97 1 1 17 25 226 27 31 0.20 0.20 94831 27476 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 19.00 1.0 7369 1874573
+1 84 1 1 14 1 1923 403 314 1.80 4.00 522927 132931 0.00 0.00 0.00 0.00 0.60 8.40 16.80 124.20 160.60 3.4 514 1698622
+1 70 1 1 14 8 3941 337 187 5.80 14.60 241200 167242 20.20 37.60 37.60 0.00 6.40 9.00 13.00 209.60 378.60 1.0 248 1103957
+1 66 1 1 56 64 3893 332 238 1.40 1.60 536029 449132 12.42 65.13 283.97 524.45 0.80 62.73 114.83 118.64 362.53 3.0 150 1035609
+1 96 1 1 17 26 247 23 35 0.20 0.20 89718 18693 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 7199 1874051
+1 85 1 1 7 1 1030 100 37 4.00 4.00 112364 17402 0.00 0.00 0.00 0.00 0.00 5.60 7.20 259.40 313.00 2.2 8514 1834352
+1 89 1 1 42 53 2608 235 148 1.40 0.60 108359 42599 0.00 0.00 0.00 0.00 0.60 1.20 1.20 84.40 157.20 1.0 615 1076654
+1 96 1 1 1 0 993 51 39 0.60 0.60 7421 6898 0.60 0.60 3.40 7.40 0.20 0.60 0.60 29.00 39.20 3.0 162 1709936
+1 98 1 1 5 4 675 46 36 0.20 0.20 4594 17850 0.00 0.00 0.00 0.00 0.00 0.60 2.00 21.20 22.80 4.0 614 970677
+1 83 1 1 47 63 2769 338 192 1.59 0.99 850333 491906 0.00 0.00 0.00 0.00 0.00 4.37 8.35 103.58 175.35 4.2 3581 1031852
+1 97 1 1 1 0 600 37 40 0.20 0.20 4767 19880 0.80 0.80 0.80 0.00 0.00 0.40 0.60 15.83 23.45 1.5 289 1018485
+1 81 1 1 5 1 5492 267 175 1.00 1.39 249419 36634 0.00 0.00 0.00 0.00 0.60 5.38 6.37 85.46 135.66 1.0 548 1017288
+1 85 1 1 80 101 1408 227 147 1.00 2.40 16443 20863 23.65 69.74 90.98 104.41 1.60 57.52 103.21 86.77 177.56 3.0 144 990772
+1 92 1 1 18 27 2223 139 73 0.60 0.60 90472 59143 0.00 0.00 0.00 0.00 0.00 12.00 12.00 28.20 56.20 2.4 4710 1731314
+1 91 1 1 1 0 2678 165 134 0.20 0.20 7384 66002 0.00 0.00 0.00 0.00 0.00 8.20 10.60 16.00 25.80 2.0 1834 1112656
+1 84 1 1 7 0 1512 276 116 4.20 2.60 1313197 44146 2.00 3.80 3.80 0.00 2.00 1.40 1.80 257.00 307.60 6.0 338 1700651
+1 58 1 1 164 18 4432 573 222 5.99 8.58 386448 38136 38.12 92.42 222.16 397.60 3.99 27.15 29.74 416.77 840.72 2.2 132 972691
+1 74 1 1 10 1 5406 252 156 5.00 18.40 145463 50994 14.20 20.00 38.40 75.60 1.60 4.40 5.00 339.40 463.80 1.0 183 1022437
+1 88 1 1 29 37 1786 175 175 1.80 1.00 64650 70255 0.00 0.00 0.00 0.00 0.00 1.20 1.20 101.20 254.89 2.0 629 1101022
+1 0 1 1 17 14 1128 429 142 0.40 0.40 818219 590202 0.00 0.00 0.00 0.00 0.00 0.40 0.40 36.20 73.00 480 93 7
+1 84 1 1 44 59 5763 262 205 0.40 0.40 152480 57054 1.60 2.40 13.20 25.00 0.00 9.80 12.00 37.00 155.60 1.5 142 1071472
+1 83 1 1 12 3 2805 544 146 1.20 2.20 279920 329100 34.00 64.00 63.60 0.00 1.20 8.20 9.40 175.60 158.80 3.0 286 1547198
+1 93 1 1 3 0 1234 205 115 0.40 2.20 123824 135757 1.20 1.20 1.20 0.00 0.00 4.20 8.20 92.60 90.40 2.4 263 1536757
+1 92 1 1 7 2 1150 111 119 0.80 0.80 52028 122409 0.00 0.00 0.00 0.00 2.20 2.60 4.80 91.80 134.80 1.0 407 1062686
+1 91 1 1 4 3 1370 94 118 0.80 1.00 25625 99074 0.00 0.00 0.00 0.00 1.80 1.60 1.60 70.20 101.80 1.0 418 1113077
+1 82 1 1 16 0 3074 259 203 1.60 4.60 537108 100961 0.00 0.00 0.00 0.00 0.40 26.60 37.80 81.80 288.60 6.6 671 1308418
+1 96 1 1 28 36 1326 75 50 0.40 2.00 84961 36739 0.00 0.00 0.00 0.00 0.00 0.80 1.60 20.20 26.20 2.0 4667 1732315
+1 94 1 1 3 2 712 73 58 0.20 0.20 18641 64419 0.00 0.00 0.00 0.00 0.00 1.60 1.80 17.17 33.93 1.5 613 1016112
+1 75 1 1 37 41 2235 172 114 6.20 20.00 95632 32410 4.00 13.40 25.20 52.20 1.40 13.80 21.60 228.60 411.20 2.3 159 1107842
+1 92 1 1 17 4 1910 131 91 1.80 2.00 113894 28026 0.00 0.00 0.00 0.00 0.00 0.00 0.00 108.60 147.80 1.4 7696 1871554
+1 70 1 1 6 2 2948 224 203 3.19 3.59 428831 387601 23.55 122.75 216.17 350.10 1.60 71.66 119.16 165.67 339.12 2.0 115 1082453
+1 99 1 1 0 0 266 19 43 0.20 0.20 4582 15903 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 1.2 7293 1875112
+1 94 1 1 1 0 2263 91 84 0.20 0.20 100381 33249 1.80 2.40 2.40 0.00 0.40 1.00 1.00 15.40 23.20 1.2 161 1751042
+1 92 1 1 0 0 3657 230 131 0.40 0.60 350733 241407 0.00 0.00 0.00 0.00 0.00 1.00 1.00 35.20 46.60 5.4 1594 1615850
+1 80 1 1 12 8 1444 134 84 0.60 2.40 510385 191128 0.00 0.00 0.00 0.00 0.00 21.60 42.40 82.40 90.20 4.0 529 1512083
+1 85 1 1 7 1 1071 50 60 6.20 9.60 27162 193369 0.00 0.00 0.00 0.00 0.00 2.60 2.60 187.00 389.00 1.8 6829 1852869
+1 95 1 1 4 1 824 136 58 0.20 0.20 27980 39647 0.00 0.00 0.00 0.00 0.20 0.60 0.60 15.60 49.20 2.0 5856 1690960
+1 84 1 1 5 1 3741 852 265 0.40 0.40 377071 88331 3.80 24.80 62.20 471.20 0.20 25.20 47.00 26.00 127.00 1.0 121 1043038
+1 96 1 1 1 0 382 57 51 0.20 0.20 8498 20401 0.00 0.00 0.00 0.00 0.00 0.40 0.40 20.20 16.80 3.6 1498 1717632
+1 92 1 1 2 0 2727 167 149 0.80 1.00 748996 23904 2.40 2.60 2.60 0.00 0.60 0.00 0.00 50.20 69.60 2.8 257 1708933
+1 98 1 1 1 1 235 19 25 0.20 0.20 7848 12733 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 7478 1873331
+1 95 1 1 3 1 663 81 96 1.80 0.60 62398 53313 0.00 0.00 0.00 0.00 0.00 0.20 0.20 87.00 125.00 1.0 7348 1874123
+1 89 1 1 1 0 2054 344 308 0.60 3.60 10011 57033 0.40 0.40 0.40 0.00 0.00 0.40 0.60 23.60 36.80 2.6 231 1696379
+1 81 1 1 1 0 4123 257 213 0.20 1.00 607636 329374 11.98 23.95 23.95 0.00 0.00 2.79 2.99 31.74 78.84 5.2 311 1003229
+1 91 1 1 3 2 743 111 64 0.60 1.20 529504 300696 0.00 0.00 0.00 0.00 0.00 5.40 8.60 44.20 89.40 2.6 3672 1811698
+1 89 1 1 0 0 2273 73 68 0.20 0.20 2262 8296 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 4115 1776888
+1 84 1 1 18 0 3762 154 114 4.79 2.99 23933 35077 6.19 15.57 42.91 80.04 1.40 11.78 16.57 292.42 377.25 1.8 224 1065365
+1 93 1 1 8 5 1028 134 141 1.00 0.60 39910 46082 0.00 0.00 0.00 0.00 0.20 5.99 6.19 62.87 130.74 5.0 548 973145
+1 97 1 1 1 1 1597 100 92 0.60 0.60 6122 38458 0.00 0.00 0.00 0.00 0.00 0.00 0.00 35.67 44.29 1.0 362 1752271
+1 95 1 1 1 1 2078 94 97 0.40 0.40 30254 10055 0.20 0.20 0.20 0.00 0.00 1.00 1.40 23.80 40.00 2.2 313 1716179
+1 73 1 1 4 1 1881 179 137 3.40 4.60 239378 64562 0.60 1.20 4.00 6.40 1.40 99.20 141.60 187.00 609.20 1.6 1793 952803
+1 95 1 1 2 1 483 36 65 0.80 0.60 10690 12182 0.00 0.00 0.00 0.00 0.00 0.00 0.00 52.20 59.20 1.2 7716 1871514
+1 88 1 1 3 0 1049 361 58 0.60 0.60 127562 12466 0.00 0.00 0.00 0.00 0.00 3.00 3.40 65.60 200.40 2.2 2165 1767824
+1 84 1 1 4 1 572 74 30 2.60 2.60 273984 39153 0.00 0.00 0.00 0.00 0.00 2.40 4.40 227.60 294.40 2.4 11040 1872051
+1 81 1 1 15 4 3019 283 157 2.00 2.20 600466 122565 21.00 26.00 33.20 31.40 18.20 14.40 17.80 103.20 248.20 1.4 209 989965
+1 84 1 1 3 0 3089 254 282 0.80 0.60 708020 413212 0.00 0.00 4.60 17.40 0.00 44.80 89.40 42.60 70.80 2.4 473 1644789
+1 97 1 1 21 28 440 32 22 0.20 0.20 1015 10645 0.60 0.60 0.60 0.00 0.40 0.40 0.40 16.40 17.40 3.0 318 1711758
+1 84 1 1 13 11 4427 270 183 1.60 3.20 172031 118129 5.00 18.60 34.80 56.00 1.40 10.40 17.40 90.40 180.20 1.3 154 998984
+1 91 1 1 35 50 2068 111 82 0.60 0.60 184724 37429 6.40 8.40 7.80 0.00 6.40 13.00 13.40 51.60 116.60 2.4 219 1085546
+1 91 1 1 3 1 2836 208 129 1.00 1.40 113354 27649 1.20 2.20 2.20 0.00 4.39 6.19 8.18 78.04 90.02 1.0 652 1064578
+1 95 1 1 2 1 313 33 28 0.60 0.60 172272 26701 0.00 0.00 0.00 0.00 0.00 0.00 0.00 32.87 44.09 1.4 6748 1865980
+1 84 1 1 3 2 6211 313 209 0.40 1.80 52583 211119 0.40 1.40 1.00 0.00 0.60 0.80 0.80 31.40 64.80 2.0 412 1013259
+1 96 1 1 0 0 280 53 21 0.40 0.20 350133 31449 0.00 0.00 0.00 0.00 0.00 0.20 0.20 37.80 46.60 2.6 3629 1821069
+1 87 1 1 3 1 751 105 27 2.40 2.00 209142 62416 0.00 0.00 0.00 0.00 0.00 15.20 29.40 186.40 165.60 1.4 6152 1848914
+1 78 1 1 23 4 3124 386 348 7.62 5.81 303675 195796 7.01 13.83 32.67 43.69 1.60 14.23 28.46 226.05 390.58 3.0 152 1045831
+1 91 1 1 7 4 3722 160 135 0.80 0.80 21245 32319 1.80 3.40 4.60 6.00 1.20 1.20 1.40 46.40 173.00 1.5 160 968381
+1 92 1 1 11 9 2064 86 67 1.80 4.80 34707 24636 1.00 1.20 1.20 0.00 0.00 2.20 2.20 132.80 204.40 2.7 215 989568
+1 91 1 1 3 0 652 28 18 2.40 2.60 66019 31317 0.00 0.00 0.00 0.00 0.00 4.00 7.20 208.20 206.40 1.0 8885 1871976
+1 87 1 1 3 1 1039 237 123 1.20 1.60 493948 152437 0.00 0.00 0.00 0.00 0.00 9.00 17.40 96.80 116.80 1.2 3462 1741133
+1 0 1 1 14 5 2150 332 247 2.60 0.80 432353 269208 23.00 59.40 134.80 268.80 0.80 19.60 31.40 133.00 353.60 395 81 19
+1 90 1 1 3 0 3051 157 115 0.60 0.80 306491 69347 0.00 0.00 0.00 0.00 0.00 20.20 20.60 46.40 101.00 4.2 3108 1539470
+1 85 1 1 11 1 3310 334 243 3.61 2.00 86931 55259 0.20 0.20 0.20 0.00 0.00 7.82 8.22 187.78 314.03 1.0 241 1059974
+1 0 1 1 7 4 2073 275 102 0.40 1.20 509927 61318 24.80 85.40 206.80 392.20 0.20 58.60 114.60 25.80 253.80 245 75 25
+1 78 1 1 3 2 4156 448 230 1.00 2.00 275661 116795 15.17 48.50 86.83 203.79 4.39 20.36 27.54 82.24 236.73 1.0 158 1121726
+1 91 1 1 45 61 1383 155 93 1.00 1.20 11530 33475 2.20 3.80 4.20 1.20 0.40 0.40 0.40 69.40 107.20 2.6 166 1059021
+1 93 1 1 8 0 2505 197 113 2.40 2.40 282389 111390 1.40 1.40 1.40 0.00 4.00 1.80 2.20 81.60 174.40 4.4 190 1322947
+1 87 1 1 5 0 1894 220 173 3.40 1.00 164014 22150 0.60 0.60 0.60 0.00 2.20 1.00 1.40 177.00 333.00 1.0 190 1026021
+1 96 1 1 2 1 823 62 45 0.40 0.40 89883 10946 0.00 0.00 0.00 0.00 0.00 0.20 0.40 40.48 42.48 1.2 957 1746548
+1 96 1 1 4 2 945 92 92 0.20 0.20 116107 76904 0.00 0.00 0.00 0.00 0.00 0.00 0.00 18.60 58.00 2.2 1454 1546534
+1 95 1 1 2 1 1962 109 81 0.60 0.40 362384 25518 0.00 0.00 0.00 0.00 0.00 0.80 1.60 50.40 75.40 1.4 1226 1058715
+1 70 1 1 9 6 2956 229 131 2.00 2.00 1032179 232843 25.15 76.25 162.67 383.63 1.20 114.17 224.35 208.58 277.64 2.0 135 983981
+1 77 1 1 10 1 1668 135 109 7.82 21.24 62480 37958 0.00 0.00 0.00 0.00 0.80 10.42 10.62 293.79 505.81 2.3 514 1084282
+1 89 1 1 12 1 2687 132 162 1.60 2.20 101289 34127 0.00 0.00 0.00 0.00 1.00 2.60 2.60 134.40 183.60 1.5 452 1059963
+1 96 1 1 2 1 534 110 50 1.00 0.40 450000 9302 0.00 0.00 0.00 0.00 0.00 0.00 0.00 52.40 72.40 1.6 6789 1840803
+1 93 1 1 3 1 363 32 28 1.60 1.60 53787 31694 0.00 0.00 0.00 0.00 0.00 1.40 2.00 139.92 125.75 1.0 11943 1884942
+1 78 1 1 5 1 5290 300 320 0.00 0.20 214690 646119 4.21 6.01 5.81 0.00 0.80 14.43 26.65 20.64 51.30 2.0 302 985582
+1 90 1 1 13 7 2844 180 160 1.00 0.40 27538 25232 0.00 0.00 0.00 0.00 0.00 5.00 12.40 74.80 96.00 2.0 2404 974149
+1 90 1 1 2 0 2277 207 92 1.20 1.60 84870 52712 9.20 13.60 13.60 0.00 6.40 4.20 4.40 71.60 199.80 2.0 280 1056816
+1 92 1 1 1 0 1616 156 60 0.80 0.80 78137 43494 0.00 0.00 0.00 0.00 0.00 0.00 0.00 55.00 87.40 1.2 375 1753667
+1 94 1 1 4 0 840 52 39 0.80 1.60 16329 16867 0.80 1.00 1.00 0.00 0.00 0.60 0.80 45.91 57.29 1.2 367 1014170
+1 91 1 1 1 1 1533 131 178 0.20 0.20 270299 208321 0.00 0.00 0.00 0.00 0.20 3.40 5.40 24.80 20.00 2.0 464 1045766
+1 94 1 1 2 1 1922 108 60 0.60 0.40 302647 12972 0.00 0.00 0.00 0.00 0.00 0.40 0.80 52.00 73.60 1.6 1014 1743666
+1 91 1 1 3 1 487 57 30 1.80 1.80 61441 17508 0.00 0.00 0.00 0.00 0.00 4.00 6.80 173.60 149.40 1.2 8318 1834110
+1 87 1 1 5 0 2500 251 347 3.40 1.00 97385 28939 0.00 0.00 0.00 0.00 0.20 0.00 0.00 168.40 243.80 3.4 2016 1719568
+1 89 1 1 3 1 3144 224 161 1.00 0.80 262412 28163 0.00 0.00 0.00 0.00 0.40 4.20 6.20 88.00 107.40 2.2 646 1054936
+1 89 1 1 27 25 1365 61 45 1.40 1.60 23523 5039 0.00 0.00 0.00 0.00 0.00 0.60 0.80 84.60 115.60 2.0 3765 1774579
+1 84 1 1 8 1 2455 358 328 6.40 1.80 187112 16175 0.00 0.00 0.00 0.00 0.00 0.20 0.20 308.60 447.60 3.2 6117 1852827
+1 0 1 1 24 18 3457 401 226 1.00 0.80 137036 87730 6.99 12.38 16.37 20.76 4.99 4.39 7.19 54.09 157.49 222 84 16
+1 97 1 1 1 1 194 15 23 0.20 0.20 585 16000 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 3.0 579 1710640
+1 89 1 1 16 5 2225 154 149 3.20 1.00 97741 8806 0.00 0.00 0.00 0.00 0.00 0.40 0.40 141.00 218.80 1.0 4318 1823917
+1 90 1 1 7 1 2041 114 70 1.80 1.80 213673 25915 1.40 1.40 1.40 0.00 1.60 4.60 6.40 93.00 176.40 1.8 242 1076898
+1 95 1 1 3 1 860 141 69 0.80 0.80 146075 148050 0.00 0.00 0.00 0.00 0.00 0.20 0.20 45.20 59.40 4.0 828 1746520
+1 88 1 1 3 0 2015 204 75 1.00 1.20 283228 16189 4.20 14.40 90.00 140.00 0.00 17.80 32.80 65.40 151.80 1.7 125 1064920
+1 78 1 1 28 19 2613 325 161 7.20 5.40 70661 96586 0.00 0.00 0.00 0.00 0.00 3.00 3.40 317.00 600.40 1.5 994 1007877
+1 93 1 1 2 0 1975 207 156 0.40 1.60 7621 71396 7.60 11.60 14.00 39.20 0.00 6.20 6.20 21.60 60.80 1.7 188 1064462
+1 88 1 1 50 71 3455 355 202 0.80 0.80 103830 53977 0.00 0.00 0.00 0.00 0.20 2.00 2.40 48.00 80.60 2.4 646 1516422
+1 63 1 1 49 34 3932 302 148 9.16 20.52 706527 105716 17.93 78.49 103.98 238.25 2.39 29.88 32.47 456.57 964.34 3.0 170 1088679
+1 83 1 1 2 1 4242 319 121 0.80 0.60 1392751 146008 0.00 0.00 0.00 0.00 0.00 2.80 2.80 58.60 397.20 2.8 2826 1407747
+1 91 1 1 7 3 1360 115 99 2.40 3.40 80145 22427 0.00 0.00 0.00 0.00 0.00 2.40 3.40 128.80 161.00 1.8 495 1046338
+1 93 1 1 4 1 809 99 91 2.00 0.80 63513 61487 0.00 0.00 0.00 0.00 0.00 0.00 0.00 111.00 155.80 1.2 7583 1865490
+1 97 1 1 2 1 254 22 17 0.40 1.60 92792 26468 0.00 0.00 0.00 0.00 0.00 0.20 0.20 20.00 24.80 2.0 3774 1821341
+1 95 1 1 6 3 2148 175 101 0.60 0.60 27775 63949 0.00 0.00 0.00 0.00 0.00 0.00 0.00 66.20 61.00 2.2 1902 1547744
+1 93 1 1 38 56 1193 88 85 0.20 0.20 6800 23963 0.00 0.00 0.00 0.00 0.00 0.60 0.60 16.20 49.20 2.6 765 1131310
+1 76 1 1 2 1 5919 314 357 1.20 1.20 262742 668483 1.79 1.99 1.99 0.00 0.60 10.36 18.92 71.12 118.13 2.0 283 980139
+1 87 1 1 4 2 2129 169 184 1.20 2.60 220260 280690 0.00 0.00 0.00 0.00 0.00 6.00 7.00 185.40 169.80 5.0 1332 1613035
+1 92 1 1 5 5 1958 262 135 0.20 0.20 772197 709935 0.00 0.00 0.00 0.00 0.00 8.20 16.00 15.80 45.40 3.2 3411 1036616
+1 85 1 1 35 50 2797 323 269 0.20 0.20 192178 238685 0.00 0.00 0.00 0.00 0.00 0.60 2.80 29.80 36.60 3.0 2121 1046506
+1 88 1 1 21 24 371 23 34 0.80 0.80 33625 42048 0.00 0.00 0.00 0.00 0.00 5.38 6.18 47.01 79.48 1.0 1957 1766228
+1 82 1 1 8 1 4069 282 257 2.99 2.59 152071 227909 2.79 5.19 7.58 11.38 1.80 3.79 5.59 282.44 387.82 1.0 151 996252
+1 96 1 1 1 1 295 34 34 0.80 0.80 104999 14568 0.00 0.00 0.00 0.00 0.00 0.60 0.60 53.80 61.20 2.2 4578 1846795
+1 98 1 1 2 1 205 11 24 0.40 2.60 7354 21644 0.00 0.00 0.00 0.00 0.00 0.00 0.00 37.60 27.60 1.2 7382 1875762
+1 96 1 1 2 1 1804 90 94 0.40 1.80 31422 86746 0.80 0.80 0.80 0.00 0.00 1.80 1.80 34.00 46.80 4.6 2120 988291
+1 79 1 1 64 66 2938 167 91 5.01 13.03 259358 47170 3.21 3.61 3.61 0.00 1.80 5.81 5.81 178.16 381.56 3.2 223 1087484
+1 74 1 1 28 3 4965 359 201 7.60 8.20 516710 71332 1.00 7.00 10.60 35.20 1.40 5.60 9.00 416.00 703.80 5.4 364 1395704
+1 96 1 1 1 1 694 30 35 0.60 1.00 7099 110246 0.00 0.00 0.00 0.00 0.00 0.00 0.00 50.90 51.70 1.2 6825 1849464
+1 77 1 1 58 73 4483 795 436 1.40 2.80 124437 16244 0.60 0.60 0.60 0.00 0.40 0.40 0.80 157.80 189.40 3.8 373 1536698
+1 86 1 1 3 0 1960 164 105 0.60 0.80 186247 42768 7.19 26.55 49.30 92.22 1.20 45.71 48.90 51.50 113.77 3.8 136 1104960
+1 98 1 1 0 0 200 31 21 0.20 0.20 21262 5539 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 1.0 6934 1845040
+1 88 1 1 17 12 3647 405 211 0.40 0.60 143002 79976 6.80 21.00 56.40 108.20 0.20 10.40 21.80 49.60 106.60 3.0 151 999584
+1 72 1 1 21 9 5903 165 114 3.20 10.40 70199 59637 0.00 0.00 0.00 0.00 0.00 8.20 8.80 277.20 342.20 4.6 6628 1409661
+1 92 1 1 1 0 3516 251 138 0.20 0.20 219873 204131 0.00 0.00 0.00 0.00 0.00 4.80 5.80 23.20 49.20 3.6 4032 1344037
+1 95 1 1 1 0 1222 67 113 0.40 0.40 12403 35778 0.00 0.00 0.00 0.00 0.00 3.00 3.40 30.80 73.40 1.0 387 1059570
+1 91 1 1 4 2 2106 213 124 1.40 2.80 17914 23884 0.00 0.00 0.00 0.00 0.00 1.60 2.00 92.80 123.60 2.0 999 1128026
+1 81 1 1 6 1 2214 308 213 3.61 5.01 918058 137988 5.01 9.22 18.44 58.92 0.40 27.05 52.51 158.12 321.84 1.0 281 1038023
+1 86 1 1 49 64 2339 224 77 2.60 3.00 221330 25672 3.60 25.40 47.00 86.20 2.60 2.40 2.60 200.80 292.60 2.6 160 1107094
+1 74 1 1 19 7 6892 355 202 2.20 8.80 172921 81519 0.00 0.00 0.00 0.00 0.00 1.80 3.40 202.00 205.60 4.2 943 1631170
+1 65 1 1 48 1 3221 243 128 10.80 31.00 562196 29018 0.80 1.00 1.00 0.00 0.00 4.80 5.20 358.60 667.60 3.5 285 1089582
+1 87 1 1 21 12 2619 442 199 1.20 1.20 546478 130566 6.40 21.20 37.40 41.20 4.00 6.40 10.40 96.00 244.00 4.8 218 1540139
+1 98 1 1 11 16 136 10 19 0.20 0.20 426 14960 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.0 8504 1862603
+1 83 1 1 25 18 2182 499 165 1.20 2.60 929960 613173 3.80 25.60 63.00 131.40 1.20 38.20 94.20 120.00 244.40 2.6 240 1032798
+1 82 1 1 8 1 2685 221 82 3.79 5.19 242335 67322 1.80 5.99 41.92 68.46 0.20 18.76 27.54 235.73 432.34 1.0 99 1064798
+1 92 1 1 4 0 943 132 122 2.40 0.80 64603 15178 0.00 0.00 0.00 0.00 0.00 0.00 0.00 126.60 176.40 2.0 7658 1879286
+1 89 1 1 2 0 453 43 36 2.20 2.20 136424 57700 0.00 0.00 0.00 0.00 0.00 1.80 3.20 170.20 169.20 2.0 6264 1853056
+1 0 1 1 2 0 1508 389 229 0.40 0.60 635277 571460 0.00 0.00 0.00 0.00 4.41 2.81 2.81 49.30 117.84 413 91 9
+1 88 1 1 5 0 3971 326 209 1.80 0.80 416863 78149 1.00 7.80 21.60 32.60 1.60 13.80 13.80 93.80 242.80 6.4 311 1316141
+1 94 1 1 2 0 1119 83 53 0.80 1.40 27734 18778 0.60 1.20 1.20 0.00 2.40 0.20 0.20 90.62 103.39 1.3 665 1064901
+1 97 1 1 1 1 246 44 26 0.20 0.20 23591 9714 0.00 0.00 0.00 0.00 0.00 0.80 0.80 15.60 21.20 1.2 8312 1835272
+1 84 1 1 1 0 3894 274 146 0.20 0.20 260849 109891 10.20 48.60 72.00 167.60 0.00 26.60 46.40 25.00 91.00 3.0 148 1029790
+1 88 1 1 3 2 1721 202 219 2.00 2.00 44461 264825 0.00 0.00 0.00 0.00 0.00 1.80 1.80 139.60 170.80 2.2 757 1381216
+1 90 1 1 9 2 2004 131 96 1.60 1.60 203406 80867 0.00 0.00 0.00 0.00 0.20 1.40 1.40 103.00 174.00 2.6 1017 1539797
+1 96 1 1 1 0 1160 161 66 0.20 0.20 166384 133012 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.40 3.0 1031 1753680
+1 97 1 1 1 0 304 33 19 0.80 3.20 65141 6647 0.00 0.00 0.00 0.00 0.20 0.00 0.00 39.20 62.00 2.0 606 1760822
+1 60 1 1 26 13 6511 707 426 8.20 15.60 347219 141663 4.20 8.60 23.40 51.40 1.20 13.60 19.00 478.00 658.80 1.7 185 1092566
+1 96 1 1 13 19 746 39 19 0.20 0.20 107834 10108 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.00 21.00 1.4 553 1752816
+1 93 1 1 2 0 2037 159 120 0.40 0.40 133558 48781 0.00 0.00 0.00 0.00 0.00 2.40 3.81 34.47 61.12 3.8 432 1064513
+1 97 1 1 1 0 1925 88 96 0.20 0.20 3715 12124 0.00 0.00 0.00 0.00 0.00 0.40 0.40 13.00 16.80 2.0 1414 1725048
+1 98 1 1 2 1 200 14 17 0.40 0.40 790 7577 0.00 0.00 0.00 0.00 0.00 0.00 0.00 29.60 39.40 1.0 7314 1864000
+1 91 1 1 2 0 3174 430 189 0.40 1.40 258274 192465 3.00 4.20 4.20 0.00 0.60 5.40 9.60 32.60 78.40 4.4 239 1539834
+1 90 1 1 6 1 3382 153 140 0.80 2.20 69020 50599 0.00 0.00 0.00 0.00 0.20 5.40 5.40 81.00 142.80 3.8 2853 1533090
+1 68 1 1 27 18 3872 342 296 6.39 6.19 402584 268770 6.39 22.36 137.13 244.91 3.39 45.71 61.08 316.57 661.48 2.0 118 1004704
+1 97 1 1 16 24 195 12 17 0.40 1.20 1216 10442 0.00 0.00 0.00 0.00 0.00 0.00 0.00 34.60 35.40 1.0 7917 1880896
+1 92 1 1 1 0 302 57 24 0.20 0.20 253775 4639 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.03 17.03 1.8 489 1745791
+1 80 1 1 3 0 862 78 209 2.00 2.60 267700 63938 0.00 0.00 0.00 0.00 0.00 2.80 4.80 160.60 174.60 2.8 2242 1796314
+1 87 1 1 6 2 1965 103 93 2.20 2.40 24422 25113 0.00 0.00 0.00 0.00 0.00 6.60 10.80 258.40 332.80 1.0 2197 1047750
+1 92 1 1 2 1 2454 77 73 0.20 0.20 112866 26523 2.40 4.81 6.41 5.21 0.40 3.01 6.41 22.04 38.68 2.6 301 983820
+1 83 1 1 8 2 3907 359 271 4.80 1.40 164803 29992 1.60 2.20 1.60 0.00 0.60 0.80 1.00 228.60 347.60 2.6 288 1709192
+1 95 1 1 0 0 801 217 165 0.20 0.20 144435 129531 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.2 2141 1763296
+1 91 1 1 7 2 2595 142 142 1.80 3.40 261645 135818 0.00 0.00 0.00 0.00 0.00 0.80 1.40 95.40 142.00 4.4 1476 1640208
+1 97 1 1 1 0 914 71 56 0.20 0.20 1297 13687 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.04 29.66 3.3 1511 1026047
+1 80 1 1 4 1 2965 289 198 3.40 1.20 374749 14956 0.00 0.00 0.00 0.00 0.00 0.00 0.00 166.40 240.20 2.8 582 1758584
+1 83 1 1 2 1 3440 219 187 0.60 0.60 163473 64164 0.00 0.00 0.00 0.00 1.20 5.21 7.41 205.81 162.53 1.8 735 1123065
+1 87 1 1 39 48 3006 235 235 2.80 1.00 110395 14018 0.00 0.00 0.00 0.00 0.00 6.20 12.00 142.80 218.20 3.4 4526 1720122
+1 81 1 1 8 1 2372 342 317 7.20 2.00 188778 93028 0.00 0.00 0.00 0.00 0.00 0.20 0.40 337.20 482.60 1.2 6825 1853173
+1 97 1 1 31 40 595 89 57 0.20 0.20 2336 11981 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 2.0 1187 1724094
+1 95 1 1 1 0 1617 143 112 0.40 0.60 12219 3838 0.20 0.20 0.20 0.00 0.00 1.00 1.40 34.00 48.00 2.0 365 1382544
+1 96 1 1 2 1 523 52 37 0.40 0.40 176128 68253 0.00 0.00 0.00 0.00 0.00 7.80 15.40 30.40 41.60 1.0 8054 1834821
+1 77 1 1 124 144 2255 343 257 5.40 4.60 192880 52201 7.20 57.20 118.60 245.60 0.00 34.00 52.20 211.40 470.00 1.0 143 1047304
+1 98 1 1 2 1 193 15 14 0.20 0.20 6997 4123 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.0 7288 1860160
+1 91 1 1 46 62 1299 155 138 2.00 1.40 56106 32993 0.00 0.00 0.00 0.00 0.00 4.20 6.20 109.20 191.40 1.5 2632 1017843
+1 83 1 1 25 4 4644 230 177 1.20 2.00 243774 58431 6.00 28.60 74.40 206.40 0.40 62.40 86.00 92.60 448.60 9.8 305 1304165
+1 98 1 1 0 0 158 10 18 0.20 0.20 426 6555 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6132 1856736
+1 86 1 1 11 3 5355 217 189 1.00 2.60 69167 77462 0.00 0.00 0.00 0.00 0.00 0.60 1.20 87.80 118.20 3.0 928 1523869
+1 78 1 1 26 3 3342 348 186 2.20 6.60 332149 186456 13.60 25.80 67.00 136.40 1.40 20.00 32.00 143.40 382.00 1.5 143 981362
+1 0 1 1 8 6 1168 129 88 0.80 0.60 135994 31885 2.00 2.00 2.00 0.00 0.40 2.00 2.00 36.60 47.80 133 94 6
+1 89 1 1 0 0 2743 95 99 0.20 0.20 3089 5280 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.57 16.97 2.0 628 1755138
+1 70 1 1 25 16 4669 463 327 2.20 1.80 330037 140092 10.00 71.60 149.40 384.40 2.20 44.40 69.00 191.00 453.00 11.0 146 1304138
+1 67 1 1 83 47 5277 407 342 7.39 17.37 372409 262232 3.39 15.17 15.17 0.00 0.00 5.79 8.38 380.84 639.32 2.6 389 1098108
+1 98 1 1 2 1 210 25 32 0.20 0.20 11974 22876 0.00 0.00 0.00 0.00 0.00 0.40 0.80 15.60 16.80 1.2 6169 1855749
+1 90 1 1 32 48 1404 116 87 0.20 0.20 15887 59172 10.16 19.32 24.90 20.12 2.99 5.98 6.77 18.92 32.27 3.7 154 1113450
+1 96 1 1 13 21 1036 58 37 0.20 0.20 46946 7024 0.00 0.00 0.00 0.00 0.00 2.60 5.20 16.40 17.00 1.0 5663 1832568
+1 91 1 1 27 39 2887 137 81 0.60 0.60 40273 39759 2.40 2.60 2.20 0.00 0.20 0.00 0.00 33.20 45.00 1.4 308 1749037
+1 96 1 1 3 0 720 53 49 0.40 1.00 98131 24861 0.00 0.00 0.00 0.00 0.00 0.00 0.00 38.92 37.92 2.4 4785 1668936
+1 74 1 1 7 1 1950 180 97 5.99 6.19 397379 148245 8.38 16.57 12.57 0.00 1.00 13.17 17.96 248.30 447.11 1.6 365 1005349
+1 83 1 1 9 7 2677 342 151 1.00 3.00 371257 343169 9.60 25.40 40.40 70.20 1.20 11.80 22.80 121.80 258.40 1.0 252 1040595
+1 87 1 1 1 0 5838 448 248 0.20 0.20 114398 54983 1.80 2.59 2.59 0.00 0.60 3.79 6.59 21.36 59.48 1.0 279 1070259
+1 89 1 1 22 5 2289 161 173 1.80 1.40 171495 107789 0.00 0.00 0.00 0.00 0.00 1.20 1.20 111.20 133.40 2.2 663 1532253
+1 94 1 1 33 47 562 92 36 0.40 1.80 292680 26315 0.00 0.00 0.00 0.00 0.40 7.58 7.58 34.73 81.84 1.0 599 1034651
+1 98 1 1 1 1 341 52 40 0.60 0.60 29813 24090 0.00 0.00 0.00 0.00 0.00 0.00 0.00 106.40 38.00 2.2 381 1716736
+1 86 1 1 5 0 1998 292 242 4.20 1.20 132678 19310 0.00 0.00 0.00 0.00 0.00 0.00 0.00 199.40 292.20 3.0 634 1711210
+1 97 1 1 1 0 397 159 60 0.60 0.40 61210 20054 0.00 0.00 0.00 0.00 0.00 1.60 3.20 33.80 40.60 1.2 6170 1857019
+1 98 1 1 1 1 205 23 35 0.20 0.20 7434 8785 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7263 1865264
+1 86 1 1 4 1 769 95 96 0.40 0.40 183897 306485 45.00 95.20 105.00 22.00 0.40 0.40 2.60 31.60 105.40 4.0 182 1708040
+1 91 1 1 40 55 2814 152 125 0.80 0.80 36577 47134 0.00 0.00 0.00 0.00 0.60 17.00 17.00 48.40 123.20 3.8 1048 1524160
+1 90 1 1 83 81 2582 170 159 1.00 1.00 66580 202445 3.00 3.60 3.60 0.00 0.20 2.60 8.00 66.00 110.20 1.5 271 988688
+1 98 1 1 1 0 311 58 35 0.20 0.20 1820 10295 0.00 0.00 0.00 0.00 0.00 4.40 4.80 15.80 26.80 1.0 1900 1771971
+1 84 1 1 42 58 3615 229 134 1.00 1.20 20581 29381 3.40 4.20 6.20 3.40 2.00 21.60 22.80 76.00 168.40 2.2 168 1130147
+1 94 1 1 2 0 1307 130 68 0.80 1.00 23161 18709 0.00 0.00 0.00 0.00 0.00 4.40 7.80 53.60 75.40 1.3 1940 1075173
+1 91 1 1 10 10 1752 206 116 0.60 0.40 492823 51586 1.60 1.60 1.60 0.00 0.80 4.41 7.82 43.89 59.52 1.0 168 1102458
+1 89 1 1 4 1 5408 239 218 0.80 2.00 320857 97794 0.00 0.00 0.00 0.00 0.20 21.80 30.40 38.20 141.40 3.0 2889 1643259
+1 93 1 1 16 24 288 68 40 0.40 0.60 229547 216569 0.00 0.00 0.00 0.00 0.00 2.40 4.80 30.60 27.80 2.4 3570 1822072
+1 86 1 1 1 0 388 76 51 0.20 0.20 325605 240758 38.60 68.00 83.80 51.60 16.00 27.20 51.40 19.80 45.40 2.8 143 1716574
+1 82 1 1 33 23 2813 214 134 1.20 1.00 359038 138798 0.80 1.60 1.60 0.00 1.60 11.20 18.80 59.60 216.20 8.0 461 1317317
+1 92 1 1 0 0 1945 140 120 0.20 0.20 55721 87368 7.20 10.20 10.00 0.00 0.80 1.20 2.20 15.40 17.80 1.2 317 1753784
+1 85 1 1 2 0 2935 172 103 1.20 1.80 499502 171548 6.40 18.00 42.60 42.40 1.60 12.60 22.20 95.60 180.00 5.6 143 1017051
+1 90 1 1 2 0 2055 239 173 0.80 0.80 106521 135119 0.20 4.20 15.20 35.00 3.20 27.60 37.00 70.60 224.00 2.8 419 1380114
+1 95 1 1 0 0 239 44 33 0.20 0.20 248037 108579 0.00 0.00 0.00 0.00 0.00 18.80 37.40 15.40 35.00 1.0 5759 1856667
+1 85 1 1 14 10 1344 118 74 1.60 2.60 321978 46937 0.00 0.00 0.00 0.00 0.00 5.20 9.00 165.00 351.80 1.0 1767 1069374
+1 91 1 1 7 1 1650 160 126 0.40 0.40 33712 61936 5.00 7.40 7.20 0.00 1.60 1.80 2.20 28.60 65.20 2.0 430 1013798
+1 82 1 1 3 0 3320 294 227 2.20 4.19 79618 108101 6.19 11.78 11.58 0.00 0.00 2.20 2.20 283.03 240.72 1.0 296 983580
+1 81 1 1 30 15 2926 269 233 5.00 4.60 198456 55428 0.00 0.00 0.00 0.00 0.20 23.40 24.00 243.00 444.00 3.8 7949 1366403
+1 91 1 1 0 0 216 14 20 0.20 0.20 452 5432 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.20 16.80 1.4 974 1761416
+1 89 1 1 2 0 1687 66 57 1.80 3.80 145191 83587 0.00 0.00 0.00 0.00 0.00 5.80 9.40 130.40 233.40 1.6 762 1069069
+1 76 1 1 8 0 3741 238 175 6.80 20.00 43717 46291 0.60 0.60 0.60 0.00 0.00 8.00 8.40 250.40 444.20 1.0 202 1091530
+1 0 1 1 23 18 2996 257 265 1.40 1.60 170904 76164 7.39 16.57 29.54 43.31 0.80 1.20 1.80 79.24 280.64 212 81 19
+1 97 1 1 1 1 241 18 24 0.20 0.20 7016 10288 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.4 7398 1865531
+1 98 1 1 0 0 319 61 37 0.20 0.20 1695 5584 1.00 1.00 1.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 253 1707712
+1 56 1 1 21 6 5456 485 304 11.40 11.00 390051 40479 1.00 1.00 1.00 0.00 0.80 46.80 49.60 538.20 1260.40 1.0 530 982954
+1 79 1 1 6 1 3959 659 573 3.00 1.40 569326 396615 1.40 2.60 2.40 0.00 2.20 3.40 4.80 180.80 303.80 2.0 427 1125595
+1 95 1 1 1 1 2021 93 96 0.20 0.20 105905 9499 0.00 0.00 0.00 0.00 0.20 0.00 0.00 17.60 19.00 2.0 630 1718893
+1 77 1 1 4 1 7225 252 310 1.40 1.40 164847 565690 1.00 1.20 1.20 0.00 0.80 7.60 10.00 64.20 116.20 2.3 299 1004424
+1 81 1 1 5 1 2433 194 142 1.40 1.40 346692 122775 0.00 0.00 0.00 0.00 0.00 2.40 4.00 111.40 167.00 1.5 875 1055194
+1 97 1 1 26 39 219 15 17 0.20 0.20 15074 10163 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 20.80 1.0 6879 1826264
+1 89 1 1 32 47 2093 164 129 1.20 3.80 94847 16603 0.00 0.00 0.00 0.00 0.60 0.40 0.40 84.60 132.20 1.4 440 1104264
+1 80 1 1 5 0 2846 512 341 4.80 2.00 330346 186516 0.00 0.00 0.00 0.00 0.00 9.80 10.20 258.60 398.40 6.8 3606 1596098
+1 98 1 1 1 1 171 11 15 0.20 0.20 7005 10148 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 8533 1870017
+1 77 1 1 20 9 5998 660 226 2.20 4.79 194430 88620 0.00 0.00 0.00 0.00 0.00 5.39 8.38 174.85 256.29 2.2 1115 1018756
+1 56 1 1 70 56 5250 502 280 9.58 22.36 1454742 74995 3.99 26.35 81.64 224.15 1.40 39.92 53.49 348.30 825.75 2.0 609 1094462
+1 92 1 1 3 1 802 52 65 1.20 3.20 56074 212985 0.60 4.20 0.80 0.00 0.80 0.20 0.40 66.40 94.80 1.2 6933 1852528
+1 97 1 1 7 1 606 58 77 0.20 0.20 5240 61640 0.00 0.00 0.00 0.00 0.00 4.80 4.80 17.40 38.40 2.0 594 1059555
+1 98 1 1 2 1 823 27 26 0.20 0.20 18803 20002 0.00 0.00 0.00 0.00 0.00 0.80 1.40 15.60 16.80 1.0 4624 1828408
+1 95 1 1 2 1 457 39 27 0.40 0.40 7987 5076 0.00 0.00 0.00 0.00 0.80 0.80 6.00 37.40 42.00 2.2 1354 1713314
+1 97 1 1 2 1 234 36 15 0.20 0.20 214764 14692 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 18.20 1.2 7280 1877278
+1 92 1 1 2 0 1623 102 104 0.60 2.20 121229 71410 4.80 4.80 4.80 0.00 1.00 2.20 2.40 50.20 78.60 1.0 170 1046589
+1 86 1 1 6 4 2763 249 112 1.60 3.20 132672 25607 0.40 0.40 0.40 0.00 0.00 2.20 2.20 116.20 159.60 1.0 320 1123400
+1 90 1 1 7 1 1796 112 99 1.40 3.19 218630 187867 2.40 2.40 2.40 0.00 4.99 1.00 1.20 169.46 153.89 3.0 239 1514932
+1 90 1 1 47 55 891 72 57 2.00 4.59 161768 38142 0.20 0.20 0.20 0.00 0.40 6.19 6.79 133.53 211.18 1.0 309 1068905
+1 78 1 1 15 9 5763 322 275 4.20 3.40 225329 158009 0.00 0.00 0.00 0.00 0.00 0.60 0.60 266.20 356.80 6.2 1164 1614413
+1 79 1 1 46 56 3635 367 264 4.98 2.39 229971 82665 0.00 0.00 0.00 0.00 0.00 0.80 0.80 259.36 392.43 3.0 873 1046947
+1 97 1 1 0 0 201 26 25 0.20 0.20 587 8785 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.60 17.20 1.0 1308 1745672
+1 91 1 1 53 75 1345 98 108 0.40 0.40 16472 65359 0.00 0.00 0.00 0.00 0.00 1.80 2.20 33.80 71.80 4.4 1432 1044718
+1 88 1 1 4 0 2781 263 222 2.60 1.20 245197 44762 0.00 0.00 0.00 0.00 0.20 5.20 5.20 138.40 252.60 1.7 2744 1047638
+1 86 1 1 14 0 1654 95 62 2.00 2.40 189881 134834 5.40 14.00 65.40 115.80 1.00 22.80 24.00 140.00 296.20 6.4 168 1593582
+1 90 1 1 39 52 2527 138 89 0.80 3.40 265344 41496 3.80 5.00 5.00 0.00 2.20 26.20 37.60 63.40 104.80 1.3 677 1057779
+1 98 1 1 1 1 465 22 28 0.20 0.20 11366 12964 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 1.2 6848 1877352
+1 77 1 1 11 0 2995 400 336 8.00 3.80 269385 80555 0.80 0.80 0.80 0.00 0.00 0.00 0.00 379.40 557.80 4.6 242 1722416
+1 92 1 1 11 8 3549 168 140 0.40 0.40 13296 40833 0.00 0.00 0.00 0.00 0.00 3.40 3.60 42.40 102.80 1.2 1524 971326
+1 83 1 1 6 0 3018 417 241 2.00 2.59 1224535 193082 0.00 0.00 0.00 0.00 0.00 15.17 23.35 108.38 196.81 1.3 406 1071511
+1 92 1 1 95 111 1137 136 93 1.00 0.80 70872 33897 0.00 0.00 0.00 0.00 0.00 8.20 8.20 62.20 111.60 2.0 859 998858
+1 93 1 1 3 0 3312 213 128 0.40 1.00 28611 70352 0.00 0.00 0.00 0.00 0.20 0.20 0.20 33.80 49.80 2.2 2479 1645269
+1 0 1 1 77 90 4219 652 595 1.39 1.39 96821 46895 3.17 16.47 36.31 82.94 0.79 11.51 13.69 102.78 224.60 134 85 15
+1 87 1 1 29 41 2498 140 150 1.40 1.60 119383 32297 0.00 0.00 0.00 0.00 0.00 10.80 20.80 66.80 101.80 3.4 3996 1716054
+1 97 1 1 1 0 346 61 23 0.20 0.20 382940 19927 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.20 18.80 1.8 8016 1862216
+1 98 1 1 2 1 261 40 26 0.20 0.20 197151 24724 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 18.20 1.2 7110 1873368
+1 83 1 1 7 2 1948 302 236 5.59 2.20 390970 260428 0.00 0.00 0.00 0.00 0.00 3.59 6.99 255.09 371.46 2.4 3458 1815641
+1 91 1 1 3 1 1490 147 111 1.40 4.00 29410 32328 0.00 0.00 0.00 0.00 0.00 1.20 1.40 72.80 84.00 1.8 1147 1124344
+1 80 1 1 55 59 5513 327 213 0.40 0.40 122053 99901 7.39 23.35 30.74 48.90 6.79 46.11 60.88 33.13 208.18 1.2 228 981948
+1 89 1 1 52 36 3084 203 389 2.80 2.80 94519 116569 0.00 0.00 0.00 0.00 0.00 0.00 0.00 150.20 200.40 2.4 1632 1641173
+1 87 1 1 1 0 1948 124 113 0.60 1.20 63813 74699 0.00 0.00 0.00 0.00 0.20 3.19 5.99 45.51 80.84 1.0 464 1117097
+1 89 1 1 1 0 2711 144 118 1.40 1.60 161993 56924 3.61 14.23 20.84 35.07 4.81 5.41 5.81 102.81 170.74 2.6 152 1087596
+1 80 1 1 6 2 2285 177 191 4.00 3.20 84430 214977 0.00 0.00 0.00 0.00 0.00 9.80 11.20 204.00 357.80 2.8 717 1016555
+1 95 1 1 14 13 1510 168 97 0.20 0.20 25438 26958 0.00 0.00 0.00 0.00 0.00 2.40 4.99 19.56 16.77 1.0 1088 1080695
+1 98 1 1 1 1 192 12 33 0.20 0.20 8571 12015 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 1.0 7293 1875112
+1 94 1 1 2 0 801 68 47 0.60 2.20 171773 20095 0.00 0.00 0.00 0.00 0.00 9.80 10.20 56.40 135.60 2.5 3020 1012598
+1 93 1 1 3 1 2307 114 105 0.40 1.80 31281 113104 0.00 0.00 0.00 0.00 0.00 0.40 0.40 19.60 35.20 2.4 3103 1656325
+1 58 1 1 54 34 5657 777 594 11.40 6.80 446525 68465 0.20 0.20 0.20 0.00 0.20 13.80 22.80 674.20 1029.20 2.0 424 1031053
+1 93 1 1 0 0 2352 82 73 0.20 0.20 3146 8482 0.00 0.00 0.00 0.00 0.00 0.60 1.00 15.60 17.40 1.0 608 1731416
+1 93 1 1 1 0 3440 144 156 0.20 0.20 92394 37398 0.60 0.60 0.60 0.00 0.40 0.00 0.00 21.60 21.20 2.6 147 1707931
+1 90 1 1 0 0 1703 158 127 0.20 0.20 5095 24264 0.80 8.40 11.80 11.00 0.60 14.80 14.80 15.40 118.60 1.6 166 1099232
+1 94 1 1 17 25 1405 83 142 0.60 0.60 12122 157021 1.80 1.80 2.40 2.20 0.00 1.20 1.20 35.47 48.50 1.2 144 1746180
+1 79 1 1 7 2 2862 278 150 5.61 4.81 253841 114278 0.00 0.00 0.00 0.00 1.20 11.82 12.22 282.57 455.91 2.4 1934 1007500
+1 97 1 1 2 0 528 35 40 0.40 0.80 1229 25473 0.00 0.00 0.00 0.00 0.00 0.60 0.80 34.27 44.49 1.3 704 1064691
+1 98 1 1 0 0 233 23 22 0.20 0.20 663 9460 0.00 0.00 0.00 0.00 0.00 0.00 0.00 14.40 16.80 2.0 2972 1707112
+1 96 1 1 19 28 586 76 51 0.20 0.20 1609 13494 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 16.80 2.0 1258 1713042
+1 80 1 1 55 61 3395 568 152 2.20 3.40 249412 37226 0.00 0.00 0.00 0.00 0.20 8.00 15.60 153.80 278.20 2.6 1223 1536299
+1 88 1 1 20 25 419 36 32 2.20 2.20 63830 39248 0.00 0.00 0.00 0.00 0.00 1.20 1.60 186.43 174.25 1.0 8249 1866379
+1 89 1 1 4 0 2197 138 131 1.40 2.20 112116 79948 0.00 0.00 0.00 0.00 0.00 8.82 10.42 73.75 160.32 1.0 712 1061429
+1 90 1 1 17 16 2075 135 79 0.20 0.20 11362 23344 0.00 0.00 0.00 0.00 0.00 1.20 1.20 88.42 17.76 1.0 1113 1081611
+1 99 1 1 0 0 151 11 25 0.20 0.20 439 21995 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.0 6737 1858691
+1 96 1 1 1 0 1505 73 77 0.20 0.20 10196 28193 0.00 0.00 0.00 0.00 0.60 0.20 0.40 16.37 24.55 1.5 1065 1053132
+1 78 1 1 17 7 3510 375 310 4.19 1.80 175138 78646 0.00 0.00 0.00 0.00 0.00 2.20 3.39 226.95 443.11 1.8 781 968909
+1 89 1 1 4 1 1602 170 162 3.40 1.00 77639 153502 0.00 0.00 0.00 0.00 0.00 0.00 0.00 161.20 232.00 2.2 5757 1840403
+1 94 1 1 1 0 2514 120 99 0.80 1.20 276080 32472 0.40 0.60 0.60 0.00 2.80 0.20 0.20 23.80 36.20 1.6 205 1749656
+1 83 1 1 7 1 2139 329 127 2.80 3.60 1001902 34497 0.00 0.00 0.00 0.00 0.00 30.00 33.60 138.00 302.00 1.2 2376 1090363
+1 72 1 1 22 18 4418 351 216 4.00 5.00 301061 68449 0.00 0.00 0.00 0.00 0.00 6.20 7.60 265.20 497.80 2.0 1063 1008304
+1 76 1 1 12 0 6188 624 408 4.99 2.00 137279 62736 0.20 0.20 0.20 0.00 0.00 1.40 1.80 265.07 397.01 1.0 328 1065847
+1 98 1 1 0 0 195 10 16 0.20 0.20 3368 46609 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 6910 1858525
+1 80 1 1 7 0 2635 588 572 0.60 2.20 647485 572968 10.18 33.33 63.07 79.44 3.19 21.36 86.43 50.30 75.85 1.0 169 1047085
+1 81 1 1 65 6 2532 166 125 0.60 0.80 38998 80415 6.19 20.16 27.35 36.13 1.00 21.36 22.75 61.88 183.83 1.0 342 1036602
+1 94 1 1 4 2 2318 252 116 0.40 0.40 284319 144524 0.00 0.00 0.00 0.00 0.00 1.20 1.20 34.40 48.40 3.6 669 1326208
+1 97 1 1 1 0 801 67 72 0.20 0.20 4584 19779 1.60 1.60 1.60 0.00 0.20 1.20 1.20 15.60 22.40 1.0 314 1016016
+1 75 1 1 49 57 5344 978 862 3.19 1.00 787806 738498 0.00 0.00 0.00 0.00 0.00 6.18 10.96 160.76 238.05 2.2 987 1074963
+1 96 1 1 28 39 157 14 15 0.20 0.20 8738 8548 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.16 16.77 1.0 1882 1768184
+1 89 1 1 5 0 2794 291 263 1.20 0.60 129608 114836 0.00 0.00 0.00 0.00 0.00 13.17 13.77 73.25 151.50 3.0 1403 1040123
+1 92 1 1 8 5 1361 117 81 0.40 1.80 32845 44283 4.59 7.19 6.79 3.59 1.60 0.20 1.60 33.53 108.98 1.5 183 967026
+1 76 1 1 17 6 5966 274 171 2.59 6.79 27941 42226 5.19 6.99 12.57 9.58 2.99 9.58 9.58 180.64 255.89 4.6 154 1311112
+1 87 1 1 8 0 2454 310 267 3.20 1.00 139403 62658 0.80 0.80 1.20 2.00 0.20 1.00 1.00 160.00 242.40 1.8 208 1110645
+1 92 1 1 78 76 1111 155 114 0.80 0.60 116400 49458 0.00 0.00 0.00 0.00 0.40 7.20 8.20 65.00 94.20 1.5 376 1017464
+1 90 1 1 3 0 2286 160 97 0.60 1.80 162790 78386 0.20 0.40 0.40 0.00 4.80 2.60 3.40 52.40 121.20 1.8 566 1014058
+1 74 1 1 20 1 2232 204 103 5.20 4.80 349753 173656 9.20 23.80 43.80 68.80 0.00 31.20 39.40 283.80 583.40 1.5 518 1029395
+1 86 1 1 4 0 1012 137 112 2.60 0.80 78025 6260 0.00 0.00 0.00 0.00 0.00 5.80 5.80 120.80 178.40 1.6 587 1742296
+1 88 1 1 3 1 544 92 73 1.80 1.80 247617 175885 0.00 0.00 0.00 0.00 0.00 6.80 11.00 161.20 147.40 2.0 3549 1822469
+1 56 1 1 48 44 5793 705 325 13.40 34.80 251986 151431 0.00 0.00 0.00 0.00 0.00 5.20 5.40 482.20 898.60 1.0 1188 1087403
+1 94 1 1 5 5 2175 83 77 0.60 0.60 17319 29789 0.00 0.00 0.00 0.00 0.00 2.00 2.40 42.60 62.60 1.5 425 988923
+1 90 1 1 254 59 4072 333 311 0.60 0.60 183534 202268 0.00 0.00 0.00 0.00 0.20 0.20 0.20 49.00 78.60 2.0 2422 1644392
+1 93 1 1 1 0 1293 59 49 0.60 1.00 3767 14409 0.00 0.00 0.00 0.00 0.00 0.80 0.80 49.80 61.75 2.4 1268 968080
+1 84 1 1 3 2 1527 122 145 0.20 0.20 413659 365236 30.74 84.83 198.00 431.34 0.60 48.70 90.42 19.56 40.92 3.0 135 968140
+1 96 1 1 0 0 319 57 14 0.20 0.20 352084 12848 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.20 1.4 9231 1867534
+1 89 1 1 40 55 2672 161 146 0.40 0.40 74895 196953 4.00 4.00 4.00 0.00 1.20 26.40 26.40 93.40 159.20 1.5 194 973072
+1 85 1 1 212 208 4232 406 255 1.20 2.00 388291 161853 0.00 0.00 0.00 0.00 0.00 5.00 21.80 94.60 166.40 3.4 422 1334416
+1 75 1 1 7 0 2820 373 332 6.80 1.80 173582 20888 2.00 2.40 2.40 0.00 0.40 0.40 0.60 319.40 462.20 4.2 143 1751645
+1 86 1 1 1 0 2634 255 127 1.00 3.60 174672 33215 0.20 0.20 0.20 0.00 0.00 0.40 0.40 121.60 141.00 1.4 415 1093984
+1 90 1 1 6 1 1279 180 157 4.00 1.20 94575 6400 0.00 0.00 0.00 0.00 0.00 0.00 0.00 198.20 281.80 1.0 7196 1875514
+1 90 1 1 3 1 388 31 24 1.60 1.60 49659 58793 0.00 0.00 0.00 0.00 0.00 0.60 1.00 130.94 121.16 1.0 7544 1861499
+1 91 1 1 1 0 2450 128 113 0.40 0.40 23110 26628 0.00 0.00 0.00 0.00 0.00 9.58 11.58 31.54 50.90 1.0 791 1050303
+1 88 1 1 1 0 2282 401 210 0.20 0.20 12692 54386 0.20 0.20 0.20 0.00 0.20 0.60 0.80 19.20 37.80 1.6 235 1742318
+1 98 1 1 0 0 158 13 15 0.20 0.20 448 6400 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7240 1863624
+1 83 1 1 15 12 3957 339 346 3.00 1.40 321703 342201 0.00 0.00 0.00 0.00 0.00 0.00 0.00 153.20 226.00 4.2 1406 1614402
+1 92 1 1 2 0 1680 400 299 0.60 0.60 11734 13465 0.20 0.20 0.20 0.00 0.60 0.60 0.60 29.20 38.80 3.6 369 1712258
+1 82 1 1 20 8 2806 306 272 5.20 8.60 214889 130687 1.80 1.80 1.80 0.00 1.40 13.80 22.00 349.00 412.60 1.2 193 999115
+1 76 1 1 198 38 4220 448 341 2.60 1.20 228047 193897 10.00 51.20 85.00 82.00 0.20 21.60 41.00 138.40 241.80 1.5 137 1017034
+1 74 1 1 6 0 2098 190 110 6.40 24.00 158411 22867 0.00 0.00 0.00 0.00 0.20 5.80 6.80 350.40 524.40 1.0 354 1035406
+1 91 1 1 25 20 1423 187 171 0.20 0.20 122096 137418 14.37 28.34 23.75 0.00 0.60 3.19 3.59 15.57 51.70 1.6 532 1099797
+1 63 1 1 53 8 5116 612 442 12.60 8.20 266963 24095 0.00 0.00 0.00 0.00 0.60 5.40 6.60 569.20 935.40 5.8 2778 1536829
+1 93 1 1 2 0 1539 132 116 1.80 0.60 117877 17639 0.60 0.60 0.60 0.00 0.00 4.01 4.01 90.58 168.14 1.0 151 1069188
+1 86 1 1 75 32 1442 166 163 0.40 0.40 392078 277539 22.36 46.71 46.71 0.00 2.79 33.73 64.67 35.13 82.63 3.8 251 1597281
+1 95 1 1 4 3 1107 80 54 0.40 0.40 3303 23337 0.00 0.00 0.00 0.00 0.20 9.00 9.00 29.20 91.20 1.0 2467 1015398
+1 98 1 1 11 15 188 15 41 0.20 0.20 2710 8658 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 16.80 1.0 3557 1847944
+1 74 1 1 7 0 3216 570 72 6.80 21.20 1510447 52634 8.80 25.20 47.40 83.20 0.40 23.80 32.20 247.40 504.60 2.8 201 1108710
+1 76 1 1 6 0 5415 412 328 3.20 2.00 290997 97991 5.60 9.60 26.40 29.40 0.40 3.60 4.60 230.40 385.60 1.3 164 1089971
+1 85 1 1 12 1 2512 284 244 2.81 3.81 94187 98275 0.00 0.00 0.00 0.00 0.00 21.44 23.45 154.31 282.57 1.5 1316 1102746
+1 87 1 1 4 2 674 79 49 2.60 2.60 191341 147817 0.00 0.00 0.00 0.00 0.00 4.40 7.00 245.00 220.20 1.2 5280 1838771
+1 63 1 1 38 0 4582 288 141 10.22 29.06 639671 86484 6.21 17.23 24.65 42.08 1.80 24.45 29.06 327.25 681.96 3.6 142 1098099
+1 91 1 1 15 14 2423 566 248 0.20 0.20 649934 653520 0.00 0.00 0.00 0.00 0.00 0.60 1.00 23.00 32.40 1.8 430 1044971
+1 0 1 1 14 5 1030 198 179 1.20 1.00 166905 30638 0.20 0.20 0.20 0.00 0.00 13.00 31.20 87.60 197.80 563 90 10
+1 87 1 1 1 0 2804 352 410 0.40 2.00 37461 53614 0.00 0.00 0.00 0.00 0.00 21.20 21.40 24.40 86.40 2.6 1969 1705293
+1 75 1 1 68 83 3135 244 162 5.41 14.83 171541 96875 9.62 19.24 18.84 0.00 0.00 5.01 7.01 207.21 374.35 1.0 365 1106976
+1 91 1 1 1 0 356 31 31 1.80 1.80 44217 20023 0.00 0.00 0.00 0.00 0.00 1.80 2.80 140.00 139.40 1.0 7303 1849827
+1 94 1 1 1 0 1592 93 69 0.40 1.80 39733 37995 0.00 0.00 0.00 0.00 0.00 0.40 0.40 33.00 45.40 1.2 2906 1050522
+1 81 1 1 6 1 4322 387 274 3.41 3.21 211938 119371 1.20 2.00 1.80 0.00 1.60 13.03 23.85 186.97 392.99 1.0 679 989015
+1 85 1 1 9 7 1106 85 60 0.20 0.20 96962 23460 0.00 0.00 0.00 0.00 0.00 51.30 99.40 91.78 370.14 1.8 2644 952324
+1 90 1 1 0 0 4209 231 178 0.40 0.60 142503 229720 0.20 0.20 9.40 18.60 0.00 0.00 0.00 33.20 59.00 2.4 152 1386010
+1 94 1 1 10 8 1672 118 71 0.20 0.20 5970 17463 0.00 0.00 0.00 0.00 0.00 0.20 0.20 71.66 19.16 2.0 1551 1078014
+1 76 1 1 12 3 4338 319 246 1.60 2.20 346697 139861 3.59 16.57 52.50 75.85 1.20 75.45 79.64 129.74 486.63 6.4 465 1290687
+1 92 1 1 16 5 2596 172 101 2.60 5.40 367523 68362 0.00 0.00 0.00 0.00 0.00 0.60 0.60 191.40 197.80 3.6 852 1545477
+1 78 1 1 19 18 3858 222 151 1.20 1.20 437045 78441 20.96 60.08 110.78 190.22 6.19 49.70 84.03 308.78 204.39 2.3 155 996604
+1 95 1 1 4 3 294 29 54 0.60 0.40 45310 30398 0.00 0.00 0.00 0.00 0.00 3.01 5.81 38.08 41.08 1.4 7511 1870499
+1 88 1 1 1 0 3567 339 304 0.60 2.20 28929 36591 3.01 3.01 3.01 0.00 0.00 7.62 10.02 30.46 57.11 1.0 271 1101937
+1 87 1 1 14 13 6360 217 166 0.60 0.60 77756 74474 0.00 0.00 0.00 0.00 0.00 5.00 5.40 31.60 67.20 1.8 766 999555
+1 89 1 1 9 8 1428 85 67 0.80 1.40 12357 29920 10.22 20.24 20.24 0.00 0.40 11.82 22.85 105.21 190.18 2.0 324 1061935
+1 91 1 1 18 14 2064 121 90 1.00 0.80 56872 28574 0.00 0.00 0.00 0.00 0.20 24.20 26.80 46.20 153.60 1.4 1269 1307661
+1 83 1 1 13 11 2756 371 195 1.80 0.80 1317864 988960 0.00 0.00 0.00 0.00 0.40 24.60 41.20 104.00 162.20 1.3 572 1014926
+1 94 1 1 1 0 3244 165 188 0.20 0.20 70909 156108 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.80 18.80 3.0 2892 1650291
+1 97 1 1 1 0 209 30 27 0.20 0.20 13961 14007 0.00 0.00 0.00 0.00 0.00 0.60 1.00 14.83 16.83 1.2 7420 1869323
+1 95 1 1 2 1 1252 138 99 0.20 0.20 4361 21604 0.00 0.00 0.00 0.00 0.00 0.40 0.40 22.36 21.36 1.3 527 976144
+1 93 1 1 9 9 1437 279 140 0.40 0.80 200790 121184 0.00 0.00 0.00 0.00 0.00 27.40 27.40 28.80 86.20 4.4 2867 1604600
+1 0 1 1 29 21 1296 480 160 1.40 2.20 816892 683670 7.60 21.20 51.00 115.20 1.00 2.80 5.60 71.40 209.40 142 89 11
+1 76 1 1 7 0 3313 416 319 7.00 2.00 191003 12980 0.00 0.00 0.00 0.00 0.00 0.00 0.00 324.80 479.20 4.0 506 1745051
+1 96 1 1 1 0 1228 42 38 0.20 0.20 7176 15793 0.00 0.00 0.00 0.00 0.00 0.00 0.00 25.40 19.40 2.0 2083 1003210
+1 87 1 1 9 3 3120 405 277 1.00 1.79 162000 110195 0.00 0.00 0.00 0.00 0.20 4.38 8.37 64.94 150.60 2.0 566 1068770
+1 85 1 1 1 0 4945 429 241 0.60 1.40 93810 41867 2.60 4.20 4.20 0.00 0.20 6.00 7.60 49.80 120.40 1.0 173 1137552
+1 94 1 1 3 2 857 94 90 0.20 0.20 94949 27795 0.00 0.00 2.40 8.00 0.00 1.60 1.60 16.00 32.60 2.6 126 1088995
+1 84 1 1 14 13 3398 511 103 2.20 2.20 125593 29286 7.40 35.80 70.40 136.20 0.00 0.40 0.40 271.20 403.60 1.0 138 1081218
+1 98 1 1 1 1 220 29 31 0.00 0.00 36999 8324 0.00 0.00 0.00 0.00 0.00 0.00 0.00 6.97 10.36 1.0 7143 1856064
+1 65 1 1 51 4 3831 205 153 11.38 32.53 191661 63592 3.79 4.39 3.99 0.00 0.40 9.38 10.78 372.85 695.21 1.0 336 1092915
+1 78 1 1 43 46 3083 467 407 8.20 2.00 224444 18218 0.00 0.00 0.00 0.00 0.00 0.00 0.00 380.40 550.00 4.2 636 1710493
+1 84 1 1 1 0 4165 259 163 0.80 1.00 55069 162071 0.00 0.00 0.00 0.00 0.20 15.00 21.00 64.20 134.20 1.5 424 1001854
+1 89 1 1 7 2 3855 274 191 1.20 2.00 130110 115049 0.00 0.00 0.00 0.00 0.00 6.60 12.40 74.80 106.20 3.4 3078 1548314
+1 84 1 1 3 1 2424 149 161 1.60 2.20 204632 239445 0.00 0.00 0.00 0.00 0.00 0.60 0.80 145.80 253.00 2.4 8289 1877581
+1 76 1 1 5 1 4983 316 333 3.00 5.60 253911 596257 0.00 0.00 0.00 0.00 0.00 8.00 10.00 176.60 251.80 1.4 826 994360
+1 78 1 1 11 9 2595 207 110 1.20 3.78 711926 75023 36.45 104.38 195.62 374.90 0.80 74.90 148.41 119.32 233.67 1.5 158 978287
+1 78 1 1 45 22 4121 620 535 2.60 4.80 917846 711555 6.60 12.80 19.00 19.60 9.20 2.20 2.40 136.00 215.00 2.0 178 1036322
+1 93 1 1 3 0 3915 155 118 0.60 1.20 106588 78827 0.00 0.00 0.00 0.00 0.00 1.40 1.60 56.60 59.40 2.2 2689 1646288
+1 93 1 1 66 35 2183 133 124 0.20 0.20 74204 52963 0.20 0.20 0.20 0.00 0.20 6.60 8.80 18.20 52.40 3.8 474 1326890
+1 98 1 1 0 0 219 29 24 0.20 0.20 84857 13021 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.6 7310 1867463
+1 97 1 1 16 23 172 22 10 0.20 0.20 105725 6405 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.2 3688 1822496
+1 99 1 1 0 0 138 8 13 0.20 0.20 490 9087 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 583 1732768
+1 0 1 1 10 7 2489 174 104 0.20 0.20 62847 19508 3.20 5.20 14.40 40.20 0.80 3.60 3.80 16.40 98.60 167 91 8
+1 77 1 1 23 4 3365 307 239 5.00 3.60 425526 43983 1.60 5.60 16.00 22.80 1.00 1.60 1.60 288.20 491.00 2.6 241 1080478
+1 75 1 1 12 0 1930 148 75 5.20 22.00 293028 25681 6.40 16.20 73.80 151.20 0.80 22.00 30.00 312.60 521.60 1.0 166 1037280
+1 89 1 1 10 6 476 44 54 1.40 1.20 30286 32718 0.00 0.00 0.00 0.00 0.00 1.20 1.60 114.77 119.96 2.0 479 1741809
+1 0 1 1 6 5 1582 320 106 0.20 0.20 480602 468110 2.60 4.40 4.40 0.00 0.60 0.80 0.80 22.40 48.40 224 88 12
+1 86 1 1 2 0 5377 1152 648 0.40 0.60 47614 86407 2.40 5.21 26.65 36.07 0.00 14.83 16.23 28.86 49.30 1.3 140 1073190
+1 99 1 1 0 0 149 10 11 0.20 0.20 3890 9804 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.37 16.77 1.0 8673 1865980
+1 95 1 1 0 0 1450 101 92 0.20 0.20 16511 19169 1.20 1.20 11.80 25.60 0.00 12.00 12.80 18.00 36.60 1.0 128 1060221
+1 88 1 1 5 1 729 91 27 1.40 1.80 65918 2998 0.00 0.00 0.00 0.00 0.00 3.00 3.40 127.00 144.80 1.8 1584 1766574
+1 88 1 1 5 0 4036 354 200 0.80 0.80 32404 49327 0.20 0.20 0.20 0.00 0.20 6.59 9.58 70.86 98.80 1.5 193 974271
+1 92 1 1 3 2 1570 83 82 0.60 1.20 48697 17966 0.00 0.00 0.00 0.00 0.00 14.60 14.80 47.80 95.80 1.5 1903 1008859
+1 84 1 1 34 15 2332 237 137 2.81 3.61 127453 67398 5.21 10.02 30.86 41.68 1.80 19.04 21.84 177.15 321.24 1.0 200 1013850
+1 84 1 1 4 0 2447 654 103 3.19 5.59 176546 30365 19.96 57.68 102.99 220.76 1.20 15.37 25.95 184.63 320.36 1.5 328 1102360
+1 97 1 1 2 1 230 12 15 0.80 0.80 9104 3377 0.00 0.00 0.00 0.00 0.00 0.00 0.00 53.60 60.20 1.2 7233 1876062
+1 0 1 1 19 17 3516 243 200 0.20 0.20 11558 30861 5.20 11.80 32.00 60.40 0.20 27.00 28.40 16.00 94.80 132 87 13
+1 94 1 1 2 0 1576 70 67 0.40 1.20 5597 19216 0.00 0.00 0.00 0.00 0.80 20.00 20.20 24.60 52.20 1.0 935 1074077
+1 92 1 1 5 2 1463 125 152 1.00 0.80 501614 26240 0.00 0.00 0.00 0.00 0.00 1.40 1.80 58.60 70.40 1.7 737 1047366
+1 81 1 1 13 0 5489 424 405 1.40 1.60 315121 171566 5.80 32.80 52.80 94.40 1.00 19.60 34.20 108.20 228.40 2.0 153 1048573
+1 0 1 1 5 4 1188 148 113 0.20 0.20 286813 28275 10.82 14.23 49.50 66.93 7.01 32.87 35.27 15.63 101.40 126 93 7
+1 83 1 1 16 0 2845 334 158 6.00 3.40 932280 17609 0.00 0.00 0.00 0.00 0.00 11.60 23.20 257.60 399.80 5.8 5058 1719349
+1 87 1 1 21 19 3374 558 226 1.40 3.20 615882 590566 0.20 0.20 0.20 0.00 0.00 1.60 1.60 125.60 217.40 1.0 434 1043605
+1 96 1 1 1 0 432 43 25 0.80 3.20 24364 8293 0.00 0.00 0.00 0.00 0.00 0.80 1.00 42.40 53.60 1.0 1404 1746466
+1 90 1 1 3 0 1193 145 152 0.80 2.60 217173 106950 0.00 0.00 0.00 0.00 0.00 2.40 2.80 62.20 162.40 1.0 576 1066038
+1 86 1 1 14 11 5552 321 158 2.20 7.40 866968 48363 0.00 0.00 0.00 0.00 0.00 1.40 2.20 75.60 143.20 1.0 425 1009667
+1 89 1 1 37 42 1295 52 52 0.20 0.20 16813 20187 0.40 0.80 0.80 0.00 0.20 1.00 1.60 18.76 22.16 1.2 297 1738584
+1 83 1 1 24 30 2583 242 171 1.40 2.00 40055 108188 4.60 33.20 214.20 527.00 0.40 2.80 3.80 106.40 123.80 4.0 648 1640984
+1 92 1 1 6 4 1090 84 52 1.40 2.20 181014 31665 7.00 8.20 7.00 0.00 5.60 4.60 4.80 70.40 179.60 1.3 175 1025157
+1 78 1 1 12 6 1579 52 71 4.01 3.61 109697 163903 28.46 51.30 68.54 54.31 11.02 17.84 27.86 259.92 404.41 1.0 186 1131263
+1 88 1 1 6 5 2350 249 160 0.80 4.99 26124 120519 1.00 1.20 1.00 0.00 1.40 4.79 4.79 33.53 105.19 1.6 449 1089070
+1 77 1 1 11 8 5409 520 317 1.39 1.99 120655 113146 4.98 8.17 6.77 0.00 6.77 9.96 19.92 155.98 287.45 4.2 248 1005404
+1 88 1 1 58 74 3580 306 157 1.20 4.80 85007 28708 0.20 0.20 0.20 0.00 0.20 10.20 13.00 85.20 124.20 5.4 354 1315827
+1 86 1 1 68 81 4483 538 375 0.20 0.20 607400 196340 4.21 11.02 27.86 51.10 0.80 13.23 30.26 15.23 60.72 1.8 137 1048723
+1 90 1 1 2 1 3898 181 176 0.20 0.20 12690 211636 1.60 2.40 2.40 0.00 0.20 0.80 0.80 22.60 39.60 1.0 281 999800
+1 77 1 1 8 1 3416 467 365 5.60 1.60 251705 69298 2.40 5.80 13.00 19.00 0.00 39.40 45.40 287.40 624.00 2.3 181 983189
+1 82 1 1 2 0 534 59 64 2.20 2.20 95619 57562 0.00 0.00 0.00 0.00 0.00 2.40 2.40 199.80 170.46 2.8 1100 1785865
+1 81 1 1 4 2 4121 373 191 0.60 3.40 363786 349279 15.60 23.20 40.40 112.00 0.80 23.40 33.60 25.80 272.80 2.2 200 1010323
+1 96 1 1 2 1 2072 95 103 0.20 0.20 17251 137276 1.80 2.00 2.00 0.00 0.20 0.40 0.40 18.40 22.00 2.4 313 1522626
+1 94 1 1 26 15 1558 153 121 0.60 2.20 60536 78144 0.00 0.00 0.00 0.00 0.00 2.20 4.40 58.80 103.60 2.4 1384 1542154
+1 84 1 1 95 39 3847 323 263 0.80 0.80 306175 83615 8.38 15.37 15.37 0.00 9.58 62.28 64.87 60.68 180.64 3.0 221 1037619
+1 90 1 1 3 0 1777 146 85 1.00 1.40 61198 40040 1.20 1.60 1.60 0.00 1.40 1.60 1.60 91.00 108.20 1.3 457 1058109
+1 83 1 1 34 15 884 154 88 2.20 2.40 535664 108937 0.00 0.00 0.00 0.00 0.00 7.00 13.40 176.80 191.60 1.6 2899 1795477
+1 94 1 1 1 0 1016 104 89 0.40 0.20 261950 100828 0.00 0.00 0.00 0.00 0.00 0.80 1.20 35.40 54.00 2.6 1581 1537914
+1 98 1 1 3 1 817 53 53 0.40 0.40 5296 28655 2.40 3.00 3.00 0.00 0.60 0.00 0.00 30.00 59.00 2.2 190 1523528
+1 84 1 1 4 3 2142 321 196 1.40 1.40 668115 48198 5.00 16.40 20.40 42.20 1.60 3.60 4.40 98.80 171.60 1.5 346 1128446
+1 0 1 1 6 1 1381 158 119 1.40 2.00 27168 22368 0.00 0.00 0.00 0.00 0.20 4.60 6.80 103.40 154.00 514 92 8
+1 88 1 1 10 1 1552 186 131 1.00 1.40 178399 72127 13.40 18.60 18.60 0.00 11.20 0.80 1.20 64.80 121.00 4.4 297 961802
+1 98 1 1 2 2 223 14 16 0.20 0.20 7619 8803 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6813 1827768
+1 86 1 1 1 0 3839 317 164 0.60 1.20 97366 49773 1.40 1.40 10.38 12.77 0.00 8.78 8.78 62.48 100.40 1.5 157 1124760
+1 73 1 1 33 7 3829 384 272 7.40 9.00 74593 51008 8.20 15.20 40.00 103.80 1.00 4.20 5.00 313.60 650.60 4.2 175 966250
+1 75 1 1 41 11 4185 549 252 5.79 7.39 112159 92205 11.98 40.52 75.65 212.77 1.20 6.79 9.58 366.87 610.38 2.8 132 1055216
+1 88 1 1 13 12 3053 353 166 0.80 2.00 373103 39226 0.00 0.00 0.00 0.00 0.00 3.00 4.60 54.00 113.00 1.8 848 1126931
+1 79 1 1 24 9 3080 259 206 4.60 4.80 806120 142362 7.60 9.40 9.20 0.00 4.00 10.60 15.00 213.80 411.80 2.5 206 1034381
+1 0 1 1 17 6 973 128 56 1.00 1.20 567287 27588 8.80 11.00 14.80 25.20 3.20 8.80 16.60 72.40 129.80 180 90 9
+1 0 1 1 23 0 4831 734 622 10.60 3.40 839067 549586 6.60 9.20 9.20 0.00 4.40 14.60 25.20 521.60 809.60 335 64 36
+1 82 1 1 13 5 2269 280 187 1.00 1.00 198481 65015 9.98 37.92 86.43 129.54 2.99 21.76 27.94 115.57 313.37 1.0 243 1090707
+1 69 1 1 14 8 4553 630 444 7.20 5.80 369317 58485 11.40 29.20 54.00 99.80 7.00 5.20 5.20 399.00 674.40 2.2 208 1010824
+1 91 1 1 4 1 2681 146 81 0.40 0.40 47057 9705 0.00 0.00 0.00 0.00 0.20 30.20 30.20 30.20 172.80 4.8 2727 1369683
+1 96 1 1 0 0 186 15 16 0.20 0.20 17025 18527 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 2668 1771728
+1 85 1 1 5 1 1056 159 90 3.78 2.39 392045 14382 0.00 0.00 0.00 0.00 0.00 1.79 1.79 264.94 268.13 2.0 11346 1873335
+1 91 1 1 5 0 1732 144 79 0.40 0.40 163239 11850 0.00 0.00 0.00 0.00 2.80 2.60 23.00 26.40 101.80 1.6 442 1727851
+1 66 1 1 34 1 3783 444 258 9.00 20.00 265747 38436 5.60 17.80 55.00 92.20 0.40 8.60 13.40 330.00 611.40 3.2 128 1108579
+1 93 1 1 2 1 1555 263 117 0.60 2.00 749837 68458 0.00 0.00 0.00 0.00 0.00 6.01 11.62 36.27 63.73 1.0 2255 1011769
+1 88 1 1 6 5 1962 119 94 1.20 1.20 183425 37920 0.20 0.20 0.20 0.00 0.00 7.80 9.20 92.60 232.20 2.0 310 990739
+1 92 1 1 2 0 2399 57 58 2.40 2.40 67724 39491 0.00 0.00 0.00 0.00 0.00 0.20 0.20 91.80 153.00 2.4 691 1763923
+1 81 1 1 8 6 5435 151 107 2.00 7.19 71250 38841 0.00 0.00 0.00 0.00 0.80 0.80 1.20 257.49 183.43 3.0 606 1444337
+1 97 1 1 1 1 555 25 30 0.20 0.20 2714 18782 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 25.00 1.0 649 1069200
+1 69 1 1 13 0 4156 431 382 9.20 4.40 221914 53340 6.80 42.80 81.80 165.40 0.00 2.80 3.80 410.60 705.40 1.8 209 1029048
+1 91 1 1 3 1 1127 107 53 1.80 2.80 218100 27522 0.00 0.00 0.00 0.00 0.20 25.80 26.60 98.80 211.40 1.0 2882 1014066
+1 93 1 1 79 101 1076 143 103 0.20 0.20 49908 52017 5.17 10.14 12.13 4.97 0.00 0.00 0.00 15.71 25.05 1.7 140 1005056
+1 93 1 1 0 0 1489 66 95 0.20 0.20 8486 21015 0.40 0.60 0.60 0.00 0.00 1.00 1.00 15.60 24.20 1.0 227 1067568
+1 0 1 1 14 10 1338 123 128 0.60 0.40 122682 43380 6.60 10.80 17.00 30.80 1.00 15.00 24.40 30.00 103.60 167 88 12
+1 86 1 1 11 11 3963 447 315 0.40 0.20 372521 39189 1.60 3.60 3.60 0.00 10.60 2.60 3.40 21.00 32.80 3.0 203 1134622
+1 94 1 1 1 0 3506 250 131 0.20 0.20 42730 93229 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 17.40 2.2 3194 1657128
+1 83 1 1 8 0 2831 417 336 4.80 3.40 179630 72118 0.00 0.00 0.00 0.00 0.00 2.00 2.40 242.60 395.40 1.0 946 1064123
+1 92 1 1 2 1 298 54 33 0.40 1.80 49708 11652 0.00 0.00 0.00 0.00 0.00 0.80 1.60 19.00 27.00 1.8 3916 1831197
+1 94 1 1 11 8 1559 148 116 0.60 0.40 199193 222198 0.00 0.00 0.00 0.00 0.00 4.40 7.20 37.40 80.40 3.8 2410 1552424
+1 98 1 1 0 0 160 17 14 0.20 0.20 2535 5991 0.00 0.00 0.00 0.00 0.00 0.00 0.00 21.20 16.80 1.2 8073 1834968
+1 94 1 1 2 0 1367 83 63 1.40 4.20 97573 20902 2.60 2.60 2.60 0.00 1.00 0.60 0.60 54.40 81.00 1.4 215 1750114
+1 74 1 1 5 0 4896 168 120 4.00 8.40 137924 143835 7.40 11.60 10.20 0.00 0.80 6.80 11.20 253.80 387.00 3.8 300 1015395
+1 95 1 1 1 0 1380 58 61 0.20 0.20 54217 79770 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.60 17.60 2.0 4671 1726971
+1 95 1 1 1 1 470 48 35 0.40 0.40 160644 60051 0.00 0.00 0.00 0.00 0.00 6.60 13.20 30.40 42.20 1.0 8717 1834907
+1 94 1 1 2 1 2587 198 100 0.20 0.20 956702 135821 0.00 0.00 0.00 0.00 0.00 2.80 2.80 17.00 90.40 6.0 642 1306768
+1 77 1 1 11 3 5387 362 355 2.80 2.20 298240 160510 0.00 0.00 0.00 0.00 0.00 8.40 9.40 262.80 264.00 7.0 396 1340256
+1 86 1 1 2 1 845 50 36 0.60 2.00 35281 7141 0.00 0.00 0.00 0.00 0.00 1.00 1.00 34.60 49.80 3.2 519 1715462
+1 96 1 1 2 0 1626 70 41 0.80 0.40 15766 21115 0.00 0.00 0.00 0.00 0.00 0.00 0.00 47.70 63.93 1.2 8342 1868431
+1 83 1 1 9 0 4601 216 153 2.00 2.60 118313 27230 2.40 2.40 2.40 0.00 0.40 11.00 17.60 111.80 222.20 3.6 319 1111411
+1 93 1 1 1 0 214 30 32 0.20 0.20 2422 6393 0.00 0.00 0.00 0.00 0.00 0.20 0.20 17.37 20.96 2.0 489 1738949
+1 95 1 1 0 0 906 187 50 0.20 0.20 194669 144179 0.00 0.00 0.00 0.00 0.00 2.20 4.40 15.60 17.40 4.0 1082 1753923
+1 95 1 1 14 18 282 23 29 0.40 0.40 7368 11958 0.00 0.00 0.00 0.00 0.00 0.80 1.00 29.80 40.20 1.2 7665 1871163
+1 90 1 1 4 1 1919 126 121 0.80 0.40 32030 174094 2.20 2.20 2.20 0.00 0.40 2.40 2.40 57.49 95.21 1.5 232 978611
+1 91 1 1 2 0 3500 380 219 0.40 0.60 120741 28679 0.20 0.40 0.40 0.00 0.00 6.40 7.80 33.40 59.60 1.5 257 1101704
+1 77 1 1 32 10 2843 330 185 7.58 4.79 243642 129323 0.00 0.00 0.00 0.00 0.00 1.40 2.20 331.34 641.52 6.2 1048 1553491
+1 81 1 1 15 11 5885 231 159 0.80 3.20 224023 51705 8.80 14.60 39.00 72.80 6.80 37.60 43.20 43.40 113.00 1.6 150 1006387
+1 98 1 1 0 0 189 12 15 0.40 1.20 435 6804 0.00 0.00 0.00 0.00 0.00 0.00 0.00 33.80 35.40 1.0 7918 1880896
+1 92 1 1 1 0 2008 157 91 0.20 0.20 176272 59457 0.00 0.00 0.00 0.00 0.20 1.00 1.20 22.00 17.80 3.2 385 1702584
+1 91 1 1 13 2 2362 112 92 0.60 0.80 40671 13680 0.00 0.00 0.00 0.00 0.00 16.60 100.60 42.40 172.80 3.4 4983 1410806
+1 93 1 1 1 0 1030 49 34 0.40 0.20 94546 25256 0.00 0.00 0.00 0.00 0.00 11.00 14.80 31.80 71.00 1.2 717 1037518
+1 97 1 1 0 0 1296 83 46 0.20 0.20 14795 12066 0.40 0.60 0.40 0.00 0.40 0.80 0.80 15.60 19.40 2.0 301 1709544
+1 90 1 1 23 10 1365 196 145 2.80 0.80 97335 28899 0.00 0.00 0.00 0.00 0.00 0.00 0.00 137.00 185.60 1.8 7263 1863861
+1 91 1 1 41 59 1487 167 82 0.20 0.20 119806 62598 6.00 7.20 7.20 0.00 1.20 6.80 10.20 15.60 85.20 1.7 174 980214
+1 96 1 1 2 1 1413 47 51 0.40 0.60 23046 23823 0.00 0.00 0.00 0.00 0.00 0.00 0.00 39.32 65.47 1.2 1181 1005154
+1 89 1 1 0 0 1769 87 67 0.20 0.20 5565 13635 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 2.0 4169 1774866
+1 90 1 1 40 56 2735 180 137 0.20 0.20 364701 383083 0.00 0.00 0.00 0.00 0.00 1.00 1.00 14.83 22.65 1.3 1181 1017937
+1 94 1 1 24 35 751 89 62 0.20 0.20 89416 20160 0.00 0.00 0.00 0.00 2.40 0.80 0.80 18.96 37.33 1.0 405 1009161
+1 96 1 1 1 0 760 29 31 0.20 0.20 2795 15330 1.00 1.20 1.40 1.20 0.20 0.80 0.80 13.03 54.51 1.0 129 1016087
+1 97 1 1 2 1 252 37 35 0.20 0.20 45099 27346 0.00 0.00 0.00 0.00 0.00 0.40 0.40 16.23 14.83 1.0 7293 1868226
+1 88 1 1 3 0 3089 196 200 0.40 0.60 33992 134141 0.00 0.00 0.00 0.00 0.40 35.27 39.88 29.66 151.50 3.0 583 1063442
+1 83 1 1 223 44 3169 245 254 0.40 1.80 341846 241158 14.60 70.20 119.20 137.60 0.00 14.80 26.80 32.80 194.80 1.0 143 1016059
+1 85 1 1 2 0 3021 336 243 1.40 4.20 174664 129337 5.80 35.80 61.20 131.60 0.20 2.60 2.80 102.80 238.00 1.2 195 1089227
+1 96 1 1 0 0 450 170 40 0.20 0.20 213146 200908 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 79.60 3.4 972 1744448
+1 93 1 1 5 5 2307 116 91 0.20 0.20 67285 70594 17.56 25.15 25.15 0.00 10.78 7.58 11.78 15.57 36.13 1.2 148 1724532
+1 99 1 1 1 1 149 12 14 0.20 0.20 8142 11981 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 8622 1868232
+1 85 1 1 20 8 2659 167 106 2.80 3.60 366490 256385 11.60 39.60 56.20 68.00 4.40 3.00 5.20 197.80 326.00 4.8 174 1539835
+1 96 1 1 1 0 383 100 33 0.60 0.80 654200 182333 0.00 0.00 0.00 0.00 0.00 0.00 0.00 34.40 50.60 2.8 5679 1837142
+1 95 1 1 1 1 1199 75 59 0.40 0.40 19530 29379 0.00 0.00 0.00 0.00 0.00 0.00 0.00 38.20 48.40 2.0 3011 1707638
+1 61 1 1 45 0 3910 282 166 11.58 32.73 103815 31905 5.39 28.74 35.33 54.89 0.00 14.37 17.56 424.75 811.78 1.8 142 1101212
+1 83 1 1 23 9 2195 171 141 2.40 4.40 121359 54590 20.60 25.40 25.40 0.00 15.80 19.60 24.40 128.80 218.20 3.0 195 1295782
+1 86 1 1 6 2 3727 228 203 1.40 1.20 118911 202558 2.80 4.20 4.20 0.00 7.00 15.20 15.20 97.20 350.80 1.0 283 1001634
+1 96 1 1 1 1 491 62 57 0.20 0.20 35989 9102 0.00 0.00 0.00 0.00 0.00 0.80 0.80 16.00 21.40 2.2 1081 1708304
+1 97 1 1 0 0 186 17 29 0.20 0.20 463 2680 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7420 1866392
+1 88 1 1 34 46 1888 171 118 1.20 3.01 30939 20025 0.20 0.20 0.20 0.00 0.60 2.40 2.61 101.80 129.26 2.0 332 1106624
+1 94 1 1 3 2 1042 93 71 0.40 0.40 85904 36139 0.00 0.00 0.00 0.00 0.00 0.20 0.20 29.80 57.00 2.2 1566 1538107
+1 97 1 1 1 0 1195 52 68 0.20 0.20 19030 47276 2.00 2.20 2.20 0.00 0.20 1.00 1.00 18.00 17.60 3.0 192 1719048
+1 95 1 1 0 0 494 23 24 0.20 0.20 1091 11026 0.20 0.20 0.20 0.00 0.00 0.80 0.80 15.60 16.80 1.2 284 1751064
+1 89 1 1 1 1 2706 144 226 0.20 0.20 77750 480168 3.80 5.80 5.80 0.00 0.40 10.20 13.00 15.20 38.00 2.4 159 1386030
+1 92 1 1 4 1 2727 232 132 0.80 2.40 10052 25310 4.20 5.60 14.00 34.20 0.00 10.40 11.00 49.20 93.80 1.0 147 983053
+1 77 1 1 4 0 815 125 44 2.60 2.40 726462 152999 0.00 0.00 0.00 0.00 0.00 6.00 8.60 231.60 231.80 2.0 2170 1817514
+1 97 1 1 1 1 212 41 37 0.20 0.20 256240 253263 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 2.4 4639 1827776
+1 89 1 1 3 0 1712 240 223 2.60 0.80 68879 24541 0.00 0.00 0.00 0.00 0.00 1.20 1.20 130.80 184.00 1.0 941 1064504
+1 89 1 1 3 1 1084 95 34 2.60 3.00 406873 20007 0.00 0.00 0.00 0.00 0.00 8.60 16.20 102.20 382.00 2.6 7141 1873899
+1 98 1 1 0 0 282 38 30 0.20 0.20 29983 7955 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 19.40 2.0 845 1722362
+1 88 1 1 15 20 413 38 23 2.20 2.20 80964 22418 0.00 0.00 0.00 0.00 0.00 3.40 5.80 192.20 180.80 1.2 6812 1855458
+1 80 1 1 80 45 4068 450 312 2.20 3.60 311482 221885 12.20 32.40 79.60 113.80 13.60 3.40 8.80 132.00 268.40 1.0 170 1097622
+1 92 1 1 11 10 2961 141 102 0.20 0.20 94910 22005 0.00 0.00 0.00 0.00 0.60 3.59 3.59 18.76 54.89 1.0 329 976061
+1 94 1 1 5 3 834 92 58 0.20 0.20 16364 32224 0.00 0.00 0.00 0.00 0.00 6.40 6.40 23.00 48.40 1.0 669 1018867
+1 92 1 1 1 0 1773 98 121 0.40 0.40 48938 29183 2.20 3.00 4.00 1.80 3.20 3.20 5.00 37.60 82.40 4.0 150 1053547
+1 84 1 1 2 1 4502 256 169 0.20 0.20 191500 262830 0.40 0.80 0.40 0.00 0.00 12.60 14.80 16.00 104.00 4.6 1673 1000469
+1 83 1 1 58 33 3809 176 142 4.00 4.40 237419 121316 0.00 0.00 0.00 0.00 0.20 1.40 2.00 188.20 330.40 3.6 1202 1543408
+1 77 1 1 156 164 5119 328 242 2.60 1.40 270639 219650 1.80 7.80 10.60 11.00 0.00 8.20 21.60 149.20 218.60 3.8 178 1328544
+1 96 1 1 0 0 345 179 36 0.20 0.20 28958 14830 0.00 0.00 0.00 0.00 0.00 3.40 6.60 15.60 16.80 1.2 5286 1858259
+1 83 1 1 9 1 1983 193 120 2.60 1.80 265901 36296 3.20 9.00 88.00 129.00 2.00 20.00 43.80 165.60 360.00 2.2 152 1122034
+1 98 1 1 1 1 262 49 13 0.20 0.20 36285 9884 0.00 0.00 0.00 0.00 0.00 0.00 0.00 23.60 16.80 1.8 7914 1869864
+1 81 1 1 3 0 1755 344 251 2.60 5.80 686906 120820 0.00 0.00 0.00 0.00 0.00 9.00 17.40 189.00 318.80 2.8 2492 1730610
+1 87 1 1 3 1 597 59 42 2.20 2.20 196705 159142 0.00 0.00 0.00 0.00 0.00 8.80 15.60 216.40 201.60 1.4 5263 1842539
+1 93 1 1 13 9 1555 165 96 0.60 0.60 90145 58107 1.40 4.19 4.39 0.60 1.00 2.40 9.38 36.33 88.82 1.5 207 967243
+1 96 1 1 13 11 913 143 66 0.20 0.20 182190 185325 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.37 38.52 3.0 2558 1578943
+1 91 1 1 64 91 2057 144 114 1.00 0.80 104539 55435 3.20 3.40 3.40 0.00 0.80 2.80 3.00 58.00 196.40 2.2 331 1014939
+1 97 1 1 1 1 755 72 47 0.20 0.20 3357 10955 0.00 0.00 0.00 0.00 0.00 0.20 0.40 21.04 17.64 1.4 1266 1749158
+1 83 1 1 24 7 1528 263 157 1.60 2.40 136375 55872 28.40 67.00 110.20 216.40 1.20 22.60 42.40 115.60 325.80 1.2 194 984714
+1 90 1 1 29 33 1025 122 116 4.60 3.20 62602 24649 0.00 0.00 0.00 0.00 0.00 1.00 1.40 182.20 273.60 1.6 7207 1874082
+1 86 1 1 9 0 3332 291 220 2.40 1.60 202138 67219 2.60 3.20 4.80 4.20 1.80 2.00 2.60 151.00 241.20 1.3 204 1089602
+1 89 1 1 0 0 2351 180 98 0.20 0.20 51956 50448 0.00 0.00 0.00 0.00 0.00 6.40 8.40 15.40 24.80 1.8 687 1769155
+1 93 1 1 0 0 574 41 39 0.20 0.20 1714 16923 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 2.0 1053 1763003
+1 97 1 1 7 3 267 46 14 0.20 0.20 280930 20146 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 18.60 1.6 7252 1848043
+1 97 1 1 0 0 485 44 30 0.20 0.20 8144 16480 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.4 332 1752946
+1 0 1 1 18 9 1401 91 81 2.00 2.00 210993 71322 8.00 32.20 64.00 107.00 1.60 13.40 13.40 112.60 228.40 196 87 12
+1 93 1 1 0 0 355 34 33 0.20 0.20 721 7999 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 2.2 4090 1773341
+1 91 1 1 4 4 1333 93 90 0.40 0.60 160801 50962 0.00 0.00 0.00 0.00 0.60 0.20 0.20 35.27 101.20 2.2 572 1128707
+1 96 1 1 1 0 1407 59 63 0.20 0.20 9532 14289 0.00 0.00 0.00 0.00 0.00 0.60 0.60 31.60 36.80 3.0 1225 1723778
+1 86 1 1 7 0 1660 259 206 1.60 8.00 34805 30923 2.60 13.20 59.20 91.80 0.20 5.80 8.20 244.60 223.00 3.0 136 1688477
+1 76 1 1 19 8 4413 146 107 2.80 9.80 309773 120556 0.00 0.00 0.00 0.00 0.00 0.40 0.40 241.80 242.60 4.6 949 1539846
+1 68 1 1 404 2 5093 441 359 7.80 9.20 270723 60705 0.00 0.00 0.00 0.00 1.00 15.00 15.40 449.00 634.60 7.2 2471 1378088
+1 91 1 1 1 0 1412 112 121 0.60 0.60 32016 40720 0.00 0.00 0.00 0.00 0.00 3.60 3.60 55.20 69.60 3.0 2511 1701450
+1 95 1 1 1 0 1729 125 58 0.20 0.20 169465 22569 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.4 6122 1729688
+1 90 1 1 16 1 1933 419 153 0.20 0.20 404583 184246 0.00 0.00 0.00 0.00 0.40 23.20 45.40 22.80 61.00 4.8 2811 1603837
+1 88 1 1 71 95 1799 188 93 1.00 2.80 664266 115590 0.00 0.00 0.00 0.00 0.60 2.60 3.00 117.00 124.20 2.2 1950 1004462
+1 93 1 1 17 24 917 168 61 0.80 0.80 561752 238652 0.00 0.00 0.00 0.00 0.00 0.00 0.00 65.87 86.23 2.8 1022 1756295
+1 77 1 1 9 0 3170 444 385 9.42 2.81 239357 23472 0.60 0.80 0.80 0.00 0.40 0.00 0.00 439.48 639.88 1.2 207 1748329
+1 80 1 1 21 14 4043 483 428 6.00 1.60 200212 31160 0.60 0.60 0.60 0.00 0.00 0.20 0.20 290.20 432.40 1.0 235 1074389
+1 94 1 1 1 0 1423 104 65 0.20 0.20 4577 25310 0.00 0.00 0.00 0.00 0.00 11.60 11.60 28.20 45.40 2.0 631 1069803
+1 92 1 1 20 30 1247 158 131 0.60 1.20 77944 30633 0.00 0.00 0.00 0.00 0.00 1.80 4.60 41.40 85.00 3.6 1360 1074344
+1 76 1 1 22 13 2209 132 56 8.18 20.56 152594 18607 0.00 0.00 0.00 0.00 0.00 6.99 8.78 355.49 566.87 1.0 744 1098283
+1 88 1 1 15 11 1243 154 50 4.00 4.00 947897 21624 0.00 0.00 0.00 0.00 0.00 0.00 0.00 172.60 286.20 2.0 3132 1845621
+1 89 1 1 2 0 1734 89 61 1.20 2.80 39725 23738 0.00 0.00 0.00 0.00 0.00 7.60 8.60 81.20 138.40 1.0 1452 1085187
+1 75 1 1 16 8 3665 293 271 6.41 4.81 190369 174297 0.00 0.00 0.00 0.00 0.20 12.42 13.23 410.42 565.73 1.0 725 988733
+1 94 1 1 3 1 2428 149 108 0.40 0.40 20081 174651 4.80 5.20 5.20 0.00 0.60 1.60 1.60 32.80 58.20 2.4 237 1519549
+1 98 1 1 1 0 223 13 21 0.20 0.20 5489 70655 0.00 0.00 0.00 0.00 0.00 0.20 0.20 22.20 18.80 1.0 7369 1862755
+1 89 1 1 4 2 2065 171 133 1.60 1.40 47486 64173 0.00 0.00 0.00 0.00 0.60 2.00 2.20 103.60 131.20 2.5 531 1059970
+1 74 1 1 34 13 5633 306 187 2.60 8.00 507057 151253 2.40 2.80 2.80 0.00 1.80 4.40 6.40 172.60 376.60 5.4 414 1314480
+1 82 1 1 7 2 2570 277 119 2.58 4.37 250167 21618 8.55 60.24 134.39 419.88 0.40 96.02 96.62 152.09 460.83 1.3 118 1123723
+1 92 1 1 5 2 1065 82 32 1.20 7.40 313886 8359 0.00 0.00 0.00 0.00 0.00 5.00 5.20 84.60 109.00 2.0 3223 1741526
+1 90 1 1 9 2 1831 158 119 0.60 0.80 104249 56308 0.00 0.00 0.00 0.00 0.00 4.40 5.20 83.40 162.00 5.8 480 1521358
+1 51 1 1 52 0 4682 357 222 12.60 34.40 290329 134230 12.80 58.60 138.60 330.80 0.60 56.60 67.00 504.20 943.00 3.0 134 1098146
+1 88 1 1 177 197 2319 186 134 0.60 0.80 367421 41690 0.00 0.00 0.00 0.00 0.00 1.80 2.60 49.40 76.40 1.2 533 1094643
+1 0 1 1 36 48 1667 95 78 0.40 0.40 18151 24364 0.00 0.00 0.00 0.00 0.00 3.19 4.59 34.53 39.92 550 91 9
+1 95 1 1 5 2 2073 73 62 0.20 0.20 9212 28959 0.80 0.80 0.80 0.00 0.40 2.20 2.20 16.60 51.40 2.0 278 1014352
+1 97 1 1 1 0 678 94 86 0.20 0.20 16341 28843 0.00 0.00 0.00 0.00 0.00 1.00 1.20 15.80 22.20 1.3 394 1091904
+1 76 1 1 15 9 4803 327 309 1.40 2.99 168100 559019 1.40 2.59 2.40 0.00 1.20 17.76 23.35 94.01 304.79 1.5 534 992567
+1 96 1 1 6 2 1705 154 172 0.20 0.20 159052 60606 0.00 0.00 0.00 0.00 0.00 1.40 2.20 21.00 41.00 5.0 2027 1367739
+1 96 1 1 24 32 366 25 37 0.20 0.20 7746 113906 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.20 17.40 1.2 5685 1840018
+1 91 1 1 2 1 452 116 58 0.40 0.40 255513 172909 0.00 0.00 0.00 0.00 0.00 2.20 2.80 36.20 42.20 2.8 4047 1827405
+1 69 1 1 39 0 5830 921 784 3.60 1.80 417541 127394 3.40 23.40 82.20 150.00 0.80 32.00 44.20 159.80 421.20 3.2 147 1046022
+1 89 1 1 14 1 1212 86 67 4.60 3.40 191330 105806 0.00 0.00 0.00 0.00 0.00 7.80 8.20 195.60 335.60 4.2 1253 1544406
+1 0 1 1 12 1 2466 193 189 3.19 2.00 105786 83337 0.00 0.00 0.00 0.00 0.00 2.40 3.19 173.85 243.11 440 87 13
+1 83 1 1 2 1 2648 199 159 1.60 2.00 115891 220023 0.00 0.00 0.00 0.00 0.40 10.00 14.80 131.60 248.60 3.4 498 1016256
+1 90 1 1 31 0 1033 174 73 0.80 0.80 506006 16902 0.00 0.00 0.00 0.00 0.00 12.00 71.40 63.60 176.40 3.8 389 1718456
+1 53 1 1 29 6 7029 678 599 7.78 3.59 528984 237007 9.18 48.10 137.33 286.23 2.99 52.30 79.04 453.89 662.67 9.0 190 1538338
+1 93 1 1 6 1 2257 87 74 0.80 4.40 132983 35334 2.60 4.60 4.00 0.00 1.40 7.20 24.00 33.00 82.00 2.0 168 1024461
+1 87 1 1 29 11 984 106 79 5.20 3.20 132091 47371 0.00 0.00 0.00 0.00 0.00 2.00 4.40 217.60 419.80 4.8 6101 1707683
+1 93 1 1 3 1 1044 32 44 1.20 2.60 54971 146349 0.00 0.00 0.00 0.00 0.00 0.00 0.00 93.00 118.00 1.4 6888 1852709
+1 95 1 1 5 4 796 58 51 0.20 0.20 16130 37792 4.01 6.41 5.61 0.00 1.00 1.80 1.80 19.24 59.52 2.0 234 1011745
+1 96 1 1 21 33 744 77 22 0.20 0.20 254058 8938 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.60 17.40 1.6 1836 1752528
+1 93 1 1 2 0 1260 88 63 1.00 1.20 46147 33738 4.80 6.00 6.00 0.60 1.20 10.00 10.40 85.60 176.20 1.0 171 1022195
+1 76 1 1 13 4 5183 200 150 1.60 2.20 237284 93098 0.00 0.00 0.00 0.00 0.00 20.40 28.00 154.60 312.40 6.8 956 1306851
+1 74 1 1 753 22 2350 146 111 2.00 0.60 259768 129649 0.00 0.00 0.00 0.00 0.00 25.00 25.00 97.60 136.20 2.2 4728 1845357
+1 86 1 1 65 77 2089 183 143 0.80 1.40 143046 144665 0.00 0.00 0.00 0.00 0.00 1.40 2.60 68.00 142.80 3.4 791 1631507
+1 93 1 1 1 0 1011 56 56 0.60 1.00 15493 18387 0.00 0.00 0.00 0.00 0.00 19.00 19.00 49.60 139.00 2.8 739 1089934
+1 74 1 1 12 1 3039 191 121 7.40 23.80 158848 24306 1.00 1.00 1.00 0.00 0.60 4.00 4.00 269.60 495.00 1.8 287 1085333
+1 81 1 1 6 1 2298 140 82 0.80 2.20 345233 10552 21.80 183.80 342.20 497.40 0.60 36.40 51.00 53.60 571.60 6.8 150 1314242
+1 89 1 1 3 2 2490 325 227 0.60 2.20 211769 308763 0.00 0.00 0.00 0.00 2.40 11.00 12.60 54.40 146.20 2.2 410 1381683
+1 94 1 1 6 4 1258 109 90 0.20 0.20 89056 23533 0.00 0.00 0.00 0.00 0.00 1.40 11.80 16.60 23.80 1.7 1785 1092926
+1 98 1 1 2 1 214 10 14 0.20 0.20 9873 44773 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.0 7731 1866403
+1 87 1 1 68 55 1596 181 170 2.20 1.00 56289 51077 19.84 44.49 96.39 190.18 0.40 26.45 51.30 113.23 228.46 1.5 160 951163
+1 75 1 1 14 9 4058 263 227 7.01 4.41 173227 92769 2.20 3.61 23.85 43.29 1.00 4.01 4.41 311.82 482.57 2.0 293 1123827
+1 94 1 1 1 0 1634 151 66 0.20 0.20 212436 200402 0.00 0.00 0.00 0.00 0.00 11.20 11.20 20.00 47.80 4.8 2524 1604440
+1 80 1 1 7 1 4504 303 255 1.20 1.80 164442 165346 19.40 42.60 57.80 54.40 0.20 9.60 17.80 132.20 136.00 1.4 150 1000069
+1 98 1 1 10 3 417 23 40 0.40 0.40 26568 27852 0.00 0.00 0.00 0.00 0.00 0.00 0.00 32.00 38.60 1.0 6217 1856637
+1 91 1 1 0 0 1774 100 66 0.40 1.80 109071 26956 10.00 17.20 24.80 47.20 2.60 1.20 1.20 33.00 58.60 1.0 176 1009816
+1 89 1 1 80 48 2115 100 118 1.20 1.60 59217 109468 4.20 16.00 33.80 38.80 1.40 6.60 12.40 184.20 103.60 4.8 131 1597446
+1 81 1 1 5 2 2929 387 204 2.60 2.60 288065 215294 14.40 29.60 26.40 11.00 3.60 2.20 2.60 142.00 249.20 2.0 315 1130874
+1 91 1 1 3 1 3629 244 127 0.40 0.40 863112 81425 0.00 0.00 0.00 0.00 0.00 0.40 0.60 53.80 38.00 3.6 1376 1542600
+1 98 1 1 1 1 212 18 28 0.20 0.20 7031 19891 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7364 1867155
+1 87 1 1 30 43 3816 139 157 0.60 3.20 47471 329880 0.20 0.20 0.20 0.00 0.20 12.00 12.60 24.60 70.40 2.4 2097 993981
+1 81 1 1 5 1 4402 697 228 2.60 5.20 336839 31786 1.60 1.60 1.60 0.00 1.00 20.80 33.20 143.00 291.60 1.3 275 1135856
+1 77 1 1 7 0 3851 377 302 5.96 2.19 189893 18213 0.00 0.00 0.00 0.00 0.00 0.99 1.99 273.76 457.06 1.0 1970 1070584
+1 80 1 1 26 27 2912 454 369 7.40 2.00 206378 14665 0.00 0.00 0.00 0.00 0.00 0.00 0.00 365.80 525.00 3.0 11640 1881640
+1 96 1 1 3 1 2193 97 80 0.40 0.40 6145 51522 0.00 0.00 0.00 0.00 0.00 0.00 0.00 34.00 34.40 2.0 3257 1657443
+1 73 1 1 30 6 5661 339 186 5.19 10.98 275673 49066 5.59 14.17 50.30 99.00 4.19 7.78 8.98 318.76 497.01 4.0 144 1456497
+1 95 1 1 1 0 2832 131 92 0.20 0.20 9102 53734 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 23.60 2.0 506 1629285
+1 95 1 1 4 4 2015 67 68 0.40 0.40 5027 16398 0.40 0.40 0.40 0.00 0.60 4.20 4.20 32.40 44.60 2.4 224 1017845
+1 95 1 1 3 2 1872 114 94 0.20 0.20 93509 29910 0.00 0.00 0.00 0.00 0.00 1.40 1.80 57.31 27.05 1.0 874 1054637
+1 91 1 1 7 1 2544 135 126 1.20 2.40 69693 23159 0.00 0.00 0.00 0.00 0.00 2.60 2.80 87.00 143.00 4.0 2892 1375262
+1 81 1 1 14 12 6140 319 203 0.80 0.80 151498 233048 0.00 0.00 0.00 0.00 0.00 4.20 5.00 58.80 101.80 3.8 841 999741
+1 90 1 1 22 13 3581 211 134 1.00 1.20 312204 31194 0.00 0.00 0.00 0.00 1.20 4.40 5.40 90.60 164.80 4.2 871 1529306
+1 94 1 1 1 0 1704 82 159 0.20 0.20 59686 170281 0.00 0.00 0.00 0.00 0.00 5.19 7.19 12.77 17.56 1.4 7735 1867811
+1 90 1 1 42 58 2302 145 125 0.40 0.60 10686 50059 0.00 0.00 0.00 0.00 0.00 10.22 10.42 32.26 92.38 3.8 336 1064146
+1 85 1 1 5 0 2392 234 182 1.40 1.60 352015 308529 18.76 65.67 132.14 256.09 0.00 31.54 61.28 69.66 113.77 2.0 123 1057613
+1 56 1 1 277 296 3809 566 472 7.40 6.40 459817 349319 16.40 39.60 93.80 149.40 4.60 52.60 81.20 350.80 784.20 4.8 207 1039954
+1 97 1 1 1 1 484 53 27 0.40 0.40 133297 20706 0.00 0.00 0.00 0.00 0.00 2.00 3.80 31.00 43.00 1.0 8767 1835240
+1 94 1 1 17 23 225 13 13 0.40 1.60 17132 12514 0.00 0.00 0.00 0.00 0.00 0.00 0.00 19.80 23.80 1.2 4179 1821682
+1 90 1 1 4 2 1604 179 73 1.80 2.00 51542 16999 0.00 0.00 0.00 0.00 0.00 2.00 3.80 118.20 151.00 2.3 693 1069450
+1 95 1 1 1 0 310 43 22 0.80 1.00 242869 14502 0.00 0.00 0.00 0.00 0.00 0.00 0.00 48.60 66.60 1.2 7202 1874066
+1 84 1 1 76 71 3089 185 139 0.20 0.20 67708 59295 3.40 15.40 60.60 77.00 0.00 16.80 28.40 17.40 59.20 2.0 126 1065362
+1 74 1 1 17 0 4962 546 485 8.20 2.20 229511 27746 0.00 0.00 0.00 0.00 0.20 3.40 3.60 384.80 589.40 1.5 232 1069243
+1 96 1 1 2 1 1338 82 48 0.20 0.20 197875 12946 0.00 0.00 0.00 0.00 0.00 0.60 1.20 23.60 24.00 1.0 5579 1832957
+1 65 1 1 8 0 3934 407 137 7.60 8.20 129213 18723 2.00 4.40 21.60 37.60 0.40 4.40 4.80 331.80 818.80 1.3 181 1035285
+1 88 1 1 12 11 3773 229 154 0.20 0.20 161126 35443 2.59 3.99 3.99 0.00 0.20 5.19 7.98 116.97 199.40 2.0 257 998285
+1 97 1 1 35 1 672 62 57 0.20 0.20 1791 8352 0.00 0.00 0.00 0.00 0.00 0.20 0.40 20.40 18.60 2.2 4046 1710048
+1 86 1 1 3 2 1997 239 91 1.00 1.20 998097 93669 0.00 0.00 0.00 0.00 0.00 2.60 3.40 88.00 120.80 2.8 2730 1089893
+1 96 1 1 23 13 1379 99 90 0.40 0.40 41732 84195 3.00 7.00 7.00 0.00 1.20 3.60 4.20 33.80 46.20 2.4 213 1719302
+1 98 1 1 1 1 178 12 13 0.20 0.20 7021 5203 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7382 1865536
+1 95 1 1 1 0 749 81 138 0.60 0.60 289878 27455 0.00 0.00 0.00 0.00 0.00 18.60 18.60 50.40 106.80 3.2 1084 1716637
+1 81 1 1 5 1 1596 182 107 0.20 0.20 818686 79474 9.58 36.13 55.49 73.45 1.60 88.82 154.69 16.97 97.60 4.4 303 1328899
+1 93 1 1 1 1 1342 153 79 0.20 0.20 75258 19540 0.00 0.00 0.00 0.00 0.00 1.00 1.80 39.00 62.80 2.2 422 988357
+1 95 1 1 47 44 1484 77 71 0.60 0.60 26243 27853 0.00 0.00 0.00 0.00 0.00 0.40 0.40 39.60 47.20 3.0 10789 1382502
+1 93 1 1 26 34 3007 113 190 0.20 0.20 12781 31510 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.57 16.77 2.2 224 1705333
+1 83 1 1 7 7 3572 241 189 0.80 2.20 448266 258824 0.00 0.00 0.00 0.00 0.20 33.60 33.60 33.60 94.00 6.2 2044 1640795
+1 92 1 1 1 0 1411 314 145 0.20 0.20 6590 26933 0.40 0.40 0.40 0.00 0.20 0.20 0.20 15.40 23.20 2.0 135 1057440
+1 84 1 1 3 0 437 38 29 2.00 2.00 59422 19164 6.20 6.20 6.20 0.00 0.00 1.60 1.60 167.00 151.40 3.0 152 1783864
+1 92 1 1 10 8 1697 159 124 0.20 0.20 367223 88343 0.00 0.00 0.00 0.00 0.00 3.60 4.20 20.20 19.20 3.4 4712 1671243
+1 88 1 1 5 0 594 107 67 2.00 2.00 46657 16271 0.00 0.00 0.00 0.00 0.00 0.00 0.00 76.60 132.20 2.0 1263 1767294
+1 80 1 1 62 77 2892 164 100 3.40 5.00 158542 45853 5.80 7.40 7.40 0.00 2.40 11.20 12.20 193.60 461.40 3.5 258 1019354
+1 89 1 1 13 3 2120 277 214 0.80 2.20 62230 30983 0.00 0.00 0.00 0.00 0.00 1.20 1.20 43.60 82.20 2.2 3105 1737642
+1 97 1 1 6 3 320 21 77 0.60 1.00 23609 116219 0.00 0.00 0.00 0.00 0.00 0.00 0.00 41.00 53.00 2.0 6521 1705557
+1 91 1 1 1 0 1272 132 96 0.60 1.20 264635 27883 0.00 0.00 0.00 0.00 0.00 3.80 6.80 33.40 83.00 1.0 1200 1131838
+1 96 1 1 0 0 887 115 51 0.20 0.20 132347 125126 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.60 3.6 1369 1755973
+1 75 1 1 64 84 6784 279 244 2.20 2.00 360337 273583 19.36 45.51 73.65 97.41 2.00 18.56 28.74 125.55 230.94 2.0 139 1002892
+1 91 1 1 3 1 3745 155 180 0.20 0.20 17499 102233 0.00 0.00 0.00 0.00 0.00 8.40 8.60 18.00 63.60 1.0 684 1061171
+1 93 1 1 5 1 928 136 42 1.60 2.00 339827 25101 0.00 0.00 0.00 0.00 0.00 6.80 7.40 116.60 166.80 1.6 7607 1879741
+1 95 1 1 2 2 2264 131 104 0.20 0.20 5816 20602 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.40 17.80 2.2 3116 1707682
+1 84 1 1 5 2 4617 460 217 1.20 1.20 122675 148030 0.00 0.00 0.00 0.00 0.00 6.99 7.39 78.44 164.87 3.0 1894 1001723
+1 88 1 1 6 3 2514 161 140 1.80 3.00 216786 186596 0.00 0.00 0.00 0.00 0.00 1.20 1.40 123.60 225.00 4.8 1565 1615507
+1 81 1 1 10 6 3269 216 143 2.60 7.00 60686 42719 0.00 0.00 0.00 0.00 0.00 0.40 0.40 208.80 242.00 2.4 647 1536179
+1 82 1 1 94 57 2937 259 214 4.00 6.20 180958 92968 0.00 0.00 0.00 0.00 0.60 2.40 2.40 217.00 362.40 2.4 541 1318082
+1 89 1 1 3 0 1036 117 28 2.00 2.80 231364 17195 0.00 0.00 0.00 0.00 0.00 0.60 0.60 151.00 202.80 1.4 1001 1762766
+1 0 1 1 89 53 2558 211 189 0.60 1.00 215246 121020 0.00 0.00 0.00 0.00 0.20 13.97 17.37 236.93 171.06 990 84 16
+1 96 1 1 2 1 785 48 44 0.40 1.40 39338 13540 2.60 5.20 5.20 0.00 0.60 0.00 0.00 53.80 82.00 2.0 279 992654
+1 91 1 1 6 4 3096 226 119 0.80 1.40 300310 78270 5.80 12.20 28.40 37.80 1.60 0.60 0.60 77.40 188.80 6.6 143 1585784
+1 89 1 1 13 6 3069 173 94 1.40 1.60 131542 105250 0.00 0.00 0.00 0.00 0.00 3.40 5.40 141.60 125.40 4.4 2549 1576858
+1 88 1 1 45 53 623 24 51 1.80 1.80 41854 212631 0.00 0.00 0.00 0.00 0.00 1.60 2.40 122.80 212.40 2.0 5071 1841507
+1 70 1 1 72 47 3260 327 161 9.60 8.60 182659 86331 12.40 40.20 81.20 212.20 2.80 8.60 24.00 437.60 792.60 1.0 153 1062189
+1 94 1 1 3 0 1008 72 58 2.20 3.59 53647 14442 2.20 6.99 10.58 17.17 0.20 0.00 0.00 162.67 198.40 2.2 211 997396
+1 65 1 1 10 1 3917 490 883 8.38 3.59 286623 132176 7.78 7.78 7.78 0.00 0.20 0.80 0.80 464.27 611.98 2.0 245 1802988
+1 81 1 1 55 75 3010 337 149 3.60 4.00 226170 131109 11.20 45.20 131.00 269.20 0.60 14.80 26.80 202.20 378.80 2.0 152 1073067
+1 93 1 1 32 46 2016 153 132 0.60 1.60 23334 18460 5.41 5.61 5.61 0.00 3.81 14.23 14.23 35.67 88.98 1.0 272 1026328
+1 98 1 1 19 28 488 138 34 0.20 0.20 178356 159984 0.00 0.00 0.00 0.00 0.00 0.00 0.00 14.51 12.92 2.2 5481 1817940
+1 98 1 1 0 0 190 19 28 0.20 0.20 450 11459 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.6 7368 1869294
+1 95 1 1 0 0 2635 141 156 0.20 0.20 5803 19417 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 2.0 280 1705852
+1 86 1 1 16 11 1869 177 115 1.60 3.20 33870 57258 22.20 41.00 95.60 125.00 16.00 34.20 43.40 134.20 273.60 1.5 139 988286
+1 98 1 1 1 1 189 10 13 0.20 0.20 7004 7560 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7650 1869904
+1 98 1 1 12 16 413 19 11 0.20 0.20 8327 2462 0.00 0.00 0.00 0.00 0.00 0.20 0.20 13.00 16.80 1.4 4607 1828310
+1 0 1 1 20 14 2173 460 246 1.40 2.20 626503 563710 0.00 0.00 0.00 0.00 0.00 0.60 0.60 87.37 131.66 745 91 9
+1 89 1 1 15 22 1561 85 87 0.20 0.20 29881 61900 0.00 0.00 0.00 0.00 0.00 1.00 1.60 15.60 17.00 1.6 4236 1780024
+1 96 1 1 1 0 502 47 53 0.20 0.20 4534 26789 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.20 1.5 379 1091186
+1 83 1 1 1 0 2792 411 245 0.60 2.00 182393 43918 0.00 0.00 0.00 0.00 0.40 1.60 1.80 55.80 137.20 1.0 680 1120920
+1 90 1 1 43 60 3084 261 155 1.40 3.80 21092 62289 3.20 4.80 4.80 0.00 0.20 1.00 1.40 110.40 137.80 2.6 274 1537773
+1 95 1 1 6 2 1197 113 133 0.60 0.60 83006 85799 0.00 0.00 0.00 0.00 0.00 1.00 1.00 58.00 95.20 2.2 1044 1544781
+1 98 1 1 2 1 332 54 30 0.20 0.20 88639 6183 0.00 0.00 0.00 0.00 0.00 0.20 0.40 20.84 18.84 1.0 588 1736382
+1 86 1 1 2 0 2585 203 145 0.60 0.60 329604 126738 1.00 1.80 1.00 0.00 0.80 29.46 30.46 49.90 194.39 1.0 451 1057294
+1 72 1 1 40 38 2674 251 114 5.40 16.20 458665 19089 7.20 33.20 111.80 221.60 0.00 48.60 107.20 209.60 408.20 2.0 134 1102896
+1 82 1 1 2 0 2959 372 250 1.40 1.40 946962 160148 9.00 37.60 87.60 228.80 0.00 31.40 49.60 82.00 194.80 1.0 152 1034645
+1 95 1 1 29 39 239 32 24 0.40 0.80 1216 6747 0.00 0.00 0.00 0.00 0.00 0.00 0.00 33.53 33.93 1.2 7038 1848915
+1 82 1 1 7 6 3970 367 169 1.40 3.20 580469 69074 2.40 3.20 3.00 0.00 1.20 18.60 22.00 69.80 287.20 3.4 415 1095523
+1 91 1 1 9 1 1720 120 127 1.00 2.79 295270 85183 0.00 0.00 0.00 0.00 0.20 5.79 5.79 78.24 169.86 2.0 579 1064374
+1 91 1 1 3 3 2070 176 118 0.60 1.00 19761 26919 0.00 0.00 0.00 0.00 0.00 2.79 2.99 56.69 96.21 2.3 499 1119318
+1 96 1 1 1 0 843 83 56 0.40 0.60 73773 21665 0.00 0.00 0.00 0.00 0.00 0.40 0.40 29.20 150.40 4.0 625 1032739
+1 86 1 1 59 45 1503 113 76 1.80 1.80 322275 27068 0.60 0.60 0.60 0.00 1.20 6.81 18.24 128.46 251.90 1.8 499 1104940
+1 84 1 1 8 1 2025 315 249 6.40 2.40 412247 27624 0.00 0.00 0.00 0.00 0.00 3.80 7.00 305.80 446.80 2.0 5317 1860229
+1 56 1 1 119 0 2773 289 109 13.20 38.80 104786 39867 0.00 0.00 0.00 0.00 0.60 65.20 65.20 488.40 916.00 1.5 821 1086093
+1 88 1 1 0 0 406 36 49 0.20 0.20 29231 39596 0.00 0.00 0.00 0.00 0.00 1.00 1.40 14.63 17.43 1.2 1839 1770817
+1 73 1 1 19 17 5367 374 258 1.20 1.00 359434 97984 28.34 50.70 96.81 136.13 15.77 52.30 68.66 168.66 325.15 1.3 145 1002831
+1 89 1 1 0 0 2128 206 137 0.40 0.40 164827 42642 5.60 7.80 7.80 0.00 0.80 1.80 2.00 48.40 116.60 1.3 314 1018701
+1 92 1 1 2 1 1169 157 68 1.00 1.40 132714 12006 0.00 0.00 0.00 0.00 0.00 0.40 0.40 80.20 100.40 2.6 1501 1717016
+1 96 1 1 2 1 876 30 29 0.20 0.20 21116 41098 0.00 0.00 0.00 0.00 0.00 1.40 2.60 15.60 16.80 1.0 4609 1828424
+1 87 1 1 1 1 2197 237 135 0.60 0.60 134759 106978 0.00 0.00 0.00 0.00 0.40 15.57 15.57 124.35 179.44 2.0 2186 1006133
+1 96 1 1 2 1 1420 104 77 0.20 0.20 8669 23573 0.40 0.40 0.40 0.00 0.00 1.20 1.20 15.80 23.40 2.5 178 1085574
+1 87 1 1 6 1 4020 498 166 0.60 0.60 122720 183984 0.20 0.20 0.20 0.00 0.00 52.20 52.20 30.80 244.60 1.0 449 1011210
+1 0 1 1 7 6 1844 103 73 0.20 0.20 29186 26099 3.01 4.01 3.61 0.00 0.60 2.61 2.61 17.64 31.46 155 95 5
+1 93 1 1 11 2 2463 113 135 0.20 0.40 175415 121252 1.80 3.61 8.02 40.08 0.80 1.20 1.40 31.06 107.62 2.3 326 1065201
+1 74 1 1 8 1 3287 352 198 6.60 19.60 41143 56011 4.60 5.40 12.20 21.40 0.00 7.80 11.20 228.20 402.60 1.5 132 1114618
+1 72 1 1 37 16 3666 627 255 4.20 4.40 591437 86958 19.20 57.60 87.80 89.20 6.60 23.60 31.20 275.20 591.60 1.5 212 988462
+1 0 1 1 2 1 1436 93 81 0.20 0.20 287757 47872 12.00 24.60 52.00 120.00 0.00 31.40 60.80 20.60 28.20 148 92 8
+1 92 1 1 39 56 2165 175 188 0.20 0.20 6088 38736 5.19 7.19 5.99 0.00 1.80 2.40 2.40 17.56 52.69 3.0 203 1021519
+1 96 1 1 0 0 1669 70 59 0.20 0.20 1920 6021 0.00 0.00 0.00 0.00 0.20 0.60 0.60 16.00 38.60 2.2 2913 1413325
+1 90 1 1 20 16 3029 394 253 0.60 0.40 203625 65382 3.60 6.00 13.80 38.80 0.80 12.00 15.20 38.20 103.20 3.8 168 1396573
+1 62 1 1 42 0 3166 179 114 11.80 35.80 108799 28442 0.00 0.00 0.00 0.00 0.00 12.60 17.60 385.80 727.80 3.0 494 1106408
+1 97 1 1 0 0 936 80 45 0.20 0.20 2024 14523 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.43 17.23 1.0 695 1738148
+1 0 1 1 12 10 2643 131 161 0.40 1.80 86268 58754 0.00 0.00 0.00 0.00 0.00 31.60 31.60 36.40 138.20 473 90 10
+1 92 1 1 7 0 2492 162 114 1.80 3.60 94763 29313 0.00 0.00 0.00 0.00 0.00 0.20 0.20 114.80 155.80 2.2 849 1065258
+1 83 1 1 2 0 2491 322 135 1.60 0.40 1125937 89220 0.00 0.00 0.00 0.00 0.40 2.40 4.60 75.20 115.60 3.0 455 1753202
+1 87 1 1 5 0 1886 150 43 2.80 3.40 210109 20612 3.00 17.20 56.00 116.80 0.60 11.00 11.20 201.20 354.80 3.6 138 1057901
+1 85 1 1 6 4 6341 175 155 1.40 1.80 27121 7526 0.00 0.00 0.00 0.00 0.00 1.00 1.00 106.00 112.60 2.2 647 1447906
+1 82 1 1 7 0 2741 296 246 4.99 2.20 177076 17349 0.80 1.20 1.00 0.00 0.00 7.78 15.37 263.27 391.42 5.6 306 1712469
+1 97 1 1 11 16 161 10 18 0.20 0.20 8627 10411 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 1.0 7306 1873272
+1 66 1 1 208 223 4083 309 198 5.60 17.20 783601 139522 17.40 58.60 68.60 141.00 1.40 37.40 46.80 203.40 503.80 3.2 172 1095856
+1 89 1 1 126 30 1697 258 228 0.40 0.40 92249 127353 5.40 39.20 88.80 146.80 0.40 55.60 65.40 35.40 170.40 1.0 130 975880
+1 98 1 1 0 0 125 9 10 0.20 0.20 431 4174 1.00 1.00 1.00 0.00 0.20 0.00 0.00 13.00 16.80 1.0 298 1755880
+1 92 1 1 1 0 1301 110 108 0.40 0.20 7167 33737 0.00 0.00 0.00 0.00 0.00 1.80 2.60 20.00 20.20 2.6 404 1053701
+1 88 1 1 1 1 3118 281 570 0.40 1.80 34561 111265 0.00 0.00 0.00 0.00 0.00 0.20 0.20 21.60 59.00 2.6 1618 1708282
+1 91 1 1 3 0 1274 139 80 0.60 0.60 218359 26748 1.80 9.02 17.23 22.85 0.00 2.00 2.00 42.89 65.53 5.4 200 1031841
+1 58 1 1 105 59 3864 315 253 13.40 33.00 294096 50699 2.60 7.80 19.20 30.40 0.00 6.60 9.20 487.60 847.40 1.0 253 1093803
+1 82 1 1 1 1 7299 305 185 0.20 0.20 87654 47922 1.00 1.60 1.60 0.00 0.80 1.80 3.40 16.00 49.20 4.0 329 998792
+1 95 1 1 0 0 524 45 140 0.60 0.80 92426 167096 0.20 0.20 0.20 0.00 0.80 0.00 0.00 45.20 60.40 1.2 297 1756365
+1 86 1 1 3 1 694 105 29 2.40 2.40 468844 13454 0.00 0.00 0.00 0.00 0.00 1.60 1.60 202.59 247.50 2.4 11175 1870992
+1 93 1 1 55 72 2533 125 98 0.40 0.40 17712 14029 0.00 0.00 0.00 0.00 0.00 4.80 8.80 37.80 42.00 4.0 690 1642230
+1 87 1 1 5 1 2879 309 414 2.60 4.20 113841 52053 0.00 0.00 0.00 0.00 0.00 1.40 2.80 116.20 201.80 4.4 1722 1698174
+1 93 1 1 0 0 2047 182 99 0.20 0.20 60110 42150 0.60 0.60 0.60 0.00 0.40 1.00 1.60 16.00 17.20 1.0 189 1127664
+1 90 1 1 15 12 2717 263 176 0.60 0.40 193730 83203 0.00 0.00 0.00 0.00 1.40 35.20 41.60 29.40 114.40 6.0 677 1320533
+1 88 1 1 9 0 2548 166 102 2.20 4.60 102717 26704 3.80 4.20 4.20 0.00 1.60 1.60 1.80 71.80 142.40 3.8 178 1112818
+1 92 1 1 29 19 2621 298 138 1.40 1.80 437944 411901 0.00 0.00 0.00 0.00 0.00 16.60 18.00 94.20 171.40 4.2 1022 1343950
+1 85 1 1 2 0 438 48 50 1.60 1.60 72567 33132 0.00 0.00 0.00 0.00 0.00 1.60 2.60 218.00 140.00 2.2 1750 1773152
+1 99 1 1 0 0 215 14 15 0.20 0.20 1747 4054 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 7565 1873980
+1 92 1 1 45 61 976 91 46 1.00 2.60 36445 18870 8.40 11.00 20.40 50.00 0.20 3.60 6.40 85.00 118.40 3.0 213 969363
+1 95 1 1 2 1 659 73 39 0.40 0.40 130243 30148 5.19 15.57 25.15 48.90 0.60 2.00 2.99 21.36 109.98 1.0 142 1022235
+1 70 1 1 10 0 3378 341 278 8.22 18.44 265448 124892 0.40 0.40 0.40 0.00 0.40 14.03 22.44 297.80 525.85 1.0 341 1079413
+1 90 1 1 2 0 603 114 66 1.80 1.40 389786 275961 0.00 0.00 0.00 0.00 0.00 2.60 5.00 80.00 111.00 2.4 3573 1821803
+1 96 1 1 0 0 1506 114 50 0.20 0.20 4736 18382 0.00 0.00 0.00 0.00 0.00 0.20 0.40 16.40 24.80 1.0 579 1734802
+1 91 1 1 0 0 4367 171 145 0.40 0.60 18863 16529 0.00 0.00 0.00 0.00 0.00 0.80 1.40 44.60 68.20 2.2 479 1380597
+1 74 1 1 27 8 3973 282 151 4.20 4.60 508438 192730 5.20 21.40 61.00 129.40 2.80 22.40 31.80 198.40 412.20 1.8 273 1014010
+1 72 1 1 222 212 6706 575 405 4.20 2.00 337384 159262 5.20 20.80 41.60 106.80 0.00 3.60 20.40 217.00 405.80 5.0 214 1331986
+1 95 1 1 1 1 772 66 48 0.20 0.20 3479 22449 0.40 0.60 0.60 0.00 0.40 0.40 0.60 16.17 48.70 1.0 441 1021113
+1 91 1 1 0 0 760 82 48 0.20 0.20 1818 9486 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13.40 16.80 2.0 651 1760472
+1 90 1 1 5 1 850 52 22 1.60 1.60 148143 17755 0.00 0.00 0.00 0.00 0.00 9.58 10.98 145.51 140.32 1.4 8300 1861533
+1 98 1 1 1 1 187 13 18 0.20 0.20 6998 4034 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6132 1856736
+1 86 1 1 29 38 486 50 46 2.20 2.20 125028 61574 0.00 0.00 0.00 0.00 0.00 4.60 8.60 211.80 180.00 2.6 10805 1870795
+1 75 1 1 28 10 5446 210 110 4.00 9.20 172907 31100 0.00 0.00 0.00 0.00 0.00 2.60 2.60 239.00 341.40 4.0 8154 1405525
+1 88 1 1 1 0 3421 253 128 0.80 2.00 85100 23729 3.00 5.00 9.00 26.20 0.00 21.20 21.20 53.60 203.40 2.2 154 1099171
+1 76 1 1 19 0 3670 491 434 8.60 2.40 292630 75181 0.00 0.00 0.00 0.00 0.00 0.00 0.00 409.60 595.00 3.0 1935 1528898
+1 98 1 1 2 2 261 20 25 0.60 0.60 8969 5009 0.00 0.00 0.00 0.00 0.00 0.00 0.00 28.00 40.00 1.0 7391 1865933
+1 97 1 1 1 0 265 80 32 0.40 0.40 108156 11835 0.00 0.00 0.00 0.00 0.00 0.00 0.00 23.80 31.20 2.2 4187 1840552
+1 86 1 1 18 3 2358 224 155 1.80 1.80 132209 23741 0.00 0.00 0.00 0.00 0.00 14.20 22.20 97.60 185.40 1.5 1901 1092824
+1 60 1 1 67 2 4368 241 210 12.20 33.60 128950 51814 2.20 6.60 16.00 23.20 1.00 11.80 12.40 421.00 777.60 1.4 279 1094907
+1 84 1 1 11 3 5890 418 292 1.00 3.40 239153 95900 0.00 0.00 0.00 0.00 0.60 8.00 8.00 45.20 82.40 5.4 1169 1333459
+1 76 1 1 52 35 4627 304 263 2.80 8.00 265763 198083 4.80 25.40 44.20 126.00 0.20 25.20 48.40 185.20 359.20 3.4 986 1401160
+1 77 1 1 10 3 1629 77 59 6.41 18.84 75901 17091 6.41 23.85 26.25 29.86 1.40 21.04 26.45 218.04 458.52 2.0 178 1107962
+1 97 1 1 1 0 461 54 18 0.20 0.20 17735 8554 0.00 0.00 0.00 0.00 0.20 1.80 3.20 15.80 18.00 1.0 579 1752811
+1 97 1 1 1 0 1220 42 50 1.00 1.00 8192 13230 0.00 0.00 0.00 0.00 0.00 0.80 0.80 41.40 59.40 3.2 314 1711651
+1 96 1 1 0 0 1060 113 53 0.20 0.20 180834 19367 3.19 3.59 3.59 0.00 3.59 1.00 1.00 17.37 41.92 1.0 224 1011219
+1 91 1 1 27 35 922 124 83 1.20 1.00 31902 40123 0.60 1.40 10.02 15.23 0.00 1.00 1.00 101.80 179.36 1.0 231 1093350
+1 84 1 1 172 9 2899 135 94 5.20 4.80 546948 91311 0.00 0.00 0.00 0.00 0.60 28.60 31.40 262.40 384.00 3.4 1323 1543117
+1 91 1 1 5 4 4051 210 173 0.60 1.20 23850 49089 0.00 0.00 0.00 0.00 0.00 2.20 2.80 66.00 73.40 1.5 710 990808
+1 88 1 1 18 14 2213 265 185 0.60 0.60 135093 112728 3.60 6.00 6.00 0.00 1.40 8.00 10.20 69.60 88.40 2.0 190 1065816
+1 92 1 1 5 0 565 89 32 2.40 3.00 46465 10275 0.00 0.00 0.00 0.00 0.00 0.00 0.00 117.60 169.60 1.2 7727 1879814
+1 90 1 1 52 63 2159 154 151 2.40 0.80 82739 42654 4.00 6.80 6.80 0.00 0.40 2.00 2.20 119.20 207.40 6.8 273 1519694
+1 97 1 1 1 1 512 47 44 0.40 0.40 92333 23899 0.00 0.00 0.00 0.00 0.00 7.20 7.20 38.60 68.60 1.0 465 982181
+1 83 1 1 5 0 3744 172 117 0.60 2.00 174906 28502 6.01 19.44 62.12 167.33 0.60 6.61 26.85 45.29 163.93 1.0 162 1014147
+1 86 1 1 11 2 3744 197 126 2.60 3.20 376579 69587 0.00 0.00 0.00 0.00 0.00 2.60 4.00 122.20 215.60 4.8 3383 1551664
+1 93 1 1 1 0 614 127 91 0.20 0.20 34233 22157 2.80 4.20 8.60 11.80 0.20 4.80 8.40 18.00 21.20 2.4 857 1704754
+1 93 1 1 1 0 1673 79 54 0.80 0.80 73470 34620 0.40 5.41 21.04 33.87 0.00 4.01 5.41 59.12 87.98 1.0 135 1068176
+1 93 1 1 0 0 317 81 48 0.20 0.20 262070 266535 0.00 0.00 0.00 0.00 0.40 3.60 6.00 16.00 22.40 2.2 3779 1811997
+1 83 1 1 3 1 4385 385 201 1.00 1.00 577997 134699 15.60 53.80 74.00 185.00 4.20 17.20 20.00 73.80 198.60 1.2 225 983021
+1 71 1 1 11 0 3251 485 403 9.60 4.00 272686 21411 0.00 0.00 0.00 0.00 0.00 2.80 4.80 517.80 686.20 1.8 6464 1849030
+1 90 1 1 3 3 3179 242 121 0.80 1.40 406678 40100 0.00 0.00 0.00 0.00 0.00 4.39 4.99 46.91 87.23 1.3 426 1007173
+1 98 1 1 1 1 217 11 17 0.20 0.20 9229 54468 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.77 16.77 1.0 7058 1853062
+1 91 1 1 63 78 1702 175 80 1.40 3.00 67821 27096 0.00 0.00 0.00 0.00 0.00 0.40 0.40 152.40 210.80 1.3 846 1073826
+1 90 1 1 18 21 594 48 53 1.00 1.40 121246 133013 0.00 0.00 0.00 0.00 0.00 8.40 16.00 79.60 120.20 1.4 6478 1846885
+1 55 1 1 49 0 5310 276 176 13.43 31.66 241989 26572 1.00 1.20 1.20 0.00 2.00 11.62 15.63 537.07 948.70 2.5 272 1108731
+1 80 1 1 3 0 2091 107 436 2.20 2.20 160355 95085 0.00 0.00 0.00 0.00 0.00 12.80 23.00 211.80 200.20 2.2 3657 1821454
+1 88 1 1 6 1 2505 170 159 0.60 0.60 417374 113156 0.00 0.00 0.00 0.00 0.00 7.20 12.80 57.20 119.60 5.4 3031 1540722
+1 79 1 1 12 1 1153 76 44 8.60 12.00 90970 74499 0.20 1.20 0.40 0.00 0.00 7.40 10.80 371.60 579.00 1.4 4622 1849155
+1 94 1 1 3 0 1514 58 51 1.00 1.00 43703 26727 1.80 2.40 2.00 0.00 0.00 1.40 2.40 81.36 100.80 1.0 208 1001206
+1 95 1 1 0 0 367 53 44 0.20 0.20 7422 11407 0.00 0.00 0.00 0.00 0.00 0.00 0.00 12.97 16.77 1.0 1101 1740180
+1 94 1 1 1 0 444 54 66 0.20 0.20 58812 53197 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.20 25.00 3.2 505 1703970
+1 89 1 1 10 2 1490 279 229 1.60 1.40 168863 24702 0.00 0.00 0.00 0.00 0.20 1.60 1.80 99.20 214.80 1.0 688 971408
+1 95 1 1 0 0 784 56 31 0.60 0.80 3987 6647 0.00 0.00 0.00 0.00 0.00 0.20 0.40 33.93 45.71 1.0 1318 1742839
+1 93 1 1 2 2 2165 119 111 0.00 0.20 38370 33538 0.00 0.00 0.00 0.00 0.00 8.55 8.75 12.52 26.84 1.0 900 1112571
+1 79 1 1 28 0 1534 171 119 7.21 19.64 420118 28592 0.00 0.00 0.00 0.00 0.20 7.01 7.21 247.90 483.77 1.4 359 1091000
+1 57 1 1 59 0 6122 345 87 15.17 49.90 476515 34281 1.40 9.78 49.10 96.41 0.20 4.59 5.19 584.23 961.68 3.2 185 1083578
+1 93 1 1 35 53 1282 69 64 0.80 6.80 48949 23650 0.00 0.00 0.00 0.00 0.00 0.00 0.00 76.40 88.20 2.2 614 1756534
+1 77 1 1 55 44 1523 214 133 6.40 19.20 390240 29553 1.00 13.40 25.20 83.00 0.00 64.60 65.20 224.80 543.40 3.0 205 1089058
+1 74 1 1 20 6 3099 170 104 6.79 19.16 228241 36850 3.59 3.79 3.79 0.00 14.57 6.19 12.18 249.70 442.12 1.6 300 1074263
+1 67 1 1 25 8 4151 261 160 2.79 4.39 386314 30764 6.79 17.56 61.48 136.33 2.40 43.51 95.21 210.98 498.80 1.5 257 1017281
+1 59 1 1 43 53 9172 1684 1499 6.20 3.60 1318504 1127032 0.00 0.00 0.00 0.00 0.00 5.00 7.00 289.20 455.40 1.7 615 1094611
+1 84 1 1 26 37 7046 205 255 0.40 0.40 103972 180082 4.00 4.80 4.40 0.00 0.40 1.40 1.40 52.80 91.00 2.0 327 1013922
+1 81 1 1 1 0 1343 154 131 0.80 0.40 289968 140984 12.80 20.40 19.60 0.00 10.00 6.00 9.20 48.80 71.80 2.4 218 1740122
+1 0 1 1 2 0 5301 331 232 0.20 0.20 344490 300554 0.00 0.00 0.00 0.00 0.00 7.39 9.78 16.77 46.51 1862 81 19
+1 86 1 1 29 24 1681 145 91 4.00 4.40 86683 32474 10.80 20.80 36.20 51.00 3.40 3.20 5.60 259.00 361.00 3.0 172 999750
+1 84 1 1 10 5 4113 222 156 3.80 3.00 126566 37744 0.00 0.00 0.00 0.00 0.00 9.60 9.60 134.40 304.80 1.6 887 982733
+1 84 1 1 28 13 5279 383 290 1.20 1.20 240082 132740 0.00 0.00 0.00 0.00 0.80 10.58 14.97 93.81 162.67 6.2 876 1309448
+1 91 1 1 3 1 2198 166 138 0.80 0.60 33606 97451 0.00 0.00 0.00 0.00 0.00 3.20 3.20 79.60 126.40 1.5 2096 1073008
+1 87 1 1 4 1 863 226 78 1.80 2.00 454550 221890 0.00 0.00 0.00 0.00 0.00 26.80 28.20 82.40 140.80 3.6 7015 1835541
+1 96 1 1 1 1 227 10 15 0.40 1.00 7003 23179 0.00 0.00 0.00 0.00 0.00 0.00 0.00 32.20 35.80 1.2 7529 1878160
+1 96 1 1 29 38 328 24 18 0.60 0.80 49477 8454 0.00 0.00 0.00 0.00 0.00 0.00 0.00 33.60 55.80 2.2 3435 1819314
+1 76 1 1 12 3 3282 297 177 5.00 6.60 157055 68800 7.20 19.80 40.40 50.20 1.40 7.80 8.20 364.00 515.80 1.4 183 1104856
+1 89 1 1 1 0 2083 172 132 1.00 1.20 21666 21076 0.60 0.60 0.60 0.00 0.00 10.20 11.60 82.00 129.40 3.0 334 1092141
+1 88 1 1 0 0 3231 112 98 0.20 0.20 33505 22795 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.20 1.8 427 1754056
+1 94 1 1 5 1 801 118 125 0.20 0.20 5585 79215 0.00 0.00 0.00 0.00 0.00 3.20 4.80 15.60 28.60 2.0 449 1068542
+1 91 1 1 1 1 4794 268 135 0.20 0.20 213843 223948 0.00 0.00 0.00 0.00 0.00 2.60 3.40 15.40 34.60 3.4 3740 1346886
+1 98 1 1 0 0 303 76 62 0.20 0.20 1029 8293 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 1344 1761853
+1 95 1 1 4 1 2605 114 59 0.40 0.40 30320 43770 0.00 0.00 0.00 0.00 0.00 2.20 2.20 34.60 62.60 1.7 1006 1077866
+1 99 1 1 1 1 152 8 13 0.20 0.20 6994 4155 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 6455 1871482
+1 86 1 1 4 2 2332 172 119 0.80 2.60 178514 58539 8.20 11.00 9.40 0.00 0.40 9.20 16.80 74.40 135.00 1.5 238 1082826
+1 85 1 1 9 1 2014 195 88 3.39 4.19 595011 18782 1.20 1.20 1.20 0.00 8.58 3.79 3.79 270.46 384.83 1.5 237 1023778
+1 86 1 1 5 1 1997 141 134 1.60 3.80 274369 54368 15.60 26.80 26.80 0.00 9.40 1.40 1.80 113.20 182.20 1.5 547 1043448
+1 82 1 1 68 67 2649 221 187 1.00 1.80 363647 201577 0.20 0.20 0.20 0.00 3.41 42.69 61.72 123.65 227.86 1.0 617 1005985
+1 76 1 1 17 13 4600 429 163 5.00 16.00 273023 45381 6.40 18.00 69.60 172.80 0.40 5.00 8.40 300.20 452.80 1.0 155 1020013
+1 92 1 1 5 4 1515 219 90 0.20 0.20 258043 239938 0.00 0.00 0.00 0.00 0.00 1.20 1.20 22.00 21.40 4.2 1911 1601232
+1 95 1 1 62 79 1022 113 81 0.60 1.80 98428 29898 1.20 1.20 1.20 0.00 2.40 1.20 1.20 28.80 46.60 1.0 179 1015712
+1 66 1 1 14 3 5506 404 234 10.40 9.40 166195 39124 10.20 40.00 100.00 169.20 1.20 18.60 21.80 405.60 723.80 1.6 152 1099514
+1 70 1 1 28 2 4815 343 244 6.40 17.40 149808 49513 0.00 0.00 0.00 0.00 0.40 21.00 25.80 229.80 451.20 3.6 405 1102202
+1 62 1 1 146 36 4654 495 340 4.21 9.82 617073 247350 31.86 120.04 166.73 207.01 2.20 50.70 84.77 274.35 702.40 1.0 163 1018099
+1 94 1 1 6 2 1224 129 92 0.20 0.20 144733 81218 0.00 0.00 0.00 0.00 0.20 0.00 0.00 20.80 50.60 2.8 1579 1538003
+1 93 1 1 6 4 1627 148 69 1.00 1.20 263421 22570 0.00 0.00 0.00 0.00 0.00 0.80 0.80 80.84 140.12 1.8 413 986381
+1 84 1 1 66 7 4211 248 156 2.20 3.00 440557 88892 0.00 0.00 0.00 0.00 0.00 6.40 6.60 142.20 201.60 3.8 531 1515758
+1 83 1 1 36 27 790 94 54 2.60 3.20 41921 13526 0.00 0.00 0.00 0.00 0.00 1.20 1.20 155.60 235.40 1.8 491 1745480
+1 89 1 1 2 1 3577 160 122 0.40 0.40 117855 49697 0.00 0.00 0.00 0.00 0.00 0.00 0.00 30.80 43.20 2.4 1860 1534048
+1 98 1 1 1 1 213 12 24 0.20 0.20 8658 28541 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 16.80 1.0 7652 1869904
+1 0 1 1 8 7 1329 162 97 0.20 0.20 256305 254541 10.22 16.23 21.84 17.23 0.40 10.22 13.03 20.24 71.94 177 89 11
+1 93 1 1 22 6 1763 186 186 0.00 0.00 89208 147372 8.00 10.20 10.20 0.00 7.20 1.60 1.60 6.40 19.60 2.8 366 1529371
+1 91 1 1 19 16 2245 116 112 0.60 1.40 28913 112980 0.00 0.00 0.00 0.00 0.00 0.40 0.40 145.80 76.00 2.2 848 1644464
+1 84 1 1 30 41 3447 298 226 2.40 2.20 202350 106970 1.80 2.20 2.20 0.00 0.00 7.80 9.00 121.00 179.80 3.6 191 1053651
+1 86 1 1 13 2 2833 188 172 2.80 3.20 57131 99198 0.00 0.00 0.00 0.00 0.00 3.80 4.60 168.00 249.80 1.2 391 1062754
+1 88 1 1 31 2 1480 168 138 2.60 2.60 121708 44505 5.80 20.20 47.40 85.20 1.40 32.60 39.40 131.40 254.60 1.2 133 1068155
+1 88 1 1 8 2 2896 220 181 1.80 0.80 94102 87033 5.40 10.20 15.40 22.20 0.20 0.40 0.40 100.60 148.00 1.0 232 1080682
+1 75 1 1 32 2 2166 147 100 7.80 20.80 47079 35106 3.60 22.80 43.20 60.80 0.60 21.40 24.80 282.60 538.00 3.6 128 1106608
+1 96 1 1 3 0 1624 113 108 0.60 0.80 9744 23072 0.00 0.00 0.00 0.00 0.00 0.00 0.00 52.60 65.60 2.0 1172 971102
+1 90 1 1 9 5 3448 295 148 0.40 0.40 228467 93546 15.00 35.60 52.60 86.00 12.60 7.60 13.00 34.20 74.20 2.4 131 1521109
+1 87 1 1 2 1 4569 334 195 0.20 0.20 14031 82179 0.00 0.00 0.00 0.00 0.00 2.40 3.60 17.00 86.80 2.0 587 1077120
+1 76 1 1 50 56 1787 103 56 6.61 17.43 290399 31307 0.00 0.00 0.00 0.00 1.20 18.84 20.04 352.10 490.98 1.8 365 1083344
+1 0 1 1 26 5 5393 717 605 10.20 6.00 350758 35418 3.20 7.40 13.40 47.40 0.40 3.00 4.20 507.00 806.40 208 64 36
+1 0 1 1 7 4 1614 112 77 0.40 0.40 103997 59856 16.20 22.00 41.60 47.20 13.20 22.60 43.40 42.20 181.40 212 89 11
+1 95 1 1 15 14 2248 183 89 0.20 0.20 262470 256876 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 18.20 3.2 3251 1347160
+1 96 1 1 19 29 579 77 42 0.20 0.20 5549 8486 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.20 16.80 2.0 1442 1716333
+1 92 1 1 1 0 2053 73 95 0.40 0.40 35359 20724 1.20 1.20 5.00 8.40 0.00 3.20 3.20 36.80 57.20 1.0 166 1053560
+1 85 1 1 24 22 3477 124 143 1.80 2.40 69066 185585 1.40 1.60 1.60 0.00 0.60 1.80 2.00 105.20 197.20 1.0 325 989464
+1 94 1 1 3 0 4033 179 117 0.20 0.20 783205 106035 0.00 0.00 0.00 0.00 0.00 0.60 0.60 19.00 22.20 3.6 2591 1635614
+1 87 1 1 44 48 2446 179 127 1.40 2.40 90591 81635 7.41 13.23 10.22 0.00 1.20 8.02 9.82 108.42 191.78 2.0 316 1020319
+1 89 1 1 1 0 2295 280 185 0.80 0.80 177334 28072 0.00 0.00 0.00 0.00 0.40 5.60 6.00 59.00 135.40 2.5 979 1127992
+1 80 1 1 20 16 3238 505 379 1.20 1.00 170554 78908 0.00 0.00 0.00 0.00 0.00 23.60 26.00 71.00 193.80 6.4 7957 1371010
+1 90 1 1 3 1 394 43 15 2.00 2.00 98609 25482 0.00 0.00 0.00 0.00 0.00 3.20 5.20 194.80 165.60 1.4 11566 1882530
+1 79 1 1 7 0 3459 373 391 5.60 1.60 237571 409952 2.00 2.20 2.20 0.00 0.40 2.80 5.40 268.00 417.20 2.2 178 1374995
+1 94 1 1 14 12 3754 222 137 0.20 0.20 264199 175965 0.00 0.00 0.00 0.00 0.00 4.00 4.20 17.80 26.60 3.8 3250 1339408
+1 93 1 1 1 1 1771 111 95 0.40 0.40 121779 26856 0.80 1.20 1.20 0.00 1.20 14.80 15.00 24.00 87.60 1.5 234 1020744
+1 91 1 1 6 1 5112 296 162 0.20 0.20 187273 128442 0.00 0.00 0.00 0.00 0.80 2.40 2.40 21.60 77.60 4.0 334 1331363
+1 96 1 1 5 4 659 94 50 0.60 0.60 259050 19313 1.40 1.60 1.40 0.00 2.80 1.00 1.40 45.80 63.60 1.0 213 1726958
+1 86 1 1 19 4 2013 125 64 2.40 2.20 268068 29939 0.00 0.00 0.00 0.00 0.00 2.80 4.60 186.20 203.40 2.0 8321 1864954
+1 74 1 1 18 4 4526 371 302 1.60 4.39 411501 385509 20.56 32.93 37.92 23.35 8.38 4.19 7.19 99.00 258.28 2.5 224 1037367
+1 82 1 1 6 4 4451 218 139 1.40 6.60 42386 69377 2.00 3.40 3.40 0.00 0.00 0.60 1.00 107.00 124.40 3.8 338 1445123
+1 97 1 1 0 0 173 15 12 0.20 0.20 1592 5127 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7219 1847184
+1 93 1 1 1 1 1440 100 65 1.00 1.00 3681 21412 0.00 0.00 0.00 0.00 0.00 0.40 0.40 42.80 56.20 2.8 347 1060786
+1 97 1 1 28 42 251 34 19 0.40 1.00 859 6147 0.00 0.00 0.00 0.00 0.00 1.20 1.20 29.80 38.40 1.0 625 1753568
+1 98 1 1 1 1 202 17 36 0.20 0.20 12392 4021 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 5426 1862208
+1 91 1 1 1 0 3577 170 171 0.80 1.80 30635 73013 0.00 0.00 0.00 0.00 0.00 2.00 2.59 44.51 81.04 2.0 903 991962
+1 98 1 1 1 1 184 17 18 0.20 0.20 8652 4487 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.40 16.80 1.0 7306 1863872
+1 91 1 1 2 0 2424 177 165 1.40 0.80 206048 17379 0.00 0.00 0.00 0.00 0.00 2.20 4.20 80.80 216.40 1.4 2091 1704171
+1 96 1 1 0 0 1334 123 107 0.20 0.20 13610 29899 0.00 0.00 0.00 0.00 0.00 1.80 1.80 16.63 50.50 1.5 557 1024446
+1 81 1 1 4 3 4246 493 167 0.40 0.40 1654907 138898 0.00 0.00 0.00 0.00 0.60 12.80 22.40 37.60 85.20 1.0 422 984907
+1 79 1 1 4 2 2161 188 131 1.20 2.79 793638 47907 8.98 54.09 153.89 315.97 0.60 74.25 139.92 77.84 129.34 2.6 128 1099957
+1 93 1 1 3 2 1060 92 31 1.20 6.00 408625 13070 0.00 0.00 0.00 0.00 0.00 11.20 22.40 88.20 109.80 1.2 5687 1832611
+1 73 1 1 185 197 2262 184 112 7.40 19.60 100959 48706 0.20 0.20 0.20 0.00 1.60 13.60 19.80 270.20 544.60 3.6 356 1095504
+1 0 1 1 7 4 1213 64 56 0.60 0.40 9159 27622 0.00 0.00 0.00 0.00 0.00 0.40 0.40 36.73 35.93 387 96 4
+1 87 1 1 4 1 4379 331 147 0.40 0.20 917608 17468 0.00 0.00 0.00 0.00 0.40 7.00 7.20 24.00 75.60 4.2 1379 1468944
+1 88 1 1 3 0 2437 231 124 2.00 5.21 52429 18634 1.40 1.40 1.40 0.00 0.00 4.81 8.62 131.46 176.75 2.0 308 1106907
+1 83 1 1 6 3 2318 251 127 2.00 3.60 373489 39134 4.20 10.60 29.40 60.00 0.00 34.40 66.40 162.80 281.00 3.0 352 1536157
+1 98 1 1 29 38 287 57 48 0.20 0.20 950 6593 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 2109 1720376
+1 64 1 1 79 97 7659 1446 493 8.40 8.80 714441 66323 4.20 7.00 17.60 22.00 1.20 33.40 37.00 466.20 909.00 1.0 233 972608
+1 66 1 1 83 67 4419 318 140 8.60 25.20 222311 50939 1.20 1.20 1.20 0.00 0.40 45.20 46.40 295.20 650.20 4.6 278 1091496
+1 73 1 1 49 62 3946 506 361 4.79 2.59 486518 250662 0.00 0.00 0.00 0.00 0.60 38.72 42.71 285.63 595.21 2.5 667 987101
+1 66 1 1 21 1 4547 1070 707 9.00 6.00 461040 51939 0.00 0.00 0.00 0.00 0.00 10.80 20.80 431.40 719.00 5.4 2182 1727709
+1 80 1 1 9 1 2230 589 174 4.19 3.79 213981 66317 0.40 0.60 0.40 0.00 0.60 8.38 11.58 280.44 492.22 5.8 341 1737435
+1 87 1 1 7 1 1976 193 118 1.00 4.20 281713 33400 3.40 12.80 36.60 70.00 0.80 51.60 53.20 85.80 202.00 5.0 144 1053805
+1 95 1 1 3 2 3797 131 152 0.40 0.20 25020 83495 0.00 0.00 0.00 0.00 0.00 0.20 0.20 19.20 21.60 2.2 2893 1641467
+1 97 1 1 2 1 342 45 23 0.20 0.20 263138 52163 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.60 17.40 1.4 7495 1864622
+1 96 1 1 0 0 1028 34 38 0.20 0.20 7826 127556 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 8249 1863248
+1 76 1 1 16 1 2820 392 351 7.20 2.00 181685 14476 1.00 1.00 1.00 0.00 0.00 0.80 0.80 350.00 509.20 2.8 283 1738422
+1 95 1 1 3 2 744 74 55 0.40 0.40 14684 19602 2.40 2.60 2.60 0.00 0.40 0.60 0.60 33.00 63.80 2.0 187 1022318
+1 84 1 1 3 1 525 84 52 2.00 2.00 240540 185870 0.00 0.00 0.00 0.00 0.00 4.59 8.78 171.26 170.06 2.6 3340 1819246
+1 93 1 1 15 20 774 59 65 0.40 0.80 55367 45091 0.00 0.00 0.00 0.00 0.00 8.20 8.80 24.60 90.00 3.0 1782 1074698
+1 74 1 1 67 34 3538 253 213 6.99 18.96 154656 121562 8.78 27.54 30.54 23.15 9.58 17.76 19.76 293.01 494.61 1.0 169 1089316
+1 90 1 1 1 0 1542 50 45 0.20 0.20 1914 10872 0.00 0.00 0.00 0.00 0.00 0.60 0.60 20.20 18.00 2.2 3827 1774014
+1 81 1 1 12 2 2318 329 269 8.80 3.60 218562 8324 0.00 0.00 0.00 0.00 0.00 0.00 0.00 413.00 614.40 4.0 7094 1859120
+1 89 1 1 13 0 1603 131 81 2.00 2.79 339713 35013 0.00 0.00 0.00 0.00 0.20 4.39 5.59 176.85 298.40 2.6 1439 1543773
+1 96 1 1 1 0 467 142 67 0.20 0.20 111229 124147 1.00 1.40 1.40 0.00 0.00 6.40 12.20 15.60 36.20 3.4 176 1736254
+1 95 1 1 3 1 726 101 94 1.80 0.60 66252 29809 0.00 0.00 0.00 0.00 0.00 0.00 0.00 95.80 133.40 1.4 7267 1864941
+1 96 1 1 0 0 2586 66 117 0.20 0.20 33772 92800 2.00 2.20 2.20 0.00 0.20 0.20 0.20 15.60 17.60 1.4 207 1749677
+1 87 1 1 8 1 4687 478 212 1.20 1.40 248995 24777 0.00 0.00 0.00 0.00 0.60 9.60 11.80 96.60 252.20 3.0 1197 1470019
+1 86 1 1 22 20 1178 75 70 1.00 2.00 27459 31140 0.00 0.00 0.00 0.00 0.00 32.53 46.11 129.54 241.52 1.0 1014 1077707
+1 93 1 1 6 1 2053 188 155 0.40 1.00 90743 191001 1.20 1.40 1.40 0.00 0.60 1.60 2.00 34.00 61.20 2.4 228 1535224
+1 86 1 1 3 0 501 60 14 2.79 2.99 190357 26600 0.00 0.00 0.00 0.00 0.00 2.99 4.98 243.23 228.88 1.4 11435 1874164
+1 98 1 1 1 1 418 54 42 0.20 0.20 1439 17874 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.77 18.56 1.0 693 1731210
+1 91 1 1 31 43 2638 113 95 0.40 2.20 128196 125266 2.80 3.00 3.00 0.00 0.60 3.40 6.80 33.60 57.80 2.4 250 1542064
+1 0 1 1 28 18 2163 114 86 0.40 0.40 413933 53634 0.00 0.00 0.00 0.00 0.00 46.20 82.20 35.00 63.00 588 85 14
+1 74 1 1 63 32 2861 367 203 7.40 20.40 990088 106603 2.40 10.00 10.00 0.00 0.60 8.20 10.20 272.60 508.60 1.0 381 1098014
+1 98 1 1 0 0 188 11 33 0.20 0.20 2439 6947 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 7725 1882294
+1 82 1 1 16 3 2257 323 294 6.40 1.80 233167 23197 0.00 0.00 0.00 0.00 0.00 0.00 0.00 303.00 430.00 2.8 7285 1874422
+1 86 1 1 1 0 3974 266 163 0.40 0.60 39665 57867 1.40 1.40 1.40 0.00 0.40 5.59 8.38 38.12 100.80 1.0 176 1125060
+1 91 1 1 1 1 337 76 47 0.20 0.20 238613 219346 0.00 0.00 0.00 0.00 0.00 2.40 4.80 15.60 16.80 3.2 3455 1822152
+1 91 1 1 4 1 1562 65 41 4.80 3.20 115860 9078 0.00 0.00 0.00 0.00 0.00 0.00 0.00 204.20 319.20 1.8 6916 1878819
+1 96 1 1 0 0 383 88 51 0.20 0.20 99388 25335 0.00 0.00 0.00 0.00 0.20 0.60 0.80 17.60 18.40 1.8 1132 1763850
+1 90 1 1 5 0 1481 124 150 0.40 0.20 68609 33107 5.00 26.40 51.40 135.40 1.00 8.20 55.40 20.00 29.00 2.0 143 1054915
+1 86 1 1 8 1 1807 121 76 1.00 1.20 27203 24142 0.00 0.00 0.00 0.00 0.00 11.80 23.00 118.80 241.60 1.8 497 965349
+1 94 1 1 2 1 1827 65 88 0.40 0.20 4487 8828 0.00 0.00 0.00 0.00 0.00 0.20 0.20 17.40 17.00 1.4 689 1752789
+1 92 1 1 12 16 231 21 29 0.20 0.20 5973 4996 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.40 16.80 1.6 488 1754712
+1 70 1 1 40 10 3027 450 312 4.41 1.80 489125 111761 0.00 0.00 0.00 0.00 0.40 52.91 64.13 240.08 529.06 2.8 2864 972754
+1 96 1 1 3 1 927 88 52 0.40 0.40 19803 23188 0.00 0.00 0.00 0.00 0.00 0.20 0.20 35.13 44.11 1.4 1102 1741247
+1 87 1 1 2 0 2595 147 142 1.00 5.61 36597 110466 6.01 8.02 7.82 0.00 0.20 1.80 3.01 44.89 119.04 1.7 247 1001614
+1 95 1 1 20 28 337 25 24 1.40 1.60 37194 20177 0.60 0.60 0.60 0.00 0.80 1.00 1.00 70.00 101.60 1.2 320 1752334
+1 94 1 1 20 2 1337 73 110 0.60 0.60 14311 82232 0.00 0.00 0.00 0.00 0.00 0.80 0.80 44.51 63.87 1.0 404 1072330
+1 76 1 1 3 1 2728 378 172 1.00 3.01 202727 97573 7.01 15.23 24.25 19.04 0.00 59.32 77.96 96.99 372.55 3.5 354 982131
+1 95 1 1 12 9 605 98 77 1.60 0.60 19814 11134 0.00 0.00 0.00 0.00 0.80 0.00 0.00 80.00 116.40 1.4 407 1757275
+1 95 1 1 36 49 1216 62 55 0.20 0.20 89409 9037 0.00 0.00 0.00 0.00 0.00 1.00 1.20 18.96 20.56 1.2 653 1728966
+1 90 1 1 1 0 2435 365 106 0.60 3.18 543956 75753 0.80 0.80 0.80 0.00 0.00 1.99 1.99 23.46 71.17 5.6 2173 983060
+1 91 1 1 5 1 1686 119 34 2.00 2.80 151948 11447 0.00 0.00 0.00 0.00 0.00 0.40 0.40 147.20 209.60 2.0 8540 1870248
+1 0 1 1 7 5 1376 297 124 0.20 0.20 894427 742384 0.00 0.00 0.00 0.00 152.80 6.20 6.20 28.00 265.20 1886 86 14
+1 81 1 1 21 6 5507 368 364 2.00 7.98 161511 11168 0.00 0.00 0.00 0.00 0.00 8.58 10.38 150.50 167.07 4.6 1527 1638571
+1 98 1 1 0 0 1059 18 25 0.20 0.20 5414 12403 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 17.00 1.0 8309 1864912
+1 62 1 1 51 2 3367 223 168 9.40 20.20 327304 119062 10.20 54.00 126.80 188.40 2.00 49.60 69.20 413.00 700.80 1.6 173 1093862
+1 94 1 1 12 12 1404 180 117 0.80 2.20 15212 21212 0.00 0.00 0.00 0.00 0.00 0.00 0.00 54.00 73.20 5.2 3040 1604526
+1 95 1 1 1 1 1242 279 120 0.20 0.20 356664 349244 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.40 27.00 2.8 1934 1759984
+1 90 1 1 31 45 2024 494 181 0.60 0.80 549020 537937 0.00 0.00 0.00 0.00 0.00 0.20 0.20 47.40 86.40 1.7 447 1044514
+1 83 1 1 5 1 2122 134 91 1.00 1.80 623731 7854 0.60 0.60 0.60 0.00 0.60 70.20 136.60 74.20 114.60 5.8 333 1341090
+1 97 1 1 1 0 295 31 17 0.80 4.20 71244 13475 2.00 2.20 2.20 0.00 0.00 0.00 0.00 27.80 41.80 2.4 521 1760613
+1 86 1 1 4 0 2162 307 216 2.19 0.60 485056 33264 0.00 0.00 0.00 0.00 0.00 5.38 5.38 108.96 196.22 2.0 504 1051743
+1 88 1 1 56 78 1815 94 112 1.60 2.40 103043 71594 0.00 0.00 0.00 0.00 0.00 2.79 2.79 115.37 168.86 2.3 614 1044506
+1 87 1 1 5 3 1188 189 75 1.60 1.80 87923 24470 2.00 2.80 2.40 0.00 1.00 3.60 3.80 89.60 195.20 1.0 262 1037323
+1 94 1 1 1 0 1054 295 248 0.20 0.20 91696 28858 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.80 20.80 2.0 407 1693584
+1 96 1 1 18 24 1477 92 45 0.20 0.20 22837 10043 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 1.0 6938 1879152
+1 86 1 1 4 1 1751 148 125 0.60 2.00 419384 40810 0.00 0.00 0.00 0.00 0.00 37.80 72.80 60.60 215.60 6.4 2621 1378523
+1 91 1 1 2 0 2437 295 116 0.60 1.40 40305 22330 0.00 0.00 0.00 0.00 0.00 1.40 1.40 67.54 110.02 1.8 490 1097225
+1 91 1 1 2 1 1602 183 143 0.60 1.00 108632 43802 1.20 1.40 1.40 0.00 1.20 0.20 0.20 50.40 56.40 1.3 289 1110890
+1 93 1 1 6 5 1774 110 76 0.40 0.60 18733 21187 0.40 0.40 0.40 0.00 0.00 13.97 14.57 37.52 112.18 2.6 442 965008
+1 82 1 1 74 80 2823 204 157 1.60 2.00 243756 101307 6.19 23.15 63.67 146.31 4.19 43.51 50.50 132.34 304.79 1.8 155 998654
+1 85 1 1 32 31 603 76 64 2.00 1.80 112623 55035 0.00 0.00 0.00 0.00 0.00 2.00 6.20 134.80 137.60 1.2 509 1802803
+1 85 1 1 2 1 3868 405 333 0.60 0.60 571151 82102 1.00 13.20 35.40 70.60 5.20 7.40 10.60 54.80 148.80 1.0 172 1046045
+1 86 1 1 69 80 4765 867 732 0.20 0.20 683248 614527 2.20 29.40 69.00 271.80 0.60 17.80 80.60 15.40 48.80 4.0 146 1397720
+1 71 1 1 10 1 4460 524 419 7.00 1.80 441130 16790 0.00 0.00 0.00 0.00 0.00 0.20 0.40 345.00 508.80 3.6 442 1744293
+1 90 1 1 10 9 4026 167 126 0.80 0.80 178582 19180 1.60 1.80 1.60 0.00 5.59 4.39 6.79 49.70 85.03 2.6 308 1457261
+1 86 1 1 12 0 4156 269 215 0.80 4.00 55765 104935 0.00 0.00 0.00 0.00 0.00 0.80 0.80 37.60 95.80 1.3 411 1070816
+1 93 1 1 10 7 1638 137 109 0.20 0.20 7565 25868 0.00 0.00 0.00 0.00 0.40 9.80 10.20 16.60 95.20 2.8 473 976858
+1 98 1 1 0 0 254 42 22 0.20 0.20 255327 12261 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 17.00 1.2 7309 1873272
+1 94 1 1 13 6 2449 197 177 0.60 0.40 278532 182715 0.00 0.00 0.00 0.00 2.80 1.80 2.20 45.80 61.80 4.6 474 1304518
+1 92 1 1 10 9 3362 172 192 0.20 0.20 422528 189987 0.00 0.00 0.00 0.00 0.00 6.80 12.00 19.40 35.60 4.4 3634 1341744
+1 88 1 1 0 0 533 107 78 0.20 0.20 23160 120134 0.00 0.00 0.00 0.00 0.00 1.60 1.60 15.63 20.84 1.8 1723 1770424
+1 74 1 1 23 21 5713 494 292 2.00 2.40 131673 84262 24.80 52.80 102.80 169.40 14.80 28.20 38.80 139.80 368.80 1.5 144 1006877
+1 95 1 1 0 0 474 53 40 0.20 0.20 3058 5309 0.00 0.00 0.00 0.00 0.00 0.00 0.00 22.60 29.00 1.0 1125 1744080
+1 90 1 1 8 4 1835 131 104 1.80 0.60 38235 42949 0.00 0.00 0.00 0.00 0.00 0.80 0.80 90.80 149.80 1.3 613 1067602
+1 72 1 1 7 0 3155 427 411 6.99 20.16 327445 165154 2.79 16.17 26.15 47.11 0.20 23.15 41.52 245.11 456.29 2.2 205 1075369
+1 93 1 1 8 5 1943 153 92 0.40 0.40 100518 32210 0.00 0.00 0.00 0.00 0.20 16.20 17.00 53.60 76.80 3.0 375 1023675
+1 94 1 1 71 70 1029 119 83 0.60 1.80 54702 51872 0.00 0.00 0.00 0.00 0.00 1.40 2.20 50.40 64.80 1.5 1181 1001486
+1 96 1 1 2 1 333 52 36 0.40 0.40 1366 10612 0.00 0.00 0.00 0.00 0.00 0.20 0.40 29.34 40.52 1.2 1311 1742307
+1 90 1 1 1 1 1811 226 132 0.60 0.60 314015 45517 0.20 0.40 0.40 0.00 1.80 1.60 1.80 49.00 212.20 1.0 486 1115851
+1 85 1 1 49 62 2358 230 162 1.20 1.40 247357 164069 7.98 60.88 158.88 410.38 5.99 0.60 0.60 136.73 160.48 2.8 1145 1524292
+1 92 1 1 33 47 2047 86 79 0.20 0.20 49666 33156 1.20 1.20 1.20 0.00 0.00 5.80 11.00 15.60 17.00 1.4 177 1744294
+1 85 1 1 9 5 1978 291 228 4.00 1.20 239288 65637 0.00 0.00 0.00 0.00 0.20 3.20 4.80 201.60 323.80 2.0 885 1008509
+1 77 1 1 29 24 5007 329 198 3.81 5.21 178918 93266 6.21 11.62 11.62 0.00 3.01 2.61 4.21 243.49 406.61 2.2 271 1125319
+1 89 1 1 6 2 2365 194 122 0.60 1.80 113604 35591 7.19 25.15 51.70 115.57 1.20 29.94 41.12 35.53 144.51 2.5 128 1064613
+1 87 1 1 59 64 1720 201 112 1.20 1.20 182095 41385 0.80 1.00 0.80 0.00 0.60 26.80 35.80 72.80 248.60 2.0 569 967757
+1 79 1 1 19 1 3124 490 345 7.39 2.99 193596 10956 0.00 0.00 0.00 0.00 0.00 0.40 0.40 365.27 528.94 3.2 2297 1524006
+1 90 1 1 11 14 1313 67 55 0.20 0.20 1909 8969 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 1.8 4097 1776888
+1 86 1 1 2 0 535 58 30 2.00 2.00 143526 45830 0.00 0.00 0.00 0.00 0.00 3.00 5.00 200.40 165.40 1.6 11497 1881234
+1 86 1 1 5 2 2157 180 105 2.80 3.40 191243 48792 5.00 18.40 30.20 44.80 1.00 5.60 5.80 160.20 297.40 3.6 168 1039970
+1 82 1 1 7 0 2385 194 133 6.00 5.00 541218 290033 0.00 0.00 0.00 0.00 53.80 4.20 5.80 224.40 445.60 5.2 1975 1724125
+1 68 1 1 48 39 3596 398 288 2.81 4.61 449827 208527 44.69 101.60 189.98 353.91 1.40 11.02 66.93 219.84 430.86 1.6 140 993279
+1 96 1 1 2 1 467 77 100 0.60 0.40 56431 37651 1.80 2.60 2.20 0.00 0.00 0.40 0.40 38.60 48.20 1.0 264 1744410
+1 0 1 1 18 12 2192 420 153 0.40 0.40 710333 550980 0.00 0.00 0.00 0.00 2.20 6.81 7.82 27.86 117.23 328 82 18
+1 98 1 1 0 0 208 10 16 0.20 0.20 5514 51055 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.37 16.77 1.2 7459 1861710
+1 98 1 1 1 0 227 40 27 0.20 0.20 86832 9129 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 18.00 1.2 1254 1760286
+1 98 1 1 1 1 803 23 20 0.20 0.20 9067 10293 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.83 16.83 1.0 8215 1872866
+1 81 1 1 37 47 689 113 62 2.00 2.00 371378 46754 0.00 0.00 0.00 0.00 0.00 2.59 3.59 183.23 173.25 2.2 2780 1791529
+1 89 1 1 24 8 2684 520 252 0.80 0.80 55758 39015 0.00 0.00 0.00 0.00 0.00 20.00 32.20 86.80 125.80 1.0 917 965910
+1 76 1 1 6 2 4480 429 333 3.60 3.80 244837 196107 0.00 0.00 0.00 0.00 0.00 20.20 36.80 191.20 350.00 3.8 509 1014661
+1 87 1 1 1 0 3357 137 71 0.80 0.80 34964 24901 0.00 0.00 0.00 0.00 0.00 0.00 0.00 56.00 84.60 2.0 1489 1755176
+1 79 1 1 45 61 4430 149 116 0.60 0.60 537881 50416 10.00 42.00 132.60 328.40 0.60 66.20 124.00 49.80 94.60 1.8 112 1012219
+1 94 1 1 3 1 1102 109 61 0.20 0.20 22698 22482 1.00 1.60 1.60 0.00 0.20 6.20 11.40 16.00 47.20 6.2 171 1112885
+1 94 1 1 9 1 1429 163 69 0.20 0.20 179877 18764 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.40 18.60 2.4 2275 1698706
+1 92 1 1 3 1 1677 63 63 1.60 1.80 46461 24101 1.00 1.20 13.00 25.80 0.40 1.20 1.60 86.60 187.00 1.5 138 1061552
+1 83 1 1 22 8 3805 253 156 0.80 1.20 494538 41636 9.38 35.13 83.83 177.45 3.59 11.58 20.76 108.78 317.76 8.4 142 1293549
+1 72 1 1 25 2 3521 416 351 9.98 5.99 343506 52407 3.39 4.39 15.37 16.17 0.80 1.40 1.60 452.10 732.14 1.5 279 1067428
+1 93 1 1 1 0 1138 296 248 0.20 0.20 239090 207539 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 2.0 1712 1763360
+1 73 1 1 31 2 4587 286 132 6.80 18.20 229893 38377 0.00 0.00 0.00 0.00 0.00 2.20 2.60 269.40 537.20 4.0 1458 1109734
+1 94 1 1 1 0 448 126 76 0.20 0.20 456419 271500 0.00 0.00 0.00 0.00 0.20 3.60 7.00 19.00 27.20 4.2 1080 1728701
+1 70 1 1 21 2 3681 466 391 8.17 2.99 209980 21093 18.92 48.01 164.54 826.29 1.00 2.39 2.59 407.37 884.06 2.8 156 958183
+1 95 1 1 15 20 797 31 30 0.20 0.20 914 4168 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.40 16.80 2.0 2039 1720296
+1 92 1 1 0 0 970 55 37 0.20 0.20 91046 16898 0.00 0.00 0.00 0.00 0.80 0.00 0.00 22.20 17.80 2.2 440 1744328
+1 70 1 1 30 0 3974 268 130 7.80 20.20 210297 33485 0.00 0.00 0.00 0.00 0.00 3.80 4.20 317.60 567.00 2.8 1359 1108970
+1 90 1 1 3 0 2085 179 149 3.20 1.40 88147 9965 0.40 1.20 13.40 17.40 0.20 0.80 0.80 164.00 247.20 1.6 145 1750694
+1 79 1 1 8 4 3661 627 346 3.20 1.00 604427 426782 0.00 0.00 0.00 0.00 0.00 0.60 0.60 169.20 303.20 2.8 581 1040554
+1 86 1 1 9 4 3895 308 182 0.80 1.00 181918 65964 1.80 2.40 2.20 0.00 2.80 28.20 30.40 63.80 190.60 5.4 432 1309147
+1 74 1 1 52 64 4385 201 145 6.20 17.40 65581 37335 0.00 0.00 0.00 0.00 0.00 7.00 7.60 256.80 414.60 3.3 387 1101664
+1 98 1 1 0 0 235 21 26 0.20 0.20 813 9813 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7693 1871504
+1 0 1 1 10 10 1489 122 64 0.20 0.20 185016 46690 4.79 9.18 8.98 0.00 0.00 2.40 2.40 16.17 62.28 195 92 8
+1 87 1 1 2 0 3542 293 178 0.80 0.40 27494 42157 5.20 7.20 6.00 0.00 0.00 1.40 1.80 52.20 82.60 2.0 206 1137126
+1 0 1 1 18 8 1587 228 160 0.60 0.80 285782 75085 6.00 7.20 35.20 59.80 5.00 15.20 23.60 75.40 208.80 236 88 11
+1 80 1 1 78 70 2450 224 154 4.59 3.59 256706 39362 11.18 21.56 47.11 143.71 3.19 0.80 2.40 167.66 418.56 4.0 210 959074
+1 91 1 1 1 0 1826 135 103 0.20 0.20 29634 44745 4.40 12.20 13.40 4.00 1.00 4.80 6.20 15.60 24.40 2.8 155 1718645
+1 93 1 1 2 0 1328 51 34 1.20 1.20 37888 19887 0.00 0.00 0.00 0.00 0.00 1.20 2.00 113.37 97.21 1.0 8554 1863067
+1 93 1 1 3 1 2518 121 165 0.40 0.20 125959 18110 0.00 0.00 0.00 0.00 0.60 8.20 16.20 23.40 23.80 3.0 384 1704326
+1 87 1 1 1 1 3793 227 157 0.40 1.80 220018 328206 7.39 11.38 18.56 42.91 2.99 25.75 39.12 19.76 54.29 2.3 133 1008315
+1 92 1 1 15 13 2768 216 115 0.40 0.40 49486 8514 0.00 0.00 0.00 0.00 0.20 1.20 1.20 44.40 52.00 2.0 966 1450728
+1 95 1 1 0 0 1380 64 47 0.20 0.20 52455 15022 0.00 0.00 0.00 0.00 0.00 0.40 0.40 16.40 25.00 2.4 423 991782
+1 94 1 1 4 3 2774 65 68 0.60 2.00 22464 3437 0.00 0.00 0.00 0.00 0.20 1.60 1.80 47.60 70.00 2.4 632 1446296
+1 92 1 1 0 0 347 29 25 0.40 0.40 19254 12714 0.00 0.00 0.00 0.00 0.00 0.00 0.00 37.00 40.40 1.8 994 1765360
+1 76 1 1 57 78 3549 385 461 1.40 1.60 242442 686812 12.40 21.40 37.00 107.00 1.80 10.60 18.00 92.00 275.20 4.2 271 1009008
+1 96 1 1 5 3 1855 94 98 0.20 0.20 9122 27521 0.00 0.00 0.00 0.00 0.00 0.80 1.00 16.00 28.60 3.0 2788 1532637
+1 88 1 1 1 0 461 59 38 0.20 0.20 21060 13045 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.97 21.96 2.0 988 1761753
+1 80 1 1 23 20 3695 344 198 1.20 3.99 276192 97365 18.76 25.35 25.35 0.00 14.17 10.58 16.37 109.18 192.22 4.4 211 1007005
+1 83 1 1 2 0 1623 83 139 0.40 0.40 279844 334809 29.60 62.60 76.00 49.20 0.20 42.80 76.00 27.60 76.40 1.6 300 1074008
+1 95 1 1 5 4 1532 79 57 0.20 0.20 2032 26233 0.00 0.00 0.00 0.00 0.00 0.40 0.40 43.20 26.80 2.0 1090 1016978
+1 82 1 1 64 83 3102 772 166 2.00 2.40 248949 94071 0.00 0.00 0.00 0.00 0.20 21.00 37.80 147.40 291.80 1.0 1155 1043166
+1 98 1 1 1 1 170 13 17 0.20 0.20 31363 11635 0.00 0.00 0.00 0.00 0.00 0.20 0.40 16.40 18.00 1.0 7248 1875328
+1 97 1 1 1 1 242 24 24 0.20 0.20 9033 14527 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7536 1878214
+1 89 1 1 57 71 1776 170 126 0.40 0.60 6148 30329 0.00 0.00 0.00 0.00 0.20 1.20 1.20 36.27 74.15 1.0 347 1093060
+1 87 1 1 2 0 1757 134 72 0.40 0.40 300196 53888 16.63 45.49 51.50 39.28 1.20 16.03 30.86 46.09 100.40 1.0 383 1053752
+1 96 1 1 6 1 1052 63 85 0.40 0.40 29462 29507 0.00 0.00 0.00 0.00 0.20 0.40 0.40 31.20 46.20 2.0 377 1059522
+1 88 1 1 1 1 3941 309 187 0.20 0.20 15356 27299 1.60 1.80 1.80 0.00 0.40 1.80 2.81 16.23 66.13 1.6 215 1129732
+1 97 1 1 27 37 756 20 23 0.20 0.20 1360 8056 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 4623 1828408
+1 93 1 1 22 29 1049 38 91 0.40 0.40 20253 382942 0.00 0.00 0.00 0.00 0.00 0.00 0.00 33.80 33.40 1.2 8378 1865056
+1 90 1 1 42 61 4328 151 168 0.20 0.20 93311 244826 0.60 1.00 1.00 0.00 0.40 6.80 7.00 28.60 55.60 2.6 214 1385874
+1 91 1 1 31 42 3118 138 129 0.80 1.00 11278 28131 2.61 3.01 2.61 0.00 0.80 2.20 2.20 58.12 87.98 1.0 283 1020074
+1 80 1 1 3 1 4821 236 258 2.00 9.38 83870 479867 0.00 0.00 0.00 0.00 0.00 10.58 10.58 74.45 163.87 2.0 963 1037206
+1 75 1 1 4 2 3824 267 239 2.19 1.99 81499 454394 0.00 0.00 0.00 0.00 0.00 9.96 9.96 136.45 283.86 1.0 508 1000888
+1 97 1 1 4 1 419 69 72 0.40 0.40 2858 33835 0.00 0.00 0.00 0.00 0.00 0.00 0.00 29.40 53.80 2.0 6653 1708432
+1 96 1 1 3 2 1200 84 44 0.20 0.20 68419 30007 0.00 0.00 0.00 0.00 0.00 0.80 1.00 16.60 26.80 1.0 561 1019416
+1 67 1 1 92 81 3244 231 156 7.98 19.56 110209 136276 14.37 39.72 58.08 88.62 3.99 13.37 16.17 344.91 559.88 2.8 266 1089792
+1 93 1 1 1 0 1743 149 150 0.40 2.00 64164 244496 0.00 0.00 0.00 0.00 0.00 0.60 0.60 31.80 63.80 3.0 393 1527189
+1 94 1 1 4 1 1263 146 68 1.00 1.80 22551 16237 0.00 0.00 0.00 0.00 0.00 1.40 1.80 60.68 131.74 1.0 621 1014224
+1 0 1 1 9 6 3453 920 839 0.20 0.20 10714 73390 12.38 18.76 30.34 22.16 7.58 9.98 12.77 15.57 76.85 170 84 16
+1 80 1 1 21 6 4489 502 165 1.20 4.39 332391 57132 0.00 0.00 0.00 0.00 4.39 18.96 31.14 70.86 196.81 2.0 722 986702
+1 84 1 1 3 0 906 59 42 2.40 2.40 98592 39686 0.00 0.00 0.00 0.00 0.00 2.81 4.21 201.60 184.57 1.0 3810 1825467
+1 90 1 1 5 1 2170 226 168 1.00 1.80 120365 150726 1.60 1.60 1.60 0.00 0.80 3.60 3.60 44.40 80.20 2.4 239 1535606
+1 77 1 1 43 31 3956 334 217 4.20 2.60 320963 76817 0.00 0.00 0.00 0.00 0.00 8.80 10.80 208.40 498.00 4.0 1029 1397515
+1 88 1 1 2 1 2914 402 484 1.00 1.20 49843 50430 0.00 0.00 0.00 0.00 0.00 0.40 0.40 76.00 119.00 2.0 771 1703163
+1 98 1 1 11 15 217 15 34 0.20 0.20 5339 19480 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7292 1875112
+1 96 1 1 10 9 906 93 62 0.20 0.20 7332 23635 0.00 0.00 0.00 0.00 0.00 2.40 3.00 15.80 25.20 1.0 1628 1081958
+1 85 1 1 1 0 3347 257 153 0.40 1.80 555900 47401 2.80 4.60 4.60 0.00 9.20 12.20 15.60 24.40 60.80 4.4 278 1041150
+1 94 1 1 11 5 1779 83 58 1.00 7.60 44176 42676 0.00 0.00 0.00 0.00 0.00 1.00 1.40 93.80 115.00 2.2 907 1535013
+1 80 1 1 2 0 426 38 30 2.20 2.20 78934 43817 0.00 0.00 0.00 0.00 0.00 4.20 5.80 190.20 177.60 1.0 2438 1796808
+1 89 1 1 30 44 1875 91 85 1.40 1.00 65420 53279 0.20 0.20 0.20 0.00 1.00 2.40 4.20 86.60 106.00 1.5 344 1059890
+1 95 1 1 2 0 1137 148 109 0.40 1.80 215885 100630 0.80 0.80 6.00 12.20 4.00 0.60 1.20 32.60 44.20 2.4 162 1522802
+1 80 1 1 46 64 4783 357 165 2.40 2.20 195220 149556 2.00 4.99 9.98 23.75 0.20 4.59 6.19 289.02 253.49 2.8 172 1120559
+1 82 1 1 17 3 2542 176 106 3.60 8.80 51858 26836 2.60 8.20 17.40 29.20 1.20 26.20 30.00 169.40 322.00 6.2 202 1111174
+1 94 1 1 7 7 1383 166 97 0.20 0.20 29617 34510 2.80 9.40 25.20 51.60 0.00 12.80 18.20 16.00 63.80 1.0 132 991891
+1 94 1 1 2 1 1259 72 60 0.40 0.20 205056 67970 0.00 0.00 0.00 0.00 0.00 0.60 1.00 32.20 48.80 1.6 4264 1822139
+1 96 1 1 24 32 278 57 33 0.40 0.40 378984 272804 0.00 0.00 0.00 0.00 0.00 0.00 0.00 39.80 33.80 2.6 5643 1836221
+1 69 1 1 12 1 3437 508 704 9.40 4.40 203779 59995 0.00 0.00 0.00 0.00 0.00 0.20 0.20 421.40 642.40 4.2 2727 1737790
+1 98 1 1 0 0 171 12 29 0.20 0.20 3904 11759 0.00 0.00 0.00 0.00 0.00 0.40 0.80 15.60 16.80 1.0 7245 1875315
+1 75 1 1 36 43 2042 149 116 7.00 20.20 161119 19732 3.60 14.00 31.40 75.80 0.40 6.00 6.80 247.20 461.00 4.0 162 1087090
+1 0 1 1 10 6 767 86 90 1.00 0.80 66939 55617 0.00 0.00 0.00 0.00 0.20 1.00 1.00 63.20 138.20 538 94 6
+1 95 1 1 6 5 1075 150 77 0.60 0.60 186329 20552 1.00 1.00 1.00 0.00 2.80 1.00 3.60 46.20 140.80 3.0 200 971387
+1 79 1 1 2 0 4292 270 226 1.20 2.61 162276 290731 0.00 0.00 0.00 0.00 0.00 11.02 11.42 65.33 312.63 3.0 836 1009645
+1 86 1 1 12 5 2405 182 129 0.60 2.00 146138 38456 8.20 18.60 36.40 63.80 0.60 38.60 45.80 64.20 226.40 2.8 475 988678
+1 88 1 1 2 0 439 56 16 2.20 2.20 144880 25284 0.00 0.00 0.00 0.00 0.00 2.20 4.20 211.80 182.00 1.0 9307 1880608
+1 98 1 1 1 1 214 31 30 0.20 0.20 17682 12325 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 17.00 1.4 8801 1835578
+1 98 1 1 1 1 182 13 27 0.20 0.20 8163 7311 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.20 16.80 1.0 5201 1860792
+1 75 1 1 10 1 4529 310 281 5.60 1.80 215089 106509 10.20 33.80 60.00 92.00 3.00 3.00 3.40 292.60 453.80 3.8 213 1512869
+1 89 1 1 0 0 539 43 26 0.20 0.20 50909 26377 0.00 0.00 0.00 0.00 0.00 6.20 12.40 15.40 17.00 2.2 543 1747245
+1 92 1 1 2 0 1854 134 241 0.40 0.40 19916 22682 2.40 2.60 2.60 0.00 0.00 6.40 7.60 32.20 57.80 4.0 312 1055160
+1 87 1 1 104 43 2459 238 171 2.58 2.98 217916 114530 0.00 0.00 0.00 0.00 0.00 2.98 3.98 148.31 260.64 2.8 5012 1664027
+1 70 1 1 13 9 6431 324 175 2.99 9.78 340837 108188 8.18 41.32 121.36 219.96 4.79 31.54 60.08 211.38 313.57 2.6 175 1388778
+1 69 1 1 5 0 5210 783 276 4.60 5.80 266860 109912 9.60 64.60 130.20 209.60 0.40 8.60 12.00 306.00 659.40 1.2 156 1119058
+1 90 1 1 0 0 645 76 49 0.60 0.60 62260 16899 0.00 0.00 0.00 0.00 0.00 0.60 0.80 56.80 78.20 2.0 1055 1765843
+1 75 1 1 26 17 3111 446 256 4.60 3.00 929087 324567 0.00 0.00 0.00 0.00 4.40 41.00 76.20 275.00 504.40 1.0 3243 1033187
+1 97 1 1 1 1 938 84 64 0.20 0.20 4789 27656 1.00 1.20 1.20 0.00 0.80 1.00 1.00 15.80 17.20 1.4 297 1752533
+1 69 1 1 45 25 6154 191 161 3.39 10.38 153242 463723 39.12 73.05 73.05 0.00 5.79 4.39 15.57 302.20 358.48 6.2 233 1521515
+1 88 1 1 21 32 5691 364 212 0.20 0.20 17833 39783 0.00 0.00 0.00 0.00 0.00 0.80 1.60 19.40 36.80 1.8 708 1739216
+1 97 1 1 1 0 1223 71 68 0.20 0.20 12841 15049 0.00 0.00 0.00 0.00 0.00 9.60 11.80 13.00 24.40 2.0 6161 1726408
+1 90 1 1 3 1 366 36 20 1.80 1.80 77008 24462 0.00 0.00 0.00 0.00 0.00 2.60 3.60 176.40 152.00 1.2 7985 1868448
+1 86 1 1 22 0 2766 222 210 1.60 4.20 11270 84861 1.20 1.20 1.20 0.00 0.00 1.20 1.60 105.40 129.80 1.2 171 1064197
+1 93 1 1 1 1 3021 162 141 0.20 0.20 363439 17804 3.00 3.60 3.60 0.00 0.00 0.00 0.00 17.20 26.20 3.0 136 1709558
+1 89 1 1 27 15 1970 271 117 1.40 2.20 1067119 27957 2.20 2.20 7.20 11.40 13.00 12.00 15.20 101.80 190.00 3.0 154 975584
+1 87 1 1 8 1 3635 133 138 1.40 3.40 84603 110664 0.00 0.00 0.00 0.00 0.40 1.80 5.40 96.60 152.80 3.4 3208 1539683
+1 80 1 1 201 197 5335 697 380 0.60 0.60 354488 230101 0.00 0.00 0.00 0.00 0.00 30.20 58.60 49.80 177.00 3.8 2857 1330510
+1 80 1 1 10 8 3537 948 190 1.40 1.80 362670 77336 3.20 7.60 9.60 434.20 1.60 29.80 58.20 119.20 211.60 1.6 308 1135336
+1 91 1 1 9 8 1979 128 256 0.20 0.20 68684 22883 0.00 0.00 0.00 0.00 0.00 1.60 2.40 24.80 38.00 1.0 595 1005963
+1 96 1 1 2 0 936 137 136 0.80 0.40 17347 62003 0.00 0.00 0.00 0.00 0.00 0.40 0.60 48.80 83.40 1.3 713 1060565
+1 84 1 1 340 0 3475 228 193 2.80 1.40 142575 57016 0.00 0.00 0.00 0.00 0.00 1.80 3.60 141.80 211.20 2.8 3988 1708720
+1 98 1 1 0 0 166 8 10 0.20 0.20 20115 7036 0.40 0.40 0.40 0.00 0.20 0.20 0.20 13.00 16.80 2.0 179 1760056
+1 86 1 1 6 0 2525 312 208 3.80 1.40 153878 59652 0.00 0.00 0.00 0.00 0.00 6.60 12.20 195.20 277.60 1.0 623 1066800
+1 89 1 1 4 3 3045 230 162 0.60 0.60 30583 30913 3.20 3.80 3.80 0.00 2.20 3.20 5.60 48.40 81.20 1.0 254 1098288
+1 96 1 1 1 0 1818 88 67 0.20 0.20 5125 19491 2.81 3.01 3.01 0.00 0.20 0.80 0.80 16.03 28.06 2.0 167 1073796
+1 97 1 1 3 1 1370 113 64 0.40 1.80 5521 6620 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.80 30.80 2.0 6131 1729808
+1 89 1 1 3 1 570 51 46 2.40 2.40 32096 19469 0.00 0.00 0.00 0.00 0.00 0.60 0.60 165.00 176.00 1.4 8578 1840808
+1 95 1 1 1 0 267 87 44 0.20 0.20 289921 232622 0.00 0.00 0.00 0.00 0.00 2.40 4.80 16.00 18.80 3.2 702 1727416
+1 76 1 1 51 45 5244 478 430 7.20 4.00 203264 92352 0.00 0.00 0.00 0.00 0.00 0.20 0.20 355.40 530.80 3.6 2571 1644069
+1 83 1 1 5 3 2167 168 103 1.60 3.40 278291 37904 7.80 23.60 45.00 94.40 3.00 13.20 16.20 107.60 264.40 3.0 169 1128174
+1 95 1 1 5 1 504 90 33 2.00 2.00 53054 13833 0.00 0.00 0.00 0.00 0.00 0.00 0.00 76.80 132.40 1.0 7461 1869166
+1 57 1 1 14 0 4165 302 159 11.60 33.00 424191 41544 2.40 9.80 16.40 18.20 8.40 31.60 40.00 428.40 864.40 1.0 247 1081554
+1 77 1 1 6 1 3940 359 160 3.19 4.79 313111 62013 13.57 31.74 91.02 139.52 0.20 41.72 74.25 159.28 271.46 1.4 129 1105768
+1 67 1 1 6 2 6241 1164 1042 4.20 1.60 870898 763147 0.00 0.00 0.00 0.00 0.00 1.80 2.40 221.60 380.60 2.2 626 1115016
+1 76 1 1 2 0 5688 569 296 1.40 1.60 672992 317610 10.00 32.80 91.20 174.60 0.00 18.40 19.40 108.40 346.60 2.6 144 1006536
+1 86 1 1 2 0 2949 213 108 1.00 1.20 603387 29934 0.00 0.00 0.00 0.00 0.00 8.00 9.20 79.40 141.40 1.4 1149 1044112
+1 83 1 1 1 0 4859 238 189 0.80 0.80 229829 305705 2.20 2.59 2.59 0.00 0.00 4.59 4.79 105.59 124.95 4.2 421 1004659
+1 68 1 1 14 1 7065 465 380 8.40 5.40 224372 83658 2.40 4.00 17.40 41.00 1.60 3.20 4.60 395.00 624.40 6.2 236 1512261
+1 90 1 1 30 43 1721 153 120 0.80 0.80 24277 27695 0.00 0.00 0.00 0.00 0.40 19.64 19.84 69.74 145.69 1.8 382 977513
+1 91 1 1 20 29 1997 94 64 0.20 0.20 4637 6918 0.00 0.00 0.00 0.00 0.00 0.40 0.40 19.80 19.20 2.0 3956 1775598
+1 85 1 1 7 0 2365 205 176 3.00 1.80 74832 63129 0.00 0.00 0.00 0.00 0.00 1.00 1.40 131.60 217.60 1.0 482 1059445
+1 91 1 1 1 1 368 26 23 0.20 0.20 3796 10090 3.20 3.60 3.60 0.00 0.00 0.60 0.60 18.60 19.20 1.6 165 1741878
+1 84 1 1 5 0 2384 322 276 3.41 1.60 157572 85444 0.00 0.00 0.00 0.00 0.00 8.02 8.82 166.73 288.98 2.0 906 1129504
+1 90 1 1 0 0 2285 207 167 0.40 0.60 174265 45943 0.00 0.00 0.00 0.00 0.00 26.15 26.95 30.54 113.37 3.5 1224 1038943
+1 89 1 1 46 55 1866 133 101 2.00 3.99 252497 173340 0.00 0.00 0.00 0.00 0.00 5.19 8.78 160.48 194.61 4.4 2889 1546965
+1 81 1 1 10 4 5748 444 256 0.40 0.60 190254 99158 7.80 50.60 104.00 194.60 0.40 34.20 43.60 47.00 153.20 3.0 136 1021834
+1 86 1 1 3 0 1752 151 80 0.40 0.40 570699 77482 17.60 102.20 237.40 514.60 0.00 54.40 105.80 59.80 198.80 3.8 115 1531446
+1 71 1 1 18 2 4780 351 327 1.00 1.40 735191 481231 23.35 74.65 170.26 343.51 0.40 51.30 98.40 51.50 130.34 5.0 154 972461
+1 83 1 1 41 54 2578 193 108 1.20 1.40 212626 32407 0.00 0.00 0.00 0.00 1.80 4.59 10.58 94.21 179.84 1.0 910 1057162
+1 93 1 1 20 29 2386 164 155 0.20 0.20 77339 62093 0.00 0.00 0.00 0.00 0.00 0.20 0.20 18.00 19.00 2.2 1411 1724984
+1 90 1 1 20 0 2710 115 144 0.60 0.60 16730 61107 6.00 23.80 40.00 126.80 0.20 25.40 41.20 57.80 205.20 1.0 183 1018200
+1 94 1 1 6 5 1730 133 101 0.20 0.20 21597 48037 0.00 0.00 0.00 0.00 0.40 2.40 2.40 20.20 48.20 3.6 2755 1048314
+1 85 1 1 31 25 3787 337 196 1.60 2.00 130458 54047 6.20 12.60 14.40 4.40 1.60 3.40 10.20 101.60 177.60 1.4 183 1085310
+1 77 1 1 15 8 3268 448 387 6.01 2.20 226097 90644 0.00 0.00 0.00 0.00 0.00 5.81 8.02 307.41 464.33 1.5 477 968228
+1 84 1 1 8 4 5225 195 149 0.80 1.20 127902 141409 0.00 0.00 0.00 0.00 0.00 31.54 31.74 89.62 154.69 3.8 3091 1344471
+1 92 1 1 0 0 2077 99 98 0.20 0.20 7498 118211 0.00 0.00 0.00 0.00 0.00 2.40 2.61 51.50 155.71 2.6 677 1019506
+1 93 1 1 2 1 1395 99 130 0.60 0.60 112895 89579 1.20 1.60 1.60 0.00 0.20 2.20 2.40 112.40 55.80 2.0 195 1708013
+1 92 1 1 0 0 1345 138 97 0.60 1.20 121947 31895 0.20 0.20 0.20 0.00 0.00 4.39 4.59 50.50 142.32 1.0 359 1029237
+1 91 1 1 1 0 3765 108 95 0.60 1.00 76969 84407 0.80 1.80 1.40 0.00 0.40 3.20 3.20 45.00 82.00 3.5 392 1016318
+1 98 1 1 0 0 150 9 19 0.20 0.20 2074 12320 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.40 17.00 1.0 7306 1873272
+1 71 1 1 51 61 3761 539 395 7.00 2.80 564511 110912 9.00 17.40 62.60 95.40 19.00 12.60 21.80 341.20 528.00 6.2 239 1596602
+1 92 1 1 2 0 1230 73 45 1.80 4.80 367776 281408 8.40 12.80 11.60 0.00 7.60 0.40 0.80 85.40 120.60 2.0 322 1760186
+1 89 1 1 1 0 2287 232 231 1.20 3.99 15551 28181 5.19 5.39 11.38 13.97 0.20 3.79 3.79 77.25 140.32 2.0 140 1097466
+1 94 1 1 1 1 572 244 62 0.80 1.20 479808 384192 0.00 0.00 0.00 0.00 0.00 0.80 0.80 61.00 101.60 2.4 5505 1828306
+1 91 1 1 6 5 3792 191 115 0.20 0.20 18171 35150 0.00 0.00 0.00 0.00 0.00 1.20 1.80 19.80 28.20 1.5 541 1119909
+1 85 1 1 3 1 3886 455 244 2.40 6.40 234874 41348 2.80 4.20 3.80 0.00 2.40 1.80 3.40 156.40 213.00 1.7 222 1094254
+1 75 1 1 6 0 4755 462 280 4.77 3.18 367389 252852 8.35 16.10 11.13 0.00 0.20 1.79 1.99 446.92 419.68 2.3 219 1118255
+1 79 1 1 7 0 3237 403 344 6.60 1.80 242204 61619 0.00 0.00 0.00 0.00 0.00 0.00 0.00 313.40 449.20 2.4 7714 1871030
+1 93 1 1 7 1 962 48 40 1.40 1.20 48929 27998 0.00 0.00 0.00 0.00 0.20 3.00 3.00 93.60 159.80 2.2 2877 1547094
+1 78 1 1 15 11 2937 187 172 2.60 3.40 85740 133011 0.00 0.00 0.00 0.00 0.00 4.80 5.20 166.60 343.40 1.2 669 1044240
+1 87 1 1 9 0 2698 260 111 0.80 0.40 375918 31631 0.00 0.00 0.00 0.00 0.40 4.00 22.20 66.40 172.40 1.6 1057 1019373
+1 77 1 1 35 44 3279 353 299 4.60 3.40 269193 104279 0.00 0.00 0.00 0.00 0.20 46.80 46.80 301.00 542.60 1.5 678 1014826
+1 88 1 1 4 0 4492 348 334 0.20 0.20 78672 78979 1.20 7.98 16.57 25.35 1.00 21.76 24.15 19.76 82.63 3.0 310 1045501
+1 88 1 1 4 2 4612 375 277 0.40 0.40 121653 111117 0.00 0.00 0.00 0.00 0.40 0.00 0.00 39.80 53.40 1.0 336 1070258
+1 73 1 1 20 13 5833 1237 1078 3.81 3.01 908980 796528 0.00 0.00 0.00 0.00 0.80 4.41 5.01 208.82 308.02 2.0 915 1082158
+1 94 1 1 45 58 948 99 48 1.40 8.60 101409 22408 0.00 0.00 0.00 0.00 0.00 0.40 0.40 45.80 82.60 2.2 3620 1746512
+1 84 1 1 16 0 1404 131 100 3.40 4.00 71028 29572 8.00 45.60 99.00 317.20 0.20 20.60 82.80 128.60 208.60 1.5 145 1058082
+1 66 1 1 18 0 6356 739 557 8.60 3.20 399290 77676 3.80 6.60 37.00 54.20 0.80 3.40 6.20 424.40 700.20 1.0 185 1066848
+1 98 1 1 2 1 205 16 16 0.20 0.20 23724 5015 0.00 0.00 0.00 0.00 0.00 0.00 0.00 19.40 18.00 1.0 8438 1865707
+1 85 1 1 4 2 3494 228 163 1.40 2.20 31729 25312 2.00 2.60 2.40 0.00 1.60 2.20 2.80 83.40 94.80 3.0 337 1103394
+1 91 1 1 7 4 4947 246 146 0.60 0.60 43806 109617 0.00 0.00 0.00 0.00 0.00 0.20 0.20 45.80 65.40 2.8 2515 1643253
+1 92 1 1 3 1 357 27 14 1.80 1.80 44160 13197 0.00 0.00 0.00 0.00 0.00 1.60 2.00 160.40 139.40 1.0 7793 1868872
+1 89 1 1 1 0 4520 335 161 0.80 2.40 245000 29445 2.00 2.59 5.39 5.19 0.40 4.19 4.39 47.31 131.74 1.2 167 1000891
+1 90 1 1 7 4 1366 161 126 2.00 1.60 56618 37103 0.00 0.00 0.00 0.00 0.00 1.60 1.60 123.60 188.60 1.0 870 998274
+1 88 1 1 56 75 3232 252 185 1.80 6.00 66912 31808 0.00 0.00 0.00 0.00 0.00 3.40 3.60 123.40 179.20 2.0 485 1098818
+1 83 1 1 2 0 2977 516 389 1.40 1.60 382554 107844 0.60 0.60 0.60 0.00 0.00 6.59 12.18 112.38 122.16 3.4 293 1692926
+1 83 1 1 8 0 2363 472 349 3.59 1.20 187907 130569 0.00 0.00 0.00 0.00 0.40 7.58 8.18 175.05 330.14 1.0 432 1060201
+1 87 1 1 53 78 1163 90 205 1.40 7.60 8742 517416 0.00 0.00 0.00 0.00 0.00 18.00 19.80 72.60 201.40 2.0 1570 1042291
+1 85 1 1 1 0 3689 333 174 0.40 0.60 146163 96026 5.20 13.60 28.20 35.40 3.40 7.20 10.80 33.00 91.80 1.5 183 1129250
+1 94 1 1 1 0 1649 107 71 0.20 0.20 16691 61172 0.00 0.00 0.00 0.00 0.00 0.80 1.60 15.40 17.40 2.2 4795 1727936
+1 82 1 1 24 5 3703 303 143 4.60 9.80 426252 52575 0.20 0.20 0.20 0.00 0.60 4.00 5.80 311.60 424.80 4.8 450 1540493
+1 88 1 1 1 1 712 130 41 0.20 0.20 605639 25952 4.60 8.00 40.60 74.00 0.40 62.80 124.60 15.60 26.00 1.0 296 1036822
+1 0 1 1 49 70 2104 412 136 0.80 0.60 590463 559409 2.40 5.00 5.00 0.00 0.40 1.00 1.00 45.40 111.40 265 84 16
+1 78 1 1 19 8 5255 152 81 2.60 8.20 76221 44818 0.00 0.00 0.00 0.00 0.00 1.00 1.00 229.00 227.60 4.8 1777 1558984
+1 95 1 1 30 38 546 172 99 0.20 0.20 119648 135541 3.00 5.40 5.40 0.00 0.20 7.00 13.20 15.80 32.60 3.2 167 1736178
+1 79 1 1 26 18 4169 837 451 1.80 3.40 103527 34744 0.00 0.00 0.00 0.00 0.20 1.00 1.00 136.00 203.80 4.0 623 1540648
+1 69 1 1 39 11 4305 447 291 6.79 7.58 187787 87124 0.00 0.00 0.00 0.00 0.40 40.12 43.71 366.27 725.15 1.0 843 1105766
+1 96 1 1 0 0 784 61 45 0.40 0.60 14287 15889 0.00 0.00 0.00 0.00 0.00 1.40 2.40 33.20 41.00 1.0 1543 998760
+1 59 1 1 212 208 6286 761 581 8.02 2.40 1079757 207983 10.62 32.26 60.92 75.35 1.40 43.69 51.30 387.98 705.01 3.8 154 1082132
+1 88 1 1 4 0 1683 203 97 0.80 1.00 208421 23930 0.00 0.00 0.00 0.00 0.00 8.78 16.57 71.06 163.87 4.0 1302 1070927
+1 65 1 1 9 0 7555 1251 1124 5.39 2.20 1139172 798539 1.00 1.80 1.60 0.00 1.20 7.98 9.58 302.00 490.02 1.2 450 1109115
+1 94 1 1 2 0 2166 87 78 0.60 0.60 25562 73636 0.00 0.00 0.00 0.00 0.00 0.00 0.00 32.00 44.20 2.4 4718 1727878
+1 88 1 1 65 60 2391 156 100 1.00 0.80 188534 52404 3.40 5.40 5.20 0.00 1.00 8.20 9.20 81.60 166.00 1.2 723 1006984
+1 96 1 1 1 1 973 49 39 0.20 0.20 5749 25238 0.00 0.00 0.00 0.00 0.40 0.40 0.40 13.60 28.40 3.0 389 1008496
+1 66 1 1 25 6 4636 705 485 6.60 2.20 467038 275586 3.60 5.20 5.00 0.00 4.40 4.80 7.60 340.00 489.00 5.8 326 1546581
+1 93 1 1 0 0 691 25 18 0.20 0.20 912 5944 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 20.00 1.8 817 1750648
+1 95 1 1 52 70 1699 125 106 0.20 0.20 6046 26711 0.00 0.00 0.00 0.00 0.00 0.00 0.00 19.60 33.60 1.8 536 977066
+1 92 1 1 0 0 2563 217 166 0.20 0.00 94197 34963 0.60 1.20 4.60 10.60 0.40 0.40 0.60 18.40 39.00 2.3 138 1057800
+1 97 1 1 18 26 188 27 18 0.20 0.20 82883 9349 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 19.40 1.6 9241 1867598
+1 98 1 1 1 0 362 49 28 0.20 0.20 85833 4820 0.20 0.40 0.40 0.00 0.00 0.20 0.20 22.60 23.40 2.4 317 1715520
+1 79 1 1 5 0 3820 374 323 5.01 2.20 179440 20591 0.00 0.00 0.00 0.00 0.00 1.40 2.61 263.93 458.12 1.6 346 1731747
+1 93 1 1 5 0 1779 144 92 0.60 0.80 265930 109091 0.00 0.00 0.00 0.00 0.00 1.00 1.00 85.80 84.40 2.4 1990 1543290
+1 81 1 1 90 110 3933 262 171 2.80 3.40 272345 12135 1.40 2.00 2.00 0.00 0.20 3.80 4.00 172.80 377.00 7.0 333 1298203
+1 90 1 1 4 2 1450 238 173 0.60 1.80 137709 123565 3.19 9.38 25.35 43.11 1.00 12.38 13.97 44.11 83.43 3.6 132 1051859
+1 82 1 1 5 0 3552 372 304 3.99 1.40 208494 24924 1.00 1.20 1.20 0.00 0.80 3.99 4.59 212.18 406.39 1.2 214 978045
+1 77 1 1 7 4 3158 248 158 1.60 2.40 787021 308246 3.99 4.59 4.59 0.00 3.39 20.56 38.52 102.79 206.99 1.8 304 1015668
+1 90 1 1 18 17 541 157 72 1.00 3.00 224685 246771 0.00 0.00 0.00 0.00 21.80 0.80 0.80 36.20 83.00 2.2 4152 1827126
+1 96 1 1 1 0 492 46 75 0.60 0.60 15833 8868 1.00 1.00 1.00 0.00 1.60 0.00 0.00 52.00 60.40 3.0 292 1716125
+1 71 1 1 13 1 4228 507 417 6.57 3.19 190947 65011 6.18 19.12 54.38 133.86 0.60 5.38 5.38 296.61 609.76 2.0 139 1009343
+1 88 1 1 2 2 322 41 46 0.20 0.20 25489 31649 0.00 0.00 0.00 0.00 0.00 0.20 0.20 26.40 19.20 1.0 1703 1772248
+1 94 1 1 30 43 1267 75 54 0.80 0.80 502808 300959 0.00 0.00 0.00 0.00 0.00 0.00 0.00 56.80 93.40 2.8 955 1758986
+1 63 1 1 43 0 3443 274 98 11.62 34.87 685449 55666 2.40 2.61 2.61 0.00 1.40 7.21 7.41 385.17 736.47 3.5 254 1091921
+1 85 1 1 1 0 4327 334 190 1.00 3.80 160513 34348 1.40 12.00 24.60 37.20 0.00 1.00 1.00 127.20 233.80 1.0 417 1093755
+1 60 1 1 59 54 6294 593 342 6.39 2.79 897218 60330 10.38 92.02 224.95 591.42 4.39 71.86 133.53 334.13 643.11 4.4 134 1525084
+1 87 1 1 34 24 2523 128 80 1.80 7.00 82901 91402 0.00 0.00 0.00 0.00 0.00 1.80 2.00 152.80 159.80 5.6 2513 1576355
+1 90 1 1 1 0 4547 172 138 0.20 0.20 8885 38067 0.00 0.00 0.00 0.00 0.20 29.20 30.60 15.80 63.60 1.0 2287 1112656
+1 93 1 1 0 0 210 30 25 0.20 0.20 3772 9781 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.8 1187 1766979
+1 95 1 1 14 19 2283 97 141 0.20 0.20 4429 12351 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.40 17.80 2.0 667 1720094
+1 97 1 1 1 1 259 37 31 0.20 0.20 39112 11366 0.00 0.00 0.00 0.00 0.00 2.00 4.00 16.60 17.60 1.0 7274 1847232
+1 80 1 1 55 57 1660 110 79 2.99 4.59 147453 90600 0.00 0.00 0.00 0.00 0.20 0.40 0.40 250.90 306.39 3.2 859 1509469
+1 81 1 1 25 0 1420 165 98 6.19 18.16 300171 25054 0.00 0.00 0.00 0.00 0.00 0.40 0.40 204.99 382.04 1.0 339 1086665
+1 75 1 1 20 14 6044 423 329 1.40 0.80 461313 150328 2.20 21.40 48.80 78.80 0.40 19.00 34.80 71.00 273.80 6.6 332 1298470
+1 96 1 1 1 0 362 37 82 0.20 0.20 90723 86835 0.00 0.00 0.00 0.00 0.00 2.20 2.20 22.40 20.80 3.2 990 1716496
+1 81 1 1 9 2 2735 384 291 3.59 5.78 186494 141547 0.00 0.00 0.00 0.00 0.00 12.15 14.54 154.98 277.69 1.0 473 1093280
+1 50 1 1 59 5 4215 255 127 14.17 32.53 147062 56430 6.19 31.14 47.31 121.56 3.19 32.93 43.11 601.20 1072.65 3.0 176 1100525
+1 93 1 1 6 5 1633 126 90 0.20 0.20 125882 48981 0.00 0.00 0.00 0.00 0.00 0.60 1.20 21.00 19.80 2.0 5097 1673574
+1 83 1 1 1 0 3744 407 216 0.99 1.59 926490 167142 3.58 11.33 69.38 125.84 0.20 11.93 18.69 104.77 247.91 2.6 125 1009166
+1 88 1 1 21 6 1974 183 191 2.00 1.80 129997 109342 0.00 0.00 0.00 0.00 0.20 2.00 2.20 124.40 186.20 3.4 550 1532637
+1 68 1 1 37 0 3486 312 132 8.18 23.35 885406 33458 8.58 28.34 61.48 170.86 8.38 24.95 32.73 294.21 616.57 3.2 134 1093019
+1 82 1 1 110 105 2055 293 267 3.59 1.00 124573 69621 0.00 0.00 0.00 0.00 0.00 0.00 0.00 165.87 241.52 1.8 3654 1769870
+1 82 1 1 5 0 1170 156 99 6.00 3.60 348701 245088 0.00 0.00 0.00 0.00 0.00 2.60 5.20 265.40 402.40 3.6 3803 1822779
+1 98 1 1 0 0 510 47 36 0.20 0.20 1091 6084 0.00 0.00 0.00 0.00 0.00 0.40 0.60 15.60 17.20 1.4 472 1730878
+1 90 1 1 2 0 836 154 160 1.20 1.20 365652 153501 2.60 19.00 91.80 234.60 1.80 20.40 39.40 54.40 108.80 2.2 112 1714547
+1 97 1 1 16 23 241 34 25 0.20 0.20 40579 15141 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.40 16.80 1.0 8741 1835070
+1 90 1 1 0 0 3884 199 199 0.40 1.80 21250 387525 15.77 21.96 21.96 0.00 11.78 0.80 1.00 34.93 59.28 2.0 187 1380750
+1 89 1 1 3 1 479 39 44 1.60 1.60 61375 49795 0.00 0.00 0.00 0.00 0.00 1.00 1.20 143.69 123.45 1.8 6517 1855889
+1 84 1 1 4 0 3039 200 137 2.20 1.20 166728 30197 0.60 1.00 1.00 0.00 0.00 7.20 10.60 132.80 196.20 2.7 313 1104350
+1 80 1 1 14 0 4146 450 322 3.79 1.20 288375 64184 0.00 0.00 0.00 0.00 0.20 5.19 10.18 189.82 340.52 1.5 421 1056758
+1 91 1 1 4 2 2426 145 307 1.00 0.40 39889 42104 4.00 4.60 4.60 0.00 0.40 5.80 5.80 53.60 96.00 1.0 264 1054392
+1 91 1 1 44 59 2191 228 146 1.60 0.60 47032 37191 0.00 0.00 0.00 0.00 0.00 0.60 0.60 77.80 126.20 4.2 748 972698
+1 93 1 1 2 2 1935 280 274 0.40 1.40 57186 32631 0.00 0.00 0.00 0.00 0.00 6.60 8.00 52.40 72.60 1.7 552 1045416
+1 77 1 1 8 0 1699 100 70 7.00 20.00 70050 15979 2.60 6.40 11.00 15.20 0.20 10.60 15.60 259.60 453.20 1.0 156 1114605
+1 82 1 1 43 59 3706 248 182 1.00 2.60 42272 97027 0.00 0.00 0.00 0.00 0.00 1.00 1.00 89.20 138.40 1.3 926 1122056
+1 82 1 1 2 0 528 74 66 2.00 2.00 51954 33545 0.00 0.00 0.00 0.00 0.00 3.60 5.20 169.60 154.60 1.4 2924 1780082
+1 93 1 1 1 1 1392 137 57 0.20 0.20 20860 77843 0.00 0.00 0.00 0.00 0.20 0.40 0.60 17.80 21.40 1.0 449 1757496
+1 92 1 1 2 0 1328 150 99 0.40 0.60 89429 107747 9.02 13.23 13.23 0.00 4.41 5.21 5.21 56.31 158.52 1.8 337 1062886
+1 97 1 1 0 0 2282 104 87 0.20 0.20 17057 3674 0.00 0.00 0.00 0.00 0.20 5.60 6.60 15.60 25.60 2.2 797 1448872
+1 91 1 1 2 0 431 55 50 1.40 1.60 45640 21646 0.00 0.00 0.00 0.00 0.00 0.20 0.20 76.05 102.79 2.2 4033 1775705
+1 74 1 1 28 14 6780 255 145 2.80 3.80 149186 69030 0.00 0.00 0.00 0.00 0.60 4.80 5.00 249.80 352.80 3.6 864 1642715
+1 98 1 1 2 1 162 13 13 0.20 0.20 10981 13750 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.77 16.97 1.0 8292 1859920
+1 95 1 1 2 0 667 131 141 1.40 4.80 2185 12395 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.80 79.20 1.0 7617 1879974
+1 85 1 1 19 5 2394 234 115 2.20 6.00 621159 132139 11.00 29.80 66.00 160.60 2.40 8.40 15.40 172.00 243.20 3.2 278 1536549
+1 0 1 1 37 43 1221 172 99 0.60 0.80 295353 33811 0.80 1.60 2.00 2.40 2.60 6.60 22.00 51.60 129.60 336 90 9
+1 93 1 1 2 0 2159 179 92 0.20 0.20 6047 22108 1.00 4.59 12.38 30.74 0.00 20.96 21.56 15.57 127.74 1.0 140 1065463
+1 56 1 1 79 28 8284 691 447 9.60 12.00 465858 141015 10.00 19.20 19.20 0.00 7.40 3.80 4.40 522.00 759.40 8.6 271 1596195
+1 0 1 1 9 8 2967 221 147 0.20 0.20 185224 44145 11.00 30.40 67.60 161.40 0.00 29.00 48.60 18.40 105.80 144 79 21
+1 88 1 1 2 0 3454 243 217 2.40 0.80 61663 43911 0.00 0.00 0.00 0.00 1.40 0.40 0.40 109.80 193.20 1.0 571 1014162
+1 99 1 1 0 0 139 10 15 0.20 0.20 1088 12201 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.97 16.77 1.0 6570 1847401
+1 92 1 1 1 1 1534 182 94 0.20 0.20 4389 14758 0.00 0.00 0.00 0.00 0.00 1.00 1.00 17.76 20.36 1.2 399 1117269
+1 75 1 1 34 11 5892 131 111 3.20 8.80 198671 85450 0.00 0.00 0.00 0.00 1.60 2.40 3.00 280.40 304.80 3.4 685 1630339
+1 74 1 1 294 298 3859 382 235 5.99 3.39 123048 167229 8.98 25.75 47.70 62.28 0.60 18.96 54.69 312.18 551.10 2.6 205 1001836
+1 90 1 1 5 1 2698 177 85 0.80 1.00 330529 92690 14.00 23.20 32.00 21.60 8.00 11.80 21.00 70.60 129.00 2.8 167 1519782
+1 92 1 1 6 1 769 104 33 2.40 2.80 231010 12158 0.00 0.00 0.00 0.00 0.00 0.60 0.60 136.00 206.00 2.4 4482 1840381
+1 97 1 1 1 0 1086 68 68 0.20 0.20 3146 21133 5.20 12.20 35.20 76.00 0.00 34.20 34.20 18.80 58.80 1.4 134 1089550
+1 85 1 1 13 12 6369 529 171 0.20 0.20 201569 142415 2.81 4.41 4.41 0.00 0.80 3.61 3.81 15.23 69.94 1.8 208 1007290
+1 92 1 1 1 0 2047 256 196 0.40 1.80 639654 26139 0.00 0.00 0.00 0.00 0.20 2.81 3.01 26.45 55.91 3.2 286 1091176
+1 93 1 1 22 14 1016 98 71 1.00 1.40 27652 41764 0.00 0.00 0.00 0.00 0.00 2.00 2.60 79.00 90.40 2.0 2644 1727899
+1 96 1 1 1 1 2118 115 130 0.40 0.40 14685 11951 0.00 0.00 0.00 0.00 0.00 0.80 1.00 45.40 96.00 2.4 1046 1721310
+1 95 1 1 45 64 712 47 46 0.40 0.40 42938 14112 0.40 0.40 0.40 0.00 0.20 2.20 2.80 39.00 57.60 2.2 488 992288
+1 79 1 1 9 0 2707 388 346 7.20 2.20 207865 21122 0.00 0.00 0.00 0.00 0.00 0.00 0.00 360.20 506.60 3.0 2403 1768251
+1 0 1 1 16 11 5084 277 209 2.00 1.60 181781 53837 6.60 11.40 22.80 30.80 2.20 8.00 13.80 155.00 309.80 362 84 15
+1 96 1 1 0 0 791 71 71 0.20 0.20 11946 21256 0.00 0.00 0.00 0.00 0.00 2.40 2.40 15.57 76.85 1.3 536 1064088
+1 94 1 1 0 0 1961 142 84 0.20 0.20 126634 19519 0.00 0.00 0.00 0.00 0.00 3.20 3.80 17.20 85.20 3.0 494 1027525
+1 95 1 1 1 0 587 75 39 0.40 0.60 21868 13848 1.60 7.40 44.80 104.00 0.00 4.80 4.80 53.80 117.60 3.6 133 1716253
+1 88 1 1 17 4 2446 199 79 4.00 3.40 214179 140499 0.00 0.00 0.00 0.00 0.00 1.00 1.20 162.00 291.00 4.2 600 1337333
+1 93 1 1 2 0 2494 198 148 0.20 0.20 41957 31916 1.60 1.80 1.80 0.00 0.20 4.19 7.19 24.55 59.68 3.0 247 1084270
+1 90 1 1 3 1 2860 267 154 0.40 0.80 196799 168812 4.60 6.80 6.80 0.00 0.20 2.20 3.60 41.40 59.20 1.0 278 1068418
+1 87 1 1 81 100 2467 86 79 2.00 8.80 31296 67249 3.60 3.60 11.20 18.80 2.40 5.00 5.00 122.20 178.00 3.0 141 1526331
+1 71 1 1 190 29 7360 457 327 2.00 8.58 128663 104128 9.98 29.14 36.93 38.12 3.19 4.79 4.79 170.86 193.81 3.2 179 1326737
+1 99 1 1 2 0 192 11 30 0.20 0.20 464 22942 0.00 0.00 0.00 0.00 0.00 0.00 0.00 21.40 16.80 1.0 6231 1856718
+1 95 1 1 1 0 1437 68 62 0.80 1.20 13136 18208 0.80 2.79 8.38 10.18 0.00 1.80 2.20 45.51 73.05 1.0 136 1061994
+1 93 1 1 3 0 972 36 21 1.80 3.19 72137 7678 0.00 0.00 0.00 0.00 0.00 0.20 0.40 146.31 180.64 1.4 7534 1865183
+1 90 1 1 1 1 2565 291 194 0.60 0.80 10841 33495 0.00 0.00 2.40 8.62 0.20 1.40 1.40 36.87 102.61 1.0 133 1101546
+1 92 1 1 1 0 3454 146 99 0.40 0.80 20262 42580 0.00 0.00 0.00 0.00 0.00 0.20 0.20 29.74 33.53 1.0 674 1058858
+1 91 1 1 2 1 3803 145 110 0.80 3.19 6064 21324 0.20 0.20 0.20 0.00 0.40 1.60 1.60 65.27 95.41 1.0 195 1013365
+1 87 1 1 10 3 1642 203 187 2.60 1.20 166460 145197 2.00 2.20 2.20 0.00 1.00 12.00 12.00 153.60 238.20 3.2 218 1522285
+1 88 1 1 1 0 4242 259 174 0.80 3.00 112567 75288 3.00 4.00 4.00 0.00 1.80 3.40 4.40 32.00 57.20 1.0 248 1117925
+1 97 1 1 2 1 396 35 30 0.40 0.40 7359 9680 0.00 0.00 0.00 0.00 0.00 0.00 0.00 32.80 33.20 1.0 7693 1871504
+1 93 1 1 15 3 1203 61 34 1.60 1.80 163076 33674 0.00 0.00 0.00 0.00 0.00 0.00 0.00 127.80 199.40 2.4 2744 1542915
+1 86 1 1 8 4 2971 360 365 0.80 0.80 219101 101997 14.63 24.25 35.27 31.26 5.61 5.21 5.81 41.28 76.35 2.7 158 1025470
+1 0 1 1 43 53 1012 250 147 1.00 3.61 1635551 1526410 1.40 1.60 1.60 0.00 0.20 0.00 0.00 42.89 67.74 147 90 10
+1 88 1 1 2 2 1177 105 146 0.40 0.40 98413 390064 4.60 20.00 49.00 89.00 0.40 32.20 46.20 31.40 81.20 2.0 120 1380834
+1 94 1 1 4 0 1287 56 32 3.20 10.20 21470 10323 0.00 0.00 0.00 0.00 0.00 0.00 0.00 94.60 172.80 2.2 4563 1828696
+1 91 1 1 4 0 1031 153 113 0.80 0.80 632762 87279 0.40 1.00 56.60 113.00 0.00 12.40 21.60 87.00 203.80 2.0 132 1035902
+1 0 1 1 13 2 1510 151 109 2.39 3.59 45093 27988 4.18 7.97 29.88 48.01 1.00 59.36 62.95 134.26 326.49 178 87 13
+1 92 1 1 2 0 3504 154 120 0.20 0.20 6741 56584 5.39 9.18 10.58 4.59 7.19 6.19 6.59 14.37 58.08 1.0 158 1069447
+1 98 1 1 0 0 219 25 23 0.20 0.20 754 5505 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.83 16.83 1.0 585 1736176
+1 97 1 1 0 0 1081 31 54 0.20 0.20 12142 144533 0.00 0.00 0.00 0.00 0.00 0.00 0.00 14.60 17.40 1.6 8345 1864720
+1 90 1 1 2 0 2941 214 118 1.20 3.00 20216 9736 0.00 0.00 0.00 0.00 0.20 0.80 1.60 67.40 87.20 2.8 1107 1403693
+1 0 1 1 22 7 5753 715 476 3.00 2.00 222677 201168 26.00 51.60 59.40 46.20 0.80 28.80 33.60 180.20 275.20 173 72 28
+1 93 1 1 2 0 3304 150 99 0.20 0.20 235979 204504 0.00 0.00 0.00 0.00 0.40 2.20 3.80 30.80 39.60 5.6 2354 1542878
+1 96 1 1 1 0 1347 71 77 0.20 0.20 5380 18794 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 20.20 4.8 1443 1075200
+1 0 1 1 44 35 2235 395 377 2.20 2.60 685440 404981 41.20 102.40 234.80 496.40 1.60 48.60 85.80 171.00 320.40 99 73 27
+1 84 1 1 8 0 3659 287 227 3.60 1.00 140955 58917 3.00 3.40 3.40 0.00 0.20 0.00 0.00 176.60 249.00 2.4 244 1626637
+1 86 1 1 29 42 3261 254 215 1.20 2.20 97834 409398 0.00 0.00 0.00 0.00 0.00 6.60 11.80 99.80 137.60 3.0 1203 1378464
+1 79 1 1 57 76 3608 378 310 6.20 2.20 182330 27624 0.00 0.00 0.00 0.00 0.00 0.00 0.00 321.20 481.20 3.4 463 1757726
+1 97 1 1 1 1 330 163 40 0.20 0.20 286593 260061 0.00 0.00 0.00 0.00 0.00 0.60 1.00 15.57 19.56 2.2 5762 1830802
+1 92 1 1 6 2 964 170 99 0.60 0.60 683508 18269 4.59 13.17 29.34 45.31 7.19 11.38 13.77 50.50 163.47 3.2 226 1038432
+1 94 1 1 0 0 1463 112 100 0.20 0.20 60598 58822 7.60 12.80 11.20 2.00 1.00 0.20 0.20 15.40 16.80 1.2 151 1750994
+1 95 1 1 199 229 543 78 58 0.40 0.80 1704 17048 0.00 0.00 0.00 0.00 0.00 0.20 0.20 39.60 77.60 1.2 712 1033613
+1 89 1 1 2 1 713 86 77 0.20 0.20 36111 31145 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.40 17.60 1.4 1718 1768344
+1 76 1 1 3 0 3295 196 165 1.40 2.40 92544 32340 7.40 17.20 50.80 153.20 0.60 47.40 79.80 109.40 295.20 3.0 168 1003514
+1 83 1 1 14 3 3990 409 213 1.40 3.20 477907 58581 0.00 0.00 0.00 0.00 0.20 11.00 24.40 106.60 230.80 5.8 3488 1540136
+1 75 1 1 2 0 723 130 66 2.20 2.20 533645 223278 0.00 0.00 0.00 0.00 0.00 2.20 2.40 215.80 172.20 2.6 2107 1817314
+1 74 1 1 1 0 6181 351 302 0.40 0.40 400445 186549 30.80 106.40 284.80 509.20 0.40 48.40 84.20 33.00 305.00 3.2 119 996330
+1 90 1 1 9 5 1371 119 68 2.60 5.20 227225 20985 0.00 0.00 0.00 0.00 0.20 1.80 1.80 134.40 216.80 2.0 2517 1015792
+1 74 1 1 34 45 8870 302 238 2.00 7.19 82170 33180 4.19 4.39 4.19 0.00 3.59 2.59 2.59 160.28 209.18 2.8 267 1444629
+1 68 1 1 11 0 2951 291 216 8.82 18.04 458725 109507 9.42 42.28 88.38 186.17 1.60 14.03 20.04 336.67 656.31 1.0 131 1107928
+1 98 1 1 0 0 494 48 33 0.20 0.20 1668 8215 0.60 0.60 0.60 0.00 0.00 0.20 0.20 15.40 22.00 2.6 317 1715520
+1 87 1 1 15 9 3223 248 125 1.20 1.20 689071 67101 0.00 0.00 0.00 0.00 0.20 3.20 4.60 125.60 255.40 6.6 633 1302059
+1 79 1 1 16 3 5017 259 249 2.80 1.40 73537 237547 0.00 0.00 0.00 0.00 0.00 5.60 5.80 142.80 276.20 4.8 2114 988600
+1 92 1 1 1 0 322 63 34 0.20 0.20 321420 9762 0.00 0.00 0.00 0.00 0.00 0.40 0.60 20.60 19.20 2.4 1187 1766859
+1 93 1 1 2 1 2600 94 99 0.20 0.20 10046 93986 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 19.40 2.0 1346 1544528
+1 81 1 1 3 1 534 57 80 1.80 1.80 74648 36616 0.00 0.00 0.00 0.00 0.00 2.40 4.20 162.40 153.80 2.0 3738 1821658
+1 89 1 1 6 2 3396 212 144 0.60 2.20 196390 92323 0.00 0.00 0.00 0.00 0.00 5.20 10.00 35.40 42.00 4.0 1874 1533405
+1 95 1 1 1 0 1451 70 58 0.20 0.20 2748 18127 0.00 0.00 0.00 0.00 0.00 1.60 1.60 15.57 35.53 2.0 361 1014422
+1 87 1 1 14 7 3574 100 79 1.80 7.00 27265 45823 0.00 0.00 0.00 0.00 0.00 0.00 0.00 135.60 160.60 2.4 3159 1657016
+1 93 1 1 5 0 850 66 97 1.20 3.00 41820 96770 0.00 0.00 0.00 0.00 0.20 1.60 1.60 94.20 135.80 1.5 681 1061544
+1 98 1 1 1 1 191 14 14 0.20 0.20 7018 4533 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 7292 1863744
+1 80 1 1 8 1 2168 339 279 7.19 5.19 405747 214249 0.00 0.00 0.00 0.00 0.00 0.00 0.00 323.95 476.65 3.2 3646 1816136
+1 88 1 1 31 44 1768 101 69 1.00 1.00 61547 48953 6.19 6.19 6.19 0.00 2.40 3.79 6.39 72.06 101.00 1.0 216 1125099
+1 81 1 1 6 1 4016 666 564 2.79 1.00 425293 404456 0.00 0.00 0.00 0.00 0.00 5.19 5.99 149.70 215.97 3.0 494 1093713
+1 89 1 1 19 16 2550 309 163 0.40 0.40 197970 57938 0.00 0.00 0.00 0.00 1.60 6.20 11.60 111.40 105.60 7.6 467 1322205
+1 84 1 1 20 13 2046 230 144 1.60 2.99 198910 62811 0.00 0.00 0.00 0.00 0.00 9.78 31.34 250.10 251.50 1.3 1102 1126978
+1 93 1 1 0 0 2927 140 132 0.20 0.20 3375 195292 16.80 22.40 22.40 0.00 14.00 0.80 1.00 27.60 34.40 2.2 217 1383510
+1 92 1 1 46 49 1715 111 83 1.00 2.40 172621 26867 0.00 0.00 0.00 0.00 0.00 6.40 35.80 81.80 152.00 2.4 479 1537131
+1 92 1 1 37 54 1507 114 102 0.40 0.40 56270 67686 0.00 0.00 0.00 0.00 0.00 7.20 12.60 72.00 46.00 1.0 466 1066010
+1 87 1 1 23 21 2218 123 88 0.40 0.40 175316 24270 0.00 0.00 0.00 0.00 0.00 4.20 4.20 30.20 120.80 3.8 8833 1369906
+1 91 1 1 40 26 1207 88 104 1.80 1.80 110864 69840 7.40 18.40 20.00 8.00 8.20 1.60 1.60 130.20 149.00 3.2 193 1535515
+1 99 1 1 2 1 214 34 21 0.20 0.20 171366 14386 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 17.80 1.2 7734 1882150
+1 98 1 1 0 0 658 51 47 0.20 0.20 4331 8920 0.00 0.00 0.00 0.00 0.00 0.40 0.60 15.60 17.40 2.0 3140 1707714
+1 88 1 1 3 0 2522 167 111 0.80 0.40 30475 141122 15.03 19.44 19.04 0.00 5.41 15.23 18.64 46.49 107.82 1.0 322 1128417
+1 0 1 1 7 2 1611 67 81 0.60 0.60 31076 37271 0.00 0.00 0.00 0.00 0.00 0.20 0.20 47.60 56.80 522 95 5
+1 98 1 1 0 0 184 13 36 0.20 0.20 992 35051 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 1.4 9223 1867568
+1 90 1 1 30 43 3041 217 194 0.20 0.20 17786 30376 4.80 4.80 4.80 0.00 0.20 2.80 4.20 15.40 37.60 1.7 219 1101704
+1 95 1 1 13 13 2065 176 86 0.20 0.20 11158 46073 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.80 19.40 2.0 1191 1458336
+1 97 1 1 3 1 808 40 41 0.60 0.60 88250 84082 0.00 0.00 0.00 0.00 0.00 0.00 0.00 102.00 55.40 2.0 630 1533294
+1 89 1 1 3 0 3471 187 95 1.60 2.40 283979 13036 0.00 0.00 0.00 0.00 0.00 0.60 0.80 95.79 192.79 1.8 421 1734499
+1 71 1 1 10 1 2728 242 216 8.78 17.96 347537 75449 4.19 34.53 51.50 165.27 0.60 30.74 56.29 333.13 581.24 1.0 153 1100479
+1 90 1 1 7 0 1505 208 172 3.40 1.00 78118 5127 0.00 0.00 0.00 0.00 0.00 0.00 0.00 163.60 237.00 2.4 6385 1711518
+1 95 1 1 0 0 951 230 74 0.20 0.20 254812 254338 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 20.00 2.6 1716 1759920
+1 89 1 1 55 72 2012 153 120 0.80 2.40 26815 27304 0.00 0.00 0.00 0.00 0.00 3.00 3.20 58.80 57.00 2.2 1232 975296
+1 84 1 1 9 6 1042 109 79 2.00 3.40 135900 55307 11.00 17.60 17.60 0.00 6.40 28.40 55.40 155.00 267.60 3.0 317 949230
+1 91 1 1 14 8 2056 149 108 1.60 1.40 104174 22894 0.00 0.00 0.00 0.00 0.00 6.80 12.40 84.00 200.80 3.4 507 1396656
+1 92 1 1 7 5 2049 224 219 0.40 1.80 24158 36335 0.00 0.00 0.00 0.00 0.00 0.60 0.60 34.53 70.86 1.0 360 976131
+1 87 1 1 5 4 2857 282 159 0.40 0.60 238603 64868 0.00 0.00 0.00 0.00 0.20 13.00 13.80 36.60 143.60 1.0 427 1108354
+1 77 1 1 107 134 3658 231 159 0.80 1.40 405741 120292 26.20 42.20 62.00 53.00 10.20 53.20 98.20 161.20 245.80 1.0 192 998960
+1 0 1 1 15 6 5508 436 337 3.59 1.20 133529 32417 4.39 9.98 17.37 23.75 0.40 3.39 3.59 210.98 372.46 164 70 30
+1 68 1 1 41 47 2048 147 108 11.22 23.85 130729 19466 3.81 30.26 83.97 198.80 0.00 8.42 12.22 390.58 739.28 2.5 172 1116617
+1 73 1 1 4 0 4009 456 435 3.59 2.40 477322 429540 0.00 0.00 0.00 0.00 0.00 4.19 6.39 202.99 296.21 1.7 2480 997472
+1 96 1 1 46 57 826 52 50 0.40 1.20 110571 72773 0.00 0.00 0.00 0.00 0.00 0.40 0.60 27.80 23.60 1.2 8160 1837149
+1 93 1 1 55 79 494 58 38 0.60 0.60 94256 19869 14.60 23.40 23.40 0.00 5.80 5.60 7.80 34.80 62.60 1.0 196 1729854
+1 82 1 1 1 0 4506 264 230 0.80 1.20 268267 539532 0.20 0.40 0.40 0.00 1.80 2.20 2.20 93.20 95.40 2.2 330 1004853
+1 88 1 1 44 62 1186 110 108 0.80 0.80 119701 57634 2.40 4.40 10.40 26.20 1.40 37.80 38.60 93.60 318.60 1.7 276 974613
+1 67 1 1 20 0 5669 716 530 9.58 4.59 277884 64534 5.79 7.78 7.19 0.00 0.20 0.60 0.60 472.26 747.70 2.0 329 1065009
+1 83 1 1 8 1 4601 301 159 1.60 2.00 96261 74664 5.21 9.42 9.42 0.00 1.00 4.81 6.81 87.58 177.96 2.0 144 1073400
+1 93 1 1 3 2 1931 233 120 0.60 0.60 275724 204664 0.00 0.00 0.00 0.00 0.00 0.20 0.20 52.40 56.00 3.6 2557 1582634
+1 88 1 1 61 81 1299 270 76 0.60 0.80 246867 40709 1.60 2.40 2.40 0.00 0.80 10.58 19.56 64.87 111.38 3.2 412 1025284
+1 79 1 1 9 2 4384 236 161 1.20 3.00 275555 137235 0.00 0.00 0.00 0.00 0.20 4.00 7.00 183.00 140.20 3.2 1166 1527758
+1 96 1 1 0 0 422 73 69 0.20 0.20 61305 54320 0.20 0.20 0.20 0.00 0.20 0.60 1.00 15.77 19.76 1.0 220 1751302
+1 96 1 1 79 34 646 142 125 0.20 0.20 64251 78486 0.00 0.00 0.00 0.00 0.00 1.20 1.20 16.40 27.60 2.0 627 1008558
+1 89 1 1 1 0 696 32 59 0.20 0.20 142694 162378 0.00 0.00 0.00 0.00 0.00 27.40 45.60 20.80 35.00 2.8 5323 1680498
+1 78 1 1 1 0 523 98 51 0.20 0.20 470059 21536 12.60 88.40 231.20 449.00 0.00 50.80 101.00 18.60 241.60 3.4 174 1750059
+1 81 1 1 12 11 4904 189 184 1.00 2.40 475481 69264 7.78 54.29 132.73 316.57 0.00 64.87 115.77 57.88 125.35 1.3 120 1009396
+1 92 1 1 36 49 1394 117 94 0.60 2.00 39790 23048 2.20 4.00 5.60 8.20 1.60 3.00 3.00 50.40 83.20 1.0 159 1098501
+1 82 1 1 51 69 4418 377 286 1.20 4.00 201922 34319 0.00 0.00 0.00 0.00 0.00 18.00 25.60 38.60 117.20 6.2 1678 1386293
+1 94 1 1 37 52 1883 177 110 0.20 0.20 345074 79143 0.00 0.00 0.00 0.00 0.00 0.00 0.00 18.00 22.80 2.2 3257 1657754
+1 96 1 1 0 0 344 54 24 0.80 0.80 341813 18796 0.00 0.00 0.00 0.00 0.00 0.40 0.60 42.60 57.80 1.8 7350 1875491
+1 85 1 1 6 0 2739 262 147 1.20 1.20 286042 57739 11.18 22.36 41.52 89.62 0.40 16.37 21.36 66.87 151.90 1.7 139 1105314
+1 92 1 1 15 12 1613 154 112 0.40 1.80 23200 23589 4.60 5.80 15.00 26.40 2.00 5.40 8.00 34.40 61.00 1.6 149 972920
+1 85 1 1 260 1 993 79 60 1.34 4.41 354307 23354 36.21 76.44 307.66 941.76 1.15 10.34 29.69 90.80 482.38 1.2 162 952564
+1 98 1 1 1 0 345 50 38 0.20 0.20 42575 17007 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 19.00 1.0 465 1743290
+1 88 1 1 52 72 2227 237 162 0.40 1.80 186688 22599 7.80 7.80 7.80 0.00 4.60 9.80 9.80 38.60 77.40 1.3 198 1100078
+1 94 1 1 1 0 1284 134 77 0.20 0.20 5757 24018 0.00 0.00 0.00 0.00 0.00 0.00 0.00 19.76 42.32 1.8 778 1036022
+1 91 1 1 6 2 3009 221 149 0.80 1.20 183034 64920 0.00 0.00 0.00 0.00 0.00 3.80 6.80 68.60 113.20 2.2 623 1629750
+1 55 1 1 28 10 4126 456 315 5.41 10.02 607622 400752 22.44 84.77 290.98 492.18 1.20 113.43 172.55 309.22 682.36 5.5 124 1003078
+1 98 1 1 15 23 148 9 19 0.20 0.20 425 9693 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6033 1855592
+1 89 1 1 6 2 3626 212 182 1.00 0.80 37579 53591 0.00 0.00 0.00 0.00 0.00 1.40 1.40 53.20 93.40 3.0 2002 1532208
+1 96 1 1 130 126 1089 113 68 0.40 0.40 6399 19869 0.00 0.00 0.00 0.00 0.20 3.61 6.21 37.07 40.68 1.6 575 1018979
+1 92 1 1 2 0 260 41 37 0.20 0.20 3108 4041 0.00 0.00 0.00 0.00 0.00 1.00 1.00 19.64 22.44 1.6 472 1747073
+1 0 1 1 14 8 2329 146 92 1.00 1.00 148968 71628 0.00 0.00 0.00 0.00 0.40 6.40 10.20 73.20 120.00 541 88 12
+1 88 1 1 1 0 5414 319 195 0.20 0.20 95095 69238 4.61 5.81 13.43 16.83 0.60 8.02 13.23 16.03 35.27 1.5 134 1073443
+1 0 1 1 31 10 3783 386 327 9.80 8.60 219330 55674 2.80 7.00 12.20 23.20 0.20 4.00 5.60 445.40 717.60 292 70 30
+1 79 1 1 22 17 3865 453 359 4.60 3.20 758522 601207 0.00 0.00 0.00 0.00 0.40 4.00 4.20 255.20 353.20 1.3 687 1014354
+1 79 1 1 20 3 3675 333 283 3.40 1.60 282964 170174 1.40 20.80 38.20 49.40 0.80 51.40 62.00 161.20 443.80 5.0 325 1292325
+1 93 1 1 5 0 1891 107 86 0.60 0.60 99766 32066 0.40 0.40 0.40 0.00 1.00 2.80 5.60 49.60 69.20 1.5 271 1081690
+1 67 1 1 20 11 6131 220 120 5.40 27.00 321920 124515 0.00 0.00 0.00 0.00 0.20 2.80 15.00 386.60 528.00 5.6 779 1604088
+1 91 1 1 3 1 393 29 13 2.20 2.20 47343 10636 0.00 0.00 0.00 0.00 0.00 0.80 0.80 177.60 165.20 1.4 7316 1849734
+1 72 1 1 74 46 3174 442 351 10.20 5.60 206485 36060 6.40 17.40 32.80 75.00 0.20 2.60 9.80 460.00 801.00 2.0 184 972274
+1 94 1 1 2 1 1896 121 107 0.20 0.20 106415 47198 1.00 1.00 1.00 0.00 0.80 2.20 3.20 24.40 67.60 2.0 259 1016510
+1 92 1 1 6 2 3078 177 143 1.20 0.60 36264 47053 0.00 0.00 0.00 0.00 0.20 1.39 1.39 87.65 102.99 3.6 3294 1543616
+1 83 1 1 31 45 5475 316 316 0.80 0.80 95638 385608 1.00 1.00 1.00 0.00 0.00 0.20 0.20 59.20 88.40 2.8 232 1377392
+1 90 1 1 2 0 3693 118 110 0.80 2.00 45770 27854 0.00 0.00 0.00 0.00 0.20 1.00 1.40 54.80 80.20 1.0 1057 1055381
+1 88 1 1 54 63 2491 207 119 2.00 3.00 1010051 85472 0.80 1.20 5.20 32.00 0.20 3.20 5.00 153.80 202.00 1.5 162 1069621
+1 88 1 1 5 0 2005 207 132 3.61 2.20 97715 17133 0.00 0.00 0.00 0.00 0.00 0.00 0.00 177.96 259.92 2.4 7847 1866225
+1 93 1 1 23 29 415 34 56 0.20 0.20 28673 57303 0.00 0.00 0.00 0.00 0.00 0.40 0.40 33.47 55.91 1.2 2212 1772588
+1 74 1 1 16 1 4211 801 230 4.60 2.60 1776806 49372 0.00 0.00 0.00 0.00 0.00 17.40 31.60 248.40 531.80 3.2 843 1529254
+1 98 1 1 0 0 1073 57 51 0.20 0.20 2235 25862 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 7721 1871742
+1 88 1 1 55 80 2565 212 223 0.20 0.20 10423 264817 2.59 5.19 5.19 0.00 0.80 16.97 16.97 26.75 216.17 2.4 607 1016117
+1 92 1 1 36 50 1133 189 95 1.00 1.40 290876 217223 0.00 0.00 0.00 0.00 0.00 16.00 19.20 84.40 137.80 4.0 2282 1603541
+1 90 1 1 5 2 4455 304 190 0.80 0.60 29321 147067 0.00 0.00 0.00 0.00 0.00 1.80 1.80 56.40 66.00 2.4 930 1377046
+1 94 1 1 9 9 1547 83 55 0.20 0.20 7272 23709 0.00 0.00 0.00 0.00 0.00 0.80 0.80 15.40 69.80 1.5 986 1010408
+1 71 1 1 19 13 6576 978 227 5.80 17.20 2214365 56365 0.00 0.00 0.00 0.00 0.00 12.40 15.00 224.80 438.20 2.2 522 1097509
+1 89 1 1 68 52 1189 110 60 1.00 1.20 27373 23232 5.80 23.00 34.40 78.00 1.20 36.40 64.20 75.20 249.40 1.5 331 1023208
+1 85 1 1 94 91 3302 370 149 0.80 2.59 303202 60139 1.60 1.80 1.80 0.00 4.59 8.78 18.36 58.88 87.43 1.2 174 1126315
+1 0 1 1 25 3 1643 338 266 1.00 0.80 361869 28712 4.00 5.40 20.60 32.60 50.40 14.20 29.80 83.60 190.00 197 88 12
+1 89 1 1 6 1 1434 154 101 2.60 5.80 53733 35765 0.00 0.00 0.00 0.00 0.40 3.80 4.00 138.20 217.20 1.0 2943 1011101
+1 82 1 1 44 56 684 87 65 2.00 2.00 195824 38557 0.00 0.00 0.00 0.00 0.00 2.60 2.80 194.40 167.40 2.6 1122 1788957
+1 92 1 1 0 0 2672 289 166 0.40 0.40 80611 75919 0.00 0.00 0.00 0.00 0.00 0.00 0.00 26.75 35.13 5.4 3041 1598547
+1 69 1 1 16 4 4378 173 123 9.20 20.60 45835 24670 1.40 1.40 1.40 0.00 1.20 6.40 8.60 343.40 594.60 1.0 306 1104760
+1 70 1 1 17 1 5741 822 608 8.42 2.40 262205 60046 1.00 2.00 1.80 0.00 7.01 1.00 1.00 404.01 627.05 1.7 319 1069743
+1 93 1 1 32 41 467 106 51 0.80 2.00 80631 5836 0.00 0.00 0.00 0.00 0.00 0.60 0.60 86.00 85.80 2.0 6231 1709760
+1 95 1 1 2 1 875 40 28 0.60 0.60 98180 6014 0.00 0.00 0.00 0.00 0.00 0.20 0.20 46.60 62.40 1.2 5027 1828758
+1 94 1 1 3 1 654 35 22 1.20 2.20 99031 16033 0.00 0.00 0.00 0.00 0.00 0.00 0.00 91.38 129.26 1.0 8511 1869794
+1 89 1 1 4 0 2458 176 111 0.80 1.40 70087 28627 0.00 0.00 0.00 0.00 0.00 1.20 1.40 99.60 189.40 2.0 1258 969024
+1 86 1 1 4 0 4182 383 239 2.20 1.60 556305 413659 0.00 0.00 0.00 0.00 0.00 4.80 8.80 131.40 195.00 1.8 3443 1041373
+1 88 1 1 226 223 5011 355 242 0.40 0.20 259348 244108 1.00 8.60 22.20 40.20 0.20 4.60 23.00 22.00 67.60 3.0 130 1327346
+1 97 1 1 1 0 217 22 30 0.20 0.20 1433 7319 0.00 0.00 0.00 0.00 0.00 0.60 0.60 16.53 14.14 1.2 6829 1821007
+1 86 1 1 18 2 2535 332 162 3.80 3.80 535709 83384 0.00 0.00 0.00 0.00 0.20 6.20 7.60 219.20 386.60 5.6 548 1298520
+1 86 1 1 4 1 4147 368 242 0.40 0.40 52481 108660 2.60 4.80 3.60 0.00 1.00 6.00 6.80 40.20 74.80 1.0 366 1090760
+1 74 1 1 5 0 1950 448 175 3.20 3.00 556152 25751 0.00 0.00 0.00 0.00 0.00 8.60 14.60 248.80 406.40 3.0 1297 1047098
+1 91 1 1 34 50 2256 214 159 0.60 0.60 94024 21088 0.20 0.20 0.20 0.00 0.20 2.00 2.60 46.60 82.20 1.0 165 1053560
+1 93 1 1 1 0 2214 94 75 0.60 0.60 18542 11875 0.00 0.00 0.00 0.00 0.00 0.60 1.00 30.60 41.80 4.0 602 1638376
+1 96 1 1 19 27 405 74 57 0.20 0.20 8428 13321 0.00 0.00 0.00 0.00 0.00 0.80 0.80 15.60 16.80 1.0 397 1742846
+1 98 1 1 1 1 208 13 13 0.20 0.20 8649 3393 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.60 16.80 1.0 7381 1865600
+1 70 1 1 15 7 3196 280 216 8.00 22.40 222937 137527 10.80 28.60 42.20 67.60 2.00 16.60 23.20 297.80 590.40 1.8 181 1076869
+1 96 1 1 0 0 286 27 29 0.40 0.40 1133 7193 0.00 0.00 0.00 0.00 0.00 0.00 0.00 30.54 38.32 1.0 7295 1861094
+1 87 1 1 7 0 3135 282 202 2.79 1.00 163206 12979 1.80 2.00 17.76 60.68 0.20 4.19 7.39 132.14 252.30 3.8 233 1388909
+1 89 1 1 3 0 921 46 20 2.60 2.80 113745 20790 0.00 0.00 0.00 0.00 0.00 1.60 3.00 221.00 236.20 1.0 8829 1872480
+1 93 1 1 5 1 1304 156 75 0.40 0.40 220730 99327 0.00 0.00 0.00 0.00 0.00 17.60 17.60 33.60 115.20 5.4 2090 1557277
+1 88 1 1 4 3 3183 180 115 0.80 1.20 13539 20608 2.00 2.20 2.20 0.00 0.80 2.80 2.80 64.00 146.80 1.0 247 1011902
+1 97 1 1 2 0 913 65 49 0.40 0.60 6778 13844 0.20 0.20 0.20 0.00 0.40 2.40 2.40 33.27 108.62 2.0 315 1018493
+1 62 1 1 48 0 3560 176 111 11.82 33.67 133245 40724 10.02 46.29 60.32 126.05 0.00 37.68 49.50 444.49 899.60 2.3 181 1111000
+1 0 1 1 22 7 3510 404 264 4.79 4.39 521690 226437 27.54 52.89 44.51 6.79 1.80 2.59 2.59 260.68 455.69 280 75 25
+1 96 1 1 0 0 603 117 91 0.20 0.20 2101 12113 0.00 0.00 0.00 0.00 1.00 0.00 0.00 15.60 16.80 2.2 700 1721992
+1 77 1 1 36 27 5339 550 371 3.40 1.00 556540 474120 0.00 0.00 0.00 0.00 0.00 5.00 9.80 167.40 262.20 3.0 3441 1039946
+1 82 1 1 19 15 1764 250 121 5.00 3.20 143132 72794 0.00 0.00 0.00 0.00 0.00 9.00 9.00 211.00 357.60 7.6 3524 1594530
+1 99 1 1 0 0 132 6 9 0.20 0.20 416 4514 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7739 1880280
+1 84 1 1 2 0 551 36 33 1.80 2.99 73886 38671 0.00 0.00 0.00 0.00 0.00 2.79 4.59 199.20 202.59 1.4 2476 1792690
+1 75 1 1 23 7 6860 415 246 1.60 3.20 135679 71857 4.00 6.80 6.80 0.00 1.00 5.60 6.80 104.40 234.00 8.2 380 1310003
+1 91 1 1 4 0 2070 348 325 0.60 0.80 224711 209477 0.00 0.00 0.00 0.00 0.20 5.39 8.18 45.11 72.65 3.8 588 1047591
+1 88 1 1 3 0 1599 141 59 3.00 4.40 306725 30076 0.20 0.40 0.40 0.00 0.00 1.00 1.60 190.40 299.40 2.0 350 1030334
+1 91 1 1 8 1 1652 93 90 1.80 3.20 16587 70546 0.00 0.00 0.00 0.00 0.00 0.20 0.20 140.20 150.00 2.8 4961 1671862
+1 98 1 1 0 0 220 29 18 0.20 0.20 87868 11098 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 18.60 1.0 7253 1864013
+1 90 1 1 2 2 891 95 80 0.60 2.20 260246 123445 21.44 37.27 53.31 107.21 15.23 17.84 30.46 35.07 100.40 1.0 159 1032980
+1 55 1 1 147 122 4252 341 167 8.58 23.75 1750729 119055 11.98 52.89 127.54 319.96 2.00 101.60 126.55 351.30 758.28 3.6 134 1098617
+1 95 1 1 1 0 1747 142 51 0.20 0.20 42148 13557 0.00 0.00 0.00 0.00 0.00 16.40 16.40 15.60 51.60 2.2 4653 1725813
+1 80 1 1 9 2 4860 476 164 0.40 0.80 794073 195570 0.20 0.40 0.20 0.00 0.20 25.15 43.11 22.55 223.95 2.4 2305 1002723
+1 98 1 1 34 47 174 13 10 0.20 0.20 7611 1522 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 37.00 2.0 10061 1871970
+1 93 1 1 7 1 2676 117 90 0.40 0.20 294048 34786 1.60 2.20 2.20 0.00 0.20 6.40 10.20 39.20 58.80 1.4 350 1752752
+1 58 1 1 47 3 3870 363 173 10.40 28.20 1108597 47821 12.40 42.40 100.80 565.40 2.20 49.60 60.20 392.40 814.00 3.8 137 1097941
+1 0 1 1 34 7 4239 510 399 11.80 6.80 588065 393858 0.00 0.00 0.00 0.00 0.00 8.40 13.80 558.60 910.20 619 64 36
+1 78 1 1 17 7 2704 335 269 6.60 3.20 359579 101440 2.00 3.00 2.60 0.00 1.20 3.80 5.40 279.20 513.60 1.0 480 964971
+1 84 1 1 2 0 497 57 59 2.00 2.00 54089 32755 0.00 0.00 0.00 0.00 0.00 2.81 3.21 157.52 159.72 1.0 3650 1822097
+1 85 1 1 12 4 2194 226 165 2.00 0.80 182972 22727 6.20 9.80 21.00 32.20 5.60 29.80 33.40 139.60 310.40 2.0 137 1105118
+1 80 1 1 7 0 2989 154 122 2.00 5.61 181428 24702 10.22 23.45 95.19 232.67 2.00 4.61 28.66 83.77 255.11 1.0 134 1019537
+1 95 1 1 23 32 707 52 30 0.20 0.20 87008 8167 1.20 1.20 3.80 5.00 0.00 1.00 1.00 15.60 16.80 1.4 136 1750139
+1 95 1 1 0 0 477 45 34 0.60 1.80 70352 5080 0.00 0.00 0.00 0.00 0.00 0.40 0.40 45.11 101.20 2.2 737 1704971
+1 82 1 1 23 12 4276 426 330 4.60 1.80 295347 108678 0.00 0.00 0.00 0.00 0.00 4.40 4.60 225.20 350.20 7.4 2985 1338730
+1 97 1 1 1 1 254 16 43 0.60 0.60 2451 21013 0.00 0.00 0.00 0.00 0.00 0.00 0.00 29.40 40.80 1.0 6220 1856464
+1 91 1 1 5 2 1734 121 97 0.60 0.60 44497 99825 0.00 0.00 0.00 0.00 0.20 4.40 7.80 47.80 102.40 2.8 1897 1529088
+1 87 1 1 4 1 3313 223 131 1.00 5.39 145996 22201 0.00 0.00 0.00 0.00 0.40 6.79 7.19 53.09 85.23 2.6 566 1093983
+1 99 1 1 0 0 139 10 11 0.20 0.20 444 4013 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 7306 1867538
+1 98 1 1 0 0 147 7 22 0.20 0.20 431 23982 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7581 1878664
+1 91 1 1 3 2 1531 93 76 0.40 0.80 101164 59291 8.40 16.20 18.60 16.60 0.40 23.20 27.80 23.60 89.60 1.0 176 1073318
+1 92 1 1 1 0 2734 153 105 1.00 1.00 51527 50891 0.00 0.00 0.00 0.00 0.00 1.00 1.20 57.88 72.85 4.0 754 1060145
+1 87 1 1 2 2 3072 273 172 0.80 1.00 223683 23110 0.00 0.00 0.00 0.00 0.00 2.40 2.80 63.60 99.60 2.5 758 1119720
+1 0 1 1 36 10 2883 150 103 4.41 28.66 283299 24843 0.00 0.00 0.00 0.00 0.00 9.22 19.44 288.58 371.34 604 82 15
+1 88 1 1 2 1 510 23 24 0.60 2.20 18019 9643 0.00 0.00 0.00 0.00 0.00 0.00 0.00 40.00 58.00 1.8 6236 1832586
+1 96 1 1 1 0 284 42 13 0.80 1.00 229389 9929 0.00 0.00 0.00 0.00 0.00 0.00 0.00 48.20 66.60 1.2 7281 1877285
+1 94 1 1 1 0 1425 137 88 0.20 0.20 186378 24064 1.60 2.00 2.00 0.00 0.40 1.00 1.00 18.80 37.80 1.0 364 1016707
+1 95 1 1 1 0 402 63 56 0.20 0.20 1691 8433 0.00 0.00 0.00 0.00 0.00 0.20 0.40 14.20 17.20 1.4 1359 1746139
+1 87 1 1 2 1 2912 250 217 1.00 2.80 141678 400483 0.60 0.60 0.60 0.00 0.40 13.20 26.00 85.20 127.80 3.0 290 1375298
+1 97 1 1 0 0 190 16 20 0.20 0.20 14151 26844 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 2720 1773112
+1 95 1 1 30 47 553 115 78 0.20 0.20 295375 45901 6.20 11.40 9.00 0.00 2.60 0.00 0.00 24.80 19.20 3.8 265 1715720
+1 82 1 1 5 0 4236 359 245 2.80 4.00 133690 28826 1.60 2.80 2.80 0.00 1.80 2.20 2.20 197.80 303.40 1.0 229 1054146
+1 90 1 1 3 0 2262 479 120 0.60 1.00 297491 357051 0.00 0.00 0.00 0.00 0.00 1.00 1.00 52.00 71.40 2.8 989 1547722
+1 90 1 1 19 5 3533 200 170 0.80 0.80 48462 62104 0.00 0.00 0.00 0.00 0.00 3.99 7.19 59.08 90.22 1.8 387 1065178
+1 90 1 1 2 0 2521 212 118 0.40 1.80 128473 22065 0.00 0.00 0.00 0.00 0.20 2.80 3.00 33.40 59.20 2.6 686 1318669
+1 84 1 1 5 1 4030 270 223 0.80 1.20 23443 90985 0.60 2.40 1.20 0.00 2.00 7.80 12.60 53.40 86.40 3.2 511 1629358
+1 96 1 1 2 1 1700 86 71 0.20 0.20 2382 9266 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.40 17.40 2.0 6339 1722656
+1 87 1 1 61 81 3280 154 134 0.60 0.60 147416 194494 0.00 0.00 0.00 0.00 0.00 5.00 5.60 105.00 63.80 3.4 1046 1549746
+1 0 1 1 24 2 2546 138 83 5.20 16.40 137284 24420 0.00 0.00 0.00 0.00 0.00 3.80 4.00 155.00 302.80 874 86 12
+1 93 1 1 6 1 2533 105 128 1.40 1.20 56544 236441 0.00 0.00 0.00 0.00 0.00 0.60 0.60 66.60 109.60 2.0 534 1524600
+1 94 1 1 40 59 1416 45 60 0.80 1.00 25327 24281 0.00 0.00 0.00 0.00 4.40 0.20 0.40 46.40 73.60 1.0 621 1056819
+1 90 1 1 0 0 1704 365 358 0.20 0.20 11320 39615 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.40 22.60 2.2 556 1702181
+1 73 1 1 9 6 7811 245 195 2.40 9.40 86551 20758 0.00 0.00 0.00 0.00 0.00 10.80 14.60 192.40 225.00 4.6 1932 1386678
+1 89 1 1 4 1 3133 285 168 1.20 1.60 106492 21962 1.80 2.20 9.60 47.40 1.00 14.40 29.20 79.60 142.40 1.0 159 1101843
+1 97 1 1 5 4 227 25 23 0.40 0.40 33963 9561 1.40 3.99 11.78 27.94 0.20 0.60 2.79 23.95 32.34 1.0 161 1751249
+1 84 1 1 120 0 2846 196 549 0.20 0.20 24954 199568 0.00 0.00 0.00 0.00 0.00 65.00 65.00 15.20 30.40 2.2 667 1714038
+1 89 1 1 2 0 384 61 61 0.80 0.80 318420 361675 0.00 0.00 0.00 0.00 0.00 11.20 15.60 59.80 96.00 1.2 394 1753864
+1 98 1 1 2 1 264 20 29 0.20 0.20 14453 57715 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.56 16.97 1.0 6870 1854566
+1 95 1 1 11 16 356 188 46 0.20 0.20 328899 301873 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.4 5744 1834547
+1 96 1 1 9 7 919 61 63 0.60 0.40 23544 42471 0.00 0.00 0.00 0.00 0.00 2.40 2.80 31.00 52.20 2.2 506 1532699
+1 86 1 1 4 2 2668 323 144 1.20 2.40 1018115 32869 6.41 7.41 7.21 0.00 6.21 2.20 2.20 64.13 130.46 2.8 400 1096968
+1 73 1 1 21 0 5553 388 219 0.40 0.60 611792 261670 17.00 59.80 112.20 137.60 5.60 63.20 85.40 40.80 122.60 2.4 130 1006030
+1 76 1 1 8 2 3275 344 162 2.20 3.60 568833 261366 18.00 31.80 84.80 150.80 3.20 42.00 63.20 87.80 391.80 1.0 166 1009979
+1 94 1 1 1 0 2100 78 80 0.60 3.00 66955 32083 2.60 3.20 3.20 0.00 0.20 0.20 0.20 21.40 33.20 2.0 263 1752520
+1 79 1 1 9 1 5001 211 134 4.40 5.00 367556 46509 0.00 0.00 0.00 0.00 0.00 19.40 37.40 208.80 410.20 3.2 1079 1387750
+1 90 1 1 2 0 4534 364 253 0.40 0.40 15433 69407 0.00 0.00 0.00 0.00 0.80 1.60 1.60 32.60 52.00 1.3 554 1077997
+1 80 1 1 57 76 3219 328 182 1.80 1.40 247623 202180 0.00 0.00 0.00 0.00 0.00 9.98 17.37 94.81 182.44 1.3 668 1063253
+1 95 1 1 2 1 1534 92 77 0.20 0.20 6186 30997 0.00 0.00 0.00 0.00 0.20 1.20 1.40 16.20 16.80 2.6 549 1530248
+1 97 1 1 1 1 249 34 27 0.20 0.20 91624 10687 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.80 17.80 1.4 7600 1869464
+1 91 1 1 34 32 1393 242 145 1.40 1.80 168392 200608 0.00 0.00 0.00 0.00 0.00 1.20 2.00 94.00 134.20 3.6 1847 1576965
+1 91 1 1 2 2 2978 177 118 0.60 0.60 17929 38643 1.60 1.80 1.80 0.00 0.40 11.00 13.20 43.40 79.00 2.0 178 1015352
+1 58 1 1 29 2 5239 707 550 9.20 12.60 613648 72642 7.20 29.80 70.20 143.00 2.60 36.60 45.60 550.40 851.80 10.4 235 1284782
+1 96 1 1 1 0 2899 66 70 0.20 0.20 5039 57219 0.00 0.00 0.00 0.00 0.00 0.00 0.00 35.40 17.60 2.2 2536 1644000
+1 95 1 1 1 1 1638 117 48 0.20 0.20 504952 63641 0.00 0.00 0.00 0.00 0.00 0.80 1.60 15.60 17.20 2.0 8385 1838173
+1 93 1 1 49 60 778 109 84 0.60 0.60 70750 34542 0.00 0.00 0.00 0.00 0.00 0.60 0.60 58.40 111.40 1.0 644 1017838
+1 92 1 1 1 0 1458 120 92 0.40 0.40 26906 28056 0.40 0.40 0.40 0.00 0.00 3.40 3.60 27.60 48.20 1.0 188 1081674
+1 94 1 1 1 0 756 53 34 0.80 0.80 20042 23249 0.00 0.00 0.00 0.00 0.00 0.00 0.00 58.60 83.60 1.0 1185 1745314
+1 0 1 1 18 14 1344 412 179 0.40 0.40 595473 535206 5.59 10.78 9.78 0.00 2.20 1.00 1.20 38.52 98.20 343 89 11
+1 88 1 1 5 0 1477 78 104 1.40 1.20 99256 62865 0.20 0.20 0.20 0.00 0.00 4.00 7.00 128.20 184.20 3.5 701 1059029
+1 98 1 1 1 0 319 44 37 0.20 0.20 89517 23455 0.00 0.00 0.00 0.00 0.00 2.40 2.40 17.00 22.40 3.2 1019 1716581
+1 94 1 1 18 26 436 95 34 0.20 0.20 333288 3395 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.20 2.8 2018 1719213
+1 71 1 1 16 10 7028 785 368 1.80 2.20 369782 215738 3.60 8.60 18.00 22.40 5.40 4.00 5.80 193.80 318.20 6.4 220 1587542
+1 81 1 1 5 0 3901 222 134 3.59 3.39 441690 89857 5.39 8.38 8.38 0.00 2.79 9.38 10.98 162.48 308.38 1.7 216 1115104
+1 87 1 1 1 0 4611 353 201 0.60 0.80 37316 207873 0.60 1.00 1.00 0.00 0.20 2.79 4.59 51.50 72.06 1.0 238 997613
+1 92 1 1 2 1 2028 137 75 0.80 1.40 54960 51440 1.40 1.80 1.80 0.00 0.00 1.60 1.60 41.52 53.29 2.5 155 1124671
+1 90 1 1 1 0 2900 153 79 0.40 0.40 257398 59018 0.20 1.00 0.80 0.00 0.00 25.85 25.85 197.19 101.80 1.7 921 1017114
+1 74 1 1 15 13 4549 389 222 1.40 4.00 331716 52806 5.00 11.20 35.00 64.60 0.60 52.80 80.20 114.00 333.40 1.7 316 998442
+1 68 1 1 8 0 5874 556 386 5.20 5.40 517390 80605 14.20 28.60 73.20 159.20 1.20 11.20 16.60 308.00 532.60 2.0 163 988098
+1 91 1 1 6 0 1375 108 81 2.00 2.00 34508 22602 1.80 1.80 1.80 0.00 0.20 2.00 2.61 78.96 137.27 1.8 255 1114565
+1 94 1 1 34 44 698 69 72 0.40 0.40 94947 66105 0.00 0.00 0.00 0.00 0.00 1.40 2.20 38.20 60.40 1.4 630 1060845
+1 51 1 1 18 1 5416 305 152 15.00 13.60 353139 55246 26.40 77.40 205.40 410.60 3.00 5.60 8.40 737.40 1365.00 2.2 204 977618
+1 92 1 1 2 1 1969 214 207 0.20 0.20 86898 410188 0.80 1.00 1.00 0.00 0.40 3.00 3.00 18.40 34.80 2.2 182 1376811
+1 85 1 1 2 0 3578 459 248 1.40 3.20 452115 428921 0.00 0.00 0.00 0.00 0.00 9.40 9.40 132.80 152.40 2.0 367 1044480
+1 92 1 1 34 51 2235 430 73 0.60 0.60 12335 21463 0.00 0.00 0.00 0.00 0.20 2.20 2.81 50.70 109.02 1.0 1167 1018240
+1 87 1 1 16 2 1974 190 153 0.20 0.20 111053 58062 5.19 21.96 72.65 190.22 2.00 23.35 42.51 15.97 73.25 1.0 131 1054119
+1 78 1 1 28 28 2755 385 340 7.82 2.20 249104 74852 0.00 0.00 0.00 0.00 0.00 0.00 0.00 372.75 548.30 2.0 7525 1868382
+1 0 1 1 9 7 1530 247 135 0.40 0.40 14513 61905 13.80 19.20 30.40 24.20 10.40 14.80 18.40 26.80 186.20 141 89 11
+1 87 1 1 8 4 2374 210 101 0.80 0.80 34810 20583 3.60 8.80 28.00 53.40 1.00 6.00 11.40 60.20 104.00 1.2 138 1111253
+1 73 1 1 23 7 4311 163 133 2.80 7.80 103307 19555 0.00 0.00 0.00 0.00 0.20 29.00 30.00 198.60 381.00 4.4 2145 1348960
+1 90 1 1 15 11 2198 305 171 0.60 1.80 294877 57789 1.60 2.00 6.60 8.40 12.20 8.00 8.60 33.80 78.60 1.2 159 1085358
+1 90 1 1 3 1 388 32 22 2.00 2.00 80840 24148 0.00 0.00 0.00 0.00 0.00 3.01 5.41 179.96 170.14 1.6 7886 1869640
+1 97 1 1 2 0 909 81 62 1.00 1.00 4380 16902 2.40 2.60 2.60 0.00 0.00 0.40 0.40 69.80 70.40 1.0 197 999130
+1 94 1 1 25 31 2300 104 105 0.20 0.20 15051 30009 3.80 6.60 5.60 2.40 3.00 0.40 0.40 20.40 16.80 2.2 152 1710746
+1 92 1 1 45 49 1883 134 118 0.40 0.40 122276 39706 0.00 0.00 0.00 0.00 0.00 4.01 4.01 32.46 69.94 1.0 1096 999726
+1 94 1 1 2 1 4381 140 154 0.40 1.80 22358 25160 0.40 0.40 0.40 0.00 0.60 0.20 0.20 37.20 60.00 1.5 313 1015656
+1 92 1 1 20 29 2296 358 102 0.20 0.20 239803 234741 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 18.20 3.6 613 1742194
+1 92 1 1 157 165 1225 220 16 1.80 2.00 1170456 9245 0.00 0.00 0.00 0.00 0.00 0.60 0.60 136.40 199.00 2.4 8416 1864085
+1 78 1 1 18 13 7525 519 188 4.00 11.40 762806 71610 0.20 0.40 0.40 0.00 0.00 5.20 5.60 192.00 289.20 1.2 378 1009299
+1 87 1 1 15 18 565 45 40 2.20 2.20 62897 142595 0.00 0.00 0.00 0.00 0.00 2.00 2.00 201.00 170.80 1.2 5538 1842536
+1 83 1 1 2 0 2560 286 237 0.80 3.60 218944 233957 0.00 0.00 0.00 0.00 0.00 26.20 52.40 39.60 54.60 2.2 3274 1737648
+1 63 1 1 80 48 7544 1096 297 3.80 7.00 2207009 200168 10.00 21.60 21.20 0.00 3.40 15.60 19.00 259.40 626.80 6.4 361 1316955
+1 98 1 1 0 0 171 19 22 0.20 0.20 456 7345 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 7346 1865486
+1 91 1 1 4 2 2039 227 129 0.60 0.60 115245 59460 0.00 0.00 0.00 0.00 0.00 1.40 2.80 47.80 85.00 2.2 526 1629592
+1 96 1 1 0 0 313 9 14 0.20 0.20 485 11607 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.80 18.00 1.0 371 1730882
+1 77 1 1 28 2 2824 172 111 6.60 18.00 393444 65196 0.00 0.00 0.00 0.00 0.00 5.40 6.20 247.00 487.00 2.5 1606 1110507
+1 97 1 1 0 0 603 52 62 0.20 0.20 2318 56100 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.60 17.20 1.0 483 1730390
+1 96 1 1 0 0 201 18 21 0.20 0.20 18913 31010 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.43 16.83 1.0 2731 1776678
+1 72 1 1 10 2 3731 321 257 1.40 1.20 479961 501134 8.00 37.00 97.40 772.40 0.00 52.60 103.20 139.00 168.20 2.6 275 1063549
+1 96 1 1 3 2 328 54 26 0.60 1.80 28411 8183 0.00 0.00 0.00 0.00 0.00 1.40 2.61 42.89 55.71 1.0 6658 1863231
+1 92 1 1 9 7 2523 214 104 0.60 0.60 50827 31696 0.00 0.00 0.00 0.00 0.20 5.60 6.80 47.40 103.40 6.0 1730 1314139
+1 93 1 1 1 1 1536 41 28 0.20 0.20 7532 9757 0.00 0.00 0.00 0.00 0.00 0.60 0.60 15.63 20.04 1.2 9006 1876935
+1 88 1 1 41 2 2558 195 167 0.40 0.40 57499 66239 7.60 13.20 10.40 0.00 1.00 8.40 8.40 41.60 52.80 2.4 320 1718912
+1 82 1 1 6 0 4507 446 381 5.00 1.40 229819 58808 0.00 0.00 0.00 0.00 1.00 0.00 0.00 237.60 368.20 2.4 233 1710437
+1 97 1 1 1 0 864 67 65 0.20 0.20 4103 20315 0.00 0.00 0.00 0.00 0.00 0.60 0.60 15.77 21.96 3.8 232 1087649
+1 90 1 1 14 20 364 35 34 0.40 0.40 18601 17863 0.00 0.00 0.00 0.00 0.00 0.20 0.20 37.60 39.60 2.0 980 1765301
+1 92 1 1 1 0 623 145 59 0.40 0.40 569925 235261 0.00 0.00 0.00 0.00 0.00 26.20 51.80 55.40 101.20 3.8 5053 1830592
+1 59 1 1 41 1 4425 523 387 11.80 19.80 436938 105307 0.00 0.00 0.00 0.00 0.00 11.80 12.40 505.00 925.00 2.5 1401 1106198
+1 86 1 1 3 0 2363 343 161 1.60 1.40 69671 29210 2.20 5.00 11.20 27.20 0.80 13.60 13.60 111.20 176.00 1.0 206 1098842
+1 77 1 1 7 1 919 113 76 3.80 3.00 216713 65818 0.00 0.00 0.00 0.00 0.00 2.40 2.40 322.20 404.00 2.4 1197 1791611
+1 73 1 1 12 1 3562 292 249 8.00 5.40 305047 77066 6.60 50.00 119.40 298.40 1.00 16.20 24.40 366.60 722.80 2.4 489 1053720
+1 72 1 1 30 3 3912 447 338 11.16 5.38 460650 120719 3.39 4.38 4.78 0.60 1.99 9.76 19.12 404.98 711.95 4.0 364 1039165
+1 92 1 1 13 13 1542 149 70 0.20 0.20 225431 55270 5.80 10.20 11.00 1.60 0.20 0.40 0.40 15.00 39.20 1.0 179 1074454
+1 98 1 1 19 28 184 10 15 0.20 0.20 3477 46599 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 7878 1875126
+1 93 1 1 1 0 1773 89 65 0.40 0.40 15913 20733 0.00 0.00 0.00 0.00 0.00 0.80 1.00 35.73 56.09 2.4 410 1087997
+1 77 1 1 30 24 5787 907 494 1.00 1.40 330017 19042 0.00 0.00 0.00 0.00 0.20 12.18 16.17 77.64 286.83 5.0 1794 1544883
+1 97 1 1 1 1 513 300 72 0.20 0.20 523790 498160 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 16.80 2.6 5735 1834579
+1 82 1 1 3 0 503 44 31 2.79 2.79 124355 51038 0.00 0.00 0.00 0.00 0.00 4.39 7.58 254.69 255.29 2.4 2331 1815754
+1 95 1 1 9 8 1089 43 31 0.20 0.20 6914 18059 0.00 0.00 0.00 0.00 0.00 0.80 1.40 15.60 48.80 1.0 664 1017936
+1 74 1 1 131 3 3379 354 626 0.60 2.20 232824 487837 0.00 0.00 0.00 0.00 0.00 67.00 71.60 32.60 66.00 2.4 1051 1714381
+1 66 1 1 10 0 3628 364 250 9.20 22.20 413713 95747 3.20 11.80 24.40 40.00 0.20 36.00 47.40 345.40 613.80 2.4 336 1106598
+1 0 1 1 3 1 1059 456 127 0.40 0.40 1005339 632144 0.00 0.00 0.00 0.00 0.00 0.40 0.40 33.20 44.80 550 93 7
+1 87 1 1 6 0 3819 311 176 1.80 1.60 15499 64796 0.00 0.00 0.00 0.00 0.00 0.60 0.60 55.20 100.00 2.2 525 1076906
+1 0 1 1 3 0 3953 340 251 0.60 1.80 147331 103576 1.00 2.00 2.00 0.00 0.00 7.21 8.02 84.77 280.96 325 79 21
+1 0 1 1 10 2 1826 291 182 1.40 2.00 121406 74108 15.83 24.85 59.92 68.54 12.22 21.24 29.26 75.35 223.45 218 86 14
+1 95 1 1 2 2 2379 220 221 0.20 0.20 23448 54657 0.00 0.00 0.00 0.00 0.40 0.60 0.80 15.80 22.20 2.0 1147 1056250
+1 97 1 1 0 0 217 17 46 0.20 0.20 1977 49154 0.00 0.00 0.00 0.00 0.00 0.60 1.00 15.60 17.80 1.0 479 1730376
+1 95 1 1 1 0 2129 84 76 0.40 0.40 27000 23093 0.00 0.00 0.00 0.00 0.40 0.20 0.20 34.80 34.40 2.2 741 1717045
+1 72 1 1 556 0 5352 406 366 3.79 1.40 191582 63557 0.00 0.00 0.00 0.00 0.40 0.80 1.20 193.41 300.40 4.6 2846 1375340
+1 97 1 1 3 0 1372 76 68 0.40 1.80 150618 119814 0.00 0.00 0.00 0.00 0.00 0.20 0.20 75.40 47.80 2.4 1435 1542104
+1 77 1 1 6 5 1892 136 109 1.60 2.00 622687 114823 25.60 46.80 127.80 335.60 0.20 76.40 145.80 108.60 213.00 1.0 242 987955
+1 95 1 1 0 0 668 100 126 0.20 0.20 42976 105204 0.00 0.00 0.00 0.00 0.00 0.20 0.20 17.20 19.40 3.0 1000 1716696
+1 90 1 1 0 0 2358 254 186 0.20 0.20 128305 68723 3.40 5.60 5.40 0.00 0.20 5.40 5.60 21.60 97.80 1.7 275 1018675
+1 91 1 1 2 1 2552 179 122 0.60 2.00 55959 40816 0.00 0.00 0.00 0.00 0.00 0.60 0.80 48.00 56.80 2.2 432 1532312
+1 93 1 1 28 40 2417 121 150 0.60 0.60 6596 18532 0.40 0.40 0.40 0.00 0.20 0.00 0.00 36.80 48.40 2.0 273 1715830
+1 83 1 1 43 31 2296 157 111 2.80 1.80 300099 56847 7.40 22.60 47.20 119.20 0.80 13.00 31.00 166.80 355.80 1.2 298 1086066
+1 94 1 1 2 0 1067 112 118 0.40 0.40 60677 38355 1.60 1.60 1.60 0.00 0.00 13.63 14.23 184.57 80.76 2.8 315 1061732
+1 68 1 1 825 15 4132 182 164 1.60 2.99 79557 167314 6.79 22.95 23.15 0.20 1.20 52.10 60.28 74.85 153.69 1.0 200 1061000
+1 80 1 1 34 41 2102 297 315 4.80 1.40 430457 412366 0.00 0.00 0.00 0.00 0.00 34.40 68.80 232.20 334.60 1.6 6224 1844643
+1 94 1 1 5 0 1187 142 84 1.20 1.00 22717 16533 0.00 0.00 0.00 0.00 0.40 2.20 3.21 99.60 138.68 4.5 1099 1018461
+1 87 1 1 11 7 3648 139 143 0.40 0.60 178028 95235 5.40 10.20 7.60 0.00 5.40 14.80 15.20 33.80 170.80 2.2 410 1068349
+1 85 1 1 17 10 3585 237 178 0.40 0.40 100434 111345 1.60 3.20 6.60 9.40 0.20 30.20 34.40 42.20 153.20 1.0 251 978011
+1 98 1 1 2 1 201 29 25 0.20 0.20 101451 7182 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 18.20 2.0 4731 1848256
+1 78 1 1 22 12 5364 167 94 2.20 7.80 105947 84709 0.00 0.00 0.00 0.00 0.00 1.60 1.60 210.80 209.20 4.2 795 1336144
+1 91 1 1 25 37 3546 138 88 0.20 0.20 42325 23463 3.40 3.40 3.40 0.00 0.40 2.80 4.20 17.80 21.40 1.0 254 1127160
+1 90 1 1 23 31 2875 168 201 1.60 0.80 37644 23857 0.00 0.00 0.00 0.00 0.20 0.20 0.20 96.60 133.40 2.0 863 1721434
+1 89 1 1 60 60 942 110 70 0.20 0.20 36442 28807 0.00 0.00 0.00 0.00 0.00 0.80 0.80 15.60 16.80 1.8 3834 1774080
+1 0 1 1 8 3 864 260 132 1.20 5.20 1965524 1801623 1.60 2.80 10.60 18.40 0.80 3.00 3.00 60.20 121.80 177 91 9
+1 97 1 1 4 2 234 13 15 0.80 0.40 14481 11215 0.00 0.00 0.00 0.00 0.00 0.00 0.00 47.40 63.80 1.0 6132 1856736
+1 89 1 1 5 0 4500 205 142 0.40 0.40 33583 31034 0.00 0.00 0.00 0.00 0.00 7.00 12.60 30.60 42.00 1.0 719 1076979
+1 74 1 1 8 1 4754 440 395 6.40 1.80 168486 310473 1.40 3.20 2.80 0.00 0.20 1.40 1.40 305.80 556.20 3.6 278 1006816
+1 89 1 1 1 0 257 26 40 0.20 0.20 5230 137977 7.20 13.40 13.20 0.00 0.80 7.60 9.40 17.20 30.60 1.6 434 1743578
+1 97 1 1 1 1 195 16 17 0.20 0.20 7032 5022 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 7321 1867607
+1 97 1 1 0 0 1079 16 24 0.20 0.20 2253 6504 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 8306 1864912
+1 82 1 1 10 3 6340 208 154 1.00 1.40 171628 167282 0.00 0.00 0.00 0.00 0.00 16.40 24.00 112.80 180.80 2.8 3816 1338878
+1 85 1 1 1 0 3810 363 251 1.00 0.40 51395 229561 0.40 2.40 1.80 0.00 0.40 6.21 6.81 54.51 129.66 3.7 390 1017385
+1 94 1 1 1 1 816 56 30 0.20 0.20 14463 13879 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 44.80 1.7 678 1069448
+1 84 1 1 2 2 2412 163 103 0.40 0.40 164340 80066 0.00 0.00 0.00 0.00 0.00 13.43 24.45 31.46 104.21 2.0 492 1122022
+1 96 1 1 2 1 294 36 26 0.40 0.40 24961 4284 0.00 0.00 0.00 0.00 0.00 0.00 0.00 35.60 40.20 1.4 7074 1846030
+1 98 1 1 0 0 230 28 16 0.20 0.20 87903 7919 0.00 0.00 0.00 0.00 0.00 0.00 0.00 23.20 17.60 1.2 6766 1826779
+1 97 1 1 13 13 286 109 39 0.20 0.20 186850 188310 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 16.80 2.2 5734 1834528
+1 0 1 1 5 2 811 81 81 0.60 0.60 95158 85829 7.21 10.82 10.82 0.00 6.01 24.25 28.26 57.11 213.03 310 91 9
+1 97 1 1 1 0 305 24 26 1.40 1.40 13475 8242 0.00 0.00 0.00 0.00 0.00 0.00 0.00 65.27 96.61 1.4 7402 1862813
+1 80 1 1 7 0 2719 417 373 7.60 2.00 208007 21557 0.00 0.00 0.00 0.00 0.80 0.00 0.00 356.80 513.20 2.4 1566 1778386
+1 86 1 1 6 1 2076 291 240 4.60 2.40 117367 26833 0.60 0.60 0.60 0.00 2.00 0.20 0.40 222.40 328.20 1.4 328 1725534
+1 98 1 1 1 1 210 15 28 0.20 0.20 26812 13536 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.80 17.40 1.0 7261 1875328
+1 93 1 1 11 5 1522 244 123 0.80 1.00 140661 21563 5.21 10.82 25.45 54.31 0.80 3.41 28.66 72.95 200.60 2.2 167 977813
+1 66 1 1 13 2 3416 224 175 10.40 35.20 96120 93186 1.60 2.00 2.00 0.00 0.40 2.40 2.40 332.00 638.20 1.3 188 1088254
+1 99 1 1 1 0 205 28 22 0.20 0.20 881 5799 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 2.2 6193 1724072
+1 75 1 1 15 5 5760 227 145 1.80 2.20 449816 72063 10.78 20.16 44.51 66.47 7.19 16.57 19.16 194.21 282.63 3.8 161 1455023
+1 88 1 1 5 0 1776 106 29 4.40 17.80 200983 13030 0.00 0.00 0.00 0.00 0.00 2.20 4.40 221.80 333.20 1.8 5306 1832483
+1 89 1 1 5 3 1926 417 175 0.20 0.60 271043 264934 0.00 0.00 0.00 0.00 0.00 16.37 16.37 33.13 60.28 4.2 2412 1574105
+1 90 1 1 1 0 354 66 59 0.20 0.20 152787 18630 1.20 1.40 1.40 0.00 0.00 6.99 10.18 15.57 37.33 1.8 202 1740099
+1 79 1 1 41 49 4568 441 442 6.00 2.00 202078 21101 0.00 0.00 0.00 0.00 0.00 0.20 0.20 296.80 457.60 3.0 532 1712181
+1 0 1 1 35 5 1636 402 152 8.00 7.00 609058 609562 5.20 10.80 10.80 0.00 0.80 14.40 16.40 279.20 630.40 251 78 22
+1 91 1 1 2 0 2799 145 91 0.80 0.80 42789 21865 0.00 0.00 0.00 0.00 0.00 0.20 0.40 59.60 92.60 1.6 1967 1753906
+1 95 1 1 1 0 341 44 47 0.60 0.60 913 23172 0.00 0.00 0.00 0.00 0.00 1.00 1.20 50.40 50.80 1.0 587 1730664
+1 69 1 1 34 24 5281 696 622 6.99 1.80 362147 173227 16.17 31.94 35.93 6.39 0.00 8.58 13.17 342.91 552.69 2.0 250 1031463
+1 1 1 1 56 48 2173 306 183 2.00 7.78 330940 138458 0.00 0.00 0.00 0.00 2.00 16.97 30.34 93.61 149.10 582 86 12
+1 93 1 1 2 1 2020 136 71 0.40 0.40 299684 9213 0.00 0.00 0.00 0.00 0.00 0.40 0.40 42.00 42.60 1.0 1086 1743760
+1 92 1 1 5 3 1714 87 54 1.40 1.40 33334 20103 0.00 0.00 0.00 0.00 0.00 6.80 10.00 70.80 125.20 2.5 709 1067816
+1 90 1 1 14 11 3731 238 185 0.80 3.39 145128 69890 0.20 0.20 0.20 0.00 0.20 4.39 6.39 59.68 112.77 1.0 382 992198
+1 90 1 1 0 0 456 31 38 0.20 0.20 624 9687 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.00 16.80 1.6 748 1757904
+1 96 1 1 2 1 506 28 51 0.60 0.40 45758 37433 0.00 0.00 0.00 0.00 0.00 0.00 0.00 37.80 40.40 1.2 7424 1876323
+1 83 1 1 14 12 4994 264 125 1.79 4.58 805100 42986 4.78 14.34 45.42 120.12 1.20 8.37 8.57 69.92 268.92 3.2 137 996161
+1 91 1 1 2 1 1536 133 110 1.40 3.80 24308 22390 1.20 1.20 6.40 10.60 0.60 4.60 5.00 57.80 113.00 1.2 162 1102811
+1 85 1 1 1 1 4923 221 239 0.80 2.40 9833 244241 5.21 5.81 5.81 0.00 0.60 0.40 0.40 47.70 90.98 1.5 231 1001451
+1 90 1 1 8 2 1659 168 101 1.20 6.00 228233 112080 0.00 0.00 0.00 0.00 0.00 2.80 4.20 172.60 145.40 2.4 753 1528994
+1 94 1 1 50 59 678 54 96 0.40 0.20 54423 111830 0.00 0.00 0.00 0.00 0.00 0.60 0.80 20.20 22.60 1.0 495 1065461
+1 94 1 1 2 0 324 33 22 0.80 0.80 67055 23653 0.00 0.00 0.00 0.00 0.00 0.20 0.20 68.80 70.00 1.2 1409 1763248
+1 78 1 1 16 10 2937 369 199 1.60 1.40 301093 44564 4.80 34.60 85.60 153.20 1.20 16.60 30.60 91.60 317.00 1.5 141 1103562
+1 91 1 1 0 0 458 51 48 0.40 0.40 57722 8820 0.00 0.00 0.00 0.00 0.00 5.40 10.00 37.20 48.80 2.0 1834 1761584
+1 94 1 1 0 0 296 54 31 0.20 0.20 261848 10456 0.00 0.00 0.00 0.00 0.00 7.80 15.40 15.60 72.00 2.4 4074 1837883
+1 88 1 1 42 60 2663 199 123 1.00 2.00 271197 145550 17.60 25.40 25.40 0.00 15.20 3.60 4.40 72.40 110.80 2.8 239 989875
+1 76 1 1 10 1 1612 410 68 2.80 2.60 137882 42400 0.00 0.00 0.00 0.00 0.00 5.00 6.60 210.00 218.00 1.6 2281 1805726
+1 84 1 1 65 90 5402 250 194 0.20 0.20 26968 61675 0.00 0.00 0.00 0.00 0.20 2.60 3.40 144.60 116.40 1.5 370 1108394
+1 93 1 1 0 0 2879 140 148 0.20 0.20 5634 34852 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 16.80 2.4 266 1709136
+1 90 1 1 1 0 2655 196 151 1.20 0.60 198790 31288 0.00 0.00 0.00 0.00 0.00 0.00 0.00 68.60 89.40 2.6 2347 1699754
+1 85 1 1 2 0 1929 120 82 2.20 2.40 322206 37095 0.00 0.00 0.00 0.00 0.00 0.60 0.80 125.60 170.20 2.6 4042 1779082
+1 83 1 1 2 0 7713 385 241 0.40 0.40 104459 31817 0.00 0.00 0.00 0.00 0.80 7.40 11.00 30.00 62.40 1.0 981 1077842
+1 81 1 1 17 15 3706 678 397 2.00 3.39 495175 178549 0.00 0.00 0.00 0.00 0.00 5.19 9.98 139.72 254.09 4.6 2878 1582806
+1 80 1 1 4 0 1108 179 138 3.40 2.20 231882 71409 8.00 8.60 8.40 0.00 0.00 8.40 15.80 230.00 267.40 1.8 307 1806805
+1 95 1 1 3 0 995 75 69 0.80 1.00 66503 19072 1.20 1.40 1.40 0.00 0.20 9.80 18.40 61.00 75.00 1.0 211 1014606
+1 77 1 1 121 112 5068 438 338 4.60 1.60 287559 161177 0.00 0.00 0.00 0.00 0.00 16.80 39.60 220.00 376.00 3.8 4462 1335558
+1 63 1 1 15 4 4503 604 476 7.40 5.60 380857 140991 0.00 0.00 0.00 0.00 0.20 30.60 37.60 380.20 750.60 1.8 1215 996741
+1 90 1 1 7 1 1869 207 132 1.60 2.80 9959 103268 0.00 0.00 0.00 0.00 0.00 6.20 10.60 127.20 137.60 2.8 762 1532491
+1 95 1 1 4 0 1297 85 84 0.80 4.00 135129 145989 0.00 0.00 0.00 0.00 0.00 0.20 0.20 75.00 77.60 2.4 375 1534925
+1 90 1 1 0 0 5706 271 219 0.20 0.20 35217 193171 5.20 6.80 6.20 0.00 3.80 3.40 3.80 17.80 70.40 1.6 269 1013115
+1 88 1 1 14 2 2429 115 104 2.40 4.00 201506 61210 0.00 0.00 0.00 0.00 0.00 3.00 5.80 181.00 262.80 2.8 1024 1543222
+1 0 1 1 47 28 7628 430 401 1.00 1.20 509671 516403 0.00 0.00 0.00 0.00 0.00 17.00 24.00 89.60 160.00 1649 79 21
+1 94 1 1 3 0 936 74 44 0.20 0.20 89501 63905 0.00 0.00 0.00 0.00 0.00 12.00 12.00 21.40 47.80 3.0 446 1704470
+1 0 1 1 23 12 1673 145 117 2.00 6.80 160268 57456 3.40 4.20 4.20 0.00 13.60 23.20 25.80 113.80 254.60 581 87 13
+1 92 1 1 3 1 433 41 43 1.80 1.80 136140 62279 0.00 0.00 0.00 0.00 0.00 1.60 2.60 149.60 138.40 2.2 6229 1853056
+1 0 1 1 6 5 1893 237 136 0.40 0.40 708874 681925 7.57 12.95 12.75 0.00 1.59 10.76 18.33 40.24 45.42 247 86 14
+1 92 1 1 4 1 852 182 73 1.80 0.60 800804 14083 0.00 0.00 0.00 0.00 0.00 0.00 0.00 95.80 124.40 2.6 6792 1842634
+1 95 1 1 18 25 518 74 37 0.40 0.40 230801 34096 0.00 0.00 0.00 0.00 0.00 3.80 7.40 30.20 42.60 1.0 7921 1832643
+1 92 1 1 18 10 1650 101 85 1.40 1.80 80582 45072 0.00 0.00 0.00 0.00 0.00 10.80 11.40 103.80 152.20 3.4 1958 1533346
+1 88 1 1 8 2 3738 361 230 1.00 2.40 124581 116888 6.40 9.60 9.00 0.00 1.20 6.00 9.60 67.60 168.80 1.5 311 1000488
+1 90 1 1 2 0 2030 252 85 0.60 1.80 1031241 18973 1.40 1.60 1.60 0.00 2.40 3.19 3.59 27.54 65.07 2.6 249 1095673
+1 94 1 1 4 2 2283 128 91 0.20 0.20 258745 244328 2.80 3.40 3.40 0.00 0.80 5.00 7.40 15.60 35.80 3.4 213 1337101
+1 53 1 1 52 1 4039 257 185 15.20 24.80 137512 25944 7.60 33.40 116.20 234.60 0.40 10.40 11.60 661.20 1133.60 5.8 159 1102581
+1 98 1 1 0 0 181 21 23 0.20 0.20 457 3332 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 7436 1870405
+1 78 1 1 7 1 3269 378 382 2.00 0.80 252575 596391 0.00 0.00 0.00 0.00 0.00 24.05 27.86 117.64 207.21 2.0 566 1028819
+1 94 1 1 1 0 3033 166 157 0.20 0.20 62537 138790 2.00 2.00 2.00 0.00 0.00 3.40 5.20 15.40 76.60 3.2 282 1629112
+1 92 1 1 11 7 2713 112 59 1.00 1.80 43203 29902 0.00 0.00 0.00 0.00 0.00 11.80 12.00 52.80 125.60 1.4 405 1085482
+1 72 1 1 6 0 2446 166 668 7.00 4.40 191203 133582 4.20 16.40 35.00 79.20 0.40 0.60 0.80 338.00 465.00 4.0 332 1810845
+1 64 1 1 23 0 4853 635 522 9.58 10.18 389071 27888 7.19 15.77 57.09 108.38 0.00 4.79 9.18 433.33 731.14 2.5 200 1002606
+1 98 1 1 1 0 280 12 15 0.60 0.60 1076 5271 0.00 0.00 0.00 0.00 0.00 0.00 0.00 48.70 54.71 1.0 7425 1869494
+1 82 1 1 0 0 3194 154 133 0.20 0.20 42325 58935 0.00 0.00 0.00 0.00 0.00 0.80 1.60 15.40 24.80 2.2 787 1769712
+1 86 1 1 7 1 554 73 19 2.80 3.00 280050 24740 0.00 0.00 0.00 0.00 0.00 2.40 3.40 246.60 230.00 1.6 11636 1886816
+1 0 1 1 24 15 3527 270 162 1.60 2.60 229708 51639 0.20 0.40 0.40 0.00 0.20 9.20 11.20 111.60 382.80 563 79 21
+1 67 1 1 61 70 5696 1219 1051 4.00 1.60 1162995 753719 4.40 33.00 104.20 198.80 1.00 19.40 45.80 257.80 505.20 1.0 298 1105275
+1 66 1 1 39 0 3445 244 119 9.60 27.40 229870 29242 4.80 25.00 54.20 93.40 0.00 22.40 36.80 351.20 647.40 2.8 152 1096787
+1 92 1 1 5 1 3343 146 109 0.20 0.20 6854 30929 6.59 8.18 15.57 25.75 0.40 10.58 15.37 16.17 62.67 2.2 147 1064287
+1 0 1 1 8 0 3509 193 127 0.80 0.80 275966 47129 0.00 0.00 0.00 0.00 1.80 5.80 30.00 90.00 177.40 359 86 13
+1 91 1 1 36 47 1065 124 76 1.60 1.80 45558 26129 0.20 0.20 0.20 0.00 0.80 6.40 6.60 88.40 219.80 1.4 265 973400
+1 89 1 1 2 1 2695 252 200 0.40 0.40 118741 87008 8.00 19.00 24.20 37.60 0.80 2.80 3.00 39.40 179.20 2.0 233 1018211
+1 82 1 1 5 4 4431 375 255 2.00 6.20 131291 39274 5.40 17.40 34.80 42.80 1.40 7.80 13.00 124.40 195.60 1.0 187 1099499
+1 92 1 1 2 2 279 73 39 0.20 0.20 267659 255630 0.00 0.00 0.00 0.00 0.00 3.20 6.20 15.40 16.80 3.0 4057 1827102
+1 96 1 1 2 1 468 73 53 0.80 1.00 130396 14905 0.00 0.00 0.00 0.00 0.00 0.00 0.00 47.60 66.60 2.0 2191 1720920
+1 94 1 1 0 0 2157 94 119 0.20 0.20 91687 20959 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 18.80 3.2 666 1726446
+1 89 1 1 4 2 1255 153 92 0.20 0.20 27881 24505 0.00 0.00 0.00 0.00 0.00 2.60 3.00 21.80 22.60 2.2 656 1760221
+1 61 1 1 80 49 3096 236 184 10.20 29.40 142410 71766 4.00 12.80 26.60 40.40 2.40 8.60 16.60 364.40 697.00 1.2 174 1091110
+1 89 1 1 1 0 516 91 70 0.40 0.40 45700 18975 0.00 0.00 0.00 0.00 0.00 1.80 3.20 38.60 40.00 2.6 1841 1768357
+1 87 1 1 2 0 1719 278 121 0.40 0.60 677064 53972 3.80 12.20 18.00 37.20 1.20 6.40 7.80 44.40 155.60 1.2 206 1125093
+1 91 1 1 5 4 1972 264 136 0.60 0.60 6710 29148 0.00 0.00 0.00 0.00 0.00 3.40 3.80 30.80 104.40 1.0 1245 971048
+1 91 1 1 1 0 2626 149 109 1.00 1.20 98210 28706 0.60 1.40 1.40 0.00 1.00 3.60 3.80 61.80 105.00 1.2 294 1016866
+1 90 1 1 30 26 3257 164 148 0.80 2.20 41354 106548 1.00 4.20 3.80 0.00 1.20 0.60 0.60 55.00 108.40 1.2 291 1068296
+1 85 1 1 10 5 2767 302 228 0.20 0.20 77857 97525 0.00 0.00 0.00 0.00 0.40 5.41 8.62 20.84 50.70 1.5 1322 1114163
+1 86 1 1 14 0 4635 785 123 0.20 0.20 690532 65110 21.40 70.80 164.60 307.40 0.00 15.60 153.00 15.80 113.60 1.8 132 1015157
+1 80 1 1 16 0 2876 692 186 0.80 2.20 482340 59018 11.60 43.20 149.60 246.40 0.20 68.80 111.00 113.40 221.40 2.4 157 1028288
+1 77 1 1 40 54 3432 390 328 3.41 4.81 415685 259602 13.23 27.66 36.87 58.32 8.22 9.82 9.82 166.93 396.59 1.5 401 1098783
+1 92 1 1 7 3 398 28 23 2.40 2.00 29854 24869 0.00 0.00 0.00 0.00 0.00 3.41 6.61 101.80 156.91 1.0 2690 1775247
+1 0 1 1 4 2 1350 171 94 0.40 0.40 10284 51892 0.00 0.00 0.00 0.00 0.20 0.20 0.20 30.06 41.88 380 95 5
+1 80 1 1 5 2 2572 353 181 1.80 2.40 132635 52281 3.80 15.80 29.80 51.40 0.60 1.40 2.00 175.80 293.80 2.8 199 1515450
+1 62 1 1 30 7 7683 542 241 7.98 13.17 675257 171753 0.00 0.00 0.00 0.00 0.20 15.17 23.35 379.44 598.20 6.4 870 1462826
+1 91 1 1 6 4 4517 290 192 0.40 0.40 180673 39693 0.20 0.20 0.20 0.00 1.80 3.80 4.40 36.60 95.20 1.7 344 982749
+1 92 1 1 4 1 3186 149 148 1.00 2.60 55029 92541 0.00 0.00 0.00 0.00 0.00 1.60 3.00 52.20 65.60 3.0 694 1645491
+1 74 1 1 14 1 4419 619 496 8.40 2.60 241499 26462 0.00 0.00 0.00 0.00 0.00 0.40 0.40 407.40 612.40 2.3 1070 1068173
+1 95 1 1 3 1 475 84 88 0.40 0.60 55384 58785 0.00 0.00 0.00 0.00 0.00 0.60 0.60 28.20 41.40 2.0 6182 1724002
+1 92 1 1 5 4 1529 175 101 0.20 0.20 195110 67620 0.00 0.00 0.00 0.00 0.00 5.40 5.40 15.60 32.40 1.0 2061 1072275
+1 0 1 1 5 4 519 66 71 0.20 0.20 92342 18279 1.60 1.60 1.60 0.00 1.00 0.60 0.60 15.60 24.60 147 97 3
+1 72 1 1 10 4 6601 1078 1011 4.80 2.00 839271 734468 6.20 8.60 8.60 0.00 2.20 1.80 1.80 247.00 388.60 1.8 227 1121504
+1 89 1 1 4 2 2903 198 137 0.80 2.20 197969 24712 0.80 9.20 21.40 33.80 1.60 7.60 8.60 53.60 127.00 2.0 369 1099566
+1 77 1 1 34 17 5783 194 164 5.40 15.80 204070 43945 9.80 25.80 75.80 165.20 3.40 23.60 36.80 233.40 433.20 2.0 168 1011917
+1 89 1 1 2 1 2538 200 118 0.60 3.20 29061 22557 0.20 0.20 0.20 0.00 0.00 1.80 4.40 41.20 143.00 1.2 418 1113773
+1 77 1 1 75 102 5997 473 174 2.00 3.60 157803 63609 0.00 0.00 0.00 0.00 0.00 5.00 7.40 254.60 342.40 3.8 2087 1393750
+1 83 1 1 5 3 4899 283 155 2.40 7.98 70991 44614 2.59 2.99 31.74 57.68 2.40 10.78 11.78 144.71 283.43 7.8 153 1018558
+1 86 1 1 1 0 2912 247 145 0.20 0.20 259647 152073 11.18 22.36 22.36 0.00 12.57 4.59 9.18 31.94 60.28 1.0 326 1015325
+1 65 1 1 93 47 4993 293 608 9.00 22.00 457411 221414 9.20 29.00 70.40 85.20 2.80 12.20 17.00 380.00 704.20 1.0 146 1075955
+1 81 1 1 8 0 2661 400 353 8.00 2.20 189718 9267 0.00 0.00 0.00 0.00 0.00 0.00 0.00 368.80 538.80 2.2 7073 1859928
+1 86 1 1 16 15 2536 348 267 0.40 0.80 236381 365923 3.20 3.80 3.80 0.00 1.40 7.20 9.40 38.40 76.00 2.4 222 1373243
+1 96 1 1 4 3 1132 109 110 0.20 0.20 8668 42910 0.00 0.00 0.00 0.00 0.00 1.20 2.00 16.80 33.00 2.4 551 1533008
+1 87 1 1 2 0 3865 467 234 0.60 0.40 137554 45369 0.00 0.00 0.00 0.00 0.80 17.80 26.00 33.00 130.60 2.0 897 1077758
+1 64 1 1 23 2 6591 1335 1312 5.59 2.99 1138923 1081232 0.00 0.00 0.00 0.00 0.00 0.80 0.80 300.00 439.72 1.3 753 1053284
+1 88 1 1 1 0 3095 253 109 1.20 0.40 1045007 15387 0.00 0.00 0.00 0.00 0.00 2.79 2.99 57.49 100.60 3.0 402 1728380
+1 94 1 1 1 1 1515 191 127 0.40 1.80 4317 17371 1.60 1.60 1.60 0.00 0.40 0.60 0.60 27.60 32.20 3.0 240 1103902
+1 67 1 1 15 0 4222 302 226 8.40 18.80 100520 35425 0.60 0.60 3.80 9.80 0.80 52.60 56.00 342.00 674.40 1.2 296 1082901
+1 77 1 1 8 4 3912 275 216 3.20 2.60 156009 225504 1.40 1.40 1.40 0.00 0.80 46.60 53.00 342.40 364.40 2.6 371 1005256
+1 79 1 1 7 0 2864 429 343 7.39 2.00 514791 52432 0.00 0.00 0.00 0.00 0.00 0.20 0.20 355.29 515.17 2.0 7441 1859318
+1 95 1 1 9 6 1312 58 44 0.60 0.60 129917 8132 4.80 33.60 71.60 148.20 0.20 15.40 30.00 33.40 93.40 4.0 127 1527920
+1 62 1 1 13 1 4137 197 96 10.20 33.60 209720 39281 6.60 7.40 12.60 9.40 3.80 3.80 3.80 542.60 838.00 1.0 226 1032648
+1 95 1 1 5 4 725 92 92 0.80 1.80 9397 30354 0.00 0.00 0.00 0.00 0.00 1.00 1.00 66.00 80.80 2.0 388 1013008
+1 93 1 1 6 4 2006 154 132 0.40 1.00 179464 33351 3.79 4.79 3.79 0.00 5.59 9.58 10.58 25.15 71.46 1.0 180 1022267
+1 94 1 1 4 2 1253 78 105 0.20 0.20 8414 32783 1.20 1.40 1.40 0.00 0.60 0.80 1.00 24.40 22.40 1.8 270 1090680
+1 95 1 1 2 1 2023 72 81 0.20 0.20 27282 124053 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 19.80 2.2 1996 1642507
+1 81 1 1 4 0 4449 610 584 3.61 6.61 442354 376615 0.00 0.00 0.00 0.00 0.00 1.20 1.20 210.22 296.59 1.5 666 1097331
+1 92 1 1 0 0 407 28 27 0.20 0.20 24024 7783 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.40 23.40 1.0 8572 1835037
+1 87 1 1 4 1 2207 283 122 1.40 2.40 610199 562531 0.00 0.00 0.00 0.00 0.00 7.01 13.43 93.39 189.38 3.2 3299 1039954
+1 99 1 1 1 1 209 12 37 0.20 0.20 10272 15749 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7205 1874080
+1 79 1 1 4 0 5861 440 363 3.20 2.60 112941 64636 0.20 0.40 0.40 0.00 0.20 0.20 0.20 163.40 239.00 1.5 359 985080
+1 91 1 1 1 1 2856 217 122 0.60 0.60 21884 26199 1.20 1.20 1.20 0.00 0.80 1.20 1.20 28.20 71.00 1.3 299 1101256
+1 92 1 1 98 127 680 54 44 1.00 0.60 12159 22830 0.00 0.00 0.00 0.00 0.80 1.00 1.00 70.80 95.80 1.8 348 975070
+1 75 1 1 55 64 2240 212 121 7.00 22.00 162659 30126 1.40 1.40 1.40 0.00 1.40 10.00 13.80 402.60 497.40 1.6 181 1105998
+1 92 1 1 13 19 980 41 32 0.20 0.20 6049 11472 0.40 0.40 0.40 0.00 0.00 1.40 1.40 14.40 16.80 2.2 305 1743032
+1 86 1 1 6 0 2000 275 268 3.00 1.20 114746 112680 0.00 0.00 0.00 0.00 0.00 1.80 1.80 153.40 269.00 2.5 429 1058998
+1 84 1 1 6 1 1987 71 43 4.20 5.40 170574 29605 0.00 0.00 0.00 0.00 0.00 3.00 5.40 258.20 342.80 2.6 8398 1865216
+1 84 1 1 8 4 2576 334 159 1.40 2.80 630571 44851 3.40 4.00 4.00 0.00 2.40 1.60 1.60 142.80 177.00 2.2 363 1038963
+1 95 1 1 5 0 1114 382 31 0.20 0.20 106997 6721 0.00 0.00 0.00 0.00 0.00 19.00 19.00 16.20 100.80 1.0 1781 1769610
+1 61 1 1 18 3 3416 188 94 13.40 37.40 208370 38913 3.20 4.00 3.40 0.00 8.80 11.60 11.80 445.40 879.80 2.0 271 1080566
+1 93 1 1 6 0 1035 87 45 1.60 1.80 304001 22135 0.00 0.00 0.00 0.00 1.20 0.00 0.00 83.97 129.26 1.4 1580 1026153
+1 86 1 1 5 0 1917 276 225 4.80 1.40 225592 9647 0.00 0.00 0.00 0.00 0.00 0.00 0.00 236.40 340.80 1.2 6776 1840662
+1 88 1 1 66 80 2306 159 468 1.60 3.60 173555 40022 5.20 6.80 6.80 0.00 8.00 4.20 4.40 100.00 228.80 1.2 213 1012886
+1 97 1 1 0 0 261 35 24 0.20 0.20 28174 9750 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7195 1847059
+1 93 1 1 1 0 839 135 174 0.40 0.40 94748 34095 0.00 0.00 0.00 0.00 0.00 3.80 6.00 31.40 81.00 3.2 1353 1716182
+1 95 1 1 13 18 262 40 46 0.20 0.20 962 35952 0.40 0.40 0.40 0.00 0.00 0.00 0.00 13.17 17.96 1.0 266 1744447
+1 96 1 1 2 1 291 69 24 0.20 0.20 478237 206365 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 19.00 3.4 5597 1835384
+1 97 1 1 1 0 300 39 54 0.40 0.20 29042 16603 0.00 0.00 0.00 0.00 0.00 0.60 0.80 16.57 18.96 1.0 466 1739299
+1 71 1 1 14 9 7394 186 137 3.20 8.80 150790 20217 3.80 6.00 5.60 0.00 2.80 2.60 4.80 252.80 308.00 3.6 261 1377384
+1 92 1 1 2 0 2443 213 120 0.20 0.20 304797 217049 0.00 0.00 0.00 0.00 0.40 3.60 6.40 19.40 26.20 3.2 1166 1729090
+1 85 1 1 13 0 4123 322 151 0.80 1.20 615802 41718 0.00 0.00 0.00 0.00 1.80 23.80 27.60 83.40 282.60 4.4 1159 1466419
+1 83 1 1 14 1 2111 350 336 5.59 3.99 375410 225367 5.59 7.78 19.36 19.96 0.60 13.37 33.33 180.24 314.57 3.5 168 1042622
+1 1 1 1 7 5 2322 259 169 0.40 0.80 620416 636285 0.00 0.00 0.00 0.00 0.00 43.20 53.00 27.20 101.40 1963 88 11
+1 0 1 1 9 1 877 79 86 1.80 6.00 77186 66921 0.60 0.60 0.60 0.00 0.60 0.40 0.40 88.80 161.20 210 94 6
+1 73 1 1 8 0 4790 433 374 6.60 5.40 193903 103264 4.00 28.60 72.60 151.40 1.40 5.40 5.60 502.40 686.20 4.6 189 1397792
+1 96 1 1 2 1 1228 50 51 0.80 1.80 137951 42570 0.00 0.00 0.00 0.00 0.00 0.20 0.20 49.60 54.40 1.6 8293 1838978
+1 83 1 1 3 0 2292 163 123 0.60 2.40 415319 481405 15.20 33.00 60.60 149.60 3.60 35.20 57.40 23.40 94.80 1.6 138 1011013
+1 80 1 1 44 53 3236 552 553 3.20 1.40 436934 459568 0.00 0.00 0.00 0.00 0.00 7.40 8.80 167.00 282.80 2.8 623 1059738
+1 94 1 1 1 0 1100 115 72 0.60 0.60 13332 29318 0.60 0.60 0.60 0.00 0.00 1.00 1.00 40.80 73.80 1.0 322 1015394
+1 94 1 1 0 0 200 18 22 0.20 0.20 641 7160 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 1.8 4133 1781096
+1 92 1 1 18 0 1228 174 155 1.00 0.80 214763 88986 0.00 0.00 0.00 0.00 0.20 2.80 7.40 42.60 149.80 2.8 1569 1531693
+1 85 1 1 1 0 1678 99 69 0.20 0.20 612194 17579 3.20 4.80 4.80 0.00 0.20 83.20 150.00 15.60 80.40 4.4 285 1329640
+1 93 1 1 4 0 1139 110 28 1.80 2.00 104583 6724 0.00 0.00 0.00 0.00 0.20 0.80 0.80 136.60 198.80 2.4 812 1715998
+1 74 1 1 14 5 3467 194 133 2.60 8.60 667592 33485 1.60 1.60 1.60 0.00 1.40 62.40 124.80 191.20 339.00 6.4 500 1360821
+1 94 1 1 8 0 1397 98 71 0.00 0.00 130510 16704 7.00 42.80 57.80 90.40 0.00 8.60 41.00 4.00 29.00 1.0 135 1054590
+1 91 1 1 1 0 997 102 51 0.20 0.20 426208 42091 0.00 0.00 0.00 0.00 0.00 3.80 4.60 16.00 26.20 2.0 829 1750946
+1 88 1 1 2 0 488 55 47 2.20 2.20 105707 47856 0.00 0.00 0.00 0.00 0.00 2.00 2.00 204.41 174.55 2.2 11158 1877659
+1 81 1 1 18 12 3208 298 153 3.79 4.19 136968 171740 11.78 34.33 79.84 134.53 2.00 20.76 23.15 312.97 416.17 1.8 122 969851
+1 85 1 1 3 0 2334 367 305 1.80 2.00 226808 102677 0.60 0.60 0.60 0.00 0.20 4.39 8.58 144.11 166.07 2.6 238 1692817
+1 97 1 1 0 0 290 33 38 0.20 0.20 4367 14889 2.00 2.00 2.00 0.00 0.20 0.60 0.60 15.57 16.77 1.0 147 1739408
+1 88 1 1 55 73 3374 694 405 0.40 0.60 45287 63171 3.59 8.18 18.36 18.16 0.80 29.94 32.14 39.32 68.46 1.0 143 1069084
+1 92 1 1 2 0 768 82 33 1.60 1.20 419416 19101 0.00 0.00 0.00 0.00 0.00 0.40 0.60 109.20 139.80 1.0 1074 1061965
+1 97 1 1 4 0 187 11 16 0.40 0.40 433 11308 0.00 0.00 0.00 0.00 0.00 5.19 9.58 34.13 45.11 1.2 8227 1860893
+1 86 1 1 61 68 1450 213 112 1.40 2.00 211900 201633 0.00 0.00 0.00 0.00 0.00 0.20 0.20 114.57 156.09 3.6 2599 1580109
+1 80 1 1 20 9 4691 143 113 2.60 8.20 35748 69147 0.00 0.00 0.00 0.00 0.00 0.00 0.00 235.60 227.40 2.8 4961 1671939
+1 84 1 1 3 2 4173 202 175 1.00 2.60 179583 231310 0.00 0.00 0.00 0.00 0.40 3.00 3.00 97.60 158.40 1.7 561 992744
+1 73 1 1 11 0 1887 160 216 7.00 20.20 58535 203177 2.60 29.80 38.80 76.00 0.60 15.40 18.40 296.40 520.60 1.0 220 1106189
+1 0 1 1 18 15 2314 256 91 0.40 0.40 294759 283260 3.20 6.80 21.00 28.20 0.20 3.60 4.00 31.20 120.20 166 84 16
+1 98 1 1 0 0 170 12 36 0.20 0.20 1886 31093 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7374 1874600
+1 89 1 1 8 0 2435 286 177 1.40 2.40 511926 160573 0.00 0.00 0.00 0.00 5.79 3.59 5.39 107.39 212.77 4.6 625 1329721
+1 75 1 1 5 0 4382 693 477 4.21 3.21 359356 539883 4.21 12.42 21.84 21.84 3.81 26.25 26.65 170.34 353.11 2.6 192 1012528
+1 87 1 1 5 1 1379 213 99 3.40 2.00 808034 27835 0.00 0.00 0.00 0.00 0.00 0.20 0.40 146.20 229.60 2.6 8208 1833008
+1 94 1 1 4 2 879 95 56 0.60 0.60 229339 14622 0.00 0.00 0.00 0.00 0.00 1.20 1.20 196.80 95.00 2.0 577 1015192
+1 97 1 1 2 0 1343 74 56 0.20 0.20 89294 21447 0.60 1.00 2.80 7.20 0.20 0.40 1.60 15.60 26.20 1.3 147 1089664
+1 97 1 1 1 1 236 32 20 0.20 0.20 19029 4338 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.4 7404 1865584
+1 87 1 1 6 0 2894 192 142 1.60 1.60 303095 170845 12.40 23.40 18.60 0.00 76.80 2.20 2.60 85.20 161.80 2.2 269 1065440
+1 88 1 1 18 22 830 112 72 0.20 0.20 18998 32495 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.43 16.83 1.4 1862 1770862
+1 97 1 1 13 19 277 46 38 0.20 0.20 2084 4319 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.80 16.80 2.2 6442 1712288
+1 87 1 1 1 0 4685 252 275 0.20 0.20 15340 159534 0.00 0.00 0.00 0.00 0.00 16.00 16.40 15.80 44.00 1.0 599 1058715
+1 0 1 1 18 12 1061 414 148 0.40 1.80 733653 636561 0.00 0.00 0.00 0.00 0.00 0.60 0.60 32.40 102.20 349 93 7
+1 97 1 1 1 0 297 31 52 0.40 0.40 90793 22285 0.00 0.00 0.00 0.00 0.00 0.00 0.00 39.00 33.60 1.2 7404 1868925
+1 92 1 1 9 8 1509 102 88 0.40 0.40 116728 71547 5.01 9.82 9.02 5.61 2.81 5.61 9.62 38.88 51.50 2.0 152 1087258
+1 94 1 1 2 1 569 88 36 0.20 0.20 286993 4202 0.00 0.00 0.00 0.00 0.00 0.60 0.60 16.80 22.00 1.6 1143 1744085
+1 0 1 1 24 8 4345 269 206 2.80 1.80 393404 68604 7.20 13.00 12.60 0.00 1.60 4.60 5.80 170.40 235.60 347 83 17
+1 85 1 1 2 1 1506 104 78 0.80 1.00 225983 151123 0.00 0.00 0.00 0.00 0.00 22.80 42.60 78.00 77.00 2.2 949 1714792
+1 82 1 1 66 86 6185 353 216 0.40 0.40 232387 62770 8.60 27.00 81.00 166.00 0.80 24.00 28.60 26.60 209.00 1.5 135 994904
+1 90 1 1 1 0 2219 98 93 0.40 0.60 25901 32545 0.40 0.80 0.60 0.00 0.00 2.20 2.20 30.60 65.00 4.6 312 1061978
+1 91 1 1 7 2 1885 165 82 1.20 1.60 59639 44156 0.00 0.00 0.00 0.00 0.00 8.42 9.02 92.79 140.68 1.0 410 1067469
+1 96 1 1 1 0 584 71 43 0.20 0.20 85722 6320 4.40 4.40 5.60 1.80 1.60 0.00 0.00 17.40 18.00 1.2 144 1749736
+1 91 1 1 0 0 3398 148 107 0.20 0.20 8555 16085 0.20 0.20 0.20 0.00 0.00 14.20 14.80 17.00 114.60 5.6 217 1022944
+1 62 1 1 51 2 2437 116 67 12.77 35.93 100642 41200 5.19 9.18 16.57 17.76 2.20 23.15 25.55 508.58 882.63 3.4 240 1093632
+1 94 1 1 3 2 1173 120 72 0.20 0.20 100626 25939 0.00 0.00 0.00 0.00 0.00 0.80 1.20 16.40 19.60 2.0 1174 1133376
+1 0 1 1 28 11 2509 250 194 0.60 0.40 289605 47012 0.00 0.00 0.00 0.00 0.00 9.80 15.40 56.60 166.20 550 82 18
+1 96 1 1 0 0 298 33 64 0.20 0.20 3314 55348 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.63 20.44 1.0 483 1733852
+1 62 1 1 8 1 8648 1697 1545 5.20 1.40 1597281 1092606 0.00 0.00 0.00 0.00 0.20 7.40 10.60 255.40 418.40 1.0 598 1093806
+1 60 1 1 7 1 8197 1643 1360 5.59 3.39 1294310 1037226 5.79 11.18 17.76 20.36 1.60 4.59 5.79 278.84 535.13 2.2 206 1088327
+1 79 1 1 28 12 3894 210 129 4.00 4.40 110564 87310 1.00 17.00 59.40 183.40 0.00 0.40 0.40 200.60 303.20 3.8 1020 1543034
+1 80 1 1 24 6 1964 224 158 6.20 5.20 286090 70019 0.00 0.00 0.00 0.00 0.00 1.00 1.80 231.80 370.00 3.2 1324 1545899
+1 72 1 1 17 14 3301 441 255 3.20 6.80 155154 103324 24.00 59.20 195.40 443.60 1.40 89.80 127.20 241.20 542.20 3.5 116 985470
+1 98 1 1 0 0 326 28 29 0.20 0.20 1045 18304 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.80 17.20 3.0 581 1710640
+1 91 1 1 2 0 393 26 36 0.80 1.20 3745 18201 0.00 0.00 0.00 0.00 0.00 0.20 0.20 42.80 68.60 1.8 982 1765360
+1 92 1 1 11 6 2480 219 148 1.00 0.80 322214 299376 0.00 0.00 0.00 0.00 0.00 2.40 4.80 73.20 71.20 4.4 2685 1563270
+1 81 1 1 49 22 2009 243 135 4.40 6.20 158925 31533 0.00 0.00 0.00 0.00 0.00 4.40 5.80 220.60 424.00 1.2 965 973090
+1 79 1 1 9 5 4233 288 216 1.80 2.40 217085 132699 0.00 0.00 0.00 0.00 0.00 8.40 15.40 121.00 291.60 1.0 1425 1018525
+1 0 1 1 89 99 1232 232 231 1.60 1.80 440049 450751 2.79 3.19 3.19 0.00 3.79 1.60 2.00 96.81 182.24 327 87 13
+1 90 1 1 4 1 2289 197 140 0.40 0.40 85895 150802 2.00 2.60 3.00 0.80 0.60 4.20 5.60 29.00 72.40 2.6 160 1312763
+1 87 1 1 5 1 1758 213 114 2.00 2.80 147106 38579 0.00 0.00 0.00 0.00 0.20 9.00 18.40 77.20 155.40 1.0 1700 1096987
+1 95 1 1 0 0 1092 287 79 0.20 0.20 631564 367543 0.00 0.00 0.00 0.00 0.20 0.20 0.20 15.60 17.40 3.0 1380 1745816
+1 83 1 1 7 0 4049 261 244 0.80 0.80 270608 186598 3.80 13.60 47.00 140.60 1.60 1.60 1.80 64.40 183.00 3.8 135 1528261
+1 89 1 1 23 12 2580 122 108 2.40 2.20 74035 28647 0.00 0.00 0.00 0.00 0.20 13.00 13.20 235.00 265.60 4.2 7303 1393122
+1 81 1 1 5 1 611 75 69 2.99 2.59 314508 47666 0.00 0.00 0.00 0.00 0.00 3.39 5.19 220.16 209.98 1.6 2093 1813919
+1 85 1 1 8 8 5656 661 143 0.60 0.80 1450782 68405 5.81 7.01 21.04 36.27 0.80 6.81 10.22 75.55 161.32 3.0 302 1006745
+1 94 1 1 36 55 1563 65 56 0.40 0.40 4148 17343 0.00 0.00 0.00 0.00 0.00 7.00 7.00 31.20 51.00 1.0 2915 1011784
+1 82 1 1 35 31 4232 320 187 1.80 2.40 176180 143770 0.00 0.00 0.00 0.00 0.20 4.80 8.60 111.20 295.60 5.6 1455 1314174
+1 93 1 1 6 4 1846 120 86 0.40 0.40 142277 54470 3.20 4.00 3.60 0.00 0.00 8.00 10.60 33.20 70.20 3.8 617 1061272
+1 95 1 1 3 2 1858 95 87 0.20 0.20 6700 52668 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 17.00 2.0 3174 1657160
+1 0 1 1 7 2 2956 295 274 1.60 1.40 702714 635175 0.00 0.00 0.00 0.00 0.00 8.58 14.77 323.95 224.35 1790 83 16
+1 85 1 1 9 2 840 120 60 2.60 2.40 98182 68589 0.00 0.00 0.00 0.00 0.20 31.00 35.60 217.20 279.60 4.2 611 1717547
+1 92 1 1 6 6 1274 283 316 0.40 0.40 63796 601041 0.00 0.00 0.00 0.00 0.00 2.20 4.40 30.80 107.80 1.5 658 960246
+1 86 1 1 133 124 3215 293 189 1.40 1.20 340039 142524 0.00 0.00 0.00 0.00 0.00 6.80 8.40 101.20 157.80 2.2 713 997958
+1 83 1 1 5 3 4902 288 219 1.60 2.20 331091 175956 0.00 0.00 0.00 0.00 0.60 9.00 9.20 152.20 177.20 3.2 1641 1413941
+1 96 1 1 0 0 310 57 43 0.20 0.20 1659 12639 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.80 20.40 3.0 538 1713112
+1 76 1 1 7 0 4394 752 639 4.81 3.61 680353 385683 0.00 0.00 0.00 0.00 2.81 3.21 3.41 258.32 389.38 5.6 540 1015469
+1 96 1 1 0 0 498 22 28 0.60 0.60 10200 11243 0.00 0.00 0.00 0.00 0.00 0.40 0.80 28.20 38.00 1.0 7680 1871328
+1 89 1 1 22 1 2421 430 418 0.40 0.40 49677 29489 0.40 0.40 4.20 12.00 0.00 23.00 23.20 37.20 73.80 2.8 167 1044270
+1 57 1 1 59 2 3976 357 244 13.03 36.07 249775 53161 1.20 1.20 1.20 0.00 1.00 21.64 29.06 514.23 856.51 1.4 401 1097045
+1 93 1 1 3 1 432 79 75 0.20 0.20 3966 18602 0.00 0.00 0.00 0.00 0.00 1.60 1.60 18.80 25.60 2.4 6355 1701950
+1 95 1 1 6 2 988 63 50 1.40 1.00 6632 31804 0.00 0.00 0.00 0.00 0.00 2.00 2.00 85.40 102.20 2.2 1619 1538554
+1 81 1 1 21 7 5216 178 117 3.60 22.60 246084 178063 0.00 0.00 0.00 0.00 0.80 20.60 34.20 251.60 396.80 5.0 2172 1558706
+1 81 1 1 5 1 6795 310 214 2.20 7.41 180947 182196 0.00 0.00 0.00 0.00 0.00 8.62 11.62 117.23 202.81 1.7 639 993645
+1 83 1 1 3 1 546 100 65 2.00 2.00 489966 509354 0.00 0.00 0.00 0.00 99.60 3.19 4.39 179.84 259.68 2.0 3786 1804230
+1 94 1 1 6 5 2622 97 100 0.80 0.80 4307 6878 1.80 3.00 2.00 0.00 0.20 0.00 0.00 65.00 61.60 2.4 370 1453632
+1 99 1 1 2 1 196 16 20 0.20 0.20 7038 10748 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.83 16.83 1.0 7354 1869587
+1 59 1 1 124 135 4269 557 323 3.99 3.59 691572 328743 27.54 112.38 287.43 438.12 2.00 83.63 130.34 246.91 596.01 1.3 127 988386
+1 84 1 1 3 0 1876 188 110 2.80 3.00 44356 69197 0.00 0.00 0.00 0.00 0.00 0.00 0.00 208.40 321.60 2.6 2633 1702410
+1 98 1 1 3 3 197 15 17 0.20 0.20 7010 4904 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.60 16.80 1.0 7348 1864270
+1 98 1 1 0 0 203 17 45 0.20 0.20 429 20260 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13.00 16.80 1.0 6168 1855848
+1 92 1 1 2 0 1897 186 116 0.40 0.40 96474 27958 0.00 0.00 0.00 0.00 0.00 1.00 11.40 33.20 63.00 1.0 1868 1098352
+1 81 1 1 6 0 1714 211 163 5.19 2.79 175386 22819 0.00 0.00 0.00 0.00 0.00 6.39 12.38 335.33 392.02 2.0 6440 1845649
+1 95 1 1 39 56 929 64 55 0.40 2.00 4306 22554 0.40 0.40 0.40 0.00 0.00 0.60 0.80 20.40 47.00 1.5 182 999139
+1 92 1 1 4 3 1357 150 107 0.40 0.60 44343 61464 3.99 7.98 11.38 7.78 0.00 0.00 0.00 23.75 45.31 1.5 139 1008875
+1 73 1 1 22 8 6591 176 98 4.00 9.00 169740 99954 4.60 10.20 12.00 6.60 4.40 1.40 2.20 254.20 328.60 3.8 156 1317042
+1 84 1 1 12 4 4168 313 205 1.40 1.00 235149 53022 1.80 9.60 18.00 34.40 2.00 17.00 68.00 60.00 91.60 1.0 257 1052590
+1 89 1 1 4 2 1796 150 140 1.20 1.20 112990 37708 0.00 0.00 0.00 0.00 0.40 2.80 4.20 80.00 150.80 1.3 1001 1040331
+1 83 1 1 8 1 2930 136 116 1.80 2.40 196392 81718 6.19 11.18 26.55 57.09 0.80 2.59 3.39 95.61 209.78 1.5 174 1054580
+1 87 1 1 32 13 1816 109 62 3.19 4.59 113378 77967 0.00 0.00 0.00 0.00 0.00 2.99 4.39 214.57 373.85 6.2 2761 1545443
+1 85 1 1 6 4 3739 386 266 1.20 2.00 67930 55275 0.00 0.00 0.00 0.00 0.00 6.01 6.01 62.32 130.26 1.0 1144 984715
+1 77 1 1 7 0 4197 627 498 5.59 2.00 274637 141793 3.19 10.78 33.53 71.86 0.00 20.16 23.55 280.24 496.81 1.8 161 980552
+1 94 1 1 0 0 2525 119 123 0.20 0.20 73271 15365 1.20 1.20 8.00 12.00 0.00 7.20 7.40 15.00 32.60 2.4 129 1709570
+1 0 1 1 100 114 2815 196 123 1.79 2.99 144658 32908 0.20 0.20 0.20 0.00 0.60 20.92 26.69 127.69 326.29 496 85 15
+1 96 1 1 0 0 391 200 58 0.20 0.20 302625 295186 0.00 0.00 0.00 0.00 0.00 0.80 0.80 15.60 16.80 2.6 1319 1745824
+1 90 1 1 5 3 2990 220 146 0.20 0.20 45866 58198 0.00 0.00 0.00 0.00 0.00 1.60 2.00 20.36 78.24 4.2 402 1060037
+1 80 1 1 7 0 3185 402 344 7.78 2.40 264732 12848 0.00 0.00 0.00 0.00 0.00 0.00 0.00 392.02 534.13 2.0 7821 1858842
+1 97 1 1 3 2 253 23 24 0.20 0.20 2158 7345 0.00 0.00 0.00 0.00 0.00 0.20 0.40 16.00 17.00 1.0 6613 1859304
+1 80 1 1 75 68 2224 308 265 6.40 5.80 211609 159046 15.60 27.00 54.80 78.00 9.40 9.40 22.40 260.80 480.80 1.0 181 960515
+1 67 1 1 67 41 2634 243 129 10.42 29.86 419114 53101 1.60 16.43 34.07 55.51 10.82 20.04 32.06 347.90 655.11 1.8 148 1094599
+1 74 1 1 8 1 4276 516 445 4.80 2.00 173748 105083 11.20 22.00 21.80 0.00 0.00 7.00 8.60 244.80 405.20 3.2 316 1033651
+1 79 1 1 9 0 2340 286 213 8.42 5.61 224186 11989 0.00 0.00 0.00 0.00 0.00 3.41 3.41 394.59 665.93 2.0 1439 1780125
+1 85 1 1 4 1 3256 591 502 1.60 3.40 343778 335048 1.00 1.00 1.00 0.00 0.40 2.00 2.20 79.80 120.40 2.3 289 1129867
+1 82 1 1 18 15 2071 228 119 2.40 2.99 639252 37961 0.00 0.00 0.00 0.00 0.00 11.58 19.36 159.28 360.48 1.8 768 1016776
+1 95 1 1 4 2 2229 105 99 0.20 0.20 115209 66791 0.00 0.00 0.00 0.00 0.00 1.00 3.20 29.20 59.80 2.4 1336 1396776
+1 97 1 1 1 0 652 27 28 0.40 1.00 2185 13897 1.20 1.20 1.20 0.00 0.20 1.40 1.40 32.40 49.00 1.5 271 1016312
+1 95 1 1 0 0 273 32 42 0.20 0.20 16418 23088 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.80 16.80 1.2 2666 1771728
+1 0 1 1 45 4 2415 116 65 11.40 11.80 111258 24508 0.00 0.00 0.00 0.00 0.20 0.80 0.80 396.80 768.40 791 77 23
+1 92 1 1 11 11 3268 229 133 0.20 0.20 135267 29878 3.41 5.81 11.22 17.84 0.80 2.61 4.61 17.64 41.48 1.0 127 981844
+1 75 1 1 26 3 3871 307 166 6.61 4.41 1025194 72910 7.41 35.07 119.44 200.40 1.00 21.44 26.85 281.36 527.05 2.6 134 1086621
+1 97 1 1 1 0 280 41 14 0.80 1.00 214840 16418 0.00 0.00 0.00 0.00 0.00 0.00 0.00 44.20 66.60 1.2 8348 1864789
+1 74 1 1 75 93 6011 365 278 2.00 5.60 159953 84717 7.40 8.20 8.20 0.00 5.60 13.20 18.80 149.20 285.60 1.0 290 1001610
+1 76 1 1 14 2 4395 517 446 7.80 2.20 284606 35105 0.00 0.00 0.00 0.00 0.40 7.60 7.60 381.60 581.20 3.6 781 1719930
+1 91 1 1 4 3 1900 172 82 0.40 0.40 357236 21458 2.20 4.40 9.60 13.60 13.60 4.80 4.80 37.00 83.00 1.6 177 1085061
+1 95 1 1 0 0 403 164 56 0.20 0.20 194739 212276 1.20 1.20 1.20 0.00 0.00 11.00 21.00 20.80 38.60 2.2 1363 1745691
+1 93 1 1 3 0 953 143 121 2.60 0.80 145468 11423 0.00 0.00 0.00 0.00 0.00 0.00 0.00 138.40 200.80 2.0 7345 1865565
+1 91 1 1 0 0 359 51 30 0.20 0.20 272187 42273 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.20 1.6 2042 1767325
+1 87 1 1 32 48 6054 283 231 0.60 2.00 24049 248288 0.00 0.00 0.00 0.00 0.00 3.00 3.00 54.80 62.60 3.0 1092 1378821
+1 81 1 1 8 0 1359 111 76 6.79 19.96 37163 21005 0.20 0.20 0.20 0.00 0.20 9.58 9.98 236.73 444.11 1.0 316 1079813
+1 97 1 1 2 1 294 50 35 0.20 0.20 259637 7396 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 17.20 1.0 6342 1855490
+1 77 1 1 33 17 1810 141 92 3.41 4.61 167970 74621 1.20 1.80 1.80 0.00 1.00 39.88 47.29 251.70 516.23 2.0 377 1021501
+1 93 1 1 19 9 676 98 69 2.20 2.99 27662 13993 1.60 1.80 1.80 0.00 1.40 0.40 0.40 134.73 198.40 1.2 205 1751332
+1 86 1 1 53 64 3918 636 168 0.40 0.40 118785 79835 8.98 28.94 46.51 78.44 1.40 16.17 22.55 38.52 132.53 2.0 158 992099
+1 72 1 1 13 2 4011 235 173 6.99 20.56 51314 87285 5.59 13.57 21.76 32.93 1.60 2.20 2.20 294.21 489.22 2.7 206 1089043
+1 50 1 1 54 1 4530 516 199 13.37 33.53 179195 43512 11.18 68.86 142.51 283.03 0.40 17.96 23.55 622.36 1120.96 2.8 165 1099238
+1 81 1 1 1 0 1490 193 123 0.80 2.20 372082 316876 5.39 10.58 7.78 0.00 0.00 22.36 27.74 68.06 80.24 1.0 370 1112581
+1 94 1 1 1 0 371 48 31 0.60 0.60 52298 9498 0.00 0.00 0.00 0.00 0.00 0.00 0.00 33.80 38.60 2.2 3042 1707706
+1 82 1 1 84 50 2687 254 153 3.60 4.40 338059 85012 0.00 0.00 0.00 0.00 0.00 11.60 16.80 242.60 375.60 6.4 3736 1604352
+1 95 1 1 10 9 1075 80 66 0.20 0.20 4730 17851 0.00 0.00 0.00 0.00 0.00 0.80 1.00 16.00 30.20 2.6 1482 967736
+1 97 1 1 2 1 268 42 15 0.20 0.20 259709 14607 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.80 19.20 1.4 6764 1875640
+1 87 1 1 24 21 2013 472 171 2.80 3.60 623893 577518 0.00 0.00 0.00 0.00 0.00 1.20 1.60 167.00 255.40 1.5 606 1045882
+1 76 1 1 50 62 3443 468 327 5.40 3.00 178546 78089 4.60 15.20 51.60 114.80 1.60 35.20 35.80 261.60 578.60 1.3 171 966218
+1 98 1 1 1 1 177 13 15 0.20 0.20 7030 7013 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 7441 1870565
+1 96 1 1 1 0 912 43 41 0.60 1.40 1609 7270 0.00 0.00 0.00 0.00 0.00 0.00 0.00 52.00 47.40 2.0 2109 1719680
+1 92 1 1 8 1 1986 229 137 1.00 1.40 265319 76638 0.00 0.00 0.00 0.00 0.00 0.00 0.00 96.00 131.20 3.4 2606 1540563
+1 79 1 1 6 3 4043 396 249 2.20 3.41 247607 41688 8.02 40.88 93.99 213.63 1.20 79.36 97.19 117.23 251.10 2.8 159 1131335
+1 94 1 1 1 0 306 51 59 0.20 0.20 10830 12360 0.00 0.00 0.00 0.00 0.00 0.80 1.00 15.40 16.80 2.0 361 1745200
+1 84 1 1 18 8 1587 178 127 2.00 7.00 44659 91316 0.00 0.00 0.00 0.00 0.00 16.80 25.80 160.00 266.80 2.6 785 1531302
+1 91 1 1 2 0 925 128 87 0.80 6.80 395229 88354 0.00 0.00 0.00 0.00 0.00 10.60 21.20 73.20 85.00 2.4 704 1756390
+1 97 1 1 1 0 322 40 32 0.60 2.00 877 6435 0.00 0.00 0.00 0.00 0.00 0.80 1.00 42.60 44.40 3.0 597 1715934
+1 93 1 1 2 1 870 52 28 1.00 1.60 232556 8611 0.00 0.00 0.00 0.00 0.00 4.60 8.60 82.80 124.80 1.6 5310 1832723
+1 79 1 1 73 98 3147 279 181 1.40 2.20 388256 56469 1.20 23.80 60.40 172.40 0.80 22.00 44.00 81.20 235.00 4.0 219 1393995
+1 81 1 1 6 3 7400 826 432 0.40 0.40 292925 64287 0.00 0.00 0.00 0.00 0.00 4.60 5.00 59.00 100.00 4.4 2616 1550853
+1 85 1 1 34 41 3476 256 187 1.20 1.20 90106 118959 1.20 1.20 1.20 0.00 1.00 2.59 3.79 83.23 128.34 1.5 349 1061626
+1 84 1 1 2 2 7028 361 221 0.20 0.20 38090 64418 6.80 10.80 9.80 5.80 1.00 2.80 3.20 14.20 72.60 2.6 158 1137550
+1 93 1 1 1 0 1894 122 68 0.20 0.20 62039 23810 1.00 1.80 1.80 0.00 1.20 0.80 0.80 15.00 43.00 1.7 201 1003520
+1 78 1 1 7 1 1933 220 109 4.18 4.38 726842 119979 0.00 0.00 0.00 0.00 0.00 8.17 12.55 269.92 374.50 5.8 7790 1856038
+1 97 1 1 1 1 218 29 27 0.20 0.20 17759 14246 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 8747 1835080
+1 90 1 1 25 37 2151 140 139 0.80 1.60 12995 63897 0.00 0.00 0.00 0.00 0.40 17.00 17.40 51.40 147.80 2.8 541 1388173
+1 76 1 1 817 1 5602 120 139 0.20 0.20 13845 38325 0.00 0.00 0.00 0.00 0.20 49.40 51.20 16.60 21.20 2.8 820 1517128
+1 0 1 1 25 13 1509 178 114 3.40 4.60 89871 23958 0.00 0.00 0.00 0.00 0.40 14.20 19.60 148.80 290.20 446 87 13
+1 65 1 1 12 0 3239 256 181 11.38 34.53 322629 96593 5.59 13.17 25.55 66.27 0.60 16.57 16.77 378.04 755.89 2.0 168 1086058
+1 81 1 1 3 0 464 39 35 2.00 2.00 73449 37326 0.00 0.00 0.00 0.00 0.00 2.00 3.40 189.60 189.00 2.2 2652 1796053
+1 98 1 1 11 17 194 9 18 0.20 0.20 3431 62750 0.00 0.00 0.00 0.00 0.00 0.00 0.00 14.83 13.23 1.0 7080 1858637
+1 91 1 1 6 4 1300 121 146 0.40 0.40 4705 255201 0.00 0.00 0.00 0.00 0.00 7.39 7.39 43.11 172.06 1.0 839 966869
+1 97 1 1 1 0 458 97 80 0.20 0.20 126668 50140 0.00 0.00 0.00 0.00 0.00 0.00 0.00 21.20 17.00 3.0 6276 1722750
+1 97 1 1 1 0 275 31 29 0.40 0.40 87930 8388 0.00 0.00 0.00 0.00 0.00 0.00 0.00 29.54 44.71 1.2 1220 1756311
+1 91 1 1 14 9 4099 408 350 0.20 0.20 169307 106148 1.00 2.99 2.99 0.00 1.40 9.98 18.96 15.57 39.52 3.6 233 1394261
+1 81 1 1 44 43 2576 299 230 0.40 0.20 301574 199914 29.26 62.73 85.17 99.20 0.40 18.24 20.24 43.49 101.80 1.0 144 974434
+1 94 1 1 0 0 1339 86 68 0.20 0.20 6285 13180 0.00 0.00 0.00 0.00 0.00 40.60 40.60 15.60 73.20 3.2 452 1719110
+1 91 1 1 1 0 2307 121 75 1.00 2.40 74054 20034 1.60 4.40 22.20 55.60 0.00 0.20 0.20 86.20 143.40 1.6 136 998451
+1 94 1 1 10 0 1032 252 100 0.60 1.00 399020 275959 0.00 0.00 0.00 0.00 0.00 10.60 20.60 56.00 85.80 4.4 1382 1602011
+1 95 1 1 17 14 2406 98 78 0.40 2.00 22998 33809 0.00 0.00 0.00 0.00 0.00 0.40 0.80 34.40 47.20 3.0 7657 1370880
+1 93 1 1 6 4 1789 88 63 0.40 1.80 276786 261189 0.00 0.00 0.00 0.00 0.00 2.80 5.20 38.60 45.60 4.4 2736 1565184
+1 93 1 1 43 59 3305 119 90 0.40 0.60 34432 20538 5.20 8.40 14.20 21.00 0.80 2.80 3.00 34.00 62.20 1.0 181 1015472
+1 99 1 1 0 0 158 11 13 0.20 0.20 1360 11033 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 17.20 1.0 8372 1864896
+1 88 1 1 5 0 2763 165 162 0.80 0.40 148059 122088 0.00 0.00 0.00 0.00 0.20 0.40 0.60 66.40 99.60 2.0 1113 1050733
+1 91 1 1 1 0 2439 262 138 0.20 0.20 256393 169970 0.00 0.00 0.00 0.00 0.00 2.80 4.20 14.00 41.80 6.0 3168 1602259
+1 98 1 1 0 0 142 9 13 0.20 0.20 439 7710 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.0 7635 1866172
+1 97 1 1 1 0 1261 50 45 0.20 0.20 2342 9868 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 2975 1707054
+1 99 1 1 1 1 167 11 16 0.20 0.20 9214 9234 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.43 16.83 1.0 7914 1867534
+1 97 1 1 1 1 335 158 40 0.20 0.20 290620 267389 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.20 17.00 2.0 5753 1833178
+1 99 1 1 1 1 218 15 36 0.20 0.20 11913 29452 0.00 0.00 0.00 0.00 0.00 0.80 1.60 15.40 16.80 1.0 7451 1876208
+1 70 1 1 7 0 2512 108 46 8.58 36.33 238613 20963 6.99 11.78 34.93 59.88 2.59 9.58 11.38 482.63 727.74 1.0 174 1034243
+1 79 1 1 17 14 4356 444 251 3.60 4.20 297685 58701 0.80 0.80 0.80 0.00 1.20 6.00 7.20 194.60 369.00 3.2 337 1136794
+1 91 1 1 3 1 2752 147 113 0.80 2.20 131882 34846 0.00 0.00 0.00 0.00 0.00 4.40 4.40 55.40 86.80 1.3 534 983482
+1 86 1 1 31 12 4007 295 143 1.40 3.20 548063 21742 10.40 41.40 61.60 109.20 5.80 8.40 8.40 103.40 294.20 5.0 143 1524043
+1 93 1 1 1 0 1457 189 119 0.20 0.20 20059 55123 2.79 4.79 4.59 0.00 1.00 0.80 0.80 14.97 27.35 1.5 515 1071665
+1 98 1 1 15 21 218 11 17 0.20 0.20 10365 48741 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.77 16.97 1.0 7379 1859400
+1 83 1 1 6 0 2312 336 305 3.80 4.20 130104 233308 8.40 10.60 15.60 13.20 1.60 10.80 11.80 174.80 271.40 2.0 151 1709832
+1 97 1 1 2 1 302 14 19 0.60 2.60 26099 50493 0.00 0.00 0.00 0.00 0.00 0.00 0.00 23.60 32.20 1.2 7742 1870256
+1 82 1 1 15 7 4877 184 207 2.00 7.20 92961 191479 0.00 0.00 0.00 0.00 0.00 0.00 0.00 159.60 170.80 3.4 2789 1648301
+1 84 1 1 20 7 3038 181 143 1.60 1.20 105138 29626 4.80 56.60 97.20 250.80 0.40 14.20 89.40 80.40 190.40 1.5 167 1052509
+1 87 1 1 33 44 457 39 18 1.80 1.80 126816 19729 0.00 0.00 0.00 0.00 0.00 15.00 29.20 169.00 189.40 1.0 8573 1834984
+1 0 1 1 12 5 2517 419 171 1.80 4.20 1084295 281753 5.60 16.60 28.20 35.40 2.40 17.60 21.00 113.00 210.40 146 81 19
+1 82 1 1 2 0 3583 179 119 1.40 1.60 100395 31497 0.00 0.00 0.00 0.00 0.20 0.20 0.40 67.60 101.40 2.6 1371 1753816
+1 86 1 1 38 21 1828 191 99 3.19 3.39 483872 23459 3.19 4.99 9.78 21.76 3.79 8.98 41.52 179.84 350.10 1.0 298 973443
+1 98 1 1 3 3 174 13 15 0.20 0.20 9661 14010 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 17.00 1.0 6855 1826152
+1 94 1 1 1 0 1085 156 61 0.20 0.20 681583 30122 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 19.20 2.8 4601 1731403
+1 96 1 1 2 1 279 34 23 0.20 0.20 1574 6389 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 18.40 3.0 529 1720128
+1 91 1 1 2 1 1614 161 129 0.60 0.80 14766 25774 2.60 5.00 15.40 19.80 0.60 8.80 9.20 50.40 104.40 1.0 151 1100256
+1 81 1 1 32 42 1606 177 145 0.80 0.80 536740 256548 34.87 66.53 91.38 131.06 3.21 22.65 39.08 88.78 184.57 1.6 159 1075711
+1 90 1 1 3 0 1543 155 133 0.40 0.40 321630 35751 2.80 31.60 86.40 141.80 6.00 74.60 76.20 34.00 187.00 2.7 253 1057774
+1 97 1 1 13 19 210 16 35 0.20 0.20 11917 30208 0.00 0.00 0.00 0.00 0.00 0.80 1.60 15.60 16.80 1.0 7645 1878904
+1 86 1 1 18 13 4270 395 191 0.60 0.60 1020951 136368 0.00 0.00 0.00 0.00 0.40 3.80 6.40 56.00 63.20 5.2 347 1523955
+1 86 1 1 8 2 3959 536 131 1.20 1.60 212552 153528 0.00 0.00 0.00 0.00 0.00 5.80 6.80 136.20 121.20 4.4 3054 1532029
+1 92 1 1 6 0 2043 121 75 0.80 2.20 155244 39102 4.40 20.80 47.20 120.40 0.60 2.40 2.40 65.20 144.40 4.4 156 1525677
+1 0 1 1 9 7 1635 226 150 0.40 0.40 79725 39372 7.58 9.78 43.31 60.48 1.20 18.56 19.56 39.12 268.06 241 88 12
+1 88 1 1 5 1 5300 242 252 0.60 1.40 84289 209924 0.00 0.00 0.00 0.00 0.00 1.60 1.60 51.90 67.07 3.2 3264 1637233
+1 0 1 1 84 103 2358 316 165 0.80 1.20 769994 343926 0.00 0.00 0.00 0.00 0.40 10.60 12.20 68.20 183.00 2157 81 19
+1 88 1 1 6 0 2039 103 89 1.60 3.00 172149 54113 1.40 17.80 74.60 178.40 1.00 5.20 27.00 78.60 193.20 1.0 131 1078506
+1 94 1 1 2 0 1691 197 111 0.60 2.20 28881 30377 0.40 0.40 0.40 0.00 0.00 3.20 3.20 50.60 80.40 1.0 153 1057536
+1 80 1 1 9 0 3034 446 397 8.20 2.20 210022 18396 0.00 0.00 0.00 0.00 0.00 0.20 0.40 385.40 557.60 1.4 1532 1747277
+1 81 1 1 69 74 3062 519 458 1.40 1.40 463945 441710 9.18 25.55 47.11 61.08 0.40 29.54 73.25 63.47 182.83 2.0 266 1046742
+1 96 1 1 12 1 992 165 77 0.80 2.00 220447 162750 0.00 0.00 0.00 0.00 0.00 0.80 0.80 51.80 74.00 4.2 2634 1575016
+1 0 1 1 31 5 2177 109 92 3.00 2.20 81775 27837 2.00 2.20 2.20 0.00 0.20 2.00 3.20 131.60 236.00 437 90 10
+1 87 1 1 11 0 1772 71 63 0.20 0.20 13348 13779 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.97 26.15 2.6 785 1753084
+1 81 1 1 4 1 4290 601 527 1.80 2.20 423536 401378 4.40 6.60 6.60 0.00 2.00 1.40 2.20 113.40 164.80 1.3 323 1122858
+1 87 1 1 54 40 2764 184 123 3.20 3.40 175671 137509 0.00 0.00 0.00 0.00 0.00 9.40 9.80 241.40 305.80 6.2 3387 1601147
+1 68 1 1 20 4 3443 316 182 2.99 5.99 425771 155256 17.96 55.09 131.14 202.00 2.20 75.65 91.22 201.80 501.40 1.0 132 1000853
+1 94 1 1 0 0 1019 104 80 0.40 0.40 10819 17998 0.00 0.00 0.00 0.00 0.00 7.60 8.00 33.20 70.40 2.0 1041 1066749
+1 75 1 1 145 168 2531 184 119 2.60 4.60 469027 13022 16.20 184.20 329.20 665.60 1.80 49.20 95.20 173.00 579.00 5.4 239 1331219
+1 97 1 1 15 21 213 26 17 0.20 0.20 84647 4861 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 1.0 7385 1865600
+1 58 1 1 58 3 3379 212 110 10.38 27.74 285687 34843 19.36 85.23 155.29 334.13 1.60 78.24 121.36 398.20 834.73 1.4 171 1105214
+1 97 1 1 0 0 238 43 18 0.20 0.20 137058 35477 0.00 0.00 0.00 0.00 0.00 9.98 19.96 15.57 16.97 1.0 6640 1848682
+1 79 1 1 3 0 4170 241 143 5.60 4.40 139387 101305 7.60 35.00 117.00 188.60 0.20 1.40 2.00 247.80 496.00 1.6 142 1001363
+1 90 1 1 14 6 2113 102 91 2.00 7.19 17577 62010 0.00 0.00 0.00 0.00 0.00 0.40 0.60 127.74 212.97 2.6 886 1642807
+1 89 1 1 5 0 1798 107 103 4.20 8.60 53830 50292 0.00 0.00 0.00 0.00 0.00 0.00 0.00 143.80 233.60 2.0 4175 1820453
+1 82 1 1 67 83 5967 199 139 1.40 1.80 254279 17845 0.00 0.00 0.00 0.00 0.00 1.60 1.60 131.80 142.00 5.0 713 1528790
+1 86 1 1 53 1 4919 189 149 0.99 2.58 333491 64310 1.98 8.13 12.10 14.48 1.79 6.75 8.13 112.10 105.16 3.2 150 1504125
+1 75 1 1 292 181 4604 252 184 1.80 2.00 278113 20555 1.40 1.60 1.60 0.00 1.40 70.20 70.40 110.40 272.80 4.2 366 1451837
+1 82 1 1 10 3 3110 411 406 3.20 1.00 274823 191752 0.00 0.00 0.00 0.00 0.20 8.60 10.20 165.60 278.20 1.8 408 1083768
+1 93 1 1 12 9 1328 237 79 1.80 2.80 466909 156780 0.00 0.00 0.00 0.00 0.00 1.20 1.80 79.00 128.40 3.2 2730 1584686
+1 91 1 1 1 0 2177 178 135 0.20 0.20 31414 38601 0.00 0.00 0.00 0.00 0.00 2.40 2.40 18.40 30.80 2.0 1748 1040098
+1 88 1 1 10 7 1354 145 89 2.00 4.20 369367 162606 4.20 4.80 4.80 0.00 3.60 0.40 0.60 127.20 260.00 5.8 265 1595098
+1 73 1 1 81 92 3030 371 310 3.60 5.00 269944 357765 5.80 32.60 70.20 122.60 2.80 25.00 36.60 244.60 530.40 3.8 175 1372950
+1 71 1 1 44 7 3759 368 214 6.00 16.20 209860 82570 7.80 23.80 60.00 170.80 2.80 38.20 57.60 223.20 433.00 5.2 147 1099771
+1 92 1 1 7 2 586 88 25 3.40 3.60 61524 12611 0.00 0.00 0.00 0.00 0.00 0.00 0.00 135.60 225.40 1.0 8743 1871075
+1 82 1 1 20 16 1462 204 109 2.99 3.79 520733 25120 0.20 0.40 0.40 0.00 0.00 5.79 9.58 198.80 384.03 1.8 658 1123840
+1 83 1 1 45 0 5195 622 613 1.60 1.00 184934 156711 2.40 10.00 18.60 25.80 0.20 7.20 10.00 87.80 172.00 3.4 187 1047942
+1 0 1 1 9 8 3033 164 127 0.20 0.20 11198 28899 0.00 0.00 0.00 0.00 0.20 1.20 1.20 16.20 125.00 540 91 9
+1 72 1 1 7 0 2314 324 293 5.99 17.17 332967 138574 3.99 4.39 4.39 0.00 0.40 28.94 44.31 210.18 397.60 1.0 260 1075920
+1 88 1 1 2 0 2486 145 83 1.40 2.20 105868 32939 0.60 4.40 28.80 558.40 0.20 4.00 6.60 125.00 171.80 1.3 129 1101853
+1 83 1 1 74 95 4446 465 324 0.60 2.20 264021 167894 0.00 0.00 0.00 0.00 0.20 1.00 1.00 38.60 130.40 5.0 1157 1606267
+1 79 1 1 116 44 3078 172 154 3.80 6.20 314895 178270 0.00 0.00 0.00 0.00 0.00 1.60 1.80 247.80 368.40 3.4 1093 1515243
+1 96 1 1 0 0 402 29 22 0.20 0.20 48163 28701 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.57 17.37 1.6 8364 1860891
+1 95 1 1 3 2 831 162 110 0.20 0.20 13405 37243 0.80 1.00 1.00 0.00 0.40 0.80 0.80 15.60 57.20 1.5 147 1057486
+1 96 1 1 1 0 1927 73 68 0.80 1.40 5096 9534 0.00 0.00 0.00 0.00 0.00 0.20 0.20 45.20 58.20 2.2 2957 1706870
+1 79 1 1 7 1 2609 205 154 7.40 4.40 378761 58057 0.00 0.00 0.00 0.00 0.00 0.20 0.20 324.40 495.00 3.2 7873 1833518
+1 0 1 1 8 1 2491 175 91 1.80 10.18 606224 610887 0.00 0.00 0.00 0.00 123.95 2.00 2.20 66.47 287.23 1881 80 20
+1 87 1 1 27 41 2552 172 176 0.20 0.20 53530 271010 2.20 3.39 3.19 0.00 0.00 5.19 5.39 19.96 90.42 1.3 233 997657
+1 71 1 1 35 0 4592 206 103 9.02 22.24 324995 28209 1.00 15.43 47.70 86.97 1.40 3.21 3.41 388.78 719.84 3.6 204 1088414
+1 91 1 1 3 0 2127 393 333 0.40 0.40 190197 134245 0.00 0.00 0.00 0.00 0.00 0.40 0.60 86.40 53.20 2.4 1589 1540909
+1 71 1 1 33 26 4041 424 285 6.60 7.60 367275 193169 0.00 0.00 0.00 0.00 0.00 27.80 46.40 319.80 604.60 2.2 2954 1030811
+1 97 1 1 1 1 277 42 23 0.20 0.20 259702 19388 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.60 19.20 1.4 7377 1874534
+1 88 1 1 9 4 1684 94 59 1.00 2.40 248085 167332 0.00 0.00 0.00 0.00 0.00 19.80 33.60 95.20 156.40 2.2 10656 1381699
+1 0 1 1 35 11 4871 550 459 9.00 3.00 396942 31688 15.40 53.60 110.00 265.60 1.60 9.00 36.40 484.60 722.20 160 66 33
+1 56 1 1 15 1 6172 635 495 12.97 17.76 273452 68783 0.00 0.00 0.00 0.00 0.20 6.39 6.79 552.49 899.20 1.3 480 1093009
+1 94 1 1 0 0 1968 90 73 0.20 0.20 20393 52096 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13.60 27.60 1.2 1950 1711416
+1 88 1 1 19 24 726 57 32 1.60 1.80 148958 4821 0.00 0.00 0.00 0.00 0.00 0.20 0.20 115.20 177.00 1.8 1695 1768030
+1 88 1 1 6 1 1752 145 106 2.61 2.40 24047 28494 0.00 0.00 0.00 0.00 0.00 52.10 56.51 104.61 254.51 3.8 1449 1042624
+1 83 1 1 29 38 7089 381 371 0.40 0.40 23628 70543 0.00 0.00 0.00 0.00 0.20 1.20 1.80 29.80 89.80 2.0 780 1063819
+1 90 1 1 4 0 2174 223 169 1.20 1.80 103138 87018 0.00 0.00 0.00 0.00 0.00 2.40 3.00 105.20 145.80 3.2 2525 1540277
+1 84 1 1 5 2 2931 630 374 1.00 1.40 148481 222789 0.20 0.20 0.20 0.00 3.61 2.00 8.62 106.61 220.44 3.2 338 1029645
+1 97 1 1 0 0 467 146 10 0.20 0.20 1115367 6098 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 2.4 8469 1868200
+1 90 1 1 2 1 2234 303 214 0.40 0.40 332451 59712 0.00 0.00 0.00 0.00 0.00 2.00 2.00 39.00 56.80 1.5 782 1126376
+1 95 1 1 3 1 2361 172 112 0.40 0.40 29740 37009 0.00 0.00 0.00 0.00 0.00 2.00 3.20 17.80 34.60 2.6 563 1535750
+1 95 1 1 3 2 1668 107 93 0.40 0.40 51510 48700 0.00 0.00 0.00 0.00 0.00 4.00 7.80 78.60 113.40 1.5 451 976706
+1 77 1 1 15 11 2889 315 128 4.19 4.19 94530 30267 19.36 48.90 136.93 322.55 0.60 10.78 14.37 290.82 515.57 2.0 121 1010938
+1 98 1 1 0 0 201 14 15 0.20 0.20 705 4909 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7549 1870232
+1 94 1 1 2 0 975 111 56 2.40 2.40 54087 18420 0.20 0.20 0.20 0.00 2.20 0.00 0.00 93.01 155.09 1.8 276 1749632
+1 88 1 1 1 0 4272 282 131 0.20 0.20 64826 50419 0.00 0.00 0.00 0.00 0.00 10.18 10.18 17.76 99.00 1.0 769 1072798
+1 90 1 1 25 35 389 28 18 2.00 2.00 59592 51764 0.00 0.00 0.00 0.00 0.00 2.20 3.60 178.00 157.00 1.0 5996 1848283
+1 87 1 1 1 0 376 70 56 0.40 0.40 1676 43014 0.00 0.00 0.00 0.00 0.00 4.40 6.00 33.60 41.20 1.6 701 1755293
+1 98 1 1 1 0 145 14 14 0.20 0.20 27257 5846 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.60 16.80 2.0 3608 1821480
+1 80 1 1 14 11 3197 564 347 2.00 1.20 74713 52640 5.39 9.38 17.76 20.16 3.59 31.14 35.13 145.71 245.31 1.5 204 1098558
+1 68 1 1 90 49 5387 310 266 7.82 10.22 296715 180601 9.82 26.25 51.70 35.67 16.03 7.01 9.02 376.35 642.28 3.0 222 1098411
+1 93 1 1 1 1 2609 117 89 0.40 1.00 14928 84242 6.39 12.18 11.98 0.00 0.40 6.99 7.39 21.96 39.92 5.0 332 974861
+1 83 1 1 3 1 4426 576 403 2.20 2.40 231193 329741 1.40 20.40 43.20 71.60 0.40 6.60 8.20 109.60 229.20 2.6 150 1366637
+1 97 1 1 17 25 186 22 22 0.20 0.20 63036 12936 0.00 0.00 0.00 0.00 0.00 0.80 1.60 16.00 16.80 1.2 7580 1877200
+1 85 1 1 9 5 4079 351 175 1.00 1.00 275337 46619 0.00 0.00 0.00 0.00 0.20 3.20 4.60 83.00 145.60 3.0 1331 1070187
+1 95 1 1 3 0 700 70 59 0.80 0.40 12315 17456 0.00 0.00 0.00 0.00 0.00 0.40 0.40 44.31 67.66 1.7 465 1060077
+1 74 1 1 26 8 6214 156 118 3.80 10.20 163996 9697 0.00 0.00 0.00 0.00 0.20 17.40 23.00 243.40 377.40 4.0 618 1322598
+1 90 1 1 3 1 390 35 20 2.20 2.59 62164 23300 0.00 0.00 0.00 0.00 0.00 2.20 3.79 191.62 163.47 1.6 8891 1868560
+1 94 1 1 41 62 1161 166 90 0.20 0.20 93957 15551 0.00 0.00 0.00 0.00 0.00 0.80 1.00 28.00 37.20 1.0 952 1065218
+1 83 1 1 13 3 4190 281 203 1.40 3.01 236259 44362 6.41 15.63 57.52 89.58 2.20 10.62 17.03 108.62 203.01 1.0 215 1111593
+1 93 1 1 1 0 2642 153 123 0.20 0.20 7778 87361 0.00 0.00 0.00 0.00 0.00 1.40 1.60 14.40 26.60 1.3 1287 1072240
+1 89 1 1 9 2 3853 178 141 1.40 2.80 189767 23555 0.00 0.00 0.00 0.00 0.00 9.20 9.20 75.60 118.20 2.6 571 1054232
+1 91 1 1 4 0 1660 108 96 0.60 0.40 126729 60770 16.80 21.80 21.80 0.00 14.80 3.20 9.80 33.80 81.20 1.0 208 1016526
+1 93 1 1 8 5 1250 169 100 0.20 0.20 203156 26983 0.00 0.00 0.00 0.00 1.20 11.60 12.40 25.00 164.60 1.7 700 988717
+1 73 1 1 27 3 4267 467 384 8.80 11.40 413386 75318 0.00 0.00 0.00 0.00 0.00 3.20 5.40 407.60 641.60 7.0 1389 1634174
+1 98 1 1 0 0 234 19 21 0.20 0.20 704 9040 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13.00 16.80 1.6 7547 1870227
+1 97 1 1 1 1 221 27 24 0.20 0.20 13467 6774 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.6 7402 1865584
+1 95 1 1 2 0 2328 122 92 0.20 0.20 107897 11362 0.00 0.00 0.00 0.00 0.60 8.40 8.40 16.00 83.60 3.2 506 1446912
+1 90 1 1 9 4 1062 144 124 0.20 0.20 112770 63316 11.60 20.40 18.20 0.00 0.40 15.80 20.80 18.40 67.60 1.0 352 945795
+1 95 1 1 0 0 2015 76 67 0.20 0.20 40551 49200 4.40 4.40 4.20 0.00 1.80 1.60 1.60 15.40 28.00 1.0 178 1013480
+1 86 1 1 26 13 2127 175 173 2.60 3.00 75457 39145 0.20 0.40 0.80 1.20 0.00 1.40 1.40 178.60 376.00 1.5 428 1065411
+1 80 1 1 9 1 3577 430 226 3.39 3.59 114246 43469 5.59 13.97 38.92 66.47 1.00 4.59 6.99 210.58 300.00 3.4 160 993788
+1 86 1 1 31 42 3056 224 179 2.00 0.60 127508 88368 0.00 0.00 0.00 0.00 1.00 11.20 11.80 285.20 283.80 2.0 510 1015450
+1 88 1 1 4 0 2732 239 161 0.80 0.40 78597 91067 5.60 14.40 23.60 39.00 0.60 5.80 9.80 47.80 150.40 1.3 212 1053800
+1 84 1 1 5 2 2398 226 178 2.40 0.80 131588 156048 15.80 32.60 44.80 33.20 0.40 8.80 12.20 294.20 184.40 2.8 189 1124510
+1 76 1 1 9 2 2285 157 109 6.79 19.96 23730 46926 0.00 0.00 0.00 0.00 0.20 7.98 8.58 230.94 432.14 1.4 562 1080802
+1 75 1 1 10 1 4471 407 444 5.81 4.41 304815 262405 13.83 26.85 34.67 17.03 0.40 5.21 7.01 312.02 509.42 1.4 193 1000760
+1 85 1 1 54 61 1893 180 146 1.00 1.40 78679 54207 23.35 59.88 98.60 171.06 0.40 21.76 31.34 76.45 242.32 1.4 177 967460
+1 96 1 1 33 48 246 47 27 0.40 1.20 308390 286630 0.00 0.00 0.00 0.00 0.00 0.00 0.00 21.20 31.80 2.8 5617 1835560
+1 78 1 1 27 19 2989 268 204 3.61 10.02 448136 389807 0.00 0.00 0.00 0.00 0.20 20.24 25.85 173.55 393.39 1.8 577 1084218
+1 75 1 1 16 5 4638 229 146 2.20 3.80 387503 91247 7.60 22.80 63.00 122.60 6.60 13.80 25.20 209.80 296.80 3.8 122 1522832
+1 97 1 1 6 4 368 174 58 0.20 0.20 297361 287679 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.40 17.20 2.2 5448 1828048
+1 94 1 1 6 5 2534 157 154 0.20 0.20 40362 144448 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 19.60 3.0 2044 1642912
+1 80 1 1 58 73 4668 396 328 3.60 1.60 296648 184970 2.20 2.60 2.60 0.00 0.20 9.80 18.40 187.40 281.40 4.2 353 1323339
+1 98 1 1 0 0 605 80 37 0.20 0.20 284759 271101 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 17.00 2.4 1315 1762011
+1 77 1 1 2 0 878 256 124 2.20 2.20 360331 385317 7.60 37.20 166.80 363.00 0.20 32.60 58.80 218.40 213.60 2.4 135 1803171
+1 91 1 1 6 5 2097 254 142 1.20 3.40 212869 103284 0.00 0.00 0.00 0.00 0.00 1.40 2.00 82.80 136.40 5.0 2946 1604310
+1 96 1 1 0 0 221 31 31 0.20 0.20 15128 19723 0.00 0.00 0.00 0.00 0.00 2.20 3.00 16.60 26.80 1.0 661 1734496
+1 87 1 1 14 13 6890 1054 171 0.60 0.80 69387 36569 4.20 7.00 7.00 0.00 0.20 1.00 1.40 58.20 68.80 3.0 254 998522
+1 71 1 1 39 19 4517 228 175 5.00 23.60 359751 160929 0.00 0.00 0.00 0.00 0.00 8.80 11.00 317.20 472.40 4.6 696 1640552
+1 76 1 1 42 3 4355 605 568 2.60 1.00 486570 430865 23.60 74.20 119.20 255.40 0.60 41.40 76.60 132.60 332.60 2.8 155 1093845
+1 77 1 1 45 54 1410 88 70 6.21 18.44 39621 18546 6.61 41.68 55.91 148.90 0.00 50.90 56.71 214.63 454.31 1.0 153 1106596
+1 83 1 1 66 63 3210 387 235 2.60 2.60 314096 84354 0.00 0.00 0.00 0.00 0.20 0.60 0.80 134.80 201.80 2.0 530 1121797
+1 75 1 1 7 0 2671 136 88 6.00 17.80 722814 19079 1.00 1.40 5.60 8.40 0.00 7.80 8.80 218.20 436.20 3.0 188 1087662
+1 84 1 1 33 46 3831 654 635 2.00 0.80 416036 400226 2.00 3.40 2.60 0.00 0.00 0.40 0.40 116.20 151.40 4.7 267 1129635
+1 70 1 1 41 18 5068 365 189 5.40 10.80 394008 124046 0.00 0.00 0.00 0.00 0.00 12.00 18.80 380.00 530.60 9.4 2372 1326565
+1 82 1 1 6 0 3467 290 193 3.20 4.00 229265 293230 11.40 27.60 43.80 75.60 8.40 3.60 5.60 216.80 288.80 2.8 208 1518378
+1 80 1 1 20 9 3878 152 79 2.60 9.40 94325 63872 0.00 0.00 0.00 0.00 0.00 1.20 1.40 220.40 243.60 5.8 3064 1604723
+1 96 1 1 13 19 419 38 38 0.20 0.20 19140 11716 0.00 0.00 0.00 0.00 0.00 1.80 3.20 15.60 18.00 1.2 5946 1864240
+1 63 1 1 25 8 7720 428 353 6.00 9.40 167410 76019 0.00 0.00 0.00 0.00 0.60 0.60 0.60 372.60 441.40 3.6 3263 1549171
+1 88 1 1 1 0 2250 129 103 0.20 0.20 82286 56953 0.00 0.00 0.00 0.00 0.00 4.00 6.40 22.60 69.60 3.2 440 1016278
+1 63 1 1 6 0 3334 631 157 5.60 7.00 468101 46656 25.60 131.80 252.80 739.80 1.00 11.60 15.60 345.40 780.60 1.3 112 1112576
+1 86 1 1 7 0 1296 150 46 6.00 4.40 100834 24403 0.00 0.00 0.00 0.00 4.40 7.00 9.20 245.40 461.40 1.5 615 1064864
+1 98 1 1 1 1 192 16 21 0.20 0.20 8965 8202 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.37 16.77 1.6 7159 1859791
+1 89 1 1 4 0 2410 118 98 1.00 3.40 115205 174195 18.60 23.40 27.80 12.00 11.00 2.60 3.20 56.20 84.80 1.0 240 1053811
+1 89 1 1 27 0 1504 270 173 0.20 0.20 134459 82065 8.40 34.40 85.60 206.40 0.40 28.20 35.00 54.40 108.80 1.0 119 1066176
+1 90 1 1 2 0 3838 204 184 0.40 0.40 44845 85764 1.20 1.60 1.60 0.00 7.80 1.20 1.20 33.80 42.20 2.0 134 1064270
+1 84 1 1 4 0 2443 243 81 2.00 2.00 168264 22420 1.20 4.00 52.40 79.60 0.00 13.00 22.80 154.80 298.60 1.0 150 1066862
+1 91 1 1 4 1 1750 168 128 0.80 0.80 7018 21939 0.00 0.00 0.00 0.00 0.20 0.80 0.80 42.80 70.40 2.0 547 976333
+1 92 1 1 5 4 1550 257 127 0.20 0.20 10676 41599 0.00 0.00 0.00 0.00 0.00 29.14 29.14 16.97 102.59 2.2 1130 969322
+1 93 1 1 3 2 1429 57 49 0.60 1.60 126556 58035 0.00 0.00 0.00 0.00 0.20 1.80 1.80 48.60 145.20 2.0 897 999174
+1 79 1 1 49 60 3735 492 275 3.61 2.61 552034 89148 4.81 9.22 9.22 0.00 0.20 2.00 2.00 191.18 344.09 1.0 187 1068874
+1 94 1 1 10 9 1459 145 74 0.20 0.20 376077 21897 0.00 0.00 0.00 0.00 0.00 0.40 3.00 19.60 28.80 3.2 955 975478
+1 84 1 1 15 9 1855 432 324 1.40 1.80 443383 145119 2.00 2.20 4.39 3.39 1.40 14.57 28.14 123.15 160.68 2.6 254 1692722
+1 98 1 1 1 0 1225 43 51 0.20 0.20 2708 55540 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.20 32.40 2.0 5233 1674902
+1 96 1 1 3 1 1982 107 101 0.60 0.60 50974 60735 0.00 0.00 0.00 0.00 0.00 1.00 1.20 87.60 55.80 2.2 1597 1548389
+1 84 1 1 16 9 6172 372 208 1.40 4.20 341591 161886 0.00 0.00 0.00 0.00 0.00 15.40 27.60 101.00 198.40 3.8 4081 1343858
+1 98 1 1 0 0 163 11 17 0.20 0.20 3703 5873 0.00 0.00 0.00 0.00 0.00 0.60 1.20 15.60 16.80 1.0 5270 1856600
+1 96 1 1 12 11 1228 136 81 0.20 0.20 8853 18761 0.00 0.00 0.00 0.00 0.00 0.60 0.60 21.64 20.44 1.0 1076 1085108
+1 0 1 1 56 25 2745 385 154 6.39 16.17 619928 296026 0.00 0.00 0.00 0.00 0.00 18.96 50.50 295.01 638.32 1109 76 24
+1 97 1 1 3 1 330 35 18 0.80 0.80 75541 7730 0.00 0.00 0.00 0.00 0.00 0.00 0.00 57.20 87.40 1.0 7579 1869181
+1 88 1 1 1 0 3623 251 145 0.40 0.40 41068 47382 4.61 5.01 5.01 0.00 0.40 1.20 1.60 39.68 42.28 1.5 242 1129377
+1 95 1 1 1 1 1438 49 29 0.00 0.00 95495 11982 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.80 3.60 1.2 8239 1863088
+1 86 1 1 27 34 1741 231 218 4.40 1.20 125125 36427 0.00 0.00 0.00 0.00 0.40 0.00 0.00 208.20 291.80 2.4 2657 1771130
+1 98 1 1 3 3 383 49 12 0.20 0.20 22602 5931 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.03 17.23 1.0 6382 1852983
+1 85 1 1 7 1 2890 477 344 3.20 3.40 386291 229773 2.00 4.00 3.60 0.00 0.60 3.20 4.60 136.20 213.00 1.3 270 1093411
+1 94 1 1 0 0 185 20 25 0.20 0.20 63914 4090 0.00 0.00 0.00 0.00 0.00 8.40 16.20 15.60 339.60 1.4 4388 1853618
+1 93 1 1 44 60 1758 109 72 0.20 0.20 44731 20281 0.00 0.00 0.00 0.00 0.00 1.80 1.80 15.80 36.40 1.2 949 975736
+1 91 1 1 1 0 2195 206 193 0.20 0.20 147433 58559 5.58 7.77 7.77 0.00 0.00 2.39 2.39 22.71 62.75 1.0 257 1040781
+1 86 1 1 1 0 3744 397 383 0.20 0.20 73993 103869 0.00 0.00 0.00 0.00 0.00 2.00 3.00 20.40 30.40 3.0 1659 1708942
+1 95 1 1 2 1 1051 94 47 0.20 0.20 30237 75384 0.00 0.00 0.00 0.00 0.00 0.00 0.00 18.36 17.96 1.0 6735 1849212
+1 97 1 1 2 0 473 48 50 0.20 0.20 35116 39123 0.00 0.00 0.00 0.00 0.20 3.19 4.19 25.15 41.32 2.0 399 1090394
+1 95 1 1 3 1 800 49 63 0.60 0.60 64103 102654 0.40 0.40 0.40 0.00 0.20 0.40 0.40 112.60 49.20 2.0 181 1522861
+1 87 1 1 4 0 2833 417 371 0.80 1.00 129848 121670 2.40 16.80 53.00 106.60 7.60 16.80 21.60 63.60 85.80 1.5 137 1103078
+1 92 1 1 0 0 578 54 52 0.20 0.20 5599 11969 0.00 0.00 0.00 0.00 0.00 0.60 0.60 15.00 22.00 3.0 2422 1772094
+1 84 1 1 11 2 2445 285 250 4.41 1.40 160468 64928 0.00 0.00 0.00 0.00 0.00 2.20 2.20 222.44 349.30 1.5 825 1072035
+1 87 1 1 31 21 1721 247 150 1.60 1.80 48063 31129 5.39 10.18 17.17 30.54 2.00 41.72 61.08 106.59 276.65 2.0 151 942600
+1 84 1 1 16 6 2859 231 130 1.00 3.00 277132 85831 0.00 0.00 0.00 0.00 0.00 41.60 48.20 71.00 275.60 2.4 2969 1408118
+1 86 1 1 8 0 1890 129 121 2.00 2.80 268324 278996 0.00 0.00 0.00 0.00 0.00 18.80 19.80 154.60 209.80 2.8 870 1538595
+1 97 1 1 1 0 494 129 125 0.20 0.20 2538 14811 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 19.00 2.0 3135 1707992
+1 72 1 1 9 1 3561 195 184 6.55 18.06 41282 57454 0.00 0.00 0.00 0.00 0.00 7.14 7.54 260.12 442.46 2.8 488 1094886
+1 89 1 1 7 1 610 94 35 3.61 3.61 84266 24174 0.00 0.00 0.00 0.00 0.00 1.20 1.20 226.05 252.91 1.0 7894 1872233
+1 81 1 1 5 1 3651 340 169 3.20 3.40 273075 60195 7.00 37.80 67.80 138.00 0.20 12.60 21.40 171.20 368.20 2.0 142 1113802
+1 96 1 1 2 1 471 26 39 0.40 0.40 9053 12211 0.00 0.00 0.00 0.00 0.00 0.00 0.00 33.47 36.27 2.0 6817 1864789
+1 65 1 1 7 0 5439 461 417 7.20 3.80 340924 225976 43.60 85.20 74.80 0.00 0.00 19.00 37.20 343.40 547.40 3.6 614 1391837
+1 91 1 1 31 39 3019 206 123 0.80 2.40 13540 50987 0.00 0.00 0.00 0.00 0.20 1.80 2.40 27.80 40.40 1.3 529 1077454
+1 98 1 1 0 0 449 64 45 0.20 0.20 1695 19282 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 3.0 1300 1713592
+1 99 1 1 1 1 185 13 34 0.20 0.20 6994 13808 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6040 1855672
+1 95 1 1 3 2 1626 139 84 0.60 0.60 105625 67257 0.00 0.00 0.00 0.00 0.40 0.40 0.40 112.00 48.00 2.2 852 1717360
+1 77 1 1 64 71 5534 657 234 5.41 5.41 161992 51093 4.81 7.62 7.62 0.00 1.00 1.40 1.40 234.87 426.25 1.2 290 1008295
+1 86 1 1 9 7 4514 197 175 0.60 0.60 10750 21717 3.00 3.20 3.20 0.00 1.20 11.60 12.00 52.40 127.60 2.3 291 987382
+1 85 1 1 6 0 1973 323 267 5.60 1.60 382504 212283 0.00 0.00 0.00 0.00 0.00 0.00 0.00 268.00 388.60 3.2 3657 1819877
+1 97 1 1 3 1 317 22 35 1.00 0.40 17745 15841 0.00 0.00 0.00 0.00 0.00 0.00 0.00 48.40 67.20 1.0 5277 1858336
+1 77 1 1 1 1 7191 767 1001 0.20 0.20 15110 50051 1.00 1.40 1.40 0.00 0.20 5.40 5.60 17.40 116.40 2.5 221 1017670
+1 90 1 1 1 1 1166 143 90 0.20 0.20 35499 54499 3.40 6.20 6.20 0.00 0.20 1.40 1.40 28.60 25.00 2.5 277 1068827
+1 84 1 1 14 3 2883 277 162 2.20 2.60 354424 36094 4.80 11.00 26.80 28.40 20.80 13.40 36.80 132.60 281.80 1.0 143 1100986
+1 91 1 1 1 0 1885 371 181 0.20 0.20 15100 68437 0.80 0.80 0.80 0.00 0.00 1.00 1.60 27.00 51.40 3.6 179 1714126
+1 91 1 1 1 0 2486 217 520 0.20 0.20 47594 56740 1.40 6.60 18.40 30.60 0.20 3.20 6.40 15.60 35.20 4.2 129 1703802
+1 92 1 1 2 1 884 111 91 0.20 0.20 17686 14948 0.00 0.00 0.00 0.00 0.40 49.70 52.89 15.57 181.24 1.6 1614 965530
+1 96 1 1 1 0 607 81 45 0.20 0.20 2174 6138 0.00 0.00 0.00 0.00 0.00 0.40 0.40 25.20 14.60 2.8 962 1711923
+1 85 1 1 1 0 3297 407 225 0.80 1.00 226064 117799 2.40 13.40 23.60 34.60 1.00 3.40 5.80 67.20 150.60 3.0 195 1113811
+1 0 1 1 23 18 1057 125 147 2.00 0.80 52933 22688 0.00 0.00 0.00 0.00 0.20 6.80 6.80 277.20 264.60 621 90 10
+1 90 1 1 5 2 1634 142 94 1.99 3.59 22655 27631 0.00 0.00 0.00 0.00 0.00 1.39 1.79 73.51 139.24 2.0 915 1114567
+1 94 1 1 5 2 447 59 42 1.80 1.80 166619 12441 0.00 0.00 0.00 0.00 0.00 0.00 0.00 66.20 117.80 2.4 4024 1837898
+1 94 1 1 24 36 700 64 108 0.40 0.40 5277 57907 0.00 0.00 0.00 0.00 0.00 1.60 2.00 32.93 58.08 1.7 688 1060442
+1 90 1 1 10 0 1036 177 75 2.60 5.80 288087 190120 0.00 0.00 0.00 0.00 0.00 5.60 12.80 104.60 216.40 3.6 1605 1732917
+1 88 1 1 5 1 1672 234 114 1.20 1.00 169980 93310 0.00 0.00 0.00 0.00 0.00 8.40 13.20 58.80 99.40 1.0 2088 1098666
+1 0 1 1 11 2 3454 182 143 1.20 1.00 176413 23893 0.40 0.40 0.40 0.00 3.00 2.80 20.80 81.60 183.80 321 90 10
+1 90 1 1 1 0 2264 148 95 0.40 0.60 23311 13315 0.00 0.00 0.00 0.00 0.00 8.40 8.60 39.20 82.60 3.4 1933 1408115
+1 98 1 1 0 0 193 15 25 0.20 0.20 2179 7422 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7105 1873392
+1 89 1 1 13 1 2112 223 109 2.20 2.60 271753 173447 2.60 17.80 34.20 86.20 2.40 5.00 19.00 107.80 178.80 4.0 169 1322045
+1 95 1 1 14 14 1537 143 87 0.40 1.80 27376 23777 0.00 0.00 0.00 0.00 0.00 0.40 0.40 33.60 52.20 2.0 1188 1458336
+1 98 1 1 2 1 236 30 20 0.20 0.20 94101 7960 0.00 0.00 0.00 0.00 0.00 0.00 0.00 22.16 17.17 1.4 7232 1861209
+1 79 1 1 7 2 3389 330 258 3.80 3.40 132226 112276 1.20 1.20 1.20 0.00 0.80 1.60 2.00 195.20 305.00 2.0 401 985917
+1 83 1 1 53 79 2675 162 110 0.60 0.80 191280 45919 0.00 0.00 0.00 0.00 0.20 8.00 8.00 54.80 145.40 2.7 1482 1042862
+1 85 1 1 3 0 2297 283 214 0.60 1.00 238430 171208 15.40 23.40 38.40 52.60 0.60 8.20 11.80 132.80 213.40 1.0 259 1054470
+1 75 1 1 18 1 4914 604 446 7.40 2.00 455057 70647 0.40 0.40 0.40 0.00 3.80 3.40 3.60 371.00 575.80 3.8 223 1533210
+1 72 1 1 58 38 6469 314 340 0.40 0.40 461409 283782 25.15 86.03 184.63 344.51 5.39 60.28 100.80 57.68 242.71 3.8 122 999623
+1 0 1 1 5 1 2299 291 111 1.20 4.00 783300 534138 6.60 10.00 26.40 54.00 0.20 11.60 21.60 63.60 90.40 141 89 11
+1 91 1 1 5 2 2282 166 124 0.40 0.40 97019 25076 0.00 0.00 0.00 0.00 4.39 2.79 2.79 31.54 192.42 1.8 500 974101
+1 88 1 1 48 71 2884 331 406 0.40 0.40 23080 60545 0.00 0.00 0.00 0.00 0.20 0.00 0.00 40.80 46.60 3.2 1672 1699862
+1 97 1 1 0 0 201 17 22 0.20 0.20 23893 34205 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.20 17.60 1.0 2839 1773744
+1 94 1 1 0 0 764 68 57 0.20 0.20 48116 38972 1.20 1.80 1.80 0.00 1.20 0.60 0.60 20.00 46.40 1.5 416 949702
+1 92 1 1 184 203 977 72 41 0.20 0.20 52830 69155 4.40 4.80 4.80 0.00 1.40 0.00 0.00 15.60 20.80 1.4 318 1753752
+1 90 1 1 16 5 2634 330 284 0.40 0.40 240012 164265 20.40 41.40 56.40 73.60 3.40 7.20 22.20 33.40 98.20 3.2 193 1322870
+1 76 1 1 65 39 3797 1477 133 2.40 2.80 505808 85412 18.40 62.20 132.40 243.20 2.20 50.40 99.20 161.40 278.80 2.4 128 1128730
+1 87 1 1 1 0 2100 201 147 0.60 0.60 191592 17844 0.00 0.00 0.00 0.00 0.00 20.80 21.60 46.00 157.20 2.6 1938 1408730
+1 76 1 1 8 1 4026 222 169 6.00 17.40 193223 79939 6.00 11.80 38.60 61.80 0.60 6.40 7.60 233.60 456.00 2.0 146 1078346
+1 84 1 1 3 0 3303 766 592 1.20 0.60 101953 99842 2.80 4.60 4.40 0.00 0.20 4.60 5.00 58.00 110.00 2.4 897 1715861
+1 84 1 1 5 1 6457 317 236 0.60 1.40 50627 101655 3.00 4.20 4.80 2.20 1.00 7.20 11.20 51.20 89.20 2.3 188 1009309
+1 87 1 1 9 8 803 104 59 1.00 1.00 177891 38416 0.00 0.00 0.00 0.00 0.00 0.00 0.00 55.00 205.40 2.2 1614 1811498
+1 97 1 1 3 1 2620 167 144 0.60 0.60 5175 57628 0.00 0.00 0.00 0.00 0.00 3.40 3.40 31.00 51.20 2.2 1767 1649326
+1 77 1 1 15 3 4709 223 136 3.40 3.60 237044 78651 8.60 42.00 94.80 165.20 1.40 13.40 41.40 272.40 456.80 1.2 188 1014941
+1 98 1 1 23 33 162 8 17 0.20 0.20 7001 18992 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 7579 1878621
+1 97 1 1 19 27 264 44 22 0.20 0.20 254670 4088 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.20 16.80 1.8 7311 1873264
+1 77 1 1 8 0 1921 78 64 7.19 21.16 21268 34032 0.00 0.00 0.00 0.00 0.00 3.99 3.99 240.12 444.31 1.0 603 1079904
+1 94 1 1 9 1 1909 78 58 0.40 0.40 43494 5858 0.00 0.00 0.00 0.00 0.40 2.20 2.20 29.40 41.00 1.0 363 1752696
+1 87 1 1 2 0 2818 212 230 1.20 3.20 35176 39424 0.00 0.00 0.00 0.00 0.00 11.40 13.20 81.40 210.60 1.0 499 1045558
+1 85 1 1 16 20 597 100 56 2.20 2.20 284141 231272 0.00 0.00 0.00 0.00 0.00 3.80 6.40 196.00 171.20 3.2 3454 1823072
+1 86 1 1 6 4 670 91 15 2.39 2.39 446893 20744 0.00 0.00 0.00 0.00 0.00 3.19 4.78 222.11 197.21 2.0 11692 1880091
+1 82 1 1 14 10 4831 332 191 0.80 3.60 265497 84870 3.20 11.20 16.20 12.80 1.40 6.60 12.00 75.80 180.20 5.4 340 1298264
+1 86 1 1 15 11 1875 115 99 1.60 1.80 187485 41084 7.78 41.92 84.83 110.98 0.60 12.97 23.95 148.70 361.68 2.2 252 1052185
+1 91 1 1 2 1 1335 151 122 0.80 5.00 66706 43887 0.00 0.00 0.00 0.00 0.60 2.40 2.60 32.40 61.00 1.0 365 1031246
+1 0 1 1 13 6 1881 141 134 1.40 2.20 72256 42530 5.41 6.81 6.81 0.00 0.80 25.05 33.07 119.24 253.31 292 86 14
+1 89 1 1 18 2 3359 225 142 3.80 4.40 139993 194535 0.00 0.00 0.00 0.00 0.00 2.80 2.80 154.20 254.60 4.2 1493 1331178
+1 98 1 1 1 1 310 14 31 0.20 0.20 6266 127742 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.60 16.80 1.0 6870 1853226
+1 91 1 1 18 15 3448 173 118 0.40 0.40 35249 49677 1.60 1.80 3.99 7.58 0.60 2.99 4.19 32.93 86.43 5.0 169 1519323
+1 89 1 1 14 5 3690 183 134 0.60 0.60 152858 33955 0.00 0.00 0.00 0.00 0.00 0.40 0.40 52.20 121.80 3.2 687 1528750
+1 74 1 1 16 4 4141 390 297 3.40 3.00 380212 155145 11.20 22.80 33.00 35.00 5.00 15.20 19.40 215.00 493.00 5.0 205 1325754
+1 95 1 1 1 1 2475 125 101 0.60 0.80 9230 5144 0.00 0.00 0.00 0.00 0.00 15.60 15.80 46.00 123.20 2.2 2578 1407528
+1 91 1 1 1 0 2416 152 179 0.20 0.20 92732 20397 0.00 0.00 0.00 0.00 0.20 12.40 23.80 12.80 20.60 3.0 4011 1721176
+1 90 1 1 6 1 889 118 79 0.60 0.60 161277 27197 4.60 12.20 58.00 92.80 0.00 2.80 26.40 44.40 128.20 1.6 180 1755830
+1 91 1 1 5 0 3044 215 113 1.40 1.60 140810 50903 0.60 0.60 0.60 0.00 0.00 5.41 10.62 71.34 110.62 2.8 294 1069146
+1 98 1 1 2 1 406 41 32 0.20 0.20 3373 7138 0.00 0.00 0.00 0.00 0.00 0.60 0.80 15.60 18.20 1.0 579 1752968
+1 92 1 1 34 46 1410 74 57 0.80 2.00 15951 14418 0.00 0.00 0.00 0.00 0.00 4.20 6.60 80.00 104.40 3.0 557 1038219
+1 83 1 1 7 0 2448 355 296 5.20 1.60 288536 152597 0.00 0.00 0.00 0.00 0.00 2.20 3.80 252.80 371.60 4.4 534 1725352
+1 91 1 1 1 0 1567 164 86 0.20 0.20 21470 58682 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.00 19.40 1.2 369 1753499
+1 1 1 1 41 33 2685 403 206 1.20 2.81 663839 106207 0.00 0.00 0.00 0.00 0.20 17.43 23.85 71.34 233.87 1538 86 13
+1 94 1 1 8 8 1255 100 85 0.60 0.40 3412 27903 0.00 0.00 0.00 0.00 0.20 5.40 5.40 37.40 65.60 2.5 913 975482
+1 98 1 1 1 1 373 51 16 0.20 0.20 21680 8776 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 5384 1860088
+1 79 1 1 37 47 2314 102 76 5.80 16.60 190684 35065 0.00 0.00 0.00 0.00 0.00 3.40 3.60 212.60 410.00 1.5 384 1082818
+1 90 1 1 4 2 2131 218 178 0.60 1.00 11474 60333 0.00 0.00 0.00 0.00 0.40 7.00 10.40 38.40 77.60 1.0 1108 1123651
+1 89 1 1 4 0 2115 197 200 1.60 0.60 66959 99470 0.20 0.20 0.20 0.00 0.00 2.40 2.40 88.80 165.60 1.2 242 1057792
+1 86 1 1 11 5 2010 257 106 3.20 3.80 315118 101709 0.00 0.00 0.00 0.00 0.00 14.80 27.00 146.40 318.40 3.8 1839 1576246
+1 92 1 1 47 67 1998 114 79 0.60 0.80 245939 36888 0.00 0.00 0.00 0.00 0.20 0.80 0.80 57.00 76.80 2.4 568 1533883
+1 85 1 1 3 1 2072 205 237 0.40 2.99 149830 441850 4.99 7.39 16.17 36.33 0.80 26.15 32.73 67.07 122.16 2.4 174 1370778
+1 95 1 1 0 0 269 38 41 0.20 0.20 14316 18332 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.80 16.80 1.0 2644 1771504
+1 87 1 1 6 1 2260 207 136 1.80 1.60 241800 63832 0.00 0.00 0.00 0.00 0.20 16.37 28.54 105.19 158.08 2.2 956 1069212
+1 96 1 1 10 1 415 34 28 0.40 0.40 19380 10141 0.00 0.00 0.00 0.00 0.00 0.00 0.00 30.60 38.60 2.4 6428 1711995
+1 98 1 1 23 32 217 16 38 0.20 0.20 9475 14828 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 1.0 7294 1875112
+1 87 1 1 6 1 2961 458 401 2.40 0.80 260714 202105 2.61 3.01 3.01 0.00 0.80 0.20 0.20 133.07 193.79 2.7 217 1006899
+1 90 1 1 1 0 2119 144 97 0.20 0.20 55894 59795 4.20 6.40 6.20 0.00 0.00 11.40 20.60 23.20 36.80 1.2 242 1118070
+1 80 1 1 15 6 4172 321 179 1.40 1.80 218370 133098 5.60 5.80 5.80 0.00 3.80 1.20 1.60 155.20 168.00 3.0 294 1526027
+1 94 1 1 5 4 1145 177 82 0.20 0.20 268645 18606 1.40 4.20 4.20 0.00 1.60 5.00 5.00 23.80 79.60 1.5 614 984304
+1 92 1 1 2 1 945 90 75 0.40 0.40 420930 85596 0.00 0.00 0.00 0.00 0.00 0.00 0.00 30.94 46.71 2.0 637 1073019
+1 89 1 1 3 1 1065 60 42 1.80 2.60 98610 319867 0.00 0.00 0.00 0.00 0.00 9.20 14.80 89.20 140.00 1.8 6823 1843387
+1 93 1 1 8 7 1847 135 122 0.60 0.60 8556 22519 0.00 0.00 0.00 0.00 0.00 1.00 1.20 53.80 79.80 3.3 540 981954
+1 92 1 1 10 5 1268 141 95 1.00 0.80 48951 32716 0.00 0.00 0.00 0.00 0.20 1.00 1.00 69.06 164.47 2.6 432 974360
+1 82 1 1 20 7 4531 397 305 3.59 1.80 408514 24179 0.00 0.00 0.00 0.00 0.00 2.99 3.19 187.03 317.56 1.8 1962 964972
+1 91 1 1 1 1 571 36 41 0.40 0.60 117314 9041 0.00 0.00 0.00 0.00 0.00 20.56 34.13 45.71 139.92 2.2 6978 1855797
+1 82 1 1 16 1 3837 407 318 0.60 0.60 284022 299801 15.20 28.00 28.40 4.00 0.40 26.00 35.20 77.60 180.80 1.0 238 998360
+1 93 1 1 1 0 3461 127 143 0.20 0.20 6869 13810 0.00 0.00 0.00 0.00 0.00 0.60 0.60 15.80 16.80 2.2 1206 1720112
+1 93 1 1 2 1 1806 125 86 0.40 0.60 55432 53360 0.80 0.80 0.80 0.00 0.60 1.00 1.20 33.87 38.48 1.0 180 1129489
+1 93 1 1 3 0 1418 124 99 1.00 2.20 17548 17883 0.00 0.00 0.00 0.00 0.00 0.40 0.40 76.00 129.60 1.2 1338 976405
+1 82 1 1 17 16 4935 245 163 1.00 2.00 244446 85677 0.00 0.00 0.00 0.00 0.20 16.20 19.40 219.20 209.80 3.2 948 999619
+1 72 1 1 38 29 2141 214 170 6.40 11.60 272617 86291 0.00 0.00 0.00 0.00 0.00 3.00 3.20 438.20 550.00 4.4 1117 1789931
+1 97 1 1 0 0 283 34 51 0.20 0.20 10756 22572 0.60 0.60 0.60 0.00 0.40 1.20 1.20 17.56 16.77 1.0 249 1740794
+1 71 1 1 54 70 4607 209 193 7.39 6.59 37206 133384 10.38 23.35 56.29 97.60 1.00 14.17 18.36 273.85 528.54 3.0 155 987796
+1 95 1 1 17 12 853 83 77 0.40 0.60 5459 11457 0.00 0.00 0.00 0.00 0.00 0.20 0.20 34.00 34.60 2.0 4899 1673314
+1 88 1 1 2 1 6162 278 278 0.20 0.20 72571 170757 0.00 0.00 0.00 0.00 0.00 5.60 7.00 15.40 25.20 3.4 3272 1640254
+1 79 1 1 6 0 658 54 31 2.60 2.60 95966 38156 0.00 0.00 0.00 0.00 0.00 3.40 5.80 223.80 221.80 1.6 2625 1795446
+1 94 1 1 8 6 1309 136 112 0.20 0.20 11073 15686 1.00 1.00 1.00 0.00 0.80 5.60 5.80 17.40 150.00 1.0 318 961362
+1 94 1 1 43 61 511 20 31 0.80 0.60 3519 13553 0.00 0.00 0.00 0.00 0.00 0.00 0.00 36.80 56.00 1.2 631 1067931
+1 98 1 1 3 2 380 47 10 0.40 1.40 21957 2478 0.00 0.00 0.00 0.00 0.00 0.00 0.00 23.75 36.13 1.0 8507 1862716
+1 76 1 1 4 2 3720 278 196 1.40 1.60 279725 263781 0.00 0.00 0.00 0.00 0.00 5.79 8.18 112.18 343.51 1.3 644 1006441
+1 90 1 1 1 0 3930 342 185 0.40 0.60 242555 187798 0.00 0.00 0.00 0.00 0.00 1.60 1.60 28.74 52.69 3.8 3440 1338127
+1 89 1 1 1 0 1388 79 47 0.20 0.20 33134 19325 0.00 0.00 0.00 0.00 0.40 0.20 0.40 21.60 22.00 2.2 1398 1753746
+1 81 1 1 9 2 2174 283 182 4.00 4.40 111934 46051 3.40 12.40 42.20 85.60 0.80 23.40 35.00 225.20 373.60 4.8 214 1055130
+1 92 1 1 1 1 2118 129 71 0.40 0.20 383282 22756 0.00 0.00 0.00 0.00 0.40 7.40 10.00 35.40 152.20 1.0 499 980013
+1 97 1 1 2 1 248 16 22 0.40 0.40 7334 9807 0.00 0.00 0.00 0.00 0.00 0.00 0.00 33.00 33.20 1.0 7550 1870232
+1 95 1 1 4 2 588 47 46 0.40 0.40 51753 37560 0.00 0.00 0.00 0.00 0.00 3.00 4.80 105.80 51.40 1.5 729 1039062
+1 91 1 1 12 6 1422 140 94 1.00 1.20 145826 29424 4.60 22.20 43.80 74.20 1.60 6.40 27.60 75.00 175.80 1.0 185 983597
+1 92 1 1 6 5 1711 50 72 0.80 2.20 28886 27183 3.60 4.60 3.60 0.00 1.80 1.40 1.80 66.60 122.40 1.0 251 1021256
+1 88 1 1 1 0 2046 238 154 0.60 0.60 25203 38223 0.60 1.20 1.20 0.00 0.20 4.60 4.60 70.00 98.80 1.8 170 1100499
+1 69 1 1 12 3 4291 458 337 5.99 6.59 357707 102795 0.00 0.00 0.00 0.00 0.00 7.39 9.58 318.56 625.95 1.3 2796 999281
+1 88 1 1 10 9 2881 222 114 0.40 0.40 148645 28774 2.00 2.20 2.00 0.00 1.60 3.59 4.99 50.30 101.40 1.5 283 978936
+1 95 1 1 1 0 887 62 64 0.20 0.20 30083 16777 1.40 1.80 1.80 0.00 0.00 2.60 4.40 15.60 37.40 1.0 241 1014226
+1 89 1 1 51 62 1865 124 98 0.80 1.00 11405 30316 0.00 0.00 0.00 0.00 0.40 4.80 4.80 70.60 133.80 2.6 701 977181
+1 86 1 1 1 1 5073 405 176 0.60 2.00 437640 205496 0.60 1.00 0.80 0.00 0.00 1.60 1.60 32.20 143.00 3.8 2180 988968
+1 97 1 1 12 11 1207 42 35 0.20 0.20 4492 18877 2.61 5.61 10.22 13.43 0.60 0.20 1.20 15.83 60.32 1.0 166 1083687
+1 94 1 1 24 37 1218 97 100 0.20 0.20 95619 30008 4.39 5.99 5.99 0.00 3.39 0.80 0.80 17.17 30.74 3.4 168 1438424
+1 90 1 1 4 0 2533 122 116 0.80 3.20 99537 100130 0.00 0.00 0.00 0.00 0.00 20.00 20.40 111.80 114.40 4.0 2942 1531818
+1 77 1 1 1 0 3032 230 149 0.60 2.00 108408 119191 0.00 0.00 0.00 0.00 0.00 8.00 13.00 43.00 197.40 1.5 432 985101
+1 97 1 1 0 0 244 38 20 0.20 0.20 168458 8012 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.97 16.97 1.2 7346 1861485
+1 92 1 1 25 22 2904 187 137 1.00 0.80 41485 57308 0.00 0.00 0.00 0.00 0.80 2.00 3.60 52.20 121.60 3.4 397 1326802
+1 84 1 1 4 1 4200 192 155 2.99 10.58 51812 35074 0.00 0.00 0.00 0.00 0.20 3.19 4.19 172.06 238.52 1.2 561 1093779
+1 75 1 1 31 18 2963 429 210 2.00 3.40 735011 735608 13.00 21.80 21.80 0.00 6.20 9.00 9.20 162.60 272.80 2.0 487 1038530
+1 89 1 1 1 0 1275 175 128 0.20 0.20 156250 60607 5.80 37.40 115.00 315.60 0.00 104.80 110.40 15.40 160.60 2.0 135 1089264
+1 98 1 1 0 0 217 10 19 0.20 0.20 3477 64742 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7746 1870136
+1 91 1 1 2 0 2137 92 72 1.20 1.40 19846 16092 1.40 10.20 19.00 28.00 0.20 11.60 12.00 98.60 160.80 1.0 201 1068720
+1 91 1 1 3 0 1626 280 150 2.20 1.00 376237 112914 0.00 0.00 0.00 0.00 0.00 0.80 1.40 115.60 166.00 4.4 3235 1605074
+1 96 1 1 2 0 801 62 62 0.40 0.40 29439 38059 0.00 0.00 0.00 0.00 0.00 1.40 1.60 34.13 50.10 1.0 792 1014876
+1 86 1 1 2 0 3292 259 126 1.20 1.80 357484 92310 0.00 0.00 0.00 0.00 0.20 30.40 38.40 99.60 205.80 1.0 2360 1013642
+1 0 1 1 0 0 1021 57 48 0.20 0.20 37328 46619 1.60 1.60 1.60 0.00 0.00 2.00 2.00 9.82 24.05 216 98 2
+1 87 1 1 7 6 3626 462 311 0.20 0.20 31210 53733 5.80 8.60 16.40 19.40 0.60 33.60 35.00 187.80 183.20 4.4 195 969245
+1 86 1 1 2 1 3236 279 185 0.80 3.59 427214 34775 0.00 0.00 0.00 0.00 0.00 1.40 2.79 44.91 81.44 3.0 609 1093292
+1 85 1 1 4 0 5283 247 208 0.80 2.20 188986 59023 0.00 0.00 0.00 0.00 0.00 23.20 23.20 95.60 260.40 2.2 552 1068752
+1 96 1 1 0 0 1290 67 78 0.20 0.20 5529 31271 0.40 0.40 0.40 0.00 0.00 1.00 1.00 15.20 29.00 1.0 230 1046680
+1 57 1 1 100 31 5548 694 543 8.00 3.00 386186 112809 3.40 14.60 40.60 74.40 0.20 51.40 70.80 456.00 774.20 1.0 591 1020440
+1 89 1 1 48 68 4285 202 165 0.40 0.40 24771 41113 0.40 0.40 0.40 0.00 0.00 0.60 3.40 20.40 91.00 1.0 265 969712
+1 95 1 1 0 0 2079 82 69 0.20 0.20 32768 35550 2.20 3.39 3.19 0.00 0.00 0.80 0.80 15.77 98.20 1.0 158 1013305
+1 97 1 1 3 1 318 31 25 0.40 0.40 117159 4530 0.00 0.00 0.00 0.00 0.00 0.20 0.20 35.60 40.00 2.0 4676 1847632
+1 96 1 1 0 0 408 47 29 0.20 0.20 89842 6208 1.80 1.80 1.80 0.00 0.80 0.00 0.00 15.60 23.20 1.0 143 1749658
+1 93 1 1 7 6 1610 50 49 0.40 0.80 15069 25364 4.40 5.40 5.40 3.40 2.00 2.60 2.60 38.60 69.40 1.0 137 1022242
+1 80 1 1 25 13 3049 179 107 2.40 4.60 149311 46521 0.00 0.00 0.00 0.00 0.00 8.00 12.20 234.40 403.20 3.2 2534 1525003
+1 99 1 1 0 0 159 15 16 0.20 0.20 452 2755 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7360 1865208
+1 95 1 1 1 0 632 101 49 0.20 0.20 195165 31251 2.60 4.80 4.80 0.00 0.00 0.20 0.20 15.60 25.40 1.0 148 1037008
+1 54 1 1 23 7 6426 916 583 12.80 5.80 774917 48759 2.20 3.00 6.20 6.80 3.20 12.00 14.20 653.20 1112.60 1.8 269 970091
+1 79 1 1 3 1 5598 221 283 0.40 0.60 98296 532449 2.00 2.40 2.40 0.00 0.80 2.40 2.60 36.20 73.00 1.0 227 1002725
+1 78 1 1 33 21 3917 271 152 3.19 11.58 496080 40455 9.98 26.95 85.23 162.87 2.79 8.38 9.18 227.54 422.75 1.8 136 1014686
+1 92 1 1 6 1 1201 128 95 2.40 3.20 158463 21294 0.00 0.00 0.00 0.00 0.00 1.40 1.80 131.60 191.40 3.0 1112 1062160
+1 89 1 1 7 5 1627 195 110 0.40 0.40 272063 84545 0.00 0.00 0.00 0.00 0.00 5.40 9.40 59.40 153.00 1.5 470 968790
+1 86 1 1 64 1 1877 196 186 2.79 2.20 53123 30434 0.00 0.00 0.00 0.00 0.00 7.39 8.98 182.24 234.73 4.0 962 1125137
+1 94 1 1 27 39 898 87 90 0.20 0.20 5233 37131 0.00 0.00 1.80 2.80 0.00 1.60 1.60 18.80 38.40 1.0 128 1128165
+1 98 1 1 12 18 177 16 16 0.20 0.20 732 6992 0.00 0.00 0.00 0.00 0.00 0.60 1.00 15.60 17.20 1.0 1322 1746112
+1 76 1 1 9 6 5988 392 257 2.40 9.00 422705 176642 0.00 0.00 0.00 0.00 0.20 2.00 2.00 189.00 225.00 3.2 1665 1413926
+1 96 1 1 5 1 413 42 50 0.40 0.40 20443 37574 3.59 4.79 4.79 0.00 0.80 1.20 1.20 30.94 38.92 1.0 172 1739796
+1 98 1 1 2 1 205 15 14 0.20 0.20 7018 2220 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7547 1870232
+1 86 1 1 44 54 2476 155 105 2.20 2.81 385336 17260 3.21 5.81 43.09 67.33 1.40 14.83 15.43 169.14 307.62 1.8 165 1062111
+1 90 1 1 4 0 2631 223 106 0.80 0.80 114906 25591 0.00 0.00 0.00 0.00 0.00 2.40 2.81 46.49 92.38 1.8 696 1109129
+1 96 1 1 0 0 2149 123 112 0.20 0.20 12090 27659 2.00 2.20 2.20 0.00 0.00 0.40 0.40 15.20 19.60 2.2 243 1708694
+1 81 1 1 17 3 2898 418 314 5.20 6.20 464006 176648 0.00 0.00 0.00 0.00 0.00 0.80 0.80 349.20 399.80 4.4 2384 1645445
+1 73 1 1 128 143 3247 543 172 3.01 5.61 648088 295537 5.41 55.91 158.92 308.42 0.20 97.39 134.87 571.34 357.72 1.7 137 1119484
+1 98 1 1 18 27 141 8 10 0.20 0.20 1028 9290 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.77 16.77 1.0 11972 1884990
+1 84 1 1 44 54 2797 323 204 1.60 4.59 265347 40452 0.00 0.00 0.00 0.00 6.39 5.59 18.56 107.78 136.13 2.3 367 1098207
+1 85 1 1 62 59 3502 273 148 2.20 2.40 355154 49921 0.00 0.00 0.00 0.00 0.00 3.00 9.40 109.40 176.40 1.0 965 975280
+1 81 1 1 5 2 3292 284 132 2.00 4.39 658861 20114 5.59 16.17 35.73 70.66 0.80 3.79 3.79 153.89 250.90 4.2 171 1095674
+1 85 1 1 7 0 4082 318 243 1.40 3.40 165226 36357 0.00 0.00 0.00 0.00 0.20 8.80 14.40 108.00 150.80 3.8 917 1070613
+1 83 1 1 1 0 4732 446 198 1.20 2.80 120247 224578 2.60 20.20 36.80 61.00 0.00 47.60 93.20 102.40 195.20 2.8 329 1382184
+1 87 1 1 6 1 5610 273 232 1.00 0.40 81512 61935 0.00 0.00 0.00 0.00 0.00 2.60 3.40 55.20 94.00 5.0 2599 1379610
+1 91 1 1 1 0 1280 53 59 0.80 0.80 71390 46715 2.40 5.59 23.35 78.24 1.80 31.54 38.92 45.11 116.77 2.0 147 1054092
+1 92 1 1 9 1 1224 109 75 1.80 3.39 58668 23476 1.80 2.00 2.20 0.60 0.80 1.00 1.00 91.42 170.46 2.0 156 973889
+1 82 1 1 47 53 1170 106 51 4.60 4.80 420909 72559 0.00 0.00 0.00 0.00 0.00 7.60 14.60 296.80 385.80 1.8 11724 1885976
+1 0 1 1 83 108 2950 250 220 0.20 0.20 130756 75616 7.40 11.20 12.40 2.40 2.60 2.40 7.60 31.20 83.40 477 86 14
+1 90 1 1 11 0 1402 176 88 2.20 2.20 326302 64623 0.00 0.00 0.00 0.00 0.00 2.00 3.00 99.60 180.20 3.0 1131 1538981
+1 85 1 1 8 6 2638 318 227 1.00 1.00 116691 55005 6.39 7.78 31.14 46.71 1.80 11.98 12.57 61.48 157.68 1.0 164 1096913
+1 0 1 1 21 18 1395 358 140 0.20 0.20 498541 524929 2.20 3.20 3.00 0.00 1.60 1.40 1.40 18.80 34.60 560 95 5
+1 52 1 1 40 26 6636 1144 313 10.22 18.84 2134529 184935 6.01 30.86 79.16 166.73 0.80 24.45 61.52 529.86 848.70 2.3 245 1098398
+1 91 1 1 5 0 1799 203 131 2.40 1.20 439266 15923 0.00 0.00 0.00 0.00 0.00 1.40 2.00 146.11 224.35 3.0 712 1066889
+1 80 1 1 6 1 6213 317 271 3.80 1.80 100052 30511 0.80 3.20 2.80 0.00 1.00 0.80 0.80 188.60 298.20 3.0 363 1015990
+1 97 1 1 2 1 453 63 46 0.40 1.80 4140 12068 1.00 1.00 1.00 0.00 0.20 1.00 1.00 20.60 30.60 3.2 329 1711859
+1 65 1 1 48 3 4078 258 170 11.98 34.33 81756 56652 4.59 5.39 5.19 0.00 0.80 0.60 0.60 389.82 753.89 2.2 192 1088992
+1 89 1 1 0 0 322 32 48 0.20 0.20 24023 34078 0.00 0.00 0.00 0.00 0.00 0.60 0.60 15.60 16.80 1.2 1842 1767288
+1 81 1 1 12 3 1752 135 45 1.60 1.80 218922 34199 0.00 0.00 0.00 0.00 0.00 1.00 1.00 127.40 187.00 3.0 759 1522786
+1 83 1 1 5 1 3187 374 224 2.80 2.20 213932 124408 0.00 0.00 0.00 0.00 0.00 3.20 3.60 171.20 361.80 3.8 549 1532930
+1 95 1 1 1 0 1870 93 59 0.20 0.20 89541 19336 0.20 0.20 0.20 0.00 0.00 0.80 1.20 18.20 18.80 3.6 160 1714075
+1 0 1 1 77 96 5275 461 387 3.99 1.00 211372 39920 4.19 9.78 43.51 64.87 0.20 23.75 26.15 188.42 449.90 142 70 30
+1 98 1 1 21 29 200 16 20 0.20 0.20 7044 10682 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 7265 1868770
+1 87 1 1 4 2 2102 253 184 1.40 6.80 44147 96111 0.00 0.00 0.00 0.00 0.00 2.20 2.20 67.20 108.20 1.4 529 1091947
+1 83 1 1 25 1 1109 83 72 5.00 3.20 136175 19238 4.00 5.80 17.00 36.00 1.40 0.60 0.60 208.80 332.80 2.4 314 1744074
+1 88 1 1 5 2 2522 269 201 1.00 0.80 599478 333148 0.00 0.00 0.00 0.00 1.40 19.76 22.36 53.29 136.93 5.0 609 1590180
+1 74 1 1 8 0 2418 364 325 7.00 2.00 197265 36000 0.00 0.00 0.00 0.00 0.00 0.00 0.00 343.40 498.40 2.2 2103 1768178
+1 93 1 1 4 2 1812 124 76 1.80 2.20 61200 9751 0.00 0.00 0.00 0.00 0.00 0.60 0.60 124.80 175.60 4.2 931 1639242
+1 88 1 1 3 0 2229 213 112 1.60 3.00 577518 102843 2.40 9.00 26.20 58.00 2.00 3.00 3.40 149.00 185.40 4.8 244 1526406
+1 86 1 1 18 1 4378 189 150 5.00 4.80 640892 100275 0.00 0.00 0.00 0.00 0.00 5.80 6.20 182.60 330.80 3.8 2809 1637317
+1 86 1 1 24 20 1737 263 145 3.40 4.40 305734 188601 0.00 0.00 0.00 0.00 0.00 1.40 2.00 222.60 337.20 5.2 2666 1603402
+1 97 1 1 2 1 699 35 33 0.20 0.20 1454 13449 0.00 0.00 0.00 0.00 0.00 0.40 0.40 27.20 19.00 1.7 677 1038936
+1 88 1 1 4 2 456 70 13 2.20 2.20 315016 17761 0.00 0.00 0.00 0.00 0.00 2.20 3.00 209.40 178.60 1.8 11662 1886528
+1 94 1 1 35 53 952 144 107 0.20 0.20 97252 50477 1.20 1.80 1.60 0.00 1.80 2.40 24.60 18.80 21.00 1.4 341 1741270
+1 95 1 1 39 65 310 44 46 0.20 0.20 890 24584 0.00 0.00 0.00 0.00 0.20 1.40 1.60 18.00 20.80 1.0 592 1730664
+1 98 1 1 2 1 756 23 20 0.20 0.20 10505 4454 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.80 16.80 1.0 4602 1828424
+1 90 1 1 11 8 1466 184 138 1.00 1.20 113794 81996 8.58 16.77 16.57 0.00 0.20 2.59 2.99 85.43 187.03 1.2 291 971772
+1 74 1 1 7 1 2394 334 315 6.80 19.20 142940 86476 1.00 1.00 1.00 0.00 0.20 17.40 28.60 251.60 453.40 1.8 354 1113926
+1 74 1 1 102 44 7489 546 411 2.00 4.79 711691 148758 3.39 8.38 8.38 0.00 12.77 4.39 5.19 112.97 200.20 2.4 428 1034216
+1 89 1 1 72 90 3643 203 130 0.40 1.80 75650 93652 10.20 18.40 25.80 14.80 1.80 6.60 7.20 33.60 81.40 3.6 163 1000467
+1 95 1 1 19 27 1400 40 35 0.20 0.20 24161 20345 1.00 1.80 1.40 0.00 0.00 1.60 2.60 15.60 30.40 1.0 182 1014530
+1 85 1 1 21 1 3336 598 572 3.00 2.00 587782 464470 0.00 0.00 0.00 0.00 0.00 2.40 3.00 138.80 219.00 1.8 509 1066181
+1 78 1 1 7 0 1703 160 127 6.20 17.80 114129 37911 2.60 22.60 29.60 42.20 0.00 19.60 26.60 220.80 434.00 1.0 156 1103315
+1 93 1 1 3 2 2520 94 67 0.40 1.20 9252 20524 3.20 3.20 3.20 0.00 0.80 3.00 3.60 29.80 63.80 3.5 183 1015502
+1 90 1 1 26 35 244 22 44 0.20 0.20 3458 87701 1.40 1.80 1.80 0.00 1.60 3.20 5.20 13.00 22.20 1.6 363 1744803
+1 95 1 1 2 2 1066 107 58 0.20 0.20 273368 251282 0.00 0.00 0.00 0.00 0.00 1.00 1.00 16.60 29.60 4.2 333 1595283
+1 97 1 1 1 1 182 13 14 0.40 0.40 1327 2502 0.00 0.00 0.00 0.00 0.00 0.00 0.00 25.55 38.92 2.0 9849 1866323
+1 92 1 1 8 7 2613 104 153 0.20 0.20 4805 360035 11.60 13.80 13.80 0.00 10.60 0.60 0.60 15.60 30.20 2.2 305 1391992
+1 81 1 1 4 0 4083 313 225 3.20 1.00 321786 73053 0.40 2.20 1.60 0.00 0.60 3.60 4.20 160.60 289.20 1.6 545 1015547
+1 84 1 1 8 3 2794 239 143 2.60 3.00 192634 23863 0.60 0.80 0.80 0.00 1.40 9.20 9.40 192.40 344.00 1.0 332 1128000
+1 98 1 1 0 0 160 12 13 0.20 0.20 737 3589 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 7562 1873980
+1 93 1 1 9 8 1824 134 112 1.00 2.20 47048 50902 2.40 5.60 5.40 0.00 0.80 4.20 6.20 54.80 161.80 1.3 213 1019315
+1 96 1 1 28 41 264 42 42 0.20 0.20 627 7520 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 215 1759640
+1 85 1 1 12 11 6414 431 191 0.20 0.20 935068 57293 0.00 0.00 0.00 0.00 0.00 1.00 3.60 26.40 58.60 1.6 405 1010683
+1 75 1 1 80 100 3318 199 183 1.40 2.59 52460 176733 2.79 4.79 4.79 0.00 0.00 12.18 45.91 139.12 325.15 2.6 385 988584
+1 87 1 1 1 0 454 38 39 0.80 1.20 102227 8211 0.00 0.00 0.00 0.00 0.00 1.60 1.60 72.40 171.20 1.6 1454 1753898
+1 91 1 1 5 0 2235 241 104 1.60 0.60 55435 35095 1.80 1.80 15.20 34.40 0.20 4.00 5.60 79.60 134.60 2.6 133 1711675
+1 82 1 1 47 55 4500 485 447 2.80 2.40 226566 245235 0.00 0.00 0.00 0.00 0.00 0.00 0.00 150.00 227.00 3.0 2388 1646278
+1 82 1 1 3 1 1996 150 83 1.00 1.60 440788 73466 6.21 13.63 39.68 95.39 12.02 26.85 48.90 95.59 134.47 2.0 133 1120213
+1 0 1 1 23 2 6172 781 624 10.40 3.40 746908 166202 23.20 40.40 74.00 96.60 13.60 30.40 56.00 536.80 832.20 134 55 45
+1 96 1 1 2 0 806 52 43 0.40 0.60 11892 22951 2.20 4.59 9.78 29.94 0.00 1.00 1.00 34.73 48.30 1.0 169 1012145
+1 88 1 1 48 2 1184 163 116 0.20 0.20 1336878 51629 9.58 25.55 37.33 60.88 3.59 45.91 292.61 28.74 46.71 3.5 160 1023751
+1 86 1 1 2 0 447 53 38 2.20 2.80 105707 29023 0.00 0.00 0.00 0.00 0.00 1.40 1.40 188.40 165.20 1.0 2693 1797126
+1 80 1 1 8 0 2802 408 355 8.38 2.20 233031 12990 0.00 0.00 0.00 0.00 0.00 0.00 0.00 390.02 560.48 3.2 7298 1859602
+1 93 1 1 3 2 1499 148 124 0.40 0.40 11264 34108 2.20 10.40 18.40 51.80 1.00 10.20 10.80 33.20 70.20 2.0 158 1085613
+1 0 1 1 8 1 885 139 63 0.40 0.40 118533 21572 0.20 0.20 0.20 0.00 8.60 29.40 38.40 29.80 136.60 450 92 8
+1 97 1 1 2 1 284 43 16 0.20 0.20 261161 11296 0.00 0.00 0.00 0.00 0.00 0.20 0.40 16.00 17.00 1.4 8351 1865738
+1 87 1 1 6 0 865 121 63 0.60 0.60 376896 21455 13.03 69.34 145.89 260.92 1.60 43.29 88.78 42.48 137.47 1.6 151 1740303
+1 87 1 1 11 0 5054 223 168 2.00 3.60 145345 14738 0.00 0.00 0.00 0.00 0.20 31.40 41.20 154.60 207.60 2.6 706 1384168
+1 88 1 1 7 3 2045 79 95 1.00 0.60 235236 89622 2.20 6.40 10.00 13.60 0.40 5.00 5.20 44.20 107.60 7.4 155 1300490
+1 83 1 1 155 136 4579 354 215 4.20 8.40 391100 262676 1.20 5.60 13.20 22.40 0.00 16.20 36.60 316.80 392.20 5.0 209 1333910
+1 96 1 1 17 21 256 23 21 0.20 0.20 46567 33495 5.20 8.40 8.20 0.00 0.00 0.00 0.00 15.40 16.80 2.0 185 1760056
+1 57 1 1 53 7 5708 311 169 11.00 27.80 405406 42991 0.00 0.00 0.00 0.00 0.00 9.60 13.20 474.60 770.80 1.0 1207 1107931
+1 83 1 1 3 0 1708 207 164 3.40 1.00 91511 9891 0.00 0.00 0.00 0.00 0.20 0.00 0.00 162.00 235.60 2.4 516 1745411
+1 98 1 1 0 0 195 9 15 0.20 0.20 840 3091 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.20 1.0 3284 1847526
+1 88 1 1 6 0 2719 136 105 1.00 2.40 50963 25627 0.00 0.00 0.00 0.00 0.60 47.60 58.00 161.60 202.00 5.6 6421 1404078
+1 95 1 1 10 6 2502 226 83 0.80 1.60 319639 286931 0.00 0.00 0.00 0.00 0.00 1.20 2.40 47.40 71.60 3.2 3079 1345570
+1 87 1 1 90 80 1995 230 119 1.00 0.80 37023 30467 2.61 42.08 92.79 266.73 0.00 13.23 60.52 44.29 80.76 2.0 128 1059710
+1 97 1 1 0 0 280 12 9 0.20 0.20 13785 3165 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.4 4581 1731592
+1 82 1 1 2 0 1096 100 58 2.60 3.80 351754 64445 4.00 4.00 4.00 0.00 0.40 0.60 1.00 187.60 218.60 1.4 230 1806363
+1 82 1 1 6 0 4386 398 270 1.40 4.20 627803 99226 2.40 4.40 6.80 8.20 5.20 5.00 23.60 106.40 210.40 2.5 284 1087445
+1 76 1 1 6 0 2029 249 176 5.79 20.76 228319 47314 5.59 22.75 47.50 82.44 0.00 37.52 54.09 210.58 480.64 1.0 141 1100679
+1 95 1 1 2 0 503 112 59 0.40 0.40 16765 10059 0.00 0.00 0.00 0.00 0.00 1.00 1.00 70.00 76.60 2.8 1463 1715962
+1 88 1 1 7 5 1982 152 219 1.80 7.20 281627 349582 0.00 0.00 0.00 0.00 0.00 1.80 2.40 208.00 169.60 4.8 1387 1613800
+1 98 1 1 12 11 322 104 41 0.20 0.20 226226 150259 0.00 0.00 0.00 0.00 0.00 0.00 0.00 21.40 18.00 3.4 1417 1757259
+1 86 1 1 22 27 2478 303 247 4.20 1.20 124481 20933 0.00 0.00 0.00 0.00 0.00 0.20 0.40 205.20 292.20 1.8 1520 1747144
+1 88 1 1 17 2 3284 239 136 0.80 1.00 372709 66373 1.60 1.60 1.60 0.00 1.40 14.20 22.00 93.20 159.40 3.6 334 1531936
+1 92 1 1 11 9 2830 235 142 0.60 0.40 59310 35831 0.00 0.00 0.00 0.00 0.00 0.60 0.60 32.20 138.60 3.2 380 1393698
+1 83 1 1 299 186 2326 148 88 3.40 3.40 418189 131463 0.00 0.00 0.00 0.00 27.60 11.20 13.40 159.60 270.40 4.6 2343 1730554
+1 88 1 1 6 0 1243 503 75 1.60 1.60 390014 10111 3.40 9.00 25.40 46.00 0.00 2.20 3.20 122.60 190.20 2.4 125 1742330
+1 93 1 1 2 0 1139 118 60 0.60 0.60 157977 42773 0.00 0.00 0.00 0.00 0.00 4.40 6.60 55.60 103.80 2.4 4565 1731554
+1 90 1 1 10 5 1610 189 99 1.60 0.80 30160 16340 0.00 0.00 0.00 0.00 0.00 17.96 17.96 98.60 212.57 2.2 986 972040
+1 98 1 1 1 1 444 53 45 0.20 0.20 12152 15855 1.00 1.00 2.40 3.39 0.60 0.00 0.00 16.37 17.37 1.0 139 1738984
+1 85 1 1 8 2 2306 411 208 1.60 2.00 1166192 126960 1.80 2.20 2.20 0.00 1.00 2.80 4.60 97.80 192.60 2.5 387 1072661
+1 95 1 1 27 36 354 50 40 0.60 0.60 4988 21803 0.00 0.00 0.00 0.00 0.60 1.00 1.00 27.60 45.20 3.0 496 1712853
+1 76 1 1 34 5 4791 581 358 4.20 1.40 211613 53201 3.60 19.40 43.20 127.00 0.60 0.80 1.00 209.00 396.00 9.2 146 1288742
+1 93 1 1 10 9 1750 84 58 0.40 1.80 25590 25581 0.00 0.00 0.00 0.00 0.00 1.60 2.00 22.36 32.93 1.3 1513 1079473
+1 80 1 1 1 0 3159 461 232 1.80 1.40 318346 64616 5.59 20.76 56.89 165.27 0.40 35.13 56.69 78.24 167.86 2.2 145 1125303
+1 89 1 1 1 0 4083 143 150 0.20 0.20 10507 4600 0.00 0.00 0.00 0.00 0.00 2.20 2.20 21.80 22.60 2.0 754 1448346
+1 92 1 1 2 0 1885 139 84 1.80 11.20 318612 22557 0.00 0.00 0.00 0.00 0.00 0.20 0.20 123.00 137.80 1.6 898 1763821
+1 93 1 1 6 5 1110 127 82 0.40 1.80 12110 29425 5.39 10.98 22.16 42.32 1.20 23.35 23.35 21.56 125.75 1.2 148 989972
+1 96 1 1 1 1 473 44 42 0.40 0.60 2302 24438 1.80 2.60 2.00 0.00 1.40 0.80 0.80 38.40 59.00 2.0 206 1024472
+1 0 1 1 18 11 1424 242 242 2.00 2.00 238848 453209 58.40 115.00 120.80 14.20 1.00 13.20 19.00 124.40 265.40 272 79 21
+1 68 1 1 37 51 2293 159 101 1.20 1.20 1062841 152976 50.70 128.34 292.61 444.11 0.60 126.35 243.11 83.43 213.97 1.4 102 981164
+1 98 1 1 0 0 165 9 14 0.20 0.20 1177 22413 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7932 1880992
+1 88 1 1 1 0 4041 374 274 0.20 0.20 89934 17257 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 18.40 2.4 6327 1732208
+1 88 1 1 0 0 4537 212 205 0.40 0.20 67028 254584 4.80 10.00 9.40 0.00 2.60 5.80 7.20 17.80 90.60 1.4 298 1013290
+1 73 1 1 44 53 4539 586 371 6.60 2.60 416014 21148 10.80 34.60 82.20 181.20 1.00 7.20 9.40 329.00 536.20 3.5 224 980310
+1 93 1 1 1 1 2428 191 96 0.20 0.20 22571 24071 0.00 0.00 0.00 0.00 0.00 2.00 3.20 14.40 35.80 2.0 842 1383738
+1 87 1 1 12 5 1694 239 118 0.80 0.40 100081 43076 0.80 1.00 1.00 0.00 0.40 4.20 4.20 86.80 119.80 3.6 336 1060800
+1 82 1 1 9 6 3690 386 253 1.20 1.20 73987 36785 0.00 0.00 0.00 0.00 0.40 12.83 16.03 148.70 169.14 2.0 426 1098613
+1 86 1 1 164 183 1909 174 153 0.60 1.00 48876 90840 4.80 16.80 61.20 132.80 0.40 29.00 55.80 99.20 130.80 1.3 165 1067525
+1 90 1 1 3 1 1329 131 74 1.00 1.00 115563 85464 20.16 27.74 27.74 0.00 11.58 1.80 2.20 52.89 156.49 1.0 232 1054184
+1 98 1 1 0 0 233 39 36 0.20 0.20 796 12532 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13.00 18.00 1.2 1334 1761776
+1 94 1 1 1 1 805 69 86 0.20 0.20 113062 253316 0.00 0.00 0.00 0.00 0.00 1.40 1.60 15.60 18.20 1.4 8201 1836408
+1 92 1 1 12 3 1719 144 87 1.60 1.60 322715 290977 0.00 0.00 0.00 0.00 0.00 2.99 5.79 90.02 163.27 4.2 2375 1560085
+1 92 1 1 5 2 1796 157 99 0.60 0.40 351476 114187 0.00 0.00 0.00 0.00 0.00 0.60 0.80 43.00 49.00 2.4 1649 1541882
+1 87 1 1 23 7 3293 228 198 2.60 1.00 162726 101353 0.00 0.00 0.00 0.00 0.60 0.40 0.40 212.00 207.60 2.8 3139 1547168
+1 82 1 1 12 0 4315 426 372 5.40 1.60 162628 11693 0.00 0.00 0.00 0.00 0.00 0.00 0.00 258.00 381.20 2.8 4973 1718726
+1 88 1 1 36 53 2180 309 119 0.20 0.20 597126 35393 2.59 3.39 7.19 7.39 0.80 21.56 43.91 18.76 40.32 1.0 157 1096487
+1 78 1 1 8 0 2953 422 339 8.00 2.20 443353 177081 0.00 0.00 0.00 0.00 0.00 1.60 3.20 373.00 544.40 3.2 3585 1820538
+1 88 1 1 3 0 3564 301 223 0.20 0.20 15492 104015 9.60 19.40 24.00 56.60 0.00 2.40 2.60 16.40 47.40 2.7 162 1065054
+1 93 1 1 21 31 2350 110 104 0.20 0.20 8605 77964 0.00 0.00 0.00 0.00 0.20 1.00 1.60 16.40 30.40 1.0 664 1060856
+1 93 1 1 24 38 2180 114 89 0.20 0.20 51945 38286 0.00 0.00 0.00 0.00 0.00 0.60 0.60 16.00 20.40 2.0 548 1120072
+1 97 1 1 2 0 429 79 46 0.40 0.60 175471 10085 0.00 0.00 0.00 0.00 0.00 4.80 4.80 36.60 54.20 2.2 6279 1710480
+1 78 1 1 11 1 2802 432 371 8.00 2.60 215560 16504 0.00 0.00 0.00 0.00 0.80 0.00 0.00 401.20 581.20 1.2 1552 1778072
+1 94 1 1 2 1 725 173 26 0.40 0.60 1219735 81878 0.00 0.00 0.00 0.00 0.00 4.20 8.40 28.40 41.80 3.0 6726 1842285
+1 93 1 1 18 15 1467 185 103 0.80 0.80 134239 129551 0.00 0.00 0.00 0.00 0.00 0.20 0.20 69.80 74.20 4.4 1496 1602899
+1 95 1 1 30 27 373 81 64 0.60 3.40 232970 238113 0.00 0.00 0.00 0.00 0.00 3.00 5.80 24.60 40.00 4.2 836 1727938
+1 84 1 1 7 3 2391 147 114 4.21 5.81 68390 36413 9.62 33.47 85.57 177.35 0.60 11.62 13.03 150.50 317.03 2.0 131 1093693
+1 87 1 1 49 56 3621 183 144 1.60 2.40 306458 121162 0.00 0.00 0.00 0.00 0.00 1.40 1.60 108.80 174.60 2.8 1390 1544488
+1 92 1 1 18 6 1590 105 91 0.60 0.60 23101 25903 2.80 2.80 2.80 0.00 2.40 4.40 4.60 61.80 111.00 1.0 322 992837
+1 88 1 1 1 1 2683 228 107 0.80 2.20 949201 88398 0.00 0.00 0.00 0.00 0.00 2.00 2.00 40.12 106.99 1.0 508 1029589
+1 97 1 1 2 1 831 71 37 0.40 0.40 3836 10985 0.00 0.00 0.00 0.00 0.00 0.40 0.60 28.06 42.89 1.0 1300 1749587
+1 87 1 1 7 0 1819 170 136 6.20 12.60 200515 22853 0.00 0.00 0.00 0.00 0.00 2.40 2.60 251.20 403.00 2.6 4234 1821074
+1 91 1 1 1 0 3178 247 157 0.20 0.20 347219 175897 0.00 0.00 0.00 0.00 0.00 20.60 37.60 15.60 51.80 3.6 3999 1334674
+1 97 1 1 2 1 508 73 41 0.40 0.40 1787 9101 0.00 0.00 0.00 0.00 0.00 0.60 0.80 29.06 40.48 1.0 640 1734296
+1 97 1 1 1 1 230 10 14 0.20 0.20 12031 45650 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 7843 1871088
+1 92 1 1 26 37 1203 101 73 0.80 0.80 107456 186673 0.00 0.00 0.00 0.00 0.00 0.20 0.20 63.60 85.00 2.0 6561 1852306
+1 98 1 1 19 28 195 13 17 0.20 0.20 5112 44704 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7480 1865456
+1 89 1 1 5 1 2143 134 91 0.80 0.60 17593 26145 0.00 0.00 0.00 0.00 0.00 1.60 1.60 55.09 100.00 1.4 547 1103411
+1 91 1 1 28 41 821 238 214 0.40 0.40 409144 158958 5.00 27.20 84.60 151.20 0.40 34.00 67.40 28.20 45.40 3.2 134 1735840
+1 90 1 1 2 1 2288 147 119 0.20 0.20 111699 23476 1.60 5.59 17.76 34.53 0.60 0.80 1.00 20.16 33.53 1.6 281 1735946
+1 87 1 1 6 0 660 73 34 0.40 0.40 235409 4964 4.40 29.60 66.00 103.40 0.80 2.40 22.80 26.00 95.00 3.4 138 1737786
+1 90 1 1 8 1 3410 378 177 1.80 1.60 121662 27652 0.00 0.00 0.00 0.00 0.00 3.20 4.20 113.40 191.80 2.6 6146 1715850
+1 71 1 1 23 5 5329 449 278 5.19 3.79 869349 28503 6.39 11.58 11.18 0.00 1.00 5.79 8.58 297.21 463.87 2.8 191 1078451
+1 75 1 1 11 1 4209 295 176 5.99 17.56 301116 42619 0.80 0.80 0.80 0.00 0.20 8.18 8.38 199.40 440.72 1.4 296 1083358
+1 91 1 1 5 1 1308 209 167 3.40 1.00 354691 23277 0.00 0.00 0.00 0.00 0.00 0.00 0.00 165.60 234.80 1.6 7649 1878550
+1 92 1 1 2 0 303 27 24 1.60 1.60 31748 14620 0.00 0.00 0.00 0.00 0.00 1.20 1.40 141.00 124.00 1.2 6738 1853766
+1 91 1 1 16 13 1163 85 103 0.60 0.40 206377 154758 0.00 0.00 0.00 0.00 0.00 1.80 2.60 97.00 48.20 2.6 475 1513082
+1 0 1 1 20 2 1169 194 195 0.40 0.80 312017 259833 1.80 2.00 22.60 44.40 0.40 31.60 60.60 35.00 75.40 227 86 13
+1 65 1 1 34 26 4307 452 388 7.40 5.40 197746 68193 16.80 31.40 29.80 0.00 2.40 28.20 39.00 396.00 717.40 2.0 304 1003450
+1 94 1 1 2 1 453 79 66 0.60 0.60 124108 134813 0.00 0.00 0.00 0.00 1.80 1.40 1.40 27.54 40.32 3.4 461 1709276
+1 90 1 1 38 37 990 120 103 1.20 1.60 45418 29320 0.00 0.00 0.00 0.00 0.00 33.00 39.60 91.40 176.00 1.0 519 1017666
+1 59 1 1 14 3 6171 691 588 7.77 2.99 224709 90255 0.00 0.00 0.00 0.00 0.00 28.09 29.08 437.65 700.00 2.3 3268 1006010
+1 91 1 1 1 0 3037 192 160 0.20 0.20 10313 96764 0.00 0.00 0.00 0.00 0.00 2.20 2.80 18.00 69.60 1.0 344 1070120
+1 78 1 1 20 4 2936 268 226 1.00 1.20 180342 61887 12.40 26.60 47.00 102.00 2.20 8.00 15.40 72.00 189.20 1.3 175 966192
+1 85 1 1 6 0 1930 275 233 5.80 1.60 130635 21141 0.00 0.00 0.00 0.00 0.00 2.20 2.60 273.20 396.40 2.8 6342 1864230
+1 85 1 1 4 2 3411 336 164 1.20 1.00 131413 44494 0.00 0.00 0.00 0.00 0.00 4.00 4.40 71.80 122.80 1.0 645 1118875
+1 77 1 1 7 0 2024 120 101 6.60 19.40 26760 71512 0.00 0.00 0.00 0.00 0.00 6.20 6.40 220.00 447.40 1.6 557 1081963
+1 92 1 1 5 0 1590 75 62 1.00 2.80 36682 28990 0.00 0.00 2.40 14.00 0.00 4.60 4.60 66.40 131.80 1.0 137 1089056
+1 97 1 1 1 0 212 29 21 0.20 0.20 75166 10225 0.00 0.00 0.00 0.00 0.00 0.20 0.20 19.60 17.00 1.2 2852 1775840
+1 96 1 1 2 0 759 45 37 0.40 1.80 18005 13520 0.00 0.00 0.00 0.00 0.00 0.20 0.20 41.28 40.48 1.0 752 1043222
+1 90 1 1 1 0 1249 94 32 0.40 0.20 357164 13705 1.40 1.60 1.60 0.00 1.80 1.40 1.60 37.40 46.60 2.0 258 1741093
+1 98 1 1 0 0 380 37 23 0.20 0.20 1007 4477 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.77 17.56 1.0 881 1737892
+1 94 1 1 1 0 859 116 67 0.20 0.20 202962 22913 0.00 0.00 0.00 0.00 0.00 1.40 1.80 20.40 18.00 2.8 438 1054056
+1 87 1 1 110 127 5176 272 172 0.20 0.20 238224 222016 0.00 0.00 0.00 0.00 0.00 7.60 14.80 16.00 61.60 3.8 1505 1326022
+1 92 1 1 35 52 937 247 159 0.20 0.20 6871 12638 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 19.80 3.2 523 1720032
+1 96 1 1 0 0 394 160 66 0.20 0.20 201455 220580 0.80 1.20 1.20 0.00 0.00 12.40 23.20 15.60 59.40 3.0 275 1736867
+1 95 1 1 27 39 1252 53 118 0.20 0.20 26592 54394 0.00 0.00 0.00 0.00 0.00 0.40 0.60 19.44 20.04 1.2 7762 1875466
+1 87 1 1 12 6 1676 479 199 1.20 2.60 469921 25152 12.80 35.80 70.40 105.00 8.40 17.00 22.80 84.20 265.20 1.4 131 960402
+1 91 1 1 7 6 1850 185 106 0.80 0.80 20420 34074 0.00 0.00 0.00 0.00 0.60 4.80 5.20 67.60 116.80 2.0 410 979160
+1 84 1 1 7 0 3317 310 254 2.59 1.60 177917 128567 0.00 0.00 0.00 0.00 0.00 15.57 15.77 152.89 263.27 4.4 1470 1041161
+1 77 1 1 25 4 2308 164 254 0.60 0.60 336637 180700 0.00 0.00 0.00 0.00 0.00 0.60 0.60 71.20 134.80 4.4 632 1520762
+1 90 1 1 1 1 331 55 54 0.20 0.20 234056 232515 0.00 0.00 0.00 0.00 0.00 5.81 8.22 15.83 22.85 1.2 2075 1770903
+1 95 1 1 16 25 352 34 30 0.40 0.40 1926 12224 0.00 0.00 0.00 0.00 0.60 0.00 0.00 33.60 39.80 2.0 713 1722112
+1 96 1 1 3 1 540 96 88 0.20 0.20 45128 56460 0.00 0.00 0.00 0.00 0.00 0.20 0.20 22.60 17.40 2.0 1333 1713242
+1 98 1 1 0 0 198 15 33 0.20 0.20 16125 7366 0.00 0.00 0.00 0.00 0.00 1.60 2.80 15.80 16.80 1.0 5255 1860792
+1 79 1 1 15 3 4342 258 171 3.20 2.00 341197 52562 0.00 0.00 0.00 0.00 0.00 0.60 0.80 226.60 273.00 3.8 841 1534317
+1 78 1 1 29 19 4862 226 212 1.60 2.40 313298 76539 9.20 19.80 35.20 49.60 5.60 25.80 47.00 105.60 219.20 2.6 176 1109021
+1 75 1 1 11 4 2378 200 109 6.79 20.56 42708 21136 3.59 11.98 14.17 30.14 0.40 7.19 9.78 250.70 448.10 1.8 138 1100343
+1 88 1 1 2 0 3329 392 156 0.40 1.80 509620 63742 0.00 0.00 0.00 0.00 0.60 13.80 25.40 33.20 54.40 1.0 472 1078000
+1 93 1 1 1 0 1628 167 128 0.80 2.00 67281 30403 1.80 2.20 2.20 0.00 0.00 0.80 1.60 58.40 71.00 2.2 230 1118339
+1 90 1 1 1 1 2372 189 414 0.20 0.20 26824 40025 0.80 1.00 1.00 0.00 0.20 7.60 7.80 22.80 21.60 2.0 198 1067126
+1 89 1 1 12 11 2014 339 206 0.20 0.20 50202 29517 0.00 0.00 0.00 0.00 0.00 6.20 8.20 18.20 128.40 1.5 435 1098538
+1 91 1 1 3 0 1379 145 124 2.80 5.40 82823 74139 0.60 0.60 0.60 0.00 0.00 0.80 1.20 167.40 207.00 2.5 179 999150
+1 0 1 1 12 5 745 82 83 1.20 0.80 56291 47669 0.00 0.00 0.00 0.00 0.00 6.80 13.40 80.00 171.00 1556 92 8
+1 87 1 1 16 1 4025 297 261 1.20 3.99 103946 105846 0.00 0.00 0.00 0.00 0.00 2.99 3.39 58.08 90.42 3.0 1012 1629728
+1 77 1 1 10 0 2665 496 314 6.80 2.40 214887 11611 0.00 0.00 0.00 0.00 0.00 0.00 0.00 356.20 521.20 4.0 448 1719106
+1 96 1 1 17 24 344 113 35 0.20 0.20 179355 7812 0.00 0.00 0.00 0.00 0.00 0.20 0.20 17.20 22.00 1.6 6461 1871491
+1 86 1 1 28 38 4703 234 187 2.60 0.80 63062 24504 0.80 0.80 0.80 0.00 1.00 1.60 2.00 132.00 292.80 1.0 185 1015110
+1 96 1 1 1 0 659 146 65 0.40 1.00 174169 173437 0.00 0.00 0.00 0.00 0.00 0.00 0.00 30.20 27.80 3.6 797 1746192
+1 92 1 1 4 1 1459 116 84 0.80 0.80 10612 19701 0.00 0.00 0.00 0.00 0.00 7.60 7.60 39.00 78.20 1.0 578 1020677
+1 83 1 1 18 2 2669 188 168 3.60 9.20 197760 233386 0.00 0.00 0.00 0.00 0.40 20.40 40.40 129.00 263.60 4.2 920 1632099
+1 86 1 1 10 8 2547 240 162 1.00 1.00 153152 170207 4.01 4.61 4.41 0.00 2.20 18.04 22.44 130.66 147.70 1.3 257 979110
+1 98 1 1 0 0 160 8 18 0.40 1.40 1092 13641 0.00 0.00 0.00 0.00 0.00 0.00 0.00 29.40 27.40 1.0 7431 1876200
+1 82 1 1 14 4 3191 175 173 0.80 2.20 211339 401453 9.80 24.20 53.20 109.00 2.00 30.00 37.00 60.80 125.60 1.8 157 1010797
+1 75 1 1 18 5 7786 298 228 1.60 3.60 123860 36841 5.00 5.20 5.20 0.00 4.60 8.60 8.80 155.20 171.80 3.2 211 1447189
+1 70 1 1 15 1 4171 681 474 9.20 4.00 446678 105973 0.00 0.00 0.00 0.00 0.20 5.80 10.60 430.20 757.40 6.8 964 1539776
+1 0 1 1 2 0 2085 122 90 0.40 0.60 56988 35006 0.00 0.00 0.00 0.00 0.00 4.40 6.80 35.40 45.40 395 95 5
+1 96 1 1 17 16 788 81 69 0.40 0.20 10555 42588 0.00 0.00 0.00 0.00 0.00 3.20 3.20 20.00 98.80 1.6 523 967448
+1 95 1 1 4 1 2377 190 78 0.40 2.00 41003 36190 2.00 2.20 2.20 0.00 0.00 2.40 2.60 33.80 47.40 2.0 347 1527106
+1 94 1 1 1 0 1474 74 58 1.20 5.40 63027 27180 1.80 3.20 2.80 0.00 0.00 4.00 4.20 60.00 136.00 2.0 250 1014005
+1 88 1 1 11 1 4485 217 251 0.80 0.60 35065 90454 0.00 0.00 0.00 0.00 0.40 11.22 11.22 38.88 207.41 1.8 726 1065044
+1 93 1 1 2 1 929 133 17 0.60 1.20 1031503 55161 0.00 0.00 0.00 0.00 0.00 0.00 0.00 39.68 72.34 1.8 8515 1868604
+1 95 1 1 2 0 683 53 30 0.80 1.00 113192 40191 0.00 0.00 0.00 0.00 0.00 0.00 0.00 51.60 66.60 2.4 2296 1698589
+1 95 1 1 4 1 877 62 51 0.60 2.00 17524 35342 0.00 0.00 0.00 0.00 0.20 0.20 0.20 49.60 58.60 2.0 1820 1539704
+1 95 1 1 1 1 1365 101 56 0.20 0.20 116063 62156 0.00 0.00 0.00 0.00 0.00 1.60 3.20 15.60 18.40 1.0 8291 1839168
+1 93 1 1 2 0 2579 106 76 0.80 0.40 11166 7333 0.00 0.00 0.00 0.00 0.00 0.60 0.80 48.00 66.00 1.0 474 1730904
+1 98 1 1 2 1 237 20 19 0.20 0.20 9384 10394 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.64 17.03 1.0 6368 1852585
+1 90 1 1 59 64 1246 160 192 1.00 0.80 149778 130773 0.00 0.00 0.00 0.00 0.00 5.60 14.00 61.60 132.00 2.4 1929 1537322
+1 76 1 1 596 0 2779 95 61 0.20 0.20 593425 5895 8.40 54.80 113.00 274.80 0.00 66.00 131.80 19.40 157.00 5.8 131 1352968
+1 95 1 1 3 2 397 52 56 0.40 0.40 9250 5433 1.80 1.80 1.80 0.00 0.80 2.20 3.20 41.00 42.00 3.2 173 1704123
+1 88 1 1 2 2 2103 173 130 0.20 0.20 249976 140342 2.00 3.59 3.59 0.00 0.00 9.58 15.57 17.17 57.49 1.7 384 988354
+1 89 1 1 48 46 1392 216 143 2.20 2.59 37374 28050 1.00 1.00 1.00 0.00 1.00 12.18 15.97 135.53 268.06 2.5 301 989464
+1 98 1 1 1 1 454 176 45 0.20 0.20 472554 211006 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 17.00 3.0 6830 1835902
+1 94 1 1 2 0 1773 84 79 0.20 0.20 18680 28607 3.40 3.80 3.80 0.00 0.40 7.60 9.20 16.00 43.80 2.0 199 1087838
+1 96 1 1 1 0 341 53 28 0.20 0.20 193835 11060 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.20 18.20 1.0 989 1762725
+1 92 1 1 3 0 1195 181 60 2.40 2.40 42713 37842 2.00 4.00 13.20 27.40 0.80 0.60 0.80 181.00 290.60 2.6 271 1754974
+1 94 1 1 2 1 420 93 30 0.80 1.00 206743 111335 0.00 0.00 0.00 0.00 0.00 2.00 3.00 45.40 65.60 3.4 1761 1758696
+1 99 1 1 2 1 149 9 7 0.20 0.20 7001 1498 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 6476 1871530
+1 91 1 1 1 1 3898 189 138 0.60 2.00 166414 10001 0.80 0.80 0.80 0.00 0.00 3.59 3.59 80.84 80.64 3.2 173 1441305
+1 91 1 1 5 0 2452 173 139 2.00 2.00 49625 39763 0.00 0.00 0.00 0.00 0.00 0.20 0.20 76.20 134.80 2.6 663 1727416
+1 92 1 1 1 0 1057 206 43 0.40 0.40 944834 7872 0.00 0.00 0.00 0.00 0.00 0.00 0.00 21.00 94.60 4.0 487 1702920
+1 91 1 1 2 0 2314 159 160 0.40 0.20 39607 181616 0.20 0.20 9.38 16.97 0.20 5.79 8.38 24.55 44.71 4.0 127 1061359
+1 89 1 1 12 5 1861 209 108 0.60 0.80 467179 16932 1.80 2.80 2.80 0.00 0.80 20.80 26.80 58.40 132.40 8.0 189 1300462
+1 90 1 1 7 5 4240 185 170 0.60 1.00 13463 40559 0.00 0.00 0.00 0.00 0.20 0.80 2.00 44.31 76.45 1.0 1134 1053974
+1 83 1 1 3 0 4718 295 160 2.40 6.20 132190 84458 4.80 14.80 22.60 39.40 0.20 5.20 7.60 120.20 249.60 1.7 353 1030331
+1 91 1 1 24 11 2682 212 193 1.00 0.80 122747 89983 4.39 4.59 4.59 0.00 2.00 1.60 2.20 64.87 139.92 1.2 263 1074010
+1 90 1 1 8 5 2489 128 208 0.20 0.20 66317 431882 3.20 14.00 19.20 14.40 1.20 6.20 8.20 16.00 29.40 2.0 172 1385682
+1 96 1 1 1 1 1571 109 85 0.20 0.20 7696 57951 0.60 0.60 1.20 0.60 0.00 1.20 1.40 16.00 38.60 1.2 144 1002419
+1 90 1 1 13 11 3520 182 207 0.20 0.20 84961 160611 2.80 5.40 5.40 0.00 1.00 2.80 6.40 17.20 41.00 1.3 198 999368
+1 92 1 1 0 0 258 24 42 0.20 0.20 25598 39822 0.00 0.00 0.00 0.00 0.00 1.79 1.79 15.51 19.68 1.2 2007 1756747
+1 85 1 1 4 2 4635 312 265 0.40 0.20 30763 129153 7.60 11.20 11.20 0.00 4.40 19.20 20.20 25.80 54.80 2.4 207 1447882
+1 96 1 1 2 1 1307 97 36 0.20 0.20 11207 22764 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.4 4621 1828408
+1 94 1 1 13 9 709 78 99 0.80 0.60 47868 37038 0.00 0.00 0.00 0.00 0.00 7.40 8.40 56.00 104.20 1.0 503 969976
+1 93 1 1 2 0 1592 107 65 0.80 0.60 29553 10110 2.80 2.80 2.80 0.00 0.20 1.00 1.00 38.20 49.00 3.2 302 1711082
+1 92 1 1 111 49 2235 218 187 0.40 0.40 184223 158204 4.00 13.80 13.80 0.00 1.00 14.20 24.40 33.20 88.20 3.2 323 1319565
+1 68 1 1 30 1 4917 365 143 7.00 19.40 268569 76831 5.40 11.80 23.60 32.40 0.20 8.40 14.20 430.20 543.00 3.4 168 1088946
+1 98 1 1 2 1 204 16 9 0.20 0.20 14162 4918 0.00 0.00 0.00 0.00 0.00 1.40 2.20 15.60 16.80 1.4 6958 1845062
+1 84 1 1 62 72 2507 234 130 3.60 7.00 147446 82699 0.00 0.00 0.00 0.00 0.00 0.60 0.80 411.20 386.40 3.4 934 1539442
+1 91 1 1 58 80 1488 181 160 0.40 0.40 25955 31343 1.20 1.20 1.20 0.00 1.00 16.20 16.60 41.60 156.60 1.2 366 986472
+1 68 1 1 12 3 3958 408 284 9.60 18.60 152577 28722 2.80 6.60 12.60 19.20 1.00 7.60 10.20 370.80 623.60 1.0 117 1109061
+1 96 1 1 1 0 1611 66 70 0.20 0.20 16723 50242 0.00 0.00 0.00 0.00 0.00 0.80 1.00 26.00 20.60 1.3 581 1019464
+1 0 1 1 22 20 2017 393 151 0.40 0.40 583985 551003 0.00 0.00 0.00 0.00 0.00 66.73 95.99 33.27 150.10 702 90 10
+1 89 1 1 21 18 2284 242 255 0.60 0.60 116690 207556 2.20 2.80 2.60 0.00 1.00 10.80 11.00 42.20 93.20 3.6 356 1068194
+1 84 1 1 42 57 2754 224 136 1.00 1.20 57544 63620 4.40 16.20 40.80 81.60 0.00 12.60 12.80 104.20 243.20 2.6 192 1525907
+1 89 1 1 39 36 1278 136 107 1.00 1.00 294454 32347 0.00 0.00 0.00 0.00 0.20 13.60 63.00 114.40 234.00 2.0 1018 1051102
+1 64 1 1 19 2 4392 320 157 10.18 28.34 820347 41889 3.99 11.18 30.34 159.08 2.99 22.36 29.54 357.88 740.92 1.8 173 1096425
+1 74 1 1 7 3 2725 237 221 3.40 1.60 300889 238908 0.00 0.00 0.00 0.00 14.40 22.20 42.00 158.80 357.60 2.0 569 1042981
+1 82 1 1 47 47 3219 273 237 5.80 4.80 216165 140492 0.00 0.00 0.00 0.00 0.20 1.20 1.40 252.40 397.60 3.0 2759 1650349
+1 98 1 1 2 1 183 13 17 0.20 0.20 8687 11003 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.84 16.83 1.4 7261 1867705
+1 91 1 1 2 1 2392 114 78 0.40 0.40 12325 61724 0.00 0.00 0.00 0.00 0.20 8.00 8.20 31.00 110.80 4.4 737 1061923
+1 88 1 1 43 50 1545 153 103 2.40 4.80 25594 42289 0.00 0.00 0.00 0.00 0.20 1.80 2.00 228.80 257.60 2.2 620 1526627
+1 76 1 1 32 35 2958 294 230 4.80 1.40 219581 27185 2.60 6.60 10.60 10.40 0.60 1.20 1.80 232.60 340.40 3.2 158 1752144
+1 86 1 1 104 108 2559 149 143 2.40 4.01 141636 130115 0.00 0.00 0.00 0.00 0.00 12.63 21.84 155.11 254.51 2.0 848 1076717
+1 90 1 1 2 0 1145 108 59 0.80 0.80 129287 17061 0.20 0.20 0.20 0.00 0.20 15.83 28.46 56.11 71.94 3.8 356 1058657
+1 94 1 1 19 26 1514 187 149 0.60 0.40 41145 31956 0.00 0.00 0.00 0.00 0.40 1.00 1.00 33.27 44.89 1.2 424 1094265
+1 85 1 1 2 1 3996 323 133 0.40 0.80 1352240 156247 0.00 0.00 0.00 0.00 0.20 5.60 6.60 41.40 108.00 1.7 392 985278
+1 90 1 1 2 1 487 48 20 2.00 2.20 110291 18247 0.00 0.00 0.00 0.00 0.00 2.00 3.20 174.40 163.40 1.0 11440 1881528
+1 91 1 1 4 1 2196 145 113 0.40 0.40 77582 39656 0.60 0.60 0.60 0.00 1.00 73.20 78.80 49.80 168.20 4.0 460 989878
+1 98 1 1 0 0 296 31 30 0.20 0.20 9917 12080 0.60 0.60 0.60 0.00 0.40 0.20 0.20 15.37 16.77 1.0 187 1739875
+1 95 1 1 17 25 1029 109 83 0.20 0.20 91929 20653 0.60 0.60 0.60 0.00 0.80 2.00 2.00 16.57 38.72 2.0 252 1012862
+1 98 1 1 1 1 263 25 43 0.20 0.20 9874 7485 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.60 16.80 1.2 7697 1871520
+1 82 1 1 30 40 467 38 27 2.60 3.20 64280 36998 0.00 0.00 0.00 0.00 0.00 2.00 3.40 201.40 205.00 1.2 2384 1796712
+1 89 1 1 3 1 2913 172 123 0.40 1.80 167743 57484 0.00 0.00 0.00 0.00 0.00 2.40 2.80 46.80 67.40 2.4 2696 1523133
+1 95 1 1 1 1 985 80 52 0.60 1.00 93811 26031 0.00 0.00 0.00 0.00 0.00 1.80 1.80 40.60 87.00 2.0 633 1032854
+1 94 1 1 1 0 1443 150 58 0.60 0.60 287782 10512 0.00 0.00 0.00 0.00 0.00 0.60 0.99 51.09 72.37 2.6 2508 1690583
+1 97 1 1 1 0 282 40 9 0.80 1.00 224466 3420 0.00 0.00 0.00 0.00 0.00 0.00 0.00 47.20 66.60 1.2 6458 1871590
+1 0 1 1 8 6 1152 138 96 0.40 0.40 16017 23243 2.40 2.79 2.79 0.00 1.20 3.59 3.79 35.33 141.72 181 93 7
+1 95 1 1 2 0 3428 228 124 0.40 0.60 292377 252714 0.00 0.00 0.00 0.00 0.00 0.40 0.40 30.20 54.40 3.8 2924 1333120
+1 97 1 1 0 0 197 12 13 0.20 0.20 815 11485 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 17.20 1.0 579 1732672
+1 92 1 1 21 29 524 76 37 1.20 0.60 389758 20490 0.00 0.00 0.00 0.00 0.00 7.80 15.40 70.20 117.00 1.8 7410 1868656
+1 87 1 1 32 28 1372 193 123 3.00 4.00 299105 65672 7.00 14.60 21.20 28.00 2.60 7.60 9.00 196.60 336.60 1.7 186 1015914
+1 88 1 1 5 0 1315 160 103 1.00 1.40 277782 69561 1.20 4.59 40.92 55.89 0.20 8.38 12.97 100.60 235.13 1.0 152 1086868
+1 87 1 1 129 45 2223 243 164 0.60 0.60 417425 122887 6.40 18.80 33.40 38.60 2.20 28.80 51.00 72.20 233.80 1.0 247 973678
+1 77 1 1 181 6 4923 286 254 3.39 3.19 211213 235251 0.00 0.00 0.00 0.00 0.00 10.38 13.57 136.93 234.13 3.4 2750 1636152
+1 79 1 1 19 29 4577 140 85 0.20 0.20 618181 101628 8.00 32.40 141.00 220.80 0.00 71.00 142.00 19.60 17.00 2.0 109 1760770
+1 91 1 1 2 0 511 80 17 1.80 1.80 452746 16232 0.00 0.00 0.00 0.00 0.00 1.00 1.40 145.31 135.33 1.8 7855 1865471
+1 84 1 1 11 1 3411 268 194 2.60 3.00 215542 105150 0.60 0.60 0.60 0.00 2.40 4.60 6.60 140.20 323.60 1.0 256 1069616
+1 67 1 1 52 19 7237 522 211 7.58 7.98 235939 45053 2.79 8.18 40.92 99.40 0.40 5.99 8.98 445.51 760.88 2.0 250 1108706
+1 75 1 1 8 2 2143 153 64 6.40 23.20 173702 24454 4.00 4.40 4.40 0.00 1.60 1.80 1.80 379.60 570.00 1.0 204 1036819
+1 97 1 1 2 1 611 38 25 0.20 0.20 65100 26381 0.00 0.00 0.00 0.00 0.00 8.82 17.64 15.63 17.23 1.2 6636 1856024
+1 91 1 1 2 0 788 91 73 1.40 1.60 171714 142275 0.00 0.00 0.00 0.00 0.00 4.20 8.20 70.80 102.80 2.0 6410 1848032
+1 91 1 1 2 0 549 49 64 0.60 4.20 116406 217353 0.00 0.00 0.00 0.00 0.00 8.80 17.60 27.80 30.40 1.4 7663 1879211
+1 84 1 1 85 98 6036 832 181 0.99 1.79 125868 91516 9.54 30.42 89.66 172.17 0.40 26.04 54.87 76.14 156.66 2.0 189 996110
+1 74 1 1 66 27 5275 461 324 6.96 9.15 373711 142975 12.33 39.36 64.61 133.60 3.58 19.28 27.24 423.46 643.14 2.2 227 1284924
+1 81 1 1 1 0 4275 278 192 0.60 0.60 398919 146602 17.80 31.60 37.20 26.80 9.80 10.60 14.60 57.20 135.80 2.2 158 990227
+1 88 1 1 8 2 2995 201 168 1.20 3.40 63991 34680 0.00 0.00 0.00 0.00 0.00 3.00 3.40 104.80 159.80 2.0 1964 969021
+1 81 1 1 4 1 638 112 46 2.00 2.00 326272 92143 0.00 0.00 0.00 0.00 0.00 3.19 5.79 193.21 160.68 1.8 8024 1864548
+1 90 1 1 4 1 4175 112 109 0.60 1.00 118854 48015 0.20 0.20 0.20 0.00 0.00 3.20 4.40 47.80 71.60 2.8 436 1016301
+1 88 1 1 9 0 3023 325 136 2.00 2.20 1136874 75778 0.00 0.00 0.00 0.00 0.00 1.40 1.80 153.20 223.60 1.7 404 1073918
+1 97 1 1 28 40 182 9 15 0.20 0.20 2630 52068 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 6879 1861804
+1 98 1 1 0 0 181 10 15 0.20 0.20 5478 46886 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13.03 16.83 1.0 7854 1874812
+1 89 1 1 20 24 1267 213 169 3.20 1.00 391564 267529 0.00 0.00 0.00 0.00 0.00 0.00 0.00 160.20 231.00 3.0 3657 1819818
+1 84 1 1 1 0 2666 245 150 0.20 0.20 91155 77414 0.00 0.00 0.00 0.00 0.00 69.74 73.95 23.45 36.47 1.5 497 1058100
+1 90 1 1 2 1 835 58 57 0.20 0.20 170094 31328 0.00 0.00 0.00 0.00 0.00 0.20 0.20 21.20 18.60 1.6 4092 1779424
+1 68 1 1 13 0 4052 436 372 12.00 19.00 223706 26754 2.20 2.40 3.40 3.40 0.00 9.00 12.80 477.20 784.40 1.8 169 1108344
+1 97 1 1 1 1 195 20 24 0.20 0.20 7034 10996 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7250 1865032
+1 86 1 1 5 1 2410 176 150 0.60 0.60 74357 96317 7.00 23.80 53.60 87.60 0.20 3.40 5.40 70.00 140.40 2.2 170 1065320
+1 0 1 1 11 5 3900 149 134 0.60 0.60 197230 30298 0.00 0.00 0.00 0.00 0.00 1.00 1.80 34.20 46.40 394 91 9
+1 0 1 1 3 1 1833 659 317 0.20 0.20 735962 516358 7.60 14.20 20.80 30.40 3.00 11.00 16.00 27.60 62.20 160 89 11
+1 83 1 1 4 1 2203 438 363 2.80 4.60 241984 93402 1.60 1.80 1.80 0.00 0.20 5.40 10.80 184.20 213.00 2.2 295 1696866
+1 73 1 1 47 59 3726 261 269 4.20 11.80 260103 486447 3.00 10.20 27.80 50.60 1.80 6.40 9.80 365.00 412.20 2.6 181 1373872
+1 59 1 1 15 0 3778 219 160 11.20 34.40 269997 75702 5.20 10.00 9.60 0.00 0.20 18.00 28.20 402.40 818.20 2.8 301 1092590
+1 97 1 1 2 1 1148 21 30 0.40 0.80 8675 6147 0.00 0.00 0.00 0.00 0.00 0.20 0.20 36.80 34.00 1.0 4918 1829331
+1 1 1 1 28 23 1303 370 177 1.00 3.60 553959 500924 0.00 0.00 0.00 0.00 0.00 14.80 20.80 37.40 130.40 818 89 10
+1 77 1 1 131 104 3404 382 217 4.80 7.20 420341 175225 0.00 0.00 0.00 0.00 0.00 6.80 9.40 369.40 606.20 1.0 1354 1006933
+1 60 1 1 48 1 4398 245 165 12.60 35.00 103091 51490 3.20 4.00 4.00 0.00 0.60 19.80 19.80 440.80 817.60 1.8 212 1095352
+1 89 1 1 7 5 2149 117 148 0.60 0.60 115000 25800 0.00 0.00 0.00 0.00 0.40 5.40 9.60 47.80 91.40 2.0 777 1047805
+1 95 1 1 1 1 1622 141 171 0.20 0.20 361119 115977 0.20 4.80 6.80 7.40 2.40 1.80 1.80 15.40 29.00 1.0 143 1046370
+1 70 1 1 13 10 3671 988 237 1.40 1.40 748238 88752 29.00 139.80 180.60 351.00 1.20 71.00 140.40 141.20 254.20 2.3 161 1132075
+1 92 1 1 15 13 918 119 100 1.80 2.20 55951 18908 0.00 0.00 0.00 0.00 0.00 1.20 1.40 114.80 195.60 1.0 1380 972787
+1 93 1 1 31 23 1443 71 49 1.80 1.80 69060 15791 0.00 0.00 0.00 0.00 0.00 2.00 2.00 132.40 185.80 2.6 4697 1670915
+1 55 1 1 22 2 5365 697 531 14.40 10.60 659595 29375 19.80 44.20 83.00 123.20 4.40 24.60 36.20 618.80 1075.40 1.0 175 972019
+1 98 1 1 0 0 199 19 17 0.20 0.20 32998 10272 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 7198 1867335
+1 84 1 1 15 12 3367 190 130 2.20 4.00 207205 137147 11.80 23.20 23.20 0.00 5.20 6.00 6.20 142.40 222.60 1.0 427 987661
+1 88 1 1 10 3 3689 152 80 1.40 1.80 116563 35809 0.00 0.00 0.00 0.00 0.00 2.20 3.00 107.80 150.80 3.4 1774 1541160
+1 81 1 1 2 0 3271 192 155 1.20 3.00 269971 81363 0.00 0.00 0.00 0.00 0.00 8.80 16.20 104.40 136.60 3.6 1298 1046453
+1 89 1 1 3 1 2610 139 176 0.80 0.80 131472 101837 0.00 0.00 0.00 0.00 0.00 0.60 0.80 67.80 84.80 2.6 623 1726461
+1 93 1 1 3 3 2431 143 152 0.60 2.00 95208 71983 0.00 0.00 0.00 0.00 0.00 0.80 0.80 35.80 66.20 2.6 1436 1725152
+1 85 1 1 2 0 348 26 21 1.80 1.80 68491 42274 0.00 0.00 0.00 0.00 0.00 2.40 4.41 158.32 147.70 1.6 2414 1823942
+1 66 1 1 87 84 5484 390 332 4.40 11.40 245476 153510 0.00 0.00 0.00 0.00 0.00 27.00 28.80 347.00 475.00 5.8 2591 1559867
+1 88 1 1 1 0 3071 169 134 1.00 2.60 271104 59046 0.00 0.00 0.00 0.00 0.00 1.80 2.00 55.20 175.80 1.0 583 1120162
+1 95 1 1 56 67 398 52 37 0.60 1.40 89176 19557 1.40 1.80 2.40 2.00 0.00 2.00 3.40 29.20 45.80 1.4 169 1754598
+1 88 1 1 4 0 538 86 56 2.00 2.00 65482 38684 0.00 0.00 0.00 0.00 0.00 0.20 0.20 76.60 132.20 1.8 1879 1771618
+1 87 1 1 71 102 3004 187 155 0.20 0.20 91873 70930 4.80 11.60 16.40 20.80 0.80 2.20 2.60 20.40 106.80 1.0 149 1013952
+1 98 1 1 2 1 170 10 22 0.20 0.20 7416 12453 0.00 0.00 0.00 0.00 0.00 0.00 0.00 22.40 17.40 1.2 7386 1874944
+1 95 1 1 1 0 763 81 39 1.60 7.00 53705 9774 0.00 0.00 0.00 0.00 0.00 2.60 4.80 58.80 85.20 1.6 2091 1763118
+1 77 1 1 41 55 5571 450 243 1.80 3.39 465244 398966 0.00 0.00 0.00 0.00 0.00 10.18 15.37 134.13 242.91 3.4 3373 1039950
+1 98 1 1 0 0 261 80 29 0.20 0.20 112146 103588 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 20.00 3.6 920 1742870
+1 91 1 1 12 10 315 43 27 0.40 0.40 22934 10444 0.00 0.00 0.00 0.00 0.00 1.20 1.20 35.20 46.60 1.6 436 1744928
+1 96 1 1 3 2 298 32 27 0.40 0.40 83707 45334 0.00 0.00 0.00 0.00 0.00 1.40 2.40 33.47 44.89 1.0 2861 1777805
+1 93 1 1 1 0 2404 101 107 0.60 2.20 30086 61136 0.00 0.00 0.00 0.00 0.00 0.60 1.00 51.40 67.00 1.3 691 1061008
+1 93 1 1 5 4 3011 128 157 0.20 0.20 9034 316545 17.60 20.60 20.60 0.00 15.80 0.20 0.20 15.40 35.00 2.2 276 1392184
+1 87 1 1 22 16 2205 196 100 1.20 1.20 303093 74007 0.00 0.00 0.00 0.00 1.40 6.19 9.58 94.41 197.80 3.2 530 1512482
+1 95 1 1 2 1 2239 103 70 0.20 0.20 140629 39509 0.00 0.00 0.00 0.00 0.00 1.00 1.00 15.60 41.40 2.6 2388 1406923
+1 95 1 1 13 2 1523 86 109 0.80 1.00 51962 8402 0.00 0.00 0.00 0.00 0.00 0.40 0.40 65.00 74.60 4.0 2118 1347805
+1 60 1 1 17 8 6310 1037 986 7.98 14.77 815153 733885 1.80 6.99 36.53 76.45 1.80 8.78 11.58 319.56 543.71 1.5 352 1091404
+1 73 1 1 18 2 4907 531 443 7.40 2.60 251588 29974 2.20 14.40 23.60 49.00 0.80 10.20 14.80 383.00 586.60 4.6 230 1330691
+1 97 1 1 0 0 201 16 25 0.20 0.20 18359 29253 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 1.2 2708 1771696
+1 74 1 1 7 1 3441 379 251 3.19 3.79 297313 175290 4.19 14.77 71.66 130.94 0.60 53.49 84.43 180.04 416.77 1.6 170 1009493
+1 87 1 1 16 2 2557 384 123 1.60 1.40 119766 29714 0.00 0.00 0.00 0.00 0.00 46.31 48.30 148.70 242.91 2.2 2370 1511946
+1 97 1 1 1 0 402 46 41 0.20 0.20 1567 10318 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.2 859 1720144
+1 92 1 1 7 6 439 156 63 0.40 0.40 210013 217302 0.00 0.00 0.00 0.00 0.00 5.40 10.80 35.60 35.20 3.4 1083 1754006
+1 78 1 1 252 267 4146 614 470 3.40 3.00 191240 107303 3.40 4.20 4.20 0.00 0.60 2.80 3.00 173.20 267.00 1.0 350 1089149
+1 72 1 1 34 1 3060 162 85 7.41 23.25 47325 22144 1.80 7.82 23.25 42.48 0.80 8.82 14.03 326.05 533.07 3.4 193 1113364
+1 88 1 1 14 13 2318 142 97 1.80 2.40 155180 86805 6.20 27.00 59.80 123.80 1.60 8.80 15.40 110.40 206.80 1.0 182 1050565
+1 95 1 1 1 0 937 145 127 0.40 0.20 429564 99723 0.00 0.00 0.00 0.00 0.00 0.20 0.20 33.60 79.60 1.7 582 1072651
+1 86 1 1 3 0 2193 156 112 1.60 1.40 241870 51689 3.80 4.60 4.60 0.00 2.00 11.00 12.60 84.80 178.80 2.6 319 1056070
+1 67 1 1 30 1 5504 400 267 8.57 18.92 894305 33041 1.39 1.59 1.59 0.00 0.00 25.50 35.06 477.09 760.16 3.2 204 1076897
+1 99 1 1 1 1 173 8 10 0.20 0.20 7117 9060 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7654 1879192
+1 96 1 1 1 1 792 46 36 0.20 0.20 8631 9915 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 1.2 7660 1871155
+1 63 1 1 5 0 7763 1587 1532 5.00 1.40 1348324 1199088 0.00 0.00 0.00 0.00 18.80 6.20 10.20 241.00 369.00 1.0 663 1093842
+1 99 1 1 1 1 194 12 24 0.20 0.20 10678 11991 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7385 1874944
+1 93 1 1 22 13 1681 146 129 2.00 0.80 70811 49799 2.60 6.60 7.20 1.80 4.40 1.20 1.60 105.20 155.40 2.4 180 1710835
+1 98 1 1 0 0 158 8 17 0.20 0.20 423 10770 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6439 1871280
+1 92 1 1 17 24 1291 56 95 0.60 0.60 48614 414968 0.00 0.00 0.00 0.00 0.00 0.00 0.00 57.29 62.28 1.4 8218 1859254
+1 91 1 1 8 6 2848 163 146 0.40 1.80 21253 84127 0.00 0.00 0.00 0.00 0.00 0.20 0.20 20.80 30.40 2.8 647 1645072
+1 86 1 1 13 11 1872 141 66 2.20 6.01 71339 39311 1.40 13.43 94.59 151.10 1.00 3.01 3.41 246.69 400.60 1.3 306 1066564
+1 79 1 1 24 3 4316 371 301 5.20 3.80 140241 105211 0.00 0.00 0.00 0.00 0.00 0.60 0.80 296.60 441.80 4.2 3744 1549013
+1 0 1 1 1 0 1086 222 94 0.20 0.20 254286 276011 5.20 11.00 15.20 10.00 0.00 2.40 2.40 22.00 38.40 127 92 8
+1 79 1 1 85 42 1373 97 89 8.00 8.20 126563 110550 0.00 0.00 0.00 0.00 0.00 10.40 18.80 382.80 597.40 2.4 6206 1835318
+1 62 1 1 52 1 2405 203 131 13.20 37.80 263363 43204 1.00 1.00 1.00 0.00 0.20 7.20 7.60 463.20 873.60 2.8 316 1096304
+1 87 1 1 18 4 3962 614 560 0.40 0.80 699997 400422 3.00 15.00 36.60 87.00 1.60 12.60 27.40 37.80 78.40 3.2 144 1396888
+1 97 1 1 0 0 1106 66 98 0.00 0.00 5108 25493 0.00 0.00 0.00 0.00 0.00 0.40 0.40 2.40 4.00 1.5 464 1045976
+1 73 1 1 43 2 5035 290 141 0.40 0.40 498675 96693 31.00 92.80 176.40 361.00 2.00 72.20 121.00 98.20 258.20 4.3 124 1007525
+1 94 1 1 1 1 1158 50 51 0.20 0.20 8656 22441 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.4 7709 1871584
+1 69 1 1 7 0 4182 542 268 5.20 3.00 2007279 22593 8.40 100.80 302.60 556.00 0.60 5.00 8.20 272.60 802.20 4.0 118 1373266
+1 78 1 1 30 3 4058 333 249 4.80 2.80 291987 34191 1.20 6.20 12.20 23.40 11.00 7.20 21.60 251.80 437.80 7.4 413 1293494
+1 84 1 1 40 50 2932 223 102 1.40 3.20 173324 43284 0.00 0.00 0.00 0.00 0.00 4.20 4.80 122.80 247.80 1.0 477 1065285
+1 85 1 1 6 2 2501 155 229 2.00 3.20 177296 56976 0.00 0.00 0.00 0.00 1.80 6.20 9.20 354.40 302.80 1.3 1089 1052451
+1 93 1 1 2 0 2622 292 215 0.40 0.40 129694 96197 0.00 0.00 0.00 0.00 0.20 0.00 0.00 34.80 50.00 2.0 413 1069749
+1 83 1 1 5 0 2619 455 348 5.40 1.40 328916 131103 0.00 0.00 0.00 0.00 0.00 0.00 0.00 252.20 361.60 3.2 1964 1759706
+1 94 1 1 2 1 696 64 47 0.80 0.80 58463 39507 0.00 0.00 0.00 0.00 0.00 6.40 12.60 57.00 62.40 1.2 8575 1840258
+1 91 1 1 22 32 3778 153 149 0.40 0.60 14108 50224 1.79 1.99 1.99 0.00 0.20 3.78 3.98 33.27 107.77 1.0 287 1011205
+1 90 1 1 1 1 1609 92 73 0.60 2.20 111653 16050 1.00 1.00 1.00 0.00 5.20 1.00 1.00 55.20 152.80 1.0 170 1025342
+1 94 1 1 2 1 786 70 43 0.40 0.40 3025 8770 0.00 0.00 0.00 0.00 0.00 0.20 0.20 28.54 42.12 1.0 1231 1742181
+1 97 1 1 11 3 401 33 34 0.40 0.40 53412 5808 0.00 0.00 0.00 0.00 0.00 0.40 0.60 33.13 39.92 1.6 5628 1857780
+1 88 1 1 0 0 4182 245 145 0.20 0.20 24077 22389 0.80 1.20 1.40 2.80 0.20 10.40 12.20 15.40 36.40 1.0 152 1137411
+1 90 1 1 5 0 2155 251 237 1.80 0.60 230371 192375 0.00 0.00 0.00 0.00 0.00 0.00 0.00 92.20 129.40 2.4 4980 1671573
+1 91 1 1 6 1 2791 99 112 0.80 1.00 29288 89337 0.20 0.20 0.20 0.00 0.00 1.60 1.60 93.00 75.40 2.4 401 1083798
+1 97 1 1 1 0 386 77 60 0.20 0.20 4932 10494 0.00 0.00 0.00 0.00 0.00 7.20 7.20 15.60 28.00 2.0 6282 1722634
+1 72 1 1 8 0 3154 148 89 6.81 20.44 128585 37322 0.00 0.00 0.00 0.00 8.02 1.00 1.00 253.51 510.42 3.4 465 1083872
+1 96 1 1 2 1 187 13 21 0.20 0.20 11954 7051 0.00 0.00 0.00 0.00 0.00 1.60 3.20 20.00 17.20 1.0 3585 1848274
+1 65 1 1 15 1 3625 268 130 11.20 32.40 140512 48992 0.20 0.20 0.20 0.00 0.20 6.40 7.20 373.20 683.40 1.0 379 1086331
+1 93 1 1 2 1 3631 144 96 0.20 0.20 29995 79122 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 19.60 2.6 3163 1656826
+1 0 1 1 3 0 1643 171 153 0.80 2.20 20529 26776 0.00 0.00 0.00 0.00 0.20 1.60 2.40 66.60 105.00 537 91 9
+1 54 1 1 47 48 4163 299 147 17.03 14.23 177185 13850 0.00 0.00 0.00 0.00 0.00 2.00 3.01 745.29 1324.65 5.6 1120 1775705
+1 82 1 1 17 8 2515 293 132 2.20 2.20 513694 197703 0.80 0.80 0.80 0.00 1.00 7.39 9.18 134.33 257.49 1.2 441 1017961
+1 85 1 1 3 0 3579 223 216 2.80 1.00 75101 141958 0.60 1.60 0.80 0.00 0.60 1.20 1.20 144.60 250.80 5.6 443 1015458
+1 74 1 1 19 12 7284 506 321 5.39 6.19 386171 72448 2.40 4.19 5.39 4.39 0.80 20.36 21.76 235.33 461.08 2.8 439 998836
+1 91 1 1 4 2 3492 130 102 1.40 2.40 101255 28790 0.00 0.00 0.00 0.00 0.00 2.60 3.40 120.20 163.60 2.6 709 990150
+1 89 1 1 8 2 3211 342 290 0.40 0.40 182187 136185 4.19 21.56 53.89 106.39 0.40 39.32 48.70 28.94 134.73 1.5 128 1044367
+1 90 1 1 16 4 2592 106 73 2.58 11.73 63542 17476 2.19 2.78 2.39 0.00 1.19 3.18 3.78 239.36 205.57 4.8 267 1536720
+1 86 1 1 2 0 3348 222 148 0.20 0.20 316936 441152 0.00 0.00 0.00 0.00 0.00 2.20 2.59 21.96 60.88 5.4 623 1006553
+1 89 1 1 7 5 2188 147 86 1.80 1.40 25136 25183 0.00 0.00 0.00 0.00 0.00 1.40 1.40 85.00 139.80 1.0 2919 1051027
+1 97 1 1 0 0 374 73 45 0.20 0.20 176823 35778 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.20 3.2 948 1716074
+1 97 1 1 0 0 485 235 67 0.20 0.20 270912 270042 0.00 0.00 0.00 0.00 0.20 0.40 0.40 15.60 18.80 2.4 1254 1745602
+1 86 1 1 64 82 5008 576 140 0.40 0.40 286004 42582 1.80 2.59 2.40 0.00 4.19 2.59 13.17 37.92 147.31 2.2 447 1001501
+1 87 1 1 11 6 1551 85 79 1.00 2.00 19640 58019 9.40 16.60 16.60 0.00 0.80 19.40 37.40 129.60 215.00 1.7 302 1052301
+1 95 1 1 1 0 1914 55 57 0.20 0.20 9833 23860 0.60 0.60 0.60 0.00 0.00 4.60 4.60 18.80 45.00 1.7 408 1116526
+1 90 1 1 0 0 3416 234 120 0.60 0.80 114455 25255 0.80 0.80 0.80 0.00 1.80 1.40 1.40 37.60 57.40 4.0 319 1118784
+1 78 1 1 16 1 2142 215 147 4.60 9.80 256517 58279 0.00 0.00 0.00 0.00 0.00 44.00 54.80 248.00 443.00 2.5 554 1040491
+1 85 1 1 2 0 404 32 30 2.20 2.99 71109 38940 0.00 0.00 0.00 0.00 0.00 3.59 5.39 181.44 181.64 1.6 2436 1816624
+1 88 1 1 5 2 3562 280 207 0.60 0.60 246876 68734 0.00 0.00 0.00 0.00 0.00 39.60 40.00 58.80 206.20 1.0 492 995621
+1 92 1 1 3 1 630 84 14 2.20 10.20 513593 6359 0.00 0.00 0.00 0.00 0.00 0.00 0.00 142.60 174.60 2.2 3714 1821429
+1 95 1 1 2 0 834 70 60 0.40 1.80 20692 22085 0.00 0.00 0.00 0.00 0.00 2.00 2.40 45.09 58.12 1.2 1082 1018774
+1 93 1 1 3 2 1889 52 69 0.60 1.40 19769 26606 0.00 0.00 0.00 0.00 0.00 3.20 5.40 53.80 72.20 2.0 705 1538586
+1 92 1 1 5 2 1393 173 142 1.60 0.60 243241 47119 0.00 0.00 0.00 0.00 0.00 0.60 0.60 91.62 135.13 1.0 2331 1008155
+1 80 1 1 4 0 3437 274 158 3.40 9.00 368553 81473 0.00 0.00 0.00 0.00 0.00 18.80 33.00 216.20 329.60 1.7 793 1096205
+1 92 1 1 15 11 1802 198 87 1.20 1.40 476981 127966 1.00 1.20 1.20 0.00 0.40 4.20 4.40 71.60 150.40 3.2 335 1326221
+1 72 1 1 32 0 6059 1491 433 5.40 3.60 873154 797327 7.60 118.00 246.20 1051.20 0.20 26.00 177.20 245.60 435.00 6.4 113 1320912
+1 84 1 1 3 1 4798 335 171 0.40 1.80 150755 80593 4.19 7.19 7.98 2.20 0.40 13.57 24.35 35.53 82.24 2.0 168 1069206
+1 92 1 1 1 0 481 101 96 0.20 0.20 162345 131193 0.60 1.20 1.00 0.00 15.20 0.20 0.20 21.60 35.40 3.8 403 1711790
+1 89 1 1 1 0 1732 262 146 0.80 1.00 88635 22567 0.00 0.00 0.00 0.00 0.00 7.41 12.42 62.73 84.97 1.0 408 1121663
+1 95 1 1 1 1 1243 35 59 0.20 0.20 6509 61181 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 16.80 1.0 8312 1839178
+1 87 1 1 12 10 2545 246 139 0.20 0.20 102216 34393 0.00 0.00 0.00 0.00 0.00 9.80 10.00 17.60 112.60 3.2 9125 1373510
+1 91 1 1 2 0 339 32 15 1.80 1.80 46087 12238 0.00 0.00 0.00 0.00 0.00 1.20 1.20 157.68 138.72 1.6 6785 1851732
+1 95 1 1 2 1 308 24 32 0.80 0.80 189492 30085 0.00 0.00 0.00 0.00 0.00 2.61 5.01 57.31 121.04 1.2 9327 1873303
+1 90 1 1 52 62 976 76 98 0.20 0.20 11377 84271 0.00 0.00 0.00 0.00 0.00 54.60 54.80 16.40 96.00 1.0 1356 1069018
+1 87 1 1 1 0 4396 223 165 0.60 0.60 113544 28272 0.00 0.00 0.00 0.00 0.00 3.61 10.82 54.91 68.54 1.8 2066 1101103
+1 96 1 1 2 0 704 111 56 0.20 0.20 4696 9190 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 5847 1720984
+1 0 1 1 73 83 4405 540 461 8.42 2.40 272948 43129 6.41 8.82 8.62 0.00 1.40 6.21 11.22 405.81 612.22 430 68 32
+1 91 1 1 12 10 3265 224 102 0.20 0.20 11191 68439 0.00 0.00 0.00 0.00 0.00 4.40 4.40 16.00 32.00 2.4 849 1642790
+1 54 1 1 28 3 3425 146 84 15.00 38.80 363364 29405 2.80 3.40 2.80 0.00 1.40 15.20 15.20 566.40 1036.20 1.2 235 1082774
+1 70 1 1 11 0 4449 612 528 10.00 3.00 290561 19801 6.20 9.40 30.20 65.40 0.20 0.40 0.40 479.00 815.40 1.5 183 1015698
+1 0 1 1 60 78 862 387 131 0.20 0.20 626392 639838 1.20 1.40 1.40 0.00 0.00 0.00 0.00 15.60 34.40 306 94 6
+1 87 1 1 1 0 894 56 70 1.40 1.60 33141 95468 0.00 0.00 0.00 0.00 0.00 0.00 0.00 68.80 100.00 2.2 4345 1782467
+1 78 1 1 25 3 3562 375 319 6.40 2.20 176802 11654 0.00 0.00 0.00 0.00 0.00 16.60 99.80 318.40 503.20 4.4 2913 1407795
+1 78 1 1 68 61 2899 279 179 4.39 4.79 327686 125390 0.00 0.00 0.00 0.00 0.00 10.78 16.37 290.02 499.80 2.0 829 971586
+1 96 1 1 0 0 1376 38 67 0.20 0.20 4051 31919 0.80 1.00 1.00 0.00 0.60 23.40 23.40 15.60 74.80 1.2 262 1750968
+1 83 1 1 5 0 3352 357 264 0.80 0.99 601754 121329 0.00 0.00 0.00 0.00 0.00 69.58 126.84 51.09 83.90 3.4 2822 1339054
+1 95 1 1 1 1 1615 91 70 0.40 1.80 43622 10744 0.00 0.00 0.00 0.00 0.00 4.60 9.20 22.80 33.20 2.4 3345 1709805
+1 60 1 1 93 80 3783 826 557 12.18 5.19 590467 225000 9.38 38.32 112.57 219.36 0.20 10.58 13.77 474.45 940.92 3.6 193 1043098
+1 95 1 1 1 1 868 75 73 0.20 0.20 60588 141166 0.00 0.00 0.00 0.00 0.00 3.39 3.39 15.57 17.76 1.6 7222 1861185
+1 89 1 1 3 1 2223 158 107 0.40 0.40 53000 46297 1.00 1.40 1.20 0.00 0.20 14.57 15.17 32.73 120.76 2.6 271 1083947
+1 86 1 1 2 0 574 95 46 1.59 1.59 50802 21976 0.00 0.00 0.00 0.00 0.00 2.39 3.59 141.43 134.86 2.2 896 1784027
+1 96 1 1 1 0 264 20 33 1.20 0.80 42849 13858 0.00 0.00 0.00 0.00 0.00 0.20 0.40 59.20 68.60 1.2 7047 1844979
+1 87 1 1 2 1 2826 208 120 0.80 0.80 449006 120906 16.80 22.40 22.40 0.00 14.60 15.60 19.60 59.00 153.40 2.2 237 989936
+1 97 1 1 13 18 220 24 21 0.20 0.20 56814 20417 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 1.6 9290 1869141
+1 97 1 1 2 1 282 36 21 0.20 0.20 189633 10196 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.4 7716 1882168
+1 98 1 1 0 0 186 21 22 0.20 0.20 481 4390 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.0 7360 1861421
+1 75 1 1 17 2 4486 522 421 6.37 3.98 271927 89228 0.80 0.80 0.80 0.00 0.40 8.17 8.76 301.79 510.96 1.0 346 1085103
+1 92 1 1 19 17 1792 111 152 1.00 1.00 281818 65470 0.00 0.00 0.00 0.00 0.00 12.02 19.64 86.77 133.87 1.5 1183 1007947
+1 83 1 1 7 6 1659 203 145 1.00 1.00 446789 242518 8.22 15.83 10.22 0.00 0.40 2.40 2.40 339.08 129.86 2.0 289 1116319
+1 93 1 1 1 0 2918 141 136 0.20 0.20 5032 66053 0.00 0.00 0.00 0.00 0.00 6.40 9.60 16.00 26.00 1.0 1771 1112643
+1 87 1 1 3 1 1305 118 37 2.00 2.00 267231 81920 0.00 0.00 0.00 0.00 0.00 1.80 2.60 187.40 165.80 1.8 7986 1868704
+1 96 1 1 2 1 1117 107 68 0.40 0.20 36318 29286 0.00 0.00 0.00 0.00 0.00 0.00 0.00 29.40 51.60 1.0 663 1069317
+1 78 1 1 17 13 1851 156 92 4.41 13.23 396014 24854 4.01 16.23 91.58 160.12 1.80 53.31 99.80 160.52 345.49 1.0 134 1108471
+1 98 1 1 0 0 189 15 12 0.20 0.20 33139 11228 0.00 0.00 0.00 0.00 0.20 0.80 1.40 15.77 22.75 1.0 591 1729309
+1 93 1 1 2 1 1574 123 92 0.80 1.20 230531 77766 0.00 0.00 0.00 0.00 0.40 5.20 10.00 64.40 84.80 2.2 327 1533171
+1 68 1 1 77 97 4424 643 459 6.80 2.20 267250 154996 0.00 0.00 0.00 0.00 0.00 27.80 35.80 340.60 575.00 1.0 931 996768
+1 91 1 1 4 0 1267 174 156 3.20 1.00 86918 10248 0.00 0.00 0.00 0.00 0.00 0.00 0.00 149.00 220.00 2.0 7374 1865027
+1 66 1 1 20 11 5400 342 163 8.20 22.60 51814 28911 1.20 3.20 3.20 0.00 1.60 4.20 5.00 287.20 586.60 1.0 378 1086531
+1 93 1 1 5 4 1506 166 98 0.60 1.60 94896 16612 0.40 0.40 6.00 14.00 0.80 0.20 0.20 43.40 75.00 1.7 217 1099789
+1 92 1 1 2 0 1248 110 39 1.20 4.01 95965 8789 0.40 5.01 12.83 25.45 3.61 6.01 6.21 71.74 104.81 1.2 133 1758248
+1 90 1 1 3 0 2876 116 116 1.40 2.00 106263 11368 0.00 0.00 0.00 0.00 0.00 9.58 16.37 125.75 159.68 3.4 4212 1715684
+1 69 1 1 12 0 3360 515 375 8.00 2.20 966822 60723 0.00 0.00 0.00 0.00 0.00 4.20 7.80 381.80 562.20 3.6 3182 1769629
+1 95 1 1 2 0 388 40 100 0.60 0.40 57023 66925 1.40 1.80 1.80 0.00 0.20 2.00 12.20 32.00 41.00 1.2 251 1743899
+1 86 1 1 10 5 4239 479 98 1.00 1.40 367261 238007 0.00 0.00 0.00 0.00 0.00 1.00 1.00 93.40 124.20 4.0 3306 1345357
+1 89 1 1 3 1 393 43 17 2.00 2.00 94596 20335 0.00 0.00 0.00 0.00 0.00 3.19 4.99 188.82 160.28 1.2 11813 1883888
+1 86 1 1 23 14 2223 301 157 2.20 2.20 198453 60717 0.00 0.00 0.00 0.00 0.20 1.40 1.40 252.80 325.20 2.8 670 1528350
+1 72 1 1 44 37 3700 488 295 3.20 4.40 233145 128026 13.20 30.80 47.40 58.40 1.00 22.60 32.20 244.60 407.20 1.0 195 945811
+1 75 1 1 22 14 1856 110 92 7.00 19.40 99492 27575 2.40 2.60 2.60 0.00 0.80 14.20 25.40 310.00 503.40 5.2 307 1106643
+1 89 1 1 14 2 1965 256 109 1.39 1.79 338545 17826 0.20 0.20 0.20 0.00 3.97 7.54 11.71 99.60 189.68 2.8 305 996413
+1 89 1 1 2 0 5105 269 190 0.60 0.60 25145 68203 0.00 0.00 0.00 0.00 0.20 0.20 0.20 26.55 53.69 2.7 501 1074799
+1 91 1 1 0 0 414 36 44 0.20 0.20 83481 46672 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 17.64 1.4 2107 1772008
+1 94 1 1 1 0 2498 135 77 0.40 0.40 45680 30423 0.00 0.00 0.00 0.00 0.00 0.00 0.00 27.20 38.40 1.2 1903 1752755
+1 82 1 1 65 60 2116 279 191 4.59 2.79 138385 54700 0.00 0.00 0.00 0.00 0.20 8.18 11.78 239.92 384.43 2.0 384 963949
+1 85 1 1 7 0 1757 187 192 4.20 2.80 111253 29838 0.00 0.00 0.00 0.00 4.40 1.00 1.20 190.00 296.80 2.0 810 1061723
+1 81 1 1 1 0 3247 303 202 0.40 0.60 645033 306096 0.60 0.80 10.00 20.00 0.40 9.00 9.00 49.20 108.60 2.8 231 1015854
+1 77 1 1 21 13 6610 260 191 1.40 5.59 256986 72968 7.78 13.97 24.55 31.34 7.98 33.33 49.10 143.11 222.55 1.2 243 1003382
+1 95 1 1 1 0 1446 75 46 0.60 0.60 11106 72845 0.00 0.00 0.00 0.00 0.00 6.80 6.80 29.00 48.40 2.0 4818 1731490
+1 75 1 1 50 1 3760 512 424 5.40 5.00 309000 188453 8.40 14.00 21.00 19.00 1.60 53.60 56.40 218.80 458.40 1.3 217 1085466
+1 92 1 1 30 36 535 198 59 0.20 0.20 485971 188544 0.00 0.00 0.00 0.00 0.00 13.00 13.00 15.60 17.00 2.6 7270 1836112
+1 82 1 1 11 0 3572 517 358 1.80 5.20 89311 184532 3.00 3.40 3.40 0.00 0.20 6.60 8.40 97.40 209.60 4.2 250 1314581
+1 93 1 1 3 1 1670 70 64 0.80 1.20 3865 6900 0.00 0.00 0.00 0.00 0.00 0.20 0.40 66.67 74.65 1.2 1361 1743170
+1 1 1 1 131 46 1726 300 282 1.00 1.20 297680 286051 0.00 0.00 0.00 0.00 0.20 8.22 12.42 85.57 143.69 525 88 12
+1 84 1 1 42 51 3543 214 172 1.00 4.20 254349 115405 17.40 22.40 22.20 0.00 12.40 3.60 21.00 90.00 205.00 3.2 386 1386395
+1 95 1 1 1 1 1063 103 69 0.20 0.20 28393 153133 0.00 0.00 0.00 0.00 0.00 0.60 0.60 15.60 18.00 1.4 8360 1864864
+1 72 1 1 5 2 2735 332 139 2.00 2.20 898179 25561 8.18 87.03 171.26 477.64 0.40 83.63 153.89 144.11 240.92 3.5 143 1126076
+1 88 1 1 15 14 4292 252 146 0.80 0.80 222526 76937 6.79 18.76 40.72 101.00 1.00 10.78 15.37 45.31 116.97 1.7 128 995545
+1 67 1 1 25 1 4418 301 153 5.80 15.00 315550 53801 4.40 31.60 93.60 288.20 3.20 40.80 74.80 225.00 425.60 3.4 123 1100149
+1 88 1 1 4 0 1734 220 202 4.20 1.20 112961 70392 0.00 0.00 0.00 0.00 0.00 0.00 0.00 201.20 287.20 2.2 7463 1863821
+1 76 1 1 6 0 1705 332 189 5.60 14.20 700086 111956 0.00 0.00 0.00 0.00 0.00 9.40 17.80 437.20 386.20 4.6 2050 1724243
+1 80 1 1 9 0 3524 392 321 7.20 3.00 314063 8169 0.00 0.00 0.00 0.00 0.00 0.00 0.00 360.60 523.80 2.2 6596 1871922
+1 91 1 1 0 0 2967 185 126 0.40 0.60 19246 50729 0.80 1.40 1.20 0.00 0.20 2.00 2.00 31.20 42.40 1.4 244 1127214
+1 64 1 1 7 0 3853 311 301 5.40 12.80 549542 509948 21.80 53.40 113.20 234.20 6.60 56.20 100.40 302.20 482.80 5.4 192 997653
+1 71 1 1 9 0 3044 278 264 8.02 18.64 330420 127851 5.81 19.64 50.50 69.54 1.80 24.85 40.48 310.82 603.41 1.7 123 1104948
+1 0 1 1 24 1 2888 503 325 6.20 3.20 189565 39458 0.40 0.40 0.40 0.00 0.40 3.40 4.40 268.40 504.40 337 78 22
+1 90 1 1 4 0 1805 151 143 2.00 0.60 102862 78396 0.00 0.00 0.00 0.00 0.00 0.60 1.20 98.80 138.20 2.4 4755 1726893
+1 96 1 1 1 0 436 45 31 0.40 0.40 34266 8778 0.00 0.00 0.00 0.00 0.00 0.00 0.00 32.40 40.60 2.0 835 1722474
+1 93 1 1 4 2 1686 312 205 0.40 0.60 126309 104451 0.00 0.00 0.00 0.00 0.80 0.60 0.80 37.40 97.00 2.4 495 1531704
+1 87 1 1 2 0 1174 231 170 1.40 1.80 427110 115077 0.00 0.00 0.00 0.00 0.00 8.80 17.20 109.00 139.80 2.2 2524 1730254
+1 89 1 1 38 49 4075 180 145 0.80 1.20 49728 143178 3.20 3.20 3.20 0.00 1.20 0.00 0.00 70.80 77.40 2.8 226 1628595
+1 90 1 1 19 11 3234 361 269 0.40 1.80 156016 62817 11.80 17.00 18.00 5.40 9.20 3.60 4.00 37.20 95.00 4.4 155 1396226
+1 90 1 1 3 2 1421 139 99 0.60 0.60 108524 50858 2.79 21.56 46.91 103.79 1.00 42.32 50.70 49.10 84.23 2.0 140 1054172
+1 88 1 1 49 60 3182 298 66 1.40 1.40 162976 97779 9.20 25.20 72.00 136.20 1.80 2.00 4.20 92.60 204.80 3.6 157 1621664
+1 86 1 1 18 14 5708 256 157 0.60 0.60 31628 26477 2.80 5.20 12.00 13.20 0.00 3.60 4.40 33.00 67.00 5.2 143 1521075
+1 98 1 1 2 1 173 11 16 0.20 0.20 7778 11304 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7916 1880864
+1 94 1 1 2 1 1121 47 59 0.60 0.60 36839 68383 0.00 0.00 0.00 0.00 0.00 1.40 2.60 30.00 41.60 2.0 4682 1725306
+1 94 1 1 1 1 1437 108 68 0.40 0.40 5340 15274 0.00 0.00 0.00 0.00 0.00 1.40 1.60 30.00 43.40 3.5 1162 1133342
+1 97 1 1 1 0 156 9 13 0.20 0.20 1607 19294 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.20 17.80 1.4 8844 1872466
+1 93 1 1 5 2 385 41 23 1.80 1.80 132680 9449 0.00 0.00 0.00 0.00 0.00 1.40 1.40 164.60 149.60 2.0 4657 1847570
+1 91 1 1 32 45 1599 125 86 0.20 0.20 364792 35528 6.80 8.00 8.00 0.00 7.20 6.40 7.00 20.20 115.00 1.0 272 1031914
+1 80 1 1 14 13 4015 329 178 1.00 1.59 114359 77960 14.74 32.07 56.37 66.14 8.96 12.15 16.14 205.78 275.50 4.8 143 1005305
+1 85 1 1 3 0 4505 269 154 0.60 0.60 144699 54580 0.00 0.00 0.00 0.00 0.40 4.40 7.80 52.00 72.00 1.0 478 1128262
+1 98 1 1 2 1 206 32 14 0.20 0.20 197577 13197 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 18.20 1.2 7202 1874062
+1 86 1 1 2 1 2472 208 137 2.40 5.80 254546 21373 3.60 17.20 47.20 158.20 0.80 2.60 2.80 155.00 294.00 2.0 193 1030011
+1 95 1 1 47 63 1921 87 73 0.20 0.20 176786 67927 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 19.80 2.4 1778 1649347
+1 59 1 1 54 9 3984 164 100 10.80 20.80 391435 512821 65.20 135.80 140.00 83.80 4.20 15.00 16.80 473.20 836.60 6.2 166 1525998
+1 90 1 1 8 1 729 97 74 1.80 0.60 131107 4970 0.00 0.00 0.00 0.00 0.00 3.40 3.80 91.20 125.40 1.6 609 1742051
+1 94 1 1 1 0 2953 198 125 0.20 0.20 7411 56754 0.00 0.00 0.00 0.00 0.00 0.80 0.80 15.60 22.40 2.0 551 1628800
+1 83 1 1 26 14 3761 760 411 2.00 2.40 67723 21589 0.00 0.00 0.00 0.00 0.00 0.40 0.40 143.60 176.40 3.8 526 1538782
+1 95 1 1 2 1 1185 70 63 0.40 1.80 23241 32553 0.00 0.00 0.00 0.00 0.80 0.40 0.60 33.20 43.80 2.0 377 1533190
+1 98 1 1 1 1 229 22 32 0.20 0.20 10948 19298 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.20 16.80 1.2 7291 1865672
+1 95 1 1 1 0 878 93 88 0.20 0.20 16472 70033 0.00 0.00 0.00 0.00 0.40 3.01 9.82 28.06 49.30 2.0 587 1063984
+1 92 1 1 0 0 391 36 32 0.20 0.20 10449 14088 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.2 1004 1758116
+1 88 1 1 1 0 742 46 43 0.40 2.00 1037 62760 0.00 0.00 0.00 0.00 0.00 0.40 0.40 24.80 29.60 3.0 491 1714830
+1 97 1 1 3 1 161 12 11 0.20 0.20 3642 7448 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 17.00 1.0 7228 1847149
+1 65 1 1 45 0 2328 191 114 12.20 34.80 373543 45577 4.80 28.40 52.40 91.00 1.40 49.20 51.60 400.80 856.00 3.4 147 1092866
+1 95 1 1 1 0 1192 58 66 0.20 0.20 7578 57791 0.00 0.00 0.00 0.00 0.00 1.00 1.00 16.60 22.20 2.0 688 1062640
+1 89 1 1 17 7 2341 230 141 1.60 3.80 339842 27019 0.00 0.00 0.00 0.00 1.20 4.20 5.20 103.20 236.00 2.2 718 990224
+1 87 1 1 25 36 1039 112 45 0.80 1.20 243641 36586 0.00 0.00 0.00 0.00 0.00 1.80 3.20 66.80 108.40 2.0 581 1749042
+1 90 1 1 4 2 2727 155 103 0.80 2.00 188454 71604 0.00 0.00 0.00 0.00 0.00 8.00 8.00 56.80 141.80 1.5 1002 1055334
+1 59 1 1 58 62 6565 679 551 11.20 4.60 358824 52641 0.00 0.00 0.00 0.00 0.20 1.20 1.80 531.20 965.00 1.8 855 1054050
+1 86 1 1 1 0 1547 115 86 1.20 3.40 53184 91654 0.00 0.00 0.00 0.00 0.00 8.20 12.60 88.20 127.00 3.6 458 1094496
+1 76 1 1 37 44 1988 168 157 6.61 19.44 14923 63751 4.21 4.81 4.81 0.00 0.60 7.21 8.22 225.65 422.85 2.4 155 1104782
+1 78 1 1 7 0 3928 589 571 4.80 3.80 355147 244977 2.20 2.40 2.40 0.00 0.20 3.00 3.00 274.20 465.80 3.2 270 1080061
+1 83 1 1 97 5 1653 193 84 0.40 0.60 994550 41011 13.60 26.60 56.80 72.60 6.80 36.80 44.00 28.20 125.40 1.5 195 981982
+1 97 1 1 7 3 759 61 58 0.80 1.40 24109 21947 0.00 0.00 0.00 0.00 0.00 1.40 1.40 55.00 82.40 2.4 5673 1683613
+1 90 1 1 1 0 2109 140 132 0.60 2.00 170044 41933 0.00 0.00 0.00 0.00 0.00 0.20 0.20 42.40 66.40 4.2 2411 1042787
+1 80 1 1 44 30 2919 478 381 8.00 2.20 353632 133883 0.00 0.00 0.00 0.00 0.00 0.20 0.20 374.00 537.00 2.6 5519 1830067
+1 96 1 1 1 0 789 116 122 0.20 0.20 5722 23842 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.80 128.40 1.5 1885 1075006
+1 96 1 1 12 3 563 27 23 0.80 0.80 20028 13118 0.00 0.00 0.00 0.00 0.00 0.20 0.20 58.68 75.05 1.0 6412 1846159
+1 88 1 1 2 1 1429 123 63 0.20 0.20 154718 45755 2.60 14.20 30.80 134.20 0.20 65.00 76.60 17.40 35.80 1.0 171 1056115
+1 91 1 1 29 43 985 111 87 1.20 1.20 277901 23626 1.00 1.20 1.20 0.00 1.60 43.60 43.80 85.80 188.80 3.0 298 1054046
+1 68 1 1 10 1 4616 625 494 8.40 3.40 402372 48289 5.80 8.80 8.80 0.00 0.80 1.20 1.20 440.00 699.20 1.3 219 997088
+1 94 1 1 0 0 1169 61 49 0.20 0.20 1730 19355 0.20 0.20 0.20 0.00 0.20 0.80 0.80 14.60 20.80 4.6 260 1104173
+1 63 1 1 46 1 4004 245 116 11.80 34.60 335229 40091 3.60 5.20 10.60 12.60 6.20 14.60 17.00 385.00 727.00 1.6 207 1095094
+1 99 1 1 0 0 157 10 9 0.20 0.20 424 1668 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6637 1873374
+1 76 1 1 19 0 3116 224 225 3.60 2.40 193385 253381 14.60 28.00 20.00 0.00 0.00 13.80 19.00 354.80 243.60 2.0 414 1116750
+1 90 1 1 1 0 1467 108 85 1.20 2.40 6816 17369 0.00 0.00 0.00 0.00 0.00 1.20 1.20 95.21 100.60 1.5 418 1091789
+1 90 1 1 1 0 3438 424 352 0.20 0.20 9987 18030 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 17.60 2.4 1510 1726141
+1 91 1 1 3 1 938 116 75 2.20 2.40 25416 19318 0.00 0.00 0.00 0.00 0.00 0.80 0.80 121.40 173.80 2.2 1283 1713362
+1 94 1 1 8 5 717 44 38 0.60 0.60 94541 27960 0.00 0.00 0.00 0.00 0.00 0.40 0.40 55.29 71.86 1.7 766 1039227
+1 87 1 1 67 72 2619 255 124 1.80 1.60 113326 50530 0.00 0.00 0.00 0.00 0.00 39.80 50.60 113.60 213.40 2.4 2215 1508795
+1 0 1 1 30 5 5937 669 584 11.00 4.40 276587 43272 14.20 25.40 42.00 90.40 0.20 18.40 22.80 516.40 816.20 199 62 38
+1 76 1 1 9 2 4048 401 320 4.41 2.20 338534 215894 5.41 10.02 10.02 0.00 1.00 27.86 31.26 219.04 383.97 3.0 419 1011559
+1 89 1 1 24 34 2649 279 186 0.40 1.80 31652 29714 2.00 8.00 20.80 39.00 0.20 5.20 5.20 35.00 84.60 1.2 127 1085298
+1 92 1 1 0 0 1168 91 47 0.20 0.20 240604 20609 1.40 2.00 2.00 0.00 1.60 0.40 0.40 15.80 17.40 2.0 227 1741504
+1 0 1 1 19 16 1806 406 226 0.60 0.40 641052 533824 0.00 0.00 0.00 0.00 0.00 22.00 32.00 37.40 79.00 754 91 9
+1 96 1 1 3 1 1406 70 84 0.40 1.20 17032 96884 0.00 0.00 0.00 0.00 0.00 0.20 0.40 37.20 37.80 2.2 701 1644637
+1 95 1 1 7 2 889 35 27 1.20 5.20 47274 23119 0.00 0.00 0.00 0.00 0.00 0.20 0.20 90.60 119.60 2.0 483 1532344
+1 81 1 1 14 11 5925 383 230 1.40 6.20 153597 50906 2.80 4.20 3.80 0.00 1.60 7.20 8.00 92.00 240.80 9.4 296 1001605
+1 88 1 1 1 0 2028 401 513 0.20 0.20 18147 54409 0.00 0.00 0.00 0.00 0.00 4.40 4.40 22.80 59.60 2.4 697 1702590
+1 94 1 1 1 0 300 55 46 0.40 0.40 17409 269144 13.77 24.15 24.15 0.00 3.99 5.59 6.79 28.54 43.11 1.2 221 1726970
+1 92 1 1 1 0 2795 189 102 0.20 0.20 110950 21427 1.20 1.40 1.40 0.00 1.60 4.40 5.00 15.40 47.00 1.0 160 1067262
+1 89 1 1 18 26 1425 83 50 2.61 2.40 177846 24584 0.00 0.00 0.00 0.00 0.00 3.01 5.21 193.79 190.58 1.0 8610 1870708
+1 81 1 1 4 0 5300 554 386 3.40 1.20 217765 64739 1.80 1.80 2.40 0.80 1.40 2.40 2.60 177.80 382.40 2.4 138 1002414
+1 72 1 1 38 45 2367 294 231 7.19 3.39 287347 32525 0.00 0.00 0.00 0.00 0.00 2.20 2.79 408.18 530.54 4.0 2374 1783503
+1 97 1 1 0 0 951 66 70 0.20 0.20 2473 33786 0.40 0.40 0.40 0.00 0.00 0.40 0.40 16.00 22.80 2.0 289 1059456
+1 63 1 1 24 0 4730 665 542 9.60 6.60 433275 28268 1.40 2.40 7.60 14.40 2.00 11.00 11.00 500.00 827.20 3.0 293 1013954
+1 94 1 1 5 1 1246 170 141 1.20 0.60 56801 54469 0.00 0.00 0.00 0.00 1.00 1.20 1.40 67.74 119.64 1.2 1254 1019580
+1 88 1 1 42 28 3371 230 101 2.80 3.40 161679 108965 0.00 0.00 0.00 0.00 0.00 5.00 6.80 199.00 270.40 4.4 3096 1345739
+1 83 1 1 53 72 2053 321 159 0.40 0.60 514922 29391 4.61 38.68 80.36 230.86 1.40 55.11 103.21 31.66 55.31 2.5 168 1130139
+1 94 1 1 1 0 768 93 78 0.20 0.20 72536 30522 2.81 3.01 3.01 0.00 0.00 1.80 2.40 15.63 56.51 1.0 146 1059721
+1 79 1 1 31 16 4495 326 186 3.40 4.40 356965 122565 0.00 0.00 0.00 0.00 0.00 1.80 1.80 211.00 418.20 6.2 1543 1328674
+1 88 1 1 13 3 1089 49 42 1.60 2.40 37164 23363 0.00 0.00 0.00 0.00 0.00 0.80 1.20 181.96 316.63 4.0 698 974719
+1 86 1 1 4 1 3290 341 307 2.00 3.60 342177 33866 2.00 2.40 2.40 0.00 0.60 6.80 10.60 112.40 231.00 1.3 340 1093653
+1 88 1 1 1 0 1763 507 375 0.40 0.40 56452 59961 6.80 12.80 16.80 15.80 0.20 8.80 15.60 37.20 36.40 3.0 139 1720707
+1 86 1 1 2 1 3723 213 194 0.40 0.60 126658 118240 4.20 8.40 13.20 29.60 1.60 18.20 21.00 108.60 216.00 1.3 159 1123099
+1 67 1 1 17 4 6199 483 104 11.02 36.27 202036 43309 11.42 46.89 111.22 782.77 0.40 10.82 11.82 550.50 896.39 1.0 133 1006331
+1 84 1 1 10 3 5341 231 153 1.80 3.19 165609 51312 0.00 0.00 0.00 0.00 0.00 0.00 0.00 117.76 133.53 4.2 985 1628203
+1 92 1 1 0 0 2790 221 89 0.20 0.20 998056 17924 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 22.00 1.2 519 1095728
+1 97 1 1 1 1 1072 58 44 0.20 0.20 261668 133124 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 17.40 1.8 8228 1863022
+1 80 1 1 23 2 2573 319 238 8.58 5.59 193986 92720 0.00 0.00 0.00 0.00 0.00 10.38 10.38 345.91 634.33 1.0 1216 1016945
+1 90 1 1 5 2 4903 333 267 0.40 1.80 15674 63082 0.00 0.00 0.00 0.00 0.60 15.17 16.97 25.35 64.87 2.2 3025 1640324
+1 87 1 1 8 2 3750 270 145 1.40 4.40 181322 61188 0.00 0.00 0.00 0.00 0.00 8.20 11.00 80.20 137.80 4.2 3889 1334074
+1 1 1 1 18 1 1135 188 135 2.40 12.40 485245 109897 3.00 3.80 3.80 0.00 1.80 14.80 19.20 60.60 139.00 387 88 10
+1 73 1 1 8 0 4402 569 493 8.20 2.20 336436 31299 0.60 0.60 0.60 0.00 2.40 7.40 7.40 394.60 642.80 1.0 340 1027978
+1 98 1 1 1 1 230 51 32 0.20 0.20 315152 297176 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 2.4 5589 1835376
+1 90 1 1 0 0 3227 387 186 0.20 0.20 111564 46429 0.40 0.40 0.40 0.00 0.80 0.00 0.00 16.80 54.80 1.4 303 1110995
+1 83 1 1 1 0 6128 505 287 0.60 0.80 261803 103675 5.98 14.74 37.25 49.60 0.20 3.39 3.39 60.96 118.92 4.8 133 996523
+1 85 1 1 12 10 2084 261 154 1.60 2.00 733109 679579 0.00 0.00 0.00 0.00 0.00 51.30 61.28 117.56 230.94 3.8 2351 1034834
+1 90 1 1 5 3 2877 207 136 1.40 2.61 21354 73178 9.82 16.83 12.83 0.00 1.20 0.80 0.80 90.98 124.25 1.0 188 995708
+1 85 1 1 21 18 718 43 47 3.39 3.39 92375 78566 0.00 0.00 0.00 0.00 0.00 3.79 6.99 257.88 389.22 1.6 6210 1848837
+1 89 1 1 5 0 2105 156 133 1.00 3.20 214979 62173 0.00 0.00 0.00 0.00 0.20 9.20 31.20 82.60 197.80 3.3 739 1034208
+1 91 1 1 2 1 1228 105 89 0.60 0.60 113956 100427 15.00 60.40 90.80 196.40 0.00 44.40 44.40 59.20 136.80 1.8 151 1119608
+1 79 1 1 7 4 4627 1283 136 2.00 3.59 509700 50768 8.78 27.15 52.50 80.24 1.20 5.19 9.58 176.85 270.66 1.8 243 1130699
+1 71 1 1 48 57 2931 169 160 7.41 20.44 222226 40920 9.02 55.71 72.34 130.86 0.20 23.25 37.47 280.16 526.65 1.2 231 1081029
+1 69 1 1 16 0 4559 783 805 12.80 15.40 84463 35268 1.80 6.00 14.40 21.40 0.00 9.80 18.00 899.80 759.00 1.4 156 1088915
+1 82 1 1 2 0 2389 232 92 2.00 9.80 296312 53188 4.60 6.00 11.00 12.40 0.80 14.20 14.20 139.40 312.40 1.3 171 1037347
+1 69 1 1 16 0 4432 674 301 4.40 4.20 395442 82388 1.00 5.20 59.40 100.80 0.80 45.20 61.40 303.80 512.80 1.5 220 1103578
+1 69 1 1 16 6 4325 478 394 8.80 4.60 274568 30021 5.80 11.80 15.60 25.20 2.00 6.60 7.40 483.20 798.20 1.0 207 1027142
+1 89 1 1 3 2 1040 120 59 0.80 3.19 154551 24953 6.39 27.54 56.69 123.55 0.40 31.14 44.71 82.83 197.80 2.6 190 993039
+1 0 1 1 5 4 825 165 129 0.20 0.20 83366 53619 0.00 0.00 0.00 0.00 0.00 2.60 3.00 19.60 56.20 632 93 7
+1 93 1 1 4 1 1062 141 126 2.80 1.20 74472 6098 0.00 0.00 0.00 0.00 0.00 0.00 0.00 161.80 211.20 1.6 7349 1864162
+1 83 1 1 3 0 3707 233 153 1.60 1.80 354435 99856 14.80 34.20 71.00 197.00 1.20 59.20 80.00 91.00 181.00 2.0 147 1009598
+1 92 1 1 9 1 1799 127 87 1.80 4.19 104229 37594 0.00 0.00 0.00 0.00 0.00 0.60 0.80 120.16 164.87 4.0 808 1529517
+1 81 1 1 9 4 3289 385 348 3.60 1.00 161759 86979 0.00 0.00 0.00 0.00 0.00 0.80 0.80 172.40 279.20 1.0 539 966606
+1 77 1 1 10 0 5975 692 612 2.20 2.00 505718 475455 5.99 21.96 84.43 122.55 0.40 24.15 72.85 95.21 230.54 1.8 126 1039337
+1 92 1 1 4 3 1509 501 139 0.60 1.00 312242 255308 0.00 0.00 0.00 0.00 0.00 3.20 3.20 52.60 119.60 4.2 1051 1600333
+1 77 1 1 8 2 4784 416 240 1.20 1.60 442876 110453 7.82 24.85 79.16 129.06 0.40 35.27 48.70 106.81 329.86 2.4 205 1011407
+1 95 1 1 2 1 588 71 71 0.20 0.20 125736 83488 0.00 0.00 0.00 0.00 0.00 16.00 29.80 13.40 31.20 1.0 567 1062424
+1 61 1 1 13 0 4279 235 176 12.22 34.47 289309 30701 0.40 0.40 2.20 7.01 8.82 4.21 4.21 397.60 751.30 1.0 184 1079269
+1 87 1 1 3 1 442 46 30 2.20 2.20 105052 44010 0.00 0.00 0.00 0.00 0.00 2.99 5.19 206.59 179.24 1.2 11466 1877964
+1 97 1 1 0 0 300 56 46 0.20 0.20 1995 18052 0.80 0.80 0.80 0.00 0.00 0.00 0.00 21.00 18.00 1.0 272 1754832
+1 98 1 1 2 1 163 10 18 0.20 0.20 427 25545 0.00 0.00 0.00 0.00 0.00 0.60 0.80 15.60 17.00 1.0 6470 1855784
+1 80 1 1 16 12 3009 360 244 1.60 5.81 405250 85282 8.02 20.64 43.69 55.11 0.60 35.87 47.90 139.28 270.74 3.2 387 986647
+1 88 1 1 15 5 1751 182 142 0.60 0.80 47141 28599 8.18 8.18 8.18 0.00 2.59 2.40 3.79 61.08 168.66 1.8 269 1059291
+1 96 1 1 11 10 568 56 56 0.60 1.20 11724 22513 0.00 0.00 0.00 0.00 0.00 0.80 3.40 57.00 60.20 2.0 660 1008230
+1 73 1 1 8 1 4476 345 309 2.59 2.99 528531 328979 8.98 28.74 98.20 186.63 0.60 19.96 38.52 159.28 395.21 1.4 209 1010328
+1 92 1 1 32 43 1579 171 601 0.20 0.20 24849 93532 0.00 0.00 0.00 0.00 0.00 0.60 0.60 15.60 30.00 2.8 1334 1704886
+1 90 1 1 4 0 1596 170 146 2.40 1.80 89489 41764 3.80 4.80 4.80 0.20 0.80 3.80 4.40 122.40 212.60 1.0 263 1055742
+1 87 1 1 16 5 3116 289 190 0.60 0.60 325948 52640 0.40 0.60 0.60 0.00 0.40 28.40 45.20 60.20 219.80 1.0 400 969106
+1 94 1 1 10 9 782 119 90 0.80 1.60 12478 24791 0.00 0.00 0.00 0.00 0.00 6.60 6.60 75.20 123.80 2.3 1048 1017725
+1 83 1 1 32 45 5180 254 179 1.20 1.20 62571 29505 1.40 1.60 13.03 18.04 0.40 23.05 24.25 93.19 202.81 5.6 141 1022458
+1 68 1 1 22 2 4052 470 151 8.02 8.62 142202 40400 0.00 0.00 0.00 0.00 0.00 16.43 26.05 416.83 810.22 1.5 2364 1097337
+1 94 1 1 2 0 985 55 46 1.60 4.80 111111 22256 0.00 0.00 0.00 0.00 0.20 3.40 6.20 91.80 110.00 2.2 659 1756514
+1 75 1 1 20 4 3121 341 233 2.80 2.60 691537 133912 0.00 0.00 0.00 0.00 19.60 12.60 24.00 217.40 343.60 1.5 539 1044970
+1 95 1 1 1 0 2147 79 68 0.20 0.20 40671 53995 0.00 0.00 0.00 0.00 0.00 1.60 2.60 16.00 26.40 2.4 4670 1730946
+1 90 1 1 3 2 5049 175 198 0.40 0.20 211318 116402 0.00 0.00 0.00 0.00 0.20 8.80 15.80 34.40 48.00 3.0 2706 1642328
+1 97 1 1 0 0 170 18 21 0.20 0.20 448 8385 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 7278 1869002
+1 91 1 1 3 0 408 28 24 2.00 3.60 44853 15881 0.40 1.20 0.40 0.00 0.80 1.00 1.20 148.20 151.40 1.2 6777 1849790
+1 87 1 1 15 3 2162 159 119 2.00 2.40 40899 31950 0.00 0.00 0.00 0.00 1.20 6.00 9.40 150.20 220.20 1.0 702 1021237
+1 98 1 1 0 0 160 12 16 0.20 0.20 2085 8670 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 16.80 1.0 7248 1863704
+1 90 1 1 5 1 330 39 38 0.40 0.40 34377 12185 0.00 0.00 0.00 0.00 0.00 1.00 1.20 37.80 47.60 1.4 633 1760253
+1 94 1 1 2 0 697 89 79 1.80 0.60 38828 2388 0.00 0.00 0.00 0.00 0.00 0.00 0.00 89.60 125.00 1.0 6622 1873187
+1 90 1 1 7 1 948 111 48 1.60 3.40 324006 3073 0.00 0.00 0.00 0.00 0.00 4.80 4.80 102.80 192.60 2.6 6213 1731014
+1 96 1 1 0 0 1201 65 61 0.40 0.40 109352 58703 0.00 0.00 0.00 0.00 0.00 0.00 0.00 28.40 34.40 1.4 6854 1877461
+1 89 1 1 0 0 1911 97 75 0.20 0.20 110056 30130 0.00 0.00 0.00 0.00 0.00 1.80 3.00 13.40 17.20 2.0 4101 1776888
+1 89 1 1 1 0 5744 168 190 0.20 0.20 51175 189975 6.00 8.80 8.00 0.00 4.40 0.60 0.60 27.40 28.60 1.2 312 1013458
+1 0 1 1 21 18 2799 291 211 0.60 0.40 374814 259868 2.60 4.80 4.80 0.00 0.00 1.00 1.00 35.40 71.00 172 87 13
+1 98 1 1 0 0 264 42 33 0.20 0.20 1016 10116 0.00 0.00 0.00 0.00 0.00 0.40 0.80 15.63 18.44 1.4 1374 1749756
+1 93 1 1 8 6 1473 123 130 0.40 0.60 138254 30008 0.00 0.00 0.00 0.00 0.00 9.20 10.20 39.00 68.60 4.5 2512 1095232
+1 98 1 1 0 0 188 13 24 0.20 0.20 550 6777 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 5310 1859912
+1 90 1 1 4 1 1983 191 152 0.80 0.80 258832 170579 0.00 0.00 0.00 0.00 0.00 1.20 1.60 65.00 65.60 3.2 1143 1535661
+1 95 1 1 1 0 917 70 37 0.60 1.00 16214 19692 0.00 0.00 0.00 0.00 0.00 0.20 0.20 52.60 98.00 3.5 2854 1009477
+1 92 1 1 6 1 2348 144 103 2.40 0.80 37237 10148 0.20 0.20 0.20 0.00 0.20 1.00 1.00 121.80 166.80 2.4 298 1709362
+1 94 1 1 9 4 639 48 45 1.20 1.60 188938 15125 0.00 0.00 0.00 0.00 0.00 8.00 15.60 56.20 259.60 2.0 6043 1855211
+1 75 1 1 25 9 4174 245 135 4.20 9.20 250833 42433 0.00 0.00 0.00 0.00 0.20 20.80 23.60 295.00 408.80 3.8 2630 1524755
+1 84 1 1 120 112 1917 228 156 2.79 3.79 168278 108067 10.58 23.75 38.92 122.75 6.99 0.80 0.80 196.61 294.21 1.0 156 968364
+1 96 1 1 0 0 596 45 196 0.20 0.20 6815 223361 1.80 1.80 1.80 0.00 0.00 0.40 0.40 15.60 19.60 1.0 165 1749568
+1 94 1 1 3 0 1131 74 44 1.20 1.80 77364 8905 0.80 0.80 12.80 32.20 0.00 4.20 7.40 108.60 142.40 3.4 133 1703250
+1 85 1 1 11 4 4406 177 151 5.20 5.20 146325 6300 2.40 2.60 2.60 0.00 4.60 11.40 11.80 202.00 418.40 3.4 233 1447301
+1 86 1 1 4 1 574 43 27 3.20 3.00 115026 62525 0.00 0.00 0.00 0.00 0.00 4.80 9.40 233.40 260.00 1.6 6267 1849520
+1 93 1 1 17 24 807 47 65 0.40 0.40 2688 13620 0.00 0.00 0.00 0.00 0.00 5.99 5.99 28.34 39.32 1.5 701 1037450
+1 73 1 1 88 59 3069 319 259 3.00 6.20 301284 392829 13.80 59.60 147.00 440.00 2.20 20.60 38.80 226.40 455.00 1.0 165 1034472
+1 89 1 1 7 4 961 86 80 1.00 4.40 216565 145935 17.20 28.00 47.20 44.40 8.80 18.80 34.80 42.40 83.00 1.5 169 989717
+1 92 1 1 3 0 1405 131 122 0.80 0.60 187208 41824 1.20 1.40 1.40 0.00 0.00 2.40 4.20 50.80 97.20 3.0 301 1114336
+1 96 1 1 1 1 250 12 22 0.20 0.20 12083 67041 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7862 1871376
+1 74 1 1 39 2 4137 227 161 7.62 18.64 70587 30229 0.00 0.00 0.00 0.00 0.40 13.83 15.23 253.71 480.36 2.7 357 1096063
+1 94 1 1 5 2 1660 125 79 0.60 2.40 36704 25056 3.79 4.79 4.59 0.00 0.80 1.40 1.80 51.30 70.66 1.5 201 1001517
+1 92 1 1 27 37 1387 196 132 0.60 0.80 21693 32019 3.21 6.81 11.02 13.63 0.20 9.42 16.83 44.69 72.14 1.0 161 1068907
+1 59 1 1 56 11 3910 259 163 10.78 37.13 183614 37938 6.99 21.96 46.51 56.29 3.59 39.32 46.51 505.59 767.07 1.0 159 1088988
+1 0 1 1 22 13 1723 163 106 2.00 3.40 458095 178681 0.00 0.00 0.00 0.00 0.40 25.00 40.40 240.80 325.80 2436 82 16
+1 94 1 1 39 39 822 45 38 1.00 0.80 13899 6834 0.00 0.00 0.00 0.00 0.00 0.00 0.00 63.80 81.80 2.0 4810 1672792
+1 92 1 1 2 0 1859 113 110 0.80 2.59 56120 49384 0.00 0.00 0.00 0.00 0.00 2.40 2.40 48.50 115.57 2.7 490 1013713
+1 77 1 1 184 138 4782 626 394 1.60 4.60 132194 158954 20.40 45.00 53.00 42.80 12.60 11.80 20.80 71.00 214.40 1.3 149 1016229
+1 89 1 1 18 25 428 109 64 0.20 0.20 283433 267502 0.00 0.00 0.00 0.00 0.00 3.20 6.40 15.60 16.80 3.0 4085 1825440
+1 98 1 1 18 23 192 14 33 0.20 0.20 427 14377 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 1.0 5274 1858256
+1 90 1 1 3 1 3085 306 153 0.40 0.40 142703 32976 0.00 0.00 0.00 0.00 0.80 9.80 19.00 30.60 81.80 1.7 575 1076379
+1 95 1 1 36 38 703 109 49 0.80 2.80 84777 60687 2.60 6.60 6.60 0.00 1.20 0.80 0.80 39.20 75.20 2.0 195 1712285
+1 96 1 1 1 1 369 166 52 0.20 0.20 328107 281166 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 2.6 5463 1828022
+1 97 1 1 2 1 301 27 37 0.60 0.40 90093 15683 0.00 0.00 0.00 0.00 0.00 0.00 0.00 51.60 65.80 1.2 7435 1875941
+1 85 1 1 1 0 4813 428 200 0.40 1.00 37103 65163 4.20 4.20 4.20 0.00 0.40 1.60 1.60 38.00 41.40 1.0 253 1129515
+1 88 1 1 24 13 2400 248 154 0.60 0.60 36555 89687 10.38 29.34 45.91 391.62 1.20 4.79 10.58 44.71 79.24 2.3 146 1099612
+1 83 1 1 13 0 3583 179 136 1.39 1.59 170092 94875 0.00 0.00 0.00 0.00 0.20 11.95 21.91 111.16 183.07 3.2 566 1059437
+1 89 1 1 5 1 1490 172 82 2.20 2.20 462717 19436 5.19 9.58 18.36 35.73 10.18 11.38 11.58 143.11 247.11 1.0 162 977095
+1 99 1 1 1 1 158 13 13 0.20 0.20 11119 16475 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.2 8609 1864503
+1 95 1 1 5 0 883 47 52 1.00 2.60 18899 19440 3.80 4.60 4.20 0.00 1.00 2.00 2.20 56.80 98.00 1.0 276 1016429
+1 96 1 1 10 9 579 87 71 0.60 2.00 22680 20401 0.00 0.00 0.00 0.00 0.00 0.80 0.80 53.20 65.00 2.6 843 1008656
+1 90 1 1 3 1 1875 192 167 0.80 3.59 106247 23835 0.00 0.00 0.00 0.00 0.20 2.59 3.79 40.72 75.65 1.7 457 1089844
+1 85 1 1 18 15 2455 288 143 1.40 1.40 420367 89848 0.00 0.00 0.00 0.00 0.00 5.00 6.80 95.00 168.40 3.6 941 1132286
+1 83 1 1 7 1 1446 153 121 7.00 5.60 251907 11167 0.00 0.00 0.00 0.00 0.00 1.00 1.00 364.20 526.40 1.6 8378 1834694
+1 81 1 1 16 5 3425 578 238 0.40 0.20 1068774 1051345 5.60 10.20 10.20 0.00 10.20 3.60 3.80 40.40 85.80 2.6 177 1036813
+1 91 1 1 3 0 1284 107 95 3.20 9.60 72827 24856 1.60 4.60 41.00 59.80 0.80 4.20 5.80 108.80 191.40 2.8 132 1753125
+1 92 1 1 11 11 2391 518 234 0.20 0.20 665687 661896 0.00 0.00 0.00 0.00 0.00 0.40 0.40 20.80 44.80 1.4 443 1044834
+1 84 1 1 4 1 3931 274 200 2.40 0.80 131422 116356 4.00 6.40 8.20 4.20 0.40 1.00 1.40 135.00 207.40 1.8 205 1009333
+1 72 1 1 30 12 3169 151 134 7.60 19.80 85104 43100 3.60 7.80 7.80 0.00 1.00 9.60 11.40 288.80 537.00 1.0 427 1077011
+1 91 1 1 60 82 1471 70 43 1.00 2.40 135198 13794 0.00 0.00 0.00 0.00 0.20 11.02 14.63 104.41 163.73 1.4 799 1000784
+1 95 1 1 12 12 664 145 57 0.20 0.20 255852 192501 0.00 0.00 0.00 0.00 0.00 1.20 1.20 15.60 18.00 2.2 1349 1745746
+1 56 1 1 17 0 3902 411 355 15.40 35.40 284485 228809 5.40 15.60 23.60 28.60 0.00 11.80 13.00 544.20 1040.60 1.0 373 1079026
+1 82 1 1 6 0 3304 376 142 1.20 2.40 1166853 25980 3.81 21.44 56.51 153.91 2.81 3.41 22.04 81.56 194.79 2.5 165 1092721
+1 57 1 1 56 59 7625 694 826 4.80 5.00 525258 111782 0.00 0.00 0.00 0.00 0.20 3.40 5.40 338.40 467.20 7.0 2345 1370643
+1 91 1 1 2 0 2389 190 123 0.40 0.60 147176 42063 6.21 9.62 21.44 48.90 0.60 15.63 25.85 34.27 108.02 1.8 193 1023149
+1 0 1 1 6 1 2414 249 163 1.20 3.60 583992 472149 2.00 2.60 2.60 0.80 0.80 11.00 15.80 61.00 133.40 167 89 10
+1 0 1 1 15 14 3082 156 125 0.20 0.20 11270 26333 0.00 0.00 0.00 0.00 0.00 4.61 4.61 18.44 32.87 637 93 7
+1 89 1 1 2 0 4242 212 163 0.40 0.60 97711 77021 0.00 0.00 0.00 0.00 0.40 8.60 8.60 31.60 108.80 1.6 519 1069346
+1 90 1 1 19 0 2078 120 40 2.80 3.60 103404 21483 1.40 1.60 1.60 0.00 0.00 21.00 33.40 175.60 254.60 1.6 281 1745158
+1 66 1 1 19 9 4082 666 553 6.80 4.80 550139 245244 9.80 56.40 145.40 301.60 3.60 18.80 32.40 340.00 737.60 2.4 219 1033072
+1 89 1 1 10 2 2445 149 90 2.00 2.20 117296 33231 0.00 0.00 0.00 0.00 0.00 2.80 4.20 124.40 197.80 2.2 1678 1532469
+1 90 1 1 5 2 3165 188 136 2.00 0.80 131842 6803 3.80 20.80 74.00 146.20 0.20 4.00 7.00 106.20 263.20 2.2 155 1381774
+1 97 1 1 0 0 189 42 29 0.20 0.20 252230 245278 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.40 17.00 2.4 5608 1835552
+1 86 1 1 3 2 3163 216 115 0.20 0.20 52430 54479 0.00 0.00 0.00 0.00 0.00 1.60 2.20 17.60 18.60 2.2 1400 1754115
+1 87 1 1 1 0 5227 171 162 0.20 0.20 102624 56903 3.60 7.00 10.60 7.20 0.60 3.20 4.00 15.20 132.00 4.4 132 1013872
+1 88 1 1 16 5 662 68 34 2.20 2.00 175605 58186 0.00 0.00 0.00 0.00 0.00 1.20 2.20 186.40 181.00 1.8 7836 1866947
+1 80 1 1 32 4 3243 182 140 5.20 5.60 337517 94832 0.80 1.00 1.00 0.00 1.40 4.60 7.00 250.60 420.20 5.6 1300 1535309
+1 93 1 1 6 3 2998 141 91 0.20 0.20 297845 265395 0.00 0.00 0.00 0.00 0.00 3.19 5.59 45.11 29.74 4.0 2531 1541389
+1 80 1 1 7 5 12277 267 216 0.60 0.80 141858 41906 36.87 86.37 178.16 331.46 0.00 38.88 42.08 51.90 315.03 2.2 195 984402
+1 98 1 1 18 28 281 22 19 0.20 0.20 3344 13554 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.23 19.04 1.2 6363 1852585
+1 98 1 1 0 0 363 46 23 0.20 0.20 15108 24939 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7458 1876208
+1 94 1 1 1 0 378 77 35 0.40 0.20 267033 25942 0.00 0.00 0.00 0.00 0.20 0.40 0.40 33.80 47.20 1.2 1157 1764158
+1 89 1 1 11 7 2207 147 111 0.40 0.60 53375 91504 9.60 36.20 89.00 199.60 1.00 2.80 3.00 64.00 143.20 1.0 319 1060714
+1 83 1 1 8 5 2735 341 201 1.80 4.60 248991 30043 0.00 0.00 0.00 0.00 0.20 1.40 1.60 135.40 232.00 2.2 1094 1130794
+1 86 1 1 6 0 1464 85 50 6.00 18.40 7508 8182 1.20 1.20 10.40 13.60 0.80 0.00 0.00 164.60 311.60 2.0 139 1751994
+1 72 1 1 11 1 4532 628 554 5.59 1.80 588953 320435 0.20 0.20 0.20 0.00 2.00 9.98 17.37 298.40 493.81 5.0 314 1010052
+1 99 1 1 2 1 162 12 15 0.20 0.20 7609 14038 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 16.80 1.0 6356 1848880
+1 91 1 1 1 1 1762 77 93 0.20 0.20 6978 56709 2.20 13.60 42.00 73.60 0.20 43.00 43.00 15.60 87.00 1.6 127 1129587
+1 97 1 1 1 0 1892 122 124 0.20 0.20 47850 53271 6.00 11.00 8.60 0.00 0.20 0.00 0.00 21.40 17.20 2.0 268 1725296
+1 75 1 1 36 45 3745 432 380 5.80 9.40 576508 641678 2.80 4.20 4.20 0.00 5.20 3.20 3.20 218.80 389.40 1.8 195 1042576
+1 89 1 1 35 44 1662 167 93 0.80 1.40 47416 22641 2.20 6.40 13.00 13.20 1.00 2.00 2.00 59.20 100.60 3.0 180 1111715
+1 82 1 1 4 1 5301 448 310 3.00 1.80 97917 10751 3.80 21.80 64.40 120.20 0.20 7.00 7.20 174.60 368.20 4.2 228 1388955
+1 93 1 1 0 0 275 18 26 0.80 0.60 1420 23585 0.00 0.00 0.00 0.00 0.00 0.20 0.40 36.80 45.00 2.4 1333 1768075
+1 93 1 1 2 1 297 40 41 0.40 0.40 2555 12235 1.20 1.20 1.20 0.00 0.60 0.20 0.20 32.34 39.92 2.0 351 1741625
+1 82 1 1 4 0 1757 133 197 4.40 7.60 191605 173745 10.80 45.60 81.00 114.40 1.20 21.00 39.00 184.60 351.40 1.0 151 1036051
+1 89 1 1 4 1 1552 247 219 3.40 1.00 141455 55801 0.00 0.00 0.00 0.00 0.00 0.20 0.20 169.40 238.20 2.2 6696 1838672
+1 98 1 1 0 0 435 51 52 0.20 0.20 10361 27422 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.63 16.83 1.0 135 1746265
+1 92 1 1 8 1 2878 174 87 1.00 1.60 202656 13263 0.00 0.00 0.00 0.00 0.20 7.60 14.20 131.20 198.80 1.6 3511 1745048
+1 0 1 1 50 65 2292 357 201 0.40 1.80 181979 75166 5.80 9.20 16.20 15.40 1.40 5.40 8.00 33.80 87.00 147 88 12
+1 85 1 1 60 73 3005 131 96 2.00 1.80 47890 31396 2.60 7.60 52.00 83.00 0.80 52.60 53.00 99.80 216.80 4.2 133 1016803
+1 88 1 1 2 0 2422 144 74 1.20 1.80 66781 16746 0.20 0.20 0.20 0.00 0.00 5.40 6.40 90.80 149.00 2.6 402 1005952
+1 94 1 1 5 0 850 74 46 0.40 1.80 141756 16669 2.60 4.20 8.80 27.40 0.60 9.80 12.80 36.40 77.00 1.0 139 972893
+1 87 1 1 4 3 2731 127 90 1.00 3.40 54912 81047 0.00 0.00 0.00 0.00 0.00 17.60 18.00 70.40 200.60 1.4 426 1023250
+1 88 1 1 14 6 1814 259 144 0.20 0.20 116743 26776 2.00 2.00 4.81 5.41 0.40 40.68 65.13 21.04 99.40 3.2 275 1045414
+1 61 1 1 51 1 4103 279 205 11.40 32.40 174616 60155 7.00 19.20 44.80 78.40 0.40 6.40 9.80 391.80 749.20 2.0 155 1089586
+1 73 1 1 156 143 6244 466 338 4.60 2.40 434226 246409 6.20 15.20 25.60 34.20 1.00 14.20 27.60 244.40 394.80 4.8 145 1325832
+1 96 1 1 1 0 432 37 20 0.80 4.20 118932 4598 0.00 0.00 0.00 0.00 0.20 0.00 0.00 27.40 42.40 1.8 606 1760808
+1 80 1 1 12 0 4996 777 739 3.78 2.79 684317 547834 4.78 22.51 56.57 98.61 0.60 19.92 77.69 121.91 245.02 1.3 147 1041729
+1 0 1 1 13 12 2527 254 144 0.20 0.20 516056 485338 0.00 0.00 0.00 0.00 107.58 25.95 26.15 37.72 238.12 2035 81 19
+1 90 1 1 0 0 3082 154 97 0.40 1.80 40618 23263 1.20 1.20 1.20 0.00 0.20 11.60 12.80 34.80 77.40 1.0 183 1027330
+1 90 1 1 36 52 2326 155 77 0.80 1.20 9028 21940 2.20 17.20 23.20 43.20 0.00 0.20 0.20 45.80 66.80 1.0 148 1137347
+1 84 1 1 77 40 2726 182 156 3.41 4.21 142105 75490 7.62 21.84 29.66 34.07 1.40 7.01 13.03 205.81 310.82 1.6 189 1088441
+1 89 1 1 6 1 2094 289 169 1.00 1.00 190655 43262 0.00 0.00 0.00 0.00 0.20 3.20 3.60 61.60 131.80 1.7 401 1080037
+1 96 1 1 0 0 580 42 30 0.20 0.20 3359 15578 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 17.80 1.2 7584 1869384
+1 86 1 1 3 1 1651 162 121 0.20 0.20 40386 45588 5.39 11.38 17.56 31.74 0.00 6.99 9.58 222.36 98.60 1.0 154 966001
+1 91 1 1 2 1 3363 126 134 0.20 0.20 13163 176688 0.00 0.00 0.00 0.00 0.20 0.80 0.80 18.00 19.60 2.2 452 1523230
+1 96 1 1 3 1 362 37 44 0.80 1.00 37567 32976 1.20 1.20 1.20 0.00 4.00 0.60 1.20 67.20 92.80 2.0 284 1719747
+1 88 1 1 3 0 3195 239 212 2.40 0.80 69373 51394 0.20 1.60 1.20 0.00 1.20 0.00 0.00 120.76 207.98 2.0 448 1013560
+1 71 1 1 14 1 5004 650 545 8.00 4.00 708302 41724 0.00 0.00 0.00 0.00 0.00 2.00 3.40 400.60 607.60 4.4 1679 1696723
+1 93 1 1 4 1 2123 352 198 0.40 0.60 22142 32892 4.00 5.60 14.40 13.80 0.80 2.20 2.40 34.20 59.80 1.4 252 1750914
+1 88 1 1 20 18 4446 293 236 0.60 3.00 44120 46650 0.00 0.00 0.00 0.00 0.00 2.80 6.00 27.40 49.40 1.7 588 1016550
+1 0 1 1 7 2 2404 211 153 1.40 2.61 76530 43705 0.40 0.40 0.40 0.00 0.00 5.01 7.41 76.95 129.86 298 89 11
+1 95 1 1 1 0 884 73 186 0.20 0.20 30354 53613 2.00 2.20 2.20 0.00 0.40 1.40 2.20 22.40 17.20 2.8 969 1716299
+1 77 1 1 9 1 1925 167 90 7.20 20.00 249672 32180 2.40 20.00 26.20 51.00 1.00 13.00 13.60 259.40 482.60 1.5 219 1104314
+1 87 1 1 12 8 5006 221 183 1.00 1.40 307424 31592 0.00 0.00 0.00 0.00 0.00 4.60 5.20 60.20 148.00 4.6 1502 1534278
+1 77 1 1 8 2 4551 974 337 0.80 2.39 596214 74507 10.16 39.24 81.87 309.96 3.19 29.68 54.18 77.89 216.73 1.2 117 1038378
+1 97 1 1 2 1 208 13 31 0.20 0.20 6997 11887 0.00 0.00 0.00 0.00 0.00 0.20 0.20 18.60 19.80 1.0 6379 1856778
+1 91 1 1 0 0 496 69 30 0.20 0.20 15309 7110 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.80 16.80 1.6 1054 1762960
+1 89 1 1 1 1 2210 277 185 0.20 0.20 523626 117453 0.60 1.20 1.20 0.00 0.40 4.80 5.60 22.00 114.00 1.5 337 1016118
+1 95 1 1 17 13 940 82 71 0.80 3.80 8065 14248 0.00 0.00 0.00 0.00 0.00 3.60 3.60 44.00 65.60 2.0 4879 1673080
+1 93 1 1 6 0 921 109 81 0.80 0.80 155425 33179 1.80 6.61 23.25 46.69 0.40 7.01 9.62 61.12 114.63 1.0 160 1092378
+1 91 1 1 1 0 1874 107 114 0.60 0.40 20679 184797 0.00 0.00 0.00 0.00 0.00 1.20 1.40 53.80 126.60 2.6 835 1017366
+1 98 1 1 2 1 207 12 12 0.40 0.40 24104 7829 0.00 0.00 0.00 0.00 0.00 0.00 0.00 33.93 39.52 1.0 8585 1862052
+1 89 1 1 25 35 1558 141 96 1.40 0.60 21185 17556 1.20 1.20 1.20 0.00 0.60 0.20 0.20 77.60 118.20 3.0 253 1104155
+1 98 1 1 2 1 255 22 23 0.40 0.80 652 4595 0.00 0.00 0.00 0.00 0.00 0.00 0.00 33.80 33.40 3.0 951 1714590
+1 93 1 1 46 66 2118 90 116 0.40 0.40 4054 20486 0.00 0.00 0.00 0.00 0.20 0.00 0.00 42.60 39.60 2.2 540 1724573
+1 0 1 1 1 0 544 55 62 0.20 0.20 1943 19308 0.00 0.00 0.00 0.00 0.20 0.40 0.40 20.20 18.60 400 97 3
+1 86 1 1 1 1 2068 199 138 0.40 1.60 139395 52225 1.40 1.60 1.60 0.00 0.60 61.88 63.67 158.68 181.24 1.0 321 1019960
+1 74 1 1 14 0 4719 495 282 4.20 5.80 437927 35992 1.60 2.40 2.40 0.00 9.40 16.40 20.40 213.40 385.80 2.8 294 1048386
+1 89 1 1 3 0 551 77 29 3.00 3.20 320678 10455 0.00 0.00 0.00 0.00 0.00 1.80 1.80 241.60 234.60 2.2 4822 1849413
+1 89 1 1 184 203 2908 312 123 0.40 1.60 1006792 24241 0.40 0.40 0.40 0.00 0.20 3.80 6.60 19.60 51.80 4.0 200 1110408
+1 80 1 1 8 0 1853 111 82 6.81 20.64 33097 18311 1.00 1.00 2.20 5.01 0.00 2.61 2.61 230.66 431.46 1.0 137 1091089
+1 88 1 1 2 0 2434 224 175 1.60 3.00 137420 31819 0.00 0.00 0.00 0.00 0.00 3.40 3.40 114.80 152.80 1.8 654 1095594
+1 63 1 1 16 1 3760 195 109 12.40 27.80 91420 35490 0.60 0.60 0.60 0.00 0.80 16.00 18.20 508.20 936.60 1.8 413 1089088
+1 88 1 1 7 4 2251 289 264 0.80 2.00 182660 29917 8.20 8.40 8.00 0.00 3.20 6.80 10.20 63.60 106.80 2.7 232 1102570
+1 96 1 1 1 0 468 39 29 0.80 2.40 84829 9977 0.00 0.00 0.00 0.00 0.20 0.20 0.20 47.20 75.40 1.2 1272 1760781
+1 93 1 1 16 8 2010 57 90 1.20 2.00 51048 64600 0.00 0.00 0.00 0.00 0.00 0.40 0.40 170.60 118.20 2.2 796 1539421
+1 93 1 1 51 69 1064 142 118 0.40 0.20 5288 24594 0.00 0.00 0.00 0.00 0.00 0.40 0.40 31.06 52.71 2.8 1752 969454
+1 91 1 1 33 40 1648 103 76 1.00 1.80 361149 68942 0.00 0.00 0.00 0.00 0.00 5.60 5.60 70.00 113.40 2.8 5148 1674381
+1 98 1 1 1 1 196 16 22 0.20 0.20 11917 14682 0.00 0.00 0.00 0.00 0.00 0.80 1.60 15.60 16.80 1.0 7728 1882194
+1 95 1 1 2 0 756 84 13 1.40 1.60 188486 9167 0.00 0.00 0.00 0.00 0.00 0.00 0.00 110.80 166.40 1.4 7618 1878770
+1 88 1 1 15 13 2711 196 128 0.60 1.40 132298 107739 2.20 5.20 15.20 25.20 2.60 2.20 3.60 40.00 68.40 1.0 131 1127534
+1 89 1 1 10 5 1711 175 137 1.39 3.76 30699 34177 2.97 2.97 2.77 0.00 1.39 7.13 7.33 67.52 148.51 1.8 246 1042893
+1 83 1 1 36 52 4171 300 306 0.80 1.80 277742 521261 3.20 4.20 4.20 0.00 2.60 42.40 42.80 56.60 207.80 1.0 299 985134
+1 91 1 1 0 0 1181 67 66 0.20 0.20 39602 77617 11.20 17.00 17.00 0.00 1.80 5.00 9.00 17.80 33.60 1.8 306 1118776
+1 81 1 1 51 65 5512 295 212 1.60 6.41 342079 135390 0.00 0.00 0.00 0.00 4.21 16.83 26.45 118.44 243.69 2.0 732 1000258
+1 84 1 1 23 19 3259 300 185 1.60 2.40 410377 185481 6.00 15.40 32.40 67.40 1.40 2.80 3.00 144.60 224.00 3.6 136 1527883
+1 99 1 1 0 0 272 59 20 0.20 0.20 7187 3939 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 17.00 1.0 3251 1847008
+1 90 1 1 1 0 2875 153 109 0.40 0.60 16975 115588 0.00 0.00 0.00 0.00 0.00 1.00 2.00 31.80 34.60 2.0 4655 1731736
+1 96 1 1 1 0 1634 172 75 0.20 0.20 122879 14839 0.00 0.00 0.00 0.00 0.00 0.20 0.40 19.20 26.60 2.4 6077 1715483
+1 79 1 1 3 1 3484 464 273 0.60 2.40 426742 313462 9.40 45.60 109.20 234.60 1.60 13.20 22.80 63.80 299.60 4.4 152 1372693
+1 72 1 1 36 22 6385 642 310 3.00 9.20 145688 17661 1.00 1.00 1.00 0.00 1.00 0.20 0.20 266.80 318.20 5.0 383 1535890
+1 85 1 1 3 0 1872 153 101 0.40 0.20 573316 5466 0.00 0.00 0.00 0.00 0.00 54.20 107.20 23.60 164.20 5.0 1146 1366662
+1 95 1 1 0 0 974 72 45 0.20 0.20 89310 13592 1.60 1.80 1.80 0.00 2.59 0.40 0.40 15.37 29.14 2.2 145 1007922
+1 98 1 1 1 1 160 14 16 0.20 0.20 7007 8363 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.60 1.0 8496 1866056
+1 86 1 1 12 6 2557 140 81 1.20 2.00 34223 30138 3.20 5.20 22.00 44.20 1.00 1.20 1.20 121.80 228.40 1.0 193 967147
+1 89 1 1 0 0 562 62 51 0.20 0.20 81921 98078 4.20 5.20 4.60 0.00 0.60 5.20 8.80 13.00 24.80 2.2 311 1742392
+1 86 1 1 3 1 6109 284 248 0.40 1.20 356163 354586 0.00 0.00 0.00 0.00 0.00 2.00 2.00 21.40 30.40 3.0 987 1376917
+1 88 1 1 6 5 2936 175 120 0.20 0.20 153155 75782 0.00 0.00 0.00 0.00 0.00 1.20 1.80 15.80 66.00 6.0 1580 1309763
+1 82 1 1 20 13 3365 234 156 1.80 1.60 377760 208093 0.80 7.40 20.60 36.00 0.20 50.80 51.20 130.60 330.00 6.8 374 1304400
+1 93 1 1 4 1 1150 86 39 2.20 7.80 394576 273556 0.00 0.00 0.00 0.00 0.00 0.60 0.60 108.20 149.80 3.2 5631 1836403
+1 90 1 1 6 5 2042 107 79 0.60 0.60 54202 132182 2.19 4.17 4.17 0.00 3.98 2.98 5.37 52.49 76.54 2.0 275 982831
+1 98 1 1 0 0 147 9 15 0.20 0.20 440 10300 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 8423 1867360
+1 77 1 1 89 41 2952 317 243 2.99 6.39 327928 230574 0.00 0.00 0.00 0.00 0.00 12.97 20.36 227.94 435.53 1.3 768 1120158
+1 88 1 1 4 1 444 44 19 2.40 2.79 81225 19035 0.00 0.00 0.00 0.00 0.00 2.00 2.59 236.73 192.22 1.0 11399 1877732
+1 90 1 1 2 0 376 35 15 2.20 2.20 62864 13634 0.00 0.00 0.00 0.00 0.00 2.40 3.59 194.41 172.46 1.2 6331 1845095
+1 90 1 1 4 1 469 53 27 2.00 2.20 146392 15978 0.00 0.00 0.00 0.00 0.00 3.80 5.60 172.80 180.40 1.2 8566 1834526
+1 86 1 1 9 1 2369 297 170 1.40 3.20 210369 145662 0.00 0.00 0.00 0.00 0.00 10.00 18.60 118.80 206.80 3.6 1163 1545403
+1 96 1 1 2 1 776 59 45 0.40 0.40 26350 18057 0.00 0.00 0.00 0.00 0.00 0.00 0.00 36.20 44.20 2.0 771 1041283
+1 73 1 1 53 55 5853 192 134 2.58 9.74 148495 241613 3.78 3.78 3.78 0.00 3.98 0.99 1.19 304.77 269.58 4.2 252 1510335
+1 70 1 1 16 0 5776 527 379 5.58 1.99 651304 62577 5.18 13.94 55.58 92.43 10.56 17.13 25.90 294.22 581.67 1.8 142 996244
+1 87 1 1 24 14 3061 237 138 1.00 1.00 63879 74591 0.00 0.00 0.00 0.00 0.00 7.20 11.40 78.40 111.60 1.8 1207 1129149
+1 94 1 1 0 0 825 51 59 0.20 0.20 20908 151062 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 44.60 2.0 6429 1849358
+1 71 1 1 12 2 3388 463 387 5.80 2.00 309278 98064 28.60 68.60 101.00 135.60 0.00 14.80 27.00 338.80 578.80 2.0 356 953130
+1 82 1 1 14 9 3448 370 261 2.00 2.00 221717 150820 5.80 14.60 37.80 74.80 3.80 5.20 16.60 130.60 235.60 2.2 158 1026549
+1 86 1 1 95 120 3749 281 194 1.40 1.20 90976 15722 0.00 0.00 0.00 0.00 0.40 11.00 11.00 68.80 225.60 6.4 1428 1307952
+1 95 1 1 1 0 1084 91 63 0.20 0.20 11951 22614 0.00 0.00 0.00 0.00 0.00 1.40 1.80 32.60 25.20 3.0 622 1016328
+1 83 1 1 11 5 3076 412 322 0.60 0.80 482557 232189 14.20 16.00 15.80 0.00 4.00 14.00 27.40 54.20 115.20 6.2 201 1300526
+1 88 1 1 14 12 3500 150 124 0.40 0.60 15426 66870 10.40 12.60 12.60 0.00 5.40 7.60 11.00 38.40 53.20 1.5 289 1125866
+1 61 1 1 23 6 8353 468 375 6.80 8.20 229579 78144 0.00 0.00 0.00 0.00 0.00 0.20 0.20 399.00 515.60 4.6 3779 1347123
+1 95 1 1 1 1 1493 55 69 0.20 0.20 19441 236133 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.6 8235 1863088
+1 91 1 1 5 1 1589 153 102 0.40 0.60 134065 20191 0.00 0.00 0.00 0.00 0.00 2.40 20.60 35.20 116.20 2.0 1801 998664
+1 88 1 1 37 7 1889 126 126 0.60 0.60 27811 96695 5.60 46.20 104.20 287.40 1.80 25.80 41.20 62.80 217.40 2.0 238 1064165
+1 82 1 1 54 68 1212 65 62 2.99 3.39 57338 45157 4.39 8.38 90.22 141.72 1.40 9.18 17.17 248.70 414.57 1.5 201 1059104
+1 86 1 1 42 47 1476 172 103 2.80 2.80 212873 30993 0.00 0.00 0.00 0.00 0.00 1.40 2.40 172.40 256.00 3.2 1426 1070854
+1 90 1 1 54 55 1563 216 151 1.20 2.40 86935 27849 0.20 0.20 0.20 0.00 0.40 12.60 14.80 76.00 143.80 1.0 431 978203
+1 97 1 1 12 16 220 17 21 0.20 0.20 20943 16792 0.00 0.00 0.00 0.00 0.00 0.00 0.00 21.40 16.80 1.0 7425 1866435
+1 92 1 1 81 80 1086 134 81 0.40 0.40 209409 50764 3.60 13.20 18.60 18.20 1.60 2.00 2.20 35.40 102.80 1.7 129 991770
+1 96 1 1 14 20 1080 30 66 0.20 0.20 16792 271467 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 4465 1824160
+1 85 1 1 7 2 2342 125 74 2.20 4.20 294081 71960 10.60 52.40 111.60 152.20 1.00 70.00 75.80 146.40 293.20 1.0 175 1058875
+1 98 1 1 4 1 263 37 32 0.40 0.60 892 11250 0.00 0.00 0.00 0.00 0.00 0.00 0.00 34.00 35.00 2.0 6368 1711616
+1 94 1 1 1 0 645 120 69 0.40 0.60 301469 183147 0.00 0.00 0.00 0.00 0.60 2.00 3.80 37.20 56.00 3.4 1092 1728875
+1 96 1 1 3 2 1388 68 49 0.20 0.20 203366 60254 0.00 0.00 0.00 0.00 0.00 5.40 5.40 16.00 25.40 2.4 5245 1675056
+1 77 1 1 9 0 4041 365 311 7.20 2.20 512190 10120 0.20 0.20 0.20 0.00 0.40 2.20 4.20 366.40 595.00 5.0 440 1711718
+1 72 1 1 56 59 5526 776 598 6.20 1.60 361328 220236 3.80 4.20 4.20 0.00 0.40 3.20 5.40 294.80 454.00 6.2 292 1545926
+1 98 1 1 1 1 242 24 34 0.20 0.20 1013 20783 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 17.00 2.0 1145 1723728
+1 89 1 1 14 2 2325 171 119 1.00 1.80 257196 112717 0.00 0.00 0.00 0.00 0.00 1.80 3.20 57.00 91.60 2.6 1264 1548634
+1 85 1 1 1 0 3294 271 172 1.00 2.60 569257 296604 4.00 5.60 5.60 0.00 2.40 17.60 20.00 90.80 222.60 1.6 369 1017470
+1 97 1 1 1 1 214 17 30 0.20 0.20 7359 29992 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 17.84 1.2 7309 1869372
+1 81 1 1 6 0 3816 367 232 4.20 3.40 680520 121189 0.00 0.00 0.00 0.00 0.00 22.60 24.20 177.00 317.80 3.6 1305 1043736
+1 97 1 1 0 0 168 12 14 0.20 0.20 1081 10287 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.00 16.80 1.0 8307 1863622
+1 86 1 1 145 3 4928 178 118 0.60 1.20 8260 38748 0.00 0.00 0.00 0.00 0.00 63.20 63.40 49.20 61.00 2.6 537 1517352
+1 98 1 1 0 0 220 32 14 0.20 0.20 127427 7746 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 18.00 1.2 8542 1864168
+1 90 1 1 7 1 1749 111 88 1.20 4.40 491681 63682 2.80 6.00 16.40 29.20 2.60 5.00 23.20 74.00 158.60 1.6 150 1054608
+1 0 1 1 10 8 1942 232 253 0.60 0.60 101588 204344 9.18 14.17 48.70 84.03 6.99 27.94 30.54 48.10 160.08 120 87 13
+1 89 1 1 28 40 3238 201 126 0.80 0.60 19199 48924 6.00 9.00 7.20 0.00 0.60 6.80 7.00 72.00 71.40 3.4 182 1113214
+1 88 1 1 8 7 1658 141 80 0.60 1.00 147920 20071 0.20 0.20 0.20 0.00 1.00 28.60 29.20 49.20 204.40 3.0 557 996139
+1 84 1 1 1 0 5200 429 398 1.20 2.80 46306 29547 3.80 11.20 29.00 56.60 0.00 2.20 3.00 79.40 170.40 1.5 132 1015242
+1 97 1 1 1 0 324 43 42 0.60 0.60 12582 13528 1.00 1.00 1.00 0.00 0.00 0.80 0.80 38.80 44.20 1.0 146 1742146
+1 92 1 1 7 0 1464 92 71 0.60 0.60 92083 24785 0.00 0.00 0.00 0.00 0.20 10.60 20.40 50.60 93.20 1.2 690 1016576
+1 70 1 1 21 1 5989 673 474 7.58 3.79 505990 66850 0.00 0.00 0.00 0.00 0.00 2.40 2.59 381.24 559.08 6.8 809 1526997
+1 84 1 1 5 2 3435 225 133 2.80 3.20 202527 126833 12.40 20.00 41.40 55.20 6.80 8.80 10.60 138.40 250.00 1.0 140 988995
+1 97 1 1 0 0 168 19 21 0.20 0.20 1057 6492 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.43 16.83 1.6 9669 1873443
+1 95 1 1 4 0 480 79 26 2.00 2.00 51676 49322 0.00 0.00 0.00 0.00 0.00 0.20 0.20 76.80 132.40 1.4 7667 1869042
+1 87 1 1 6 6 2945 327 214 0.40 0.40 262196 54753 4.80 8.20 14.60 21.20 6.00 3.40 5.40 32.00 65.20 1.0 135 966686
+1 93 1 1 2 0 1199 76 98 1.80 1.20 114783 111454 3.40 3.80 3.80 0.00 0.20 6.40 11.40 63.80 107.40 2.3 253 1059168
+1 76 1 1 21 14 2023 154 106 6.20 17.20 54172 31468 0.00 0.00 0.00 0.00 0.00 15.80 17.60 231.80 455.80 2.7 660 1101168
+1 85 1 1 7 3 3030 238 120 1.40 1.40 261528 35193 0.00 0.00 0.00 0.00 0.00 3.60 13.20 111.20 217.40 1.0 1746 1091978
+1 91 1 1 14 21 4405 139 129 0.20 0.20 4462 6266 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.6 4587 1731704
+1 86 1 1 43 52 4584 255 139 0.60 0.80 240501 28792 0.00 0.00 0.00 0.00 0.20 3.80 5.60 55.80 97.80 1.2 629 1119488
+1 94 1 1 26 38 396 80 26 0.60 0.60 414176 17481 0.00 0.00 0.00 0.00 0.00 0.00 0.00 40.80 44.80 1.2 912 1762022
+1 77 1 1 8 2 4094 314 202 2.20 2.81 399035 67149 2.20 8.62 28.46 63.13 2.61 17.84 34.27 185.57 288.38 1.6 298 997220
+1 98 1 1 23 30 176 11 21 0.20 0.20 8633 3581 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6459 1871616
+1 97 1 1 6 5 367 72 62 0.40 0.40 2927 13606 2.60 2.60 2.60 0.00 0.20 0.00 0.00 35.00 34.00 1.0 137 1753517
+1 76 1 1 378 5 4095 152 178 8.60 8.00 100834 40629 0.00 0.00 0.00 0.00 0.00 2.60 2.60 332.40 542.00 2.6 2373 1714294
+1 93 1 1 12 5 1519 109 69 1.40 1.40 276516 244145 0.00 0.00 0.00 0.00 0.00 3.20 4.80 101.20 124.40 5.4 2520 1548502
+1 80 1 1 8 1 2327 347 318 6.99 2.00 183514 21399 0.00 0.00 0.00 0.00 0.00 0.00 0.00 337.13 487.23 2.8 6117 1852802
+1 90 1 1 9 1 3468 339 138 0.60 2.00 82704 26937 1.80 2.00 2.00 0.00 1.00 4.39 8.18 40.72 50.30 1.0 196 991962
+1 66 1 1 30 23 6777 316 194 6.01 8.42 224570 66141 10.02 18.04 33.87 57.52 7.82 7.41 10.02 264.73 698.20 2.3 192 1012991
+1 0 1 1 12 9 1767 52 45 0.60 0.60 37701 29679 1.60 2.80 2.80 0.00 0.00 2.00 2.00 31.80 49.20 336 96 4
+1 86 1 1 20 9 1834 261 258 4.40 1.40 137547 45286 0.00 0.00 0.00 0.00 0.00 0.20 0.40 213.80 358.20 4.4 6190 1709211
+1 67 1 1 12 5 6127 434 401 6.60 5.20 239634 289980 5.80 29.40 63.80 115.40 1.60 20.40 21.20 382.20 595.00 3.8 249 1372461
+1 88 1 1 2 0 451 41 43 2.00 2.00 67254 46721 0.00 0.00 0.00 0.00 0.00 1.60 1.80 176.55 154.71 1.0 11991 1892471
+1 91 1 1 5 1 2598 182 69 0.60 1.20 756698 13776 0.00 0.00 0.00 0.00 0.00 0.40 0.80 64.60 84.20 2.8 2569 1702059
+1 66 1 1 78 94 3863 148 123 11.22 32.26 74522 27955 0.00 0.00 0.00 0.00 0.00 4.41 7.41 368.74 733.47 1.3 530 1095466
+1 0 1 1 49 71 3273 225 180 0.60 0.40 83246 53705 5.39 7.19 7.19 0.00 2.79 3.99 4.59 59.88 74.05 227 82 18
+1 46 1 1 74 0 6835 377 188 20.12 59.56 274532 34446 3.59 28.88 58.96 112.55 2.19 14.74 21.71 801.39 1278.88 1.5 168 1100449
+1 92 1 1 5 4 1874 122 91 0.20 0.20 99524 39946 0.40 0.40 0.40 0.00 0.00 3.60 5.00 24.20 37.80 2.0 428 987506
+1 94 1 1 39 55 1791 133 82 0.40 0.40 11445 20407 0.00 0.00 0.00 0.00 0.00 2.00 2.00 39.00 52.80 1.6 2938 1050990
+1 85 1 1 2 1 400 79 77 0.60 0.80 1297030 420210 0.00 0.00 0.00 0.00 0.00 26.00 51.40 19.00 56.20 2.0 4449 1825016
+1 97 1 1 1 0 883 49 48 0.20 0.20 3049 13534 4.81 5.21 5.21 0.00 0.40 0.80 0.80 15.63 54.31 1.3 162 1015463
+1 76 1 1 7 0 3992 268 243 4.41 3.01 107318 188650 0.00 0.00 0.00 0.00 0.00 8.22 8.82 236.87 457.52 2.4 686 1017114
+1 71 1 1 55 17 3192 316 148 10.00 8.40 516472 77134 6.00 11.20 17.40 25.60 10.00 40.60 46.20 424.80 814.60 4.4 202 1039774
+1 84 1 1 5 1 3202 283 234 3.00 3.00 88712 58154 1.40 1.40 15.60 27.00 0.80 31.80 32.20 165.00 320.40 3.0 164 1108459
+1 78 1 1 11 2 4396 232 298 0.80 5.98 416339 513414 3.98 4.58 4.58 0.00 7.57 13.15 13.75 30.68 163.94 3.4 227 1003385
+1 76 1 1 82 92 4279 338 271 1.60 2.40 138155 38109 11.80 22.60 22.60 0.00 0.80 18.20 31.80 170.80 226.80 1.0 368 1011166
+1 90 1 1 1 0 3548 436 166 0.40 0.20 499823 82427 5.00 9.40 9.40 0.00 17.80 11.00 11.00 12.80 125.40 4.6 327 976682
+1 96 1 1 2 0 2157 123 84 0.40 0.60 88150 5522 0.00 0.00 0.00 0.00 0.00 14.80 29.60 37.00 62.60 3.8 6643 1411531
+1 87 1 1 2 0 504 52 68 1.80 2.00 116953 143309 0.00 0.00 0.00 0.00 0.00 0.80 0.80 160.08 146.51 1.6 5885 1845479
+1 96 1 1 1 1 364 35 51 0.20 0.20 8962 39416 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 16.80 1.0 5986 1864160
+1 97 1 1 2 1 249 15 24 0.40 1.00 43745 23849 0.00 0.00 0.00 0.00 0.00 0.40 0.60 35.80 57.60 1.0 8355 1864778
+1 90 1 1 0 0 1220 61 96 0.20 0.20 17422 107652 0.00 0.00 0.00 0.00 0.00 1.00 1.80 15.60 17.00 1.6 4371 1782864
+1 89 1 1 104 135 2591 158 102 0.80 0.80 47110 43166 0.00 0.00 0.00 0.00 0.00 5.60 9.40 73.40 74.20 1.0 496 1028866
+1 96 1 1 1 1 359 50 35 0.20 0.20 280638 34065 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.56 17.76 1.2 6719 1858523
+1 96 1 1 0 0 1136 36 35 0.20 0.20 1376 15696 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.63 17.23 1.0 1838 1756040
+1 87 1 1 3 1 477 49 47 2.00 2.00 103752 45064 0.00 0.00 0.00 0.00 0.00 2.20 2.20 195.40 162.60 2.0 11204 1874557
+1 86 1 1 141 62 3383 364 233 0.80 2.00 464991 232759 3.60 3.60 7.60 12.20 5.60 17.00 19.60 47.20 99.60 1.7 353 1038570
+1 74 1 1 73 71 6221 275 148 6.00 18.00 281372 83399 0.00 0.00 0.00 0.00 0.00 7.20 7.20 216.60 449.00 1.5 1504 1109962
+1 91 1 1 13 6 3189 199 96 1.60 3.60 189156 59636 0.00 0.00 0.00 0.00 0.00 0.20 0.40 83.00 194.20 2.4 888 1643034
+1 87 1 1 37 47 1448 111 111 1.40 1.20 94599 109802 0.00 0.00 0.00 0.00 1.00 9.58 13.57 93.81 187.43 3.0 600 1070943
+1 96 1 1 1 0 529 34 68 0.20 0.20 5877 70884 0.00 0.00 0.00 0.00 0.00 1.40 1.40 16.20 44.00 1.0 713 1062614
+1 72 1 1 64 5 2696 317 365 6.81 4.01 226884 117404 9.02 28.66 93.79 206.41 1.20 57.11 96.59 335.87 606.01 1.8 141 1043352
+1 90 1 1 3 0 551 131 44 0.60 0.60 33213 18076 7.00 11.80 11.80 0.00 2.20 1.60 2.60 45.20 52.60 2.0 528 1749958
+1 96 1 1 0 0 957 82 62 0.40 1.80 17922 13341 0.40 0.40 0.40 0.00 0.00 0.20 0.20 19.84 25.45 1.5 199 994078
+1 92 1 1 30 7 1015 79 67 0.60 2.20 43567 18853 13.17 27.54 36.33 23.95 0.00 27.94 44.11 96.81 132.34 1.0 265 983173
+1 97 1 1 1 0 993 82 88 0.20 0.20 4533 23992 0.40 0.40 1.80 3.41 0.40 0.80 0.80 17.23 23.65 2.0 132 1066410
+1 98 1 1 0 0 1479 46 38 0.20 0.20 3056 6332 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 4621 1828408
+1 99 1 1 0 0 142 9 18 0.20 0.20 423 3675 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6459 1871616
+1 94 1 1 4 2 2821 171 126 0.40 0.60 25208 41575 0.00 0.00 0.00 0.00 0.20 2.00 2.20 28.14 69.06 3.4 2859 1529525
+1 89 1 1 9 0 2866 400 227 0.20 0.20 127318 81657 5.99 15.17 84.43 136.73 0.00 24.15 46.31 14.17 118.96 1.3 132 1074390
+1 81 1 1 66 80 4529 182 149 2.80 4.20 98313 86538 0.00 0.00 0.00 0.00 0.00 0.60 1.20 185.00 234.60 4.8 1782 1531538
+1 54 1 1 13 0 8309 1407 519 10.80 14.20 2214883 95033 1.00 1.40 1.40 0.00 1.40 14.20 22.00 477.80 831.20 3.5 279 1093539
+1 96 1 1 1 0 1493 47 64 0.20 0.20 18589 12370 0.40 0.60 0.60 0.00 0.00 0.80 1.40 17.60 25.60 2.4 165 1709802
+1 96 1 1 3 1 1051 93 36 0.60 0.60 113167 102455 0.00 0.00 0.00 0.00 0.00 1.20 1.20 25.20 41.20 4.6 1965 1558918
+1 89 1 1 5 0 1649 554 19 3.61 5.01 206447 4026 0.00 0.00 0.00 0.00 0.00 10.82 20.84 236.07 342.28 1.6 8589 1870285
+1 92 1 1 1 1 313 66 41 0.20 0.20 291336 266985 0.00 0.00 0.00 0.00 0.00 2.40 4.80 16.00 16.80 2.4 4121 1827112
+1 96 1 1 0 0 409 97 65 0.20 0.20 212316 199266 0.80 0.80 0.80 0.00 0.00 3.20 5.80 15.60 18.40 3.8 161 1735571
+1 95 1 1 11 1 1964 101 88 0.20 0.20 53319 24307 1.60 1.60 1.60 0.00 1.00 0.20 0.20 15.80 17.00 1.0 330 1748642
+1 76 1 1 19 0 4181 302 162 4.79 13.37 492647 33582 1.80 9.18 26.15 51.70 2.40 2.99 4.39 180.44 333.73 3.4 156 1086548
+1 91 1 1 3 1 1693 208 124 0.40 1.60 26945 36802 0.00 0.00 0.00 0.00 0.00 20.36 22.75 15.97 99.40 3.3 469 1105220
+1 86 1 1 2 0 2735 330 174 1.20 3.99 293121 31777 0.00 0.00 0.00 0.00 0.40 60.88 66.67 197.21 277.05 2.0 368 1097134
+1 92 1 1 11 1 1562 193 68 1.80 2.60 241653 145933 0.00 0.00 0.00 0.00 0.00 7.00 7.00 153.40 209.40 4.6 2542 1574757
+1 94 1 1 29 37 3472 248 137 0.20 0.20 207334 206626 0.00 0.00 0.00 0.00 0.00 4.00 4.00 15.40 60.60 3.6 3326 1346128
+1 88 1 1 2 1 2304 131 102 1.60 4.39 119424 18630 0.00 0.00 0.00 0.00 0.00 2.20 2.20 110.18 184.03 1.0 678 1093673
+1 76 1 1 5 3 3694 611 520 2.40 2.20 723819 282690 2.00 2.00 2.00 0.00 0.80 52.91 103.61 111.82 234.87 2.0 502 1132314
+1 84 1 1 32 42 1405 80 52 3.00 9.00 831099 21519 0.00 0.00 0.00 0.00 0.00 14.20 14.60 124.00 262.80 1.8 748 1089336
+1 86 1 1 5 0 2709 297 116 3.60 4.80 263524 34694 2.40 7.20 16.00 27.00 2.20 8.20 11.20 209.80 332.20 2.4 151 1105862
+1 81 1 1 19 12 3139 238 154 3.20 4.00 110280 49214 4.60 6.80 6.80 0.00 0.60 4.60 8.40 178.80 306.20 3.3 207 1009814
+1 73 1 1 8 4 2357 413 296 3.20 2.60 1027253 950762 0.00 0.00 0.00 0.00 122.00 39.40 75.00 204.00 507.40 2.4 3776 1039309
+1 97 1 1 0 0 185 16 16 0.20 0.20 1044 2335 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 23.40 2.0 9887 1870296
+1 95 1 1 0 0 1899 151 95 0.20 0.20 148859 155251 2.80 3.80 3.80 0.00 0.20 2.00 3.80 19.00 21.60 3.6 168 1737504
+1 98 1 1 13 18 140 7 12 0.20 0.20 422 9648 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7260 1875328
+1 96 1 1 1 1 419 164 44 0.80 0.60 254313 229754 0.00 0.00 0.00 0.00 0.00 9.80 10.80 40.80 44.80 3.2 6884 1836338
+1 87 1 1 8 7 1663 93 78 0.20 0.20 43229 62330 0.00 0.00 0.00 0.00 0.00 2.20 2.80 15.80 98.60 2.6 583 1758885
+1 98 1 1 34 47 137 8 8 0.20 0.20 424 2326 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 8498 1866072
+1 85 1 1 1 0 2647 330 336 0.40 0.40 149828 80133 0.00 0.00 0.00 0.00 0.00 16.60 31.80 48.60 68.00 2.6 1659 1709059
+1 94 1 1 1 0 769 99 67 0.80 1.00 96293 14271 1.00 1.00 1.00 0.00 0.40 6.40 6.40 64.80 122.40 1.0 272 1023098
+1 97 1 1 19 25 197 15 18 0.20 0.20 7457 4595 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 1.2 7548 1870232
+1 98 1 1 0 0 161 14 20 0.20 0.20 446 12219 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7410 1865584
+1 83 1 1 8 2 3014 245 288 2.00 0.60 64641 482422 0.00 0.00 0.00 0.00 0.00 0.40 0.40 106.00 201.20 2.6 434 1016594
+1 92 1 1 2 0 1322 109 71 0.60 0.60 166893 128089 0.00 0.00 0.00 0.00 0.00 1.80 1.80 45.11 84.03 1.8 2368 1007775
+1 95 1 1 1 0 996 85 55 0.40 0.40 16667 36431 0.00 0.00 0.00 0.00 0.00 1.00 1.40 35.53 52.10 2.0 2979 1010114
+1 98 1 1 0 0 201 31 29 0.20 0.20 644 7749 2.40 2.40 2.40 0.00 0.00 0.00 0.00 15.57 16.77 1.0 288 1752346
+1 87 1 1 18 7 2276 170 135 2.79 2.79 136153 140940 0.00 0.00 0.00 0.00 0.00 0.60 0.60 147.31 202.20 2.2 643 1537186
+1 93 1 1 2 0 1318 108 95 0.40 0.80 4035 43515 0.00 0.00 0.00 0.00 0.00 0.80 0.80 29.00 46.60 2.2 1046 973795
+1 72 1 1 3 1 6994 554 242 1.20 1.60 1060802 495513 6.99 19.96 49.10 103.19 0.80 15.17 15.17 78.64 265.67 3.2 130 1008538
+1 96 1 1 1 0 325 62 27 0.80 0.80 324311 181984 0.00 0.00 0.00 0.00 0.00 0.00 0.00 55.80 87.60 2.4 5669 1836762
+1 93 1 1 0 0 3119 172 178 0.40 0.40 287429 357693 0.00 0.00 0.00 0.00 0.00 11.80 12.00 16.40 43.60 2.8 1340 1376870
+1 87 1 1 12 7 2366 160 110 0.60 1.80 387104 88446 0.00 0.00 0.00 0.00 0.00 13.20 22.40 34.80 73.20 4.6 10137 1373203
+1 87 1 1 22 4 3111 177 131 1.80 2.20 123060 53761 0.00 0.00 0.00 0.00 0.60 0.40 0.40 146.60 235.60 1.5 969 1077584
+1 98 1 1 16 14 630 39 42 0.20 0.20 3971 6865 0.00 0.00 0.00 0.00 0.00 0.00 0.00 24.60 19.20 2.2 5613 1683274
+1 97 1 1 1 0 258 35 16 0.20 0.20 186209 43337 0.00 0.00 0.00 0.00 0.00 8.98 8.98 17.76 45.31 1.2 7052 1851499
+1 93 1 1 4 1 1310 114 123 1.00 0.60 22851 96155 0.00 0.00 0.00 0.00 0.00 0.60 0.60 93.80 116.40 3.5 611 1059350
+1 97 1 1 0 0 289 63 30 0.20 0.20 233037 219508 2.60 2.80 10.40 13.80 0.00 4.60 7.00 15.60 30.80 3.4 134 1735434
+1 77 1 1 11 5 2477 255 143 5.41 5.21 772599 68306 0.00 0.00 0.00 0.00 0.00 3.21 3.81 204.41 374.95 1.0 551 1033986
+1 0 1 1 18 6 2174 231 135 2.00 3.40 168211 43126 3.00 4.80 3.60 0.00 4.60 11.80 16.00 128.40 240.40 368 85 14
+1 76 1 1 1 0 3483 294 283 0.80 2.60 621569 553056 18.80 70.80 183.60 384.60 6.00 44.80 83.20 41.80 75.20 6.2 132 994390
+1 91 1 1 20 26 863 70 44 0.20 0.20 1864 14232 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 17.00 1.6 994 1761544
+1 60 1 1 15 3 4027 274 158 11.60 33.60 295178 43767 0.20 0.20 0.20 0.00 0.00 23.80 31.60 402.40 817.40 1.0 582 1092362
+1 92 1 1 1 0 3389 81 57 0.60 0.60 6093 57028 13.80 21.40 21.40 0.00 7.60 5.20 7.80 33.20 60.60 1.0 231 1731570
+1 83 1 1 21 3 3030 287 241 5.20 2.00 109422 9208 0.00 0.00 0.00 0.00 0.00 10.40 19.60 227.40 371.80 3.6 2498 1407235
+1 91 1 1 9 3 2374 164 141 1.00 2.40 14453 122037 2.20 2.40 2.40 0.00 1.00 20.80 21.20 56.80 127.40 1.5 301 1061539
+1 75 1 1 25 2 3772 286 250 3.60 3.20 380396 202088 20.60 43.00 48.20 17.40 0.60 21.00 28.60 252.20 360.80 5.2 250 1522648
+1 94 1 1 3 1 1002 86 108 0.60 1.60 50946 131296 0.00 0.00 0.00 0.00 0.00 0.20 0.20 37.80 66.80 2.8 940 1540130
+1 91 1 1 12 17 1140 54 45 0.20 0.20 89639 38819 0.00 0.00 0.00 0.00 0.00 11.80 22.60 22.80 19.20 1.0 567 1752966
+1 79 1 1 13 7 1521 198 189 2.99 3.79 192593 211442 15.77 63.67 127.35 235.73 2.00 18.56 27.54 126.95 354.89 4.4 138 1048398
+1 90 1 1 0 0 3592 265 121 0.20 0.20 9519 22662 3.80 4.20 4.20 0.00 0.00 0.20 0.20 15.80 31.60 4.4 244 1104192
+1 91 1 1 3 1 1850 76 60 0.20 0.20 34911 74165 14.54 20.92 20.92 0.00 9.96 8.37 13.15 24.50 48.80 1.3 302 1125887
+1 84 1 1 4 2 3996 172 126 1.00 1.60 28255 62502 10.18 11.38 23.55 25.75 0.60 16.57 18.76 82.83 170.06 2.2 133 1012739
+1 85 1 1 46 54 1304 154 104 1.20 2.00 441213 141771 9.20 42.60 103.80 197.20 8.60 20.40 40.40 181.00 298.20 2.8 202 1068515
+1 88 1 1 1 0 1745 99 62 0.60 0.60 172724 9196 0.00 0.00 0.00 0.00 0.00 0.00 0.00 32.20 37.80 2.6 779 1750693
+1 94 1 1 1 0 3075 193 116 0.20 0.20 9169 47411 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 26.20 2.0 579 1628867
+1 76 1 1 252 270 3919 612 553 5.20 1.80 302760 180215 0.00 0.00 0.00 0.00 6.20 1.20 1.20 262.80 420.80 1.5 461 965438
+1 95 1 1 4 0 915 128 42 1.00 1.20 296223 11187 0.00 0.00 0.00 0.00 0.00 0.00 0.00 70.80 89.20 2.8 5272 1724709
+1 76 1 1 644 9 4506 264 176 1.80 3.19 202621 114122 2.79 5.19 7.78 11.98 1.00 26.75 27.35 90.82 196.21 2.3 245 1063034
+1 96 1 1 0 0 815 60 47 0.20 0.20 1633 20397 0.00 0.00 0.00 0.00 0.00 1.00 1.00 15.80 17.40 1.2 2987 1014693
+1 96 1 1 2 1 310 43 39 0.80 0.80 29399 9719 0.00 0.00 0.00 0.00 0.00 0.20 0.20 51.40 69.60 1.0 6808 1841216
+1 96 1 1 5 5 691 72 53 0.20 0.20 5917 23539 0.00 0.00 0.00 0.00 0.00 17.56 17.56 15.77 65.87 2.0 575 967896
+1 0 1 1 42 49 3354 168 110 2.20 8.98 425112 18385 0.00 0.00 0.00 0.00 0.00 4.79 5.59 157.49 193.21 609 83 15
+1 85 1 1 21 29 482 34 31 2.00 2.00 104119 45343 0.00 0.00 0.00 0.00 0.20 2.20 4.00 168.40 164.80 2.2 741 1786800
+1 87 1 1 5 3 4180 409 294 0.20 0.20 41553 69632 0.00 0.00 0.00 0.00 0.00 4.19 5.39 22.36 37.72 2.8 545 1093344
+1 91 1 1 3 2 1435 183 116 0.60 0.40 96056 18798 0.00 0.00 0.00 0.00 0.40 1.80 3.00 46.40 61.00 1.6 1231 1133731
+1 90 1 1 2 0 348 30 19 1.80 1.80 59890 23320 0.00 0.00 0.00 0.00 0.00 2.79 4.99 154.29 145.51 1.2 8936 1868695
+1 96 1 1 3 2 1265 102 49 0.20 0.20 14291 20874 0.00 0.00 0.00 0.00 0.00 0.60 1.20 16.60 18.80 1.0 626 1066987
+1 83 1 1 54 45 5845 361 921 0.80 2.00 247854 158248 11.22 24.65 36.87 42.08 6.61 14.83 28.26 43.49 92.18 2.8 145 1047979
+1 86 1 1 50 74 2563 158 149 1.40 1.20 29578 177680 0.00 0.00 0.00 0.00 0.00 1.00 1.00 92.60 121.00 2.6 882 1017909
+1 96 1 1 0 0 600 127 158 0.20 0.20 29801 52413 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 22.00 2.0 2019 1730618
+1 88 1 1 25 36 1504 83 85 0.40 0.60 135516 65096 0.00 0.00 0.00 0.00 0.00 0.00 0.00 34.20 46.60 1.6 3572 1772755
+1 80 1 1 7 0 1261 75 29 3.60 4.00 130020 29856 0.00 0.00 0.00 0.00 0.00 6.40 9.40 321.00 331.60 3.0 1926 1804962
+1 90 1 1 0 0 2823 263 164 0.40 0.60 9096 25836 0.20 0.20 0.20 0.00 0.00 1.80 1.80 30.20 72.60 4.0 260 1104285
+1 92 1 1 11 2 1489 108 85 0.80 1.40 27042 23640 5.00 8.00 18.60 33.00 1.20 8.20 12.20 61.40 98.20 1.4 146 1066688
+1 81 1 1 55 63 3646 248 163 2.80 2.20 129850 58805 0.00 0.00 0.00 0.00 0.20 21.20 23.80 155.00 307.60 2.0 511 1112904
+1 87 1 1 26 22 2971 337 273 2.40 1.80 286522 60223 3.40 4.60 6.40 5.80 4.00 3.20 3.80 125.60 253.00 1.0 175 963154
+1 95 1 1 23 30 796 53 57 0.20 0.20 82739 148250 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 17.00 1.0 7036 1830402
+1 96 1 1 0 0 995 34 84 0.20 0.20 13842 375855 0.00 0.00 0.00 0.00 0.00 0.00 0.00 14.40 16.80 1.0 8339 1864704
+1 96 1 1 3 0 852 99 73 1.20 1.00 9893 7375 2.60 2.60 2.60 0.00 0.40 0.80 1.00 75.60 98.20 1.0 181 1751136
+1 94 1 1 2 1 4350 187 139 0.20 0.20 6315 63845 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.40 17.60 2.2 2549 1643882
+1 0 1 1 78 108 2717 321 292 0.40 0.40 405968 261396 0.00 0.00 0.00 0.00 12.63 8.42 18.64 33.47 90.38 731 85 15
+1 82 1 1 42 64 2453 423 669 1.40 2.20 474034 140393 0.00 0.00 0.00 0.00 0.00 8.40 16.80 128.00 187.80 2.6 2592 1733226
+1 92 1 1 1 0 1550 212 190 0.60 2.20 79081 70944 0.00 0.00 0.00 0.00 0.20 6.80 6.80 50.80 84.20 3.2 611 1050608
+1 94 1 1 0 0 2034 109 83 0.20 0.20 30215 22382 1.80 1.80 1.80 0.00 0.20 0.00 0.00 15.63 16.83 1.0 269 1751431
+1 87 1 1 1 0 2629 394 278 1.00 3.80 95204 324792 0.20 0.20 0.20 0.00 0.00 5.80 11.00 66.80 113.00 2.4 174 1375040
+1 87 1 1 6 1 3844 433 228 0.97 2.70 119325 117400 0.00 0.00 0.00 0.00 0.00 1.74 1.74 128.38 129.34 2.8 608 1486673
+1 76 1 1 62 19 5210 820 696 1.20 2.80 361705 40816 0.00 0.00 0.00 0.00 0.00 3.80 5.80 71.80 253.40 3.6 657 1399072
+1 88 1 1 13 3 2243 175 142 1.00 1.20 54515 35406 7.20 12.60 27.80 59.20 2.40 10.60 12.00 80.40 163.00 1.5 204 1021176
+1 89 1 1 19 15 934 96 78 1.60 1.40 69777 88143 13.80 19.20 19.20 0.00 8.00 28.40 41.40 70.60 156.60 1.0 265 991232
+1 87 1 1 2 0 4574 265 160 0.60 0.60 152091 30401 1.60 4.80 9.80 26.60 1.60 0.60 0.60 38.20 61.80 2.0 166 1057317
+1 0 1 1 6 4 1051 214 116 0.20 0.20 100352 87270 17.37 27.54 27.54 0.00 6.99 20.76 23.15 15.77 103.19 283 90 10
+1 82 1 1 3 0 3496 315 151 1.80 3.60 459199 61862 0.00 0.00 0.00 0.00 0.20 14.40 24.60 160.00 272.60 3.2 397 1017672
+1 98 1 1 1 1 444 18 31 0.20 0.20 6233 119597 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 8440 1837168
+1 96 1 1 6 4 704 53 55 0.20 0.20 33847 36582 0.00 0.00 0.00 0.00 0.00 1.40 1.40 18.60 25.00 2.0 4818 1672818
+1 91 1 1 0 0 279 31 30 0.20 0.20 109280 34524 0.00 0.00 0.00 0.00 0.00 1.80 1.80 15.03 17.64 1.4 2039 1770862
+1 95 1 1 1 0 1576 109 111 0.20 0.20 9675 51611 0.00 0.00 0.00 0.00 0.00 2.59 3.59 13.57 32.34 2.0 338 1064992
+1 97 1 1 7 1 776 70 47 0.40 0.40 13890 20383 1.20 1.20 1.20 0.00 0.20 7.21 13.03 42.69 78.76 1.0 244 1017748
+1 91 1 1 3 0 2691 128 81 0.80 2.20 14234 27960 0.00 0.00 0.00 0.00 0.00 3.60 3.60 48.60 104.60 1.0 636 1020024
+1 84 1 1 31 40 2928 271 213 3.80 3.00 89408 46791 1.80 1.80 1.80 0.00 0.40 2.60 2.80 192.20 274.60 1.4 179 1124382
+1 71 1 1 65 23 4564 199 122 2.40 7.78 495455 54727 10.58 64.07 91.02 114.57 4.79 51.50 85.23 202.40 352.10 4.4 154 1316873
+1 82 1 1 5 0 3054 371 292 0.80 2.00 137772 125680 19.56 36.13 55.09 106.39 1.40 27.35 36.13 38.52 163.07 1.3 131 980881
+1 75 1 1 21 10 3047 445 208 6.21 7.21 654086 429810 0.00 0.00 0.00 0.00 0.00 60.32 68.74 332.87 648.30 1.6 1526 1037688
+1 90 1 1 3 2 1974 309 196 0.60 2.00 7450 26728 1.40 1.40 1.40 0.00 0.80 1.20 1.40 34.00 106.80 2.5 207 1100702
+1 65 1 1 47 0 2824 150 111 12.00 35.00 85212 42485 0.40 0.40 0.40 0.00 0.80 9.40 9.40 378.00 736.00 3.2 198 1096288
+1 87 1 1 0 0 2703 244 214 0.40 1.20 267496 233645 0.60 1.20 1.20 0.00 4.40 9.60 18.40 50.20 65.20 2.3 475 997758
+1 98 1 1 0 0 166 10 14 0.20 0.20 425 9930 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7202 1874064
+1 90 1 1 1 0 1532 83 74 0.20 0.20 88312 26448 0.00 0.00 0.00 0.00 0.00 0.20 0.20 20.00 20.60 2.2 1167 1742472
+1 81 1 1 8 0 1582 117 71 5.37 10.74 77856 17189 3.78 16.10 33.20 59.44 0.80 23.26 31.21 303.98 552.68 2.4 166 1057544
+1 75 1 1 68 20 4502 547 406 5.00 5.00 176961 167776 9.40 15.80 14.60 0.00 4.20 31.80 36.60 217.80 470.60 1.0 295 1086019
+1 92 1 1 44 43 985 148 130 0.20 0.20 29097 34174 1.20 1.20 1.20 0.00 0.80 10.40 14.60 23.00 179.20 1.4 219 990363
+1 78 1 1 3 0 900 198 139 1.60 0.60 249554 1469273 0.00 0.00 0.00 0.00 0.00 21.60 42.00 85.60 117.20 1.6 5028 1828024
+1 97 1 1 2 0 360 69 71 0.40 0.60 36089 49991 0.00 0.00 0.00 0.00 0.00 0.00 0.00 33.20 34.40 2.0 6371 1711587
+1 0 1 1 6 4 1532 130 55 0.60 1.00 228855 43159 0.40 0.60 0.60 0.00 0.40 0.40 0.40 54.00 114.40 323 93 7
+1 69 1 1 37 7 4774 232 157 4.40 6.20 522823 107871 3.60 5.40 5.20 0.00 1.00 10.60 18.80 342.40 461.80 4.8 377 1527138
+1 76 1 1 13 6 2845 225 119 5.00 6.60 343010 48285 0.00 0.00 0.00 0.00 2.00 4.80 8.00 226.20 391.80 2.2 526 1007958
+1 96 1 1 0 0 303 48 38 0.40 0.40 956 8918 0.00 0.00 0.00 0.00 0.00 9.00 17.20 35.20 49.20 1.0 606 1725613
+1 94 1 1 3 2 1451 127 88 0.20 0.20 5870 33268 0.00 0.00 0.00 0.00 0.00 0.60 0.60 15.40 20.40 2.6 1993 1528734
+1 87 1 1 8 5 1833 311 160 1.80 5.99 332148 102369 0.00 0.00 0.00 0.00 0.00 4.19 5.39 156.49 238.72 6.0 2895 1599931
+1 95 1 1 33 47 956 85 72 0.20 0.20 190279 102313 0.00 0.00 0.00 0.00 0.00 0.60 0.60 47.80 43.20 2.6 1109 1537536
+1 81 1 1 14 4 3441 404 348 6.40 2.00 194491 41018 3.80 6.60 13.40 19.20 1.00 2.00 4.00 329.00 471.20 3.6 187 1710275
+1 94 1 1 2 0 834 68 72 1.40 1.60 7242 17194 0.00 0.00 0.00 0.00 0.00 2.79 2.99 79.84 104.99 3.6 573 1048361
+1 83 1 1 8 0 2967 372 288 3.39 1.39 208178 52085 4.38 7.77 7.77 0.00 0.80 1.59 2.19 192.23 281.08 1.7 233 1000888
+1 89 1 1 4 0 4017 268 190 0.60 1.80 449731 221130 0.00 0.00 0.00 0.00 0.00 32.20 46.80 42.60 101.80 4.6 813 1318486
+1 88 1 1 2 0 2988 191 151 1.00 2.60 30668 22032 0.00 0.00 0.00 0.00 0.00 1.60 1.60 77.00 109.20 5.6 449 1062632
+1 81 1 1 4 3 4345 352 222 1.00 2.40 471573 148396 0.00 0.00 0.00 0.00 0.80 5.60 6.40 57.60 251.40 1.0 551 1007046
+1 75 1 1 8 1 2340 221 99 5.99 7.39 282634 28684 4.39 17.96 47.50 89.62 3.39 15.97 17.56 321.56 595.81 3.2 127 1036955
+1 95 1 1 0 0 344 53 20 0.20 0.20 252379 11130 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 46.20 2.0 5524 1816099
+1 89 1 1 5 4 1923 280 224 0.80 1.20 12283 21171 0.00 0.00 0.00 0.00 8.60 14.00 22.40 77.60 190.20 1.0 1059 969250
+1 90 1 1 5 4 1098 189 292 0.40 1.80 21978 751823 0.00 0.00 0.00 0.00 0.00 0.40 0.40 33.20 53.00 1.0 634 960042
+1 86 1 1 1 0 1450 94 76 0.60 0.80 133560 144848 0.00 0.00 0.00 0.00 0.00 24.15 44.51 55.49 57.09 2.0 786 1711489
+1 85 1 1 2 0 401 36 38 1.60 1.60 93100 32813 7.20 20.40 43.00 69.20 0.00 7.80 13.80 141.80 137.80 2.0 158 1784021
+1 90 1 1 2 0 1125 250 134 2.40 1.40 300388 210751 0.00 0.00 0.00 0.00 0.00 1.80 2.80 131.60 192.20 3.4 622 1740842
+1 85 1 1 9 0 1366 136 84 4.40 4.60 203565 153111 0.00 0.00 0.00 0.00 0.00 8.40 15.20 216.20 395.20 4.2 1756 1755198
+1 79 1 1 22 19 3515 293 190 2.99 2.99 208287 57369 0.00 0.00 0.00 0.00 0.00 2.79 4.19 176.05 435.93 3.2 523 1017028
+1 93 1 1 2 0 1453 183 63 0.40 0.40 104451 17773 0.40 0.40 0.40 0.00 1.40 4.60 7.20 31.20 58.80 2.2 308 1114030
+1 65 1 1 55 75 3564 475 433 2.40 0.80 838904 847055 0.00 0.00 0.00 0.00 0.00 16.63 16.83 133.27 338.68 2.0 1726 996467
+1 89 1 1 14 11 625 143 75 1.00 0.60 348717 175042 0.00 0.00 0.00 0.00 0.00 0.60 0.60 55.60 78.60 3.2 4625 1832802
+1 72 1 1 47 45 6735 288 182 2.59 7.78 157424 177312 4.79 4.79 4.79 0.00 6.59 0.80 1.20 238.52 281.44 2.6 202 1382053
+1 79 1 1 11 1 3873 447 342 4.99 2.00 406849 69884 0.00 0.00 0.00 0.00 0.00 12.57 12.77 264.47 459.08 2.4 1513 1070647
+1 74 1 1 29 15 2799 438 181 10.42 7.82 537341 148680 4.61 13.83 17.03 19.24 13.63 4.01 9.62 402.20 838.48 4.0 311 1007726
+1 93 1 1 0 0 1743 122 71 0.40 0.40 89137 21834 0.00 0.00 0.00 0.00 0.00 0.00 0.00 29.60 34.20 2.2 2483 1700363
+1 58 1 1 14 0 4397 371 164 12.55 35.66 247839 21597 0.60 0.60 0.60 0.00 0.20 12.15 14.74 445.22 865.14 2.7 307 1074696
+1 97 1 1 1 0 426 30 105 0.40 0.40 6559 11362 0.00 0.00 0.00 0.00 0.00 0.00 0.00 37.00 40.20 3.2 955 1714613
+1 94 1 1 2 0 490 67 55 0.20 0.20 51759 49356 0.00 0.00 0.00 0.00 0.00 2.00 11.00 15.00 36.60 1.2 2958 1773195
+1 70 1 1 41 17 4739 739 662 7.00 4.00 574189 494152 16.60 66.80 102.60 316.80 4.00 7.20 23.40 331.40 552.00 2.7 118 1052146
+1 90 1 1 2 0 1317 73 55 1.60 1.60 35882 16564 0.00 0.00 0.00 0.00 0.20 14.60 15.80 99.80 157.20 2.8 906 1068621
+1 68 1 1 20 9 4406 560 440 9.80 9.40 412612 21369 3.20 3.40 3.40 0.00 0.20 16.80 30.40 487.60 736.40 7.2 394 1597472
+1 97 1 1 11 15 277 45 33 0.20 0.20 253502 33525 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 17.40 1.4 9219 1867472
+1 89 1 1 1 0 2324 202 89 0.40 0.40 59488 63951 0.00 0.00 0.00 0.00 0.00 1.00 1.40 34.93 36.53 1.6 3564 1769182
+1 95 1 1 0 0 567 90 61 0.40 0.20 334065 296521 0.00 0.00 0.00 0.00 0.00 0.00 0.00 23.20 23.00 2.6 992 1758486
+1 95 1 1 62 84 1034 71 54 0.20 0.20 92170 79203 0.00 0.00 0.00 0.00 0.00 0.20 0.20 64.74 38.65 2.8 1303 1844602
+1 1 1 1 13 9 1583 229 155 0.60 0.80 892724 877944 0.00 0.00 0.00 0.00 0.00 109.38 214.37 49.30 207.19 2426 73 26
+1 91 1 1 5 1 1259 183 171 3.20 1.00 103477 6816 0.00 0.00 0.00 0.00 0.00 0.00 0.00 165.20 231.20 1.4 5299 1860629
+1 88 1 1 14 7 2823 194 119 1.40 3.60 195576 114991 0.00 0.00 0.00 0.00 0.00 0.20 0.40 172.60 151.00 2.4 1996 1548301
+1 82 1 1 56 68 3702 395 153 2.60 4.20 455770 94304 0.00 0.00 0.00 0.00 0.00 5.60 10.60 174.00 286.80 6.6 2759 1603320
+1 86 1 1 8 1 4911 247 185 2.00 4.00 215402 41434 0.00 0.00 0.00 0.00 0.00 1.60 2.20 130.20 164.60 2.8 990 1538602
+1 0 1 1 1 0 3083 219 152 0.20 0.20 107127 81287 6.00 14.60 26.80 43.60 0.40 2.40 2.60 22.60 84.20 147 83 16
+1 86 1 1 6 4 1555 332 97 1.00 1.60 625533 55347 10.78 26.95 54.69 100.40 0.60 9.58 13.17 131.14 361.88 2.8 335 964810
+1 96 1 1 1 0 219 22 18 0.20 0.20 18596 19607 0.00 0.00 0.00 0.00 0.00 0.20 0.20 20.60 17.40 1.0 2814 1775373
+1 89 1 1 22 27 2694 286 94 2.20 2.40 151084 107315 0.00 0.00 0.00 0.00 0.00 0.40 0.40 90.80 156.80 3.0 920 1748875
+1 74 1 1 23 4 2637 398 298 5.99 3.19 197373 44202 0.00 0.00 0.00 0.00 0.00 8.58 8.98 273.05 474.85 1.4 585 1022631
+1 70 1 1 8 0 4171 556 512 8.00 2.20 410525 140796 0.00 0.00 0.00 0.00 0.00 0.40 0.40 382.60 562.80 3.4 454 1757598
+1 72 1 1 13 9 5911 184 181 3.60 9.40 75490 343226 0.00 0.00 0.00 0.00 0.00 1.00 1.00 269.40 305.20 3.6 998 1377794
+1 82 1 1 2 0 2140 170 142 1.40 1.40 280183 189646 0.00 0.00 0.00 0.00 0.40 25.15 34.93 77.05 237.13 1.2 677 1053309
+1 88 1 1 10 1 1693 133 228 1.00 0.80 208049 85099 0.00 0.00 0.00 0.00 0.00 24.80 46.20 69.80 133.80 1.0 818 1042898
+1 94 1 1 2 1 2849 173 94 0.20 0.20 249539 163404 0.00 0.00 0.00 0.00 0.20 1.60 1.60 24.60 68.00 3.4 3241 1341669
+1 80 1 1 28 6 2044 141 130 5.19 5.59 153223 32302 8.58 17.76 51.70 117.56 2.59 30.74 54.09 196.81 348.10 2.2 143 1055602
+1 84 1 1 4 1 3913 176 129 1.00 1.00 63044 33613 1.00 1.00 2.80 2.40 0.60 3.80 3.80 111.00 253.00 3.0 211 1089725
+1 87 1 1 36 11 2058 107 122 2.20 2.40 122788 35607 14.40 21.40 35.60 88.40 4.00 13.40 17.20 137.00 243.80 2.0 156 973878
+1 91 1 1 12 2 1150 95 87 1.40 1.60 108636 22667 1.00 1.00 1.00 0.00 3.20 12.60 13.00 113.00 168.00 1.0 333 1026162
+1 0 1 1 77 101 2680 373 289 3.19 2.99 276666 110753 12.57 40.32 112.38 222.36 0.00 8.38 14.97 182.24 380.24 109 77 23
+1 98 1 1 0 0 156 16 21 0.20 0.20 436 7606 0.40 0.40 0.40 0.00 0.20 0.00 0.00 15.77 17.17 1.0 256 1756335
+1 94 1 1 37 53 1471 71 68 0.20 0.20 5876 29047 0.00 0.00 0.00 0.00 0.00 8.80 8.80 15.60 40.80 2.0 845 1052512
+1 88 1 1 3 0 2724 214 178 2.20 1.00 263237 109902 0.00 0.00 0.00 0.00 0.00 1.20 1.20 106.20 212.40 3.2 853 1537499
+1 90 1 1 119 52 2129 201 168 0.39 0.39 140345 124347 0.00 0.00 0.00 0.00 0.00 2.16 3.54 53.05 74.66 1.0 910 1317084
+1 90 1 1 36 53 1730 158 151 1.20 4.01 31690 26367 0.80 0.80 0.80 0.00 0.20 15.23 17.43 62.32 131.46 1.2 323 1093624
+1 96 1 1 2 2 614 34 31 0.40 0.40 33362 17996 0.00 0.00 0.00 0.00 0.00 0.80 0.80 24.40 46.20 2.0 903 1074280
+1 89 1 1 12 11 820 170 97 0.80 2.40 277834 222616 0.00 0.00 0.00 0.00 0.00 0.60 0.60 41.20 51.80 3.4 4085 1828326
+1 91 1 1 1 1 2744 151 107 0.40 0.60 45621 57609 0.00 0.00 0.00 0.00 0.00 5.79 5.79 35.93 96.81 3.0 2365 1040741
+1 62 1 1 48 0 2778 235 111 11.80 34.00 171649 124322 13.40 26.20 21.40 0.00 1.60 10.20 15.60 413.40 762.20 4.7 181 1103187
+1 93 1 1 1 0 2163 249 147 0.40 0.20 8970 6914 1.80 1.80 1.80 0.00 0.40 0.40 0.40 16.37 32.34 3.2 161 1438344
+1 80 1 1 14 19 440 28 92 1.20 1.20 53079 609753 68.60 134.80 134.80 0.00 0.00 1.40 2.00 115.60 98.60 2.2 283 1783810
+1 81 1 1 15 1 3885 287 292 3.19 1.00 198469 81204 5.38 5.98 15.34 32.07 2.19 4.58 5.18 150.60 272.11 1.0 194 1049610
+1 68 1 1 17 6 4805 565 701 9.00 3.20 418659 75421 6.20 18.60 29.80 42.00 1.20 2.20 2.60 467.00 695.40 6.0 333 1439998
+1 87 1 1 86 47 2042 284 245 1.60 2.81 530893 179856 0.00 0.00 0.00 0.00 0.00 9.82 18.64 92.59 190.38 1.0 1319 1097717
+1 93 1 1 8 6 496 72 67 0.80 2.00 58479 49585 7.00 11.40 10.00 0.00 1.60 2.40 5.20 35.20 39.40 2.0 207 1719907
+1 0 1 1 139 89 1743 253 173 1.60 1.80 360018 101640 0.80 3.60 3.60 0.00 27.00 1.00 5.20 89.60 236.80 515 83 17
+1 86 1 1 1 0 3523 214 149 0.40 0.60 253210 121578 8.58 19.96 25.55 27.15 2.00 7.78 9.58 45.71 147.31 1.0 228 1112768
+1 79 1 1 28 14 3857 294 218 3.00 11.60 215408 170249 8.00 11.80 15.60 11.40 5.40 41.80 49.80 292.60 472.00 7.6 277 1313382
+1 71 1 1 36 7 2588 295 154 4.00 4.80 488771 61496 0.00 0.00 0.00 0.00 0.00 39.60 63.40 328.20 649.80 1.6 2335 951362
+1 93 1 1 1 0 1364 54 57 1.20 3.19 57963 21216 0.60 0.60 0.60 0.00 0.20 4.19 6.59 85.03 154.69 1.0 219 987281
+1 89 1 1 10 9 3305 179 161 0.80 1.20 23778 15635 0.00 0.00 0.00 0.00 0.00 6.20 6.40 65.00 96.40 2.4 1140 1458098
+1 88 1 1 4 4 2215 208 206 1.00 1.20 225023 60418 7.00 11.20 9.00 0.00 4.20 1.80 1.80 80.20 118.80 1.5 318 1101534
+1 88 1 1 30 41 1972 156 137 0.40 0.40 108058 183512 7.80 26.40 44.80 77.20 0.80 14.20 24.20 28.20 62.40 6.0 141 1053814
+1 92 1 1 7 1 2418 161 98 1.40 1.40 71746 51496 0.00 0.00 0.00 0.00 0.00 2.20 2.20 150.20 117.80 2.4 1103 1521163
+1 74 1 1 11 1 2230 129 101 7.40 22.60 111719 49997 0.60 0.60 0.60 0.00 0.00 3.40 4.00 279.20 531.20 2.2 506 1078693
+1 96 1 1 2 2 408 66 26 0.40 0.40 412546 18184 0.00 0.00 0.00 0.00 0.00 0.40 0.60 30.86 35.27 3.0 8132 1867545
+1 91 1 1 6 4 1754 183 131 1.00 2.81 78480 20040 0.40 0.60 0.60 0.00 0.00 7.01 7.41 84.97 112.63 1.3 250 1125440
+1 89 1 1 16 3 2012 154 151 2.20 4.00 104179 108236 0.00 0.00 0.00 0.00 0.00 4.60 9.80 199.40 196.20 3.2 1830 1531176
+1 87 1 1 4 0 578 43 28 1.40 1.60 102585 53515 0.00 0.00 0.00 0.00 0.00 4.80 8.80 116.80 154.20 1.8 1294 1751954
+1 91 1 1 1 0 3064 265 410 0.40 2.00 23293 50002 0.00 0.00 0.00 0.00 0.00 0.00 0.00 24.40 38.80 3.0 1765 1699619
+1 91 1 1 7 2 2320 158 172 1.00 1.60 16005 104078 0.00 0.00 0.00 0.00 0.20 22.60 22.80 72.20 148.00 2.5 1665 1072854
+1 93 1 1 43 59 3504 140 138 0.20 0.20 31397 92240 0.00 0.00 0.00 0.00 0.00 1.20 1.60 20.40 26.80 2.4 2601 1645296
+1 87 1 1 3 0 4364 172 182 0.40 0.40 116745 177014 2.40 15.80 35.60 333.80 0.20 2.20 2.20 39.00 78.40 3.4 159 1619979
+1 60 1 1 12 1 4607 387 288 11.80 34.40 199059 40730 9.00 32.00 43.00 54.80 2.00 13.40 16.60 386.00 737.00 1.6 158 1077451
+1 80 1 1 8 0 3540 382 347 7.39 2.00 187167 18673 0.00 0.00 0.00 0.00 0.00 0.00 0.00 347.90 500.60 2.8 8310 1860712
+1 71 1 1 7 1 3220 157 111 6.41 18.04 170836 67909 8.42 17.43 31.06 53.51 1.40 23.05 41.28 231.06 464.93 2.2 219 1078485
+1 90 1 1 8 0 1646 162 129 1.20 1.20 29000 67970 4.41 7.82 7.62 0.00 0.40 6.81 9.02 246.09 123.45 1.7 200 1073063
+1 58 1 1 24 0 6552 523 336 9.40 16.20 1159856 57651 1.80 20.80 105.40 241.80 7.20 38.00 57.00 361.20 855.00 3.2 281 1092915
+1 82 1 1 13 4 2682 229 241 1.20 2.60 203604 428823 6.80 13.00 14.60 10.00 1.20 21.60 36.20 85.60 171.00 3.4 355 1374622
+1 66 1 1 14 2 5636 651 529 5.80 2.80 521404 278252 0.00 0.00 0.00 0.00 0.00 15.60 42.20 356.80 548.00 4.6 1445 1038379
+1 80 1 1 70 61 5313 469 331 2.99 3.19 274212 274987 6.19 13.17 31.34 57.88 1.00 4.19 10.98 123.55 235.33 4.2 137 1330298
+1 0 1 1 2 0 1301 213 270 0.00 0.00 843248 718848 0.00 0.00 0.00 0.00 4.61 33.87 45.89 9.22 143.49 778 88 10
+1 95 1 1 26 37 1021 55 42 0.80 2.60 22395 5741 1.20 1.40 1.40 0.00 1.00 5.20 5.80 75.40 108.40 3.2 190 1442749
+1 97 1 1 0 0 134 10 8 0.20 0.20 1856 3830 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7226 1847216
+1 91 1 1 0 0 3180 235 166 0.60 0.60 218260 101942 0.00 0.00 0.00 0.00 0.60 2.00 2.00 112.20 73.20 2.6 1730 1413717
+1 90 1 1 18 13 1224 88 77 2.99 2.99 51124 23822 0.00 0.00 0.00 0.00 0.00 1.00 1.60 161.28 267.86 1.0 1053 1090694
+1 0 1 1 20 5 3424 638 278 5.20 2.80 836291 568945 0.00 0.00 0.00 0.00 0.00 2.20 2.60 224.80 453.40 841 82 18
+1 88 1 1 2 0 2224 249 186 1.00 2.99 203563 49821 0.00 0.00 0.00 0.00 5.39 3.99 5.19 87.23 121.76 2.2 339 1016750
+1 84 1 1 5 3 4509 291 182 1.00 1.60 138031 108618 0.60 0.60 3.00 8.00 3.60 0.60 1.00 90.60 125.60 1.0 149 1127822
+1 93 1 1 1 0 2332 146 144 0.20 0.20 12285 64453 0.00 0.00 0.00 0.00 0.00 0.40 0.40 21.20 53.80 1.0 731 1061085
+1 89 1 1 12 4 4961 165 141 1.00 1.00 125039 50388 0.00 0.00 0.00 0.00 0.00 12.60 15.60 70.80 142.60 3.2 831 1529981
+1 85 1 1 13 6 2243 161 116 1.60 3.39 194591 52749 10.78 31.34 48.50 109.58 3.79 43.91 44.91 164.07 224.75 2.5 141 1105448
+1 89 1 1 3 1 667 55 91 2.00 3.00 56315 138603 0.00 0.00 0.00 0.00 0.00 1.60 2.20 164.20 169.60 1.0 5601 1841586
+1 95 1 1 0 0 2140 80 77 0.40 1.00 2306 9377 0.00 0.00 0.00 0.00 0.00 0.00 0.00 28.60 33.20 1.2 1665 1708704
+1 76 1 1 35 34 2719 373 279 7.60 3.60 333360 10367 0.00 0.00 0.00 0.00 0.00 0.60 0.80 416.40 680.40 2.8 437 1728880
+1 82 1 1 6 1 3196 299 300 3.20 1.00 258950 352656 0.00 0.00 0.00 0.00 0.00 12.60 20.80 159.40 261.00 2.6 399 1382054
+1 88 1 1 2 0 2306 184 135 0.40 0.60 56480 71830 0.00 0.00 0.00 0.00 0.00 6.59 11.78 34.53 55.89 1.0 1172 1097932
+1 94 1 1 0 0 823 64 125 0.40 0.40 95754 20225 0.00 0.00 0.00 0.00 0.00 0.00 0.00 32.00 44.80 3.2 1298 1713150
+1 77 1 1 10 1 4046 500 389 7.40 2.40 618922 61134 0.00 0.00 0.00 0.00 0.00 0.60 1.00 365.80 524.20 3.4 8098 1834163
+1 93 1 1 11 3 1012 122 85 0.60 0.80 194793 28034 5.60 5.60 5.60 0.00 1.40 5.40 7.20 52.60 90.20 1.7 212 1026517
+1 98 1 1 1 1 181 14 13 0.20 0.20 7597 2540 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.17 23.35 2.0 9908 1866879
+1 92 1 1 0 0 2296 103 67 0.40 0.60 77486 18974 1.60 3.79 18.96 48.50 0.80 10.18 17.37 37.92 94.21 1.2 165 1011243
+1 98 1 1 0 0 821 43 20 0.20 0.20 3187 14115 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 1.0 1722 1780144
+1 90 1 1 4 4 1901 213 103 0.40 0.80 616593 504045 0.00 0.00 0.00 0.00 0.00 5.39 10.18 41.32 79.64 4.6 3058 1032533
+1 88 1 1 16 5 2158 156 107 1.20 3.40 161619 65233 0.00 0.00 0.00 0.00 0.00 10.60 14.60 67.60 283.60 5.4 1441 1313944
+1 83 1 1 70 92 4371 237 203 1.20 1.00 205153 71432 24.40 45.40 77.40 163.80 10.60 3.80 6.40 65.40 146.00 1.0 131 1003590
+1 86 1 1 40 54 3383 318 150 1.00 0.80 284086 43582 0.00 0.00 0.00 0.00 0.00 15.57 37.72 47.31 80.24 4.8 764 1106066
+1 91 1 1 3 2 1494 165 118 1.00 2.60 19279 19156 0.00 0.00 0.00 0.00 0.00 0.40 0.40 108.20 141.80 1.0 2094 1072672
+1 88 1 1 1 1 1996 218 112 0.40 0.40 195971 60009 13.35 84.66 127.69 201.99 1.99 52.99 67.33 33.67 159.36 2.0 155 1095359
+1 62 1 1 14 0 4895 693 480 10.00 14.60 323747 109589 6.40 16.00 51.20 106.40 1.20 14.40 19.20 428.60 763.40 1.5 136 1091562
+1 81 1 1 12 4 3825 352 315 6.00 2.00 173914 35915 0.00 0.00 0.00 0.00 0.00 0.00 0.00 297.60 441.00 3.8 2002 1719354
+1 73 1 1 20 4 2472 268 316 1.80 2.00 532635 766797 18.16 89.62 211.38 592.22 1.80 53.29 104.99 100.40 259.48 1.0 139 1024303
+1 91 1 1 22 17 1556 524 175 0.60 1.60 665917 637838 0.00 0.00 0.00 0.00 0.00 0.00 0.00 57.00 171.80 1.7 609 1045942
+1 90 1 1 4 2 2483 268 162 0.40 0.40 561018 286158 0.00 0.00 0.00 0.00 0.00 2.40 4.80 66.00 45.20 4.8 2622 1562976
+1 86 1 1 3 1 595 75 39 2.40 2.40 226201 34972 0.00 0.00 0.00 0.00 0.00 1.80 2.79 207.39 245.31 1.8 11125 1868394
+1 88 1 1 2 1 1956 121 108 1.20 3.60 104453 27160 0.00 0.00 0.00 0.00 0.20 1.80 2.00 85.00 197.40 1.4 890 1094987
+1 76 1 1 4 0 5359 331 195 4.41 4.61 212339 22073 4.01 5.21 9.82 13.83 1.60 30.26 43.09 153.31 392.99 1.2 196 999274
+1 98 1 1 2 1 217 15 17 0.20 0.20 25964 10572 0.00 0.00 0.00 0.00 0.00 1.60 3.21 20.24 17.23 1.2 8094 1866180
+1 92 1 1 0 0 1270 105 69 0.40 0.40 106063 26040 15.83 37.27 64.33 215.63 0.00 13.63 22.44 33.47 97.80 1.2 142 1014038
+1 80 1 1 3 0 677 95 48 3.20 3.20 385542 261097 0.00 0.00 0.00 0.00 44.80 7.60 13.60 304.40 345.60 2.6 3915 1810822
+1 94 1 1 12 12 1487 217 67 0.40 0.40 163884 143946 0.00 0.00 0.00 0.00 0.00 3.40 4.60 26.20 38.00 3.8 668 1742373
+1 78 1 1 2 2 3370 194 183 0.20 0.20 497987 355650 17.17 46.31 144.51 202.99 6.39 37.72 70.46 16.17 33.13 1.0 108 1123297
+1 97 1 1 17 25 189 20 17 0.20 0.20 9763 5724 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 17.00 1.0 8739 1834968
+1 95 1 1 26 38 370 69 21 0.20 0.20 339921 6853 0.80 0.80 0.80 0.00 3.40 0.00 0.00 15.60 29.80 1.4 136 1749590
+1 86 1 1 0 0 1665 117 80 0.40 0.80 4611 45409 0.00 0.00 0.00 0.00 0.00 1.40 2.20 35.40 47.60 2.6 433 1754104
+1 86 1 1 32 44 4496 572 466 0.20 0.20 35864 43328 0.40 0.40 0.40 0.00 0.00 2.81 3.81 18.84 66.73 1.0 203 1016794
+1 89 1 1 23 13 2766 146 118 1.40 1.40 167712 54865 0.00 0.00 0.00 0.00 0.00 4.60 5.80 81.60 218.40 2.8 8013 1385042
+1 64 1 1 66 59 5976 1045 991 4.99 3.99 1104612 829940 0.00 0.00 0.00 0.00 0.60 48.90 49.50 298.60 468.06 1.0 715 1115499
+1 95 1 1 2 1 262 30 20 1.00 1.00 63371 26554 0.00 0.00 0.00 0.00 0.00 1.40 2.80 81.60 75.40 1.0 8697 1834794
+1 92 1 1 35 45 1346 102 26 1.40 6.60 34154 22581 0.00 0.00 0.00 0.00 0.00 0.00 0.00 72.80 106.40 1.2 6841 1826680
+1 61 1 1 64 39 4298 575 343 15.80 11.60 463509 143596 4.60 9.60 9.00 2.40 6.20 5.00 6.80 651.20 1108.00 1.8 374 1043554
+1 89 1 1 6 2 1336 137 76 3.00 3.80 83576 66955 0.00 0.00 0.00 0.00 0.20 17.80 18.00 155.40 260.20 2.3 2708 1014373
+1 0 1 1 35 29 1418 178 129 1.40 6.40 511310 474767 7.60 12.00 11.80 0.00 2.20 6.60 11.80 43.60 86.80 205 90 10
+1 89 1 1 47 66 2379 174 103 0.20 0.20 316190 53327 0.80 0.80 0.80 0.00 8.40 1.20 1.20 21.60 96.40 1.5 163 1114024
+1 83 1 1 1 0 2550 251 144 0.60 2.00 348880 40837 3.61 13.23 106.41 216.03 0.80 47.29 92.59 55.71 116.23 3.8 184 1105180
+1 84 1 1 6 2 2649 257 199 2.20 7.58 72918 39879 0.80 1.00 1.00 0.00 0.40 40.72 42.12 114.77 243.71 2.0 331 1095416
+1 97 1 1 1 0 1275 51 54 0.20 0.40 2600 15749 1.00 1.20 1.20 0.00 0.40 0.00 0.00 26.20 31.40 1.2 236 1747384
+1 0 1 1 35 44 2500 76 65 1.20 1.60 10740 14939 0.80 0.80 0.80 0.00 0.20 0.80 0.80 96.60 124.80 144 91 8
+1 98 1 1 13 19 162 16 23 0.20 0.20 6777 13697 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 8366 1868345
+1 95 1 1 0 0 963 47 60 0.20 0.20 3269 38455 1.20 1.60 1.60 0.00 0.00 0.60 0.60 15.40 17.00 1.0 167 1750968
+1 92 1 1 4 0 2505 108 116 0.40 0.60 100645 67034 0.00 0.00 0.00 0.00 0.00 1.60 2.20 31.00 49.60 1.4 596 1058706
+1 94 1 1 1 0 1660 64 68 0.40 0.60 33268 84585 0.00 0.00 0.00 0.00 0.00 0.40 0.40 29.66 48.50 1.0 1270 1062068
+1 95 1 1 13 11 709 126 58 0.20 0.20 356875 135170 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 18.20 3.8 1392 1756062
+1 62 1 1 7 0 6386 990 892 6.40 5.60 738732 562838 8.60 28.60 54.40 118.40 1.20 9.40 11.80 353.80 519.60 1.0 285 1103182
+1 95 1 1 19 27 2061 90 106 0.20 0.20 88071 10311 0.00 0.00 0.00 0.00 0.00 0.20 0.20 22.40 17.20 2.2 690 1726904
+1 75 1 1 148 1 3940 305 251 3.20 1.00 82286 71429 5.60 9.60 7.20 0.00 0.20 141.20 142.40 151.00 236.20 1.5 252 1084762
+1 92 1 1 1 0 1283 125 445 0.20 0.20 17782 52520 0.00 0.00 0.00 0.00 0.00 0.80 0.80 20.20 26.20 2.4 829 1704290
+1 98 1 1 1 1 158 14 13 0.20 0.20 7637 5958 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7222 1847120
+1 81 1 1 51 68 2562 195 162 2.40 2.40 379087 50798 0.00 0.00 0.00 0.00 0.00 5.00 8.00 171.60 337.40 4.8 3418 1425371
+1 83 1 1 5 0 2183 370 340 0.40 1.80 113768 19844 0.80 0.80 0.80 0.00 1.60 3.00 15.80 37.40 52.60 1.6 364 1086010
+1 87 1 1 10 1 1849 166 171 3.18 3.18 98036 38009 0.00 0.00 0.00 0.00 0.00 1.39 1.59 182.90 250.89 1.0 418 1085931
+1 77 1 1 670 3 4831 181 118 3.60 4.80 152348 36710 0.00 0.00 0.00 0.00 0.00 24.00 24.60 153.20 268.80 1.4 2645 1712398
+1 78 1 1 4 2 4287 267 264 1.00 2.59 450609 441354 0.40 0.60 0.60 0.00 0.40 26.35 49.90 90.02 209.18 2.2 706 1244394
+1 63 1 1 41 0 4887 292 133 9.20 27.40 606890 39021 5.20 30.60 78.80 195.00 0.60 67.80 74.60 343.60 903.40 2.7 129 1095571
+1 86 1 1 3 1 2298 238 235 0.60 0.80 111211 392803 2.60 10.00 16.20 20.00 0.60 13.00 25.60 60.20 78.00 2.0 141 1375952
+1 95 1 1 1 1 1063 83 60 1.00 0.80 186842 16328 1.60 2.20 2.20 0.00 1.80 0.40 0.40 63.93 118.04 1.0 258 1016519
+1 92 1 1 13 8 876 83 62 0.80 0.60 40199 21695 0.00 0.00 0.00 0.00 0.00 13.17 26.95 64.87 121.16 2.4 749 971332
+1 92 1 1 4 4 2113 101 153 0.40 0.60 8068 356041 9.40 10.60 10.60 0.00 8.60 0.20 0.20 32.80 49.80 2.2 294 1391992
+1 80 1 1 7 0 2080 92 84 6.00 17.20 123799 38864 0.00 0.00 0.00 0.00 0.00 6.60 7.60 203.20 361.60 1.0 420 1082914
+1 90 1 1 0 0 2123 343 106 0.80 1.20 518845 579056 8.20 13.80 13.80 0.00 3.80 8.00 8.00 33.20 87.80 7.2 288 976629
+1 89 1 1 14 13 1844 180 97 1.60 3.21 43391 31850 0.00 0.00 0.00 0.00 0.00 0.60 0.60 125.85 228.66 1.0 1318 1087683
+1 97 1 1 1 1 971 43 51 0.20 0.20 103245 183485 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 17.00 1.4 4633 1827176
+1 93 1 1 4 2 1806 97 69 0.60 5.40 4959 7334 0.00 0.00 0.00 0.00 0.00 3.00 3.60 61.80 72.60 2.2 474 1383408
+1 75 1 1 71 34 4680 605 425 6.20 1.80 413769 77475 0.40 0.40 0.40 0.00 0.20 12.20 12.20 311.20 491.40 4.5 482 983392
+1 65 1 1 43 49 4750 969 331 6.60 4.40 522328 362630 48.00 95.20 104.40 26.20 1.20 12.80 14.80 347.00 540.40 2.8 214 1375587
+1 89 1 1 13 9 2548 188 118 0.60 1.00 136256 21993 0.00 0.00 0.00 0.00 0.00 0.60 1.20 52.40 136.40 1.8 1053 973027
+1 93 1 1 1 1 1028 49 48 0.20 0.20 93613 102306 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 1.2 8439 1837168
+1 96 1 1 0 0 895 113 43 0.20 0.20 254795 6673 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.80 19.20 1.2 5977 1863736
+1 86 1 1 2 0 1294 90 58 0.60 1.00 317298 49078 0.00 0.00 0.00 0.00 0.00 9.80 18.40 57.20 113.20 2.6 3725 1770955
+1 95 1 1 1 0 2574 104 101 0.80 0.60 12772 71645 0.00 0.00 0.00 0.00 0.00 0.20 0.20 34.00 41.55 2.0 622 1635033
+1 0 1 1 76 105 3310 229 182 0.20 0.20 104204 111076 6.00 8.60 12.40 13.00 2.00 4.60 6.00 17.60 55.80 136 84 15
+1 95 1 1 3 1 1057 134 43 0.20 0.20 27113 13876 0.00 0.00 0.00 0.00 0.00 1.40 1.60 18.40 25.60 1.6 495 1732306
+1 84 1 1 7 1 4364 331 155 1.80 4.00 73616 39495 1.20 3.60 11.80 16.60 0.40 6.60 6.60 91.60 188.40 1.5 155 1066408
+1 55 1 1 50 0 5031 397 239 14.20 34.80 150140 25263 2.00 7.40 13.40 20.40 0.80 17.80 20.60 545.20 999.80 1.0 187 1105467
+1 90 1 1 4 0 2989 191 144 0.80 0.60 72422 64404 8.00 15.60 15.40 5.80 3.40 4.20 5.60 39.40 76.60 1.0 231 1751608
+1 97 1 1 1 1 298 16 32 0.20 0.20 8934 128171 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 17.60 1.0 6876 1852733
+1 91 1 1 1 0 2399 197 150 0.40 0.60 255688 50220 0.00 0.00 0.00 0.00 0.80 4.99 8.38 30.54 47.50 3.8 418 1052332
+1 86 1 1 21 17 1662 274 218 5.20 3.20 379341 50010 0.00 0.00 0.00 0.00 2.80 0.40 0.40 231.00 346.00 2.8 1714 1748792
+1 79 1 1 84 47 2579 355 292 2.00 2.00 289199 192469 0.00 0.00 0.00 0.00 0.20 78.84 96.21 118.36 333.33 1.0 998 1093544
+1 97 1 1 2 0 954 85 95 0.20 0.20 36587 95983 0.00 0.00 0.00 0.00 1.00 0.00 0.00 15.40 51.80 2.4 1586 1538088
+1 80 1 1 11 1 3102 522 258 1.60 1.20 146669 55686 3.41 20.24 121.84 190.98 0.40 37.27 48.10 115.63 297.60 1.0 132 1089326
+1 98 1 1 6 2 194 14 22 0.20 0.20 7185 13113 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 17.00 1.0 7229 1864853
+1 49 1 1 52 1 5644 436 203 13.97 29.54 391968 28302 3.99 16.17 48.30 110.78 2.79 33.93 39.52 600.40 1138.72 2.8 193 1102157
+1 68 1 1 26 2 5900 1094 1036 5.40 2.60 1143194 743917 0.00 0.00 0.00 0.00 0.00 12.20 21.60 307.20 496.20 2.0 859 1055504
+1 73 1 1 22 13 3962 281 187 5.80 16.00 85048 103566 0.00 0.00 0.00 0.00 0.40 16.00 19.20 223.40 424.20 1.0 1082 1104157
+1 67 1 1 15 1 5274 647 664 8.00 3.80 417904 48173 0.00 0.00 0.00 0.00 0.00 3.40 4.80 427.00 681.80 5.8 1860 1725293
+1 90 1 1 13 10 1970 114 67 2.00 2.00 42776 22590 0.00 0.00 0.00 0.00 0.20 0.20 0.20 130.94 182.44 1.0 918 997309
+1 97 1 1 1 1 318 19 40 0.20 0.60 32972 12604 0.00 0.00 0.00 0.00 0.00 0.00 0.00 31.20 50.20 1.0 6454 1871424
+1 50 1 1 15 5 7183 845 609 9.98 6.99 314269 47208 8.78 75.45 107.39 212.18 1.60 10.98 14.37 533.13 874.25 8.6 241 1436899
+1 74 1 1 5 1 7488 364 278 2.20 4.20 380096 236477 5.60 17.60 28.00 44.80 7.40 9.00 13.40 172.80 326.40 1.0 218 1003992
+1 87 1 1 1 0 2474 126 158 1.20 1.60 82015 257281 0.00 0.00 0.00 0.00 0.40 6.60 11.00 82.60 227.40 1.8 490 1019664
+1 70 1 1 44 22 4240 653 500 9.40 4.00 282144 34164 5.00 20.20 38.60 102.20 0.80 3.20 3.60 473.00 761.60 1.5 197 969099
+1 64 1 1 13 1 4392 524 392 10.38 18.76 308510 22421 2.20 7.19 12.18 23.35 1.20 13.77 23.75 436.73 812.97 1.5 172 1107251
+1 94 1 1 2 0 668 51 129 0.60 0.60 7239 28933 0.00 0.00 0.00 0.00 0.00 0.00 0.00 56.20 58.00 2.6 1183 1718032
+1 89 1 1 3 1 2070 300 243 1.00 0.80 117702 26318 1.40 1.40 1.40 0.00 2.80 5.20 6.40 79.00 119.40 1.0 195 1103667
+1 84 1 1 4 0 746 284 50 2.20 2.20 173503 36933 9.20 10.60 19.40 27.00 0.00 4.80 8.00 171.40 191.60 1.8 183 1805030
+1 84 1 1 11 6 2292 218 158 1.20 3.00 131627 159328 0.00 0.00 0.00 0.00 18.60 3.60 3.60 102.40 177.60 1.0 562 1113438
+1 83 1 1 5 0 3811 297 136 1.40 2.80 138739 29632 0.00 0.00 0.00 0.00 0.00 16.80 22.80 125.40 198.00 3.2 906 1439373
+1 76 1 1 3 0 5748 321 185 2.81 3.21 184508 274579 0.00 0.00 0.00 0.00 0.60 20.64 37.68 182.36 326.65 2.8 1286 985836
+1 72 1 1 3 0 4119 277 251 1.80 1.80 233930 404746 4.19 7.39 16.97 18.76 0.20 14.17 14.17 113.37 378.44 3.0 315 997440
+1 65 1 1 16 2 5937 760 527 8.02 3.41 253970 146319 0.00 0.00 0.00 0.00 0.20 15.83 19.64 447.09 711.62 2.0 515 1000834
+1 96 1 1 1 0 293 28 18 1.40 1.60 37211 4523 0.80 1.00 1.00 0.00 0.60 0.00 0.00 69.34 102.20 1.4 291 1759290
+1 92 1 1 0 0 760 92 54 0.20 0.20 166118 48516 5.40 6.60 6.60 0.00 1.00 2.60 3.20 15.60 24.20 1.2 286 1752392
+1 78 1 1 30 2 2242 133 75 6.60 18.20 207579 25105 0.00 0.00 0.00 0.00 0.00 3.00 5.80 250.60 468.20 2.2 1668 1110758
+1 0 1 1 15 9 841 148 104 1.00 0.80 156734 17341 3.00 4.20 4.20 0.00 0.20 7.40 10.40 61.40 225.80 316 91 9
+1 0 1 1 4 1 1065 229 68 0.60 0.60 105847 17529 1.60 1.80 1.60 0.00 0.60 4.40 8.00 49.40 103.40 305 91 9
+1 98 1 1 0 0 128 8 9 0.20 0.20 979 5030 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 1.0 6946 1845040
+1 82 1 1 35 7 2362 261 156 3.80 3.80 151582 72259 13.40 21.00 71.40 84.60 3.20 29.80 38.80 168.60 338.60 1.0 188 1070666
+1 95 1 1 0 0 1947 70 89 0.20 0.20 3710 11642 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 16.80 2.0 1514 1726216
+1 92 1 1 30 42 1403 103 78 0.80 3.39 30929 36075 2.99 4.79 4.59 0.00 0.40 0.80 1.00 39.92 62.28 1.7 305 1102510
+1 94 1 1 0 0 1327 157 87 0.20 0.20 6109 31242 1.00 1.20 1.00 0.00 0.00 11.40 11.40 15.40 41.80 1.3 246 1129960
+1 93 1 1 2 2 1479 213 153 0.40 0.20 88759 45182 0.00 0.00 0.00 0.00 0.00 0.00 0.00 25.40 47.60 1.7 638 1120110
+1 79 1 1 285 79 2780 417 367 2.80 3.60 278259 312911 12.40 58.80 58.40 0.00 1.20 1.80 2.00 186.80 291.80 1.4 280 1066042
+1 90 1 1 7 2 3426 121 103 0.60 0.60 100253 53470 2.20 8.80 44.60 102.20 0.40 19.40 25.40 56.00 116.20 2.6 159 1519462
+1 80 1 1 18 12 2385 334 124 5.80 16.00 928637 33286 0.00 0.00 0.00 0.00 0.00 7.20 9.20 206.60 399.00 2.8 672 1097338
+1 90 1 1 5 2 929 64 109 1.20 2.80 21100 80970 12.60 23.20 22.80 0.00 9.20 6.40 10.60 103.00 110.60 1.0 381 1059995
+1 77 1 1 6 0 1510 77 29 5.40 22.20 146683 19155 0.00 0.00 0.00 0.00 0.00 0.40 0.40 314.80 447.00 2.6 760 1749810
+1 0 1 1 35 8 4319 388 295 5.16 2.78 359506 31978 1.98 3.57 3.57 0.00 4.76 27.18 35.91 339.09 496.83 478 71 28
+1 87 1 1 89 124 2416 191 121 0.60 0.60 420935 37668 3.19 3.19 3.19 0.00 3.19 23.35 27.94 59.08 213.77 1.0 244 1015669
+1 93 1 1 8 3 819 84 105 1.20 1.00 123070 102258 0.00 0.00 0.00 0.00 0.20 14.40 27.00 66.40 115.60 1.0 459 1063021
+1 87 1 1 2 1 3917 148 126 1.60 1.80 76308 115810 1.20 1.40 1.20 0.00 0.80 2.40 2.61 126.85 162.93 1.6 225 1019128
+1 86 1 1 45 0 1064 129 85 1.20 1.20 175785 30129 1.40 3.61 15.23 42.08 0.40 11.82 38.88 127.05 245.49 1.0 251 973562
+1 90 1 1 7 0 1924 177 133 0.40 0.60 354623 68081 3.00 4.80 4.60 0.00 2.40 3.00 26.20 90.20 119.60 2.0 206 968166
+1 93 1 1 1 0 996 291 203 1.20 3.60 100026 47886 1.00 1.20 1.20 0.00 0.00 0.20 0.40 50.20 99.20 4.2 209 1712002
+1 91 1 1 22 31 405 31 42 0.80 0.40 22336 41726 0.00 0.00 0.00 0.00 0.00 0.00 0.00 44.60 63.80 2.8 2112 1768477
+1 83 1 1 36 48 3604 509 225 2.20 6.80 1154894 714912 3.20 13.40 29.40 66.20 1.40 4.00 6.20 126.20 239.60 1.0 152 1042494
+1 0 1 1 7 4 813 125 126 0.40 0.40 87675 81946 21.96 32.14 100.80 142.91 11.98 24.75 50.10 33.33 138.12 127 89 11
+1 91 1 1 6 5 2383 194 136 0.20 0.20 9974 33744 0.00 0.00 0.00 0.00 0.00 0.20 0.20 16.60 36.40 2.4 1195 971432
+1 77 1 1 10 1 3107 446 377 9.20 3.00 352305 10765 0.00 0.00 0.00 0.00 0.00 0.00 0.00 480.20 668.00 1.6 8647 1866547
+1 78 1 1 55 65 2360 81 67 6.20 18.20 48147 72936 0.00 0.00 0.00 0.00 0.40 2.80 3.20 207.20 425.40 2.0 634 1082086
+1 98 1 1 0 0 243 21 19 0.20 0.20 52466 69040 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.97 1.0 6823 1850258
+1 88 1 1 1 1 506 166 91 0.20 0.20 274362 218621 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 3.0 4182 1829272
+1 0 1 1 3 2 1067 38 47 0.20 0.20 3671 26017 0.00 0.00 0.00 0.00 0.00 3.79 3.79 15.57 27.15 353 95 5
+1 94 1 1 1 0 1763 72 61 0.80 1.20 4240 9021 0.00 0.00 0.00 0.00 0.00 0.20 0.40 64.00 76.80 1.4 1345 1746206
+1 80 1 1 7 3 2933 494 317 4.00 2.80 704923 70100 0.00 0.00 0.00 0.00 0.00 4.40 5.20 198.40 305.40 2.0 624 1122808
+1 94 1 1 1 0 1186 94 45 0.60 2.20 29469 15838 0.00 0.00 0.00 0.00 0.00 0.20 0.20 50.20 77.40 1.5 652 1069200
+1 93 1 1 8 3 1159 148 118 0.80 1.00 111780 31354 3.39 5.79 11.18 34.53 0.80 4.59 9.58 49.10 104.59 1.5 157 966175
+1 93 1 1 12 11 589 124 50 1.00 0.60 419557 118856 0.00 0.00 0.00 0.00 0.00 8.40 16.00 78.20 268.60 3.4 6476 1834381
+1 95 1 1 1 0 1016 130 50 0.20 0.20 191891 24969 0.00 0.00 0.00 0.00 0.00 2.20 3.80 15.60 17.60 2.0 3427 1710080
+1 89 1 1 5 0 1812 99 55 5.00 3.20 78722 14526 0.00 0.00 0.00 0.00 0.00 0.20 0.40 211.60 332.80 1.4 1832 1753208
+1 96 1 1 0 0 1920 112 87 0.00 0.00 13273 53920 0.00 0.00 0.00 0.00 0.00 0.00 0.00 1.40 28.00 1.2 1950 1711416
+1 90 1 1 5 0 2406 331 97 0.60 2.00 968395 62250 0.60 11.80 28.00 66.40 0.00 7.00 34.60 47.20 123.80 1.4 240 1016227
+1 92 1 1 3 0 2547 131 144 0.20 0.20 8134 96050 0.00 0.00 0.00 0.00 0.00 2.60 3.00 15.80 49.40 2.5 381 1061312
+1 76 1 1 14 8 2121 194 100 5.80 19.40 254587 25724 4.80 23.20 55.40 117.00 0.20 29.20 55.20 193.20 373.60 2.0 138 1107872
+1 92 1 1 33 47 2060 143 113 0.20 0.20 93686 28812 1.00 1.20 1.20 0.00 7.80 1.40 2.40 15.80 35.00 1.8 288 1012149
+1 91 1 1 0 0 434 61 64 0.20 0.20 63282 58129 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 17.40 2.0 973 1761416
+1 96 1 1 0 0 2333 112 143 0.20 0.20 5050 25855 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 17.00 2.0 819 1720944
+1 92 1 1 43 58 1368 177 122 0.40 0.40 154537 119308 3.20 3.80 3.80 0.00 4.80 1.40 1.60 54.00 67.00 1.8 486 1514824
+1 99 1 1 0 0 175 16 37 0.20 0.20 1239 22025 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6169 1855848
+1 94 1 1 13 3 662 34 35 1.40 1.20 26150 5587 0.00 0.00 0.00 0.00 0.00 0.00 0.00 88.60 117.00 1.0 7405 1865309
+1 81 1 1 14 13 1642 194 201 0.40 1.00 587932 495713 0.40 0.80 0.80 0.00 0.40 55.09 105.99 31.34 68.06 1.0 645 1082777
+1 84 1 1 10 1 3817 232 181 3.60 2.20 173472 63448 0.00 0.00 0.00 0.00 0.00 0.80 0.80 272.80 282.80 3.0 2554 1643912
+1 97 1 1 2 1 243 27 28 0.20 0.20 1676 5507 0.00 0.00 0.00 0.00 0.00 0.20 0.20 21.36 33.33 1.0 7302 1861143
+1 87 1 1 4 1 3029 173 114 0.60 0.80 327541 46295 2.40 18.60 58.00 132.80 1.00 2.20 4.20 55.60 144.20 3.2 193 1523653
+1 64 1 1 52 0 2393 97 75 12.80 37.00 133167 34177 2.00 14.60 35.20 64.00 0.40 29.60 30.80 417.20 810.40 1.7 127 1091302
+1 90 1 1 3 1 565 74 42 1.80 2.00 178698 115623 0.00 0.00 0.00 0.00 0.00 2.80 3.80 186.20 152.60 1.0 5270 1839325
+1 81 1 1 2 0 517 71 28 1.80 1.80 362691 28190 16.40 46.20 182.20 432.40 0.00 40.00 77.40 153.40 240.40 2.6 131 1792312
+1 91 1 1 2 0 366 30 24 2.19 2.19 65134 22674 0.00 0.00 0.00 0.00 0.00 3.39 5.98 189.44 169.72 1.2 8010 1863272
+1 79 1 1 3 0 2792 341 251 2.40 3.39 758562 251742 0.00 0.00 0.00 0.00 0.00 21.76 40.32 149.70 278.24 2.8 598 1039615
+1 93 1 1 0 0 1191 44 39 0.20 0.20 3627 8428 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 4114 1776888
+1 59 1 1 44 1 4272 391 149 10.00 30.00 885549 53987 4.00 7.40 15.60 35.40 1.00 97.60 104.40 360.00 800.80 2.5 284 1099925
+1 80 1 1 3 1 561 83 26 1.40 1.40 511866 34420 7.40 29.80 90.00 245.40 0.00 58.20 115.20 123.00 267.20 2.6 367 1797285
+1 90 1 1 29 24 1994 189 116 1.40 1.60 97492 40908 0.00 0.00 0.00 0.00 0.00 18.84 20.24 91.38 187.58 2.0 585 981603
+1 96 1 1 0 0 1188 115 79 0.20 0.20 6090 20123 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.30 18.29 1.2 794 1059268
+1 0 1 1 27 5 6777 1208 535 9.00 5.40 623272 213540 10.40 17.20 25.40 23.60 6.80 7.40 11.80 467.60 756.00 233 62 38
+1 94 1 1 1 0 798 59 48 0.80 0.60 14801 15432 0.00 0.00 0.00 0.00 1.20 6.80 6.80 53.20 88.20 2.2 985 1718382
+1 99 1 1 0 0 156 10 14 0.20 0.20 2088 4065 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.63 16.83 1.0 7326 1867559
+1 96 1 1 37 55 846 70 81 0.20 0.20 21396 43922 0.00 0.00 0.00 0.00 0.20 0.20 0.20 15.80 25.40 1.0 703 1060514
+1 95 1 1 15 12 574 161 56 1.20 1.20 165041 135206 0.00 0.00 0.00 0.00 0.00 0.40 0.40 74.80 107.00 3.4 1896 1763454
+1 97 1 1 1 1 385 150 50 0.40 1.00 268276 228622 0.00 0.00 0.00 0.00 0.00 0.00 0.00 27.40 36.80 2.2 6835 1835978
+1 83 1 1 11 8 4602 739 638 2.20 2.20 423020 318145 6.40 13.40 19.80 31.60 0.40 7.60 13.20 102.60 171.40 2.4 230 1129762
+1 83 1 1 5 2 4650 466 237 0.40 0.80 166926 89156 1.20 13.60 33.00 68.60 1.40 31.00 31.40 31.20 250.00 7.2 371 1309459
+1 85 1 1 6 0 1899 222 92 4.79 2.99 299235 26325 0.00 0.00 0.00 0.00 2.99 2.59 2.99 186.43 387.43 1.0 1085 1053785
+1 89 1 1 4 1 419 43 13 2.20 2.20 80408 13554 0.00 0.00 0.00 0.00 0.00 2.40 2.79 217.17 180.44 1.2 11735 1883075
+1 82 1 1 3 0 548 63 39 2.40 2.40 231152 48871 0.00 0.00 0.00 0.00 0.00 2.20 2.20 183.00 264.80 2.8 1024 1789218
+1 87 1 1 28 40 3732 224 132 1.00 0.80 250893 27310 0.00 0.00 0.00 0.00 0.00 10.20 10.20 64.20 172.40 2.8 512 1383642
+1 97 1 1 1 1 280 45 13 0.20 0.20 259511 5734 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 17.00 1.6 5271 1856600
+1 94 1 1 19 29 2161 80 108 0.20 0.20 3948 12262 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 16.80 2.4 1361 1723224
+1 84 1 1 29 24 4334 393 204 1.00 1.00 301361 107213 0.00 0.00 0.00 0.00 1.60 20.60 21.40 63.00 251.80 6.0 1088 1322402
+1 87 1 1 3 3 2685 152 138 0.40 0.40 309122 26873 5.79 26.15 97.41 182.83 0.60 35.93 70.66 31.94 99.80 3.8 133 1702307
+1 88 1 1 11 8 1884 147 94 0.40 0.40 118121 53108 0.00 0.00 0.00 0.00 0.00 13.03 17.43 30.86 92.18 1.3 1104 1089499
+1 94 1 1 7 5 719 88 96 0.80 0.80 26625 22985 0.00 0.00 0.00 0.00 0.00 10.80 10.80 65.60 101.60 1.5 708 991186
+1 83 1 1 13 6 4688 129 120 1.80 8.40 51511 188157 0.00 0.00 0.00 0.00 0.20 1.80 1.80 142.00 182.40 2.4 405 1523059
+1 97 1 1 1 0 336 39 37 0.40 0.40 4079 8482 0.00 0.00 0.00 0.00 0.00 0.00 0.00 35.00 37.40 2.2 1066 1711875
+1 86 1 1 40 24 1444 155 117 3.00 3.80 128282 45359 5.80 10.00 17.20 15.40 1.40 7.40 11.80 199.60 302.60 2.0 253 1090144
+1 97 1 1 6 5 811 67 57 0.20 0.20 6642 23298 0.00 0.00 0.00 0.00 0.00 0.40 0.80 15.80 26.80 4.0 372 978118
+1 90 1 1 0 0 1773 289 150 0.40 1.80 1141912 86538 0.00 0.00 0.00 0.00 0.20 0.20 0.20 17.20 66.00 1.0 413 1036922
+1 88 1 1 5 3 3239 127 143 0.40 0.40 21107 210168 1.20 1.20 1.20 0.00 0.40 0.60 0.60 32.40 57.00 2.6 226 1519560
+1 97 1 1 0 0 552 77 43 0.20 0.20 93253 14041 0.00 0.00 0.00 0.00 0.80 0.00 0.00 18.20 17.80 2.0 896 1716600
+1 80 1 1 5 3 3768 293 179 3.00 5.00 111976 49759 6.20 22.80 91.00 164.20 0.60 8.60 9.80 204.80 426.40 6.0 114 1015811
+1 79 1 1 12 4 2173 246 110 7.20 19.80 26190 28608 1.80 9.80 28.20 69.40 1.20 5.20 5.40 248.80 461.00 1.0 138 1089453
+1 94 1 1 20 26 401 38 34 0.20 0.20 10085 11856 0.00 0.00 0.00 0.00 0.20 0.00 0.00 15.77 18.56 1.0 225 1740241
+1 76 1 1 23 13 4115 433 366 7.77 2.19 190173 28373 2.19 2.39 2.39 0.00 0.00 0.40 2.59 369.72 567.13 3.0 256 1070261
+1 78 1 1 16 1 3609 417 350 5.40 2.00 221199 68804 0.00 0.00 0.00 0.00 0.00 1.80 3.00 297.60 402.80 3.2 741 1530386
+1 84 1 1 16 13 896 72 69 0.60 2.00 146207 99210 0.00 0.00 0.00 0.00 0.20 0.60 0.80 105.40 77.60 3.8 973 1541157
+1 84 1 1 5 3 1855 183 122 0.60 1.20 100408 86305 6.20 11.60 9.80 0.00 0.00 26.40 42.00 107.60 175.20 1.3 647 1037645
+1 82 1 1 19 12 1486 335 193 2.40 7.40 522139 153118 0.00 0.00 0.00 0.00 0.00 9.00 17.60 149.80 187.40 2.2 2970 1737266
+1 88 1 1 3 0 2658 279 180 3.20 1.20 131446 38526 0.00 0.00 0.00 0.00 0.20 1.00 1.00 161.20 237.60 2.5 338 1125981
+1 97 1 1 30 39 246 26 23 0.20 0.20 661 10920 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 2972 1707112
+1 98 1 1 0 0 227 35 18 0.20 0.20 169774 12795 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.4 9243 1871237
+1 96 1 1 3 3 599 56 47 0.60 0.80 6105 17181 2.20 6.60 8.20 6.60 1.20 0.00 0.00 43.60 70.60 2.0 149 1023728
+1 80 1 1 14 0 2491 224 152 3.99 3.79 80285 25237 2.59 36.13 96.01 215.17 0.00 40.52 71.06 180.44 329.54 2.5 154 1052506
+1 90 1 1 15 7 1430 135 117 1.60 2.20 33236 19901 0.00 0.00 0.00 0.00 0.00 1.60 2.00 130.60 181.40 2.2 802 970798
+1 79 1 1 20 6 4048 498 162 2.20 3.40 100701 25574 0.00 0.00 0.00 0.00 0.20 60.60 63.80 129.20 366.20 1.7 918 981229
+1 83 1 1 13 5 4678 146 113 1.80 7.00 28663 94395 0.00 0.00 0.00 0.00 0.00 0.00 0.00 162.20 155.00 3.2 601 1644702
+1 67 1 1 27 18 6449 492 299 6.59 4.99 445690 72219 1.40 2.20 2.20 0.00 0.20 15.17 15.97 322.55 552.89 2.5 344 996402
+1 70 1 1 553 0 4259 189 136 2.40 2.60 376809 34697 12.80 154.80 523.00 1237.00 0.00 12.40 49.20 162.00 738.60 7.0 119 1319936
+1 98 1 1 0 0 229 24 21 0.20 0.20 1422 10540 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.57 17.17 1.0 1856 1750071
+1 85 1 1 2 0 2253 353 176 0.80 1.20 387419 31544 6.00 41.20 115.40 210.80 0.40 32.00 47.60 48.60 204.60 1.5 172 1050558
+1 55 1 1 162 176 7560 506 410 9.60 12.80 242465 86281 0.00 0.00 0.00 0.00 0.00 0.40 0.60 506.00 677.60 7.4 1351 1634653
+1 73 1 1 19 7 5937 338 185 2.40 8.60 310390 39939 0.00 0.00 0.00 0.00 0.20 3.40 4.40 209.80 272.00 5.8 3304 1548571
+1 96 1 1 0 0 1030 72 36 0.20 0.20 101884 8637 0.00 0.00 0.00 0.00 0.00 4.80 9.60 18.00 16.80 1.2 5737 1833264
+1 93 1 1 57 0 687 21 22 1.80 3.01 303675 57878 0.00 0.00 0.00 0.00 0.00 12.83 55.71 121.04 162.73 1.4 6912 1860856
+1 81 1 1 24 2 2721 295 245 6.01 4.01 219240 63103 4.41 5.21 27.05 43.49 0.60 1.60 12.22 269.54 456.51 2.6 265 1113138
+1 99 1 1 0 0 135 8 10 0.00 0.00 981 8307 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.80 3.61 1.0 12012 1892571
+1 84 1 1 43 59 2362 386 356 2.99 2.59 279958 193793 0.60 1.20 13.37 34.53 0.60 0.80 1.40 156.29 237.33 2.5 150 1090135
+1 84 1 1 65 82 1599 98 92 2.80 4.80 166910 98679 0.00 0.00 0.00 0.00 0.00 8.20 14.00 156.60 252.00 3.0 1842 1542608
+1 89 1 1 4 1 2632 439 108 0.80 1.40 520684 85619 7.19 14.37 14.37 0.00 4.79 15.77 16.17 56.69 125.15 5.2 303 974881
+1 97 1 1 1 0 207 13 14 0.80 1.20 11109 6958 0.00 0.00 0.00 0.00 0.00 1.00 1.60 69.00 60.40 1.0 8805 1871411
+1 95 1 1 3 2 2130 114 137 0.40 0.40 4434 28432 0.00 0.00 0.00 0.00 0.00 0.00 0.00 34.60 40.00 2.2 737 1728022
+1 0 1 1 13 10 2259 214 181 0.60 3.00 99277 40755 0.00 0.00 0.00 0.00 0.00 4.60 8.60 27.20 52.00 547 90 10
+1 87 1 1 3 1 494 58 43 2.20 2.20 196572 50883 0.00 0.00 0.00 0.00 0.00 1.40 1.40 183.60 215.80 2.4 11075 1873811
+1 91 1 1 8 4 1382 178 128 0.40 0.40 95104 20338 0.00 0.00 0.00 0.00 0.00 42.91 44.71 42.51 139.52 1.4 686 974373
+1 83 1 1 335 242 2930 274 590 0.20 0.20 24372 228660 6.00 9.60 9.60 0.00 3.60 51.20 51.20 15.60 33.00 2.2 338 1713718
+1 90 1 1 1 0 255 28 26 0.40 0.60 104467 22583 0.00 0.00 0.00 0.00 0.00 1.20 2.00 34.80 48.00 2.0 454 1746654
+1 92 1 1 4 1 2360 155 102 0.80 0.80 23647 28846 0.00 0.00 0.00 0.00 0.00 1.40 1.40 48.00 71.80 1.8 1520 971381
+1 62 1 1 53 1 2824 180 129 12.97 34.73 177009 23091 0.00 0.00 0.00 0.00 0.00 66.67 70.26 439.12 891.62 4.4 665 1105410
+1 84 1 1 46 61 2650 143 112 1.40 4.00 58112 39991 12.60 32.00 47.40 62.40 0.80 21.80 32.80 159.60 278.00 1.6 298 1053496
+1 88 1 1 57 75 2117 313 205 0.80 1.40 232233 84426 4.01 8.02 14.43 18.24 4.01 3.61 5.21 78.36 142.08 2.0 133 1055830
+1 88 1 1 2 0 2065 296 325 0.40 0.60 109498 26175 0.00 0.00 0.00 0.00 0.80 0.20 0.40 44.69 171.34 1.3 1527 1023142
+1 89 1 1 31 17 1373 130 81 2.80 5.00 152019 94826 0.00 0.00 0.00 0.00 0.00 0.60 0.60 184.00 277.60 2.8 1606 1537723
+1 0 1 1 13 0 3170 531 326 1.00 1.40 191399 60890 4.61 8.42 30.66 43.89 0.80 15.43 27.45 52.30 218.64 138 85 15
+1 81 1 1 171 4 2428 195 144 0.60 0.80 657219 14586 5.40 61.00 139.20 404.80 0.40 67.20 141.00 50.20 197.80 5.6 127 1347790
+1 89 1 1 2 1 3560 195 195 0.20 0.20 64062 44007 2.40 4.60 4.20 0.00 0.20 4.20 4.20 17.00 43.60 1.3 172 1052894
+1 81 1 1 20 0 4094 357 261 4.00 1.80 438359 122338 0.00 0.00 0.00 0.00 0.80 6.60 10.20 197.20 464.80 1.2 1086 1057803
+1 72 1 1 22 4 3675 661 464 7.00 3.40 353396 189025 0.00 0.00 0.00 0.00 0.00 0.20 0.20 345.00 635.20 1.0 890 1010875
+1 97 1 1 1 1 388 182 45 0.20 0.20 332374 292317 0.00 0.00 0.00 0.00 0.00 4.00 8.00 15.60 26.00 2.0 5882 1834992
+1 77 1 1 1 1 5950 209 197 1.20 3.20 164470 108426 10.60 21.80 29.40 23.00 1.00 5.40 6.00 70.60 212.00 3.0 152 1447282
+1 78 1 1 17 15 7659 1073 149 1.00 0.60 1274680 64552 7.60 26.60 64.00 115.40 0.80 19.40 25.20 107.20 190.80 1.4 163 997478
+1 74 1 1 33 5 3679 349 285 3.99 2.99 483452 152847 1.00 1.20 1.20 0.00 0.60 11.58 11.98 198.80 505.59 2.0 594 983668
+1 97 1 1 2 1 221 38 26 0.20 0.20 87720 6324 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.56 18.56 1.2 7364 1861736
+1 79 1 1 4 1 2922 182 235 0.80 3.60 602110 663645 0.80 1.60 1.60 0.00 0.40 37.40 66.60 46.80 110.00 2.8 481 1037405
+1 91 1 1 2 0 2276 149 158 1.00 0.40 101233 110252 0.00 0.00 0.00 0.00 0.00 0.80 0.80 53.20 93.00 1.0 401 1062278
+1 55 1 1 36 0 5542 652 483 13.03 7.01 394254 20627 8.62 24.65 59.32 178.36 1.80 15.03 23.25 673.55 1069.74 1.0 184 969985
+1 83 1 1 9 2 6177 232 182 1.60 1.60 133249 65281 3.99 5.79 5.19 0.00 0.80 2.40 2.99 113.57 174.25 3.4 259 1458397
+1 86 1 1 14 11 3911 205 162 1.60 0.60 56870 76075 1.20 2.40 2.40 0.00 0.60 3.80 4.80 88.80 154.00 2.8 1010 1011650
+1 94 1 1 2 1 1194 222 89 0.80 1.00 195188 24373 1.60 2.81 2.20 0.00 6.41 1.00 1.00 68.74 102.00 1.7 286 1027902
+1 91 1 1 1 0 2180 249 178 0.60 0.40 91820 39871 0.00 0.00 0.00 0.00 0.80 1.80 2.40 40.40 67.00 7.2 560 1096173
+1 92 1 1 2 0 370 38 30 2.00 2.00 108142 20247 0.00 0.00 0.00 0.00 0.00 1.40 1.40 179.60 155.00 2.0 4691 1848902
+1 81 1 1 43 59 3849 179 134 2.00 3.99 242114 51145 0.00 0.00 0.00 0.00 0.40 6.19 9.58 146.11 233.53 1.0 405 1018470
+1 57 1 1 16 0 4800 430 220 13.20 31.00 1009348 44725 3.00 10.40 26.00 90.00 10.60 12.20 13.40 466.00 853.00 4.5 174 1098397
+1 95 1 1 2 1 1584 95 113 0.60 0.60 44283 95737 0.80 0.80 0.80 0.00 0.80 0.80 1.20 95.40 46.40 2.0 272 1535600
+1 92 1 1 10 5 1185 126 80 0.80 1.00 130493 25628 2.81 7.41 11.42 44.89 2.00 2.00 3.61 54.51 121.84 1.0 295 977643
+1 91 1 1 1 0 3841 296 134 0.20 0.20 19987 52794 0.00 0.00 0.00 0.00 0.00 1.60 1.60 20.00 21.00 2.0 4644 1730949
+1 79 1 1 10 2 3408 397 306 5.20 2.20 196093 14080 1.80 2.40 2.40 0.00 1.60 0.80 0.80 249.40 417.40 3.0 236 1435354
+1 95 1 1 34 43 793 55 50 1.00 0.40 34368 22420 0.00 0.00 0.00 0.00 0.00 0.00 0.00 54.00 83.00 2.0 5398 1680534
+1 94 1 1 0 0 302 33 61 0.20 0.20 36566 50719 0.00 0.00 0.00 0.00 0.00 0.60 0.60 15.57 16.77 1.0 2729 1768495
+1 91 1 1 2 0 2338 197 91 1.20 1.60 187157 37649 0.00 0.00 0.00 0.00 0.00 4.59 12.77 93.21 162.67 1.0 433 1063786
+1 96 1 1 4 3 622 64 50 0.60 0.80 2705 21780 2.00 2.00 2.00 0.00 1.40 2.00 2.00 43.40 68.20 2.3 303 1023552
+1 93 1 1 0 0 2376 87 69 0.20 0.20 2851 3983 0.60 0.60 0.60 0.00 0.00 0.60 0.60 15.20 16.80 2.0 316 1709720
+1 97 1 1 0 0 261 51 35 0.20 0.20 270982 20290 0.00 0.00 0.00 0.00 0.00 1.80 2.61 16.23 21.84 1.4 8318 1868621
+1 72 1 1 37 4 3418 305 186 7.20 20.20 176489 65081 7.40 15.40 23.40 27.40 1.80 25.80 28.20 257.20 504.20 1.0 185 1093237
+1 89 1 1 2 0 2214 104 87 0.80 1.60 30187 59706 0.00 0.00 0.00 0.00 0.00 35.80 36.20 63.40 152.20 4.0 544 1017939
+1 95 1 1 4 1 653 81 91 1.60 0.60 40388 20918 0.00 0.00 0.00 0.00 0.00 0.00 0.00 85.60 119.20 1.0 7203 1874077
+1 87 1 1 6 4 1263 154 97 1.40 2.99 449239 28906 4.39 36.33 49.50 112.38 6.79 2.59 3.39 112.97 251.10 3.0 193 1057043
+1 69 1 1 21 2 5002 588 483 9.18 3.19 469386 35692 7.39 13.77 27.15 48.10 2.99 2.59 2.79 467.27 740.92 1.8 226 1010475
+1 86 1 1 4 2 2741 250 155 0.80 1.20 768769 116500 1.00 1.20 1.20 0.00 2.59 9.78 9.98 74.85 303.19 1.2 323 1018675
+1 95 1 1 1 0 3150 97 89 0.20 0.20 17502 68238 0.00 0.00 0.00 0.00 0.00 1.20 1.20 14.80 18.00 2.2 2484 1644968
+1 90 1 1 22 19 924 96 70 1.60 2.00 22095 21418 0.00 0.00 0.00 0.00 0.00 12.40 16.00 115.40 175.40 1.0 599 1017939
+1 54 1 1 17 1 6877 598 407 12.60 23.40 619940 76187 9.60 27.60 61.00 86.60 6.80 30.00 32.60 477.20 889.40 2.7 147 1097533
+1 93 1 1 28 38 2089 139 132 0.60 0.60 39676 74809 0.00 0.00 0.00 0.00 0.00 6.00 7.00 45.20 125.60 2.7 2041 1860174
+1 90 1 1 3 1 2018 159 118 1.00 1.00 116293 62743 0.00 0.00 0.00 0.00 0.00 8.20 12.60 90.00 111.20 2.8 2997 1419893
+1 95 1 1 1 0 2180 109 153 0.20 0.20 8008 17867 0.00 0.00 0.00 0.00 0.20 0.60 0.60 15.40 16.80 3.4 1334 1724854
+1 90 1 1 2 0 1887 58 47 1.40 4.20 48685 6603 0.00 0.00 0.00 0.00 0.00 5.60 10.80 42.80 69.40 1.6 4586 1828430
+1 0 1 1 20 6 5112 629 541 8.18 3.39 309676 39994 2.59 4.19 4.19 0.00 1.00 6.19 7.58 536.93 588.62 225 69 31
+1 89 1 1 9 0 1448 217 193 4.00 3.00 102838 7053 0.00 0.00 0.00 0.00 0.00 0.00 0.00 219.00 297.60 2.0 6283 1724059
+1 84 1 1 10 1 2691 267 237 3.60 1.20 121579 50442 1.80 2.80 2.40 0.00 0.20 5.40 8.60 162.60 290.80 1.3 374 1003082
+1 86 1 1 0 0 2061 150 104 0.20 0.20 48089 87253 0.00 0.00 0.00 0.00 0.00 2.00 3.20 13.80 24.00 2.6 722 1769267
+1 83 1 1 76 85 4335 281 203 3.60 3.20 203259 34160 1.60 2.00 2.00 0.00 0.20 13.60 15.20 196.00 347.60 5.4 292 1523802
+1 68 1 1 30 9 6933 216 120 4.20 15.40 193186 13480 4.00 4.60 4.60 0.00 4.80 3.20 21.20 396.20 465.20 6.4 359 1322592
+1 92 1 1 7 2 1575 177 131 0.80 0.40 190860 27291 0.00 0.00 0.00 0.00 0.00 2.00 2.40 55.20 89.60 2.2 661 1103814
+1 85 1 1 6 3 3247 1153 1135 0.40 0.40 16695 30315 5.40 13.40 68.20 119.00 0.80 2.00 2.00 36.20 254.80 1.4 374 954331
+1 96 1 1 0 0 905 57 47 0.60 0.40 56722 10728 0.00 0.00 0.00 0.00 0.00 4.20 8.40 33.20 39.80 1.0 5813 1818853
+1 90 1 1 2 0 1275 91 65 1.80 1.80 263192 102294 0.00 0.00 0.00 0.00 0.00 2.61 4.21 156.91 143.29 1.8 6572 1856228
+1 64 1 1 39 0 3920 291 155 9.98 29.74 509907 56912 5.59 7.19 6.99 0.00 0.80 6.39 7.39 323.35 621.56 2.8 298 1087858
+1 95 1 1 9 5 728 72 75 0.60 1.00 4942 57669 5.19 7.78 6.99 0.00 0.40 1.00 1.00 55.29 72.46 2.0 381 1089528
+1 94 1 1 7 6 819 91 46 0.20 0.20 194325 24819 1.00 1.40 1.40 0.00 1.60 15.60 15.60 20.60 206.60 2.0 205 969859
+1 84 1 1 28 21 2482 200 100 5.77 3.98 33090 44927 0.00 0.00 0.00 0.00 0.00 1.79 1.79 225.65 363.82 2.0 743 985194
+1 92 1 1 1 0 1448 150 127 0.20 0.20 8504 54101 0.00 0.00 0.00 0.00 0.00 11.40 11.40 21.40 49.80 1.0 1167 1068462
+1 94 1 1 2 0 2276 166 118 0.40 0.60 29704 23901 0.00 0.00 0.00 0.00 0.20 7.82 8.02 46.69 93.99 2.0 1352 1075373
+1 55 1 1 16 2 7472 815 570 12.77 9.98 428576 117636 7.98 12.57 26.75 29.34 1.60 4.39 5.59 629.74 967.27 1.0 274 996176
+1 84 1 1 86 106 2765 294 132 2.20 3.20 813180 55605 0.00 0.00 0.00 0.00 0.20 36.00 38.20 184.20 329.80 1.8 822 1050037
+1 65 1 1 46 16 4730 413 272 9.40 10.00 249982 110365 0.60 0.60 0.60 0.00 0.40 34.40 50.40 596.60 941.00 11.0 645 1311661
+1 82 1 1 4 0 3843 574 530 4.20 1.20 381660 302440 4.00 9.00 20.80 34.60 0.20 0.00 0.00 191.80 301.80 2.5 164 1004674
+1 79 1 1 19 7 3762 216 131 3.00 8.20 302582 73496 0.60 0.80 0.60 0.00 0.00 4.40 5.00 271.80 359.60 3.8 441 1527320
+1 88 1 1 4 0 2584 192 121 1.80 1.80 293863 105193 0.20 0.20 0.20 0.00 0.40 0.80 1.40 131.60 185.40 3.6 292 1530752
+1 88 1 1 3 0 2299 308 107 1.40 1.40 128515 32200 0.00 0.00 0.00 0.00 0.00 5.60 8.20 97.40 147.40 2.7 1237 1058554
+1 97 1 1 3 0 513 52 61 0.60 0.60 5028 38652 0.00 0.00 0.00 0.00 0.00 0.20 0.20 41.20 46.20 1.5 373 1091149
+1 94 1 1 7 3 439 49 58 0.80 1.40 3877 23938 0.00 0.00 0.00 0.00 0.00 0.20 0.40 51.80 118.20 2.2 6333 1701510
+1 78 1 1 25 12 3656 383 211 3.56 5.35 420694 70994 3.17 7.33 29.90 44.75 5.15 13.27 16.24 229.31 404.36 1.5 330 1088813
+1 87 1 1 53 65 1017 176 68 3.19 2.99 81296 8662 2.00 3.99 3.19 0.00 4.79 11.38 11.58 136.93 257.09 3.0 511 1707930
+1 84 1 1 45 59 2782 164 120 1.40 3.00 141984 48006 0.00 0.00 0.00 0.00 0.00 1.80 2.20 129.20 256.00 1.0 1097 1057458
+1 87 1 1 0 0 1326 114 58 0.20 0.20 37952 38662 2.40 3.80 3.40 0.00 2.80 15.60 15.60 15.20 21.80 2.4 265 1741510
+1 94 1 1 2 1 1563 58 37 0.60 0.60 27841 7395 0.00 0.00 0.00 0.00 0.00 0.20 0.20 45.69 44.69 1.4 8415 1868611
+1 80 1 1 12 8 4746 239 175 1.40 2.40 115480 41224 0.20 0.20 0.20 0.00 0.00 13.80 25.20 140.20 306.60 1.0 406 987694
+1 87 1 1 35 39 700 150 56 2.00 2.00 82631 8659 0.00 0.00 0.00 0.00 0.00 10.60 11.00 77.00 133.40 2.6 534 1745819
+1 51 1 1 15 0 5893 492 268 11.38 30.54 405715 45200 6.99 40.92 79.64 741.32 9.78 25.35 29.14 447.50 969.86 2.5 129 1087794
+1 80 1 1 14 0 2664 340 323 6.20 9.00 67387 26099 4.00 4.20 5.60 3.20 0.40 2.80 4.40 477.00 446.60 1.0 237 1089926
+1 85 1 1 1 0 1943 166 167 0.20 0.20 254381 289243 33.00 70.60 93.20 60.40 0.20 26.00 54.20 15.60 25.20 4.4 138 1599682
+1 88 1 1 0 0 906 66 78 0.20 0.20 22117 108214 0.00 0.00 0.00 0.00 0.00 1.20 2.20 15.60 17.00 2.2 4101 1776888
+1 94 1 1 8 2 1095 80 76 0.20 0.20 234011 61095 0.00 0.00 0.00 0.00 0.00 7.20 9.60 29.80 49.60 2.6 1328 1540717
+1 83 1 1 8 1 5297 409 274 2.61 1.00 58800 34122 1.60 1.60 1.60 0.00 0.80 0.20 0.20 134.27 222.44 1.6 150 1067618
+1 78 1 1 20 14 4276 270 167 2.60 9.00 259286 33552 0.00 0.00 0.00 0.00 0.00 14.80 26.20 231.00 261.60 5.0 1330 1640848
+1 87 1 1 15 5 1421 148 97 1.60 2.80 215537 45333 1.40 2.00 2.80 3.00 1.40 24.00 38.60 77.00 204.60 2.3 303 950886
+1 67 1 1 45 0 2337 117 67 11.40 33.00 158274 70992 8.00 22.00 23.80 26.60 5.20 11.40 16.60 377.60 721.20 2.5 327 1104586
+1 87 1 1 12 10 2124 128 94 0.60 1.40 126181 49317 2.00 2.20 2.20 0.00 0.40 5.20 6.60 65.00 141.20 3.6 352 1025507
+1 93 1 1 1 0 1054 39 43 0.20 0.20 10008 10321 0.00 0.00 0.00 0.00 0.00 0.80 1.80 32.80 23.80 2.0 443 1744632
+1 97 1 1 0 0 159 9 10 0.20 0.20 682 7433 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.0 1849 1777844
+1 84 1 1 4 1 3334 262 179 3.00 2.60 233666 72812 2.00 3.40 3.40 0.00 5.00 1.40 1.60 150.80 244.20 2.5 175 1018566
+1 88 1 1 4 3 3282 257 187 0.80 0.80 64145 281762 5.00 6.80 9.20 5.80 1.60 3.20 5.20 46.80 80.00 2.8 134 1010344
+1 87 1 1 1 0 2409 113 149 0.40 0.40 224873 40149 0.00 0.00 0.00 0.00 0.00 34.60 58.40 35.80 127.80 3.2 4218 1723419
+1 94 1 1 0 0 315 31 34 0.20 0.20 1491 8278 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.20 16.80 1.2 1023 1761680
+1 64 1 1 26 11 7797 638 360 3.40 9.00 418175 137794 0.00 0.00 0.00 0.00 0.80 13.20 13.40 259.80 449.40 5.0 2825 1544000
+1 75 1 1 123 122 4374 477 383 8.18 3.59 271392 13229 0.00 0.00 0.00 0.00 0.00 0.40 0.40 391.82 614.37 4.0 2251 1399210
+1 86 1 1 125 135 5182 436 302 0.20 0.20 454076 182538 0.00 0.00 0.00 0.00 0.00 49.50 59.08 15.57 108.38 5.2 1357 1331511
+1 96 1 1 2 0 726 76 81 0.40 0.80 75929 76281 0.00 0.00 0.00 0.00 0.00 13.00 21.20 32.60 50.80 2.5 632 1059584
+1 94 1 1 3 0 1204 73 91 1.00 1.60 109982 21147 0.00 0.00 0.00 0.00 0.00 2.20 2.20 152.40 153.40 1.0 834 1048877
+1 77 1 1 16 10 1984 331 224 2.79 2.59 87876 31361 37.33 94.81 198.40 504.99 0.40 86.23 167.66 208.18 433.53 1.0 114 989970
+1 90 1 1 3 0 2484 181 82 1.60 3.61 127530 49770 0.00 0.00 0.00 0.00 0.00 5.01 5.21 131.46 181.76 2.0 536 1068205
+1 87 1 1 1 0 4146 275 190 1.20 3.40 823128 82198 8.80 14.40 10.20 0.00 0.80 1.60 2.40 46.40 70.00 2.8 269 1752118
+1 83 1 1 10 4 1977 214 129 1.00 1.00 288196 84397 2.99 8.98 12.77 23.95 4.19 3.59 6.39 208.98 325.75 1.0 326 1116013
+1 90 1 1 2 1 422 73 44 1.00 1.00 276333 259294 0.00 0.00 0.00 0.00 0.00 2.40 4.80 73.40 76.20 2.2 3462 1822493
+1 89 1 1 18 16 2304 506 238 1.00 1.00 576576 492864 6.20 10.20 9.60 0.00 9.40 0.80 0.80 80.60 82.00 1.6 621 1044544
+1 91 1 1 5 0 1321 131 91 1.00 0.80 103867 26989 0.00 0.00 0.00 0.00 0.60 0.00 0.00 192.60 183.40 1.0 447 978733
+1 98 1 1 0 0 172 14 12 0.20 0.20 579 5428 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 1857 1784970
+1 93 1 1 1 0 1284 147 80 0.20 0.20 103627 18532 0.00 0.00 0.00 0.00 3.20 1.20 1.20 33.80 102.60 1.6 395 1060934
+1 78 1 1 7 1 2808 386 377 6.41 3.61 197062 151607 10.42 24.05 72.95 189.38 0.00 2.00 2.00 286.57 571.74 1.0 148 968997
+1 83 1 1 55 52 7418 2503 2485 0.80 0.60 39717 60613 3.19 4.39 6.99 8.18 0.40 3.59 10.18 33.13 69.46 3.4 153 971222
+1 88 1 1 3 2 1893 204 151 0.80 0.80 224155 58290 12.20 29.40 31.60 31.20 0.60 15.20 22.20 36.60 97.00 3.0 167 1135840
+1 88 1 1 10 2 2180 308 162 2.00 1.80 70457 48047 0.00 0.00 0.00 0.00 0.40 1.20 6.60 123.60 209.40 3.2 1100 1534987
+1 0 1 1 45 31 2366 465 225 5.77 3.98 635457 467915 1.79 3.58 3.58 0.00 0.00 8.95 10.93 261.23 475.75 453 81 19
+1 88 1 1 3 1 2118 116 92 1.40 1.60 36005 34644 0.00 0.00 0.00 0.00 0.00 1.60 1.60 100.60 129.00 1.5 2807 1049018
+1 93 1 1 1 0 1987 63 98 0.40 0.40 3299 18693 0.00 0.00 0.00 0.00 0.20 0.60 1.00 33.20 36.00 2.2 679 1720187
+1 85 1 1 5 1 5473 335 200 1.00 1.00 908732 64771 0.00 0.00 0.00 0.00 0.00 0.80 1.00 71.20 130.60 1.0 480 1074680
+1 84 1 1 11 7 3199 409 208 1.00 1.20 144553 64604 5.60 7.80 6.80 0.00 4.80 9.40 11.00 326.20 251.80 1.4 250 967437
+1 82 1 1 39 48 4804 274 179 1.40 1.60 138000 56152 15.00 19.80 26.20 27.60 14.00 20.60 26.20 76.20 140.00 5.6 148 1302861
+1 60 1 1 6 1 7448 1590 1544 4.40 1.60 1349215 1292798 0.00 0.00 0.00 0.00 0.00 5.00 7.80 257.20 349.40 1.7 725 1113125
+1 77 1 1 105 96 4309 386 272 6.00 5.20 305737 110175 8.80 52.40 90.80 177.40 1.40 4.20 15.00 269.20 490.00 1.2 183 1083451
+1 0 1 1 10 6 2098 619 99 0.20 0.20 388449 55019 0.20 0.20 0.20 0.00 0.60 22.80 39.40 19.80 72.20 291 91 9
+1 97 1 1 6 5 166 12 16 0.40 0.20 1256 6319 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.60 23.40 1.0 1713 1779874
+1 89 1 1 4 0 1467 191 173 3.40 1.00 77585 14861 0.00 0.00 0.00 0.00 0.00 0.00 0.00 163.60 238.60 3.2 633 1711213
+1 86 1 1 2 1 1218 162 62 1.20 1.60 60975 14627 0.60 0.60 0.60 0.00 0.60 4.20 4.40 98.00 223.60 3.0 245 1037384
+1 95 1 1 0 0 1469 136 65 0.20 0.20 4169 32465 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 7728 1871744
+1 92 1 1 4 0 1404 150 105 0.60 1.00 96753 28924 0.00 0.00 0.00 0.00 0.00 2.00 3.20 47.40 95.40 2.6 630 1103502
+1 76 1 1 2 0 738 119 53 1.80 1.80 649012 198478 0.00 0.00 0.00 0.00 0.00 1.80 1.80 173.40 141.80 2.0 2133 1817235
+1 84 1 1 35 0 1936 215 134 2.00 1.40 731904 175475 0.00 0.00 0.00 0.00 25.80 2.40 3.80 93.20 165.60 4.6 1923 1724267
+1 82 1 1 18 4 4427 185 146 1.60 2.60 131611 47320 0.00 0.00 0.00 0.00 0.40 15.20 54.60 172.60 299.80 1.3 717 987594
+1 94 1 1 2 1 1494 137 101 0.40 0.60 3222 17991 1.60 2.00 2.00 0.00 0.80 2.40 2.40 31.40 42.00 1.0 162 1100578
+1 97 1 1 1 0 320 63 43 0.20 0.20 51245 8234 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.4 6320 1722646
+1 87 1 1 43 53 3209 322 289 1.40 3.80 240965 28418 0.00 0.00 0.00 0.00 0.00 5.20 6.80 70.00 161.40 4.8 2827 1375077
+1 71 1 1 39 0 2390 126 73 10.18 27.74 70831 41582 0.80 1.00 1.00 0.00 0.40 1.00 1.00 339.92 607.58 1.5 202 1091181
+1 83 1 1 2 1 3810 174 121 1.00 1.40 384349 234513 4.19 8.98 17.56 28.54 2.99 24.15 35.53 70.06 162.48 3.3 185 1009234
+1 93 1 1 36 47 767 106 84 2.00 0.60 164585 26451 0.00 0.00 0.00 0.00 0.00 0.00 0.00 97.00 135.80 1.4 7215 1875907
+1 96 1 1 0 0 697 38 26 0.20 0.20 14267 25939 0.00 0.00 0.00 0.00 0.20 0.00 0.00 15.60 19.80 1.2 2029 1763994
+1 69 1 1 9 2 3510 112 59 5.57 20.28 134275 33270 0.60 0.99 0.80 0.00 0.40 1.99 1.99 351.09 495.83 1.0 351 1029007
+1 80 1 1 14 0 2252 215 177 2.79 3.79 198289 24564 3.99 44.91 94.01 311.98 0.20 29.34 53.69 194.81 307.58 3.0 146 1051986
+1 93 1 1 3 1 1254 78 56 0.40 0.60 171088 23484 0.00 0.00 0.00 0.00 0.20 0.40 0.40 32.00 47.80 4.0 734 1529357
+1 93 1 1 1 1 2044 115 89 0.20 0.20 6558 20569 0.60 0.60 1.00 0.60 0.20 1.40 1.60 15.80 23.60 1.5 128 1020136
+1 95 1 1 4 1 1894 100 96 0.60 0.60 45860 69687 0.00 0.00 0.00 0.00 0.00 0.00 0.00 86.20 43.20 2.8 2156 1550662
+1 98 1 1 0 0 253 17 25 0.40 0.40 1467 6983 0.00 0.00 0.00 0.00 0.00 0.00 0.00 29.40 36.00 1.0 7548 1870237
+1 78 1 1 18 0 3305 276 129 4.19 4.59 109923 43134 0.00 0.00 0.00 0.00 0.00 10.58 11.58 192.81 423.75 3.0 1168 1108353
+1 81 1 1 15 11 4050 275 248 1.20 0.80 357139 178959 4.60 9.00 8.60 0.00 0.20 4.80 5.20 92.00 185.60 3.0 387 997587
+1 84 1 1 77 100 3656 223 126 0.80 2.00 351795 49663 6.39 9.38 15.57 15.57 6.99 3.79 3.99 68.06 191.62 4.0 171 1008244
+1 98 1 1 1 1 195 20 20 0.20 0.20 10290 7876 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 7189 1867223
+1 87 1 1 6 2 2712 259 301 3.19 1.00 91310 26600 1.20 1.40 1.40 0.00 0.40 2.40 2.40 160.48 250.50 1.5 304 1032599
+1 82 1 1 5 1 1938 395 191 3.20 2.80 1251157 110467 3.60 7.00 20.40 27.40 0.40 29.60 42.20 192.00 379.00 3.8 167 980648
+1 68 1 1 63 77 6686 221 126 4.20 9.60 328031 86274 2.60 3.40 3.20 0.00 2.00 1.60 1.80 335.00 409.00 4.6 524 1533360
+1 97 1 1 1 0 1188 65 61 0.20 0.20 2635 18487 0.20 0.20 0.20 0.00 0.00 0.20 0.20 22.20 19.40 1.0 168 1064578
+1 87 1 1 2 0 419 34 57 1.80 1.80 51740 52923 8.60 8.80 8.80 0.00 0.40 1.60 1.80 155.80 137.20 1.6 248 1801502
+1 77 1 1 9 0 3153 274 209 8.60 4.40 161102 12945 0.00 0.00 0.00 0.00 0.00 1.00 1.00 372.20 556.20 2.8 4265 1727141
+1 83 1 1 5 0 2436 187 159 1.00 1.20 257550 255184 20.20 28.40 35.00 17.40 7.60 17.60 29.40 45.60 133.00 1.0 238 1052554
+1 94 1 1 0 0 1197 217 110 0.20 0.20 249037 256014 1.00 1.20 1.60 0.40 0.00 2.40 4.80 16.00 23.20 3.8 138 1737429
+1 72 1 1 7 0 3826 270 255 7.41 21.44 121829 110094 0.40 0.40 0.40 0.00 8.22 9.22 10.22 247.50 469.94 1.0 302 1093433
+1 91 1 1 72 91 1320 101 51 0.80 1.00 78153 29519 0.00 0.00 0.00 0.00 0.20 5.19 5.19 75.25 169.06 3.0 1173 1544433
+1 94 1 1 4 2 950 62 49 0.40 0.40 5406 33164 0.00 0.00 0.00 0.00 0.00 0.00 0.00 34.20 42.40 2.4 1379 1532280
+1 79 1 1 9 5 2416 173 107 2.60 2.80 345321 41989 0.00 0.00 0.00 0.00 1.40 24.40 30.20 178.80 371.40 5.6 1655 1385616
+1 81 1 1 3 2 4108 316 219 0.60 2.19 104272 176519 3.19 5.58 5.58 0.00 0.60 4.98 4.98 40.84 284.46 1.0 310 1000884
+1 85 1 1 5 1 3648 213 117 2.80 3.00 316448 79611 0.00 0.00 0.00 0.00 0.00 25.40 25.80 238.80 290.80 3.0 3675 1402318
+1 78 1 1 40 41 5084 352 295 4.40 3.00 335386 105668 0.00 0.00 0.00 0.00 0.00 1.20 1.60 242.80 361.20 4.4 965 1537475
+1 86 1 1 14 11 1785 122 96 2.40 2.61 47389 47507 16.43 20.64 27.05 14.83 13.23 16.63 19.04 147.90 255.31 2.2 151 1018783
+1 95 1 1 0 0 758 74 51 0.20 0.20 88227 26902 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 2.4 3135 1707978
+1 89 1 1 1 0 414 86 40 0.20 0.20 347102 138503 13.77 24.95 24.95 0.00 0.00 59.08 78.44 15.57 73.45 3.0 271 1711791
+1 90 1 1 3 1 429 60 30 2.40 2.40 60955 12806 0.00 0.00 0.00 0.00 0.00 3.40 4.40 230.80 188.20 1.6 8427 1837531
+1 88 1 1 3 1 378 31 30 1.60 1.60 50120 19904 5.80 6.00 8.20 4.20 0.00 1.80 2.20 121.00 122.00 3.0 139 1783634
+1 95 1 1 0 0 328 43 45 0.20 0.20 977 21791 1.00 1.00 1.00 0.00 0.00 1.00 1.00 15.60 16.80 1.0 294 1752520
+1 80 1 1 8 1 1594 220 208 5.60 1.60 130662 12888 0.00 0.00 0.00 0.00 0.00 0.20 0.40 263.80 379.80 1.0 589 1759709
+1 79 1 1 8 0 2572 403 348 7.20 2.40 190992 15889 0.00 0.00 0.00 0.00 0.00 0.20 0.40 359.60 512.20 1.4 1477 1745970
+1 90 1 1 11 7 1793 87 64 0.60 1.20 74149 26459 3.80 5.20 4.80 0.00 1.60 9.80 16.00 62.20 94.40 2.0 359 1119374
+1 98 1 1 0 0 1522 28 34 0.20 0.20 1936 4988 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 4518 1828232
+1 0 1 1 48 65 1199 101 69 0.60 0.60 86306 24924 0.00 0.00 0.00 0.00 0.00 12.60 20.20 40.80 110.00 616 90 10
+1 66 1 1 23 6 7129 691 516 8.58 2.59 758159 113632 4.99 11.58 26.35 37.72 0.20 2.20 2.20 422.95 658.88 3.2 152 1076744
+1 90 1 1 3 0 1817 163 152 2.80 0.80 67906 18789 0.00 0.00 0.00 0.00 0.00 0.40 0.40 129.40 186.80 2.2 2044 1719758
+1 79 1 1 8 0 2928 495 380 6.80 1.80 468904 99160 0.00 0.00 0.00 0.00 0.00 3.20 5.60 341.60 491.00 5.2 1534 1755962
+1 94 1 1 25 31 989 119 66 1.80 0.80 349572 9053 0.40 0.60 0.60 0.00 0.20 0.60 0.80 101.60 169.40 3.6 284 1709568
+1 83 1 1 8 1 5398 435 196 0.40 0.40 206075 51884 3.61 16.63 64.93 98.00 1.00 14.03 38.68 36.47 204.41 6.0 183 1005125
+1 79 1 1 6 0 3755 313 232 3.79 1.60 190407 88541 2.40 7.98 7.39 0.00 3.79 14.17 16.57 189.02 444.51 1.0 267 1006453
+1 0 1 1 77 75 1569 145 87 4.20 15.80 364729 56427 0.00 0.00 0.00 0.00 0.00 4.80 10.60 217.40 359.60 959 80 17
+1 93 1 1 14 21 1165 43 50 0.20 0.20 5524 12916 1.80 1.80 1.80 0.00 0.40 0.80 0.80 15.60 16.80 1.2 157 1751000
+1 91 1 1 3 0 917 109 106 1.80 0.60 45919 21664 0.60 0.60 0.60 0.00 0.00 0.00 0.00 87.80 127.20 1.0 243 1750581
+1 87 1 1 7 2 2576 157 118 0.40 0.60 317672 104149 13.20 36.40 62.00 78.60 0.40 17.60 47.60 43.80 146.00 1.6 147 981075
+1 82 1 1 5 0 3150 163 108 5.20 3.20 120314 18880 0.00 0.00 0.00 0.00 0.40 0.40 0.40 225.20 341.00 3.6 744 1749576
+1 77 1 1 4 0 3278 233 167 3.81 4.21 327640 137004 0.00 0.00 0.00 0.00 0.00 5.21 7.01 205.21 416.63 3.2 1257 1049927
+1 94 1 1 0 0 1745 229 97 0.20 0.20 19591 17415 0.00 0.00 0.00 0.00 0.00 3.00 5.00 24.00 18.80 1.4 1762 1074608
+1 96 1 1 2 0 1059 131 110 0.60 0.60 18821 30496 0.00 0.00 0.00 0.00 0.00 1.00 1.00 52.20 81.00 1.0 806 1016627
+1 91 1 1 40 57 2460 76 66 0.20 0.20 7302 28418 0.00 0.00 0.00 0.00 0.00 4.00 4.00 15.80 48.20 1.6 759 967594
+1 88 1 1 13 3 4229 615 463 1.00 2.20 209747 204867 0.00 0.00 0.00 0.00 0.00 7.60 19.40 61.80 114.40 3.4 1506 1398194
+1 98 1 1 2 1 176 10 13 0.40 0.40 7566 11234 0.00 0.00 0.00 0.00 0.00 0.00 0.00 33.67 33.27 1.0 6598 1854819
+1 83 1 1 33 17 3814 345 205 2.80 4.80 126811 66231 0.00 0.00 0.00 0.00 0.00 14.80 14.80 168.80 402.20 3.6 7378 1389501
+1 85 1 1 12 11 4931 544 254 0.20 0.20 237284 187031 3.61 4.81 4.81 0.00 0.20 28.46 28.86 36.07 67.33 1.8 377 1007014
+1 86 1 1 12 2 2610 232 152 3.80 2.20 152811 76289 0.00 0.00 0.00 0.00 0.40 4.00 4.20 224.00 377.20 6.2 2567 1555021
+1 94 1 1 1 0 1430 202 69 0.40 0.20 362703 101886 0.00 0.00 0.00 0.00 0.00 2.00 3.80 36.20 51.00 3.4 1248 1729682
+1 64 1 1 14 5 4970 457 324 9.40 6.20 402397 60714 21.40 70.20 117.00 198.40 0.40 25.60 35.60 438.60 763.40 1.5 312 972771
+1 97 1 1 5 4 730 66 55 0.40 1.80 21076 18606 2.40 2.40 2.40 0.00 1.00 0.40 0.40 32.00 46.40 1.0 267 1016494
+1 90 1 1 46 66 3275 115 108 0.40 1.80 148581 166728 0.00 0.00 0.00 0.00 0.20 9.78 11.98 38.32 67.27 1.6 613 988845
+1 88 1 1 17 2 867 72 67 2.40 3.40 108462 60920 0.00 0.00 0.00 0.00 0.00 2.60 4.60 208.40 205.40 1.4 6307 1853466
+1 81 1 1 8 0 2616 413 350 5.79 3.39 263708 92655 2.00 6.99 13.97 20.96 0.40 1.60 3.19 278.44 402.00 4.6 223 1718330
+1 97 1 1 1 1 205 19 21 0.20 0.20 7020 4259 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7403 1865584
+1 86 1 1 4 0 1898 175 134 1.80 4.60 467918 366260 0.00 0.00 0.00 0.00 0.00 28.20 55.20 103.40 136.80 3.0 770 1758770
+1 77 1 1 7 0 3164 409 345 6.60 2.80 205234 73445 0.00 0.00 0.00 0.00 0.00 4.60 5.00 316.00 495.60 1.0 756 1126109
+1 91 1 1 13 12 1974 374 179 0.20 0.20 527950 748715 0.00 0.00 0.00 0.00 0.00 0.40 0.40 21.40 32.20 3.6 615 1045459
+1 92 1 1 3 0 1073 141 132 2.99 1.00 82644 19928 0.00 0.00 0.00 0.00 0.00 0.00 0.00 150.30 230.34 2.0 8317 1860658
+1 98 1 1 0 0 423 30 25 0.20 0.20 1119 11172 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 17.00 3.0 1279 1712942
+1 0 1 1 55 68 4149 462 267 3.40 1.60 531019 385011 0.40 0.80 0.80 0.00 0.20 47.80 56.40 193.00 375.80 403 73 26
+1 93 1 1 2 0 301 39 28 0.60 0.60 48377 16470 0.00 0.00 0.00 0.00 0.00 5.60 8.80 32.00 50.00 1.4 481 1754590
+1 87 1 1 16 20 424 43 14 2.20 2.20 100127 19122 0.00 0.00 0.00 0.00 0.00 2.20 4.01 213.23 177.15 1.0 9316 1884377
+1 86 1 1 7 5 1939 156 113 0.60 0.80 64527 60547 10.76 24.50 28.29 61.75 5.58 5.18 6.37 58.17 158.37 1.0 590 1310239
+1 85 1 1 28 44 1901 49 46 0.20 0.20 1549 7356 0.00 0.00 0.00 0.00 0.00 0.00 0.00 22.40 21.00 2.2 978 1761437
+1 87 1 1 12 0 2309 102 55 1.20 1.40 342236 21886 0.00 0.00 0.00 0.00 1.60 29.34 48.70 81.24 150.10 3.8 366 1085594
+1 88 1 1 8 0 1676 178 146 1.80 3.20 108171 23730 0.00 0.00 0.00 0.00 0.20 3.60 4.00 136.60 167.60 1.0 772 1105752
+1 91 1 1 8 0 1139 91 86 1.80 4.60 140884 109592 0.00 0.00 0.00 0.00 0.00 1.40 1.60 170.00 194.80 2.2 1190 1544694
+1 91 1 1 6 1 2086 91 126 1.00 1.60 81695 193847 0.00 0.00 0.00 0.00 0.40 0.60 0.60 87.00 108.00 2.4 544 1524283
+1 56 1 1 54 2 5599 232 211 13.20 40.60 234916 50239 3.00 9.80 20.20 26.60 2.40 5.00 5.60 473.40 846.60 2.0 213 1095446
+1 95 1 1 1 1 1189 434 51 0.40 0.40 135376 55384 0.00 0.00 0.00 0.00 0.00 0.00 0.00 23.55 50.30 1.4 8193 1833289
+1 0 1 1 19 1 3302 238 139 3.01 4.41 522596 56297 3.01 4.61 9.22 19.24 2.61 19.24 31.06 167.54 317.64 389 84 16
+1 97 1 1 13 13 485 273 75 0.20 0.20 481854 480621 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 2.6 5757 1834560
+1 72 1 1 13 3 3576 467 176 4.80 5.40 276569 51757 10.60 50.80 130.40 214.00 1.00 14.00 46.60 309.80 638.80 1.0 161 1119142
+1 96 1 1 2 2 466 52 68 0.40 0.40 20982 129280 0.00 0.00 0.00 0.00 0.00 0.40 0.60 30.00 43.20 1.0 6308 1845610
+1 97 1 1 3 0 1289 58 59 0.40 0.20 64893 61114 0.00 0.00 0.00 0.00 0.00 0.20 0.20 28.80 25.60 2.0 5091 1673590
+1 50 1 1 51 63 7093 633 357 8.18 11.78 287553 371722 8.58 32.73 74.85 153.89 1.00 48.90 49.50 551.70 931.94 6.8 221 1371542
+1 87 1 1 3 2 6051 1025 922 0.20 0.20 274243 164297 11.60 28.40 40.20 55.40 5.20 9.00 14.40 17.40 64.40 2.6 140 1521426
+1 94 1 1 6 1 2170 101 79 1.20 1.20 118152 67852 0.00 0.00 0.00 0.00 0.00 0.00 0.00 159.80 111.40 2.6 2011 1642163
+1 82 1 1 17 4 3977 314 274 3.79 4.19 370084 169843 0.00 0.00 0.00 0.00 0.00 0.40 0.40 218.56 350.50 3.6 1309 1641036
+1 80 1 1 4 1 730 95 60 2.80 2.80 345600 52749 0.00 0.00 0.00 0.00 0.00 7.00 11.80 241.80 271.60 1.6 2996 1795890
+1 98 1 1 1 0 198 16 24 0.40 0.40 452 12704 0.00 0.00 0.00 0.00 0.00 0.00 0.00 37.40 33.20 1.0 5925 1863982
+1 96 1 1 1 1 1078 34 30 0.40 0.40 1887 3124 0.00 0.00 0.00 0.00 0.00 0.00 0.00 30.40 38.60 2.0 2233 1697794
+1 89 1 1 8 4 2216 95 70 2.60 3.40 40924 21939 1.80 2.00 22.60 54.20 0.40 5.40 5.40 149.00 272.80 3.0 116 1060146
+1 80 1 1 81 46 3787 318 276 1.60 1.80 468759 221749 4.39 16.97 45.11 42.71 14.57 4.39 28.34 100.40 230.14 1.0 188 1094873
+1 81 1 1 10 0 5016 694 723 5.01 3.81 613278 597142 2.00 18.44 68.94 114.83 0.20 13.03 74.35 145.89 267.74 2.8 132 1047607
+1 91 1 1 1 1 3835 268 146 0.20 0.20 361961 76683 10.00 17.60 17.60 0.00 3.60 5.40 5.60 13.40 52.80 2.4 207 1446538
+1 69 1 1 17 13 3350 321 288 0.80 0.60 438593 637453 19.60 55.80 171.80 375.60 4.00 61.20 104.00 93.60 293.20 2.0 118 1028534
+1 93 1 1 7 0 963 105 66 1.20 1.60 119224 19633 0.00 0.00 0.00 0.00 0.00 3.80 4.60 84.00 154.60 1.5 1351 976717
+1 91 1 1 3 1 2265 189 112 0.40 1.80 238639 32278 0.00 0.00 0.00 0.00 0.00 1.40 1.40 32.20 74.60 3.8 594 1076909
+1 95 1 1 6 1 504 80 34 2.20 3.60 53037 22287 0.00 0.00 0.00 0.00 0.00 0.00 0.00 81.00 140.80 1.2 7970 1877981
+1 93 1 1 0 0 2254 109 137 0.20 0.20 50288 17569 0.00 0.00 0.00 0.00 0.00 14.80 20.40 15.20 52.40 3.2 3917 1721176
+1 75 1 1 10 3 6207 253 302 2.60 3.60 83282 499348 9.20 18.20 33.00 66.00 0.00 20.00 26.00 110.00 269.40 2.4 211 1012282
+1 85 1 1 8 1 1215 62 104 7.00 10.80 98480 179820 0.20 2.20 0.40 0.00 0.40 2.60 2.60 221.60 459.40 2.0 6469 1852026
+1 79 1 1 62 79 3705 451 262 5.20 1.60 545099 24655 1.20 1.20 1.20 0.00 0.60 11.00 12.80 260.60 442.80 1.0 298 980144
+1 98 1 1 2 1 330 47 35 0.40 0.40 5114 11775 0.00 0.00 0.00 0.00 0.00 4.40 4.80 27.80 45.40 2.0 998 1723549
+1 93 1 1 5 1 921 94 65 0.60 1.00 41990 15763 16.80 37.60 60.60 118.00 0.20 16.40 17.20 70.80 175.80 1.8 149 1022018
+1 85 1 1 17 13 3125 228 147 3.00 3.00 41720 28149 0.00 0.00 0.00 0.00 1.00 1.60 2.80 147.60 256.20 3.0 658 1074107
+1 98 1 1 1 1 181 16 26 0.20 0.20 10180 25473 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 9225 1867488
+1 85 1 1 8 3 2092 294 150 0.40 0.40 403159 42079 3.60 12.20 21.20 30.40 1.40 25.20 45.60 57.80 137.40 1.0 192 1130656
+1 95 1 1 2 0 1343 194 65 0.40 0.40 104806 14598 0.00 0.00 0.00 0.00 0.00 1.40 1.60 27.40 48.60 2.2 6218 1725992
+1 87 1 1 19 4 2798 511 271 1.60 1.80 238944 99836 0.00 0.00 0.00 0.00 0.00 3.40 5.40 111.20 133.60 4.0 2657 1538936
+1 92 1 1 2 1 3272 245 259 0.20 0.20 4942 18681 1.20 1.20 1.20 0.00 0.60 0.80 0.80 24.15 43.91 1.5 221 1021681
+1 90 1 1 27 37 2024 128 120 1.40 2.00 206529 22860 0.00 0.00 0.00 0.00 0.40 2.20 2.20 89.42 122.95 2.0 1069 1053356
+1 86 1 1 12 10 4538 192 166 0.40 0.40 14797 46413 0.00 0.00 0.00 0.00 0.00 1.20 3.98 40.44 64.74 2.0 827 990382
+1 97 1 1 13 6 348 33 55 0.40 0.40 25478 31897 0.00 0.00 0.00 0.00 0.00 1.00 1.00 39.20 33.80 1.0 7617 1871486
+1 89 1 1 20 30 1889 127 113 0.20 0.20 76661 106567 5.60 13.20 18.60 25.40 0.80 54.40 54.80 15.60 124.60 1.5 202 1118800
+1 90 1 1 122 53 3858 253 267 0.20 0.20 92027 172470 3.00 23.20 23.40 5.00 0.00 0.60 0.60 20.20 27.20 3.0 399 1066162
+1 48 1 1 44 1 6493 591 460 14.40 19.20 391816 97027 4.00 10.00 20.20 33.40 2.20 6.00 7.00 751.40 1114.80 4.8 182 1096938
+1 0 1 1 4 3 1260 238 219 0.20 0.20 123476 64198 9.60 15.40 48.00 60.60 4.80 10.60 16.80 22.80 79.40 142 93 7
+1 91 1 1 5 2 1928 222 126 1.00 0.60 21098 49694 0.00 0.00 0.00 0.00 0.00 2.99 2.99 58.88 120.96 1.5 2105 1070438
+1 89 1 1 1 0 3645 250 156 0.20 0.20 18141 70828 0.00 0.00 0.00 0.00 1.00 2.80 4.80 16.40 37.40 2.0 496 1079114
+1 84 1 1 13 4 3250 137 97 2.00 3.60 30021 7073 0.00 0.00 0.00 0.00 0.20 2.20 2.20 158.20 249.00 5.0 2188 1348486
+1 87 1 1 2 0 1053 127 47 0.40 0.20 311277 30292 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.80 33.00 1.8 493 1748054
+1 75 1 1 37 44 2886 451 357 7.60 2.00 467306 99716 0.00 0.00 0.00 0.00 0.00 6.60 13.20 373.40 542.20 6.8 1607 1756069
+1 81 1 1 71 82 2446 267 175 2.61 4.81 351530 41723 0.00 0.00 0.00 0.00 0.40 6.21 32.26 155.11 350.50 1.3 752 1012120
+1 89 1 1 6 1 782 40 41 2.60 6.00 66890 53993 0.00 0.00 0.00 0.00 0.00 1.40 2.00 233.20 222.40 1.2 5779 1847056
+1 94 1 1 11 9 1686 81 67 0.20 0.20 4975 18963 1.40 1.40 1.40 0.00 0.60 1.80 3.20 22.40 47.00 3.2 266 971168
+1 95 1 1 1 0 324 44 28 0.60 0.60 127787 17925 0.00 0.00 0.00 0.00 0.00 0.60 0.60 36.80 46.40 1.4 950 1762378
+1 74 1 1 32 45 1301 218 291 2.00 2.00 582646 151253 16.97 33.53 38.12 14.77 23.35 3.59 5.79 173.25 168.46 3.2 189 1809574
+1 93 1 1 6 1 1560 110 145 1.20 1.00 29946 47399 0.00 0.00 0.00 0.00 0.00 1.40 1.60 79.80 121.80 2.2 2428 1538910
+1 94 1 1 3 0 2327 122 129 0.60 2.40 46731 204548 0.00 0.00 0.00 0.00 0.00 0.20 0.20 50.40 67.00 2.0 329 1522802
+1 90 1 1 32 28 2149 114 75 1.40 1.60 125493 25113 0.00 0.00 0.00 0.00 0.60 8.18 9.78 84.23 148.90 1.0 655 1079909
+1 83 1 1 7 2 1420 131 134 3.80 6.60 506387 250930 0.00 0.00 0.00 0.00 0.00 13.80 26.60 266.80 331.20 1.8 6101 1843602
+1 86 1 1 7 1 3718 246 166 1.60 1.40 133979 27598 0.00 0.00 0.00 0.00 0.00 11.98 14.97 78.24 183.43 3.0 1257 1468233
+1 94 1 1 16 22 922 60 38 0.20 0.20 79758 51856 0.00 0.00 0.00 0.00 0.00 4.00 8.00 15.80 17.20 1.0 8464 1837406
+1 80 1 1 18 12 4758 543 172 0.59 0.59 562483 107950 2.57 4.55 4.55 0.00 2.57 4.16 20.99 56.44 183.56 2.2 472 997467
+1 97 1 1 0 0 187 36 18 0.20 0.20 19921 19620 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.60 1.0 2033 1764024
+1 90 1 1 10 5 1378 174 98 0.60 0.80 236766 43659 23.55 38.12 68.66 68.06 16.17 8.78 32.93 39.92 156.29 1.0 132 980332
+1 82 1 1 1 0 2414 225 143 1.80 1.80 828634 69976 0.00 0.00 0.00 0.00 0.20 2.80 3.00 105.00 193.00 1.0 531 1095776
+1 88 1 1 4 1 2331 172 98 2.20 6.99 104697 25963 2.00 2.99 2.20 0.00 1.00 2.20 2.40 162.08 234.73 1.6 249 1087917
+1 97 1 1 1 1 681 49 44 0.20 0.20 4409 20747 0.00 0.00 0.00 0.00 0.00 0.20 0.20 16.20 20.60 2.0 912 1074280
+1 99 1 1 1 0 206 15 30 0.20 0.20 3319 15828 0.00 0.00 0.00 0.00 0.20 0.40 0.40 15.60 16.80 2.0 1113 1718144
+1 86 1 1 8 5 4299 206 143 1.40 1.80 207260 38473 0.00 0.00 0.00 0.00 0.40 2.79 3.99 100.00 168.46 3.2 607 1443460
+1 89 1 1 17 23 2608 203 91 1.00 1.00 175845 145439 0.20 0.40 0.40 0.00 0.00 2.00 3.60 73.20 110.80 4.0 289 1723885
+1 64 1 1 4 0 3296 179 99 2.40 2.80 261026 29326 0.00 0.00 0.00 0.00 0.40 4.60 5.60 171.20 281.00 1.0 859 1017344
+1 95 1 1 1 1 1336 76 53 0.20 0.20 4384 19359 0.00 0.00 0.00 0.00 0.00 1.00 1.00 21.20 32.00 2.0 2965 1014437
+1 89 1 1 11 4 3344 175 106 1.80 7.00 170377 98441 0.00 0.00 0.00 0.00 27.00 15.40 15.40 74.40 159.00 4.8 2977 1546898
+1 95 1 1 7 4 2794 168 109 0.20 0.20 405323 185677 0.00 0.00 0.00 0.00 0.20 2.00 3.40 20.20 56.20 4.8 413 1596082
+1 86 1 1 3 2 3833 575 489 0.80 2.20 43967 39891 0.00 0.00 0.00 0.00 0.00 0.40 0.40 119.80 57.60 2.2 1505 1725224
+1 96 1 1 2 0 998 92 93 0.40 0.60 13248 45535 0.00 0.00 0.00 0.00 0.00 3.60 3.60 39.60 48.20 1.0 806 1081493
+1 88 1 1 10 1 1591 329 137 1.60 2.00 192864 11556 0.00 0.00 0.00 0.00 0.20 20.00 20.00 122.40 304.60 3.8 6061 1709011
+1 79 1 1 9 0 3006 399 352 7.78 2.20 212973 22736 0.00 0.00 0.00 0.00 0.00 0.20 0.40 375.45 552.30 2.0 359 1722405
+1 89 1 1 1 0 857 106 65 1.00 1.20 187708 39359 0.40 0.40 0.40 0.00 0.20 6.19 7.78 70.06 92.22 2.8 373 1051851
+1 81 1 1 17 8 5228 209 116 2.20 7.40 129995 97271 0.00 0.00 0.00 0.00 0.00 0.00 0.00 180.00 193.40 3.4 885 1645398
+1 85 1 1 10 1 3819 367 252 3.39 2.59 142268 83109 0.00 0.00 0.00 0.00 0.00 1.60 1.80 177.45 263.67 2.2 664 1525033
+1 93 1 1 1 0 2699 88 157 0.20 0.20 5087 38464 1.00 1.00 1.00 0.00 0.00 0.00 0.00 15.60 17.80 2.2 213 1709248
+1 92 1 1 4 0 1508 175 147 1.80 2.20 179589 66684 0.00 0.00 0.00 0.00 0.00 12.40 12.40 101.60 190.00 1.2 336 1012502
+1 83 1 1 6 0 3556 246 122 3.00 3.80 300151 49692 0.00 0.00 0.00 0.00 0.20 20.00 23.20 245.40 368.80 1.0 620 1021299
+1 89 1 1 36 44 1809 146 103 1.20 1.20 172354 37272 0.60 0.60 0.60 0.00 2.81 2.61 2.81 79.36 216.03 2.6 396 977395
+1 93 1 1 0 0 261 20 14 0.20 0.20 810 5665 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 504 1747160
+1 81 1 1 6 0 4894 161 111 5.40 18.00 93945 27244 1.60 1.60 1.40 0.00 0.20 1.00 1.20 231.80 327.20 1.8 293 1752838
+1 96 1 1 5 3 931 86 86 0.40 0.40 108376 82230 0.80 0.80 0.80 0.00 0.60 1.80 2.00 38.00 73.60 2.8 307 1524280
+1 98 1 1 2 1 322 63 44 0.20 0.20 1342 18195 0.00 0.00 0.00 0.00 0.00 0.60 0.80 15.80 20.40 1.0 1370 1746256
+1 88 1 1 9 1 2779 308 190 3.20 1.40 173458 110845 0.00 0.00 0.00 0.00 0.00 0.80 0.80 155.80 239.20 5.0 2864 1559789
+1 78 1 1 9 0 2486 178 157 6.39 18.56 57610 57884 3.59 17.76 20.36 47.70 0.20 6.59 6.59 241.12 398.80 2.4 173 1101016
+1 74 1 1 9 2 3614 236 266 4.39 19.96 131305 514045 0.00 0.00 0.00 0.00 0.00 10.78 16.97 238.32 397.41 2.6 869 1031599
+1 84 1 1 2 0 5703 277 189 0.80 2.00 154491 30652 0.40 0.40 0.40 0.00 0.60 12.60 13.60 66.00 146.40 1.4 371 1103440
+1 93 1 1 0 0 2693 334 112 0.20 0.20 178179 173468 0.00 0.00 0.00 0.00 0.00 1.60 2.80 15.60 23.80 3.6 1317 1731365
+1 98 1 1 2 1 2905 80 80 0.20 0.20 3086 4895 0.00 0.00 0.00 0.00 0.00 1.20 1.20 20.96 20.36 2.0 619 1443205
+1 87 1 1 1 0 4022 282 237 0.60 3.40 158712 84261 3.00 6.00 6.00 0.00 1.40 2.00 2.40 43.40 57.20 3.0 147 985730
+1 88 1 1 0 0 3414 277 136 0.20 0.20 56625 33528 0.80 1.00 1.00 0.00 0.20 1.40 2.40 32.60 17.80 1.7 220 1127178
+1 92 1 1 34 49 1484 86 109 0.20 0.20 50849 211870 2.79 3.19 3.19 0.00 1.20 1.00 1.40 12.97 23.15 3.2 164 1520671
+1 83 1 1 18 4 2940 447 377 4.80 1.80 194915 71553 0.20 0.20 0.20 0.00 0.20 2.60 2.80 248.20 389.40 1.6 243 965794
+1 90 1 1 13 11 2080 139 110 0.40 0.40 16990 25726 0.00 0.00 0.00 0.00 0.00 19.40 19.60 41.40 143.20 1.6 1436 970912
+1 91 1 1 50 62 1290 136 79 1.20 0.80 278394 22175 1.60 4.19 8.98 55.49 2.00 5.99 6.39 72.26 107.98 1.0 213 970344
+1 86 1 1 17 3 3680 200 152 2.00 2.20 256835 87761 5.40 11.40 31.80 70.00 2.20 2.60 3.80 141.20 273.20 3.2 159 1526898
+1 92 1 1 0 0 1182 143 65 0.20 0.20 449623 251294 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 18.60 2.6 1036 1758723
+1 86 1 1 11 11 6070 358 246 0.20 0.20 974434 50477 0.00 0.00 0.00 0.00 3.20 0.40 0.40 19.60 32.00 1.0 657 1010163
+1 90 1 1 1 0 2185 167 838 0.60 0.80 47868 97238 0.00 0.00 0.00 0.00 0.00 0.00 0.00 46.20 74.60 1.8 1974 1734194
+1 96 1 1 7 3 709 44 46 0.80 1.40 23587 16036 0.00 0.00 0.00 0.00 0.00 0.20 0.20 54.20 80.40 2.2 5368 1680051
+1 95 1 1 1 0 2451 73 77 0.20 0.20 5872 99640 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 18.80 2.2 829 1643104
+1 78 1 1 5 0 3169 196 105 2.40 2.60 307553 104790 18.80 30.00 56.20 67.00 10.20 14.00 22.20 185.40 338.80 1.5 150 1129994
+1 95 1 1 3 3 2213 135 125 0.20 0.20 23254 25981 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.80 17.60 4.2 707 1637710
+1 88 1 1 1 0 4463 204 149 0.20 0.20 38837 41409 0.00 0.00 0.00 0.00 0.00 44.31 44.51 15.77 64.87 1.0 2124 1110435
+1 79 1 1 9 2 3602 297 238 3.40 1.00 138967 52594 0.00 0.00 0.00 0.00 0.00 0.20 0.20 166.20 235.00 2.8 3651 1773886
+1 89 1 1 2 0 461 44 64 1.20 0.80 24720 20705 0.00 0.00 0.00 0.00 0.00 1.80 3.20 55.00 69.00 2.0 534 1742819
+1 94 1 1 6 0 853 64 74 1.60 2.20 44658 60932 0.00 0.00 0.00 0.00 0.00 0.60 0.60 95.80 140.60 1.0 474 1062429
+1 89 1 1 0 0 2514 129 73 0.20 0.20 7689 24957 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13.00 16.80 1.6 1406 1753992
+1 90 1 1 18 25 223 21 32 0.20 0.20 1187 21394 0.00 0.00 0.00 0.00 0.00 0.20 0.20 21.80 18.80 1.6 4123 1780992
+1 82 1 1 222 217 5397 422 285 1.00 3.59 312033 283788 1.60 7.58 32.34 61.08 1.00 7.78 25.75 62.28 104.19 4.0 131 1326418
+1 91 1 1 3 1 413 62 50 0.60 1.60 33928 169053 0.00 0.00 0.00 0.00 0.00 1.40 2.59 27.15 33.53 1.6 3922 1827066
+1 79 1 1 30 0 5261 983 438 1.40 1.40 1038498 968879 8.80 89.20 171.00 503.00 1.60 52.20 226.80 102.80 220.60 4.2 95 1330648
+1 93 1 1 1 0 2673 153 195 0.40 2.00 198974 59565 0.00 0.00 0.00 0.00 0.00 0.20 0.20 19.60 40.80 3.0 1677 1698960
+1 73 1 1 199 186 7625 779 485 3.40 3.60 292564 190527 3.20 12.80 24.00 34.80 1.20 9.00 23.60 134.60 280.40 3.4 154 1337360
+1 88 1 1 2 1 450 82 45 1.60 1.60 356547 297275 0.00 0.00 0.00 0.00 0.00 7.20 14.00 128.80 133.40 2.2 3680 1822077
+1 91 1 1 1 0 2747 322 244 0.20 0.20 8792 97754 0.00 0.00 0.00 0.00 0.00 0.60 0.60 17.23 46.89 1.0 376 1072536
+1 86 1 1 169 186 3660 405 197 0.60 0.80 32957 25578 0.00 0.00 0.00 0.00 0.00 5.41 5.81 58.32 91.78 1.5 1195 1133937
+1 97 1 1 1 1 1781 76 41 0.20 0.20 17273 21476 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.37 16.77 1.6 8315 1860982
+1 81 1 1 9 5 3414 433 231 1.60 6.01 323068 110155 0.00 0.00 0.00 0.00 0.60 11.02 18.84 100.40 201.00 1.5 512 1096037
+1 82 1 1 20 11 2530 110 63 2.00 2.60 212140 106952 0.00 0.00 0.00 0.00 0.00 1.40 2.20 222.00 260.80 2.8 848 1518690
+1 84 1 1 2 0 2361 483 438 1.20 2.20 124713 252627 0.00 0.00 0.00 0.00 0.20 10.60 15.80 86.60 133.40 2.6 646 1380874
+1 88 1 1 4 1 520 51 52 2.00 2.00 126557 53547 0.00 0.00 0.00 0.00 0.00 2.00 2.00 207.19 165.67 2.2 11197 1868873
+1 77 1 1 2 0 842 166 201 0.40 0.80 847117 522561 6.39 41.72 221.36 381.24 0.20 62.67 124.35 36.73 45.11 3.4 177 1753610
+1 93 1 1 0 0 278 25 49 0.20 0.20 28634 39878 0.00 0.00 0.00 0.00 0.00 1.20 1.60 15.57 17.17 1.0 2981 1769748
+1 88 1 1 69 59 731 80 61 2.40 3.60 249270 114777 0.00 0.00 0.00 0.00 0.00 15.60 29.20 148.40 367.40 2.6 6676 1713430
+1 95 1 1 1 0 3704 199 96 0.20 0.20 194193 189146 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 18.20 3.4 3355 1346128
+1 95 1 1 4 1 417 60 28 1.80 1.80 45835 20821 0.00 0.00 0.00 0.00 0.00 0.00 0.00 69.00 118.20 1.6 7559 1879333
+1 82 1 1 179 170 4794 358 239 3.00 2.40 348791 319511 4.00 4.00 4.00 0.00 1.00 23.20 39.60 125.00 274.00 5.0 336 1337942
+1 80 1 1 24 8 2557 245 136 1.80 3.21 295980 118629 20.04 51.30 134.07 230.46 3.01 22.65 36.67 152.91 313.43 1.0 136 1060449
+1 95 1 1 1 0 2259 159 130 0.20 0.20 8720 12054 0.00 0.00 0.00 0.00 0.00 7.80 7.80 24.00 69.00 4.2 6679 1410040
+1 92 1 1 7 0 3084 163 183 0.20 0.20 8727 40144 0.80 2.80 16.00 30.00 0.00 15.00 18.60 15.80 60.20 3.0 131 1041432
+1 95 1 1 15 22 261 44 28 0.20 0.20 93708 38179 0.00 0.00 0.00 0.00 0.00 10.80 21.40 15.40 17.20 1.0 7233 1847203
+1 89 1 1 12 3 2296 104 62 1.80 2.20 48107 38568 0.00 0.00 0.00 0.00 0.00 0.40 0.40 148.60 221.60 2.8 1217 1544565
+1 81 1 1 37 31 1163 132 150 0.80 0.40 695983 437060 11.58 40.92 81.04 143.71 3.99 64.07 127.35 63.67 116.97 2.3 325 1064177
+1 82 1 1 0 0 3852 193 223 0.20 0.20 142656 376531 7.60 28.80 114.00 232.20 0.20 0.40 0.40 28.60 168.20 2.8 127 1004758
+1 92 1 1 7 2 2183 162 110 0.80 1.00 76676 84219 0.00 0.00 0.00 0.00 0.00 9.60 9.60 55.00 83.80 3.6 2879 1532101
+1 91 1 1 2 0 410 34 44 1.80 1.80 42883 56980 0.00 0.00 0.00 0.00 0.00 1.80 3.00 150.20 142.20 1.2 6441 1851192
+1 90 1 1 3 0 370 21 24 0.80 0.80 22085 6406 0.00 0.00 0.00 0.00 0.00 2.60 7.40 61.60 64.00 2.2 1060 1752096
+1 85 1 1 38 56 2924 397 166 0.60 2.20 280716 261622 3.60 8.20 8.20 0.00 0.00 13.20 25.00 59.00 129.20 4.0 235 1025885
+1 86 1 1 30 22 1967 94 74 1.20 2.00 167772 92963 0.00 0.00 0.00 0.00 0.00 4.79 6.39 88.82 251.90 3.2 7647 1370671
+1 94 1 1 1 0 905 63 37 1.00 1.40 74842 14846 0.00 0.00 0.00 0.00 0.00 0.20 0.20 79.00 123.40 1.0 1712 1009738
+1 90 1 1 2 0 450 48 30 2.00 2.40 110942 48105 0.00 0.00 0.00 0.00 0.00 4.20 6.60 185.20 161.40 1.0 11884 1888162
+1 78 1 1 9 5 3136 348 297 3.59 1.40 155004 72160 37.52 78.24 167.86 456.29 0.00 11.38 15.17 192.81 525.95 1.5 202 947304
+1 86 1 1 3 0 2271 199 284 0.60 0.60 189869 199051 7.00 18.80 32.00 53.00 0.00 7.20 9.00 46.20 93.00 3.2 294 1047448
+1 95 1 1 12 11 402 189 61 0.20 0.20 205804 208228 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 17.20 3.2 903 1742826
+1 88 1 1 49 65 1825 252 107 0.40 0.20 182668 56760 0.00 0.00 0.00 0.00 0.00 13.97 30.74 42.91 74.05 1.0 1875 1092909
+1 92 1 1 9 7 1681 166 106 0.40 0.40 138589 52968 2.00 3.20 3.20 0.00 7.20 4.00 4.00 34.20 50.40 1.2 290 1011274
+1 97 1 1 0 0 220 32 25 0.20 0.20 91884 4369 0.00 0.00 0.00 0.00 0.00 0.20 0.20 16.00 16.80 2.0 4676 1847632
+1 68 1 1 20 9 7173 358 163 3.20 14.00 124968 23362 0.00 0.00 0.00 0.00 0.20 28.00 67.00 250.40 419.40 3.0 2868 1396782
+1 92 1 1 5 0 1363 202 149 1.20 1.00 8169 26982 0.00 0.00 0.00 0.00 0.00 0.80 0.80 78.20 90.20 2.0 538 978795
+1 78 1 1 3 1 4299 244 273 1.20 1.40 178072 614311 2.40 3.00 2.40 0.00 0.80 1.00 1.20 77.20 137.60 1.0 343 984790
+1 92 1 1 13 8 2006 151 113 0.60 0.60 93482 28252 2.40 3.00 2.80 0.00 0.80 4.80 8.00 50.60 66.40 2.2 226 1086950
+1 90 1 1 1 0 941 88 71 0.80 1.00 180557 96584 19.80 37.00 64.80 59.20 8.80 19.60 35.60 44.80 97.20 1.0 133 990742
+1 77 1 1 23 1 3357 305 173 6.80 5.00 345574 146362 3.20 4.00 3.80 0.00 0.60 14.40 19.60 366.60 490.60 4.2 325 1528362
+1 88 1 1 4 2 2333 195 158 0.40 0.40 70434 44240 3.39 5.39 6.79 5.39 0.40 6.59 9.38 38.92 65.47 1.6 146 1032714
+1 90 1 1 11 5 2822 165 92 1.40 1.20 367038 192213 0.00 0.00 0.00 0.00 0.00 4.60 8.60 94.60 112.00 5.4 2344 1543234
+1 96 1 1 2 0 996 69 62 0.20 0.40 2317 30113 1.20 1.20 1.20 0.00 0.00 0.00 0.00 21.20 59.20 2.0 577 1527410
+1 94 1 1 10 7 1323 101 112 0.40 0.40 62393 90762 1.00 1.00 1.00 0.00 0.40 0.00 0.00 43.40 53.00 2.6 284 1535160
+1 92 1 1 1 1 3624 158 106 0.40 0.60 24880 5624 0.00 0.00 0.00 0.00 0.00 0.00 0.00 60.20 107.40 1.6 1046 1742170
+1 96 1 1 10 2 2195 198 162 0.20 0.20 55757 45611 0.00 0.00 0.00 0.00 0.00 6.20 7.40 15.60 18.00 3.0 964 1398045
+1 80 1 1 55 69 4194 278 195 2.79 1.80 199257 49131 1.00 1.00 1.00 0.00 1.20 4.39 5.99 161.88 315.37 2.2 340 1090001
+1 94 1 1 0 0 1533 83 85 0.20 0.20 16672 26572 0.00 0.00 0.00 0.00 0.00 0.20 0.20 177.49 30.68 1.2 1283 1055874
+1 86 1 1 9 1 2989 232 200 1.40 1.00 118874 122222 0.20 0.40 0.40 0.00 0.20 4.00 5.80 109.00 166.80 1.4 624 1001170
+1 92 1 1 0 0 247 35 37 0.00 0.00 2609 5855 0.00 0.00 0.00 0.00 0.00 1.60 1.60 4.00 0.80 2.0 583 1745904
+1 95 1 1 1 0 2285 92 135 0.20 0.20 11706 25473 0.00 0.00 0.00 0.00 0.00 1.20 1.80 15.60 21.60 3.0 1337 1724755
+1 94 1 1 3 0 2031 104 90 0.40 1.60 6882 32301 0.00 0.00 0.00 0.00 0.00 7.80 8.60 38.60 67.40 1.0 595 1021051
+1 93 1 1 4 2 1589 165 108 1.20 1.80 34616 55818 0.00 0.00 0.00 0.00 0.00 1.20 1.40 132.80 118.00 2.6 879 1540005
+1 98 1 1 1 0 224 15 20 0.40 0.40 624 6824 0.00 0.00 0.00 0.00 0.00 0.80 0.80 41.48 35.27 1.0 1660 1785451
+1 0 1 1 48 56 2159 307 267 3.00 1.40 431140 110214 6.00 6.80 12.20 9.40 4.20 21.00 29.20 165.00 415.60 312 81 19
+1 92 1 1 29 42 3552 248 207 0.20 0.20 8408 116748 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.43 55.11 1.0 329 1072233
+1 76 1 1 21 15 4885 301 182 2.80 8.40 217813 204250 0.00 0.00 0.00 0.00 0.00 0.00 0.00 256.60 252.00 3.8 1910 1576610
+1 94 1 1 4 1 462 54 29 1.80 2.00 171457 10198 0.00 0.00 0.00 0.00 0.00 0.20 0.20 94.00 129.80 2.2 6289 1845656
+1 96 1 1 26 35 2728 135 138 0.20 0.20 5321 17760 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 281 1709264
+1 87 1 1 1 0 3290 173 148 1.20 2.40 227387 130637 0.00 0.00 0.00 0.00 0.00 8.40 9.40 81.00 147.40 4.0 607 1119533
+1 90 1 1 5 0 925 158 118 1.00 3.60 509935 268476 0.00 0.00 0.00 0.00 0.00 30.00 58.00 42.60 79.20 2.0 2400 1738904
+1 92 1 1 45 57 1655 146 72 0.60 0.80 175563 38792 0.00 0.00 0.00 0.00 0.00 0.00 0.00 58.80 72.40 3.2 2186 1550549
+1 74 1 1 39 22 5077 118 131 4.00 10.20 52311 59359 9.60 14.00 35.20 67.60 7.80 0.40 0.60 312.00 410.40 3.2 249 1643522
+1 75 1 1 12 9 5661 289 150 2.80 9.80 89740 42905 0.00 0.00 0.00 0.00 0.00 0.20 0.20 247.00 251.60 6.4 3168 1602059
+1 84 1 1 12 4 2128 269 206 3.00 1.20 94070 21569 2.00 5.00 18.40 27.20 0.20 1.00 1.00 148.20 252.80 2.6 173 959533
+1 96 1 1 21 29 282 45 15 0.20 0.20 263872 15322 0.00 0.00 0.00 0.00 0.00 0.00 0.00 22.24 21.64 1.6 7862 1872056
+1 95 1 1 0 0 539 72 37 0.20 0.20 1970 4897 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 2.2 1366 1713440
+1 97 1 1 14 13 1282 52 51 0.20 0.20 25505 20393 0.00 0.00 0.00 0.00 0.00 0.80 1.20 15.83 17.23 1.0 1188 1096305
+1 81 1 1 37 33 2128 330 288 3.00 3.80 289446 109712 0.00 0.00 0.00 0.00 0.00 4.60 6.80 162.60 280.80 2.0 724 1122869
+1 85 1 1 8 1 2685 310 221 1.80 0.80 122569 51469 1.00 5.79 22.95 48.50 0.20 2.40 5.19 100.20 174.45 3.0 414 1107248
+1 98 1 1 1 1 191 12 21 0.20 0.20 7015 20098 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7291 1865608
+1 92 1 1 0 0 2831 207 104 0.20 0.20 80279 30493 1.40 1.60 1.60 0.00 0.00 1.00 1.00 16.00 21.40 1.4 261 1127110
+1 91 1 1 7 0 1596 148 71 1.40 1.40 25499 12712 0.00 0.00 0.00 0.00 0.00 1.60 1.60 112.20 160.60 2.4 5735 1730274
+1 90 1 1 46 62 2883 132 132 0.40 0.40 99017 281676 0.00 0.00 0.00 0.00 0.80 0.80 0.80 115.77 89.62 2.4 572 1520806
+1 97 1 1 0 0 162 20 19 0.20 0.20 1355 6365 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 17.00 1.0 8001 1833296
+1 81 1 1 8 0 2393 337 202 7.19 3.79 480188 13650 0.00 0.00 0.00 0.00 0.00 1.00 1.00 379.84 567.66 3.0 11671 1879063
+1 78 1 1 21 8 5068 151 101 2.60 7.40 185450 48157 3.20 4.00 4.00 0.00 2.40 0.20 0.20 209.60 267.80 7.6 327 1309747
+1 93 1 1 11 8 2661 141 119 0.60 0.60 16438 22723 0.00 0.00 0.00 0.00 0.00 1.20 1.60 33.00 51.00 1.6 1877 968390
+1 92 1 1 16 4 1169 122 93 0.40 0.80 266767 41480 6.39 13.37 35.53 57.09 1.60 7.78 37.52 20.36 98.20 4.0 151 1027202
+1 88 1 1 5 1 797 84 72 3.00 2.00 78488 73953 0.00 0.00 0.00 0.00 0.00 2.20 3.40 222.80 232.40 1.4 5810 1846563
+1 82 1 1 12 9 4495 473 204 1.60 1.60 187576 143122 0.00 0.00 0.00 0.00 0.00 8.40 9.40 141.40 215.80 3.8 2019 1005795
+1 77 1 1 9 0 2261 97 91 7.01 20.64 29185 38582 0.00 0.00 0.00 0.00 0.00 2.00 2.40 233.27 439.88 2.4 656 1083941
+1 86 1 1 2 0 399 33 24 2.00 2.00 62604 29308 3.60 3.60 3.60 0.00 0.00 2.80 2.80 166.40 159.20 1.8 322 1814866
+1 85 1 1 14 0 2339 181 121 3.40 3.20 89211 45547 0.00 0.00 0.00 0.00 0.20 2.40 3.40 175.00 275.80 4.0 723 1106075
+1 63 1 1 11 1 5233 687 559 9.42 4.61 315760 73309 3.21 5.21 5.21 0.00 0.60 4.41 5.01 457.92 809.02 1.0 283 1000053
+1 89 1 1 2 0 4178 252 175 0.80 1.40 136384 89683 0.00 0.00 0.00 0.00 0.00 12.80 12.80 74.40 116.20 2.6 4554 1404134
+1 93 1 1 7 0 3739 162 141 0.80 3.21 92903 92426 6.21 8.22 7.82 0.00 0.80 10.62 14.43 42.28 98.80 5.2 234 977153
+1 89 1 1 5 0 1928 215 140 1.80 1.80 166288 22784 0.80 0.80 0.80 0.00 2.40 3.00 4.40 143.20 206.80 1.3 271 1056302
+1 62 1 1 48 1 3046 276 129 11.82 34.67 155350 41410 4.41 27.25 66.93 126.25 0.00 8.02 9.42 415.83 808.82 2.8 140 1093905
+1 93 1 1 5 0 955 77 106 1.20 1.40 82944 127270 0.00 0.00 0.00 0.00 0.00 8.40 11.20 69.60 125.20 1.0 658 1059768
+1 69 1 1 12 2 7402 1453 1388 4.59 1.40 1239896 1176112 0.00 0.00 0.00 0.00 0.20 7.58 8.38 238.52 476.25 1.5 808 1057677
+1 88 1 1 7 3 1631 203 199 1.80 6.60 83523 22114 0.00 0.00 0.00 0.00 1.60 4.40 4.80 106.80 183.40 2.5 801 1048598
+1 98 1 1 2 2 222 11 16 0.20 0.20 13354 51904 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 6992 1863239
+1 84 1 1 3 1 521 85 50 2.20 2.20 241528 164561 0.00 0.00 0.00 0.00 0.00 4.80 8.20 207.20 182.00 2.8 3313 1822792
+1 0 1 1 2 0 1141 139 86 0.40 0.60 14230 19909 2.80 3.20 5.20 11.00 0.00 4.80 5.00 33.80 73.60 232 95 5
+1 90 1 1 17 1 1972 142 72 3.38 6.16 126748 18912 0.00 0.00 0.00 0.00 0.00 5.17 21.47 140.16 266.00 3.0 520 1010212
+1 75 1 1 11 4 4533 431 337 6.80 4.00 171401 77556 3.40 3.40 3.40 0.00 0.80 2.80 4.40 334.40 512.00 2.5 337 1136933
+1 94 1 1 0 0 1944 114 133 0.20 0.20 10959 36319 1.00 1.80 1.80 0.00 0.00 1.80 3.00 13.20 44.20 2.0 136 1053427
+1 96 1 1 2 2 1148 62 40 0.20 0.20 3507 39776 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 17.60 1.0 588 1065888
+1 84 1 1 5 2 3209 425 330 1.40 2.00 382241 34171 6.00 6.00 6.00 0.00 2.00 4.80 7.60 116.80 175.40 1.5 265 1093546
+1 0 1 1 52 57 4676 318 221 1.40 3.01 651365 561036 0.00 0.00 0.00 0.00 0.00 19.64 32.87 81.76 143.69 1574 80 20
+1 81 1 1 10 3 3768 463 264 2.20 0.80 235474 60534 8.80 11.60 12.80 3.80 25.60 8.20 9.20 118.80 233.20 1.0 157 1099117
+1 64 1 1 38 1 4458 344 177 10.00 28.80 625132 49787 1.20 13.80 29.00 93.00 1.00 17.00 20.40 337.40 642.20 2.2 153 1096109
+1 95 1 1 0 0 568 54 50 0.40 0.60 4835 16186 0.00 0.00 0.00 0.00 0.00 0.20 0.20 33.60 78.00 1.0 715 1033664
+1 96 1 1 33 50 343 44 42 0.80 0.60 7971 14495 0.00 0.00 0.00 0.00 0.00 0.40 0.40 37.68 44.89 1.0 399 1745525
+1 87 1 1 19 21 2218 257 214 4.80 1.40 121798 10325 0.80 0.80 0.80 0.00 0.80 0.40 0.40 219.60 325.80 3.4 303 1709224
+1 88 1 1 5 0 1333 185 167 3.99 1.20 104199 21861 0.00 0.00 0.00 0.00 0.00 2.99 5.99 196.01 281.44 1.2 8052 1858590
+1 94 1 1 17 3 720 40 67 0.80 1.60 74233 9042 0.00 0.00 0.00 0.00 0.00 1.20 2.79 64.67 106.59 1.6 6058 1852752
+1 83 1 1 31 10 2096 252 197 1.60 3.80 320289 105215 0.00 0.00 0.00 0.00 5.20 27.60 37.40 261.60 324.20 4.6 722 1033245
+1 86 1 1 2 2 3472 220 193 0.20 0.20 23632 308442 4.41 6.01 6.01 0.00 0.40 0.60 0.60 15.23 73.55 3.0 259 1001804
+1 91 1 1 2 1 2224 211 80 0.20 0.20 752908 128130 0.00 0.00 0.00 0.00 26.60 0.60 0.60 23.20 54.00 4.4 2382 1731205
+1 81 1 1 1 1 2811 273 137 1.60 4.20 1047353 926559 4.20 11.80 23.20 45.20 2.00 41.20 67.40 76.00 159.60 3.8 405 1034064
+1 98 1 1 0 0 247 35 20 0.20 0.20 50244 7235 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 1.0 7215 1847184
+1 79 1 1 27 21 4340 154 109 1.80 2.40 189072 48502 0.00 0.00 0.00 0.00 0.00 14.63 31.06 157.72 372.55 2.0 743 1018156
+1 94 1 1 1 0 459 93 44 0.20 0.20 333283 30776 0.00 0.00 0.00 0.00 0.00 0.60 0.60 20.80 19.60 2.6 2006 1719051
+1 87 1 1 6 0 1981 108 56 1.40 2.40 48258 15708 0.00 0.00 0.00 0.00 0.00 7.58 7.98 166.27 233.33 2.5 647 1069704
+1 76 1 1 9 0 4135 444 433 8.40 2.20 232559 81621 0.00 0.00 0.00 0.00 0.20 0.00 0.00 382.80 561.80 2.8 456 1757352
+1 86 1 1 11 7 7136 279 234 0.60 0.60 93643 71213 0.00 0.00 0.00 0.00 0.00 6.40 6.40 49.40 65.20 4.8 369 1526109
+1 96 1 1 1 1 1603 54 60 0.20 0.20 59769 30942 1.40 1.40 1.40 0.00 1.00 1.00 1.00 15.60 17.40 1.0 281 1751058
+1 78 1 1 9 1 4655 404 140 3.60 5.80 400425 55951 0.00 0.00 0.00 0.00 0.00 14.20 20.60 282.40 400.40 1.4 939 1048038
+1 96 1 1 1 0 852 131 54 0.40 0.40 147982 133938 0.00 0.00 0.00 0.00 0.00 0.80 1.20 36.00 37.80 4.0 1094 1753981
+1 92 1 1 23 9 1006 86 91 1.00 2.20 56527 48456 0.00 0.00 0.00 0.00 0.60 18.36 18.76 59.08 108.38 2.6 831 972132
+1 91 1 1 4 0 1799 122 72 0.60 0.60 16781 17929 0.40 0.40 0.40 0.00 0.00 1.80 4.60 44.40 50.20 1.5 250 1113107
+1 91 1 1 13 0 2093 98 74 0.40 1.80 39697 6783 0.00 0.00 0.00 0.00 0.00 14.20 120.20 43.20 67.60 3.4 5549 1410350
+1 89 1 1 15 6 1771 231 173 2.79 1.20 287828 37280 0.00 0.00 0.00 0.00 0.60 11.18 11.58 144.11 234.33 2.4 723 968551
+1 68 1 1 19 7 5222 117 91 2.80 10.00 49911 36240 0.00 0.00 0.00 0.00 0.00 0.80 0.80 215.20 242.80 3.2 1051 1519818
+1 82 1 1 72 89 5298 221 174 2.00 8.60 224286 66761 18.40 38.00 81.60 168.60 11.60 3.60 19.60 124.80 245.60 2.0 144 1003038
+1 89 1 1 7 5 3577 180 135 0.60 3.01 100188 34902 0.00 0.00 0.00 0.00 0.00 10.62 11.62 53.31 79.96 1.0 517 984358
+1 76 1 1 9 1 3007 418 378 7.40 2.00 458899 227474 0.00 0.00 0.00 0.00 0.00 12.80 25.20 344.40 503.20 2.2 6462 1845981
+1 82 1 1 19 26 2041 433 332 2.20 5.80 417645 100281 0.00 0.00 0.00 0.00 0.00 8.60 17.00 151.60 182.20 2.2 414 1697981
+1 57 1 1 46 1 4794 362 243 12.83 30.06 260165 41943 2.20 10.02 19.64 36.67 1.40 23.25 29.06 504.21 898.00 1.5 163 1107203
+1 98 1 1 0 0 175 10 22 0.20 0.20 2738 21092 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.4 8334 1861017
+1 89 1 1 3 0 4123 229 116 0.80 0.80 278629 221211 0.00 0.00 0.00 0.00 0.00 4.59 7.19 58.68 191.22 3.6 3536 1329499
+1 89 1 1 50 64 1493 162 83 0.60 1.00 106998 27928 0.00 0.00 0.00 0.00 0.00 9.58 11.38 79.64 154.49 1.3 473 1065485
+1 76 1 1 16 1 3680 481 367 6.20 2.20 366751 96530 1.80 11.40 23.00 35.60 0.00 8.20 9.00 319.80 518.00 3.0 174 1533642
+1 96 1 1 3 2 437 57 46 0.40 0.40 1521 13330 0.00 0.00 0.00 0.00 0.00 0.00 0.00 34.80 39.80 2.0 658 1721608
+1 84 1 1 14 8 2420 355 239 0.80 0.80 81892 50960 7.21 13.43 53.71 76.35 2.61 51.10 63.73 78.96 164.13 3.0 140 1097291
+1 83 1 1 4 1 541 60 27 2.60 2.60 160141 22719 0.00 0.00 0.00 0.00 0.00 2.00 2.00 211.20 216.60 1.6 2015 1805800
+1 86 1 1 3 0 2457 226 203 3.39 2.59 87333 56444 3.59 6.79 4.99 0.00 0.00 4.79 4.79 151.70 231.74 1.0 192 1122643
+1 87 1 1 15 0 1491 50 50 3.58 11.33 45636 29872 0.00 0.00 0.00 0.00 0.00 6.76 6.96 243.94 352.49 1.5 676 1055254
+1 84 1 1 6 4 3360 291 248 1.20 2.79 149886 83802 0.00 0.00 0.00 0.00 0.20 21.56 21.76 129.34 289.82 1.3 991 1042996
+1 98 1 1 18 26 256 26 22 0.20 0.20 2031 7574 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 17.40 2.2 860 1720098
+1 84 1 1 28 13 3753 371 248 4.60 7.80 487032 117631 0.00 0.00 0.00 0.00 0.00 2.40 2.80 263.80 385.00 5.4 2341 1330541
+1 90 1 1 26 40 2662 301 155 0.20 0.20 8421 32644 0.00 0.00 0.00 0.00 0.00 2.20 2.40 13.97 18.16 1.8 954 1125487
+1 85 1 1 5 1 3459 140 163 1.80 1.80 81599 264271 5.20 7.00 7.00 0.00 2.40 4.20 4.80 135.80 216.40 2.0 507 1019634
+1 95 1 1 37 53 1209 83 81 0.20 0.20 9480 33242 0.00 0.00 0.00 0.00 0.20 1.40 2.40 16.00 22.40 1.0 477 1060016
+1 64 1 1 100 108 8616 836 566 8.40 3.60 710465 472436 0.00 0.00 0.00 0.00 0.00 4.80 5.60 437.20 668.20 1.5 710 1013787
+1 79 1 1 19 4 4329 648 451 3.60 1.60 330594 205467 0.00 0.00 0.00 0.00 0.00 4.80 4.80 356.20 330.00 3.4 1237 1036218
+1 96 1 1 1 1 1115 36 29 0.80 1.60 24117 49679 0.00 0.00 0.00 0.00 0.00 0.80 0.80 41.00 61.40 1.2 8171 1838451
+1 83 1 1 59 82 1680 262 174 0.40 0.40 985090 421929 18.04 32.87 59.92 69.94 15.23 26.25 44.49 51.70 178.96 1.8 150 1017930
+1 90 1 1 15 4 1209 118 77 1.60 1.80 97947 88854 0.00 0.00 0.00 0.00 0.00 5.20 7.80 93.80 173.80 1.3 2764 1013981
+1 0 1 1 24 17 2002 197 142 1.20 1.20 268033 42989 0.00 0.00 0.00 0.00 0.00 7.00 11.80 132.20 301.40 907 82 18
+1 93 1 1 4 0 1525 255 166 0.40 0.40 10103 28248 0.00 0.00 0.00 0.00 0.20 20.80 21.60 35.40 170.20 1.2 541 976770
+1 98 1 1 1 1 293 16 19 0.20 0.20 585 10621 0.00 0.00 0.00 0.00 1.00 0.00 0.00 15.60 17.00 2.0 1114 1718784
+1 78 1 1 17 9 2154 169 126 4.20 9.80 435778 96535 12.40 21.80 21.40 0.00 3.60 30.20 33.80 266.20 458.00 1.8 256 974442
+1 0 1 1 3 0 943 119 116 0.80 0.60 34217 32924 0.00 0.00 0.00 0.00 0.00 1.60 1.60 58.40 130.00 531 93 7
+1 93 1 1 4 2 2005 146 106 0.40 0.40 238364 19838 1.60 1.60 1.60 0.00 3.01 2.40 2.40 31.46 55.51 1.0 209 1025621
+1 88 1 1 16 1 2239 174 120 1.00 1.20 84704 41242 6.19 10.98 41.72 61.88 2.20 25.15 40.32 72.06 179.24 1.5 205 1096663
+1 90 1 1 3 0 1421 220 183 3.20 1.00 304536 18545 0.00 0.00 0.00 0.00 0.00 0.00 0.00 159.40 231.60 2.2 7319 1873293
+1 98 1 1 1 0 405 43 34 0.20 0.20 37605 9043 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.77 17.17 1.2 949 1739202
+1 96 1 1 19 27 198 18 19 0.20 0.20 7064 8851 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 16.80 1.0 6343 1857216
+1 0 1 1 24 9 1698 259 107 2.00 2.60 810653 260681 13.40 34.20 100.60 191.00 2.80 10.40 17.20 170.60 364.80 134 80 19
+1 94 1 1 37 53 1569 139 77 0.20 0.40 60204 26377 0.00 0.00 0.00 0.00 0.00 11.78 11.78 34.73 90.22 1.0 328 1021311
+1 85 1 1 1 0 3289 96 87 0.40 0.60 9591 19138 0.00 0.00 0.00 0.00 0.00 0.00 0.00 44.11 51.90 1.8 1352 1749926
+1 77 1 1 32 5 4074 768 402 2.20 3.80 335040 67394 0.00 0.00 0.00 0.00 0.00 3.40 26.20 178.20 312.20 4.4 2478 1546706
+1 87 1 1 23 9 2699 142 95 2.60 3.20 414327 272247 0.00 0.00 0.00 0.00 0.00 3.00 6.00 193.20 259.40 4.8 2672 1564619
+1 91 1 1 4 0 2061 531 240 0.20 0.20 56419 91653 0.80 1.00 0.60 0.00 0.20 5.80 5.80 20.20 88.40 1.0 269 1064781
+1 81 1 1 14 12 6674 369 225 1.60 3.00 124916 65986 0.00 0.00 0.00 0.00 0.00 2.40 3.40 94.80 166.00 1.0 1087 1014102
+1 96 1 1 2 0 346 33 20 1.60 9.40 99978 34645 0.00 0.00 0.00 0.00 0.00 1.40 2.40 43.00 75.20 2.0 4305 1821611
+1 76 1 1 24 20 3553 363 194 3.20 4.40 84523 47889 7.80 23.20 50.00 102.00 1.80 26.80 27.60 219.20 433.80 1.5 166 1102165
+1 98 1 1 0 0 203 28 24 0.20 0.20 627 4744 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.63 17.23 1.0 1311 1749170
+1 72 1 1 7 0 3478 716 203 5.99 19.16 1303922 52090 4.79 27.35 76.65 130.14 0.00 12.38 21.56 223.75 468.86 4.0 115 1101715
+1 66 1 1 25 14 4621 503 191 10.40 10.60 405253 204578 0.00 0.00 0.00 0.00 0.00 7.00 12.00 486.40 913.60 5.8 2976 1040554
+1 96 1 1 0 0 1499 77 46 0.20 0.20 10497 10210 0.80 1.20 1.20 0.00 0.20 0.80 0.80 16.40 16.80 1.0 307 1752248
+1 77 1 1 56 62 7214 430 266 5.00 2.80 541187 136387 0.00 0.00 0.00 0.00 0.00 2.40 3.00 275.00 525.20 4.2 656 1341658
+1 0 1 1 3 0 4168 321 231 1.00 3.60 1292810 1170072 4.00 5.60 5.60 0.00 0.20 2.40 2.60 49.00 72.00 399 85 15
+1 93 1 1 48 59 1137 157 91 0.80 0.80 130417 123332 0.00 0.00 0.00 0.00 0.00 0.40 0.40 53.40 84.60 4.2 2524 1575485
+1 73 1 1 14 10 4603 973 646 4.59 9.38 1129725 1009913 0.00 0.00 0.00 0.00 211.58 3.99 4.39 173.85 513.97 2.2 3782 1037549
+1 97 1 1 0 0 179 11 25 0.20 0.20 12930 29466 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.0 2831 1770204
+1 86 1 1 4 2 3812 297 147 0.40 0.40 394794 88076 0.00 0.00 0.00 0.00 0.00 1.60 2.00 38.00 77.40 3.0 1207 1536325
+1 92 1 1 9 8 1075 93 53 0.60 2.40 167060 39030 0.00 0.00 0.00 0.00 0.00 8.98 11.98 46.51 101.60 2.0 657 996094
+1 89 1 1 0 0 463 34 34 0.20 0.20 749 7750 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.6 4098 1776888
+1 88 1 1 3 1 3179 255 184 0.40 1.80 142564 143743 1.00 1.20 1.20 0.00 0.00 2.80 2.80 38.00 48.40 2.4 261 1535739
+1 88 1 1 21 11 1435 149 127 1.00 1.00 50750 75544 0.00 0.00 0.00 0.00 0.00 35.33 35.53 76.45 276.65 1.0 692 977183
+1 92 1 1 2 0 330 30 29 1.80 1.80 62207 24991 0.00 0.00 0.00 0.00 0.00 3.60 6.80 161.20 149.00 1.0 6792 1855616
+1 96 1 1 2 1 587 45 32 0.60 0.60 94622 9992 0.00 0.00 0.00 0.00 0.00 0.20 0.40 31.20 38.40 1.4 6259 1857560
+1 97 1 1 0 0 267 31 43 0.40 0.40 420 5591 0.00 0.00 0.00 0.00 0.00 0.00 0.00 32.27 29.88 1.0 1965 1765388
+1 91 1 1 4 0 1266 153 133 2.60 0.80 57254 23163 0.00 0.00 0.00 0.00 0.00 5.00 5.00 122.80 202.60 1.0 586 1067526
+1 75 1 1 8 0 3791 399 369 5.80 5.20 232803 99600 0.00 0.00 0.00 0.00 0.00 14.80 17.20 271.80 471.60 1.0 960 1050710
+1 89 1 1 393 404 4310 273 141 0.60 2.00 224160 245543 10.18 14.97 14.97 0.00 8.98 17.56 30.94 37.13 113.17 3.8 264 1333863
+1 89 1 1 12 5 3132 204 169 0.60 1.40 139503 19639 5.00 15.40 24.00 42.40 1.20 3.00 23.40 45.20 105.40 1.5 316 981682
+1 97 1 1 4 4 222 35 31 0.20 0.20 3686 8226 0.00 0.00 0.00 0.00 0.60 0.00 0.00 11.58 13.97 1.0 427 1753803
+1 81 1 1 49 55 2576 195 145 5.61 7.01 215151 33737 21.24 72.55 132.87 218.84 3.01 11.82 12.42 231.06 527.25 2.0 187 1028593
+1 93 1 1 16 23 970 139 83 0.20 0.20 129190 133167 0.00 0.00 0.00 0.00 0.00 0.20 0.40 17.20 17.60 3.2 1448 1756176
+1 69 1 1 20 6 6768 388 300 5.00 11.60 232295 62970 0.80 0.80 0.80 0.00 1.20 1.00 1.00 303.00 420.60 6.6 352 1317531
+1 86 1 1 41 28 3198 232 175 3.20 5.20 183291 216937 0.00 0.00 0.00 0.00 0.00 0.60 1.00 183.40 244.00 3.0 812 1541331
+1 79 1 1 16 3 4601 285 200 2.00 4.21 154735 58160 0.00 0.00 0.00 0.00 0.20 22.44 29.66 134.27 249.90 3.3 575 1011166
+1 98 1 1 0 0 206 13 31 0.20 0.20 1306 18946 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.60 1.0 7134 1873480
+1 76 1 1 9 2 2171 220 134 6.81 19.64 40442 53040 2.40 2.40 3.81 10.42 1.00 10.82 14.83 244.29 443.89 1.8 180 1105772
+1 93 1 1 29 40 624 41 45 1.80 1.60 53108 133278 0.00 0.00 0.00 0.00 0.00 0.20 0.20 115.60 147.20 1.2 6893 1853598
+1 88 1 1 18 16 5396 303 149 0.80 2.20 986318 36593 0.00 0.00 0.00 0.00 0.20 2.00 4.60 44.00 72.00 2.5 608 1009339
+1 82 1 1 19 12 3164 165 158 1.20 1.00 216323 361322 48.40 100.40 102.20 23.80 4.40 3.80 7.00 104.80 106.40 4.4 251 1525315
+1 98 1 1 0 0 138 9 19 0.20 0.20 425 12721 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6027 1855560
+1 94 1 1 14 13 2410 265 194 0.20 0.20 29585 37210 2.20 3.00 3.00 0.00 0.60 3.80 5.20 15.80 21.40 1.5 171 1085166
+1 86 1 1 7 0 2569 185 102 2.60 2.40 98063 48782 3.60 7.80 47.20 70.20 0.20 12.80 13.80 183.00 291.40 1.6 123 1107248
+1 97 1 1 16 24 281 11 22 0.40 0.80 9868 65802 0.00 0.00 0.00 0.00 0.00 0.00 0.00 32.34 33.93 1.2 7717 1866314
+1 85 1 1 5 0 3091 316 355 3.60 6.60 264451 45752 0.00 0.00 0.00 0.00 0.00 0.40 0.40 139.00 238.00 5.6 1651 1698152
+1 96 1 1 0 0 2194 111 125 0.20 0.20 3731 18802 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 2.0 562 1725064
+1 92 1 1 0 0 3516 149 194 0.60 0.20 200474 399631 3.60 4.60 5.80 2.80 1.40 1.20 1.60 43.00 85.40 2.2 155 1365594
+1 90 1 1 14 14 1499 125 75 0.80 0.80 156488 21855 0.00 0.00 0.00 0.00 0.00 13.43 27.05 86.77 120.04 1.0 1443 1083232
+1 82 1 1 21 10 3214 198 113 1.20 1.20 274440 103344 9.22 16.43 23.65 21.44 2.81 19.64 28.86 67.33 254.91 3.6 416 1010256
+1 84 1 1 54 69 1119 120 112 0.60 0.60 255769 25425 2.81 7.41 9.82 7.41 0.80 45.69 46.49 49.70 160.92 4.0 260 1042852
+1 79 1 1 8 0 2896 438 400 8.20 2.00 238898 25251 0.00 0.00 0.00 0.00 0.00 0.00 0.00 384.20 543.40 2.2 7384 1874275
+1 93 1 1 1 0 1465 127 89 0.20 0.20 52089 44307 4.20 7.00 7.00 0.00 0.00 1.00 1.00 26.00 36.00 1.0 288 1011408
+1 96 1 1 1 0 581 54 52 0.20 0.20 2830 19132 0.00 0.00 0.00 0.00 0.00 1.40 1.40 15.63 24.05 1.0 758 1040858
+1 85 1 1 2 0 3952 272 185 2.40 4.19 108374 56949 7.39 11.18 22.16 41.32 0.40 4.59 5.19 116.97 256.29 1.0 173 983393
+1 96 1 1 3 3 245 14 18 0.60 0.60 7337 7968 0.00 0.00 0.00 0.00 0.00 0.00 0.00 47.80 57.80 1.2 7393 1865622
+1 82 1 1 230 227 5281 472 439 0.40 1.80 556076 308309 0.00 0.00 0.00 0.00 0.00 12.60 35.00 20.00 66.80 5.0 1135 1334136
+1 85 1 1 1 0 2496 137 135 1.40 1.80 95179 182817 0.00 0.00 0.00 0.00 0.00 0.80 1.00 102.60 189.80 2.2 937 1020712
+1 80 1 1 30 40 2753 404 379 3.40 4.20 332007 232751 0.00 0.00 0.00 0.00 0.00 3.40 3.80 188.60 269.80 1.3 745 1127904
+1 97 1 1 0 0 1358 60 55 0.20 0.20 1537 3667 1.80 2.00 2.00 0.00 0.20 0.80 0.80 15.60 16.80 1.0 257 1752019
+1 68 1 1 13 1 4872 652 550 8.20 2.20 411321 92375 0.00 0.00 0.00 0.00 0.00 5.80 10.60 407.80 658.00 3.0 845 1055786
+1 84 1 1 4 0 3028 272 172 3.40 1.80 233445 29012 2.20 3.60 12.40 556.20 0.60 6.20 8.60 183.80 323.80 1.6 169 1003584
+1 87 1 1 40 62 3236 247 277 0.20 0.20 149105 68558 6.00 22.20 26.20 51.20 0.40 7.00 10.20 36.80 123.20 2.8 270 1135904
+1 93 1 1 50 59 1547 185 141 0.60 0.40 39002 26888 0.00 0.00 0.00 0.00 0.20 4.21 6.21 30.06 50.50 4.6 733 1057994
+1 87 1 1 5 2 2644 327 197 0.40 0.40 103311 47800 0.00 0.00 0.00 0.00 0.20 11.60 11.60 50.80 152.60 1.3 715 1104346
+1 98 1 1 2 1 172 12 12 0.20 0.20 6991 2794 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 8498 1866072
+1 97 1 1 51 70 393 38 58 0.20 0.20 3889 60386 0.00 0.00 0.00 0.00 0.00 0.40 0.60 15.37 24.75 1.0 494 1727013
+1 92 1 1 29 41 1607 95 66 0.20 0.20 7241 24019 0.00 0.00 0.00 0.00 0.00 1.40 1.40 30.40 42.00 1.7 935 998152
+1 99 1 1 1 1 164 15 17 0.20 0.20 7020 6495 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 8510 1869780
+1 80 1 1 7 5 5673 346 264 0.40 0.40 158597 252957 0.40 0.80 0.80 0.00 0.00 3.81 5.01 29.46 286.37 1.0 621 1009584
+1 94 1 1 6 1 1084 81 87 0.80 2.60 36715 92172 0.00 0.00 0.00 0.00 0.00 1.00 1.80 83.20 135.40 2.8 1029 1544618
+1 85 1 1 3 0 478 67 39 2.20 2.20 206591 47523 0.00 0.00 0.00 0.00 2.00 3.40 4.40 206.60 180.00 1.6 416 1815674
+1 81 1 1 796 14 1627 15 28 0.20 0.20 1487 64857 0.00 0.00 0.00 0.00 0.00 94.40 94.40 15.60 16.80 1.8 3059 1845336
+1 87 1 1 59 75 3562 297 259 0.20 0.20 49443 74684 0.00 0.00 0.00 0.00 0.60 6.01 9.02 17.23 69.94 2.2 419 1054597
+1 74 1 1 21 1 5699 525 452 8.60 2.40 329026 20245 0.00 0.00 0.00 0.00 0.00 17.40 17.40 413.40 648.60 4.4 3792 1346574
+1 92 1 1 2 0 3168 78 68 0.40 0.40 94366 48138 0.00 0.00 0.00 0.00 0.00 1.00 1.20 29.20 94.20 3.4 987 1629045
+1 90 1 1 19 6 1985 190 110 1.00 1.00 259376 68790 2.99 4.39 8.58 10.78 2.00 7.19 7.98 80.84 178.64 1.5 287 986922
+1 89 1 1 2 0 967 126 53 1.60 2.20 361138 138354 0.00 0.00 0.00 0.00 0.00 16.40 32.40 135.20 192.20 2.2 7329 1876546
+1 83 1 1 16 7 5260 356 340 2.20 7.80 30065 28222 0.00 0.00 0.00 0.00 0.00 0.40 0.40 163.40 185.80 2.6 2224 1551408
+1 95 1 1 0 0 1170 168 100 0.20 0.20 282286 34783 0.00 0.00 0.00 0.00 0.00 4.20 6.20 15.60 45.60 1.6 1639 1073829
+1 76 1 1 16 0 2980 326 266 5.40 5.80 149079 63913 0.00 0.00 0.00 0.00 0.20 0.40 0.60 277.00 469.80 4.6 1028 1626883
+1 59 1 1 79 72 5033 593 499 9.00 5.20 489658 44708 5.00 35.40 69.60 129.00 1.00 57.80 87.80 464.00 787.20 1.7 306 1027808
+1 97 1 1 0 0 508 105 41 0.20 0.20 133259 132790 0.00 0.00 0.00 0.00 0.40 0.00 0.00 15.60 17.20 3.2 749 1741819
+1 96 1 1 5 2 523 51 44 0.60 0.60 11383 37532 0.00 0.00 0.00 0.00 0.00 0.60 0.60 31.00 39.60 1.3 572 1036720
+1 89 1 1 2 1 3985 235 135 0.80 2.60 8082 67275 4.40 7.60 6.00 0.00 0.80 0.40 0.40 38.60 64.20 1.2 235 1129376
+1 88 1 1 11 10 2301 262 118 0.60 0.60 981662 93397 0.00 0.00 0.00 0.00 0.00 3.00 3.40 65.40 78.80 2.0 2731 1089587
+1 85 1 1 1 0 3266 549 109 0.20 0.20 118567 45860 9.38 25.15 49.70 87.62 0.00 99.00 110.18 21.56 222.55 2.2 253 997362
+1 89 1 1 6 1 2745 152 117 1.00 3.80 12744 32916 0.00 0.00 0.00 0.00 0.20 12.40 12.60 55.80 99.40 1.0 1343 1113069
+1 84 1 1 0 0 4714 171 139 0.20 0.20 90210 17821 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.20 18.20 2.2 775 1769904
+1 90 1 1 56 73 2713 188 151 0.60 2.39 170618 30422 0.00 0.00 0.00 0.00 0.00 0.60 0.99 49.50 74.35 3.6 1100 1525921
+1 89 1 1 5 2 3352 287 273 0.40 0.80 152003 157928 0.00 0.00 0.00 0.00 0.00 3.00 3.00 50.40 104.80 3.8 2959 1546090
+1 60 1 1 25 2 5086 335 283 9.80 28.00 723823 61615 4.80 12.60 26.20 117.00 5.60 24.20 33.00 394.20 727.00 4.2 170 1098459
+1 97 1 1 9 1 333 40 31 0.20 0.20 66184 26605 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 18.00 2.0 3368 1819768
+1 99 1 1 0 0 151 7 9 0.20 0.20 473 4910 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 9016 1873488
+1 89 1 1 3 0 1905 173 129 1.00 1.00 165380 57897 0.00 0.00 0.00 0.00 0.00 1.00 1.40 126.95 99.40 1.5 943 1045870
+1 84 1 1 5 2 3416 154 75 0.80 4.60 525401 62664 1.60 8.80 27.40 49.80 0.80 2.80 4.00 41.00 98.60 2.8 164 1087301
+1 0 1 1 3 0 3042 276 139 0.80 2.00 903563 510177 0.00 0.00 0.00 0.00 0.00 25.85 30.66 59.72 112.22 2170 87 13
+1 98 1 1 0 0 218 23 28 0.20 0.20 2094 7513 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.20 16.80 1.0 7696 1871514
+1 74 1 1 25 22 5511 398 245 2.60 2.40 124777 90042 3.20 4.20 4.20 0.00 3.00 9.40 10.00 333.80 368.80 1.5 428 1000051
+1 96 1 1 2 0 794 33 39 0.40 0.80 2305 14686 0.00 0.00 0.00 0.00 0.80 0.40 0.60 43.11 52.89 1.0 1563 1022057
+1 91 1 1 29 36 1356 262 184 0.20 0.20 23770 57600 14.37 20.36 26.55 49.30 0.00 8.78 14.57 17.17 47.90 2.0 151 1012145
+1 58 1 1 36 2 5332 576 393 10.58 16.17 232136 41525 6.79 34.93 83.63 188.02 0.20 9.18 11.78 517.37 879.24 4.4 130 1091202
+1 92 1 1 2 0 1440 176 139 0.40 0.60 8153 18700 3.19 3.39 3.39 0.00 0.00 4.99 6.79 31.14 64.87 4.0 322 1098930
+1 94 1 1 10 5 2243 96 87 1.60 0.60 39657 55403 0.00 0.00 0.00 0.00 0.00 0.00 0.00 85.63 120.36 2.0 1775 1638170
+1 53 1 1 83 68 5019 529 453 11.98 19.56 259917 42539 6.99 9.38 11.78 6.59 5.59 13.57 15.37 536.13 873.05 5.8 233 1091556
+1 91 1 1 1 0 3162 262 164 1.00 0.40 263084 234498 0.00 0.00 0.00 0.00 0.00 0.80 0.80 52.60 71.80 4.8 1358 1616242
+1 91 1 1 31 45 1372 125 53 0.60 0.60 146667 40853 0.00 0.00 0.00 0.00 1.60 9.80 18.40 37.40 45.80 1.2 663 1759590
+1 85 1 1 5 0 1134 113 83 5.80 3.40 208562 32671 0.00 0.00 0.00 0.00 0.20 0.00 0.00 248.00 385.40 1.8 2695 1772870
+1 98 1 1 0 0 555 169 53 0.20 0.20 370181 201206 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.6 1326 1745715
+1 88 1 1 68 85 3048 288 160 0.40 0.60 236299 104846 0.00 0.00 0.00 0.00 0.00 2.00 3.20 33.60 46.80 1.0 415 987549
+1 67 1 1 14 1 3532 235 175 10.80 32.00 201549 27048 3.00 5.00 9.00 8.60 4.20 14.40 15.80 353.00 725.00 1.0 143 1077171
+1 66 1 1 63 8 2788 309 214 7.39 6.19 609458 142265 7.78 16.57 19.36 17.76 8.78 60.68 64.87 339.72 695.81 4.0 321 1039178
+1 91 1 1 0 0 767 38 41 0.20 0.20 960 6172 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.4 975 1761416
+1 83 1 1 4 0 539 63 44 2.60 2.60 189971 37803 6.80 6.80 6.80 0.00 0.00 2.60 3.80 215.80 216.60 1.6 224 1815128
+1 92 1 1 9 7 2053 156 131 0.40 0.40 149799 52383 2.80 6.20 8.80 15.00 3.00 9.60 14.80 39.20 74.20 1.7 439 973485
+1 72 1 1 66 46 2127 209 61 10.18 26.35 324528 22056 0.00 0.00 0.00 0.00 0.40 2.20 2.40 408.58 673.85 1.5 1532 1021378
+1 90 1 1 5 3 2625 136 117 1.00 0.80 20621 48605 0.00 0.00 0.00 0.00 0.20 5.20 5.60 46.20 88.20 1.0 478 1067037
+1 94 1 1 2 1 2441 136 80 0.40 1.80 81726 39191 0.00 0.00 0.00 0.00 0.00 0.60 0.80 16.43 19.04 1.2 527 1743094
+1 87 1 1 13 11 3030 332 180 1.40 4.40 1200996 1105343 1.20 1.60 1.60 0.00 0.80 8.60 13.80 76.60 104.60 1.0 200 1014856
+1 89 1 1 18 24 422 59 64 0.20 0.20 17697 120835 0.00 0.00 0.00 0.00 0.00 0.40 0.60 15.60 16.80 1.0 1722 1768696
+1 74 1 1 9 0 1731 246 188 6.39 4.39 163671 33692 0.00 0.00 0.00 0.00 0.00 4.39 5.79 400.80 489.02 1.8 3659 1815918
+1 90 1 1 3 1 2215 179 112 0.40 0.40 72784 88980 5.00 24.40 44.60 92.00 1.20 9.00 13.80 29.00 81.40 2.0 136 1051462
+1 84 1 1 16 0 4343 189 200 5.20 3.20 114332 129891 0.00 0.00 0.00 0.00 0.00 0.00 0.00 213.20 341.80 4.2 2785 1647862
+1 98 1 1 0 0 1070 23 26 0.20 0.20 32006 17738 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 8258 1866982
+1 91 1 1 0 0 2025 135 85 0.60 0.80 395767 76084 0.00 0.00 0.00 0.00 0.20 29.74 29.74 52.50 117.96 2.0 742 1012610
+1 86 1 1 12 1 3119 262 182 2.60 6.80 302944 102304 4.40 21.00 42.80 93.80 0.80 10.40 13.40 117.20 276.60 7.0 266 1313187
+1 63 1 1 19 2 3575 279 128 10.80 32.60 288291 40182 0.00 0.00 0.00 0.00 0.00 34.00 66.60 374.40 795.80 2.0 1443 1090662
+1 91 1 1 30 40 1190 140 110 0.80 2.20 108130 29941 0.00 0.00 0.00 0.00 0.60 2.00 2.00 64.80 90.20 1.2 1510 1023830
+1 78 1 1 106 0 4164 437 173 2.60 5.00 405237 234732 2.00 15.60 58.00 113.80 0.00 18.20 23.40 308.80 233.40 1.2 139 1118814
+1 85 1 1 7 4 2490 262 123 2.00 7.40 95775 26881 2.80 3.00 37.60 72.60 2.00 19.20 20.20 96.00 313.80 8.6 143 1021181
+1 95 1 1 1 1 960 19 39 0.80 2.80 36531 156825 0.00 0.00 0.00 0.00 0.00 1.60 2.60 38.40 64.00 1.6 6927 1853190
+1 97 1 1 4 2 817 52 62 0.40 0.40 8453 46857 3.80 6.00 4.40 0.00 0.20 0.00 0.00 41.40 42.40 2.2 183 1523678
+1 93 1 1 17 23 566 90 54 0.80 0.80 146507 9607 1.60 8.60 21.80 34.40 1.00 3.20 5.80 59.20 90.60 3.2 136 1703814
+1 91 1 1 11 1 2323 192 131 1.00 2.00 317087 135869 0.00 0.00 0.00 0.00 0.00 0.40 0.40 92.20 103.00 2.4 872 1539085
+1 95 1 1 35 46 728 138 84 0.20 0.20 114244 19674 0.00 0.00 0.00 0.00 0.00 1.40 2.80 16.20 25.20 1.3 971 1009992
+1 89 1 1 3 0 5439 284 198 0.60 3.20 184699 57465 0.00 0.00 0.00 0.00 0.20 1.00 1.00 24.00 43.20 3.0 568 1078104
+1 87 1 1 2 0 432 43 19 2.00 2.00 92598 57906 0.00 0.00 0.00 0.00 0.00 2.00 3.60 197.20 164.00 1.2 7854 1867176
+1 92 1 1 1 1 985 127 101 0.80 0.80 9435 22703 3.60 3.60 3.60 0.00 0.60 11.00 11.00 43.00 145.00 3.4 282 971450
+1 88 1 1 1 0 335 40 67 0.20 0.20 15260 148559 15.80 20.60 21.40 2.00 11.80 10.60 14.40 60.80 38.20 2.0 132 1752387
+1 91 1 1 4 2 383 40 30 2.00 3.00 126060 32885 0.00 0.00 0.00 0.00 0.00 1.40 1.80 169.60 151.80 2.4 6126 1851406
+1 97 1 1 1 0 1609 104 45 0.20 0.20 101426 89444 0.00 0.00 0.00 0.00 0.00 0.40 0.40 18.20 18.60 4.2 2020 1559666
+1 94 1 1 2 1 1140 113 116 0.60 0.60 7927 47988 0.00 0.00 0.00 0.00 0.00 0.60 0.60 98.60 78.16 2.0 698 1062855
+1 93 1 1 1 0 2430 90 78 0.20 0.20 4435 17861 1.40 1.40 1.40 0.00 0.00 8.02 8.02 15.63 42.89 1.0 156 1069491
+1 94 1 1 123 58 668 228 199 0.20 0.20 575770 196314 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.80 20.00 2.8 6158 1836848
+1 87 1 1 17 9 2596 188 134 1.00 0.80 464824 158736 3.40 16.00 45.40 113.00 1.20 7.20 11.00 62.00 157.00 1.5 399 1049707
+1 90 1 1 5 1 1442 176 162 3.39 1.00 86640 50523 0.00 0.00 0.00 0.00 0.00 0.00 0.00 163.07 234.33 1.0 7439 1859754
+1 84 1 1 40 50 1809 610 57 2.80 4.40 555730 378487 4.80 6.80 8.60 4.20 1.00 10.60 21.00 166.60 262.60 2.6 229 1757285
+1 91 1 1 1 1 1345 223 192 0.60 0.60 198703 293578 0.60 6.20 23.40 56.40 2.60 3.80 7.40 28.20 56.60 2.6 121 1375446
+1 88 1 1 3 1 418 44 17 2.20 2.20 91498 21389 0.00 0.00 0.00 0.00 0.00 2.40 3.00 215.20 176.40 1.6 8942 1873310
+1 98 1 1 1 1 262 51 18 0.00 0.00 33784 8661 0.00 0.00 0.00 0.00 0.00 0.00 0.00 6.20 7.60 2.0 7393 1865390
+1 79 1 1 105 111 4269 518 454 3.80 2.20 353289 211528 3.60 20.80 38.20 72.00 3.60 7.60 10.60 207.00 398.40 1.6 268 1077443
+1 69 1 1 9 7 4001 282 162 2.20 7.80 227990 194705 0.00 0.00 0.00 0.00 0.00 24.40 45.80 196.40 235.40 5.2 1145 1598792
+1 93 1 1 14 9 2527 81 66 1.00 1.00 157167 36437 0.00 0.00 0.00 0.00 0.00 0.80 1.20 55.00 192.80 3.6 8169 1402438
+1 0 1 1 1 0 2542 138 98 0.20 0.20 8835 17943 0.00 0.00 0.00 0.00 0.00 1.80 2.40 195.00 97.60 618 93 7
+1 85 1 1 15 11 3371 223 174 3.00 4.60 48615 22997 0.80 0.80 0.80 0.00 1.20 13.40 13.60 195.00 244.60 3.2 231 987485
+1 90 1 1 3 2 2557 139 120 1.00 1.60 9275 52926 2.80 3.60 3.40 0.00 0.40 12.20 12.80 76.20 102.00 2.0 264 1129726
+1 83 1 1 2 0 644 155 52 1.60 1.60 724550 37539 4.80 4.80 4.80 0.00 0.00 2.00 3.20 138.40 127.60 1.8 256 1806056
+1 67 1 1 36 7 5442 675 383 5.80 3.80 619161 49966 1.60 4.00 5.40 5.00 0.40 17.80 40.00 255.60 602.60 7.2 573 1292381
+1 84 1 1 4 0 4970 240 125 1.00 1.00 328221 30572 0.00 0.00 0.00 0.00 0.00 1.80 7.00 306.20 238.80 4.4 658 1003938
+1 84 1 1 11 1 2789 298 250 5.60 3.60 182067 44371 0.00 0.00 0.00 0.00 0.20 1.60 1.60 295.60 422.60 2.0 698 1068331
+1 96 1 1 7 6 593 57 47 0.20 0.20 3953 16665 0.00 0.00 0.00 0.00 0.00 3.61 3.81 15.83 38.88 2.4 886 978309
+1 82 1 1 5 0 4269 839 508 1.00 1.40 42874 168151 0.00 0.00 0.00 0.00 0.00 9.40 11.60 73.40 149.40 1.5 1456 1087378
+1 93 1 1 1 1 2113 116 69 0.40 1.00 68850 25188 0.00 0.00 0.00 0.00 0.80 1.20 1.40 31.40 88.80 2.8 438 1027216
+1 92 1 1 1 0 1620 157 128 0.80 2.40 97142 30551 2.20 21.40 65.60 128.80 0.00 2.40 3.20 78.00 169.40 1.0 184 1054022
+1 91 1 1 4 1 3423 104 94 1.40 1.80 57427 32880 1.40 1.60 1.60 0.00 0.40 0.20 0.20 82.63 153.29 2.2 261 1527663
+1 88 1 1 72 91 1273 81 52 1.60 1.80 145574 47053 0.00 0.00 0.00 0.00 5.80 12.80 36.00 165.40 237.20 3.0 578 1063845
+1 75 1 1 12 5 3351 162 122 6.21 17.84 59099 39632 0.00 0.00 0.00 0.00 0.00 16.63 17.43 230.86 428.26 1.5 527 1105538
+1 97 1 1 24 33 371 27 55 0.20 0.20 791 27404 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.37 16.77 1.2 5924 1860192
+1 98 1 1 0 0 169 15 24 0.20 0.20 429 5621 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 5270 1856587
+1 92 1 1 2 0 2091 74 162 0.20 0.20 37888 206184 3.00 3.40 5.80 4.40 0.20 1.00 1.20 15.40 24.20 2.2 136 1710504
+1 80 1 1 14 0 7368 253 196 2.20 2.00 175340 50896 3.99 4.79 4.59 0.00 0.40 13.77 20.36 144.31 244.51 2.8 268 1066098
+1 0 1 1 17 2 1109 117 99 2.00 2.60 104225 45581 0.40 0.80 0.80 0.00 0.40 0.00 0.00 111.00 239.20 546 90 10
+1 84 1 1 11 8 2471 347 267 2.80 1.00 501057 83661 0.40 0.40 0.40 0.00 6.40 1.40 4.00 143.00 227.80 1.0 179 984490
+1 84 1 1 3 2 4566 555 420 0.40 2.60 684504 479811 17.00 21.20 21.20 0.00 19.40 12.80 14.20 18.40 98.40 2.2 264 1043224
+1 92 1 1 47 67 1061 122 80 0.40 0.60 138370 33738 0.60 0.80 0.80 0.00 1.00 1.40 1.80 39.92 109.18 3.0 550 1009661
+1 79 1 1 63 63 2254 283 232 7.40 3.60 141409 30567 13.60 35.40 88.00 230.00 0.80 0.80 0.80 305.20 539.80 1.8 184 966634
+1 77 1 1 59 65 4327 296 227 3.99 7.58 163390 88519 14.97 42.71 78.44 266.27 0.60 18.56 22.95 246.31 382.24 1.3 171 1060752
+1 83 1 1 0 0 3705 218 177 0.20 0.20 205718 173263 3.59 26.15 68.86 110.38 0.00 15.77 30.74 15.77 17.96 2.4 131 1755281
+1 94 1 1 1 0 1482 117 83 0.20 0.20 57224 63869 2.81 6.61 6.61 0.00 0.00 3.41 5.61 19.04 34.87 1.5 219 981977
+1 95 1 1 2 1 2161 208 121 0.00 0.00 8981 30912 1.60 1.80 1.80 0.00 0.00 0.20 0.20 7.20 19.00 2.2 287 1537754
+1 97 1 1 1 0 839 65 23 0.20 0.20 355321 11361 0.00 0.00 0.00 0.00 0.00 0.00 0.00 23.20 18.40 1.6 4575 1827339
+1 79 1 1 55 76 4119 285 206 1.60 2.80 126303 102504 6.40 8.60 8.60 0.00 1.20 18.20 22.20 85.40 194.20 1.0 283 982560
+1 83 1 1 4 1 2474 336 296 3.60 1.00 456198 349894 0.00 0.00 0.00 0.00 0.00 26.00 51.40 170.40 244.00 1.2 5872 1841914
+1 63 1 1 15 2 6214 509 460 9.40 5.60 340370 267867 14.80 18.60 16.60 0.00 10.40 5.80 7.00 421.60 674.20 4.2 315 1511987
+1 88 1 1 2 0 2991 196 151 0.60 2.60 279677 33378 0.00 0.00 0.00 0.00 0.00 3.20 4.20 34.40 73.00 2.0 779 1108133
+1 99 1 1 0 0 164 8 28 0.20 0.20 2061 29064 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 1.0 7351 1874424
+1 94 1 1 2 0 1685 152 79 0.20 0.20 27226 24932 1.80 5.39 8.98 14.77 0.00 3.99 6.19 15.57 35.93 3.0 134 1012024
+1 93 1 1 1 0 1331 159 75 0.20 0.20 543957 21499 0.00 0.00 0.00 0.00 0.00 1.20 1.20 23.80 28.60 2.3 765 1119675
+1 69 1 1 55 47 4025 596 497 9.40 6.60 657013 284435 2.80 7.60 15.40 47.40 3.20 2.00 2.20 425.40 823.20 2.0 279 1008312
+1 84 1 1 3 1 881 148 112 1.20 1.40 315287 207336 16.77 28.74 42.12 36.73 5.19 27.15 50.30 85.03 122.95 3.2 317 1714683
+1 94 1 1 5 0 2628 152 133 1.60 1.40 208287 177679 0.00 0.00 0.00 0.00 0.00 0.60 1.00 95.41 112.77 2.6 2657 1648291
+1 98 1 1 0 0 160 8 28 0.20 0.20 1014 28847 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7571 1877232
+1 94 1 1 2 1 2266 103 83 0.40 1.80 5874 11341 1.40 1.40 1.40 0.00 0.80 0.40 0.40 21.20 30.20 2.4 217 1711016
+1 93 1 1 3 2 1346 76 63 0.80 1.00 87027 23039 0.00 0.00 0.00 0.00 0.20 47.00 47.00 46.80 161.40 3.0 1681 1008840
+1 98 1 1 2 1 254 11 22 0.20 0.20 10004 67114 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.63 17.23 1.0 7493 1869185
+1 91 1 1 1 0 5490 278 203 0.40 2.00 24054 18264 0.00 0.00 0.00 0.00 0.00 8.80 9.00 34.60 92.60 2.6 411 1447018
+1 93 1 1 2 1 852 72 45 1.20 1.20 59243 101504 0.00 0.00 0.00 0.00 0.00 2.20 4.21 94.39 98.20 1.0 6750 1857629
+1 58 1 1 26 1 3173 357 226 7.40 9.80 231176 71434 38.00 90.00 190.40 587.00 4.40 72.80 99.00 329.00 745.00 1.4 145 996291
+1 94 1 1 27 43 960 88 96 0.40 0.40 7834 15414 0.00 0.00 0.00 0.00 0.00 0.40 0.60 29.34 45.51 1.0 2113 1070729
+1 95 1 1 0 0 1418 66 65 0.20 0.20 9536 22884 0.40 0.60 0.60 0.00 0.00 2.00 2.40 13.40 28.40 2.2 181 1085774
+1 89 1 1 5 0 2047 288 233 0.40 0.80 39532 31482 1.00 10.80 57.00 96.60 0.00 7.20 15.60 24.60 140.20 2.4 300 1692720
+1 95 1 1 14 18 1659 78 68 0.20 0.20 43191 31299 5.40 6.80 6.80 0.00 2.00 2.80 5.60 15.40 16.80 1.4 278 1750906
+1 74 1 1 10 0 4690 495 465 7.40 2.60 249492 58996 5.40 10.40 7.60 0.00 0.40 0.00 0.00 359.60 520.40 4.2 3782 1720078
+1 76 1 1 7 3 7070 346 226 2.60 5.60 429107 40146 0.00 0.00 0.00 0.00 0.00 26.60 30.20 195.40 341.60 5.8 2650 1436826
+1 94 1 1 4 3 2000 107 68 0.60 2.00 23644 17392 1.60 1.60 1.60 0.00 0.80 1.20 1.60 29.00 49.60 1.5 205 1015739
+1 84 1 1 1 0 3678 234 144 0.80 0.80 306668 200609 17.00 26.40 20.60 0.00 2.00 6.00 6.80 113.20 98.60 1.0 250 1117645
+1 90 1 1 0 0 1724 206 157 0.40 0.60 134961 336338 0.00 0.00 0.00 0.00 0.00 0.20 0.20 32.20 40.00 5.6 1883 1601197
+1 89 1 1 14 9 2005 170 93 1.00 3.60 360383 11977 5.20 5.20 5.20 0.00 3.80 26.20 49.00 110.20 123.40 4.4 274 1319438
+1 81 1 1 34 45 4051 198 165 2.20 8.58 300514 250049 0.00 0.00 0.00 0.00 0.00 3.39 4.59 168.86 209.18 5.0 957 1604386
+1 89 1 1 1 1 2033 553 142 0.20 0.60 327246 254291 29.40 58.20 58.20 0.00 0.80 1.20 1.80 40.60 64.00 2.4 267 1382013
+1 82 1 1 83 116 2984 145 132 1.20 1.00 172801 120045 0.00 0.00 0.00 0.00 0.20 19.64 37.07 72.55 206.61 1.4 516 1021016
+1 90 1 1 10 2 2826 197 236 0.60 0.60 57037 166871 2.60 2.80 2.80 0.00 1.00 5.20 5.20 51.00 201.60 1.0 302 1000642
+1 83 1 1 21 3 4275 370 163 2.59 2.20 869526 17545 0.00 0.00 0.00 0.00 1.80 6.19 8.18 158.68 285.03 4.4 956 1462379
+1 81 1 1 16 9 2043 336 145 5.79 3.99 49693 26578 0.00 0.00 0.00 0.00 0.00 2.99 4.19 232.53 523.55 1.0 649 1004255
+1 79 1 1 112 121 2279 267 145 3.39 2.99 576694 513275 0.00 0.00 0.00 0.00 0.00 50.50 61.48 219.16 394.21 2.0 2023 1034794
+1 84 1 1 4 1 1148 170 88 2.40 2.79 829628 35348 5.99 6.19 10.38 14.37 0.60 2.00 2.20 183.63 189.02 3.0 147 1801689
+1 90 1 1 3 0 2443 366 128 1.80 0.60 255296 213845 0.00 0.00 0.00 0.00 0.00 0.00 0.00 92.40 131.60 3.4 666 1742014
+1 80 1 1 40 50 2610 233 75 2.80 2.60 544046 24440 0.00 0.00 0.00 0.00 0.00 27.00 32.60 217.00 292.40 2.4 1310 1752834
+1 98 1 1 0 0 172 17 20 0.20 0.20 446 4412 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.0 7388 1861860
+1 80 1 1 87 106 5490 491 299 1.40 1.20 101447 90854 1.00 1.60 1.40 0.00 0.20 0.80 1.20 89.40 129.40 5.4 537 1335731
+1 91 1 1 3 2 4698 215 167 0.40 0.40 43638 36529 0.00 0.00 0.00 0.00 0.00 2.80 2.80 31.80 61.60 2.4 498 1447382
+1 71 1 1 57 76 2674 346 273 5.39 4.19 390009 21069 0.00 0.00 0.00 0.00 0.00 8.78 9.58 279.24 485.03 2.8 3119 1759583
+1 96 1 1 5 4 1030 170 115 0.20 0.20 120128 128776 0.00 0.00 0.00 0.00 0.00 1.00 1.00 21.00 18.40 4.0 1754 1557714
+1 84 1 1 36 42 1327 179 180 3.20 1.00 87113 29424 0.00 0.00 0.00 0.00 0.00 0.00 0.00 163.00 230.40 2.2 3673 1773795
+1 96 1 1 1 0 1691 35 58 0.40 2.00 10331 6008 0.00 0.00 0.00 0.00 0.00 0.40 0.40 35.40 45.00 2.0 976 1402544
+1 73 1 1 72 79 3435 381 410 2.40 2.59 389074 487297 27.74 49.30 83.03 102.59 4.39 22.36 26.95 146.91 346.71 1.0 199 996364
+1 97 1 1 0 0 1203 69 58 0.20 0.20 12567 47830 0.60 0.60 0.60 0.00 0.00 1.20 1.20 15.60 18.00 2.0 151 1718886
+1 82 1 1 2 0 1850 259 163 1.80 0.60 89563 43126 0.00 0.00 0.00 0.00 0.00 0.60 0.60 93.40 130.20 2.0 1697 1767690
+1 0 1 1 9 0 1356 176 89 1.20 1.40 642889 434490 0.00 0.00 0.00 0.00 1.20 9.80 18.60 129.20 203.00 406 88 12
+1 90 1 1 12 2 621 98 44 0.40 0.40 399046 11578 1.40 5.00 12.80 26.40 0.40 1.00 1.00 35.40 48.20 3.2 273 1736120
+1 73 1 1 10 3 5252 392 248 5.20 4.80 163743 100347 0.00 0.00 0.00 0.00 0.20 22.40 24.40 283.60 667.20 1.0 856 990546
+1 96 1 1 23 33 203 26 21 0.20 0.20 15807 16332 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 18.00 1.0 2642 1771504
+1 81 1 1 20 6 6709 335 318 2.39 1.00 85428 34037 0.00 0.00 0.00 0.00 0.00 7.77 8.37 143.82 201.99 2.6 2005 963321
+1 97 1 1 13 19 200 14 15 0.20 0.20 7018 4955 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7240 1863624
+1 83 1 1 47 65 3012 269 110 1.60 3.60 913173 28574 7.80 15.60 28.20 86.40 0.40 10.20 10.60 117.80 207.60 1.0 151 1088790
+1 82 1 1 183 196 6390 405 204 2.40 2.40 953894 78904 0.00 0.00 0.00 0.00 0.00 0.40 0.40 108.40 139.80 4.2 1375 1542507
+1 92 1 1 3 0 830 113 99 2.00 1.00 167001 95606 0.00 0.00 0.00 0.00 1.40 0.00 0.00 120.20 159.40 2.6 743 1715010
+1 84 1 1 9 0 2561 298 88 2.81 4.41 191532 22154 3.41 18.04 76.55 128.06 0.80 36.27 41.88 247.50 441.28 1.6 116 1108486
+1 82 1 1 9 3 2043 165 635 3.20 4.80 49093 177175 0.00 0.00 0.00 0.00 0.00 3.40 3.40 125.40 215.40 2.6 1350 1713138
+1 85 1 1 3 0 339 40 57 0.60 0.80 26052 80777 0.00 0.00 0.00 0.00 0.20 18.20 23.00 49.00 92.60 1.4 462 1755136
+1 85 1 1 12 10 998 40 48 1.40 3.60 91235 37368 0.20 0.40 0.40 0.00 0.40 6.80 12.80 155.60 342.00 1.5 491 1065987
+1 0 1 1 99 46 5467 904 164 3.39 4.39 2204636 77915 3.39 11.38 18.56 41.92 12.57 4.79 6.99 272.26 420.76 452 77 23
+1 75 1 1 28 0 4247 653 620 4.20 1.20 535995 317269 9.00 25.60 67.40 178.20 0.80 11.40 27.40 207.20 422.20 4.4 141 1072970
+1 90 1 1 9 5 1306 133 107 1.60 1.40 113429 40956 0.20 0.20 0.20 0.00 0.40 4.20 7.20 93.40 143.00 1.0 386 1058034
+1 98 1 1 0 0 319 69 35 0.20 0.20 436770 15308 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 18.60 1.4 6025 1855512
+1 88 1 1 15 13 1669 161 81 0.80 1.80 82168 24313 0.00 0.00 0.00 0.00 0.40 44.91 45.31 76.65 158.08 1.7 1149 1083920
+1 95 1 1 3 2 840 59 38 0.20 0.20 3682 14522 2.59 2.79 2.79 0.00 0.40 20.76 20.76 15.37 91.82 1.0 158 1011914
+1 80 1 1 22 1 3850 262 159 4.38 2.99 332663 56147 1.00 1.20 1.20 0.00 1.00 6.57 8.96 254.78 390.24 4.0 292 1614306
+1 92 1 1 4 2 956 183 66 1.20 1.00 333045 23677 5.60 6.00 5.80 0.00 3.20 1.40 1.80 69.60 112.80 1.4 190 1726691
+1 98 1 1 2 1 159 8 13 0.20 0.20 6994 10941 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 7260 1875328
+1 95 1 1 25 35 926 82 48 0.20 0.20 424352 236380 0.00 0.00 0.00 0.00 0.00 1.40 2.60 15.60 17.60 2.4 1016 1758643
+1 77 1 1 17 3 4065 443 301 4.19 2.59 203488 80888 1.40 1.80 1.60 0.00 0.20 6.99 11.58 245.31 393.41 5.8 470 1522307
+1 94 1 1 8 7 1608 79 67 0.20 0.20 16265 17578 0.00 0.00 0.00 0.00 0.00 2.40 2.40 38.00 87.60 3.0 691 978082
+1 85 1 1 20 1 2916 215 169 4.40 6.60 145022 130332 0.00 0.00 0.00 0.00 0.00 5.80 5.80 288.40 365.00 2.8 442 1534784
+1 91 1 1 0 0 5186 141 183 0.40 0.60 60757 187028 2.60 5.80 5.00 0.00 4.80 13.00 17.00 34.20 100.20 2.5 353 1013157
+1 91 1 1 4 0 2281 154 114 0.80 1.00 97786 25104 1.00 2.40 10.80 16.80 0.40 1.20 1.40 52.60 73.20 1.0 181 1111448
+1 77 1 1 11 0 4295 528 423 4.00 1.40 218071 107357 1.40 1.60 1.60 0.00 0.80 14.40 14.60 217.00 353.60 2.0 186 1088074
+1 79 1 1 15 12 7635 711 209 3.00 6.20 865872 61238 0.00 0.00 0.00 0.00 0.00 13.80 13.80 139.40 238.80 1.4 497 1012398
+1 89 1 1 7 6 1426 146 134 0.60 0.40 14599 33493 4.20 5.40 4.40 0.00 2.60 25.00 25.60 267.00 111.00 1.7 178 1098067
+1 77 1 1 15 9 3412 498 247 1.80 1.20 438647 144470 1.80 17.20 59.80 93.00 0.00 62.80 82.80 99.00 322.20 5.2 452 1298973
+1 86 1 1 80 89 2360 231 184 2.60 1.60 234714 46287 0.00 0.00 0.00 0.00 0.20 17.60 18.80 165.20 316.60 4.6 7774 1365789
+1 77 1 1 14 3 1883 81 83 7.40 19.60 22186 20651 1.40 1.40 1.40 0.00 0.80 11.20 11.60 302.60 517.80 1.0 277 1104808
+1 86 1 1 4 2 2896 373 301 1.20 2.00 138977 35508 0.00 0.00 0.00 0.00 0.40 17.80 17.80 63.40 115.00 3.0 1255 1719930
+1 90 1 1 11 11 3893 363 99 0.20 0.20 111535 50786 4.80 8.20 10.60 17.80 0.80 3.40 4.40 16.00 33.40 3.0 130 997800
+1 67 1 1 74 67 3416 523 148 5.19 5.39 302580 28790 7.58 32.14 153.49 309.38 11.58 30.74 50.70 341.52 773.45 1.0 85 1026534
+1 74 1 1 7 0 2300 170 164 6.60 19.40 59500 88247 2.40 10.40 14.20 20.40 0.00 9.80 13.60 224.60 411.60 7.0 141 1103325
+1 81 1 1 0 0 2363 127 81 0.20 0.20 638295 107566 4.19 36.13 142.51 238.32 0.40 69.46 138.72 15.37 16.97 2.0 130 1757261
+1 93 1 1 0 0 1311 99 72 0.20 0.20 7261 23751 1.00 1.00 1.00 0.00 0.20 1.20 1.20 37.20 23.80 2.2 323 1118797
+1 86 1 1 8 4 2359 160 112 1.20 2.81 166388 43275 7.21 14.63 22.24 33.87 1.40 3.01 4.61 81.16 206.01 1.0 249 1125539
+1 90 1 1 1 0 2138 162 90 1.00 1.00 133853 48999 2.80 3.40 9.40 9.60 0.60 4.40 6.20 82.80 109.00 4.5 139 1127086
+1 87 1 1 2 0 446 41 35 2.00 2.00 67589 37736 0.00 0.00 0.00 0.00 0.00 2.60 3.00 173.00 150.60 2.2 479 1785278
+1 74 1 1 12 8 4600 231 189 2.80 8.00 264988 252353 4.60 5.40 5.20 0.00 4.80 0.40 0.40 233.40 313.80 4.6 326 1524637
+1 71 1 1 680 9 4355 186 171 0.20 0.20 88093 181024 0.00 0.00 0.00 0.00 0.00 61.12 63.33 21.64 78.16 2.2 572 1064629
+1 92 1 1 2 1 1162 128 142 0.20 0.20 100251 105326 5.00 5.80 5.40 0.00 1.20 1.80 2.60 20.60 23.40 2.0 198 1708232
+1 90 1 1 12 11 2712 138 88 1.00 1.40 28926 33076 0.00 0.00 0.00 0.00 0.00 1.20 1.20 59.40 130.80 2.5 2373 1013866
+1 80 1 1 4 0 3883 424 224 0.80 1.00 706506 603887 25.20 46.00 83.20 165.00 12.60 24.20 35.40 52.80 159.60 3.8 143 1030888
+1 92 1 1 1 1 2540 163 108 0.40 0.40 186048 22114 0.00 0.00 0.00 0.00 0.20 6.20 8.40 32.40 104.60 2.2 1864 1415659
+1 90 1 1 3 1 722 57 68 0.60 0.60 43279 20088 5.20 10.00 9.80 0.00 2.20 12.80 24.20 81.60 116.00 1.0 434 1062194
+1 78 1 1 9 2 4394 471 342 4.00 1.00 210471 64941 6.40 10.20 19.60 24.40 0.80 23.40 40.20 199.20 392.20 1.2 133 1099586
+1 95 1 1 27 26 2339 118 119 0.20 0.20 36205 118269 0.00 0.00 0.00 0.00 0.00 0.00 0.00 26.60 18.20 2.4 843 1644499
+1 96 1 1 1 0 1838 54 56 0.20 0.20 25869 45796 0.00 0.00 0.00 0.00 0.00 0.40 0.80 16.00 17.60 2.0 4691 1731144
+1 85 1 1 49 11 2854 176 138 3.40 2.80 188673 82705 9.40 20.00 18.20 0.00 0.80 2.40 2.40 188.00 334.40 1.3 225 978666
+1 65 1 1 117 118 8353 263 175 2.80 8.40 223582 115554 0.00 0.00 0.00 0.00 0.00 7.20 18.00 235.20 270.40 4.6 2065 1327851
+1 77 1 1 51 71 4254 276 244 0.60 1.00 358561 356424 1.40 1.80 1.80 0.00 0.00 6.41 6.61 50.70 395.19 1.0 317 1006596
+1 90 1 1 3 2 2763 137 118 0.80 2.20 82822 65914 3.99 10.18 18.56 52.30 1.40 3.79 3.99 56.69 106.39 1.3 158 1120913
+1 91 1 1 6 0 2755 168 152 0.20 0.20 301436 22497 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 34.33 2.6 1811 1695318
+1 84 1 1 9 7 3519 224 102 2.00 8.60 121234 102854 0.00 0.00 0.00 0.00 0.00 2.80 4.60 171.40 178.00 6.2 4024 1606019
+1 94 1 1 31 43 1918 113 66 0.20 0.20 3987 11048 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 18.00 2.2 5297 1724966
+1 90 1 1 9 6 3368 138 101 0.60 2.20 105369 88612 0.00 0.00 0.00 0.00 0.40 4.00 4.80 58.60 167.40 5.6 1397 1327512
+1 68 1 1 23 1 6362 527 468 6.57 6.18 386297 115456 0.00 0.00 0.00 0.00 0.00 12.55 17.13 393.23 653.98 5.6 3542 1336048
+1 0 1 1 4 2 1153 76 157 0.40 1.80 147498 40987 0.00 0.00 0.00 0.00 7.20 2.60 4.80 194.60 69.80 579 92 8
+1 97 1 1 4 3 272 27 28 0.40 0.40 35210 11609 0.00 0.00 0.00 0.00 0.00 3.00 4.60 34.40 39.60 1.0 7283 1863856
+1 79 1 1 22 2 3538 415 392 7.20 2.00 239000 55448 0.00 0.00 0.00 0.00 0.00 0.40 0.40 362.00 532.20 4.0 2003 1530184
+1 92 1 1 2 0 1646 85 55 0.80 0.80 247300 21669 0.00 0.00 0.00 0.00 0.00 0.60 0.60 55.60 94.60 1.6 494 1754752
+1 95 1 1 1 0 1419 143 58 0.20 0.20 294580 5987 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 2.6 6227 1731128
+1 92 1 1 13 11 991 120 151 1.40 1.60 46652 39307 0.00 0.00 0.00 0.00 0.00 1.60 4.40 133.60 155.60 1.0 359 1012294
+1 91 1 1 6 2 1393 122 112 0.40 0.40 178327 40704 0.00 0.00 0.00 0.00 0.00 5.20 5.60 38.40 78.80 5.8 441 1054702
+1 96 1 1 1 0 371 53 85 0.20 0.20 8026 81321 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.80 18.60 2.2 6601 1706384
+1 88 1 1 10 5 2358 209 174 2.80 1.60 74757 36749 0.00 0.00 0.00 0.00 0.00 2.40 2.60 138.80 224.60 2.5 498 1053219
+1 98 1 1 1 1 195 15 22 0.20 0.20 10279 9542 0.00 0.00 0.00 0.00 0.00 0.60 1.20 15.60 16.80 1.0 7738 1882360
+1 79 1 1 6 3 5178 257 313 0.60 2.00 171929 653829 4.60 4.80 4.80 0.60 7.40 16.60 19.40 48.40 235.40 2.0 203 1005581
+1 84 1 1 11 4 1917 199 116 1.80 3.20 219990 38219 10.00 22.40 74.40 120.20 2.60 17.40 42.20 192.00 274.20 2.0 159 1112970
+1 93 1 1 3 1 2669 147 111 0.40 0.40 416802 208804 3.00 3.20 3.20 0.00 10.20 2.00 2.40 42.60 53.60 3.0 178 1518803
+1 82 1 1 27 32 2899 249 194 3.19 2.40 72150 117011 6.39 12.77 9.18 0.00 0.20 16.77 19.56 166.07 314.17 2.0 361 1059804
+1 94 1 1 1 0 2638 148 126 0.20 0.20 292436 17005 0.00 0.00 0.00 0.00 0.00 0.00 0.00 22.60 18.00 2.0 2493 1700475
+1 59 1 1 57 1 3518 301 132 10.60 29.00 588337 75972 8.20 37.60 100.00 152.60 0.80 59.20 95.80 412.20 825.40 2.6 172 1094818
+1 96 1 1 3 2 922 101 65 0.80 3.79 4190 16327 2.20 2.20 2.20 0.00 0.80 1.40 1.40 51.10 128.14 1.3 211 1022715
+1 91 1 1 3 0 1105 190 113 0.80 0.80 22845 123327 16.77 30.54 46.31 114.37 11.38 7.98 13.17 70.06 96.01 1.6 129 1725212
+1 94 1 1 46 66 621 76 61 0.60 0.80 4980 16132 0.00 0.00 0.00 0.00 0.00 0.20 0.20 44.20 53.80 1.0 1888 1075016
+1 97 1 1 26 37 1360 69 55 0.20 0.20 10060 16581 0.00 0.00 0.00 0.00 0.00 0.20 0.20 12.77 16.97 1.4 8953 1869190
+1 71 1 1 54 66 2449 84 67 6.00 18.00 54266 34429 10.40 35.60 137.20 263.20 0.60 67.20 130.40 249.80 545.00 1.0 114 1061226
+1 0 1 1 47 41 1241 123 81 1.80 2.80 224930 43021 4.20 5.80 5.80 0.00 5.40 10.20 13.40 137.20 239.20 364 88 12
+1 90 1 1 20 17 4119 280 171 0.60 0.60 401636 245747 0.00 0.00 0.00 0.00 0.00 3.00 5.00 119.00 55.20 4.0 1686 1325539
+1 82 1 1 5 0 2103 117 122 5.00 14.60 69029 57987 0.80 8.20 35.40 59.00 0.40 8.80 13.60 164.80 342.60 3.0 129 1076949
+1 87 1 1 10 3 3028 283 175 1.40 1.20 374314 66447 0.00 0.00 0.00 0.00 0.40 35.00 35.60 104.40 236.20 3.6 3045 1419264
+1 91 1 1 1 1 349 82 47 0.20 0.20 274730 267022 0.00 0.00 0.00 0.00 0.00 3.20 6.40 18.00 17.00 2.2 3479 1822152
+1 92 1 1 39 54 1682 129 97 0.20 0.20 48078 29929 0.00 0.00 0.00 0.00 0.00 2.80 4.00 15.60 50.60 2.4 1017 1071213
+1 92 1 1 13 5 1129 167 99 0.40 0.60 282508 18904 12.57 23.95 69.66 153.29 0.40 3.79 23.75 39.92 165.07 2.4 256 967705
+1 72 1 1 11 0 2113 134 90 5.80 14.60 1040960 40672 3.60 48.00 141.20 429.60 0.00 16.40 21.20 245.20 704.20 2.4 395 1084862
+1 80 1 1 69 90 3175 109 128 1.00 1.60 66150 121835 0.00 0.00 0.00 0.00 0.00 7.40 9.40 59.60 88.80 3.8 735 1519203
+1 88 1 1 28 26 4492 312 135 1.80 2.20 231071 29774 0.00 0.00 0.00 0.00 0.40 5.00 9.40 138.20 216.80 2.8 441 1379102
+1 79 1 1 8 2 4496 237 166 1.60 3.59 104263 34799 0.00 0.00 0.00 0.00 0.00 1.00 1.00 141.92 218.36 7.2 1107 1304056
+1 89 1 1 31 41 2270 124 152 0.80 0.80 66758 45937 2.60 4.40 3.20 0.00 1.00 7.60 13.80 43.80 98.00 3.8 348 1703654
+1 92 1 1 6 2 1267 154 62 2.40 3.00 309013 206077 0.00 0.00 0.00 0.00 0.00 0.60 0.60 133.00 188.60 2.8 6770 1835762
+1 75 1 1 23 17 3065 233 105 4.40 13.40 453418 47662 0.00 0.00 0.00 0.00 0.00 4.40 7.80 289.40 566.60 3.6 425 1018480
+1 95 1 1 5 2 2468 99 97 0.40 0.40 152648 32618 0.00 0.00 0.00 0.00 0.00 2.80 3.20 32.40 50.60 3.2 3414 1551606
+1 82 1 1 31 3 2629 202 145 1.20 1.20 288215 79023 0.00 0.00 0.00 0.00 0.00 74.40 74.80 103.20 283.00 1.0 1700 1069051
+1 78 1 1 15 9 5018 328 150 3.18 3.38 203089 47521 0.00 0.00 0.00 0.00 0.20 14.51 19.09 279.32 426.44 3.2 579 1006093
+1 84 1 1 8 2 1388 190 158 1.00 0.80 1087958 385189 7.60 42.20 108.80 244.20 1.40 85.60 152.80 76.00 152.40 1.0 136 1059101
+1 97 1 1 2 1 287 23 24 0.60 1.60 9982 62656 0.00 0.00 0.00 0.00 0.00 0.00 0.00 42.91 37.13 1.4 7022 1850919
+1 84 1 1 5 0 2232 198 92 3.80 4.80 278965 45357 4.00 6.60 6.00 0.00 2.00 12.00 13.00 234.40 405.00 1.0 255 1031590
+1 91 1 1 49 11 2424 233 152 0.20 0.20 214926 81346 0.00 0.00 0.00 0.00 0.40 5.00 7.60 22.60 59.20 1.0 507 981270
+1 83 1 1 2 0 2191 158 132 1.80 0.60 76488 54752 6.40 8.20 8.00 0.00 0.80 1.80 3.00 94.20 131.40 2.2 269 1740456
+1 87 1 1 3 0 4115 247 134 1.20 4.00 199866 106274 0.00 0.00 0.00 0.00 0.00 2.60 3.60 68.40 113.80 2.6 3433 1428013
+1 93 1 1 3 3 1236 248 144 0.40 0.40 150286 148238 0.00 0.00 0.00 0.00 0.00 0.20 0.20 29.60 45.20 3.0 1937 1577413
+1 86 1 1 55 76 1846 251 198 0.60 0.60 382579 56300 4.80 28.80 62.60 125.20 6.40 6.00 10.00 72.60 175.40 1.0 128 1046594
+1 78 1 1 12 5 3192 363 257 5.60 4.40 145662 40099 0.80 0.80 0.80 0.00 1.20 1.40 1.40 245.20 449.60 2.0 322 1025882
+1 86 1 1 46 64 2447 285 150 0.80 1.20 103376 86067 7.41 17.23 36.47 51.90 5.61 13.83 21.64 68.54 129.46 2.3 139 1101517
+1 60 1 1 21 4 5077 748 763 10.80 7.40 387795 50254 0.00 0.00 0.00 0.00 0.00 2.40 3.20 601.80 847.60 3.0 2541 1734995
+1 66 1 1 27 11 3540 490 233 6.21 10.02 256042 29123 0.60 0.60 0.60 0.00 3.21 22.04 48.70 377.15 737.07 1.0 564 1103211
+1 93 1 1 3 1 538 23 53 1.80 3.60 42074 158460 0.20 2.20 0.40 0.00 0.40 0.40 0.60 90.00 128.20 1.2 6854 1853379
+1 83 1 1 10 2 2726 202 178 1.80 5.20 71533 397123 2.80 14.80 70.60 110.40 1.60 51.00 51.40 170.80 268.20 5.8 136 1313141
+1 89 1 1 34 44 2335 167 135 1.78 0.59 125037 31276 0.00 0.00 0.00 0.00 4.36 3.37 3.56 101.78 185.74 2.6 587 1012445
+1 64 1 1 35 3 3940 450 375 8.62 20.04 344858 244721 6.21 11.42 7.82 0.00 1.20 12.42 15.43 362.12 664.33 5.2 356 1098964
+1 83 1 1 11 0 6430 361 267 1.80 3.39 262309 187326 12.57 46.71 94.01 154.49 3.39 61.88 72.06 135.93 282.83 2.2 133 989712
+1 81 1 1 32 28 1946 176 112 1.60 1.60 366407 150365 17.20 36.60 43.40 32.60 1.40 9.60 12.80 136.00 202.40 1.0 205 1081718
+1 75 1 1 10 7 6625 358 177 2.20 8.80 109062 43673 0.00 0.00 0.00 0.00 0.00 5.80 6.60 214.60 248.20 3.4 2660 1414230
+1 85 1 1 225 221 4964 428 283 0.60 0.60 254814 233832 0.00 0.00 2.40 4.40 0.20 4.00 20.80 44.80 98.20 4.6 1009 1335726
+1 75 1 1 22 14 3398 232 144 5.39 7.39 165777 46649 6.99 9.58 24.55 36.33 5.79 11.38 13.37 298.80 494.81 1.8 181 1015425
+1 73 1 1 31 18 5959 381 184 3.40 9.40 167379 30436 0.00 0.00 0.00 0.00 0.20 2.60 2.80 218.60 388.60 5.0 8046 1373474
+1 92 1 1 1 1 1537 129 53 0.40 1.80 70679 42282 0.00 0.00 0.00 0.00 0.00 5.20 9.40 21.40 33.20 2.0 1727 1074430
+1 88 1 1 2 1 638 74 49 1.80 2.00 8441 8438 0.00 0.00 0.00 0.00 0.00 1.20 1.20 80.80 126.40 1.8 711 1759778
+1 97 1 1 22 29 1873 60 59 0.20 0.20 4773 52693 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.20 17.60 2.0 2046 1642926
+1 86 1 1 16 14 5702 310 174 1.00 0.60 62510 36316 0.00 0.00 0.00 0.00 0.00 1.20 1.20 73.60 96.20 1.7 1192 1014768
+1 67 1 1 34 20 4479 501 189 11.00 12.00 140854 37224 0.20 0.20 0.20 0.00 0.20 0.60 3.20 527.40 976.00 1.0 514 1073038
+1 77 1 1 19 13 2241 177 100 6.21 20.64 168805 30757 4.21 13.83 25.45 34.47 1.00 17.64 29.06 208.62 405.01 2.0 137 1110113
+1 96 1 1 6 4 765 72 38 0.20 0.20 149433 24390 0.00 0.00 0.00 0.00 6.00 4.80 5.00 23.60 101.40 1.4 607 965299
+1 75 1 1 207 202 4832 194 113 6.40 18.60 214574 104466 0.60 0.60 2.80 3.60 1.60 12.20 13.40 224.80 433.60 5.2 212 1107437
+1 86 1 1 15 12 2882 358 253 0.80 0.80 372240 271212 0.00 0.00 0.00 0.00 0.60 16.77 25.35 68.26 107.58 4.2 610 1334266
+1 92 1 1 1 0 2811 114 67 0.40 0.20 179340 21446 0.00 0.00 0.00 0.00 0.00 0.40 0.60 32.60 44.80 1.5 1026 1078163
+1 90 1 1 1 0 2046 142 111 0.40 0.40 74395 45172 5.39 9.78 11.58 8.18 2.00 1.40 1.40 35.93 108.58 1.5 337 1010007
+1 90 1 1 1 0 1310 187 173 0.20 0.20 58730 45906 2.60 5.00 5.00 0.00 0.00 1.40 1.60 16.00 47.80 1.7 302 1004142
+1 90 1 1 4 2 389 38 15 2.00 2.00 80836 17496 0.00 0.00 0.00 0.00 0.00 2.20 3.79 182.04 165.87 1.2 11542 1879136
+1 87 1 1 25 16 1998 224 158 1.60 5.00 97530 126579 5.20 30.40 67.20 124.80 0.80 5.60 10.40 130.00 261.60 1.5 149 1065418
+1 81 1 1 19 11 1667 116 87 3.01 6.61 88806 48340 1.20 1.60 1.60 0.00 0.00 12.83 24.05 239.88 485.17 2.5 412 1045656
+1 88 1 1 16 23 5071 148 139 0.80 0.40 21392 36057 0.00 0.00 0.00 0.00 0.00 0.00 0.00 47.50 64.27 1.2 582 1737030
+1 85 1 1 5 1 1659 299 253 3.60 1.40 248055 126071 0.00 0.00 0.00 0.00 0.00 0.80 1.20 184.40 257.40 2.6 6692 1839965
+1 77 1 1 9 2 2273 186 109 6.60 19.00 32197 17334 0.40 0.40 0.40 0.00 0.20 7.80 9.60 238.80 447.80 4.2 364 1094742
+1 75 1 1 9 0 2853 136 147 6.20 17.80 95074 82610 1.80 16.80 49.20 76.60 0.00 10.40 15.60 207.20 422.60 1.6 126 1081834
+1 91 1 1 95 82 1567 170 114 0.80 0.80 245713 56190 0.00 0.00 0.00 0.00 0.60 2.00 4.00 51.80 185.40 1.0 637 992291
+1 98 1 1 0 0 183 26 25 0.20 0.20 552 6790 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.57 17.17 1.0 431 1753792
+1 66 1 1 44 0 3218 174 114 11.42 33.27 350499 57070 0.60 0.80 0.80 0.00 2.61 3.61 4.41 366.93 685.17 1.0 281 1096983
+1 91 1 1 3 0 1923 176 77 1.20 1.40 115148 36799 0.40 0.40 0.40 0.00 0.80 2.20 2.20 95.00 143.80 1.0 176 1126896
+1 86 1 1 9 1 2503 345 279 3.99 1.20 104620 30990 0.00 0.00 0.00 0.00 0.00 4.19 5.39 183.23 316.97 2.0 911 971214
+1 74 1 1 17 6 3386 545 378 6.80 5.20 947563 119175 0.00 0.00 0.00 0.00 0.00 7.60 9.80 324.40 510.40 2.0 2521 1091992
+1 87 1 1 50 62 3731 387 227 0.20 0.40 93976 59287 5.80 6.60 6.60 0.00 6.00 4.00 5.60 27.60 83.20 1.5 306 1090744
+1 95 1 1 2 0 1510 178 138 0.40 0.60 17912 30669 2.40 4.40 4.40 0.00 0.20 1.20 2.00 33.20 66.60 2.7 203 1003520
+1 64 1 1 23 9 5404 618 116 3.40 14.60 420330 347477 27.60 52.60 52.60 0.00 2.20 2.00 2.60 265.40 304.00 3.8 323 1546792
+1 78 1 1 12 4 1128 129 107 6.99 19.76 43742 25080 2.79 3.19 3.19 0.00 0.80 8.98 12.97 235.53 454.09 1.0 181 1103166
+1 90 1 1 15 2 2389 264 198 1.80 0.60 101604 86282 1.20 1.20 1.20 0.00 0.60 24.00 25.60 90.20 209.40 1.5 239 1077859
+1 91 1 1 11 6 2015 180 149 1.20 0.60 42567 68083 0.00 0.00 0.00 0.00 0.20 0.60 0.60 75.95 155.51 2.6 718 1106855
+1 84 1 1 5 0 1277 148 186 3.20 1.00 75836 83467 0.00 0.00 0.00 0.00 0.00 0.00 0.00 157.60 226.60 2.2 980 1761306
+1 96 1 1 1 0 854 119 96 0.20 0.20 3876 32284 0.80 0.80 0.80 0.00 0.20 2.20 2.60 14.40 25.60 2.0 161 1058893
+1 83 1 1 4 1 5393 225 235 1.20 3.60 149317 390589 13.80 24.20 34.60 31.20 12.00 3.60 4.40 138.20 217.80 3.4 206 1384973
+1 97 1 1 0 0 310 49 48 0.20 0.20 1355 16980 0.00 0.00 0.00 0.00 0.00 9.78 9.98 15.77 51.30 1.2 415 1722994
+1 85 1 1 4 0 583 49 46 3.00 2.80 88884 74076 0.00 0.00 0.00 0.00 0.00 2.20 2.20 246.20 218.20 1.0 6204 1849088
+1 91 1 1 7 4 1911 255 198 1.00 0.80 22534 24164 0.00 0.00 0.00 0.00 0.20 1.20 1.20 58.80 74.80 2.0 1211 1133518
+1 78 1 1 10 0 2488 271 224 0.60 1.80 364602 420692 4.80 39.00 202.20 420.40 0.40 48.20 91.80 45.40 192.80 1.6 132 1025203
+1 94 1 1 4 1 411 17 21 2.00 2.20 48540 37250 0.00 0.00 0.00 0.00 0.00 5.80 11.60 101.00 140.40 1.2 7785 1879002
+1 80 1 1 175 75 2984 333 357 3.60 7.40 409779 343871 0.00 0.00 0.00 0.00 0.20 3.40 4.20 234.80 356.80 1.0 799 1124395
+1 90 1 1 4 1 2237 278 169 0.60 0.60 156950 85934 0.00 0.00 0.00 0.00 0.40 3.41 5.01 41.68 94.59 2.0 451 989412
+1 98 1 1 12 17 194 20 22 0.20 0.20 68352 15981 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 5230 1856600
+1 87 1 1 2 1 3436 240 321 0.40 1.80 97319 545693 0.20 0.20 0.20 0.00 0.60 3.20 3.20 32.40 49.00 1.0 704 992006
+1 89 1 1 1 0 2521 196 162 0.40 1.80 185731 50125 12.18 15.97 15.97 0.00 11.78 3.59 5.99 33.93 95.21 1.0 159 1014073
+1 97 1 1 1 0 269 38 20 0.20 0.20 200152 10044 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.77 16.97 2.2 8117 1860287
+1 82 1 1 182 44 902 222 184 1.60 1.80 227621 205407 0.00 0.00 0.00 0.00 0.00 20.24 39.68 151.90 154.31 1.8 2528 1784827
+1 90 1 1 10 4 3660 203 167 1.00 1.60 92071 87407 0.00 0.00 0.00 0.00 0.00 2.40 2.40 103.80 117.40 3.8 2695 1530957
+1 90 1 1 21 4 3092 242 180 1.40 1.60 122507 16070 0.00 0.00 0.00 0.00 0.00 5.40 14.40 88.40 141.60 2.4 1135 1524046
+1 81 1 1 9 1 3244 413 338 6.00 1.60 163931 14484 2.60 3.00 3.00 0.00 0.20 1.00 1.00 302.40 427.80 2.4 292 1709072
+1 72 1 1 3 0 1957 169 154 1.40 2.60 460204 192763 9.40 67.40 200.60 374.00 0.60 46.80 86.40 94.60 309.40 2.0 133 1019830
+1 68 1 1 51 61 2947 212 149 7.62 20.84 195892 59564 4.01 8.42 20.64 47.29 3.01 10.42 14.23 329.86 604.81 4.8 191 1089134
+1 97 1 1 15 22 189 10 15 0.20 0.20 7564 13521 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.4 8320 1863725
+1 87 1 1 33 46 2709 158 99 1.20 2.80 182741 77871 0.00 0.00 0.00 0.00 0.20 2.60 3.20 93.80 134.60 2.0 359 987986
+1 0 1 1 22 31 1564 89 75 0.40 0.40 31239 39031 0.80 0.80 0.80 0.00 0.40 2.20 2.60 40.60 36.40 367 95 5
+1 90 1 1 31 1 1301 176 93 1.00 0.80 52549 25910 4.19 40.52 133.93 272.26 0.20 49.50 67.86 108.78 159.48 2.4 105 1526877
+1 95 1 1 1 0 1493 118 45 0.20 0.20 466559 7214 0.00 0.00 0.00 0.00 0.00 0.20 0.20 13.43 18.04 1.0 1059 1746774
+1 96 1 1 1 0 649 77 78 0.20 0.20 2893 34456 0.00 0.00 0.00 0.00 0.60 0.40 0.40 20.20 34.00 1.0 1143 1065840
+1 86 1 1 56 77 1668 157 121 1.20 1.60 33278 55933 9.58 17.17 26.35 52.30 1.00 4.99 5.59 83.23 125.15 1.0 268 961782
+1 84 1 1 7 1 3909 172 113 3.79 4.39 140762 30751 1.00 1.20 1.20 0.00 0.40 2.59 3.19 237.92 386.63 1.5 242 1014125
+1 88 1 1 11 2 3382 288 236 0.60 0.80 271527 69690 2.60 8.00 19.00 40.20 0.60 19.20 23.40 42.00 81.80 3.0 142 1046256
+1 88 1 1 30 40 3888 207 130 0.80 1.00 119982 45116 0.60 0.60 0.60 0.00 0.40 2.40 3.21 70.74 90.98 2.0 271 1069917
+1 98 1 1 1 1 192 13 23 0.20 0.20 7000 15797 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.6 7394 1861860
+1 90 1 1 14 21 409 79 44 0.60 0.80 251088 220098 0.00 0.00 0.00 0.00 0.00 3.00 5.40 48.80 64.60 2.6 3607 1822008
+1 95 1 1 1 1 384 151 56 0.20 0.20 278545 232878 0.00 0.00 0.00 0.00 0.00 5.40 10.00 16.20 36.60 2.4 5806 1829590
+1 83 1 1 11 11 5091 342 209 0.80 1.00 209472 59179 7.60 24.00 38.60 86.80 1.00 4.00 7.20 116.00 184.80 1.2 212 999008
+1 87 1 1 4 2 2351 228 161 2.40 4.00 45032 84410 1.60 1.60 3.00 2.20 0.60 0.60 0.60 224.60 230.20 1.0 216 1064830
+1 66 1 1 7 0 6644 1280 1233 6.60 1.80 1043946 877963 0.00 0.00 0.00 0.00 0.20 11.80 12.40 312.20 512.00 3.0 997 1118688
+1 95 1 1 3 0 982 153 24 0.20 0.20 144680 5430 0.00 0.00 0.00 0.00 0.00 0.00 0.00 46.80 71.40 2.4 4038 1716050
+1 88 1 1 13 4 2460 212 205 0.60 0.60 218663 95372 0.00 0.00 0.00 0.00 0.00 10.20 15.60 34.20 73.80 1.0 404 1018656
+1 94 1 1 4 0 2056 93 100 1.00 1.40 12514 71606 0.00 0.00 0.00 0.00 0.00 0.00 0.00 68.20 89.80 2.0 2976 1654442
+1 93 1 1 1 0 1333 114 62 0.20 0.20 141952 21894 2.79 9.98 39.72 71.46 0.00 16.97 32.73 16.17 37.33 1.5 140 1034957
+1 92 1 1 97 0 887 135 47 0.80 1.00 845121 35646 0.20 0.40 0.40 0.00 0.40 1.20 1.20 47.00 73.80 4.2 356 1700874
+1 78 1 1 55 68 4924 611 348 4.60 1.40 130709 32755 4.00 4.00 4.00 0.00 1.00 2.00 2.20 226.20 446.20 1.0 237 1074595
+1 92 1 1 6 1 1043 160 116 1.60 1.60 25641 20715 0.00 0.00 0.00 0.00 0.00 2.00 3.40 84.80 152.20 1.0 577 970690
+1 95 1 1 2 0 692 87 62 1.00 0.40 33394 5284 0.00 0.00 0.00 0.00 0.00 0.20 0.20 59.00 78.40 2.0 391 1717506
+1 92 1 1 3 0 1651 103 90 0.80 2.20 24966 16984 1.40 7.40 15.80 36.20 0.40 6.20 10.80 45.00 142.20 3.2 140 1440835
+1 90 1 1 5 2 1198 280 164 0.40 0.40 107936 28463 0.00 0.00 0.00 0.00 0.00 2.40 2.60 40.00 60.20 5.0 1457 1071050
+1 97 1 1 1 1 372 25 33 0.20 0.20 7977 18631 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 1.0 7591 1869464
+1 99 1 1 0 0 174 11 13 0.20 0.20 452 4750 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 7318 1867615
+1 92 1 1 12 10 588 100 91 0.80 0.60 27040 33387 4.80 9.20 12.00 13.00 5.20 0.00 0.00 55.60 71.00 2.4 194 1716059
+1 84 1 1 1 0 3017 351 206 0.40 0.60 90084 116978 7.20 39.40 82.80 142.20 0.00 23.80 24.00 46.80 131.00 1.6 140 1119339
+1 87 1 1 4 0 889 77 36 2.59 5.19 134414 28946 0.00 0.00 0.00 0.00 0.00 7.19 12.38 234.73 208.78 1.4 6376 1847115
+1 91 1 1 2 0 2897 199 171 0.80 2.40 326263 140615 0.00 0.00 0.00 0.00 0.00 1.00 1.20 45.20 88.80 1.0 534 1119382
+1 77 1 1 15 15 8965 771 275 0.60 0.60 67057 119165 2.60 2.80 10.60 23.40 0.80 4.80 5.80 27.40 63.40 3.0 153 998382
+1 92 1 1 1 0 2948 178 106 0.40 0.40 21262 17499 0.00 0.00 0.00 0.00 0.00 0.80 0.80 37.20 35.60 1.0 2993 1012963
+1 96 1 1 15 13 935 133 51 0.40 0.40 123350 56128 0.00 0.00 0.00 0.00 0.00 0.00 0.00 29.46 43.29 1.2 7297 1869177
+1 83 1 1 27 0 3188 285 214 3.20 3.20 99363 30864 6.80 44.20 75.40 191.20 0.00 31.00 42.00 162.80 302.00 2.5 203 1047605
+1 88 1 1 5 2 2935 336 212 0.60 0.60 65027 96604 6.00 10.60 9.20 0.00 2.00 1.60 2.20 44.60 64.60 1.5 288 1090358
+1 95 1 1 2 1 375 69 71 0.40 0.40 37289 46049 0.00 0.00 0.00 0.00 0.00 8.60 8.60 36.00 50.00 2.0 6433 1712288
+1 99 1 1 0 0 133 7 9 0.20 0.20 438 5817 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 8603 1865776
+1 96 1 1 3 2 520 61 48 0.40 0.40 138319 109404 0.00 0.00 0.00 0.00 0.00 0.60 0.60 39.40 41.40 1.2 5921 1842325
+1 94 1 1 0 0 2441 70 89 0.20 0.20 14125 41814 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.6 584 1743992
+1 79 1 1 6 3 4203 359 261 0.60 0.60 187068 195261 0.00 0.00 0.00 0.00 0.00 3.40 4.20 64.60 96.00 1.0 547 1053986
+1 78 1 1 51 71 3627 193 262 0.20 0.20 87581 567966 9.00 15.40 52.60 111.20 0.20 9.80 16.20 20.20 105.60 2.8 153 997955
+1 95 1 1 2 1 1767 170 62 0.80 0.80 119982 9697 0.00 0.00 0.00 0.00 0.00 0.60 1.00 58.40 85.40 1.6 5910 1863094
+1 0 1 1 41 39 1523 438 146 0.40 0.40 649909 644008 0.00 0.00 0.00 0.00 0.00 0.00 0.00 30.60 58.80 663 92 8
+1 93 1 1 13 13 2538 156 86 0.20 0.20 29138 24202 3.80 4.00 4.00 0.00 0.40 3.00 3.00 17.80 36.20 3.2 229 1086987
+1 93 1 1 5 2 2521 118 103 0.60 0.60 99305 82467 0.00 0.00 0.00 0.00 0.00 0.60 0.60 36.60 103.60 2.2 839 1645302
+1 89 1 1 1 0 2247 162 89 0.40 0.40 50221 27247 1.40 2.81 2.81 0.00 0.00 1.00 1.00 56.51 62.32 1.2 241 1058693
+1 90 1 1 25 35 1361 142 109 1.20 0.80 83578 18388 1.20 1.20 1.20 0.00 0.60 4.58 5.18 87.25 112.95 1.0 233 1113963
+1 95 1 1 33 47 967 78 46 0.40 0.60 36104 46064 0.00 0.00 0.00 0.00 0.00 1.20 1.20 35.60 92.00 1.0 2953 1014126
+1 0 1 1 6 0 828 126 130 1.19 0.80 217177 25808 10.14 48.11 122.47 260.83 0.40 6.56 10.34 69.38 222.07 168 89 11
+1 90 1 1 1 0 2633 354 339 0.20 0.20 83258 37363 0.00 0.00 0.00 0.00 0.20 27.20 27.40 22.20 75.40 2.6 2070 1709363
+1 69 1 1 155 145 8441 326 222 2.20 7.78 319257 126880 0.00 0.00 0.00 0.00 0.00 26.55 37.72 200.20 280.24 5.2 1579 1330772
+1 96 1 1 2 0 432 50 23 1.40 1.40 178357 16605 0.00 0.00 0.00 0.00 0.00 4.40 7.40 64.40 94.80 1.0 5631 1856450
+1 94 1 1 18 28 703 59 40 0.60 0.60 1611 8707 0.00 0.00 0.00 0.00 0.00 0.00 0.00 50.80 61.40 1.0 1082 1743728
+1 94 1 1 1 0 1359 97 59 0.20 0.20 159517 157847 0.00 0.00 0.00 0.00 0.20 1.80 3.40 24.80 19.80 3.2 451 1725314
+1 76 1 1 7 1 3865 191 179 1.60 3.80 186277 146745 0.00 0.00 0.00 0.00 0.00 3.40 4.40 133.80 202.00 4.2 825 1515533
+1 96 1 1 0 0 341 90 49 0.20 0.20 120762 118827 0.00 0.00 0.00 0.00 0.00 6.60 12.60 15.20 17.80 3.0 1240 1751693
+1 90 1 1 6 0 2805 184 135 0.60 0.60 33796 65116 0.00 0.00 0.00 0.00 0.00 3.79 5.59 51.50 74.85 2.8 1090 1531406
+1 94 1 1 1 0 538 95 48 0.20 0.20 139284 97012 0.00 0.00 0.00 0.00 0.00 2.40 4.00 16.00 25.60 3.2 1083 1749909
+1 85 1 1 152 149 3297 262 224 1.00 0.60 69750 136002 0.20 0.20 0.20 0.00 9.98 10.98 11.78 54.29 109.78 3.0 326 1079545
+1 63 1 1 48 1 3217 190 95 11.80 33.80 249106 33453 1.60 8.80 12.80 14.00 3.60 15.40 15.60 422.20 772.60 1.2 197 1095115
+1 86 1 1 29 38 4259 249 175 1.00 2.60 311298 226466 0.00 0.00 0.00 0.00 0.00 9.20 14.40 81.40 190.60 5.2 3500 1332434
+1 90 1 1 5 2 1825 126 191 0.40 0.40 215016 445735 3.80 4.00 4.00 0.00 3.60 5.20 6.20 34.40 67.00 3.0 328 1372560
+1 96 1 1 2 0 1010 63 59 0.80 0.40 18045 14704 0.00 0.00 0.00 0.00 0.00 0.00 0.00 45.00 65.80 2.0 2174 1720634
+1 88 1 1 2 2 4353 226 147 0.80 4.00 93265 40400 0.00 0.00 0.00 0.00 0.00 2.60 4.40 116.40 77.60 2.6 1090 1461510
+1 77 1 1 12 0 3877 518 438 6.20 3.80 204681 53648 5.00 8.60 8.60 0.00 0.00 1.00 1.00 305.60 519.20 2.8 231 1004098
+1 93 1 1 2 1 1073 63 71 0.20 0.20 34069 220893 0.00 0.00 0.00 0.00 0.00 18.36 18.36 15.37 49.10 1.2 8295 1860032
+1 89 1 1 19 20 2914 153 118 0.60 0.80 73684 96738 0.00 0.00 0.00 0.00 0.40 24.05 27.86 47.70 96.99 1.5 1676 1114847
+1 82 1 1 65 83 2194 220 133 0.40 0.40 246472 80797 0.00 0.00 0.00 0.00 0.00 31.94 53.69 42.91 119.96 1.0 1310 1086976
+1 91 1 1 0 0 1848 161 94 0.20 0.20 6060 43988 0.00 0.00 0.00 0.00 0.20 48.20 48.20 15.20 138.60 1.8 627 1065781
+1 96 1 1 1 0 1219 155 105 0.20 0.20 8458 26050 0.20 0.20 0.20 0.00 0.00 1.40 1.40 15.80 19.40 2.0 219 1067466
+1 96 1 1 1 0 1413 168 67 0.20 0.20 146112 137143 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.20 17.40 4.0 2372 1575277
+1 83 1 1 6 4 3353 401 344 1.40 2.81 162814 35797 7.41 7.82 7.82 0.00 3.41 11.02 11.82 96.39 178.16 1.0 200 1105945
+1 84 1 1 4 2 3440 454 221 0.80 1.40 241481 33613 0.00 0.00 0.00 0.00 0.20 7.78 7.78 56.09 115.97 1.5 1121 1128426
+1 88 1 1 4 0 2300 235 213 3.60 1.60 118361 19833 0.00 0.00 0.00 0.00 0.00 0.00 0.00 187.80 253.80 2.2 6855 1827522
+1 88 1 1 3 1 1909 303 103 1.00 4.01 1150630 27113 1.00 1.00 1.80 3.61 2.00 8.42 9.02 55.31 250.10 2.6 220 1099550
+1 95 1 1 0 0 877 212 88 0.20 0.20 250261 236379 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.40 3.2 1011 1753638
+1 85 1 1 5 1 2443 405 327 3.80 2.20 183535 89572 0.00 0.00 0.00 0.00 0.00 2.40 2.60 211.80 324.20 1.0 2637 1017880
+1 90 1 1 1 0 344 35 47 0.80 1.00 1606 4855 0.00 0.00 0.00 0.00 0.00 0.20 0.20 47.40 82.40 1.8 792 1760419
+1 93 1 1 11 2 2036 161 99 0.80 2.40 213829 47951 0.00 0.00 0.00 0.00 0.00 0.40 0.40 43.69 88.38 3.0 785 1054851
+1 99 1 1 0 0 161 10 27 0.20 0.20 425 23258 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6236 1856808
+1 98 1 1 0 0 293 29 26 0.40 1.00 718 10486 0.00 0.00 0.00 0.00 0.00 0.00 0.00 29.00 33.20 2.0 882 1704760
+1 98 1 1 0 0 138 9 10 0.20 0.20 1046 7427 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 6363 1852585
+1 93 1 1 1 0 1930 113 128 0.20 0.20 134171 244514 1.60 7.80 15.60 36.60 0.00 5.00 10.00 55.80 27.80 2.6 136 1539870
+1 73 1 1 40 3 2374 255 138 3.79 4.39 300938 45485 0.00 0.00 0.00 0.00 0.20 36.73 55.29 303.19 569.26 2.2 2604 950612
+1 91 1 1 62 59 1596 120 102 0.40 0.40 12770 81899 1.60 1.60 1.60 0.00 0.80 45.00 45.20 47.00 118.20 1.8 429 976446
+1 86 1 1 1 0 5181 281 144 0.40 0.40 319646 68764 7.39 26.75 34.73 56.69 3.19 18.36 26.15 37.92 96.01 1.0 161 1026603
+1 93 1 1 16 13 2743 133 112 0.40 1.80 42204 44457 0.00 0.00 0.00 0.00 0.20 2.80 4.20 35.40 110.00 4.0 6913 1367715
+1 79 1 1 10 1 5806 994 164 0.60 1.20 2526649 37704 5.19 7.78 9.18 7.19 0.60 18.96 25.55 56.49 231.74 1.2 306 1126339
+1 94 1 1 1 0 1099 55 51 0.80 0.80 3061 16526 1.40 1.60 1.60 0.00 0.00 1.20 1.20 77.80 97.80 2.3 267 1119752
+1 96 1 1 2 1 279 47 20 0.20 0.20 179007 5222 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 18.84 1.4 7401 1869352
+1 89 1 1 14 6 2181 278 116 2.20 9.80 257023 18972 0.00 0.00 0.00 0.00 1.00 0.60 0.60 132.80 216.60 2.0 1589 1023714
+1 86 1 1 106 49 2258 270 216 2.00 2.00 138625 103691 0.00 0.00 0.00 0.00 0.20 12.60 16.00 88.00 198.40 1.0 883 1010248
+1 96 1 1 1 0 238 31 24 0.20 0.20 19037 5086 0.00 0.00 0.00 0.00 0.00 0.20 0.20 17.00 17.80 2.0 585 1710952
+1 94 1 1 2 1 1438 171 129 0.40 1.40 21961 19207 0.00 0.00 0.00 0.00 0.00 0.80 0.80 20.84 39.08 1.6 992 1129921
+1 98 1 1 1 0 243 35 33 0.20 0.20 6023 13554 0.00 0.00 0.00 0.00 0.00 0.60 0.60 15.57 16.77 1.0 448 1739701
+1 80 1 1 4 0 5308 213 116 3.99 6.99 211452 67544 1.80 3.19 2.99 0.00 1.20 3.19 3.19 253.49 445.71 4.2 329 1013876
+1 94 1 1 16 15 623 130 61 0.20 0.20 228717 134209 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 20.20 4.6 578 1742218
+1 96 1 1 2 2 1753 204 93 0.20 0.20 149267 137092 0.00 0.00 0.00 0.00 0.00 0.60 0.80 15.20 18.40 5.6 3856 1605106
+1 87 1 1 11 6 2532 201 110 1.40 2.60 137911 26016 5.00 8.40 27.20 37.60 4.40 20.60 24.20 77.40 181.20 2.5 141 1112808
+1 93 1 1 1 0 522 148 77 0.20 0.20 217279 226751 0.00 0.00 0.00 0.00 0.00 8.60 16.80 15.60 27.80 3.6 1485 1754614
+1 96 1 1 2 2 1668 73 61 0.20 0.20 7043 12137 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 16.80 2.0 2083 1720422
+1 88 1 1 4 2 1652 228 135 0.60 2.00 155437 16671 1.40 5.61 9.82 12.42 1.80 14.63 14.83 56.11 177.76 5.0 618 1124457
+1 86 1 1 3 2 2604 478 337 1.20 0.40 1288734 224743 0.00 0.00 0.00 0.00 0.40 2.81 2.81 60.12 92.18 3.0 2480 1094020
+1 1 1 1 34 5 2424 109 142 6.40 19.80 40458 85259 3.80 4.20 9.40 9.60 1.60 8.00 15.80 202.00 402.80 207 80 18
+1 91 1 1 2 2 2318 120 142 0.60 0.60 21467 79415 0.00 0.00 0.00 0.00 1.00 2.99 3.39 43.11 87.82 1.0 568 1127934
+1 95 1 1 5 4 1806 83 61 0.20 0.20 6241 28631 5.19 6.19 5.39 0.00 1.40 0.00 0.00 19.16 30.94 1.5 287 1015270
+1 97 1 1 0 0 656 46 33 0.40 1.60 1306 14762 0.00 0.00 0.00 0.00 0.00 0.00 0.00 19.20 23.20 1.4 7786 1879430
+1 83 1 1 4 1 2327 105 87 0.40 0.60 37127 55716 0.00 0.00 0.00 0.00 0.00 0.60 0.60 31.60 38.40 2.4 974 1519320
+1 68 1 1 20 7 8566 265 170 3.19 8.98 175738 40365 0.00 0.00 0.00 0.00 0.00 0.00 0.00 245.11 286.43 3.6 974 1521282
+1 90 1 1 22 30 239 24 32 0.20 0.20 16918 31674 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.60 16.80 1.6 2179 1776491
+1 87 1 1 3 0 2409 183 158 2.20 3.01 149023 57004 2.81 12.42 28.66 45.29 0.40 10.22 17.64 125.05 199.20 3.2 193 1057406
+1 87 1 1 5 0 1816 234 191 3.80 1.20 260546 124832 0.00 0.00 0.00 0.00 0.00 1.60 3.20 187.60 266.40 3.6 516 1725078
+1 90 1 1 4 1 3201 199 117 0.80 0.80 361096 41257 4.00 5.60 10.20 8.80 9.40 3.00 4.80 60.20 80.20 1.0 156 975768
+1 86 1 1 18 12 1428 139 55 4.60 4.40 243613 33068 0.00 0.00 0.00 0.00 0.00 2.00 4.00 202.00 323.80 1.6 8441 1835414
+1 78 1 1 33 35 3332 479 415 7.60 2.40 200556 15057 0.00 0.00 0.00 0.00 0.00 0.40 0.40 364.60 528.40 4.0 1992 1718714
+1 68 1 1 18 1 4108 599 507 7.57 1.99 460349 19771 9.56 34.86 53.78 142.63 0.20 19.32 35.06 379.48 601.79 1.0 184 963066
+1 95 1 1 4 1 633 123 17 2.00 2.40 896067 8671 0.00 0.00 0.00 0.00 0.00 0.00 0.00 101.80 133.20 2.4 8381 1863686
+1 88 1 1 5 0 2504 329 242 0.40 0.40 254766 56907 1.60 2.00 1.80 0.00 22.24 4.01 5.21 36.67 133.67 4.2 440 1093691
+1 78 1 1 10 4 4151 483 196 0.80 2.20 669530 439084 0.00 0.00 0.00 0.00 0.00 40.32 52.30 66.67 181.04 3.6 860 1031340
+1 90 1 1 13 3 2486 136 111 1.20 2.60 93047 17950 4.20 4.20 4.20 0.00 2.00 7.80 7.80 76.40 132.20 2.2 150 1053270
+1 95 1 1 1 0 1320 97 76 0.60 0.60 23050 42531 0.00 0.00 0.00 0.00 0.20 4.00 4.00 39.20 72.40 3.0 590 1032355
+1 77 1 1 6 0 2901 391 235 5.40 3.00 899023 23670 0.00 0.00 0.00 0.00 0.00 4.60 8.00 281.60 393.60 4.0 2988 1769106
+1 97 1 1 14 22 449 119 49 0.20 0.20 65939 7203 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 32.26 1.6 897 1770642
+1 94 1 1 2 1 1389 206 73 0.40 0.60 170513 162281 0.00 0.00 0.00 0.00 0.00 3.00 5.20 29.40 43.80 3.2 588 1742114
+1 87 1 1 20 19 1692 170 91 0.80 1.40 19836 27765 0.00 0.00 0.00 0.00 0.00 11.62 22.85 119.84 189.58 1.0 1358 1077927
+1 79 1 1 7 0 4117 303 247 4.20 3.80 188954 92388 4.40 4.60 4.60 0.00 0.40 11.80 13.20 190.00 309.00 3.6 470 1049291
+1 75 1 1 6 0 5077 462 404 5.40 1.80 180837 225321 5.00 11.80 31.00 55.80 1.00 8.40 8.80 257.00 508.40 1.2 157 1006085
+1 95 1 1 14 17 442 20 13 4.01 2.61 53077 7000 0.00 0.00 0.00 0.00 0.00 0.00 0.00 139.48 216.83 1.0 9034 1877243
+1 93 1 1 2 1 766 179 73 0.20 0.20 444620 202863 0.00 0.00 0.00 0.00 0.00 6.20 12.00 15.80 42.80 1.4 8331 1837272
+1 92 1 1 1 0 326 37 32 0.40 0.40 18480 11480 0.00 0.00 0.00 0.00 0.00 0.20 0.20 37.33 39.92 1.4 995 1761844
+1 87 1 1 6 0 4513 278 170 1.20 3.00 192102 71682 0.00 0.00 0.00 0.00 0.80 1.40 1.40 53.80 89.80 1.0 514 1076918
+1 89 1 1 12 1 2349 169 106 2.20 2.20 108705 44134 0.00 0.00 0.00 0.00 0.00 1.40 1.40 101.20 190.62 3.2 1604 1538354
+1 74 1 1 9 3 3136 529 210 4.59 6.39 688893 577311 0.00 0.00 0.00 0.00 0.00 18.16 28.54 257.88 502.40 1.6 1252 1033330
+1 82 1 1 41 50 2676 434 375 2.80 1.20 168112 174379 0.00 0.00 0.00 0.00 0.00 1.20 2.20 157.40 299.20 2.0 441 1058874
+1 93 1 1 2 1 1061 109 50 1.20 1.40 231092 10300 1.60 1.60 2.20 3.20 0.80 0.20 0.20 62.00 88.20 2.8 155 1710000
+1 96 1 1 2 2 761 23 39 0.20 0.20 3423 39956 0.00 0.00 0.00 0.00 0.00 2.40 2.40 15.60 22.80 1.0 1847 1074878
+1 94 1 1 10 9 734 79 85 0.40 0.40 15256 18019 0.00 0.00 0.00 0.00 0.00 7.40 7.40 142.00 114.20 1.0 681 1016560
+1 86 1 1 6 0 1564 109 26 3.79 4.99 136101 18307 0.00 0.00 0.00 0.00 0.00 2.20 3.39 311.58 342.12 1.6 11589 1882777
+1 87 1 1 12 12 2479 297 168 0.80 1.40 1196116 1036352 4.40 5.80 5.80 0.00 0.40 22.60 25.00 65.80 165.00 1.4 306 1014872
+1 93 1 1 1 0 2342 108 123 0.20 0.20 36047 87756 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.40 26.80 1.0 351 1070133
+1 87 1 1 2 0 1860 166 100 1.20 1.00 140779 44401 0.00 0.00 0.00 0.00 0.00 12.00 12.40 75.20 161.40 1.2 2551 1096235
+1 85 1 1 70 87 3937 330 272 0.60 0.60 235212 108984 8.80 14.60 14.40 0.00 6.80 8.20 10.80 60.20 80.20 4.0 270 1048549
+1 97 1 1 1 1 809 33 28 0.40 0.40 7506 3989 0.00 0.00 0.00 0.00 0.00 0.00 0.00 32.40 39.60 1.0 4950 1828000
+1 0 1 1 2 0 2414 226 207 0.60 2.00 136711 124416 0.00 0.00 0.00 0.00 0.00 7.62 7.82 51.30 143.09 599 89 11
+1 88 1 1 41 59 1532 137 137 1.00 2.40 58358 50384 0.00 0.00 0.00 0.00 0.00 2.20 3.20 66.60 99.60 2.0 464 1131266
+1 84 1 1 2 0 3335 329 241 0.40 0.20 425840 324350 11.40 24.00 57.80 92.40 3.20 33.80 65.20 36.00 81.60 1.8 132 1004899
+1 96 1 1 23 34 315 92 40 0.20 0.20 111809 115758 0.00 0.00 0.00 0.00 0.20 0.00 0.00 15.60 18.00 3.6 719 1741602
+1 90 1 1 0 0 281 26 29 0.20 0.20 22484 40083 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.0 1852 1763705
+1 94 1 1 2 0 1191 86 68 0.40 0.60 13193 19300 0.00 0.00 0.00 0.00 0.00 1.00 1.00 30.46 80.96 1.3 686 1106847
+1 78 1 1 8 1 4813 473 339 4.80 1.40 228953 24687 0.00 0.00 0.00 0.00 0.60 14.40 14.40 234.40 398.20 2.4 544 988722
+1 98 1 1 2 2 378 49 16 0.20 0.20 21735 12519 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.6 8359 1869392
+1 98 1 1 0 0 166 10 20 0.20 0.20 431 12101 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6040 1855672
+1 84 1 1 7 1 616 102 53 2.20 2.20 401538 43194 0.00 0.00 0.00 0.00 0.00 4.40 6.80 171.80 177.20 1.8 1973 1822176
+1 80 1 1 4 0 5695 333 169 3.20 9.40 566222 306482 0.00 0.00 0.00 0.00 0.00 5.40 9.00 250.80 389.60 2.6 3250 1035138
+1 84 1 1 38 34 2722 194 162 2.80 3.40 239126 80216 0.00 0.00 0.00 0.00 0.00 0.20 0.20 172.80 273.20 3.2 500 1725562
+1 88 1 1 3 1 543 95 19 2.20 2.20 468258 28996 0.00 0.00 0.00 0.00 0.00 2.60 4.80 211.40 181.40 1.4 11462 1881400
+1 71 1 1 27 17 3059 385 287 6.79 7.19 343111 254225 5.99 18.76 65.67 103.99 2.59 4.59 8.98 284.03 565.87 2.2 171 1003404
+1 82 1 1 24 30 992 51 32 2.99 3.59 126690 26503 0.00 0.00 0.00 0.00 0.00 1.00 1.40 251.10 265.07 1.8 2287 1816024
+1 95 1 1 5 0 630 107 43 2.00 2.00 46911 21708 0.00 0.00 0.00 0.00 0.00 0.20 0.20 81.80 137.20 2.2 920 1721906
+1 97 1 1 1 0 795 71 48 0.20 0.20 108337 25139 1.60 3.41 4.61 3.41 0.40 0.60 0.60 15.63 16.83 1.2 130 1745911
+1 97 1 1 0 0 159 8 27 0.20 0.20 2061 27692 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.60 16.80 1.0 7641 1878904
+1 90 1 1 34 44 854 64 42 0.80 0.80 151356 50454 0.00 0.00 0.00 0.00 0.80 0.20 0.20 96.21 129.54 1.0 542 1015930
+1 91 1 1 11 5 1302 166 145 2.20 2.40 78127 33561 0.00 0.00 0.00 0.00 0.00 1.40 1.40 121.60 169.60 4.0 648 976386
+1 84 1 1 5 0 3426 275 269 3.20 1.00 81449 18478 0.00 0.00 0.00 0.00 0.00 0.20 0.20 162.00 236.80 3.4 844 1720685
+1 91 1 1 8 2 1175 193 183 1.20 1.40 125658 26936 0.00 0.00 0.00 0.00 0.40 10.60 20.20 72.40 107.80 2.0 746 971304
+1 94 1 1 6 0 894 89 57 1.60 1.80 85340 31182 0.00 0.00 0.00 0.00 0.00 2.60 3.00 77.40 167.20 1.0 560 1036755
+1 85 1 1 46 57 2290 270 180 2.60 4.80 399432 25519 2.20 2.40 3.20 1.40 7.60 5.20 6.00 156.20 280.80 1.0 236 1100771
+1 81 1 1 82 2 4146 436 204 0.60 1.20 213852 125542 0.00 0.00 0.00 0.00 0.00 6.59 16.57 119.56 219.36 6.6 1149 1305397
+1 90 1 1 11 6 1582 174 138 0.40 0.40 235837 61049 0.00 0.00 0.00 0.00 19.60 2.80 3.60 88.60 219.00 1.7 709 1114536
+1 97 1 1 1 0 346 58 47 0.20 0.20 59213 45801 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 17.00 2.0 903 1716584
+1 81 1 1 7 1 2766 314 264 6.99 2.40 246241 11230 0.00 0.00 0.00 0.00 0.00 0.00 0.00 345.91 489.02 3.2 7164 1858774
+1 83 1 1 228 47 2835 275 249 0.20 0.20 201736 209106 12.80 61.80 115.40 130.80 1.00 35.00 60.20 15.60 122.80 3.0 124 1017016
+1 94 1 1 1 0 1082 89 63 0.20 0.20 124699 83264 0.00 0.00 0.00 0.00 0.00 2.20 3.60 20.40 17.40 1.4 5797 1818256
+1 96 1 1 11 15 768 74 81 0.20 0.20 3565 71315 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 494 1733956
+1 94 1 1 39 53 1241 135 106 0.20 0.20 5594 17154 0.00 0.00 0.00 0.00 0.00 0.40 0.60 17.00 22.40 1.5 1613 1081952
+1 89 1 1 41 59 2423 135 83 0.20 0.20 153542 31762 2.00 3.20 3.20 0.00 0.60 10.20 10.20 25.80 66.40 1.6 233 982238
+1 98 1 1 1 1 141 11 11 0.20 0.20 6995 2231 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6459 1871616
+1 90 1 1 3 1 903 107 86 2.20 2.00 61943 151411 0.00 0.00 0.00 0.00 0.00 2.60 2.60 187.20 170.60 1.4 5507 1840805
+1 81 1 1 462 42 3683 173 164 1.00 3.00 22304 120135 0.00 0.00 0.00 0.00 0.00 45.40 47.60 26.20 64.00 1.5 1178 1070446
+1 78 1 1 5 3 3747 533 287 3.19 3.79 466175 605903 0.00 0.00 3.39 14.37 0.00 0.80 0.80 219.96 402.00 2.7 441 1038063
+1 88 1 1 4 1 548 80 85 2.20 1.80 257084 218771 0.00 0.00 0.00 0.00 0.00 1.00 1.20 164.00 158.60 1.6 5861 1849299
+1 94 1 1 24 0 1511 124 78 0.40 0.40 174835 149879 0.00 0.00 0.00 0.00 0.20 27.60 58.00 34.40 103.00 3.8 1915 1732395
+1 82 1 1 8 2 1967 286 220 6.59 3.99 470743 75387 0.00 0.00 0.00 0.00 0.00 8.78 16.97 297.60 431.94 2.2 8666 1860993
+1 85 1 1 3 1 3909 214 109 2.19 5.38 155848 27340 4.18 10.56 32.47 76.10 0.40 6.97 7.37 135.26 250.20 1.5 179 1023871
+1 85 1 1 1 0 3706 371 229 0.60 0.80 150837 64124 2.20 2.60 2.60 0.00 0.40 1.60 2.20 62.60 171.40 1.3 259 1114672
+1 0 1 1 14 5 2725 214 105 2.20 2.80 510378 275208 10.20 29.00 67.60 114.60 0.40 37.40 49.60 134.60 302.60 187 76 24
+1 86 1 1 2 0 2450 370 201 1.20 1.00 265523 94422 1.40 1.80 1.80 0.00 0.80 4.80 6.60 78.40 208.60 1.0 234 1113288
+1 96 1 1 1 0 508 196 77 0.20 0.20 259438 266905 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 16.80 2.4 1702 1759920
+1 91 1 1 13 10 1427 151 107 0.60 0.60 91093 109257 3.40 7.20 22.60 27.00 0.60 4.40 6.00 31.80 143.80 2.5 348 1000827
+1 95 1 1 1 0 2590 87 73 0.20 0.20 57840 105459 0.00 0.00 0.00 0.00 0.00 0.20 0.20 16.20 18.60 2.6 776 1643104
+1 94 1 1 4 1 1574 92 67 0.40 0.40 317762 40053 0.00 0.00 0.00 0.00 0.00 0.40 0.40 47.60 75.40 3.6 681 1529123
+1 85 1 1 3 0 1396 136 139 1.40 2.20 181842 63692 0.80 1.00 1.00 0.00 0.20 10.80 14.20 91.00 150.60 4.4 365 1052814
+1 0 1 1 7 1 1280 91 50 1.80 3.00 131362 16863 0.00 0.00 0.00 0.00 0.00 1.40 1.60 82.00 128.60 916 93 7
+1 95 1 1 0 0 1658 91 68 0.20 0.20 87721 11305 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 16.80 3.4 1598 1719224
+1 65 1 1 13 0 4075 192 143 10.40 30.80 180221 55147 3.40 8.20 14.40 29.20 0.40 13.80 24.20 338.40 694.80 1.0 139 1077811
+1 87 1 1 2 0 849 59 17 1.80 2.00 129696 10218 0.00 0.00 0.00 0.00 0.00 0.80 0.80 132.60 192.80 2.2 4106 1780830
+1 83 1 1 9 2 2682 376 330 6.80 2.00 204365 6143 0.00 0.00 0.00 0.00 0.00 0.00 0.00 333.00 490.40 2.6 6626 1872949
+1 81 1 1 6 0 1455 200 188 4.20 1.20 131063 51130 0.00 0.00 0.00 0.00 0.00 0.00 0.00 198.40 284.00 2.2 2103 1768179
+1 79 1 1 4 1 2893 380 188 2.60 2.60 168579 263824 33.20 62.20 55.00 0.00 0.80 27.40 52.40 130.60 315.20 2.4 243 1535341
+1 93 1 1 0 0 1260 90 76 0.20 0.20 5812 21490 0.20 0.20 0.20 0.00 0.20 0.80 0.80 15.60 134.40 2.7 169 1099162
+1 75 1 1 28 1 4700 385 179 6.40 9.80 156781 63261 0.00 0.00 0.00 0.00 0.00 19.40 22.60 380.40 590.00 4.0 734 1629358
+1 85 1 1 3 1 3109 210 383 0.80 1.00 123627 36022 1.20 7.40 16.00 23.20 0.60 7.80 8.60 67.20 98.60 2.2 203 1051835
+1 92 1 1 38 37 2798 190 116 0.40 0.20 29179 36285 0.00 0.00 0.00 0.00 0.00 0.00 0.00 25.20 145.60 1.8 702 978275
+1 94 1 1 2 0 317 40 23 0.20 0.20 35889 6305 0.00 0.00 0.00 0.00 0.40 0.20 0.20 20.60 18.60 1.8 476 1746894
+1 87 1 1 11 8 2549 192 134 2.99 3.99 274418 39942 0.60 1.00 1.00 0.00 1.80 1.60 2.00 210.98 315.37 1.5 383 1015162
+1 90 1 1 7 0 2100 178 104 1.60 1.80 58633 26231 0.80 0.80 0.80 0.00 0.40 1.80 5.40 103.60 136.80 3.2 283 1113419
+1 96 1 1 2 0 900 49 35 0.40 1.80 193177 13610 2.40 3.20 5.20 8.00 1.60 1.20 1.20 32.80 48.60 1.0 173 1014144
+1 92 1 1 6 1 1193 96 236 1.20 1.20 153211 277202 0.00 0.00 0.00 0.00 0.40 0.20 0.20 134.40 90.80 4.0 689 1540053
+1 90 1 1 3 2 2590 130 167 0.80 0.40 106798 26057 0.00 0.00 0.00 0.00 0.00 9.20 18.00 45.80 67.20 3.2 4490 1720176
+1 75 1 1 6 1 5112 801 786 4.40 3.20 534914 433180 0.00 0.00 0.00 0.00 0.00 8.80 10.80 218.60 344.20 3.8 1484 1038488
+1 87 1 1 11 9 2393 210 158 0.80 0.80 92784 64280 1.60 9.80 23.20 31.00 0.00 8.40 12.20 107.00 134.80 1.0 579 1060939
+1 99 1 1 0 0 168 16 15 0.20 0.20 501 4292 0.20 0.20 0.20 0.00 0.00 0.00 0.00 15.43 24.65 1.0 298 1759391
+1 81 1 1 59 67 1813 123 94 0.40 0.40 223748 30279 0.00 0.00 0.00 0.00 0.00 5.00 9.80 193.20 104.80 2.8 1969 1768944
+1 85 1 1 42 54 4727 393 215 0.60 2.80 684711 703355 0.00 0.00 0.00 0.00 142.40 3.20 3.60 38.60 203.00 4.2 2867 1546402
+1 94 1 1 28 38 4140 103 121 0.40 1.80 56604 77333 0.00 0.00 0.00 0.00 0.00 1.60 2.00 20.76 33.93 2.8 3162 1645161
+1 97 1 1 1 1 283 46 39 0.20 0.20 22876 9102 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 7197 1847022
+1 67 1 1 6 1 7108 1327 1268 5.00 2.60 1244800 896995 0.00 0.00 0.00 0.00 0.60 3.80 6.40 250.20 380.80 1.2 722 1093789
+1 90 1 1 2 2 1668 81 91 0.20 0.20 127124 109027 15.57 20.76 20.76 0.00 16.37 9.58 14.77 16.97 42.91 1.3 193 1128155
+1 80 1 1 27 21 3859 373 197 3.99 10.18 290104 55249 1.40 1.40 1.40 0.00 1.60 13.17 16.17 283.43 373.45 1.7 385 1017758
+1 89 1 1 4 2 2445 156 147 0.60 2.00 48871 82323 9.00 14.00 13.80 0.00 1.20 0.60 0.80 48.00 59.60 1.3 305 1011376
+1 86 1 1 7 1 2092 123 153 1.20 2.00 246048 441796 9.60 47.60 95.80 174.20 1.40 33.40 56.60 53.60 146.60 3.2 172 1378574
+1 76 1 1 12 1 3163 474 414 8.80 2.40 261271 9070 0.00 0.00 0.00 0.00 0.00 0.00 0.00 436.00 621.60 3.0 7201 1863333
+1 63 1 1 72 46 4424 282 163 11.20 31.80 330988 79649 4.00 16.60 29.20 45.60 2.40 18.60 25.00 379.40 704.80 2.0 165 1095630
+1 97 1 1 0 0 354 69 82 0.00 0.00 17661 63201 0.20 0.40 11.80 27.20 0.20 0.00 0.00 4.20 24.40 3.8 129 1711278
+1 82 1 1 9 5 766 72 62 2.60 4.80 174457 52467 0.40 0.40 0.40 0.00 0.00 4.00 6.60 225.60 233.20 1.8 425 1802610
+1 69 1 1 13 1 3501 353 147 5.99 6.79 251468 31489 4.79 18.76 65.07 111.98 2.99 54.09 56.09 350.90 687.82 1.0 125 1084677
+1 98 1 1 1 1 167 12 18 0.20 0.20 12365 15635 0.00 0.00 0.00 0.00 0.00 0.00 0.00 38.48 16.83 1.0 8337 1867503
+1 0 1 1 14 12 1028 362 128 0.20 0.20 597656 620164 0.00 0.00 0.00 0.00 0.00 0.40 0.40 24.95 53.29 821 94 5
+1 87 1 1 54 74 3871 283 269 0.99 0.79 44706 84551 0.79 1.19 1.19 0.00 1.19 4.56 4.96 47.62 96.43 6.4 247 967683
+1 94 1 1 1 0 1290 57 31 0.20 0.20 179031 20684 0.00 0.00 0.00 0.00 0.00 2.00 3.79 15.57 19.16 1.8 737 1036984
+1 93 1 1 4 1 1708 220 73 0.80 2.40 43234 37983 0.00 0.00 0.00 0.00 0.00 1.00 1.60 68.60 102.20 3.0 629 1534331
+1 89 1 1 48 68 516 64 18 0.80 0.80 351460 4520 0.00 0.00 0.00 0.00 0.00 1.40 1.80 61.68 66.27 2.2 581 1738362
+1 96 1 1 7 5 892 84 53 0.60 0.60 5332 16069 0.00 0.00 0.00 0.00 0.00 1.00 1.00 36.87 83.37 3.0 951 977579
+1 83 1 1 20 14 4323 184 161 1.00 2.00 204809 125941 3.40 24.00 61.60 165.20 0.80 6.00 9.80 96.80 182.80 3.8 276 1540699
+1 89 1 1 0 0 870 101 72 0.20 0.20 82498 117368 0.00 0.00 0.00 0.00 0.00 3.00 6.00 15.40 19.20 1.8 1952 1769032
+1 92 1 1 5 0 2277 100 111 0.60 3.60 51150 49643 0.00 0.00 0.00 0.00 0.00 3.20 4.20 56.80 62.40 2.0 617 1085829
+1 84 1 1 13 9 1409 104 95 2.20 2.20 58232 54434 0.00 0.00 0.00 0.00 0.00 12.20 23.60 195.60 334.60 2.5 650 1062995
+1 73 1 1 6 0 4772 409 417 5.80 1.80 164052 486561 0.00 0.00 0.00 0.00 0.00 6.80 9.40 283.60 450.80 2.8 442 1016723
+1 91 1 1 34 51 1790 216 191 0.20 0.20 25402 21911 0.00 0.00 0.00 0.00 0.00 0.80 0.80 15.60 19.40 2.0 535 1045381
+1 89 1 1 61 77 2148 166 71 0.80 1.20 138152 32010 0.60 0.60 0.40 0.00 0.20 11.40 11.40 72.00 127.00 1.0 141 1081685
+1 80 1 1 6 0 3566 280 265 1.60 4.39 284087 337511 6.19 13.17 45.51 158.68 0.00 34.13 66.87 101.60 139.72 2.2 326 1063309
+1 95 1 1 30 45 1307 98 67 0.20 0.20 4867 19027 0.00 0.00 0.00 0.00 0.00 0.60 0.80 15.63 18.44 1.5 1122 1064507
+1 73 1 1 213 15 4003 300 183 4.59 3.99 295658 95762 18.56 56.29 112.38 195.61 5.39 33.73 59.28 246.31 434.73 5.0 112 1064093
+1 73 1 1 8 0 4637 798 628 5.60 1.60 251739 62604 2.40 5.40 15.20 29.60 0.00 3.80 3.80 273.60 428.60 3.8 148 1696598
+1 97 1 1 1 1 555 55 17 0.20 0.20 267213 42374 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.37 18.36 1.6 7002 1850772
+1 96 1 1 12 11 414 167 56 0.60 2.60 281537 281447 0.00 0.00 0.00 0.00 0.00 0.00 0.00 57.00 53.60 2.6 5535 1828835
+1 91 1 1 8 8 2768 184 197 0.20 0.20 6837 380457 13.40 17.00 17.00 0.00 11.80 4.20 4.20 15.60 40.80 1.8 323 1392037
+1 80 1 1 13 6 5452 310 208 1.20 1.60 167956 44363 7.39 11.98 31.54 85.43 3.59 5.19 8.98 110.18 205.79 3.6 262 1322413
+1 96 1 1 6 5 787 61 51 0.20 0.20 3195 15728 0.00 0.00 0.00 0.00 0.00 0.60 3.20 15.60 17.00 1.2 1606 1081952
+1 84 1 1 14 6 4229 148 75 1.80 7.00 40707 8863 0.00 0.00 0.00 0.00 0.00 0.80 0.80 153.80 177.40 2.4 10833 1382525
+1 89 1 1 1 0 2370 155 81 0.80 0.80 57350 58671 0.00 0.00 0.00 0.00 0.00 0.00 0.00 60.00 69.60 1.2 500 1757933
+1 99 1 1 0 0 186 19 18 0.20 0.20 615 5652 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 1863 1781320
+1 71 1 1 13 1 4636 573 532 9.78 7.39 315909 39256 2.40 2.79 2.79 0.00 1.00 1.80 3.99 497.01 734.33 6.8 268 1437071
+1 93 1 1 1 0 2134 163 68 0.20 0.20 607320 24839 0.00 0.00 0.00 0.00 0.00 0.20 0.20 16.20 19.00 3.0 1081 1717874
+1 93 1 1 2 1 1409 53 44 0.80 2.40 11702 15503 0.00 0.00 0.00 0.00 0.00 1.60 1.60 37.80 62.00 1.4 731 1090829
+1 85 1 1 6 0 1480 70 86 5.80 16.60 37016 60141 2.80 9.00 16.60 17.80 0.20 6.40 6.80 188.00 393.40 2.0 443 1081386
+1 80 1 1 60 85 2690 281 214 0.60 0.60 444983 419165 1.80 30.20 59.80 175.60 0.60 8.20 8.80 49.80 143.40 3.6 421 1327763
+1 99 1 1 1 1 166 10 12 0.20 0.20 6990 5747 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 5264 1856536
+1 97 1 1 0 0 854 51 44 0.20 0.20 2472 14021 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 18.40 1.0 1857 1074888
+1 63 1 1 90 70 3394 357 359 2.99 2.99 524815 628705 15.37 25.35 37.33 26.15 16.57 39.92 54.49 163.07 344.11 3.2 361 1020385
+1 79 1 1 20 5 4567 393 320 3.60 5.00 240737 66407 0.00 0.00 0.00 0.00 0.00 5.20 5.20 224.00 372.80 3.6 777 972827
+1 86 1 1 627 8 1183 17 32 0.20 0.20 5068 43710 0.00 0.00 0.00 0.00 0.00 72.00 72.00 15.60 16.80 1.2 5768 1848389
+1 59 1 1 20 6 9388 631 503 9.38 9.98 409706 81338 4.39 4.79 4.79 0.00 10.38 2.59 3.39 519.56 776.05 7.0 200 1506469
+1 93 1 1 42 60 1112 87 68 0.20 0.20 80519 61557 0.00 0.00 0.00 0.00 0.00 10.00 12.20 15.40 62.00 1.3 469 979336
+1 89 1 1 1 0 1899 128 112 1.00 1.60 19624 26141 0.00 0.00 0.00 0.00 0.00 1.40 1.60 91.78 173.15 2.0 934 1096898
+1 98 1 1 2 1 209 22 15 0.20 0.20 91604 9887 0.00 0.00 0.00 0.00 0.00 0.00 0.00 22.40 17.20 1.2 8359 1866029
+1 83 1 1 4 2 672 99 127 1.40 1.60 65248 516883 60.80 130.40 162.20 85.80 0.40 0.00 0.00 67.80 118.60 3.6 250 1706224
+1 97 1 1 1 1 166 10 13 0.00 0.00 7601 43378 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.80 3.60 1.0 7065 1854920
+1 87 1 1 4 0 1511 192 185 3.60 1.20 114916 34748 0.00 0.00 0.00 0.00 0.60 0.20 0.20 190.20 262.60 1.8 2681 1771302
+1 85 1 1 3 0 3746 307 203 0.40 0.40 508095 123529 3.80 9.80 39.00 72.80 0.00 27.40 51.80 60.20 103.20 1.0 163 1058296
+1 92 1 1 6 0 1998 152 133 0.60 0.60 128710 98867 0.00 0.00 0.00 0.00 0.00 1.40 4.20 52.80 50.60 3.6 1753 1532064
+1 94 1 1 1 0 1089 103 100 0.20 0.20 8045 51111 0.00 0.00 0.00 0.00 0.00 3.21 3.61 19.44 33.07 2.2 413 1106748
+1 81 1 1 24 16 3737 332 254 3.80 2.60 290677 33078 8.60 14.20 52.20 85.20 3.60 4.20 8.40 212.60 391.80 1.5 170 981816
+1 91 1 1 31 43 1604 108 91 0.80 0.80 4370 21249 0.00 0.00 0.00 0.00 0.00 1.80 1.80 63.20 98.20 2.5 728 1096389
+1 77 1 1 7 0 1833 147 77 6.60 19.40 114842 16350 0.00 0.00 0.00 0.00 0.00 12.40 14.60 228.00 435.40 2.3 359 1104646
+1 62 1 1 15 1 5710 410 307 11.00 26.00 313576 11481 0.00 0.00 0.00 0.00 0.00 5.40 6.40 654.60 904.80 5.4 1758 1399382
+1 81 1 1 9 0 3349 342 225 3.39 4.39 241506 32980 12.97 35.13 79.84 147.11 2.59 7.98 12.57 214.77 428.54 1.0 171 973162
+1 59 1 1 44 11 4890 639 456 7.00 5.00 541547 228102 20.00 67.80 144.40 292.60 3.60 54.40 71.00 463.40 832.60 4.4 139 1032154
+1 80 1 1 19 9 3744 393 329 6.80 4.40 209666 21515 1.00 4.80 17.00 37.20 0.60 6.20 6.20 356.40 572.20 1.3 235 1073950
+1 96 1 1 1 0 220 30 20 0.20 0.20 24212 23258 0.00 0.00 0.00 0.00 0.00 1.40 1.40 16.00 18.80 1.2 1207 1765368
+1 91 1 1 0 0 297 24 31 0.20 0.20 19779 36920 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.4 1776 1766960
+1 81 1 1 3 0 3612 223 148 1.00 0.80 170093 31671 4.01 11.02 48.10 153.91 0.20 24.45 35.07 75.55 212.83 2.2 154 1005722
+1 77 1 1 42 3 3704 403 316 6.00 4.80 381160 118895 4.00 5.40 5.40 0.00 1.80 39.60 47.60 266.60 493.60 6.8 362 1316630
+1 80 1 1 19 2 2448 477 269 5.41 5.21 413929 51595 0.00 0.00 0.00 0.00 0.20 2.40 3.21 272.55 454.91 3.0 1418 1074081
+1 96 1 1 1 0 576 52 22 1.00 3.60 303082 202993 0.00 0.00 0.00 0.00 0.00 0.00 0.00 43.60 63.00 2.8 1027 1758669
+1 88 1 1 32 29 1423 173 88 2.40 3.19 235626 39853 9.98 31.94 88.82 149.50 1.80 2.59 2.79 158.88 306.79 1.6 128 991545
+1 83 1 1 1 0 5943 300 203 0.80 1.20 51713 38197 1.00 7.82 46.29 65.93 0.00 21.64 23.65 78.56 213.63 6.2 138 1024835
+1 90 1 1 0 0 2682 237 129 0.80 0.80 158917 22200 0.00 0.00 0.00 0.00 0.00 2.20 2.81 54.91 113.63 3.4 518 1021098
+1 87 1 1 5 0 2091 250 199 3.20 1.00 116897 48437 5.80 11.00 8.20 0.00 1.00 1.00 1.00 160.20 231.80 1.6 197 1750514
+1 94 1 1 3 0 858 139 160 0.80 2.00 24953 21251 0.00 0.00 0.00 0.00 0.40 15.60 16.40 40.80 101.60 1.0 369 1022384
+1 60 1 1 26 6 7952 555 470 9.20 8.80 417622 41813 4.40 4.80 4.80 0.00 5.80 1.80 2.20 513.20 714.00 6.4 259 1331227
+1 98 1 1 1 0 241 28 18 0.20 0.20 956 4955 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 17.20 2.0 6193 1724072
+1 95 1 1 1 1 681 78 50 0.60 0.60 93016 21209 0.00 0.00 0.00 0.00 0.00 0.80 0.80 31.80 55.60 1.0 2212 1073000
+1 90 1 1 1 0 1977 337 300 0.60 2.20 95597 53903 0.40 0.60 0.60 0.00 0.00 1.00 1.00 35.40 53.60 2.2 207 1696294
+1 88 1 1 9 5 3769 283 189 0.60 0.60 15260 63227 0.00 0.00 0.00 0.00 0.40 7.98 9.58 41.52 76.05 1.0 507 1128370
+1 90 1 1 9 7 1453 313 156 1.20 3.20 183445 21267 14.40 22.40 69.80 110.20 0.00 8.60 11.00 100.40 251.60 2.2 153 986941
+1 98 1 1 1 0 163 8 12 0.20 0.20 430 8682 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.57 17.17 1.0 1824 1749022
+1 94 1 1 2 0 799 32 34 0.60 0.60 29766 45886 1.20 1.60 1.60 0.00 0.20 0.00 0.00 40.00 49.40 1.4 229 1753770
+1 96 1 1 2 1 817 71 43 0.60 0.60 17994 134016 0.00 0.00 0.00 0.00 0.00 0.20 0.20 42.00 55.40 1.0 6879 1853251
+1 61 1 1 37 24 5147 558 444 10.40 7.00 399153 62552 5.20 13.20 46.60 87.60 3.60 6.20 7.60 613.40 974.60 2.0 405 1008416
+1 60 1 1 40 0 2321 177 90 9.58 26.75 628741 44636 10.78 87.62 132.34 197.80 0.80 50.70 93.61 333.53 629.14 1.4 139 1093538
+1 90 1 1 2 1 3977 286 171 0.20 0.80 286399 215557 0.00 0.00 0.00 0.00 0.00 2.60 4.40 18.00 49.80 3.2 3701 1332736
+1 83 1 1 19 3 3238 298 264 4.00 1.60 135898 24557 5.60 5.60 5.60 0.00 1.80 4.20 4.20 199.60 334.00 3.0 242 1065974
+1 97 1 1 1 1 610 46 43 0.20 0.20 10408 28520 3.00 3.40 3.00 0.00 0.60 0.20 0.20 15.60 17.60 1.0 276 1750955
+1 93 1 1 1 0 2999 158 102 0.60 0.60 19744 29690 0.00 0.00 0.00 0.00 0.00 0.60 1.20 35.20 68.80 1.0 2932 1011786
+1 97 1 1 1 0 1956 72 75 0.20 0.20 104757 19342 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.97 17.76 1.0 1264 1056591
+1 95 1 1 1 1 1642 81 48 0.40 0.40 175290 62313 0.00 0.00 0.00 0.00 0.00 0.20 0.20 23.80 35.40 1.2 8244 1839018
+1 73 1 1 7 0 4049 230 144 7.00 18.80 148937 40161 1.00 1.20 1.20 0.00 0.20 16.80 16.80 258.20 511.00 2.2 251 1086152
+1 84 1 1 25 27 3011 324 269 4.38 1.59 140574 47566 0.00 0.00 0.00 0.00 0.00 0.20 0.20 213.35 307.77 1.2 462 1057825
+1 95 1 1 0 0 2106 87 52 0.20 0.20 19292 28755 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13.00 16.80 1.0 499 1739078
+1 83 1 1 95 79 1856 228 152 3.00 3.00 133141 44174 15.20 24.60 47.40 87.60 2.00 25.60 34.80 155.80 326.40 1.0 149 977054
+1 87 1 1 8 1 1935 313 273 5.00 1.40 138248 19599 0.00 0.00 0.00 0.00 0.00 1.00 1.00 231.80 331.20 1.4 428 1742645
+1 97 1 1 2 0 369 79 43 0.40 1.00 220234 206298 0.80 0.80 6.20 7.40 0.00 2.20 3.80 31.40 60.40 3.2 178 1735726
+1 81 1 1 11 6 4938 596 711 1.80 1.00 89363 38418 1.60 1.60 1.60 0.00 2.20 2.80 2.80 118.00 201.20 1.0 336 1024986
+1 97 1 1 1 0 756 44 33 0.20 0.20 19561 13898 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.60 29.20 1.0 520 993283
+1 92 1 1 5 3 838 71 56 2.40 5.40 10837 11095 3.20 6.80 28.40 68.40 1.80 0.80 0.80 106.00 176.60 2.4 146 1720134
+1 92 1 1 3 0 2526 163 144 1.00 0.60 39034 29260 1.60 1.60 1.60 0.00 0.40 9.40 9.60 73.20 109.80 4.0 223 1054778
+1 87 1 1 6 0 2066 156 106 1.20 1.40 64065 39743 0.00 0.00 0.00 0.00 0.80 32.34 35.53 90.62 221.16 1.0 698 1089169
+1 93 1 1 4 3 3915 184 155 0.20 0.20 23675 24855 0.00 0.00 0.00 0.00 0.00 0.60 1.00 37.40 42.80 2.2 654 1382950
+1 88 1 1 3 0 2914 260 216 2.20 1.40 167240 31205 0.00 0.00 0.00 0.00 5.20 1.80 1.80 103.60 182.80 1.0 568 1014578
+1 61 1 1 99 119 6109 556 368 10.00 18.00 372732 58751 0.00 0.00 0.00 0.00 0.40 11.60 13.80 405.60 696.00 1.0 627 1096899
+1 99 1 1 0 0 132 6 7 0.20 0.20 416 1985 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.00 16.80 1.0 6643 1873435
+1 81 1 1 7 3 7036 363 221 1.80 2.40 228636 92387 0.00 0.00 0.00 0.00 0.00 17.60 19.40 157.20 308.00 3.4 1518 1389834
+1 76 1 1 24 11 4818 143 84 2.60 8.20 372082 92551 0.00 0.00 0.00 0.00 0.00 1.60 2.00 261.40 240.20 3.4 978 1541931
+1 66 1 1 32 5 5741 342 192 6.41 18.84 181237 73067 7.82 26.65 55.51 143.89 3.81 27.86 44.09 252.10 493.79 2.8 178 1104233
+1 78 1 1 13 4 1704 137 137 6.20 17.20 42806 158841 14.60 28.40 23.60 6.60 2.40 13.60 18.00 220.80 425.40 1.7 206 1103458
+1 90 1 1 32 43 1148 86 36 1.80 7.00 205838 15591 3.40 7.80 26.40 32.40 0.40 1.80 3.00 120.00 182.80 2.2 140 1754102
+1 91 1 1 2 1 2066 269 289 0.40 0.40 111975 110966 4.80 13.00 33.80 55.40 0.40 4.00 5.80 28.80 51.40 2.0 158 1093189
+1 98 1 1 0 0 264 43 30 0.20 0.20 242664 22158 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 18.20 1.2 7598 1879750
+1 87 1 1 4 0 2668 224 185 2.00 7.00 55466 68582 0.00 0.00 0.00 0.00 0.20 8.60 10.20 103.80 185.60 1.7 652 1096485
+1 71 1 1 6 0 5959 1191 1060 3.61 1.00 964823 871943 0.00 0.00 0.00 0.00 0.00 13.23 17.03 170.34 547.50 1.0 797 1062269
+1 0 1 1 6 5 1313 95 78 0.20 0.20 347551 64589 14.40 27.60 59.00 141.40 0.00 33.20 65.80 15.40 63.20 136 91 8
+1 84 1 1 49 55 1233 153 147 0.80 0.60 225042 202091 0.00 0.00 0.00 0.00 0.00 24.40 41.80 52.20 85.00 5.0 806 1599282
+1 85 1 1 17 13 4231 893 481 0.60 0.80 103959 65253 0.00 0.00 0.00 0.00 0.00 0.00 0.00 84.40 74.80 3.2 608 1540382
+1 66 1 1 43 0 2832 164 76 11.20 33.20 216920 26051 0.00 0.00 0.00 0.00 0.40 16.80 25.80 355.00 683.00 2.2 406 1106517
+1 79 1 1 33 26 4625 293 168 3.21 5.61 218398 62600 3.01 6.41 15.03 18.84 0.80 11.82 18.24 243.89 434.07 2.6 304 1025106
+1 85 1 1 1 0 3615 397 197 0.20 0.20 328830 225257 0.00 0.00 0.00 0.00 0.40 16.17 27.94 133.53 168.46 3.0 593 1006561
+1 75 1 1 17 11 1921 187 106 6.80 19.80 197311 20816 0.00 0.00 0.00 0.00 0.00 6.00 6.20 276.00 518.80 1.5 612 1099563
+1 89 1 1 1 0 2313 261 227 0.60 0.80 7620 24670 0.40 0.40 1.60 6.00 0.00 0.80 0.80 32.60 75.40 1.0 152 1014445
+1 97 1 1 0 0 788 102 48 0.20 0.20 191141 180333 0.00 0.00 0.00 0.00 0.00 2.40 4.80 15.40 18.60 3.2 449 1728448
+1 92 1 1 9 7 2592 152 92 0.80 0.80 105624 25500 0.80 1.20 1.20 0.00 0.20 0.40 0.40 53.40 129.00 1.6 361 988168
+1 91 1 1 4 3 2051 176 124 0.80 1.00 68340 50092 0.00 0.00 0.00 0.00 0.20 0.60 0.60 64.13 94.59 1.3 1205 1051819
+1 93 1 1 2 1 1932 117 122 0.60 0.60 133827 91027 0.00 0.00 0.00 0.00 0.00 0.00 0.00 113.20 57.40 2.2 544 1725482
+1 62 1 1 35 0 3593 621 124 7.62 10.22 731563 25521 11.62 84.77 281.56 596.39 1.00 30.06 47.29 549.70 1024.25 2.2 127 1058769
+1 83 1 1 16 4 1983 230 119 0.40 0.40 527573 77687 20.00 64.40 140.20 219.40 1.80 14.80 60.80 58.20 313.80 1.0 144 997109
+1 91 1 1 13 4 3499 105 74 2.00 14.20 294889 273161 0.00 0.00 0.00 0.00 0.00 6.60 11.20 105.20 148.60 4.8 2391 1564432
+1 84 1 1 1 0 1760 184 192 0.40 0.60 289863 262582 0.20 0.40 0.40 0.00 0.00 29.06 57.52 31.86 66.13 1.5 684 1044353
+1 93 1 1 42 55 959 89 69 0.20 0.20 26378 26513 0.60 1.20 0.60 0.00 0.00 2.40 4.21 17.03 40.88 2.0 341 965472
+1 84 1 1 6 0 3919 207 206 0.40 0.20 93352 273327 3.81 3.81 5.81 2.40 0.00 28.66 69.54 23.05 95.99 2.2 262 1064978
+1 89 1 1 35 39 2290 298 204 2.60 0.80 211885 161555 0.00 0.00 0.00 0.00 0.00 0.80 1.40 124.80 182.20 3.8 1964 1759938
+1 97 1 1 2 1 263 11 10 0.20 0.20 10917 3367 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 16.80 1.2 3338 1847986
+1 97 1 1 3 2 996 88 68 0.20 0.20 1718 15568 0.00 0.00 0.00 0.00 0.40 0.20 0.20 17.23 33.67 2.3 1551 1026145
+1 89 1 1 4 2 1159 104 75 0.60 0.60 13302 26359 1.20 1.20 1.20 0.00 0.40 71.80 80.20 28.00 148.60 1.0 374 1097306
+1 78 1 1 12 0 1798 111 207 2.80 3.20 116467 82644 0.00 0.00 0.00 0.00 0.00 1.60 1.60 120.80 193.60 2.4 612 1521061
+1 82 1 1 4 0 3963 396 264 1.00 1.20 303723 162298 0.00 0.00 0.00 0.00 0.40 9.00 15.20 90.80 183.20 2.2 969 1083214
+1 81 1 1 14 10 3387 211 117 3.41 21.24 167882 36052 2.81 5.41 17.64 31.46 0.80 6.61 9.02 239.48 328.06 1.5 165 1020268
+1 71 1 1 7 0 4307 301 350 4.99 4.79 113691 506583 0.00 0.00 0.00 0.00 0.00 11.18 18.16 291.62 504.19 2.2 540 1014933
+1 83 1 1 1 1 3956 433 214 0.40 0.40 218586 96722 7.00 16.60 24.80 111.60 0.60 7.00 10.20 41.80 103.60 2.0 130 1030576
+1 91 1 1 4 3 1048 241 169 0.20 0.20 144119 63045 9.20 13.20 19.40 21.80 1.60 3.00 4.00 29.20 57.80 2.0 135 984496
+1 75 1 1 16 8 3478 338 250 3.60 2.20 245418 91421 2.60 4.60 14.00 30.00 2.60 17.00 19.40 244.60 511.00 1.8 329 982115
+1 81 1 1 3 0 1889 275 175 1.20 1.40 1004117 381578 8.40 16.40 12.60 0.00 0.40 7.60 9.40 89.60 120.60 1.4 315 1020269
+1 96 1 1 11 16 317 89 35 0.20 0.20 66227 57424 0.00 0.00 0.00 0.00 0.00 6.61 12.83 15.63 16.83 1.0 6846 1857446
+1 80 1 1 10 8 2997 188 119 2.19 3.18 69317 28954 8.95 18.69 46.12 55.67 0.40 12.72 24.25 175.94 340.56 4.6 248 1004094
+1 0 1 1 53 20 1639 224 225 4.19 7.19 1072755 459032 18.16 63.67 144.11 346.71 3.19 65.27 127.35 303.39 465.87 238 73 27
+1 94 1 1 37 55 956 81 40 0.40 0.80 296870 22289 0.00 0.00 0.00 0.00 0.00 4.20 4.40 33.80 75.40 1.5 1729 1009814
+1 98 1 1 9 9 186 19 18 0.20 0.20 3472 11255 0.00 0.00 0.00 0.00 1.00 0.00 0.00 15.60 17.20 1.0 417 1757288
+1 94 1 1 4 2 635 94 70 0.40 0.40 37166 28774 0.00 0.00 0.00 0.00 0.00 11.18 11.58 43.71 78.24 2.0 847 1065635
+1 78 1 1 30 1 2329 176 111 6.60 19.00 46790 43319 5.20 5.60 5.60 0.00 0.20 5.60 7.20 232.80 428.00 2.3 228 1093566
+1 89 1 1 10 9 3884 295 136 1.40 4.60 110300 59845 0.00 0.00 0.00 0.00 0.00 0.80 1.20 107.80 122.80 6.0 2912 1600592
+1 73 1 1 15 1 3969 304 258 0.40 0.20 542851 473805 13.60 21.60 65.00 89.40 6.60 51.40 101.40 120.00 302.40 1.8 138 1007989
+1 89 1 1 23 9 3676 171 126 1.40 1.60 27496 46688 0.00 0.00 0.00 0.00 0.00 1.00 1.20 64.20 115.80 6.2 918 1313874
+1 91 1 1 0 0 403 63 56 0.20 0.20 251165 35837 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.57 16.97 1.6 1980 1763633
+1 85 1 1 18 11 2651 203 114 3.20 4.20 152264 53820 0.00 0.00 0.00 0.00 0.20 7.80 9.60 202.80 373.40 1.2 681 967776
+1 98 1 1 2 0 326 55 42 0.40 0.40 1323 6704 0.00 0.00 0.00 0.00 0.00 0.00 0.00 37.20 36.40 2.0 6353 1724304
+1 54 1 1 54 61 4814 410 180 10.20 31.20 426881 38624 8.20 60.00 136.40 280.40 1.20 7.00 10.00 348.20 795.40 1.8 141 1081010
+1 92 1 1 1 0 293 39 35 0.20 0.20 1950 4592 0.00 0.00 0.00 0.00 0.00 0.80 1.00 16.00 17.00 2.0 479 1743872
+1 87 1 1 42 56 4620 229 166 0.80 2.40 87932 14760 0.00 0.00 0.00 0.00 0.20 8.00 9.00 73.20 125.40 2.4 624 1319765
+1 96 1 1 4 1 210 13 19 0.40 1.00 9889 18407 0.00 0.00 0.00 0.00 0.00 0.00 0.00 34.80 37.40 1.0 6578 1851074
+1 92 1 1 21 13 3825 177 157 0.60 0.60 133084 145454 0.00 0.00 0.00 0.00 1.00 11.20 14.20 46.00 68.60 3.4 566 1628328
+1 92 1 1 5 2 1618 112 80 0.60 2.00 31294 30419 4.60 4.80 12.20 20.00 0.60 3.60 6.60 48.20 84.40 3.0 140 1112069
+1 58 1 1 47 1 3817 210 151 12.00 34.80 229231 34353 5.20 26.00 63.00 128.80 0.60 17.20 20.60 467.60 823.80 2.6 162 1095566
+1 97 1 1 34 43 713 38 24 0.20 0.20 5409 7962 0.00 0.00 0.00 0.00 0.00 0.20 0.20 21.20 25.60 1.2 1704 1780000
+1 95 1 1 1 1 2428 93 86 0.20 0.20 88628 23314 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 1.4 8464 1882056
+1 97 1 1 0 0 303 59 50 0.20 0.20 2072 15020 1.00 1.40 3.40 4.20 0.00 0.40 0.60 15.80 24.40 3.0 136 1711002
+1 95 1 1 19 28 328 59 40 0.20 0.80 174891 18230 0.00 0.00 0.00 0.00 0.00 20.36 39.32 21.76 29.54 1.6 2006 1759344
+1 86 1 1 23 1 1576 198 127 0.80 0.80 184039 37931 7.80 34.60 82.00 234.40 1.80 64.40 74.60 47.00 254.00 1.0 130 968042
+1 90 1 1 3 1 486 77 55 1.00 1.00 258903 184265 0.00 0.00 0.00 0.00 0.00 2.60 4.40 106.00 109.80 2.6 3842 1812214
+1 86 1 1 92 90 2612 243 170 2.60 1.60 67969 57978 0.00 0.00 0.00 0.00 0.00 1.00 1.00 130.00 224.60 3.0 688 1123032
+1 92 1 1 5 0 1492 40 33 1.20 1.20 32114 19663 0.80 0.80 0.80 0.00 0.00 5.01 6.81 102.61 115.83 1.0 153 1066347
+1 98 1 1 1 1 161 8 9 0.20 0.20 6994 6201 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7730 1882360
+1 85 1 1 14 10 3386 356 186 3.40 4.80 136801 50751 0.00 0.00 0.00 0.00 0.20 17.40 18.00 258.60 303.60 5.2 3755 1597365
+1 94 1 1 3 1 2459 127 103 0.60 0.60 26388 76015 0.00 0.00 0.00 0.00 0.00 0.00 0.00 28.20 41.60 2.4 3145 1656507
+1 86 1 1 20 17 2003 180 105 2.20 2.20 115928 48771 3.99 6.39 6.19 0.00 2.00 2.59 4.19 124.95 327.15 3.4 343 1018272
+1 0 1 1 8 6 3491 263 112 0.20 0.20 364523 28094 1.60 2.00 2.00 0.00 0.60 0.60 0.60 20.80 26.60 193 92 8
+1 96 1 1 0 0 830 41 48 0.20 0.20 1605 40024 4.60 5.80 5.80 0.00 0.00 4.40 5.40 15.00 58.20 2.0 195 1013584
+1 96 1 1 0 0 201 9 15 0.20 0.20 2103 23567 0.00 0.00 0.00 0.00 0.00 1.20 1.40 15.60 17.20 1.0 592 1752840
+1 88 1 1 6 2 1549 232 201 4.40 1.20 133566 9375 0.00 0.00 0.00 0.00 0.00 0.00 0.00 209.00 300.80 2.4 7948 1833715
+1 90 1 1 0 0 1599 132 56 0.40 1.80 61352 30538 13.80 32.40 76.60 160.20 0.00 28.00 44.80 19.60 114.00 2.8 129 992258
+1 83 1 1 4 1 4396 573 250 0.80 0.80 884924 121975 0.00 0.00 0.00 0.00 0.00 24.00 24.20 58.60 183.40 1.3 720 1081861
+1 98 1 1 0 0 199 10 18 0.20 0.20 5478 58790 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 7877 1875126
+1 88 1 1 5 2 528 49 37 3.00 2.60 152840 82964 0.00 0.00 0.00 0.00 0.00 2.80 4.20 243.60 213.60 1.4 5774 1847291
+1 78 1 1 26 10 5194 533 225 2.00 3.00 86415 135940 4.40 4.40 4.40 0.00 3.20 17.60 21.40 102.00 187.80 2.0 521 985760
+1 80 1 1 44 63 2898 201 169 2.20 2.40 159332 217054 0.00 0.00 0.00 0.00 0.00 7.40 10.20 107.40 177.80 4.4 1800 1004824
+1 87 1 1 0 0 4891 153 138 0.20 0.20 19710 94854 1.80 3.40 3.40 0.00 0.00 3.00 4.00 12.80 24.20 4.2 327 976960
+1 87 1 1 5 0 2505 349 341 1.80 0.40 208343 175584 0.00 0.00 0.00 0.00 0.20 1.60 2.20 83.03 167.07 2.2 404 1010756
+1 78 1 1 77 37 4517 636 586 2.60 2.80 197716 63560 2.40 6.20 12.60 25.40 2.20 4.00 4.80 150.60 315.20 4.6 472 1395994
+1 81 1 1 8 0 2168 374 249 5.80 2.00 758057 10001 0.00 0.00 0.00 0.00 0.00 0.00 0.00 287.80 430.00 3.6 390 1717275
+1 98 1 1 1 0 180 12 28 0.60 0.20 4049 10974 0.00 0.00 0.00 0.00 0.00 0.00 0.00 24.80 31.40 1.0 6406 1870936
+1 87 1 1 7 0 2428 211 144 1.80 1.40 151817 186467 0.00 0.00 0.00 0.00 0.00 12.20 16.20 78.40 163.00 2.4 568 1081509
+1 62 1 1 38 41 3834 195 122 11.80 33.80 102413 48962 0.20 0.20 0.20 0.00 0.00 6.60 9.40 384.20 767.40 2.5 182 1078150
+1 82 1 1 3 0 2177 213 165 3.18 2.78 90658 81272 9.94 22.47 34.59 38.17 2.98 31.41 41.75 118.29 191.25 3.0 139 1093401
+1 91 1 1 7 0 609 98 48 1.40 1.80 77701 6884 0.00 0.00 0.00 0.00 0.00 0.20 0.20 109.40 159.20 2.4 6367 1712043
+1 79 1 1 9 1 2772 465 380 7.20 1.80 527107 8114 0.00 0.00 0.00 0.00 0.00 0.00 0.00 347.00 486.60 2.4 6602 1872614
+1 86 1 1 6 3 4453 294 224 2.60 0.80 92293 49961 0.20 0.20 0.20 0.00 1.20 15.00 15.00 129.80 254.40 2.2 368 1016914
+1 95 1 1 2 0 1050 118 105 0.40 0.40 33268 34654 0.00 0.00 0.00 0.00 0.00 0.00 0.00 36.40 41.60 2.0 433 1092555
+1 93 1 1 12 9 607 50 20 2.40 3.21 37751 6467 0.00 0.00 0.00 0.00 0.20 1.80 2.20 153.11 228.66 1.4 1783 1784160
+1 81 1 1 57 67 2890 115 123 2.80 2.60 115270 75326 0.00 0.00 0.00 0.00 0.00 0.40 0.40 187.40 197.20 2.6 1345 1541262
+1 85 1 1 5 0 2053 297 504 4.00 3.00 58759 55921 0.00 0.00 0.00 0.00 0.00 3.20 4.40 173.20 270.60 3.0 733 1703618
+1 75 1 1 12 1 3007 356 300 9.80 4.60 196639 22334 0.00 0.00 0.00 0.00 0.00 0.80 0.80 446.20 731.40 3.0 1061 1068536
+1 66 1 1 24 7 5880 1236 1128 6.40 6.00 1301407 888107 0.00 0.00 0.00 0.00 0.00 21.40 25.00 296.80 512.80 1.0 721 1057133
+1 84 1 1 14 0 806 101 60 0.40 0.40 175267 8453 3.39 18.56 47.70 91.42 0.60 9.58 27.15 23.15 99.20 2.4 137 1735008
+1 91 1 1 27 31 1258 181 172 3.40 1.00 82577 7863 0.00 0.00 0.00 0.00 0.00 0.00 0.00 163.00 232.20 1.6 5292 1860475
+1 95 1 1 3 2 1178 107 79 0.40 1.80 14852 28976 2.20 3.20 3.20 0.00 1.00 0.40 0.40 20.80 80.20 1.0 236 1003650
+1 89 1 1 8 5 3428 301 156 0.40 0.40 284331 33861 0.00 0.00 0.00 0.00 0.20 12.95 18.73 28.29 105.18 1.4 539 980623
+1 86 1 1 16 4 3431 479 196 1.20 2.40 602937 571768 6.00 13.20 28.80 58.40 2.80 5.20 5.20 83.00 121.60 2.2 257 1043798
+1 94 1 1 14 8 1586 151 74 0.80 0.80 324862 253923 0.00 0.00 0.00 0.00 0.00 3.60 6.00 115.00 117.00 4.4 2632 1550600
+1 83 1 1 33 47 3278 218 180 0.20 0.20 169118 125701 0.00 0.00 0.00 0.00 0.00 13.63 21.04 33.07 44.69 4.8 1395 1050499
+1 79 1 1 16 7 6743 222 175 2.00 7.20 270921 173821 0.00 0.00 0.00 0.00 0.00 11.40 13.00 178.00 195.00 3.4 2959 1647653
+1 95 1 1 9 8 1174 103 67 0.20 0.20 7145 21507 0.00 0.00 0.00 0.00 0.00 0.20 0.20 14.80 23.00 1.0 1517 1081568
+1 62 1 1 17 1 3603 148 123 13.37 35.53 63275 32649 0.60 0.80 0.80 0.00 0.40 1.40 1.40 478.64 880.04 1.0 263 1076239
+1 93 1 1 33 44 905 96 83 0.20 0.20 19351 18112 0.40 0.60 0.60 0.00 0.00 7.21 8.02 27.86 44.89 1.5 308 1015077
+1 93 1 1 1 0 1939 118 80 0.40 0.20 136082 10325 0.00 0.00 0.00 0.00 0.00 0.40 0.60 33.20 38.20 1.0 705 1731995
+1 69 1 1 10 2 3359 493 129 7.20 19.60 676642 75031 5.40 9.00 7.20 0.00 1.40 10.40 11.60 304.20 498.80 2.5 228 1103565
+1 87 1 1 6 0 1146 99 53 2.80 5.20 216282 21654 0.00 0.00 0.00 0.00 0.40 10.80 16.60 196.00 292.40 1.6 911 1065722
+1 97 1 1 0 0 180 16 21 0.20 0.20 32785 24624 0.00 0.00 0.00 0.00 0.00 3.40 6.60 15.40 19.20 1.0 5323 1859947
+1 81 1 1 7 3 4580 458 378 2.20 0.80 196516 130871 7.20 14.00 28.80 26.40 1.40 2.20 2.20 124.00 209.00 1.5 189 1091019
+1 88 1 1 95 53 2002 194 198 1.60 2.79 282367 160351 5.19 14.57 19.16 13.57 15.57 13.97 26.75 111.38 187.03 4.4 403 1538564
+1 86 1 1 34 41 1784 320 138 1.80 2.40 178145 28247 0.00 0.00 0.00 0.00 0.00 27.05 31.26 134.27 302.00 3.8 676 1066519
+1 80 1 1 2 0 4798 316 251 2.00 0.80 72190 187115 4.40 7.20 51.00 75.20 0.00 3.40 3.40 131.00 276.60 4.8 121 1018835
+1 89 1 1 13 2 2145 107 85 1.40 4.20 169926 26644 2.80 3.60 3.60 0.00 0.60 13.00 25.20 73.00 191.40 5.2 352 1520968
+1 95 1 1 28 40 1361 200 86 0.20 0.20 166067 159270 0.00 0.00 0.00 0.00 0.00 0.20 0.20 16.00 17.80 4.6 2548 1577029
+1 90 1 1 5 2 1638 95 108 0.20 0.20 250446 75823 1.20 7.20 12.40 22.20 1.40 31.60 32.60 20.20 150.60 4.7 216 1046744
+1 71 1 1 39 25 3065 301 157 9.80 8.40 336047 128920 9.40 30.00 47.20 86.60 5.20 10.80 22.20 397.40 767.00 3.6 263 1040093
+1 86 1 1 25 15 1568 137 79 4.19 4.99 178748 55975 2.40 2.79 2.79 0.00 1.80 11.18 16.17 229.94 368.26 2.2 265 1057790
+1 68 1 1 23 4 3769 296 176 5.60 9.80 505747 46865 17.20 68.40 113.60 191.00 5.40 47.60 64.60 317.60 637.40 1.3 154 1005171
+1 85 1 1 21 1 3154 167 145 11.40 3.80 166556 83679 0.20 0.40 0.40 0.00 0.00 4.60 5.40 243.60 459.60 2.4 406 1716117
+1 87 1 1 13 12 1683 218 125 1.00 3.60 1328599 1260805 0.00 0.00 0.00 0.00 0.60 9.80 12.00 46.80 110.00 2.0 388 1015101
+1 91 1 1 2 0 916 125 82 2.00 1.00 345868 252498 0.00 0.00 0.00 0.00 0.00 2.00 3.79 104.79 153.89 2.8 1062 1756469
+1 94 1 1 8 1 2549 129 107 1.60 1.80 6665 50010 0.00 0.00 0.00 0.00 0.00 1.20 1.20 74.00 109.40 2.0 1224 1636050
+1 89 1 1 2 1 2818 186 177 0.20 0.20 256228 245958 0.40 0.60 0.60 0.00 5.40 0.20 0.20 15.80 20.40 2.4 227 1519582
+1 89 1 1 14 4 2210 181 144 1.20 1.00 290899 53735 4.00 4.40 5.00 3.20 7.60 22.60 22.80 61.80 148.80 3.5 204 1018000
+1 87 1 1 40 23 2008 143 99 3.40 8.60 80598 29954 0.00 0.00 0.00 0.00 0.20 19.40 19.80 238.20 407.00 4.4 10935 1383370
+1 91 1 1 20 29 3350 221 206 0.20 0.20 37797 100198 1.20 1.20 1.20 0.00 0.40 9.40 10.00 12.80 63.40 1.0 346 1069827
+1 95 1 1 1 0 919 294 128 0.20 0.20 43726 48934 6.20 11.60 8.00 0.00 0.20 7.80 7.80 15.40 48.60 2.4 252 1707578
+1 92 1 1 0 0 2416 133 90 0.20 0.20 71249 55485 3.00 4.00 4.00 0.00 1.00 2.60 3.00 16.00 20.00 1.2 262 1127160
+1 90 1 1 15 4 1535 91 79 1.40 3.60 81085 23764 0.00 0.00 0.00 0.00 0.00 11.80 16.80 105.40 188.00 1.8 1561 970909
+1 94 1 1 2 0 1225 134 118 0.40 0.40 5809 34227 1.80 2.80 2.00 0.00 0.00 6.20 6.60 33.80 108.40 1.0 344 1016576
+1 85 1 1 6 4 3077 912 77 1.80 1.80 276247 41108 6.19 30.54 68.26 135.33 0.20 31.54 62.48 112.57 186.03 3.0 126 1125610
+1 85 1 1 43 51 3645 150 101 2.20 1.80 281255 69111 0.00 0.00 0.00 0.00 0.00 0.20 0.20 161.80 177.00 3.0 708 1528086
+1 77 1 1 39 58 2693 153 179 0.40 0.60 384247 406989 18.00 71.60 171.60 273.80 8.80 71.20 119.40 32.60 109.80 1.0 168 1129622
+1 95 1 1 0 0 1108 87 48 0.60 0.60 199489 36309 0.00 0.00 0.00 0.00 0.00 1.60 1.60 72.00 100.60 1.4 462 989240
+1 76 1 1 38 27 3718 162 98 2.80 7.40 241103 140723 0.00 0.00 0.00 0.00 1.20 8.20 13.40 171.00 413.40 5.6 776 1321907
+1 97 1 1 7 0 273 62 32 0.20 0.20 115125 10672 0.00 0.00 0.00 0.00 0.00 25.25 46.09 15.83 64.73 1.4 1653 1774815
+1 95 1 1 1 1 764 96 49 0.20 0.20 241669 21943 0.00 0.00 0.00 0.00 0.00 1.60 2.61 16.03 22.85 2.5 539 1038814
+1 95 1 1 14 13 2116 122 147 0.40 0.20 19106 226484 0.00 0.00 0.00 0.00 0.00 0.40 0.40 21.20 31.40 2.0 477 1523474
+1 93 1 1 3 0 1285 128 57 2.40 2.40 259420 139590 0.00 0.00 0.00 0.00 0.00 2.20 4.40 97.40 153.60 3.6 1979 1764050
+1 81 1 1 20 10 2543 200 181 2.40 4.41 91285 165013 4.01 14.03 49.50 65.73 0.60 1.60 2.20 200.60 343.69 1.7 295 1060851
+1 98 1 1 1 0 262 15 13 0.20 0.20 1020 4421 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 16.80 2.0 4587 1731637
+1 81 1 1 10 5 1301 54 76 1.20 0.80 476209 489895 0.00 0.00 0.00 0.00 0.00 57.20 115.40 85.00 194.00 2.6 1605 1534619
+1 92 1 1 18 28 1214 41 36 0.40 0.60 35060 22650 0.00 0.00 0.00 0.00 0.00 0.80 1.40 29.80 41.00 1.0 698 1069582
+1 92 1 1 88 121 3171 171 111 0.60 0.60 107282 77941 2.60 4.20 4.20 0.00 0.20 1.20 1.20 43.80 109.00 6.2 300 1309459
+1 80 1 1 50 56 3278 340 304 3.39 1.20 177583 55518 0.00 0.00 0.00 0.00 0.40 33.33 63.47 180.64 330.54 2.8 4717 1710033
+1 84 1 1 29 39 452 62 44 1.80 1.80 66490 41917 0.00 0.00 0.00 0.00 0.00 3.40 3.40 171.60 145.00 1.8 399 1801952
+1 90 1 1 10 4 1519 118 68 1.40 2.00 419241 196810 2.00 17.20 44.60 73.40 0.20 29.20 57.20 74.40 122.00 4.0 229 1538755
+1 65 1 1 29 2 4586 526 491 11.58 7.78 342195 266494 0.00 0.00 0.00 0.00 0.00 12.38 13.37 485.03 873.85 2.0 1309 1032302
+1 86 1 1 32 14 3547 382 358 2.00 2.61 241903 217797 0.00 0.00 0.00 0.00 0.00 0.80 1.00 124.25 179.16 1.0 1016 1084180
+1 69 1 1 20 2 3353 507 209 5.45 5.45 235910 44191 9.34 53.11 119.65 190.08 0.00 26.26 43.77 334.63 634.05 3.0 173 1001418
+1 88 1 1 38 48 3077 321 197 0.80 1.60 314835 136734 0.00 0.00 0.00 0.00 0.00 0.80 1.20 110.20 79.80 5.4 2886 1545778
+1 93 1 1 5 1 2351 181 104 0.80 1.20 198544 190501 1.60 4.20 4.20 0.00 0.20 0.60 0.60 73.80 125.00 4.4 229 1323051
+1 78 1 1 9 5 4405 322 169 5.01 5.81 372177 85671 0.00 0.00 0.00 0.00 0.00 15.63 19.24 165.93 480.16 1.3 981 984762
+1 70 1 1 15 4 4585 614 551 7.20 5.20 537884 324709 5.40 14.60 31.80 64.80 1.20 3.40 4.40 379.60 628.40 3.3 185 1005782
+1 92 1 1 13 4 1109 134 104 0.40 0.40 573439 103146 0.00 0.00 0.00 0.00 0.00 10.22 18.04 35.47 88.38 1.0 766 1078288
+1 86 1 1 19 14 3611 152 112 0.60 0.60 182337 50411 0.00 0.00 0.00 0.00 0.00 3.79 3.79 54.49 106.19 1.2 1070 1012917
+1 88 1 1 5 4 2013 147 223 0.60 0.60 10939 521717 0.00 0.00 0.00 0.00 0.00 1.00 1.00 42.40 55.60 1.2 684 1032240
+1 83 1 1 10 6 4041 116 99 1.80 7.00 126815 119643 4.60 5.40 5.40 0.00 3.60 1.40 1.60 182.40 181.40 2.6 211 1526616
+1 80 1 1 98 126 4032 143 79 1.80 2.40 464450 40608 0.00 0.00 0.00 0.00 0.00 6.20 8.00 153.20 259.40 6.0 7804 1371829
+1 89 1 1 3 2 2268 501 240 0.60 1.60 465230 58127 0.00 0.00 0.00 0.00 0.00 3.40 3.40 28.20 82.00 1.2 2900 1051288
+1 88 1 1 20 18 3442 453 196 0.60 2.20 459002 462125 2.20 2.40 2.40 0.00 1.00 16.20 16.40 43.40 112.80 1.2 205 1043048
+1 93 1 1 1 1 395 160 72 0.20 0.20 223067 235328 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.4 4016 1827064
+1 94 1 1 3 0 1209 147 105 1.00 0.40 21270 19479 2.80 4.00 4.00 0.00 0.00 1.20 1.20 53.80 114.40 1.5 318 1001574
+1 89 1 1 15 13 1900 275 127 0.80 1.20 390344 33013 0.80 6.20 20.40 37.80 13.60 16.60 17.20 53.00 97.60 1.2 132 1085112
+1 84 1 1 18 1 4125 325 290 3.39 3.19 209255 203019 0.00 0.00 0.00 0.00 0.00 1.80 2.59 251.10 333.73 2.8 3409 1652576
+1 89 1 1 2 1 1770 223 661 0.40 0.40 28321 79451 0.00 0.00 0.00 0.00 0.00 0.00 0.00 30.00 53.80 2.2 3011 1743214
+1 85 1 1 6 1 5341 234 216 0.80 2.60 286651 231266 7.80 9.80 9.80 0.00 5.80 4.80 5.80 34.20 69.20 1.4 308 1053389
+1 0 1 1 60 78 1839 203 129 0.80 1.20 603041 462290 0.00 0.00 0.00 0.00 0.40 102.20 152.71 128.86 370.34 2823 77 23
+1 74 1 1 11 3 5178 216 154 7.40 18.80 41410 36739 0.00 0.00 0.00 0.00 0.00 7.40 8.00 285.60 475.20 3.0 372 1100992
+1 95 1 1 1 0 1299 43 61 0.20 0.20 5834 41561 0.20 0.20 0.20 0.00 0.20 0.20 0.20 15.83 18.04 2.0 165 1058397
+1 97 1 1 1 1 326 25 66 0.20 0.20 4291 72522 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.57 21.36 1.0 492 1727034
+1 81 1 1 11 1 4377 151 157 2.40 2.60 143728 165257 4.00 46.80 208.40 525.00 0.20 2.40 3.40 161.60 259.80 4.4 623 1622459
+1 97 1 1 0 0 946 67 43 0.20 0.20 121879 14862 0.00 0.00 0.00 0.00 0.00 1.00 1.00 15.60 113.40 2.3 766 1032696
+1 82 1 1 1 0 3759 473 222 0.80 2.60 225559 19037 2.80 20.20 51.20 79.20 0.20 13.20 22.40 38.80 98.40 2.0 137 1102133
+1 88 1 1 187 25 4331 333 284 1.20 2.80 235764 188657 0.20 2.80 2.80 0.00 0.20 26.40 36.80 57.40 162.60 3.0 2364 1345203
+1 84 1 1 21 13 5708 478 299 0.40 0.40 359552 60994 14.20 31.20 48.00 110.00 1.40 15.40 43.20 49.60 189.80 1.7 478 1001208
+1 87 1 1 3 1 428 47 13 2.40 2.40 114325 23268 0.00 0.00 0.00 0.00 0.00 3.61 6.01 215.63 195.59 1.0 11591 1886331
+1 74 1 1 6 0 4720 457 329 3.60 3.60 161074 181366 8.60 22.40 31.40 27.80 1.80 49.80 52.60 177.40 439.00 1.7 198 1120477
+1 92 1 1 0 0 1002 51 60 0.20 0.20 13574 49364 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 17.96 1.8 1013 1758144
+1 90 1 1 1 0 527 42 44 1.60 1.60 120751 85707 0.00 0.00 0.00 0.00 0.00 3.60 6.60 147.00 126.80 2.0 6485 1853040
+1 84 1 1 31 28 3930 194 169 2.20 3.00 118913 168930 1.60 1.60 1.60 0.00 0.20 6.60 9.40 138.00 323.00 1.5 349 989998
+1 95 1 1 1 1 212 21 26 0.20 0.20 70143 40111 0.00 0.00 0.00 0.00 0.00 7.00 13.60 15.60 22.00 1.0 6223 1857336
+1 94 1 1 6 1 2099 143 114 0.80 0.80 68384 88662 0.00 0.00 0.00 0.00 0.00 1.60 2.00 107.80 69.60 2.4 2037 1546490
+1 80 1 1 8 1 1845 203 174 7.80 4.20 209312 137191 0.00 0.00 0.00 0.00 0.00 1.20 1.20 381.00 565.00 2.8 6634 1848373
+1 92 1 1 1 1 1075 146 59 0.40 0.40 441386 64385 5.99 16.77 25.55 36.13 3.59 2.59 4.59 29.34 160.08 1.0 159 1023106
+1 83 1 1 7 2 3782 317 333 4.20 1.60 159752 65501 0.00 0.00 0.00 0.00 0.20 0.40 0.80 207.80 292.20 2.8 4616 1720686
+1 92 1 1 3 0 1192 134 183 0.60 2.20 120758 22028 1.00 4.20 21.60 45.00 0.40 15.80 18.00 49.80 103.80 1.7 140 1057594
+1 84 1 1 3 0 1354 152 100 2.00 4.81 403622 26061 0.80 0.80 0.80 0.00 0.20 24.25 36.67 177.15 342.28 1.8 392 1067513
+1 94 1 1 3 0 493 72 55 0.60 0.80 29548 12598 4.00 4.60 4.60 0.00 0.40 6.60 7.00 39.60 59.00 3.2 325 1701342
+1 81 1 1 48 46 2516 361 382 1.40 1.60 41113 68007 0.00 0.00 0.00 0.00 0.80 9.80 18.00 108.40 317.40 1.0 735 986773
+1 76 1 1 9 0 4033 556 517 5.00 3.20 380106 244752 7.00 7.60 12.00 12.40 0.60 5.80 6.00 252.00 466.40 2.6 224 1074147
+1 79 1 1 3 0 6648 907 556 2.00 0.60 238227 287122 2.99 5.39 5.39 0.00 0.40 5.99 6.19 273.05 197.80 3.2 190 1007257
+1 77 1 1 22 14 6101 320 204 1.00 1.80 181939 49527 6.00 17.00 40.80 76.60 4.80 16.00 46.40 137.60 284.80 1.8 274 987613
+1 91 1 1 5 1 1922 253 142 0.60 0.80 13307 25394 0.00 0.00 0.00 0.00 0.00 0.60 0.60 51.30 67.27 2.0 1491 965857
+1 75 1 1 6 1 5646 966 814 4.60 1.40 139644 30990 0.00 0.00 0.00 0.00 0.00 0.00 0.00 219.40 320.00 2.8 864 1721136
+1 96 1 1 17 22 254 24 44 0.20 0.20 7140 28377 0.00 0.00 0.00 0.00 0.00 0.00 0.00 19.96 16.77 1.0 7465 1865982
+1 97 1 1 0 0 299 21 28 0.20 0.20 880 17742 0.40 0.40 0.40 0.00 0.20 0.00 0.00 15.40 16.80 1.2 263 1750872
+1 94 1 1 1 1 593 159 92 1.00 4.59 120581 81233 0.00 0.00 0.00 0.00 0.00 6.79 12.97 30.94 71.26 3.8 351 1734211
+1 97 1 1 0 0 155 10 23 0.20 0.20 452 31807 0.00 0.00 0.00 0.00 0.00 0.80 1.20 15.60 17.20 1.0 1345 1761811
+1 0 1 1 14 5 1238 77 61 0.20 0.20 107535 56627 0.00 0.00 0.00 0.00 0.40 9.02 14.03 16.23 23.45 370 95 5
+1 90 1 1 3 1 1581 232 175 0.40 1.80 108075 127030 14.43 28.46 27.86 0.00 0.40 1.20 1.20 50.10 96.99 2.0 414 1019966
+1 73 1 1 36 24 4583 671 262 2.80 3.20 248855 155439 0.00 0.00 0.00 0.00 0.00 0.60 1.00 245.40 458.00 4.2 914 1641515
+1 89 1 1 9 3 1611 279 141 1.20 2.00 33847 22830 3.40 4.00 11.40 21.80 1.60 19.40 20.00 65.20 227.80 1.5 238 977387
+1 89 1 1 28 33 2183 348 285 2.20 0.80 199473 29083 0.00 0.00 0.00 0.00 0.00 1.40 1.60 136.40 222.20 2.4 969 973827
+1 97 1 1 1 0 278 35 28 0.20 0.20 32016 17965 6.40 8.20 8.20 0.00 5.80 0.00 0.00 20.60 21.00 2.2 305 1716877
+1 95 1 1 0 0 408 170 58 0.20 0.20 278728 227876 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 17.40 2.0 1717 1759920
+1 88 1 1 0 0 327 44 44 0.20 0.20 187661 39582 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.77 16.77 1.6 2025 1763776
+1 80 1 1 17 10 2072 361 203 3.20 9.00 863910 370839 0.00 0.00 0.00 0.00 1.60 57.80 63.20 129.60 388.60 4.0 712 1037512
+1 92 1 1 11 5 1416 172 108 2.40 0.80 52119 9732 0.00 0.00 0.00 0.00 0.00 0.00 0.00 125.80 175.00 3.4 6084 1723587
+1 96 1 1 1 1 242 35 34 0.20 0.20 9342 13762 0.00 0.00 0.00 0.00 0.20 0.00 0.00 15.60 16.80 1.0 633 1752147
+1 98 1 1 0 0 128 8 11 0.20 0.20 430 8983 0.00 0.00 0.00 0.00 0.00 0.60 0.80 15.77 17.17 1.0 606 1729525
+1 72 1 1 29 13 6425 136 104 3.78 10.76 93046 74742 0.00 0.00 0.00 0.00 0.00 0.40 0.40 280.68 383.86 4.2 2106 1628714
+1 83 1 1 45 53 3136 576 317 3.20 1.80 182297 60670 0.00 0.00 0.00 0.00 1.20 0.80 0.80 192.40 324.20 3.6 3069 1546811
+1 91 1 1 1 0 1914 154 307 0.60 2.20 50582 26076 0.40 0.60 0.60 0.00 0.00 7.78 8.18 109.78 84.03 1.6 238 1064963
+1 92 1 1 41 56 1263 187 251 0.40 2.00 22737 139621 0.00 0.00 0.00 0.00 0.00 2.20 3.79 46.71 59.88 2.0 1223 1542449
+1 0 1 1 9 5 2947 243 148 1.20 2.40 208635 32396 0.00 0.00 0.00 0.00 0.60 14.97 15.37 52.89 128.34 1106 90 9
+1 78 1 1 8 3 3502 574 195 3.40 6.60 1322699 41747 13.80 26.40 51.40 108.00 10.80 5.20 6.60 266.80 409.00 2.8 146 1095131
+1 81 1 1 5 0 2576 340 209 3.00 1.40 453313 22792 0.00 0.00 0.00 0.00 0.00 15.20 28.20 161.20 251.20 3.2 2440 1763877
+1 86 1 1 126 123 5600 350 224 0.40 0.60 290128 233814 0.00 0.00 0.00 0.00 0.00 2.99 14.97 32.34 107.78 3.6 1429 1323393
+1 87 1 1 58 84 2633 150 135 1.00 1.00 50178 113357 0.00 0.00 0.00 0.00 0.00 11.40 13.60 71.60 108.00 1.5 668 1055989
+1 87 1 1 23 30 1036 65 35 3.60 8.20 147215 29783 0.00 0.00 0.00 0.00 0.00 4.00 6.60 290.40 320.40 1.8 8581 1834046
+1 93 1 1 3 2 1452 118 129 0.20 0.20 54165 25934 0.00 0.00 0.00 0.00 0.00 9.40 10.40 16.40 42.60 1.6 446 1060850
+1 87 1 1 3 1 1013 86 77 0.60 2.20 235054 30659 0.00 0.00 0.00 0.00 0.00 14.37 27.54 67.86 293.21 2.0 1109 1060136
+1 95 1 1 3 0 1391 56 37 0.60 0.60 91372 17434 0.00 0.00 0.00 0.00 0.60 0.20 0.20 49.70 74.65 1.5 1600 1022271
+1 97 1 1 0 0 329 51 48 0.20 0.20 2236 13291 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.77 17.17 1.0 426 1723010
+1 81 1 1 29 30 2678 222 206 6.20 2.40 141104 28803 0.00 0.00 0.00 0.00 0.00 13.80 14.20 279.20 465.00 3.2 814 1719293
+1 79 1 1 8 1 2917 441 394 7.00 2.20 208791 26249 0.60 0.60 0.60 0.00 0.20 0.00 0.00 333.60 481.80 1.6 236 1744536
+1 61 1 1 22 13 6880 491 395 7.00 12.80 215557 98816 4.40 15.40 23.80 23.60 0.00 7.60 15.00 316.40 572.60 1.8 159 1091131
+1 98 1 1 0 0 246 21 23 0.20 0.20 1143 34969 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.80 2.0 720 1722043
+1 94 1 1 1 0 845 63 56 0.60 0.80 13187 19673 0.00 0.00 0.00 0.00 0.00 0.40 0.40 44.40 99.60 1.0 671 1033102
+1 93 1 1 6 5 1765 76 84 0.20 0.20 43538 29070 3.60 8.60 21.80 34.20 1.40 1.80 3.20 18.00 57.40 1.0 133 1060421
+1 81 1 1 34 17 2758 241 156 3.39 4.39 106233 27403 0.00 0.00 0.00 0.00 0.00 3.59 4.19 212.57 381.64 1.6 1816 966362
+1 76 1 1 16 3 5028 440 343 5.40 1.60 235095 24289 0.00 0.00 0.00 0.00 0.00 3.00 3.20 430.00 484.60 2.6 2470 974229
+1 86 1 1 2 0 362 30 34 1.60 1.60 44893 35162 0.00 0.00 0.00 0.00 0.00 1.40 2.40 126.15 122.75 1.4 2467 1817001
+1 77 1 1 7 0 1846 103 62 6.40 24.60 269233 20339 5.40 5.80 5.80 0.00 0.40 2.00 2.20 224.60 413.60 1.3 238 1088765
+1 96 1 1 2 1 888 52 59 0.20 0.20 237283 288087 0.00 0.00 0.00 0.00 0.00 5.19 5.19 13.97 23.35 2.0 4355 1818307
+1 82 1 1 19 5 3409 160 130 1.20 1.59 329382 209971 7.57 17.53 41.63 78.09 4.58 6.77 11.75 143.23 201.99 4.2 156 1516041
+1 58 1 1 46 0 4677 212 131 11.40 34.20 441971 35914 5.60 39.20 57.40 98.60 1.80 45.40 73.60 399.60 779.60 2.8 211 1107467
+1 92 1 1 16 11 1317 70 80 0.60 2.00 53127 106100 0.00 0.00 0.00 0.00 0.00 19.20 21.20 53.40 136.80 1.3 1090 1007282
+1 80 1 1 4 0 2226 300 250 4.20 1.20 203984 22500 0.00 0.00 0.00 0.00 0.00 0.40 0.40 197.00 289.80 2.8 645 1758651
+1 94 1 1 1 1 1286 50 54 0.20 0.20 4851 31814 0.40 0.40 0.40 0.00 1.60 0.20 0.40 15.40 17.00 1.0 168 1750936
+1 96 1 1 17 17 1832 199 74 0.40 0.40 254770 220716 0.00 0.00 0.00 0.00 0.00 0.00 0.00 35.00 48.00 4.4 2514 1604200
+1 95 1 1 1 0 433 72 108 0.20 0.20 41766 51175 2.60 5.20 3.80 0.00 0.00 0.80 0.80 23.80 22.80 3.0 511 1715755
+1 67 1 1 53 69 7365 1077 636 3.60 1.80 71374 162978 0.00 0.00 0.00 0.00 0.00 1.60 1.60 167.60 288.40 2.4 567 1011078
+1 94 1 1 1 0 841 49 52 0.80 1.40 2567 27968 0.00 0.00 0.00 0.00 0.00 0.00 0.00 67.20 71.80 1.0 7750 1879542
+1 89 1 1 5 0 1739 225 194 4.20 1.40 137766 8145 0.00 0.00 0.00 0.00 0.00 0.20 0.40 211.80 308.00 1.2 7278 1875016
+1 92 1 1 4 1 2143 125 85 0.80 1.80 194743 48969 0.00 0.00 0.00 0.00 0.00 0.40 0.40 65.80 86.40 2.6 3062 1655947
+1 97 1 1 0 0 360 126 47 0.40 0.40 150266 151116 0.00 0.00 0.00 0.00 0.00 0.00 0.00 25.00 32.20 3.0 1817 1759117
+1 97 1 1 1 1 377 57 20 0.40 0.40 341112 44148 0.00 0.00 0.00 0.00 0.00 0.00 0.00 34.87 34.27 1.8 7041 1858289
+1 94 1 1 21 26 751 41 75 1.20 1.40 28239 10848 0.00 0.00 0.00 0.00 0.00 0.00 0.00 81.20 105.00 1.2 7717 1871694
+1 96 1 1 1 0 746 115 86 0.20 0.20 7705 17882 0.00 0.00 0.00 0.00 0.00 1.60 1.80 15.57 16.77 1.0 381 1739376
+1 97 1 1 0 0 193 44 22 0.20 0.20 301404 256088 0.00 0.00 0.00 0.00 0.00 2.60 5.00 15.60 18.80 2.2 3652 1819909
+1 79 1 1 16 11 4393 810 380 1.19 0.99 495757 300434 0.00 0.00 0.00 0.00 0.60 36.78 42.94 68.99 250.89 1.0 433 987322
+1 76 1 1 12 2 2357 113 96 6.99 20.16 55137 36291 0.00 0.00 0.00 0.00 0.00 8.38 12.18 231.14 423.35 1.7 530 1077027
+1 90 1 1 4 0 2107 142 86 0.80 3.80 35105 26504 1.20 2.00 10.20 14.80 0.00 1.40 4.60 43.80 67.20 3.2 161 1107042
+1 75 1 1 9 0 3319 507 432 8.78 2.40 423006 26076 0.00 0.00 0.00 0.00 0.80 1.00 1.00 430.34 625.15 3.6 1526 1773533
+1 87 1 1 1 0 2456 158 111 0.60 1.60 192118 128268 9.02 25.25 58.92 160.92 0.00 17.23 31.46 48.90 83.37 7.0 137 1022636
+1 89 1 1 3 2 2257 356 161 1.00 1.00 153753 162182 0.00 0.00 0.00 0.00 0.00 1.20 1.40 72.00 90.20 3.2 2656 1578555
+1 89 1 1 40 34 4017 219 151 1.40 4.40 471335 293032 0.00 0.00 0.00 0.00 0.00 3.20 8.40 93.80 249.00 4.6 1505 1323968
+1 0 1 1 7 5 1021 141 101 0.20 0.20 69214 35381 2.20 2.20 2.60 0.80 0.40 1.60 2.00 29.60 58.40 291 94 6
+1 84 1 1 1 1 630 104 65 0.20 0.20 224349 176457 33.80 59.60 89.80 105.40 13.40 36.40 58.20 16.20 59.40 2.6 133 1715848
+1 70 1 1 26 0 4202 587 204 4.39 5.79 415447 130177 16.17 50.50 182.24 364.07 0.40 25.55 42.51 313.77 647.50 1.8 138 1055066
+1 95 1 1 5 4 386 77 76 0.20 0.20 23370 32312 2.40 4.80 3.20 0.00 0.00 0.00 0.00 20.80 17.00 2.0 387 1708888
+1 87 1 1 72 35 3623 252 166 0.40 0.40 228362 86602 2.40 3.80 9.00 12.40 2.20 7.00 10.60 41.40 84.20 1.0 422 978666
+1 96 1 1 21 31 648 46 39 0.20 0.20 86065 16965 0.00 0.00 0.00 0.00 0.00 0.20 0.40 21.24 17.84 1.0 913 1746004
+1 95 1 1 1 0 1109 77 96 0.20 0.20 30972 91009 0.00 0.00 0.00 0.00 0.00 3.60 6.00 16.60 36.80 1.2 403 1074365
+1 94 1 1 0 0 1327 62 68 0.20 0.20 69648 264439 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 6924 1879024
+1 96 1 1 0 0 592 56 36 0.20 0.20 1371 6333 0.00 0.00 0.00 0.00 0.00 0.20 0.39 16.02 16.80 1.0 1343 1705852
+1 98 1 1 2 1 209 9 16 0.20 0.20 7026 12841 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7546 1878304
+1 71 1 1 4 0 3708 427 350 3.39 1.00 543727 727869 81.44 168.06 195.81 83.23 0.80 11.38 11.58 156.69 299.80 1.6 127 1009038
+1 97 1 1 0 0 308 10 15 0.20 0.20 13642 34486 3.60 6.80 6.80 0.00 3.20 0.00 0.00 15.20 16.80 2.0 178 1760056
+1 92 1 1 7 4 1380 81 110 0.60 0.60 37010 34884 0.00 0.00 0.00 0.00 0.20 5.40 6.20 171.40 163.80 4.0 987 1336469
+1 85 1 1 17 4 2191 247 188 2.40 4.20 175850 56681 7.80 13.00 16.00 9.20 5.40 5.60 11.20 319.00 311.40 2.0 253 1006234
+1 92 1 1 18 26 2469 249 138 0.20 0.20 95921 47034 0.00 0.00 0.00 0.00 0.00 1.00 1.00 15.80 76.40 3.0 979 1084157
+1 84 1 1 7 6 1144 176 107 0.80 2.20 139134 20153 34.47 76.35 157.92 306.81 0.60 83.57 158.72 43.29 289.58 1.6 124 944686
+1 79 1 1 97 87 5807 346 206 2.40 2.80 380237 202112 0.00 0.00 0.00 0.00 0.00 7.40 17.00 200.80 261.60 4.0 836 1336240
+1 94 1 1 0 0 1076 71 140 0.60 0.40 71539 48756 1.80 15.60 47.60 78.40 0.40 15.00 20.00 31.00 61.80 3.2 135 1443416
+1 94 1 1 1 1 2357 51 70 0.20 0.20 48094 82282 0.00 0.00 0.00 0.00 0.00 0.40 0.80 15.60 17.20 1.6 8276 1839155
+1 93 1 1 24 34 3712 118 92 0.20 0.20 102973 25526 0.20 0.40 0.40 0.00 0.00 1.80 1.80 17.60 20.00 1.6 334 1752571
+1 75 1 1 6 1 5386 561 303 4.60 2.20 374135 166222 0.60 0.60 0.60 0.00 0.40 2.60 2.80 343.40 397.00 1.0 234 1116590
+1 92 1 1 2 0 2840 195 149 0.40 0.40 58645 151856 0.00 0.00 0.00 0.00 0.40 7.80 10.60 38.80 51.40 2.6 506 1544602
+1 87 1 1 136 172 2730 272 218 2.40 0.80 115066 41164 0.00 0.00 0.00 0.00 0.20 2.60 2.60 122.20 238.00 5.2 2871 1378723
+1 92 1 1 1 0 2034 137 112 0.20 0.20 84566 105634 0.00 0.00 0.00 0.00 0.00 1.60 2.00 15.80 96.60 2.5 1663 1105595
+1 82 1 1 54 21 3709 243 140 4.60 5.40 265286 116407 0.00 0.00 0.00 0.00 0.00 4.20 6.40 285.60 428.40 5.6 2836 1565138
+1 87 1 1 2 0 430 41 37 1.80 2.40 46701 30907 0.20 0.20 0.20 0.00 0.00 1.20 2.00 137.20 141.20 1.4 388 1813072
+1 76 1 1 77 86 4335 507 326 4.60 2.20 113343 43362 0.00 0.00 0.00 0.00 0.00 13.60 18.20 240.80 378.00 1.8 2555 974474
+1 98 1 1 0 0 221 28 25 0.20 0.20 132148 12550 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 17.80 1.2 5264 1858165
+1 95 1 1 2 0 322 37 30 0.80 1.20 51712 26236 2.80 3.40 3.40 0.00 0.40 0.60 0.60 64.00 67.20 1.0 492 1762806
+1 84 1 1 9 6 3915 169 121 3.00 3.40 170292 27567 1.80 2.20 2.20 0.00 1.40 3.60 5.00 262.40 366.40 2.7 421 1026229
+1 87 1 1 60 76 1376 201 92 0.80 1.20 153571 52010 0.00 0.00 0.00 0.00 0.60 4.81 8.42 89.58 305.01 1.0 1811 1006641
+1 94 1 1 21 29 421 24 17 1.20 1.20 44450 7566 0.00 0.00 0.00 0.00 0.00 1.00 1.60 71.80 103.40 1.2 3313 1847784
+1 74 1 1 18 3 3319 461 361 9.80 5.40 190527 28434 0.80 1.00 4.20 7.60 0.40 1.00 1.00 467.00 708.60 3.4 881 1539952
+1 67 1 1 9 0 5384 534 447 7.77 5.38 366651 212196 0.00 0.00 0.00 0.00 0.60 9.56 12.75 393.03 635.26 1.2 582 1009565
+1 91 1 1 3 0 1513 111 55 2.00 2.20 27360 16241 0.00 0.00 0.00 0.00 0.00 0.60 0.60 96.59 159.32 1.0 1544 1084026
+1 93 1 1 1 0 1267 126 88 0.60 0.60 69701 27538 10.42 27.86 55.91 91.38 0.20 3.61 3.61 51.70 102.40 2.0 152 979707
+1 81 1 1 1 0 1190 59 62 0.20 0.20 132309 105665 6.80 22.80 35.80 77.00 0.00 7.20 13.40 51.80 47.60 2.8 366 1513949
+1 86 1 1 9 1 3762 359 253 2.60 3.80 600348 115966 0.00 0.00 0.00 0.00 0.00 0.20 0.20 150.60 229.40 3.6 2506 1646629
+1 93 1 1 0 0 410 63 84 0.40 0.60 185201 96070 0.00 0.00 0.00 0.00 0.00 2.20 2.40 33.20 45.40 1.8 2502 1771370
+1 89 1 1 1 1 2515 170 131 1.40 3.20 48911 98175 7.20 10.60 18.40 30.00 1.80 6.60 9.00 88.20 150.20 1.0 171 1023765
+1 98 1 1 0 0 133 9 9 0.20 0.20 1287 4064 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7224 1847200
+1 81 1 1 8 5 3788 268 287 1.40 2.60 131250 448735 4.40 5.00 4.80 0.00 1.20 28.20 31.00 69.80 159.60 3.2 314 1005253
+1 90 1 1 3 0 1828 140 111 0.40 0.60 14806 95873 2.40 4.60 7.80 10.40 0.00 11.40 11.40 33.00 102.80 1.0 155 1102946
+1 91 1 1 2 1 1800 92 48 0.20 0.20 43848 15151 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 17.20 1.4 6623 1859394
+1 90 1 1 35 48 2546 201 94 0.40 1.80 36846 24797 0.20 0.20 0.20 0.00 0.00 7.00 14.80 20.20 34.60 2.0 212 1113213
+1 88 1 1 2 0 2839 153 128 0.20 0.20 69921 134836 0.00 0.00 0.00 0.00 0.20 0.60 1.00 35.80 47.80 3.2 2963 1534675
+1 98 1 1 1 1 539 20 20 0.20 0.20 8073 8099 0.00 0.00 0.00 0.00 0.00 0.00 0.00 14.23 16.83 1.0 8540 1869996
+1 90 1 1 4 1 2356 250 74 0.80 0.40 348950 17696 0.00 0.00 0.00 0.00 0.40 9.60 9.60 50.60 112.60 2.0 2550 1016749
+1 91 1 1 35 48 1723 101 85 0.40 0.60 165098 99015 0.00 0.00 0.00 0.00 0.00 0.60 1.00 34.40 100.40 1.6 8455 1882138
+1 91 1 1 198 219 430 51 32 1.20 1.20 50363 11116 0.00 0.00 0.00 0.00 0.00 29.34 29.54 78.84 154.89 1.4 538 1731609
+1 90 1 1 4 0 1917 195 155 1.60 0.60 89080 73434 0.00 0.00 0.00 0.00 0.00 0.60 0.80 80.24 179.84 1.0 1156 1013640
+1 97 1 1 3 2 910 96 96 0.60 2.00 8324 17686 0.00 0.00 0.00 0.00 0.00 0.40 0.40 39.40 51.20 2.8 3025 1013448
+1 89 1 1 3 2 1505 93 86 1.60 3.60 33117 58751 0.00 0.00 0.00 0.00 0.20 1.40 2.60 76.40 194.80 1.0 898 1132768
+1 59 1 1 41 15 5902 395 202 4.40 8.00 430922 116491 14.80 75.40 135.20 208.80 6.20 80.40 104.00 357.80 635.40 6.6 188 1316494
+1 95 1 1 4 2 566 24 20 1.40 3.80 15866 12723 0.00 0.00 0.00 0.00 0.00 1.80 3.00 93.60 123.20 1.2 6884 1826949
+1 92 1 1 1 1 4301 139 140 0.20 0.20 41786 119139 2.60 4.20 4.20 0.00 0.40 1.80 1.80 15.60 42.60 1.0 324 1015587
+1 74 1 1 196 197 7054 594 351 4.00 4.80 582061 265288 9.40 19.00 30.20 38.60 0.40 11.00 32.00 185.60 336.80 5.2 170 1339541
+1 98 1 1 27 36 219 11 26 0.40 1.80 424 23995 0.00 0.00 0.00 0.00 0.00 0.20 0.20 19.80 24.40 1.0 8023 1878440
+1 62 1 1 60 31 6355 358 264 6.00 13.80 251366 242337 0.00 0.00 0.00 0.00 0.00 13.60 25.40 439.20 593.00 3.8 3155 1653723
+1 86 1 1 7 0 4004 321 287 2.40 0.80 159976 96480 0.00 0.00 0.00 0.00 0.60 3.40 5.40 134.20 191.80 4.4 3568 1546930
+1 67 1 1 52 16 7332 562 507 3.80 9.00 243486 68862 4.80 8.60 16.20 26.40 3.80 3.80 4.80 258.40 465.40 3.8 324 1396166
+1 96 1 1 2 1 949 179 72 0.40 1.80 233389 216172 0.00 0.00 0.00 0.00 0.20 6.60 6.60 39.20 48.80 3.6 2537 1577202
+1 85 1 1 3 1 479 79 42 2.00 2.00 328600 271946 0.00 0.00 0.00 0.00 0.00 6.39 10.78 181.64 164.27 2.6 3477 1819364
+1 89 1 1 2 1 2578 243 174 0.60 1.00 89694 66911 0.00 0.00 0.00 0.00 1.00 6.19 9.18 59.48 107.98 1.3 832 1120236
+1 89 1 1 3 0 1232 244 173 0.80 0.80 307433 27955 0.00 0.00 0.00 0.00 0.00 3.20 3.80 79.40 130.20 3.0 3027 1734002
+1 94 1 1 28 39 1360 57 36 1.00 5.60 102607 18360 0.00 0.00 0.00 0.00 0.00 0.00 0.00 76.80 88.80 1.4 4631 1824720
+1 97 1 1 1 0 438 19 19 0.80 2.40 5598 7819 0.00 0.00 0.00 0.00 0.00 0.00 0.00 46.69 65.33 1.0 1756 1774116
+1 94 1 1 1 0 1607 93 67 0.40 0.60 9713 48502 0.20 0.20 0.20 0.00 0.20 1.20 1.40 37.60 38.00 1.0 154 1126918
+1 97 1 1 0 0 199 17 21 0.20 0.20 13540 22848 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 2707 1771696
+1 79 1 1 551 2 4525 162 149 0.20 0.20 141542 176694 0.60 0.60 0.60 0.00 0.20 46.00 46.80 21.80 35.00 2.8 389 1515992
+1 81 1 1 14 1 2859 181 127 3.00 3.40 491868 266231 0.00 0.00 0.00 0.00 0.00 11.80 23.00 192.60 279.20 3.2 885 1540702
+1 94 1 1 7 4 900 76 107 0.60 2.40 24530 33419 0.00 0.00 0.00 0.00 0.00 2.80 3.00 56.60 78.00 1.0 495 1014379
+1 79 1 1 4 1 4182 770 659 2.40 1.60 522993 475727 0.00 0.00 0.00 0.00 0.00 0.20 0.20 143.60 200.00 1.0 842 1130637
+1 83 1 1 15 2 4507 476 484 0.80 0.80 252332 133646 17.76 29.54 52.30 86.83 13.57 11.58 20.16 55.49 128.14 1.5 132 1022917
+1 94 1 1 15 3 679 96 61 0.40 0.40 290517 8610 4.40 4.40 4.40 0.00 2.80 1.80 3.40 31.40 42.80 3.6 149 1704173
+1 90 1 1 27 38 2245 139 139 0.80 0.80 91783 66250 0.00 0.00 0.00 0.00 0.20 0.00 0.00 89.20 112.20 1.5 506 1046352
+1 87 1 1 4 0 1757 326 149 3.19 1.00 1337864 51392 0.00 0.00 0.00 0.00 0.00 0.00 0.00 155.89 229.34 2.6 8438 1860554
+1 86 1 1 188 199 1363 207 71 1.79 1.79 1253463 105106 0.00 0.00 0.00 0.00 0.00 4.18 5.78 135.66 143.82 4.8 7644 1855914
+1 85 1 1 11 1 4579 228 149 1.60 1.60 117336 61540 0.00 0.00 0.00 0.00 0.00 8.80 11.60 142.60 251.60 3.2 1838 1391714
+1 88 1 1 3 2 2868 472 364 0.60 0.60 22198 68182 2.20 2.60 4.60 4.80 1.00 0.00 0.00 42.60 47.60 2.2 128 1695483
+1 83 1 1 3 2 3798 389 219 0.80 2.00 129830 163040 0.00 0.00 0.00 0.00 0.00 9.60 10.60 70.00 152.40 5.6 1914 1005442
+1 90 1 1 13 12 2434 469 223 0.20 0.20 610383 768455 0.00 0.00 0.00 0.00 0.00 0.20 0.20 60.80 30.20 1.2 620 1045774
+1 97 1 1 1 0 959 93 35 0.20 0.20 5607 10188 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 5951 1722552
+1 95 1 1 0 0 1215 79 42 0.20 0.20 109593 52797 0.00 0.00 0.00 0.00 0.00 14.23 14.63 15.63 33.27 1.4 8520 1867833
+1 88 1 1 0 0 3805 416 410 0.20 0.20 17377 30167 1.60 2.20 2.20 0.00 0.20 1.00 1.00 16.20 27.80 1.0 244 1017678
+1 96 1 1 3 1 794 32 32 0.60 0.60 25397 10264 0.00 0.00 0.00 0.00 0.00 0.00 0.00 42.40 45.20 1.0 8565 1883538
+1 83 1 1 6 3 4225 212 204 1.80 4.40 189851 209246 0.00 0.00 0.00 0.00 0.00 1.00 1.00 92.00 123.00 4.8 1121 1608506
+1 84 1 1 19 2 2224 268 239 4.80 2.20 174928 82819 3.00 16.40 38.40 60.20 1.00 13.80 14.60 297.00 433.00 2.6 172 1522099
+1 89 1 1 1 0 4489 288 216 0.20 0.20 22982 44999 1.80 2.60 2.60 0.00 0.00 6.40 7.80 15.60 41.20 2.5 297 1015237
+1 91 1 1 6 1 2544 269 119 1.00 1.00 30350 34213 0.20 0.20 0.20 0.00 0.00 1.00 1.00 58.40 85.00 2.8 369 1536586
+1 98 1 1 0 0 139 10 20 0.20 0.20 3693 2724 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 6460 1871616
+1 80 1 1 186 167 5364 578 343 2.40 0.80 518970 232856 11.00 31.20 57.60 102.40 3.00 20.60 46.80 125.80 277.60 3.4 136 1326243
+1 80 1 1 2 0 2977 159 127 2.20 2.40 51139 66704 0.80 4.20 11.40 13.40 0.00 5.20 10.20 117.00 155.40 2.4 162 1760360
+1 94 1 1 5 3 943 78 46 0.40 0.60 23152 26389 0.00 0.00 0.00 0.00 0.00 0.00 0.00 32.87 101.00 2.4 774 1040228
+1 88 1 1 19 6 1782 167 77 3.00 4.20 121916 38079 1.20 1.20 3.40 11.80 0.80 1.20 1.20 172.60 305.20 1.0 353 976608
+1 79 1 1 9 0 4290 428 346 3.80 1.20 251693 148389 1.00 1.60 1.60 0.00 1.20 1.60 1.80 192.40 330.20 3.0 342 1088830
+1 67 1 1 79 42 5462 343 292 7.98 18.36 216677 161066 2.99 13.57 13.57 0.00 0.80 6.99 7.58 322.95 572.85 2.5 258 1097418
+1 72 1 1 36 38 3291 461 336 8.80 3.80 265082 19912 0.00 0.00 0.00 0.00 0.00 3.00 5.40 506.00 644.60 3.0 6445 1849002
+1 97 1 1 1 0 266 50 40 0.20 0.20 986 7095 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.80 2.0 6343 1724179
+1 62 1 1 42 0 3642 187 119 10.78 32.53 244853 34785 3.39 4.19 4.19 0.00 1.60 13.77 13.77 355.89 675.85 1.2 284 1092806
+1 85 1 1 4 2 2821 320 190 0.80 1.00 650097 53346 1.80 1.80 1.80 0.00 0.80 7.41 10.02 66.53 113.23 3.4 337 1042942
+1 85 1 1 15 13 4405 191 170 2.00 7.00 128411 32278 4.60 7.40 25.20 55.60 3.60 31.40 36.00 101.40 241.60 3.7 187 1001387
+1 95 1 1 1 0 711 72 82 1.00 0.80 57329 28539 0.00 0.00 0.00 0.00 0.20 1.60 3.00 57.60 68.20 1.2 682 1752805
+1 84 1 1 7 1 3917 412 362 0.20 0.20 311329 190481 5.00 6.00 5.60 0.00 0.80 17.60 27.40 17.20 75.80 3.2 224 1046589
+1 73 1 1 4 0 4608 490 560 2.79 1.00 315487 704234 16.77 24.15 24.15 0.00 11.98 6.79 9.38 142.91 232.73 2.6 201 1023724
+1 89 1 1 0 0 1558 96 86 0.20 0.20 96181 138854 0.00 0.00 0.00 0.00 0.00 6.80 8.60 15.60 35.60 1.0 1884 1711538
+1 93 1 1 2 0 523 96 81 0.20 0.20 33225 7501 0.00 0.00 0.00 0.00 0.20 35.80 41.60 16.60 54.60 2.2 1285 1705038
+1 88 1 1 2 0 2732 289 273 1.60 6.21 14112 28338 0.00 0.00 0.00 0.00 0.00 3.61 4.01 87.58 135.67 2.2 638 1099346
+1 91 1 1 3 1 3060 154 106 0.80 0.80 27921 19649 0.00 0.00 0.00 0.00 0.00 0.60 1.00 59.92 69.34 2.0 535 1735083
+1 79 1 1 9 1 4652 285 164 3.40 5.40 314418 78977 3.60 6.00 8.40 5.20 2.40 6.60 8.00 242.20 322.60 1.4 278 989790
+1 80 1 1 4 1 4148 423 250 3.40 2.20 250623 346396 12.80 25.60 25.60 0.00 0.00 18.20 19.20 193.60 342.60 1.8 378 988138
+1 91 1 1 137 128 1222 169 139 0.80 0.80 79344 90148 0.00 0.00 0.00 0.00 0.00 1.20 6.00 74.40 115.00 1.0 733 990430
+1 90 1 1 4 1 2009 124 104 3.00 6.80 57597 9936 0.00 0.00 0.00 0.00 0.00 0.60 0.60 161.60 222.80 4.2 856 1638418
+1 99 1 1 1 1 161 8 9 0.20 0.20 6994 4352 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 1.0 7739 1880280
+1 82 1 1 29 3 4067 174 126 2.80 3.00 296780 169853 7.20 33.80 70.40 183.00 0.80 18.00 21.20 211.40 349.00 5.4 179 1313411
+1 94 1 1 1 0 2533 145 134 0.60 0.60 4528 22579 0.00 0.00 0.00 0.00 0.00 0.00 0.00 42.40 44.00 2.4 509 1723696
+1 85 1 1 50 67 2197 135 118 1.00 1.60 115733 112170 9.20 59.60 91.60 240.80 1.40 22.60 42.00 123.00 320.80 2.0 245 1010376
+1 96 1 1 1 0 570 63 42 0.20 0.20 63967 31511 0.00 0.00 0.00 0.00 0.00 0.80 1.60 15.60 19.20 2.4 3041 1707746
+1 70 1 1 22 14 4563 339 233 7.00 15.00 105413 42167 0.60 1.00 1.00 0.00 0.20 9.40 12.40 262.40 448.60 1.0 654 1096325
+1 88 1 1 1 0 2181 277 738 1.00 4.00 58057 102085 0.00 0.00 0.00 0.00 0.00 0.00 0.00 49.80 82.40 3.2 1694 1727438
+1 89 1 1 10 7 1245 127 68 3.00 4.00 217133 21362 3.00 3.00 3.00 0.00 1.40 1.80 2.00 204.20 313.00 3.0 234 1025125
+1 97 1 1 0 0 202 11 16 0.40 0.40 421 8942 0.00 0.00 0.00 0.00 0.00 0.00 0.00 34.60 34.40 1.0 7544 1878098
+1 91 1 1 33 42 1366 84 82 0.80 0.80 168814 106967 0.00 0.00 0.00 0.00 0.00 0.00 0.00 138.60 66.40 3.0 1005 1540261
+1 85 1 1 14 2 3770 339 231 1.00 1.20 410959 94864 5.00 10.00 18.40 46.80 2.40 21.20 23.80 104.00 164.20 4.4 153 1529242
+1 90 1 1 3 2 4459 230 190 0.20 0.20 8172 25544 1.20 1.20 1.20 0.00 1.20 0.60 0.80 21.40 23.80 1.3 212 1127518
+1 84 1 1 27 5 2847 180 107 2.60 2.80 325450 84809 0.00 0.00 0.00 0.00 0.00 3.00 5.00 175.80 275.60 3.4 548 1540213
+1 85 1 1 18 11 3589 225 189 0.60 0.80 197954 27757 0.00 0.00 0.00 0.00 0.00 7.40 28.20 49.60 158.60 2.4 2065 966973
+1 77 1 1 33 16 4611 348 166 2.60 4.60 215913 85675 0.00 0.00 0.00 0.00 1.60 10.20 11.80 136.40 359.40 6.4 1134 1304538
+1 97 1 1 0 0 157 12 12 0.20 0.20 2251 11782 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.54 16.73 1.0 8312 1857227
+1 0 1 1 27 16 3967 790 204 2.59 2.59 1889308 578939 72.26 163.27 208.38 195.41 0.00 13.17 16.57 190.82 354.29 171 68 30
+1 90 1 1 19 16 4159 287 180 0.40 0.20 314222 142441 2.20 4.20 4.20 0.00 5.00 1.80 2.40 22.40 50.40 4.2 199 1323206
+1 1 1 1 54 72 1075 269 118 0.60 1.00 556405 509163 0.00 0.00 0.00 0.00 0.00 28.54 34.33 37.13 141.12 1502 90 9
+1 86 1 1 1 1 2173 184 149 0.40 0.40 767207 294541 0.40 0.40 0.40 0.00 0.00 4.79 6.19 28.14 52.10 1.6 345 1018735
+1 73 1 1 77 85 3678 486 170 5.80 6.00 483047 256999 0.00 0.00 0.00 0.00 0.00 12.60 22.00 341.00 572.20 4.4 2213 1575354
+1 89 1 1 8 4 1885 145 78 1.00 1.00 170236 31127 14.80 46.40 73.40 141.60 1.60 18.60 21.80 81.60 197.80 2.7 110 1021736
+1 91 1 1 1 0 400 45 49 1.20 1.20 40302 24635 0.00 0.00 0.00 0.00 0.00 0.40 0.60 86.20 106.00 2.0 4062 1779392
+1 85 1 1 20 11 2590 210 119 1.80 1.80 388668 216314 1.60 2.80 2.80 0.00 0.00 7.20 8.40 103.80 382.20 5.0 434 1315821
+1 59 1 1 9 1 8781 1694 1490 6.19 3.39 1313350 1148615 1.60 1.60 1.60 0.00 0.60 9.18 11.38 297.60 521.96 1.6 367 1087598
+1 77 1 1 39 35 4535 431 217 1.80 3.79 460699 84909 9.78 13.77 22.16 31.94 4.19 39.12 72.26 88.02 246.51 3.6 247 1031990
+1 95 1 1 1 0 3654 104 138 0.20 0.20 39922 137992 0.00 0.00 0.00 0.00 0.00 0.60 0.60 15.60 16.80 2.4 3124 1647952
+1 92 1 1 32 46 2742 153 111 0.40 1.80 44729 16642 0.00 0.00 0.00 0.00 0.00 2.20 3.80 73.20 53.00 2.0 1074 1461398
+1 83 1 1 6 5 12493 231 167 0.60 0.80 201271 96174 17.37 37.72 68.86 115.57 0.20 40.92 51.30 42.32 164.67 3.2 121 977595
+1 97 1 1 1 0 383 63 39 0.40 0.40 181714 6983 0.80 2.60 4.60 7.60 0.80 2.60 2.60 35.20 47.60 3.4 132 1701336
+1 73 1 1 2 1 5162 461 286 1.80 4.40 704358 431868 0.00 0.00 0.00 0.00 0.00 56.80 105.40 117.80 204.20 3.8 1068 1438059
+1 74 1 1 76 60 2588 190 139 7.58 20.56 110996 60096 2.40 2.59 9.78 17.76 1.20 7.98 17.56 294.21 541.32 1.0 168 1073726
+1 72 1 1 12 1 5169 561 498 8.40 6.40 308532 189057 0.00 0.00 0.00 0.00 4.00 2.20 2.80 405.40 644.40 2.0 643 1013078
+1 90 1 1 3 2 2717 250 187 0.40 1.80 106983 78503 0.60 1.00 1.00 0.00 0.20 5.80 6.60 25.40 82.60 1.0 341 1031469
+1 94 1 1 35 47 628 62 36 0.80 1.00 181004 9809 0.00 0.00 0.00 0.00 0.00 2.00 3.20 60.20 124.60 1.4 1616 1708194
+1 84 1 1 10 1 3271 259 138 1.80 1.80 164963 43123 5.00 12.40 64.00 112.80 0.60 44.40 48.20 75.80 183.60 3.0 130 1112949
+1 82 1 1 5 2 583 68 52 2.80 4.40 229645 124317 0.00 0.00 0.00 0.00 0.00 17.60 30.60 223.00 227.80 2.6 3246 1807819
+1 67 1 1 80 67 3131 244 136 6.01 7.41 182851 27898 8.42 41.68 102.00 191.58 1.80 26.45 32.06 360.72 732.26 2.2 166 1038256
+1 91 1 1 5 3 2260 167 151 0.80 4.40 120348 80288 0.00 0.00 0.00 0.00 0.00 0.00 0.00 63.60 62.00 4.4 1470 1641002
+1 81 1 1 11 8 2953 283 188 2.00 2.40 418539 336791 0.00 0.00 0.00 0.00 0.00 16.37 31.14 189.62 392.22 4.6 2952 1034488
+1 84 1 1 34 28 1250 141 115 1.19 2.17 133929 94242 17.39 32.41 57.31 142.49 1.98 14.03 24.70 151.19 341.50 2.2 232 1010522
+1 84 1 1 17 10 6870 407 217 1.80 1.80 339216 132711 0.00 0.00 0.00 0.00 0.00 4.40 6.40 84.40 197.40 5.4 1423 1332939
+1 88 1 1 2 0 1977 229 179 0.60 0.60 401623 145101 6.80 37.60 63.80 128.40 1.20 13.00 24.80 43.20 64.20 3.5 152 1035016
+1 84 1 1 4 0 4412 521 252 1.00 0.40 940869 73413 0.00 0.00 0.00 0.00 0.00 0.20 0.20 63.60 97.20 1.5 500 1074803
+1 89 1 1 3 1 3384 544 386 0.40 1.79 26014 38071 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.52 28.09 2.2 6153 1723610
+1 89 1 1 1 0 4022 162 114 0.60 0.80 21270 15841 0.00 0.00 0.00 0.00 0.00 8.38 9.58 42.12 73.05 6.0 167 1021150
+1 73 1 1 34 34 2883 447 396 7.78 2.00 225955 20663 0.00 0.00 0.00 0.00 0.00 0.00 0.00 361.28 517.56 3.2 260 1734611
+1 87 1 1 3 1 3206 191 118 0.40 0.40 204680 103124 21.00 32.40 46.40 39.00 15.80 14.80 25.00 31.20 71.80 1.0 156 1130344
+1 90 1 1 8 7 4210 136 121 1.00 2.40 41243 53051 1.20 1.40 1.40 0.00 0.80 2.40 2.40 79.00 145.20 1.0 283 989158
+1 70 1 1 67 74 6081 1328 1287 4.61 3.81 1188892 1066282 0.00 0.00 0.00 0.00 0.00 17.03 17.03 253.91 589.58 1.0 892 1059750
+1 66 1 1 219 109 5165 558 462 5.60 1.60 279042 155638 5.20 37.80 67.80 72.40 0.40 17.20 32.60 273.60 469.60 1.0 140 1017734
+1 80 1 1 5 1 1960 425 161 3.20 6.20 892842 246681 2.60 11.00 95.60 132.00 0.40 29.80 58.00 230.60 336.20 3.0 214 1757221
+1 91 1 1 1 0 2140 124 80 0.40 0.40 216382 101066 0.00 0.00 0.00 0.00 0.00 8.58 8.58 34.13 98.60 2.5 1129 1013696
+1 75 1 1 9 2 3513 495 410 2.81 1.00 335095 553721 20.24 26.85 32.26 14.63 15.63 14.63 15.83 135.87 293.39 2.4 174 1027723
+1 96 1 1 1 1 876 83 83 0.20 0.20 15661 15976 0.60 0.80 0.80 0.00 0.40 0.80 0.80 15.20 24.60 1.0 242 1014240
+1 84 1 1 30 20 4417 646 64 1.20 1.40 1594269 115065 0.00 0.00 0.00 0.00 3.20 2.40 4.20 81.60 262.40 5.4 1234 1322147
+1 93 1 1 11 2 1820 112 84 2.60 2.20 17805 17394 0.00 0.00 0.00 0.00 0.20 2.20 2.20 117.60 204.40 1.4 558 1021718
+1 86 1 1 1 0 2738 312 117 0.60 2.00 352370 31621 0.00 0.00 0.00 0.00 0.20 7.20 13.00 64.00 75.40 2.4 1130 1133245
+1 96 1 1 3 2 1110 50 48 0.20 0.20 18645 61810 0.00 0.00 0.00 0.00 0.00 0.80 1.60 15.60 16.80 1.6 8417 1837398
+1 79 1 1 56 56 3007 311 211 5.40 4.40 328714 42929 0.00 0.00 0.00 0.00 0.00 6.80 9.00 250.80 418.80 3.8 1683 1532330
+1 70 1 1 16 3 5849 521 474 5.60 2.20 347734 92820 2.60 3.40 2.80 0.00 15.20 8.20 8.40 301.20 534.40 1.7 279 971722
+1 96 1 1 0 0 1606 60 68 0.20 0.20 9075 197083 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 8557 1870237
+1 81 1 1 13 12 6465 508 286 1.40 4.40 818503 57953 0.40 0.60 0.60 0.00 0.00 13.80 17.00 79.40 182.60 2.0 315 1011723
+1 92 1 1 1 1 332 78 42 0.20 0.20 327206 209122 0.00 0.00 0.00 0.00 0.00 2.40 4.80 16.20 17.40 2.8 4094 1824344
+1 89 1 1 8 2 2357 167 99 5.00 3.60 87491 73356 0.00 0.00 0.00 0.00 0.00 1.60 2.00 295.80 329.20 3.2 628 1536202
+1 63 1 1 28 7 2915 409 343 10.18 4.79 291094 55552 0.00 0.00 0.00 0.00 0.00 14.57 17.96 559.88 783.63 4.0 1461 1770421
+1 88 1 1 3 1 5670 226 196 0.20 0.20 11251 27610 0.00 0.00 0.00 0.00 0.20 2.99 3.59 21.96 85.23 1.0 425 1010614
+1 91 1 1 5 1 1706 124 58 3.20 5.80 91651 35442 0.00 0.00 0.00 0.00 0.00 1.40 2.80 160.00 217.40 1.2 8437 1882131
+1 74 1 1 3 0 1613 226 397 2.60 2.80 474325 108778 0.00 0.00 0.00 0.00 1.40 19.80 25.40 207.80 421.20 3.8 1140 1820253
+1 91 1 1 2 0 1606 90 82 1.20 1.80 15697 56112 0.00 0.00 0.00 0.00 0.00 8.40 8.60 106.40 168.60 2.0 675 1060986
+1 82 1 1 4 1 4191 399 341 2.00 1.20 206184 159001 0.40 0.40 0.40 0.00 1.40 22.00 22.60 127.00 281.40 2.4 236 1077565
+1 0 1 1 57 34 4103 738 398 6.80 4.80 945180 528524 0.00 0.00 0.00 0.00 0.80 6.60 8.40 380.00 628.00 796 73 27
+1 94 1 1 1 0 1413 72 59 0.60 0.60 20064 27109 1.60 2.00 2.00 0.00 0.60 1.20 1.20 35.20 55.80 1.0 198 1085352
+1 93 1 1 18 27 1040 54 47 0.40 0.40 2553 10626 0.00 0.00 0.00 0.00 0.00 0.20 0.40 34.60 41.40 1.0 1344 1746229
+1 92 1 1 3 1 2125 166 78 0.40 0.40 174304 50630 2.40 2.80 2.80 0.00 3.40 8.40 8.40 26.60 87.80 2.2 221 1439635
+1 85 1 1 1 1 3845 192 125 0.40 0.40 93527 135304 0.00 0.00 0.00 0.00 0.00 3.20 3.20 34.00 61.40 7.5 1875 1005304
+1 92 1 1 5 1 1268 203 121 1.00 0.80 144371 69267 0.00 0.00 0.00 0.00 0.20 2.80 3.40 73.60 86.20 3.8 1346 1072618
+1 89 1 1 1 1 423 123 61 0.40 1.20 191608 168981 0.00 0.00 0.00 0.00 0.00 0.00 0.00 19.80 25.60 2.2 4144 1829253
+1 82 1 1 1 0 2497 362 169 0.80 2.00 262300 41748 0.00 0.00 0.00 0.00 0.00 8.38 9.78 109.58 170.06 2.4 2632 1042780
+1 95 1 1 143 81 682 144 167 0.20 0.20 86750 138284 0.00 0.00 0.00 0.00 0.00 0.20 0.40 14.60 16.80 2.0 1756 1762155
+1 66 1 1 12 2 3175 373 153 7.58 14.77 191239 47291 10.18 20.96 66.47 100.00 2.20 20.16 25.35 385.43 826.75 2.0 149 1033405
+1 89 1 1 1 0 2486 135 99 0.40 0.80 44382 30344 0.00 0.00 0.00 0.00 0.00 0.00 0.00 36.80 34.80 2.0 437 1754147
+1 73 1 1 11 2 4641 332 293 0.60 0.60 635586 444475 0.00 0.00 0.00 0.00 0.00 55.80 110.80 83.60 189.80 1.0 1563 1025074
+1 0 1 1 13 9 1076 119 95 1.00 0.60 104474 56550 11.80 15.40 15.40 0.00 10.20 9.00 12.40 81.80 139.00 317 89 11
+1 95 1 1 2 1 415 58 31 1.40 1.20 126763 56055 0.00 0.00 0.00 0.00 0.00 0.00 0.00 79.80 128.60 3.4 824 1722403
+1 97 1 1 2 1 210 13 23 0.40 0.40 12083 13571 0.00 0.00 0.00 0.00 0.00 0.00 0.00 37.60 33.40 1.0 6128 1864090
+1 94 1 1 4 1 1065 102 79 0.60 2.40 274824 78924 0.00 0.00 0.00 0.00 0.00 0.60 0.60 53.20 71.80 2.6 1507 1547243
+1 82 1 1 8 0 2340 276 204 5.59 5.59 304026 21110 1.40 1.40 1.20 0.00 2.20 1.40 2.00 264.07 388.02 3.4 254 1747404
+1 90 1 1 3 1 472 36 41 1.60 1.60 49324 97117 0.00 0.00 0.00 0.00 0.00 1.60 2.40 140.52 126.95 1.0 5287 1836260
+1 94 1 1 1 0 2309 95 73 0.40 0.40 18045 7270 0.00 0.00 0.00 0.00 0.00 11.40 11.40 34.00 52.80 2.6 4549 1731907
+1 90 1 1 20 27 1209 99 42 1.00 1.60 417136 280732 0.00 0.00 0.00 0.00 0.00 0.20 0.20 94.00 121.40 2.6 1210 1760954
+1 88 1 1 2 0 4424 259 230 0.40 0.40 61058 99269 0.00 0.00 0.00 0.00 0.79 4.76 5.56 33.73 86.90 3.4 466 1061705
+1 85 1 1 4 3 2365 409 202 1.20 2.59 158972 63925 12.38 54.69 76.65 125.55 2.79 45.71 58.48 85.63 145.71 1.0 157 1099780
+1 81 1 1 61 77 2816 348 243 1.60 3.40 381116 30220 9.40 48.80 69.60 60.00 0.20 39.20 53.00 127.60 212.80 1.0 200 1093723
+1 0 1 1 9 0 2683 382 164 0.80 0.80 256718 61215 8.60 23.40 117.40 206.00 1.40 12.40 47.60 103.80 357.60 128 80 20
+1 83 1 1 7 1 2697 552 496 0.20 0.20 581228 478856 14.43 40.28 74.35 89.78 6.21 25.25 71.34 15.63 39.68 1.5 134 1051256
+1 84 1 1 13 4 3954 806 172 0.80 0.40 1927635 34038 8.80 24.80 48.20 156.40 0.80 6.00 9.00 70.00 198.00 2.0 201 1018061
+1 79 1 1 12 2 3575 345 198 3.40 2.00 125934 75566 0.00 0.00 0.00 0.00 0.40 55.00 70.00 191.80 357.60 3.4 1417 1531504
+1 93 1 1 1 1 1016 65 49 0.20 0.20 60794 38169 0.00 0.00 0.00 0.00 0.00 1.00 1.00 16.60 25.00 2.0 569 1032410
+1 98 1 1 2 1 200 13 15 0.40 1.20 7798 8207 0.00 0.00 0.00 0.00 0.00 0.00 0.00 35.00 35.60 1.0 7917 1880896
+1 76 1 1 38 45 1669 122 101 5.00 10.20 304523 270928 0.00 0.00 0.00 0.00 0.00 25.40 28.80 303.40 433.40 1.8 8137 1864890
+1 84 1 1 4 2 2677 248 142 1.80 4.20 231107 38426 0.00 0.00 0.00 0.00 0.00 2.20 2.80 108.20 259.80 1.8 760 1117523
+1 72 1 1 96 114 5373 289 201 4.20 3.80 156887 60216 0.00 0.00 0.00 0.00 0.80 22.80 24.00 234.60 561.60 5.0 1005 1320126
+1 86 1 1 1 0 4351 296 149 1.00 3.19 472345 30765 0.00 0.00 0.00 0.00 0.20 1.40 1.40 226.55 59.48 2.0 583 1116706
+1 98 1 1 1 1 231 23 29 0.20 0.20 19505 2909 0.00 0.00 0.00 0.00 0.00 1.80 2.61 15.43 20.64 1.0 7261 1868646
+1 98 1 1 0 0 311 21 22 0.40 0.60 2364 10512 0.00 0.00 0.00 0.00 0.00 0.20 0.40 23.35 30.34 1.2 1313 1742256
+1 88 1 1 50 61 2040 189 139 0.80 2.20 106948 41849 0.80 5.79 15.37 22.36 0.80 16.57 22.55 52.89 116.17 2.4 129 1106501
+1 98 1 1 1 1 301 43 32 0.20 0.20 20290 4785 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.2 147 1716640
+1 90 1 1 33 29 2038 228 127 2.40 2.00 173290 81406 0.00 0.00 0.00 0.00 0.00 4.20 4.60 123.40 178.20 7.2 3167 1594966
+1 92 1 1 2 1 2669 170 114 0.20 0.20 12970 27319 6.00 13.40 22.20 66.40 0.20 2.40 3.00 17.00 34.40 1.2 173 1137886
+1 81 1 1 182 176 4748 327 235 1.60 2.60 276900 221153 1.60 8.60 23.60 52.40 0.00 5.40 20.00 72.80 149.60 3.8 147 1328122
+1 87 1 1 37 47 3209 204 81 2.00 5.20 228027 46911 0.20 5.20 13.00 19.60 0.80 3.60 5.00 116.40 159.40 1.8 159 1126944
+1 83 1 1 0 0 4622 443 202 0.60 1.00 332229 76821 2.00 3.59 2.79 0.00 4.79 1.20 1.20 221.76 71.06 2.0 248 1115422
+1 94 1 1 13 12 811 190 85 0.40 1.60 269386 228952 0.00 0.00 0.00 0.00 0.00 3.00 5.80 22.60 28.00 3.6 1003 1753603
+1 93 1 1 0 0 2132 129 62 0.20 0.20 90813 28590 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.43 16.83 1.6 488 1742493
+1 84 1 1 5 0 3291 265 173 4.40 3.60 203625 41092 0.00 0.00 0.00 0.00 4.00 1.40 1.80 158.20 271.80 3.4 724 1516834
+1 84 1 1 29 28 1124 120 92 0.40 1.60 95071 14653 0.00 0.00 0.00 0.00 0.00 4.40 4.40 31.80 42.40 4.0 4812 1671920
+1 89 1 1 4 0 1688 89 62 2.59 7.78 74975 20311 0.20 0.20 0.20 0.00 0.20 2.20 2.20 130.54 215.17 2.0 470 1034916
+1 0 1 1 8 4 2803 125 72 0.60 2.20 147274 25176 0.60 0.60 0.60 0.00 0.20 1.60 1.80 55.60 127.80 170 91 9
+1 64 1 1 12 0 4635 679 576 10.80 4.40 322232 50852 0.80 1.00 1.00 0.00 0.20 1.80 3.00 535.00 833.40 1.0 408 1027626
+1 91 1 1 1 0 1266 242 97 1.40 4.40 736445 228457 0.00 0.00 0.00 0.00 0.00 1.60 2.20 51.80 76.00 2.6 486 1757878
+1 97 1 1 0 0 658 25 22 0.20 0.20 989 9206 0.80 0.80 0.80 0.00 0.00 0.80 0.80 15.60 16.80 1.0 284 1751064
+1 85 1 1 27 15 3413 250 171 2.40 3.20 244989 95168 0.00 0.00 0.00 0.00 0.00 0.80 0.80 154.00 286.40 1.4 385 1068986
+1 88 1 1 1 1 6315 274 164 0.20 0.20 13562 28007 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.77 28.34 2.0 1057 1077118
+1 88 1 1 2 0 5836 294 277 0.40 2.00 7776 98384 0.00 0.00 0.00 0.00 0.00 0.00 0.00 19.36 51.50 1.7 327 1067952
+1 95 1 1 6 0 1984 59 58 1.40 4.20 2161 5422 0.00 0.00 0.00 0.00 0.00 0.20 0.20 41.80 72.60 4.0 839 1631088
+1 94 1 1 3 2 2557 130 155 0.40 0.40 7007 17054 0.00 0.00 0.00 0.00 0.00 0.00 0.00 29.40 40.60 2.2 1427 1725170
+1 89 1 1 49 67 2959 235 147 0.40 1.20 140615 130533 6.00 10.80 14.20 9.60 6.00 3.80 4.00 18.80 36.00 1.3 138 1128235
+1 90 1 1 10 2 2441 225 118 1.00 5.59 271980 38053 0.40 0.80 0.80 0.00 22.36 6.19 7.58 50.10 162.87 4.8 444 1311257
+1 82 1 1 5 1 2802 360 242 1.60 1.80 502512 321340 0.00 0.00 0.00 0.00 0.00 9.60 18.00 115.00 218.80 5.0 928 1601696
+1 94 1 1 10 6 655 118 83 0.80 1.20 260079 11342 0.00 0.00 0.00 0.00 0.00 0.40 0.60 59.60 112.80 2.8 6231 1721918
+1 90 1 1 47 70 791 110 59 0.20 0.20 10027 11437 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 17.60 1.8 658 1759344
+1 0 1 1 2 0 694 71 77 0.20 0.20 123951 57396 0.20 0.20 1.60 3.80 0.40 1.40 2.40 14.40 24.60 146 95 5
+1 77 1 1 15 1 3637 545 267 4.60 2.60 133027 41938 1.80 7.80 47.00 70.00 1.20 30.80 40.60 208.00 448.00 2.8 204 1099102
+1 96 1 1 31 47 761 57 45 0.20 0.20 1304 15389 0.00 0.00 0.00 0.00 0.00 0.00 0.00 21.64 19.24 5.2 397 1010637
+1 97 1 1 1 0 223 42 29 0.20 0.20 166383 139685 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.00 18.20 3.0 5728 1836571
+1 87 1 1 23 19 2130 164 157 1.00 1.00 52391 117772 4.39 8.38 8.38 0.00 0.20 1.80 3.19 70.26 93.61 2.2 178 1062783
+1 87 1 1 9 7 3717 203 191 0.60 0.80 204642 234240 2.59 11.38 46.51 79.64 1.20 3.79 5.59 67.07 221.56 2.3 127 1008517
+1 0 1 1 40 27 1866 210 124 2.00 5.00 256508 44587 0.00 0.00 0.00 0.00 0.00 9.20 14.00 124.80 203.00 579 87 13
+1 89 1 1 40 9 1113 135 87 1.40 0.60 121004 31788 32.60 71.60 130.40 253.20 0.40 45.00 70.40 93.00 309.40 1.0 204 982482
+1 91 1 1 22 23 1068 61 52 2.00 1.80 18034 20905 1.60 1.80 1.80 0.00 0.00 4.79 6.59 75.45 140.92 1.0 309 1014486
+1 83 1 1 2 0 3971 696 630 2.00 1.80 490705 450985 1.60 3.20 3.00 0.00 0.80 1.60 2.00 101.40 177.80 2.0 317 1130125
+1 70 1 1 37 17 5308 585 355 6.80 5.00 779615 84251 0.00 0.00 0.00 0.00 0.00 7.80 8.00 382.20 674.20 9.8 2083 1330581
+1 97 1 1 2 1 487 57 46 0.40 1.80 6810 13719 0.00 0.00 0.00 0.00 0.00 0.80 0.80 21.20 31.40 3.0 1383 1716426
+1 84 1 1 43 35 1386 193 127 1.39 2.39 174523 35983 43.63 85.06 120.12 206.18 2.59 45.02 82.07 117.33 222.11 1.3 206 986542
+1 86 1 1 12 1 2459 229 198 4.00 2.20 170719 34712 0.00 0.00 0.00 0.00 0.00 27.60 29.40 205.80 349.00 1.8 638 1042656
+1 62 1 1 27 16 4416 295 182 10.80 21.60 165424 44132 5.20 9.20 15.00 17.00 1.20 7.00 9.20 427.80 798.80 1.5 426 1098062
+1 89 1 1 35 49 1897 259 311 0.20 0.20 96054 34273 0.00 0.00 0.00 0.00 0.40 21.00 33.40 27.20 167.80 1.5 714 1011355
+1 90 1 1 5 0 842 140 155 1.40 8.00 129889 56953 0.00 0.00 0.00 0.00 0.00 0.00 0.00 235.60 335.40 1.8 1639 1729440
+1 88 1 1 12 9 4264 220 156 0.40 0.40 34420 51388 0.00 0.00 0.00 0.00 1.00 8.00 12.00 35.40 51.80 1.7 407 1130074
+1 95 1 1 1 0 2135 68 103 0.20 0.20 3939 12896 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 18.60 2.6 1416 1725048
+1 86 1 1 5 0 1550 124 196 1.80 3.20 142782 434355 0.00 0.00 0.00 0.00 0.00 12.80 25.20 94.00 197.80 1.8 1407 1041555
+1 84 1 1 10 2 1893 117 100 1.40 2.80 85176 71503 0.00 0.00 0.00 0.00 0.20 1.60 1.80 129.20 186.60 3.4 1192 1513686
+1 84 1 1 3 0 615 79 50 2.40 3.00 203184 27089 7.20 7.40 7.40 0.00 0.20 1.20 1.60 205.00 200.20 1.2 286 1806579
+1 98 1 1 1 0 244 46 21 0.20 0.20 137263 9223 0.00 0.00 0.00 0.00 0.00 0.00 0.00 22.20 17.20 1.4 7945 1833245
+1 85 1 1 34 45 2253 374 185 1.80 2.00 538610 219894 14.20 23.00 21.20 0.00 9.40 10.40 11.00 101.00 192.20 6.6 726 978285
+1 87 1 1 4 0 2366 338 203 3.80 1.20 329195 208622 0.00 0.00 0.00 0.00 0.00 0.40 0.40 191.80 280.80 2.8 1961 1759778
+1 81 1 1 27 17 3766 271 218 3.40 2.40 238375 91801 0.00 0.00 0.00 0.00 0.60 1.80 2.00 162.00 263.00 5.6 3744 1548725
+1 87 1 1 14 12 4319 322 167 0.80 1.40 720157 38604 1.40 1.80 2.00 1.40 0.20 28.60 50.20 70.60 122.80 1.2 202 1011394
+1 91 1 1 3 1 2284 267 217 0.80 1.00 67409 24680 0.20 0.20 0.20 0.00 0.00 3.41 3.61 51.50 103.41 2.0 190 1016872
+1 89 1 1 12 4 2014 101 143 2.40 2.80 97317 79868 0.00 0.00 0.00 0.00 0.00 6.60 12.20 109.80 182.20 3.2 850 1517122
+1 63 1 1 13 0 3327 197 96 11.60 34.80 30830 68500 0.00 0.00 0.00 0.00 0.00 4.80 5.40 399.00 758.40 1.0 1594 1093397
+1 78 1 1 18 17 4222 496 288 1.40 2.80 167621 104576 12.00 43.60 81.20 178.00 4.20 1.60 2.40 110.20 293.80 1.0 169 997555
+1 91 1 1 50 68 2487 124 80 0.20 0.20 12574 22433 0.00 0.00 0.00 0.00 0.00 34.26 34.66 15.94 99.80 3.4 303 1018837
+1 75 1 1 17 2 4377 348 263 4.00 2.40 248105 159199 1.60 1.60 1.60 0.00 1.00 3.60 26.60 253.00 374.40 5.0 397 1070579
+1 87 1 1 5 2 2091 232 139 1.20 1.00 114989 38534 2.61 3.21 3.21 0.00 4.21 6.21 9.82 71.14 101.80 2.0 199 1099744
+1 93 1 1 32 39 746 175 144 0.40 0.20 173416 73499 3.40 6.20 6.20 0.00 9.40 1.40 1.60 17.40 25.20 3.2 341 1738622
+1 78 1 1 10 8 3158 324 172 0.60 2.20 1037534 884253 0.00 0.00 0.00 0.00 0.00 26.00 45.80 46.00 79.20 3.0 510 1032922
+1 93 1 1 6 4 815 66 40 0.80 2.20 15458 19199 0.00 0.00 0.00 0.00 0.00 31.20 39.80 39.20 114.80 2.2 519 997528
+1 93 1 1 7 5 858 81 84 0.20 0.20 7141 26164 0.00 0.00 0.00 0.00 0.40 50.20 50.60 31.00 124.40 2.0 1407 971707
+1 79 1 1 8 5 3281 366 155 2.99 4.78 389489 60828 6.77 27.89 130.68 296.81 1.59 92.23 92.63 146.41 414.54 2.2 115 1124140
+1 84 1 1 2 0 1753 123 126 1.20 0.80 30510 22466 1.00 1.00 1.00 0.00 0.00 1.20 1.60 67.00 112.20 1.6 279 1019373
+1 82 1 1 14 3 4871 280 185 3.60 2.40 370904 50113 2.00 2.00 2.00 0.00 4.00 0.20 0.20 257.20 324.60 3.6 214 1626373
+1 94 1 1 0 0 1146 86 88 0.20 0.20 45974 74323 10.40 18.20 16.60 0.00 0.00 2.00 2.40 16.00 17.00 3.0 310 1711723
+1 92 1 1 2 0 1373 64 43 0.80 0.80 14472 15298 10.18 20.16 20.16 0.00 0.80 11.78 22.36 116.77 226.75 1.0 450 1057974
+1 91 1 1 68 70 2012 338 332 0.40 1.00 39811 30496 0.80 3.40 12.80 31.60 0.20 4.20 4.20 37.80 49.20 4.2 136 1044910
+1 87 1 1 16 14 2626 218 118 1.00 1.00 773291 99704 0.80 1.60 1.60 0.00 0.20 3.20 5.60 48.00 216.00 6.4 627 1308659
+1 63 1 1 25 12 5876 695 552 9.60 5.40 692094 332051 0.00 0.00 0.00 0.00 0.00 6.80 7.80 568.20 817.20 1.0 1077 1014856
+1 88 1 1 9 4 1632 313 151 1.80 2.00 1238191 53430 1.20 2.20 2.20 0.00 0.80 8.80 12.20 113.80 201.40 4.0 357 982474
+1 81 1 1 72 65 3269 319 200 2.20 5.39 305717 55090 14.97 31.94 61.48 62.08 15.17 10.78 13.17 141.12 310.78 5.4 186 1308784
+1 98 1 1 1 1 187 11 9 0.20 0.20 11769 6159 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.20 13.20 1.0 11982 1888734
+1 79 1 1 19 1 4233 878 403 3.40 1.80 313999 280066 0.00 0.00 0.00 0.00 0.40 23.80 26.60 174.40 401.40 2.0 644 1059965
+1 96 1 1 3 3 1256 94 89 0.60 0.60 13216 18267 0.00 0.00 0.00 0.00 0.00 2.20 2.40 45.60 74.40 3.0 498 1447061
+1 80 1 1 6 3 2578 234 115 2.80 3.00 597742 95903 0.00 0.00 0.00 0.00 0.00 1.60 2.00 206.60 340.80 1.5 650 1053069
+1 98 1 1 1 0 1361 55 57 0.20 0.20 4454 4513 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 2.0 6121 1729688
+1 71 1 1 69 6 3549 207 117 7.80 23.20 150887 38835 4.20 21.40 37.60 51.40 1.20 51.20 89.00 283.00 588.60 2.0 356 1085282
+1 77 1 1 12 5 3497 381 174 6.00 16.60 234057 24578 0.40 0.60 0.60 0.00 3.20 15.60 21.60 191.20 374.00 1.8 170 1114086
+1 87 1 1 4 0 2917 267 135 1.80 5.19 291639 39035 7.58 26.95 34.93 54.29 2.99 21.56 22.16 133.53 250.90 1.0 173 1100238
+1 91 1 1 0 0 228 31 36 0.20 0.20 854 10593 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 2.0 1017 1761517
+1 88 1 1 2 1 608 182 73 0.20 0.40 59059 25554 0.00 0.00 0.00 0.00 0.00 1.40 1.40 26.00 32.40 2.0 437 1742504
+1 89 1 1 5 1 1795 221 127 1.00 1.40 207913 51728 0.00 0.00 0.00 0.00 0.00 0.20 0.20 66.80 145.80 3.0 2711 1541586
+1 95 1 1 0 0 1292 88 70 0.20 0.20 2222 10137 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 2.0 2104 1720376
+1 96 1 1 0 0 405 71 57 0.20 0.20 1355 13224 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 2.0 684 1721986
+1 54 1 1 160 140 5157 419 212 9.80 25.20 439846 73418 6.40 30.20 72.40 254.20 1.00 74.60 78.40 386.20 927.40 3.3 161 1096931
+1 79 1 1 16 1 3879 346 306 6.40 2.80 186830 77820 0.00 0.00 0.00 0.00 0.00 0.60 1.20 321.40 489.20 4.4 513 1539016
+1 91 1 1 0 0 579 63 39 0.00 0.00 1601 17342 1.40 1.40 1.40 0.00 0.00 0.20 0.20 0.00 0.60 1.6 240 1755790
+1 96 1 1 2 0 1177 136 61 0.20 0.20 124566 69960 0.00 0.00 0.00 0.00 0.00 2.81 3.61 16.03 41.68 1.0 711 1063202
+1 94 1 1 3 0 1485 98 89 1.40 4.00 273682 231957 0.00 0.00 0.00 0.00 0.20 0.00 0.00 65.00 95.60 2.6 802 1761578
+1 92 1 1 3 3 1758 232 171 1.20 1.40 16809 56375 0.00 0.00 0.00 0.00 0.20 1.00 1.00 62.40 100.40 1.0 637 1120304
+1 87 1 1 8 7 3129 140 118 1.40 2.20 70014 36333 0.00 0.00 0.00 0.00 0.00 12.80 15.00 118.00 173.40 1.0 654 991731
+1 85 1 1 7 0 1565 177 143 7.80 3.80 149622 11778 0.00 0.00 0.00 0.00 0.00 0.00 0.00 334.00 505.20 1.6 6971 1844266
+1 85 1 1 39 48 2754 129 83 2.59 3.79 138656 25427 0.00 0.00 0.00 0.00 0.00 0.40 0.40 184.03 270.06 1.8 2695 1012754
+1 98 1 1 2 1 199 19 18 0.40 0.40 31182 11487 0.00 0.00 0.00 0.00 0.00 0.00 0.00 36.80 40.00 1.0 8337 1864566
+1 86 1 1 6 2 2839 221 201 0.40 0.80 129995 271522 11.00 13.40 13.40 0.00 13.80 9.20 9.20 35.60 128.00 1.0 331 1000355
+1 93 1 1 0 0 1892 143 102 0.20 0.20 268383 61995 14.80 18.40 18.40 0.00 15.40 3.20 5.20 18.80 46.80 1.5 197 1016394
+1 89 1 1 6 1 2018 254 243 2.40 0.80 186521 142178 0.00 0.00 0.00 0.00 0.00 2.40 3.19 118.56 167.07 1.0 469 1010584
+1 87 1 1 3 1 583 58 110 1.20 4.20 5458 533869 38.80 77.00 79.00 5.20 0.40 0.20 0.20 70.80 86.60 3.4 276 1714979
+1 78 1 1 10 1 2866 424 386 7.40 2.40 212790 119991 0.00 0.00 0.00 0.00 0.00 0.00 0.00 368.80 532.40 2.8 6457 1845248
+1 84 1 1 18 25 495 69 47 2.00 2.00 75783 34467 0.00 0.00 0.00 0.00 0.00 2.40 4.20 162.80 165.20 1.0 635 1814986
+1 93 1 1 2 0 878 168 64 0.60 0.40 256762 221846 0.00 0.00 0.00 0.00 0.00 4.60 5.20 32.00 55.60 4.2 2598 1574843
+1 94 1 1 9 7 619 68 60 0.80 0.80 26307 23684 0.00 0.00 0.00 0.00 0.40 0.40 0.40 59.60 73.80 2.2 1344 972406
+1 93 1 1 5 3 2373 250 133 0.20 0.20 121195 73791 0.80 6.80 15.20 23.00 0.00 6.40 11.20 18.40 72.00 5.4 162 1534834
+1 88 1 1 12 8 1852 191 121 1.20 2.59 242070 19965 14.57 30.34 58.48 127.74 1.40 19.16 47.50 124.95 212.97 1.3 215 970743
+1 90 1 1 29 42 3746 162 116 0.40 1.00 216431 126334 0.60 1.00 1.00 0.00 2.80 1.00 1.20 30.80 68.20 2.4 330 1015565
+1 97 1 1 19 17 1814 71 73 0.40 0.20 7718 50977 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.80 23.80 2.0 3394 1657253
+1 93 1 1 1 0 1326 92 75 1.00 1.80 18039 19357 0.80 1.00 6.00 15.40 0.00 2.60 2.60 76.40 106.60 1.5 156 1117818
+1 68 1 1 67 63 5337 234 146 6.40 18.00 141332 43164 3.20 3.40 3.40 0.00 1.80 64.80 69.20 491.20 601.60 5.6 316 1543805
+1 74 1 1 43 25 6291 390 288 4.60 5.60 257974 192468 0.80 5.40 1.20 0.00 1.40 1.40 2.00 223.80 379.00 7.0 2339 1327936
+1 77 1 1 6 0 1474 217 222 4.60 2.80 168369 45720 0.00 0.00 0.00 0.00 0.00 3.80 6.60 307.20 351.80 1.8 3704 1820309
+1 88 1 1 97 110 1371 227 170 1.00 2.20 237035 70000 2.00 2.40 2.40 0.00 1.00 1.60 1.60 72.80 105.20 1.0 199 1117930
+1 83 1 1 37 26 1669 134 99 2.81 3.61 66491 24147 0.80 0.80 0.80 0.00 2.20 4.21 4.21 269.74 351.50 3.2 488 978381
+1 76 1 1 12 2 1802 82 70 7.39 22.75 34951 32627 6.79 14.97 36.33 83.23 0.40 15.97 16.97 249.70 493.61 1.5 150 1086395
+1 0 1 1 43 54 1614 171 124 1.40 5.60 203635 111536 0.00 0.00 0.00 0.00 0.00 5.60 6.60 42.40 76.60 637 89 9
+1 95 1 1 1 0 699 69 80 0.60 2.20 52955 18020 0.00 0.00 0.00 0.00 0.00 4.20 7.40 50.00 74.00 2.0 1731 1074205
+1 96 1 1 1 0 465 25 31 0.80 2.40 4507 8507 0.00 0.00 0.00 0.00 0.80 0.20 0.20 46.91 64.87 1.4 416 1753565
+1 91 1 1 20 8 1387 214 148 0.60 0.60 27968 25950 0.00 0.00 0.00 0.00 0.00 11.40 11.80 49.20 156.80 1.6 691 976568
+1 75 1 1 10 1 3399 222 154 2.20 5.01 354216 75374 0.60 0.80 0.60 0.00 0.40 41.48 51.90 136.47 411.82 1.0 453 991214
+1 89 1 1 36 51 1700 145 113 0.20 0.20 265148 97093 0.00 0.00 0.00 0.00 0.00 1.20 1.20 22.00 43.20 1.0 1211 1100832
+1 77 1 1 80 64 3594 390 263 2.00 7.41 543460 115695 17.03 39.88 84.57 160.12 14.23 22.85 45.49 151.30 297.80 2.5 206 1041760
+1 92 1 1 1 1 264 31 11 0.60 1.20 180683 6818 0.00 0.00 0.00 0.00 0.00 24.40 48.60 50.40 121.80 1.6 7137 1877192
+1 95 1 1 4 2 2142 127 132 0.40 0.40 54322 13560 0.60 0.80 0.80 0.00 0.20 19.60 23.20 27.80 66.40 3.2 332 1702925
+1 91 1 1 4 3 1669 169 119 1.40 2.80 162209 46829 2.60 3.60 2.80 0.00 1.20 5.20 5.80 100.20 169.20 3.0 331 1104515
+1 87 1 1 14 1 2648 212 111 1.20 2.61 273653 85476 0.00 0.00 0.00 0.00 0.00 8.22 12.63 88.98 150.30 1.5 1096 1115118
+1 89 1 1 186 204 416 44 33 1.99 1.99 77138 42947 0.00 0.00 0.00 0.00 0.00 3.59 6.37 175.10 164.34 2.2 7837 1860077
+1 92 1 1 5 5 3797 200 165 0.20 0.20 50974 41728 0.00 0.00 0.00 0.00 0.00 2.00 2.00 16.37 28.74 1.0 535 980455
+1 97 1 1 4 3 374 76 69 0.20 0.20 7140 57194 0.00 0.00 0.00 0.00 0.00 0.00 0.00 19.76 16.77 1.0 5907 1859933
+1 95 1 1 28 41 1882 100 85 0.20 0.20 3722 9791 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.40 17.20 1.4 397 1730840
+1 87 1 1 7 0 1629 264 238 5.20 1.40 152408 20174 0.00 0.00 0.00 0.00 0.00 0.00 0.00 257.40 362.20 2.2 8355 1864778
+1 75 1 1 11 0 2009 408 281 5.00 4.20 418070 61161 2.40 10.40 63.60 100.80 0.60 5.60 10.20 327.40 581.20 4.4 427 1721011
+1 85 1 1 4 1 5370 251 150 2.40 4.00 183113 60491 0.00 0.00 0.00 0.00 0.00 1.20 1.20 200.20 273.20 2.8 1386 1390003
+1 92 1 1 6 6 794 150 101 0.60 0.60 15740 30957 0.00 0.00 0.00 0.00 0.20 5.61 5.61 36.27 177.96 1.2 687 1019849
+1 59 1 1 50 12 6113 563 525 13.00 8.40 374186 38201 4.80 5.00 5.00 0.00 5.20 10.40 12.80 586.40 984.60 1.0 295 972165
+1 97 1 1 2 1 710 40 41 0.20 0.20 2913 18830 0.00 0.00 0.00 0.00 0.00 0.40 0.40 24.80 18.80 1.0 684 1039054
+1 90 1 1 9 2 2128 113 84 1.59 1.99 16656 25126 0.60 0.60 19.28 25.84 0.80 2.78 3.38 68.79 116.50 3.5 128 1105893
+1 0 1 1 13 10 1660 453 154 0.40 0.60 661738 654478 0.00 0.00 0.00 0.00 0.00 7.40 7.80 31.80 55.60 603 93 7
+1 96 1 1 2 1 229 12 18 0.20 0.20 10387 47820 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 7337 1862256
+1 98 1 1 2 1 209 16 28 0.20 0.20 23130 27776 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 8315 1863747
+1 85 1 1 7 2 2088 257 200 4.80 2.40 359374 8357 0.00 0.00 0.00 0.00 0.00 0.00 0.00 253.00 367.80 2.2 8581 1865357
+1 63 1 1 44 2 2544 190 105 10.82 32.46 387999 161319 15.03 34.87 43.89 38.08 0.60 19.44 31.46 381.16 746.49 1.0 265 1096840
+1 83 1 1 82 49 2004 215 160 2.79 3.79 239272 161394 0.00 0.00 0.00 0.00 0.00 18.96 29.14 189.62 324.55 1.0 1257 999866
+1 0 1 1 67 66 1117 430 154 0.40 0.20 631396 632869 0.00 0.00 0.00 0.00 0.00 1.99 1.99 21.47 55.07 688 94 6
+1 92 1 1 7 3 2304 99 69 0.60 0.60 146483 27071 0.00 0.00 0.00 0.00 0.00 1.00 1.60 57.60 52.20 2.2 6239 1721694
+1 93 1 1 4 1 1079 150 99 0.60 0.60 279546 123542 0.00 0.00 0.00 0.00 0.20 5.20 5.60 42.40 83.00 2.6 1602 1538696
+1 89 1 1 36 20 2289 253 141 2.80 4.20 256637 49444 0.00 0.00 0.00 0.00 1.20 0.60 0.60 152.20 251.80 4.2 521 1542646
+1 90 1 1 3 1 405 37 14 2.00 2.00 68996 10749 0.00 0.00 0.00 0.00 0.00 1.40 1.40 178.04 153.69 1.4 9082 1874730
+1 79 1 1 71 87 5000 470 208 1.40 1.40 293420 86058 5.60 15.80 40.00 85.40 1.40 30.60 37.20 81.60 235.80 1.0 125 984354
+1 81 1 1 26 36 5731 312 224 0.80 0.80 155004 264757 0.00 0.00 0.00 0.00 3.20 0.20 0.20 48.80 134.00 3.2 249 1383946
+1 78 1 1 29 15 5190 350 132 1.37 3.13 357653 44662 2.34 3.13 2.54 0.00 4.49 7.62 49.41 108.01 244.73 1.7 597 1176309
+1 81 1 1 17 7 4987 182 114 2.20 7.40 213349 37367 0.00 0.00 0.00 0.00 0.00 0.40 0.40 186.80 180.60 3.2 841 1534522
+1 97 1 1 0 0 573 106 87 0.20 0.20 1787 17669 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.80 17.20 1.0 428 1726456
+1 89 1 1 0 0 660 68 24 0.60 1.20 412816 11399 0.00 0.00 0.00 0.00 0.00 0.00 0.00 39.60 73.20 2.6 1187 1766742
+1 88 1 1 119 116 4029 453 246 0.40 0.60 369988 215679 0.00 0.00 0.00 0.00 0.00 11.20 21.20 31.40 97.60 3.6 3168 1331394
+1 71 1 1 8 1 4773 1009 880 3.20 1.40 1086945 662015 2.20 4.60 13.00 36.00 11.80 17.80 37.80 225.00 376.40 2.0 204 1121336
+1 0 1 1 31 41 1394 163 124 0.40 0.40 26747 64771 14.77 20.56 28.74 19.16 10.98 11.38 14.57 37.33 78.84 136 89 11
+1 88 1 1 251 191 2326 321 151 0.20 0.20 1017291 78778 0.00 0.00 0.00 0.00 0.00 12.80 12.80 14.40 35.00 1.8 408 1072592
+1 0 1 1 23 13 1205 154 79 1.20 2.81 605642 53078 29.26 109.62 219.44 507.21 1.60 62.73 123.25 137.27 376.75 255 78 21
+1 81 1 1 172 0 3252 205 174 1.60 0.60 516331 33097 0.00 0.00 0.00 0.00 0.20 48.20 96.20 95.80 223.20 5.6 1616 1369450
+1 93 1 1 70 100 1169 61 47 0.60 2.20 30737 21237 1.20 3.80 10.20 14.80 0.00 0.60 1.00 61.00 79.20 1.0 139 1061795
+1 83 1 1 133 131 3828 283 224 0.60 0.60 364223 169192 0.00 0.00 0.00 0.00 0.00 7.77 9.76 75.50 134.26 1.3 1070 1010744
+1 97 1 1 0 0 927 95 54 0.00 0.00 2205 9319 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.80 3.60 2.0 2527 1700784
+1 75 1 1 35 47 4549 608 456 3.20 1.00 124709 48059 3.20 5.20 6.20 1.80 0.80 10.60 15.00 178.80 316.40 2.3 172 1100077
+1 91 1 1 20 27 1359 268 179 1.20 2.40 172460 22644 0.00 0.00 0.00 0.00 0.20 1.80 2.20 97.60 132.40 3.0 404 1712434
+1 91 1 1 2 0 3520 178 147 0.40 0.40 116102 53455 0.20 0.40 0.40 0.00 0.60 5.20 10.20 36.20 47.80 2.8 389 1067304
+1 94 1 1 21 19 1446 156 87 0.20 0.20 232432 53083 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.20 23.20 4.6 2734 1603858
+1 93 1 1 19 24 961 151 124 2.20 0.80 71986 28290 0.00 0.00 0.00 0.00 0.00 3.00 5.80 112.00 157.00 2.6 852 1704750
+1 95 1 1 3 3 1290 118 88 0.20 0.20 20182 53300 0.00 0.00 0.00 0.00 0.00 0.20 0.20 27.60 30.80 1.0 2118 1047573
+1 97 1 1 2 0 278 59 41 0.20 0.20 1558 13630 0.00 0.00 0.00 0.00 0.00 0.20 0.20 19.00 22.20 1.0 6479 1856891
+1 0 1 1 7 5 1019 75 44 0.20 0.20 167825 17102 1.00 1.20 1.20 0.00 0.40 4.79 7.98 19.96 51.70 184 95 5
+1 79 1 1 33 15 4954 287 213 1.20 1.20 302830 82599 0.00 0.00 0.00 0.00 1.60 1.60 2.20 69.60 308.40 6.8 1435 1307883
+1 90 1 1 13 5 1096 98 67 2.00 2.99 16596 26431 0.00 0.00 0.00 0.00 0.20 2.79 3.59 99.40 157.88 1.8 1345 1016145
+1 73 1 1 93 123 3393 430 325 3.00 1.20 485834 161780 10.20 22.60 43.80 55.00 3.60 34.60 42.60 169.80 427.60 6.2 222 1292978
+1 98 1 1 2 1 206 14 31 0.20 0.20 7000 14343 0.00 0.00 0.00 0.00 0.00 0.80 1.40 15.60 18.40 1.0 8188 1864384
+1 89 1 1 3 1 477 35 30 2.20 2.20 77144 25437 0.00 0.00 0.00 0.00 0.00 13.40 26.20 221.60 211.40 1.2 8588 1833952
+1 97 1 1 9 8 1079 59 51 0.20 0.20 8296 31390 0.00 0.00 0.00 0.00 0.40 5.80 6.00 15.60 33.00 1.2 1569 1081923
+1 98 1 1 1 1 171 16 15 0.20 0.20 7578 2380 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.23 16.83 2.0 9865 1873443
+1 93 1 1 24 37 1195 140 67 0.20 0.20 197189 16598 1.80 1.80 1.60 0.00 3.60 8.20 9.00 28.60 53.40 4.7 330 992792
+1 78 1 1 6 0 4876 443 331 5.20 1.60 473486 62373 2.00 2.60 2.40 0.00 1.80 6.00 10.60 253.60 405.00 2.0 226 1115813
+1 93 1 1 2 1 1098 24 39 1.00 1.60 18446 13224 0.00 0.00 0.00 0.00 0.00 0.20 0.20 77.40 105.60 1.2 7034 1845005
+1 91 1 1 1 0 906 91 50 0.20 0.20 2541 21618 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 17.60 1.6 990 1761512
+1 94 1 1 5 1 676 104 56 0.80 0.80 22221 13409 1.00 1.00 1.00 0.00 1.00 0.00 0.00 61.40 83.80 1.0 232 1747290
+1 70 1 1 10 1 5002 580 433 7.60 2.00 676779 76726 4.80 8.20 8.00 0.00 3.40 14.60 24.60 373.00 579.20 1.8 253 1115773
+1 88 1 1 17 17 3042 424 166 0.80 0.80 638349 604780 3.39 5.79 5.79 0.00 0.40 11.18 11.38 59.08 127.35 1.7 229 1041536
+1 93 1 1 2 0 1524 107 106 0.20 0.20 6493 72539 0.00 0.00 0.00 0.00 0.00 10.80 15.60 15.80 28.00 1.0 1921 1112656
+1 77 1 1 15 3 3760 718 501 4.00 3.00 378705 122879 0.00 0.00 0.00 0.00 0.00 0.00 0.00 192.20 289.60 5.6 2921 1602693
+1 91 1 1 21 31 1622 104 58 0.60 2.20 366070 61248 0.00 0.00 0.00 0.00 0.00 0.20 0.40 52.00 54.00 2.8 6658 1825005
+1 77 1 1 7 5 4324 723 264 2.60 9.00 532078 21737 0.00 0.00 0.00 0.00 0.00 3.60 4.20 193.60 262.60 3.4 2486 1409182
+1 95 1 1 0 0 2281 102 142 0.20 0.20 5975 20690 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 17.20 2.0 843 1721008
+1 92 1 1 3 0 1359 149 112 0.80 0.40 16723 25838 3.00 3.00 3.00 0.00 0.40 1.40 1.40 52.00 67.40 2.0 246 1118432
+1 76 1 1 19 9 4223 412 393 6.60 2.60 173798 95760 0.00 0.00 0.00 0.00 0.00 13.40 14.00 340.40 524.40 1.7 1119 1058566
+1 94 1 1 4 1 1048 57 70 1.00 0.80 44646 75392 0.00 0.00 0.00 0.00 0.00 0.00 0.00 46.40 56.00 2.4 1342 1546405
+1 90 1 1 5 0 1429 225 184 3.60 1.00 182598 11768 0.40 0.40 0.40 0.00 0.80 0.20 0.20 188.20 273.20 2.4 330 1717701
+1 80 1 1 21 4 6398 247 179 2.20 6.60 181309 55825 0.00 0.00 0.00 0.00 0.20 13.60 18.80 148.00 306.00 4.0 635 1529202
+1 93 1 1 1 0 1564 175 110 0.40 0.20 6163 22276 0.80 1.20 1.20 0.00 0.00 2.20 2.40 22.00 49.20 1.0 239 1099744
+1 94 1 1 37 41 1858 84 69 0.40 0.80 7765 60755 0.00 0.00 0.00 0.00 0.00 0.00 0.00 32.00 46.40 2.0 833 1643795
+1 74 1 1 128 51 2429 355 346 1.60 3.00 661653 450703 28.00 113.00 188.80 361.80 2.40 57.80 105.60 125.40 222.00 2.0 132 1016723
+1 91 1 1 12 10 1468 119 90 1.20 1.60 29347 18501 0.00 0.00 0.00 0.00 0.00 1.80 1.80 82.36 122.65 2.8 964 978007
+1 81 1 1 19 0 2287 235 131 0.40 1.40 210667 135817 12.00 71.20 141.60 330.00 0.20 33.60 65.80 56.60 133.80 3.8 146 1112992
+1 71 1 1 88 102 5375 463 301 1.40 2.61 380129 173613 5.01 15.03 21.24 31.46 5.21 41.68 66.93 85.77 287.17 3.4 418 1033974
+1 94 1 1 15 11 564 53 36 1.00 1.40 80003 38957 0.00 0.00 0.00 0.00 0.00 1.80 2.81 51.10 81.76 1.0 6876 1864968
+1 0 1 1 23 21 2458 180 137 0.40 0.40 11664 33798 0.00 0.00 0.00 0.00 0.00 2.20 2.20 31.80 187.80 362 94 6
+1 84 1 1 2 1 2695 222 152 1.20 1.80 241693 134072 6.79 12.97 9.78 0.00 2.79 21.36 31.14 74.65 210.78 2.0 529 1007079
+1 84 1 1 28 2 3169 160 128 2.40 5.20 258909 77744 0.00 0.00 0.00 0.00 0.00 6.20 6.20 164.80 200.00 3.4 1787 1644523
+1 87 1 1 2 1 2768 210 232 0.40 0.40 320031 216650 0.00 0.00 0.00 0.00 0.00 2.60 3.00 43.40 62.20 3.8 3419 1427370
+1 75 1 1 8 0 3782 498 428 7.20 2.20 181646 22390 0.20 0.20 0.20 0.00 0.00 0.80 0.80 349.00 611.60 1.5 370 1028214
+1 95 1 1 47 65 2181 78 86 0.20 0.20 16114 88636 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.20 2.4 760 1645581
+1 88 1 1 6 0 1978 424 307 2.40 0.80 197951 25163 0.00 0.00 0.00 0.00 0.20 1.20 1.80 123.60 193.60 2.6 1361 1072078
+1 90 1 1 5 4 2718 265 190 0.20 0.20 146000 94479 17.20 22.20 22.00 0.00 13.60 2.40 2.40 25.20 82.60 1.2 243 982323
+1 94 1 1 12 11 1351 121 113 0.20 0.20 231592 84571 0.00 0.00 0.00 0.00 0.00 3.80 4.20 18.20 59.60 2.6 976 1086653
+1 66 1 1 28 19 6195 1218 991 6.19 6.59 927159 775752 0.00 0.00 0.00 0.00 0.20 2.79 6.99 348.10 595.21 1.3 778 1077009
+1 85 1 1 68 40 1263 197 123 2.00 3.40 253418 116677 0.00 0.00 0.00 0.00 0.00 0.80 0.80 138.40 259.60 2.6 3505 1823155
+1 93 1 1 0 0 2525 91 72 0.20 0.20 3022 16676 1.40 1.40 1.40 0.00 0.20 0.20 0.20 15.37 33.93 1.0 158 1065222
+1 97 1 1 0 0 812 132 81 0.20 0.20 15160 17977 0.00 0.00 0.00 0.00 0.00 0.80 0.80 54.80 20.80 2.0 1875 1074955
+1 73 1 1 17 4 3846 336 330 4.99 3.79 556898 415572 1.40 1.60 6.19 16.57 0.20 35.53 70.26 251.70 365.07 6.8 461 1544899
+1 64 1 1 30 8 4113 479 348 10.00 18.20 239482 38730 9.20 42.60 72.20 191.00 7.40 36.00 37.60 494.00 847.00 1.7 210 1083712
+1 80 1 1 10 1 3895 359 194 2.40 4.00 355931 141785 0.00 0.00 0.00 0.00 0.00 25.80 32.00 180.00 470.60 5.6 1242 1339760
+1 91 1 1 0 0 313 26 33 0.20 0.20 22208 30376 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.60 1.4 1857 1767232
+1 92 1 1 23 33 4590 91 120 0.20 0.20 79232 53278 5.41 9.82 17.03 26.65 0.20 1.40 2.20 14.43 48.10 1.0 119 1016200
+1 81 1 1 28 16 3269 431 269 2.59 7.39 503221 204217 3.79 6.99 20.76 32.53 1.20 15.97 28.34 121.56 209.58 5.4 150 1534435
+1 92 1 1 2 0 2115 125 85 0.20 0.20 29926 24886 2.40 3.20 3.00 0.00 0.00 5.00 7.60 15.80 44.80 2.4 188 1087811
+1 94 1 1 18 8 901 78 58 0.60 0.60 128052 21829 0.00 0.00 0.00 0.00 0.00 2.79 2.79 43.31 115.37 1.6 631 968121
+1 98 1 1 0 0 484 37 29 0.20 0.20 7835 10182 1.80 1.80 1.80 0.00 0.00 0.00 0.00 15.63 16.83 1.0 180 1746769
+1 88 1 1 3 2 2547 250 119 1.00 2.60 265377 23343 8.00 10.60 18.60 27.00 16.40 0.40 0.40 118.60 132.60 4.6 173 1072302
+1 80 1 1 40 55 5497 160 103 1.40 1.80 31832 42627 5.60 7.20 7.20 0.00 3.80 3.60 4.40 137.00 144.40 3.4 325 1445446
+1 87 1 1 3 0 1997 257 160 2.60 0.80 540001 106074 0.00 0.00 0.00 0.00 0.00 0.00 0.00 127.20 181.20 4.8 1468 1756045
+1 98 1 1 0 0 234 43 13 0.20 0.20 265827 10854 0.00 0.00 0.00 0.00 0.00 0.00 0.00 18.00 17.00 1.2 8602 1865776
+1 0 1 1 11 1 3556 348 267 3.40 2.20 225660 113178 6.80 13.40 67.80 107.60 0.20 11.60 21.20 219.80 416.60 171 73 27
+1 80 1 1 9 7 3711 208 121 2.20 7.80 193836 177797 0.00 0.00 0.00 0.00 0.00 0.60 0.80 191.60 219.60 3.2 2513 1582630
+1 89 1 1 6 0 2424 239 155 1.80 1.80 13184 34056 0.00 0.00 0.00 0.00 0.00 3.41 3.81 73.15 203.41 1.0 545 1023155
+1 89 1 1 2 0 1790 127 73 1.80 2.20 137017 28650 4.39 4.79 4.79 0.00 1.80 31.14 32.93 121.56 219.56 2.2 283 1052872
+1 92 1 1 6 1 2282 125 125 1.20 1.40 48385 63513 0.00 0.00 0.00 0.00 0.00 2.00 2.40 102.40 105.40 4.2 2743 1531896
+1 83 1 1 31 18 3012 183 102 1.00 1.00 173124 55477 0.00 0.00 0.00 0.00 0.00 23.60 62.00 57.00 259.00 2.8 5375 1416432
+1 92 1 1 2 0 1861 223 120 0.80 0.60 232693 29510 0.00 0.00 0.00 0.00 0.60 4.60 4.80 56.20 136.60 2.2 434 1104610
+1 69 1 1 98 63 2605 303 217 8.20 21.80 535376 133157 3.20 17.40 49.20 84.00 1.40 8.60 9.80 363.40 709.80 1.5 441 1098037
+1 82 1 1 72 38 3563 135 109 2.20 7.40 77168 55026 9.80 22.40 32.60 25.40 4.00 14.60 25.00 175.60 211.20 4.4 146 1598184
+1 68 1 1 40 3 4682 294 173 8.38 19.36 162052 55293 4.19 7.58 25.95 49.30 1.80 5.59 8.78 327.15 560.28 4.0 151 1107687
+1 91 1 1 0 0 601 120 49 0.20 0.20 454452 13125 0.00 0.00 0.00 0.00 0.00 50.80 101.60 18.00 169.80 2.8 1659 1733061
+1 73 1 1 20 11 3691 396 270 2.60 1.60 255211 84733 0.00 0.00 0.00 0.00 0.00 12.80 15.80 165.60 365.40 5.6 8426 1373406
+1 95 1 1 7 14 1497 69 69 0.20 0.20 11560 34500 1.00 1.00 1.00 0.00 0.40 1.00 1.00 15.00 20.80 1.2 151 1750891
+1 72 1 1 16 0 2382 128 77 7.41 20.64 90058 25881 0.20 0.20 0.20 0.00 0.00 13.63 19.84 266.13 495.79 1.0 471 1079901
+1 91 1 1 6 5 3402 106 99 0.60 0.60 23385 58740 1.80 1.80 1.80 0.00 0.60 1.20 2.00 49.20 115.40 1.7 326 989523
+1 91 1 1 6 2 2352 190 100 0.60 0.80 484452 29922 2.00 2.00 2.00 0.00 4.40 10.20 12.80 50.20 119.80 1.0 209 1026242
+1 83 1 1 14 8 3554 360 281 2.59 2.99 213151 89146 0.00 0.00 0.00 0.00 0.00 16.97 17.96 121.76 283.43 1.0 1389 1109887
+1 77 1 1 3 1 3614 233 180 1.60 3.21 261234 80077 4.41 4.81 5.61 1.20 0.60 29.46 38.08 124.65 250.70 1.5 435 1117693
+1 90 1 1 5 4 5427 247 221 0.40 0.40 11161 16785 0.00 0.00 0.00 0.00 0.00 0.60 0.60 34.20 52.60 2.2 429 1377768
+1 75 1 1 12 0 4838 583 646 6.59 4.99 679610 63248 0.00 0.00 0.00 0.00 0.00 2.20 3.59 292.42 465.47 6.0 1836 1694959
+1 96 1 1 2 0 817 43 73 0.40 0.80 102203 26343 0.00 0.00 0.00 0.00 0.20 2.00 2.20 34.40 47.60 1.3 494 1014829
+1 80 1 1 1 0 3438 398 213 0.60 1.80 1376248 345348 7.20 8.20 8.20 0.00 7.40 2.00 2.40 45.60 186.80 1.2 222 1019029
+1 87 1 1 8 3 1693 238 205 4.60 1.80 108650 7332 0.00 0.00 0.00 0.00 0.40 0.00 0.00 239.60 337.00 2.2 414 1717702
+1 80 1 1 10 2 2904 404 193 6.40 6.40 533415 300560 0.00 0.00 0.00 0.00 0.00 0.80 1.00 423.00 483.80 3.2 8710 1864650
+1 89 1 1 18 3 3307 175 111 1.60 1.60 128997 53305 0.00 0.00 0.00 0.00 0.00 0.40 0.40 92.20 144.40 4.8 702 1522429
+1 91 1 1 2 0 340 28 18 2.00 2.00 51800 20787 0.00 0.00 0.00 0.00 0.00 2.40 4.00 178.80 156.60 1.0 8092 1868448
+1 99 1 1 1 1 154 8 12 0.20 0.20 7001 10981 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 1.0 7265 1875328
+1 64 1 1 66 53 4338 354 220 6.97 19.12 207848 84626 4.98 25.30 65.14 164.54 0.60 21.51 33.47 298.80 545.42 3.0 159 1094373
+1 87 1 1 4 2 445 41 15 2.00 2.00 89005 17012 0.00 0.00 0.00 0.00 0.00 3.41 5.61 206.01 164.93 1.2 11753 1891069
+1 86 1 1 1 0 3402 193 212 0.60 0.80 32898 530532 3.99 5.99 5.99 0.00 0.20 0.40 0.60 41.72 80.84 4.0 168 1008651
+1 87 1 1 4 1 4437 722 402 0.40 1.80 49022 91833 3.60 7.40 19.60 25.20 0.60 5.00 7.00 33.20 82.40 1.0 325 1074453
+1 97 1 1 6 2 239 35 31 0.20 0.20 109650 6671 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.80 17.40 2.0 4694 1847805
+1 94 1 1 10 9 1370 136 86 0.20 0.20 121256 47389 1.00 3.20 5.00 9.60 6.00 0.60 0.60 20.40 60.20 2.0 133 1072768
+1 81 1 1 4 2 5139 461 382 1.20 4.20 35171 532139 0.00 0.00 0.00 0.00 0.00 8.20 8.60 100.20 160.80 1.0 861 995771
+1 91 1 1 3 1 704 55 51 1.80 2.00 8530 11424 0.00 0.00 0.00 0.00 0.00 0.20 0.20 75.80 127.20 1.6 590 1759749
+1 78 1 1 23 15 4420 229 168 1.60 10.40 86381 69422 10.40 20.80 29.60 38.00 6.40 3.40 4.60 251.60 222.20 7.8 153 1292285
+1 78 1 1 10 1 3338 478 417 8.60 2.40 328815 18709 0.00 0.00 0.00 0.00 0.00 0.00 0.00 434.60 629.00 2.8 7381 1874141
+1 74 1 1 1 0 2697 271 258 1.80 2.40 770736 548396 0.00 0.00 0.00 0.00 0.00 62.28 106.99 131.94 245.31 4.8 1241 1000888
+1 97 1 1 15 23 200 16 19 0.20 0.20 3376 1612 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.0 7250 1861542
+1 88 1 1 21 5 968 86 106 1.00 1.00 11050 43365 19.64 41.68 103.41 217.03 9.02 15.63 25.45 119.24 231.66 4.0 464 972561
+1 82 1 1 42 51 3598 192 152 1.00 1.00 326100 239844 1.60 4.81 18.44 41.28 0.80 13.63 43.29 130.26 193.59 1.4 249 1014642
+1 94 1 1 11 5 1293 102 90 0.60 0.80 21387 22319 0.00 0.00 0.00 0.00 0.00 0.80 0.80 48.40 147.60 2.0 993 973275
+1 97 1 1 1 0 355 24 21 0.80 0.80 18370 3178 0.00 0.00 0.00 0.00 0.00 0.40 0.40 50.60 73.80 1.0 7309 1864419
+1 88 1 1 2 0 2486 284 256 2.60 4.80 134314 55197 1.00 1.00 3.40 6.20 0.80 3.40 3.80 150.40 223.00 4.0 245 1055248
+1 95 1 1 57 56 958 130 86 0.60 0.40 56797 50759 4.20 16.60 31.60 59.20 1.20 1.40 3.20 41.20 79.20 2.8 175 991931
+1 85 1 1 45 54 2320 116 89 2.00 2.80 124687 63844 15.20 18.00 18.80 3.00 13.60 12.20 19.20 129.40 224.60 3.0 170 1533677
+1 74 1 1 31 22 4119 203 315 6.19 18.96 74396 49147 3.59 4.39 4.19 0.00 0.20 1.60 1.60 200.00 379.44 1.2 316 1083757
+1 89 1 1 42 60 1256 88 89 0.60 1.80 101694 34680 0.00 0.00 0.00 0.00 0.00 4.01 7.82 44.89 77.15 2.0 973 1130743
+1 87 1 1 7 2 1561 84 56 0.80 2.40 124456 336573 0.00 0.00 0.00 0.00 0.00 6.00 11.40 40.00 61.00 1.2 6601 1851443
+1 92 1 1 9 9 1323 104 90 0.60 0.60 21111 20767 0.40 0.40 0.40 0.00 1.00 4.80 4.80 49.00 100.60 1.0 204 1118088
+1 94 1 1 4 1 1882 86 82 0.80 1.00 101904 27502 0.00 0.00 0.00 0.00 0.00 6.20 6.20 68.40 93.60 4.4 6508 1411128
+1 98 1 1 1 1 196 41 22 0.20 0.20 285750 259748 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.20 17.40 3.2 3656 1820056
+1 97 1 1 32 44 152 8 10 0.20 0.20 6995 8957 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 1.0 7550 1878208
+1 93 1 1 10 9 1844 192 125 0.60 0.60 25148 51077 0.00 0.00 0.00 0.00 0.20 27.00 27.00 27.40 101.80 1.5 1623 1040469
+1 80 1 1 518 8 1623 107 102 2.40 0.80 73351 37095 0.00 0.00 0.00 0.00 0.00 111.60 112.00 120.20 173.00 1.4 3024 1845179
+1 91 1 1 9 7 1755 190 169 0.80 0.40 16544 26314 0.00 0.00 0.00 0.00 0.00 0.80 0.80 54.60 86.00 1.8 447 1131064
+1 72 1 1 55 67 5296 695 423 6.80 2.40 270206 78483 2.20 4.20 3.80 0.00 0.80 4.80 5.60 352.40 564.00 2.0 228 1114467
+1 90 1 1 3 1 1952 147 94 0.60 2.60 48430 37008 2.20 6.20 10.80 13.40 0.40 1.20 1.40 63.80 71.60 1.3 185 1081821
+1 94 1 1 3 0 845 73 59 0.40 0.60 136822 23071 6.60 21.80 48.40 89.00 0.80 0.60 3.00 29.80 93.00 1.8 206 987451
+1 80 1 1 7 2 3068 433 327 5.20 1.40 203964 95184 0.00 0.00 0.00 0.00 0.00 1.40 1.40 241.40 354.20 6.2 4007 1605390
+1 92 1 1 0 0 2287 69 72 0.20 0.20 4922 12462 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 8353 1864864
+1 91 1 1 30 3 1708 139 125 1.40 1.20 66870 45771 1.00 1.00 1.00 0.00 1.00 1.80 1.80 83.40 126.40 2.2 253 1530205
+1 81 1 1 31 3 3748 343 276 5.60 5.20 161126 93390 0.00 0.00 0.00 0.00 3.20 4.00 4.60 220.60 432.60 2.2 534 1073170
+1 85 1 1 9 3 4092 159 161 1.20 1.60 46573 154843 0.00 0.00 0.00 0.00 0.20 1.20 1.20 122.00 116.40 2.2 368 1522917
+1 97 1 1 1 1 198 18 20 0.20 0.20 7026 4055 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 8901 2243187
+1 97 1 1 0 0 719 60 60 0.20 0.20 7281 19696 0.00 0.00 0.00 0.00 0.00 0.20 0.20 17.96 23.55 1.0 1124 1060267
+1 98 1 1 0 0 220 19 18 0.20 0.20 1977 9515 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.57 21.16 1.0 1904 1750683
+1 78 1 1 25 7 3713 151 90 4.80 10.00 290336 81955 0.00 0.00 0.00 0.00 0.00 1.40 1.80 304.60 349.60 3.4 1431 1541880
+1 83 1 1 106 98 4116 234 194 1.60 5.20 246490 119184 0.00 0.00 0.00 0.00 0.00 3.60 4.20 124.60 236.40 1.3 950 1002078
+1 90 1 1 4 2 1959 214 126 0.60 1.79 117352 23063 0.00 0.00 0.00 0.00 0.20 4.77 4.97 43.54 69.58 1.0 776 1118409
+1 91 1 1 8 5 1111 156 128 0.40 0.60 215802 17088 6.21 15.03 40.68 205.01 3.41 69.74 70.94 29.46 180.56 2.5 244 974036
+1 95 1 1 14 13 953 129 57 0.20 0.20 167995 177470 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 53.60 3.0 1218 1746349
+1 94 1 1 1 0 1661 147 170 0.20 0.20 10165 101683 0.00 0.00 0.00 0.00 0.00 3.40 4.00 13.00 53.60 1.0 369 1061306
+1 74 1 1 24 15 3210 228 191 6.81 18.64 232219 100561 5.81 12.22 22.24 33.87 12.42 12.22 16.03 283.77 570.94 1.0 192 1093629
+1 88 1 1 1 0 519 34 29 2.00 1.60 18989 18822 0.00 0.00 0.00 0.00 0.00 0.00 0.00 77.00 105.40 2.0 977 1765294
+1 76 1 1 187 202 4014 514 384 3.80 1.00 183906 106306 2.20 3.60 3.60 0.00 0.20 6.00 6.20 190.60 354.60 2.0 300 999016
+1 89 1 1 26 20 2253 148 68 1.40 1.40 286052 33031 0.00 0.00 0.00 0.00 0.00 9.40 11.00 73.60 279.20 3.6 7579 1379354
+1 94 1 1 74 39 946 113 127 0.20 0.20 185780 145380 3.60 19.60 33.20 31.00 1.20 8.00 28.20 25.20 34.20 4.4 132 1597397
+1 88 1 1 0 0 328 48 44 0.20 0.20 139217 9468 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.80 17.00 2.0 621 1758632
+1 96 1 1 34 49 481 46 40 0.40 1.80 4978 18275 1.40 1.60 1.20 0.00 0.60 0.20 0.20 20.84 36.47 1.0 243 1026964
+1 98 1 1 0 0 1792 60 72 0.20 0.20 3164 8671 0.60 0.60 0.60 0.00 0.20 0.20 0.20 14.80 22.80 2.2 315 1715520
+1 96 1 1 11 8 1392 68 56 0.60 0.60 6614 19602 0.00 0.00 0.00 0.00 0.00 0.20 0.20 46.89 49.90 2.2 1165 972803
+1 90 1 1 1 0 1522 185 143 0.80 1.00 24539 44745 0.00 0.00 0.00 0.00 0.00 0.00 0.00 58.80 91.40 1.0 687 1120960
+1 90 1 1 11 2 2434 123 111 0.80 0.80 49585 46772 4.99 6.99 6.99 0.00 1.80 4.19 7.58 58.48 101.60 2.0 237 1051034
+1 98 1 1 0 0 158 12 23 0.20 0.20 443 8217 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 1.0 3739 1849659
+1 97 1 1 20 13 1056 93 67 0.40 0.40 25620 42410 0.00 0.00 0.00 0.00 0.00 1.00 1.00 31.40 43.80 2.2 2434 1726120
+1 91 1 1 2 1 3118 299 167 0.40 0.20 194860 155593 0.40 0.60 0.40 0.00 0.20 1.80 1.80 23.80 33.00 5.6 2131 988368
+1 85 1 1 2 1 3673 359 167 0.80 0.80 260107 50871 6.40 8.00 8.00 0.00 0.80 7.00 11.80 78.60 108.40 1.7 393 1127054
+1 96 1 1 2 1 208 28 30 0.20 0.20 133961 93202 0.00 0.00 0.00 0.00 0.00 14.80 29.40 13.40 31.00 1.4 6191 1856795
+1 82 1 1 8 0 3585 214 137 1.80 3.40 138923 19446 0.00 0.00 0.00 0.00 0.20 36.60 36.60 151.20 333.40 1.5 725 966637
+1 0 1 1 10 4 2685 362 243 2.79 1.00 765585 659609 4.99 12.77 28.74 50.90 0.40 40.72 50.90 137.33 292.02 144 84 16
+1 78 1 1 28 18 4804 305 193 2.19 3.19 187500 56726 0.00 0.00 0.00 0.00 0.00 23.71 31.08 153.78 382.27 4.0 1279 1012456
+1 76 1 1 46 11 4580 117 97 4.80 11.00 66861 32358 0.00 0.00 0.00 0.00 0.00 2.40 2.80 286.20 370.20 3.2 1062 1537206
+1 86 1 1 12 5 3506 425 283 1.40 1.00 226175 186398 0.00 0.00 0.00 0.00 1.00 4.20 7.60 100.00 151.60 4.8 632 1550574
+1 91 1 1 7 5 2818 137 128 0.40 0.40 11207 32846 0.00 0.00 0.00 0.00 0.00 2.00 4.80 32.20 80.40 1.8 2034 969880
+1 85 1 1 30 15 2435 207 143 2.80 5.20 78379 63231 0.00 0.00 0.00 0.00 0.00 3.20 6.00 350.60 386.20 1.0 574 1073299
+1 93 1 1 13 11 1213 139 129 2.00 1.00 170892 33003 0.00 0.00 0.00 0.00 0.20 0.80 0.80 121.60 141.40 1.0 856 998221
+1 92 1 1 24 36 3436 162 101 0.20 0.20 43117 21185 0.80 0.80 0.80 0.00 0.20 0.20 0.20 16.00 22.20 3.2 180 1714208
+1 97 1 1 5 1 247 27 21 0.40 0.20 99815 10481 0.00 0.00 0.00 0.00 0.00 1.20 1.20 32.60 45.40 2.0 8117 1863984
+1 87 1 1 4 0 2548 266 208 2.59 1.60 237912 20143 1.40 1.80 1.80 0.00 2.20 9.18 9.58 144.51 216.57 2.0 334 1014651
+1 69 1 1 44 2 4527 402 224 5.40 15.20 319514 58917 4.60 36.00 91.00 279.60 0.00 53.80 95.80 190.80 430.00 3.5 132 1097944
+1 95 1 1 0 0 2443 74 72 0.20 0.20 7001 26941 4.60 6.40 6.40 0.00 0.00 1.40 1.60 15.60 79.60 3.2 195 1443330
+1 90 1 1 1 0 1541 146 118 0.60 0.80 28217 19883 0.60 2.20 7.40 17.20 0.00 14.60 16.00 37.80 65.60 2.7 167 1098957
+1 88 1 1 2 0 468 41 45 1.40 1.60 76117 44209 0.00 0.00 0.00 0.00 0.00 1.60 2.99 70.66 103.39 1.0 1668 1768097
+1 90 1 1 1 0 3931 261 217 0.60 0.80 108422 332231 0.00 0.00 0.00 0.00 0.00 9.80 18.00 51.20 82.60 2.2 1146 1395598
+1 97 1 1 0 0 401 58 47 0.20 0.20 1573 6755 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.40 17.00 2.2 563 1710728
+1 0 1 1 11 6 719 61 43 1.20 1.80 13076 15236 4.60 5.00 5.00 0.00 1.00 1.60 2.20 61.60 75.80 259 94 6
+1 95 1 1 2 0 751 93 85 2.00 1.60 38779 5145 0.00 0.00 0.00 0.00 0.00 0.00 0.00 107.78 143.71 1.2 7333 1860592
+1 92 1 1 19 27 744 71 78 0.20 0.20 74934 203418 0.00 0.00 0.00 0.00 0.00 8.00 15.80 16.20 18.20 1.2 4387 1821778
+1 61 1 1 20 3 6825 544 414 10.40 7.60 443725 60351 3.60 4.00 4.20 1.00 6.60 2.40 2.80 515.40 798.40 5.4 167 1509966
+1 85 1 1 2 1 525 95 52 2.00 2.00 326756 243185 0.00 0.00 0.00 0.00 0.00 5.60 10.60 156.00 150.40 2.6 3403 1822906
+1 92 1 1 6 5 1742 114 96 0.40 0.60 39603 19967 0.00 0.00 0.00 0.00 0.00 0.80 1.00 41.28 77.56 2.2 732 974256
+1 96 1 1 0 0 918 85 102 0.40 0.40 12093 24617 0.00 0.00 0.00 0.00 0.00 1.40 2.00 28.80 36.60 1.6 402 1060733
+1 85 1 1 17 5 1896 205 193 2.19 2.59 45718 41239 5.18 18.92 57.17 146.41 0.00 33.27 113.75 128.49 206.37 2.0 176 1050849
+1 88 1 1 198 195 1791 253 189 2.00 3.00 132619 97036 0.00 0.00 0.00 0.00 0.00 2.60 15.00 110.20 165.40 1.0 464 983346
+1 89 1 1 8 5 2119 175 110 0.60 1.00 73746 40532 5.20 14.80 31.40 54.60 1.00 10.40 10.60 77.20 163.80 2.4 147 1531090
+1 96 1 1 0 0 1758 116 166 0.20 0.20 49953 70743 5.79 10.78 7.98 0.00 0.60 0.40 0.60 15.57 29.54 2.0 274 1705742
+1 91 1 1 26 34 906 74 50 1.60 1.80 178551 25205 0.00 0.00 0.00 0.00 0.00 0.60 0.60 120.80 178.00 2.2 4532 1840355
+1 90 1 1 4 1 2941 171 130 2.20 2.60 129588 24635 3.20 3.60 3.60 0.00 1.00 2.20 2.40 105.40 157.60 2.8 310 1024850
+1 97 1 1 21 27 246 26 21 0.40 0.40 5274 11095 0.00 0.00 0.00 0.00 0.00 0.20 0.40 28.06 39.08 1.0 1905 1757582
+1 88 1 1 1 0 660 108 59 0.40 1.00 175527 166176 21.20 44.40 71.40 80.40 0.20 27.20 51.00 31.40 33.40 3.0 137 1719968
+1 95 1 1 4 4 1129 238 84 0.20 0.20 433947 226213 0.00 0.00 0.00 0.00 0.00 0.20 0.20 18.80 21.40 4.0 2551 1581917
+1 82 1 1 1 0 3848 259 222 0.60 1.40 218722 312753 0.00 0.00 0.00 0.00 0.00 6.99 7.19 50.90 247.90 1.0 384 1002692
+1 98 1 1 2 1 769 30 22 0.20 0.20 12571 5656 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 1.0 4621 1828405
+1 93 1 1 34 0 1377 82 82 1.80 0.80 34866 18090 0.60 4.40 5.80 6.60 0.40 0.80 0.80 102.00 147.80 1.0 163 1067130
+1 90 1 1 4 1 1999 170 154 2.80 0.80 130868 105798 0.00 0.00 0.00 0.00 0.00 0.80 1.60 138.80 202.80 1.8 7150 1856408
+1 81 1 1 8 1 2071 125 86 6.40 18.60 71609 38177 0.60 4.00 11.20 24.40 0.00 11.60 15.60 240.80 421.00 1.0 137 1076886
+1 96 1 1 0 0 334 70 32 0.20 0.20 384724 185229 0.00 0.00 0.00 0.00 0.00 1.20 1.20 16.20 23.40 2.8 991 1759528
+1 87 1 1 0 0 3577 505 217 0.20 0.20 12789 36746 1.20 1.20 1.20 0.00 0.20 16.80 16.80 16.40 52.80 2.0 175 1129958
+1 79 1 1 188 210 3051 152 268 1.80 2.80 39987 678400 4.00 4.20 4.20 0.00 1.00 2.80 3.80 96.00 183.00 2.7 271 998874
+1 81 1 1 6 1 1376 74 53 5.79 16.97 169845 16701 5.79 21.36 31.14 86.63 0.00 24.15 43.71 193.81 381.44 2.0 165 1102272
+1 96 1 1 3 2 499 64 48 1.20 1.20 73009 24372 0.00 0.00 0.00 0.00 0.00 0.00 0.00 62.80 92.40 2.6 674 1721486
+1 98 1 1 1 1 198 15 26 0.20 0.20 6998 11084 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 5274 1858256
+1 85 1 1 0 0 6707 278 213 0.20 0.20 30362 148179 3.99 8.38 12.77 15.57 0.40 1.20 1.40 15.37 44.31 2.6 135 1011721
+1 96 1 1 2 0 629 139 54 0.40 0.80 261274 6739 0.00 0.00 0.00 0.00 0.00 1.40 1.60 24.40 42.40 2.6 5874 1721307
+1 85 1 1 5 2 3162 147 108 3.00 6.40 137154 17985 0.00 0.00 0.00 0.00 0.00 7.40 10.60 214.20 301.40 4.4 2756 1418467
+1 90 1 1 2 1 4259 223 161 0.40 1.00 19185 99520 0.20 0.40 0.40 0.00 0.00 2.99 3.19 20.76 42.51 6.2 337 975016
+1 0 1 1 10 4 3000 259 168 1.00 5.80 1447130 1280788 0.00 0.00 0.00 0.00 0.00 2.80 4.40 71.60 80.60 543 87 11
+1 93 1 1 4 0 1056 95 119 0.20 0.20 33604 113845 0.00 0.00 0.00 0.00 0.00 7.80 10.40 20.80 49.20 2.5 467 1062845
+1 76 1 1 28 2 1483 148 111 6.60 20.20 338077 39781 8.80 25.80 70.00 277.00 2.00 67.20 71.60 225.20 504.60 2.0 132 1088853
+1 86 1 1 3 1 3081 286 212 0.80 1.60 411248 548836 0.00 0.00 0.00 0.00 0.00 9.40 10.60 64.80 136.40 1.6 902 1033120
+1 96 1 1 3 2 1126 136 106 0.20 0.20 11318 27334 0.00 0.00 0.00 0.00 0.00 2.20 2.20 17.23 61.72 3.0 422 993879
+1 69 1 1 869 12 3509 166 155 4.20 5.00 91358 144560 5.20 7.60 6.80 0.00 3.00 1.80 2.40 216.40 330.60 4.0 236 1513158
+1 97 1 1 0 0 177 11 24 0.20 0.20 992 23063 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 16.80 1.0 9300 1869232
+1 90 1 1 5 2 1687 224 163 0.20 0.20 277479 103797 3.99 5.79 5.79 0.00 46.11 3.99 5.19 17.37 32.53 3.0 177 1062338
+1 59 1 1 11 1 5215 1011 805 9.18 6.39 773878 391304 0.00 0.00 0.00 0.00 0.00 31.34 35.93 415.77 812.38 3.4 1426 1031578
+1 85 1 1 17 31 1298 151 192 0.40 0.40 472966 492728 5.20 28.60 83.80 274.60 0.00 56.60 113.20 33.20 51.80 2.0 344 1539426
+1 96 1 1 11 8 865 74 57 0.60 1.40 173603 38639 0.00 0.00 0.00 0.00 0.20 0.00 0.00 51.00 62.40 2.2 4847 1672862
+1 95 1 1 13 8 3154 125 96 0.20 0.20 49783 92992 0.40 0.40 0.40 0.00 0.80 2.60 3.00 30.80 28.40 2.0 1297 1395208
+1 81 1 1 20 22 2066 297 247 6.59 3.19 174105 10290 0.00 0.00 0.00 0.00 0.00 0.60 0.60 314.37 476.25 1.6 385 1753290
+1 90 1 1 3 0 3052 111 197 1.00 1.20 112750 473805 0.00 0.00 0.00 0.00 0.00 4.40 7.00 88.00 142.60 2.0 480 1386939
+1 91 1 1 4 2 1314 119 89 0.40 1.80 50000 41118 3.20 5.40 5.00 0.00 0.20 1.60 2.40 178.00 129.00 4.0 189 1029926
+1 88 1 1 11 5 2725 243 140 0.20 1.60 34737 61559 3.80 4.40 4.40 0.00 0.40 52.40 56.20 24.40 103.60 1.3 205 1107142
+1 89 1 1 10 8 1439 107 91 1.40 3.20 36486 21669 0.00 0.00 0.00 0.00 0.00 8.80 9.00 111.40 270.80 1.6 908 1132680
+1 87 1 1 231 137 1763 270 229 0.60 0.60 253410 163869 0.00 0.00 0.00 0.00 0.00 0.00 0.00 58.40 85.20 2.0 442 1012315
+1 76 1 1 7 0 1748 133 108 7.20 20.60 167537 56646 3.00 22.20 28.00 43.60 0.00 14.40 22.00 258.00 484.00 1.5 132 1104482
+1 95 1 1 1 0 489 86 64 0.80 1.00 129749 34764 0.00 0.00 0.00 0.00 0.00 1.60 1.60 48.20 71.20 2.6 966 1717426
+1 90 1 1 76 70 4243 291 210 2.00 0.60 233251 135677 1.80 8.00 15.00 26.60 0.00 8.80 20.40 100.00 176.60 4.2 154 1326290
+1 94 1 1 1 1 1429 87 67 0.20 0.20 7163 24842 0.00 0.00 0.00 0.00 0.00 1.60 1.60 15.77 30.74 1.2 1476 1021541
+1 91 1 1 7 0 2067 151 63 1.80 2.00 205488 170521 3.60 5.60 5.40 0.00 0.00 1.00 1.20 87.60 150.00 3.6 316 1331270
+1 85 1 1 60 81 3927 314 176 2.20 4.60 296949 133548 0.00 0.00 0.00 0.00 0.00 23.00 28.00 147.20 260.40 3.4 582 1445262
+1 96 1 1 1 0 639 142 128 0.20 0.20 13625 39037 3.80 6.40 6.20 0.00 1.00 0.20 0.20 19.80 20.00 3.4 389 1708934
+1 96 1 1 4 0 631 33 75 0.60 0.80 36707 84581 0.00 0.00 0.00 0.00 0.00 1.20 1.40 47.60 64.40 1.0 481 1065304
+1 93 1 1 1 1 1051 61 83 0.20 0.20 67916 350924 0.00 0.00 0.00 0.00 0.00 4.19 7.78 15.57 16.77 1.6 6837 1873536
+1 98 1 1 0 0 901 53 57 0.20 0.20 1300 20351 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.54 14.94 1.7 447 1041675
+1 94 1 1 1 0 1522 214 101 0.40 0.80 48317 22956 0.00 0.00 0.00 0.00 0.00 1.60 2.60 30.00 33.60 1.0 1792 1074664
+1 81 1 1 20 6 4211 276 206 2.80 3.20 210977 55356 4.60 12.80 20.40 33.40 2.60 22.20 47.40 170.80 430.00 1.0 280 978371
+1 62 1 1 48 2 3381 159 128 11.78 35.33 81817 53880 4.99 5.79 5.79 0.00 1.00 11.78 11.98 398.60 731.54 6.6 261 1093753
+1 67 1 1 114 100 2969 224 151 7.41 18.64 136034 84091 8.42 31.26 93.99 173.35 1.60 42.89 80.76 311.62 557.11 1.3 130 1074519
+1 90 1 1 7 2 1655 143 82 0.60 1.00 169343 32311 0.00 0.00 0.00 0.00 0.00 3.61 22.44 55.91 168.94 2.0 711 971296
+1 90 1 1 24 33 2750 160 140 0.80 0.20 27531 88516 0.00 0.00 0.00 0.00 4.40 0.20 0.40 17.40 28.40 2.6 1018 1647146
+1 86 1 1 16 11 4775 249 162 1.00 1.80 336027 29890 0.00 0.00 0.00 0.00 0.00 5.41 7.41 85.37 183.17 2.2 2037 969858
+1 0 1 1 11 7 1589 162 119 0.80 1.00 307837 255022 6.59 27.15 74.45 120.16 0.00 19.56 30.34 62.08 149.10 134 83 17
+1 93 1 1 1 0 345 47 41 0.80 0.80 82998 18250 0.00 0.00 0.00 0.00 0.00 15.97 18.36 45.71 96.01 2.2 854 1764458
+1 91 1 1 1 0 1908 313 141 0.20 0.20 158242 161640 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.80 17.00 5.6 4056 1606056
+1 83 1 1 7 0 4421 349 391 4.60 1.60 118190 23704 0.00 0.00 0.00 0.00 0.00 0.80 0.80 217.80 321.80 5.0 2105 1719128
+1 92 1 1 1 0 420 28 58 1.80 1.80 38630 72092 0.00 0.00 0.00 0.00 0.00 1.40 2.40 142.60 138.80 1.2 12027 1889014
+1 94 1 1 7 1 773 71 55 1.40 3.60 11998 5884 0.00 0.00 0.00 0.00 0.00 0.80 0.80 124.20 141.60 2.0 6258 1710963
+1 95 1 1 1 0 1130 96 49 0.20 0.20 106879 15422 1.80 5.40 11.00 23.80 0.40 13.20 13.80 16.00 55.60 2.0 134 1013482
+1 97 1 1 0 0 742 20 20 0.20 0.20 5277 9899 0.00 0.00 0.00 0.00 0.00 0.80 1.40 15.60 16.80 1.0 4601 1828424
+1 92 1 1 9 8 3206 105 70 0.20 0.20 5415 33582 0.00 0.00 0.00 0.00 0.00 2.40 2.40 23.80 21.40 1.2 2912 1011918
+1 76 1 1 5 0 3661 363 371 3.81 1.20 334091 139933 6.21 12.22 10.02 0.00 0.00 10.42 12.02 184.17 334.47 1.7 377 1036935
+1 94 1 1 6 1 1791 256 161 1.00 2.40 73757 43555 0.00 0.00 0.00 0.00 0.00 0.20 0.20 74.40 100.40 3.4 2889 1548859
+1 92 1 1 12 10 2363 121 99 1.00 2.80 44871 20145 0.00 0.00 0.00 0.00 0.00 0.20 0.20 158.60 90.20 2.2 1094 1457250
+1 88 1 1 193 24 4132 660 420 0.60 0.60 225963 131040 7.20 47.00 71.60 112.40 1.60 9.00 10.20 42.00 130.80 3.8 151 1326901
+1 92 1 1 1 1 1408 188 131 0.60 0.40 321935 27929 0.00 0.00 0.00 0.00 0.00 6.59 11.98 34.13 47.90 3.6 480 1051839
+1 88 1 1 8 5 1834 121 109 2.59 5.38 54648 27728 1.59 1.59 1.59 0.00 1.79 3.98 4.38 108.17 239.04 2.0 329 1025321
+1 89 1 1 7 3 3021 190 108 2.80 6.60 112454 38502 2.00 3.60 3.20 0.00 1.00 9.00 11.00 129.20 234.60 1.3 355 1095077
+1 98 1 1 0 0 138 8 11 0.20 0.20 452 8586 0.00 0.00 0.00 0.00 0.00 0.20 0.40 20.20 17.20 1.2 1909 1754184
+1 77 1 1 8 1 7167 520 381 3.79 2.59 141684 51961 0.60 0.60 0.60 0.00 0.20 0.00 0.00 183.23 302.59 1.6 165 1063446
+1 98 1 1 1 0 139 11 16 0.20 0.20 433 12587 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 17.17 1.0 8475 1862328
+1 87 1 1 5 0 2807 198 142 1.40 2.60 270295 56991 0.00 0.00 0.00 0.00 2.40 24.60 37.60 104.20 156.20 2.8 906 1064958
+1 95 1 1 1 0 1755 156 129 0.80 0.80 15060 6223 0.00 0.00 0.00 0.00 0.00 1.60 2.60 52.60 83.80 2.2 336 1381960
+1 82 1 1 44 27 3547 196 129 3.80 4.40 127785 39678 0.00 0.00 0.00 0.00 0.20 2.20 2.20 237.40 414.00 1.7 687 1106726
+1 92 1 1 0 0 653 95 63 0.20 0.20 3396 18647 1.20 1.20 1.20 0.00 0.20 0.00 0.00 16.40 18.40 1.4 264 1757120
+1 75 1 1 10 0 3290 463 321 6.60 3.40 394348 64553 0.00 0.00 0.00 0.00 2.20 13.60 15.20 294.60 524.40 2.5 2681 1045133
+1 77 1 1 34 37 3359 497 412 8.40 2.20 453532 21230 1.40 1.40 1.40 0.00 2.00 0.00 0.00 407.80 586.40 2.6 165 1743528
+1 75 1 1 45 55 2511 159 112 7.20 20.40 69116 51134 0.20 0.20 0.20 0.00 0.80 11.00 17.00 253.00 434.20 1.8 367 1109370
+1 96 1 1 2 0 1306 85 90 0.20 0.20 22034 25816 0.00 0.00 0.00 0.00 0.00 3.20 5.20 14.80 65.80 5.4 1427 1075194
+1 91 1 1 5 1 2122 144 142 1.00 2.20 158643 53503 0.00 0.00 0.00 0.00 0.00 1.00 6.00 127.00 166.00 5.6 2202 1369078
+1 97 1 1 1 0 655 50 25 0.20 0.20 146677 13323 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 26.60 1.3 2988 1014718
+1 84 1 1 6 2 3132 388 156 1.00 3.00 427460 69115 4.60 7.40 6.20 0.00 16.20 3.20 5.00 99.20 242.40 1.4 862 1018798
+1 95 1 1 2 1 390 20 27 1.00 0.80 48696 71655 0.00 0.00 0.00 0.00 0.00 0.00 0.00 52.89 76.85 1.2 7474 1860794
+1 85 1 1 39 52 2470 237 175 2.60 1.00 149827 39404 0.00 0.00 0.00 0.00 0.80 17.80 18.20 145.20 312.40 1.5 2183 1036381
+1 97 1 1 2 1 161 15 15 0.20 0.20 20785 8860 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 3688 1822496
+1 0 1 1 11 5 1917 72 41 0.80 2.20 90772 26338 0.00 0.00 0.00 0.00 0.00 4.61 6.61 31.66 60.32 1041 92 8
+1 89 1 1 44 59 3218 306 196 1.60 2.00 234230 30845 0.00 0.00 0.00 0.00 0.00 4.80 7.40 90.60 157.40 1.0 527 981970
+1 96 1 1 15 14 526 81 48 0.40 0.60 115860 129640 0.00 0.00 0.00 0.00 0.00 0.00 0.00 31.40 42.00 3.6 909 1748992
+1 85 1 1 5 0 2641 265 216 3.40 1.00 84304 19404 1.40 1.40 1.40 0.00 0.60 33.60 34.20 257.40 373.00 1.3 240 1066467
+1 98 1 1 21 30 184 26 24 0.20 0.20 588 6136 0.40 0.60 0.60 0.00 0.00 0.00 0.00 16.23 16.83 1.0 305 1759367
+1 93 1 1 15 13 1720 151 92 0.60 1.00 340969 30999 0.00 0.00 0.00 0.00 0.00 6.80 12.40 53.00 85.00 1.5 400 979176
+1 96 1 1 1 0 684 59 62 0.20 0.20 2692 20480 0.00 0.00 0.00 0.00 0.00 0.40 0.40 21.16 28.34 1.8 786 1014446
+1 89 1 1 6 0 1601 84 49 5.00 16.20 43490 20837 3.40 4.00 3.80 0.00 2.80 0.80 1.40 141.80 267.20 2.2 192 1749606
+1 57 1 1 16 2 4734 576 492 14.12 20.28 246735 20236 2.19 7.55 17.50 43.74 0.60 8.35 10.74 591.65 993.44 1.5 189 1102007
+1 96 1 1 1 0 506 41 25 0.40 1.40 1401 4161 0.00 0.00 0.00 0.00 0.00 0.00 0.00 30.00 26.80 2.0 1350 1713304
+1 98 1 1 0 0 325 122 41 0.20 0.20 213523 167029 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 25.00 3.4 952 1753448
+1 68 1 1 41 1 3373 287 118 9.20 26.80 1067364 38192 6.00 19.20 39.20 106.60 9.20 13.60 17.40 310.40 641.00 3.0 159 1093850
+1 65 1 1 15 1 3140 216 158 13.20 34.00 290917 67225 0.00 0.00 0.00 0.00 4.80 2.20 2.40 468.20 820.00 1.0 364 1080395
+1 90 1 1 5 1 3584 133 157 0.20 0.20 7705 88398 0.00 0.00 0.00 0.00 0.00 0.80 0.80 16.17 56.69 1.0 686 1058842
+1 65 1 1 13 0 3936 303 130 10.40 30.80 179414 54004 6.80 12.20 22.80 27.60 0.40 16.80 27.80 347.20 695.60 1.0 209 1077893
+1 85 1 1 20 15 3672 347 230 0.80 0.80 190433 71105 4.00 4.60 4.60 0.00 6.60 7.00 21.40 124.20 190.80 2.6 419 995144
+1 92 1 1 5 4 2261 193 123 0.40 0.40 46972 154058 0.00 0.00 0.00 0.00 0.00 2.00 3.80 31.20 39.60 1.4 8466 1882056
+1 92 1 1 5 1 2956 109 90 1.20 1.20 51726 81322 0.00 0.00 0.00 0.00 0.60 1.80 1.80 92.00 119.80 2.6 1883 1649765
+1 91 1 1 0 0 363 52 52 0.20 0.20 51528 70717 0.00 0.00 0.00 0.00 0.00 3.20 3.80 15.60 18.80 1.2 2064 1767435
+1 91 1 1 18 16 1828 238 179 1.00 2.20 301884 138239 14.40 26.20 26.20 0.00 11.80 2.40 5.00 68.80 104.80 4.8 278 1606438
+1 79 1 1 10 1 3011 432 332 8.20 2.20 548223 9855 0.00 0.00 0.00 0.00 0.00 0.00 0.00 394.00 576.80 3.2 6812 1840608
+1 86 1 1 7 1 1871 196 181 4.19 3.39 127647 130529 0.00 0.00 0.00 0.00 0.00 0.00 0.00 199.20 281.84 1.0 8303 1832996
+1 88 1 1 10 0 1687 277 236 5.00 1.60 133461 7138 0.00 0.00 0.00 0.00 0.00 11.60 11.60 239.40 354.40 2.0 6313 1723896
+1 88 1 1 3 0 2335 257 251 0.80 2.20 153481 51172 1.00 1.40 1.40 0.00 0.20 9.00 14.60 65.20 115.40 3.0 227 1101150
+1 94 1 1 3 1 2241 84 107 0.40 0.80 46882 143333 0.00 0.00 0.00 0.00 0.00 0.20 0.20 34.40 43.40 2.0 770 1646266
+1 83 1 1 10 1 3301 345 236 3.40 1.40 310665 42670 7.60 18.60 43.40 116.40 0.60 7.20 10.60 168.60 303.60 7.4 171 1518701
+1 93 1 1 1 1 1543 315 160 0.20 0.20 106514 100867 0.00 0.00 0.00 0.00 0.00 3.80 3.80 18.00 26.60 5.8 3958 1605258
+1 93 1 1 8 0 3360 194 111 0.40 0.20 223067 128505 0.00 0.00 0.00 0.00 0.00 26.00 30.00 32.20 175.40 3.6 3731 1342350
+1 86 1 1 20 0 3711 291 167 1.80 1.80 428180 32595 1.20 14.20 19.60 43.40 0.20 20.80 22.00 110.80 160.00 1.2 131 1054350
+1 93 1 1 0 0 1505 207 150 0.40 0.40 148989 19610 0.80 0.80 3.80 11.00 1.20 2.80 2.80 32.60 69.80 3.0 179 1098778
+1 90 1 1 39 37 4800 455 259 0.20 0.20 274036 237469 0.00 0.00 0.00 0.00 0.00 8.20 13.20 14.60 45.40 3.2 3627 1332514
+1 97 1 1 2 1 1776 69 67 0.20 0.20 5274 52246 0.00 0.00 0.00 0.00 0.00 0.00 0.00 26.00 22.00 2.0 3173 1657160
+1 81 1 1 39 2 3204 353 221 0.60 0.60 136586 197932 8.02 66.53 156.31 263.93 0.40 60.92 88.98 107.41 278.16 2.2 128 1026091
+1 94 1 1 2 0 2035 98 66 0.80 0.80 104168 49244 0.00 0.00 0.00 0.00 0.00 0.40 0.40 63.40 87.80 2.2 4680 1727440
+1 91 1 1 11 1 697 135 80 2.40 2.80 64101 34394 0.00 0.00 0.00 0.00 0.00 0.20 0.20 105.20 181.40 2.2 6359 1703250
+1 93 1 1 47 59 414 178 71 0.20 0.20 299254 317256 0.00 0.00 0.00 0.00 0.00 0.60 1.20 15.60 19.00 2.4 5380 1826053
+1 93 1 1 5 4 3334 243 139 0.20 0.20 9967 55289 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 2.2 917 1646168
+1 81 1 1 5 4 3638 503 196 1.40 2.80 530100 252494 5.00 14.80 30.00 65.40 1.00 15.40 24.80 115.40 236.40 2.8 221 1025456
+1 98 1 1 1 1 217 19 29 0.20 0.20 12371 15195 0.00 0.00 0.00 0.00 0.00 1.00 1.80 15.60 16.80 1.0 7255 1875328
+1 97 1 1 1 0 253 24 14 1.00 5.60 57502 22233 0.00 0.00 0.00 0.00 0.00 0.20 0.20 33.00 49.20 2.0 4027 1821648
+1 95 1 1 7 2 846 45 71 0.20 0.20 1444 68532 0.00 0.00 0.00 0.00 0.00 0.60 0.80 17.03 20.84 2.0 655 1077505
+1 89 1 1 90 113 1083 100 88 1.80 1.60 47270 23513 0.00 0.00 0.00 0.00 0.00 0.20 0.20 121.40 229.60 2.0 1171 1077315
+1 94 1 1 2 1 1027 159 113 0.20 0.20 12193 86190 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 22.80 2.8 1974 1538989
+1 93 1 1 8 1 1895 175 159 1.80 0.80 92383 108629 0.00 0.00 0.00 0.00 0.00 0.00 0.00 103.00 148.40 2.2 5123 1674083
+1 97 1 1 1 1 247 28 35 0.20 0.20 10410 14684 0.00 0.00 0.00 0.00 0.00 0.60 1.00 15.60 16.80 1.0 5267 1858240
+1 82 1 1 33 4 2445 213 134 3.00 5.20 303584 124055 0.00 0.00 0.00 0.00 0.00 49.00 91.00 176.40 330.40 1.0 1066 1083290
+1 96 1 1 2 1 338 34 19 1.40 7.40 99771 34115 0.00 0.00 0.00 0.00 0.00 1.00 1.60 36.80 61.80 1.8 4292 1821627
+1 96 1 1 1 0 2118 77 54 0.20 0.20 5097 46649 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.80 18.40 2.0 776 1631770
+1 94 1 1 4 2 1453 103 86 0.60 0.60 9576 33300 0.00 0.00 0.00 0.00 0.00 1.40 1.60 52.00 68.80 3.2 751 1532051
+1 92 1 1 44 50 2470 96 84 1.20 1.20 38426 50268 0.00 0.00 0.00 0.00 0.00 0.40 0.40 109.40 118.80 2.4 1232 1636173
+1 81 1 1 1 1 6930 1136 656 0.80 1.20 133954 153745 3.20 5.40 5.40 0.00 1.60 1.60 2.00 58.80 86.00 2.6 189 1010837
+1 0 1 1 21 18 1111 157 164 0.60 0.80 188084 634890 0.00 0.00 0.00 0.00 1.20 1.20 4.20 55.40 129.40 1083 88 11
+1 82 1 1 31 33 1891 278 195 7.20 3.20 430255 14730 0.00 0.00 0.00 0.00 0.00 0.00 0.00 351.40 510.20 2.4 7870 1862782
+1 96 1 1 2 1 1046 103 117 0.20 0.20 92688 84068 0.00 0.00 0.00 0.00 0.00 0.60 0.60 17.00 19.60 1.0 564 1072352
+1 91 1 1 9 7 2014 127 150 0.60 2.20 192523 150917 2.60 16.20 26.40 66.00 2.60 7.20 13.40 57.20 115.20 1.0 182 1068709
+1 82 1 1 36 15 2306 208 225 4.20 14.60 307712 145811 5.40 18.80 47.60 72.80 2.00 6.00 10.80 283.20 387.20 6.0 200 1538973
+1 74 1 1 27 11 4766 860 490 3.60 6.80 116408 63010 2.00 2.20 2.20 0.00 1.00 6.60 7.00 221.60 320.60 2.6 368 1538506
+1 91 1 1 0 0 1423 325 278 0.40 0.40 9495 58622 3.20 3.40 4.60 2.00 0.00 0.00 0.00 30.20 39.40 2.0 138 1695530
+1 84 1 1 11 3 3207 442 260 1.00 1.20 33806 76858 6.20 18.60 35.60 71.20 1.20 12.60 14.00 81.80 237.60 2.5 152 1130134
+1 94 1 1 0 0 2219 148 116 0.20 0.20 32355 49411 0.00 0.00 0.00 0.00 0.00 8.20 8.20 15.80 55.40 1.0 544 1022382
+1 59 1 1 20 1 5777 677 569 11.80 5.80 500122 41626 9.00 23.60 51.80 109.60 1.80 8.80 13.20 647.00 1002.80 1.2 152 1024738
+1 75 1 1 24 16 1927 178 167 7.20 19.80 54727 70307 1.40 1.40 1.40 0.00 1.20 17.40 22.20 262.60 480.40 2.0 219 1106378
+1 97 1 1 0 0 303 93 46 0.20 0.20 14776 18949 0.00 0.00 0.00 0.00 0.00 1.40 2.60 15.60 17.00 1.0 5925 1863899
+1 90 1 1 12 12 4098 138 141 0.20 0.20 10405 26548 0.00 0.00 0.00 0.00 0.00 5.60 5.60 15.80 39.00 1.2 952 975870
+1 94 1 1 2 0 777 100 128 0.60 0.40 38511 29268 0.40 0.40 0.40 0.00 1.20 5.81 6.21 31.86 60.12 1.0 319 1093058
+1 90 1 1 1 0 3625 238 190 0.20 0.20 129097 122787 0.00 0.00 0.00 0.00 1.20 1.00 1.80 13.00 54.80 1.0 394 1069808
+1 96 1 1 0 0 881 94 45 0.20 0.20 2389 18464 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.77 17.17 1.0 685 1731202
+1 91 1 1 3 1 380 38 17 1.80 1.80 86640 20172 0.00 0.00 0.00 0.00 0.00 2.60 4.60 174.40 148.20 1.0 11396 1881704
+1 94 1 1 2 0 1002 93 81 0.40 0.60 21689 20743 1.00 1.00 1.00 0.00 0.00 21.40 22.40 30.40 85.60 1.5 320 1013824
+1 87 1 1 13 1 2022 116 84 1.00 4.40 15760 28782 3.20 3.20 4.20 2.20 0.20 29.20 35.60 81.60 161.60 2.4 286 1115763
+1 85 1 1 16 0 3041 284 188 1.20 1.20 191742 86046 8.42 24.25 59.52 119.24 0.00 36.87 58.72 106.41 204.61 1.0 148 978713
+1 88 1 1 28 22 2586 195 128 1.40 1.40 234850 107410 0.00 0.00 0.40 3.00 0.60 4.40 7.80 79.00 233.60 8.0 436 1317290
+1 92 1 1 1 0 2184 278 135 0.40 0.40 339524 188087 0.00 0.00 0.00 0.00 0.00 12.20 12.40 42.40 66.20 5.0 2834 1604205
+1 93 1 1 5 4 706 70 218 0.20 0.20 5138 794374 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.63 32.67 1.0 631 961905
+1 87 1 1 19 10 2090 256 96 1.20 1.60 863773 124296 10.98 14.77 14.77 0.00 10.38 4.79 6.59 159.48 145.51 1.7 602 990371
+1 88 1 1 0 0 1306 57 79 0.20 0.20 1475 10579 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.17 16.77 1.6 4107 1773341
+1 87 1 1 8 7 3288 257 175 0.20 0.20 34842 45553 3.60 5.40 5.40 0.00 0.40 20.80 20.80 27.20 87.00 2.6 259 968504
+1 91 1 1 14 3 2078 88 68 2.40 7.60 16209 70474 0.00 0.00 0.00 0.00 0.00 4.60 8.40 91.20 160.20 3.6 1780 1642589
+1 89 1 1 1 0 722 33 31 0.40 1.80 908 7635 0.00 0.00 0.00 0.00 0.00 0.60 0.60 23.80 26.20 3.4 521 1715288
+1 81 1 1 86 47 2365 291 270 2.60 5.80 242125 183977 0.00 0.00 0.00 0.00 0.00 62.60 73.20 160.20 311.20 1.0 649 1096326
+1 89 1 1 2 0 2990 198 139 0.20 0.20 54856 115878 0.00 0.00 0.00 0.00 0.00 1.20 1.40 28.80 43.20 4.8 548 1019227
+1 92 1 1 3 0 449 37 37 1.80 1.80 60822 68322 0.00 0.00 0.00 0.00 0.00 2.20 4.00 151.20 150.80 1.2 6239 1852714
+1 79 1 1 10 0 4754 756 720 2.40 0.80 598136 521849 2.20 5.80 11.60 16.40 2.80 11.40 34.20 126.60 185.80 2.8 181 1047442
+1 86 1 1 1 0 3861 298 138 1.20 2.61 297235 31839 0.00 0.00 0.00 0.00 0.60 13.43 14.03 149.30 215.83 3.0 498 1014899
+1 88 1 1 14 6 2394 203 148 2.60 2.00 127529 96304 0.00 0.00 0.00 0.00 0.60 8.20 8.40 137.20 298.20 4.6 2892 1560206
+1 82 1 1 19 17 3752 358 204 2.40 3.61 914154 563127 0.00 0.00 0.00 0.00 0.00 10.02 16.83 153.31 264.93 4.8 2603 1038966
+1 0 1 1 179 98 2391 319 265 0.40 0.40 310489 166378 4.99 15.37 15.17 0.00 2.40 1.20 5.19 48.90 72.46 286 88 12
+1 85 1 1 8 1 4348 228 156 1.60 3.39 176836 79761 7.78 18.56 18.56 0.00 0.00 7.98 11.58 107.19 287.43 2.0 697 981344
+1 79 1 1 5 4 3859 1148 216 1.00 0.80 515037 80371 22.60 126.80 146.40 335.00 0.00 58.80 110.60 62.80 187.00 1.6 143 1133149
+1 88 1 1 3 0 3980 451 180 0.60 0.60 27783 53049 0.00 0.00 0.00 0.00 0.00 1.00 1.60 43.60 76.40 1.3 553 1082528
+1 73 1 1 476 142 3768 618 528 1.60 5.80 553559 484708 28.00 135.20 143.40 42.80 5.80 32.40 60.20 96.60 305.40 1.0 177 1017134
+1 92 1 1 8 7 1359 61 56 0.80 4.00 11441 21004 1.60 3.20 6.00 12.00 1.20 10.20 10.20 60.40 120.60 3.0 151 1023602
+1 87 1 1 0 0 1140 228 133 0.40 0.20 27082 33187 0.00 0.00 0.00 0.00 0.00 0.60 1.00 17.60 19.80 1.6 1650 1766666
+1 82 1 1 28 1 2993 395 210 0.20 0.20 383988 75354 6.00 13.80 21.60 35.20 1.00 19.20 30.40 22.20 114.40 1.6 466 1025397
+1 0 1 1 46 57 1935 157 93 2.00 1.00 262074 63713 0.40 0.60 0.60 0.00 0.00 3.80 4.20 101.20 179.00 365 90 10
+1 96 1 1 10 0 298 53 37 0.40 0.40 138133 12881 3.99 10.58 27.94 60.48 0.80 3.79 25.95 26.15 90.82 1.4 285 1725635
+1 68 1 1 18 0 6879 827 618 9.42 2.61 273275 50969 0.60 1.00 0.80 0.00 0.20 0.00 0.00 453.51 692.99 1.3 326 1069265
+1 83 1 1 20 3 2530 308 255 4.00 2.60 141234 73496 3.80 5.40 17.40 22.00 1.80 6.00 10.60 181.40 360.00 2.6 224 1111064
+1 98 1 1 0 0 174 10 10 0.20 0.20 1016 4634 0.00 0.00 0.00 0.00 0.00 0.60 1.00 15.60 16.80 1.0 1827 1781192
+1 93 1 1 1 0 2588 150 123 0.20 0.20 259473 78565 0.00 0.00 0.00 0.00 0.00 10.38 10.58 23.95 51.50 2.8 2546 1389025
+1 0 1 1 45 60 1219 67 42 0.60 1.20 122445 17921 4.20 5.20 10.60 23.20 0.00 11.20 11.40 49.00 99.40 145 93 7
+1 0 1 1 17 1 1919 278 210 3.61 1.20 295943 60406 18.04 27.05 94.79 139.28 14.43 12.83 25.25 177.96 391.18 126 85 15
+1 96 1 1 0 0 431 88 54 0.20 0.20 193433 6067 0.00 0.00 0.00 0.00 0.00 11.98 23.95 15.57 18.76 3.0 687 1700786
+1 85 1 1 14 12 4939 475 300 1.00 1.20 530441 632132 4.00 8.40 8.20 0.00 0.60 2.00 2.00 58.80 101.00 2.2 211 1042893
+1 91 1 1 4 0 2739 163 140 0.80 2.00 112413 48966 6.80 9.60 16.00 14.20 1.80 15.80 16.80 44.20 123.60 6.4 178 1310477
+1 66 1 1 26 7 6351 373 266 4.80 4.00 103110 17879 4.80 8.00 9.40 9.00 3.20 10.40 12.00 306.40 446.60 8.2 181 1300654
+1 74 1 1 27 0 2052 163 87 6.60 19.40 536165 28955 6.80 17.60 61.60 151.60 0.40 64.60 69.60 217.40 479.80 2.0 126 1089085
+1 0 1 1 20 16 1339 365 132 1.00 0.80 686687 547979 0.00 0.00 0.00 0.00 0.20 0.40 0.40 93.00 146.80 559 90 10
+1 75 1 1 9 2 2363 217 143 6.99 20.96 170241 56440 2.59 7.58 25.15 65.27 1.20 14.77 23.75 242.51 442.32 1.3 117 1112195
+1 0 1 1 22 17 1838 346 302 0.80 0.60 807509 796102 11.80 34.00 188.60 287.00 1.20 58.00 114.40 60.40 99.20 116 77 23
+1 97 1 1 2 1 266 34 18 0.20 0.20 91816 3993 0.00 0.00 0.00 0.00 0.00 0.00 0.00 22.44 17.23 1.2 7404 1869613
+1 67 1 1 11 1 5400 698 556 7.00 3.00 296912 110777 18.60 36.80 34.00 0.00 0.20 12.80 13.60 356.60 616.60 1.8 265 1010934
+1 82 1 1 12 6 4534 378 258 1.00 3.81 205135 143395 6.01 8.62 8.42 0.00 2.20 5.21 8.22 34.87 70.14 2.0 226 985252
+1 97 1 1 1 1 983 32 45 0.20 0.20 9311 142734 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.20 16.80 1.2 8439 1837168
+1 85 1 1 16 0 1395 204 85 5.60 3.80 36451 28097 0.00 0.00 0.00 0.00 2.20 7.60 11.00 211.80 376.40 1.5 1044 1015834
+1 96 1 1 0 0 1092 30 31 0.20 0.20 15426 11363 0.80 1.20 1.20 0.00 0.00 0.00 0.00 15.60 16.80 2.0 172 1760056
+1 96 1 1 7 7 898 62 64 0.20 0.20 23215 16810 2.40 2.61 2.61 0.00 0.00 4.21 4.21 16.23 42.08 2.0 186 991279
+1 97 1 1 0 0 314 48 26 0.20 0.20 182613 24696 2.40 3.00 3.00 0.00 0.20 1.20 1.20 15.60 20.80 1.4 324 1752632
+1 84 1 1 9 5 2960 521 200 1.00 1.00 731913 50971 12.20 22.20 37.40 64.60 4.20 11.20 13.40 78.80 212.40 1.0 135 967152
+1 82 1 1 2 1 3080 510 262 0.40 0.40 874754 387849 0.60 0.80 0.80 0.00 0.40 3.20 5.00 41.40 74.20 2.4 374 1020645
+1 87 1 1 0 0 5241 289 271 0.20 0.20 24691 350196 0.00 0.00 0.00 0.00 0.00 10.60 12.60 16.00 51.80 2.4 1295 1377797
+1 67 1 1 21 14 4435 375 232 7.60 18.20 141324 38980 0.00 0.00 0.00 0.00 0.00 6.80 9.20 305.80 538.00 1.0 687 1097723
+1 95 1 1 0 0 2414 75 132 0.20 0.20 33243 31811 0.00 0.00 0.00 0.00 0.20 0.00 0.00 15.60 17.00 2.0 262 1708744
+1 94 1 1 2 0 630 75 72 1.40 1.60 75078 42865 0.00 0.00 0.00 0.00 0.00 4.00 8.00 69.80 102.40 3.2 395 1705382
+1 98 1 1 1 0 262 21 17 0.20 0.20 831 4648 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 23.80 3.0 513 1719942
+1 98 1 1 2 1 214 44 28 0.20 0.20 10304 7695 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 17.00 1.2 7102 1847088
+1 84 1 1 3 1 570 75 63 2.20 2.20 208429 64691 0.00 0.00 0.00 0.00 0.00 2.60 2.60 193.80 166.60 2.0 1320 1796026
+1 95 1 1 5 4 1451 110 60 0.20 0.00 18364 26638 0.00 0.00 0.00 0.00 0.00 0.20 0.20 7.58 6.99 1.0 713 990247
+1 95 1 1 1 1 1937 127 85 0.40 1.00 47917 30954 5.20 12.40 14.80 10.60 1.20 8.40 8.80 31.00 67.60 1.2 142 1013344
+1 96 1 1 1 0 702 32 37 0.80 2.20 3024 22659 0.00 0.00 0.00 0.00 0.00 0.40 0.40 53.80 100.60 1.0 443 992320
+1 92 1 1 1 0 2183 187 125 0.40 0.40 9210 25126 0.00 0.00 0.00 0.00 0.00 0.40 0.40 38.28 40.68 1.0 2133 1075083
+1 95 1 1 1 1 2913 167 107 0.20 0.20 9863 23225 0.40 0.40 0.40 0.00 0.00 0.40 0.40 18.00 42.40 2.6 219 1017912
+1 96 1 1 1 0 475 77 45 0.80 1.00 157874 16216 0.00 0.00 0.00 0.00 0.00 0.20 0.20 48.80 67.20 2.2 1052 1723310
+1 85 1 1 13 10 1030 113 93 0.40 1.80 18024 24547 3.19 8.78 24.95 42.51 0.60 79.64 116.17 81.84 222.16 1.6 357 942938
+1 84 1 1 5 0 4476 337 309 4.00 1.20 120003 28641 0.40 0.40 0.40 0.00 0.00 0.80 1.40 199.40 303.80 3.2 165 1709944
+1 94 1 1 2 1 1624 120 59 0.40 0.40 19036 36462 0.40 0.40 0.40 0.00 0.60 0.40 0.40 27.20 38.00 1.4 329 1753800
+1 62 1 1 94 49 5163 410 292 7.20 17.40 254820 153663 2.80 6.20 6.00 0.00 1.80 16.00 20.20 319.80 584.40 1.0 541 1101859
+1 89 1 1 35 48 840 141 129 2.00 2.00 74675 151299 0.00 0.00 0.00 0.00 0.00 3.00 3.60 176.60 166.80 1.4 5555 1841400
+1 89 1 1 54 51 3061 293 125 1.20 0.80 216263 34769 0.00 0.00 0.00 0.00 0.00 0.60 0.60 71.40 117.80 3.2 742 972704
+1 91 1 1 51 76 2023 193 101 0.20 0.20 130770 18136 0.00 0.00 0.00 0.00 0.00 1.00 1.20 15.80 19.00 2.4 3438 1710080
+1 0 1 1 8 4 1658 264 187 1.00 3.60 1605549 1520769 2.60 3.20 6.60 11.20 4.20 7.60 7.80 42.20 171.40 135 87 13
+1 88 1 1 1 0 3171 288 154 0.20 0.20 27450 52947 0.00 0.00 0.00 0.00 0.00 24.00 41.00 38.80 95.80 2.6 2588 1442398
+1 84 1 1 10 7 2944 444 218 1.99 1.79 283744 202504 7.37 14.34 36.25 66.73 2.99 6.18 9.36 75.70 188.25 2.0 157 1022185
+1 95 1 1 1 0 2384 65 128 0.20 0.20 4569 11586 3.80 4.00 4.00 0.00 0.00 0.00 0.00 15.60 20.20 2.4 308 1715526
+1 97 1 1 0 0 193 46 25 0.20 0.20 274032 258127 0.00 0.00 0.00 0.00 0.00 1.20 1.20 15.80 21.20 2.4 5690 1837224
+1 77 1 1 9 2 2227 140 73 6.41 19.44 108370 28568 2.81 4.21 3.41 0.00 0.20 7.01 10.42 225.65 406.81 2.6 314 1108418
+1 92 1 1 21 18 886 218 119 0.60 0.60 83461 25311 0.00 0.00 0.00 0.00 0.00 12.57 19.16 47.90 83.03 1.0 572 983730
+1 84 1 1 47 65 1732 224 248 1.80 2.20 114823 411178 0.00 0.00 0.00 0.00 0.00 12.00 13.60 124.00 209.80 2.2 980 1383302
+1 82 1 1 405 393 3168 295 198 1.00 2.40 990950 37039 0.00 0.00 0.00 0.00 0.00 7.39 9.18 63.67 143.91 2.4 2398 1702935
+1 94 1 1 4 1 702 93 99 0.80 0.60 4112 34632 0.00 0.00 0.00 0.00 0.00 1.20 1.20 44.20 44.20 1.0 412 1092226
+1 98 1 1 0 0 210 26 27 0.20 0.20 84655 3719 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6340 1855480
+1 89 1 1 15 10 4119 150 118 1.20 1.40 107909 12136 0.00 0.00 0.00 0.00 0.00 0.60 0.60 101.40 126.40 3.6 7383 1388517
+1 74 1 1 10 3 6838 508 367 4.81 3.21 306676 208280 10.22 26.65 29.66 24.85 2.61 2.61 8.82 245.49 457.92 1.5 187 1012170
+1 78 1 1 13 6 3424 339 296 4.00 3.40 276177 235290 0.80 0.80 0.80 0.00 1.40 7.40 9.80 228.80 429.60 3.6 362 1376770
+1 86 1 1 13 4 3199 418 215 0.20 0.20 426397 54353 7.60 20.20 31.80 47.40 13.80 11.80 13.00 20.40 139.80 8.6 125 1300486
+1 92 1 1 9 1 1275 113 64 0.40 0.40 197595 45059 0.00 0.00 0.00 0.00 1.00 6.40 8.40 28.80 63.00 1.3 772 1076837
+1 85 1 1 3 0 5610 342 252 2.40 0.80 263075 50660 2.40 14.60 14.60 0.00 1.00 5.40 5.40 120.80 207.20 2.4 168 1437877
+1 0 1 1 2 0 1200 134 128 0.60 0.60 208393 90332 17.37 24.35 60.08 78.24 14.77 26.95 31.74 29.94 131.54 126 90 10
+1 90 1 1 4 2 3081 205 123 0.40 1.80 27783 79274 0.00 0.00 0.00 0.00 0.00 2.40 2.40 141.80 53.40 1.0 553 1077114
+1 90 1 1 9 2 1542 183 81 1.80 1.40 21281 15756 5.20 5.40 7.80 4.80 0.40 2.80 2.80 86.40 215.80 2.0 161 1065467
+1 91 1 1 8 6 1474 130 61 1.00 1.20 31184 24607 0.00 0.00 0.00 0.00 0.20 3.61 4.81 84.17 156.91 3.2 676 973321
+1 90 1 1 1 0 2272 155 81 0.60 0.60 270726 52765 0.00 0.00 0.00 0.00 0.00 0.80 0.80 49.70 73.05 1.4 644 1020297
+1 90 1 1 1 0 3039 206 103 0.20 0.20 277673 36645 4.59 5.79 9.78 11.78 4.19 63.07 63.27 20.56 208.18 2.6 192 1009614
+1 82 1 1 3 0 4577 195 157 2.80 3.40 191031 116174 12.80 20.20 25.60 35.00 5.20 2.60 2.80 152.20 254.40 1.8 167 990722
+1 83 1 1 98 93 2793 310 376 2.58 1.19 276631 63186 0.00 0.00 0.00 0.00 0.00 3.38 4.97 158.65 262.03 2.3 908 1000204
+1 96 1 1 0 0 1751 43 51 0.20 0.20 47969 32606 3.20 4.60 4.60 0.00 0.60 0.60 1.00 17.20 17.40 2.2 156 1760072
+1 87 1 1 10 7 3275 208 186 0.20 0.20 269437 167708 6.20 9.80 8.60 0.00 15.40 5.60 8.00 142.20 75.00 1.0 280 1129741
+1 0 1 1 17 4 2404 223 156 4.20 3.20 285474 87061 13.80 22.20 42.40 74.80 0.00 23.80 24.60 232.20 457.00 276 82 18
+1 88 1 1 5 1 2382 173 193 0.80 1.80 94104 97560 0.00 0.00 0.00 0.00 0.00 1.20 1.20 44.89 154.31 1.0 1102 1101961
+1 96 1 1 0 0 456 59 55 0.20 0.20 2675 7266 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 17.60 2.2 1336 1705102
+1 85 1 1 23 3 2408 276 176 2.40 2.20 152134 48956 10.42 18.64 51.90 87.58 1.60 19.24 39.48 152.91 243.89 2.0 112 979309
+1 80 1 1 3 2 4103 272 245 0.60 1.00 63344 456656 0.00 0.00 0.00 0.00 0.00 7.19 7.19 64.27 150.70 2.0 436 1002681
+1 84 1 1 1 0 3985 422 225 0.60 0.40 142894 46262 0.00 0.00 0.00 0.00 0.00 2.00 3.00 48.40 77.00 1.5 607 1095648
+1 91 1 1 4 2 691 55 24 2.00 2.00 49048 14633 0.00 0.00 0.00 0.00 0.00 1.00 1.20 169.74 151.90 1.0 6808 1859426
+1 88 1 1 7 2 1210 151 82 3.40 2.40 327843 26844 11.80 35.40 62.20 117.40 0.40 14.40 16.60 129.60 237.60 1.8 239 1020592
+1 88 1 1 1 0 1817 181 132 0.40 0.60 320521 158073 11.02 36.27 56.71 65.93 4.01 12.22 18.44 43.69 171.34 1.6 132 1121385
+1 94 1 1 1 1 1630 59 92 0.20 0.20 22811 383465 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 8358 1864774
+1 93 1 1 4 0 2886 173 130 0.80 0.80 177255 315932 1.00 1.20 1.20 0.00 2.60 0.60 0.60 67.20 102.80 2.2 320 1520312
+1 90 1 1 4 2 3682 404 178 0.60 1.00 250263 243861 3.60 4.00 4.00 0.00 0.80 0.80 1.00 49.60 91.40 4.2 274 1323344
+1 87 1 1 14 3 3123 261 151 0.40 0.60 156543 36039 0.00 0.00 0.00 0.00 0.20 1.60 2.80 33.00 79.20 2.5 601 1076970
+1 85 1 1 1 0 3801 511 491 0.60 0.80 69409 73843 0.80 0.80 0.80 0.00 0.00 1.00 1.00 37.92 57.68 1.5 182 1012693
+1 95 1 1 2 0 800 73 57 0.40 0.40 36986 17713 0.00 0.00 0.00 0.00 0.00 0.40 0.40 30.46 52.30 1.0 704 1074615
+1 84 1 1 6 2 3225 223 152 2.59 2.59 47285 46942 5.39 8.78 8.58 0.00 1.20 9.18 17.37 89.62 162.48 1.2 328 1097562
+1 74 1 1 87 7 3754 206 185 10.80 8.20 35220 86724 0.00 0.00 0.00 0.00 0.00 18.40 18.80 344.00 619.00 2.2 453 1716659
+1 91 1 1 43 29 1569 260 134 1.60 3.60 307107 241976 0.00 0.00 0.00 0.00 0.00 1.00 1.20 107.40 213.80 3.4 2497 1581968
+1 74 1 1 16 1 3791 457 374 3.20 1.60 331609 160649 14.20 37.20 52.80 108.80 0.40 24.40 33.20 211.40 417.40 1.7 256 1052498
+1 79 1 1 7 0 2452 368 323 6.80 1.80 193892 23470 0.00 0.00 0.00 0.00 0.60 1.20 1.80 318.40 456.20 1.6 2377 1768187
+1 87 1 1 5 0 2895 173 181 1.00 0.60 63003 143471 2.20 3.39 3.19 0.00 1.80 3.19 4.39 70.86 141.72 2.2 298 1025753
+1 98 1 1 2 1 166 12 18 0.20 0.20 9368 16392 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.83 16.83 1.4 8358 1868393
+1 95 1 1 1 0 1274 150 91 0.20 0.20 62260 37831 0.00 0.00 0.00 0.00 0.00 0.20 0.20 18.40 36.60 3.2 655 1630731
+1 86 1 1 33 47 2055 204 116 1.60 3.21 119329 25799 0.00 0.00 0.00 0.00 0.20 0.60 0.60 126.85 181.76 1.0 542 1097457
+1 71 1 1 6 0 3517 475 406 5.00 2.60 373736 232228 0.00 0.00 0.00 0.00 0.00 8.60 14.40 235.00 451.40 2.0 772 1016816
+1 91 1 1 1 0 2328 236 74 1.00 4.60 858682 42844 0.00 0.00 0.00 0.00 11.20 0.80 0.80 35.20 59.00 5.0 2313 1730270
+1 85 1 1 4 1 5622 1314 695 0.60 1.00 126628 69404 0.00 0.00 0.00 0.00 0.00 7.80 8.80 47.80 79.00 2.0 1513 1087435
+1 98 1 1 1 1 185 11 14 0.20 0.20 6992 13238 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.0 7278 1860096
+1 97 1 1 1 1 904 48 30 0.20 0.20 12169 6254 0.00 0.00 0.00 0.00 0.00 0.60 1.00 17.20 17.60 1.0 5050 1828856
+1 90 1 1 1 0 5520 414 259 0.20 0.20 84595 46486 1.60 1.80 1.80 0.00 0.40 0.20 0.20 15.80 39.60 1.2 178 1066061
+1 97 1 1 0 0 556 47 36 0.20 0.20 1332 14788 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 17.00 3.0 1277 1712936
+1 91 1 1 15 23 309 47 70 0.20 0.20 4288 10154 0.00 0.00 0.00 0.00 0.00 0.60 0.80 17.00 21.40 2.4 1929 1769096
+1 79 1 1 4 1 4210 789 756 2.61 1.00 454987 396436 5.81 6.21 6.01 0.00 0.80 4.81 7.21 140.68 253.51 2.0 167 1094804
+1 91 1 1 1 0 2638 122 89 1.40 3.61 57618 53356 0.00 0.00 0.00 0.00 0.00 2.81 2.81 95.19 123.65 1.3 607 1121238
+1 96 1 1 3 1 544 80 27 1.00 0.40 368791 4454 0.00 0.00 0.00 0.00 0.40 0.00 0.00 49.40 70.60 2.4 850 1716526
+1 83 1 1 2 0 2193 338 144 3.19 3.99 374978 33587 0.60 0.60 10.38 14.57 2.40 1.80 2.20 140.52 291.22 1.0 258 1099142
+1 94 1 1 6 3 1698 120 71 0.40 0.40 43357 36278 0.00 0.00 0.00 0.00 0.00 3.80 7.20 30.20 46.20 2.4 1703 1546931
+1 92 1 1 2 0 1502 159 151 0.20 0.20 136162 88666 4.80 5.00 4.80 0.00 18.60 6.60 11.40 15.60 23.00 1.2 190 1064517
+1 85 1 1 31 46 3827 330 155 0.40 0.60 372450 49765 5.40 7.40 6.60 0.00 7.20 7.40 8.00 24.20 60.60 1.5 255 1117835
+1 98 1 1 1 1 159 12 10 0.20 0.20 8582 7064 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7234 1847178
+1 89 1 1 8 1 1714 120 119 2.00 4.00 61411 33120 0.00 0.00 0.00 0.00 0.00 1.20 2.20 137.00 171.60 2.4 1188 1536725
+1 85 1 1 26 17 4451 401 312 2.60 2.20 201547 55361 0.00 0.00 0.00 0.00 0.00 11.40 14.80 146.40 314.80 4.4 770 1395122
+1 86 1 1 10 1 2172 312 235 1.00 1.20 275037 191712 1.80 2.40 2.20 0.00 0.60 12.20 13.20 74.80 203.20 1.0 555 1069630
+1 85 1 1 0 0 4146 273 214 0.20 0.20 530070 25740 10.78 42.91 130.54 353.89 0.00 64.47 128.14 15.17 31.74 2.4 109 1013046
+1 75 1 1 7 0 1648 87 34 5.60 21.40 160372 9952 0.00 0.00 0.00 0.00 0.00 6.40 7.60 290.20 445.00 2.2 791 1750378
+1 85 1 1 2 0 4970 402 317 1.80 0.60 237185 128888 0.00 0.00 0.00 0.00 0.00 11.00 12.40 86.00 154.40 4.2 1409 1044597
+1 98 1 1 14 14 261 81 44 0.20 0.20 102119 117424 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.40 3.2 1829 1759162
+1 84 1 1 2 1 1363 291 389 0.40 0.40 679012 348619 0.00 0.00 0.00 0.00 0.00 30.40 58.40 27.80 56.80 1.8 1344 1707259
+1 86 1 1 0 0 4129 274 136 0.80 0.80 295888 114089 1.40 1.80 1.60 0.00 0.20 11.58 11.78 52.69 106.39 2.2 515 1011946
+1 92 1 1 3 1 1831 111 112 0.60 1.00 346303 8738 0.00 0.00 0.00 0.00 0.00 0.60 0.60 70.40 66.60 5.8 870 1638619
+1 87 1 1 28 2 1776 157 148 0.60 0.80 177035 91063 0.00 0.00 0.00 0.00 0.40 15.31 26.64 67.40 216.70 2.2 710 1022157
+1 76 1 1 13 7 3758 230 159 2.99 3.59 433969 76306 0.40 0.60 0.40 0.00 0.60 53.49 79.24 182.83 364.67 1.0 527 996667
+1 87 1 1 1 0 2284 92 62 0.20 0.20 20074 11558 0.00 0.00 0.00 0.00 0.00 0.20 0.20 16.80 17.20 1.8 828 1750747
+1 78 1 1 4 1 1636 132 188 0.60 2.00 454609 491193 57.88 156.29 218.16 224.15 0.40 59.88 111.18 46.31 121.56 1.4 144 1071767
+1 84 1 1 17 13 4699 823 422 0.80 0.80 78499 25513 0.00 0.00 0.00 0.00 0.00 0.20 0.20 68.20 88.40 4.2 360 1536730
+1 91 1 1 28 37 2440 104 95 1.20 3.20 87122 35216 1.80 2.00 2.00 0.00 0.60 1.60 1.60 77.00 95.20 2.6 241 1752318
+1 91 1 1 3 0 646 49 21 1.80 1.80 121611 16718 0.00 0.00 0.00 0.00 0.00 2.20 4.19 150.10 145.31 1.2 6740 1850714
+1 87 1 1 14 6 2878 169 125 1.40 2.00 218353 208284 0.00 0.00 0.00 0.00 0.00 2.00 4.00 96.40 174.40 5.6 2650 1564030
+1 89 1 1 108 86 2048 167 187 0.60 0.60 113516 176344 2.60 8.20 7.80 0.00 0.60 8.00 19.60 53.80 87.20 4.4 400 1604200
+1 93 1 1 1 0 1359 56 60 0.20 0.20 2257 34153 0.60 0.60 0.60 0.00 0.00 22.95 28.34 15.77 62.48 2.8 230 1064977
+1 74 1 1 85 65 2751 268 152 4.81 5.61 339810 69713 6.41 15.03 44.69 84.97 1.60 12.42 14.43 291.78 559.72 2.0 313 1089049
+1 82 1 1 27 22 4171 256 159 2.80 3.20 126002 50538 0.00 0.00 0.00 0.00 0.00 2.40 5.80 172.40 376.80 1.2 537 1016587
+1 93 1 1 8 4 2247 142 110 0.40 0.40 174831 170471 0.40 0.60 0.60 0.00 0.00 6.60 6.80 44.00 110.40 5.0 360 1314491
+1 97 1 1 29 37 302 123 46 0.20 0.20 199469 206094 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.6 5272 1825416
+1 72 1 1 6 2 5057 189 209 0.80 1.40 275465 490861 9.18 15.17 57.29 79.04 0.40 15.57 16.77 58.68 249.50 3.6 141 1006825
+1 94 1 1 10 0 1984 57 59 2.00 6.20 3169 2233 0.00 0.00 0.00 0.00 0.00 0.40 0.40 69.20 121.60 4.0 847 1631198
+1 94 1 1 173 189 643 156 69 0.20 0.20 769383 39827 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 19.20 4.0 425 1702806
+1 87 1 1 8 1 2887 294 209 2.60 0.80 202152 40571 0.00 0.00 0.00 0.00 0.00 1.60 1.60 134.00 191.60 2.4 1021 1539986
+1 77 1 1 9 0 2555 397 314 8.60 3.80 510619 46678 0.00 0.00 0.00 0.00 0.00 0.00 0.00 629.80 583.00 3.6 8741 1864907
+1 83 1 1 8 3 4462 368 291 3.80 2.80 272876 184735 0.00 0.00 0.00 0.00 0.00 26.00 27.00 187.20 317.80 5.0 1293 1614219
+1 93 1 1 5 2 753 40 41 1.40 1.20 31626 24099 0.00 0.00 0.00 0.00 0.00 3.80 4.20 79.80 114.00 3.6 529 1050267
+1 91 1 1 163 52 1891 255 246 0.80 0.80 196064 238996 8.02 41.88 50.50 38.48 0.60 4.01 4.01 70.94 120.84 1.0 177 981045
+1 96 1 1 13 20 1082 41 46 0.20 0.20 86109 18500 2.80 2.80 2.80 0.00 0.20 1.00 1.00 15.40 16.80 1.2 263 1750872
+1 88 1 1 12 9 6262 212 186 0.60 0.60 20505 27881 0.00 0.00 0.00 0.00 0.00 1.80 1.80 39.80 71.20 2.4 2463 975309
+1 82 1 1 3 0 579 95 60 2.40 3.80 335111 286429 0.00 0.00 0.00 0.00 42.80 12.60 22.60 194.40 235.40 3.4 3835 1808006
+1 90 1 1 0 0 3530 183 163 0.60 3.20 10471 30606 0.00 0.00 0.00 0.00 0.20 1.40 1.40 26.20 47.80 1.6 410 1090200
+1 84 1 1 5 0 1824 371 283 4.60 1.20 268748 146941 0.00 0.00 0.00 0.00 0.00 7.40 14.40 231.20 334.60 3.0 1539 1747669
+1 87 1 1 21 6 1814 203 152 2.40 1.00 280020 77574 0.00 0.00 0.00 0.00 0.40 0.00 0.00 192.20 180.20 3.2 2847 1544379
+1 85 1 1 9 1 3097 377 201 1.40 1.20 89157 69225 0.00 0.00 0.00 0.00 0.20 6.80 8.60 72.80 134.20 2.5 940 1095928
+1 91 1 1 4 0 1376 171 166 3.20 1.00 75541 9528 0.00 0.00 0.00 0.00 0.00 0.00 0.00 156.80 229.00 2.0 6270 1856525
+1 84 1 1 7 1 2067 306 280 5.60 1.60 156275 8013 0.00 0.00 0.00 0.00 0.00 0.20 0.20 281.80 394.80 1.2 7269 1846770
+1 91 1 1 14 7 1495 197 169 0.80 1.00 10304 24435 7.98 14.57 24.75 38.52 1.00 2.00 2.00 63.07 106.79 2.4 186 974392
+1 91 1 1 5 1 1300 179 159 3.80 2.00 90738 6911 0.00 0.00 0.00 0.00 0.00 0.20 0.20 185.80 254.40 2.0 7346 1864166
+1 91 1 1 18 12 923 212 117 2.00 0.60 294150 236336 0.00 0.00 0.00 0.00 0.00 0.00 0.00 97.80 137.00 2.6 5351 1826106
+1 81 1 1 3 2 3379 264 170 1.60 5.00 73327 54095 2.80 3.80 3.80 0.00 2.80 14.20 14.40 107.80 212.80 1.0 353 986517
+1 93 1 1 0 0 2797 119 156 0.20 0.20 10956 102698 3.80 6.20 20.20 25.20 0.40 2.00 2.40 14.80 33.20 2.2 140 1708843
+1 0 1 1 17 13 3457 241 141 0.60 1.80 409008 180947 0.00 0.00 0.00 0.00 0.00 16.23 18.04 48.10 140.68 1975 82 18
+1 89 1 1 48 40 2400 181 175 0.20 0.20 85111 185686 0.00 0.00 0.00 0.00 0.00 3.00 5.80 19.40 31.20 3.0 2089 1643112
+1 92 1 1 6 1 4244 348 168 0.80 0.80 243159 218163 0.00 0.00 0.00 0.00 0.00 4.80 8.00 43.60 102.00 3.6 3214 1337067
+1 86 1 1 160 169 930 155 68 1.00 2.00 765731 275305 0.00 0.00 0.00 0.00 0.00 4.00 6.60 86.00 142.40 3.6 3720 1811906
+1 88 1 1 39 51 2253 100 126 0.20 0.20 138204 351378 4.01 4.81 4.41 0.00 2.81 3.01 3.41 16.43 56.51 2.4 212 1013159
+1 96 1 1 2 0 799 64 45 0.40 0.60 24644 17052 2.80 3.20 3.20 0.00 0.00 0.00 0.00 38.40 42.40 1.0 288 1745998
+1 90 1 1 20 19 3001 211 129 0.40 1.40 17274 51893 4.00 5.40 5.40 0.00 0.60 0.80 0.80 23.20 38.20 1.8 174 1128501
+1 73 1 1 15 4 2526 241 153 5.59 12.38 694520 21962 9.38 32.93 73.45 170.66 1.20 80.44 142.32 229.94 448.30 2.0 194 1105546
+1 92 1 1 4 1 3390 196 118 1.20 2.20 176880 165486 0.00 0.00 0.00 0.00 0.00 2.60 3.20 93.40 112.40 3.2 3928 1343186
+1 0 1 1 4 2 1218 135 78 0.40 0.60 8089 39394 0.00 0.00 0.00 0.00 0.00 0.20 0.20 32.73 43.51 347 95 5
+1 93 1 1 18 27 470 44 34 0.20 0.20 1650 6261 0.00 0.00 0.00 0.00 0.00 0.40 0.40 16.40 17.00 2.0 486 1742376
+1 83 1 1 24 28 807 148 59 3.80 3.80 337841 209579 0.00 0.00 0.00 0.00 0.20 5.20 8.80 238.60 306.80 2.8 3809 1811477
+1 85 1 1 39 23 3674 318 177 2.59 3.59 160120 78498 2.79 2.79 2.79 0.00 1.60 0.20 0.20 175.85 262.08 2.6 223 1624016
+1 2 1 1 194 87 2192 372 408 1.80 2.20 361348 309937 0.00 0.00 0.00 0.00 0.60 6.80 15.00 134.60 237.00 549 82 16
+1 88 1 1 1 0 2528 246 143 0.60 1.80 31990 48475 0.00 0.00 0.00 0.00 0.00 2.00 2.40 42.71 87.62 2.3 828 1116351
+1 88 1 1 4 1 1811 124 80 0.60 0.60 40704 71992 0.00 0.00 0.00 0.00 0.00 0.80 0.80 51.60 47.40 1.8 3693 1774053
+1 86 1 1 1 0 1407 294 169 0.60 1.00 175488 73052 0.00 0.00 0.00 0.00 0.00 8.00 14.80 83.00 195.20 3.4 2271 1726030
+1 85 1 1 6 1 3869 308 184 1.00 1.20 89698 41172 5.60 10.60 22.00 32.40 1.20 16.20 21.80 71.80 174.00 3.0 220 997363
+1 96 1 1 24 37 230 26 40 0.20 0.20 3618 4979 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.80 16.80 1.0 7074 1846032
+1 0 1 1 19 13 1121 322 121 1.20 1.20 889484 380111 0.60 0.60 0.60 0.00 0.60 1.00 1.00 96.80 165.60 471 89 11
+1 95 1 1 1 1 771 39 79 0.20 0.20 13227 26071 0.00 0.00 0.00 0.00 0.00 1.40 1.40 17.00 30.20 1.0 1834 1074840
+1 98 1 1 0 0 281 55 47 0.20 0.20 1049 8784 0.60 0.60 0.60 0.00 0.20 0.40 0.40 16.00 16.80 1.0 188 1755512
+1 83 1 1 5 1 1636 198 110 0.60 2.40 766534 293691 7.60 40.60 135.40 245.40 0.60 58.80 115.20 77.40 76.20 4.2 121 1537819
+1 97 1 1 1 0 391 50 37 0.20 0.20 10642 17148 0.80 0.80 5.00 11.80 0.20 0.40 0.40 21.80 19.00 2.6 184 1712110
+1 96 1 1 0 0 1022 224 68 0.20 0.20 330543 324797 0.00 0.00 0.00 0.00 0.00 0.60 0.60 18.80 17.80 3.4 1991 1764438
+1 82 1 1 3 0 601 65 41 3.00 4.40 114968 36935 0.00 0.00 0.00 0.00 0.00 2.20 2.80 265.60 231.80 1.4 2582 1820523
+1 84 1 1 2 0 5192 326 228 0.60 0.80 267945 92218 2.20 3.80 3.60 0.00 1.60 7.00 11.60 49.00 94.20 2.2 472 1005806
+1 92 1 1 4 0 1323 167 135 2.60 0.80 72105 6511 0.00 0.00 0.00 0.00 0.00 0.20 0.20 130.00 191.20 2.2 1343 1712976
+1 97 1 1 1 0 872 77 54 0.20 0.20 3152 21336 0.00 0.00 0.00 0.00 0.00 1.40 1.60 16.00 25.20 1.6 395 1016512
+1 0 1 1 2 1 4298 199 124 0.20 0.20 61506 23699 1.80 1.80 1.80 0.00 0.80 1.40 1.80 18.36 44.91 161 91 9
+1 85 1 1 15 10 4620 345 500 0.80 1.20 128085 72013 0.00 0.00 0.00 0.00 0.20 8.80 12.20 58.60 88.80 2.8 447 1049379
+1 98 1 1 1 1 170 14 14 0.20 0.20 20923 17200 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6459 1871530
+1 95 1 1 24 37 295 19 17 0.20 0.20 1028 8832 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.40 17.00 3.0 1281 1712952
+1 79 1 1 189 14 2690 322 276 4.99 2.79 210248 134085 0.00 0.00 0.00 0.00 0.00 21.76 23.75 228.54 392.22 6.0 2409 1088888
+1 81 1 1 13 11 6133 387 212 1.60 4.40 789486 61672 0.00 0.00 0.00 0.00 0.20 3.00 4.60 74.80 140.60 1.3 686 1010558
+1 89 1 1 4 2 2757 162 108 1.20 5.99 253784 229457 0.00 0.00 0.00 0.00 0.00 2.20 2.40 152.89 120.96 4.2 1624 1613467
+1 92 1 1 5 2 4876 275 188 0.40 0.40 95773 80962 3.80 4.20 4.20 0.00 1.60 5.20 6.00 46.40 64.60 2.2 204 1446067
+1 96 1 1 1 0 409 33 24 0.60 2.60 1398 4392 0.00 0.00 0.00 0.00 0.00 0.00 0.00 43.60 36.80 2.2 1364 1713419
+1 93 1 1 4 2 1165 198 95 0.40 0.40 20605 23601 0.00 0.00 0.00 0.00 0.00 1.80 1.80 107.19 78.44 1.0 1200 1015337
+1 0 1 1 61 85 1943 234 125 0.40 0.60 337577 288667 4.20 5.80 5.80 0.00 0.00 1.00 1.40 45.60 65.40 257 86 14
+1 94 1 1 19 28 183 19 17 0.20 0.20 22871 22611 0.00 0.00 0.00 0.00 0.00 0.00 0.00 18.60 17.60 1.0 2667 1771702
+1 85 1 1 49 63 1521 131 64 1.80 3.81 309246 35824 8.02 44.89 76.35 166.13 3.41 6.61 11.42 142.69 343.89 3.8 219 1066911
+1 57 1 1 13 4 3606 395 241 7.19 6.79 548681 397874 13.37 46.91 224.75 318.56 1.80 63.07 109.38 364.67 722.36 1.0 125 1076163
+1 85 1 1 42 16 3378 241 180 0.80 2.20 141310 83507 8.82 18.84 24.85 18.84 1.00 15.43 25.05 94.79 162.53 1.2 206 996731
+1 92 1 1 182 199 1134 210 73 0.60 5.41 1011772 54133 0.00 0.00 0.00 0.00 0.20 3.81 3.81 39.68 120.04 1.0 429 1032951
+1 85 1 1 3 1 474 43 50 2.40 2.40 72534 44687 7.00 7.00 7.00 0.00 0.20 3.00 3.20 205.20 178.40 1.8 236 1801544
+1 88 1 1 37 48 495 63 21 2.19 2.19 268983 32654 0.00 0.00 0.00 0.00 0.00 2.79 4.78 204.58 176.29 1.4 11471 1873924
+1 68 1 1 79 42 3900 340 235 6.80 17.00 311957 210122 0.00 0.00 0.00 0.00 0.00 11.20 13.20 289.20 571.20 1.3 711 1102216
+1 80 1 1 13 2 5872 503 253 1.80 6.40 210122 87588 0.40 6.40 16.40 21.40 1.40 8.80 10.80 83.40 291.60 7.6 295 1307861
+1 95 1 1 0 0 1228 57 72 0.20 0.20 10301 108556 0.00 0.00 0.00 0.00 0.00 0.20 0.40 13.20 16.80 1.8 6800 1860962
+1 96 1 1 1 1 1112 62 51 0.40 0.60 4128 6023 0.00 0.00 0.00 0.00 0.00 0.00 0.00 35.40 37.40 2.0 2112 1720872
+1 0 1 1 9 5 2585 304 259 0.80 0.80 212643 195632 0.00 0.00 0.00 0.00 1.80 2.40 2.60 42.20 82.00 828 88 12
+1 87 1 1 3 1 1496 131 59 2.00 2.00 161751 78418 0.00 0.00 0.00 0.00 0.00 6.60 7.80 179.00 167.40 2.0 8279 1864566
+1 94 1 1 1 0 1790 103 58 0.80 0.80 174914 7706 0.00 0.00 0.00 0.00 1.00 1.20 1.20 51.60 65.20 3.0 353 1711541
+1 90 1 1 61 84 2896 158 124 0.60 0.60 17358 30465 5.20 6.60 6.20 0.00 0.60 1.60 1.60 38.40 56.00 1.0 299 987488
+1 86 1 1 11 5 5244 242 187 1.60 1.60 205563 26003 0.00 0.00 0.00 0.00 0.20 4.20 7.20 76.80 193.00 1.0 527 976651
+1 98 1 1 9 8 186 10 16 0.20 0.20 10308 4776 0.00 0.00 0.00 0.00 0.00 0.00 0.00 24.60 19.20 1.2 7663 1879509
+1 90 1 1 14 1 2900 240 211 3.00 1.20 165946 51916 0.00 0.00 0.00 0.00 0.20 10.80 18.20 148.40 220.00 2.8 3309 1547917
+1 89 1 1 0 0 338 52 31 0.20 0.20 271093 35462 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 17.76 1.6 2040 1763821
+1 86 1 1 16 0 1877 168 104 3.20 2.80 92379 38380 1.60 21.60 58.80 193.60 0.40 20.20 62.60 137.20 273.40 1.5 152 1056966
+1 81 1 1 17 9 2787 268 116 0.60 2.20 754629 62263 0.60 0.60 0.60 0.00 0.40 8.18 15.37 47.70 194.61 8.2 340 1297729
+1 80 1 1 25 31 2352 276 189 3.60 1.00 84138 13474 0.00 0.00 0.00 0.00 0.00 0.40 0.40 166.00 238.60 2.6 518 1745262
+1 75 1 1 10 2 3473 350 194 6.39 4.79 336687 21143 0.00 0.00 0.00 0.00 0.00 3.59 5.19 457.09 570.66 4.4 8008 1860413
+1 79 1 1 70 83 2171 247 138 1.40 9.58 299118 152053 5.79 19.76 28.94 54.49 1.80 7.39 13.97 226.35 287.03 9.0 347 1318009
+1 78 1 1 21 9 3550 435 277 3.60 2.80 292689 104828 0.00 0.00 0.00 0.00 0.00 16.00 23.80 252.60 469.80 1.0 2609 997461
+1 93 1 1 1 0 2081 126 75 0.40 1.80 286305 28351 0.00 0.00 0.00 0.00 0.00 10.18 10.18 34.53 66.07 1.3 882 1050243
+1 94 1 1 1 1 949 227 48 0.80 0.80 120175 13528 0.80 0.80 0.80 0.00 0.40 1.80 2.61 45.89 74.75 1.0 276 1731014
+1 89 1 1 0 0 681 62 40 0.20 0.20 1931 34918 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 18.40 1.8 991 1765360
+1 90 1 1 52 65 2385 124 102 0.80 0.80 112156 47219 0.00 0.00 0.00 0.00 0.00 6.01 8.22 56.31 91.98 1.2 549 1087394
+1 93 1 1 4 0 716 50 25 2.00 9.80 86846 19261 0.00 0.00 0.00 0.00 0.00 0.60 0.60 147.60 185.20 1.2 8403 1865018
+1 98 1 1 0 0 173 17 20 0.20 0.20 456 4817 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13.00 16.80 1.0 7306 1863872
+1 93 1 1 9 2 957 114 117 0.40 0.40 5523 21982 1.60 1.60 1.60 0.00 1.00 40.60 44.20 40.40 110.00 2.0 335 991712
+1 66 1 1 10 0 5812 701 587 9.40 2.80 321978 28967 0.40 0.40 0.40 0.00 0.20 1.00 1.20 478.00 741.20 1.0 330 1027738
+1 98 1 1 1 1 202 18 36 0.20 0.20 13420 4559 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 1.0 7219 1847104
+1 96 1 1 2 1 1681 155 35 0.60 3.00 22775 27131 0.00 0.00 0.00 0.00 0.00 0.20 0.20 47.60 60.60 1.4 8192 1836408
+1 77 1 1 53 63 3486 164 117 7.20 12.20 84134 25864 10.40 24.00 35.60 60.80 1.80 5.80 9.80 443.00 617.00 2.0 158 1026368
+1 81 1 1 96 113 3173 407 316 3.00 2.40 262944 45752 0.00 0.00 0.00 0.00 0.00 6.60 6.80 150.60 241.60 2.2 503 1120907
+1 77 1 1 20 8 2207 208 97 2.80 4.40 252626 99620 1.80 2.80 7.80 9.80 1.40 30.00 30.60 360.20 419.60 2.0 483 1014834
+1 89 1 1 1 1 3420 341 166 0.20 0.20 696743 147916 0.00 0.00 0.00 0.00 0.00 1.00 1.40 19.60 203.40 2.6 1341 1395784
+1 88 1 1 2 0 386 42 14 2.20 2.20 92461 20544 0.00 0.00 0.00 0.00 0.00 2.20 4.00 208.80 178.00 1.6 9145 1879085
+1 87 1 1 12 4 2439 162 130 1.60 3.21 34099 76305 0.00 0.00 0.00 0.00 0.20 9.62 14.63 104.21 155.11 1.0 1177 1114536
+1 89 1 1 1 0 2488 130 165 0.60 0.60 162018 30392 0.00 0.00 0.00 0.00 0.00 15.80 27.20 30.60 48.20 2.8 3857 1716347
+1 95 1 1 18 17 1021 92 77 0.20 0.20 9480 28576 0.00 0.00 0.00 0.00 0.00 0.00 0.00 28.14 19.36 1.2 1743 1079361
+1 84 1 1 5 0 3138 132 93 1.20 1.80 132558 48767 4.00 7.40 7.40 0.00 0.00 8.80 15.40 101.60 139.40 1.2 284 1001408
+1 95 1 1 2 1 1393 135 111 0.40 0.40 12864 54844 0.00 0.00 0.00 0.00 0.00 1.40 1.40 31.20 86.20 1.0 699 1062579
+1 78 1 1 68 71 2893 259 102 3.00 3.60 317902 77606 16.20 28.80 72.00 109.60 13.00 20.80 28.20 208.60 493.80 1.0 189 972046
+1 92 1 1 5 2 2574 112 87 0.40 0.60 56458 97339 0.00 0.00 0.00 0.00 0.00 0.80 1.00 43.80 50.00 3.2 1196 1548555
+1 90 1 1 3 1 579 57 39 2.00 2.00 151855 149247 0.00 0.00 0.00 0.00 0.00 1.80 1.80 200.20 155.80 1.6 5528 1842536
+1 95 1 1 3 1 964 80 47 0.40 0.20 181069 39597 0.00 0.00 0.00 0.00 0.00 3.40 6.20 36.00 52.00 2.4 6156 1843946
+1 91 1 1 9 6 2444 127 94 0.80 0.80 10375 22113 0.00 0.00 0.00 0.00 0.00 0.40 0.40 212.00 101.80 3.0 387 978213
+1 95 1 1 3 1 995 110 74 1.40 0.60 191157 15389 0.00 0.00 0.00 0.00 0.00 1.80 1.80 76.20 127.40 1.0 497 1012941
+1 97 1 1 1 1 245 32 22 0.20 0.20 20549 12114 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.4 7395 1865552
+1 91 1 1 7 4 1282 314 118 0.60 0.60 937754 24186 7.20 13.20 46.20 78.00 3.20 15.40 18.80 55.00 192.40 1.2 144 989789
+1 87 1 1 10 8 3514 176 111 1.80 3.80 375121 94898 0.00 0.00 0.00 0.00 0.00 1.80 2.00 101.00 229.40 5.6 2094 1640810
+1 61 1 1 81 94 5480 729 683 9.00 6.60 476209 430097 0.00 0.00 0.00 0.00 0.00 24.00 24.60 412.40 754.60 2.2 1473 1037573
+1 94 1 1 1 0 3419 249 144 0.20 0.20 197230 207916 0.00 0.00 0.00 0.00 0.00 0.60 0.60 13.20 41.80 3.6 3708 1346824
+1 90 1 1 32 47 1389 170 96 0.20 0.20 398035 25963 0.00 0.00 0.00 0.00 0.00 4.39 20.36 16.77 29.74 1.0 1473 1093851
+1 90 1 1 2 1 4024 175 169 0.20 0.20 24876 223160 0.00 0.00 0.00 0.00 0.00 3.60 5.60 16.00 34.80 2.6 1236 1395318
+1 88 1 1 16 1 2425 124 108 1.20 1.20 154629 100614 7.21 18.84 40.08 56.31 1.20 5.81 7.41 88.98 214.03 1.7 134 1056598
+1 0 1 1 7 5 1243 144 71 0.60 0.40 55702 34563 0.00 0.00 0.00 0.00 0.00 0.40 0.60 32.46 42.69 422 96 4
+1 90 1 1 12 2 2144 148 134 3.00 9.20 97089 19517 0.00 0.00 0.00 0.00 0.20 0.60 0.60 147.80 223.80 4.4 887 1638498
+1 97 1 1 1 0 907 106 76 0.20 0.20 24733 69413 0.00 0.00 0.00 0.00 0.20 0.40 0.60 16.40 34.40 1.3 511 1061837
+1 96 1 1 25 38 771 117 48 0.20 0.20 5607 25167 0.00 0.00 0.00 0.00 0.00 0.20 0.40 13.43 17.84 1.2 692 1738142
+1 96 1 1 9 8 2064 61 69 0.20 0.20 2085 14400 0.00 0.00 0.00 0.00 0.00 0.40 0.40 21.40 26.80 2.0 1706 1009560
+1 53 1 1 18 0 4574 741 595 10.40 9.00 798352 550111 14.60 83.40 211.60 460.00 2.40 18.40 53.20 570.20 1029.20 4.6 346 1022109
+1 0 1 1 59 66 3486 459 227 1.00 0.40 821073 703274 0.00 0.00 0.00 0.00 0.00 0.60 0.80 119.60 95.60 634 85 15
+1 86 1 1 38 54 4622 205 160 0.20 0.20 11591 55704 0.00 0.00 0.00 0.00 0.20 1.20 1.20 15.60 39.60 2.0 348 1067128
+1 0 1 1 3 0 1093 189 128 0.40 0.60 17112 78185 13.03 21.04 28.06 15.23 6.01 31.06 34.87 37.47 105.61 196 90 10
+1 97 1 1 0 0 314 40 40 0.60 0.60 6241 9258 0.00 0.00 0.00 0.00 0.00 0.00 0.00 28.20 38.80 2.0 3170 1708352
+1 94 1 1 5 2 1918 140 109 0.80 0.80 123435 146039 0.00 0.00 0.00 0.00 0.00 2.40 3.20 48.60 106.00 2.4 2156 1550651
+1 83 1 1 5 0 3511 228 205 5.80 2.00 137255 41885 0.00 0.00 0.00 0.00 0.00 0.00 0.00 258.60 376.40 2.4 433 1758200
+1 97 1 1 1 0 451 41 73 0.20 0.20 20545 73753 0.00 0.00 0.00 0.00 0.00 7.40 7.60 17.40 35.00 2.5 483 1061952
+1 94 1 1 1 0 562 91 83 1.00 0.80 1594 7916 0.00 0.00 0.00 0.00 0.00 0.20 0.40 63.87 157.68 1.6 571 1728011
+1 87 1 1 2 0 2396 202 106 1.60 2.80 579404 22490 0.00 0.00 0.00 0.00 0.00 4.00 6.40 99.40 134.60 3.8 599 1096501
+1 81 1 1 22 7 4405 350 223 1.20 2.40 665083 125980 8.80 37.20 87.60 209.40 1.80 16.80 30.00 75.80 222.20 8.0 295 1298189
+1 88 1 1 38 54 2482 124 111 0.80 1.40 53726 185804 0.00 0.00 0.00 0.00 0.40 3.00 3.00 95.20 83.40 4.0 628 1017234
+1 85 1 1 856 216 1464 79 23 1.20 1.00 38375 43463 0.00 0.00 0.00 0.00 0.00 14.20 14.40 56.80 83.40 1.6 3144 1845290
+1 80 1 1 3 0 1518 95 546 2.40 3.20 91213 113264 0.00 0.00 0.00 0.00 0.00 2.00 2.20 215.80 195.60 1.2 2499 1819904
+1 97 1 1 2 0 306 43 38 0.40 1.40 845 10232 0.00 0.00 0.00 0.00 0.00 0.00 0.00 36.00 41.00 2.0 6381 1711666
+1 90 1 1 5 1 2626 231 169 0.80 1.00 60891 52848 0.00 0.00 0.00 0.00 0.00 0.60 0.60 54.00 73.20 2.4 2294 1534176
+1 94 1 1 1 0 819 73 56 0.20 0.20 98716 52191 5.60 6.80 6.80 0.00 0.80 1.00 1.80 15.00 97.40 1.0 173 1023683
+1 91 1 1 0 0 1124 67 55 0.20 0.20 2781 12296 0.00 0.00 0.00 0.00 0.00 0.20 0.40 20.00 16.80 1.8 778 1758064
+1 97 1 1 1 1 198 16 24 0.20 0.20 7924 10576 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.03 16.83 1.0 7238 1868701
+1 94 1 1 11 10 2007 127 102 0.60 0.60 32665 49643 1.60 1.60 1.60 0.00 0.60 1.60 2.00 36.20 62.40 2.0 329 989029
+1 88 1 1 20 17 2175 397 197 0.20 0.20 643307 639374 5.80 7.00 7.00 0.00 6.00 5.00 8.40 31.40 67.00 1.5 278 1043112
+1 90 1 1 1 0 1635 173 114 0.60 0.80 111740 27259 0.00 0.00 0.00 0.00 0.00 19.60 32.60 56.40 70.40 1.8 994 1127674
+1 98 1 1 0 0 341 153 54 0.20 0.20 225248 238684 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.2 1703 1759920
+1 92 1 1 1 0 1444 124 92 0.80 2.40 99178 22756 1.80 1.80 1.80 0.00 0.20 0.60 0.60 46.60 87.40 2.0 211 1118126
+1 69 1 1 20 0 5722 1013 820 2.60 0.80 667520 174329 3.80 21.60 68.00 117.60 1.00 33.20 38.20 124.20 283.20 5.0 156 1044653
+1 81 1 1 11 2 4053 131 92 2.00 1.80 229531 74623 0.00 0.00 0.00 0.00 0.00 6.20 6.80 133.40 223.00 3.4 1084 1516277
+1 67 1 1 88 47 3382 347 220 7.39 18.56 360144 142694 0.00 0.00 0.00 0.00 0.20 15.57 24.95 343.11 576.45 1.0 497 1102534
+1 90 1 1 2 1 2201 96 49 0.60 1.40 365028 209294 0.00 0.00 0.00 0.00 0.00 41.20 81.00 59.60 146.80 3.2 2689 1730584
+1 92 1 1 10 7 1122 109 79 1.80 1.80 66512 38500 0.00 0.00 0.00 0.00 0.00 2.61 2.81 72.14 159.92 3.6 540 970956
+1 90 1 1 3 2 3423 146 160 0.80 1.20 31159 24676 5.41 5.81 5.81 0.00 0.60 0.40 0.40 70.34 93.39 1.5 220 1025794
+1 79 1 1 18 15 7119 288 232 0.80 0.60 469495 104663 3.99 15.37 27.74 48.10 1.60 18.56 19.76 54.29 149.50 3.0 160 997265
+1 89 1 1 13 2 1438 82 80 0.20 0.20 5794 42148 5.60 30.40 39.40 68.00 0.60 11.20 104.60 21.60 82.60 1.3 218 1054350
+1 71 1 1 14 8 5089 232 176 2.60 10.40 412560 370166 6.40 36.80 98.40 192.00 5.20 25.80 42.00 202.20 310.20 5.0 127 1376259
+1 91 1 1 22 30 915 152 79 0.40 0.80 193376 159007 0.00 0.00 0.00 0.00 0.00 2.40 2.80 39.00 39.00 4.4 2372 1565046
+1 82 1 1 60 72 3150 285 205 0.80 0.80 248818 306181 5.40 12.00 21.00 16.60 5.00 18.00 19.80 69.60 161.80 2.6 192 1313083
+1 87 1 1 34 48 3941 283 270 1.80 0.80 194163 352420 0.00 0.00 0.00 0.00 0.80 1.60 1.60 95.20 151.20 2.6 882 1372090
+1 89 1 1 1 0 1606 148 123 0.60 1.00 101977 79770 5.80 15.40 30.60 99.00 0.20 21.20 29.40 55.60 96.00 2.0 188 1099693
+1 88 1 1 29 42 2656 410 312 0.20 0.20 180209 32295 0.00 0.00 0.00 0.00 0.40 0.40 0.40 19.20 23.00 2.4 427 1693699
+1 72 1 1 88 72 6078 332 221 3.80 10.40 359195 203698 0.00 0.00 0.00 0.00 0.20 15.60 25.60 316.20 414.20 4.4 737 1336512
+1 1 1 1 32 14 2141 221 115 3.60 17.60 108448 24365 1.60 2.20 2.20 0.00 0.20 15.20 16.80 178.40 355.20 402 82 16
+1 77 1 1 7 1 1692 118 76 6.40 18.80 1062718 22681 4.80 11.40 18.80 32.80 0.00 15.80 18.00 211.00 432.40 2.5 168 1087544
+1 86 1 1 17 15 3856 250 177 1.20 2.40 50246 29854 0.00 0.00 0.00 0.00 0.20 12.20 12.20 100.80 131.80 2.0 767 1017691
+1 91 1 1 7 1 1598 164 126 0.40 0.40 160440 77520 3.40 9.20 17.40 20.80 3.40 40.80 49.00 57.60 95.60 2.0 204 1129565
+1 88 1 1 10 15 220 19 30 0.20 0.20 15758 32757 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.4 2033 1770843
+1 79 1 1 8 1 2702 414 340 4.60 3.80 173275 127401 0.00 0.00 0.00 0.00 0.00 23.80 24.00 322.40 458.00 2.0 988 1015205
+1 84 1 1 4 2 4804 232 164 0.20 0.20 115314 86722 0.00 0.00 0.00 0.00 0.00 4.40 4.40 18.40 95.40 7.4 1034 1312821
+1 72 1 1 11 3 6599 306 263 4.60 5.20 184847 164077 8.60 15.00 24.40 31.20 5.60 16.40 21.20 239.60 501.00 3.0 168 990966
+1 93 1 1 1 1 384 92 54 0.20 0.20 259906 238551 0.00 0.00 0.00 0.00 0.00 2.40 4.80 15.60 16.80 2.2 4128 1825290
+1 89 1 1 3 0 1131 89 69 0.80 0.40 41757 72089 9.58 16.37 13.17 0.00 0.60 3.59 3.59 48.70 204.19 1.0 263 1117493
+1 86 1 1 27 33 2254 132 132 3.19 1.60 60873 74996 17.17 26.95 43.51 43.71 10.78 15.17 26.75 162.67 252.49 1.8 167 1723071
+1 69 1 1 10 0 3430 366 152 7.20 23.20 274847 27494 8.60 50.80 110.20 204.20 1.20 37.80 48.00 309.20 804.00 1.4 148 1084952
+1 90 1 1 5 1 2312 80 81 0.20 0.20 5089 14521 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 18.80 2.0 835 1750304
+1 85 1 1 5 0 1794 99 106 5.60 8.20 43470 345679 0.00 0.00 0.00 0.00 0.00 1.80 1.80 167.60 357.40 2.2 6415 1851832
+1 76 1 1 19 12 5315 437 423 4.19 1.20 262877 50135 3.79 4.79 4.39 0.00 7.58 6.59 6.59 204.19 364.27 1.0 320 971347
+1 84 1 1 1 0 3341 132 200 2.40 5.00 191162 459666 0.00 0.00 0.00 0.00 0.00 22.20 32.00 65.00 155.40 2.2 855 1038861
+1 97 1 1 0 0 226 31 34 0.20 0.20 21032 19301 0.00 0.00 0.00 0.00 0.00 0.80 1.40 15.80 17.20 1.0 6234 1857173
+1 90 1 1 10 1 1414 191 319 1.00 0.60 272169 51784 0.00 0.00 0.00 0.00 0.00 0.60 0.60 50.20 81.00 2.6 1420 1715034
+1 80 1 1 190 208 5275 401 263 2.20 4.80 753429 40588 0.00 0.00 0.00 0.00 0.00 18.40 30.60 100.00 306.80 1.5 594 1010032
+1 90 1 1 6 2 2810 467 250 0.40 1.80 292182 101724 0.00 0.00 0.00 0.00 0.00 4.20 7.00 21.60 49.60 4.4 3058 1605155
+1 87 1 1 7 6 2446 349 216 1.00 3.41 47815 34294 0.00 0.00 0.00 0.00 0.40 6.21 6.21 41.68 80.96 1.8 385 1100598
+1 97 1 1 6 5 551 71 68 0.40 1.80 16543 35390 0.00 0.00 0.00 0.00 0.00 0.60 0.60 25.80 30.80 2.0 2638 1728000
+1 87 1 1 2 1 1116 97 62 0.40 0.60 298029 57307 0.00 0.00 0.00 0.00 0.00 10.00 18.80 37.40 48.60 2.6 3771 1771147
+1 80 1 1 25 9 2112 155 98 2.79 6.19 149522 27273 2.99 3.99 19.96 32.53 1.40 16.77 22.16 163.87 406.59 1.2 1645 951912
+1 85 1 1 101 2 5227 208 110 0.80 0.80 821072 74087 0.00 0.00 0.00 0.00 0.20 2.40 2.40 52.20 143.20 3.6 2557 1632006
+1 92 1 1 3 0 1202 101 106 0.60 0.60 142319 88654 0.00 0.00 0.00 0.00 0.00 8.20 8.60 51.80 76.80 1.0 411 1061699
+1 97 1 1 2 0 325 44 36 0.80 0.80 11252 11785 0.00 0.00 0.00 0.00 0.00 0.00 0.00 61.00 61.00 2.0 3173 1708285
+1 82 1 1 5 3 1507 196 146 1.40 2.40 355598 323470 23.40 44.60 44.20 0.00 0.20 9.80 18.80 80.00 147.60 2.8 594 1722392
+1 92 1 1 13 3 744 45 66 1.20 1.00 52868 11534 0.00 0.00 0.00 0.00 0.00 0.00 0.00 83.00 101.80 1.0 7564 1871114
+1 87 1 1 19 7 2115 255 97 3.20 3.40 184244 138777 0.00 0.00 0.00 0.00 0.00 1.20 1.40 160.80 300.40 4.0 2538 1577461
+1 79 1 1 84 37 3277 261 221 4.40 2.80 253538 87740 3.80 19.60 29.80 27.00 2.00 15.60 23.60 230.20 425.60 5.2 240 1081061
+1 78 1 1 28 10 4615 126 98 2.20 5.79 41279 6016 0.00 0.00 0.00 0.00 0.00 2.59 2.79 215.57 228.74 4.0 629 1538887
+1 83 1 1 0 0 2210 135 69 0.40 0.40 226358 24348 2.40 24.80 38.80 43.00 0.40 9.20 17.00 36.40 82.40 2.6 236 1742238
+1 78 1 1 9 0 3793 347 296 5.00 2.20 148737 40376 0.20 0.20 0.20 0.00 0.60 49.40 50.20 246.00 515.20 1.0 840 978990
+1 93 1 1 1 0 4591 79 102 0.20 0.20 62867 42250 1.60 6.39 12.38 18.56 0.00 6.99 13.37 20.76 42.32 1.5 180 1013748
+1 97 1 1 0 0 280 15 22 0.40 0.40 16155 13745 0.00 0.00 0.00 0.00 0.00 0.00 0.00 40.60 50.60 1.4 7192 1874133
+1 62 1 1 16 0 3595 425 333 12.00 33.80 315121 47203 3.40 9.40 14.80 27.40 11.80 3.40 6.40 380.60 733.40 2.4 159 1080640
+1 81 1 1 14 18 498 58 35 2.20 2.20 94619 27799 0.00 0.00 0.00 0.00 0.00 2.20 2.60 204.20 172.20 1.2 393 1813523
+1 69 1 1 10 0 3467 567 446 8.40 3.20 837479 24967 0.00 0.00 0.00 0.00 0.00 0.60 0.80 427.40 623.00 5.0 2972 1762784
+1 89 1 1 9 1 3562 567 527 0.20 0.20 476112 460575 2.40 15.97 42.12 182.63 0.00 10.58 52.50 15.57 23.35 3.2 153 1394962
+1 78 1 1 10 3 3180 433 390 5.01 1.40 271335 136601 3.61 7.21 7.21 0.00 0.80 10.62 12.02 237.07 429.66 3.4 625 958091
+1 81 1 1 8 0 3454 394 323 3.40 1.00 208051 178541 7.40 22.60 38.20 82.20 6.00 13.00 15.60 166.20 328.40 1.0 159 997997
+1 91 1 1 2 0 1806 117 104 0.40 0.40 32221 56025 4.60 8.20 8.20 0.00 0.20 2.20 2.20 27.40 33.80 3.8 169 1029627
+1 92 1 1 2 1 1632 128 102 0.40 0.20 92965 48978 0.00 0.00 0.00 0.00 0.20 5.59 5.59 27.35 89.22 1.6 473 974620
+1 85 1 1 46 35 1800 207 131 2.40 3.60 439817 75475 2.40 2.40 2.40 0.00 1.40 29.80 30.80 142.60 275.40 1.0 270 1118438
+1 89 1 1 50 66 2373 147 91 2.20 2.20 199369 78755 0.00 0.00 0.00 0.00 0.00 1.80 2.80 154.60 261.60 2.6 703 1537453
+1 90 1 1 3 0 2201 201 74 0.40 1.00 111582 23487 0.80 0.80 3.60 7.20 0.00 9.00 23.40 33.80 46.80 3.6 139 1112096
+1 64 1 1 18 2 2957 226 127 12.00 34.40 88464 33763 0.00 0.00 0.00 0.00 0.00 32.80 34.60 425.20 781.80 2.0 567 1086784
+1 90 1 1 1 0 2159 410 217 0.40 0.60 13065 22843 0.00 0.00 0.00 0.00 0.00 10.98 10.98 32.14 65.47 1.8 370 1099321
+1 69 1 1 87 45 4469 301 210 9.00 19.40 237822 144350 0.00 0.00 0.00 0.00 0.00 9.00 13.20 328.00 602.00 2.0 428 1096499
+1 66 1 1 217 2 2358 130 151 3.41 3.81 197593 265851 3.61 12.02 41.28 80.76 0.80 126.45 151.30 159.72 362.32 2.8 169 1014346
+1 88 1 1 10 8 6647 235 228 0.20 0.20 14918 62481 0.00 0.00 0.00 0.00 0.00 1.00 1.00 16.23 43.69 3.0 358 1069267
+1 92 1 1 10 7 939 91 83 0.80 0.40 193957 15920 6.60 13.20 13.20 0.00 0.00 1.60 1.60 63.00 75.60 1.0 639 1057786
+1 83 1 1 3 2 2069 103 78 0.80 1.00 82489 18122 0.00 0.00 0.00 0.00 0.00 1.00 3.60 59.60 73.00 3.0 510 1757989
+1 94 1 1 5 4 350 64 49 0.40 0.60 17411 77711 15.60 29.40 29.40 0.00 1.40 3.60 4.40 36.80 40.40 1.0 147 1753459
+1 96 1 1 0 0 404 55 41 0.20 0.20 2133 12253 0.00 0.00 0.00 0.00 0.00 0.20 0.20 17.40 19.40 2.0 696 1722088
+1 93 1 1 35 23 1686 107 67 1.40 2.60 221992 21091 0.00 0.00 0.00 0.00 0.00 0.40 0.60 94.60 151.00 1.0 1874 1008506
+1 83 1 1 17 6 3602 268 218 3.00 1.60 609352 126676 0.00 0.00 0.00 0.00 0.00 29.00 64.60 168.00 280.60 5.0 4126 1334456
+1 61 1 1 190 36 5134 711 631 7.00 2.00 379021 172375 10.60 49.80 99.00 160.00 0.20 32.80 50.60 338.40 623.00 3.0 138 1017674
+1 97 1 1 0 0 191 16 26 0.20 0.20 5571 15140 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 7293 1875112
+1 96 1 1 3 2 1232 50 40 0.20 0.20 3482 41303 4.39 9.58 17.76 16.57 1.00 4.79 4.79 20.96 36.13 1.3 165 1063457
+1 92 1 1 1 0 3573 106 114 0.40 0.60 75742 125259 0.00 0.00 0.00 0.00 0.00 1.20 1.40 36.47 87.58 1.8 448 1018682
+1 64 1 1 104 118 5679 569 448 7.20 5.00 407867 26012 0.00 0.00 0.00 0.00 0.20 19.60 20.00 362.20 621.00 6.6 905 1295725
+1 91 1 1 10 5 2337 74 54 1.00 1.40 10637 60984 0.00 0.00 0.00 0.00 0.00 0.00 0.00 143.00 96.40 2.0 5050 1673683
+1 97 1 1 3 2 277 30 25 0.40 0.40 22035 6858 0.00 0.00 0.00 0.00 0.00 0.00 0.00 28.60 41.00 2.2 3361 1819552
+1 92 1 1 43 50 1532 178 80 1.20 1.20 153622 48096 0.00 0.00 0.00 0.00 0.00 1.40 1.80 69.40 163.20 2.8 3403 1534949
+1 96 1 1 1 0 220 12 19 0.40 0.40 2501 8204 0.00 0.00 0.00 0.00 0.00 0.00 0.00 37.80 33.60 1.0 5782 1864648
+1 83 1 1 28 0 4875 252 173 0.80 1.20 138830 48403 27.35 62.48 157.49 426.75 0.20 30.94 65.27 73.05 210.18 1.2 139 1015904
+1 89 1 1 5 1 1391 177 158 3.39 1.00 104967 6694 0.00 0.00 0.00 0.00 0.00 0.20 0.20 162.28 231.54 1.0 7269 1871409
+1 77 1 1 204 226 3108 381 183 0.60 0.80 1207116 324896 2.80 11.60 25.40 44.60 0.40 19.20 28.40 61.80 128.80 1.4 229 1019115
+1 94 1 1 2 1 764 132 78 0.60 2.40 301591 53269 0.00 0.00 0.00 0.00 0.00 4.60 9.20 41.60 70.20 3.8 2603 1727674
+1 92 1 1 3 1 1283 173 128 0.40 0.40 140358 87665 3.60 6.00 5.40 0.00 0.60 2.40 3.20 55.00 49.00 1.0 291 1068875
+1 87 1 1 7 4 4185 179 120 0.60 0.80 272263 138962 0.00 0.00 0.00 0.00 0.00 8.80 8.80 56.00 85.60 3.6 573 1541683
+1 77 1 1 22 6 6243 410 347 1.20 1.60 248374 39425 2.80 19.00 31.60 67.40 2.60 3.80 4.20 125.40 162.00 4.2 131 1393301
+1 92 1 1 0 0 786 69 44 0.20 0.20 5189 25007 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 17.00 1.4 762 1750550
+1 94 1 1 0 0 1498 172 43 0.20 0.20 13410 23242 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.6 5805 1818256
+1 97 1 1 1 1 866 72 52 0.20 0.20 126330 110599 0.00 0.00 0.00 0.00 0.00 12.40 24.80 15.80 16.80 1.0 8506 1837072
+1 98 1 1 0 0 179 10 30 0.20 0.20 2182 20065 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.20 16.80 1.0 7167 1873768
+1 97 1 1 0 0 174 10 10 0.20 0.20 20814 4821 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.40 22.60 1.0 6357 1870942
+1 89 1 1 16 5 2809 284 101 1.00 0.80 59725 12710 0.00 0.00 0.00 0.00 0.00 28.80 29.00 46.40 240.40 4.2 7209 1379947
+1 65 1 1 56 31 6025 509 410 6.60 10.40 357773 269817 0.00 0.00 0.00 0.00 0.00 1.20 1.40 471.80 548.40 4.8 2450 1644301
+1 91 1 1 14 21 1191 93 51 0.20 0.20 3079 5915 0.00 0.00 0.00 0.00 0.00 1.80 1.80 15.60 19.60 1.8 657 1759232
+1 77 1 1 46 63 1602 102 88 0.60 0.60 160155 78983 6.20 30.80 62.80 202.80 0.00 5.00 7.80 72.40 173.20 4.2 218 1517030
+1 96 1 1 1 0 1552 104 135 0.20 0.20 9644 30750 0.40 0.40 0.40 0.00 0.20 4.60 5.40 14.40 31.00 1.0 190 1046680
+1 76 1 1 17 0 3861 414 329 5.39 2.00 333146 24300 1.20 11.98 56.49 84.23 0.00 7.39 32.34 331.14 488.22 2.6 170 1060878
+1 78 1 1 1 0 3235 358 357 0.20 0.20 507366 535487 24.60 92.20 249.20 516.80 0.20 61.40 122.60 15.80 36.80 1.7 101 1063947
+1 94 1 1 1 0 2924 104 146 0.20 0.20 5775 45319 3.80 4.00 4.00 0.00 0.40 0.20 0.20 15.60 16.80 2.0 252 1708706
+1 80 1 1 3 0 3565 361 246 3.00 6.40 219668 173869 0.00 0.00 0.00 0.00 0.00 8.20 14.40 163.40 293.80 2.5 2486 996440
+1 89 1 1 6 4 1969 259 119 1.60 4.20 1036736 75725 0.00 0.00 0.00 0.00 0.00 1.00 1.20 82.20 133.60 1.0 633 1037386
+1 90 1 1 23 18 1962 62 69 1.00 1.00 101240 69589 0.00 0.00 0.00 0.00 0.00 3.00 5.20 53.40 194.00 3.2 8202 1404438
+1 91 1 1 4 0 2237 243 109 0.40 0.80 48026 35618 0.00 0.00 0.00 0.00 0.00 9.82 46.89 40.48 81.36 1.0 787 1085459
+1 88 1 1 0 0 881 42 24 0.20 0.20 1536 7161 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 1.6 1210 1753160
+1 83 1 1 50 55 1562 118 58 2.60 3.20 323290 39714 6.40 12.80 70.40 135.40 5.60 4.20 6.40 183.20 452.80 1.4 189 948240
+1 85 1 1 4 1 2753 225 143 1.00 1.20 930934 362163 9.60 62.40 144.40 330.00 0.00 65.00 129.80 92.60 129.20 4.2 116 1543341
+1 91 1 1 5 3 3878 123 133 0.80 0.80 5190 19411 1.80 1.80 1.80 0.00 0.80 0.00 0.00 46.00 63.80 1.6 298 1748235
+1 89 1 1 112 60 2131 230 173 1.00 2.40 207237 183891 0.00 0.00 0.00 0.00 0.00 1.80 2.00 82.80 135.00 2.2 4792 1672382
+1 88 1 1 14 0 1800 193 122 1.60 4.79 1102299 39041 17.96 66.47 80.44 47.70 0.00 29.14 71.46 88.02 138.72 1.5 1359 989162
+1 95 1 1 6 5 1064 132 90 0.20 0.20 183030 27829 0.00 0.00 0.00 0.00 0.00 1.20 1.20 17.23 44.09 3.2 1490 969653
+1 89 1 1 2 0 467 44 21 2.20 2.00 95990 64953 0.00 0.00 0.00 0.00 0.00 2.20 3.80 200.80 164.60 1.0 7532 1865549
+1 77 1 1 19 13 3798 348 222 3.60 4.80 1013563 885994 0.00 0.00 0.00 0.00 0.40 11.60 19.00 186.20 290.00 1.3 660 1014594
+1 89 1 1 40 44 1491 111 84 2.20 6.40 166590 41098 0.00 0.00 0.00 0.00 0.00 2.60 3.60 70.00 198.80 5.6 552 1622781
+1 88 1 1 9 4 3539 208 113 1.40 7.00 204879 6080 1.40 1.40 1.40 0.00 2.20 7.40 14.40 103.20 116.20 5.0 506 1319302
+1 91 1 1 10 7 1507 144 91 0.40 1.80 23105 26379 0.00 0.00 0.00 0.00 0.00 19.24 20.84 33.67 94.39 2.2 1074 975830
+1 91 1 1 18 4 1734 177 113 0.80 2.20 381629 48488 5.59 13.17 16.77 6.59 7.78 2.59 4.39 238.32 126.55 2.0 221 1008517
+1 59 1 1 230 170 7266 608 475 6.20 9.00 510565 259471 0.00 0.00 0.00 0.00 0.60 4.40 5.00 380.60 544.60 5.2 545 1530973
+1 87 1 1 24 19 2241 149 130 4.00 4.80 281949 299215 0.00 0.00 0.00 0.00 0.20 9.60 10.60 176.60 299.20 1.5 1379 1020952
+1 97 1 1 2 1 243 13 15 0.60 0.60 19519 8189 0.00 0.00 0.00 0.00 0.00 0.00 0.00 47.00 53.20 1.2 8393 1864787
+1 90 1 1 4 1 2984 276 176 1.20 1.20 134618 58090 0.00 0.00 0.00 0.00 0.00 2.80 5.20 56.60 109.60 1.5 478 1081077
+1 77 1 1 12 1 4309 764 686 5.19 2.20 478330 364735 3.19 6.19 10.38 11.98 0.80 5.39 11.98 271.86 418.16 3.0 181 1003125
+1 81 1 1 14 6 2105 294 172 2.59 4.19 1164744 82863 3.19 3.79 9.18 11.18 22.55 7.78 27.54 211.18 389.62 2.5 210 974264
+1 87 1 1 1 0 1278 149 122 0.20 0.20 365791 88856 10.22 18.64 15.03 0.00 5.01 9.42 13.63 15.23 59.92 3.6 274 1043205
+1 79 1 1 13 1 5052 677 581 5.18 1.39 214153 111303 1.39 1.59 4.78 6.77 1.00 0.40 0.40 243.03 403.59 1.5 192 1083463
+1 89 1 1 1 0 4921 202 147 0.60 1.40 71952 49607 0.00 0.00 0.00 0.00 0.00 2.40 4.20 45.80 65.40 1.8 1875 1710853
+1 95 1 1 1 0 1279 76 60 0.40 0.40 5187 21909 0.00 0.00 0.00 0.00 0.20 0.40 0.60 26.75 29.74 2.0 760 1039144
+1 86 1 1 2 0 1484 257 364 1.40 1.60 191652 98350 3.20 8.80 25.80 45.80 0.20 10.40 15.80 72.60 121.00 4.2 177 1703526
+1 88 1 1 22 13 2831 376 152 0.40 0.40 449524 505237 0.00 0.00 0.00 0.00 0.00 0.60 1.20 31.00 118.80 1.8 631 1046166
+1 79 1 1 8 6 2263 481 171 2.60 5.40 399854 284917 8.40 16.80 49.80 99.80 0.80 3.80 3.80 383.40 309.80 5.0 144 1122085
+1 88 1 1 6 0 2731 135 123 1.00 0.60 319370 12894 0.00 0.00 0.00 0.00 0.00 44.40 74.20 68.80 150.80 2.8 3979 1718138
+1 92 1 1 29 38 1917 98 162 0.80 2.20 26811 172251 0.00 0.00 0.00 0.00 0.00 0.20 0.20 64.20 73.60 1.0 700 1077370
+1 73 1 1 11 0 2920 403 351 7.60 2.80 226968 22823 0.00 0.00 0.00 0.00 0.00 1.00 1.20 382.40 544.80 1.8 693 1759370
+1 0 1 1 87 113 1933 441 175 0.60 0.80 661668 724078 0.00 0.00 0.00 0.00 0.00 42.80 76.00 60.80 180.40 588 85 15
+1 98 1 1 0 0 303 48 39 0.20 0.20 253231 18778 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.80 19.60 1.2 8054 1862464
+1 96 1 1 1 1 313 23 40 0.20 0.20 8460 103930 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 17.00 1.0 5683 1840152
+1 51 1 1 25 8 5080 843 736 8.40 6.20 662262 507951 28.80 73.80 148.00 340.20 2.40 76.80 107.60 445.80 939.80 3.0 119 1030128
+1 98 1 1 1 1 178 16 9 0.20 0.20 35893 3878 0.00 0.00 0.00 0.00 0.00 0.20 0.40 17.80 19.80 1.0 7263 1848069
+1 94 1 1 1 0 591 74 48 1.20 2.00 96343 17447 0.40 0.40 0.40 0.00 0.00 21.20 22.60 75.00 115.00 3.2 234 1719037
+1 90 1 1 5 1 2037 84 83 2.00 2.40 53959 44009 0.00 0.00 0.00 0.00 0.00 7.58 8.38 78.24 146.51 1.8 1142 1124263
+1 93 1 1 22 19 2425 207 119 0.40 0.60 37916 28731 0.00 0.00 0.00 0.00 0.00 1.20 1.20 35.20 56.60 3.6 7675 1371205
+1 98 1 1 1 1 152 8 9 0.20 0.20 7001 3048 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 1.0 6460 1871616
+1 90 1 1 165 176 1057 242 83 1.80 0.60 1232467 6549 0.00 0.00 0.00 0.00 0.00 0.00 0.00 90.20 127.60 2.6 8450 1864304
+1 96 1 1 515 575 202 36 27 0.20 0.20 908 10669 0.00 0.00 0.00 0.00 0.00 0.80 0.80 15.60 16.80 1.0 6609 1856976
+1 98 1 1 3 2 267 35 30 0.20 0.20 9632 14033 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.17 18.16 1.0 647 1748749
+1 89 1 1 13 11 1779 483 181 1.60 1.20 751142 647291 0.00 0.00 0.00 0.00 0.00 1.00 1.60 97.00 152.00 3.2 567 1040558
+1 89 1 1 2 0 1997 347 216 0.20 0.20 79789 52096 3.40 3.80 6.20 3.40 3.20 4.40 5.20 175.40 81.80 1.0 177 1064438
+1 96 1 1 1 0 452 46 48 0.40 0.40 12705 45613 0.00 0.00 0.00 0.00 0.00 2.40 3.20 37.80 43.40 3.2 1241 1712851
+1 76 1 1 17 0 2620 188 117 6.61 19.64 191548 31831 4.21 15.43 33.67 44.69 0.00 18.44 26.65 255.51 508.82 1.6 149 1085324
+1 96 1 1 0 0 310 46 43 0.60 0.60 2741 6925 0.00 0.00 0.00 0.00 0.00 0.40 0.80 49.30 53.29 1.0 1920 1768619
+1 87 1 1 1 1 679 114 80 0.40 0.40 265622 14995 5.80 39.20 181.20 308.80 0.00 56.40 112.00 37.80 180.20 3.8 175 1722042
+1 95 1 1 1 0 1235 172 90 0.40 1.20 4897 15753 0.00 0.00 0.00 0.00 0.60 9.00 9.20 32.40 49.80 2.0 1049 1718782
+1 89 1 1 11 0 1118 64 51 3.00 4.60 53934 16807 1.40 1.60 1.60 0.00 0.40 23.00 23.40 227.40 302.40 2.0 285 1070042
+1 91 1 1 5 2 1476 103 90 1.60 1.60 181487 89106 0.00 0.00 0.00 0.00 1.20 3.60 6.00 125.20 153.40 2.4 615 1534014
+1 79 1 1 71 87 1921 230 144 6.00 17.20 318647 27609 0.00 0.00 0.00 0.00 0.00 6.20 6.20 216.20 489.60 2.0 543 1099277
+1 91 1 1 2 0 1557 97 84 2.00 2.40 41239 16244 0.00 0.00 0.00 0.00 0.00 2.80 3.00 115.00 155.00 3.4 518 1053942
+1 98 1 1 0 0 266 46 39 0.20 0.20 17961 5218 0.00 0.00 0.00 0.00 0.00 0.60 1.20 15.60 16.80 1.0 7227 1847184
+1 87 1 1 4 0 3605 365 139 1.00 1.80 550337 458674 0.40 0.60 0.60 0.00 0.20 20.44 24.25 100.60 194.59 3.6 581 1006190
+1 84 1 1 1 1 4693 235 192 0.60 0.40 348855 363934 14.03 27.45 27.45 0.00 4.61 5.21 9.22 40.68 56.31 3.8 301 1007096
+1 0 1 1 1 0 1785 88 84 0.20 0.20 23164 31231 4.00 5.20 5.20 0.00 0.00 0.20 0.20 15.80 31.40 154 96 4
+1 60 1 1 47 1 5782 249 218 11.18 33.13 144335 64720 0.40 0.60 0.60 0.00 1.00 14.17 14.37 367.47 720.76 4.0 243 1094050
+1 75 1 1 12 4 5671 179 125 2.40 4.80 357299 130956 8.20 26.80 57.40 122.80 4.40 2.20 2.20 247.80 314.40 4.4 148 1526715
+1 86 1 1 10 7 4379 244 151 2.20 2.20 80140 41270 0.00 0.00 0.00 0.00 0.00 0.80 1.00 93.60 159.00 2.5 2584 1014251
+1 98 1 1 1 0 1965 62 62 0.20 0.20 7315 52915 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.20 16.80 2.0 2094 1642685
+1 94 1 1 5 4 2096 137 105 0.20 0.20 4584 21087 0.00 0.00 0.00 0.00 0.00 1.00 1.00 20.04 100.00 1.6 516 978044
+1 87 1 1 13 9 990 78 67 1.00 1.60 123889 46300 0.00 0.00 0.00 0.00 0.00 20.56 33.13 123.95 263.67 1.3 512 1065831
+1 87 1 1 19 24 873 110 99 2.20 1.00 110991 25644 0.00 0.00 0.00 0.00 0.00 0.00 0.00 142.40 178.80 1.8 1024 1762342
+1 95 1 1 9 7 1193 48 39 0.20 0.20 5602 23886 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.77 31.74 2.8 902 973503
+1 89 1 1 2 0 2745 500 473 1.60 2.61 475622 350382 0.00 0.00 0.00 0.00 0.00 9.02 9.02 80.76 124.85 1.0 849 1131040
+1 88 1 1 14 2 2736 274 251 1.00 1.20 315718 199935 2.80 45.80 121.40 414.60 0.20 18.80 38.40 70.40 344.80 3.6 232 1399029
+1 78 1 1 277 285 3967 422 251 4.20 2.80 594708 103365 0.00 0.00 0.00 0.00 0.00 13.80 13.80 228.60 368.20 7.6 2633 1335160
+1 91 1 1 4 0 893 192 43 2.20 1.80 226622 106636 0.00 0.00 0.00 0.00 0.00 0.40 0.60 209.18 232.53 2.0 8872 1859895
+1 98 1 1 0 0 199 24 19 0.20 0.20 4935 9164 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 1.0 7276 1847232
+1 94 1 1 4 3 1500 100 104 0.40 1.40 9224 28250 0.00 0.00 0.00 0.00 0.20 1.40 2.40 23.20 30.60 1.0 440 1045754
+1 78 1 1 10 2 4133 392 307 6.00 2.80 250980 73843 0.00 0.00 0.00 0.00 0.00 4.20 5.20 316.00 475.60 1.0 1050 1058078
+1 92 1 1 19 17 1063 124 73 1.60 2.80 71903 23242 1.20 1.20 1.20 0.00 2.00 4.00 4.20 93.00 170.00 3.0 309 974800
+1 79 1 1 15 5 3625 193 127 1.80 8.58 298958 80896 24.55 35.33 50.70 34.13 12.77 18.56 24.75 141.92 281.04 7.4 206 1311396
+1 82 1 1 32 3 3090 299 268 3.40 2.20 266999 123153 0.80 1.00 8.80 28.40 0.40 20.80 38.00 212.80 343.00 2.2 370 1082306
+1 82 1 1 8 2 3000 342 265 3.00 2.20 280468 127589 0.00 0.00 0.00 0.00 0.00 21.80 24.20 169.60 292.40 4.2 1430 1043278
+1 90 1 1 2 1 482 70 13 1.80 1.80 353103 16885 0.00 0.00 0.00 0.00 0.00 2.00 3.41 170.34 154.51 1.4 11424 1885058
+1 93 1 1 26 39 1681 99 152 0.20 0.20 5788 102550 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.80 51.80 3.0 391 1061328
+1 77 1 1 12 4 4074 510 129 4.60 7.20 440079 36412 0.00 0.00 0.00 0.00 0.00 7.60 11.60 248.40 424.40 3.6 718 1012301
+1 98 1 1 1 0 1182 41 35 0.20 0.20 1195 4803 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.20 2.0 6187 1726776
+1 84 1 1 27 37 1887 182 172 0.20 0.20 172511 144573 0.00 0.00 0.00 0.00 0.00 0.80 1.20 15.57 45.31 2.2 850 1765946
+1 87 1 1 1 0 3591 219 113 1.00 4.00 494383 20340 1.40 1.40 1.40 0.00 6.00 8.80 10.00 76.20 127.20 4.0 202 1040878
+1 81 1 1 3 0 2071 226 253 0.40 0.40 572187 483574 9.40 87.60 205.20 491.00 0.20 62.40 118.00 42.80 90.80 3.7 124 1037978
+1 93 1 1 33 40 1774 89 57 0.60 0.60 209087 17601 0.00 0.00 0.00 0.00 0.00 0.00 0.00 54.71 81.36 1.0 6845 1864867
+1 96 1 1 2 0 465 51 64 1.00 0.40 20285 50349 0.00 0.00 0.00 0.00 0.00 0.00 0.00 55.51 71.14 1.0 7515 1867968
+1 91 1 1 32 31 813 113 79 3.00 1.20 49470 4308 0.00 0.00 0.00 0.00 0.00 0.20 0.20 167.80 239.20 2.4 6350 1724222
+1 98 1 1 1 0 208 20 38 0.40 0.80 1392 14222 0.00 0.00 0.00 0.00 0.00 0.40 0.40 22.00 26.60 1.0 6354 1857517
+1 80 1 1 9 0 2528 393 339 6.40 2.20 177417 18991 0.00 0.00 0.00 0.00 0.00 0.00 0.00 325.40 473.40 3.6 623 1710544
+1 90 1 1 19 5 2394 168 140 0.80 0.80 245608 228961 3.00 3.00 3.00 0.00 4.00 2.20 2.20 68.60 113.20 2.2 336 1521518
+1 97 1 1 1 0 160 16 16 0.20 0.20 752 6999 0.00 0.00 0.00 0.00 0.20 1.00 1.20 20.64 18.64 1.4 566 1738057
+1 85 1 1 6 0 2088 223 151 2.60 3.20 74339 26261 0.00 0.00 0.00 0.00 4.60 41.00 41.20 141.60 268.80 1.0 578 1066797
+1 94 1 1 55 80 1557 88 106 0.20 0.20 179093 82821 2.40 3.00 3.00 0.00 38.20 0.80 0.80 16.60 39.60 1.0 190 1064605
+1 79 1 1 68 84 5676 656 172 0.20 0.20 665462 468208 3.79 3.79 3.79 0.00 1.40 51.10 58.88 17.96 228.94 1.0 576 999928
+1 94 1 1 4 1 639 111 108 0.80 0.80 81040 53388 0.00 0.00 0.00 0.00 0.00 2.80 4.00 129.20 89.40 2.4 6908 1713547
+1 93 1 1 34 51 317 35 25 0.80 0.80 50096 10405 0.00 0.00 0.00 0.00 0.00 1.20 1.20 60.60 87.00 1.0 372 1742496
+1 97 1 1 2 1 197 14 23 0.20 0.20 6998 12768 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 5382 1860022
+1 90 1 1 4 0 2729 173 163 0.80 0.80 190292 24797 0.00 0.00 0.00 0.00 0.20 7.60 9.80 63.40 139.60 4.4 2873 1375566
+1 97 1 1 0 0 305 95 22 0.20 0.20 88105 14491 0.00 0.00 0.00 0.00 0.00 5.21 5.21 13.03 26.25 1.2 1597 1784334
+1 88 1 1 2 0 1884 133 84 1.20 1.40 92242 76126 0.00 0.00 0.00 0.00 0.00 12.80 21.00 82.40 378.40 2.0 810 1033502
+1 92 1 1 6 1 988 196 38 1.20 1.00 59739 17286 0.00 0.00 0.00 0.00 0.20 18.64 18.84 58.52 152.71 1.2 498 1733140
+1 57 1 1 1845 13 4377 125 118 3.80 4.00 33563 62630 1.40 1.80 1.60 0.00 0.80 2.20 2.60 184.60 289.80 4.2 376 1512704
+1 97 1 1 1 0 840 48 46 0.20 0.20 2048 13725 1.00 1.40 1.40 0.00 0.00 1.00 1.00 15.63 18.04 1.2 317 1018052
+1 67 1 1 23 13 2531 199 131 6.80 16.40 140011 77853 0.00 0.00 0.00 0.00 0.20 22.80 35.60 257.00 432.60 2.0 1284 1105122
+1 96 1 1 0 0 1193 118 38 0.20 0.20 334361 11815 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13.00 18.00 4.0 1284 1712965
+1 80 1 1 25 34 3032 325 155 0.40 0.40 375978 40713 4.76 15.28 35.91 58.93 4.37 3.97 6.35 38.89 80.16 3.6 133 1725756
+1 0 1 1 7 5 581 65 65 0.80 0.60 216603 25199 4.80 7.00 10.60 15.80 0.00 6.40 6.80 48.80 78.00 156 95 5
+1 90 1 1 73 94 2073 188 208 1.00 1.40 27350 111966 0.00 0.00 0.00 0.00 0.00 3.00 3.00 80.40 123.00 1.4 1126 1052686
+1 91 1 1 13 13 2035 148 121 0.20 0.20 254255 299557 0.00 0.00 0.00 0.00 0.00 6.39 6.59 15.77 69.46 1.3 1408 1018692
+1 59 1 1 66 3 4117 159 120 12.00 35.40 168445 64244 16.80 32.60 48.40 50.40 13.40 5.00 6.00 407.40 777.00 2.4 145 1094560
+1 77 1 1 14 0 5432 522 456 6.60 1.80 212925 49011 5.00 5.40 5.40 0.00 0.20 6.20 6.20 311.00 479.20 1.2 236 1068981
+1 70 1 1 11 3 4923 201 129 2.20 4.19 336425 13988 5.99 62.87 117.76 270.66 2.00 33.53 49.10 171.66 387.62 5.0 164 1312171
+1 93 1 1 1 0 2358 143 184 0.40 0.60 75627 11554 0.00 0.00 0.00 0.00 0.00 0.00 0.00 19.80 35.00 4.6 826 1637987
+1 91 1 1 4 0 1799 313 115 0.80 3.40 904098 27923 0.40 0.40 0.40 0.00 0.20 2.80 5.40 45.60 84.40 4.6 159 1110357
+1 83 1 1 24 20 2284 310 187 1.20 2.00 360668 526108 4.20 12.20 23.00 50.40 0.00 15.00 26.00 152.60 315.00 2.0 399 1035773
+1 72 1 1 46 2 4418 292 229 6.96 20.08 40625 25738 0.00 0.00 0.00 0.00 0.60 3.78 4.17 241.55 477.93 2.6 1416 1102454
+1 96 1 1 2 1 1202 34 45 0.20 0.20 2522 56655 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13.00 21.80 2.0 5014 1672688
+1 97 1 1 3 0 540 43 35 0.60 0.20 1700 23338 0.00 0.00 0.00 0.00 0.00 0.40 0.80 22.80 25.00 2.0 6195 1728032
+1 93 1 1 3 2 2879 229 150 0.40 0.60 20915 78528 0.00 0.00 0.00 0.00 0.00 3.41 5.01 53.51 136.87 1.6 471 996451
+1 90 1 1 3 0 2095 118 91 0.40 0.40 317741 97914 0.00 0.00 0.00 0.00 0.00 0.60 1.20 34.60 107.20 5.0 410 1522066
+1 97 1 1 20 27 147 12 12 0.20 0.20 7123 13270 0.00 0.00 0.00 0.00 0.00 0.40 0.80 15.60 16.80 1.0 8385 1864813
+1 88 1 1 26 23 2106 238 183 2.20 0.80 65300 29634 3.81 3.81 3.81 0.00 3.61 6.01 8.02 179.76 198.00 1.7 195 1076550
+1 68 1 1 50 2 4391 419 282 7.60 5.20 563240 22672 3.40 19.00 44.80 101.00 0.20 17.80 26.60 403.20 709.60 9.6 400 1289837
+1 95 1 1 0 0 238 34 32 0.19 0.19 14213 20702 0.00 0.00 0.00 0.00 0.00 0.19 0.39 15.20 18.13 1.0 1558 2042280
+1 75 1 1 33 21 2574 208 113 5.80 5.80 635811 92129 0.00 0.00 0.00 0.00 0.40 11.60 13.20 278.40 477.40 3.6 2059 1088930
+1 96 1 1 8 7 1446 65 78 0.20 0.20 5586 11140 0.20 0.20 0.20 0.00 0.20 0.20 0.20 24.20 19.20 2.0 393 1726670
+1 91 1 1 12 8 942 91 72 1.20 1.20 14671 34954 0.80 7.80 7.80 0.00 0.00 12.40 16.60 78.00 180.80 4.6 524 1023150
+1 82 1 1 4 0 5495 355 273 0.80 0.80 201946 33764 0.00 0.00 0.00 0.00 0.20 9.60 17.20 57.60 103.40 1.8 944 1070510
+1 90 1 1 10 6 4048 316 210 0.40 0.40 346276 341507 0.00 0.00 0.00 0.00 0.00 5.00 9.60 30.00 27.60 4.0 420 1549619
+1 87 1 1 16 12 2180 394 155 2.60 2.80 504805 679981 0.00 0.00 0.00 0.00 4.40 0.40 0.40 100.40 199.20 3.8 628 1045381
+1 78 1 1 15 13 1660 184 98 2.19 5.98 767315 30028 13.94 68.33 158.96 337.85 1.79 83.67 157.37 90.04 177.49 1.0 126 1101873
+1 97 1 1 1 0 659 79 72 0.20 0.20 12273 12505 0.00 0.00 0.00 0.00 0.00 1.00 1.00 19.00 17.40 3.0 1525 1717901
+1 94 1 1 4 3 4859 172 174 0.20 0.20 164186 176914 0.00 0.00 0.00 0.00 0.00 0.20 0.40 13.20 74.40 5.4 866 1320174
+1 73 1 1 18 13 3596 317 157 2.59 6.59 336597 73095 7.19 36.73 148.30 311.18 0.60 63.07 83.63 225.35 533.13 1.0 252 996648
+1 97 1 1 1 0 481 53 57 1.20 0.60 16429 15214 0.00 0.00 0.00 0.00 0.00 0.00 0.00 71.14 84.77 1.0 7217 1867607
+1 83 1 1 7 1 1321 84 36 5.40 5.60 139381 78821 0.00 0.00 0.00 0.00 0.00 2.00 3.20 350.60 435.20 1.6 6111 1847878
+1 88 1 1 39 61 2039 197 115 0.80 5.60 246681 29935 0.00 0.00 0.00 0.00 0.00 13.60 13.80 70.40 194.60 2.2 2055 1413619
+1 93 1 1 4 1 1245 115 82 2.00 0.80 147312 16759 0.00 0.00 0.00 0.00 0.00 0.40 0.40 103.60 175.60 1.0 1089 1062110
+1 93 1 1 1 0 865 150 115 0.20 0.20 20990 87927 0.00 0.00 0.00 0.00 0.00 2.81 2.81 16.63 145.49 1.0 659 1064699
+1 80 1 1 168 12 1667 193 48 5.80 5.80 1176816 24624 0.00 0.00 0.00 0.00 0.00 3.00 4.80 327.60 429.00 4.6 7632 1862787
+1 92 1 1 0 0 6450 157 157 0.40 0.60 9174 54104 0.80 1.00 1.00 0.00 0.00 0.60 0.60 35.07 104.21 1.0 180 1017812
+1 87 1 1 3 2 3855 1984 80 0.80 1.00 635931 73150 2.80 7.40 11.20 17.00 0.40 8.20 15.60 268.20 88.20 2.2 150 1129062
+1 93 1 1 1 0 1012 247 137 0.20 0.20 49962 40693 0.00 0.00 0.00 0.00 0.00 0.20 0.20 23.60 36.80 3.4 427 1061962
+1 97 1 1 3 2 256 67 28 0.20 0.20 10942 17701 0.00 0.00 0.00 0.00 0.00 1.60 2.59 15.57 23.95 1.2 1821 1775173
+1 85 1 1 5 0 8158 536 245 1.20 1.20 326530 205427 0.00 0.00 0.00 0.00 0.00 1.00 1.00 62.80 107.00 4.6 1207 1329096
+1 72 1 1 257 275 3697 642 517 3.39 1.20 533822 317751 32.53 59.28 150.50 448.70 1.60 4.19 7.58 192.42 406.39 3.5 166 1007147
+1 80 1 1 10 2 4806 317 187 0.60 3.00 394265 74984 0.00 0.00 0.00 0.00 0.40 5.20 5.60 43.20 215.40 8.4 826 1308418
+1 93 1 1 2 2 1049 93 55 0.80 1.20 82530 32811 0.00 0.00 0.00 0.00 0.20 1.80 2.00 50.40 143.00 1.0 574 1039853
+1 97 1 1 4 4 517 109 40 0.40 0.40 138351 146506 0.00 0.00 0.00 0.00 0.00 0.20 0.20 30.80 36.40 3.0 1098 1749926
+1 88 1 1 1 0 1136 108 53 0.60 0.60 139798 33742 0.00 0.00 0.00 0.00 0.00 1.00 1.00 44.20 56.60 1.6 505 1748077
+1 95 1 1 1 0 385 67 65 0.20 0.20 93006 48585 6.80 37.80 100.60 169.80 0.00 13.20 25.60 16.00 97.80 3.6 130 1711507
+1 96 1 1 2 1 434 15 19 0.60 0.80 9043 11519 0.00 0.00 0.00 0.00 0.00 0.00 0.00 33.73 45.31 1.0 7206 1859744
+1 92 1 1 5 2 3637 103 110 0.80 2.40 45895 113168 0.00 0.00 0.00 0.00 0.00 1.80 2.00 50.60 75.00 2.8 2521 1645106
+1 96 1 1 1 0 442 84 49 0.20 0.20 215389 4085 1.60 2.20 2.20 0.00 0.20 6.20 11.80 15.40 23.40 3.2 222 1704142
+1 77 1 1 76 2 5422 253 299 1.20 2.20 177270 562666 2.60 3.40 3.00 0.00 2.40 59.80 65.80 96.00 173.80 1.0 452 999261
+1 86 1 1 3 0 724 43 13 2.81 3.01 88088 19214 0.00 0.00 0.00 0.00 0.00 2.20 3.21 247.50 227.45 1.4 11780 1890676
+1 82 1 1 36 44 3028 350 336 2.40 7.20 239705 224320 0.40 0.40 0.40 0.00 0.40 12.40 19.80 122.80 233.60 3.8 498 1095611
+1 87 1 1 4 1 5063 288 240 0.80 0.80 94981 52687 0.00 0.00 0.00 0.00 0.00 1.60 1.80 62.67 105.19 2.6 2849 1443738
+1 94 1 1 2 2 1360 106 77 0.40 1.20 46607 22159 0.60 0.80 0.80 0.00 0.00 8.22 9.02 21.24 89.78 1.4 196 972189
+1 93 1 1 2 0 2037 131 122 0.40 0.40 120630 39618 0.00 0.00 0.00 0.00 0.00 6.40 6.40 46.00 74.20 3.6 574 1049920
+1 85 1 1 27 39 4342 477 324 0.40 0.60 105608 97979 0.00 0.00 0.00 0.00 0.00 11.38 11.38 57.09 185.63 2.0 1185 1082117
+1 98 1 1 2 1 213 24 19 0.40 0.40 8182 12511 0.00 0.00 0.00 0.00 0.00 0.00 0.00 23.60 31.00 1.0 7759 1882280
+1 90 1 1 95 111 2879 209 211 0.20 0.20 102004 136716 0.00 0.00 0.00 0.00 0.00 6.40 10.00 15.80 33.40 3.4 929 1402032
+1 82 1 1 14 6 1594 232 206 5.60 6.80 332216 51673 14.20 17.60 17.60 0.00 12.80 7.20 8.40 242.40 444.00 1.0 258 982355
+1 87 1 1 15 9 1852 174 153 0.40 0.40 31744 45354 18.16 41.12 65.07 71.06 0.00 19.56 33.33 94.41 163.47 1.3 282 963205
+1 82 1 1 421 93 2399 488 427 1.20 1.40 364724 369211 13.80 84.40 124.00 120.20 0.00 55.60 97.40 80.80 164.80 1.8 266 976278
+1 0 1 1 3 0 1617 354 220 0.40 0.40 592827 569846 0.80 2.80 2.80 0.00 0.40 1.00 1.80 42.20 110.20 468 90 10
+1 88 1 1 2 0 849 36 30 1.20 6.40 20978 6748 0.00 0.00 0.00 0.00 0.00 0.80 0.80 57.20 80.00 2.0 875 1751528
+1 90 1 1 8 6 1627 284 263 1.00 1.00 31480 59363 0.00 0.00 0.00 0.00 0.20 16.00 16.20 76.80 131.40 1.7 406 1099387
+1 93 1 1 1 0 965 176 121 1.00 0.40 174723 153621 0.00 0.00 0.00 0.00 0.00 1.80 3.40 52.40 108.00 4.2 340 1724080
+1 90 1 1 1 0 2112 109 89 0.80 3.61 108588 121214 0.00 0.00 0.00 0.00 0.20 3.61 4.41 43.29 65.13 1.8 2448 1012757
+1 89 1 1 3 1 1340 205 122 0.80 2.40 372970 188361 0.00 0.00 0.00 0.00 0.00 2.59 2.59 80.04 125.75 4.6 1314 1598261
+1 95 1 1 5 1 357 78 54 0.20 0.20 1986 6841 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13.57 15.17 2.0 6397 1708602
+1 93 1 1 2 1 990 139 109 0.60 0.40 14850 23152 0.00 0.00 0.00 0.00 0.00 21.16 21.96 38.32 84.23 4.0 768 1062687
+1 74 1 1 5 0 850 145 69 0.40 0.40 604037 25686 0.00 0.00 0.00 0.00 0.20 70.40 135.00 30.60 398.00 3.8 2948 1768731
+1 89 1 1 2 1 523 76 53 0.60 0.60 86956 13855 3.20 6.80 18.20 32.40 2.20 4.00 4.40 44.40 85.60 2.0 210 1756472
+1 72 1 1 25 8 4772 171 118 4.60 20.20 119132 119493 0.00 0.00 0.00 0.00 0.20 0.60 0.60 326.00 401.20 4.0 1653 1643622
+1 88 1 1 1 0 3105 288 178 0.40 0.60 170480 49000 5.99 21.36 56.69 146.91 5.79 17.37 17.76 49.10 142.12 1.5 181 1014231
+1 88 1 1 4 0 2335 330 256 1.00 1.00 149954 52374 9.18 19.56 38.32 51.50 0.00 16.57 31.54 52.30 140.52 1.0 157 1100803
+1 73 1 1 52 67 5028 397 361 5.40 5.20 114224 251581 0.00 0.00 0.00 0.00 0.00 5.40 5.40 186.20 392.40 1.8 462 995160
+1 82 1 1 5 3 5089 331 184 1.20 2.80 140551 83988 4.20 11.20 47.80 124.40 2.20 7.40 9.80 97.20 323.00 1.8 375 1017955
+1 89 1 1 5 0 4134 284 165 1.40 2.00 240249 178420 0.00 0.00 0.00 0.00 0.00 2.59 3.19 96.61 181.84 3.2 3327 1337281
+1 78 1 1 60 3 3491 480 354 4.60 2.00 627230 42192 5.80 23.00 35.60 54.80 2.40 50.20 112.00 260.00 415.60 1.8 213 1025504
+1 93 1 1 30 43 848 126 41 1.20 1.00 39046 8223 0.00 0.00 0.00 0.00 0.00 0.60 1.00 69.46 123.55 2.2 787 1706722
+1 96 1 1 2 1 205 23 21 0.20 0.20 11019 5549 0.00 0.00 0.00 0.00 0.00 1.00 1.00 16.00 22.80 1.0 7116 1847163
+1 0 1 1 18 5 2148 302 182 3.01 4.61 1238843 954679 8.82 12.83 39.48 85.57 0.40 1.80 3.61 154.91 278.56 135 87 13
+1 92 1 1 0 0 1855 175 161 0.40 1.80 42276 22413 0.80 0.80 0.80 0.00 0.00 2.79 4.99 32.34 51.10 1.0 274 1089161
+1 75 1 1 17 8 2105 204 135 6.40 18.00 135636 28884 4.40 6.20 25.40 77.60 3.40 20.60 23.60 304.20 601.20 4.0 143 1090653
+1 95 1 1 3 0 942 68 72 0.60 1.00 122953 112252 0.00 0.00 0.00 0.00 0.00 1.80 2.40 103.00 89.40 2.0 1860 1525842
+1 85 1 1 0 0 2173 89 119 0.20 0.20 390646 11791 0.00 0.00 0.00 0.00 0.00 47.00 93.60 15.40 131.00 3.8 718 1708427
+1 73 1 1 41 36 3265 527 470 9.78 2.79 255950 13672 0.00 0.00 0.00 0.00 0.00 0.00 0.00 474.85 687.43 2.6 7304 1859067
+1 73 1 1 4 0 2306 146 41 3.80 4.60 353240 40932 0.00 0.00 0.00 0.00 0.00 8.20 15.80 268.60 442.00 3.8 2911 1799469
+1 95 1 1 4 2 2000 176 62 0.20 0.20 447596 188253 1.00 1.00 1.00 0.00 5.00 2.00 2.60 17.40 28.60 4.0 227 1323011
+1 0 1 1 20 18 909 374 134 0.20 0.20 564903 546743 2.60 4.20 4.20 0.00 0.80 6.80 6.80 24.80 46.80 201 93 6
+1 90 1 1 21 10 1562 142 144 1.60 1.00 50456 95182 0.00 0.00 0.00 0.00 0.60 12.60 15.40 79.80 157.80 1.7 655 1053592
+1 97 1 1 21 27 199 11 31 0.20 0.20 9439 24923 0.00 0.00 0.00 0.00 0.00 1.40 1.40 15.60 19.00 1.0 7911 1880848
+1 91 1 1 11 10 3175 159 127 1.80 2.80 15819 25258 0.00 0.00 0.00 0.00 0.00 8.80 9.00 80.60 157.80 2.3 687 990960
+1 96 1 1 1 1 1913 104 108 0.20 0.20 5303 37591 0.00 0.00 0.00 0.00 0.40 0.20 0.20 15.63 19.64 2.0 1069 1057396
+1 82 1 1 3 0 4900 325 223 2.99 2.99 233922 33408 0.00 0.00 0.00 0.00 0.00 3.39 3.99 146.31 252.49 3.0 1445 1047328
+1 92 1 1 3 1 319 30 17 1.60 1.40 66781 37738 0.00 0.00 0.00 0.00 0.00 3.61 6.81 133.47 123.25 1.2 7998 1874464
+1 80 1 1 26 1 3209 248 180 7.60 9.40 111866 148898 0.00 0.00 0.00 0.00 0.20 0.60 0.60 291.00 502.60 4.4 1559 1638931
+1 90 1 1 1 0 1642 189 132 1.60 1.20 24684 27671 3.60 3.60 10.80 30.20 0.20 2.20 2.20 62.40 142.40 1.4 146 1099021
+1 95 1 1 3 1 368 80 41 0.40 3.40 149950 134453 0.00 0.00 0.00 0.00 0.00 1.60 3.20 27.60 44.60 3.2 2130 1733178
+1 88 1 1 1 0 2079 295 166 1.00 3.60 174955 55598 0.00 0.00 13.60 23.20 0.20 10.80 13.40 53.00 93.60 1.8 129 1100454
+1 97 1 1 49 67 268 35 37 0.20 0.20 2253 18811 1.00 1.00 1.00 0.00 0.20 0.00 0.00 16.43 18.44 1.2 279 1759367
+1 92 1 1 3 0 3583 222 115 0.80 2.99 207530 55930 0.00 0.00 0.00 0.00 0.00 0.00 0.00 41.72 64.87 3.2 1009 1629554
+1 85 1 1 2 0 467 70 37 2.00 2.00 222944 39615 6.40 6.40 6.40 0.00 0.20 2.60 2.60 193.60 157.20 1.8 191 1801205
+1 98 1 1 1 1 1242 41 36 0.20 0.20 35851 15667 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 17.00 1.4 4621 1828408
+1 84 1 1 40 10 3755 465 241 1.80 2.40 588852 546019 8.40 10.40 10.20 0.00 9.20 1.60 2.40 88.00 145.20 1.2 178 1036090
+1 0 1 1 12 8 2666 536 239 0.60 0.60 696898 693997 0.00 0.00 0.00 0.00 0.00 4.60 5.40 227.00 111.00 572 89 11
+1 96 1 1 3 2 627 86 56 0.20 0.20 178422 21013 1.40 1.40 1.40 0.00 8.60 0.00 0.00 20.40 25.20 2.0 207 1024472
+1 72 1 1 8 1 3382 168 115 6.99 22.75 31740 16446 0.60 0.60 0.60 0.00 0.00 6.79 9.38 247.31 426.15 4.0 329 1103171
+1 86 1 1 11 5 5830 385 230 1.00 0.80 210572 167953 0.00 0.00 0.00 0.00 0.00 2.20 2.40 87.60 93.60 4.8 1570 1330362
+1 84 1 1 8 2 2259 139 92 1.20 6.41 178051 27909 3.21 17.84 49.30 99.40 2.20 22.04 30.46 130.86 259.52 2.0 270 1130600
+1 90 1 1 1 0 601 107 53 1.00 1.60 325402 53635 18.00 33.80 49.00 44.80 10.20 16.40 28.00 86.80 158.00 3.2 199 1730275
+1 76 1 1 11 11 1967 155 63 0.60 1.40 1002900 23869 16.40 50.00 128.80 348.00 0.40 112.20 218.20 29.20 129.80 2.6 302 1105456
+1 86 1 1 10 1 2028 229 140 1.20 1.20 128849 44653 5.59 12.18 73.85 109.58 1.20 42.12 56.69 71.66 160.48 1.8 125 1068635
+1 75 1 1 13 6 3048 340 157 6.00 17.20 743972 53549 1.40 1.60 1.60 0.00 0.40 12.20 13.60 217.80 424.80 2.5 490 1098693
+1 94 1 1 0 0 935 93 55 0.40 1.80 101335 21527 0.00 0.00 0.00 0.00 0.00 1.00 1.00 32.80 70.60 1.4 1542 998768
+1 91 1 1 0 0 206 9 15 0.20 0.20 429 8995 0.40 1.40 2.20 6.40 0.00 0.80 0.80 15.60 18.20 1.8 155 1741574
+1 77 1 1 189 205 3091 345 158 1.20 5.39 1158330 49191 19.16 51.90 127.54 244.51 12.77 26.55 49.30 69.66 201.20 1.8 134 1091347
+1 68 1 1 23 0 7010 634 583 9.00 3.80 354709 41888 0.00 0.00 0.00 0.00 0.00 0.60 0.80 466.00 703.00 5.6 530 1538702
+1 97 1 1 2 1 663 32 29 0.40 0.40 5901 13361 0.59 0.59 0.59 0.00 0.00 1.39 1.39 38.22 40.00 1.0 330 1207598
+1 89 1 1 5 3 3618 246 176 0.20 0.20 100084 224588 5.20 12.40 14.60 6.20 0.40 3.20 5.00 15.40 54.60 3.8 181 1519798
+1 91 1 1 2 1 3839 197 106 0.20 0.20 158527 158520 0.40 0.40 0.20 0.00 0.20 3.20 3.60 15.60 36.00 3.8 330 1338384
+1 88 1 1 178 192 2040 142 115 2.00 4.40 73754 79125 0.40 0.40 0.40 0.00 0.00 18.40 21.80 108.80 211.20 2.5 348 1025120
+1 85 1 1 6 4 2218 222 166 1.40 2.60 243755 39063 10.60 33.60 65.20 151.20 1.80 34.60 37.00 83.20 194.20 1.5 201 1098210
+1 66 1 1 39 0 2762 200 101 10.62 31.06 403480 59518 0.00 0.00 0.00 0.00 0.00 29.26 44.29 345.49 678.36 2.5 989 1110060
+1 98 1 1 2 1 208 17 17 0.20 0.20 7212 8911 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.57 16.97 1.0 7244 1861541
+1 98 1 1 1 0 253 37 31 0.20 0.20 781 8619 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 6167 1723842
+1 88 1 1 9 4 1926 146 182 0.60 0.80 78004 123542 0.00 0.00 0.00 0.00 0.00 2.20 2.20 61.80 72.40 1.7 858 1046085
+1 98 1 1 2 1 310 52 22 0.20 0.20 261896 6656 0.00 0.00 0.00 0.00 0.00 0.40 0.60 20.44 19.44 1.0 7380 1868882
+1 94 1 1 2 1 616 73 36 1.80 2.00 176699 6604 1.40 1.40 1.40 0.00 3.00 0.20 0.20 76.80 127.00 3.4 248 1715482
+1 94 1 1 1 1 498 203 76 0.20 0.20 193035 215610 1.20 1.20 1.20 0.00 0.00 11.40 21.60 15.60 53.00 3.6 226 1736312
+1 98 1 1 0 0 212 16 16 0.20 0.20 1023 7425 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.57 17.17 1.0 583 1729245
+1 88 1 1 14 3 1522 144 117 2.20 4.19 196094 70633 1.20 1.20 1.20 0.00 21.96 5.39 10.38 204.79 260.88 2.2 335 1063077
+1 71 1 1 63 53 3813 370 277 8.58 18.96 267107 84420 3.99 10.18 41.92 80.64 0.80 7.78 14.57 504.59 772.85 2.0 137 982794
+1 93 1 1 2 0 1125 103 65 1.80 1.60 29108 23369 0.00 0.00 0.00 0.00 0.00 2.40 2.80 89.20 152.80 1.0 422 992030
+1 83 1 1 10 5 5022 184 84 2.20 8.00 265707 10060 0.00 0.00 0.00 0.00 0.00 1.20 1.20 149.40 208.40 3.2 1181 1397485
+1 98 1 1 19 24 205 13 29 0.20 0.20 7545 27060 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.40 17.20 1.0 6297 1857310
+1 83 1 1 17 22 612 73 56 2.20 2.20 166890 35369 6.59 6.59 8.78 9.58 0.00 2.40 2.59 191.22 220.36 1.8 311 1803770
+1 92 1 1 5 3 2562 165 132 0.40 0.40 372680 115023 2.20 2.40 2.40 0.00 5.80 1.80 1.80 31.00 58.80 3.8 212 1323400
+1 93 1 1 4 0 898 94 63 1.00 1.20 51077 35165 2.00 3.41 3.21 0.00 1.00 1.00 2.00 94.59 126.65 1.0 464 1014270
+1 78 1 1 7 4 4425 306 241 2.81 5.01 154513 63102 9.02 24.65 48.90 96.59 2.00 14.03 22.65 136.87 303.21 2.0 168 995703
+1 79 1 1 35 26 4039 410 255 2.00 1.40 135818 111308 0.00 0.00 0.00 0.00 0.00 9.40 13.60 105.40 244.40 4.2 8216 1373632
+1 83 1 1 7 2 3364 281 173 2.00 2.20 126358 32396 0.80 0.80 0.80 0.00 6.80 14.00 17.60 144.40 281.80 1.2 334 1012155
+1 94 1 1 1 0 3365 145 109 0.20 0.20 4215 18277 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.83 17.64 1.2 689 1738140
+1 91 1 1 2 0 3088 123 76 1.00 1.20 124815 6114 0.00 0.00 0.00 0.00 0.00 2.60 2.60 85.20 125.40 2.4 4838 1405595
+1 95 1 1 6 5 689 75 51 0.60 0.40 110658 21332 5.20 6.20 6.80 5.40 6.00 2.80 3.40 49.20 72.60 1.0 139 1024010
+1 80 1 1 5 2 4331 264 210 0.80 3.80 287845 120123 6.00 8.20 8.20 0.00 1.40 8.80 30.20 55.80 152.80 1.0 244 985754
+1 97 1 1 42 59 415 65 60 0.40 0.40 13406 9725 1.60 2.00 1.80 0.00 2.60 0.80 0.80 41.00 41.80 2.8 281 1713627
+1 94 1 1 0 0 2595 174 146 0.20 0.20 84039 82244 8.40 14.20 11.40 0.00 1.00 1.40 2.00 15.60 17.40 1.0 156 1751064
+1 98 1 1 1 0 256 14 15 0.60 0.60 1230 10334 0.00 0.00 0.00 0.00 0.00 0.40 0.40 60.00 68.20 1.2 10916 1876062
+1 87 1 1 5 0 3206 130 106 1.40 2.20 98359 45104 0.00 0.00 0.00 0.00 0.20 0.80 1.00 80.20 129.80 2.6 858 1523749
+1 92 1 1 3 1 418 56 49 1.80 1.80 35096 26899 0.00 0.00 0.00 0.00 0.00 1.80 2.20 163.80 137.40 1.2 8600 1841038
+1 93 1 1 5 1 1871 99 96 0.40 0.40 13170 37286 0.00 0.00 0.00 0.00 0.40 0.20 0.40 37.80 48.80 1.0 1059 1055131
+1 95 1 1 26 36 926 59 38 0.80 0.80 135371 42672 0.00 0.00 0.00 0.00 0.00 1.40 1.80 67.00 136.00 1.0 635 1016406
+1 87 1 1 5 4 1958 248 102 0.60 1.20 147350 68937 15.60 21.00 30.40 30.00 10.20 40.00 42.40 39.00 152.60 2.0 160 990064
+1 91 1 1 7 0 2834 43 43 1.60 1.60 110077 45701 0.00 0.00 0.00 0.00 0.00 1.20 2.20 102.80 201.80 2.2 1366 1637480
+1 94 1 1 1 0 1917 186 90 0.80 1.00 733309 14402 0.00 0.00 0.00 0.00 0.20 0.20 0.20 50.00 68.80 2.8 725 1719962
+1 90 1 1 1 0 3887 172 152 0.40 0.40 160360 175808 0.00 0.00 0.00 0.00 0.00 5.00 5.60 184.80 77.20 1.8 668 991030
+1 93 1 1 2 1 310 25 17 1.40 1.40 45713 20147 0.00 0.00 0.00 0.00 0.00 1.60 2.61 116.43 110.62 1.2 8249 1873379
+1 97 1 1 1 1 262 50 44 0.20 0.20 17875 22004 0.00 0.00 0.00 0.00 0.00 1.00 1.80 15.80 16.80 1.2 6160 1855840
+1 92 1 1 2 0 385 35 25 1.80 1.80 125918 34085 0.00 0.00 0.00 0.00 0.00 1.80 2.80 156.00 135.00 1.6 8201 1868654
+1 77 1 1 17 12 4120 383 272 3.79 2.59 981550 821788 2.79 2.99 2.99 0.00 0.40 13.17 16.77 193.61 342.91 3.0 171 1013509
+1 88 1 1 3 2 5105 283 182 0.20 0.20 9800 34917 0.00 0.00 0.00 0.00 0.00 0.20 0.20 20.60 20.40 1.0 608 1076626
+1 95 1 1 8 6 1385 126 82 0.40 0.40 96745 48870 0.00 0.00 0.00 0.00 0.00 2.20 2.40 30.06 83.37 2.0 727 1035279
+1 99 1 1 0 0 131 6 10 0.20 0.20 419 6684 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.57 16.77 1.0 1913 1781405
+1 98 1 1 1 1 142 13 23 0.00 0.00 10150 5921 0.00 0.00 0.00 0.00 0.00 0.20 0.20 0.00 0.40 1.0 7228 1847216
+1 95 1 1 23 33 765 78 50 0.20 0.20 177869 46901 4.20 7.60 6.20 0.60 0.60 4.40 6.20 22.60 36.60 3.0 145 1037312
+1 88 1 1 10 1 4521 213 164 0.60 0.60 158060 198081 0.00 0.00 0.00 0.00 0.00 1.60 1.60 50.80 63.00 3.0 1082 1378862
+1 91 1 1 3 0 1944 196 103 0.40 0.40 369644 29704 0.00 0.00 0.00 0.00 0.20 17.60 25.00 37.20 140.60 1.0 517 975115
+1 93 1 1 1 0 2396 106 91 0.60 0.80 4561 33580 0.00 0.00 0.00 0.00 0.00 0.00 0.00 42.71 62.87 2.6 650 1015272
+1 91 1 1 58 73 1214 327 105 0.80 2.60 332602 24428 0.00 0.00 0.00 0.00 0.60 41.00 53.40 59.80 198.60 1.0 692 986238
+1 88 1 1 13 12 4135 134 146 0.40 0.40 50014 84037 0.00 0.00 0.00 0.00 0.00 10.98 16.37 43.51 109.98 3.8 937 997648
+1 94 1 1 13 12 3185 232 124 0.20 0.20 186795 178492 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.40 27.60 3.6 3702 1346824
+1 87 1 1 17 6 2263 223 144 0.60 0.60 21673 83921 1.00 1.80 1.80 0.00 0.80 14.60 22.40 56.60 121.60 1.0 391 1094760
+1 86 1 1 6 1 2425 311 213 1.00 1.00 475421 340088 0.00 0.00 0.00 0.00 0.00 6.40 8.60 68.20 104.20 4.6 897 1600730
+1 75 1 1 26 18 10331 4449 4590 1.20 1.60 36289 36990 9.80 15.60 34.60 72.40 1.20 1.40 1.60 76.40 207.60 3.4 168 974222
+1 69 1 1 13 1 4690 635 522 10.00 4.80 300199 21514 0.00 0.00 0.00 0.00 0.00 0.80 1.00 488.20 715.40 1.7 1096 1068226
+1 69 1 1 34 1 2849 215 190 9.18 19.36 125454 56632 0.00 0.00 0.00 0.00 0.00 15.97 16.97 367.27 673.05 1.0 1640 1107898
+1 73 1 1 23 11 5333 181 109 3.19 9.38 338051 149661 0.00 0.00 0.00 0.00 0.00 11.18 18.76 275.05 331.74 5.2 2477 1543837
+1 87 1 1 98 105 2663 421 153 0.60 0.40 603068 499815 0.00 0.00 0.00 0.00 0.00 6.00 6.20 37.40 69.00 1.2 451 1044634
+1 83 1 1 10 8 1964 157 85 1.20 2.40 115996 27543 8.42 41.88 84.57 114.63 1.20 14.23 25.25 149.30 446.09 3.5 310 1065315
+1 61 1 1 15 5 5918 1230 1056 3.19 1.79 1634341 790603 5.38 23.90 45.22 78.09 4.18 23.31 61.16 402.19 458.76 2.0 270 1102400
+1 83 1 1 16 10 1961 285 232 4.99 2.79 269925 39790 0.00 0.00 0.00 0.00 0.00 4.59 8.58 260.28 441.92 1.5 887 1006247
+1 84 1 1 8 1 1652 298 221 5.60 1.80 275926 146174 0.00 0.00 0.00 0.00 0.00 0.00 0.00 257.20 366.20 2.4 5155 1836584
+1 99 1 1 0 0 109 10 13 0.00 0.00 278 7934 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.20 1.0 8493 1866040
+1 70 1 1 12 0 3298 203 127 9.20 27.80 254710 57313 3.20 14.60 23.60 40.60 1.40 10.00 11.40 312.20 617.60 2.0 153 1077395
+1 90 1 1 18 16 1370 157 98 1.40 1.80 539887 63362 0.00 0.00 0.00 0.00 7.40 9.00 14.80 85.20 134.40 2.0 465 974966
+1 79 1 1 19 1 5834 598 551 3.79 1.40 350133 289622 0.00 0.00 0.00 0.00 0.00 0.00 0.00 198.40 285.03 3.8 2295 1641327
+1 98 1 1 25 34 159 16 16 0.20 0.20 948 2479 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 9844 1869696
+1 93 1 1 26 20 1865 122 81 0.80 0.80 146350 43436 0.00 0.00 0.00 0.00 0.00 0.20 0.20 83.80 111.40 2.4 2249 1551853
+1 87 1 1 70 1 3227 235 91 0.40 0.80 938351 72918 5.20 7.80 18.20 36.40 0.00 1.40 1.60 24.00 55.40 5.2 163 1110411
+1 84 1 1 7 4 2319 174 120 2.00 5.60 112936 112075 3.20 19.40 57.60 112.20 0.80 0.80 0.80 180.60 340.40 1.0 185 1060130
+1 98 1 1 18 27 184 20 23 0.20 0.20 503 10524 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 6298 1724355
+1 83 1 1 6 0 4174 261 218 3.01 2.00 204257 52796 2.20 2.61 2.61 0.00 0.80 2.20 2.81 159.32 249.50 1.7 260 1054503
+1 72 1 1 76 1 3648 354 199 1.80 4.59 1943774 44069 5.39 7.19 10.38 16.17 9.38 44.11 291.62 109.38 326.95 2.0 284 1023842
+1 93 1 1 16 12 650 240 70 2.00 2.00 344785 290625 0.00 0.00 0.00 0.00 0.00 0.00 0.00 77.00 133.00 2.6 5670 1832144
+1 91 1 1 1 0 230 28 34 0.20 0.20 2337 5853 0.00 0.00 0.00 0.00 0.00 1.40 1.40 15.40 16.80 2.2 635 1746576
+1 98 1 1 0 0 173 16 20 0.20 0.20 445 5965 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7360 1865600
+1 91 1 1 41 64 3201 214 140 0.60 0.60 44587 48536 0.00 0.00 0.00 0.00 0.00 16.20 16.20 111.60 101.80 2.0 2445 1406579
+1 87 1 1 9 8 1765 78 64 0.80 1.40 16460 28646 0.00 0.00 0.00 0.00 0.00 11.22 22.24 125.25 195.59 1.8 1008 1053841
+1 97 1 1 1 1 488 33 42 0.20 0.20 9922 141695 0.00 0.00 0.00 0.00 0.00 0.20 0.20 14.77 13.97 1.2 5652 1836271
+1 92 1 1 0 0 2362 130 128 0.20 0.20 71809 48947 0.00 0.00 0.00 0.00 0.00 27.74 29.54 15.57 62.48 2.8 2381 1411045
+1 90 1 1 1 0 2085 245 145 0.40 0.60 38666 48507 0.80 0.80 0.80 0.00 0.80 3.40 3.80 34.00 62.00 2.0 202 1126938
+1 82 1 1 7 0 2798 169 107 5.60 4.20 270281 79436 7.20 25.80 72.00 113.80 2.60 5.60 8.80 260.00 460.20 1.5 198 1011712
+1 87 1 1 60 84 2475 210 73 1.80 2.00 400236 26803 0.00 0.00 0.00 0.00 0.00 33.47 91.78 105.01 157.92 1.0 583 1070709
+1 98 1 1 15 21 196 13 36 0.20 0.20 9023 13261 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.40 1.0 7137 1873493
+1 83 1 1 12 3 2088 162 96 5.00 3.20 28417 253115 10.80 19.20 19.20 0.00 0.20 30.20 59.40 186.60 337.40 3.2 345 1538939
+1 96 1 1 0 0 458 63 15 0.40 0.40 107375 3819 0.00 0.00 0.00 0.00 0.00 7.78 15.57 33.73 74.25 1.6 7307 1861728
+1 58 1 1 14 2 4725 247 161 10.62 33.87 464922 45701 1.20 1.40 1.40 0.00 0.80 5.41 5.81 349.30 719.64 1.0 174 1090443
+1 92 1 1 20 28 360 29 20 0.60 0.60 53449 12945 0.60 2.40 13.80 35.60 0.40 3.80 5.80 38.40 67.00 1.2 247 1756248
+1 83 1 1 80 111 2618 316 191 0.80 0.80 616266 107389 2.81 11.02 14.63 13.83 3.81 16.83 37.27 69.54 192.38 3.2 468 1028564
+1 91 1 1 1 0 490 53 48 1.20 0.60 36794 7750 0.00 0.00 0.00 0.00 0.00 0.00 0.00 74.40 94.80 2.6 965 1761134
+1 76 1 1 4 0 3538 315 229 3.20 6.20 308752 33198 9.40 37.20 132.00 268.20 1.60 28.80 47.20 226.20 376.80 1.0 125 1100429
+1 87 1 1 1 0 2797 183 141 0.20 0.20 129142 119557 1.80 1.80 1.80 0.00 1.60 29.60 35.20 22.40 96.00 4.0 397 1118680
+1 87 1 1 5 0 1538 293 123 1.20 2.00 375998 36154 0.00 0.00 0.00 0.00 1.00 1.40 1.40 131.54 356.29 1.0 620 1029116
+1 79 1 1 68 67 2285 296 164 3.40 4.40 105612 68966 0.00 0.00 0.00 0.00 0.00 5.20 5.60 243.20 459.40 2.6 1122 1540368
+1 90 1 1 7 2 1628 212 170 3.99 1.20 122017 15907 0.00 0.00 0.00 0.00 0.00 0.00 0.00 198.00 281.64 1.8 8532 1862631
+1 70 1 1 38 25 2538 305 314 1.20 2.60 724260 778799 23.60 98.40 257.80 584.80 0.40 64.20 122.60 93.80 180.20 1.0 129 1021626
+1 93 1 1 43 59 1132 132 95 0.40 0.40 69187 22703 1.40 1.60 1.60 0.00 0.60 3.41 5.21 32.67 82.97 3.0 207 978217
+1 90 1 1 1 0 287 29 39 0.20 0.20 25343 35325 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.57 17.76 1.4 1863 1763816
+1 85 1 1 51 61 2882 256 155 2.00 2.20 286567 33091 3.40 4.20 4.20 0.00 2.00 8.40 9.00 166.60 271.00 1.5 371 1131234
+1 90 1 1 83 53 1579 168 144 2.00 8.78 140579 103506 5.99 11.58 11.38 0.00 3.99 15.37 23.75 77.25 163.67 4.6 451 1601996
+1 93 1 1 3 0 1192 127 108 1.80 0.60 77466 32241 0.00 0.00 0.00 0.00 0.00 0.60 1.00 145.60 150.60 2.0 634 1068851
+1 57 1 1 34 6 6266 751 536 9.38 5.99 734546 57497 2.40 3.19 3.19 0.00 0.60 39.92 44.11 502.20 930.94 2.6 414 1078189
+1 79 1 1 15 13 1828 199 188 0.80 1.00 509736 331591 0.00 0.00 0.00 0.00 0.20 58.20 96.40 69.60 151.40 1.0 1567 1088618
+1 93 1 1 4 1 921 59 29 3.00 3.40 100187 8096 0.00 0.00 0.00 0.00 0.80 0.40 0.40 165.60 233.80 1.0 858 1754422
+1 96 1 1 1 0 251 17 18 0.60 1.40 445 2290 0.00 0.00 0.00 0.00 0.00 0.00 0.00 52.51 51.70 1.0 7560 1873974
+1 98 1 1 0 0 216 21 13 0.40 0.40 86324 5874 0.00 0.00 0.00 0.00 0.00 0.00 0.00 37.07 45.29 1.2 8732 1871530
+1 90 1 1 2 0 1506 222 165 2.00 0.80 339023 59833 0.20 0.20 0.20 0.00 0.00 9.80 18.60 96.40 199.40 2.5 465 1012653
+1 91 1 1 2 1 3456 199 143 0.20 0.20 13373 19947 1.60 2.40 2.40 0.40 0.80 5.20 5.20 20.80 40.80 4.0 459 1316662
+1 92 1 1 1 0 1369 143 113 0.40 0.40 320935 50526 0.40 0.40 0.40 0.00 0.40 19.20 19.80 31.40 56.80 1.0 507 1117390
+1 89 1 1 3 1 2780 163 160 1.80 1.60 118023 15161 1.20 1.40 3.20 3.60 1.00 0.00 0.00 108.40 160.00 3.0 166 1723630
+1 93 1 1 42 40 1177 139 139 0.80 0.80 35931 40257 0.60 0.60 0.60 0.00 3.20 0.80 0.80 56.40 66.40 1.7 244 1089917
+1 0 1 1 11 8 1153 74 49 0.20 0.20 94959 31350 2.20 2.20 2.20 0.00 0.40 3.19 3.79 30.94 74.65 330 95 5
+1 95 1 1 6 6 1143 100 67 0.40 1.00 92840 29857 0.00 0.00 0.00 0.00 0.00 0.80 0.80 45.80 67.60 1.0 676 991750
+1 92 1 1 2 1 347 83 45 0.20 0.20 299809 255418 0.00 0.00 0.00 0.00 0.60 2.40 4.80 13.00 16.80 2.0 4146 1824344
+1 96 1 1 0 0 620 73 37 0.20 0.20 85768 9920 0.00 0.00 0.00 0.00 0.00 0.20 0.40 16.60 19.40 1.4 658 1731074
+1 86 1 1 2 0 3214 171 126 0.40 0.20 209570 16714 4.19 6.19 23.95 47.90 0.40 0.60 0.80 20.56 30.54 2.2 259 1753694
+1 80 1 1 18 2 3726 444 224 5.00 3.20 202871 62296 2.40 4.20 11.00 13.40 1.80 16.80 30.80 184.80 342.80 1.5 161 1075733
+1 96 1 1 4 2 648 65 81 0.60 0.60 5570 22076 0.40 0.40 0.40 0.00 0.00 0.40 0.40 49.10 62.08 1.0 349 1088770
+1 92 1 1 0 0 3867 146 104 0.20 0.20 83311 21524 0.00 0.00 0.00 0.00 0.00 4.60 9.20 15.40 18.40 4.2 667 1638752
+1 74 1 1 63 32 2379 315 216 7.20 17.60 889404 112252 4.00 14.20 14.00 0.00 1.40 6.20 6.40 290.60 540.80 2.0 297 1097571
+1 61 1 1 48 0 3866 245 197 11.18 33.73 133990 65861 1.00 1.20 1.20 0.00 1.20 4.79 5.99 363.47 688.42 2.0 315 1092819
+1 82 1 1 8 5 2335 118 85 1.60 3.40 262631 95924 24.40 41.40 61.20 119.20 10.40 13.00 16.20 173.80 248.60 3.4 266 1022885
+1 92 1 1 3 2 450 24 37 1.40 1.40 25504 150391 0.00 0.00 0.00 0.00 0.00 0.80 0.80 109.40 106.20 1.2 5555 1843573
+1 95 1 1 15 13 1342 242 90 0.20 0.20 365912 197691 0.00 0.00 0.00 0.00 0.00 0.60 0.80 31.80 38.60 4.2 2593 1575800
+1 93 1 1 170 188 1557 80 99 0.20 0.20 24826 41252 3.00 5.40 5.20 0.00 0.60 2.80 4.20 20.80 26.40 2.0 374 1116261
+1 67 1 1 54 66 4976 378 282 6.79 18.56 248262 196824 0.80 0.80 0.80 0.00 1.60 9.18 10.38 245.91 449.90 1.0 520 1090140
+1 87 1 1 21 15 2743 140 135 1.40 1.60 93968 57136 0.00 0.00 0.00 0.00 0.20 7.60 7.60 109.80 261.20 4.0 7773 1383296
+1 91 1 1 5 0 1329 122 81 1.00 1.60 121397 21232 3.40 3.40 3.40 0.00 0.40 6.80 9.20 92.60 187.00 3.0 286 973730
+1 81 1 1 7 0 4116 477 424 4.40 1.40 255848 196444 0.40 0.80 0.60 0.00 0.00 1.00 1.00 211.40 336.60 1.4 259 1073829
+1 0 1 1 69 53 5445 553 280 4.00 7.00 543318 461196 0.00 0.00 0.00 0.00 0.00 22.80 34.20 252.80 436.20 1250 71 29
+1 94 1 1 57 73 1120 138 106 0.20 0.20 15091 23190 0.00 0.00 0.00 0.00 0.00 1.80 2.00 25.15 18.16 1.0 1168 1081843
+1 85 1 1 42 36 2071 326 587 3.59 8.38 153277 50719 5.99 8.78 8.78 0.00 6.19 3.19 3.79 141.52 277.05 1.0 313 1013351
+1 90 1 1 17 5 2435 162 124 0.80 0.80 113728 69800 3.40 3.80 3.40 0.00 1.80 1.00 1.00 67.60 91.20 1.5 255 1070645
+1 98 1 1 1 1 232 19 44 0.20 0.20 12476 6506 0.00 0.00 0.00 0.00 0.00 1.00 1.80 15.60 16.80 1.0 7281 1875328
+1 87 1 1 5 2 4541 346 212 1.00 2.60 97261 56502 0.00 0.00 0.00 0.00 0.20 3.60 3.80 79.60 114.80 3.2 718 1517275
+1 79 1 1 20 13 3304 369 137 3.81 5.41 751052 214921 8.42 23.25 55.71 78.96 10.22 29.46 31.46 209.02 563.13 2.0 194 1008276
+1 85 1 1 4 2 3984 359 149 0.60 0.40 84511 26097 2.80 3.00 3.00 0.00 2.20 16.40 18.40 161.80 95.00 1.3 264 1102635
+1 96 1 1 1 0 649 154 65 0.20 0.20 250243 172462 0.00 0.00 0.00 0.00 0.00 0.00 0.00 25.15 37.33 3.2 999 1750280
+1 96 1 1 3 1 856 64 52 0.60 0.60 11415 23700 0.00 0.00 0.00 0.00 0.20 1.20 1.20 41.52 46.91 2.5 1172 974162
+1 67 1 1 13 4 2585 161 76 3.59 13.77 2104670 20704 18.16 102.20 232.93 574.65 2.00 100.40 187.62 244.31 482.63 2.2 185 1104053
+1 98 1 1 0 0 133 8 9 0.20 0.20 977 6114 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.0 11958 1884974
+1 84 1 1 42 43 768 58 54 2.00 2.00 69166 35674 0.00 0.00 0.00 0.00 0.00 1.20 1.60 139.80 156.40 2.0 2691 1795552
+1 91 1 1 15 1 1441 149 159 0.80 0.80 53265 118104 2.40 4.79 11.98 41.72 1.20 26.35 27.35 61.08 132.14 3.0 326 1060929
+1 92 1 1 2 1 1973 114 72 0.40 0.60 32204 22609 0.00 0.00 0.00 0.00 0.00 4.40 4.80 15.00 52.40 2.2 2934 1051275
+1 94 1 1 10 4 481 57 48 1.60 0.80 35708 35100 0.00 0.00 0.00 0.00 0.00 2.80 4.20 91.40 136.20 1.0 366 1742059
+1 59 1 1 88 64 4215 279 189 12.42 30.46 135841 25070 0.00 0.00 0.00 0.00 0.40 27.66 33.67 441.48 807.21 3.8 434 1109996
+1 96 1 1 0 0 876 81 61 0.20 0.20 2073 23892 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.77 35.33 2.3 445 990339
+1 98 1 1 1 1 214 16 20 0.20 0.20 7013 6313 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7246 1863656
+1 95 1 1 0 0 1297 103 45 0.20 0.20 346042 11105 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.40 4.0 1286 1712987
+1 92 1 1 19 24 3265 112 102 0.20 0.20 5403 28241 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 17.00 1.4 484 1739008
+1 91 1 1 3 0 2408 121 55 2.60 6.60 346759 261168 0.00 0.00 0.00 0.00 0.00 0.60 0.80 173.80 234.80 3.2 4697 1828213
+1 89 1 1 1 0 4093 171 102 0.20 0.20 156218 37170 0.00 0.00 0.00 0.00 0.00 2.20 2.20 15.60 29.60 2.5 1044 1015238
+1 0 1 1 6 5 1642 97 93 0.20 0.20 119009 24558 0.00 0.00 0.00 0.00 0.00 2.40 3.21 21.04 42.08 404 93 7
+1 81 1 1 30 25 1951 86 132 1.20 1.60 70927 44956 0.00 0.00 0.00 0.00 0.20 14.40 22.00 86.60 156.80 1.8 3293 1761960
+1 0 1 1 23 20 2088 469 166 0.20 0.20 761340 748362 0.00 0.00 0.00 0.00 0.20 7.60 7.60 26.20 51.80 735 94 6
+1 81 1 1 3 0 4450 273 243 3.20 1.00 87743 49090 0.20 1.00 0.60 0.00 0.40 7.60 7.60 159.20 270.20 3.4 450 1015536
+1 97 1 1 0 0 254 32 22 0.40 0.20 99193 8531 0.00 0.00 0.00 0.00 0.00 0.40 0.40 32.60 44.00 1.2 7646 1870685
+1 90 1 1 3 1 1896 168 155 0.40 0.40 18991 105189 0.00 0.00 0.00 0.00 0.00 1.60 2.40 29.80 41.00 2.0 1476 1087976
+1 97 1 1 1 1 315 26 20 0.20 0.20 95538 8984 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 18.40 1.0 3233 1846845
+1 95 1 1 0 0 1308 95 53 0.20 0.20 212600 31039 0.00 0.00 0.00 0.00 0.00 4.00 4.80 18.20 104.00 2.0 361 1032442
+1 91 1 1 30 40 2497 85 155 0.40 1.80 6519 21026 0.00 0.00 0.00 0.00 0.00 0.60 0.60 20.80 30.20 3.2 1319 1724685
+1 96 1 1 39 57 936 51 50 0.40 0.40 3353 23502 2.60 2.60 2.60 0.00 0.40 1.00 1.00 31.60 65.60 1.7 182 989358
+1 85 1 1 6 0 761 88 54 4.00 2.60 102831 9123 0.00 0.00 0.00 0.00 0.00 1.80 1.80 280.60 305.60 1.4 11335 1880605
+1 0 1 1 1 0 670 70 35 0.20 0.20 97203 17815 0.60 0.80 0.80 0.00 0.20 1.60 1.60 16.60 27.80 131 96 4
+1 89 1 1 6 5 2065 151 108 1.00 1.20 246521 25261 0.00 0.00 0.00 0.00 1.40 8.98 16.77 77.64 154.89 1.7 555 1017827
+1 86 1 1 28 25 3903 271 162 2.40 2.40 293696 35661 0.00 0.00 0.00 0.00 0.00 0.40 0.60 171.00 285.80 1.2 920 974752
+1 93 1 1 17 15 1035 576 58 1.40 1.60 114839 46623 0.00 0.00 0.00 0.00 0.00 11.60 22.80 75.40 144.00 1.2 5848 1862774
+1 83 1 1 4 2 3122 188 191 1.00 1.20 125528 444558 0.20 0.40 0.40 0.00 0.20 1.40 2.00 89.40 108.60 2.4 360 1378723
+1 93 1 1 5 1 1645 56 38 3.20 10.20 135660 7797 0.00 0.00 0.00 0.00 0.00 0.20 0.20 94.60 172.80 1.6 4545 1828509
+1 91 1 1 0 0 1333 131 63 0.40 0.40 360558 21855 0.00 0.00 0.00 0.00 0.00 0.60 0.60 32.34 111.38 2.0 1862 1039313
+1 83 1 1 8 0 2659 373 331 6.19 1.60 208922 20252 2.00 2.40 2.40 0.00 0.40 0.00 0.00 302.00 437.92 2.0 175 1740453
+1 92 1 1 3 1 1414 129 96 0.80 1.00 29398 32450 0.00 0.00 0.00 0.00 0.00 0.80 6.00 76.40 90.40 1.5 1925 1098349
+1 85 1 1 2 0 492 38 40 2.00 1.80 76493 42729 0.00 0.00 0.00 0.00 0.00 1.00 1.00 155.80 146.20 1.0 2018 1817005
+1 90 1 1 1 1 1800 174 95 1.20 1.20 235774 31673 0.00 0.00 0.00 0.00 0.20 1.80 1.80 157.72 179.76 2.0 2559 1051687
+1 81 1 1 3 1 7240 409 238 2.00 1.00 114813 203551 3.99 7.78 6.99 0.40 2.79 0.40 0.40 122.95 289.62 2.8 229 1009956
+1 92 1 1 1 0 1859 184 112 0.20 0.20 28872 59647 6.21 16.23 26.45 42.08 0.00 2.61 3.61 15.63 96.79 1.2 150 1103641
+1 92 1 1 12 10 1152 107 71 0.20 0.20 213053 103408 0.00 0.00 0.00 0.00 0.20 1.60 2.20 19.80 69.80 3.2 660 1516470
+1 64 1 1 1486 1 7266 157 192 1.60 1.00 98595 73892 0.00 0.00 0.00 0.00 1.20 6.80 12.80 91.80 176.60 2.8 2451 1712099
+1 92 1 1 17 9 2371 109 117 1.60 1.60 30574 84978 0.00 0.00 0.00 0.00 0.00 0.20 0.20 93.80 200.20 2.6 1840 1641224
+1 98 1 1 0 0 253 44 35 0.20 0.20 873 8478 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.40 18.20 1.0 1372 1746256
+1 60 1 1 13 1 4124 286 122 11.02 33.67 186591 25774 3.41 3.81 3.81 0.00 5.21 2.61 3.41 365.53 695.79 1.7 221 1080034
+1 93 1 1 0 0 284 22 29 0.20 0.20 2931 17844 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 17.00 2.0 965 1765304
+1 84 1 1 18 15 2708 373 155 1.40 2.60 190144 184226 6.80 10.20 12.40 7.80 0.60 31.80 43.00 156.60 281.60 1.0 236 973752
+1 95 1 1 6 0 2246 70 64 1.40 7.80 62874 3089 0.00 0.00 0.00 0.00 0.00 1.40 1.80 35.20 79.00 4.6 922 1631942
+1 84 1 1 3 0 2428 209 140 0.80 0.80 279413 100262 0.00 0.00 0.00 0.00 8.22 13.83 24.05 97.19 136.47 4.0 660 972253
+1 93 1 1 88 59 1377 95 97 0.40 0.40 8007 24951 0.00 0.00 0.00 0.00 0.00 2.40 5.00 49.00 47.00 2.0 981 1086547
+1 97 1 1 1 0 297 35 28 0.20 0.20 938 5213 0.40 0.40 0.40 0.00 0.00 0.80 0.80 15.60 17.00 2.0 160 1710048
+1 97 1 1 8 8 396 71 55 0.40 0.20 173114 8007 1.00 1.00 1.00 0.00 2.80 0.00 0.00 24.20 31.60 2.0 187 1715517
+1 90 1 1 2 0 2812 169 69 1.60 2.40 151900 21265 0.00 0.00 0.00 0.00 0.00 0.80 1.20 132.80 174.00 1.8 1885 1753530
+1 90 1 1 16 11 1316 85 97 0.80 0.60 42652 102052 0.00 0.00 0.00 0.00 0.20 1.60 2.00 45.20 80.00 2.4 590 1514522
+1 88 1 1 36 50 2211 211 138 1.80 2.00 61150 19699 0.00 0.00 0.00 0.00 0.00 1.80 2.00 135.07 205.41 2.7 745 1128345
+1 98 1 1 1 1 1533 39 37 0.20 0.20 12691 25273 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 8243 1863248
+1 90 1 1 3 1 814 68 45 2.60 2.80 160007 70993 0.00 0.00 0.00 0.00 0.00 0.60 0.60 185.40 232.40 1.6 8400 1838891
+1 85 1 1 4 1 3725 177 180 3.19 3.19 36525 117889 0.00 0.00 0.00 0.00 0.00 2.00 2.20 109.38 238.52 1.0 925 992080
+1 68 1 1 70 78 3840 447 172 8.20 12.00 376602 61600 0.00 0.00 0.00 0.00 0.20 2.40 3.00 529.40 712.20 1.8 936 1021230
+1 98 1 1 1 0 158 16 22 0.20 0.20 23640 27403 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 16.80 2.2 3684 1822544
+1 86 1 1 20 8 2277 314 133 2.60 3.60 118925 40369 0.00 0.00 0.00 0.00 0.00 0.20 0.20 173.20 292.00 2.8 952 1533365
+1 81 1 1 8 1 2237 173 123 7.80 4.40 130884 17590 0.00 0.00 0.00 0.00 0.00 7.80 8.00 338.80 625.20 1.0 665 1032821
+1 82 1 1 4 2 3652 267 322 2.40 0.80 98603 523740 0.00 0.00 0.00 0.00 0.00 1.20 1.80 128.14 196.61 3.2 422 1015224
+1 93 1 1 1 0 2574 77 155 0.40 0.40 5773 23044 0.00 0.00 0.00 0.00 0.00 0.00 0.00 29.40 36.60 2.2 672 1720138
+1 94 1 1 4 1 987 45 42 0.80 0.40 12821 27199 0.00 0.00 0.00 0.00 0.40 2.20 2.20 64.27 120.56 3.6 1077 1014427
+1 80 1 1 15 4 1902 109 100 0.80 0.80 89409 107126 0.20 0.20 0.20 0.00 0.20 0.40 0.40 94.20 87.40 2.6 448 1519893
+1 87 1 1 6 2 3529 123 87 0.80 2.40 203737 45113 0.00 0.00 0.00 0.00 0.00 0.40 0.40 64.80 81.20 3.8 3325 1547805
+1 95 1 1 3 3 1293 94 103 0.20 0.20 80560 26332 0.00 0.00 0.00 0.00 0.00 0.80 1.20 16.40 32.20 1.7 697 1047581
+1 92 1 1 0 0 2435 112 95 0.20 0.20 10684 40132 0.00 0.00 0.00 0.00 0.00 3.60 3.60 15.80 43.40 1.5 749 1116725
+1 89 1 1 3 1 531 50 42 2.00 2.00 65466 75511 0.00 0.00 0.00 0.00 0.00 1.60 2.20 185.40 157.40 1.4 6257 1853168
+1 93 1 1 7 1 1089 75 84 1.40 2.60 127719 78911 0.00 0.00 0.00 0.00 0.00 1.80 2.60 119.80 103.80 2.2 2031 1528709
+1 91 1 1 15 14 1484 106 79 0.80 2.00 24168 29798 2.20 3.00 8.00 19.40 1.20 34.60 35.40 60.80 140.20 1.0 175 1017035
+1 88 1 1 12 2 1511 99 146 0.80 0.80 122876 412045 4.00 25.20 54.20 93.40 0.80 33.60 50.00 63.20 111.40 2.8 134 1379763
+1 92 1 1 26 34 548 85 81 1.20 1.00 1966 15806 0.00 0.00 0.00 0.00 0.20 0.60 0.80 75.25 171.46 1.2 369 1721643
+1 99 1 1 0 0 138 9 13 0.20 0.20 439 6989 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 8524 1870132
+1 93 1 1 13 8 1536 158 106 0.60 0.40 181548 22361 0.40 0.40 0.40 0.00 8.20 1.00 1.00 49.40 71.00 2.0 205 1086210
+1 75 1 1 42 45 3708 465 436 8.00 2.20 267790 130802 0.00 0.00 0.00 0.00 0.00 0.00 0.00 451.80 611.40 3.8 741 1535707
+1 73 1 1 60 66 5440 383 282 4.00 4.00 531346 95902 4.20 4.40 4.00 0.00 4.20 11.20 26.20 201.80 352.00 1.2 249 1054382
+1 97 1 1 1 0 401 36 25 0.20 0.20 25843 8743 0.40 0.80 0.80 0.00 0.00 0.20 0.20 22.95 19.96 2.2 1119 1707957
+1 94 1 1 1 0 2155 93 83 0.80 3.20 191310 39240 1.60 2.00 2.00 0.00 0.60 2.20 2.40 46.20 62.40 2.6 239 1752434
+1 62 1 1 35 17 6334 365 246 5.60 10.20 447472 85784 3.60 6.00 6.00 0.00 2.20 33.20 38.60 326.20 659.20 7.2 727 1290646
+1 84 1 1 5 1 3075 134 108 4.79 3.19 92817 23032 0.80 0.80 0.80 0.00 0.20 0.00 0.00 206.99 329.34 3.0 489 1746229
+1 91 1 1 2 1 2128 197 133 0.60 1.99 43234 59314 0.00 0.00 0.00 0.00 0.00 7.57 8.37 202.39 106.18 1.5 735 991469
+1 86 1 1 3 0 3548 171 145 2.00 3.80 59768 39613 4.00 6.80 6.80 0.00 4.80 0.80 0.80 141.80 176.00 4.6 606 1014917
+1 87 1 1 7 3 2453 347 484 2.00 1.40 144649 114582 0.00 0.00 0.00 0.00 0.40 0.80 1.20 141.80 178.60 1.3 1024 1015162
+1 97 1 1 1 1 224 27 22 0.20 0.20 93905 10793 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.63 16.83 2.2 7426 1869323
+1 0 1 1 27 24 1733 220 150 0.40 0.60 611974 42921 54.00 142.40 293.60 720.60 0.20 70.60 142.80 50.80 287.00 162 76 24
+1 77 1 1 13 0 3985 402 232 1.60 4.00 471191 61253 3.00 15.00 36.00 96.60 3.20 8.40 24.60 139.40 301.00 9.4 206 1300291
+1 91 1 1 10 0 1113 83 124 1.20 3.20 129474 140520 2.60 8.80 30.40 71.80 1.60 8.00 16.80 107.80 139.60 2.2 122 1533229
+1 69 1 1 58 69 2937 141 128 9.18 25.55 68989 32723 0.80 0.80 7.78 18.56 0.00 3.59 3.79 332.14 578.64 1.0 150 1079478
+1 95 1 1 2 1 740 174 31 1.00 1.00 1260379 17197 0.00 0.00 0.00 0.00 0.00 0.00 0.00 50.20 70.20 2.6 3131 1845962
+1 77 1 1 4 1 4855 922 121 1.80 3.81 2486203 62381 14.83 47.29 74.75 552.10 1.20 11.22 18.44 153.71 350.90 1.0 240 1036099
+1 69 1 1 25 19 4247 570 241 1.60 4.39 378875 66423 9.38 43.71 129.74 227.74 2.99 50.90 96.81 191.02 472.46 1.0 167 983594
+1 95 1 1 12 11 1725 128 96 0.40 0.40 9587 32274 0.00 0.00 0.00 0.00 0.20 2.20 2.40 65.20 47.40 2.0 471 979923
+1 91 1 1 3 1 2838 212 153 0.80 1.00 38724 46621 0.00 0.00 0.00 0.00 0.00 0.00 0.00 80.20 98.20 2.5 1197 1058146
+1 97 1 1 2 0 657 40 37 0.20 0.20 2515 9962 0.00 0.00 0.00 0.00 0.00 11.80 11.80 16.40 56.20 2.0 6061 1693763
+1 78 1 1 42 54 3844 490 336 4.98 2.79 380591 28167 0.40 0.40 15.34 59.96 4.98 6.97 10.16 304.58 518.92 2.2 151 998441
+1 95 1 1 23 34 839 76 71 0.20 0.20 22834 54700 1.60 1.80 5.40 13.40 0.80 1.00 1.20 12.80 21.60 2.0 129 1089048
+1 74 1 1 17 13 4745 253 149 3.59 8.58 594275 66775 7.98 26.55 82.24 170.26 0.40 56.89 108.38 235.53 239.32 1.0 141 1009704
+1 98 1 1 0 0 507 20 24 0.20 0.20 789 6978 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7014 1861808
+1 80 1 1 1 0 1480 111 535 1.40 1.40 112448 119496 0.00 0.00 0.00 0.00 0.00 4.40 6.20 121.40 113.80 1.4 2316 1796571
+1 96 1 1 15 21 186 11 23 0.20 0.20 2058 12778 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 17.20 1.0 7138 1873512
+1 95 1 1 6 5 1109 77 121 0.40 0.20 38758 90756 7.00 8.80 8.80 0.00 2.80 1.40 1.40 22.40 59.60 2.5 327 1059706
+1 97 1 1 2 1 237 24 18 0.40 0.40 28137 10858 0.00 0.00 0.00 0.00 0.00 0.20 0.20 37.40 39.80 1.0 7053 1852656
+1 90 1 1 10 5 1449 237 110 1.80 1.40 27394 21164 0.00 0.00 0.00 0.00 0.20 19.00 21.00 90.60 186.20 1.2 1149 970851
+1 93 1 1 54 5 2288 217 183 0.80 0.80 143018 79772 0.00 0.00 0.00 0.00 0.00 0.80 0.80 66.27 94.01 3.0 1391 1532322
+1 98 1 1 0 0 406 33 19 0.20 0.20 1111 11640 0.00 0.00 0.00 0.00 0.40 0.20 0.20 15.63 29.66 1.2 586 1736241
+1 95 1 1 14 12 903 105 92 0.60 0.80 44847 29587 1.80 1.80 1.80 0.00 0.40 2.80 2.80 52.40 76.80 1.2 230 1016176
+1 70 1 1 5 0 2533 279 221 4.79 3.59 80767 580473 77.64 167.66 211.98 123.35 0.00 50.30 50.90 209.18 532.93 2.5 225 1015690
+1 91 1 1 42 53 764 64 50 1.40 1.60 44710 27568 2.00 3.20 3.00 0.00 0.60 1.20 1.40 71.20 106.40 2.2 635 1036734
+1 67 1 1 14 7 3390 531 410 5.59 3.99 510713 145422 39.72 89.22 269.66 663.27 0.60 49.50 74.85 281.04 757.68 2.5 136 954700
+1 78 1 1 31 12 4606 421 274 4.79 5.19 693526 116904 0.00 0.00 0.00 0.00 0.00 5.59 7.39 347.70 470.66 7.0 2628 1334692
+1 96 1 1 14 19 320 49 37 0.40 0.20 258302 32701 0.00 0.00 0.00 0.00 0.00 0.00 0.00 25.00 27.40 1.4 7444 1875896
+1 90 1 1 1 0 1945 213 98 0.60 0.60 668372 43269 0.00 0.00 0.00 0.00 0.00 0.00 0.00 47.40 46.40 3.2 1059 1723270
+1 0 1 1 19 6 3963 628 485 7.20 2.80 941296 728515 17.00 21.20 21.20 0.00 13.20 12.20 23.40 315.80 497.80 254 74 26
+1 82 1 1 7 2 1605 189 150 2.59 4.18 233699 128372 16.93 39.04 79.28 206.18 0.00 33.67 62.15 183.07 295.42 1.0 135 1034875
+1 96 1 1 2 0 1997 75 60 0.20 0.20 15216 20451 0.00 0.00 0.00 0.00 0.00 2.60 3.80 20.80 35.80 4.4 694 1642832
+1 88 1 1 3 1 4572 179 182 1.40 0.60 61547 191192 4.01 6.01 5.61 0.00 2.61 2.00 2.00 77.76 180.56 2.3 267 1015134
+1 0 1 1 1 0 2061 220 184 0.20 0.20 118267 40022 1.00 1.00 1.00 0.00 0.40 2.00 2.40 15.60 60.40 175 94 6
+1 96 1 1 5 4 837 63 51 0.60 0.80 6255 23670 0.00 0.00 0.00 0.00 0.00 0.60 0.60 50.20 72.60 2.4 3052 1013758
+1 91 1 1 0 0 2310 163 61 0.20 0.20 8993 50725 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 2.0 1378 1753942
+1 83 1 1 23 0 4000 293 216 3.20 1.20 411895 34783 0.00 0.00 0.00 0.00 0.20 25.40 48.80 153.40 365.00 3.6 1765 1397034
+1 72 1 1 21 9 5964 189 156 3.00 8.60 70316 116504 5.00 5.00 5.00 0.00 4.40 3.20 4.00 261.20 299.20 2.8 301 1535931
+1 96 1 1 4 1 2463 97 107 0.20 0.20 156305 197606 0.00 0.00 0.00 0.00 0.00 0.20 0.20 62.40 25.00 2.2 1266 1543440
+1 90 1 1 2 0 3182 157 72 0.20 0.20 117898 28715 2.80 3.60 3.60 0.00 3.40 25.80 26.40 16.80 86.80 1.0 280 1029800
+1 90 1 1 3 1 883 197 163 1.20 1.40 307742 153302 0.00 0.00 0.00 0.00 0.00 0.00 0.00 75.20 129.20 2.2 6010 1837382
+1 97 1 1 0 0 227 22 38 0.40 0.20 84629 24638 0.00 0.00 0.00 0.00 0.00 0.00 0.00 32.60 44.20 1.2 6815 1876861
+1 93 1 1 64 78 1355 110 98 0.20 0.20 277664 225439 0.00 0.00 0.00 0.00 0.00 6.00 11.60 29.80 69.20 6.4 1512 1549362
+1 0 1 1 19 4 3273 318 255 3.00 1.20 164691 56358 0.00 0.00 0.00 0.00 0.20 2.40 2.40 156.00 255.20 434 86 12
+1 94 1 1 2 1 1583 176 75 0.80 2.00 252010 144391 0.00 0.00 0.00 0.00 0.00 0.40 0.40 59.20 74.80 4.2 3260 1605616
+1 71 1 1 84 109 4458 398 247 1.00 0.40 554419 149277 5.40 14.80 19.60 15.20 1.40 61.00 66.00 60.00 262.20 6.0 279 1297440
+1 90 1 1 8 6 1440 172 118 1.00 2.40 353123 93783 0.60 0.60 16.97 53.29 7.78 4.19 5.39 54.89 133.33 2.2 141 1000632
+1 91 1 1 6 0 1795 215 122 1.00 1.20 174802 29322 2.00 3.40 3.40 0.00 4.00 5.20 8.80 79.80 135.60 1.7 215 1102888
+1 90 1 1 5 1 1526 181 162 3.99 1.20 100316 14250 0.00 0.00 0.00 0.00 0.00 0.00 0.00 179.64 265.27 1.2 7310 1869344
+1 77 1 1 83 96 3389 407 293 2.60 2.80 855090 269362 0.00 0.00 0.00 0.00 23.60 5.60 8.00 259.60 238.40 3.8 2937 1652590
+1 76 1 1 36 48 4637 858 472 1.60 3.20 226690 79258 0.00 0.00 0.00 0.00 0.80 24.20 36.80 120.40 262.60 4.4 1105 1542547
+1 78 1 1 46 0 3871 726 696 1.80 0.80 132101 114754 6.81 13.83 23.45 27.86 0.60 7.62 10.02 107.21 189.98 3.2 185 1046607
+1 94 1 1 17 14 960 51 45 2.20 2.00 43138 21762 0.00 0.00 0.00 0.00 0.40 4.20 5.40 117.20 182.80 1.0 1133 1093691
+1 89 1 1 7 3 3528 270 180 0.40 2.80 28796 14453 0.20 0.20 0.20 0.00 0.60 6.00 7.20 40.00 76.80 5.8 756 1299115
+1 85 1 1 55 70 2242 389 263 0.60 2.60 218732 150155 0.00 0.00 0.00 0.00 0.40 8.60 9.80 58.60 112.60 3.8 2689 1547544
+1 88 1 1 3 2 3764 192 172 1.00 2.59 9224 37656 12.77 16.17 15.77 0.00 10.98 0.20 0.20 122.95 131.54 2.4 358 1382413
+1 94 1 1 38 43 3692 149 123 0.60 0.60 125064 110712 4.80 4.80 4.80 0.00 1.60 2.80 5.20 30.00 57.60 2.0 196 1543643
+1 95 1 1 6 1 1038 43 45 1.00 1.80 39702 38793 0.00 0.00 0.00 0.00 0.00 0.60 0.60 91.22 109.58 2.4 629 1513416
+1 79 1 1 8 0 1717 178 108 6.99 18.96 105627 39301 0.00 0.00 0.00 0.00 0.00 2.59 2.79 243.31 455.89 1.4 460 1079449
+1 94 1 1 0 0 2487 99 141 0.20 0.20 63574 13382 0.00 0.00 0.00 0.00 0.00 7.40 14.60 15.60 17.00 2.8 3959 1716152
+1 94 1 1 50 68 964 96 66 0.60 0.60 5346 14303 0.00 0.00 0.00 0.00 0.00 3.20 3.20 240.80 78.20 3.2 896 975246
+1 97 1 1 2 1 189 15 30 0.20 0.20 8656 15489 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7202 1874064
+1 92 1 1 15 13 1993 132 116 1.20 1.60 34793 60597 2.61 2.61 2.61 0.00 0.40 4.61 4.61 86.17 145.89 1.0 305 991550
+1 93 1 1 4 2 2550 328 203 0.40 0.40 10001 104087 0.00 0.00 0.00 0.00 2.60 0.00 0.00 34.00 109.20 2.3 338 1069949
+1 86 1 1 11 11 3545 539 270 0.40 0.40 663877 574269 3.60 4.00 4.00 0.00 0.60 11.40 11.40 32.60 90.80 2.6 288 1044133
+1 90 1 1 2 1 3075 251 143 1.00 1.00 37634 49451 0.00 0.00 0.00 0.00 0.20 3.60 3.60 68.40 109.00 2.0 715 1116754
+1 85 1 1 5 2 2319 192 140 0.40 0.40 207127 69932 7.00 37.60 143.80 241.00 0.40 45.60 90.40 40.00 159.60 1.0 126 1074045
+1 96 1 1 17 26 408 65 43 0.60 0.60 3516 5376 0.00 0.00 0.00 0.00 0.00 0.00 0.00 36.20 46.80 2.0 389 1717520
+1 96 1 1 3 2 325 28 34 0.20 0.20 93859 27823 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7728 1871744
+1 83 1 1 2 0 516 53 30 2.60 2.60 78884 23095 0.00 0.00 0.00 0.00 0.00 3.80 3.80 197.40 190.80 2.4 922 1789414
+1 93 1 1 12 5 1548 178 72 1.40 2.00 210346 213026 0.00 0.00 0.00 0.00 0.00 1.40 1.60 87.00 180.40 4.4 1990 1559387
+1 93 1 1 7 0 1147 132 97 1.40 1.60 39079 19112 2.00 4.99 9.58 15.17 0.20 3.79 3.79 76.05 138.92 1.7 165 1087467
+1 90 1 1 4 1 2931 123 77 1.40 5.40 189194 2538 0.00 0.00 0.00 0.00 0.00 5.00 6.60 141.60 267.40 3.2 582 1411947
+1 89 1 1 8 2 2835 254 245 1.80 1.40 176000 153151 0.00 0.00 0.00 0.00 0.00 0.00 0.00 117.00 177.00 2.6 1534 1639528
+1 92 1 1 0 0 241 25 38 0.20 0.20 15975 105114 11.60 22.80 19.60 10.80 0.00 3.00 5.00 15.40 21.40 2.0 155 1741774
+1 70 1 1 20 13 3062 299 134 6.80 21.00 177292 30180 6.60 13.80 36.60 78.40 0.20 22.40 39.80 232.40 417.80 1.5 119 1114483
+1 88 1 1 35 6 1493 127 142 0.60 0.80 239978 122822 0.00 0.00 0.00 0.00 0.00 19.60 38.20 49.80 155.40 2.0 1062 1065931
+1 93 1 1 2 0 1056 73 89 0.80 2.40 57689 41735 2.00 3.80 3.60 0.00 1.20 17.40 18.00 72.20 138.40 1.3 317 1059472
+1 89 1 1 7 1 1415 163 120 0.60 0.80 60245 42952 0.00 0.00 0.00 0.00 0.00 7.40 10.40 57.60 118.60 1.0 1214 976187
+1 91 1 1 13 7 1042 112 76 1.00 1.60 39083 32135 2.00 6.40 47.40 97.80 0.60 4.00 4.60 50.00 312.60 1.0 371 966165
+1 84 1 1 6 2 2239 84 106 0.80 0.80 28054 60978 0.00 0.00 0.00 0.00 0.00 4.20 5.80 47.40 73.20 3.6 490 1504586
+1 94 1 1 2 1 1495 71 75 0.60 0.60 16318 11141 0.00 0.00 0.00 0.00 0.00 0.00 0.00 49.00 70.60 2.0 666 1726560
+1 71 1 1 8 0 3238 472 414 8.00 2.20 242440 25070 0.00 0.00 0.00 0.00 0.00 1.00 2.00 384.20 558.40 3.2 735 1759242
+1 95 1 1 0 0 1163 93 79 0.20 0.20 4568 21955 0.00 0.00 0.00 0.00 0.00 1.00 1.00 12.60 93.20 1.0 2913 1050986
+1 82 1 1 11 7 3256 186 94 3.80 4.60 191672 93934 0.00 0.00 0.00 0.00 0.00 16.20 16.20 243.60 383.00 5.4 2532 1601099
+1 79 1 1 5 0 5369 247 227 3.01 2.81 149397 215582 5.41 12.63 25.45 41.08 2.20 13.43 15.03 146.29 299.80 3.2 181 993226
+1 83 1 1 63 81 2007 224 100 1.00 3.00 675249 84771 4.20 14.60 34.00 57.40 5.80 14.40 25.60 107.00 249.60 7.2 202 1586085
+1 97 1 1 0 0 603 44 41 0.20 0.20 1271 13421 0.00 0.00 0.00 0.00 0.00 1.60 1.60 22.00 48.60 1.0 730 1034027
+1 88 1 1 0 0 4630 197 148 0.20 0.20 21921 142011 0.00 0.00 0.00 0.00 1.20 1.00 1.00 15.57 45.51 1.0 341 1013229
+1 74 1 1 28 15 3407 244 145 1.80 4.59 454752 124782 11.98 59.48 114.57 342.12 2.79 19.36 43.71 201.20 430.74 7.8 211 1313086
+1 95 1 1 1 0 291 31 36 0.20 0.20 13411 9400 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 18.00 1.0 417 1753864
+1 90 1 1 0 0 1512 106 119 0.20 0.20 114263 69327 0.20 0.40 0.40 0.00 0.00 10.00 18.20 15.60 22.20 3.2 337 1703808
+1 96 1 1 4 2 219 21 27 0.20 0.20 43529 29703 0.00 0.00 0.00 0.00 0.00 0.40 0.80 19.00 22.40 1.0 5332 1860462
+1 98 1 1 22 32 243 28 24 0.20 0.20 673 4066 0.40 0.40 0.40 0.00 0.00 0.00 0.00 15.60 16.80 2.0 148 1716640
+1 69 1 1 20 13 5194 508 390 7.40 5.40 521179 342017 0.00 0.00 0.00 0.00 0.00 4.00 7.20 389.20 556.60 1.3 1142 1014674
+1 88 1 1 7 4 916 112 133 3.00 4.60 104384 96116 0.00 0.00 0.00 0.00 0.00 4.20 8.00 203.40 270.20 1.6 2921 1737634
+1 87 1 1 4 0 1972 202 86 2.61 2.61 383791 23638 0.00 0.00 0.00 0.00 0.00 22.65 24.25 164.53 245.09 1.0 1237 1065042
+1 68 1 1 28 4 5380 351 330 2.20 1.40 416770 756590 2.40 3.59 3.59 0.00 3.19 8.18 31.34 128.14 377.25 4.8 402 1006272
+1 87 1 1 11 3 3062 260 303 0.40 0.20 157549 461744 0.00 0.00 0.00 0.00 0.00 2.40 2.60 18.20 53.40 2.2 506 1385634
+1 98 1 1 0 0 166 12 20 0.20 0.20 444 13044 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.4 7425 1869323
+1 97 1 1 20 13 388 55 41 0.40 0.40 25037 34828 0.00 0.00 0.00 0.00 0.00 0.00 0.00 36.60 43.80 2.0 673 1711805
+1 80 1 1 17 13 3587 342 223 2.81 4.01 509515 315743 14.43 26.25 33.67 29.26 8.62 5.61 13.03 162.32 277.76 2.0 189 1040996
+1 86 1 1 0 0 2253 188 136 0.20 0.20 67816 70543 7.20 9.20 8.80 0.00 1.80 0.60 1.00 15.60 18.20 2.2 170 1765675
+1 66 1 1 12 4 3870 162 96 2.00 6.60 415969 37617 7.20 25.20 58.20 105.20 3.00 44.20 68.80 139.40 246.60 5.8 162 1290510
+1 78 1 1 83 100 4659 260 242 3.40 7.00 87695 133647 1.20 1.80 1.60 0.00 0.80 24.00 24.40 139.80 303.40 3.8 1069 1639603
+1 94 1 1 11 2 596 65 76 0.80 0.80 25733 19067 2.61 2.61 2.61 0.00 1.80 1.80 1.80 46.29 64.93 1.2 189 1746907
+1 77 1 1 499 161 1939 101 151 8.60 9.20 8949 139059 0.40 4.80 0.60 0.00 0.80 8.20 10.80 273.80 480.60 2.4 1519 1715733
+1 95 1 1 1 0 1927 102 81 0.40 0.60 20124 27027 0.00 0.00 0.00 0.00 0.00 0.40 0.40 34.40 45.00 2.0 793 1052765
+1 98 1 1 2 1 317 23 38 0.40 0.40 12206 10751 0.00 0.00 0.00 0.00 0.00 0.20 0.20 31.20 36.00 1.0 7904 1880794
+1 84 1 1 11 3 3619 306 254 2.99 3.59 124782 53702 4.99 9.78 21.96 24.75 1.80 4.59 5.19 162.87 261.68 1.0 172 1087230
+1 92 1 1 2 0 469 62 33 1.60 1.60 60798 11526 0.00 0.00 0.00 0.00 0.40 0.60 0.60 101.60 143.20 1.2 1113 1763752
+1 74 1 1 6 1 4146 248 164 6.80 7.20 452773 119655 0.00 0.00 0.00 0.00 2.00 11.60 18.00 289.60 570.60 1.4 787 996381
+1 85 1 1 7 1 1821 218 179 0.60 0.60 205863 73349 4.39 6.19 7.58 6.99 3.99 6.19 24.75 71.26 157.29 2.5 256 1099336
+1 95 1 1 1 1 330 40 46 0.20 0.20 85936 34518 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.80 18.20 3.4 1000 1717138
+1 72 1 1 27 2 4332 507 422 7.80 3.20 375370 26815 0.00 0.00 0.00 0.00 0.00 7.80 8.80 380.00 627.20 1.5 1970 1077070
+1 92 1 1 0 0 2247 212 63 0.80 0.80 445362 22351 0.00 0.00 0.00 0.00 0.00 3.80 4.00 77.60 164.80 1.0 994 1022558
+1 94 1 1 0 0 1603 126 76 0.80 1.00 187135 37253 2.60 4.60 4.20 0.00 0.00 0.80 0.80 59.40 95.00 1.0 281 1015630
+1 78 1 1 23 14 3718 424 149 4.79 7.98 101003 39227 7.58 28.14 45.51 102.59 1.00 0.60 0.60 300.80 498.40 1.0 328 1065656
+1 98 1 1 0 0 380 175 45 0.20 0.20 350658 250588 0.00 0.00 0.00 0.00 0.00 0.40 0.40 16.00 17.00 2.8 1316 1745824
+1 0 1 1 3 2 1740 206 162 0.20 0.20 141298 107080 9.02 20.64 42.89 61.72 1.20 4.81 6.01 22.85 124.45 135 84 16
+1 74 1 1 25 1 5077 284 227 5.80 16.40 157608 68914 4.20 5.60 4.60 0.00 0.60 20.60 24.40 197.60 380.40 4.0 273 1102235
+1 88 1 1 0 0 1743 123 72 0.20 0.20 132643 50785 0.00 0.00 0.00 0.00 0.00 10.20 20.40 15.60 21.00 2.0 599 1768939
+1 91 1 1 11 10 1429 104 77 0.80 2.40 29048 26115 0.00 0.00 0.00 0.00 0.00 19.00 19.00 74.40 119.40 1.0 1036 1086347
+1 58 1 1 60 5 3777 198 102 12.40 33.60 117384 28568 0.00 0.00 0.00 0.00 0.00 12.60 17.80 467.20 848.20 1.6 1086 1107486
+1 85 1 1 64 86 2489 218 160 1.20 2.80 265618 190198 3.00 24.80 44.00 116.20 1.40 6.40 8.40 92.40 269.60 4.8 330 1330898
+1 92 1 1 1 0 1139 85 43 0.20 0.20 25711 5372 0.00 0.00 0.00 0.00 0.00 2.00 2.00 15.60 16.80 1.8 492 1742376
+1 95 1 1 7 3 1240 134 45 0.40 0.40 355655 8700 0.00 0.00 0.00 0.00 0.00 0.40 0.60 33.80 45.20 1.2 5789 1862691
+1 95 1 1 4 0 1176 67 57 0.80 3.40 14861 28364 0.00 0.00 0.00 0.00 0.00 0.00 0.00 68.00 86.20 2.0 474 1536344
+1 64 1 1 70 81 6198 350 236 4.60 9.60 161690 85053 17.40 49.60 51.80 11.60 3.00 4.20 5.80 250.60 366.40 4.4 177 1318411
+1 96 1 1 1 1 893 70 73 0.20 0.20 18669 49639 0.00 0.00 0.00 0.00 0.20 1.20 2.20 19.96 44.71 1.0 707 1058507
+1 83 1 1 5 1 3506 350 189 1.00 1.00 162808 119490 0.00 0.00 0.00 0.00 0.00 7.40 9.60 85.40 145.60 2.6 2354 1397294
+1 85 1 1 32 20 2872 460 230 0.80 1.00 554538 518043 4.61 5.21 5.21 0.00 3.61 29.66 56.71 76.75 176.75 2.2 264 1036653
+1 72 1 1 9 0 4615 474 401 8.62 3.61 282155 66364 2.61 13.23 20.84 24.25 0.00 3.81 4.81 403.41 642.48 2.7 235 1117606
+1 93 1 1 2 1 1274 143 103 0.60 0.60 33226 41914 0.00 0.00 0.00 0.00 0.00 2.20 2.40 44.40 74.20 3.2 2869 1049982
+1 90 1 1 4 0 2220 97 105 2.20 3.80 123115 115700 0.00 0.00 0.00 0.00 0.00 0.00 0.00 147.40 197.40 2.4 809 1539522
+1 0 1 1 33 4 1723 97 63 8.20 8.00 93520 46645 7.20 11.80 36.00 56.00 0.40 6.40 6.60 287.60 591.80 133 82 18
+1 97 1 1 13 13 218 19 28 0.20 0.20 4963 25330 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7582 1878664
+1 96 1 1 4 2 1036 64 51 0.40 0.60 101463 32561 1.40 1.60 2.00 2.20 4.40 0.60 0.80 30.80 71.40 2.2 138 1523264
+1 89 1 1 13 9 4732 422 127 0.80 0.80 289875 93154 7.39 13.77 16.17 14.97 10.18 4.19 10.58 111.78 143.71 2.0 268 1002544
+1 98 1 1 0 0 411 61 30 0.40 0.20 101420 12926 0.00 0.00 0.00 0.00 0.00 0.20 0.20 32.60 44.20 1.2 7219 1874861
+1 0 1 1 10 5 2074 339 203 0.40 1.00 107949 28309 1.40 1.80 2.60 1.80 1.20 9.80 10.00 55.00 193.80 226 88 12
+1 76 1 1 22 10 4572 205 146 2.00 3.80 226476 42162 17.60 21.40 25.60 13.00 17.00 23.40 28.40 161.60 309.60 7.2 202 1313782
+1 72 1 1 193 213 4585 385 330 0.60 0.60 561341 494475 0.00 0.00 0.00 0.00 0.00 36.33 70.66 43.91 181.84 2.0 1041 1018917
+1 94 1 1 5 3 1038 77 38 1.00 1.20 308260 13559 7.40 13.00 24.40 37.20 6.40 3.00 4.20 54.40 155.00 1.7 145 1010936
+1 89 1 1 21 7 2366 157 127 0.60 0.80 33344 46142 2.60 2.60 2.60 0.00 0.80 26.00 26.00 51.00 179.40 1.8 321 976061
+1 84 1 1 4 0 4521 312 264 0.60 2.20 42268 336855 6.39 8.98 8.98 0.00 0.60 11.38 13.17 39.72 102.99 1.0 205 996974
+1 95 1 1 1 1 1630 74 65 0.20 0.20 63651 124637 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.60 16.80 1.2 6927 1879024
+1 84 1 1 3 3 1920 208 147 1.20 2.60 340730 105979 0.00 0.00 0.00 0.00 0.00 8.80 12.40 218.80 354.00 2.0 662 989347
+1 84 1 1 39 50 4374 202 227 1.20 1.60 171941 241147 12.20 14.80 14.80 0.00 5.40 1.00 1.20 73.40 169.20 1.0 238 999811
+1 77 1 1 12 8 5073 133 86 2.80 8.40 78122 29148 0.00 0.00 0.00 0.00 0.20 6.40 6.40 250.00 265.00 3.0 674 1445475
+1 81 1 1 3 1 4361 266 219 1.00 1.20 106745 199509 12.80 31.60 61.60 128.20 1.00 10.80 19.40 94.80 190.20 1.8 238 1001872
+1 91 1 1 5 1 2210 146 128 0.80 0.80 131443 216349 0.00 0.00 0.00 0.00 0.00 6.80 6.80 43.40 121.00 2.2 652 1525027
+1 94 1 1 2 0 2501 155 78 0.40 0.60 349248 231571 0.00 0.00 0.00 0.00 0.00 2.80 5.00 45.20 50.60 5.2 2422 1542738
+1 77 1 1 51 43 2855 338 262 7.20 5.20 224173 133492 6.80 16.00 25.80 43.00 7.60 4.60 7.40 401.60 658.60 1.5 231 960576
+1 79 1 1 23 19 3755 298 174 3.01 4.61 138010 62887 0.00 0.00 0.00 0.00 0.00 7.62 9.22 186.57 531.46 1.8 734 1022807
+1 98 1 1 15 22 160 16 13 0.20 0.20 6989 11016 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.4 8506 1866392
+1 91 1 1 29 20 3382 202 159 1.80 0.80 166820 31939 2.40 4.60 10.40 23.00 0.60 3.20 17.80 79.80 119.60 4.8 136 1520570
+1 80 1 1 6 1 5074 324 205 2.40 7.20 531727 88764 8.80 25.00 34.60 64.80 4.20 9.80 12.20 92.60 222.80 1.0 177 1088126
+1 98 1 1 0 0 148 8 15 0.20 0.20 423 3942 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 6458 1871616
+1 85 1 1 3 2 3170 262 116 0.80 1.20 277748 32232 7.60 9.80 9.80 0.00 10.80 4.40 5.60 97.20 122.40 4.4 172 1441368
+1 94 1 1 11 8 2236 159 149 0.80 0.60 75475 100500 0.00 0.00 0.00 0.00 0.20 0.60 0.60 52.49 78.53 3.0 2236 1967275
+1 78 1 1 8 0 2722 267 221 1.20 2.80 674717 254025 0.60 10.80 32.00 79.00 3.60 54.20 83.60 144.60 235.20 2.0 395 1048712
+1 97 1 1 0 0 1179 83 171 0.20 0.20 38433 24002 0.80 1.00 0.80 0.00 0.00 1.20 1.20 15.20 25.80 3.2 180 1710194
+1 96 1 1 5 1 734 71 80 0.40 0.40 17817 27947 0.00 0.00 0.00 0.00 0.00 0.60 0.60 36.00 101.60 1.0 834 1035170
+1 92 1 1 4 1 3028 204 158 1.60 0.60 303218 17160 5.20 5.40 5.40 0.00 2.60 0.00 0.00 82.80 126.00 2.8 161 1709837
+1 68 1 1 219 209 5898 436 237 2.20 7.40 509331 282566 8.80 34.20 64.60 83.80 3.00 25.20 62.80 175.20 210.80 4.8 141 1336872
+1 90 1 1 20 4 2581 322 165 0.40 0.40 32867 12276 0.00 0.00 0.00 0.00 0.00 19.00 22.80 26.60 97.00 3.4 3887 1414698
+1 99 1 1 0 0 339 49 10 0.20 0.20 15123 3804 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13.00 17.00 1.0 7110 1873408
+1 79 1 1 11 9 1784 106 65 1.39 3.78 552187 20575 20.12 104.18 237.45 524.30 0.40 75.30 148.41 54.58 317.53 1.0 323 1100151
+1 92 1 1 2 1 1120 60 59 1.60 2.80 9287 15261 0.40 0.40 0.40 0.00 0.60 0.40 0.60 90.00 158.20 1.0 179 1024437
+1 81 1 1 14 9 3013 271 138 3.80 4.60 595449 504034 0.00 0.00 0.00 0.00 0.20 12.20 18.40 231.20 373.20 5.0 3141 1040317
+1 86 1 1 8 4 3313 332 135 0.60 0.60 1195810 56297 16.80 19.60 19.60 0.00 17.20 15.80 17.20 46.20 100.60 3.4 168 1092554
+1 0 1 1 3 2 1894 122 116 0.20 0.20 5776 29548 2.60 5.00 5.00 0.00 0.60 4.00 4.00 15.60 53.60 165 95 5
+1 97 1 1 0 0 204 23 31 0.20 0.20 8121 8267 0.00 0.00 0.00 0.00 0.00 0.60 1.00 14.40 16.80 1.0 5204 1860792
+1 81 1 1 220 3 2368 183 66 2.79 4.59 478318 47522 0.00 0.00 0.00 0.00 0.00 115.57 115.57 122.36 202.59 3.8 1403 1539388
+1 94 1 1 15 14 2238 204 113 0.20 0.20 183180 180325 0.00 0.00 0.00 0.00 0.00 1.20 2.20 23.00 42.40 4.0 1230 1598811
+1 96 1 1 5 2 378 59 49 0.60 3.60 45580 39395 0.00 0.00 0.00 0.00 0.00 0.20 0.20 25.80 42.20 2.2 2092 1720181
+1 92 1 1 4 1 2605 176 103 0.40 0.40 175026 45282 0.00 0.00 0.00 0.00 0.00 2.60 4.20 34.80 43.80 3.0 427 1629016
+1 90 1 1 1 0 3989 188 139 0.40 0.40 157284 29787 0.00 0.00 0.00 0.00 0.00 4.20 4.20 37.40 52.20 2.0 468 1060715
+1 85 1 1 3 1 1635 150 147 1.80 1.60 178375 71109 2.20 3.20 2.60 0.00 2.00 3.80 5.20 106.60 229.20 2.0 340 1110091
+1 85 1 1 8 1 3276 193 145 1.80 3.20 41480 102652 0.00 0.00 0.00 0.00 0.00 15.40 20.60 131.40 198.40 1.0 1182 1111248
+1 68 1 1 53 61 4087 256 176 7.80 22.00 119035 43429 2.00 2.20 2.20 0.00 5.60 2.80 3.20 301.20 568.80 1.8 334 1086571
+1 80 1 1 44 1 2417 283 559 1.60 2.40 80297 128013 0.00 0.00 0.00 0.00 0.20 16.60 16.80 64.00 93.20 2.2 1388 1714877
+1 83 1 1 17 2 2349 344 125 2.60 6.00 254144 189500 3.20 12.20 25.00 69.60 0.60 4.40 4.80 501.20 212.60 1.6 171 1120445
+1 0 1 1 6 2 1322 51 51 0.40 0.40 27582 35275 2.99 3.99 3.99 0.00 0.00 2.40 2.99 35.33 43.91 334 95 5
+1 90 1 1 39 56 2168 257 161 0.40 0.60 185504 46769 0.00 0.00 0.00 0.00 0.20 3.60 6.60 34.00 82.20 3.2 986 1058147
+1 90 1 1 13 6 1792 138 89 1.80 2.00 85911 18297 0.00 0.00 0.00 0.00 0.40 2.20 2.60 107.60 159.80 1.0 552 1015315
+1 83 1 1 23 14 4784 385 228 3.20 6.80 313076 216093 0.00 0.00 0.00 0.00 0.00 3.60 4.80 124.40 199.40 2.5 680 1017240
+1 80 1 1 22 12 2000 304 70 3.40 3.40 198968 16062 1.40 1.60 1.60 0.00 1.20 1.60 2.40 226.00 327.00 2.2 359 1744197
+1 90 1 1 8 5 3209 191 123 1.60 2.20 289588 141211 0.00 0.00 0.00 0.00 0.00 0.20 0.40 92.60 205.80 5.4 1578 1640846
+1 86 1 1 31 25 3143 248 147 1.20 1.20 170701 69003 0.00 0.00 0.00 0.00 0.00 21.60 23.60 75.40 305.20 4.6 7443 1371331
+1 93 1 1 13 11 3942 183 115 0.60 0.60 253758 171361 0.00 0.00 0.00 0.00 0.00 0.20 0.40 42.80 77.40 3.6 3311 1339798
+1 69 1 1 48 14 5818 260 116 5.40 10.40 518051 116869 0.00 0.00 0.00 0.00 0.00 17.80 20.80 368.80 450.00 3.2 1251 1545342
+1 94 1 1 2 0 1770 95 74 0.60 0.60 10302 37454 1.80 2.00 2.00 0.00 0.00 0.80 0.80 35.80 44.80 2.0 164 1057232
+1 92 1 1 1 0 2414 171 148 0.20 0.20 59875 60014 0.00 0.00 0.00 0.00 0.00 0.00 0.00 24.60 25.00 1.0 2740 1051534
+1 92 1 1 7 2 2105 154 83 1.00 1.20 144945 36898 0.00 0.00 0.00 0.00 0.40 10.62 15.63 94.99 167.74 1.0 812 1021146
+1 84 1 1 22 18 1067 86 74 2.00 2.20 97803 45412 6.79 12.77 12.77 0.00 3.19 13.37 14.77 127.94 396.81 1.8 557 1017241
+1 85 1 1 4 3 3790 312 200 0.40 0.40 50530 39704 1.40 1.60 1.60 0.00 0.80 3.00 3.40 33.60 56.00 2.0 361 1103565
+1 98 1 1 1 1 179 12 30 0.20 0.20 7241 15541 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7293 1875112
+1 82 1 1 12 2 4312 266 131 0.80 0.80 367000 37658 4.60 31.00 201.40 337.80 0.40 20.20 24.80 103.20 321.80 1.0 127 1075939
+1 96 1 1 1 0 467 96 94 0.20 0.20 230419 80550 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 23.60 2.8 2203 1731413
+1 71 1 1 18 2 5375 545 358 6.40 2.20 1067251 73202 2.40 3.60 3.00 0.00 1.80 14.40 17.20 315.20 503.40 3.4 272 1080474
+1 96 1 1 29 12 862 135 91 0.40 0.40 131306 52089 0.00 0.00 0.00 0.00 0.00 1.40 1.40 40.20 47.80 1.0 693 990952
+1 94 1 1 13 17 240 15 23 0.00 0.00 2214 3927 0.00 0.00 0.00 0.00 0.00 1.00 1.00 1.60 3.79 1.6 3682 1770946
+1 93 1 1 2 1 2497 129 137 0.40 1.80 20588 58331 3.40 4.00 4.80 1.20 0.60 1.40 1.60 21.60 43.80 2.4 155 1709878
+1 90 1 1 3 0 2048 210 154 1.00 1.00 224820 95010 5.40 14.80 37.20 80.00 0.20 17.00 21.80 61.20 84.60 3.2 205 1700128
+1 76 1 1 4 1 7003 340 256 1.40 3.99 337791 188634 15.17 62.28 143.31 334.93 0.80 115.37 140.32 99.20 302.20 2.5 134 1008271
+1 90 1 1 0 0 3265 203 162 0.20 0.20 36774 258941 0.00 0.00 0.00 0.00 0.60 1.40 2.61 15.63 29.06 2.8 606 1016348
+1 0 1 1 12 7 1279 105 65 0.80 2.59 38119 32996 0.00 0.00 0.00 0.00 0.20 3.79 3.79 77.64 102.99 545 91 9
+1 93 1 1 2 1 1832 216 139 0.40 1.80 12707 21307 0.00 0.00 0.00 0.00 0.40 5.41 5.41 103.01 115.63 3.8 406 1103627
+1 94 1 1 3 2 842 94 74 0.20 0.20 14825 35144 2.80 4.20 4.20 0.00 0.20 2.60 3.00 15.80 45.40 1.0 219 1003526
+1 92 1 1 1 1 1344 84 74 0.20 0.20 87208 108645 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.17 20.36 1.0 8371 1834485
+1 87 1 1 5 0 1136 167 124 2.80 1.60 189887 15359 0.00 0.00 0.00 0.00 0.00 12.80 26.00 163.60 270.20 1.6 741 1773115
+1 95 1 1 0 0 522 64 136 0.20 0.20 183839 147631 0.80 0.80 0.80 0.00 1.60 0.00 0.00 16.03 18.24 1.4 214 1747157
+1 87 1 1 11 1 3579 233 152 2.00 2.00 159831 134542 1.00 1.00 10.20 13.80 1.20 2.80 2.80 81.00 169.80 3.6 167 1064186
+1 93 1 1 0 0 798 67 55 0.20 0.20 1382 6939 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13.00 16.80 1.6 987 1761488
+1 88 1 1 4 2 3367 215 174 0.40 0.40 8468 23881 0.00 0.00 0.00 0.00 0.00 19.32 19.92 41.24 87.45 2.2 497 1015256
+1 88 1 1 2 0 3584 137 89 0.60 0.80 113087 83996 0.00 0.00 0.00 0.00 0.00 4.79 6.19 49.30 97.60 3.2 703 1015262
+1 75 1 1 44 0 3700 410 200 3.39 5.79 544367 247202 2.99 7.98 21.16 51.10 1.20 21.36 53.89 618.16 427.15 2.0 180 1118221
+1 84 1 1 6 3 480 56 29 1.60 1.60 253233 41812 0.00 0.00 0.00 0.00 0.00 2.40 4.19 146.71 138.52 2.0 2627 1791313
+1 78 1 1 36 21 3119 232 109 3.00 7.00 319349 35204 4.80 9.80 21.80 42.00 3.40 1.20 3.80 207.20 400.40 2.0 227 1109101
+1 87 1 1 30 26 3345 168 136 2.00 2.00 33450 35514 1.40 1.40 4.99 9.98 1.00 6.59 9.98 127.15 210.38 2.6 181 1083288
+1 75 1 1 47 27 3614 297 224 2.40 9.60 268558 149443 4.00 13.80 26.00 27.00 3.60 26.20 29.20 165.40 577.20 6.2 334 1315598
+1 86 1 1 6 0 1183 192 132 2.80 1.80 261276 123008 4.80 9.60 25.80 47.40 0.40 16.80 29.20 170.60 239.20 3.4 187 1708110
+1 88 1 1 1 0 957 165 97 0.20 0.20 19800 41088 0.00 0.00 0.00 0.00 0.00 0.20 0.20 19.00 23.80 1.8 1746 1768891
+1 88 1 1 52 48 4380 344 257 0.80 0.60 232167 101473 3.99 5.59 5.39 0.00 2.20 8.38 8.58 51.90 211.58 5.8 228 1294933
+1 76 1 1 27 5 6165 861 380 4.40 6.80 671262 217361 0.00 0.00 0.00 0.00 0.20 0.40 0.40 238.60 430.60 5.4 2541 1645075
+1 92 1 1 1 0 2870 219 124 0.60 1.00 258293 26410 0.00 0.00 0.00 0.00 0.00 1.40 1.40 52.60 55.60 1.3 504 1060874
+1 99 1 1 1 1 197 13 24 0.20 0.20 10134 12202 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 1.0 7309 1873272
+1 90 1 1 30 44 1406 136 85 0.20 0.20 39455 29702 0.60 0.60 0.60 0.00 0.20 1.80 1.80 16.80 28.00 2.0 183 1741947
+1 81 1 1 34 21 2783 251 178 3.99 2.79 329611 106187 0.00 0.00 0.00 0.00 0.00 33.13 43.91 201.80 461.28 4.0 8614 1367184
+1 74 1 1 12 5 4038 530 466 6.00 1.80 269206 113453 0.00 0.00 0.00 0.00 0.00 4.40 5.00 479.20 496.80 1.0 1028 999211
+1 78 1 1 8 2 1816 257 216 6.01 3.21 230537 47539 0.00 0.00 0.00 0.00 0.00 3.61 6.61 383.37 449.30 3.0 10875 1874171
+1 85 1 1 6 2 2157 114 105 3.59 4.58 43925 64027 3.19 18.53 41.04 96.41 0.80 1.79 2.39 177.29 234.66 2.2 163 1508021
+1 95 1 1 1 1 912 47 39 0.40 1.80 9071 14411 0.00 0.00 0.00 0.00 1.20 0.00 0.00 20.80 32.60 2.2 1121 1718784
+1 66 1 1 21 13 5070 465 418 7.60 15.40 188568 166592 3.80 12.00 17.40 14.20 0.00 8.00 9.00 319.00 499.40 1.5 136 1090643
+1 89 1 1 22 17 1893 138 110 0.80 0.80 141423 58049 8.00 16.80 37.40 99.00 3.00 5.40 13.80 45.00 132.00 1.5 122 968677
+1 88 1 1 14 8 2128 206 118 2.00 2.40 221487 182173 2.40 13.40 45.20 71.40 0.40 6.20 10.00 90.60 175.40 5.0 193 1594190
+1 94 1 1 1 0 819 121 96 0.20 0.20 18574 20181 0.00 0.00 0.00 0.00 0.00 59.60 61.40 15.60 94.60 1.4 1462 1074070
+1 88 1 1 61 83 1438 120 106 1.00 1.40 43252 59905 0.00 0.00 0.00 0.00 0.20 8.00 10.00 82.00 93.00 2.0 627 1116195
+1 60 1 1 40 10 6410 450 400 9.80 10.60 216352 40236 0.00 0.00 0.00 0.00 0.00 0.00 0.00 588.60 794.00 3.6 1157 1540979
+1 91 1 1 1 0 3543 139 128 0.20 0.20 23901 45254 0.00 0.00 0.00 0.00 0.00 0.20 0.20 22.00 19.80 2.3 2491 1046205
+1 97 1 1 1 1 320 145 39 0.20 0.20 260349 235866 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 5716 1832992
+1 95 1 1 15 14 681 97 60 0.60 2.40 36367 35582 0.00 0.00 0.00 0.00 0.00 4.99 4.99 48.50 99.60 1.0 801 1016639
+1 93 1 1 3 1 767 87 83 2.20 2.40 86290 18476 0.00 0.00 0.00 0.00 1.00 2.00 2.60 113.80 203.60 3.6 628 1713152
+1 0 1 1 12 5 1176 88 72 1.40 1.80 33693 24259 2.00 2.00 2.00 0.00 0.00 6.00 9.40 100.80 142.60 262 94 6
+1 93 1 1 4 2 1492 219 99 0.40 0.40 241235 231696 0.00 0.00 0.00 0.00 0.00 6.40 10.60 37.80 55.20 4.2 1642 1604389
+1 91 1 1 2 1 2224 104 110 0.40 0.80 46636 57564 0.00 0.00 0.00 0.00 0.00 1.20 1.40 41.12 67.66 2.0 714 1058857
+1 88 1 1 1 0 2156 461 219 0.60 1.00 145309 69430 0.00 0.00 0.00 0.00 0.00 0.60 1.00 74.80 177.80 1.0 632 1061534
+1 88 1 1 5 1 1960 207 129 0.80 0.80 155226 48472 0.00 0.00 0.00 0.00 0.20 10.20 18.40 69.80 158.20 4.3 1121 1068314
+1 91 1 1 1 0 2907 185 161 0.20 0.20 5274 77481 0.00 0.00 0.00 0.00 0.40 8.00 8.00 15.40 33.60 1.2 153 1064822
+1 78 1 1 16 1 5420 560 450 6.59 1.80 190506 64355 0.00 0.00 0.00 0.00 0.00 0.00 0.00 317.76 465.67 3.8 2525 1640078
+1 65 1 1 47 0 2735 104 81 12.22 36.27 70870 43520 0.60 0.80 5.61 6.81 0.20 13.83 21.24 418.44 785.97 1.8 208 1097988
+1 81 1 1 3 0 854 92 200 1.80 1.80 208005 122355 4.20 4.20 4.20 0.00 0.20 4.20 7.20 159.20 154.60 1.2 364 1813250
+1 73 1 1 28 10 4791 310 180 5.80 4.20 533790 66271 0.00 0.00 0.00 0.00 0.00 4.60 5.80 357.80 538.00 6.8 1281 1543910
+1 93 1 1 24 15 1489 170 105 0.20 0.20 177302 51313 0.00 0.00 0.00 0.00 0.00 2.40 3.00 30.00 72.00 1.0 1061 1082534
+1 89 1 1 2 0 1894 176 144 1.00 1.40 68498 79861 0.00 0.00 0.00 0.00 0.00 14.60 14.80 80.20 147.40 3.0 2393 1092941
+1 73 1 1 17 1 4513 669 285 6.20 6.60 141283 54741 5.40 24.60 58.60 148.00 0.00 30.20 43.60 369.20 583.60 1.8 182 992085
+1 96 1 1 0 0 1274 57 49 0.80 0.60 18505 37252 0.00 0.00 0.00 0.00 0.00 0.00 0.00 37.80 46.60 1.2 6764 1825955
+1 82 1 1 27 37 469 45 63 2.00 2.00 79060 69304 6.60 6.80 6.80 0.00 0.00 2.40 3.60 184.60 160.80 1.2 256 1801634
+1 89 1 1 1 0 1203 150 77 0.80 2.00 644364 347794 2.40 4.80 4.80 0.00 2.40 8.80 17.20 54.00 69.60 2.6 271 1756702
+1 85 1 1 97 126 3958 138 103 1.80 2.80 119994 32326 3.20 12.00 36.60 82.60 0.00 3.40 6.80 177.00 308.20 1.7 414 1012853
+1 94 1 1 2 0 1317 134 88 0.60 2.00 61085 24946 4.41 4.61 4.61 0.00 1.20 4.81 7.82 50.70 73.35 1.0 191 1016476
+1 73 1 1 3 0 2582 482 157 3.59 3.79 715262 181985 7.58 46.11 116.37 355.69 0.20 34.93 53.29 458.88 439.12 2.5 149 1113241
+1 91 1 1 4 0 1275 180 142 2.40 0.80 84377 21289 4.40 4.40 4.40 0.00 1.80 0.40 0.40 118.00 253.40 1.0 180 1023469
+1 73 1 1 912 13 3457 204 175 0.80 1.80 148759 172326 5.60 23.20 30.20 21.60 0.80 29.60 32.60 43.80 87.00 1.0 136 1062344
+1 84 1 1 6 0 3233 273 212 2.40 2.40 762669 37788 0.00 0.00 0.00 0.00 0.00 7.60 14.40 91.20 170.20 3.2 2216 1704267
+1 89 1 1 165 179 1947 176 205 0.60 1.80 100934 26525 0.00 0.00 0.00 0.00 0.00 9.20 11.40 34.20 149.80 2.0 569 1090400
+1 98 1 1 2 2 175 16 14 0.20 0.20 7570 3624 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.20 17.40 1.0 5059 1828909
+1 95 1 1 1 0 1261 213 71 0.40 0.60 206688 220190 0.00 0.00 0.00 0.00 0.00 0.00 0.00 29.40 44.60 3.4 940 1749050
+1 94 1 1 0 0 2450 110 98 0.20 0.20 221129 23126 1.40 2.60 2.60 0.00 0.80 0.40 0.60 15.80 19.60 2.6 156 1709690
+1 73 1 1 0 0 11710 5318 5456 0.60 2.00 54077 60565 15.43 28.26 37.47 58.72 0.00 17.64 26.85 47.09 76.75 1.0 319 994078
+1 59 1 1 23 11 7183 819 707 10.78 5.79 619588 328356 0.00 0.00 0.00 0.00 0.00 5.39 10.58 531.74 837.13 1.8 821 1012409
+1 95 1 1 3 2 615 98 43 1.20 3.80 437999 380525 0.00 0.00 0.00 0.00 0.00 0.00 0.00 67.00 88.60 2.8 5752 1837685
+1 88 1 1 54 73 3182 252 148 1.00 4.00 272213 87430 0.00 0.00 0.00 0.00 0.00 8.20 9.80 70.20 113.40 1.8 495 1009674
+1 94 1 1 3 1 2042 74 63 0.40 0.40 2667 15224 0.00 0.00 0.00 0.00 0.00 1.20 1.80 31.80 42.00 1.0 1240 1745904
+1 95 1 1 20 27 1101 107 32 0.80 1.20 44885 12600 0.00 0.00 0.00 0.00 0.00 0.40 0.40 44.91 67.66 1.0 8246 1859824
+1 92 1 1 0 0 1669 104 64 0.20 0.20 3101 16334 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.40 1.8 989 1761502
+1 74 1 1 190 36 3506 550 440 3.40 1.00 264051 173799 12.40 56.00 112.40 150.20 0.60 30.20 50.00 174.80 300.20 1.0 137 1017334
+1 94 1 1 2 0 915 89 86 0.40 0.60 8379 26797 0.00 0.00 0.00 0.00 0.00 2.40 2.40 35.47 59.72 3.2 675 979117
+1 83 1 1 70 78 2836 158 114 2.80 5.80 293303 8046 0.00 0.00 0.00 0.00 0.00 8.40 11.80 196.20 383.60 5.4 971 1331979
+1 91 1 1 1 0 2481 262 205 0.20 0.20 9731 44698 0.00 0.00 0.00 0.00 0.00 8.40 8.80 17.80 60.00 2.5 634 977747
+1 88 1 1 46 62 3939 234 129 2.60 5.00 298009 188750 0.00 0.00 0.00 0.00 0.00 0.60 0.60 139.40 212.00 4.6 2185 1641514
+1 0 1 1 9 5 2164 82 169 0.60 2.00 60189 23390 0.00 0.00 0.00 0.00 0.40 15.60 15.60 51.40 101.00 403 91 9
+1 88 1 1 184 25 3797 251 240 1.80 3.79 150508 116593 6.79 29.34 29.14 0.00 0.60 6.79 6.99 87.43 155.69 3.4 309 1327385
+1 0 1 1 11 6 1512 98 59 0.40 0.40 313126 16402 3.20 4.20 5.20 11.40 3.60 3.00 4.20 39.80 53.60 163 92 7
+1 92 1 1 0 0 1927 64 88 0.20 0.20 22556 61561 0.20 0.40 0.40 0.00 0.00 67.00 67.00 15.40 91.60 2.2 375 1759814
+1 0 1 1 14 6 1797 403 268 1.80 8.80 208664 97152 0.00 0.00 0.00 0.00 0.00 1.60 2.20 78.20 357.40 522 87 12
+1 94 1 1 0 0 392 65 36 0.40 0.60 446999 276715 0.00 0.00 0.00 0.00 0.00 0.00 0.00 29.40 215.60 3.2 4074 1823195
+1 94 1 1 36 26 2259 155 121 0.40 0.60 193753 144893 0.00 0.00 0.00 0.00 0.00 3.20 6.20 37.60 63.60 2.4 1817 1640472
+1 81 1 1 2 0 538 60 22 2.40 2.40 181203 26377 0.00 0.00 0.00 0.00 0.00 1.00 1.00 196.39 192.79 1.2 2589 1797740
+1 84 1 1 12 2 2166 361 118 5.81 3.81 145888 29915 0.20 0.20 0.20 0.00 0.00 1.60 2.61 227.45 383.57 1.5 449 1068301
+1 98 1 1 1 0 874 14 20 0.20 0.20 570 6276 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.60 16.80 1.4 556 1752872
+1 69 1 1 50 3 4572 219 101 9.18 21.76 505063 27195 2.99 3.59 7.19 8.18 9.18 5.39 6.59 377.05 637.13 3.0 165 1086970
+1 83 1 1 5 1 1644 165 161 2.81 5.21 359829 241730 12.02 69.54 142.89 274.55 1.20 45.29 74.15 175.15 300.60 3.0 156 1068024
+1 92 1 1 0 0 2734 175 146 0.40 1.80 175914 72506 0.00 0.00 0.00 0.00 0.20 14.60 15.80 33.80 67.40 2.4 4893 1405738
+1 93 1 1 5 4 1750 85 73 0.60 3.59 7772 49825 0.00 0.00 0.00 0.00 0.00 20.16 20.76 25.15 75.65 2.5 364 1028722
+1 92 1 1 23 34 461 63 45 0.40 0.60 322640 150635 0.00 0.00 0.00 0.00 0.00 4.80 9.60 37.00 42.20 1.6 6805 1842576
+1 74 1 1 24 8 6091 495 274 4.20 4.20 565155 81709 14.60 22.80 34.80 47.60 9.60 27.40 46.60 188.00 341.00 4.8 238 1461266
+1 78 1 1 21 4 5347 535 434 3.40 8.80 533236 228358 0.00 0.00 0.00 0.00 0.00 1.80 2.20 437.80 367.00 6.0 2354 1645154
+1 82 1 1 2 0 814 64 74 2.40 3.00 288360 356713 41.80 78.60 78.60 0.00 0.00 1.40 1.40 186.40 194.40 2.0 370 2161779
+1 92 1 1 1 1 1535 69 62 0.20 0.20 10996 26527 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.60 16.80 1.2 7709 1871584
+1 87 1 1 3 1 447 45 37 1.80 1.80 142564 25634 6.20 6.20 6.20 0.00 0.40 2.80 4.40 144.00 137.40 2.6 149 1783752
+1 94 1 1 6 5 942 128 67 0.80 2.20 157604 131146 0.00 0.00 0.00 0.00 0.00 0.00 0.00 64.40 74.80 4.4 2835 1583784
+1 76 1 1 24 1 3656 306 243 4.00 6.40 272195 70513 0.80 0.80 2.40 9.60 1.20 14.60 39.20 242.00 348.20 9.0 310 1301122
+1 86 1 1 3 0 2205 324 246 2.40 0.60 277121 85851 0.00 0.00 0.00 0.00 0.00 9.40 9.40 122.80 224.60 4.0 741 972250
+1 61 1 1 19 5 5535 739 654 11.20 21.60 602850 387484 0.40 0.80 0.80 0.00 1.40 1.20 1.40 565.80 814.00 5.0 421 1010981
+1 69 1 1 12 2 3078 433 156 7.78 7.98 193588 31408 8.18 14.37 50.50 120.56 4.99 45.91 52.89 281.84 664.47 1.6 161 995554
+1 75 1 1 79 99 5994 583 323 2.20 4.19 202576 21233 0.00 0.00 0.00 0.00 3.39 1.20 2.20 193.01 378.44 5.4 752 1527609
+1 92 1 1 12 3 1615 168 101 1.40 1.60 140349 81304 0.60 0.60 0.60 0.00 0.00 0.20 0.20 160.00 165.60 2.4 362 1530742
+1 94 1 1 2 1 1425 74 58 0.40 0.60 203335 53824 0.00 0.00 0.00 0.00 0.00 4.20 8.40 34.60 40.60 1.4 5792 1832846
+1 87 1 1 14 6 2795 232 144 3.00 3.80 103958 65649 12.40 17.00 15.20 0.00 3.20 5.40 5.40 142.40 229.60 1.0 171 993523
+1 88 1 1 45 51 3855 184 200 1.80 1.80 226375 171511 0.00 0.00 0.00 0.00 0.00 1.00 2.00 101.40 141.40 4.8 1533 1640438
+1 0 1 1 10 5 2287 404 193 1.00 2.20 608764 628562 4.60 7.80 10.60 6.80 2.20 1.20 1.80 59.60 89.00 471 92 8
+1 57 1 1 755 207 9934 2396 1645 7.40 3.40 1494946 1312695 11.80 134.40 140.20 31.80 0.20 16.00 29.00 363.00 649.80 6.8 151 1307638
+1 87 1 1 5 1 2140 290 228 1.00 0.80 48362 513735 0.00 0.00 0.00 0.00 0.00 4.60 5.00 48.40 132.00 1.6 905 1034624
+1 84 1 1 3 0 1639 113 163 0.40 1.20 433863 436736 1.00 4.01 24.25 57.92 0.00 56.31 108.42 46.29 83.97 2.2 436 976228
+1 89 1 1 3 0 958 93 35 0.80 1.20 144354 8695 2.20 5.01 9.62 12.63 0.00 0.80 0.80 76.75 84.37 2.0 140 1744762
+1 97 1 1 1 1 190 37 19 0.20 0.20 244154 224365 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.6 3659 1819845
+1 90 1 1 35 17 3406 251 176 1.20 1.60 300935 29767 0.20 0.20 0.20 0.00 1.00 6.60 7.60 107.60 153.80 1.0 517 1014586
+1 95 1 1 1 0 939 94 91 0.20 0.20 14208 21796 0.00 0.00 0.00 0.00 0.00 0.60 0.80 18.56 19.56 5.8 375 1054422
+1 86 1 1 45 60 2732 266 143 1.00 4.21 978675 58322 1.80 6.81 21.84 30.66 0.40 3.81 4.21 44.89 169.94 3.4 131 1082503
+1 83 1 1 10 0 2394 403 358 3.60 2.40 279300 162864 13.60 23.80 38.40 89.00 0.40 12.20 17.60 154.80 328.20 1.2 224 1009920
+1 76 1 1 8 1 2004 174 114 6.40 21.00 179671 17740 4.40 12.60 30.40 54.20 1.20 22.60 39.20 226.60 443.40 1.5 157 1103323
+1 91 1 1 11 1 1554 140 128 1.40 1.40 167484 79731 0.00 0.00 0.00 0.00 0.00 4.60 6.60 106.20 137.40 1.5 456 1074590
+1 65 1 1 48 30 4032 470 330 6.00 2.60 655028 68781 0.00 0.00 0.00 0.00 0.00 9.20 13.00 323.00 718.00 7.6 8067 1368011
+1 91 1 1 0 0 2706 195 142 0.20 0.20 21387 27513 0.40 0.40 1.20 2.40 0.00 2.00 2.00 20.40 118.20 1.3 137 1050074
+1 89 1 1 2 0 2186 281 120 0.80 1.00 169234 41731 1.80 7.00 11.00 10.20 1.00 8.40 14.60 66.20 120.80 1.5 188 1127333
+1 77 1 1 19 0 3154 302 120 6.00 5.60 231905 45438 2.00 28.60 68.80 204.00 0.00 15.80 18.80 353.00 505.00 1.7 135 1054933
+1 95 1 1 11 10 971 75 56 0.40 1.80 16086 19014 0.00 0.00 0.00 0.00 0.00 1.40 2.00 23.80 63.80 1.7 1753 1081851
+1 88 1 1 10 10 3924 213 166 0.40 0.40 15944 29018 2.99 7.39 14.17 28.54 0.40 2.40 2.40 37.92 78.04 1.0 213 978721
+1 90 1 1 1 0 3197 463 320 0.20 0.20 11613 98812 0.00 0.00 0.00 0.00 0.60 0.00 0.00 15.80 89.60 1.5 441 1070038
+1 86 1 1 3 0 3562 228 151 1.20 1.80 453897 79788 0.00 0.00 0.00 0.00 0.00 5.80 9.60 107.40 173.00 3.4 1127 1044126
+1 69 1 1 21 1 4721 566 460 7.20 2.40 473996 89664 0.00 0.00 0.00 0.00 0.00 14.00 22.60 378.80 610.60 6.4 857 1529090
+1 93 1 1 1 0 1674 110 78 0.60 0.60 17273 50639 0.80 1.20 1.20 0.00 0.60 1.00 1.00 45.69 46.29 1.3 180 1129784
+1 88 1 1 7 3 4982 171 104 1.00 2.79 255423 61928 0.00 0.00 0.00 0.00 0.00 0.60 0.60 70.06 86.43 2.4 3027 1644635
+1 89 1 1 1 0 5063 225 210 0.20 0.20 23730 223135 0.00 0.00 0.00 0.00 0.00 1.60 1.60 26.60 33.60 2.6 451 1387595
+1 76 1 1 29 17 3626 229 331 2.40 1.80 95892 649135 8.40 27.40 42.60 72.00 1.40 21.80 25.80 123.00 306.80 1.0 252 999570
+1 88 1 1 33 43 2829 155 109 3.01 3.21 105461 36984 0.80 0.80 11.62 23.65 0.00 3.01 3.61 123.45 239.48 2.0 194 1005643
+1 81 1 1 9 0 4534 497 255 2.20 2.99 103874 29816 0.00 0.00 0.00 0.00 0.00 2.40 2.79 183.43 302.20 5.0 11015 1380610
+1 98 1 1 22 32 192 22 22 0.20 0.20 527 6310 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.63 16.83 1.0 432 1760834
+1 96 1 1 1 0 3108 216 127 0.20 0.20 298303 209120 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.40 32.00 3.2 3341 1345885
+1 94 1 1 1 0 944 110 77 0.40 0.20 8785 20711 0.00 0.00 0.00 0.00 0.00 3.20 3.60 16.80 26.00 1.0 778 1020872
+1 75 1 1 7 0 3770 362 194 3.00 6.60 505328 216868 20.20 49.40 96.00 136.20 19.80 33.20 42.60 233.60 353.00 1.8 139 983210
+1 94 1 1 1 0 956 173 86 1.00 0.60 469212 30623 2.60 6.40 20.00 34.80 0.00 17.80 25.20 76.20 79.80 3.6 143 1704136
+1 99 1 1 2 1 158 9 10 0.20 0.20 13646 4979 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.60 16.80 1.2 8577 1865565
+1 90 1 1 1 0 2732 185 168 0.20 0.20 23269 21040 2.40 17.96 53.49 97.41 0.20 72.26 74.25 36.93 102.99 2.0 159 1097503
+1 91 1 1 1 0 2856 150 157 0.60 0.60 10376 69707 0.00 0.00 0.00 0.00 0.00 0.20 0.20 48.40 64.20 1.7 731 1062061
+1 76 1 1 18 1 3550 218 152 8.20 21.00 59077 67661 2.60 3.00 3.00 0.00 1.20 7.00 7.00 331.40 556.20 1.3 179 1091533
+1 81 1 1 1 0 1430 161 174 0.60 1.80 362978 364675 37.47 72.95 49.90 0.00 0.00 7.82 11.42 39.68 84.17 1.0 220 1117581
+1 79 1 1 11 0 3684 499 458 4.40 2.80 224737 103468 2.40 3.60 3.40 0.00 1.60 10.40 10.60 212.40 384.60 1.5 239 1087352
+1 78 1 1 32 23 3136 277 237 7.80 3.80 198001 33552 10.40 41.20 86.40 170.60 4.00 1.80 6.40 340.60 595.20 1.0 164 1075589
+1 97 1 1 15 23 542 21 27 0.20 0.20 1274 6512 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.03 16.83 1.2 6306 1861603
+1 94 1 1 9 6 1841 57 45 0.40 0.40 37270 14071 0.00 0.00 0.00 0.00 0.00 3.60 6.60 26.40 107.80 3.2 8055 1403126
+1 88 1 1 4 2 3107 270 198 1.60 1.80 49962 60719 3.40 3.60 13.80 16.60 1.20 13.60 14.20 91.40 220.60 5.0 156 1020181
+1 87 1 1 5 2 3810 254 229 1.20 1.40 176156 250947 0.00 0.00 0.00 0.00 0.00 9.60 17.80 82.60 155.40 3.6 700 1386723
+1 74 1 1 191 210 3205 223 186 1.00 1.00 286727 337862 11.22 17.23 91.18 147.09 1.80 33.67 36.87 111.42 412.63 1.5 109 1002637
+1 84 1 1 2 0 2130 471 366 1.40 1.80 422662 131321 4.40 4.60 4.60 0.00 0.20 8.40 16.80 106.40 124.20 2.8 292 1696270
+1 80 1 1 20 14 3720 355 192 1.80 1.20 425236 398844 3.00 9.80 39.60 86.80 6.20 2.00 2.00 94.20 298.00 2.4 145 1038234
+1 98 1 1 0 0 156 9 14 0.20 0.20 1046 10826 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.00 1.8 8524 1866256
+1 94 1 1 39 52 1084 54 58 0.60 2.00 112426 38263 0.00 0.00 0.00 0.00 0.00 5.61 10.62 65.13 78.16 1.3 682 1042923
+1 69 1 1 26 0 3761 322 134 6.39 17.17 1046646 36322 0.00 0.00 0.00 0.00 0.60 52.50 91.42 225.75 465.27 2.7 434 1098175
+1 98 1 1 0 0 148 10 15 0.20 0.20 417 1941 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6460 1871616
+1 94 1 1 4 0 429 21 27 1.80 4.20 27962 24559 0.00 0.00 0.00 0.00 0.00 0.20 0.20 120.80 136.20 1.4 8430 1882008
+1 84 1 1 6 5 2212 181 150 0.60 0.60 347038 193991 2.00 3.79 11.58 22.16 1.20 31.94 57.49 43.71 150.90 1.8 482 1003155
+1 88 1 1 235 253 2173 406 183 1.20 0.40 1050030 39200 6.60 7.80 13.20 12.40 1.00 14.40 15.00 64.20 132.60 2.0 143 975350
+1 90 1 1 4 3 2807 324 177 1.20 2.81 31280 26717 5.21 19.04 24.45 56.51 1.60 1.20 1.20 128.86 171.74 2.6 138 1060800
+1 82 1 1 26 1 2050 145 111 4.80 4.80 39860 75624 5.40 18.00 27.20 62.40 0.40 12.00 19.40 229.20 432.20 1.7 160 1063896
+1 95 1 1 0 0 2367 97 139 0.20 0.20 31548 37969 0.00 0.00 0.00 0.00 0.00 0.40 0.60 13.20 17.40 2.0 838 1720995
+1 96 1 1 99 37 575 176 131 0.20 0.20 114644 105899 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 2199 1763296
+1 92 1 1 3 1 2058 162 105 0.60 2.00 204184 27750 0.00 0.00 0.00 0.00 0.00 0.80 11.20 47.60 66.60 1.7 2011 1098920
+1 94 1 1 5 5 2630 94 74 0.20 0.20 7567 37410 3.80 5.60 4.60 0.00 1.80 2.00 2.00 15.80 67.80 1.0 274 1016989
+1 95 1 1 2 1 837 42 50 0.40 0.60 3692 32235 0.00 0.00 0.00 0.00 0.20 1.00 1.00 32.00 179.80 1.5 771 1032677
+1 92 1 1 3 1 2002 144 91 1.80 1.60 31286 18379 0.00 0.00 0.00 0.00 0.00 0.20 0.20 106.80 158.20 3.0 1495 1717507
+1 95 1 1 19 27 370 81 27 0.20 0.20 431388 10433 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 19.00 1.6 7241 1863912
+1 0 1 1 5 4 809 72 62 0.20 0.20 5228 19660 1.60 2.00 3.61 12.02 0.00 4.61 4.61 15.63 53.51 142 96 4
+1 71 1 1 38 4 3790 289 156 6.19 18.76 305886 115692 4.39 23.15 52.10 87.03 2.20 20.96 32.73 204.59 422.36 4.0 139 1089752
+1 60 1 1 15 2 4106 204 134 12.40 36.20 172102 52177 8.60 12.40 32.80 53.80 4.20 13.60 15.00 397.80 798.20 1.4 134 1081658
+1 93 1 1 2 0 1196 109 103 0.40 2.20 11692 45527 7.20 8.00 8.00 0.00 0.60 9.80 11.80 19.40 38.40 3.8 215 1055501
+1 94 1 1 4 1 706 73 53 0.80 0.20 129808 24619 0.40 0.60 1.40 4.40 0.00 8.60 8.60 40.00 47.80 2.2 238 1020434
+1 92 1 1 25 13 3659 140 148 0.40 0.40 165106 199521 0.00 0.00 0.00 0.00 0.00 4.00 6.80 43.20 48.00 2.6 3172 1637477
+1 76 1 1 4 0 655 78 98 2.60 3.40 272364 232714 0.00 0.00 0.00 0.00 0.00 30.40 58.60 187.60 198.60 2.4 2060 1795691
+1 87 1 1 13 11 3836 306 145 0.80 0.60 444375 52421 0.00 0.00 0.00 0.00 0.00 22.00 25.80 55.00 91.60 3.2 2432 1509254
+1 92 1 1 25 24 1839 234 175 0.40 0.40 102099 31838 0.00 0.00 0.00 0.00 0.00 5.80 5.80 36.00 92.40 2.0 522 985510
+1 98 1 1 0 0 238 38 11 0.20 0.20 243290 9658 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.4 7717 1882171
+1 88 1 1 2 0 1722 132 77 1.40 1.40 175711 32362 0.00 0.00 0.00 0.00 13.23 2.40 3.41 138.48 190.38 1.0 776 1068697
+1 91 1 1 1 0 4183 274 195 0.20 0.20 9067 51436 0.00 0.00 0.00 0.00 0.20 0.00 0.00 17.53 19.92 2.2 268 1063124
+1 95 1 1 3 1 575 81 44 1.80 1.60 59646 5592 0.00 0.00 0.00 0.00 0.00 0.20 0.20 106.40 160.60 2.4 593 1710902
+1 93 1 1 13 6 1643 117 171 1.20 2.80 357570 269732 0.00 0.00 0.00 0.00 0.00 3.20 6.00 128.20 121.80 4.0 2537 1551914
+1 96 1 1 0 0 810 45 21 0.40 0.40 108170 5654 0.00 0.00 0.00 0.00 0.00 0.00 0.00 74.00 76.00 1.4 5136 1830157
+1 70 1 1 7 2 6741 458 380 2.00 2.20 129326 509497 17.37 57.29 93.21 179.84 0.80 68.06 79.84 147.11 342.32 1.0 267 986973
+1 84 1 1 8 1 2451 248 223 5.40 3.40 87278 58133 0.00 0.00 0.00 0.00 0.00 0.40 0.80 243.40 361.60 4.2 858 1541506
+1 95 1 1 6 2 1080 164 85 0.40 0.60 135663 43467 4.39 7.78 6.19 0.00 1.20 1.20 1.20 45.31 102.99 3.4 317 1038767
+1 97 1 1 1 0 226 12 25 0.40 0.40 441 13364 0.00 0.00 0.00 0.00 0.00 0.00 0.00 36.40 33.40 1.0 7645 1869835
+1 63 1 1 26 4 5240 304 299 3.59 4.79 523148 603192 4.19 7.39 23.55 44.51 0.40 62.48 112.38 237.52 429.94 5.0 769 977341
+1 86 1 1 45 59 2875 238 128 1.60 6.40 184912 159603 0.00 0.00 0.00 0.00 0.40 13.00 14.40 167.00 375.80 3.2 890 1545994
+1 96 1 1 21 13 1258 92 64 0.40 0.40 27604 35912 0.00 0.00 0.00 0.00 0.00 0.20 0.20 31.00 44.20 2.2 1143 1714018
+1 74 1 1 18 13 4475 699 425 4.20 1.20 557374 557281 0.00 0.00 0.00 0.00 0.00 6.20 8.80 207.40 373.20 1.5 567 1040643
+1 97 1 1 1 0 225 14 22 0.20 0.20 5448 67049 0.00 0.00 0.00 0.00 0.00 0.00 0.00 23.55 19.36 1.0 6935 1855302
+1 90 1 1 12 11 1377 128 97 0.60 0.60 51717 23905 11.40 18.40 49.00 129.00 3.00 2.20 2.40 109.20 138.80 1.0 189 1128397
+1 97 1 1 1 1 197 14 30 0.20 0.20 6990 11710 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6136 1856768
+1 87 1 1 1 0 3517 212 133 0.20 0.20 46686 203317 12.57 27.35 30.94 15.37 0.60 1.40 1.80 23.75 57.88 2.0 448 1008695
+1 96 1 1 0 0 230 34 24 0.20 0.20 110524 36306 0.00 0.00 0.00 0.00 0.00 5.00 9.80 14.20 20.80 1.0 5744 1863488
+1 95 1 1 3 2 933 66 74 0.40 0.40 5198 20851 0.00 0.00 0.00 0.00 0.00 1.40 1.40 35.00 53.00 1.5 3042 1013574
+1 95 1 1 0 0 2513 121 69 0.20 0.20 34212 26923 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 16.80 1.4 414 1749112
+1 93 1 1 2 0 813 117 113 1.80 0.60 59903 24550 0.60 2.20 7.20 14.00 0.00 0.00 0.00 96.00 135.60 1.6 179 1761718
+1 96 1 1 1 0 520 112 42 0.20 0.40 168661 164328 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.00 28.60 3.0 929 1749128
+1 87 1 1 10 0 1115 103 90 2.20 5.39 48365 26347 6.19 22.55 71.26 205.39 0.00 75.85 75.85 102.00 255.89 4.2 132 1087315
+1 92 1 1 1 0 1176 123 119 0.60 0.60 94557 174600 0.00 0.00 0.00 0.00 0.00 1.20 1.40 56.89 93.41 2.6 866 1015700
+1 97 1 1 14 20 1384 40 30 0.20 0.20 97418 10952 0.00 0.00 0.00 0.00 0.00 0.00 0.00 22.40 17.20 1.2 8234 1863248
+1 93 1 1 5 4 2157 164 139 0.60 0.40 155928 21930 4.21 5.41 5.21 0.00 2.61 4.41 4.61 39.48 87.37 2.0 308 1018546
+1 93 1 1 14 12 1038 214 87 0.80 0.40 229373 236383 0.00 0.00 0.00 0.00 0.00 0.00 0.00 45.60 64.40 2.6 1854 1759920
+1 93 1 1 37 52 2153 158 62 0.40 0.60 154124 29953 0.00 0.00 0.00 0.00 0.00 4.00 7.20 33.80 52.60 2.5 494 981554
+1 96 1 1 3 3 449 76 64 0.40 0.40 1633 12751 0.00 0.00 0.00 0.00 0.00 0.00 0.00 34.40 39.80 2.0 690 1722080
+1 73 1 1 2 1 3274 245 176 0.40 0.80 303552 102946 0.00 0.00 0.00 0.00 0.00 11.00 17.20 40.00 96.80 2.8 1161 1043141
+1 90 1 1 3 1 2573 275 175 0.20 0.20 271616 121425 3.80 7.40 8.20 1.60 5.60 5.00 10.60 61.00 94.40 1.5 178 1052728
+1 72 1 1 8 0 5699 646 508 7.60 2.00 409346 37592 2.80 7.80 15.40 17.80 9.20 16.00 24.60 375.40 621.20 1.4 191 1006571
+1 84 1 1 2 0 439 48 37 2.20 2.20 63971 29152 0.00 0.00 0.00 0.00 0.00 2.40 3.60 186.00 171.00 1.0 889 1791464
+1 89 1 1 48 61 1313 149 53 0.80 0.80 800155 47478 0.00 0.00 0.00 0.00 0.00 1.60 1.80 67.40 66.60 2.8 579 1513722
+1 98 1 1 1 1 203 14 37 0.20 0.20 8286 18401 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 5309 1858272
+1 76 1 1 14 4 4556 730 385 3.80 1.40 328442 162971 0.00 0.00 0.00 0.00 0.00 1.60 2.60 195.00 311.80 4.8 2816 1602554
+1 82 1 1 18 8 4272 141 134 2.40 8.40 86263 110091 0.00 0.00 0.00 0.00 0.00 0.40 0.60 196.20 216.80 3.0 1582 1638861
+1 93 1 1 1 0 3016 144 102 0.20 0.20 305394 11274 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.00 17.00 2.8 6120 1729688
+1 81 1 1 81 77 1443 123 81 2.40 3.41 204489 20241 0.00 0.00 0.00 0.00 0.00 17.64 28.86 215.83 403.41 1.7 1208 965715
+1 83 1 1 2 1 3036 172 101 0.60 0.80 213468 125979 6.19 11.38 11.38 0.00 3.19 18.56 29.14 52.50 73.45 1.0 332 1125341
+1 76 1 1 15 2 3435 213 230 3.00 2.00 193802 120473 0.00 0.00 0.00 0.00 0.20 5.20 8.00 225.80 261.80 4.6 655 1503752
+1 82 1 1 13 11 3085 406 273 1.40 4.20 342384 133641 15.40 41.00 55.80 44.80 4.00 5.80 7.40 124.20 213.40 1.0 193 1101050
+1 94 1 1 26 37 1000 205 108 0.20 0.20 9145 42305 4.00 4.60 5.00 1.20 1.20 2.20 2.20 17.00 52.60 1.0 140 1057504
+1 74 1 1 12 1 3494 331 375 3.21 1.80 118999 498678 0.00 0.00 0.00 0.00 0.40 20.24 20.64 170.14 334.87 2.8 687 1019367
+1 91 1 1 1 0 2659 171 139 0.40 0.40 15534 19898 0.00 0.00 0.00 0.00 0.00 35.40 35.40 34.60 96.00 2.6 1724 1409158
+1 97 1 1 1 1 1096 78 29 0.20 0.20 29396 6396 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 4738 1826728
+1 79 1 1 19 5 4770 1638 1563 0.80 2.40 157093 36008 11.98 30.94 62.87 155.29 1.20 7.98 14.37 88.02 173.25 1.0 138 986815
+1 98 1 1 1 1 192 16 36 0.20 0.20 14470 26804 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 8360 1864653
+1 83 1 1 16 2 6188 312 195 5.00 3.80 323403 43465 0.00 0.00 0.00 0.00 0.40 0.60 0.60 257.00 382.60 3.8 3280 1550174
+1 85 1 1 3 2 3446 307 210 0.80 2.40 534055 75495 1.80 3.40 3.40 0.00 3.60 2.00 2.20 71.60 196.60 2.5 351 985938
+1 97 1 1 17 23 277 46 22 0.20 0.20 263599 11435 0.00 0.00 0.00 0.00 0.00 0.20 0.20 20.80 19.20 1.6 7170 1873640
+1 93 1 1 2 1 1373 91 77 0.20 0.20 184464 37232 0.00 0.00 0.00 0.00 1.00 0.20 0.20 15.60 17.00 2.6 1157 1718800
+1 79 1 1 24 4 2059 299 184 2.20 2.60 576941 262582 16.00 28.60 28.20 0.00 1.60 36.60 50.80 140.60 355.40 4.8 416 1024258
+1 77 1 1 28 0 2916 194 134 6.41 19.44 76359 34803 2.00 6.01 6.81 12.22 1.40 8.42 10.42 239.48 452.30 4.2 158 1109499
+1 72 1 1 12 5 3886 545 309 5.00 6.20 1517447 1023435 0.00 0.00 0.00 0.00 202.20 2.80 4.60 238.80 704.60 3.2 3636 1038083
+1 69 1 1 246 111 2597 224 193 4.00 6.80 441256 180505 14.00 37.80 60.00 142.20 3.00 49.40 73.00 258.40 495.20 2.0 221 1037286
+1 90 1 1 31 24 1710 130 108 1.00 1.20 232573 221977 17.76 25.15 22.95 0.00 11.58 3.79 6.19 65.67 90.62 4.2 262 1536589
+1 92 1 1 2 0 3122 276 175 0.40 0.40 42658 49244 0.00 0.00 0.00 0.00 0.40 0.00 0.00 33.00 38.00 2.0 355 1077730
+1 90 1 1 3 1 403 45 13 2.20 2.20 109630 25486 0.00 0.00 0.00 0.00 0.00 3.61 6.21 213.83 181.76 1.4 11474 1885897
+1 84 1 1 3 0 5187 306 181 0.60 0.80 294902 58527 0.40 1.60 12.80 19.00 0.00 16.80 30.20 75.80 160.20 1.8 359 1079656
+1 96 1 1 2 0 2211 164 168 0.40 0.20 63322 120460 0.00 0.00 0.00 0.00 0.00 0.20 0.20 35.80 30.20 2.0 2880 1652454
+1 95 1 1 1 0 813 89 88 0.60 0.60 5816 22412 0.20 0.40 0.40 0.00 0.00 2.00 2.20 59.60 89.40 2.0 178 973330
+1 87 1 1 4 1 1949 222 91 1.19 3.98 997168 28599 6.96 7.75 9.54 12.92 0.99 5.17 5.96 76.74 159.44 1.5 235 1082155
+1 81 1 1 22 10 3834 198 139 1.80 6.79 108456 51500 0.00 0.00 0.00 0.00 0.00 7.58 10.78 124.35 146.31 5.2 10047 1370033
+1 83 1 1 62 77 4386 399 275 3.80 1.60 151336 30028 0.00 0.00 0.00 0.00 0.00 8.00 10.40 199.40 334.40 4.6 860 1395843
+1 95 1 1 19 28 454 198 62 0.20 0.20 328739 239199 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 40.20 2.2 1537 1746402
+1 67 1 1 93 88 2902 533 254 6.20 5.00 283206 19777 0.00 0.00 0.00 0.00 0.00 28.00 42.40 451.80 766.60 4.6 3150 1534064
+1 92 1 1 82 94 1507 120 76 0.60 0.80 13668 20814 4.00 4.80 5.20 3.80 1.00 6.20 6.20 60.20 149.60 1.0 151 1026094
+1 90 1 1 1 0 1095 196 94 1.00 1.60 323860 227922 0.00 0.00 0.00 0.00 0.00 0.20 0.20 68.40 131.60 4.4 1246 1601501
+1 90 1 1 7 1 1879 176 135 1.60 3.01 23947 64669 0.00 0.00 0.00 0.00 0.00 10.62 13.43 85.97 146.49 1.2 583 1110095
+1 89 1 1 74 92 2780 280 164 0.80 0.80 398730 89072 8.00 14.60 10.20 0.00 1.40 5.40 10.00 50.80 94.60 4.8 305 1539635
+1 93 1 1 11 1 2683 199 184 0.40 0.40 177008 159682 0.00 0.00 0.00 0.00 0.00 0.40 0.40 33.20 61.40 3.2 889 1642858
+1 96 1 1 1 1 331 128 41 0.20 0.20 194221 188868 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.8 5283 1825419
+1 71 1 1 10 0 5002 450 228 5.79 5.99 98474 85220 6.99 11.98 11.78 0.00 1.80 43.91 49.10 221.56 504.99 1.8 335 994360
+1 85 1 1 188 213 1992 211 92 1.20 0.80 143039 20785 0.00 0.00 0.00 0.00 0.00 13.80 28.80 69.40 136.40 2.2 2170 1763142
+1 95 1 1 2 1 1630 121 98 0.20 0.20 104391 31531 8.80 17.20 54.80 121.00 0.00 61.40 61.80 55.00 111.40 1.0 125 1089237
+1 98 1 1 0 0 156 14 17 0.20 0.20 437 3379 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 8497 1866062
+1 97 1 1 1 1 1334 92 56 0.40 0.20 79074 32024 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.76 19.76 1.4 566 1736932
+1 92 1 1 0 0 2047 168 804 0.20 0.20 38632 107808 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 36.00 2.2 827 1704214
+1 53 1 1 33 7 6062 617 627 8.78 9.38 570314 337127 12.18 66.27 191.62 441.12 3.19 52.50 89.02 482.63 761.88 7.4 115 1539693
+1 75 1 1 4 3 4571 441 362 0.60 1.99 469603 479822 0.99 1.99 1.99 0.00 0.00 48.91 90.66 63.22 162.82 2.0 586 1012072
+1 94 1 1 4 0 595 75 63 2.40 0.80 43202 7944 0.00 0.00 0.00 0.00 0.00 0.00 0.00 121.60 173.60 1.0 7942 1833843
+1 92 1 1 4 0 1948 136 86 0.60 1.00 85252 19664 4.00 7.40 19.60 58.80 0.40 9.20 14.40 51.40 81.20 1.0 129 1020147
+1 94 1 1 0 0 2386 146 158 0.20 0.20 17498 29550 1.20 1.20 1.20 0.00 0.60 1.20 1.20 15.60 18.80 2.4 237 1708638
+1 88 1 1 3 0 2883 310 228 0.80 0.80 75734 43575 5.99 6.19 6.19 0.00 0.00 1.40 1.60 66.67 109.38 1.4 169 1064008
+1 93 1 1 29 43 2026 112 101 0.40 1.80 106168 95221 0.00 0.00 0.00 0.00 0.00 0.00 0.00 64.40 47.20 2.4 2107 1550110
+1 91 1 1 4 0 1681 180 162 2.60 0.80 135030 50758 0.00 0.00 0.00 0.00 0.00 0.00 0.00 132.80 186.00 2.2 2067 1719888
+1 83 1 1 33 3 2603 272 194 4.20 4.80 753295 85799 6.20 29.40 46.20 116.40 1.60 14.60 20.80 239.60 413.60 1.0 192 1069163
+1 88 1 1 1 0 2286 100 65 0.80 0.80 97449 9632 0.00 0.00 0.00 0.00 0.00 0.00 0.00 57.60 85.20 2.2 1157 1766731
+1 81 1 1 11 0 3388 355 283 4.20 2.80 196671 81600 1.20 1.20 1.20 0.00 0.00 2.80 3.40 206.00 329.00 1.0 228 1088998
+1 95 1 1 1 0 2154 78 121 0.20 0.20 8958 19002 0.00 0.00 0.00 0.00 0.00 1.00 2.00 15.60 16.80 2.2 750 1720262
+1 85 1 1 10 6 2410 156 137 2.60 4.80 174801 46740 0.00 0.00 0.00 0.00 0.20 4.60 4.80 160.60 350.40 1.6 747 1117078
+1 96 1 1 2 0 522 36 33 0.80 0.60 3011 14854 2.40 4.79 8.78 10.38 0.00 11.58 11.58 43.11 85.23 1.0 177 1066296
+1 87 1 1 3 1 4153 313 158 0.80 1.20 108978 27688 2.60 3.40 3.40 0.00 8.40 8.20 10.40 73.40 147.00 1.4 212 1011496
+1 83 1 1 59 77 3690 665 267 1.00 0.60 89635 108337 5.60 14.60 22.80 26.80 1.20 12.60 24.00 59.80 98.80 1.6 212 1132274
+1 91 1 1 14 6 1493 167 88 2.00 2.40 145001 61683 0.00 0.00 0.00 0.00 0.00 1.40 1.80 115.40 218.60 5.2 2137 1554117
+1 84 1 1 2 0 1560 111 143 0.80 1.20 143877 323124 4.80 9.80 14.40 15.60 0.20 14.60 29.20 54.80 94.20 2.8 238 1766866
+1 92 1 1 28 40 943 123 228 0.20 0.20 7320 618319 0.00 0.00 0.00 0.00 0.00 2.40 2.40 15.80 35.40 1.0 624 960032
+1 83 1 1 2 0 462 51 35 2.00 2.60 61049 24273 0.60 0.60 0.60 0.00 0.00 0.80 1.20 169.40 162.20 1.0 355 1813288
+1 89 1 1 1 0 3935 183 202 0.40 0.40 68647 312570 0.00 0.00 0.00 0.00 1.20 4.00 4.20 24.80 97.20 2.6 479 1387520
+1 87 1 1 2 0 1382 145 116 2.40 2.79 359501 205647 0.00 0.00 0.00 0.00 0.00 6.99 10.98 105.99 147.90 2.4 6185 1839187
+1 0 1 1 21 18 1219 502 174 0.20 0.20 780529 685012 0.00 0.00 0.00 0.00 0.00 3.80 3.80 15.20 33.20 643 94 6
+1 93 1 1 6 2 1244 95 91 1.20 2.00 96987 79947 3.60 4.40 4.40 0.00 0.00 0.40 0.40 71.80 99.00 2.2 220 1537019
+1 86 1 1 14 7 1943 90 95 1.60 3.20 19687 11116 0.00 0.00 0.00 0.00 0.20 29.60 47.80 103.40 294.00 2.8 777 1398755
+1 95 1 1 34 48 733 60 48 0.60 1.00 3466 18820 0.00 0.00 0.00 0.00 0.00 8.80 8.80 42.60 96.00 1.0 920 1036125
+1 64 1 1 11 2 4116 573 357 8.18 23.35 112691 58567 1.80 2.20 2.20 0.00 1.00 32.14 33.53 284.63 568.06 1.5 256 1075701
+1 0 1 1 14 1 1939 143 91 2.59 10.18 373972 26795 0.00 0.00 0.00 0.00 0.00 5.79 5.99 162.08 255.29 560 88 11
+1 96 1 1 4 1 584 59 25 0.60 0.80 141156 13629 0.00 0.00 0.00 0.00 0.00 0.00 0.00 57.60 80.00 2.4 6287 1725046
+1 92 1 1 0 0 2355 228 121 0.20 0.20 29610 25019 2.00 2.00 2.00 0.00 0.40 2.60 4.60 15.60 28.20 1.0 183 1136872
+1 99 1 1 0 0 153 11 22 0.20 0.20 3693 1972 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.60 16.80 1.0 6477 1871658
+1 86 1 1 78 89 2986 361 79 1.39 0.60 239193 48069 0.99 1.39 1.39 0.99 0.80 1.99 2.39 81.11 114.71 6.2 277 1283260
+1 86 1 1 43 55 2386 247 221 3.39 1.20 99913 23227 2.20 8.78 14.77 27.74 0.40 18.16 18.16 179.84 289.42 1.0 141 1064891
+1 0 1 1 42 27 1230 173 143 2.60 2.60 215978 42779 0.00 0.00 0.00 0.00 0.00 9.20 32.00 158.00 381.80 1496 87 13
+1 86 1 1 2 1 3058 263 209 0.40 1.80 70206 261401 11.42 23.05 44.69 93.59 1.40 37.68 40.48 22.65 207.21 1.0 128 1000492
+1 75 1 1 9 0 2215 185 167 7.62 20.04 333381 19480 0.60 0.60 0.60 0.00 0.20 6.21 6.41 305.41 527.66 2.7 214 1090602
+1 93 1 1 30 43 1061 114 132 0.20 0.20 20541 118239 0.40 0.40 0.40 0.00 0.00 0.60 0.80 21.00 23.60 2.2 255 1523914
+1 97 1 1 1 1 332 58 17 0.20 0.20 343314 5858 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.97 1.2 7369 1861876
+1 0 1 1 70 75 1764 290 152 1.80 3.00 363507 53398 2.60 13.60 176.80 322.20 0.40 13.00 22.80 166.80 407.40 130 82 18
+1 90 1 1 3 0 3988 220 202 0.40 0.80 40409 127057 0.00 0.00 0.00 0.00 0.00 2.00 3.40 42.80 41.20 3.2 2760 1647885
+1 92 1 1 70 37 3511 278 184 0.60 1.80 136622 69549 3.40 9.20 9.20 0.00 0.20 2.60 3.00 37.40 124.20 2.8 305 1339018
+1 84 1 1 5 1 3972 199 148 3.60 6.60 97157 48932 4.00 7.20 20.60 35.00 1.40 4.00 4.60 229.60 348.80 1.8 139 1013686
+1 88 1 1 9 2 1470 218 185 5.40 1.60 145547 12325 0.00 0.00 0.00 0.00 0.00 0.00 0.00 266.20 382.60 1.0 7240 1864706
+1 91 1 1 43 62 1695 155 83 0.40 0.40 82945 16982 0.00 0.00 0.00 0.00 0.00 47.00 48.00 35.00 106.20 1.0 572 1068110
+1 84 1 1 187 207 2510 354 209 2.79 1.00 1060574 29950 0.00 0.00 0.00 0.00 0.20 3.79 4.19 147.50 214.37 1.6 2526 1089847
+1 88 1 1 4 1 1040 98 46 3.00 3.20 194087 61224 0.00 0.00 0.00 0.00 0.00 2.60 4.80 213.40 232.00 2.4 6259 1853043
+1 79 1 1 30 41 1298 133 179 1.40 1.80 240956 551071 22.60 46.40 64.00 34.60 0.40 0.60 1.00 127.40 410.80 1.8 845 1723450
+1 98 1 1 1 1 201 28 20 0.20 0.20 21164 4068 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 1.2 7218 1847104
+1 93 1 1 1 0 1752 146 122 0.20 0.20 85105 109732 0.00 0.00 0.00 0.00 0.00 1.20 1.20 54.20 22.20 2.6 1045 1539776
+1 96 1 1 3 2 394 18 52 0.40 0.40 27574 144877 0.00 0.00 0.00 0.00 0.00 0.00 0.00 49.60 39.80 1.2 6887 1852704
+1 74 1 1 7 0 1921 115 117 6.40 18.40 141973 64008 8.60 20.00 29.80 54.80 5.80 20.40 25.80 229.60 466.20 1.5 155 1088210
+1 97 1 1 0 0 189 27 34 0.20 0.20 772 18709 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 18.40 1.2 1334 1761776
+1 97 1 1 1 0 362 115 67 0.20 0.20 196922 186447 0.00 0.00 0.00 0.00 0.00 2.40 4.80 15.60 19.40 3.6 741 1727502
+1 94 1 1 21 24 333 35 29 0.80 0.80 50320 9400 0.00 0.00 0.00 0.00 0.00 1.20 1.20 67.13 82.16 1.4 1803 1781719
+1 83 1 1 11 1 5032 270 152 2.60 4.00 854256 68312 1.40 1.40 1.40 0.00 0.00 2.20 2.40 199.20 288.80 2.0 273 1072720
+1 75 1 1 25 8 4319 506 448 7.20 2.00 210976 25256 2.80 2.80 2.80 0.00 0.00 4.40 4.40 346.00 540.60 2.4 293 967184
+1 91 1 1 98 113 2469 201 104 0.40 0.40 8522 33720 0.00 0.00 0.00 0.00 0.00 8.40 10.00 46.80 71.20 2.5 1184 1123517
+1 87 1 1 3 0 2384 293 225 0.60 0.60 46740 160397 6.80 11.60 11.20 0.00 0.40 1.40 2.60 62.20 54.80 1.0 311 1069066
+1 88 1 1 53 72 3728 209 185 0.60 0.60 222399 271021 0.00 0.00 0.00 0.00 0.00 6.60 7.60 40.80 102.00 4.6 1171 1327197
+1 89 1 1 11 6 1995 235 213 1.00 1.40 113578 155541 0.00 0.00 0.00 0.00 0.00 0.80 0.80 74.40 86.80 3.4 447 976970
+1 89 1 1 3 1 670 94 44 1.80 1.80 457127 136277 0.00 0.00 0.00 0.00 0.00 2.59 4.19 176.05 156.29 1.6 5286 1835205
+1 90 1 1 2 0 771 152 44 2.40 3.39 331157 62884 0.00 0.00 0.00 0.00 0.00 0.80 1.00 134.33 236.73 4.4 1150 1751431
+1 98 1 1 1 1 256 18 20 0.40 1.00 23745 11954 0.00 0.00 0.00 0.00 0.00 0.60 1.00 31.20 40.60 1.2 3719 1849424
+1 97 1 1 13 19 978 63 53 0.20 0.20 5099 18390 0.00 0.00 0.00 0.00 0.40 0.00 0.00 17.60 16.80 2.2 1040 1718776
+1 75 1 1 184 6 5040 103 93 1.80 7.00 29913 129926 6.40 16.80 26.00 33.20 3.20 45.20 45.80 141.00 162.20 2.6 168 1518035
+1 80 1 1 7 2 3513 495 107 1.20 1.60 271233 302107 0.00 0.00 0.00 0.00 0.00 0.60 0.60 96.60 111.40 2.4 567 1547306
+1 70 1 1 7 1 2886 276 136 6.20 23.00 157598 37806 3.20 3.20 3.20 0.00 1.40 20.40 21.00 370.40 587.40 1.3 309 1033933
+1 72 1 1 18 0 6014 987 691 7.21 2.81 233983 58331 1.00 1.20 8.62 11.62 0.40 3.41 4.41 375.95 572.95 1.0 229 1070730
+1 96 1 1 18 24 442 187 69 0.20 0.20 252050 247297 0.00 0.00 0.00 0.00 0.00 0.40 0.40 13.00 17.40 3.4 898 1742800
+1 76 1 1 19 3 5503 575 406 3.59 3.19 88126 77733 5.39 6.99 18.56 22.36 1.80 10.18 11.78 134.73 232.73 2.8 184 1042028
+1 63 1 1 36 3 3491 468 331 9.60 18.40 329289 34314 0.40 0.40 0.40 0.00 0.80 44.00 53.40 524.40 841.80 3.2 476 1087774
+1 92 1 1 0 0 2139 139 117 0.20 0.20 13481 28544 2.60 3.00 3.00 0.00 0.00 0.60 1.00 17.00 25.20 3.4 193 1443370
+1 58 1 1 34 11 6742 280 189 3.00 9.20 626826 453135 0.00 0.00 0.00 0.00 0.20 26.20 30.20 240.20 377.40 8.2 1366 1344714
+1 91 1 1 39 54 381 62 54 0.40 0.40 264031 51760 0.00 0.00 0.00 0.00 0.00 0.00 0.00 23.80 49.40 2.6 1531 1811552
+1 94 1 1 2 1 1600 85 136 0.20 0.20 15271 112122 1.60 1.80 1.60 0.00 0.00 4.40 5.00 15.60 31.60 2.5 331 1061296
+1 82 1 1 2 0 4283 379 392 0.40 0.40 202517 118178 0.00 0.00 0.00 0.00 0.20 9.20 14.40 28.80 89.20 3.2 1824 1708766
+1 88 1 1 2 1 2710 183 114 0.60 0.60 317726 22725 2.40 4.40 3.40 0.00 7.60 4.60 4.60 57.00 121.40 2.0 274 1086291
+1 96 1 1 0 0 200 32 31 0.20 0.20 700 15435 0.00 0.00 0.00 0.00 0.00 0.60 0.80 15.57 17.37 1.0 605 1727257
+1 0 1 1 15 6 1963 286 277 0.60 1.20 703296 539298 14.40 35.60 286.40 491.80 0.20 80.80 150.00 53.40 143.80 101 75 25
+1 89 1 1 5 4 2207 178 98 1.00 2.20 34542 25834 0.00 0.00 0.00 0.00 0.00 8.20 9.00 38.40 87.60 2.2 1111 1128755
+1 87 1 1 5 0 4247 229 136 0.60 2.00 201583 88050 3.00 3.80 3.80 0.00 0.40 5.00 8.60 77.20 128.20 2.4 186 1460765
+1 89 1 1 0 0 755 106 74 0.20 0.20 74771 37926 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.37 19.56 1.2 2104 1764972
+1 87 1 1 33 18 3104 208 139 1.40 3.00 359408 34574 0.00 0.00 0.00 0.00 0.20 14.00 17.20 107.60 291.80 4.6 7345 1377104
+1 79 1 1 7 0 1837 262 219 4.39 1.20 193979 41064 0.00 0.00 0.00 0.00 0.00 2.20 2.79 218.56 319.16 2.4 1042 1741938
+1 86 1 1 18 13 1885 203 82 1.80 2.00 1013582 37129 0.00 0.00 0.00 0.00 0.00 4.00 6.00 139.20 183.20 1.4 2501 1092259
+1 90 1 1 6 3 2822 113 92 0.80 2.59 179136 99896 13.97 20.56 20.56 0.00 11.98 10.58 19.36 61.28 91.82 2.2 264 1517261
+1 88 1 1 4 3 2809 242 129 0.60 0.60 110125 35179 4.97 9.94 14.51 21.87 1.39 6.76 6.76 51.29 111.33 2.0 222 1093338
+1 98 1 1 0 0 221 22 23 0.20 0.20 7212 12680 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.0 7447 1865839
+1 91 1 1 4 4 2369 85 136 0.20 0.20 6027 377608 2.59 3.39 3.39 0.00 2.59 0.80 1.00 16.57 23.75 2.0 326 1389325
+1 98 1 1 0 0 181 18 21 0.20 0.20 454 17694 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.23 16.83 1.2 7368 1868960
+1 55 1 1 53 0 3760 272 112 12.83 36.67 434501 32705 10.62 58.12 82.57 143.69 0.20 21.44 33.07 498.00 962.53 2.3 185 1108132
+1 77 1 1 7 4 3676 307 178 0.40 0.80 979176 51971 36.40 98.60 196.80 412.40 0.80 102.60 201.00 41.60 105.80 1.0 116 985454
+1 91 1 1 48 65 2210 116 80 0.20 0.20 110663 103760 0.00 0.00 0.00 0.00 0.00 1.60 2.79 15.57 24.55 3.2 1439 1728436
+1 87 1 1 3 0 1952 293 213 2.80 1.40 528958 65882 0.00 0.00 0.00 0.00 0.00 1.20 1.20 137.60 250.40 1.0 2345 1010205
+1 85 1 1 1 0 3246 164 99 0.40 0.60 322114 25211 5.00 5.60 29.80 55.80 0.00 21.20 40.80 39.00 108.40 1.6 174 1001443
+1 83 1 1 11 3 2515 215 140 1.40 2.80 328668 20783 0.00 0.00 0.00 0.00 0.40 2.20 5.40 85.40 230.20 4.2 1027 1122035
+1 96 1 1 1 0 810 55 68 0.20 0.20 3885 15299 0.00 0.00 0.00 0.00 0.20 1.20 1.20 15.60 39.20 2.0 378 1016666
+1 92 1 1 6 5 894 99 63 1.20 2.80 70329 34735 5.40 11.40 15.60 22.60 3.80 2.00 2.00 73.00 162.40 1.0 153 1024410
+1 58 1 1 22 1 9304 1949 1888 8.38 3.39 1605251 1523413 0.00 0.00 0.00 0.00 0.00 5.19 8.98 369.06 581.64 2.0 784 1056779
+1 94 1 1 1 0 1817 128 103 0.40 1.80 26502 27641 1.80 2.40 2.40 0.00 0.00 7.20 8.20 19.40 55.80 1.0 201 1028013
+1 97 1 1 1 1 313 21 15 0.20 0.20 7861 9902 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.57 16.77 1.0 6337 1845190
+1 94 1 1 2 1 356 40 47 0.80 0.60 17697 18709 0.00 0.00 0.00 0.00 0.00 0.00 0.00 52.80 58.00 1.0 2832 1773406
+1 67 1 1 17 4 3826 341 144 8.40 21.40 139374 49257 0.20 0.40 0.40 0.00 0.40 18.80 24.00 311.20 644.40 1.6 388 1088096
+1 97 1 1 2 0 411 60 67 0.40 0.40 69261 44301 0.00 0.00 0.00 0.00 0.00 0.00 0.00 33.00 42.00 2.2 856 1722466
+1 90 1 1 1 0 2049 146 111 1.00 1.20 205882 27620 4.00 4.60 4.60 0.00 3.80 3.00 3.20 91.40 134.20 1.0 208 1017088
+1 87 1 1 31 41 459 73 59 0.60 2.60 161489 164550 17.60 32.80 38.00 16.20 0.60 26.80 50.00 36.60 54.80 2.4 242 1720221
+1 80 1 1 7 1 2934 358 129 5.79 9.78 910220 55253 0.00 0.00 0.00 0.00 0.00 1.40 1.40 370.66 541.32 1.7 548 1035238
+1 91 1 1 3 0 2298 204 175 1.60 0.60 109711 89342 1.00 1.00 1.00 0.00 0.20 1.40 1.40 251.70 178.24 2.5 281 1004112
+1 90 1 1 3 0 2757 171 250 1.80 0.60 56418 22397 1.40 1.60 1.60 0.00 0.40 1.80 1.80 95.80 132.80 3.0 187 1710638
+1 79 1 1 4 0 4652 762 692 2.80 1.40 602266 574167 0.00 0.00 0.00 0.00 0.00 0.80 0.80 152.40 220.80 4.4 461 1095811
+1 86 1 1 13 4 2000 116 70 2.00 9.60 113026 51436 0.00 0.00 0.00 0.00 0.00 9.20 10.60 131.40 187.00 1.0 628 1040571
+1 92 1 1 16 15 1629 114 57 0.40 0.20 281427 21018 0.80 0.80 0.80 0.00 13.40 0.20 0.20 33.20 77.60 1.0 141 1072750
+1 88 1 1 2 0 2702 190 140 0.40 0.60 228543 125011 2.20 6.39 17.56 36.13 0.00 11.78 20.16 30.74 133.13 2.0 216 1056597
+1 63 1 1 18 2 6671 1381 1345 5.40 2.20 1066971 1049237 0.00 0.00 0.00 0.00 0.00 2.00 2.00 271.40 480.20 1.0 899 1057339
+1 96 1 1 27 42 234 23 27 0.20 0.20 7179 8894 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13.15 13.15 1.6 6660 1852606
+1 82 1 1 8 2 2766 266 204 6.41 4.01 146608 55637 11.02 28.66 65.93 129.06 0.40 10.02 10.62 281.56 588.98 1.6 175 987902
+1 93 1 1 84 38 1328 222 188 0.40 0.40 100484 87614 0.00 0.00 0.00 0.00 0.00 1.20 1.60 35.07 67.74 2.5 885 999952
+1 93 1 1 54 58 1339 231 140 0.40 0.60 153872 122181 0.00 0.00 0.00 0.00 0.00 10.60 13.00 54.80 115.20 5.6 2885 1603096
+1 77 1 1 6 1 2200 179 109 5.80 18.80 316995 41538 5.60 33.60 76.00 148.80 0.20 34.40 63.00 204.00 403.40 1.0 153 1103341
+1 91 1 1 85 100 1191 160 108 1.40 1.20 34462 38868 0.00 0.00 0.00 0.00 0.00 1.40 4.60 60.00 93.80 1.0 1342 972136
+1 97 1 1 1 1 530 91 26 0.40 0.40 277646 16615 0.00 0.00 0.00 0.00 0.00 0.00 0.00 30.60 38.80 1.4 7648 1871579
+1 0 1 1 53 49 2724 216 152 0.60 1.00 31155 43152 2.60 3.60 3.40 0.00 1.80 4.20 12.40 50.40 97.60 590 90 10
+1 85 1 1 74 1 2589 379 212 1.20 5.60 795637 70712 4.40 9.00 23.40 39.80 0.20 6.60 6.60 73.60 107.40 1.5 220 1088314
+1 72 1 1 40 48 5093 527 431 6.80 2.40 278837 76965 2.20 3.20 2.60 0.00 2.00 20.80 21.80 324.00 599.20 3.2 186 1005570
+1 82 1 1 4 3 3163 340 214 1.00 2.40 338299 157235 2.20 3.00 3.00 0.00 0.80 46.00 46.80 74.60 211.00 1.5 445 985458
+1 93 1 1 2 0 1417 58 73 0.40 0.40 10453 25846 0.20 0.20 0.20 0.00 0.00 10.20 10.20 32.40 71.60 1.5 229 1081544
+1 88 1 1 3 3 2041 162 111 0.60 3.40 166876 75927 6.20 8.00 13.20 9.60 1.00 12.00 21.00 39.40 65.40 1.8 158 1098038
+1 98 1 1 0 0 159 11 32 0.20 0.20 426 11790 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 6137 1856768
+1 78 1 1 2 0 667 85 37 2.80 4.40 323466 58226 0.00 0.00 0.00 0.00 0.00 26.20 49.40 223.20 266.00 2.2 1407 1802781
+1 88 1 1 34 50 2599 207 80 0.60 0.40 510208 4578 0.00 0.00 0.00 0.00 0.20 40.80 81.20 59.80 193.20 2.0 987 1402938
+1 90 1 1 67 81 2332 195 120 0.40 0.60 159456 25770 2.20 10.00 28.00 32.80 0.40 8.60 11.40 33.00 116.00 1.4 129 1041139
+1 83 1 1 73 79 2821 287 153 3.79 9.18 130158 64654 0.00 0.00 0.00 0.00 0.00 6.19 9.38 261.48 327.54 3.8 818 1541429
+1 96 1 1 0 0 2288 61 60 0.20 0.20 22154 28667 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 2.6 521 1759688
+1 89 1 1 2 1 1424 149 63 2.00 4.60 335886 64486 0.00 0.00 0.00 0.00 0.00 1.80 2.80 139.40 155.40 1.4 8277 1837725
+1 95 1 1 1 0 1624 101 89 0.40 0.40 7681 30563 0.80 2.19 2.78 6.76 0.00 6.16 6.16 25.05 69.98 2.0 142 1083149
+1 99 1 1 0 0 152 6 12 0.20 0.20 416 9545 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7550 1878208
+1 93 1 1 0 0 1899 193 148 0.40 1.20 45870 51612 0.00 0.00 0.00 0.00 0.00 0.20 0.20 40.08 49.90 4.0 2542 1045193
+1 83 1 1 5 2 678 102 44 3.40 6.00 397658 284229 0.00 0.00 0.00 0.00 18.80 7.40 13.00 261.20 295.80 2.8 3859 1810773
+1 0 1 1 7 4 2241 235 202 0.40 0.40 127621 35747 2.60 4.20 4.00 0.00 0.40 2.60 3.00 166.40 199.00 391 88 12
+1 98 1 1 0 0 256 45 21 0.20 0.20 254806 15333 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.80 19.40 1.0 7321 1863888
+1 90 1 1 3 0 1266 192 169 3.60 1.00 90502 9050 0.00 0.00 0.00 0.00 0.00 0.20 0.20 168.20 240.20 1.4 403 1757090
+1 87 1 1 2 1 3081 289 191 0.80 2.20 151942 26417 2.80 10.60 15.00 68.00 0.80 8.60 15.20 64.60 105.20 1.0 155 1137291
+1 93 1 1 31 51 1162 84 103 0.60 0.60 40639 145846 0.00 0.00 0.00 0.00 0.00 5.80 11.60 25.60 39.20 2.2 4670 1726842
+1 93 1 1 6 1 2471 159 139 0.20 0.20 97192 223499 0.60 0.60 0.60 0.00 0.80 6.20 12.00 21.20 21.60 2.0 206 1540662
+1 77 1 1 9 0 4252 620 576 5.36 2.38 417664 287315 0.60 2.58 9.13 25.20 0.00 4.17 4.17 273.21 462.30 1.4 201 1064038
+1 90 1 1 1 0 1310 141 134 0.40 0.40 90515 24380 1.80 15.80 58.60 140.80 0.00 75.80 79.00 31.80 124.60 2.4 133 1119430
+1 75 1 1 96 116 4373 231 243 2.00 7.19 135553 152248 0.00 0.00 0.00 0.00 0.00 3.79 3.99 140.92 194.61 6.2 8137 1361273
+1 75 1 1 684 10 5244 306 191 0.20 0.20 28437 119658 0.00 0.00 0.00 0.00 0.00 79.20 80.40 16.00 65.40 2.0 638 1062344
+1 98 1 1 2 0 238 22 35 0.20 0.20 4108 30354 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.37 16.77 2.0 6549 1702609
+1 92 1 1 12 18 1207 280 200 0.20 0.20 13777 74406 2.80 3.40 3.40 0.00 0.00 2.00 2.00 15.20 28.20 2.2 236 1708720
+1 92 1 1 1 0 1094 95 81 1.20 2.40 153250 44201 0.00 0.00 0.00 0.00 11.20 6.40 12.00 93.80 140.20 1.0 1686 999614
+1 90 1 1 45 59 1734 124 100 0.60 1.40 19784 25273 1.80 2.00 2.00 0.00 0.00 13.20 14.20 49.40 94.00 2.0 187 1085952
+1 89 1 1 4 1 1391 298 194 3.20 1.00 293409 198201 0.00 0.00 0.00 0.00 0.00 0.00 0.00 163.40 229.40 2.4 5159 1836803
+1 72 1 1 30 1 4748 439 227 6.20 17.80 84770 85892 2.80 19.20 42.20 91.20 0.00 7.00 12.00 219.60 403.40 3.4 147 1089080
+1 93 1 1 31 46 1251 90 74 0.60 2.00 3967 15469 0.20 0.40 0.40 0.00 0.20 3.00 3.00 39.20 46.00 1.7 189 1098888
+1 95 1 1 5 1 2189 175 146 1.00 0.40 181958 277008 1.80 1.80 1.80 0.00 0.80 0.80 0.80 54.40 69.00 3.6 175 1323394
+1 90 1 1 10 0 4207 145 141 0.80 2.20 222977 112587 1.80 7.80 52.60 123.20 1.20 3.20 17.80 51.80 128.00 2.8 133 1524387
+1 87 1 1 3 0 3940 271 182 1.00 0.80 362811 124977 0.00 0.00 0.00 0.00 0.20 21.04 31.46 96.19 232.87 2.0 443 1075396
+1 89 1 1 5 0 1189 113 70 0.20 0.20 151043 66978 22.60 48.60 74.40 113.60 3.40 50.20 56.80 16.00 86.60 1.6 130 1108072
+1 71 1 1 7 0 4160 267 208 7.20 18.00 244849 21467 2.00 9.20 24.20 42.20 1.00 0.20 0.20 347.60 531.20 3.6 149 1750672
+1 92 1 1 16 22 349 24 15 1.60 1.60 33103 18390 0.00 0.00 0.00 0.00 0.00 1.00 1.60 124.35 123.55 1.2 7758 1865076
+1 95 1 1 23 22 593 100 84 0.60 0.60 27600 26262 0.00 0.00 0.00 0.00 0.00 0.00 0.00 47.40 70.00 2.0 709 1008691
+1 87 1 1 2 2 3072 225 236 0.20 0.20 82909 498611 0.00 0.00 0.00 0.00 0.00 8.60 9.60 18.40 38.80 1.6 659 1031766
+1 81 1 1 5 0 2900 393 270 4.20 3.00 452681 38764 0.00 0.00 0.00 0.00 0.00 3.80 4.40 204.40 345.60 3.5 568 1122034
+1 93 1 1 0 0 886 105 62 0.20 0.20 5502 23118 0.40 0.40 0.40 0.00 0.20 0.20 0.20 13.00 17.00 2.2 262 1757120
+1 95 1 1 1 0 859 84 72 0.20 0.20 12240 28445 0.60 3.60 4.60 4.00 0.00 2.40 2.40 15.60 31.80 4.8 139 1089118
+1 84 1 1 5 1 3552 237 126 0.80 0.40 33094 56108 1.80 3.81 40.68 61.52 0.40 76.75 77.56 47.70 186.37 2.4 156 1018071
+1 96 1 1 37 58 1061 76 45 0.20 0.20 1985 5799 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.80 18.40 1.0 611 1730464
+1 78 1 1 14 6 4258 651 495 8.20 2.20 321591 105441 0.00 0.00 0.00 0.00 0.00 0.20 0.20 386.60 579.60 7.2 4033 1605499
+1 97 1 1 1 1 166 11 11 0.20 0.20 7467 6028 0.00 0.00 0.00 0.00 0.00 0.00 0.00 14.31 12.92 1.0 4811 1816638
+1 92 1 1 15 13 2212 142 83 0.40 0.40 84255 17588 0.00 0.00 0.00 0.00 2.20 18.20 18.20 139.00 199.20 3.6 7493 1370760
+1 90 1 1 77 98 2220 146 90 0.40 1.80 111903 52092 1.40 1.40 1.60 0.20 2.40 4.60 5.40 30.60 134.60 1.3 148 1102810
+1 84 1 1 33 43 2649 192 169 0.80 3.40 370637 301988 0.80 1.40 2.80 4.60 0.00 26.20 50.80 65.40 86.60 4.4 519 1543136
+1 97 1 1 2 1 212 18 17 0.40 1.40 16919 6130 0.00 0.00 0.00 0.00 0.00 0.00 0.00 24.25 38.28 1.2 7257 1867125
+1 68 1 1 26 0 3800 698 406 7.20 5.20 241006 160185 0.00 0.00 0.00 0.00 0.00 9.00 14.80 428.80 727.40 3.8 820 1538923
+1 94 1 1 7 6 833 94 76 0.60 0.80 3504 22736 1.60 2.40 1.80 0.00 0.80 8.18 8.18 43.51 71.46 2.4 228 970579
+1 96 1 1 0 0 1212 146 57 0.20 0.20 226437 214163 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 17.40 3.4 1378 1756008
+1 87 1 1 20 7 1892 124 97 1.40 1.40 84535 32313 4.60 5.40 5.00 0.00 3.00 7.60 12.80 110.60 157.60 1.5 219 1112464
+1 92 1 1 6 4 1657 144 142 1.20 2.40 5804 22230 1.60 1.60 1.60 0.00 0.60 1.00 1.00 48.20 77.80 1.0 270 1016170
+1 99 1 1 1 1 152 9 16 0.20 0.20 3027 16568 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 8321 1863768
+1 93 1 1 4 3 954 140 157 1.00 1.20 7126 21906 1.60 1.80 10.80 20.20 1.20 2.40 2.40 80.80 94.00 3.0 154 1053506
+1 89 1 1 49 74 2478 212 116 1.00 3.19 452496 51666 0.00 0.00 0.00 0.00 0.00 0.40 0.40 43.43 64.34 3.2 2479 1038937
+1 94 1 1 4 2 1620 163 60 0.20 0.20 96638 13553 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.4 5951 1722552
+1 72 1 1 17 3 6510 389 349 4.20 2.00 348289 117345 12.20 26.80 51.00 115.80 3.20 12.40 17.00 230.40 476.80 2.7 190 1010160
+1 95 1 1 0 0 961 88 66 0.20 0.20 93061 15958 1.20 2.20 2.20 0.00 1.60 1.20 1.20 15.37 27.54 1.0 203 1011728
+1 95 1 1 4 4 489 57 31 0.60 0.60 267780 21380 0.00 0.00 0.00 0.00 0.00 0.00 0.00 58.00 63.40 1.4 7638 1870000
+1 76 1 1 9 3 2961 416 311 4.60 6.40 81892 72210 7.20 8.60 8.40 0.00 1.00 11.80 13.20 228.20 444.20 1.3 222 1123211
+1 97 1 1 2 0 456 80 75 0.20 0.20 37484 44629 0.00 0.00 0.00 0.00 0.40 1.00 1.00 26.80 20.60 1.0 574 1751778
+1 71 1 1 10 4 4382 400 191 5.00 6.40 298795 250019 4.40 17.20 36.80 106.00 0.20 16.00 18.20 567.20 534.00 1.0 153 1122323
+1 78 1 1 41 23 4062 257 153 3.20 4.00 389889 47269 3.40 6.40 9.80 10.60 2.40 16.00 22.20 216.40 590.60 7.0 350 1311875
+1 71 1 1 3 1 5480 444 349 1.20 1.20 505897 531224 6.20 14.60 18.80 11.80 0.00 42.60 84.40 129.40 169.20 1.2 505 1219461
+1 89 1 1 1 0 3002 255 182 0.20 0.20 43151 35724 3.59 5.39 5.19 0.00 1.00 8.58 8.78 18.16 55.49 2.5 191 992311
+1 81 1 1 84 91 1897 218 173 0.60 2.00 376838 252983 29.94 63.07 108.18 109.78 3.79 25.55 61.68 35.93 69.06 5.4 126 1597289
+1 86 1 1 17 4 3763 194 78 2.40 3.00 225802 155227 0.00 0.00 0.00 0.00 0.00 9.00 10.80 205.00 298.20 4.6 2488 1551186
+1 0 1 1 22 19 1615 375 124 0.80 0.80 687553 537619 0.00 0.00 0.00 0.00 0.40 0.20 0.20 92.60 137.40 552 89 11
+1 77 1 1 11 2 3354 380 249 0.60 2.00 361171 268701 13.77 35.33 63.67 103.19 1.40 30.34 46.91 72.85 280.44 3.0 273 1016677
+1 87 1 1 5 2 2747 308 162 0.40 1.79 860758 73164 3.78 8.17 11.35 16.93 0.40 5.38 6.37 34.46 56.18 6.0 141 1092602
+1 76 1 1 12 1 3302 508 410 9.60 3.20 468033 12205 0.00 0.00 0.00 0.00 0.00 0.00 0.00 484.20 699.40 2.6 7838 1862467
+1 95 1 1 1 0 1149 78 64 0.20 0.20 26968 17900 0.00 0.00 0.00 0.00 0.00 0.80 0.80 15.80 69.40 2.7 693 1062730
+1 86 1 1 41 58 4876 270 204 0.20 0.20 63051 106043 3.00 5.00 5.00 0.00 0.40 1.80 2.00 15.40 34.40 1.6 296 1067949
+1 98 1 1 1 1 215 24 24 0.20 0.20 4481 10470 0.00 0.00 0.00 0.00 0.00 0.00 0.00 20.80 16.80 1.0 8767 1835301
+1 94 1 1 3 1 1969 101 91 0.80 1.20 245698 56669 0.00 0.00 0.00 0.00 0.00 13.97 14.37 32.14 79.44 2.4 1855 1547837
+1 74 1 1 11 0 4176 277 193 1.40 1.40 302317 141525 14.77 49.30 147.50 328.14 0.80 34.53 49.10 267.86 333.33 3.0 145 999352
+1 86 1 1 7 1 3273 483 242 1.80 1.80 181856 62053 0.00 0.00 0.00 0.00 0.00 2.20 2.40 71.00 149.40 3.2 2893 1734720
+1 90 1 1 3 0 1492 143 129 0.80 1.00 34802 41505 5.39 7.58 20.96 37.52 0.00 20.16 20.56 53.29 138.72 3.6 164 1027489
+1 98 1 1 18 28 187 15 14 0.20 0.20 546 5216 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 578 1710862
+1 85 1 1 1 0 2903 411 299 0.80 2.20 96619 33746 0.60 0.80 0.80 0.00 0.20 7.78 12.18 63.87 158.88 2.2 254 1101202
+1 68 1 1 8 0 5541 469 407 7.60 2.20 209351 11982 0.00 0.00 0.00 0.00 0.20 0.20 0.20 372.00 544.40 3.6 482 1744770
+1 97 1 1 0 0 1569 42 37 0.20 0.20 12811 13660 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 16.80 1.2 5964 1818256
+1 90 1 1 3 1 406 43 30 2.00 2.00 92514 42969 0.00 0.00 0.00 0.00 0.00 2.40 4.41 188.58 163.53 1.4 11490 1885199
+1 97 1 1 0 0 1385 56 52 0.20 0.20 12446 20066 1.60 2.00 2.00 0.00 0.40 1.60 2.00 15.60 17.00 1.0 149 1750992
+1 88 1 1 39 55 478 79 65 0.80 0.80 18849 12080 0.00 0.00 0.00 0.00 0.00 1.60 1.60 66.47 64.67 2.6 807 1750812
+1 76 1 1 16 11 7188 496 378 4.60 10.80 219020 80489 1.20 2.20 1.80 0.00 0.80 8.40 12.40 243.00 611.60 2.8 345 1001160
+1 87 1 1 62 90 2492 146 124 0.20 0.20 117979 82643 0.00 0.00 0.00 0.00 0.00 5.40 8.60 21.60 52.00 1.7 910 994222
+1 91 1 1 15 14 2060 534 207 0.20 0.20 638967 667864 0.00 0.00 0.00 0.00 0.00 0.60 0.60 23.20 55.60 1.7 351 1044085
+1 72 1 1 39 17 4118 358 218 6.19 5.79 596924 159901 13.97 41.32 148.70 196.01 5.79 26.15 51.50 240.72 569.46 1.0 208 1081980
+1 96 1 1 15 21 390 60 39 0.20 0.20 4844 10564 0.00 0.00 0.00 0.00 0.20 0.00 0.00 15.60 16.80 2.0 693 1722062
+1 85 1 1 16 3 3127 202 175 2.60 3.80 296643 125693 2.80 2.80 2.80 0.00 0.60 14.20 23.80 141.00 280.40 4.6 225 1540502
+1 91 1 1 50 64 1275 109 104 0.60 0.60 26991 58709 3.40 4.00 3.80 0.00 1.00 3.40 5.80 49.40 64.00 6.8 305 1056435
+1 92 1 1 1 1 2444 91 152 0.20 0.20 86880 23199 1.80 3.20 2.60 0.00 0.00 10.80 21.00 15.60 25.00 2.8 321 1703744
+1 95 1 1 1 0 1395 123 60 0.20 0.20 255917 16050 1.59 2.39 2.39 0.00 0.00 1.00 1.00 14.34 12.95 1.4 284 1745434
+1 84 1 1 98 92 2289 455 304 2.00 1.00 1079576 56489 5.20 10.00 19.60 24.80 0.80 12.80 14.00 112.60 194.80 1.0 193 974730
+1 98 1 1 0 0 164 14 15 0.20 0.20 444 3556 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.83 16.83 1.4 7418 1869323
+1 66 1 1 57 45 5276 748 513 8.80 3.60 241474 20542 0.00 0.00 0.00 0.00 0.40 7.60 7.80 435.20 693.80 1.0 1927 1076997
+1 89 1 1 1 0 2233 194 90 1.00 2.59 206352 24771 0.00 0.00 0.00 0.00 0.00 1.60 1.60 74.65 97.60 2.2 546 1094047
+1 85 1 1 7 2 1976 366 321 1.00 2.80 235811 56167 0.00 0.00 0.00 0.00 0.00 3.80 7.60 67.00 80.00 3.4 431 1697954
+1 98 1 1 2 1 198 13 24 0.20 0.20 8636 11574 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7385 1874944
+1 81 1 1 38 18 3091 381 188 4.79 6.59 206975 64456 4.19 10.78 34.13 58.88 2.59 7.58 26.55 210.58 371.46 2.6 165 1109397
+1 95 1 1 2 1 1407 71 67 0.20 0.20 5374 23273 0.00 0.00 0.00 0.00 0.00 1.40 2.40 18.84 25.05 1.0 601 1734565
+1 72 1 1 13 1 2434 125 73 6.97 18.92 128305 29428 6.97 42.63 85.26 233.67 1.20 55.38 104.78 316.93 528.69 1.0 175 1057957
+1 98 1 1 1 0 163 15 14 0.20 0.20 32518 14777 0.00 0.00 0.00 0.00 0.00 0.00 0.00 18.80 18.00 2.4 3611 1821618
+1 98 1 1 3 3 261 72 34 0.20 0.20 18543 7923 0.00 0.00 0.00 0.00 0.00 1.60 2.80 15.60 16.80 1.0 5313 1859928
+1 79 1 1 3 0 2971 383 174 1.80 4.19 362574 52408 0.00 0.00 0.00 0.00 0.00 23.35 43.91 148.30 240.52 1.3 541 1122655
+1 79 1 1 8 2 2725 176 97 2.20 2.40 409928 62603 0.00 0.00 0.00 0.00 0.20 7.00 11.40 111.60 334.20 6.4 1472 1309614
+1 98 1 1 0 0 455 65 32 0.20 0.20 16881 7823 1.80 1.80 1.80 0.00 0.20 0.20 0.40 15.17 16.77 1.0 218 1756128
+1 94 1 1 12 11 1222 163 131 0.40 0.20 41368 54403 4.60 8.60 8.60 0.00 0.00 0.00 0.00 20.80 38.60 1.0 136 1011194
+1 92 1 1 6 1 1541 180 92 0.60 2.00 346647 106369 0.00 0.00 0.00 0.00 0.00 1.00 1.60 93.20 133.60 3.0 928 1542392
+1 95 1 1 2 1 1959 190 142 0.20 0.20 92269 26717 0.00 0.00 0.00 0.00 0.00 0.00 0.00 21.40 21.00 2.8 468 1629221
+1 83 1 1 10 6 2050 186 132 1.80 3.00 154733 82863 0.20 0.20 0.20 0.00 0.00 11.60 16.00 166.20 276.00 1.3 542 1128686
+1 94 1 1 4 2 1520 178 54 0.80 1.00 559134 26927 0.00 0.00 0.00 0.00 0.00 0.80 0.80 54.49 67.47 3.4 2666 1724321
+1 76 1 1 10 3 1873 187 210 5.18 5.98 336610 280145 1.59 1.79 1.79 0.00 1.59 12.75 14.94 200.40 375.30 2.2 235 1014985
+1 76 1 1 4 3 6037 306 187 1.40 2.81 342631 295887 4.01 8.22 10.42 12.63 4.41 25.25 38.68 75.15 185.37 1.0 225 1013159
+1 91 1 1 1 0 1723 125 56 0.40 0.40 176002 15941 0.00 0.00 0.00 0.00 0.00 11.38 17.76 41.72 82.04 1.0 733 1055425
+1 91 1 1 15 11 1252 274 172 0.80 1.20 29556 34544 1.60 1.60 1.60 0.00 1.00 21.20 24.60 39.60 108.60 1.5 301 1016866
+1 94 1 1 6 2 2010 143 124 0.60 0.60 98448 134872 0.00 0.00 0.00 0.00 0.00 3.40 4.40 65.60 78.20 2.2 1931 1545338
+1 84 1 1 25 13 2598 115 81 1.40 1.40 336212 57944 7.40 47.60 93.20 165.40 3.60 21.40 39.00 81.80 365.80 4.6 236 1303083
+1 63 1 1 23 12 6085 634 548 9.80 3.20 595452 318636 0.00 0.00 0.00 0.00 0.00 15.80 27.80 464.60 747.80 1.0 639 1008197
+1 86 1 1 3 0 3517 342 189 1.00 2.99 310439 214462 0.00 0.00 0.00 0.00 0.20 8.18 15.57 88.82 87.82 4.4 420 1547657
+1 93 1 1 1 0 1478 108 80 0.60 1.20 49601 14601 4.60 6.00 6.00 0.00 0.00 2.00 2.20 47.20 108.60 2.0 272 1023184
+1 95 1 1 0 0 820 157 68 0.40 0.40 212904 156341 0.00 0.00 0.00 0.00 0.00 2.40 4.00 33.80 39.80 3.6 1063 1753798
+1 88 1 1 5 1 2046 230 170 3.40 1.00 91592 15184 0.00 0.00 0.00 0.00 0.00 0.00 0.00 163.80 240.60 1.2 7846 1862954
+1 97 1 1 20 26 177 18 19 0.20 0.20 2164 6015 0.00 0.00 0.00 0.00 0.00 0.20 0.20 15.60 16.80 1.0 7431 1866853
+1 86 1 1 3 0 2432 181 97 1.80 2.00 356550 25434 2.79 22.16 67.47 198.80 2.20 5.59 8.98 137.92 278.04 5.0 153 1118042
+1 96 1 1 5 1 309 37 42 0.20 0.20 20830 24601 0.00 0.00 0.00 0.00 0.00 0.00 0.00 18.84 17.23 1.4 2804 1776871
+1 91 1 1 14 12 2248 386 119 0.20 0.20 682046 624653 0.00 0.00 0.00 0.00 0.00 1.60 1.80 20.80 52.60 3.8 426 1044509
+1 60 1 1 10 0 4065 279 142 9.80 37.60 224594 29644 4.40 5.00 4.60 0.00 3.60 3.00 3.60 528.40 837.40 1.7 244 1034034
+1 97 1 1 1 1 2680 102 91 0.20 0.20 2612 5061 0.00 0.00 0.00 0.00 0.00 2.40 2.40 15.80 25.20 2.2 2927 1413368
+1 86 1 1 99 121 3142 245 190 1.40 3.00 361331 69490 0.00 0.00 0.00 0.00 0.00 11.00 18.40 112.80 243.20 5.2 10382 1374640
+1 0 1 1 23 18 2182 379 133 0.60 0.40 594823 503069 0.00 0.00 0.00 0.00 0.00 39.20 69.40 36.80 221.80 910 82 17
+1 86 1 1 164 160 4597 370 253 0.40 1.00 315228 250265 0.00 0.00 0.00 0.00 0.00 4.60 19.60 40.60 53.00 3.8 1947 1327789
+1 92 1 1 1 1 332 65 39 0.40 0.40 274459 249984 0.00 0.00 0.00 0.00 0.00 4.80 7.80 35.20 35.20 2.6 3539 1822098
+1 95 1 1 2 1 306 18 26 1.00 1.00 18417 62482 0.00 0.00 0.00 0.00 0.00 0.00 0.00 69.40 74.00 1.2 7544 1865267
+1 80 1 1 1 0 3480 189 237 0.80 1.00 280924 528709 12.77 40.72 142.91 292.02 0.00 10.58 11.78 63.27 236.73 2.4 132 998563
+1 93 1 1 10 9 1289 144 85 0.40 0.40 58855 28895 0.00 0.00 0.00 0.00 0.00 0.40 3.20 33.00 82.20 2.0 685 1012931
+1 91 1 1 1 1 549 173 92 1.00 1.00 437698 350866 0.00 0.00 0.00 0.00 0.00 20.00 39.60 50.60 69.40 3.0 5669 1828162
+1 88 1 1 13 8 4312 206 152 0.40 0.40 233531 66819 0.00 0.00 0.00 0.00 0.00 19.80 28.20 38.00 106.00 2.6 1272 1397251
+1 93 1 1 29 40 1473 93 73 0.20 0.20 4410 27749 0.40 0.40 0.40 0.00 0.00 1.80 1.80 16.37 27.54 2.0 159 1087457
+1 87 1 1 4 0 2006 192 91 3.80 8.80 224844 38733 0.00 0.00 0.00 0.00 0.20 0.40 0.80 209.00 336.80 1.0 472 1031155
+1 94 1 1 1 0 430 59 15 0.80 1.00 275854 7040 0.00 0.00 0.00 0.00 0.00 0.00 0.00 53.20 67.00 1.4 6919 1828906
+1 93 1 1 62 62 2510 180 145 0.60 0.20 51069 89375 0.00 0.00 0.00 0.00 0.00 2.20 3.01 26.25 51.10 2.0 364 991380
+1 81 1 1 16 11 2915 253 96 2.60 2.80 167969 85311 0.00 0.00 0.00 0.00 0.00 29.60 32.40 211.80 364.60 1.0 883 1012941
+1 93 1 1 4 1 1534 105 107 0.40 0.40 209324 111844 0.00 0.00 0.00 0.00 0.00 0.60 0.60 33.67 44.09 1.5 401 1076553
+1 90 1 1 2 0 398 41 13 2.00 2.00 151420 12892 0.00 0.00 0.00 0.00 0.00 1.00 1.60 154.29 148.50 1.4 7683 1864718
+1 84 1 1 2 2 2157 155 128 0.20 0.20 144409 89393 0.00 0.00 0.00 0.00 0.00 15.17 27.15 15.57 35.33 2.0 490 1117539
+1 95 1 1 1 0 3252 274 157 0.20 0.20 15043 72970 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.77 16.97 2.4 936 1643090
+1 85 1 1 165 144 3417 233 128 3.80 3.00 112558 74099 0.00 0.00 0.00 0.00 0.20 15.60 17.60 147.20 272.80 6.0 476 1307589
+1 98 1 1 0 0 230 35 14 0.20 0.20 169196 5037 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.83 16.83 1.0 7398 1869339
+1 0 1 1 10 4 1404 94 62 0.40 0.60 220900 19629 12.20 22.60 48.80 115.40 1.40 3.00 24.20 29.40 101.20 159 92 8
+1 78 1 1 10 5 2549 320 181 3.80 3.40 449917 64221 0.00 0.00 0.00 0.00 0.00 3.20 5.40 230.00 574.40 1.0 1005 1070168
+1 77 1 1 12 1 2896 364 274 8.80 3.00 213542 13831 1.80 3.00 10.80 16.20 0.00 0.60 0.80 404.20 610.60 2.4 333 1725171
+1 90 1 1 2 0 977 119 88 1.60 2.20 229909 44485 2.00 2.79 2.79 0.00 0.40 6.19 6.79 100.60 195.41 2.6 458 1053327
+1 0 1 1 17 1 3418 383 265 5.80 3.20 435552 31323 1.20 1.40 1.40 0.00 0.80 1.00 1.00 279.60 521.80 360 80 19
+1 88 1 1 5 0 2233 297 122 1.20 1.40 317752 110756 0.20 0.20 0.20 0.00 1.60 2.60 2.60 163.60 175.80 2.2 298 1535555
+1 88 1 1 37 37 2799 208 109 1.00 2.40 289700 32274 4.81 16.83 33.07 59.52 4.01 22.85 24.85 81.56 189.38 1.0 174 1070764
+1 88 1 1 16 14 2942 77 79 1.60 3.19 39721 33909 3.99 17.37 84.43 159.28 1.20 1.00 1.00 155.89 308.38 3.0 233 1014451
+1 96 1 1 1 0 535 36 61 0.40 0.40 1068 38349 0.00 0.00 0.00 0.00 0.00 0.00 0.00 33.40 33.20 1.0 5962 1864144
+1 98 1 1 1 1 198 18 22 0.20 0.20 7045 10484 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.2 7352 1869571
+1 98 1 1 0 0 356 56 23 0.20 0.20 340971 51221 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16.03 17.03 1.6 7491 1868151
+1 94 1 1 5 4 1056 81 68 0.20 0.20 5452 16180 0.40 0.40 0.40 0.00 0.60 11.58 11.98 15.57 30.14 2.0 213 1116158
+1 63 1 1 59 50 4550 456 234 7.60 18.20 770540 86051 20.40 89.60 120.60 239.20 1.40 20.20 22.60 307.40 688.20 2.4 159 1088917
+1 98 1 1 0 0 259 17 34 0.40 0.40 17865 13867 0.00 0.00 0.00 0.00 0.00 0.00 0.00 40.60 51.00 1.0 7188 1874112
+1 88 1 1 3 1 508 41 27 2.00 2.20 93328 86630 0.00 0.00 0.00 0.00 0.00 2.00 3.21 200.60 174.15 1.2 7529 1869275
+1 97 1 1 0 0 417 61 44 0.20 0.20 1454 8594 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.0 2100 1720376
+1 92 1 1 13 11 1608 426 197 0.60 1.80 659972 557345 0.00 0.00 0.00 0.00 0.00 0.80 1.20 41.92 98.20 4.6 633 1039238
+1 73 1 1 37 47 2127 408 365 3.20 2.00 554916 632629 48.40 114.40 223.20 224.60 0.40 9.40 18.00 182.00 310.60 4.8 150 1714603
+1 63 1 1 20 1 4250 332 155 8.20 27.00 559345 28785 10.20 29.80 76.00 147.80 5.80 20.40 33.20 305.80 676.40 1.6 173 1083291
+1 88 1 1 0 0 3028 807 601 0.20 0.20 13703 22683 0.00 0.00 0.00 0.00 0.60 0.00 0.00 16.60 20.00 2.2 1183 1719400
+1 84 1 1 3 1 2659 262 181 1.20 1.80 190937 49972 4.00 6.80 6.80 0.00 3.60 9.60 14.60 70.20 134.60 1.0 292 1104144
+1 95 1 1 14 3 512 28 27 1.40 1.60 82639 11864 0.00 0.00 0.00 0.00 0.00 0.80 0.80 124.80 131.40 1.0 7240 1847587
+1 89 1 1 2 1 2648 257 164 0.40 0.60 106551 27902 0.00 0.00 0.00 0.00 0.00 0.80 1.20 34.87 71.14 2.0 916 1054447
+1 64 1 1 39 16 5213 754 767 6.99 4.99 435848 314796 6.19 9.98 10.18 5.19 5.39 15.77 17.56 348.10 617.17 4.8 236 1002172
+1 90 1 1 22 10 2473 229 177 0.40 0.20 147854 42367 0.00 0.00 0.00 0.00 0.20 8.20 8.80 31.40 108.40 3.4 7604 1380197
+1 94 1 1 34 48 1078 141 122 0.40 1.80 44449 24698 3.00 3.00 3.00 0.00 0.00 2.40 3.00 25.60 36.00 1.7 325 1030629
+1 93 1 1 6 2 1562 183 116 0.20 0.20 244700 29933 0.00 0.00 0.00 0.00 0.40 3.00 3.80 17.20 45.40 3.0 572 1076589
+1 67 1 1 26 1 5901 754 581 10.22 2.81 975989 30641 5.21 5.81 5.81 0.00 1.20 0.80 0.80 492.99 735.47 3.0 191 1081557
+1 89 1 1 62 59 2204 274 165 1.00 0.80 56067 64473 0.60 0.60 0.60 0.00 3.00 1.20 1.80 54.60 93.40 1.0 409 977250
+1 72 1 1 10 4 4758 276 187 2.20 2.40 326597 138722 0.00 0.00 0.00 0.00 0.00 11.38 12.57 161.08 239.52 5.6 1514 1343109
+1 93 1 1 1 1 1563 91 74 0.20 0.20 18554 16897 0.00 0.00 0.00 0.00 0.00 2.00 3.00 15.60 20.00 4.2 1402 1075176
+1 91 1 1 6 4 2360 190 107 0.99 0.79 114342 36546 1.39 1.98 1.98 0.00 0.40 6.53 7.13 66.34 99.01 2.0 377 1020046
+1 80 1 1 18 12 3820 270 155 5.80 7.80 201297 79120 0.00 0.00 0.00 0.00 0.00 1.80 2.20 359.20 487.60 5.2 1509 1615386
+1 91 1 1 19 15 981 132 115 0.60 0.60 36934 56799 0.00 0.00 0.00 0.00 0.20 4.19 4.19 53.89 155.89 1.7 566 975364
+1 91 1 1 3 2 1391 111 73 0.40 0.40 7741 18379 0.20 0.20 0.20 0.00 0.20 0.40 0.40 34.13 93.61 2.0 317 1023543
+1 97 1 1 1 1 1107 47 26 0.20 0.20 9887 13536 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.80 17.00 1.0 8188 1836408
+1 94 1 1 5 4 2339 132 116 0.40 0.40 22609 50185 4.80 9.20 7.40 0.00 3.80 1.60 1.60 33.60 41.60 2.4 216 1710456
+1 83 1 1 20 5 3061 368 193 2.20 9.22 327102 303753 0.00 0.00 0.00 0.00 0.20 16.23 30.66 105.61 245.89 2.2 538 1038554
+1 92 1 1 2 1 555 43 35 1.00 1.00 89902 92146 0.00 0.00 0.00 0.00 0.00 10.20 20.20 48.40 72.20 1.2 7591 1879139
+1 80 1 1 18 15 1747 142 74 3.39 5.78 216979 50870 4.38 5.58 53.59 118.33 3.78 2.79 3.59 238.84 546.41 3.6 197 1014610
+1 94 1 1 6 2 1665 83 117 1.00 1.00 49351 102448 0.00 0.00 0.00 0.00 0.00 0.60 0.60 67.20 98.20 3.6 812 1523256
+1 0 1 1 11 5 3115 250 206 3.00 2.40 197735 18979 3.80 7.60 7.60 0.00 0.00 1.00 1.00 304.60 223.80 352 85 15
+1 86 1 1 8 1 2830 292 266 2.20 4.99 27269 46849 0.00 0.00 0.00 0.00 0.20 5.19 7.58 189.22 223.15 3.0 746 1535593
+1 83 1 1 10 7 2595 193 242 2.00 3.80 190853 456167 1.80 2.00 2.00 0.00 2.20 26.40 30.40 145.20 270.80 2.4 367 1374733
+1 93 1 1 5 5 1282 121 82 0.40 0.20 110743 33071 6.01 7.21 7.21 0.00 1.60 1.60 2.00 26.05 52.51 1.0 175 1101082
+1 89 1 1 34 48 1648 267 223 0.20 0.20 13279 37860 0.00 0.00 0.00 0.00 0.00 0.40 0.40 15.80 22.20 2.2 2935 1736318
+1 86 1 1 18 2 3344 172 100 3.60 8.00 368260 143396 0.00 0.00 0.00 0.00 0.00 1.00 1.80 262.80 361.80 5.2 2574 1551755
+1 85 1 1 3 1 3289 165 162 1.60 2.40 112097 189578 3.80 9.80 18.60 27.20 0.60 3.00 3.00 114.40 161.20 3.0 173 997024
+1 92 1 1 13 10 2230 91 58 0.40 0.40 134528 62074 0.00 0.00 0.00 0.00 0.00 0.80 0.80 23.80 161.40 4.4 1164 1532026
+1 87 1 1 19 15 3163 285 168 0.40 0.40 154297 104602 5.00 8.40 8.20 0.00 3.00 10.20 13.60 41.60 82.00 2.5 265 1123963
+1 89 1 1 0 0 3809 281 186 0.40 0.40 129636 105267 5.80 14.40 22.60 52.20 0.20 2.60 5.00 39.80 92.40 1.0 175 1029466
+1 89 1 1 3 2 3492 124 92 0.40 0.40 9465 29079 6.20 14.40 33.20 47.80 8.00 30.20 40.80 35.00 134.20 1.5 142 983269
+1 96 1 1 1 0 1209 77 62 0.40 1.20 17007 15222 0.00 0.00 0.00 0.00 0.00 2.59 2.59 29.94 53.29 2.6 926 1063254
+1 84 1 1 9 1 2714 368 272 4.60 4.00 179782 115412 0.00 0.00 0.00 0.00 0.00 0.40 0.60 218.80 377.40 3.4 810 1541016
+1 98 1 1 0 0 225 50 30 0.20 0.20 312021 297905 0.00 0.00 0.00 0.00 0.00 0.00 0.00 13.00 16.80 2.2 1314 1762008
+1 97 1 1 1 0 387 52 28 0.20 0.20 38561 20944 0.00 0.00 0.00 0.00 0.00 3.80 3.80 16.60 24.40 1.0 8313 1863734
+1 86 1 1 45 40 1278 178 80 3.20 4.80 353625 88144 0.00 0.00 0.00 0.00 0.00 1.80 3.40 225.00 352.80 2.2 6622 1839845
+1 93 1 1 10 5 1002 93 69 0.60 1.20 146514 64707 15.80 24.40 37.60 52.80 1.60 11.60 22.00 61.80 126.40 1.8 161 1072518
+1 77 1 1 13 1 3195 475 372 9.80 3.80 256291 9559 0.00 0.00 0.00 0.00 0.00 0.00 0.00 429.00 646.80 2.0 6118 1854101
+1 80 1 1 3 0 4563 313 282 0.80 1.00 559849 428414 5.00 75.60 183.20 540.80 0.00 43.60 86.00 60.60 90.80 6.6 126 1318419
+1 84 1 1 8 3 2781 182 109 0.80 3.60 187626 63713 17.40 63.60 162.00 435.20 0.80 18.40 32.60 43.20 280.60 2.0 222 1026811
+1 80 1 1 16 3 2926 157 123 2.40 7.60 212406 28189 0.00 0.00 0.00 0.00 3.60 16.40 30.00 122.60 307.20 3.8 725 1317494
+1 81 1 1 2 0 4923 288 216 0.80 3.60 274812 70913 13.20 23.40 38.80 44.60 12.80 25.00 34.00 63.20 175.00 1.2 144 982850
+1 95 1 1 2 1 448 120 32 1.20 0.80 268056 136239 0.00 0.00 0.00 0.00 0.00 0.00 0.00 73.00 115.00 2.4 6787 1835458
+1 84 1 1 3 1 5627 271 223 2.00 1.60 39191 19973 0.00 0.00 0.00 0.00 0.00 1.60 1.60 147.80 168.60 2.4 552 1384080
+1 97 1 1 22 33 210 14 17 0.20 0.20 7026 7795 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7537 1868896
+1 96 1 1 0 0 264 46 25 0.20 0.20 256267 28155 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 18.20 1.0 7358 1874496
+1 88 1 1 24 15 3052 203 173 1.80 2.20 115480 178745 1.60 2.00 2.00 0.00 2.40 1.20 1.20 129.20 180.40 2.6 227 1519690
+1 95 1 1 2 1 1520 128 84 0.40 1.40 91932 12370 0.00 0.00 0.00 0.00 0.00 0.60 0.60 21.24 30.86 1.4 1174 1747784
+1 69 1 1 36 27 2641 230 161 8.98 21.56 47204 29349 2.20 2.59 2.59 0.00 0.00 8.18 14.97 413.77 609.98 3.0 328 1104260
+1 94 1 1 2 1 849 82 50 0.60 0.60 281290 10373 1.60 8.20 15.20 25.80 7.20 0.80 0.80 55.60 60.40 2.8 132 1438760
+1 88 1 1 1 0 1676 80 76 0.20 0.20 98641 55135 0.00 0.00 0.00 0.00 0.00 0.20 0.20 22.80 21.00 2.0 3517 1771766
+1 96 1 1 2 1 818 54 50 0.20 0.20 1114 13939 0.60 0.60 0.60 0.00 0.20 1.60 1.60 15.20 22.60 1.0 133 1014048
+1 86 1 1 3 2 4073 470 347 0.80 0.40 37552 54687 1.40 1.40 1.60 0.60 0.60 0.00 0.00 47.20 75.00 3.0 137 1695512
+1 83 1 1 92 108 3091 280 168 3.80 4.20 664426 106101 1.40 1.80 2.60 3.40 11.00 13.00 17.80 198.20 362.00 7.2 305 1302630
+1 68 1 1 7 3 4821 472 459 2.59 3.59 520991 570078 0.00 0.00 0.00 0.00 0.00 26.89 27.29 167.73 428.09 4.5 1133 988041
+1 93 1 1 1 0 2164 166 167 0.60 2.40 249529 93523 0.00 0.00 0.00 0.00 0.00 0.40 0.40 50.40 61.00 1.0 2728 1051227
+1 82 1 1 3 0 5026 603 161 2.60 4.00 115599 207586 0.40 0.40 1.80 4.40 0.00 4.60 8.80 143.80 213.60 2.6 269 1017270
+1 58 1 1 145 53 7870 1348 1234 6.00 2.00 951510 794198 8.40 72.20 146.40 238.20 3.80 17.20 42.60 309.60 581.60 1.8 135 1089506
+1 78 1 1 188 203 2150 153 121 6.19 16.77 38701 18975 2.40 2.40 2.40 0.00 0.20 9.38 13.57 221.16 382.63 1.0 174 1101199
+1 89 1 1 4 1 568 44 37 2.40 1.80 61422 47876 0.00 0.00 0.00 0.00 0.00 0.80 1.00 172.80 179.60 1.2 5922 1848787
+1 91 1 1 0 0 3017 266 130 0.40 0.40 20466 111084 0.00 0.00 0.00 0.00 0.20 2.20 2.20 33.27 116.03 2.2 521 1023338
+1 56 1 1 40 10 7969 450 283 8.60 17.60 297948 79757 0.00 0.00 0.00 0.00 0.00 2.60 5.60 584.20 791.60 6.6 2397 1372435
+1 98 1 1 0 0 216 32 27 0.20 0.20 3001 23146 0.00 0.00 0.00 0.00 0.00 0.40 0.60 15.80 19.40 1.0 925 1742603
+1 64 1 1 40 23 5016 469 356 2.20 2.99 174025 440935 40.72 85.83 136.33 215.57 1.80 24.55 66.87 145.91 317.56 1.4 133 991666
+1 98 1 1 1 0 534 72 56 0.20 0.20 1687 20954 0.00 0.00 0.00 0.00 0.00 0.20 0.20 20.60 17.00 3.0 1314 1713731
+1 93 1 1 2 1 1738 144 72 0.60 2.00 176182 20310 0.00 0.00 0.00 0.00 0.00 1.80 1.80 39.72 60.28 1.0 557 1093573
+1 90 1 1 3 1 2363 154 102 1.00 1.20 103610 33127 0.00 0.00 0.00 0.00 0.20 2.20 3.20 79.40 124.80 1.0 586 1033074
+1 96 1 1 0 0 1364 69 62 0.20 0.20 1972 16209 0.00 0.00 0.00 0.00 0.00 0.20 0.40 15.80 17.40 1.6 690 1734606
+1 94 1 1 0 0 1122 125 70 0.20 0.20 237010 233482 0.00 0.00 0.00 0.00 0.00 8.60 10.80 15.60 28.20 3.4 1917 1747221
+1 94 1 1 4 0 1511 87 61 1.20 3.60 28598 3684 0.00 0.00 0.00 0.00 0.00 9.80 11.20 54.00 122.00 2.0 409 1382992
+1 89 1 1 25 7 2221 195 84 4.80 6.00 328178 167211 0.00 0.00 0.00 0.00 0.00 2.20 4.00 253.20 355.20 4.6 1187 1560675
+1 74 1 1 11 0 4669 536 460 8.38 2.40 389919 19976 0.00 0.00 0.00 0.00 0.00 2.40 4.39 427.35 614.97 3.4 4130 1720584
+1 97 1 1 1 0 239 28 23 0.60 0.60 11276 6283 0.00 0.00 0.00 0.00 0.00 0.00 0.00 51.40 63.80 1.0 437 1757280
+1 96 1 1 1 0 775 72 45 0.20 0.40 95931 13822 0.00 0.00 0.00 0.00 0.00 0.20 0.20 27.45 27.86 1.0 761 1043072
+1 79 1 1 71 50 2990 419 300 1.40 2.20 360025 61354 13.40 34.80 103.80 154.80 1.40 63.40 82.00 124.20 345.40 3.8 315 985166
+1 96 1 1 0 0 2334 76 110 0.20 0.20 4703 14345 0.00 0.00 0.00 0.00 0.00 1.00 1.00 15.60 18.60 2.4 1393 1725040
+1 97 1 1 60 78 237 36 25 0.20 0.20 8085 8482 0.00 0.00 0.00 0.00 0.00 0.00 0.00 19.60 24.20 1.0 8509 1837342
+1 95 1 1 3 1 888 52 60 1.40 0.80 17442 25811 0.00 0.00 0.00 0.00 0.00 0.60 0.60 67.60 99.20 1.0 2091 1072318
+1 95 1 1 5 3 1065 102 86 0.40 0.60 8540 27168 0.00 0.00 0.00 0.00 0.20 0.80 0.80 34.00 75.40 1.3 1549 1023907
+1 92 1 1 0 0 897 101 53 0.60 0.80 400470 287614 2.40 3.60 3.60 0.00 2.40 0.00 0.00 41.60 58.80 2.8 341 1760334
+1 63 1 1 35 10 6454 468 156 6.20 14.20 169118 55350 7.60 19.40 59.40 114.00 4.80 4.60 7.00 421.60 630.80 8.4 161 1301640
+1 94 1 1 9 1 1239 95 73 0.60 0.80 44883 18876 1.20 1.20 1.20 0.00 1.20 7.82 8.82 58.92 88.78 3.0 336 1058588
+1 94 1 1 9 1 2707 183 125 0.20 0.20 36566 35855 0.00 0.00 0.00 0.00 0.00 1.20 1.40 18.20 28.20 3.0 1282 1058850
+1 95 1 1 1 0 591 21 21 1.40 7.80 12275 45375 0.00 0.00 0.00 0.00 0.00 0.20 0.20 86.60 109.40 1.2 6969 1859427
+1 84 1 1 14 2 4407 228 211 1.00 1.20 46198 34261 1.20 1.20 1.20 0.00 1.00 13.60 17.20 82.40 151.40 2.0 420 1065842
+1 83 1 1 2 0 944 71 288 2.00 2.00 78629 86668 0.00 0.00 0.00 0.00 0.00 1.80 2.00 194.40 160.40 1.6 2471 1820541
+1 88 1 1 4 1 487 45 24 2.20 2.20 98727 64366 0.00 0.00 0.00 0.00 0.00 2.00 3.60 207.80 176.40 1.0 7553 1865453
+1 96 1 1 22 29 792 71 40 0.20 0.20 11629 55572 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.4 6796 1853318
+1 0 1 1 8 1 2091 237 165 2.20 4.00 127579 86009 0.00 0.00 0.00 0.00 0.00 5.80 6.00 164.40 214.00 844 87 11
+1 96 1 1 2 0 537 96 39 0.20 0.20 114833 115848 0.00 0.00 0.00 0.00 0.00 7.20 8.40 20.40 50.20 3.2 704 1744550
+1 85 1 1 1 0 3290 360 240 0.60 0.60 49705 52288 7.58 10.18 10.18 0.00 2.79 2.20 3.19 55.89 60.88 5.0 163 1098061
+1 89 1 1 2 1 3503 268 139 1.00 3.79 15539 23163 0.00 0.00 0.00 0.00 0.00 0.40 0.40 58.28 81.84 4.8 613 1093443
+1 98 1 1 1 0 304 58 46 0.20 0.20 1397 10710 1.80 2.00 2.00 0.00 0.20 0.00 0.00 16.80 20.80 1.2 225 1759638
+1 82 1 1 54 29 2360 267 144 1.20 1.80 193935 41415 0.00 0.00 0.00 0.00 0.00 5.39 5.79 75.65 345.31 1.0 1112 963759
+1 96 1 1 2 1 1232 158 78 0.20 0.20 164699 137104 0.00 0.00 0.00 0.00 0.00 1.80 1.80 16.00 25.60 4.2 1813 1558149
+1 86 1 1 6 4 3254 370 171 1.60 3.40 60838 37427 3.00 11.60 36.60 77.80 1.20 2.60 7.20 149.80 235.20 2.0 181 1068232
+1 83 1 1 14 12 3259 198 92 2.20 3.80 234635 300332 0.00 0.00 0.00 0.00 0.00 0.60 0.60 294.20 232.00 5.0 2677 1605075
+1 88 1 1 41 59 2408 434 188 0.60 0.60 544624 738665 0.00 0.00 0.00 0.00 0.00 24.20 24.60 30.40 81.40 3.2 565 1042760
+1 78 1 1 60 68 4080 602 525 3.78 1.79 378975 255371 5.58 7.57 7.57 0.00 2.99 12.15 14.74 206.18 391.04 1.6 249 1074040
+1 81 1 1 158 52 2354 331 248 4.00 3.80 343227 191826 8.80 35.60 35.60 0.00 1.80 2.80 3.40 235.80 498.80 1.0 222 986966
+1 92 1 1 15 5 2715 283 180 0.20 0.20 40059 37693 0.00 0.00 0.00 0.00 0.40 2.20 2.20 24.60 62.80 1.0 641 1077050
+1 98 1 1 2 1 170 15 16 0.20 0.20 11638 8714 0.00 0.00 0.00 0.00 0.00 0.60 1.20 15.60 17.20 1.2 7247 1847131
+1 90 1 1 43 56 1826 118 95 0.80 0.80 18516 28681 0.00 0.00 0.00 0.00 0.00 12.57 13.17 135.53 131.54 1.0 836 964444
+1 92 1 1 34 47 1310 87 89 0.60 2.20 111704 74598 0.00 0.00 0.00 0.00 0.00 10.58 19.76 49.30 79.04 1.0 616 1073293
+1 99 1 1 1 0 146 9 9 0.20 0.20 986 3941 0.00 0.00 0.00 0.00 0.00 0.00 0.00 18.60 16.80 1.0 7203 1847472
+1 83 1 1 18 4 1419 126 111 2.40 3.20 58634 30159 34.20 74.40 112.80 225.60 4.00 32.00 40.40 192.20 363.00 2.6 126 966930
+1 96 1 1 1 0 510 85 58 0.20 0.20 1802 5367 0.00 0.00 0.00 0.00 0.00 0.00 0.00 22.80 17.60 2.2 406 1717720
+1 91 1 1 3 1 1298 80 56 0.60 0.60 141608 21016 2.60 6.20 57.80 131.80 0.20 14.60 28.80 167.00 119.40 1.0 120 1062837
+1 75 1 1 3 2 6960 750 803 0.80 2.20 335321 50376 2.20 2.80 2.60 0.00 1.80 19.40 37.20 61.00 147.60 1.7 280 1024984
+1 82 1 1 22 1 3985 111 89 5.00 7.20 77540 14371 0.00 0.00 0.00 0.00 0.00 0.80 0.80 256.00 387.80 3.0 1941 1533075
+1 95 1 1 36 52 881 82 93 0.20 0.20 115750 107755 0.00 0.00 0.00 0.00 0.00 0.00 0.00 17.20 24.40 2.4 1581 1537800
+1 55 1 1 39 1 3080 712 165 11.00 10.20 216458 176871 24.20 130.80 348.20 720.80 2.20 43.40 69.80 568.40 1051.20 6.4 119 1744413
+1 96 1 1 0 0 1494 90 54 0.20 0.20 2782 6131 0.40 0.40 0.40 0.00 0.00 0.60 0.60 15.60 18.40 2.0 150 1718720
+1 90 1 1 2 0 2798 145 120 0.40 1.80 26499 36460 0.20 0.20 0.20 0.00 0.20 2.59 2.59 32.34 95.01 3.6 306 1079321
+1 81 1 1 8 2 3488 273 134 6.00 5.00 101956 53951 0.00 0.00 0.00 0.00 0.00 6.80 10.60 246.60 430.40 1.8 427 1008350
+1 78 1 1 74 83 2313 310 162 1.80 3.20 324311 131691 0.00 0.00 0.00 0.00 0.40 31.00 40.40 122.00 441.40 5.0 848 1017496
+1 93 1 1 2 1 1092 80 64 0.60 0.60 152586 85234 0.00 0.00 0.00 0.00 0.00 0.80 1.40 50.60 64.80 2.4 6604 1852661
+1 87 1 1 11 3 2311 197 96 1.40 1.40 142319 28945 5.80 8.20 31.00 47.40 1.40 2.20 10.60 79.00 119.60 2.5 142 1112250
+1 85 1 1 14 9 2521 167 99 1.20 2.00 95741 40725 0.00 0.00 0.00 0.00 0.20 3.20 5.80 113.60 238.60 1.6 1419 963726
+1 0 1 1 12 5 943 78 161 1.40 4.20 169313 185587 2.60 2.60 2.60 0.00 1.00 1.20 2.20 47.20 87.60 186 91 9
+1 84 1 1 44 56 2303 246 153 2.20 4.40 1225925 1104543 0.80 0.80 1.00 1.20 0.20 11.60 12.00 116.20 244.80 1.7 174 1015101
+1 94 1 1 39 54 1231 136 124 1.00 0.40 66365 71032 0.00 0.00 0.00 0.00 0.00 0.00 0.00 51.60 80.40 2.0 1551 998853
+1 89 1 1 4 1 434 40 16 2.20 2.20 86587 12381 0.00 0.00 0.00 0.00 0.00 1.60 2.80 196.20 170.60 1.6 11527 1882008
+1 91 1 1 6 1 2365 91 80 4.00 10.40 31104 26401 0.00 0.00 0.00 0.00 0.00 0.00 0.00 132.20 227.80 1.4 4189 1820699
+1 90 1 1 4 2 2168 207 142 1.00 1.00 266451 26908 0.80 0.80 0.80 0.00 0.60 19.40 20.40 58.60 123.20 1.0 305 1067419
+1 85 1 1 9 0 2578 385 165 2.00 4.40 243996 150373 0.00 0.00 0.00 0.00 0.20 0.20 0.20 265.00 307.20 4.2 2187 1539344
+1 90 1 1 15 2 3028 211 147 0.40 0.40 116391 11256 0.00 0.00 0.00 0.00 0.80 3.80 4.60 25.60 59.20 4.6 398 1309442
+1 73 1 1 22 1 6798 557 436 7.00 2.40 326097 67166 0.00 0.00 0.00 0.00 0.00 10.40 10.40 350.40 546.40 5.8 3897 1345814
+1 77 1 1 45 22 3780 202 128 5.20 6.00 118963 39750 0.00 0.00 0.00 0.00 0.20 12.20 20.40 330.80 541.00 2.7 795 982021
+1 56 1 1 87 57 3900 216 143 12.38 33.93 220639 88324 8.58 25.95 46.31 76.85 0.40 23.75 42.51 468.06 843.11 2.0 165 1104481
+1 89 1 1 47 29 1055 101 86 1.00 1.40 17622 26557 17.76 48.30 87.03 160.48 0.40 35.73 99.00 162.08 201.20 1.7 241 1066601
+1 83 1 1 1 0 5703 351 254 0.40 0.60 141136 85738 0.00 0.00 0.00 0.00 1.00 3.80 7.00 29.60 54.20 1.5 390 1077890
+1 91 1 1 4 2 2865 368 134 0.20 0.20 226324 113731 0.00 0.00 0.00 0.00 0.00 6.40 10.40 24.20 31.00 2.4 960 1527998
+1 83 1 1 58 79 1203 118 128 1.20 1.60 10510 79501 0.00 0.00 0.00 0.00 0.00 45.80 83.00 85.80 181.40 1.3 598 948125
+1 78 1 1 78 18 1979 306 184 6.60 6.60 81263 90651 11.40 22.20 34.40 37.40 2.00 15.20 16.00 308.00 559.40 2.8 275 973173
+1 98 1 1 0 0 230 12 31 0.40 1.60 430 20073 0.00 0.00 0.00 0.00 0.00 0.00 0.00 19.80 23.20 1.0 7828 1875280
+1 94 1 1 1 0 1171 177 100 0.80 0.40 130893 105178 0.00 0.00 0.00 0.00 0.00 0.80 0.80 57.40 69.80 5.6 4008 1605864
+1 92 1 1 2 0 1708 129 96 1.20 1.80 20244 18736 2.40 3.20 3.20 0.00 0.20 3.80 3.80 93.40 156.20 1.8 303 1085696
+1 96 1 1 0 0 180 19 18 0.20 0.20 15803 23954 2.59 2.59 2.40 0.00 0.20 1.00 1.40 15.77 17.76 1.0 285 1752255
+1 90 1 1 10 4 1244 77 83 1.20 3.00 169377 48731 0.00 0.00 0.00 0.00 0.00 0.60 0.60 76.80 143.40 3.0 914 1513603
+1 95 1 1 11 3 813 33 44 0.60 0.60 6232 14433 0.00 0.00 0.00 0.00 0.00 0.00 0.00 52.09 62.03 1.5 730 989538
+1 89 1 1 51 68 3126 163 85 1.00 1.00 482044 67636 8.00 26.20 34.40 69.60 5.40 2.60 3.80 79.60 153.60 2.0 199 1029074
+1 81 1 1 5 0 4222 692 530 2.00 6.60 614486 379180 0.40 0.40 0.40 0.00 0.20 8.60 10.60 175.40 236.40 1.0 357 1092782
+1 0 1 1 3 0 1455 139 86 0.60 0.60 36191 23316 0.00 0.00 0.00 0.00 0.00 4.20 6.80 44.40 54.00 650 94 6
+1 92 1 1 5 0 2877 102 83 0.20 0.20 70516 4055 0.60 0.60 0.60 0.00 0.00 5.00 14.00 21.80 118.80 2.2 649 1412344
+1 95 1 1 6 2 1746 176 39 0.40 0.60 53078 35289 0.00 0.00 0.00 0.00 0.00 0.00 0.00 30.20 84.00 1.4 6830 1826608
+1 83 1 1 5 2 3380 361 186 2.40 1.20 162994 58649 3.79 4.39 4.39 0.00 4.19 2.00 2.40 133.93 305.59 1.0 331 972947
+1 86 1 1 5 3 3590 263 203 1.00 3.81 596993 101007 12.22 18.84 28.26 30.26 15.63 12.02 13.23 66.53 142.08 1.0 239 992026
+1 81 1 1 45 55 2712 123 120 2.40 2.60 126075 194040 2.00 2.20 2.20 0.00 0.40 29.80 38.60 128.40 260.60 1.5 357 990066
+1 89 1 1 24 5 2198 134 137 1.40 1.40 49285 50462 0.00 0.00 0.00 0.00 0.20 1.40 1.60 80.00 98.00 2.8 914 1537662
+1 86 1 1 47 17 2625 340 251 1.60 1.00 87682 214358 3.00 17.20 37.00 310.60 1.00 13.40 22.20 98.00 186.60 1.0 121 1102846
+1 97 1 1 1 0 572 67 50 0.20 0.20 34560 9750 0.00 0.00 0.00 0.00 0.00 1.00 1.40 16.00 18.60 2.2 1347 1713429
+1 80 1 1 23 7 3369 551 347 3.79 2.20 86636 45185 0.00 0.00 0.00 0.00 0.20 19.76 24.35 200.40 360.48 2.2 2732 973673
+1 92 1 1 0 0 209 16 29 0.20 0.20 5044 10538 0.00 0.00 0.00 0.00 0.00 0.40 0.40 13.20 16.80 2.6 2430 1772118
+1 89 1 1 3 1 487 46 41 2.00 2.00 76727 82479 0.00 0.00 0.00 0.00 0.00 1.80 1.80 188.60 160.20 1.2 6294 1850770
+1 82 1 1 30 26 1993 185 160 1.20 1.20 529293 226883 18.16 33.33 34.33 7.39 3.19 27.15 28.74 118.16 218.36 2.0 181 1079669
+1 75 1 1 18 3 3518 445 311 4.60 5.00 350475 143998 7.40 30.20 52.40 61.40 0.80 22.80 25.80 285.00 554.60 4.6 185 1291466
+1 89 1 1 7 5 2153 134 140 0.20 0.20 160748 106148 0.40 0.80 0.80 0.00 0.00 7.58 13.77 15.57 224.55 1.0 785 1066577
+1 82 1 1 16 4 2715 244 137 1.60 1.80 347384 46348 4.00 11.20 23.40 52.80 3.00 12.20 33.60 162.60 281.40 1.0 284 1019566
+1 84 1 1 16 6 2734 219 124 2.20 5.21 234900 68243 0.00 0.00 0.00 0.00 0.20 14.63 21.64 109.82 218.84 2.0 1628 1087989
+1 96 1 1 1 0 419 23 15 1.40 8.40 54345 15243 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.60 111.00 2.8 3716 1821034
+1 72 1 1 11 4 3632 313 124 7.40 18.20 233748 21962 0.00 0.00 0.00 0.00 0.00 10.60 14.40 286.00 518.60 5.4 428 1094683
+1 94 1 1 23 36 3096 149 147 0.20 0.20 34328 42898 0.00 0.00 0.00 0.00 0.00 1.80 1.80 15.60 17.00 2.2 1189 1720062
+1 92 1 1 43 10 1642 153 143 0.40 0.80 114798 271973 6.00 15.20 18.00 5.00 0.20 6.60 12.80 33.00 48.80 4.8 145 1597686
+1 88 1 1 31 25 1942 182 124 1.00 1.00 345184 103592 0.00 0.00 0.00 0.00 0.00 26.40 32.60 54.60 291.80 3.2 9684 1373666
+1 89 1 1 11 6 2975 303 137 1.00 2.61 53887 26547 0.00 0.00 0.00 0.00 0.00 0.80 1.60 71.34 101.40 3.7 808 1110774
+1 0 1 1 26 16 3638 534 238 1.60 3.60 1071680 590668 0.00 0.00 0.00 0.00 55.20 45.80 85.00 151.80 449.80 1805 71 29
+1 63 1 1 62 11 3587 174 142 11.80 35.40 74641 37564 6.20 6.20 6.20 0.00 4.60 5.20 5.20 439.60 734.20 5.2 314 1096350
+1 79 1 1 14 3 3117 457 400 5.21 2.00 143833 30140 1.80 2.00 2.00 0.00 0.20 1.20 1.20 266.13 374.15 3.0 291 969090
+1 82 1 1 10 0 2045 322 283 6.00 1.40 168307 29811 0.60 0.80 0.80 0.00 0.20 1.20 1.20 267.60 372.40 1.4 346 1741760
+1 95 1 1 3 0 2254 107 88 0.60 2.20 206795 72088 0.00 0.00 0.00 0.00 0.00 0.00 0.00 88.00 76.80 3.0 990 1547120
+1 93 1 1 0 0 224 27 24 0.20 0.20 593 5597 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 990 1761512
+1 94 1 1 1 0 5670 199 126 0.20 0.20 13572 50962 1.20 1.40 1.80 0.40 0.20 1.00 1.20 13.20 43.00 1.0 128 1013904
+1 92 1 1 55 66 1676 153 117 0.20 0.20 56689 68826 0.00 0.00 0.00 0.00 0.00 0.60 1.00 23.40 30.20 2.2 1976 1528355
+1 98 1 1 0 0 175 13 19 0.20 0.20 6319 12731 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.77 16.77 1.0 8186 1865405
+1 77 1 1 27 0 5461 176 115 6.40 18.40 107414 87502 1.80 18.40 44.20 65.60 0.00 40.00 40.60 231.20 515.60 3.4 134 1106838
+1 81 1 1 19 14 2843 245 183 2.99 4.79 209223 124323 0.00 0.00 0.00 0.00 0.00 7.98 12.97 192.22 324.35 2.0 2339 1090427
+1 92 1 1 9 1 614 27 29 3.80 3.00 58983 14529 0.00 0.00 0.00 0.00 0.00 3.40 6.20 150.40 244.60 1.4 6182 1856533
+1 85 1 1 11 3 1770 422 149 1.20 1.20 534102 488437 1.40 1.40 1.40 0.00 1.20 30.14 56.29 79.44 198.00 3.4 362 1032634
+1 89 1 1 1 0 4652 276 178 0.80 2.40 93489 25181 1.20 1.40 4.61 9.42 0.20 7.41 7.41 45.09 130.86 1.6 147 1004648
+1 94 1 1 3 1 1299 258 126 0.40 0.40 194200 56983 0.00 0.00 0.00 0.00 0.20 0.00 0.00 43.00 118.80 3.2 967 1540414
+1 90 1 1 22 20 1693 167 87 1.60 4.80 63293 33705 0.00 0.00 0.00 0.00 0.00 0.20 2.80 146.40 236.00 1.3 1682 1081171
+1 82 1 1 44 56 3487 272 182 1.80 1.80 200911 51793 0.00 0.00 0.00 0.00 0.00 20.36 22.55 136.73 239.92 2.0 773 1116289
+1 84 1 1 21 20 3132 145 127 0.80 2.00 53362 63831 0.00 0.00 0.00 0.00 0.00 14.20 15.20 61.60 133.80 1.4 859 1005901
+1 92 1 1 3 1 3736 161 145 0.40 0.40 10611 211654 0.40 0.40 0.40 0.00 0.20 1.80 1.80 31.54 60.08 2.2 277 1382574
+1 77 1 1 20 14 1878 168 100 5.19 15.17 347685 38846 7.58 24.15 47.70 86.63 0.40 39.92 72.85 177.45 342.51 3.2 189 1105273
+1 75 1 1 28 12 4658 366 181 3.20 6.20 652294 177495 9.00 24.80 71.00 106.80 1.60 7.60 11.80 235.80 476.40 6.8 243 1308429
+1 77 1 1 10 2 3723 305 244 0.80 1.39 328181 401702 0.00 0.00 0.00 0.00 2.59 24.10 32.27 69.32 197.01 2.7 1124 1005014
+1 95 1 1 0 0 799 42 28 0.20 0.20 1445 16223 0.00 0.00 0.00 0.00 0.00 0.40 0.60 15.77 20.16 1.0 691 1731210
+1 88 1 1 3 1 510 48 85 2.00 2.00 166234 138252 0.00 0.00 0.00 0.00 0.00 12.57 24.15 182.63 167.47 2.4 5812 1842711
+1 81 1 1 51 72 3680 234 179 0.60 1.20 176480 86286 0.80 5.80 25.80 52.60 0.20 26.00 26.60 65.00 317.60 7.2 203 1308542
+1 88 1 1 0 0 3918 405 245 0.20 0.20 73824 101855 5.99 11.58 14.37 13.57 0.20 8.38 8.98 15.77 193.01 1.5 135 1002566
+1 97 1 1 1 1 1529 78 67 0.20 0.20 26507 41825 0.40 0.40 0.40 0.00 0.00 2.20 2.20 13.03 38.68 1.3 335 1017246
+1 80 1 1 10 1 6019 337 282 0.80 0.80 121389 385351 9.40 11.40 11.20 0.00 1.00 9.00 11.40 49.80 97.20 1.0 289 983114
+1 91 1 1 75 99 1292 75 67 0.60 0.80 16586 38494 0.00 0.00 0.00 0.00 0.00 12.60 12.60 47.00 94.40 1.0 2488 1094443
+1 92 1 1 1 0 1538 155 106 1.00 1.60 15336 20631 0.40 0.40 0.40 0.00 0.00 0.40 0.40 93.20 97.80 3.0 223 1118258
+1 89 1 1 10 3 2239 222 137 0.40 0.60 110938 44047 3.99 5.59 5.59 0.00 2.00 40.92 58.68 28.54 113.97 2.8 286 1096404
+1 98 1 1 1 0 505 35 33 0.20 0.20 3027 21246 0.00 0.00 0.00 0.00 0.00 1.40 1.40 15.40 18.00 2.2 1861 1074888
+1 75 1 1 7 0 2622 154 118 6.60 17.20 109539 47095 0.00 0.00 0.00 0.00 0.00 8.20 9.20 244.40 461.00 1.6 473 1082902
+1 91 1 1 1 0 1272 138 77 0.80 0.80 135403 29470 0.00 0.00 0.00 0.00 1.60 1.80 2.20 62.32 105.21 2.6 425 1057451
+1 80 1 1 35 51 4707 870 741 2.60 1.00 649581 548667 0.00 0.00 0.00 0.00 0.20 4.00 6.00 144.60 244.40 1.0 741 1118274
+1 78 1 1 65 80 5470 745 456 1.00 1.20 197237 121219 1.40 10.40 23.60 68.60 0.80 3.80 6.80 72.00 152.40 1.4 321 1082862
+1 68 1 1 38 1 7447 1700 584 7.40 5.20 721860 553232 7.00 67.00 122.80 271.80 0.40 14.20 81.00 352.40 582.60 7.2 146 1309923
+1 77 1 1 34 16 2849 421 367 7.40 3.20 272508 59603 0.00 0.00 0.00 0.00 0.00 5.00 8.00 365.80 659.80 2.8 6234 1707322
+1 69 1 1 39 45 2827 242 116 6.79 24.15 288688 30965 6.19 13.17 47.50 87.62 4.79 7.58 7.78 389.82 633.93 1.5 256 1031297
+1 89 1 1 18 3 3341 357 278 0.80 2.40 209753 152282 2.00 3.60 3.80 2.00 1.00 17.40 29.60 63.60 113.60 3.4 198 1398704
+1 88 1 1 33 21 2389 161 122 2.00 2.60 219788 28278 0.00 0.00 0.00 0.00 0.00 5.40 8.80 146.20 338.00 3.0 8577 1369232
+1 76 1 1 29 15 4571 564 440 7.00 3.60 228363 43176 0.00 0.00 0.00 0.00 0.40 3.60 4.80 351.20 521.60 3.2 766 1446157
+1 90 1 1 1 1 4795 175 168 0.60 0.80 13037 346069 0.00 0.00 0.00 0.00 0.00 0.20 0.20 39.60 60.00 2.0 1024 1378904
+1 0 1 1 2 1 1133 183 134 0.20 0.20 194225 21523 0.00 0.00 0.00 0.00 0.00 4.40 7.00 18.00 25.80 667 94 6
+1 85 1 1 26 5 1912 187 144 3.00 3.20 357583 165363 7.20 8.40 8.40 0.00 5.00 10.40 19.20 157.00 250.20 2.4 302 1536163
+1 91 1 1 6 0 1063 66 48 1.40 1.40 156950 40098 0.00 0.00 0.00 0.00 0.20 1.60 2.00 290.42 166.07 1.0 739 1038885
+1 80 1 1 4 1 4174 435 389 2.60 3.00 241550 220264 0.80 1.20 1.20 0.00 0.20 59.60 61.80 165.80 363.60 2.4 252 1130003
+1 80 1 1 4 1 4682 556 502 2.00 0.80 374054 397653 0.00 0.00 0.00 0.00 0.20 7.20 8.00 112.20 179.60 2.2 474 1096338
+1 86 1 1 31 41 5305 225 177 0.20 0.20 58099 75714 0.80 2.60 20.00 34.80 0.40 10.80 39.00 21.20 97.80 2.0 371 1060971
+1 79 1 1 7 0 3918 360 321 3.60 2.60 130383 67078 0.00 0.00 0.00 0.00 0.00 1.20 2.00 180.80 345.80 1.0 462 1059221
+1 89 1 1 10 4 1750 191 69 0.20 0.20 95403 9137 0.00 0.00 0.00 0.00 0.00 3.80 5.00 38.00 40.20 1.6 1086 1762445
+1 96 1 1 1 0 1218 76 73 0.60 1.40 272091 34204 0.00 0.00 0.00 0.00 0.00 0.80 1.20 58.00 59.20 2.8 615 1534221
+1 87 1 1 1 0 7657 253 208 0.20 0.20 98585 54427 0.00 0.00 0.00 0.00 0.20 0.20 0.20 16.40 25.40 1.3 591 1077248
+1 85 1 1 7 0 2144 344 296 6.60 1.80 203939 12761 0.00 0.00 0.00 0.00 0.00 0.00 0.00 311.20 448.20 2.6 7276 1846826
+1 82 1 1 2 2 3958 527 226 0.60 1.80 290157 135926 5.80 16.40 53.40 67.00 0.60 11.60 20.40 39.40 63.20 2.2 132 1125998
+1 93 1 1 4 1 1285 143 92 0.40 0.80 15502 36431 0.00 0.00 0.00 0.00 0.00 6.60 6.60 40.40 86.20 2.8 1582 1537486
+1 72 1 1 90 83 3018 296 128 5.19 5.59 296804 31129 0.80 0.80 0.80 0.00 0.40 8.18 14.17 345.11 705.59 1.0 559 1085472
+1 91 1 1 2 1 3358 282 126 0.20 0.20 808678 39710 0.00 0.00 0.00 0.00 0.00 8.60 12.00 17.20 68.00 3.0 360 1452310
+1 74 1 1 19 7 4247 337 240 1.60 2.80 372442 147253 20.20 79.80 123.40 212.60 2.60 49.20 85.00 107.20 395.00 1.0 158 1006832
+1 74 1 1 10 0 2301 180 77 7.40 24.40 143010 16978 0.00 0.00 0.00 0.00 0.20 5.20 5.20 272.80 511.40 1.8 264 1089357
+1 62 1 1 75 45 3882 199 97 11.00 35.00 125564 27633 0.20 0.40 0.40 0.00 0.00 21.20 29.00 349.40 701.40 1.8 262 1106469
+1 89 1 1 11 10 2843 499 206 0.60 2.40 644540 560547 3.20 12.40 18.00 27.40 0.60 12.20 15.40 41.60 126.20 1.4 184 1043746
+1 77 1 1 1 0 8840 492 321 0.20 0.20 24851 65220 3.20 9.40 47.80 78.00 0.00 37.20 37.80 20.60 138.60 2.3 131 1058443
+1 70 1 1 11 0 4575 643 547 8.78 2.40 261177 27758 0.40 0.40 0.40 0.00 0.80 3.59 4.59 422.95 674.45 1.0 763 1020744
+1 88 1 1 4 0 1479 219 194 4.00 1.20 106304 8465 0.00 0.00 0.00 0.00 0.00 0.00 0.00 201.80 283.60 1.0 7349 1864163
+1 83 1 1 55 74 3992 406 333 1.80 1.40 236911 225773 1.60 1.80 1.80 0.00 1.00 1.00 1.20 121.00 196.00 2.8 391 1123736
+1 90 1 1 4 0 1723 81 55 0.80 0.80 141172 28012 0.00 0.00 0.00 0.00 0.00 8.02 25.05 67.54 161.12 2.8 517 1068305
+1 96 1 1 16 23 701 40 33 0.40 0.40 46977 41240 0.00 0.00 0.00 0.00 0.00 0.00 0.00 37.13 41.92 1.6 8402 1861517
+1 70 1 1 11 0 5423 585 508 8.18 2.20 455277 27670 0.60 0.60 0.60 0.00 1.60 1.80 2.99 413.77 589.82 4.4 276 1706392
+1 82 1 1 10 1 3429 191 201 1.00 1.80 114285 50592 0.00 0.00 0.00 0.00 0.20 15.40 27.20 272.80 224.20 3.7 699 1039192
+1 87 1 1 9 6 1770 208 116 2.00 2.00 76625 27792 6.40 6.60 6.60 0.00 2.80 0.40 0.40 119.60 206.40 1.4 245 1067682
+1 97 1 1 0 0 382 57 14 0.20 0.20 347005 7518 0.00 0.00 0.00 0.00 0.00 0.20 0.40 16.63 17.84 1.2 972 1746730
+1 98 1 1 19 25 179 10 23 0.20 0.20 2064 8280 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.2 7382 1874901
+1 84 1 1 31 13 3597 687 374 0.80 1.20 171212 118051 0.00 0.00 0.00 0.00 0.00 6.99 13.17 106.19 100.40 4.6 432 1535051
+1 77 1 1 13 2 5673 356 250 4.40 7.60 366128 176393 10.80 24.00 57.20 101.40 1.60 12.20 44.80 221.20 411.40 2.0 141 983581
+1 97 1 1 0 0 771 25 26 0.20 0.20 15308 24778 0.00 0.00 0.00 0.00 0.00 3.20 5.40 15.60 17.60 1.2 613 1752872
+1 72 1 1 19 7 2730 178 113 3.00 4.60 656621 547133 63.80 150.00 170.20 186.60 1.60 4.20 4.80 314.60 295.40 3.0 158 1528717
+1 95 1 1 1 0 1135 96 95 0.20 0.20 3079 12149 0.00 0.00 0.00 0.00 0.00 0.40 0.60 15.60 18.00 1.2 599 1731042
+1 97 1 1 10 10 983 184 84 0.20 0.20 248551 189255 0.00 0.00 0.00 0.00 0.00 0.00 0.00 21.00 21.40 3.2 2694 1583341
+1 0 1 1 67 47 1880 369 144 2.40 3.20 558976 549673 0.00 0.00 0.00 0.00 0.00 0.00 0.00 150.80 233.20 771 87 13
+1 79 1 1 7 1 1691 99 105 6.01 17.64 62475 60755 2.61 13.03 16.63 32.46 0.40 14.63 20.84 201.80 379.56 1.0 142 1105557
+1 94 1 1 1 0 1518 66 70 0.20 0.20 12246 27009 2.00 2.61 2.20 0.00 0.00 3.01 4.21 13.03 125.25 1.0 233 1016173
+1 87 1 1 36 42 2126 176 134 2.40 0.80 307257 243412 0.00 0.00 0.00 0.00 60.80 0.60 0.60 122.00 239.40 3.6 2048 1725027
+1 92 1 1 3 1 1067 157 28 1.80 1.80 464877 6537 0.00 0.00 0.00 0.00 0.00 1.00 1.20 125.75 190.42 2.0 517 1728779
+1 89 1 1 0 0 248 16 29 0.60 0.40 800 7862 0.00 0.00 0.00 0.00 0.00 0.00 0.00 31.94 42.91 1.8 970 1757734
+1 89 1 1 7 7 1243 218 79 0.40 0.40 1182330 23285 9.40 31.60 125.00 179.00 0.20 6.80 10.20 33.20 199.20 1.0 152 1171952
+1 94 1 1 7 2 2715 185 94 0.60 2.80 178325 182757 0.80 1.00 1.00 0.00 0.40 2.80 2.80 48.40 117.00 3.6 370 1331888
+1 86 1 1 5 0 2014 171 95 4.00 3.60 127863 8310 0.00 0.00 0.00 0.00 0.00 0.60 0.80 219.00 332.80 2.2 1512 1747224
+1 74 1 1 101 105 4419 139 78 5.00 7.20 352137 75612 0.00 0.00 0.00 0.00 0.00 2.00 2.80 264.80 552.40 8.4 578 1308730
+1 91 1 1 38 36 1352 177 163 1.00 1.40 234679 64393 9.80 28.40 48.80 84.40 4.60 14.40 20.00 88.20 158.80 1.5 149 1016574
+1 91 1 1 60 87 3116 167 147 0.40 3.19 47466 66573 9.38 17.17 23.35 19.16 1.60 0.60 0.60 16.37 52.10 1.0 168 983853
+1 99 1 1 0 0 348 51 16 0.20 0.20 19341 18074 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.0 8651 1871976
+1 82 1 1 33 40 731 112 72 2.79 2.99 318492 36947 0.00 0.00 0.00 0.00 0.00 2.40 2.59 227.94 225.55 2.2 1996 1812881
+1 85 1 1 5 1 2048 148 187 0.60 2.20 153060 124675 0.60 1.20 1.20 0.00 2.20 1.00 1.00 71.60 78.60 3.2 300 1518179
+1 73 1 1 9 0 5143 487 347 6.59 3.19 218950 79051 7.78 41.92 61.48 113.37 0.00 4.99 6.19 383.43 627.94 1.0 157 1114036
+1 89 1 1 21 3 1400 154 77 0.40 0.80 313266 20451 11.20 21.80 21.80 0.00 8.00 13.40 24.20 85.60 123.40 2.4 443 1061789
+1 94 1 1 6 5 1463 83 89 0.20 0.20 3034 53378 0.80 0.80 0.80 0.00 0.40 4.60 4.80 21.80 30.40 1.0 167 1128846
+1 94 1 1 0 0 2046 77 103 0.20 0.20 3550 10601 0.00 0.00 0.00 0.00 0.20 0.20 0.20 15.60 16.80 2.2 699 1720400
+1 92 1 1 1 0 268 42 43 0.20 0.20 18237 5721 0.00 0.00 0.00 0.00 0.00 5.40 5.40 15.80 16.80 2.0 613 1746560
+1 79 1 1 13 0 2594 417 362 6.80 2.40 217746 24709 0.00 0.00 0.00 0.00 0.00 1.00 1.00 351.00 501.00 3.0 432 1742651
+1 90 1 1 5 3 2183 140 103 1.00 2.40 96236 20477 2.59 3.19 2.99 0.00 3.19 1.60 1.80 67.66 98.40 1.0 304 1099120
+1 83 1 1 10 1 4871 522 431 1.00 1.80 708698 295910 8.58 54.69 62.87 47.11 0.80 12.97 40.72 89.42 150.90 1.0 261 1044677
+1 92 1 1 4 0 2265 78 108 2.58 2.98 25262 18305 0.00 0.00 0.00 0.00 0.00 0.60 0.60 133.73 187.70 2.4 1134 1709394
+1 90 1 1 0 0 2011 330 243 0.20 0.20 104281 33860 0.00 0.00 0.00 0.00 0.20 0.40 0.60 18.40 27.20 2.2 2976 1736637
+1 87 1 1 9 8 1608 173 148 0.40 0.40 422098 192255 12.02 37.88 68.14 85.37 0.00 17.64 31.66 33.47 86.77 1.0 146 1084374
+1 93 1 1 4 1 2063 131 114 0.60 2.40 28368 52695 0.00 0.00 0.00 0.00 0.00 1.00 1.00 51.40 79.00 2.0 2253 1551627
+1 93 1 1 1 0 443 83 49 1.00 3.60 522666 155858 0.00 0.00 0.00 0.00 74.20 0.00 0.00 46.20 63.20 2.4 1382 1762197
+1 88 1 1 11 7 683 44 53 2.80 2.80 80340 144685 0.00 0.00 0.00 0.00 0.00 3.60 4.80 228.40 262.60 1.8 5247 1842926
+1 83 1 1 5 0 1021 119 57 0.40 0.40 200195 15184 4.40 11.20 16.80 18.60 8.40 15.60 28.80 27.20 98.80 3.8 139 1732986
+1 86 1 1 42 5 1609 116 135 1.80 3.20 48167 115657 4.20 16.80 36.40 112.80 0.60 35.20 66.20 123.00 224.60 2.0 355 1065910
+1 81 1 1 2 2 4823 276 267 0.80 1.40 578780 116251 8.22 29.46 86.17 728.86 0.40 71.54 113.83 44.29 118.44 1.3 166 1017270
+1 98 1 1 1 0 2126 120 72 0.20 0.20 18017 55400 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.40 16.80 2.0 3258 1657448
+1 98 1 1 0 0 139 13 12 0.20 0.20 979 5195 3.80 3.80 3.80 0.00 0.20 0.00 0.00 15.60 16.80 1.0 321 1755848
+1 97 1 1 1 1 369 184 51 0.20 0.20 311998 299575 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.2 5714 1832986
+1 85 1 1 9 2 1532 179 143 7.20 5.40 419570 11651 0.00 0.00 0.00 0.00 0.00 0.80 1.20 289.00 476.60 2.0 3216 1846592
+1 92 1 1 171 22 2935 235 275 0.20 0.20 90618 314006 11.40 50.80 58.20 38.40 0.00 2.80 2.80 15.80 42.40 2.8 187 1329400
+1 77 1 1 42 57 3647 435 185 2.80 3.80 75594 54490 0.80 0.80 0.80 0.00 0.40 9.80 9.80 190.40 428.00 1.0 424 1124478
+1 87 1 1 3 0 4944 257 200 0.60 2.00 228459 144888 0.00 0.00 0.00 0.00 0.20 4.00 5.00 84.00 82.60 3.0 2246 1533838
+1 96 1 1 0 0 384 106 78 0.20 0.20 373825 348459 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 2.4 1321 1762056
+1 84 1 1 10 7 3269 213 106 2.20 2.40 301574 22453 0.00 0.00 0.00 0.00 0.00 9.78 9.98 162.48 259.68 1.0 811 973052
+1 83 1 1 6 2 772 84 83 2.59 2.99 287951 221075 0.00 0.00 0.00 0.00 0.00 21.56 42.51 212.18 223.75 1.4 6621 1848714
+1 92 1 1 4 3 2319 163 134 1.00 3.99 144616 27375 0.00 0.00 0.00 0.00 0.20 2.00 2.00 44.71 85.23 1.0 410 1016651
+1 85 1 1 3 0 2393 99 206 0.80 2.40 174982 229702 3.60 32.20 92.00 194.80 0.00 23.40 42.80 36.60 65.60 1.6 147 1053766
+1 86 1 1 4 0 4200 252 228 3.41 1.00 97923 42963 3.21 3.81 3.81 0.00 0.20 2.00 2.20 161.72 269.14 1.2 220 1017728
+1 94 1 1 4 2 1797 147 116 0.20 0.20 6141 39596 3.99 5.19 4.79 0.00 0.80 0.80 0.80 26.95 37.33 1.0 204 1055489
+1 87 1 1 4 0 2075 254 204 3.40 1.00 110184 69205 7.80 22.40 59.60 96.20 1.60 82.00 82.40 164.60 374.00 1.4 130 1106848
+1 98 1 1 0 0 246 41 15 0.20 0.20 172229 42402 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.63 16.83 1.4 7071 1858535
+1 87 1 1 6 2 2003 103 134 0.20 0.20 53400 16856 3.80 27.60 68.80 329.80 0.40 8.60 57.80 15.80 28.20 1.0 130 1054803
+1 92 1 1 1 1 1826 214 195 0.60 0.60 24066 37270 0.60 5.40 7.80 8.20 0.20 3.20 4.00 55.00 67.80 1.3 138 1102162
+1 0 1 1 71 80 1052 221 157 0.40 0.40 145004 48770 1.40 1.60 3.80 3.80 3.60 10.40 15.40 36.60 120.40 896 89 11
+1 69 1 1 40 1 2330 228 81 10.60 21.80 955802 67045 7.00 22.00 68.60 101.20 1.40 51.80 53.20 359.60 761.80 4.4 122 1107003
+1 83 1 1 4 0 1641 156 75 0.20 0.20 242121 40298 0.00 0.00 0.00 0.00 0.00 4.80 57.00 13.40 22.00 2.2 1737 1770982
+1 98 1 1 1 0 1338 77 75 0.60 3.40 86591 15400 0.00 0.00 0.00 0.00 0.00 0.20 0.20 23.20 30.80 2.2 3308 1709498
+1 92 1 1 1 0 2371 167 117 0.20 0.20 6600 32354 1.40 1.60 1.60 0.00 0.00 1.00 1.00 16.17 25.35 2.5 149 1055497
+1 78 1 1 10 2 2981 190 107 1.00 2.00 670209 86240 16.00 119.40 233.40 460.00 0.40 62.60 108.80 75.00 367.80 5.6 137 1317451
+1 84 1 1 3 0 3580 278 230 3.19 1.00 292840 55884 0.00 0.00 0.00 0.00 0.40 18.76 23.15 163.07 358.08 4.2 1006 1388792
+1 98 1 1 0 0 160 13 18 0.20 0.20 2085 4636 0.00 0.00 0.00 0.00 0.00 0.00 0.00 15.60 16.80 1.0 7426 1866406
+1 96 1 1 2 1 637 102 95 0.40 0.20 37606 49019 0.00 0.00 0.00 0.00 0.20 17.80 17.80 19.20 61.80 1.5 391 1092827
+1 93 1 1 10 1 1564 157 137 0.60 0.60 184137 59736 0.00 0.00 0.00 0.00 0.00 6.20 10.40 52.40 87.80 1.3 485 1067194
+1 85 1 1 15 11 2599 277 234 3.61 2.20 133465 102035 17.03 31.46 50.10 46.29 10.22 10.02 15.83 187.78 297.80 2.0 139 1731732
+1 69 1 1 74 49 2688 176 103 11.00 32.20 57714 38484 0.80 1.00 1.00 0.00 0.00 0.80 0.80 343.20 649.40 7.0 314 1096333
+1 88 1 1 29 40 1906 118 90 0.80 2.00 8175 27313 0.00 0.00 0.00 0.00 0.00 0.80 0.80 56.20 78.60 3.6 166 1107088
+1 92 1 1 3 0 926 90 67 0.60 1.00 5411 19322 0.00 0.00 0.00 0.00 0.40 0.40 0.40 53.40 154.00 1.0 1177 1020400
+1 96 1 1 4 0 418 30 29 0.80 1.00 3959 10679 0.00 0.00 0.00 0.00 0.00 0.20 0.20 61.00 73.20 2.4 6355 1702592
+1 80 1 1 5 0 1888 248 215 6.20 1.80 216420 39346 0.00 0.00 0.00 0.00 0.00 7.40 14.80 296.60 420.20 4.6 1628 1757696
diff --git a/library/cpp/linear_regression/benchmark/delta_ailerons.features b/library/cpp/linear_regression/benchmark/delta_ailerons.features
new file mode 100644
index 0000000000..f6f049686d
--- /dev/null
+++ b/library/cpp/linear_regression/benchmark/delta_ailerons.features
@@ -0,0 +1,7129 @@
+1 -0.0001 1 1 0.0020 0.0025 0.015 0.010 -0.00004
+1 0.0003 1 1 -0.0023 0.0003 0.022 -0.011 0.00005
+1 -0.0002 1 1 0.0059 -0.0006 0.014 -0.005 0.00017
+1 -0.0002 1 1 0.0046 0.0001 0.011 0.015 -0.00009
+1 0.0002 1 1 -0.0076 0.0012 0.010 0.001 -0.00010
+1 0.0001 1 1 -0.0073 0.0013 0.010 -0.013 0.00006
+1 -0.0001 1 1 0.0054 0.0027 0.017 -0.022 0.00014
+1 -0.0001 1 1 0.0061 0.0018 0.019 -0.008 -0.00001
+1 0.0001 1 1 -0.0038 0.0008 0.015 -0.014 0.00001
+1 0.0001 1 1 0.0041 0.0012 0.013 -0.011 0.00005
+1 -0.0001 1 1 0.0058 0.0012 0.014 0.002 0.00004
+1 -0.0001 1 1 0.0056 0.0013 0.014 0.010 -0.00004
+1 0.0002 1 1 -0.0067 0.0001 0.012 0.004 -0.00011
+1 -0.0002 1 1 0.0042 0.0027 0.008 -0.007 0.00009
+1 0.0001 1 1 -0.0033 0.0004 0.013 -0.013 0.00000
+1 -0.0001 1 1 0.0044 0.0015 0.009 -0.001 0.00001
+1 -0.0002 1 1 0.0044 0.0004 0.008 0.010 0.00008
+1 0.0002 1 1 -0.0047 -0.0004 0.016 0.008 -0.00008
+1 -0.0001 1 1 0.0047 -0.0002 0.003 0.005 0.00014
+1 -0.0002 1 1 0.0059 0.0017 0.005 0.013 0.00004
+1 0.0001 1 1 -0.0054 0.0007 0.017 0.015 -0.00011
+1 0.0001 1 1 -0.0061 0.0008 0.017 0.005 -0.00002
+1 -0.0002 1 1 0.0043 -0.0004 0.007 -0.006 0.00013
+1 0.0002 1 1 -0.0051 0.0014 0.011 -0.014 -0.00003
+1 -0.0002 1 1 0.0067 0.0002 0.010 0.000 0.00004
+1 0.0001 1 1 0.0048 0.0012 0.011 0.011 -0.00017
+1 0.0001 1 1 -0.0038 0.0008 0.011 0.015 -0.00020
+1 0.0002 1 1 -0.0067 0.0001 0.009 0.006 -0.00014
+1 -0.0001 1 1 0.0053 0.0007 0.005 -0.002 0.00004
+1 -0.0002 1 1 0.0031 0.0019 0.008 0.010 -0.00011
+1 0.0001 1 1 -0.0065 0.0022 0.014 0.005 -0.00017
+1 0.0002 1 1 -0.0068 -0.0008 0.011 -0.010 0.00010
+1 -0.0001 1 1 0.0067 0.0020 0.003 -0.004 0.00008
+1 -0.0002 1 1 0.0044 0.0023 0.007 0.011 -0.00013
+1 0.0003 1 1 -0.0088 0.0016 0.014 -0.009 -0.00010
+1 0.0001 1 1 -0.0047 -0.0001 0.012 -0.028 0.00024
+1 -0.0001 1 1 0.0057 -0.0001 0.007 -0.026 0.00022
+1 -0.0001 1 1 0.0088 0.0001 0.004 -0.004 0.00003
+1 -0.0001 1 1 0.0068 0.0013 0.006 0.013 -0.00014
+1 0.0001 1 1 -0.0074 0.0014 0.011 0.006 -0.00010
+1 -0.0001 1 1 0.0050 0.0010 0.012 -0.022 0.00016
+1 0.0001 1 1 -0.0045 0.0005 0.011 -0.011 -0.00005
+1 0.0002 1 1 -0.0058 0.0016 0.009 -0.014 -0.00005
+1 -0.0001 1 1 0.0080 0.0011 0.010 -0.005 0.00008
+1 -0.0001 1 1 0.0054 0.0014 0.012 0.015 -0.00014
+1 0.0001 1 1 -0.0036 0.0015 0.015 0.019 -0.00017
+1 0.0001 1 1 -0.0061 0.0014 0.017 0.002 -0.00003
+1 0.0001 1 1 -0.0035 -0.0005 0.017 -0.012 0.00012
+1 -0.0002 1 1 0.0065 -0.0001 0.012 -0.003 0.00014
+1 -0.0002 1 1 0.0023 0.0012 0.012 0.027 -0.00015
+1 0.0002 1 1 -0.0052 0.0009 0.013 0.023 -0.00029
+1 0.0001 1 1 -0.0038 -0.0008 0.007 -0.010 0.00012
+1 -0.0002 1 1 0.0045 0.0019 0.000 -0.006 0.00011
+1 0.0001 1 1 -0.0040 0.0015 0.009 -0.010 -0.00001
+1 -0.0001 1 1 0.0051 0.0011 0.008 -0.007 0.00011
+1 -0.0001 1 1 0.0022 0.0014 0.010 0.010 -0.00010
+1 0.0002 1 1 -0.0034 0.0016 0.013 0.008 -0.00013
+1 -0.0001 1 1 0.0039 0.0002 0.008 0.010 0.00001
+1 0.0001 1 1 -0.0059 0.0008 0.011 0.006 -0.00016
+1 0.0001 1 1 -0.0053 0.0004 0.010 -0.010 0.00007
+1 -0.0002 1 1 0.0059 0.0021 0.003 0.003 0.00001
+1 0.0003 1 1 -0.0078 0.0020 0.010 0.002 -0.00022
+1 -0.0001 1 1 0.0065 0.0002 0.004 -0.014 0.00018
+1 -0.0003 1 1 0.0084 0.0023 0.004 0.002 0.00004
+1 0.0001 1 1 0.0042 0.0028 0.009 0.017 -0.00028
+1 0.0001 1 1 -0.0046 0.0026 0.018 0.015 -0.00016
+1 0.0001 1 1 -0.0022 0.0020 0.001 -0.010 -0.00002
+1 -0.0002 1 1 0.0040 0.0013 0.004 -0.007 0.00011
+1 0.0001 1 1 -0.0031 0.0012 0.016 -0.010 0.00000
+1 -0.0003 1 1 0.0048 -0.0009 0.010 -0.007 0.00018
+1 0.0002 1 1 -0.0059 0.0008 0.009 -0.014 -0.00003
+1 -0.0001 1 1 0.0045 0.0003 0.005 -0.024 0.00022
+1 -0.0001 1 1 0.0077 0.0005 0.003 -0.007 0.00004
+1 -0.0002 1 1 0.0056 0.0018 0.005 0.011 -0.00012
+1 -0.0003 1 1 0.0055 0.0001 0.010 0.013 0.00009
+1 -0.0001 1 1 -0.0003 0.0005 0.012 0.027 -0.00013
+1 -0.0001 1 1 0.0033 0.0002 0.006 0.028 0.00001
+1 0.0002 1 1 -0.0051 0.0007 0.006 -0.010 0.00007
+1 -0.0002 1 1 0.0090 0.0012 0.004 0.004 0.00014
+1 0.0001 1 1 -0.0042 0.0028 0.018 0.024 -0.00019
+1 -0.0001 1 1 0.0039 -0.0007 0.009 0.007 0.00013
+1 0.0001 1 1 -0.0051 0.0007 0.008 -0.010 0.00007
+1 -0.0002 1 1 0.0055 0.0025 0.005 -0.002 0.00003
+1 -0.0001 1 1 0.0002 0.0019 0.010 0.010 -0.00016
+1 0.0003 1 1 -0.0045 0.0021 0.013 0.005 -0.00018
+1 -0.0002 1 1 0.0040 0.0004 0.010 -0.008 0.00017
+1 -0.0001 1 1 0.0039 0.0007 0.010 0.011 -0.00004
+1 0.0002 1 1 -0.0047 0.0009 0.011 0.008 -0.00011
+1 0.0001 1 1 -0.0007 0.0006 0.010 -0.010 0.00010
+1 -0.0002 1 1 0.0031 -0.0005 0.006 -0.007 0.00014
+1 0.0001 1 1 -0.0030 0.0010 0.006 -0.012 0.00000
+1 -0.0001 1 1 0.0068 0.0006 0.004 0.004 0.00007
+1 0.0002 1 1 -0.0071 0.0004 0.012 0.001 -0.00007
+1 0.0001 1 1 -0.0052 0.0006 0.011 -0.013 0.00018
+1 -0.0001 1 1 0.0065 0.0005 0.009 -0.008 0.00016
+1 -0.0001 1 1 0.0080 0.0029 0.011 0.005 0.00003
+1 0.0002 1 1 -0.0077 0.0000 0.015 0.007 -0.00008
+1 0.0006 1 1 -0.0112 0.0004 0.020 -0.009 -0.00011
+1 -0.0001 1 1 0.0065 0.0011 0.013 -0.006 0.00000
+1 -0.0003 1 1 0.0045 0.0004 0.012 0.010 -0.00009
+1 0.0005 1 1 -0.0048 0.0003 0.016 0.011 -0.00028
+1 -0.0002 1 1 0.0043 -0.0005 0.013 -0.003 0.00003
+1 0.0001 1 1 -0.0037 0.0016 0.015 0.000 -0.00011
+1 0.0002 1 1 -0.0036 0.0016 0.016 -0.010 0.00003
+1 -0.0002 1 1 0.0051 0.0018 0.010 -0.005 0.00010
+1 -0.0001 1 1 0.0021 0.0033 0.019 0.010 -0.00014
+1 0.0004 1 1 -0.0054 -0.0003 0.017 0.005 -0.00023
+1 0.0002 1 1 -0.0012 0.0001 0.014 -0.010 0.00020
+1 -0.0002 1 1 0.0047 -0.0009 0.010 -0.006 0.00027
+1 -0.0001 1 1 0.0084 0.0014 0.011 0.018 0.00003
+1 -0.0001 1 1 0.0071 -0.0002 0.013 0.033 -0.00009
+1 -0.0001 1 1 0.0021 0.0000 0.011 0.046 -0.00020
+1 0.0002 1 1 -0.0056 0.0004 0.011 0.041 -0.00026
+1 -0.0001 1 1 -0.0009 0.0004 0.007 -0.009 0.00018
+1 -0.0001 1 1 0.0045 0.0022 0.010 -0.004 0.00020
+1 -0.0001 1 1 0.0063 0.0017 0.013 0.012 0.00001
+1 -0.0001 1 1 0.0042 0.0009 0.015 0.031 -0.00008
+1 0.0001 1 1 -0.0068 -0.0005 0.011 0.015 -0.00006
+1 0.0001 1 1 0.0000 -0.0004 0.002 -0.009 0.00012
+1 -0.0002 1 1 0.0027 0.0022 0.005 -0.007 0.00013
+1 0.0001 1 1 -0.0042 0.0035 0.016 -0.007 -0.00017
+1 0.0001 1 1 0.0052 -0.0016 0.002 -0.009 0.00005
+1 -0.0002 1 1 0.0069 0.0023 0.005 0.005 0.00006
+1 -0.0001 1 1 0.0052 0.0025 0.010 0.024 -0.00010
+1 0.0001 1 1 -0.0049 0.0007 0.016 0.017 -0.00006
+1 0.0001 1 1 -0.0043 0.0006 0.010 -0.002 -0.00006
+1 -0.0001 1 1 0.0035 0.0017 0.011 0.012 -0.00005
+1 -0.0002 1 1 0.0035 -0.0002 0.012 -0.009 0.00017
+1 0.0001 1 1 -0.0039 0.0015 0.008 -0.011 0.00000
+1 -0.0001 1 1 0.0059 0.0004 0.009 0.015 -0.00002
+1 -0.0001 1 1 -0.0036 0.0007 0.010 0.021 -0.00016
+1 0.0003 1 1 -0.0066 -0.0005 0.008 0.012 -0.00015
+1 0.0001 1 1 -0.0018 0.0008 0.002 -0.010 0.00014
+1 -0.0002 1 1 0.0047 0.0021 0.006 -0.006 0.00022
+1 0.0003 1 1 -0.0049 -0.0011 0.009 0.022 -0.00014
+1 -0.0002 1 1 0.0023 -0.0008 0.001 0.011 0.00015
+1 0.0001 1 1 -0.0056 0.0017 0.016 0.004 -0.00004
+1 0.0001 1 1 -0.0042 -0.0002 0.013 -0.013 0.00007
+1 -0.0001 1 1 0.0070 -0.0006 0.007 -0.005 0.00013
+1 -0.0001 1 1 0.0057 0.0016 0.009 0.017 -0.00009
+1 0.0001 1 1 -0.0075 -0.0001 0.010 -0.013 0.00004
+1 0.0001 1 1 -0.0042 0.0007 0.009 -0.030 0.00018
+1 0.0001 1 1 0.0071 0.0018 0.007 -0.022 0.00018
+1 -0.0002 1 1 0.0104 0.0043 0.014 -0.003 0.00011
+1 -0.0001 1 1 0.0057 0.0009 0.020 0.025 -0.00022
+1 0.0002 1 1 -0.0059 0.0057 0.005 0.005 -0.00015
+1 0.0001 1 1 0.0046 0.0001 0.016 -0.013 0.00029
+1 -0.0002 1 1 0.0088 -0.0025 0.013 -0.004 0.00031
+1 -0.0002 1 1 0.0101 -0.0013 0.009 0.016 -0.00004
+1 0.0001 1 1 0.0004 -0.0008 0.004 0.037 -0.00034
+1 0.0002 1 1 -0.0048 0.0008 0.005 0.029 -0.00013
+1 0.0001 1 1 -0.0048 0.0051 0.010 0.021 -0.00020
+1 0.0002 1 1 -0.0066 -0.0005 0.010 0.007 -0.00003
+1 -0.0002 1 1 0.0039 0.0021 0.010 -0.007 0.00014
+1 0.0002 1 1 -0.0022 0.0031 0.006 -0.011 -0.00004
+1 -0.0001 1 1 0.0073 0.0026 0.007 0.006 0.00003
+1 0.0003 1 1 -0.0075 -0.0016 0.007 0.014 -0.00020
+1 -0.0003 1 1 0.0049 -0.0019 0.003 0.014 -0.00009
+1 0.0002 1 1 -0.0084 0.0024 0.010 0.005 -0.00022
+1 0.0002 1 1 -0.0088 -0.0003 0.008 -0.013 0.00006
+1 -0.0002 1 1 0.0056 0.0035 0.012 -0.026 0.00031
+1 0.0001 1 1 0.0044 0.0000 0.017 0.012 -0.00010
+1 0.0002 1 1 -0.0056 0.0026 0.002 0.008 -0.00012
+1 -0.0002 1 1 0.0034 0.0016 0.012 -0.007 0.00015
+1 0.0001 1 1 -0.0026 -0.0014 0.005 -0.011 0.00003
+1 -0.0004 1 1 0.0055 0.0029 0.005 -0.002 0.00011
+1 0.0003 1 1 -0.0050 0.0006 0.016 0.000 -0.00020
+1 -0.0002 1 1 0.0038 0.0014 0.006 -0.007 0.00010
+1 -0.0003 1 1 0.0035 -0.0002 0.000 0.010 0.00006
+1 0.0001 1 1 -0.0098 -0.0003 0.010 -0.013 -0.00011
+1 0.0003 1 1 -0.0082 0.0000 0.009 -0.030 0.00021
+1 -0.0001 1 1 0.0112 0.0014 0.016 -0.002 0.00008
+1 -0.0002 1 1 0.0089 -0.0033 0.013 0.034 -0.00019
+1 -0.0002 1 1 0.0023 -0.0015 0.009 0.046 -0.00036
+1 0.0004 1 1 -0.0075 -0.0011 0.006 0.041 -0.00051
+1 -0.0003 1 1 0.0062 -0.0013 0.016 0.013 0.00012
+1 0.0003 1 1 -0.0067 -0.0015 0.011 0.018 -0.00022
+1 -0.0004 1 1 0.0064 -0.0012 0.000 0.013 0.00009
+1 0.0002 1 1 -0.0089 0.0049 0.012 0.009 -0.00025
+1 -0.0001 1 1 0.0070 -0.0006 0.012 -0.014 0.00032
+1 -0.0001 1 1 0.0101 -0.0005 0.011 0.000 0.00014
+1 -0.0003 1 1 0.0105 -0.0002 0.009 0.023 -0.00003
+1 -0.0003 1 1 0.0011 -0.0013 0.003 0.044 -0.00035
+1 0.0004 1 1 -0.0072 -0.0009 0.002 0.040 -0.00058
+1 -0.0002 1 1 0.0034 -0.0007 0.009 -0.007 0.00003
+1 0.0001 1 1 -0.0038 0.0039 0.013 -0.006 -0.00016
+1 -0.0001 1 1 0.0068 -0.0011 0.011 -0.009 0.00016
+1 -0.0003 1 1 0.0066 -0.0009 0.007 0.012 -0.00005
+1 0.0002 1 1 -0.0072 -0.0025 0.007 0.006 -0.00011
+1 0.0001 1 1 -0.0037 -0.0005 0.003 -0.011 0.00021
+1 -0.0004 1 1 0.0064 0.0007 0.002 -0.006 0.00022
+1 0.0004 1 1 -0.0067 -0.0002 0.008 0.004 -0.00039
+1 -0.0001 1 1 0.0029 -0.0009 -0.001 -0.008 0.00028
+1 -0.0002 1 1 0.0070 0.0040 0.006 0.003 0.00016
+1 0.0003 1 1 -0.0045 0.0025 0.019 0.018 -0.00022
+1 0.0001 1 1 -0.0031 0.0015 0.011 -0.012 0.00000
+1 -0.0001 1 1 0.0044 0.0003 0.009 0.015 -0.00006
+1 0.0002 1 1 -0.0076 0.0007 0.009 -0.014 -0.00001
+1 -0.0002 1 1 0.0049 0.0011 0.010 -0.024 0.00021
+1 0.0001 1 1 0.0005 -0.0017 0.003 -0.009 0.00015
+1 -0.0002 1 1 0.0039 0.0020 0.005 -0.005 0.00018
+1 -0.0002 1 1 0.0034 0.0000 0.009 0.010 -0.00004
+1 0.0002 1 1 -0.0057 0.0008 0.010 0.005 -0.00015
+1 0.0002 1 1 -0.0051 0.0014 0.012 -0.013 0.00007
+1 -0.0001 1 1 0.0045 -0.0010 0.008 -0.013 0.00004
+1 0.0001 1 1 -0.0005 0.0028 0.015 -0.010 0.00003
+1 -0.0001 1 1 0.0038 0.0013 0.017 -0.006 0.00015
+1 0.0001 1 1 0.0049 0.0016 0.019 0.004 0.00002
+1 -0.0001 1 1 0.0053 -0.0011 0.016 0.013 0.00001
+1 -0.0001 1 1 0.0036 -0.0028 0.009 0.027 -0.00007
+1 -0.0001 1 1 -0.0011 -0.0018 0.003 0.031 -0.00023
+1 0.0002 1 1 -0.0111 0.0012 0.002 -0.017 -0.00004
+1 0.0001 1 1 -0.0096 0.0020 0.004 -0.034 0.00017
+1 0.0001 1 1 -0.0048 0.0018 0.006 -0.047 0.00028
+1 -0.0002 1 1 0.0093 0.0014 0.007 -0.038 0.00030
+1 -0.0001 1 1 0.0055 0.0001 0.021 -0.020 0.00021
+1 -0.0003 1 1 0.0088 -0.0002 0.017 0.012 -0.00001
+1 0.0003 1 1 -0.0075 0.0026 0.014 0.019 -0.00015
+1 0.0001 1 1 -0.0042 0.0017 0.018 -0.010 0.00012
+1 0.0003 1 1 0.0002 0.0008 0.020 -0.009 -0.00007
+1 0.0001 1 1 -0.0011 0.0004 0.009 -0.010 0.00001
+1 0.0001 1 1 -0.0020 0.0016 0.022 -0.016 0.00006
+1 0.0001 1 1 -0.0005 0.0013 0.012 -0.010 -0.00001
+1 -0.0001 1 1 0.0019 0.0007 0.013 0.011 -0.00004
+1 0.0003 1 1 -0.0037 0.0002 0.012 0.007 -0.00011
+1 -0.0002 1 1 0.0055 0.0000 0.009 0.014 0.00007
+1 0.0001 1 1 -0.0038 -0.0001 0.011 0.024 -0.00017
+1 0.0001 1 1 -0.0060 0.0023 0.007 -0.011 0.00005
+1 -0.0001 1 1 0.0055 0.0020 0.019 -0.013 0.00014
+1 0.0001 1 1 -0.0037 0.0032 0.015 0.017 -0.00009
+1 -0.0002 1 1 0.0054 0.0011 0.019 0.024 0.00000
+1 0.0001 1 1 -0.0038 -0.0001 0.016 0.032 -0.00029
+1 0.0002 1 1 -0.0102 -0.0009 0.012 0.011 -0.00016
+1 0.0001 1 1 -0.0094 -0.0003 0.013 -0.010 0.00021
+1 -0.0001 1 1 0.0076 0.0020 0.004 -0.007 0.00009
+1 -0.0001 1 1 0.0070 0.0019 0.006 0.010 -0.00007
+1 0.0002 1 1 -0.0043 -0.0006 0.009 0.018 -0.00012
+1 -0.0001 1 1 0.0004 0.0034 0.019 0.010 -0.00005
+1 -0.0001 1 1 0.0041 -0.0037 -0.001 0.010 0.00017
+1 -0.0002 1 1 0.0057 0.0032 -0.003 0.016 0.00010
+1 -0.0001 1 1 0.0030 0.0037 0.007 0.031 -0.00014
+1 0.0001 1 1 -0.0039 -0.0003 0.012 0.023 -0.00005
+1 0.0002 1 1 -0.0033 -0.0006 0.002 -0.011 0.00001
+1 -0.0001 1 1 0.0045 0.0031 0.007 -0.007 0.00008
+1 -0.0001 1 1 0.0028 -0.0018 0.017 0.011 0.00001
+1 0.0002 1 1 -0.0037 -0.0006 0.007 0.005 -0.00004
+1 -0.0001 1 1 0.0022 0.0000 0.012 0.010 0.00001
+1 0.0001 1 1 -0.0005 0.0008 0.012 -0.010 0.00008
+1 -0.0002 1 1 0.0028 0.0001 0.010 -0.007 0.00012
+1 0.0002 1 1 -0.0044 0.0002 0.012 -0.011 0.00001
+1 0.0001 1 1 -0.0034 0.0014 0.013 0.008 -0.00007
+1 -0.0002 1 1 0.0055 0.0011 0.008 -0.002 0.00008
+1 0.0003 1 1 -0.0040 -0.0015 0.011 0.007 -0.00009
+1 -0.0002 1 1 0.0065 0.0017 0.006 0.013 0.00015
+1 0.0002 1 1 -0.0089 0.0026 0.015 0.005 -0.00009
+1 0.0002 1 1 -0.0051 -0.0020 0.011 -0.013 0.00024
+1 -0.0001 1 1 0.0061 -0.0026 -0.002 -0.012 0.00029
+1 -0.0001 1 1 0.0104 0.0009 -0.001 0.013 0.00003
+1 -0.0001 1 1 0.0040 0.0024 0.005 0.046 -0.00019
+1 -0.0002 1 1 0.0000 -0.0017 0.010 0.032 -0.00003
+1 0.0001 1 1 -0.0037 0.0025 0.014 0.028 -0.00015
+1 0.0001 1 1 -0.0035 0.0004 0.014 0.026 -0.00012
+1 0.0002 1 1 -0.0078 0.0000 0.004 -0.012 -0.00008
+1 0.0002 1 1 -0.0047 0.0015 0.005 -0.031 0.00017
+1 -0.0003 1 1 0.0075 0.0021 0.011 -0.025 0.00022
+1 0.0004 1 1 -0.0085 -0.0015 0.007 -0.009 -0.00019
+1 -0.0002 1 1 0.0057 0.0022 0.006 -0.025 0.00023
+1 -0.0002 1 1 0.0076 0.0024 0.011 -0.004 0.00001
+1 0.0001 1 1 -0.0074 0.0002 0.009 0.003 -0.00026
+1 0.0001 1 1 -0.0100 0.0021 0.011 -0.015 -0.00007
+1 0.0003 1 1 -0.0090 0.0018 0.013 -0.032 0.00010
+1 -0.0003 1 1 0.0077 -0.0002 0.008 -0.041 0.00043
+1 -0.0002 1 1 0.0119 0.0004 0.007 -0.006 -0.00001
+1 -0.0004 1 1 0.0077 0.0034 0.012 0.013 -0.00029
+1 -0.0002 1 1 0.0006 -0.0019 0.014 0.010 0.00021
+1 0.0001 1 1 -0.0041 0.0009 0.001 0.005 -0.00011
+1 0.0001 1 1 -0.0020 0.0025 0.007 -0.013 0.00009
+1 -0.0001 1 1 0.0085 -0.0008 0.006 0.016 0.00006
+1 -0.0001 1 1 0.0063 0.0016 0.007 0.033 -0.00015
+1 0.0002 1 1 -0.0093 -0.0002 0.009 0.014 -0.00009
+1 0.0001 1 1 -0.0053 0.0002 0.006 -0.012 0.00022
+1 -0.0002 1 1 0.0059 -0.0002 0.009 -0.011 0.00024
+1 -0.0001 1 1 0.0069 0.0004 0.008 0.016 -0.00003
+1 -0.0001 1 1 0.0037 0.0027 0.012 0.026 -0.00018
+1 -0.0001 1 1 0.0010 -0.0028 0.010 0.029 -0.00024
+1 0.0002 1 1 -0.0076 -0.0016 0.005 0.021 -0.00030
+1 0.0001 1 1 -0.0098 0.0030 0.009 -0.002 -0.00001
+1 0.0001 1 1 -0.0052 0.0016 0.011 -0.029 0.00017
+1 -0.0001 1 1 0.0039 0.0004 0.009 -0.032 0.00024
+1 -0.0001 1 1 0.0054 0.0006 0.008 0.011 -0.00006
+1 0.0002 1 1 -0.0055 0.0000 0.008 0.013 -0.00018
+1 0.0002 1 1 -0.0022 0.0006 0.007 -0.013 0.00011
+1 -0.0002 1 1 0.0052 0.0012 0.008 -0.008 0.00019
+1 -0.0002 1 1 0.0047 0.0016 0.012 0.012 -0.00007
+1 0.0003 1 1 -0.0039 -0.0009 0.009 0.014 -0.00018
+1 -0.0003 1 1 0.0042 -0.0006 0.009 -0.008 0.00017
+1 0.0002 1 1 -0.0054 0.0013 0.012 -0.007 -0.00019
+1 -0.0001 1 1 0.0085 -0.0018 0.008 -0.005 0.00018
+1 -0.0003 1 1 0.0092 -0.0007 0.006 0.012 -0.00003
+1 0.0001 1 1 0.0019 0.0021 0.008 0.030 -0.00029
+1 0.0003 1 1 -0.0063 -0.0023 0.009 0.023 -0.00019
+1 0.0002 1 1 -0.0088 0.0044 0.011 0.004 -0.00017
+1 -0.0002 1 1 0.0075 -0.0010 0.013 -0.024 0.00041
+1 -0.0001 1 1 0.0100 -0.0003 0.010 0.002 -0.00001
+1 -0.0001 1 1 0.0079 0.0039 0.013 0.021 -0.00025
+1 0.0002 1 1 -0.0048 -0.0009 0.014 0.025 -0.00015
+1 -0.0002 1 1 0.0041 -0.0024 -0.003 0.016 0.00010
+1 -0.0002 1 1 0.0017 0.0036 0.001 0.035 -0.00010
+1 0.0001 1 1 -0.0036 0.0054 0.012 0.033 -0.00025
+1 -0.0003 1 1 0.0063 -0.0018 0.010 -0.012 0.00033
+1 0.0002 1 1 -0.0021 0.0001 0.008 -0.010 0.00000
+1 -0.0002 1 1 0.0042 0.0028 0.010 -0.007 0.00014
+1 -0.0002 1 1 0.0004 -0.0011 0.013 0.009 -0.00001
+1 0.0002 1 1 -0.0071 0.0004 0.004 -0.016 -0.00007
+1 0.0001 1 1 -0.0055 0.0032 0.007 -0.032 0.00012
+1 0.0001 1 1 0.0060 0.0017 0.014 -0.032 0.00022
+1 -0.0003 1 1 0.0105 -0.0020 0.011 -0.016 0.00020
+1 0.0002 1 1 -0.0057 0.0018 0.001 0.010 -0.00030
+1 -0.0001 1 1 0.0047 -0.0009 0.004 -0.005 0.00002
+1 -0.0002 1 1 0.0002 0.0021 0.010 0.010 -0.00010
+1 0.0004 1 1 -0.0048 0.0011 0.011 0.006 -0.00029
+1 0.0002 1 1 -0.0016 0.0012 0.014 -0.010 -0.00001
+1 -0.0004 1 1 0.0053 -0.0007 0.011 -0.007 0.00027
+1 0.0001 1 1 0.0039 0.0010 0.012 0.012 -0.00011
+1 0.0002 1 1 -0.0072 0.0027 0.007 0.005 -0.00017
+1 -0.0003 1 1 0.0055 -0.0011 0.011 -0.030 0.00024
+1 -0.0001 1 1 0.0012 0.0000 0.008 0.011 -0.00003
+1 0.0001 1 1 -0.0040 0.0003 0.007 0.005 -0.00010
+1 -0.0003 1 1 0.0046 -0.0003 0.006 -0.007 0.00020
+1 -0.0001 1 1 0.0030 0.0002 0.004 0.011 -0.00009
+1 0.0003 1 1 -0.0048 0.0035 0.014 0.009 -0.00020
+1 -0.0002 1 1 0.0056 0.0025 0.008 0.011 0.00003
+1 0.0001 1 1 -0.0042 0.0002 0.010 0.016 -0.00008
+1 0.0002 1 1 -0.0030 0.0035 0.009 -0.010 -0.00003
+1 -0.0003 1 1 0.0049 -0.0001 0.013 -0.007 0.00011
+1 -0.0002 1 1 0.0026 0.0020 0.006 -0.007 0.00011
+1 0.0001 1 1 -0.0024 0.0022 0.005 -0.012 -0.00001
+1 0.0001 1 1 -0.0036 0.0017 0.011 -0.032 0.00011
+1 -0.0001 1 1 0.0078 -0.0015 0.009 -0.003 0.00002
+1 -0.0001 1 1 0.0057 -0.0011 0.006 0.012 -0.00012
+1 -0.0001 1 1 0.0047 0.0009 0.009 -0.023 0.00002
+1 -0.0001 1 1 0.0032 0.0011 0.012 -0.007 -0.00006
+1 0.0002 1 1 -0.0048 0.0015 0.018 -0.012 -0.00010
+1 -0.0001 1 1 0.0064 0.0000 0.015 -0.005 0.00006
+1 -0.0001 1 1 0.0063 -0.0020 0.010 0.016 -0.00004
+1 0.0001 1 1 -0.0070 -0.0010 0.008 0.013 -0.00008
+1 -0.0001 1 1 0.0035 0.0010 0.006 -0.002 0.00006
+1 -0.0001 1 1 0.0022 0.0012 0.010 0.011 -0.00006
+1 0.0002 1 1 -0.0040 -0.0002 0.014 0.005 -0.00008
+1 -0.0001 1 1 0.0029 0.0018 0.007 -0.006 0.00007
+1 0.0001 1 1 -0.0022 -0.0006 0.010 -0.013 0.00002
+1 -0.0002 1 1 0.0045 0.0004 0.002 -0.005 0.00006
+1 0.0001 1 1 -0.0021 0.0004 0.008 -0.010 0.00004
+1 -0.0001 1 1 0.0033 0.0022 0.014 -0.006 0.00007
+1 0.0001 1 1 -0.0041 -0.0004 0.012 -0.015 -0.00001
+1 0.0001 1 1 -0.0029 -0.0006 0.010 -0.022 0.00009
+1 -0.0001 1 1 0.0066 0.0011 0.002 -0.002 0.00004
+1 0.0002 1 1 -0.0070 0.0002 0.016 0.005 -0.00007
+1 -0.0001 1 1 0.0069 0.0008 0.001 0.000 0.00006
+1 -0.0002 1 1 0.0052 0.0004 0.002 0.019 -0.00010
+1 0.0001 1 1 -0.0103 0.0020 0.012 0.003 -0.00019
+1 -0.0001 1 1 0.0076 0.0002 0.011 -0.036 0.00018
+1 -0.0001 1 1 0.0088 0.0004 0.011 -0.020 0.00001
+1 -0.0002 1 1 0.0008 -0.0006 0.010 0.010 0.00000
+1 -0.0001 1 1 0.0042 -0.0009 -0.002 0.010 0.00005
+1 0.0002 1 1 -0.0069 0.0031 0.011 0.008 -0.00019
+1 0.0001 1 1 -0.0053 0.0005 0.017 -0.028 0.00012
+1 -0.0001 1 1 0.0067 -0.0007 0.010 -0.023 0.00015
+1 0.0001 1 1 -0.0030 -0.0004 0.006 -0.010 0.00005
+1 -0.0001 1 1 0.0041 0.0014 0.010 -0.005 0.00006
+1 -0.0001 1 1 0.0023 -0.0001 0.015 0.010 -0.00008
+1 0.0001 1 1 -0.0050 0.0029 0.020 0.011 -0.00011
+1 0.0001 1 1 -0.0057 -0.0027 0.020 0.003 -0.00002
+1 -0.0001 1 1 -0.0001 -0.0035 0.006 -0.010 0.00018
+1 -0.0001 1 1 0.0058 0.0004 0.005 0.011 0.00000
+1 -0.0002 1 1 0.0012 0.0006 0.008 0.030 -0.00011
+1 0.0001 1 1 -0.0040 0.0011 0.010 0.028 -0.00026
+1 0.0001 1 1 -0.0071 0.0010 0.011 0.019 -0.00016
+1 -0.0001 1 1 0.0026 0.0006 0.014 0.011 -0.00005
+1 -0.0001 1 1 0.0039 0.0016 0.004 -0.007 0.00013
+1 0.0001 1 1 -0.0035 -0.0010 0.008 -0.015 -0.00001
+1 0.0001 1 1 -0.0025 -0.0011 0.006 -0.020 0.00008
+1 0.0001 1 1 0.0047 0.0007 0.008 -0.005 0.00003
+1 -0.0001 1 1 0.0054 0.0006 0.009 0.005 0.00002
+1 0.0001 1 1 0.0050 0.0007 0.010 0.015 -0.00004
+1 0.0001 1 1 -0.0052 -0.0011 0.005 0.003 -0.00002
+1 -0.0002 1 1 0.0048 0.0014 0.003 -0.005 0.00015
+1 -0.0002 1 1 0.0056 0.0014 0.002 0.014 -0.00001
+1 0.0001 1 1 -0.0082 0.0012 0.011 0.002 -0.00009
+1 0.0001 1 1 -0.0080 0.0003 0.011 -0.011 0.00004
+1 0.0003 1 1 -0.0043 0.0096 0.014 -0.010 0.00034
+1 0.0006 1 1 -0.0041 0.0042 0.007 -0.010 -0.00013
+1 -0.0008 1 1 0.0058 0.0064 0.021 -0.008 0.00012
+1 0.0010 1 1 -0.0076 -0.0019 0.031 -0.012 -0.00015
+1 0.0001 1 1 0.0037 -0.0010 0.018 -0.025 0.00035
+1 -0.0001 1 1 0.0096 -0.0008 0.012 -0.013 0.00028
+1 -0.0009 1 1 0.0122 0.0066 0.017 0.003 0.00012
+1 -0.0002 1 1 0.0075 0.0042 0.023 0.025 -0.00054
+1 0.0016 1 1 -0.0092 -0.0021 0.021 0.023 -0.00083
+1 -0.0006 1 1 0.0067 0.0022 0.017 -0.023 0.00034
+1 0.0001 1 1 0.0007 0.0017 0.020 0.009 -0.00022
+1 -0.0004 1 1 0.0039 0.0020 0.018 0.008 0.00014
+1 0.0007 1 1 -0.0063 0.0024 0.019 0.007 -0.00028
+1 -0.0001 1 1 0.0039 0.0021 0.019 -0.010 0.00027
+1 -0.0005 1 1 0.0066 0.0038 0.020 -0.002 0.00007
+1 0.0013 1 1 -0.0116 0.0009 0.020 -0.011 -0.00041
+1 -0.0008 1 1 0.0118 0.0040 0.009 -0.026 0.00044
+1 -0.0001 1 1 0.0075 0.0036 0.014 0.013 -0.00040
+1 0.0001 1 1 -0.0095 0.0041 0.023 0.004 -0.00027
+1 -0.0005 1 1 0.0103 0.0001 0.020 -0.023 0.00052
+1 -0.0006 1 1 0.0133 0.0024 0.022 -0.001 0.00000
+1 0.0001 1 1 -0.0079 -0.0005 0.006 0.013 -0.00031
+1 0.0001 1 1 0.0036 0.0053 0.021 -0.030 0.00035
+1 -0.0002 1 1 0.0103 -0.0012 0.017 -0.016 0.00029
+1 -0.0001 1 1 0.0124 -0.0006 0.013 0.003 0.00005
+1 -0.0001 1 1 0.0100 -0.0001 0.010 0.019 -0.00022
+1 0.0001 1 1 0.0039 0.0009 0.010 0.031 -0.00036
+1 0.0004 1 1 -0.0038 0.0018 0.010 0.006 -0.00006
+1 0.0008 1 1 -0.0146 0.0009 0.014 -0.008 -0.00022
+1 0.0002 1 1 -0.0076 0.0022 0.012 -0.036 0.00055
+1 -0.0009 1 1 0.0122 0.0027 0.009 -0.028 0.00053
+1 -0.0004 1 1 0.0106 0.0050 0.017 0.013 -0.00039
+1 0.0001 1 1 -0.0044 0.0012 0.019 0.018 -0.00013
+1 -0.0003 1 1 -0.0053 -0.0019 0.015 0.008 -0.00001
+1 0.0004 1 1 -0.0072 -0.0008 0.012 -0.001 -0.00017
+1 -0.0005 1 1 0.0064 0.0013 0.003 -0.005 0.00040
+1 -0.0002 1 1 0.0068 0.0042 0.010 0.019 -0.00011
+1 0.0001 1 1 -0.0044 0.0013 0.018 0.025 -0.00025
+1 0.0001 1 1 -0.0078 -0.0016 0.013 0.016 -0.00022
+1 -0.0007 1 1 0.0050 0.0016 0.015 -0.007 0.00022
+1 0.0004 1 1 -0.0050 0.0011 0.018 -0.002 -0.00032
+1 0.0002 1 1 -0.0049 0.0013 0.017 -0.013 0.00012
+1 -0.0009 1 1 0.0097 -0.0014 0.008 -0.005 0.00033
+1 0.0005 1 1 -0.0085 0.0036 0.010 -0.011 -0.00003
+1 -0.0005 1 1 0.0111 -0.0022 0.011 -0.003 0.00021
+1 -0.0001 1 1 0.0064 0.0008 0.009 0.019 -0.00039
+1 0.0001 1 1 -0.0051 0.0026 0.012 0.021 -0.00045
+1 0.0001 1 1 -0.0101 0.0027 0.014 0.010 -0.00030
+1 0.0008 1 1 -0.0044 -0.0008 0.015 0.007 -0.00031
+1 -0.0001 1 1 0.0075 0.0045 0.006 0.008 0.00022
+1 -0.0002 1 1 0.0018 0.0028 0.012 0.028 -0.00022
+1 -0.0001 1 1 -0.0041 0.0030 0.016 0.026 -0.00034
+1 -0.0003 1 1 0.0030 -0.0005 0.008 -0.005 0.00021
+1 0.0002 1 1 -0.0031 0.0024 0.012 -0.014 0.00000
+1 -0.0007 1 1 0.0065 0.0009 0.010 -0.008 0.00019
+1 0.0001 1 1 -0.0063 0.0023 0.012 -0.002 -0.00049
+1 0.0003 1 1 -0.0120 -0.0036 0.014 -0.021 -0.00009
+1 0.0001 1 1 -0.0081 -0.0024 0.009 -0.041 0.00040
+1 -0.0004 1 1 0.0076 0.0000 -0.001 -0.042 0.00040
+1 -0.0004 1 1 0.0065 0.0034 0.010 -0.005 0.00009
+1 0.0006 1 1 -0.0120 0.0036 0.021 -0.015 -0.00033
+1 -0.0002 1 1 0.0084 -0.0011 0.014 -0.038 0.00039
+1 0.0001 1 1 -0.0033 0.0019 0.005 -0.012 0.00004
+1 -0.0003 1 1 0.0042 0.0020 0.012 -0.007 0.00006
+1 0.0005 1 1 -0.0064 -0.0002 0.012 -0.013 -0.00012
+1 -0.0003 1 1 0.0104 0.0016 0.012 -0.005 0.00023
+1 0.0004 1 1 -0.0104 -0.0001 0.007 0.004 -0.00021
+1 -0.0003 1 1 0.0065 0.0017 0.011 -0.004 0.00020
+1 -0.0002 1 1 0.0059 0.0016 0.011 0.010 -0.00020
+1 0.0006 1 1 -0.0093 0.0000 0.006 0.003 -0.00030
+1 -0.0003 1 1 0.0047 0.0030 0.004 -0.020 0.00036
+1 -0.0001 1 1 0.0075 0.0031 0.010 0.011 -0.00004
+1 0.0001 1 1 -0.0066 0.0016 0.009 0.004 -0.00012
+1 0.0002 1 1 -0.0059 0.0014 0.008 -0.013 0.00007
+1 -0.0002 1 1 0.0058 0.0031 0.014 -0.013 0.00012
+1 -0.0007 1 1 0.0035 -0.0001 0.011 0.010 0.00015
+1 0.0004 1 1 -0.0078 0.0004 0.007 0.009 -0.00050
+1 0.0002 1 1 -0.0119 0.0029 0.010 -0.013 -0.00004
+1 0.0001 1 1 -0.0075 0.0030 0.012 -0.031 0.00037
+1 -0.0001 1 1 0.0083 0.0018 0.014 -0.029 0.00033
+1 -0.0001 1 1 0.0112 0.0010 0.013 -0.011 0.00009
+1 -0.0003 1 1 0.0099 0.0003 0.010 0.018 -0.00011
+1 -0.0004 1 1 0.0047 0.0013 0.011 0.030 -0.00042
+1 0.0002 1 1 -0.0087 0.0029 0.015 0.027 -0.00070
+1 0.0004 1 1 -0.0141 -0.0022 0.008 0.011 -0.00030
+1 -0.0004 1 1 0.0107 0.0024 0.000 -0.005 0.00036
+1 0.0001 1 1 0.0102 0.0074 0.005 0.017 -0.00057
+1 0.0001 1 1 0.0036 0.0036 0.015 0.030 -0.00002
+1 0.0002 1 1 -0.0006 -0.0016 0.008 0.039 -0.00016
+1 -0.0002 1 1 -0.0006 0.0006 0.003 0.036 0.00002
+1 0.0001 1 1 -0.0098 0.0019 0.003 0.020 -0.00030
+1 0.0001 1 1 -0.0121 0.0034 0.007 0.002 -0.00009
+1 0.0003 1 1 -0.0075 0.0041 0.013 -0.029 0.00029
+1 -0.0008 1 1 0.0103 0.0015 0.014 -0.026 0.00048
+1 -0.0007 1 1 0.0063 0.0016 0.016 0.013 0.00005
+1 0.0005 1 1 -0.0133 -0.0014 0.007 0.002 -0.00040
+1 0.0001 1 1 -0.0094 0.0005 0.004 -0.031 0.00034
+1 -0.0002 1 1 0.0113 0.0016 0.011 -0.022 0.00024
+1 -0.0002 1 1 0.0087 0.0015 0.011 0.021 -0.00019
+1 0.0001 1 1 -0.0077 0.0019 0.014 0.025 -0.00033
+1 0.0004 1 1 -0.0034 0.0022 0.003 -0.012 -0.00009
+1 -0.0006 1 1 0.0071 0.0030 0.008 -0.006 0.00020
+1 0.0003 1 1 -0.0035 0.0022 0.011 0.006 -0.00038
+1 0.0002 1 1 -0.0065 0.0017 0.011 -0.012 0.00000
+1 -0.0002 1 1 0.0050 0.0012 0.009 -0.017 0.00021
+1 0.0001 1 1 -0.0038 0.0023 0.009 0.001 -0.00028
+1 0.0003 1 1 -0.0064 0.0018 0.010 -0.011 -0.00007
+1 -0.0001 1 1 0.0039 0.0023 0.013 -0.022 0.00017
+1 0.0001 1 1 0.0060 0.0007 0.011 -0.013 0.00009
+1 -0.0002 1 1 0.0077 0.0003 0.009 -0.002 0.00010
+1 -0.0002 1 1 0.0037 -0.0019 0.007 0.013 -0.00031
+1 -0.0001 1 1 -0.0053 0.0030 0.007 0.012 -0.00047
+1 0.0004 1 1 -0.0122 0.0026 0.009 -0.001 -0.00047
+1 -0.0001 1 1 0.0074 0.0011 0.009 -0.021 0.00036
+1 -0.0001 1 1 0.0088 0.0025 0.011 -0.004 0.00001
+1 -0.0002 1 1 0.0060 0.0037 0.013 0.014 -0.00031
+1 0.0003 1 1 -0.0117 0.0009 0.019 0.005 -0.00047
+1 0.0001 1 1 0.0064 0.0067 0.024 -0.013 0.00017
+1 -0.0006 1 1 0.0096 -0.0004 0.019 0.001 0.00015
+1 0.0007 1 1 -0.0042 -0.0014 0.014 0.019 -0.00062
+1 0.0001 1 1 -0.0087 -0.0015 0.010 0.002 -0.00005
+1 0.0002 1 1 -0.0019 0.0020 0.019 -0.028 -0.00008
+1 -0.0001 1 1 0.0015 -0.0023 0.007 0.010 0.00004
+1 -0.0001 1 1 0.0006 0.0019 0.012 0.011 -0.00007
+1 0.0001 1 1 -0.0034 0.0035 0.022 0.007 -0.00012
+1 0.0001 1 1 -0.0047 -0.0014 0.022 -0.011 0.00001
+1 -0.0001 1 1 0.0051 0.0012 0.008 0.011 -0.00002
+1 -0.0002 1 1 0.0024 -0.0007 0.006 0.011 0.00000
+1 -0.0001 1 1 0.0037 -0.0014 0.016 0.013 0.00003
+1 -0.0001 1 1 0.0011 0.0013 0.015 0.010 -0.00001
+1 -0.0002 1 1 0.0011 -0.0010 0.006 0.010 -0.00001
+1 0.0002 1 1 -0.0062 0.0015 0.013 -0.010 -0.00005
+1 -0.0001 1 1 0.0057 0.0029 0.010 0.014 -0.00007
+1 0.0001 1 1 -0.0047 -0.0011 0.014 0.006 -0.00005
+1 0.0001 1 1 0.0038 0.0019 0.012 0.004 0.00001
+1 -0.0001 1 1 0.0048 -0.0016 0.009 0.012 0.00004
+1 -0.0001 1 1 0.0016 -0.0001 0.006 0.030 -0.00009
+1 0.0001 1 1 -0.0047 0.0002 0.006 0.023 -0.00013
+1 -0.0001 1 1 0.0041 -0.0013 0.010 0.010 -0.00002
+1 0.0001 1 1 -0.0050 0.0004 0.007 0.004 -0.00006
+1 -0.0001 1 1 0.0039 -0.0009 0.014 0.003 -0.00001
+1 -0.0001 1 1 0.0010 -0.0006 0.011 0.011 -0.00011
+1 0.0003 1 1 -0.0050 -0.0057 0.011 0.005 -0.00013
+1 0.0001 1 1 -0.0019 -0.0004 0.012 -0.014 0.00008
+1 -0.0001 1 1 0.0051 0.0013 0.010 -0.006 0.00011
+1 -0.0002 1 1 0.0045 -0.0009 0.014 0.013 -0.00004
+1 -0.0001 1 1 0.0036 -0.0008 0.005 -0.012 0.00012
+1 -0.0001 1 1 0.0058 0.0002 0.005 -0.001 0.00007
+1 -0.0002 1 1 0.0033 0.0010 0.011 0.010 0.00007
+1 0.0001 1 1 -0.0054 0.0027 0.013 -0.013 -0.00002
+1 -0.0001 1 1 0.0075 -0.0027 0.009 -0.010 0.00014
+1 -0.0003 1 1 0.0072 0.0015 0.003 0.027 -0.00008
+1 0.0002 1 1 -0.0039 0.0019 0.009 0.034 -0.00034
+1 -0.0001 1 1 0.0044 0.0002 0.013 -0.011 0.00014
+1 -0.0002 1 1 0.0058 0.0003 0.013 0.012 -0.00001
+1 -0.0004 1 1 0.0014 0.0014 0.007 0.009 0.00005
+1 0.0004 1 1 -0.0051 0.0023 0.012 0.007 -0.00036
+1 0.0001 1 1 -0.0033 -0.0010 0.011 -0.011 0.00019
+1 0.0002 1 1 -0.0051 -0.0002 0.010 0.006 -0.00011
+1 -0.0001 1 1 0.0041 0.0012 0.009 -0.008 0.00013
+1 0.0002 1 1 -0.0039 0.0011 0.011 -0.028 -0.00006
+1 -0.0001 1 1 0.0062 -0.0004 0.010 -0.006 0.00001
+1 0.0002 1 1 -0.0044 0.0009 0.009 0.008 -0.00013
+1 0.0001 1 1 0.0002 0.0015 0.011 -0.010 0.00008
+1 -0.0002 1 1 0.0039 -0.0010 0.009 -0.006 0.00016
+1 -0.0002 1 1 0.0014 0.0011 0.006 0.010 0.00002
+1 0.0002 1 1 -0.0035 0.0019 0.012 0.007 -0.00014
+1 -0.0001 1 1 0.0038 -0.0015 0.006 0.013 0.00001
+1 -0.0001 1 1 0.0061 0.0025 0.011 0.011 0.00001
+1 0.0001 1 1 -0.0072 0.0020 0.009 -0.012 0.00000
+1 0.0002 1 1 -0.0038 -0.0001 0.011 0.004 -0.00006
+1 -0.0002 1 1 0.0050 -0.0005 0.004 0.014 0.00003
+1 -0.0001 1 1 0.0003 0.0018 0.010 0.027 -0.00013
+1 0.0002 1 1 -0.0055 0.0019 0.012 -0.012 0.00003
+1 -0.0001 1 1 0.0013 -0.0031 0.009 0.010 0.00000
+1 0.0003 1 1 -0.0042 0.0028 0.008 0.005 -0.00013
+1 -0.0001 1 1 0.0065 0.0001 0.003 0.014 0.00005
+1 -0.0001 1 1 0.0049 0.0038 0.013 0.030 -0.00009
+1 -0.0001 1 1 0.0008 0.0009 0.008 0.010 -0.00002
+1 -0.0002 1 1 0.0040 -0.0013 0.008 0.011 0.00005
+1 0.0003 1 1 -0.0044 0.0004 0.012 -0.036 0.00012
+1 -0.0002 1 1 0.0096 -0.0006 0.007 -0.024 0.00024
+1 0.0002 1 1 -0.0081 0.0006 0.012 0.010 -0.00026
+1 0.0001 1 1 -0.0050 -0.0018 0.013 -0.014 0.00026
+1 -0.0001 1 1 0.0066 -0.0003 0.008 -0.002 0.00007
+1 -0.0001 1 1 0.0063 -0.0001 0.008 0.011 -0.00005
+1 -0.0001 1 1 -0.0055 -0.0008 0.004 0.009 -0.00006
+1 0.0001 1 1 -0.0069 0.0017 0.008 0.001 -0.00009
+1 0.0001 1 1 -0.0057 -0.0030 0.012 -0.014 0.00014
+1 0.0003 1 1 -0.0019 0.0004 0.008 -0.027 -0.00002
+1 -0.0002 1 1 0.0061 -0.0002 0.005 -0.017 0.00012
+1 -0.0003 1 1 0.0038 0.0025 0.009 0.010 -0.00014
+1 0.0003 1 1 -0.0049 -0.0023 0.012 0.007 -0.00014
+1 -0.0001 1 1 0.0040 -0.0001 0.011 0.011 0.00001
+1 0.0001 1 1 -0.0069 -0.0005 0.007 -0.014 -0.00002
+1 0.0001 1 1 -0.0039 0.0011 0.009 -0.029 0.00013
+1 -0.0002 1 1 0.0064 -0.0002 0.012 -0.023 0.00018
+1 -0.0002 1 1 0.0051 -0.0009 0.009 0.011 -0.00008
+1 0.0001 1 1 -0.0020 0.0013 0.009 -0.011 0.00002
+1 0.0001 1 1 -0.0035 -0.0004 0.009 -0.011 -0.00005
+1 0.0002 1 1 -0.0030 0.0016 0.008 -0.012 -0.00007
+1 -0.0001 1 1 0.0046 0.0002 0.010 0.011 -0.00004
+1 0.0002 1 1 -0.0065 0.0005 0.012 0.002 -0.00009
+1 0.0001 1 1 -0.0055 0.0002 0.011 -0.011 0.00012
+1 -0.0001 1 1 0.0042 0.0011 0.007 -0.013 0.00012
+1 0.0001 1 1 -0.0017 0.0024 0.013 -0.010 0.00001
+1 -0.0001 1 1 0.0050 -0.0017 0.011 -0.004 0.00013
+1 0.0002 1 1 -0.0068 0.0015 0.008 0.006 -0.00016
+1 0.0001 1 1 -0.0008 -0.0004 0.010 -0.009 -0.00002
+1 -0.0001 1 1 0.0033 0.0013 0.010 -0.005 0.00006
+1 0.0001 1 1 -0.0038 0.0006 0.008 -0.013 -0.00001
+1 -0.0002 1 1 0.0013 0.0014 0.011 0.010 -0.00002
+1 0.0003 1 1 -0.0051 -0.0008 0.012 0.005 -0.00025
+1 -0.0001 1 1 0.0024 0.0003 0.011 0.028 -0.00008
+1 0.0002 1 1 -0.0036 -0.0004 0.009 0.026 -0.00013
+1 -0.0002 1 1 0.0026 -0.0009 0.010 0.010 0.00006
+1 0.0001 1 1 -0.0045 -0.0020 0.004 0.005 -0.00009
+1 -0.0001 1 1 0.0044 0.0009 0.014 -0.006 0.00013
+1 -0.0001 1 1 0.0051 -0.0026 0.009 0.014 0.00001
+1 0.0002 1 1 -0.0040 0.0006 0.009 0.006 -0.00002
+1 -0.0001 1 1 0.0049 0.0002 0.009 0.016 0.00002
+1 -0.0001 1 1 0.0040 0.0003 0.010 0.029 -0.00005
+1 0.0002 1 1 -0.0013 0.0006 0.011 0.033 -0.00017
+1 -0.0001 1 1 -0.0003 -0.0009 0.006 0.027 0.00005
+1 -0.0001 1 1 0.0024 0.0025 0.011 0.011 0.00000
+1 -0.0001 1 1 0.0046 0.0010 0.004 0.014 0.00006
+1 -0.0001 1 1 0.0023 0.0015 0.009 0.028 -0.00009
+1 0.0001 1 1 -0.0046 0.0000 0.011 0.021 -0.00011
+1 0.0001 1 1 -0.0021 0.0006 0.006 -0.013 0.00003
+1 -0.0004 1 1 0.0063 0.0022 0.020 -0.005 0.00017
+1 0.0004 1 1 -0.0038 -0.0048 0.004 0.007 -0.00026
+1 0.0002 1 1 -0.0029 0.0019 0.005 -0.012 -0.00003
+1 -0.0001 1 1 0.0080 -0.0018 0.008 0.014 0.00005
+1 -0.0002 1 1 0.0068 -0.0006 0.006 0.029 -0.00011
+1 0.0002 1 1 -0.0085 0.0001 0.007 0.023 -0.00019
+1 -0.0001 1 1 0.0047 0.0021 0.007 -0.016 0.00015
+1 0.0002 1 1 -0.0050 0.0019 0.007 0.007 -0.00011
+1 0.0001 1 1 -0.0034 0.0008 0.010 -0.010 0.00011
+1 -0.0002 1 1 0.0059 0.0002 0.009 -0.005 0.00018
+1 -0.0002 1 1 0.0043 0.0007 0.011 0.013 -0.00009
+1 0.0002 1 1 -0.0062 -0.0017 0.005 0.005 -0.00012
+1 0.0001 1 1 -0.0047 -0.0003 0.003 -0.010 0.00012
+1 -0.0001 1 1 0.0037 0.0005 0.001 -0.013 0.00019
+1 -0.0001 1 1 0.0050 0.0006 0.001 -0.006 0.00006
+1 -0.0001 1 1 -0.0041 -0.0013 0.005 0.006 -0.00019
+1 0.0002 1 1 -0.0023 -0.0009 0.005 -0.010 -0.00001
+1 -0.0003 1 1 0.0035 0.0006 0.005 -0.008 0.00011
+1 0.0001 1 1 -0.0012 -0.0015 0.012 -0.010 0.00004
+1 -0.0004 1 1 0.0034 -0.0023 0.003 -0.006 0.00012
+1 0.0001 1 1 -0.0035 -0.0008 0.005 -0.006 -0.00012
+1 -0.0002 1 1 0.0045 -0.0002 0.012 0.010 -0.00003
+1 0.0002 1 1 -0.0041 -0.0018 0.008 0.012 -0.00016
+1 0.0002 1 1 -0.0014 0.0056 0.004 -0.010 -0.00005
+1 -0.0001 1 1 0.0028 0.0009 0.014 -0.007 0.00003
+1 0.0016 1 1 -0.0097 -0.0030 0.029 -0.009 -0.00004
+1 -0.0002 1 1 0.0062 0.0013 0.018 -0.019 0.00022
+1 -0.0005 1 1 0.0083 0.0012 0.017 -0.005 0.00005
+1 0.0001 1 1 -0.0033 0.0017 0.023 0.006 -0.00002
+1 0.0006 1 1 -0.0031 0.0029 0.016 -0.012 -0.00009
+1 -0.0003 1 1 0.0070 0.0033 0.025 -0.002 0.00010
+1 -0.0001 1 1 0.0056 0.0021 0.026 0.012 -0.00012
+1 0.0001 1 1 -0.0051 0.0020 0.029 0.012 -0.00012
+1 0.0005 1 1 -0.0059 0.0006 0.029 0.004 -0.00003
+1 -0.0008 1 1 0.0083 -0.0007 0.021 0.010 0.00018
+1 0.0001 1 1 0.0043 0.0011 0.022 0.027 -0.00032
+1 0.0006 1 1 -0.0052 0.0010 0.021 0.024 -0.00021
+1 -0.0002 1 1 0.0016 0.0000 0.016 0.009 0.00017
+1 -0.0001 1 1 -0.0041 0.0018 0.009 0.007 -0.00001
+1 0.0003 1 1 -0.0067 0.0036 0.017 -0.014 -0.00004
+1 -0.0003 1 1 0.0052 0.0032 0.024 -0.023 0.00016
+1 0.0005 1 1 -0.0057 -0.0026 0.011 -0.008 -0.00024
+1 -0.0002 1 1 0.0053 0.0037 0.011 -0.023 0.00012
+1 0.0001 1 1 -0.0060 0.0005 0.022 -0.012 -0.00012
+1 -0.0004 1 1 0.0056 -0.0026 0.005 -0.023 0.00038
+1 0.0001 1 1 -0.0061 0.0037 0.020 0.009 -0.00037
+1 0.0004 1 1 -0.0116 0.0020 0.021 -0.008 -0.00025
+1 0.0002 1 1 -0.0047 -0.0028 0.014 -0.044 0.00038
+1 -0.0007 1 1 0.0053 -0.0031 0.004 -0.044 0.00054
+1 -0.0005 1 1 0.0098 0.0027 0.016 0.004 0.00009
+1 -0.0002 1 1 0.0038 -0.0016 0.015 0.028 -0.00035
+1 -0.0003 1 1 0.0064 -0.0074 0.018 -0.025 0.00024
+1 -0.0005 1 1 0.0064 0.0023 0.007 0.012 0.00004
+1 0.0001 1 1 -0.0033 0.0040 0.018 0.020 -0.00036
+1 0.0003 1 1 -0.0102 0.0009 0.019 0.003 -0.00022
+1 -0.0002 1 1 0.0056 0.0003 0.011 -0.031 0.00032
+1 0.0003 1 1 -0.0031 0.0024 0.012 -0.010 0.00004
+1 -0.0002 1 1 0.0065 0.0012 0.014 -0.005 0.00022
+1 -0.0001 1 1 0.0064 0.0019 0.016 0.010 -0.00013
+1 -0.0001 1 1 0.0008 -0.0002 0.010 0.028 -0.00009
+1 0.0001 1 1 -0.0069 0.0004 0.008 0.018 -0.00020
+1 0.0002 1 1 -0.0065 0.0013 0.009 -0.011 0.00006
+1 -0.0002 1 1 0.0038 0.0002 0.011 -0.019 0.00024
+1 -0.0002 1 1 0.0050 0.0006 0.009 0.010 -0.00007
+1 0.0005 1 1 -0.0071 0.0013 0.011 0.008 -0.00026
+1 -0.0009 1 1 0.0086 0.0012 0.007 -0.003 0.00033
+1 0.0001 1 1 -0.0065 0.0019 0.014 0.012 -0.00044
+1 -0.0006 1 1 0.0085 0.0001 0.008 -0.006 0.00045
+1 -0.0001 1 1 0.0086 0.0031 0.011 0.014 -0.00041
+1 0.0003 1 1 -0.0054 0.0000 0.012 0.015 -0.00028
+1 -0.0001 1 1 -0.0039 -0.0005 0.007 -0.010 0.00014
+1 0.0001 1 1 -0.0025 -0.0003 0.005 -0.014 0.00009
+1 -0.0004 1 1 0.0054 0.0028 0.005 -0.009 0.00016
+1 0.0001 1 1 -0.0045 0.0022 0.019 -0.002 -0.00014
+1 0.0001 1 1 -0.0053 0.0021 0.021 -0.012 0.00002
+1 -0.0003 1 1 0.0087 -0.0024 0.006 -0.005 0.00020
+1 -0.0003 1 1 0.0076 0.0003 0.006 0.011 -0.00018
+1 0.0002 1 1 -0.0093 0.0018 0.013 0.006 -0.00027
+1 -0.0004 1 1 0.0106 0.0008 0.003 -0.004 0.00020
+1 0.0007 1 1 -0.0069 0.0012 0.016 0.024 -0.00059
+1 -0.0002 1 1 0.0047 0.0016 0.001 -0.002 0.00013
+1 -0.0002 1 1 0.0027 0.0029 0.007 0.010 -0.00012
+1 0.0003 1 1 -0.0046 0.0022 0.012 0.007 -0.00019
+1 -0.0003 1 1 0.0038 0.0005 0.014 -0.005 0.00016
+1 0.0002 1 1 -0.0060 -0.0004 0.008 -0.006 -0.00017
+1 -0.0003 1 1 0.0058 -0.0001 0.010 -0.018 0.00028
+1 -0.0002 1 1 0.0036 0.0013 0.011 0.013 -0.00018
+1 0.0004 1 1 -0.0080 0.0000 0.008 0.007 -0.00035
+1 0.0003 1 1 -0.0069 0.0010 0.008 -0.014 0.00019
+1 -0.0006 1 1 0.0111 0.0003 0.005 -0.005 0.00030
+1 0.0004 1 1 -0.0050 0.0020 0.011 0.022 -0.00053
+1 -0.0004 1 1 0.0073 -0.0001 0.001 -0.007 0.00015
+1 0.0002 1 1 -0.0028 0.0024 0.016 -0.011 -0.00002
+1 -0.0005 1 1 0.0063 -0.0004 0.013 -0.007 0.00024
+1 0.0001 1 1 -0.0098 0.0013 0.014 0.000 -0.00033
+1 0.0002 1 1 -0.0055 -0.0038 0.011 -0.011 0.00037
+1 -0.0001 1 1 0.0053 -0.0027 0.002 -0.012 0.00045
+1 -0.0002 1 1 0.0107 -0.0007 0.000 0.000 0.00033
+1 -0.0001 1 1 0.0027 0.0027 0.005 0.027 -0.00030
+1 0.0005 1 1 -0.0061 0.0029 0.009 0.024 -0.00039
+1 0.0003 1 1 -0.0070 -0.0012 0.010 -0.008 -0.00015
+1 -0.0005 1 1 0.0102 0.0005 0.006 -0.004 0.00024
+1 0.0002 1 1 -0.0069 0.0015 0.010 0.006 -0.00010
+1 0.0001 1 1 -0.0037 -0.0006 0.011 -0.011 0.00017
+1 -0.0003 1 1 0.0036 0.0011 0.008 -0.007 0.00001
+1 0.0008 1 1 -0.0088 0.0014 0.015 -0.014 -0.00037
+1 -0.0007 1 1 0.0093 -0.0020 0.007 -0.024 0.00052
+1 0.0004 1 1 -0.0106 0.0021 0.013 -0.009 -0.00016
+1 0.0002 1 1 -0.0054 -0.0012 0.009 -0.031 0.00035
+1 -0.0002 1 1 0.0049 0.0003 0.003 -0.032 0.00048
+1 -0.0001 1 1 0.0024 0.0007 0.012 0.010 -0.00027
+1 0.0007 1 1 -0.0046 0.0002 0.012 0.009 -0.00046
+1 -0.0003 1 1 0.0061 0.0000 0.001 0.010 0.00010
+1 0.0002 1 1 -0.0068 0.0016 0.005 0.006 -0.00011
+1 0.0002 1 1 -0.0034 0.0023 0.008 -0.014 0.00016
+1 -0.0002 1 1 0.0070 0.0001 0.011 -0.007 0.00023
+1 -0.0003 1 1 0.0082 0.0003 0.010 0.004 0.00000
+1 0.0003 1 1 -0.0072 0.0008 0.006 0.005 -0.00015
+1 0.0001 1 1 -0.0048 0.0022 0.008 -0.010 0.00020
+1 -0.0005 1 1 0.0070 0.0027 0.013 -0.006 0.00030
+1 -0.0001 1 1 0.0010 -0.0002 0.020 0.010 -0.00002
+1 0.0005 1 1 -0.0037 -0.0013 0.018 0.008 -0.00037
+1 0.0001 1 1 -0.0045 -0.0004 0.013 -0.004 -0.00013
+1 0.0003 1 1 -0.0051 -0.0016 0.009 -0.012 -0.00001
+1 -0.0002 1 1 0.0071 0.0044 0.001 -0.009 0.00022
+1 -0.0003 1 1 0.0049 0.0047 0.011 0.011 -0.00021
+1 0.0006 1 1 -0.0103 -0.0035 0.016 0.002 -0.00035
+1 -0.0003 1 1 0.0073 0.0003 0.002 -0.021 0.00035
+1 -0.0002 1 1 0.0055 -0.0009 0.006 0.004 0.00013
+1 0.0002 1 1 -0.0059 0.0019 0.008 0.012 -0.00027
+1 0.0001 1 1 -0.0074 0.0025 0.011 0.000 -0.00003
+1 0.0002 1 1 -0.0055 0.0004 0.010 -0.012 0.00013
+1 -0.0005 1 1 0.0082 0.0007 0.008 -0.009 0.00031
+1 0.0007 1 1 -0.0075 0.0003 0.014 0.006 -0.00028
+1 -0.0009 1 1 0.0084 -0.0018 0.007 -0.004 0.00046
+1 0.0007 1 1 -0.0111 -0.0011 0.014 0.002 -0.00047
+1 -0.0003 1 1 0.0097 -0.0032 0.001 -0.019 0.00053
+1 -0.0003 1 1 0.0129 0.0067 0.003 0.007 0.00002
+1 -0.0002 1 1 0.0079 0.0057 0.014 0.029 -0.00031
+1 0.0001 1 1 -0.0040 0.0022 0.008 -0.013 0.00016
+1 -0.0001 1 1 0.0047 -0.0010 0.002 -0.014 0.00036
+1 -0.0001 1 1 0.0089 0.0011 0.002 -0.003 0.00006
+1 -0.0001 1 1 0.0059 0.0029 0.006 0.011 -0.00020
+1 0.0001 1 1 -0.0035 0.0018 0.011 0.016 -0.00043
+1 0.0004 1 1 -0.0083 -0.0001 0.011 0.006 -0.00020
+1 -0.0004 1 1 0.0083 -0.0001 0.004 -0.004 0.00030
+1 -0.0001 1 1 0.0077 0.0002 0.009 0.019 -0.00010
+1 0.0001 1 1 0.0048 0.0015 0.010 0.028 -0.00024
+1 -0.0001 1 1 0.0009 0.0002 0.009 0.033 -0.00028
+1 0.0002 1 1 -0.0076 0.0001 0.007 0.024 -0.00027
+1 -0.0001 1 1 0.0058 0.0015 0.011 -0.007 0.00005
+1 -0.0002 1 1 0.0035 0.0013 0.008 0.007 0.00025
+1 -0.0002 1 1 0.0037 0.0016 0.010 0.013 -0.00025
+1 0.0007 1 1 -0.0096 -0.0017 0.013 0.006 -0.00048
+1 0.0002 1 1 -0.0081 -0.0014 0.009 -0.013 0.00031
+1 -0.0003 1 1 0.0087 0.0006 0.003 -0.012 0.00035
+1 -0.0002 1 1 0.0054 0.0020 0.006 0.015 -0.00033
+1 0.0002 1 1 -0.0075 0.0026 0.011 0.013 -0.00049
+1 0.0002 1 1 -0.0112 0.0021 0.013 -0.005 -0.00010
+1 0.0001 1 1 -0.0050 0.0002 0.008 -0.037 0.00036
+1 -0.0001 1 1 0.0057 -0.0010 0.003 -0.036 0.00043
+1 -0.0003 1 1 0.0111 0.0035 0.006 -0.018 0.00002
+1 0.0004 1 1 -0.0051 0.0023 0.016 0.002 -0.00054
+1 0.0005 1 1 -0.0083 0.0004 0.015 -0.012 -0.00001
+1 -0.0001 1 1 0.0090 -0.0011 0.006 -0.015 0.00037
+1 -0.0005 1 1 0.0134 0.0002 0.004 0.013 0.00007
+1 0.0004 1 1 -0.0004 0.0014 0.008 0.042 -0.00061
+1 -0.0001 1 1 -0.0055 0.0015 0.011 0.031 -0.00008
+1 0.0003 1 1 -0.0085 0.0011 0.012 0.020 -0.00019
+1 -0.0001 1 1 0.0048 0.0005 0.004 0.012 0.00000
+1 0.0001 1 1 -0.0042 0.0025 0.009 0.013 -0.00016
+1 0.0009 1 1 -0.0081 0.0018 0.018 -0.013 -0.00047
+1 -0.0004 1 1 0.0081 -0.0034 0.009 -0.024 0.00054
+1 -0.0004 1 1 0.0111 -0.0005 0.005 -0.003 0.00002
+1 0.0002 1 1 -0.0038 0.0027 0.012 -0.010 0.00004
+1 0.0001 1 1 0.0042 0.0003 0.011 -0.011 0.00023
+1 -0.0004 1 1 0.0073 0.0002 0.007 0.013 0.00013
+1 -0.0003 1 1 -0.0009 0.0021 0.011 0.027 -0.00034
+1 0.0001 1 1 -0.0086 0.0020 0.015 0.020 -0.00050
+1 -0.0004 1 1 0.0035 0.0007 0.006 0.011 -0.00004
+1 0.0006 1 1 -0.0066 0.0026 0.011 0.009 -0.00040
+1 0.0002 1 1 -0.0044 0.0006 0.012 -0.012 0.00027
+1 -0.0005 1 1 0.0077 -0.0015 0.007 -0.009 0.00045
+1 -0.0004 1 1 0.0095 0.0027 0.009 0.015 -0.00011
+1 0.0005 1 1 -0.0078 -0.0022 0.014 0.021 -0.00046
+1 -0.0001 1 1 0.0053 0.0000 0.000 -0.009 0.00033
+1 -0.0006 1 1 0.0094 0.0038 0.002 0.001 0.00025
+1 0.0003 1 1 -0.0080 0.0015 0.009 0.011 -0.00038
+1 0.0003 1 1 -0.0085 0.0008 0.009 -0.014 0.00016
+1 -0.0006 1 1 0.0132 0.0010 0.006 0.001 0.00026
+1 -0.0001 1 1 0.0082 0.0011 0.009 0.031 -0.00047
+1 0.0006 1 1 -0.0102 -0.0012 0.009 0.026 -0.00045
+1 -0.0001 1 1 0.0056 0.0011 0.002 -0.011 0.00033
+1 -0.0001 1 1 0.0081 0.0015 0.003 -0.001 0.00011
+1 -0.0002 1 1 0.0078 0.0053 0.007 0.014 -0.00012
+1 -0.0001 1 1 -0.0048 -0.0035 0.015 0.012 -0.00001
+1 0.0001 1 1 -0.0068 -0.0032 0.004 -0.003 -0.00006
+1 -0.0001 1 1 0.0054 0.0026 0.013 -0.007 0.00004
+1 0.0001 1 1 -0.0041 0.0004 0.017 0.000 -0.00021
+1 0.0005 1 1 -0.0063 -0.0015 0.012 -0.011 -0.00007
+1 -0.0003 1 1 0.0091 0.0011 0.006 -0.006 0.00025
+1 -0.0004 1 1 0.0081 0.0009 0.007 0.014 -0.00014
+1 0.0004 1 1 -0.0128 0.0009 0.007 0.004 -0.00038
+1 0.0001 1 1 -0.0099 0.0007 0.007 -0.030 0.00033
+1 -0.0002 1 1 0.0049 0.0029 0.009 -0.038 0.00042
+1 -0.0001 1 1 0.0085 0.0039 0.017 -0.018 0.00005
+1 -0.0002 1 1 0.0103 0.0036 0.015 -0.011 0.00026
+1 -0.0008 1 1 0.0114 0.0046 0.018 0.014 -0.00003
+1 -0.0002 1 1 -0.0034 0.0025 0.015 0.018 -0.00004
+1 0.0006 1 1 -0.0067 0.0032 0.015 0.006 -0.00013
+1 -0.0016 1 1 0.0122 0.0026 0.017 0.004 0.00047
+1 0.0008 1 1 -0.0116 0.0022 0.018 0.018 -0.00057
+1 0.0012 1 1 -0.0061 0.0024 0.018 -0.012 -0.00040
+1 -0.0005 1 1 0.0053 0.0006 0.012 -0.018 0.00071
+1 -0.0005 1 1 0.0138 0.0037 0.007 0.012 0.00013
+1 -0.0002 1 1 0.0038 0.0043 0.013 0.046 -0.00047
+1 0.0009 1 1 -0.0064 0.0047 0.018 0.043 -0.00058
+1 -0.0004 1 1 0.0080 0.0013 0.003 0.009 0.00035
+1 0.0002 1 1 0.0076 0.0057 0.005 0.023 -0.00039
+1 0.0002 1 1 -0.0064 0.0026 0.012 0.023 -0.00021
+1 0.0001 1 1 -0.0046 0.0032 0.014 -0.010 0.00023
+1 -0.0005 1 1 0.0075 0.0039 0.016 -0.005 0.00025
+1 -0.0002 1 1 0.0043 0.0031 0.017 0.011 -0.00025
+1 0.0009 1 1 -0.0076 0.0013 0.018 0.005 -0.00033
+1 0.0002 1 1 -0.0034 0.0022 0.016 -0.011 0.00039
+1 -0.0009 1 1 0.0089 0.0016 0.013 -0.005 0.00050
+1 -0.0005 1 1 0.0062 0.0039 0.014 0.016 -0.00058
+1 0.0014 1 1 -0.0135 0.0027 0.015 0.008 -0.00079
+1 -0.0003 1 1 0.0111 0.0065 0.006 -0.021 0.00040
+1 -0.0001 1 1 0.0134 0.0076 0.013 -0.003 0.00005
+1 -0.0007 1 1 0.0095 0.0026 0.017 0.020 -0.00023
+1 0.0013 1 1 -0.0048 0.0027 0.019 0.029 -0.00077
+1 -0.0008 1 1 0.0066 0.0008 0.014 0.012 0.00042
+1 0.0005 1 1 -0.0105 0.0021 0.007 0.002 -0.00020
+1 0.0001 1 1 0.0093 0.0059 0.016 -0.009 0.00003
+1 0.0002 1 1 -0.0055 0.0014 0.009 0.023 -0.00017
+1 -0.0006 1 1 0.0051 0.0020 0.008 0.009 0.00022
+1 0.0007 1 1 -0.0065 0.0033 0.011 0.013 -0.00034
+1 -0.0004 1 1 0.0097 0.0007 0.018 0.011 0.00024
+1 -0.0002 1 1 0.0083 0.0002 0.013 0.032 -0.00020
+1 0.0006 1 1 -0.0012 0.0006 0.010 0.041 -0.00052
+1 0.0002 1 1 -0.0050 0.0017 0.008 0.006 -0.00008
+1 -0.0003 1 1 0.0039 0.0034 0.011 0.001 0.00016
+1 0.0007 1 1 -0.0058 0.0010 0.011 0.005 -0.00041
+1 -0.0004 1 1 0.0069 0.0019 0.009 0.001 0.00049
+1 -0.0002 1 1 0.0032 0.0026 0.009 0.027 -0.00047
+1 0.0008 1 1 -0.0168 0.0031 0.012 0.001 -0.00044
+1 0.0001 1 1 -0.0137 0.0021 0.011 -0.034 0.00052
+1 -0.0011 1 1 0.0141 0.0072 0.004 -0.030 0.00014
+1 0.0002 1 1 -0.0051 0.0069 0.017 -0.010 -0.00091
+1 0.0004 1 1 -0.0142 0.0009 0.017 -0.024 -0.00036
+1 0.0003 1 1 -0.0068 0.0009 0.012 -0.043 0.00062
+1 -0.0001 1 1 0.0098 0.0011 0.007 -0.041 0.00081
+1 -0.0004 1 1 0.0165 0.0045 0.005 -0.019 0.00028
+1 -0.0002 1 1 0.0121 0.0044 0.013 0.029 -0.00018
+1 -0.0001 1 1 0.0036 0.0024 0.014 0.045 -0.00045
+1 0.0006 1 1 -0.0099 0.0012 0.013 0.036 -0.00043
+1 0.0006 1 1 -0.0078 0.0027 0.004 -0.013 -0.00031
+1 -0.0006 1 1 0.0101 0.0045 0.008 -0.020 0.00039
+1 -0.0008 1 1 0.0032 0.0037 0.014 0.010 0.00004
+1 0.0009 1 1 -0.0121 0.0023 0.015 0.001 -0.00062
+1 -0.0004 1 1 0.0106 0.0016 0.009 -0.027 0.00038
+1 0.0008 1 1 -0.0109 0.0024 0.009 0.007 -0.00056
+1 -0.0005 1 1 0.0079 0.0028 0.009 -0.020 0.00042
+1 0.0009 1 1 -0.0047 0.0019 0.013 0.008 -0.00023
+1 -0.0006 1 1 0.0064 0.0013 0.011 0.003 0.00061
+1 -0.0003 1 1 0.0095 0.0012 0.010 0.022 -0.00046
+1 0.0008 1 1 -0.0108 0.0016 0.009 0.021 -0.00061
+1 0.0001 1 1 -0.0037 -0.0001 0.001 -0.013 0.00042
+1 -0.0005 1 1 0.0053 0.0054 0.006 -0.012 0.00044
+1 -0.0002 1 1 0.0064 0.0011 0.013 0.013 -0.00008
+1 -0.0008 1 1 0.0054 0.0013 0.007 0.029 0.00010
+1 0.0009 1 1 -0.0125 0.0017 0.005 0.023 -0.00051
+1 0.0001 1 1 0.0042 0.0010 0.000 -0.008 0.00052
+1 0.0003 1 1 -0.0045 0.0064 0.011 0.013 -0.00095
+1 0.0010 1 1 -0.0155 0.0046 0.014 -0.004 -0.00054
+1 -0.0008 1 1 0.0128 -0.0023 0.009 -0.021 0.00082
+1 0.0007 1 1 0.0008 0.0012 0.009 0.029 -0.00082
+1 0.0001 1 1 -0.0079 0.0040 0.012 0.009 -0.00001
+1 -0.0010 1 1 0.0057 0.0013 0.007 -0.008 0.00035
+1 0.0006 1 1 -0.0045 0.0042 0.010 0.000 -0.00064
+1 0.0002 1 1 -0.0079 0.0040 0.013 -0.014 0.00007
+1 -0.0003 1 1 0.0050 0.0023 0.011 -0.020 0.00044
+1 -0.0001 1 1 0.0076 0.0039 0.013 -0.009 0.00004
+1 0.0003 1 1 -0.0039 0.0019 0.011 0.006 -0.00062
+1 0.0002 1 1 -0.0086 0.0003 0.006 -0.012 0.00020
+1 -0.0004 1 1 0.0069 0.0048 0.012 -0.005 0.00009
+1 0.0003 1 1 -0.0052 0.0014 0.013 0.001 -0.00021
+1 0.0002 1 1 -0.0048 0.0011 0.009 -0.012 0.00008
+1 -0.0001 1 1 0.0079 0.0016 0.002 -0.004 0.00019
+1 -0.0001 1 1 0.0092 0.0028 0.003 0.012 -0.00003
+1 -0.0001 1 1 0.0030 0.0022 0.003 0.031 -0.00028
+1 0.0003 1 1 -0.0072 0.0033 0.007 0.025 -0.00031
+1 -0.0003 1 1 0.0101 0.0031 0.012 0.010 0.00035
+1 -0.0003 1 1 0.0115 0.0022 0.012 0.034 -0.00011
+1 -0.0003 1 1 0.0066 0.0014 0.011 0.047 -0.00042
+1 0.0006 1 1 -0.0107 0.0018 0.011 0.041 -0.00059
+1 -0.0001 1 1 0.0041 0.0001 0.002 -0.013 0.00068
+1 -0.0001 1 1 0.0120 0.0040 0.004 -0.001 0.00046
+1 0.0004 1 1 0.0041 0.0035 0.008 0.026 -0.00047
+1 -0.0001 1 1 0.0002 0.0028 0.012 0.032 -0.00004
+1 0.0002 1 1 -0.0039 0.0019 0.015 0.021 -0.00005
+1 -0.0004 1 1 0.0041 0.0024 0.011 0.009 0.00023
+1 0.0003 1 1 -0.0048 0.0025 0.012 0.014 -0.00027
+1 0.0003 1 1 -0.0041 0.0027 0.009 0.004 -0.00034
+1 -0.0006 1 1 0.0097 0.0013 0.010 -0.006 0.00037
+1 0.0008 1 1 -0.0120 0.0021 0.010 0.001 -0.00044
+1 -0.0004 1 1 0.0075 0.0010 0.005 -0.023 0.00065
+1 -0.0003 1 1 0.0114 0.0028 0.008 -0.006 -0.00001
+1 -0.0006 1 1 0.0041 0.0040 0.014 0.012 0.00027
+1 -0.0001 1 1 0.0036 -0.0045 0.006 0.013 0.00032
+1 -0.0008 1 1 0.0067 0.0044 -0.001 0.028 0.00001
+1 0.0004 1 1 -0.0093 0.0041 0.005 0.029 -0.00070
+1 0.0001 1 1 -0.0058 0.0004 0.004 -0.032 0.00061
+1 -0.0001 1 1 0.0046 0.0042 0.003 -0.021 0.00002
+1 -0.0002 1 1 0.0044 0.0021 0.014 0.013 -0.00006
+1 0.0005 1 1 -0.0075 0.0016 0.011 0.006 -0.00021
+1 -0.0003 1 1 0.0091 0.0015 0.006 -0.004 0.00031
+1 -0.0002 1 1 0.0104 0.0019 0.005 0.013 -0.00003
+1 0.0001 1 1 0.0040 0.0056 0.013 0.033 -0.00033
+1 0.0002 1 1 -0.0113 0.0025 0.018 0.012 -0.00021
+1 0.0001 1 1 -0.0095 0.0010 0.013 -0.012 0.00035
+1 -0.0001 1 1 0.0050 0.0001 0.010 -0.014 0.00020
+1 -0.0008 1 1 0.0075 0.0044 0.011 -0.004 0.00011
+1 0.0002 1 1 -0.0055 0.0047 0.033 0.006 -0.00019
+1 -0.0001 1 1 -0.0008 0.0009 0.026 -0.011 0.00014
+1 -0.0001 1 1 0.0015 0.0041 0.029 -0.011 0.00010
+1 -0.0002 1 1 0.0024 0.0026 0.030 -0.008 0.00004
+1 0.0005 1 1 -0.0002 0.0004 0.027 -0.004 -0.00012
+1 -0.0003 1 1 0.0044 0.0013 0.021 0.011 0.00001
+1 -0.0001 1 1 -0.0041 0.0029 0.028 0.012 -0.00012
+1 0.0001 1 1 -0.0067 0.0025 0.029 0.001 -0.00011
+1 0.0004 1 1 -0.0077 -0.0019 0.026 -0.009 -0.00005
+1 -0.0003 1 1 0.0062 0.0043 0.008 -0.017 0.00013
+1 -0.0003 1 1 0.0036 0.0029 0.029 0.011 -0.00002
+1 0.0003 1 1 -0.0054 -0.0009 0.022 0.009 -0.00021
+1 0.0001 1 1 -0.0038 0.0005 0.015 -0.028 0.00025
+1 -0.0004 1 1 0.0051 0.0010 0.012 -0.026 0.00022
+1 0.0004 1 1 -0.0035 0.0014 0.018 -0.011 -0.00007
+1 -0.0002 1 1 0.0065 0.0004 0.016 -0.007 0.00016
+1 -0.0002 1 1 0.0062 0.0010 0.015 0.013 -0.00007
+1 0.0002 1 1 -0.0040 0.0009 0.016 0.020 -0.00015
+1 0.0003 1 1 -0.0034 0.0015 0.014 -0.013 0.00005
+1 -0.0003 1 1 0.0045 0.0004 0.010 -0.012 0.00021
+1 -0.0002 1 1 0.0039 0.0033 0.018 0.020 -0.00008
+1 0.0003 1 1 -0.0073 0.0010 0.017 0.008 -0.00014
+1 0.0002 1 1 -0.0047 -0.0002 0.013 -0.012 0.00015
+1 -0.0003 1 1 0.0074 0.0010 0.010 -0.005 0.00018
+1 -0.0001 1 1 0.0052 0.0017 0.011 0.014 -0.00014
+1 -0.0001 1 1 -0.0058 0.0023 0.018 0.011 -0.00014
+1 0.0004 1 1 -0.0084 0.0008 0.017 -0.002 -0.00012
+1 -0.0002 1 1 0.0089 0.0027 0.010 0.013 0.00002
+1 -0.0002 1 1 0.0055 0.0041 0.017 0.031 -0.00019
+1 0.0005 1 1 -0.0077 -0.0015 0.015 0.025 -0.00022
+1 0.0001 1 1 0.0017 0.0059 0.027 0.011 -0.00007
+1 -0.0004 1 1 0.0061 0.0019 0.005 0.031 0.00007
+1 0.0003 1 1 -0.0091 0.0007 0.018 0.028 -0.00027
+1 0.0003 1 1 0.0037 0.0042 0.016 -0.016 0.00001
+1 -0.0002 1 1 0.0083 0.0004 0.016 0.001 0.00015
+1 -0.0002 1 1 0.0082 -0.0020 0.014 0.015 -0.00008
+1 0.0002 1 1 -0.0050 -0.0003 0.008 0.024 -0.00024
+1 0.0001 1 1 -0.0042 0.0029 0.006 -0.013 0.00003
+1 -0.0004 1 1 0.0065 -0.0025 0.018 -0.003 0.00019
+1 0.0005 1 1 -0.0062 -0.0003 0.009 0.007 -0.00025
+1 0.0001 1 1 -0.0005 0.0020 0.002 -0.010 0.00023
+1 -0.0002 1 1 0.0058 0.0040 0.011 0.000 0.00013
+1 0.0001 1 1 0.0042 0.0046 0.020 0.013 -0.00013
+1 -0.0003 1 1 0.0039 -0.0009 0.013 0.030 0.00008
+1 -0.0001 1 1 -0.0053 0.0008 0.012 0.029 -0.00022
+1 0.0003 1 1 -0.0104 -0.0011 0.008 0.014 -0.00024
+1 0.0002 1 1 -0.0076 -0.0012 0.002 -0.012 0.00019
+1 0.0001 1 1 0.0038 -0.0001 0.011 -0.014 0.00006
+1 -0.0001 1 1 0.0066 -0.0009 0.007 -0.006 0.00018
+1 -0.0001 1 1 0.0053 0.0002 0.005 0.016 -0.00011
+1 0.0002 1 1 -0.0071 0.0024 0.010 0.006 -0.00010
+1 -0.0003 1 1 0.0071 0.0000 0.010 -0.011 0.00027
+1 0.0005 1 1 -0.0073 0.0013 0.011 0.005 -0.00030
+1 -0.0004 1 1 0.0046 0.0021 0.007 -0.007 0.00027
+1 0.0002 1 1 -0.0035 -0.0015 0.015 0.002 -0.00016
+1 -0.0005 1 1 0.0078 0.0046 0.002 -0.004 0.00017
+1 0.0001 1 1 0.0005 0.0058 0.015 0.011 -0.00035
+1 0.0003 1 1 -0.0053 -0.0007 0.014 0.002 -0.00015
+1 -0.0005 1 1 0.0054 0.0025 0.007 -0.005 0.00019
+1 -0.0002 1 1 0.0055 -0.0054 0.003 0.011 0.00012
+1 -0.0001 1 1 0.0040 0.0017 -0.002 0.024 -0.00016
+1 -0.0001 1 1 0.0004 0.0051 0.002 0.028 -0.00026
+1 0.0003 1 1 -0.0046 0.0058 0.009 0.025 -0.00038
+1 -0.0001 1 1 0.0071 0.0018 0.005 0.015 0.00007
+1 0.0001 1 1 -0.0041 0.0003 0.016 0.042 -0.00017
+1 0.0001 1 1 -0.0051 -0.0007 0.013 0.034 -0.00001
+1 0.0001 1 1 -0.0058 -0.0015 0.006 0.018 -0.00006
+1 0.0001 1 1 -0.0024 0.0013 0.003 -0.010 0.00010
+1 0.0001 1 1 0.0028 0.0010 0.012 0.009 -0.00004
+1 0.0002 1 1 -0.0040 0.0017 0.014 0.013 -0.00022
+1 0.0002 1 1 -0.0027 -0.0006 0.012 -0.013 0.00008
+1 -0.0002 1 1 0.0069 -0.0001 0.007 -0.006 0.00021
+1 0.0002 1 1 -0.0078 0.0028 0.009 0.003 -0.00011
+1 0.0002 1 1 -0.0023 -0.0010 0.012 -0.027 0.00012
+1 -0.0002 1 1 0.0047 -0.0017 0.004 -0.024 0.00025
+1 -0.0001 1 1 0.0016 -0.0003 0.015 0.011 -0.00008
+1 0.0002 1 1 -0.0060 -0.0001 0.011 0.001 -0.00014
+1 -0.0001 1 1 0.0045 0.0024 0.012 -0.004 0.00004
+1 -0.0001 1 1 0.0025 0.0021 0.008 0.011 0.00000
+1 0.0003 1 1 -0.0036 -0.0005 0.013 0.005 -0.00004
+1 -0.0001 1 1 0.0060 0.0001 0.006 0.012 0.00011
+1 -0.0001 1 1 0.0040 0.0004 0.005 0.029 -0.00010
+1 0.0001 1 1 -0.0063 0.0003 0.013 0.017 -0.00006
+1 0.0002 1 1 -0.0007 -0.0005 0.003 -0.009 0.00011
+1 -0.0004 1 1 0.0060 0.0052 0.002 -0.002 0.00022
+1 0.0001 1 1 0.0021 0.0053 0.011 0.010 -0.00035
+1 -0.0003 1 1 0.0049 -0.0001 0.012 0.008 0.00022
+1 0.0003 1 1 -0.0067 0.0000 0.014 0.015 -0.00026
+1 -0.0001 1 1 0.0060 -0.0019 -0.001 -0.001 0.00026
+1 -0.0002 1 1 0.0071 0.0041 0.006 0.019 -0.00002
+1 0.0001 1 1 0.0038 0.0058 0.018 0.032 -0.00017
+1 -0.0001 1 1 -0.0015 -0.0015 0.011 0.036 -0.00008
+1 0.0001 1 1 -0.0041 -0.0013 0.006 0.030 -0.00011
+1 0.0002 1 1 -0.0012 0.0019 0.014 -0.010 0.00010
+1 -0.0005 1 1 0.0039 -0.0007 0.013 -0.008 0.00028
+1 0.0002 1 1 -0.0041 -0.0018 0.004 -0.012 -0.00002
+1 -0.0002 1 1 0.0078 -0.0015 0.007 -0.003 0.00011
+1 -0.0001 1 1 0.0063 -0.0001 0.004 0.013 -0.00011
+1 0.0001 1 1 -0.0069 0.0000 0.005 0.003 -0.00008
+1 0.0002 1 1 -0.0047 0.0007 0.004 -0.012 0.00013
+1 -0.0002 1 1 0.0070 0.0004 0.008 -0.006 0.00021
+1 0.0001 1 1 0.0080 0.0012 0.009 0.008 -0.00001
+1 -0.0001 1 1 0.0080 0.0021 0.011 0.019 -0.00001
+1 -0.0002 1 1 0.0057 0.0033 0.015 0.029 -0.00021
+1 0.0002 1 1 -0.0047 -0.0030 0.021 0.030 -0.00023
+1 -0.0002 1 1 0.0030 0.0022 0.005 0.028 0.00000
+1 0.0002 1 1 -0.0067 0.0008 0.008 0.003 -0.00002
+1 0.0001 1 1 -0.0036 0.0026 0.011 -0.012 0.00016
+1 -0.0004 1 1 0.0068 0.0012 0.012 -0.005 0.00020
+1 0.0001 1 1 0.0041 0.0012 0.016 0.013 -0.00019
+1 0.0001 1 1 -0.0067 -0.0016 0.012 0.004 -0.00013
+1 0.0002 1 1 -0.0070 -0.0002 0.009 -0.010 0.00003
+1 -0.0002 1 1 0.0014 -0.0019 0.028 -0.017 0.00031
+1 -0.0007 1 1 0.0053 0.0089 0.031 -0.010 0.00014
+1 -0.0005 1 1 0.0056 0.0045 0.018 -0.007 0.00002
+1 0.0008 1 1 -0.0062 0.0045 0.024 -0.014 -0.00011
+1 -0.0004 1 1 0.0088 0.0030 0.018 -0.014 0.00035
+1 -0.0005 1 1 0.0078 0.0051 0.020 0.011 -0.00026
+1 -0.0001 1 1 0.0071 0.0033 0.012 0.001 0.00033
+1 0.0013 1 1 -0.0066 0.0070 0.016 0.007 -0.00038
+1 -0.0004 1 1 0.0076 0.0019 0.018 0.011 0.00010
+1 -0.0003 1 1 0.0009 0.0046 0.010 0.030 0.00004
+1 0.0005 1 1 -0.0047 0.0055 0.016 0.025 -0.00021
+1 0.0007 1 1 -0.0035 0.0019 0.017 0.007 -0.00006
+1 -0.0001 1 1 0.0063 0.0021 0.013 0.009 0.00030
+1 -0.0002 1 1 0.0067 0.0061 0.022 0.033 -0.00014
+1 0.0006 1 1 -0.0131 0.0021 0.016 0.011 -0.00020
+1 0.0008 1 1 -0.0109 0.0045 0.018 -0.012 0.00027
+1 -0.0007 1 1 0.0045 0.0018 0.014 -0.024 0.00074
+1 -0.0002 1 1 0.0107 0.0017 0.011 -0.009 0.00010
+1 -0.0001 1 1 0.0102 0.0041 0.013 0.011 -0.00028
+1 0.0010 1 1 -0.0083 0.0047 0.017 0.007 -0.00024
+1 -0.0004 1 1 0.0040 0.0017 0.011 -0.010 0.00049
+1 -0.0005 1 1 0.0074 0.0058 0.017 0.011 -0.00008
+1 -0.0001 1 1 0.0036 0.0045 0.011 0.019 -0.00016
+1 0.0001 1 1 -0.0041 0.0043 0.020 0.018 -0.00020
+1 0.0004 1 1 -0.0059 0.0014 0.019 0.007 -0.00004
+1 -0.0004 1 1 0.0071 0.0024 0.010 0.009 0.00013
+1 0.0006 1 1 -0.0042 0.0044 0.015 0.021 -0.00032
+1 -0.0004 1 1 0.0054 0.0019 0.009 0.012 0.00019
+1 -0.0002 1 1 -0.0043 0.0015 0.014 0.009 -0.00002
+1 0.0005 1 1 -0.0084 0.0024 0.012 -0.012 -0.00010
+1 0.0001 1 1 -0.0030 0.0022 0.023 -0.011 0.00013
+1 -0.0003 1 1 0.0059 0.0000 0.022 -0.006 0.00018
+1 -0.0003 1 1 0.0052 0.0013 0.022 0.013 -0.00007
+1 0.0003 1 1 -0.0072 0.0013 0.015 0.007 -0.00019
+1 0.0001 1 1 -0.0067 0.0022 0.017 -0.013 0.00017
+1 0.0001 1 1 0.0049 0.0017 0.023 -0.019 0.00019
+1 -0.0006 1 1 0.0080 -0.0017 0.020 -0.003 0.00007
+1 0.0001 1 1 -0.0059 0.0011 0.013 0.010 -0.00040
+1 0.0003 1 1 -0.0103 0.0021 0.015 -0.002 -0.00026
+1 -0.0005 1 1 0.0091 0.0023 0.016 -0.006 0.00027
+1 -0.0002 1 1 0.0080 0.0026 0.019 0.015 -0.00019
+1 0.0009 1 1 -0.0068 0.0012 0.020 0.020 -0.00028
+1 -0.0001 1 1 0.0065 -0.0001 0.020 0.012 0.00003
+1 -0.0002 1 1 0.0047 -0.0015 0.013 0.028 -0.00010
+1 0.0002 1 1 -0.0033 0.0012 0.013 0.030 -0.00014
+1 -0.0006 1 1 0.0064 0.0000 0.018 0.011 0.00018
+1 0.0005 1 1 -0.0105 -0.0013 0.016 0.007 -0.00027
+1 -0.0006 1 1 0.0060 -0.0039 0.015 -0.024 0.00037
+1 -0.0009 1 1 0.0090 -0.0018 0.014 0.010 0.00022
+1 0.0001 1 1 -0.0102 -0.0015 0.009 0.013 -0.00039
+1 0.0003 1 1 -0.0133 0.0019 0.009 -0.010 0.00018
+1 -0.0005 1 1 0.0087 0.0011 0.012 -0.027 0.00043
+1 -0.0001 1 1 0.0062 -0.0007 0.007 0.012 -0.00038
+1 0.0001 1 1 -0.0049 0.0014 0.008 0.013 -0.00049
+1 0.0004 1 1 -0.0105 0.0026 0.010 0.002 -0.00028
+1 -0.0003 1 1 0.0080 0.0005 0.013 -0.009 0.00024
+1 -0.0001 1 1 0.0083 -0.0013 0.013 0.010 -0.00016
+1 0.0002 1 1 -0.0073 0.0018 0.008 0.005 -0.00008
+1 -0.0002 1 1 0.0068 0.0007 0.013 -0.009 0.00014
+1 -0.0002 1 1 0.0054 0.0001 0.011 0.011 -0.00011
+1 0.0003 1 1 -0.0079 0.0003 0.014 0.004 -0.00014
+1 -0.0001 1 1 0.0055 0.0037 0.008 -0.011 0.00014
+1 0.0007 1 1 -0.0092 -0.0002 0.011 -0.011 -0.00028
+1 -0.0002 1 1 0.0101 0.0005 0.011 -0.023 0.00028
+1 -0.0001 1 1 0.0120 0.0010 0.011 -0.005 0.00002
+1 -0.0001 1 1 0.0079 0.0015 0.012 0.015 -0.00024
+1 0.0001 1 1 -0.0034 0.0018 0.016 0.024 -0.00034
+1 0.0003 1 1 -0.0091 -0.0010 0.012 0.005 -0.00013
+1 -0.0003 1 1 0.0066 0.0018 0.011 -0.008 0.00016
+1 0.0008 1 1 -0.0048 -0.0009 0.014 0.007 -0.00039
+1 -0.0003 1 1 0.0054 -0.0014 0.009 0.000 0.00038
+1 -0.0003 1 1 0.0081 -0.0006 0.007 0.011 0.00005
+1 0.0003 1 1 -0.0105 0.0016 0.008 0.004 -0.00023
+1 -0.0004 1 1 0.0050 -0.0016 0.013 -0.024 0.00038
+1 0.0007 1 1 -0.0076 0.0037 0.014 0.008 -0.00053
+1 -0.0005 1 1 0.0094 -0.0003 0.012 -0.022 0.00035
+1 0.0004 1 1 -0.0033 -0.0009 0.009 0.006 -0.00021
+1 -0.0004 1 1 0.0059 0.0014 0.007 0.010 0.00009
+1 0.0003 1 1 -0.0048 0.0025 0.014 0.016 -0.00028
+1 0.0001 1 1 -0.0057 0.0001 0.012 0.004 -0.00007
+1 0.0002 1 1 -0.0055 -0.0006 0.008 -0.012 0.00004
+1 -0.0004 1 1 0.0090 0.0008 0.009 -0.001 0.00016
+1 0.0005 1 1 -0.0071 0.0012 0.013 0.010 -0.00030
+1 -0.0008 1 1 0.0068 0.0001 0.013 -0.006 0.00048
+1 0.0007 1 1 -0.0051 -0.0035 0.012 0.007 -0.00017
+1 0.0002 1 1 -0.0002 0.0008 0.003 -0.010 0.00004
+1 -0.0003 1 1 0.0053 0.0022 0.007 -0.003 0.00018
+1 -0.0001 1 1 0.0011 0.0019 0.011 0.010 -0.00016
+1 0.0005 1 1 -0.0043 -0.0017 0.010 0.007 -0.00022
+1 -0.0002 1 1 0.0061 -0.0007 0.002 0.005 0.00021
+1 0.0004 1 1 -0.0091 0.0044 0.009 0.007 -0.00018
+1 -0.0001 1 1 0.0049 0.0012 0.016 -0.016 0.00039
+1 -0.0004 1 1 0.0095 0.0010 0.016 -0.005 0.00028
+1 0.0005 1 1 -0.0054 -0.0015 0.008 0.009 -0.00021
+1 -0.0002 1 1 0.0038 0.0022 0.012 -0.002 0.00023
+1 0.0003 1 1 -0.0040 0.0009 0.009 0.005 -0.00005
+1 -0.0005 1 1 0.0047 0.0012 0.011 0.004 0.00021
+1 0.0004 1 1 -0.0106 -0.0004 0.011 -0.005 -0.00020
+1 0.0001 1 1 -0.0037 0.0014 0.011 -0.034 0.00037
+1 -0.0005 1 1 0.0089 0.0007 0.012 -0.027 0.00043
+1 0.0002 1 1 -0.0037 0.0000 0.009 -0.012 0.00002
+1 -0.0004 1 1 0.0081 -0.0009 0.013 -0.005 0.00026
+1 0.0003 1 1 -0.0093 -0.0006 0.002 0.004 -0.00018
+1 0.0001 1 1 0.0043 0.0026 0.008 -0.027 0.00026
+1 -0.0007 1 1 0.0111 -0.0005 0.009 -0.009 0.00025
+1 -0.0001 1 1 0.0038 0.0009 0.009 0.011 -0.00051
+1 0.0007 1 1 -0.0084 -0.0012 0.005 0.006 -0.00055
+1 -0.0002 1 1 0.0050 -0.0001 0.011 -0.007 0.00017
+1 -0.0001 1 1 0.0049 -0.0001 0.008 0.014 -0.00005
+1 0.0002 1 1 -0.0061 0.0002 0.011 0.007 -0.00009
+1 0.0002 1 1 -0.0032 -0.0001 0.007 -0.011 0.00012
+1 -0.0003 1 1 0.0072 0.0014 0.009 -0.003 0.00021
+1 -0.0002 1 1 0.0069 0.0007 0.010 0.011 -0.00012
+1 0.0004 1 1 -0.0084 0.0006 0.009 0.007 -0.00028
+1 0.0002 1 1 -0.0086 0.0016 0.011 -0.012 0.00014
+1 -0.0001 1 1 0.0071 -0.0006 0.012 -0.017 0.00028
+1 -0.0002 1 1 0.0101 -0.0005 0.010 -0.005 0.00017
+1 -0.0003 1 1 0.0097 -0.0015 0.008 0.011 -0.00013
+1 -0.0002 1 1 0.0003 0.0015 0.004 0.027 -0.00039
+1 0.0001 1 1 -0.0073 0.0011 0.005 0.022 -0.00057
+1 -0.0002 1 1 0.0004 0.0005 0.012 -0.009 0.00024
+1 0.0002 1 1 -0.0012 0.0001 0.005 -0.010 0.00005
+1 -0.0004 1 1 0.0060 0.0024 0.009 -0.003 0.00022
+1 0.0002 1 1 -0.0054 0.0004 0.012 0.007 -0.00016
+1 -0.0002 1 1 0.0030 -0.0005 0.007 -0.006 0.00022
+1 -0.0001 1 1 0.0034 0.0000 0.004 0.010 -0.00003
+1 0.0004 1 1 -0.0053 0.0024 0.009 0.007 -0.00019
+1 -0.0002 1 1 0.0070 -0.0002 0.013 0.005 0.00020
+1 -0.0001 1 1 0.0040 0.0000 0.010 0.033 -0.00017
+1 0.0002 1 1 -0.0076 0.0003 0.009 0.024 -0.00020
+1 -0.0003 1 1 0.0053 -0.0010 0.008 0.000 0.00034
+1 -0.0001 1 1 0.0077 -0.0003 0.006 0.014 0.00003
+1 -0.0002 1 1 0.0055 0.0030 0.006 0.028 -0.00019
+1 0.0001 1 1 -0.0047 0.0023 0.013 0.030 -0.00026
+1 0.0002 1 1 -0.0092 0.0003 0.011 0.003 -0.00005
+1 0.0001 1 1 0.0054 0.0020 0.008 -0.009 0.00005
+1 0.0005 1 1 -0.0051 0.0010 0.014 0.007 -0.00045
+1 -0.0005 1 1 0.0079 0.0002 0.013 -0.003 0.00029
+1 -0.0002 1 1 0.0052 0.0014 0.014 0.015 -0.00025
+1 0.0004 1 1 -0.0040 -0.0020 0.009 0.017 -0.00043
+1 0.0001 1 1 -0.0029 0.0037 0.005 -0.015 0.00010
+1 0.0001 1 1 0.0058 0.0000 0.011 -0.011 0.00022
+1 -0.0003 1 1 0.0055 0.0004 0.009 0.011 -0.00023
+1 0.0001 1 1 -0.0070 0.0011 0.010 0.011 -0.00054
+1 -0.0004 1 1 0.0104 0.0017 0.005 0.006 0.00011
+1 -0.0003 1 1 0.0050 0.0025 0.009 0.027 -0.00037
+1 0.0003 1 1 -0.0114 0.0019 0.015 0.017 -0.00045
+1 0.0001 1 1 -0.0142 -0.0003 0.013 -0.011 0.00005
+1 0.0001 1 1 -0.0118 -0.0009 0.011 -0.030 0.00031
+1 -0.0001 1 1 0.0087 0.0010 0.007 -0.025 0.00014
+1 -0.0003 1 1 0.0066 0.0021 0.012 0.013 -0.00008
+1 0.0001 1 1 -0.0089 0.0008 0.013 0.008 -0.00028
+1 0.0001 1 1 -0.0089 0.0008 0.012 -0.014 0.00027
+1 -0.0001 1 1 0.0090 -0.0015 0.003 -0.014 0.00033
+1 -0.0001 1 1 0.0124 0.0017 0.003 0.001 0.00019
+1 0.0001 1 1 0.0070 0.0043 0.008 0.023 -0.00055
+1 -0.0002 1 1 -0.0011 0.0029 0.012 0.028 -0.00042
+1 0.0001 1 1 -0.0097 -0.0012 0.016 0.011 -0.00002
+1 -0.0004 1 1 0.0060 -0.0003 0.003 -0.006 0.00036
+1 -0.0004 1 1 0.0060 0.0021 0.007 0.018 -0.00010
+1 0.0001 1 1 -0.0036 0.0013 0.009 0.006 -0.00006
+1 -0.0001 1 1 0.0039 0.0007 0.005 0.007 0.00007
+1 0.0003 1 1 -0.0046 0.0025 0.013 0.008 -0.00013
+1 -0.0004 1 1 0.0072 -0.0002 0.006 0.013 0.00013
+1 -0.0002 1 1 0.0004 0.0033 0.010 0.028 -0.00029
+1 0.0002 1 1 -0.0063 0.0030 0.014 0.023 -0.00045
+1 0.0001 1 1 -0.0031 -0.0005 0.004 -0.010 0.00013
+1 -0.0004 1 1 0.0045 0.0041 0.007 -0.007 0.00013
+1 0.0003 1 1 -0.0057 -0.0002 0.012 -0.013 -0.00008
+1 -0.0004 1 1 0.0099 0.0007 0.010 -0.003 0.00020
+1 -0.0002 1 1 0.0082 0.0014 0.011 0.017 -0.00022
+1 0.0001 1 1 -0.0074 0.0027 0.022 0.000 -0.00016
+1 0.0001 1 1 -0.0046 -0.0001 0.017 -0.013 0.00045
+1 -0.0001 1 1 0.0013 0.0018 0.011 0.011 -0.00005
+1 0.0006 1 1 -0.0054 0.0024 0.011 0.006 -0.00031
+1 0.0006 1 1 -0.0051 0.0040 0.014 -0.015 -0.00013
+1 -0.0003 1 1 0.0066 0.0013 0.013 -0.018 0.00042
+1 -0.0006 1 1 0.0039 0.0038 0.029 0.000 0.00037
+1 -0.0003 1 1 0.0065 0.0047 0.029 0.013 -0.00007
+1 0.0010 1 1 -0.0079 0.0026 0.024 0.010 -0.00040
+1 0.0007 1 1 -0.0083 0.0036 0.022 -0.012 0.00016
+1 -0.0011 1 1 0.0059 0.0051 0.021 -0.018 0.00041
+1 -0.0007 1 1 0.0047 0.0015 0.017 0.010 0.00006
+1 0.0003 1 1 -0.0053 0.0058 0.022 0.004 -0.00006
+1 -0.0013 1 1 0.0070 0.0011 0.018 -0.006 0.00050
+1 0.0007 1 1 -0.0051 0.0016 0.023 0.009 -0.00027
+1 0.0007 1 1 -0.0024 0.0026 0.021 -0.010 -0.00009
+1 -0.0001 1 1 0.0039 0.0040 0.020 -0.011 0.00025
+1 -0.0005 1 1 0.0064 0.0042 0.020 -0.004 0.00014
+1 -0.0003 1 1 0.0039 0.0048 0.013 0.010 -0.00002
+1 0.0006 1 1 -0.0044 0.0022 0.020 -0.009 -0.00011
+1 -0.0005 1 1 0.0060 0.0037 0.016 -0.009 0.00017
+1 0.0003 1 1 -0.0066 0.0042 0.019 -0.005 -0.00023
+1 -0.0002 1 1 0.0087 0.0045 0.013 -0.013 0.00038
+1 0.0002 1 1 0.0040 0.0058 0.019 0.014 -0.00033
+1 0.0001 1 1 -0.0037 0.0033 0.015 0.005 -0.00010
+1 0.0001 1 1 -0.0013 0.0035 0.012 -0.010 0.00014
+1 -0.0004 1 1 0.0054 0.0034 0.013 -0.004 0.00015
+1 0.0004 1 1 -0.0067 0.0039 0.012 -0.011 -0.00008
+1 -0.0005 1 1 0.0083 0.0029 0.015 -0.005 0.00016
+1 -0.0005 1 1 0.0042 0.0018 0.015 0.013 -0.00024
+1 0.0001 1 1 -0.0022 -0.0007 0.017 -0.017 0.00007
+1 0.0002 1 1 0.0010 0.0020 0.029 -0.018 0.00003
+1 -0.0002 1 1 0.0039 0.0006 0.029 -0.007 0.00003
+1 0.0001 1 1 -0.0029 0.0020 0.022 -0.010 -0.00002
+1 0.0001 1 1 -0.0023 0.0021 0.025 -0.016 0.00004
+1 0.0001 1 1 -0.0003 0.0012 0.026 -0.020 0.00007
+1 -0.0003 1 1 0.0049 -0.0003 0.020 -0.008 0.00006
+1 0.0003 1 1 -0.0049 0.0020 0.021 -0.011 -0.00004
+1 0.0003 1 1 -0.0030 0.0005 0.020 -0.011 -0.00002
+1 -0.0001 1 1 0.0043 -0.0001 0.013 -0.007 0.00007
+1 0.0001 1 1 0.0051 0.0028 0.019 0.002 0.00002
+1 -0.0001 1 1 0.0048 0.0004 0.018 0.013 -0.00008
+1 0.0001 1 1 -0.0039 -0.0011 0.012 0.018 -0.00022
+1 0.0003 1 1 -0.0076 0.0001 0.013 -0.008 -0.00002
+1 0.0001 1 1 -0.0034 0.0020 0.013 -0.028 0.00016
+1 0.0001 1 1 0.0042 -0.0011 0.013 -0.027 0.00020
+1 -0.0002 1 1 0.0075 -0.0017 0.011 -0.018 0.00022
+1 0.0003 1 1 -0.0039 -0.0012 0.017 0.011 -0.00018
+1 0.0001 1 1 -0.0033 0.0001 0.014 -0.010 0.00001
+1 0.0001 1 1 0.0056 0.0024 0.015 0.004 0.00001
+1 -0.0004 1 1 0.0059 -0.0032 0.007 0.013 0.00001
+1 0.0001 1 1 -0.0102 0.0036 0.016 0.003 -0.00022
+1 0.0004 1 1 -0.0128 0.0014 0.016 -0.016 -0.00012
+1 0.0001 1 1 -0.0053 -0.0008 0.016 -0.047 0.00040
+1 -0.0004 1 1 0.0058 -0.0023 0.008 -0.046 0.00038
+1 -0.0002 1 1 0.0039 0.0010 0.011 -0.008 0.00015
+1 0.0001 1 1 0.0020 0.0006 0.014 0.011 -0.00018
+1 -0.0002 1 1 0.0022 0.0001 0.011 0.010 0.00000
+1 0.0001 1 1 -0.0047 0.0014 0.014 -0.001 -0.00012
+1 0.0003 1 1 -0.0056 -0.0019 0.011 -0.011 -0.00001
+1 -0.0002 1 1 0.0070 -0.0019 0.012 0.005 0.00013
+1 0.0002 1 1 -0.0064 0.0010 0.011 0.015 -0.00022
+1 -0.0001 1 1 0.0041 0.0008 0.010 -0.013 0.00016
+1 -0.0001 1 1 0.0031 -0.0019 0.008 0.010 -0.00004
+1 0.0002 1 1 -0.0045 0.0017 0.011 0.006 -0.00011
+1 -0.0001 1 1 0.0008 -0.0004 0.013 0.010 -0.00002
+1 0.0002 1 1 -0.0040 0.0004 0.008 0.003 -0.00010
+1 0.0001 1 1 -0.0035 0.0022 0.011 -0.010 0.00001
+1 -0.0001 1 1 0.0033 -0.0011 0.007 -0.004 -0.00006
+1 0.0002 1 1 -0.0046 -0.0002 0.007 -0.013 -0.00005
+1 -0.0002 1 1 0.0039 -0.0003 0.011 0.011 -0.00003
+1 -0.0001 1 1 -0.0048 0.0002 0.014 0.006 -0.00016
+1 0.0003 1 1 -0.0071 -0.0041 0.010 -0.002 -0.00014
+1 -0.0001 1 1 0.0050 0.0014 0.006 -0.014 0.00021
+1 -0.0002 1 1 0.0063 -0.0006 0.012 0.010 -0.00001
+1 -0.0004 1 1 0.0024 0.0015 0.010 0.010 0.00008
+1 -0.0001 1 1 0.0049 0.0030 0.008 0.020 0.00012
+1 -0.0002 1 1 0.0056 0.0016 0.011 0.029 0.00000
+1 0.0001 1 1 -0.0069 -0.0048 0.013 0.023 -0.00009
+1 0.0001 1 1 -0.0004 0.0010 0.011 -0.009 0.00000
+1 0.0001 1 1 0.0029 -0.0002 0.010 -0.006 0.00010
+1 -0.0002 1 1 0.0055 0.0014 0.012 0.006 0.00007
+1 -0.0001 1 1 0.0044 0.0020 0.015 0.013 -0.00015
+1 0.0002 1 1 -0.0041 -0.0005 0.014 0.014 -0.00035
+1 0.0003 1 1 -0.0076 -0.0036 0.008 0.004 -0.00014
+1 -0.0002 1 1 0.0031 0.0017 0.007 -0.008 0.00006
+1 0.0001 1 1 -0.0022 -0.0008 0.009 -0.011 -0.00002
+1 -0.0001 1 1 0.0039 -0.0016 0.008 -0.008 0.00012
+1 -0.0002 1 1 0.0046 0.0032 0.017 -0.026 0.00032
+1 -0.0003 1 1 0.0081 -0.0001 0.018 0.013 -0.00002
+1 0.0001 1 1 -0.0057 -0.0013 0.014 0.026 -0.00056
+1 0.0005 1 1 -0.0119 0.0025 0.015 0.013 -0.00036
+1 -0.0003 1 1 0.0051 -0.0020 0.013 -0.041 0.00033
+1 -0.0001 1 1 -0.0043 -0.0022 0.009 -0.010 -0.00008
+1 0.0004 1 1 -0.0060 0.0023 0.014 -0.020 -0.00008
+1 -0.0001 1 1 0.0080 0.0005 0.014 -0.018 0.00020
+1 -0.0003 1 1 0.0099 0.0009 0.015 0.017 -0.00002
+1 -0.0002 1 1 0.0060 -0.0001 0.014 0.031 -0.00031
+1 0.0002 1 1 -0.0044 0.0030 0.013 -0.012 0.00006
+1 -0.0002 1 1 0.0066 0.0000 0.014 -0.007 0.00016
+1 -0.0003 1 1 0.0049 -0.0030 0.012 0.012 -0.00009
+1 0.0004 1 1 -0.0042 -0.0014 0.007 0.015 -0.00040
+1 0.0001 1 1 -0.0037 0.0044 0.018 -0.028 0.00018
+1 -0.0003 1 1 0.0048 0.0003 0.015 -0.026 0.00015
+1 -0.0002 1 1 0.0047 0.0009 0.014 -0.005 0.00012
+1 0.0001 1 1 0.0011 -0.0014 0.007 0.009 -0.00009
+1 0.0003 1 1 -0.0038 0.0019 0.010 0.005 -0.00013
+1 -0.0002 1 1 0.0053 0.0007 0.011 0.012 0.00004
+1 0.0001 1 1 -0.0019 -0.0007 0.010 -0.011 0.00012
+1 -0.0004 1 1 0.0047 0.0003 0.009 -0.005 0.00014
+1 0.0002 1 1 -0.0033 0.0022 0.013 -0.011 0.00000
+1 -0.0003 1 1 0.0061 -0.0008 0.010 -0.006 0.00018
+1 0.0001 1 1 -0.0059 0.0008 0.010 0.009 -0.00021
+1 -0.0001 1 1 0.0061 -0.0001 0.008 -0.008 0.00028
+1 -0.0001 1 1 0.0080 0.0013 0.009 0.011 -0.00004
+1 -0.0001 1 1 0.0041 -0.0033 0.012 0.029 -0.00014
+1 0.0004 1 1 -0.0037 -0.0017 0.005 0.031 -0.00028
+1 -0.0001 1 1 0.0030 -0.0002 0.010 0.011 0.00005
+1 0.0002 1 1 -0.0057 0.0015 0.010 0.008 -0.00011
+1 0.0002 1 1 -0.0036 0.0013 0.013 -0.011 0.00010
+1 -0.0001 1 1 0.0057 0.0017 0.010 -0.007 0.00020
+1 -0.0001 1 1 0.0054 -0.0007 0.013 0.021 -0.00005
+1 -0.0002 1 1 0.0023 -0.0030 0.012 0.030 -0.00019
+1 0.0003 1 1 -0.0080 -0.0017 0.004 0.021 -0.00029
+1 -0.0001 1 1 0.0051 -0.0019 0.007 -0.022 0.00027
+1 -0.0003 1 1 0.0077 0.0013 0.007 -0.013 0.00012
+1 0.0001 1 1 0.0038 0.0019 0.013 0.013 -0.00013
+1 -0.0002 1 1 0.0019 0.0019 0.011 0.027 -0.00003
+1 0.0001 1 1 -0.0066 0.0003 0.013 0.022 -0.00033
+1 0.0002 1 1 -0.0088 0.0001 0.013 0.011 -0.00009
+1 0.0001 1 1 -0.0057 -0.0014 0.008 -0.011 0.00017
+1 -0.0001 1 1 0.0038 0.0028 0.011 -0.006 0.00003
+1 -0.0001 1 1 -0.0015 -0.0010 0.006 -0.009 0.00004
+1 -0.0002 1 1 0.0035 0.0014 0.007 -0.007 0.00021
+1 0.0002 1 1 -0.0005 -0.0009 0.012 -0.009 0.00003
+1 -0.0003 1 1 0.0029 0.0006 0.011 -0.007 0.00014
+1 0.0002 1 1 -0.0043 0.0022 0.009 -0.010 -0.00007
+1 -0.0001 1 1 0.0038 0.0004 0.002 -0.013 0.00008
+1 0.0003 1 1 -0.0048 -0.0004 0.012 -0.011 -0.00009
+1 -0.0004 1 1 0.0060 -0.0003 0.011 0.018 -0.00004
+1 0.0001 1 1 -0.0097 -0.0019 0.009 0.012 -0.00037
+1 0.0002 1 1 -0.0129 0.0024 0.010 -0.002 -0.00020
+1 0.0001 1 1 -0.0072 0.0015 0.012 -0.038 0.00033
+1 -0.0003 1 1 0.0055 -0.0018 0.004 -0.041 0.00042
+1 -0.0002 1 1 0.0081 0.0027 0.005 -0.025 0.00002
+1 -0.0001 1 1 0.0038 0.0037 0.007 0.007 -0.00001
+1 0.0001 1 1 -0.0071 -0.0014 0.010 0.004 -0.00024
+1 0.0002 1 1 -0.0084 -0.0006 0.007 -0.013 -0.00001
+1 0.0001 1 1 -0.0045 0.0026 0.006 -0.029 0.00020
+1 0.0001 1 1 0.0036 -0.0008 0.009 -0.015 -0.00001
+1 -0.0003 1 1 0.0067 0.0019 0.006 0.012 0.00001
+1 -0.0002 1 1 0.0012 -0.0012 0.005 0.027 -0.00009
+1 0.0001 1 1 -0.0054 0.0027 0.009 0.022 -0.00023
+1 -0.0001 1 1 0.0040 -0.0009 0.007 0.024 -0.00009
+1 -0.0001 1 1 0.0014 0.0022 0.010 0.030 -0.00012
+1 0.0002 1 1 -0.0052 -0.0008 0.010 0.023 -0.00015
+1 -0.0001 1 1 0.0037 0.0019 0.008 0.011 0.00003
+1 0.0003 1 1 -0.0051 0.0007 0.010 0.007 -0.00011
+1 -0.0002 1 1 0.0022 0.0005 0.006 0.010 0.00000
+1 0.0001 1 1 -0.0038 0.0025 0.012 0.009 -0.00020
+1 0.0001 1 1 -0.0020 -0.0006 0.008 -0.010 0.00005
+1 -0.0002 1 1 0.0053 0.0009 0.008 -0.001 0.00011
+1 -0.0003 1 1 0.0031 0.0020 0.011 -0.008 0.00014
+1 -0.0002 1 1 0.0064 0.0001 0.006 0.016 0.00004
+1 -0.0001 1 1 0.0015 0.0003 0.010 0.035 -0.00012
+1 0.0001 1 1 -0.0047 0.0014 0.012 0.030 -0.00020
+1 0.0002 1 1 -0.0064 -0.0013 0.010 0.022 -0.00008
+1 -0.0001 1 1 0.0031 0.0021 0.005 0.010 0.00012
+1 0.0002 1 1 -0.0082 0.0016 0.010 0.001 -0.00007
+1 0.0002 1 1 -0.0064 0.0012 0.011 -0.013 0.00016
+1 0.0001 1 1 0.0084 0.0018 0.009 -0.005 0.00017
+1 -0.0001 1 1 0.0105 0.0001 0.007 0.008 0.00012
+1 -0.0002 1 1 0.0081 0.0004 0.007 0.032 -0.00021
+1 0.0003 1 1 -0.0014 0.0008 0.008 0.042 -0.00036
+1 0.0002 1 1 -0.0023 0.0003 0.012 -0.017 0.00007
+1 -0.0003 1 1 0.0060 0.0000 0.009 -0.008 0.00013
+1 -0.0002 1 1 0.0018 0.0014 0.010 0.010 -0.00016
+1 0.0005 1 1 -0.0091 -0.0007 0.010 0.000 -0.00035
+1 -0.0004 1 1 0.0085 0.0005 0.006 -0.022 0.00038
+1 0.0001 1 1 0.0071 0.0013 0.010 0.025 -0.00013
+1 0.0001 1 1 0.0015 -0.0013 0.007 0.039 -0.00028
+1 0.0002 1 1 -0.0014 0.0008 0.008 0.039 -0.00019
+1 -0.0002 1 1 -0.0015 0.0009 0.010 0.035 0.00002
+1 0.0005 1 1 -0.0121 -0.0012 0.013 0.006 -0.00021
+1 -0.0003 1 1 0.0077 -0.0026 0.007 0.012 0.00007
+1 -0.0001 1 1 -0.0004 0.0018 0.008 0.029 -0.00021
+1 0.0005 1 1 -0.0079 0.0019 0.012 0.019 -0.00026
+1 -0.0001 1 1 0.0064 0.0011 0.009 0.018 0.00004
+1 -0.0002 1 1 0.0056 0.0012 0.010 0.028 -0.00008
+1 -0.0001 1 1 0.0019 -0.0029 0.012 0.035 -0.00033
+1 0.0002 1 1 -0.0064 -0.0017 0.006 0.029 -0.00032
+1 -0.0003 1 1 0.0026 -0.0006 0.005 0.010 0.00001
+1 0.0003 1 1 -0.0054 -0.0021 0.011 0.006 -0.00021
+1 0.0001 1 1 -0.0039 -0.0005 0.007 -0.011 0.00011
+1 0.0001 1 1 0.0003 -0.0006 0.014 -0.009 -0.00001
+1 -0.0001 1 1 0.0048 -0.0014 0.007 0.003 0.00008
+1 0.0004 1 1 -0.0057 -0.0009 0.005 0.007 -0.00014
+1 0.0001 1 1 -0.0025 0.0005 0.007 -0.011 0.00005
+1 -0.0001 1 1 0.0040 0.0004 0.008 -0.007 0.00010
+1 -0.0003 1 1 0.0023 0.0013 0.009 0.010 0.00008
+1 0.0004 1 1 -0.0049 -0.0010 0.009 0.008 -0.00021
+1 -0.0002 1 1 0.0061 -0.0003 0.007 0.013 0.00003
+1 0.0002 1 1 -0.0034 0.0011 0.011 0.021 -0.00017
+1 -0.0001 1 1 0.0026 0.0009 0.008 0.010 0.00000
+1 0.0001 1 1 -0.0035 0.0011 0.012 0.006 -0.00006
+1 0.0004 1 1 -0.0091 0.0023 0.008 -0.026 -0.00003
+1 -0.0001 1 1 0.0039 0.0004 0.006 -0.040 0.00042
+1 -0.0001 1 1 0.0078 0.0044 0.010 -0.032 0.00018
+1 0.0002 1 1 -0.0005 0.0040 0.004 -0.010 0.00002
+1 -0.0004 1 1 0.0032 0.0027 0.009 -0.007 0.00017
+1 -0.0002 1 1 0.0051 0.0008 0.007 0.020 0.00000
+1 -0.0002 1 1 0.0018 0.0012 0.009 0.027 -0.00026
+1 0.0005 1 1 -0.0050 0.0001 0.009 0.025 -0.00040
+1 0.0001 1 1 -0.0036 0.0007 0.008 0.005 -0.00005
+1 -0.0001 1 1 0.0036 0.0015 0.010 -0.005 0.00005
+1 -0.0002 1 1 0.0013 -0.0004 0.010 0.011 -0.00003
+1 0.0002 1 1 -0.0042 0.0000 0.008 0.006 -0.00015
+1 -0.0001 1 1 0.0035 0.0014 0.009 -0.007 0.00010
+1 0.0001 1 1 -0.0033 0.0008 0.008 -0.006 -0.00001
+1 -0.0002 1 1 0.0045 0.0005 0.004 -0.005 0.00010
+1 0.0001 1 1 -0.0016 -0.0004 0.006 -0.010 0.00005
+1 -0.0003 1 1 0.0038 0.0021 0.004 -0.006 0.00014
+1 0.0001 1 1 -0.0043 0.0001 0.010 -0.012 -0.00003
+1 -0.0001 1 1 0.0061 0.0015 0.008 -0.005 0.00008
+1 -0.0001 1 1 0.0050 0.0017 0.012 0.012 -0.00007
+1 0.0001 1 1 0.0016 -0.0036 0.041 -0.006 0.00005
+1 -0.0004 1 1 0.0002 0.0025 0.022 0.010 -0.00007
+1 0.0005 1 1 -0.0057 -0.0016 0.027 0.000 -0.00013
+1 0.0001 1 1 -0.0053 -0.0020 0.022 -0.011 0.00008
+1 -0.0003 1 1 0.0058 0.0021 0.027 -0.006 0.00007
+1 -0.0003 1 1 0.0029 0.0010 0.030 0.011 -0.00012
+1 0.0001 1 1 -0.0038 0.0008 0.031 0.010 -0.00024
+1 0.0001 1 1 -0.0032 -0.0009 0.023 -0.012 0.00009
+1 -0.0002 1 1 0.0036 0.0006 0.019 -0.008 0.00004
+1 -0.0001 1 1 0.0027 -0.0011 0.007 -0.006 0.00002
+1 -0.0001 1 1 0.0018 -0.0002 0.016 0.010 -0.00002
+1 0.0001 1 1 -0.0036 -0.0014 0.007 0.006 -0.00008
+1 0.0001 1 1 0.0048 0.0000 0.008 -0.005 0.00015
+1 -0.0001 1 1 0.0073 0.0009 0.010 0.004 0.00014
+1 -0.0001 1 1 0.0058 0.0018 0.015 0.028 -0.00009
+1 0.0002 1 1 -0.0050 -0.0015 0.013 0.024 -0.00004
+1 -0.0001 1 1 0.0051 0.0011 0.005 0.014 0.00008
+1 -0.0001 1 1 0.0009 -0.0005 0.012 0.010 -0.00001
+1 -0.0002 1 1 0.0061 -0.0019 0.010 -0.017 0.00011
+1 0.0001 1 1 -0.0019 -0.0019 0.005 -0.012 0.00003
+1 -0.0002 1 1 0.0036 0.0012 0.005 -0.006 0.00008
+1 -0.0001 1 1 0.0027 0.0008 0.006 -0.007 0.00005
+1 0.0001 1 1 -0.0031 0.0013 0.015 -0.011 -0.00004
+1 -0.0001 1 1 0.0053 0.0012 0.005 -0.005 0.00009
+1 -0.0001 1 1 0.0039 0.0024 0.013 0.013 -0.00007
+1 0.0002 1 1 -0.0063 -0.0001 0.012 0.007 -0.00016
+1 -0.0001 1 1 0.0062 0.0005 0.008 -0.004 0.00005
+1 0.0001 1 1 -0.0063 -0.0005 0.012 0.003 -0.00010
+1 -0.0002 1 1 0.0046 -0.0006 0.012 -0.025 0.00010
+1 0.0002 1 1 -0.0041 -0.0023 0.015 0.007 -0.00008
+1 -0.0001 1 1 0.0046 0.0009 0.001 -0.002 0.00011
+1 0.0001 1 1 -0.0040 -0.0007 0.015 0.003 -0.00003
+1 -0.0001 1 1 0.0043 -0.0001 0.006 0.012 0.00001
+1 0.0001 1 1 -0.0035 0.0021 0.015 0.023 -0.00008
+1 -0.0001 1 1 0.0026 0.0029 0.005 0.010 0.00001
+1 0.0003 1 1 -0.0054 -0.0005 0.012 0.002 -0.00010
+1 -0.0002 1 1 0.0042 -0.0011 0.007 -0.005 0.00018
+1 0.0002 1 1 -0.0053 -0.0006 0.010 0.006 -0.00012
+1 -0.0001 1 1 -0.0030 -0.0009 0.005 -0.012 0.00009
+1 -0.0001 1 1 0.0037 -0.0005 0.011 0.000 -0.00001
+1 0.0001 1 1 -0.0034 -0.0005 0.005 0.000 -0.00006
+1 0.0001 1 1 -0.0039 0.0013 0.008 -0.011 0.00001
+1 -0.0001 1 1 0.0058 0.0012 0.010 -0.003 0.00007
+1 -0.0001 1 1 0.0047 -0.0006 0.013 0.017 -0.00007
+1 0.0002 1 1 -0.0061 -0.0006 0.008 0.007 -0.00007
+1 0.0001 1 1 -0.0030 0.0001 0.007 -0.012 0.00012
+1 -0.0002 1 1 0.0060 0.0019 0.007 -0.003 0.00013
+1 -0.0002 1 1 0.0052 0.0022 0.015 0.020 -0.00007
+1 0.0002 1 1 -0.0067 -0.0012 0.010 0.015 -0.00018
+1 0.0001 1 1 -0.0035 -0.0008 0.004 -0.014 0.00010
+1 -0.0001 1 1 0.0052 0.0009 0.007 -0.010 0.00016
+1 -0.0004 1 1 0.0019 0.0005 0.010 0.029 0.00002
+1 0.0005 1 1 -0.0064 0.0010 0.012 0.024 -0.00034
+1 -0.0001 1 1 0.0045 0.0022 0.013 0.027 -0.00005
+1 -0.0002 1 1 0.0036 -0.0014 0.013 0.032 -0.00008
+1 0.0001 1 1 -0.0073 0.0029 0.004 0.016 -0.00010
+1 -0.0001 1 1 0.0035 0.0000 0.012 -0.017 0.00017
+1 0.0001 1 1 -0.0038 0.0005 0.008 0.006 -0.00004
+1 -0.0001 1 1 0.0004 0.0003 0.017 0.011 -0.00004
+1 -0.0001 1 1 0.0031 0.0001 0.005 0.010 0.00002
+1 0.0002 1 1 -0.0048 -0.0021 0.001 0.008 -0.00011
+1 -0.0001 1 1 0.0030 -0.0007 0.006 0.010 -0.00001
+1 0.0001 1 1 -0.0036 0.0003 0.014 0.007 -0.00005
+1 0.0003 1 1 -0.0030 0.0008 0.011 -0.013 -0.00008
+1 -0.0002 1 1 0.0038 -0.0010 0.007 -0.014 0.00021
+1 -0.0001 1 1 0.0055 0.0005 0.007 -0.001 0.00001
+1 -0.0002 1 1 0.0021 -0.0013 0.011 0.011 -0.00017
+1 -0.0001 1 1 -0.0041 0.0012 0.012 0.009 -0.00030
+1 0.0001 1 1 -0.0088 -0.0001 0.011 0.000 -0.00034
+1 -0.0001 1 1 0.0063 0.0013 0.013 0.008 0.00000
+1 0.0001 1 1 0.0056 0.0000 0.015 0.019 -0.00006
+1 -0.0001 1 1 0.0041 -0.0008 0.013 0.030 -0.00008
+1 0.0002 1 1 -0.0010 -0.0010 0.011 0.035 -0.00018
+1 0.0002 1 1 -0.0070 -0.0004 0.009 0.008 -0.00007
+1 -0.0001 1 1 0.0046 -0.0009 0.001 -0.010 0.00020
+1 -0.0001 1 1 0.0074 0.0013 0.006 0.023 -0.00006
+1 0.0001 1 1 -0.0051 0.0026 0.007 -0.012 0.00009
+1 -0.0001 1 1 0.0067 0.0015 0.009 -0.002 0.00010
+1 -0.0001 1 1 0.0047 0.0015 0.017 0.020 -0.00014
+1 0.0002 1 1 -0.0081 -0.0028 0.013 -0.001 -0.00006
+1 -0.0002 1 1 0.0034 0.0017 0.011 -0.006 -0.00001
+1 0.0001 1 1 -0.0028 0.0019 0.012 -0.013 0.00001
+1 -0.0001 1 1 0.0059 -0.0014 0.008 0.010 0.00001
+1 -0.0001 1 1 0.0025 -0.0003 0.005 0.029 -0.00010
+1 0.0001 1 1 -0.0068 0.0001 0.004 0.018 -0.00015
+1 0.0001 1 1 -0.0062 0.0009 0.007 -0.014 0.00007
+1 0.0002 1 1 -0.0073 0.0004 0.012 -0.016 -0.00013
+1 0.0001 1 1 -0.0045 -0.0020 0.006 -0.035 0.00015
+1 -0.0001 1 1 0.0036 0.0020 0.016 0.012 -0.00011
+1 -0.0001 1 1 0.0006 0.0009 0.016 0.011 -0.00008
+1 -0.0001 1 1 0.0025 0.0018 -0.003 0.011 0.00002
+1 -0.0001 1 1 0.0036 -0.0013 0.007 0.012 0.00002
+1 0.0001 1 1 -0.0015 0.0000 0.006 -0.010 0.00004
+1 -0.0002 1 1 0.0033 0.0005 0.005 -0.007 0.00011
+1 0.0002 1 1 -0.0036 -0.0007 0.009 -0.012 -0.00002
+1 -0.0001 1 1 0.0042 0.0007 0.009 -0.013 0.00012
+1 -0.0001 1 1 0.0012 -0.0001 0.012 0.010 -0.00004
+1 0.0002 1 1 -0.0043 -0.0005 0.011 0.005 -0.00016
+1 -0.0001 1 1 0.0047 0.0008 0.003 -0.003 0.00009
+1 0.0001 1 1 -0.0008 0.0020 0.011 -0.010 0.00003
+1 -0.0003 1 1 0.0028 0.0006 0.012 -0.007 0.00014
+1 -0.0001 1 1 0.0036 -0.0012 0.002 -0.007 0.00017
+1 -0.0001 1 1 0.0055 0.0026 0.004 0.012 0.00000
+1 0.0002 1 1 -0.0035 -0.0007 0.016 0.028 -0.00015
+1 0.0001 1 1 -0.0018 -0.0007 -0.001 -0.009 0.00005
+1 -0.0001 1 1 0.0036 0.0059 0.003 -0.005 0.00005
+1 0.0001 1 1 -0.0023 -0.0007 0.008 -0.011 0.00002
+1 0.0002 1 1 -0.0061 -0.0015 0.014 0.004 -0.00010
+1 0.0001 1 1 -0.0040 -0.0009 0.011 -0.012 0.00010
+1 -0.0001 1 1 0.0038 -0.0010 0.004 -0.010 0.00006
+1 -0.0001 1 1 0.0027 0.0012 0.005 0.011 -0.00005
+1 0.0001 1 1 -0.0038 -0.0002 0.012 -0.005 -0.00004
+1 0.0001 1 1 -0.0033 0.0005 0.004 -0.014 -0.00002
+1 -0.0001 1 1 0.0059 -0.0009 0.008 0.000 0.00005
+1 -0.0001 1 1 0.0043 0.0002 0.008 0.017 -0.00008
+1 0.0001 1 1 -0.0060 0.0005 0.011 0.008 -0.00007
+1 -0.0001 1 1 0.0040 0.0002 0.010 -0.006 0.00004
+1 -0.0002 1 1 0.0038 -0.0009 0.005 0.012 0.00002
+1 0.0002 1 1 -0.0066 0.0006 0.008 0.001 -0.00010
+1 -0.0001 1 1 0.0041 0.0002 0.007 -0.005 0.00004
+1 -0.0001 1 1 0.0003 -0.0020 0.013 0.010 -0.00006
+1 -0.0002 1 1 0.0021 -0.0006 0.011 0.009 0.00000
+1 0.0001 1 1 -0.0020 0.0026 0.011 -0.010 -0.00001
+1 -0.0001 1 1 0.0037 0.0000 0.012 -0.007 0.00014
+1 0.0001 1 1 0.0046 0.0014 0.014 0.003 0.00000
+1 -0.0002 1 1 0.0045 -0.0020 0.012 0.010 0.00000
+1 0.0001 1 1 -0.0035 -0.0011 0.006 0.014 -0.00019
+1 0.0001 1 1 -0.0039 0.0013 0.004 -0.014 0.00002
+1 -0.0001 1 1 0.0039 -0.0008 0.005 0.010 0.00003
+1 0.0001 1 1 -0.0027 -0.0015 0.010 -0.011 0.00013
+1 -0.0001 1 1 0.0037 -0.0011 0.006 -0.010 0.00020
+1 -0.0001 1 1 0.0064 0.0012 0.009 0.009 0.00000
+1 -0.0001 1 1 0.0041 -0.0004 0.010 0.028 -0.00011
+1 0.0002 1 1 -0.0045 -0.0022 0.006 0.028 -0.00017
+1 -0.0001 1 1 0.0028 0.0024 0.013 0.010 0.00002
+1 0.0001 1 1 -0.0040 0.0006 0.004 0.006 -0.00004
+1 -0.0001 1 1 0.0025 0.0004 0.013 0.010 -0.00001
+1 0.0001 1 1 -0.0004 -0.0004 0.008 -0.009 0.00004
+1 0.0003 1 1 -0.0040 -0.0014 0.010 -0.011 -0.00015
+1 -0.0001 1 1 0.0035 0.0005 0.005 -0.011 0.00006
+1 -0.0001 1 1 0.0030 -0.0013 0.001 0.011 0.00000
+1 0.0001 1 1 0.0037 0.0004 0.015 -0.009 0.00015
+1 -0.0002 1 1 0.0060 -0.0013 0.013 0.000 0.00011
+1 -0.0001 1 1 0.0044 -0.0022 0.005 0.021 -0.00007
+1 0.0001 1 1 -0.0039 0.0000 0.002 0.024 -0.00023
+1 0.0001 1 1 -0.0063 0.0018 0.006 0.006 -0.00003
+1 -0.0001 1 1 0.0046 0.0001 0.010 -0.005 0.00023
+1 0.0004 1 1 -0.0102 0.0010 0.020 -0.010 0.00001
+1 -0.0003 1 1 0.0057 -0.0016 0.027 -0.033 0.00019
+1 0.0004 1 1 -0.0053 0.0007 0.020 -0.011 -0.00015
+1 -0.0005 1 1 0.0066 0.0032 0.019 -0.020 0.00017
+1 0.0005 1 1 -0.0051 0.0006 0.022 -0.008 -0.00021
+1 -0.0007 1 1 0.0070 -0.0003 0.018 -0.021 0.00029
+1 -0.0002 1 1 0.0032 0.0008 0.010 0.010 0.00000
+1 0.0004 1 1 -0.0053 0.0019 0.014 0.004 -0.00011
+1 0.0001 1 1 0.0005 0.0017 0.016 -0.010 0.00020
+1 -0.0004 1 1 0.0051 0.0008 0.016 -0.004 0.00024
+1 -0.0001 1 1 0.0005 0.0019 0.018 0.011 -0.00024
+1 0.0006 1 1 -0.0076 0.0013 0.019 -0.001 -0.00021
+1 -0.0004 1 1 0.0047 -0.0006 0.011 -0.017 0.00035
+1 -0.0003 1 1 0.0049 0.0015 0.013 0.013 -0.00007
+1 0.0002 1 1 -0.0037 0.0011 0.014 0.016 -0.00026
+1 0.0005 1 1 -0.0060 -0.0003 0.011 0.007 -0.00008
+1 -0.0001 1 1 0.0050 0.0007 0.009 0.000 0.00024
+1 -0.0002 1 1 0.0070 0.0021 0.011 0.013 0.00000
+1 0.0005 1 1 -0.0072 0.0003 0.014 0.022 -0.00034
+1 -0.0001 1 1 0.0068 0.0008 0.002 -0.004 0.00023
+1 0.0005 1 1 -0.0083 0.0026 0.011 0.005 -0.00032
+1 -0.0004 1 1 0.0082 0.0019 0.018 -0.006 0.00025
+1 0.0004 1 1 -0.0080 -0.0009 0.013 0.003 -0.00011
+1 -0.0003 1 1 0.0067 0.0015 0.006 -0.007 0.00026
+1 -0.0002 1 1 0.0058 0.0022 0.011 0.016 -0.00010
+1 0.0005 1 1 -0.0054 0.0001 0.012 0.027 -0.00036
+1 -0.0005 1 1 0.0070 0.0001 0.007 0.011 0.00023
+1 0.0001 1 1 -0.0061 0.0013 0.011 0.024 -0.00024
+1 -0.0003 1 1 0.0045 0.0006 0.009 0.005 0.00027
+1 -0.0005 1 1 0.0016 -0.0013 0.011 0.009 0.00007
+1 0.0007 1 1 -0.0107 0.0007 0.009 -0.009 -0.00024
+1 -0.0003 1 1 0.0082 0.0015 0.007 -0.025 0.00033
+1 0.0001 1 1 -0.0047 0.0008 0.015 0.007 -0.00028
+1 -0.0002 1 1 0.0040 -0.0001 0.009 -0.006 0.00022
+1 -0.0002 1 1 0.0028 0.0015 0.011 0.010 -0.00009
+1 0.0003 1 1 -0.0073 0.0004 0.012 0.003 -0.00025
+1 -0.0004 1 1 0.0061 0.0003 0.007 -0.024 0.00027
+1 0.0006 1 1 -0.0050 0.0007 0.010 -0.011 -0.00030
+1 -0.0002 1 1 0.0073 0.0012 0.010 -0.016 0.00034
+1 -0.0001 1 1 0.0094 0.0002 0.008 0.000 0.00002
+1 -0.0002 1 1 0.0084 0.0010 0.009 0.012 -0.00014
+1 0.0004 1 1 -0.0036 0.0015 0.012 0.023 -0.00030
+1 0.0004 1 1 -0.0077 0.0000 0.008 0.003 -0.00026
+1 -0.0001 1 1 0.0047 0.0029 0.011 -0.021 0.00028
+1 0.0003 1 1 -0.0034 -0.0003 0.009 -0.013 0.00002
+1 -0.0005 1 1 0.0092 -0.0002 0.004 -0.003 0.00028
+1 -0.0001 1 1 0.0052 0.0023 0.006 0.019 -0.00034
+1 0.0001 1 1 -0.0080 0.0008 0.009 0.013 -0.00030
+1 0.0001 1 1 -0.0077 -0.0007 0.006 -0.010 0.00029
+1 -0.0002 1 1 0.0064 0.0011 0.006 -0.013 0.00029
+1 -0.0003 1 1 0.0088 0.0021 0.008 0.003 0.00003
+1 0.0001 1 1 -0.0100 0.0008 0.017 0.005 -0.00026
+1 0.0001 1 1 -0.0121 -0.0015 0.014 -0.011 -0.00009
+1 0.0001 1 1 -0.0052 -0.0007 0.010 -0.029 0.00038
+1 -0.0001 1 1 0.0064 -0.0010 0.005 -0.027 0.00042
+1 -0.0001 1 1 0.0106 0.0008 0.005 -0.015 0.00022
+1 -0.0001 1 1 0.0112 0.0007 0.009 0.024 -0.00005
+1 -0.0004 1 1 0.0080 0.0007 0.009 0.038 -0.00040
+1 -0.0004 1 1 -0.0034 0.0016 0.012 0.038 -0.00006
+1 0.0002 1 1 -0.0112 0.0022 0.016 0.020 -0.00032
+1 0.0001 1 1 0.0054 -0.0003 0.005 -0.015 0.00009
+1 -0.0004 1 1 0.0086 -0.0006 0.002 -0.002 0.00017
+1 0.0005 1 1 -0.0078 0.0011 0.009 0.009 -0.00023
+1 0.0001 1 1 -0.0003 0.0013 0.010 -0.010 0.00028
+1 -0.0004 1 1 0.0049 0.0001 0.009 -0.007 0.00039
+1 -0.0002 1 1 0.0058 0.0017 0.011 0.012 -0.00007
+1 0.0001 1 1 -0.0054 0.0011 0.015 0.013 -0.00019
+1 0.0003 1 1 -0.0087 0.0001 0.014 -0.004 -0.00010
+1 -0.0003 1 1 0.0058 -0.0007 0.005 -0.019 0.00029
+1 -0.0004 1 1 0.0067 0.0008 0.003 0.012 -0.00007
+1 0.0002 1 1 -0.0042 0.0001 0.009 0.006 -0.00010
+1 0.0003 1 1 -0.0042 0.0012 0.009 -0.011 -0.00005
+1 -0.0004 1 1 0.0075 0.0002 0.013 -0.003 0.00013
+1 -0.0002 1 1 0.0039 0.0014 0.014 0.014 -0.00024
+1 0.0001 1 1 -0.0040 0.0007 0.014 0.014 -0.00040
+1 0.0006 1 1 -0.0099 -0.0004 0.011 0.003 -0.00038
+1 -0.0003 1 1 0.0056 -0.0006 0.000 -0.023 0.00047
+1 -0.0004 1 1 0.0036 0.0008 0.015 0.010 0.00006
+1 0.0002 1 1 -0.0063 0.0003 0.014 0.010 -0.00030
+1 -0.0004 1 1 0.0059 0.0009 0.002 -0.007 0.00032
+1 0.0002 1 1 -0.0046 0.0012 0.013 0.010 -0.00019
+1 0.0005 1 1 -0.0026 -0.0003 0.012 -0.011 -0.00005
+1 -0.0004 1 1 0.0057 0.0000 0.010 -0.009 0.00039
+1 -0.0002 1 1 0.0065 0.0019 0.012 0.012 -0.00008
+1 0.0002 1 1 -0.0045 0.0010 0.016 0.017 -0.00041
+1 0.0005 1 1 -0.0083 -0.0006 0.014 0.008 -0.00020
+1 -0.0002 1 1 0.0073 -0.0007 0.002 -0.006 0.00035
+1 -0.0001 1 1 0.0104 0.0001 0.001 0.008 0.00011
+1 -0.0002 1 1 0.0099 0.0015 0.003 0.023 -0.00009
+1 0.0004 1 1 0.0036 0.0039 0.009 0.037 -0.00043
+1 -0.0001 1 1 -0.0009 -0.0016 0.010 0.040 -0.00005
+1 0.0001 1 1 -0.0063 0.0000 0.004 0.022 -0.00008
+1 0.0001 1 1 -0.0056 0.0024 0.018 0.006 -0.00018
+1 0.0001 1 1 -0.0075 0.0009 0.017 -0.004 -0.00011
+1 -0.0002 1 1 0.0064 -0.0002 0.008 -0.007 0.00011
+1 -0.0003 1 1 0.0021 0.0003 0.006 0.011 -0.00015
+1 0.0004 1 1 -0.0065 0.0009 0.006 0.006 -0.00037
+1 0.0002 1 1 -0.0082 0.0020 0.008 -0.010 0.00008
+1 0.0006 1 1 -0.0032 0.0007 0.009 -0.028 -0.00013
+1 -0.0003 1 1 0.0086 0.0015 0.006 -0.024 0.00042
+1 -0.0001 1 1 0.0116 0.0040 0.013 0.000 0.00001
+1 -0.0003 1 1 0.0101 -0.0030 0.015 0.015 -0.00015
+1 0.0001 1 1 -0.0083 0.0013 0.016 0.025 -0.00075
+1 -0.0001 1 1 0.0078 0.0029 0.009 0.003 0.00004
+1 -0.0002 1 1 0.0067 -0.0004 0.011 0.016 -0.00008
+1 -0.0001 1 1 -0.0061 -0.0012 0.009 0.015 -0.00016
+1 0.0001 1 1 -0.0096 0.0000 0.005 0.000 -0.00016
+1 -0.0001 1 1 0.0042 0.0007 0.011 -0.036 0.00031
+1 -0.0001 1 1 0.0090 0.0000 0.008 -0.004 0.00003
+1 -0.0002 1 1 0.0075 0.0011 0.008 0.011 -0.00013
+1 0.0003 1 1 -0.0098 0.0019 0.012 0.005 -0.00035
+1 0.0001 1 1 -0.0038 -0.0004 0.007 -0.034 0.00049
+1 -0.0002 1 1 0.0078 0.0016 0.006 -0.024 0.00019
+1 -0.0001 1 1 0.0025 0.0017 0.009 0.011 -0.00004
+1 0.0007 1 1 -0.0080 0.0013 0.011 0.006 -0.00051
+1 0.0002 1 1 -0.0066 -0.0002 0.009 -0.014 0.00029
+1 -0.0003 1 1 0.0098 0.0005 0.004 -0.006 0.00029
+1 -0.0002 1 1 0.0092 0.0030 0.008 0.015 -0.00012
+1 0.0006 1 1 -0.0051 -0.0004 0.015 0.025 -0.00051
+1 -0.0003 1 1 0.0042 0.0024 0.007 0.010 -0.00001
+1 0.0002 1 1 -0.0062 0.0015 0.013 0.005 -0.00016
+1 0.0003 1 1 -0.0064 0.0002 0.012 -0.011 0.00009
+1 -0.0003 1 1 0.0042 0.0006 0.010 -0.018 0.00029
+1 -0.0001 1 1 0.0060 -0.0021 0.010 -0.003 0.00001
+1 0.0002 1 1 -0.0058 0.0006 0.008 -0.002 -0.00013
+1 0.0001 1 1 -0.0048 0.0010 0.009 -0.013 0.00013
+1 -0.0003 1 1 0.0091 0.0013 0.011 -0.005 0.00032
+1 -0.0003 1 1 0.0103 0.0008 0.011 0.013 -0.00005
+1 -0.0001 1 1 0.0027 0.0012 0.012 0.030 -0.00056
+1 0.0008 1 1 -0.0095 -0.0018 0.010 0.023 -0.00059
+1 0.0001 1 1 0.0003 -0.0004 0.001 -0.009 0.00032
+1 -0.0004 1 1 0.0088 0.0009 0.000 0.000 0.00036
+1 -0.0002 1 1 0.0084 0.0028 0.004 0.015 -0.00018
+1 0.0002 1 1 0.0045 0.0044 0.010 0.025 -0.00032
+1 -0.0002 1 1 0.0036 0.0061 0.016 0.031 -0.00035
+1 0.0001 1 1 -0.0098 -0.0001 0.018 0.019 -0.00029
+1 0.0006 1 1 -0.0129 -0.0022 0.013 0.003 -0.00017
+1 -0.0002 1 1 0.0088 0.0019 0.005 0.001 0.00010
+1 0.0001 1 1 0.0048 0.0023 0.011 0.026 -0.00017
+1 -0.0001 1 1 -0.0060 0.0006 0.003 0.025 -0.00015
+1 0.0004 1 1 -0.0036 0.0016 0.018 -0.011 -0.00006
+1 -0.0005 1 1 0.0080 -0.0019 0.010 -0.006 0.00032
+1 -0.0001 1 1 0.0077 -0.0002 0.008 0.010 -0.00018
+1 0.0001 1 1 0.0038 0.0027 0.011 0.018 -0.00034
+1 0.0001 1 1 -0.0067 -0.0003 0.002 0.012 -0.00022
+1 -0.0002 1 1 0.0054 -0.0025 0.010 -0.021 0.00034
+1 -0.0001 1 1 0.0093 0.0011 0.010 0.005 0.00004
+1 -0.0001 1 1 0.0076 -0.0002 0.009 0.019 -0.00013
+1 -0.0003 1 1 0.0044 0.0005 0.009 0.028 -0.00028
+1 0.0009 1 1 -0.0105 0.0013 0.011 0.021 -0.00054
+1 -0.0002 1 1 0.0067 0.0028 0.006 -0.010 0.00039
+1 -0.0001 1 1 0.0041 0.0025 0.012 0.017 -0.00020
+1 -0.0004 1 1 0.0083 -0.0012 0.022 -0.002 0.00027
+1 -0.0002 1 1 0.0060 0.0010 0.020 0.029 -0.00017
+1 0.0002 1 1 -0.0063 0.0009 0.020 0.024 -0.00014
+1 -0.0003 1 1 0.0077 0.0007 0.013 0.010 0.00011
+1 0.0003 1 1 -0.0061 -0.0012 0.014 0.023 -0.00017
+1 -0.0002 1 1 0.0040 0.0032 0.011 0.002 0.00022
+1 -0.0003 1 1 0.0050 0.0000 0.016 0.021 -0.00004
+1 0.0003 1 1 -0.0037 0.0015 0.018 0.025 -0.00019
+1 0.0003 1 1 -0.0038 0.0036 0.012 0.007 -0.00018
+1 0.0001 1 1 -0.0026 0.0000 0.017 -0.013 0.00008
+1 -0.0002 1 1 0.0042 0.0013 0.014 -0.007 0.00006
+1 0.0002 1 1 -0.0042 0.0022 0.013 -0.010 -0.00002
+1 -0.0003 1 1 0.0086 0.0015 0.012 0.015 0.00004
+1 0.0002 1 1 -0.0104 0.0007 0.017 0.012 -0.00018
+1 -0.0001 1 1 0.0052 0.0025 0.013 0.014 0.00001
+1 -0.0001 1 1 0.0040 0.0031 0.016 0.024 -0.00008
+1 0.0002 1 1 -0.0062 0.0007 0.014 0.019 -0.00019
+1 -0.0004 1 1 0.0056 0.0013 0.010 -0.007 0.00021
+1 0.0002 1 1 -0.0044 0.0012 0.009 0.008 -0.00011
+1 0.0004 1 1 -0.0108 0.0014 0.005 -0.013 -0.00017
+1 0.0001 1 1 -0.0053 0.0017 0.004 -0.039 0.00029
+1 -0.0004 1 1 0.0092 0.0039 0.012 -0.019 0.00011
+1 0.0001 1 1 -0.0047 0.0041 0.022 -0.002 -0.00056
+1 0.0006 1 1 -0.0109 0.0002 0.022 -0.015 -0.00024
+1 0.0001 1 1 -0.0060 -0.0003 0.018 -0.038 0.00047
+1 -0.0001 1 1 0.0078 -0.0004 0.010 -0.035 0.00049
+1 -0.0006 1 1 0.0132 0.0011 0.008 -0.021 0.00032
+1 0.0001 1 1 0.0087 0.0034 0.013 0.018 -0.00036
+1 0.0003 1 1 -0.0062 0.0006 0.008 0.022 -0.00025
+1 -0.0002 1 1 0.0051 0.0002 0.007 0.003 0.00015
+1 -0.0002 1 1 0.0051 0.0026 0.008 0.010 -0.00008
+1 0.0001 1 1 -0.0040 0.0018 0.009 0.013 -0.00018
+1 0.0002 1 1 -0.0057 0.0018 0.009 0.005 -0.00007
+1 -0.0004 1 1 0.0086 0.0025 0.005 0.012 0.00014
+1 -0.0001 1 1 0.0052 0.0037 0.009 0.025 -0.00031
+1 0.0004 1 1 -0.0143 0.0009 0.017 0.003 -0.00031
+1 0.0004 1 1 -0.0014 0.0037 0.032 -0.010 0.00022
+1 -0.0007 1 1 0.0063 0.0017 0.029 -0.006 0.00039
+1 -0.0004 1 1 0.0021 0.0036 0.016 0.010 0.00007
+1 0.0001 1 1 -0.0044 0.0048 0.020 0.006 -0.00018
+1 0.0004 1 1 -0.0059 0.0031 0.021 -0.001 -0.00006
+1 0.0002 1 1 -0.0035 0.0046 0.022 -0.010 0.00026
+1 0.0001 1 1 0.0036 0.0049 0.024 -0.011 0.00033
+1 -0.0001 1 1 0.0082 0.0019 0.022 -0.002 0.00016
+1 -0.0003 1 1 0.0038 0.0027 0.018 0.028 -0.00013
+1 0.0007 1 1 -0.0052 0.0035 0.020 0.026 -0.00023
+1 0.0008 1 1 -0.0066 0.0063 0.019 -0.012 -0.00013
+1 -0.0004 1 1 0.0057 0.0038 0.019 -0.019 0.00030
+1 -0.0003 1 1 0.0066 0.0025 0.018 0.027 -0.00006
+1 0.0006 1 1 -0.0085 0.0021 0.017 0.023 -0.00026
+1 -0.0001 1 1 0.0028 0.0042 0.017 -0.004 0.00028
+1 -0.0001 1 1 0.0062 0.0025 0.016 0.014 0.00001
+1 -0.0002 1 1 -0.0002 0.0021 0.012 0.029 -0.00015
+1 0.0005 1 1 -0.0049 0.0025 0.011 0.025 -0.00027
+1 -0.0002 1 1 0.0011 0.0031 0.014 0.009 0.00001
+1 -0.0001 1 1 0.0038 0.0014 0.008 0.007 0.00014
+1 0.0002 1 1 -0.0044 0.0024 0.014 0.003 -0.00004
+1 0.0004 1 1 -0.0034 0.0045 0.017 -0.010 -0.00006
+1 -0.0003 1 1 0.0079 0.0030 0.017 -0.003 0.00022
+1 0.0005 1 1 -0.0084 0.0022 0.009 0.006 -0.00015
+1 0.0001 1 1 -0.0043 0.0029 0.008 -0.013 0.00024
+1 -0.0004 1 1 0.0065 0.0038 0.010 -0.009 0.00028
+1 -0.0002 1 1 0.0051 0.0054 0.016 0.011 -0.00015
+1 0.0002 1 1 -0.0035 0.0019 0.014 0.014 -0.00023
+1 0.0002 1 1 -0.0007 0.0037 0.013 -0.009 0.00001
+1 -0.0005 1 1 0.0032 0.0024 0.012 -0.007 0.00014
+1 0.0006 1 1 -0.0081 0.0025 0.012 -0.019 -0.00015
+1 0.0001 1 1 -0.0033 0.0017 0.009 -0.032 0.00045
+1 -0.0005 1 1 0.0092 0.0013 0.004 -0.025 0.00047
+1 -0.0003 1 1 0.0102 0.0053 0.009 0.018 -0.00013
+1 0.0004 1 1 -0.0076 0.0034 0.021 0.023 -0.00024
+1 -0.0002 1 1 0.0050 0.0004 0.004 0.012 0.00000
+1 -0.0001 1 1 -0.0041 0.0048 0.008 0.014 -0.00010
+1 0.0005 1 1 -0.0085 0.0043 0.014 -0.010 -0.00007
+1 -0.0003 1 1 0.0056 0.0034 0.013 -0.022 0.00034
+1 0.0004 1 1 -0.0043 0.0016 0.013 0.004 -0.00020
+1 -0.0005 1 1 0.0094 0.0009 0.006 0.010 0.00039
+1 -0.0003 1 1 0.0091 0.0034 0.008 0.028 -0.00015
+1 0.0003 1 1 -0.0040 0.0026 0.014 0.036 -0.00008
+1 -0.0003 1 1 -0.0012 0.0006 0.011 0.028 0.00016
+1 0.0001 1 1 -0.0048 0.0025 0.010 0.018 -0.00010
+1 -0.0001 1 1 0.0027 0.0033 0.001 -0.004 0.00007
+1 -0.0003 1 1 0.0022 0.0029 0.015 0.010 0.00003
+1 0.0002 1 1 -0.0057 0.0034 0.019 0.004 -0.00015
+1 0.0001 1 1 0.0045 0.0014 0.013 -0.011 0.00031
+1 -0.0002 1 1 0.0055 0.0011 0.007 0.013 -0.00013
+1 0.0001 1 1 -0.0066 0.0032 0.006 0.004 -0.00007
+1 -0.0003 1 1 0.0061 0.0025 0.014 -0.015 0.00036
+1 -0.0001 1 1 0.0080 0.0030 0.014 -0.003 0.00002
+1 -0.0003 1 1 0.0062 0.0005 0.013 0.013 -0.00006
+1 0.0001 1 1 -0.0055 0.0048 0.016 -0.002 -0.00018
+1 0.0004 1 1 -0.0066 0.0021 0.017 -0.011 -0.00003
+1 -0.0003 1 1 0.0082 0.0007 0.012 -0.014 0.00043
+1 -0.0002 1 1 0.0095 0.0005 0.006 0.013 -0.00017
+1 -0.0004 1 1 0.0020 0.0010 0.002 0.027 -0.00034
+1 0.0002 1 1 -0.0073 0.0031 0.002 0.023 -0.00061
+1 0.0003 1 1 -0.0093 0.0047 0.007 0.005 -0.00001
+1 -0.0002 1 1 0.0058 0.0027 0.013 -0.007 0.00026
+1 -0.0001 1 1 0.0039 0.0021 0.012 0.014 -0.00014
+1 -0.0001 1 1 0.0054 0.0012 0.005 0.027 0.00004
+1 0.0001 1 1 -0.0058 0.0045 0.016 0.025 -0.00009
+1 0.0001 1 1 -0.0036 0.0020 0.005 0.001 -0.00016
+1 0.0002 1 1 -0.0055 0.0030 0.005 -0.012 -0.00004
+1 -0.0002 1 1 0.0056 0.0025 0.013 -0.006 0.00013
+1 -0.0002 1 1 0.0020 0.0029 0.015 0.009 -0.00014
+1 0.0006 1 1 -0.0036 0.0020 0.014 0.008 -0.00026
+1 -0.0001 1 1 0.0048 0.0004 0.004 0.009 0.00004
+1 -0.0001 1 1 0.0040 0.0021 0.003 0.016 -0.00034
+1 0.0001 1 1 -0.0090 0.0043 0.006 0.005 -0.00026
+1 0.0001 1 1 -0.0055 0.0043 0.011 -0.035 0.00040
+1 -0.0001 1 1 0.0053 0.0042 0.012 -0.036 0.00047
+1 -0.0001 1 1 0.0108 0.0034 0.012 -0.024 0.00034
+1 -0.0004 1 1 0.0048 0.0005 0.013 0.011 -0.00004
+1 -0.0003 1 1 0.0062 0.0020 -0.001 0.018 0.00020
+1 -0.0002 1 1 0.0056 0.0021 -0.001 0.029 -0.00014
+1 0.0002 1 1 -0.0039 0.0039 0.004 0.033 -0.00029
+1 0.0004 1 1 -0.0063 0.0014 0.009 -0.011 -0.00017
+1 -0.0002 1 1 0.0052 0.0047 0.014 -0.007 0.00003
+1 0.0003 1 1 -0.0058 0.0012 0.009 -0.012 -0.00008
+1 -0.0005 1 1 0.0060 0.0065 0.004 -0.001 0.00000
+1 0.0005 1 1 -0.0076 0.0056 0.013 0.000 -0.00047
+1 -0.0007 1 1 0.0085 0.0022 0.009 -0.024 0.00043
+1 -0.0008 1 1 0.0075 0.0030 0.002 0.012 0.00013
+1 0.0001 1 1 -0.0090 0.0050 0.011 0.006 -0.00001
+1 -0.0002 1 1 0.0050 -0.0009 0.015 -0.017 0.00046
+1 -0.0001 1 1 0.0069 0.0021 0.015 0.011 0.00007
+1 0.0002 1 1 -0.0044 0.0000 0.014 0.023 -0.00002
+1 -0.0001 1 1 0.0004 0.0000 0.011 0.011 0.00011
+1 -0.0002 1 1 0.0037 0.0001 0.007 0.013 0.00000
+1 0.0001 1 1 -0.0076 0.0009 0.010 -0.005 -0.00008
+1 -0.0001 1 1 0.0054 0.0008 0.011 -0.024 0.00014
+1 0.0002 1 1 -0.0066 0.0008 0.007 -0.017 -0.00005
+1 -0.0001 1 1 0.0082 0.0010 0.017 -0.016 0.00009
+1 0.0001 1 1 -0.0079 0.0011 -0.001 0.002 -0.00012
+1 0.0001 1 1 -0.0050 0.0034 0.007 -0.034 0.00016
+1 0.0001 1 1 0.0051 0.0033 0.022 -0.032 0.00015
+1 -0.0001 1 1 0.0093 -0.0018 0.016 -0.004 0.00005
+1 -0.0002 1 1 0.0084 -0.0017 0.012 0.014 -0.00009
+1 0.0002 1 1 -0.0076 0.0012 0.004 0.017 -0.00018
+1 -0.0001 1 1 0.0093 0.0013 0.007 0.002 0.00015
+1 -0.0002 1 1 0.0094 0.0023 0.009 0.017 -0.00009
+1 0.0001 1 1 -0.0077 0.0008 0.017 0.023 -0.00025
+1 0.0003 1 1 -0.0092 0.0001 0.017 0.009 -0.00003
+1 -0.0001 1 1 0.0062 -0.0005 0.003 -0.005 0.00021
+1 -0.0001 1 1 0.0077 -0.0001 0.002 0.010 0.00000
+1 -0.0002 1 1 0.0070 0.0022 0.004 0.021 -0.00005
+1 0.0001 1 1 -0.0033 0.0017 0.011 0.032 -0.00033
+1 0.0002 1 1 -0.0082 0.0013 0.016 -0.002 -0.00001
+1 -0.0001 1 1 0.0035 -0.0012 0.009 -0.021 0.00025
+1 -0.0002 1 1 0.0075 0.0009 0.010 -0.004 0.00008
+1 0.0001 1 1 -0.0071 -0.0014 0.013 -0.002 -0.00005
+1 0.0001 1 1 -0.0059 -0.0016 0.010 -0.013 0.00012
+1 -0.0002 1 1 0.0070 0.0010 0.006 -0.003 0.00008
+1 0.0001 1 1 -0.0036 0.0016 0.013 0.012 -0.00020
+1 0.0002 1 1 -0.0058 0.0007 0.013 0.003 -0.00009
+1 -0.0003 1 1 0.0076 -0.0012 0.004 0.001 0.00015
+1 -0.0001 1 1 0.0066 -0.0009 0.003 0.015 -0.00019
+1 0.0002 1 1 -0.0094 0.0019 0.009 0.007 -0.00026
+1 0.0001 1 1 -0.0046 0.0003 0.011 -0.030 0.00024
+1 -0.0001 1 1 0.0069 0.0017 0.011 -0.024 0.00022
+1 -0.0001 1 1 0.0086 0.0022 0.013 -0.013 0.00006
+1 -0.0001 1 1 0.0058 -0.0005 0.012 0.015 -0.00018
+1 0.0001 1 1 -0.0079 0.0010 0.007 0.004 -0.00013
+1 0.0002 1 1 -0.0082 0.0012 0.009 -0.012 0.00007
+1 -0.0001 1 1 0.0061 0.0008 0.011 -0.020 0.00025
+1 -0.0001 1 1 0.0087 0.0011 0.012 -0.001 0.00002
+1 -0.0001 1 1 0.0080 0.0011 0.014 0.014 -0.00007
+1 0.0001 1 1 -0.0042 -0.0006 0.008 0.029 -0.00013
+1 -0.0001 1 1 0.0008 0.0012 0.004 0.011 -0.00006
+1 0.0002 1 1 -0.0045 0.0017 0.009 0.004 -0.00011
+1 -0.0001 1 1 0.0053 -0.0001 0.010 0.002 0.00015
+1 -0.0002 1 1 0.0071 0.0000 0.009 0.014 0.00007
+1 -0.0001 1 1 0.0036 0.0005 0.010 0.028 -0.00017
+1 0.0002 1 1 -0.0070 0.0009 0.012 0.022 -0.00026
+1 -0.0002 1 1 0.0069 -0.0007 0.017 0.011 0.00004
+1 0.0002 1 1 -0.0043 -0.0006 0.003 0.023 -0.00011
+1 -0.0002 1 1 0.0052 0.0020 0.012 0.017 0.00010
+1 0.0002 1 1 -0.0088 -0.0002 0.013 0.009 -0.00013
+1 -0.0003 1 1 0.0123 -0.0027 0.007 0.009 0.00012
+1 -0.0001 1 1 0.0084 0.0023 0.003 0.036 -0.00028
+1 0.0002 1 1 -0.0091 0.0014 0.012 0.030 -0.00011
+1 0.0003 1 1 -0.0057 0.0009 0.008 0.000 -0.00014
+1 -0.0001 1 1 0.0066 0.0001 0.012 -0.004 0.00013
+1 -0.0001 1 1 0.0039 0.0005 0.013 0.021 -0.00010
+1 -0.0002 1 1 0.0037 0.0004 0.002 -0.006 0.00012
+1 0.0001 1 1 -0.0042 0.0020 0.009 -0.002 -0.00010
+1 0.0001 1 1 -0.0022 0.0016 0.013 -0.015 0.00008
+1 -0.0001 1 1 0.0065 -0.0007 0.011 0.000 0.00009
+1 -0.0001 1 1 0.0065 -0.0005 0.010 0.011 -0.00003
+1 -0.0001 1 1 0.0016 0.0004 0.009 0.011 0.00003
+1 0.0002 1 1 -0.0033 0.0000 0.010 0.003 -0.00005
+1 -0.0001 1 1 0.0042 0.0004 0.011 0.011 0.00002
+1 0.0001 1 1 -0.0054 -0.0002 0.006 0.002 -0.00003
+1 0.0001 1 1 -0.0041 0.0007 0.007 -0.010 0.00008
+1 -0.0001 1 1 0.0053 0.0003 0.009 -0.007 0.00015
+1 0.0001 1 1 0.0031 0.0018 0.014 0.010 -0.00012
+1 -0.0002 1 1 0.0040 0.0005 0.008 0.019 -0.00001
+1 0.0001 1 1 -0.0054 0.0036 0.022 -0.043 0.00031
+1 -0.0003 1 1 0.0086 -0.0014 0.022 -0.036 0.00027
+1 0.0001 1 1 -0.0077 0.0016 0.017 0.008 -0.00017
+1 0.0002 1 1 -0.0094 -0.0028 0.013 -0.005 -0.00010
+1 -0.0002 1 1 0.0070 0.0004 0.009 -0.020 0.00009
+1 -0.0001 1 1 0.0010 0.0022 0.019 0.010 -0.00012
+1 0.0004 1 1 -0.0034 -0.0003 0.017 0.007 -0.00017
+1 0.0001 1 1 0.0035 -0.0022 0.014 0.008 0.00001
+1 0.0002 1 1 -0.0053 -0.0002 0.013 0.007 -0.00008
+1 -0.0001 1 1 0.0034 -0.0005 0.015 -0.006 0.00012
+1 -0.0001 1 1 0.0009 0.0008 0.012 0.010 -0.00009
+1 0.0003 1 1 -0.0033 0.0011 0.013 0.007 -0.00017
+1 -0.0001 1 1 0.0039 0.0002 0.011 0.021 -0.00006
+1 -0.0001 1 1 0.0002 0.0005 0.012 0.028 -0.00012
+1 0.0002 1 1 -0.0061 0.0000 0.010 0.017 -0.00014
+1 -0.0002 1 1 0.0056 0.0010 0.011 -0.003 0.00011
+1 -0.0001 1 1 0.0029 0.0010 0.012 0.010 -0.00029
+1 0.0005 1 1 -0.0067 -0.0006 0.010 0.005 -0.00033
+1 -0.0004 1 1 0.0067 0.0014 0.010 -0.005 0.00018
+1 -0.0001 1 1 0.0049 0.0022 0.013 0.010 -0.00021
+1 0.0004 1 1 -0.0068 -0.0003 0.011 0.005 -0.00022
+1 -0.0001 1 1 0.0078 -0.0001 0.006 0.002 0.00015
+1 -0.0001 1 1 0.0083 -0.0004 0.006 0.014 -0.00010
+1 0.0001 1 1 -0.0041 0.0019 0.011 0.023 -0.00033
+1 0.0002 1 1 -0.0098 0.0012 0.013 0.003 -0.00016
+1 0.0001 1 1 -0.0089 0.0005 0.013 -0.010 0.00022
+1 -0.0002 1 1 0.0109 0.0013 0.014 0.000 0.00018
+1 -0.0001 1 1 0.0091 -0.0017 0.016 0.021 -0.00032
+1 0.0001 1 1 -0.0056 -0.0011 0.010 0.029 -0.00044
+1 -0.0001 1 1 0.0043 0.0008 0.011 -0.025 0.00029
+1 -0.0002 1 1 0.0079 -0.0009 0.008 -0.009 0.00007
+1 -0.0001 1 1 0.0039 -0.0003 0.007 0.013 -0.00021
+1 0.0003 1 1 -0.0051 0.0029 0.014 0.009 -0.00018
+1 -0.0001 1 1 0.0045 -0.0009 0.007 -0.001 0.00021
+1 -0.0002 1 1 0.0058 0.0003 0.005 0.018 -0.00001
+1 -0.0001 1 1 0.0029 0.0006 0.008 0.028 -0.00022
+1 0.0001 1 1 -0.0054 0.0014 0.011 0.024 -0.00028
+1 0.0001 1 1 0.0066 -0.0001 0.012 -0.012 0.00012
+1 -0.0002 1 1 0.0085 0.0000 0.010 0.016 -0.00003
+1 0.0001 1 1 -0.0053 -0.0003 0.007 0.028 -0.00023
+1 -0.0001 1 1 0.0051 -0.0001 0.010 0.004 0.00018
+1 -0.0001 1 1 0.0060 0.0007 0.010 0.017 -0.00010
+1 -0.0001 1 1 0.0018 -0.0003 0.008 0.028 -0.00016
+1 0.0003 1 1 -0.0039 -0.0010 0.005 0.026 -0.00022
+1 -0.0003 1 1 0.0041 0.0000 0.013 0.011 0.00019
+1 0.0002 1 1 -0.0061 -0.0009 0.008 0.011 -0.00016
+1 0.0001 1 1 -0.0041 0.0016 0.009 -0.012 0.00013
+1 -0.0001 1 1 0.0083 0.0011 0.013 0.000 0.00016
+1 -0.0001 1 1 0.0075 0.0019 0.014 0.016 -0.00033
+1 0.0001 1 1 -0.0071 -0.0015 0.007 0.015 -0.00028
+1 -0.0002 1 1 0.0076 0.0012 0.009 -0.006 0.00019
+1 -0.0002 1 1 0.0056 -0.0010 0.008 0.021 -0.00015
+1 0.0003 1 1 -0.0077 0.0013 0.008 0.018 -0.00032
+1 0.0006 1 1 -0.0008 0.0048 0.037 -0.009 -0.00001
+1 0.0002 1 1 0.0037 0.0028 0.037 -0.008 0.00018
+1 -0.0005 1 1 0.0062 -0.0008 0.035 -0.001 0.00013
+1 -0.0001 1 1 -0.0035 0.0042 0.019 -0.016 -0.00004
+1 0.0001 1 1 -0.0040 0.0051 0.021 -0.022 -0.00003
+1 0.0003 1 1 -0.0002 0.0051 0.027 -0.030 0.00011
+1 0.0001 1 1 0.0034 0.0052 0.031 -0.028 0.00022
+1 -0.0004 1 1 0.0041 -0.0012 0.024 0.012 -0.00008
+1 0.0001 1 1 -0.0038 0.0024 0.020 0.007 -0.00006
+1 -0.0001 1 1 -0.0017 -0.0001 0.021 -0.009 0.00007
+1 -0.0005 1 1 0.0051 0.0055 0.019 -0.005 0.00018
+1 0.0005 1 1 -0.0086 -0.0009 0.023 -0.001 -0.00013
+1 -0.0003 1 1 0.0035 0.0025 0.020 -0.024 0.00021
+1 0.0001 1 1 0.0049 0.0030 0.021 -0.013 0.00000
+1 0.0003 1 1 -0.0027 0.0028 0.015 -0.011 0.00005
+1 -0.0001 1 1 0.0052 0.0009 0.010 -0.008 0.00020
+1 -0.0006 1 1 0.0067 0.0105 0.017 0.001 0.00005
+1 0.0001 1 1 0.0014 0.0084 0.027 0.009 -0.00043
+1 0.0010 1 1 -0.0075 0.0012 0.028 -0.002 -0.00022
+1 -0.0010 1 1 0.0090 0.0006 0.021 -0.008 0.00036
+1 0.0005 1 1 0.0046 0.0020 0.021 0.016 -0.00032
+1 0.0004 1 1 -0.0053 -0.0008 0.012 0.020 -0.00021
+1 0.0001 1 1 -0.0015 0.0035 0.017 -0.010 0.00005
+1 -0.0005 1 1 0.0064 0.0001 0.016 -0.002 0.00020
+1 0.0002 1 1 -0.0051 0.0017 0.014 0.010 -0.00013
+1 0.0001 1 1 -0.0031 0.0020 0.014 -0.012 0.00010
+1 -0.0002 1 1 0.0057 0.0022 0.015 -0.005 0.00013
+1 -0.0001 1 1 0.0039 0.0017 0.015 0.012 -0.00009
+1 0.0005 1 1 -0.0060 0.0003 0.013 0.010 -0.00029
+1 0.0001 1 1 -0.0039 0.0011 0.010 -0.010 0.00014
+1 -0.0004 1 1 0.0051 0.0024 0.012 -0.009 0.00017
+1 -0.0001 1 1 0.0045 0.0017 0.016 0.007 0.00022
+1 -0.0004 1 1 0.0066 -0.0016 0.014 0.015 0.00010
+1 0.0004 1 1 -0.0056 0.0028 0.014 0.021 -0.00025
+1 -0.0001 1 1 0.0003 0.0031 0.015 0.009 -0.00007
+1 0.0004 1 1 -0.0085 0.0018 0.017 0.000 -0.00032
+1 -0.0001 1 1 0.0044 0.0012 0.013 -0.006 0.00003
+1 -0.0003 1 1 0.0057 0.0002 0.010 0.012 0.00013
+1 0.0004 1 1 -0.0085 -0.0002 0.008 0.004 -0.00019
+1 -0.0001 1 1 0.0082 0.0012 0.014 -0.023 0.00031
+1 -0.0001 1 1 0.0094 -0.0020 0.004 0.015 -0.00007
+1 0.0001 1 1 -0.0044 0.0034 0.013 0.030 -0.00031
+1 0.0001 1 1 -0.0072 -0.0020 0.013 0.022 -0.00002
+1 -0.0002 1 1 0.0005 0.0016 0.018 0.009 -0.00012
+1 0.0006 1 1 -0.0044 0.0018 0.018 0.006 -0.00029
+1 -0.0002 1 1 0.0054 -0.0019 0.012 0.000 0.00027
+1 -0.0001 1 1 0.0077 -0.0015 0.006 0.015 0.00004
+1 -0.0001 1 1 0.0050 0.0009 0.001 0.034 -0.00015
+1 -0.0001 1 1 0.0027 0.0017 0.002 0.039 -0.00017
+1 0.0001 1 1 -0.0099 0.0033 0.012 0.020 -0.00019
+1 0.0003 1 1 -0.0112 0.0026 0.013 0.003 -0.00003
+1 -0.0003 1 1 0.0110 0.0019 0.010 0.005 0.00011
+1 -0.0001 1 1 0.0094 0.0023 0.011 0.022 -0.00018
+1 -0.0004 1 1 0.0035 0.0029 0.014 0.033 -0.00047
+1 0.0014 1 1 -0.0158 0.0009 0.013 0.019 -0.00078
+1 -0.0005 1 1 0.0052 -0.0002 0.009 -0.033 0.00053
+1 -0.0002 1 1 0.0092 0.0016 0.009 -0.017 0.00002
+1 -0.0005 1 1 0.0081 -0.0016 0.011 -0.012 0.00036
+1 -0.0001 1 1 0.0037 -0.0011 0.002 -0.001 0.00020
+1 -0.0003 1 1 0.0072 0.0027 0.006 0.016 0.00008
+1 0.0002 1 1 -0.0038 -0.0024 0.009 0.023 -0.00006
+1 0.0001 1 1 -0.0045 0.0070 0.016 0.009 -0.00019
+1 0.0006 1 1 -0.0097 0.0016 0.019 -0.012 -0.00017
+1 -0.0001 1 1 0.0080 -0.0026 0.002 -0.023 0.00048
+1 -0.0010 1 1 0.0133 0.0026 0.003 -0.006 0.00024
+1 0.0001 1 1 -0.0053 -0.0016 0.001 -0.001 -0.00006
+1 -0.0001 1 1 0.0089 -0.0002 0.009 -0.026 0.00028
+1 -0.0003 1 1 0.0121 0.0024 0.010 -0.004 0.00009
+1 -0.0002 1 1 0.0087 0.0033 0.014 0.016 -0.00027
+1 -0.0001 1 1 0.0074 0.0025 0.009 -0.016 0.00020
+1 -0.0001 1 1 0.0068 0.0023 0.016 0.016 -0.00010
+1 0.0001 1 1 0.0045 0.0005 0.018 0.025 -0.00016
+1 -0.0001 1 1 0.0040 -0.0010 0.002 0.010 0.00007
+1 -0.0001 1 1 -0.0039 0.0032 0.017 0.012 -0.00005
+1 0.0001 1 1 -0.0059 -0.0014 0.022 0.001 -0.00003
+1 -0.0001 1 1 0.0063 0.0003 0.002 0.000 0.00003
+1 -0.0002 1 1 0.0046 0.0030 0.003 0.013 -0.00011
+1 0.0003 1 1 -0.0075 0.0017 0.010 0.004 -0.00016
+1 0.0001 1 1 -0.0069 0.0000 0.009 -0.011 0.00010
+1 -0.0002 1 1 0.0075 0.0040 0.014 -0.006 0.00013
+1 -0.0001 1 1 0.0058 -0.0008 0.023 0.010 -0.00011
+1 0.0002 1 1 -0.0039 -0.0008 0.007 0.007 -0.00002
+1 -0.0002 1 1 0.0045 0.0031 0.004 0.011 0.00005
+1 0.0003 1 1 -0.0052 -0.0002 0.021 0.002 -0.00002
+1 -0.0001 1 1 0.0045 -0.0025 0.004 -0.002 0.00016
+1 -0.0002 1 1 0.0081 -0.0005 0.001 0.022 0.00004
+1 -0.0001 1 1 0.0060 0.0000 0.000 0.033 -0.00019
+1 0.0001 1 1 -0.0087 0.0016 0.005 0.023 -0.00019
+1 -0.0001 1 1 0.0057 0.0015 0.010 -0.023 0.00026
+1 -0.0001 1 1 0.0089 0.0025 0.015 -0.003 0.00006
+1 0.0001 1 1 -0.0036 -0.0023 0.007 0.026 -0.00001
+1 -0.0002 1 1 0.0035 0.0043 0.007 0.028 0.00003
+1 0.0001 1 1 -0.0074 0.0013 0.022 0.008 -0.00005
+1 0.0001 1 1 -0.0051 -0.0027 0.013 -0.013 0.00017
+1 -0.0001 1 1 0.0081 0.0044 0.000 0.004 0.00007
+1 -0.0001 1 1 0.0069 0.0026 0.005 0.017 -0.00023
+1 0.0001 1 1 -0.0050 0.0029 0.017 0.020 -0.00024
+1 0.0001 1 1 -0.0081 0.0017 0.020 0.005 -0.00010
+1 -0.0002 1 1 0.0079 -0.0006 0.004 -0.003 0.00012
+1 -0.0003 1 1 0.0069 0.0008 0.005 0.014 -0.00010
+1 0.0001 1 1 -0.0099 0.0014 0.010 0.007 -0.00026
+1 -0.0002 1 1 0.0075 -0.0002 0.001 -0.040 0.00037
+1 -0.0003 1 1 0.0121 0.0073 0.003 -0.010 0.00004
+1 0.0001 1 1 -0.0040 0.0000 0.021 0.017 -0.00014
+1 -0.0001 1 1 0.0052 -0.0009 0.000 0.005 0.00011
+1 -0.0001 1 1 0.0065 0.0019 0.000 0.015 -0.00002
+1 -0.0001 1 1 0.0040 0.0017 0.005 0.032 -0.00011
+1 -0.0001 1 1 0.0008 0.0027 0.009 0.035 -0.00026
+1 0.0001 1 1 -0.0066 0.0032 0.017 0.027 -0.00025
+1 -0.0001 1 1 0.0056 0.0037 0.019 0.028 -0.00007
+1 0.0001 1 1 -0.0015 -0.0018 0.000 -0.010 0.00000
+1 -0.0001 1 1 0.0044 0.0014 -0.001 -0.002 0.00009
+1 -0.0001 1 1 0.0039 0.0037 0.008 0.010 -0.00005
+1 0.0001 1 1 -0.0043 0.0000 0.016 0.003 -0.00005
+1 0.0001 1 1 -0.0020 -0.0002 0.013 -0.011 0.00008
+1 -0.0002 1 1 0.0056 0.0023 0.005 0.000 0.00008
+1 0.0003 1 1 -0.0067 0.0010 0.014 0.006 -0.00028
+1 0.0001 1 1 -0.0070 -0.0011 0.011 -0.014 0.00008
+1 -0.0001 1 1 0.0043 0.0017 0.004 -0.023 0.00016
+1 0.0002 1 1 -0.0042 0.0012 0.008 -0.011 -0.00001
+1 -0.0002 1 1 0.0061 -0.0003 0.013 0.018 -0.00001
+1 -0.0002 1 1 0.0045 0.0016 0.013 -0.005 0.00014
+1 0.0002 1 1 -0.0050 -0.0006 0.005 -0.012 -0.00004
+1 -0.0002 1 1 0.0057 -0.0014 0.012 -0.007 0.00007
+1 0.0002 1 1 -0.0064 -0.0002 0.011 0.005 -0.00020
+1 0.0001 1 1 -0.0067 0.0001 0.010 -0.011 0.00006
+1 -0.0001 1 1 0.0062 0.0019 0.010 -0.005 0.00005
+1 -0.0001 1 1 0.0041 -0.0003 0.014 0.015 -0.00008
+1 0.0001 1 1 -0.0037 -0.0008 0.012 0.015 -0.00014
+1 0.0001 1 1 -0.0053 -0.0008 0.010 0.004 -0.00004
+1 -0.0001 1 1 0.0064 0.0018 0.012 0.028 -0.00006
+1 -0.0001 1 1 0.0050 0.0011 0.013 0.036 -0.00012
+1 -0.0001 1 1 -0.0061 -0.0009 0.011 0.030 -0.00012
+1 -0.0001 1 1 0.0061 0.0019 0.008 0.011 -0.00001
+1 -0.0001 1 1 0.0016 0.0001 0.011 0.029 -0.00011
+1 -0.0002 1 1 0.0014 0.0000 0.006 0.010 0.00004
+1 -0.0002 1 1 0.0047 -0.0002 0.009 0.012 0.00005
+1 0.0001 1 1 -0.0070 0.0004 0.013 0.002 -0.00008
+1 -0.0001 1 1 0.0083 -0.0003 0.009 -0.004 0.00016
+1 -0.0002 1 1 0.0089 0.0010 0.010 0.010 -0.00002
+1 0.0001 1 1 -0.0058 0.0008 0.000 0.022 -0.00016
+1 0.0001 1 1 -0.0069 0.0016 0.009 0.000 -0.00009
+1 -0.0001 1 1 0.0074 0.0020 0.016 -0.004 0.00008
+1 0.0001 1 1 0.0071 0.0008 0.019 0.011 -0.00005
+1 -0.0001 1 1 0.0068 0.0002 0.018 0.020 -0.00003
+1 -0.0001 1 1 0.0054 0.0002 0.018 0.029 -0.00013
+1 0.0002 1 1 -0.0063 -0.0023 0.006 0.023 -0.00013
+1 -0.0001 1 1 0.0042 0.0001 0.017 0.011 0.00002
+1 -0.0002 1 1 0.0043 0.0011 0.005 0.012 0.00001
+1 0.0001 1 1 -0.0038 0.0003 0.011 0.014 -0.00009
+1 0.0001 1 1 -0.0051 -0.0005 0.009 0.004 -0.00004
+1 -0.0002 1 1 0.0058 0.0010 0.010 0.013 0.00004
+1 0.0001 1 1 0.0040 0.0014 0.012 0.021 -0.00016
+1 -0.0001 1 1 0.0035 -0.0007 0.012 0.013 0.00002
+1 0.0001 1 1 -0.0036 0.0005 0.013 0.015 -0.00009
+1 0.0001 1 1 -0.0050 -0.0022 0.005 0.000 -0.00001
+1 -0.0001 1 1 0.0042 0.0024 0.004 -0.004 0.00010
+1 -0.0001 1 1 0.0038 0.0024 0.012 0.014 -0.00004
+1 0.0001 1 1 -0.0041 0.0006 0.010 0.002 -0.00005
+1 0.0001 1 1 -0.0036 -0.0010 0.002 -0.012 0.00010
+1 -0.0001 1 1 0.0049 0.0022 0.005 -0.003 0.00009
+1 -0.0001 1 1 0.0043 0.0017 0.012 0.014 -0.00004
+1 -0.0001 1 1 -0.0039 -0.0003 0.004 0.012 -0.00008
+1 0.0001 1 1 -0.0049 0.0005 0.005 0.006 -0.00006
+1 0.0001 1 1 -0.0031 0.0005 0.005 -0.010 0.00008
+1 -0.0001 1 1 0.0057 0.0013 0.009 0.001 0.00008
+1 -0.0002 1 1 0.0054 0.0004 0.010 0.013 -0.00004
+1 0.0001 1 1 -0.0043 0.0019 0.017 0.017 -0.00022
+1 0.0001 1 1 -0.0068 -0.0001 0.017 0.007 -0.00009
+1 0.0001 1 1 -0.0042 -0.0006 0.014 -0.012 0.00014
+1 -0.0001 1 1 0.0076 -0.0003 0.002 -0.002 0.00016
+1 -0.0001 1 1 0.0086 0.0013 0.004 0.015 0.00001
+1 -0.0001 1 1 0.0046 0.0015 0.008 0.035 -0.00016
+1 0.0001 1 1 -0.0015 0.0016 0.012 0.040 -0.00020
+1 -0.0001 1 1 0.0058 -0.0020 0.011 0.018 0.00004
+1 -0.0001 1 1 0.0001 -0.0003 0.008 0.032 -0.00016
+1 0.0001 1 1 -0.0056 0.0008 0.010 0.023 -0.00016
+1 -0.0001 1 1 0.0056 -0.0005 0.007 -0.006 0.00008
+1 0.0001 1 1 -0.0048 0.0009 0.010 0.006 -0.00011
+1 0.0001 1 1 -0.0030 -0.0001 0.009 -0.011 0.00009
+1 -0.0001 1 1 0.0045 0.0028 0.004 -0.004 0.00006
+1 -0.0001 1 1 0.0039 0.0016 0.009 0.016 -0.00004
+1 0.0001 1 1 -0.0048 -0.0011 0.009 0.005 -0.00004
+1 -0.0002 1 1 0.0070 0.0034 0.012 0.021 0.00003
+1 0.0001 1 1 -0.0055 -0.0022 0.021 0.027 -0.00015
+1 -0.0001 1 1 -0.0078 -0.0045 0.005 0.005 -0.00003
+1 0.0001 1 1 0.0031 0.0075 0.032 -0.005 0.00019
+1 -0.0003 1 1 0.0078 0.0038 0.030 0.012 0.00008
+1 -0.0002 1 1 0.0065 0.0034 0.031 0.029 -0.00010
+1 0.0001 1 1 -0.0072 0.0040 0.027 0.024 -0.00016
+1 0.0004 1 1 -0.0087 0.0046 0.027 0.003 -0.00002
+1 0.0003 1 1 -0.0052 0.0033 0.023 -0.014 0.00020
+1 -0.0005 1 1 0.0048 0.0045 0.024 -0.007 0.00009
+1 0.0005 1 1 -0.0038 0.0047 0.026 -0.003 -0.00017
+1 0.0002 1 1 -0.0022 0.0048 0.027 -0.013 0.00012
+1 -0.0002 1 1 0.0046 0.0026 0.022 -0.010 0.00020
+1 -0.0001 1 1 0.0058 0.0015 0.019 -0.003 0.00003
+1 0.0006 1 1 -0.0062 0.0040 0.012 0.005 -0.00013
+1 -0.0001 1 1 -0.0015 0.0051 0.014 -0.009 0.00020
+1 -0.0006 1 1 0.0048 0.0079 0.020 -0.006 0.00025
+1 0.0004 1 1 -0.0042 0.0052 0.010 -0.010 -0.00008
+1 0.0002 1 1 0.0036 0.0050 0.024 -0.004 0.00003
+1 -0.0006 1 1 0.0015 0.0007 0.014 0.010 -0.00004
+1 0.0007 1 1 -0.0054 0.0010 0.009 0.007 -0.00041
+1 0.0001 1 1 -0.0060 0.0030 0.005 -0.014 0.00010
+1 -0.0002 1 1 0.0070 0.0033 0.023 -0.002 0.00016
+1 0.0001 1 1 0.0065 0.0036 0.023 0.010 -0.00009
+1 -0.0003 1 1 0.0061 0.0005 0.019 0.019 -0.00001
+1 0.0001 1 1 -0.0071 0.0016 0.012 0.021 -0.00044
+1 0.0008 1 1 -0.0036 0.0032 0.007 -0.010 -0.00015
+1 -0.0004 1 1 0.0090 0.0040 0.004 -0.003 0.00029
+1 -0.0002 1 1 0.0090 0.0050 0.007 0.012 -0.00011
+1 0.0002 1 1 0.0052 0.0061 0.013 0.027 -0.00023
+1 0.0006 1 1 -0.0057 0.0024 0.022 0.040 -0.00034
+1 -0.0001 1 1 0.0047 0.0006 0.005 0.031 0.00008
+1 -0.0001 1 1 -0.0015 0.0022 0.004 0.034 -0.00037
+1 0.0004 1 1 -0.0096 0.0028 0.004 0.023 -0.00038
+1 -0.0002 1 1 0.0077 0.0070 0.021 -0.006 0.00010
+1 -0.0005 1 1 0.0054 0.0007 0.024 0.014 -0.00002
+1 0.0005 1 1 -0.0079 -0.0003 0.012 0.007 -0.00024
+1 -0.0007 1 1 0.0065 0.0073 0.007 -0.007 0.00024
+1 -0.0006 1 1 0.0040 0.0030 0.021 0.012 0.00009
+1 0.0003 1 1 -0.0042 0.0001 0.015 0.014 -0.00024
+1 0.0001 1 1 -0.0040 0.0046 0.013 -0.006 -0.00016
+1 -0.0001 1 1 0.0076 0.0039 0.009 -0.005 0.00023
+1 -0.0001 1 1 0.0057 0.0046 0.012 0.015 -0.00021
+1 0.0002 1 1 -0.0048 0.0023 0.010 -0.002 -0.00016
+1 0.0002 1 1 -0.0043 0.0022 0.008 -0.011 0.00011
+1 -0.0001 1 1 0.0053 0.0030 0.005 -0.009 0.00018
+1 0.0005 1 1 -0.0143 0.0034 0.012 -0.006 -0.00038
+1 0.0002 1 1 -0.0135 0.0030 0.009 -0.033 0.00031
+1 -0.0002 1 1 0.0101 0.0057 0.007 -0.038 0.00032
+1 0.0004 1 1 -0.0052 0.0029 0.018 -0.004 -0.00028
+1 0.0002 1 1 -0.0047 0.0027 0.017 -0.013 0.00016
+1 -0.0005 1 1 0.0077 0.0026 0.013 -0.007 0.00021
+1 -0.0001 1 1 0.0012 0.0033 0.013 0.011 -0.00029
+1 0.0008 1 1 -0.0069 0.0021 0.014 0.005 -0.00041
+1 0.0002 1 1 -0.0040 0.0027 0.012 -0.011 0.00035
+1 -0.0003 1 1 0.0075 0.0022 0.007 0.010 -0.00006
+1 0.0003 1 1 -0.0069 0.0038 0.008 0.006 -0.00035
+1 0.0003 1 1 -0.0077 0.0036 0.009 -0.012 0.00006
+1 -0.0003 1 1 0.0096 0.0043 0.014 -0.003 0.00014
+1 -0.0002 1 1 0.0078 0.0046 0.018 0.019 -0.00014
+1 0.0003 1 1 -0.0061 0.0008 0.017 0.023 -0.00037
+1 -0.0002 1 1 0.0038 0.0015 0.012 0.009 0.00017
+1 0.0002 1 1 -0.0076 0.0024 0.007 0.002 -0.00015
+1 0.0002 1 1 -0.0078 0.0038 0.008 -0.011 0.00004
+1 0.0001 1 1 -0.0046 0.0049 0.014 -0.005 -0.00019
+1 -0.0002 1 1 0.0044 0.0019 0.011 -0.012 0.00030
+1 0.0008 1 1 -0.0095 0.0033 0.009 0.005 -0.00056
+1 -0.0004 1 1 0.0053 0.0033 0.011 -0.027 0.00077
+1 -0.0004 1 1 0.0098 0.0036 0.014 0.012 -0.00006
+1 0.0001 1 1 -0.0069 0.0028 0.015 0.008 -0.00029
+1 0.0008 1 1 -0.0111 -0.0015 0.009 -0.012 -0.00012
+1 -0.0002 1 1 0.0047 -0.0002 -0.002 -0.028 0.00066
+1 -0.0004 1 1 0.0127 0.0061 0.002 -0.011 0.00028
+1 -0.0006 1 1 0.0104 0.0059 0.011 0.029 -0.00041
+1 0.0001 1 1 -0.0039 0.0037 0.015 0.013 -0.00034
+1 0.0005 1 1 -0.0089 0.0004 0.007 -0.011 -0.00008
+1 -0.0001 1 1 0.0068 0.0000 0.014 0.011 -0.00006
+1 0.0001 1 1 -0.0003 -0.0006 0.005 -0.009 0.00008
+1 0.0001 1 1 -0.0031 -0.0004 0.015 -0.014 -0.00001
+1 -0.0001 1 1 0.0071 -0.0005 0.005 0.011 0.00003
+1 -0.0001 1 1 0.0058 0.0001 0.005 0.025 -0.00011
+1 0.0001 1 1 -0.0077 0.0004 0.004 0.007 -0.00006
+1 0.0001 1 1 -0.0059 0.0011 0.006 -0.013 0.00011
+1 -0.0001 1 1 0.0071 0.0004 0.011 -0.003 0.00007
+1 0.0001 1 1 -0.0053 0.0030 0.011 0.018 -0.00008
+1 -0.0001 1 1 0.0041 -0.0037 0.009 0.010 0.00006
+1 -0.0001 1 1 -0.0050 0.0010 0.007 0.006 -0.00004
+1 0.0001 1 1 -0.0058 0.0011 0.009 -0.001 -0.00005
+1 0.0001 1 1 -0.0055 0.0010 0.010 -0.010 0.00005
+1 -0.0001 1 1 0.0062 0.0006 0.016 0.015 -0.00002
+1 0.0001 1 1 -0.0034 0.0008 0.007 -0.011 0.00009
+1 -0.0001 1 1 0.0047 -0.0011 0.010 -0.005 0.00007
+1 -0.0001 1 1 0.0040 -0.0001 0.009 0.010 -0.00005
+1 0.0001 1 1 -0.0054 0.0003 0.009 0.005 -0.00012
+1 -0.0001 1 1 0.0067 -0.0003 0.008 -0.001 0.00007
+1 -0.0001 1 1 0.0061 -0.0001 0.007 0.012 -0.00007
+1 0.0001 1 1 -0.0051 -0.0009 0.006 -0.010 0.00003
+1 -0.0001 1 1 0.0059 0.0008 0.001 -0.008 0.00015
+1 -0.0001 1 1 0.0081 0.0018 0.005 0.011 0.00004
+1 0.0001 1 1 -0.0050 -0.0007 0.015 0.025 -0.00005
+1 -0.0001 1 1 0.0034 0.0005 -0.001 0.011 0.00008
+1 0.0001 1 1 -0.0051 0.0003 0.014 0.007 -0.00004
+1 -0.0001 1 1 0.0055 0.0023 0.011 0.021 0.00000
+1 0.0002 1 1 -0.0054 -0.0017 0.008 0.021 -0.00011
+1 0.0001 1 1 -0.0030 0.0010 0.008 -0.010 0.00008
+1 -0.0001 1 1 0.0047 0.0008 0.011 -0.004 0.00009
+1 -0.0001 1 1 0.0041 -0.0014 0.012 0.010 -0.00005
+1 0.0002 1 1 -0.0041 0.0000 0.003 0.007 -0.00008
+1 -0.0001 1 1 0.0051 0.0009 0.007 0.012 0.00003
+1 -0.0001 1 1 0.0017 -0.0028 0.005 0.010 0.00001
+1 0.0001 1 1 -0.0062 0.0015 0.007 -0.004 -0.00004
+1 -0.0001 1 1 0.0035 0.0011 0.015 -0.028 0.00015
+1 -0.0002 1 1 0.0049 -0.0016 0.014 -0.023 0.00010
+1 0.0002 1 1 -0.0042 -0.0013 0.001 -0.013 -0.00001
+1 -0.0001 1 1 0.0032 0.0013 0.018 0.011 -0.00006
+1 0.0001 1 1 -0.0033 -0.0010 0.004 0.002 -0.00002
+1 0.0001 1 1 0.0004 0.0023 0.007 -0.009 0.00005
+1 0.0001 1 1 -0.0048 -0.0005 0.007 0.005 -0.00007
+1 0.0001 1 1 -0.0030 0.0003 0.008 -0.011 0.00009
+1 -0.0001 1 1 0.0038 0.0001 0.011 -0.007 0.00008
+1 0.0001 1 1 -0.0046 -0.0005 0.007 0.004 -0.00003
+1 0.0001 1 1 0.0026 0.0013 0.014 -0.008 0.00005
+1 -0.0001 1 1 0.0048 -0.0008 0.012 0.012 -0.00002
+1 0.0001 1 1 -0.0069 -0.0003 0.006 0.000 -0.00008
+1 -0.0001 1 1 0.0054 0.0005 0.007 0.021 -0.00010
+1 0.0001 1 1 -0.0043 0.0008 0.010 0.025 -0.00019
+1 -0.0001 1 1 0.0062 0.0003 0.006 0.015 -0.00001
+1 -0.0002 1 1 0.0026 0.0005 0.008 0.029 -0.00015
+1 0.0001 1 1 -0.0055 0.0019 0.014 0.025 -0.00024
+1 0.0001 1 1 -0.0077 0.0016 0.016 0.015 -0.00010
+1 0.0001 1 1 -0.0082 0.0009 0.016 0.004 -0.00001
+1 -0.0001 1 1 0.0050 -0.0011 0.007 -0.014 0.00018
+1 -0.0001 1 1 0.0072 -0.0004 0.005 0.000 0.00000
+1 -0.0002 1 1 0.0033 0.0017 0.009 0.029 -0.00016
+1 0.0001 1 1 -0.0013 0.0011 0.011 0.031 -0.00027
+1 0.0001 1 1 -0.0056 0.0008 0.012 0.024 -0.00018
+1 -0.0001 1 1 0.0044 0.0013 0.007 0.014 0.00000
+1 0.0002 1 1 -0.0048 -0.0013 0.010 0.004 -0.00002
+1 -0.0002 1 1 0.0060 0.0022 0.008 0.009 0.00009
+1 -0.0001 1 1 -0.0047 -0.0015 0.011 0.016 -0.00006
+1 0.0002 1 1 -0.0062 -0.0012 0.008 0.003 -0.00004
+1 -0.0001 1 1 0.0062 0.0003 0.002 -0.002 0.00011
+1 -0.0001 1 1 0.0059 0.0005 0.003 0.015 -0.00005
+1 0.0002 1 1 -0.0077 0.0010 0.009 0.005 -0.00010
+1 -0.0001 1 1 -0.0065 -0.0004 0.008 -0.010 0.00011
+1 -0.0001 1 1 0.0041 0.0010 0.007 -0.019 0.00020
+1 -0.0002 1 1 0.0083 -0.0005 0.017 0.028 -0.00004
+1 0.0003 1 1 -0.0044 -0.0001 0.017 0.042 -0.00029
+1 0.0001 1 1 -0.0054 -0.0005 0.011 0.006 -0.00003
+1 -0.0002 1 1 0.0043 -0.0004 0.011 0.015 0.00001
+1 0.0001 1 1 -0.0063 -0.0011 0.004 0.006 -0.00005
+1 -0.0001 1 1 0.0075 0.0024 0.003 0.008 0.00003
+1 0.0002 1 1 -0.0052 0.0002 0.011 0.022 -0.00022
+1 0.0001 1 1 -0.0052 0.0007 0.013 -0.011 0.00006
+1 -0.0001 1 1 0.0080 0.0013 0.004 0.007 0.00006
+1 -0.0001 1 1 0.0062 0.0035 0.002 0.025 0.00000
+1 0.0001 1 1 -0.0002 0.0030 0.012 0.038 -0.00022
+1 -0.0001 1 1 0.0068 0.0004 0.004 0.024 -0.00004
+1 0.0001 1 1 0.0003 0.0002 0.004 0.037 -0.00029
+1 0.0001 1 1 -0.0079 0.0011 0.008 0.021 -0.00015
+1 -0.0004 1 1 0.0047 0.0024 0.024 -0.007 0.00024
+1 -0.0001 1 1 0.0053 0.0003 0.025 0.013 -0.00006
+1 -0.0002 1 1 -0.0052 0.0005 0.017 0.012 -0.00011
+1 0.0001 1 1 -0.0086 0.0010 0.016 -0.002 -0.00016
+1 0.0007 1 1 -0.0102 -0.0012 0.018 -0.032 0.00001
+1 -0.0004 1 1 0.0131 0.0030 0.013 -0.018 0.00019
+1 0.0001 1 1 -0.0048 0.0050 0.030 0.027 -0.00032
+1 0.0004 1 1 -0.0084 -0.0010 0.026 0.015 -0.00015
+1 -0.0003 1 1 0.0010 -0.0008 0.020 0.009 -0.00001
+1 0.0005 1 1 -0.0084 -0.0010 0.024 -0.012 -0.00010
+1 0.0002 1 1 -0.0053 -0.0008 0.019 -0.029 0.00021
+1 0.0001 1 1 0.0048 0.0015 0.010 -0.022 0.00000
+1 0.0003 1 1 -0.0060 0.0019 0.012 -0.015 -0.00011
+1 -0.0003 1 1 0.0065 0.0031 0.018 -0.023 0.00015
+1 -0.0002 1 1 0.0045 0.0026 0.017 0.015 0.00001
+1 0.0002 1 1 -0.0043 0.0014 0.015 0.006 -0.00002
+1 -0.0004 1 1 0.0068 0.0004 0.008 0.014 0.00010
+1 0.0006 1 1 -0.0122 -0.0026 0.015 -0.002 -0.00016
+1 -0.0003 1 1 0.0091 0.0009 0.007 -0.023 0.00036
+1 -0.0007 1 1 0.0113 0.0022 0.009 -0.004 -0.00001
+1 -0.0008 1 1 0.0069 -0.0004 0.014 0.015 0.00026
+1 -0.0002 1 1 0.0017 -0.0007 0.012 0.027 -0.00039
+1 0.0005 1 1 -0.0080 0.0010 0.012 0.021 -0.00048
+1 0.0004 1 1 -0.0103 0.0015 0.014 -0.010 0.00005
+1 -0.0002 1 1 0.0059 0.0009 0.006 -0.023 0.00034
+1 -0.0001 1 1 0.0099 0.0014 0.006 -0.005 0.00011
+1 -0.0001 1 1 0.0092 0.0017 0.008 0.019 -0.00008
+1 0.0001 1 1 -0.0039 0.0022 0.015 0.035 -0.00024
+1 0.0003 1 1 -0.0065 0.0005 0.014 0.025 -0.00011
+1 -0.0004 1 1 0.0041 0.0019 0.008 0.010 0.00014
+1 0.0002 1 1 -0.0024 0.0019 0.022 -0.010 0.00001
+1 -0.0002 1 1 0.0060 -0.0043 0.015 -0.007 0.00030
+1 -0.0002 1 1 0.0065 -0.0034 0.003 0.011 -0.00011
+1 0.0003 1 1 -0.0085 0.0002 0.010 0.005 -0.00019
+1 0.0002 1 1 -0.0081 0.0002 0.008 -0.011 0.00012
+1 -0.0004 1 1 0.0087 0.0022 0.005 -0.007 0.00018
+1 0.0001 1 1 0.0045 0.0039 0.015 0.016 -0.00021
+1 -0.0001 1 1 -0.0054 -0.0009 0.008 0.008 -0.00008
+1 0.0003 1 1 -0.0030 -0.0026 0.005 -0.010 -0.00001
+1 -0.0004 1 1 0.0059 0.0019 0.004 -0.006 0.00020
+1 -0.0001 1 1 0.0017 0.0025 0.010 0.011 -0.00017
+1 0.0004 1 1 -0.0053 0.0029 0.015 0.006 -0.00026
+1 -0.0004 1 1 0.0037 0.0002 0.009 -0.007 0.00013
+1 0.0004 1 1 -0.0054 0.0007 0.013 -0.008 -0.00019
+1 -0.0004 1 1 0.0048 0.0002 0.007 -0.015 0.00025
+1 -0.0004 1 1 0.0039 -0.0005 0.003 0.010 0.00008
+1 0.0006 1 1 -0.0114 0.0047 0.013 -0.001 -0.00037
+1 0.0002 1 1 -0.0085 -0.0043 0.013 -0.030 0.00047
+1 -0.0001 1 1 0.0065 -0.0013 0.006 -0.034 0.00063
+1 -0.0003 1 1 0.0120 0.0026 0.011 0.010 -0.00007
+1 -0.0003 1 1 0.0062 -0.0046 0.014 0.030 -0.00022
+1 0.0003 1 1 0.0006 -0.0018 0.012 0.036 -0.00042
+1 0.0001 1 1 -0.0027 0.0018 0.009 -0.011 0.00010
+1 -0.0003 1 1 0.0049 0.0015 0.011 -0.007 0.00016
+1 0.0008 1 1 -0.0128 0.0008 0.012 -0.026 -0.00022
+1 -0.0002 1 1 0.0079 0.0054 0.001 -0.045 0.00051
+1 -0.0002 1 1 0.0145 0.0025 0.005 -0.014 0.00014
+1 -0.0002 1 1 0.0136 0.0031 0.008 0.015 -0.00023
+1 0.0002 1 1 -0.0079 0.0001 0.013 0.027 -0.00021
+1 0.0001 1 1 -0.0037 -0.0001 0.007 -0.012 0.00013
+1 -0.0002 1 1 0.0018 0.0024 0.003 0.010 -0.00003
+1 0.0003 1 1 -0.0036 0.0022 0.008 0.008 -0.00014
+1 0.0004 1 1 -0.0083 -0.0004 0.013 -0.015 -0.00013
+1 -0.0001 1 1 0.0062 -0.0019 0.005 -0.027 0.00045
+1 -0.0003 1 1 0.0115 -0.0003 0.003 -0.015 0.00032
+1 -0.0002 1 1 0.0080 0.0022 0.006 0.020 -0.00031
+1 0.0004 1 1 -0.0061 0.0025 0.012 0.023 -0.00039
+1 -0.0004 1 1 0.0042 -0.0016 0.010 0.011 0.00004
+1 0.0003 1 1 -0.0076 -0.0003 0.004 0.006 -0.00028
+1 0.0002 1 1 -0.0040 0.0040 0.007 -0.030 -0.00003
+1 -0.0002 1 1 0.0059 0.0037 0.017 -0.027 0.00026
+1 -0.0003 1 1 0.0050 0.0019 0.001 -0.006 0.00006
+1 0.0002 1 1 -0.0033 -0.0011 0.012 -0.001 -0.00024
+1 0.0002 1 1 -0.0046 0.0013 0.012 -0.010 0.00001
+1 -0.0002 1 1 0.0028 0.0006 0.009 -0.007 -0.00009
+1 0.0003 1 1 -0.0042 -0.0013 0.003 -0.010 -0.00016
+1 0.0001 1 1 0.0041 0.0013 0.017 -0.016 0.00009
+1 -0.0001 1 1 0.0065 0.0007 0.015 -0.005 0.00010
+1 -0.0003 1 1 0.0061 0.0002 0.014 0.012 -0.00005
+1 0.0003 1 1 -0.0040 0.0005 0.013 0.018 -0.00028
+1 -0.0003 1 1 0.0050 0.0032 0.004 -0.007 0.00020
+1 -0.0001 1 1 0.0041 0.0042 0.015 0.011 -0.00008
+1 0.0002 1 1 -0.0035 0.0002 0.014 0.006 -0.00004
+1 -0.0001 1 1 0.0014 0.0001 0.007 0.011 -0.00002
+1 0.0003 1 1 -0.0041 0.0014 0.008 0.006 -0.00012
+1 -0.0001 1 1 0.0043 0.0001 0.011 0.002 0.00014
+1 -0.0001 1 1 0.0037 0.0011 0.012 0.015 -0.00006
+1 0.0003 1 1 -0.0073 0.0006 0.009 0.006 -0.00015
+1 0.0001 1 1 -0.0040 0.0000 0.007 -0.012 0.00019
+1 -0.0007 1 1 0.0062 0.0014 0.006 -0.007 0.00020
+1 0.0001 1 1 -0.0037 0.0030 0.012 0.002 -0.00041
+1 0.0006 1 1 -0.0099 0.0009 0.012 -0.014 -0.00021
+1 0.0003 1 1 -0.0029 -0.0016 0.033 -0.013 0.00008
+1 -0.0001 1 1 0.0038 0.0013 0.026 -0.011 0.00009
+1 0.0002 1 1 -0.0047 0.0028 0.021 -0.007 -0.00017
+1 -0.0004 1 1 -0.0028 0.0006 0.025 -0.031 0.00010
+1 -0.0005 1 1 0.0084 0.0027 0.025 -0.023 0.00020
+1 -0.0004 1 1 0.0057 0.0019 0.027 0.012 -0.00011
+1 0.0007 1 1 -0.0038 -0.0014 0.023 0.016 -0.00029
+1 0.0002 1 1 -0.0026 0.0039 0.018 -0.011 -0.00003
+1 -0.0002 1 1 0.0041 0.0014 0.020 -0.007 0.00004
+1 0.0002 1 1 -0.0017 0.0031 0.023 -0.010 0.00000
+1 -0.0004 1 1 0.0051 0.0001 0.018 -0.003 0.00010
+1 -0.0002 1 1 0.0012 -0.0033 0.017 0.009 -0.00014
+1 0.0005 1 1 -0.0036 -0.0007 0.013 0.008 -0.00031
+1 -0.0004 1 1 0.0050 0.0001 0.015 -0.008 0.00018
+1 0.0004 1 1 -0.0074 0.0013 0.014 0.000 -0.00009
+1 -0.0004 1 1 0.0051 -0.0001 0.012 -0.017 0.00027
+1 -0.0002 1 1 0.0032 0.0020 0.013 0.011 -0.00010
+1 0.0004 1 1 -0.0043 0.0003 0.015 0.010 -0.00023
+1 -0.0005 1 1 0.0028 0.0010 0.013 -0.008 0.00012
+1 0.0006 1 1 -0.0056 0.0014 0.015 -0.011 -0.00027
+1 -0.0003 1 1 0.0071 0.0001 0.012 -0.004 0.00007
+1 0.0002 1 1 -0.0046 0.0002 0.009 0.005 -0.00008
+1 -0.0001 1 1 0.0009 0.0019 0.008 0.010 -0.00003
+1 0.0003 1 1 -0.0038 0.0020 0.011 0.005 -0.00013
+1 0.0001 1 1 -0.0003 0.0030 0.010 -0.009 0.00000
+1 0.0004 1 1 -0.0031 -0.0017 0.014 -0.010 -0.00007
+1 -0.0002 1 1 0.0038 -0.0011 0.006 -0.011 0.00024
+1 -0.0001 1 1 0.0044 0.0035 0.011 0.012 -0.00011
+1 0.0002 1 1 -0.0051 0.0020 0.010 0.005 -0.00010
+1 0.0001 1 1 -0.0017 0.0001 0.009 -0.009 0.00014
+1 -0.0004 1 1 0.0061 0.0013 0.007 0.000 0.00015
+1 -0.0001 1 1 0.0037 0.0032 0.011 0.011 -0.00025
+1 -0.0001 1 1 -0.0060 0.0009 0.010 0.009 -0.00039
+1 -0.0001 1 1 0.0086 0.0021 0.008 -0.019 0.00001
+1 0.0002 1 1 -0.0038 0.0015 0.006 -0.012 -0.00001
+1 0.0001 1 1 0.0044 0.0021 0.006 -0.010 0.00006
+1 0.0002 1 1 -0.0016 0.0004 0.012 -0.010 0.00005
+1 -0.0002 1 1 0.0038 -0.0009 0.006 -0.008 0.00020
+1 -0.0002 1 1 0.0037 0.0021 0.008 0.012 0.00005
+1 0.0001 1 1 -0.0046 0.0031 0.013 0.012 -0.00039
+1 0.0001 1 1 -0.0071 0.0004 0.012 -0.014 0.00010
+1 0.0001 1 1 0.0044 0.0012 0.012 -0.011 0.00013
+1 -0.0002 1 1 0.0039 0.0005 0.007 0.012 -0.00011
+1 0.0003 1 1 -0.0060 0.0018 0.010 0.008 -0.00020
+1 -0.0003 1 1 0.0043 0.0011 0.009 -0.012 0.00020
+1 0.0004 1 1 -0.0068 0.0021 0.015 -0.008 -0.00030
+1 -0.0001 1 1 0.0040 0.0000 0.005 -0.024 0.00030
+1 -0.0001 1 1 0.0067 0.0015 0.004 -0.011 0.00006
+1 0.0001 1 1 0.0043 0.0051 0.010 0.016 -0.00047
+1 0.0003 1 1 -0.0081 0.0005 0.011 0.010 -0.00040
+1 0.0001 1 1 -0.0109 0.0006 0.010 -0.010 -0.00002
+1 -0.0002 1 1 0.0061 0.0014 0.007 -0.030 0.00019
+1 -0.0003 1 1 0.0036 0.0014 0.007 0.012 0.00001
+1 0.0002 1 1 -0.0066 0.0029 0.015 0.007 -0.00020
+1 -0.0001 1 1 0.0061 0.0024 0.006 -0.019 0.00020
+1 -0.0001 1 1 0.0082 0.0023 0.008 -0.006 0.00008
+1 0.0003 1 1 -0.0048 0.0012 0.013 0.009 -0.00027
+1 0.0002 1 1 -0.0041 -0.0003 0.007 -0.013 0.00008
+1 -0.0002 1 1 0.0064 0.0022 0.011 -0.007 0.00016
+1 -0.0006 1 1 0.0041 -0.0005 0.009 0.011 0.00028
+1 0.0003 1 1 -0.0037 0.0010 0.009 0.016 -0.00030
+1 0.0002 1 1 -0.0065 0.0017 0.010 0.001 -0.00003
+1 0.0001 1 1 -0.0041 0.0015 0.010 -0.014 0.00013
+1 -0.0002 1 1 0.0065 0.0002 0.006 -0.010 0.00023
+1 -0.0003 1 1 0.0045 0.0034 0.008 0.012 -0.00021
+1 0.0003 1 1 -0.0074 -0.0024 0.012 0.009 -0.00039
+1 0.0002 1 1 -0.0030 0.0030 0.008 -0.012 -0.00008
+1 -0.0002 1 1 0.0045 0.0016 0.009 -0.006 0.00006
+1 -0.0003 1 1 0.0022 0.0027 0.008 0.010 0.00001
+1 0.0002 1 1 -0.0044 0.0016 0.013 0.005 -0.00012
+1 0.0004 1 1 -0.0030 -0.0011 0.012 -0.010 -0.00005
+1 -0.0003 1 1 0.0061 0.0028 0.004 -0.007 0.00027
+1 0.0001 1 1 0.0056 0.0016 0.005 0.013 -0.00007
+1 0.0002 1 1 0.0045 0.0014 0.007 0.026 -0.00005
+1 0.0002 1 1 0.0011 0.0027 0.009 0.037 -0.00058
+1 0.0003 1 1 -0.0054 0.0008 0.008 0.033 -0.00034
+1 -0.0002 1 1 0.0058 -0.0007 0.006 0.012 0.00012
+1 -0.0002 1 1 0.0026 0.0035 0.010 0.030 -0.00014
+1 0.0003 1 1 -0.0055 -0.0005 0.015 0.025 -0.00017
+1 0.0003 1 1 -0.0085 0.0021 0.009 -0.003 -0.00008
+1 -0.0002 1 1 0.0070 0.0011 0.008 -0.013 0.00033
+1 0.0004 1 1 0.0035 -0.0019 0.011 0.025 -0.00020
+1 -0.0003 1 1 0.0048 -0.0012 0.007 0.031 0.00021
+1 -0.0001 1 1 0.0000 0.0031 0.010 0.042 -0.00016
+1 0.0002 1 1 -0.0089 0.0010 0.015 0.022 -0.00014
+1 -0.0005 1 1 0.0035 -0.0005 0.004 -0.008 0.00020
+1 -0.0001 1 1 0.0040 -0.0004 0.011 0.002 0.00006
+1 -0.0001 1 1 -0.0036 0.0018 0.013 0.007 -0.00001
+1 0.0004 1 1 -0.0045 -0.0006 0.012 0.002 -0.00010
+1 -0.0001 1 1 0.0044 -0.0007 0.005 -0.002 0.00028
+1 -0.0001 1 1 0.0078 0.0016 0.006 0.013 0.00003
+1 -0.0001 1 1 0.0036 0.0027 0.012 0.035 -0.00014
+1 0.0002 1 1 -0.0015 -0.0010 0.008 0.037 -0.00021
+1 -0.0002 1 1 -0.0015 0.0013 0.006 0.028 0.00003
+1 0.0002 1 1 -0.0055 0.0020 0.009 0.016 -0.00009
+1 -0.0002 1 1 0.0026 0.0023 0.010 0.011 0.00000
+1 0.0001 1 1 -0.0039 -0.0006 0.012 0.002 -0.00003
+1 -0.0002 1 1 0.0045 0.0009 0.007 0.011 0.00001
+1 0.0002 1 1 -0.0052 0.0010 0.013 0.003 -0.00004
+1 -0.0002 1 1 0.0076 0.0024 0.003 0.013 0.00009
+1 -0.0001 1 1 0.0062 0.0018 0.005 0.028 -0.00013
+1 0.0002 1 1 -0.0072 0.0012 0.010 0.023 -0.00016
+1 -0.0002 1 1 0.0058 0.0003 0.008 -0.011 0.00029
+1 -0.0002 1 1 0.0073 0.0018 0.010 0.015 -0.00003
+1 0.0006 1 1 -0.0065 -0.0013 0.014 0.021 -0.00034
+1 -0.0002 1 1 0.0028 0.0007 0.010 0.028 -0.00003
+1 0.0002 1 1 -0.0053 0.0012 0.011 0.023 -0.00017
+1 0.0003 1 1 -0.0093 0.0012 0.008 -0.002 -0.00013
+1 -0.0001 1 1 0.0077 0.0026 0.008 0.000 0.00006
+1 -0.0001 1 1 0.0065 -0.0007 0.011 0.014 -0.00007
+1 0.0001 1 1 -0.0034 0.0021 0.015 0.021 -0.00012
+1 0.0001 1 1 -0.0059 0.0012 0.015 0.004 -0.00004
+1 -0.0002 1 1 0.0047 -0.0001 0.006 -0.007 0.00014
+1 0.0002 1 1 -0.0044 0.0010 0.010 -0.003 -0.00007
+1 0.0001 1 1 0.0047 0.0031 0.022 -0.013 0.00009
+1 -0.0004 1 1 0.0074 -0.0060 0.019 0.036 -0.00005
+1 -0.0001 1 1 0.0035 -0.0006 0.016 0.045 -0.00034
+1 0.0003 1 1 -0.0082 0.0000 0.013 0.037 -0.00029
+1 -0.0002 1 1 0.0040 0.0010 0.020 -0.009 0.00025
+1 -0.0001 1 1 0.0064 0.0021 0.024 0.011 0.00000
+1 0.0003 1 1 -0.0047 0.0000 0.019 0.026 -0.00016
+1 0.0002 1 1 -0.0018 0.0024 0.017 -0.010 -0.00001
+1 -0.0002 1 1 0.0041 -0.0007 0.022 -0.006 0.00013
+1 -0.0001 1 1 0.0005 -0.0010 0.016 0.010 -0.00008
+1 0.0006 1 1 -0.0045 -0.0046 0.014 0.005 -0.00024
+1 -0.0001 1 1 0.0041 0.0019 0.002 0.013 0.00000
+1 0.0001 1 1 -0.0048 0.0020 0.016 0.004 -0.00003
+1 -0.0002 1 1 0.0049 -0.0011 0.014 -0.006 0.00018
+1 0.0002 1 1 -0.0058 -0.0018 0.017 0.000 -0.00004
+1 -0.0003 1 1 0.0051 -0.0001 0.003 -0.007 0.00021
+1 -0.0002 1 1 0.0026 0.0037 0.014 0.011 -0.00013
+1 0.0001 1 1 -0.0058 0.0008 0.022 0.003 -0.00014
+1 -0.0002 1 1 0.0038 0.0016 0.001 0.013 0.00005
+1 0.0001 1 1 -0.0037 -0.0004 0.016 0.007 -0.00002
+1 -0.0003 1 1 0.0050 0.0006 0.008 0.011 0.00009
+1 0.0001 1 1 -0.0050 0.0004 0.015 0.002 -0.00001
+1 -0.0002 1 1 0.0036 -0.0018 0.006 -0.008 0.00017
+1 -0.0001 1 1 0.0013 0.0009 0.007 0.009 -0.00007
+1 0.0003 1 1 -0.0041 0.0013 0.010 0.005 -0.00015
+1 -0.0001 1 1 0.0077 0.0007 0.011 0.020 0.00007
+1 -0.0002 1 1 0.0074 0.0009 0.011 0.033 -0.00006
+1 0.0003 1 1 -0.0092 -0.0012 0.017 0.031 -0.00025
+1 -0.0001 1 1 -0.0035 0.0021 0.020 0.012 -0.00014
+1 0.0003 1 1 -0.0066 -0.0001 0.018 0.004 -0.00018
+1 -0.0002 1 1 0.0055 0.0012 -0.001 -0.006 0.00024
+1 0.0004 1 1 -0.0080 0.0006 0.015 -0.003 -0.00011
+1 -0.0001 1 1 0.0065 0.0000 0.007 -0.006 0.00016
+1 -0.0001 1 1 0.0058 0.0023 0.010 0.032 -0.00010
+1 -0.0001 1 1 0.0011 0.0020 0.008 0.010 -0.00005
+1 -0.0001 1 1 0.0044 0.0018 0.007 0.015 0.00001
+1 0.0002 1 1 -0.0057 -0.0009 0.009 0.011 -0.00010
+1 0.0001 1 1 -0.0021 0.0009 0.005 -0.013 0.00009
+1 -0.0001 1 1 0.0054 0.0012 0.006 -0.007 0.00020
+1 -0.0001 1 1 0.0036 0.0031 0.014 0.013 -0.00014
+1 0.0003 1 1 -0.0060 -0.0016 0.012 0.005 -0.00013
+1 -0.0002 1 1 0.0035 -0.0006 -0.005 -0.003 0.00004
+1 -0.0002 1 1 0.0072 -0.0026 0.005 -0.004 0.00027
+1 -0.0001 1 1 0.0068 0.0014 0.004 0.011 -0.00014
+1 0.0001 1 1 -0.0041 0.0020 0.013 0.015 -0.00005
+1 -0.0001 1 1 0.0043 -0.0016 0.012 -0.020 0.00010
+1 0.0001 1 1 -0.0033 0.0003 0.008 0.001 -0.00010
+1 0.0001 1 1 -0.0029 0.0011 0.009 -0.012 0.00004
+1 -0.0001 1 1 0.0035 -0.0009 0.004 -0.007 0.00001
+1 -0.0001 1 1 0.0011 0.0031 0.013 0.010 -0.00006
+1 0.0003 1 1 -0.0050 0.0012 0.016 0.006 -0.00029
+1 -0.0001 1 1 0.0061 -0.0005 0.003 -0.007 0.00017
+1 -0.0001 1 1 0.0063 0.0019 0.007 0.011 -0.00004
+1 0.0001 1 1 -0.0036 0.0010 0.018 0.016 -0.00005
+1 0.0003 1 1 -0.0053 -0.0023 0.012 0.005 -0.00007
+1 0.0003 1 1 -0.0076 -0.0013 0.011 0.001 -0.00017
+1 -0.0001 1 1 0.0006 0.0001 0.014 0.009 -0.00003
+1 -0.0001 1 1 0.0040 -0.0002 0.007 0.011 0.00008
+1 -0.0001 1 1 -0.0004 0.0011 0.010 0.027 -0.00010
+1 0.0002 1 1 -0.0035 0.0013 0.012 0.023 -0.00018
+1 -0.0001 1 1 0.0026 -0.0020 0.013 0.010 0.00007
+1 -0.0001 1 1 0.0013 0.0009 0.006 0.009 0.00005
+1 -0.0001 1 1 0.0029 0.0008 0.005 0.010 0.00004
+1 -0.0002 1 1 0.0023 0.0000 0.012 0.028 -0.00006
+1 0.0003 1 1 -0.0055 -0.0005 0.013 0.021 -0.00014
+1 -0.0001 1 1 0.0022 -0.0008 0.013 0.011 0.00001
+1 0.0001 1 1 -0.0035 -0.0005 0.005 0.005 -0.00004
+1 0.0001 1 1 -0.0062 -0.0002 0.011 0.008 -0.00015
+1 0.0001 1 1 -0.0066 -0.0004 0.008 -0.011 0.00003
+1 -0.0001 1 1 0.0029 0.0006 0.018 -0.007 0.00006
+1 0.0001 1 1 -0.0001 0.0005 0.014 -0.009 0.00003
+1 -0.0002 1 1 0.0035 0.0002 0.013 -0.003 0.00009
+1 0.0003 1 1 -0.0030 0.0018 0.008 -0.010 -0.00007
+1 -0.0002 1 1 0.0048 0.0018 0.008 -0.007 0.00012
+1 -0.0002 1 1 0.0038 0.0016 0.015 0.013 -0.00002
+1 0.0003 1 1 -0.0036 0.0000 0.014 0.015 -0.00025
+1 -0.0001 1 1 0.0037 0.0023 0.014 0.011 0.00003
+1 0.0001 1 1 -0.0033 0.0006 0.016 0.012 -0.00008
+1 -0.0002 1 1 0.0047 -0.0002 0.011 0.005 0.00021
+1 -0.0001 1 1 0.0061 0.0001 0.011 0.016 0.00001
+1 -0.0001 1 1 0.0040 0.0004 0.011 0.028 -0.00011
+1 0.0001 1 1 -0.0005 0.0007 0.011 0.032 -0.00021
+1 -0.0003 1 1 0.0022 -0.0006 0.009 0.009 0.00010
+1 0.0001 1 1 -0.0061 0.0009 0.010 0.002 -0.00014
+1 0.0003 1 1 -0.0066 0.0017 0.012 -0.010 0.00000
+1 -0.0002 1 1 0.0040 -0.0006 0.009 -0.007 0.00006
+1 0.0003 1 1 -0.0050 0.0001 0.005 -0.010 -0.00010
+1 -0.0001 1 1 0.0050 0.0025 0.010 -0.008 0.00008
+1 0.0001 1 1 -0.0038 0.0001 0.015 0.011 -0.00024
+1 0.0002 1 1 -0.0046 0.0003 0.014 0.007 -0.00010
+1 0.0001 1 1 0.0038 0.0012 0.013 -0.010 0.00023
+1 -0.0001 1 1 0.0063 -0.0002 0.021 -0.002 0.00010
+1 -0.0001 1 1 0.0064 0.0004 0.021 0.013 -0.00004
+1 0.0001 1 1 0.0036 -0.0019 0.019 0.028 -0.00011
+1 -0.0001 1 1 0.0001 -0.0033 0.004 0.034 -0.00010
+1 0.0001 1 1 -0.0024 0.0026 0.015 -0.010 0.00010
+1 0.0001 1 1 0.0059 -0.0024 0.024 0.000 0.00012
+1 -0.0002 1 1 0.0083 -0.0027 0.018 0.015 0.00007
+1 -0.0001 1 1 0.0047 -0.0021 0.008 0.043 -0.00014
+1 0.0001 1 1 -0.0061 0.0016 0.009 0.039 -0.00016
+1 -0.0001 1 1 0.0050 -0.0002 0.006 0.019 0.00002
+1 -0.0001 1 1 0.0012 0.0013 0.010 0.033 -0.00011
+1 0.0001 1 1 -0.0073 -0.0003 0.010 0.008 -0.00005
+1 -0.0001 1 1 0.0082 0.0008 0.005 0.011 0.00005
+1 -0.0001 1 1 0.0047 0.0013 0.008 0.029 -0.00020
+1 0.0001 1 1 -0.0034 0.0017 0.013 0.031 -0.00026
+1 0.0002 1 1 -0.0059 -0.0017 0.013 0.024 -0.00012
+1 -0.0001 1 1 0.0049 0.0005 0.010 0.012 0.00004
+1 0.0001 1 1 -0.0066 0.0002 0.012 0.001 -0.00004
+1 -0.0002 1 1 0.0063 0.0001 0.009 -0.001 0.00004
+1 -0.0002 1 1 0.0036 0.0006 0.010 0.013 -0.00014
+1 0.0002 1 1 -0.0100 -0.0009 0.010 -0.004 -0.00019
+1 0.0001 1 1 -0.0036 0.0003 0.010 -0.045 0.00030
+1 -0.0002 1 1 0.0049 0.0003 0.009 -0.043 0.00028
+1 0.0001 1 1 -0.0051 0.0003 0.006 0.004 -0.00007
+1 0.0001 1 1 -0.0022 0.0001 0.005 -0.015 0.00009
+1 -0.0001 1 1 0.0044 0.0001 0.004 -0.006 0.00007
+1 -0.0001 1 1 0.0013 0.0004 0.005 0.010 -0.00008
+1 0.0002 1 1 -0.0034 0.0006 0.006 0.005 -0.00009
+1 -0.0001 1 1 0.0036 0.0022 0.014 0.011 0.00000
+1 0.0001 1 1 -0.0052 -0.0004 0.012 0.005 -0.00007
+1 0.0001 1 1 -0.0041 -0.0006 0.009 -0.014 0.00007
+1 -0.0001 1 1 0.0053 0.0002 0.008 -0.005 0.00006
+1 -0.0001 1 1 0.0042 0.0004 0.009 0.012 -0.00007
+1 0.0001 1 1 -0.0066 -0.0003 0.011 0.000 -0.00009
+1 -0.0001 1 1 0.0071 0.0001 0.009 -0.002 0.00007
+1 -0.0001 1 1 0.0052 0.0003 0.010 0.019 -0.00009
+1 0.0001 1 1 -0.0060 0.0010 0.007 0.017 -0.00016
+1 -0.0001 1 1 0.0051 0.0013 0.008 -0.007 0.00009
+1 0.0001 1 1 -0.0045 -0.0004 0.011 0.007 -0.00009
+1 -0.0001 1 1 0.0031 0.0003 0.007 -0.005 0.00007
+1 -0.0001 1 1 0.0038 -0.0027 0.006 0.011 0.00006
+1 0.0001 1 1 -0.0051 0.0006 0.007 0.005 -0.00004
+1 -0.0001 1 1 0.0041 0.0015 0.009 -0.003 0.00009
+1 0.0001 1 1 0.0041 0.0005 0.014 0.010 -0.00003
+1 0.0001 1 1 -0.0023 0.0005 0.008 -0.012 0.00008
+1 -0.0001 1 1 0.0044 0.0003 0.009 -0.006 0.00010
+1 0.0001 1 1 -0.0045 -0.0020 0.012 -0.001 -0.00001
+1 -0.0001 1 1 0.0049 -0.0008 0.008 -0.004 0.00012
+1 -0.0001 1 1 0.0037 -0.0001 0.008 0.013 -0.00006
+1 0.0001 1 1 -0.0040 0.0008 0.007 0.012 -0.00011
+1 -0.0002 1 1 0.0052 0.0004 0.009 0.014 0.00003
+1 -0.0001 1 1 -0.0055 -0.0001 0.007 0.014 -0.00010
+1 0.0002 1 1 -0.0085 0.0010 0.009 -0.001 -0.00013
+1 0.0001 1 1 -0.0033 0.0005 0.010 -0.029 0.00021
+1 -0.0001 1 1 0.0080 0.0016 0.009 -0.016 0.00016
+1 -0.0001 1 1 0.0090 0.0016 0.011 -0.004 0.00002
+1 0.0001 1 1 0.0085 0.0033 0.014 0.010 -0.00006
+1 -0.0001 1 1 0.0054 -0.0013 0.011 0.029 -0.00016
+1 0.0001 1 1 -0.0060 -0.0002 0.005 0.022 -0.00008
+1 -0.0001 1 1 0.0050 0.0035 0.017 0.014 0.00005
+1 0.0001 1 1 0.0035 0.0006 0.018 0.024 -0.00010
+1 0.0001 1 1 -0.0039 -0.0012 0.011 0.024 -0.00010
+1 -0.0001 1 1 0.0034 0.0005 0.007 0.010 0.00005
+1 0.0001 1 1 -0.0044 -0.0002 0.011 0.003 -0.00003
+1 -0.0001 1 1 0.0052 0.0004 0.006 0.010 0.00004
+1 0.0001 1 1 -0.0050 -0.0001 0.010 0.005 -0.00003
+1 -0.0001 1 1 0.0069 0.0005 0.009 0.019 0.00003
+1 -0.0001 1 1 0.0057 0.0008 0.010 0.028 -0.00013
+1 0.0001 1 1 -0.0057 -0.0001 0.013 0.024 -0.00009
+1 -0.0001 1 1 0.0024 -0.0002 0.006 0.031 -0.00008
+1 0.0001 1 1 -0.0042 0.0000 0.009 0.024 -0.00006
+1 -0.0001 1 1 0.0027 -0.0005 0.009 0.010 0.00009
+1 0.0001 1 1 -0.0039 0.0000 0.009 0.003 -0.00003
+1 -0.0001 1 1 -0.0003 -0.0001 0.007 -0.010 0.00007
+1 0.0001 1 1 0.0040 0.0006 0.008 -0.005 0.00013
+1 0.0001 1 1 -0.0039 0.0008 0.004 0.006 -0.00001
+1 -0.0001 1 1 0.0036 0.0008 0.012 0.010 0.00002
+1 -0.0001 1 1 0.0028 -0.0003 0.008 -0.006 0.00011
+1 0.0001 1 1 0.0041 0.0010 0.012 -0.002 0.00002
+1 0.0001 1 1 -0.0060 0.0004 0.011 0.007 -0.00012
+1 -0.0002 1 1 0.0041 0.0020 0.009 -0.007 0.00007
+1 0.0001 1 1 -0.0026 0.0003 0.001 -0.016 0.00007
+1 -0.0001 1 1 0.0070 -0.0002 0.011 0.025 -0.00002
+1 0.0002 1 1 -0.0106 -0.0003 0.012 0.014 -0.00020
+1 -0.0001 1 1 0.0055 -0.0026 0.008 -0.022 0.00026
+1 -0.0002 1 1 0.0077 -0.0009 0.005 -0.004 0.00001
+1 0.0001 1 1 0.0058 0.0000 0.004 0.010 -0.00015
+1 -0.0001 1 1 -0.0040 0.0001 0.010 0.012 -0.00002
+1 0.0002 1 1 -0.0053 0.0004 0.011 0.005 -0.00012
+1 -0.0002 1 1 0.0040 -0.0004 0.006 -0.006 0.00016
+1 0.0001 1 1 -0.0073 -0.0005 0.008 0.005 -0.00010
+1 -0.0001 1 1 0.0052 -0.0002 0.007 -0.022 0.00015
+1 -0.0001 1 1 0.0051 0.0005 0.003 0.011 -0.00010
+1 0.0001 1 1 -0.0048 0.0024 0.016 0.007 -0.00005
+1 -0.0001 1 1 0.0017 -0.0007 0.003 0.011 -0.00004
+1 0.0001 1 1 -0.0036 0.0004 0.012 0.007 -0.00005
+1 -0.0001 1 1 0.0056 -0.0002 0.010 0.011 0.00009
+1 -0.0001 1 1 0.0028 0.0004 0.010 0.027 -0.00014
+1 0.0002 1 1 -0.0040 -0.0005 0.007 0.024 -0.00014
+1 -0.0002 1 1 0.0011 0.0002 0.006 0.010 0.00000
+1 -0.0001 1 1 0.0044 0.0001 0.007 0.017 0.00003
+1 0.0001 1 1 -0.0053 0.0005 0.011 0.006 -0.00003
+1 0.0001 1 1 0.0005 0.0001 0.008 -0.009 0.00013
+1 0.0001 1 1 -0.0045 0.0003 0.013 0.005 -0.00004
+1 0.0001 1 1 -0.0015 -0.0008 0.012 -0.010 0.00011
+1 -0.0001 1 1 0.0062 -0.0002 0.008 0.002 0.00012
+1 -0.0001 1 1 -0.0042 -0.0016 0.009 0.031 -0.00004
+1 0.0001 1 1 -0.0049 -0.0015 0.007 0.025 -0.00005
+1 -0.0001 1 1 0.0043 0.0021 0.012 0.013 0.00006
+1 0.0001 1 1 -0.0044 -0.0003 0.012 0.025 -0.00014
+1 -0.0001 1 1 0.0038 0.0004 0.006 -0.006 0.00007
+1 0.0001 1 1 -0.0028 -0.0003 0.009 -0.014 0.00002
+1 -0.0001 1 1 0.0067 0.0006 0.006 0.010 -0.00003
+1 -0.0001 1 1 0.0054 -0.0008 0.005 0.018 -0.00001
+1 -0.0001 1 1 0.0037 0.0005 0.006 0.029 -0.00004
+1 0.0001 1 1 -0.0046 0.0006 0.010 0.023 -0.00006
+1 -0.0001 1 1 0.0036 0.0002 0.004 0.011 0.00005
+1 0.0001 1 1 -0.0025 -0.0001 0.013 -0.010 -0.00003
+1 0.0002 1 1 -0.0041 0.0010 0.009 -0.014 -0.00002
+1 0.0003 1 1 -0.0056 0.0020 0.023 -0.014 0.00001
+1 0.0001 1 1 0.0074 0.0003 0.016 -0.008 0.00011
+1 -0.0005 1 1 0.0094 0.0005 0.014 0.012 0.00001
+1 0.0002 1 1 -0.0074 0.0003 0.018 0.024 -0.00039
+1 0.0001 1 1 -0.0109 0.0009 0.017 0.004 -0.00010
+1 0.0002 1 1 -0.0117 -0.0003 0.013 -0.017 -0.00001
+1 0.0002 1 1 -0.0045 0.0014 0.010 -0.048 0.00024
+1 -0.0002 1 1 0.0084 0.0041 0.013 -0.034 0.00014
+1 -0.0004 1 1 0.0010 -0.0016 0.009 0.009 0.00001
+1 0.0003 1 1 -0.0052 0.0009 0.007 0.005 -0.00027
+1 0.0001 1 1 0.0055 0.0026 0.015 -0.017 0.00012
+1 -0.0006 1 1 0.0095 0.0015 0.016 0.011 0.00005
+1 0.0002 1 1 -0.0053 0.0007 0.021 0.025 -0.00044
+1 0.0001 1 1 -0.0091 -0.0014 0.013 -0.002 -0.00004
+1 -0.0003 1 1 0.0050 0.0029 0.008 -0.025 0.00018
+1 -0.0001 1 1 0.0042 -0.0026 0.001 -0.007 0.00021
+1 -0.0001 1 1 0.0075 0.0020 0.003 0.012 0.00002
+1 -0.0005 1 1 0.0071 0.0054 0.012 0.025 -0.00004
+1 0.0003 1 1 -0.0076 -0.0010 0.021 0.024 -0.00025
+1 -0.0002 1 1 0.0049 0.0004 0.002 -0.006 0.00016
+1 -0.0002 1 1 0.0055 0.0035 0.006 0.013 -0.00004
+1 0.0002 1 1 -0.0062 -0.0007 0.011 0.006 -0.00009
+1 0.0001 1 1 -0.0007 0.0027 0.003 -0.010 0.00014
+1 -0.0001 1 1 0.0041 0.0022 0.006 -0.005 0.00014
+1 -0.0002 1 1 0.0022 0.0026 0.013 0.011 -0.00007
+1 0.0003 1 1 -0.0043 0.0020 0.017 0.007 -0.00015
+1 -0.0001 1 1 0.0042 0.0019 0.010 0.004 0.00005
+1 -0.0001 1 1 0.0035 0.0020 0.012 0.010 -0.00008
+1 0.0003 1 1 -0.0043 0.0005 0.014 0.006 -0.00008
+1 -0.0003 1 1 0.0066 0.0000 0.007 0.013 0.00012
+1 0.0002 1 1 -0.0041 0.0019 0.010 0.024 -0.00023
+1 0.0001 1 1 -0.0026 0.0008 0.012 -0.011 0.00008
+1 -0.0003 1 1 0.0051 -0.0003 0.005 -0.005 0.00014
+1 0.0002 1 1 -0.0076 0.0017 0.008 -0.013 -0.00009
+1 0.0001 1 1 -0.0044 0.0015 0.009 -0.033 0.00014
+1 -0.0001 1 1 0.0082 0.0024 0.010 -0.018 0.00013
+1 0.0001 1 1 0.0047 -0.0003 0.015 0.013 -0.00017
+1 0.0001 1 1 -0.0044 0.0000 0.011 0.014 -0.00019
+1 -0.0001 1 1 0.0073 0.0026 0.017 -0.010 0.00010
+1 -0.0002 1 1 0.0077 -0.0001 0.013 0.016 -0.00007
+1 -0.0002 1 1 0.0032 0.0001 0.012 0.027 -0.00027
+1 0.0003 1 1 -0.0060 -0.0028 0.011 0.025 -0.00041
+1 0.0001 1 1 -0.0033 -0.0006 0.002 -0.010 0.00028
+1 -0.0001 1 1 0.0091 0.0048 0.014 0.008 0.00011
+1 -0.0003 1 1 0.0096 0.0022 0.016 0.023 -0.00002
+1 0.0002 1 1 -0.0108 -0.0028 0.009 0.020 -0.00026
+1 0.0001 1 1 0.0073 0.0073 0.006 -0.018 0.00019
+1 -0.0001 1 1 0.0102 0.0053 0.014 -0.003 0.00013
+1 -0.0001 1 1 0.0106 0.0026 0.018 0.014 -0.00002
+1 -0.0002 1 1 0.0085 0.0031 0.022 0.030 -0.00017
+1 0.0001 1 1 -0.0084 -0.0030 0.007 0.025 -0.00016
+1 -0.0003 1 1 0.0074 0.0046 0.004 -0.005 0.00022
+1 -0.0001 1 1 0.0062 0.0045 0.013 0.012 -0.00011
+1 0.0002 1 1 -0.0047 -0.0005 0.007 0.008 -0.00004
+1 -0.0001 1 1 0.0052 0.0007 0.014 0.013 0.00005
+1 -0.0002 1 1 0.0036 -0.0008 0.010 0.027 -0.00008
+1 0.0001 1 1 -0.0077 -0.0001 0.005 0.021 -0.00027
+1 -0.0001 1 1 0.0091 0.0001 0.010 0.000 0.00026
+1 -0.0002 1 1 0.0096 0.0031 0.012 0.019 -0.00034
+1 0.0005 1 1 -0.0067 0.0021 0.017 0.025 -0.00047
+1 -0.0005 1 1 0.0104 -0.0027 0.008 0.012 0.00033
+1 -0.0001 1 1 0.0083 -0.0005 0.006 0.036 -0.00048
+1 0.0002 1 1 -0.0071 0.0026 0.015 -0.011 -0.00006
+1 0.0002 1 1 -0.0036 0.0002 0.015 -0.029 0.00016
+1 -0.0002 1 1 0.0069 0.0001 0.014 -0.022 0.00021
+1 -0.0001 1 1 0.0083 0.0005 0.014 0.000 -0.00001
+1 0.0002 1 1 -0.0023 0.0026 0.012 -0.010 -0.00002
+1 -0.0001 1 1 0.0035 0.0005 0.013 -0.007 0.00008
+1 -0.0002 1 1 0.0039 -0.0006 0.009 0.011 0.00009
+1 -0.0001 1 1 0.0022 0.0001 0.008 0.009 -0.00001
+1 0.0001 1 1 -0.0029 -0.0008 0.008 -0.012 0.00003
+1 -0.0001 1 1 0.0044 0.0001 0.004 -0.004 0.00005
+1 0.0001 1 1 -0.0038 0.0014 0.012 0.007 -0.00008
+1 0.0001 1 1 -0.0029 -0.0006 0.013 -0.012 -0.00001
+1 -0.0001 1 1 0.0047 -0.0010 0.006 -0.007 0.00010
+1 -0.0001 1 1 0.0063 0.0021 0.005 0.015 -0.00003
+1 -0.0001 1 1 0.0036 0.0024 0.009 0.024 -0.00018
+1 -0.0001 1 1 -0.0002 0.0018 0.011 0.027 -0.00027
+1 0.0004 1 1 -0.0097 -0.0017 0.015 0.012 -0.00025
+1 -0.0002 1 1 0.0055 0.0014 0.003 -0.023 0.00029
+1 -0.0001 1 1 0.0057 0.0012 0.008 0.021 -0.00009
+1 -0.0001 1 1 -0.0039 0.0013 0.017 0.026 -0.00010
+1 0.0004 1 1 -0.0067 -0.0004 0.016 0.016 -0.00013
+1 -0.0001 1 1 0.0036 0.0026 0.002 0.002 0.00019
+1 -0.0002 1 1 0.0057 0.0009 0.003 0.013 0.00005
+1 0.0002 1 1 -0.0079 0.0027 0.016 0.010 -0.00018
+1 -0.0001 1 1 0.0067 -0.0045 0.011 -0.016 0.00029
+1 -0.0002 1 1 0.0090 -0.0029 0.005 -0.001 0.00006
+1 0.0002 1 1 -0.0037 0.0005 0.006 0.025 -0.00014
+1 -0.0001 1 1 0.0012 -0.0036 0.007 0.010 0.00001
+1 0.0001 1 1 -0.0048 0.0023 0.005 0.001 -0.00012
+1 0.0001 1 1 -0.0051 0.0026 0.011 -0.013 0.00003
+1 -0.0002 1 1 0.0043 -0.0020 0.011 -0.007 0.00007
+1 0.0001 1 1 -0.0033 -0.0003 0.008 -0.003 -0.00009
+1 0.0001 1 1 -0.0031 -0.0004 0.006 -0.012 0.00004
+1 -0.0001 1 1 0.0051 -0.0002 0.011 -0.008 0.00013
+1 -0.0001 1 1 0.0040 0.0000 0.012 0.012 -0.00012
+1 0.0002 1 1 -0.0035 -0.0020 0.008 0.013 -0.00017
+1 -0.0001 1 1 -0.0036 -0.0013 -0.002 -0.010 0.00004
+1 0.0001 1 1 -0.0044 0.0014 0.001 -0.017 -0.00005
+1 0.0001 1 1 0.0048 0.0004 0.017 -0.016 0.00009
+1 -0.0003 1 1 0.0079 -0.0039 0.008 -0.001 0.00011
+1 -0.0001 1 1 0.0054 -0.0021 0.003 0.014 -0.00022
+1 0.0004 1 1 -0.0093 0.0011 0.007 -0.001 -0.00017
+1 -0.0002 1 1 0.0046 0.0002 0.012 -0.003 0.00008
+1 -0.0001 1 1 0.0019 0.0004 0.011 0.010 0.00002
+1 -0.0001 1 1 0.0022 -0.0005 0.003 0.009 0.00002
+1 0.0002 1 1 -0.0033 -0.0021 0.008 0.009 -0.00002
+1 -0.0001 1 1 0.0040 0.0033 0.006 0.013 0.00006
+1 -0.0003 1 1 0.0019 -0.0016 0.010 0.028 0.00004
+1 0.0002 1 1 -0.0061 0.0001 0.010 0.021 -0.00020
+1 -0.0001 1 1 0.0009 0.0006 0.016 0.011 -0.00002
+1 0.0001 1 1 -0.0046 0.0019 0.003 0.000 -0.00011
+1 0.0002 1 1 -0.0058 0.0042 0.012 -0.013 -0.00002
+1 0.0004 1 1 -0.0028 0.0002 0.013 -0.027 -0.00006
+1 -0.0001 1 1 0.0074 -0.0018 0.000 -0.022 0.00027
+1 -0.0001 1 1 0.0107 0.0049 0.002 -0.001 0.00005
+1 -0.0002 1 1 0.0050 0.0053 0.018 0.029 -0.00027
+1 0.0004 1 1 -0.0062 -0.0033 0.016 0.024 -0.00018
+1 -0.0001 1 1 0.0013 0.0013 0.007 0.009 0.00005
+1 -0.0003 1 1 0.0032 -0.0008 0.009 0.011 0.00011
+1 0.0001 1 1 -0.0033 -0.0009 0.009 0.012 -0.00017
+1 0.0002 1 1 -0.0029 0.0010 0.002 -0.011 -0.00002
+1 -0.0002 1 1 0.0038 0.0015 0.008 -0.010 0.00014
+1 -0.0001 1 1 0.0016 -0.0002 0.013 0.010 -0.00006
+1 0.0001 1 1 0.0003 0.0015 0.018 -0.009 0.00012
+1 -0.0003 1 1 0.0033 -0.0004 0.016 -0.006 0.00017
+1 -0.0001 1 1 -0.0007 -0.0021 0.000 -0.009 0.00007
+1 0.0001 1 1 -0.0004 0.0003 0.000 -0.010 0.00001
+1 0.0002 1 1 -0.0010 0.0009 0.013 -0.010 0.00001
+1 -0.0002 1 1 0.0027 -0.0003 0.011 -0.008 0.00011
+1 0.0001 1 1 -0.0011 0.0000 0.009 -0.010 0.00002
+1 -0.0003 1 1 0.0035 0.0005 0.005 0.011 -0.00003
+1 0.0002 1 1 -0.0052 0.0015 0.009 0.009 -0.00023
+1 0.0002 1 1 -0.0070 0.0011 0.012 -0.012 0.00001
+1 -0.0002 1 1 0.0045 -0.0002 0.011 -0.006 0.00006
+1 0.0001 1 1 -0.0010 0.0012 0.011 -0.010 -0.00004
+1 0.0002 1 1 -0.0037 -0.0018 0.012 0.006 -0.00001
+1 -0.0001 1 1 0.0027 0.0019 0.008 0.010 0.00000
+1 0.0001 1 1 -0.0029 -0.0018 0.005 -0.014 0.00005
+1 0.0001 1 1 -0.0003 0.0012 0.009 -0.009 0.00001
+1 0.0001 1 1 -0.0026 -0.0002 0.014 -0.011 -0.00001
+1 -0.0001 1 1 0.0067 -0.0012 0.005 0.015 0.00002
+1 -0.0001 1 1 0.0045 0.0010 0.007 0.031 -0.00011
+1 0.0001 1 1 -0.0045 0.0012 0.012 0.030 -0.00015
+1 0.0001 1 1 -0.0037 0.0002 0.013 -0.001 -0.00004
+1 0.0001 1 1 -0.0018 -0.0027 0.004 -0.010 0.00008
+1 -0.0005 1 1 0.0040 -0.0013 0.007 -0.006 0.00013
+1 0.0001 1 1 -0.0030 0.0010 0.010 -0.011 0.00010
+1 0.0001 1 1 -0.0033 0.0016 0.003 0.006 -0.00008
+1 0.0001 1 1 -0.0030 0.0014 0.009 -0.011 -0.00002
+1 -0.0001 1 1 0.0023 -0.0018 0.003 0.009 0.00000
+1 0.0002 1 1 -0.0048 0.0025 0.014 0.006 -0.00013
+1 0.0001 1 1 -0.0035 0.0002 0.014 -0.012 0.00008
+1 -0.0001 1 1 0.0036 0.0000 0.001 -0.008 0.00003
+1 0.0001 1 1 -0.0019 0.0026 0.008 -0.010 -0.00004
+1 -0.0002 1 1 0.0032 -0.0006 0.007 0.011 -0.00003
+1 0.0001 1 1 -0.0051 0.0006 0.009 0.006 -0.00011
+1 0.0001 1 1 -0.0048 -0.0013 0.008 -0.013 0.00006
+1 -0.0001 1 1 0.0035 0.0024 0.001 -0.014 0.00004
+1 -0.0001 1 1 0.0018 -0.0017 0.008 0.011 -0.00001
+1 -0.0001 1 1 -0.0041 -0.0012 0.000 0.006 -0.00010
+1 0.0001 1 1 -0.0042 0.0026 0.014 -0.028 0.00008
+1 -0.0002 1 1 0.0051 -0.0007 0.009 -0.026 0.00013
+1 -0.0002 1 1 0.0028 0.0014 0.010 -0.006 0.00002
+1 -0.0002 1 1 0.0019 0.0013 0.001 0.010 -0.00003
+1 0.0001 1 1 -0.0004 -0.0015 0.017 -0.009 0.00011
+1 -0.0003 1 1 0.0035 -0.0050 0.010 -0.006 0.00016
+1 0.0002 1 1 -0.0021 -0.0026 0.008 -0.010 -0.00003
+1 -0.0001 1 1 0.0043 -0.0027 -0.005 -0.007 0.00015
+1 0.0003 1 1 -0.0053 -0.0019 0.011 0.007 -0.00018
+1 0.0001 1 1 -0.0027 -0.0010 0.010 -0.011 0.00000
+1 -0.0001 1 1 0.0030 0.0015 0.010 -0.005 0.00002
+1 0.0001 1 1 -0.0019 0.0017 0.010 -0.012 0.00002
+1 -0.0001 1 1 0.0036 0.0015 0.011 0.010 -0.00003
+1 0.0001 1 1 -0.0005 -0.0004 0.007 -0.009 0.00006
+1 -0.0002 1 1 0.0029 0.0003 0.007 -0.007 0.00014
+1 -0.0001 1 1 0.0004 0.0009 0.010 0.009 -0.00010
+1 0.0002 1 1 -0.0049 0.0010 0.012 0.002 -0.00015
+1 -0.0001 1 1 0.0041 0.0004 0.004 -0.010 0.00011
+1 -0.0002 1 1 0.0032 -0.0017 0.009 0.010 0.00006
+1 0.0001 1 1 -0.0030 0.0008 0.009 -0.010 0.00003
+1 -0.0001 1 1 0.0043 0.0006 0.007 -0.004 0.00005
+1 0.0001 1 1 -0.0044 0.0006 0.011 0.005 -0.00026
+1 0.0002 1 1 -0.0070 -0.0015 0.009 -0.003 -0.00014
+1 -0.0001 1 1 0.0035 -0.0003 0.009 -0.005 0.00003
+1 0.0002 1 1 -0.0046 0.0011 0.012 -0.010 -0.00006
+1 -0.0001 1 1 0.0041 0.0007 0.004 -0.014 0.00009
+1 0.0001 1 1 0.0006 0.0019 0.011 0.009 -0.00010
+1 -0.0002 1 1 0.0008 -0.0001 0.013 0.009 0.00006
+1 0.0002 1 1 -0.0050 -0.0005 0.011 0.005 -0.00025
+1 0.0002 1 1 -0.0057 -0.0001 0.010 -0.011 0.00005
+1 -0.0002 1 1 0.0062 -0.0006 0.012 0.000 0.00010
+1 -0.0004 1 1 0.0049 -0.0033 0.010 0.012 -0.00010
+1 -0.0001 1 1 0.0034 0.0015 0.008 -0.004 0.00013
+1 -0.0002 1 1 0.0037 -0.0012 0.006 0.013 -0.00002
+1 0.0001 1 1 -0.0057 0.0001 0.010 0.005 -0.00009
+1 0.0001 1 1 -0.0010 -0.0025 0.011 -0.010 0.00018
+1 -0.0005 1 1 0.0046 -0.0010 0.007 -0.007 0.00028
+1 0.0004 1 1 -0.0074 0.0005 0.008 -0.012 -0.00013
+1 0.0003 1 1 -0.0029 0.0079 0.015 -0.010 0.00010
+1 0.0001 1 1 0.0063 0.0004 0.027 -0.004 0.00020
+1 -0.0002 1 1 0.0082 0.0025 0.026 0.010 -0.00004
+1 0.0001 1 1 0.0050 0.0017 0.025 0.024 -0.00019
+1 0.0004 1 1 -0.0076 0.0001 0.012 0.024 -0.00014
+1 -0.0003 1 1 0.0064 0.0021 0.016 0.011 0.00007
+1 0.0004 1 1 -0.0049 0.0002 0.020 0.025 -0.00030
+1 -0.0004 1 1 0.0046 0.0042 0.016 -0.005 0.00008
+1 0.0001 1 1 -0.0038 0.0020 0.022 -0.006 -0.00005
+1 -0.0001 1 1 0.0049 0.0011 0.012 -0.005 0.00008
+1 0.0003 1 1 -0.0049 0.0023 0.015 0.006 -0.00020
+1 0.0003 1 1 -0.0021 0.0021 0.016 -0.013 0.00011
+1 -0.0003 1 1 0.0059 0.0020 0.014 -0.007 0.00022
+1 0.0001 1 1 0.0067 0.0036 0.017 0.010 -0.00004
+1 0.0002 1 1 -0.0048 0.0012 0.009 0.023 -0.00008
+1 -0.0006 1 1 0.0030 0.0022 0.015 0.011 0.00015
+1 0.0003 1 1 -0.0066 0.0023 0.019 0.005 -0.00018
+1 0.0002 1 1 -0.0058 0.0009 0.020 -0.012 0.00015
+1 -0.0006 1 1 0.0099 0.0009 0.012 0.007 0.00011
+1 0.0001 1 1 0.0040 0.0017 0.011 0.027 -0.00040
+1 0.0003 1 1 -0.0050 0.0009 0.009 0.024 -0.00026
+1 0.0001 1 1 -0.0070 0.0037 0.012 0.009 -0.00001
+1 -0.0001 1 1 0.0098 -0.0006 0.004 0.011 0.00021
+1 -0.0003 1 1 0.0112 0.0020 0.004 0.028 -0.00013
+1 -0.0001 1 1 0.0016 0.0024 0.006 0.049 -0.00034
+1 0.0003 1 1 -0.0062 0.0035 0.010 0.044 -0.00038
+1 0.0001 1 1 -0.0089 0.0043 0.015 0.029 -0.00002
+1 -0.0003 1 1 0.0030 0.0002 0.013 -0.006 0.00025
+1 -0.0002 1 1 0.0019 0.0010 0.008 0.010 -0.00006
+1 0.0003 1 1 -0.0033 0.0014 0.006 0.008 -0.00019
+1 -0.0001 1 1 0.0035 0.0015 0.011 0.000 0.00015
+1 -0.0001 1 1 0.0012 0.0025 0.013 0.009 -0.00009
+1 0.0003 1 1 -0.0062 0.0020 0.012 -0.012 -0.00005
+1 -0.0002 1 1 0.0084 0.0016 0.007 -0.002 0.00010
+1 -0.0002 1 1 0.0011 0.0020 0.012 0.027 -0.00016
+1 0.0003 1 1 -0.0073 0.0012 0.012 0.014 -0.00014
+1 -0.0001 1 1 0.0066 0.0008 0.006 0.002 0.00022
+1 -0.0004 1 1 0.0088 0.0024 0.008 0.016 0.00008
+1 -0.0001 1 1 0.0044 0.0016 0.008 0.031 -0.00027
+1 0.0001 1 1 -0.0050 0.0019 0.009 0.031 -0.00038
+1 -0.0002 1 1 0.0035 0.0018 0.015 0.003 0.00004
+1 -0.0002 1 1 0.0014 0.0010 0.013 0.010 -0.00003
+1 0.0002 1 1 -0.0049 0.0012 0.011 0.006 -0.00022
+1 0.0002 1 1 -0.0040 0.0010 0.009 -0.012 0.00013
+1 -0.0002 1 1 0.0087 0.0015 0.006 0.000 0.00019
+1 0.0002 1 1 -0.0059 0.0007 0.005 0.022 -0.00035
+1 -0.0002 1 1 0.0093 0.0008 0.005 0.002 0.00024
+1 -0.0001 1 1 0.0103 0.0011 0.004 0.016 0.00000
+1 -0.0003 1 1 0.0087 -0.0012 0.003 0.029 -0.00014
+1 -0.0001 1 1 -0.0046 0.0048 0.007 0.037 -0.00047
+1 0.0002 1 1 -0.0116 0.0049 0.013 0.024 -0.00039
+1 -0.0002 1 1 0.0061 0.0002 0.010 -0.042 0.00047
+1 -0.0001 1 1 0.0110 0.0007 0.006 -0.022 0.00013
+1 -0.0001 1 1 0.0020 0.0031 0.010 0.029 -0.00038
+1 0.0004 1 1 -0.0072 0.0022 0.012 0.023 -0.00039
+1 -0.0002 1 1 0.0106 -0.0010 0.018 0.001 0.00034
+1 -0.0001 1 1 0.0122 0.0006 0.015 0.020 -0.00017
+1 -0.0002 1 1 0.0021 -0.0002 0.010 0.051 -0.00025
+1 0.0004 1 1 -0.0077 0.0001 0.006 0.043 -0.00033
+1 -0.0001 1 1 0.0035 0.0023 0.008 0.013 0.00011
+1 -0.0003 1 1 0.0045 0.0014 0.007 0.029 -0.00001
+1 0.0001 1 1 -0.0041 0.0012 0.007 0.032 -0.00034
+1 0.0002 1 1 -0.0080 0.0012 0.006 0.022 -0.00020
+1 -0.0002 1 1 0.0078 0.0022 0.016 -0.024 0.00013
+1 -0.0001 1 1 0.0035 -0.0009 0.024 0.014 -0.00014
+1 -0.0001 1 1 -0.0043 -0.0023 0.017 0.011 -0.00012
+1 0.0001 1 1 -0.0065 -0.0026 0.013 0.004 -0.00012
+1 -0.0001 1 1 -0.0028 0.0020 0.015 -0.014 0.00012
+1 -0.0002 1 1 0.0053 0.0001 0.010 -0.005 0.00007
+1 -0.0001 1 1 0.0026 0.0008 0.012 0.010 -0.00010
+1 0.0002 1 1 -0.0047 0.0006 0.014 0.007 -0.00018
+1 -0.0001 1 1 0.0039 -0.0005 0.009 -0.009 0.00012
+1 -0.0002 1 1 0.0055 0.0004 0.009 -0.002 0.00008
+1 -0.0001 1 1 0.0030 0.0013 0.012 0.011 -0.00013
+1 0.0003 1 1 -0.0045 -0.0002 0.010 0.008 -0.00015
+1 -0.0002 1 1 -0.0015 0.0008 0.013 -0.009 0.00014
+1 -0.0002 1 1 0.0055 0.0015 0.011 -0.002 0.00018
+1 -0.0002 1 1 0.0064 0.0022 0.015 0.013 -0.00002
+1 0.0002 1 1 -0.0060 -0.0021 0.009 0.005 -0.00005
+1 -0.0002 1 1 0.0037 0.0012 0.005 -0.005 0.00015
+1 -0.0002 1 1 0.0037 -0.0024 0.010 0.013 0.00004
+1 0.0001 1 1 -0.0044 0.0025 0.002 0.007 -0.00002
+1 0.0001 1 1 -0.0007 0.0018 0.009 -0.009 0.00008
+1 -0.0002 1 1 0.0032 0.0017 0.014 -0.006 0.00011
+1 0.0002 1 1 -0.0055 -0.0004 0.013 -0.013 -0.00007
+1 -0.0001 1 1 0.0070 0.0003 0.013 -0.007 0.00006
+1 0.0001 1 1 -0.0057 -0.0009 0.008 0.007 -0.00010
+1 -0.0002 1 1 0.0056 -0.0003 0.008 -0.005 0.00015
+1 -0.0001 1 1 0.0054 0.0013 0.011 0.012 -0.00011
+1 0.0002 1 1 -0.0055 -0.0003 0.010 0.009 -0.00012
+1 -0.0001 1 1 0.0034 -0.0012 0.011 -0.008 0.00015
+1 0.0002 1 1 -0.0044 0.0037 0.004 0.008 -0.00010
+1 -0.0001 1 1 0.0061 -0.0004 0.013 0.006 0.00013
+1 -0.0001 1 1 0.0055 -0.0008 0.010 0.024 -0.00010
+1 0.0003 1 1 -0.0090 0.0022 0.005 0.019 -0.00029
+1 -0.0001 1 1 0.0050 -0.0014 0.009 -0.003 -0.00001
+1 0.0001 1 1 0.0008 0.0001 0.005 0.010 -0.00012
+1 -0.0002 1 1 0.0021 0.0006 0.009 0.010 0.00006
+1 0.0002 1 1 -0.0046 0.0012 0.011 0.003 -0.00008
+1 -0.0002 1 1 0.0049 0.0005 0.009 -0.001 0.00013
+1 -0.0001 1 1 0.0048 0.0028 0.011 0.010 -0.00007
+1 0.0003 1 1 -0.0073 -0.0006 0.013 0.002 -0.00014
+1 -0.0001 1 1 0.0051 -0.0014 0.003 -0.015 0.00019
+1 -0.0001 1 1 0.0073 0.0004 0.003 -0.005 0.00010
+1 -0.0002 1 1 0.0028 0.0013 0.007 0.010 -0.00018
+1 0.0001 1 1 -0.0077 0.0017 0.012 0.001 -0.00026
+1 0.0002 1 1 -0.0095 -0.0006 0.013 -0.014 0.00010
+1 -0.0003 1 1 0.0061 0.0003 0.003 -0.025 0.00021
+1 0.0001 1 1 -0.0030 -0.0011 0.017 -0.015 0.00010
+1 -0.0001 1 1 0.0064 -0.0023 0.006 -0.005 0.00012
+1 0.0001 1 1 -0.0033 0.0014 0.010 0.013 -0.00022
+1 0.0001 1 1 -0.0053 0.0012 0.011 0.007 -0.00009
+1 0.0001 1 1 -0.0048 0.0000 0.012 -0.010 0.00006
+1 -0.0001 1 1 0.0059 -0.0003 0.008 -0.004 0.00009
+1 0.0001 1 1 -0.0059 -0.0006 0.007 0.005 -0.00011
+1 0.0001 1 1 -0.0045 0.0000 0.006 -0.011 0.00009
+1 -0.0001 1 1 0.0052 0.0008 0.009 -0.007 0.00010
+1 -0.0001 1 1 0.0029 0.0011 0.013 0.010 -0.00009
+1 0.0003 1 1 -0.0047 0.0003 0.014 0.005 -0.00012
+1 -0.0001 1 1 0.0047 -0.0014 0.010 0.000 0.00016
+1 -0.0001 1 1 0.0063 -0.0003 0.008 0.020 0.00000
+1 -0.0001 1 1 0.0031 -0.0020 0.001 0.040 -0.00010
+1 0.0001 1 1 0.0005 0.0019 0.004 0.044 -0.00012
+1 0.0001 1 1 -0.0045 0.0040 0.014 0.037 -0.00009
+1 0.0001 1 1 -0.0049 0.0010 0.020 0.020 -0.00001
+1 -0.0002 1 1 0.0052 -0.0004 0.001 0.010 0.00010
+1 -0.0001 1 1 -0.0040 0.0014 0.012 0.016 -0.00008
+1 0.0002 1 1 -0.0078 -0.0008 0.013 -0.006 -0.00006
+1 -0.0002 1 1 0.0086 -0.0006 0.001 -0.005 0.00013
+1 -0.0001 1 1 0.0086 0.0017 0.001 0.013 -0.00007
+1 -0.0001 1 1 0.0034 0.0015 0.004 0.028 -0.00025
+1 0.0002 1 1 -0.0058 0.0016 0.009 0.024 -0.00024
+1 -0.0002 1 1 0.0057 0.0019 0.005 -0.006 0.00006
+1 -0.0001 1 1 0.0052 -0.0011 0.005 -0.002 0.00012
+1 0.0002 1 1 -0.0051 0.0014 0.014 0.006 -0.00009
+1 -0.0001 1 1 0.0071 -0.0001 0.006 0.014 0.00004
+1 -0.0001 1 1 0.0046 0.0003 0.007 0.028 -0.00016
+1 -0.0002 1 1 0.0037 0.0000 0.005 -0.008 0.00014
+1 0.0001 1 1 -0.0037 0.0013 0.009 -0.006 -0.00006
+1 0.0001 1 1 -0.0032 0.0004 0.010 -0.012 0.00009
+1 -0.0001 1 1 0.0053 0.0000 0.010 -0.005 0.00009
+1 0.0001 1 1 -0.0049 -0.0015 0.005 0.006 -0.00002
+1 -0.0002 1 1 0.0045 0.0010 0.005 0.012 0.00004
+1 0.0002 1 1 -0.0067 0.0007 0.008 0.004 -0.00011
+1 -0.0001 1 1 0.0061 0.0011 0.013 -0.005 0.00008
+1 -0.0001 1 1 0.0045 0.0005 0.014 0.010 -0.00010
+1 0.0001 1 1 -0.0053 -0.0012 0.006 0.006 -0.00011
+1 -0.0001 1 1 0.0046 -0.0039 0.016 -0.004 0.00010
+1 0.0001 1 1 -0.0037 0.0004 0.004 0.008 -0.00013
+1 -0.0001 1 1 0.0026 0.0013 0.011 -0.004 0.00007
+1 -0.0003 1 1 0.0053 0.0006 0.007 0.017 0.00001
+1 0.0003 1 1 -0.0112 0.0022 0.013 0.007 -0.00031
+1 0.0001 1 1 -0.0074 0.0004 0.013 -0.030 0.00027
+1 -0.0002 1 1 0.0088 -0.0010 0.008 -0.024 0.00021
+1 0.0002 1 1 -0.0071 -0.0018 -0.001 -0.001 -0.00007
+1 -0.0002 1 1 0.0091 -0.0045 0.016 0.014 0.00007
+1 -0.0002 1 1 0.0077 -0.0044 0.008 0.030 -0.00019
+1 0.0001 1 1 -0.0063 0.0014 0.007 0.030 -0.00016
+1 -0.0001 1 1 0.0026 0.0001 0.001 -0.005 0.00016
+1 -0.0001 1 1 0.0039 0.0004 0.001 0.000 0.00005
+1 -0.0001 1 1 0.0036 0.0025 0.008 0.012 -0.00003
+1 0.0002 1 1 -0.0049 -0.0003 0.014 0.005 -0.00007
+1 0.0001 1 1 -0.0006 -0.0006 0.010 -0.010 0.00011
+1 -0.0003 1 1 0.0045 0.0014 0.006 -0.005 0.00018
+1 -0.0001 1 1 0.0030 0.0004 0.008 0.011 0.00002
+1 0.0002 1 1 -0.0037 -0.0045 0.015 0.007 -0.00003
+1 -0.0003 1 1 0.0033 -0.0016 0.001 0.009 0.00003
+1 0.0003 1 1 -0.0069 0.0006 0.007 0.003 -0.00015
+1 0.0001 1 1 -0.0063 0.0008 0.007 -0.011 0.00017
+1 -0.0001 1 1 0.0076 0.0033 0.017 -0.004 0.00015
+1 -0.0001 1 1 0.0082 -0.0020 0.020 0.008 0.00000
+1 0.0001 1 1 0.0048 -0.0012 0.016 0.026 -0.00018
+1 0.0001 1 1 -0.0045 -0.0018 0.006 0.022 -0.00005
+1 0.0001 1 1 -0.0036 0.0008 0.008 0.006 -0.00005
+1 -0.0003 1 1 0.0046 -0.0015 0.010 0.012 0.00004
+1 -0.0001 1 1 -0.0044 -0.0006 0.013 0.014 -0.00025
+1 0.0004 1 1 -0.0088 -0.0007 0.011 0.003 -0.00022
+1 -0.0003 1 1 0.0056 0.0003 0.010 -0.024 0.00021
+1 -0.0001 1 1 0.0047 -0.0006 0.009 0.012 0.00007
+1 -0.0001 1 1 -0.0004 -0.0003 0.006 0.028 -0.00009
+1 0.0001 1 1 -0.0061 0.0000 0.006 0.013 -0.00009
+1 0.0001 1 1 -0.0039 0.0007 0.008 -0.011 0.00009
+1 -0.0001 1 1 0.0045 0.0007 0.007 -0.007 0.00007
+1 -0.0001 1 1 0.0021 0.0009 0.010 0.010 -0.00008
+1 0.0001 1 1 -0.0047 0.0000 0.012 0.004 -0.00007
+1 -0.0001 1 1 0.0038 0.0006 0.010 -0.007 0.00011
+1 -0.0001 1 1 0.0030 0.0008 0.012 0.010 -0.00005
+1 0.0002 1 1 -0.0037 0.0000 0.012 0.007 -0.00009
+1 -0.0002 1 1 0.0041 -0.0003 0.005 0.014 0.00001
+1 0.0001 1 1 -0.0063 0.0011 0.009 0.002 -0.00006
+1 -0.0002 1 1 0.0061 0.0001 0.014 -0.007 0.00015
+1 -0.0001 1 1 0.0051 0.0000 0.013 0.012 -0.00010
+1 0.0003 1 1 -0.0066 0.0003 0.012 0.008 -0.00016
+1 -0.0002 1 1 0.0085 -0.0006 0.006 0.004 0.00010
+1 -0.0001 1 1 0.0069 0.0019 0.008 0.023 -0.00013
+1 -0.0001 1 1 0.0042 0.0021 0.010 0.031 -0.00022
+1 0.0001 1 1 -0.0057 0.0001 0.021 0.029 -0.00025
+1 0.0002 1 1 -0.0102 -0.0019 0.015 -0.010 -0.00001
+1 -0.0001 1 1 0.0090 -0.0008 0.005 -0.020 0.00017
+1 -0.0003 1 1 0.0099 -0.0038 0.004 0.032 -0.00004
+1 -0.0001 1 1 0.0049 0.0000 0.005 0.047 -0.00035
+1 0.0004 1 1 -0.0093 -0.0003 0.003 0.040 -0.00040
+1 0.0002 1 1 -0.0057 0.0014 0.008 -0.021 -0.00003
+1 -0.0002 1 1 0.0073 0.0000 0.012 -0.021 0.00022
+1 -0.0001 1 1 0.0068 0.0003 0.014 0.018 -0.00013
+1 0.0001 1 1 0.0037 -0.0006 0.012 0.026 -0.00022
+1 -0.0001 1 1 0.0009 -0.0022 0.008 0.030 -0.00016
+1 0.0003 1 1 -0.0056 -0.0008 0.003 0.024 -0.00026
+1 -0.0001 1 1 0.0054 -0.0003 0.007 0.014 0.00003
+1 -0.0001 1 1 -0.0006 0.0002 0.007 0.027 -0.00017
+1 0.0002 1 1 -0.0042 0.0004 0.008 0.023 -0.00023
+1 0.0001 1 1 -0.0064 0.0000 0.012 -0.014 0.00004
+1 -0.0001 1 1 0.0053 0.0008 0.012 -0.020 0.00014
+1 0.0001 1 1 0.0002 -0.0007 0.009 0.009 -0.00010
+1 0.0001 1 1 -0.0021 0.0015 0.007 -0.011 0.00000
+1 -0.0002 1 1 0.0050 0.0007 0.012 -0.006 0.00018
+1 -0.0001 1 1 0.0036 -0.0007 0.012 0.010 -0.00008
+1 0.0002 1 1 -0.0052 -0.0006 0.008 0.005 -0.00011
+1 -0.0001 1 1 0.0055 -0.0004 0.006 -0.004 0.00014
+1 -0.0001 1 1 0.0059 0.0000 0.005 0.013 -0.00004
+1 -0.0001 1 1 0.0016 0.0002 0.006 0.028 -0.00014
+1 0.0001 1 1 -0.0045 0.0014 0.009 0.023 -0.00019
+1 -0.0002 1 1 0.0035 0.0013 0.003 0.012 0.00002
+1 0.0002 1 1 -0.0063 0.0015 0.009 0.004 -0.00011
+1 -0.0001 1 1 0.0078 -0.0003 0.007 0.007 0.00009
+1 -0.0001 1 1 0.0021 0.0005 0.007 0.030 -0.00024
+1 0.0002 1 1 -0.0069 0.0000 0.011 0.023 -0.00026
+1 0.0001 1 1 -0.0039 0.0000 0.013 -0.012 0.00016
+1 -0.0001 1 1 0.0063 -0.0016 0.006 -0.006 0.00017
+1 -0.0001 1 1 0.0072 0.0000 0.005 0.011 0.00000
+1 -0.0001 1 1 0.0045 0.0022 0.010 0.028 -0.00012
+1 -0.0005 1 1 0.0036 0.0019 0.026 -0.012 0.00036
+1 0.0011 1 1 -0.0039 0.0020 0.027 0.010 -0.00026
+1 -0.0004 1 1 0.0020 0.0020 0.023 0.011 -0.00005
+1 0.0011 1 1 -0.0041 -0.0008 0.023 0.007 -0.00019
+1 -0.0005 1 1 0.0057 0.0017 0.017 0.006 0.00028
+1 0.0002 1 1 -0.0048 0.0037 0.022 0.026 -0.00027
+1 -0.0012 1 1 0.0084 0.0027 0.018 0.012 0.00036
+1 -0.0002 1 1 0.0050 0.0040 0.022 0.030 -0.00041
+1 0.0009 1 1 -0.0055 0.0020 0.020 0.030 -0.00047
+1 -0.0004 1 1 0.0044 0.0030 0.020 0.012 0.00006
+1 0.0005 1 1 -0.0073 -0.0008 0.015 0.005 -0.00014
+1 0.0002 1 1 -0.0049 0.0003 0.009 -0.011 0.00019
+1 -0.0003 1 1 0.0054 0.0057 0.016 -0.011 0.00024
+1 -0.0003 1 1 0.0057 0.0036 0.022 0.011 -0.00006
+1 0.0005 1 1 -0.0035 0.0006 0.022 0.016 -0.00021
+1 0.0004 1 1 -0.0036 0.0029 0.015 0.007 -0.00005
+1 -0.0011 1 1 0.0057 0.0030 0.018 0.012 0.00010
+1 0.0015 1 1 -0.0124 0.0025 0.022 0.007 -0.00054
+1 -0.0006 1 1 0.0036 -0.0003 0.007 -0.024 0.00059
+1 -0.0003 1 1 0.0092 0.0044 0.012 0.006 -0.00001
+1 0.0009 1 1 -0.0038 -0.0004 0.018 0.027 -0.00029
+1 -0.0002 1 1 0.0044 0.0003 0.010 0.023 0.00022
+1 -0.0002 1 1 -0.0033 0.0022 0.028 0.034 -0.00009
+1 0.0002 1 1 -0.0068 0.0021 0.027 0.026 -0.00025
+1 0.0003 1 1 -0.0043 0.0006 0.020 0.007 -0.00016
+1 0.0003 1 1 -0.0058 0.0013 0.016 -0.015 -0.00015
+1 -0.0006 1 1 0.0134 0.0009 0.011 -0.003 0.00050
+1 -0.0004 1 1 0.0129 0.0027 0.011 0.030 -0.00046
+1 0.0001 1 1 -0.0059 0.0035 0.016 0.040 -0.00090
+1 0.0016 1 1 -0.0172 0.0009 0.016 0.023 -0.00071
+1 0.0001 1 1 -0.0048 -0.0003 0.007 -0.029 0.00081
+1 -0.0009 1 1 0.0116 0.0042 0.002 -0.022 0.00069
+1 -0.0003 1 1 0.0123 0.0064 0.012 0.014 -0.00016
+1 -0.0003 1 1 0.0053 0.0005 0.020 0.030 -0.00041
+1 -0.0001 1 1 -0.0053 0.0021 0.003 0.012 -0.00008
+1 0.0002 1 1 -0.0071 0.0031 0.007 0.003 -0.00013
+1 -0.0011 1 1 0.0089 0.0030 0.012 -0.002 0.00039
+1 0.0005 1 1 -0.0058 0.0006 0.007 0.005 -0.00013
+1 -0.0003 1 1 0.0041 0.0031 0.007 -0.002 0.00020
+1 -0.0001 1 1 0.0047 0.0046 0.014 0.012 -0.00005
+1 0.0001 1 1 -0.0057 0.0000 0.017 -0.001 -0.00004
+1 0.0003 1 1 -0.0058 -0.0012 0.010 -0.011 0.00001
+1 -0.0002 1 1 0.0083 0.0007 -0.001 -0.005 0.00019
+1 -0.0002 1 1 0.0092 0.0035 0.001 0.012 -0.00003
+1 0.0003 1 1 0.0013 0.0058 0.011 0.027 -0.00033
+1 -0.0009 1 1 0.0055 -0.0025 0.006 0.028 0.00029
+1 0.0001 1 1 -0.0011 0.0007 0.005 0.036 -0.00055
+1 0.0004 1 1 -0.0118 0.0070 0.010 0.015 -0.00030
+1 0.0002 1 1 -0.0087 0.0022 0.012 -0.013 0.00036
+1 -0.0001 1 1 0.0054 -0.0001 0.007 -0.019 0.00047
+1 -0.0002 1 1 0.0111 0.0030 0.010 -0.006 0.00029
+1 -0.0001 1 1 0.0119 0.0030 0.015 0.019 -0.00016
+1 0.0001 1 1 -0.0078 0.0023 0.019 0.035 -0.00037
+1 0.0003 1 1 -0.0111 0.0006 0.017 0.021 -0.00019
+1 -0.0005 1 1 0.0074 0.0015 0.005 -0.005 0.00038
+1 -0.0002 1 1 0.0057 0.0034 0.008 0.014 -0.00017
+1 0.0001 1 1 -0.0059 0.0037 0.016 0.014 -0.00026
+1 0.0003 1 1 -0.0082 0.0011 0.016 0.004 -0.00011
+1 -0.0004 1 1 0.0073 0.0048 0.006 -0.007 0.00038
+1 -0.0004 1 1 0.0068 0.0035 0.011 0.017 -0.00012
+1 0.0006 1 1 -0.0132 0.0018 0.016 0.005 -0.00040
+1 -0.0004 1 1 0.0044 -0.0003 0.007 -0.033 0.00064
+1 -0.0010 1 1 0.0118 0.0037 0.009 -0.007 0.00011
+1 0.0005 1 1 -0.0120 0.0003 0.012 -0.003 -0.00044
+1 0.0002 1 1 0.0043 0.0030 0.005 -0.018 0.00008
+1 -0.0003 1 1 0.0092 0.0025 0.006 -0.005 0.00025
+1 -0.0003 1 1 0.0088 0.0029 0.008 0.012 -0.00013
+1 0.0002 1 1 -0.0036 0.0036 0.014 0.023 -0.00041
+1 0.0001 1 1 -0.0072 0.0013 0.013 0.006 -0.00006
+1 0.0004 1 1 -0.0067 0.0024 0.013 -0.012 0.00005
+1 0.0002 1 1 -0.0038 0.0039 0.019 0.001 -0.00011
+1 0.0002 1 1 -0.0034 0.0043 0.002 -0.011 -0.00008
+1 -0.0004 1 1 0.0113 0.0001 0.008 0.019 0.00011
+1 -0.0004 1 1 0.0079 0.0035 0.009 0.040 -0.00037
+1 0.0011 1 1 -0.0094 0.0043 0.014 0.041 -0.00105
+1 -0.0003 1 1 0.0048 0.0068 0.004 0.003 0.00048
+1 -0.0001 1 1 0.0067 0.0062 0.011 0.017 -0.00025
+1 0.0003 1 1 -0.0043 0.0029 0.019 0.021 -0.00024
+1 -0.0006 1 1 0.0094 -0.0004 0.010 0.017 0.00035
+1 0.0002 1 1 0.0008 0.0021 0.011 0.039 -0.00056
+1 0.0001 1 1 -0.0044 0.0005 0.003 0.024 -0.00014
+1 -0.0002 1 1 0.0032 -0.0009 0.014 0.010 0.00007
+1 0.0004 1 1 -0.0052 0.0010 0.013 0.006 -0.00016
+1 0.0004 1 1 -0.0040 0.0020 0.005 -0.010 -0.00005
+1 -0.0006 1 1 0.0055 0.0024 0.006 -0.010 0.00023
+1 0.0001 1 1 -0.0055 0.0045 0.016 -0.003 -0.00034
+1 0.0008 1 1 -0.0096 0.0025 0.016 -0.019 -0.00014
+1 -0.0007 1 1 0.0092 0.0006 0.011 -0.029 0.00062
+1 0.0004 1 1 -0.0110 0.0016 0.012 0.007 -0.00037
+1 -0.0004 1 1 0.0095 0.0021 0.005 -0.020 0.00045
+1 -0.0002 1 1 0.0048 0.0020 0.013 0.025 0.00018
+1 -0.0003 1 1 0.0038 0.0009 0.014 0.034 -0.00015
+1 0.0005 1 1 -0.0081 0.0012 0.014 0.026 -0.00028
+1 -0.0003 1 1 0.0036 -0.0025 0.009 0.005 0.00043
+1 -0.0003 1 1 0.0026 0.0016 0.005 0.033 -0.00015
+1 0.0004 1 1 -0.0091 0.0031 0.009 0.025 -0.00039
+1 0.0006 1 1 -0.0077 0.0018 0.031 -0.003 -0.00001
+1 -0.0004 1 1 0.0017 0.0016 0.028 -0.020 0.00021
+1 0.0004 1 1 0.0026 0.0023 0.028 -0.016 -0.00003
+1 -0.0006 1 1 0.0057 -0.0002 0.022 -0.006 0.00012
+1 0.0003 1 1 -0.0034 0.0028 0.024 -0.011 -0.00002
+1 -0.0002 1 1 0.0058 -0.0007 0.017 -0.005 0.00010
+1 0.0004 1 1 -0.0066 0.0049 0.021 0.005 -0.00020
+1 -0.0002 1 1 -0.0027 0.0024 0.022 -0.011 0.00001
+1 -0.0003 1 1 0.0052 -0.0002 0.016 -0.014 0.00028
+1 -0.0001 1 1 0.0075 0.0005 0.014 -0.001 0.00001
+1 0.0002 1 1 -0.0054 0.0019 0.014 0.007 -0.00013
+1 0.0002 1 1 -0.0053 0.0022 0.015 -0.012 0.00004
+1 -0.0001 1 1 0.0039 0.0025 0.018 -0.017 0.00015
+1 0.0003 1 1 -0.0051 -0.0011 0.014 0.011 -0.00024
+1 0.0002 1 1 -0.0046 0.0001 0.006 -0.014 0.00007
+1 0.0001 1 1 0.0038 0.0048 0.016 -0.015 0.00009
+1 -0.0003 1 1 0.0056 0.0014 0.015 -0.006 0.00007
+1 0.0002 1 1 -0.0037 0.0028 0.021 0.006 -0.00025
+1 0.0002 1 1 -0.0022 0.0016 0.012 -0.011 -0.00002
+1 -0.0002 1 1 0.0037 0.0008 0.009 -0.005 0.00004
+1 0.0002 1 1 -0.0025 0.0007 0.012 -0.011 0.00002
+1 -0.0002 1 1 0.0044 0.0008 0.007 -0.005 0.00007
+1 -0.0001 1 1 0.0011 0.0023 0.011 0.010 -0.00009
+1 0.0003 1 1 -0.0034 0.0026 0.015 0.007 -0.00013
+1 -0.0001 1 1 0.0003 0.0022 0.010 0.009 -0.00004
+1 0.0001 1 1 -0.0055 0.0027 0.015 -0.002 -0.00011
+1 0.0001 1 1 -0.0031 0.0015 0.016 -0.018 0.00012
+1 -0.0002 1 1 0.0063 0.0005 0.010 -0.006 0.00010
+1 0.0004 1 1 -0.0044 -0.0030 0.011 0.009 -0.00012
+1 -0.0003 1 1 0.0050 0.0030 0.006 0.010 0.00013
+1 -0.0001 1 1 0.0008 0.0019 0.016 0.010 -0.00002
+1 -0.0004 1 1 0.0047 -0.0001 0.005 0.012 0.00008
+1 0.0003 1 1 -0.0082 0.0009 0.011 0.005 -0.00020
+1 -0.0003 1 1 0.0055 0.0023 0.006 -0.023 0.00028
+1 0.0005 1 1 -0.0033 0.0034 0.016 -0.002 -0.00034
+1 0.0001 1 1 -0.0033 0.0016 0.017 -0.013 0.00012
+1 -0.0005 1 1 0.0082 -0.0028 0.009 -0.004 0.00028
+1 0.0002 1 1 -0.0075 0.0041 0.002 0.003 -0.00020
+1 -0.0001 1 1 0.0086 -0.0004 0.009 -0.011 0.00028
+1 -0.0002 1 1 0.0097 0.0042 0.015 0.020 -0.00009
+1 -0.0002 1 1 0.0041 0.0044 0.022 0.033 -0.00037
+1 0.0005 1 1 -0.0116 -0.0043 0.016 0.014 -0.00025
+1 -0.0001 1 1 0.0047 0.0012 0.003 -0.013 0.00034
+1 -0.0002 1 1 0.0076 0.0019 0.004 -0.004 0.00014
+1 0.0003 1 1 -0.0071 0.0010 0.010 0.002 -0.00017
+1 0.0001 1 1 -0.0057 0.0013 0.010 -0.012 0.00018
+1 -0.0003 1 1 0.0063 0.0000 0.009 -0.013 0.00034
+1 0.0002 1 1 -0.0051 0.0009 0.006 0.006 -0.00012
+1 0.0002 1 1 -0.0036 0.0000 0.009 -0.010 0.00012
+1 -0.0002 1 1 0.0043 0.0010 0.008 -0.010 0.00029
+1 -0.0002 1 1 0.0062 0.0014 0.009 0.015 -0.00003
+1 -0.0002 1 1 0.0047 -0.0008 0.001 0.029 0.00007
+1 0.0001 1 1 -0.0061 0.0003 0.015 0.016 -0.00002
+1 -0.0003 1 1 0.0040 0.0025 0.008 0.012 -0.00001
+1 0.0002 1 1 -0.0070 0.0009 0.013 0.005 -0.00018
+1 0.0003 1 1 -0.0069 0.0008 0.012 -0.010 0.00008
+1 -0.0001 1 1 0.0072 -0.0006 0.002 -0.010 0.00024
+1 -0.0002 1 1 0.0097 0.0045 0.005 0.002 0.00012
+1 0.0005 1 1 -0.0039 0.0001 0.016 0.024 -0.00025
+1 -0.0001 1 1 0.0036 -0.0005 0.009 0.027 -0.00003
+1 0.0001 1 1 -0.0058 -0.0001 0.001 0.017 -0.00008
+1 0.0002 1 1 -0.0027 0.0037 0.015 -0.011 0.00008
+1 -0.0006 1 1 0.0067 0.0001 0.012 -0.006 0.00031
+1 0.0005 1 1 0.0014 0.0013 0.012 0.009 -0.00031
+1 -0.0001 1 1 0.0015 -0.0010 0.008 0.010 0.00016
+1 0.0004 1 1 -0.0047 0.0007 0.007 0.007 -0.00034
+1 0.0001 1 1 -0.0035 -0.0002 0.003 -0.011 0.00013
+1 -0.0002 1 1 0.0050 0.0023 0.005 -0.008 0.00022
+1 -0.0003 1 1 0.0044 0.0018 0.008 0.010 -0.00006
+1 0.0001 1 1 -0.0047 0.0043 0.017 0.011 -0.00033
+1 0.0004 1 1 -0.0083 0.0009 0.016 -0.001 -0.00014
+1 -0.0002 1 1 0.0086 -0.0010 0.004 -0.009 0.00040
+1 -0.0001 1 1 0.0107 0.0028 0.007 0.016 -0.00008
+1 -0.0003 1 1 0.0087 0.0027 0.009 0.030 -0.00017
+1 -0.0001 1 1 0.0008 -0.0017 0.005 0.036 0.00013
+1 -0.0001 1 1 -0.0034 0.0016 0.010 0.028 -0.00002
+1 -0.0001 1 1 0.0037 -0.0006 0.002 0.004 0.00021
+1 -0.0002 1 1 0.0054 0.0034 0.005 0.013 -0.00010
+1 0.0001 1 1 -0.0033 0.0042 0.015 0.017 -0.00028
+1 0.0002 1 1 -0.0061 0.0019 0.016 0.009 -0.00013
+1 0.0001 1 1 0.0003 0.0006 0.013 -0.009 0.00016
+1 -0.0004 1 1 0.0057 0.0003 0.011 -0.002 0.00021
+1 0.0002 1 1 -0.0051 0.0013 0.011 0.002 -0.00018
+1 -0.0002 1 1 0.0060 0.0036 0.005 -0.024 0.00031
+1 -0.0002 1 1 0.0081 0.0038 0.012 -0.004 0.00000
+1 -0.0002 1 1 0.0052 0.0005 0.014 0.013 -0.00011
+1 0.0001 1 1 -0.0035 0.0019 0.010 0.015 -0.00011
+1 0.0004 1 1 -0.0051 -0.0006 0.008 0.007 -0.00010
+1 -0.0002 1 1 0.0040 0.0008 0.010 0.013 0.00000
+1 -0.0001 1 1 -0.0039 -0.0008 0.002 0.010 -0.00005
+1 0.0002 1 1 -0.0050 0.0030 0.004 0.003 -0.00007
+1 -0.0003 1 1 0.0048 0.0024 0.017 -0.007 0.00027
+1 -0.0003 1 1 0.0029 -0.0001 0.010 0.029 -0.00009
+1 0.0001 1 1 -0.0044 0.0026 0.013 0.028 -0.00036
+1 -0.0001 1 1 0.0044 0.0019 -0.002 0.007 0.00007
+1 -0.0002 1 1 0.0040 0.0043 0.005 0.014 -0.00004
+1 0.0002 1 1 -0.0079 0.0024 0.015 0.003 -0.00018
+1 0.0004 1 1 -0.0077 0.0021 0.016 -0.011 0.00007
+1 -0.0001 1 1 0.0091 -0.0003 0.005 -0.003 0.00015
+1 -0.0002 1 1 0.0089 0.0030 0.008 0.018 -0.00006
+1 -0.0002 1 1 0.0057 0.0030 0.012 0.031 -0.00022
+1 0.0001 1 1 -0.0071 0.0013 0.015 0.027 -0.00025
+1 0.0001 1 1 -0.0090 -0.0027 0.011 0.015 -0.00007
+1 -0.0001 1 1 0.0052 0.0009 0.000 0.005 0.00012
+1 0.0001 1 1 -0.0065 0.0013 0.010 0.003 -0.00010
+1 0.0001 1 1 -0.0067 0.0003 0.008 -0.011 0.00002
+1 -0.0002 1 1 0.0080 0.0028 0.010 -0.006 0.00013
+1 -0.0003 1 1 0.0029 0.0002 0.012 0.029 -0.00015
+1 0.0004 1 1 -0.0062 0.0015 0.014 0.025 -0.00033
+1 0.0002 1 1 -0.0033 0.0022 0.016 -0.007 -0.00003
+1 -0.0002 1 1 0.0065 -0.0009 0.012 -0.002 0.00016
+1 -0.0001 1 1 0.0056 0.0009 0.012 0.010 -0.00012
+1 -0.0001 1 1 -0.0083 0.0000 0.008 0.007 -0.00030
+1 0.0001 1 1 -0.0127 0.0001 0.006 -0.007 -0.00029
+1 0.0001 1 1 -0.0057 0.0002 0.003 -0.038 0.00052
+1 -0.0002 1 1 0.0082 0.0022 0.003 -0.030 0.00021
+1 0.0005 1 1 -0.0039 0.0004 0.011 -0.010 -0.00014
+1 -0.0003 1 1 0.0078 0.0005 0.008 -0.006 0.00026
+1 -0.0004 1 1 0.0077 0.0011 0.007 0.014 -0.00009
+1 -0.0002 1 1 0.0028 -0.0010 0.004 0.028 -0.00002
+1 0.0001 1 1 -0.0048 0.0022 0.009 0.023 -0.00013
+1 0.0001 1 1 -0.0066 -0.0006 0.005 0.005 -0.00002
+1 -0.0003 1 1 0.0056 0.0029 0.008 -0.007 0.00016
+1 -0.0002 1 1 0.0006 0.0020 0.005 0.009 -0.00004
+1 0.0002 1 1 -0.0039 0.0037 0.011 0.006 -0.00023
+1 -0.0002 1 1 0.0028 0.0007 0.013 -0.007 0.00024
+1 -0.0002 1 1 0.0014 0.0002 0.003 0.009 -0.00002
+1 0.0004 1 1 -0.0047 0.0026 0.007 0.005 -0.00021
+1 -0.0002 1 1 0.0062 0.0002 0.011 0.006 0.00013
+1 -0.0002 1 1 0.0038 0.0002 0.008 0.029 -0.00010
+1 -0.0002 1 1 -0.0037 0.0013 0.010 -0.012 0.00006
+1 -0.0001 1 1 0.0098 0.0011 0.004 -0.006 0.00027
+1 -0.0001 1 1 0.0115 0.0032 0.006 0.010 -0.00001
+1 -0.0003 1 1 0.0088 0.0032 0.011 0.030 -0.00017
+1 0.0003 1 1 -0.0104 -0.0002 0.012 0.025 -0.00026
+1 -0.0001 1 1 0.0053 0.0011 0.014 0.015 -0.00001
+1 -0.0002 1 1 0.0015 0.0003 0.012 0.027 -0.00014
+1 0.0004 1 1 -0.0094 0.0018 0.011 -0.001 -0.00014
+1 -0.0003 1 1 0.0112 0.0027 0.012 -0.002 0.00024
+1 -0.0003 1 1 0.0052 0.0017 0.014 0.030 -0.00040
+1 0.0001 1 1 -0.0073 0.0015 0.015 0.029 -0.00066
+1 -0.0001 1 1 0.0042 0.0010 0.005 -0.021 0.00037
+1 0.0003 1 1 -0.0056 0.0056 0.006 -0.012 0.00008
+1 -0.0006 1 1 0.0047 0.0001 0.014 0.006 0.00013
+1 0.0005 1 1 -0.0091 0.0025 0.012 0.002 -0.00027
+1 -0.0004 1 1 0.0052 0.0032 0.015 -0.026 0.00030
+1 -0.0005 1 1 0.0056 -0.0003 0.014 0.010 0.00014
+1 0.0002 1 1 -0.0057 0.0008 0.008 0.014 -0.00023
+1 0.0001 1 1 -0.0078 0.0020 0.007 -0.003 -0.00003
+1 -0.0003 1 1 0.0054 0.0040 0.013 -0.025 0.00025
+1 -0.0001 1 1 0.0041 0.0014 0.019 0.011 -0.00016
+1 0.0001 1 1 -0.0047 0.0011 0.019 0.011 -0.00034
+1 0.0008 1 1 -0.0108 0.0004 0.015 -0.007 -0.00022
+1 -0.0004 1 1 0.0093 0.0011 0.006 -0.017 0.00036
+1 -0.0002 1 1 0.0041 0.0045 0.011 0.025 -0.00027
+1 0.0005 1 1 -0.0037 0.0027 0.014 0.026 -0.00036
+1 -0.0004 1 1 0.0045 0.0012 0.011 0.010 0.00019
+1 0.0003 1 1 -0.0075 0.0014 0.007 0.004 -0.00012
+1 0.0002 1 1 -0.0046 0.0022 0.007 -0.013 0.00018
+1 -0.0004 1 1 0.0073 0.0031 0.010 -0.007 0.00020
+1 0.0002 1 1 -0.0051 0.0017 0.009 0.007 -0.00010
+1 -0.0003 1 1 0.0033 0.0026 0.008 -0.006 0.00021
+1 -0.0005 1 1 0.0061 0.0012 0.011 0.010 0.00009
+1 0.0005 1 1 -0.0101 0.0014 0.012 0.006 -0.00031
+1 -0.0005 1 1 0.0048 0.0011 0.008 -0.026 0.00048
+1 0.0002 1 1 -0.0039 0.0033 0.015 -0.005 -0.00005
+1 0.0003 1 1 -0.0024 0.0016 0.013 -0.011 0.00013
+1 -0.0003 1 1 0.0089 0.0014 0.011 -0.001 0.00032
+1 -0.0001 1 1 0.0068 0.0013 0.011 0.030 -0.00020
+1 0.0001 1 1 -0.0050 -0.0001 0.010 0.034 -0.00029
+1 0.0001 1 1 -0.0078 0.0013 0.010 0.020 -0.00009
+1 -0.0004 1 1 0.0073 0.0010 0.006 -0.004 0.00028
+1 -0.0003 1 1 0.0063 0.0018 0.005 0.014 -0.00016
+1 0.0004 1 1 -0.0111 0.0025 0.009 0.005 -0.00035
+1 0.0002 1 1 -0.0012 0.0006 0.027 -0.014 0.00027
+1 -0.0013 1 1 0.0069 -0.0006 0.020 -0.008 0.00032
+1 0.0004 1 1 -0.0143 0.0037 0.017 0.005 -0.00004
+1 0.0006 1 1 -0.0118 0.0038 0.015 0.004 -0.00010
+1 -0.0007 1 1 0.0120 0.0021 0.019 -0.010 0.00035
+1 -0.0003 1 1 0.0093 -0.0016 0.020 0.031 -0.00018
+1 0.0002 1 1 -0.0062 0.0010 0.014 0.038 -0.00033
+1 0.0002 1 1 -0.0095 0.0033 0.016 0.025 -0.00014
+1 0.0003 1 1 -0.0063 0.0034 0.020 -0.013 0.00026
+1 -0.0003 1 1 0.0055 0.0009 0.015 -0.015 0.00045
+1 -0.0004 1 1 0.0069 0.0033 0.017 0.016 -0.00013
+1 0.0001 1 1 -0.0065 0.0033 0.023 0.018 -0.00034
+1 0.0004 1 1 -0.0099 0.0022 0.023 0.006 -0.00019
+1 -0.0004 1 1 0.0064 0.0030 0.015 0.015 0.00001
+1 0.0009 1 1 -0.0125 0.0015 0.014 0.003 -0.00030
+1 -0.0005 1 1 0.0079 0.0035 0.005 -0.021 0.00052
+1 -0.0004 1 1 0.0116 0.0045 0.010 0.004 0.00003
+1 -0.0003 1 1 0.0049 0.0048 0.021 0.028 -0.00027
+1 0.0001 1 1 -0.0045 -0.0034 0.010 0.026 -0.00012
+1 -0.0004 1 1 0.0044 0.0071 0.005 0.029 0.00008
+1 0.0003 1 1 -0.0070 0.0002 0.013 0.003 -0.00004
+1 -0.0001 1 1 0.0052 0.0050 0.018 -0.009 0.00030
+1 -0.0004 1 1 0.0087 0.0020 0.018 0.001 0.00022
+1 -0.0001 1 1 0.0072 0.0016 0.018 0.016 -0.00020
+1 0.0001 1 1 -0.0066 0.0003 0.010 0.017 -0.00026
+1 0.0002 1 1 -0.0099 0.0019 0.010 0.002 -0.00013
+1 -0.0003 1 1 0.0109 0.0002 0.012 -0.020 0.00036
+1 -0.0005 1 1 0.0135 0.0006 0.009 0.011 0.00001
+1 -0.0003 1 1 0.0080 0.0026 0.011 0.029 -0.00047
+1 0.0007 1 1 -0.0079 -0.0056 0.015 0.029 -0.00045
+1 -0.0004 1 1 0.0072 0.0053 0.014 -0.002 0.00022
+1 0.0002 1 1 -0.0045 0.0015 0.018 0.015 -0.00035
+1 0.0002 1 1 -0.0076 -0.0003 0.014 0.005 -0.00011
+1 -0.0004 1 1 0.0066 0.0030 0.005 0.012 0.00008
+1 0.0001 1 1 -0.0067 0.0021 0.005 -0.003 -0.00008
+1 0.0004 1 1 -0.0070 0.0037 0.008 -0.014 0.00001
+1 -0.0002 1 1 0.0101 0.0034 0.013 -0.009 0.00033
+1 -0.0001 1 1 0.0109 0.0032 0.011 0.011 -0.00025
+1 -0.0001 1 1 -0.0052 0.0018 0.012 0.023 -0.00034
+1 0.0004 1 1 -0.0103 0.0032 0.015 0.010 -0.00028
+1 0.0002 1 1 -0.0094 -0.0006 0.013 -0.011 0.00026
+1 -0.0002 1 1 0.0041 0.0021 0.007 -0.021 0.00031
+1 -0.0001 1 1 0.0087 0.0034 0.009 0.003 0.00006
+1 -0.0002 1 1 0.0043 0.0035 0.017 0.032 -0.00015
+1 0.0003 1 1 -0.0101 0.0001 0.014 0.012 -0.00017
+1 0.0002 1 1 -0.0081 -0.0002 0.008 -0.012 0.00018
+1 -0.0003 1 1 0.0050 0.0012 0.003 -0.019 0.00035
+1 0.0009 1 1 -0.0157 0.0024 0.019 -0.008 -0.00044
+1 0.0009 1 1 -0.0056 0.0019 0.018 -0.029 -0.00038
+1 0.0001 1 1 0.0035 0.0005 0.013 -0.037 0.00052
+1 -0.0005 1 1 0.0118 -0.0015 0.006 -0.023 0.00039
+1 -0.0003 1 1 0.0085 0.0015 0.003 0.012 -0.00026
+1 0.0002 1 1 -0.0052 0.0050 0.009 0.018 -0.00041
+1 0.0003 1 1 -0.0098 0.0028 0.010 0.005 -0.00021
+1 0.0003 1 1 -0.0082 0.0017 0.009 -0.010 0.00020
+1 -0.0003 1 1 0.0082 -0.0004 0.010 -0.012 0.00035
+1 0.0008 1 1 -0.0070 0.0008 0.010 0.006 -0.00038
+1 -0.0005 1 1 0.0058 0.0012 0.005 -0.005 0.00034
+1 -0.0002 1 1 0.0029 0.0023 0.008 0.010 -0.00015
+1 0.0003 1 1 -0.0065 0.0035 0.013 0.006 -0.00036
+1 0.0002 1 1 -0.0074 -0.0026 0.015 -0.012 0.00020
+1 -0.0003 1 1 0.0063 -0.0008 0.006 -0.015 0.00034
+1 -0.0004 1 1 0.0086 0.0025 0.002 0.011 0.00002
+1 0.0001 1 1 -0.0066 0.0025 0.012 0.017 -0.00013
+1 0.0001 1 1 -0.0075 0.0023 0.012 0.003 -0.00001
+1 0.0003 1 1 -0.0059 0.0014 0.011 -0.011 0.00011
+1 -0.0003 1 1 0.0052 0.0016 0.009 -0.014 0.00037
+1 -0.0002 1 1 0.0062 0.0031 0.014 0.011 -0.00005
+1 0.0004 1 1 -0.0052 -0.0017 0.007 0.014 -0.00022
+1 0.0004 1 1 -0.0044 0.0035 0.015 0.005 -0.00013
+1 -0.0004 1 1 0.0078 0.0007 0.012 0.009 0.00023
+1 -0.0003 1 1 0.0039 0.0014 0.011 0.029 -0.00022
+1 0.0009 1 1 -0.0093 0.0021 0.012 0.023 -0.00047
+1 -0.0002 1 1 0.0070 0.0030 0.008 0.012 0.00008
+1 0.0007 1 1 -0.0113 0.0015 0.015 0.014 -0.00041
+1 0.0001 1 1 -0.0056 -0.0021 0.010 -0.011 0.00053
+1 -0.0007 1 1 0.0065 -0.0017 0.002 -0.010 0.00059
+1 -0.0007 1 1 0.0070 0.0048 0.006 0.011 -0.00022
+1 0.0010 1 1 -0.0054 0.0056 0.013 0.015 -0.00094
+1 -0.0001 1 1 0.0077 0.0032 0.009 0.001 0.00004
+1 -0.0005 1 1 0.0063 0.0033 0.012 0.012 -0.00013
+1 0.0006 1 1 -0.0050 0.0010 0.012 0.016 -0.00046
+1 0.0002 1 1 -0.0057 0.0028 0.012 -0.017 -0.00004
+1 -0.0003 1 1 0.0048 0.0003 0.008 -0.025 0.00031
+1 0.0003 1 1 -0.0058 0.0030 0.010 0.000 -0.00026
+1 0.0001 1 1 -0.0062 0.0026 0.011 -0.014 0.00010
+1 -0.0003 1 1 0.0061 0.0018 0.008 -0.015 0.00030
+1 0.0007 1 1 -0.0079 0.0000 0.017 0.007 -0.00041
+1 -0.0001 1 1 0.0056 -0.0019 0.001 -0.009 0.00039
+1 -0.0001 1 1 0.0095 0.0014 0.001 0.001 0.00022
+1 -0.0001 1 1 0.0070 0.0032 0.004 0.015 -0.00023
+1 0.0001 1 1 -0.0069 -0.0001 -0.001 0.000 -0.00004
+1 -0.0005 1 1 0.0068 0.0031 0.014 -0.009 0.00025
+1 -0.0002 1 1 0.0047 0.0028 0.016 0.013 -0.00013
+1 0.0001 1 1 -0.0050 0.0029 0.011 0.010 -0.00015
+1 -0.0001 1 1 0.0043 0.0030 0.019 -0.001 0.00014
+1 -0.0003 1 1 0.0058 0.0023 0.017 0.010 0.00003
+1 -0.0001 1 1 0.0039 0.0027 0.017 0.018 -0.00019
+1 0.0005 1 1 -0.0089 0.0024 0.015 0.006 -0.00023
+1 0.0003 1 1 -0.0075 0.0031 0.014 -0.014 0.00017
+1 -0.0005 1 1 0.0096 0.0035 0.014 -0.006 0.00019
+1 -0.0004 1 1 0.0082 0.0041 0.016 0.011 -0.00020
+1 0.0012 1 1 -0.0115 0.0024 0.017 0.002 -0.00033
+1 -0.0002 1 1 0.0092 0.0020 0.008 -0.019 0.00054
+1 -0.0004 1 1 0.0153 0.0013 0.007 0.007 0.00013
+1 -0.0005 1 1 0.0070 0.0059 0.014 0.045 -0.00052
+1 0.0002 1 1 -0.0094 0.0063 0.023 0.043 -0.00077
+1 -0.0012 1 1 0.0102 -0.0003 0.014 -0.002 0.00047
+1 0.0001 1 1 0.0057 0.0043 0.017 0.027 -0.00046
+1 0.0009 1 1 -0.0100 0.0025 0.018 0.022 -0.00058
+1 -0.0007 1 1 0.0086 0.0011 0.007 -0.006 0.00033
+1 -0.0001 1 1 0.0068 0.0010 0.004 0.013 -0.00025
+1 -0.0001 1 1 -0.0055 0.0031 0.004 0.016 -0.00048
+1 0.0011 1 1 -0.0127 0.0056 0.010 0.001 -0.00040
+1 -0.0005 1 1 0.0113 0.0030 0.013 -0.017 0.00041
+1 -0.0002 1 1 0.0115 0.0032 0.016 0.010 -0.00019
+1 -0.0001 1 1 0.0047 0.0022 0.016 0.029 -0.00033
+1 0.0001 1 1 -0.0057 0.0013 0.013 0.027 -0.00035
+1 -0.0006 1 1 0.0067 0.0027 0.007 0.012 0.00023
+1 -0.0001 1 1 -0.0015 0.0042 0.009 0.027 -0.00035
+1 0.0002 1 1 -0.0080 0.0041 0.012 0.020 -0.00047
+1 0.0001 1 1 0.0047 0.0038 0.019 -0.012 0.00018
+1 -0.0001 1 1 0.0073 0.0023 0.018 0.001 0.00000
+1 -0.0004 1 1 -0.0010 0.0057 0.006 0.027 -0.00008
+1 -0.0002 1 1 -0.0080 0.0063 0.014 0.012 -0.00015
+1 0.0006 1 1 -0.0112 -0.0018 0.018 -0.008 -0.00001
+1 -0.0002 1 1 0.0075 0.0002 0.007 -0.023 0.00045
+1 0.0003 1 1 -0.0115 0.0031 0.031 0.002 -0.00001
+1 0.0002 1 1 -0.0046 -0.0009 0.037 -0.034 0.00024
+1 -0.0004 1 1 0.0092 0.0000 0.029 -0.023 0.00022
+1 0.0005 1 1 -0.0081 0.0006 0.015 0.006 -0.00025
+1 0.0003 1 1 -0.0088 0.0023 0.015 -0.012 0.00008
+1 -0.0003 1 1 0.0058 0.0024 0.020 -0.023 0.00013
+1 0.0001 1 1 -0.0020 0.0022 0.019 -0.011 0.00006
+1 -0.0005 1 1 0.0077 0.0044 0.014 0.001 0.00012
+1 0.0004 1 1 -0.0070 0.0033 0.028 0.005 -0.00012
+1 -0.0005 1 1 0.0094 -0.0023 0.018 0.001 0.00019
+1 -0.0003 1 1 0.0026 -0.0015 0.007 0.028 -0.00026
+1 0.0006 1 1 -0.0053 -0.0002 0.005 0.026 -0.00042
+1 0.0003 1 1 -0.0074 0.0036 0.012 -0.014 0.00006
+1 -0.0004 1 1 0.0040 0.0040 0.016 -0.025 0.00026
+1 0.0001 1 1 0.0025 0.0046 0.027 -0.010 -0.00010
+1 -0.0003 1 1 0.0017 0.0017 0.029 -0.007 -0.00003
+1 0.0009 1 1 -0.0049 -0.0017 0.025 -0.012 -0.00020
+1 -0.0001 1 1 0.0092 -0.0030 0.007 -0.011 0.00038
+1 -0.0004 1 1 0.0127 -0.0010 0.005 0.005 0.00012
+1 -0.0002 1 1 0.0084 0.0016 0.006 0.030 -0.00035
+1 0.0001 1 1 -0.0005 0.0019 0.008 0.039 -0.00046
+1 0.0006 1 1 -0.0094 0.0033 0.013 0.026 -0.00030
+1 -0.0004 1 1 0.0075 0.0016 0.013 -0.007 0.00035
+1 -0.0003 1 1 0.0090 0.0015 0.014 0.016 -0.00005
+1 0.0001 1 1 -0.0045 0.0022 0.020 0.029 -0.00025
+1 -0.0001 1 1 0.0057 -0.0017 0.014 0.007 0.00021
+1 0.0001 1 1 0.0060 0.0001 0.010 0.017 -0.00020
+1 0.0004 1 1 -0.0039 0.0000 0.015 0.005 -0.00007
+1 -0.0001 1 1 0.0040 0.0015 0.015 0.002 0.00024
+1 0.0001 1 1 0.0058 0.0018 0.016 0.010 0.00006
+1 -0.0003 1 1 0.0072 -0.0006 0.013 0.019 0.00009
+1 -0.0002 1 1 0.0047 0.0004 0.012 0.031 -0.00028
+1 0.0007 1 1 -0.0074 0.0021 0.015 0.028 -0.00050
+1 -0.0006 1 1 0.0055 -0.0030 0.011 -0.006 0.00031
+1 0.0005 1 1 -0.0063 0.0008 0.008 0.002 -0.00034
+1 0.0001 1 1 -0.0070 0.0001 0.006 -0.012 0.00015
+1 -0.0001 1 1 0.0073 0.0008 0.004 -0.011 0.00029
+1 -0.0004 1 1 0.0103 0.0026 0.007 0.001 0.00017
+1 0.0006 1 1 -0.0089 0.0015 0.018 0.010 -0.00030
+1 -0.0003 1 1 0.0051 -0.0028 0.010 -0.015 0.00041
+1 -0.0003 1 1 0.0086 0.0007 0.008 0.010 0.00002
+1 0.0001 1 1 0.0039 0.0013 0.009 0.026 -0.00030
+1 -0.0002 1 1 0.0006 -0.0008 0.007 0.029 -0.00021
+1 0.0004 1 1 -0.0077 -0.0002 0.004 0.019 -0.00027
+1 0.0001 1 1 0.0061 0.0006 0.015 -0.015 0.00016
+1 -0.0004 1 1 0.0099 -0.0012 0.010 -0.001 0.00020
+1 0.0004 1 1 -0.0060 0.0023 0.012 0.021 -0.00074
+1 0.0002 1 1 -0.0136 0.0037 0.017 -0.001 -0.00021
+1 0.0002 1 1 -0.0084 0.0028 0.021 -0.031 0.00038
+1 -0.0003 1 1 0.0110 -0.0023 0.016 -0.027 0.00049
+1 -0.0005 1 1 0.0146 -0.0019 0.011 0.018 -0.00002
+1 0.0009 1 1 -0.0099 0.0013 0.012 0.037 -0.00067
+1 -0.0002 1 1 0.0041 0.0015 0.008 0.019 -0.00006
+1 0.0003 1 1 -0.0066 0.0001 0.005 0.004 -0.00007
+1 -0.0005 1 1 0.0044 0.0017 0.005 -0.008 0.00023
+1 0.0001 1 1 -0.0043 0.0030 0.010 -0.002 -0.00039
+1 0.0007 1 1 -0.0099 0.0013 0.010 -0.015 -0.00020
+1 -0.0005 1 1 0.0060 0.0013 0.009 -0.031 0.00055
+1 -0.0003 1 1 0.0064 0.0015 0.011 0.013 -0.00013
+1 0.0008 1 1 -0.0068 0.0013 0.013 0.015 -0.00049
+1 -0.0004 1 1 0.0056 0.0003 0.008 0.010 0.00016
+1 0.0002 1 1 -0.0077 0.0012 0.010 0.002 -0.00008
+1 0.0002 1 1 -0.0062 0.0018 0.011 -0.012 0.00013
+1 -0.0001 1 1 0.0057 0.0004 0.007 -0.015 0.00028
+1 -0.0003 1 1 0.0070 0.0019 0.011 0.013 -0.00003
+1 0.0001 1 1 -0.0081 0.0009 0.016 0.014 -0.00032
+1 0.0003 1 1 -0.0118 -0.0010 0.013 -0.001 -0.00022
+1 -0.0004 1 1 0.0050 -0.0001 0.005 -0.025 0.00048
+1 -0.0003 1 1 0.0035 -0.0001 0.007 0.011 0.00008
+1 0.0001 1 1 -0.0053 -0.0011 0.006 0.006 -0.00008
+1 0.0004 1 1 -0.0022 0.0014 0.004 -0.011 -0.00001
+1 -0.0001 1 1 0.0038 0.0039 0.009 -0.011 0.00030
+1 -0.0002 1 1 0.0003 0.0003 0.012 0.010 -0.00015
+1 0.0004 1 1 -0.0039 0.0007 0.012 0.007 -0.00026
+1 0.0002 1 1 -0.0030 0.0004 0.005 -0.011 -0.00006
+1 -0.0004 1 1 0.0076 0.0025 0.008 -0.002 0.00021
+1 -0.0004 1 1 0.0051 0.0024 0.011 0.013 -0.00020
+1 0.0008 1 1 -0.0092 0.0011 0.014 0.009 -0.00055
+1 -0.0003 1 1 0.0104 0.0028 0.010 -0.006 0.00020
+1 0.0001 1 1 0.0099 0.0038 0.015 0.010 -0.00013
+1 -0.0002 1 1 0.0082 0.0009 0.016 0.023 -0.00012
+1 0.0005 1 1 -0.0084 -0.0018 0.014 0.027 -0.00041
+1 -0.0003 1 1 0.0059 -0.0005 0.002 0.003 0.00035
+1 -0.0001 1 1 0.0087 -0.0003 0.000 0.016 0.00007
+1 -0.0002 1 1 0.0067 0.0019 0.002 0.033 -0.00015
+1 0.0003 1 1 -0.0072 0.0029 0.013 0.007 -0.00026
+1 -0.0002 1 1 0.0100 0.0008 0.015 -0.007 0.00023
+1 -0.0002 1 1 0.0107 -0.0005 0.012 0.010 -0.00002
+1 -0.0003 1 1 0.0022 0.0008 0.012 0.028 -0.00035
+1 0.0006 1 1 -0.0076 0.0059 0.011 0.024 -0.00064
+1 0.0004 1 1 -0.0086 -0.0025 0.014 -0.010 0.00017
+1 -0.0003 1 1 0.0047 -0.0005 0.008 -0.018 0.00043
+1 -0.0004 1 1 0.0092 -0.0008 0.004 -0.001 0.00009
+1 0.0001 1 1 -0.0053 0.0025 0.008 0.003 -0.00005
+1 0.0003 1 1 -0.0048 0.0034 0.015 -0.012 0.00005
+1 -0.0006 1 1 0.0092 0.0000 0.014 -0.005 0.00032
+1 -0.0001 1 1 0.0052 0.0000 0.014 0.016 -0.00032
+1 0.0001 1 1 -0.0033 0.0058 0.015 0.011 -0.00026
+1 -0.0002 1 1 0.0069 -0.0005 0.005 0.019 0.00002
+1 -0.0001 1 1 0.0047 0.0018 0.007 0.031 -0.00020
+1 0.0001 1 1 -0.0055 0.0008 0.009 0.027 -0.00018
+1 0.0001 1 1 -0.0054 0.0004 0.015 -0.003 -0.00002
+1 0.0002 1 1 -0.0048 0.0006 0.014 -0.011 0.00007
+1 -0.0002 1 1 0.0039 -0.0001 0.010 -0.014 0.00030
+1 -0.0002 1 1 0.0067 0.0003 0.007 0.012 0.00000
+1 0.0003 1 1 -0.0084 0.0018 0.012 0.005 -0.00016
+1 -0.0004 1 1 0.0099 0.0001 0.010 -0.004 0.00022
+1 0.0003 1 1 -0.0056 0.0000 0.010 0.015 -0.00026
+1 0.0001 1 1 -0.0029 0.0004 0.007 -0.011 0.00012
+1 -0.0003 1 1 0.0042 0.0012 0.006 -0.007 0.00012
+1 0.0001 1 1 -0.0041 0.0032 0.013 -0.002 -0.00033
+1 0.0001 1 1 -0.0067 0.0004 0.013 -0.014 0.00010
+1 -0.0002 1 1 0.0040 0.0002 0.010 -0.021 0.00023
+1 0.0004 1 1 -0.0043 0.0009 0.008 -0.012 -0.00012
+1 -0.0004 1 1 0.0075 0.0031 0.003 -0.009 0.00024
+1 -0.0003 1 1 0.0027 0.0039 0.012 0.010 -0.00027
+1 0.0004 1 1 -0.0079 0.0011 0.016 0.004 -0.00037
+1 0.0004 1 1 -0.0051 0.0002 0.011 -0.028 -0.00005
+1 -0.0002 1 1 0.0074 0.0000 0.006 -0.027 0.00032
+1 -0.0002 1 1 0.0101 0.0004 0.004 -0.004 0.00002
+1 -0.0003 1 1 0.0067 0.0015 0.005 0.012 -0.00027
+1 0.0006 1 1 -0.0094 -0.0001 0.009 0.007 -0.00035
+1 -0.0002 1 1 0.0086 0.0011 0.002 0.016 0.00001
+1 -0.0001 1 1 0.0060 0.0016 0.003 0.029 -0.00019
+1 0.0002 1 1 -0.0072 0.0018 0.009 0.024 -0.00017
+1 -0.0002 1 1 0.0039 0.0001 0.008 -0.011 0.00024
+1 -0.0005 1 1 0.0009 0.0015 0.012 0.009 0.00003
+1 0.0005 1 1 -0.0078 0.0007 0.015 0.003 -0.00045
+1 0.0001 1 1 -0.0085 0.0013 0.016 -0.011 0.00015
+1 -0.0002 1 1 0.0054 -0.0007 0.006 -0.021 0.00023
+1 0.0003 1 1 -0.0043 0.0033 0.006 0.014 -0.00031
+1 -0.0002 1 1 0.0085 0.0000 0.008 0.012 0.00018
+1 -0.0001 1 1 0.0051 0.0005 0.008 0.034 -0.00019
+1 0.0003 1 1 -0.0093 -0.0029 0.012 0.025 -0.00025
+1 -0.0001 1 1 -0.0016 0.0020 0.015 -0.009 0.00004
+1 -0.0002 1 1 0.0067 0.0027 0.011 0.004 0.00010
+1 0.0002 1 1 -0.0050 0.0001 0.017 0.022 -0.00009
+1 -0.0002 1 1 0.0053 0.0006 0.007 0.014 0.00007
+1 -0.0001 1 1 -0.0003 0.0010 0.010 0.031 -0.00012
+1 0.0001 1 1 -0.0049 0.0013 0.012 0.022 -0.00012
+1 -0.0002 1 1 0.0041 -0.0004 0.012 0.011 0.00001
+1 0.0001 1 1 -0.0045 0.0006 0.002 0.003 -0.00002
+1 -0.0001 1 1 0.0034 0.0017 0.008 -0.006 0.00009
+1 -0.0002 1 1 0.0012 0.0006 -0.002 0.010 -0.00004
+1 0.0002 1 1 -0.0046 0.0025 0.002 0.004 -0.00015
+1 0.0001 1 1 -0.0032 0.0009 0.005 -0.011 0.00009
+1 -0.0001 1 1 0.0036 0.0021 0.013 -0.010 0.00009
+1 -0.0001 1 1 0.0020 0.0001 0.016 0.010 0.00000
+1 0.0003 1 1 -0.0052 0.0007 0.011 0.008 -0.00016
+1 -0.0001 1 1 0.0046 0.0020 0.007 -0.003 0.00009
+1 0.0002 1 1 -0.0048 0.0013 0.017 0.002 -0.00005
+1 -0.0001 1 1 0.0061 0.0000 0.004 0.012 0.00004
+1 -0.0001 1 1 0.0012 0.0005 0.005 0.031 -0.00013
+1 0.0001 1 1 -0.0046 0.0007 0.006 0.024 -0.00013
+1 -0.0001 1 1 0.0060 0.0003 0.008 -0.003 0.00013
+1 0.0001 1 1 -0.0043 0.0009 0.010 0.003 -0.00006
+1 -0.0001 1 1 0.0047 0.0003 0.008 -0.006 0.00011
+1 0.0001 1 1 -0.0044 0.0007 0.014 0.007 -0.00002
+1 -0.0002 1 1 0.0041 0.0005 0.007 0.012 0.00001
+1 0.0001 1 1 -0.0065 -0.0001 0.007 0.000 -0.00002
+1 0.0001 1 1 -0.0027 -0.0002 0.003 -0.021 0.00012
+1 -0.0003 1 1 0.0058 0.0007 0.003 -0.006 0.00006
+1 0.0002 1 1 -0.0061 0.0012 0.015 -0.012 0.00000
+1 -0.0001 1 1 0.0046 -0.0012 0.010 -0.010 0.00001
+1 0.0001 1 1 -0.0016 0.0019 0.013 -0.010 0.00002
+1 -0.0002 1 1 0.0057 0.0016 0.014 0.013 -0.00001
+1 0.0001 1 1 -0.0059 -0.0010 0.006 0.004 -0.00003
+1 0.0001 1 1 -0.0013 -0.0004 0.002 -0.009 0.00015
+1 -0.0002 1 1 0.0056 0.0009 0.002 -0.001 0.00015
+1 -0.0002 1 1 0.0038 -0.0004 0.011 0.015 0.00005
+1 -0.0002 1 1 0.0054 -0.0004 0.003 0.013 0.00005
+1 0.0001 1 1 -0.0062 0.0011 0.010 0.006 -0.00005
+1 -0.0001 1 1 0.0078 0.0027 0.004 0.001 0.00016
+1 -0.0001 1 1 0.0082 0.0027 0.008 0.014 -0.00004
+1 -0.0001 1 1 0.0003 -0.0015 0.005 0.038 0.00003
+1 0.0001 1 1 -0.0043 0.0029 0.016 0.024 -0.00005
+1 -0.0002 1 1 0.0037 0.0005 -0.004 0.012 0.00006
+1 0.0001 1 1 -0.0045 0.0033 0.009 0.010 -0.00010
+1 -0.0001 1 1 0.0058 0.0007 0.014 0.015 0.00003
+1 -0.0001 1 1 0.0046 0.0008 0.009 0.012 0.00005
+1 -0.0002 1 1 0.0040 0.0018 0.008 0.011 0.00005
+1 0.0002 1 1 -0.0046 0.0002 0.015 0.006 -0.00006
+1 -0.0002 1 1 0.0058 0.0000 0.001 0.014 0.00004
+1 -0.0001 1 1 0.0006 0.0012 0.003 0.027 -0.00021
+1 0.0001 1 1 -0.0059 0.0031 0.009 0.020 -0.00023
+1 -0.0001 1 1 0.0061 -0.0002 0.010 -0.005 0.00006
+1 -0.0001 1 1 0.0054 -0.0014 0.008 0.016 -0.00013
+1 0.0001 1 1 -0.0039 0.0005 0.009 0.019 -0.00021
+1 0.0002 1 1 -0.0083 0.0005 0.009 -0.010 -0.00003
+1 -0.0002 1 1 0.0063 -0.0003 0.004 -0.023 0.00027
+1 -0.0001 1 1 0.0074 0.0001 0.003 0.002 -0.00001
+1 -0.0001 1 1 0.0005 -0.0003 0.006 0.027 -0.00001
+1 -0.0001 1 1 0.0063 0.0023 0.007 0.002 0.00006
+1 0.0001 1 1 0.0039 0.0032 0.014 0.017 -0.00016
+1 0.0001 1 1 -0.0042 -0.0007 0.008 0.018 -0.00004
+1 0.0001 1 1 -0.0023 0.0002 0.004 -0.010 0.00003
+1 -0.0001 1 1 0.0052 0.0021 0.005 0.002 0.00003
+1 -0.0001 1 1 0.0024 0.0018 0.009 0.010 0.00003
+1 -0.0002 1 1 0.0035 0.0012 0.004 0.021 -0.00002
+1 0.0001 1 1 -0.0065 0.0017 0.013 0.014 -0.00013
+1 0.0001 1 1 -0.0072 0.0001 0.012 0.004 -0.00003
+1 -0.0001 1 1 0.0035 -0.0008 0.016 -0.003 -0.00001
+1 0.0001 1 1 -0.0003 0.0012 0.008 -0.010 0.00002
+1 -0.0001 1 1 0.0033 0.0004 0.008 -0.004 0.00008
+1 0.0001 1 1 0.0039 0.0049 0.020 -0.015 0.00013
+1 -0.0006 1 1 0.0070 0.0012 0.022 -0.006 0.00022
+1 0.0002 1 1 0.0044 0.0037 0.022 0.010 -0.00025
+1 -0.0001 1 1 -0.0035 0.0002 0.010 0.014 -0.00027
+1 0.0005 1 1 -0.0079 0.0033 0.010 0.004 -0.00025
+1 0.0001 1 1 -0.0071 0.0033 0.010 -0.012 0.00017
+1 0.0001 1 1 0.0067 0.0042 0.016 -0.011 0.00012
+1 -0.0001 1 1 0.0058 0.0045 0.019 0.014 -0.00018
+1 0.0001 1 1 -0.0073 0.0030 0.020 0.010 -0.00033
+1 0.0007 1 1 -0.0107 0.0023 0.018 -0.005 -0.00016
+1 -0.0006 1 1 0.0064 0.0012 0.013 -0.024 0.00047
+1 0.0007 1 1 -0.0072 0.0021 0.010 -0.010 -0.00021
+1 -0.0003 1 1 0.0059 0.0036 0.008 -0.022 0.00037
+1 -0.0002 1 1 0.0095 0.0049 0.011 -0.004 0.00007
+1 -0.0002 1 1 0.0066 0.0020 0.014 0.014 -0.00017
+1 0.0005 1 1 -0.0091 0.0029 0.014 0.005 -0.00021
+1 -0.0003 1 1 0.0077 0.0050 0.012 -0.006 0.00014
+1 -0.0002 1 1 0.0042 0.0029 0.014 0.012 -0.00018
+1 0.0005 1 1 -0.0078 0.0018 0.012 0.003 -0.00024
+1 -0.0005 1 1 0.0075 0.0023 0.013 -0.007 0.00034
+1 0.0004 1 1 -0.0073 0.0023 0.015 0.003 -0.00018
+1 -0.0005 1 1 0.0090 0.0008 0.010 -0.001 0.00019
+1 -0.0002 1 1 0.0061 0.0009 0.006 0.016 -0.00029
+1 -0.0001 1 1 -0.0037 0.0004 -0.001 0.020 -0.00043
+1 0.0007 1 1 -0.0113 0.0059 0.003 0.006 -0.00033
+1 -0.0004 1 1 0.0066 0.0044 0.015 -0.024 0.00048
+1 -0.0001 1 1 0.0097 0.0021 0.016 -0.006 0.00002
+1 0.0004 1 1 -0.0067 0.0016 0.011 0.007 -0.00023
+1 -0.0006 1 1 0.0065 0.0015 0.008 -0.007 0.00049
+1 0.0002 1 1 -0.0040 0.0037 0.009 0.007 -0.00005
+1 0.0001 1 1 0.0037 0.0037 0.011 -0.009 0.00025
+1 -0.0002 1 1 0.0072 0.0021 0.012 -0.001 0.00013
+1 -0.0001 1 1 0.0065 0.0030 0.013 0.018 -0.00007
+1 0.0003 1 1 -0.0065 0.0007 0.004 0.018 -0.00022
+1 -0.0003 1 1 0.0087 0.0022 0.016 -0.007 0.00027
+1 -0.0001 1 1 0.0090 0.0025 0.016 0.016 -0.00009
+1 -0.0002 1 1 0.0044 0.0017 0.014 0.030 -0.00025
+1 0.0004 1 1 -0.0095 0.0004 0.008 0.024 -0.00050
+1 0.0002 1 1 -0.0135 0.0041 0.010 0.001 -0.00008
+1 0.0001 1 1 0.0036 0.0042 0.012 -0.030 0.00054
+1 -0.0002 1 1 0.0113 0.0020 0.010 -0.020 0.00052
+1 0.0002 1 1 -0.0077 0.0031 0.014 0.001 -0.00004
+1 0.0001 1 1 -0.0042 0.0010 0.013 -0.013 0.00022
+1 -0.0003 1 1 0.0070 0.0021 0.010 -0.007 0.00021
+1 -0.0003 1 1 0.0053 0.0024 0.009 0.011 -0.00014
+1 0.0004 1 1 -0.0085 0.0022 0.008 0.005 -0.00030
+1 0.0003 1 1 -0.0083 0.0032 0.009 -0.012 0.00015
+1 -0.0005 1 1 0.0114 -0.0013 0.009 -0.007 0.00049
+1 -0.0003 1 1 0.0131 -0.0006 0.005 0.020 -0.00011
+1 -0.0001 1 1 0.0005 -0.0006 -0.002 0.039 -0.00052
+1 0.0004 1 1 -0.0143 0.0045 0.002 0.019 -0.00045
+1 0.0002 1 1 -0.0162 0.0059 0.008 -0.014 0.00020
+1 -0.0003 1 1 0.0044 0.0001 0.017 -0.034 0.00075
+1 -0.0004 1 1 0.0102 0.0018 0.010 0.011 -0.00010
+1 0.0003 1 1 -0.0038 0.0036 0.009 0.025 -0.00044
+1 0.0001 1 1 -0.0069 0.0039 0.012 0.011 -0.00004
+1 -0.0003 1 1 0.0076 -0.0003 0.013 0.007 0.00029
+1 0.0001 1 1 -0.0057 0.0013 0.005 0.024 -0.00022
+1 0.0003 1 1 -0.0076 0.0042 0.009 0.008 -0.00003
+1 -0.0002 1 1 0.0067 0.0001 0.003 0.011 0.00002
+1 -0.0001 1 1 -0.0058 0.0033 0.006 0.014 -0.00013
+1 0.0003 1 1 -0.0087 0.0045 0.008 0.004 -0.00028
+1 -0.0004 1 1 0.0075 0.0035 0.013 -0.023 0.00042
+1 -0.0002 1 1 0.0073 0.0024 0.014 0.019 -0.00020
+1 0.0005 1 1 -0.0062 0.0010 0.010 0.024 -0.00048
+1 -0.0003 1 1 0.0040 0.0026 0.007 -0.002 0.00026
+1 -0.0002 1 1 0.0007 0.0034 0.008 0.009 -0.00015
+1 0.0005 1 1 -0.0042 0.0029 0.008 0.006 -0.00028
+1 0.0002 1 1 -0.0076 0.0046 0.017 -0.002 -0.00002
+1 -0.0004 1 1 0.0083 0.0051 0.023 -0.004 0.00011
+1 -0.0002 1 1 0.0049 0.0033 0.027 0.016 -0.00019
+1 0.0007 1 1 -0.0078 0.0010 0.022 0.007 -0.00022
+1 0.0001 1 1 -0.0043 0.0019 0.018 -0.012 0.00028
+1 -0.0009 1 1 0.0064 0.0020 0.013 -0.009 0.00025
+1 0.0012 1 1 -0.0115 0.0029 0.013 -0.011 -0.00035
+1 -0.0006 1 1 0.0177 0.0039 0.008 -0.008 0.00040
+1 -0.0004 1 1 0.0174 0.0034 0.010 0.025 -0.00023
+1 0.0010 1 1 -0.0094 0.0038 0.016 0.041 -0.00071
+1 -0.0003 1 1 0.0077 0.0039 0.019 0.011 0.00016
+1 -0.0001 1 1 0.0054 0.0024 0.020 0.032 -0.00014
+1 0.0004 1 1 -0.0082 0.0014 0.013 0.006 -0.00005
+1 -0.0012 1 1 0.0047 0.0023 0.005 -0.007 0.00029
+1 0.0004 1 1 -0.0080 0.0037 0.008 -0.013 -0.00011
+1 -0.0001 1 1 0.0068 0.0066 0.016 -0.024 0.00027
+1 -0.0001 1 1 0.0103 0.0026 0.021 -0.006 0.00008
+1 -0.0001 1 1 0.0069 0.0019 0.025 0.018 -0.00023
+1 0.0004 1 1 -0.0085 0.0001 0.015 0.008 -0.00016
+1 -0.0005 1 1 0.0069 0.0051 0.007 -0.004 0.00022
+1 0.0006 1 1 -0.0084 0.0010 0.011 -0.005 -0.00034
+1 -0.0003 1 1 0.0082 0.0036 0.013 -0.019 0.00031
+1 0.0009 1 1 -0.0068 0.0025 0.015 0.006 -0.00025
+1 -0.0006 1 1 0.0070 0.0023 0.013 -0.004 0.00048
+1 0.0001 1 1 -0.0053 0.0027 0.018 0.017 -0.00023
+1 0.0007 1 1 -0.0083 -0.0021 0.014 0.004 -0.00011
+1 0.0001 1 1 0.0041 -0.0002 0.005 -0.007 0.00048
+1 -0.0017 1 1 0.0110 0.0064 0.004 0.005 0.00034
+1 0.0001 1 1 -0.0039 0.0036 0.009 0.022 -0.00106
+1 0.0012 1 1 -0.0171 0.0025 0.010 0.004 -0.00034
+1 -0.0004 1 1 0.0055 0.0054 0.007 -0.038 0.00071
+1 -0.0003 1 1 0.0148 0.0049 0.016 0.011 0.00003
+1 -0.0001 1 1 0.0108 0.0026 0.018 0.037 -0.00043
+1 0.0002 1 1 -0.0092 -0.0003 0.016 0.039 -0.00043
+1 -0.0001 1 1 0.0065 0.0015 0.005 0.009 0.00008
+1 -0.0002 1 1 0.0014 0.0019 0.003 0.031 -0.00019
+1 0.0005 1 1 -0.0099 0.0045 0.009 0.015 -0.00027
+1 -0.0003 1 1 0.0047 0.0044 0.011 -0.005 0.00041
+1 -0.0002 1 1 0.0078 0.0040 0.015 0.013 0.00002
+1 0.0004 1 1 -0.0050 0.0006 0.012 0.025 -0.00021
+1 0.0002 1 1 -0.0084 0.0032 0.008 -0.006 -0.00014
+1 0.0001 1 1 0.0002 0.0002 0.019 -0.010 0.00017
+1 -0.0001 1 1 0.0034 0.0002 0.017 -0.007 0.00020
+1 -0.0001 1 1 0.0049 0.0006 0.014 0.004 -0.00001
+1 -0.0001 1 1 0.0041 -0.0007 0.010 0.011 -0.00007
+1 0.0002 1 1 -0.0074 0.0027 0.005 -0.002 -0.00013
+1 -0.0001 1 1 0.0039 -0.0002 0.013 0.006 0.00001
+1 0.0001 1 1 -0.0047 0.0006 0.005 0.004 -0.00008
+1 -0.0002 1 1 0.0044 0.0029 0.011 -0.005 0.00011
+1 -0.0004 1 1 0.0043 -0.0019 0.016 0.012 0.00014
+1 0.0002 1 1 -0.0078 -0.0019 0.005 0.001 -0.00011
+1 0.0001 1 1 0.0050 0.0056 0.019 -0.017 0.00005
+1 -0.0002 1 1 0.0062 0.0022 0.022 0.002 0.00000
+1 0.0001 1 1 0.0046 0.0024 0.023 0.011 -0.00014
+1 0.0001 1 1 -0.0055 -0.0003 0.012 0.008 -0.00012
+1 0.0001 1 1 -0.0050 -0.0003 0.007 -0.010 0.00006
+1 -0.0001 1 1 0.0046 0.0008 0.011 -0.004 0.00003
+1 -0.0002 1 1 0.0031 0.0007 0.006 0.010 0.00004
+1 0.0001 1 1 -0.0052 0.0023 0.011 0.005 -0.00011
+1 -0.0001 1 1 0.0060 0.0001 0.008 -0.005 0.00013
+1 0.0002 1 1 -0.0077 0.0009 0.007 -0.001 -0.00013
+1 -0.0001 1 1 0.0079 0.0026 0.011 -0.005 0.00002
+1 0.0001 1 1 0.0063 0.0028 0.014 0.010 -0.00014
+1 0.0002 1 1 -0.0041 0.0009 0.013 0.024 -0.00011
+1 -0.0002 1 1 0.0025 0.0006 0.009 0.010 0.00008
+1 0.0003 1 1 -0.0053 0.0013 0.009 0.007 -0.00019
+1 -0.0002 1 1 0.0051 0.0018 0.009 -0.006 0.00011
+1 0.0001 1 1 -0.0028 -0.0007 0.008 -0.011 0.00002
+1 -0.0002 1 1 0.0060 0.0017 0.000 0.020 -0.00004
+1 0.0002 1 1 -0.0048 0.0033 0.011 0.024 -0.00021
+1 -0.0002 1 1 0.0060 -0.0002 0.007 0.014 0.00006
+1 0.0001 1 1 -0.0057 0.0013 0.009 0.020 -0.00016
+1 0.0001 1 1 -0.0043 0.0012 0.009 -0.014 0.00007
+1 -0.0002 1 1 0.0057 0.0020 0.009 0.000 0.00003
+1 -0.0001 1 1 0.0031 0.0032 0.013 0.011 -0.00020
+1 0.0002 1 1 -0.0049 0.0014 0.017 0.005 -0.00012
+1 -0.0001 1 1 0.0044 -0.0001 0.010 -0.004 0.00013
+1 -0.0001 1 1 0.0038 0.0010 0.009 0.012 -0.00005
+1 -0.0001 1 1 0.0023 0.0020 0.011 0.011 0.00001
+1 0.0001 1 1 -0.0038 0.0003 0.009 0.005 -0.00004
+1 0.0002 1 1 -0.0023 0.0014 0.014 -0.014 0.00000
+1 -0.0002 1 1 0.0050 -0.0001 0.011 -0.004 0.00007
+1 0.0001 1 1 -0.0040 0.0015 0.006 -0.013 0.00000
+1 -0.0002 1 1 0.0037 0.0022 0.007 -0.008 0.00000
+1 0.0002 1 1 -0.0042 0.0017 0.013 -0.012 -0.00007
+1 -0.0001 1 1 0.0074 0.0019 0.009 0.013 -0.00003
+1 -0.0002 1 1 0.0040 0.0013 0.004 -0.007 0.00007
+1 -0.0019 1 1 0.0065 0.0050 0.027 -0.015 0.00073
+1 -0.0003 1 1 0.0063 0.0022 0.028 0.016 -0.00032
+1 0.0016 1 1 -0.0095 0.0008 0.018 0.008 -0.00035
+1 -0.0021 1 1 0.0078 0.0082 0.009 -0.007 0.00055
+1 0.0015 1 1 -0.0063 0.0067 0.026 -0.011 -0.00024
+1 -0.0010 1 1 0.0115 -0.0024 0.026 -0.009 0.00057
+1 0.0007 1 1 0.0086 0.0019 0.018 0.028 -0.00037
+1 -0.0004 1 1 0.0064 0.0020 0.014 0.043 0.00001
+1 0.0007 1 1 -0.0099 -0.0028 0.025 -0.002 -0.00001
+1 -0.0003 1 1 0.0036 0.0058 0.022 -0.007 0.00002
+1 0.0004 1 1 -0.0025 0.0042 0.023 -0.012 0.00012
+1 -0.0008 1 1 0.0054 0.0033 0.021 -0.009 0.00024
+1 0.0001 1 1 -0.0038 0.0036 0.024 -0.010 0.00002
+1 -0.0004 1 1 0.0051 0.0037 0.012 -0.008 0.00007
+1 -0.0002 1 1 0.0008 0.0024 0.012 0.009 -0.00006
+1 0.0004 1 1 -0.0035 0.0038 0.012 0.006 -0.00019
+1 0.0003 1 1 -0.0017 0.0039 0.022 -0.010 -0.00005
+1 -0.0003 1 1 0.0036 0.0029 0.019 -0.008 0.00013
+1 0.0003 1 1 -0.0052 0.0009 0.012 -0.006 -0.00027
+1 0.0003 1 1 -0.0068 0.0043 0.012 -0.032 0.00002
+1 -0.0007 1 1 0.0091 0.0040 0.014 -0.032 0.00031
+1 -0.0004 1 1 0.0040 0.0025 0.014 0.010 0.00008
+1 0.0003 1 1 -0.0061 0.0046 0.018 0.007 -0.00018
+1 0.0003 1 1 -0.0052 0.0034 0.019 -0.013 0.00011
+1 -0.0008 1 1 0.0083 0.0022 0.013 -0.010 0.00034
+1 0.0001 1 1 -0.0039 0.0034 0.014 0.012 -0.00031
+1 -0.0001 1 1 0.0048 0.0038 0.012 0.004 0.00017
+1 -0.0002 1 1 0.0049 0.0044 0.017 0.022 -0.00004
+1 -0.0004 1 1 0.0040 0.0041 0.012 0.028 0.00013
+1 0.0004 1 1 -0.0064 0.0005 0.009 0.022 -0.00011
+1 0.0004 1 1 -0.0068 0.0016 0.012 0.008 -0.00025
+1 0.0001 1 1 -0.0051 0.0032 0.012 -0.012 0.00016
+1 -0.0002 1 1 0.0053 0.0032 0.011 -0.011 0.00017
+1 -0.0002 1 1 0.0045 0.0046 0.017 0.012 -0.00007
+1 -0.0004 1 1 0.0039 0.0004 0.007 0.026 0.00007
+1 0.0003 1 1 -0.0081 0.0021 0.012 0.016 -0.00015
+1 -0.0001 1 1 0.0030 0.0043 0.013 -0.008 0.00013
+1 -0.0004 1 1 0.0043 0.0023 0.013 0.011 0.00008
+1 0.0005 1 1 -0.0074 0.0014 0.008 0.009 -0.00031
+1 -0.0003 1 1 0.0096 0.0027 0.013 -0.002 0.00020
+1 -0.0005 1 1 0.0028 0.0027 0.010 0.027 0.00021
+1 0.0004 1 1 -0.0060 0.0027 0.011 0.025 -0.00025
+1 -0.0002 1 1 0.0037 0.0022 0.010 0.007 0.00021
+1 -0.0001 1 1 -0.0055 0.0023 0.010 0.009 -0.00012
+1 0.0002 1 1 -0.0078 0.0023 0.010 0.000 -0.00016
+1 -0.0006 1 1 0.0045 0.0036 0.009 -0.011 0.00030
+1 -0.0001 1 1 0.0056 0.0019 0.008 0.006 0.00013
+1 -0.0001 1 1 0.0063 0.0020 0.007 0.014 0.00002
+1 -0.0002 1 1 0.0072 0.0042 0.012 0.030 -0.00001
+1 0.0006 1 1 -0.0087 -0.0001 0.009 0.038 -0.00037
+1 -0.0002 1 1 0.0024 0.0028 0.013 0.010 0.00010
+1 0.0002 1 1 -0.0038 0.0021 0.010 0.006 -0.00008
+1 -0.0001 1 1 0.0042 0.0018 0.008 0.005 0.00012
+1 0.0003 1 1 -0.0090 0.0036 0.009 -0.015 -0.00009
+1 0.0001 1 1 -0.0063 0.0024 0.008 -0.028 0.00027
+1 -0.0003 1 1 0.0070 0.0022 0.008 -0.007 0.00012
+1 0.0009 1 1 -0.0080 0.0022 0.009 0.009 -0.00043
+1 -0.0001 1 1 -0.0033 0.0029 0.009 -0.014 0.00045
+1 -0.0007 1 1 0.0069 0.0039 0.011 -0.008 0.00031
+1 0.0001 1 1 -0.0039 0.0011 0.003 0.000 -0.00022
+1 0.0004 1 1 -0.0072 0.0028 0.001 -0.013 -0.00010
+1 -0.0004 1 1 0.0057 0.0045 0.004 -0.024 0.00030
+1 0.0006 1 1 -0.0081 0.0014 0.017 -0.016 -0.00014
+1 -0.0007 1 1 0.0048 0.0011 0.009 -0.029 0.00049
+1 0.0001 1 1 -0.0037 0.0040 0.011 -0.008 -0.00025
+1 -0.0005 1 1 0.0051 0.0022 0.008 -0.021 0.00032
+1 0.0003 1 1 -0.0025 0.0024 0.011 -0.012 -0.00022
+1 -0.0001 1 1 0.0049 0.0042 0.010 -0.001 0.00002
+1 -0.0002 1 1 0.0024 0.0015 0.009 0.010 -0.00012
+1 0.0005 1 1 -0.0070 0.0056 0.007 0.001 -0.00025
+1 -0.0009 1 1 0.0048 -0.0054 0.008 -0.010 0.00039
+1 0.0002 1 1 -0.0040 0.0022 0.004 0.000 -0.00045
+1 0.0005 1 1 -0.0068 0.0031 0.009 -0.012 -0.00007
+1 -0.0006 1 1 0.0093 0.0026 0.018 -0.007 0.00023
+1 0.0003 1 1 -0.0043 0.0018 0.019 0.017 -0.00024
+1 -0.0002 1 1 0.0071 0.0021 0.008 -0.007 0.00016
+1 0.0001 1 1 0.0035 0.0035 0.017 0.014 -0.00019
+1 0.0001 1 1 -0.0040 0.0006 0.019 0.012 -0.00012
+1 -0.0004 1 1 0.0020 0.0045 0.005 0.009 -0.00007
+1 0.0004 1 1 -0.0053 0.0027 0.012 0.006 -0.00031
+1 -0.0001 1 1 0.0035 0.0031 0.015 -0.013 0.00010
+1 0.0005 1 1 -0.0044 -0.0010 0.013 -0.009 -0.00011
+1 -0.0003 1 1 0.0064 -0.0007 0.005 -0.008 0.00021
+1 0.0005 1 1 -0.0065 -0.0013 0.011 0.007 -0.00016
+1 -0.0002 1 1 0.0030 0.0006 0.010 -0.007 0.00025
+1 -0.0002 1 1 0.0054 0.0011 0.011 0.015 -0.00001
+1 0.0003 1 1 -0.0071 -0.0001 0.006 0.008 -0.00012
+1 -0.0006 1 1 0.0083 0.0023 0.012 -0.001 0.00026
+1 -0.0001 1 1 0.0061 0.0016 0.013 0.015 -0.00029
+1 0.0006 1 1 -0.0080 0.0015 0.015 0.009 -0.00026
+1 -0.0002 1 1 0.0053 0.0037 0.010 -0.008 0.00036
+1 -0.0001 1 1 0.0079 0.0029 0.015 0.009 0.00002
+1 -0.0001 1 1 0.0077 0.0004 0.015 0.020 -0.00004
+1 -0.0001 1 1 0.0053 -0.0026 0.011 0.033 -0.00010
+1 0.0001 1 1 -0.0051 0.0004 0.005 0.034 -0.00012
+1 0.0001 1 1 -0.0064 0.0014 0.007 0.020 -0.00003
+1 -0.0005 1 1 0.0056 0.0009 0.012 0.010 0.00021
+1 0.0003 1 1 -0.0092 -0.0008 0.011 0.005 -0.00023
+1 -0.0004 1 1 0.0092 0.0003 0.007 -0.007 0.00020
+1 -0.0001 1 1 0.0069 0.0012 0.008 0.011 -0.00030
+1 0.0004 1 1 -0.0088 -0.0011 0.011 0.006 -0.00031
+1 -0.0002 1 1 0.0038 0.0003 0.010 -0.023 0.00040
+1 -0.0001 1 1 0.0084 -0.0004 0.010 -0.003 0.00007
+1 -0.0001 1 1 0.0072 0.0001 0.009 0.018 -0.00009
+1 -0.0002 1 1 0.0006 0.0004 0.008 0.032 -0.00021
+1 0.0002 1 1 -0.0107 0.0009 0.009 0.015 -0.00028
+1 -0.0002 1 1 0.0045 0.0007 0.007 -0.021 0.00024
+1 -0.0001 1 1 0.0066 0.0021 0.009 -0.004 0.00002
+1 0.0004 1 1 -0.0059 0.0017 0.014 0.009 -0.00018
+1 -0.0003 1 1 0.0028 -0.0011 0.006 -0.004 0.00024
+1 0.0001 1 1 -0.0062 0.0021 0.007 0.005 -0.00044
+1 0.0001 1 1 -0.0052 0.0026 0.011 -0.013 0.00006
+1 -0.0001 1 1 0.0068 0.0029 0.010 -0.012 0.00019
+1 0.0001 1 1 -0.0034 0.0020 0.016 0.014 -0.00034
+1 0.0003 1 1 -0.0072 -0.0003 0.014 0.006 -0.00019
+1 0.0001 1 1 -0.0039 -0.0008 0.009 -0.011 0.00021
+1 -0.0001 1 1 0.0037 0.0016 0.006 -0.011 0.00021
+1 -0.0001 1 1 -0.0040 0.0016 0.021 -0.002 -0.00009
+1 0.0005 1 1 -0.0065 -0.0075 0.021 -0.013 -0.00009
+1 -0.0001 1 1 0.0078 -0.0019 -0.001 -0.014 0.00029
+1 0.0001 1 1 -0.0097 0.0019 0.010 0.006 -0.00020
+1 0.0003 1 1 -0.0111 0.0003 0.009 -0.009 -0.00006
+1 -0.0004 1 1 0.0117 -0.0027 0.004 -0.008 0.00037
+1 -0.0001 1 1 0.0128 -0.0012 0.001 0.012 -0.00007
+1 -0.0001 1 1 0.0087 -0.0002 0.001 0.028 -0.00037
+1 0.0002 1 1 -0.0037 0.0040 0.010 0.036 -0.00037
+1 -0.0003 1 1 0.0040 0.0021 0.009 0.009 0.00009
+1 0.0003 1 1 -0.0059 0.0007 0.015 0.005 -0.00015
+1 -0.0005 1 1 0.0042 0.0002 0.008 -0.008 0.00020
+1 0.0005 1 1 -0.0068 0.0011 0.010 -0.012 -0.00016
+1 -0.0001 1 1 0.0072 -0.0001 0.004 -0.019 0.00033
+1 -0.0005 1 1 0.0102 0.0026 0.006 -0.006 0.00013
+1 -0.0003 1 1 0.0066 0.0020 0.008 0.012 -0.00032
+1 0.0002 1 1 -0.0080 0.0021 0.020 0.001 -0.00008
+1 -0.0003 1 1 0.0084 -0.0021 0.008 -0.008 0.00029
+1 0.0001 1 1 -0.0062 0.0033 0.002 0.017 -0.00029
+1 0.0001 1 1 -0.0088 0.0038 0.008 0.002 -0.00003
+1 0.0001 1 1 -0.0077 0.0036 0.013 -0.013 0.00012
+1 -0.0002 1 1 0.0118 -0.0011 0.005 -0.004 0.00024
+1 -0.0002 1 1 0.0131 -0.0001 0.004 0.019 0.00000
+1 -0.0002 1 1 0.0093 0.0016 0.006 0.040 -0.00031
+1 0.0003 1 1 -0.0059 0.0023 0.012 0.047 -0.00051
+1 -0.0002 1 1 0.0037 0.0004 0.010 -0.006 0.00011
+1 -0.0001 1 1 -0.0051 0.0001 0.011 -0.004 -0.00025
+1 0.0006 1 1 -0.0093 -0.0011 0.010 -0.015 -0.00024
+1 0.0001 1 1 -0.0054 0.0001 0.008 -0.033 0.00037
+1 -0.0001 1 1 0.0130 0.0018 0.009 -0.014 0.00031
+1 -0.0002 1 1 0.0142 0.0010 0.008 0.012 -0.00024
+1 -0.0002 1 1 0.0089 0.0012 0.009 0.029 -0.00045
+1 0.0004 1 1 -0.0039 0.0001 0.009 -0.009 -0.00011
+1 -0.0005 1 1 0.0068 -0.0010 0.006 -0.007 0.00023
+1 0.0001 1 1 -0.0039 0.0018 0.011 0.001 -0.00004
+1 0.0002 1 1 -0.0010 -0.0004 0.007 -0.009 0.00010
+1 -0.0001 1 1 0.0052 0.0010 0.003 -0.004 0.00022
+1 -0.0002 1 1 0.0060 0.0017 0.006 0.011 -0.00007
+1 -0.0001 1 1 -0.0048 -0.0001 0.010 0.011 -0.00011
+1 0.0001 1 1 -0.0044 0.0045 0.030 -0.004 -0.00009
+1 0.0002 1 1 -0.0050 0.0046 0.035 -0.011 -0.00002
+1 0.0002 1 1 -0.0006 0.0009 0.034 -0.027 0.00010
+1 -0.0003 1 1 0.0047 0.0001 0.030 -0.022 0.00016
+1 0.0002 1 1 -0.0045 0.0010 0.020 -0.012 -0.00004
+1 0.0001 1 1 0.0037 0.0022 0.023 -0.025 0.00016
+1 -0.0003 1 1 0.0088 -0.0015 0.020 0.007 0.00000
+1 -0.0001 1 1 0.0072 -0.0011 0.018 0.019 -0.00017
+1 0.0002 1 1 -0.0041 0.0027 0.022 0.028 -0.00037
+1 0.0001 1 1 -0.0010 0.0003 0.015 -0.010 0.00001
+1 -0.0002 1 1 0.0057 0.0007 0.015 0.012 0.00002
+1 0.0002 1 1 -0.0055 -0.0002 0.015 0.004 -0.00009
+1 0.0001 1 1 -0.0035 0.0010 0.014 -0.012 0.00009
+1 -0.0001 1 1 0.0067 0.0032 0.007 0.000 0.00007
+1 0.0002 1 1 -0.0062 0.0003 0.014 0.024 -0.00018
+1 -0.0002 1 1 0.0039 -0.0001 0.014 -0.017 0.00020
+1 -0.0001 1 1 0.0042 0.0000 0.009 0.014 -0.00006
+1 0.0002 1 1 -0.0040 -0.0006 0.011 0.012 -0.00006
+1 0.0003 1 1 -0.0047 0.0017 0.014 0.005 -0.00006
+1 -0.0001 1 1 0.0027 0.0008 0.013 0.011 -0.00002
+1 0.0001 1 1 -0.0034 0.0003 0.012 0.011 -0.00015
+1 0.0001 1 1 -0.0043 0.0001 0.003 0.004 -0.00007
+1 0.0003 1 1 -0.0031 0.0040 0.013 -0.012 0.00005
+1 -0.0002 1 1 0.0039 0.0007 0.013 -0.012 0.00022
+1 -0.0002 1 1 0.0062 0.0009 0.014 0.011 0.00000
+1 0.0001 1 1 -0.0041 0.0015 0.014 0.003 -0.00003
+1 -0.0001 1 1 0.0043 0.0005 0.010 0.012 0.00000
+1 0.0001 1 1 -0.0047 0.0000 0.008 0.002 -0.00002
+1 0.0001 1 1 -0.0020 0.0009 0.008 -0.011 0.00010
+1 -0.0001 1 1 0.0062 0.0007 0.008 0.001 0.00011
+1 -0.0001 1 1 0.0058 0.0011 0.008 0.013 -0.00007
+1 0.0001 1 1 -0.0047 0.0007 0.007 0.004 -0.00004
+1 0.0001 1 1 -0.0020 0.0015 0.010 -0.010 0.00009
+1 -0.0002 1 1 0.0044 0.0006 0.007 -0.006 0.00014
+1 0.0002 1 1 -0.0036 -0.0002 0.011 -0.011 0.00001
+1 -0.0001 1 1 0.0036 -0.0007 0.005 -0.013 0.00018
+1 -0.0001 1 1 0.0053 0.0014 0.007 0.012 -0.00002
+1 0.0002 1 1 -0.0055 0.0007 0.015 0.004 -0.00003
+1 -0.0002 1 1 0.0047 0.0001 0.005 -0.007 0.00019
+1 -0.0001 1 1 0.0059 0.0013 0.006 0.013 -0.00003
+1 0.0001 1 1 -0.0039 0.0006 0.018 0.017 -0.00009
+1 0.0004 1 1 -0.0048 -0.0028 0.008 0.004 -0.00005
+1 -0.0001 1 1 0.0049 -0.0001 0.002 0.001 0.00024
+1 -0.0001 1 1 0.0062 0.0024 0.005 0.013 0.00002
+1 -0.0001 1 1 0.0045 0.0024 0.011 0.029 -0.00008
+1 -0.0001 1 1 0.0020 -0.0017 0.002 0.035 0.00004
+1 -0.0001 1 1 0.0022 -0.0004 0.008 0.010 0.00002
+1 0.0001 1 1 -0.0043 -0.0001 0.013 -0.011 0.00002
+1 0.0003 1 1 -0.0065 0.0000 0.011 0.005 -0.00008
+1 0.0001 1 1 0.0027 -0.0007 0.008 -0.008 0.00021
+1 -0.0002 1 1 0.0085 0.0000 0.006 0.004 0.00024
+1 -0.0003 1 1 0.0080 0.0039 0.014 0.030 -0.00017
+1 0.0001 1 1 -0.0064 -0.0007 0.021 0.032 -0.00023
+1 -0.0002 1 1 -0.0082 -0.0034 0.016 0.021 -0.00008
+1 0.0001 1 1 -0.0038 -0.0024 0.002 -0.012 0.00023
+1 -0.0003 1 1 0.0067 -0.0005 0.011 -0.004 0.00016
+1 -0.0001 1 1 0.0053 0.0008 0.011 0.014 -0.00012
+1 -0.0001 1 1 -0.0082 -0.0022 -0.001 0.003 -0.00015
+1 0.0003 1 1 -0.0112 0.0027 0.002 -0.010 -0.00021
+1 0.0001 1 1 -0.0077 0.0036 0.008 -0.033 0.00029
+1 -0.0002 1 1 0.0064 -0.0007 0.008 -0.036 0.00033
+1 -0.0003 1 1 0.0099 -0.0003 0.004 0.001 0.00000
+1 -0.0003 1 1 0.0058 0.0012 0.005 0.017 -0.00032
+1 0.0007 1 1 -0.0070 0.0043 0.012 0.016 -0.00076
+1 0.0001 1 1 -0.0109 -0.0001 0.017 -0.011 0.00026
+1 -0.0004 1 1 0.0062 -0.0005 0.002 -0.024 0.00035
+1 0.0003 1 1 -0.0025 0.0029 0.014 -0.010 0.00003
+1 -0.0005 1 1 0.0063 -0.0011 0.008 -0.006 0.00033
+1 0.0001 1 1 -0.0066 0.0022 0.010 0.005 -0.00044
+1 0.0001 1 1 -0.0006 0.0010 0.012 -0.010 0.00027
+1 -0.0005 1 1 0.0049 -0.0006 0.010 -0.006 0.00030
+1 0.0001 1 1 0.0010 0.0002 0.008 0.011 -0.00020
+1 0.0004 1 1 -0.0041 0.0012 0.008 0.006 -0.00017
+1 0.0001 1 1 -0.0034 0.0010 0.013 -0.013 0.00001
+1 -0.0003 1 1 0.0064 -0.0003 0.009 -0.007 0.00010
+1 0.0002 1 1 -0.0090 0.0005 0.006 -0.016 -0.00012
+1 0.0002 1 1 -0.0075 0.0025 0.009 -0.030 0.00018
+1 -0.0003 1 1 0.0124 -0.0005 0.008 -0.005 0.00013
+1 -0.0006 1 1 0.0108 0.0007 0.008 0.017 -0.00018
+1 0.0006 1 1 -0.0092 0.0004 0.023 0.023 -0.00072
+1 0.0004 1 1 -0.0085 -0.0072 0.010 -0.031 0.00018
+1 -0.0002 1 1 0.0115 0.0037 0.007 -0.010 0.00013
+1 -0.0003 1 1 0.0110 0.0031 0.012 0.011 -0.00012
+1 0.0001 1 1 -0.0081 -0.0018 0.008 0.019 -0.00015
+1 0.0003 1 1 -0.0064 0.0021 0.001 -0.011 -0.00024
+1 0.0001 1 1 -0.0033 0.0020 0.004 -0.030 0.00016
+1 -0.0001 1 1 0.0054 0.0020 0.009 -0.023 0.00009
+1 -0.0004 1 1 0.0071 0.0016 0.013 -0.002 0.00019
+1 -0.0002 1 1 0.0042 0.0006 0.005 0.006 0.00015
+1 -0.0001 1 1 0.0019 -0.0001 0.009 0.010 0.00002
+1 0.0002 1 1 -0.0044 0.0003 0.007 0.004 -0.00009
+1 0.0002 1 1 -0.0009 0.0012 0.010 -0.010 -0.00002
+1 -0.0001 1 1 0.0034 0.0007 0.010 -0.007 0.00016
+1 0.0001 1 1 -0.0043 -0.0005 0.003 -0.011 -0.00003
+1 0.0001 1 1 0.0038 0.0041 0.018 -0.010 0.00005
+1 0.0004 1 1 -0.0042 0.0015 0.012 -0.011 -0.00012
+1 -0.0002 1 1 0.0077 0.0005 0.011 -0.004 0.00020
+1 -0.0003 1 1 0.0074 0.0011 0.012 0.012 -0.00008
+1 0.0003 1 1 -0.0041 0.0006 0.013 0.020 -0.00027
+1 -0.0002 1 1 0.0018 0.0000 0.010 0.010 0.00002
+1 0.0003 1 1 -0.0039 0.0005 0.010 0.007 -0.00016
+1 -0.0002 1 1 0.0059 0.0008 0.006 0.013 0.00007
+1 -0.0001 1 1 -0.0005 -0.0002 0.012 0.028 -0.00013
+1 0.0002 1 1 -0.0058 0.0007 0.012 0.022 -0.00027
+1 -0.0002 1 1 0.0065 0.0007 0.005 -0.003 0.00024
+1 -0.0001 1 1 0.0057 -0.0003 0.007 0.019 -0.00008
+1 -0.0001 1 1 0.0025 0.0004 0.007 0.027 -0.00020
+1 0.0001 1 1 -0.0020 -0.0006 0.007 -0.010 0.00001
+1 0.0001 1 1 0.0026 -0.0006 0.001 -0.008 0.00004
+1 0.0002 1 1 -0.0024 0.0015 0.012 -0.014 0.00000
+1 -0.0001 1 1 0.0071 0.0033 0.010 -0.001 0.00010
+1 -0.0002 1 1 0.0056 0.0022 0.014 0.018 -0.00009
+1 0.0003 1 1 -0.0095 -0.0002 0.012 0.005 -0.00017
+1 0.0001 1 1 -0.0069 -0.0001 0.011 -0.013 0.00024
+1 -0.0002 1 1 0.0066 -0.0014 0.006 -0.014 0.00029
+1 -0.0002 1 1 0.0057 0.0024 0.008 0.012 -0.00019
+1 0.0005 1 1 -0.0092 -0.0018 0.012 -0.005 -0.00007
+1 -0.0004 1 1 0.0088 0.0019 0.009 0.013 0.00004
+1 0.0005 1 1 -0.0051 -0.0018 0.012 0.025 -0.00032
+1 -0.0001 1 1 0.0043 -0.0001 0.006 0.006 0.00016
+1 -0.0002 1 1 0.0057 0.0020 0.008 0.013 0.00007
+1 -0.0001 1 1 0.0016 0.0012 0.006 0.029 -0.00005
+1 0.0002 1 1 -0.0051 0.0009 0.011 0.022 -0.00015
+1 -0.0002 1 1 0.0053 -0.0003 0.012 0.017 0.00004
+1 -0.0002 1 1 -0.0009 0.0001 0.007 0.027 -0.00013
+1 0.0001 1 1 -0.0063 0.0020 0.010 0.020 -0.00027
+1 0.0002 1 1 -0.0085 -0.0018 0.010 0.008 -0.00001
+1 0.0001 1 1 -0.0036 0.0011 0.008 -0.010 0.00020
+1 -0.0001 1 1 0.0045 0.0019 0.012 -0.009 0.00023
+1 -0.0001 1 1 0.0057 -0.0006 0.014 0.010 -0.00004
+1 0.0001 1 1 -0.0035 0.0017 0.023 -0.012 0.00015
+1 -0.0002 1 1 0.0048 0.0005 0.011 -0.007 0.00007
+1 0.0002 1 1 -0.0055 -0.0001 0.018 -0.011 -0.00006
+1 -0.0003 1 1 0.0049 -0.0008 0.010 -0.023 0.00019
+1 -0.0001 1 1 0.0007 -0.0014 0.017 0.009 0.00001
+1 -0.0004 1 1 0.0048 0.0041 0.010 0.014 0.00006
+1 0.0001 1 1 -0.0040 0.0018 0.026 0.018 -0.00014
+1 0.0003 1 1 -0.0049 -0.0037 0.017 0.006 -0.00001
+1 0.0002 1 1 -0.0041 0.0013 0.013 -0.011 -0.00002
+1 -0.0002 1 1 0.0045 0.0028 0.016 -0.006 0.00000
+1 0.0001 1 1 -0.0003 -0.0005 0.013 -0.010 0.00003
+1 -0.0004 1 1 0.0040 -0.0019 0.007 -0.007 0.00019
+1 0.0001 1 1 -0.0065 0.0022 0.008 -0.009 -0.00015
+1 0.0001 1 1 -0.0057 0.0021 0.011 -0.029 0.00009
+1 -0.0002 1 1 0.0082 0.0009 0.013 -0.021 0.00014
+1 -0.0001 1 1 -0.0084 0.0003 0.011 0.007 -0.00045
+1 0.0002 1 1 -0.0102 0.0005 0.011 -0.014 0.00013
+1 -0.0005 1 1 0.0068 0.0001 0.004 -0.025 0.00029
+1 0.0002 1 1 -0.0020 0.0019 0.012 -0.010 -0.00001
+1 -0.0002 1 1 0.0042 0.0004 0.013 -0.007 0.00016
+1 0.0001 1 1 -0.0040 0.0028 0.005 -0.011 -0.00001
+1 -0.0001 1 1 0.0033 -0.0004 0.011 -0.007 0.00007
+1 0.0001 1 1 -0.0032 0.0010 0.011 -0.013 0.00000
+1 0.0001 1 1 -0.0017 0.0002 0.006 -0.010 -0.00001
+1 -0.0001 1 1 0.0042 0.0009 0.009 0.011 -0.00001
+1 0.0002 1 1 -0.0046 0.0012 0.014 0.007 -0.00006
+1 -0.0001 1 1 0.0046 -0.0003 0.008 0.004 0.00012
+1 -0.0001 1 1 0.0049 0.0000 0.006 0.015 -0.00002
+1 0.0001 1 1 -0.0064 0.0005 0.006 0.013 -0.00018
+1 0.0001 1 1 -0.0048 0.0020 0.007 -0.030 0.00017
+1 -0.0002 1 1 0.0066 -0.0005 0.014 -0.026 0.00024
+1 0.0001 1 1 -0.0033 0.0010 0.016 0.001 -0.00036
+1 0.0001 1 1 -0.0070 -0.0025 0.013 -0.006 -0.00021
+1 -0.0003 1 1 0.0058 0.0048 0.004 -0.017 0.00005
+1 0.0007 1 1 -0.0062 0.0042 0.019 -0.013 -0.00042
+1 -0.0002 1 1 0.0075 -0.0022 0.010 -0.020 0.00027
+1 -0.0001 1 1 0.0087 -0.0017 0.005 -0.003 -0.00001
+1 -0.0002 1 1 0.0044 0.0010 0.004 0.016 -0.00020
+1 0.0002 1 1 -0.0115 0.0000 0.010 -0.003 -0.00022
+1 0.0002 1 1 -0.0096 0.0006 0.010 -0.028 0.00030
+1 -0.0005 1 1 0.0060 -0.0030 0.010 -0.036 0.00040
+1 0.0004 1 1 -0.0032 -0.0003 0.009 -0.010 -0.00024
+1 -0.0001 1 1 0.0044 0.0011 -0.002 -0.014 0.00022
+1 -0.0008 1 1 0.0068 0.0024 0.002 -0.005 0.00011
+1 0.0002 1 1 -0.0083 0.0011 0.012 -0.015 -0.00002
+1 0.0001 1 1 -0.0048 -0.0009 0.012 -0.028 0.00031
+1 -0.0004 1 1 0.0109 -0.0003 0.008 -0.015 0.00032
+1 -0.0002 1 1 0.0066 0.0018 0.010 0.011 -0.00032
+1 0.0004 1 1 -0.0061 0.0013 0.012 0.012 -0.00054
+1 0.0001 1 1 -0.0079 0.0006 0.014 -0.010 0.00023
+1 -0.0001 1 1 0.0053 0.0012 0.007 -0.007 -0.00001
+1 -0.0002 1 1 0.0015 0.0004 0.006 0.011 -0.00009
+1 0.0004 1 1 -0.0051 0.0018 0.009 0.007 -0.00025
+1 -0.0004 1 1 0.0050 -0.0012 0.006 -0.008 0.00025
+1 0.0003 1 1 -0.0036 0.0017 0.015 -0.012 0.00000
+1 -0.0003 1 1 0.0069 -0.0002 0.011 -0.006 0.00022
+1 0.0001 1 1 0.0049 0.0004 0.010 0.016 -0.00013
+1 -0.0005 1 1 0.0042 -0.0003 0.006 0.012 0.00018
+1 0.0004 1 1 -0.0081 0.0010 0.007 0.008 -0.00029
+1 0.0002 1 1 -0.0066 0.0001 0.006 -0.011 0.00022
+1 -0.0002 1 1 0.0076 0.0023 0.006 -0.009 0.00032
+1 -0.0009 1 1 0.0104 0.0019 0.011 0.022 0.00000
+1 0.0011 1 1 -0.0051 0.0028 0.016 0.035 -0.00090
+1 -0.0004 1 1 0.0028 -0.0034 0.004 -0.008 0.00042
+1 -0.0002 1 1 0.0041 0.0023 0.007 0.010 -0.00007
+1 0.0002 1 1 -0.0052 -0.0018 0.012 0.007 -0.00014
+1 0.0001 1 1 -0.0035 -0.0014 0.004 -0.012 0.00008
+1 0.0001 1 1 -0.0021 0.0001 0.013 -0.017 -0.00003
+1 -0.0003 1 1 0.0030 0.0053 0.008 -0.008 -0.00001
+1 0.0003 1 1 -0.0049 0.0021 0.015 -0.011 -0.00019
+1 0.0002 1 1 -0.0010 0.0006 0.010 -0.009 -0.00002
+1 -0.0003 1 1 0.0032 -0.0007 0.005 -0.007 0.00012
+1 0.0001 1 1 -0.0042 0.0018 0.011 -0.011 -0.00006
+1 -0.0003 1 1 0.0066 -0.0017 0.003 -0.007 0.00016
+1 0.0007 1 1 -0.0102 0.0029 0.011 0.001 -0.00066
+1 0.0001 1 1 -0.0041 -0.0001 0.010 -0.030 0.00043
+1 -0.0005 1 1 0.0072 0.0006 0.009 -0.027 0.00044
+1 -0.0005 1 1 0.0070 -0.0010 0.012 0.012 -0.00005
+1 0.0002 1 1 -0.0056 -0.0016 0.003 -0.011 0.00019
+1 -0.0001 1 1 0.0041 0.0016 -0.001 -0.014 0.00032
+1 -0.0002 1 1 0.0071 0.0042 0.004 -0.006 0.00015
+1 -0.0004 1 1 0.0071 0.0046 0.013 0.012 -0.00006
+1 0.0002 1 1 -0.0037 -0.0012 0.012 0.019 -0.00031
+1 0.0002 1 1 -0.0027 0.0016 0.003 -0.011 0.00004
+1 -0.0004 1 1 0.0049 0.0019 0.005 -0.008 0.00018
+1 0.0003 1 1 -0.0064 0.0020 0.019 -0.011 -0.00011
+1 0.0001 1 1 0.0055 -0.0026 0.009 -0.019 0.00017
+1 -0.0002 1 1 0.0121 0.0000 0.005 0.006 0.00020
+1 -0.0004 1 1 0.0128 0.0010 0.006 0.024 -0.00003
+1 0.0003 1 1 -0.0052 0.0027 0.012 0.038 -0.00073
+1 0.0003 1 1 -0.0114 0.0002 0.014 0.023 -0.00005
+1 -0.0002 1 1 0.0066 -0.0013 0.010 0.015 0.00007
+1 -0.0002 1 1 0.0037 0.0007 0.010 0.028 -0.00016
+1 0.0004 1 1 -0.0047 0.0012 0.011 0.028 -0.00037
+1 -0.0002 1 1 0.0017 0.0025 0.014 0.010 0.00000
+1 0.0006 1 1 -0.0039 0.0008 0.017 0.007 -0.00018
+1 -0.0004 1 1 0.0047 -0.0008 0.014 0.013 0.00005
+1 0.0001 1 1 -0.0073 -0.0026 0.006 0.009 -0.00024
+1 -0.0004 1 1 0.0060 -0.0036 0.006 -0.034 0.00034
+1 -0.0002 1 1 0.0027 0.0032 0.006 -0.007 -0.00012
+1 0.0002 1 1 -0.0041 0.0042 0.017 -0.009 -0.00022
+1 -0.0001 1 1 0.0028 0.0017 0.004 -0.005 0.00000
+1 -0.0002 1 1 0.0019 0.0007 0.015 0.010 -0.00004
+1 0.0001 1 1 -0.0036 -0.0005 0.014 0.007 -0.00009
+1 -0.0001 1 1 0.0007 0.0016 0.002 0.009 -0.00003
+1 0.0001 1 1 -0.0024 0.0029 0.012 -0.010 0.00003
+1 -0.0001 1 1 0.0041 0.0007 0.014 -0.008 0.00016
+1 -0.0001 1 1 0.0038 0.0007 0.015 0.010 -0.00005
+1 -0.0002 1 1 0.0043 -0.0003 0.007 0.015 -0.00001
+1 0.0001 1 1 -0.0054 0.0010 0.008 0.007 -0.00005
+1 0.0001 1 1 -0.0027 0.0008 0.008 -0.010 0.00010
+1 -0.0003 1 1 0.0042 0.0005 0.007 -0.008 0.00020
+1 -0.0001 1 1 0.0040 0.0017 0.009 0.010 0.00005
+1 0.0001 1 1 -0.0080 0.0018 0.015 0.010 -0.00044
+1 0.0001 1 1 -0.0042 -0.0006 0.012 -0.029 0.00036
+1 -0.0003 1 1 0.0075 -0.0016 0.004 -0.024 0.00032
+1 -0.0001 1 1 0.0097 0.0010 0.003 -0.004 0.00001
+1 -0.0002 1 1 0.0049 0.0035 0.008 0.013 -0.00040
+1 0.0004 1 1 -0.0051 0.0039 0.015 0.013 -0.00050
+1 0.0001 1 1 -0.0085 0.0020 0.019 0.001 -0.00007
+1 0.0001 1 1 -0.0070 0.0008 0.019 -0.012 0.00014
+1 0.0001 1 1 0.0017 -0.0002 0.030 -0.020 0.00018
+1 -0.0001 1 1 0.0081 -0.0034 0.015 -0.004 0.00019
+1 -0.0002 1 1 0.0090 -0.0003 0.007 0.024 -0.00003
+1 0.0003 1 1 -0.0090 0.0019 0.013 0.026 -0.00024
+1 0.0001 1 1 -0.0064 0.0005 0.015 -0.011 0.00023
+1 -0.0001 1 1 0.0062 0.0006 0.013 -0.011 0.00019
+1 -0.0002 1 1 0.0082 -0.0001 0.011 0.030 -0.00005
+1 -0.0002 1 1 0.0033 0.0004 0.011 0.045 -0.00026
+1 0.0002 1 1 -0.0050 0.0008 0.012 0.043 -0.00034
+1 0.0001 1 1 -0.0090 0.0006 0.012 0.021 -0.00006
+1 0.0001 1 1 -0.0077 0.0007 0.012 -0.010 0.00013
+1 -0.0001 1 1 0.0038 -0.0001 0.009 -0.024 0.00025
+1 -0.0001 1 1 0.0063 0.0001 0.007 -0.012 0.00006
+1 0.0001 1 1 -0.0055 -0.0001 0.010 0.006 -0.00005
+1 0.0001 1 1 0.0001 -0.0011 0.002 -0.009 0.00012
+1 -0.0001 1 1 0.0046 0.0032 0.006 0.000 0.00009
+1 0.0001 1 1 -0.0036 -0.0013 0.013 0.006 -0.00006
+1 0.0002 1 1 -0.0017 0.0021 0.010 -0.010 -0.00005
+1 -0.0001 1 1 0.0033 0.0017 0.011 -0.007 0.00007
+1 -0.0002 1 1 0.0034 0.0000 0.011 0.011 0.00006
+1 0.0001 1 1 -0.0064 -0.0001 0.002 -0.014 -0.00001
+1 0.0002 1 1 -0.0086 0.0002 0.008 -0.012 0.00017
+1 -0.0002 1 1 0.0096 0.0020 0.006 -0.007 0.00019
+1 -0.0002 1 1 0.0102 0.0023 0.009 0.010 -0.00005
+1 0.0001 1 1 0.0050 0.0031 0.013 0.026 -0.00035
+1 0.0003 1 1 -0.0055 0.0009 0.016 0.023 -0.00020
+1 -0.0003 1 1 0.0012 0.0000 0.007 0.009 -0.00007
+1 0.0006 1 1 -0.0072 0.0018 0.009 0.003 -0.00033
+1 -0.0001 1 1 0.0057 0.0011 0.003 -0.013 0.00032
+1 -0.0003 1 1 0.0038 0.0036 0.011 0.010 -0.00024
+1 0.0008 1 1 -0.0107 0.0021 0.016 -0.002 -0.00037
+1 -0.0006 1 1 0.0084 0.0004 0.005 -0.021 0.00033
+1 0.0005 1 1 -0.0055 0.0004 0.012 0.008 -0.00029
+1 0.0004 1 1 -0.0065 -0.0010 0.013 -0.006 -0.00021
+1 0.0001 1 1 0.0038 0.0044 -0.001 -0.017 0.00007
+1 0.0001 1 1 0.0052 0.0030 0.001 -0.011 0.00010
+1 -0.0001 1 1 0.0083 0.0025 0.005 0.004 0.00012
+1 0.0001 1 1 -0.0070 0.0024 0.016 0.015 -0.00026
+1 -0.0004 1 1 0.0090 -0.0006 0.010 -0.024 0.00023
+1 0.0001 1 1 -0.0048 0.0005 0.008 0.002 -0.00021
+1 0.0002 1 1 -0.0067 0.0012 0.010 -0.013 -0.00003
+1 -0.0004 1 1 0.0062 -0.0005 0.007 -0.022 0.00028
+1 0.0005 1 1 -0.0047 0.0004 0.008 -0.010 -0.00011
+1 -0.0001 1 1 0.0077 0.0012 0.010 -0.010 0.00029
+1 -0.0001 1 1 0.0056 0.0009 0.013 0.019 -0.00033
+1 0.0001 1 1 -0.0055 0.0007 0.014 0.019 -0.00040
+1 0.0001 1 1 -0.0097 -0.0008 0.011 0.008 -0.00024
+1 -0.0001 1 1 0.0039 -0.0016 0.000 -0.019 0.00036
+1 -0.0001 1 1 0.0080 0.0011 0.001 -0.011 0.00025
+1 -0.0002 1 1 0.0042 0.0022 0.006 0.013 -0.00019
+1 0.0005 1 1 -0.0059 0.0026 0.012 0.011 -0.00033
+1 -0.0002 1 1 0.0050 0.0003 0.011 -0.001 0.00025
+1 -0.0001 1 1 0.0057 0.0008 0.012 0.015 -0.00003
+1 -0.0001 1 1 -0.0001 0.0000 0.010 0.028 -0.00014
+1 0.0003 1 1 -0.0066 0.0005 0.010 0.020 -0.00026
+1 -0.0003 1 1 0.0043 -0.0008 0.006 0.003 0.00028
+1 -0.0002 1 1 0.0057 0.0005 0.006 0.013 -0.00002
+1 -0.0001 1 1 0.0042 -0.0003 0.009 0.009 0.00006
+1 0.0003 1 1 -0.0066 0.0004 0.007 0.006 -0.00015
+1 -0.0001 1 1 0.0051 -0.0010 0.013 -0.011 0.00020
+1 0.0004 1 1 -0.0073 -0.0011 0.006 -0.008 -0.00020
+1 -0.0003 1 1 0.0068 0.0027 0.012 -0.023 0.00026
+1 0.0005 1 1 -0.0047 -0.0005 0.010 -0.010 -0.00009
+1 -0.0001 1 1 0.0076 -0.0005 0.004 -0.008 0.00026
+1 -0.0004 1 1 0.0106 0.0002 0.003 0.005 0.00018
+1 0.0004 1 1 -0.0078 0.0008 0.008 0.019 -0.00069
+1 0.0002 1 1 -0.0144 0.0015 0.009 -0.003 -0.00019
+1 -0.0002 1 1 0.0061 0.0001 0.004 -0.039 0.00053
+1 -0.0001 1 1 0.0109 0.0043 0.005 -0.024 0.00009
+1 0.0001 1 1 0.0048 0.0052 0.019 0.014 -0.00036
+1 0.0003 1 1 -0.0034 -0.0010 0.016 0.015 -0.00023
+1 -0.0009 1 1 0.0060 -0.0007 0.008 0.009 0.00028
+1 0.0007 1 1 -0.0113 0.0006 0.013 0.009 -0.00056
+1 -0.0003 1 1 0.0095 -0.0010 0.005 -0.021 0.00047
+1 -0.0002 1 1 0.0098 0.0034 0.011 0.011 -0.00030
+1 0.0003 1 1 -0.0066 -0.0010 0.016 0.017 -0.00037
+1 -0.0004 1 1 0.0052 -0.0015 0.003 -0.009 0.00035
+1 -0.0002 1 1 0.0035 0.0041 0.006 0.010 -0.00012
+1 0.0004 1 1 -0.0055 0.0006 0.011 0.005 -0.00014
+1 -0.0002 1 1 0.0077 0.0007 0.003 0.011 0.00015
+1 0.0002 1 1 -0.0056 -0.0002 0.007 0.025 -0.00009
+1 -0.0004 1 1 0.0038 0.0047 0.005 0.014 0.00007
+1 0.0003 1 1 -0.0101 0.0009 0.012 0.004 -0.00032
+1 0.0004 1 1 -0.0102 0.0004 0.012 -0.030 0.00012
+1 -0.0003 1 1 0.0070 -0.0005 0.006 -0.041 0.00047
+1 -0.0002 1 1 0.0082 0.0013 0.017 0.011 0.00007
+1 0.0004 1 1 -0.0082 -0.0011 0.010 0.020 -0.00029
+1 -0.0005 1 1 0.0043 0.0007 0.001 -0.008 0.00027
+1 0.0001 1 1 -0.0084 0.0031 0.012 -0.011 -0.00031
+1 0.0001 1 1 -0.0054 -0.0009 0.008 -0.032 0.00041
+1 -0.0001 1 1 0.0048 -0.0026 0.001 -0.033 0.00051
+1 -0.0003 1 1 0.0103 0.0038 0.004 -0.022 0.00032
+1 -0.0001 1 1 0.0026 0.0017 0.013 0.011 -0.00029
+1 0.0006 1 1 -0.0086 0.0002 0.012 0.001 -0.00031
+1 -0.0003 1 1 0.0077 0.0066 -0.002 -0.008 0.00009
+1 0.0004 1 1 -0.0081 0.0019 0.013 -0.011 -0.00016
+1 -0.0001 1 1 0.0060 0.0002 0.011 -0.023 0.00015
+1 0.0002 1 1 -0.0039 -0.0012 0.015 -0.001 -0.00001
+1 -0.0001 1 1 0.0035 -0.0008 0.006 -0.004 0.00012
+1 -0.0002 1 1 0.0045 0.0020 0.005 0.017 -0.00003
+1 0.0003 1 1 -0.0083 0.0017 0.012 0.004 -0.00014
+1 -0.0004 1 1 0.0080 -0.0001 0.010 -0.007 0.00018
+1 -0.0001 1 1 0.0049 0.0009 0.010 0.013 -0.00029
+1 0.0001 1 1 -0.0069 -0.0002 0.011 0.008 -0.00027
+1 0.0001 1 1 -0.0050 -0.0007 0.009 -0.010 0.00042
+1 -0.0005 1 1 0.0073 0.0005 0.006 -0.007 0.00040
+1 -0.0005 1 1 0.0075 0.0026 0.009 0.012 -0.00021
+1 0.0007 1 1 -0.0106 -0.0012 0.015 0.009 -0.00045
+1 -0.0002 1 1 0.0092 -0.0007 0.010 -0.003 0.00015
+1 -0.0001 1 1 0.0087 0.0003 0.009 0.016 -0.00009
+1 -0.0003 1 1 0.0055 0.0025 0.010 0.027 -0.00030
+1 0.0006 1 1 -0.0080 -0.0007 0.010 0.023 -0.00036
+1 -0.0003 1 1 0.0051 0.0022 0.007 0.012 0.00008
+1 0.0002 1 1 -0.0055 -0.0021 0.003 0.005 -0.00006
+1 -0.0004 1 1 0.0060 0.0042 0.009 0.010 0.00006
+1 0.0003 1 1 -0.0099 -0.0009 0.016 -0.006 -0.00012
+1 -0.0001 1 1 0.0052 -0.0022 0.004 -0.026 0.00044
+1 -0.0003 1 1 0.0102 0.0043 0.003 -0.015 0.00025
+1 -0.0003 1 1 0.0028 -0.0018 0.008 0.009 0.00008
+1 0.0002 1 1 -0.0063 0.0011 0.000 0.005 -0.00021
+1 -0.0003 1 1 0.0017 0.0015 0.008 0.010 -0.00004
+1 0.0001 1 1 -0.0033 0.0021 0.011 0.010 -0.00033
+1 0.0003 1 1 -0.0068 0.0013 0.012 0.002 -0.00020
+1 -0.0001 1 1 0.0033 0.0013 0.010 -0.005 -0.00023
+1 0.0007 1 1 -0.0056 -0.0005 0.008 -0.008 -0.00028
+1 -0.0004 1 1 0.0111 0.0006 0.007 -0.004 0.00030
+1 -0.0002 1 1 0.0095 0.0021 0.009 0.019 -0.00037
+1 0.0005 1 1 -0.0045 0.0014 0.012 0.025 -0.00058
+1 -0.0004 1 1 0.0055 -0.0009 0.011 -0.007 0.00037
+1 -0.0003 1 1 0.0039 -0.0011 0.009 0.010 -0.00018
+1 0.0007 1 1 -0.0068 -0.0005 0.005 0.006 -0.00033
+1 -0.0003 1 1 0.0069 -0.0004 0.008 -0.006 0.00034
+1 -0.0001 1 1 0.0069 0.0017 0.010 0.013 -0.00008
+1 0.0001 1 1 -0.0038 -0.0012 0.001 0.024 -0.00019
+1 -0.0002 1 1 0.0012 0.0040 0.010 0.010 -0.00006
+1 0.0001 1 1 -0.0039 0.0020 0.015 0.008 -0.00025
+1 0.0001 1 1 -0.0011 -0.0004 0.013 -0.010 0.00020
+1 -0.0004 1 1 0.0038 -0.0001 0.012 -0.008 0.00024
+1 0.0005 1 1 -0.0085 -0.0002 0.010 -0.011 -0.00026
+1 -0.0005 1 1 0.0071 0.0016 0.004 -0.025 0.00014
+1 0.0001 1 1 -0.0016 0.0025 0.010 -0.010 -0.00035
+1 -0.0002 1 1 0.0082 -0.0017 0.010 -0.018 0.00019
+1 0.0005 1 1 -0.0092 0.0007 0.008 -0.008 -0.00035
+1 0.0001 1 1 -0.0070 0.0011 0.009 -0.029 0.00036
+1 -0.0002 1 1 0.0095 0.0000 0.010 -0.025 0.00039
+1 -0.0005 1 1 0.0049 0.0023 0.008 -0.007 0.00018
+1 0.0004 1 1 -0.0076 0.0003 0.011 -0.012 -0.00013
+1 -0.0003 1 1 0.0065 0.0009 0.013 -0.024 0.00038
+1 -0.0004 1 1 0.0089 -0.0024 0.010 -0.006 0.00001
+1 0.0001 1 1 -0.0060 -0.0017 -0.003 0.002 -0.00023
+1 0.0003 1 1 -0.0089 0.0026 -0.002 -0.010 -0.00015
+1 0.0001 1 1 -0.0078 0.0052 0.007 -0.032 0.00012
+1 -0.0001 1 1 0.0070 0.0014 0.014 -0.035 0.00027
+1 -0.0003 1 1 0.0102 -0.0023 0.009 -0.003 -0.00001
+1 -0.0003 1 1 0.0050 -0.0014 0.006 0.012 -0.00039
+1 0.0001 1 1 -0.0045 0.0008 0.003 0.013 -0.00060
+1 0.0001 1 1 -0.0109 0.0036 0.006 0.002 -0.00026
+1 -0.0004 1 1 0.0078 0.0003 0.011 -0.024 0.00027
+1 0.0007 1 1 -0.0064 0.0002 0.009 -0.006 -0.00060
+1 -0.0008 1 1 0.0109 -0.0004 0.008 -0.019 0.00043
+1 -0.0002 1 1 0.0048 0.0025 0.013 0.012 -0.00045
+1 0.0007 1 1 -0.0095 -0.0009 0.010 0.006 -0.00052
+1 -0.0002 1 1 0.0068 0.0029 0.000 -0.017 0.00031
+1 -0.0001 1 1 0.0089 0.0038 0.010 0.013 -0.00006
+1 -0.0002 1 1 0.0037 -0.0039 0.013 0.029 -0.00024
+1 0.0002 1 1 -0.0042 -0.0014 0.009 0.028 -0.00033
+1 0.0002 1 1 -0.0076 0.0009 0.009 0.005 -0.00002
+1 0.0001 1 1 -0.0046 0.0006 0.009 -0.010 0.00016
+1 -0.0008 1 1 0.0079 0.0015 0.009 0.011 0.00007
+1 0.0001 1 1 -0.0082 0.0001 0.009 0.004 -0.00006
+1 0.0001 1 1 -0.0070 0.0003 0.006 -0.010 0.00014
+1 -0.0001 1 1 0.0052 0.0018 0.010 -0.006 0.00004
+1 -0.0002 1 1 0.0026 0.0000 0.009 0.011 -0.00008
+1 0.0004 1 1 -0.0078 0.0022 0.010 0.002 -0.00026
+1 -0.0003 1 1 0.0090 0.0003 0.009 -0.007 0.00021
+1 -0.0001 1 1 0.0073 0.0013 0.010 0.013 -0.00025
+1 0.0004 1 1 -0.0100 -0.0002 0.008 0.006 -0.00030
+1 -0.0005 1 1 0.0085 0.0009 0.013 -0.021 0.00038
+1 -0.0003 1 1 0.0052 -0.0016 0.003 0.004 0.00021
+1 0.0001 1 1 -0.0089 0.0036 0.013 0.004 -0.00028
+1 0.0001 1 1 -0.0090 -0.0014 0.012 -0.014 0.00031
+1 -0.0001 1 1 0.0049 0.0007 0.004 -0.020 0.00028
+1 -0.0002 1 1 0.0079 0.0007 0.004 -0.006 0.00008
+1 0.0001 1 1 0.0042 0.0023 0.008 0.012 -0.00024
+1 0.0001 1 1 -0.0070 0.0015 0.010 0.010 -0.00029
+1 -0.0003 1 1 0.0076 0.0000 0.007 -0.008 0.00035
+1 -0.0001 1 1 0.0086 0.0012 0.007 0.012 -0.00014
+1 -0.0001 1 1 -0.0043 0.0017 0.013 0.010 -0.00031
+1 0.0002 1 1 -0.0049 -0.0031 0.007 -0.012 0.00024
+1 -0.0003 1 1 0.0096 0.0023 0.005 0.000 0.00027
+1 -0.0001 1 1 0.0089 0.0014 0.009 0.022 -0.00018
+1 0.0002 1 1 0.0037 0.0009 0.012 0.033 -0.00043
+1 0.0001 1 1 -0.0006 -0.0004 0.010 0.035 -0.00020
+1 0.0001 1 1 -0.0043 0.0011 0.009 0.007 -0.00005
+1 0.0002 1 1 0.0003 0.0009 0.010 -0.009 0.00009
+1 -0.0007 1 1 0.0085 0.0004 0.011 0.010 0.00015
+1 0.0004 1 1 -0.0122 -0.0021 0.012 0.010 -0.00035
+1 -0.0002 1 1 0.0047 0.0035 0.003 -0.030 0.00046
+1 -0.0001 1 1 0.0002 0.0074 0.037 -0.008 0.00044
+1 -0.0013 1 1 0.0065 -0.0055 0.034 -0.003 0.00036
+1 0.0003 1 1 -0.0087 -0.0004 0.015 0.001 -0.00018
+1 0.0003 1 1 -0.0093 0.0018 0.014 -0.014 0.00004
+1 -0.0001 1 1 -0.0036 0.0039 0.017 -0.029 0.00028
+1 -0.0009 1 1 0.0066 0.0030 0.017 -0.022 0.00017
+1 -0.0004 1 1 0.0051 0.0018 0.022 -0.001 0.00018
+1 0.0002 1 1 0.0050 0.0025 0.023 0.010 -0.00007
+1 -0.0003 1 1 0.0045 0.0002 0.021 0.017 -0.00003
+1 -0.0001 1 1 -0.0071 0.0037 0.016 -0.009 -0.00004
+1 -0.0001 1 1 0.0030 0.0007 0.028 -0.033 0.00031
+1 -0.0004 1 1 0.0051 0.0030 0.012 0.010 -0.00010
+1 0.0006 1 1 -0.0094 0.0029 0.020 0.000 -0.00024
+1 -0.0008 1 1 0.0050 0.0007 0.016 -0.026 0.00037
+1 -0.0001 1 1 0.0090 0.0004 0.012 0.011 0.00015
+1 0.0002 1 1 -0.0069 0.0000 0.013 0.040 -0.00019
+1 0.0003 1 1 -0.0028 0.0040 0.019 -0.010 0.00008
+1 -0.0003 1 1 0.0064 0.0015 0.018 -0.006 0.00029
+1 -0.0004 1 1 0.0064 -0.0008 0.013 0.016 -0.00009
+1 0.0001 1 1 -0.0061 0.0012 0.011 0.017 -0.00032
+1 0.0005 1 1 -0.0101 0.0022 0.013 0.002 -0.00017
+1 -0.0003 1 1 0.0049 0.0030 0.015 -0.003 0.00004
+1 -0.0004 1 1 0.0032 0.0001 0.013 0.010 0.00005
+1 0.0006 1 1 -0.0059 0.0006 0.011 0.007 -0.00021
+1 0.0001 1 1 -0.0058 0.0020 0.013 0.007 -0.00019
+1 0.0002 1 1 -0.0057 0.0009 0.011 -0.013 0.00009
+1 -0.0003 1 1 0.0022 -0.0004 0.010 0.010 -0.00003
+1 -0.0001 1 1 -0.0064 0.0002 0.005 0.004 -0.00025
+1 0.0002 1 1 -0.0073 0.0041 0.013 -0.034 0.00012
+1 -0.0005 1 1 0.0075 0.0007 0.011 -0.040 0.00041
+1 -0.0002 1 1 0.0084 -0.0019 0.014 0.008 0.00015
+1 -0.0002 1 1 0.0076 0.0012 0.013 0.023 -0.00022
+1 0.0006 1 1 -0.0069 0.0001 0.011 0.027 -0.00042
+1 -0.0005 1 1 0.0060 0.0007 0.007 0.011 0.00029
+1 -0.0003 1 1 0.0020 -0.0010 0.009 0.027 -0.00004
+1 0.0005 1 1 -0.0087 0.0023 0.010 0.011 -0.00018
+1 -0.0001 1 1 0.0045 0.0003 0.008 -0.006 0.00015
+1 0.0003 1 1 -0.0069 0.0020 0.010 -0.010 -0.00027
+1 -0.0006 1 1 0.0076 0.0010 0.009 -0.025 0.00034
+1 0.0001 1 1 0.0000 0.0018 0.012 -0.010 0.00032
+1 -0.0004 1 1 0.0068 0.0004 0.010 -0.004 0.00037
+1 -0.0004 1 1 0.0031 0.0002 0.007 0.028 0.00009
+1 0.0003 1 1 -0.0093 0.0016 0.007 0.019 -0.00037
+1 0.0004 1 1 -0.0109 0.0021 0.009 -0.011 0.00004
+1 -0.0001 1 1 0.0060 0.0001 0.004 -0.026 0.00049
+1 -0.0003 1 1 0.0114 0.0059 0.008 -0.007 0.00003
+1 -0.0002 1 1 0.0060 -0.0004 0.016 0.015 -0.00023
+1 0.0006 1 1 -0.0042 0.0011 0.017 0.018 -0.00039
+1 -0.0001 1 1 0.0041 -0.0015 0.007 0.005 0.00032
+1 -0.0008 1 1 0.0070 0.0006 0.005 0.012 0.00016
+1 -0.0003 1 1 0.0065 0.0037 0.003 0.013 0.00002
+1 -0.0001 1 1 -0.0064 0.0000 0.014 0.013 -0.00014
+1 0.0004 1 1 -0.0116 0.0014 0.014 -0.009 -0.00019
+1 -0.0002 1 1 0.0067 0.0015 0.004 -0.032 0.00024
+1 -0.0002 1 1 0.0028 -0.0034 0.002 -0.004 0.00028
+1 0.0002 1 1 -0.0056 0.0042 0.013 -0.012 -0.00004
+1 -0.0002 1 1 0.0057 0.0000 0.016 -0.004 0.00006
+1 0.0002 1 1 -0.0049 0.0004 0.010 0.000 -0.00018
+1 -0.0002 1 1 0.0036 0.0020 0.007 -0.005 -0.00001
+1 0.0001 1 1 -0.0075 0.0016 0.014 -0.018 -0.00012
+1 0.0006 1 1 -0.0086 0.0008 0.012 -0.030 -0.00006
+1 -0.0006 1 1 0.0105 -0.0003 0.006 -0.031 0.00064
+1 0.0002 1 1 -0.0046 0.0049 0.015 0.009 -0.00072
+1 0.0001 1 1 -0.0109 0.0017 0.015 -0.003 -0.00006
+1 -0.0006 1 1 0.0080 -0.0002 0.010 -0.009 0.00045
+1 -0.0004 1 1 0.0067 0.0022 0.011 0.014 -0.00024
+1 -0.0003 1 1 0.0023 0.0017 0.006 0.010 0.00019
+1 0.0005 1 1 -0.0062 0.0022 0.012 0.003 -0.00013
+1 -0.0001 1 1 0.0051 0.0003 0.010 -0.004 0.00037
+1 -0.0004 1 1 0.0097 0.0015 0.010 0.015 0.00012
+1 -0.0001 1 1 0.0050 0.0021 0.012 0.034 -0.00029
+1 -0.0001 1 1 -0.0010 0.0004 0.012 0.038 -0.00040
+1 0.0006 1 1 -0.0099 0.0003 0.013 0.027 -0.00039
+1 -0.0003 1 1 0.0102 0.0030 0.010 0.009 0.00011
+1 -0.0001 1 1 0.0085 0.0043 0.014 0.031 -0.00018
+1 0.0001 1 1 -0.0036 0.0025 0.018 0.037 -0.00011
+1 0.0001 1 1 -0.0056 0.0007 0.011 0.017 -0.00001
+1 -0.0004 1 1 0.0043 0.0024 0.001 0.010 0.00014
+1 0.0003 1 1 -0.0068 0.0057 0.012 0.008 -0.00022
+1 0.0002 1 1 -0.0064 0.0035 0.014 -0.010 0.00010
+1 -0.0003 1 1 0.0077 0.0032 0.014 -0.004 0.00015
+1 0.0001 1 1 -0.0051 0.0019 0.015 0.018 -0.00023
+1 0.0002 1 1 -0.0075 0.0011 0.011 0.005 -0.00007
+1 -0.0003 1 1 0.0093 0.0057 0.000 0.012 0.00010
+1 -0.0001 1 1 0.0058 0.0063 0.009 0.032 -0.00025
+1 0.0002 1 1 -0.0044 0.0002 0.020 -0.012 0.00007
+1 -0.0001 1 1 0.0036 0.0012 0.028 -0.015 0.00010
+1 -0.0001 1 1 0.0032 0.0013 0.019 0.010 -0.00006
+1 0.0001 1 1 -0.0046 -0.0005 0.024 0.001 -0.00005
+1 0.0002 1 1 -0.0037 0.0001 0.022 -0.013 0.00006
+1 -0.0002 1 1 0.0031 -0.0010 0.015 -0.006 0.00003
+1 0.0002 1 1 -0.0031 0.0009 0.018 -0.010 -0.00001
+1 0.0001 1 1 -0.0061 0.0038 0.019 0.002 -0.00007
+1 -0.0001 1 1 0.0044 -0.0006 0.019 0.001 -0.00001
+1 0.0002 1 1 -0.0039 0.0003 0.006 0.006 -0.00011
+1 0.0001 1 1 -0.0007 0.0006 0.006 -0.010 0.00007
+1 -0.0001 1 1 0.0041 0.0028 0.013 -0.005 0.00014
+1 -0.0001 1 1 0.0037 0.0033 0.023 0.010 -0.00007
+1 0.0001 1 1 -0.0052 -0.0004 0.019 0.004 -0.00010
+1 -0.0001 1 1 0.0055 -0.0005 0.011 -0.003 0.00004
+1 0.0001 1 1 -0.0058 0.0005 0.010 0.003 -0.00008
+1 -0.0002 1 1 0.0058 -0.0016 0.013 -0.017 0.00012
+1 -0.0001 1 1 0.0017 -0.0007 0.006 0.011 -0.00010
+1 0.0002 1 1 -0.0045 0.0022 0.010 0.007 -0.00022
+1 0.0002 1 1 -0.0055 0.0025 0.017 -0.011 0.00003
+1 -0.0001 1 1 0.0010 -0.0001 0.007 0.009 -0.00006
+1 0.0001 1 1 -0.0039 0.0023 0.014 0.004 -0.00012
+1 0.0001 1 1 -0.0019 0.0002 0.009 -0.013 0.00006
+1 -0.0002 1 1 0.0047 0.0018 0.011 -0.007 0.00013
+1 0.0001 1 1 0.0028 0.0025 0.020 0.009 -0.00009
+1 0.0003 1 1 -0.0040 0.0002 0.014 0.006 -0.00012
+1 -0.0001 1 1 0.0039 0.0019 0.010 0.012 0.00001
+1 0.0001 1 1 -0.0036 0.0016 0.012 -0.014 0.00002
+1 -0.0001 1 1 0.0064 0.0001 0.005 -0.002 0.00007
+1 -0.0002 1 1 0.0059 0.0007 0.006 0.016 -0.00009
+1 0.0001 1 1 -0.0076 -0.0007 0.014 0.003 -0.00009
+1 -0.0001 1 1 0.0036 0.0011 0.011 -0.016 -0.00001
+1 0.0001 1 1 0.0029 -0.0013 0.007 -0.005 0.00011
+1 -0.0001 1 1 0.0045 0.0016 0.000 0.007 0.00008
+1 0.0002 1 1 -0.0067 0.0003 0.017 0.015 -0.00015
+1 -0.0001 1 1 0.0032 -0.0026 0.001 -0.006 -0.00001
+1 -0.0001 1 1 0.0010 0.0020 0.011 0.009 -0.00001
+1 0.0001 1 1 -0.0021 -0.0017 -0.003 -0.030 0.00012
+1 -0.0001 1 1 0.0045 0.0032 0.007 -0.020 0.00006
+1 -0.0001 1 1 0.0031 0.0016 0.017 -0.005 0.00003
+1 0.0001 1 1 -0.0021 -0.0008 0.015 -0.016 0.00003
+1 -0.0001 1 1 0.0035 0.0032 0.010 -0.008 0.00007
+1 0.0001 1 1 -0.0022 -0.0007 0.004 -0.014 0.00002
+1 -0.0001 1 1 0.0059 0.0007 0.012 -0.003 0.00011
+1 -0.0001 1 1 0.0025 -0.0022 0.005 0.028 -0.00013
+1 0.0001 1 1 -0.0049 0.0015 0.002 0.023 -0.00015
+1 0.0001 1 1 -0.0025 0.0044 0.015 -0.010 0.00010
+1 -0.0002 1 1 0.0025 -0.0009 0.011 0.010 0.00000
+1 0.0001 1 1 -0.0036 -0.0014 0.005 0.009 -0.00013
+1 0.0001 1 1 -0.0054 0.0005 0.008 0.001 -0.00006
+1 0.0001 1 1 -0.0019 0.0012 0.012 -0.019 0.00010
+1 -0.0001 1 1 0.0059 0.0015 0.011 -0.005 0.00005
+1 0.0001 1 1 0.0056 0.0022 0.016 0.010 -0.00004
+1 0.0001 1 1 -0.0079 -0.0003 0.004 -0.001 -0.00008
+1 -0.0001 1 1 0.0044 0.0022 0.015 -0.025 0.00012
+1 -0.0002 1 1 0.0067 -0.0016 0.010 -0.007 0.00003
+1 0.0001 1 1 -0.0074 0.0018 0.009 0.002 -0.00015
+1 -0.0003 1 1 0.0053 0.0001 0.011 -0.027 0.00020
+1 0.0001 1 1 -0.0026 -0.0013 0.009 -0.015 -0.00001
+1 -0.0002 1 1 0.0013 -0.0007 0.009 0.010 -0.00007
+1 0.0004 1 1 -0.0040 -0.0002 0.008 0.006 -0.00018
+1 -0.0001 1 1 0.0038 0.0002 0.010 0.011 0.00002
+1 0.0001 1 1 -0.0090 0.0030 0.014 -0.006 -0.00012
+1 -0.0001 1 1 0.0094 -0.0009 0.007 -0.007 0.00010
+1 0.0001 1 1 0.0051 0.0027 0.013 0.016 -0.00027
+1 0.0002 1 1 -0.0071 -0.0002 0.011 0.003 -0.00010
+1 -0.0001 1 1 0.0067 0.0013 0.007 -0.007 0.00008
+1 -0.0001 1 1 0.0043 0.0004 0.013 0.019 -0.00009
+1 0.0001 1 1 -0.0079 -0.0002 0.010 0.002 -0.00008
+1 0.0002 1 1 -0.0040 -0.0004 0.007 -0.029 0.00012
+1 -0.0001 1 1 0.0047 0.0012 0.009 -0.029 0.00023
+1 0.0003 1 1 -0.0083 -0.0010 0.009 0.001 -0.00013
+1 -0.0001 1 1 0.0052 0.0007 0.011 -0.025 0.00022
+1 -0.0002 1 1 0.0075 -0.0006 0.009 -0.009 0.00003
+1 -0.0001 1 1 0.0015 -0.0005 0.006 0.010 0.00000
+1 0.0001 1 1 -0.0040 0.0007 0.012 -0.011 0.00001
+1 -0.0001 1 1 0.0046 -0.0004 0.005 -0.002 0.00003
+1 -0.0002 1 1 0.0030 0.0008 0.006 0.009 -0.00009
+1 0.0001 1 1 -0.0048 0.0005 0.011 0.005 -0.00012
+1 -0.0001 1 1 0.0035 -0.0004 0.010 -0.002 0.00003
+1 0.0001 1 1 -0.0050 0.0003 0.011 0.003 -0.00021
+1 0.0001 1 1 -0.0079 -0.0009 0.008 -0.013 -0.00007
+1 0.0001 1 1 -0.0048 0.0008 0.009 -0.034 0.00014
+1 -0.0001 1 1 0.0061 -0.0002 0.007 -0.019 0.00004
+1 0.0001 1 1 -0.0027 0.0030 0.013 -0.012 0.00000
+1 -0.0001 1 1 0.0060 -0.0014 0.007 0.015 0.00000
+1 -0.0001 1 1 0.0034 -0.0012 0.003 0.030 -0.00011
+1 0.0001 1 1 -0.0060 0.0030 0.012 0.023 -0.00014
+1 0.0001 1 1 -0.0015 -0.0024 0.008 -0.010 0.00015
+1 -0.0001 1 1 0.0040 -0.0025 -0.001 -0.007 0.00017
+1 -0.0003 1 1 0.0016 0.0017 0.006 0.010 0.00003
+1 0.0003 1 1 -0.0036 0.0013 0.010 0.008 -0.00019
+1 0.0001 1 1 -0.0002 0.0008 0.010 -0.009 0.00007
+1 -0.0001 1 1 0.0030 -0.0002 0.007 -0.007 0.00005
+1 0.0001 1 1 -0.0022 0.0000 0.008 -0.012 0.00001
+1 0.0002 1 1 -0.0042 0.0001 0.010 0.003 -0.00007
+1 -0.0001 1 1 0.0030 0.0005 0.007 -0.007 0.00008
+1 -0.0001 1 1 0.0019 0.0009 0.012 0.010 -0.00005
+1 0.0001 1 1 -0.0037 -0.0012 0.009 0.007 -0.00011
+1 -0.0001 1 1 -0.0009 -0.0010 0.001 -0.009 0.00008
+1 0.0001 1 1 -0.0007 0.0002 0.010 -0.010 0.00000
+1 -0.0002 1 1 0.0027 -0.0001 0.008 -0.004 0.00004
+1 -0.0001 1 1 0.0043 0.0010 0.011 -0.024 0.00009
+1 -0.0001 1 1 -0.0019 -0.0016 0.004 -0.017 0.00004
+1 0.0002 1 1 -0.0033 0.0015 0.008 -0.027 -0.00003
+1 -0.0001 1 1 0.0082 0.0009 0.006 0.024 -0.00006
+1 0.0002 1 1 -0.0098 -0.0005 0.011 0.010 -0.00009
+1 0.0001 1 1 -0.0067 -0.0012 0.007 -0.011 0.00021
+1 -0.0001 1 1 0.0069 -0.0003 0.001 -0.009 0.00018
+1 -0.0002 1 1 0.0083 0.0016 0.003 0.001 0.00004
+1 0.0001 1 1 -0.0051 0.0026 0.017 0.012 -0.00020
+1 0.0002 1 1 -0.0070 0.0005 0.018 0.003 -0.00010
+1 -0.0001 1 1 0.0039 -0.0014 0.012 -0.011 0.00020
+1 -0.0001 1 1 0.0060 -0.0012 0.010 -0.003 0.00009
+1 -0.0001 1 1 0.0052 -0.0012 0.009 0.011 -0.00005
+1 -0.0002 1 1 0.0013 0.0004 0.003 0.010 -0.00004
+1 0.0002 1 1 -0.0046 0.0016 0.007 0.006 -0.00018
+1 -0.0001 1 1 0.0032 0.0033 0.007 -0.005 -0.00001
+1 0.0001 1 1 -0.0003 -0.0016 0.003 -0.009 0.00005
+1 -0.0001 1 1 0.0036 0.0008 0.003 -0.004 0.00010
+1 0.0003 1 1 -0.0048 -0.0034 0.014 0.006 -0.00014
+1 -0.0001 1 1 0.0034 0.0002 0.008 0.011 -0.00001
+1 -0.0001 1 1 0.0026 0.0001 0.006 0.011 0.00003
+1 -0.0002 1 1 0.0072 0.0002 0.009 0.010 -0.00003
+1 -0.0001 1 1 0.0001 0.0007 0.010 0.027 -0.00021
+1 0.0003 1 1 -0.0050 -0.0012 0.010 0.023 -0.00031
+1 0.0001 1 1 -0.0035 0.0003 0.002 -0.011 0.00005
+1 -0.0001 1 1 0.0037 0.0031 0.010 -0.011 0.00011
+1 0.0001 1 1 0.0044 0.0034 0.021 0.004 -0.00001
+1 -0.0001 1 1 0.0043 -0.0048 0.016 0.015 -0.00001
+1 0.0001 1 1 -0.0061 -0.0003 0.002 0.006 -0.00006
+1 0.0001 1 1 -0.0044 0.0024 0.008 -0.012 0.00009
+1 -0.0001 1 1 0.0062 0.0001 0.015 -0.005 0.00009
+1 -0.0002 1 1 0.0050 -0.0025 0.009 0.012 -0.00008
+1 0.0001 1 1 -0.0075 0.0027 0.004 0.004 -0.00016
+1 0.0001 1 1 -0.0074 0.0027 0.014 -0.030 0.00009
+1 -0.0001 1 1 0.0055 -0.0010 0.008 -0.038 0.00007
+1 -0.0001 1 1 0.0019 -0.0011 0.010 0.010 -0.00007
+1 0.0002 1 1 -0.0039 -0.0002 0.008 0.005 -0.00012
+1 -0.0002 1 1 0.0050 -0.0016 0.006 0.011 -0.00001
+1 0.0002 1 1 -0.0042 0.0023 0.009 0.015 -0.00032
+1 0.0002 1 1 -0.0068 0.0018 0.012 0.006 -0.00007
+1 -0.0001 1 1 0.0060 0.0003 0.012 -0.004 0.00009
+1 -0.0001 1 1 0.0047 -0.0013 0.010 0.012 -0.00009
+1 -0.0002 1 1 0.0060 -0.0008 0.004 -0.027 0.00020
+1 0.0001 1 1 -0.0033 0.0020 0.010 0.000 -0.00017
+1 0.0001 1 1 -0.0051 -0.0009 0.008 -0.009 -0.00006
+1 -0.0002 1 1 0.0064 0.0014 0.009 -0.006 0.00005
+1 0.0002 1 1 -0.0043 -0.0019 0.010 0.006 -0.00015
+1 -0.0002 1 1 0.0042 0.0002 0.016 0.014 0.00000
+1 0.0001 1 1 -0.0055 -0.0011 0.005 0.006 -0.00006
+1 0.0001 1 1 -0.0057 0.0017 0.009 -0.012 0.00003
+1 0.0002 1 1 -0.0045 -0.0001 0.009 0.007 -0.00008
+1 -0.0003 1 1 0.0054 0.0023 0.006 0.012 0.00006
+1 0.0002 1 1 -0.0074 -0.0009 0.009 -0.004 -0.00006
+1 0.0002 1 1 -0.0052 -0.0044 0.004 0.002 -0.00006
+1 -0.0001 1 1 0.0037 -0.0011 0.012 -0.003 0.00008
+1 0.0001 1 1 -0.0048 0.0013 0.012 0.014 -0.00025
+1 -0.0001 1 1 0.0036 0.0004 0.004 -0.008 0.00017
+1 -0.0002 1 1 0.0015 0.0019 0.012 0.011 -0.00009
+1 0.0001 1 1 -0.0037 0.0001 0.012 -0.013 -0.00006
+1 0.0002 1 1 -0.0028 0.0001 0.006 -0.013 -0.00002
+1 0.0001 1 1 -0.0051 0.0001 0.010 -0.007 -0.00002
+1 0.0001 1 1 0.0038 0.0019 0.014 -0.002 -0.00001
+1 -0.0002 1 1 0.0032 -0.0011 0.010 0.011 -0.00004
+1 0.0001 1 1 -0.0065 -0.0005 0.007 0.004 -0.00019
+1 0.0001 1 1 -0.0039 -0.0002 0.007 -0.030 0.00020
+1 -0.0001 1 1 0.0012 -0.0018 0.005 0.010 -0.00009
+1 0.0002 1 1 -0.0044 0.0045 0.012 0.007 -0.00031
+1 0.0001 1 1 -0.0052 -0.0029 0.006 -0.013 0.00013
+1 -0.0001 1 1 0.0054 0.0016 0.006 -0.010 0.00014
+1 -0.0001 1 1 0.0050 -0.0003 0.004 0.021 0.00001
+1 -0.0001 1 1 0.0032 0.0009 0.005 0.029 -0.00011
+1 0.0001 1 1 -0.0050 0.0022 0.015 0.025 -0.00015
+1 -0.0002 1 1 0.0032 0.0021 0.004 0.010 0.00002
+1 0.0002 1 1 -0.0041 -0.0016 0.008 0.005 -0.00006
+1 0.0001 1 1 -0.0020 0.0033 0.010 -0.011 0.00004
+1 0.0001 1 1 0.0042 0.0006 0.017 -0.008 0.00014
+1 -0.0001 1 1 0.0060 -0.0009 0.015 0.000 0.00011
+1 -0.0001 1 1 0.0053 -0.0009 0.012 0.013 -0.00006
+1 0.0001 1 1 -0.0070 -0.0005 0.006 0.005 -0.00009
+1 0.0001 1 1 -0.0034 0.0032 0.016 -0.029 0.00018
+1 -0.0002 1 1 0.0060 0.0053 0.023 -0.020 0.00010
+1 0.0006 1 1 -0.0064 0.0029 0.029 -0.013 -0.00008
+1 -0.0001 1 1 0.0054 0.0028 0.026 -0.020 0.00016
+1 -0.0001 1 1 0.0073 0.0021 0.024 0.005 -0.00001
+1 -0.0002 1 1 0.0062 0.0025 0.024 0.015 -0.00017
+1 0.0005 1 1 -0.0096 -0.0014 0.010 -0.009 -0.00010
+1 -0.0001 1 1 0.0041 0.0058 0.017 -0.033 0.00012
+1 -0.0001 1 1 0.0052 0.0037 0.019 -0.025 0.00004
+1 0.0002 1 1 -0.0024 0.0036 0.014 -0.011 -0.00002
+1 -0.0001 1 1 0.0047 0.0011 0.012 0.012 -0.00002
+1 0.0002 1 1 -0.0070 0.0033 0.014 -0.002 -0.00007
+1 -0.0001 1 1 0.0048 0.0032 0.015 -0.023 0.00023
+1 -0.0001 1 1 0.0080 0.0020 0.013 -0.010 0.00011
+1 -0.0002 1 1 0.0072 0.0019 0.012 0.011 -0.00008
+1 0.0003 1 1 -0.0073 0.0027 0.016 0.008 -0.00014
+1 0.0002 1 1 -0.0063 0.0019 0.015 -0.010 0.00012
+1 -0.0001 1 1 0.0062 0.0025 0.012 -0.005 0.00008
+1 0.0002 1 1 -0.0050 0.0016 0.017 0.005 -0.00010
+1 0.0001 1 1 -0.0031 0.0017 0.014 -0.013 0.00008
+1 -0.0001 1 1 0.0036 0.0029 0.008 -0.011 0.00009
+1 -0.0002 1 1 0.0022 0.0012 0.015 0.011 -0.00003
+1 0.0003 1 1 -0.0043 0.0008 0.012 0.007 -0.00012
+1 0.0001 1 1 0.0002 0.0039 0.011 -0.009 0.00007
+1 -0.0001 1 1 0.0062 0.0018 0.014 0.017 0.00003
+1 0.0002 1 1 -0.0084 0.0008 0.012 0.017 -0.00023
+1 -0.0002 1 1 0.0067 0.0037 0.005 0.002 0.00010
+1 0.0002 1 1 -0.0037 0.0031 0.018 0.021 -0.00011
+1 -0.0001 1 1 0.0004 0.0018 0.018 0.011 0.00012
+1 -0.0002 1 1 0.0046 0.0026 0.006 0.013 0.00007
+1 0.0002 1 1 -0.0086 0.0021 0.011 0.004 -0.00017
+1 -0.0002 1 1 0.0078 0.0030 0.008 -0.030 0.00024
+1 -0.0002 1 1 0.0066 0.0032 0.014 0.015 -0.00010
+1 0.0002 1 1 -0.0048 0.0015 0.016 0.019 -0.00018
+1 -0.0001 1 1 0.0063 0.0016 0.000 0.015 0.00005
+1 -0.0001 1 1 0.0058 0.0030 0.003 0.024 -0.00007
+1 0.0001 1 1 -0.0102 0.0037 0.014 0.017 -0.00017
+1 0.0001 1 1 -0.0111 0.0023 0.014 0.001 -0.00002
+1 -0.0002 1 1 0.0073 0.0019 0.009 -0.024 0.00016
+1 0.0002 1 1 -0.0065 0.0019 0.014 -0.003 -0.00005
+1 -0.0001 1 1 0.0041 0.0006 0.004 -0.016 0.00016
+1 -0.0001 1 1 0.0078 0.0015 0.003 0.009 0.00004
+1 0.0002 1 1 -0.0080 0.0005 0.017 0.013 -0.00015
+1 0.0002 1 1 -0.0118 0.0030 0.012 -0.010 -0.00008
+1 0.0002 1 1 -0.0053 0.0019 0.011 -0.045 0.00028
+1 -0.0001 1 1 0.0082 0.0006 0.004 -0.040 0.00033
+1 -0.0002 1 1 0.0115 0.0030 0.002 -0.024 0.00004
+1 -0.0003 1 1 0.0010 0.0063 0.012 0.011 -0.00028
+1 0.0005 1 1 -0.0070 0.0066 0.020 0.006 -0.00048
+1 -0.0003 1 1 0.0116 0.0009 0.003 0.008 0.00007
+1 -0.0002 1 1 0.0076 0.0021 0.003 0.030 -0.00032
+1 -0.0001 1 1 0.0006 0.0022 0.004 0.037 -0.00047
+1 0.0002 1 1 -0.0090 0.0055 0.012 0.029 -0.00044
+1 0.0001 1 1 -0.0134 0.0031 0.018 0.002 -0.00004
+1 -0.0004 1 1 0.0051 0.0005 0.011 -0.043 0.00042
+1 -0.0002 1 1 0.0035 0.0018 0.007 -0.004 0.00004
+1 0.0005 1 1 -0.0077 -0.0021 0.022 -0.010 0.00003
+1 -0.0008 1 1 0.0123 0.0003 0.016 0.013 0.00012
+1 0.0002 1 1 0.0056 0.0016 0.019 0.038 -0.00045
+1 -0.0002 1 1 -0.0053 -0.0022 0.008 0.032 -0.00012
+1 0.0006 1 1 -0.0123 0.0030 0.011 0.003 -0.00017
+1 -0.0003 1 1 0.0080 0.0005 0.016 -0.021 0.00029
+1 -0.0004 1 1 0.0101 0.0010 0.018 -0.002 0.00002
+1 0.0001 1 1 0.0048 0.0018 0.021 0.017 -0.00030
+1 0.0001 1 1 -0.0040 -0.0004 0.011 0.025 -0.00028
+1 0.0003 1 1 -0.0079 0.0014 0.014 0.014 -0.00018
+1 -0.0005 1 1 0.0073 0.0030 0.014 -0.007 0.00016
+1 0.0001 1 1 0.0035 -0.0009 0.012 0.011 -0.00023
+1 0.0004 1 1 -0.0058 -0.0049 0.017 0.007 -0.00022
+1 0.0001 1 1 -0.0001 0.0000 0.011 -0.009 0.00010
+1 -0.0006 1 1 0.0033 -0.0002 0.010 -0.007 0.00020
+1 0.0002 1 1 -0.0007 -0.0010 0.013 -0.009 0.00006
+1 -0.0005 1 1 0.0078 -0.0004 0.008 0.010 0.00010
+1 -0.0002 1 1 0.0003 0.0025 0.012 0.027 -0.00028
+1 0.0004 1 1 -0.0051 0.0031 0.016 0.024 -0.00034
+1 0.0002 1 1 -0.0051 -0.0039 0.013 -0.012 0.00009
+1 -0.0002 1 1 0.0056 0.0016 0.011 -0.011 0.00018
+1 -0.0003 1 1 0.0010 -0.0012 0.010 0.010 -0.00015
+1 0.0001 1 1 -0.0052 -0.0016 0.006 0.006 -0.00031
+1 0.0001 1 1 -0.0082 0.0032 0.012 -0.006 -0.00013
+1 0.0002 1 1 -0.0088 0.0004 0.012 -0.019 -0.00001
+1 -0.0004 1 1 0.0095 0.0023 0.010 -0.019 0.00025
+1 -0.0001 1 1 0.0058 -0.0008 0.013 0.015 -0.00020
+1 0.0001 1 1 -0.0044 -0.0003 0.008 0.004 -0.00003
+1 -0.0002 1 1 0.0041 -0.0001 0.013 0.012 0.00001
+1 0.0002 1 1 -0.0059 -0.0005 0.009 0.004 -0.00007
+1 -0.0004 1 1 0.0050 -0.0012 0.008 -0.008 0.00023
+1 0.0001 1 1 -0.0016 0.0004 0.006 -0.009 0.00002
+1 -0.0002 1 1 0.0050 0.0018 0.010 -0.004 0.00015
+1 -0.0002 1 1 0.0040 0.0015 0.014 0.010 -0.00008
+1 0.0003 1 1 -0.0062 0.0001 0.014 0.005 -0.00020
+1 0.0002 1 1 -0.0042 0.0004 0.015 -0.014 0.00013
+1 -0.0002 1 1 0.0040 -0.0019 0.008 -0.015 0.00026
+1 -0.0002 1 1 0.0031 0.0010 0.009 0.010 0.00000
+1 0.0002 1 1 -0.0052 -0.0004 0.012 0.004 -0.00010
+1 -0.0002 1 1 0.0046 -0.0022 0.005 -0.007 0.00025
+1 -0.0001 1 1 -0.0034 -0.0013 0.006 0.012 -0.00013
+1 0.0002 1 1 -0.0020 0.0016 0.015 -0.010 -0.00004
+1 -0.0004 1 1 0.0048 -0.0010 0.011 -0.006 0.00016
+1 0.0001 1 1 -0.0059 0.0007 0.009 -0.008 -0.00002
+1 -0.0002 1 1 0.0081 0.0021 0.014 -0.002 0.00014
+1 -0.0002 1 1 0.0058 -0.0013 0.012 0.016 -0.00019
+1 0.0002 1 1 -0.0048 0.0008 0.009 0.016 -0.00016
+1 0.0001 1 1 0.0043 0.0004 0.011 -0.008 0.00006
+1 -0.0003 1 1 0.0062 -0.0007 0.009 0.003 0.00009
+1 -0.0001 1 1 0.0045 0.0005 0.009 0.013 -0.00019
+1 0.0005 1 1 -0.0117 -0.0018 0.010 -0.014 -0.00013
+1 -0.0001 1 1 0.0067 -0.0005 0.013 -0.023 0.00010
+1 -0.0004 1 1 0.0023 -0.0005 0.006 0.011 -0.00003
+1 0.0004 1 1 -0.0110 0.0006 0.007 -0.003 -0.00033
+1 0.0001 1 1 -0.0089 0.0021 0.008 -0.030 0.00031
+1 -0.0002 1 1 0.0103 -0.0019 0.009 -0.024 0.00026
+1 0.0001 1 1 0.0066 0.0009 0.010 0.023 -0.00024
+1 -0.0001 1 1 0.0034 0.0008 0.011 0.031 -0.00019
+1 0.0001 1 1 -0.0033 -0.0007 0.012 0.031 -0.00026
+1 0.0002 1 1 -0.0066 -0.0009 0.010 0.022 -0.00015
+1 0.0001 1 1 0.0024 0.0049 0.012 0.009 -0.00005
+1 0.0002 1 1 -0.0071 -0.0007 0.007 -0.010 -0.00004
+1 -0.0002 1 1 0.0052 0.0013 0.009 -0.024 0.00024
+1 -0.0003 1 1 0.0035 0.0020 0.004 0.013 0.00007
+1 0.0001 1 1 -0.0058 -0.0008 0.013 0.006 -0.00011
+1 0.0002 1 1 -0.0045 -0.0060 0.011 -0.013 0.00011
+1 -0.0002 1 1 0.0035 0.0004 0.009 0.010 0.00008
+1 0.0001 1 1 -0.0055 0.0011 0.007 -0.014 0.00000
+1 -0.0002 1 1 0.0049 -0.0014 0.008 -0.006 0.00013
+1 0.0005 1 1 -0.0073 -0.0005 0.011 0.002 -0.00036
+1 0.0001 1 1 -0.0005 0.0010 0.011 -0.010 0.00000
+1 -0.0001 1 1 0.0034 -0.0002 0.011 -0.005 0.00010
+1 0.0001 1 1 -0.0029 -0.0009 0.007 -0.012 -0.00001
+1 0.0001 1 1 -0.0019 -0.0010 0.005 -0.010 0.00003
+1 -0.0003 1 1 0.0007 0.0021 0.011 0.009 -0.00003
+1 0.0003 1 1 -0.0066 -0.0004 0.010 -0.001 -0.00017
+1 -0.0001 1 1 0.0045 0.0022 0.010 -0.013 0.00002
+1 -0.0001 1 1 0.0035 -0.0001 0.009 0.013 -0.00004
+1 0.0001 1 1 -0.0050 0.0002 0.008 0.005 -0.00006
+1 -0.0002 1 1 0.0048 0.0007 0.007 -0.004 0.00005
+1 -0.0003 1 1 0.0032 -0.0002 0.010 -0.007 0.00011
+1 0.0001 1 1 -0.0034 0.0003 0.005 -0.012 -0.00001
+1 0.0001 1 1 0.0052 0.0019 0.010 0.014 -0.00003
+1 -0.0002 1 1 0.0051 0.0003 0.010 0.022 0.00000
+1 0.0002 1 1 -0.0079 -0.0004 0.011 0.015 -0.00022
+1 -0.0002 1 1 0.0029 -0.0008 0.007 0.010 -0.00006
+1 0.0004 1 1 -0.0067 0.0008 0.008 0.004 -0.00026
+1 -0.0003 1 1 0.0061 -0.0003 0.007 -0.006 0.00015
+1 0.0001 1 1 0.0010 0.0014 0.011 0.011 -0.00017
+1 0.0001 1 1 -0.0035 -0.0005 0.009 0.007 -0.00012
+1 -0.0002 1 1 -0.0017 0.0021 0.008 -0.009 0.00004
+1 -0.0002 1 1 0.0050 0.0000 0.012 0.002 0.00003
+1 0.0002 1 1 -0.0047 -0.0013 0.008 0.005 -0.00010
+1 0.0001 1 1 -0.0043 0.0002 0.008 0.007 -0.00003
+1 -0.0001 1 1 0.0043 0.0000 0.005 0.006 0.00006
+1 0.0001 1 1 -0.0047 0.0040 0.005 0.006 -0.00003
+1 0.0002 1 1 -0.0009 0.0011 0.009 -0.010 0.00009
+1 -0.0001 1 1 0.0052 -0.0002 0.009 -0.004 0.00018
+1 0.0001 1 1 -0.0038 0.0007 0.010 0.015 -0.00020
+1 -0.0002 1 1 -0.0006 0.0000 0.009 -0.009 0.00013
+1 -0.0003 1 1 0.0030 -0.0002 0.008 -0.007 0.00023
+1 -0.0002 1 1 0.0013 -0.0007 0.010 0.010 -0.00006
+1 0.0001 1 1 -0.0044 0.0009 0.011 0.007 -0.00023
+1 -0.0001 1 1 0.0035 0.0011 0.008 -0.008 0.00010
+1 -0.0002 1 1 0.0040 0.0012 0.007 0.014 0.00003
+1 -0.0002 1 1 0.0056 0.0009 0.009 0.012 0.00009
+1 -0.0001 1 1 0.0022 0.0004 0.011 0.028 -0.00013
+1 0.0003 1 1 -0.0040 0.0011 0.013 0.027 -0.00030
+1 0.0001 1 1 -0.0042 0.0015 0.008 -0.012 -0.00002
+1 -0.0003 1 1 0.0055 -0.0008 0.008 -0.007 0.00010
+1 0.0001 1 1 -0.0033 0.0007 0.011 0.004 -0.00012
+1 0.0001 1 1 -0.0056 -0.0012 0.006 -0.012 -0.00003
+1 -0.0002 1 1 0.0061 -0.0007 0.007 -0.006 0.00005
+1 0.0002 1 1 -0.0053 0.0011 0.011 0.006 -0.00034
+1 -0.0002 1 1 0.0032 0.0004 0.008 -0.007 0.00003
+1 -0.0001 1 1 0.0017 0.0004 0.007 0.011 -0.00003
+1 -0.0002 1 1 0.0037 -0.0006 0.010 -0.006 0.00011
+1 -0.0002 1 1 0.0022 0.0006 0.010 0.010 -0.00007
+1 0.0003 1 1 -0.0036 -0.0010 0.012 0.008 -0.00016
+1 -0.0001 1 1 0.0036 0.0009 0.007 0.011 0.00004
+1 0.0001 1 1 -0.0038 0.0000 0.006 0.007 -0.00012
+1 -0.0001 1 1 0.0014 0.0024 0.006 0.010 -0.00003
+1 0.0001 1 1 -0.0040 0.0008 0.008 -0.002 -0.00005
+1 -0.0003 1 1 0.0026 -0.0005 0.010 0.010 0.00002
+1 0.0002 1 1 -0.0058 0.0003 0.011 0.007 -0.00027
+1 -0.0001 1 1 -0.0026 -0.0006 0.009 -0.027 0.00004
+1 -0.0001 1 1 0.0066 0.0001 0.008 -0.023 0.00026
+1 -0.0002 1 1 0.0062 0.0018 0.013 0.011 -0.00015
+1 0.0003 1 1 -0.0083 -0.0007 0.013 0.006 -0.00023
+1 0.0002 1 1 -0.0067 -0.0005 0.011 -0.014 0.00018
+1 -0.0003 1 1 0.0073 0.0004 0.008 -0.002 0.00006
+1 -0.0001 1 1 -0.0035 0.0007 0.007 0.012 -0.00005
+1 0.0002 1 1 -0.0055 -0.0013 0.005 0.005 -0.00013
+1 -0.0002 1 1 0.0030 0.0013 0.006 -0.008 0.00017
+1 -0.0001 1 1 0.0006 0.0008 0.014 0.010 -0.00006
+1 0.0003 1 1 -0.0047 -0.0032 0.009 0.004 -0.00017
+1 -0.0002 1 1 0.0010 0.0008 0.011 0.010 -0.00006
+1 -0.0001 1 1 0.0040 -0.0004 0.008 0.014 0.00000
+1 0.0001 1 1 -0.0047 0.0012 0.008 0.005 -0.00007
+1 0.0001 1 1 -0.0025 -0.0014 0.009 -0.010 0.00008
+1 -0.0002 1 1 0.0038 0.0023 0.007 -0.008 0.00013
+1 0.0001 1 1 -0.0051 0.0002 0.009 -0.012 -0.00005
+1 -0.0003 1 1 0.0047 0.0014 0.010 -0.024 0.00022
+1 -0.0001 1 1 0.0034 -0.0020 0.009 -0.004 0.00003
+1 -0.0004 1 1 0.0027 0.0015 0.010 0.011 0.00008
+1 0.0004 1 1 -0.0083 -0.0027 0.010 0.001 -0.00019
+1 0.0001 1 1 0.0040 -0.0011 0.007 -0.014 0.00006
+1 -0.0002 1 1 0.0059 -0.0005 0.006 -0.004 0.00009
+1 -0.0003 1 1 0.0033 0.0024 0.009 0.011 -0.00014
+1 0.0005 1 1 -0.0068 -0.0020 0.011 0.005 -0.00022
+1 -0.0002 1 1 -0.0043 -0.0024 0.005 -0.010 0.00025
+1 0.0002 1 1 -0.0050 0.0039 0.003 -0.021 -0.00003
+1 0.0001 1 1 -0.0035 0.0021 0.006 -0.028 0.00016
+1 -0.0002 1 1 0.0052 0.0006 0.007 -0.025 0.00022
+1 0.0002 1 1 -0.0032 -0.0017 0.004 -0.010 0.00000
+1 0.0001 1 1 0.0041 0.0016 0.014 -0.008 0.00010
+1 0.0001 1 1 -0.0050 -0.0016 0.002 -0.009 -0.00009
+1 -0.0001 1 1 0.0085 -0.0013 0.006 -0.006 0.00008
+1 -0.0003 1 1 0.0040 0.0021 0.011 0.028 -0.00019
+1 0.0004 1 1 -0.0063 -0.0009 0.010 0.026 -0.00037
+1 -0.0002 1 1 0.0043 0.0029 0.005 -0.007 0.00016
+1 0.0003 1 1 -0.0042 0.0029 0.008 0.006 -0.00014
+1 -0.0001 1 1 0.0019 0.0000 0.007 0.010 -0.00001
+1 0.0003 1 1 -0.0055 0.0005 0.012 -0.011 -0.00010
+1 -0.0002 1 1 0.0051 -0.0006 0.004 0.000 0.00000
+1 0.0004 1 1 -0.0051 0.0006 0.007 0.004 -0.00026
+1 -0.0001 1 1 0.0059 0.0018 0.009 -0.003 0.00014
+1 -0.0001 1 1 0.0066 -0.0029 0.012 0.012 -0.00001
+1 -0.0002 1 1 0.0028 -0.0008 0.008 0.027 -0.00016
+1 0.0001 1 1 -0.0062 0.0002 0.009 0.006 -0.00001
+1 0.0001 1 1 -0.0043 -0.0010 0.007 -0.011 0.00009
+1 -0.0001 1 1 0.0037 -0.0015 0.014 -0.002 0.00003
+1 -0.0001 1 1 0.0044 0.0011 0.008 -0.007 0.00006
+1 -0.0003 1 1 0.0035 -0.0008 0.010 0.011 0.00009
+1 0.0004 1 1 -0.0060 0.0000 0.009 0.009 -0.00026
+1 0.0002 1 1 -0.0016 -0.0005 0.012 -0.010 -0.00002
+1 -0.0002 1 1 0.0036 -0.0009 0.009 -0.007 0.00015
+1 0.0002 1 1 -0.0012 0.0015 0.005 -0.009 0.00001
+1 -0.0002 1 1 0.0026 0.0011 0.008 -0.007 0.00011
+1 -0.0002 1 1 0.0035 0.0006 0.006 -0.007 0.00014
+1 0.0001 1 1 -0.0049 -0.0003 0.010 -0.014 -0.00003
+1 -0.0003 1 1 0.0040 0.0003 0.004 -0.006 0.00007
+1 0.0003 1 1 -0.0067 0.0001 0.005 -0.013 -0.00013
+1 -0.0002 1 1 0.0044 0.0022 0.007 -0.025 0.00022
+1 0.0001 1 1 0.0057 0.0012 0.013 -0.009 0.00002
+1 -0.0004 1 1 0.0070 -0.0003 0.014 0.013 -0.00005
+1 0.0003 1 1 -0.0077 -0.0015 0.010 0.009 -0.00017
+1 -0.0002 1 1 0.0079 0.0013 0.009 0.016 0.00000
+1 -0.0001 1 1 0.0040 0.0006 0.012 0.033 -0.00015
+1 0.0001 1 1 -0.0053 -0.0002 0.012 0.031 -0.00023
+1 0.0001 1 1 -0.0081 -0.0003 0.011 0.018 -0.00012
+1 -0.0001 1 1 0.0050 0.0011 0.014 -0.005 0.00018
+1 0.0003 1 1 -0.0048 0.0007 0.019 0.005 -0.00005
+1 -0.0003 1 1 0.0070 0.0010 0.010 0.015 0.00007
+1 0.0002 1 1 -0.0084 0.0006 0.023 0.017 -0.00021
+1 -0.0004 1 1 0.0070 -0.0010 0.008 -0.004 0.00017
+1 0.0001 1 1 -0.0035 0.0013 0.020 0.016 -0.00016
+1 -0.0002 1 1 0.0029 0.0002 0.013 -0.007 0.00015
+1 0.0003 1 1 -0.0080 0.0008 0.019 -0.003 -0.00011
+1 0.0001 1 1 0.0044 0.0017 0.008 -0.013 -0.00001
+1 -0.0002 1 1 0.0037 0.0032 0.017 0.010 -0.00005
+1 0.0001 1 1 -0.0044 0.0008 0.019 0.005 -0.00009
+1 -0.0001 1 1 0.0041 0.0023 0.005 -0.004 0.00008
+1 -0.0001 1 1 0.0043 0.0026 0.010 0.011 -0.00003
+1 -0.0001 1 1 -0.0034 0.0004 0.015 0.008 -0.00002
+1 0.0002 1 1 -0.0041 0.0006 0.015 0.003 -0.00006
+1 -0.0002 1 1 0.0043 0.0019 0.011 0.012 0.00001
+1 0.0002 1 1 -0.0069 -0.0001 0.017 0.005 -0.00013
+1 0.0002 1 1 -0.0057 0.0006 0.016 -0.014 0.00010
+1 -0.0002 1 1 0.0070 -0.0002 0.005 -0.006 0.00010
+1 -0.0001 1 1 0.0060 0.0022 0.006 0.014 -0.00009
+1 0.0002 1 1 -0.0078 0.0000 0.008 -0.008 -0.00003
+1 -0.0001 1 1 0.0078 0.0029 0.009 -0.017 0.00019
+1 -0.0001 1 1 0.0075 0.0032 0.017 0.013 -0.00006
+1 0.0002 1 1 -0.0066 -0.0003 0.015 0.017 -0.00014
+1 -0.0001 1 1 0.0042 0.0038 0.005 -0.001 0.00005
+1 0.0002 1 1 -0.0036 -0.0018 0.018 0.006 -0.00007
+1 -0.0001 1 1 0.0058 -0.0009 0.003 0.015 0.00006
+1 -0.0001 1 1 0.0036 0.0017 0.003 0.031 -0.00010
+1 0.0002 1 1 -0.0063 0.0019 0.009 0.023 -0.00015
+1 -0.0003 1 1 0.0071 0.0026 0.013 0.013 0.00012
+1 -0.0002 1 1 0.0043 0.0023 0.018 0.028 -0.00016
+1 0.0002 1 1 -0.0059 -0.0006 0.017 0.023 -0.00019
+1 -0.0002 1 1 0.0062 0.0014 0.004 0.015 0.00013
+1 -0.0001 1 1 0.0027 0.0014 0.007 0.031 -0.00017
+1 0.0001 1 1 -0.0008 0.0023 0.010 0.033 -0.00023
+1 0.0001 1 1 -0.0065 0.0016 0.014 0.013 -0.00006
+1 -0.0002 1 1 0.0066 0.0008 0.005 0.013 0.00008
+1 0.0001 1 1 -0.0058 0.0014 0.019 0.022 -0.00009
+1 -0.0001 1 1 0.0049 -0.0012 0.002 0.011 0.00007
+1 -0.0001 1 1 0.0057 -0.0005 0.000 0.020 0.00003
+1 0.0001 1 1 -0.0060 0.0005 0.009 0.022 -0.00009
+1 -0.0001 1 1 0.0036 0.0036 0.006 0.011 -0.00002
+1 0.0001 1 1 -0.0044 0.0004 0.017 0.003 -0.00004
+1 -0.0001 1 1 0.0044 0.0001 0.011 -0.002 0.00010
+1 0.0001 1 1 -0.0059 0.0006 0.008 0.003 -0.00009
+1 0.0001 1 1 -0.0029 0.0005 0.005 -0.033 0.00013
+1 -0.0002 1 1 0.0053 0.0024 0.010 -0.025 0.00010
+1 0.0002 1 1 -0.0021 -0.0009 0.012 -0.010 -0.00004
+1 -0.0001 1 1 0.0069 0.0018 0.002 0.016 0.00002
+1 -0.0001 1 1 0.0022 0.0015 0.005 0.031 -0.00018
+1 0.0001 1 1 -0.0068 0.0026 0.013 0.021 -0.00017
+1 0.0001 1 1 -0.0081 0.0006 0.013 0.005 -0.00002
+1 -0.0001 1 1 0.0068 0.0008 0.011 -0.005 0.00010
+1 -0.0001 1 1 0.0054 0.0004 0.010 0.018 -0.00008
+1 0.0001 1 1 -0.0062 -0.0001 0.007 -0.039 0.00018
+1 -0.0002 1 1 0.0070 0.0004 0.000 -0.040 0.00035
+1 -0.0001 1 1 0.0089 0.0045 0.012 0.016 -0.00014
+1 0.0001 1 1 -0.0060 -0.0013 0.014 0.020 -0.00006
+1 -0.0001 1 1 0.0052 0.0012 0.006 0.012 0.00004
+1 0.0001 1 1 -0.0047 0.0007 0.008 -0.011 0.00007
+1 -0.0002 1 1 0.0066 0.0014 0.011 0.011 -0.00002
+1 0.0001 1 1 -0.0080 -0.0001 0.009 -0.014 -0.00001
+1 0.0001 1 1 -0.0048 -0.0003 0.005 -0.034 0.00021
+1 -0.0001 1 1 0.0096 0.0035 0.009 -0.014 0.00013
+1 -0.0001 1 1 0.0062 0.0007 0.015 0.030 -0.00018
+1 0.0001 1 1 -0.0074 -0.0002 0.010 0.023 -0.00013
+1 0.0002 1 1 -0.0080 -0.0002 0.006 -0.012 0.00005
+1 -0.0001 1 1 0.0089 0.0046 0.006 -0.005 0.00010
+1 -0.0003 1 1 0.0087 0.0046 0.013 0.011 -0.00006
+1 -0.0001 1 1 -0.0034 0.0018 0.007 0.011 -0.00008
+1 0.0001 1 1 -0.0059 0.0019 0.009 0.001 -0.00010
+1 -0.0001 1 1 0.0067 0.0014 0.011 -0.003 0.00008
+1 0.0002 1 1 -0.0035 0.0008 0.013 0.024 -0.00018
+1 0.0001 1 1 -0.0038 0.0018 0.010 -0.013 0.00006
+1 -0.0001 1 1 0.0052 0.0006 0.010 -0.005 0.00006
+1 0.0001 1 1 -0.0042 0.0008 0.010 -0.012 0.00007
+1 -0.0001 1 1 0.0058 0.0006 0.007 0.010 0.00000
+1 -0.0001 1 1 0.0049 0.0018 0.008 0.018 -0.00009
+1 0.0001 1 1 -0.0085 0.0002 0.011 0.004 -0.00013
+1 0.0001 1 1 -0.0080 -0.0001 0.010 -0.010 0.00010
+1 -0.0002 1 1 0.0070 0.0033 0.007 0.010 -0.00003
+1 0.0001 1 1 0.0044 0.0030 0.011 0.019 -0.00022
+1 0.0001 1 1 -0.0054 0.0002 0.012 0.006 -0.00003
+1 -0.0001 1 1 0.0028 -0.0003 0.002 -0.008 0.00014
+1 -0.0001 1 1 0.0046 0.0007 0.002 0.003 0.00003
+1 0.0001 1 1 -0.0060 0.0033 0.011 0.006 -0.00013
+1 0.0001 1 1 0.0051 0.0007 0.014 -0.011 0.00013
+1 -0.0002 1 1 0.0095 -0.0005 0.010 0.019 0.00005
+1 -0.0001 1 1 0.0015 -0.0002 0.010 0.045 -0.00026
+1 0.0001 1 1 -0.0049 0.0011 0.011 0.042 -0.00036
+1 0.0001 1 1 -0.0086 0.0008 0.012 0.024 -0.00002
+1 -0.0002 1 1 0.0072 -0.0006 0.006 -0.002 0.00018
+1 -0.0001 1 1 0.0066 0.0009 0.006 0.016 -0.00008
+1 0.0001 1 1 -0.0049 0.0022 0.013 0.021 -0.00024
+1 0.0002 1 1 -0.0097 -0.0005 0.014 0.000 -0.00010
+1 -0.0001 1 1 0.0073 -0.0005 0.004 -0.019 0.00024
+1 -0.0002 1 1 0.0035 0.0028 0.023 0.012 0.00000
+1 0.0002 1 1 -0.0050 -0.0007 0.013 0.007 -0.00009
+1 0.0008 1 1 -0.0036 0.0005 0.013 -0.014 -0.00007
+1 -0.0015 1 1 0.0120 0.0024 0.011 0.001 0.00030
+1 0.0003 1 1 -0.0108 0.0002 0.015 0.001 -0.00001
+1 -0.0005 1 1 0.0055 0.0026 0.018 0.010 0.00009
+1 -0.0002 1 1 0.0006 0.0013 0.013 0.011 0.00001
+1 0.0005 1 1 -0.0055 0.0001 0.014 0.007 -0.00013
+1 -0.0002 1 1 0.0073 0.0011 0.012 0.007 0.00021
+1 0.0001 1 1 0.0009 0.0010 0.012 0.038 -0.00024
+1 0.0002 1 1 -0.0056 -0.0006 0.003 0.024 -0.00008
+1 0.0001 1 1 -0.0066 0.0044 0.021 0.011 -0.00023
+1 0.0001 1 1 -0.0071 0.0026 0.025 -0.010 0.00007
+1 -0.0001 1 1 0.0112 -0.0026 0.005 -0.010 0.00037
+1 -0.0004 1 1 0.0141 0.0008 0.004 0.017 -0.00006
+1 -0.0001 1 1 -0.0002 0.0020 0.007 0.045 -0.00059
+1 0.0003 1 1 -0.0099 0.0008 0.009 0.033 -0.00012
+1 0.0001 1 1 0.0008 0.0041 0.015 0.010 -0.00021
+1 0.0005 1 1 -0.0069 0.0014 0.016 -0.001 -0.00017
+1 -0.0005 1 1 0.0083 0.0004 0.014 -0.007 0.00032
+1 -0.0002 1 1 0.0067 -0.0024 0.013 0.012 -0.00020
+1 0.0004 1 1 -0.0068 -0.0008 0.006 0.014 -0.00043
+1 -0.0003 1 1 0.0041 0.0028 0.012 -0.020 0.00037
+1 0.0005 1 1 -0.0064 -0.0008 0.008 0.006 -0.00019
+1 -0.0003 1 1 0.0041 0.0030 0.007 -0.006 0.00023
+1 0.0007 1 1 -0.0049 0.0008 0.011 0.006 -0.00023
+1 -0.0002 1 1 0.0071 0.0013 0.011 0.003 0.00032
+1 -0.0001 1 1 0.0090 0.0013 0.010 0.015 -0.00003
+1 0.0004 1 1 -0.0118 0.0010 0.010 0.004 -0.00025
+1 -0.0006 1 1 0.0070 -0.0005 0.005 -0.027 0.00054
+1 -0.0002 1 1 0.0047 -0.0003 0.004 0.010 0.00003
+1 0.0005 1 1 -0.0072 0.0023 0.009 0.007 -0.00019
+1 -0.0006 1 1 0.0072 0.0018 0.008 -0.001 0.00032
+1 -0.0002 1 1 0.0052 0.0031 0.012 0.012 -0.00029
+1 0.0008 1 1 -0.0101 0.0021 0.016 0.005 -0.00048
+1 -0.0001 1 1 0.0059 -0.0001 0.003 -0.020 0.00040
+1 -0.0003 1 1 0.0110 0.0030 0.007 0.004 0.00007
+1 -0.0002 1 1 0.0057 0.0035 0.013 0.030 -0.00029
+1 -0.0001 1 1 -0.0058 0.0017 0.017 0.031 -0.00043
+1 0.0002 1 1 -0.0112 0.0025 0.020 0.018 -0.00028
+1 -0.0006 1 1 0.0062 -0.0026 0.012 0.001 0.00045
+1 -0.0002 1 1 -0.0055 0.0010 0.011 0.018 -0.00038
+1 0.0008 1 1 -0.0124 0.0014 0.009 0.004 -0.00043
+1 0.0001 1 1 0.0090 0.0041 0.019 -0.021 0.00044
+1 -0.0010 1 1 0.0160 -0.0017 0.011 0.027 0.00000
+1 0.0006 1 1 -0.0131 -0.0007 0.006 0.041 -0.00100
+1 -0.0001 1 1 0.0106 0.0027 0.008 -0.014 0.00033
+1 -0.0004 1 1 0.0139 -0.0005 0.011 0.020 0.00001
+1 -0.0004 1 1 0.0068 0.0009 0.010 0.047 -0.00054
+1 0.0006 1 1 -0.0080 0.0000 0.011 0.046 -0.00069
+1 0.0001 1 1 -0.0124 0.0003 0.010 0.026 -0.00005
+1 0.0002 1 1 -0.0069 -0.0032 0.009 -0.010 0.00036
+1 -0.0004 1 1 0.0064 0.0010 0.006 -0.008 0.00022
+1 0.0001 1 1 -0.0043 0.0033 0.016 -0.011 0.00010
+1 -0.0006 1 1 0.0074 -0.0003 0.012 -0.007 0.00031
+1 -0.0001 1 1 0.0017 -0.0025 0.006 0.011 -0.00011
+1 0.0003 1 1 -0.0062 0.0000 0.001 0.005 -0.00024
+1 0.0001 1 1 -0.0042 0.0003 -0.001 -0.010 0.00018
+1 -0.0003 1 1 0.0058 0.0031 0.005 -0.006 0.00020
+1 0.0004 1 1 -0.0069 0.0012 0.016 0.005 -0.00033
+1 0.0002 1 1 -0.0047 0.0000 0.014 -0.012 0.00025
+1 -0.0002 1 1 0.0061 -0.0003 0.010 -0.010 0.00038
+1 -0.0001 1 1 0.0030 0.0004 0.001 0.011 -0.00004
+1 0.0003 1 1 -0.0038 0.0026 0.013 0.005 -0.00001
+1 -0.0007 1 1 0.0095 0.0007 0.015 0.018 0.00021
+1 -0.0001 1 1 0.0044 0.0012 0.018 0.033 -0.00067
+1 0.0012 1 1 -0.0129 0.0015 0.019 0.022 -0.00058
+1 -0.0004 1 1 0.0048 -0.0059 0.006 -0.019 0.00064
+1 -0.0006 1 1 0.0127 0.0018 -0.002 0.013 0.00009
+1 0.0001 1 1 0.0011 0.0041 0.007 0.036 -0.00052
+1 0.0002 1 1 -0.0053 -0.0019 0.012 0.032 -0.00020
+1 -0.0002 1 1 -0.0031 0.0018 0.009 -0.011 -0.00002
+1 -0.0002 1 1 0.0044 -0.0003 0.006 -0.015 0.00040
+1 -0.0001 1 1 0.0052 0.0027 0.010 0.012 -0.00015
+1 0.0004 1 1 -0.0076 0.0020 0.015 0.004 -0.00018
+1 0.0002 1 1 -0.0043 0.0011 0.015 -0.014 0.00034
+1 -0.0010 1 1 0.0097 -0.0006 0.010 -0.007 0.00048
+1 0.0005 1 1 0.0030 0.0024 0.012 0.011 -0.00058
+1 -0.0001 1 1 0.0008 0.0003 0.009 0.010 0.00009
+1 -0.0003 1 1 0.0078 0.0018 0.011 0.016 0.00022
+1 -0.0003 1 1 0.0076 -0.0011 0.008 0.031 -0.00024
+1 0.0002 1 1 -0.0041 -0.0004 0.004 0.037 -0.00050
+1 0.0001 1 1 -0.0102 0.0013 0.004 0.023 -0.00021
+1 -0.0004 1 1 0.0039 0.0012 0.017 0.010 0.00007
+1 0.0001 1 1 -0.0052 0.0011 0.017 0.011 -0.00028
+1 -0.0011 1 1 0.0084 0.0005 0.011 -0.005 0.00044
+1 0.0010 1 1 -0.0111 0.0010 0.012 0.002 -0.00052
+1 -0.0001 1 1 0.0037 -0.0006 0.007 -0.025 0.00063
+1 -0.0004 1 1 0.0122 0.0010 0.006 -0.012 0.00046
+1 -0.0008 1 1 0.0147 0.0030 0.010 0.020 -0.00008
+1 0.0006 1 1 -0.0128 -0.0031 0.011 0.023 -0.00039
+1 -0.0001 1 1 -0.0081 -0.0033 -0.003 -0.013 0.00031
+1 -0.0002 1 1 0.0091 0.0054 0.005 -0.013 0.00033
+1 0.0003 1 1 -0.0089 -0.0017 0.010 0.007 -0.00020
+1 0.0004 1 1 -0.0060 -0.0003 0.006 -0.013 0.00021
+1 -0.0004 1 1 0.0119 0.0030 0.000 -0.001 0.00032
+1 -0.0002 1 1 0.0116 0.0026 0.003 0.019 -0.00016
+1 0.0006 1 1 0.0023 0.0023 0.007 0.034 -0.00066
+1 0.0002 1 1 -0.0073 -0.0011 0.012 0.010 -0.00016
+1 0.0002 1 1 -0.0042 -0.0020 0.002 -0.013 0.00017
+1 -0.0003 1 1 0.0077 0.0033 0.005 -0.007 0.00029
+1 -0.0001 1 1 0.0068 0.0021 0.007 0.013 -0.00022
+1 -0.0001 1 1 0.0026 0.0009 0.012 0.010 -0.00005
+1 0.0006 1 1 -0.0063 0.0004 0.012 0.007 -0.00032
+1 -0.0003 1 1 0.0056 0.0005 0.009 0.013 0.00011
+1 0.0003 1 1 -0.0088 0.0015 0.016 0.004 -0.00016
+1 0.0003 1 1 -0.0073 0.0008 0.015 -0.012 0.00021
+1 -0.0004 1 1 0.0068 0.0001 0.011 -0.015 0.00042
+1 -0.0003 1 1 0.0058 0.0015 0.006 0.015 -0.00020
+1 0.0008 1 1 -0.0078 0.0027 0.012 0.013 -0.00045
+1 0.0001 1 1 -0.0039 0.0004 0.009 -0.014 0.00047
+1 -0.0005 1 1 0.0080 -0.0001 0.006 -0.009 0.00046
+1 -0.0003 1 1 0.0093 0.0009 0.005 0.011 -0.00015
+1 0.0003 1 1 -0.0064 0.0025 0.012 0.018 -0.00031
+1 0.0003 1 1 -0.0038 0.0008 0.010 -0.010 0.00018
+1 0.0002 1 1 -0.0065 0.0037 0.017 -0.011 0.00026
+1 -0.0004 1 1 0.0091 0.0039 0.016 -0.005 0.00025
+1 0.0003 1 1 -0.0046 0.0021 0.016 0.018 -0.00002
+1 -0.0003 1 1 0.0011 0.0021 0.011 0.010 0.00017
+1 0.0002 1 1 -0.0058 0.0052 0.014 0.006 -0.00019
+1 0.0001 1 1 0.0043 0.0016 0.020 -0.021 0.00015
+1 -0.0001 1 1 0.0082 0.0007 0.021 -0.004 0.00012
+1 -0.0002 1 1 0.0084 -0.0030 0.021 0.014 -0.00002
+1 0.0001 1 1 -0.0059 -0.0013 0.013 0.024 -0.00012
+1 0.0001 1 1 -0.0016 -0.0002 0.007 -0.010 0.00011
+1 -0.0002 1 1 0.0039 0.0011 0.005 -0.006 0.00012
+1 0.0001 1 1 0.0019 0.0028 0.014 0.009 -0.00006
+1 -0.0001 1 1 0.0013 0.0008 0.011 0.010 -0.00003
+1 -0.0001 1 1 0.0022 0.0016 0.013 0.011 0.00000
+1 0.0002 1 1 -0.0038 -0.0010 0.014 0.003 -0.00005
+1 0.0001 1 1 -0.0054 -0.0002 0.010 -0.004 -0.00003
+1 -0.0001 1 1 0.0035 0.0007 0.009 -0.024 0.00017
+1 -0.0001 1 1 0.0050 0.0010 0.012 -0.006 -0.00001
+1 -0.0001 1 1 0.0012 0.0010 0.013 0.010 -0.00001
+1 0.0001 1 1 -0.0041 -0.0005 0.012 0.005 -0.00012
+1 -0.0001 1 1 0.0035 -0.0008 0.001 -0.006 0.00008
+1 -0.0001 1 1 0.0019 0.0014 0.006 0.011 -0.00006
+1 0.0001 1 1 -0.0040 0.0016 0.013 0.006 -0.00010
+1 -0.0001 1 1 0.0029 0.0001 0.011 -0.005 0.00011
+1 0.0001 1 1 0.0035 0.0003 0.011 0.008 -0.00001
+1 0.0001 1 1 -0.0041 0.0003 0.006 0.007 -0.00005
+1 -0.0001 1 1 0.0039 0.0013 0.014 0.016 -0.00001
+1 0.0001 1 1 -0.0051 -0.0004 0.011 -0.011 0.00002
+1 -0.0001 1 1 0.0069 0.0024 0.003 0.002 0.00002
+1 -0.0002 1 1 0.0058 0.0017 0.005 0.011 -0.00012
+1 0.0002 1 1 -0.0097 0.0003 0.012 -0.002 -0.00016
+1 -0.0002 1 1 0.0067 0.0004 0.004 -0.023 0.00020
+1 0.0001 1 1 -0.0038 0.0002 0.008 0.008 -0.00019
+1 0.0001 1 1 -0.0060 0.0006 0.009 0.000 -0.00011
+1 -0.0001 1 1 0.0066 0.0002 0.009 -0.002 0.00010
+1 -0.0001 1 1 0.0058 0.0016 0.012 0.012 -0.00008
+1 0.0002 1 1 -0.0059 -0.0012 0.010 0.004 -0.00006
+1 -0.0001 1 1 0.0058 0.0024 0.007 -0.001 0.00012
+1 -0.0001 1 1 0.0072 0.0035 0.014 0.014 0.00000
+1 0.0001 1 1 0.0039 0.0015 0.020 0.031 -0.00013
+1 -0.0001 1 1 0.0041 -0.0008 0.011 0.014 0.00004
+1 0.0001 1 1 -0.0035 0.0017 0.010 -0.013 0.00005
+1 -0.0001 1 1 0.0059 -0.0005 0.007 0.006 0.00002
+1 0.0001 1 1 0.0054 0.0021 0.014 -0.012 0.00024
+1 -0.0003 1 1 0.0090 -0.0026 0.010 -0.002 0.00025
+1 -0.0001 1 1 0.0075 0.0024 0.010 0.036 -0.00013
+1 -0.0001 1 1 0.0049 0.0020 0.012 0.045 -0.00025
+1 0.0003 1 1 -0.0059 0.0002 0.017 0.043 -0.00024
+1 0.0001 1 1 -0.0053 0.0015 0.013 0.007 -0.00013
+1 -0.0001 1 1 0.0036 0.0020 0.004 -0.007 0.00008
+1 -0.0001 1 1 -0.0005 0.0003 0.005 -0.009 0.00001
+1 -0.0002 1 1 0.0033 0.0010 0.011 -0.004 0.00007
+1 0.0003 1 1 -0.0040 -0.0018 0.013 0.007 -0.00006
+1 -0.0002 1 1 0.0058 0.0002 -0.002 0.011 0.00010
+1 -0.0001 1 1 0.0053 0.0007 -0.002 0.021 -0.00008
+1 -0.0001 1 1 0.0018 0.0052 0.007 0.028 -0.00018
+1 0.0001 1 1 -0.0038 0.0035 0.011 0.006 -0.00007
+1 -0.0002 1 1 0.0040 0.0001 0.013 -0.007 0.00017
+1 0.0001 1 1 -0.0051 0.0008 0.012 0.000 -0.00008
+1 0.0002 1 1 -0.0025 -0.0004 0.009 -0.019 0.00009
+1 -0.0001 1 1 0.0076 0.0016 0.005 0.009 0.00003
+1 0.0001 1 1 -0.0062 0.0020 0.016 0.007 -0.00005
+1 -0.0002 1 1 0.0076 -0.0005 0.006 0.013 0.00008
+1 -0.0002 1 1 0.0060 -0.0001 0.004 0.030 -0.00011
+1 -0.0001 1 1 -0.0074 0.0009 0.003 0.027 -0.00030
+1 0.0002 1 1 -0.0114 0.0038 0.008 0.014 -0.00025
+1 0.0001 1 1 -0.0084 0.0020 0.014 -0.029 0.00020
+1 -0.0001 1 1 0.0089 -0.0001 0.007 -0.021 0.00014
+1 0.0002 1 1 -0.0036 0.0013 0.010 -0.012 -0.00006
+1 -0.0001 1 1 0.0064 0.0027 0.004 -0.003 0.00008
+1 -0.0002 1 1 0.0039 0.0022 0.008 0.012 -0.00013
+1 0.0003 1 1 -0.0058 0.0024 0.015 0.008 -0.00019
+1 -0.0003 1 1 0.0043 0.0000 0.007 -0.007 0.00007
+1 0.0001 1 1 -0.0053 0.0015 0.010 -0.008 -0.00013
+1 -0.0001 1 1 0.0073 0.0020 0.015 0.011 0.00003
+1 0.0001 1 1 -0.0060 0.0004 0.016 0.021 -0.00021
+1 -0.0001 1 1 0.0063 0.0008 0.005 0.000 0.00008
+1 -0.0002 1 1 0.0027 0.0010 0.007 0.027 -0.00010
+1 0.0002 1 1 -0.0046 0.0010 0.009 0.025 -0.00030
+1 -0.0008 1 1 0.0117 0.0014 0.016 -0.007 0.00044
+1 -0.0002 1 1 0.0098 0.0034 0.019 0.026 -0.00037
+1 0.0001 1 1 -0.0033 0.0006 0.020 0.035 -0.00060
+1 0.0005 1 1 -0.0131 -0.0002 0.015 0.009 -0.00019
+1 -0.0001 1 1 -0.0052 0.0003 0.007 -0.030 0.00035
+1 -0.0006 1 1 0.0088 0.0026 0.007 -0.023 0.00037
+1 -0.0003 1 1 0.0051 0.0047 0.017 0.013 -0.00001
+1 0.0002 1 1 -0.0059 0.0017 0.012 -0.004 -0.00009
+1 0.0002 1 1 -0.0046 0.0024 0.013 -0.014 0.00012
+1 0.0002 1 1 -0.0018 0.0007 0.009 -0.010 -0.00004
+1 -0.0003 1 1 0.0032 0.0027 0.011 -0.008 0.00009
+1 0.0001 1 1 -0.0020 0.0001 0.011 -0.010 0.00002
+1 -0.0002 1 1 0.0037 0.0030 0.011 -0.007 0.00013
+1 -0.0002 1 1 0.0074 0.0012 0.014 -0.020 0.00020
+1 0.0003 1 1 -0.0062 -0.0005 0.010 0.006 -0.00026
+1 -0.0002 1 1 0.0055 0.0031 0.009 -0.023 0.00025
+1 -0.0003 1 1 0.0048 0.0043 0.010 -0.005 0.00011
+1 0.0003 1 1 -0.0045 0.0011 0.015 0.000 -0.00025
+1 0.0002 1 1 -0.0043 0.0016 0.014 -0.014 0.00008
+1 -0.0001 1 1 0.0029 0.0019 0.010 0.010 0.00002
+1 0.0004 1 1 -0.0044 0.0007 0.014 0.007 -0.00013
+1 0.0002 1 1 -0.0030 0.0026 0.012 -0.011 -0.00004
+1 -0.0002 1 1 0.0054 0.0013 0.010 -0.005 0.00012
+1 0.0004 1 1 -0.0066 0.0003 0.006 0.005 -0.00027
+1 -0.0003 1 1 0.0055 0.0023 0.012 -0.009 0.00017
+1 0.0002 1 1 -0.0051 0.0024 0.007 -0.014 -0.00003
+1 -0.0001 1 1 0.0040 0.0011 0.009 -0.018 0.00009
+1 -0.0001 1 1 0.0055 0.0020 0.011 0.014 -0.00003
+1 0.0001 1 1 -0.0077 0.0006 0.009 0.003 -0.00012
+1 -0.0003 1 1 0.0061 0.0030 0.007 -0.024 0.00027
+1 0.0004 1 1 -0.0041 0.0028 0.013 -0.011 -0.00020
+1 -0.0003 1 1 0.0075 -0.0002 0.009 -0.005 0.00017
+1 -0.0001 1 1 0.0054 0.0005 0.006 0.013 -0.00014
+1 0.0002 1 1 -0.0035 0.0026 0.009 0.016 -0.00030
+1 0.0001 1 1 -0.0053 0.0022 0.010 0.005 -0.00002
+1 -0.0002 1 1 0.0040 0.0021 0.011 -0.001 0.00009
+1 0.0002 1 1 -0.0038 0.0007 0.004 0.006 -0.00015
+1 -0.0001 1 1 0.0079 0.0010 0.007 -0.009 0.00016
+1 -0.0002 1 1 0.0071 0.0034 0.011 0.013 -0.00012
+1 0.0004 1 1 -0.0063 0.0006 0.016 0.005 -0.00006
+1 -0.0002 1 1 0.0052 0.0011 0.004 0.012 -0.00001
+1 0.0002 1 1 -0.0062 0.0025 0.012 0.006 -0.00009
+1 -0.0004 1 1 0.0054 0.0008 0.013 -0.008 0.00030
+1 0.0002 1 1 -0.0044 0.0007 0.007 0.009 -0.00016
+1 0.0002 1 1 -0.0009 0.0023 0.006 -0.010 0.00008
+1 -0.0005 1 1 0.0033 0.0031 0.009 -0.008 0.00017
+1 -0.0001 1 1 0.0047 -0.0005 0.008 0.007 0.00010
+1 -0.0001 1 1 0.0042 -0.0006 0.004 0.017 -0.00006
+1 0.0002 1 1 -0.0033 0.0025 0.008 0.019 -0.00015
+1 -0.0006 1 1 0.0043 0.0009 0.011 0.014 0.00011
+1 0.0008 1 1 -0.0117 0.0006 0.012 0.001 -0.00032
+1 -0.0001 1 1 0.0048 0.0007 0.007 -0.023 0.00045
+1 -0.0007 1 1 0.0117 0.0030 0.008 -0.002 0.00021
+1 -0.0003 1 1 0.0048 0.0021 0.013 0.019 -0.00052
+1 0.0007 1 1 -0.0113 0.0007 0.012 0.013 -0.00074
+1 0.0001 1 1 -0.0142 -0.0007 0.007 -0.013 0.00010
+1 0.0002 1 1 -0.0106 0.0002 0.005 -0.030 0.00030
+1 -0.0002 1 1 0.0102 0.0018 0.002 -0.029 0.00042
+1 -0.0009 1 1 0.0141 0.0019 0.002 -0.009 0.00015
+1 0.0008 1 1 -0.0117 0.0037 0.012 0.012 -0.00069
+1 -0.0008 1 1 0.0125 0.0024 0.013 -0.022 0.00066
+1 -0.0001 1 1 0.0079 0.0039 0.019 0.018 -0.00046
+1 0.0002 1 1 -0.0072 -0.0021 0.014 0.018 -0.00020
+1 -0.0005 1 1 0.0052 0.0028 0.005 0.011 0.00010
+1 0.0001 1 1 -0.0046 0.0038 0.014 0.016 -0.00031
+1 0.0004 1 1 -0.0082 -0.0001 0.011 0.005 -0.00017
+1 0.0003 1 1 -0.0046 0.0003 0.007 -0.012 0.00025
+1 -0.0004 1 1 0.0050 0.0003 0.004 -0.013 0.00054
+1 -0.0004 1 1 0.0084 0.0021 0.004 0.017 -0.00014
+1 0.0003 1 1 -0.0114 -0.0002 0.011 0.011 -0.00036
+1 0.0002 1 1 -0.0072 0.0010 0.007 -0.032 0.00038
+1 -0.0001 1 1 0.0036 0.0009 0.005 -0.036 0.00050
+1 0.0006 1 1 -0.0062 0.0008 0.013 -0.012 -0.00044
+1 -0.0003 1 1 0.0058 0.0014 0.009 -0.023 0.00016
+1 0.0002 1 1 -0.0044 0.0021 0.010 -0.015 -0.00017
+1 -0.0003 1 1 0.0074 0.0014 0.006 -0.016 0.00013
+1 0.0007 1 1 -0.0056 0.0026 0.008 -0.007 -0.00046
+1 -0.0002 1 1 0.0054 0.0003 0.012 -0.004 0.00012
+1 -0.0005 1 1 0.0025 -0.0007 0.006 0.010 0.00016
+1 0.0007 1 1 -0.0077 0.0007 0.003 0.006 -0.00045
+1 0.0001 1 1 -0.0059 0.0004 0.001 -0.011 0.00031
+1 -0.0004 1 1 0.0082 0.0040 0.003 -0.005 0.00029
+1 0.0002 1 1 -0.0050 -0.0001 0.008 0.008 -0.00006
+1 -0.0004 1 1 0.0055 0.0018 0.016 0.023 0.00018
+1 0.0005 1 1 -0.0090 -0.0006 0.010 0.021 -0.00021
+1 -0.0004 1 1 0.0043 0.0009 0.008 -0.007 0.00024
+1 -0.0001 1 1 -0.0033 0.0008 0.008 -0.010 0.00004
+1 -0.0004 1 1 0.0065 -0.0001 0.001 -0.007 0.00029
+1 -0.0002 1 1 0.0039 0.0027 0.003 0.014 -0.00017
+1 0.0005 1 1 -0.0114 -0.0006 0.014 -0.003 -0.00023
+1 -0.0007 1 1 0.0070 0.0050 0.004 -0.025 0.00042
+1 -0.0004 1 1 0.0071 0.0011 0.012 0.011 0.00016
+1 0.0003 1 1 -0.0097 0.0012 0.013 0.003 -0.00018
+1 -0.0007 1 1 0.0068 0.0027 0.008 -0.021 0.00031
+1 -0.0006 1 1 0.0063 -0.0026 0.000 -0.005 0.00037
+1 -0.0002 1 1 0.0034 0.0045 -0.001 0.010 -0.00033
+1 0.0008 1 1 -0.0100 0.0048 0.007 0.002 -0.00049
+1 0.0003 1 1 -0.0039 0.0015 0.009 -0.014 0.00018
+1 -0.0006 1 1 0.0086 0.0004 0.013 -0.005 0.00026
+1 -0.0001 1 1 0.0039 0.0030 0.015 0.021 -0.00022
+1 0.0003 1 1 -0.0039 0.0046 0.023 0.020 -0.00019
+1 0.0002 1 1 -0.0026 0.0013 0.026 -0.011 0.00010
+1 -0.0006 1 1 0.0045 0.0002 0.017 -0.008 0.00016
+1 0.0002 1 1 -0.0048 0.0016 0.011 -0.004 -0.00021
+1 0.0001 1 1 -0.0063 0.0034 0.011 -0.014 -0.00004
+1 -0.0008 1 1 0.0050 0.0043 0.018 -0.024 0.00020
+1 0.0003 1 1 -0.0037 0.0031 0.023 -0.019 -0.00023
+1 0.0004 1 1 -0.0047 0.0025 0.021 -0.029 0.00003
+1 -0.0004 1 1 0.0069 0.0023 0.015 -0.024 0.00018
+1 0.0002 1 1 -0.0036 -0.0006 0.020 -0.006 -0.00002
+1 -0.0007 1 1 0.0064 -0.0001 0.010 -0.005 0.00027
+1 0.0001 1 1 -0.0051 0.0053 0.013 0.008 -0.00035
+1 -0.0005 1 1 0.0106 0.0029 0.010 0.007 0.00025
+1 -0.0001 1 1 0.0076 0.0030 0.013 0.035 -0.00023
+1 0.0006 1 1 -0.0042 0.0023 0.015 0.043 -0.00041
+1 -0.0008 1 1 0.0051 0.0008 0.011 0.012 0.00027
+1 0.0004 1 1 -0.0099 0.0030 0.015 0.006 -0.00030
+1 -0.0003 1 1 0.0067 0.0040 0.011 -0.024 0.00022
+1 0.0005 1 1 -0.0072 0.0004 0.021 0.006 -0.00031
+1 0.0001 1 1 -0.0050 -0.0020 0.015 -0.013 0.00035
+1 -0.0003 1 1 0.0073 -0.0011 0.005 -0.009 0.00037
+1 -0.0003 1 1 0.0096 0.0027 0.003 0.011 -0.00004
+1 0.0001 1 1 0.0049 0.0029 0.005 0.025 -0.00034
+1 0.0005 1 1 -0.0054 0.0032 0.011 0.022 -0.00021
+1 -0.0002 1 1 0.0003 0.0027 0.014 0.009 0.00020
+1 0.0004 1 1 -0.0062 0.0011 0.006 -0.012 -0.00001
+1 -0.0005 1 1 0.0095 0.0041 0.008 -0.001 0.00015
+1 0.0001 1 1 -0.0055 0.0022 0.019 0.013 -0.00020
+1 0.0002 1 1 -0.0075 -0.0006 0.016 0.004 -0.00005
+1 -0.0002 1 1 0.0047 -0.0002 0.006 -0.002 0.00033
+1 -0.0002 1 1 0.0071 0.0002 0.003 0.010 0.00003
+1 0.0001 1 1 0.0058 0.0018 0.003 0.020 -0.00014
+1 -0.0003 1 1 0.0031 0.0037 0.007 0.030 -0.00012
+1 -0.0002 1 1 -0.0038 0.0023 0.010 0.011 -0.00002
+1 0.0005 1 1 -0.0074 0.0027 0.013 -0.008 -0.00008
+1 -0.0003 1 1 0.0101 0.0021 0.009 -0.006 0.00026
+1 -0.0002 1 1 0.0097 0.0024 0.010 0.013 -0.00011
+1 0.0001 1 1 0.0042 0.0028 0.012 0.029 -0.00028
+1 0.0002 1 1 -0.0046 0.0017 0.015 0.025 -0.00014
+1 0.0005 1 1 -0.0051 0.0002 0.008 0.005 -0.00020
+1 -0.0004 1 1 0.0107 0.0019 0.003 0.015 0.00023
+1 -0.0001 1 1 0.0090 0.0033 0.005 0.033 -0.00035
+1 0.0003 1 1 -0.0095 0.0054 0.013 0.030 -0.00032
+1 0.0003 1 1 -0.0111 0.0044 0.016 0.015 -0.00002
+1 -0.0006 1 1 0.0101 0.0005 0.012 0.001 0.00035
+1 -0.0004 1 1 0.0086 -0.0003 0.003 0.029 0.00017
+1 -0.0001 1 1 0.0032 0.0026 0.005 0.047 -0.00028
+1 0.0005 1 1 -0.0052 0.0027 0.008 0.045 -0.00031
+1 -0.0003 1 1 -0.0010 0.0018 0.010 0.028 0.00026
+1 0.0005 1 1 -0.0097 0.0010 0.014 -0.003 -0.00010
+1 -0.0004 1 1 0.0080 0.0011 0.006 -0.012 0.00044
+1 -0.0003 1 1 0.0111 0.0025 0.007 0.014 -0.00002
+1 -0.0001 1 1 0.0072 0.0029 0.009 0.029 -0.00034
+1 0.0004 1 1 -0.0051 -0.0006 0.012 0.031 -0.00030
+1 0.0001 1 1 -0.0046 0.0022 0.013 0.020 -0.00015
+1 -0.0002 1 1 0.0046 0.0009 0.003 0.008 0.00007
+1 0.0004 1 1 -0.0051 0.0032 0.012 0.004 -0.00004
+1 -0.0004 1 1 0.0113 0.0012 0.010 0.016 0.00027
+1 -0.0001 1 1 0.0095 0.0014 0.009 0.039 -0.00037
+1 0.0003 1 1 -0.0109 0.0019 0.011 0.040 -0.00060
+1 0.0005 1 1 -0.0093 0.0012 0.008 -0.011 0.00014
+1 -0.0002 1 1 0.0115 0.0048 0.005 -0.006 0.00031
+1 -0.0002 1 1 0.0131 0.0047 0.009 0.015 -0.00001
+1 -0.0001 1 1 0.0099 0.0070 0.015 0.031 -0.00043
+1 -0.0001 1 1 -0.0071 -0.0005 0.012 0.033 -0.00022
+1 0.0002 1 1 -0.0109 -0.0007 0.008 0.020 -0.00029
+1 -0.0005 1 1 0.0060 0.0046 0.003 -0.014 0.00048
+1 -0.0004 1 1 0.0074 0.0053 0.013 0.010 -0.00015
+1 0.0006 1 1 -0.0090 0.0030 0.019 0.009 -0.00043
+1 0.0002 1 1 -0.0085 0.0013 0.020 -0.014 0.00026
+1 -0.0003 1 1 0.0085 -0.0006 0.012 -0.015 0.00042
+1 -0.0002 1 1 0.0084 0.0018 0.010 0.012 -0.00035
+1 0.0004 1 1 -0.0054 0.0028 0.013 0.016 -0.00048
+1 -0.0007 1 1 0.0096 -0.0007 0.005 -0.003 0.00042
+1 0.0001 1 1 -0.0070 0.0028 0.000 0.019 -0.00048
+1 0.0003 1 1 -0.0129 0.0037 0.003 0.002 -0.00030
+1 -0.0003 1 1 0.0106 -0.0005 0.009 -0.020 0.00049
+1 -0.0003 1 1 0.0075 0.0017 0.008 0.014 -0.00035
+1 -0.0003 1 1 0.0036 0.0029 0.012 0.028 -0.00002
+1 0.0002 1 1 -0.0079 0.0025 0.018 0.019 -0.00021
+1 0.0002 1 1 -0.0023 0.0029 0.027 -0.010 0.00013
+1 -0.0006 1 1 0.0039 0.0029 0.025 -0.008 0.00017
+1 0.0003 1 1 -0.0034 -0.0023 0.024 -0.011 -0.00003
+1 -0.0001 1 1 0.0031 0.0028 0.026 -0.010 0.00004
+1 -0.0003 1 1 0.0032 -0.0012 0.026 -0.004 0.00000
+1 0.0003 1 1 -0.0025 0.0004 0.020 -0.011 -0.00001
+1 -0.0002 1 1 0.0036 0.0003 0.020 -0.009 0.00013
+1 0.0002 1 1 -0.0011 -0.0036 0.013 -0.010 0.00000
+1 0.0002 1 1 0.0001 -0.0012 0.018 -0.010 0.00012
+1 -0.0003 1 1 0.0032 0.0015 0.018 -0.007 0.00022
+1 -0.0003 1 1 0.0038 0.0000 0.011 0.012 0.00002
+1 0.0003 1 1 -0.0019 0.0028 0.019 -0.010 0.00002
+1 -0.0004 1 1 0.0047 -0.0011 0.016 -0.008 0.00024
+1 0.0001 1 1 -0.0037 0.0029 0.019 0.011 -0.00005
+1 -0.0001 1 1 0.0026 -0.0005 0.011 0.011 0.00000
+1 0.0002 1 1 -0.0027 0.0021 0.017 -0.011 -0.00006
+1 -0.0003 1 1 0.0039 0.0000 0.013 -0.008 0.00009
+1 0.0001 1 1 -0.0045 0.0006 0.012 -0.012 -0.00004
+1 -0.0005 1 1 0.0103 0.0012 0.011 -0.006 0.00018
+1 0.0003 1 1 0.0037 -0.0007 0.013 0.026 -0.00021
+1 -0.0003 1 1 0.0032 -0.0005 0.012 0.031 0.00006
+1 0.0003 1 1 -0.0086 0.0009 0.014 0.017 -0.00018
+1 -0.0001 1 1 0.0038 -0.0006 0.009 -0.011 0.00019
+1 -0.0002 1 1 0.0032 -0.0014 0.011 0.011 0.00002
+1 0.0002 1 1 -0.0058 0.0008 0.009 0.006 -0.00018
+1 0.0001 1 1 -0.0037 -0.0003 0.009 -0.011 0.00011
+1 -0.0003 1 1 0.0041 -0.0005 0.004 -0.010 0.00015
+1 0.0001 1 1 -0.0021 0.0025 0.009 -0.010 -0.00001
+1 -0.0002 1 1 0.0030 -0.0006 0.011 -0.008 0.00007
+1 0.0001 1 1 -0.0022 0.0005 0.009 -0.011 0.00005
+1 -0.0002 1 1 0.0068 0.0033 0.008 0.002 0.00007
+1 -0.0001 1 1 0.0051 0.0027 0.013 0.013 -0.00014
+1 -0.0001 1 1 0.0007 0.0012 0.029 -0.005 0.00027
+1 -0.0002 1 1 0.0070 -0.0012 0.019 0.012 0.00008
+1 -0.0001 1 1 0.0007 -0.0014 0.011 0.035 -0.00018
+1 0.0003 1 1 -0.0080 0.0017 0.007 0.019 -0.00017
+1 0.0002 1 1 0.0005 -0.0001 0.020 -0.010 0.00020
+1 -0.0007 1 1 0.0049 -0.0018 0.017 -0.007 0.00030
+1 0.0004 1 1 -0.0076 0.0044 0.017 -0.004 -0.00022
+1 -0.0003 1 1 0.0066 0.0032 0.018 -0.024 0.00026
+1 -0.0002 1 1 0.0050 -0.0018 0.027 0.014 -0.00011
+1 0.0001 1 1 -0.0072 -0.0024 0.006 0.008 -0.00019
+1 0.0001 1 1 -0.0079 0.0007 0.003 -0.012 0.00010
+1 0.0001 1 1 0.0043 0.0044 0.017 -0.025 0.00014
+1 -0.0001 1 1 0.0064 0.0019 0.016 -0.017 0.00011
+1 -0.0005 1 1 0.0075 0.0024 0.017 -0.007 0.00006
+1 0.0001 1 1 -0.0039 0.0024 0.020 0.002 -0.00035
+1 0.0002 1 1 -0.0091 0.0013 0.019 -0.017 -0.00010
+1 0.0001 1 1 -0.0086 0.0006 0.017 -0.033 0.00008
+1 0.0002 1 1 -0.0057 0.0004 0.014 -0.045 0.00022
+1 -0.0001 1 1 0.0049 0.0003 0.008 -0.048 0.00032
+1 0.0004 1 1 -0.0031 0.0005 0.018 -0.014 0.00000
+1 -0.0003 1 1 0.0058 0.0002 0.013 -0.010 0.00022
+1 -0.0002 1 1 0.0054 0.0007 0.010 0.011 -0.00008
+1 0.0008 1 1 -0.0078 0.0006 0.010 0.007 -0.00025
+1 -0.0001 1 1 0.0044 -0.0003 0.002 -0.009 0.00034
+1 -0.0004 1 1 0.0086 0.0037 0.004 0.001 0.00026
+1 -0.0001 1 1 0.0069 0.0048 0.010 0.014 -0.00029
+1 0.0009 1 1 -0.0130 0.0017 0.017 -0.001 -0.00036
+1 0.0002 1 1 -0.0099 0.0015 0.017 -0.028 0.00044
+1 -0.0005 1 1 0.0037 0.0000 0.013 -0.035 0.00069
+1 -0.0003 1 1 0.0124 0.0012 0.015 -0.007 0.00011
+1 0.0006 1 1 -0.0036 0.0016 0.016 0.042 -0.00031
+1 0.0001 1 1 -0.0058 0.0063 0.012 0.014 -0.00013
+1 -0.0005 1 1 0.0105 -0.0003 0.011 0.017 0.00023
+1 -0.0002 1 1 0.0026 0.0015 0.012 0.045 -0.00031
+1 0.0005 1 1 -0.0069 0.0000 0.011 0.041 -0.00044
+1 -0.0002 1 1 0.0007 0.0023 0.018 0.010 -0.00001
+1 0.0005 1 1 -0.0066 0.0002 0.016 0.001 -0.00025
+1 -0.0006 1 1 0.0083 -0.0011 0.010 -0.007 0.00033
+1 -0.0004 1 1 0.0059 -0.0005 0.005 0.014 -0.00036
+1 0.0009 1 1 -0.0092 0.0013 0.005 0.011 -0.00071
+1 0.0002 1 1 -0.0100 0.0029 0.008 -0.030 0.00029
+1 -0.0004 1 1 0.0040 0.0012 0.008 -0.041 0.00041
+1 0.0004 1 1 -0.0036 0.0007 0.008 -0.002 -0.00022
+1 -0.0004 1 1 0.0055 0.0019 0.008 -0.007 0.00027
+1 -0.0003 1 1 0.0037 0.0026 0.013 0.014 -0.00013
+1 0.0004 1 1 -0.0083 0.0022 0.017 0.006 -0.00032
+1 0.0002 1 1 -0.0041 -0.0004 0.011 -0.028 0.00026
+1 -0.0005 1 1 0.0075 -0.0007 0.003 -0.023 0.00033
+1 0.0006 1 1 -0.0096 0.0027 0.009 -0.014 -0.00025
+1 0.0001 1 1 -0.0065 0.0034 0.013 -0.031 0.00035
+1 -0.0003 1 1 0.0105 0.0011 0.016 -0.023 0.00038
+1 -0.0004 1 1 0.0118 0.0004 0.018 0.013 -0.00005
+1 -0.0001 1 1 0.0073 0.0006 0.017 0.029 -0.00039
+1 0.0004 1 1 -0.0089 -0.0019 0.009 0.024 -0.00040
+1 -0.0001 1 1 0.0048 0.0043 0.015 -0.004 0.00008
+1 -0.0001 1 1 0.0037 0.0007 0.019 0.011 -0.00005
+1 0.0001 1 1 -0.0046 0.0007 0.020 0.010 -0.00020
+1 0.0002 1 1 -0.0065 -0.0033 0.014 0.002 -0.00010
+1 -0.0002 1 1 0.0038 -0.0041 0.000 -0.003 0.00043
+1 -0.0003 1 1 0.0081 0.0011 -0.002 0.010 0.00009
+1 0.0001 1 1 -0.0047 0.0027 0.005 0.024 -0.00021
+1 -0.0003 1 1 0.0060 0.0022 0.012 -0.023 0.00026
+1 -0.0001 1 1 0.0028 -0.0014 0.000 -0.004 0.00009
+1 -0.0001 1 1 0.0006 0.0046 0.011 0.010 -0.00007
+1 0.0001 1 1 -0.0039 0.0023 0.017 0.005 -0.00007
+1 -0.0001 1 1 0.0041 -0.0009 0.009 0.005 0.00021
+1 -0.0002 1 1 0.0068 0.0004 0.009 0.014 0.00014
+1 -0.0001 1 1 0.0035 0.0024 0.014 0.033 -0.00014
+1 0.0002 1 1 -0.0058 -0.0005 0.014 0.022 -0.00008
+1 -0.0002 1 1 0.0022 0.0007 0.002 0.009 0.00014
+1 0.0002 1 1 -0.0024 0.0035 0.013 -0.010 0.00002
+1 -0.0003 1 1 0.0063 0.0003 0.014 -0.002 0.00015
+1 0.0002 1 1 -0.0028 0.0017 0.009 -0.012 0.00005
+1 -0.0002 1 1 0.0052 0.0021 0.010 -0.006 0.00010
+1 -0.0001 1 1 0.0042 -0.0004 0.005 0.013 0.00002
+1 0.0002 1 1 -0.0064 0.0019 0.005 -0.004 -0.00002
+1 -0.0001 1 1 0.0075 0.0014 0.018 0.001 0.00007
+1 -0.0002 1 1 0.0048 -0.0003 0.015 0.019 -0.00013
+1 0.0001 1 1 -0.0058 0.0001 0.011 0.017 -0.00021
+1 0.0003 1 1 -0.0075 -0.0007 0.008 0.008 -0.00008
+1 -0.0002 1 1 0.0043 0.0026 0.005 -0.007 0.00011
+1 -0.0005 1 1 0.0029 0.0005 0.011 0.009 0.00008
+1 0.0008 1 1 -0.0131 0.0019 0.014 -0.003 -0.00051
+1 -0.0001 1 1 0.0093 0.0005 0.006 -0.024 0.00021
+1 -0.0002 1 1 0.0106 0.0016 0.006 -0.004 0.00000
+1 0.0004 1 1 -0.0103 0.0015 0.012 0.012 -0.00033
+1 0.0001 1 1 -0.0075 0.0005 0.010 -0.014 0.00022
+1 -0.0003 1 1 0.0041 0.0017 0.007 -0.023 0.00017
+1 -0.0003 1 1 0.0071 0.0013 0.013 -0.008 0.00021
+1 -0.0005 1 1 0.0055 0.0003 0.014 0.010 -0.00019
+1 0.0001 1 1 -0.0048 0.0018 0.015 0.013 -0.00063
+1 0.0001 1 1 -0.0123 -0.0002 0.012 0.001 -0.00048
+1 -0.0001 1 1 0.0049 0.0025 -0.006 -0.044 0.00034
+1 -0.0003 1 1 0.0076 0.0056 0.000 -0.035 0.00015
+1 -0.0002 1 1 0.0069 -0.0015 0.017 -0.006 0.00032
+1 -0.0004 1 1 0.0093 -0.0042 0.015 0.011 0.00007
+1 -0.0001 1 1 0.0066 -0.0013 0.011 0.025 -0.00029
+1 0.0005 1 1 -0.0112 0.0018 0.006 0.013 -0.00032
+1 0.0002 1 1 -0.0092 0.0005 0.005 -0.010 0.00032
+1 -0.0005 1 1 0.0123 0.0021 0.005 -0.002 0.00032
+1 0.0003 1 1 -0.0035 0.0025 0.015 0.029 -0.00029
+1 0.0006 1 1 -0.0057 -0.0013 0.010 0.006 -0.00030
+1 0.0002 1 1 -0.0042 0.0032 0.012 -0.011 -0.00003
+1 -0.0003 1 1 0.0077 0.0032 0.009 -0.006 0.00019
+1 -0.0003 1 1 0.0037 0.0022 0.012 0.012 -0.00027
+1 0.0009 1 1 -0.0137 0.0013 0.014 -0.007 -0.00039
+1 -0.0002 1 1 0.0051 0.0007 0.010 -0.039 0.00075
+1 -0.0003 1 1 0.0151 0.0001 0.007 -0.015 0.00031
+1 -0.0008 1 1 0.0149 0.0016 0.008 0.021 -0.00046
+1 0.0022 1 1 -0.0208 0.0034 0.013 0.019 -0.00150
+1 -0.0002 1 1 0.0116 -0.0005 0.001 -0.039 0.00064
+1 -0.0006 1 1 0.0143 0.0006 0.000 -0.020 0.00008
+1 0.0003 1 1 -0.0079 0.0042 0.010 -0.006 -0.00018
+1 0.0001 1 1 0.0037 -0.0007 0.007 -0.012 -0.00001
+1 -0.0001 1 1 0.0050 -0.0003 0.005 -0.006 0.00013
+1 0.0001 1 1 -0.0063 0.0035 0.015 -0.007 -0.00017
+1 0.0001 1 1 -0.0074 0.0014 0.015 -0.017 -0.00003
+1 -0.0004 1 1 0.0037 -0.0008 0.012 -0.031 0.00038
+1 -0.0003 1 1 0.0053 -0.0001 0.003 -0.004 0.00012
+1 -0.0001 1 1 0.0002 0.0003 0.003 0.009 -0.00008
+1 0.0004 1 1 -0.0037 0.0034 0.007 0.006 -0.00023
+1 -0.0002 1 1 0.0038 -0.0001 0.008 0.011 0.00003
+1 -0.0001 1 1 -0.0045 0.0027 0.006 0.011 -0.00016
+1 0.0002 1 1 -0.0075 0.0030 0.009 0.002 -0.00012
+1 -0.0001 1 1 0.0057 -0.0003 0.014 -0.007 0.00007
+1 -0.0002 1 1 0.0045 -0.0007 0.007 0.011 -0.00009
+1 0.0002 1 1 -0.0064 0.0007 0.005 0.008 -0.00025
+1 -0.0003 1 1 0.0028 0.0002 0.008 -0.005 0.00002
+1 0.0002 1 1 -0.0033 0.0017 0.009 -0.005 -0.00025
+1 0.0002 1 1 -0.0045 0.0019 0.010 -0.012 0.00006
+1 -0.0002 1 1 0.0039 -0.0001 0.010 -0.016 0.00011
+1 0.0006 1 1 -0.0051 0.0020 0.011 -0.011 -0.00029
+1 -0.0002 1 1 0.0036 0.0005 0.009 -0.019 0.00037
+1 -0.0002 1 1 0.0075 0.0010 0.008 -0.005 0.00010
+1 -0.0002 1 1 0.0035 0.0014 0.008 0.013 -0.00019
+1 0.0005 1 1 -0.0037 0.0017 0.010 0.013 -0.00030
+1 0.0002 1 1 -0.0054 0.0006 0.006 -0.015 -0.00004
+1 -0.0002 1 1 0.0035 0.0027 0.007 -0.024 0.00017
+1 -0.0003 1 1 0.0042 0.0007 0.016 -0.006 0.00013
+1 -0.0001 1 1 -0.0044 -0.0030 0.005 -0.007 -0.00008
+1 0.0001 1 1 -0.0024 0.0012 0.000 -0.029 0.00011
+1 -0.0002 1 1 0.0050 0.0023 0.004 -0.021 0.00010
+1 -0.0006 1 1 0.0100 -0.0036 0.024 -0.024 0.00013
+1 0.0001 1 1 -0.0020 0.0014 0.012 -0.010 -0.00001
+1 -0.0003 1 1 0.0036 -0.0010 0.016 -0.006 0.00010
+1 0.0001 1 1 -0.0042 -0.0008 0.011 -0.012 -0.00004
+1 0.0001 1 1 -0.0029 0.0016 0.014 -0.021 0.00009
+1 -0.0002 1 1 0.0050 0.0010 0.016 0.011 -0.00003
+1 0.0004 1 1 -0.0071 -0.0012 0.014 0.006 -0.00015
+1 0.0001 1 1 -0.0047 -0.0004 0.011 -0.012 0.00017
+1 -0.0002 1 1 0.0065 -0.0013 0.006 -0.006 0.00018
+1 -0.0001 1 1 0.0061 0.0014 0.008 0.019 -0.00005
+1 -0.0002 1 1 0.0039 0.0010 0.009 0.027 -0.00018
+1 0.0002 1 1 -0.0054 -0.0013 0.013 0.022 -0.00014
+1 -0.0001 1 1 0.0038 0.0004 0.015 0.009 0.00004
+1 0.0001 1 1 -0.0053 -0.0006 0.010 0.006 -0.00006
+1 0.0002 1 1 -0.0030 0.0006 0.011 -0.011 0.00010
+1 -0.0001 1 1 0.0069 0.0014 0.008 -0.002 0.00017
+1 -0.0001 1 1 0.0081 0.0016 0.011 0.016 0.00000
+1 -0.0001 1 1 0.0068 0.0019 0.013 0.027 -0.00014
+1 0.0001 1 1 -0.0066 0.0004 0.016 0.028 -0.00019
+1 -0.0001 1 1 0.0036 -0.0009 0.005 -0.011 0.00020
+1 -0.0002 1 1 0.0060 -0.0014 0.010 0.013 0.00000
+1 -0.0001 1 1 -0.0043 0.0003 0.013 0.015 -0.00008
+1 0.0002 1 1 -0.0062 -0.0005 0.012 0.003 -0.00007
+1 -0.0001 1 1 0.0062 0.0010 0.012 -0.006 0.00018
+1 -0.0001 1 1 0.0012 -0.0003 0.006 0.045 -0.00013
+1 0.0001 1 1 -0.0047 0.0000 0.006 0.039 -0.00017
+1 0.0002 1 1 -0.0046 -0.0004 0.014 0.004 -0.00005
+1 -0.0002 1 1 0.0042 -0.0013 0.009 0.000 0.00020
+1 -0.0001 1 1 0.0055 -0.0008 0.006 0.013 0.00000
+1 0.0001 1 1 -0.0050 -0.0002 0.004 0.003 -0.00005
+1 0.0001 1 1 -0.0009 0.0016 0.008 -0.010 0.00013
+1 -0.0002 1 1 0.0043 0.0025 0.013 -0.005 0.00018
+1 -0.0002 1 1 0.0020 -0.0007 0.013 0.009 -0.00010
+1 0.0003 1 1 -0.0044 0.0007 0.013 0.007 -0.00028
+1 -0.0002 1 1 0.0058 -0.0007 0.014 -0.008 0.00024
+1 -0.0001 1 1 0.0054 0.0001 0.013 0.012 -0.00014
+1 0.0001 1 1 -0.0033 -0.0040 0.003 0.017 -0.00027
+1 -0.0001 1 1 -0.0064 -0.0032 -0.001 0.010 -0.00019
+1 -0.0001 1 1 0.0045 0.0007 0.002 -0.034 0.00039
+1 -0.0001 1 1 0.0097 0.0012 0.004 -0.016 0.00015
+1 -0.0002 1 1 0.0100 0.0051 0.013 0.011 -0.00008
+1 -0.0002 1 1 0.0058 0.0026 0.020 0.028 -0.00021
+1 0.0002 1 1 -0.0067 -0.0017 0.017 0.024 -0.00020
+1 -0.0002 1 1 0.0050 0.0023 0.002 -0.008 0.00021
+1 -0.0001 1 1 0.0067 -0.0007 0.007 0.008 -0.00001
+1 0.0002 1 1 -0.0043 0.0002 0.007 0.018 -0.00027
+1 0.0001 1 1 -0.0070 0.0009 0.008 0.003 -0.00005
+1 0.0001 1 1 -0.0035 0.0004 0.008 -0.014 0.00015
+1 -0.0002 1 1 0.0058 0.0003 0.008 -0.006 0.00012
+1 0.0002 1 1 -0.0060 -0.0009 0.009 0.005 -0.00020
+1 -0.0002 1 1 0.0046 0.0014 0.009 -0.025 0.00022
+1 -0.0006 1 1 0.0011 -0.0005 0.012 0.009 0.00002
+1 0.0007 1 1 -0.0079 0.0001 0.011 0.004 -0.00051
+1 0.0002 1 1 0.0044 -0.0038 0.012 -0.019 0.00003
+1 -0.0001 1 1 0.0083 -0.0017 0.006 -0.001 0.00012
+1 -0.0001 1 1 0.0069 0.0009 0.005 0.027 -0.00012
+1 0.0001 1 1 0.0015 0.0018 0.009 0.038 -0.00022
+1 0.0002 1 1 -0.0052 0.0008 0.011 0.003 -0.00001
+1 0.0001 1 1 -0.0033 -0.0007 0.005 -0.006 -0.00013
+1 -0.0005 1 1 0.0061 -0.0005 0.011 -0.009 0.00010
+1 -0.0002 1 1 0.0046 -0.0005 0.005 0.010 0.00004
+1 0.0001 1 1 -0.0063 0.0000 0.009 0.000 -0.00004
+1 0.0001 1 1 -0.0047 0.0007 0.010 -0.012 0.00012
+1 -0.0002 1 1 0.0072 0.0004 0.010 -0.003 0.00013
+1 -0.0002 1 1 0.0062 0.0016 0.012 0.010 -0.00015
+1 0.0005 1 1 -0.0073 -0.0007 0.010 0.007 -0.00020
+1 -0.0001 1 1 0.0044 -0.0017 0.005 -0.011 0.00024
+1 -0.0001 1 1 0.0069 0.0009 0.005 -0.003 0.00013
+1 0.0001 1 1 0.0069 0.0029 0.010 0.013 -0.00004
+1 -0.0001 1 1 0.0047 -0.0002 0.009 0.029 -0.00015
+1 0.0001 1 1 -0.0057 0.0002 0.009 0.028 -0.00024
+1 -0.0003 1 1 0.0040 0.0002 0.010 -0.008 0.00020
+1 0.0002 1 1 -0.0023 0.0002 0.007 -0.011 -0.00002
+1 -0.0001 1 1 0.0054 0.0004 0.009 -0.006 0.00015
+1 -0.0001 1 1 0.0015 0.0021 0.015 0.011 -0.00018
+1 0.0004 1 1 -0.0039 -0.0015 0.014 0.008 -0.00022
+1 -0.0001 1 1 0.0050 0.0006 0.003 0.015 0.00002
+1 -0.0002 1 1 0.0006 0.0009 0.006 0.027 -0.00012
+1 0.0001 1 1 -0.0047 0.0031 0.012 0.023 -0.00025
+1 -0.0001 1 1 0.0038 0.0013 0.006 0.013 0.00009
+1 0.0002 1 1 -0.0049 0.0001 0.012 0.007 -0.00007
+1 -0.0002 1 1 0.0008 0.0009 0.011 0.010 -0.00002
+1 0.0001 1 1 -0.0006 -0.0011 0.011 -0.009 0.00006
+1 -0.0004 1 1 0.0037 -0.0013 0.006 -0.005 0.00014
+1 0.0003 1 1 -0.0067 -0.0005 0.006 -0.011 -0.00014
+1 -0.0002 1 1 0.0053 0.0011 0.011 -0.023 0.00006
+1 0.0002 1 1 -0.0059 -0.0001 0.013 -0.009 -0.00028
+1 0.0001 1 1 -0.0048 0.0011 0.014 -0.031 0.00014
+1 -0.0001 1 1 0.0056 0.0008 0.012 -0.003 0.00007
+1 -0.0003 1 1 0.0034 -0.0008 0.010 0.010 -0.00011
+1 0.0005 1 1 -0.0041 -0.0002 0.008 0.010 -0.00029
+1 -0.0001 1 1 0.0061 0.0005 0.009 0.012 0.00011
+1 -0.0001 1 1 0.0057 0.0009 0.010 0.024 -0.00010
+1 0.0003 1 1 -0.0006 0.0008 0.011 0.032 -0.00045
+1 0.0002 1 1 -0.0054 -0.0014 0.009 0.026 -0.00016
+1 0.0003 1 1 -0.0067 0.0007 0.008 0.006 -0.00021
+1 0.0001 1 1 -0.0041 0.0007 0.009 -0.011 0.00021
+1 -0.0004 1 1 0.0065 0.0004 0.009 -0.006 0.00023
+1 0.0005 1 1 -0.0102 -0.0008 0.012 0.001 -0.00033
+1 -0.0004 1 1 0.0062 -0.0007 0.006 -0.023 0.00033
+1 0.0001 1 1 -0.0038 0.0014 0.002 -0.012 -0.00002
+1 -0.0001 1 1 0.0062 0.0009 0.016 -0.003 0.00007
+1 -0.0001 1 1 0.0046 -0.0017 0.011 0.014 -0.00008
+1 0.0001 1 1 -0.0071 -0.0013 0.002 0.004 -0.00013
+1 0.0001 1 1 -0.0079 0.0025 0.006 -0.010 -0.00001
+1 0.0001 1 1 -0.0054 0.0023 0.010 -0.028 0.00013
+1 -0.0003 1 1 0.0047 0.0009 0.013 -0.031 0.00032
+1 -0.0002 1 1 0.0066 -0.0021 0.014 -0.015 0.00000
+1 0.0001 1 1 0.0033 0.0005 0.014 -0.005 -0.00022
+1 0.0001 1 1 -0.0037 -0.0016 0.009 -0.011 0.00000
+1 0.0004 1 1 -0.0078 -0.0010 0.008 0.002 -0.00029
+1 0.0001 1 1 0.0062 0.0010 0.009 -0.013 0.00010
+1 -0.0004 1 1 0.0079 0.0008 0.010 -0.003 0.00012
+1 -0.0003 1 1 0.0031 -0.0014 0.012 0.011 -0.00032
+1 0.0001 1 1 -0.0068 0.0005 0.012 0.009 -0.00061
+1 0.0001 1 1 -0.0099 -0.0024 0.008 -0.014 0.00028
+1 -0.0001 1 1 0.0065 -0.0002 -0.002 -0.022 0.00030
+1 -0.0001 1 1 0.0089 0.0019 0.001 -0.006 0.00001
+1 -0.0003 1 1 0.0067 0.0024 0.006 0.013 -0.00012
+1 0.0005 1 1 -0.0097 0.0000 0.013 0.006 -0.00030
+1 -0.0001 1 1 0.0070 0.0001 0.006 -0.004 0.00007
+1 0.0001 1 1 -0.0038 0.0077 0.014 -0.043 0.00005
+1 0.0002 1 1 0.0005 0.0044 0.027 -0.050 0.00012
+1 -0.0003 1 1 0.0066 -0.0015 0.023 -0.040 0.00019
+1 0.0003 1 1 -0.0054 -0.0004 0.015 -0.028 0.00003
+1 -0.0002 1 1 0.0096 0.0010 0.016 -0.013 0.00012
+1 0.0003 1 1 -0.0062 0.0005 0.017 0.021 -0.00017
+1 -0.0001 1 1 0.0049 0.0017 0.009 0.012 0.00008
+1 -0.0002 1 1 0.0038 -0.0012 0.017 0.030 -0.00005
+1 0.0001 1 1 -0.0061 -0.0007 0.009 0.017 -0.00006
+1 0.0001 1 1 -0.0001 0.0016 0.011 -0.010 0.00013
+1 -0.0001 1 1 0.0054 -0.0004 0.008 -0.002 0.00015
+1 -0.0001 1 1 0.0066 0.0038 0.014 0.012 -0.00003
+1 -0.0001 1 1 0.0049 0.0044 0.021 0.021 -0.00013
+1 0.0001 1 1 -0.0075 -0.0031 0.016 0.015 -0.00021
+1 0.0001 1 1 -0.0075 -0.0027 0.007 -0.011 0.00015
+1 -0.0001 1 1 0.0051 -0.0022 0.014 0.010 0.00000
+1 0.0001 1 1 -0.0040 0.0042 0.020 0.005 -0.00003
+1 0.0001 1 1 -0.0017 0.0037 0.009 -0.009 0.00005
+1 -0.0001 1 1 0.0044 -0.0026 0.015 -0.004 0.00011
+1 -0.0002 1 1 0.0045 0.0018 0.009 0.010 -0.00001
+1 0.0001 1 1 -0.0044 -0.0003 0.016 0.006 -0.00006
+1 -0.0001 1 1 -0.0027 -0.0013 0.009 -0.010 0.00007
+1 0.0001 1 1 -0.0035 0.0008 0.007 -0.022 -0.00002
+1 -0.0001 1 1 0.0053 -0.0021 0.005 -0.022 0.00017
+1 -0.0001 1 1 0.0049 0.0013 0.010 0.013 -0.00007
+1 0.0001 1 1 -0.0057 0.0018 0.015 0.013 -0.00019
+1 0.0001 1 1 -0.0073 -0.0011 0.014 0.004 -0.00008
+1 -0.0001 1 1 0.0049 -0.0006 0.006 -0.020 0.00018
+1 -0.0001 1 1 0.0047 0.0005 0.014 0.011 -0.00002
+1 0.0001 1 1 -0.0067 -0.0015 0.003 -0.002 -0.00006
+1 -0.0001 1 1 0.0055 -0.0022 0.011 0.011 -0.00009
+1 0.0001 1 1 -0.0074 0.0006 0.012 0.002 -0.00009
+1 0.0001 1 1 -0.0071 -0.0016 0.009 -0.013 0.00006
+1 -0.0003 1 1 0.0051 -0.0077 0.017 -0.022 0.00021
+1 -0.0001 1 1 0.0072 -0.0004 0.003 -0.023 0.00022
+1 -0.0002 1 1 0.0053 0.0031 0.018 0.031 -0.00015
+1 0.0002 1 1 -0.0088 -0.0032 0.007 0.018 -0.00016
+1 -0.0002 1 1 0.0047 0.0007 0.004 -0.003 0.00017
+1 0.0001 1 1 -0.0037 0.0013 0.016 0.006 -0.00005
+1 -0.0002 1 1 0.0055 0.0008 0.005 -0.001 0.00010
+1 0.0002 1 1 -0.0033 0.0016 0.012 0.008 -0.00015
+1 0.0001 1 1 -0.0036 0.0001 0.015 0.004 -0.00004
+1 0.0001 1 1 -0.0021 0.0005 0.010 -0.016 0.00006
+1 0.0001 1 1 -0.0033 -0.0012 0.007 -0.012 -0.00002
+1 -0.0001 1 1 0.0039 -0.0017 0.006 -0.005 0.00011
+1 0.0001 1 1 -0.0018 -0.0017 0.011 -0.010 0.00005
+1 0.0001 1 1 -0.0035 0.0009 0.012 -0.007 -0.00005
+1 0.0001 1 1 -0.0060 0.0011 0.012 0.002 -0.00011
+1 -0.0001 1 1 0.0062 -0.0006 0.006 -0.018 0.00019
+1 -0.0001 1 1 0.0093 -0.0007 0.007 0.023 -0.00003
+1 -0.0001 1 1 0.0070 -0.0003 0.007 0.035 -0.00019
+1 0.0002 1 1 -0.0070 -0.0002 0.012 0.034 -0.00025
+1 -0.0003 1 1 0.0032 -0.0014 0.007 0.011 0.00003
+1 0.0002 1 1 -0.0063 0.0003 0.007 0.004 -0.00016
+1 -0.0003 1 1 0.0038 -0.0007 0.009 -0.025 0.00025
+1 0.0001 1 1 -0.0020 0.0000 0.008 -0.011 0.00001
+1 0.0001 1 1 0.0032 0.0020 0.009 -0.004 0.00003
+1 -0.0001 1 1 0.0036 -0.0002 0.008 0.011 -0.00002
+1 0.0002 1 1 -0.0039 -0.0017 0.009 0.007 -0.00007
+1 0.0001 1 1 0.0020 0.0030 0.012 0.011 -0.00002
+1 0.0001 1 1 -0.0062 -0.0015 0.007 0.004 -0.00014
+1 -0.0001 1 1 0.0046 0.0032 0.005 -0.024 0.00016
+1 -0.0001 1 1 0.0059 -0.0006 0.015 0.012 -0.00007
+1 0.0002 1 1 -0.0040 -0.0016 0.010 0.017 -0.00015
+1 0.0002 1 1 -0.0001 0.0011 0.006 -0.009 0.00003
+1 -0.0001 1 1 0.0042 0.0030 0.011 -0.004 0.00014
+1 -0.0001 1 1 0.0048 -0.0002 0.012 0.013 -0.00003
+1 0.0001 1 1 -0.0054 0.0002 0.009 0.001 -0.00001
+1 -0.0001 1 1 0.0045 0.0008 0.007 -0.005 0.00006
+1 0.0003 1 1 -0.0055 0.0007 0.018 0.006 -0.00022
+1 -0.0001 1 1 0.0072 0.0008 0.003 0.011 0.00002
+1 -0.0001 1 1 0.0043 0.0020 0.007 0.029 -0.00013
+1 0.0002 1 1 -0.0046 -0.0008 0.013 0.027 -0.00014
+1 0.0001 1 1 0.0026 0.0020 0.017 0.009 -0.00001
+1 0.0003 1 1 -0.0052 -0.0035 0.013 0.006 -0.00014
+1 0.0002 1 1 -0.0013 -0.0008 0.005 -0.010 0.00004
+1 -0.0002 1 1 0.0034 0.0020 0.002 -0.007 0.00016
+1 -0.0001 1 1 0.0009 -0.0020 0.012 0.010 -0.00006
+1 0.0002 1 1 -0.0051 -0.0004 0.009 0.003 -0.00015
+1 -0.0001 1 1 0.0042 0.0000 0.007 -0.007 0.00008
+1 -0.0001 1 1 0.0020 0.0003 0.007 0.010 -0.00008
+1 0.0002 1 1 -0.0038 0.0005 0.008 0.006 -0.00013
+1 0.0001 1 1 0.0002 -0.0008 0.006 0.009 -0.00002
+1 -0.0001 1 1 0.0037 0.0008 0.008 0.023 -0.00003
+1 -0.0001 1 1 0.0016 0.0024 0.012 0.029 -0.00015
+1 0.0002 1 1 -0.0042 -0.0014 0.016 0.025 -0.00018
+1 0.0002 1 1 -0.0062 -0.0022 0.007 0.004 -0.00013
+1 -0.0001 1 1 -0.0047 -0.0017 0.003 -0.010 0.00010
+1 -0.0001 1 1 0.0056 0.0002 0.007 -0.002 0.00005
+1 -0.0002 1 1 0.0041 0.0005 0.007 0.010 -0.00009
+1 0.0003 1 1 -0.0067 0.0009 0.011 0.005 -0.00021
+1 -0.0001 1 1 0.0053 0.0032 0.011 0.020 -0.00015
+1 0.0002 1 1 -0.0035 -0.0005 0.015 0.023 -0.00018
+1 -0.0001 1 1 0.0013 0.0004 0.008 0.010 0.00000
+1 0.0001 1 1 -0.0006 0.0007 0.006 -0.010 0.00000
+1 0.0002 1 1 -0.0028 -0.0001 0.010 -0.012 -0.00002
+1 0.0003 1 1 -0.0050 0.0011 0.011 0.008 -0.00018
+1 -0.0001 1 1 0.0054 -0.0005 0.002 -0.004 0.00006
+1 0.0001 1 1 -0.0047 0.0007 0.019 0.005 -0.00003
+1 0.0001 1 1 0.0025 0.0026 0.012 0.010 -0.00002
+1 0.0001 1 1 -0.0048 -0.0011 0.007 0.005 -0.00006
+1 -0.0002 1 1 0.0071 0.0025 0.009 0.014 0.00004
+1 0.0001 1 1 0.0045 0.0029 0.014 0.025 -0.00020
+1 0.0001 1 1 -0.0046 0.0009 0.019 0.025 -0.00014
+1 -0.0002 1 1 0.0011 -0.0003 0.005 0.010 0.00004
+1 0.0002 1 1 -0.0037 0.0011 0.008 0.006 -0.00013
+1 0.0001 1 1 -0.0012 -0.0002 0.011 -0.010 0.00001
+1 -0.0001 1 1 0.0030 -0.0005 0.008 -0.007 0.00009
+1 0.0001 1 1 -0.0023 0.0010 0.005 -0.013 0.00001
+1 -0.0001 1 1 0.0048 0.0026 0.011 -0.006 0.00009
+1 0.0003 1 1 -0.0038 -0.0038 0.014 0.006 -0.00014
+1 -0.0001 1 1 0.0048 0.0005 0.004 0.015 0.00003
+1 0.0002 1 1 -0.0040 0.0013 0.013 0.023 -0.00029
+1 0.0002 1 1 -0.0046 -0.0007 0.011 0.006 -0.00007
+1 0.0001 1 1 -0.0036 -0.0010 0.007 0.005 -0.00003
+1 0.0004 1 1 -0.0146 0.0038 0.014 0.001 -0.00016
+1 -0.0001 1 1 0.0069 0.0061 0.017 -0.023 0.00017
+1 -0.0002 1 1 0.0090 0.0038 0.019 -0.003 0.00004
+1 -0.0001 1 1 0.0072 0.0032 0.019 0.013 -0.00014
+1 -0.0001 1 1 -0.0036 0.0024 0.014 0.022 -0.00019
+1 0.0006 1 1 -0.0089 0.0029 0.013 0.007 -0.00019
+1 0.0001 1 1 -0.0049 0.0033 0.013 -0.011 0.00033
+1 -0.0001 1 1 0.0046 0.0020 0.010 -0.012 0.00041
+1 0.0007 1 1 -0.0058 0.0006 0.013 0.009 -0.00039
+1 -0.0001 1 1 0.0039 0.0032 0.008 -0.013 0.00027
+1 -0.0005 1 1 0.0065 0.0043 0.010 -0.006 0.00015
+1 0.0004 1 1 -0.0071 0.0024 0.008 -0.010 -0.00011
+1 -0.0004 1 1 0.0102 0.0051 0.014 -0.003 0.00015
+1 -0.0001 1 1 -0.0081 0.0008 0.014 0.007 -0.00017
+1 -0.0003 1 1 0.0079 0.0045 0.014 -0.006 0.00024
+1 -0.0001 1 1 0.0067 0.0024 0.017 0.019 -0.00010
+1 -0.0002 1 1 0.0037 0.0029 0.017 0.028 -0.00019
+1 0.0006 1 1 -0.0055 -0.0002 0.017 0.023 -0.00017
+1 -0.0003 1 1 0.0072 0.0018 0.013 0.029 0.00008
+1 0.0001 1 1 0.0051 0.0020 0.013 0.042 -0.00016
+1 0.0001 1 1 -0.0060 0.0023 0.008 0.043 -0.00028
+1 -0.0003 1 1 0.0041 0.0038 0.013 0.010 -0.00002
+1 0.0004 1 1 -0.0055 0.0033 0.016 0.009 -0.00020
+1 -0.0003 1 1 0.0050 0.0018 0.011 0.013 0.00012
+1 0.0004 1 1 -0.0055 0.0029 0.023 -0.002 -0.00019
+1 0.0002 1 1 0.0000 0.0019 0.028 -0.027 0.00017
+1 0.0001 1 1 0.0048 0.0014 0.026 -0.022 0.00021
+1 -0.0003 1 1 0.0080 -0.0048 0.018 -0.014 0.00022
+1 -0.0004 1 1 0.0028 -0.0009 0.008 0.010 -0.00021
+1 0.0008 1 1 -0.0062 0.0036 0.011 0.005 -0.00029
+1 -0.0003 1 1 0.0060 0.0028 0.020 -0.009 0.00018
+1 -0.0003 1 1 0.0051 0.0035 0.027 0.012 -0.00009
+1 0.0006 1 1 -0.0067 -0.0007 0.024 0.007 -0.00020
+1 -0.0004 1 1 0.0057 0.0019 0.012 -0.003 0.00013
+1 0.0004 1 1 -0.0061 0.0014 0.019 0.005 -0.00015
+1 -0.0001 1 1 0.0051 0.0021 0.021 0.000 0.00004
+1 0.0004 1 1 -0.0041 0.0011 0.019 0.007 -0.00010
+1 -0.0001 1 1 0.0048 0.0006 0.010 0.014 0.00003
+1 0.0001 1 1 -0.0003 0.0013 0.009 -0.010 0.00011
+1 -0.0001 1 1 0.0028 0.0041 0.015 -0.008 0.00016
+1 -0.0001 1 1 0.0045 0.0014 0.024 0.012 0.00000
+1 0.0002 1 1 -0.0055 0.0030 0.012 0.008 -0.00007
+1 0.0003 1 1 -0.0005 0.0030 0.020 -0.010 0.00012
+1 -0.0005 1 1 0.0054 -0.0024 0.013 -0.005 0.00028
+1 0.0002 1 1 -0.0036 0.0034 0.011 0.007 -0.00017
+1 0.0001 1 1 -0.0019 0.0008 0.014 -0.010 0.00007
+1 -0.0001 1 1 0.0036 0.0009 0.012 -0.008 0.00014
+1 -0.0003 1 1 0.0039 0.0013 0.012 0.011 -0.00004
+1 0.0004 1 1 -0.0052 0.0000 0.012 0.007 -0.00015
+1 -0.0001 1 1 0.0063 0.0027 0.013 0.014 0.00007
+1 -0.0002 1 1 0.0052 -0.0008 0.016 0.029 -0.00006
+1 0.0004 1 1 -0.0072 0.0005 0.013 0.020 -0.00013
+1 0.0001 1 1 -0.0054 -0.0004 0.014 0.001 -0.00009
+1 0.0002 1 1 -0.0045 -0.0006 0.010 -0.012 0.00007
+1 0.0001 1 1 0.0044 0.0014 0.012 -0.003 0.00002
+1 -0.0001 1 1 0.0056 -0.0003 0.005 0.028 -0.00008
+1 -0.0001 1 1 0.0046 0.0020 0.012 0.005 0.00009
+1 -0.0001 1 1 0.0045 0.0025 0.014 0.014 -0.00011
+1 -0.0001 1 1 -0.0064 -0.0006 0.006 0.005 -0.00007
+1 0.0002 1 1 -0.0076 0.0019 0.008 -0.009 -0.00004
+1 -0.0001 1 1 0.0041 0.0011 0.011 -0.025 0.00019
+1 -0.0002 1 1 0.0059 0.0014 0.011 -0.007 0.00000
+1 0.0002 1 1 -0.0054 0.0008 0.011 -0.012 -0.00004
+1 -0.0001 1 1 0.0061 -0.0012 0.009 -0.004 0.00007
+1 0.0002 1 1 -0.0049 0.0031 0.013 0.007 -0.00020
+1 -0.0002 1 1 0.0056 -0.0004 0.002 -0.004 0.00017
+1 0.0001 1 1 0.0035 0.0039 0.012 0.015 -0.00009
+1 0.0003 1 1 -0.0051 0.0000 0.014 0.003 -0.00002
+1 -0.0001 1 1 0.0045 -0.0015 0.003 -0.001 0.00022
+1 -0.0002 1 1 0.0067 0.0007 0.002 0.013 0.00004
+1 -0.0001 1 1 0.0040 0.0052 0.012 0.028 -0.00014
+1 0.0002 1 1 -0.0046 -0.0031 0.013 0.024 -0.00012
+1 0.0001 1 1 -0.0013 0.0009 0.016 -0.010 0.00005
+1 -0.0003 1 1 0.0031 -0.0012 0.009 -0.008 0.00015
+1 0.0002 1 1 -0.0034 0.0004 0.005 -0.005 -0.00014
+1 0.0002 1 1 -0.0054 0.0006 0.007 -0.014 -0.00017
+1 0.0002 1 1 -0.0050 0.0012 0.006 -0.030 0.00007
+1 0.0001 1 1 0.0057 0.0009 0.015 -0.006 0.00000
+1 -0.0005 1 1 0.0069 -0.0007 0.012 0.003 0.00010
+1 -0.0001 1 1 -0.0042 -0.0005 0.011 0.011 -0.00040
+1 -0.0001 1 1 -0.0061 -0.0019 0.003 -0.010 0.00026
+1 -0.0001 1 1 0.0059 0.0041 0.005 -0.004 0.00008
+1 -0.0002 1 1 0.0059 0.0040 0.012 0.011 -0.00003
+1 0.0003 1 1 -0.0042 -0.0017 0.010 0.007 -0.00002
+1 0.0002 1 1 -0.0044 0.0003 0.016 0.023 -0.00023
+1 -0.0001 1 1 0.0009 0.0010 0.013 0.010 -0.00003
+1 0.0004 1 1 -0.0056 -0.0007 0.012 0.006 -0.00021
+1 0.0001 1 1 0.0002 0.0010 0.003 -0.010 0.00015
+1 -0.0003 1 1 0.0040 0.0023 0.005 -0.006 0.00020
+1 -0.0002 1 1 0.0049 0.0006 0.005 0.009 0.00017
+1 -0.0003 1 1 0.0023 0.0010 0.006 0.028 -0.00010
+1 0.0004 1 1 -0.0053 0.0016 0.008 0.026 -0.00032
+1 -0.0001 1 1 0.0046 -0.0003 0.010 0.011 0.00007
+1 -0.0002 1 1 0.0020 0.0001 0.006 0.028 -0.00008
+1 0.0002 1 1 -0.0068 0.0014 0.009 0.015 -0.00013
+1 0.0002 1 1 -0.0034 0.0002 0.005 -0.011 0.00013
+1 -0.0001 1 1 0.0076 0.0033 0.008 0.000 0.00015
+1 -0.0002 1 1 0.0083 0.0039 0.012 0.012 0.00000
+1 0.0005 1 1 -0.0077 0.0002 0.016 0.022 -0.00026
+1 -0.0001 1 1 0.0061 0.0007 0.003 0.013 0.00005
+1 -0.0003 1 1 0.0031 0.0031 0.010 0.028 -0.00012
+1 0.0003 1 1 -0.0069 0.0009 0.015 0.023 -0.00029
+1 0.0002 1 1 0.0048 -0.0013 0.013 -0.014 0.00011
+1 -0.0001 1 1 0.0074 -0.0021 0.007 -0.004 0.00013
+1 0.0004 1 1 -0.0073 0.0019 0.016 0.000 -0.00021
+1 -0.0001 1 1 0.0059 -0.0003 0.003 -0.011 0.00023
+1 -0.0002 1 1 0.0083 0.0027 0.006 0.012 0.00001
+1 -0.0001 1 1 0.0043 0.0033 0.013 0.029 -0.00019
+1 0.0003 1 1 -0.0082 -0.0009 0.015 0.021 -0.00025
+1 -0.0002 1 1 0.0046 0.0017 0.002 -0.003 0.00020
+1 -0.0002 1 1 0.0017 0.0000 0.012 0.010 0.00009
+1 0.0001 1 1 -0.0043 0.0005 0.010 0.004 -0.00010
+1 0.0001 1 1 -0.0008 0.0022 0.009 -0.009 -0.00003
+1 -0.0004 1 1 0.0047 0.0000 0.004 -0.006 0.00022
+1 0.0001 1 1 -0.0055 0.0016 0.015 -0.008 -0.00006
+1 -0.0001 1 1 0.0035 -0.0009 0.006 -0.022 0.00024
+1 -0.0001 1 1 0.0084 0.0011 0.005 -0.006 0.00014
+1 -0.0003 1 1 0.0071 0.0023 0.008 0.015 -0.00009
+1 0.0001 1 1 -0.0062 0.0006 0.013 0.001 -0.00014
+1 -0.0001 1 1 0.0045 0.0022 0.008 0.012 -0.00001
+1 0.0003 1 1 -0.0039 -0.0037 0.011 0.016 -0.00017
+1 -0.0002 1 1 0.0029 0.0012 0.012 0.011 0.00002
+1 0.0002 1 1 -0.0056 -0.0002 0.013 0.005 -0.00015
+1 0.0001 1 1 -0.0030 -0.0006 0.008 -0.011 0.00013
+1 -0.0001 1 1 0.0054 0.0001 0.003 -0.006 0.00017
+1 0.0001 1 1 -0.0043 0.0015 0.017 0.008 -0.00006
+1 -0.0004 1 1 0.0050 0.0016 0.001 0.010 0.00005
+1 0.0002 1 1 -0.0078 0.0019 0.015 0.002 -0.00015
+1 0.0002 1 1 -0.0062 -0.0001 0.013 -0.013 0.00016
+1 -0.0001 1 1 0.0032 0.0004 0.008 0.009 -0.00003
+1 0.0001 1 1 -0.0036 0.0016 0.009 0.007 -0.00006
+1 0.0002 1 1 -0.0020 -0.0002 0.004 -0.011 0.00001
+1 -0.0001 1 1 0.0038 0.0022 0.007 -0.009 0.00018
+1 -0.0002 1 1 0.0034 0.0025 0.014 0.011 -0.00006
+1 0.0002 1 1 -0.0053 -0.0001 0.010 0.007 -0.00016
+1 0.0001 1 1 -0.0025 0.0005 0.008 -0.011 0.00012
+1 0.0001 1 1 -0.0032 -0.0002 0.009 -0.011 -0.00004
+1 0.0002 1 1 -0.0023 0.0017 0.015 -0.012 0.00000
+1 -0.0002 1 1 0.0056 0.0002 0.011 -0.007 0.00017
+1 0.0004 1 1 -0.0064 -0.0006 0.009 0.005 -0.00043
+1 -0.0001 1 1 0.0035 0.0023 0.011 -0.017 0.00020
+1 -0.0001 1 1 0.0057 -0.0003 0.011 -0.005 0.00006
+1 0.0004 1 1 -0.0054 0.0029 0.009 0.006 -0.00026
+1 -0.0001 1 1 0.0053 -0.0020 0.003 -0.008 0.00033
+1 -0.0002 1 1 0.0084 0.0014 0.004 0.002 0.00015
+1 -0.0003 1 1 0.0053 0.0017 0.012 0.027 -0.00018
+1 0.0004 1 1 -0.0060 0.0010 0.015 0.027 -0.00038
+1 0.0001 1 1 -0.0054 0.0038 0.015 0.010 -0.00029
+1 0.0001 1 1 -0.0079 0.0017 0.014 0.000 -0.00013
+1 0.0002 1 1 -0.0074 0.0009 0.014 -0.011 0.00009
+1 -0.0002 1 1 0.0069 -0.0008 0.005 -0.014 0.00029
+1 0.0002 1 1 -0.0073 0.0012 0.014 -0.004 -0.00019
+1 -0.0004 1 1 0.0069 0.0034 0.022 -0.006 0.00008
+1 0.0006 1 1 -0.0049 0.0021 0.019 0.006 -0.00017
+1 -0.0005 1 1 -0.0003 0.0027 0.013 -0.009 0.00013
+1 -0.0003 1 1 0.0051 0.0056 0.011 -0.004 0.00021
+1 -0.0004 1 1 0.0057 0.0052 0.015 0.010 -0.00004
+1 0.0003 1 1 -0.0069 0.0058 0.031 0.004 -0.00016
+1 0.0001 1 1 -0.0073 0.0037 0.031 -0.010 0.00003
+1 0.0002 1 1 -0.0014 0.0027 0.027 -0.028 0.00023
+1 -0.0005 1 1 0.0079 0.0029 0.024 -0.018 0.00024
+1 0.0008 1 1 -0.0050 0.0006 0.018 0.009 -0.00024
+1 0.0002 1 1 -0.0037 0.0063 0.023 -0.003 -0.00017
+1 0.0005 1 1 -0.0049 0.0040 0.023 -0.010 -0.00005
+1 -0.0004 1 1 0.0085 0.0022 0.015 -0.001 0.00014
+1 -0.0003 1 1 0.0059 0.0029 0.015 0.017 -0.00017
+1 0.0014 1 1 -0.0138 0.0034 0.014 -0.014 -0.00017
+1 -0.0001 1 1 0.0123 0.0072 0.010 -0.014 -0.00001
+1 0.0003 1 1 -0.0071 0.0021 0.012 0.025 -0.00015
+1 -0.0004 1 1 0.0043 0.0033 0.010 0.005 0.00022
+1 0.0005 1 1 -0.0077 0.0018 0.019 0.003 -0.00028
+1 -0.0004 1 1 0.0077 0.0050 0.009 -0.008 0.00013
+1 -0.0002 1 1 0.0011 0.0057 0.019 0.010 -0.00026
+1 0.0011 1 1 -0.0113 0.0043 0.024 -0.007 -0.00036
+1 -0.0005 1 1 0.0121 0.0018 0.017 -0.019 0.00047
+1 -0.0003 1 1 0.0135 0.0037 0.018 0.012 -0.00014
+1 -0.0002 1 1 0.0077 0.0032 0.020 0.031 -0.00037
+1 0.0001 1 1 -0.0082 0.0024 0.021 0.030 -0.00043
+1 -0.0003 1 1 0.0085 0.0009 0.006 -0.007 0.00046
+1 -0.0001 1 1 0.0116 0.0035 0.007 0.023 -0.00011
+1 -0.0002 1 1 0.0063 0.0036 0.010 0.045 -0.00029
+1 0.0001 1 1 -0.0044 0.0040 0.016 0.047 -0.00040
+1 -0.0003 1 1 0.0049 0.0014 0.010 0.025 0.00020
+1 0.0004 1 1 -0.0086 0.0038 0.015 0.024 -0.00031
+1 -0.0003 1 1 0.0112 0.0032 0.005 0.003 0.00020
+1 -0.0002 1 1 0.0039 0.0044 0.010 0.029 -0.00044
+1 0.0006 1 1 -0.0049 0.0047 0.014 0.028 -0.00058
+1 -0.0003 1 1 0.0032 0.0015 0.007 0.010 -0.00002
+1 0.0005 1 1 -0.0064 0.0021 0.006 0.006 -0.00029
+1 -0.0003 1 1 0.0087 0.0034 0.007 0.009 0.00017
+1 -0.0002 1 1 0.0058 0.0039 0.012 0.033 -0.00017
+1 0.0001 1 1 -0.0084 0.0033 0.020 0.024 -0.00020
+1 -0.0002 1 1 0.0050 0.0012 0.008 0.012 0.00001
+1 0.0004 1 1 -0.0066 0.0038 0.007 0.006 -0.00010
+1 0.0002 1 1 -0.0005 0.0030 0.002 -0.009 0.00006
+1 -0.0004 1 1 0.0034 0.0031 0.002 -0.007 0.00031
+1 0.0005 1 1 -0.0069 0.0050 0.011 -0.009 -0.00026
+1 -0.0004 1 1 0.0066 0.0033 0.017 -0.024 0.00040
+1 0.0002 1 1 0.0068 0.0035 0.021 0.011 -0.00014
+1 0.0002 1 1 -0.0069 0.0002 0.009 0.020 -0.00038
+1 0.0001 1 1 -0.0009 0.0037 0.000 -0.009 0.00020
+1 -0.0005 1 1 0.0031 0.0031 0.001 -0.008 0.00029
+1 0.0003 1 1 -0.0034 0.0041 0.014 -0.003 -0.00014
+1 -0.0004 1 1 0.0048 0.0007 0.010 -0.006 0.00018
+1 -0.0006 1 1 0.0063 0.0009 0.005 0.011 0.00011
+1 0.0005 1 1 -0.0117 0.0019 0.006 0.003 -0.00034
+1 -0.0004 1 1 0.0078 0.0077 -0.001 -0.024 0.00041
+1 0.0003 1 1 -0.0036 0.0008 0.017 0.010 -0.00014
+1 -0.0006 1 1 0.0073 -0.0001 0.007 0.011 0.00029
+1 -0.0002 1 1 0.0000 0.0038 0.011 0.028 -0.00036
+1 0.0001 1 1 -0.0091 0.0031 0.013 0.019 -0.00044
+1 0.0003 1 1 -0.0133 0.0017 0.012 0.003 -0.00022
+1 0.0001 1 1 0.0052 0.0004 -0.001 -0.026 0.00036
+1 -0.0001 1 1 0.0100 0.0031 -0.003 -0.015 0.00027
+1 -0.0002 1 1 0.0072 0.0097 0.009 0.012 -0.00026
+1 0.0001 1 1 -0.0065 0.0028 0.021 0.012 -0.00025
+1 -0.0004 1 1 0.0073 -0.0007 0.002 -0.004 0.00029
+1 -0.0002 1 1 0.0068 0.0042 0.003 0.013 -0.00011
+1 0.0002 1 1 -0.0061 0.0054 0.011 0.014 -0.00049
+1 0.0002 1 1 -0.0104 0.0020 0.012 -0.013 0.00012
+1 -0.0004 1 1 0.0068 0.0036 0.008 -0.025 0.00025
+1 0.0002 1 1 -0.0049 -0.0001 0.018 -0.001 -0.00005
+1 0.0002 1 1 -0.0041 0.0014 0.016 -0.010 0.00008
+1 -0.0005 1 1 0.0051 0.0031 0.017 -0.008 0.00014
+1 0.0005 1 1 -0.0043 0.0017 0.020 -0.009 -0.00004
+1 0.0001 1 1 0.0040 0.0026 0.020 -0.013 0.00024
+1 -0.0006 1 1 0.0075 0.0016 0.019 -0.005 0.00024
+1 -0.0003 1 1 0.0046 0.0034 0.022 0.013 -0.00021
+1 0.0005 1 1 -0.0065 0.0011 0.020 0.010 -0.00033
+1 0.0001 1 1 -0.0054 0.0031 0.021 -0.013 0.00021
+1 -0.0004 1 1 0.0074 0.0012 0.016 -0.008 0.00022
+1 -0.0002 1 1 0.0059 0.0030 0.018 0.010 -0.00013
+1 -0.0006 1 1 0.0022 -0.0007 0.014 0.010 0.00011
+1 0.0004 1 1 -0.0056 0.0026 0.012 0.007 -0.00032
+1 0.0004 1 1 -0.0072 0.0035 0.015 -0.013 0.00002
+1 -0.0004 1 1 0.0094 -0.0005 0.013 -0.003 0.00023
+1 -0.0002 1 1 0.0051 0.0022 0.013 0.033 -0.00017
+1 0.0003 1 1 -0.0066 0.0031 0.018 0.031 -0.00031
+1 -0.0003 1 1 0.0043 0.0056 0.008 0.011 -0.00002
+1 0.0007 1 1 -0.0067 -0.0017 0.027 0.006 -0.00024
+1 -0.0006 1 1 0.0059 -0.0012 0.016 -0.008 0.00047
+1 0.0002 1 1 -0.0035 0.0010 0.007 0.005 -0.00002
+1 -0.0002 1 1 0.0041 0.0035 0.008 0.014 0.00000
+1 -0.0002 1 1 -0.0044 0.0020 0.017 0.010 -0.00006
+1 0.0005 1 1 -0.0063 0.0006 0.015 0.001 -0.00014
+1 -0.0003 1 1 0.0063 -0.0002 0.006 -0.004 0.00029
+1 -0.0001 1 1 0.0075 0.0013 0.005 0.020 -0.00004
+1 -0.0002 1 1 0.0038 0.0049 0.013 0.035 -0.00016
+1 0.0006 1 1 -0.0115 -0.0009 0.024 0.010 -0.00014
+1 -0.0001 1 1 0.0045 0.0018 0.001 -0.002 0.00003
+1 -0.0003 1 1 0.0038 -0.0016 0.007 0.009 0.00020
+1 -0.0001 1 1 0.0040 -0.0003 0.004 0.016 -0.00008
+1 0.0003 1 1 0.0001 0.0014 0.017 -0.009 0.00006
+1 -0.0006 1 1 0.0053 0.0001 0.013 -0.005 0.00037
+1 0.0004 1 1 -0.0097 0.0003 0.011 -0.015 -0.00020
+1 -0.0006 1 1 0.0110 0.0007 0.005 -0.004 0.00003
+1 0.0002 1 1 -0.0080 0.0039 0.014 0.011 -0.00055
+1 0.0002 1 1 -0.0122 0.0050 0.018 -0.004 -0.00021
+1 -0.0001 1 1 0.0112 0.0020 0.019 -0.017 0.00054
+1 0.0001 1 1 0.0038 0.0028 0.022 0.013 -0.00051
+1 -0.0002 1 1 0.0052 -0.0012 -0.001 0.013 0.00003
+1 -0.0002 1 1 0.0040 0.0023 0.004 0.008 0.00012
+1 -0.0001 1 1 0.0040 0.0039 0.008 0.016 -0.00004
+1 -0.0004 1 1 0.0064 -0.0030 0.006 0.032 0.00020
+1 -0.0001 1 1 0.0047 -0.0016 0.001 0.042 -0.00027
+1 0.0001 1 1 -0.0056 0.0044 0.005 0.042 -0.00037
+1 0.0001 1 1 -0.0052 0.0039 0.012 0.008 -0.00012
+1 0.0002 1 1 -0.0048 0.0021 0.012 -0.011 0.00003
+1 -0.0002 1 1 0.0046 0.0023 0.013 -0.014 0.00025
+1 -0.0001 1 1 0.0060 0.0015 0.013 0.017 -0.00004
+1 0.0006 1 1 -0.0047 -0.0005 0.011 0.025 -0.00034
+1 0.0004 1 1 -0.0041 0.0035 -0.001 0.005 -0.00018
+1 -0.0002 1 1 0.0075 0.0035 0.018 0.014 0.00013
+1 -0.0001 1 1 0.0062 0.0008 0.021 0.026 -0.00013
+1 0.0002 1 1 -0.0044 -0.0023 0.008 0.032 -0.00025
+1 -0.0002 1 1 0.0093 0.0012 0.011 0.014 0.00013
+1 -0.0002 1 1 0.0075 0.0023 0.013 0.030 -0.00017
+1 0.0003 1 1 -0.0014 0.0034 0.003 -0.010 0.00006
+1 -0.0004 1 1 0.0046 0.0044 0.010 -0.007 0.00026
+1 0.0004 1 1 -0.0052 -0.0005 0.011 0.006 -0.00028
+1 -0.0002 1 1 0.0056 0.0023 0.000 -0.005 0.00022
+1 -0.0001 1 1 0.0053 0.0046 0.010 0.018 -0.00007
+1 0.0002 1 1 -0.0056 -0.0009 0.013 0.006 -0.00004
+1 0.0003 1 1 -0.0033 0.0036 0.021 -0.011 -0.00005
+1 -0.0001 1 1 0.0043 0.0005 0.017 -0.012 0.00021
+1 -0.0003 1 1 0.0070 -0.0028 0.013 -0.005 0.00020
+1 -0.0003 1 1 0.0013 -0.0014 0.003 0.011 -0.00022
+1 0.0005 1 1 -0.0073 0.0025 0.001 0.005 -0.00037
+1 0.0002 1 1 0.0038 0.0013 0.014 -0.011 0.00001
+1 -0.0002 1 1 0.0064 -0.0003 0.011 -0.004 0.00024
+1 -0.0003 1 1 0.0031 0.0003 0.008 0.010 -0.00018
+1 0.0009 1 1 -0.0073 0.0026 0.009 0.006 -0.00049
+1 -0.0004 1 1 0.0083 0.0022 0.007 -0.002 0.00039
+1 0.0005 1 1 -0.0068 0.0007 0.014 0.024 -0.00034
+1 -0.0005 1 1 0.0051 0.0003 0.007 0.008 0.00025
+1 -0.0001 1 1 -0.0065 0.0021 0.014 0.008 -0.00016
+1 0.0005 1 1 -0.0099 0.0017 0.014 -0.003 -0.00024
+1 0.0001 1 1 -0.0022 0.0039 0.003 -0.010 -0.00006
+1 -0.0003 1 1 0.0047 0.0008 0.011 -0.007 0.00013
+1 0.0001 1 1 -0.0048 0.0037 0.003 -0.010 -0.00003
+1 -0.0003 1 1 0.0037 -0.0007 0.014 -0.006 0.00008
+1 0.0003 1 1 -0.0056 0.0006 0.007 -0.009 -0.00015
+1 -0.0002 1 1 0.0091 0.0012 0.005 -0.004 0.00019
+1 0.0003 1 1 -0.0068 0.0012 0.006 0.016 -0.00040
+1 0.0002 1 1 -0.0085 0.0034 0.008 -0.014 0.00006
+1 -0.0004 1 1 0.0101 -0.0001 0.010 -0.019 0.00040
+1 0.0001 1 1 0.0017 0.0004 0.010 0.027 -0.00031
+1 -0.0001 1 1 -0.0066 0.0032 0.013 0.007 -0.00025
+1 -0.0004 1 1 0.0101 0.0035 -0.005 -0.024 0.00040
+1 -0.0005 1 1 0.0101 0.0078 0.006 0.017 -0.00014
+1 0.0004 1 1 -0.0082 0.0002 0.014 0.023 -0.00047
+1 -0.0002 1 1 0.0063 -0.0015 0.013 -0.025 0.00015
+1 0.0002 1 1 -0.0014 0.0005 0.026 -0.009 0.00000
+1 -0.0004 1 1 0.0029 -0.0064 0.018 -0.008 0.00010
+1 0.0003 1 1 -0.0041 0.0017 0.016 -0.009 -0.00009
+1 -0.0002 1 1 -0.0024 0.0019 0.020 -0.021 0.00009
+1 0.0004 1 1 -0.0022 0.0027 0.026 -0.028 0.00000
+1 -0.0002 1 1 0.0059 -0.0023 0.018 -0.022 0.00017
+1 -0.0002 1 1 0.0048 0.0006 0.014 0.011 -0.00008
+1 0.0003 1 1 -0.0034 -0.0015 0.015 0.014 -0.00020
+1 0.0003 1 1 -0.0035 0.0014 0.018 -0.011 -0.00005
+1 -0.0002 1 1 0.0070 -0.0002 0.016 0.003 0.00007
+1 -0.0001 1 1 0.0043 0.0016 0.019 0.016 -0.00025
+1 0.0001 1 1 -0.0034 0.0006 0.010 -0.010 0.00000
+1 -0.0002 1 1 0.0057 0.0004 0.013 -0.007 0.00009
+1 0.0001 1 1 -0.0051 -0.0009 0.012 0.006 -0.00002
+1 -0.0002 1 1 0.0040 -0.0002 0.012 0.010 0.00001
+1 0.0001 1 1 -0.0033 -0.0002 0.011 0.014 -0.00011
+1 -0.0001 1 1 0.0004 -0.0008 0.011 0.011 -0.00001
+1 -0.0001 1 1 -0.0034 0.0000 0.012 0.008 -0.00020
+1 0.0001 1 1 -0.0064 0.0011 0.012 -0.001 -0.00007
+1 0.0001 1 1 -0.0052 0.0009 0.013 -0.011 0.00008
+1 -0.0003 1 1 0.0046 0.0018 0.006 -0.007 0.00001
+1 -0.0001 1 1 -0.0010 -0.0017 0.010 -0.009 0.00006
+1 0.0001 1 1 -0.0014 -0.0004 0.009 -0.010 -0.00006
+1 0.0003 1 1 -0.0062 0.0004 0.013 -0.011 -0.00019
+1 0.0001 1 1 -0.0035 0.0000 0.011 -0.032 0.00014
+1 -0.0002 1 1 0.0069 0.0013 0.010 -0.021 0.00011
+1 0.0003 1 1 -0.0065 -0.0011 0.010 -0.014 -0.00007
+1 0.0004 1 1 -0.0045 0.0051 0.011 -0.026 -0.00018
+1 -0.0002 1 1 0.0070 0.0012 0.009 -0.025 0.00015
+1 -0.0003 1 1 0.0021 -0.0010 0.007 0.011 0.00000
+1 0.0003 1 1 -0.0096 0.0010 0.009 -0.002 -0.00027
+1 0.0001 1 1 -0.0059 0.0001 0.009 -0.031 0.00024
+1 0.0003 1 1 -0.0033 -0.0008 0.011 -0.010 -0.00017
+1 -0.0002 1 1 0.0038 -0.0014 0.007 -0.004 0.00013
+1 0.0001 1 1 -0.0043 0.0014 0.012 -0.003 -0.00011
+1 0.0001 1 1 -0.0044 -0.0011 0.009 -0.010 0.00002
+1 -0.0001 1 1 0.0055 0.0010 0.008 -0.004 0.00008
+1 -0.0002 1 1 0.0034 0.0014 0.012 0.011 -0.00010
+1 0.0002 1 1 -0.0057 -0.0010 0.012 0.006 -0.00016
+1 -0.0002 1 1 0.0058 -0.0001 0.006 -0.003 0.00016
+1 0.0002 1 1 -0.0022 0.0035 0.033 -0.024 0.00006
+1 0.0001 1 1 0.0043 0.0025 0.031 -0.016 0.00004
+1 0.0001 1 1 0.0054 0.0032 0.034 -0.005 0.00002
+1 -0.0008 1 1 0.0053 0.0005 0.031 0.011 -0.00004
+1 0.0011 1 1 -0.0064 -0.0011 0.025 0.011 -0.00031
+1 -0.0003 1 1 0.0043 0.0032 0.021 -0.009 0.00016
+1 -0.0005 1 1 0.0021 0.0039 0.030 0.009 -0.00009
+1 0.0012 1 1 -0.0042 0.0011 0.029 0.008 -0.00030
+1 -0.0003 1 1 0.0020 0.0026 0.021 0.010 -0.00004
+1 -0.0003 1 1 0.0042 0.0005 0.017 0.011 0.00011
+1 -0.0001 1 1 -0.0039 -0.0002 0.019 0.015 -0.00011
+1 0.0003 1 1 -0.0059 0.0008 0.018 0.007 -0.00007
+1 -0.0004 1 1 0.0059 0.0000 0.015 -0.006 0.00025
+1 0.0005 1 1 -0.0055 -0.0008 0.020 0.020 -0.00023
+1 0.0002 1 1 -0.0042 0.0013 0.015 0.007 -0.00012
+1 0.0001 1 1 0.0038 0.0012 0.017 -0.007 0.00013
+1 -0.0004 1 1 0.0040 0.0006 0.013 0.010 0.00015
+1 0.0002 1 1 -0.0033 0.0007 0.014 0.015 -0.00013
+1 -0.0002 1 1 0.0045 0.0008 0.014 0.011 0.00008
+1 0.0006 1 1 -0.0033 0.0012 0.027 -0.010 -0.00007
+1 -0.0004 1 1 0.0052 -0.0017 0.018 -0.009 0.00020
+1 -0.0002 1 1 0.0042 0.0036 0.015 0.011 -0.00009
+1 0.0004 1 1 -0.0052 0.0010 0.026 0.006 -0.00010
+1 0.0002 1 1 -0.0015 -0.0011 0.026 -0.011 0.00009
+1 -0.0006 1 1 0.0044 -0.0020 0.019 -0.008 0.00021
+1 0.0003 1 1 -0.0024 0.0013 0.020 -0.011 -0.00007
+1 -0.0002 1 1 0.0053 -0.0006 0.015 -0.004 0.00010
+1 0.0003 1 1 -0.0051 -0.0011 0.012 0.002 -0.00007
+1 -0.0002 1 1 0.0054 0.0014 0.021 -0.005 0.00014
+1 -0.0002 1 1 0.0051 -0.0002 0.020 0.011 -0.00006
+1 0.0001 1 1 -0.0033 -0.0013 0.011 0.016 -0.00016
+1 0.0001 1 1 -0.0055 0.0005 0.012 0.007 -0.00008
+1 0.0001 1 1 -0.0044 0.0012 0.013 -0.012 0.00006
+1 -0.0002 1 1 0.0053 0.0010 0.021 -0.002 0.00008
+1 0.0002 1 1 -0.0060 -0.0008 0.009 0.010 -0.00016
+1 0.0003 1 1 -0.0065 0.0003 0.013 -0.028 0.00011
+1 -0.0005 1 1 0.0118 -0.0006 0.007 -0.003 0.00012
+1 0.0001 1 1 -0.0038 -0.0002 0.012 0.005 -0.00009
+1 0.0001 1 1 -0.0006 0.0004 0.009 -0.010 0.00001
+1 -0.0002 1 1 0.0028 0.0030 0.005 -0.005 0.00005
+1 -0.0001 1 1 0.0037 -0.0006 0.014 0.011 0.00000
+1 0.0001 1 1 -0.0048 0.0000 0.010 0.006 -0.00008
+1 0.0001 1 1 -0.0020 -0.0006 0.008 -0.010 0.00010
+1 -0.0002 1 1 0.0040 0.0008 0.008 -0.006 0.00013
+1 0.0001 1 1 -0.0038 0.0016 0.017 -0.002 -0.00007
+1 0.0001 1 1 -0.0024 0.0003 0.017 -0.011 0.00009
+1 -0.0002 1 1 0.0061 -0.0019 0.008 -0.002 0.00015
+1 -0.0002 1 1 0.0041 -0.0003 0.006 0.011 -0.00015
+1 0.0002 1 1 -0.0044 -0.0009 0.006 0.007 -0.00009
+1 -0.0002 1 1 0.0041 0.0041 0.012 0.014 0.00004
+1 0.0001 1 1 -0.0062 0.0003 0.016 -0.001 -0.00001
+1 0.0003 1 1 -0.0040 0.0009 0.017 0.008 -0.00017
+1 -0.0001 1 1 0.0048 -0.0004 0.004 0.010 0.00003
+1 -0.0001 1 1 0.0036 0.0006 0.005 0.018 -0.00009
+1 0.0001 1 1 -0.0054 0.0012 0.010 0.008 -0.00007
+1 0.0001 1 1 -0.0039 0.0020 0.016 -0.010 0.00008
+1 -0.0001 1 1 0.0069 -0.0003 0.014 0.000 0.00012
+1 -0.0001 1 1 0.0066 0.0000 0.014 0.011 -0.00008
+1 0.0001 1 1 -0.0031 0.0013 0.005 -0.013 0.00004
+1 0.0001 1 1 -0.0036 -0.0005 0.014 0.011 -0.00017
+1 -0.0001 1 1 0.0039 0.0013 0.004 0.011 0.00002
+1 -0.0001 1 1 0.0023 -0.0001 0.006 0.027 0.00002
+1 -0.0001 1 1 0.0012 0.0010 0.008 0.030 -0.00012
+1 0.0001 1 1 -0.0058 0.0013 0.012 0.020 -0.00011
+1 -0.0002 1 1 0.0051 0.0010 0.003 -0.003 0.00013
+1 0.0001 1 1 -0.0033 0.0032 0.015 0.006 -0.00014
+1 -0.0001 1 1 0.0038 0.0008 0.012 -0.007 0.00019
+1 -0.0001 1 1 0.0062 -0.0009 0.009 0.010 0.00002
+1 -0.0001 1 1 0.0039 0.0014 0.009 0.031 -0.00009
+1 -0.0001 1 1 0.0026 -0.0022 0.002 0.027 0.00010
+1 -0.0001 1 1 0.0021 0.0011 0.004 0.036 -0.00006
+1 -0.0001 1 1 -0.0054 0.0017 0.021 0.025 -0.00003
+1 0.0001 1 1 -0.0065 0.0008 0.021 0.017 -0.00008
+1 -0.0001 1 1 0.0044 -0.0012 0.005 -0.006 0.00022
+1 -0.0002 1 1 0.0063 0.0000 0.004 0.012 0.00000
+1 0.0001 1 1 0.0042 0.0010 0.006 0.021 -0.00016
+1 -0.0001 1 1 0.0014 0.0013 0.008 0.027 -0.00012
+1 0.0002 1 1 -0.0046 0.0015 0.012 0.022 -0.00017
+1 0.0002 1 1 -0.0043 0.0014 0.006 -0.012 0.00000
+1 -0.0002 1 1 0.0054 0.0001 0.010 -0.004 0.00010
+1 0.0002 1 1 -0.0029 -0.0004 0.005 -0.011 0.00000
+1 -0.0002 1 1 0.0047 -0.0007 0.004 -0.005 0.00008
+1 -0.0002 1 1 0.0010 0.0022 0.012 0.009 0.00003
+1 0.0002 1 1 -0.0042 0.0007 0.014 0.003 -0.00010
+1 0.0003 1 1 -0.0024 0.0018 0.010 -0.010 -0.00008
+1 -0.0002 1 1 0.0048 0.0010 0.012 -0.008 0.00018
+1 0.0001 1 1 -0.0034 0.0005 0.014 0.018 -0.00011
+1 -0.0002 1 1 0.0042 0.0002 0.008 -0.003 0.00011
+1 0.0002 1 1 -0.0037 0.0001 0.009 0.006 -0.00016
+1 -0.0001 1 1 0.0039 0.0003 0.007 0.010 0.00002
+1 0.0001 1 1 -0.0037 0.0005 0.009 0.006 -0.00001
+1 0.0002 1 1 -0.0037 0.0001 0.010 -0.015 -0.00004
+1 -0.0002 1 1 0.0059 0.0004 0.009 -0.003 0.00006
+1 0.0001 1 1 -0.0046 0.0008 0.012 0.010 -0.00012
+1 0.0001 1 1 -0.0033 0.0008 0.010 -0.011 -0.00001
+1 -0.0001 1 1 0.0039 0.0006 0.011 -0.006 0.00004
+1 0.0001 1 1 -0.0015 0.0008 0.011 -0.009 -0.00002
+1 -0.0002 1 1 0.0039 0.0005 0.011 -0.003 0.00007
+1 -0.0002 1 1 0.0002 0.0008 0.013 0.010 -0.00009
+1 0.0003 1 1 -0.0043 -0.0006 0.011 0.006 -0.00026
+1 0.0002 1 1 -0.0049 0.0007 0.011 -0.012 0.00005
+1 -0.0001 1 1 0.0073 0.0015 0.008 0.013 -0.00002
+1 -0.0001 1 1 0.0054 0.0024 0.012 0.025 -0.00014
+1 0.0002 1 1 -0.0058 0.0002 0.014 0.025 -0.00021
+1 -0.0002 1 1 0.0033 0.0003 0.004 -0.008 0.00020
+1 -0.0001 1 1 0.0041 0.0008 0.005 0.011 -0.00007
+1 0.0001 1 1 -0.0033 0.0018 0.013 0.013 -0.00010
+1 0.0003 1 1 -0.0031 0.0000 0.011 -0.011 -0.00005
+1 -0.0001 1 1 0.0050 0.0021 0.005 -0.006 0.00002
+1 -0.0003 1 1 0.0012 0.0000 0.010 0.010 -0.00004
+1 0.0003 1 1 -0.0054 -0.0013 0.009 0.005 -0.00026
+1 -0.0001 1 1 0.0052 0.0010 0.005 -0.022 0.00032
+1 -0.0001 1 1 0.0050 0.0007 0.013 0.013 -0.00008
+1 0.0001 1 1 -0.0065 0.0001 0.011 0.003 -0.00008
+1 0.0001 1 1 -0.0051 0.0008 0.011 -0.012 0.00010
+1 0.0001 1 1 -0.0047 0.0014 0.005 0.006 -0.00011
+1 0.0001 1 1 -0.0030 0.0018 0.011 -0.011 0.00008
+1 -0.0002 1 1 0.0033 0.0008 0.012 -0.007 0.00000
+1 0.0001 1 1 -0.0040 0.0013 0.004 -0.012 -0.00006
+1 -0.0003 1 1 0.0056 0.0007 0.015 -0.004 0.00006
+1 0.0002 1 1 -0.0082 -0.0014 0.007 -0.013 -0.00010
+1 0.0001 1 1 -0.0067 0.0003 0.003 -0.034 0.00014
+1 -0.0002 1 1 0.0041 0.0014 0.005 -0.042 0.00030
+1 -0.0001 1 1 0.0043 0.0014 0.015 0.011 -0.00017
+1 0.0003 1 1 -0.0037 0.0003 0.016 0.011 -0.00018
+1 -0.0001 1 1 0.0037 -0.0023 0.002 -0.009 0.00018
+1 -0.0001 1 1 0.0072 0.0024 -0.002 0.013 0.00002
+1 -0.0001 1 1 0.0043 0.0032 0.005 0.029 -0.00015
+1 0.0001 1 1 -0.0015 0.0010 0.010 -0.010 0.00007
+1 -0.0001 1 1 0.0062 0.0007 0.012 0.007 0.00006
+1 0.0002 1 1 -0.0123 -0.0002 0.016 -0.003 -0.00017
+1 -0.0002 1 1 0.0102 -0.0005 0.005 -0.031 0.00026
+1 0.0004 1 1 -0.0130 0.0011 0.008 -0.002 -0.00038
+1 -0.0004 1 1 0.0060 0.0025 0.009 -0.043 0.00017
+1 0.0001 1 1 -0.0027 0.0004 0.017 -0.037 0.00003
+1 -0.0003 1 1 0.0091 0.0000 0.001 -0.007 0.00005
+1 -0.0002 1 1 0.0038 0.0007 0.001 0.011 -0.00027
+1 0.0006 1 1 -0.0065 0.0019 0.005 0.008 -0.00035
+1 -0.0001 1 1 0.0036 -0.0003 0.002 -0.013 0.00022
+1 -0.0001 1 1 0.0053 0.0022 0.005 -0.005 0.00005
+1 -0.0003 1 1 0.0049 0.0031 0.013 0.010 -0.00004
+1 0.0002 1 1 -0.0095 0.0014 0.005 -0.006 -0.00013
+1 -0.0001 1 1 0.0058 0.0018 0.000 -0.027 0.00024
+1 -0.0001 1 1 0.0084 0.0032 0.007 -0.008 0.00004
+1 0.0001 1 1 -0.0033 -0.0001 0.017 0.016 -0.00024
+1 0.0001 1 1 -0.0053 0.0003 0.017 0.005 -0.00005
+1 0.0002 1 1 -0.0053 -0.0015 0.011 -0.011 0.00003
+1 -0.0001 1 1 0.0037 0.0012 0.012 -0.005 0.00003
+1 0.0001 1 1 -0.0039 0.0004 0.012 -0.008 -0.00006
+1 -0.0002 1 1 0.0068 -0.0012 0.004 -0.003 0.00014
+1 -0.0002 1 1 0.0036 0.0022 0.012 0.029 -0.00013
+1 0.0001 1 1 -0.0065 0.0011 0.018 0.025 -0.00033
+1 -0.0002 1 1 0.0054 -0.0034 0.005 -0.011 0.00028
+1 -0.0001 1 1 0.0089 -0.0020 -0.003 0.012 0.00004
+1 -0.0001 1 1 0.0059 0.0051 0.001 0.037 -0.00015
+1 -0.0001 1 1 0.0009 0.0044 0.010 0.045 -0.00024
+1 -0.0001 1 1 -0.0041 0.0046 0.017 0.043 -0.00032
+1 0.0001 1 1 -0.0089 -0.0001 0.017 0.033 -0.00033
+1 0.0004 1 1 -0.0132 -0.0004 0.015 0.001 -0.00006
+1 0.0001 1 1 -0.0058 -0.0006 0.012 -0.030 0.00043
+1 -0.0002 1 1 0.0081 0.0000 0.008 -0.020 0.00010
+1 -0.0001 1 1 0.0038 0.0001 0.007 0.013 0.00002
+1 0.0003 1 1 -0.0085 0.0010 0.010 0.005 -0.00031
+1 -0.0001 1 1 0.0063 0.0003 0.003 -0.024 0.00030
+1 -0.0003 1 1 0.0087 0.0026 0.007 0.017 -0.00005
+1 0.0003 1 1 -0.0078 -0.0001 0.015 0.023 -0.00035
+1 0.0001 1 1 -0.0036 -0.0010 0.008 -0.013 0.00019
+1 -0.0001 1 1 0.0034 0.0003 0.006 -0.005 0.00000
+1 0.0001 1 1 -0.0008 0.0004 0.010 -0.010 0.00003
+1 0.0002 1 1 -0.0037 0.0006 0.010 -0.012 -0.00005
+1 -0.0002 1 1 0.0053 0.0002 0.008 -0.004 0.00007
+1 -0.0002 1 1 0.0015 0.0006 0.008 0.010 -0.00014
+1 0.0004 1 1 -0.0041 0.0010 0.009 0.007 -0.00028
+1 -0.0002 1 1 0.0035 0.0001 0.007 -0.008 0.00013
+1 -0.0003 1 1 0.0025 -0.0009 0.001 0.011 0.00008
+1 -0.0001 1 1 0.0015 0.0004 0.005 0.010 0.00000
+1 0.0003 1 1 -0.0063 0.0010 0.009 -0.010 -0.00009
+1 -0.0002 1 1 0.0077 0.0016 0.015 -0.005 0.00009
+1 0.0001 1 1 -0.0051 -0.0004 0.012 0.007 -0.00004
+1 0.0001 1 1 -0.0034 0.0007 0.012 0.007 -0.00006
+1 0.0001 1 1 -0.0022 -0.0002 0.008 -0.011 0.00000
+1 -0.0002 1 1 0.0042 0.0003 0.007 -0.007 0.00012
+1 -0.0001 1 1 0.0024 0.0016 0.010 0.011 -0.00002
+1 0.0001 1 1 -0.0035 0.0008 0.013 0.007 -0.00006
+1 -0.0002 1 1 0.0012 -0.0004 0.003 0.010 0.00001
+1 0.0001 1 1 -0.0066 0.0012 0.006 0.002 -0.00019
+1 0.0002 1 1 -0.0052 0.0009 0.006 -0.012 0.00006
+1 -0.0001 1 1 0.0054 0.0014 0.007 -0.004 0.00002
+1 -0.0001 1 1 0.0021 0.0019 0.013 0.011 -0.00011
+1 0.0001 1 1 -0.0045 -0.0012 0.018 0.005 -0.00015
+1 -0.0001 1 1 0.0035 0.0006 0.004 0.015 -0.00003
+1 0.0001 1 1 0.0038 -0.0006 0.011 0.007 0.00009
+1 -0.0001 1 1 -0.0049 -0.0001 0.004 0.011 -0.00006
+1 0.0002 1 1 -0.0033 0.0007 0.005 -0.011 0.00009
+1 -0.0003 1 1 0.0057 0.0004 0.004 -0.005 0.00015
+1 0.0001 1 1 -0.0015 0.0041 0.027 -0.010 0.00011
+1 -0.0004 1 1 0.0056 0.0026 0.026 -0.005 0.00021
+1 -0.0001 1 1 0.0057 0.0026 0.029 0.018 -0.00012
+1 -0.0001 1 1 -0.0065 -0.0012 0.012 0.009 -0.00013
+1 0.0002 1 1 -0.0058 0.0036 0.003 -0.013 0.00015
+1 0.0001 1 1 0.0043 0.0076 0.019 -0.014 0.00009
+1 -0.0004 1 1 0.0054 0.0048 0.023 -0.007 0.00007
+1 -0.0005 1 1 0.0056 -0.0008 0.016 0.015 0.00013
+1 -0.0002 1 1 0.0016 0.0002 0.010 0.027 -0.00021
+1 0.0005 1 1 -0.0041 0.0007 0.007 0.025 -0.00033
+1 -0.0005 1 1 0.0056 0.0041 0.013 0.010 0.00005
+1 0.0005 1 1 -0.0071 0.0023 0.018 0.002 -0.00011
+1 -0.0010 1 1 0.0049 0.0029 0.014 -0.010 0.00028
+1 -0.0004 1 1 0.0063 0.0015 0.018 0.014 0.00013
+1 -0.0001 1 1 -0.0040 0.0016 0.012 0.015 -0.00002
+1 0.0005 1 1 -0.0071 0.0033 0.014 0.005 -0.00037
+1 0.0001 1 1 -0.0086 0.0051 0.016 -0.010 0.00007
+1 -0.0002 1 1 0.0073 0.0009 0.013 -0.024 0.00034
+1 0.0004 1 1 -0.0060 0.0024 0.015 -0.011 -0.00011
+1 0.0001 1 1 -0.0076 0.0043 0.014 -0.014 0.00026
+1 -0.0001 1 1 0.0050 0.0057 0.016 -0.020 0.00031
+1 -0.0004 1 1 0.0090 0.0057 0.018 -0.008 0.00017
+1 0.0004 1 1 -0.0056 0.0006 0.019 0.003 -0.00011
+1 0.0002 1 1 -0.0045 0.0070 0.005 -0.002 -0.00022
+1 0.0002 1 1 -0.0058 0.0062 0.009 -0.012 -0.00001
+1 -0.0003 1 1 0.0046 0.0021 0.018 -0.007 0.00001
+1 0.0003 1 1 -0.0041 0.0039 0.014 -0.012 -0.00004
+1 0.0001 1 1 0.0036 0.0038 0.010 -0.016 0.00023
+1 -0.0009 1 1 0.0105 0.0047 0.012 0.007 0.00015
+1 0.0001 1 1 0.0036 0.0048 0.014 0.024 -0.00059
+1 0.0001 1 1 -0.0058 0.0039 0.016 0.020 -0.00033
+1 0.0005 1 1 -0.0103 0.0046 0.017 0.003 -0.00017
+1 -0.0004 1 1 0.0122 0.0022 0.008 -0.008 0.00038
+1 -0.0002 1 1 0.0139 0.0062 0.008 0.019 -0.00010
+1 0.0005 1 1 -0.0083 0.0010 0.022 0.036 -0.00031
+1 -0.0001 1 1 0.0047 0.0021 0.011 0.011 0.00010
+1 -0.0001 1 1 0.0015 0.0036 0.010 0.028 -0.00012
+1 -0.0002 1 1 -0.0008 0.0028 0.010 0.029 -0.00018
+1 0.0005 1 1 -0.0106 0.0034 0.009 0.009 -0.00024
+1 0.0002 1 1 -0.0093 0.0029 0.008 -0.011 0.00023
+1 -0.0001 1 1 0.0042 0.0060 0.013 -0.023 0.00036
+1 -0.0003 1 1 0.0094 0.0061 0.017 -0.009 0.00020
+1 -0.0001 1 1 0.0073 0.0050 0.021 0.013 -0.00022
+1 0.0001 1 1 0.0035 0.0038 0.021 0.020 -0.00029
+1 -0.0005 1 1 0.0038 0.0035 0.004 0.010 0.00012
+1 0.0004 1 1 -0.0076 0.0064 0.009 0.005 -0.00024
+1 0.0002 1 1 -0.0063 0.0041 0.010 -0.013 0.00016
+1 -0.0005 1 1 0.0087 0.0041 0.011 -0.005 0.00019
+1 -0.0001 1 1 0.0060 0.0046 0.013 0.013 -0.00026
+1 0.0003 1 1 -0.0105 0.0051 0.020 -0.012 -0.00008
+1 0.0001 1 1 -0.0036 0.0018 0.027 -0.014 0.00018
+1 -0.0001 1 1 0.0037 0.0013 0.023 -0.014 0.00017
+1 -0.0003 1 1 0.0052 0.0018 0.023 -0.008 0.00008
+1 -0.0001 1 1 0.0032 0.0008 0.025 0.010 0.00006
+1 0.0004 1 1 -0.0039 -0.0005 0.017 0.014 -0.00030
+1 0.0002 1 1 -0.0035 0.0035 0.016 -0.014 0.00008
+1 0.0001 1 1 -0.0005 0.0033 0.026 -0.017 -0.00006
+1 0.0002 1 1 -0.0007 0.0019 0.027 -0.018 0.00001
+1 -0.0003 1 1 0.0054 -0.0021 0.023 -0.005 0.00002
+1 0.0001 1 1 -0.0070 0.0025 0.018 -0.015 -0.00008
+1 -0.0004 1 1 0.0068 0.0026 0.017 -0.021 0.00010
+1 0.0014 1 1 -0.0057 0.0019 0.023 -0.011 -0.00043
+1 -0.0005 1 1 0.0052 -0.0001 0.016 -0.024 0.00039
+1 -0.0002 1 1 0.0079 0.0018 0.016 0.018 0.00002
+1 0.0009 1 1 -0.0059 0.0008 0.018 0.027 -0.00032
+1 -0.0004 1 1 0.0019 -0.0014 0.020 0.011 0.00027
+1 -0.0003 1 1 -0.0038 -0.0019 0.020 0.011 -0.00010
+1 0.0003 1 1 -0.0070 -0.0011 0.016 0.002 -0.00017
+1 -0.0005 1 1 0.0056 0.0019 0.010 -0.007 0.00024
+1 -0.0004 1 1 0.0035 0.0016 0.007 0.018 -0.00001
+1 0.0001 1 1 -0.0050 0.0031 0.018 0.016 -0.00021
+1 0.0003 1 1 -0.0068 0.0018 0.017 0.007 -0.00009
+1 -0.0005 1 1 0.0059 0.0024 0.016 -0.001 0.00013
+1 -0.0004 1 1 0.0021 0.0033 0.008 0.010 -0.00004
+1 -0.0003 1 1 0.0057 0.0025 0.014 0.011 0.00005
+1 0.0004 1 1 -0.0065 -0.0018 0.007 0.008 -0.00020
+1 0.0001 1 1 -0.0021 0.0033 0.004 -0.012 0.00009
+1 0.0002 1 1 -0.0005 0.0018 0.016 -0.010 -0.00016
+1 -0.0002 1 1 0.0031 0.0003 0.005 -0.006 0.00000
+1 0.0001 1 1 -0.0052 0.0020 0.007 -0.010 -0.00016
+1 0.0001 1 1 -0.0036 0.0047 0.011 -0.030 0.00008
+1 0.0001 1 1 0.0064 0.0017 0.017 -0.027 0.00020
+1 -0.0007 1 1 0.0112 0.0000 0.014 -0.010 0.00022
+1 -0.0003 1 1 0.0055 0.0013 0.014 0.012 -0.00044
+1 0.0010 1 1 -0.0086 -0.0002 0.011 0.009 -0.00065
+1 -0.0007 1 1 0.0100 -0.0001 0.008 -0.007 0.00016
+1 -0.0005 1 1 0.0048 0.0009 0.009 0.011 0.00023
+1 -0.0001 1 1 -0.0038 -0.0015 0.013 0.017 -0.00018
+1 0.0005 1 1 -0.0075 -0.0006 0.010 0.007 -0.00019
+1 -0.0004 1 1 0.0030 0.0043 0.005 -0.008 0.00013
+1 0.0001 1 1 -0.0004 0.0012 0.013 -0.009 0.00011
+1 -0.0006 1 1 0.0046 0.0006 0.011 -0.005 0.00023
+1 0.0001 1 1 -0.0039 0.0004 0.012 0.000 -0.00029
+1 -0.0002 1 1 0.0047 0.0017 0.007 -0.004 0.00022
+1 -0.0002 1 1 0.0045 0.0023 0.011 0.011 -0.00006
+1 0.0004 1 1 -0.0057 -0.0003 0.009 0.007 -0.00016
+1 -0.0002 1 1 0.0004 0.0022 0.006 0.010 -0.00004
+1 0.0003 1 1 -0.0066 -0.0013 0.012 -0.001 -0.00014
+1 0.0001 1 1 -0.0057 -0.0001 0.010 -0.012 0.00015
+1 -0.0002 1 1 0.0060 0.0026 0.009 -0.006 0.00009
+1 -0.0001 1 1 0.0039 0.0006 0.011 0.012 -0.00004
+1 -0.0002 1 1 0.0037 -0.0006 0.008 0.004 0.00030
+1 0.0001 1 1 -0.0040 -0.0005 0.015 0.016 -0.00022
+1 0.0002 1 1 -0.0061 -0.0015 0.011 0.008 -0.00008
+1 0.0001 1 1 -0.0008 0.0072 0.004 -0.010 0.00001
+1 -0.0002 1 1 0.0043 -0.0010 0.012 -0.003 0.00013
+1 0.0001 1 1 -0.0060 0.0022 0.005 -0.018 -0.00004
+1 0.0001 1 1 -0.0043 0.0023 0.006 -0.030 0.00011
+1 -0.0002 1 1 0.0085 0.0020 0.009 -0.012 0.00010
+1 0.0004 1 1 -0.0035 0.0007 0.011 0.008 -0.00027
+1 0.0003 1 1 -0.0021 0.0024 0.012 -0.010 -0.00010
+1 -0.0004 1 1 0.0045 0.0027 0.012 -0.007 0.00016
+1 -0.0001 1 1 0.0039 0.0012 0.013 -0.006 0.00007
+1 0.0001 1 1 -0.0071 0.0008 0.011 0.005 -0.00024
+1 0.0002 1 1 -0.0073 -0.0006 0.008 -0.013 0.00017
+1 -0.0003 1 1 0.0054 0.0011 0.009 0.011 0.00000
+1 0.0003 1 1 -0.0069 -0.0002 0.006 0.006 -0.00016
+1 -0.0002 1 1 0.0044 0.0017 0.011 0.011 -0.00006
+1 0.0005 1 1 -0.0050 0.0019 0.015 0.011 -0.00029
+1 -0.0002 1 1 0.0085 0.0009 0.006 0.026 0.00004
+1 -0.0001 1 1 0.0054 0.0021 0.007 0.041 -0.00044
+1 0.0006 1 1 -0.0096 0.0023 0.011 0.037 -0.00068
+1 0.0003 1 1 -0.0031 0.0008 0.008 -0.011 -0.00007
+1 -0.0002 1 1 0.0058 0.0026 0.007 -0.008 0.00022
+1 -0.0002 1 1 0.0035 0.0025 0.012 0.013 -0.00013
+1 0.0001 1 1 -0.0035 0.0012 0.014 0.014 -0.00045
+1 0.0006 1 1 -0.0089 -0.0006 0.011 0.003 -0.00027
+1 -0.0002 1 1 0.0073 0.0032 0.011 -0.001 0.00002
+1 0.0005 1 1 -0.0089 0.0002 0.011 0.002 -0.00028
+1 -0.0003 1 1 0.0059 -0.0006 0.003 -0.007 0.00013
+1 -0.0003 1 1 0.0028 0.0003 0.009 0.010 0.00003
+1 0.0002 1 1 -0.0037 0.0002 0.009 0.009 -0.00012
+1 -0.0002 1 1 0.0037 0.0013 0.009 0.012 0.00001
+1 0.0002 1 1 -0.0039 -0.0003 0.006 0.007 -0.00004
+1 -0.0003 1 1 0.0054 0.0021 0.009 0.011 0.00010
+1 -0.0001 1 1 0.0041 0.0025 0.011 0.021 -0.00016
+1 0.0001 1 1 -0.0046 0.0027 0.013 0.006 -0.00007
+1 -0.0005 1 1 0.0040 0.0024 0.003 -0.006 0.00011
+1 0.0005 1 1 -0.0085 0.0034 0.012 -0.013 -0.00028
+1 0.0001 1 1 -0.0069 0.0011 0.011 -0.030 0.00021
+1 -0.0002 1 1 0.0060 -0.0002 0.009 -0.005 0.00018
+1 -0.0004 1 1 0.0016 0.0018 0.011 0.010 -0.00017
+1 0.0010 1 1 -0.0078 0.0030 0.014 0.006 -0.00068
+1 -0.0002 1 1 0.0054 0.0014 0.007 -0.003 0.00005
+1 -0.0004 1 1 0.0035 0.0024 0.009 0.010 -0.00006
+1 0.0005 1 1 -0.0043 0.0008 0.011 0.009 -0.00018
+1 -0.0004 1 1 0.0035 0.0001 0.007 0.028 0.00008
+1 0.0003 1 1 -0.0067 0.0029 0.014 0.025 -0.00026
+1 -0.0001 1 1 0.0040 0.0024 0.009 0.010 0.00000
+1 0.0004 1 1 -0.0076 0.0001 0.011 0.004 -0.00022
+1 -0.0003 1 1 0.0061 0.0036 0.002 -0.005 0.00019
+1 0.0001 1 1 0.0023 0.0040 0.009 0.009 -0.00020
+1 0.0003 1 1 -0.0043 0.0011 0.009 0.006 -0.00019
+1 0.0001 1 1 -0.0017 0.0011 0.010 -0.010 -0.00001
+1 -0.0004 1 1 0.0043 0.0017 0.004 -0.007 0.00019
+1 0.0003 1 1 -0.0077 0.0001 0.015 -0.018 -0.00008
+1 -0.0003 1 1 0.0042 0.0005 0.009 -0.033 0.00027
+1 -0.0002 1 1 0.0063 0.0005 0.010 -0.001 0.00010
+1 -0.0004 1 1 0.0038 0.0010 0.010 0.010 -0.00017
+1 0.0008 1 1 -0.0081 0.0018 0.011 0.007 -0.00048
+1 0.0005 1 1 -0.0023 0.0024 0.008 -0.010 -0.00016
+1 -0.0003 1 1 0.0050 0.0032 0.008 -0.009 0.00027
+1 -0.0003 1 1 0.0053 -0.0008 0.012 0.011 -0.00005
+1 0.0002 1 1 -0.0046 0.0021 0.011 -0.011 -0.00007
+1 0.0001 1 1 -0.0002 0.0016 0.025 -0.009 0.00010
+1 0.0001 1 1 -0.0026 -0.0001 0.019 -0.018 0.00002
+1 -0.0002 1 1 0.0045 0.0003 0.020 -0.004 0.00005
+1 -0.0003 1 1 0.0024 0.0001 0.019 0.011 -0.00006
+1 0.0001 1 1 -0.0034 0.0006 0.020 0.010 -0.00023
+1 0.0002 1 1 -0.0058 -0.0030 0.019 0.003 -0.00014
+1 -0.0001 1 1 -0.0023 -0.0003 0.016 -0.015 0.00012
+1 -0.0001 1 1 0.0028 0.0001 0.011 -0.005 -0.00002
+1 0.0002 1 1 -0.0029 0.0032 0.022 -0.011 0.00001
+1 -0.0001 1 1 0.0054 -0.0011 0.015 -0.005 0.00011
+1 -0.0001 1 1 0.0043 -0.0003 0.012 0.011 -0.00007
+1 -0.0001 1 1 0.0032 0.0010 0.016 0.010 0.00003
+1 -0.0001 1 1 0.0022 0.0008 0.015 0.011 0.00002
+1 -0.0001 1 1 0.0019 -0.0003 0.010 0.010 0.00002
+1 0.0001 1 1 -0.0027 0.0003 0.012 -0.011 -0.00001
+1 -0.0001 1 1 0.0038 0.0004 0.012 -0.008 0.00006
+1 0.0001 1 1 -0.0039 0.0013 0.011 -0.011 -0.00001
+1 -0.0001 1 1 0.0032 0.0005 0.011 0.010 -0.00004
+1 0.0001 1 1 -0.0038 -0.0001 0.011 0.007 -0.00007
+1 -0.0001 1 1 0.0040 0.0009 0.012 0.010 0.00002
+1 0.0009 1 1 -0.0096 0.0024 0.027 -0.010 -0.00014
+1 0.0004 1 1 -0.0059 0.0032 0.024 -0.028 0.00032
+1 -0.0001 1 1 0.0071 0.0033 0.020 -0.028 0.00053
+1 -0.0004 1 1 0.0104 -0.0015 0.020 0.013 -0.00016
+1 0.0002 1 1 0.0053 0.0007 0.016 0.026 -0.00038
+1 0.0007 1 1 -0.0044 0.0039 0.021 0.025 -0.00022
+1 -0.0009 1 1 0.0041 0.0014 0.022 0.009 0.00013
+1 0.0003 1 1 -0.0064 0.0024 0.018 0.006 -0.00022
+1 0.0005 1 1 -0.0065 0.0022 0.013 -0.013 0.00005
+1 -0.0002 1 1 0.0047 0.0070 0.020 -0.020 0.00020
+1 0.0002 1 1 0.0061 0.0065 0.024 -0.010 0.00003
+1 -0.0003 1 1 0.0076 0.0021 0.025 0.012 0.00002
+1 0.0006 1 1 -0.0053 0.0011 0.015 0.026 -0.00031
+1 -0.0002 1 1 0.0044 0.0027 0.013 0.006 0.00014
+1 0.0002 1 1 -0.0045 0.0009 0.021 0.005 -0.00003
+1 -0.0002 1 1 0.0033 0.0041 0.015 0.011 -0.00002
+1 0.0004 1 1 -0.0040 0.0038 0.017 0.009 -0.00013
+1 0.0003 1 1 -0.0021 0.0017 0.011 -0.010 -0.00001
+1 0.0003 1 1 -0.0025 0.0047 0.021 -0.011 0.00008
+1 -0.0005 1 1 0.0046 0.0012 0.015 -0.008 0.00020
+1 0.0003 1 1 -0.0035 0.0043 0.017 -0.010 -0.00005
+1 -0.0007 1 1 0.0076 0.0017 0.015 -0.002 0.00016
+1 0.0009 1 1 -0.0065 0.0033 0.015 0.007 -0.00052
+1 0.0002 1 1 -0.0049 0.0026 0.014 -0.010 0.00031
+1 -0.0005 1 1 0.0066 0.0032 0.013 -0.008 0.00035
+1 0.0001 1 1 0.0049 0.0043 0.016 0.018 -0.00022
+1 0.0002 1 1 -0.0035 0.0052 0.014 -0.029 0.00019
+1 -0.0003 1 1 0.0053 0.0016 0.019 -0.025 0.00017
+1 0.0005 1 1 -0.0026 0.0014 0.025 -0.010 -0.00003
+1 -0.0004 1 1 0.0063 0.0004 0.019 -0.005 0.00020
+1 -0.0002 1 1 0.0035 0.0013 0.017 0.017 -0.00013
+1 0.0001 1 1 -0.0040 0.0000 0.012 0.017 -0.00020
+1 0.0002 1 1 -0.0068 0.0012 0.011 0.004 -0.00009
+1 -0.0003 1 1 0.0054 0.0014 0.022 0.012 -0.00001
+1 0.0004 1 1 -0.0067 0.0007 0.015 0.005 -0.00009
+1 0.0001 1 1 0.0087 0.0016 0.017 0.000 0.00023
+1 -0.0002 1 1 0.0117 -0.0003 0.015 0.014 0.00016
+1 0.0014 1 1 -0.0153 0.0005 0.015 0.010 -0.00041
+1 0.0001 1 1 -0.0051 -0.0001 0.011 -0.028 0.00073
+1 -0.0003 1 1 0.0049 0.0009 0.009 -0.028 0.00069
+1 -0.0006 1 1 0.0115 -0.0022 0.013 0.020 -0.00013
+1 0.0001 1 1 -0.0058 0.0009 0.012 0.015 -0.00001
+1 0.0005 1 1 -0.0022 0.0017 0.013 -0.010 -0.00009
+1 -0.0004 1 1 0.0060 0.0013 0.013 -0.006 0.00029
+1 -0.0004 1 1 0.0053 0.0004 0.011 0.012 -0.00013
+1 0.0001 1 1 -0.0065 -0.0012 0.005 0.012 -0.00041
+1 0.0001 1 1 -0.0074 0.0024 0.004 -0.012 0.00016
+1 -0.0004 1 1 0.0083 0.0017 0.010 -0.010 0.00022
+1 0.0001 1 1 -0.0052 0.0036 0.019 0.009 -0.00034
+1 0.0002 1 1 -0.0063 0.0011 0.018 -0.012 0.00010
+1 -0.0003 1 1 0.0082 0.0001 0.008 -0.005 0.00015
+1 -0.0003 1 1 0.0059 0.0007 0.007 0.014 -0.00019
+1 0.0005 1 1 -0.0085 0.0024 0.011 0.009 -0.00032
+1 0.0001 1 1 -0.0083 0.0019 0.012 -0.012 0.00015
+1 -0.0002 1 1 0.0048 0.0017 0.013 -0.021 0.00026
+1 0.0005 1 1 -0.0037 0.0007 0.014 0.008 -0.00014
+1 -0.0006 1 1 0.0066 -0.0001 0.008 0.010 0.00024
+1 0.0005 1 1 -0.0057 0.0034 0.011 0.023 -0.00028
+1 0.0001 1 1 0.0011 0.0033 0.019 0.009 0.00025
+1 -0.0008 1 1 0.0083 -0.0029 0.015 0.023 0.00024
+1 0.0007 1 1 -0.0035 0.0017 0.015 0.037 -0.00049
+1 -0.0001 1 1 0.0007 -0.0017 -0.002 0.011 0.00008
+1 0.0001 1 1 -0.0052 0.0030 0.018 0.006 -0.00005
+1 0.0002 1 1 -0.0014 -0.0002 0.015 -0.009 0.00014
+1 0.0001 1 1 0.0038 0.0014 0.014 -0.008 0.00034
+1 -0.0003 1 1 0.0093 0.0004 0.012 0.002 0.00032
+1 -0.0002 1 1 0.0095 0.0007 0.010 0.021 -0.00022
+1 0.0005 1 1 -0.0083 0.0006 0.008 0.023 -0.00027
+1 0.0004 1 1 -0.0014 0.0017 0.008 -0.010 -0.00001
+1 -0.0008 1 1 0.0070 0.0030 0.013 -0.004 0.00029
+1 -0.0002 1 1 0.0010 0.0022 0.003 0.009 -0.00003
+1 0.0003 1 1 -0.0043 0.0035 0.008 0.006 -0.00022
+1 -0.0002 1 1 0.0069 0.0009 0.008 0.022 0.00001
+1 0.0004 1 1 -0.0066 -0.0017 0.013 0.024 -0.00014
+1 -0.0001 1 1 0.0022 0.0008 0.004 0.011 0.00018
+1 -0.0002 1 1 0.0044 0.0011 0.005 0.030 0.00000
+1 0.0002 1 1 -0.0056 0.0016 0.009 0.025 -0.00013
+1 -0.0004 1 1 0.0059 0.0021 0.014 0.012 0.00015
+1 0.0005 1 1 -0.0079 0.0001 0.014 0.006 -0.00016
+1 -0.0002 1 1 0.0056 0.0033 0.006 -0.008 0.00026
+1 -0.0002 1 1 0.0065 0.0024 0.010 0.017 -0.00004
+1 0.0003 1 1 -0.0046 -0.0003 0.012 0.024 -0.00017
+1 -0.0001 1 1 0.0024 0.0005 0.002 0.028 -0.00004
+1 0.0002 1 1 -0.0073 0.0029 0.009 0.018 -0.00017
+1 -0.0004 1 1 0.0055 -0.0005 0.008 -0.005 0.00032
+1 0.0002 1 1 0.0028 0.0022 0.009 0.009 -0.00033
+1 0.0004 1 1 -0.0036 0.0019 0.012 0.006 -0.00014
+1 -0.0003 1 1 0.0041 0.0019 0.014 0.003 0.00029
+1 -0.0001 1 1 0.0044 0.0023 0.017 0.012 -0.00008
+1 0.0002 1 1 -0.0061 -0.0017 0.003 0.005 -0.00014
+1 -0.0003 1 1 0.0052 0.0034 0.006 -0.007 0.00025
+1 -0.0003 1 1 0.0040 0.0001 0.014 0.013 -0.00007
+1 0.0002 1 1 -0.0050 0.0004 0.011 0.012 -0.00028
+1 0.0002 1 1 -0.0007 -0.0006 0.007 -0.010 0.00022
+1 -0.0005 1 1 0.0094 0.0005 0.005 0.002 0.00034
+1 -0.0002 1 1 0.0049 0.0019 0.007 0.029 -0.00026
+1 0.0001 1 1 -0.0004 0.0029 0.010 0.033 -0.00041
+1 0.0004 1 1 -0.0054 -0.0004 0.010 0.027 -0.00025
+1 0.0002 1 1 -0.0056 0.0060 0.012 0.012 -0.00080
+1 -0.0004 1 1 0.0124 0.0023 0.013 -0.004 0.00019
+1 -0.0003 1 1 0.0081 0.0010 0.017 0.033 -0.00023
+1 0.0003 1 1 -0.0099 -0.0032 0.005 0.022 -0.00021
+1 -0.0001 1 1 -0.0008 -0.0025 0.010 -0.010 0.00011
+1 0.0001 1 1 -0.0035 0.0036 0.018 -0.011 -0.00005
+1 -0.0002 1 1 0.0044 -0.0004 0.017 -0.008 0.00005
+1 0.0002 1 1 -0.0036 0.0007 0.017 -0.003 -0.00004
+1 -0.0003 1 1 0.0042 0.0000 0.016 -0.007 0.00013
+1 0.0002 1 1 -0.0043 0.0011 0.006 -0.010 -0.00003
+1 -0.0002 1 1 0.0040 0.0005 0.018 0.011 -0.00003
+1 0.0003 1 1 -0.0066 -0.0024 0.011 0.000 -0.00009
+1 -0.0001 1 1 0.0069 -0.0001 0.006 -0.008 0.00020
+1 -0.0001 1 1 0.0086 0.0002 0.006 0.004 0.00005
+1 -0.0001 1 1 0.0042 0.0028 0.016 0.033 -0.00016
+1 0.0001 1 1 -0.0037 -0.0020 0.021 0.032 -0.00014
+1 0.0001 1 1 -0.0055 -0.0028 0.014 0.021 -0.00005
+1 -0.0001 1 1 0.0047 0.0001 0.002 0.012 0.00008
+1 -0.0001 1 1 0.0028 0.0026 0.012 0.028 -0.00007
+1 0.0001 1 1 -0.0013 0.0007 0.006 -0.009 0.00007
+1 -0.0002 1 1 0.0029 0.0014 0.010 -0.008 0.00017
+1 0.0002 1 1 -0.0049 0.0005 0.017 -0.010 -0.00007
+1 -0.0001 1 1 0.0070 0.0021 0.004 0.003 0.00004
+1 -0.0001 1 1 0.0059 0.0024 0.007 0.012 -0.00013
+1 0.0002 1 1 -0.0055 -0.0014 0.011 0.005 -0.00006
+1 0.0001 1 1 -0.0020 -0.0042 0.007 -0.012 0.00013
+1 -0.0001 1 1 0.0057 -0.0004 0.000 -0.005 0.00017
+1 -0.0001 1 1 0.0073 0.0034 0.008 0.030 -0.00009
+1 0.0001 1 1 -0.0086 0.0027 0.003 0.019 -0.00006
+1 -0.0002 1 1 0.0063 0.0004 0.015 -0.001 0.00017
+1 0.0001 1 1 -0.0070 -0.0021 0.010 0.012 -0.00021
+1 0.0002 1 1 -0.0075 0.0003 0.010 -0.011 0.00011
+1 -0.0002 1 1 0.0082 -0.0001 0.006 -0.005 0.00013
+1 -0.0001 1 1 0.0080 0.0013 0.008 0.015 -0.00007
+1 0.0001 1 1 -0.0069 -0.0004 0.001 0.020 -0.00015
+1 -0.0001 1 1 0.0043 0.0011 0.009 -0.018 0.00017
+1 -0.0001 1 1 0.0053 0.0012 0.015 0.012 -0.00004
+1 0.0003 1 1 -0.0090 -0.0002 0.013 -0.006 -0.00010
+1 0.0001 1 1 -0.0063 -0.0022 0.009 -0.028 0.00027
+1 -0.0002 1 1 0.0036 0.0000 0.006 -0.033 0.00025
+1 -0.0002 1 1 0.0072 0.0003 0.006 -0.005 0.00001
+1 0.0002 1 1 -0.0074 0.0014 0.013 0.003 -0.00045
+1 0.0001 1 1 -0.0055 -0.0006 0.011 -0.028 0.00023
+1 -0.0004 1 1 0.0079 -0.0027 0.009 -0.021 0.00021
+1 0.0001 1 1 -0.0021 0.0006 0.013 -0.010 0.00004
+1 -0.0005 1 1 0.0062 -0.0010 0.011 -0.001 0.00013
+1 -0.0001 1 1 0.0003 0.0023 0.014 0.011 -0.00034
+1 0.0004 1 1 -0.0051 -0.0003 0.014 0.007 -0.00039
+1 -0.0002 1 1 0.0060 0.0013 0.003 -0.008 0.00006
+1 -0.0002 1 1 0.0021 -0.0017 0.006 0.009 0.00004
+1 0.0002 1 1 -0.0043 0.0008 0.008 0.006 -0.00013
+1 -0.0002 1 1 0.0022 0.0014 0.013 0.011 -0.00002
+1 0.0002 1 1 -0.0065 0.0001 0.013 0.003 -0.00020
+1 0.0001 1 1 -0.0069 -0.0004 0.012 -0.013 0.00004
+1 -0.0002 1 1 0.0039 0.0013 0.007 -0.024 0.00019
+1 0.0004 1 1 -0.0044 -0.0009 0.012 -0.010 -0.00016
+1 -0.0001 1 1 0.0063 0.0012 0.005 -0.007 0.00011
+1 -0.0002 1 1 0.0038 0.0017 0.010 0.012 -0.00011
+1 0.0003 1 1 -0.0061 0.0000 0.013 0.005 -0.00016
+1 -0.0001 1 1 0.0058 0.0013 0.003 -0.001 0.00003
+1 -0.0001 1 1 0.0038 0.0029 0.009 0.016 -0.00009
+1 0.0002 1 1 -0.0069 -0.0018 0.009 0.007 -0.00015
+1 -0.0004 1 1 0.0045 0.0020 0.008 -0.007 0.00018
+1 0.0002 1 1 -0.0034 0.0004 0.019 -0.001 -0.00016
+1 0.0001 1 1 -0.0036 -0.0010 0.017 -0.011 0.00006
+1 -0.0001 1 1 0.0050 -0.0014 0.002 0.001 0.00002
+1 -0.0001 1 1 0.0038 -0.0007 0.009 0.010 0.00005
+1 0.0001 1 1 -0.0024 -0.0003 0.009 -0.010 0.00004
+1 -0.0002 1 1 0.0045 0.0003 0.009 -0.005 0.00013
+1 0.0003 1 1 -0.0055 0.0001 0.009 0.001 -0.00015
+1 -0.0001 1 1 0.0041 -0.0005 0.003 -0.014 0.00013
+1 0.0002 1 1 -0.0053 0.0011 0.012 0.004 -0.00017
+1 -0.0002 1 1 0.0065 0.0014 0.007 -0.003 0.00010
+1 -0.0001 1 1 0.0046 0.0010 0.009 0.011 -0.00015
+1 0.0004 1 1 -0.0058 -0.0005 0.009 0.010 -0.00034
+1 0.0001 1 1 -0.0057 -0.0003 0.008 -0.013 0.00011
+1 -0.0001 1 1 0.0047 0.0004 0.007 -0.016 0.00019
+1 -0.0001 1 1 0.0074 0.0005 0.008 0.002 0.00005
+1 -0.0001 1 1 0.0032 0.0009 0.011 0.029 -0.00016
+1 0.0002 1 1 -0.0074 0.0004 0.012 0.022 -0.00026
+1 0.0001 1 1 -0.0061 -0.0015 0.011 -0.013 0.00012
+1 -0.0003 1 1 0.0079 0.0023 0.007 -0.002 0.00012
+1 -0.0001 1 1 0.0057 0.0019 0.014 0.016 -0.00023
+1 0.0001 1 1 -0.0044 0.0012 0.018 0.018 -0.00022
+1 0.0002 1 1 -0.0077 -0.0010 0.016 0.002 -0.00008
+1 0.0001 1 1 -0.0061 -0.0006 0.014 -0.010 0.00017
+1 -0.0002 1 1 0.0087 -0.0001 0.002 0.003 0.00012
+1 0.0001 1 1 -0.0006 0.0011 0.007 0.033 -0.00024
+1 0.0002 1 1 -0.0034 0.0007 0.009 0.023 -0.00003
+1 0.0001 1 1 -0.0079 0.0013 0.016 0.004 -0.00021
+1 0.0002 1 1 -0.0086 -0.0004 0.015 -0.010 0.00001
+1 -0.0002 1 1 0.0079 0.0009 0.001 -0.021 0.00019
+1 0.0002 1 1 -0.0044 0.0017 0.008 0.012 -0.00037
+1 0.0001 1 1 -0.0050 0.0007 0.013 -0.012 0.00013
+1 0.0003 1 1 -0.0056 -0.0014 0.006 -0.012 -0.00019
+1 -0.0002 1 1 0.0047 0.0005 0.006 -0.023 0.00024
+1 -0.0001 1 1 0.0068 0.0008 0.008 -0.003 0.00001
+1 0.0001 1 1 -0.0052 -0.0016 0.002 0.005 -0.00010
+1 -0.0003 1 1 0.0050 0.0016 0.011 -0.006 0.00012
+1 -0.0002 1 1 0.0023 -0.0013 0.014 0.009 0.00004
+1 0.0003 1 1 -0.0044 -0.0006 0.009 0.007 -0.00017
+1 0.0002 1 1 -0.0038 0.0003 0.007 -0.011 -0.00007
+1 -0.0002 1 1 0.0052 -0.0002 0.007 -0.005 0.00007
+1 -0.0002 1 1 0.0002 -0.0007 0.006 0.010 -0.00011
+1 0.0004 1 1 -0.0040 -0.0004 0.005 0.007 -0.00028
+1 -0.0001 1 1 0.0033 0.0019 0.013 -0.007 0.00007
+1 0.0003 1 1 -0.0053 0.0018 0.015 -0.011 -0.00023
+1 -0.0003 1 1 0.0077 -0.0038 0.014 -0.020 0.00023
+1 -0.0006 1 1 0.0040 -0.0009 0.009 0.011 -0.00005
+1 0.0006 1 1 -0.0099 -0.0013 0.009 0.006 -0.00046
+1 -0.0002 1 1 0.0102 0.0046 0.004 -0.008 0.00008
+1 -0.0002 1 1 0.0067 0.0047 0.014 0.012 -0.00024
+1 0.0003 1 1 -0.0064 -0.0003 0.020 0.011 -0.00028
+1 -0.0002 1 1 0.0052 0.0021 0.009 -0.008 0.00007
+1 0.0002 1 1 -0.0049 -0.0006 0.002 -0.012 -0.00005
+1 -0.0001 1 1 0.0051 0.0011 0.010 -0.004 0.00002
+1 0.0003 1 1 -0.0042 -0.0015 0.013 -0.010 -0.00001
+1 -0.0001 1 1 0.0042 -0.0021 0.001 -0.012 0.00016
+1 -0.0001 1 1 0.0048 0.0010 0.001 0.012 -0.00007
+1 0.0002 1 1 -0.0066 0.0005 0.012 0.004 -0.00010
+1 0.0001 1 1 -0.0046 0.0000 0.012 -0.011 0.00013
+1 -0.0002 1 1 0.0053 -0.0002 0.009 -0.008 0.00016
+1 0.0002 1 1 -0.0037 -0.0022 0.012 0.016 -0.00015
+1 -0.0001 1 1 0.0014 0.0012 0.012 0.010 -0.00001
+1 0.0003 1 1 -0.0042 -0.0002 0.013 0.003 -0.00011
+1 -0.0001 1 1 0.0046 -0.0002 0.004 0.002 0.00013
+1 -0.0001 1 1 0.0060 0.0011 0.006 0.016 0.00002
+1 -0.0001 1 1 0.0017 0.0014 0.011 0.036 -0.00017
+1 0.0002 1 1 -0.0062 -0.0016 0.009 0.024 -0.00012
+1 -0.0001 1 1 0.0038 -0.0010 0.012 0.013 0.00001
+1 0.0001 1 1 -0.0042 -0.0004 -0.002 -0.012 0.00002
+1 -0.0001 1 1 0.0065 0.0042 0.016 -0.006 0.00013
+1 -0.0004 1 1 0.0062 -0.0018 0.018 0.011 -0.00009
+1 0.0002 1 1 -0.0048 -0.0004 0.016 0.009 -0.00008
+1 -0.0001 1 1 0.0049 -0.0006 0.005 0.011 -0.00002
+1 0.0001 1 1 -0.0051 0.0005 0.008 0.003 -0.00002
+1 0.0001 1 1 -0.0026 0.0002 0.008 -0.012 0.00012
+1 -0.0001 1 1 0.0039 0.0018 0.010 -0.009 0.00014
+1 0.0001 1 1 -0.0061 -0.0034 0.006 -0.010 -0.00012
+1 -0.0001 1 1 0.0047 0.0036 0.010 -0.025 0.00012
+1 -0.0001 1 1 0.0042 0.0011 0.021 -0.006 -0.00001
+1 0.0001 1 1 -0.0057 -0.0035 0.006 -0.009 -0.00012
+1 0.0001 1 1 -0.0044 -0.0017 -0.002 -0.028 0.00013
+1 -0.0002 1 1 0.0087 0.0044 0.003 -0.017 0.00018
+1 -0.0001 1 1 0.0084 0.0046 0.017 0.012 -0.00007
+1 0.0003 1 1 -0.0075 -0.0015 0.019 0.018 -0.00022
+1 0.0001 1 1 -0.0036 -0.0028 0.008 -0.011 0.00017
+1 -0.0002 1 1 0.0062 -0.0002 0.001 -0.003 0.00014
+1 -0.0001 1 1 0.0042 0.0033 0.005 0.015 -0.00008
+1 0.0002 1 1 -0.0073 -0.0011 0.012 0.002 -0.00013
+1 0.0001 1 1 -0.0051 -0.0009 0.010 -0.012 0.00017
+1 -0.0001 1 1 0.0052 0.0001 0.008 -0.011 0.00017
+1 -0.0002 1 1 0.0055 0.0004 0.009 0.017 -0.00005
+1 0.0001 1 1 -0.0112 -0.0016 0.008 0.000 -0.00018
+1 -0.0001 1 1 0.0090 0.0011 0.011 -0.023 0.00018
+1 -0.0002 1 1 0.0106 -0.0006 0.012 -0.010 0.00007
+1 -0.0003 1 1 0.0073 0.0006 0.014 0.011 -0.00020
+1 0.0004 1 1 -0.0098 -0.0012 0.009 0.008 -0.00040
+1 0.0002 1 1 -0.0107 -0.0005 0.007 -0.013 0.00012
+1 -0.0001 1 1 0.0063 0.0011 0.002 -0.027 0.00034
+1 -0.0002 1 1 0.0111 0.0012 0.004 -0.007 0.00011
+1 -0.0002 1 1 0.0065 0.0018 0.009 0.026 -0.00021
+1 0.0004 1 1 -0.0078 -0.0018 0.009 0.022 -0.00028
+1 -0.0003 1 1 0.0021 -0.0004 0.010 0.011 0.00000
+1 0.0001 1 1 -0.0038 -0.0007 0.008 0.010 -0.00023
+1 0.0001 1 1 -0.0061 0.0023 0.008 0.004 -0.00016
+1 0.0001 1 1 -0.0054 0.0007 0.009 -0.012 0.00007
+1 -0.0001 1 1 0.0064 0.0003 0.010 -0.005 0.00009
+1 0.0004 1 1 -0.0088 0.0018 0.017 0.004 -0.00043
+1 -0.0001 1 1 0.0068 0.0108 0.007 -0.020 0.00030
+1 0.0001 1 1 0.0094 0.0028 0.016 -0.009 0.00009
+1 -0.0001 1 1 0.0106 -0.0045 0.017 0.005 0.00008
+1 0.0001 1 1 -0.0070 -0.0013 0.013 0.021 -0.00046
+1 0.0004 1 1 -0.0136 -0.0025 0.007 0.002 -0.00038
+1 0.0001 1 1 -0.0060 -0.0014 -0.001 -0.041 0.00037
+1 -0.0003 1 1 0.0045 0.0000 -0.003 -0.043 0.00040
+1 0.0001 1 1 0.0064 0.0006 0.014 -0.009 0.00001
+1 -0.0003 1 1 0.0039 -0.0010 0.011 0.013 -0.00017
+1 0.0004 1 1 -0.0088 -0.0007 0.009 0.007 -0.00040
+1 0.0001 1 1 -0.0097 -0.0005 0.008 -0.012 0.00010
+1 0.0001 1 1 -0.0056 -0.0006 0.006 -0.028 0.00026
+1 -0.0001 1 1 0.0074 -0.0008 0.001 -0.023 0.00022
+1 -0.0001 1 1 0.0093 0.0004 0.001 -0.004 0.00003
+1 -0.0001 1 1 0.0072 0.0040 0.010 0.018 -0.00012
+1 0.0004 1 1 -0.0113 -0.0028 0.014 0.010 -0.00025
+1 0.0001 1 1 -0.0050 -0.0039 -0.002 -0.028 0.00035
+1 -0.0003 1 1 0.0058 0.0030 -0.002 -0.026 0.00027
+1 0.0001 1 1 -0.0045 0.0003 0.014 -0.003 -0.00019
+1 0.0001 1 1 -0.0055 0.0001 0.014 -0.012 -0.00001
+1 -0.0001 1 1 0.0073 -0.0006 0.002 -0.005 0.00011
+1 -0.0001 1 1 0.0062 0.0048 0.003 0.013 -0.00009
+1 0.0001 1 1 -0.0054 0.0001 0.017 0.014 -0.00009
+1 0.0001 1 1 -0.0063 -0.0015 0.014 0.005 -0.00005
+1 0.0001 1 1 -0.0022 -0.0014 0.007 -0.012 0.00013
+1 -0.0001 1 1 0.0047 -0.0006 0.001 -0.006 0.00013
+1 0.0002 1 1 -0.0061 0.0022 0.009 0.009 -0.00014
+1 0.0001 1 1 -0.0004 -0.0008 0.006 -0.010 0.00015
+1 -0.0001 1 1 0.0050 0.0009 0.004 -0.004 0.00019
+1 -0.0001 1 1 0.0061 0.0031 0.007 0.011 -0.00001
+1 0.0002 1 1 -0.0035 0.0002 0.019 0.024 -0.00018
+1 -0.0002 1 1 0.0039 0.0000 -0.004 0.008 0.00011
+1 0.0001 1 1 -0.0038 -0.0025 0.007 0.004 -0.00001
+1 -0.0002 1 1 0.0083 -0.0027 0.010 0.024 0.00006
+1 -0.0001 1 1 0.0065 -0.0021 0.005 0.040 -0.00015
+1 0.0003 1 1 -0.0077 0.0028 0.011 0.042 -0.00045
+1 -0.0001 1 1 0.0060 0.0001 0.004 -0.012 0.00019
+1 -0.0002 1 1 0.0081 0.0013 0.006 0.001 0.00008
+1 -0.0001 1 1 -0.0050 -0.0017 0.009 0.009 -0.00003
+1 -0.0002 1 1 0.0038 -0.0005 -0.001 -0.007 0.00017
+1 0.0001 1 1 0.0023 0.0022 0.004 0.009 -0.00005
+1 0.0002 1 1 -0.0057 0.0026 0.014 0.007 -0.00023
+1 -0.0001 1 1 0.0044 -0.0019 -0.001 -0.001 0.00000
+1 -0.0003 1 1 0.0019 0.0016 0.007 0.011 0.00009
+1 0.0002 1 1 -0.0052 0.0008 0.013 0.007 -0.00022
+1 -0.0002 1 1 0.0070 0.0014 0.009 -0.002 0.00010
+1 -0.0001 1 1 0.0042 0.0012 0.012 0.014 -0.00015
+1 0.0002 1 1 -0.0070 -0.0023 0.004 0.001 -0.00011
+1 0.0001 1 1 0.0043 0.0021 0.010 -0.013 0.00002
+1 0.0005 1 1 -0.0122 0.0024 0.018 -0.010 -0.00005
+1 -0.0001 1 1 -0.0059 0.0054 0.019 -0.036 0.00037
+1 -0.0001 1 1 0.0061 0.0041 0.025 -0.041 0.00039
+1 -0.0003 1 1 0.0120 0.0033 0.026 -0.023 0.00023
+1 0.0011 1 1 -0.0148 -0.0019 0.014 0.008 -0.00049
+1 -0.0006 1 1 0.0115 0.0053 0.002 -0.024 0.00042
+1 0.0001 1 1 0.0053 0.0060 0.023 0.034 -0.00022
+1 0.0007 1 1 -0.0075 -0.0014 0.013 0.022 -0.00012
+1 -0.0006 1 1 0.0042 0.0028 0.007 0.010 0.00026
+1 0.0001 1 1 -0.0055 0.0000 0.009 0.004 -0.00006
+1 -0.0003 1 1 0.0033 0.0036 0.019 -0.008 0.00008
+1 0.0002 1 1 -0.0037 0.0005 0.010 -0.011 -0.00006
+1 -0.0003 1 1 0.0068 -0.0001 0.008 -0.003 0.00020
+1 -0.0002 1 1 0.0071 0.0032 0.007 0.015 -0.00006
+1 0.0001 1 1 -0.0035 0.0023 0.020 0.023 -0.00010
+1 -0.0001 1 1 0.0003 0.0034 0.006 0.028 -0.00010
+1 0.0001 1 1 -0.0041 0.0046 0.012 0.025 -0.00022
+1 -0.0002 1 1 0.0051 0.0014 0.010 0.004 0.00015
+1 -0.0002 1 1 0.0040 0.0019 0.011 0.032 -0.00007
+1 0.0002 1 1 -0.0093 0.0026 0.018 0.014 -0.00014
+1 0.0002 1 1 -0.0070 0.0005 0.015 -0.011 0.00015
+1 -0.0003 1 1 0.0035 0.0003 0.009 -0.018 0.00028
+1 -0.0001 1 1 0.0059 0.0027 0.010 0.011 -0.00004
+1 0.0005 1 1 -0.0108 0.0030 0.008 -0.016 -0.00004
+1 -0.0002 1 1 0.0092 0.0041 0.012 -0.025 0.00033
+1 -0.0002 1 1 0.0112 0.0015 0.014 -0.004 0.00002
+1 -0.0001 1 1 0.0038 0.0017 0.015 0.028 -0.00022
+1 0.0001 1 1 -0.0063 0.0010 0.013 0.022 -0.00021
+1 0.0003 1 1 -0.0081 0.0002 0.011 0.012 -0.00008
+1 -0.0004 1 1 0.0037 0.0010 0.009 0.003 0.00039
+1 -0.0002 1 1 0.0064 0.0018 0.009 0.019 -0.00002
+1 -0.0001 1 1 -0.0014 0.0022 0.012 0.030 -0.00022
+1 -0.0002 1 1 -0.0066 0.0024 0.014 0.022 -0.00024
+1 0.0005 1 1 -0.0141 0.0001 0.011 -0.001 -0.00030
+1 -0.0002 1 1 0.0070 0.0020 0.007 -0.040 0.00040
+1 -0.0002 1 1 0.0101 0.0064 0.011 -0.027 0.00012
+1 -0.0005 1 1 0.0088 0.0024 0.015 0.012 -0.00010
+1 0.0005 1 1 -0.0103 -0.0012 0.012 0.009 -0.00028
+1 -0.0001 1 1 0.0045 0.0023 -0.002 -0.013 0.00001
+1 -0.0005 1 1 0.0039 0.0017 0.016 0.011 0.00013
+1 0.0006 1 1 -0.0087 -0.0001 0.008 0.003 -0.00023
+1 -0.0004 1 1 0.0069 0.0008 0.001 -0.008 0.00029
+1 0.0001 1 1 -0.0058 0.0032 0.003 0.018 -0.00021
+1 0.0001 1 1 -0.0067 0.0038 0.011 -0.011 0.00003
+1 -0.0007 1 1 0.0070 0.0004 0.013 -0.022 0.00048
+1 0.0002 1 1 -0.0045 0.0005 0.003 -0.016 -0.00007
+1 -0.0002 1 1 0.0069 0.0029 0.011 -0.004 0.00007
+1 0.0005 1 1 -0.0070 -0.0004 0.009 0.003 -0.00018
+1 -0.0004 1 1 0.0067 0.0034 0.009 -0.005 0.00030
+1 0.0006 1 1 -0.0066 0.0007 0.011 0.010 -0.00030
+1 -0.0001 1 1 0.0065 0.0004 0.010 0.019 0.00002
+1 -0.0002 1 1 0.0043 0.0007 0.003 0.005 0.00020
+1 0.0002 1 1 -0.0049 0.0032 0.019 0.009 -0.00012
+1 -0.0002 1 1 0.0048 0.0001 0.002 0.015 -0.00001
+1 -0.0001 1 1 -0.0039 0.0012 0.010 0.016 -0.00005
+1 0.0001 1 1 -0.0067 0.0033 0.009 -0.005 -0.00005
+1 -0.0004 1 1 0.0065 0.0009 0.014 -0.022 0.00033
+1 0.0002 1 1 -0.0051 0.0006 0.004 0.005 -0.00014
+1 -0.0002 1 1 0.0035 0.0011 0.005 0.012 0.00000
+1 0.0005 1 1 -0.0062 0.0016 0.005 0.007 -0.00015
+1 -0.0002 1 1 0.0088 0.0036 0.014 0.012 0.00017
+1 -0.0002 1 1 0.0036 0.0013 0.017 0.040 -0.00023
+1 0.0006 1 1 -0.0110 -0.0001 0.011 0.025 -0.00030
+1 -0.0001 1 1 0.0047 0.0011 0.005 0.021 -0.00004
+1 0.0003 1 1 -0.0080 -0.0003 0.009 0.009 -0.00012
+1 -0.0004 1 1 0.0058 0.0016 0.009 -0.007 0.00033
+1 -0.0003 1 1 0.0036 0.0024 0.012 0.011 -0.00015
+1 0.0006 1 1 -0.0078 0.0021 0.013 0.006 -0.00039
+1 0.0002 1 1 -0.0046 0.0019 0.013 -0.014 0.00030
+1 -0.0003 1 1 0.0060 -0.0004 0.008 -0.013 0.00037
+1 -0.0001 1 1 0.0095 0.0011 0.006 0.013 0.00002
+1 -0.0001 1 1 0.0075 0.0042 0.010 0.027 -0.00019
+1 -0.0004 1 1 -0.0033 -0.0018 -0.002 0.030 -0.00006
+1 0.0006 1 1 -0.0110 0.0057 0.005 0.014 -0.00036
+1 -0.0003 1 1 0.0038 0.0028 0.017 -0.022 0.00033
+1 -0.0001 1 1 0.0076 -0.0007 0.007 0.021 -0.00003
+1 -0.0003 1 1 -0.0062 0.0033 0.013 0.029 -0.00010
+1 0.0006 1 1 -0.0125 0.0000 0.010 0.006 -0.00023
+1 0.0002 1 1 0.0046 0.0024 0.006 -0.013 0.00006
+1 -0.0001 1 1 0.0066 0.0030 0.008 -0.005 0.00014
+1 0.0003 1 1 -0.0024 -0.0020 0.014 -0.011 0.00006
+1 -0.0003 1 1 0.0062 -0.0009 0.004 -0.006 0.00025
+1 -0.0003 1 1 0.0045 0.0034 0.009 0.018 -0.00012
+1 0.0001 1 1 -0.0042 0.0038 0.016 0.019 -0.00031
+1 0.0004 1 1 -0.0089 0.0009 0.017 0.004 -0.00019
+1 0.0001 1 1 -0.0051 0.0010 0.015 -0.014 0.00031
+1 -0.0004 1 1 0.0076 -0.0011 0.005 -0.009 0.00030
+1 -0.0001 1 1 0.0053 0.0005 0.001 0.019 -0.00009
+1 -0.0002 1 1 0.0012 0.0048 0.001 0.030 -0.00015
+1 0.0001 1 1 -0.0056 0.0048 0.010 0.025 -0.00026
+1 0.0002 1 1 -0.0080 0.0031 0.012 0.013 -0.00010
+1 0.0001 1 1 -0.0008 0.0002 0.008 -0.010 0.00023
+1 -0.0003 1 1 0.0050 0.0051 0.006 -0.005 0.00027
+1 -0.0001 1 1 0.0056 0.0033 0.012 0.013 -0.00004
+1 0.0004 1 1 -0.0109 -0.0006 0.006 -0.011 -0.00017
+1 0.0001 1 1 -0.0041 0.0017 0.003 -0.047 0.00023
+1 -0.0004 1 1 0.0133 0.0060 0.006 -0.024 0.00023
+1 -0.0002 1 1 0.0098 0.0058 0.017 0.012 -0.00024
+1 0.0006 1 1 -0.0061 -0.0010 0.011 0.004 -0.00018
+1 -0.0001 1 1 0.0046 -0.0010 0.003 -0.003 0.00040
+1 -0.0006 1 1 0.0104 0.0018 0.003 0.013 0.00023
+1 -0.0001 1 1 0.0051 0.0028 0.006 0.031 -0.00047
+1 0.0011 1 1 -0.0065 0.0036 0.010 0.030 -0.00079
+1 -0.0005 1 1 0.0061 0.0028 0.011 0.010 0.00010
+1 -0.0003 1 1 0.0056 -0.0002 0.013 0.029 0.00013
+1 -0.0001 1 1 -0.0047 0.0011 0.006 0.035 -0.00016
+1 0.0004 1 1 -0.0109 0.0018 0.007 0.007 -0.00011
+1 0.0001 1 1 -0.0061 0.0002 0.005 -0.013 0.00032
+1 0.0001 1 1 0.0038 0.0035 0.009 -0.009 0.00004
+1 0.0002 1 1 -0.0038 0.0016 0.021 -0.029 0.00012
+1 -0.0002 1 1 0.0069 -0.0010 0.020 -0.022 0.00017
+1 -0.0002 1 1 0.0081 0.0003 0.020 -0.005 0.00001
+1 -0.0001 1 1 0.0037 0.0002 0.019 0.011 -0.00024
+1 0.0001 1 1 -0.0023 -0.0011 0.016 -0.010 0.00009
+1 0.0002 1 1 -0.0048 0.0023 0.016 -0.013 -0.00010
+1 0.0002 1 1 -0.0027 0.0002 0.018 -0.028 0.00009
+1 -0.0002 1 1 0.0051 -0.0005 0.015 -0.024 0.00016
+1 0.0001 1 1 -0.0038 0.0006 0.018 -0.011 -0.00006
+1 -0.0001 1 1 0.0047 -0.0028 0.010 -0.018 0.00016
+1 -0.0002 1 1 0.0068 0.0011 0.011 -0.006 0.00006
+1 -0.0002 1 1 0.0037 0.0026 0.019 0.013 -0.00013
+1 -0.0002 1 1 0.0042 -0.0004 0.013 -0.006 0.00013
+1 -0.0001 1 1 0.0027 -0.0007 0.015 0.011 -0.00004
+1 0.0002 1 1 -0.0044 0.0011 0.016 0.006 -0.00008
+1 0.0001 1 1 -0.0013 -0.0017 0.012 -0.009 0.00011
+1 -0.0003 1 1 0.0028 -0.0020 0.006 -0.008 0.00014
+1 0.0001 1 1 0.0041 0.0013 0.018 -0.015 0.00016
+1 -0.0005 1 1 0.0071 0.0007 0.018 -0.005 0.00015
+1 -0.0003 1 1 0.0024 0.0015 0.019 0.011 -0.00025
+1 0.0007 1 1 -0.0099 -0.0010 0.015 -0.004 -0.00028
+1 -0.0002 1 1 0.0097 0.0016 0.010 -0.019 0.00026
+1 -0.0004 1 1 0.0112 0.0004 0.009 0.001 0.00000
+1 0.0001 1 1 0.0037 0.0007 0.009 0.022 -0.00038
+1 0.0002 1 1 -0.0043 0.0002 0.017 0.005 -0.00006
+1 -0.0002 1 1 0.0046 0.0007 0.007 0.002 0.00015
+1 -0.0002 1 1 0.0040 0.0018 0.010 0.016 -0.00007
+1 0.0004 1 1 -0.0082 0.0016 0.017 0.004 -0.00017
+1 0.0001 1 1 -0.0061 -0.0005 0.014 -0.013 0.00019
diff --git a/library/cpp/linear_regression/benchmark/kin8nm.features b/library/cpp/linear_regression/benchmark/kin8nm.features
new file mode 100644
index 0000000000..3b6f7fedfa
--- /dev/null
+++ b/library/cpp/linear_regression/benchmark/kin8nm.features
@@ -0,0 +1,8192 @@
+1 5.3652416e-01 1 1 -1.5119208e-02 3.6074091e-01 4.6939777e-01 1.3096745e+00 9.8802387e-01 -2.5492554e-02 6.6407094e-01 6.2762996e-02
+1 3.0801430e-01 1 1 3.6047801e-01 -3.0139478e-01 6.2918307e-01 -1.4401463e+00 -7.4163685e-01 -1.1967495e+00 -1.0384439e+00 -7.1746120e-01
+1 5.1889978e-01 1 1 1.5632379e+00 -1.2947529e+00 7.8987171e-02 1.4329368e+00 1.1491364e+00 -1.2921402e+00 1.5629882e+00 -9.3773069e-01
+1 4.9415079e-01 1 1 1.9948468e-01 9.0115659e-01 -1.3563042e+00 -8.0524638e-02 -9.7662848e-01 8.2989378e-01 -8.5564902e-01 9.3062954e-01
+1 4.7021765e-01 1 1 6.5973667e-01 1.2055156e-01 -8.7562194e-03 6.4883889e-01 6.2683171e-01 -6.4653937e-01 1.3180738e+00 -8.9917230e-01
+1 2.8517032e-01 1 1 1.5136662e+00 -2.1721217e-01 4.8907586e-01 5.6705131e-01 1.4003115e+00 3.8172143e-01 1.4959806e+00 -1.3281023e+00
+1 5.2743972e-01 1 1 -4.2916947e-01 -1.5432012e-01 1.4916375e+00 -1.1607759e+00 1.3649491e+00 4.5987858e-01 7.8013127e-01 -4.0000056e-01
+1 1.1177628e+00 1 1 4.5435426e-02 1.2972702e+00 4.1723630e-02 1.2943647e-01 7.8913725e-01 8.6135091e-01 -1.3414275e+00 1.9887659e-01
+1 5.7456790e-01 1 1 2.2619045e-01 5.6802604e-01 6.7388457e-01 1.4566167e+00 -7.7444761e-01 2.6581168e-01 -1.3026241e+00 -1.3569806e-01
+1 7.9019284e-01 1 1 2.5574014e-01 -4.8646636e-01 5.3642514e-01 -1.0744508e+00 -5.2253870e-01 1.5208582e-01 5.5605189e-01 1.1900247e-01
+1 6.7938934e-01 1 1 5.2576581e-01 1.5255593e+00 -6.7358732e-01 -4.1959610e-01 -1.5565182e+00 -1.1500165e+00 -6.7409671e-01 -1.1199496e+00
+1 5.7751391e-01 1 1 -7.5409541e-01 1.5374519e+00 1.3178684e+00 7.2393068e-01 -3.6011512e-01 -1.2494858e+00 -9.6025625e-01 1.4309194e+00
+1 5.4140341e-01 1 1 -8.9679110e-01 3.5512910e-01 1.1862098e+00 -2.8548339e-01 1.3942862e+00 1.4385891e+00 -6.6534825e-01 5.7069010e-01
+1 6.2963212e-01 1 1 9.9347572e-01 -3.7127026e-01 8.1449761e-02 -9.0731517e-01 6.2903747e-01 6.6936080e-01 1.5617882e+00 3.0619354e-01
+1 1.2299687e+00 1 1 -2.1854018e-01 -7.3622589e-01 -8.0825886e-01 4.4664244e-02 7.7353236e-01 -9.6277706e-02 9.6804199e-01 2.6606137e-01
+1 9.4067874e-01 1 1 -4.8304739e-01 9.8492065e-01 -1.6008452e-01 -1.6868901e-01 8.4794730e-01 -2.1918561e-01 -4.2659888e-01 1.2071212e+00
+1 1.3044195e+00 1 1 -7.0202732e-01 5.0975332e-01 -1.3372290e+00 -1.4395670e+00 1.1860183e+00 1.2356681e+00 -7.3290792e-01 -3.1971355e-01
+1 6.1655412e-01 1 1 8.4890688e-01 3.0083374e-01 1.4616293e-01 -1.3981803e+00 4.0777898e-03 -1.1944747e+00 2.0142198e-01 -1.3022388e+00
+1 6.3863788e-01 1 1 -1.5359397e+00 1.2900445e+00 -1.6501629e-01 -1.0376638e-01 -5.7962538e-01 -7.5990029e-01 -1.3377046e+00 7.4890609e-01
+1 6.2526404e-01 1 1 -7.1351500e-02 -1.4938764e+00 5.9745815e-01 -4.1770934e-01 3.1498155e-01 -1.0700519e+00 -1.5633567e+00 -1.4971342e+00
+1 3.7683645e-01 1 1 8.8373901e-01 2.7981876e-02 9.4892602e-01 1.0187642e+00 3.1125447e-01 1.2560535e+00 9.4559753e-01 -1.3189854e+00
+1 1.1351477e+00 1 1 -4.4847905e-01 -9.4751475e-01 -1.2662242e+00 6.9072685e-01 5.0203626e-01 -1.0119485e+00 -6.5953250e-01 -1.1106774e+00
+1 8.8741745e-01 1 1 -9.0662327e-01 -1.4723249e-01 -2.8089623e-01 8.6126749e-01 -5.9439056e-01 7.6346047e-01 -1.2239095e+00 1.8785035e-01
+1 4.6601327e-01 1 1 -8.9293850e-01 1.0384792e+00 7.9082759e-01 -1.1362771e+00 3.4250282e-01 1.2157264e+00 9.0241171e-01 -9.9826331e-02
+1 1.3441938e+00 1 1 -2.2918853e-01 -9.6954996e-01 -6.3915664e-01 3.3313937e-01 1.0471561e+00 -2.0584408e-01 -7.7568326e-01 -1.7066987e-01
+1 1.0074333e+00 1 1 -3.7902806e-01 2.1493572e-01 -1.2004137e+00 7.5536518e-01 3.5027565e-01 -7.2794820e-01 7.0092802e-01 -1.7440831e-01
+1 8.1236277e-01 1 1 8.2526422e-01 -4.0683440e-01 -4.4819061e-02 2.4662562e-01 -2.6184741e-01 -1.2635992e+00 -4.7527851e-01 -1.7452203e-01
+1 5.8446871e-01 1 1 8.4224076e-02 -1.5601190e+00 7.0828526e-01 1.2761265e+00 5.0184828e-01 -1.4609317e-01 1.0642746e+00 1.0557551e+00
+1 8.7028780e-01 1 1 -1.3042462e+00 -1.1884058e+00 6.5572137e-01 2.0566060e-01 -6.1223676e-01 1.3375583e+00 -9.6577055e-01 3.5989512e-01
+1 5.8425999e-01 1 1 1.5674126e+00 7.0971984e-01 1.9562323e-03 7.8575701e-01 -1.1473617e+00 -8.9409122e-01 9.0356660e-01 1.1913925e+00
+1 5.2122202e-01 1 1 1.2487533e+00 -3.6601100e-01 1.4624705e+00 -1.0375058e+00 -6.1253707e-01 -7.5348705e-01 -2.1497101e-01 -7.7730285e-01
+1 1.0426291e+00 1 1 -1.1845123e+00 -3.0847449e-01 -8.0024553e-02 -1.5212140e+00 8.8574597e-02 -9.6783148e-02 -1.8618583e-01 -1.3866696e+00
+1 8.5285490e-01 1 1 1.7493348e-01 -9.0282173e-01 -3.7100410e-01 -7.6216340e-01 -4.4167289e-01 7.1061882e-01 -1.9889709e-01 -1.4221960e+00
+1 1.5939153e-01 1 1 -4.2377231e-01 1.6774687e-01 5.9544078e-01 -1.4069705e+00 3.8723050e-01 -9.6475621e-01 -2.0886786e-01 1.5300024e+00
+1 1.1956055e+00 1 1 -3.5073654e-01 1.3129634e+00 -1.5410831e+00 -1.8606166e-01 -1.1970095e+00 -8.9801631e-01 -1.2831606e+00 8.1488019e-01
+1 6.9272769e-01 1 1 -1.2012340e+00 4.2858738e-01 1.4481101e+00 -1.2536457e+00 6.2056057e-01 -7.4899880e-01 9.5349152e-01 1.4890531e+00
+1 8.0980840e-01 1 1 -1.2659781e+00 -4.0383153e-01 4.6765658e-01 6.3863535e-01 -3.2619221e-01 -6.1059077e-02 6.7781217e-02 5.8754522e-01
+1 6.0346477e-01 1 1 7.1286766e-01 -1.3563816e+00 -3.6063826e-01 -1.2777530e+00 -2.3323602e-01 1.0808974e+00 -1.1992131e+00 8.4673996e-01
+1 1.1264575e+00 1 1 -8.6753878e-01 -1.3090537e+00 -1.1149833e+00 7.3341353e-01 7.0986103e-01 -1.1879907e+00 1.2833355e+00 -2.5627032e-01
+1 8.1107379e-01 1 1 -5.9283290e-01 -6.9193034e-01 7.5754084e-02 -1.1283005e+00 -1.1345393e+00 1.4034904e+00 -1.1559226e+00 -1.1682848e-02
+1 6.6601999e-01 1 1 1.3893216e+00 9.0270106e-01 8.5387046e-01 -6.9360648e-01 1.2659674e+00 1.3850401e+00 1.7653245e-02 1.5667037e+00
+1 1.6067133e-01 1 1 -1.1304668e+00 9.4578989e-01 2.0556672e-01 1.0062508e+00 -8.9252680e-01 -8.3298842e-01 1.3883847e+00 -1.2408177e+00
+1 9.0508746e-01 1 1 5.9678293e-01 -5.6814579e-01 -7.9203232e-01 8.6363200e-01 4.0692487e-01 -1.0995326e+00 -1.1678187e+00 -5.3153754e-01
+1 9.9087222e-01 1 1 -9.7462155e-01 -1.5262471e+00 -7.5916994e-01 9.0498158e-01 -6.0898849e-02 -9.9593113e-01 1.1419747e+00 1.1381542e+00
+1 1.1605411e+00 1 1 -2.0037867e-01 -5.3073440e-01 -1.3614030e+00 -1.5661481e+00 6.3224943e-01 -2.0885547e-01 1.1797135e+00 -2.0080303e-01
+1 1.0504132e+00 1 1 2.2974055e-02 -1.0714748e+00 -8.8033648e-01 1.1532746e+00 1.3497381e+00 -1.0748819e+00 8.5289745e-01 -8.2606505e-01
+1 7.3385537e-01 1 1 -2.9094736e-01 -6.6865770e-01 1.0862226e+00 -5.4009911e-01 -3.9187098e-01 -1.3819579e+00 -4.3987739e-01 -9.7741361e-01
+1 2.2132653e-01 1 1 1.5074016e+00 -6.5306035e-01 3.4817918e-01 -1.3846075e+00 -1.3973144e+00 -7.7201578e-01 -8.5183699e-01 -2.6102489e-03
+1 5.7695208e-01 1 1 1.0950623e+00 7.3939005e-01 -9.3969724e-01 -1.3214585e+00 -1.2588476e+00 -4.9151434e-01 -5.8664119e-01 1.1184408e-01
+1 1.1722645e+00 1 1 1.2628763e+00 -1.2120054e+00 -7.0516883e-01 1.3077102e+00 1.1744834e+00 1.5072309e+00 -1.3607575e+00 1.0910499e+00
+1 3.5994711e-01 1 1 5.6168370e-01 -8.7909180e-02 1.4565041e+00 1.0292230e-01 9.1615371e-01 1.3676163e+00 5.4391753e-01 -2.0125735e-01
+1 2.8333815e-01 1 1 -2.6791663e-01 -9.4103310e-01 1.7475850e-01 -1.2024764e+00 8.4979754e-01 -1.5061953e+00 -4.1273488e-01 9.6301508e-01
+1 1.3459304e+00 1 1 -9.7256636e-01 -1.1658314e+00 -2.2293939e-01 -1.5578492e-01 8.6707999e-01 3.2972014e-01 -1.9846652e-01 -9.0846116e-02
+1 6.7822628e-01 1 1 -2.1630768e-01 -1.4287008e-02 9.7768320e-01 -1.3304892e+00 -8.3494123e-01 -1.6296822e-01 7.4454418e-01 -3.6647139e-02
+1 2.4686742e-01 1 1 -6.6051887e-01 -1.3607004e+00 1.3919586e+00 3.2525473e-01 6.3711153e-01 4.6188751e-01 5.9054703e-01 -1.7630119e-01
+1 8.1654611e-01 1 1 1.0477574e+00 1.5028454e+00 -7.9168780e-01 1.8506573e-01 1.3857981e+00 6.7898846e-02 1.0327992e+00 -5.7215495e-01
+1 7.4152645e-01 1 1 1.0310845e+00 -8.2002541e-02 -1.2519808e+00 2.2291916e-01 -6.5890260e-01 7.7777502e-01 9.5615484e-01 2.0680374e-01
+1 7.0528018e-01 1 1 4.1286281e-01 9.4246860e-01 3.4674719e-01 -1.3177742e+00 -6.1878627e-02 -1.0232295e-01 8.4790161e-01 1.1490335e+00
+1 9.9175241e-01 1 1 -7.9289612e-01 1.5956438e-01 1.2557918e-01 3.9659531e-01 -1.2691079e-01 -1.2905658e+00 4.1813345e-01 4.3647951e-01
+1 7.8589652e-01 1 1 4.3099733e-01 -1.1215383e+00 -5.4106470e-01 -8.8220492e-01 1.5182817e-01 -9.8401979e-01 -1.7392956e-01 2.9223178e-01
+1 5.9385283e-01 1 1 -7.4058346e-01 -1.3830495e-01 1.2363460e+00 1.0992216e+00 8.0288442e-01 -1.0769531e+00 -1.5529457e+00 1.2301933e+00
+1 8.2834900e-01 1 1 3.8858886e-03 2.8723744e-01 7.7328074e-01 -1.0895073e+00 9.3797376e-01 1.5066037e+00 -6.3094508e-03 1.0373619e+00
+1 5.1830445e-01 1 1 -6.6331628e-01 -1.0281866e+00 -2.3942031e-01 9.9450765e-01 1.3123861e-02 2.5119485e-01 7.7120996e-01 -8.9723851e-01
+1 8.5680827e-01 1 1 1.1555610e+00 1.1693638e+00 4.4307860e-01 1.4171560e+00 6.6124222e-01 -4.6871404e-01 -4.8551777e-01 -2.4288656e-01
+1 5.0022092e-01 1 1 1.8763412e-01 -3.0702443e-01 1.2474985e+00 -1.4146745e+00 -1.4568569e+00 1.4375607e+00 -1.3810736e+00 -1.2655878e+00
+1 9.8412045e-01 1 1 -5.9235426e-01 1.4771964e+00 -2.8240109e-01 -8.6088572e-01 1.7999484e-01 -9.0582612e-01 1.5238280e+00 9.8944150e-01
+1 6.0887038e-01 1 1 9.1030553e-03 -7.6680414e-01 6.3133861e-01 1.2694334e+00 -1.8044583e-01 -6.1585928e-02 7.1398804e-01 1.0934046e+00
+1 1.1949203e+00 1 1 -9.4298964e-01 -8.6410297e-01 -1.3918973e+00 8.1124675e-01 -1.1161552e+00 -1.4907009e+00 -8.8698762e-01 -1.4663998e+00
+1 6.6761958e-01 1 1 5.0799229e-01 6.0424631e-01 -1.3197722e+00 1.1199921e-01 -7.7152273e-01 -8.0352348e-03 -7.4371145e-01 1.3135971e-02
+1 4.1543189e-01 1 1 -1.0224892e+00 -1.2012854e+00 1.3735913e+00 5.5676446e-01 1.5118968e+00 4.0292521e-02 8.3889074e-01 8.6477559e-01
+1 5.0710849e-01 1 1 -4.6488361e-01 1.0125032e+00 1.5262201e+00 -1.2641585e+00 1.2485594e+00 -1.3876056e+00 -2.3123834e-01 1.2757326e+00
+1 8.3476123e-01 1 1 -1.5792020e-01 -8.6582970e-01 7.7296072e-02 -1.2026410e-01 -1.3010763e+00 -1.4442792e+00 -2.7269168e-01 -1.3147167e-01
+1 7.1203666e-01 1 1 4.8097814e-01 -1.4255450e-01 -1.5042822e+00 -1.2345757e+00 1.4364149e+00 1.0854871e+00 4.5458632e-01 -1.1047273e+00
+1 1.5981160e-01 1 1 4.8174648e-01 1.1217509e+00 1.0665344e+00 7.0526164e-01 -1.3149333e+00 5.5303227e-01 -1.2108917e-01 -3.3958088e-01
+1 1.0360063e+00 1 1 8.2880370e-01 5.6904508e-01 -6.8441910e-01 1.0328733e-01 1.0203120e+00 -1.1593092e+00 6.0631807e-01 9.3795739e-01
+1 6.4134995e-01 1 1 -1.1796206e-01 9.3268978e-01 1.4804833e+00 -1.3505246e+00 1.5705981e+00 -3.5140067e-01 -9.3868987e-01 -2.6205680e-01
+1 5.6168099e-01 1 1 -2.4343913e-01 -8.3015231e-01 1.0696464e+00 -2.6075677e-01 1.3804459e+00 2.0308416e-01 5.1770718e-01 1.2426581e-01
+1 5.2661844e-01 1 1 -1.1278375e+00 -5.5685553e-01 1.3545609e+00 -1.7238347e-02 4.9209838e-01 1.4658005e+00 -1.1070639e+00 -6.2359969e-01
+1 7.0760228e-01 1 1 8.0495439e-01 -2.6644790e-01 -1.0165199e+00 -6.9837606e-01 -1.1160108e+00 -6.6112087e-01 1.2305666e+00 -4.8689141e-01
+1 8.7304188e-01 1 1 1.1704253e+00 -1.4203336e+00 -6.6985287e-01 -6.1630658e-01 -1.4848034e+00 3.5472859e-01 1.0278630e+00 6.6489041e-01
+1 6.9099652e-01 1 1 -1.3152255e+00 1.4151630e+00 1.2508589e+00 -4.3377262e-01 -1.4205588e+00 -8.1946320e-01 -3.2539761e-01 1.6808578e-01
+1 9.6046348e-01 1 1 -7.4905717e-01 -3.5344253e-01 -3.5245113e-01 1.2201957e+00 7.7240689e-01 2.4200082e-02 5.5511342e-01 7.2593414e-01
+1 1.9630649e-01 1 1 -1.0421155e+00 4.4315067e-01 1.3976813e+00 -4.8783664e-01 7.8173410e-01 1.4653206e+00 -7.3886340e-01 -1.1707443e+00
+1 3.3287683e-01 1 1 -4.5623584e-01 -6.8292554e-01 1.1409926e+00 4.8648138e-01 4.6462142e-01 6.9866563e-01 6.3851960e-01 -9.0460691e-01
+1 3.8816368e-01 1 1 6.7195499e-01 1.4500111e+00 3.8057436e-01 -1.2731219e+00 -1.1072133e+00 -8.0005107e-01 -8.1602995e-02 -1.5614873e+00
+1 4.7022107e-01 1 1 -4.7805307e-01 1.0025848e+00 3.0585252e-02 2.8540473e-02 -1.2811208e+00 -4.4171748e-01 1.3744585e+00 9.4867863e-01
+1 1.1436294e+00 1 1 1.5561313e+00 -1.0604639e+00 -1.1748575e+00 -9.8394093e-01 6.7848650e-01 -3.6228766e-01 3.9375915e-01 8.5893514e-01
+1 1.1052736e+00 1 1 1.3935437e-01 -9.6126964e-01 -9.2022690e-01 2.4844799e-01 -6.5866879e-01 -5.6219968e-01 -1.4257179e+00 5.0460795e-01
+1 8.0296923e-01 1 1 -1.4992423e+00 1.1521672e+00 -1.9283292e-01 4.8875168e-01 7.2608987e-01 1.0206682e+00 -1.1139881e+00 -1.3544164e+00
+1 3.9646365e-01 1 1 9.4850184e-01 -3.0283171e-01 1.1807699e+00 -8.1538137e-01 1.4465208e+00 1.2740674e+00 1.0940395e+00 3.0407523e-01
+1 6.1050498e-01 1 1 1.0292799e+00 -3.1240928e-01 -2.4116235e-01 -4.8752757e-01 -1.1104684e+00 1.5485977e-01 -2.2037886e-01 -7.7887631e-01
+1 1.0908929e+00 1 1 1.4973256e+00 -1.0614700e+00 -5.6112627e-01 -6.0227556e-01 5.6014655e-01 1.4894912e+00 3.0228653e-02 4.4251264e-01
+1 7.2730303e-01 1 1 1.3939725e+00 9.7873957e-01 2.1184522e-01 -2.3384510e-01 -9.7007112e-01 -1.4740847e+00 -8.8503912e-01 1.1601032e+00
+1 6.8618572e-01 1 1 -1.5029446e+00 2.9681700e-01 1.0581945e+00 -1.0217010e-01 8.8057459e-01 -3.4261916e-01 5.8868009e-01 1.1305299e+00
+1 2.6131916e-01 1 1 1.5559394e+00 -2.4585931e-01 5.1904372e-01 1.2783853e+00 -2.2591837e-01 1.3906062e-01 1.0709263e+00 4.6351825e-01
+1 7.3648214e-01 1 1 5.6499437e-02 -9.6312267e-01 -6.3501746e-01 4.6965344e-01 1.1755295e+00 -1.5303216e-01 8.7444096e-01 -7.9856910e-01
+1 8.8095717e-01 1 1 8.2506353e-01 1.4241930e+00 -7.4812389e-01 -1.3569353e+00 -3.5132006e-01 9.5279822e-01 3.5880534e-01 -6.6697001e-01
+1 1.2203113e+00 1 1 -1.4718711e-01 6.1755526e-01 -1.0643877e+00 -1.1897192e+00 1.5578670e+00 9.8195229e-01 -1.4165824e+00 -5.6241986e-01
+1 1.3424423e+00 1 1 -1.3402690e+00 -5.7081828e-01 -9.3588222e-01 6.2588172e-01 1.0374898e+00 8.8600484e-01 -1.5116445e+00 4.6168087e-01
+1 6.0816582e-01 1 1 -6.8236149e-01 6.8116138e-01 5.8194064e-01 1.1418709e+00 1.2516638e+00 -6.5828070e-02 -1.4980789e-01 -2.6348415e-01
+1 2.3973652e-01 1 1 1.5052708e+00 3.1561723e-01 8.9847309e-01 -5.6477752e-01 6.0894348e-01 -5.3175131e-01 -1.4054656e+00 1.2675084e+00
+1 8.0560810e-01 1 1 -1.5867039e-01 1.5703312e+00 -9.9867638e-01 -1.4643619e+00 -7.9574842e-01 6.8676072e-01 -2.4359828e-02 -1.2546194e-01
+1 6.5753671e-01 1 1 4.3890134e-01 3.7100260e-02 7.7555788e-01 -2.9289817e-01 -3.8381155e-01 1.7600921e-01 -1.0085834e+00 -6.3015378e-01
+1 5.9127035e-01 1 1 1.5530054e-01 1.5087259e+00 3.3343775e-01 1.3616216e-01 -1.0309951e+00 -1.1934523e+00 7.7206510e-01 -6.8573093e-01
+1 6.3638754e-01 1 1 -5.2724246e-01 1.3620264e+00 -5.1305090e-01 1.3980234e+00 1.0906238e+00 7.1565904e-01 1.3204002e+00 1.4236666e+00
+1 6.4520210e-01 1 1 1.0687718e+00 -1.2080732e+00 8.2528847e-01 6.0830119e-01 -1.0788423e+00 -1.0768386e+00 -2.4458117e-01 1.1953192e+00
+1 8.2609617e-01 1 1 -7.7881022e-01 2.7686773e-02 4.9168422e-01 9.7568221e-01 1.1707340e+00 2.8834976e-01 -1.4724769e+00 -7.5449923e-01
+1 4.9029809e-01 1 1 1.5532423e+00 3.7587845e-01 1.3479652e+00 -8.2279604e-01 7.3089789e-01 -1.1830129e+00 1.5478132e+00 -1.4005758e+00
+1 7.8361273e-01 1 1 -1.2916605e+00 -3.5363455e-01 1.2262338e+00 5.5774463e-01 5.7354046e-01 2.4231856e-01 -1.4320810e+00 4.7546514e-01
+1 9.0718276e-01 1 1 -5.3316283e-01 3.5736985e-01 4.6331185e-01 -4.9845804e-01 1.0883259e+00 1.1440408e+00 -1.2441841e+00 -1.0690241e+00
+1 1.2048732e+00 1 1 -1.0453584e+00 -4.1006957e-01 -1.1258952e+00 1.0432506e+00 1.1416875e+00 1.3471563e+00 -5.6209859e-01 -3.1910533e-01
+1 6.4780456e-01 1 1 -1.5527081e+00 6.1496962e-01 -1.1079804e+00 6.8403653e-01 -5.0628027e-01 1.9712585e-01 -4.2184618e-01 -5.0456661e-01
+1 5.9321578e-01 1 1 8.4489749e-01 -4.5502470e-02 1.5346334e+00 1.5145038e+00 1.5220159e+00 -1.2861726e+00 6.0588783e-01 -1.0924631e+00
+1 8.1586334e-01 1 1 1.9325095e-01 -1.3530002e+00 1.0821226e-01 1.0809637e+00 -1.4671354e+00 5.9664917e-01 1.2549983e+00 -1.5600715e+00
+1 1.2085504e+00 1 1 -4.3811988e-01 -1.0263502e+00 -2.5863835e-01 -7.3425411e-02 2.1582538e-01 -8.1140813e-02 1.0315795e-01 -3.8860669e-01
+1 6.3688665e-01 1 1 4.1237820e-01 6.1679727e-01 1.0294942e+00 5.8502480e-01 -1.1622742e+00 -2.8244047e-01 -3.8340505e-01 5.8500695e-02
+1 1.0935504e+00 1 1 4.8705554e-01 -7.4411731e-01 -1.1833092e+00 -6.7314160e-01 7.9852561e-02 -3.0525950e-02 -4.8206813e-01 -9.7324146e-02
+1 7.0179846e-01 1 1 -1.0479887e+00 3.0075758e-01 1.5455748e+00 -6.1580942e-01 6.2192128e-01 -9.7004122e-01 4.8453591e-02 1.0428544e+00
+1 9.0773938e-01 1 1 1.3635266e+00 1.0105331e-02 -1.3539912e+00 -1.5027901e+00 5.5225711e-01 1.3830399e+00 6.8701233e-01 3.0815474e-01
+1 2.7140111e-01 1 1 -1.1270913e+00 1.9429810e-01 1.1663177e+00 1.0111553e+00 1.5206004e+00 1.0783970e-01 1.2632785e+00 -1.3296239e+00
+1 8.6553581e-01 1 1 7.7993254e-01 1.4534560e+00 -1.2366025e+00 -1.5299027e+00 -1.2458843e-01 -2.3704243e-01 1.0381274e+00 -8.4116124e-01
+1 7.9507205e-01 1 1 -1.5398671e+00 -7.9017606e-01 1.1987245e+00 8.6184829e-01 1.4846294e+00 -4.3269992e-01 -5.9820021e-01 -2.2996895e-01
+1 5.8606676e-01 1 1 -1.0659627e-01 -9.7685789e-01 -7.1121725e-02 -7.9959151e-01 -1.5042684e+00 3.9944792e-01 -8.5444516e-01 -9.2915150e-01
+1 1.2852731e+00 1 1 -8.5574298e-01 -8.7350408e-02 -1.5376231e+00 9.9879285e-01 1.2989578e+00 -6.2281893e-02 -4.3977255e-01 6.0778002e-01
+1 4.4544464e-01 1 1 -2.6104328e-01 -9.7453340e-01 -8.9607085e-02 1.1819326e+00 6.5613404e-01 -6.2142613e-01 9.1020929e-01 -1.5004437e+00
+1 5.8316327e-01 1 1 1.4506050e+00 1.2812990e+00 -1.2033910e+00 4.5028039e-01 6.5459227e-01 1.4865597e+00 1.4729470e+00 -3.9295440e-01
+1 9.0976303e-01 1 1 1.5598181e+00 -8.2466194e-01 1.8029455e-01 -2.3426728e-01 -1.2511044e-01 -4.7734902e-01 6.9971296e-02 -7.5686509e-01
+1 1.0457684e+00 1 1 -7.2794600e-01 6.1359921e-01 -1.4264137e+00 -9.1450042e-01 -1.0057325e+00 8.2262741e-01 1.0519265e+00 -3.2283754e-01
+1 8.9839244e-01 1 1 -1.2266692e+00 -1.0867687e+00 -2.4218089e-01 -1.3372774e+00 1.5633194e+00 -2.5044885e-01 -1.1539335e+00 -3.9998776e-01
+1 6.7762025e-01 1 1 -1.4977389e+00 -1.0106472e-01 1.1698666e+00 -6.6730670e-01 1.5693395e+00 4.4024998e-01 -1.1092513e+00 4.1396598e-01
+1 4.1251925e-01 1 1 1.0836986e+00 1.0067941e+00 -1.2804221e+00 6.2055771e-02 -9.2259368e-01 8.3065906e-01 -9.7572595e-01 -1.1015158e+00
+1 1.1067183e+00 1 1 -1.2318182e+00 5.7004762e-01 -1.4412160e-01 -3.7410049e-02 8.6939083e-01 -3.5089412e-01 8.7686020e-02 2.3008467e-01
+1 1.1686622e+00 1 1 -7.3675948e-02 -1.0672386e+00 -8.3827869e-02 -4.3216425e-01 3.0423528e-01 -7.0803395e-01 3.3198612e-01 -2.6746562e-01
+1 3.4716132e-01 1 1 -4.8414823e-01 1.4150708e+00 -1.4614892e+00 -2.2309867e-02 -1.2304747e+00 4.2635998e-01 2.2223983e-01 3.2442811e-01
+1 8.9832405e-01 1 1 -3.5433851e-01 1.2391771e+00 8.6347698e-01 -1.1124119e+00 5.1555338e-01 -1.4062425e-01 -1.6877020e-01 -1.1415973e+00
+1 6.8807487e-01 1 1 1.0923735e+00 1.2313284e+00 1.4411602e+00 -6.8926296e-01 3.9317782e-01 -9.9417639e-01 3.3740787e-01 -1.1191387e+00
+1 9.0528959e-01 1 1 5.4519505e-02 1.2658265e+00 -9.9836079e-02 -1.3904924e+00 1.3703378e+00 1.0087177e+00 2.3928143e-01 -6.4957728e-01
+1 4.8907374e-01 1 1 -1.0357329e+00 -1.1972036e-01 -3.3449481e-01 3.0256475e-01 2.5107218e-01 1.4842098e+00 3.6437130e-01 -4.1093017e-01
+1 6.9617017e-01 1 1 2.1509921e-03 -1.5207102e+00 -1.5450299e+00 -1.0327312e+00 6.1118734e-01 8.6824294e-01 1.0243700e+00 -1.2827572e+00
+1 5.5841646e-01 1 1 -1.5473878e+00 1.4220871e+00 1.0875758e+00 1.8604652e-01 -7.8232439e-01 -1.3870398e-01 6.5922903e-01 1.4503427e+00
+1 7.6898642e-01 1 1 -8.4257301e-01 -2.1915287e-01 1.1002745e+00 9.9919210e-01 -9.6073079e-01 -1.3599942e-01 -7.3492914e-01 2.9156198e-01
+1 6.9788498e-01 1 1 1.1751280e+00 -1.3557599e+00 8.9992586e-01 -1.5326368e+00 7.8393589e-01 1.3371376e+00 7.8824267e-01 -6.0225848e-01
+1 4.7800018e-01 1 1 -8.1603565e-01 -2.8483447e-01 1.4268282e+00 -1.1082219e+00 -2.2901051e-01 1.4593896e+00 -1.0159638e-01 5.3334146e-02
+1 4.2453349e-01 1 1 1.0824104e+00 5.7430092e-01 9.2456752e-01 6.1679500e-01 -5.2857195e-01 1.5465673e+00 1.4960931e+00 1.0330931e+00
+1 8.9823042e-01 1 1 -8.9100972e-01 1.3029562e+00 8.8907340e-01 -7.8222757e-01 7.1523600e-01 -3.8161028e-01 -4.7116792e-01 -3.8614597e-01
+1 4.0411978e-01 1 1 7.7176668e-01 -1.2581495e+00 1.2420251e+00 6.6652812e-01 1.2380156e+00 1.4082372e+00 1.0357850e+00 5.7502518e-01
+1 1.1713728e+00 1 1 -5.5346483e-01 3.4130279e-01 -1.1678894e+00 -5.8129761e-01 5.5935879e-01 -5.1701561e-01 8.7379488e-01 9.0919912e-01
+1 1.0360416e+00 1 1 1.7245843e-01 -2.7222079e-01 -4.6991607e-02 4.8425303e-01 1.4979454e+00 1.6387984e-01 -1.0750869e+00 2.0293719e-01
+1 1.0250167e+00 1 1 -1.1811045e+00 -1.0559447e+00 -1.2481761e+00 -1.0259455e+00 -7.5450387e-01 -8.4834628e-01 1.4558387e+00 -1.0042361e+00
+1 5.4436687e-01 1 1 9.0124034e-01 -4.0572163e-01 1.4605902e+00 1.1364408e+00 -1.4785912e+00 1.5330751e+00 1.5568006e+00 -1.5602348e+00
+1 7.4079821e-01 1 1 1.5282708e+00 1.4342202e+00 -2.6529727e-01 -7.2287625e-01 -6.8504477e-01 -9.4957241e-01 -1.1769906e+00 7.0557146e-03
+1 1.0383610e+00 1 1 -1.4509235e-02 -5.0180728e-01 -9.3131784e-01 -8.4231014e-01 3.8965722e-01 -1.7285596e-01 9.2812130e-01 -7.9512537e-01
+1 6.3831186e-01 1 1 1.1875074e+00 1.3013686e+00 -1.2444067e+00 -6.8999636e-01 -1.2517455e+00 7.8306954e-01 9.2712942e-01 6.6297878e-01
+1 1.0474024e+00 1 1 -1.0182816e-01 3.3408529e-01 -1.1612861e+00 -1.1502582e+00 1.1590817e+00 9.1817822e-01 -3.5367464e-02 -5.4485422e-01
+1 6.4949058e-01 1 1 7.4210419e-01 9.4545316e-01 9.8024202e-01 9.7163757e-01 -3.3062130e-01 3.1827360e-01 -6.5996171e-01 3.7776794e-01
+1 7.1858947e-01 1 1 4.2225197e-01 5.5616811e-02 4.1571240e-01 3.1396445e-01 7.2522594e-01 -9.0785677e-01 9.8713730e-01 -1.2945734e-02
+1 1.0205836e+00 1 1 -6.8934867e-02 -1.4428737e+00 -2.3696616e-02 -1.0751023e+00 -5.0719120e-01 3.6676985e-01 6.5878826e-02 -8.0906500e-01
+1 5.5120546e-01 1 1 6.5937547e-01 -4.2469586e-01 7.1325022e-01 1.1971315e+00 -1.2216849e+00 4.9610789e-01 1.3848064e+00 -1.1424275e+00
+1 7.9384142e-01 1 1 -1.4154104e+00 -1.6486067e-01 -7.2108075e-01 1.4292305e+00 5.9207065e-01 2.9843200e-01 1.5235370e+00 6.3567505e-01
+1 7.6012863e-01 1 1 -6.6323670e-01 7.1483241e-02 1.0603134e+00 4.5915044e-01 1.5075215e+00 -1.3767879e+00 -1.0347524e+00 -7.6607478e-01
+1 9.2326194e-01 1 1 -6.4843533e-01 1.3304425e+00 -1.5682681e+00 1.1898534e+00 -3.1604021e-02 1.2978002e+00 7.7350649e-01 -1.1721980e+00
+1 9.4309060e-01 1 1 -6.7618509e-02 -1.1098343e+00 8.0454987e-02 -1.5134861e+00 -2.3962706e-01 5.0377918e-02 4.1312153e-01 -2.0398421e-01
+1 5.8502247e-01 1 1 7.9226518e-01 -1.3500300e+00 1.3221295e+00 3.1473619e-01 1.0977780e-01 -1.5283458e+00 4.1386725e-01 -8.8510231e-01
+1 7.9821997e-01 1 1 1.5311321e+00 -1.3722119e+00 5.4623085e-01 -6.7080589e-01 9.2058282e-01 -1.2464240e+00 3.8068243e-01 -4.7324385e-01
+1 6.9610955e-01 1 1 9.5217517e-01 -3.3379142e-01 7.6809246e-01 9.4142434e-01 -1.0829560e-01 -5.0869444e-01 -1.2945987e+00 7.0314038e-01
+1 5.2421871e-01 1 1 -6.4862618e-02 8.5204381e-01 5.2580235e-01 1.4582886e+00 -1.1420735e+00 -1.3538082e+00 3.5081570e-01 -9.9124286e-01
+1 1.0571889e+00 1 1 -1.3374181e-02 9.2104842e-01 -1.4010225e-01 -1.2498937e+00 3.0174712e-01 1.1008623e+00 -6.0989258e-01 4.7166340e-02
+1 4.0101153e-01 1 1 1.4148163e+00 1.4338339e+00 1.4959888e+00 8.6738604e-01 9.3323801e-01 1.3527371e+00 5.5218314e-01 1.0433354e+00
+1 3.9875179e-01 1 1 1.0305292e-01 -7.1098742e-01 9.1841005e-01 1.1672939e+00 -1.0409268e+00 -2.5437162e-01 2.7734543e-01 -1.0317898e+00
+1 8.3248063e-01 1 1 9.9282204e-01 1.0528361e+00 1.0729509e+00 -5.3770568e-01 6.7305690e-01 4.8385656e-01 -7.7884853e-01 2.9952059e-01
+1 8.1521701e-01 1 1 1.3614540e+00 1.5663848e+00 3.4461354e-01 1.1427659e+00 -8.0781776e-01 -1.4061792e+00 9.0935102e-01 1.2110993e+00
+1 1.4275434e+00 1 1 -1.4033819e+00 -3.1726261e-01 -1.1770330e+00 -1.2302034e+00 9.7038041e-01 5.4738442e-01 -3.8561230e-01 5.6698818e-01
+1 9.4017212e-01 1 1 4.3734336e-01 -9.5003098e-01 2.1479559e-01 -1.2071862e+00 1.1761459e+00 1.3066762e+00 1.1973036e-01 9.1980252e-01
+1 2.3659981e-01 1 1 -8.9702576e-01 1.5448228e+00 3.7951963e-01 -7.7252648e-01 5.8337692e-01 -1.5677124e+00 -1.4526810e+00 -6.5650124e-01
+1 2.4862364e-01 1 1 1.9122203e-01 -1.4271463e+00 1.1533876e+00 3.4982512e-01 -9.4713463e-02 -4.4326952e-03 1.2482940e+00 -5.4290862e-01
+1 3.5373448e-01 1 1 1.9298047e-02 1.1232050e-02 1.3581114e+00 -1.5507281e+00 9.3830042e-01 8.9791582e-01 5.2077447e-01 -1.4801651e+00
+1 7.4623301e-01 1 1 7.5822500e-01 2.8150882e-01 -1.0331952e+00 -4.3434974e-01 -7.7989747e-01 -9.3997414e-01 1.7939833e-01 1.1367613e+00
+1 6.7438727e-01 1 1 1.1877639e+00 8.0262142e-02 -1.3287174e+00 9.4517500e-01 -1.0121967e+00 9.2411452e-01 -7.8119860e-01 1.5226253e+00
+1 7.8008234e-01 1 1 1.0675134e+00 1.2225798e+00 -1.3119543e+00 -1.4777884e+00 -2.6553697e-01 -4.4126140e-01 -8.8910839e-01 -6.5092445e-01
+1 5.8315783e-01 1 1 6.1857385e-02 -1.2580129e+00 8.2244105e-01 2.4259153e-01 1.3232442e+00 1.0198771e+00 1.3115386e+00 -1.0616523e+00
+1 8.1275524e-01 1 1 -2.3009629e-01 -5.0356893e-01 -2.4095402e-01 -5.5148062e-01 4.3135884e-01 5.4480113e-01 -1.5267841e+00 1.0568820e+00
+1 5.6133928e-01 1 1 7.2218154e-02 -3.2428550e-02 -2.0132040e-01 -1.0364446e+00 -9.4778863e-01 -1.2700152e+00 -1.3171983e-01 4.5165448e-01
+1 1.1400137e+00 1 1 1.1157545e+00 -1.5311057e+00 -9.6671415e-02 6.0632584e-01 1.5327990e+00 -1.1645041e+00 1.0076712e+00 8.6903258e-01
+1 1.1121948e+00 1 1 3.1892867e-01 -5.0790790e-01 -5.5307236e-01 -8.0813149e-01 6.9264385e-01 3.0158112e-01 -3.9637554e-01 5.6624547e-01
+1 6.5487106e-01 1 1 6.7712418e-01 -7.0076249e-01 4.8554436e-01 -1.1609870e+00 -1.4772483e+00 1.2849384e+00 1.4342832e+00 1.0033912e+00
+1 1.0768147e+00 1 1 -1.5640903e+00 1.1568562e-01 -1.3136701e+00 -2.7686392e-01 -1.0471603e-01 6.5150316e-01 5.5733830e-01 -7.3031357e-02
+1 6.0018004e-01 1 1 1.1809388e+00 -3.1766621e-01 2.5984802e-01 -5.5322813e-01 -6.7037191e-01 1.3632518e+00 -1.0444591e+00 9.2471415e-01
+1 2.0315809e-01 1 1 -5.4344233e-01 -1.4501276e+00 4.5193733e-01 1.0091097e+00 -1.1893696e+00 5.3735183e-01 9.9527806e-01 2.1181306e-01
+1 4.2800666e-01 1 1 -1.0253375e+00 1.8068145e-01 -6.6025438e-01 -1.3518206e+00 2.1929842e-01 -8.0669892e-01 -1.3424655e+00 5.1766809e-01
+1 1.3042058e+00 1 1 -1.2112907e+00 -1.2069807e+00 -7.9009976e-01 -5.1490107e-02 6.6040332e-01 9.2509037e-01 1.0049762e-01 1.3775325e+00
+1 8.0872043e-01 1 1 -6.4271280e-01 -4.6093623e-01 3.0544170e-01 -1.4562569e+00 1.5168730e-01 2.5175907e-01 -1.1134166e+00 -1.3494255e+00
+1 1.1150369e-01 1 1 -1.2785469e+00 2.1220311e-01 1.9622555e-01 8.3931447e-01 -1.5647954e+00 -4.1062678e-01 1.2746942e+00 -6.3659799e-01
+1 4.9782285e-01 1 1 -4.4781369e-02 7.9001292e-01 -7.0948213e-01 6.0727742e-01 -1.2435005e+00 6.7480288e-01 1.2658474e+00 9.6210520e-01
+1 7.4926284e-01 1 1 1.3417761e+00 1.3765526e+00 1.2195046e+00 -5.2296456e-01 1.5031454e+00 2.6245310e-01 2.3256597e-01 3.2467481e-01
+1 2.3699584e-01 1 1 8.7912476e-01 1.0313350e+00 4.6255148e-01 7.1085794e-01 -1.3234710e+00 2.5314039e-01 5.9492791e-01 -1.3699040e-01
+1 3.9999835e-01 1 1 5.3956553e-01 1.4812245e+00 -1.3390748e+00 -8.7437603e-02 -1.1007921e+00 8.1415874e-01 -7.3600984e-01 3.8973729e-01
+1 4.9190113e-01 1 1 -1.3000922e+00 9.5940514e-01 5.4016616e-01 7.0155996e-01 -1.7426948e-01 -1.2115750e+00 1.4744489e+00 9.4013799e-02
+1 5.9734099e-01 1 1 -8.7210826e-01 -1.0729056e+00 -6.3017542e-01 7.2107615e-01 -9.8283249e-01 8.6235570e-01 1.8040868e-01 -1.3118229e-01
+1 8.5632504e-01 1 1 1.1477541e+00 4.1815715e-01 -1.0495241e+00 -1.1376403e+00 2.8514607e-02 1.4452666e+00 4.9183544e-01 6.1721298e-01
+1 4.1200280e-01 1 1 9.2385271e-01 2.2450706e-01 6.9131939e-01 -5.8794426e-01 -1.4186684e+00 -1.9896485e-01 7.4790885e-01 -4.0315169e-02
+1 5.7789745e-01 1 1 1.4416396e+00 2.3731244e-01 1.3952904e+00 -1.2702965e+00 1.1292495e+00 -1.3477008e+00 5.9189842e-01 1.0069701e+00
+1 1.2284387e+00 1 1 -1.4676134e+00 -1.3124386e+00 -1.3430827e+00 3.9109121e-01 9.3579487e-01 7.6296979e-02 -1.3872601e+00 3.8713881e-01
+1 8.5966451e-01 1 1 -1.5352221e+00 -1.0339874e+00 -8.4779613e-01 8.5818151e-01 1.0916202e+00 5.5352458e-01 1.2203614e+00 4.0365013e-01
+1 6.4853316e-01 1 1 -5.7732482e-01 1.0635458e+00 1.3547312e+00 4.0484942e-01 -3.9928169e-02 8.3178378e-01 -8.4472492e-01 1.4491289e+00
+1 1.2293144e+00 1 1 1.2815063e+00 -6.4715219e-01 -1.2956633e+00 -3.8542969e-01 1.2280997e+00 -2.9726960e-01 -4.3460368e-01 -1.2584680e+00
+1 6.9723909e-01 1 1 -4.8300146e-01 -4.9305640e-01 1.3071376e+00 4.7316721e-02 4.0748186e-01 -1.0778615e+00 -1.8116342e-01 1.2713735e+00
+1 8.7304503e-01 1 1 6.9816081e-02 7.2258611e-01 -9.4968144e-02 4.2919059e-01 -1.2434644e-01 -1.1952988e+00 -6.1032945e-01 -1.1383477e+00
+1 7.4732362e-01 1 1 -1.5567822e+00 -8.9246472e-01 -2.0052833e-01 3.0945714e-01 -7.3145361e-01 1.0984996e+00 -5.0712625e-01 9.0287429e-02
+1 4.0956186e-01 1 1 1.4871343e+00 1.4503100e+00 6.4928958e-01 -1.4311984e+00 -4.8882489e-01 -6.5655815e-01 -1.3003492e-01 7.1573500e-02
+1 6.2161630e-01 1 1 -2.4432338e-01 -2.5700447e-01 -1.2828331e+00 1.0235810e+00 -4.1518661e-01 -1.4994270e+00 1.0515467e+00 -2.9416515e-01
+1 8.6126301e-01 1 1 -2.8142479e-01 2.1583970e-01 1.7391942e-01 -3.5664219e-02 -5.6414814e-01 9.8732928e-01 -1.2548805e+00 8.3309262e-01
+1 4.2946711e-01 1 1 1.3321041e+00 -9.2163869e-01 1.3825314e+00 6.3567247e-01 -3.1120703e-01 1.5077450e-01 -1.2655988e+00 -2.9078302e-01
+1 7.0752936e-01 1 1 -1.4576831e+00 1.2118707e+00 9.8519950e-01 -8.0942213e-01 2.9525495e-01 -1.1982523e+00 8.0518454e-01 1.1279913e+00
+1 9.2653784e-01 1 1 -1.1405213e+00 9.6526068e-01 -1.0869027e+00 -8.6155886e-01 -1.3664153e+00 -1.4169611e+00 -1.2445195e+00 -1.3610487e+00
+1 3.2386087e-01 1 1 1.2560686e+00 -4.8286174e-02 7.8690847e-01 -6.1924945e-01 -2.9920282e-01 1.5483021e+00 8.4653107e-02 -1.2092240e+00
+1 1.3404791e+00 1 1 -7.5793752e-01 -1.0148139e+00 -5.3442612e-01 3.7096116e-01 9.8805523e-01 5.0174820e-01 -3.7669997e-01 -4.6523839e-01
+1 8.4474212e-01 1 1 5.0236053e-01 -2.7049469e-01 -2.8641887e-01 -1.3171999e+00 -2.1453508e-01 8.4724280e-01 -8.8721890e-01 1.6243556e-01
+1 7.7001571e-01 1 1 -1.4276612e+00 -3.1971642e-01 -9.2207137e-01 6.2445763e-01 8.5728937e-01 -1.2297909e+00 -1.4893161e+00 1.0470871e-02
+1 9.5747310e-01 1 1 7.8222734e-01 -1.3503806e+00 2.2300379e-01 -8.0167408e-01 1.1184909e+00 -5.5759894e-01 1.2748500e+00 5.4732494e-02
+1 5.0142254e-01 1 1 -6.7036373e-01 -9.8207749e-01 1.0474652e-01 5.5454663e-01 -8.1350001e-01 -1.9456273e-01 7.4193787e-01 -5.9761658e-01
+1 4.7026520e-01 1 1 -1.0520005e+00 1.5150809e-01 1.1828443e+00 -8.4024884e-01 -2.8347018e-01 3.8211455e-01 7.6856774e-01 -4.7018325e-01
+1 1.0171352e+00 1 1 -8.9764062e-02 -1.4350934e+00 6.5050973e-02 -6.0319978e-01 1.5127186e+00 7.8378290e-01 -9.1106523e-01 -1.2644276e+00
+1 6.5946995e-01 1 1 -7.0011018e-01 1.5337555e+00 3.7465551e-02 -5.9131843e-02 -6.4819666e-01 3.4119689e-01 -1.5074612e-01 -1.5022855e+00
+1 7.6958757e-01 1 1 -1.4873223e+00 1.0609403e+00 1.3649805e+00 -1.0856059e+00 8.0200429e-01 1.0894752e+00 -1.4662983e+00 6.8122877e-02
+1 5.1167418e-01 1 1 2.2765736e-01 -4.5595271e-01 1.3170996e+00 5.9241876e-01 -1.2879930e+00 -1.5335342e+00 -1.4225185e+00 1.4014760e+00
+1 7.1883711e-01 1 1 -2.2256451e-01 -8.5275873e-01 8.3066999e-01 1.0749002e+00 1.4163809e+00 -4.8388138e-01 -7.4888859e-01 -1.0546143e+00
+1 8.8820113e-01 1 1 9.9505810e-01 -3.7032628e-01 -1.6727643e-01 -1.4508925e+00 1.2657760e+00 9.8905628e-01 -1.3504194e+00 -3.6941709e-02
+1 4.6986743e-01 1 1 1.2437542e+00 -5.7881438e-01 3.1047621e-01 -1.0761222e-01 -9.6761216e-01 9.0222230e-01 1.5087640e+00 1.1560418e+00
+1 9.9317367e-01 1 1 -3.8130644e-01 1.3791263e+00 -1.1747201e-02 9.1886771e-01 1.3675944e+00 -8.1750205e-01 -1.1385517e+00 -1.1563182e+00
+1 5.8802286e-01 1 1 2.3165452e-01 3.0568220e-01 4.8513452e-01 -6.5992271e-01 1.2664655e+00 1.5693206e+00 -1.9750235e-01 -3.4758227e-01
+1 4.9442289e-01 1 1 9.8414046e-01 1.0966808e+00 1.2229366e+00 -1.4989343e+00 1.1951941e+00 -1.2402120e+00 1.2414566e+00 1.5471869e+00
+1 9.7318576e-01 1 1 -3.6608272e-02 1.8970321e-01 -1.5447578e+00 -1.5726949e-01 2.8357921e-01 2.2490179e-01 -1.2967388e+00 6.0803924e-01
+1 1.0085440e+00 1 1 4.7693325e-01 -3.7470426e-01 -6.2318976e-01 -1.1489036e+00 3.1979481e-01 5.8838569e-01 -1.0616032e+00 -2.8532066e-01
+1 4.4983309e-01 1 1 -1.5273393e+00 1.2388003e+00 1.1961892e-01 -1.3944772e+00 -4.7370346e-01 -7.3537289e-01 -1.2607176e+00 -1.3139681e+00
+1 6.9524526e-01 1 1 -3.7611922e-02 1.1828752e+00 -1.8407238e-01 -6.9760720e-01 -7.3832886e-01 -3.8662686e-01 1.1613215e+00 1.5348043e+00
+1 8.0435469e-01 1 1 -6.8344194e-01 5.8539124e-01 7.6421417e-01 -2.6049629e-01 1.9780503e-01 -1.2240166e+00 -3.8395169e-01 -1.6112078e-01
+1 5.5645010e-01 1 1 -9.4593572e-01 -7.9753687e-01 1.3167634e+00 1.2189806e+00 7.0410484e-01 -8.9899878e-01 -2.4469023e-01 9.5962941e-02
+1 5.6899176e-01 1 1 1.2587816e+00 9.7364362e-01 1.4639970e+00 1.0805648e+00 -4.8943754e-01 -1.5534979e+00 -1.6393854e-01 1.2121260e+00
+1 5.4958645e-01 1 1 8.5748600e-01 -5.2782617e-01 4.4451154e-01 -4.9432649e-01 -1.2871369e+00 1.3689922e-01 -1.3834063e-01 -1.0269799e+00
+1 3.2106615e-01 1 1 1.2817708e+00 6.8315762e-01 1.9808086e-01 1.3672686e+00 9.7056707e-02 1.2194049e+00 -3.1237217e-01 -5.4073410e-01
+1 4.2240151e-01 1 1 8.2093077e-01 -6.9110477e-01 -9.4327474e-01 -1.0663946e+00 7.4548399e-01 -1.2115462e+00 -4.3769109e-01 5.0956275e-01
+1 5.6865364e-01 1 1 -4.9151423e-01 -9.2978390e-01 -1.1420549e+00 -1.0756541e-01 6.7790943e-01 1.3472411e+00 1.3358921e+00 2.3961560e-01
+1 3.1834045e-01 1 1 1.5090503e+00 -5.9607374e-01 6.1501345e-01 -1.4361538e+00 -9.3282893e-01 -1.5181350e+00 -6.2359398e-01 -3.0241901e-01
+1 4.0712945e-01 1 1 5.3131279e-01 3.2754193e-01 6.9120573e-01 -5.8018756e-01 -1.5084899e+00 7.2013638e-01 -3.9085356e-01 3.4054640e-01
+1 7.4940826e-01 1 1 1.3677143e+00 9.2686287e-01 -5.1499248e-01 2.9134105e-01 -5.3722618e-01 -1.2243880e+00 -5.5239297e-03 -4.1854759e-01
+1 1.1188766e+00 1 1 1.4156941e-01 -1.3736481e+00 -3.9090365e-01 -1.1739820e+00 -2.2309361e-01 -8.5773306e-01 1.4070938e+00 -5.0344127e-01
+1 9.6083044e-01 1 1 1.1715036e+00 6.6072284e-01 -8.4749020e-01 1.2283146e+00 1.5273111e+00 8.4919110e-01 -8.8439821e-01 -1.0284136e+00
+1 9.1451159e-01 1 1 1.0995673e+00 -7.6122153e-01 2.1323461e-01 8.7793042e-01 -4.3672558e-01 9.9404287e-02 -1.2058380e+00 4.9548017e-01
+1 6.1308309e-01 1 1 -1.5616402e+00 -1.2849647e+00 -7.2308763e-01 -6.8404395e-01 -1.2863645e+00 -6.3944760e-01 -1.0481461e-01 -8.2696381e-01
+1 9.9157976e-01 1 1 1.5191565e+00 -1.0937789e+00 -1.2533313e+00 1.5024315e+00 5.1278616e-01 1.9265982e-01 8.1440795e-01 -3.7478361e-01
+1 9.4148790e-01 1 1 7.3941664e-01 1.4587369e+00 -3.6015679e-01 -7.5607868e-01 1.0083642e+00 -9.4836693e-01 -1.6475180e-01 -9.4886626e-02
+1 7.3325504e-01 1 1 -7.6505811e-01 1.3193319e-03 6.9384425e-01 3.2794616e-01 -1.3147265e+00 1.2382068e+00 -1.2403990e+00 1.1695478e+00
+1 6.7215736e-01 1 1 2.0712679e-01 1.8286332e-01 -1.5167539e-01 1.4376304e+00 1.3552109e+00 6.3235423e-01 2.2328318e-01 -3.5549007e-01
+1 9.2800682e-01 1 1 2.9533083e-01 9.0624901e-01 -1.3766324e+00 2.6506858e-01 4.8365953e-01 -3.0447510e-02 -1.4828614e+00 5.8757272e-01
+1 8.3979281e-01 1 1 -9.1098468e-02 8.8598860e-01 7.6953869e-01 2.2915890e-01 1.5655688e+00 3.4830329e-01 -1.9748225e-01 1.3089805e+00
+1 6.5567727e-01 1 1 -1.1363330e+00 -3.3882046e-01 -3.0014164e-01 -1.1891321e-01 -1.4658892e+00 1.1463600e+00 -1.5622578e+00 -5.3770332e-01
+1 5.9933649e-01 1 1 -6.0643834e-01 1.1519483e+00 9.1733841e-01 -5.2142658e-01 -8.3085891e-01 -5.1491577e-01 5.6397830e-01 1.1823023e+00
+1 8.9282018e-01 1 1 -1.0825799e+00 -8.3971506e-01 -1.2300190e+00 1.4269288e+00 1.3371896e-01 8.9840330e-01 5.9821831e-01 3.8069013e-01
+1 5.6645382e-01 1 1 1.1835040e+00 -1.0567981e+00 -1.2497017e+00 -5.2564264e-01 1.1758577e+00 9.7003001e-01 1.1586634e+00 -1.1652205e+00
+1 6.1974158e-01 1 1 -1.4135208e+00 9.5967907e-01 9.5210961e-01 -3.1734795e-01 -1.1195328e+00 1.5700422e+00 -1.0774512e+00 8.2783893e-01
+1 6.5114756e-01 1 1 -3.1964658e-01 3.8941783e-01 -1.1668392e+00 7.5733738e-01 -9.9010259e-01 1.4622602e+00 -5.8143685e-01 -6.2495529e-01
+1 8.3812569e-01 1 1 -1.7665841e-01 1.0080045e+00 -1.2452768e+00 -1.1640405e+00 3.6198137e-01 -4.7297406e-01 1.2856299e+00 -1.2793837e+00
+1 4.3827930e-01 1 1 -2.9283534e-01 -1.0780903e+00 -7.7237432e-02 -1.3318125e+00 -1.4441661e+00 -1.0456125e+00 -2.9293484e-01 -1.5409981e+00
+1 8.6918643e-01 1 1 1.1922097e+00 1.2423155e+00 -6.5175454e-01 7.5649281e-02 -1.5482160e-01 4.6006280e-01 -4.8011761e-01 -2.6601979e-01
+1 6.5899645e-01 1 1 3.9126405e-01 5.7148324e-01 6.9495641e-01 -9.0756115e-01 -8.4786191e-01 8.1600785e-01 1.4148001e+00 -5.0822819e-01
+1 6.2381107e-01 1 1 6.2147577e-01 1.0700049e+00 -3.0915712e-01 -9.4784570e-01 2.4923866e-01 -1.5496422e+00 -1.6893140e-01 1.9916426e-01
+1 9.0160426e-01 1 1 -6.5224007e-01 1.0958946e+00 1.9049216e-01 5.7367439e-01 1.2112318e+00 -1.0334925e+00 7.6972988e-01 1.5575981e+00
+1 9.3224179e-01 1 1 -1.1821500e+00 -4.5707277e-01 3.1876293e-01 1.9759897e-01 -3.4689999e-01 -4.2721377e-02 -2.2842473e-01 -3.4049928e-01
+1 3.2947853e-01 1 1 -9.6274858e-01 -8.2794988e-01 1.0331273e+00 3.8253216e-01 4.4779997e-01 1.4065425e+00 -1.0828970e-01 1.2103804e+00
+1 9.1520114e-01 1 1 1.4283154e+00 -1.2397182e+00 1.8838463e-01 1.5194993e+00 -1.0818347e+00 -7.2478983e-01 -1.0429131e+00 1.0515460e+00
+1 7.9673162e-01 1 1 7.8706694e-01 -9.0187121e-01 -5.4496661e-01 2.1818293e-01 1.1427217e+00 1.5536415e+00 -1.2944974e+00 -1.2668299e+00
+1 1.1049122e+00 1 1 -1.0126526e+00 4.3506344e-01 -1.5111978e+00 7.6187526e-01 1.1675016e+00 -8.6618621e-01 -1.0891170e+00 -1.0374093e+00
+1 6.0239440e-01 1 1 1.4974561e+00 -1.5163783e+00 1.0751459e+00 -2.9414435e-01 -1.8861985e-01 1.4866536e-01 1.2712290e+00 1.0088161e-01
+1 4.3443470e-01 1 1 4.4551459e-01 -1.1710099e+00 -4.6376714e-01 1.1827235e+00 -2.6680236e-01 1.0524911e+00 -4.2565706e-01 -9.4281387e-01
+1 1.0629879e+00 1 1 1.3484490e+00 9.1380168e-01 -2.4294327e-01 1.1774321e+00 -1.0944949e+00 -1.0904371e+00 -6.1178721e-01 3.2065777e-01
+1 4.9264091e-01 1 1 -6.6601605e-02 -9.8158422e-01 9.2297789e-01 2.0964605e-01 -1.1510167e+00 1.0757893e+00 1.2509468e-01 1.4637564e+00
+1 1.0322213e+00 1 1 -9.6619168e-01 -9.8293613e-01 -6.9510001e-01 -1.3457304e+00 7.9029850e-01 9.2508120e-01 7.4073100e-01 -4.5896792e-01
+1 7.4189134e-01 1 1 1.0891452e-01 1.4281734e+00 1.0371902e+00 -1.3659392e+00 -1.0682993e-01 9.7769034e-02 -6.6570543e-01 -1.2639143e+00
+1 9.8220079e-01 1 1 -1.0221141e+00 1.5417280e+00 -6.4255948e-01 1.4185535e+00 1.5004137e+00 1.5119322e-01 -1.2996734e+00 8.4114296e-01
+1 6.8244345e-01 1 1 -4.4278796e-01 -3.3961430e-02 1.2983950e+00 8.2144527e-02 -1.1165002e-01 -4.4402165e-01 -1.1765636e-01 -7.7224330e-02
+1 9.8970061e-01 1 1 4.9578357e-01 9.8010270e-01 6.2280616e-01 1.4438975e+00 -9.7109275e-01 -1.3893217e+00 -1.3886484e+00 -4.3155101e-01
+1 7.3901935e-01 1 1 1.1308175e+00 1.2158107e+00 -2.8365685e-01 -1.2179550e+00 -5.8202725e-01 1.1289916e+00 -1.2236925e-01 8.5967203e-01
+1 2.7137363e-01 1 1 -9.8512248e-01 1.2120789e+00 1.5169517e+00 4.4847181e-01 7.8747976e-01 -2.5833064e-01 1.0832171e+00 3.2313734e-01
+1 2.2909359e-01 1 1 -7.6021963e-01 1.3225832e+00 1.3834560e+00 7.8501466e-01 -3.5745944e-01 -8.1956787e-02 1.0045511e-01 -8.4440656e-01
+1 6.6277970e-01 1 1 -1.5397129e-01 -1.2531514e+00 8.1860004e-01 -9.4772113e-01 -1.0956545e+00 -1.4301328e+00 1.3137685e+00 -1.3670840e+00
+1 3.9960611e-01 1 1 8.7686891e-01 -4.7766348e-01 1.1766381e+00 -4.7428813e-01 1.3512091e+00 8.3732512e-02 1.3941618e+00 1.0283293e+00
+1 7.1827806e-01 1 1 3.2457511e-01 -1.3208124e+00 -5.6992574e-01 -1.1400969e+00 -8.0251148e-01 -1.4118241e-01 -1.4618143e+00 1.2300828e+00
+1 4.9394927e-01 1 1 1.3289556e+00 -3.9986732e-01 -2.5841562e-02 -1.0349851e+00 -9.5317699e-01 -9.5032485e-01 -1.4583434e+00 -8.2015670e-01
+1 8.5179916e-01 1 1 -9.6680161e-01 -7.0330804e-01 -7.7934777e-01 3.3145854e-03 -1.0647539e+00 -2.5274797e-01 3.2836300e-01 9.3487977e-01
+1 8.6344181e-01 1 1 -7.1750015e-01 1.3149138e+00 -1.1982610e+00 -8.4043049e-01 -8.0708583e-01 -5.0193337e-01 -9.8142462e-01 1.4193892e+00
+1 6.7640608e-01 1 1 1.5491277e+00 -1.3489208e+00 -1.5631078e+00 -5.1463230e-01 7.0548522e-01 -8.1795522e-01 -1.4421074e+00 1.5613223e+00
+1 1.1540587e+00 1 1 -1.3305646e+00 1.5630195e+00 -1.1553925e+00 -6.2050783e-01 7.1944002e-01 2.3610911e-01 -1.1242962e-01 -5.7900496e-01
+1 1.0998737e+00 1 1 -9.4354645e-01 -3.2842432e-01 -4.9738862e-01 1.2125877e+00 -3.6162892e-01 4.5425911e-01 -1.5073736e+00 1.3176869e+00
+1 8.4161362e-01 1 1 5.7456246e-01 -4.9175148e-02 1.6745193e-01 4.4937869e-01 1.0844953e+00 6.6266276e-01 -6.2428999e-01 1.2772606e+00
+1 6.7155348e-01 1 1 -5.8461640e-01 -2.4784261e-01 -5.0238396e-01 3.1891774e-01 -4.0801397e-01 4.2701487e-01 4.7765897e-01 4.1642232e-01
+1 3.0477095e-01 1 1 1.2539091e+00 2.6107367e-01 1.0339208e+00 4.9335897e-01 6.0599880e-01 1.4413325e+00 1.2450590e+00 -6.5848261e-01
+1 6.6106472e-01 1 1 6.4629093e-01 -9.3970627e-01 9.5777729e-01 1.2211559e+00 -2.1527442e-02 -3.4625379e-01 -4.4184474e-01 7.1369374e-01
+1 1.0976437e+00 1 1 -1.4158084e+00 -8.5704436e-01 -1.5785318e-01 -5.7408147e-02 -5.2855475e-01 -1.2578351e+00 6.4048347e-01 4.4987941e-01
+1 1.0776854e+00 1 1 -1.0696559e+00 -1.4230692e-01 -1.5341982e+00 -3.8977445e-01 1.0042839e+00 -6.5817780e-01 1.5092007e+00 -6.9027897e-01
+1 7.9751522e-01 1 1 -1.5131488e+00 -1.0004334e+00 9.2373150e-01 -7.1850572e-01 -7.7814108e-01 -4.4651380e-01 -8.3200854e-02 3.8308565e-01
+1 1.0795198e+00 1 1 -2.9897022e-01 -4.8012553e-01 -5.9551360e-01 3.5649403e-01 2.3316008e-01 7.0748913e-01 -3.4801824e-01 1.3972390e+00
+1 7.1686683e-01 1 1 -1.3857797e+00 1.2817093e+00 3.1712907e-01 5.7791662e-01 1.1553576e+00 -1.5832177e-01 5.0290034e-01 -9.4863969e-03
+1 8.6713013e-01 1 1 9.6914470e-01 -2.1306204e-01 -1.2944666e+00 -7.5985075e-01 -8.9607721e-02 1.5008610e-02 1.3617556e+00 7.8335284e-01
+1 6.3932965e-01 1 1 -7.4296351e-01 4.8193159e-01 -5.7113709e-01 -2.3747794e-01 -1.2140865e+00 9.2229289e-01 5.2359156e-01 -6.0370797e-01
+1 6.7061090e-01 1 1 8.4305398e-01 7.9836052e-01 -1.5355239e+00 -1.4690202e+00 -5.0751897e-01 3.5840709e-01 4.0239176e-01 8.2449770e-01
+1 5.7841624e-01 1 1 6.2529067e-01 3.0308265e-01 6.3407340e-01 -4.6159601e-02 -4.4722692e-01 1.3148784e+00 -8.5068973e-01 -2.3229577e-01
+1 8.9571577e-01 1 1 6.3282866e-01 1.3884422e+00 5.8933549e-01 1.6896807e-01 1.2883798e+00 1.1981273e+00 -1.5405317e-01 8.0469795e-01
+1 8.7439304e-01 1 1 -1.4814282e+00 -2.0281776e-01 -4.8000572e-01 -1.5340093e-01 -1.1981034e+00 -6.8402060e-01 -4.9930486e-01 2.1164146e-03
+1 7.9551682e-01 1 1 -1.2415890e+00 -1.3002773e-01 1.5381356e-01 1.0381243e+00 1.0844242e+00 -1.2466993e+00 -6.2274125e-01 1.0130603e+00
+1 6.1478610e-01 1 1 -9.2828562e-01 1.1724423e+00 -3.8632425e-01 -6.5005475e-01 1.5384901e+00 1.1482742e+00 1.3745446e+00 -9.2790040e-01
+1 7.2912889e-01 1 1 -5.4732580e-01 1.1682434e+00 7.2034006e-01 9.8905651e-01 -1.0456322e+00 2.4046185e-01 -1.3014877e+00 -3.5606977e-01
+1 6.0453316e-01 1 1 -3.2148909e-01 -2.8740348e-01 -9.4269589e-01 9.0600874e-01 1.2835602e-01 1.3540821e+00 8.0603030e-01 2.6932762e-01
+1 5.1738615e-01 1 1 2.7222359e-01 1.3791493e+00 -8.3811955e-01 -1.0680191e-02 -9.9449149e-01 3.6133820e-01 4.0364657e-01 -4.4573399e-01
+1 4.7974888e-01 1 1 1.1029064e+00 6.9229234e-01 6.2616697e-01 -4.3118395e-01 -1.1456388e+00 3.1251217e-01 1.3893818e+00 1.2473843e+00
+1 1.0596886e+00 1 1 1.1508300e+00 -1.1018662e+00 -3.4711750e-01 7.4565258e-01 6.9427123e-02 -3.5087580e-01 -1.1752070e-01 9.3968843e-01
+1 9.6450760e-01 1 1 -7.8653250e-01 6.2351378e-01 -6.6217222e-02 3.6990062e-01 1.3307832e+00 -4.0012764e-01 8.9145151e-01 5.5725185e-01
+1 1.0035037e+00 1 1 5.7014312e-01 -9.5692191e-01 -7.8904874e-01 -2.9215657e-01 1.4744551e+00 1.2045982e+00 3.7018051e-01 6.4417374e-01
+1 4.3542756e-01 1 1 5.3779343e-01 -1.1738138e+00 -8.7951722e-01 3.3911723e-02 2.8392107e-01 1.2587977e+00 1.2703107e+00 6.9980332e-01
+1 6.1191260e-01 1 1 3.3207651e-01 9.1347052e-01 -8.5243017e-01 1.3260639e+00 -2.1788778e-01 1.1282901e+00 -1.5092282e-01 -5.2850963e-01
+1 1.2569511e+00 1 1 -1.4003025e+00 -2.6426708e-01 -1.1313842e+00 6.9752751e-01 1.0570618e+00 5.1898773e-01 -1.2945029e+00 -1.3788654e+00
+1 7.9382667e-01 1 1 -1.2129506e+00 6.7526701e-01 8.8658917e-01 -1.0789933e+00 3.3132026e-01 1.5655468e+00 -1.1814913e+00 9.3764243e-01
+1 9.7057124e-01 1 1 -2.6572812e-01 -1.3615481e+00 3.3023572e-01 -1.3671389e+00 -1.5441214e+00 1.3072141e+00 6.8227447e-01 7.2756429e-01
+1 1.0505653e+00 1 1 1.2522895e+00 -1.7880851e-01 -9.2243208e-01 1.0586437e-01 6.4913954e-01 1.1897164e+00 1.7377299e-01 1.0944717e+00
+1 9.2896577e-01 1 1 -1.4405937e+00 1.2695876e+00 4.4370738e-01 1.1209578e+00 -6.6303323e-01 -6.7355643e-01 -1.0784571e+00 7.6167735e-01
+1 7.9202232e-01 1 1 1.9640241e-01 2.6090587e-01 -7.5109388e-01 -1.9334021e-01 -3.7033293e-01 -1.3045150e+00 1.3612770e+00 -4.7888891e-01
+1 8.5558129e-01 1 1 -8.7864666e-01 -6.1844493e-01 -7.1560017e-01 -1.0620720e+00 -6.9051432e-01 1.9180847e-01 -1.2374138e+00 7.4543910e-02
+1 6.6539653e-01 1 1 1.2126621e+00 1.3261598e+00 -1.0754363e+00 2.8460437e-01 -4.3096993e-01 4.5086585e-01 1.3030152e-01 -6.3596992e-01
+1 1.3683618e+00 1 1 -1.4405747e+00 -8.3249292e-01 -1.2748679e+00 -1.2998915e+00 1.2011029e+00 1.8082706e-01 2.8764367e-01 -1.0482399e+00
+1 4.6353604e-01 1 1 5.1571721e-01 9.4520978e-01 -1.0432794e+00 -6.4155764e-01 -9.3765544e-01 1.2402880e+00 -4.8395578e-01 2.8397773e-01
+1 7.7549489e-01 1 1 4.9407739e-03 -8.9325074e-01 -1.1679631e+00 -7.1318770e-01 -9.4616966e-01 1.0539556e+00 -2.6147656e-01 7.3440155e-01
+1 6.8042396e-01 1 1 1.3581787e+00 8.0611570e-01 -1.2843703e+00 -1.3697014e+00 4.6855108e-01 1.5321098e+00 4.5158361e-01 -2.3076319e-01
+1 1.0481982e+00 1 1 9.6491264e-02 -1.3025416e+00 -5.2789084e-01 1.0193885e+00 -1.0347434e+00 -1.4649253e+00 -3.2204826e-01 1.4300418e+00
+1 7.2307453e-01 1 1 6.6686637e-01 -1.1990649e+00 -4.0377157e-01 -1.3840123e+00 9.2398054e-01 -3.3810170e-01 2.9898698e-01 1.5291716e+00
+1 1.2056888e+00 1 1 -1.1795878e+00 6.3240809e-01 -3.4867257e-01 -7.4226873e-01 4.4850666e-01 6.6581695e-01 -1.4741413e+00 -5.8276624e-01
+1 7.8943000e-01 1 1 1.2590010e+00 8.7480638e-01 -1.0695165e+00 -4.6038093e-02 1.3707079e+00 3.2417101e-02 -1.2930399e+00 9.3366764e-01
+1 4.2752289e-01 1 1 1.4036388e+00 2.1724816e-01 8.2900942e-01 -9.3043101e-01 1.8844012e-01 1.3386858e+00 1.4170584e+00 -1.0320141e-01
+1 9.1052620e-01 1 1 7.3730904e-01 7.5916682e-01 1.9790637e-01 1.0942681e+00 3.8770208e-01 -7.9500485e-01 8.6578838e-02 -3.4698422e-01
+1 8.6680050e-01 1 1 1.5116248e+00 1.3089583e+00 -7.3425426e-01 4.8035402e-01 4.4575566e-01 -4.5299212e-01 5.7313832e-01 -9.6788552e-01
+1 7.7199006e-01 1 1 -1.8148091e-01 -9.1069212e-01 -4.3540830e-01 -5.8311549e-01 -8.8305019e-01 -1.3595440e+00 6.1261985e-01 -8.5213762e-02
+1 5.3117149e-01 1 1 3.3682943e-01 -1.6307263e-01 -1.1379602e+00 1.3471108e+00 -5.4087988e-01 -1.0533248e+00 1.3027449e+00 3.7855646e-01
+1 9.2898099e-01 1 1 -5.7671102e-02 -1.2929547e+00 3.1881775e-01 -5.6721844e-01 1.2009854e+00 -3.5500701e-01 1.4746840e+00 6.7334198e-01
+1 9.1115691e-01 1 1 1.4739239e+00 -2.9343255e-01 -1.1871068e+00 1.4934458e+00 2.2810467e-01 -7.1841685e-01 9.8994021e-01 8.4183599e-01
+1 7.8115065e-01 1 1 7.8064542e-01 5.7967968e-01 5.5134881e-01 -9.8247576e-01 1.0121258e+00 -1.2914469e+00 5.0375791e-02 -9.9574735e-01
+1 7.3452946e-01 1 1 1.0167042e+00 5.9757476e-01 -1.1788187e+00 -2.5911551e-01 -9.2534717e-01 -8.4670689e-02 -1.5640957e+00 -2.6169765e-01
+1 7.4703668e-01 1 1 6.2421476e-01 -2.3269287e-01 -1.5225277e+00 -7.0689927e-01 -1.4261902e+00 8.1210230e-02 1.0910970e+00 -1.2267238e-01
+1 4.8614090e-01 1 1 1.3996074e+00 4.1384251e-01 -8.5163200e-01 6.4735001e-01 3.7357841e-01 1.4491307e+00 5.9042797e-01 -8.6989266e-01
+1 1.1660040e+00 1 1 -1.0444429e+00 -3.5039030e-02 -2.8284510e-01 6.7620278e-01 -1.3114554e+00 -1.2274143e+00 -9.6830909e-01 6.8622593e-01
+1 5.9512895e-01 1 1 1.2684672e+00 -1.4231587e+00 -5.4798121e-01 -1.3421450e+00 -2.1692423e-01 -1.4548176e+00 -9.2095116e-01 6.1254395e-01
+1 7.8680384e-01 1 1 2.7974002e-01 1.0583411e+00 1.2293938e+00 -7.9495426e-01 1.5435738e+00 -1.0312397e-01 2.0085036e-01 2.6985545e-02
+1 9.0623346e-01 1 1 -1.3737421e+00 -1.5885589e-01 1.6637469e-01 3.9738300e-01 -4.2651400e-01 9.5459178e-01 -1.5200313e+00 1.1567128e+00
+1 9.7043706e-01 1 1 -9.1984485e-01 4.6280431e-01 2.4202036e-01 -2.0990736e-01 6.9357139e-01 -2.8964415e-01 2.6614945e-01 6.9666395e-01
+1 9.7993950e-01 1 1 -5.4906663e-02 -2.3134890e-01 -7.2628362e-01 9.5472203e-02 1.5455672e+00 1.4194239e+00 -4.5419524e-01 1.1510796e-01
+1 2.7905466e-01 1 1 8.1194791e-01 1.0106939e+00 -1.5613638e+00 -7.5253565e-01 -1.4822876e+00 -9.9735546e-01 4.1081720e-01 -6.0166126e-01
+1 9.5797501e-01 1 1 -6.6991697e-01 1.4081439e-01 -1.1730636e-01 1.8533496e-01 2.2217101e-02 9.8513527e-01 -6.1604346e-01 6.6603632e-01
+1 6.1824053e-01 1 1 1.7354334e-01 1.0481167e+00 1.3521635e+00 -1.5351769e+00 -4.4671568e-01 9.7518608e-01 8.4690006e-01 5.7785682e-01
+1 6.7294274e-01 1 1 1.3448720e+00 7.8736728e-01 -4.6900599e-01 1.8266752e-01 4.5608851e-01 2.6355550e-01 -7.0693443e-01 1.3766883e+00
+1 7.2838423e-01 1 1 -4.9606228e-01 8.9369223e-01 -3.2762857e-01 7.5695929e-01 -6.5457121e-03 -6.8436739e-02 5.6444287e-02 1.7040783e-01
+1 6.5359542e-01 1 1 4.6812513e-01 3.3088945e-01 7.5849988e-01 -1.2353845e+00 -5.8040551e-02 -3.9336528e-01 -1.0185174e-01 -1.0881190e+00
+1 1.0698007e+00 1 1 1.2310838e+00 6.3992858e-01 -4.7542533e-01 -3.2106793e-01 1.5477677e+00 -1.3793571e+00 3.4580666e-01 -8.0467401e-01
+1 1.3147557e+00 1 1 2.9539590e-01 -1.5335387e+00 -1.4034508e+00 1.0674166e+00 9.4516736e-01 -1.0432960e+00 2.6193610e-02 4.0030334e-01
+1 9.6606051e-01 1 1 1.0025676e+00 -5.5916758e-01 -7.1961036e-01 -1.5650819e+00 1.5354342e+00 -1.4468072e+00 4.1303841e-01 -1.3932604e+00
+1 8.5739050e-01 1 1 -1.3488479e+00 -1.4259089e+00 6.4040347e-01 2.2404784e-01 1.0003691e+00 -5.6197778e-01 -9.8313193e-01 9.0373642e-01
+1 7.8150234e-01 1 1 -3.5405360e-01 -1.1822136e+00 1.6471990e-01 -1.1975182e+00 -5.9982087e-01 -1.5330717e+00 1.2790312e+00 -5.0249862e-01
+1 4.4774363e-01 1 1 -4.0236831e-01 1.1092243e+00 7.0429827e-01 1.4951666e+00 1.8142903e-01 1.0063444e+00 -1.2418089e+00 -8.9332732e-01
+1 8.3765157e-01 1 1 1.2447252e+00 5.2228762e-01 -3.8015130e-01 -3.3483539e-01 -1.2087184e+00 -7.0442492e-01 -1.4813474e+00 -4.8102758e-01
+1 5.8827808e-01 1 1 2.3131368e-01 4.7814957e-01 7.9659578e-01 -9.8590720e-01 -1.3921907e+00 1.3930770e+00 1.1614429e-01 -1.3126239e+00
+1 8.8052548e-01 1 1 1.5388374e+00 6.5890551e-02 -1.0826428e+00 -1.3826788e+00 3.3002739e-02 -8.4543587e-01 1.1080918e+00 -1.0062243e+00
+1 5.6538113e-01 1 1 -1.4915060e+00 -1.5597193e+00 1.2703840e-01 -3.2173261e-01 -1.3848621e+00 1.8297123e-01 3.3702289e-01 -4.1815995e-01
+1 1.4395848e+00 1 1 -9.7321628e-01 -7.5294907e-01 -1.1486246e+00 -6.7907810e-01 6.8287902e-01 -4.2178703e-01 5.2156059e-02 -2.7149332e-01
+1 8.5877384e-01 1 1 1.4269004e+00 -4.7976682e-01 1.5321314e-01 1.4043089e-01 9.0980489e-01 -1.5416663e+00 8.2525228e-02 -1.3956589e+00
+1 5.4648606e-01 1 1 -1.0038895e+00 1.0273703e+00 -1.0527496e+00 8.8582447e-01 9.5930275e-01 1.0703884e+00 1.5591543e+00 1.4325395e+00
+1 3.7232983e-01 1 1 1.1230183e+00 8.1966831e-01 -1.1268738e-01 4.4228674e-02 3.4787365e-01 1.2579164e+00 6.8195349e-01 -4.7524028e-01
+1 7.9980960e-01 1 1 -1.1955029e-01 2.8153840e-01 4.4351121e-01 -1.2061403e+00 2.0856089e-01 -1.1179611e+00 1.0623896e+00 -1.4348529e+00
+1 5.0306144e-01 1 1 1.3375593e+00 5.7734286e-01 -9.0643207e-01 1.0970192e+00 -7.3458909e-01 2.9277848e-01 -1.2305339e+00 -7.0689018e-01
+1 1.1841933e+00 1 1 -8.7796198e-01 -9.7822239e-01 -8.2100031e-01 -4.0617744e-01 2.2024399e-01 9.9389723e-01 -4.7880475e-01 8.0011068e-01
+1 9.0963881e-01 1 1 1.5377042e-01 -1.0293086e+00 -6.7726596e-01 5.6677832e-02 8.4454118e-01 5.8267670e-01 1.4888771e+00 1.4436239e+00
+1 6.4035891e-01 1 1 -1.1112306e+00 1.1605864e+00 -8.1883354e-01 6.8174022e-01 4.8801137e-01 7.0293857e-01 7.7205220e-01 4.6699395e-01
+1 5.1570105e-01 1 1 3.1630666e-01 -1.7305013e-01 1.1821248e+00 6.1947878e-01 -6.9134661e-01 -1.2414387e+00 1.1035897e+00 1.0688573e+00
+1 7.3430713e-01 1 1 5.9129895e-01 6.6131756e-01 5.4026562e-01 3.4177030e-01 1.2886841e+00 -1.5435369e+00 6.8899997e-02 6.5765152e-01
+1 5.0329092e-01 1 1 1.1038889e+00 -1.9058816e-01 1.0415618e+00 1.3021426e+00 7.7347136e-01 1.0477604e+00 -1.2454375e+00 1.0260726e+00
+1 3.8167338e-01 1 1 -1.1848375e+00 1.2092659e+00 5.7559486e-01 7.7641817e-01 -1.7716950e-01 1.0823490e+00 3.6386224e-01 1.0008809e+00
+1 6.5126612e-01 1 1 9.9217326e-01 1.1694914e+00 1.0590952e+00 -9.1573895e-01 5.4198849e-01 1.2180162e+00 -1.2482963e+00 -1.4233100e+00
+1 4.5816899e-01 1 1 -1.1780171e-01 -1.3032553e+00 -5.0565587e-02 -1.6214924e-01 -1.4181158e+00 5.8028391e-01 -5.5964694e-01 -1.4842033e+00
+1 5.6833734e-01 1 1 -6.8992341e-01 -6.2859923e-01 1.5157859e+00 -1.4813631e+00 9.9132713e-01 1.3280008e+00 -5.7639795e-02 -7.5932136e-01
+1 6.8284879e-01 1 1 7.5736554e-02 3.0883989e-01 6.3816720e-01 -1.4738200e-01 1.3692076e+00 -1.3070440e+00 -1.1415013e+00 -7.6481344e-01
+1 2.8716158e-01 1 1 5.5924127e-01 7.6092033e-01 2.7887918e-01 -1.4743392e+00 1.0593386e-01 -1.4729658e+00 4.9371203e-01 1.1776803e+00
+1 6.4823342e-01 1 1 -4.7714949e-01 -6.3573906e-01 -1.3381026e-01 -1.4783253e+00 -8.5256769e-01 -3.8677820e-01 8.7186094e-01 1.2392336e+00
+1 3.7765215e-01 1 1 1.0345655e+00 -3.0969179e-01 4.3134218e-01 6.4241748e-01 -3.0109270e-01 -6.2592729e-01 9.7865918e-01 -9.6031070e-01
+1 1.0329549e+00 1 1 -7.7340399e-01 6.2919057e-01 -1.2278867e+00 -5.4343894e-01 6.4080161e-01 1.2338039e+00 -1.0543515e+00 1.5610818e+00
+1 7.6646710e-01 1 1 1.3095605e+00 2.0504607e-01 2.9601785e-02 -9.6844255e-01 5.7305689e-01 -1.1116971e+00 1.2381988e+00 -1.4793127e+00
+1 7.2283598e-01 1 1 -2.1409820e-01 -1.1776333e-01 1.1455659e+00 -2.2380855e-02 -7.5593186e-01 -1.2417800e+00 4.9810777e-01 -2.4366219e-01
+1 1.1542768e+00 1 1 -1.2248464e+00 -4.4925709e-02 -1.2959874e+00 8.3608374e-01 -3.4604407e-01 -9.9597021e-01 -6.4721523e-01 1.4063309e+00
+1 8.2818681e-01 1 1 8.6370752e-01 -1.0841509e+00 -9.9808633e-01 -2.8453047e-01 -8.7472054e-01 -8.6567964e-01 -1.5525462e+00 -1.1392532e+00
+1 7.4508677e-01 1 1 -9.6744108e-01 -8.6616323e-02 1.2678316e+00 -5.9962630e-01 1.2255817e+00 -7.6220688e-01 4.2467241e-01 5.7880794e-01
+1 7.3981238e-01 1 1 1.1013347e+00 -1.2031378e+00 -9.7658297e-01 3.0994251e-01 -1.0718061e+00 1.0038394e+00 -2.2939611e-01 -1.4874332e+00
+1 5.6421454e-01 1 1 -1.3123972e-01 1.2951261e+00 1.3915694e+00 4.4320339e-01 4.6692460e-02 1.1769523e+00 -7.2629443e-01 1.5040110e+00
+1 1.0138220e+00 1 1 -3.4796007e-01 -9.1058181e-01 -1.0506817e+00 2.0327322e-01 -6.3798258e-01 1.5694326e+00 1.3985290e+00 6.5807380e-01
+1 3.1822336e-01 1 1 1.4806129e+00 -1.4505889e+00 8.4235552e-02 1.5018412e+00 -3.1750992e-01 6.4108256e-01 -3.1916744e-01 -1.3012965e+00
+1 5.9611664e-01 1 1 1.0557566e-01 -1.2881534e+00 -1.1113591e+00 -1.2511062e+00 1.1766281e+00 -9.8819351e-01 -1.5485664e+00 8.7836188e-01
+1 2.1801824e-01 1 1 -5.8967237e-01 -1.2794651e+00 1.2970722e+00 -6.6240864e-01 -7.3647986e-01 1.0320658e+00 1.3390594e+00 2.8419421e-01
+1 6.5689447e-01 1 1 1.1013834e+00 2.3142811e-01 3.8089652e-01 7.0232320e-01 -1.4200786e-01 1.1962169e+00 -7.9850454e-01 1.2313306e+00
+1 8.2922925e-01 1 1 6.8616388e-01 3.2060811e-01 -8.3804191e-01 9.8237300e-01 8.8427461e-01 -1.3756926e+00 4.1799219e-01 1.3024615e+00
+1 8.8778839e-01 1 1 -4.3037404e-01 6.2911709e-01 -1.2105796e+00 -1.4680415e+00 -8.7151538e-01 8.5616347e-01 5.9361521e-01 -1.4703860e-01
+1 6.9921153e-01 1 1 -1.3501620e+00 -1.0299722e+00 -1.2568701e+00 6.9601081e-01 -1.4539885e+00 1.0450491e+00 -8.0735763e-01 1.1557071e+00
+1 7.8403967e-01 1 1 -4.4848883e-01 -5.6732031e-01 -1.4648840e-01 -1.4373440e+00 1.2651161e+00 -5.0479918e-01 -7.2098994e-01 -4.9837929e-01
+1 1.9728111e-01 1 1 -1.0709400e+00 -2.1876215e-01 9.7810083e-01 1.4061482e+00 5.0719771e-01 1.2819865e+00 -5.5497568e-01 -7.7463752e-01
+1 1.0743182e+00 1 1 -1.1035451e+00 -1.0719820e+00 -1.0136963e+00 -1.0685852e+00 1.3311228e+00 1.3040172e+00 -8.7715391e-02 -5.7291386e-01
+1 9.1735190e-01 1 1 6.8071651e-01 2.3277302e-01 -3.3715107e-01 7.7295430e-01 8.9922775e-01 8.6648900e-01 -8.2562463e-01 1.8260609e-02
+1 6.6592230e-01 1 1 -8.7801239e-01 9.3336745e-01 9.3510051e-01 5.5731370e-01 -8.8143632e-01 -1.3428771e+00 1.4164283e-01 -9.7001764e-01
+1 1.1774014e+00 1 1 -6.9353129e-01 1.1346773e+00 -1.1537992e+00 -1.4579677e+00 1.4507783e+00 -5.3337834e-01 -7.3617722e-01 -1.3622306e+00
+1 3.3355979e-01 1 1 -8.7158108e-01 1.0537672e+00 1.1478596e+00 3.5903960e-01 1.3296772e+00 -1.5259861e+00 -1.3386291e+00 9.1713621e-01
+1 4.8980569e-01 1 1 5.8331639e-01 1.5073300e+00 -4.4494902e-01 -6.2086894e-01 -1.4061926e+00 7.1399170e-01 -1.3948394e+00 -1.4868042e+00
+1 1.0665860e+00 1 1 -1.1120607e+00 -1.0742700e-01 -1.2676677e+00 1.4265052e+00 3.2218967e-01 -8.2539652e-01 -5.0129419e-01 -4.9089329e-01
+1 8.3908768e-01 1 1 -1.0693658e+00 8.9026857e-01 5.8994410e-01 -1.3628553e+00 -1.0639747e+00 8.3386852e-01 5.0005722e-01 -6.2125601e-01
+1 7.1578328e-01 1 1 2.2096223e-01 -6.6194336e-01 3.2400996e-01 -1.5660175e-01 -2.7697643e-01 1.8334119e-01 7.0133014e-01 1.2041708e+00
+1 5.1065055e-01 1 1 3.4965672e-01 -9.0252457e-01 1.2553292e+00 6.4897846e-01 6.9753015e-01 -4.8702534e-01 -1.4986864e-05 3.5928095e-01
+1 7.5399791e-01 1 1 -1.2393754e+00 -1.1211012e+00 -6.1836361e-01 -2.2864588e-01 -1.0345641e+00 1.5554944e+00 -2.5188423e-01 2.9392066e-01
+1 1.0390647e+00 1 1 -1.4233016e+00 9.2432372e-01 -4.4870062e-01 -6.8355378e-01 7.9673730e-01 -1.1389496e+00 1.4486806e+00 1.3408970e+00
+1 1.1679408e+00 1 1 -1.3439084e+00 -6.6899866e-02 -1.4889931e+00 3.1603435e-01 1.2959537e+00 -6.0249547e-01 6.3232963e-01 -1.3300243e+00
+1 7.1831510e-01 1 1 9.8306607e-01 3.0411762e-01 4.2070473e-01 -8.4385551e-01 4.3228421e-01 -7.8818541e-01 -4.4383318e-01 -1.2872151e+00
+1 5.3518142e-01 1 1 7.5561827e-01 -6.6337390e-02 -9.4074148e-01 -1.5303313e+00 -1.1031517e+00 1.0640648e+00 -1.3633371e+00 -1.2169359e+00
+1 7.5251621e-01 1 1 1.3588018e+00 3.3287228e-01 5.9382581e-01 -5.8543064e-02 1.0090220e+00 -1.3493277e+00 1.1706066e+00 -1.2729074e+00
+1 8.9633938e-01 1 1 1.1445355e+00 -5.9216027e-01 -4.0941691e-01 -6.1477220e-01 3.1483121e-01 1.0062984e+00 -1.4092268e+00 4.9058019e-01
+1 1.0271676e+00 1 1 2.3700426e-01 1.2780622e-01 -9.8203896e-01 2.2188735e-01 9.2606316e-01 -1.4774485e+00 -4.0712514e-01 -1.4994160e+00
+1 7.2861327e-01 1 1 -2.0895391e-01 -8.1027127e-01 7.9896452e-01 1.9028592e-01 8.9344133e-01 -3.2870185e-01 -1.6345579e-01 1.1722255e+00
+1 5.2683513e-01 1 1 4.1216001e-01 5.7499738e-01 1.0297222e+00 -5.9323296e-03 -7.4440582e-01 1.5694128e+00 -1.4494443e+00 6.6651983e-01
+1 6.0118478e-01 1 1 -3.8542257e-02 4.4194275e-01 -4.9273085e-01 8.2630172e-01 -1.4066025e+00 3.0817100e-01 -9.0174028e-01 -7.2065822e-01
+1 6.5523122e-01 1 1 -6.1162638e-01 1.0067895e+00 -8.9121541e-02 -1.3281179e+00 -2.8316506e-01 -1.0562136e+00 -5.0587072e-01 -1.2630480e+00
+1 9.0083740e-01 1 1 -3.1347250e-01 4.9259774e-01 6.7396122e-01 -6.6104354e-01 3.5762520e-01 1.3585950e+00 -1.0194099e+00 -3.0641458e-01
+1 5.8018735e-01 1 1 -8.1495085e-02 9.9354361e-01 -1.3169178e+00 -1.4872059e+00 7.3994639e-01 8.1047253e-01 1.0242022e+00 -8.3945681e-01
+1 5.2575361e-01 1 1 4.6496245e-02 9.2257933e-01 -9.1734424e-01 -9.5787090e-01 -1.2864189e+00 -3.3392340e-01 9.8105588e-01 1.4199902e-01
+1 7.6283425e-01 1 1 -7.9418132e-01 -1.1104690e+00 1.1320633e+00 -1.4155104e+00 -4.0186007e-01 -1.3661454e+00 1.5279745e+00 -1.0329046e+00
+1 3.7825413e-01 1 1 8.2171800e-01 5.5023789e-01 1.1034670e+00 7.9717718e-01 3.6207917e-01 1.0949893e+00 1.2884765e+00 4.1306488e-01
+1 5.5843738e-01 1 1 1.7306293e-01 -1.0006345e+00 1.1477195e+00 -7.3577813e-01 1.9956627e-01 3.4717848e-02 4.2704096e-01 -5.3832373e-01
+1 4.3153158e-01 1 1 -4.4617900e-01 -7.1832280e-01 3.4334741e-01 -9.1431043e-01 -1.1106489e+00 -8.3335792e-01 -1.2617709e+00 1.7986737e-01
+1 2.2612403e-01 1 1 5.1246755e-02 2.8929288e-01 -4.6586655e-01 -1.2856483e+00 6.6828549e-01 -1.0264509e+00 -8.3347163e-01 8.1871097e-01
+1 1.2575447e+00 1 1 5.0783188e-01 -1.0399112e+00 -9.7016432e-01 -1.6495883e-02 6.8048345e-01 -1.0754212e+00 2.0399827e-01 -1.0050235e-01
+1 1.2221563e+00 1 1 -5.7681634e-01 -1.1070367e+00 -6.8578166e-01 -7.8614460e-01 1.4880775e+00 -1.0214224e+00 1.1213859e+00 1.0337784e+00
+1 5.6279258e-01 1 1 4.0264667e-01 -1.4548586e+00 5.7100489e-01 8.0636925e-01 -1.0033652e-01 -1.3840788e+00 7.1874065e-01 -1.4345881e+00
+1 7.5635021e-01 1 1 2.9207299e-01 -7.9242792e-01 -6.8635344e-01 -1.8264504e-01 6.7942265e-01 1.2814148e+00 4.5028372e-01 6.0139399e-01
+1 8.8417017e-01 1 1 -1.4385821e+00 -1.1247988e+00 3.8599817e-01 -3.7917598e-01 -6.3284832e-01 1.1207070e+00 -1.7815914e-01 1.1253017e+00
+1 1.0520974e+00 1 1 -5.5271882e-01 -1.5312259e+00 8.2491587e-02 1.4807894e+00 1.1509508e+00 -1.2671602e+00 -3.8284071e-01 5.5777905e-01
+1 8.3092074e-01 1 1 1.4424025e-01 6.1376724e-01 9.9374557e-01 -6.9194759e-02 1.2434412e+00 -3.0546275e-01 -4.2198930e-01 8.0031107e-02
+1 6.6967051e-01 1 1 -1.0636885e+00 -1.4041944e+00 1.1752585e+00 -5.6703312e-01 6.4197462e-01 -5.5003628e-01 1.3420593e+00 4.8115505e-01
+1 5.9378828e-01 1 1 1.3914128e+00 -6.5097071e-01 1.3765828e+00 1.4664448e+00 1.4382086e+00 1.2474127e+00 -6.4531851e-01 3.1339333e-01
+1 1.6979257e-01 1 1 -5.4039351e-01 1.3024911e+00 1.5389883e+00 7.4324204e-01 5.5887394e-01 1.4175911e+00 -1.0902734e+00 -1.2491431e+00
+1 4.8420694e-01 1 1 -4.9436996e-02 3.5046011e-01 1.0436377e+00 6.9652260e-01 -3.6780163e-01 -3.8526321e-01 6.8565903e-01 9.1622434e-01
+1 2.6659991e-01 1 1 -1.5071244e+00 -3.0323193e-01 9.0627252e-01 8.8105456e-01 1.0123702e+00 -2.9626986e-01 5.0951117e-01 -1.1046974e+00
+1 4.7532086e-01 1 1 4.2223818e-01 -7.5570936e-01 1.2810076e+00 1.5577810e+00 4.0903579e-02 1.6865675e-02 -6.2735592e-01 1.6320408e-01
+1 7.6578924e-01 1 1 -3.0076818e-01 2.5193863e-01 5.6000273e-01 -4.0787253e-01 -5.4233245e-01 7.1805417e-01 -7.8606003e-01 3.6062609e-01
+1 6.0039438e-01 1 1 -1.8824006e-01 -5.3432945e-01 -2.4572617e-01 -1.5852174e-01 -1.2211262e+00 1.4790560e+00 -9.1378448e-01 9.1049103e-01
+1 7.1697803e-01 1 1 -1.6688801e-01 1.3382830e+00 1.2746380e+00 -2.0430564e-01 5.5729181e-01 -9.2781845e-01 1.2706813e+00 -7.5075459e-02
+1 8.5723081e-01 1 1 5.5540624e-01 -1.2817752e+00 3.2059007e-01 -4.0831587e-03 1.3158240e+00 1.0213088e+00 -2.0674420e-01 1.1270146e+00
+1 7.4945924e-01 1 1 1.0408570e+00 -8.9513513e-01 3.2598071e-01 4.8939012e-01 1.3839125e+00 -5.2583531e-01 -1.4835646e-01 1.0725990e+00
+1 4.0023710e-01 1 1 1.2953053e+00 5.5106432e-01 -1.7982587e-01 4.9026367e-01 -9.3507444e-01 -4.1384881e-01 9.9746791e-01 7.1313576e-01
+1 6.2585485e-01 1 1 -1.0414394e+00 3.2293052e-01 -1.2126864e-01 -5.3598030e-01 -1.5495992e+00 -7.0858316e-02 9.0474020e-01 4.9668142e-01
+1 6.9382590e-01 1 1 1.4827034e+00 -1.1787892e+00 7.3164351e-01 -1.2748183e+00 -3.1074987e-01 -2.5210669e-01 6.6016318e-01 5.1294344e-01
+1 5.8784842e-01 1 1 6.8259312e-01 -1.0269223e+00 5.3880665e-01 -2.0910727e-01 -1.4461259e+00 8.5136179e-01 -7.4269487e-01 5.1009917e-01
+1 9.7434298e-01 1 1 -7.5386361e-01 4.2761071e-01 -1.4882173e+00 9.7629435e-01 1.4644921e+00 -1.1170020e+00 -9.2512284e-01 -1.6952892e-01
+1 7.4209443e-01 1 1 -1.4245799e-01 -1.1107192e+00 8.9229644e-01 4.0647052e-02 -6.5998540e-01 7.0432396e-01 -7.9749798e-01 1.5191355e-01
+1 1.1688268e+00 1 1 -3.9779540e-01 -5.1433733e-01 -1.1369904e+00 1.4294023e+00 5.8899574e-01 5.1601061e-02 -1.5143704e+00 -9.0372174e-01
+1 5.0047996e-01 1 1 -4.3808168e-01 1.1954788e+00 9.1117796e-01 2.0589747e-01 9.2885834e-02 1.7946067e-01 1.1607309e+00 7.4925641e-01
+1 7.3350849e-01 1 1 1.0543025e+00 -1.2149245e+00 -1.0961520e+00 -1.5163568e+00 -2.3934136e-01 2.6653849e-01 -8.8551943e-01 1.2490869e+00
+1 8.6450441e-01 1 1 1.0794746e+00 1.1164168e+00 -7.2667692e-01 -8.0972469e-01 -1.3717115e+00 -1.9869268e-01 -1.2006498e+00 1.2821763e+00
+1 6.1912373e-01 1 1 3.1939619e-02 -1.1155335e+00 1.2532758e+00 3.3656223e-01 -1.3485203e+00 8.5044145e-02 -8.7102075e-01 1.3525975e+00
+1 5.1273699e-01 1 1 -4.0316608e-01 2.5338493e-01 -5.7320034e-01 -1.4069422e+00 -1.1306260e+00 -8.7709566e-02 5.7602612e-01 5.4125181e-01
+1 5.7177612e-01 1 1 4.0297224e-01 -1.3591670e+00 1.4864974e+00 2.8952979e-01 1.0619535e+00 -7.2771814e-01 -1.1176277e+00 -1.2330800e+00
+1 1.1123595e+00 1 1 -5.1931503e-01 -9.9970826e-01 -1.5247911e+00 -1.9984226e-01 8.6512483e-01 -5.3859873e-01 -3.8662510e-01 7.1058847e-01
+1 1.1106323e+00 1 1 -7.8324556e-01 -8.5915480e-01 -1.1921158e+00 -3.8631799e-01 8.6228949e-01 -1.3004293e+00 -1.1943890e+00 -1.4748190e+00
+1 3.2761932e-01 1 1 -7.3482684e-01 -1.0549651e+00 1.1873612e+00 8.2554896e-01 3.3254535e-01 -2.5532844e-01 6.8133137e-01 -1.1706359e-01
+1 8.3381957e-01 1 1 -6.3406095e-01 3.5019306e-01 5.8391479e-01 -1.4133207e+00 1.9643535e-01 1.1042135e-01 3.1163019e-02 -8.5081447e-01
+1 9.0983136e-01 1 1 -3.8002411e-01 1.4917696e+00 -4.7963953e-01 -9.9299669e-02 -3.2499064e-01 -8.2965358e-01 -8.8911677e-01 8.9088512e-01
+1 5.9696427e-01 1 1 -2.0740472e-01 -8.7944237e-01 2.5164692e-02 -7.4383603e-01 1.1118591e+00 1.5420034e+00 1.1707765e+00 2.7558116e-01
+1 6.9166327e-01 1 1 1.3167906e+00 4.0550344e-01 -1.1720326e+00 -1.2550099e+00 8.2339893e-01 1.4531213e+00 1.4456742e+00 9.8498494e-01
+1 7.7961207e-01 1 1 -1.2203709e+00 1.1818238e+00 -5.6576537e-01 -2.9756945e-01 1.5025778e-01 -1.3105697e-01 3.6945981e-01 -1.5513766e+00
+1 4.1029571e-01 1 1 6.8549780e-01 -1.3769467e+00 7.8242265e-01 1.6572143e-01 -4.5796647e-01 -4.1803792e-01 -1.4176549e+00 1.2325113e+00
+1 5.6987225e-01 1 1 9.4129226e-01 -1.3723521e+00 -5.2940910e-01 -1.3126691e+00 -1.4049381e-01 -1.3621885e+00 -6.8676610e-01 -8.4536341e-01
+1 6.6740683e-01 1 1 -7.6152340e-01 4.5170205e-01 -7.8828319e-01 1.3759661e+00 1.1981470e+00 -1.5165399e+00 -2.6639200e-01 1.4007784e+00
+1 1.1590186e+00 1 1 -7.5336765e-02 -1.4730068e+00 -5.7939708e-01 5.9932466e-01 -3.5196960e-01 -7.4540026e-01 -4.8073134e-01 -2.1241015e-01
+1 3.3605139e-01 1 1 -1.2316985e-01 -1.0757625e+00 1.0105265e+00 9.0352103e-01 6.5948844e-02 7.2941640e-01 5.2475362e-01 -1.1282066e+00
+1 7.4679095e-01 1 1 1.9383859e-01 -4.7481464e-01 4.6925521e-01 -9.8088887e-01 -5.7999057e-01 8.0690679e-01 1.0834833e+00 8.8514175e-01
+1 2.3484380e-01 1 1 1.3658654e-02 -5.6425073e-01 1.3747468e+00 1.2789322e+00 4.6047269e-01 -5.7302948e-01 1.4320972e+00 1.1362394e+00
+1 4.9365343e-01 1 1 2.2473207e-01 1.1062775e+00 -1.0439894e+00 2.3655373e-01 1.4217560e+00 1.2165988e+00 1.5161193e+00 -9.6559757e-01
+1 5.8200113e-01 1 1 8.7753607e-01 1.2604145e+00 -5.3524240e-01 -1.4977362e+00 4.9897565e-01 -1.2498892e+00 -4.1285552e-02 6.6927042e-01
+1 1.1869200e+00 1 1 -1.0288474e+00 2.7185928e-02 -1.4392991e+00 1.1289146e+00 1.3729316e+00 9.4168875e-01 4.0570932e-01 1.5261662e+00
+1 9.1414081e-01 1 1 -5.1305652e-01 1.3829607e+00 -3.6468028e-02 -1.5522846e+00 -1.3724339e-01 -3.8089626e-01 1.5004215e+00 -8.2795782e-01
+1 9.9882498e-01 1 1 7.3082420e-01 -1.2243229e+00 -3.0757674e-01 -1.4616708e+00 -7.2069317e-01 8.4234469e-01 1.9375510e-02 -1.3732271e+00
+1 1.2177849e+00 1 1 -6.6499379e-01 2.3765415e-01 -1.5223186e+00 9.5342134e-01 1.2911795e+00 1.2706246e+00 -1.0814474e+00 1.4537276e+00
+1 2.4200197e-01 1 1 1.2359741e+00 1.2890127e+00 -4.7800808e-01 -1.1116207e+00 -1.2684361e+00 -1.1592302e+00 1.3681540e+00 6.3329945e-01
+1 6.4189802e-01 1 1 8.0586716e-01 1.3667430e-02 -8.2937843e-01 4.2904582e-02 2.4269017e-01 9.7515599e-01 1.2478897e+00 1.4798611e-01
+1 9.7400840e-01 1 1 8.0346422e-01 3.7223107e-01 -1.1661258e-01 -1.4689983e+00 1.1064632e+00 -2.4213077e-01 8.8759285e-03 -9.3884357e-01
+1 9.2715356e-01 1 1 1.2579646e+00 1.1765876e+00 4.4622917e-01 3.2210844e-01 1.2399292e+00 -1.1293172e+00 1.5228754e+00 1.0759652e+00
+1 3.5599854e-01 1 1 -3.0817959e-01 -1.4173750e+00 7.9207182e-01 7.1243472e-01 1.3052703e+00 1.0685385e+00 4.1111827e-01 7.3917275e-01
+1 4.9834032e-01 1 1 9.1183716e-01 8.7597168e-01 1.4229769e+00 1.2807859e+00 -6.3430370e-02 -1.5592550e+00 1.3025950e+00 1.4190860e+00
+1 4.6749291e-01 1 1 5.5811590e-01 9.5280045e-01 -9.7215858e-01 -2.4752026e-02 -1.0743232e+00 7.6697813e-01 -1.0457073e+00 -3.9232836e-01
+1 3.1159978e-01 1 1 -5.4171534e-01 1.0193987e+00 3.5408396e-01 -1.3170715e+00 -1.4175973e+00 6.4679658e-01 -1.1324789e+00 3.4030454e-01
+1 2.4354668e-01 1 1 -2.7420931e-01 -1.2124178e+00 9.1265239e-01 -3.5965177e-01 2.8091486e-01 7.9952035e-01 1.3372740e+00 -1.3417460e+00
+1 8.0876888e-01 1 1 8.0548871e-02 -7.3528355e-01 -1.4481273e+00 -2.4299214e-01 -4.7773337e-01 9.4680151e-01 6.1075599e-01 -3.7361061e-01
+1 4.7610657e-01 1 1 -2.4155085e-01 1.1149174e+00 -7.5640941e-01 1.0156657e-01 6.4604997e-01 7.2618081e-01 1.3927758e+00 7.7024055e-01
+1 1.8135921e-01 1 1 -8.0750695e-01 -1.1840496e+00 1.0524674e+00 1.1445341e+00 8.1768235e-01 -1.6655540e-01 3.7594478e-01 -1.0704772e+00
+1 1.3972869e+00 1 1 -8.9068510e-02 -1.4738271e+00 -1.4890950e+00 2.1219571e-01 1.4609859e+00 -1.3759410e-01 7.6107824e-01 3.9054090e-01
+1 7.8154796e-01 1 1 1.5652495e+00 8.4528577e-01 -1.2920195e+00 6.6557677e-01 1.0224944e-01 -3.3186188e-01 -1.1232595e+00 1.0337716e+00
+1 7.0742089e-01 1 1 -5.4779250e-01 4.3594354e-01 -2.8347086e-01 -8.6260434e-01 5.5154142e-02 -1.2755870e+00 -7.9179709e-01 -1.5494352e+00
+1 5.9005484e-01 1 1 1.2595582e+00 7.0892459e-01 1.5013101e+00 6.5894437e-01 2.0583774e-01 -5.6189333e-01 5.2721962e-02 -6.9611021e-01
+1 1.2072699e+00 1 1 1.3434367e+00 -1.1653264e+00 -7.5354588e-01 7.6394337e-01 6.2136241e-01 -1.1364897e-01 1.6888784e-01 -2.3331138e-01
+1 1.1463599e+00 1 1 5.1396655e-01 -9.5159055e-01 -1.0856829e+00 -9.2992406e-02 5.8403630e-01 -9.9309572e-03 -1.5018157e+00 -5.5675188e-01
+1 5.4425330e-01 1 1 -1.1440585e+00 4.6579469e-01 -7.0259245e-01 -1.5518162e+00 1.5627262e+00 -4.0518722e-01 -1.4606273e+00 1.4756335e+00
+1 6.7839758e-01 1 1 1.4973731e+00 -2.3756210e-01 7.7550175e-01 1.2660899e-01 1.0239081e+00 9.9131735e-01 -3.5813740e-01 1.2402916e+00
+1 3.8196909e-01 1 1 -9.4971430e-01 2.5804254e-01 -6.0995099e-01 1.0591275e+00 -8.2113726e-01 1.2048172e+00 7.6314057e-02 1.1132355e+00
+1 8.2877420e-01 1 1 5.8401794e-01 1.5230984e+00 -4.2946338e-01 4.9143606e-01 1.6263913e-01 -1.3443872e+00 8.4055630e-01 -1.1771770e+00
+1 5.4708942e-01 1 1 1.2540822e+00 1.0178540e+00 1.3888673e+00 3.1884480e-01 2.9026979e-01 -7.8088973e-01 -5.1238187e-01 9.3660805e-01
+1 5.7459474e-01 1 1 4.1489603e-01 1.1009123e+00 6.5846581e-01 -7.3243909e-01 -3.2906493e-01 1.1604326e+00 -4.9666239e-01 -9.4924179e-01
+1 7.4105644e-01 1 1 -1.1780521e+00 -9.4715979e-01 -9.9607847e-01 -1.3437279e+00 -1.3911848e+00 3.8397849e-01 -1.9306313e-01 -8.9929498e-01
+1 4.3117774e-01 1 1 -1.2042868e+00 -4.6453944e-01 4.5648005e-01 8.7458291e-01 1.2319553e+00 6.9520267e-01 4.5318772e-01 -2.4844682e-01
+1 4.0999148e-01 1 1 8.3335303e-01 -6.5655822e-01 2.9090271e-01 -3.9708507e-01 -7.6369666e-01 6.8824569e-01 1.5054653e+00 -4.6908186e-01
+1 4.3889159e-01 1 1 9.4432946e-01 -1.5005334e+00 8.8371402e-01 -1.0660324e+00 1.0978697e+00 1.1113986e-03 -3.1853431e-02 1.5386719e+00
+1 1.1603264e+00 1 1 1.9178791e-02 1.2411685e+00 -8.6857705e-01 -3.0397678e-01 1.3231266e+00 -1.7027940e-01 -1.2898679e+00 -1.1327245e+00
+1 4.8954518e-01 1 1 -1.2461042e+00 1.4373891e-01 8.0664989e-01 -7.0806723e-01 -1.5455064e+00 1.0496847e-01 1.3210975e+00 3.5127971e-01
+1 3.7044618e-01 1 1 -1.4164645e+00 -6.4941369e-02 1.3924601e+00 -1.3297569e-01 -6.3753213e-01 -1.3699122e+00 -1.0905718e+00 9.0548597e-01
+1 5.7947273e-01 1 1 4.6979392e-01 -1.3369312e+00 1.3536902e+00 -1.2500540e+00 9.7009222e-01 6.1889069e-01 -1.1880339e+00 6.2791268e-01
+1 6.0809648e-01 1 1 1.0040076e+00 -1.1319897e+00 5.7595435e-02 1.3134032e+00 -5.2600165e-01 -1.1743358e-01 6.7762516e-01 7.1870307e-01
+1 4.6775138e-01 1 1 8.6183774e-01 1.3415757e-01 3.9594170e-01 1.5369730e+00 -6.8000206e-02 -7.8601874e-01 5.7268214e-01 -1.8133851e-01
+1 7.2391759e-01 1 1 -9.7679193e-01 -8.7721592e-01 6.9899405e-01 -1.4119739e+00 6.6026445e-01 -2.1978436e-01 -7.7116766e-01 -4.1138975e-01
+1 7.8953152e-01 1 1 1.0212893e+00 1.2631444e-01 -1.5635923e+00 5.4613615e-01 9.5938308e-01 5.9714934e-01 1.1963602e+00 4.1788256e-01
+1 7.1004814e-01 1 1 -8.5242794e-01 -7.4980258e-01 1.2733753e-01 -8.2349032e-01 -1.4437307e+00 -1.0995086e+00 1.0323349e+00 -1.2489789e+00
+1 8.8641436e-01 1 1 -1.0938148e+00 -1.0038165e+00 7.3723900e-01 1.4553931e+00 8.8022017e-01 -5.9250330e-01 -5.6416576e-01 5.3290474e-01
+1 7.7453432e-01 1 1 8.5435732e-01 -7.9201406e-01 3.3446037e-01 3.5087738e-01 1.0051045e-01 6.4574524e-01 -6.0728686e-01 -1.5063573e-01
+1 8.3393573e-01 1 1 -1.0365697e+00 -4.5224712e-01 9.6619651e-01 4.2678024e-01 -8.9771253e-01 -1.1624488e+00 3.6422918e-01 3.8895832e-01
+1 1.2694320e+00 1 1 -1.4960819e+00 -1.4047274e+00 -2.7629029e-02 6.3939840e-01 1.2150523e+00 2.8737322e-01 -1.3641843e+00 -4.3184201e-01
+1 7.3142314e-01 1 1 6.5839994e-01 -1.8530007e-01 5.9463004e-01 -1.0195049e+00 1.0317725e+00 1.2537820e+00 -5.0305644e-01 -8.8965850e-01
+1 3.1703088e-01 1 1 1.0384726e+00 -1.0199112e+00 5.4079050e-01 -5.7303561e-01 -5.9176481e-01 -1.4895064e+00 -8.4372236e-01 1.4906938e+00
+1 1.0046675e-01 1 1 -1.0794796e+00 -1.1176106e+00 4.3832546e-01 1.1136520e+00 4.9117310e-01 1.2184018e+00 7.0745399e-01 -1.1020492e-01
+1 6.7175247e-01 1 1 -1.1634770e-01 -9.9249153e-02 -9.8845559e-02 -4.6046655e-01 -9.5924621e-01 7.7785886e-01 -7.4890785e-01 1.3255991e+00
+1 4.5327272e-01 1 1 -1.3851123e+00 1.0518679e-01 6.0520968e-01 -1.3186370e+00 6.0239952e-01 1.3068715e+00 1.4674574e+00 -8.3034138e-01
+1 6.3800059e-01 1 1 -3.8120445e-01 -8.4232279e-01 -7.1789593e-01 -1.5373239e+00 -8.2439490e-01 -1.4263152e+00 -1.0878210e+00 -5.9299466e-01
+1 2.0425331e-01 1 1 -1.1956895e+00 -9.0270078e-01 1.1804992e+00 -1.3455328e+00 -1.1814761e+00 1.4143860e+00 1.0615935e+00 -1.3294152e+00
+1 5.2683207e-01 1 1 8.1489385e-01 -9.4104455e-01 1.4916334e+00 -1.1864563e+00 9.3884257e-01 -8.4554002e-01 1.0979745e+00 -4.7363496e-01
+1 6.2206953e-01 1 1 -1.4230913e+00 -1.3583005e+00 -2.7022361e-02 -1.0832291e+00 -1.0928566e+00 -1.5676174e+00 -5.7427837e-02 4.1299437e-01
+1 4.3583696e-01 1 1 -9.4982786e-01 9.9791660e-01 1.3661168e+00 -3.0211985e-01 1.2511504e+00 -1.5495497e+00 -7.2071903e-01 1.4182120e+00
+1 3.9398471e-01 1 1 -1.3245193e+00 -9.7887796e-01 1.5653569e+00 -9.1459256e-01 1.4056571e+00 5.2130773e-01 8.5659959e-01 6.2499044e-01
+1 6.1578314e-01 1 1 1.3024331e-01 5.1879588e-01 1.2560767e+00 2.5563725e-01 1.0128923e-01 -2.8283009e-01 -1.0497983e+00 -1.2714508e+00
+1 7.9279249e-01 1 1 -6.9070816e-01 1.4827165e+00 -6.2110939e-01 -1.2034565e+00 -3.7515141e-01 -2.9571588e-01 -7.7540512e-01 -1.6037623e-01
+1 7.8799094e-01 1 1 -5.4718978e-01 9.0316546e-01 5.2683673e-01 -9.1946919e-01 6.6916601e-03 -9.7280852e-02 -9.0755452e-01 4.3206664e-02
+1 6.2693868e-01 1 1 -1.1768596e+00 -6.7376106e-01 1.5368022e+00 -2.4402166e-02 -6.3060369e-01 -1.3711028e+00 -8.3641622e-01 4.6650698e-01
+1 9.9877025e-01 1 1 -1.1485151e-02 1.5393792e+00 -1.1404771e+00 1.4214292e+00 1.1773569e+00 -5.4226714e-01 9.7974366e-01 -8.3246755e-01
+1 4.9842317e-01 1 1 -1.3937833e+00 1.3311282e+00 -1.1426199e+00 1.2900300e+00 -1.0552212e+00 -1.2355070e-01 1.4646667e+00 1.3715284e+00
+1 7.1720720e-01 1 1 1.5399689e+00 9.9098742e-01 5.4352613e-01 1.4032451e+00 -8.1157561e-01 7.6196832e-02 -8.6657175e-01 1.4117629e+00
+1 1.2968801e+00 1 1 -1.3243621e+00 -1.1986575e+00 -7.0774916e-01 4.0425826e-01 6.4406746e-01 -1.1296458e+00 -4.7778586e-02 -9.5103507e-01
+1 5.0227796e-01 1 1 -3.6925111e-01 1.1965054e+00 -1.0703488e+00 -8.9636518e-01 -1.0865106e+00 -1.3119225e+00 1.2330193e+00 3.7707139e-01
+1 8.8717329e-01 1 1 -1.3578622e+00 3.3156910e-01 -5.9354391e-01 -1.2727449e+00 1.0944868e+00 1.3566485e+00 1.4096738e+00 8.4651868e-01
+1 1.2664289e+00 1 1 -1.0601728e+00 -5.0351873e-01 -1.1359009e+00 8.1419381e-02 1.0154425e+00 -4.8749683e-01 -1.5039816e+00 -8.3367348e-01
+1 9.4609355e-01 1 1 7.8938859e-01 8.1128342e-01 3.7138886e-01 -1.3188626e+00 1.4108150e+00 -8.5598793e-02 -1.6404191e-01 -4.6935196e-02
+1 6.3034602e-01 1 1 3.0832219e-01 7.2832816e-01 -4.1202808e-01 9.5440688e-01 -1.1741437e+00 1.9052136e-01 1.2660389e+00 -3.0009116e-01
+1 9.5944414e-01 1 1 1.4846835e+00 1.3664641e+00 -8.8577091e-01 -2.5566040e-01 -1.4904467e+00 8.0964766e-01 3.0833977e-01 -1.3759199e+00
+1 7.1611737e-01 1 1 -5.9515429e-01 1.1190897e+00 8.5583731e-01 8.1441219e-01 1.1215241e+00 1.5104618e+00 -1.3614440e+00 1.7837051e-01
+1 8.4684966e-01 1 1 7.2846302e-02 -1.7412065e-01 -1.2951626e+00 -9.3448735e-02 -1.0004399e-01 -8.7894753e-01 -1.5703043e+00 7.9368974e-01
+1 8.5709691e-01 1 1 -8.9333665e-01 1.5185282e+00 2.9794094e-01 2.0343182e-01 -6.8721955e-01 -7.0241113e-01 4.1577256e-01 3.4107535e-01
+1 2.3245408e-01 1 1 -6.3777139e-01 -3.9453554e-01 -2.0524146e-01 1.0257539e+00 1.5371455e+00 6.8130380e-01 9.8733169e-01 -9.5323469e-01
+1 9.6871314e-01 1 1 9.0413227e-02 9.4333240e-01 -2.4445257e-02 -1.2146241e+00 1.4872334e+00 -4.3233150e-01 1.9126972e-01 1.1071662e+00
+1 6.3472085e-01 1 1 -9.5573572e-01 -1.0305291e+00 6.9721133e-01 -1.1897857e-01 1.4204065e+00 3.0831922e-01 8.2096579e-01 4.8948467e-01
+1 5.6077139e-01 1 1 -8.7007846e-02 -5.0264336e-01 -1.0970585e-01 1.5216563e+00 -1.9025009e-01 1.4348943e+00 9.7178638e-02 -1.0622787e+00
+1 1.0342999e+00 1 1 -1.5002912e+00 -1.8430024e-01 2.8871718e-01 -1.2286552e+00 6.0812360e-01 1.4028327e+00 -3.4680937e-01 -4.6803211e-02
+1 1.2851845e+00 1 1 -9.7095596e-01 7.6266666e-02 -1.2910576e+00 -3.2013545e-01 1.1325039e+00 -2.4375538e-01 -1.1707100e+00 -1.2233963e+00
+1 8.8171713e-01 1 1 -1.4245140e+00 4.4051880e-02 1.7498711e-01 1.0316705e+00 -9.1638924e-01 -1.5982863e-01 -3.2840437e-01 1.0309189e-01
+1 4.6940733e-01 1 1 2.7066795e-01 -1.0359185e+00 4.7764596e-01 8.3702985e-01 1.4748136e+00 -1.7801740e-01 2.8597385e-01 -1.4936675e+00
+1 7.1533296e-01 1 1 9.0116395e-02 2.3546061e-02 1.0265028e+00 -9.1270733e-02 2.6926683e-02 -1.1421979e+00 -2.7426284e-01 3.9644247e-01
+1 1.0885030e+00 1 1 3.3859534e-01 -1.0203127e-01 -1.1939383e+00 -8.8998902e-01 1.6741964e-01 1.3522421e+00 -8.1917289e-01 -3.0946504e-01
+1 5.9147887e-01 1 1 1.3475521e+00 4.6997650e-01 -1.1681597e+00 -9.2281246e-01 -1.0451724e+00 8.5216607e-01 -1.3796918e+00 1.2985009e+00
+1 3.5399707e-01 1 1 5.6595110e-01 9.3105305e-01 -1.4471092e+00 3.3393354e-01 -1.5679810e+00 -1.6581115e-01 -3.8513579e-01 -7.3908656e-01
+1 8.7695058e-01 1 1 -8.0246542e-01 -6.4344625e-02 6.4573234e-01 1.5365106e+00 -1.3767175e+00 -1.9534159e-01 -1.2963118e+00 2.9620151e-02
+1 1.0343917e+00 1 1 -1.7899780e-01 -7.3224447e-01 -1.3791118e+00 2.4123705e-01 -6.6148926e-01 -1.4182346e-01 -1.6739731e-01 1.4542344e+00
+1 8.7710432e-01 1 1 1.2296620e+00 -1.2143785e+00 -6.1309377e-02 -1.3250407e+00 4.4647197e-01 8.4195578e-01 1.4203986e+00 -2.7373717e-01
+1 4.5769511e-01 1 1 1.5327094e+00 8.6863851e-01 1.5682899e-02 7.9177610e-01 -1.4104636e+00 1.0174332e+00 -3.2267709e-01 -1.4089600e+00
+1 9.9520124e-01 1 1 -8.1283434e-01 2.2631025e-01 -3.1129134e-01 -4.0552462e-01 7.9637672e-01 3.1181697e-01 -8.4494763e-01 9.3405680e-01
+1 1.3133337e+00 1 1 1.4797193e+00 -8.7235228e-01 -1.1217583e+00 -1.5377491e+00 1.5188210e+00 5.3133184e-01 -1.0360286e+00 1.5407142e-01
+1 1.0705313e+00 1 1 7.9416274e-01 1.8819107e-01 -6.9350582e-01 9.3391570e-01 1.3838817e+00 -1.4537521e+00 1.3153651e+00 8.0605556e-01
+1 1.2240479e+00 1 1 -1.1340008e+00 -6.5656405e-01 -4.4349222e-01 9.2422245e-01 -1.4519479e+00 -1.0459475e+00 -4.6787544e-02 8.2834239e-01
+1 6.5319334e-01 1 1 8.9053204e-01 1.5429807e+00 1.2255502e+00 1.3725903e+00 1.0033144e+00 1.1127400e+00 -9.6009124e-01 1.5534188e+00
+1 4.5614122e-01 1 1 6.2463026e-01 -9.7125698e-01 1.5402752e+00 4.0948731e-01 -1.3634447e+00 -7.9416975e-02 -1.0336204e+00 -1.4661113e+00
+1 5.7956823e-01 1 1 -1.0418712e+00 -2.0067464e-01 6.8190537e-01 -9.7626702e-01 -6.3896684e-01 4.1577590e-01 9.4859209e-01 -1.4216130e+00
+1 3.8355147e-01 1 1 5.0790040e-01 1.3318854e+00 2.5354238e-01 4.1869222e-01 -1.1520301e+00 1.0435382e+00 -5.9547530e-01 -1.2367698e+00
+1 5.6563165e-01 1 1 5.7485111e-01 1.1496079e+00 1.2870865e+00 -2.0745445e-01 -5.3436879e-01 -7.6571062e-01 9.6082365e-01 1.5280013e+00
+1 8.8799247e-01 1 1 1.1252024e+00 6.6439100e-01 -9.4465346e-01 4.8094657e-01 6.7720518e-01 -1.3349002e+00 7.7676529e-01 -1.4023578e+00
+1 6.5268067e-01 1 1 -1.1113028e+00 1.1992389e+00 8.1849301e-01 -4.8895856e-02 -2.0266894e-01 -1.5546658e+00 -1.3649074e+00 -1.1994557e+00
+1 9.3488319e-01 1 1 -8.9766492e-01 -8.5005870e-01 -6.2221536e-01 1.3046177e+00 -7.7040717e-01 -6.4241840e-01 -8.8965727e-02 3.4789257e-01
+1 6.1941854e-01 1 1 -1.1263724e+00 1.0268115e+00 7.8832259e-01 1.5343158e+00 1.4115559e+00 5.2794896e-01 1.5113348e-01 5.2642504e-01
+1 5.4180445e-01 1 1 2.9594024e-01 8.5252934e-01 1.2415321e+00 1.0535763e+00 -1.2878027e+00 1.3805990e+00 -1.4479934e+00 9.0068878e-01
+1 2.2353621e-01 1 1 7.2646479e-01 -3.4341326e-01 -2.8355653e-02 1.4403585e+00 1.4738372e+00 -7.6117445e-02 1.4930794e+00 -1.4586064e+00
+1 4.2508483e-01 1 1 1.4647317e+00 -6.4092915e-01 9.4862947e-01 -1.0082451e+00 -6.7693677e-01 -6.7769441e-01 -8.5687572e-01 -9.4960509e-01
+1 4.7986385e-01 1 1 2.2505361e-01 4.2499349e-01 3.2852236e-02 1.7483215e-01 -1.5693189e+00 1.4049494e+00 -4.4945518e-01 -7.2198792e-01
+1 6.2768765e-01 1 1 -1.5406875e-03 -1.1161687e+00 -7.7278258e-01 1.0148327e+00 1.2691512e+00 7.7465264e-01 1.5372036e+00 1.5214683e+00
+1 6.1541677e-01 1 1 -7.6159420e-01 -9.9728299e-01 -8.1285328e-01 5.8602305e-01 -7.9046184e-01 8.2697406e-01 -6.7758102e-01 -1.2472145e+00
+1 3.5527249e-01 1 1 -1.2652128e+00 -9.3845349e-01 1.1613142e+00 3.9648199e-01 5.0320536e-01 5.4711575e-01 1.6914021e-01 -1.2275357e+00
+1 9.6321989e-01 1 1 1.0086850e+00 1.3488755e+00 -5.0757645e-01 3.5480908e-01 2.0508862e-01 -6.7354344e-02 -4.0188397e-01 -3.5330398e-01
+1 9.5794219e-01 1 1 9.3537288e-01 8.1789234e-01 -1.4133589e+00 5.3327890e-01 5.9723431e-01 -1.0510995e+00 -3.9701318e-02 -3.6983137e-01
+1 4.9727774e-01 1 1 2.8231414e-01 -1.2929189e+00 -7.4060928e-01 -1.4535777e-01 3.2854432e-01 -6.5366912e-01 -1.2424123e+00 1.4559947e+00
+1 3.4780637e-01 1 1 1.0488116e+00 3.0848827e-01 -4.3007932e-01 1.1311071e+00 -1.0754505e+00 -6.7428579e-02 9.4216207e-01 1.0380052e+00
+1 3.5994579e-01 1 1 -9.9069359e-02 1.1344583e+00 4.6149727e-01 7.3937491e-01 -1.5134136e+00 8.4281244e-01 1.2909311e+00 4.8954451e-01
+1 1.0951096e+00 1 1 -1.4606512e-02 5.1555612e-01 -2.0769150e-01 -1.4664836e+00 1.5340186e+00 -2.9257234e-01 8.3936462e-01 -5.6659580e-02
+1 9.1700504e-01 1 1 -4.4742276e-01 4.3922977e-01 -3.6160565e-01 -1.3951488e+00 -7.9988131e-01 -6.7084932e-01 1.4501780e+00 -3.7498951e-01
+1 3.8260758e-01 1 1 1.1384017e+00 -6.0799478e-01 1.4756295e+00 5.8237319e-01 -7.3013024e-01 2.1152682e-01 6.6598099e-01 -4.1387764e-01
+1 4.6805444e-01 1 1 8.1781859e-01 1.0326014e+00 1.1726274e+00 -1.2565147e+00 -2.3803925e-01 -1.1516801e+00 -3.5208269e-01 -5.5539953e-01
+1 3.0261404e-01 1 1 6.0910683e-01 7.7359855e-01 1.1383903e+00 -4.5696008e-01 -1.4782772e+00 -9.3446105e-01 1.3068722e+00 -9.2814896e-01
+1 1.0133572e+00 1 1 -1.1919026e+00 -1.1811946e+00 6.2657884e-01 1.0659333e+00 1.4518794e+00 -6.6513400e-01 -1.4145133e+00 -1.3920008e+00
+1 4.4299884e-01 1 1 -1.5117632e+00 -6.1340889e-01 2.9206931e-01 -1.3615891e+00 9.8670910e-01 -1.1204447e+00 -1.2932323e+00 8.2615689e-02
+1 4.7539722e-01 1 1 9.9810186e-01 1.1438561e+00 -1.5003945e+00 -8.6683392e-01 -8.4775103e-01 -6.0809411e-01 1.3239014e+00 -6.2060289e-02
+1 5.1204713e-01 1 1 -1.0067641e+00 1.3845576e+00 4.3374318e-01 -1.3125679e+00 -1.0288115e+00 -6.3687386e-01 -1.0898964e+00 -3.8515423e-02
+1 6.4127661e-01 1 1 -6.5689070e-02 4.8354909e-01 1.4267012e+00 -6.4974630e-02 9.1495127e-02 -5.3272255e-01 7.3839042e-01 -1.6062220e-01
+1 9.1014799e-01 1 1 -1.3371851e+00 -2.9072051e-01 -1.2095578e+00 1.2456454e+00 1.5197876e+00 7.1116369e-02 8.3675328e-01 -9.4918034e-01
+1 6.0102153e-01 1 1 8.8449389e-01 -9.6301209e-01 2.0755121e-01 -1.0916208e-02 -1.2189755e+00 1.4476091e+00 1.5437415e+00 1.3346847e-01
+1 6.5113447e-01 1 1 -3.2762466e-01 1.4110248e-01 1.1454026e+00 -1.2563284e+00 -9.9630426e-01 1.4724030e+00 -7.5104545e-01 1.0734849e-01
+1 9.4149521e-01 1 1 8.2434458e-01 -3.9300033e-01 -8.9818589e-01 -4.6692207e-01 -1.9682400e-01 3.5175379e-01 9.8361207e-02 9.3192231e-01
+1 9.0029219e-01 1 1 3.3572336e-01 -1.5287085e+00 -4.5751263e-01 1.3916417e-01 7.6102067e-02 -5.5142023e-01 6.7906933e-01 -1.1626539e+00
+1 7.0699519e-01 1 1 2.0206906e-01 -1.0587411e+00 1.2039787e+00 -1.5542399e+00 4.1923309e-01 -2.1408606e-02 -2.8780695e-01 -1.7332597e-02
+1 3.0971474e-01 1 1 1.1307911e-01 -2.8146913e-01 2.7118894e-01 2.3273239e-01 -5.4173075e-01 1.4687179e+00 8.8131471e-01 8.5915751e-01
+1 7.0902106e-01 1 1 -1.4291562e-01 5.8693786e-01 -5.7849753e-01 2.5035784e-01 -5.3321155e-01 1.2480917e+00 -3.5305112e-01 1.1004516e+00
+1 6.1484457e-01 1 1 1.3355946e+00 6.3648039e-02 4.2134575e-01 1.1716952e+00 1.2773062e+00 2.6339914e-01 7.3838624e-01 7.3336758e-01
+1 4.2542226e-01 1 1 6.5868932e-01 -1.5504985e+00 4.0812798e-01 1.1786604e+00 1.1832745e+00 4.4526912e-01 7.6650747e-01 1.2409324e+00
+1 7.2007714e-01 1 1 -3.8105679e-01 2.8359422e-01 1.3101359e+00 -1.1379372e+00 1.0130784e+00 3.6439710e-01 -9.8040485e-01 -6.8273324e-01
+1 4.2585315e-01 1 1 1.2859768e+00 5.7201096e-01 3.0655569e-02 7.0596881e-01 -6.2338713e-01 1.4580156e+00 -1.0903537e-02 1.5403652e+00
+1 8.8917498e-01 1 1 -7.4468494e-01 5.1473826e-01 6.9539365e-03 -5.7759978e-01 -5.6028344e-02 4.4550485e-01 -1.0433781e+00 -9.4779182e-01
+1 6.3732451e-01 1 1 1.8535741e-01 -7.4022928e-01 6.3588214e-01 -1.9822488e-01 8.0941573e-01 1.1847962e+00 3.1465311e-01 1.4791742e+00
+1 1.0691382e+00 1 1 -1.1579099e+00 -3.2667359e-01 -4.2714350e-01 -1.4773414e+00 7.5398958e-01 1.4554439e+00 1.0744023e+00 1.0573327e+00
+1 5.2453302e-01 1 1 1.1748493e+00 1.1009551e+00 -4.6152584e-01 1.4711596e+00 -8.8187617e-01 1.2045718e+00 -3.9564382e-01 -1.3993610e+00
+1 3.9698919e-01 1 1 7.8229235e-01 -2.2763809e-01 -2.7247318e-01 1.4459653e+00 3.4128626e-01 8.1489925e-01 1.1659212e+00 -1.0972637e+00
+1 6.7108798e-01 1 1 4.2219594e-01 5.4652631e-01 9.8532285e-01 -1.0226056e+00 -5.4993394e-01 -1.3322905e+00 1.5243138e+00 -5.6149937e-01
+1 3.4050470e-01 1 1 -1.0106763e+00 -5.4927686e-01 9.8631996e-01 7.2069383e-01 -1.7415329e-01 1.4662190e+00 -5.4543325e-01 2.2439303e-01
+1 1.0836962e+00 1 1 1.5558508e-01 1.4445860e+00 -1.1048517e+00 -1.2800906e+00 9.6993720e-01 9.0626433e-02 7.0660872e-02 1.4624016e+00
+1 6.3839964e-01 1 1 1.1134123e+00 9.2837780e-01 7.1081578e-01 -8.5671799e-01 1.0324492e-02 -5.1398049e-01 7.5254647e-02 -1.2369537e+00
+1 1.2254775e+00 1 1 -1.3460711e+00 -1.0449496e+00 -7.9606714e-01 -9.4012277e-01 7.3614808e-01 9.0964353e-01 -1.2569870e+00 -1.5619294e+00
+1 4.4807241e-01 1 1 -8.0780003e-01 -9.6453988e-01 5.4262027e-01 1.5676903e+00 8.4894918e-01 1.3888956e+00 1.0293033e+00 -1.9884987e-01
+1 6.8820976e-01 1 1 1.2683289e+00 -4.0364434e-01 -2.2451491e-01 -3.6649077e-01 -8.2497435e-01 1.1346228e+00 -1.2500349e+00 5.8480903e-01
+1 8.0366147e-01 1 1 1.0973445e+00 -1.3518371e+00 -3.6937064e-01 1.0527873e+00 -1.4954922e+00 1.3742444e-01 -1.5060472e+00 -1.1581212e+00
+1 1.2222701e+00 1 1 -1.2221141e+00 -3.2794931e-01 -2.2524568e-01 7.4553898e-01 1.1460513e+00 6.2194657e-01 -3.2253495e-01 7.6436907e-01
+1 9.4721818e-01 1 1 -3.3881946e-01 -1.4904684e+00 -8.5002334e-02 -1.5395217e+00 5.7949624e-01 9.7719880e-01 1.5440493e+00 7.7859322e-01
+1 7.6312397e-01 1 1 1.1688398e+00 7.5687040e-01 7.9043816e-01 -5.8460557e-01 6.5612119e-01 -4.6616638e-01 1.2813582e+00 1.0829141e+00
+1 8.9047332e-01 1 1 3.1155441e-01 4.1223683e-01 -9.0112564e-01 1.4359532e+00 4.3856857e-01 2.7371368e-01 1.7033547e-01 1.2912984e+00
+1 4.2365187e-01 1 1 -7.3994851e-01 1.2526087e+00 3.9946908e-01 3.5030078e-01 8.4562087e-01 1.0141132e+00 8.3731384e-01 7.2969713e-01
+1 5.3836655e-01 1 1 1.2507182e+00 7.8282846e-01 2.9329912e-01 1.6066014e-01 -2.1518469e-01 1.0597871e+00 1.5401639e+00 -7.5813004e-01
+1 3.7010441e-01 1 1 4.2426470e-01 7.8635029e-03 3.1945613e-01 -1.5547908e+00 -6.3598109e-01 -9.8932393e-01 -1.1895051e+00 4.0814628e-01
+1 5.9230390e-01 1 1 -7.9853381e-01 2.1500119e-01 1.1735808e-01 3.9890556e-01 -1.2359391e+00 8.8264926e-01 1.0839629e+00 -1.5238209e+00
+1 7.5992402e-01 1 1 -7.3876027e-02 6.9347026e-01 -4.8297914e-01 2.4708751e-01 -2.1702677e-01 8.5654982e-02 6.8499658e-02 -5.9513320e-01
+1 4.7874549e-01 1 1 -7.0528194e-01 -1.5407664e-01 4.4496856e-01 -3.8568992e-01 -1.7989502e-01 7.5385087e-01 1.4508389e+00 4.2727172e-01
+1 8.1251205e-01 1 1 -4.4441104e-01 -8.9380751e-01 -1.5455620e+00 -1.1848453e+00 -1.2835332e+00 -7.1672496e-02 -7.9233083e-01 -5.2509146e-01
+1 5.8686165e-01 1 1 1.4910396e+00 8.7325138e-01 1.5688348e+00 8.6109856e-01 9.7422688e-01 -1.3696550e+00 5.0703329e-01 -4.7843156e-01
+1 5.4164679e-01 1 1 -5.8194447e-01 -7.8496930e-01 1.8668415e-02 -8.3392333e-01 -1.4978485e-01 -1.3424191e+00 -1.4323874e+00 1.4779029e+00
+1 1.0537976e+00 1 1 -9.6271961e-01 -1.4314450e+00 -3.9920801e-01 -1.1045276e+00 -1.0181916e+00 8.8092197e-01 -1.0996534e-01 -1.4592473e+00
+1 6.3992644e-01 1 1 -1.2263265e+00 1.9613381e-02 9.5280387e-01 -1.2486445e-01 -4.9025474e-01 -6.7066110e-01 -9.3105285e-01 8.4501133e-01
+1 4.2523438e-01 1 1 1.1197433e+00 -2.2512634e-01 1.0768100e+00 -1.2976720e-02 6.8608555e-01 2.3335616e-01 6.7762255e-02 -1.0348870e+00
+1 1.0886460e+00 1 1 1.3856584e+00 -1.2208643e+00 -7.7028473e-01 -1.3298478e+00 1.3948165e+00 1.3093189e+00 -1.5179133e+00 -1.4896528e+00
+1 8.0972274e-01 1 1 1.3357366e-01 -1.3250928e+00 3.2791725e-01 -1.4625264e+00 1.1640516e-01 -1.1343953e+00 1.3059238e+00 -1.2432751e+00
+1 1.8407744e-01 1 1 -1.2662232e+00 -8.5054912e-02 9.5173689e-01 -8.6075794e-01 -7.9076636e-01 5.4319606e-01 1.4949963e+00 -9.9195388e-01
+1 6.4909031e-01 1 1 -2.6417689e-01 -9.3252698e-02 -1.1479233e+00 2.7553826e-01 -1.4732623e+00 2.7910081e-02 -5.4634776e-02 6.6329060e-01
+1 1.1708466e+00 1 1 -9.5056998e-01 3.5663091e-01 -6.2653937e-01 2.6396342e-01 9.1369968e-01 9.8743333e-01 -9.0162059e-01 1.5544022e+00
+1 6.3788051e-01 1 1 -1.2309727e+00 -2.6304573e-01 3.7146719e-01 5.0436446e-01 4.4561227e-01 -1.2420490e+00 1.5057609e+00 -6.4590092e-01
+1 4.7143299e-01 1 1 1.5707529e+00 -7.8863856e-01 9.0439863e-01 8.3644008e-01 -1.5152576e-01 7.6581391e-01 -1.3471574e+00 -1.4541770e+00
+1 5.6746585e-01 1 1 8.4023495e-01 -2.6890081e-01 1.2024928e+00 -5.7870080e-01 1.1382022e+00 -7.0659484e-02 -2.1659896e-01 1.2379021e+00
+1 4.8807251e-01 1 1 3.6976829e-01 1.3359322e+00 4.3032631e-01 1.4653804e-01 6.0632309e-01 -5.1921333e-02 7.2719462e-01 -1.3467689e+00
+1 3.6856726e-01 1 1 6.2537052e-01 4.9359445e-02 5.4805165e-01 -1.4373202e-01 -8.5442931e-01 7.2090865e-01 1.1644800e+00 3.0740622e-02
+1 7.0870211e-01 1 1 -1.1666928e+00 2.0372891e-01 -4.5566185e-02 1.8067362e-01 -1.7344331e-01 -8.1111730e-01 -7.0709887e-01 1.4364329e+00
+1 6.1182829e-01 1 1 1.2160313e+00 -2.6417603e-01 7.1774336e-01 -1.3385472e+00 3.3630681e-01 -1.0779632e+00 4.3433010e-01 -1.0119936e+00
+1 1.1836339e+00 1 1 -1.3644043e+00 -9.3618643e-01 -6.0313687e-01 -1.7042871e-02 5.8340508e-01 2.3718397e-01 -1.2753574e+00 5.8530994e-03
+1 8.3992379e-01 1 1 -1.0577164e+00 -1.3892899e+00 9.9819428e-01 -5.5459389e-01 3.7856678e-01 -3.3007493e-01 1.5531302e-01 9.8366929e-01
+1 7.2207454e-01 1 1 1.2336019e+00 -1.4793771e+00 5.4646258e-01 4.5908092e-02 8.4682971e-01 4.8334857e-01 -3.1758686e-01 1.4692758e+00
+1 5.4787674e-01 1 1 -1.3637862e+00 -1.3264361e+00 1.5212946e+00 -1.2544916e+00 1.2522321e+00 -5.1915663e-01 -1.1648984e-01 1.1993719e+00
+1 5.9972332e-01 1 1 -9.4301469e-02 -6.7062074e-01 -1.0248677e+00 -1.0126041e+00 7.3575214e-01 -1.2627014e+00 -6.3246743e-01 1.3851203e+00
+1 9.1439224e-01 1 1 -1.5620893e+00 9.1164501e-01 4.0110918e-01 -8.3017520e-01 4.7761603e-01 -7.6330342e-01 1.2694777e+00 5.1550008e-01
+1 2.1496979e-01 1 1 2.5552692e-01 4.7039269e-01 -4.1583492e-01 -9.4157246e-01 5.2332446e-01 1.4238394e+00 1.5553557e+00 -5.0265915e-01
+1 6.1561997e-01 1 1 8.3789302e-02 -1.4987466e+00 1.1062042e+00 -8.0608265e-01 -9.4523204e-01 9.5745790e-01 -3.2901642e-01 -4.4962141e-01
+1 8.2579812e-01 1 1 8.1329518e-01 -1.4421780e-01 2.9403942e-02 -1.2836002e+00 5.1913093e-01 7.5736685e-01 -5.7587107e-01 -1.2566227e+00
+1 8.2433557e-01 1 1 -1.7473783e-02 1.4409309e+00 9.6200149e-01 -1.5127973e-01 8.3070312e-01 -6.6875469e-01 5.8181791e-01 8.7019082e-01
+1 1.1337026e+00 1 1 -1.5137594e+00 -8.1246919e-01 -1.4182918e+00 -1.0099216e+00 3.8964969e-01 8.5851962e-01 -1.1643000e+00 1.1833855e+00
+1 3.4095332e-01 1 1 -1.1361541e+00 1.3335151e+00 1.1753669e+00 2.7228423e-01 -1.3783208e+00 -1.9575198e-01 5.9010852e-01 -2.6315228e-01
+1 7.8097023e-01 1 1 -7.4206584e-01 2.6612553e-01 5.7717811e-02 -1.0194212e+00 6.6731760e-01 -7.5595585e-01 -5.4170899e-02 5.6216529e-01
+1 1.0039834e+00 1 1 2.2232775e-01 -8.5622159e-01 -6.8887713e-01 8.3355260e-01 1.2114393e-01 -7.4920144e-01 6.1156970e-01 1.5429763e+00
+1 8.1830099e-01 1 1 1.3087769e+00 1.1196424e+00 -1.1889343e+00 1.1569560e+00 3.1405699e-01 -3.2529426e-01 -6.3918563e-01 -1.0455105e+00
+1 6.4726997e-01 1 1 -8.1919876e-01 -3.1012526e-01 1.2525699e+00 -1.4994788e+00 4.8009137e-01 -8.4933984e-01 1.4539332e+00 -9.6760084e-01
+1 6.4783574e-01 1 1 1.3270013e+00 -3.7300261e-01 1.2996283e-01 1.1627627e-01 1.2856478e+00 5.4230287e-01 9.4683210e-01 1.5578506e+00
+1 4.0950641e-01 1 1 7.4459137e-01 1.5641263e+00 8.7843475e-01 1.8463915e-01 8.7263071e-03 7.2404545e-01 1.2402513e+00 7.6194032e-01
+1 6.4451593e-01 1 1 1.3836584e+00 -5.7707562e-01 1.5089596e+00 -6.6339424e-01 -9.9181165e-01 -1.4980822e+00 4.3686443e-01 7.9930046e-01
+1 9.4079900e-01 1 1 1.0781391e+00 -8.1348444e-01 -9.9341722e-01 -1.5474350e-01 -8.7829881e-02 -1.5445283e+00 4.7839825e-01 3.9265790e-01
+1 1.5098574e-01 1 1 -4.2338747e-01 -2.1714167e-02 1.2016619e+00 4.6470461e-01 3.9174415e-01 9.3524842e-02 1.1037148e+00 -1.0848644e+00
+1 7.9643726e-01 1 1 -1.6587320e-01 -5.2525591e-01 -9.6692673e-01 2.9096604e-01 -7.3435218e-01 1.0756960e+00 -9.6959643e-01 4.8820133e-01
+1 8.2285094e-01 1 1 -1.2381858e+00 -1.0074245e-01 3.2129132e-01 -1.1935943e+00 1.0604358e+00 -6.4282404e-01 -5.6607872e-01 -6.4018467e-01
+1 1.0106128e+00 1 1 -2.7925653e-01 1.4008472e-01 -4.5455859e-01 1.4709594e+00 4.8985802e-01 -6.5698605e-03 -1.3425275e+00 3.7115537e-01
+1 6.1165172e-01 1 1 7.4981232e-02 1.3509746e+00 5.8714076e-01 1.2212664e+00 -1.0705237e+00 -4.6390252e-01 -9.4141229e-01 -1.1947103e+00
+1 3.9997031e-01 1 1 4.3091235e-01 1.5404664e+00 3.3230893e-01 -1.3419493e+00 -3.9096530e-01 6.2329479e-01 -1.2557633e+00 1.5639979e+00
+1 6.5115714e-01 1 1 9.7278419e-01 7.5364686e-01 -6.3561811e-01 -6.4863960e-01 1.2580935e+00 -1.4960181e+00 -3.9391035e-01 4.0641909e-01
+1 1.1948948e+00 1 1 7.3575866e-01 -3.5884759e-01 -1.4185570e+00 -3.5917014e-01 -1.2829212e+00 -1.4105241e+00 -1.1154496e+00 8.6325051e-01
+1 1.0340469e+00 1 1 5.8717688e-01 7.0640388e-01 -1.4019506e-01 1.5685646e+00 -1.3069715e+00 -2.2104427e-01 -1.4778823e+00 7.7642308e-01
+1 7.9983459e-01 1 1 9.3922095e-01 4.5144269e-01 -6.3851787e-02 -1.3803182e+00 -2.5417516e-01 1.4130330e+00 -1.3355174e+00 -8.3322409e-01
+1 5.7750337e-01 1 1 -1.0164969e+00 4.5100406e-01 1.2676999e+00 -1.4874933e+00 6.4416137e-01 1.5465143e+00 6.3794464e-01 1.2227182e+00
+1 8.1031506e-01 1 1 -2.8201337e-01 -6.3785922e-01 -4.9368506e-02 4.9394158e-01 4.9191800e-01 -1.2711775e+00 -3.2016077e-01 1.0679177e+00
+1 1.0551291e+00 1 1 8.6466345e-01 -1.3858553e+00 -3.5602243e-01 -1.5532138e+00 -1.0060278e+00 1.2914484e+00 6.0611418e-01 5.7469024e-01
+1 2.6795286e-01 1 1 -6.0895493e-01 -3.0189392e-01 1.0650944e+00 -1.3711689e+00 -2.5731422e-01 1.0955300e-01 -1.2239717e+00 1.5631057e+00
+1 7.1997022e-01 1 1 6.0342684e-01 -2.5902649e-01 2.4702883e-01 1.4876124e+00 1.2930652e+00 2.8397353e-01 -1.4441565e-01 1.1198639e+00
+1 8.6795549e-01 1 1 7.3385140e-01 7.8923575e-01 -1.3719097e+00 1.5066503e+00 -9.9086276e-01 6.6386068e-01 1.2573419e+00 2.7086765e-01
+1 9.3375119e-01 1 1 -5.2320964e-02 8.8111124e-01 -1.5373955e+00 1.0355040e+00 1.5224401e-01 -1.4305820e+00 -1.3480117e+00 3.0475906e-01
+1 7.2688344e-01 1 1 2.8749266e-01 -6.3115351e-01 5.9381636e-01 -7.0777674e-01 1.5086535e+00 -1.1827246e+00 1.1331642e+00 1.2895394e+00
+1 1.0372928e+00 1 1 1.1961653e-01 1.3612821e+00 -5.6827522e-01 -1.5338434e+00 1.4571902e-01 -1.1953071e+00 7.5671247e-01 -5.5846607e-01
+1 5.6283038e-01 1 1 -2.2434632e-01 -1.1518501e+00 -5.5996345e-01 6.0389207e-01 -1.3426642e+00 9.5911444e-01 8.9933927e-01 9.3966851e-01
+1 7.7946332e-01 1 1 -6.7745321e-01 -6.5037565e-01 9.0582045e-01 -8.7178316e-01 -9.6983141e-02 3.2449531e-01 9.9285083e-01 2.2234873e-01
+1 1.0882925e+00 1 1 -8.2428776e-01 -1.2626656e+00 -3.3714308e-02 3.2854731e-01 4.9093576e-01 -1.2107538e-02 -1.2962613e+00 -1.4802098e+00
+1 1.1057568e+00 1 1 6.1917222e-01 -1.6207105e-01 -1.1497036e+00 -1.0252433e+00 1.3350735e+00 7.1213244e-01 6.8160092e-01 3.8534994e-01
+1 3.6987776e-01 1 1 1.4726452e+00 -1.6727215e-01 8.6811274e-01 3.7205533e-01 1.3250166e+00 -6.5808787e-01 1.4198476e+00 -1.3875685e+00
+1 3.6196002e-01 1 1 1.2814679e+00 3.8236937e-01 8.1449923e-01 1.3645860e+00 -1.1958432e+00 1.0648653e+00 -1.6001989e-01 -8.2136089e-01
+1 5.8238669e-01 1 1 -1.1288843e+00 -1.2165714e+00 1.3693460e+00 9.7062414e-01 1.3731027e+00 -4.6169491e-01 -2.5101284e-01 -4.5432494e-01
+1 9.8509686e-01 1 1 -1.0804992e+00 -1.4313561e+00 -7.1024452e-01 -1.0106782e+00 -4.0333091e-01 2.7520177e-02 3.8619503e-01 1.3724784e+00
+1 1.0232264e-01 1 1 -1.5448716e+00 1.5150600e+00 9.7246832e-01 1.2217099e-01 7.7426867e-01 7.1749805e-01 2.4943496e-01 -1.4700369e+00
+1 5.5872619e-01 1 1 6.0649723e-01 1.0043373e+00 -1.4315553e+00 -1.2737397e+00 6.5669097e-01 1.5571576e+00 1.3688075e+00 -1.4259515e+00
+1 5.4654438e-01 1 1 -1.0691786e+00 1.2030214e-01 1.3073755e+00 -9.3022745e-01 5.9006285e-01 -1.4599983e+00 -3.3594015e-01 1.2429062e+00
+1 5.6218362e-01 1 1 2.2479369e-01 -1.2675268e+00 7.6086120e-01 1.3739441e+00 -8.2173611e-01 7.8884603e-01 -7.0408767e-01 1.0742066e+00
+1 5.5352361e-01 1 1 -1.2283673e+00 -1.8271483e-01 1.5120610e+00 1.1719585e+00 -4.7752702e-01 6.1424937e-01 7.7799367e-01 -5.4299115e-01
+1 6.0791667e-01 1 1 1.3783978e+00 -1.5521114e+00 8.6570696e-01 -6.7933369e-01 9.7261387e-01 4.1574661e-01 4.3099525e-01 2.7443536e-01
+1 8.1906273e-01 1 1 6.2730021e-01 1.4487974e+00 1.2213249e+00 -1.0136174e+00 1.0146807e+00 5.5127656e-01 -7.7544820e-01 5.7703336e-01
+1 1.6522303e-01 1 1 -1.5037052e-01 -5.4638796e-01 -3.5944225e-01 9.8960229e-01 1.1742283e+00 7.4835981e-01 1.5100170e+00 1.0315838e-01
+1 8.3954897e-01 1 1 -1.4367527e+00 -2.6714739e-01 1.3680318e-01 6.5419812e-01 -2.2963324e-01 -1.2537078e+00 1.0697531e+00 -3.7632391e-01
+1 5.4594919e-01 1 1 -1.2213618e+00 -6.1033880e-01 -3.9474895e-01 -4.6644713e-01 -1.5700760e+00 -4.0575787e-01 6.0928585e-03 -8.5000208e-01
+1 8.7929183e-01 1 1 -2.6111571e-01 -6.6414052e-01 4.9813495e-01 -1.3033093e+00 1.1107028e+00 8.2514448e-01 -1.2698847e+00 -1.1631557e+00
+1 8.6077987e-01 1 1 2.3316665e-01 -1.3102478e-01 -1.9026092e-01 -1.5354021e+00 2.3915667e-01 1.2132262e+00 1.0283110e+00 9.7364494e-01
+1 7.7357440e-01 1 1 1.2658281e+00 1.2293106e-01 4.2600574e-01 -4.6136713e-01 1.4091375e+00 -1.3848232e+00 9.2247151e-01 -5.0555011e-01
+1 7.3862216e-01 1 1 -9.1862985e-02 -1.0655759e+00 1.8877962e-01 -7.4669189e-01 -1.0934110e+00 1.3360397e+00 2.1887022e-01 1.2273947e+00
+1 8.0672226e-01 1 1 -1.4191928e+00 1.0856379e+00 -1.8949224e-01 1.0119777e+00 1.3582896e+00 -1.2850939e+00 -2.5322654e-01 1.1260613e+00
+1 6.1095170e-01 1 1 -1.4027386e+00 -5.3613448e-02 7.7886556e-01 -2.7351006e-01 -1.1807229e+00 -1.2333999e-01 8.7966203e-01 7.5731269e-01
+1 1.1663577e+00 1 1 -1.3168270e+00 5.5586710e-01 -6.2315527e-01 -7.3347828e-01 1.0308561e+00 4.7590784e-01 1.4475538e-01 1.5625683e+00
+1 5.6777519e-01 1 1 6.0861513e-01 -6.3817057e-01 6.9931285e-01 4.0141971e-02 -2.8496877e-01 8.8118049e-02 1.3110395e+00 1.5119940e+00
+1 7.6060850e-01 1 1 -3.1125384e-02 -3.3538072e-01 6.5294545e-01 -7.7631284e-01 1.4586598e+00 1.3099117e+00 -4.8933664e-01 -2.5933249e-01
+1 4.3712501e-01 1 1 1.5216487e+00 -7.2647453e-01 4.7104512e-01 -4.5566903e-01 -1.2940115e+00 -5.9584836e-01 4.0869588e-01 -1.2120651e+00
+1 5.7656376e-01 1 1 -1.3556976e+00 1.5132082e+00 4.1780577e-02 7.7348795e-01 7.9455420e-01 9.7398613e-01 1.4301093e+00 -1.0905778e+00
+1 6.8698409e-01 1 1 7.6135362e-01 1.2969919e+00 -1.5105997e+00 1.0150255e-01 -8.3792930e-01 -1.0544445e+00 -4.7884985e-01 -1.2897514e+00
+1 1.2418600e+00 1 1 3.6345448e-01 -9.6928851e-01 -1.4381317e+00 6.8521622e-02 6.8209885e-01 -3.2446933e-01 7.3099928e-01 1.3780671e-01
+1 4.6349529e-01 1 1 1.3232490e+00 1.4675789e+00 7.3503084e-01 -1.3216005e+00 3.6373835e-01 4.4890029e-01 -8.6403185e-01 7.6363467e-01
+1 3.7904316e-01 1 1 5.1092323e-01 9.5503642e-01 9.2103934e-01 -1.0802541e+00 -1.8892526e-01 -1.4384487e+00 -1.3419873e+00 1.0019605e+00
+1 2.5544954e-01 1 1 1.1139834e+00 9.0032197e-01 1.2812453e+00 -5.6642556e-01 8.8339816e-01 -1.4513383e+00 -1.2872200e+00 1.0139556e+00
+1 3.3738140e-01 1 1 -1.1726695e+00 -1.3405300e+00 1.4142585e+00 -8.8863832e-01 1.0597205e-01 -1.3174694e+00 -1.2998687e+00 1.5533559e+00
+1 7.8232033e-01 1 1 1.2952858e+00 1.2144805e+00 1.5236283e-01 -2.1268755e-01 -2.1071716e-01 -7.6361222e-01 -2.5804549e-01 6.1840109e-01
+1 5.6617533e-01 1 1 -1.3679828e+00 8.4595436e-01 3.6403848e-01 4.9279086e-01 -9.4838809e-01 -6.2459520e-01 1.5689263e+00 1.0787001e+00
+1 1.2089222e+00 1 1 -1.5123790e+00 -8.9340808e-01 -1.4277383e+00 1.0977895e+00 8.8250287e-01 -1.5104139e+00 1.5576836e+00 -4.1875293e-01
+1 1.1556772e+00 1 1 7.2231702e-02 1.3032006e+00 -5.1243964e-01 -2.6099514e-02 7.6687387e-01 -1.4575843e+00 1.0971672e+00 -8.1286784e-01
+1 8.7668983e-01 1 1 1.3434571e+00 -2.9202170e-01 -1.4676134e+00 1.1684390e+00 -1.1054886e+00 5.1956155e-01 -1.0592685e+00 9.1664632e-01
+1 8.2722592e-01 1 1 8.5757356e-01 -8.4103022e-01 -1.5353204e+00 -1.4133470e-01 -5.6734070e-01 -1.3565432e+00 2.7996891e-01 -2.9561261e-01
+1 7.5917621e-01 1 1 -3.8822492e-01 -1.1695754e+00 9.1131524e-01 -3.6819264e-01 -5.6148402e-01 -8.8314895e-01 -6.6831310e-01 -1.5030864e+00
+1 2.6348877e-01 1 1 1.9165702e-01 -1.0847160e-01 1.2110677e+00 7.2387159e-01 4.8238719e-01 9.4094951e-01 -1.1445189e+00 -8.2688612e-01
+1 4.5460957e-01 1 1 1.0470620e+00 -9.5847625e-01 3.6616303e-02 -1.2786122e+00 -9.6915658e-01 -2.3908491e-01 4.2897159e-02 9.3092305e-01
+1 1.1092381e+00 1 1 -1.2313739e+00 9.7674861e-01 -3.4194917e-01 -1.1408570e+00 5.4321658e-01 -2.0315676e-01 1.5478386e+00 8.9232539e-01
+1 1.0028621e+00 1 1 1.1115448e+00 1.3922498e+00 -1.1667118e+00 -1.2439357e+00 3.7277105e-01 4.5557544e-01 -1.0059591e+00 -6.5058051e-01
+1 3.3578587e-01 1 1 -1.3176559e+00 9.6098659e-01 8.9595426e-01 4.7179172e-01 8.2726393e-01 7.9510990e-01 8.9651692e-01 -1.5641996e+00
+1 6.5195208e-01 1 1 -7.5576473e-01 3.7377588e-01 6.4958895e-01 2.3618581e-02 -8.6427528e-01 -9.2313662e-01 6.8146619e-01 -6.5604944e-01
+1 6.6506660e-01 1 1 -6.7878767e-01 -1.1341362e+00 6.0706278e-01 1.1168086e+00 8.4985264e-01 1.1689745e+00 -8.4459031e-01 7.6733839e-01
+1 1.2287791e+00 1 1 -1.2613957e+00 -1.3845521e+00 -9.8881531e-01 -8.1420029e-01 -1.3484334e+00 -5.6599378e-01 -1.3136517e+00 4.1842177e-01
+1 9.3115179e-01 1 1 -8.1014661e-01 -3.9033877e-01 6.2729598e-03 5.1332130e-01 3.2993120e-01 8.5058223e-02 5.6905746e-01 1.5303571e+00
+1 8.7044600e-01 1 1 -4.7153908e-01 -7.7819115e-01 -1.3845147e+00 5.7760750e-01 2.4271749e-01 1.4889368e-01 1.1406489e+00 4.9263121e-01
+1 7.7204484e-01 1 1 1.0809109e+00 -6.0848656e-01 2.3862804e-01 3.2802105e-01 1.5655566e+00 -1.3933107e+00 8.8708030e-01 1.5561494e+00
+1 1.3936948e+00 1 1 -9.6016509e-01 -9.4959097e-01 -1.1923835e+00 -4.4536479e-01 1.4710882e+00 5.8352514e-02 -8.4017967e-01 4.4401516e-01
+1 5.5014755e-01 1 1 8.6673335e-01 -4.8476999e-01 -1.6945819e-01 1.1693360e+00 2.4522163e-01 5.5379993e-01 5.5921231e-01 1.2802280e+00
+1 6.6548862e-01 1 1 -3.7765899e-01 -1.3795412e+00 1.3407078e+00 -7.7351859e-01 -3.2963864e-01 -8.2356208e-01 -9.6387897e-01 2.3451458e-02
+1 1.3516462e+00 1 1 -1.2975596e+00 -9.9542042e-01 -1.3684993e+00 -6.1653197e-01 1.5327493e+00 2.4943693e-01 1.2794398e+00 1.4495768e+00
+1 1.0622256e+00 1 1 8.5209346e-01 -1.0501212e+00 -7.6710199e-01 -1.0802660e+00 -1.4233964e-01 1.4019511e+00 -6.5703366e-01 -1.4286986e-02
+1 6.6963891e-01 1 1 -1.3860525e+00 8.1198872e-02 4.1304159e-01 -7.6656589e-01 -1.5504013e+00 6.4718488e-01 -6.6493346e-02 -1.3603316e+00
+1 4.8115240e-01 1 1 -4.7459072e-01 1.2582352e+00 -9.2972839e-01 -1.4383667e-03 -1.2254533e+00 1.0425572e+00 8.5331505e-01 1.4182323e+00
+1 8.9524309e-01 1 1 5.7557037e-02 1.0992896e+00 3.3679164e-01 9.5811282e-01 8.8385174e-02 -1.5455979e+00 2.9551938e-01 9.6754021e-01
+1 9.2303729e-01 1 1 -2.4942481e-01 5.4021776e-02 -6.9278472e-01 -8.0177734e-01 -4.8371296e-01 9.6580752e-01 -6.3761579e-02 5.6469830e-01
+1 1.1698569e+00 1 1 -1.1980981e+00 2.3720179e-02 -8.9045611e-01 -1.1808471e+00 6.7807242e-01 -2.8227103e-01 -3.5776830e-01 1.3288774e-01
+1 4.2877095e-01 1 1 1.1743152e+00 -3.1722316e-01 6.5159627e-01 -1.0558404e+00 -1.3350315e+00 -3.2422497e-01 -3.4061509e-03 -2.2810769e-01
+1 2.9625985e-01 1 1 1.2310961e+00 -2.8688788e-01 -2.1341069e-01 1.3469569e+00 -6.2046857e-01 1.4141921e+00 -6.9851096e-01 -1.0629723e+00
+1 5.7951392e-01 1 1 5.0335498e-01 6.2020181e-01 9.0535716e-01 -1.1886339e-02 -1.2693041e+00 -9.6291547e-01 2.5797150e-01 8.6205702e-01
+1 1.2705250e+00 1 1 -4.2179242e-01 -7.2664628e-02 -1.5369713e+00 1.2882325e+00 1.3616773e+00 -1.3766243e+00 3.2921461e-01 -4.3302414e-01
+1 3.7121039e-01 1 1 1.5094206e+00 8.0513798e-01 1.4390444e+00 -5.3330884e-01 -7.9195001e-01 9.0516204e-01 7.6533638e-01 1.2334316e+00
+1 6.3353689e-01 1 1 4.7160661e-01 1.1145343e+00 -1.1018690e+00 -3.5784518e-01 6.2433083e-01 1.4668138e+00 1.3282699e+00 -1.0844707e+00
+1 9.5438243e-01 1 1 5.4086350e-02 -1.3390640e+00 5.7674881e-01 -1.2956390e+00 2.0876827e-01 6.6273504e-01 7.5567460e-02 8.2137505e-01
+1 7.4114451e-01 1 1 1.1090020e+00 7.2100548e-01 -1.5377177e+00 -1.4258884e+00 -3.9064200e-01 -1.4997948e+00 8.5886582e-01 6.9240342e-01
+1 7.4054624e-01 1 1 -7.2277454e-02 8.1631371e-01 1.4609683e+00 -8.3818862e-01 4.0849686e-01 1.0878995e+00 -6.6036122e-01 7.6506936e-01
+1 9.2652726e-01 1 1 1.0291934e+00 4.4947033e-01 -1.9410086e-01 -5.3467153e-01 1.2268259e+00 2.5741483e-01 5.5586040e-01 -1.8026143e-02
+1 1.3523134e+00 1 1 4.4734606e-02 -1.2824795e+00 -1.2798986e+00 -1.2694627e+00 9.9067163e-01 3.9799764e-01 -7.5078024e-01 -1.3724931e+00
+1 8.5700346e-01 1 1 1.0138846e+00 -1.6598322e-01 -7.7103552e-01 -1.3042460e+00 -2.2290366e-01 6.9553078e-01 1.4142674e+00 1.2237463e+00
+1 6.2264663e-01 1 1 3.6055400e-01 5.4346224e-02 2.7566132e-01 -1.5702953e+00 -1.5633409e+00 -8.0458838e-02 3.0278771e-01 -5.0306122e-01
+1 1.1583052e+00 1 1 -3.0119394e-01 -8.0647709e-01 -8.0929940e-01 5.6693506e-01 1.2097877e+00 -1.3868432e+00 -4.2705269e-01 -9.2407354e-01
+1 7.2866371e-01 1 1 -1.0607108e+00 1.5117875e+00 1.2012143e+00 2.7014370e-02 5.1395790e-01 -1.1979806e+00 1.0646794e+00 1.1300244e+00
+1 2.5297595e-01 1 1 1.1713642e+00 -5.8860098e-01 9.3355830e-01 -1.5004124e+00 -1.2892955e+00 7.2274173e-03 -4.4487307e-01 1.3930522e+00
+1 5.8198567e-01 1 1 -1.2432301e+00 2.5862998e-01 1.2006899e+00 1.3299177e-01 1.5171193e+00 -1.0509108e+00 8.8046829e-03 -1.2614278e+00
+1 4.2160284e-01 1 1 -2.3633808e-01 -1.1700842e+00 1.5462608e+00 1.5202435e+00 1.0589000e+00 -6.2446360e-01 3.2545103e-01 -1.3496158e+00
+1 1.9718486e-01 1 1 -1.1610159e+00 7.6524928e-01 7.5059236e-01 1.5923066e-01 -1.8984829e-01 7.0130887e-01 3.4256759e-01 -6.9336584e-01
+1 1.2781274e+00 1 1 -7.6170018e-01 -1.3572953e-01 -1.4303188e+00 -4.4719970e-01 1.0779287e+00 -3.5741546e-01 -1.0058354e+00 -1.2324771e+00
+1 4.1462469e-01 1 1 9.5057125e-02 -4.0986958e-01 9.9398748e-02 -1.3956684e+00 -8.1633698e-01 -3.5646297e-01 -1.6629631e-01 1.4194514e+00
+1 6.4340011e-01 1 1 -1.4455686e+00 8.3467726e-01 -7.3253498e-01 1.2733861e+00 -8.4048159e-01 -5.6027351e-02 1.0753407e+00 -5.3427893e-01
+1 2.9149441e-01 1 1 1.4066504e+00 1.2094987e+00 1.8616958e-01 1.2711627e+00 -1.3735638e+00 8.2611048e-01 -3.3195897e-01 -9.5416394e-01
+1 2.5168669e-01 1 1 1.0884226e+00 -1.2022290e+00 -7.4218237e-02 -1.5393126e+00 -1.0637583e+00 -1.4006461e+00 2.3422273e-01 1.1971026e+00
+1 9.9507744e-01 1 1 -3.7616224e-01 8.6138605e-01 -1.7362322e-01 -2.1147340e-01 2.1882161e-01 -7.0590372e-01 1.6574446e-01 9.4397623e-01
+1 5.7534177e-01 1 1 -1.2743086e+00 8.5637317e-01 4.5403478e-01 -1.0921578e+00 -1.0702367e+00 -1.4700317e+00 -9.2549343e-01 3.6557247e-01
+1 9.2751471e-01 1 1 -1.0682971e+00 1.4279916e+00 3.4019736e-02 4.2947664e-01 1.2907011e+00 -1.3386176e+00 -7.4288137e-01 -7.7879062e-01
+1 6.7087806e-01 1 1 -6.6693336e-01 -1.5137067e+00 -1.5270012e-04 -1.1660083e+00 1.1569182e-01 -1.2005508e+00 -9.1803756e-01 -1.2590285e+00
+1 7.4384562e-01 1 1 5.3589455e-02 -2.5197151e-01 5.7516173e-01 1.5367274e-01 -2.1336704e-01 7.9179134e-01 -1.0957025e+00 1.2754429e+00
+1 5.6607052e-01 1 1 -9.5912282e-01 -1.8244722e-02 6.2532529e-02 3.8862129e-01 -1.5026007e+00 -1.4944826e-01 5.4494350e-01 1.2816896e+00
+1 4.2412974e-01 1 1 -4.6535575e-01 1.2370353e+00 -1.4493216e+00 1.8690479e-01 1.0533429e+00 1.4972289e+00 1.1228174e+00 -5.4312147e-01
+1 4.8688216e-01 1 1 1.3316133e+00 -2.0737430e-01 1.1620901e+00 -2.8386585e-01 6.5868431e-01 -2.3026222e-01 -3.5541177e-01 1.2256470e+00
+1 1.0198190e+00 1 1 -2.8139136e-01 -1.3136082e+00 -3.3378482e-02 1.1459587e+00 -4.6526817e-01 4.2509872e-01 -1.2379374e+00 2.6015218e-02
+1 5.2695753e-01 1 1 -1.2476204e+00 1.2996680e+00 1.3529315e+00 -9.7741850e-01 -3.3798903e-01 6.5246699e-01 7.5350277e-01 5.5638631e-01
+1 6.2300651e-01 1 1 1.3745715e+00 2.6560545e-02 -1.2743172e-01 -8.4731711e-02 -5.8204003e-01 -1.2872064e+00 3.6104706e-01 -1.3365597e+00
+1 4.3510936e-01 1 1 -8.4890992e-01 2.9692906e-01 8.2127806e-01 -9.4439832e-01 5.7271001e-01 -1.0715268e+00 -1.4390066e+00 -1.1707967e+00
+1 9.2010627e-01 1 1 1.4848228e+00 -1.5040921e+00 -9.3773220e-01 -1.1764767e+00 -3.0273111e-01 -1.5415793e+00 -1.4039954e+00 1.3561716e+00
+1 7.2031876e-01 1 1 -1.3959656e+00 1.1198600e+00 9.0532924e-01 1.3979199e-01 1.3783831e+00 -6.0936849e-01 -4.4778571e-01 9.2124292e-01
+1 6.0707014e-01 1 1 -5.8046487e-01 2.0549011e-01 1.1353734e+00 -4.2736887e-01 3.8076371e-01 -6.4084495e-02 1.3216097e+00 1.5610934e+00
+1 4.0567559e-01 1 1 -1.2279510e+00 1.0619499e+00 1.8653320e-01 -1.1077242e+00 7.1420549e-02 4.9817184e-01 1.2339245e+00 -1.2846553e+00
+1 9.8437670e-01 1 1 -1.0508610e+00 8.0400090e-01 -2.4601775e-01 -4.4196963e-01 2.7677986e-01 4.2973153e-01 9.1569493e-01 9.6481026e-01
+1 6.1269523e-01 1 1 2.1388835e-01 8.5304905e-01 -4.8437990e-01 -1.4585559e+00 -8.5967901e-01 -2.3663556e-02 -5.7765696e-01 -1.3352245e+00
+1 9.4386889e-01 1 1 8.3942057e-01 -1.0335164e+00 -1.1064588e+00 -1.0090190e-01 -4.4046777e-01 1.2688732e+00 -1.1591689e+00 -7.2112468e-01
+1 7.8872421e-01 1 1 -7.5114849e-01 -4.4516572e-01 -1.1656264e+00 6.0178851e-01 -1.3494462e+00 8.2124163e-01 -1.1360828e+00 3.2188407e-01
+1 8.5885570e-01 1 1 1.5082237e+00 1.3735045e+00 2.8813219e-01 1.4728098e+00 -9.8470448e-01 -1.5501272e+00 4.5703045e-01 8.2980322e-02
+1 2.3006631e-01 1 1 -7.9589114e-01 6.7162675e-02 1.4434807e+00 9.0557362e-01 -1.8085944e-02 2.4028775e-01 1.1673867e-01 -2.1687000e-01
+1 7.8563213e-01 1 1 3.5919514e-01 9.7131797e-01 1.2021819e+00 -1.0406078e+00 7.6402139e-01 1.5696674e+00 -1.4685226e+00 -6.8664269e-01
+1 2.7241537e-01 1 1 -1.1484420e+00 1.2256685e+00 1.4885705e+00 -2.4902298e-01 1.2183939e+00 1.4468276e+00 -1.1073338e+00 -1.3338276e+00
+1 1.1585393e+00 1 1 8.0283165e-02 3.8754635e-01 -1.2401654e+00 -7.2777661e-01 6.4562856e-01 9.0511764e-01 -1.6399432e-01 7.6418749e-01
+1 5.7594742e-01 1 1 -1.5656938e+00 9.6993570e-01 1.0081291e+00 -1.5213025e+00 1.8112817e-02 7.2056579e-01 -1.0757792e+00 8.6836547e-01
+1 5.4464669e-01 1 1 -6.3592845e-01 -1.5024977e-02 1.0164004e+00 8.9140803e-01 -3.1237794e-01 -2.9044910e-01 -7.5611753e-01 -1.2209411e+00
+1 9.3286365e-01 1 1 -3.5126470e-01 -1.1973752e+00 -1.3400085e+00 -3.6062675e-01 -5.3468784e-01 4.5699661e-01 -3.2496864e-01 5.2537340e-01
+1 5.9787191e-01 1 1 -6.5322064e-01 7.5756910e-01 5.5570146e-01 -9.2150612e-01 -1.5436107e+00 -4.5196475e-01 1.4817254e+00 -1.0662716e+00
+1 5.7149998e-01 1 1 1.1870053e+00 -4.1118265e-01 -2.8044631e-01 2.9835131e-01 -1.9318340e-01 1.9953822e-01 -4.6988616e-02 -1.1823772e+00
+1 5.5300012e-01 1 1 8.8541212e-01 7.5696137e-01 -1.0721619e+00 4.0864506e-01 -1.5682296e+00 1.5595568e+00 -1.1979197e+00 1.5010265e+00
+1 3.0115920e-01 1 1 -6.0294900e-01 -1.2004706e+00 3.5109109e-01 5.7592313e-01 7.2724756e-01 1.1631671e+00 1.0309427e+00 7.6371790e-01
+1 3.7496332e-01 1 1 1.0141227e+00 -1.0007227e+00 8.7691972e-01 2.9304612e-01 -1.0872996e+00 -7.8110208e-01 1.1712857e+00 -7.4086267e-01
+1 2.7264556e-01 1 1 1.2196780e+00 9.4036278e-01 1.1785891e+00 -7.9109727e-01 4.0047874e-01 7.3306095e-01 5.7937872e-01 -1.5471729e+00
+1 6.2068902e-01 1 1 2.3663955e-01 -6.7542265e-01 8.0598525e-01 -7.5166698e-01 1.5546542e+00 -7.7099010e-01 -1.3190721e+00 -3.7313252e-01
+1 8.7387227e-01 1 1 -5.5398151e-02 -1.2541434e+00 -3.5337071e-01 -9.2288295e-01 4.4709717e-01 1.0390713e+00 5.7468532e-01 -6.1937031e-01
+1 1.0066019e+00 1 1 -1.1653024e+00 -1.4424224e+00 -1.4913303e+00 -8.5082837e-01 -3.2748083e-01 -4.4241146e-01 1.4803696e+00 1.4812524e+00
+1 9.3501042e-01 1 1 -5.4882658e-01 8.7738818e-01 -1.1613622e+00 6.5730611e-01 1.0009798e-01 5.4037657e-01 -8.4255427e-01 1.4288498e+00
+1 3.1114706e-01 1 1 -4.1225667e-01 -3.7285509e-01 -2.9893499e-01 1.5039836e+00 -1.5469801e+00 -2.3528352e-01 1.4900909e+00 3.4391823e-01
+1 7.2066349e-01 1 1 1.5556052e+00 9.0186416e-01 -7.9369375e-01 1.9782481e-01 -2.7400082e-01 8.5497153e-01 -8.1896954e-01 -2.9681697e-01
+1 1.0318416e+00 1 1 7.2240461e-01 -5.5357406e-01 -4.0851821e-01 1.0365001e+00 4.4301017e-01 -1.3833565e-01 -1.1035810e+00 2.4640023e-01
+1 6.3637403e-01 1 1 -8.0131559e-01 1.4782430e+00 1.5559402e+00 3.2535936e-01 9.7355438e-02 -2.2867712e-01 7.7197527e-02 6.2958399e-01
+1 5.6626225e-01 1 1 2.9664252e-01 1.1155515e+00 6.9678211e-02 -1.1980704e+00 -5.1693280e-01 -1.2085410e+00 -1.8936848e-02 5.3401537e-01
+1 4.6752599e-01 1 1 -3.6789656e-02 4.8669613e-02 -7.3236706e-01 -1.5015946e+00 1.5557157e+00 -1.5527497e+00 -9.7074102e-01 -3.3386033e-01
+1 7.0073874e-01 1 1 5.7000019e-01 1.1760980e+00 -1.3319855e-01 -8.8725645e-01 -5.6211198e-01 1.4625037e-01 -9.5369664e-01 -3.0606550e-01
+1 4.4483479e-01 1 1 1.2772350e+00 -2.2116753e-01 1.2875812e+00 1.0210969e+00 -6.4694258e-01 1.3045891e+00 -3.7364263e-01 -1.2557521e+00
+1 4.9002337e-01 1 1 -1.4641594e-02 -6.5864072e-01 1.0871068e+00 -9.4487190e-01 -1.1181043e-01 1.0534135e+00 2.3195157e-01 -2.0571943e-01
+1 9.7940440e-01 1 1 -1.0370499e+00 1.1979441e+00 -4.9867612e-01 2.8883831e-01 -5.2541985e-01 -1.2950730e+00 -3.0642875e-01 1.3671326e+00
+1 8.4515566e-01 1 1 -1.4241767e-01 -6.2161397e-01 5.1964436e-01 7.4489079e-01 2.8550303e-01 -1.3383702e+00 -1.0775845e+00 -2.1139290e-01
+1 1.1035963e+00 1 1 2.7987878e-01 1.4710985e+00 3.5169745e-02 1.3272388e-01 1.2374730e+00 -1.8492886e-01 3.1956760e-01 2.6075640e-01
+1 5.6371927e-01 1 1 9.5840903e-01 4.1777505e-01 4.7848727e-01 1.5941633e-01 8.6457295e-01 -1.0642011e+00 -1.1508572e+00 1.0993182e-02
+1 1.1230141e+00 1 1 1.0351084e+00 8.5671073e-02 -5.4171822e-01 -4.6834889e-01 1.0114729e+00 -9.4151685e-01 3.2972572e-01 -5.9155619e-01
+1 9.0132413e-01 1 1 -1.0727172e+00 1.0242862e+00 -3.2259705e-01 1.2913566e+00 6.6664561e-01 1.2845467e-01 -6.9266158e-02 8.5584725e-01
+1 6.0488854e-01 1 1 4.4222394e-01 -7.4984249e-01 5.0036912e-01 -1.4338633e+00 1.3933548e+00 6.6352608e-01 1.3745535e+00 -1.1280184e+00
+1 7.5387899e-01 1 1 -5.5052697e-01 1.4670110e+00 -3.3980127e-01 2.1619332e-01 6.8167496e-01 -7.7114326e-01 -1.1514070e+00 9.0704486e-01
+1 7.2271086e-01 1 1 -7.1633920e-01 8.3407953e-01 3.7542952e-01 -1.2615905e+00 -4.7730990e-01 -1.5349940e+00 5.1279035e-01 -1.4462325e+00
+1 3.8831953e-01 1 1 -9.2983848e-01 5.8826469e-01 1.5259513e+00 -9.4279075e-01 1.4801154e+00 1.1497463e-01 1.0787330e+00 -3.2730479e-01
+1 1.2993852e+00 1 1 -1.5135475e+00 3.7263173e-01 -1.2988735e+00 7.0916113e-01 1.1695282e+00 2.9914649e-01 1.3401795e-01 -8.2909180e-02
+1 7.1019546e-01 1 1 -7.1724046e-01 -1.5142058e+00 7.5972357e-01 -3.3137969e-01 -6.8468895e-01 1.2068294e+00 -8.2280936e-02 1.4125487e+00
+1 3.6148529e-01 1 1 -3.6935105e-01 7.8473834e-01 1.2414538e+00 5.4538669e-01 8.6660068e-02 1.0596403e+00 -5.9491971e-01 -3.1038132e-01
+1 7.8858326e-01 1 1 1.0392861e-01 6.9139713e-01 -1.3436513e+00 -8.5319973e-01 -1.2032219e+00 -3.1481736e-01 8.7389522e-01 -1.5350171e+00
+1 9.4448235e-01 1 1 2.6721684e-03 -4.3961208e-01 -9.8023527e-01 -1.4989718e+00 -1.1866614e-01 -6.9336929e-01 6.1130440e-01 -2.7436470e-01
+1 9.9098250e-01 1 1 9.2883646e-01 4.6569199e-01 -3.0238970e-01 -7.8690015e-01 4.8945005e-01 -1.2904539e+00 1.1850747e+00 6.1055609e-01
+1 7.1470988e-01 1 1 3.8053794e-01 1.1780538e+00 8.3317682e-01 6.7422931e-01 1.4973826e+00 8.9761895e-01 -1.4644928e-01 1.1745434e+00
+1 6.0803864e-01 1 1 -5.8141634e-01 1.2330293e+00 1.1243616e+00 4.7228634e-02 -7.8938075e-01 3.5369306e-01 -1.5060776e+00 -1.2175086e+00
+1 9.4641798e-01 1 1 -1.5112739e+00 -1.5632256e+00 4.6490911e-01 -1.0512824e+00 -1.7650986e-01 6.2602237e-01 -8.3343371e-01 -1.4747073e+00
+1 4.2137299e-01 1 1 -2.0417863e-01 6.3844781e-03 5.8650080e-01 -5.8538614e-01 -9.3778801e-01 3.6412244e-01 8.4127557e-01 -1.3804843e+00
+1 9.3525244e-01 1 1 -1.0110095e+00 4.8977247e-01 -9.9875935e-01 8.8332184e-01 -3.2748646e-02 -1.6601419e-02 -9.8998149e-01 -1.1380796e+00
+1 5.5171257e-01 1 1 8.3737363e-01 6.3318114e-01 -6.1881045e-01 -1.1767701e+00 -6.2778589e-01 5.8169823e-01 -7.4415462e-01 1.4543355e+00
+1 4.7574274e-01 1 1 -5.9649813e-01 1.3011329e+00 1.4659713e+00 1.4921982e+00 1.4122014e+00 -3.4240628e-02 -3.2641435e-01 1.4262754e+00
+1 9.7491352e-01 1 1 -5.2198893e-01 -4.8501068e-01 -9.3222420e-01 4.0383471e-02 1.3573830e-01 -5.7078401e-01 -8.2524402e-01 1.0595395e+00
+1 8.9321749e-01 1 1 1.4004116e+00 8.5849822e-01 -7.6948296e-01 1.4098466e-01 5.5734399e-01 1.2570689e+00 2.5537522e-01 1.1325653e+00
+1 3.4195057e-01 1 1 -9.4260052e-02 -5.5553741e-01 1.2368672e+00 7.6830948e-01 -9.4886384e-01 3.4581320e-01 6.7570725e-01 1.1455475e-01
+1 6.3026655e-01 1 1 -8.6599923e-01 -1.0393054e-01 1.0887124e-01 1.0317057e+00 -8.3023765e-01 1.3607409e-01 -2.4571263e-01 -4.7468018e-01
+1 3.9439782e-01 1 1 1.4971846e-01 -3.5053595e-02 1.3920152e+00 1.4285994e+00 1.1503653e+00 -8.2154462e-02 1.5020948e+00 -1.4459788e+00
+1 9.8571456e-01 1 1 -9.7553907e-02 1.4736432e+00 1.5870831e-01 -7.2215681e-01 8.2844522e-01 1.5307230e+00 -1.3155387e-01 7.9583729e-01
+1 7.8533759e-01 1 1 3.2284509e-01 -7.9588581e-01 1.9837596e-01 -1.3170822e+00 1.4013875e-01 3.5992545e-01 6.5533154e-01 -1.2642523e+00
+1 5.1032142e-01 1 1 5.2683346e-01 4.4876654e-01 8.7492471e-01 -5.3899127e-01 -8.8258577e-01 -1.4404078e+00 -2.6662674e-01 1.4438097e+00
+1 1.1677207e+00 1 1 1.4818251e+00 -5.4474664e-01 -9.3565281e-01 1.5268972e+00 9.8143228e-01 1.7931011e-01 -1.2845586e+00 4.4778715e-01
+1 5.1611307e-01 1 1 -1.5127379e+00 -9.5584942e-01 1.2961228e+00 -1.1086380e+00 -1.5706479e+00 8.7763450e-01 -5.5190845e-01 -1.2974158e+00
+1 5.4495719e-01 1 1 3.2293175e-01 1.1437118e+00 1.3172534e-01 -9.3449005e-02 9.2299153e-01 6.2560497e-01 1.1977387e+00 1.2696172e-01
+1 1.1092820e+00 1 1 -1.1582588e+00 -1.0410497e+00 -9.1502637e-01 1.9890776e-01 -4.6589753e-01 -3.6783211e-01 -9.3059797e-01 7.0422660e-01
+1 6.9748352e-01 1 1 -1.5482598e+00 -1.3932814e+00 -7.5223558e-01 3.8815819e-01 -1.4909717e+00 4.9999625e-01 1.4296671e+00 1.5569850e+00
+1 9.6411829e-01 1 1 2.0909420e-01 5.5169597e-01 -1.0546091e+00 -1.3132051e+00 -1.4191188e+00 -3.2341786e-01 1.5144521e+00 -1.2191373e+00
+1 8.2729329e-01 1 1 -1.1959816e+00 1.5142448e+00 5.1179046e-02 -1.3493025e+00 -1.5763957e-01 -7.2865786e-01 2.1286116e-01 -5.7344834e-01
+1 1.2579107e+00 1 1 -9.5213951e-01 -1.2993033e-01 -6.3016505e-01 1.4300107e+00 -1.0856323e+00 -6.2453506e-01 -7.1646535e-01 4.6000784e-01
+1 8.9064388e-01 1 1 6.6430012e-01 -3.3208115e-01 -8.7522498e-01 1.0066185e+00 1.4842194e-01 -4.9972981e-01 9.1446856e-02 -1.0768649e-01
+1 8.9639978e-01 1 1 -3.2819570e-01 1.3222133e+00 -9.6938886e-01 7.5991462e-01 1.0295969e-01 -1.4817136e+00 7.0850627e-01 -3.2952604e-01
+1 2.3818039e-01 1 1 6.5158232e-01 -1.1872738e+00 -2.1908281e-01 1.3109333e+00 -5.7409972e-01 2.4427682e-01 1.2287726e+00 2.8363837e-01
+1 9.6436831e-01 1 1 -4.4794860e-01 8.8618233e-01 -1.7822663e-01 8.6675348e-01 -1.0629149e+00 -5.0101572e-01 -8.4931274e-01 1.3139562e+00
+1 1.0439649e+00 1 1 -1.4161576e+00 -2.2442007e-01 -1.5171250e+00 -3.9412001e-02 -1.3140921e+00 -1.1028686e+00 9.9775735e-01 1.4078774e+00
+1 9.1631074e-01 1 1 -6.5471291e-01 1.2246217e+00 -1.1532905e+00 4.7854448e-01 -5.4992522e-01 -5.1576553e-01 -5.1378113e-01 -2.8092040e-01
+1 8.6395347e-01 1 1 1.2392127e+00 -1.4982023e+00 2.7288473e-01 4.1986510e-01 -2.7662374e-02 -8.1715646e-01 1.1188278e+00 3.8452305e-01
+1 1.1706480e+00 1 1 -1.3113431e+00 -4.2103367e-01 -3.5169277e-01 6.5555822e-01 3.4187937e-02 1.0944831e+00 -1.4344351e+00 4.2286169e-01
+1 8.7037407e-01 1 1 -1.4705592e+00 -1.4462106e+00 -1.5645393e+00 4.0155260e-01 -3.1480007e-01 9.5213030e-01 3.1653760e-02 7.5381631e-01
+1 4.6029450e-01 1 1 -7.7931863e-01 4.1356647e-02 -8.1338426e-02 7.5350248e-01 -4.0272324e-01 -8.1910153e-01 1.0755940e+00 -6.5249744e-01
+1 1.0578673e+00 1 1 -7.0840890e-01 7.8918255e-01 -4.6212005e-01 3.5622796e-01 1.5627206e+00 -1.8047260e-01 7.8493795e-01 7.7552088e-01
+1 1.1816590e+00 1 1 4.0778031e-01 -1.3102970e-02 -8.3464853e-01 -7.5227481e-01 9.3064861e-01 -1.5661268e+00 9.0453998e-01 -2.8849710e-01
+1 1.0418086e+00 1 1 -1.3915332e+00 -3.1013609e-01 -7.2665396e-01 1.4277007e+00 -5.7870189e-01 1.5122241e+00 4.3654616e-01 -1.2932688e+00
+1 9.7212369e-01 1 1 -1.4820319e+00 -5.5497295e-01 -1.5024198e+00 -1.1925635e-01 1.2812218e-01 4.6574179e-01 1.4124767e+00 7.1022788e-01
+1 5.1892487e-01 1 1 1.1780111e+00 -4.1761794e-02 9.5230963e-01 -5.3316101e-03 1.3585672e+00 -1.1266867e+00 -1.5196321e+00 -1.2521730e+00
+1 7.2100170e-01 1 1 5.1508119e-01 -1.3153171e+00 -9.4656606e-01 1.4978166e+00 3.4282277e-01 1.2963551e+00 6.9081238e-01 2.5698323e-01
+1 8.8571507e-01 1 1 -1.2597911e+00 8.5273348e-01 8.9423766e-02 2.2220476e-01 1.4130380e-01 8.9584419e-01 -8.4285535e-01 -5.7269925e-01
+1 5.9829499e-01 1 1 1.0261200e+00 -5.4148244e-02 1.2639536e+00 -7.5824986e-01 -1.5106579e-01 -1.2003322e+00 -4.2864588e-01 4.8352126e-01
+1 2.0302710e-01 1 1 -1.3444532e+00 9.9232807e-01 -1.8102409e-01 1.5360174e+00 -5.5594653e-01 1.3244703e+00 -5.7931482e-01 -7.5837027e-01
+1 1.0506309e+00 1 1 1.2510305e+00 -6.5744713e-01 -1.4102065e+00 1.3777958e+00 -6.9681953e-01 -9.5374455e-01 -7.4847510e-01 -4.8778489e-01
+1 6.7180051e-01 1 1 -6.0971182e-01 -7.3255403e-01 -1.1653510e+00 -6.5753149e-02 4.1157998e-01 -1.1789739e+00 -6.8401445e-01 1.3561821e+00
+1 8.9158062e-01 1 1 4.4869120e-01 -1.3405495e-01 -1.3662793e+00 7.2743625e-01 -3.6231949e-01 -9.8922584e-01 -1.1433098e+00 1.0976565e+00
+1 6.5066796e-01 1 1 1.3305773e+00 -5.3965391e-01 -1.1563190e+00 -1.0576269e+00 -1.0971448e+00 -6.1029357e-01 1.5139529e+00 8.8134679e-01
+1 9.8559383e-01 1 1 1.1564722e+00 -1.8529823e-01 -3.6122820e-01 -4.0403694e-01 1.4364371e+00 9.6048513e-02 1.2469648e+00 1.8619676e-01
+1 4.4055292e-01 1 1 -2.0622542e-01 -9.8895581e-01 1.5362780e+00 1.4744076e+00 -9.4073973e-01 -4.9125924e-01 1.7222987e-01 3.8266231e-01
+1 1.1698255e+00 1 1 -8.5394963e-01 7.8643100e-01 -5.2593062e-01 -5.1418153e-01 6.2320759e-01 -4.8857484e-01 1.2605667e+00 5.6521426e-01
+1 3.4458708e-01 1 1 -1.5362049e+00 8.6553597e-01 1.1258098e+00 6.7242975e-01 1.8012442e-01 6.4589721e-01 -5.5651987e-01 -6.2008508e-01
+1 3.8530476e-01 1 1 -1.3868397e+00 1.4891089e+00 -3.2693233e-01 1.2180419e+00 -1.1442707e+00 1.3917745e+00 -9.0815921e-01 -1.1071594e+00
+1 5.1715164e-01 1 1 -1.1397088e+00 1.5262870e+00 -1.0620162e-01 1.0121592e+00 1.0719930e+00 -7.4437776e-01 1.5669317e+00 -3.7461297e-01
+1 9.3945828e-01 1 1 -7.9526761e-01 1.2009586e+00 -5.0594827e-01 -3.6453626e-01 -4.8319369e-02 -9.3499417e-01 -5.5033774e-01 -3.6857161e-01
+1 5.5239244e-01 1 1 1.4140255e+00 -2.2108006e-01 8.1878730e-01 -6.5521269e-01 1.5688692e+00 -2.0049602e-01 -6.7759382e-01 6.3762776e-01
+1 6.5065069e-01 1 1 -6.2191056e-01 8.1153015e-01 1.1822644e+00 -8.7742281e-01 5.9673958e-01 1.1922993e+00 -4.5924592e-02 6.3722642e-01
+1 1.2122632e+00 1 1 -3.7200788e-01 -1.4079938e+00 -2.5589873e-01 -2.0919922e-01 1.4384259e+00 -1.2449734e+00 9.7717188e-01 1.7504332e-01
+1 3.3357279e-01 1 1 -5.6704892e-01 1.4663995e+00 -4.9555533e-02 -5.6903979e-01 1.0681950e+00 -1.2600898e+00 -9.1857204e-01 1.4224116e+00
+1 4.4367667e-01 1 1 1.2009515e+00 -1.8053424e-02 -3.5778856e-01 -8.4378224e-01 -1.0492577e+00 -8.5376887e-01 -6.5400440e-01 -1.0484896e+00
+1 7.6595108e-01 1 1 -3.4072169e-01 1.3105963e+00 -3.4398893e-01 -2.9880438e-01 -1.1142301e+00 1.5017975e+00 5.8079835e-01 -7.7137727e-01
+1 7.1171959e-01 1 1 6.1399590e-01 1.4855249e+00 -8.9153469e-01 1.4014572e+00 1.6904616e-01 1.1550322e+00 5.4950635e-01 8.1518796e-01
+1 7.3890820e-01 1 1 -7.0269930e-01 9.7961880e-01 1.3734787e+00 -1.3707082e+00 1.1589935e+00 7.2517334e-01 -7.2910073e-01 3.7846262e-01
+1 1.0773998e+00 1 1 -1.0203028e+00 -6.3397922e-01 -3.6704841e-01 -1.9340675e-01 1.3287773e+00 -1.3912263e+00 1.3569404e+00 -9.0390643e-01
+1 2.9261951e-01 1 1 -1.4172473e+00 9.9354340e-01 1.1053427e+00 9.6119349e-01 -8.2195389e-01 5.3392292e-01 1.2765123e+00 7.8663320e-01
+1 2.1243484e-01 1 1 -1.2008713e-01 9.1896501e-01 1.2571160e+00 7.0948623e-01 -9.9614203e-01 1.2538172e+00 4.0579263e-01 1.1222720e+00
+1 6.7492786e-01 1 1 -1.4019208e+00 9.7537623e-01 1.1373510e+00 -1.1505865e+00 -6.1191034e-01 -8.9734669e-01 -2.4090190e-01 -9.6175795e-02
+1 1.1088233e+00 1 1 -1.3788429e-01 3.1781544e-01 -1.1330863e+00 -1.4037093e+00 1.1972265e+00 1.0804533e+00 6.7462547e-01 1.4936370e+00
+1 3.0567933e-01 1 1 1.0740708e+00 8.1655886e-01 5.5287899e-01 1.2188087e+00 -1.1551772e-01 7.7339700e-01 4.2244658e-01 -9.1024253e-01
+1 9.3659261e-01 1 1 3.1611660e-01 1.4280639e+00 -5.9394546e-01 1.3332277e+00 -2.0707188e-03 -1.4270139e+00 6.0193295e-02 1.1100722e+00
+1 5.8952010e-01 1 1 5.3848966e-01 -2.9818617e-01 1.5401402e+00 -1.4226466e+00 -2.4505251e-01 -9.0435264e-01 7.5880378e-02 -9.3538908e-01
+1 5.3061783e-01 1 1 -5.3279711e-01 -7.7463063e-01 1.5537985e+00 2.4087587e-01 3.0505839e-02 -4.2959211e-01 -1.6510368e-01 -5.5464268e-01
+1 1.0821121e+00 1 1 -1.1818998e+00 -4.5708326e-01 -1.3684590e+00 -1.1121067e+00 6.3204010e-01 -7.7473823e-01 -8.7121291e-01 -7.7405258e-01
+1 4.0459906e-01 1 1 1.0062186e-01 -1.0042651e+00 -9.0509658e-02 1.2995721e+00 9.7323750e-01 8.7604235e-01 4.8805703e-01 -1.6654800e-01
+1 5.8105366e-01 1 1 9.7468140e-01 1.0929810e+00 -6.6498297e-01 1.5561630e+00 -1.0703113e+00 -1.0009077e+00 7.6144837e-02 -1.3231719e-02
+1 3.8433483e-01 1 1 1.2061945e+00 8.3930794e-01 1.4178461e+00 6.7245543e-01 3.7979965e-02 9.7277294e-01 1.1380663e+00 6.6758062e-01
+1 7.7329463e-01 1 1 -1.8684782e-01 4.9759363e-01 7.5880263e-01 -1.4919459e+00 5.8596973e-01 5.4665802e-01 1.4650374e+00 1.4001693e+00
+1 5.4684091e-01 1 1 1.2413431e+00 1.3654085e-01 1.4712672e+00 1.0571879e+00 -4.9977296e-01 -1.4772535e+00 -9.1900009e-01 -1.0256952e+00
+1 8.4130081e-01 1 1 -6.3535879e-02 1.4794727e+00 1.1136441e-01 -6.9180912e-01 9.3457934e-01 -1.9342688e-01 -1.5650280e+00 -9.4087169e-01
+1 6.5063336e-01 1 1 2.9398675e-01 -2.0756743e-01 -6.8751077e-01 -2.0151712e-01 -4.8838165e-01 6.2289732e-01 1.1297197e+00 1.5469307e+00
+1 1.0477450e+00 1 1 -6.8986766e-01 -1.4179033e+00 -2.1567646e-01 -2.6140194e-01 7.5122490e-01 1.2484985e+00 -5.8671014e-01 -5.5702412e-01
+1 9.2009490e-01 1 1 1.0127572e+00 1.4218706e+00 5.2364050e-01 -1.4358127e+00 -2.2398169e-01 8.1721897e-01 6.2193909e-01 4.1733017e-02
+1 6.1730605e-01 1 1 2.6112341e-01 -7.1677036e-01 1.2248357e+00 -1.1307785e+00 -8.3223833e-01 -4.3918456e-02 8.5145953e-01 8.3166104e-01
+1 5.7719062e-01 1 1 -1.0383764e-01 1.2483105e+00 -1.0422848e+00 -1.4996214e+00 -1.0591769e+00 1.3678273e-01 5.2579601e-01 7.8142700e-01
+1 3.0280125e-01 1 1 1.5263114e+00 7.9917606e-01 -1.6025020e-01 8.6078278e-01 -1.3218217e+00 -7.3847890e-01 -2.4658969e-01 -1.5552674e+00
+1 9.5243824e-01 1 1 -1.5292153e+00 1.4434971e+00 -9.8024236e-01 1.4197807e-01 1.4853123e+00 8.1770328e-01 -6.7221415e-01 -1.3276776e+00
+1 4.7134907e-01 1 1 -1.5256507e-01 1.4778051e+00 -4.2139206e-01 -1.3849451e+00 5.4850986e-01 -1.3287876e+00 -7.3611106e-01 4.5535748e-01
+1 1.3970091e+00 1 1 -6.2148758e-01 3.9055585e-02 -1.1865362e+00 -7.1178436e-01 1.3722993e+00 6.4954799e-01 -2.2679305e-01 2.7339689e-01
+1 4.5541221e-01 1 1 4.5389461e-01 -1.8565269e-01 7.1671031e-01 2.2507327e-01 -1.3392531e+00 -8.1331443e-02 -9.5884969e-01 -1.1685925e+00
+1 6.5627668e-01 1 1 8.1980826e-01 -6.6326461e-01 8.8387659e-01 3.2881379e-01 6.8422709e-01 -3.4476504e-01 9.8364134e-01 7.0350205e-01
+1 5.1652363e-01 1 1 -5.0793821e-01 -1.1175849e+00 -1.2778116e+00 3.1195553e-01 -1.5660675e+00 -1.3691503e+00 9.9946231e-01 -1.1957434e+00
+1 7.8297725e-01 1 1 -1.2103335e+00 3.3282284e-01 -2.5251117e-01 -2.8155185e-01 -6.3247794e-01 8.5734597e-01 -1.3283881e-01 -9.1613996e-02
+1 1.0338823e+00 1 1 -2.6337665e-01 -1.4230377e+00 3.3641442e-01 -8.0347193e-01 1.0928673e+00 -1.0717713e+00 1.0505517e+00 -3.7603314e-01
+1 8.7712075e-01 1 1 -6.7289108e-02 -4.9614354e-02 -7.4957301e-01 -1.3875149e+00 -1.0708028e+00 6.3194311e-01 8.7137721e-01 8.9546824e-01
+1 1.1623576e+00 1 1 4.5320379e-02 -1.3463933e+00 -2.8695441e-01 8.0081978e-02 1.2008471e+00 -6.5692270e-01 -8.6825405e-01 -1.2356558e+00
+1 6.3169895e-01 1 1 1.4341915e+00 6.0064930e-02 -4.9810073e-01 1.3361526e+00 1.0455124e+00 -1.3432895e+00 -4.7913358e-02 1.4017208e+00
+1 7.6335268e-01 1 1 -9.8435692e-01 1.0600389e+00 7.6545538e-01 6.1198566e-01 9.9944135e-01 -1.1824246e+00 -1.0320824e+00 -8.1995462e-02
+1 7.6843838e-01 1 1 -4.5990279e-01 1.0269067e-01 1.8665453e-01 6.8673404e-02 -4.8519889e-01 7.0410411e-01 -1.4766101e+00 1.0614464e+00
+1 6.9504555e-01 1 1 -1.2682947e+00 1.1877828e+00 -1.3483181e+00 1.2294019e+00 8.3679181e-01 -5.0168200e-01 1.1968229e+00 -1.3755534e+00
+1 7.6207905e-01 1 1 -5.2320726e-01 1.3850579e+00 -8.7492265e-01 3.0246520e-01 -9.5034559e-01 2.6538008e-01 -6.1455712e-01 5.3901476e-02
+1 6.6993985e-01 1 1 -2.2650277e-01 -5.3336802e-01 9.7022250e-01 4.3572271e-01 -6.0134621e-01 -8.1856190e-01 6.9506510e-01 1.1434283e+00
+1 9.0683348e-01 1 1 7.7826097e-01 -1.3524738e+00 -1.4779263e+00 1.3909431e-01 -3.2210953e-01 -5.3554973e-01 1.5177258e+00 4.7781223e-01
+1 7.4935992e-01 1 1 -1.3597527e+00 1.5376260e+00 1.0654822e+00 4.1306501e-01 -7.3080141e-01 -3.2138166e-01 -1.3151645e+00 6.7927733e-01
+1 8.8580831e-01 1 1 -1.4181465e+00 1.3831445e-01 4.8175515e-01 -5.3620923e-01 1.0479896e+00 -1.0637541e+00 2.7682184e-01 6.6343856e-02
+1 2.8945070e-01 1 1 4.7592890e-01 -1.2751858e-01 9.7445866e-01 1.1608290e+00 -1.3486759e+00 2.8781347e-01 -1.5407370e-01 -2.2419657e-01
+1 6.5792007e-01 1 1 4.4207630e-01 -6.3851699e-01 6.0415487e-01 7.6234360e-01 -6.0447903e-01 -7.7168010e-01 -8.4433793e-01 -1.3021460e+00
+1 7.4689182e-01 1 1 1.0981734e-01 1.2551585e-01 4.0350491e-01 1.2940863e+00 4.3151147e-01 -1.1329306e+00 -2.1364624e-01 -8.3301805e-01
+1 8.0597921e-01 1 1 -1.5564898e+00 1.5361945e+00 -9.9155047e-01 4.6195335e-01 -1.5241920e+00 2.8576016e-02 8.8105238e-02 1.5440942e+00
+1 1.8312788e-01 1 1 1.1727120e-01 1.2119259e+00 1.1603138e+00 1.1744733e+00 -5.4870415e-01 -3.8656876e-01 1.0946010e+00 -1.1053316e+00
+1 5.2510151e-01 1 1 1.1985480e+00 -1.2473514e+00 1.5292574e+00 7.4539516e-01 -1.4962149e+00 -2.4760721e-01 -2.0758134e-01 -1.0715067e+00
+1 5.7628788e-01 1 1 1.0418962e-01 -3.8679463e-01 8.5971937e-01 -8.1505384e-01 1.5646415e+00 1.0759406e+00 1.4898153e+00 -1.2040700e+00
+1 5.0434507e-01 1 1 1.2477917e+00 -9.0206686e-01 1.1188796e+00 -1.2659441e+00 -1.3428830e+00 3.2691809e-01 8.3300787e-01 1.3359617e+00
+1 3.5653543e-01 1 1 1.5035399e+00 2.8850291e-01 -5.6488189e-01 1.2851117e+00 -6.3295676e-01 -1.3315540e-01 1.4263465e+00 5.4619429e-01
+1 9.5473533e-01 1 1 -9.7677427e-01 1.3909786e+00 -7.6996741e-02 4.2202608e-01 -6.7160478e-01 -1.1288347e+00 -8.8814482e-01 1.5373049e-01
+1 2.5725780e-01 1 1 1.3181068e+00 -1.5547820e+00 2.5194620e-01 -7.2393544e-01 8.0788341e-02 -2.4642546e-01 -1.3432716e+00 1.3592281e+00
+1 1.0482351e+00 1 1 -1.0906283e+00 5.4704383e-01 -4.0709036e-01 2.0547643e-01 6.4161953e-01 -1.0535668e+00 -8.8059139e-01 -1.1145793e+00
+1 7.7917105e-01 1 1 1.0030397e+00 -1.2760397e+00 4.2110642e-01 8.3203439e-01 -1.3882162e+00 -1.2805167e+00 -5.6515537e-02 5.8226802e-01
+1 9.9086793e-01 1 1 3.0267034e-01 1.2544295e+00 -4.7268203e-01 7.7303445e-01 8.5971155e-01 1.4077323e+00 -1.0956464e+00 1.1742576e-01
+1 7.4478450e-01 1 1 7.4185459e-01 -3.1739918e-02 7.2100287e-01 -1.2372657e+00 9.8733770e-01 4.2269748e-01 1.4875209e+00 6.5452605e-01
+1 4.2071889e-01 1 1 -6.3120980e-01 6.1795628e-01 7.7240086e-01 -5.2264201e-01 2.9224962e-01 1.1356115e+00 -3.1258445e-02 -1.2382005e+00
+1 7.0480579e-01 1 1 4.1526248e-01 -1.1419191e-01 6.8040999e-01 -1.5122901e-01 1.5300104e+00 1.0470095e+00 -7.1471048e-01 -5.2571926e-01
+1 6.2511467e-01 1 1 -1.3024473e+00 2.8975106e-01 2.5342804e-01 -1.5755494e-01 9.4873326e-01 1.0287653e+00 1.3113312e+00 1.5364867e+00
+1 2.3842084e-01 1 1 3.8516625e-01 3.7753632e-01 -6.3450657e-01 3.3669178e-01 -1.3643970e+00 -8.6673157e-01 1.2712794e+00 -1.5892068e-01
+1 4.7418794e-01 1 1 -1.3332757e+00 -7.6430379e-01 1.5551290e+00 7.7035834e-01 -9.3495217e-01 4.0770463e-01 4.2189052e-01 -6.2604268e-01
+1 6.8863348e-01 1 1 6.1633182e-01 3.1853968e-01 -9.9844971e-01 9.0933847e-01 5.0530598e-01 4.7816032e-01 1.3935215e-01 -7.0556578e-01
+1 5.3968927e-01 1 1 8.5797668e-01 4.2248218e-01 1.4436635e+00 -5.9662020e-01 9.5274168e-01 2.4653318e-01 -1.5366150e+00 1.0682058e+00
+1 2.0830933e-01 1 1 1.0385628e-01 6.5864731e-01 1.1317844e+00 5.6804241e-01 3.1703709e-02 -2.7754269e-01 1.1450462e+00 -8.6792660e-01
+1 6.9518054e-01 1 1 -1.2129468e+00 -1.0872522e+00 -4.4314157e-01 -2.1135946e-01 -1.2265157e+00 6.0516824e-01 -6.0463024e-01 -8.2775591e-01
+1 6.7355710e-01 1 1 -2.0145701e-01 1.1969094e+00 8.3578456e-01 8.2282125e-01 1.0824486e+00 -1.4143302e+00 1.0317399e+00 -1.1213593e+00
+1 5.8133088e-01 1 1 7.4893792e-01 8.3847643e-01 9.7036261e-01 -1.3403231e-01 -2.4994598e-01 -1.3574338e+00 -1.1387823e+00 -2.7130161e-01
+1 7.9294741e-01 1 1 -9.6209075e-01 -9.1133836e-01 8.7699267e-01 -1.5906765e-01 -5.3277886e-01 -1.4435468e-01 -9.3105923e-01 -1.3152627e+00
+1 6.1979925e-01 1 1 -8.1801810e-02 1.5419970e+00 -7.3693500e-01 4.5365889e-02 -8.7527202e-01 -8.5950273e-01 -3.9413630e-02 -1.3748768e+00
+1 1.1683718e+00 1 1 1.1745682e+00 1.3452816e+00 -1.5082892e+00 -9.4251598e-01 1.3816249e+00 -6.1936885e-01 4.5117885e-01 -1.1405152e+00
+1 1.0162213e+00 1 1 -8.0011524e-01 1.0538308e-01 -3.0625757e-01 -9.5592128e-01 1.4584021e+00 1.5058151e+00 -8.4166721e-01 1.3587696e+00
+1 1.3820534e+00 1 1 -1.5202870e+00 -6.8489469e-01 -1.3421722e+00 -6.4162129e-02 6.5891401e-01 -4.3646975e-01 6.9098406e-01 6.0344362e-01
+1 7.7484366e-01 1 1 -8.9055425e-01 -2.2957717e-01 -1.2522774e+00 -8.0662509e-01 2.5365929e-01 -1.2821014e-01 -1.0988621e+00 1.0157936e+00
+1 1.1584408e+00 1 1 -9.9784034e-01 -6.2779370e-01 -1.4965559e+00 -9.7563224e-01 1.1040962e-01 3.0474082e-01 8.4795371e-01 1.0278109e+00
+1 1.0825620e+00 1 1 -8.8105437e-01 1.2809545e+00 -1.0235573e+00 -1.4789694e+00 -1.0267205e+00 9.8301001e-01 1.2937597e+00 -1.2009009e+00
+1 1.0854435e+00 1 1 -1.5546338e+00 -3.3145771e-01 4.3333863e-01 -7.5808523e-01 6.7689684e-01 -1.8651652e-01 1.2562778e+00 1.1910968e+00
+1 4.1287953e-01 1 1 -1.0471952e-01 -7.6592587e-01 9.1057365e-01 1.1613034e+00 8.9813576e-01 5.2638632e-01 -3.8320717e-01 5.3564077e-01
+1 3.9098720e-01 1 1 -7.2903712e-01 1.3306626e+00 1.3135886e+00 -6.8964514e-01 -3.8492080e-01 2.5001142e-01 -2.9801202e-01 -1.2900964e+00
+1 2.9086535e-01 1 1 -7.1549964e-01 -5.5224850e-01 1.5126028e+00 -1.5306069e+00 -8.2458470e-01 -1.5089517e+00 -9.8925701e-01 6.2277421e-01
+1 7.2787717e-01 1 1 6.1420052e-01 -1.3759044e+00 5.4792871e-01 -1.5492893e+00 -1.2298597e+00 1.1262130e+00 -1.1342482e+00 -8.2059353e-01
+1 7.6976622e-01 1 1 -4.0527131e-01 4.3838082e-01 1.0298111e+00 -1.3858363e+00 1.4283923e+00 1.6679622e-01 -1.2469653e-01 -1.2364283e-01
+1 1.7848799e-01 1 1 -4.2205695e-01 8.3173322e-01 1.0018552e+00 1.7297941e-02 -1.0617765e+00 1.0434094e+00 -3.3234484e-01 -1.4723337e+00
+1 7.2912412e-01 1 1 2.0511957e-01 -1.1471530e+00 -7.5662246e-01 -1.4416298e+00 -1.0320519e+00 2.1077672e-01 3.1951600e-02 8.1363336e-01
+1 2.5467947e-01 1 1 1.1175500e+00 -2.4592052e-01 6.1339216e-01 -1.5094904e+00 -9.6357220e-01 -1.1921095e+00 -2.0179639e-01 -6.1699334e-01
+1 8.5526518e-01 1 1 -9.1969625e-01 1.1496897e+00 -1.4250853e+00 1.4969031e+00 1.5220379e-01 1.2933078e+00 1.3281238e+00 5.9022977e-01
+1 5.6345766e-01 1 1 -6.9899878e-01 -1.1020606e+00 9.4438890e-02 5.7608541e-01 8.3262671e-01 -5.5936189e-02 7.6116288e-01 -1.1578482e+00
+1 7.8712157e-01 1 1 1.4839541e+00 4.9851628e-01 7.3012586e-01 -1.2105673e-01 1.3034431e+00 -7.8332680e-01 2.9928586e-01 -9.2916081e-01
+1 4.1099731e-01 1 1 -2.8723139e-01 -6.4456189e-02 1.6440040e-01 1.1515898e+00 6.4177385e-01 1.0412137e+00 4.0769000e-01 4.5135585e-01
+1 5.8773543e-01 1 1 1.1300024e+00 5.3429883e-01 -1.5240659e+00 -5.8203223e-01 1.2055927e+00 1.0083144e+00 2.3218933e-01 -1.0084959e+00
+1 3.9830109e-01 1 1 1.0234073e+00 1.2886491e+00 1.5705213e+00 7.0378472e-01 -8.7626226e-01 9.8974362e-01 5.4802371e-01 -8.9893870e-01
+1 9.5333399e-01 1 1 1.8651045e-01 1.8541777e-01 9.0401300e-02 4.1339051e-01 4.4654281e-01 -1.1214188e-01 -5.1518293e-01 -5.4367440e-01
+1 7.8453966e-01 1 1 -6.2834971e-01 -1.4348855e-01 -1.1561957e+00 -1.3486053e+00 -2.1977616e-01 1.8707819e-01 -4.5015481e-01 1.3573980e+00
+1 1.0252533e+00 1 1 1.3609739e+00 1.1310656e+00 -1.4303112e+00 5.8136472e-01 7.3501013e-01 -5.1115467e-01 -7.9682838e-01 -4.5761531e-01
+1 1.0694003e-01 1 1 -4.6988480e-02 4.2080095e-02 2.2698206e-01 6.4363854e-01 5.7300662e-01 1.2794475e+00 3.1483587e-01 -5.2175223e-01
+1 2.9955694e-01 1 1 -1.1956331e+00 3.8180416e-01 9.9402991e-01 1.1294782e+00 1.5407686e+00 -5.2743419e-01 1.0043982e+00 -9.0462812e-01
+1 1.1269213e+00 1 1 -1.3786139e+00 -1.2912797e+00 -3.2899862e-01 -1.5041798e+00 -4.4976050e-01 9.8808057e-01 1.1428619e+00 1.2236638e+00
+1 9.5909818e-01 1 1 -1.1180087e+00 -4.1584070e-01 -2.7674242e-01 -3.5311382e-01 -4.5276251e-01 2.1134092e-01 3.8203269e-01 1.2524244e+00
+1 7.1479456e-01 1 1 -5.0616008e-01 1.0090354e+00 1.4888917e+00 -3.1542391e-01 -6.4204265e-01 -1.1343911e+00 -5.9192371e-01 8.2640124e-01
+1 6.9454787e-01 1 1 4.0048832e-01 5.4041936e-01 1.0170643e+00 -1.4627661e+00 5.6000246e-01 6.1516298e-01 9.6222005e-01 3.4450455e-01
+1 8.5493873e-01 1 1 -1.4258673e+00 4.8374643e-01 3.9377462e-01 1.3942959e+00 -2.5025022e-01 6.2800280e-02 -8.8654715e-01 1.3268551e-01
+1 1.1165181e+00 1 1 -4.8265678e-01 -1.1554040e-01 -1.1656338e+00 7.9128883e-01 6.3704229e-01 -9.0830182e-02 3.7598427e-01 -4.8548303e-01
+1 2.1424098e-01 1 1 -4.2026557e-01 -3.8324708e-01 1.6376981e-01 8.2965363e-01 2.2200915e-01 2.3115734e-01 1.4247377e+00 -7.9710151e-01
+1 7.7595883e-01 1 1 -1.1030873e+00 -9.6865423e-01 4.4403823e-01 -1.5411674e+00 -9.0434323e-01 -1.0886560e+00 3.4693539e-01 -1.1339399e+00
+1 8.8429359e-01 1 1 -1.0500672e+00 -4.3856533e-01 -1.4735744e+00 3.0605116e-02 -2.7147142e-01 -4.0511852e-01 1.4708888e-01 -1.2274928e+00
+1 7.9966761e-01 1 1 9.8775589e-01 -7.9108632e-01 -1.1892203e+00 -8.4101163e-01 -1.0275876e+00 -9.9568197e-01 -3.1056905e-01 3.6739791e-01
+1 4.8612001e-01 1 1 1.0376534e+00 -5.6765590e-01 -4.1294264e-01 -8.5712044e-01 -1.3298991e+00 8.3723012e-01 -1.5487081e+00 -1.5144831e+00
+1 8.5802461e-01 1 1 8.6000911e-01 4.2425228e-01 -5.4873254e-01 -1.4209922e+00 8.1806941e-01 1.3318225e-01 -1.0420204e+00 -7.3305391e-01
+1 7.0214339e-01 1 1 -2.9465056e-01 -1.0071813e+00 1.1682373e+00 -2.2826188e-01 -1.4584937e+00 -1.5614342e+00 1.1414938e+00 8.8930402e-01
+1 1.1354147e+00 1 1 -1.0418747e+00 -7.9540619e-01 -3.9042412e-01 -5.1275435e-01 9.4415518e-01 -1.3003718e+00 -6.2065607e-01 -1.1652485e+00
+1 7.6188482e-01 1 1 4.4982529e-01 -9.1502769e-01 9.2885757e-01 -4.7368958e-01 2.3154314e-01 7.1205747e-01 -1.2790119e+00 3.5699282e-01
+1 4.5357034e-01 1 1 1.5416587e+00 -7.7433953e-01 7.3533217e-01 -5.0506949e-01 -8.8773714e-01 1.2234075e+00 1.5651560e+00 -4.6361234e-01
+1 6.2614416e-01 1 1 -1.1988568e+00 1.2938209e+00 -2.9778423e-01 -1.1950804e-01 -7.7452728e-01 8.5812056e-02 1.0209529e+00 -7.8276080e-01
+1 8.6586437e-01 1 1 9.8850129e-01 -8.5732134e-01 -3.0239135e-01 -1.0938548e+00 1.2799578e+00 2.5219277e-01 -2.2423963e-01 1.1292729e+00
+1 2.6965782e-01 1 1 9.9918233e-01 1.4857962e+00 8.0554074e-01 1.8223987e-01 -1.3760515e+00 5.9532825e-01 1.1157943e+00 1.3280355e+00
+1 1.1229057e+00 1 1 1.4447129e+00 -7.4248148e-01 -1.5411977e+00 -1.4742575e-01 1.1080683e+00 -2.9069361e-01 9.8853822e-01 -7.2317026e-01
+1 1.0193810e+00 1 1 -7.9114081e-02 -4.8026962e-01 -4.7876924e-01 9.3209422e-01 -5.7553525e-02 -5.1095065e-01 -1.5216065e+00 4.9949893e-01
+1 1.2664456e+00 1 1 -7.7666553e-01 -1.1399150e+00 -1.0557614e+00 -1.4150709e+00 3.0843424e-01 1.5666718e+00 -1.0760607e+00 7.4289506e-01
+1 1.0659633e+00 1 1 -1.0012889e-01 -1.1187581e+00 -4.6586623e-01 -1.2398163e+00 2.2637692e-01 1.3645759e+00 7.9669944e-01 1.1480760e+00
+1 5.6655092e-01 1 1 1.0273529e+00 -5.3527939e-01 -9.6477970e-01 5.9085033e-01 2.4811394e-01 8.0023440e-01 6.5961073e-01 5.1266996e-02
+1 1.1105931e+00 1 1 5.2653895e-01 1.0806538e+00 -1.2928140e+00 -1.5288077e-01 1.1575090e+00 3.8144995e-01 -6.0285466e-01 8.4802127e-01
+1 1.1941999e+00 1 1 -3.2639196e-01 1.0005792e+00 -1.0702713e+00 3.5564319e-01 1.5115676e+00 -9.6131032e-01 -5.4188649e-01 -7.1241770e-01
+1 6.1437852e-01 1 1 -4.4886218e-01 -2.1132166e-01 7.0970402e-01 -1.1557640e+00 -1.1425725e+00 4.6854292e-01 -9.0561044e-03 -9.9461470e-01
+1 6.2676065e-01 1 1 -1.0626458e+00 1.4581562e+00 -6.3179933e-01 -4.5742602e-01 1.3402518e+00 -1.1719895e+00 -1.4094994e+00 -7.4785573e-02
+1 7.0533530e-01 1 1 6.7093295e-02 -3.3369428e-01 -6.8110691e-02 -4.8192501e-01 3.9333820e-01 1.5764112e-01 1.2945677e+00 -2.8405677e-01
+1 1.2293384e+00 1 1 -1.9475762e-01 -6.5692991e-01 -1.1966641e+00 -6.8779160e-01 9.2412395e-01 1.1116702e+00 -8.7122974e-01 1.0787166e+00
+1 3.1818649e-01 1 1 2.4819187e-01 -1.4644556e+00 1.4284631e-01 1.3476147e+00 -2.8291942e-01 7.8939890e-01 2.0518056e-01 -1.4067097e-01
+1 4.6619400e-01 1 1 -6.7434471e-01 1.2736098e+00 6.4117643e-01 -1.5231100e+00 1.3445784e+00 4.8149029e-01 -9.9907338e-01 1.3623203e+00
+1 7.4713393e-01 1 1 1.1547977e+00 -1.2531954e+00 5.8942371e-01 -1.2120197e+00 8.5354095e-01 -3.3542369e-01 3.8649731e-01 5.9053024e-01
+1 5.8493912e-01 1 1 -7.4719980e-02 -1.2174943e+00 1.0026555e+00 -3.2780712e-01 9.5061830e-01 -1.4487746e+00 -9.5325936e-01 7.5051279e-01
+1 6.8149518e-02 1 1 8.1836239e-01 -1.2329899e+00 1.2774025e-01 8.9931530e-01 -1.0985026e+00 9.3012139e-01 6.9242825e-01 3.7387424e-01
+1 3.0849054e-01 1 1 3.2412800e-01 -9.1554357e-01 1.2226079e+00 5.8991475e-01 6.0681811e-01 -1.4780544e-02 1.1824873e+00 5.1896392e-01
+1 1.1028627e+00 1 1 9.7559958e-02 -1.9916061e-02 -7.8682253e-01 -1.6928432e-01 1.1822976e+00 -2.3078023e-01 3.4963227e-01 1.1653154e+00
+1 7.3120913e-01 1 1 -2.2115216e-01 1.4211821e+00 -1.1627631e+00 1.1213606e+00 3.0208465e-01 1.1435756e+00 1.4912411e+00 7.6649763e-01
+1 4.2047081e-01 1 1 -4.0025316e-01 2.7868621e-01 1.2882799e+00 2.9402024e-01 3.2292464e-01 -1.8855596e-01 -3.3671524e-01 -1.1458526e+00
+1 6.6930011e-01 1 1 -9.0498907e-01 -2.3554821e-01 2.6314641e-01 -1.2699142e-01 -1.2777038e+00 8.0704641e-01 -1.1647135e+00 -3.8090906e-01
+1 5.4612087e-01 1 1 1.4403105e+00 -4.5198494e-01 -6.6078481e-01 -1.2033727e+00 1.5601111e+00 -1.3681366e+00 -7.5509601e-02 6.2727989e-01
+1 1.0369897e+00 1 1 1.3273278e+00 -1.3981520e-01 -2.8027039e-01 4.8933187e-01 1.0552658e+00 -9.5483405e-01 1.1356048e-01 -4.9191220e-01
+1 6.8543397e-01 1 1 -5.0642810e-02 3.7291920e-02 -1.2571114e+00 -4.8877660e-01 1.5612659e+00 -6.4066002e-01 -1.4774264e+00 1.1034917e+00
+1 1.2697686e+00 1 1 2.1789795e-01 -1.5532327e+00 -1.0608600e+00 3.9648815e-01 -1.5278029e+00 -1.3348974e+00 4.2590422e-02 1.5635639e+00
+1 1.1308161e+00 1 1 -8.8620491e-01 1.4521908e+00 -1.3360204e+00 4.5832146e-01 -1.5465240e+00 -1.5077779e+00 -4.6590339e-01 -6.0349449e-01
+1 1.2467565e+00 1 1 -1.5510894e-01 -6.3052440e-02 -1.5325616e+00 -1.7644432e-01 1.1083115e+00 -1.1370245e+00 1.5521489e+00 1.2708507e+00
+1 9.0122560e-01 1 1 6.0599132e-01 -1.0056347e+00 1.5588308e-01 1.6379519e-01 8.8784722e-01 3.3740957e-01 -8.1857667e-01 -4.9992689e-01
+1 8.2240335e-01 1 1 -1.4721754e-01 6.5827900e-02 -1.6137183e-01 8.7052892e-01 -5.1687374e-01 2.6785183e-01 -7.8380734e-01 1.4891001e+00
+1 8.2541536e-01 1 1 1.2898839e+00 5.2889919e-01 -9.8193857e-01 5.8251363e-01 -5.9333829e-01 -1.1657568e-01 -7.5192713e-01 1.3775094e+00
+1 6.6942796e-01 1 1 -1.0515965e+00 -1.4984962e+00 -6.5535172e-01 1.1038872e+00 -8.2150775e-01 1.0664183e+00 9.8789999e-01 1.4046719e+00
+1 8.5982477e-01 1 1 4.1731538e-01 9.2286531e-01 -7.2431629e-02 -1.2134571e+00 2.1902603e-01 5.0671506e-01 3.1802921e-01 -7.4825377e-01
+1 5.8278723e-01 1 1 -1.3568554e+00 5.5440432e-01 -1.5620338e+00 6.4664394e-01 -7.7617721e-01 -4.9764505e-01 1.2678539e+00 -1.0565238e-01
+1 5.9185147e-01 1 1 1.5205693e-01 -9.0480653e-02 1.1884169e+00 1.3757270e+00 -1.3176043e+00 -1.0006603e+00 -6.0170096e-01 -6.9973294e-01
+1 9.1254177e-01 1 1 1.5060760e+00 -1.7749129e-01 -5.2329920e-01 -2.7760055e-01 1.1093633e-01 -1.1513783e+00 -1.2374392e-03 -1.4302635e+00
+1 5.0409540e-01 1 1 8.0774002e-01 1.4169838e+00 1.3697803e+00 -3.6743016e-01 1.5424190e+00 9.9595468e-01 1.1935071e+00 1.0281827e+00
+1 2.3418930e-01 1 1 8.6464502e-01 -1.1678634e+00 3.0706983e-01 9.7238306e-01 -9.8616901e-01 6.0458749e-01 2.0537988e-01 -1.2353560e+00
+1 1.0343033e+00 1 1 -9.1872987e-01 3.9107968e-01 -7.1415525e-01 2.7704237e-01 5.0036971e-01 1.3912408e+00 -7.9070046e-01 1.5803950e-01
+1 6.7396609e-01 1 1 -1.6498415e-01 6.6433552e-01 1.2183051e+00 4.1086372e-01 -3.2979426e-01 -2.9043524e-01 -3.6572899e-01 1.5240149e+00
+1 6.9675948e-01 1 1 1.1376895e+00 2.6686527e-01 -8.4627746e-01 1.6588071e-01 -1.0826472e+00 6.8993635e-01 1.2896444e+00 7.1354132e-01
+1 8.3814995e-01 1 1 1.4147648e+00 -9.8974703e-01 -1.3953178e+00 1.3644414e+00 5.3694590e-02 1.4181156e-01 1.2050555e+00 1.0297742e+00
+1 5.6843880e-01 1 1 -7.6313181e-01 5.4730614e-02 8.8224361e-01 -1.4594827e+00 8.0789009e-01 -1.0419486e+00 -4.8078826e-01 3.8078089e-01
+1 7.6782535e-01 1 1 1.1664312e+00 -6.2921122e-01 -4.4893760e-01 2.9726391e-02 2.4533686e-01 -7.9239706e-01 -4.3193683e-01 3.6012421e-01
+1 3.3854071e-01 1 1 6.7063158e-01 -5.5204613e-01 8.1122756e-01 9.8218018e-02 -1.5344925e+00 -6.0615510e-01 6.5831063e-01 -1.2415256e+00
+1 6.4157861e-01 1 1 -7.2950256e-01 -1.1162670e+00 -2.1048734e-01 1.4140852e+00 -8.8133835e-01 5.3626597e-01 -4.6255527e-01 1.3838366e-01
+1 7.0547038e-01 1 1 8.8656976e-01 4.9130789e-01 -2.2746907e-01 3.8083184e-01 -4.4229897e-02 -2.0723653e-01 1.2753692e+00 1.0356065e+00
+1 6.7185807e-01 1 1 4.0610760e-03 1.3062243e+00 2.4567239e-01 1.2164249e+00 1.1855854e+00 1.0018974e+00 4.2884918e-02 1.0158642e+00
+1 4.5814962e-01 1 1 -8.6053488e-01 2.6247766e-01 9.6317600e-01 -1.0324599e+00 -9.8891975e-01 -4.7451999e-02 1.3420923e+00 -9.2574978e-01
+1 1.0047269e+00 1 1 8.8288871e-01 6.6593597e-01 -5.2798723e-01 -1.5374798e+00 1.3924825e+00 4.3879316e-01 -8.9277526e-02 1.2319022e+00
+1 3.5590223e-01 1 1 9.6845655e-01 -1.1087312e+00 1.1177908e+00 -8.2376235e-01 -1.4123074e+00 1.4787142e+00 1.1939122e+00 1.4850341e+00
+1 8.9893535e-01 1 1 2.5775474e-01 1.4831397e+00 -1.3536777e-02 2.4934774e-02 1.2239170e+00 -3.9013586e-01 7.3077683e-01 -9.8575587e-01
+1 1.2664585e+00 1 1 -1.7243519e-01 -1.4088120e+00 -1.3179352e+00 1.2469199e+00 -7.7618070e-01 -5.0945650e-01 -1.4611048e+00 1.1607999e+00
+1 4.1388308e-01 1 1 -1.5697966e+00 2.8020353e-01 8.3358891e-01 -5.8127143e-01 -1.3762941e+00 1.5461082e+00 1.0410625e+00 2.7381925e-01
+1 9.4191099e-01 1 1 -4.7570032e-01 1.3335050e-01 -1.3744791e+00 9.2424212e-01 1.7156813e-01 1.3280776e+00 -1.5337628e+00 -3.5309040e-01
+1 6.7223892e-01 1 1 2.5794355e-01 1.2662979e+00 -7.3999700e-01 -1.4383775e+00 -4.3648301e-01 -1.5893014e-02 -1.1839750e+00 7.8218194e-02
+1 7.2355787e-01 1 1 -1.4069718e-01 1.5205861e+00 4.3569956e-01 -2.5452863e-01 -3.5114286e-01 -7.8510999e-02 -2.1977832e-01 1.4274620e+00
+1 4.1852957e-01 1 1 9.2176573e-01 -3.6583866e-01 -2.4992539e-01 9.8649815e-01 1.3944805e+00 -6.5442188e-02 6.9871933e-01 -9.8951841e-01
+1 9.3075091e-01 1 1 9.2326276e-01 -5.5356448e-01 -1.8661477e-01 -1.2516173e+00 7.5224011e-01 -3.2943102e-01 1.0247364e-01 7.5551267e-01
+1 1.4585206e+00 1 1 9.5106235e-01 -1.5024506e+00 -1.1249681e+00 1.7280858e-01 1.1306083e+00 -1.2608148e+00 6.8168266e-01 -4.1607906e-01
+1 6.7894493e-01 1 1 8.1505671e-02 4.3472314e-01 -1.2342813e+00 1.5622154e+00 -1.3602708e+00 -4.7159243e-01 -3.4795631e-01 1.4452673e-01
+1 1.0511091e+00 1 1 1.3141720e-01 -9.5278076e-01 -6.3010556e-01 -1.2774024e+00 -7.0171031e-01 1.8428718e-01 1.5439005e+00 6.0961822e-01
+1 7.7217417e-01 1 1 1.8922054e-01 -6.8855247e-01 1.2464071e-01 3.4281196e-01 -1.0634122e-01 -2.9578176e-01 -1.2193386e+00 1.1197099e+00
+1 5.4979755e-01 1 1 9.3792387e-01 1.1259525e+00 -6.0592974e-01 -4.0346907e-02 2.8933094e-01 -1.2044699e+00 -8.1555498e-01 8.2506873e-01
+1 4.5455400e-01 1 1 -8.2540020e-01 -1.0704554e+00 1.1821692e+00 4.7354942e-01 -4.0029808e-01 8.9669397e-01 -2.6382849e-01 -5.9853143e-02
+1 7.0962370e-01 1 1 7.7205614e-01 7.5802215e-01 1.2865874e+00 1.2909318e+00 1.4817008e+00 5.1562094e-01 -1.3782737e+00 -6.4213337e-01
+1 7.4663524e-01 1 1 1.1698032e+00 9.1998812e-01 9.2867768e-02 8.5143697e-01 -4.5943997e-01 1.5286423e+00 1.4575523e+00 -9.6477673e-01
+1 1.0165801e+00 1 1 7.9543561e-01 -6.7875686e-01 -5.4296949e-01 1.4658663e-01 2.2711898e-01 -5.4078441e-02 -1.0584898e+00 -1.2427789e+00
+1 6.6617680e-01 1 1 1.4096251e+00 -7.4363708e-01 6.3844980e-01 6.7293396e-01 1.5355931e-01 -9.7608327e-01 8.0117773e-01 1.0641232e+00
+1 5.1991563e-01 1 1 8.1878141e-01 -1.0528575e+00 -1.2546614e+00 2.6748580e-01 -1.5178014e+00 3.6533370e-01 5.2796930e-01 -3.6839423e-01
+1 9.2826634e-01 1 1 1.0833007e+00 1.2151028e+00 -7.2372421e-01 1.4777786e-02 4.4027490e-02 1.4915319e+00 -1.4192307e+00 4.7724089e-01
+1 4.8608158e-01 1 1 1.5046584e+00 -1.2612154e+00 6.1391591e-01 1.8443324e-01 -1.4458374e+00 1.4086076e+00 1.1027815e+00 5.0154844e-01
+1 4.5726491e-01 1 1 -1.0279161e+00 -9.2094097e-01 1.0944863e+00 -9.8250820e-01 2.9816922e-02 -5.7504985e-01 -9.4793889e-01 6.3156747e-01
+1 5.7297641e-01 1 1 -5.6758723e-01 3.7207607e-01 1.0069107e+00 -8.0428891e-01 -1.5218164e+00 -1.3238879e+00 -9.9260810e-01 -6.8718133e-01
+1 5.1302834e-01 1 1 -1.5633371e+00 -1.4284330e+00 -6.1115329e-01 5.8939569e-01 -1.4621012e+00 1.3165418e+00 -9.0735597e-01 -9.6198199e-01
+1 3.9383704e-01 1 1 1.2738867e+00 3.7756215e-01 1.3546913e+00 5.3171103e-01 3.0827056e-03 8.8056999e-01 -6.4112373e-01 -1.3954789e+00
+1 5.2689455e-01 1 1 2.5953191e-01 -3.3004353e-01 1.1748937e+00 -1.3638694e+00 1.5455505e+00 -3.0312238e-01 2.9630789e-01 1.3169506e+00
+1 5.5317183e-01 1 1 1.4221345e+00 1.0109913e+00 1.5292043e+00 -1.4928005e+00 1.3794036e+00 1.0855079e+00 6.2242778e-01 1.4683448e+00
+1 4.1563049e-01 1 1 5.7744990e-01 -1.1445423e+00 -3.3560522e-02 -7.3852639e-01 -1.3166676e+00 9.0308115e-01 -3.5981990e-01 1.2613034e+00
+1 3.6338773e-01 1 1 8.2072938e-01 -3.5096623e-01 1.4349834e+00 1.9526926e-02 1.4708345e-01 1.0507692e+00 7.2835418e-02 -7.4133434e-01
+1 3.3064409e-01 1 1 -7.3460436e-01 1.2216525e+00 -2.4117428e-01 1.4634082e+00 -4.0188615e-01 1.3858124e+00 -1.0762659e+00 -4.9869863e-02
+1 1.1099719e+00 1 1 -3.6348702e-02 -1.1368261e+00 -7.6168459e-01 -2.7699012e-02 -7.6385516e-02 -4.1917677e-01 4.8960866e-01 6.4245423e-01
+1 5.7779971e-01 1 1 -1.4436600e+00 5.3063673e-01 3.5718195e-01 -5.8157551e-01 1.1000223e+00 1.4882912e+00 1.0215903e+00 7.4316071e-02
+1 9.3778391e-01 1 1 -1.0738076e+00 -5.7006926e-01 -4.2656348e-01 -1.0448002e+00 -1.9867813e-01 3.5027013e-01 1.0643664e+00 -1.3236716e+00
+1 4.5024025e-01 1 1 9.6497407e-01 7.0356837e-01 -1.3794530e-01 1.5460411e+00 3.2961366e-01 -3.5463975e-01 5.7823588e-01 -1.3301626e+00
+1 8.1082162e-01 1 1 1.4178361e+00 -8.1227332e-02 4.8732684e-02 1.9957133e-01 1.1889666e+00 -8.2896949e-01 1.4642844e+00 -4.6904513e-01
+1 6.0731393e-01 1 1 5.9104373e-01 1.4050368e+00 -9.0546389e-01 -1.0256015e+00 -7.0842916e-01 4.7322759e-01 -1.0084811e+00 -9.8560835e-01
+1 1.0204495e+00 1 1 -4.4012516e-02 -8.9863777e-01 -2.5679252e-01 6.3438515e-01 6.7295874e-02 -9.7645241e-01 -6.5009100e-01 4.9853781e-01
+1 6.3842527e-01 1 1 -1.4440800e+00 1.3724561e+00 6.3649906e-01 -4.5423006e-01 6.8395718e-02 4.4443923e-01 3.7980869e-01 2.9732082e-01
+1 7.5026586e-01 1 1 1.2921635e+00 1.2967966e+00 5.1665078e-01 -1.7443345e-01 -2.9608619e-01 -1.0171693e+00 -2.7162480e-01 -1.2029556e+00
+1 9.7773442e-01 1 1 -4.3829243e-01 -1.1085466e+00 -1.2438579e-02 -5.9710334e-01 -3.7869724e-02 9.8341137e-01 -4.6394500e-01 1.2154838e+00
+1 6.8968284e-01 1 1 6.5392763e-01 1.4429600e+00 1.4315149e+00 -1.2689130e+00 1.2668527e+00 2.7588786e-01 -9.0694777e-02 -1.1402051e+00
+1 3.9747017e-01 1 1 1.2706514e+00 -1.2672563e+00 1.1546006e+00 -1.4894743e+00 1.4205772e+00 -1.4343126e-01 -6.3468731e-01 2.8732208e-01
+1 5.0147790e-01 1 1 -7.0916036e-01 1.2218531e+00 -2.4564649e-01 -1.3841397e+00 -4.6250901e-01 -1.0475915e+00 -1.4826275e+00 3.9426042e-01
+1 9.8376580e-01 1 1 3.4436176e-01 -9.0654591e-01 -5.2783390e-01 2.5782239e-01 -1.0887250e+00 -1.3844077e+00 5.9205983e-01 7.1589825e-01
+1 2.1537367e-01 1 1 8.7446283e-01 4.0726062e-01 5.5336145e-01 9.6470119e-01 -1.5658095e+00 -1.1046767e+00 1.3256741e+00 -1.9799561e-01
+1 3.7254409e-01 1 1 7.2631118e-01 -7.0113492e-01 1.2316014e+00 -2.6759871e-02 5.6140170e-01 5.1126139e-01 4.2869866e-01 -7.6564262e-01
+1 9.4105840e-01 1 1 -1.1171278e+00 1.3946980e-01 -4.2868688e-01 -5.0540032e-01 1.2756555e+00 5.1434094e-01 1.4663741e+00 -1.9193665e-01
+1 1.2647207e+00 1 1 -1.4087547e+00 4.4081573e-01 -1.2685204e+00 6.0336583e-01 -1.4274910e+00 -1.1348712e+00 -4.4432282e-01 5.3643989e-01
+1 9.0632686e-01 1 1 1.2435571e+00 9.1448919e-01 -1.1749131e+00 -2.9160963e-01 5.0266600e-01 -1.1706509e+00 -1.6794102e-01 -4.2562476e-01
+1 8.0295161e-01 1 1 -5.5127405e-01 1.1484964e+00 1.2864350e+00 -1.9849954e-01 5.6476356e-01 6.6524073e-01 -1.4344941e+00 -6.8851244e-02
+1 8.8063573e-01 1 1 -7.0621724e-01 8.3337957e-01 6.7300842e-01 1.8956046e-01 1.2297994e+00 -2.2726114e-01 -9.5980308e-01 -1.0767600e+00
+1 1.8572813e-01 1 1 -4.5604466e-01 1.3904162e+00 1.5188792e+00 3.6763857e-01 6.9973792e-01 5.9874136e-01 6.6791244e-01 -1.5315053e+00
+1 8.9950572e-01 1 1 7.4354896e-01 1.5588428e+00 -7.7921158e-01 -6.1129864e-01 1.5138848e+00 5.2474209e-01 6.9379346e-01 -9.4149600e-01
+1 8.6114618e-01 1 1 -4.2827927e-01 -1.4114758e+00 1.0907150e+00 -1.0883238e+00 1.0284560e-01 8.8968644e-01 -1.0052960e+00 4.7889695e-01
+1 5.6898847e-01 1 1 -7.0100548e-01 -5.0746516e-01 4.5355897e-01 -1.1064294e+00 6.5007973e-01 -1.0210033e+00 -5.2503694e-01 6.0636868e-02
+1 6.7550788e-01 1 1 -8.2671548e-01 4.5719101e-01 1.4617900e+00 -6.7122574e-01 -5.6927815e-01 -6.2377512e-01 4.3786201e-01 1.2478240e+00
+1 3.1012595e-01 1 1 6.5721348e-01 -3.2640174e-01 1.0504161e+00 1.6826153e-01 1.4334001e+00 -2.9368054e-01 1.5368100e+00 -1.0941333e+00
+1 1.2529686e+00 1 1 -5.2832796e-02 -6.1322804e-01 -1.4073213e+00 5.3813247e-01 1.4233471e+00 -4.4680986e-01 -1.0082960e+00 -1.3570662e+00
+1 6.5748193e-01 1 1 1.1099245e+00 1.0418640e+00 2.0262211e-01 -2.5283822e-01 -1.0337334e+00 -1.1269133e+00 -6.8033748e-01 -2.4974399e-01
+1 3.5641255e-01 1 1 -2.7602827e-01 -6.2901727e-01 -1.6655740e-02 1.1229201e+00 -9.4971682e-01 6.2989691e-01 9.6516594e-01 -2.7941125e-01
+1 5.2229583e-01 1 1 9.2523665e-01 -4.3393307e-01 -3.3127607e-01 1.3714993e+00 5.4175243e-01 -4.8988037e-01 1.5011336e+00 6.1607730e-01
+1 1.2773688e+00 1 1 -4.3132845e-01 -1.4764863e+00 -8.5466545e-01 9.2375483e-01 8.9764398e-01 6.9500243e-01 -5.7816078e-01 -2.7814747e-01
+1 1.1176224e+00 1 1 1.4585399e+00 1.3568165e-01 -1.0006285e+00 -2.0339591e-01 7.7445492e-01 4.6435821e-01 -2.0214640e-01 -1.3465009e-01
+1 1.1310697e+00 1 1 -1.6786148e-01 -3.9482240e-01 -6.1751502e-01 -4.2225950e-01 6.4540126e-01 7.5225600e-01 -1.4128111e+00 -1.1173192e+00
+1 1.5871339e-01 1 1 -9.7758278e-02 -7.3644076e-01 1.2472631e+00 -5.7689543e-02 -6.6041776e-01 1.3976998e+00 -9.5839113e-01 -1.4851186e+00
+1 4.4167550e-01 1 1 2.9572347e-02 5.1528347e-01 -1.0970222e+00 1.1639768e+00 -3.9451112e-01 1.4514314e+00 -7.3411114e-01 -4.3460121e-01
+1 8.7228430e-01 1 1 6.5079634e-01 -1.0016535e+00 3.5550308e-01 2.6116004e-01 1.3536938e+00 -2.5995524e-01 -1.1716289e+00 -1.3961094e-01
+1 7.6133317e-01 1 1 -1.0915036e+00 1.0042612e+00 -3.6889359e-01 5.1187663e-01 1.1830139e-01 8.8760555e-01 -6.4119715e-02 3.2857309e-01
+1 6.2447562e-01 1 1 -1.1422808e+00 -1.1587519e+00 1.5093037e+00 1.4298353e+00 -3.3668108e-01 -1.4369742e+00 -9.3766543e-02 -5.9196650e-01
+1 1.0533408e+00 1 1 -4.0970610e-02 -4.1074219e-01 -1.4925962e+00 1.1991901e+00 -5.9050251e-01 1.3390167e+00 1.1452307e+00 2.4294423e-01
+1 1.1504856e+00 1 1 -5.8425600e-01 -1.2648864e+00 -4.4631090e-01 1.4703931e+00 -2.8441202e-01 -1.5164281e+00 -6.4611311e-01 -9.0682406e-01
+1 2.9117553e-01 1 1 1.0280668e+00 2.1185268e-01 9.7587956e-01 1.1288799e+00 1.3912291e+00 1.1346649e+00 1.2628223e+00 -1.1259970e+00
+1 4.6583276e-01 1 1 -4.1640147e-02 1.1834666e+00 -6.4746841e-01 1.0066391e+00 -4.8725629e-01 8.4556223e-01 -3.4504542e-01 3.2216655e-01
+1 7.8811555e-01 1 1 7.2921225e-01 1.1003345e+00 4.7534589e-01 1.1065705e+00 8.1561864e-01 -1.2006914e+00 2.0159080e-01 -1.4524534e+00
+1 6.9674011e-01 1 1 5.1732214e-01 -1.2346954e+00 6.8239399e-02 -9.8777764e-02 1.3337187e+00 1.5705971e+00 1.4996411e+00 -1.2101949e+00
+1 1.1402621e+00 1 1 -1.2951973e+00 -1.3060012e+00 2.1825894e-01 -1.3969600e+00 5.4673582e-01 1.3636528e+00 -5.2910058e-01 -1.0746130e+00
+1 9.6695802e-01 1 1 -2.8608034e-01 3.4642179e-01 -1.1022861e+00 1.5571768e+00 -1.6953072e-01 9.9378150e-01 1.2552831e+00 -4.3868166e-03
+1 3.0695085e-01 1 1 -1.5155425e+00 9.3981931e-01 -1.5031288e-01 -1.1384952e+00 1.2179416e-01 -1.3624218e+00 -1.3928624e+00 -1.4725956e+00
+1 6.9374714e-01 1 1 3.1101998e-01 -3.8466580e-01 -4.6813742e-01 7.5151687e-01 -1.3240369e+00 8.4613234e-01 1.3095655e+00 -4.4808254e-01
+1 6.3600719e-01 1 1 -2.9736531e-01 3.1957949e-01 -1.4376168e+00 1.5416256e+00 -1.1875973e+00 -1.0436404e+00 -1.3072279e-01 -5.2570108e-01
+1 8.7559367e-01 1 1 4.5518314e-01 -9.5096270e-01 -3.5964448e-02 1.3868915e+00 -1.4099935e+00 -9.5271786e-01 -1.0846070e+00 -1.2995846e+00
+1 8.4234828e-01 1 1 4.8490068e-01 -1.5482631e+00 -1.2686808e+00 -1.1313718e+00 -7.2802152e-01 3.6869989e-01 -1.4684614e+00 1.3759216e+00
+1 4.6465296e-01 1 1 4.3440263e-01 1.5463341e-01 -7.2808463e-01 1.0949416e+00 6.4572891e-01 1.5183065e+00 -7.9635314e-02 -1.4935753e-01
+1 6.0597949e-01 1 1 -5.6296228e-02 8.2657348e-01 -4.1499026e-01 -7.6549925e-01 -1.4368673e+00 -9.7980662e-01 -1.1225603e-01 -1.1953535e-01
+1 4.2419178e-01 1 1 -5.5131308e-01 9.7816378e-02 -4.0553985e-01 -9.2400200e-01 -5.5911844e-03 6.1876385e-01 1.4100283e+00 -1.5528499e+00
+1 3.6681241e-01 1 1 -1.3622300e+00 9.4691085e-01 1.3477918e+00 -8.0910348e-01 2.7674348e-01 8.9236951e-01 1.3117232e+00 -1.5375592e+00
+1 4.9868834e-01 1 1 9.2711864e-01 -5.7773513e-01 1.4537685e+00 1.3524218e+00 -1.4710413e+00 9.0971377e-02 -1.5659312e+00 9.8306149e-01
+1 5.8374710e-01 1 1 -2.1652643e-01 6.6855409e-01 1.3206118e+00 7.2998780e-01 5.4252973e-01 -9.9968561e-01 -1.4837178e+00 6.7868472e-01
+1 7.4469196e-01 1 1 -1.1953615e+00 -1.0882835e+00 1.7101321e-01 9.8569293e-01 1.3952490e+00 -4.7849478e-01 1.1181292e+00 -4.6878550e-01
+1 1.0773317e+00 1 1 4.4615737e-02 -4.2764875e-01 -3.3824445e-01 9.2302405e-01 1.1027887e+00 4.1541344e-01 -6.0907320e-01 2.3644829e-01
+1 6.5337328e-01 1 1 -9.8395351e-01 4.7142576e-01 1.4083073e+00 8.0603586e-02 -8.2660074e-01 1.2348600e+00 -1.3844043e+00 -1.2824607e-01
+1 4.5446174e-01 1 1 3.7046694e-02 1.5610306e-01 6.6174701e-01 6.7803741e-01 -5.5597546e-01 9.3050031e-01 -1.0477326e+00 -2.9907321e-01
+1 4.8636944e-01 1 1 6.0843864e-01 3.9422243e-01 7.4394086e-01 1.2182371e+00 -1.1829835e+00 7.0479791e-02 -6.1494510e-01 2.4820419e-02
+1 3.7178142e-01 1 1 1.4418596e-01 7.7416173e-02 -1.2465945e-01 1.1507780e+00 7.3615377e-01 1.7341115e-01 4.5756043e-01 -6.7504192e-01
+1 8.0441546e-01 1 1 1.1654708e+00 5.1425841e-01 2.9096689e-01 1.4822614e+00 9.4447070e-01 -8.7671029e-01 -4.0066357e-01 -1.1384686e+00
+1 8.4400944e-01 1 1 2.3744932e-01 6.1977851e-01 -1.1792354e+00 -4.6156692e-01 -7.4861186e-01 -8.0031823e-01 -1.5196132e+00 1.1993493e+00
+1 5.1547439e-01 1 1 9.8797040e-01 -9.0390256e-01 8.9940398e-01 -9.6303108e-01 1.5911158e-01 1.3512679e+00 1.0091683e+00 1.0052717e+00
+1 1.0744390e+00 1 1 1.5012667e+00 8.5178945e-01 -1.0610750e+00 -1.7806479e-01 6.9291589e-01 1.8597030e-01 -3.6759246e-01 1.1560982e-01
+1 2.4927057e-01 1 1 -1.4825583e+00 -2.1246948e-01 1.3336730e+00 1.2028411e+00 -4.6568678e-02 -2.8182895e-01 1.3862892e+00 1.5499865e+00
+1 5.6324011e-01 1 1 -1.3854488e+00 1.0162742e+00 -2.2117361e-01 2.2291587e-03 -4.2320789e-01 8.2261508e-01 1.3116354e+00 5.3719028e-01
+1 8.9848076e-01 1 1 2.4678717e-01 -3.1953449e-01 -7.6077621e-01 -2.3364109e-01 -2.8923165e-01 -4.5757197e-01 1.0035186e-01 -3.8027785e-01
+1 6.1825109e-01 1 1 8.4960712e-01 -1.4343257e+00 -8.3737617e-02 1.8502959e-01 -1.0725570e+00 2.0674382e-01 -4.2155142e-01 -1.3303993e+00
+1 9.5413106e-01 1 1 8.0819764e-01 -1.2717458e+00 5.5372859e-02 -3.8443544e-01 -6.1535623e-03 1.4191460e-01 -7.2330797e-01 -1.3056226e+00
+1 2.4931774e-01 1 1 -8.6889248e-01 1.1639267e+00 7.4021319e-01 1.0495958e+00 2.4963617e-01 6.8987996e-01 1.3265695e+00 4.2482228e-01
+1 7.9377864e-01 1 1 -1.3533371e+00 -5.8134715e-01 5.6164508e-02 5.1387454e-01 -1.5325964e+00 -8.0607665e-01 -2.3001489e-01 -8.5209731e-01
+1 4.1408171e-01 1 1 -4.0607903e-01 -3.4844385e-01 1.4790931e+00 4.5121652e-01 -4.2875289e-01 -1.1827186e+00 1.4402289e+00 1.3213388e+00
+1 1.2251342e+00 1 1 -1.4309787e+00 -3.6706253e-01 -3.0566231e-01 -2.0861892e-01 7.6374405e-01 -1.0951877e+00 -4.3510499e-02 -1.7715905e-01
+1 8.5674860e-01 1 1 -1.5678512e+00 8.6800182e-01 -7.6251527e-01 -2.4071391e-01 -3.0131615e-01 -2.2880556e-01 7.1012485e-01 7.1776284e-01
+1 1.0654175e+00 1 1 8.0424657e-01 -1.0496580e+00 -1.0376861e+00 6.9257003e-01 2.6886361e-02 -2.2568559e-01 1.5778778e-01 -2.7568368e-01
+1 1.0262014e+00 1 1 -1.3010495e+00 -1.5586857e+00 -1.4099279e+00 4.2367105e-01 -5.1027912e-01 -1.1954286e+00 4.3497536e-01 4.3353224e-01
+1 2.7999746e-01 1 1 -1.2534606e+00 9.0981769e-01 3.7579912e-01 -1.3512676e+00 2.8669139e-01 -1.0842593e+00 1.4474138e-01 1.0229825e+00
+1 3.9706882e-01 1 1 6.0848722e-01 1.1744659e+00 1.4545662e+00 -1.8203634e-01 -7.8099837e-01 1.2325437e+00 1.0757394e+00 -6.7010154e-01
+1 6.6714135e-01 1 1 9.6055689e-01 6.2177040e-01 -9.8028509e-01 4.2648705e-01 -6.6541761e-01 -2.9959990e-01 8.6729259e-02 2.1313298e-01
+1 1.1832950e+00 1 1 -5.6498216e-01 1.1578702e+00 -1.1396352e+00 -1.1466655e+00 3.9608144e-01 5.9742107e-01 -4.0342660e-02 7.1037861e-01
+1 6.1950120e-01 1 1 1.3794586e+00 1.2989778e+00 4.4122591e-01 -1.4775828e+00 -9.4047721e-02 3.2586016e-01 5.4492625e-01 1.2812495e+00
+1 1.8480716e-01 1 1 -3.9329285e-01 9.9337296e-01 1.5251302e+00 5.5590288e-01 -4.3894719e-01 9.3575163e-01 8.3288436e-01 1.4841355e+00
+1 5.9686511e-01 1 1 -1.6194334e-01 1.1958955e+00 6.0850422e-01 -3.6766084e-02 -9.2581623e-01 3.6479611e-01 -6.4945788e-01 -3.8047044e-01
+1 6.7533703e-01 1 1 -1.1625442e+00 -4.9393585e-01 1.2463347e+00 9.6617478e-01 1.1505033e-01 -1.2606106e+00 -1.5456857e+00 -1.4256462e+00
+1 9.4116417e-01 1 1 -1.3151017e+00 -1.4920214e+00 -9.9314483e-01 -3.9289743e-01 -1.5701290e+00 -1.8225365e-01 -5.1053476e-01 9.1771324e-02
+1 9.2541301e-01 1 1 1.3312467e+00 -2.1033479e-01 -5.0342395e-01 2.0073509e-01 2.2012755e-01 -8.4333806e-02 -8.6814368e-01 -1.2134678e-01
+1 8.9198937e-01 1 1 -1.6021702e-01 -8.0507722e-01 -7.3734956e-01 -3.1581667e-01 -1.1124329e+00 -5.3999530e-01 -1.3344707e+00 -5.8166062e-01
+1 6.6362200e-01 1 1 -4.2260320e-01 -9.3351454e-02 9.4892521e-01 1.3608232e+00 -1.0424836e+00 3.6022770e-01 -6.1895661e-01 6.6630543e-01
+1 7.6884345e-01 1 1 4.4893933e-01 -1.3031569e+00 -1.2799684e+00 5.6064073e-01 -3.5962418e-01 4.9794962e-01 -9.9046854e-01 -1.1824767e+00
+1 2.7260180e-01 1 1 -7.8219000e-01 1.0252385e+00 1.1968349e+00 1.0523460e+00 2.2069908e-01 -1.6353042e-01 4.9468713e-01 -1.7002230e-01
+1 6.8079794e-01 1 1 1.2978799e+00 -4.5211146e-01 -4.1358083e-01 -3.8745845e-01 -9.3155688e-01 4.3785361e-01 1.5523911e+00 1.2844892e+00
+1 2.9820939e-01 1 1 1.3894987e+00 8.7524957e-01 1.2915916e+00 5.0746383e-01 1.0212934e+00 1.3956300e+00 1.0988345e-01 -6.1556861e-01
+1 7.1105734e-01 1 1 -1.2955744e+00 1.3826516e+00 -6.2514319e-01 -4.7941789e-01 -7.8419828e-01 1.2222991e+00 -4.4526844e-01 -5.9704865e-01
+1 5.2900157e-01 1 1 -3.4080329e-01 -1.3546756e-01 -1.2957546e+00 6.0864091e-01 -1.0392702e+00 3.0687645e-01 -3.5291485e-01 -3.4964434e-01
+1 7.7995589e-01 1 1 -7.5755545e-01 8.5132999e-01 -2.2772232e-01 4.0207762e-01 2.4102133e-01 -8.2258093e-01 -1.1295193e-01 1.4473591e+00
+1 1.2463042e+00 1 1 6.4053265e-01 1.4901618e+00 -8.6913460e-01 1.5282317e-01 1.3325558e+00 1.0315371e+00 -8.6118323e-01 4.1217972e-01
+1 3.6545370e-01 1 1 -8.0569439e-01 3.7331608e-01 8.6058221e-01 -1.3237421e+00 -1.4807537e-01 -1.4064351e+00 -5.8911376e-01 2.9279571e-01
+1 7.5711315e-01 1 1 -1.0412272e+00 5.6279087e-01 -8.7367778e-02 6.2524211e-01 -5.6134835e-01 -6.1113873e-01 1.0650555e+00 1.2834860e+00
+1 9.8775696e-01 1 1 -1.2347385e+00 -5.0938846e-01 -1.2664826e+00 -1.8332099e-01 -3.7898259e-01 -1.5422581e+00 -4.0679570e-01 1.3745740e+00
+1 3.9846269e-01 1 1 1.1104393e+00 -4.5185701e-01 -1.4823487e+00 8.2657546e-01 -1.5520087e+00 5.4969174e-01 -9.0966297e-01 -8.0664441e-01
+1 8.6158098e-01 1 1 -1.0484004e+00 -1.1313499e+00 -1.0056043e+00 1.3108295e-01 3.2960253e-02 -7.5487233e-01 1.4259815e+00 -1.3003316e+00
+1 5.3554596e-01 1 1 7.2692144e-01 1.4617590e+00 5.7694795e-01 8.5463397e-01 1.0426672e+00 -1.3881756e+00 -7.3918687e-01 1.3860681e+00
+1 8.0701404e-01 1 1 -2.8520555e-01 5.2965784e-01 -1.3323690e+00 4.7155974e-01 3.0449538e-01 1.5418360e+00 1.4851412e+00 7.3767444e-01
+1 5.6871816e-01 1 1 6.2075456e-01 -1.3141821e+00 1.4593213e-01 -7.3376336e-01 -5.2558185e-04 -1.3598830e+00 8.1390893e-01 1.3697726e+00
+1 8.1025470e-01 1 1 -2.0729235e-01 1.0799933e+00 -9.0258090e-01 1.5320317e+00 5.9132386e-01 -4.6659060e-01 8.7303989e-01 1.7700320e-01
+1 7.4605866e-01 1 1 6.3794897e-02 -6.7574346e-01 1.0738080e+00 3.6333863e-01 1.5224871e+00 -5.7294047e-01 -1.1978345e+00 -1.9547603e-01
+1 6.8384037e-01 1 1 9.1774324e-01 -3.6296968e-01 -9.5892560e-01 -6.2384107e-01 1.6869615e-01 -4.2895714e-01 -6.7854012e-01 7.4029797e-01
+1 8.3378594e-01 1 1 -7.0934281e-01 5.4156379e-01 -2.9221638e-01 -1.4022465e+00 1.5595775e+00 4.7251206e-01 -2.4240526e-01 1.4810211e+00
+1 1.2054181e+00 1 1 4.1957835e-01 8.6870892e-01 -9.7146151e-01 6.7079912e-01 1.5111015e+00 -4.3610609e-01 5.4041220e-01 6.8226165e-01
+1 1.1512520e+00 1 1 -1.0221496e+00 1.4097444e+00 -4.9655363e-01 -1.0551650e+00 4.4801467e-01 -2.9944415e-01 3.6351471e-01 -4.1685202e-02
+1 1.0288801e+00 1 1 -1.0397421e+00 -3.1685930e-01 -1.5066910e+00 1.3196066e-01 -6.1495127e-01 7.3683611e-02 -8.0601226e-01 -2.8026313e-02
+1 4.9595756e-01 1 1 -1.4078907e+00 -4.5467966e-01 1.4220464e+00 -1.0168382e-01 3.5375300e-01 6.1293632e-01 -1.0058395e-01 2.0065201e-01
+1 8.8744169e-01 1 1 5.7594284e-02 -1.4477750e+00 -9.0324432e-01 2.6364779e-02 -1.5082055e+00 3.3842412e-01 -3.3764997e-01 1.4294653e+00
+1 4.7635624e-01 1 1 3.7659153e-01 -1.1189815e+00 -6.5166459e-01 1.4827861e-01 1.1015108e+00 -1.5300676e+00 -1.1667581e+00 1.2634695e+00
+1 7.0291688e-01 1 1 -9.3538582e-01 -1.1485800e+00 -9.3476537e-01 8.3554137e-01 -3.1299293e-01 1.2316203e+00 1.1865249e-01 1.1065004e+00
+1 4.9041242e-01 1 1 -4.9981308e-01 9.0349351e-01 5.0323651e-01 2.4666821e-02 -1.4460269e+00 -1.1160953e-01 -7.1899675e-01 -1.2755488e+00
+1 6.0262674e-01 1 1 2.6037196e-01 -1.4435474e+00 7.2852688e-01 -1.1496448e-01 -1.3870498e-02 -2.9049269e-01 1.5286305e+00 7.9342521e-02
+1 6.4230865e-01 1 1 -1.6696114e-01 8.1850198e-01 1.5647562e+00 -1.2853546e-01 -6.4359655e-01 -2.7567927e-01 -2.5139124e-01 1.4744725e+00
+1 2.3946401e-01 1 1 -6.7361275e-01 -4.7139709e-01 5.8522567e-01 1.1201857e+00 -4.2377455e-01 5.0763825e-01 3.0961400e-01 5.7692749e-01
+1 6.7499641e-01 1 1 8.9044341e-01 3.2585649e-01 -4.3877995e-01 -6.0307037e-01 -3.8833047e-01 -6.8952021e-01 1.2050481e+00 1.4654445e+00
+1 1.2974045e+00 1 1 -8.6496455e-01 8.7411136e-01 -1.2566912e+00 -1.0258089e+00 1.5593523e+00 5.6907171e-01 -6.0488018e-01 -3.6097584e-01
+1 4.6694825e-01 1 1 -1.3100277e+00 1.1023325e+00 -2.8145204e-01 2.9080687e-01 8.6861586e-01 1.3802272e+00 -2.7352345e-02 -5.0553049e-01
+1 4.1109711e-01 1 1 -1.3545610e+00 9.3051595e-01 8.7406793e-01 -7.2709601e-01 -1.5437436e-01 -4.2178723e-02 -1.0383414e+00 1.5571591e+00
+1 2.3179039e-01 1 1 1.0159544e+00 3.3334223e-01 3.7243498e-01 4.9282455e-01 3.8562367e-01 1.1021397e+00 1.4309410e-01 -1.4349193e+00
+1 4.2520199e-01 1 1 5.9015341e-01 1.0231901e+00 1.4621400e+00 -1.4775339e+00 7.1312680e-02 8.3217104e-01 -1.4774427e+00 1.3183423e+00
+1 4.8499670e-01 1 1 7.0031389e-01 -3.2222048e-01 6.4877484e-01 1.3775601e+00 -1.5361867e+00 -7.1788099e-02 -2.3047573e-01 -2.7347474e-01
+1 7.6419129e-01 1 1 -1.3721357e+00 5.4604396e-01 -5.0932994e-01 -8.8561132e-01 -1.0806791e+00 -1.7099715e-01 -2.1918183e-02 -1.3989255e-01
+1 2.2795318e-01 1 1 9.4705752e-01 7.6861294e-01 5.3163356e-01 3.9646930e-01 -1.4270453e+00 6.0821261e-01 -8.1255394e-01 -1.2627351e+00
+1 4.9439661e-01 1 1 -1.2542824e+00 -1.5124501e-01 4.7565552e-01 1.4151456e-01 -1.4315282e+00 -5.1322416e-01 -9.0874298e-02 -1.3302120e+00
+1 6.7032960e-01 1 1 -6.3826718e-01 -4.2636750e-01 -1.0110269e+00 2.4955494e-01 -1.3774596e+00 1.0549377e+00 -5.1029620e-01 -1.2992341e+00
+1 5.7955769e-01 1 1 1.1824198e+00 1.4245717e-02 5.4623583e-01 2.4366552e-01 -5.6649206e-01 -8.1164684e-01 -2.1739914e-04 9.8286129e-01
+1 6.1470159e-01 1 1 -7.8492245e-01 6.6672487e-01 8.5193503e-01 -1.3504195e+00 1.1352911e+00 -5.5308643e-01 -5.1223462e-01 4.5548569e-01
+1 6.9337092e-01 1 1 -6.4408709e-01 -4.1607534e-01 -9.0721137e-01 1.5066004e+00 -1.1967463e+00 2.4896570e-01 -1.1633748e+00 -7.1334335e-01
+1 3.9794235e-01 1 1 7.5659869e-01 2.0697838e-01 -1.3522899e+00 1.9560304e-01 -1.2386383e+00 -2.3483937e-01 4.3255717e-01 -8.4409531e-01
+1 5.5864564e-01 1 1 -1.0129352e+00 9.4257012e-01 1.4864065e+00 1.3944421e+00 1.5406069e+00 -1.1048917e+00 3.4296867e-01 7.2248511e-01
+1 1.0146068e+00 1 1 -1.1133364e-01 -1.2756967e+00 8.9907899e-02 1.0667690e-01 -2.7076691e-02 3.8599976e-02 -5.4810265e-01 5.5164780e-01
+1 2.5333407e-01 1 1 1.2046547e+00 7.3501524e-01 -2.4013485e-02 -9.3079637e-01 4.5299495e-01 -1.5598758e+00 -8.1154584e-01 7.0463535e-01
+1 8.8590291e-01 1 1 -9.3321021e-01 6.5888993e-01 -1.4707831e+00 1.2367596e+00 1.4070958e+00 -2.4123478e-01 1.1442953e+00 -9.9791461e-01
+1 4.6180612e-01 1 1 1.5081586e+00 -1.5099791e-01 -1.4010772e+00 1.4412838e+00 -8.5022191e-01 1.3632247e+00 -6.5831223e-01 1.0123658e+00
+1 6.5903549e-01 1 1 1.2514453e+00 5.8505005e-01 1.4737697e+00 -1.1637557e+00 1.4253260e+00 8.2167807e-02 4.3563222e-01 -3.3522069e-02
+1 6.5409555e-01 1 1 7.8772454e-02 -2.4883919e-01 1.3307158e+00 3.1321889e-01 8.1063874e-01 -1.3064380e+00 -1.3818001e+00 -1.0603330e+00
+1 4.2559214e-01 1 1 1.3181346e+00 -7.8039751e-01 3.4312131e-01 -1.0394341e+00 -6.8198486e-01 -7.1271549e-01 -1.2612819e+00 1.2377661e+00
+1 5.7086186e-01 1 1 -6.2381452e-01 8.4576802e-03 -1.1242847e+00 6.2716846e-01 1.5520029e+00 2.8351335e-01 1.1023983e+00 -4.9184095e-01
+1 8.3293175e-01 1 1 -9.5591392e-01 7.7656186e-01 8.2609437e-01 7.7699148e-01 -1.3057169e-01 -7.8719759e-01 -1.1049203e+00 -8.4065201e-01
+1 7.1243819e-01 1 1 5.9659333e-02 1.4992713e+00 1.4701178e+00 -7.0491561e-01 1.4548395e+00 -1.1831868e+00 -4.4090085e-01 -1.0962399e+00
+1 9.1449371e-01 1 1 5.2635609e-01 -4.6177236e-01 -3.5635881e-01 -5.7072411e-01 4.7107238e-01 4.6043633e-01 7.9649350e-01 9.3714740e-01
+1 9.9527220e-01 1 1 -2.5808439e-01 -1.2741542e+00 -1.4468593e+00 -8.7774908e-01 4.9996424e-01 8.1076246e-01 3.3998045e-01 -1.3092610e+00
+1 7.7510115e-01 1 1 9.1512639e-01 1.5278967e+00 -1.4366451e+00 5.9026398e-01 -8.6128885e-01 1.3973601e+00 -5.0562324e-01 -1.0340088e+00
+1 8.1300766e-01 1 1 -7.0842417e-01 -1.7918567e-02 5.8663810e-01 -5.8294875e-01 7.7725383e-01 -1.1160158e+00 -1.5996578e-03 7.0462096e-01
+1 2.8285525e-01 1 1 1.5116303e-01 4.3553140e-01 1.3087800e+00 1.0078270e+00 5.6289793e-01 -1.5691131e+00 1.3888858e+00 -1.2397549e+00
+1 1.2178643e+00 1 1 -9.5137985e-01 6.5287488e-02 -7.6660660e-01 -9.1949832e-01 1.2900796e+00 -1.5558846e+00 9.7084700e-01 -1.5187657e+00
+1 6.0793879e-01 1 1 8.6553028e-01 8.7096966e-01 -6.8572652e-01 -5.1405753e-01 -9.0392957e-01 8.6461324e-01 -4.0672084e-01 -4.5433561e-01
+1 5.3413593e-01 1 1 1.3934399e+00 -1.4347363e+00 1.4978956e+00 -3.8514639e-01 3.9771185e-01 -1.4528882e+00 3.4846734e-01 1.1931389e+00
+1 5.0295687e-01 1 1 -1.0295044e+00 1.2519280e+00 1.5490073e+00 -1.4745449e+00 -9.6604780e-01 9.0803496e-01 7.6190941e-01 2.9985245e-01
+1 8.5731058e-01 1 1 1.0114934e+00 -1.2340524e+00 -2.1267595e-01 1.3486528e+00 -6.1449611e-01 -5.1360914e-01 2.7974698e-01 5.0543651e-01
+1 5.2405086e-01 1 1 1.0114820e+00 7.6429912e-02 6.8779245e-01 2.1722962e-01 -1.4210911e+00 8.6776312e-01 -1.2566822e+00 4.9230873e-03
+1 1.1374166e+00 1 1 8.1994720e-01 -3.5387255e-01 -1.3331820e+00 4.4762159e-01 1.2506662e+00 1.2216234e+00 -1.3001908e-01 1.0609186e+00
+1 9.9699216e-01 1 1 -1.3143555e+00 -5.0109033e-01 -9.5032362e-01 -9.3826550e-01 -4.4944373e-01 1.5172749e+00 1.3177776e+00 -8.2040973e-01
+1 1.3272492e-01 1 1 1.3074296e+00 7.8474900e-01 -2.3209467e-01 1.3668446e+00 -1.4120921e+00 5.3149905e-01 -3.4014295e-01 -1.7616538e-01
+1 5.8740700e-01 1 1 -1.4713961e+00 8.7051535e-01 1.0429198e+00 1.2323550e+00 -1.4408590e+00 1.3565968e+00 9.1601341e-01 -1.4312135e+00
+1 4.8942969e-01 1 1 8.6350017e-01 3.5454052e-01 1.4077710e+00 -3.3057571e-01 -1.1213479e+00 -1.3578368e+00 -1.5081949e+00 7.6922574e-01
+1 2.3213593e-01 1 1 -1.3106751e+00 -8.3878464e-01 1.0721209e+00 1.4914634e+00 -7.9299667e-02 -6.3419844e-01 1.2802111e+00 7.2328695e-01
+1 7.8830071e-01 1 1 3.3061755e-01 -1.1272122e+00 -1.0396328e+00 2.5819405e-01 -7.5421321e-01 4.5066076e-01 -2.6070355e-01 1.4617288e+00
+1 5.3969357e-01 1 1 -7.8824309e-01 -1.2509509e+00 4.2929431e-01 9.2798411e-01 2.6491210e-01 -1.2456720e-01 8.7712339e-01 2.1168635e-02
+1 1.2046167e+00 1 1 9.4539832e-02 -1.1935469e+00 -1.0888739e+00 -1.3786150e+00 7.4092237e-01 -1.3002266e+00 1.4600354e+00 7.8127095e-01
+1 8.7131097e-01 1 1 -7.1492098e-01 -8.7316997e-01 -9.2629061e-01 -1.1371130e+00 -5.9103805e-01 9.2509578e-03 -1.6519008e-01 -1.0363982e+00
+1 2.4782944e-01 1 1 9.1498867e-01 -9.8846504e-01 1.5669161e+00 -1.1497511e+00 1.3938651e-01 1.5428074e+00 8.1830510e-01 1.3870944e+00
+1 8.4346551e-01 1 1 1.1847426e-01 -3.8998369e-01 -8.1162659e-01 6.9567572e-02 -9.5898639e-01 -7.4261586e-01 -6.3880762e-01 -8.6322722e-01
+1 7.8739265e-01 1 1 -5.7282131e-01 -1.0935557e+00 -2.1287246e-01 5.4971539e-01 -1.3140139e+00 4.0278613e-01 1.5240477e+00 -3.8499383e-01
+1 1.1173760e+00 1 1 -1.5678925e+00 -1.0736367e+00 5.2660250e-01 -3.5744380e-01 7.6458368e-01 -5.0576329e-01 1.2653287e+00 1.0895380e+00
+1 4.4192272e-01 1 1 1.0928755e-01 6.9598525e-01 7.4170338e-01 -8.3271828e-01 1.2439522e+00 7.8603291e-01 9.3879840e-01 -4.7901107e-01
+1 4.4777575e-01 1 1 -1.0358421e+00 1.2745862e+00 -3.0858423e-02 2.9910980e-01 -1.9407857e-01 4.5803495e-01 1.3064219e+00 1.1629279e+00
+1 3.4768750e-01 1 1 1.3087224e+00 -5.5058587e-01 -2.7472968e-01 5.9020541e-01 -9.0540999e-01 1.2914728e+00 4.4262440e-01 1.4812296e+00
+1 7.3313233e-01 1 1 1.4065183e+00 1.4352473e+00 7.5944027e-01 -1.5673245e+00 6.4912523e-01 5.2011114e-01 -1.0319458e-01 1.0451901e+00
+1 8.4709286e-01 1 1 -1.1316353e+00 1.0523821e+00 -3.7835097e-01 2.3221142e-01 -9.0349667e-01 -1.5444761e+00 -2.3213711e-01 -1.2760320e+00
+1 8.2205310e-01 1 1 -1.9239418e-01 2.1967487e-01 -3.6123539e-01 9.1934057e-01 1.3903160e+00 9.7070008e-01 3.2961869e-01 1.3825291e+00
+1 1.6451249e-01 1 1 -8.7016460e-01 7.0413576e-01 1.4153578e+00 1.0043317e+00 -1.2518808e-01 2.6557287e-01 1.2733993e+00 9.4804814e-01
+1 9.6025419e-01 1 1 -7.4270795e-01 3.0214290e-02 -2.2070004e-01 2.6034574e-02 8.3103859e-01 -7.1987277e-01 1.4930874e+00 -3.1280766e-01
+1 7.0116244e-01 1 1 -1.1449822e+00 -1.1264369e+00 9.1540305e-01 8.8170041e-01 -2.5528255e-01 -6.2827062e-01 -7.2226045e-01 -1.4739130e+00
+1 9.3223810e-01 1 1 -1.4600648e+00 -7.8735003e-01 7.9980364e-01 -1.5382881e-01 8.8182217e-01 -4.5145579e-01 8.2699468e-02 -5.9835545e-01
+1 4.8306489e-01 1 1 -3.2933357e-01 -6.0371004e-01 -5.7515844e-01 1.2987909e-01 -1.2488514e+00 -6.7125677e-01 1.3460032e+00 -3.2190546e-01
+1 8.2989495e-01 1 1 3.7696747e-01 7.8963296e-01 -7.3095338e-03 -5.2911236e-01 -4.6428508e-01 -3.5333269e-01 -3.3366371e-01 -4.4244612e-01
+1 1.0552896e+00 1 1 -9.0008680e-01 1.2738353e+00 -3.2922148e-01 1.0573311e+00 4.7683675e-01 -8.5245478e-01 -1.4305609e-01 -4.2194063e-02
+1 8.0251109e-01 1 1 -9.9030175e-01 -6.0382529e-01 -8.8074900e-01 -1.4265791e+00 -7.5717399e-03 -1.5449911e+00 -1.0253483e+00 8.4431768e-01
+1 6.8391733e-01 1 1 1.5641140e-01 -1.1473517e+00 4.3611904e-01 1.2063293e-01 1.5470655e+00 -1.4026019e+00 -1.3928677e+00 -1.2678902e-01
+1 5.9446940e-01 1 1 -7.0668062e-01 -4.4445853e-01 5.1699226e-01 1.1503806e+00 -1.4319661e+00 9.8139374e-01 1.2216169e+00 -9.4329272e-01
+1 3.6672238e-01 1 1 1.1805699e+00 6.9276490e-01 -5.5639092e-01 1.0861443e+00 6.8768638e-01 9.2319323e-01 1.4065584e+00 -1.4442323e+00
+1 6.4825386e-01 1 1 -4.6163220e-01 5.5729868e-01 1.2591098e+00 -9.6709193e-01 2.5661935e-02 -2.1749655e-01 -4.5703452e-01 -1.2681083e+00
+1 4.7549122e-01 1 1 1.0814533e+00 1.4311875e+00 8.9986255e-02 6.8626882e-01 9.0194402e-01 1.3492731e+00 -1.8518962e-01 -5.3216117e-01
+1 5.7186283e-01 1 1 -1.2702229e+00 -1.2069528e+00 1.2929296e+00 1.3333934e+00 7.8862011e-01 1.2179434e+00 8.3642727e-01 8.1528923e-02
+1 1.1695381e+00 1 1 -1.5148931e+00 7.9428940e-03 -1.2929629e-01 1.3617628e+00 -4.1292116e-02 -6.4273579e-01 -7.9401147e-01 5.2220718e-01
+1 3.6061156e-01 1 1 -1.3409165e+00 1.5493274e+00 8.9940870e-01 6.4411833e-01 2.9538626e-01 1.4767306e+00 5.3480506e-01 -8.7387949e-01
+1 1.0394276e+00 1 1 1.0013172e+00 -1.1153811e+00 -9.8180568e-01 -2.3146390e-01 8.4051297e-01 8.2943808e-01 3.7209719e-01 -3.4701590e-01
+1 7.1089894e-01 1 1 -3.7371255e-01 -3.2614104e-01 -1.5634127e+00 -9.2203718e-01 -1.2406566e+00 1.1192812e+00 -1.0734667e+00 -1.5002244e+00
+1 5.5566866e-01 1 1 -9.4307378e-01 6.2675272e-01 3.6348533e-03 7.9768192e-01 -9.6565442e-01 -9.7510887e-02 4.1226866e-01 1.5150183e-01
+1 3.5021383e-01 1 1 -9.0614421e-01 7.2795941e-02 1.4007191e+00 1.4641836e+00 -2.8619067e-01 1.0458828e+00 -1.3540880e+00 -1.5404252e+00
+1 6.5531477e-01 1 1 8.7539383e-01 1.4018394e+00 -1.2097679e+00 4.3890149e-01 -2.2824751e-01 9.4069408e-01 -4.5941680e-01 -6.1810418e-02
+1 9.4187208e-01 1 1 6.6575659e-01 -1.2295118e+00 -1.8207901e-01 1.5783303e-01 -2.7133200e-01 -1.3905023e+00 6.1665500e-01 1.0194704e+00
+1 1.0060806e+00 1 1 -9.8207801e-01 9.9136996e-01 -2.9072345e-01 1.1955824e+00 1.3155787e+00 1.3480585e-01 6.4622541e-03 -7.2238288e-03
+1 1.1633671e+00 1 1 1.4275503e-01 -1.0524700e+00 -1.0124571e+00 5.2637015e-01 4.0177835e-01 5.9358177e-01 -1.3446383e+00 1.1112234e+00
+1 1.2561087e+00 1 1 -8.9301968e-01 1.4456247e+00 -1.5003544e+00 -2.1800780e-02 1.4061918e+00 -1.3693979e+00 1.2819409e+00 -4.3678426e-01
+1 5.0162880e-01 1 1 1.5479093e+00 -4.6353211e-01 1.1077293e+00 1.1606232e+00 -3.3514716e-01 -1.6272630e-01 5.3758299e-01 8.6903301e-01
+1 4.8710166e-01 1 1 1.8303179e-01 5.6555559e-01 5.2773001e-01 4.4499993e-01 5.7363302e-02 1.3863399e+00 -6.3208791e-02 5.7347412e-01
+1 4.9691580e-01 1 1 5.9605194e-01 -1.1665207e+00 8.4219123e-01 -1.0182390e+00 -3.6392355e-01 -9.7793480e-01 -4.9183051e-01 -2.6706488e-02
+1 1.0745870e+00 1 1 -6.9401510e-01 9.6567959e-01 -1.3085302e+00 -1.2870542e+00 2.1786861e-01 6.6261063e-01 -6.6504977e-01 3.9181354e-01
+1 3.9724469e-01 1 1 4.2172146e-01 7.0918996e-01 -1.3191393e+00 1.4868764e+00 -1.3792287e+00 -4.4910311e-01 2.9511784e-01 4.3192011e-01
+1 1.0494657e+00 1 1 4.3956679e-01 1.5318612e-01 -5.5507488e-01 -1.4378834e+00 1.1149495e+00 1.1711401e+00 -5.2931313e-01 -9.3936765e-01
+1 1.4619656e-01 1 1 -1.2268891e+00 -1.5069255e+00 1.3866641e+00 -1.3753023e+00 -6.4411328e-01 1.2734076e+00 8.2464134e-01 -1.4489665e+00
+1 5.4173497e-01 1 1 1.0889725e+00 6.2237436e-01 1.3284448e+00 1.1323193e+00 3.1633913e-01 -1.5096364e+00 -9.5983706e-01 8.4697142e-01
+1 9.5131544e-01 1 1 -5.5812044e-01 -1.2576976e+00 -1.2755208e-01 -8.7746345e-01 1.1370625e+00 -9.5653708e-01 9.6750291e-02 4.9226020e-01
+1 9.9109269e-01 1 1 4.6544565e-01 -1.4883709e+00 -1.2015899e+00 -8.9233176e-01 3.0053159e-01 -9.8902421e-01 -1.2628488e+00 -1.5377848e+00
+1 7.3811296e-01 1 1 1.7927409e-01 1.4522264e+00 -9.6425950e-01 5.4338004e-01 -6.4656717e-01 -3.6319571e-01 -9.9369375e-02 3.3288002e-01
+1 2.5817828e-01 1 1 2.7222230e-01 5.3510652e-01 1.1671089e+00 -2.1539056e-02 -8.5461176e-02 -1.1577257e-01 1.2261981e+00 -4.6194612e-01
+1 7.2390275e-01 1 1 1.0812696e+00 -8.4443976e-01 -5.0549221e-01 -7.2375304e-01 -6.3814735e-01 -1.1437024e+00 -1.3681409e-01 -1.0530368e+00
+1 8.4235343e-01 1 1 -1.2155859e+00 1.2165253e+00 -9.4105858e-01 1.2935011e-01 5.4819166e-02 1.1988754e+00 2.1137713e-01 1.3441901e+00
+1 7.5560105e-01 1 1 -5.7505158e-01 6.5584917e-01 1.5474020e+00 5.2059220e-03 8.5908047e-01 -6.7683313e-01 -5.2585628e-01 6.0986487e-01
+1 7.6271367e-01 1 1 -1.3528763e+00 -9.9159467e-01 1.0810449e+00 -4.6866337e-01 -1.9436295e-01 1.7263959e-01 -7.6633183e-01 -1.0179889e+00
+1 6.6783275e-01 1 1 1.0556255e+00 4.1733590e-01 1.2910448e+00 -8.5242744e-01 5.9828162e-01 -1.2780070e+00 7.9078372e-01 -2.2518360e-01
+1 6.5335609e-01 1 1 1.3245560e+00 -1.0119207e+00 -3.9027320e-01 -1.0854306e+00 -9.1884166e-01 -3.9503939e-01 -1.3764795e+00 9.5845657e-01
+1 9.6704973e-01 1 1 4.8697078e-01 1.2316020e+00 3.2385920e-01 3.9689668e-01 1.0977727e+00 -1.2418032e+00 1.9699551e-01 -1.3075457e+00
+1 1.0265439e+00 1 1 6.6901784e-01 -4.1951584e-01 -1.2784621e+00 1.0413264e+00 -3.0769745e-01 -1.3869569e+00 -3.3510846e-01 -4.7930829e-01
+1 2.7650127e-01 1 1 4.2279233e-01 -1.0687309e+00 1.3806899e+00 -2.4040311e-01 -4.0954404e-01 3.3107857e-02 7.0779479e-01 -6.9082474e-01
+1 7.2293133e-01 1 1 -4.1196424e-01 1.4664914e+00 1.4511205e+00 -3.6692807e-01 2.2797499e-02 3.8185578e-01 -1.3043670e+00 6.3506838e-01
+1 7.0871315e-01 1 1 1.8729106e-01 1.5267644e+00 7.9794468e-01 -1.3701620e-02 -1.1674245e-01 -4.2369349e-01 -4.6324957e-01 -1.5375123e+00
+1 1.0773814e+00 1 1 -7.5054510e-02 -1.9979025e-01 -4.0276023e-01 -9.4686002e-01 1.4050629e+00 9.7397608e-01 -9.6896845e-01 -1.3702881e+00
+1 5.7056948e-01 1 1 1.4791042e+00 4.8773466e-01 9.4098246e-01 1.4320442e+00 -4.6041896e-01 -1.2233836e+00 5.6359527e-01 5.8428012e-01
+1 3.4167815e-01 1 1 -1.1766809e-01 9.4125602e-01 3.1474321e-01 6.2574068e-01 -5.1878870e-01 3.1596843e-01 4.4386776e-01 -6.2264736e-01
+1 6.5405602e-01 1 1 1.5557544e+00 -1.3705991e+00 -5.5288537e-01 -1.2285626e+00 -1.3620668e+00 1.1897858e+00 -1.1970372e+00 -1.8898828e-01
+1 2.0829347e-01 1 1 8.7926110e-02 -1.5018959e+00 4.8662205e-01 1.2365580e+00 5.2916962e-01 4.9345348e-01 1.5443521e-01 -1.7579659e-01
+1 2.5287718e-01 1 1 1.2255815e+00 3.3223097e-01 1.0911157e+00 1.1949728e+00 -9.4936362e-02 -3.3195195e-01 6.3705900e-01 -1.5162692e+00
+1 6.5497222e-01 1 1 -1.0746828e+00 1.1957930e+00 9.0534165e-01 -2.9468450e-01 3.3362998e-01 3.5206948e-01 5.0284488e-01 6.6366712e-01
+1 1.6701134e-01 1 1 -1.1782812e+00 9.2470427e-01 1.3438734e+00 1.5291705e+00 -4.2372952e-01 -1.5287723e+00 4.2962781e-01 -1.5422532e+00
+1 3.4408237e-01 1 1 1.2286805e+00 4.5775268e-02 1.5702271e+00 -6.0064118e-01 3.6846552e-01 1.0106993e+00 1.3746921e+00 6.3173944e-01
+1 3.6667824e-01 1 1 7.4414282e-01 -3.4527504e-01 1.4288665e+00 -1.0391645e+00 7.2092108e-01 2.3127093e-01 1.1772036e+00 -9.3834438e-01
+1 7.9291264e-01 1 1 1.2806889e-01 -5.1603353e-01 6.2497525e-01 -1.1244365e+00 -6.0222391e-01 8.2042217e-01 -4.8988205e-01 4.1123942e-02
+1 8.9850724e-01 1 1 4.6290230e-01 9.6171581e-01 -1.5268879e+00 1.4165617e+00 6.3435579e-01 3.8518171e-01 6.6672708e-01 1.9703677e-02
+1 5.3338296e-01 1 1 1.4155306e+00 6.3492595e-02 1.2656523e+00 1.1628004e+00 -9.4777021e-01 -1.0734620e+00 -3.7902233e-01 1.2924734e+00
+1 7.2831403e-01 1 1 -4.5772541e-01 -1.0214501e+00 9.4438865e-02 -6.6115711e-01 -1.2991908e+00 4.9006276e-01 9.2152336e-01 -1.5133543e+00
+1 3.8925299e-01 1 1 7.6940292e-01 1.2913639e+00 7.2970788e-01 -2.5427336e-01 -1.4316122e+00 -7.7112875e-01 -8.6395794e-03 -6.1100304e-01
+1 3.2130657e-01 1 1 5.5955621e-01 -1.3101648e+00 -5.7746283e-01 -1.0063079e+00 3.5184064e-01 -1.2911867e+00 -6.9214963e-01 7.3833362e-01
+1 9.4416791e-01 1 1 -1.4672623e+00 -5.1701624e-01 -1.0380316e+00 1.3178280e+00 9.0832565e-01 1.1476388e+00 3.5873658e-01 -1.1777348e-01
+1 1.2011648e+00 1 1 1.2243745e+00 1.5330731e-01 -9.3349215e-01 5.0676536e-01 1.2304597e+00 -1.0128615e+00 5.6933505e-01 -2.1558591e-01
+1 3.7471927e-01 1 1 6.3071885e-01 5.3003094e-01 -8.8804683e-02 3.4773886e-01 -7.6816294e-01 1.1273727e+00 -4.7698013e-01 -1.0960497e+00
+1 7.5920780e-01 1 1 7.5805422e-01 -1.3266807e+00 -2.8379478e-01 1.0846338e+00 1.4313480e+00 8.0808094e-01 7.3939122e-01 9.9239083e-01
+1 1.0162343e+00 1 1 1.4590147e+00 1.5022624e+00 -8.0123388e-01 -1.2211435e+00 1.4914011e+00 3.1127576e-01 -1.1923110e+00 3.9729733e-01
+1 6.6504567e-01 1 1 1.5295612e+00 -4.5532311e-01 -1.4716777e+00 2.6549016e-01 -7.8971515e-01 8.5987931e-01 1.0486195e+00 1.4918059e+00
+1 8.5448064e-01 1 1 -3.1801888e-01 3.0413336e-01 -7.2768507e-01 1.0316051e+00 4.8649401e-01 6.6528956e-01 -1.8748101e-01 -2.6879308e-01
+1 6.1914992e-01 1 1 -1.0941941e+00 1.9817240e-01 1.7270138e-02 -2.6216839e-01 -1.0607862e+00 5.9338798e-01 2.4064673e-02 4.9702415e-03
+1 5.7679345e-01 1 1 7.6317145e-01 5.9527331e-01 1.2326819e+00 1.3904403e+00 -9.6060104e-02 -1.4849047e+00 -8.1050115e-01 -1.2881527e+00
+1 1.2023961e+00 1 1 -5.0019008e-01 -1.2140191e+00 -1.1188763e+00 -1.1775517e+00 2.9645435e-01 1.8439571e-02 -1.4707725e-01 -1.2680075e+00
+1 7.9099463e-01 1 1 2.0727177e-01 6.2455244e-01 6.1993278e-01 9.2193775e-01 -5.7733856e-02 -1.1038011e+00 5.0613615e-01 1.1632536e+00
+1 9.5857517e-01 1 1 -4.0959018e-01 7.9175274e-01 -1.4526207e+00 6.7286191e-01 4.1920401e-01 -4.8038830e-01 -8.0256385e-01 6.7271826e-01
+1 1.0427572e+00 1 1 -7.5266023e-01 -7.9810946e-01 -8.7927075e-01 -9.4341237e-01 -1.0304764e+00 6.9375372e-03 1.3082162e+00 -2.1609236e-01
+1 9.3222041e-01 1 1 1.2331991e+00 7.7489262e-01 1.4836568e-01 -3.1360744e-01 3.8365375e-01 3.6025890e-01 -8.1744062e-01 -1.8321046e-01
+1 1.2465138e+00 1 1 1.2911591e+00 -1.4228427e+00 -8.4256814e-01 7.9229126e-01 1.5204825e+00 1.0223714e+00 -5.3982822e-01 -4.5742480e-01
+1 5.6841116e-01 1 1 1.5297463e+00 8.6496592e-02 1.2568807e+00 -1.1720942e+00 1.0346069e+00 -1.5160385e+00 2.6672728e-02 -4.6132088e-01
+1 1.9536657e-01 1 1 -3.4883087e-01 -8.0918226e-01 3.2481983e-01 1.5403592e+00 -7.7510651e-02 1.3989205e+00 -9.5921383e-01 3.0585288e-02
+1 1.0251068e+00 1 1 -5.8853631e-01 2.8323841e-02 -8.4119838e-01 -1.0472719e+00 1.0394395e+00 -2.2284527e-02 1.1466140e+00 -1.1742674e+00
+1 7.4873246e-01 1 1 1.3455100e+00 -1.4832795e+00 -8.5428876e-01 8.4491541e-01 -5.3631852e-01 -6.8651133e-01 6.1257825e-01 -4.2728928e-01
+1 5.9365076e-01 1 1 8.0259998e-01 -9.4141080e-01 -9.5276538e-01 4.9456787e-01 -6.7606094e-01 8.7388741e-01 6.0358148e-01 2.2979842e-01
+1 1.2677951e+00 1 1 -7.0103370e-01 -1.2307089e+00 -4.3001739e-01 -4.5196270e-01 5.8448426e-01 4.7998382e-01 1.9120633e-01 1.2046559e+00
+1 5.6218186e-01 1 1 -1.3010038e+00 -2.7765220e-01 1.5024483e+00 2.3400957e-01 -3.3330858e-01 -5.2183573e-01 -2.4452330e-01 -9.1216351e-01
+1 1.0878847e+00 1 1 -4.8611665e-01 -1.2353852e+00 -4.7366936e-01 -2.7519938e-01 -4.5760926e-01 8.3364643e-01 -4.9987848e-01 2.4004417e-01
+1 4.4637458e-01 1 1 1.1200333e+00 -3.3282065e-01 -1.6517515e-01 -8.5165651e-01 -4.2001013e-01 -4.0763414e-01 -8.3890003e-01 6.1733307e-01
+1 6.1485454e-01 1 1 -2.4331197e-02 1.4599186e+00 1.0692181e+00 -6.9475554e-01 4.8428477e-02 7.0652783e-01 7.5035452e-02 -1.1636868e+00
+1 7.1997410e-01 1 1 -5.2738609e-01 1.0130849e+00 4.3916079e-01 5.4351878e-01 2.6492277e-01 -6.0704318e-01 1.3421901e+00 1.4713036e+00
+1 5.0130210e-01 1 1 -1.3452058e+00 -5.1348206e-01 1.3742346e+00 -8.3137392e-01 9.2018811e-01 1.3181617e+00 1.5541106e+00 7.2412821e-01
+1 4.6612358e-01 1 1 1.1688519e+00 -1.3798307e-01 -2.2819614e-01 9.0257516e-01 -4.5904922e-01 -1.6752407e-01 7.3593621e-01 -1.0708235e-01
+1 6.6636703e-01 1 1 5.1484191e-01 -5.8611048e-01 5.9214813e-01 -1.1702147e+00 5.1136404e-01 -7.1001404e-01 4.2959295e-01 3.9957224e-01
+1 5.2990856e-01 1 1 1.0018521e+00 1.2757758e+00 -3.3192969e-01 -1.4276396e+00 -9.0208633e-01 -1.4370919e+00 7.8880215e-01 -1.1144243e+00
+1 7.1152469e-01 1 1 -8.0764103e-01 5.9326253e-01 7.2633682e-01 1.1452583e+00 -3.8753574e-02 -6.3870909e-01 -1.2327020e-01 4.7023713e-02
+1 5.6737188e-01 1 1 7.9902762e-01 -4.5176832e-01 -6.8616220e-01 -1.8202850e-01 -1.0216395e+00 3.8456495e-02 -1.4927494e+00 -1.3537999e+00
+1 9.0497673e-01 1 1 -1.0513726e+00 3.5935129e-01 4.5845269e-01 5.5832396e-01 1.2511679e+00 -8.2977739e-01 1.2011005e-01 1.2406654e+00
+1 1.2229548e+00 1 1 1.0399837e+00 1.4760763e+00 -1.1123627e+00 -1.8653187e-01 -1.4423883e+00 -5.3881678e-01 -1.3544878e+00 1.1135468e+00
+1 9.6184430e-01 1 1 -8.1559311e-01 -7.4243785e-01 1.3834435e-01 2.6831840e-01 1.4510828e+00 1.3179997e+00 -8.9573409e-01 9.1386731e-01
+1 4.0664802e-01 1 1 -9.0472012e-01 2.5299636e-01 3.7492217e-01 1.4418552e+00 1.6501933e-01 2.5090614e-01 -9.0822936e-02 1.2147421e-01
+1 8.5180156e-01 1 1 -3.2265380e-01 1.5350123e+00 -7.1799706e-01 -9.8575639e-01 -5.4646416e-01 9.6217469e-01 3.5293806e-01 -4.1811086e-01
+1 6.8679423e-01 1 1 -4.5356756e-01 1.9293168e-01 -5.1926759e-01 1.1520223e+00 -1.5477996e+00 1.4925699e+00 5.0307805e-01 5.5345857e-01
+1 4.7085416e-01 1 1 1.5354016e+00 4.7909172e-01 1.3922724e-02 4.0265481e-01 -1.4812927e+00 4.1827205e-03 1.2070238e+00 -2.7766734e-01
+1 3.4753431e-01 1 1 4.5305664e-01 1.9259257e-01 1.5213619e+00 4.2885194e-01 1.0360522e+00 1.1839453e+00 1.1849082e+00 -1.4898634e+00
+1 8.1018829e-01 1 1 -6.9772568e-01 1.0628263e+00 1.0658902e-01 9.0101043e-01 -9.1884626e-01 -2.7899892e-01 1.9674390e-01 1.5015324e+00
+1 6.4693348e-01 1 1 8.8994595e-01 -1.7491260e-01 7.3391308e-01 8.0572900e-01 1.0203966e+00 1.2629845e+00 -1.4223777e+00 -1.5826778e-01
+1 3.3377584e-01 1 1 1.9891423e-01 7.7470634e-01 9.8442562e-01 -1.5186554e+00 -1.4879345e-01 -7.6084480e-01 -1.5237850e+00 9.2240159e-01
+1 1.0100915e+00 1 1 4.9683390e-01 -1.4121677e+00 -1.5271703e+00 1.3997654e+00 -6.3808464e-02 -1.2364131e+00 9.4922105e-03 -9.5615514e-01
+1 8.2867170e-01 1 1 -6.5918672e-02 4.3080144e-01 -3.3900675e-01 -1.5304143e+00 -1.1457655e+00 1.2396090e+00 -6.8564305e-01 -8.5294200e-01
+1 5.9499212e-01 1 1 1.0870783e+00 -8.9125007e-01 1.1625496e+00 -1.4539687e+00 1.0817873e+00 -9.3460072e-01 -2.4084613e-01 -3.0895232e-01
+1 7.0013034e-01 1 1 -9.7775896e-01 -1.2608230e-01 1.4064680e+00 -1.5435158e+00 1.2022436e+00 1.2894043e-01 -1.5296269e+00 4.9094438e-01
+1 7.2979148e-01 1 1 4.7628419e-01 1.5098891e+00 1.1644997e+00 1.4016941e+00 -6.1563634e-01 -5.9705082e-01 -7.8676066e-01 1.4798187e+00
+1 1.1855936e+00 1 1 1.3035067e-01 -1.0791000e+00 -3.7581007e-01 -5.3098349e-01 1.4061783e+00 -3.8613184e-01 -1.2296771e-01 -6.7630733e-01
+1 4.3587671e-01 1 1 1.1136528e+00 -1.9260888e-02 1.5029662e+00 1.0251632e+00 -5.6343990e-01 8.1251356e-01 4.4966493e-01 -4.1505764e-01
+1 7.6230532e-01 1 1 -4.4627970e-01 -1.3370849e-01 -1.1933264e+00 1.4242697e+00 -9.7421920e-01 -5.8778337e-01 -1.1534743e+00 -1.5381276e+00
+1 1.0301195e+00 1 1 1.5003259e+00 -9.9983745e-01 -3.1002742e-01 -1.2343370e+00 2.7879422e-01 1.4338354e+00 3.2592360e-01 8.5558897e-01
+1 5.2226068e-01 1 1 1.5548543e+00 1.1116114e-01 1.2712953e+00 -1.5662656e+00 -1.5617648e+00 -6.8497410e-01 -1.1395897e+00 8.1426087e-01
+1 6.5908664e-01 1 1 6.6862427e-01 -9.6239223e-01 6.8799848e-01 -8.2186948e-01 -5.7435072e-01 -1.5641739e+00 1.2058652e+00 5.0481273e-01
+1 9.6222830e-01 1 1 9.1216779e-02 1.1343417e+00 -1.0121010e+00 4.2249393e-01 1.0017106e+00 -2.2296937e-01 5.6277699e-01 -1.0542838e+00
+1 5.4418012e-01 1 1 -1.6813871e-02 -1.4440488e+00 1.3423472e+00 8.5615680e-01 -4.4890774e-02 4.7391474e-01 -7.4264783e-01 -7.6537229e-01
+1 4.4459046e-01 1 1 1.5260544e-01 -1.3254500e+00 1.0519854e+00 9.3295573e-01 -4.9700702e-01 1.1477272e+00 -1.3454395e-01 1.2097545e+00
+1 5.6053959e-01 1 1 1.3000469e+00 1.9569077e-01 -1.6540257e-01 4.9807214e-01 2.9785448e-01 4.7297146e-01 6.6660972e-01 -4.2968216e-02
+1 8.2114441e-01 1 1 1.1120620e-01 -2.7277529e-01 3.8857305e-01 -1.2459397e+00 1.4832193e+00 1.0019455e+00 7.9008164e-01 3.9950149e-01
+1 8.9494761e-01 1 1 -2.0505532e-01 -9.5057583e-01 -6.2393401e-01 1.3481520e+00 -7.0994390e-02 7.6166569e-01 -6.1005331e-01 8.3805455e-01
+1 9.3527466e-01 1 1 -3.7628179e-02 -1.3293218e+00 1.7739100e-01 1.2251478e+00 6.0250159e-01 -6.7480023e-01 9.9237308e-01 1.4228906e+00
+1 1.0226423e+00 1 1 -9.5668021e-01 1.0958930e+00 3.9127348e-02 1.0606597e+00 8.9105852e-01 -2.1792556e-01 9.8955465e-02 7.1903136e-01
+1 4.7275600e-01 1 1 -2.5302490e-01 -4.8328279e-01 1.0204756e+00 1.1115429e+00 4.8390690e-02 4.2209571e-01 1.2419823e+00 -9.4692045e-01
+1 6.1482848e-01 1 1 1.1270058e+00 -1.5168451e+00 1.1783287e+00 -1.3508241e+00 -3.7016626e-01 4.4636916e-01 1.2549437e+00 4.1641809e-01
+1 5.8462667e-01 1 1 9.2372314e-01 4.0875881e-01 -4.2932392e-01 9.8946474e-01 -1.0309537e+00 3.2836476e-03 -8.1404535e-01 -7.2958898e-01
+1 9.5725776e-01 1 1 -7.3610358e-01 -6.5381304e-01 5.9112932e-01 1.4839487e+00 -1.3558869e+00 -1.3604020e+00 -2.4160447e-02 -5.6582452e-01
+1 7.9948988e-01 1 1 -1.0093084e-01 6.5536737e-01 1.3944408e+00 -3.7869601e-01 7.2214108e-01 2.3575705e-01 -7.9917786e-01 -2.1171420e-01
+1 8.6803870e-01 1 1 1.1537867e-01 3.3561370e-01 8.5113866e-02 1.2289614e-01 1.0527937e+00 8.2037177e-01 -1.4737149e+00 1.1438409e+00
+1 6.9168405e-01 1 1 8.0659474e-01 1.5007233e+00 1.0840949e+00 1.4889958e+00 8.5414092e-01 -4.6184954e-01 -4.0948023e-01 1.1281125e+00
+1 6.8188095e-01 1 1 4.6547109e-01 -1.1903999e+00 -8.5512507e-01 -3.7423480e-01 -1.5319498e+00 5.7021442e-01 1.0952448e+00 6.7477678e-01
+1 8.2539761e-01 1 1 6.0696955e-01 -1.3898927e+00 6.9934740e-01 -2.9572785e-01 1.0135482e+00 -1.4054160e+00 1.1877826e+00 -1.7608535e-01
+1 2.9265674e-01 1 1 5.8583100e-01 9.5659812e-01 1.2336966e+00 -2.9833091e-01 9.8869313e-01 8.0895173e-01 1.3828942e+00 -8.6118065e-02
+1 8.9336029e-01 1 1 3.1025860e-01 -1.1266157e+00 2.2774743e-01 -6.5751070e-02 1.0819389e+00 -7.6129062e-01 8.0078672e-01 8.8790238e-01
+1 2.7123859e-01 1 1 -5.2743633e-01 -6.5064069e-01 1.2912242e+00 7.6237475e-01 6.0904712e-01 6.9534688e-01 2.3947064e-01 4.1026281e-01
+1 1.0418126e+00 1 1 9.5206023e-01 5.6589755e-01 -5.1749185e-01 -1.3240435e+00 9.4613631e-01 -2.9632814e-02 4.0284622e-01 -5.0878137e-01
+1 9.4822013e-01 1 1 1.1448349e+00 1.4391842e+00 -1.5570482e+00 -1.2988793e+00 -1.0290915e+00 1.4745309e+00 5.0425693e-01 3.2671085e-01
+1 6.6005662e-02 1 1 -1.0143729e+00 1.2469032e+00 1.5691832e-01 6.6336608e-01 -1.4737997e+00 1.5583527e+00 -9.7074842e-01 -4.7471752e-01
+1 5.7329966e-01 1 1 8.5881464e-01 -8.6264808e-01 1.5299899e+00 -3.1863510e-01 1.3061249e+00 -2.2362802e-01 -1.0781082e+00 1.0679010e+00
+1 8.2183121e-01 1 1 -1.5205712e+00 -7.6190240e-02 6.0458532e-01 1.1154062e+00 -1.4089154e+00 -1.1713788e+00 9.4203122e-01 2.9402662e-01
+1 4.0517819e-01 1 1 6.1537481e-01 1.2404360e+00 1.3549008e+00 7.4805849e-01 -1.4570342e+00 9.9824265e-01 -9.0822761e-01 -1.9790948e-02
+1 3.1072000e-01 1 1 4.8134513e-01 3.9857791e-01 1.5541481e+00 -3.4736748e-02 3.4082428e-01 1.3593913e+00 4.1718204e-01 3.8236604e-01
+1 6.8515476e-01 1 1 3.6649767e-01 1.0233649e+00 1.3664274e+00 5.1571505e-01 1.1103335e+00 -1.5138315e+00 -4.5624437e-01 -1.2724583e+00
+1 3.0888824e-01 1 1 -9.3678454e-01 -5.2568424e-01 5.0342464e-01 -3.1276266e-02 3.1509044e-01 7.9338476e-01 5.2853748e-01 -1.3854651e+00
+1 6.3521655e-01 1 1 1.1246023e+00 -1.0165606e+00 7.4883181e-01 -1.0142325e+00 -1.0002098e+00 1.4985045e+00 -1.2946103e+00 -2.7139543e-02
+1 9.4309750e-01 1 1 1.3695933e+00 -1.3526166e+00 3.9613846e-01 7.5632367e-02 1.3674019e-01 -7.8286543e-01 1.5546989e-01 -6.0337227e-01
+1 4.2230697e-01 1 1 3.0601672e-01 -8.6292699e-01 8.6429007e-01 -1.1918391e+00 -1.4534520e+00 -6.2928202e-01 -8.2266259e-01 1.8335191e-01
+1 8.4098369e-01 1 1 4.3588975e-01 1.5193348e+00 -6.0115247e-01 -4.4489717e-01 8.5747140e-01 1.3995967e+00 -3.4092402e-01 -3.0692363e-01
+1 9.8767915e-01 1 1 -1.9497700e-01 5.9496231e-01 -2.0751244e-01 -3.9624591e-01 1.0363161e+00 -1.2241266e+00 3.5494864e-01 2.9617076e-02
+1 1.0434528e+00 1 1 -2.9732161e-01 -1.5779115e-01 -4.9381552e-01 4.7146638e-01 3.7564446e-01 3.9461509e-01 -2.6268875e-01 1.4025519e+00
+1 6.5114909e-01 1 1 1.1895310e+00 -4.9167359e-01 5.3037947e-01 8.3869469e-01 -1.1447502e+00 3.9379679e-01 -1.0721626e+00 1.3208389e+00
+1 7.9771346e-01 1 1 -6.4884208e-01 -1.1693387e+00 1.3894456e+00 -3.8465872e-01 -7.0346968e-01 -7.9306303e-01 3.3860076e-01 8.4548689e-01
+1 2.8081998e-01 1 1 -6.2067613e-01 7.2793380e-01 9.5475448e-01 4.3855726e-01 -1.4018068e+00 7.6728149e-01 1.4386479e+00 6.7463255e-01
+1 1.0644625e+00 1 1 1.5254648e+00 1.0216114e+00 -6.9669045e-01 6.5551214e-01 -1.3640799e+00 -5.3787528e-01 -1.4839222e+00 5.4132600e-01
+1 5.4807937e-01 1 1 -5.1549185e-02 1.4187181e+00 -5.6065377e-01 -3.7282329e-01 1.2524250e+00 1.4338095e+00 8.2399595e-01 1.3715544e-02
+1 1.0207262e+00 1 1 6.9242830e-01 -2.9323338e-01 -1.2715415e+00 1.4363667e+00 8.3702294e-01 -1.1202670e+00 7.5951774e-01 1.1808816e+00
+1 2.7203961e-01 1 1 1.1833233e+00 7.8539717e-01 1.4575437e+00 1.0171483e+00 -2.0739638e-01 -7.6307179e-01 9.2371678e-01 -1.5053453e+00
+1 1.1722164e+00 1 1 -1.3082339e+00 -8.0207448e-01 -1.2031613e+00 -1.3363124e+00 1.4568643e+00 -9.6634603e-01 -8.4300900e-01 -1.0924034e+00
+1 5.3043763e-01 1 1 5.1917252e-01 1.0836984e-01 9.0062348e-01 -1.5610905e-01 -5.5534109e-02 6.5632952e-01 1.3059559e-01 -5.5600135e-01
+1 3.4335272e-01 1 1 1.5297190e+00 -7.5181384e-01 5.8541082e-01 -4.9490727e-01 -3.0875173e-01 7.9847280e-01 -1.0531081e+00 1.5235375e+00
+1 9.9064777e-01 1 1 -8.0630151e-01 -2.4960575e-01 -4.6851010e-01 1.0308044e+00 7.2075739e-01 -9.5153583e-01 1.4442994e-01 -1.0267861e+00
+1 1.0594946e+00 1 1 1.3212812e+00 -1.0976058e+00 -1.4181108e+00 -1.1544974e+00 -2.1189694e-01 1.3855797e+00 -1.0171981e+00 -4.2581737e-01
+1 6.6969025e-01 1 1 -1.1445941e+00 -2.8488361e-02 1.0757106e+00 -1.1610442e+00 1.2142384e+00 -1.1890982e+00 4.9845217e-01 -1.6454073e-01
+1 7.1206089e-01 1 1 -1.2216996e+00 -1.2818042e+00 -3.9734480e-01 -1.2381522e+00 -8.1768142e-02 -1.5028264e+00 -1.1420176e+00 -8.3446739e-01
+1 2.6885620e-01 1 1 3.4442773e-01 -1.3822826e+00 8.5195459e-01 2.8588174e-01 -1.4011731e+00 4.0087477e-01 1.2408331e+00 -8.2385156e-01
+1 5.9836461e-01 1 1 -1.1584409e+00 5.4075422e-02 -5.7845506e-01 1.3192419e+00 -1.3831887e-01 -1.2139825e+00 7.8960546e-01 -1.4743720e+00
+1 4.4466132e-01 1 1 -1.4666997e+00 9.2533516e-01 1.1351140e+00 -8.6238505e-01 5.3289625e-02 1.2397750e+00 8.1159475e-01 1.1125126e+00
+1 9.1167002e-01 1 1 1.2553666e+00 1.2243287e+00 -1.0307535e+00 1.2030072e+00 2.8482893e-01 -1.2863011e+00 -3.2239228e-01 -7.6016041e-01
+1 8.8220873e-01 1 1 1.0455671e-02 -1.3871500e-01 -1.1324420e+00 -3.4824185e-01 -6.6733913e-01 -1.5634895e+00 8.0025583e-01 8.4132116e-01
+1 9.6633700e-01 1 1 -2.0072918e-01 -3.2121528e-01 -1.1841049e+00 -1.1371951e-01 -4.8297011e-01 -1.2872457e+00 7.4155502e-01 -2.2374399e-01
+1 7.1729528e-01 1 1 4.1517380e-01 -1.4091110e+00 7.3863739e-01 -1.1954797e+00 5.9672115e-01 1.4102912e+00 6.1716766e-01 2.1230632e-02
+1 1.0508792e+00 1 1 3.4883747e-01 1.5382684e+00 -1.2956347e+00 1.1999508e+00 1.1286509e+00 -5.5199975e-01 -8.0207779e-01 -1.3183380e+00
+1 1.0421050e+00 1 1 6.9947405e-01 1.5106156e+00 -1.3532577e+00 -1.4510372e+00 2.9978397e-01 -3.3672782e-01 5.2704275e-02 3.4566295e-01
+1 7.1086661e-01 1 1 2.2057426e-01 -1.4359270e+00 9.2935364e-01 6.0143946e-01 -6.4541956e-01 -1.3761394e+00 -1.2837218e-01 7.5233343e-01
+1 9.9649974e-01 1 1 1.1227498e-01 9.0180053e-02 -3.5207663e-01 -1.2521926e+00 3.5285568e-01 -3.6906078e-01 7.2287599e-01 -4.4243984e-01
+1 7.1254889e-01 1 1 -1.0915740e+00 1.4084856e+00 1.4087127e+00 -7.1035458e-02 -8.8157831e-01 -1.3006763e+00 8.3793361e-01 6.3481998e-02
+1 5.1076492e-01 1 1 8.1649232e-01 5.1601414e-01 1.1914959e+00 -8.7736680e-02 -9.3578453e-01 -1.2653199e+00 -6.0976312e-01 -1.1995603e+00
+1 5.7752368e-01 1 1 3.0971217e-01 -1.2876200e+00 9.6005783e-01 -1.1834185e+00 -9.1783744e-01 -7.9142234e-01 -4.1346122e-01 -1.4095805e+00
+1 7.0779845e-01 1 1 -2.8654246e-01 1.4024316e+00 4.7204733e-01 -2.9156099e-01 -8.7400324e-01 6.8031530e-02 1.6020449e-01 -6.9091136e-02
+1 5.4002553e-01 1 1 1.4246297e-01 -7.0185699e-01 1.1780111e+00 6.1895323e-01 7.1471549e-01 -1.3380195e-01 2.1203787e-01 1.1745566e+00
+1 6.2971785e-01 1 1 4.8146586e-01 5.7003398e-01 5.1517954e-01 9.3362279e-01 -1.2270215e+00 5.7094866e-01 1.1544741e+00 -9.9610032e-01
+1 8.1968760e-01 1 1 -7.4600642e-01 -1.2965148e+00 3.9316153e-01 -8.5712069e-01 -1.1359536e+00 1.5102031e+00 7.6968873e-01 8.9121734e-02
+1 7.2137300e-01 1 1 -3.3563135e-02 -4.3807435e-01 1.0965586e+00 -1.4251720e+00 -5.1409687e-01 1.0569636e+00 -9.2003989e-01 -6.7071570e-01
+1 3.8168845e-01 1 1 1.3910705e+00 1.1775093e+00 1.2775217e+00 -1.3637088e+00 -1.0463225e+00 -1.3191736e+00 -1.9136183e-01 -6.8431430e-01
+1 1.1098637e+00 1 1 -1.0234627e-02 1.5062800e+00 -1.4787969e+00 1.2059960e+00 1.0932015e+00 -1.1314495e+00 7.7258812e-01 1.0022394e-01
+1 1.1884682e+00 1 1 7.7422297e-01 1.0946447e+00 -9.9978219e-01 -3.8108306e-01 1.4029422e+00 -2.1187144e-01 6.8608550e-01 5.7010627e-01
+1 4.6824855e-01 1 1 -1.1134141e-01 5.2615179e-01 1.0398713e+00 8.4446334e-01 -1.5442537e+00 -1.4988720e+00 1.3939314e+00 -8.1584344e-02
+1 4.7011848e-01 1 1 1.0742193e+00 -5.5010318e-01 4.3666499e-01 -8.2027696e-01 1.5667158e+00 8.8909071e-01 9.4779506e-01 -1.4536711e+00
+1 7.5637135e-01 1 1 -3.2991792e-01 1.2308629e-01 2.6798459e-01 -1.0862671e+00 -1.0371614e+00 1.5329170e+00 -1.4247134e+00 3.1603940e-01
+1 1.2837972e+00 1 1 -1.9391368e-02 1.5433295e+00 -1.0268987e+00 -1.0963942e+00 1.1256500e+00 -4.6551879e-01 6.1704943e-02 -7.5890651e-01
+1 7.5968388e-01 1 1 8.1492149e-01 -1.3911174e+00 8.2368695e-01 1.4849804e+00 1.2933768e-01 -1.4086619e+00 3.4940509e-01 -7.5591547e-02
+1 7.6659481e-01 1 1 -9.5856407e-01 -7.7766425e-01 -1.2922115e+00 1.2531891e+00 -2.0381041e-01 -3.3802279e-01 8.1465293e-01 -1.2636951e+00
+1 1.0270841e+00 1 1 -4.9922486e-01 -1.1776696e+00 -3.6939920e-01 1.1128017e+00 -1.1055805e+00 -1.1494895e+00 8.1103880e-01 1.3839273e+00
+1 6.7405624e-01 1 1 7.2176412e-01 -1.0590581e+00 -7.0526284e-01 9.5683786e-01 1.0298767e+00 1.3247678e+00 -2.4136480e-01 -6.8664472e-01
+1 4.4974331e-01 1 1 1.0002836e+00 6.7414778e-01 -1.2344889e-01 -2.3887206e-01 -1.0375888e+00 9.0605655e-01 -8.2206676e-01 -1.3679793e+00
+1 8.9442033e-01 1 1 1.1044495e+00 -1.3229458e+00 -1.3543435e+00 2.3272211e-01 2.2635457e-01 7.9280702e-01 2.4844484e-01 -1.4537384e+00
+1 4.4059932e-01 1 1 -1.1883659e+00 1.4421374e+00 1.5288160e+00 7.7681486e-02 -1.2748111e-01 1.2130588e+00 4.3579071e-01 -8.1487640e-01
+1 7.3660832e-01 1 1 1.3801899e+00 6.1536210e-01 -2.7526962e-01 -1.3098053e+00 -8.8125637e-03 -1.0566037e+00 1.2819595e+00 -1.4252491e+00
+1 5.1179414e-01 1 1 -6.6777707e-01 2.6787850e-01 1.1095016e+00 -7.5711917e-01 -4.5790262e-01 1.0851191e+00 8.5121813e-01 4.8235631e-01
+1 1.1715637e+00 1 1 -1.5603020e+00 3.3169932e-01 -1.1006768e+00 -1.4517084e+00 9.3271568e-01 6.5205348e-01 -3.8985415e-01 -1.4882183e+00
+1 1.0748003e+00 1 1 -1.1213276e+00 -1.4564269e+00 -1.3776235e+00 -1.2553537e+00 -3.9490856e-01 1.1876617e+00 1.0836465e+00 8.7545417e-01
+1 6.7096056e-01 1 1 2.6135688e-01 1.1232032e+00 -1.8054162e-01 2.0664987e-01 9.5715874e-01 -6.4995619e-01 1.0348120e+00 -1.4617835e+00
+1 5.5268343e-01 1 1 6.7852496e-01 -1.5456670e-01 4.1541417e-01 -1.4370795e+00 -1.1290868e+00 -4.9601840e-01 2.2876875e-01 -9.4124865e-01
+1 4.1805985e-01 1 1 -1.2367968e-02 2.9453200e-01 1.2471290e+00 -4.3089753e-01 -1.3429395e+00 1.2057185e+00 -3.9302832e-01 1.4945927e+00
+1 8.4235732e-01 1 1 -5.2332426e-01 -9.5067722e-01 -2.0877853e-01 -7.2373979e-01 1.5585348e+00 1.2377015e+00 1.1423331e+00 -5.5564116e-01
+1 3.4549055e-01 1 1 9.4857591e-01 1.0827512e-01 2.1830987e-01 3.5203696e-01 -3.0469638e-01 1.5647895e+00 9.1986696e-01 1.2939825e+00
+1 6.4645063e-01 1 1 -8.6741044e-01 7.9785180e-01 -2.4625589e-01 1.0662701e+00 -2.3607351e-01 1.1449056e+00 4.2646940e-01 -1.2818246e+00
+1 7.1818082e-01 1 1 1.5642078e+00 1.1778362e+00 -1.3452742e+00 1.1568065e+00 1.4399820e-01 1.7279861e-01 -1.4432371e+00 1.4163423e+00
+1 9.3832033e-01 1 1 7.9290215e-01 7.1763522e-01 1.8487561e-02 -8.7050783e-01 1.1514848e+00 1.3946532e+00 -2.4859358e-01 6.1765575e-01
+1 1.1093647e+00 1 1 -3.2962404e-01 7.2096522e-01 -2.9724048e-01 -2.2818657e-01 7.9412109e-01 5.1322316e-01 2.0594104e-01 1.1181055e+00
+1 1.2331559e+00 1 1 -1.3633395e+00 1.3959844e-01 -5.8845203e-01 7.5299801e-01 1.3075924e+00 -1.0717554e+00 -7.8412352e-01 -1.0083704e+00
+1 7.9783132e-01 1 1 1.1294230e+00 -5.3869585e-01 -3.7951202e-01 1.3023583e+00 1.2649206e+00 9.0009181e-01 2.1716359e-01 1.2115583e+00
+1 6.5968500e-01 1 1 7.0885028e-01 2.0888864e-01 -1.0254109e+00 1.2604635e+00 3.6223535e-01 1.0744640e+00 -6.6214916e-01 -1.1433390e+00
+1 8.4552479e-01 1 1 7.2725786e-01 -1.5092683e+00 6.9707853e-01 8.5058882e-01 -3.1696712e-01 6.4107817e-01 -1.2197699e+00 1.0245188e+00
+1 9.1580479e-01 1 1 -9.1420524e-01 -1.0536159e+00 7.9978120e-01 -1.5419025e+00 8.7468410e-01 -1.0619799e+00 1.3611188e+00 1.7939860e-02
+1 9.0196732e-01 1 1 4.8224977e-01 1.0354848e+00 -9.5227790e-01 2.4165420e-01 1.3035914e+00 -1.3081136e+00 -7.5424528e-01 -7.7663766e-02
+1 4.7354352e-01 1 1 -1.3719318e-01 -1.0296732e+00 1.4799376e+00 -5.9716760e-01 -6.4735142e-03 -5.9942921e-01 -2.7411449e-01 -1.5339619e+00
+1 6.1069711e-01 1 1 1.2328926e-01 1.3164534e+00 1.3218996e+00 7.9268410e-01 1.1553901e+00 4.8084444e-01 -1.4673957e+00 -1.3878730e+00
+1 1.2056343e+00 1 1 -1.3285450e+00 -6.0523838e-01 -1.7616341e-01 -8.5281228e-01 4.5738514e-01 1.3761615e+00 -1.0166563e+00 3.4356740e-01
+1 1.0537919e+00 1 1 -1.5565526e+00 2.3554298e-01 -1.3982174e+00 -1.2703431e+00 -2.0509232e-01 7.4182829e-01 1.8072309e-01 8.9973585e-02
+1 8.7182465e-01 1 1 -9.3720279e-01 3.6413464e-01 -7.2707812e-01 -3.9262783e-01 -6.5956303e-01 -1.0730921e+00 -5.0705506e-01 1.0799793e+00
+1 5.9462760e-01 1 1 3.7821503e-01 1.8845636e-01 7.9347762e-01 -1.5514108e+00 1.4046945e+00 4.2428353e-01 1.0665535e+00 -9.1087147e-01
+1 7.3036430e-01 1 1 1.2180319e+00 6.6071906e-01 -8.2436129e-02 6.5729221e-01 -3.6808549e-01 -4.8202196e-01 -3.6362906e-01 -3.5829392e-02
+1 8.0484864e-01 1 1 8.4501498e-01 -8.2470585e-01 -6.1666973e-02 1.2703308e+00 -6.1685149e-01 8.2445224e-01 -1.1159742e+00 1.0011909e+00
+1 7.9025528e-01 1 1 -9.7364017e-01 -1.2436294e-01 2.8875735e-01 1.8651280e-01 -1.6725881e-01 -9.9646794e-01 -8.6985135e-01 6.4499113e-01
+1 7.7307578e-01 1 1 5.8577836e-01 -1.0087734e+00 -6.1581759e-01 -5.8888715e-01 6.0655604e-01 1.9379802e-01 1.3805457e+00 -1.2703211e+00
+1 5.8978985e-01 1 1 -5.7456327e-01 7.2159159e-01 1.5016056e+00 -1.4094396e+00 -8.0721433e-02 -6.6834288e-01 -9.7207735e-01 -2.3745108e-02
+1 8.7464378e-01 1 1 5.7092130e-01 1.2422264e+00 1.0712921e+00 -8.4324988e-01 4.8290359e-01 1.4965508e+00 -1.4222517e+00 -1.0176841e-01
+1 5.7881953e-01 1 1 1.0502984e+00 -9.2492225e-01 7.3927647e-01 -7.7635067e-01 1.4267903e+00 9.3902632e-01 5.9460455e-01 -1.3952708e+00
+1 9.0448184e-01 1 1 -2.4468374e-01 -5.6778332e-01 2.0730417e-02 -1.0914219e+00 2.8701976e-01 -1.1462151e+00 1.1238201e-01 -1.4693602e+00
+1 4.1598439e-01 1 1 -5.4844852e-02 1.4241467e+00 -3.0065872e-01 2.3128670e-01 -1.5451788e+00 -1.9145589e-01 7.0718105e-01 5.2223248e-01
+1 5.2500695e-01 1 1 -1.2907837e+00 -1.6075458e-01 -1.4901644e+00 1.0853991e+00 -1.4157765e+00 -8.0827462e-01 9.4688405e-01 -4.4854441e-01
+1 6.6697881e-01 1 1 -1.5036183e+00 -3.2612161e-02 -4.1700765e-01 -9.2567038e-01 -5.3303884e-01 -4.2486477e-01 -1.0281000e+00 1.1364350e+00
+1 1.0678830e+00 1 1 -3.4144731e-01 -1.4754606e+00 2.4569948e-01 -5.7533961e-01 1.0385352e+00 1.3793564e-01 -5.1791681e-01 -8.2016805e-01
+1 4.7401726e-01 1 1 9.8476386e-01 -1.4748582e+00 1.4183846e+00 8.9420912e-02 -2.8300312e-02 -2.1108239e-01 7.2539993e-01 7.4410718e-01
+1 8.2220432e-01 1 1 1.0160338e+00 -7.7612521e-01 3.8499001e-01 1.2159839e+00 -1.2628516e+00 -8.0360998e-01 -7.2442383e-01 -4.7090145e-01
+1 8.1373665e-01 1 1 -1.2172114e+00 -4.4369918e-01 -1.1537845e+00 9.8065938e-01 -1.4625729e-01 -5.6612397e-01 1.4217962e+00 -7.6878095e-01
+1 5.1755994e-01 1 1 3.8010263e-01 8.8880715e-01 1.3956008e+00 1.1471015e+00 -1.4207885e+00 1.0385319e+00 1.1758139e+00 4.6911331e-01
+1 4.2074982e-01 1 1 1.5269540e+00 -9.1313533e-02 7.3237329e-01 -6.1999375e-01 5.3725306e-02 -8.3326609e-02 1.2856958e+00 -1.0102178e+00
+1 3.2101238e-01 1 1 -1.5435714e-01 1.5322540e+00 2.3786653e-01 4.2794645e-01 1.3241243e+00 6.8000401e-01 8.1563114e-01 -1.5637656e+00
+1 6.1709625e-01 1 1 6.7508953e-01 9.5878884e-01 -1.4246673e+00 1.3903423e+00 -4.8539805e-01 -2.8672127e-01 1.5438661e+00 3.5617534e-01
+1 5.2628724e-01 1 1 -1.2029807e+00 1.1353178e+00 8.3509734e-01 3.1721057e-01 6.3114808e-01 2.7882808e-01 1.3430518e+00 1.5050123e+00
+1 4.6156962e-01 1 1 7.9317299e-01 -7.4714357e-01 -1.1550218e+00 7.5240705e-02 -1.4525746e+00 -9.9266798e-01 3.2900486e-01 -1.3623112e+00
+1 8.4313701e-01 1 1 1.0807465e+00 -2.9617940e-01 -5.5065294e-01 -1.4913037e+00 -1.0418183e-01 1.2278062e+00 3.8153334e-01 -4.3661396e-01
+1 6.7608719e-01 1 1 -5.8294314e-01 1.5372192e+00 3.0806873e-01 -7.1466076e-01 -1.1169628e+00 -1.3834257e+00 4.4021292e-01 5.8954542e-01
+1 7.9824362e-01 1 1 1.1021683e+00 -4.1565290e-01 3.6638510e-01 -9.9468785e-01 1.3633856e+00 -3.0893064e-01 2.0778990e-01 -9.3276790e-02
+1 6.1030133e-01 1 1 1.3125816e+00 1.0238328e+00 3.1269520e-01 -1.3042225e+00 -3.5551423e-01 8.5537681e-01 -1.1261984e+00 -4.8272154e-02
+1 9.2041084e-01 1 1 2.9528353e-01 1.0542359e+00 -4.1630666e-01 -1.1763336e+00 1.8153864e-01 3.8998719e-01 7.8535503e-02 -7.7919414e-01
+1 1.0491978e+00 1 1 -8.8605389e-01 -4.0155654e-02 -5.3914259e-01 -5.9551888e-01 6.3343319e-01 1.1523684e+00 4.7727886e-01 1.3839427e+00
+1 6.5632625e-01 1 1 -7.5860749e-01 5.4634816e-01 -1.0162864e+00 2.2831987e-01 -7.4596179e-01 -6.2397000e-02 1.1398092e+00 -4.2715073e-01
+1 8.5080070e-01 1 1 -1.3330171e+00 -4.0177372e-01 1.1307523e-01 1.4874427e+00 7.1647136e-01 5.8556681e-01 -6.5823725e-01 -5.8315903e-01
+1 5.6687164e-01 1 1 -1.3215463e+00 -1.3282256e+00 -2.0812104e-01 -1.3453002e+00 9.4838631e-03 -9.8833819e-01 -1.4456910e+00 6.1522170e-01
+1 9.7229090e-01 1 1 -1.6838622e-01 6.6918077e-01 -1.2977328e+00 -4.1798555e-01 -8.2593798e-01 -1.3996147e+00 -6.5167243e-01 1.0496347e+00
+1 6.7129733e-01 1 1 5.0783848e-01 1.9532457e-02 1.0818164e+00 -4.8201362e-01 1.1583591e+00 9.2212123e-01 -1.0665039e+00 1.1678958e+00
+1 7.4028778e-01 1 1 -4.6582943e-01 1.5563726e+00 -1.4496691e+00 9.6450129e-01 9.1534035e-02 6.1493017e-01 1.1960555e+00 1.5328235e-01
+1 1.0859526e+00 1 1 -3.4638542e-01 1.0541931e+00 -1.5374153e+00 -2.4486934e-01 -9.6788213e-01 -7.0849805e-01 -9.4693575e-01 1.1047387e-01
+1 9.3670767e-01 1 1 -3.2862910e-01 -7.5837423e-01 2.6137196e-01 -3.2662991e-02 -2.8269658e-02 -1.0905430e+00 1.5918613e-01 5.3053787e-02
+1 8.1528186e-01 1 1 -3.4940608e-01 -5.5424426e-01 9.3204424e-01 8.1182301e-01 -7.4765003e-01 -7.0437780e-01 -1.1956114e+00 -5.3731586e-01
+1 4.9661776e-01 1 1 -8.3134768e-01 -3.6114236e-01 8.8654707e-01 3.7243966e-01 6.1656147e-01 -9.5653532e-01 -1.0146978e+00 1.4112506e+00
+1 1.0441904e+00 1 1 1.3435969e+00 -1.6270612e-01 -3.7731198e-01 1.5407209e+00 -1.5655491e+00 -9.5949491e-01 -1.4610633e+00 -1.3612692e-01
+1 6.5781711e-01 1 1 6.5392350e-02 -1.4161206e+00 1.3931435e+00 -1.2526084e+00 -1.3447097e+00 -4.3581815e-01 -1.4034812e+00 -8.0574082e-01
+1 8.3204989e-01 1 1 -5.0820790e-01 -3.3220632e-02 2.7294043e-01 -7.7759137e-01 8.2229890e-02 1.3984498e+00 -1.2312467e+00 1.3199411e+00
+1 6.1397343e-01 1 1 5.4023879e-01 8.6432927e-01 5.8456567e-01 4.7267912e-02 -2.6300370e-01 1.4914920e+00 1.0685589e-01 1.4640986e+00
+1 6.7411768e-01 1 1 5.9060683e-01 5.7540342e-02 1.0349235e+00 -3.9113890e-01 -8.2344811e-02 7.3848167e-01 -1.0641127e+00 -9.8981525e-01
+1 1.0898824e+00 1 1 -1.1038137e+00 -5.3001466e-01 -1.0393235e+00 1.4820139e+00 1.4731192e+00 -7.7113500e-01 5.4534877e-01 -1.0918719e+00
+1 7.5551721e-01 1 1 -6.9144538e-01 -1.5412803e+00 -6.5572537e-01 -1.4813687e+00 -1.7679064e-01 -1.3963218e+00 -1.4905262e+00 -1.0477099e+00
+1 1.1021733e+00 1 1 -3.7122672e-01 1.2750445e+00 -6.9251574e-02 -2.4248554e-01 6.2643745e-01 -2.8361454e-01 -2.1408066e-01 -2.3347369e-01
+1 8.2370494e-01 1 1 -4.4351470e-03 8.6885318e-01 -1.5219287e+00 -8.0883851e-01 1.0571799e+00 -9.1345430e-01 -9.3002049e-01 -1.4316536e-01
+1 6.3425404e-01 1 1 8.5670756e-01 6.9275109e-01 -2.0826950e-01 -4.7737072e-01 -8.2467870e-01 5.3686607e-01 -1.4308564e+00 2.7972326e-01
+1 7.9881508e-01 1 1 7.6486475e-01 3.2517032e-01 -6.5130494e-01 4.5797369e-01 3.3190292e-01 4.5400091e-01 4.8843089e-01 1.4862526e+00
+1 9.5547662e-01 1 1 -3.1530661e-01 -1.2336932e+00 -1.1732701e+00 2.6183196e-01 -1.1761116e+00 -5.3532295e-01 7.6333237e-02 6.4376476e-01
+1 5.6323274e-01 1 1 5.0868992e-01 -1.6974608e-01 6.2595919e-01 -7.6151438e-01 -7.3710861e-03 3.4849421e-01 1.1629199e+00 1.0922553e-01
+1 8.1270169e-01 1 1 1.2778336e+00 -3.5615352e-01 -6.9762939e-01 7.6342068e-02 -1.3637306e+00 1.2134053e+00 1.3472536e+00 1.0633981e+00
+1 6.0421040e-01 1 1 6.2146766e-01 -1.1382687e+00 -6.3331298e-01 1.3113286e+00 8.3947365e-01 -1.5159758e+00 -1.3091433e+00 1.1274308e-02
+1 7.9963783e-01 1 1 -7.8865022e-01 1.4177538e+00 -3.7531995e-01 1.2281534e+00 1.4102498e-01 -6.8952585e-01 9.4381531e-01 9.9173654e-01
+1 9.4393887e-02 1 1 -4.6476296e-01 -7.9179318e-01 3.1558561e-01 1.3100803e+00 1.4459591e+00 4.7433698e-01 8.0268900e-01 -1.1746524e+00
+1 7.0775132e-01 1 1 -1.2716537e+00 1.1846831e-01 1.0389267e+00 -9.0282450e-01 -1.1266343e+00 -1.1804778e+00 7.9512591e-01 -6.1419337e-01
+1 8.5573449e-01 1 1 -4.2815197e-01 -6.7291606e-01 2.6890224e-01 1.2110483e-01 -9.6439877e-01 -1.1332740e+00 -6.5400442e-01 5.2550303e-01
+1 4.5142666e-01 1 1 1.4385291e+00 3.3265614e-02 -1.3118858e+00 -3.4323435e-01 -1.1736478e+00 5.3992565e-01 5.8033119e-01 1.1125288e+00
+1 7.9247519e-01 1 1 -3.3898749e-01 -1.0832007e-01 -1.1679021e+00 -7.7557316e-01 5.6105711e-01 -1.5308273e+00 -1.0188332e+00 -4.8778270e-01
+1 8.2116410e-01 1 1 1.4863639e+00 -1.5532217e+00 -2.6026154e-01 -5.9012879e-01 -1.3742327e+00 1.0285707e+00 1.2925106e+00 1.3930384e+00
+1 1.1136525e+00 1 1 -6.2717966e-01 -1.5043335e+00 -1.1186619e+00 -2.8651023e-01 2.5979077e-01 -9.9694157e-01 -8.8726417e-01 -1.4937037e+00
+1 6.1792941e-01 1 1 -9.6520698e-01 2.0376728e-01 1.0818250e+00 6.8404663e-01 -5.1028525e-01 -1.4833156e+00 8.9142368e-01 -2.1074002e-01
+1 8.0768675e-01 1 1 9.5068794e-01 3.8062497e-01 -1.3059319e+00 -1.4573384e+00 1.8376910e-01 -1.5469705e+00 -9.7567608e-02 -1.3326133e+00
+1 3.3078957e-01 1 1 7.2023285e-02 8.8120624e-01 1.5096453e+00 1.5110142e+00 4.2166247e-01 -1.1288048e-01 9.2585356e-02 -8.1714686e-01
+1 6.0730125e-01 1 1 9.8217602e-01 9.6556801e-01 1.1055605e+00 -1.0185910e+00 -5.5193923e-01 3.3973252e-01 9.9371823e-01 1.2558001e+00
+1 9.9583277e-01 1 1 1.5045425e+00 -1.1661298e+00 -1.3654929e+00 -9.2133495e-01 6.8054565e-01 -1.5310064e+00 7.1577171e-01 1.0131652e+00
+1 6.1381898e-01 1 1 1.6646360e-01 1.2521867e+00 -5.0433052e-01 3.3739027e-02 -6.0818760e-01 1.1616657e+00 8.1679869e-01 8.3500644e-01
+1 1.0111786e+00 1 1 -1.4053551e+00 -2.7657820e-02 -2.6608931e-01 1.5651546e+00 9.3344509e-01 -8.8308145e-01 -8.2430992e-01 4.5889035e-01
+1 6.1936281e-01 1 1 -1.3091715e+00 1.1072809e-01 1.4648547e+00 9.9801295e-01 -7.0202008e-01 -1.0661868e+00 2.4672434e-01 -3.9800751e-02
+1 1.0779619e+00 1 1 4.7011708e-01 1.1841621e+00 -8.4818462e-01 6.4046384e-01 9.7049090e-01 2.4329070e-01 -2.0626836e-01 2.2800855e-01
+1 2.1029221e-01 1 1 1.5229649e-01 2.2360979e-01 1.1085473e+00 1.1793625e+00 -1.0851820e-01 -1.3669092e+00 1.5660314e+00 -6.0325742e-01
+1 9.7338199e-01 1 1 -7.5096936e-01 8.6484934e-01 -1.4322645e+00 1.2380652e+00 1.3999137e+00 8.2341493e-01 2.6598572e-02 -1.0280176e+00
+1 1.0113310e+00 1 1 1.3772186e+00 -6.2629310e-01 -1.1865229e+00 1.3943177e+00 9.6197209e-01 4.1916869e-01 9.3605040e-01 8.6821479e-01
+1 4.0211500e-01 1 1 -3.4202779e-01 1.3689192e+00 9.4055276e-01 1.1578604e+00 1.2290969e+00 1.5174322e+00 -8.9693223e-01 -6.1183670e-01
+1 1.2185121e+00 1 1 6.5348751e-01 1.5414942e+00 -6.2401482e-01 1.1340219e+00 1.4595502e+00 3.3578213e-02 -1.3785068e+00 -7.0669247e-01
+1 1.1428732e+00 1 1 1.5658615e-01 -8.2212662e-01 -1.1808832e+00 -5.3664755e-01 1.1039432e+00 -1.1376496e+00 6.8153319e-01 9.8146219e-01
+1 6.1638200e-01 1 1 -9.1125081e-01 -7.5764142e-01 1.4778813e+00 7.7153613e-02 -2.7309256e-01 -7.4380293e-01 2.8148181e-01 -1.0679859e+00
+1 6.1089673e-01 1 1 -1.2819545e-01 -8.0436251e-01 1.3195111e+00 -7.5699734e-01 2.4656094e-04 -6.9864924e-01 -3.7381545e-01 1.4210621e+00
+1 3.8269019e-01 1 1 5.5169531e-01 -6.4754040e-01 5.2098863e-01 5.9589432e-01 1.0023571e+00 1.0755268e+00 4.6900153e-01 1.4040003e+00
+1 6.2184644e-01 1 1 1.5030822e+00 -7.3449503e-01 6.3725822e-01 -2.0147888e-01 1.3966973e+00 -3.4563363e-01 2.5280953e-01 5.3000552e-01
+1 5.3149142e-01 1 1 7.5550929e-01 -1.3404613e+00 7.0947210e-01 3.8140750e-01 3.1040636e-01 -2.5965383e-01 1.5364671e+00 1.3875853e+00
+1 1.0843944e+00 1 1 -4.7287564e-01 -7.7286306e-01 -1.3881732e+00 1.4668091e+00 -1.1857645e+00 -3.2976737e-01 -4.8902928e-01 1.1040407e+00
+1 6.6185549e-01 1 1 6.0856946e-01 9.7621856e-01 -1.5596794e+00 5.8309689e-01 1.1202199e+00 -6.3070867e-01 -7.0880357e-01 1.3652306e+00
+1 7.3991117e-01 1 1 -7.9873977e-01 -1.2331699e+00 -8.2528135e-02 1.4819040e+00 -2.9080688e-02 -5.8692686e-01 5.7665964e-02 -7.6178650e-01
+1 6.1571662e-01 1 1 -3.9392430e-01 -8.0027432e-01 1.5335835e+00 -1.8645173e-01 1.3293307e+00 1.2122360e-01 -1.5602744e+00 -1.3556160e+00
+1 4.2139187e-01 1 1 -1.3499137e+00 -1.0524118e+00 1.3111199e+00 -1.5263102e+00 -9.4620578e-01 -1.4885870e+00 -6.5721840e-01 -1.0090073e+00
+1 3.3977913e-01 1 1 5.8191009e-01 -7.1850128e-01 8.6097132e-01 1.5507046e+00 -1.3858223e-01 9.6178835e-01 -2.9903348e-02 -6.8688105e-02
+1 6.2198833e-01 1 1 3.8496808e-01 4.3109179e-01 1.6926579e-01 3.9552043e-02 -1.2314154e+00 1.2826029e+00 6.9249987e-02 -1.4764793e+00
+1 1.2928892e+00 1 1 -1.5223968e+00 8.4699160e-01 -1.4328567e+00 -1.2664475e+00 4.1434836e-01 -9.0159994e-01 1.4952515e+00 2.5286455e-01
+1 3.7259327e-01 1 1 1.3499854e+00 8.3151528e-01 1.4268249e+00 -8.9304120e-01 -9.5800820e-01 -1.2888563e+00 1.0926274e+00 -6.8039855e-01
+1 3.1285841e-01 1 1 6.2244787e-01 1.4731201e+00 8.6895113e-01 1.1863044e+00 -5.8145712e-01 -5.2636521e-01 1.1798007e+00 -6.1106463e-02
+1 1.1034458e+00 1 1 -2.2187586e-02 -1.6275131e-01 -8.0260129e-01 -1.4702320e+00 9.4497333e-01 1.0480738e-01 -8.2287628e-01 2.8446672e-01
+1 4.3478632e-01 1 1 9.4276373e-01 9.6597145e-01 6.7892975e-01 -1.5637098e+00 1.4159196e+00 -9.3577069e-01 -7.9074387e-01 -4.7181291e-01
+1 1.0795296e+00 1 1 -1.1633371e+00 -6.6868862e-01 5.0784107e-01 1.2930730e+00 -2.0283754e-01 -6.8511899e-01 -1.0953315e+00 -3.7966675e-01
+1 9.2531962e-01 1 1 1.0664414e+00 -1.1726876e+00 -4.2238374e-01 -8.5929631e-01 -4.6254589e-01 -8.5777763e-01 4.9694086e-01 -4.8443772e-01
+1 5.4966685e-01 1 1 8.9499714e-01 9.9192817e-01 9.9592805e-01 -2.9164935e-01 1.4330473e+00 1.0014010e-01 -1.4097889e+00 1.0634206e+00
+1 5.2891837e-01 1 1 2.7126088e-01 -1.0953872e+00 1.5707469e-01 -8.6614212e-01 -1.3650658e+00 -8.3903902e-01 -4.3056895e-01 3.8969689e-01
+1 5.1966349e-01 1 1 6.3060578e-01 -4.3941592e-01 1.0165053e+00 8.8982385e-01 3.8997374e-01 8.8064131e-01 -1.4843797e+00 -5.8503726e-01
+1 7.0472543e-01 1 1 -1.1423200e+00 6.2098101e-01 4.2437363e-01 1.2883801e+00 9.2638689e-01 8.9553134e-01 -5.8228891e-01 4.6373188e-01
+1 8.1587160e-01 1 1 -6.9983553e-01 4.5697762e-01 1.0322093e+00 -1.1946366e+00 5.1294650e-02 -1.7518253e-01 -4.6865483e-01 -3.4973274e-01
+1 8.4134937e-01 1 1 -1.2828168e-02 -7.7115661e-01 4.6700366e-01 -3.3925723e-01 1.3127943e+00 -6.2039547e-01 -7.0888699e-01 -3.8252593e-02
+1 5.4213496e-01 1 1 1.1668659e+00 1.3821415e+00 1.2320921e+00 9.4458409e-02 7.2897414e-01 -4.0678511e-02 -1.3442753e+00 1.1151576e+00
+1 7.5914550e-01 1 1 -1.4477704e+00 7.1669028e-01 1.5353355e+00 1.0581937e+00 -3.4303126e-01 1.1834658e+00 1.1002081e+00 -2.8770045e-01
+1 6.2464728e-01 1 1 -1.0415808e+00 5.4737529e-01 -6.5865651e-01 5.0591412e-01 -5.0378969e-01 1.0865656e+00 -2.1697521e-01 -4.7037429e-01
+1 5.6586440e-01 1 1 -8.9424581e-01 1.1532516e+00 9.3247536e-01 -1.3927032e+00 -6.0107865e-01 -1.7020241e-01 6.8678145e-01 -1.3335383e+00
+1 5.7042338e-01 1 1 -2.1003060e-01 -9.2619292e-01 -1.2923396e+00 8.4390316e-01 1.0331609e+00 1.3989716e+00 5.2443533e-01 -6.5571073e-01
+1 8.0100179e-01 1 1 1.1659075e+00 6.7162640e-02 6.2078325e-01 -8.1045419e-01 7.5273610e-01 8.3627815e-01 -1.1243506e+00 1.7684235e-01
+1 9.2077752e-01 1 1 1.2937099e+00 9.7072787e-01 2.7491308e-01 6.4212476e-01 4.2043906e-02 -1.5864783e-01 -2.8016041e-01 2.4277152e-01
+1 6.3537678e-01 1 1 4.1930274e-01 7.3273089e-01 -8.1867514e-01 8.2005609e-01 -2.2641099e-01 8.1811072e-01 5.9140829e-01 -6.6797923e-01
+1 6.6744774e-01 1 1 6.2886890e-01 -3.5084987e-02 7.0279198e-01 5.1574838e-01 -8.2087426e-01 -7.6422310e-01 -2.0010077e-01 1.3252922e+00
+1 1.0905239e+00 1 1 1.0818608e+00 9.4604965e-01 -5.6361286e-01 5.2889537e-01 1.4412957e+00 -1.4669424e+00 1.5521502e+00 2.9473095e-01
+1 6.8420967e-01 1 1 -7.0381443e-01 6.5597618e-01 -7.3948044e-01 -1.5626689e+00 -9.6486936e-01 3.1788297e-01 -7.9674318e-01 -7.4850029e-01
+1 8.3066285e-01 1 1 -9.1285620e-01 1.1430470e+00 -3.0724166e-01 -6.2423134e-02 3.4202192e-01 -1.1900365e+00 -1.3946716e+00 -1.1074071e+00
+1 5.3154659e-01 1 1 1.1644190e+00 3.5208126e-01 9.6777703e-01 1.4633993e-01 -7.5213161e-01 -1.5646918e+00 -8.2253094e-01 -1.3968735e+00
+1 5.6828265e-01 1 1 1.4087869e+00 -1.3308940e+00 1.4032920e+00 -3.3189420e-01 6.9288156e-01 4.9626973e-01 -1.2699088e+00 -1.3113646e-01
+1 5.3090696e-01 1 1 -7.0263732e-01 -1.9529853e-01 1.1920588e+00 1.3226517e+00 -6.2358259e-01 -1.2309620e-01 6.2372761e-01 1.3874828e+00
+1 3.1027944e-01 1 1 2.1410361e-02 5.8197642e-01 9.9572150e-01 -1.0190188e-01 -1.9956464e-01 1.4316844e+00 -5.0476627e-01 -6.1891187e-01
+1 1.0911547e+00 1 1 -1.4392132e+00 1.4998284e+00 -1.7278390e-01 -4.9697099e-01 1.1379899e+00 8.6171295e-01 -1.3066140e+00 -2.3856542e-01
+1 9.8745903e-01 1 1 1.4076403e+00 -5.2359719e-01 -1.1473299e+00 9.0343880e-01 1.8000866e-01 6.7482506e-02 -5.2943788e-01 -8.9672675e-01
+1 9.2602982e-01 1 1 -1.1229809e+00 -4.9688062e-01 -7.7764075e-02 7.7862907e-01 5.1879229e-02 6.3523290e-02 -1.2719884e+00 -1.0665724e+00
+1 4.4181326e-01 1 1 7.4903343e-01 -7.1922643e-01 -7.8268748e-02 -1.4561676e+00 -1.4285547e+00 -5.0556016e-01 2.2828710e-01 4.6059960e-02
+1 7.2273517e-01 1 1 6.4306421e-01 8.0985060e-01 8.6446858e-01 -8.0257801e-01 1.4737403e+00 1.0584802e+00 9.3668796e-01 1.2979614e+00
+1 1.2818063e+00 1 1 9.0139460e-01 -1.3619536e+00 -7.4258256e-01 1.0703098e+00 8.3675771e-01 -9.6185550e-01 3.9371458e-01 -3.8157529e-01
+1 3.8608928e-01 1 1 9.7933137e-01 -7.1084402e-01 9.6256437e-01 -6.2321357e-02 -1.5234993e+00 7.3040973e-01 9.6677455e-01 -1.1452527e+00
+1 6.2594613e-01 1 1 8.1847253e-01 3.2143460e-01 -1.3828248e+00 -1.2846922e+00 -1.4727593e+00 -1.3478230e+00 2.6268494e-01 2.7577973e-01
+1 5.6568331e-01 1 1 -9.6633871e-01 -1.1880992e+00 3.6622319e-01 3.4498992e-01 -5.7165481e-02 1.1635254e+00 1.0081128e+00 1.1808184e+00
+1 7.5094238e-01 1 1 7.7926584e-01 -4.1995031e-01 7.3309239e-01 -1.1344808e+00 5.4711910e-01 -1.0435057e+00 7.4230154e-01 5.7324160e-01
+1 6.1829929e-01 1 1 -1.7874877e-01 1.0537771e+00 -2.4258521e-01 -8.9255265e-01 -1.0951160e-02 1.3121626e+00 5.9753043e-01 -7.9311195e-01
+1 9.8370964e-01 1 1 -8.6793498e-01 -1.4672905e+00 6.5769760e-01 -2.7384563e-02 1.2978254e+00 -4.6415959e-01 -9.7780991e-01 -5.4916626e-02
+1 1.0143684e+00 1 1 -9.6854259e-01 7.5060253e-01 -1.3409720e+00 1.5617659e+00 4.7293464e-01 -5.5558662e-01 -3.7994269e-01 6.4450864e-01
+1 9.4335413e-01 1 1 1.4378609e+00 -1.2593881e+00 6.9091076e-02 5.9325832e-01 3.8308408e-01 -9.3094776e-01 1.1609995e+00 4.5306637e-02
+1 1.0141691e+00 1 1 9.9766655e-01 1.5153245e+00 -1.1755646e+00 -5.2243211e-01 1.3707339e+00 -1.3075305e+00 4.8615072e-01 1.2032187e+00
+1 1.0116019e+00 1 1 1.1017046e+00 -8.3243794e-01 -2.3870051e-01 2.3493441e-01 6.2594590e-01 -2.2475634e-01 -5.4742046e-01 6.4992146e-02
+1 7.9591227e-01 1 1 -1.9741235e-01 -1.2724181e+00 -2.5718771e-02 -4.3934012e-01 -9.2107844e-01 -1.2854634e+00 1.2292830e+00 -9.5123752e-01
+1 6.3792046e-01 1 1 -3.8747835e-01 -7.0933992e-01 1.2844088e+00 -1.2465980e+00 1.2032035e+00 -5.0110822e-02 1.4458263e+00 1.1608173e-01
+1 6.8790956e-01 1 1 1.7290493e-01 4.6808902e-01 1.1761095e+00 -2.9062584e-01 -1.9049412e-01 -2.6574598e-01 -2.1640967e-01 5.6641999e-02
+1 3.4611219e-01 1 1 3.9939951e-02 6.2422090e-01 -2.8993478e-02 6.2802977e-01 -3.5168528e-01 9.5200528e-01 7.6697266e-01 7.9499772e-02
+1 4.8331629e-01 1 1 -1.0300738e+00 1.5027510e+00 -3.4651681e-01 -4.5494955e-01 -1.4387017e+00 2.2128811e-01 5.5484021e-01 9.7578949e-01
+1 9.8830248e-01 1 1 8.6594923e-01 1.4720396e+00 6.0480595e-01 2.9940431e-01 5.7965178e-01 -4.5642045e-01 9.5242903e-01 9.8026180e-01
+1 9.8162372e-01 1 1 -9.9008656e-01 5.2807736e-01 -1.2203038e+00 -7.4319481e-01 1.2862187e-01 7.1080702e-01 1.0601973e+00 7.4818139e-01
+1 9.3773824e-01 1 1 6.3143319e-01 3.9693216e-01 -1.3289163e+00 9.7154291e-02 3.3206102e-01 -9.4332027e-01 -3.7806825e-01 -1.1107779e+00
+1 6.5760763e-01 1 1 1.9769387e-01 -1.5039268e+00 -1.5143034e+00 -7.5601521e-01 1.4810094e+00 1.2343575e+00 1.2488329e+00 -1.5010488e+00
+1 9.4132234e-01 1 1 -1.1641338e+00 7.5709536e-01 -8.5454373e-01 1.3946892e+00 4.8657161e-01 -1.2306873e+00 1.5345288e-01 -1.1386491e+00
+1 5.9768046e-01 1 1 2.4162907e-01 1.0514524e+00 1.0451057e+00 1.1186845e+00 2.4339601e-01 8.4149395e-02 -1.6493223e-01 1.3071932e+00
+1 8.3769643e-01 1 1 -1.0194784e+00 3.0139909e-01 4.4618703e-01 -7.0094367e-01 4.0312790e-01 5.8219119e-01 -1.1312028e+00 8.3856110e-01
+1 6.4781750e-01 1 1 -1.2795695e-01 1.3671623e+00 8.3688150e-02 2.1226854e-01 -1.0446752e+00 -1.1737744e+00 7.9352223e-01 5.1179708e-01
+1 7.6407131e-01 1 1 1.4185152e+00 2.8883499e-01 -8.8676661e-01 -1.2518898e+00 5.0444666e-01 -1.5664051e+00 6.6725414e-01 9.2829020e-02
+1 5.2748335e-01 1 1 -5.6243519e-01 6.8895476e-01 -1.7085693e-01 -1.2651734e+00 -9.2359420e-01 -2.3959438e-02 -9.4540241e-01 -1.1942124e+00
+1 8.2602338e-01 1 1 2.0405552e-01 -6.4786145e-01 -1.7669078e-01 -1.4705021e+00 -2.3841679e-01 -5.6240666e-01 7.9731538e-01 5.0840500e-01
+1 6.9977459e-01 1 1 -1.0581317e+00 1.5279387e-01 -8.3682855e-01 1.7997807e-01 -1.5403271e+00 6.8363010e-01 -1.5546119e+00 -3.6926311e-01
+1 7.9281676e-01 1 1 5.3688093e-01 1.3253430e+00 3.3278728e-01 -4.6228964e-01 -1.5545811e+00 9.6680616e-01 2.6330265e-01 -1.5595269e+00
+1 7.7162633e-01 1 1 7.0365999e-01 1.1485237e+00 1.1208877e+00 -5.4333448e-01 7.8093833e-01 7.9389278e-01 -1.1763593e+00 -6.6099685e-01
+1 6.3807941e-01 1 1 1.4586484e+00 1.2925713e+00 -1.3708243e+00 7.8730940e-01 -3.4366830e-01 6.1199826e-01 -1.0282056e+00 -7.0240498e-01
+1 5.6007983e-01 1 1 -1.4848087e+00 1.3293518e-01 9.9669475e-01 -7.9201223e-02 1.3557863e+00 2.8044351e-01 8.5036859e-01 7.8464407e-01
+1 3.5920526e-01 1 1 -1.5089746e+00 5.6923270e-01 4.7661877e-01 9.0033756e-01 7.2856082e-01 1.0251018e+00 1.0398914e+00 -8.9312911e-01
+1 7.2669822e-01 1 1 7.4134859e-01 9.4429082e-01 -5.2962897e-01 -1.0785035e+00 -1.0063873e+00 3.9244062e-01 7.7520703e-01 -2.9119346e-01
+1 7.4853893e-01 1 1 2.8932523e-01 -6.3022003e-01 -1.3421318e+00 5.8053297e-01 -1.7260458e-02 1.5465467e+00 7.1976114e-01 5.1285089e-01
+1 7.0772348e-01 1 1 -4.9631134e-01 1.3423783e+00 -5.7317713e-01 -7.6907989e-01 -1.0699880e+00 -7.2730721e-01 -1.2478114e+00 -1.0454141e+00
+1 9.0203247e-01 1 1 -5.7623935e-01 -1.5665378e+00 -1.2649937e+00 -1.4134802e+00 -8.1149372e-01 8.4680118e-02 1.3064444e+00 6.5304409e-01
+1 3.1602572e-01 1 1 6.7535616e-01 8.8673239e-01 1.5494040e+00 3.6213367e-01 -1.1212777e+00 7.7279274e-02 8.1922752e-01 -1.0127021e+00
+1 7.2446789e-01 1 1 1.3675056e-01 -4.0428836e-01 1.7146717e-01 1.1155648e+00 1.1005202e+00 1.3549995e+00 -8.4366486e-01 6.6520177e-01
+1 7.2962804e-01 1 1 -1.2792020e+00 3.9050680e-01 1.0082688e+00 2.7258583e-01 -1.2544677e+00 7.1015627e-02 -1.4676625e+00 -8.8209374e-01
+1 4.1428545e-01 1 1 1.5118795e+00 4.6079001e-01 2.2259639e-01 9.0792107e-01 -6.1038107e-01 -2.4556827e-01 7.8223005e-01 -1.7381277e-01
+1 4.7813335e-01 1 1 9.5751995e-01 4.7181873e-01 -4.5937537e-01 7.1398793e-01 -1.3746879e+00 7.8677336e-01 -6.2482812e-01 4.0992938e-01
+1 4.8489503e-01 1 1 -1.3412832e+00 4.7749948e-01 1.3128434e+00 -8.8875790e-01 -1.1066135e+00 3.3633599e-01 8.5803639e-01 1.7037634e-01
+1 4.4810065e-01 1 1 1.1216310e+00 -1.4355183e+00 1.5536064e+00 9.1906837e-01 -6.2541551e-01 1.0737735e+00 1.1073609e+00 1.5242082e+00
+1 1.0322661e+00 1 1 -1.4456599e+00 6.7569286e-01 -1.4555429e+00 -4.2900327e-01 4.1046228e-01 -1.5389146e+00 6.1949798e-01 8.2132774e-01
+1 8.1017456e-01 1 1 -1.2884884e-01 -4.8747920e-01 2.7187299e-01 -3.0289649e-01 -2.9790055e-01 1.9509330e-01 6.6442897e-01 -1.0287164e-01
+1 6.7812435e-01 1 1 -1.0051578e+00 2.1067774e-01 1.4936555e+00 -1.4012809e+00 8.8407123e-01 -8.8960812e-01 -1.3041421e+00 -1.0877084e+00
+1 7.9943810e-01 1 1 -1.3436986e+00 2.8585967e-01 -5.9928740e-01 1.1926676e+00 -1.1480196e+00 -8.0431014e-01 1.7525294e-01 -1.8813207e-01
+1 9.6113359e-01 1 1 1.3665495e+00 9.4829384e-01 -2.7723424e-01 -1.3375527e+00 8.9664580e-01 2.3260990e-01 -1.3377138e+00 -1.4934980e+00
+1 7.0606630e-01 1 1 -5.8682798e-01 6.7507987e-01 -4.9396452e-01 9.8877678e-01 -2.9401308e-01 1.3333080e+00 1.4226478e+00 1.0441538e-01
+1 7.1041219e-01 1 1 -1.3585405e+00 -1.3652321e+00 1.1676363e+00 -6.5387691e-01 2.4741984e-01 -7.2141906e-02 -2.2032092e-01 -1.2409641e+00
+1 5.8109674e-01 1 1 1.0596857e-01 7.3705171e-01 -1.0654304e+00 -4.1813717e-01 -1.0834356e+00 1.6575832e-01 1.0040073e+00 1.5000099e-01
+1 6.7425012e-01 1 1 -2.6933320e-01 3.2826853e-01 3.8897823e-01 1.1140415e-01 -6.3111788e-01 -6.9260287e-01 8.5571551e-01 1.5093180e+00
+1 5.2175658e-01 1 1 3.5195816e-01 5.7247004e-01 -9.7233933e-02 -1.9720672e-02 -1.1814632e+00 -9.7558137e-01 -2.0053343e-01 -1.2529441e+00
+1 1.1455384e+00 1 1 -2.5817207e-01 -1.1943349e+00 -5.8254004e-01 1.5634890e+00 1.1552351e+00 -6.2394732e-01 5.6348003e-01 -1.3585548e-01
+1 9.8318950e-01 1 1 -5.5860964e-01 -1.5515160e+00 -1.5477611e+00 1.2793532e+00 9.9339165e-01 -4.6254754e-02 -1.4929448e+00 6.1483339e-01
+1 1.1028939e+00 1 1 -1.4733502e+00 -1.1103354e+00 -8.3388541e-01 1.0287471e+00 1.5101453e+00 -1.4302614e+00 -2.2664045e-02 8.0657332e-01
+1 1.1220769e+00 1 1 -5.6325728e-01 -3.4653755e-01 -4.6720115e-01 -1.1737036e+00 8.5594558e-02 1.0644243e+00 -7.8190162e-01 1.0546437e-01
+1 8.1294526e-01 1 1 -1.0464361e+00 2.5618313e-01 -1.4097556e+00 -3.7544719e-01 -2.6170149e-01 1.5502934e+00 -1.3841803e-01 6.8144417e-01
+1 4.7725232e-01 1 1 -8.1661429e-01 -1.4537181e+00 1.3014361e-01 1.3187010e+00 -1.8728771e-01 -5.8889013e-01 1.5282838e+00 -1.2147024e+00
+1 5.9815804e-01 1 1 7.8186816e-01 -4.7397398e-01 7.7523785e-01 -5.2911682e-01 1.3131017e-01 -1.4595731e+00 2.0348145e-01 -1.4340530e+00
+1 5.7826649e-01 1 1 -4.2396646e-01 9.9827790e-01 1.2378640e+00 9.8236449e-01 1.5319844e+00 -1.4890043e+00 -1.2816912e+00 1.7034222e-01
+1 3.8426349e-01 1 1 -4.7216889e-01 -1.1896237e+00 1.1532191e+00 1.5305517e+00 -4.3218231e-01 2.3130903e-01 5.1639512e-01 9.5078406e-01
+1 7.3514622e-01 1 1 -7.9497134e-02 -9.0991671e-01 -1.4727678e+00 6.2131680e-01 -3.2581506e-01 1.4607483e+00 -1.1677654e+00 -1.4541124e+00
+1 8.7450839e-01 1 1 -9.3145865e-01 3.0288860e-01 -1.9996831e-01 -1.8244707e-01 -1.7765251e-01 -7.5013769e-01 -1.1035351e+00 -8.1703178e-01
+1 3.8122592e-01 1 1 -4.6933823e-01 1.2686326e+00 6.3673763e-01 -1.9344794e-01 -1.2927540e+00 -3.5276207e-01 8.4886881e-01 4.8364602e-02
+1 2.4216368e-01 1 1 3.7146941e-01 -8.1696915e-02 1.3848229e+00 2.6893906e-01 -6.2316411e-02 -6.8682283e-01 9.6589236e-01 -8.0863095e-01
+1 3.2605453e-01 1 1 9.4172210e-01 -2.0406842e-01 -1.3410063e+00 -6.9299980e-01 -1.2015626e+00 -1.2198615e+00 1.1436674e+00 -1.3049774e-01
+1 8.9220632e-01 1 1 1.7947208e-01 8.4132118e-01 -5.0760320e-01 -1.3637322e+00 -5.0555950e-01 -1.7878157e-01 1.3534589e+00 -4.4391617e-01
+1 5.2090966e-01 1 1 4.5822080e-01 -2.2339976e-01 1.2785819e+00 8.1279647e-01 1.0696429e+00 -1.4192306e+00 -6.8859930e-01 3.8346926e-01
+1 4.5544494e-01 1 1 1.2734462e+00 -4.7662059e-01 6.3204817e-01 1.0253829e+00 1.2942975e+00 1.1040109e+00 3.3896335e-01 1.5612769e+00
+1 3.4767865e-01 1 1 -8.6028674e-01 4.9899324e-01 1.1088854e+00 -1.1671378e+00 8.7120421e-01 8.6441263e-01 1.2495389e+00 -1.3423658e+00
+1 2.8265460e-01 1 1 -1.2299032e+00 -1.4729992e+00 1.1098824e+00 1.8811904e-02 -6.3417914e-01 1.4586702e+00 -5.4621890e-01 -1.3643174e+00
+1 5.0596105e-01 1 1 6.9662614e-01 -9.4808085e-01 -9.8441194e-01 -1.1291834e+00 7.7499136e-01 -1.1193928e+00 -5.6731286e-01 4.0252124e-01
+1 1.0335746e+00 1 1 -5.2032530e-01 -2.3688980e-01 -1.3845069e+00 1.7498396e-01 2.3660096e-01 1.3643492e+00 -9.3588384e-02 1.3254553e+00
+1 3.5027612e-01 1 1 1.0866408e+00 -1.0089804e+00 3.6997320e-01 4.2468500e-01 -7.0393642e-01 1.3281727e-01 9.9794882e-01 -1.0688157e-01
+1 5.4272321e-01 1 1 1.0934600e+00 3.8413554e-01 9.2776513e-01 -1.7748944e-02 1.7855202e-01 -1.4125991e+00 -4.3734347e-01 6.3245866e-01
+1 3.3667831e-01 1 1 -5.3429660e-01 1.9310200e-01 1.2242502e+00 1.4480744e-01 7.0283565e-01 -5.3814976e-01 8.9510795e-01 -1.4168537e+00
+1 1.1346922e+00 1 1 -1.2512027e+00 2.0014506e-01 -1.4584364e+00 -9.5573826e-01 1.7041532e-01 -3.7684895e-02 -1.0078711e+00 2.1178346e-01
+1 6.6050683e-01 1 1 8.5775229e-01 -8.0769703e-01 -1.2347231e+00 -1.2961758e-01 -9.6213383e-01 1.2316888e+00 1.7794644e-01 2.0193974e-02
+1 6.5662572e-01 1 1 -5.2596693e-01 -1.4212368e-01 1.3690973e+00 -1.3588782e+00 -8.0584756e-01 1.0397137e+00 -5.0456502e-02 1.0811699e-01
+1 2.8312263e-01 1 1 5.1560310e-01 -1.0622253e+00 1.3942861e+00 7.1286431e-01 -4.7409323e-01 9.2991424e-01 2.0759174e-01 1.2817087e+00
+1 3.5254832e-01 1 1 1.2287022e+00 8.4984514e-01 6.2635746e-01 -9.2399114e-01 -1.0059775e+00 -3.5479367e-01 -1.3151228e+00 -2.2228226e-01
+1 1.0791684e+00 1 1 1.1099521e+00 -1.4745414e+00 -2.8712872e-01 -6.2664139e-01 5.8745501e-01 -2.7437501e-01 9.7650162e-01 -5.4433422e-01
+1 9.0253338e-01 1 1 1.8842515e-01 1.4065067e+00 -2.8610519e-01 -1.3432978e+00 -6.6940910e-01 4.3724046e-01 3.8262716e-01 -3.0746697e-01
+1 7.6035472e-01 1 1 1.3612520e-01 -1.3271286e+00 1.2084355e+00 -1.3211706e+00 -7.1547082e-01 5.1522167e-01 -2.5470173e-02 3.2256219e-01
+1 7.5336622e-01 1 1 7.7672785e-01 2.5699957e-01 -2.2095097e-01 -1.3702117e-01 1.0985942e+00 1.1012502e+00 -8.2058891e-01 -1.0862344e+00
+1 8.1175859e-01 1 1 1.1474972e+00 -2.9813328e-01 -1.6038396e-01 -1.2730828e-01 9.3293472e-01 -1.5525557e+00 -4.6119188e-02 -5.4743437e-01
+1 9.0129914e-01 1 1 -2.5232410e-01 1.1432190e-01 -8.6712439e-02 -2.4573959e-01 1.4485150e-01 2.6490436e-01 8.4819124e-01 9.9550728e-01
+1 6.7667338e-01 1 1 3.3901652e-01 -1.2464702e+00 3.2302244e-01 1.0490499e+00 -2.1507151e-01 6.1083115e-01 -9.9724071e-01 -6.3167645e-01
+1 8.4040491e-01 1 1 -9.9835585e-01 -1.2856766e+00 3.6597943e-01 7.6290680e-01 1.2662864e+00 -4.8559699e-01 -2.2785697e-01 -1.1444469e+00
+1 1.0352568e+00 1 1 -1.2045949e-01 -4.9189064e-01 -2.2219244e-01 1.3349624e+00 1.3263221e+00 4.2916786e-01 9.3479083e-03 1.2524922e+00
+1 3.7224771e-01 1 1 -1.3770548e+00 1.4659571e+00 9.6539756e-01 -5.4098461e-01 -1.2456860e+00 -7.2579766e-02 3.0661868e-02 -1.1758422e+00
+1 9.0180941e-01 1 1 -4.6479720e-02 -1.1693929e+00 -8.8927311e-01 -5.5921688e-01 -6.7184753e-01 -9.1017206e-01 1.1282670e-01 1.3798628e+00
+1 1.1225595e+00 1 1 1.0719191e+00 -1.8358984e-01 -1.4568398e+00 8.8704377e-01 -8.5745751e-01 -8.4722571e-01 -1.2436833e+00 1.1705670e-01
+1 5.1004661e-01 1 1 -1.2902713e+00 -5.5050388e-01 4.6587096e-01 -1.4540745e+00 -8.0288465e-01 1.5170685e+00 -1.5690579e+00 7.3491011e-01
+1 3.9695336e-01 1 1 8.2508237e-01 -3.2835217e-01 1.0443441e+00 -1.8061503e-01 -9.4188314e-01 2.0422212e-01 -6.2655979e-01 -1.1080738e+00
+1 7.1960727e-01 1 1 1.6937392e-01 1.1633950e+00 2.1299342e-01 -8.1837474e-01 2.5545619e-01 -1.3995300e+00 2.8253566e-02 -3.5214222e-02
+1 3.8622199e-01 1 1 3.8453552e-01 -9.3597147e-02 1.5063954e+00 -5.3166909e-01 -1.1049803e+00 -7.9636057e-01 4.7719012e-01 -1.2260139e+00
+1 7.1589102e-01 1 1 6.3246812e-01 8.5067111e-01 -1.0706203e-01 -1.0729293e+00 -1.4502818e+00 -1.2474759e+00 -3.5162963e-01 9.1298917e-02
+1 8.6575905e-01 1 1 -1.2579216e+00 -1.5884435e-01 7.4106475e-01 1.8442000e-02 7.3109609e-01 6.6138918e-01 -5.0332838e-01 1.3636873e+00
+1 3.7276342e-01 1 1 1.0294224e+00 6.5672406e-01 -1.3395523e+00 -1.0629862e+00 7.6317788e-01 1.0131797e+00 8.6891182e-01 -1.5683877e+00
+1 7.8317133e-01 1 1 7.5156513e-01 1.1463497e+00 -1.2023250e+00 6.2774039e-01 -3.9210447e-01 1.0791088e+00 -1.4633103e+00 1.2121617e+00
+1 1.3149153e+00 1 1 -7.8895614e-01 -6.8835433e-01 -7.5161224e-01 9.6460444e-01 9.6162056e-01 1.6722704e-01 -1.4681697e+00 -4.2614090e-01
+1 1.1319948e+00 1 1 6.7670908e-01 1.3144835e+00 -2.9012877e-03 1.4887787e+00 -1.5374333e+00 -1.1404931e+00 -1.4594809e+00 6.8112193e-01
+1 6.1023153e-01 1 1 8.8412517e-01 8.4454611e-01 1.5035407e+00 -8.8264610e-01 -4.2723321e-02 -1.4103014e+00 6.0337535e-02 -3.4728000e-01
+1 1.2261887e+00 1 1 -2.4148717e-01 5.7091962e-01 -9.6268576e-01 -3.2423555e-02 1.3738660e+00 3.8047900e-01 -6.4148179e-01 3.4414837e-01
+1 8.8576398e-01 1 1 2.6282583e-01 1.0221459e+00 -6.5747557e-01 -1.4471648e+00 -1.3957534e-01 1.5694571e+00 5.6153901e-01 4.2951126e-01
+1 6.9339175e-01 1 1 2.3449495e-01 9.7812646e-01 -1.2104813e+00 -2.8796901e-01 9.2697793e-01 1.0534110e+00 4.4182348e-01 -5.8422444e-01
+1 5.6322656e-01 1 1 -1.5421444e+00 -5.8292746e-01 3.9522196e-01 1.2990811e+00 5.6001729e-01 -1.3378303e+00 -9.9773642e-01 1.5584140e+00
+1 6.6147934e-01 1 1 -6.8117544e-01 1.3657438e+00 1.1685782e+00 -4.1351445e-01 -1.0583020e-03 -5.3479349e-01 8.6564946e-01 8.0687339e-01
+1 1.2475300e+00 1 1 -5.5195001e-01 -1.5616964e+00 -9.4325247e-01 -7.3440311e-01 1.0626742e+00 -1.7756276e-01 2.5494703e-01 -1.1343813e+00
+1 1.0477904e+00 1 1 4.9928833e-01 5.7505471e-01 -7.6766459e-01 2.0443023e-01 4.1031761e-01 2.1574838e-01 -2.3762756e-01 7.7916003e-01
+1 8.4606743e-01 1 1 3.4505269e-01 1.4054685e+00 3.8222161e-01 -1.0435351e+00 4.1225755e-01 6.8511858e-01 -8.4206542e-01 1.1844962e+00
+1 4.5633034e-01 1 1 -7.9515030e-02 7.3239309e-02 -5.5839083e-01 8.1665543e-01 -1.5408282e+00 8.5094237e-01 2.8136854e-01 -4.4426237e-01
+1 8.0378279e-01 1 1 -1.2322347e+00 -5.7125179e-01 -9.3735197e-01 -9.0449701e-02 -5.5209676e-01 1.2585827e+00 8.6413286e-01 8.4810309e-01
+1 6.0763009e-01 1 1 -7.8903410e-01 -3.2162190e-01 1.0125214e+00 3.4272605e-01 1.1745325e+00 6.5594835e-01 -1.0185474e-01 6.6269881e-01
+1 5.2332711e-01 1 1 -6.3354623e-01 1.1817598e+00 -5.5993954e-01 -1.4842094e+00 -1.4001920e+00 6.7527431e-01 2.9532901e-01 1.0330172e+00
+1 5.3492682e-01 1 1 -1.1539207e+00 6.8838760e-01 1.3076747e+00 -8.6185026e-01 6.4346162e-01 -1.2388823e+00 -1.2170961e-01 1.4786055e+00
+1 1.3362288e+00 1 1 -8.9374393e-01 -7.5534452e-01 -4.9361390e-01 7.6647247e-01 1.2975855e+00 5.8153560e-01 -3.9663316e-01 9.2413132e-01
+1 8.6087325e-01 1 1 -1.1996804e+00 1.0057113e-01 7.7730522e-01 -1.5686797e+00 -4.1702182e-01 3.7408422e-01 2.4610781e-01 -1.5890126e-01
+1 6.3877486e-01 1 1 -2.8726608e-01 1.2221636e-01 1.4265502e+00 -5.5477327e-01 7.3997139e-03 9.0652881e-01 -1.1435716e+00 -2.9972051e-01
+1 3.8590464e-01 1 1 5.4689088e-01 -5.1116567e-01 -6.0635433e-01 1.7261041e-01 -1.2967139e+00 -6.9463656e-01 2.5607258e-01 -1.4296267e+00
+1 3.9393911e-01 1 1 -7.0504548e-01 1.0945267e+00 3.2929452e-01 1.3731926e+00 -6.4162817e-01 -5.9844086e-01 -1.7003747e-01 -8.3611407e-01
+1 4.3075666e-01 1 1 3.8813417e-01 -1.4564177e+00 -1.0331770e+00 1.1092038e+00 1.2430038e+00 1.3841844e+00 1.0295192e+00 -2.2531104e-01
+1 6.7790827e-01 1 1 1.4245909e+00 1.2782750e+00 -1.0226551e+00 1.7772170e-01 -4.2672711e-01 4.9304807e-01 -7.6279321e-01 -1.1834629e+00
+1 1.1148281e+00 1 1 1.0223025e+00 -1.3834641e+00 -1.1065075e-01 -6.8600854e-01 2.5348810e-01 -8.6256140e-01 5.7416486e-01 -1.0386696e+00
+1 9.6204402e-01 1 1 4.6803493e-01 -9.5341201e-01 1.1574193e-01 -1.0056749e-01 3.7477604e-01 1.3805806e+00 -9.8383152e-01 9.1039715e-01
+1 5.0505562e-01 1 1 -2.8494237e-01 1.2684874e+00 6.2877135e-01 -6.1018663e-02 -3.2426228e-02 -3.8562193e-01 -1.0541402e+00 1.4886787e+00
+1 7.3046430e-01 1 1 -1.2392065e+00 6.2024904e-01 -5.5766715e-01 -1.3814721e+00 -1.4920857e+00 -4.2078423e-02 -1.4940200e+00 5.7887421e-01
+1 4.0652839e-01 1 1 1.4154947e+00 7.2115978e-01 -1.3408947e+00 1.1097622e+00 -1.2918302e+00 -3.5370092e-01 7.5564611e-01 -3.7360558e-01
+1 6.6706864e-01 1 1 -1.0613427e+00 2.6801357e-01 1.3676428e+00 1.3750908e-01 -2.4320107e-01 -7.5800680e-01 -1.3149690e+00 8.5477156e-01
+1 1.0205381e+00 1 1 -2.4474132e-02 -5.3972664e-01 -1.0601331e+00 -1.0971499e+00 -2.6834467e-01 -6.6209230e-01 4.2038273e-01 -3.5760072e-01
+1 3.4896355e-01 1 1 2.1190791e-01 -1.4076787e+00 1.4561460e+00 1.3502096e+00 1.2581748e+00 -2.6416128e-01 -6.9409711e-02 -3.2857687e-01
+1 8.9957583e-01 1 1 -1.0297601e+00 4.7918795e-01 4.3944870e-01 1.2488780e+00 8.3688073e-02 -6.8822387e-01 -1.0381455e+00 5.2845760e-01
+1 5.4273514e-01 1 1 -1.4434975e-01 -1.3316253e+00 -7.0005004e-02 9.1265843e-01 -8.8806973e-01 3.6558306e-01 2.9349025e-01 5.0441938e-01
+1 5.9065664e-01 1 1 -7.7679117e-01 8.0267538e-02 1.5231510e+00 -1.3467294e+00 -8.1330244e-02 -6.0075424e-01 3.9009119e-01 -1.3819746e+00
+1 6.7923165e-01 1 1 9.2981116e-01 1.3132577e+00 -1.2405149e+00 6.9449841e-01 -3.2460348e-01 2.0220143e-01 -2.4119267e-01 -1.0520401e+00
+1 3.1945712e-01 1 1 1.0543803e+00 -9.0815671e-01 1.4164089e+00 1.4179877e+00 1.3357179e+00 -8.0385788e-01 -1.0706973e+00 -7.5499708e-01
+1 8.7502814e-01 1 1 -7.5363303e-01 -1.5326659e+00 -1.4046263e+00 -2.6690875e-03 -4.1071329e-01 1.5506265e+00 -1.6721704e-01 -3.4321269e-01
+1 5.5617754e-01 1 1 5.9117265e-01 1.5436662e+00 1.5147863e+00 -8.7705568e-01 -7.7926334e-01 -1.2733341e+00 1.3085716e+00 -4.1163247e-01
+1 9.5035317e-01 1 1 -1.0188033e+00 1.1253358e+00 -4.5328988e-01 -3.2216141e-01 2.2081758e-01 -3.9708551e-01 -1.1271009e+00 -5.1994531e-01
+1 9.3414075e-01 1 1 -1.3477723e+00 1.1303673e+00 -8.0875070e-02 1.5390006e+00 1.0600607e+00 -1.0733348e+00 6.1849257e-01 1.1899728e+00
+1 6.5772167e-01 1 1 -1.1261432e+00 8.7174474e-01 1.0423172e+00 1.2510804e+00 4.6810659e-01 -5.1359351e-01 -5.2550011e-01 4.9320346e-01
+1 4.1540498e-01 1 1 1.0073932e+00 -9.7420887e-01 7.0407131e-01 2.2868930e-01 9.1951394e-01 1.1304534e+00 -1.0633543e+00 -1.3924703e+00
+1 7.3938634e-01 1 1 1.2141723e+00 4.5247866e-01 -1.0530022e+00 1.4132792e+00 7.7652658e-01 -8.2126465e-01 7.2521260e-01 -1.5241537e+00
+1 1.4500372e+00 1 1 -1.1916864e+00 -9.8705615e-01 -1.2168973e+00 -5.9873276e-01 9.0630026e-01 1.1630991e+00 -7.3127953e-01 9.4818315e-02
+1 4.4247226e-01 1 1 -1.0205138e+00 1.2980259e+00 -6.2422165e-01 -3.8024274e-01 -1.3943122e+00 1.2163960e+00 -7.0458228e-01 8.2394256e-01
+1 1.1073042e+00 1 1 1.3210938e+00 7.0178875e-01 -1.5154380e+00 -7.4020658e-01 -1.0654122e+00 -1.5174437e+00 -1.2517505e+00 -1.3779447e-01
+1 8.0058430e-01 1 1 -1.1538840e+00 1.4246366e+00 -1.0746240e+00 5.4896164e-02 6.9464710e-01 -2.2703081e-01 1.0761734e+00 -5.5779010e-01
+1 7.1829894e-01 1 1 -2.7635772e-01 -1.3524871e+00 -1.8987314e-01 -9.8841071e-01 7.7544457e-01 1.3282905e+00 1.0974788e+00 -2.6568954e-01
+1 1.5274785e-01 1 1 -1.4702964e+00 1.3131196e+00 6.6031407e-01 5.2318730e-01 1.5705993e+00 4.2123981e-01 1.0357835e+00 -1.2409124e+00
+1 1.1723867e+00 1 1 4.9700211e-01 -8.6446190e-02 -1.3483079e+00 -1.0881834e-01 1.4004353e+00 -1.3724079e+00 8.4920762e-01 1.0193083e+00
+1 1.2739571e+00 1 1 -3.8046769e-01 -1.4853054e+00 -7.0350024e-01 -5.0291512e-01 3.0429950e-01 -4.8686758e-01 3.7699450e-01 4.0987867e-01
+1 4.6325115e-01 1 1 -1.3794467e+00 -4.3228586e-01 1.2261333e+00 1.5313336e+00 -1.5114301e-01 1.0654415e+00 -4.4583710e-01 -6.8189200e-01
+1 1.1790667e+00 1 1 5.9286767e-01 1.0753927e+00 -1.2256365e+00 1.1966668e+00 1.2878320e+00 -2.0228713e-01 -4.8564904e-01 -2.8839369e-02
+1 7.3316845e-01 1 1 -8.0495607e-01 5.4241332e-01 1.5039840e-01 -9.7630333e-02 -9.8147719e-01 -6.3656240e-01 -4.4574535e-01 -8.9801329e-01
+1 5.8696177e-01 1 1 -1.1986761e+00 -5.6115959e-01 -1.2361329e+00 -9.6164277e-01 8.1581894e-01 1.5602396e+00 1.0563412e+00 -6.9827527e-01
+1 9.9216346e-01 1 1 8.8508311e-01 -3.4800678e-01 -3.3418094e-01 1.1641741e+00 1.5585651e+00 7.2631609e-02 7.8696345e-01 1.0776330e+00
+1 8.0185905e-01 1 1 1.5053601e-01 6.9554155e-01 5.8864875e-01 4.3491409e-01 2.0391576e-01 -1.3600971e+00 3.8963703e-01 4.9586902e-01
+1 7.2145313e-01 1 1 1.0766681e+00 1.0062636e-01 5.4426713e-01 -8.8502241e-01 -2.6533578e-01 -9.2420461e-01 1.5504445e+00 -5.7468219e-01
+1 1.0614157e+00 1 1 -1.3607523e-02 1.0504348e+00 -8.2020331e-01 8.6951582e-01 1.5630397e+00 -1.0728223e+00 -1.1896595e+00 -1.4276791e+00
+1 1.8615353e-01 1 1 6.3461740e-01 -1.0936861e+00 1.5145577e-01 -7.3669528e-01 9.9210269e-03 -1.3245923e+00 -1.5114441e+00 4.8277905e-01
+1 7.6373737e-01 1 1 3.0757759e-01 -1.2402325e-01 8.2706200e-01 -6.2098821e-01 2.3828887e-01 -1.0969070e+00 7.6735015e-02 -6.6634814e-01
+1 1.0532128e+00 1 1 1.5365792e+00 1.5588213e+00 -1.1165119e+00 -5.7799614e-01 -6.0963243e-01 -8.5094894e-01 -1.5091872e+00 4.6470065e-01
+1 6.1649351e-01 1 1 1.3950928e+00 1.3685857e+00 -4.8209775e-01 -5.7656540e-01 -1.3585260e+00 -1.3691270e+00 3.0950203e-01 2.2453125e-01
+1 9.5670967e-01 1 1 -1.5234016e+00 -9.2101454e-01 -4.4941392e-01 1.4786058e+00 3.4820229e-01 1.2481851e+00 -6.7676278e-01 6.4391203e-01
+1 5.4260490e-01 1 1 1.7026003e-01 -8.6434368e-01 -9.1102823e-01 9.2966346e-01 -5.5116929e-01 -1.3083950e+00 1.3549920e+00 -5.5719183e-01
+1 1.0167378e+00 1 1 -4.3052844e-01 -2.9982324e-01 4.7106579e-01 -1.4280974e+00 1.0545259e+00 9.5301894e-01 -5.5436673e-02 3.6469088e-01
+1 7.1244229e-01 1 1 -8.0360753e-01 -1.4625545e-02 3.8932156e-01 -2.6454255e-01 -1.4485224e+00 1.5500369e+00 1.3288584e+00 1.1237092e-01
+1 9.6500134e-01 1 1 -5.2486654e-01 -7.6730307e-01 -6.1010797e-01 -8.1299594e-01 -1.1152276e+00 1.3836314e+00 5.4118862e-01 5.2090794e-01
+1 7.5982249e-01 1 1 1.6016930e-01 1.7511479e-01 7.3694541e-02 -1.2362637e+00 -8.8931647e-01 6.2470073e-01 8.4644116e-01 -7.1904904e-01
+1 4.9708515e-01 1 1 -3.7948253e-01 -5.1811780e-01 7.9665236e-01 6.0977746e-01 9.5588795e-01 1.4244812e-01 1.0049663e+00 6.4975877e-01
+1 3.0033635e-01 1 1 -5.2975620e-01 4.8904671e-01 -1.3170578e-01 6.5449017e-01 -4.9605868e-01 2.3200348e-01 1.2662283e+00 3.1963351e-01
+1 2.7451816e-01 1 1 -3.3879512e-01 1.0016871e+00 1.2438564e+00 1.3004387e+00 5.2858521e-01 5.6592739e-01 3.5072406e-01 -4.3004208e-02
+1 7.4767878e-01 1 1 -1.5636700e+00 -4.4052444e-01 1.3377613e+00 4.1305574e-01 -4.9232787e-01 -1.2009758e+00 9.9145549e-01 -2.0541897e-01
+1 1.1706841e+00 1 1 -1.1784429e+00 8.3958668e-01 -6.2432391e-01 -6.9189578e-01 4.0059929e-01 -6.7377723e-02 3.8504903e-01 1.3370418e-01
+1 1.1098832e+00 1 1 -1.4896875e+00 -1.1009065e+00 -9.2445925e-02 1.4835506e+00 4.3919964e-01 -1.4440286e+00 -1.6186049e-01 9.2732960e-01
+1 4.5049709e-01 1 1 1.3163616e+00 1.0456810e+00 1.3496939e+00 -7.8614785e-01 -1.1143695e+00 -9.8476885e-01 2.3002930e-01 1.8748735e-01
+1 5.4971365e-01 1 1 9.9382308e-01 6.9047364e-01 -1.1348981e+00 7.5173635e-01 9.6742336e-01 -1.0999256e+00 -1.1980936e+00 8.2447356e-02
+1 5.7427755e-01 1 1 -6.6362714e-01 -2.5285106e-01 1.5182165e+00 -1.0527570e+00 -1.3991603e+00 -1.3178439e+00 1.2503145e+00 2.5034964e-01
+1 7.4489657e-01 1 1 -9.2736954e-01 9.0701936e-01 6.4861203e-01 -2.3788573e-01 -8.6536074e-01 -7.7393057e-01 -7.7995636e-02 1.0338098e+00
+1 1.0039484e+00 1 1 -8.5871966e-01 1.2668287e+00 -1.0410309e-01 1.1019349e+00 1.4561011e+00 -1.2575628e+00 -8.2852038e-01 -9.0709294e-01
+1 9.0768107e-01 1 1 -2.4693286e-02 1.0169527e+00 2.0642207e-01 5.3147295e-01 -3.1523279e-01 7.7697666e-01 -1.4033586e+00 6.3817207e-01
+1 7.6118281e-01 1 1 -3.2981913e-01 -1.4814223e+00 1.0175246e+00 9.1795996e-01 -1.3922048e+00 -9.5388624e-01 8.2936270e-01 3.6058266e-01
+1 1.1471168e+00 1 1 -1.5006552e+00 -1.1420352e+00 -1.2952845e+00 -2.0845521e-01 -2.0396931e-01 -4.1880529e-01 -1.4777427e-01 1.8056892e-01
+1 3.8880067e-01 1 1 -8.0690143e-01 9.4568756e-01 1.3901114e+00 -6.3089336e-01 -6.3465643e-01 1.4486237e+00 1.3575605e+00 4.3310415e-02
+1 5.7779574e-01 1 1 6.6311722e-01 8.5366608e-01 -4.2281276e-01 -5.4947631e-01 -9.6361497e-01 -3.2468045e-01 -8.6756292e-01 -9.3135690e-01
+1 1.0328431e+00 1 1 -1.3596803e+00 -8.7804366e-02 6.8480156e-02 1.2341231e+00 -5.6665406e-01 4.2083562e-02 -9.9844900e-01 1.2407798e+00
+1 2.8932413e-01 1 1 -2.0183909e-01 8.2057062e-01 1.1230661e+00 1.1128806e+00 1.5542130e+00 4.4007598e-01 1.4556375e+00 -1.0674784e-01
+1 4.0243389e-01 1 1 6.1051992e-01 -2.6134455e-01 6.8342058e-01 -8.5768180e-01 -6.8457254e-01 1.0478179e+00 1.3168331e+00 -2.6158759e-01
+1 3.4676213e-01 1 1 5.6674622e-01 -4.7132808e-01 5.8698625e-01 -1.4308638e+00 -1.0983765e+00 -1.0924970e+00 -5.0662716e-01 -1.4144914e+00
+1 5.2616013e-01 1 1 -5.2399714e-03 1.4855886e+00 8.7697015e-01 3.6360135e-01 -4.1459016e-01 1.0115884e+00 -1.1666218e+00 -9.2513639e-01
+1 1.0850318e+00 1 1 -1.0360521e-01 -1.0912969e+00 -1.1154068e+00 6.5014387e-01 3.5645720e-02 -5.3289740e-01 -7.3349706e-01 -1.0252990e+00
+1 8.0513117e-01 1 1 -8.5037557e-01 -8.0826698e-01 -7.5799175e-01 5.0877504e-01 -9.4657842e-01 2.7411297e-01 -2.7558309e-01 -5.6437521e-01
+1 9.9796612e-01 1 1 -1.1572710e+00 -2.9651925e-01 -4.0906477e-01 -4.3314912e-01 -1.1838779e-01 1.4418741e+00 -1.0173910e+00 -9.8595117e-01
+1 7.7748069e-01 1 1 -6.5394342e-01 -1.0330801e+00 -1.3468239e+00 -8.6700917e-01 -1.1154427e+00 -6.6794141e-01 3.9902542e-01 1.0199436e+00
+1 6.7171079e-01 1 1 -1.5359725e+00 6.0504639e-01 -8.9440437e-01 -1.1164066e+00 -1.3628384e+00 -1.1807688e+00 -8.8007059e-01 -1.4785382e+00
+1 7.4548852e-01 1 1 -6.2372898e-01 -3.2078288e-01 2.6664684e-01 1.2880132e+00 1.2629931e-01 2.5938151e-01 -7.2817828e-01 2.0698118e-01
+1 6.2805754e-01 1 1 4.8177718e-01 -4.2481736e-01 -1.5192296e+00 -1.0777897e+00 -1.0041578e+00 -1.1054854e+00 1.1526487e+00 9.8955638e-01
+1 4.9740625e-01 1 1 1.3448412e+00 9.3471052e-01 1.1729112e+00 1.2476815e-02 -2.4486537e-01 -5.1487148e-01 1.5060942e+00 -1.1735023e-01
+1 1.0548464e+00 1 1 -1.0130095e+00 -1.4251114e+00 -3.7614429e-01 -7.8887759e-01 3.4042257e-02 -1.4988099e+00 1.1131138e+00 6.1491440e-01
+1 1.2385491e+00 1 1 -1.3602683e+00 -3.4471424e-01 -9.7269668e-01 -1.1446458e+00 3.7834364e-01 -1.2085513e+00 -7.9941605e-02 -9.7347499e-01
+1 4.7211180e-01 1 1 -6.5983820e-01 -5.1530836e-01 7.3512524e-01 1.0508562e+00 2.3810237e-01 1.4165108e+00 1.0230938e+00 2.2030911e-01
+1 6.4942459e-01 1 1 -7.8528048e-02 5.8330122e-01 -6.3398633e-01 -2.9369860e-01 -6.0244880e-01 3.0849134e-01 1.2004729e+00 -1.2025002e+00
+1 3.4597309e-01 1 1 -3.5198216e-01 -1.3670060e+00 8.7407388e-01 -7.5038881e-01 -3.7779194e-03 1.1861408e+00 1.0405787e+00 -5.5589347e-01
+1 3.8712928e-01 1 1 -1.4528034e-01 -8.0335222e-01 4.7250514e-01 -1.4318684e+00 -6.6363793e-01 -1.0790199e+00 -2.4055863e-01 1.9498513e-01
+1 7.6305206e-01 1 1 -7.0922921e-01 6.2438721e-01 -5.5225633e-01 -8.1182125e-01 -1.1087006e+00 1.3263755e+00 1.6091547e-01 4.3392845e-01
+1 9.1148020e-01 1 1 -8.1288700e-01 1.1563614e+00 -1.5074217e+00 -3.4278741e-01 -1.1451938e+00 -3.4857053e-01 -4.0504529e-01 1.3989872e+00
+1 1.1399076e+00 1 1 5.9462692e-01 1.0744556e+00 -1.4328422e+00 4.5284744e-01 1.2657122e+00 6.4534681e-01 2.3508271e-01 1.0986243e+00
+1 1.0123926e+00 1 1 4.8849339e-01 4.9997186e-01 -1.4706408e+00 -1.0721118e+00 1.1004760e+00 1.5659386e+00 -1.0883743e+00 1.4379079e+00
+1 3.4894798e-01 1 1 1.1267258e+00 -7.3326296e-01 9.9052597e-01 1.1924673e+00 1.1433848e+00 -1.5337338e+00 1.1875420e+00 -1.3533964e+00
+1 8.0179243e-01 1 1 -6.4083409e-01 5.1732745e-01 4.7051051e-01 -1.5637514e+00 -2.5397852e-01 -6.9623743e-01 4.7951311e-01 -1.4022566e+00
+1 3.7435233e-01 1 1 -1.1189925e+00 -1.2060931e+00 4.8151166e-01 5.9464722e-01 8.0749042e-01 7.7014819e-01 9.9174412e-01 5.0102406e-01
+1 1.0471679e+00 1 1 -1.3333778e+00 -1.2507245e+00 2.3722476e-02 8.2959250e-01 -1.8876758e-01 5.1894604e-01 -1.0472658e+00 1.2431389e+00
+1 5.4827218e-01 1 1 -1.1008919e+00 -5.3006370e-01 -2.7862115e-01 5.7297264e-01 3.9194377e-01 8.6483440e-01 9.4805899e-01 -1.2966778e+00
+1 5.5623681e-01 1 1 1.2908897e+00 7.7622102e-01 1.3289193e+00 9.6965566e-01 -5.2079135e-01 -8.7752576e-01 -1.3054228e-01 -3.6215960e-02
+1 3.8134746e-01 1 1 1.4497111e-01 -1.0875752e+00 1.5637975e+00 1.5616662e+00 -4.6313536e-01 1.2020401e+00 -1.1923525e+00 7.8733916e-01
+1 1.0725874e+00 1 1 -1.3465078e+00 -1.0901938e+00 1.8088427e-01 -1.0824129e+00 9.5060844e-01 -8.9381250e-01 3.5120171e-01 4.2102667e-01
+1 6.6925673e-01 1 1 1.2769911e+00 -1.1182881e+00 -9.3981964e-01 8.4938348e-01 -1.2641962e+00 7.8935963e-01 -4.0538402e-01 1.3285359e+00
+1 6.9605452e-01 1 1 -9.7105743e-01 1.0807348e+00 3.7915825e-01 1.9120898e-01 -7.5397624e-01 -1.7843188e-01 8.2528370e-01 1.4042345e+00
+1 2.6200553e-01 1 1 1.1533891e-02 -7.7831354e-01 1.3628548e+00 -1.9992200e-01 1.1060628e+00 1.3163197e+00 4.1160350e-01 1.3248830e+00
+1 4.9508157e-01 1 1 -9.2863544e-01 4.7616016e-01 1.4799621e-01 1.4150721e+00 7.9456375e-01 2.8900457e-01 3.2969954e-02 -2.9958410e-01
+1 5.3963971e-01 1 1 -1.4357004e-01 1.1872630e+00 -7.6906851e-01 1.2598550e+00 -6.7739905e-01 3.9749318e-01 1.2057054e+00 8.6306188e-01
+1 1.1258089e+00 1 1 -2.3851879e-01 -1.0680051e+00 -1.2223388e+00 4.7827089e-02 8.5883582e-02 -1.4996610e+00 1.0178668e+00 7.4766013e-01
+1 8.2593353e-01 1 1 -1.1315523e-01 1.0979609e+00 -9.7378141e-01 -4.1782852e-01 1.4543379e+00 1.9471379e-01 1.3154608e+00 -4.4686017e-01
+1 5.4166762e-01 1 1 -1.1364089e+00 -2.8640903e-01 1.3536182e+00 -9.8440934e-01 1.4657872e+00 -9.8485089e-01 1.5621538e+00 1.1691233e+00
+1 1.0468284e+00 1 1 1.2587557e+00 -7.5659908e-01 -1.1533027e+00 -1.3408645e+00 -8.8439782e-01 6.6281331e-01 8.2992703e-01 -1.2064716e+00
+1 4.8919311e-01 1 1 4.2162757e-01 1.0062475e+00 6.7556482e-02 -1.2649934e+00 -1.1992732e+00 -1.8422866e-01 -8.7769209e-02 -1.3287808e+00
+1 6.8412688e-01 1 1 -1.1384192e+00 8.0789267e-01 1.3068521e+00 1.5543460e+00 2.7402828e-01 1.2791986e+00 1.4114518e+00 7.6400171e-01
+1 6.2366619e-01 1 1 -1.1128658e+00 2.8870880e-01 1.3884144e+00 1.5509261e+00 1.8394428e-02 -1.5698317e+00 1.0347182e-01 8.8754769e-01
+1 5.4233799e-01 1 1 1.1079064e+00 -1.4318935e+00 -6.6960697e-01 6.2081541e-01 1.2790778e+00 -1.0661143e+00 -1.3914912e+00 7.3209381e-01
+1 7.1237590e-01 1 1 3.6294202e-01 -1.2338616e+00 -8.9942858e-01 8.1534115e-01 -4.5860614e-01 1.4614667e+00 -7.7645118e-01 -1.3177409e+00
+1 7.4745823e-01 1 1 -1.0064844e+00 1.4059852e-01 6.4766476e-01 -1.8852384e-01 -1.4665709e+00 -1.2421454e+00 3.6090275e-01 9.5627521e-01
+1 8.9250750e-01 1 1 1.4936557e+00 5.6168641e-01 -3.1695888e-01 1.3467614e+00 2.7929725e-01 -8.5517524e-01 -7.2292299e-01 -2.7062636e-01
+1 5.1540623e-01 1 1 -5.9618940e-01 -2.2235643e-01 1.0132087e+00 -1.5552099e-01 6.0952820e-01 -1.4384823e-01 1.5137194e+00 6.0897329e-01
+1 4.1644067e-01 1 1 1.5252901e+00 1.3507087e+00 1.5671660e+00 -3.6145958e-02 -3.9314442e-01 1.3690786e+00 4.6506933e-01 -2.9483209e-01
+1 6.5098713e-01 1 1 1.5405367e-01 2.1302874e-01 2.4606419e-01 -1.1777283e+00 -8.0888759e-01 1.0793724e+00 1.3765615e-01 -9.5131563e-01
+1 5.5473851e-01 1 1 5.0763994e-01 -1.0416115e+00 1.2648534e+00 1.0955280e+00 -1.3022734e+00 1.4557676e+00 1.3746569e+00 -1.1967798e+00
+1 1.0935062e+00 1 1 -6.6119569e-01 -1.4099391e+00 -7.6590209e-01 -3.3565256e-01 1.6645839e-01 3.6328565e-01 5.8654374e-01 1.3392421e+00
+1 1.0893421e+00 1 1 -9.0266410e-01 1.8716563e-01 -1.4112887e+00 9.8785617e-01 -1.4929349e+00 -1.5141213e+00 -2.7714773e-01 -8.6858239e-01
+1 1.0439518e+00 1 1 -3.2461725e-01 9.5847529e-01 -5.0446966e-01 -4.1845770e-01 1.4349669e-01 -9.3657099e-01 9.5997876e-01 7.1678344e-01
+1 7.5890269e-01 1 1 1.1043517e+00 -9.9295162e-01 5.3703323e-01 1.0073969e+00 -9.9436039e-01 -1.5695063e+00 -8.5691889e-01 -1.0285004e+00
+1 7.0676729e-01 1 1 3.1001070e-01 -3.9762910e-01 1.2184741e-01 1.2775337e+00 1.0577980e+00 1.2613612e+00 -1.1750008e+00 -9.6308552e-01
+1 1.2041052e+00 1 1 -1.5523523e+00 -7.8476626e-01 -4.2906050e-01 -1.2768863e+00 1.3841658e-01 2.2966589e-01 -1.8624374e-01 -1.0929569e+00
+1 1.1721115e+00 1 1 5.4207244e-01 -1.1605467e+00 -1.2646027e+00 -4.0816930e-01 -1.5526989e+00 -1.0227289e+00 -1.1722331e+00 -4.3423277e-01
+1 8.6247911e-01 1 1 -7.1510515e-03 8.4005343e-01 -1.3040342e+00 1.1369649e+00 9.9967431e-01 -1.3512503e+00 -7.9452112e-01 -2.3037083e-01
+1 7.8430465e-01 1 1 -8.0720204e-01 4.6059779e-01 -1.1527585e+00 -1.3387013e+00 2.8868110e-01 1.0890476e-01 1.3938228e+00 -1.4004565e+00
+1 1.0165396e+00 1 1 -1.2476779e+00 3.8279239e-01 -2.1053792e-01 5.3361765e-01 1.2442131e+00 -1.1862587e+00 -8.7734214e-01 -6.5975758e-01
+1 1.0908975e+00 1 1 4.0900506e-01 -3.9000510e-01 -1.0775245e+00 -7.3523912e-01 1.0488035e+00 -9.0232016e-01 1.1465179e+00 1.2764515e+00
+1 6.4178538e-01 1 1 3.4339307e-01 -1.4534395e+00 1.3265390e+00 -1.2799601e+00 -2.3626629e-01 -8.2723840e-01 -1.0022641e+00 -6.1598031e-01
+1 6.7322882e-01 1 1 3.0167408e-01 1.0670287e+00 -7.4209385e-01 1.3374741e+00 4.5530361e-02 1.2932984e+00 1.6737238e-01 -1.2332112e+00
+1 7.0614646e-01 1 1 -2.9430574e-01 1.3396945e+00 -2.4842001e-01 8.3095538e-01 -1.3198363e+00 -2.1253247e-01 1.3022270e+00 -1.4942499e+00
+1 9.9559369e-01 1 1 -1.5297926e+00 4.5154870e-01 -1.8520248e-02 1.4877619e+00 2.9728381e-01 -4.2453440e-02 -9.4624347e-01 3.4358275e-02
+1 1.1605148e+00 1 1 -4.3063458e-01 -9.0889708e-01 -2.5213735e-01 8.7890875e-01 1.3167514e+00 -3.7343619e-01 -7.7199933e-01 -5.9352544e-01
+1 7.0376701e-01 1 1 5.5410535e-01 -1.4098114e+00 3.3606190e-01 5.0725695e-02 1.2617422e+00 5.6003988e-01 -2.1510431e-01 -8.2546215e-01
+1 3.8285677e-01 1 1 1.1680022e+00 -8.0759005e-01 -3.9118074e-01 1.1751427e+00 3.5074987e-01 3.7859364e-01 7.1496614e-01 -2.6914074e-01
+1 8.7980270e-01 1 1 -1.1999556e+00 -1.4857726e+00 7.7864598e-01 -5.7004007e-01 1.4252486e+00 1.2982519e+00 -1.5595523e-01 4.4499222e-01
+1 6.5900069e-01 1 1 1.3703172e+00 1.1392708e+00 -1.1719389e+00 1.1941580e+00 -4.9083891e-01 1.3583875e+00 -1.0513458e+00 -1.1478876e+00
+1 4.8912762e-01 1 1 -9.4255946e-02 -2.8368701e-01 1.0095898e+00 -1.4211580e+00 2.9272636e-01 4.6468140e-01 1.4898569e+00 -2.6511770e-02
+1 6.6565183e-01 1 1 -7.9698278e-01 1.0101345e+00 4.3421452e-01 1.2638897e-01 1.1780384e-01 -9.9110910e-02 1.5308928e+00 5.2283492e-01
+1 9.4516266e-01 1 1 8.6151325e-01 1.6317666e-01 -7.6379874e-02 5.0277101e-01 7.2572247e-01 -7.1295858e-01 7.0996360e-02 2.5183595e-01
+1 6.5588297e-01 1 1 -1.4738145e-01 -1.0033594e-01 1.1948553e+00 -8.1193068e-01 1.5548114e+00 -6.6041216e-01 -5.6938254e-01 8.8148313e-01
+1 5.4504647e-01 1 1 -1.4649715e+00 6.8915920e-01 8.7338680e-01 9.5953036e-01 -5.2348075e-02 -3.0034190e-01 -3.2117164e-01 -6.6401040e-01
+1 4.5852234e-01 1 1 -1.1142233e+00 -3.5335935e-01 1.4911475e+00 1.0315921e+00 -1.6815852e-01 6.9310671e-01 -6.7554998e-01 -1.0856295e+00
+1 5.5837075e-01 1 1 2.8310647e-01 -1.3004101e+00 1.2315630e+00 -4.8065081e-01 1.1931306e+00 1.8976819e-02 -2.5272453e-01 1.9575242e-01
+1 8.2658966e-01 1 1 -1.3423451e+00 6.6764718e-02 -1.0752582e+00 -1.2635314e+00 1.5945917e-01 -1.4990538e+00 -1.0797164e-01 7.6345496e-01
+1 7.9642570e-01 1 1 -1.0177107e+00 5.6602980e-01 -1.4231333e+00 9.9362487e-01 2.5168914e-01 9.7564203e-01 1.1611835e+00 1.1231307e+00
+1 5.8587932e-01 1 1 1.3079265e+00 5.2035398e-01 1.4855202e+00 -8.5328914e-01 1.5556455e+00 -1.4980607e+00 4.3741461e-01 -1.3723493e+00
+1 7.3309519e-01 1 1 5.9731886e-01 -6.0455829e-01 9.0152965e-01 1.3982272e-01 1.3994149e+00 -1.1821120e+00 3.0052153e-01 4.9839327e-01
+1 1.0018253e+00 1 1 -1.3920766e+00 -9.0052816e-01 1.0738907e-01 8.9135792e-02 -1.1374769e+00 -3.2431568e-01 -8.1562920e-01 1.0096672e+00
+1 7.1236647e-01 1 1 -1.1904637e+00 1.0166953e+00 -1.5275950e+00 -4.3443209e-01 -9.8340997e-01 -1.1041495e-01 -1.5112142e+00 -1.4071790e+00
+1 7.0020758e-01 1 1 6.8062957e-01 4.7565851e-01 -1.1947582e+00 -4.3881751e-01 -2.5235785e-01 9.3722286e-01 8.0008818e-01 -5.4832626e-01
+1 2.2547475e-01 1 1 8.0226081e-01 -9.6072132e-01 7.5940423e-01 1.2536480e+00 -2.2833460e-01 -4.0877763e-02 1.0654472e+00 -1.4282395e+00
+1 1.1539943e+00 1 1 -1.1830725e-01 9.4306467e-01 -9.8398446e-01 -5.9929573e-01 1.4066546e+00 9.7622390e-01 -1.0703607e-01 4.8893831e-01
+1 1.0731559e+00 1 1 2.3828285e-01 7.5294097e-01 -4.8312147e-01 -4.1725871e-01 1.1587667e+00 -1.1434018e+00 1.1773658e+00 -8.2018004e-01
+1 7.3857690e-01 1 1 -7.1083360e-01 3.4367631e-01 1.1945155e+00 -8.3232497e-01 6.5934402e-01 -3.2266413e-02 -9.0585353e-01 5.4271290e-01
+1 3.7944568e-01 1 1 4.9647133e-01 -1.2210727e+00 1.4441884e+00 6.2630882e-01 1.1975806e+00 1.1939254e+00 -5.2235126e-01 1.3323015e+00
+1 7.0471398e-01 1 1 1.2355908e-01 1.4565464e+00 5.3026912e-01 -1.1047044e+00 -4.4617555e-01 9.5166881e-01 -1.5477202e+00 -1.2814703e+00
+1 8.6897865e-01 1 1 6.4761953e-02 8.8562549e-01 -4.6524545e-01 4.5234389e-02 1.0924811e-01 8.4950101e-01 -1.4544201e-01 1.0872827e+00
+1 8.5945126e-01 1 1 1.4630926e+00 -1.5844000e-01 4.3777425e-02 -1.1047916e-02 1.4429025e+00 -9.7516580e-01 -2.8477512e-01 -6.8487962e-01
+1 7.1679959e-01 1 1 9.5162002e-01 1.1695569e+00 6.3449931e-01 -3.2835171e-01 9.0901579e-01 7.7199399e-02 -1.5699094e+00 2.3696234e-02
+1 3.0095577e-01 1 1 2.9441986e-02 -2.0204096e-01 1.4644125e+00 1.1710908e+00 2.6335225e-01 1.2534850e-02 7.7006674e-01 -7.1966750e-01
+1 6.8130363e-01 1 1 -1.5401748e+00 3.5929141e-01 1.1442814e+00 4.4464466e-01 -3.4280187e-01 1.8652377e-01 -8.5007283e-01 -3.1992589e-01
+1 8.5878975e-01 1 1 1.0061333e+00 4.6959666e-01 -8.9331730e-01 -7.0609535e-01 2.0987609e-01 -4.0450725e-01 7.8929853e-01 1.4121543e+00
+1 4.8717362e-01 1 1 -1.1116842e+00 8.3037650e-01 -3.1262941e-01 -1.5490265e+00 -6.2104956e-01 -1.4691747e-01 -1.2053190e+00 -6.5498812e-01
+1 7.6563779e-01 1 1 -1.0250924e+00 1.1833349e+00 1.5220697e+00 -1.0936804e-01 1.5324067e+00 4.9939906e-02 -8.0652298e-01 -2.4459995e-01
+1 1.1608894e+00 1 1 -2.3404947e-01 -1.1138224e+00 -5.6372557e-01 -3.1692461e-01 3.8213958e-01 5.3475939e-01 7.4050963e-01 1.3534153e+00
+1 7.1814244e-01 1 1 -3.9536907e-01 7.3685614e-01 5.0783562e-01 -1.5524027e+00 1.2046185e+00 -3.9551720e-01 -1.2448051e+00 -1.4216194e+00
+1 9.5814533e-01 1 1 -4.9953002e-01 1.8286360e-01 -5.1399588e-01 -3.0451624e-01 -1.5413024e+00 1.5255296e-01 1.5675685e+00 -1.3451751e+00
+1 4.0269715e-01 1 1 -1.2654482e+00 9.1087142e-01 6.5098551e-01 -3.4996587e-01 9.0316210e-01 4.1805255e-01 7.2747452e-01 -1.4568508e+00
+1 8.7970843e-01 1 1 1.9460486e-01 3.4944251e-02 -1.0537909e+00 -8.1491095e-01 -7.3036094e-01 -1.5335315e+00 -4.1432572e-01 2.8195822e-01
+1 3.5810426e-01 1 1 3.2599866e-01 -1.6980098e-01 1.2351867e+00 1.1357153e+00 -9.7385816e-01 -4.3790319e-01 1.3385699e+00 1.3501615e+00
+1 9.1416956e-01 1 1 1.2193362e-01 -1.2789381e+00 1.3934761e-01 -3.4974792e-01 6.3647362e-02 9.1260194e-01 3.9888308e-01 4.3978494e-01
+1 3.7637893e-01 1 1 1.0199899e+00 -3.3630426e-01 1.5288063e+00 -2.9341922e-01 -1.5618824e+00 8.4552442e-01 -1.3074498e-01 -7.0210269e-01
+1 9.3380104e-01 1 1 -7.0054795e-01 -5.4054948e-01 -4.3852905e-01 8.0362048e-01 5.9148315e-01 1.3054188e+00 -1.4575712e+00 -4.1787815e-01
+1 9.7466021e-01 1 1 5.7986443e-01 4.7080908e-01 -1.8142052e-01 7.4263594e-01 1.0581279e+00 -7.0916984e-01 7.4099445e-01 1.3231587e+00
+1 2.5940381e-01 1 1 5.6105853e-01 -7.8375726e-01 1.3518409e+00 -6.5325924e-02 -6.0056194e-01 1.8506088e-01 6.2052397e-01 -1.0056930e+00
+1 9.1728672e-01 1 1 -1.3505060e+00 8.9793267e-02 3.9148280e-01 -1.5169754e+00 2.9262924e-01 1.4143696e-01 -9.4116886e-01 -9.1355659e-01
+1 5.9640021e-01 1 1 5.2337455e-02 1.1909703e+00 1.1563430e+00 1.3598229e+00 -1.5145200e+00 -1.0546027e+00 -3.0598600e-01 -1.1823738e+00
+1 3.8919231e-01 1 1 -1.0345017e-02 1.5514186e+00 7.6413970e-01 -5.4266742e-01 -1.3546937e+00 1.5771566e-01 8.0541143e-02 1.5589049e+00
+1 7.0784949e-01 1 1 -1.0811074e+00 -5.2720099e-01 6.5099554e-02 -5.6785885e-01 -1.2152414e+00 -7.7707842e-01 -3.7144537e-01 -3.6740220e-01
+1 6.0813334e-01 1 1 7.9986028e-01 -1.3757719e+00 8.5395942e-01 1.5480461e-01 -1.0689934e+00 -7.5628091e-01 -5.3775335e-01 1.4423194e+00
+1 8.7215078e-01 1 1 3.7676208e-01 -4.7629414e-01 -1.4408744e+00 5.6228083e-01 1.9587492e-01 7.0546242e-02 3.4158994e-01 5.3385118e-01
+1 9.3988972e-01 1 1 -1.2105215e+00 -2.9751948e-01 -1.3798338e+00 3.4323655e-01 -3.1929854e-01 1.2902630e+00 1.4124206e+00 4.8082382e-02
+1 7.2287144e-01 1 1 -2.8004267e-01 1.0055978e+00 3.7068086e-01 8.1252781e-01 -6.1031229e-01 -9.6313986e-01 6.7957985e-01 7.3127771e-01
+1 1.0326119e+00 1 1 -5.7127841e-01 -6.8653338e-01 2.5501640e-01 -3.4827883e-01 -2.1857012e-01 1.1353910e+00 -1.1323919e+00 6.7394655e-01
+1 4.9234182e-01 1 1 -7.6911010e-01 5.0323440e-01 9.2830051e-01 -7.3513803e-01 -9.8617657e-01 4.8290808e-01 -3.4267953e-01 -1.5633805e+00
+1 5.9345176e-01 1 1 1.2202625e+00 6.9312122e-01 7.9757498e-01 4.1911823e-01 3.7315521e-01 1.5022732e+00 -8.7555742e-01 5.4416127e-01
+1 1.0719278e+00 1 1 6.3540794e-01 2.6283331e-01 -3.3319456e-01 6.6929451e-01 1.0006204e+00 -2.7529517e-01 -2.7356099e-01 5.4223032e-01
+1 3.5886352e-01 1 1 1.0278203e+00 3.6008670e-01 1.4586975e+00 -1.2104988e+00 4.8206378e-01 6.8013420e-01 1.5521334e+00 -4.9535992e-01
+1 9.6496783e-01 1 1 -1.0420918e+00 1.2696496e+00 -6.5980761e-01 1.0142874e-01 -1.2155153e-01 -1.2401458e+00 -1.0800130e+00 -2.9360491e-01
+1 7.8206760e-01 1 1 -5.7454999e-02 1.3042664e+00 4.3549330e-01 -1.1720042e+00 -8.8130146e-01 1.3375247e+00 3.4307778e-01 8.2437628e-01
+1 1.2847029e+00 1 1 -1.1772308e+00 -1.2277887e+00 -5.7503863e-01 -8.8723269e-02 5.7573797e-01 -1.4599671e+00 1.2857385e+00 8.6857855e-01
+1 9.2741471e-01 1 1 3.3149031e-02 -1.4640541e+00 -1.1353036e+00 1.0845356e+00 3.2267792e-01 1.3130711e+00 1.5318581e+00 -7.8142336e-01
+1 5.7117461e-01 1 1 1.0738643e+00 -1.4031690e+00 9.8615637e-01 2.7000443e-01 8.5896237e-01 -9.0257125e-01 5.8809496e-01 -1.5251276e+00
+1 4.7437210e-01 1 1 -1.1996293e-02 8.7521379e-01 -7.1277909e-01 1.5046383e+00 9.6232446e-01 1.2359364e+00 6.6143789e-01 -5.6496017e-01
+1 1.0893021e+00 1 1 -5.5977088e-01 7.8144381e-01 -7.8531961e-01 -1.3649829e+00 8.6814754e-01 1.7259759e-01 -1.3098292e+00 -1.3926612e+00
+1 7.8836470e-01 1 1 1.0007477e+00 -1.2727105e+00 -1.0359752e+00 -1.3578161e+00 1.3994794e+00 1.1576115e+00 -1.1590226e+00 1.5492872e+00
+1 9.2659749e-01 1 1 -5.2001891e-01 6.5862999e-01 -9.2859574e-01 -2.8584608e-01 -5.3621148e-02 9.3443849e-02 1.3233075e+00 1.3497176e+00
+1 8.9248434e-01 1 1 -4.7061683e-02 -1.3781933e+00 5.2362996e-01 -7.1995192e-01 4.2646433e-01 -2.8555328e-01 1.4948072e+00 -7.3675653e-01
+1 3.6187581e-01 1 1 7.1563746e-01 -3.3193755e-01 1.0477091e+00 1.1829789e+00 -1.5284319e+00 1.0595963e+00 -9.1978681e-02 1.4912095e+00
+1 8.3696721e-01 1 1 -1.4395008e+00 5.9413110e-01 2.1992611e-01 -8.1306273e-01 4.4747052e-01 -1.0529024e+00 -2.2210857e-01 -8.6883281e-01
+1 7.8154579e-01 1 1 -2.8459855e-01 -1.5616828e+00 -1.3563836e+00 7.8277282e-01 -3.3579962e-01 4.6002791e-01 -7.6660724e-01 -3.5044720e-01
+1 5.5145499e-01 1 1 1.3977980e+00 8.0460141e-01 -1.3432546e+00 -9.2726392e-01 -1.4837786e+00 2.2955242e-01 -6.9639739e-01 5.2018995e-01
+1 5.6524888e-01 1 1 -3.8683926e-02 1.5210480e+00 -5.9473986e-01 9.1652999e-01 9.6282544e-02 2.1177719e-01 1.2233202e+00 -2.1993557e-01
+1 7.6913460e-01 1 1 1.4893561e-01 1.1140113e+00 7.5503624e-01 8.9070245e-01 3.0049569e-01 -8.5187040e-02 -1.3811871e+00 1.1974761e+00
+1 6.8055407e-01 1 1 -6.8859056e-01 -7.0435592e-01 1.0012908e+00 3.4710966e-01 -1.2499140e+00 8.2766743e-01 -3.8281598e-01 9.3885378e-01
+1 1.0300484e+00 1 1 4.8587225e-01 -5.8888196e-01 -8.1704551e-01 -6.5496752e-02 5.2468875e-01 -3.6577679e-01 -6.4399475e-03 -9.0441982e-01
+1 8.4929617e-01 1 1 1.0556529e+00 -1.3222040e+00 -1.8236228e-01 -1.2464868e+00 -6.6914480e-03 4.8625550e-01 -1.4220478e+00 -1.5586639e+00
+1 5.4475037e-01 1 1 -1.3573778e+00 1.3435258e+00 1.2315070e+00 -1.5637339e+00 6.3416885e-01 1.2137653e+00 8.8008312e-01 1.2774465e+00
+1 5.0021835e-01 1 1 7.9782929e-01 -1.1292045e+00 1.1250602e+00 8.8775200e-01 -9.4808570e-01 1.3919066e+00 9.3881737e-01 3.9851864e-01
+1 7.7516373e-01 1 1 7.9938903e-01 -1.7826126e-01 -3.5858414e-01 1.0242847e+00 -3.1837199e-01 1.4748195e+00 -1.5163477e+00 2.7310254e-02
+1 7.5446659e-01 1 1 -1.2604218e+00 1.0423150e+00 -1.1488610e+00 -7.7462645e-01 -7.4580886e-01 1.2586583e-01 -6.5536584e-01 3.3091665e-01
+1 9.4495759e-01 1 1 -1.4963050e-01 6.6817391e-01 -6.7869280e-01 -3.8681286e-01 1.4525589e-01 1.1352171e+00 -3.0987084e-01 1.0970796e+00
+1 1.1276495e+00 1 1 -1.5657541e+00 -1.1949101e+00 3.3311298e-01 -1.2084733e+00 2.9822851e-01 7.0097667e-01 7.6142503e-01 6.0932575e-01
+1 5.5978226e-01 1 1 1.4929148e+00 1.3473636e+00 3.1171258e-01 -4.1494945e-01 1.4862352e+00 3.4251849e-01 1.5635343e+00 -6.5418325e-01
+1 1.0556146e+00 1 1 -4.8162074e-01 5.4070413e-01 -1.2231662e+00 2.8034647e-01 3.5235651e-01 1.3104857e+00 -1.1023701e+00 7.1635209e-01
+1 2.6973324e-01 1 1 1.2844471e+00 -1.0133066e+00 8.2865791e-01 -6.0584516e-01 1.5363171e-01 -3.7319854e-01 -1.5619907e+00 1.1464769e+00
+1 8.1721626e-01 1 1 -1.3229196e+00 -7.0608838e-02 5.7328843e-01 -5.3778779e-01 -3.0092853e-01 1.4126237e+00 -1.2287366e+00 1.4489920e+00
+1 1.4810543e-01 1 1 -1.2587532e+00 7.9928975e-01 -6.0244495e-03 -2.3736636e-01 2.5831798e-01 9.5082240e-01 1.4539873e+00 -4.1846458e-01
+1 8.9413804e-01 1 1 -3.7953418e-01 2.1267912e-01 -7.2195831e-01 4.0617666e-01 -1.3074764e-01 -8.0980309e-01 -1.2841958e+00 8.9183680e-01
+1 1.2627687e+00 1 1 -1.3978096e+00 -6.3438892e-01 -1.1224044e+00 -6.9758256e-02 -1.5022462e+00 -9.8121678e-01 -7.3755060e-01 5.6249379e-01
+1 7.8740365e-01 1 1 -1.5535876e-01 3.9094244e-01 1.0129898e+00 -6.1294968e-01 7.2792211e-01 -1.0905629e+00 7.1176060e-01 7.8081194e-01
+1 4.8862115e-01 1 1 -4.5123230e-01 1.4993478e+00 1.0298155e+00 -5.6302878e-01 8.2513456e-01 -1.0388875e+00 -6.2434585e-01 6.7373225e-01
+1 7.8526282e-01 1 1 -5.6603903e-02 8.2298596e-01 1.0749285e+00 -3.4764566e-01 1.0465492e+00 3.8929882e-01 -4.6120571e-01 1.1180656e+00
+1 8.2484085e-01 1 1 5.6077717e-01 -5.0746783e-01 -9.7557148e-01 4.8174699e-01 -4.2558762e-01 -9.9219406e-01 -1.1753504e+00 1.4630472e+00
+1 9.6771820e-01 1 1 2.0400747e-01 4.1231925e-01 -4.5783576e-01 8.3745842e-01 5.5541939e-01 -2.3175543e-01 2.2031497e-01 1.8899685e-01
+1 1.1913472e+00 1 1 1.2760152e+00 -5.0378662e-01 -1.0851898e+00 8.2860428e-01 1.2619702e+00 4.6142271e-01 -1.1040037e+00 3.1980420e-01
+1 5.8005114e-01 1 1 1.4763346e+00 -5.4949457e-01 1.3015317e+00 -3.2803150e-01 1.0418691e+00 -1.4607568e+00 -7.4319742e-01 -3.1582864e-01
+1 5.9593954e-01 1 1 4.5616254e-01 9.2722491e-01 -6.5634009e-02 2.6968878e-01 -5.4298643e-01 6.0652348e-01 5.3364373e-02 1.1596256e+00
+1 9.5674016e-01 1 1 1.2376928e+00 1.5694433e+00 -4.1176961e-01 -6.5881551e-01 3.5372928e-01 -6.2810770e-01 1.5411152e+00 -6.1343646e-01
+1 6.2255872e-01 1 1 1.4177822e+00 8.2108592e-01 3.1671427e-01 1.4017520e+00 1.2347784e+00 -8.5471566e-01 -9.0834586e-01 6.8053373e-01
+1 4.4374094e-01 1 1 -3.1416099e-01 -1.0254308e+00 1.1587155e+00 4.4313933e-01 -4.3982168e-01 1.2970801e+00 -1.5701573e+00 -8.0852463e-01
+1 7.1404062e-01 1 1 9.1351892e-01 3.6153613e-01 -2.0086601e-01 -8.7352601e-01 8.4470613e-02 5.1356940e-01 -2.5625069e-01 -1.4852601e+00
+1 6.3169857e-01 1 1 5.4912880e-01 4.9757636e-01 1.2570951e+00 -6.8920515e-01 -3.0229476e-01 -1.5357745e+00 3.1810613e-01 3.2790318e-01
+1 7.1557246e-01 1 1 -7.9151950e-01 -1.5378556e-01 7.8594982e-01 -4.1885286e-01 -7.1272698e-01 -4.3674698e-01 -5.8103871e-01 7.1515823e-01
+1 9.9399162e-01 1 1 -1.5649070e+00 8.5680155e-01 -9.3852165e-01 6.4911962e-01 9.0503325e-02 1.4955165e+00 -1.4475766e+00 -6.9092579e-02
+1 2.0132603e-01 1 1 2.1198763e-02 -7.9706994e-01 2.0333027e-01 -9.9778883e-01 5.5854471e-01 -7.3706674e-01 -9.2668866e-01 1.1503135e+00
+1 1.0583007e+00 1 1 1.2876457e+00 -6.0346971e-01 -6.8092186e-01 -1.5287625e-02 3.8201988e-01 -5.8085349e-01 1.1600052e+00 -4.1870172e-02
+1 1.0702419e+00 1 1 -9.7122016e-01 -1.4543812e+00 5.6826618e-01 6.7148646e-01 -8.0730814e-01 -1.4762987e+00 -5.1632506e-01 4.7772460e-03
+1 4.2455749e-01 1 1 4.1826056e-01 9.4804704e-01 4.0808792e-01 1.0721372e+00 1.1077262e-01 1.4669259e-01 -7.9641695e-01 -1.3902349e+00
+1 5.1961348e-01 1 1 -1.1790611e+00 -3.3137105e-01 6.3696116e-01 -7.6533732e-01 -1.2089450e+00 -6.8782774e-01 9.4664650e-01 1.4881093e+00
+1 7.8868839e-01 1 1 6.8708881e-01 6.9054990e-01 -1.1414776e+00 -1.3439320e+00 1.0823536e+00 7.4016173e-01 1.2624824e+00 4.3399391e-01
+1 8.5726948e-01 1 1 -5.9296577e-01 1.0289322e+00 8.9251745e-01 5.8551459e-01 1.2959332e+00 -8.0869251e-01 2.2435474e-01 -6.4252207e-01
+1 8.4446285e-01 1 1 -8.4384128e-01 -1.2042205e+00 -5.6408666e-01 1.2755629e+00 8.7841223e-02 -1.1651790e+00 8.1887915e-01 -1.2144767e+00
+1 4.2035337e-01 1 1 -1.2911464e+00 -1.1941169e+00 7.2207275e-01 1.5728531e-01 -2.0111909e-01 1.5252321e+00 -4.1551853e-01 -7.8217500e-01
+1 1.0657501e+00 1 1 -1.3164272e+00 -1.0292375e+00 -9.5726569e-02 1.4147657e+00 1.4521394e-01 -8.2029044e-01 1.4050656e-01 1.5500715e+00
+1 4.9809633e-01 1 1 1.0457930e+00 -7.8518007e-01 -3.8100684e-01 -7.4776477e-01 -4.0678671e-01 -1.3128142e+00 -9.8394277e-01 -1.1768904e+00
+1 6.4284592e-01 1 1 -5.6827550e-01 1.3093548e+00 -1.0161329e+00 -1.3119160e+00 -7.5854964e-01 -1.0624020e+00 2.1754180e-01 -5.2968633e-01
+1 6.2451012e-01 1 1 -5.6468421e-01 -5.3107306e-01 -4.4717432e-01 1.4664798e+00 -3.6081211e-01 1.0217880e+00 -5.8881365e-01 8.3541886e-01
+1 4.3780012e-01 1 1 1.0391220e-01 -4.8019202e-01 -9.6912855e-01 1.3324266e+00 -8.9529195e-01 1.2459147e+00 -1.7415089e-01 1.1071499e+00
+1 3.1077380e-01 1 1 -2.7317235e-01 1.6424270e-01 1.0143577e+00 8.2224057e-01 1.0569760e+00 1.3725312e+00 1.0103341e+00 2.1445153e-01
+1 7.9832109e-01 1 1 -1.3407920e+00 -1.0328082e+00 -1.1128994e+00 -4.6877546e-01 -1.1105015e+00 -5.8236293e-01 3.7658996e-01 8.8017380e-01
+1 5.0105114e-01 1 1 -4.7063309e-02 -1.1086205e+00 5.4195674e-01 4.0516610e-01 3.3187811e-03 1.4290190e+00 -9.6174337e-01 -6.7868454e-01
+1 4.7310749e-01 1 1 6.8832101e-01 2.0194239e-01 1.1897857e+00 -1.3462345e+00 -7.6991421e-01 4.5793502e-02 -5.2654454e-01 4.7188350e-01
+1 8.0535779e-01 1 1 1.2670359e+00 1.1256360e+00 4.9109310e-01 -4.1304736e-01 2.7194834e-01 -3.8819383e-02 2.3239485e-01 1.5660760e+00
+1 2.7074456e-01 1 1 1.3568429e+00 -1.0714263e-01 8.3789025e-01 8.3285457e-01 -3.8154555e-01 1.0138951e+00 8.6052369e-01 7.7626426e-01
+1 8.5487587e-01 1 1 -3.6242557e-01 -6.1361974e-01 -1.3384559e+00 -1.1501038e+00 -6.4541822e-01 5.3677092e-01 -1.0709567e+00 -3.6092319e-01
+1 6.0778854e-01 1 1 2.6164993e-01 7.4171099e-01 1.5172762e+00 4.2584533e-01 3.7535302e-01 -1.1452531e+00 -1.3848480e+00 3.7941432e-01
+1 2.1713228e-01 1 1 -6.7936418e-01 9.6921589e-02 5.5311125e-01 6.3435417e-01 2.4020950e-01 2.6926411e-01 9.1999860e-01 -6.1660041e-01
+1 3.6086555e-01 1 1 -1.5260406e+00 -1.5254449e+00 1.6818182e-01 -9.7491455e-01 2.5447007e-01 -1.5131409e+00 -5.0256453e-01 9.1108527e-01
+1 1.0054820e+00 1 1 -2.0119544e-01 3.8514918e-01 -8.0152921e-01 1.1584202e+00 1.1709155e+00 -1.6632193e-01 1.1406583e+00 4.8754246e-01
+1 4.2389323e-01 1 1 -1.1381429e+00 1.5214820e+00 -1.5207091e-01 1.1184949e+00 6.4031426e-01 6.4484226e-01 1.0449059e+00 8.5250015e-01
+1 6.0060973e-01 1 1 3.8995286e-01 -1.0167826e+00 1.4006837e+00 -7.4691770e-01 -1.3346852e+00 -6.3082684e-01 2.3129849e-01 -8.3407670e-01
+1 4.6501354e-01 1 1 5.7537911e-01 1.1982466e+00 1.3366654e+00 3.5845236e-01 -1.0830617e+00 5.6853118e-01 1.2835479e+00 -5.4071293e-01
+1 8.0128141e-01 1 1 5.7448439e-01 1.3214150e+00 -1.9370226e-01 -1.0658614e+00 -6.2947883e-01 -1.4212620e+00 -7.2764120e-01 8.6541423e-01
+1 4.9875735e-01 1 1 1.2449998e+00 1.1036899e+00 -8.6384122e-01 -5.7104779e-01 1.2332926e+00 1.5200484e+00 7.5447008e-01 -5.5706781e-01
+1 9.2028385e-01 1 1 -1.4364733e+00 -1.3885634e+00 -1.2797857e+00 -3.4668084e-02 -2.7977458e-01 2.2431273e-02 9.1067461e-01 -6.9251645e-01
+1 7.4915995e-01 1 1 3.3215577e-01 1.3065934e+00 1.1268062e+00 -1.4718498e+00 7.9286803e-01 1.1291733e-02 -1.3123692e-01 4.7676374e-01
+1 3.8337478e-01 1 1 -6.8189079e-02 1.8211818e-01 7.1168672e-01 -4.7856276e-01 -9.0304821e-01 1.2845954e+00 -3.0085087e-01 -1.2346483e+00
+1 3.9153932e-01 1 1 6.2746919e-01 9.4904745e-01 1.2754916e+00 -7.2708296e-01 -4.9718696e-01 1.1708437e+00 1.5635575e+00 -5.1505346e-01
+1 9.9396011e-01 1 1 -4.5186370e-01 7.7456794e-01 -1.0406800e+00 7.1209378e-01 4.1526282e-01 -5.6709252e-01 -7.1187515e-01 -1.4156762e+00
+1 9.2293906e-01 1 1 -1.2437137e+00 -5.9665312e-01 -1.4618390e+00 -1.3079047e+00 -1.2966693e+00 4.6807893e-01 -1.3007632e+00 1.1522214e+00
+1 4.5168313e-01 1 1 1.0606034e+00 1.4706026e-02 1.2687817e+00 -2.3010807e-01 1.0675898e-01 4.5456877e-01 4.1660061e-01 6.0837230e-01
+1 1.1479277e+00 1 1 1.6422015e-01 -1.0216458e+00 -7.1620000e-01 -1.2573391e-01 4.4879502e-01 -4.1593964e-01 -8.0357620e-01 -9.7079730e-01
+1 4.7564294e-01 1 1 -1.4118947e+00 1.1439674e+00 1.4095905e+00 1.0820378e+00 -6.6081785e-02 -6.5394882e-01 1.5467821e-03 1.2420731e+00
+1 6.7412211e-01 1 1 -1.2644987e+00 1.1346570e-01 2.3778436e-01 -8.7000390e-01 1.4872402e+00 1.5148193e+00 8.6402474e-01 -3.5992736e-01
+1 7.2992641e-01 1 1 4.4429237e-01 7.1280330e-02 3.3580950e-01 -1.1833651e+00 1.5345652e+00 1.0181678e-01 1.2225670e+00 1.4083706e+00
+1 1.0231308e+00 1 1 -3.4379371e-01 1.0617078e+00 -1.4916780e+00 6.0666094e-01 -1.0386361e+00 -9.3336852e-01 -1.4743562e+00 -1.4162744e+00
+1 1.3049789e+00 1 1 -7.5200611e-01 -1.2283647e-01 -7.2197947e-01 -1.4592843e+00 1.4736668e+00 -1.1525276e+00 1.3782518e+00 5.2434891e-01
+1 7.1493534e-01 1 1 -3.3946805e-01 -4.8610591e-01 -1.4780838e+00 2.2246181e-01 -3.9882608e-01 5.2823146e-01 1.3145922e+00 5.6467569e-01
+1 7.2676774e-01 1 1 -3.0724416e-01 1.3005038e+00 1.5607476e+00 4.2031191e-01 1.0888369e+00 -1.5476102e-01 -4.7085208e-01 -2.4701008e-01
+1 9.5787436e-01 1 1 9.2565904e-01 1.5067710e+00 -8.1301409e-01 -1.2595562e+00 3.0457705e-01 1.7027212e-01 6.0965451e-02 -1.4544743e+00
+1 1.2295522e+00 1 1 3.8468996e-01 -7.7934419e-02 -1.5414162e+00 -1.3103176e+00 1.3720093e+00 -2.2743764e-01 4.8713495e-01 -6.1634223e-01
+1 6.2174656e-01 1 1 8.6479179e-02 2.0035828e-01 -1.0096779e+00 5.5920337e-02 6.9654592e-02 7.7388059e-01 2.8665715e-01 -1.0329151e+00
+1 8.2744079e-01 1 1 -1.1018445e+00 -3.6574511e-01 1.2273478e+00 5.1689921e-01 -1.1293284e+00 4.1748977e-01 -1.3564141e+00 2.3743805e-01
+1 9.7679593e-01 1 1 9.8873301e-01 1.0188402e+00 3.3663796e-01 1.0213288e+00 8.7968369e-01 -1.5674249e+00 1.2859641e+00 7.9867305e-01
+1 8.0544929e-01 1 1 -1.3895033e+00 -1.1737541e+00 -1.3415793e-01 -1.8921107e-01 5.0869607e-01 -1.4558518e+00 -9.5906130e-01 -7.2747624e-01
+1 6.7762923e-01 1 1 1.2183704e+00 -1.2254043e+00 8.7116746e-01 -7.7872134e-01 1.3812230e+00 1.3642443e+00 5.6871082e-01 3.8550944e-01
+1 1.0541783e+00 1 1 2.5078168e-01 9.1092751e-01 -1.2519342e+00 -9.4526534e-02 9.8714635e-01 1.5101262e+00 -1.5437107e+00 1.2931809e+00
+1 2.5662833e-01 1 1 -1.1296360e+00 9.7764455e-01 1.1302204e+00 9.3841921e-01 2.1785271e-01 -2.3615438e-01 1.2675255e+00 9.5376855e-01
+1 3.7841250e-01 1 1 -1.1476304e+00 7.4231394e-01 1.5443827e+00 1.2165638e+00 1.4949774e+00 -1.2151612e+00 1.6169272e-01 -1.5592893e+00
+1 5.8813640e-01 1 1 1.1540170e+00 8.0600584e-01 6.0119246e-01 1.3027155e+00 -3.7242517e-01 2.8003600e-01 9.1871310e-02 1.9087394e-01
+1 2.9746942e-01 1 1 -6.2961335e-01 -7.3541367e-03 8.7962990e-01 9.8028332e-01 -1.2971840e+00 4.5920966e-01 1.5591190e+00 4.5228807e-01
+1 1.1613417e+00 1 1 -1.0275064e+00 -1.0788626e+00 -3.9532846e-01 1.1098109e+00 8.8124566e-01 -9.5637308e-01 8.8146478e-02 -1.0486923e+00
+1 8.9621303e-01 1 1 3.5579233e-02 8.2946273e-01 1.8303702e-01 9.5572405e-01 -1.5135208e+00 -1.3743846e+00 -1.3538767e+00 -1.0363009e+00
+1 7.9005814e-01 1 1 1.0775722e+00 1.5335766e+00 6.8402517e-01 -1.0907559e-01 -2.6857206e-01 8.4961880e-01 -4.9723362e-02 -1.1934682e-01
+1 4.1743816e-01 1 1 -5.2489584e-01 1.1959777e+00 1.3235345e+00 1.4567473e+00 5.7802146e-01 1.0045761e+00 -3.6896026e-02 -1.5259064e+00
+1 1.0247692e+00 1 1 -3.3219067e-01 8.8779464e-01 -9.7363949e-01 1.1203559e+00 1.0021709e+00 9.9191651e-01 -1.2177644e+00 -1.0876196e+00
+1 6.7031553e-01 1 1 -5.1836470e-01 -1.4006630e+00 5.9718685e-01 -8.8393484e-01 1.4088721e+00 -1.2914214e+00 5.1032922e-01 1.3043395e+00
+1 9.8418489e-01 1 1 -5.1900238e-01 -9.8853433e-01 -4.6921405e-01 2.9884511e-01 7.2949706e-01 3.4351652e-01 5.5529948e-01 -3.6788074e-04
+1 8.8385339e-01 1 1 1.3297306e+00 -1.5544611e+00 -6.8298415e-01 -7.1689858e-01 -9.7904246e-01 -7.6519605e-01 -7.5349698e-01 1.0021369e-01
+1 9.5289584e-01 1 1 -5.0787234e-01 -3.4329389e-01 4.6489779e-01 -9.0664025e-01 8.9562444e-01 1.0303125e+00 -2.6368150e-01 3.9787248e-01
+1 6.4786606e-01 1 1 -1.0309527e-01 1.3652933e+00 3.9619538e-01 -1.1782737e+00 1.3895264e+00 4.2390765e-03 1.0923037e+00 -1.4079834e+00
+1 6.6994788e-01 1 1 1.4368956e+00 2.9104015e-01 -1.3207105e+00 1.3540755e+00 -8.2994082e-01 -1.0104722e+00 -1.1184651e+00 -1.5016808e+00
+1 2.6180389e-01 1 1 4.8083841e-01 5.2094832e-02 1.3126602e+00 2.5003165e-01 -1.4403952e-01 4.4423542e-01 1.2473915e+00 8.0558083e-01
+1 1.3062996e+00 1 1 1.2749112e+00 -9.4650095e-01 -1.5248912e+00 -1.1689590e+00 1.2957635e+00 -1.3010988e+00 1.0605348e+00 -8.6728540e-01
+1 8.6631878e-01 1 1 -1.3712433e+00 1.1837045e+00 2.6655236e-01 8.2629915e-01 3.7726206e-01 1.0582382e+00 -9.8769318e-01 5.2413777e-01
+1 9.7741658e-01 1 1 2.3784173e-01 -1.1839782e+00 3.4443754e-02 -1.3713423e+00 9.0943334e-01 1.2526293e+00 1.6353432e-02 1.5776062e-01
+1 4.7380018e-01 1 1 1.3000237e+00 -2.7379654e-01 8.4313299e-01 -1.4258063e+00 9.9788847e-01 1.1288204e+00 1.5335770e+00 -2.1438027e-02
+1 3.8600738e-01 1 1 -2.7933791e-01 7.3478309e-01 -1.1883193e+00 5.4177158e-01 -1.4516911e+00 7.0930293e-03 1.2024196e+00 9.7424342e-01
+1 1.1158166e+00 1 1 -1.2927591e+00 -1.0139330e-01 -9.7731486e-01 1.2194667e+00 -9.6298654e-01 -1.6797803e-01 -7.9955323e-01 1.2824794e-01
+1 1.2981010e+00 1 1 -1.4738834e-01 -1.3739866e+00 -1.4843905e+00 -1.7396361e-01 5.7056823e-01 1.0850900e+00 -1.4993265e+00 3.3052032e-01
+1 1.1063760e+00 1 1 1.5606922e+00 1.2554479e+00 -7.6320200e-01 1.0163046e+00 1.3994212e+00 1.6185719e-01 -4.6597888e-01 7.1920622e-01
+1 5.0282341e-01 1 1 1.3969425e+00 1.3763520e+00 -1.3265758e-02 1.9276575e-01 -1.0318255e+00 -2.8537523e-01 2.8342150e-01 -1.1495728e+00
+1 4.7480157e-01 1 1 1.2912619e+00 8.0063688e-01 9.5484161e-02 8.3187394e-01 -2.9893342e-01 9.1044586e-01 8.1063451e-01 -7.5698134e-02
+1 9.9818080e-01 1 1 1.1732672e-01 8.6273735e-01 -5.5155935e-01 1.2179451e+00 -7.6736079e-01 -8.3430559e-01 -7.5311582e-01 8.6494046e-02
+1 7.6538765e-01 1 1 -1.0099334e+00 -1.5650876e+00 7.8186146e-01 -6.1374740e-01 -7.9502490e-01 -1.2460190e+00 -1.4075347e-01 -8.5196410e-01
+1 5.7376371e-01 1 1 7.4651802e-02 1.2877219e-01 -5.3645319e-01 -1.4039458e+00 -7.8988681e-01 1.4686357e-02 -2.4376782e-02 4.1866243e-01
+1 5.3508868e-01 1 1 1.1773654e+00 -2.8309189e-01 2.0207735e-01 3.8545209e-01 7.4289415e-01 -1.3522216e+00 -1.2935252e+00 -7.0812491e-01
+1 1.0741503e+00 1 1 -9.1185283e-01 -1.5541371e+00 2.5241514e-01 3.2918806e-01 1.1328319e+00 -5.0713299e-01 -4.5763844e-01 -1.1023532e+00
+1 6.9265768e-01 1 1 -8.2149467e-01 -1.1807444e+00 1.1911473e+00 3.1897919e-01 1.4542123e+00 -2.4328386e-01 -9.1037853e-01 -1.2778111e+00
+1 2.4834854e-01 1 1 4.3871323e-01 6.6957084e-01 1.3838522e+00 1.5261716e+00 -6.4517697e-01 1.4817809e+00 -1.1756828e+00 -2.4304507e-01
+1 3.4417187e-01 1 1 1.3531525e-01 2.9227068e-01 1.1936950e+00 -7.3816513e-01 1.2885199e+00 8.8732742e-01 9.1665918e-01 -7.8812358e-01
+1 9.3980474e-01 1 1 -2.6971411e-01 -1.2575748e+00 2.2192296e-01 -1.9198102e-01 1.1552174e+00 1.7165586e-01 -7.9564316e-02 -1.0384454e+00
+1 5.9036564e-01 1 1 2.3323456e-01 5.7511522e-01 7.8869075e-01 -2.0931642e-01 6.9586117e-01 1.0379906e+00 1.0810131e+00 1.5361143e+00
+1 4.1055815e-01 1 1 -7.3439912e-01 -7.1902284e-01 1.1460515e+00 6.0276878e-01 -8.1078264e-01 2.4455701e-01 7.5637017e-01 -1.3560365e-01
+1 4.6765269e-01 1 1 2.7150428e-01 1.0901167e+00 5.8229919e-01 -9.0145968e-01 1.4050513e+00 1.0663936e+00 1.4295227e+00 -1.4359003e+00
+1 9.1823838e-01 1 1 -1.5616276e+00 -1.7741155e-01 6.4138036e-01 1.0684722e+00 -6.5517468e-01 9.1755804e-02 -9.1184371e-01 5.3906973e-01
+1 8.9896564e-01 1 1 -1.4097318e+00 -3.8443089e-01 8.7527109e-01 4.6944431e-01 -2.3862110e-01 -3.8219306e-01 -6.6826684e-01 -2.0818390e-01
+1 1.1694066e+00 1 1 5.3020299e-01 1.1261851e+00 -1.3971149e+00 1.4113039e+00 1.3090500e+00 1.0381621e+00 -3.6711877e-01 7.8734506e-01
+1 1.1162576e+00 1 1 1.5648799e+00 -3.0227961e-01 -1.0462457e+00 7.6084106e-01 6.3065888e-01 -1.4990304e-02 -7.7157200e-02 5.2023628e-01
+1 9.1899876e-01 1 1 -4.7682536e-01 -4.5802751e-01 -7.5741231e-01 1.1736173e+00 -2.4977774e-01 -6.1463245e-01 6.9670937e-01 5.5876768e-01
+1 6.7368987e-01 1 1 1.9910653e-01 -1.1662991e+00 -9.5269962e-02 -1.0747096e+00 -8.4671320e-01 -5.7095771e-01 8.7859168e-01 9.8789509e-01
+1 3.8118323e-01 1 1 5.8723712e-01 1.5498197e+00 1.0100093e+00 1.5126761e+00 7.0597138e-01 1.4792435e+00 1.0049411e+00 2.3563729e-01
+1 5.9733461e-01 1 1 -1.1898190e+00 8.7435958e-01 1.2017468e+00 -1.3618174e+00 -5.3449831e-01 -9.1820897e-01 8.4342572e-01 -1.1924154e+00
+1 6.8713918e-01 1 1 -1.0504534e+00 -1.0089596e+00 4.6001974e-01 -1.5628706e+00 -1.4996528e+00 -8.3512248e-01 5.9009800e-01 -7.0673909e-01
+1 9.2498083e-01 1 1 7.8103447e-01 7.3347139e-01 9.2183377e-02 -3.1055365e-01 3.3262376e-01 7.3241592e-01 -2.3100250e-01 1.9796443e-01
+1 8.5443073e-01 1 1 1.2722313e+00 -1.5594799e-01 5.2083968e-01 -1.2898780e+00 1.5141406e+00 9.5433941e-01 5.4945311e-01 2.4156508e-01
+1 3.7943482e-01 1 1 7.1167986e-01 -9.2951590e-01 1.2753265e+00 1.1517405e+00 1.2605082e+00 -1.3896496e+00 1.5175893e+00 1.0465935e+00
+1 9.1744831e-01 1 1 1.1601528e+00 7.6647452e-01 -6.7491567e-01 -1.1919972e+00 -1.5395433e+00 -1.2412165e+00 -4.6793236e-01 3.1982447e-01
+1 7.4974638e-01 1 1 -1.1781692e+00 -1.5341346e+00 9.8336314e-01 3.8885987e-02 -9.4682515e-01 -9.5130760e-01 -1.1328126e+00 2.4877079e-02
+1 1.1422789e+00 1 1 -3.1052159e-02 -1.1498150e+00 -5.3468047e-01 1.0551384e-01 -1.1234864e+00 -1.0617957e+00 -1.1299800e+00 2.7724741e-01
+1 1.3841176e+00 1 1 -3.8925301e-01 -1.0039861e+00 -1.4197401e+00 1.5128625e+00 -1.4643038e+00 -1.3548089e+00 -6.4660746e-01 7.1529908e-01
+1 1.3939595e+00 1 1 -1.3794238e+00 -5.0097047e-01 -1.1753186e+00 -1.3708205e+00 6.8297035e-01 -1.0240059e-02 -7.6266819e-01 -8.4352179e-01
+1 5.1653028e-01 1 1 9.7748624e-01 -3.4231075e-01 7.5533384e-01 1.0602774e+00 -6.9695239e-01 6.8293046e-01 -4.6629855e-01 9.3697196e-01
+1 6.9002837e-01 1 1 1.2233187e+00 -9.6061306e-01 -2.8005816e-01 9.6896960e-01 1.3202311e+00 -1.3673733e+00 1.1939945e+00 -1.1162960e+00
+1 1.0003532e+00 1 1 -1.4058481e+00 -3.7911961e-01 -8.3175589e-01 -5.4419592e-01 5.4551638e-02 -6.9311922e-01 -1.0277085e+00 5.0947417e-03
+1 5.2385678e-01 1 1 -1.7044905e-01 -7.1340677e-01 7.6609955e-01 -1.1246043e+00 -4.9567364e-01 -2.2919793e-01 -2.1955866e-01 8.0432180e-01
+1 1.0631579e+00 1 1 3.9524986e-01 1.2315903e+00 -1.5530831e+00 -1.4023190e+00 7.1691536e-01 -5.3697665e-01 1.2490027e+00 -3.6747752e-02
+1 8.4639361e-01 1 1 -1.5039878e+00 -6.1643523e-01 8.2548184e-01 -5.4727853e-01 1.1886316e+00 8.2918797e-01 -1.3301748e-01 1.2742778e+00
+1 3.2123291e-01 1 1 -2.6829191e-01 5.4559144e-01 6.0020825e-01 4.7302376e-01 -5.6710836e-02 5.7238483e-02 1.1892034e+00 5.4965333e-01
+1 8.6326251e-01 1 1 -9.9660441e-01 -5.5363265e-01 4.6093213e-02 -1.2606033e+00 -1.2364535e+00 6.7983455e-01 1.2927937e-01 -1.4005585e+00
+1 7.3901924e-01 1 1 1.0416940e+00 4.9347390e-01 -1.2847627e+00 -5.8284669e-02 5.6163974e-01 6.8794052e-03 -1.1837358e+00 7.6741432e-01
+1 4.2273933e-01 1 1 -3.4532526e-01 1.1310842e-02 -8.4048502e-01 5.8648362e-01 -1.0067639e+00 -6.1676521e-01 6.5827791e-01 -1.4469689e+00
+1 1.0679774e+00 1 1 -1.3600897e+00 -1.5358384e+00 -1.4312209e+00 -1.2875859e+00 -6.3181169e-02 1.2828489e+00 -1.0125232e+00 -1.3816296e-01
+1 9.7053432e-01 1 1 -7.9986682e-01 -1.5102269e+00 6.4491253e-01 -1.1666958e+00 -2.7598372e-02 9.0295320e-02 5.3004143e-01 -4.6791535e-01
+1 8.0605981e-01 1 1 -4.8661798e-01 -1.4570476e+00 5.5032074e-01 1.1652586e+00 1.1098807e+00 2.0419720e-01 -1.1504392e+00 -8.4686272e-01
+1 4.3795349e-01 1 1 -1.0226402e+00 1.1629339e-01 3.9198816e-01 -1.8797997e-01 -1.0115071e+00 1.3232186e+00 1.0714414e+00 1.3345243e+00
+1 7.0635852e-01 1 1 1.3999182e-01 4.7233473e-01 2.2516165e-01 1.0628890e+00 -1.2420122e+00 9.0960808e-04 1.0686330e-01 1.5207683e+00
+1 1.2717094e+00 1 1 -2.1031665e-01 -2.7490784e-01 -1.3272164e+00 8.8010232e-01 1.3845032e+00 -4.2018021e-01 -9.3947983e-01 -4.4525967e-01
+1 4.1739674e-01 1 1 -5.0014597e-01 9.0672213e-01 -1.2174987e+00 1.2615006e+00 -4.3080209e-01 3.3153039e-01 -1.9277440e-01 -2.0563714e-01
+1 7.8714856e-01 1 1 9.4855320e-01 -5.8712061e-01 -1.3070713e+00 -5.6780158e-01 8.8025956e-01 -1.1541715e+00 -9.7725843e-01 -3.9145105e-01
+1 1.8185953e-01 1 1 -1.2491031e+00 6.4789870e-03 1.2101973e+00 1.1172731e+00 7.6259630e-01 1.1741762e+00 -5.3603509e-01 -6.2279934e-01
+1 8.3291181e-01 1 1 -1.5542098e+00 -1.0634092e+00 1.1147148e+00 7.0904619e-01 -7.4201796e-01 -1.1052349e+00 9.4590756e-01 3.9825809e-01
+1 4.6345006e-01 1 1 7.3942673e-01 -1.9705568e-01 -1.4466128e+00 8.7836703e-01 1.0269214e+00 5.5454743e-01 1.4095062e+00 -1.2102364e+00
+1 8.4581159e-01 1 1 -5.9555351e-01 -6.7609196e-01 -4.3661147e-01 3.7086432e-01 -4.4241225e-01 -8.2682419e-01 -1.1792534e+00 1.3698570e+00
+1 6.3821050e-01 1 1 -3.5361150e-01 6.3111321e-02 6.3144212e-01 1.9681420e-01 5.2717321e-01 -1.1698415e+00 5.9548081e-01 -1.5466173e+00
+1 5.6387365e-01 1 1 7.4486513e-01 -1.1463451e+00 3.4777453e-01 -2.4081215e-01 9.0890892e-01 -1.4398432e+00 -8.6817883e-01 -4.6006095e-01
+1 1.0516900e+00 1 1 -2.9841380e-01 7.6491907e-01 -1.4573738e+00 -9.5846476e-01 -1.5328212e+00 2.4319996e-01 1.2162162e+00 -7.8483120e-01
+1 7.2667050e-01 1 1 -1.4588655e+00 5.9771686e-01 9.1671548e-01 1.1698816e+00 -1.0654851e+00 2.4970752e-01 -1.3970111e+00 8.8964186e-01
+1 5.6803958e-01 1 1 9.7890528e-01 -9.8600162e-01 8.6675031e-01 -1.0288944e+00 -5.3029040e-01 -3.3342631e-01 6.9748307e-01 1.3713662e+00
+1 4.9739771e-01 1 1 -5.9727069e-02 1.7210100e-01 -9.2717190e-02 -1.3015701e+00 1.0752535e-01 7.0537248e-01 1.3158350e+00 -1.3132928e+00
+1 9.9312237e-01 1 1 1.4767971e+00 -9.0535000e-01 -6.7856063e-02 -5.7879818e-01 7.6273320e-01 -1.1753283e+00 1.5680465e+00 3.1774273e-01
+1 1.2284160e+00 1 1 -1.1954256e+00 -1.4842175e+00 -5.8720476e-02 -1.4902361e+00 1.5588582e+00 5.9163184e-01 -6.6334111e-01 -4.0540358e-01
+1 3.9878236e-01 1 1 -1.0333391e+00 -9.9749819e-01 -4.5495083e-01 1.5195632e+00 -1.1526702e+00 4.1551100e-01 7.3829052e-01 4.9647822e-01
+1 1.0608046e+00 1 1 -6.0604433e-01 -1.4137212e+00 2.7786587e-01 1.2918596e+00 1.2730576e+00 -2.6700803e-01 -8.4218805e-01 2.3931592e-01
+1 8.8122437e-01 1 1 -7.4375116e-01 -5.4628783e-01 -1.4566581e+00 7.3715921e-01 -1.1085115e+00 -1.4096995e+00 1.3619584e+00 9.4411440e-01
+1 8.0945214e-01 1 1 1.7149404e-01 1.4157033e+00 3.7907377e-01 -1.0066274e+00 -1.1077516e+00 1.0724505e+00 7.9013795e-01 -4.5372850e-01
+1 6.9158208e-01 1 1 1.4598139e+00 -6.9713575e-01 -5.7059741e-02 -9.0970024e-01 -9.0243991e-01 1.3587277e+00 3.3631048e-01 -1.1695171e+00
+1 9.5137256e-01 1 1 -7.4665014e-01 1.3800069e+00 -8.1730610e-01 7.9957178e-01 3.0168998e-01 -1.0053893e-01 6.4511912e-01 8.7187179e-01
+1 1.1901884e+00 1 1 -1.4277961e+00 -6.0342805e-01 -1.4204990e+00 -1.3305242e+00 -2.6993007e-02 4.1904767e-01 8.8074484e-01 1.1611213e+00
+1 8.0774456e-01 1 1 -1.4842021e+00 -7.5420965e-01 -1.3640830e+00 -2.6407740e-01 -1.2821324e+00 -5.1654924e-01 -5.0606980e-01 -6.0847843e-01
+1 7.9413765e-01 1 1 -7.3876641e-01 3.2473292e-01 1.2003246e+00 7.2151151e-01 -6.1579093e-01 -1.4226258e+00 -1.2238734e+00 -8.1295954e-01
+1 1.0346051e+00 1 1 -8.7291285e-01 8.3968949e-01 -1.4518569e+00 -1.0370498e-01 -1.1918842e+00 5.8935117e-01 1.5078485e+00 -6.2460633e-01
+1 9.3998439e-01 1 1 1.9137527e-01 6.2711104e-01 -6.0850780e-01 6.1426732e-01 -1.2026275e+00 -2.1652860e-01 -8.1810973e-01 1.4440451e+00
+1 1.1112930e+00 1 1 -5.4672951e-01 -1.8805864e-01 -1.3065735e+00 7.1730941e-01 4.4709895e-01 -1.2318244e+00 7.8089327e-01 1.2627033e+00
+1 8.5371057e-01 1 1 2.7562476e-01 -2.5938945e-01 1.5251448e-01 1.5282226e+00 -2.9765647e-01 -1.7699163e-01 -1.1009314e+00 7.9568485e-01
+1 8.0672245e-01 1 1 -1.4238089e+00 9.7212412e-01 -2.2869085e-01 -8.2470876e-01 -1.2968520e+00 3.8988753e-01 6.2587800e-01 -6.8472636e-01
+1 1.0310661e+00 1 1 -4.4478886e-01 -9.3328614e-01 -1.4392188e+00 -1.7341453e-01 1.7855794e-01 -5.2261435e-01 1.0794193e+00 -5.4211004e-01
+1 5.2064322e-01 1 1 1.4242197e+00 2.3190744e-01 1.3138645e+00 8.1998747e-01 8.0234031e-01 3.1371615e-01 -8.9772943e-01 -6.2471705e-01
+1 6.9066264e-01 1 1 1.0663958e+00 -1.0481036e+00 -1.3376868e-01 -6.3751725e-01 1.2179122e+00 1.0349113e+00 9.3104481e-01 -4.1681740e-01
+1 6.7774724e-01 1 1 1.2762862e-01 -5.6669659e-01 1.1301122e+00 1.2201939e+00 -1.1671575e+00 -1.2446518e+00 -2.0284468e-01 3.0150842e-01
+1 9.0607038e-01 1 1 -6.5352331e-01 8.3936291e-01 -2.7303413e-01 -5.1852154e-01 -3.1235396e-01 1.0028195e+00 -5.8258091e-01 6.3049703e-02
+1 6.7765644e-01 1 1 -7.5831026e-01 1.4213863e+00 9.8231107e-01 -1.3533258e-02 -1.3162882e-01 -2.5789055e-01 9.0688797e-01 9.5963194e-01
+1 6.8150929e-01 1 1 5.2078469e-01 5.6937728e-01 6.3269855e-01 -1.2588028e+00 -6.0439694e-01 1.0313954e+00 -9.4152558e-01 -4.0261171e-01
+1 3.6191831e-01 1 1 3.5109120e-01 2.3278042e-01 -5.2665139e-01 -1.2135342e+00 -1.3302931e+00 -6.4557803e-01 -1.8257533e-02 2.9558721e-01
+1 7.7831247e-01 1 1 8.7873918e-01 1.0577298e+00 -1.5633360e+00 -6.4939993e-01 4.7887181e-01 8.3100835e-01 1.0217247e+00 1.0762761e+00
+1 7.2350815e-01 1 1 3.4228562e-01 -1.0074729e+00 1.2929418e+00 -5.7171044e-01 -3.6187068e-01 -7.6357506e-01 1.8089272e-01 -3.1811249e-01
+1 8.6102952e-01 1 1 5.3830221e-01 5.8793077e-01 7.6646637e-02 1.3945324e+00 1.6287044e-01 -4.9249137e-06 -7.9777902e-01 4.7403493e-01
+1 1.0123591e+00 1 1 -5.4152144e-01 1.0435281e+00 1.4703963e-01 -1.5164801e+00 1.0363170e+00 -8.2773025e-02 4.5527720e-02 2.6150457e-02
+1 1.2258889e+00 1 1 -1.5685845e-01 -9.3464971e-01 -1.1383239e+00 2.6044013e-01 3.9007719e-01 5.5931727e-01 -1.3642163e+00 -3.1223670e-01
+1 3.9149068e-01 1 1 -5.2368236e-01 -6.9446246e-01 4.8963377e-01 9.7878078e-01 -4.7659114e-01 8.0010971e-01 -1.0401160e+00 -1.3025523e+00
+1 2.8955654e-01 1 1 1.2131186e+00 -8.1378027e-01 1.4436799e+00 9.8951399e-01 9.9400863e-01 1.4273226e+00 -1.4089150e+00 -1.3781094e+00
+1 4.6669865e-01 1 1 -5.2312294e-02 1.2894838e+00 1.4074568e+00 -8.2986456e-01 -6.8669414e-01 -1.9133791e-01 -1.4509857e+00 1.0779699e+00
+1 5.6239701e-01 1 1 4.3322137e-01 -1.4942573e+00 -1.0661801e+00 1.1377929e+00 9.4300635e-01 1.1746391e+00 1.4664440e+00 -1.2408256e-01
+1 7.1025487e-01 1 1 -1.0601447e+00 -9.1454756e-02 3.5472018e-01 1.0999958e-02 -2.2713197e-01 3.9049844e-01 7.2991574e-01 5.6200444e-01
+1 8.6950419e-01 1 1 1.2608248e+00 -8.4127750e-01 -9.6083997e-01 -4.7766798e-01 -3.7189422e-01 3.2022462e-01 -2.2547570e-01 -1.1604180e+00
+1 1.2320597e+00 1 1 6.3991684e-01 9.5760006e-01 -1.0511100e+00 -1.3965657e+00 1.3432586e+00 4.6699697e-01 -8.0938816e-01 -1.3867136e-01
+1 1.0965672e+00 1 1 1.4106920e+00 5.0415939e-03 -8.2993522e-01 -1.2415794e+00 6.6201061e-01 1.1195562e+00 -2.9064259e-01 4.1224739e-01
+1 6.6638236e-01 1 1 -9.9946611e-02 -8.8933510e-02 -4.9845709e-02 -7.6613261e-01 -1.1088161e+00 1.3831054e+00 3.4660395e-01 1.4301288e+00
+1 4.0907531e-01 1 1 9.4938251e-01 6.9259422e-01 1.0484146e+00 9.9743553e-01 5.4791760e-02 1.2088328e+00 8.5973444e-01 -1.5075739e-01
+1 6.8838603e-01 1 1 1.2277585e-01 8.3019687e-01 -4.8985104e-01 3.6055029e-01 3.9846266e-01 1.7329752e-01 1.3722021e+00 1.4857511e+00
+1 2.5714592e-01 1 1 -5.3261821e-01 1.3058574e+00 1.1879525e+00 -3.6357182e-01 -9.1354600e-01 3.5496827e-01 1.6972061e-01 -1.5004577e+00
+1 4.3384020e-01 1 1 -1.3167651e+00 3.7841491e-01 1.0961780e+00 -1.5394829e-01 -1.0042636e+00 6.7247747e-02 -7.1861571e-02 -6.2771360e-01
+1 6.4443260e-01 1 1 -1.4920511e+00 1.4358218e+00 1.1641335e+00 1.2634053e+00 1.1182567e+00 -7.4047610e-01 -1.4058433e+00 -5.1433787e-01
+1 8.0906479e-01 1 1 -7.1034139e-01 1.2833670e+00 -2.4693992e-01 2.7906339e-02 1.5331168e+00 -1.3332966e+00 -9.0269986e-02 1.1863323e+00
+1 4.0202150e-01 1 1 -6.5572490e-01 -6.2562450e-01 -2.7536741e-01 9.2453911e-01 -2.4925337e-01 2.6407009e-01 2.2160504e-01 -1.0014759e+00
+1 1.0694509e+00 1 1 -6.1408237e-02 3.9690487e-02 -5.3413243e-01 4.1149038e-01 -1.4583338e+00 -8.4442324e-01 -1.4130208e+00 8.4881640e-01
+1 5.5097731e-01 1 1 1.4957420e+00 1.0603682e+00 1.5081030e+00 1.2734508e+00 4.8899159e-01 1.4941647e+00 -1.3424646e+00 8.5029035e-02
+1 7.9622840e-01 1 1 -8.8581796e-02 -6.4617193e-01 3.1826030e-01 -7.8391870e-01 7.5312713e-02 -1.4656567e+00 1.1539750e-01 -3.4167142e-01
+1 6.0240999e-01 1 1 3.2067896e-01 2.7419303e-01 -1.1314042e+00 5.1798462e-01 -2.8106936e-01 -6.3887936e-02 1.1230820e+00 3.5985810e-01
+1 4.9365455e-01 1 1 -1.3217144e+00 -3.5422971e-01 5.5033375e-01 4.1429352e-01 1.0226651e+00 6.6014859e-01 9.5056121e-01 5.6921181e-01
+1 4.6981983e-01 1 1 1.4837566e-01 -2.2063970e-01 6.1049517e-01 1.2619309e+00 2.7818837e-01 -9.8790366e-01 1.0835721e+00 5.9328304e-01
+1 1.1960885e+00 1 1 -6.7490759e-01 -1.2120387e+00 1.5077888e-01 3.7990622e-01 8.2198706e-01 -3.7962031e-01 -2.1685183e-01 -1.0703029e-01
+1 1.2020736e+00 1 1 1.1192078e+00 -6.4800706e-01 -1.1245888e+00 1.3675097e+00 1.5535845e+00 2.9615874e-01 -3.8126887e-01 1.2745838e+00
+1 5.4806530e-01 1 1 -1.3317670e+00 8.4711777e-01 -1.1429725e+00 -1.5548976e-01 1.3179292e+00 1.2572505e+00 8.6317840e-01 -5.9039265e-01
+1 5.3692982e-01 1 1 8.4033778e-01 -1.8954878e-01 8.9970554e-01 4.8864461e-01 -9.3375742e-01 2.5702444e-01 -4.3558152e-01 1.5619194e+00
+1 8.3231315e-01 1 1 -1.0434380e+00 -1.7138303e-01 8.6552968e-01 5.2674318e-01 -1.4056698e+00 1.1989939e-01 -9.0777009e-01 3.1312253e-02
+1 2.7257109e-01 1 1 -6.9298215e-01 4.0591689e-01 1.3833345e+00 -3.5455010e-02 -3.1583770e-01 1.3881561e+00 -1.3180520e+00 -1.5225380e+00
+1 1.1279028e+00 1 1 -1.0670131e+00 -1.2940032e+00 -1.2243803e+00 1.0102553e+00 1.0074304e+00 1.2721068e+00 -1.1299500e+00 -1.0242346e+00
+1 5.1129020e-01 1 1 -1.0783565e+00 9.3475078e-01 -7.2828111e-01 -9.4763091e-01 -1.3011581e+00 -1.3813602e+00 -1.4222433e-01 -1.5246311e+00
+1 8.9943106e-01 1 1 -8.9793757e-02 -7.4849447e-01 -5.7566388e-01 1.0419839e+00 6.1814685e-02 -1.5080641e-01 3.8773896e-01 1.4960589e+00
+1 5.1369377e-01 1 1 -1.1992071e+00 -1.0095007e+00 9.2256866e-01 1.3852943e+00 -9.4774936e-01 6.6197945e-01 1.0654777e+00 -1.0448871e+00
+1 8.9686638e-01 1 1 1.3854710e+00 1.0644776e+00 -1.2899314e+00 2.9898048e-01 -9.4867481e-01 1.5090186e+00 4.0484618e-01 8.4672445e-02
+1 6.8502168e-01 1 1 1.2575906e-01 -6.9538856e-01 2.5393651e-01 1.5583577e+00 -7.9478696e-01 -1.6407497e-03 -4.3989048e-01 -5.1680926e-02
+1 9.2762615e-01 1 1 -6.5933359e-01 -6.7080917e-01 -1.5134891e+00 -1.4059683e-01 6.7442353e-02 6.9825417e-01 -1.0717209e+00 -1.5217532e+00
+1 7.9725603e-01 1 1 -1.0223226e+00 8.8634887e-01 2.6401267e-01 -5.3328812e-01 -6.1132335e-01 -1.4322551e+00 1.4791465e+00 -3.9995596e-01
+1 7.2054721e-01 1 1 -8.0620816e-01 -5.6692481e-01 1.3320947e+00 -9.6649343e-03 -1.5035536e+00 -1.0284267e+00 5.9206788e-01 9.4841934e-01
+1 5.2387300e-01 1 1 -2.5144726e-01 1.4521942e-01 1.5264527e+00 9.2426660e-01 7.4658830e-01 2.7446525e-01 1.4608548e+00 -3.5726974e-01
+1 3.9046236e-01 1 1 -6.3193070e-01 -3.1478116e-01 8.4498007e-01 -1.0270079e+00 3.8849243e-01 1.0794249e+00 1.0405528e+00 -1.0488937e+00
+1 1.0906284e+00 1 1 8.6557023e-01 -8.4982022e-02 -1.5603169e+00 -1.0124899e+00 1.1628020e+00 -8.0279800e-01 -6.7599907e-01 -1.2793173e+00
+1 8.9628112e-01 1 1 -1.0767730e+00 1.1318077e+00 -1.3719456e+00 1.0890575e+00 -6.3401277e-01 5.1446969e-01 -1.5174113e+00 -4.2503140e-01
+1 3.8701449e-01 1 1 1.3921704e+00 -5.0851772e-02 1.0006536e+00 8.7007997e-01 4.2970826e-01 1.0291277e+00 3.1671654e-01 4.7894056e-01
+1 7.4353931e-01 1 1 -3.7417562e-01 -1.5252962e-01 1.0396538e+00 -6.7966528e-01 -4.1482234e-01 -1.0596024e+00 1.1969241e+00 7.9353404e-01
+1 6.3085290e-01 1 1 6.9890075e-01 -2.5787339e-02 -7.7696431e-02 -3.0343055e-01 -7.2500632e-01 9.5182420e-01 1.0863160e+00 8.6577171e-01
+1 7.4509275e-01 1 1 9.9967900e-03 1.3197917e-01 1.0586218e+00 -9.5232956e-01 1.0566386e+00 3.1956755e-01 -1.2226561e+00 -8.3198630e-01
+1 5.4071279e-01 1 1 1.5116387e+00 2.0954177e-01 1.4167164e+00 6.1166293e-01 -4.9753270e-01 -1.1515456e+00 -2.3622873e-02 3.5075165e-02
+1 4.2139968e-01 1 1 5.1704704e-02 4.3085329e-02 6.2241738e-01 9.2778530e-01 8.8751870e-01 1.3254282e+00 -1.1889476e+00 -1.1111285e+00
+1 4.9636934e-01 1 1 -1.2201981e+00 1.5688074e+00 -5.3456158e-01 1.5631857e+00 2.4487258e-01 -5.6233605e-01 1.0282357e+00 -1.1105948e+00
+1 6.6722559e-01 1 1 4.4773481e-01 -4.4192480e-01 5.7844229e-01 -6.7803477e-01 8.7148368e-02 -1.2713074e+00 -3.4372342e-01 -1.5644389e+00
+1 1.0151769e+00 1 1 9.6451829e-01 -7.0515291e-01 -1.3496625e+00 -1.1738816e+00 7.2045276e-01 -8.9217112e-01 4.2931358e-01 -1.5364169e+00
+1 1.1724333e+00 1 1 4.0736318e-02 -1.4175299e+00 -1.4785601e+00 -2.2661633e-01 9.5140859e-01 1.0169028e-01 -7.6493669e-01 1.3333068e+00
+1 7.0941912e-01 1 1 -2.1190005e-01 1.4132075e+00 -1.6202448e-01 -1.1303992e+00 -3.8243971e-01 8.2065056e-02 -8.9374752e-01 -9.3655762e-02
+1 4.4672819e-01 1 1 1.1618675e+00 1.3387970e+00 6.1531588e-01 -1.4081897e+00 3.4292852e-02 1.0821896e-01 -1.2601405e+00 -1.3446680e-01
+1 5.8616218e-01 1 1 -6.3308229e-01 1.0742419e+00 -5.0902987e-01 1.3151920e+00 1.4485002e+00 -1.4605327e-01 1.4361455e+00 -1.1784719e+00
+1 8.2850731e-01 1 1 3.6020391e-01 5.0742107e-02 -7.0826130e-01 1.8551708e-01 7.4086196e-01 -1.1333921e+00 4.4168750e-01 1.1642660e+00
+1 1.0388991e+00 1 1 9.7988596e-02 1.4509872e+00 -2.5310491e-01 1.5255933e+00 1.5353465e+00 -1.4447829e+00 -1.4167749e-01 -1.1622050e+00
+1 4.6987709e-01 1 1 6.9978011e-01 -1.4420043e+00 -2.1784383e-01 -1.0328310e+00 -4.7407992e-01 -1.0966489e+00 1.5365576e-01 1.2440349e+00
+1 8.3041144e-01 1 1 -9.1861116e-01 -1.5198334e+00 -1.3457573e+00 -1.4919851e+00 -7.8228259e-01 3.4617621e-01 1.0311398e-01 1.1959870e+00
+1 6.9915805e-01 1 1 -1.3114678e+00 4.5069730e-01 1.3238133e+00 3.9925725e-01 -2.5827265e-01 -4.5978308e-02 -1.1224982e+00 1.0436041e+00
+1 9.2987932e-01 1 1 -4.2594056e-01 4.8967183e-01 5.7053490e-01 -1.2529490e-01 8.9265778e-01 7.4376716e-02 -5.6347177e-01 3.4280618e-01
+1 4.9273822e-01 1 1 9.0665676e-01 -1.0582505e+00 8.3924958e-01 -9.6434802e-01 -1.3472444e+00 -3.0440651e-01 -1.5097298e+00 -1.3739284e-01
+1 8.8194796e-01 1 1 1.4557901e+00 -1.4605147e+00 -4.8338903e-01 -3.2071564e-01 1.4640430e+00 1.4941527e+00 6.1486371e-01 -9.0837074e-02
+1 2.3682480e-01 1 1 7.4141319e-01 1.5352541e+00 -1.6087792e-01 7.0516413e-01 1.2178056e+00 1.4744433e+00 1.3161935e+00 1.1532674e-01
+1 7.4276423e-01 1 1 1.3750251e+00 1.1144582e+00 1.0360528e+00 -1.5356259e+00 1.8229401e-01 8.6362398e-02 1.3110029e+00 -6.6130203e-02
+1 8.5569004e-01 1 1 4.9049759e-01 5.2340082e-01 -9.0802786e-01 -1.0814292e+00 7.6257349e-01 7.7020650e-02 -1.1045100e+00 6.7347550e-01
+1 4.9623902e-01 1 1 2.5380765e-01 3.3807562e-01 6.3280820e-01 -1.4670076e+00 -1.1254072e+00 1.4988346e-01 1.7163337e-01 -5.5627884e-02
+1 6.9007078e-01 1 1 -5.3769022e-01 -1.1040849e+00 1.3162624e+00 -7.7701249e-01 8.1099809e-01 -4.6604738e-01 6.5991227e-01 1.2567727e+00
+1 6.0994311e-01 1 1 1.4025058e+00 1.0323514e+00 -6.7309508e-01 3.5171956e-01 -9.2555460e-01 -8.6790174e-01 1.3234796e+00 -1.4901628e+00
+1 8.8478819e-01 1 1 5.4540575e-01 -2.8583793e-01 1.6611475e-01 -1.1267622e+00 1.3706686e+00 -4.0977242e-01 1.2453407e+00 -3.9020753e-01
+1 8.9342078e-01 1 1 -5.3292603e-01 -5.8290251e-01 -9.8524878e-01 2.8094883e-02 -4.7192462e-01 -6.7400142e-01 1.1502256e+00 1.4275323e+00
+1 1.0754808e+00 1 1 -2.0705979e-01 -1.3565868e+00 2.5860699e-01 9.5180223e-01 8.8434406e-01 6.4125979e-01 -1.5188517e+00 1.9253890e-01
+1 8.3494915e-01 1 1 8.3079045e-01 1.5244893e+00 -1.5566206e+00 -4.9659391e-02 2.9576499e-01 -1.1511375e+00 1.2410833e+00 1.6081788e-01
+1 5.9653233e-01 1 1 -1.2841816e+00 -7.3827532e-01 1.0619180e+00 1.0382559e+00 9.2260155e-01 -1.2396752e+00 -1.2875349e+00 1.0965031e+00
+1 6.5457476e-01 1 1 -4.9930001e-01 1.0977481e+00 2.6868698e-01 1.5606599e+00 -7.3711135e-01 -1.7866143e-01 -3.0911660e-01 3.4477923e-01
+1 4.8655360e-01 1 1 -5.4120988e-01 -7.2179615e-01 1.3534311e+00 8.5442455e-01 -1.3305929e+00 5.9999845e-01 8.7155937e-01 -1.5338721e+00
+1 1.0840314e+00 1 1 -1.2037433e+00 -1.5387201e+00 -1.1562736e+00 9.3387176e-02 -1.4190395e+00 -3.3844745e-01 -9.4814222e-01 1.2018683e-01
+1 8.9292078e-01 1 1 5.4340756e-01 3.2176274e-01 4.0095240e-01 -1.2380639e+00 1.1737116e+00 1.1379991e+00 -1.2683255e+00 -6.4098981e-02
+1 7.6442400e-01 1 1 4.4109491e-01 1.1853790e+00 9.0814397e-02 -1.3717220e+00 5.1077549e-01 3.3424457e-01 -1.0410642e+00 2.5470875e-01
+1 1.2891885e+00 1 1 -6.7656098e-01 -1.3149673e+00 -4.9645392e-01 -1.5247126e+00 -1.3690106e+00 4.8084807e-01 1.5048482e+00 -1.1007839e+00
+1 7.9526345e-01 1 1 -1.5365032e+00 4.4870725e-01 1.6900477e-01 1.2667127e-01 6.3197777e-02 1.4371625e+00 -9.7881946e-01 -3.5916947e-02
+1 1.0803636e+00 1 1 -1.1768605e-01 -1.5411455e+00 4.6346894e-01 -1.0358099e+00 3.0671299e-01 -1.3151220e+00 1.5019914e+00 -4.7033229e-01
+1 4.9234267e-01 1 1 1.2539949e+00 3.9860270e-01 1.5142852e+00 -1.2926635e+00 -4.2824624e-01 9.9031966e-01 1.2724568e+00 -6.2761333e-01
+1 1.2814436e-01 1 1 -1.0533324e+00 1.4400207e+00 5.4980918e-01 1.4591189e+00 -1.4580047e-01 1.4461048e-01 1.3606565e+00 1.1709224e+00
+1 6.6295642e-01 1 1 -4.8381969e-01 -4.0203784e-01 1.2188949e+00 1.3924559e-01 -2.6256332e-02 -1.1244273e+00 9.0167023e-01 7.5616945e-01
+1 9.8693247e-01 1 1 -1.1157406e+00 5.1587665e-01 -3.5936373e-01 -1.8595866e-01 -1.4671928e+00 -1.5702542e+00 -6.7139208e-01 1.1976198e+00
+1 5.7359495e-01 1 1 -8.5964344e-02 -4.5683678e-01 1.4565246e+00 4.7749439e-01 -7.4829042e-01 1.2582306e+00 5.1413472e-01 2.1214845e-01
+1 5.5210504e-01 1 1 3.2989027e-01 -3.3709473e-03 5.1875892e-01 -1.5209344e+00 -7.2166170e-01 1.0211759e+00 -1.4590993e+00 -1.2864103e-01
+1 2.2453752e-01 1 1 -4.4518499e-01 -1.0684304e-01 8.6151926e-01 7.9420628e-01 7.2107075e-01 3.8215192e-01 1.9086302e-01 -6.5410501e-01
+1 9.1475512e-01 1 1 1.0495919e+00 1.2800380e+00 -4.6278617e-02 -4.0230844e-01 -1.2283919e+00 1.4119629e+00 2.6871955e-01 -1.1101416e+00
+1 6.5865329e-01 1 1 4.4785774e-01 -2.7440030e-02 1.3102638e+00 -8.9063365e-01 9.6407779e-01 -7.3024558e-01 -1.2407261e+00 -2.3056357e-01
+1 1.0187188e+00 1 1 -1.1100656e-01 6.2953980e-01 -9.6001863e-01 8.0930314e-01 -1.0794266e+00 9.6499514e-01 1.0078219e+00 -1.4982359e+00
+1 4.5630735e-01 1 1 4.1878826e-01 -2.0859377e-01 1.8679300e-01 -1.1383938e+00 7.7550614e-01 -1.3694787e+00 -1.0049145e+00 -9.8518844e-01
+1 3.6497653e-01 1 1 1.4067240e+00 1.8194116e-01 9.7891560e-01 -6.8521947e-01 -5.3628755e-01 -1.5201400e+00 -3.9554412e-01 1.2726841e+00
+1 9.0075922e-01 1 1 -8.1549640e-01 1.1153599e+00 1.1380984e-01 5.9503879e-01 -1.5547479e-01 -1.5611269e+00 -2.9997563e-01 -1.1025530e+00
+1 2.5467425e-01 1 1 7.2081767e-01 -3.0325118e-02 -4.2792319e-01 1.1275081e+00 7.4027067e-01 7.2283631e-01 5.6573639e-01 -1.4956255e+00
+1 1.2426849e+00 1 1 8.0136881e-01 -7.3624508e-01 -9.9950317e-01 -5.8525924e-02 1.0222473e+00 1.7100406e-01 -1.2694964e+00 -1.0946353e+00
+1 6.5480475e-01 1 1 5.9781757e-01 6.6245869e-01 -5.5383431e-01 -3.2670781e-01 -4.5998677e-01 -4.9196402e-01 1.2721346e+00 -3.6835073e-01
+1 7.6747796e-01 1 1 7.0656106e-01 1.3875794e-01 2.4583513e-01 5.2576069e-01 4.6189062e-01 2.3256163e-01 -9.1267775e-01 1.2083432e+00
+1 8.0691845e-01 1 1 -4.8445128e-02 1.0428761e+00 5.5667061e-01 -8.4029836e-01 1.2022054e-01 5.2202667e-01 1.0220054e+00 1.3690378e+00
+1 1.2013921e-01 1 1 -5.4477501e-01 6.7278386e-01 2.9998908e-01 -1.4355278e+00 5.0261287e-01 -7.6598643e-01 -1.3842916e+00 3.9360900e-01
+1 3.6601846e-01 1 1 -1.4325965e+00 8.8644974e-01 -3.3977943e-01 5.1513803e-01 -3.2812294e-01 3.1274984e-01 8.4556051e-01 -8.0758995e-01
+1 3.5327557e-01 1 1 -4.8272871e-01 1.1283916e+00 7.4256655e-01 -3.0450209e-01 -1.2670644e+00 5.0197849e-01 -1.2297536e+00 -1.4841007e+00
+1 8.9994413e-01 1 1 1.5124451e+00 -9.1654384e-01 -1.2315736e+00 -1.1213326e-01 1.3051998e+00 -1.5654646e+00 6.9966387e-02 9.6513100e-01
+1 4.5880505e-01 1 1 1.0381291e+00 -1.1235193e+00 8.9606619e-01 3.3184800e-01 -1.2492741e+00 7.5647413e-02 9.6941169e-01 9.1376845e-01
+1 4.1208922e-01 1 1 -5.6901513e-01 1.1253048e+00 -6.1073377e-01 1.0423522e+00 -1.2864503e+00 -9.3895908e-01 6.0279166e-01 -1.5401823e+00
+1 1.1135889e+00 1 1 -4.2921637e-01 6.0963359e-01 -1.0192707e+00 1.2924445e+00 -9.2967487e-01 -8.6539604e-01 -5.1693946e-01 8.8000059e-01
+1 1.7617354e-01 1 1 -7.4288144e-01 1.3781221e+00 2.2265329e-01 1.1438201e+00 1.2363905e+00 8.6271209e-01 1.4437945e+00 -4.4834690e-01
+1 5.9498543e-01 1 1 -9.1911940e-01 -8.6462625e-01 4.9697085e-01 7.7914544e-01 1.5207582e+00 1.1519568e+00 1.9183373e-01 1.3144427e+00
+1 4.6640069e-01 1 1 -4.2862509e-01 1.2342828e+00 -9.0572542e-01 9.3921370e-01 -6.1547730e-01 -6.9742856e-01 8.7538955e-01 1.5809429e-01
+1 1.2540745e+00 1 1 -2.2988062e-01 6.5498787e-01 -1.5106651e+00 -1.1384743e+00 9.3756545e-01 -3.9963977e-01 5.9378966e-01 -6.9673553e-01
+1 3.6589194e-01 1 1 5.5542751e-01 2.4054305e-01 6.0386936e-01 1.1035327e+00 -5.6626672e-01 -2.0499276e-02 -1.0169682e+00 -1.3183103e+00
+1 1.0362902e+00 1 1 1.3983558e+00 -4.2267148e-01 -1.2534759e+00 -8.8835596e-01 -1.3606442e+00 1.0438538e+00 1.2210185e+00 8.1151784e-01
+1 1.9478248e-01 1 1 -8.8756042e-02 -6.9857287e-01 3.5172242e-01 1.3912831e+00 -6.9371115e-01 1.3975711e+00 7.7536664e-01 1.5266479e+00
+1 8.6619835e-01 1 1 5.3370717e-01 -7.8253693e-01 -1.0787187e+00 4.2038257e-01 -7.5296797e-01 -7.1111686e-01 2.6078653e-01 9.8396773e-01
+1 8.1929989e-01 1 1 7.6930475e-01 -1.3912988e+00 1.0612586e-01 -7.2040549e-02 -7.9745886e-01 -1.1226942e+00 5.1749082e-01 2.0186775e-01
+1 1.0910539e+00 1 1 -1.0904213e+00 -6.8491694e-01 -7.6727862e-01 -1.2723303e+00 -8.5683317e-01 -7.1620370e-01 1.5398126e+00 -1.2875707e-01
+1 7.1066220e-01 1 1 1.3402253e+00 -6.0359864e-01 5.8606632e-01 7.6545336e-01 2.6559164e-01 1.3474093e+00 -8.1033657e-01 5.3727503e-01
+1 3.8556795e-01 1 1 -5.2232205e-02 -4.7961494e-01 1.1236503e+00 1.5269952e-01 -4.0444275e-01 1.3088594e+00 -5.2257809e-01 1.0441115e+00
+1 3.3446791e-01 1 1 -1.3623169e+00 4.3850119e-01 1.0776403e+00 -2.6033880e-01 9.3713501e-01 5.6872771e-01 9.2303773e-01 -5.5397755e-01
+1 8.4845040e-01 1 1 -5.3314356e-01 -2.8686852e-01 6.1937085e-01 7.2430524e-01 -1.5174659e+00 -1.2597770e+00 3.1066662e-01 9.7996581e-01
+1 8.2074219e-01 1 1 -7.2161790e-01 9.4556507e-01 -1.4722043e+00 -2.7332099e-01 -6.0043759e-01 1.2624282e+00 4.6840101e-02 -1.0848934e+00
+1 4.8876762e-01 1 1 1.4571151e+00 -1.2050501e+00 -1.5365835e-01 -6.9741291e-01 -7.5894761e-01 -6.8571826e-01 -1.2981794e+00 1.1522184e-03
+1 7.1705457e-01 1 1 1.0185564e+00 5.7023672e-01 -1.4675637e-01 -1.3660522e-01 -7.6637073e-01 -1.5049266e+00 -1.3952304e-01 5.1577903e-01
+1 8.6598490e-01 1 1 3.3866596e-01 -1.0305585e+00 -3.8412780e-01 5.8035406e-01 1.3695919e-01 -3.3822193e-01 -1.3356200e+00 1.0439986e+00
+1 8.2324158e-01 1 1 -6.0709042e-01 -9.9709324e-01 -6.3109137e-02 -6.3458340e-01 -9.1423281e-01 -1.3548382e+00 -1.0864094e+00 6.8878987e-01
+1 6.7769817e-01 1 1 5.2423895e-01 -8.9090587e-01 1.1830539e+00 2.6380585e-01 1.8779839e-02 -5.0178864e-01 -3.4579006e-01 -2.7762227e-01
+1 1.0737874e+00 1 1 -1.2833523e+00 -6.2440068e-01 4.4747713e-01 9.9761371e-01 1.4734810e+00 -1.5270561e+00 2.5282266e-01 -7.3247728e-01
+1 4.6513067e-01 1 1 8.7380834e-01 -1.3827118e+00 -2.2466518e-01 2.1366182e-01 -3.8038148e-01 -1.5608996e+00 -1.3843565e+00 1.1560388e+00
+1 5.2378812e-01 1 1 -8.4885946e-01 -8.7615083e-01 2.4661824e-01 1.7382289e-01 6.9505351e-02 1.4009489e+00 -2.4461420e-01 -1.2064762e+00
+1 3.5324119e-01 1 1 -8.0865681e-01 -8.2228710e-01 1.1520346e+00 -2.3990845e-01 -4.9603013e-01 -4.8872598e-01 1.1139108e+00 -1.4065749e+00
+1 8.1397656e-01 1 1 -5.6512681e-01 -3.1324706e-01 6.1024508e-01 -1.4778915e+00 1.0085040e+00 1.2472813e+00 7.4735406e-01 1.8104248e-01
+1 1.1869947e+00 1 1 -1.0517547e+00 5.6593261e-01 -9.1089504e-01 -1.4902697e+00 1.0347587e+00 -7.9177130e-01 6.9232525e-01 -1.4222751e+00
+1 8.3795079e-01 1 1 9.0095101e-01 -1.1132484e+00 -4.3185646e-01 9.5575264e-01 -6.6665024e-01 4.8631837e-01 -5.4872652e-01 2.0110997e-01
+1 2.9659816e-01 1 1 -1.9293191e-01 9.5938302e-01 -1.1324331e+00 3.7131038e-01 -1.4711243e+00 -8.7131264e-01 1.2694876e+00 -2.9841718e-01
+1 1.2020413e+00 1 1 -4.8300110e-01 -1.4446896e+00 -1.0355240e+00 1.4105808e+00 -8.5139604e-01 -1.1881059e+00 -1.4189452e+00 -1.5157358e+00
+1 9.1393510e-01 1 1 7.5987484e-02 4.7189563e-01 3.7061158e-01 1.1730877e+00 5.4129125e-01 -5.3361724e-01 -3.8207627e-01 2.0323356e-01
+1 8.7267749e-01 1 1 -1.5065644e+00 -1.3716636e+00 -9.0933808e-01 -5.5005416e-01 -5.7020739e-01 7.4214814e-01 -1.4040796e-01 8.3528052e-01
+1 1.5844158e-01 1 1 4.0936659e-01 -5.4382828e-01 6.0316041e-01 9.4690716e-01 1.5235332e+00 1.1609517e+00 -5.0046828e-01 -1.2179202e+00
+1 7.6635748e-01 1 1 1.3638460e-01 -1.2288626e+00 -6.0243767e-01 -6.3967045e-01 -1.0994415e+00 -3.1615630e-01 -1.3267727e+00 1.0331570e+00
+1 8.4592741e-01 1 1 -1.1466929e+00 -6.6282859e-01 1.8313446e-01 -4.1117465e-01 5.3499487e-01 -1.2057880e+00 -4.3538858e-02 6.8637508e-01
+1 6.5725437e-01 1 1 1.2025315e+00 -7.2585310e-02 -8.1988358e-01 8.9152747e-01 4.2065289e-01 7.3520928e-01 2.3350073e-01 -2.2327950e-02
+1 8.9220509e-01 1 1 1.0813479e+00 -1.0033578e+00 -7.5791249e-01 -1.4947922e+00 1.3296506e+00 7.7837989e-01 5.9753800e-01 -1.4163351e+00
+1 7.0081563e-01 1 1 1.0054577e-01 6.3492410e-01 9.2292568e-01 3.4365392e-01 1.2898542e+00 6.3897062e-01 -8.5047247e-01 -4.9636678e-01
+1 5.3042862e-01 1 1 -3.0405303e-01 -8.2081403e-01 1.5689978e+00 1.5440890e+00 -1.5510130e+00 1.2155636e+00 3.5583336e-01 -1.5079491e+00
+1 9.1334660e-01 1 1 1.1518897e+00 -6.8799016e-01 -3.8318998e-01 -1.1935016e+00 1.0596053e+00 2.0024332e-01 -1.1010614e+00 -8.7327276e-01
+1 7.0360606e-01 1 1 1.3161004e+00 1.1519780e+00 -9.0378999e-03 -1.1177616e-01 -9.0228086e-01 8.4380492e-01 -1.5589217e+00 4.2552808e-01
+1 6.9376224e-01 1 1 -2.5424689e-01 -3.4182296e-01 -1.1035354e+00 5.0413875e-02 -1.6675072e-01 6.8000532e-01 8.5681331e-02 -1.5559735e+00
+1 7.0335517e-01 1 1 -5.6142595e-01 9.5448064e-01 8.4291869e-01 -9.2401544e-01 -2.7874544e-01 -2.6461731e-01 1.1966921e+00 -6.2972691e-01
+1 5.4573493e-01 1 1 1.4583786e+00 9.8410322e-01 1.4932252e+00 -1.0350113e+00 -7.5989177e-01 1.0719908e+00 3.2763099e-01 2.0540157e-01
+1 7.1765404e-01 1 1 2.6391961e-01 -6.6247708e-01 -1.5470690e+00 -4.3576478e-01 -9.2683106e-01 -8.4167600e-02 -7.1790631e-01 -4.2609592e-01
+1 5.8656171e-01 1 1 -2.3192576e-01 -4.4794278e-01 1.3744073e+00 -8.4615026e-01 -1.2332945e+00 -8.8815511e-01 1.0060033e+00 1.4371065e+00
+1 8.9986403e-01 1 1 7.4029561e-01 -1.3183495e+00 -4.6765565e-01 7.4249561e-01 2.4783572e-01 -1.5161692e+00 -1.5356356e-01 8.8539311e-01
+1 3.5308211e-01 1 1 1.4414110e+00 1.5368559e-01 3.7627576e-01 7.1763506e-01 -3.7687969e-01 -7.9804989e-01 1.4464738e+00 -9.2241132e-01
+1 5.6994915e-01 1 1 9.7324633e-01 6.0452206e-01 4.0663105e-02 7.1833438e-01 -7.6612247e-01 -1.3653837e+00 1.2404962e+00 7.9269900e-01
+1 4.2484233e-01 1 1 -9.2187796e-01 2.9157538e-01 -1.4423943e+00 -9.4586340e-02 1.1678499e+00 1.3305187e+00 1.4111552e+00 -6.0229265e-01
+1 3.0935652e-01 1 1 3.3211792e-01 -3.7706372e-01 1.3499062e+00 -6.6732735e-02 -6.1833976e-01 1.7052286e-01 1.4026466e+00 -5.2099976e-01
+1 9.2080923e-01 1 1 -7.0418784e-01 -7.1760765e-01 -7.0833780e-01 -2.8503034e-02 -4.7879042e-02 8.4525137e-01 -2.3042493e-01 -8.2419518e-01
+1 9.6739209e-01 1 1 -9.0552089e-01 -2.5764281e-01 -1.5388959e+00 -1.5284145e+00 -4.5533899e-01 -1.4212763e-01 8.3189915e-01 -9.6646459e-01
+1 9.1028906e-01 1 1 -1.2148599e+00 -1.0881088e+00 5.0902349e-01 7.4138667e-01 3.7312372e-02 -1.1287093e+00 -1.4998368e+00 -1.3364191e+00
+1 9.4189569e-01 1 1 -9.3886133e-01 -6.3408757e-01 6.0101165e-01 9.2938089e-01 -1.2095028e+00 -1.2807175e+00 3.8167950e-01 1.1922607e+00
+1 4.2639074e-01 1 1 7.7745119e-01 -8.2751232e-01 9.8248257e-01 1.0593493e-01 1.1326224e+00 1.1744771e+00 -2.4489076e-01 1.2470975e+00
+1 7.9392089e-01 1 1 7.3827474e-01 -1.6890200e-01 3.7361840e-01 -8.3464358e-01 1.0754742e+00 8.0974003e-01 -3.9264513e-01 -7.3779810e-01
+1 7.3411537e-01 1 1 -1.1074355e+00 1.2638110e+00 -6.3933795e-01 -6.4337689e-01 -1.2291770e+00 -7.8691005e-02 1.2995358e+00 -3.0649221e-01
+1 8.8633370e-01 1 1 1.2687835e+00 5.6279397e-01 -1.1060682e+00 1.2645969e-01 3.3593896e-01 5.0785958e-02 9.4571039e-01 9.9746184e-01
+1 1.2693467e+00 1 1 -6.8708868e-01 -4.5716511e-01 -8.8460231e-01 -1.4502979e+00 6.8417199e-01 -9.5360222e-01 1.2373012e+00 8.0282599e-01
+1 6.0546336e-01 1 1 5.9510486e-01 7.6162090e-01 -1.4946358e+00 4.6085747e-01 6.4951965e-01 1.2132686e+00 1.1189078e+00 -4.3967805e-02
+1 6.7499250e-01 1 1 -9.0355161e-01 -1.4275885e+00 -1.6973231e-01 -1.5359322e+00 -5.5763592e-01 -6.7307110e-01 -9.0986965e-02 -6.9261945e-01
+1 6.4405194e-01 1 1 4.6699047e-01 -1.1367144e+00 -1.2476278e-01 5.3699326e-02 -8.1610418e-01 5.6914919e-01 7.3770831e-01 -1.2543518e+00
+1 8.8996997e-01 1 1 1.0103150e+00 -7.3448051e-01 -1.4457545e+00 8.8747907e-01 -6.9478312e-02 -4.5927315e-01 -1.2026741e+00 1.3381596e+00
+1 6.4823611e-01 1 1 5.6119559e-02 -1.0964327e+00 1.4230542e+00 -4.2124558e-01 9.5047653e-01 -1.1071418e-01 -3.3595624e-01 -2.1320856e-01
+1 8.5829179e-01 1 1 7.2362478e-01 8.3735184e-01 3.2784384e-01 1.2754358e+00 -3.3953878e-01 -9.5041102e-01 -9.7459675e-01 1.1609376e+00
+1 5.8584147e-01 1 1 8.5648039e-01 -9.6270085e-01 -2.8217496e-01 1.1621955e+00 -1.4960384e+00 1.4406548e+00 2.1644922e-01 -5.5330046e-01
+1 6.1582886e-01 1 1 8.8448673e-02 -9.1097026e-01 1.2902731e+00 -1.4028195e+00 1.3904366e+00 8.3097643e-01 -1.0230515e-01 -2.0665674e-01
+1 1.1156115e+00 1 1 5.8352183e-01 1.4454345e+00 -7.9334021e-01 4.6580296e-01 -1.2405443e+00 -1.3001183e+00 -9.9143716e-01 1.3216423e+00
+1 1.2089361e+00 1 1 -8.0088843e-01 -5.1857885e-01 -7.4967480e-01 -9.8521121e-02 9.2252453e-01 -1.3119744e+00 -7.6946020e-02 -1.3595443e+00
+1 4.1318476e-01 1 1 1.1927416e+00 -9.7669016e-01 1.1437581e+00 -2.2515970e-01 1.1100602e+00 4.8478415e-01 1.1044112e+00 -1.0575046e+00
+1 3.2868466e-01 1 1 -9.3855118e-02 -4.0986570e-01 -2.6389548e-01 1.3600404e+00 -1.1370538e+00 -1.5241205e+00 1.3102698e+00 -1.4904539e+00
+1 7.8018469e-01 1 1 -3.4345440e-01 8.9985810e-01 6.3746809e-01 -2.9879588e-02 -1.5546673e-01 6.5353931e-01 -8.6026810e-01 1.0003335e+00
+1 1.5425902e-01 1 1 -1.3324214e+00 2.8799528e-01 1.0952667e+00 4.6859633e-01 8.7574650e-01 1.0271966e+00 -9.1651393e-01 -1.1988404e+00
+1 6.4963754e-01 1 1 -7.3348055e-01 -8.5756756e-01 1.5562474e+00 -2.7423477e-01 3.0977388e-01 1.0413758e+00 -6.2080805e-01 1.2648621e+00
+1 1.0722268e+00 1 1 1.9825371e-03 4.8910647e-01 -1.0509192e+00 -3.4734329e-01 7.5054835e-01 5.9076935e-01 -6.9174097e-01 -6.1955869e-01
+1 1.0140970e+00 1 1 -1.2370186e+00 -1.1355650e+00 -7.6574202e-01 -7.1947209e-01 9.7154145e-01 -1.5138350e+00 9.4395434e-01 1.4567185e+00
+1 3.2813135e-01 1 1 4.8850508e-01 -2.6594591e-01 1.2789514e+00 -1.7737308e-01 -1.3014188e+00 7.3373606e-01 -2.3021803e-03 6.3554427e-01
+1 4.8064396e-01 1 1 1.3232518e+00 7.3340406e-01 5.5935992e-01 2.6201746e-01 -1.1777727e+00 1.1508118e+00 -9.9363220e-01 1.7758856e-01
+1 6.7795340e-01 1 1 5.5781114e-01 -1.2875522e+00 1.5170006e+00 -7.8539276e-01 3.4994379e-01 -1.0923489e+00 7.3013154e-01 2.1797096e-01
+1 1.0176019e+00 1 1 6.1937733e-01 -6.0015605e-01 -9.3738914e-01 8.7622966e-01 4.4381537e-01 3.5962837e-01 2.5984816e-01 3.4087169e-01
+1 7.5263729e-01 1 1 -1.3632089e+00 8.3135248e-01 3.8790656e-01 -9.9439623e-01 1.0639134e+00 -1.5020739e-01 4.5417478e-01 -1.2345826e+00
+1 5.8125877e-01 1 1 1.8253868e-01 -1.2629261e+00 7.4077410e-01 4.5541004e-01 -7.5335288e-01 1.3048994e+00 -7.5469467e-01 5.8970150e-01
+1 1.0745695e+00 1 1 -1.4084411e+00 -1.3990522e+00 5.8561614e-02 1.1568910e+00 -9.8345322e-01 -1.4542591e-02 -1.5438171e+00 -6.1175258e-01
+1 5.2967989e-01 1 1 2.3173374e-01 9.5136763e-01 9.2653871e-01 5.5093108e-01 -9.7928032e-01 6.2689316e-01 -5.2028822e-01 7.0717357e-01
+1 1.1073658e+00 1 1 -8.2600266e-01 -1.0709077e+00 -5.3870549e-01 1.2251397e+00 3.9622985e-02 -7.0849311e-01 -1.4316893e+00 8.2114478e-01
+1 9.0943188e-01 1 1 7.1159442e-02 -5.6137133e-01 4.6858566e-02 9.2542979e-01 -7.4137307e-02 -1.0076101e+00 -9.4420323e-01 -3.6137657e-02
+1 1.1213333e+00 1 1 -9.7006075e-01 -7.6515016e-01 -9.8783891e-01 -3.2678755e-01 1.1865688e+00 1.4223529e+00 -1.0391118e+00 -1.0382202e+00
+1 6.4794938e-01 1 1 1.0548737e+00 -1.3399530e+00 7.0858742e-01 -8.1446650e-01 -1.6807009e-01 1.1067112e+00 -2.3899998e-01 -9.6092739e-01
+1 7.4825823e-01 1 1 1.2549660e+00 1.4869195e+00 -5.4903829e-01 -8.1923051e-01 -4.6226032e-01 -8.7500184e-01 1.2243798e+00 6.2127070e-01
+1 6.9850868e-01 1 1 -4.3884370e-01 -7.1339506e-01 -8.2890830e-01 7.9340849e-01 -5.0581115e-02 -3.6075987e-01 7.1940511e-01 -9.5726552e-01
+1 5.9293485e-01 1 1 8.1353601e-01 1.4284605e+00 1.5016883e+00 -1.2442827e+00 1.2548166e+00 -1.7354510e-02 -9.4845316e-01 -6.6568509e-01
+1 5.7897092e-01 1 1 8.8853817e-01 8.4358778e-02 -6.8070212e-01 9.2277962e-01 1.9179919e-01 4.9086488e-01 -2.1106488e-01 -9.5791046e-01
+1 6.5506072e-01 1 1 -1.4705320e+00 9.5969990e-01 1.1199511e+00 -8.8586845e-01 2.9493342e-01 1.4374676e-01 -5.0925125e-01 1.0612426e+00
+1 8.6047436e-01 1 1 -3.2138083e-01 7.3946671e-01 -1.4055699e+00 -7.8337101e-01 -4.8724017e-01 6.6969304e-02 -1.2874347e+00 1.4826997e+00
+1 3.3896789e-01 1 1 -1.0498869e+00 7.6490184e-02 1.3628332e+00 2.9826038e-01 1.0864965e+00 8.6291687e-01 1.3744226e+00 6.2166588e-01
+1 8.0048358e-01 1 1 8.7627308e-01 6.5912273e-01 -2.1481346e-01 -1.1196255e+00 -1.3309426e+00 1.4521386e+00 -2.1094003e-01 -5.9879151e-01
+1 9.7899200e-01 1 1 -2.6462165e-01 6.2005455e-01 -6.7985306e-01 5.9383770e-01 -1.0120137e+00 -9.4039979e-01 -1.5525176e+00 -1.3676427e+00
+1 7.4182852e-01 1 1 9.9918793e-01 5.9397401e-01 -3.1798206e-01 -2.0964539e-01 -3.3131205e-01 5.3414036e-02 9.0513213e-01 1.0629607e+00
+1 3.4588260e-01 1 1 1.5388084e+00 -1.0601968e+00 -4.7535725e-01 1.3569668e+00 -1.4595121e+00 -7.6578901e-01 9.6415182e-01 -1.0576487e+00
+1 7.9566377e-01 1 1 1.1621770e+00 3.8652627e-01 -2.5913492e-01 -1.4213786e+00 -4.6526441e-01 4.8913472e-01 1.6466443e-01 -7.7053470e-01
+1 8.4299994e-01 1 1 1.4273755e+00 -4.6657906e-01 -1.0331477e+00 -4.3953194e-01 -2.7484893e-01 -6.6073578e-01 -2.2809997e-01 -7.3183886e-01
+1 5.1387502e-01 1 1 6.9800802e-01 -3.7892237e-01 -5.3046723e-01 -1.3290103e+00 -1.2447906e+00 5.4384553e-01 -9.3307778e-01 -6.8047432e-01
+1 6.0075961e-01 1 1 7.1387715e-01 -5.3989859e-01 2.7715703e-01 4.7188758e-02 -1.3296268e+00 1.5187464e+00 5.9230341e-01 -1.3346284e+00
+1 8.4426286e-01 1 1 3.9084124e-01 -1.1560976e+00 -8.0367752e-01 1.4201107e+00 -8.8851631e-01 1.3039840e-01 -8.6368260e-01 -1.2794480e-01
+1 3.6150020e-01 1 1 -2.0152542e-01 2.1794525e-01 1.4403730e+00 1.1204069e+00 -1.3037024e+00 -1.2256820e+00 1.3862605e+00 -1.5188065e+00
+1 1.0391442e+00 1 1 -4.0088549e-01 -9.1249482e-02 -7.6325763e-01 -2.7339141e-02 1.2829992e+00 -6.1438845e-01 8.2974960e-01 -1.1406645e+00
+1 8.7166747e-01 1 1 1.0338808e+00 -5.3283442e-01 -9.4822107e-01 -8.1641676e-01 -5.2367740e-01 3.8838401e-01 7.1732523e-02 -1.1499182e+00
+1 9.0873474e-01 1 1 2.8610241e-01 1.3325701e+00 5.4808734e-01 9.6014626e-01 1.2965186e+00 -6.5948304e-01 -7.6307302e-01 4.0363888e-01
+1 3.3778610e-01 1 1 -1.2552005e+00 9.1748806e-02 5.5433847e-01 -1.1832698e+00 5.0116527e-01 -3.9263865e-01 -9.8699933e-01 1.2601020e+00
+1 1.1770434e+00 1 1 -3.5984484e-01 -4.9981854e-01 -1.1970797e+00 -9.3390742e-01 4.7485654e-01 1.4084574e+00 -8.8852366e-01 1.0584087e+00
+1 7.0151728e-01 1 1 -3.4642661e-01 1.6863688e-01 -5.5834958e-01 -7.8505853e-01 1.2685529e+00 4.2192975e-02 -1.4272534e+00 9.7695278e-01
+1 4.1326397e-01 1 1 -1.0208589e+00 5.6349823e-01 -2.4408947e-01 2.1039825e-01 -1.4206210e+00 -8.6261060e-01 1.3540450e+00 -1.4594631e+00
+1 8.9540526e-01 1 1 -1.3386540e+00 -1.1871284e+00 5.0821564e-01 -1.2698953e+00 -2.7252725e-01 5.5368629e-01 -2.6212106e-01 3.5882692e-01
+1 7.2508063e-01 1 1 1.3293107e+00 1.8785070e-01 -4.1019675e-01 8.4980750e-01 7.6577570e-02 4.0809190e-01 -9.5572977e-01 -1.0538219e+00
+1 5.1539399e-01 1 1 -1.2821907e+00 -9.3900800e-02 -1.5225242e+00 1.0344947e+00 -1.0137743e+00 7.0376476e-01 1.3062319e-02 7.1425638e-01
+1 1.3332432e+00 1 1 1.5457042e+00 -1.1112409e+00 -7.9198329e-01 1.1781897e+00 1.4941617e+00 7.7995642e-02 -3.7309481e-01 4.8141242e-01
+1 3.1824011e-01 1 1 8.2089979e-01 1.4252388e-01 6.4847632e-02 3.7522468e-01 -1.5161835e+00 8.2861873e-01 1.4440186e-02 1.4975118e+00
+1 4.7553819e-01 1 1 -1.0121004e+00 1.5052304e+00 -2.3849775e-01 1.2247861e+00 -1.0382675e+00 -8.5281441e-02 7.9356642e-01 1.3825106e+00
+1 5.6377079e-01 1 1 1.3532639e+00 -8.3892623e-01 2.4048339e-01 1.2641276e+00 1.3860541e+00 -7.5892414e-01 1.4099862e+00 6.3709301e-01
+1 1.2672647e+00 1 1 -8.2424308e-01 -3.6529786e-01 -1.4254139e+00 -3.9771580e-01 5.0114496e-01 -3.7184349e-01 6.0498685e-01 1.0744988e+00
+1 4.9058955e-01 1 1 1.3700919e+00 -8.8911933e-01 8.5458705e-01 8.9973595e-01 1.3348697e-01 -9.4579528e-01 -1.3214599e+00 1.2262551e+00
+1 4.8814332e-01 1 1 -7.4033134e-01 1.1277488e+00 -3.1712594e-01 1.3766006e+00 4.1827903e-01 4.7749255e-01 1.2828279e+00 8.2095820e-01
+1 4.4928023e-01 1 1 1.0997115e+00 8.4522400e-01 1.3471325e+00 -1.3044100e+00 -8.6862227e-01 -1.5519636e+00 -2.6226146e-01 -3.0527612e-02
+1 9.0881730e-01 1 1 8.6187722e-01 -6.0227828e-01 -2.0187628e-01 -1.1859676e+00 4.6559209e-02 7.9204286e-01 -1.7387520e-01 -9.9797235e-01
+1 8.5562169e-01 1 1 -3.1332919e-01 -2.7955282e-01 -1.4537506e-02 8.4767422e-01 2.6405453e-01 9.3627200e-01 -6.3938129e-01 4.1808151e-02
+1 3.8818114e-01 1 1 -8.1442099e-01 1.3783112e+00 7.1235849e-01 -2.6214283e-01 -1.1059580e+00 -3.1404611e-01 1.3070530e+00 -1.0471543e+00
+1 6.0367865e-01 1 1 -5.4419071e-02 -8.2740528e-01 -5.3022807e-04 -1.3216374e+00 9.6809722e-01 -2.9733423e-01 -1.5179069e+00 -3.2045129e-01
+1 7.3118770e-01 1 1 -4.1787031e-01 -1.5114199e+00 5.1323471e-01 1.4413461e+00 5.0157034e-01 9.7749039e-01 1.4129522e+00 -1.1351025e+00
+1 1.0112455e+00 1 1 1.4548235e+00 4.8311332e-01 -8.7773725e-01 -1.1675627e-01 9.9968798e-01 1.2930236e+00 1.8806799e-01 1.2236898e+00
+1 4.7732701e-01 1 1 2.0336625e-01 -1.3314911e+00 7.8915036e-01 1.1728607e+00 5.1844909e-01 1.4518369e+00 4.1650207e-01 -1.4530148e+00
+1 1.0056300e+00 1 1 -7.6321038e-02 -8.0650088e-01 -5.5414572e-01 -1.2234214e+00 -1.2042493e+00 2.7279330e-01 6.8181833e-01 -1.2193289e+00
+1 5.4073767e-01 1 1 -9.5788673e-01 1.1119986e+00 1.2951295e+00 -3.1980905e-01 1.4626641e+00 1.2532942e+00 -1.2092523e+00 -6.5197591e-01
+1 8.8584187e-01 1 1 1.4601218e+00 2.5783936e-02 -8.5378523e-01 2.3434645e-01 3.2285921e-02 -2.6268778e-01 -9.4082984e-01 1.1600425e-01
+1 4.5429612e-01 1 1 1.2864666e+00 -1.8916915e-01 1.2269611e+00 -8.9645409e-01 -8.6605422e-01 -1.0559104e+00 -8.9136788e-01 -1.2456716e+00
+1 3.6915608e-01 1 1 1.2033065e+00 -7.4124108e-02 1.2020457e-01 3.7455681e-01 -7.7446763e-01 1.7045632e-01 1.0354242e+00 -4.2951546e-01
+1 6.2303249e-01 1 1 1.5409164e+00 1.4083951e+00 2.3416912e-01 -5.7540722e-01 -8.5901541e-01 -2.7314951e-01 1.0930232e+00 5.1365900e-01
+1 1.3986971e+00 1 1 -1.1072281e+00 -1.0039705e+00 -7.3518207e-01 -1.0469779e+00 1.2877832e+00 -9.5696022e-01 1.5491177e+00 -2.9878329e-02
+1 1.2581067e+00 1 1 -1.5292309e+00 -2.3852601e-01 -3.2115512e-01 -4.9627897e-01 1.3400073e+00 1.3239613e+00 -1.4991841e+00 4.8974138e-01
+1 9.7040996e-01 1 1 -4.1422273e-01 -2.3439503e-01 -3.9798436e-01 -3.2147784e-02 -5.7566632e-01 -8.2359464e-02 -1.2141981e+00 1.1060343e-01
+1 2.6138541e-01 1 1 -7.2153144e-02 7.9911042e-02 -4.7235218e-01 4.6138570e-02 8.8148334e-01 1.2268532e+00 7.5897516e-01 -9.1101699e-01
+1 6.1053569e-01 1 1 -2.3121044e-02 -1.5367709e+00 -1.8491983e-02 -5.2243458e-01 -6.6049442e-01 1.4490274e+00 1.2293243e+00 6.6004351e-01
+1 9.4682804e-01 1 1 9.6211006e-01 -1.4752677e+00 2.2291318e-01 1.9348028e-01 1.4587581e+00 1.7748153e-01 -1.0008565e+00 3.8756122e-01
+1 1.1731604e+00 1 1 4.0645205e-01 -1.3748168e+00 -1.4181886e+00 2.7470994e-01 3.5773631e-01 1.5607102e+00 -1.3080934e+00 1.2198898e+00
+1 4.7946469e-01 1 1 1.4171032e+00 -1.3189649e-01 -2.3274982e-01 -1.0913192e+00 -5.3412062e-01 -1.4424726e+00 -2.5963322e-01 6.5461889e-01
+1 3.3217659e-01 1 1 8.3993261e-01 1.1801550e+00 -5.4333968e-01 -1.1832228e+00 -1.4350212e+00 3.2791064e-02 1.6618010e-02 3.2223024e-01
+1 7.5120120e-01 1 1 -1.5699660e+00 -1.1510508e+00 6.9980333e-01 -1.4342687e-01 -3.9479989e-01 1.3406936e+00 -3.0285406e-01 -3.8207149e-01
+1 9.0941528e-01 1 1 -1.8197672e-01 2.1692350e-01 -5.2841128e-01 -9.7390343e-01 -3.5806735e-01 1.5351379e+00 -6.8815185e-01 -6.0155128e-02
+1 5.0173070e-01 1 1 1.4285410e+00 -1.5557937e+00 2.7408716e-01 -6.9718094e-01 1.2536260e+00 -8.3845903e-01 -1.5656278e+00 5.6560134e-01
+1 3.5635175e-01 1 1 1.4374697e+00 -7.4932352e-01 1.0080810e+00 6.2053085e-01 -9.6928488e-01 1.2037547e+00 4.7440781e-01 -3.9757864e-01
+1 1.0202377e+00 1 1 7.0552897e-01 7.6461414e-01 2.0794653e-01 -8.2565789e-01 1.5285308e+00 -3.5160232e-01 9.9391525e-03 6.3371419e-02
+1 3.8634349e-01 1 1 1.4547959e+00 -1.3857090e+00 1.5062370e+00 -4.1742238e-01 1.2132025e+00 -4.4357921e-02 5.4292507e-01 8.3530249e-02
+1 6.7432419e-01 1 1 -2.6057084e-01 -9.8485851e-01 3.7160698e-01 -4.4158002e-01 1.3577181e+00 -9.6611988e-01 -1.3849929e+00 -3.9902490e-01
+1 3.5473432e-01 1 1 -3.3986423e-02 5.3473825e-01 1.1229118e-01 -1.1935380e+00 -1.3603942e+00 1.3155837e+00 -1.5157879e+00 8.8879907e-01
+1 1.1716337e+00 1 1 5.6005388e-01 -7.5077858e-01 -8.1936842e-01 -7.2473666e-01 3.6619248e-01 4.8594056e-01 -6.7239268e-01 -2.2713358e-01
+1 9.4154469e-01 1 1 6.1396752e-01 1.4421740e+00 -1.5244575e+00 -6.9432708e-01 2.1707948e-01 -9.3791124e-01 -5.9492684e-01 -3.9901397e-01
+1 3.5774865e-01 1 1 -1.1796922e+00 1.2307813e+00 1.2726795e+00 1.4614514e+00 1.0657004e+00 1.0377850e+00 7.5393396e-01 1.0725151e+00
+1 9.3442798e-01 1 1 -4.9593955e-01 1.4957299e+00 -1.1799783e+00 -1.4993036e+00 1.0067383e+00 -7.0180415e-02 1.3248595e+00 -6.9726348e-01
+1 7.0425178e-01 1 1 -6.1064523e-01 -2.9280361e-01 9.7839487e-01 -8.1483245e-02 -3.6807944e-01 -1.4249850e+00 -6.9475061e-01 -7.6668260e-01
+1 7.2002708e-01 1 1 4.6877515e-01 -1.4162081e+00 7.8667736e-01 2.4550556e-01 -5.1528150e-01 -1.3614263e+00 6.2640244e-01 1.1786561e+00
+1 1.3295017e+00 1 1 -4.1045236e-01 -1.5033177e+00 -1.2771049e+00 1.3008125e+00 1.0347234e+00 -1.2732901e+00 4.6888048e-01 -1.2099779e+00
+1 1.1032554e+00 1 1 4.6462679e-01 1.5683889e+00 -9.4060235e-01 4.1167056e-01 -1.2608506e+00 3.4188472e-01 1.3598061e+00 -5.6863583e-01
+1 7.3759798e-01 1 1 -1.0168305e+00 -1.1922460e+00 -2.0954261e-01 1.1600501e+00 -1.0744230e+00 8.3470712e-02 -8.2591270e-01 -3.3756335e-01
+1 4.6127892e-01 1 1 3.9306286e-01 -1.0013724e+00 -5.7198418e-02 2.3874982e-01 4.7660273e-02 -1.3996528e+00 -1.5584640e+00 2.8907844e-01
+1 4.7116275e-01 1 1 -5.6192615e-01 -5.5448126e-01 -6.4631509e-03 8.5440792e-01 -7.9921603e-02 2.8132795e-01 1.4952855e+00 -1.5024918e+00
+1 7.8571469e-01 1 1 -6.6531342e-01 -1.2027603e+00 1.3295663e+00 -1.8607167e-01 1.3592754e+00 1.8191004e-01 -1.4782457e+00 -2.5802303e-01
+1 7.9940948e-01 1 1 -9.9435708e-01 1.3569056e+00 -1.2792119e-01 -1.4218472e+00 -3.1950096e-01 5.9241333e-01 -1.1602511e+00 -1.1952518e+00
+1 7.2321266e-01 1 1 1.1134144e+00 6.9185173e-01 -1.1221156e+00 1.1098470e+00 -8.7085938e-01 9.8373067e-01 -4.7498011e-01 -1.2538910e+00
+1 9.7857152e-01 1 1 -1.3115014e+00 9.1767037e-01 -4.1598107e-01 1.5622181e+00 1.4665457e-01 -6.4073364e-01 -2.0369893e-01 -3.4263821e-01
+1 8.6712499e-01 1 1 -9.8960359e-01 1.2075090e+00 -1.3501372e+00 -1.2318176e+00 -1.3268261e+00 5.6929199e-01 7.6799366e-01 -1.8111473e-01
+1 8.7916753e-01 1 1 -6.7605620e-01 -8.4028336e-02 -3.2324794e-02 -6.2267457e-02 -9.4240006e-01 -1.2007308e+00 -1.1346985e+00 2.0800846e-01
+1 1.1100828e+00 1 1 6.6407323e-01 1.4524541e+00 2.1272143e-01 -3.7879901e-01 9.9232436e-01 9.0799490e-01 -1.4109464e+00 -5.9445383e-01
+1 9.7894165e-01 1 1 -9.9989102e-01 1.2210379e+00 7.6699350e-02 1.5333487e+00 -7.1994796e-01 -1.1868576e+00 -1.0343581e+00 -7.2084718e-01
+1 4.4701892e-01 1 1 -7.8927365e-01 1.1002627e+00 1.0329925e+00 5.0697297e-01 1.2496104e+00 -1.5440845e+00 1.1174003e+00 -1.2972939e+00
+1 2.1444515e-01 1 1 -1.5180689e+00 7.0165416e-01 1.0643101e+00 6.9539862e-01 6.5533611e-01 1.2689599e+00 -2.9483137e-01 -9.6597091e-01
+1 1.1234786e+00 1 1 -1.3101611e+00 -8.3739174e-01 -3.6935729e-01 8.3999413e-01 -1.8979154e-01 -8.6377691e-01 -9.3919411e-01 6.7778591e-01
+1 6.6987282e-01 1 1 -4.5485964e-01 2.9210780e-01 -8.1313302e-04 -5.3599779e-01 -1.1099239e+00 -1.9890497e-01 1.4676978e+00 1.3276266e-01
+1 1.1004621e+00 1 1 -1.3310059e+00 -8.5345441e-01 -1.0999561e+00 -1.5686607e+00 2.8574024e-01 -3.4124569e-01 -1.8938193e-01 8.1124929e-01
+1 3.4024430e-01 1 1 1.0649013e+00 5.0374296e-01 1.3099979e+00 -2.3457333e-01 -1.0589858e+00 1.2318371e+00 -5.0882279e-01 1.5463353e-01
+1 6.1154484e-01 1 1 1.4211912e-01 -1.8418940e-01 8.5315288e-01 2.2480794e-01 -1.2522439e+00 3.9097459e-01 -3.6942836e-01 8.2858964e-01
+1 4.5098194e-01 1 1 9.8570977e-01 -1.2024227e+00 7.1156463e-01 -9.8893648e-01 -9.3451559e-01 -1.1018660e+00 -1.1953854e+00 -5.7417460e-01
+1 1.1177396e+00 1 1 1.2060235e+00 7.4649391e-01 -7.7656145e-01 1.1113025e+00 1.5597717e+00 6.2666095e-01 -3.5677135e-01 8.2010492e-01
+1 1.1150735e+00 1 1 8.0419890e-02 -1.1978779e+00 -1.4924361e+00 8.9316545e-01 -1.5079770e+00 -1.4695140e+00 1.0442856e+00 1.3364713e+00
+1 4.3017365e-01 1 1 7.3225648e-01 -1.4073066e+00 -8.9695043e-01 9.0201487e-01 -1.3407996e+00 1.0802200e+00 -7.6998081e-01 -3.1503626e-01
+1 4.8445395e-01 1 1 1.4162153e+00 4.4861769e-01 1.4572448e+00 -1.1623097e+00 -1.7464662e-01 -6.3347593e-03 -8.4738686e-01 -1.2307444e+00
+1 7.0362568e-01 1 1 -1.5167401e+00 9.5091881e-02 5.7780294e-02 -5.1589685e-01 -1.0382439e+00 3.4585029e-01 -1.1914645e+00 -8.7482767e-01
+1 5.1408412e-01 1 1 -9.6744369e-01 -8.6142435e-01 3.6126951e-01 1.1736043e-01 -1.3593886e+00 7.5938583e-01 -4.3271019e-01 -5.7501744e-01
+1 1.2080986e+00 1 1 1.0574956e+00 -1.5000432e+00 -8.4188447e-01 -4.4349200e-01 1.5593671e+00 -1.2933414e+00 2.2689450e-01 -7.7913249e-01
+1 8.3738554e-01 1 1 1.3394144e+00 5.5607349e-02 1.8102377e-01 1.2293858e+00 1.1166522e+00 -5.0966924e-01 -4.7759161e-01 -7.2161641e-01
+1 5.1702152e-01 1 1 -1.1154181e+00 1.5396885e+00 1.4047727e+00 3.1980708e-02 -3.0137957e-01 1.1123193e+00 -1.1296302e-01 1.4822433e+00
+1 7.8956831e-01 1 1 -9.4842011e-01 2.4630526e-01 9.4590708e-01 2.8741640e-01 -1.0391191e+00 -8.6789765e-01 -1.0475301e+00 -7.6706368e-01
+1 6.0321470e-01 1 1 3.4438601e-01 -9.6667038e-01 1.4015399e+00 -1.1619946e+00 -3.6055941e-01 -3.4114937e-01 -3.5316865e-01 1.0569575e+00
+1 6.9742664e-01 1 1 1.2819967e+00 1.4881741e+00 2.0070420e-02 -1.5036247e+00 2.1019647e-01 -2.9083171e-01 -1.2369054e+00 -1.4225385e+00
+1 3.7527898e-01 1 1 1.4766444e+00 1.5236769e+00 1.1731431e+00 -4.4943458e-01 -1.5196486e+00 3.0967802e-01 -7.5032838e-01 -1.0838901e+00
+1 3.0987412e-01 1 1 -6.2007949e-01 1.3154213e+00 3.8015581e-01 -1.2582250e+00 4.1420565e-01 -8.6048296e-01 -4.1609472e-01 1.1554298e+00
+1 7.2668941e-01 1 1 -1.0131131e+00 8.9753551e-01 -7.2084242e-01 -9.2727711e-01 -2.1490317e-01 -1.3862003e+00 -1.1865535e-01 1.1238721e+00
+1 7.1066577e-01 1 1 4.0201813e-02 -1.0485924e+00 -1.2172378e+00 6.9482663e-01 9.5404855e-01 1.8290146e-01 6.7092864e-01 -1.4779928e+00
+1 4.3454292e-01 1 1 2.2945378e-01 6.4276338e-01 -6.4213826e-02 6.5120098e-01 5.0712472e-03 1.5472636e+00 1.1216930e+00 -5.1763051e-02
+1 7.1300667e-01 1 1 -1.4460191e+00 -1.0129656e+00 1.4661028e+00 -5.7397462e-01 4.0945033e-01 -1.2450332e+00 -4.0333204e-01 2.3955963e-01
+1 3.6624931e-01 1 1 1.1786806e-01 -6.2284709e-01 1.2789085e+00 1.0395913e+00 1.5438579e+00 8.7494940e-01 7.5536106e-01 -1.2430048e+00
+1 1.1376688e+00 1 1 -1.3364155e+00 -4.0429480e-01 -1.6225169e-01 -1.1276710e+00 1.2068138e+00 -5.2066896e-01 1.7741247e-01 4.0939309e-01
+1 8.4428525e-01 1 1 1.2516881e+00 2.8219990e-01 -6.1788640e-02 4.6264635e-01 7.9746627e-01 -1.5476837e+00 4.0001921e-01 5.8173371e-01
+1 3.5653082e-01 1 1 1.0172396e+00 -8.7110947e-01 1.3855010e+00 2.5533555e-01 9.8129390e-01 4.6670711e-01 1.1461103e-01 5.6219723e-01
+1 5.0500238e-01 1 1 1.9859677e-01 -9.1501935e-01 6.3068312e-01 9.0727553e-03 -7.5478920e-01 -6.1052247e-01 4.7121646e-01 -1.0619256e+00
+1 7.2090067e-01 1 1 1.4445337e+00 -6.3409378e-01 1.5753488e-01 -1.4522411e+00 9.0448911e-03 -6.0950347e-01 -2.1997959e-01 -3.9570479e-01
+1 1.0099248e+00 1 1 4.9997792e-02 -9.3186067e-01 -6.7393069e-01 -7.8215935e-01 1.2210380e+00 8.0881671e-01 4.5764536e-01 1.4129615e-01
+1 1.2022568e+00 1 1 1.5076528e+00 -9.4290523e-01 -1.3116616e+00 -1.3285850e+00 1.1020084e+00 1.1097131e-01 1.0266763e+00 -2.7973095e-01
+1 1.0059463e+00 1 1 -9.6496531e-01 -1.2148661e+00 -5.4051306e-01 9.1260298e-01 -1.3743638e+00 -1.0112676e+00 -1.4200961e+00 1.5261586e+00
+1 6.6494661e-01 1 1 -1.2706076e+00 -1.0430622e+00 1.0829090e+00 8.6303056e-01 1.1982908e+00 -3.5768620e-01 -8.7527189e-01 -9.5647545e-01
+1 4.3589470e-01 1 1 1.4455735e+00 -6.5871580e-01 1.2056118e+00 2.2127139e-01 -1.0771259e+00 1.3764311e+00 1.3837148e+00 4.6714291e-02
+1 8.9702367e-01 1 1 -1.3236192e+00 -6.3948106e-02 -5.5581645e-01 -7.3747746e-01 -1.3986029e+00 -1.0105635e+00 -1.1154670e+00 -2.7106684e-01
+1 5.8906612e-01 1 1 -4.5033191e-01 -3.5112559e-01 1.4895292e+00 -1.2007147e+00 -9.2221894e-01 -1.0907721e+00 1.3703352e+00 -5.1099289e-01
+1 1.1655356e+00 1 1 -6.3174534e-01 -1.4567120e+00 -8.3501257e-01 1.1790203e+00 8.8447911e-01 -1.4131015e+00 2.0735602e-01 8.5688664e-01
+1 8.1946108e-01 1 1 8.3918394e-01 -5.2696692e-01 -5.6193558e-01 -1.3720900e+00 -5.7600520e-01 4.4289453e-01 1.0064395e+00 6.3299910e-01
+1 1.1380762e+00 1 1 1.5551206e+00 -5.8325476e-01 -8.2372916e-01 -1.4263798e+00 1.4692010e+00 1.2953986e+00 8.9446028e-01 1.3831848e+00
+1 3.3464111e-01 1 1 -1.1389413e+00 -9.9362135e-01 5.8281980e-01 3.2775189e-01 -5.6865185e-02 5.2752313e-01 6.7310298e-01 -5.9875324e-01
+1 2.0276236e-01 1 1 -4.6303650e-01 9.1256904e-01 -3.3552491e-02 1.3141573e+00 -6.8898931e-01 5.0672674e-01 -3.3343524e-02 -7.2446443e-01
+1 5.4668478e-01 1 1 -5.2952443e-01 2.9248309e-01 1.5699675e+00 -1.4960344e+00 6.7110268e-02 -3.0129116e-01 -1.2011239e+00 7.3937673e-01
+1 2.5904911e-01 1 1 4.1497249e-01 -8.2919508e-01 2.0636728e-01 1.4582728e+00 9.0503817e-02 4.4691059e-01 5.8566416e-01 -1.4358233e+00
+1 8.0885585e-01 1 1 1.0695211e-01 -1.7670800e-01 9.6657746e-02 -1.5146247e+00 5.6680603e-01 -3.2167408e-01 6.4779672e-01 -1.3083723e+00
+1 7.0744057e-01 1 1 5.5318839e-01 -1.1262944e+00 3.2332896e-01 2.7434319e-02 9.9996115e-01 3.0465834e-01 -1.2407311e+00 1.3358426e+00
+1 9.8346824e-01 1 1 1.4646683e+00 -1.5345120e+00 -7.6543642e-01 -7.2552848e-01 -1.1736547e+00 -4.0336747e-01 9.2388098e-01 -1.4553319e+00
+1 3.6303138e-01 1 1 -8.4058301e-01 -1.2084719e+00 1.3202100e-01 -1.4361082e+00 4.4517734e-01 1.5993128e-01 -1.2248534e+00 6.7635393e-01
+1 6.7837287e-01 1 1 6.3565952e-02 -3.9065723e-01 9.1249165e-01 1.8506645e-01 -1.1781833e+00 -1.2382378e+00 7.4620498e-01 1.1982112e+00
+1 8.9197249e-01 1 1 2.1145364e-01 1.5259262e-01 -1.0082078e+00 2.3516361e-01 -2.6763081e-01 -1.1522028e+00 2.2922443e-01 7.2642781e-01
+1 8.2363807e-01 1 1 7.5995929e-01 1.0845149e+00 8.0276629e-01 2.7130143e-01 6.8957772e-01 -2.9456505e-01 9.8247329e-01 8.4314104e-01
+1 7.4043066e-01 1 1 -1.0799610e+00 -7.8077470e-02 -1.0473986e+00 1.3122139e+00 3.9742906e-01 3.9522633e-01 2.1753844e-01 -1.0530155e+00
+1 6.7715377e-01 1 1 1.2178189e+00 9.3768530e-01 -1.2853497e+00 3.9882880e-01 5.6414889e-01 1.2420695e+00 -6.4524142e-01 -1.4408627e+00
+1 8.9227994e-01 1 1 4.0574307e-01 1.4481678e+00 -1.2820107e+00 -1.0430800e+00 3.2369736e-01 -4.2033826e-01 2.0527877e-01 -1.1825210e+00
+1 2.8512505e-01 1 1 -1.0739430e+00 1.4384601e+00 1.4307300e+00 -9.5858207e-01 -8.5698310e-01 8.1666584e-01 6.5151884e-01 -9.1501641e-01
+1 8.5016956e-01 1 1 -1.3102330e+00 -1.4978098e+00 5.2906801e-01 -8.0179573e-01 8.8733394e-01 8.4537858e-02 -1.5148146e+00 -5.8469797e-01
+1 4.8961519e-01 1 1 1.4782690e+00 -1.0797233e-01 1.3388987e+00 -1.4899827e+00 2.8119212e-01 8.2790801e-01 -2.1809823e-02 -1.1688008e-01
+1 6.3178633e-01 1 1 1.5520738e+00 1.1495783e+00 -3.5799497e-01 -5.0483750e-01 1.0406490e+00 5.3607991e-01 1.0086493e+00 -9.0805777e-01
+1 1.0588963e+00 1 1 1.0599191e+00 1.6775285e-01 -6.7148714e-01 6.3784931e-01 9.4108070e-01 -1.9272590e-01 3.3482895e-01 1.3009700e-01
+1 5.4975278e-01 1 1 1.2291603e+00 1.4135499e+00 -1.0836195e+00 1.2192766e+00 -1.1756425e+00 -1.6209227e-01 8.7772324e-01 -8.2844941e-03
+1 5.5463840e-01 1 1 -6.1561909e-01 8.0900690e-01 -5.7972635e-01 -2.2751053e-01 -1.5480215e+00 -5.2400877e-01 -1.0246226e+00 -1.0074158e+00
+1 1.2047250e+00 1 1 -1.4455060e+00 1.6596887e-01 -1.3819823e+00 -4.5115526e-01 1.0729144e+00 -1.1311500e+00 1.3791372e+00 1.5465390e+00
+1 1.0144802e+00 1 1 -6.8263194e-01 -2.9549811e-01 -1.1811970e+00 1.2382106e+00 -2.6947797e-01 -1.4604210e+00 4.8875897e-01 -8.5624283e-01
+1 1.0940638e+00 1 1 1.0131762e-01 4.2123581e-01 -6.5446962e-01 6.9586313e-01 1.0604197e+00 -3.2606167e-02 -6.9286303e-01 7.6275826e-01
+1 1.2249483e+00 1 1 1.0193986e-01 -1.4395312e+00 -9.5506140e-01 -7.7781112e-01 2.1942271e-01 -1.3747265e+00 9.3498029e-01 -1.1614808e+00
+1 7.9252031e-01 1 1 1.1352810e+00 -7.9525144e-01 -1.3200020e+00 -5.0449073e-01 -3.9235372e-01 1.3849902e+00 -3.2640418e-02 8.4828632e-01
+1 2.0549954e-01 1 1 -1.3667672e+00 -1.4557795e+00 6.5407375e-01 1.8280452e-01 -8.6038616e-02 1.4701293e+00 1.1912045e+00 6.0071017e-01
+1 6.8570427e-01 1 1 6.8876823e-02 -5.6313094e-01 5.8488384e-01 -8.2085244e-02 -9.1840513e-01 -1.6224236e-01 -7.9600960e-01 -9.4291735e-01
+1 7.9813353e-01 1 1 1.5066683e+00 1.0769938e+00 9.9345210e-02 -4.4752321e-01 -9.9026397e-01 9.5151868e-02 1.5096865e+00 -1.4185224e+00
+1 6.2827826e-01 1 1 1.3374356e+00 -8.2290562e-01 1.5092376e+00 -5.4973529e-01 7.9132832e-01 1.4677642e-01 -1.3420321e+00 4.4134291e-01
+1 5.6460903e-01 1 1 1.8455621e-01 -1.2839152e+00 5.3666866e-01 2.3007828e-02 1.4933868e+00 7.2107167e-01 1.1025679e+00 3.5010068e-01
+1 4.9368758e-01 1 1 1.0842235e+00 8.3689072e-01 2.7771437e-01 2.7667422e-01 1.1687419e+00 -1.2128528e+00 -1.3970949e+00 -6.0940728e-02
+1 3.8057774e-01 1 1 1.3064151e+00 7.1197475e-01 -8.6124875e-01 5.0641813e-01 -1.3338745e+00 1.3783977e+00 -7.1023615e-01 -7.1610186e-02
+1 4.5956350e-01 1 1 3.2728554e-01 -1.6680560e-01 1.4512153e+00 7.9494032e-01 -2.3219646e-02 6.2508735e-01 1.1131321e+00 -3.2240967e-01
+1 8.1058595e-01 1 1 -2.4068380e-01 -1.2010383e+00 -7.4931141e-01 -6.3167504e-01 -6.9509613e-01 3.5730793e-01 2.2621901e-01 5.0801161e-01
+1 5.5158650e-01 1 1 1.1986497e+00 -1.1179423e+00 9.6802458e-01 -1.1208186e+00 1.1024448e+00 -1.4508239e+00 7.3575730e-01 -6.9776524e-01
+1 8.1009755e-01 1 1 -1.3284161e+00 6.0865107e-01 -7.1931026e-01 -6.0791371e-01 -3.2434840e-01 1.0452600e+00 5.6421237e-01 2.2490963e-01
+1 6.9495386e-01 1 1 6.1017549e-01 5.7281159e-01 -5.9897505e-01 -7.4634050e-01 -6.6030911e-01 -1.0105586e-01 1.3906863e+00 7.2012425e-01
+1 6.2673765e-01 1 1 1.0609831e+00 1.4044364e+00 -1.3108174e+00 6.3460407e-01 1.4316096e+00 1.1557683e+00 -1.8514013e-01 -1.4281919e+00
+1 6.5383741e-01 1 1 2.6327394e-01 -1.5645222e+00 1.0818856e+00 8.3489261e-02 -3.9597478e-01 5.3064689e-01 -1.4733782e+00 1.2888358e+00
+1 3.5015694e-01 1 1 1.4826345e+00 2.0588999e-01 -2.8774875e-01 -1.0879109e+00 -1.2549367e+00 -3.9918777e-01 -1.0347427e+00 1.8155342e-01
+1 8.4704876e-01 1 1 -4.7436060e-01 1.4996195e+00 -1.2821474e+00 -4.4872833e-01 9.3235926e-01 1.2930178e+00 9.3708556e-01 8.8183831e-01
+1 7.0568017e-01 1 1 7.8356562e-01 -8.9316420e-01 -8.6736781e-01 1.1868430e+00 -1.0201677e-01 1.3544468e+00 7.9295428e-01 -9.7758007e-01
+1 1.0951754e+00 1 1 -1.6896011e-01 -8.8109110e-01 -8.6091199e-01 1.2993429e+00 7.1375922e-01 2.0625803e-01 5.4646936e-01 3.4127138e-01
+1 7.4863746e-01 1 1 2.8720482e-01 9.6959721e-01 8.2791989e-01 8.4488217e-01 1.5504791e+00 1.4019506e+00 -1.5063853e+00 -8.0015853e-01
+1 5.3661874e-01 1 1 1.5651347e+00 5.7913456e-01 7.3565473e-01 -6.4177708e-02 -6.0856409e-01 6.3840723e-01 2.7755012e-01 8.9376851e-01
+1 6.9834420e-01 1 1 6.6313441e-01 8.6049882e-01 -1.1596253e+00 -1.0684549e+00 8.8899962e-01 1.1713927e+00 -4.8024036e-01 -1.5287724e+00
+1 6.8526260e-01 1 1 -1.0706816e+00 -1.4888418e+00 6.1828015e-01 -1.7737220e-01 1.9172236e-03 -7.6365556e-01 -6.4812050e-01 1.0081176e+00
+1 3.9662874e-01 1 1 9.7120633e-02 -1.7925326e-01 -9.5402739e-01 2.7694193e-01 8.0685105e-01 -1.3529929e+00 -1.0595754e+00 8.2356245e-01
+1 6.9127056e-01 1 1 -1.3216944e+00 7.7875756e-02 3.5063270e-01 -1.2772487e+00 -1.5098288e+00 -9.0400401e-01 1.4051396e+00 -2.4319177e-01
+1 7.1719482e-01 1 1 4.8396723e-01 -1.1863076e+00 -5.4396998e-01 -2.1569190e-01 -1.0493253e+00 -8.5336191e-01 8.2913387e-01 -1.1201884e-01
+1 1.0968519e+00 1 1 4.5377355e-01 1.4172219e+00 -4.6881689e-01 2.6422027e-01 8.9148015e-01 -1.0831478e+00 -8.5207231e-01 -8.8672555e-01
+1 1.0167780e+00 1 1 -1.2148616e+00 -3.0701824e-01 -2.9116981e-01 -1.4618628e+00 8.5159914e-01 1.0643419e+00 -1.3999592e+00 5.1923382e-01
+1 6.4609137e-02 1 1 -9.6843981e-01 -1.5603429e+00 9.1037777e-01 8.6857484e-01 -2.6940944e-01 1.6647296e-01 1.4154730e+00 -5.8164265e-01
+1 4.8566643e-01 1 1 2.3597329e-02 1.3315266e+00 1.1629958e+00 -8.4367831e-01 -9.2938252e-01 -1.2479720e+00 -1.4267587e+00 9.6826162e-01
+1 9.4310977e-01 1 1 7.5962940e-01 1.4032584e+00 -5.1924357e-01 1.4478257e+00 -1.3342349e-01 -1.3927947e+00 2.4379468e-01 1.2309444e-01
+1 8.1407473e-01 1 1 -3.4122835e-01 6.2736309e-01 4.1776854e-01 -1.1702690e+00 6.4851318e-01 -6.9331719e-01 8.2043924e-01 -1.4613366e+00
+1 9.9185920e-01 1 1 1.5232946e+00 9.0656221e-01 -2.3766840e-02 7.9974936e-01 1.3761527e+00 -4.1477845e-01 6.7216426e-01 2.8631139e-01
+1 9.8698387e-01 1 1 1.1730447e+00 -1.3330932e-01 -4.6701222e-01 -1.4875181e+00 5.9344416e-01 1.2709952e-02 -1.0251134e-01 -8.8435493e-01
+1 1.0019594e+00 1 1 -1.2731164e+00 -5.7424020e-01 -1.3759276e+00 7.8441405e-02 -5.4075377e-01 -1.2145476e-02 -1.3153456e+00 -4.7839919e-01
+1 8.1327807e-01 1 1 1.1980840e-01 -2.8241259e-01 4.7836720e-02 -1.1042231e+00 1.7886405e-01 7.4510918e-02 3.7347852e-01 -1.1195490e+00
+1 6.6755984e-01 1 1 -1.4114717e-01 4.3810730e-01 -2.5597056e-01 -1.2905549e+00 -3.3608291e-01 -1.1904619e+00 1.5141720e-01 -1.2619886e+00
+1 8.8805216e-01 1 1 -3.5801766e-01 -6.2370574e-01 -1.2569131e+00 -8.0128725e-01 3.8181393e-02 7.1042933e-01 1.7884336e-01 -1.3497509e+00
+1 1.0228240e+00 1 1 -1.0528602e+00 8.7234587e-01 -8.7014076e-01 7.7294700e-01 8.2977289e-01 -1.0079273e+00 -6.8374682e-01 1.7798637e-01
+1 9.5414795e-01 1 1 1.1700589e+00 -2.9580952e-01 -3.4193555e-01 4.3454949e-01 4.6316177e-01 -7.6657332e-01 2.1309162e-01 6.2065287e-01
+1 8.4254170e-01 1 1 -1.1896746e+00 1.4705548e+00 -9.3780438e-01 -7.2967178e-01 -5.0675915e-01 -1.2626791e-01 1.5296654e-02 1.2252396e+00
+1 5.0191563e-01 1 1 1.3757195e+00 7.0484380e-01 -3.0788013e-01 1.1841044e+00 -2.4329216e-01 1.5319235e+00 -5.1973387e-01 -5.3830337e-01
+1 7.0823176e-01 1 1 -4.0402827e-01 -6.3606799e-01 -3.3828600e-01 -7.4687412e-01 1.3423220e+00 -1.4559222e+00 -1.5395169e+00 5.2207291e-01
+1 7.1224593e-01 1 1 -1.5213580e+00 4.4509635e-01 7.0988147e-01 1.0909315e+00 6.2866644e-01 1.8034291e-01 -5.0371347e-01 1.1118640e-02
+1 1.0562559e+00 1 1 -4.0990203e-02 6.0220927e-01 -7.9095684e-01 9.5181573e-01 8.2074820e-01 -6.1370631e-01 6.7984405e-01 1.5170230e+00
+1 9.3067058e-01 1 1 -9.1355323e-01 -8.8032678e-01 -1.5330298e+00 1.7713353e-01 -4.1828921e-01 -7.1326496e-01 1.6654910e-01 -5.6046638e-01
+1 1.0420632e+00 1 1 -1.1257985e+00 1.2492607e+00 -1.4304543e+00 -1.1465401e+00 6.9766702e-01 4.7343782e-01 3.1647580e-02 -1.2636531e+00
+1 5.2535501e-01 1 1 5.1731152e-01 1.0615506e+00 9.6280927e-01 6.2915235e-01 1.2658695e+00 -5.8468309e-01 9.7171285e-01 -1.0512241e+00
+1 1.0080903e+00 1 1 -1.4737255e+00 3.7628915e-01 -4.0843566e-01 -4.3734538e-01 6.0363696e-01 1.3317240e-01 -1.5623184e+00 3.9321156e-01
+1 3.9011160e-01 1 1 -5.8729533e-01 2.6566116e-01 -1.9816855e-01 8.6307075e-01 1.1236537e+00 1.4145387e+00 -4.5415572e-01 -1.2042480e+00
+1 8.8974200e-01 1 1 2.1156551e-01 7.6394404e-01 -5.3060881e-01 8.9675730e-01 1.1348795e+00 -1.4214517e+00 1.0748946e+00 1.4855056e+00
+1 5.8843257e-01 1 1 -5.0142069e-01 -8.1706852e-02 1.0392926e+00 -1.5616628e+00 1.3104295e+00 1.4740498e+00 -1.5455780e+00 6.5622251e-01
+1 2.1463359e-01 1 1 1.5156137e+00 -3.7106511e-01 1.3570473e-01 1.1398242e+00 -1.3176691e+00 -2.4462305e-01 1.2997517e+00 -1.0000610e+00
+1 5.9393500e-01 1 1 8.8667483e-01 -4.2994649e-01 -6.8353743e-03 -4.0725046e-01 -9.7830406e-01 9.6510863e-01 1.4337880e+00 -5.0437687e-01
+1 4.9167440e-01 1 1 -1.3716497e+00 -4.4754721e-01 1.3567927e+00 8.7199182e-01 7.3957706e-01 5.3782918e-01 -1.4819457e+00 -1.0451122e+00
+1 5.6619533e-01 1 1 -3.0924119e-01 -9.5318771e-01 -1.2063588e+00 3.6741525e-02 -1.2104114e+00 9.3294007e-01 -5.1445741e-01 -5.5606751e-01
+1 6.5426048e-01 1 1 -1.2224642e+00 -1.2448310e+00 5.6625804e-01 -1.3789458e+00 1.5700998e+00 2.3479172e-01 -8.2274222e-01 4.1150473e-01
+1 2.8758270e-01 1 1 6.0928580e-02 1.1320297e+00 1.2147679e+00 -4.1256718e-01 -7.1113521e-01 3.0401079e-01 1.4623347e+00 1.5145043e+00
+1 6.3796897e-01 1 1 -1.3256246e-01 5.3778777e-01 -6.0595647e-01 -5.2164567e-01 -1.4310923e+00 1.2796965e+00 7.7942742e-01 1.0899626e+00
+1 6.8782853e-01 1 1 -5.8800108e-01 2.3699756e-01 7.3293534e-01 8.8628362e-01 -3.3442693e-01 5.1636479e-01 -6.0480103e-01 3.7528971e-01
+1 6.8199727e-01 1 1 9.1640062e-01 -3.2156358e-01 2.5951546e-01 1.4779775e+00 -4.0420542e-01 1.4641087e+00 1.3029416e+00 -8.2382895e-01
+1 6.7185881e-01 1 1 -1.2836231e+00 -9.7978449e-01 1.1457982e+00 -2.0507551e-01 -1.3571109e+00 -8.2043359e-01 -1.5032108e+00 -1.0942775e+00
+1 4.9604499e-01 1 1 -5.3636546e-01 9.9071998e-01 -5.3216358e-01 -3.7695701e-01 -1.0003686e+00 -5.7720824e-01 2.2464156e-01 -6.3840095e-01
+1 8.7324928e-01 1 1 -1.4649433e+00 5.8970542e-01 4.0935350e-02 1.0758857e+00 6.0923779e-01 9.9174370e-02 -6.4370256e-01 -1.0659134e+00
+1 9.7331759e-01 1 1 -6.4052505e-01 -5.4578495e-01 -8.3708297e-03 -5.9562065e-01 1.0091493e+00 -1.3620631e+00 9.3624953e-01 -1.4445349e+00
+1 6.1003387e-01 1 1 9.3349899e-01 4.4292035e-01 6.8313484e-01 -1.4819948e+00 -6.8616964e-01 5.9039191e-01 -6.9178025e-01 -7.0675681e-02
+1 9.3919428e-01 1 1 2.0375014e-01 -1.4122780e+00 -1.0738793e+00 -1.3402453e+00 3.3347563e-01 1.5672567e+00 2.8373712e-01 -3.2415152e-01
+1 1.1050824e+00 1 1 9.2658931e-02 -1.4237667e+00 -2.3953142e-01 -2.8286762e-01 1.2361171e-01 -1.3714623e+00 -1.6782396e-01 -4.9297234e-01
+1 1.1944718e+00 1 1 -9.1130715e-01 2.6396362e-01 -1.4243733e+00 -9.2637921e-01 9.4933796e-01 -3.0174623e-01 5.3283129e-01 -1.0062961e+00
+1 7.1265468e-01 1 1 -1.0750018e+00 5.0775750e-01 -5.0577741e-01 7.7813074e-02 -6.2605386e-01 -9.1826436e-01 -1.3852360e+00 1.5161734e+00
+1 2.8593890e-01 1 1 -2.5615210e-01 1.3146369e+00 5.4876581e-01 9.0179457e-01 -8.9351083e-01 1.3755472e+00 6.8126456e-01 8.6910708e-01
+1 7.4233468e-01 1 1 -1.1664770e+00 2.8063306e-01 -6.0902453e-01 1.4184516e+00 -4.2358758e-01 -1.5896286e-01 -1.0917127e+00 -1.3231670e+00
+1 9.1973683e-01 1 1 -1.4413440e+00 1.0692810e+00 -5.6633684e-01 1.5112096e+00 -3.8752324e-01 -1.3349673e+00 -1.5150688e+00 8.6665201e-01
+1 5.5310983e-01 1 1 1.5299789e-01 1.4957985e+00 6.0250549e-01 -8.7611200e-01 -5.8148151e-01 4.5982205e-01 -1.1523035e+00 1.3967588e+00
+1 6.0219834e-01 1 1 -1.5288041e+00 8.6041284e-01 9.5673110e-01 -1.6959359e-01 5.3500529e-01 -8.8700977e-02 1.1538994e+00 1.3454318e+00
+1 3.2913197e-01 1 1 4.7649179e-01 2.0760978e-01 1.1084650e+00 -9.3489270e-01 5.9571421e-01 1.4591964e+00 5.3607299e-01 -5.1117131e-01
+1 3.3077295e-01 1 1 4.7781374e-01 -1.0118881e+00 3.2668794e-01 1.5049012e+00 -8.7045600e-02 1.4412396e+00 -3.0892531e-01 9.9971820e-01
+1 9.6208327e-01 1 1 7.0470056e-01 -1.3622848e+00 -8.5972949e-01 -8.7826185e-02 1.0067780e+00 1.2341459e+00 9.4504656e-01 1.0263482e+00
+1 6.3750989e-01 1 1 9.7988931e-02 7.0140434e-03 -1.2889988e+00 4.5385157e-01 2.9919432e-01 1.4960977e+00 -4.9495750e-01 -6.5104732e-01
+1 6.8212314e-01 1 1 7.0541059e-01 -1.4954936e+00 2.1944442e-01 9.6450949e-02 -1.1309318e+00 -3.9283290e-01 1.8667441e-01 1.4831497e-02
+1 7.1123892e-01 1 1 -5.3485467e-01 1.1219804e+00 -2.7380373e-02 -1.0709461e-02 -9.3556084e-01 1.2852056e+00 -1.0142018e+00 1.0871546e+00
+1 9.2686121e-01 1 1 -1.2058513e+00 1.2848008e+00 -1.5094088e+00 -9.2312593e-01 -2.9974236e-01 -1.1413593e+00 5.9221079e-01 3.0520448e-01
+1 8.9033825e-01 1 1 -3.2892752e-01 1.4804423e+00 -2.7311363e-01 1.3486336e+00 1.3447797e+00 -2.6040810e-01 7.2116743e-01 -6.4908044e-01
+1 8.5006809e-01 1 1 9.1827238e-01 3.8051460e-01 -3.5390839e-01 -1.0537987e-01 1.0949346e+00 -4.4036887e-01 3.9648203e-01 -1.4853323e+00
+1 7.0264663e-01 1 1 -1.2407844e+00 -9.7375531e-01 -1.1034537e+00 7.3878997e-01 -8.8467372e-01 3.1262828e-01 3.5544834e-01 -8.8476528e-01
+1 1.0082746e+00 1 1 2.8953739e-02 -1.3494360e+00 -9.2513103e-01 1.2689153e+00 4.4680327e-01 -1.5409527e+00 -1.2888998e+00 -1.0920398e+00
+1 1.2131701e+00 1 1 -3.2137164e-01 -8.1404428e-01 -9.3523584e-01 1.5290106e+00 1.0161723e+00 4.9768522e-01 -1.2583035e+00 -7.2912857e-01
+1 1.2598882e+00 1 1 -8.9533139e-01 -6.1871567e-03 -1.1206948e+00 -1.4655944e-01 1.1099240e+00 -1.4656678e+00 8.9518424e-01 8.8906937e-01
+1 4.7994649e-01 1 1 3.9415255e-01 -3.1498576e-01 1.4717017e+00 -2.1585672e-01 -2.8411748e-01 -2.5035775e-01 2.7425637e-01 1.1741888e+00
+1 5.4948659e-01 1 1 -1.0969699e+00 -3.8204120e-01 1.1312604e+00 6.3566422e-01 5.8369762e-02 -1.1700970e+00 7.1044800e-01 -8.9380901e-01
+1 8.0481829e-01 1 1 1.2339569e+00 4.4894876e-01 1.7516681e-01 -9.4802054e-01 8.4368378e-01 5.4907805e-01 -6.9407087e-01 8.4809861e-01
+1 3.6440615e-01 1 1 1.4598111e+00 -6.2367591e-01 3.5620532e-01 7.7674475e-01 -1.3559923e+00 1.4971655e+00 -5.1566799e-01 5.8741261e-01
+1 4.6637786e-01 1 1 -7.9363640e-01 1.3736556e+00 -1.1328119e+00 1.4315784e+00 -1.0488304e+00 -1.2957759e+00 8.2229773e-01 -1.3819480e+00
+1 9.1107387e-01 1 1 5.5545007e-01 -5.3468853e-01 -1.1180798e+00 -9.1958516e-01 -2.1579515e-01 -5.8519655e-01 4.9184895e-01 -6.0583046e-01
+1 5.1113201e-01 1 1 -1.3641012e+00 -1.5550684e+00 1.4403194e+00 1.1680597e+00 -1.4710997e+00 9.2816486e-01 9.7499683e-01 -2.9073496e-01
+1 3.8279523e-01 1 1 8.9359852e-01 -1.1250089e+00 1.4772118e+00 -2.3298772e-01 -4.3773991e-01 -1.4823529e+00 2.2436754e-01 -1.2059343e+00
+1 7.4398571e-01 1 1 -1.2442199e+00 1.2212529e+00 -5.0819529e-01 -1.4001525e+00 5.1536595e-01 -1.0746699e+00 1.0341406e+00 1.4186410e+00
+1 7.7780354e-01 1 1 -1.1626671e+00 -1.5691356e+00 7.5210725e-01 1.3072440e+00 3.8465019e-01 -9.6132314e-01 1.5113308e+00 1.5529547e+00
+1 8.3031735e-01 1 1 -2.3967523e-01 1.2075313e+00 -1.1023333e+00 -1.4492142e+00 -5.8190101e-01 2.5303555e-01 1.1602544e+00 1.5737360e-01
+1 1.0142900e+00 1 1 -6.9975787e-01 2.9058322e-01 -9.4339968e-01 -1.7548582e-01 -2.3235493e-01 -9.4803507e-01 5.3000640e-01 -2.4288722e-01
+1 3.8623980e-01 1 1 1.2923130e+00 -1.3443797e+00 -1.0023916e-01 5.6538281e-01 -1.8961101e-01 5.3259322e-01 1.4024360e+00 -1.2766029e+00
+1 6.5208385e-01 1 1 -1.0672142e+00 -6.5547009e-01 -8.2586299e-01 -9.2880692e-01 -1.2173007e+00 8.9676543e-01 -6.2752969e-01 1.2127174e+00
+1 9.7843967e-01 1 1 -1.3167259e+00 1.0795596e+00 -7.2289040e-01 1.1597727e-01 -1.1208023e+00 -1.4249084e+00 -5.6491803e-01 -5.1252841e-01
+1 9.2907032e-01 1 1 -8.3328453e-01 1.4607547e+00 -1.0802165e+00 1.4425073e+00 -3.3519177e-01 -7.5414080e-02 -6.8425299e-01 1.8212236e-01
+1 8.5809100e-01 1 1 2.0687083e-01 -6.4210125e-01 6.5122908e-02 5.4955829e-01 -6.9247449e-01 -1.4226068e+00 1.1306762e+00 1.0193178e+00
+1 4.6777228e-01 1 1 -8.6496260e-01 -4.2488958e-01 1.2464705e+00 1.4374715e-01 1.1819757e+00 9.0979698e-01 -2.1937257e-01 5.7035974e-01
+1 1.5466887e-01 1 1 -1.2772529e+00 -2.7908895e-01 1.2899548e+00 7.3534103e-02 1.1744491e+00 8.2645776e-01 1.2349101e+00 1.0370091e+00
+1 6.1765171e-01 1 1 -2.8682285e-01 -2.5011572e-01 1.3869751e-01 1.2417598e+00 3.3899227e-01 1.2945318e+00 -1.3687573e+00 -5.4425545e-01
+1 9.0136538e-01 1 1 -1.4285361e+00 -2.4399730e-01 2.7323716e-02 6.5612505e-01 -1.4059881e+00 -1.4739373e+00 1.1797259e+00 1.0165080e+00
+1 1.0497682e+00 1 1 -1.3556679e+00 -1.0841335e+00 5.5716865e-01 5.0342977e-01 6.1784737e-01 -1.0068483e+00 1.0616433e+00 4.6963878e-01
+1 2.6940252e-01 1 1 1.2618028e+00 2.0565249e-01 -7.5417773e-01 8.3520687e-01 1.1970510e+00 -1.4805632e+00 -1.2069873e+00 1.5382193e+00
+1 6.1745625e-01 1 1 1.3692035e+00 6.4942063e-01 8.6120243e-01 6.8594959e-01 7.7496452e-02 7.2992416e-01 -5.7165268e-01 6.8502441e-01
+1 3.8881380e-01 1 1 3.7482921e-02 9.1959564e-01 9.1194454e-01 -8.9029925e-01 -1.2780835e+00 -8.3951410e-02 -7.7633046e-01 -7.3173983e-01
+1 1.1800252e+00 1 1 -1.4846630e+00 -9.9189196e-01 -7.7867321e-01 1.4627467e-01 1.4606639e+00 -3.9624186e-01 -7.5177345e-01 9.8393594e-01
+1 8.2656775e-01 1 1 9.3915470e-01 -1.4375477e+00 7.1429611e-01 -1.4286337e+00 9.7370414e-01 5.3947475e-01 4.2922403e-01 -3.3236432e-01
+1 4.4935888e-01 1 1 1.0116124e+00 1.1241119e+00 1.1491533e+00 1.4588051e-01 4.8937353e-01 3.1568864e-01 8.7152200e-01 -2.9545241e-01
+1 6.1999664e-01 1 1 -1.3062517e-01 -5.9034753e-01 -6.9139162e-01 1.3714993e+00 2.1139492e-01 -3.7108330e-01 1.5653688e+00 1.1893419e+00
+1 1.9073289e-01 1 1 5.5607660e-01 -8.2135284e-01 5.3220772e-01 9.2370566e-01 -2.2682597e-01 -7.3556618e-01 1.4560695e+00 -6.8397313e-01
+1 4.8833873e-01 1 1 -2.5874405e-01 -3.1909499e-01 7.0081324e-01 -1.0298722e+00 -1.5122107e+00 -4.9374942e-01 -8.4614558e-01 -4.4884255e-01
+1 6.9478208e-01 1 1 -7.4708316e-01 -3.3078383e-01 7.3719740e-01 1.1133175e+00 -2.3988318e-01 -1.5003114e+00 8.2117485e-01 -7.3283219e-01
+1 9.5816071e-01 1 1 7.1917626e-01 1.1351981e+00 -3.6470307e-01 2.0211934e-01 -1.0531956e+00 -1.3112437e+00 4.6920438e-01 1.4741817e+00
+1 4.0137766e-01 1 1 1.4885218e+00 3.8274371e-01 -3.1728118e-01 9.5809421e-01 -1.3262327e+00 1.9972740e-01 5.2051151e-01 -1.1693050e+00
+1 9.8685828e-01 1 1 1.0840975e+00 -1.2081463e+00 -1.2620925e+00 -1.1146011e+00 -3.9283798e-01 -1.5441019e+00 -1.0985697e+00 1.2939326e+00
+1 1.1694897e+00 1 1 -8.1133515e-01 -1.2017994e+00 4.4375763e-02 2.1628659e-01 1.1998386e+00 9.7659272e-01 -5.2176190e-01 1.0212440e+00
+1 3.0111823e-01 1 1 1.5438097e+00 -1.3428746e+00 1.2659862e+00 3.0599511e-01 -1.9636955e-01 -1.2276953e+00 -1.0671253e+00 1.5271562e+00
+1 1.1014618e+00 1 1 3.9513904e-01 -4.9229303e-01 -5.7773606e-01 7.2637513e-02 1.4307783e+00 1.0618696e-01 1.7675372e-01 1.0272315e-01
+1 7.9315523e-01 1 1 -2.2500333e-01 9.8616957e-01 6.5291659e-01 -1.2608629e+00 1.3401035e+00 2.5968223e-01 -1.2469462e+00 -1.4080464e+00
+1 9.8216212e-01 1 1 8.4653120e-01 -4.9082985e-01 -1.3963257e-02 -1.2807347e+00 1.0419544e+00 8.0703075e-01 1.3926618e-01 5.8170056e-01
+1 2.0930304e-01 1 1 -6.2332943e-01 4.4497070e-01 9.3899144e-01 8.8464242e-01 8.8971345e-01 1.5103723e+00 1.6018085e-01 4.9022963e-03
+1 5.8691539e-01 1 1 9.1369335e-01 -1.5095908e+00 1.4092417e+00 -9.7294614e-01 -5.6702408e-01 7.5942897e-01 -1.8543984e-01 7.1148444e-01
+1 6.0329970e-01 1 1 3.3932152e-01 -1.9113554e-01 6.5887414e-01 -3.1600074e-01 -1.5231494e+00 -5.6823841e-01 -2.2745950e-01 1.0172803e+00
+1 1.1637506e+00 1 1 9.8617644e-01 1.4342272e+00 -4.1644201e-01 1.4087233e+00 1.2666512e+00 5.8676700e-02 4.0639934e-01 8.8305703e-01
+1 7.8803481e-01 1 1 -3.7544182e-01 -3.8305079e-01 3.2756262e-01 1.3705649e+00 1.1743645e+00 -2.8079846e-01 5.3127327e-01 6.5582534e-01
+1 3.6689223e-01 1 1 1.4089362e+00 -8.1129989e-01 1.2746497e+00 9.2773413e-01 -1.0820778e+00 -7.0754902e-01 7.0348940e-01 -1.3921212e+00
+1 6.3911263e-01 1 1 -1.3343620e+00 -1.0051562e+00 5.1763241e-01 7.0314774e-01 1.9766516e-01 -8.4820706e-01 -1.4083249e+00 1.2009470e+00
+1 6.9941831e-01 1 1 1.2070903e+00 -1.3160626e+00 7.7784911e-01 -8.6744598e-01 1.4949583e+00 7.3132945e-01 -9.5780225e-01 -4.1721267e-01
+1 2.1274605e-01 1 1 -8.3825895e-01 8.9051611e-01 1.1429482e+00 9.6690938e-01 -6.9316603e-01 1.5436227e+00 -2.6172848e-01 -5.8490005e-02
+1 4.0478577e-01 1 1 1.4248146e+00 3.5685037e-01 -1.3082967e+00 -6.1292086e-01 -1.0158429e+00 3.9415970e-01 -6.4089815e-01 2.7698329e-01
+1 1.1954874e+00 1 1 -1.5012442e+00 2.8372171e-01 -5.3554735e-01 -7.8585915e-02 1.2851664e+00 -9.7683654e-01 9.4607138e-01 -5.8224047e-01
+1 1.3413810e+00 1 1 -1.2812511e+00 -4.2692455e-01 -2.8140277e-01 -1.3245560e+00 1.3422782e+00 2.7147613e-01 1.0211954e+00 3.4557701e-01
+1 8.7220481e-01 1 1 -1.5107389e+00 7.6636053e-02 -1.4393519e+00 -4.8692160e-01 -1.0713203e-01 1.1067094e+00 7.1046566e-01 -6.9194705e-01
+1 1.0450054e+00 1 1 -6.3704986e-01 -3.0849224e-02 -9.2404368e-01 1.5745845e-01 -4.3541125e-01 -9.0502289e-01 -3.9732718e-01 6.2188992e-01
+1 1.0917242e+00 1 1 -3.4922365e-01 -1.2012496e-01 -1.5095946e+00 1.1832233e+00 -1.1875773e+00 8.7187755e-01 1.1480098e+00 2.5056995e-02
+1 6.9568265e-01 1 1 -9.0683473e-01 1.1037960e+00 -2.5476738e-01 1.5215535e-01 -1.0737135e+00 1.2578230e+00 -1.0606674e+00 1.5949485e-01
+1 8.4729329e-01 1 1 -1.3054103e+00 3.9531637e-01 1.1540012e-01 1.8591568e-02 -5.9504282e-01 4.5375928e-01 -1.2409210e+00 8.5144627e-01
+1 5.1423509e-01 1 1 8.5234148e-01 -3.8627535e-01 1.1670932e+00 1.4508157e+00 -1.1952706e+00 -1.4546858e+00 8.7380087e-01 3.0298622e-01
+1 9.7805275e-01 1 1 -3.5929248e-01 1.5422431e+00 -7.6901851e-01 -1.1835142e+00 -1.5692718e+00 -1.0299696e+00 -9.7440203e-01 -2.3225194e-01
+1 1.0129319e+00 1 1 -4.8766830e-01 -8.0075230e-01 -3.8189693e-01 1.2415083e+00 -1.0815675e+00 -5.2402214e-01 3.4761812e-01 1.5412586e+00
+1 6.5520842e-01 1 1 1.7407145e-01 3.3906769e-01 -2.6794625e-01 -4.2920182e-01 -6.5068166e-01 -1.3558776e+00 -9.4455307e-01 1.5022879e+00
+1 9.7251485e-01 1 1 7.9614554e-01 -1.3846546e-01 -1.4702864e+00 -4.9826275e-01 -1.2261961e-01 8.7886031e-01 -6.3572488e-01 -2.7947288e-02
+1 6.9596545e-01 1 1 7.7501121e-01 7.3111547e-01 6.6508064e-01 1.1840331e+00 1.7043718e-02 -7.6348156e-01 -7.1416608e-02 1.5288314e+00
+1 8.9125612e-01 1 1 5.7029931e-01 1.0888854e+00 2.2372261e-01 1.1966795e+00 5.6882992e-01 -1.5701518e+00 -2.1054177e-01 -1.6365727e-02
+1 7.4575005e-01 1 1 2.1333795e-02 1.1192515e+00 -3.8047515e-01 1.1620510e-01 4.5793845e-01 -1.6240111e-01 -1.1421399e+00 1.4013843e+00
+1 8.5531742e-01 1 1 4.1553125e-01 -5.9754208e-01 -1.5047680e+00 -1.0114575e+00 -3.3049982e-01 5.6860838e-01 -8.1385082e-01 5.4565193e-01
+1 8.5126121e-01 1 1 7.3230529e-02 7.8199694e-01 -8.1489937e-01 -4.0823346e-01 -3.7464030e-01 -1.2389042e-01 1.0366459e-01 4.6300155e-01
+1 8.0909774e-01 1 1 -7.1882455e-01 -1.4011668e+00 1.3302989e+00 5.8542926e-02 -8.2786171e-01 6.4960472e-01 -1.2931463e+00 -5.7988252e-02
+1 7.0404794e-01 1 1 1.2812047e+00 -3.2495287e-02 -3.8098991e-01 6.1246100e-01 2.4215618e-01 8.7201514e-01 -3.7132085e-01 -7.1483022e-01
+1 5.9149336e-01 1 1 7.3206025e-01 4.8884056e-01 -7.3160903e-01 -1.3671615e+00 1.5563980e+00 4.2868710e-01 1.5550900e+00 -7.0125929e-01
+1 6.4177216e-01 1 1 1.2598691e+00 6.7849163e-01 4.0665990e-02 -2.7479566e-01 1.4804871e+00 1.2721839e+00 1.4882366e+00 1.1907024e+00
+1 1.3175235e+00 1 1 2.8465162e-01 -5.7256419e-01 -1.3939082e+00 -3.4942076e-01 1.1334012e+00 -8.4455755e-02 -5.6860511e-01 1.9051764e-01
+1 5.5351066e-01 1 1 -5.0587042e-01 -3.8812599e-01 -5.5855408e-01 -1.0780071e+00 -1.5436065e+00 5.5200302e-01 1.7874461e-01 7.4709766e-01
+1 9.3723961e-01 1 1 -1.0143695e+00 -1.2871727e+00 -5.3964883e-01 -5.0080276e-01 -1.2242126e-01 3.9158201e-01 7.9805798e-01 -4.7544271e-01
+1 8.1090408e-01 1 1 9.1502113e-01 -5.0488869e-01 -9.9857482e-02 -6.6531779e-01 2.0913986e-01 -3.1779060e-01 1.5013759e+00 1.4460206e+00
+1 7.9605456e-01 1 1 6.6404107e-01 -2.2253282e-01 -6.9423107e-01 -1.0677992e+00 -4.2849010e-01 -3.9914088e-01 3.5182375e-01 -9.2739880e-02
+1 3.9204624e-01 1 1 -1.5404912e+00 1.5277166e+00 -6.6528282e-02 1.4169765e+00 -1.1027572e+00 -1.0604055e+00 6.2441651e-01 -4.4920453e-01
+1 6.5274578e-01 1 1 -1.1704993e+00 9.5949202e-02 2.6614659e-01 -1.2898162e+00 1.3558662e+00 2.0327707e-02 -1.4927975e+00 -5.3339659e-01
+1 8.2353055e-01 1 1 7.0888647e-02 9.8120240e-01 -5.0218958e-01 -9.5172872e-01 -1.0700263e+00 -7.8583091e-01 -6.8854048e-01 1.3089050e+00
+1 2.6097203e-01 1 1 7.6187444e-01 8.4884549e-01 1.1592625e+00 1.2851202e+00 -1.4554342e+00 -2.0456900e-01 1.3274451e+00 1.3348669e+00
+1 1.0257649e+00 1 1 -3.0798698e-01 5.7394678e-01 -4.3253966e-01 5.6640249e-01 -1.0417057e+00 -1.2887636e+00 -1.2207057e+00 9.9424831e-01
+1 3.3530073e-01 1 1 1.0075021e+00 -1.5074623e+00 -4.8634529e-02 5.0094633e-01 1.4739779e-01 1.0321477e+00 1.3411501e+00 2.0006598e-01
+1 9.2757315e-01 1 1 -9.7414848e-02 1.0253475e+00 -5.8644627e-01 -6.3280761e-02 -1.4019814e+00 -5.6819392e-01 -2.1779900e-01 1.0048065e+00
+1 6.0520026e-01 1 1 -4.8158059e-01 1.3793447e+00 -1.2263676e+00 1.4401671e+00 -1.1568543e+00 8.0642458e-01 -5.9232978e-01 -1.4197336e+00
+1 6.1495678e-01 1 1 -1.1822252e+00 8.3366496e-01 4.2879200e-01 -1.0829617e+00 6.7020629e-02 7.4717153e-01 4.2042340e-01 -1.0662986e+00
+1 1.7182851e-01 1 1 9.1478823e-01 -9.6285617e-02 -1.0635437e-01 1.0508886e+00 -1.4160562e+00 7.6604202e-01 6.1416541e-01 1.5047690e+00
+1 1.0043506e+00 1 1 -1.0863415e-01 -3.5215353e-01 6.8340611e-02 2.5014709e-01 1.0492583e+00 6.2146785e-01 -9.9546400e-01 8.3206128e-01
+1 1.1824306e+00 1 1 -5.4879911e-01 1.1613560e-01 -1.2222638e+00 7.7119741e-01 1.1240158e+00 -7.8535552e-01 1.3590169e+00 1.2249975e+00
+1 9.3156664e-01 1 1 4.9418393e-02 9.6196965e-01 2.8589790e-01 -6.9635356e-01 9.3691912e-01 1.5020739e+00 -1.5232401e+00 -1.4646490e+00
+1 9.2993211e-01 1 1 1.1944727e+00 1.1881591e+00 -1.5507844e+00 -1.1816872e+00 1.1372539e+00 -4.8275835e-01 -2.5773462e-01 1.1644956e+00
+1 7.3271979e-01 1 1 7.2596987e-01 1.4268234e+00 -1.3811561e+00 5.3222254e-01 3.7632998e-01 1.0142087e+00 5.1046090e-01 -4.4426101e-01
+1 9.6795733e-01 1 1 -5.7032331e-01 8.4362625e-01 1.3732759e-01 9.4998057e-01 9.5189170e-01 -4.7529835e-01 -3.7324271e-01 8.7087089e-01
+1 9.6186156e-01 1 1 -4.2461410e-01 8.1870623e-01 -1.0057549e+00 7.4959112e-01 1.4540485e+00 7.3082210e-01 6.7038337e-01 4.6920958e-02
+1 3.7729861e-01 1 1 1.2092969e+00 -1.8023885e-01 1.1873309e+00 5.9139392e-01 -2.5593184e-01 -7.0025193e-01 1.3820108e+00 6.0783318e-02
+1 7.4398208e-01 1 1 -1.4508021e+00 -7.7906801e-01 7.4392911e-02 -4.4157229e-01 -6.0611284e-01 -7.2811256e-01 -1.4804276e+00 5.6761321e-01
+1 8.4731225e-01 1 1 1.4116594e+00 3.6221478e-01 -3.2225500e-02 -1.0635943e+00 1.2463953e+00 -8.8441030e-01 -1.3356012e-01 -1.1415857e+00
+1 9.2392400e-01 1 1 4.5223801e-01 -6.6271323e-01 -1.2600353e+00 -1.6801397e-01 2.6489013e-02 -1.4091255e+00 1.4938275e+00 -9.2480100e-01
+1 7.0998803e-01 1 1 1.2516225e+00 -1.2753492e+00 6.3606541e-02 4.8103007e-01 -9.0531440e-01 1.2949774e+00 -8.5013081e-01 1.4699845e+00
+1 5.6847552e-01 1 1 -8.4269843e-02 2.9187068e-01 8.9362728e-01 1.3544714e+00 -8.8591099e-01 -2.6882547e-01 -1.8521768e-01 5.4557995e-01
+1 3.1622523e-01 1 1 5.3503365e-01 1.4444550e+00 -7.6078508e-01 6.2079930e-01 -1.4984670e+00 -5.3951472e-01 3.6474519e-01 -7.4666726e-01
+1 9.6165381e-01 1 1 1.0724613e+00 -1.2727233e+00 -2.3278561e-01 5.4463537e-01 1.4134304e+00 -9.8756022e-01 1.0251977e+00 1.4259780e+00
+1 6.8162671e-01 1 1 1.5393949e+00 4.4457327e-01 -1.1449409e+00 -9.1438083e-01 -1.1987645e+00 -8.9057654e-01 -1.1380961e+00 -7.9728658e-01
+1 5.2375346e-01 1 1 -1.5467168e+00 1.2356634e+00 -7.6606471e-01 6.7258393e-01 -6.0133995e-01 -1.3725502e+00 1.1759339e+00 -1.1028821e+00
+1 8.8047057e-01 1 1 1.0093765e+00 -1.2742112e+00 -1.0028655e+00 6.6772559e-01 -2.1697439e-01 2.6282684e-01 1.6217665e-01 -7.4236176e-01
+1 8.9985393e-01 1 1 -1.0220723e-02 5.6884591e-01 -5.1579689e-01 6.9495321e-01 7.0045197e-01 2.5143558e-01 -1.1994643e+00 1.5319521e+00
+1 8.6302940e-01 1 1 1.0079003e+00 7.2675101e-01 -1.3442336e+00 -3.6292947e-01 9.4858241e-01 4.3560139e-01 2.0440129e-01 -9.7472488e-01
+1 7.0306433e-01 1 1 3.1320875e-01 -8.0537568e-03 -1.3420244e+00 1.2173447e+00 -7.5816923e-01 1.2416897e+00 -1.5298466e+00 1.2046647e+00
+1 5.2807788e-01 1 1 -1.2097747e+00 -2.7100683e-01 1.2308150e+00 -1.2798039e+00 -2.5039900e-01 -5.2071977e-01 -1.3381997e+00 -7.6525461e-01
+1 1.1106251e+00 1 1 -2.9581970e-01 4.9755210e-01 -1.0794706e+00 8.2000634e-01 1.2781102e+00 7.4001783e-01 -4.6011367e-01 4.6158122e-02
+1 5.9114981e-01 1 1 1.2995258e+00 -5.6144240e-01 3.5454072e-02 -3.2039071e-01 -1.0128069e+00 -8.5724444e-02 1.4706856e+00 -1.9382579e-01
+1 3.7779124e-01 1 1 7.7755809e-01 1.1818703e+00 -1.0260157e+00 -1.1689476e-01 -1.0968199e+00 1.2202893e+00 -2.3759018e-01 2.0145532e-01
+1 1.1096653e+00 1 1 -6.0660358e-01 -5.9676826e-01 -4.4239629e-02 -1.1548647e+00 6.1314888e-01 1.0856007e+00 -2.1388541e-01 -7.7731163e-01
+1 7.6959722e-01 1 1 -7.1829089e-01 1.2212072e+00 1.0220063e+00 -1.0521389e+00 7.6926260e-01 -6.7837583e-01 -7.9007393e-01 -1.5342424e+00
+1 1.1312901e+00 1 1 8.2556570e-01 8.0506391e-01 -1.3687525e+00 7.2614386e-01 1.3428122e+00 -6.2284815e-01 7.3965278e-01 1.8063062e-01
+1 6.9336467e-01 1 1 -1.1319687e+00 -1.3049100e-01 1.2598804e+00 -7.8758052e-01 -5.5628003e-01 -4.2214515e-01 6.2200834e-02 1.0803029e+00
+1 1.8541715e-01 1 1 4.8789454e-01 -3.3054430e-01 4.7476034e-01 -1.3359638e+00 -1.8719073e-02 -1.2773941e+00 -7.4092959e-01 1.3863616e+00
+1 8.9516020e-01 1 1 4.8673171e-01 -1.1221669e+00 -3.4823182e-01 -5.8076399e-01 -4.5219977e-01 4.8145954e-01 4.6969991e-01 -6.1254347e-01
+1 9.4801505e-01 1 1 -2.0741563e-01 -1.2782810e+00 5.4875360e-02 2.8073068e-02 -6.0888687e-01 -8.5217422e-01 -5.7601916e-01 -1.8896335e-02
+1 7.5851083e-01 1 1 1.1334188e+00 1.2832464e+00 -1.3380662e+00 5.8515695e-01 -1.3944155e+00 2.8737154e-02 1.2346139e+00 -2.8984591e-01
+1 1.0538711e+00 1 1 -1.2480922e+00 4.8837942e-01 -1.3582660e+00 1.5478506e+00 3.4061461e-01 -8.1992344e-01 -6.3263584e-02 1.1699165e+00
+1 5.6407795e-01 1 1 -2.7109495e-01 -7.8874507e-01 -1.5642772e+00 -8.0449109e-01 7.2798112e-01 -1.4279400e+00 -1.4127465e+00 -4.4216848e-01
+1 6.9143810e-01 1 1 -9.8351093e-01 1.0826898e+00 1.1824674e+00 3.3302843e-01 -1.3246570e+00 -7.6179953e-01 1.2708741e-01 1.4826301e+00
+1 8.8038687e-01 1 1 1.1923694e+00 6.6346673e-01 1.4311158e-02 -1.1092100e+00 9.5637954e-01 1.5670024e+00 -3.2485290e-01 -5.4799946e-01
+1 1.1973298e+00 1 1 -6.7833495e-02 1.3730179e+00 -1.3750057e+00 -2.8167665e-01 1.4828881e+00 6.3862860e-01 2.8532952e-01 9.2281518e-01
+1 1.0408025e+00 1 1 3.2058725e-01 1.3130118e+00 -1.6513432e-01 2.4063039e-01 6.4659321e-01 -1.3912969e+00 1.4627702e+00 -2.8815205e-01
+1 7.6775662e-01 1 1 2.7847811e-01 1.2424750e+00 -1.3861932e+00 1.0452374e+00 5.2313907e-01 -6.5361736e-01 -1.3252794e+00 1.3643152e+00
+1 6.8512968e-01 1 1 -5.9139553e-01 1.1095963e-01 3.0278896e-01 -4.8171588e-01 -9.1955879e-01 8.0259176e-01 -7.9494042e-02 -4.3881204e-01
+1 8.5834457e-01 1 1 4.1442795e-01 -1.2075477e+00 -4.0600599e-01 -3.1461025e-01 -1.5302983e+00 -8.3909119e-01 -8.7948117e-01 1.3456044e+00
+1 1.0263404e+00 1 1 3.7961273e-01 -5.6554260e-01 -2.0343498e-01 -3.5402002e-01 4.9494084e-01 3.7611222e-03 -2.4664916e-01 -7.5220441e-01
+1 8.3293094e-01 1 1 -4.2347160e-01 1.3849540e+00 -1.0789853e+00 1.6208151e-01 -4.6664959e-01 3.8132696e-01 1.4699308e+00 -5.3065447e-01
+1 4.9353748e-01 1 1 1.5618042e+00 8.6181585e-01 -1.2336546e+00 3.4309568e-01 -1.5643973e+00 1.1318186e-01 -3.5770696e-01 2.7192409e-01
+1 4.5419859e-01 1 1 1.2372479e+00 -1.3447895e+00 4.7862008e-01 -1.5550536e+00 -8.3663874e-01 -1.5575480e+00 1.0275132e+00 -7.8907945e-01
+1 8.1678023e-01 1 1 2.2447226e-01 -1.2597430e+00 -1.4510823e+00 -8.7680049e-01 3.8136756e-01 1.1821705e+00 8.0349717e-02 -1.3957514e+00
+1 5.5470890e-01 1 1 -3.4752022e-01 -1.3075105e+00 -1.5700388e-01 8.2532206e-01 7.9565056e-01 1.3078062e+00 -4.4714541e-01 -1.2169526e-01
+1 1.0266442e+00 1 1 -5.5163528e-01 1.1090899e-01 1.7361660e-01 1.0563799e+00 -1.2610272e+00 -1.4241722e+00 -4.8325962e-01 -1.5543210e-01
+1 1.1130528e+00 1 1 -4.9424213e-01 1.0829322e+00 -5.6543968e-01 1.4371245e+00 -9.0093109e-01 -2.6841611e-01 -1.1274812e+00 1.4578254e+00
+1 8.0796697e-01 1 1 -3.5657320e-01 -1.5459531e+00 -2.6850863e-02 1.1867592e+00 5.2778586e-01 5.7455753e-02 5.1058736e-01 3.9018766e-01
+1 4.9299737e-01 1 1 1.2330625e+00 1.2786642e+00 1.1068891e+00 -1.0977784e-01 -1.3606843e+00 1.1898932e+00 -1.3893155e+00 1.3801161e+00
+1 6.2073013e-01 1 1 -1.0057832e+00 -1.1267076e+00 -1.0267586e+00 -9.2124668e-01 -1.3675497e+00 -8.4380279e-01 1.2318155e+00 1.2329947e+00
+1 8.1135952e-01 1 1 7.1240333e-01 9.4640461e-01 3.6890350e-02 1.5172362e+00 -5.1616053e-01 -6.4428003e-01 2.7648589e-02 9.9690282e-01
+1 4.3961967e-01 1 1 7.5324153e-01 3.3871841e-01 1.1223658e+00 -1.1878491e-01 -1.1727538e+00 6.5545083e-01 -2.6587373e-01 8.3214646e-01
+1 5.5037886e-01 1 1 -8.8800639e-01 2.7448594e-01 1.4794990e+00 -1.5067162e+00 -1.2017837e-01 -1.4033247e+00 -1.1949792e+00 -4.8495249e-01
+1 3.9897174e-01 1 1 9.8322453e-01 1.4271134e+00 2.3433947e-01 9.9973554e-01 2.0618878e-01 1.3993692e+00 1.8610714e-01 -1.3050868e+00
+1 8.3317072e-01 1 1 2.7736725e-01 -5.6447008e-01 -1.0136862e+00 1.3177073e+00 2.3813701e-01 1.2362309e+00 -1.1235043e+00 5.5478016e-03
+1 1.0052938e+00 1 1 -4.1215407e-01 5.6115740e-01 -1.6634335e-01 -1.5219298e+00 -2.0271554e-02 -1.1614173e+00 1.3762916e+00 -1.0058788e+00
+1 5.3036847e-01 1 1 1.3831737e-01 3.1132258e-01 2.8483554e-01 -2.2685747e-01 -1.4120042e+00 -1.2256781e+00 -2.1427621e-01 -8.9491530e-01
+1 1.0716812e+00 1 1 -7.8442397e-02 -1.4946996e+00 -5.5635222e-01 1.0999199e+00 3.6368400e-02 -5.4962560e-01 -1.0750566e+00 1.1041999e+00
+1 1.3249556e+00 1 1 1.0875530e+00 -1.2414666e+00 -1.2320022e+00 1.2218060e+00 -1.3668651e+00 -1.2749826e+00 -1.1770681e+00 8.9917487e-01
+1 1.0140225e+00 1 1 7.1683616e-01 1.1298405e+00 -2.3980938e-02 1.4443449e+00 1.5648931e+00 1.7121268e-01 -3.7433985e-01 1.3714497e+00
+1 6.4564071e-01 1 1 -1.4247373e-01 1.4432881e+00 -9.2376568e-01 1.8554830e-02 -2.5603172e-01 -1.2733904e-01 1.0802780e+00 8.9361437e-02
+1 9.5192463e-01 1 1 -6.6232977e-01 1.1070087e+00 2.1155108e-02 8.3335569e-01 8.5675976e-01 -7.6268682e-01 9.6764054e-01 2.1638864e-01
+1 7.0882766e-01 1 1 -1.1137209e+00 9.8408623e-01 5.5393711e-01 9.8897993e-01 -1.4994297e+00 -7.7934359e-01 -8.9067519e-01 -1.1203654e+00
+1 7.8842979e-01 1 1 -6.9764276e-01 -9.4810733e-01 1.4819365e+00 -3.8098701e-01 9.4076100e-01 -1.1280151e+00 1.1104942e-01 7.2495359e-01
+1 9.4091073e-01 1 1 -8.5816351e-01 -6.8194387e-01 3.6039361e-01 -6.8292625e-01 -2.6570877e-01 9.6103849e-01 3.0156941e-01 1.1986323e+00
+1 2.9091351e-01 1 1 -1.0222938e-01 -9.0060541e-01 1.4484777e-01 1.4381109e+00 -1.5641857e+00 1.2460582e+00 1.0880682e+00 1.5211045e+00
+1 7.9619556e-01 1 1 2.8206019e-01 -2.8168435e-01 -2.7779362e-01 -1.0843421e+00 -4.2217538e-01 6.4435067e-01 -4.9290850e-02 -1.0780704e+00
+1 4.6667944e-01 1 1 -7.7772651e-02 1.1130138e-01 -4.7069253e-01 -1.5875121e-01 1.3562011e+00 5.3186816e-01 9.4914332e-01 -1.5642019e+00
+1 1.1670756e+00 1 1 -2.2239929e-01 1.3946904e+00 -3.9896806e-01 -9.1937289e-01 1.4168976e+00 1.2769995e+00 -7.5574753e-01 -6.9465144e-01
+1 1.0042937e+00 1 1 6.3037565e-01 1.1393624e+00 -1.2974800e+00 -1.5475382e+00 5.2521978e-01 -8.3071333e-01 -3.8971520e-01 -8.4846875e-01
+1 6.3238534e-01 1 1 1.2730673e+00 1.2571477e+00 -9.5214872e-01 -2.2820689e-01 -5.0651380e-01 -5.6119503e-01 2.7727848e-01 -5.2517395e-01
+1 1.0757605e+00 1 1 -9.4461276e-01 -1.4713865e+00 5.0949870e-01 4.1143174e-01 7.3864526e-01 -9.4378078e-01 1.2374588e+00 1.2768082e+00
+1 5.1293758e-01 1 1 1.5025845e+00 1.0250139e+00 -8.3686400e-01 2.8777192e-01 -1.1632568e+00 -2.2225745e-01 6.2676493e-01 -9.0400382e-01
+1 1.0159066e+00 1 1 -1.3263107e+00 -1.0853277e+00 -2.6296213e-01 -1.4700076e+00 -7.2666272e-01 -1.2733422e-01 2.7795207e-01 -8.5006722e-01
+1 4.9684900e-01 1 1 1.4382535e+00 -1.0159900e+00 6.1632689e-01 -9.3268184e-01 1.4918706e+00 -6.8167178e-01 -7.7797845e-03 8.8368904e-01
+1 3.4408302e-01 1 1 1.3125965e+00 -1.1881157e+00 7.7501926e-01 9.6363656e-01 8.1757060e-01 5.3073803e-01 1.1920542e+00 -1.2883554e+00
+1 4.4091155e-01 1 1 5.4607363e-01 -6.9719630e-01 7.0548009e-01 9.2961125e-01 -4.1716142e-01 1.1324758e+00 9.1817327e-01 -1.5327590e+00
+1 7.9378434e-01 1 1 1.2673164e+00 3.6231540e-01 6.3318790e-01 8.3600042e-01 8.0275268e-01 -1.3882926e+00 2.3504571e-01 -2.0206759e-02
+1 3.8400817e-01 1 1 -2.1107064e-01 1.0283496e+00 1.4147507e+00 1.4566700e+00 -1.2760848e+00 -4.2512053e-01 1.4313327e+00 -3.2298509e-01
+1 1.2854628e+00 1 1 -6.0622342e-01 -1.5706812e+00 -9.9985799e-01 -1.7947436e-01 4.9603533e-01 -1.0190631e+00 1.2338003e+00 2.6165967e-01
+1 7.0800775e-01 1 1 -6.1210679e-01 3.6365586e-01 -2.3416699e-01 -4.9660152e-01 -9.2104712e-01 5.6960002e-01 -1.1711245e+00 -5.1571135e-01
+1 5.2654616e-01 1 1 1.0370446e+00 1.5662653e+00 7.7103030e-01 8.2989000e-01 -1.4120250e+00 8.3479544e-01 -1.0119220e+00 9.3506632e-02
+1 8.8865805e-01 1 1 5.2575803e-02 8.1660781e-01 -3.6341327e-01 -7.1022039e-01 -3.1311497e-01 5.4138959e-02 1.2092276e+00 7.6963375e-01
+1 9.9575015e-01 1 1 8.5399152e-01 -8.9086350e-01 -6.3069949e-01 1.3780107e+00 -3.5565138e-01 -1.1483834e+00 5.2488710e-01 1.2974650e+00
+1 1.0321954e+00 1 1 -9.0138065e-01 8.7769430e-02 -4.3276471e-01 4.0400697e-01 1.0180999e+00 1.0647818e+00 1.8525717e-01 7.0012926e-01
+1 1.1386500e+00 1 1 -7.4476887e-01 -1.4077391e+00 -6.8952201e-01 1.1634412e+00 -1.0507766e+00 1.2761125e+00 2.9901259e-01 -1.3336279e+00
+1 9.2240363e-01 1 1 -1.2253123e+00 -5.3636441e-01 5.3890314e-01 6.8318829e-01 -1.5104698e+00 -3.0524661e-02 -1.0436429e+00 9.7964154e-01
+1 8.8710095e-01 1 1 -6.8370824e-01 -1.4472405e+00 1.3343569e-01 -1.7555901e-01 7.4406179e-01 -9.4837984e-01 -9.9417199e-01 -2.5179478e-01
+1 1.0668159e+00 1 1 8.6145778e-01 -1.5603599e+00 -4.4345540e-01 -6.6481636e-01 -1.2337705e+00 1.0211013e+00 1.0827499e+00 -1.8964669e-01
+1 1.1317764e+00 1 1 -1.0796322e+00 1.0460685e+00 -1.2971319e+00 1.0764969e+00 -1.4692076e+00 -8.7142974e-01 -1.4680073e+00 1.3246332e+00
+1 6.6813882e-01 1 1 4.6153092e-01 9.2033167e-01 -1.3839094e+00 2.5203743e-01 -5.3433283e-02 -1.4723783e-02 1.2691891e+00 -1.3567831e+00
+1 5.6509829e-01 1 1 3.5793851e-01 -1.1878199e+00 9.8717485e-01 1.1261468e+00 4.4231897e-01 7.2320562e-01 -1.5269279e-01 1.3669137e+00
+1 8.8512293e-01 1 1 -2.7735997e-01 1.1326575e+00 6.9688637e-01 -9.4570372e-01 1.0466617e+00 9.4849010e-02 3.7341563e-01 -7.4923516e-01
+1 7.3614685e-01 1 1 5.3452489e-01 -1.4767371e+00 7.1186130e-01 -1.1252324e+00 1.4661811e+00 1.3398325e+00 -9.0561387e-01 -8.9195693e-01
+1 8.0101840e-01 1 1 -1.1952384e+00 -9.3914646e-01 1.0679710e+00 6.0657543e-01 -5.4741307e-01 -3.7067815e-01 3.6404005e-01 5.5996814e-01
+1 7.3109982e-01 1 1 -1.0283766e+00 -8.7301394e-01 1.4690520e+00 2.4510899e-01 1.3533749e+00 -2.0948079e-01 -1.4013070e+00 -8.2699368e-01
+1 2.3628860e-01 1 1 1.1169233e+00 -1.5076784e+00 5.7992452e-01 9.1885760e-01 1.0412418e+00 9.8173643e-01 7.5400627e-01 -8.7688013e-01
+1 1.2064442e+00 1 1 1.1132691e+00 5.3468818e-01 -1.5706123e+00 -8.2972236e-01 1.4802424e+00 3.9954997e-01 -6.0140925e-01 -5.1325777e-01
+1 5.9730644e-01 1 1 -6.1191580e-01 1.5492904e+00 1.5229454e+00 3.8613151e-01 1.6132329e-01 -1.4887899e+00 -1.3817223e+00 4.9006986e-01
+1 8.2822517e-01 1 1 1.1054668e+00 1.4034162e+00 -1.5542442e+00 -8.1811946e-01 1.6605938e-01 6.9305370e-01 4.6686796e-02 -6.5188052e-01
+1 9.2148567e-01 1 1 2.0170350e-01 1.3826909e-01 1.5983115e-01 6.1726503e-01 1.2257897e+00 -8.7199187e-01 -7.3318447e-01 -1.4222775e+00
+1 1.0057568e+00 1 1 2.5220215e-01 -8.9004340e-01 2.2038125e-01 8.3435217e-01 -7.1738486e-01 -3.7675841e-02 -1.3049618e+00 1.6059016e-01
+1 9.7041468e-01 1 1 7.5305555e-01 1.3047978e+00 9.9961112e-03 -1.1127397e+00 3.4520817e-01 1.3838594e+00 -1.0344484e+00 4.1071926e-01
+1 4.3703018e-01 1 1 -8.7216805e-01 1.4203005e+00 1.5002302e+00 8.4703237e-02 -6.0797325e-01 1.3141972e+00 -4.0130588e-01 8.7950562e-01
+1 1.0396128e+00 1 1 1.4294635e-01 1.1700690e+00 -5.3644516e-02 4.6583181e-01 1.3945259e+00 -8.2517085e-01 2.5149779e-01 6.5745317e-01
+1 4.7977757e-01 1 1 -8.1906534e-01 -1.0196537e+00 3.3707373e-02 3.8633973e-01 1.5157730e+00 1.4851318e+00 1.4812731e+00 8.3400109e-01
+1 7.3433852e-01 1 1 4.2784090e-01 6.8204393e-02 1.0331354e+00 -4.6020681e-01 4.2209433e-01 6.5689467e-01 -1.3639725e+00 -7.3015359e-01
+1 6.9356546e-01 1 1 -3.8357962e-01 -3.7008971e-01 3.2363917e-01 -9.4662542e-02 4.2313420e-01 8.7205003e-01 -8.4831223e-02 -6.3040281e-01
+1 5.0977177e-01 1 1 -2.7447371e-01 2.5572239e-01 1.3066019e+00 -1.3474587e+00 -9.4927802e-01 1.0151425e+00 5.2469486e-01 1.4119152e+00
+1 3.2105532e-01 1 1 -1.2215639e+00 2.2744854e-01 3.2624872e-01 1.0024213e+00 -1.5081494e+00 -4.8923548e-01 9.5984967e-02 -1.5317904e+00
+1 3.9001760e-01 1 1 -5.1652406e-01 -5.9068088e-01 1.1831404e+00 -6.6644882e-01 -1.0974553e+00 -1.0327612e+00 -1.5592808e+00 5.5063960e-01
+1 9.1273680e-01 1 1 -9.9942984e-01 -1.4084283e-01 -1.2410820e+00 -1.2275178e+00 -6.4059245e-01 -3.1838579e-01 3.3313586e-01 -5.3225540e-01
+1 4.5816428e-01 1 1 6.7860231e-01 -1.5262406e+00 1.3105240e+00 -5.2773847e-02 -1.9931004e-01 -9.7769134e-01 6.9620822e-01 -1.5022351e+00
+1 6.7587219e-01 1 1 1.2876836e+00 -4.2240291e-01 2.7088943e-01 -1.0409243e+00 -8.6600337e-01 -1.5288359e+00 -1.2610821e+00 9.1463780e-01
+1 2.5824653e-01 1 1 -3.3310689e-01 6.7366278e-01 6.7088801e-01 7.1411763e-01 8.0062741e-02 -5.9264698e-02 1.3188359e+00 5.0457637e-01
+1 6.4077127e-01 1 1 -2.0938039e-01 -4.9608153e-02 4.3880632e-01 1.2910998e+00 1.0128300e+00 -1.7690560e-01 -1.4035178e+00 1.2564602e+00
+1 1.4529015e+00 1 1 -4.7243228e-01 -1.2421679e+00 -1.4417160e+00 5.3334738e-01 1.4856183e+00 -1.3058265e+00 1.2947792e+00 -4.5982524e-01
+1 8.2057091e-01 1 1 -1.3647676e+00 -1.2321226e+00 1.8290430e-01 1.0056212e+00 -5.9101979e-01 1.4079435e-01 -4.5883170e-01 3.5174503e-02
+1 7.8939459e-01 1 1 -8.8163869e-01 1.0944733e+00 -1.5465806e+00 -2.9222743e-01 4.4640768e-01 7.1136953e-01 1.0255288e+00 5.5844505e-01
+1 8.4510457e-01 1 1 1.1911655e+00 7.8727269e-01 1.5732526e-01 -1.1570708e+00 6.5064173e-01 -9.1395094e-01 1.2845566e+00 -1.2929137e+00
+1 1.0661288e+00 1 1 -1.4516044e+00 -6.9616944e-01 -1.0554471e+00 -4.2983466e-01 -5.4853894e-01 -1.5268822e+00 5.1834684e-01 3.9528131e-01
+1 6.2083163e-01 1 1 4.9312042e-01 -1.2287759e+00 -1.4676826e+00 1.4320262e+00 1.2804248e+00 1.3606821e+00 2.1886565e-01 -9.7545996e-01
+1 6.6520398e-01 1 1 3.5345092e-01 7.9278662e-01 4.4400764e-01 3.2297311e-01 1.8992768e-01 1.3308163e+00 -3.3001256e-01 1.4165252e+00
+1 7.9379529e-01 1 1 -3.0209353e-01 8.7031237e-01 1.1538986e+00 -4.6302936e-01 2.5629914e-01 -1.1094738e+00 1.5315036e+00 5.4907772e-01
+1 6.0928186e-01 1 1 -4.7226768e-01 8.4527331e-02 5.2247624e-01 -4.0944023e-01 4.9612571e-01 1.5674906e+00 9.1312230e-01 1.4916826e+00
+1 6.6431208e-01 1 1 1.4017176e+00 6.5097806e-01 5.0664206e-01 -1.3739845e+00 5.9797864e-01 -5.8133014e-01 1.6636257e-01 7.9989651e-01
+1 5.4162980e-01 1 1 -1.3611203e-01 -1.1789893e+00 1.4170923e+00 1.2894275e+00 2.7214913e-01 -6.2469379e-02 3.8191941e-02 9.8564109e-01
+1 5.0076406e-01 1 1 -5.5544247e-01 -1.2479822e+00 6.5636410e-01 7.0161078e-01 -1.4846243e-01 -6.3091267e-01 1.0070471e+00 5.1725165e-02
+1 5.7619803e-01 1 1 1.4917337e+00 -1.5643400e+00 1.3795928e+00 -1.5663795e+00 -7.8353516e-01 -8.7400361e-01 -1.4612129e+00 -8.7632060e-01
+1 1.1325623e+00 1 1 -1.4821500e+00 1.2617393e-01 -1.2794466e+00 4.0558007e-01 6.8098989e-01 7.0864244e-01 -7.7576422e-01 -5.3399728e-01
+1 9.2648775e-01 1 1 -8.0652537e-01 3.0281700e-02 5.4297334e-01 -6.7186332e-01 5.7496784e-01 3.7571330e-01 -6.5970660e-01 6.3790644e-01
+1 8.1319560e-01 1 1 7.0033404e-01 6.5196634e-03 -5.7376071e-01 -1.1228524e+00 -5.4547874e-02 1.2252674e-02 -1.0082750e+00 -9.6223259e-01
+1 7.5502117e-01 1 1 -1.0335199e+00 -3.7976027e-01 1.4931730e+00 -2.3389578e-01 5.5893667e-01 -1.4144226e+00 -3.2721520e-01 6.7585888e-01
+1 4.7456215e-01 1 1 -5.0304414e-01 1.0853403e+00 7.1619286e-01 -9.5397128e-01 6.8652485e-01 2.3071090e-01 1.4229378e+00 -8.3876159e-01
+1 1.0892004e+00 1 1 -6.3696806e-01 1.2276618e+00 -1.5296993e+00 1.2936772e+00 -6.4672567e-01 8.3270366e-01 1.5125607e+00 -7.3988898e-01
+1 5.9443419e-01 1 1 1.0255732e+00 -6.6913696e-01 1.1379345e+00 -1.2970628e-01 3.9219975e-01 -5.4490868e-01 -1.5971734e-01 -8.9036950e-01
+1 1.1251648e+00 1 1 -1.1097061e+00 7.1673317e-01 -7.5049635e-01 2.9186570e-01 6.3987089e-01 -5.3764049e-01 -1.4491585e+00 -1.0344549e+00
+1 9.9561743e-01 1 1 8.0445360e-01 1.2681264e+00 -9.7636322e-02 1.3607108e+00 6.3840599e-01 -9.0324280e-01 7.6064968e-01 -5.1022746e-01
+1 1.1935157e+00 1 1 -9.6310167e-01 8.3507626e-01 -1.0623030e+00 -1.3283496e+00 1.1506411e+00 -6.2606925e-01 1.0986549e+00 1.1550152e+00
+1 1.0411130e+00 1 1 -1.3643511e+00 -1.5092259e+00 -4.5595987e-01 -1.4143932e+00 -8.1986868e-01 -1.1520459e+00 -1.1894421e+00 4.3959226e-01
+1 1.0005933e+00 1 1 -1.6438731e-01 -3.4134744e-01 -9.7311339e-01 7.2562794e-01 -5.0756497e-01 -8.0008335e-01 -9.9890217e-01 -7.9875108e-01
+1 8.4613752e-01 1 1 -1.3976182e+00 -4.7818251e-01 1.4603762e-02 -3.3943840e-02 -1.2203980e+00 -9.8430923e-01 1.2240136e-01 -5.8391009e-01
+1 8.4132289e-01 1 1 -8.1478183e-02 -6.1944822e-01 4.0119871e-01 1.2757400e+00 2.2876478e-01 3.4171578e-01 -5.4352666e-01 5.5863841e-01
+1 2.5693732e-01 1 1 3.3057750e-01 1.7188223e-01 1.0888565e+00 -8.2648895e-03 -4.5970898e-01 3.8577527e-01 6.9892233e-01 -1.1846847e+00
+1 7.3523834e-01 1 1 -1.4614424e+00 -1.4405860e+00 6.3357923e-01 -6.7792190e-01 -1.1525420e+00 -5.2220344e-01 3.7270811e-01 4.1773686e-01
+1 8.9709443e-01 1 1 -1.4908315e+00 3.2560848e-01 -1.4329833e+00 7.2312415e-01 2.8641571e-01 9.3667537e-01 -2.3052935e-01 -5.5617946e-01
+1 1.0405712e+00 1 1 9.3843106e-01 -1.5269782e-01 -7.0061274e-01 -1.2743174e+00 8.6893829e-01 1.8211658e-01 -9.2309059e-01 -1.4700111e+00
+1 5.4727840e-01 1 1 1.4157206e+00 2.8893379e-01 -5.0913009e-01 -1.2151322e+00 -1.0183299e+00 9.2214898e-01 -1.1990045e+00 -9.9154375e-01
+1 7.9997822e-01 1 1 -4.0604713e-01 -7.9201407e-01 7.4900541e-01 7.6666713e-01 3.2533355e-01 1.0813752e+00 -1.4928700e+00 1.2731940e+00
+1 9.9689789e-01 1 1 -8.9490262e-01 -4.5241923e-01 1.7214434e-01 -1.4386173e+00 1.5097046e+00 5.5875403e-01 1.2344336e+00 1.1836362e+00
+1 5.7290153e-01 1 1 1.3173714e+00 -1.1558018e+00 -1.7697689e-01 -1.1431820e+00 -1.0389448e+00 7.5849592e-01 4.7579951e-02 8.0956132e-01
+1 8.8317614e-01 1 1 -8.8329191e-01 -1.0939657e+00 6.3772715e-01 5.2128710e-01 -5.7405478e-01 -5.4210599e-01 -1.4298853e+00 5.9395219e-02
+1 9.2127372e-01 1 1 -1.4618163e+00 1.4602162e+00 -8.3393210e-01 -6.2955969e-01 -3.0756951e-01 -5.5673326e-01 1.1008543e+00 -7.7101134e-01
+1 7.0492441e-01 1 1 -1.4919788e+00 -2.6740348e-01 -1.2519037e+00 -1.2571926e-01 -1.4008329e+00 -1.3530616e+00 1.2192036e+00 6.8208880e-01
+1 4.9420799e-01 1 1 5.0525295e-01 1.3687722e+00 -1.4993179e+00 1.3282055e+00 -7.0353920e-01 1.0828724e+00 -1.4536036e+00 1.9487302e-01
+1 3.7676214e-01 1 1 6.1330420e-02 -9.2937836e-01 -3.2179916e-01 -1.0071819e+00 5.7144820e-01 5.8962703e-01 1.4498811e+00 -1.4503657e+00
+1 5.5041448e-01 1 1 3.3798031e-01 -6.3374377e-02 1.3439907e+00 -8.0484770e-01 4.8123827e-01 1.2782254e+00 -1.1827067e+00 -6.7908186e-01
+1 4.7157662e-01 1 1 4.3552452e-01 -1.3324570e-01 4.0100021e-01 6.2274847e-01 -1.4295528e+00 9.2361225e-01 -8.9418684e-01 7.7364554e-02
+1 7.1435097e-01 1 1 -5.0198892e-02 4.9513368e-01 8.9425243e-01 -1.2532556e+00 4.0672295e-01 5.4177445e-01 7.8095909e-01 -3.5330320e-01
+1 2.5454147e-01 1 1 1.3956442e+00 -3.6717367e-01 3.2131255e-01 9.1164403e-01 -3.1291416e-01 1.2677315e+00 5.2495667e-03 -3.5680012e-01
+1 9.9617527e-01 1 1 1.4611890e+00 -9.9986805e-01 -9.7674449e-02 4.5391922e-01 -1.2215028e-01 4.8161805e-01 2.6487307e-01 5.6072788e-01
+1 5.6664356e-01 1 1 3.7331988e-01 -4.0320443e-01 1.4384963e+00 1.2334398e+00 -1.5197465e+00 -1.3296876e+00 8.4934160e-02 -6.2446039e-01
+1 9.5521492e-01 1 1 6.2666858e-01 -2.4148454e-01 -8.8898000e-01 -9.4710166e-01 -1.2311741e+00 1.2301478e+00 1.2053634e+00 7.5522874e-01
+1 4.7639699e-01 1 1 -1.3413651e+00 3.0703373e-01 3.2779799e-01 5.1231257e-01 1.3283020e+00 2.7294389e-01 1.5531153e+00 1.0951608e+00
+1 1.3561525e+00 1 1 -2.5510829e-01 -1.3207722e+00 -1.0527152e+00 -6.6811008e-01 6.1424983e-01 6.4266537e-01 -2.8517671e-01 -2.2303459e-01
+1 6.0280335e-01 1 1 6.6891691e-01 2.7485639e-01 4.6484286e-01 -8.7394019e-01 4.2344243e-01 4.8135408e-01 1.1053450e+00 -6.2233302e-01
+1 7.1002863e-01 1 1 -1.2736797e+00 1.3700873e+00 -5.2690887e-01 -1.3671661e+00 1.0895184e+00 5.1694714e-01 1.2952262e+00 -1.1890590e+00
+1 7.6992114e-01 1 1 7.7161941e-02 -8.1743700e-01 3.9234330e-01 -3.5155710e-01 -8.0840665e-01 -1.3146376e+00 7.7158046e-01 -8.4302721e-01
+1 1.0722557e+00 1 1 -6.1702205e-01 -4.7895015e-01 -8.9170228e-02 7.1565900e-01 4.9770271e-01 -2.9236119e-01 -5.4168338e-01 -1.7546667e-01
+1 4.7953985e-01 1 1 1.0777847e-01 -9.5487567e-01 -1.4432752e-01 -1.0774287e+00 -1.1718500e+00 -2.6354085e-01 2.6292406e-01 8.8718093e-01
+1 9.2399637e-01 1 1 -1.2661670e+00 -1.3400447e+00 -4.0311393e-01 -2.0458785e-01 -6.3812984e-01 3.1457984e-01 -1.2561367e+00 8.5112905e-01
+1 3.7737430e-01 1 1 6.8049039e-01 -5.4333147e-02 1.2794836e+00 1.5359484e+00 3.4917789e-01 -1.5705086e-01 -3.8647669e-01 1.2546692e+00
+1 9.4792385e-01 1 1 -1.5369223e+00 1.0262626e+00 7.9502429e-02 2.1843251e-01 1.3776970e-01 -6.1592963e-01 1.2998169e+00 8.5479892e-01
+1 6.3611442e-01 1 1 -8.7885027e-01 1.0526575e+00 1.0204400e+00 -1.3265507e+00 1.4152772e-01 -3.8150839e-01 -6.1349926e-01 1.0220571e-01
+1 7.9127502e-01 1 1 9.3212560e-01 -1.4346629e+00 5.8009599e-01 5.4598583e-01 4.7066821e-01 -2.0901713e-02 -3.7504670e-01 -6.7988212e-01
+1 8.1215094e-01 1 1 -8.8755112e-01 -6.5594952e-01 1.3113593e+00 -2.0836200e-01 -9.7706185e-03 5.6327944e-01 -1.3750184e+00 -8.0630971e-01
+1 6.3730330e-01 1 1 -7.8980012e-01 -6.9496871e-01 -1.3977952e+00 9.3570876e-01 -8.5196654e-01 1.4188840e+00 -3.7845342e-01 1.1833713e+00
+1 8.8564134e-01 1 1 -9.4165723e-01 1.0235364e-01 8.6407806e-02 -3.5561073e-01 3.7762628e-01 -6.4606477e-01 1.0584374e+00 -5.0199296e-01
+1 5.6920972e-01 1 1 9.1080098e-01 -1.3350877e+00 8.4018474e-01 -1.4402865e+00 7.4778837e-01 -1.0664317e+00 1.4596008e+00 1.3221982e+00
+1 7.2003562e-01 1 1 -1.1489325e+00 -1.5639802e+00 -4.7401744e-01 -9.2348201e-01 -1.4331087e+00 -7.3151642e-01 -1.1868318e+00 -1.4418503e+00
+1 3.5399075e-01 1 1 1.2611973e+00 -1.1031467e-01 2.6781487e-01 -1.4944859e+00 3.3360550e-01 -1.5443807e+00 -1.1099472e+00 1.0675828e+00
+1 6.6530683e-01 1 1 6.1775542e-01 -5.1898659e-01 -7.3769914e-01 -7.9149919e-01 -8.3529574e-01 -5.6844222e-01 -1.0477928e-01 1.2285477e+00
+1 4.2883113e-01 1 1 -3.4840604e-01 -1.5464425e+00 1.3566887e+00 -1.2236358e+00 9.6211429e-01 -2.2512994e-01 1.4081412e+00 -1.4880365e+00
+1 7.5251655e-01 1 1 2.6846907e-01 -6.6362306e-01 1.8737440e-01 -7.8147996e-01 4.7748465e-01 -1.2813736e+00 1.0118000e+00 7.8895202e-01
+1 4.6186388e-01 1 1 8.3265238e-01 -8.5879566e-01 1.3256328e+00 6.6520840e-01 1.4569070e+00 -4.2815752e-01 -1.1784394e-01 -7.4592223e-01
+1 1.0665422e+00 1 1 -1.4066431e+00 -1.3020262e+00 -2.6537522e-01 -7.7068885e-01 6.6329915e-01 1.3453188e+00 -1.3997086e+00 1.3813602e+00
+1 4.7246298e-01 1 1 -9.6615009e-01 1.1793020e+00 9.0019161e-01 -1.8098164e-01 -1.4435762e+00 7.2992417e-01 -6.5584021e-01 1.5043760e-01
+1 8.6781637e-01 1 1 8.0788127e-01 2.2064425e-01 -3.8978554e-01 -6.9680701e-01 3.3496885e-01 -8.3730124e-02 1.1421917e+00 -5.7736638e-01
+1 9.8794282e-01 1 1 9.7051073e-02 1.2885297e+00 -9.0487718e-01 6.2197320e-01 8.7361483e-02 1.8130883e-01 -1.4573527e+00 5.8303129e-01
+1 5.9445888e-01 1 1 6.5079844e-01 1.3204930e+00 1.7920099e-01 1.4247854e+00 1.1606836e+00 -8.7436664e-02 1.2714114e+00 3.7941105e-01
+1 1.0628452e+00 1 1 -1.0563193e+00 1.3147923e+00 -9.5625577e-01 1.1482835e+00 1.4600360e+00 7.1734499e-01 -5.0257017e-01 -6.7157753e-01
+1 8.9421384e-01 1 1 -4.1790862e-01 -2.4851360e-01 5.9731734e-01 3.9713189e-01 -1.5584692e-01 -1.0154078e+00 1.0457268e+00 5.3882449e-01
+1 9.1055893e-01 1 1 8.1107977e-01 1.5501514e+00 -1.4176473e+00 -1.2886694e+00 7.6916900e-01 -8.2782635e-01 1.4614811e+00 -1.1884986e+00
+1 8.6966593e-01 1 1 4.4725071e-01 1.6594303e-01 -5.5994499e-01 -5.2737744e-01 -2.3033009e-01 8.3640577e-01 -1.0006739e+00 -8.4928482e-01
+1 1.0760581e-01 1 1 -8.8856634e-01 -7.2980755e-01 1.2161609e+00 -1.1997229e+00 -7.1575034e-01 -1.1554197e+00 -1.3810233e+00 1.4670053e+00
+1 3.2935995e-01 1 1 9.9695667e-01 -1.0976921e+00 8.1439615e-01 -1.0016982e+00 -4.5767711e-01 -9.5414623e-01 -7.7257744e-01 7.3873012e-01
+1 4.6265905e-01 1 1 -1.4044136e+00 -1.4785223e+00 -3.6312185e-01 2.5312031e-01 -1.5603674e+00 1.4948052e+00 -5.0662306e-01 2.6297659e-01
+1 6.5353353e-01 1 1 -1.1935583e+00 4.7417098e-01 1.1256138e+00 4.7667396e-01 9.1986205e-01 -1.2561406e-01 -1.0976300e+00 -3.7330637e-01
+1 1.2607710e+00 1 1 -1.0653686e+00 -8.2897415e-01 -4.7961510e-01 3.9792557e-01 3.4395454e-01 -4.5218616e-02 -4.3494043e-01 -3.9960519e-01
+1 7.7853285e-01 1 1 1.4277656e+00 3.9484339e-01 4.3582118e-01 -5.1571162e-01 3.1348811e-01 2.7614780e-01 4.4237790e-01 5.6059613e-01
+1 9.5202141e-01 1 1 9.7094295e-01 1.0892434e+00 -1.3475296e+00 8.9007162e-02 3.4371826e-01 1.0836904e+00 -1.1045068e+00 3.0270490e-01
+1 8.1765095e-01 1 1 1.2058349e+00 8.5357777e-01 -1.8848742e-01 5.4527619e-01 -5.1613121e-01 -1.3703183e+00 2.2582370e-01 1.3227533e+00
+1 6.4116734e-01 1 1 5.2640431e-02 1.5695535e+00 -1.1826329e+00 4.3109558e-01 -6.7997581e-01 7.5987608e-02 3.7492291e-01 -1.5366712e+00
+1 9.4296834e-01 1 1 -1.2014096e+00 -4.6785638e-01 3.4520797e-01 9.1069720e-01 7.6056702e-01 -1.5044745e+00 -7.0558050e-01 1.9956757e-01
+1 6.8038726e-01 1 1 -1.0745867e+00 1.4429907e-01 -6.1131712e-01 2.4846420e-01 -2.9059933e-01 9.7709006e-01 8.2088246e-01 -1.0887662e+00
+1 1.0896282e+00 1 1 4.3747091e-01 -7.5059181e-02 -1.3987872e+00 7.6120315e-01 1.0736248e+00 8.4780575e-01 -1.3033857e+00 8.8389754e-01
+1 4.9368460e-01 1 1 1.2467378e+00 1.4005971e+00 -8.7913790e-01 9.7605031e-01 -8.9686319e-01 -1.1929962e+00 3.2226819e-01 -9.2569741e-01
+1 9.0213657e-01 1 1 -5.0071940e-01 -1.1816302e-01 -7.6045751e-01 -9.1926018e-01 -2.1816007e-01 -1.0430312e+00 2.5567297e-01 -1.0295401e+00
+1 1.0179740e+00 1 1 7.3571370e-01 -4.7934978e-01 -1.0105137e+00 3.4683679e-01 -3.7769926e-01 -1.3906397e-01 -6.0318301e-01 4.1124451e-01
+1 1.2586823e+00 1 1 -1.6853728e-01 -1.3882179e+00 -2.5325609e-01 -1.5100927e+00 1.1673178e+00 9.6751917e-02 2.2268738e-01 2.8256357e-01
+1 5.5914050e-01 1 1 1.1105748e+00 8.3040353e-01 3.8287636e-01 7.9866181e-01 -1.3607272e-01 -1.2355323e+00 1.0699279e+00 -1.0421714e+00
+1 5.5415969e-01 1 1 1.2291670e+00 -1.5040818e+00 1.0212301e+00 -9.1635560e-01 1.0531566e-01 3.3568663e-01 -1.9862485e-01 -1.3950022e+00
+1 7.0612059e-01 1 1 -5.0335365e-01 1.2927085e+00 1.2936510e+00 -1.1013703e+00 1.3237168e+00 -4.1524338e-01 1.2251064e+00 -9.5501833e-02
+1 6.9352230e-01 1 1 4.4428977e-01 -7.0352769e-01 -5.7075262e-01 -4.6637832e-01 -1.0504051e+00 -1.5181832e+00 3.6518439e-01 2.5454520e-01
+1 6.9201574e-01 1 1 -3.8763280e-01 7.6480245e-01 -1.3569794e+00 -1.4677357e-01 -1.5490555e+00 -8.8956724e-02 -1.0180656e+00 -7.0797362e-01
+1 4.5341963e-01 1 1 7.1864799e-01 -1.3623553e+00 1.2090676e+00 -6.7310192e-01 -5.9796615e-01 3.0244351e-01 -1.5146381e+00 1.4403142e+00
+1 8.5420933e-01 1 1 -1.1069261e+00 -1.1774282e+00 9.7737067e-01 5.1169291e-02 -6.2223069e-02 7.1118169e-02 -1.9689988e-01 1.3888452e+00
+1 1.1048434e+00 1 1 4.0531548e-01 -1.4419476e-01 -7.1917348e-01 -7.9411293e-01 3.6722776e-01 1.4778514e+00 -1.1992147e+00 2.8722271e-01
+1 1.2935322e+00 1 1 1.1644694e+00 -1.3133386e+00 -1.4417077e+00 -1.1704446e+00 -1.2326105e+00 8.1731626e-01 1.2563632e+00 -1.2758787e+00
+1 9.7580608e-01 1 1 -8.8523360e-01 -4.5188781e-01 3.2317465e-01 9.9005893e-01 -8.2290705e-01 -1.5503351e+00 1.0527628e+00 8.1851774e-01
+1 5.2179648e-01 1 1 4.6174019e-01 1.4926070e+00 -2.1743133e-01 -1.0958374e+00 -1.3079861e+00 -1.1265828e-01 3.3483332e-01 -2.0654308e-01
+1 5.6543322e-01 1 1 7.3350482e-01 6.2906804e-01 -6.9604716e-01 1.4178939e+00 1.5421953e+00 9.3269942e-01 9.5109164e-01 9.0406309e-02
+1 7.5509422e-01 1 1 4.0599394e-01 1.2872587e+00 8.2637512e-01 1.5620931e+00 1.5362959e+00 -6.6819600e-01 5.7369353e-01 -1.0720089e+00
+1 7.2474055e-01 1 1 8.6051548e-04 -1.1923743e+00 -9.4525641e-02 -1.9039526e-01 -2.2485957e-01 8.2359326e-01 5.1922498e-01 -2.1958346e-01
+1 7.7236586e-01 1 1 -1.2452796e+00 -1.5320633e-02 9.5344203e-01 1.3098237e+00 1.2117817e-01 2.7471436e-01 -7.3019890e-01 8.3212568e-01
+1 9.0991637e-01 1 1 -1.2429746e-01 1.1672402e-01 -7.6393217e-01 1.0669433e+00 8.8939897e-01 -1.0168935e+00 -1.3920671e+00 -8.3421457e-01
+1 7.3494331e-01 1 1 9.1777166e-02 1.4267794e+00 2.8123250e-01 -9.4996914e-02 4.3058788e-01 -6.6522217e-01 -1.0309907e+00 2.8367760e-01
+1 1.0823026e+00 1 1 -2.3169832e-02 1.0524612e-01 -1.4223106e+00 -6.8406147e-01 -1.3390292e+00 5.3927352e-01 1.1647298e+00 -1.1681568e+00
+1 5.2424601e-01 1 1 1.4212480e-01 1.5483829e-01 -3.9569669e-01 1.2080482e+00 1.3064774e+00 7.5229341e-02 3.5024769e-01 -1.3989674e+00
+1 8.8853766e-01 1 1 1.0811575e+00 1.1284518e+00 2.7733748e-01 -4.4800605e-01 1.3749243e+00 1.4592951e+00 -7.3168544e-01 -7.6487674e-01
+1 9.5825246e-01 1 1 4.2671501e-02 9.3943544e-02 -9.1250490e-01 7.5984402e-01 -1.2032207e+00 -4.0909447e-02 -1.2436006e+00 1.1383856e-01
+1 6.3010934e-01 1 1 8.9679655e-01 -1.3119611e+00 7.8552092e-01 1.2435193e-01 -9.8283302e-02 4.4371293e-01 -1.7901687e-01 5.4798565e-02
+1 3.3954164e-01 1 1 -9.0196192e-01 7.0914294e-01 1.2777622e+00 8.2385255e-01 6.3027624e-01 -6.5776063e-01 9.0921618e-01 5.1284262e-01
+1 6.4440759e-01 1 1 -1.0894699e+00 -6.3719608e-01 -5.7807120e-01 1.4910176e+00 -3.9758808e-01 2.8167891e-01 4.8972304e-01 -1.1843813e+00
+1 7.6990515e-01 1 1 -1.5181182e+00 3.3487195e-01 1.3034301e+00 -9.5203197e-01 -9.5216435e-02 -2.0269224e-01 -1.9759793e-01 -7.6563188e-01
+1 4.9218085e-01 1 1 1.0029637e+00 -1.5412005e+00 4.2476666e-01 -6.6988275e-01 -1.2319599e+00 -1.1620823e+00 -3.6492768e-01 -1.1416953e-02
+1 4.7587745e-01 1 1 -9.7564611e-01 -5.2614889e-01 1.3547613e+00 7.4876238e-01 6.8693522e-01 1.6445319e-01 -9.5069413e-01 -2.4757425e-01
+1 8.3022984e-01 1 1 1.4294130e+00 5.9885972e-01 -7.9009998e-01 -7.7082227e-01 -3.2789984e-02 -6.3680991e-01 -1.7605200e-01 -1.5117501e+00
+1 4.9005532e-01 1 1 3.8570413e-01 -6.2751961e-01 3.0182737e-01 7.1820334e-01 -1.3225482e+00 5.4203594e-01 4.7432403e-01 1.2169039e+00
+1 1.1926965e+00 1 1 1.4236860e+00 -3.9553636e-01 -8.5952192e-01 8.4460213e-01 -1.2998714e+00 -6.2067705e-01 -1.3980997e+00 7.3611829e-01
+1 9.1844657e-01 1 1 1.5204612e+00 -1.6958937e-01 -9.4190458e-01 1.5123168e+00 -3.0279431e-01 1.5099502e+00 1.2513115e+00 3.4825413e-01
+1 1.0149527e+00 1 1 6.7715723e-01 -8.6403220e-01 -1.0489475e-01 -1.1178051e+00 3.1613954e-01 -5.2630892e-02 9.7124512e-01 3.2008042e-01
+1 1.2079302e+00 1 1 -1.0085657e+00 -1.3479620e+00 -5.3265449e-01 -2.2643492e-01 9.2406713e-01 1.3617185e+00 1.2719246e-03 1.1849738e+00
+1 4.3147320e-01 1 1 1.0703086e+00 -1.1731253e+00 1.2150388e+00 -1.2230235e+00 -1.2377904e+00 -9.9179250e-02 -6.1391156e-01 1.2990893e+00
+1 7.1602144e-01 1 1 -8.2728786e-02 -8.1223847e-02 8.0544669e-01 8.3930118e-02 8.3102275e-02 1.2800400e+00 -1.0213146e+00 -2.7508815e-01
+1 4.3310645e-01 1 1 1.3028361e+00 1.4636037e+00 1.9778062e-02 3.8398818e-02 -1.3087946e+00 6.3182839e-03 4.2709285e-01 1.0178115e+00
+1 9.9948090e-01 1 1 -1.3384353e-01 1.1613233e-01 -5.9893067e-01 1.3424378e+00 5.2171745e-01 -6.2275206e-01 -3.8963607e-01 3.8652937e-01
+1 1.1158521e+00 1 1 -1.2794432e-01 9.0711547e-01 -5.6486435e-01 -5.6657380e-01 3.2013967e-01 1.1928939e+00 -1.5344136e+00 -4.1445406e-01
+1 6.9108318e-01 1 1 -1.5108402e+00 -2.5950361e-01 2.1780456e-01 -2.3844855e-01 -9.6071170e-01 -6.7687247e-01 4.4396437e-01 -8.1839705e-01
+1 4.6464610e-01 1 1 8.0160429e-01 -9.4656763e-01 6.8573680e-01 1.0674023e+00 1.1046522e+00 -4.8868405e-01 4.2655816e-01 -9.0657570e-01
+1 6.3611549e-01 1 1 1.4140122e+00 6.3115394e-02 -1.3250225e+00 1.3357031e+00 -9.2358981e-01 -1.1896896e+00 4.8570594e-02 -9.3360665e-02
+1 4.8517692e-01 1 1 -8.4469576e-01 -1.0778942e+00 1.0968057e+00 -6.5904466e-01 -1.6470417e-01 1.1243885e+00 -4.8811552e-01 -1.4579584e+00
+1 7.1146127e-01 1 1 5.5568017e-02 1.3970144e+00 -8.5226002e-01 6.9206939e-01 -4.3986224e-01 9.1773276e-01 -1.0591191e+00 5.1657021e-01
+1 6.0204628e-01 1 1 8.7863534e-01 -6.4253054e-01 -1.4132567e+00 1.4342446e+00 -5.9716211e-01 -8.8551055e-01 -3.5025599e-01 -1.3666559e+00
+1 8.5409066e-01 1 1 -1.4029430e+00 -1.3568124e+00 9.7644231e-01 -9.0806569e-02 8.8491093e-01 -1.0514788e+00 5.9215272e-01 -1.2020676e+00
+1 8.7904026e-01 1 1 1.5318617e+00 8.7578306e-01 -6.1406677e-01 6.2802037e-01 3.9830602e-01 -7.4610894e-01 -2.5477485e-01 4.3223579e-01
+1 6.8727976e-01 1 1 6.4796494e-01 9.2423420e-01 -4.8828319e-01 -6.1289814e-01 -4.0463465e-01 1.3849540e+00 -1.0117867e-02 1.2247254e+00
+1 1.1501190e+00 1 1 -1.5549113e+00 1.5700752e+00 -7.3559570e-01 3.0332806e-01 8.5346870e-01 8.6267640e-01 -4.0498637e-01 2.4530518e-01
+1 1.0423320e+00 1 1 1.5143355e+00 -1.1251356e+00 -9.8984665e-01 -7.7018041e-01 -2.6364833e-01 5.5217509e-01 1.2253594e+00 1.0746629e+00
+1 3.8621596e-01 1 1 1.3953160e+00 -9.0731575e-01 1.5220535e+00 -1.0603576e+00 -1.4918465e+00 1.4199254e-01 1.4750248e+00 8.4401730e-01
+1 1.0924693e+00 1 1 -9.1280558e-01 3.4976862e-02 -8.3556236e-01 8.2504428e-01 -4.1244625e-01 -1.1417770e+00 4.3342377e-01 1.1079425e+00
+1 6.9220650e-01 1 1 -1.1264789e+00 3.7829831e-01 -3.7742030e-01 -4.7082926e-01 1.5108605e+00 -9.9853406e-01 -8.0001564e-01 9.7005074e-01
+1 7.2873819e-01 1 1 -1.4942585e+00 -5.2378318e-01 -4.2742046e-01 4.4445301e-01 -4.6065270e-01 2.6010987e-02 1.5373688e-01 -1.2230506e+00
+1 3.2734382e-01 1 1 -1.1031319e-01 -4.8131273e-01 1.1666511e+00 -7.8558182e-01 -1.3056016e+00 4.8527995e-01 1.4666007e+00 -3.7051629e-01
+1 3.0378026e-01 1 1 -4.9407969e-01 1.7806105e-01 1.2251932e+00 8.4023806e-01 7.7873136e-01 5.2551474e-01 2.2223376e-01 -6.3056642e-01
+1 8.4831686e-01 1 1 -7.6802062e-01 -1.2656862e+00 -1.3181868e+00 4.2206540e-01 2.6292471e-01 1.3092023e+00 -2.7085652e-01 -1.3378752e+00
+1 5.2271314e-01 1 1 6.8157985e-01 -6.6380614e-01 -2.5422127e-01 -6.3029775e-02 -1.2453183e+00 4.8698778e-02 -1.1779751e-01 -1.2903601e+00
+1 5.9949035e-01 1 1 1.0656926e+00 -7.9429912e-01 -1.3092754e-01 -6.2470423e-01 -7.7406509e-01 -1.4753229e+00 -6.1930879e-01 -6.6837265e-01
+1 8.8183805e-01 1 1 8.7576190e-01 -1.1580977e+00 -1.3843461e+00 -2.0135921e-01 -3.7671994e-01 8.3863122e-01 -6.2632286e-01 9.9627377e-01
+1 3.8120124e-01 1 1 5.6875153e-01 1.1602240e+00 -7.0388847e-02 -7.4892236e-01 -1.2227859e+00 -1.4512542e+00 8.6864211e-01 -3.1564835e-01
+1 3.8699632e-01 1 1 -8.5944717e-01 1.9550211e-02 1.3550807e+00 1.2236747e+00 9.3683358e-01 9.5339361e-02 2.8681951e-01 1.0482166e+00
+1 5.5161034e-01 1 1 3.1450462e-01 -1.2868290e+00 1.4363464e+00 1.4343456e+00 -3.0046180e-01 1.5638589e-01 1.3723051e+00 -6.7599707e-01
+1 2.6976860e-01 1 1 -1.4213034e+00 -1.0110996e+00 6.7609832e-01 -1.5357796e+00 -1.3220900e+00 -1.1353596e+00 -1.2421826e+00 -1.4836530e+00
+1 7.3739507e-01 1 1 8.2440096e-01 -6.7609542e-01 4.3917040e-02 -5.2326956e-01 1.1745318e-01 4.5398465e-02 -1.4797409e+00 -9.3557532e-01
+1 5.7085512e-01 1 1 1.2833411e+00 4.9624412e-03 -1.6058320e-01 -1.2737235e+00 1.1153406e+00 -3.9500678e-01 -1.1582509e+00 -5.4318086e-01
+1 7.9373986e-01 1 1 -1.0611879e+00 -1.4192520e+00 -2.9378223e-01 -6.5893157e-01 -3.5470489e-01 -6.9370394e-01 -1.4156115e+00 2.2750242e-01
+1 6.7402782e-01 1 1 -5.6323441e-01 7.4422543e-01 9.8572206e-01 -5.4885398e-01 1.2177031e+00 -6.3180193e-01 -9.0187653e-01 3.1489264e-01
+1 3.1431008e-01 1 1 -6.6211262e-01 1.5164379e+00 1.4125811e+00 -8.7282530e-01 -1.5398471e+00 -1.1190061e-01 3.4563957e-01 -1.1829873e+00
+1 1.0989563e+00 1 1 -6.0560462e-01 -9.6877463e-01 2.3422658e-01 -1.4786942e+00 2.2926576e-01 1.1004663e+00 3.5935519e-01 6.7168596e-01
+1 3.3026925e-01 1 1 3.6338046e-01 6.7954466e-01 2.3058108e-01 7.2587495e-01 -1.4646275e+00 9.8140390e-01 1.5415768e+00 1.2835098e+00
+1 4.8234137e-01 1 1 7.9354681e-02 1.4178033e+00 -1.3491456e+00 9.7597389e-01 1.5255842e+00 1.0939272e+00 5.6656206e-01 -1.3679919e+00
+1 5.6401575e-01 1 1 -1.4627508e+00 3.9280934e-02 9.2604143e-01 9.3786921e-01 -1.1858130e+00 1.0341167e+00 4.1184932e-02 1.4765513e+00
+1 1.4552064e-01 1 1 -1.4899419e+00 4.6020142e-01 5.2834505e-01 1.3974156e+00 3.0463575e-01 1.1084931e+00 1.0447713e+00 9.5776316e-01
+1 8.1369703e-01 1 1 1.8190937e-01 4.0830607e-03 -1.3872264e+00 -1.8319957e-01 -7.8297024e-01 7.9859130e-01 1.1100269e+00 -3.9524322e-01
+1 5.1891363e-01 1 1 5.8117695e-01 -4.9103747e-01 -1.3545440e+00 -2.7432344e-01 7.5082986e-01 1.0402047e+00 1.4444164e+00 -1.5258557e+00
+1 3.6977464e-01 1 1 6.2945584e-01 9.7114233e-02 1.3007979e+00 1.3039661e+00 -5.8029202e-01 -2.4300905e-01 1.2194460e+00 -2.3672819e-01
+1 4.8879531e-01 1 1 1.5218374e+00 -1.4292637e+00 1.6690434e-01 8.0738485e-03 -1.4644355e+00 -1.8273597e-01 -5.2177505e-01 -1.4343934e+00
+1 8.2730740e-01 1 1 -1.3254349e+00 -1.0171584e+00 -2.8093861e-01 6.0868832e-01 -1.5303998e+00 1.2342444e+00 -1.2882140e+00 7.3283336e-01
+1 5.0049052e-01 1 1 4.4977556e-01 1.1660210e+00 7.8583725e-02 1.1988525e+00 -1.2097434e+00 1.0063935e-02 8.4342800e-01 -1.4545119e+00
+1 6.0213005e-01 1 1 7.0583922e-01 5.9597187e-02 1.2877489e+00 -1.0612058e+00 2.3101161e-01 -5.0144771e-01 6.2840495e-01 -1.2489971e+00
+1 6.8911930e-01 1 1 3.8585631e-01 -5.1813548e-01 7.6316546e-01 -8.6484638e-01 -3.9634821e-01 1.0614132e+00 -4.3246050e-01 2.2740799e-01
+1 9.0655456e-01 1 1 8.3983265e-01 1.9186045e-01 -6.0094869e-01 6.7605772e-01 -1.2480194e+00 1.2084984e+00 1.2817332e+00 -1.2722398e+00
+1 9.1865790e-01 1 1 -1.0849488e-01 1.3245005e+00 7.5777864e-02 -6.3855165e-01 9.5280988e-01 8.3652268e-01 1.8839881e-01 -8.5551535e-01
+1 6.4906973e-01 1 1 -1.3496350e+00 -4.4532910e-01 1.2535364e+00 -4.5710396e-01 1.1779620e+00 8.0952072e-01 -3.0659308e-01 4.2301944e-01
+1 4.1052239e-01 1 1 -1.0171309e+00 -1.3725487e+00 6.6658372e-01 -1.3522733e+00 -3.1016574e-01 -6.2297512e-01 -6.9797754e-01 2.6354211e-01
+1 8.2993023e-01 1 1 -1.5139458e+00 2.8893851e-01 3.5311678e-01 -1.3758502e+00 -1.0534551e+00 5.8542049e-01 -2.0160150e-01 -2.9338562e-01
+1 5.8600312e-01 1 1 -1.1280116e+00 -7.1262180e-01 3.6518853e-01 1.3490931e+00 5.9561453e-01 -3.0596370e-01 1.4621203e+00 1.3683654e+00
+1 6.3431443e-01 1 1 1.0210068e+00 -1.2833142e+00 -9.4845904e-01 1.3333602e+00 1.3792200e+00 4.5527564e-01 3.1741228e-01 -1.4833211e+00
+1 8.6638702e-01 1 1 6.8266161e-01 1.5132493e+00 -3.0990568e-01 8.0419736e-01 -1.2608503e+00 -1.1020884e+00 3.2391215e-01 1.5012151e+00
+1 7.7886335e-01 1 1 3.9736128e-01 -1.1527889e+00 1.7590392e-01 1.0135014e+00 -1.0687925e+00 2.9981376e-02 -3.8862445e-01 7.9171864e-01
+1 1.6098618e-01 1 1 -5.7500365e-01 -7.2190384e-01 1.7844739e-01 2.0241701e-01 4.3141676e-01 1.2421609e+00 -2.4008704e-01 -1.3712386e+00
+1 1.1433501e+00 1 1 -5.4734835e-01 -2.0704515e-01 -1.0556947e+00 -3.2212376e-01 2.5694918e-02 1.1154314e+00 -1.3379366e+00 3.1671767e-01
+1 7.6217098e-01 1 1 -7.0047718e-01 1.0768106e+00 6.5521467e-01 -9.6991255e-01 1.4562885e+00 1.1726805e+00 8.1969846e-01 1.2159055e+00
+1 9.2629684e-01 1 1 -1.3722947e+00 -7.5919587e-01 9.1071396e-01 4.0399550e-01 -3.0788534e-01 -1.1104142e+00 7.8818356e-01 -3.3628367e-01
+1 6.1509319e-01 1 1 1.4156949e+00 1.3443558e+00 5.3016049e-01 9.7057868e-01 -4.2584125e-01 1.4704900e+00 -1.0950448e+00 -1.9438539e-01
+1 7.1710543e-01 1 1 -8.3821747e-01 2.5430429e-01 8.5054614e-01 1.3667668e+00 -5.6580488e-01 -3.8383108e-01 -9.6795205e-01 2.2111299e-01
+1 5.4600039e-01 1 1 -1.0196307e+00 1.5262302e+00 8.8235667e-01 -7.5490797e-02 1.1836982e-01 -1.3592105e+00 -1.2032950e+00 -2.5807084e-01
+1 5.7938893e-01 1 1 4.5422444e-01 2.4689902e-01 1.4512645e+00 4.2960517e-01 8.1336362e-01 1.4112738e+00 -1.3473655e+00 1.1428782e+00
+1 9.6316665e-01 1 1 8.0018359e-02 -4.1206791e-01 7.7410757e-02 9.9415498e-01 1.1326693e+00 2.5493351e-01 -5.7205289e-01 6.5669702e-01
+1 3.7524849e-01 1 1 2.6690163e-01 -1.5550854e+00 4.2323636e-01 -1.3685769e+00 -1.2792276e+00 -4.6481388e-01 -1.2193601e+00 6.9182953e-01
+1 8.3076708e-01 1 1 -3.7865517e-01 -1.4113522e+00 7.6777358e-01 1.0696937e+00 1.0810615e+00 1.0141055e+00 -1.1759305e+00 5.4455863e-01
+1 6.1174997e-01 1 1 8.0929879e-01 1.5697161e+00 1.4494558e+00 -9.9232218e-01 1.5697415e+00 9.3112190e-01 -1.0474080e-01 9.3753605e-01
+1 3.5654233e-01 1 1 -1.2114180e+00 -8.7667297e-01 1.0943569e+00 7.5655839e-01 -4.5050192e-01 1.0927812e+00 -1.0867572e+00 -1.0603232e+00
+1 5.6899944e-01 1 1 3.6020585e-01 -1.7299877e-01 -1.1684967e+00 1.4514258e+00 -3.4741407e-01 6.2299334e-01 9.1010983e-02 1.4029679e+00
+1 1.2584610e+00 1 1 1.3068966e-01 1.5244535e+00 -8.2755104e-01 -3.5272299e-01 1.2324412e+00 -2.7921071e-01 -3.3403460e-01 -1.1126243e+00
+1 9.3819807e-01 1 1 5.2780377e-01 -1.3402453e+00 -8.1957936e-01 -2.9974066e-02 1.1187943e+00 8.4510352e-01 -9.3529044e-02 -1.1166101e+00
+1 6.8927433e-01 1 1 -1.0597362e+00 -2.8350689e-01 1.2134656e+00 -1.1192984e+00 1.1444289e+00 5.1447941e-01 -1.1463106e+00 1.0093698e+00
+1 1.0595631e+00 1 1 -1.2967795e+00 8.9579953e-01 -5.0298056e-01 -1.9077479e-01 -1.5559728e+00 1.1923872e+00 1.3448835e+00 -1.2135516e-01
+1 4.2040360e-01 1 1 1.3975207e+00 1.1907588e+00 4.3161903e-01 1.2142859e+00 -6.1775292e-01 2.3131975e-01 -3.0283097e-01 -7.2249647e-01
+1 8.5781529e-01 1 1 -1.5572384e+00 1.1377174e+00 2.8356200e-01 7.1680161e-01 3.9045026e-01 -1.5006935e+00 -3.0006647e-01 -7.4254332e-01
+1 6.1633622e-01 1 1 1.0283049e-01 -1.2580225e+00 3.0402708e-02 -7.2315115e-01 -4.8958151e-01 -1.4495388e+00 -9.6103437e-01 -1.5195241e+00
+1 7.7745161e-01 1 1 3.9606870e-01 -6.6572194e-01 -1.1012883e+00 8.2068236e-01 -5.6529985e-01 6.5316246e-01 -1.1767959e+00 -6.3483871e-01
+1 6.6909607e-01 1 1 -3.0817820e-01 1.5644028e+00 9.1213123e-01 -1.5249374e+00 -8.1846657e-01 9.7670264e-01 1.0582330e+00 -8.8552167e-01
+1 3.8937018e-01 1 1 9.3519506e-01 9.2844759e-01 -7.8253756e-01 -5.0966757e-01 1.0666056e+00 6.1969341e-01 1.1651970e+00 -1.2382929e+00
+1 9.8242091e-01 1 1 4.3527566e-01 1.2788752e-01 -1.4019697e+00 1.1403733e+00 5.1224305e-01 8.0754729e-01 -1.2222678e+00 1.0630893e+00
+1 1.2415158e+00 1 1 -1.0913179e+00 5.5609218e-01 -9.5949231e-01 -6.0206780e-01 1.3050220e+00 7.6701314e-01 2.1906971e-01 1.1046045e+00
+1 6.2943667e-01 1 1 -1.1613155e+00 3.1103094e-03 -3.9220034e-01 1.1649468e-01 -1.0948128e+00 1.2352682e+00 -4.1903149e-02 1.4165318e+00
+1 8.5518061e-01 1 1 4.8542333e-01 -1.1321051e+00 -6.4975497e-01 7.1385127e-01 -2.1020130e-01 1.5077026e+00 -5.4946886e-01 6.6065473e-01
+1 1.0725822e+00 1 1 -2.0628016e-01 1.3370690e+00 -2.5573121e-01 -4.4009115e-02 1.4384615e+00 -1.2830988e-01 1.3592231e+00 1.2355881e+00
+1 9.5911055e-01 1 1 1.3676859e+00 3.0698449e-01 -3.7573433e-01 -1.3869146e+00 -1.4753617e+00 -1.3715943e+00 -1.1984957e+00 6.0182575e-01
+1 5.3222624e-01 1 1 -3.3574315e-01 9.9323770e-01 -3.6562083e-01 7.4350768e-01 1.8733918e-01 6.2217355e-01 7.7556728e-01 -1.0428895e+00
+1 9.8681915e-01 1 1 -5.3463640e-01 -1.0773200e+00 -3.4138091e-02 -1.1219843e+00 7.3381731e-01 -1.4911004e+00 4.9138633e-01 -8.9790486e-01
+1 2.8821234e-01 1 1 -6.7895040e-01 -1.5187321e+00 1.1525619e+00 -1.3518011e+00 -6.2527798e-01 -4.3916461e-01 -5.1697465e-01 1.1242065e+00
+1 9.7754228e-01 1 1 -8.5481654e-01 1.0999128e-01 4.7897318e-02 2.7736455e-01 -4.1960791e-01 -1.4385303e+00 8.5227406e-01 1.0005714e+00
+1 9.0212673e-01 1 1 -3.9840848e-01 1.3669113e+00 7.6250768e-01 -4.5749299e-01 5.2543769e-01 3.1830960e-01 -1.4923966e+00 -3.4200297e-01
+1 8.1619985e-01 1 1 -1.3173344e+00 -7.8916488e-01 9.1015199e-01 1.5341856e+00 1.4338655e-02 -3.0286255e-01 -2.3309430e-01 1.0706596e+00
+1 4.3562874e-01 1 1 1.5058906e+00 3.1011712e-01 5.0983927e-01 -1.1346902e+00 -9.1286348e-01 -8.3075798e-01 -4.9840405e-02 -4.6654428e-01
+1 1.1206577e+00 1 1 8.3309364e-01 2.3624824e-01 -1.3962080e+00 -1.2712907e+00 1.0420727e+00 -1.3116967e+00 1.1375434e+00 2.0559066e-01
+1 9.3556605e-01 1 1 -2.7369487e-01 -3.4888803e-01 -1.5118509e+00 -6.1138457e-01 -2.6264659e-01 -1.1305336e+00 -1.0412570e+00 -3.8961257e-01
+1 5.7682742e-01 1 1 -6.9801929e-01 -1.5491607e+00 -4.7634720e-01 6.0918502e-01 -3.6360682e-01 -5.2653541e-01 1.4056427e+00 -1.1393701e+00
+1 6.2594062e-01 1 1 -9.0332202e-01 7.7567927e-01 -1.1892258e+00 1.2221294e-01 -7.4217400e-01 3.8591772e-01 -1.3932174e-01 -1.3855669e+00
+1 5.5283418e-01 1 1 1.1841722e+00 -7.6800207e-01 -5.0539075e-01 -5.6877363e-01 1.5460118e+00 -1.2696358e+00 -1.0939314e+00 1.4026878e+00
+1 6.6914924e-01 1 1 3.9313897e-01 9.9337095e-01 7.6419112e-01 4.8808113e-01 -2.9168221e-01 -1.0721135e+00 -1.1044363e+00 4.6222289e-01
+1 6.5611589e-01 1 1 7.1734920e-01 1.1621126e+00 9.2944024e-01 4.8109708e-01 -1.4183229e+00 1.1643149e+00 1.4108315e+00 -5.7858239e-01
+1 7.2095112e-01 1 1 -9.4454732e-01 3.4511786e-01 1.1034157e+00 -6.6090160e-01 6.5217456e-01 -3.4094118e-01 -8.9667647e-01 -1.0049369e+00
+1 5.0446805e-01 1 1 -5.3909693e-01 1.0158722e+00 2.8541959e-01 8.9847179e-01 8.0984765e-02 6.6564617e-02 -2.2143433e-01 -7.7170467e-01
+1 5.6813852e-01 1 1 -2.4889334e-01 -7.9241304e-01 -1.6486166e-01 -1.0205590e+00 8.0133424e-01 3.4452729e-01 1.1405652e+00 -1.5459966e+00
+1 9.0081988e-01 1 1 1.4510976e+00 -8.7477096e-01 5.4837663e-02 5.5994583e-01 1.6943452e-02 5.1489453e-01 -5.1869653e-01 5.4743893e-01
+1 3.8635809e-01 1 1 4.1300647e-01 3.7813244e-01 1.1699618e+00 -1.2019740e+00 -1.1163320e+00 -1.2554350e+00 1.8700462e-01 -9.1879501e-01
+1 8.8783175e-01 1 1 -1.5199457e+00 -1.6999289e-01 3.2020882e-01 -1.1370259e+00 -6.0053875e-01 -1.1592218e+00 1.3939445e+00 -1.2598796e+00
+1 2.7924773e-01 1 1 -1.4369653e+00 -1.3627520e+00 2.0147910e-01 3.1370744e-01 6.8243572e-01 1.1163852e+00 1.1683428e+00 -4.6214708e-01
+1 7.3749945e-01 1 1 1.4882368e+00 -1.5619156e+00 -3.7764565e-01 8.8854330e-01 -2.5759012e-01 1.4953431e+00 1.3837437e+00 -1.2888982e+00
+1 7.9858809e-01 1 1 -5.6503996e-01 3.3180141e-02 -1.0732254e+00 -1.3843044e+00 -2.0242639e-01 -5.1051554e-01 -6.3026197e-01 -1.2313067e+00
+1 3.3133419e-01 1 1 4.0801578e-01 -1.5448556e+00 1.3257797e+00 6.3059405e-01 1.6451940e-01 -5.4511620e-01 6.3743684e-01 -9.0026304e-01
+1 1.1784402e+00 1 1 -5.7553518e-01 8.7582612e-01 -9.3693132e-01 -1.3393378e+00 4.7598508e-01 -8.8377585e-01 5.6998440e-01 -8.1071222e-01
+1 1.3648191e+00 1 1 -5.6008606e-02 -1.4935094e+00 -1.3422871e+00 -7.3846578e-01 1.3863502e+00 -1.7057909e-01 1.0117909e+00 -5.5295965e-01
+1 2.3211080e-01 1 1 1.1411471e+00 -8.7168580e-02 -4.2112665e-02 1.0382019e+00 -8.0516009e-01 1.3513790e+00 -2.7212902e-01 -7.6184546e-01
+1 9.1672096e-01 1 1 -1.6386558e-01 -1.0601504e+00 -9.2921501e-01 6.5319319e-01 -1.4861216e+00 -1.0887851e+00 4.8643897e-01 7.9496234e-01
+1 6.8611117e-01 1 1 1.0879246e+00 1.1657704e+00 -4.5957770e-01 1.4931581e+00 1.5571150e+00 5.6527118e-01 1.1556122e+00 -2.6158754e-01
+1 3.8498684e-01 1 1 6.7925852e-01 -1.0096988e+00 1.0539191e+00 4.6650919e-01 9.6529359e-01 3.3660537e-01 1.0492702e+00 -1.4136554e+00
+1 7.8776151e-01 1 1 -2.4970084e-01 8.7606953e-01 9.1821503e-01 -7.9531620e-01 5.0490268e-01 -6.8198676e-01 1.3247954e+00 5.5859006e-01
+1 4.0004240e-01 1 1 4.4581469e-01 -5.4419928e-01 9.3683999e-01 5.9743328e-01 4.5763624e-01 1.5200395e+00 1.3691331e+00 1.1442251e+00
+1 8.1968561e-01 1 1 1.0902133e-01 -1.1810566e+00 -1.9259747e-01 5.3099171e-01 8.7349763e-01 -1.2782150e-01 -1.1464922e+00 1.3020591e+00
+1 7.6614714e-01 1 1 7.7297749e-01 -1.4361275e+00 -1.1452919e+00 -8.8710574e-01 2.1221223e-01 5.5345729e-01 1.4349753e+00 -6.2753920e-01
+1 1.0435716e+00 1 1 9.4697266e-01 -1.3830524e-01 -3.8347858e-01 4.1255797e-01 9.4321616e-01 -2.9915661e-01 -3.7618295e-01 -7.2485818e-01
+1 5.1923345e-01 1 1 4.6112596e-01 2.8231999e-01 1.4236211e+00 3.6689343e-01 1.5748246e-01 -1.3768503e+00 1.5191283e+00 4.0489989e-01
+1 3.3635186e-01 1 1 -1.6514724e-01 1.1471853e+00 4.3028652e-01 -5.6847562e-01 -1.5549415e+00 2.4787486e-01 2.6662814e-01 4.6270799e-01
+1 9.5108885e-01 1 1 1.5383185e+00 7.8902860e-01 -1.2077111e-01 -7.8650636e-01 1.0067561e+00 2.8087880e-01 1.3079903e+00 1.2913937e+00
+1 1.0160045e+00 1 1 -7.8775686e-01 5.4112270e-01 -3.3117802e-01 1.0095421e+00 -6.8975375e-02 -1.0837111e+00 -1.4728100e+00 -8.0988774e-01
+1 9.3168283e-01 1 1 -1.1580708e+00 -2.6151014e-01 7.9322217e-01 -3.6757617e-01 -2.1445878e-02 1.0220151e+00 -9.0911418e-01 7.3765842e-01
+1 1.2371976e+00 1 1 -1.5292334e+00 -1.1284162e-01 -1.2342470e+00 -1.4815243e+00 8.4228357e-01 -1.2204913e+00 1.2245748e+00 1.1004683e+00
+1 9.7003667e-01 1 1 -4.5675870e-01 9.9281943e-01 -5.2329442e-02 2.8518588e-01 2.4351623e-01 -1.3386487e+00 8.5482761e-01 1.0145721e+00
+1 8.1005713e-01 1 1 1.3089743e+00 1.3175657e+00 1.4500946e-01 -9.5125657e-01 -7.1803090e-01 1.4175298e+00 5.8446031e-01 -6.5130228e-01
+1 9.0800538e-01 1 1 -6.4266635e-01 -7.5920413e-01 -7.0185431e-01 -2.0409362e-01 -1.0880202e+00 -1.4154450e+00 -7.3587586e-01 -1.1286197e+00
+1 9.2263541e-01 1 1 -4.9787672e-01 1.2054624e+00 6.1495491e-01 4.1768262e-01 8.5550724e-01 -1.2443567e+00 5.8475463e-01 2.2579339e-01
+1 7.5050034e-01 1 1 1.3887630e+00 7.5342773e-02 -2.9265365e-01 -1.4677523e+00 -5.5935582e-01 -3.2052457e-01 1.0692923e+00 -1.3445145e-01
+1 5.1235025e-01 1 1 -1.0942619e+00 2.2414975e-01 1.1042078e+00 -7.2700999e-01 -1.4480333e+00 7.7498781e-01 -1.4551691e+00 -9.2033022e-01
+1 7.0739956e-01 1 1 -3.7644824e-01 5.1520600e-01 1.0323395e+00 -1.2030370e+00 8.2270763e-01 1.7692767e-01 2.7127460e-01 1.2121367e+00
+1 1.1311823e+00 1 1 2.0201734e-01 8.3789597e-01 -4.8629789e-01 -1.5196145e-01 1.0978430e+00 -1.4648673e+00 8.6125890e-01 -8.4717321e-01
+1 7.1896143e-01 1 1 -7.5620361e-01 -1.2423197e+00 1.2153868e+00 9.8759295e-02 8.7281086e-01 6.3685708e-01 -1.2805797e+00 -7.4228395e-01
+1 6.1626833e-01 1 1 1.3697619e+00 -6.4177822e-01 3.7068639e-01 1.0865458e+00 1.2360917e+00 2.5085416e-01 3.4797205e-01 -3.0184399e-01
+1 6.9866024e-01 1 1 -3.2460345e-03 -1.2790348e+00 3.4788250e-01 -5.0340902e-01 -3.5942578e-01 8.8466254e-02 -1.2792432e+00 5.8021060e-01
+1 6.1302483e-01 1 1 -1.1490276e+00 1.1798244e+00 3.5724007e-01 -4.8631360e-01 4.1350825e-01 8.7901157e-01 8.1957591e-01 9.5957539e-02
+1 4.5914692e-01 1 1 -3.3606512e-01 -4.2485765e-01 5.5033770e-01 9.5149170e-01 6.3025146e-01 -1.3628003e+00 -1.2714424e+00 1.1213252e+00
+1 1.7617915e-01 1 1 3.3711335e-01 2.5765103e-01 6.7697914e-01 1.0144611e+00 -8.1412092e-01 7.6787938e-01 -1.8851937e-02 -3.0143412e-01
+1 6.3005673e-01 1 1 -1.5690585e+00 1.2261663e+00 -8.6025117e-01 6.2458418e-01 -1.2942648e+00 8.6112450e-02 4.5635297e-01 1.1857129e+00
+1 8.3501118e-01 1 1 -6.3794369e-01 -6.7067736e-01 -6.3201469e-01 1.3252718e+00 -3.2015445e-01 -9.8226830e-01 1.2966243e+00 1.1537866e+00
+1 1.0160684e+00 1 1 3.3614249e-01 -3.9931283e-02 -5.4620589e-01 -4.8949826e-02 7.1242951e-01 8.6011772e-02 -8.6338286e-01 -1.3607361e+00
+1 1.0733234e+00 1 1 9.6330705e-01 1.1757534e+00 -3.4873208e-01 3.9754434e-01 1.1931569e+00 4.6722883e-01 1.4071061e-01 9.0308828e-01
+1 5.1694201e-01 1 1 -1.4669298e+00 2.6940586e-01 1.0717433e+00 -6.3991818e-01 6.0143983e-01 -1.2666952e+00 -6.9600547e-01 1.1706567e+00
+1 1.0908893e+00 1 1 5.2953014e-01 8.6924208e-01 -1.1027892e+00 -1.4331401e+00 -1.2459720e+00 1.2266351e+00 1.5270876e+00 -5.6745718e-01
+1 9.3388849e-01 1 1 -3.1893464e-01 9.4574574e-01 8.1826566e-01 -1.9536490e-01 8.0565865e-01 9.2588834e-01 -1.0513784e+00 6.2242148e-01
+1 7.1035498e-01 1 1 -7.7736646e-01 -1.3101894e+00 -1.3016803e+00 -5.3362151e-01 4.4051118e-01 1.0969543e+00 9.4111830e-01 -4.6564348e-01
+1 7.2379584e-01 1 1 6.8581960e-01 -9.3074614e-01 7.1110302e-01 6.7025498e-01 -1.0625194e+00 -1.4969176e+00 -5.4367609e-01 -3.6271552e-01
+1 5.1230239e-01 1 1 6.6592043e-02 -1.0604818e+00 8.8995117e-01 -7.7581667e-01 -9.5094653e-01 -8.2094997e-01 1.3289505e+00 -1.4699286e+00
+1 4.0165378e-02 1 1 8.0548932e-01 -1.2630537e+00 2.8673993e-01 -1.5412584e+00 -1.2764509e+00 1.6870804e-01 -1.0520702e+00 3.9483373e-01
+1 3.9796915e-01 1 1 7.3622635e-01 -4.0232950e-01 3.4954584e-02 -1.4979113e+00 6.2665118e-01 -1.3821945e+00 -1.2611505e+00 9.2674618e-01
+1 2.2892302e-01 1 1 -9.7715108e-01 -1.2444444e+00 3.8588670e-03 1.3277068e+00 1.5077866e+00 1.5349909e+00 1.6915997e-01 -1.9333234e-01
+1 1.1183851e+00 1 1 1.2682029e+00 1.3472337e+00 -1.1174676e+00 3.4887984e-02 1.2828516e+00 -1.6631284e-01 -6.9710032e-02 -9.2981715e-01
+1 8.1338240e-01 1 1 -1.0193731e+00 1.4987018e+00 -8.3773178e-01 -1.1154763e+00 1.3578176e-01 7.9757834e-01 1.9754489e-01 -1.1549914e+00
+1 9.4968937e-01 1 1 -1.4991436e+00 -6.0793120e-01 8.6022943e-01 1.2142060e+00 1.2877578e+00 -2.7664385e-01 -5.2643441e-01 -4.0024633e-02
+1 9.4415776e-01 1 1 -5.3418810e-01 -1.0403058e+00 2.6659877e-01 -6.2502374e-01 9.1432796e-01 3.8659549e-03 -1.0581456e+00 -3.9318453e-01
+1 4.1909917e-01 1 1 5.7238553e-01 -1.4570527e+00 8.1447471e-01 7.1177091e-01 -1.5612660e+00 -9.9834234e-01 3.0251513e-01 -1.4829720e+00
+1 6.0928292e-01 1 1 5.2685148e-01 2.9352821e-02 9.5726341e-01 -4.5120233e-01 1.5256884e+00 1.0657930e-01 1.2748123e+00 1.0853378e+00
+1 6.6909306e-01 1 1 -1.3568033e+00 1.0282413e-01 6.3018108e-01 4.4704162e-01 5.6556241e-01 5.7053071e-01 1.0797985e-01 1.1858634e+00
+1 4.3486606e-01 1 1 1.0276340e+00 2.8926163e-01 1.1446276e+00 -1.2611822e+00 -1.0519441e+00 7.6890541e-01 -1.0231752e+00 5.4276431e-01
+1 1.3699476e+00 1 1 -1.0317856e+00 -1.5652918e+00 -1.3568201e+00 -3.6330182e-01 8.5915681e-01 -1.5188953e+00 5.7293682e-01 -9.4531930e-01
+1 3.3290049e-01 1 1 3.7146292e-01 -1.6285320e-01 7.4534762e-01 1.2424075e+00 1.0886988e+00 5.0882544e-01 3.6761191e-01 -9.4740103e-01
+1 4.4837807e-01 1 1 8.3275134e-01 -7.4650691e-01 1.5275265e+00 -1.0240868e+00 1.1258696e+00 4.1393131e-01 -1.0593032e+00 -1.3775588e+00
+1 7.1781736e-01 1 1 2.5651319e-01 9.7937083e-01 4.2525226e-02 9.5873174e-01 6.7750658e-01 1.4573833e+00 -3.0304430e-01 9.0786280e-01
+1 7.8056599e-01 1 1 9.5211697e-01 1.4816894e+00 -1.5616594e+00 1.7557855e-01 -1.4202631e+00 -7.5650487e-01 -7.4381327e-01 -2.6547032e-01
+1 6.4628520e-01 1 1 -1.0431161e+00 -6.5124522e-01 1.1969404e+00 9.9322845e-01 -5.4169233e-01 -5.5187620e-01 -8.7245661e-01 -6.9815267e-01
+1 3.6980226e-01 1 1 -1.5652482e+00 -1.6961801e-01 1.3592101e+00 -1.2328344e+00 1.1252377e-01 -1.4018031e+00 -1.5653726e+00 -3.3502367e-03
+1 8.6681460e-01 1 1 5.6987186e-01 -1.3453525e+00 -1.4177157e+00 -1.4449361e+00 -5.1807357e-02 -1.3010627e+00 -1.5206603e+00 2.4123886e-01
+1 6.2224228e-01 1 1 -8.7963362e-01 -1.2968819e+00 1.4324144e+00 -5.2983454e-01 -5.0509025e-01 -1.4765162e+00 -8.8100609e-01 -1.2946016e+00
+1 7.6728624e-01 1 1 3.3285222e-01 -3.2422702e-01 5.6347743e-01 1.4860266e+00 -4.6845049e-01 -3.6796387e-01 -7.4320494e-01 3.0100191e-01
+1 6.3498162e-01 1 1 -9.2922708e-01 1.3796716e+00 -1.5366610e+00 -1.2489759e-02 -4.1617976e-01 1.4271370e+00 -7.3038752e-02 9.7485625e-01
+1 4.6414666e-01 1 1 -6.6242263e-01 4.5364384e-02 3.7258815e-01 5.7132948e-01 -1.5479376e+00 -1.6913146e-01 8.0042553e-01 1.0033700e+00
+1 6.6834330e-01 1 1 4.6721978e-01 -9.6781628e-01 8.9488305e-01 -1.5142395e+00 -6.5847572e-01 5.4889122e-01 4.5208501e-01 -4.3003843e-01
+1 5.7221133e-01 1 1 -1.4188412e+00 1.0786244e+00 1.4954157e+00 2.1869035e-01 8.2957351e-01 1.4987679e+00 -1.3198611e+00 1.1487605e+00
+1 7.3026937e-01 1 1 1.3653898e+00 1.4504734e+00 7.1100433e-01 -1.3471177e-01 2.5382995e-01 5.0169204e-01 -1.1917527e-01 -1.0111407e+00
+1 6.5851542e-01 1 1 -1.2284077e+00 -6.5264228e-01 -7.6863191e-01 9.8752684e-01 -1.6285738e-01 -9.6637686e-02 1.3574175e+00 -1.3670221e+00
+1 4.5329696e-01 1 1 6.9792066e-01 1.4827039e+00 -1.6745511e-01 3.2954435e-01 -8.1677731e-01 1.3811605e-02 -1.2981791e-01 -1.0738121e+00
+1 6.0260541e-01 1 1 -7.5444968e-01 6.9186251e-01 4.4895583e-01 2.4022071e-02 1.1835790e+00 -3.4621294e-01 1.5573272e+00 8.8931905e-01
+1 9.8332318e-01 1 1 -5.6787897e-01 1.0988785e+00 -5.0491942e-01 -1.5265069e+00 -1.5197282e-01 -5.7128496e-01 1.3892230e+00 -9.1251602e-01
+1 1.0031504e+00 1 1 -1.8341780e-01 -5.7220754e-01 -7.3901289e-01 1.3862445e+00 -9.2283748e-02 -8.7916270e-01 3.5519819e-01 5.9865771e-01
+1 3.8277615e-01 1 1 -8.0058509e-01 -6.7708382e-01 1.2676627e+00 5.6083869e-01 9.3382078e-01 -1.1772116e+00 7.9001082e-01 -8.8110850e-01
+1 4.1444287e-01 1 1 7.6763913e-03 -8.9911511e-01 -6.7499144e-01 1.2379265e+00 -6.7102384e-01 3.5447999e-01 1.3412207e+00 6.7715629e-01
+1 3.7703500e-01 1 1 2.1180900e-01 -3.6691241e-01 -2.9010962e-01 -9.3714504e-01 4.1995720e-01 1.2854608e+00 9.6912659e-01 -1.0244982e+00
+1 9.2545085e-01 1 1 4.4931550e-01 2.4952963e-01 -1.2061569e-01 1.3487973e+00 -9.3797111e-01 6.7143003e-03 -1.0472801e+00 3.2736368e-01
+1 1.1285480e+00 1 1 -7.4320290e-01 -1.8169415e-01 -8.6071808e-01 -4.9669033e-01 3.1526611e-02 -2.5009119e-01 7.0732508e-01 1.0725957e+00
+1 5.5047849e-01 1 1 -3.8739518e-02 -1.0551589e-01 9.4546745e-01 -6.6265529e-01 -1.0614080e+00 1.6830654e-01 2.2607967e-01 6.5791276e-01
+1 7.5306078e-01 1 1 -7.8540502e-01 -1.5472601e+00 2.9573603e-01 -3.0147230e-01 -1.1215579e+00 1.2945842e+00 1.5354622e+00 -8.6636820e-01
+1 5.2558738e-01 1 1 6.7018839e-01 1.3036985e+00 4.3592124e-01 5.4398526e-01 -4.6701209e-01 -5.9341824e-01 1.4713628e+00 2.3160235e-01
+1 7.1028178e-01 1 1 1.2466129e+00 -1.3488194e+00 3.3423927e-01 7.2568004e-01 -1.3736902e+00 9.7634175e-01 -1.4233276e+00 1.0735862e-01
+1 1.9719804e-01 1 1 5.4148970e-01 1.2576686e-01 3.9179300e-01 8.4180533e-01 -4.6603573e-02 8.3729900e-01 1.3612603e+00 1.1021399e+00
+1 4.7816545e-01 1 1 -3.7653766e-01 -5.2823430e-01 8.6690332e-02 -1.5110472e+00 -1.0096879e+00 1.2907752e+00 -1.5168234e+00 8.3573620e-01
+1 5.3964805e-01 1 1 -1.3008792e+00 1.0703714e-01 -6.9458517e-01 4.6412365e-01 1.0589496e+00 1.3621432e+00 7.7299454e-01 1.5748307e-01
+1 3.8249286e-01 1 1 -1.5331203e+00 -1.1593925e+00 2.6530973e-01 -4.8350350e-02 6.4353703e-01 7.5477731e-01 1.2336356e+00 -1.5445903e+00
+1 5.3489076e-01 1 1 1.9066192e-01 1.3900456e+00 1.1407030e+00 1.0481601e+00 -5.7665664e-01 -2.0886559e-01 -7.9842663e-01 -9.4917186e-01
+1 1.1704867e+00 1 1 3.0325587e-02 -1.5275677e+00 -1.3448819e+00 1.5163551e+00 -5.4828112e-02 -1.2449274e+00 -1.4140828e+00 2.7609919e-01
+1 7.7756000e-01 1 1 7.4413759e-01 -7.3544350e-01 3.2852466e-01 7.8021997e-01 -1.0094316e+00 -4.8768093e-01 -3.4070542e-01 2.6665557e-01
+1 8.0530514e-01 1 1 4.0095661e-02 1.5681140e+00 -1.4058541e+00 1.4929836e-01 -9.1642409e-01 -3.8165812e-02 8.8740628e-01 -1.3725174e+00
+1 1.0962820e+00 1 1 -1.5546473e+00 4.7064810e-01 -2.7184693e-01 -8.7506866e-01 8.8912043e-01 -5.6789394e-01 1.4970569e+00 8.1471257e-01
+1 6.1023461e-01 1 1 -3.3070106e-01 -3.4767339e-01 -1.0556580e+00 -1.4838323e+00 -1.1092346e+00 -4.3494551e-01 2.0138632e-02 -1.3281803e+00
+1 6.3387621e-01 1 1 -6.1534547e-01 1.5670814e-02 1.2720845e+00 -8.0761905e-01 -6.9457058e-01 3.5686339e-01 -8.2201921e-01 1.4316810e+00
+1 3.2079621e-01 1 1 1.1727867e-02 -5.1440673e-01 1.3868749e+00 1.1685004e+00 5.1056769e-01 5.0264671e-01 1.0475801e+00 8.0457215e-01
+1 1.1806821e+00 1 1 -8.1007980e-01 2.9108132e-02 -1.4115682e+00 8.9120746e-01 1.4216768e+00 2.4055590e-01 1.1935122e+00 1.0293765e+00
+1 5.8849123e-01 1 1 6.5131210e-01 -8.6807360e-01 1.0803845e+00 -5.8994801e-01 -8.3252306e-01 -2.0677071e-01 2.8978796e-01 -2.0573316e-02
+1 1.0494541e+00 1 1 1.2936248e+00 -1.5678991e-01 -3.8301580e-01 -3.8980548e-01 4.3868755e-01 -5.9390228e-01 9.9757794e-01 -2.0053222e-01
+1 5.4671976e-01 1 1 -1.0108892e+00 6.2818179e-01 -2.2312336e-01 -1.2400016e+00 -2.9626500e-01 -8.7573480e-01 -3.8749679e-01 5.8391205e-01
+1 6.0345916e-01 1 1 -2.8238370e-01 -1.0416058e+00 1.0273536e+00 6.1885937e-01 9.8495392e-02 -1.1327246e-01 -1.3694377e-01 -5.2564230e-01
+1 8.1454635e-01 1 1 9.2358284e-01 -1.3148110e+00 5.3910304e-01 -6.4379773e-01 -2.0728110e-01 3.4858740e-02 1.1734072e+00 -3.1161912e-01
+1 9.4936842e-01 1 1 4.7422920e-02 -6.5096954e-02 3.5159434e-01 -6.6339788e-01 2.5279720e-01 1.5346169e+00 -1.4644628e+00 -3.4754618e-01
+1 7.4074985e-01 1 1 -9.2751421e-01 -8.1026785e-01 -8.9716430e-02 -2.1581826e-01 1.3292211e+00 -1.6930419e-01 1.1519520e+00 -9.8798546e-01
+1 7.5850945e-01 1 1 -1.4861074e-01 6.3238405e-01 1.0042655e-01 1.2819405e+00 3.5286647e-01 7.8746560e-01 -7.7873864e-01 1.3871755e+00
+1 7.2326139e-01 1 1 -1.3447641e-01 4.7083763e-01 8.3382511e-01 5.3091984e-01 -7.0019807e-01 -5.9556251e-01 -3.8539387e-01 4.9903015e-01
+1 7.3237173e-01 1 1 -1.3399119e+00 -3.0381386e-01 -5.4616294e-01 1.0465884e+00 1.7716592e-01 -5.0484776e-01 6.4928671e-01 -8.5261339e-01
+1 8.4727169e-01 1 1 -9.6295964e-01 -1.1114746e+00 3.7322375e-01 2.3374446e-01 -6.0222729e-01 4.6546800e-01 -1.3311471e+00 -1.0691251e+00
+1 9.7854853e-01 1 1 1.0226297e+00 -6.4406773e-01 -9.8891138e-01 1.5523311e+00 5.7748544e-01 5.5504125e-01 -1.3081385e+00 1.1249580e+00
+1 7.2372738e-01 1 1 -3.1660214e-01 1.0819865e+00 1.5332446e+00 -8.9844025e-01 1.4181507e+00 1.1896182e+00 -1.0190846e+00 1.0648751e+00
+1 7.8234078e-01 1 1 7.2575074e-01 1.4095101e+00 -1.2431731e+00 1.5506113e+00 -4.0418326e-01 8.1781282e-01 2.0762632e-01 -2.9779621e-01
+1 7.0972428e-01 1 1 -1.1115832e+00 -1.1140234e+00 7.2273733e-01 -1.5286974e+00 -9.8473679e-01 5.1218384e-01 -7.3385532e-01 -5.0373645e-01
+1 6.1251951e-01 1 1 6.7283029e-01 5.0045374e-01 -1.4924473e+00 -8.7293518e-01 -5.6116944e-01 3.0990168e-01 -1.3572903e-02 2.9362731e-01
+1 7.4004928e-01 1 1 -1.4748661e+00 1.0824982e+00 -1.0859036e+00 -1.8387556e-01 -5.1355283e-01 -2.4312550e-01 1.2164750e+00 -4.4787151e-01
+1 6.2562436e-01 1 1 -9.0828175e-01 5.8412778e-01 -1.2693493e+00 9.3069039e-01 -1.3274166e+00 1.0018088e+00 -1.8955932e-01 -1.2040877e-01
+1 8.8385625e-01 1 1 -4.9274343e-01 -4.1474044e-02 6.0158662e-01 1.2348578e-01 -1.4407469e+00 -1.5359650e+00 -3.4853427e-01 -5.2454056e-01
+1 6.4862395e-01 1 1 -3.0062119e-01 3.7930674e-01 1.2212370e+00 -1.1671829e+00 7.6348722e-01 -4.9644071e-01 1.2548897e+00 -6.4423593e-01
+1 2.8170793e-01 1 1 -8.5930441e-01 7.1694319e-01 1.3062753e+00 -7.3877088e-01 -1.4763619e+00 3.9107694e-01 1.4192446e+00 1.3965601e+00
+1 5.8321242e-01 1 1 -4.2778904e-01 -1.4852867e+00 1.1192701e+00 -9.4800236e-01 -9.1633777e-01 6.1835734e-01 -8.6915332e-01 1.1476806e+00
+1 2.0618494e-01 1 1 1.2552719e+00 -1.1869989e-01 -2.8501336e-01 1.0823153e+00 -8.0177447e-01 3.4331961e-01 5.4601275e-01 -3.1084593e-01
+1 6.2192674e-01 1 1 1.5600230e+00 -7.7728962e-02 7.0919080e-01 6.5130433e-01 -1.1325577e+00 -9.3304915e-01 2.4419119e-01 8.0993234e-02
+1 3.7145841e-01 1 1 -4.2623983e-01 5.1187477e-01 1.6727462e-01 1.1631156e+00 1.2979393e-02 1.0734024e+00 1.2012631e+00 9.4366992e-01
+1 3.6130931e-01 1 1 -9.8161639e-01 1.3985111e+00 -3.4091524e-01 1.4942813e+00 1.3747688e+00 -1.4923134e+00 -1.3874344e+00 1.5005781e+00
+1 4.1891595e-01 1 1 -1.5236838e+00 -6.2023849e-01 5.0252140e-01 4.9343194e-01 -6.7520505e-01 1.1642737e+00 1.4321602e+00 -4.9049474e-01
+1 6.7283616e-01 1 1 -1.4324812e+00 -5.4393478e-01 1.2760773e+00 -6.9402401e-01 -7.3855258e-01 -1.0328022e+00 -5.6605734e-01 -2.0591166e-01
+1 6.7051451e-01 1 1 1.4542314e+00 1.2272809e-01 -6.2246305e-01 2.7205878e-01 -4.2070804e-01 -1.0072963e+00 -9.8308629e-01 1.2778850e+00
+1 1.0515842e+00 1 1 -3.2409189e-01 -1.3352940e+00 -2.3288069e-01 1.4746700e+00 8.8505132e-01 4.1313576e-01 -1.0955864e+00 1.4851445e+00
+1 6.5526612e-01 1 1 5.0932748e-01 1.2510731e+00 3.9865173e-01 7.5358284e-01 -3.8362230e-01 6.5292922e-01 -6.4564974e-01 8.6974661e-01
+1 4.7152773e-01 1 1 -5.7296475e-01 1.0592509e-01 -8.7748063e-01 -1.4348354e+00 -9.9190549e-01 1.9820025e-01 -3.7418558e-01 6.7261974e-04
+1 8.2605558e-01 1 1 -8.3700737e-01 -1.0000175e+00 -1.1810108e+00 -4.1415422e-01 1.4766865e+00 1.0633165e+00 5.3151066e-01 -1.2616506e+00
+1 8.1244035e-01 1 1 4.6895570e-01 2.2633203e-01 -6.6666905e-01 1.0794160e+00 8.7615737e-02 -1.3606213e+00 1.5516967e+00 1.1889784e+00
+1 4.8139604e-01 1 1 -5.1755863e-01 -5.0624791e-01 1.3542024e+00 -9.5351793e-01 -8.4925981e-01 -3.0877294e-01 1.0057370e+00 -5.1133765e-01
+1 8.6027323e-01 1 1 4.6211121e-01 -1.0757802e+00 -7.5893547e-01 -5.1170427e-01 -1.2541697e+00 3.6421747e-01 -1.4879840e+00 1.3456406e+00
+1 6.7000558e-01 1 1 6.8606769e-01 -7.7202549e-01 -5.6222268e-01 1.4669870e+00 1.2559602e+00 -1.5611037e+00 -1.4694907e+00 -1.4440724e-01
+1 2.1071687e-01 1 1 1.0946798e+00 -6.5467542e-01 6.3413179e-01 4.3168437e-01 5.6269776e-01 1.1112659e+00 1.4714526e+00 1.3986695e+00
+1 4.3137130e-01 1 1 1.1161232e+00 -1.2723313e+00 1.5707361e+00 1.3817030e+00 1.0674461e+00 2.7774623e-01 8.5666574e-02 -1.0991780e+00
+1 4.0633486e-01 1 1 2.3286495e-01 7.4897989e-01 5.5927628e-01 -3.7099281e-01 -1.0687880e+00 -3.2583648e-01 9.4868035e-01 -1.3191882e+00
+1 3.8453265e-01 1 1 -6.6323528e-01 -2.5670673e-01 1.1119915e-01 7.8525445e-01 5.0758811e-01 -5.3780676e-01 8.8787435e-01 -1.3765600e+00
+1 5.6963021e-01 1 1 -6.2463485e-01 -1.0632227e+00 -3.2344300e-01 -5.9116965e-02 -1.5323225e+00 -5.5611566e-01 -6.0952105e-02 -1.1550090e+00
+1 1.1563610e+00 1 1 9.6464262e-01 -2.0431307e-01 -1.1511654e+00 -8.3555338e-01 1.0330788e+00 -3.9771131e-01 -2.6282534e-01 -3.3477676e-01
+1 3.9432123e-01 1 1 -1.0111602e+00 -1.2896187e-01 1.4321040e+00 -2.2657743e-01 -6.2798631e-01 9.7514509e-01 -2.2620904e-01 -4.9882800e-04
+1 9.0318819e-01 1 1 1.4473386e+00 2.3672446e-01 -1.5108721e+00 -4.7664841e-01 1.1854863e+00 -4.2542882e-01 -5.6826885e-01 1.0409757e+00
+1 1.0729443e+00 1 1 6.8400595e-02 1.3716958e+00 2.6542982e-01 3.1441825e-02 4.8838558e-01 8.2675916e-02 -4.5295968e-01 1.4982966e-01
+1 4.2944705e-01 1 1 -2.1411225e-01 1.0850186e+00 1.7429673e-02 6.5518056e-01 -6.8518351e-01 9.5017279e-01 -8.1434605e-01 -1.3702686e+00
+1 4.1368119e-01 1 1 -1.4610562e+00 -1.0385668e+00 7.7240416e-01 3.3743731e-01 1.1994429e+00 8.3861745e-01 1.2052111e+00 9.1119239e-01
+1 3.0311495e-01 1 1 -1.2836675e+00 -5.0349762e-01 7.3595262e-01 7.3414929e-01 -5.6295737e-01 1.4588985e+00 -1.0071566e+00 -8.5377071e-01
+1 4.0039716e-01 1 1 -1.2826381e+00 1.1660285e+00 7.0538829e-01 -1.3287525e+00 8.5263082e-01 -4.2365109e-01 -3.7904545e-01 1.4709159e+00
+1 1.0060753e+00 1 1 3.1022706e-01 1.8548398e-01 -9.0963834e-01 1.2390031e+00 1.3620331e+00 -1.4549301e+00 5.3294624e-01 4.9070502e-01
+1 8.4221361e-01 1 1 -1.0575377e+00 9.6933102e-01 -1.3016846e+00 1.4484135e+00 -1.0945784e+00 1.1464049e+00 5.4678202e-01 5.9861529e-01
+1 5.7021642e-01 1 1 1.0943355e+00 -7.5297468e-01 6.3891481e-01 -7.1549087e-01 5.8824137e-01 2.4015911e-01 6.0686132e-01 1.5475273e+00
+1 1.0397220e+00 1 1 -1.5278641e+00 -9.1019147e-01 2.7751029e-01 7.6167493e-01 -1.9436781e-02 -5.9236448e-01 -1.2330610e+00 4.4933423e-02
+1 1.0417609e+00 1 1 5.6633749e-01 -1.1733758e+00 -1.1496778e+00 -5.1945789e-01 5.1659044e-02 -1.6268816e-01 1.0298295e+00 1.2137995e+00
+1 3.3160934e-01 1 1 -5.9146581e-01 -1.1493888e+00 1.3016846e+00 -4.2795946e-02 1.1539769e+00 -1.1142874e+00 1.3106466e+00 -1.1739261e+00
+1 8.5341833e-01 1 1 -7.6676881e-01 -1.2438507e-01 -6.3893940e-01 1.5325589e-01 -1.3035257e+00 -7.9384028e-01 -8.0977415e-01 -9.7441338e-01
+1 1.3160431e+00 1 1 -2.7032054e-01 -1.3806803e+00 -6.9074844e-01 -3.3421139e-01 1.1111793e+00 2.7036489e-01 -4.9483152e-01 1.5674719e-01
+1 7.8739238e-01 1 1 -5.3431821e-01 -1.2908607e+00 -1.2241263e+00 7.6815671e-02 -1.1779427e+00 1.2796811e+00 -8.3758599e-01 -1.3462037e+00
+1 8.7378104e-01 1 1 1.5272853e+00 3.4340572e-01 3.9901621e-01 -1.5359300e-01 6.3314405e-01 2.5728879e-01 1.6900352e-01 1.0532593e-01
+1 8.2324104e-01 1 1 -8.7029740e-01 5.1425556e-01 -1.0347982e+00 9.5167965e-01 6.7767369e-01 1.4211516e+00 4.4242224e-01 1.4963194e+00
+1 1.0631598e+00 1 1 1.6707414e-01 5.7188251e-01 2.8678658e-03 1.0317418e+00 1.3883400e+00 -2.3383531e-01 -3.5919302e-01 1.9138093e-01
+1 7.3315292e-01 1 1 -5.6871210e-01 1.4974954e+00 1.0763313e+00 -1.1068434e+00 1.2224363e+00 6.2294114e-02 1.1839214e+00 -4.5150304e-01
+1 6.3373170e-01 1 1 1.5222460e+00 1.1057318e+00 6.0986003e-01 -1.3470476e+00 -5.2850458e-01 8.2682814e-01 -6.8023848e-01 -1.4652779e+00
+1 6.3508626e-01 1 1 -7.4127435e-01 1.5139708e+00 -1.0992744e+00 -1.5118356e+00 -1.2940885e+00 1.2362026e+00 -5.1253278e-01 1.9479179e-02
+1 7.5333171e-01 1 1 9.5845384e-01 1.5485276e+00 2.0230045e-01 -2.1948405e-01 -5.0028489e-01 1.5042151e+00 1.0858186e-01 6.6092905e-01
+1 4.1994289e-01 1 1 -1.3534255e+00 1.1491759e+00 8.6045403e-01 -6.3859026e-01 -1.3862534e+00 9.4672414e-01 -3.3007265e-01 -4.3714095e-01
+1 4.1233548e-01 1 1 1.2500986e+00 -3.1250188e-01 8.9993796e-01 -1.1060602e+00 -7.0988669e-01 -5.7421500e-01 5.2160635e-01 1.1572778e+00
+1 1.0096551e+00 1 1 -5.6368830e-01 5.2377344e-01 -1.5112803e+00 -7.5028209e-01 7.0335241e-01 1.4107845e-01 -1.5470909e+00 7.6788080e-01
+1 6.2457740e-01 1 1 1.1341224e+00 3.1758614e-01 -3.1091194e-01 3.6184632e-01 -5.6913285e-01 -7.9696908e-01 1.0051557e+00 1.1003586e-01
+1 2.4628849e-01 1 1 1.1527434e+00 1.0426997e-01 -1.0284087e+00 -5.7224839e-01 7.3376537e-01 1.0918222e+00 1.3089077e+00 -1.0254091e+00
+1 6.7883569e-01 1 1 -4.4038611e-02 -5.4337009e-01 5.7755245e-01 -1.3635848e+00 -1.4981996e+00 2.1221008e-01 1.3792961e+00 7.2682912e-01
+1 7.6998204e-01 1 1 1.2589250e+00 1.8870786e-01 -5.9719770e-01 1.4834609e-01 -3.7591604e-01 9.0709747e-01 1.6531821e-02 1.3047095e+00
+1 9.6582548e-01 1 1 1.2642873e-01 -1.3954975e+00 2.8672738e-01 -1.1717916e+00 -2.7803685e-01 -5.6197613e-01 1.3901553e+00 -6.4966921e-02
+1 8.8759431e-01 1 1 1.1710283e+00 1.0034630e+00 -1.7612708e-01 3.4272989e-01 -1.4170768e+00 -1.5053619e+00 3.1613287e-01 1.3751957e+00
+1 7.3713794e-01 1 1 -6.0601831e-01 1.1328264e+00 -7.8754354e-01 -1.4195941e+00 -3.9522277e-01 -1.3715672e+00 8.1204756e-01 2.1718141e-01
+1 9.8874328e-01 1 1 -3.0636831e-01 1.3622805e+00 -7.1437317e-01 1.2785396e+00 -1.1821504e+00 1.0774805e+00 1.0047954e+00 -3.6272546e-01
+1 2.0367738e-01 1 1 -6.1884581e-02 -7.9030140e-02 6.9730517e-01 -7.9285966e-02 -9.6953467e-01 1.0748295e+00 1.5349959e+00 1.5045690e+00
+1 7.0357085e-01 1 1 -2.2698095e-01 6.3412710e-01 1.4673950e+00 -5.2395348e-01 4.7192181e-01 5.0129128e-01 -8.3576695e-02 6.1220611e-01
+1 7.6678282e-01 1 1 -9.7536818e-01 1.4918602e+00 1.0060837e+00 -2.0197267e-01 -9.3160078e-01 -5.4901046e-01 -3.8159615e-01 6.3216018e-01
+1 6.4321051e-01 1 1 -1.8251172e-01 6.4339442e-01 1.1976541e+00 1.5069757e+00 2.8345418e-01 -3.6120936e-01 -1.4958671e+00 -1.5028169e-01
+1 8.3590506e-01 1 1 -1.2801067e+00 1.6814491e-01 7.8889191e-01 2.2101798e-01 1.3599878e+00 -1.2886553e+00 1.1275946e+00 5.6185988e-02
+1 4.3119165e-01 1 1 -1.1261944e+00 -1.4218167e+00 1.3852814e+00 1.2866282e+00 -9.1396385e-01 -2.8976612e-01 1.3947781e+00 -1.3014848e+00
+1 1.1279971e+00 1 1 1.4637176e-01 -1.5196667e+00 8.1161912e-02 7.7762308e-01 1.3977278e+00 -6.3051468e-01 -5.2908429e-01 8.5466390e-01
+1 3.0010212e-01 1 1 2.0319843e-01 1.0927440e-01 6.3703800e-01 4.8558728e-01 -1.2185038e+00 -4.6814993e-01 1.5291361e+00 9.7461516e-01
+1 1.0014956e+00 1 1 2.4471902e-01 -1.2568078e+00 1.4984553e-01 -5.9235353e-01 6.4919010e-01 1.4936564e+00 -1.1795975e+00 9.2932328e-02
+1 8.7839973e-01 1 1 6.4776673e-01 8.9999474e-01 -1.1035460e+00 2.1372100e-02 1.8670262e-01 -5.8335485e-01 1.0961842e+00 5.4209107e-01
+1 2.8067725e-01 1 1 1.3968472e+00 -5.5707314e-01 6.6591498e-01 1.0593242e+00 -5.4011016e-01 4.6571069e-01 1.2678180e+00 3.0584482e-01
+1 5.6237054e-01 1 1 -3.1113924e-01 -7.8208786e-01 -1.4615584e+00 6.5582236e-01 -1.5703643e+00 1.4923036e+00 -1.2055888e+00 6.8833134e-01
+1 3.6874929e-01 1 1 1.4345058e+00 -1.2693163e-01 -2.9895969e-01 -1.4421563e+00 -5.9257573e-01 -1.3290329e+00 9.4245118e-01 1.4407449e+00
+1 6.0897954e-01 1 1 1.1575830e+00 -1.9851575e-01 -1.2089235e+00 -9.3344754e-01 -5.7161939e-01 -3.3290576e-01 -1.3324535e-01 -7.9680296e-01
+1 2.5939382e-01 1 1 -3.8527018e-01 -8.2866431e-02 1.4444994e+00 6.6088559e-01 -2.1672433e-01 2.9431559e-02 5.0103462e-01 7.4216252e-01
+1 1.0442518e+00 1 1 -4.1352652e-01 -1.0105550e+00 -5.2593428e-01 -1.1675302e+00 -1.3799093e+00 1.4261599e+00 1.4206098e+00 1.4026200e+00
+1 7.6428875e-01 1 1 -9.3727263e-01 -9.4735456e-01 1.0642187e+00 -2.9267585e-01 -8.9925133e-01 -8.8307569e-01 8.4852664e-02 -6.7769186e-01
+1 7.1590939e-01 1 1 -7.9550720e-01 -5.9654431e-01 1.2370804e+00 7.3112063e-01 4.8511421e-01 -9.6948507e-01 -1.6434392e-01 1.4479526e+00
+1 5.7583692e-01 1 1 5.2878979e-01 -1.2980367e+00 5.4934793e-01 1.1756047e+00 8.8151788e-01 1.3055284e+00 -6.6831081e-01 9.6186474e-01
+1 6.8329954e-01 1 1 -1.9568667e-01 -8.8417707e-01 -2.5016126e-01 9.1121136e-01 -7.9915349e-02 1.1329572e+00 -1.1060398e+00 -5.7509198e-01
+1 1.1981239e+00 1 1 3.4159504e-01 -6.3079520e-01 -1.0093988e+00 -5.3480013e-01 1.4643860e+00 4.1805164e-01 -4.0748645e-01 1.1097145e+00
+1 9.6831275e-01 1 1 1.4980581e+00 1.1002799e+00 -3.6579231e-01 -2.8923811e-01 6.9851427e-01 -1.5488985e+00 4.7191602e-02 -6.6457666e-01
+1 8.2995413e-01 1 1 1.1386171e+00 9.9067745e-01 2.2550757e-01 -1.1811097e+00 -2.0247805e-01 -1.1011487e+00 1.4679083e+00 -1.1779668e+00
+1 4.0783226e-01 1 1 1.2971186e+00 -1.2519387e-01 1.3449479e+00 8.1275078e-01 -7.0373066e-01 1.1675367e-01 2.0764906e-01 2.2922447e-01
+1 6.1570729e-01 1 1 1.1602882e+00 7.3369762e-01 7.8104939e-01 2.5749804e-01 4.9510890e-01 -1.2164048e+00 -3.5172006e-01 9.8308797e-01
+1 4.6280174e-01 1 1 1.0982673e+00 5.0465848e-01 1.5230460e+00 -1.3451452e+00 -7.8368192e-01 1.3697480e+00 1.1183534e+00 1.1237142e+00
+1 9.9376101e-01 1 1 -1.4207262e+00 -5.0509853e-01 1.3669567e-01 -9.5450839e-01 1.3559144e+00 -2.3633330e-01 1.6127605e-02 -9.9039861e-01
+1 5.3147166e-01 1 1 1.1009952e+00 -6.0756523e-01 9.3990108e-01 -1.4504744e+00 -2.5918749e-01 -1.0806401e+00 8.7968285e-01 -1.4715359e+00
+1 2.8443627e-01 1 1 4.4620047e-01 -1.1726920e+00 9.8951639e-01 6.3493945e-01 1.2249016e+00 -7.7103247e-01 4.9468133e-01 -1.4873373e+00
+1 6.6838077e-01 1 1 3.0971887e-01 9.1848602e-01 -7.8946768e-01 -5.6286904e-01 6.5125563e-02 3.2690118e-01 1.4549272e+00 -2.5763570e-02
+1 7.3954983e-01 1 1 -1.7398196e-01 -7.9182509e-01 1.5040584e+00 -8.0443200e-01 1.2910964e+00 -4.1738417e-01 -1.1963663e+00 5.3147304e-01
+1 4.4189749e-01 1 1 7.0793117e-01 -4.1773075e-01 1.4547012e+00 1.3261326e+00 4.7655080e-01 2.0059015e-01 -1.1348392e+00 9.1948437e-01
+1 6.5219671e-01 1 1 9.8778067e-01 6.5885587e-01 1.2884309e+00 -1.2889063e+00 1.4696640e+00 3.8966985e-01 -6.3290284e-01 2.7956879e-01
+1 9.3847693e-01 1 1 1.4540633e+00 -7.2343859e-01 -3.3919654e-01 -1.3668808e+00 1.4410072e+00 -1.0395083e+00 2.3473095e-01 -1.1098921e+00
+1 7.7413406e-01 1 1 -7.1333151e-03 -8.6882735e-01 1.1144365e+00 1.3008504e+00 4.7088765e-01 -6.1847152e-01 -7.1734416e-01 8.2122626e-01
+1 1.6801041e-01 1 1 -5.0910605e-01 -2.5861377e-01 1.5845205e-01 1.0499068e+00 5.3677553e-01 8.7933543e-01 1.0292504e+00 1.3332992e+00
+1 9.9351158e-01 1 1 1.1529496e+00 1.4426832e+00 -9.6690869e-01 -5.4299272e-01 -1.0678032e+00 9.3866186e-01 1.0030478e+00 -2.2082109e-01
+1 7.0840980e-01 1 1 2.7996821e-01 3.6401864e-01 6.2442770e-01 2.4802864e-01 1.3500746e+00 -9.8850412e-01 4.3844121e-01 -1.1191685e+00
+1 9.5572750e-01 1 1 -6.8013957e-01 1.3804511e+00 -1.3047049e+00 -2.7617440e-01 -1.0206494e+00 -1.0467095e+00 -1.2949463e+00 -1.1493380e+00
+1 7.6754308e-01 1 1 1.1498613e+00 5.7955528e-01 1.4108909e-01 -1.5308343e+00 -9.5826855e-01 8.7207189e-01 7.9064098e-01 7.2921098e-01
+1 1.3162597e+00 1 1 -1.3587557e+00 -1.4932770e+00 -6.1809673e-01 9.1096980e-01 1.3259328e+00 1.3825992e+00 -6.3393999e-01 4.9607875e-01
+1 5.6964260e-01 1 1 -3.7077434e-01 6.7702403e-01 8.9518591e-01 -1.4532286e+00 -1.5059585e+00 -1.0162571e+00 -1.4887909e+00 -1.9139547e-01
+1 4.4188860e-01 1 1 1.3155484e+00 -1.0574179e-01 3.0243338e-01 1.4689771e+00 1.1671336e+00 6.0570566e-01 6.7616225e-01 2.0715481e-01
+1 6.8091084e-01 1 1 -1.0680920e-01 9.3911071e-01 -9.9124049e-02 -6.7857460e-01 -8.9672400e-02 1.3347881e+00 1.1183313e+00 7.6615235e-01
+1 1.3238347e+00 1 1 -1.2929004e+00 2.7224873e-01 -9.3377680e-01 -8.2192708e-01 8.4045403e-01 -3.2938247e-01 -3.5452540e-01 -6.6567957e-01
+1 6.9509654e-01 1 1 6.1961551e-01 1.5255369e+00 1.4102891e+00 -5.4553124e-01 9.1031514e-01 -4.4486183e-01 1.0928203e+00 -8.6516730e-01
+1 6.7075999e-01 1 1 -5.0177370e-01 1.1603817e+00 -5.8747917e-01 1.5653494e+00 1.1039042e-01 1.9768405e-01 1.2793504e+00 1.5655841e+00
+1 5.9445409e-01 1 1 -1.2759463e+00 -4.7274014e-01 2.6322750e-01 1.1304358e+00 -1.3494038e+00 -1.3292619e+00 9.8136743e-01 -1.2087802e+00
+1 6.6099378e-01 1 1 -3.1861864e-01 -2.5572620e-01 7.0208724e-01 -1.1177871e+00 -2.7164923e-01 -1.0394658e+00 4.8091752e-01 7.1056546e-01
+1 5.8160284e-01 1 1 1.3920129e+00 -2.9144919e-01 1.5828581e-01 7.6971918e-02 -8.7450314e-01 9.4706669e-02 -5.3710057e-01 1.2799422e+00
+1 9.6105858e-01 1 1 1.2010630e-01 -6.4353317e-01 -6.1933898e-01 -6.6914290e-01 -1.4038378e+00 -1.0524837e+00 -1.2536484e+00 1.5039327e+00
+1 9.0439739e-01 1 1 -1.4174312e+00 6.4144408e-01 -1.1337056e+00 6.1698264e-01 -9.4152671e-01 1.2150453e+00 5.9410782e-01 -6.5771364e-01
+1 9.8218413e-01 1 1 -6.8671012e-02 -1.1953003e+00 -4.3133675e-01 -7.7015937e-01 -3.7189726e-02 9.1444203e-01 1.1886036e+00 1.0714464e+00
+1 7.7110932e-01 1 1 -1.1892017e+00 1.0723388e+00 1.3190563e+00 -7.0679274e-01 1.2920802e-01 3.5597509e-01 -5.2711437e-01 1.9092716e-01
+1 1.1620152e+00 1 1 -1.0051227e-01 -5.1897708e-01 -8.3976062e-01 -7.0367513e-01 7.5863761e-01 1.2809773e+00 7.9990843e-02 1.3466498e+00
+1 5.8780924e-01 1 1 8.6710138e-01 -1.3865270e+00 1.3191226e+00 1.4283677e+00 -1.3023238e+00 5.0997186e-02 -1.9556022e-01 1.1097192e+00
+1 5.1345804e-01 1 1 -4.7535249e-01 9.7557857e-01 2.7399328e-01 -1.4753835e+00 -6.7946644e-01 -5.4508897e-01 -6.7477285e-01 -5.8518438e-01
+1 8.5546921e-01 1 1 -1.7922631e-01 5.7696105e-01 -5.6983128e-01 -1.7965032e-01 -1.0309767e-01 -4.2615769e-01 2.4222509e-01 1.1327309e+00
+1 5.3198317e-01 1 1 5.3077316e-01 -1.1120917e+00 1.5616843e+00 -3.1241418e-01 1.3966462e+00 3.9903225e-01 -4.2706077e-01 -2.4331703e-01
+1 6.6452022e-01 1 1 -1.4186045e+00 1.5503622e+00 -7.7819468e-01 -1.1437636e+00 -5.4759081e-01 -7.6524807e-01 9.2893313e-01 9.2426473e-01
+1 1.2230955e+00 1 1 -9.3886316e-01 5.6794065e-01 -6.6784022e-01 1.7142278e-01 1.5076641e+00 1.5608778e-01 -1.1364266e+00 -1.0584059e+00
+1 3.9095648e-01 1 1 7.4676628e-01 1.2199923e+00 5.1998143e-01 2.6221742e-01 -7.7517621e-01 1.3745763e-01 9.6075803e-01 -9.3004028e-01
+1 9.1731636e-01 1 1 2.3826010e-01 -7.6515224e-01 -5.8293779e-01 -5.6627521e-01 -2.0187960e-01 1.1797332e+00 -3.2604727e-01 1.3780952e+00
+1 7.9761892e-01 1 1 -1.0931164e+00 -1.3749653e+00 1.1921085e+00 -1.5032995e+00 -7.0301421e-02 1.1853664e+00 -9.3894382e-01 -1.3171548e+00
+1 7.6403702e-01 1 1 2.6708824e-02 5.1362170e-01 -1.3099288e+00 -1.2662564e+00 -3.1715245e-01 -1.5269587e+00 -6.0895088e-01 1.3819667e+00
+1 9.4168798e-01 1 1 -3.5254768e-01 -6.5677980e-01 3.0869370e-01 -8.2233237e-01 9.0151295e-01 7.5456609e-02 6.7148439e-01 9.1902303e-01
+1 6.6910367e-01 1 1 -2.2505357e-01 1.0584190e+00 1.4455814e+00 -1.0741245e+00 -1.7320078e-01 -1.0042095e+00 1.0373216e+00 -1.1910118e+00
+1 1.2534732e+00 1 1 2.2291309e-03 1.1507847e+00 -1.1904054e+00 -1.2197231e+00 1.2708154e+00 -1.1138776e+00 1.5672701e+00 8.9364148e-01
+1 8.5663727e-01 1 1 -2.3410825e-01 -1.5469182e+00 -1.4816032e+00 -9.9481243e-01 -1.0940290e+00 -1.9084593e-01 -1.1464397e+00 -5.2209192e-01
+1 1.2589354e+00 1 1 -1.3833099e+00 7.6606504e-01 -1.0412970e+00 -2.5635837e-01 3.9716129e-01 1.8607217e-02 -8.2376241e-01 -3.3065473e-01
+1 3.3180567e-01 1 1 -1.5044167e+00 1.0084222e+00 7.3367280e-01 -1.4915903e+00 -7.9458836e-01 -1.4277670e+00 2.3926696e-02 1.6343154e-01
+1 1.0255683e+00 1 1 -1.1946088e+00 -3.4016106e-01 8.7658479e-02 7.5155986e-01 2.6384127e-01 -9.9589902e-01 1.2119096e-02 1.0418613e+00
+1 3.6898164e-01 1 1 1.2878593e-01 6.1162308e-01 -1.3089371e-01 -8.7747029e-01 -1.5485983e+00 3.3085957e-01 -5.1786847e-01 -6.7506921e-01
+1 1.0169203e+00 1 1 -5.2143719e-02 2.5795446e-01 -8.1574107e-01 -1.0073018e+00 8.0283575e-01 1.3773371e-01 1.5379353e+00 1.5443995e+00
+1 6.9588171e-01 1 1 1.2486834e-01 4.2772985e-02 -2.4980961e-01 3.2127774e-01 1.2002925e-01 -4.6326981e-01 -9.4658229e-01 8.8357718e-01
+1 1.0202566e+00 1 1 7.8378843e-02 -5.3915300e-01 -1.3822484e+00 -6.8280216e-01 4.2907651e-01 -1.3090841e+00 -1.8329817e-01 -2.6729559e-02
+1 6.7855869e-01 1 1 9.8589516e-01 -1.1912986e+00 6.2880272e-01 3.8203456e-01 1.5338087e+00 -1.2026816e+00 1.2100876e+00 4.0477941e-03
+1 5.2031870e-01 1 1 1.1802764e+00 -7.8534488e-01 -3.0344095e-02 -5.6055036e-01 -1.1864873e+00 -4.6223643e-01 -7.2839568e-01 -1.0837626e+00
+1 1.1160138e+00 1 1 8.9013471e-01 -1.4606218e+00 -1.0551911e+00 4.6653225e-01 1.5381462e+00 3.5090432e-01 6.4042636e-01 1.5536323e-01
+1 6.8366338e-01 1 1 2.2979168e-01 -2.6615644e-01 -3.0574182e-01 -4.0779633e-01 -5.4251934e-01 8.7953012e-01 5.4933848e-01 5.2637098e-01
+1 3.7572652e-01 1 1 1.0914316e+00 3.3664353e-01 1.0427842e+00 1.1223272e+00 -1.2206057e+00 1.0692653e+00 -4.0901958e-01 -7.8598017e-03
+1 6.1352343e-01 1 1 -6.8691119e-02 -4.0627979e-02 -8.7196018e-01 8.3096076e-01 -1.1975554e-01 1.2311412e+00 -5.8732332e-01 -1.5279541e-01
+1 8.8928455e-01 1 1 -1.5271291e+00 -1.1088336e+00 4.9495806e-01 -1.5633988e+00 1.0295588e+00 1.2601756e+00 -2.5893638e-01 -1.3513072e+00
+1 8.8331748e-01 1 1 3.5388694e-01 -2.3831302e-01 -1.7718373e-01 2.3797607e-01 -9.7830649e-02 -8.4698551e-01 -8.3792895e-01 -8.4663009e-01
+1 1.5986849e-01 1 1 7.4285690e-01 2.0377046e-01 3.0290193e-01 4.1632864e-01 -1.1867596e+00 -7.2920767e-01 6.8797520e-01 -1.0387942e+00
+1 5.3285272e-01 1 1 5.0666804e-01 4.3405309e-01 1.4927209e+00 9.0868917e-01 1.0296717e-01 -4.4036401e-01 -1.4033090e+00 -1.1839214e+00
+1 1.0749064e+00 1 1 -1.2879289e+00 3.5220488e-01 -5.9879949e-01 1.0569883e+00 -4.4838504e-01 3.9443011e-01 -1.4780087e+00 6.8048436e-01
+1 1.1240986e+00 1 1 -6.4750282e-01 7.4680361e-01 -1.5018400e+00 -9.0477986e-01 6.7347726e-01 4.2637906e-01 -3.1863322e-01 1.5033216e+00
+1 3.7045837e-01 1 1 -1.0292198e-01 8.6565332e-01 1.2726692e+00 -1.3266010e+00 -2.6000230e-02 1.8009202e-01 1.1470008e+00 -1.5032818e+00
+1 7.6935231e-01 1 1 1.2078856e+00 3.1978365e-01 -1.3524826e+00 -2.9952101e-01 -3.0448979e-01 1.4528370e+00 8.2992137e-01 -9.6897177e-01
+1 4.4175459e-01 1 1 -3.8009275e-02 -6.6127970e-01 1.3895615e+00 -1.2182542e+00 9.4498106e-02 1.3725855e+00 -1.8289733e-01 5.0780677e-01
+1 3.1146281e-01 1 1 -1.0785756e+00 8.2685738e-01 -2.4043658e-01 -1.4387687e+00 -1.4162235e+00 3.2911154e-01 -1.4778783e+00 -9.9888132e-01
+1 7.3473659e-01 1 1 -6.2989804e-01 -1.4138415e+00 -9.2941091e-01 -5.4642033e-01 1.3789039e+00 -9.6693473e-01 -1.2693777e+00 4.7279446e-01
+1 7.2941316e-01 1 1 4.7087441e-01 5.7260895e-01 -6.1053935e-01 -8.1121437e-01 -2.9183335e-01 1.8684816e-01 1.2476581e-01 1.1687005e+00
+1 6.1153310e-01 1 1 3.1435914e-01 1.1402504e+00 -8.9331426e-01 4.3211694e-01 -8.1696344e-01 -1.2356388e+00 1.4966747e+00 1.1118740e+00
+1 6.2218082e-01 1 1 -7.2484040e-01 4.7330953e-01 -2.6148790e-01 -7.7274391e-01 1.1969832e+00 -1.4545858e+00 -1.2004965e-01 1.0733776e+00
+1 5.4178178e-01 1 1 7.0370891e-01 4.0060650e-01 2.6103232e-01 -1.6281519e-01 -1.0621232e+00 6.4985685e-01 -7.7199509e-01 1.2331398e+00
+1 7.6935980e-01 1 1 -8.6072152e-01 5.6036568e-01 1.5068044e+00 -1.0775438e-01 -5.7587611e-01 -1.1736290e+00 -1.4375207e-01 2.9385044e-01
+1 7.8973763e-01 1 1 8.8763820e-01 -4.2881123e-01 4.8356493e-01 -1.4704489e+00 4.9718855e-01 8.7847869e-01 -1.5631942e-01 1.6075748e-01
+1 1.0891084e+00 1 1 -8.8826022e-01 -2.1686981e-01 -2.4366676e-02 1.0753725e+00 -3.8853646e-01 -8.9405622e-01 -8.8906156e-01 8.1319531e-02
+1 1.2527900e+00 1 1 -1.4124526e-01 -6.8334799e-01 -1.1236764e+00 2.0256816e-01 1.2387877e+00 -1.6523675e-01 -1.0429174e+00 1.4455095e-01
+1 7.1546793e-01 1 1 1.1349989e+00 6.3300921e-01 -1.5162279e+00 -9.2340946e-01 9.7076088e-01 3.3848438e-02 -1.3673495e+00 1.0166358e+00
+1 6.8860004e-01 1 1 1.7646072e-01 1.5530828e+00 1.3564870e+00 -2.7500679e-01 1.2875425e+00 2.6241884e-01 -2.9261728e-01 -5.2477268e-01
+1 8.3022936e-01 1 1 1.1180346e-01 -8.3086646e-01 -6.0067682e-02 -7.5626207e-01 4.3674909e-01 -3.2259498e-01 -1.4260471e+00 -1.4038799e+00
+1 7.3893377e-01 1 1 4.0831071e-01 6.8240923e-03 -1.1062876e+00 3.8727938e-01 -1.4601108e+00 5.3503716e-01 -3.6389614e-01 1.4929854e+00
+1 9.8407415e-01 1 1 1.2397876e+00 -1.5464097e+00 -1.4302633e+00 -3.7545066e-01 -1.1026030e+00 1.1313478e+00 6.7838807e-01 7.0513274e-01
+1 6.6945958e-01 1 1 -1.0745802e+00 -1.1129475e-01 1.0314036e+00 1.2603554e+00 8.0599247e-01 -1.4985170e+00 8.2859438e-01 1.0784224e+00
+1 8.5193608e-01 1 1 5.4732680e-01 -1.2833101e+00 -5.0823358e-01 -9.6633624e-01 -2.3213091e-01 5.7306231e-01 -4.9453645e-01 1.1969091e+00
+1 1.0847589e+00 1 1 3.3830678e-01 -1.5597695e+00 1.0870772e-01 8.2079373e-01 4.3394245e-01 -6.6488522e-01 9.7999878e-01 8.3328851e-01
+1 6.8631159e-01 1 1 -3.6066856e-01 1.5454971e+00 -1.3563000e+00 3.4691563e-01 -1.5074283e+00 -8.0800994e-02 -5.3077018e-01 -1.3999348e-01
+1 4.2264957e-01 1 1 1.5173088e+00 4.8209144e-01 6.1686292e-02 -1.8498671e-01 -1.5436324e+00 -8.5427477e-01 1.4686887e+00 1.8255763e-01
+1 2.6706508e-01 1 1 1.1007188e+00 3.4341822e-01 3.5942058e-02 1.1051373e+00 -5.5729620e-01 -7.1768655e-01 7.5814131e-01 -1.0900114e+00
+1 4.2523991e-01 1 1 -1.0582409e+00 7.2440291e-01 8.9237268e-01 9.4734517e-01 -1.3894875e+00 1.5579587e+00 -2.1884893e-01 -1.1948816e+00
+1 7.2026644e-01 1 1 -1.2987305e+00 1.3681985e+00 1.4422739e-01 4.3866949e-01 1.4836916e+00 -5.6319443e-01 6.1097123e-01 -1.3144331e+00
+1 9.6129554e-01 1 1 2.3035810e-02 -1.1455617e+00 -1.2797614e+00 -5.9991771e-01 -1.5579216e+00 9.8573110e-03 -1.2729345e+00 1.5999957e-03
+1 6.4901783e-01 1 1 7.4695482e-01 1.3654710e+00 1.5356678e+00 -1.4461741e+00 1.1858177e+00 -8.3258484e-01 3.5691218e-02 -1.3832062e+00
+1 9.3055790e-01 1 1 2.6537570e-01 1.3662799e-01 -1.3558613e+00 6.5436632e-01 -2.2534182e-01 -5.9965720e-01 -1.8188992e-01 2.3938579e-01
+1 6.5456614e-01 1 1 -8.9210240e-01 -1.9767788e-01 1.1526641e+00 -7.8119285e-01 1.4407153e+00 -2.0934051e-01 -2.5426469e-01 -1.0232397e+00
+1 4.8759965e-01 1 1 1.2566524e+00 1.4329710e+00 -1.3766929e+00 -7.9255420e-01 -1.2938099e+00 1.9789030e-01 -8.6057919e-01 -5.1126318e-01
+1 1.1686304e+00 1 1 -3.7013505e-01 4.9405514e-01 -2.4795606e-01 -1.0565260e-01 1.0410865e+00 -1.0043699e+00 1.3806672e-01 -5.4441116e-01
+1 5.4853152e-01 1 1 -5.0626151e-01 3.5532340e-01 1.4959486e+00 -7.0337186e-01 -1.1294498e+00 -6.6832768e-01 -1.1496562e+00 1.5410323e+00
+1 6.6856207e-01 1 1 -1.3043680e+00 -2.4733001e-01 2.4174395e-01 2.4234353e-01 -1.1607642e+00 -1.3895064e+00 -1.4764837e+00 8.3981277e-01
+1 4.1672900e-01 1 1 -4.7928047e-01 -5.4837610e-01 9.1126106e-01 1.5635487e+00 3.2660174e-01 1.1659504e+00 1.7802092e-01 -4.4253745e-01
+1 7.1391122e-01 1 1 -2.2327332e-01 8.7578804e-01 3.0040464e-01 -8.5905451e-01 8.3308321e-01 -1.1270088e+00 1.2013303e+00 1.5645386e+00
+1 9.2718620e-01 1 1 -1.4931114e+00 1.0080768e+00 3.6146563e-01 6.3068854e-01 -4.4902665e-01 -9.7427455e-01 -2.5777256e-01 7.0151221e-02
+1 8.7890530e-01 1 1 3.1856216e-01 1.3706144e-01 -6.8728390e-01 2.4865528e-01 -6.8535003e-01 -6.5151409e-01 -1.2708686e-01 9.3432152e-01
+1 5.9661402e-01 1 1 8.0026550e-01 8.0426943e-01 4.5565005e-01 8.3102683e-01 1.5422427e+00 -1.5469678e+00 3.3409771e-01 1.4616426e+00
+1 8.6898215e-01 1 1 9.0405225e-01 -9.1689805e-01 -1.0924831e+00 -4.5298874e-01 -8.0788260e-01 -6.7221931e-02 1.1541744e+00 -1.4278818e+00
+1 8.5567561e-01 1 1 -1.4775149e+00 -7.9352529e-01 1.2454133e+00 -1.3026983e+00 -1.1947466e-01 1.1743675e+00 -1.1247312e+00 2.1721616e-01
+1 9.8975056e-01 1 1 -1.4442998e+00 -7.1866611e-01 -7.7051100e-01 -6.9089122e-01 -5.3287180e-01 -1.0312314e+00 -3.9490087e-01 2.2129583e-01
+1 7.1982201e-01 1 1 7.3983933e-01 8.0241280e-01 -3.3342683e-01 -4.8222607e-01 7.0429174e-01 2.6095531e-01 1.0863156e+00 -3.2672263e-01
+1 8.8117084e-01 1 1 5.5951520e-02 -7.0535691e-01 6.9654566e-01 5.3540851e-01 -4.8976132e-01 2.1258001e-01 -1.2296143e+00 2.7674087e-01
+1 2.1028529e-01 1 1 1.0410013e+00 1.4370352e+00 1.2686236e+00 1.0894182e+00 -4.4577701e-01 8.4141659e-01 -7.3109083e-01 -1.5148558e+00
+1 7.4769739e-01 1 1 5.7991008e-01 -3.1448997e-01 -2.3244143e-01 6.4932722e-01 5.2419907e-01 1.3800833e+00 -6.7468832e-01 -7.1517067e-01
+1 6.2871845e-01 1 1 1.3283287e+00 -1.4740724e+00 1.4981121e+00 -6.5030117e-01 1.1879916e+00 6.8071558e-01 -1.4787154e+00 -1.3999752e-01
+1 5.9019088e-01 1 1 1.0629182e+00 -1.3510265e-01 -1.0946236e+00 -1.1001725e-02 -1.3884676e+00 -8.9369906e-01 3.6901540e-01 1.1464760e-01
+1 7.2780658e-01 1 1 1.3708149e+00 7.0119186e-01 -1.7300492e-01 4.4796657e-01 -2.2394339e-01 -4.4568738e-01 5.3785645e-01 1.0859472e+00
+1 6.8281649e-01 1 1 -1.1538320e+00 8.1746652e-01 1.4211132e+00 -1.4234789e+00 -1.8849458e-01 -1.1109565e+00 1.3913696e+00 -1.1380184e+00
+1 1.0050658e+00 1 1 5.9779328e-01 9.7514573e-01 -8.7944770e-01 -1.1813087e+00 -1.3030613e+00 -1.3606514e+00 -1.2667013e+00 -6.5992747e-01
+1 6.6448566e-01 1 1 2.9836330e-01 -4.1453666e-01 3.1600580e-01 6.1106560e-01 -5.0957643e-01 -8.1517224e-01 1.1246963e+00 1.5626268e+00
+1 5.4861278e-01 1 1 6.1016227e-01 9.3480197e-01 -1.3237497e+00 3.1316532e-01 -4.6953111e-01 -1.1419870e-01 -1.9148079e-01 -6.4578842e-01
+1 7.6649966e-01 1 1 8.3891094e-01 1.1186308e-01 4.9741292e-01 1.2017729e+00 2.7145257e-01 1.7551864e-01 -1.2267744e+00 4.3658361e-01
+1 7.3006484e-01 1 1 1.0838554e-01 1.4104138e+00 2.4091794e-01 8.9796809e-01 7.1073152e-01 -1.3792131e-02 -1.2544581e-01 -1.0997312e+00
+1 9.0207698e-01 1 1 -4.8799250e-01 1.5088064e+00 -4.0514906e-01 -6.1495777e-02 9.2942203e-01 6.7351860e-01 -3.5903002e-01 -1.1919612e+00
+1 9.7843713e-01 1 1 1.0084977e+00 -4.2704545e-01 -1.5089411e+00 2.4464702e-02 7.9737797e-01 6.6878668e-01 7.8198928e-01 6.4380645e-01
+1 4.2615250e-01 1 1 9.2905810e-01 1.1864110e+00 1.3042986e+00 -3.7039742e-01 -5.0264584e-01 -3.2077157e-01 -1.5297828e+00 8.0986421e-01
+1 5.0636934e-01 1 1 9.6398957e-01 3.2038465e-01 -6.8709017e-01 1.3672226e+00 -2.2595106e-01 -2.3475781e-01 -2.6550651e-01 -1.1331692e+00
+1 6.3882907e-01 1 1 5.7945572e-01 1.4931378e-02 5.7012420e-01 1.3007484e+00 6.2600418e-01 2.6587282e-01 -1.3063924e+00 -8.3927650e-01
+1 8.7795666e-01 1 1 -2.4896856e-02 -3.7574255e-01 2.1990469e-01 -6.6441565e-01 5.8453574e-02 1.1797105e+00 5.3817056e-02 3.0909611e-02
+1 4.1362170e-01 1 1 -6.0964263e-01 -5.0380126e-01 1.4251531e+00 1.5281321e+00 -8.8927992e-01 8.0359998e-01 -2.7542892e-01 1.1350381e+00
+1 8.2547052e-01 1 1 -1.5300960e+00 -7.9556391e-01 1.0463364e+00 7.9628454e-01 1.5701516e+00 3.9809461e-01 -1.5678056e+00 8.3399792e-01
+1 7.7018664e-01 1 1 7.5445526e-01 -4.2423716e-01 -8.5969620e-01 -3.0496298e-02 1.5915559e-01 -8.1624589e-01 1.5704595e+00 -7.8333584e-01
+1 1.0957960e+00 1 1 6.6167939e-01 1.2613645e+00 -7.2946647e-01 -4.7168197e-01 1.4326237e+00 6.9037065e-01 -9.4890236e-01 8.8938739e-01
+1 7.8782247e-01 1 1 -3.9255625e-01 2.8538063e-01 1.4931867e+00 -1.3205272e+00 9.4101072e-01 1.1578228e+00 -1.4775957e+00 2.3597968e-01
+1 2.5211259e-01 1 1 -3.4828223e-01 -8.1969426e-01 9.4750984e-01 1.2522452e+00 7.8981833e-01 5.0254719e-01 3.3850230e-01 1.4205673e+00
+1 1.2073776e+00 1 1 -7.9227883e-01 -7.1771647e-01 6.4693048e-02 9.5526724e-01 1.2476949e+00 -1.4320419e+00 -2.1622253e-01 -6.2913690e-01
+1 6.2477605e-01 1 1 1.3810122e+00 1.0551491e+00 3.0500787e-01 -1.5035586e+00 -1.2273555e-01 -5.8726161e-01 7.7058284e-01 6.9698689e-01
+1 3.8646979e-01 1 1 5.8519790e-01 -3.9910128e-01 -8.1194233e-01 6.6254903e-01 1.2100219e+00 7.7817901e-01 1.5408582e+00 -7.4041420e-01
+1 8.3412287e-01 1 1 -9.0547081e-01 -3.9490199e-01 7.6369280e-01 -1.4843990e+00 1.3092288e+00 4.0438768e-01 1.0555210e+00 -2.9293571e-01
+1 8.9694243e-01 1 1 -3.7313945e-01 1.0674572e+00 -1.1627555e+00 -9.0748007e-01 4.9375285e-01 1.2788947e+00 -4.3244991e-01 -4.9484538e-01
+1 2.2602518e-01 1 1 -7.3579101e-01 -8.8241650e-01 1.4156419e+00 4.1480507e-01 1.5578948e+00 -3.9418336e-01 1.4597941e+00 -1.0706241e+00
+1 6.6579800e-01 1 1 -1.1307521e+00 6.8488114e-01 1.4121606e+00 4.3467991e-01 1.5044511e+00 5.7923589e-01 -1.0787257e+00 1.0638673e+00
+1 5.7267602e-01 1 1 -1.0567802e+00 1.8499338e-03 -5.4904159e-01 1.4622828e+00 -1.3694536e+00 -5.7800780e-01 -1.2089705e-02 -1.5281222e+00
+1 5.9554118e-01 1 1 1.2600863e+00 -3.2408934e-01 -8.8445093e-01 -9.1969814e-02 -1.0992060e+00 -7.7264883e-01 1.0118512e+00 -6.2921408e-01
+1 3.4017342e-01 1 1 7.9372677e-01 5.5218309e-01 1.0497280e+00 -7.3085159e-02 1.3509191e+00 1.4350619e+00 7.4192351e-01 -6.0011424e-01
+1 7.9839420e-01 1 1 9.6347735e-01 2.7641111e-01 -4.0557035e-01 2.0468333e-02 6.0696174e-01 1.0790635e+00 5.2726832e-01 1.5340565e+00
+1 3.6630490e-01 1 1 1.3953228e+00 -7.7393492e-01 8.3517193e-01 -1.5639236e+00 4.5455960e-01 -5.9495356e-01 -6.3414275e-01 -1.6341538e-01
+1 4.6472127e-01 1 1 -7.9938453e-01 -1.3306116e+00 9.8658197e-02 8.4145833e-01 -5.7017555e-01 3.0497051e-01 1.3866487e+00 -7.7039329e-01
+1 5.9130658e-01 1 1 1.3359539e+00 1.4091638e+00 -6.1260630e-01 -1.0600348e+00 -1.0829177e+00 -1.4397781e+00 1.0708686e+00 -1.4966544e+00
+1 6.4947174e-01 1 1 4.1379187e-01 -6.5044685e-01 -1.0749439e+00 -3.2125225e-02 -1.3508979e+00 1.3372840e+00 -9.5723308e-02 4.6107500e-01
+1 3.6577891e-01 1 1 -8.8610259e-01 6.8219116e-01 7.1691346e-01 4.2527418e-01 -2.5091356e-01 7.7905582e-01 -3.2620183e-01 -1.0214725e+00
+1 5.3687308e-01 1 1 1.5644997e+00 -1.2263242e+00 1.1567419e+00 4.5991998e-01 -1.0869305e+00 -5.6707587e-01 -3.9494646e-01 9.1601475e-01
+1 4.4842930e-01 1 1 -5.8352578e-01 1.1589600e+00 1.1857538e+00 1.5571459e+00 3.2095523e-01 7.4800493e-01 3.2020107e-01 -1.4856975e+00
+1 7.4684579e-01 1 1 7.3440446e-01 7.6604859e-01 -1.2996086e+00 1.4843307e+00 1.7989947e-01 -9.3490108e-01 7.1191187e-02 -7.3959378e-01
+1 7.1884582e-01 1 1 -1.8171160e-01 7.3201219e-01 9.7249376e-01 -2.4057306e-01 1.3583277e+00 1.3640654e+00 -4.3651712e-01 9.2955105e-01
+1 1.0056310e+00 1 1 -3.9871901e-01 4.5210366e-01 -1.0039582e+00 -8.1613308e-02 -5.4083936e-01 -1.4966749e+00 -9.2432117e-01 -1.7571633e-01
+1 4.5745184e-01 1 1 -2.5331224e-01 -1.0063980e+00 -3.1968402e-02 1.2011183e+00 -1.2595647e+00 1.1680413e-01 1.0982923e-01 -1.6723975e-01
+1 9.2689467e-01 1 1 -5.6073366e-01 -1.9689501e-01 -8.0588338e-02 -6.7880072e-01 -1.4520386e+00 -3.6836546e-01 -1.3566200e+00 9.2700186e-01
+1 9.9018028e-01 1 1 5.2726694e-01 -1.1173637e+00 -4.2176436e-01 -1.4807633e+00 -5.2153850e-01 9.6087237e-01 9.6763693e-01 9.6226493e-01
+1 1.1063867e+00 1 1 -6.5745148e-01 9.0857866e-01 -1.1605391e+00 5.0886422e-01 -4.5409524e-01 -1.5458502e+00 -9.5135656e-01 -1.3233282e-01
+1 3.0741294e-01 1 1 -8.0562738e-01 -8.0040744e-01 9.6751381e-01 1.0656905e+00 -1.0501130e+00 -1.3282106e-01 1.2569104e+00 1.2984454e-01
+1 5.0610006e-01 1 1 8.4894070e-02 -1.4806349e-01 1.2097194e-01 8.4065129e-01 2.1807617e-01 1.3488690e+00 8.2327743e-01 -1.1097160e+00
+1 1.6352854e-01 1 1 5.3157401e-01 -3.6167518e-01 5.6497416e-01 1.0840938e+00 -1.0324049e+00 7.0796268e-01 1.2497798e+00 6.3846498e-01
+1 9.4293473e-01 1 1 -5.2519366e-01 3.0707060e-01 -1.5138034e+00 -8.7327047e-01 -6.1341667e-01 1.5173903e+00 3.6055525e-01 -9.9956850e-01
+1 5.1898224e-01 1 1 9.4554399e-01 -7.0119776e-01 1.2651652e+00 4.6408091e-01 1.0131011e+00 -6.6978965e-01 -2.8007348e-01 1.4896911e+00
+1 6.9348624e-01 1 1 -1.5594018e+00 -9.1667613e-01 1.3322480e+00 -7.6664269e-01 -2.4265335e-01 -8.2821972e-01 -1.0891108e+00 -1.2546476e+00
+1 5.3067663e-01 1 1 1.4417060e+00 -2.0537749e-01 9.6047432e-01 -1.2921468e+00 -4.8752799e-01 5.0827244e-01 1.3754790e+00 -4.9164503e-01
+1 5.6478848e-01 1 1 -3.5167128e-01 8.3087605e-01 1.1888561e+00 7.1875935e-01 -6.0928293e-01 5.4440378e-01 -1.3046064e+00 -6.8927238e-01
+1 3.0494681e-01 1 1 -1.2034999e+00 1.5444377e-01 5.7571862e-01 7.6465648e-01 1.3738033e+00 1.4765176e+00 -1.3451414e+00 -1.5487360e+00
+1 4.6803169e-01 1 1 1.4922259e+00 7.8096826e-01 -2.4640566e-03 -6.7403064e-01 -1.1939264e+00 3.9124801e-01 -8.9102408e-01 -1.5107766e+00
+1 5.8169934e-01 1 1 5.0722186e-01 1.5938713e-01 -5.7269409e-01 1.5012919e-01 -9.6875696e-01 3.5190101e-01 5.3051644e-01 -1.2710325e+00
+1 1.1212239e+00 1 1 -1.4047308e+00 -9.5911069e-01 5.7031430e-01 5.2233190e-01 9.7650964e-01 -1.2186981e+00 5.4993395e-01 5.8738794e-01
+1 6.7078498e-01 1 1 -2.4249004e-01 -2.6137981e-01 2.7330408e-01 1.2223569e+00 5.1743913e-01 5.2451223e-01 1.7427623e-01 1.3449558e+00
+1 3.1367087e-01 1 1 -8.8449352e-01 -1.0638811e+00 4.1318414e-01 1.2778275e+00 6.7099701e-01 1.6807897e-01 1.0962535e+00 9.1364851e-01
+1 3.8914028e-01 1 1 3.3386982e-01 1.2949120e+00 1.4660300e+00 5.1967638e-01 -8.7091222e-01 6.1152960e-01 -7.0767446e-01 -4.1440106e-01
+1 9.6443009e-01 1 1 4.6558767e-01 -1.3685892e+00 5.5741254e-02 5.7340955e-01 -7.4143741e-01 -1.3131471e+00 1.8512604e-01 7.2301182e-02
+1 8.4794222e-01 1 1 -5.7526402e-01 8.6249685e-01 6.4864192e-01 -1.1120375e+00 1.3595254e+00 -3.7545015e-01 1.2365537e+00 -6.3038800e-01
+1 6.3220763e-02 1 1 1.3597219e+00 6.7604987e-01 3.9823930e-01 -6.7960847e-01 7.4074689e-01 1.2688872e+00 1.1227846e+00 -1.4806822e+00
+1 7.6398983e-01 1 1 9.0127299e-01 -7.7041315e-01 -1.5260106e+00 6.5141586e-01 -3.9866315e-01 1.0556320e+00 -9.0712539e-01 -1.2704711e+00
+1 6.1942606e-01 1 1 -1.0646079e+00 1.3111169e+00 3.0230255e-01 -1.0409156e-01 6.8555244e-01 1.4335513e+00 9.2752784e-02 5.9807095e-01
+1 3.3055339e-01 1 1 -1.4947712e+00 8.1120670e-01 8.4365416e-01 4.0019430e-01 -1.2819169e+00 8.2316781e-01 6.6608879e-01 -1.3180117e+00
+1 3.1938493e-01 1 1 6.9734171e-01 -5.6110173e-01 1.2877821e+00 -8.4205741e-02 -1.3489277e-01 -5.9266684e-01 1.4596299e+00 -4.5352979e-01
+1 6.8441766e-01 1 1 -1.0600323e+00 6.2434575e-01 1.3211980e+00 -1.5291943e+00 1.0870356e+00 1.0386539e+00 -6.9771733e-01 -9.7132328e-01
+1 6.2953849e-01 1 1 8.3454115e-03 4.5963213e-01 5.9800778e-01 2.0161447e-01 1.4467707e+00 -1.1748578e+00 1.0301671e+00 -1.3149449e+00
+1 7.2591196e-01 1 1 -1.1103386e+00 -1.3914989e-01 7.6187826e-01 -1.2440312e+00 -5.1671157e-02 -9.2460343e-01 7.0158721e-01 8.2602341e-01
+1 5.6146938e-01 1 1 -3.9974439e-01 -1.3473319e+00 -2.4376505e-01 -1.1336583e+00 -1.3575594e+00 -1.4925924e+00 1.1790385e+00 2.7751255e-01
+1 1.0236411e+00 1 1 1.3627352e+00 -6.8900333e-03 -3.2232586e-01 3.6474969e-01 8.8605254e-01 -3.8294953e-01 -1.0658802e+00 -1.1116413e+00
+1 1.1030223e+00 1 1 1.2797275e+00 4.3813874e-01 -1.2249275e+00 1.1007298e+00 7.3586427e-01 8.9067971e-01 -8.8724001e-01 -3.0380043e-01
+1 7.8472363e-01 1 1 1.0374919e+00 -9.5423780e-02 -4.9997592e-01 -8.7393476e-01 -7.7955953e-01 -3.5123948e-02 1.2975069e+00 -8.8576354e-01
+1 9.2816391e-01 1 1 1.2863564e+00 1.5663741e+00 6.6510707e-01 -1.2759227e+00 1.5259916e+00 2.9121704e-01 1.4044560e+00 9.7980629e-01
+1 8.6063678e-01 1 1 -6.4826199e-01 -4.9702010e-01 6.6784236e-01 7.7998520e-02 -6.2132230e-01 -1.1657795e-01 -1.2347332e+00 -6.2434516e-01
+1 4.9080918e-01 1 1 -2.9589082e-01 7.7995168e-02 -4.8393650e-01 8.7698188e-01 9.0023542e-02 1.0282343e+00 1.1997403e+00 -4.4964970e-01
+1 4.1957461e-01 1 1 1.0419134e-01 8.2065245e-01 6.2681931e-02 -9.1833983e-01 -1.2219829e+00 -3.6722885e-01 1.2928606e+00 1.4094277e+00
+1 3.7344819e-01 1 1 1.2767309e+00 1.1140424e+00 1.0616774e+00 1.0711480e-01 -1.2755246e+00 1.2143176e+00 -1.2883153e+00 6.4286368e-01
+1 1.0464504e+00 1 1 9.3797982e-01 -1.8126188e-01 -6.3442367e-01 1.4592080e-01 4.8613881e-01 1.2498043e+00 -8.5924004e-01 6.7276178e-01
+1 7.7739784e-01 1 1 1.1481679e-01 8.7649115e-01 -1.9317720e-01 -1.0929601e+00 -7.4756079e-01 7.7278533e-01 6.5407518e-01 5.1532957e-01
+1 6.8680475e-01 1 1 7.8782252e-01 2.5873871e-01 -1.4639059e+00 -4.8785759e-01 -1.0251097e+00 8.5892982e-01 6.0878266e-01 -2.2681048e-01
+1 2.9227348e-01 1 1 -8.8002086e-01 6.5726588e-01 1.0880126e+00 1.3431800e-01 -5.2496598e-01 4.1518407e-01 -3.5703372e-01 -1.2518561e+00
+1 6.2851703e-01 1 1 1.0756742e-01 8.2793218e-01 -9.8242670e-01 -1.3225692e+00 -1.5109779e+00 5.2131713e-01 -2.2374922e-01 -6.9969093e-01
+1 2.4319126e-01 1 1 1.4698137e+00 9.4231069e-01 5.6544298e-01 1.4892874e+00 -1.5116639e+00 -1.2493068e-01 -6.6742600e-02 -7.2409270e-01
+1 8.2962639e-01 1 1 8.1653575e-01 6.4713398e-01 8.2467254e-02 1.3853240e+00 -4.7490070e-01 -1.1261159e+00 -1.9429496e-01 7.0401195e-01
+1 7.6043572e-01 1 1 1.0397080e+00 1.8704331e-01 5.8478561e-01 7.9778231e-01 1.1309469e+00 1.4652818e+00 -1.4005688e+00 1.0908638e+00
+1 1.3293418e+00 1 1 8.3478612e-01 -1.0974134e+00 -1.5517388e+00 9.8919734e-03 1.1896456e+00 4.6217991e-02 5.9471338e-01 -1.8615662e-01
+1 7.5078816e-01 1 1 -1.0253109e-01 6.3586794e-02 1.4289718e+00 -2.5001420e-01 1.2783569e+00 8.1238340e-01 -1.2001149e+00 2.9196305e-01
+1 8.9211648e-01 1 1 1.4943681e+00 5.6174839e-01 -7.4697366e-01 1.4623343e+00 -8.3475605e-03 3.6620663e-01 -1.3061540e+00 -1.4477155e-01
+1 9.5430066e-01 1 1 -1.1880952e+00 8.1923384e-01 -5.8201049e-01 7.7242004e-01 1.0742199e+00 4.5483832e-01 9.1901415e-01 1.5588884e+00
+1 4.1026300e-01 1 1 -3.5324507e-01 -7.3744788e-01 1.0691760e+00 1.0028474e+00 -3.1971420e-01 9.7274489e-01 -1.3403302e+00 -6.4484489e-01
+1 4.7857105e-01 1 1 6.2029776e-01 -7.0348647e-01 -2.6811645e-01 2.1118528e-01 -1.3131555e+00 7.5148050e-02 1.4308934e+00 5.8654518e-01
+1 6.7466050e-01 1 1 1.5399649e+00 1.4576470e+00 -1.1893481e+00 -6.0876038e-01 -5.1645811e-01 9.3030016e-02 1.3411864e-01 -2.5297845e-01
+1 8.1318856e-01 1 1 -1.3925671e+00 5.3306840e-01 5.8014111e-01 7.3149775e-01 1.0896403e-01 -9.5766244e-01 -1.5315322e+00 -1.2339658e+00
+1 9.1771209e-01 1 1 -1.0557595e-02 -5.4165114e-01 -1.0719375e+00 1.2306718e+00 -1.9008106e-01 -1.0533934e+00 -1.3930165e+00 1.5307912e+00
+1 1.4417459e-01 1 1 -1.5123147e+00 8.0477819e-01 9.8015209e-01 -3.4462687e-01 3.0726969e-01 -1.5076580e+00 -1.2802110e+00 1.5050281e+00
+1 8.2143757e-01 1 1 1.1531862e+00 1.3506787e+00 -1.0956421e+00 9.5301847e-01 -4.9663587e-01 8.7905740e-01 2.6126906e-01 -1.0966950e+00
+1 3.0752963e-01 1 1 1.1151197e+00 -2.9194449e-01 1.5587256e+00 1.5420214e+00 2.5263021e-01 -5.9245670e-01 -7.9742392e-01 -4.2805215e-01
+1 8.5475665e-01 1 1 -9.2564161e-01 4.5663641e-01 -2.4038025e-01 -1.3851137e+00 -1.4773660e+00 1.4289971e+00 -2.6961554e-01 -2.5277851e-02
+1 9.3401950e-01 1 1 -9.1658946e-02 -2.2275397e-01 1.7321694e-02 -4.0365262e-01 1.0583395e+00 -3.2119600e-01 -1.2518158e+00 -7.2984147e-01
+1 6.5952879e-01 1 1 -1.1315014e+00 9.5242793e-01 -1.0424064e+00 -1.4910010e+00 -1.8597564e-01 -1.0850509e+00 -2.1451244e-02 1.4737219e+00
+1 1.2822119e-01 1 1 -1.0839817e+00 1.0416585e+00 9.3801786e-01 1.2306548e+00 1.9206085e-01 4.9540955e-01 7.5209749e-01 5.2799085e-01
+1 5.5347046e-01 1 1 -3.8469188e-01 -9.4195982e-01 7.5428235e-01 -6.3006042e-01 1.5509697e+00 1.1278016e+00 -1.2663549e+00 -1.0571095e+00
+1 5.2415763e-01 1 1 -1.1866391e-01 -1.0332607e+00 8.9713118e-01 8.8332992e-01 1.3528274e+00 -1.4084734e+00 6.6325886e-01 -1.1323242e+00
+1 1.0834839e+00 1 1 5.2704397e-01 7.1202972e-01 -1.5610564e+00 -1.0409501e+00 1.2646787e+00 -3.1134976e-01 1.0209816e+00 7.9622713e-01
+1 7.6537018e-01 1 1 -1.2632038e+00 7.5713461e-01 -1.2350517e+00 2.8187353e-01 -5.6032382e-01 1.0380158e+00 2.5789204e-01 -9.9530054e-01
+1 1.3716155e+00 1 1 2.1761793e-01 -1.4303656e+00 -1.0110686e+00 -7.3342794e-02 1.1322774e+00 6.6694162e-01 -1.0063902e+00 9.6463303e-01
+1 9.0570854e-01 1 1 6.9073217e-01 -6.8818050e-01 -1.5573056e-01 -1.1680267e+00 1.5603925e+00 8.5156477e-02 -6.4640116e-02 -1.1723789e+00
+1 7.6479238e-01 1 1 9.5064219e-01 1.0945217e+00 -4.1680183e-01 7.8784851e-01 -4.9828881e-01 -1.3413446e+00 5.8463311e-01 -1.0233632e-01
+1 8.3580581e-01 1 1 -6.9689423e-01 -1.5407028e+00 5.6321526e-01 -4.4312977e-01 7.4591265e-01 9.0982039e-02 -9.7314710e-01 -1.5152688e+00
+1 7.3244364e-01 1 1 -8.4387032e-01 1.5561874e+00 3.4019157e-01 1.0342038e+00 -1.5423084e+00 -8.2049363e-01 -5.5203433e-01 -1.3730930e+00
+1 7.2713744e-01 1 1 1.3624137e+00 1.0825464e+00 -9.8929448e-02 -5.6917387e-01 -2.9608556e-01 1.5553723e+00 -9.1784781e-01 5.6597567e-01
+1 1.0480836e+00 1 1 -9.8202615e-01 1.3944502e+00 -8.0472240e-01 4.4313895e-02 -2.7198852e-02 -5.0836111e-02 -1.0482286e+00 -3.8952232e-01
+1 9.4292857e-01 1 1 1.0142506e+00 2.4404594e-01 -4.1292042e-01 2.2616617e-01 1.5414281e+00 1.1067704e-01 4.7354553e-01 3.7754119e-01
+1 6.2948066e-01 1 1 2.2821704e-01 -1.2398589e+00 -1.7539952e-01 -1.5235927e-01 1.2091789e+00 3.2614038e-01 1.2255788e+00 -6.8235444e-01
+1 9.1552419e-01 1 1 -2.4077154e-01 -1.2375392e-01 -1.1258317e+00 -3.0426684e-01 -2.9236898e-01 -6.3779240e-01 -1.1197267e+00 -1.5178850e+00
+1 8.2969701e-01 1 1 -2.7587313e-01 -1.9772573e-01 -4.1040661e-02 7.0002910e-01 -3.9449262e-01 -2.6275824e-01 -1.1067404e+00 -1.3602495e+00
+1 3.6266595e-01 1 1 3.9100042e-01 6.2869699e-01 1.3800001e+00 1.2457314e-01 -1.4769437e+00 9.0160876e-01 3.8374830e-01 -3.4386727e-01
+1 4.4042802e-01 1 1 -6.6775327e-01 1.3341549e+00 -7.1692286e-01 1.3999772e+00 -1.2690050e+00 1.4371421e+00 -3.1961516e-02 1.1533389e+00
+1 1.0461849e+00 1 1 -1.1603164e+00 -1.5475214e+00 -1.3147642e+00 -1.1125579e+00 1.0474348e-01 1.4826669e+00 3.5143914e-02 5.4021610e-01
+1 7.0993934e-01 1 1 1.5701927e+00 5.2800952e-02 7.2004815e-01 -9.3835296e-04 1.1317765e+00 7.0173540e-02 4.4349942e-02 2.0923377e-01
+1 5.6273239e-01 1 1 8.5003312e-01 1.4964772e+00 4.3439590e-01 -6.2934946e-02 -5.7578986e-01 1.3094494e+00 8.3202094e-01 1.1498647e+00
+1 7.7226337e-01 1 1 -1.4566706e+00 -2.9899161e-01 -1.6949599e-01 9.6909141e-01 -1.1948374e+00 1.0596246e+00 5.4707749e-01 -1.3013937e+00
+1 6.0030342e-01 1 1 1.6801669e-01 1.3962488e+00 7.0539746e-01 1.5029643e+00 -5.7125850e-01 -5.7839283e-01 -7.1033589e-01 -7.5511760e-01
+1 7.2333909e-01 1 1 -4.3522400e-01 -9.4287196e-01 -7.5559913e-01 -1.2258308e+00 -4.3450203e-01 -9.6068393e-01 -5.6320303e-01 7.7273361e-01
+1 1.2273901e+00 1 1 -1.1820001e+00 -6.5572708e-01 -1.0370283e+00 2.6261455e-02 1.5273810e+00 -1.5702250e+00 -1.3461745e-01 -1.0180797e-02
+1 7.1340608e-01 1 1 1.5554298e+00 -9.7944912e-02 2.2216229e-01 1.5532974e+00 7.3854565e-01 -1.3939034e+00 -5.6882655e-01 -1.4626567e+00
+1 9.6788038e-01 1 1 9.1682026e-01 3.4420187e-02 -1.4721165e+00 -3.6592544e-01 3.0413982e-01 -4.7815373e-01 -4.0133857e-01 9.1142145e-02
+1 1.5803288e-01 1 1 -5.1390249e-01 4.4703216e-01 1.3219463e+00 1.1295608e+00 3.0670058e-01 -1.3574297e-01 -2.9785545e-01 -1.2711823e+00
+1 4.4642765e-01 1 1 -9.2088244e-01 -1.4200651e+00 6.0834242e-01 -1.1549108e-01 -6.3686918e-01 -6.3580195e-01 -1.4994715e+00 1.2102613e+00
+1 8.3205266e-01 1 1 1.3558371e+00 -3.5446446e-01 -1.4729676e+00 4.4571254e-01 -4.5409248e-01 -1.3667474e+00 2.3913883e-01 -9.5160301e-01
+1 6.5047688e-01 1 1 -1.5589932e+00 -1.0245407e+00 -4.1601245e-01 1.5337099e+00 -1.0037906e+00 4.0114911e-01 1.1092958e+00 2.5640955e-01
+1 6.7274804e-01 1 1 -1.1161196e+00 -3.8682258e-01 1.2639603e+00 2.9480117e-01 -3.5622939e-01 2.5527446e-01 -1.4180205e+00 -7.8986611e-01
+1 8.3612014e-01 1 1 -1.7161807e-01 -1.3719786e+00 -6.9102864e-02 4.3161463e-01 7.2822847e-01 -1.0177406e+00 -5.4835609e-01 1.0908039e+00
+1 4.0569234e-01 1 1 -4.0292619e-01 4.4493226e-01 9.7744046e-01 2.0960350e-01 -3.0915800e-01 8.0622340e-01 1.2120435e+00 -1.1928822e+00
+1 5.3618795e-01 1 1 1.2933467e+00 9.8597144e-01 4.5390948e-01 1.0807416e+00 1.7578897e-01 5.0757279e-01 7.2781732e-01 8.7398857e-01
+1 4.5236374e-01 1 1 5.9823256e-01 -6.7928708e-01 1.0697132e+00 -6.6400735e-01 1.3881695e+00 1.3517924e+00 -9.3614952e-01 -9.6132575e-01
+1 6.8456815e-01 1 1 1.3981679e+00 -2.3031632e-01 -6.6477064e-01 -1.0343896e+00 1.4981375e+00 -4.2373253e-01 -7.6902702e-01 2.0909810e-01
+1 5.1395727e-01 1 1 -1.0483196e-01 -4.8426125e-01 -1.2967437e+00 5.8766765e-01 -6.6857553e-01 3.1784035e-01 -5.2501940e-01 -1.1303336e+00
+1 5.3174131e-01 1 1 5.2265547e-01 8.8778964e-01 -1.1432084e+00 -2.3716915e-01 7.2798169e-01 1.2351816e+00 7.3276166e-01 -3.0530335e-01
+1 3.7020965e-01 1 1 3.7750560e-01 -1.4846285e+00 7.7855794e-02 5.7924226e-01 -1.3151418e+00 5.3243014e-02 4.8196059e-01 -1.0126498e+00
+1 1.0465628e+00 1 1 -1.2804642e+00 1.5198813e+00 -1.5218008e+00 -4.7095485e-01 6.5831783e-01 -4.9857048e-01 1.2858030e+00 1.5437293e+00
+1 8.8254980e-01 1 1 -8.5260362e-01 3.5507652e-01 -1.2000993e+00 1.4752536e+00 -3.4156134e-01 -8.4642819e-01 -5.2425597e-01 -9.5526727e-01
+1 9.0798146e-01 1 1 -9.0493132e-01 -1.2549857e+00 -1.0441029e+00 1.1384102e+00 -9.3173962e-01 -7.8700019e-01 9.9735320e-01 1.5030668e+00
+1 7.3177692e-01 1 1 -7.3062613e-01 1.0829252e-01 6.9830479e-01 9.6180160e-01 1.0915188e+00 -1.0070724e+00 -1.0231964e+00 4.9746595e-01
+1 9.6484075e-01 1 1 8.5232001e-01 1.0901944e+00 -5.8156034e-01 1.5053635e+00 1.3964394e+00 1.0352877e+00 2.1706076e-01 1.1322063e+00
+1 7.0190437e-01 1 1 -7.2008600e-01 1.1285164e+00 -7.8987944e-01 1.3991787e+00 -8.8229309e-01 -1.2006243e+00 7.5105717e-01 3.6397625e-01
+1 7.5751453e-01 1 1 -1.0704438e+00 1.1803318e+00 8.6678938e-01 1.1748406e+00 -3.8267743e-01 -4.4298107e-01 9.8582779e-02 6.6796134e-01
+1 3.3518358e-01 1 1 9.5162226e-01 -1.3208546e+00 5.6393487e-01 6.3663739e-01 -8.1942199e-01 3.9178360e-01 1.2614391e+00 1.5156719e+00
+1 4.4013695e-01 1 1 6.7183437e-02 -1.1093328e+00 -1.3160545e-01 -2.9992100e-01 7.1687249e-01 -7.1307428e-02 1.5401425e+00 -1.2765906e+00
+1 4.3416316e-01 1 1 1.3202604e+00 7.9561848e-01 -2.1159081e-01 1.4839724e+00 4.6807722e-01 -1.5171377e+00 -1.5487250e+00 1.4199388e+00
+1 2.7578826e-01 1 1 5.4799344e-01 1.3413913e+00 7.6208540e-02 1.9298036e-02 4.2577709e-01 -1.3676915e+00 -1.3259050e+00 1.3739303e+00
+1 1.0291582e+00 1 1 -1.0238688e+00 6.9450729e-01 -9.3287389e-01 7.5805289e-01 -5.1254335e-01 2.4299998e-01 -1.1685253e+00 9.4130538e-01
+1 7.2509148e-01 1 1 1.4809857e+00 1.5673062e+00 8.7751153e-01 1.4366895e+00 -6.9085715e-02 3.0294928e-02 -1.3088221e+00 -5.4107399e-01
+1 1.2943494e+00 1 1 8.7495727e-02 -5.3992104e-01 -1.4412742e+00 1.5884775e-01 1.2656770e+00 2.2883771e-01 5.7977064e-02 1.0801677e+00
+1 3.2899945e-01 1 1 2.7531663e-01 -1.5332662e+00 1.3252203e+00 -5.9960785e-01 5.0885720e-01 7.6591696e-01 5.2678683e-01 -8.8557533e-01
+1 1.0365186e+00 1 1 -3.1938986e-01 8.7871607e-01 -9.1434776e-01 6.2011085e-01 9.4779458e-01 -1.4803252e+00 6.9810602e-01 1.0014881e+00
+1 6.0298964e-01 1 1 9.9644499e-01 -4.6143977e-02 1.2284036e+00 1.5402395e+00 -1.4329009e+00 -1.5542410e+00 -7.8073762e-01 -6.4277513e-01
+1 1.1064251e+00 1 1 -5.7949843e-01 4.3156005e-01 -7.6723216e-01 8.1189331e-02 6.8347812e-01 2.1478368e-01 5.7537453e-01 8.1555449e-01
+1 4.8795465e-01 1 1 -6.9285456e-01 -7.0764897e-01 1.3669824e+00 1.0978771e+00 1.5539788e+00 1.7940389e-01 4.9750167e-01 2.5559176e-01
+1 8.1014233e-01 1 1 1.0773897e+00 6.1350994e-01 4.0639084e-01 1.4465793e+00 -1.4802614e+00 -6.8776699e-01 -1.4090637e+00 1.1735706e+00
+1 5.4207032e-01 1 1 -4.5088402e-01 5.5445997e-01 3.8849502e-01 -1.2791211e-01 -4.8169534e-01 -1.3804694e+00 -8.0898354e-01 1.2825985e+00
+1 7.2969804e-01 1 1 -4.8632382e-01 8.4484346e-01 1.2063461e+00 -9.6952703e-01 3.0668702e-02 -8.8687149e-01 2.2671433e-01 -9.7661568e-01
+1 9.8982033e-01 1 1 7.7970049e-01 -7.1470754e-01 -7.8033935e-01 6.0036568e-01 2.2767381e-01 1.2079764e+00 -3.6419100e-01 8.4179816e-01
+1 6.8610894e-01 1 1 8.4316340e-01 1.3606287e+00 9.8585061e-01 -4.4966394e-01 5.3820922e-02 1.4877780e+00 -1.1356315e+00 1.5098957e+00
+1 4.4480682e-01 1 1 -6.7724839e-01 4.3330744e-01 4.3147131e-01 1.1700215e+00 -2.1044478e-01 1.1487540e+00 -1.3839534e+00 -9.6821144e-01
+1 7.4380742e-01 1 1 -5.2346673e-01 3.8629942e-01 9.4248024e-01 1.3231971e+00 4.8797115e-01 -1.1203819e+00 2.4719655e-01 7.2034707e-01
+1 7.9097551e-01 1 1 -1.4459777e+00 -1.1376597e+00 3.5518066e-01 -3.6089198e-01 -1.3673489e+00 4.4758466e-01 1.4468726e+00 -8.2484914e-01
+1 4.7764363e-01 1 1 8.1275332e-01 -9.1360257e-01 4.9525869e-01 9.0383608e-01 -2.8194640e-01 -1.5590202e+00 -1.4802691e+00 6.0895637e-01
+1 1.0381753e+00 1 1 3.0025529e-01 1.1864166e+00 -1.4076862e+00 1.1724842e+00 -1.1514718e+00 -1.5690907e+00 -6.1080307e-01 -5.7923297e-01
+1 3.4940889e-01 1 1 9.9287073e-01 4.1467680e-01 3.5148170e-01 -1.2694405e+00 -5.7529444e-01 -1.1790356e+00 9.5767246e-01 6.2703481e-01
+1 2.7924572e-01 1 1 -9.6187449e-01 1.4205350e+00 1.1588044e+00 -9.3037204e-01 8.4852811e-01 1.1149318e+00 1.2218407e+00 -1.4693502e+00
+1 6.4725389e-01 1 1 4.1116869e-01 -1.1724171e+00 1.2927857e+00 -1.0563103e+00 1.5228268e+00 -9.4152083e-01 -1.1143575e+00 6.9183543e-01
+1 8.0581132e-01 1 1 -9.9169598e-01 -7.4489988e-01 5.9450774e-01 -2.6706575e-01 -4.0567064e-01 6.1601901e-02 1.1694569e+00 6.4366989e-01
+1 7.0242709e-01 1 1 -1.2853567e+00 -2.8550914e-01 -1.5145819e+00 7.6185183e-01 -8.5040796e-01 -1.3824235e+00 1.2586434e+00 -1.4851848e+00
+1 8.2912666e-01 1 1 -1.3994886e+00 -1.3400756e+00 7.4808703e-01 -6.8795856e-01 1.4399104e+00 8.2833252e-01 -1.4656171e+00 -1.5471012e+00
+1 7.8691035e-01 1 1 -1.0095898e-01 -5.7300148e-01 4.4493619e-01 -1.4585790e+00 8.8636354e-01 1.3876023e+00 6.0200894e-01 8.3333994e-01
+1 8.2034966e-01 1 1 -3.5758195e-01 -1.4544673e+00 1.0520128e+00 -4.8901187e-01 -3.2031455e-01 1.3900889e+00 -1.1056895e+00 7.2437180e-01
+1 6.0851099e-01 1 1 -1.3023920e-02 -5.0014282e-01 2.9617414e-01 -4.1604302e-01 1.1631428e+00 -8.0049773e-01 -8.0273502e-01 8.4525201e-01
+1 3.6730583e-01 1 1 1.0184613e+00 1.0015388e+00 1.5160806e+00 7.5020939e-01 -1.1900866e+00 1.4760278e+00 -1.5686412e+00 -1.3150593e-01
+1 9.5481870e-01 1 1 -1.2589407e+00 2.0838678e-01 -6.9080731e-01 1.5579806e+00 7.3441820e-01 -1.5578253e+00 9.2240584e-02 1.4609824e+00
+1 4.7187559e-01 1 1 -3.8988127e-01 -5.1915134e-01 9.2800105e-01 -1.9502474e-01 4.9187403e-02 -3.3658065e-01 1.4823246e+00 4.3461291e-02
+1 6.6298994e-01 1 1 6.2784784e-01 -1.1736955e+00 -1.0938945e+00 -1.0996286e+00 4.5381012e-01 1.0973886e+00 6.0052913e-01 -1.5371667e+00
+1 9.9356556e-01 1 1 -3.7110283e-01 -2.3930751e-01 -4.8496014e-01 5.3116341e-01 -6.0020459e-01 -4.8039010e-01 -8.4417075e-01 1.2980898e+00
+1 1.1536104e+00 1 1 -1.0638799e+00 -8.0271305e-01 -1.4336536e+00 -1.1429158e+00 1.5399535e-02 -2.3231036e-02 -5.4530799e-01 -1.3655863e+00
+1 4.1879942e-01 1 1 1.3155407e+00 -1.1993159e+00 5.9901287e-01 -1.2881226e+00 1.2093901e+00 -8.8653257e-01 -9.6564729e-01 1.0663818e+00
+1 1.0998756e+00 1 1 -2.3697418e-01 -4.4460828e-01 -1.1950962e+00 -7.6074761e-01 1.1449692e-01 6.2109470e-01 -1.6630317e-01 -1.0676177e-01
+1 2.8968133e-01 1 1 7.1441889e-01 1.3175314e+00 1.3621939e+00 3.9704175e-01 -1.4465410e+00 -7.7371745e-01 9.6007557e-01 -4.9560917e-01
+1 1.1957189e+00 1 1 7.1169772e-02 -1.3358492e+00 -1.5343749e+00 3.3783142e-01 7.7150834e-01 -8.1715990e-01 7.7026626e-01 -1.3411903e+00
+1 4.5164308e-01 1 1 -7.9645008e-01 1.3444926e+00 1.0952564e+00 1.0746992e+00 1.3878063e+00 1.0366784e+00 -6.3835605e-01 -4.5847370e-01
+1 4.7202381e-01 1 1 3.8986790e-01 -5.8948559e-01 1.3830793e+00 1.4531668e+00 -1.4645745e+00 1.8137219e-01 -3.1120729e-01 7.5926498e-01
+1 1.8530974e-01 1 1 -8.5247708e-01 1.0989451e+00 7.6918794e-01 6.3262346e-01 -7.2575281e-01 9.7753610e-01 2.9090301e-01 -1.8287807e-01
+1 7.2950411e-01 1 1 1.2217441e+00 5.4656215e-01 8.7878278e-02 1.3528770e+00 1.0768660e+00 -1.0804137e+00 8.8865606e-01 -1.1541378e+00
+1 6.3568494e-01 1 1 4.0344309e-01 5.3135697e-02 4.2167632e-01 -1.0439220e+00 1.7113703e-01 -1.0772141e-01 5.1088189e-01 -1.4011471e+00
+1 6.2738750e-01 1 1 1.1110090e+00 8.3934965e-01 -3.1919618e-01 5.9805836e-01 -1.3987956e+00 -9.1637486e-01 4.1919652e-01 2.9842470e-01
+1 2.6516824e-01 1 1 -8.9865187e-01 1.1985519e+00 1.1100094e+00 -1.5295606e+00 -1.0206130e+00 -1.4251600e+00 -1.1563878e+00 -1.4995029e+00
+1 5.6506807e-01 1 1 1.1355824e+00 1.7047688e-01 1.1510411e+00 3.2832094e-01 -3.4712752e-01 -1.1610852e+00 -1.5170509e+00 -2.8902019e-01
+1 4.8697779e-01 1 1 5.5836224e-01 7.2449074e-02 -3.7927321e-01 1.4533825e+00 -2.3461539e-01 1.2151446e+00 9.1513489e-02 -6.6013434e-01
+1 9.6960899e-01 1 1 4.5699059e-01 -1.2863558e+00 -1.5328016e-01 1.1174802e+00 -4.8214967e-01 -5.5870805e-01 -1.3131857e+00 1.2274328e+00
+1 5.9850037e-01 1 1 -5.5311675e-01 6.5922791e-01 -7.3592972e-02 1.0481004e+00 -1.3220159e+00 1.4257208e-02 -1.0232016e+00 -1.3761150e+00
+1 4.7542849e-01 1 1 -2.6058076e-01 -7.5386133e-01 9.1041681e-01 5.1363727e-01 1.3631669e+00 8.5985783e-01 1.2839908e-01 4.0145055e-02
+1 6.7510320e-01 1 1 -2.0066349e-01 -1.0427397e-01 -1.3225595e+00 -3.9497462e-01 -8.8888160e-01 3.0437311e-01 -2.7078996e-01 -7.2448289e-01
+1 8.0306984e-01 1 1 1.5192895e+00 4.7614851e-01 -1.4891687e+00 -1.5307918e-01 -1.1600553e+00 1.0860144e+00 1.0008738e+00 4.2918381e-01
+1 7.9323764e-01 1 1 -1.6665278e-01 9.9154833e-01 6.1005540e-01 1.6266190e-01 -3.2502653e-01 -1.0003939e-02 -1.5420419e+00 1.9549518e-01
+1 5.1941262e-01 1 1 1.3673719e+00 -1.1961621e+00 -9.5738540e-01 6.7294597e-01 5.0873355e-01 1.5097960e+00 1.0417033e+00 -4.1849985e-01
+1 5.4849691e-01 1 1 6.6926958e-01 -8.4468901e-01 4.6110420e-01 4.6932265e-01 -1.1304931e+00 4.9753788e-01 -1.8786842e-01 2.9891492e-01
+1 8.1992452e-01 1 1 1.5120532e+00 1.6896448e-01 -5.3080903e-01 -6.3332377e-01 1.5480227e-01 -8.0050437e-01 -2.0399849e-01 4.5643025e-01
+1 6.5403967e-01 1 1 7.3438638e-01 -2.1376266e-01 8.1579853e-01 -5.5670020e-01 5.2303956e-01 1.3643525e+00 -1.1250740e+00 -5.4602317e-01
+1 7.8756744e-01 1 1 -4.8558559e-01 1.2728959e+00 1.2154744e+00 -7.9736484e-01 5.4960816e-01 1.8690925e-01 1.2739009e-01 -4.1932627e-01
+1 1.1539026e+00 1 1 6.2065347e-01 -6.8481958e-01 -1.2986946e+00 7.2331653e-01 9.8187781e-01 -2.0894845e-01 -1.5209333e+00 -1.0242813e+00
+1 6.7623676e-01 1 1 1.2352466e+00 1.0328067e+00 6.2478451e-01 -1.1825864e+00 -3.6590489e-01 5.0394427e-01 8.1426948e-01 8.3228359e-01
+1 3.2167028e-01 1 1 1.1452126e+00 1.0832956e+00 1.5506591e+00 1.1262716e+00 1.4749381e+00 5.7474674e-02 6.4960712e-01 -1.3218579e+00
+1 6.7249713e-01 1 1 -9.5018380e-01 1.4193651e+00 -7.2530857e-01 1.1508523e+00 -1.0224373e+00 1.5079049e+00 9.1246119e-01 8.7697420e-01
+1 1.0844195e+00 1 1 -1.0237104e+00 1.1567881e+00 -8.8164500e-01 -4.1147837e-01 4.0789051e-01 1.2931133e-01 -1.5201638e+00 -1.0472754e+00
+1 5.8459142e-01 1 1 1.0026363e+00 -1.1797664e+00 1.0850223e+00 -1.0715893e+00 4.6055169e-01 -6.4667621e-01 1.1803081e+00 7.8519295e-01
+1 9.1226746e-01 1 1 -1.9482007e-01 1.3982183e+00 -9.7606598e-01 5.4905529e-01 -3.9200148e-01 1.2234706e+00 1.4218343e+00 -1.0928393e+00
+1 7.6187806e-01 1 1 -8.0134009e-01 7.4124038e-01 6.5593058e-01 1.1146861e+00 -4.4900411e-01 1.1459165e+00 -1.3263378e+00 1.5419194e+00
+1 3.7846534e-01 1 1 -1.1521875e-01 -1.5293455e+00 3.7663740e-01 1.2117417e+00 -3.0648488e-01 1.4562822e+00 9.8176635e-01 4.1836956e-02
+1 1.1424520e+00 1 1 -1.2604060e+00 8.0081025e-01 -1.6437839e-01 -1.2021804e+00 1.1205703e+00 -4.1289755e-01 9.0238411e-01 -5.6303108e-01
+1 7.3904917e-01 1 1 1.1524809e-01 6.3493220e-01 -1.2476359e+00 -1.4640078e+00 -4.2332118e-01 2.0909612e-01 -1.2396449e+00 -3.8627225e-01
+1 7.3962077e-01 1 1 -1.3879661e+00 -6.8482187e-01 1.1139219e+00 -6.2515417e-01 9.4829868e-01 -1.1637476e+00 3.3002448e-01 -1.5472983e+00
+1 5.7953931e-01 1 1 -1.2209940e+00 9.9435225e-01 9.3522535e-01 -1.4802575e+00 7.5631619e-01 4.4913728e-01 -1.3311420e+00 6.6165123e-01
+1 7.4153255e-01 1 1 -3.6264482e-01 -1.1946753e+00 9.4440414e-01 -4.1484257e-01 5.2240022e-01 -5.9680618e-01 -1.2227716e+00 -8.6583650e-01
+1 2.5440729e-01 1 1 -2.8179822e-01 -9.8936908e-01 1.2742357e+00 -1.0649744e+00 -7.7096136e-01 5.8388075e-01 1.1775183e+00 -2.5681151e-01
+1 3.3624067e-01 1 1 1.3389968e+00 1.2381253e-01 -1.5786979e-01 -1.3718020e+00 1.5221864e+00 -1.0516376e+00 -1.4835600e+00 3.1718426e-01
+1 6.2641568e-01 1 1 1.2911220e+00 1.1828391e+00 1.3282553e+00 2.7281726e-01 1.3985594e+00 -2.7361133e-01 6.2726495e-01 -3.6693665e-01
+1 7.9846746e-01 1 1 9.0724591e-01 -2.2307576e-02 -1.7114115e-01 -1.4855590e+00 1.9158379e-01 7.0596266e-01 -7.4289899e-01 -1.5795510e-01
+1 4.6657149e-01 1 1 -1.2087483e+00 -1.0739083e+00 1.3295825e+00 -1.5539773e+00 -1.8362894e-01 -6.8096464e-01 -1.2141912e+00 -1.0555104e-01
+1 2.7826172e-01 1 1 1.2475759e+00 -7.2640842e-01 1.4450569e-01 1.5050454e+00 -1.2076477e+00 -1.5066542e-01 8.7514998e-01 1.0034514e+00
+1 7.1332494e-01 1 1 1.0186586e+00 -5.1733520e-01 2.5607794e-01 -8.0607350e-01 8.9541220e-01 -1.1004021e-01 -2.9105265e-01 9.3888209e-01
+1 1.0346239e+00 1 1 -1.0852358e+00 1.0757314e+00 -7.9925149e-02 -1.1297085e+00 9.6407251e-01 9.5231115e-01 -2.6211924e-01 -4.2865626e-01
+1 6.3449938e-01 1 1 5.2833605e-01 -4.7861426e-02 1.2996759e+00 7.7554033e-01 -1.1682603e+00 -9.2111824e-01 -9.2521697e-01 -7.5378604e-01
+1 8.3440559e-01 1 1 -1.5384872e+00 -1.5925915e-01 1.5928260e-01 3.8464340e-02 2.5846156e-03 5.3430699e-01 7.6200257e-01 1.1611588e+00
+1 7.2416067e-01 1 1 1.0944134e+00 -3.1661861e-02 4.2567277e-01 -6.9791589e-01 -5.4266212e-01 1.4257723e+00 -1.2960795e+00 2.1693146e-02
+1 8.0035522e-01 1 1 -2.1955119e-01 -1.2117337e+00 8.7575608e-01 8.3455499e-01 -4.7882837e-01 -1.1144336e+00 5.9504960e-01 1.7196151e-01
+1 9.7480980e-01 1 1 1.3744961e+00 1.3364761e+00 4.7084505e-01 -8.4548030e-01 1.0920387e+00 -1.0930211e-01 1.3092326e+00 -1.0810381e-01
+1 5.8617502e-01 1 1 1.0258239e+00 -2.3434086e-01 -1.7920560e-01 -5.6384233e-01 7.0953252e-01 7.9110045e-01 5.5657331e-01 -1.0601775e+00
+1 5.1896098e-01 1 1 -3.7385939e-02 9.9042661e-01 8.7875671e-01 -1.4546706e+00 -3.7264541e-01 8.0511969e-01 -1.3353590e+00 7.1070935e-01
+1 7.4925837e-01 1 1 -2.6941548e-02 -1.1994565e+00 6.3698857e-01 -7.7529475e-01 1.2842903e+00 8.0711973e-01 1.5858719e-01 5.5675287e-01
+1 6.4186839e-01 1 1 -4.1725083e-01 3.3520554e-01 -6.8085978e-01 9.4752998e-01 -8.1570479e-01 -1.3572455e-01 1.3043152e+00 -1.4590863e+00
+1 1.0974150e+00 1 1 -6.9987338e-01 9.2384065e-01 -1.5298922e+00 4.0318591e-01 3.5988078e-01 -3.2622371e-01 -4.0713958e-01 4.0882912e-01
+1 8.1821166e-01 1 1 -6.4897445e-01 1.2388930e+00 1.0384586e+00 -6.9691875e-02 9.5048652e-01 -7.6264899e-01 -4.0610750e-01 5.2787546e-01
+1 7.6719067e-01 1 1 2.9603957e-01 -4.0136013e-01 -1.3150256e+00 5.0272201e-01 -1.7175529e-01 -1.4356612e-01 1.2321212e+00 1.4528566e-01
+1 1.1109992e+00 1 1 -7.4562804e-01 -6.6024714e-01 -5.3107064e-01 1.5062591e+00 4.3247944e-01 -1.7257575e-01 -1.1182737e+00 7.9865309e-01
+1 4.2643408e-01 1 1 4.2698261e-02 -6.6839280e-01 -4.3945092e-01 7.4280091e-01 -9.6350020e-01 -7.9064660e-01 1.3220588e+00 -1.0628465e+00
+1 1.0607294e+00 1 1 1.3465468e+00 6.5746127e-01 3.2656949e-02 -4.3438491e-01 1.3622660e+00 5.3954949e-01 -6.4199787e-01 -1.6562101e-01
+1 8.8058828e-01 1 1 -6.2166678e-01 9.7014077e-01 -9.1336841e-01 3.5417093e-01 -3.2271452e-01 -1.5697653e+00 1.3125694e+00 -1.4125376e-01
+1 3.7540983e-01 1 1 5.8359658e-01 2.9002506e-01 -1.1611837e+00 -7.6720282e-01 -1.4739390e+00 5.0073732e-02 9.0987955e-02 9.9209775e-01
+1 5.6703965e-01 1 1 4.5547160e-01 -1.3006019e+00 -4.4110270e-01 -1.2814881e+00 -1.0350744e+00 -3.5761492e-01 -7.2106273e-01 -1.3868733e+00
+1 5.5711178e-01 1 1 -9.5014329e-01 -1.5057549e-02 5.4560921e-01 7.8928501e-01 -1.4974674e+00 -5.6729462e-01 1.3631547e+00 1.4371390e+00
+1 5.6585099e-01 1 1 -3.4281527e-01 1.3967820e+00 -2.5502033e-01 -1.4325545e+00 -6.3638552e-01 2.1308856e-01 -1.0940869e+00 1.4306895e+00
+1 1.4259905e+00 1 1 -1.5343246e-02 -1.4065264e+00 -9.9426814e-01 2.2317165e-01 1.3914930e+00 -3.6164490e-02 -5.7691235e-01 -1.5251554e-01
+1 4.7797537e-01 1 1 -2.6334591e-01 9.9468423e-01 -5.3332176e-01 -2.1575262e-01 8.0765242e-01 -1.4891998e+00 -1.2110155e+00 2.1098801e-01
+1 8.1810478e-01 1 1 4.4933849e-01 1.2433199e+00 -5.7497531e-01 -7.5634789e-01 -6.0766494e-01 8.8018603e-02 8.4173912e-01 -7.8253902e-01
+1 9.8843550e-01 1 1 -3.5678946e-01 -1.3969489e+00 -7.1068459e-02 -1.0550587e+00 2.9300818e-01 -3.6148137e-01 5.1770125e-01 -1.4264340e+00
+1 3.7007184e-01 1 1 7.3999362e-01 -1.3974543e+00 -6.4237618e-01 -1.2228263e+00 -1.4288417e+00 4.2277411e-01 -1.2066669e+00 -5.8281285e-01
+1 7.6864731e-01 1 1 -4.9247156e-01 -4.6826458e-01 1.2374145e+00 2.5689737e-01 -2.0863910e-01 -7.1805109e-01 -1.4698829e+00 1.5036658e-01
+1 7.6040873e-01 1 1 1.1272063e+00 -4.3327205e-01 -1.1832753e-01 1.1258423e+00 -5.7996899e-01 -1.4272507e+00 1.1624481e+00 1.3706621e+00
+1 5.8970479e-01 1 1 1.1520609e+00 2.0834356e-01 -1.0259498e-01 2.1860988e-01 8.2325777e-01 1.3994331e+00 -2.9927345e-01 -5.8057574e-01
+1 5.1590616e-01 1 1 1.0522257e+00 -1.2455329e+00 4.2047019e-01 -1.4871097e+00 9.1930238e-01 -8.3151301e-01 -1.9911623e-01 5.0295806e-02
+1 6.5158491e-01 1 1 7.3303651e-01 -1.2392766e+00 1.4006628e+00 6.5923346e-01 3.6240744e-01 -1.4350590e+00 -7.5037362e-01 2.3318830e-01
+1 5.7481665e-01 1 1 -1.1818433e+00 2.3810899e-01 9.8614936e-01 -6.6050349e-01 -5.6638448e-01 -1.0294955e+00 -1.1765050e+00 -1.5119222e+00
+1 8.1356059e-01 1 1 1.0502558e+00 -4.9121601e-01 -8.3052749e-01 1.3062433e+00 -1.9822794e-01 1.1610085e+00 -3.3597157e-01 1.4669606e+00
+1 7.4638114e-01 1 1 -9.6056652e-01 2.3797882e-01 -5.7944293e-01 5.8110402e-01 -1.5287288e+00 6.3854258e-01 -1.2322467e+00 -1.3148417e-02
+1 4.1368554e-01 1 1 4.0307502e-01 4.6255270e-01 2.3986331e-01 -5.9636680e-01 -1.4001845e+00 3.0461375e-01 -9.9143646e-01 -1.0739640e+00
+1 2.0645944e-01 1 1 1.2081616e+00 -1.3185690e+00 7.1922684e-01 -1.4562845e+00 7.7013521e-01 -1.1527135e+00 -6.5144133e-02 1.4778685e+00
+1 7.3017213e-01 1 1 1.4581462e+00 -3.9440956e-01 -8.0306451e-01 3.7434472e-01 3.0070948e-01 5.4581550e-01 1.5383855e+00 1.1051102e+00
+1 8.4541229e-01 1 1 -5.0130566e-01 -8.0903416e-02 -8.2324544e-01 -9.9842695e-01 -7.9834850e-01 7.0535488e-02 3.3811856e-01 4.9110389e-01
+1 7.4584387e-01 1 1 3.0721931e-01 5.6591434e-01 -7.1208092e-01 -1.3154251e+00 -1.0104910e-01 1.1095221e+00 -3.8254708e-01 1.0192459e+00
+1 5.0088687e-01 1 1 -1.3434458e+00 -1.4202204e+00 1.5240513e+00 -9.6249506e-01 1.2693615e+00 -7.5667640e-01 1.3714262e+00 -6.3874356e-01
+1 7.0481083e-01 1 1 -6.6773530e-01 1.7623120e-01 1.3255675e+00 -5.9394622e-01 -3.9743857e-01 -2.9316486e-01 -3.0536250e-01 -5.4091780e-01
+1 6.2445500e-01 1 1 -8.5816347e-01 -6.0414894e-01 -1.3621639e+00 1.5272564e+00 -7.2406445e-01 -1.2045034e+00 1.1348306e+00 5.6370806e-01
+1 1.1418632e+00 1 1 -1.0151635e-01 -3.0375438e-01 -1.1030559e+00 -1.3546911e+00 1.1786937e+00 3.3371938e-01 4.8862477e-01 -8.0212058e-01
+1 8.7345336e-01 1 1 -3.0040411e-01 -1.1175646e-01 -5.2239994e-01 -1.1711319e+00 -5.7877361e-01 1.0787982e+00 1.9333988e-01 -6.6657155e-01
+1 5.0421192e-01 1 1 -3.5249128e-01 3.8155515e-01 7.7560835e-01 -1.1356205e+00 -1.0772684e+00 1.2299952e+00 1.0565399e+00 -1.4864909e-01
+1 4.8476572e-01 1 1 7.2276088e-01 8.0678444e-01 1.1816000e+00 -1.1991555e+00 -6.5225232e-01 8.5047829e-01 9.8459173e-01 -7.7910530e-01
+1 4.4350880e-01 1 1 -1.0967153e+00 5.1215816e-01 1.1442642e+00 -8.9001072e-01 -1.3879454e+00 -2.5802523e-01 1.2647136e+00 -2.6463752e-01
+1 8.6009197e-01 1 1 -7.6954466e-01 -1.2167857e-01 -1.1815784e+00 -1.2875645e+00 -8.7254327e-01 -1.2321327e+00 2.4926826e-02 7.3244070e-01
+1 8.6928453e-01 1 1 1.9985018e-01 1.2508400e-01 -7.8081528e-01 -8.0673824e-01 1.1969510e-01 9.2423105e-01 1.1133373e+00 1.3708477e+00
+1 2.7427614e-01 1 1 5.1950720e-01 5.6129315e-01 -7.2981580e-01 2.6430764e-01 1.0961865e+00 1.5172371e+00 5.3461291e-01 -6.0383944e-01
+1 1.0795379e+00 1 1 8.7153427e-01 -5.4876865e-01 -1.2364872e+00 6.5378211e-03 1.3065430e+00 -1.0319659e-01 2.8425105e-01 -1.3852335e+00
+1 8.7441126e-01 1 1 -1.3700351e+00 5.6127606e-01 -4.5311891e-03 -7.4583152e-02 -6.6518353e-01 -2.6592001e-01 -9.5509602e-01 7.2389888e-01
+1 5.4614991e-01 1 1 -1.4471034e+00 -8.3602166e-01 -7.5747092e-01 -2.3558854e-02 1.1886969e+00 1.1686724e+00 1.2396101e+00 -8.1988757e-01
+1 1.1885840e+00 1 1 7.4422892e-01 1.3278910e+00 -1.0802849e+00 -1.1298435e-01 1.0415777e+00 6.3970019e-01 -9.1498008e-01 -8.2508490e-01
+1 1.3709308e+00 1 1 -1.5664157e+00 -9.7174619e-03 -1.0850201e+00 -1.4060370e+00 8.4157989e-01 9.1100914e-01 2.5754630e-02 -2.1193447e-01
+1 7.6614660e-01 1 1 -2.0293013e-01 4.1436288e-02 1.0119388e+00 -2.0390817e-01 9.8304396e-01 -7.9195418e-01 -6.8172581e-01 5.8335375e-01
+1 1.0083371e+00 1 1 1.1228696e+00 -1.0138794e+00 -9.2726082e-01 3.9294369e-01 3.8415389e-01 5.5418336e-01 -3.7731881e-01 -4.8422490e-01
+1 5.1430218e-01 1 1 5.2296825e-01 -2.7326921e-01 9.6848288e-01 5.7676338e-01 5.0145088e-01 -6.6242544e-01 1.2782718e+00 1.4986356e+00
+1 3.3444849e-01 1 1 -6.4894721e-01 1.7285330e-01 7.0015338e-01 -1.2928777e+00 -1.0081080e+00 4.1993847e-01 -1.4378019e+00 1.4207435e+00
+1 9.7476035e-01 1 1 7.5392820e-01 -8.2772001e-01 -9.2823308e-01 1.0000788e+00 -6.6209788e-01 -1.2528602e+00 -6.2588836e-03 -8.0921817e-01
+1 6.3641845e-01 1 1 1.2280103e+00 -5.1801242e-01 3.3577496e-01 8.0429232e-01 -3.5793711e-01 1.2741749e+00 -1.5204993e+00 -5.7521973e-01
+1 6.0365013e-01 1 1 -1.0948246e+00 -8.8145154e-01 1.0694094e+00 -5.3215654e-01 3.0098833e-01 -1.1787822e+00 -1.3174588e+00 -1.0374421e+00
+1 9.2053200e-01 1 1 -4.0832548e-01 1.1948740e+00 5.1210705e-01 1.5934761e-01 7.4666186e-01 -9.0868211e-01 -5.8446941e-01 -4.5083201e-01
+1 7.7323012e-01 1 1 -1.4879222e+00 1.1873662e+00 -9.8063464e-01 1.5184046e+00 -1.5168526e+00 -9.3828095e-01 5.8279555e-01 3.8787636e-01
+1 8.4890704e-01 1 1 -4.3136722e-01 6.6665093e-01 -7.3140458e-01 6.6815476e-01 2.8311789e-01 1.1072277e+00 -4.4108639e-01 2.3324379e-01
+1 9.7300126e-01 1 1 8.0697737e-01 1.4827786e+00 3.3531561e-01 -1.5167328e+00 -1.1504907e+00 1.5229366e+00 8.1963427e-01 -5.7925348e-01
+1 1.0517186e+00 1 1 6.1318308e-01 -1.1940586e+00 -3.6768331e-01 -8.4581049e-01 2.0550256e-01 1.4394068e+00 -2.9068100e-01 2.8232136e-01
+1 5.2824681e-01 1 1 1.3441128e+00 -4.8303989e-02 -1.4067824e-01 1.6980075e-01 1.2712613e+00 -1.2943218e+00 -2.9898385e-01 1.1702481e+00
+1 2.6474307e-01 1 1 -6.8826892e-01 -1.3142376e+00 1.2400233e+00 1.2751025e+00 1.1659046e-01 -1.2788611e+00 1.5266843e+00 -1.1510768e+00
+1 6.8785157e-01 1 1 -3.9155715e-01 1.4675905e-01 -2.5442694e-01 -1.2969939e+00 -8.1793943e-01 9.5924786e-01 -1.5461643e+00 -2.1979549e-01
+1 9.3954255e-01 1 1 7.3552822e-01 4.2919626e-01 -4.4603377e-01 9.3503845e-01 5.0138110e-01 -5.7468967e-01 8.7182285e-01 4.1023696e-01
+1 1.0392873e+00 1 1 -1.4429008e-01 4.0480656e-01 -6.4951901e-01 9.4472792e-01 9.6067215e-01 -1.5535167e+00 3.3857893e-01 -9.4326292e-01
+1 4.0318031e-01 1 1 2.2607416e-01 -1.1059103e+00 5.6847891e-01 4.3287580e-01 1.3721009e+00 -1.7821116e-01 1.0717567e+00 -9.4329142e-01
+1 3.5475153e-01 1 1 1.4428420e+00 -1.3720736e+00 8.4175394e-01 -5.8501215e-01 -1.5324803e+00 -1.2570901e+00 -8.7720107e-01 -1.4223743e+00
+1 3.5449614e-01 1 1 -1.0838061e-01 -1.1502649e+00 7.6674565e-01 8.8574768e-01 1.5221482e+00 -7.0200890e-01 3.7594894e-01 -1.4657344e+00
+1 4.7698065e-01 1 1 5.7080240e-01 8.5981469e-01 -1.1887127e-01 -1.2463568e+00 7.5538116e-01 1.1584605e+00 8.3093066e-01 -1.3705535e+00
+1 1.0102572e+00 1 1 -9.4795778e-01 -4.2072990e-01 1.8356404e-01 6.2069695e-01 5.1516772e-01 -1.3450794e+00 1.0722618e+00 -7.3538796e-01
+1 7.8917965e-01 1 1 -1.3100543e+00 5.1766842e-01 1.1688289e-01 -1.1754896e+00 1.9454561e-01 1.5172180e-01 1.3278994e+00 -6.3994944e-01
+1 7.5430819e-01 1 1 1.3408220e+00 1.3831138e+00 9.5531450e-01 1.0219131e+00 -6.6981012e-01 -9.8500308e-01 1.3133967e-01 1.1829735e+00
+1 3.8823417e-01 1 1 5.5169232e-01 1.3494474e+00 -7.0931617e-01 2.0655767e-01 -1.1722693e+00 1.2464699e+00 -1.1137569e+00 -9.0413395e-01
+1 4.1659277e-01 1 1 1.4528750e+00 1.0045956e+00 8.6728785e-01 1.5492541e-01 -1.4026625e+00 1.2804149e+00 -1.3037434e+00 1.0429159e-01
+1 9.4987678e-01 1 1 -1.1299596e+00 1.3189271e+00 -4.8310163e-01 -5.4889555e-01 -3.7650009e-02 2.3521071e-02 5.9320355e-01 -1.7992115e-01
+1 6.3879560e-01 1 1 -3.0344302e-01 1.3040780e-01 1.5279188e+00 1.5701694e+00 -1.3235714e+00 -5.2203092e-01 -1.4430530e+00 1.4189063e+00
+1 7.7953280e-01 1 1 -1.1619360e+00 -1.0677334e+00 3.5219352e-01 4.5912021e-01 3.5369621e-01 6.9460960e-01 -2.9725592e-01 -2.7120734e-01
+1 9.3169456e-01 1 1 -5.1819176e-01 -6.1831220e-01 5.5593268e-01 6.8183130e-01 6.7895875e-01 1.4529758e-01 -8.4799519e-01 2.6911598e-01
+1 4.0657317e-01 1 1 -7.5413454e-01 4.1536960e-01 4.6400273e-01 -9.9128622e-01 9.9513606e-01 9.9891636e-01 1.1507840e+00 -8.6113166e-01
+1 5.9624404e-01 1 1 -1.5544512e+00 4.9802884e-01 1.0608345e+00 -6.8167393e-01 -5.8755860e-01 1.1614428e-01 -1.5587939e+00 2.7746436e-01
+1 6.0489876e-01 1 1 -1.7757573e-01 1.1678945e+00 9.0645633e-01 4.9464392e-01 -1.0716151e+00 1.1078213e+00 -9.0762370e-01 1.2200715e+00
+1 4.3976434e-01 1 1 -2.2668903e-03 1.3238318e-01 1.2287801e+00 8.2625541e-01 1.1612275e-01 -1.0670041e+00 1.1423464e+00 5.6578096e-01
+1 9.0734096e-01 1 1 -4.0051363e-01 7.1642451e-01 -7.2320466e-01 1.0350912e+00 7.4594595e-01 -9.2694813e-01 1.1426276e+00 -5.2042076e-01
+1 5.4895636e-01 1 1 1.0005076e+00 -7.7797245e-01 -7.8818114e-02 -1.3625519e+00 -9.8270226e-01 -5.9322239e-02 -4.1434465e-01 -5.1777656e-01
+1 7.4229294e-01 1 1 -1.4140323e+00 -7.4283224e-02 1.0560650e+00 -1.3404622e+00 -9.2422144e-01 -1.1439965e+00 1.0204599e+00 -5.8962531e-02
+1 8.3565513e-01 1 1 5.0799776e-01 -1.2658633e+00 -7.1420781e-01 -7.8783670e-01 -1.3556742e+00 -6.0154748e-01 9.1440902e-01 -1.3815669e+00
+1 1.0361829e+00 1 1 -9.3040994e-01 -4.9837888e-01 3.3478640e-01 6.4159816e-01 1.1550203e+00 -5.6335562e-01 -1.9878735e-01 -4.8373840e-01
+1 9.4183808e-01 1 1 1.4483985e+00 -7.6780226e-01 1.6255349e-01 1.3943287e+00 5.2532805e-01 4.4232685e-01 -1.5059731e+00 2.5045072e-01
+1 4.5694289e-01 1 1 -9.6866593e-01 1.2099560e+00 -1.1491670e+00 1.3425107e+00 1.3132388e+00 1.1791379e+00 9.2158062e-01 -4.0892580e-01
+1 1.1944426e-01 1 1 -6.3509133e-01 2.0135128e-01 4.6177116e-01 6.5897839e-01 -1.2255537e+00 6.0413596e-01 9.5368135e-01 9.8876949e-01
+1 5.2252062e-01 1 1 1.1518611e+00 6.1565939e-01 1.2540910e+00 1.3356464e+00 1.5419884e+00 8.5542408e-02 1.1677949e-01 -7.7637066e-01
+1 7.2588108e-01 1 1 8.3556692e-01 -1.0188797e+00 5.6178035e-01 1.5301111e+00 1.2009052e+00 -1.1381883e+00 -7.8258710e-01 -1.4274069e+00
+1 2.5303213e-01 1 1 4.5408339e-01 5.1078314e-01 1.3564164e+00 -4.9953451e-01 -1.1194987e+00 -3.7286701e-01 9.0709821e-01 -1.2260195e+00
+1 9.2231179e-01 1 1 8.5098076e-01 -1.2404930e+00 -1.2476571e+00 -1.3409311e+00 -4.1613750e-01 7.0142879e-01 -5.4953498e-01 -3.8783824e-03
+1 9.7064144e-01 1 1 -1.2376680e+00 -1.3567436e+00 7.5760330e-01 7.5691979e-01 -8.3770989e-01 -1.4836392e+00 2.4802632e-01 7.8947354e-01
+1 8.7536285e-01 1 1 -1.0017903e+00 -1.1100852e+00 1.6356923e-01 1.2422783e+00 1.2282024e+00 -7.0386494e-01 -3.1507145e-01 -1.4056601e+00
+1 6.3057364e-01 1 1 -1.2948447e+00 7.1604610e-01 2.1452027e-01 -5.3697130e-02 -1.0071997e+00 1.3798366e+00 1.3192787e+00 -1.5336505e-01
+1 6.1916746e-01 1 1 -6.4194011e-01 -8.5470100e-01 -1.1061862e+00 -8.5057358e-01 -1.1042468e+00 -3.2367001e-01 -2.4394159e-01 -1.5004903e+00
+1 8.0503594e-01 1 1 -8.5831802e-01 1.5434936e+00 2.7314234e-01 -1.3436383e+00 1.4532404e+00 1.3165682e+00 -1.4792424e-01 -1.1755916e+00
+1 5.0437851e-01 1 1 4.4245644e-01 1.3671802e+00 8.3650721e-01 -7.6150697e-01 -1.2721315e+00 1.3254028e+00 -1.1629537e+00 -6.9194214e-01
+1 8.7112578e-01 1 1 2.1550969e-01 5.8963558e-01 5.4960875e-01 2.0077821e-01 9.6613046e-01 -9.8904802e-01 1.2270126e+00 7.0442936e-01
+1 7.0417551e-02 1 1 -1.8499596e-01 1.4218888e+00 9.9193400e-01 4.0889294e-01 -1.1377686e+00 -7.6335343e-01 9.8579921e-01 -1.3184300e+00
+1 9.7356652e-01 1 1 9.4962288e-01 -4.1063434e-01 -9.9750528e-01 -1.5410486e+00 3.9773872e-01 5.8322542e-01 -4.3237763e-01 -1.2006055e+00
+1 7.3680867e-01 1 1 1.0211412e+00 5.4773589e-01 -1.5328956e+00 -1.1142312e+00 -5.1447810e-01 5.0054835e-01 -4.6699098e-01 -1.2718225e-01
+1 5.7171567e-01 1 1 -2.0115633e-01 9.3070402e-01 8.2451744e-01 1.4957304e-01 -1.1705045e+00 -4.6898691e-01 -1.0189206e+00 -1.2690165e+00
+1 7.9645055e-01 1 1 -4.8080239e-01 3.5271285e-01 9.9386426e-02 6.0001551e-01 -1.5707697e-02 -7.0106480e-03 -1.7620961e-01 -8.7774799e-02
+1 7.1228652e-01 1 1 -6.6949898e-01 -1.4051402e-01 -9.3963351e-01 -5.1686188e-02 -1.0548738e-01 1.5525606e+00 9.6698320e-01 1.3175038e+00
+1 3.9421403e-01 1 1 9.1557867e-01 8.5847396e-01 3.6590157e-01 1.5313991e+00 -1.0680789e+00 -1.8199611e-01 6.2777708e-01 1.3416096e+00
+1 8.8027259e-01 1 1 6.0991205e-01 -9.6314508e-01 -1.5307512e+00 -8.4425241e-01 -1.4158144e-01 1.1026614e+00 -1.5603888e+00 1.2225146e+00
+1 2.8653262e-01 1 1 -2.2497583e-01 1.0476145e+00 -8.3354992e-01 1.2237990e+00 -1.3735617e+00 1.7503937e-01 5.6091258e-01 7.8757791e-01
+1 7.6506314e-01 1 1 1.3087963e+00 -1.3703290e+00 -1.1118629e+00 3.8249827e-01 -1.0290164e+00 1.3560260e+00 -6.6188636e-01 1.2920264e+00
+1 1.1024689e+00 1 1 -4.9152429e-01 -1.0308144e-01 -8.8717830e-01 9.4993533e-01 -2.1190756e-01 -1.5260996e+00 5.5567354e-02 3.9846549e-01
+1 1.3514117e+00 1 1 1.3398899e+00 -1.4721508e+00 -8.0692115e-01 -1.0720851e-02 1.0356365e+00 -1.1935128e+00 8.6749731e-01 -8.6596964e-01
+1 8.0073957e-01 1 1 5.9419986e-01 7.4598964e-01 3.3165631e-01 -1.1145624e+00 1.5188951e+00 -3.0119645e-01 -1.0426521e-01 6.4702047e-01
+1 6.7351444e-01 1 1 -4.0608134e-01 -2.4832985e-01 9.6220185e-01 8.6728358e-01 -5.1229224e-01 -1.1029272e+00 6.2327870e-01 1.4207872e+00
+1 1.2377554e+00 1 1 -1.4697774e+00 1.4968666e+00 -1.1925357e+00 -5.5474892e-01 1.0097501e+00 -1.5001904e+00 1.3752130e+00 -7.5362098e-02
+1 1.7750003e-01 1 1 -2.0637821e-01 -3.6948847e-02 4.1439513e-01 5.8193919e-01 -1.3351603e-02 7.2234434e-01 5.0736030e-01 -5.4894751e-01
+1 5.9288552e-01 1 1 -2.8022626e-01 1.0360805e+00 -1.7192878e-01 8.7398417e-01 -1.3473211e+00 1.3273064e+00 9.2210949e-01 6.9687897e-01
+1 7.8919374e-01 1 1 -5.1536282e-01 -4.4276306e-01 6.5829302e-01 -1.0352351e+00 1.7431810e-01 -4.1126421e-01 4.1761737e-01 5.8742515e-01
+1 5.7693653e-01 1 1 -3.3203345e-01 9.1418505e-01 -7.5853676e-01 -1.0556793e+00 -1.3415779e+00 -6.1380319e-01 5.7719922e-01 -1.1711860e+00
+1 6.6495318e-01 1 1 -1.0175887e+00 -8.2155401e-01 -1.4429666e-01 9.1296296e-01 -6.8847926e-01 8.0001154e-01 -2.5082862e-01 1.0966613e+00
+1 5.6144072e-01 1 1 2.1787061e-01 -5.5859538e-01 1.1555440e-01 6.2995958e-01 -7.8519510e-01 -2.2260581e-01 3.4080279e-01 -1.3735658e-01
+1 6.9890890e-01 1 1 -1.3457409e+00 -1.2336735e+00 6.1862096e-01 5.6343803e-01 1.0566223e+00 3.0103339e-01 7.4909743e-01 5.1858286e-01
+1 8.1771587e-01 1 1 -1.5413694e+00 1.6043630e-01 -1.5092899e+00 9.4269833e-01 -7.7273795e-01 1.5040479e+00 -1.4227865e+00 1.0440347e+00
+1 6.7312882e-01 1 1 -2.2172983e-01 9.6632182e-01 -1.4157617e+00 8.7905735e-01 -6.2695854e-02 1.2792464e+00 1.0311639e+00 1.2958002e+00
+1 9.8196324e-01 1 1 -6.8432196e-01 -1.0632733e+00 -2.8424031e-01 -5.9344019e-01 -1.2956744e+00 -7.6509053e-01 -1.3955346e+00 9.9445156e-01
+1 6.1773576e-01 1 1 -2.8539562e-02 -1.0558684e+00 1.1355420e+00 6.0743443e-01 1.1209629e+00 -3.3787451e-01 3.8044629e-01 4.7450488e-01
+1 4.5016832e-01 1 1 9.9925880e-01 8.7711888e-01 -1.2174607e-01 -1.0255816e+00 -1.0794864e-01 1.3427002e+00 1.0196859e+00 -1.5003131e+00
+1 6.2235892e-01 1 1 -4.1167882e-01 1.3842575e+00 -1.0093724e+00 9.6953415e-01 1.5477690e+00 7.0192819e-01 4.7239578e-01 -1.3398141e+00
+1 1.1798246e+00 1 1 -1.2989190e+00 -1.4201403e+00 7.8917539e-02 -4.8065029e-01 9.6722214e-01 6.2665276e-01 7.5131539e-01 6.8067438e-01
+1 6.7953076e-01 1 1 -4.4731902e-03 1.5232691e+00 6.1498383e-01 -1.2546800e+00 1.5021206e+00 1.5342917e+00 1.2969127e+00 1.5554425e+00
+1 8.9489777e-01 1 1 2.1731576e-01 7.4441493e-01 1.9343656e-01 -1.0370889e+00 3.0285391e-01 6.4741926e-01 8.4210857e-01 1.1291067e+00
+1 1.0247969e+00 1 1 -1.2463221e+00 1.5597811e+00 -4.6008045e-01 -7.9700440e-01 6.8561936e-01 -1.3013796e+00 4.4380823e-01 -1.4649794e+00
+1 7.7386401e-01 1 1 1.2039560e+00 -1.3491432e+00 -1.1126778e+00 4.9811348e-01 -1.5719709e-01 -5.1915363e-01 9.4392752e-01 -1.2465028e+00
+1 4.9648104e-01 1 1 -1.0920063e-01 9.6547940e-01 1.1256788e+00 -5.5110361e-01 6.7993858e-02 -1.2122729e+00 -4.5303591e-01 1.3094641e+00
+1 5.3099015e-01 1 1 -6.4484910e-01 4.8628598e-01 6.1309210e-01 -9.8324609e-01 -7.6694859e-01 -1.4418765e+00 1.0461026e+00 1.3071692e+00
+1 8.8485479e-01 1 1 5.1578303e-01 -1.4156993e+00 -1.8501829e-01 -6.3968517e-01 -1.5030595e-01 6.2749536e-01 1.4942722e+00 4.3461694e-01
+1 7.0838972e-01 1 1 1.1112447e+00 7.6543917e-01 5.7427371e-01 -6.5864546e-01 -3.5166755e-01 -1.1972954e-02 3.4084338e-01 4.0397321e-01
+1 2.5368688e-01 1 1 -7.8228183e-02 -8.5747766e-02 8.4560846e-01 1.1182321e+00 -1.1407286e+00 -1.6750567e-01 1.4312219e+00 5.9599171e-01
+1 7.4713886e-01 1 1 1.5462488e+00 8.2831915e-01 -4.2373387e-01 1.1203704e+00 9.1408848e-01 -4.0080461e-01 -6.2841448e-01 1.4352461e+00
+1 7.7677867e-01 1 1 5.4964065e-01 1.1628256e+00 2.9544135e-01 -6.4147983e-01 6.9693498e-01 -7.4838034e-01 2.7232365e-01 1.0332286e+00
+1 8.3435103e-01 1 1 1.5279855e+00 -2.3869873e-01 -1.3752463e+00 5.9455971e-01 1.5288469e+00 9.0862559e-01 -3.5689282e-01 -1.2503925e+00
+1 8.7890884e-01 1 1 1.4744792e+00 4.2039299e-03 -1.0665730e+00 -6.4124223e-01 2.4369377e-01 -1.1623416e-02 -9.9724411e-01 -1.2328006e+00
+1 5.4652352e-01 1 1 6.8894707e-01 1.5404115e+00 3.4651470e-02 1.4462584e+00 -8.7568859e-01 -5.7600678e-01 -2.8499777e-01 -8.7598681e-01
+1 6.1522259e-01 1 1 -7.7714128e-01 -1.6950656e-01 1.1926122e+00 7.6237643e-01 6.6343921e-01 1.4426714e+00 9.7124186e-01 -1.2071065e+00
+1 6.7982561e-01 1 1 1.3287232e+00 5.2772989e-01 8.7233016e-01 -1.2957436e+00 9.1050683e-01 1.6532896e-01 -5.3434738e-02 5.6602876e-01
+1 7.4323813e-01 1 1 1.4108443e+00 8.4015048e-01 -5.5985215e-01 -4.2260584e-02 1.9041782e-01 1.5159606e+00 4.1785464e-01 5.0289703e-01
+1 7.2848329e-01 1 1 -6.8111992e-01 -1.0497774e+00 -3.6509938e-01 -2.7368981e-01 -9.3061431e-01 4.3312986e-01 1.4233412e+00 1.3060654e+00
+1 1.0454819e+00 1 1 3.8108749e-01 -4.2454486e-01 -6.9490867e-01 -6.1299654e-01 1.1551257e+00 5.4336701e-01 -1.1328447e+00 7.3379508e-01
+1 5.2671994e-01 1 1 -7.6996393e-01 -7.6858050e-01 1.1113904e+00 -1.3504605e+00 -8.4470304e-01 -2.4046406e-01 1.4730040e+00 -9.9893064e-01
+1 8.7453430e-01 1 1 -5.6360066e-01 6.9651676e-01 -7.7183905e-01 8.1724724e-01 -6.6827385e-02 -1.3912335e+00 1.0285304e+00 -3.5604221e-01
+1 7.8698852e-01 1 1 -5.3439807e-01 7.8302514e-01 -6.6291630e-01 4.3132877e-01 1.5223182e+00 4.1275688e-01 1.4672720e+00 7.3252709e-01
+1 1.0833110e+00 1 1 1.8501733e-01 1.7183182e-01 -1.5467639e+00 -1.4531553e+00 4.7166457e-01 5.6825898e-01 -1.0625411e+00 -3.1884245e-01
+1 8.4012946e-01 1 1 -5.9047672e-01 8.5372953e-01 2.1820747e-01 -4.3917086e-01 1.0280862e+00 2.8694647e-01 -1.3164608e+00 7.7195082e-01
+1 7.9255572e-01 1 1 1.4901227e-01 9.7849611e-01 1.1743266e+00 -1.5435179e+00 2.8571469e-01 3.6464106e-01 4.8045802e-01 -6.0020937e-01
+1 5.2446076e-01 1 1 5.9995420e-01 -6.5347661e-01 1.4224096e+00 1.3664851e+00 -1.4884024e+00 -7.2497295e-01 1.1647439e+00 -6.4828708e-02
+1 1.1457953e+00 1 1 -1.0822122e+00 2.6466034e-02 -1.0814857e+00 1.4729988e+00 9.2340348e-01 -1.5239956e+00 5.8773608e-01 5.5655860e-01
+1 5.7203837e-01 1 1 1.0811635e+00 -1.2915311e+00 7.2492660e-01 9.4090137e-01 1.7461699e-01 -3.8871897e-01 9.1292472e-01 1.5591070e+00
+1 8.6572959e-01 1 1 1.4261873e-01 -1.5003316e+00 7.4499728e-01 -1.0481288e+00 5.4015509e-01 1.3129716e+00 -1.2702330e-02 -1.1255936e-01
+1 7.1138406e-01 1 1 -4.2197843e-02 1.4910693e+00 -1.2189651e+00 -9.9144158e-01 -8.1620267e-01 5.6770212e-01 1.4024512e-01 -5.4637619e-01
+1 9.5285640e-01 1 1 7.8078419e-01 -8.2823004e-02 -8.2107083e-01 -1.5115038e-01 1.4169243e+00 3.5268068e-01 9.0527714e-01 -6.9342853e-02
+1 4.6751889e-01 1 1 2.0733644e-01 -2.8068202e-01 1.2791468e+00 1.1639613e+00 9.7447827e-01 -6.8121255e-01 2.5969796e-01 8.5541606e-02
+1 8.2130437e-01 1 1 6.7728983e-01 1.2493759e+00 7.0169145e-01 6.5797740e-04 9.3379632e-01 -1.1757043e+00 1.0714422e+00 -1.1516621e+00
+1 7.5839854e-01 1 1 1.2200239e+00 -1.4418839e-01 -2.1068696e-01 -1.5077445e+00 -1.0820737e+00 5.5537392e-01 1.1982079e-01 -6.3270155e-01
+1 1.1977834e+00 1 1 -2.3308384e-01 -1.2064086e+00 -4.4088237e-01 -5.7572184e-01 2.6682914e-01 4.9767514e-01 6.7131546e-02 4.7612456e-01
+1 2.4656334e-01 1 1 1.2588477e-01 -2.7017610e-01 1.1070798e+00 -5.1627925e-02 1.5445894e+00 1.5063711e+00 4.4812557e-01 5.8895647e-01
+1 1.1680172e+00 1 1 1.4534992e+00 -1.2482873e+00 -9.6271291e-01 -6.3095660e-01 9.3346059e-01 -5.1609576e-01 1.2489355e+00 -5.6703634e-01
+1 1.0694357e+00 1 1 -6.3474878e-02 -4.0946793e-01 -1.1137414e+00 1.5291843e+00 -4.4149343e-01 -8.4054292e-02 -1.2638349e+00 1.4124020e+00
+1 1.0222588e+00 1 1 1.3192265e+00 1.3020729e+00 -1.0431430e+00 -3.6846365e-01 2.6175754e-01 1.0162023e+00 -9.6577923e-01 3.6606764e-01
+1 6.7468789e-01 1 1 -1.1212398e+00 -3.9597635e-01 1.1241846e+00 -6.8940021e-01 1.1292504e+00 -1.5277772e+00 7.5766578e-01 1.2604442e+00
+1 1.0489074e+00 1 1 -1.4039918e+00 -1.2812696e+00 6.3294262e-01 -5.5562766e-01 9.5003090e-01 -1.1152880e+00 1.2137159e+00 5.2608611e-01
+1 4.0822025e-01 1 1 -3.8855499e-01 1.3188659e+00 4.3394429e-01 1.5208492e+00 -1.5461259e+00 1.2379532e+00 5.6157007e-01 1.4874476e+00
+1 8.6444080e-01 1 1 9.2743920e-01 -8.9778241e-01 -1.4764729e+00 9.1468649e-01 1.5166730e+00 -4.8896839e-01 9.6386028e-01 -1.2633017e+00
+1 6.3492225e-01 1 1 -1.1121504e+00 4.0543279e-02 3.6040924e-01 1.3230618e+00 -1.5914476e-01 3.1459212e-01 1.5479522e+00 -1.4279339e+00
+1 1.6622561e-01 1 1 5.6436373e-01 -3.1471984e-01 4.0748893e-01 5.0696883e-01 -1.2505550e+00 4.9359225e-02 9.0397955e-01 -6.5872972e-01
+1 2.9546409e-01 1 1 7.9294115e-01 9.4561774e-01 -5.5653639e-03 6.2581667e-01 -8.2376272e-01 2.0004082e-01 4.4218909e-01 -2.9782216e-01
+1 7.6498783e-01 1 1 3.2579866e-01 -3.1983486e-01 7.1070869e-01 4.8499881e-02 1.8861720e-02 5.8195470e-01 -1.1361710e+00 -9.3998828e-01
+1 5.6260161e-01 1 1 -9.7847783e-02 -1.9949583e-01 5.4573777e-01 1.4650025e+00 -2.9193793e-01 1.1347567e+00 -1.0260241e+00 6.8640485e-01
+1 1.0209732e+00 1 1 -1.4747256e+00 -8.4704244e-01 -1.2358104e+00 -1.5054309e+00 5.6693487e-01 -7.5317959e-01 -1.8581310e-01 4.7817040e-01
+1 8.2085414e-01 1 1 1.4520464e+00 1.4555470e+00 -1.1971039e+00 6.0962955e-01 2.3916375e-02 -1.2126107e+00 -2.1761630e-01 4.1589026e-01
+1 9.4074639e-01 1 1 6.5263779e-01 -2.0337287e-01 -9.6519504e-01 1.3102367e+00 -1.6134405e-01 -8.3596425e-01 -6.6329278e-01 -1.7611721e-01
+1 7.2009083e-01 1 1 -1.5581376e+00 -3.5083856e-02 1.1514675e+00 -1.4170221e+00 -5.1502642e-01 -8.4872527e-01 1.5506046e+00 -6.2175161e-01
+1 7.7392032e-01 1 1 6.9692871e-01 9.6505560e-01 5.0423725e-01 5.2335742e-01 -9.6135277e-01 1.4466346e+00 1.4996955e+00 -8.4221887e-01
+1 7.9888871e-01 1 1 1.4234167e+00 -3.5338539e-01 -1.3015701e+00 -3.9120722e-01 -2.4500408e-01 8.0195363e-01 3.8377536e-01 8.4397847e-01
+1 8.1988977e-01 1 1 1.3676791e-01 1.4035292e+00 -5.7840479e-01 3.3371485e-01 8.4444263e-01 1.0021673e+00 4.2275535e-01 4.5529817e-01
+1 5.6146438e-01 1 1 -9.8759706e-01 -1.1038836e+00 -1.1616111e+00 1.0026268e+00 -1.1682851e+00 1.3470597e+00 -1.0334565e+00 -7.2341998e-01
+1 8.7417265e-01 1 1 -1.5098068e+00 1.2737204e+00 -1.3402752e+00 -3.5358003e-01 -4.1350566e-01 -1.4256336e+00 5.6217450e-01 -5.5600359e-01
+1 1.0745129e+00 1 1 -6.7886895e-01 6.0722456e-01 -7.8661149e-01 1.2736880e+00 -5.8660907e-01 3.0341849e-01 -1.4439379e+00 1.4858452e+00
+1 7.6611190e-01 1 1 5.1403022e-01 -1.4114008e+00 -7.5737245e-01 6.2075736e-02 -8.2084572e-01 7.4975509e-01 5.3855969e-01 8.0847645e-02
+1 3.6760247e-01 1 1 -7.3947005e-02 7.5346810e-01 5.7468381e-01 2.9813235e-01 -1.2207470e+00 2.0566477e-01 6.4429358e-01 -1.5032546e+00
+1 3.9785984e-01 1 1 1.2433858e+00 -2.2162192e-01 1.4550201e+00 -1.2995940e-01 6.4683033e-01 8.5585530e-01 -4.2769900e-01 -5.1216499e-01
+1 8.5077737e-01 1 1 -2.8860416e-01 1.1292346e+00 3.6551510e-01 -8.2080220e-01 1.3668223e+00 -9.9278841e-01 -3.7314676e-01 6.9298086e-03
+1 7.3968219e-01 1 1 4.8978650e-02 6.8539818e-01 1.3987108e+00 -4.8927589e-01 8.5690743e-01 -7.9621739e-01 -8.5870274e-01 2.3036439e-01
+1 7.7961076e-01 1 1 8.6898530e-02 -7.3312501e-01 -4.0517784e-01 1.4297066e+00 9.8253165e-01 1.1590025e+00 2.5970760e-01 1.2921250e+00
+1 5.3714052e-01 1 1 -3.3699215e-01 -3.0571078e-01 1.1488725e+00 -9.6318607e-01 1.1984473e+00 1.4813905e+00 1.2334231e+00 -1.0853800e+00
+1 8.3362238e-01 1 1 4.6447154e-01 1.5644276e+00 8.7226833e-01 3.5872851e-01 1.5540556e+00 6.0763100e-01 -1.2280849e+00 1.2460916e+00
+1 7.1398481e-01 1 1 -4.8463506e-01 1.3451034e+00 1.5424368e+00 4.3373629e-01 -1.8952841e-01 -8.6345729e-01 -1.5949471e-01 1.2050878e+00
+1 8.9663933e-01 1 1 8.8824051e-01 2.5153392e-01 -6.8649943e-01 1.3108952e+00 1.7089628e-01 -1.1102648e+00 -8.4913507e-01 6.3131201e-02
+1 3.0204615e-01 1 1 -1.9006813e-01 -1.0530633e+00 1.0739048e+00 2.2620607e-01 8.3803901e-01 8.3984712e-01 8.4228793e-01 -8.1222881e-01
+1 5.3993955e-01 1 1 5.2471945e-01 8.9889014e-01 6.6818578e-01 5.1835671e-01 1.1617493e+00 1.3477152e-01 3.1676169e-01 -9.0954014e-01
+1 1.0786844e+00 1 1 5.0929688e-01 -2.7254901e-01 -9.9528613e-01 3.8475592e-01 5.2158895e-01 1.6567858e-02 -1.1859055e+00 3.4866179e-01
+1 6.7295534e-01 1 1 -1.0873549e+00 -2.8910881e-01 1.2069405e+00 1.1950943e+00 1.3020608e+00 -1.1457547e+00 -1.2505825e+00 8.8840673e-01
+1 8.2102719e-01 1 1 -5.2933783e-01 9.9206020e-01 -2.1450050e-01 -1.3929772e+00 -5.9847706e-01 1.2644952e+00 -1.2847247e+00 -5.3793289e-01
+1 7.3591873e-01 1 1 4.0943621e-01 1.1235888e+00 1.4384585e+00 -6.1859234e-01 7.7577251e-01 -5.0268713e-01 -2.0247011e-01 4.6558767e-01
+1 1.0090237e+00 1 1 1.3064187e+00 4.3893395e-02 -1.5245362e+00 -1.1513759e+00 7.9914097e-01 -9.1990201e-01 -5.7022182e-01 -5.7538696e-01
+1 5.5733393e-01 1 1 3.8867994e-01 -5.5798715e-01 -5.0090722e-02 1.0360565e+00 8.5369784e-01 -1.0155802e+00 1.2811028e+00 -7.0646883e-01
+1 7.4766745e-01 1 1 1.1725836e+00 -4.3600137e-01 7.2058439e-02 -8.4641218e-01 4.4591138e-01 -5.8435911e-01 -9.8191793e-01 -1.5429697e+00
+1 1.0660428e+00 1 1 4.0222303e-01 1.4606597e+00 -1.5685847e+00 -5.1796634e-01 -1.4075499e+00 -7.0494197e-01 -3.0845000e-01 1.1557106e+00
+1 7.7376536e-01 1 1 -5.4496753e-01 9.0338457e-01 1.0428826e+00 -1.0707566e-01 -4.9781572e-01 -1.0138358e+00 -4.9135386e-01 -4.3868141e-01
+1 3.4272892e-01 1 1 -1.5267615e+00 -1.3289457e-01 7.8187756e-01 5.1200980e-01 -7.2763912e-01 4.6051310e-01 1.0627382e+00 3.9953151e-01
+1 1.0304182e+00 1 1 2.4758790e-01 1.1330976e-01 -2.6599329e-01 5.2644586e-01 7.8948234e-01 -1.0405889e+00 1.4859612e+00 1.3425852e+00
+1 5.9746732e-01 1 1 -1.4004925e+00 5.9194439e-01 -6.2854491e-02 1.2506885e+00 -1.2576202e+00 6.8374015e-02 -1.1109258e+00 -1.2304587e+00
+1 1.0353695e+00 1 1 -1.2656369e+00 -6.1465449e-01 -8.2030007e-01 -7.5004288e-02 -1.8785217e-01 -6.6083826e-01 -8.4454014e-01 7.8566907e-01
+1 8.8311487e-01 1 1 1.6377658e-01 -9.4131568e-01 -1.4746475e+00 -8.1840763e-01 6.9190600e-02 -1.1785415e+00 -4.7050524e-01 6.2609720e-01
+1 9.5506147e-01 1 1 5.5787727e-01 3.6805341e-01 -3.7666008e-01 -1.0844400e+00 4.9713153e-01 -5.3501701e-03 -3.9280081e-01 -1.5197087e+00
+1 4.3411161e-01 1 1 -1.4108710e+00 7.7775724e-02 -2.1672421e-01 1.3380764e+00 -1.3468497e+00 1.1858780e+00 -1.3169917e+00 -5.9606044e-01
+1 7.4213509e-01 1 1 2.3279575e-01 2.7405713e-01 -1.3778440e+00 1.5300080e+00 -1.3273615e+00 7.8794851e-01 9.8234570e-01 5.5108933e-01
+1 6.2692454e-01 1 1 1.3152814e+00 5.0340280e-01 -7.4476601e-01 9.0909859e-01 -5.1533142e-01 1.2375327e+00 1.2147529e+00 7.4329898e-01
+1 8.2931934e-01 1 1 -1.4525398e+00 3.8186690e-01 -1.1772688e+00 -1.4866504e+00 1.9570759e-01 -1.2732692e+00 -8.5947575e-01 -1.4880354e+00
+1 9.9982640e-01 1 1 4.8033120e-01 -2.3685487e-01 -6.0567727e-01 -1.0473564e+00 9.9782504e-03 6.9311379e-01 -1.6597970e-01 8.0837596e-01
+1 1.2026713e+00 1 1 -9.6667681e-01 -4.2198402e-01 -8.5762307e-01 -5.7544166e-01 1.2000443e+00 1.3783165e-01 1.1350318e-01 -1.0134206e+00
+1 6.6331707e-01 1 1 1.3801131e+00 1.4307701e+00 -4.4390645e-01 1.5157568e+00 1.1959723e-01 1.1828229e+00 7.0123063e-01 1.1558080e+00
+1 5.5108292e-01 1 1 1.1825662e+00 1.2030049e+00 5.4692539e-01 1.5042964e-01 -5.4867692e-01 -2.9316088e-01 1.4690782e+00 1.1984862e+00
+1 7.7275267e-01 1 1 -1.4661168e+00 -3.8654881e-01 -1.2508109e-01 -7.1104733e-01 -1.0386214e+00 -1.1376015e+00 1.0205775e+00 -9.3513863e-01
+1 7.3475955e-01 1 1 -1.5131022e+00 8.7738489e-02 -5.1241367e-01 4.5963038e-02 -1.4205780e+00 6.4552556e-02 -2.5039218e-01 5.1315347e-01
+1 6.1554130e-01 1 1 4.8447837e-01 1.2138329e+00 -1.0310666e+00 -3.3101858e-01 4.4987116e-01 1.0853380e+00 1.3928344e+00 8.9854921e-01
+1 5.5530195e-01 1 1 -3.8021431e-01 -6.1245135e-01 -1.1083286e-01 3.3132167e-01 -8.2897572e-01 1.1891827e+00 1.3600992e+00 2.8072191e-01
+1 1.0329385e+00 1 1 -2.6240228e-01 1.5292162e+00 1.9658900e-01 -1.5203947e+00 3.6843667e-01 -2.1875335e-01 9.5914311e-01 -5.7907793e-01
+1 9.6920270e-01 1 1 6.0102116e-01 1.6660440e-01 -8.8408459e-01 4.4168622e-01 2.3603565e-01 -9.2421252e-01 8.0640569e-01 9.1347934e-02
+1 5.0853571e-01 1 1 1.1422998e+00 9.6102158e-01 9.2348870e-01 -1.6309300e-01 -7.8041495e-01 -1.2057411e+00 4.2974995e-01 -9.5408453e-01
+1 9.4190878e-01 1 1 3.5986743e-01 9.6182947e-01 -1.5346446e+00 1.5063832e+00 -2.8474545e-01 1.5239441e+00 2.8586551e-01 -6.0979501e-01
+1 6.9024780e-01 1 1 7.2598021e-01 -1.1678172e+00 -2.9598520e-01 -3.1231651e-01 -1.0710829e+00 -4.7603970e-01 1.0464954e+00 -9.4948817e-01
+1 9.2377632e-01 1 1 -3.9651594e-01 1.1679635e+00 -1.4820806e+00 4.9773138e-01 -3.6516081e-01 8.3730155e-01 -1.3294892e+00 1.2430508e+00
+1 5.8732118e-01 1 1 -9.2530737e-01 1.2910580e+00 3.5957480e-01 -6.8996418e-01 1.4143139e+00 1.3336308e+00 1.4234241e+00 3.6399931e-01
+1 1.0586455e+00 1 1 -7.5726907e-01 -1.6866818e-01 -1.0505438e+00 -6.0951050e-01 1.0842201e+00 -9.3007361e-01 2.6149910e-01 1.0554320e+00
+1 1.3015803e+00 1 1 -8.2944982e-01 -1.0895919e+00 -7.3941736e-01 6.9069949e-01 1.2505036e+00 8.1784977e-01 -7.2767635e-02 1.2140896e+00
+1 7.3837187e-01 1 1 -1.3164957e+00 -4.2781641e-01 7.5298576e-01 4.0146106e-01 -4.0061636e-02 1.1331598e+00 -9.2610046e-01 5.5895552e-01
+1 5.3995275e-01 1 1 -1.0543190e-01 7.9521959e-01 1.0964646e+00 -7.8497181e-01 -1.0150948e+00 6.8179507e-01 -1.5204412e+00 1.0034547e+00
+1 1.1115446e+00 1 1 -1.3572984e-01 9.2053939e-01 -3.0228380e-01 -1.4736860e+00 1.2916408e+00 1.5413537e+00 -3.3986914e-01 9.9346581e-01
+1 1.2200257e+00 1 1 -4.1513125e-01 -8.3836524e-01 -5.2847002e-01 7.6413283e-02 2.0248871e-01 -4.2042343e-02 -7.6524742e-01 -3.8502055e-01
+1 1.1934248e+00 1 1 3.6630770e-01 -3.6152387e-01 -7.1316526e-01 -6.3335598e-01 8.8289806e-01 2.5269478e-01 1.6688159e-01 6.4050076e-01
+1 1.2821186e+00 1 1 -9.8816777e-01 -2.9148591e-01 -9.9250819e-01 -1.0981118e+00 1.1255200e+00 -3.9210872e-01 -6.6336891e-01 -1.3417705e+00
+1 3.2416000e-01 1 1 1.4645803e+00 -1.2607473e+00 7.7185582e-01 8.9251383e-01 1.0852209e+00 8.9004704e-01 2.7098498e-01 -7.8485719e-01
+1 5.8078557e-01 1 1 8.2309378e-01 6.6313440e-01 9.4468635e-01 -6.2503849e-01 -7.7939660e-01 -1.2436985e+00 -8.6481207e-01 4.5279994e-01
+1 4.0373556e-01 1 1 1.3047857e+00 -1.0709029e+00 -2.6577131e-01 4.6390670e-01 1.1226826e+00 1.3172944e+00 1.2527766e+00 1.2712061e+00
+1 6.4229576e-01 1 1 1.2157837e+00 -4.8043005e-01 5.2632597e-01 -5.5312273e-01 5.2053825e-01 9.6378129e-01 4.6213262e-01 -8.0988224e-01
+1 7.0861070e-01 1 1 7.5750952e-01 -6.9478298e-01 -7.6431157e-01 -3.6114267e-01 -6.4908997e-01 2.2036288e-01 1.0459515e+00 8.3015571e-01
+1 8.9232157e-01 1 1 -1.4125727e+00 8.2310874e-02 1.8778461e-01 -1.6784486e-01 1.4960989e+00 -2.9884451e-01 -1.0459856e+00 6.1402092e-01
+1 6.5300889e-01 1 1 -9.4521748e-02 1.0980981e+00 -1.2047288e+00 1.8170057e-01 -3.7316309e-01 7.2690560e-01 4.7241391e-01 -2.8220791e-01
+1 5.6467221e-01 1 1 1.0188687e+00 -1.1226014e+00 -3.1242977e-01 2.1335563e-01 -1.1330966e+00 -5.5143644e-01 1.0559024e+00 7.3664172e-01
+1 9.6604638e-01 1 1 -6.9464670e-01 8.4299765e-01 -1.4058146e+00 1.3108200e+00 3.7998134e-01 -2.9398302e-01 -3.0492407e-01 -2.7929906e-01
+1 8.0281076e-01 1 1 -7.6880601e-01 -3.2129442e-01 3.9213214e-01 -1.0368417e+00 -5.1140395e-01 7.5268812e-01 -9.2116889e-01 -6.3984430e-01
+1 9.8298876e-01 1 1 4.7958059e-02 4.0253194e-01 -4.9655246e-01 2.1620802e-01 2.3127200e-01 -7.6441836e-01 -3.1697786e-01 -1.9148329e-01
+1 4.1305967e-01 1 1 -1.3582218e+00 1.5052865e+00 -1.4870950e+00 -1.0145131e+00 8.3837087e-01 1.5346053e+00 6.9428734e-01 -1.2688433e+00
+1 8.4476131e-01 1 1 -8.2097959e-01 1.0480673e-01 9.0562244e-01 -1.4981205e+00 4.5613566e-01 -3.6398615e-01 1.0122036e+00 -3.1757152e-01
+1 1.1414957e+00 1 1 -3.2903654e-01 -9.4673661e-01 -2.2013080e-01 9.5383697e-01 7.8600016e-01 -8.3424501e-01 3.8230189e-01 1.4140598e-01
+1 7.0789836e-01 1 1 -9.1404431e-01 3.6463316e-01 1.0578492e+00 -4.0936753e-01 -9.2400129e-02 -2.2781125e-01 7.9090906e-01 1.5662071e+00
+1 2.6107934e-01 1 1 4.5428284e-02 -8.5769500e-01 9.9884789e-01 -1.5214503e-01 -1.0221944e+00 7.7772450e-01 7.3000975e-01 -1.6238329e-01
+1 1.2630775e+00 1 1 1.0615542e-01 1.4888534e+00 -1.0346626e+00 1.5482241e-01 1.3483984e+00 -9.5134576e-01 1.3545511e+00 8.6808125e-01
+1 4.0402872e-01 1 1 -2.7041919e-01 3.7302549e-01 -8.5936246e-01 8.6145866e-01 -9.1773893e-01 1.4383398e+00 -1.1821643e+00 2.8533213e-01
+1 7.0179816e-01 1 1 9.4930605e-01 -1.1796060e+00 -1.4034854e+00 -1.0648060e+00 7.8175230e-01 -3.7888847e-01 -1.2041709e+00 1.5067076e+00
+1 1.0214091e+00 1 1 -1.1623267e+00 9.5239784e-01 -1.3021318e+00 1.4583151e+00 7.7041322e-01 2.9812903e-02 -3.6095289e-01 -1.1429809e+00
+1 7.5755453e-01 1 1 -8.0145334e-01 5.3587386e-01 -5.9511168e-01 -8.0442160e-01 -1.3099367e+00 1.5522351e+00 -1.1978090e-01 7.5840253e-01
+1 2.8128431e-01 1 1 1.1230738e+00 -5.1420023e-01 7.8897496e-01 1.5008743e+00 1.7466853e-01 6.2924438e-01 6.0324021e-01 1.0299341e+00
+1 2.9949051e-01 1 1 8.1247913e-01 3.5820451e-01 -3.6046769e-01 1.3470795e+00 1.4063644e+00 1.1094886e+00 7.3874841e-01 -7.3694253e-02
+1 7.8327601e-01 1 1 -1.1664938e+00 1.0517496e+00 -1.3898239e+00 -1.0934842e+00 -5.7657365e-01 -1.3193068e+00 5.7039115e-01 -7.9180867e-01
+1 8.4172202e-01 1 1 1.4183803e+00 -9.8594918e-01 -1.0288030e+00 1.2742656e-01 1.3399582e+00 -2.2783883e-01 1.5649468e+00 -1.4178788e-01
+1 4.0489369e-01 1 1 3.1258052e-01 1.0533085e+00 2.3353575e-01 -9.0807110e-01 -1.4001019e+00 3.1418081e-01 6.4762400e-01 1.4398443e+00
+1 6.4026773e-01 1 1 7.9781660e-01 8.2137555e-02 1.1861571e+00 -9.3942156e-02 -9.8328510e-01 -5.8038607e-01 -1.0020338e+00 -2.2539878e-01
+1 3.4906175e-01 1 1 5.8609451e-01 1.3267146e+00 -8.0445395e-01 1.3352944e+00 -1.2952800e+00 9.6441952e-02 8.9574135e-01 4.8341019e-01
+1 6.3251443e-01 1 1 -1.5441457e+00 -9.3237883e-01 9.5717614e-01 -1.2452213e+00 1.4663811e+00 -1.6192114e-01 2.1284953e-01 5.1643435e-01
+1 1.0725687e+00 1 1 2.3939278e-01 -2.2686248e-01 -8.3667051e-01 8.5538209e-01 -3.2787754e-01 -7.8928491e-01 -9.1200787e-01 -5.0840872e-01
+1 4.3279195e-01 1 1 -9.0568798e-01 1.0158314e+00 -1.5254488e-01 4.7872262e-01 -2.8429101e-01 1.4343002e+00 -2.8563569e-01 3.0661476e-01
+1 1.1251722e+00 1 1 -8.8145240e-01 -1.4775617e+00 -2.8213416e-01 2.7233736e-01 2.8334738e-01 8.4240304e-01 -3.2547800e-01 1.0622624e+00
+1 8.3477813e-01 1 1 1.1804659e+00 9.0963985e-01 -1.1654332e+00 -1.2646098e-01 -4.3507923e-01 -8.9015750e-01 -7.9598133e-01 -2.2606625e-01
+1 9.2418392e-01 1 1 9.3244524e-01 1.3271815e+00 3.9461548e-01 1.4285382e+00 1.2511063e+00 -6.1288585e-01 -1.1566835e+00 -1.3098987e+00
+1 7.3740679e-01 1 1 1.3429767e+00 6.3244471e-01 4.0036159e-01 1.3897212e+00 6.6459691e-01 5.0991025e-01 -2.0361554e-01 8.1467501e-01
+1 7.2635375e-01 1 1 -9.3303483e-01 1.4903240e+00 -4.1422015e-01 -6.9682952e-01 1.5183529e+00 -2.0313557e-01 -9.7192823e-01 1.1821344e+00
+1 4.8691252e-01 1 1 1.3141855e+00 -4.3540548e-02 -2.8732035e-02 2.4359979e-01 -2.0051329e-01 8.1177114e-01 1.0839773e+00 7.0059917e-01
+1 6.7008379e-01 1 1 -1.0224591e+00 2.0510244e-01 9.0595428e-01 6.8644280e-01 9.0212042e-01 -4.9942473e-01 3.1129889e-01 2.8103404e-01
+1 7.3134053e-01 1 1 4.2474585e-02 8.2955937e-01 -9.2599027e-01 1.1159149e+00 6.1178435e-01 5.0409722e-01 1.2487023e+00 1.5253173e+00
+1 6.7241500e-01 1 1 7.2882051e-01 1.6144867e-02 3.3147158e-01 -1.2713762e-01 -1.7313819e-01 -5.1347034e-01 1.1006568e+00 6.1145054e-01
+1 5.0539044e-01 1 1 2.1652985e-01 1.1698126e+00 9.9908689e-01 -5.1903118e-01 -8.1876198e-01 5.9083850e-02 1.0412697e+00 4.9970059e-01
+1 8.4534168e-01 1 1 1.2529203e+00 9.5303998e-01 -1.5933558e-01 8.4575490e-01 -7.5680637e-01 2.7899607e-01 -1.1921515e+00 9.9068136e-01
+1 1.3151640e+00 1 1 -2.6464647e-01 -1.2380401e+00 -1.3161497e+00 -1.1042151e+00 6.6394772e-01 -1.3108313e+00 5.8735824e-01 -5.9447526e-02
+1 9.4075998e-01 1 1 5.8201582e-01 -9.7156427e-01 -5.7439309e-01 -1.1560380e+00 3.2261891e-02 8.4712636e-01 8.4578520e-01 -1.0810629e-01
+1 4.5084870e-01 1 1 -9.7965382e-01 9.1788207e-01 2.8956509e-01 1.2195075e+00 -1.2699246e+00 -4.5221539e-02 -5.9486537e-01 -1.1018529e+00
+1 9.1775486e-01 1 1 4.5335528e-02 -1.5175795e+00 3.9337466e-01 5.1130803e-01 3.5742295e-01 2.2702244e-01 -1.3545264e+00 8.4720871e-01
+1 6.5727290e-01 1 1 -1.4528001e+00 6.3205235e-01 1.5370107e+00 1.2980846e+00 4.8237435e-01 -1.4688559e+00 -1.5455509e+00 1.3389431e+00
+1 8.3690145e-01 1 1 -7.5251925e-01 1.1791067e+00 -7.7789291e-01 -1.4536333e+00 -1.1848607e+00 -4.2606157e-01 -1.3857963e+00 3.8825309e-01
+1 5.0604035e-01 1 1 4.6093361e-01 7.9197865e-02 1.2624772e+00 9.5071045e-01 6.0285852e-01 -1.1271280e+00 6.8889906e-01 2.8169699e-01
+1 4.9962428e-01 1 1 -2.5633725e-01 -9.5676533e-01 1.3675031e-01 4.5037211e-01 6.0684604e-01 1.6389864e-01 1.5575957e+00 1.0118176e-01
+1 9.7885571e-01 1 1 -1.1366239e+00 1.4579332e+00 -1.2832835e+00 1.3072804e+00 -1.4899980e+00 -5.3230159e-01 -3.8047817e-01 9.6013788e-01
+1 8.2482452e-01 1 1 7.8626636e-01 -9.3934821e-01 -1.1122075e+00 -8.3689299e-01 -7.6052046e-01 8.6306385e-01 -1.5556145e+00 -1.3241056e+00
+1 1.0770242e+00 1 1 1.2400779e+00 -1.1223247e+00 -3.9488380e-01 -7.5015877e-01 1.0730890e+00 7.8085293e-01 -8.7818952e-01 7.9883649e-01
+1 2.4803916e-01 1 1 6.6388279e-01 -7.8817892e-01 1.3732982e+00 -7.0713831e-01 -4.7638394e-01 1.3627412e+00 -5.2891540e-01 -1.1221060e+00
+1 4.0805996e-01 1 1 -1.0591176e+00 1.1730602e+00 -2.5866360e-01 -2.2859172e-01 1.3347348e+00 1.3801911e+00 1.2260201e+00 -2.5441815e-01
+1 7.5751960e-01 1 1 -3.2537368e-01 -1.0131307e+00 6.0509343e-01 2.2681427e-01 -1.2255637e+00 -6.4827937e-01 1.4057510e-02 -2.9831349e-01
+1 7.2501825e-01 1 1 9.5733648e-01 -2.5538628e-01 4.6991895e-01 1.3155125e+00 1.3746229e+00 -5.8808587e-01 6.4511682e-01 2.2708325e-01
+1 1.1865318e+00 1 1 -1.2833761e+00 -8.6158697e-01 -3.6111570e-02 -7.0983645e-01 1.4250577e-02 -5.0865263e-01 8.4206907e-01 -4.4696003e-01
+1 1.1629004e+00 1 1 4.7347851e-01 -1.0915954e+00 -5.9978008e-01 1.5477528e+00 7.4840376e-01 -6.5110421e-01 -2.1999873e-01 -5.0915416e-01
+1 7.6960969e-01 1 1 9.9064142e-02 4.5751826e-01 8.6697113e-01 6.9459856e-01 -5.1493431e-01 -9.4121968e-01 1.3589642e-01 3.4439739e-01
+1 5.9653552e-01 1 1 -7.3071672e-02 -1.1093669e+00 4.7708851e-01 -4.0385440e-02 5.8673514e-01 -1.1601967e+00 7.3216609e-02 1.4732611e+00
+1 5.6696583e-01 1 1 2.4713832e-01 2.2332532e-01 1.0821071e+00 -1.7407912e-01 -2.0179192e-01 4.3919896e-01 -9.5277236e-01 -9.3467262e-01
+1 6.2428750e-01 1 1 4.6827494e-01 -7.7464987e-01 2.9368672e-01 -9.2495822e-01 1.4033363e+00 -1.1257534e+00 -5.4737240e-01 -1.0793761e+00
+1 6.1796013e-01 1 1 6.0730071e-01 -7.8040578e-01 5.5071564e-01 -1.1723350e+00 -1.2051790e+00 1.2753123e+00 -1.1046426e+00 -1.5177276e+00
+1 7.4391192e-01 1 1 -1.3148614e-01 -1.3063247e-01 7.4581518e-01 6.3518326e-01 1.5454947e+00 -9.1304333e-01 1.0839234e+00 1.2853401e+00
+1 1.0401213e+00 1 1 -1.3479445e+00 4.3328780e-01 -3.8989733e-02 3.9322717e-01 4.4147328e-01 1.1609317e+00 -5.9582363e-01 1.1201281e+00
+1 6.1135736e-01 1 1 -8.7930748e-01 5.6313748e-02 1.2924238e+00 -9.4192647e-01 -6.0039793e-01 -6.5263301e-01 1.3895847e+00 1.5701283e+00
+1 8.2507571e-01 1 1 -4.6899594e-01 8.4577016e-01 7.9519729e-01 -4.7276940e-01 -9.2386882e-02 -1.5030792e+00 1.4951743e-01 -2.3200320e-01
+1 6.8440174e-01 1 1 -1.5871407e-01 -8.4772080e-01 5.4573113e-01 -7.4749607e-01 -7.9955676e-01 -7.0626100e-01 -3.3464475e-01 -5.6125581e-01
+1 1.3088982e+00 1 1 -2.9517602e-01 -5.2078942e-01 -1.3474366e+00 6.2606259e-02 -1.5586064e+00 -1.1915727e+00 -9.2341052e-01 1.1764077e+00
+1 2.5492661e-01 1 1 -4.4852237e-01 -4.3070476e-01 1.3741070e+00 -2.1014803e-01 -8.9828469e-01 8.9141649e-01 -2.9298008e-01 -1.2991798e+00
+1 4.8668189e-01 1 1 1.5069405e+00 -6.2539489e-01 7.6845276e-01 -8.0773680e-01 1.0234808e+00 -2.1846319e-01 -1.2404542e+00 -1.2466668e+00
+1 7.8048921e-01 1 1 -3.7114169e-01 7.5716729e-01 2.9821433e-01 -8.1050387e-01 1.4217746e+00 8.1105409e-01 -7.0439430e-01 -1.4475304e+00
+1 5.7695410e-01 1 1 1.4245766e+00 -8.8113532e-01 1.2479846e+00 -1.9273580e-01 8.1199611e-01 1.5522937e-02 -1.2338797e+00 -1.4965735e-01
+1 8.3746906e-01 1 1 7.8208494e-01 2.2637338e-01 -1.5362657e+00 -3.2849888e-01 1.4011045e-01 1.4180691e-01 -1.6231657e-01 1.1245639e+00
+1 6.0312861e-01 1 1 7.7880039e-02 1.8876028e-01 7.3302915e-01 -1.3023388e+00 -1.3582018e+00 -1.1200131e+00 -1.1522092e+00 7.2459565e-01
+1 9.6024354e-01 1 1 -1.1143161e+00 -5.1451129e-01 -1.3055418e+00 -9.3266608e-01 -4.8560931e-01 3.6220938e-01 -4.0321617e-01 1.4659042e+00
+1 9.7289079e-01 1 1 -1.2762424e+00 1.4133998e+00 -1.3581273e+00 1.2284906e+00 2.2209392e-01 -7.5348941e-01 -4.3882192e-01 1.0817473e+00
+1 7.3933281e-01 1 1 9.8852238e-01 1.4290773e+00 7.6612831e-01 6.9416106e-01 5.2039038e-01 -1.3656534e-01 1.1794929e+00 5.3101130e-01
+1 8.6388010e-01 1 1 1.3537553e+00 1.0257435e+00 -1.0697467e+00 -1.1101198e+00 7.0990814e-03 1.2505291e+00 2.8673066e-01 -5.5788227e-01
+1 9.1966926e-01 1 1 1.1507944e+00 -1.3894396e+00 1.0241074e-01 1.3475400e-01 -6.6260515e-02 3.8797805e-01 -1.2085491e-01 1.3267088e+00
+1 6.8669635e-01 1 1 -1.3849127e+00 -8.5308614e-01 -3.7549594e-01 -2.7786463e-01 -1.5166842e+00 -1.1993373e+00 1.4019824e+00 -1.0302853e+00
+1 4.8279728e-01 1 1 -1.6860252e-01 4.1003260e-01 4.9940414e-01 1.4774343e+00 -2.9095339e-02 -8.0363151e-01 1.1729835e+00 4.5337908e-01
+1 1.1736056e+00 1 1 1.4007433e-02 -1.2363144e+00 -8.5011379e-01 9.0377503e-02 1.0830892e+00 -9.2802391e-01 8.4023684e-01 -1.5615092e+00
+1 1.0553011e+00 1 1 -1.9652982e-01 -2.4177785e-01 1.0100266e-01 -1.5561567e+00 1.0928504e+00 7.0959558e-01 4.0160880e-01 5.8073022e-01
+1 7.0211793e-01 1 1 -1.2628795e+00 -1.4810217e+00 1.0916839e+00 -5.6700065e-01 -1.3553267e+00 6.8718861e-01 -1.4435704e+00 -5.9562089e-01
+1 4.6485932e-01 1 1 -6.1516100e-01 -6.9362096e-01 1.0300850e+00 -1.1294827e+00 7.1300676e-01 1.0843528e+00 4.3203937e-01 -1.4860517e+00
+1 5.8157911e-01 1 1 -2.9558299e-02 7.6281228e-01 -6.7884015e-01 1.4285247e+00 1.4702921e+00 3.3855787e-01 1.0649861e+00 -4.0950146e-01
+1 2.6825701e-01 1 1 -4.1468484e-01 -2.5364528e-01 9.9815345e-01 1.1643544e+00 -5.6923949e-01 7.1782305e-01 1.5685001e+00 7.3853276e-01
+1 3.8380139e-01 1 1 -1.5556666e+00 1.2493967e-01 -1.3976796e-01 3.2303789e-01 -1.0584495e+00 7.3613141e-01 6.7690236e-01 8.7501435e-02
+1 5.4932086e-01 1 1 1.3870393e+00 1.2771309e+00 8.3119009e-01 6.2567011e-01 1.4786060e+00 5.6880189e-01 9.9100186e-01 3.7125613e-01
+1 1.0268432e+00 1 1 1.3516960e+00 1.3781573e+00 -8.5064271e-01 7.2694041e-01 9.3367118e-01 -1.3055184e-02 -9.5598124e-01 4.9883585e-01
+1 6.0317179e-01 1 1 1.0987888e+00 -2.7276162e-01 6.3615691e-01 3.3642094e-02 -4.3724820e-02 4.9300690e-01 -1.0718220e+00 -9.7657823e-01
+1 4.2173419e-01 1 1 1.0613007e+00 -7.2093078e-01 1.0494159e+00 -6.3997527e-02 2.4963412e-01 -1.5544716e+00 -2.1968596e-01 1.4713796e+00
+1 3.1607067e-01 1 1 -6.8265559e-01 4.3921034e-01 6.3216802e-01 -1.1817571e+00 -1.5670677e+00 -5.1975669e-01 -8.9055640e-01 -1.1397135e+00
+1 9.8179284e-01 1 1 -2.9606175e-01 -9.3448906e-01 -1.8469363e-02 -6.4334373e-01 1.4060033e+00 1.2185636e+00 -1.0339836e+00 -8.7434025e-01
+1 4.6844292e-01 1 1 3.7295887e-01 -1.1360047e+00 6.0308146e-01 6.8380379e-01 -3.6302497e-01 3.5576515e-01 1.1278415e+00 1.3338311e+00
+1 4.3955592e-01 1 1 8.4243012e-01 -1.3723399e+00 1.2122049e+00 7.4436103e-01 -3.8766268e-01 8.9405167e-01 -7.3726565e-01 -7.0584191e-01
+1 8.8392617e-01 1 1 -4.3507183e-01 6.5631727e-01 2.9972431e-01 6.5388797e-01 2.1642854e-01 8.8770358e-02 -7.8234198e-01 -4.3114605e-01
+1 5.5413712e-01 1 1 1.3754933e+00 5.9250528e-01 1.4934799e+00 6.0409065e-01 -4.4989530e-01 -2.9309620e-01 -1.2563189e+00 1.3825119e+00
+1 1.1657229e+00 1 1 -1.0643151e+00 -6.1240491e-01 -4.0910076e-01 -6.7597434e-01 4.2318752e-01 -5.0524785e-02 -3.0710486e-01 6.5826265e-01
+1 6.3351334e-01 1 1 2.8472792e-01 -8.3170626e-01 1.1898483e+00 -1.1016653e+00 -5.3195175e-02 -9.4004341e-01 1.2541321e-01 -1.2690175e+00
+1 4.0123873e-01 1 1 7.7657670e-01 -1.5414439e+00 1.5428379e+00 8.5851471e-01 1.3025986e+00 -2.4006785e-01 -1.8892175e-01 -1.0520717e-01
+1 8.0808790e-01 1 1 -1.3929573e+00 -1.4750164e+00 -2.2891415e-01 -2.7838977e-01 -9.8446038e-01 -1.0153271e+00 9.4228466e-01 4.9977303e-01
+1 5.2753149e-01 1 1 -2.8506610e-01 -2.9374352e-01 1.0908190e+00 -1.0654214e+00 9.4295230e-01 5.2853008e-01 2.0965279e-01 -9.3344832e-01
+1 1.1576785e+00 1 1 -1.7718007e-01 -1.5053653e+00 -9.3931370e-01 5.4046036e-01 -1.1356068e+00 -1.4189973e+00 -1.2325307e+00 6.4778058e-01
+1 5.6238970e-01 1 1 3.6437010e-01 -1.4297406e+00 -5.4221274e-01 1.1729520e+00 -9.6796148e-01 -1.2572108e+00 5.1894289e-01 -1.5119778e+00
+1 1.7893213e-01 1 1 1.0041101e+00 3.9133548e-01 7.9070213e-01 3.1089763e-01 -1.3618091e+00 4.1096235e-01 8.1192260e-01 5.3156267e-01
+1 1.1149843e+00 1 1 -5.5699907e-01 -1.3196683e+00 3.9385682e-01 7.8789609e-01 -1.4231412e+00 -1.3180140e+00 -1.0953012e+00 -7.1564661e-01
+1 7.8077579e-01 1 1 4.6269157e-01 -2.0879533e-02 2.1589994e-01 3.5662018e-01 1.3521343e+00 -4.9156628e-01 1.0052088e+00 1.2857566e+00
+1 5.6790166e-01 1 1 1.0153525e+00 9.3607154e-01 9.0815672e-02 -4.4349166e-01 -9.5986613e-01 6.3416170e-01 -9.4119997e-01 -1.3043853e+00
+1 1.0937848e+00 1 1 -1.0223609e-01 -5.4164627e-01 -4.7503842e-01 1.2350900e+00 -3.9172489e-01 -1.0681207e+00 -8.2885876e-01 -7.6972982e-01
+1 8.4585819e-01 1 1 1.6918006e-01 8.8670295e-01 -1.1837227e+00 -1.4861410e+00 1.0580435e+00 -8.4453132e-01 -8.0728127e-01 2.2945740e-01
+1 1.7374767e-01 1 1 2.6784852e-01 -8.9898411e-01 8.7889943e-01 1.2312600e+00 1.1229111e+00 -3.2226862e-01 5.6229314e-01 -1.3852640e+00
+1 1.2727038e+00 1 1 -1.7224124e-01 -1.3068877e+00 -1.0594435e-01 1.1610142e-01 1.2193779e+00 -2.6297539e-01 5.5016296e-01 2.1172158e-01
+1 2.2811134e-01 1 1 -1.4517327e+00 1.1548226e+00 6.7630159e-01 3.8761116e-01 1.4757476e+00 3.9356627e-01 8.8172143e-01 -1.0198965e+00
+1 6.2970729e-01 1 1 1.4791968e+00 3.4409948e-01 3.1867557e-01 -1.0823674e+00 1.6112130e-02 -1.5257594e+00 1.9958852e-01 -8.7053320e-01
+1 1.0551962e+00 1 1 1.4378944e+00 -3.9214594e-01 -4.3519950e-01 -1.5272994e+00 6.1959877e-01 1.3833758e+00 -7.3667656e-01 -6.5457890e-01
+1 8.3231388e-01 1 1 1.5596576e+00 2.6462080e-01 -7.7033559e-01 6.3288277e-01 -7.8307659e-01 -5.2981470e-01 -3.0636957e-01 3.4986262e-01
+1 7.2047510e-01 1 1 -2.8303531e-01 -1.0134731e+00 -5.2685899e-01 -5.7196986e-01 -1.0366642e+00 -1.3221136e+00 -8.3078803e-02 -9.2031064e-01
+1 5.7202898e-01 1 1 -6.0315089e-01 2.7246141e-01 1.2306952e+00 1.7604093e-01 5.6829225e-02 -2.7800838e-01 -1.4382954e+00 1.5413601e+00
+1 9.2932476e-01 1 1 7.6254994e-01 -1.1832012e+00 4.8941466e-02 -6.6042504e-01 8.4609774e-02 -9.3858401e-01 1.1238826e+00 6.6977587e-02
+1 8.9359085e-01 1 1 -1.5212130e+00 2.1967784e-01 -5.3806055e-01 -5.1675900e-01 -1.1049993e+00 -8.4480021e-01 -1.3022184e+00 1.0021300e+00
+1 4.5106520e-01 1 1 -7.4507525e-01 7.5414626e-01 1.4615727e+00 1.3352130e+00 1.3721436e+00 1.4416300e+00 1.0906691e+00 7.2001072e-01
+1 1.9352863e-01 1 1 -9.1388537e-02 -1.3902220e+00 5.3961984e-01 5.2777044e-01 -8.1465510e-01 1.5130064e+00 -3.1823525e-01 -1.9479219e-01
+1 8.7770859e-01 1 1 2.7166501e-01 -1.4367466e+00 -3.8741292e-01 1.5217094e+00 -8.4747713e-01 1.0474844e+00 1.5523627e+00 -3.3285436e-01
+1 5.9824258e-01 1 1 1.1397505e+00 -1.1192017e+00 1.2726441e+00 -3.3510489e-01 4.3299558e-01 -4.1410152e-01 -3.6664231e-01 8.9328050e-01
+1 5.1474026e-01 1 1 1.4970127e+00 1.4338041e+00 1.3662829e+00 7.6778771e-01 1.4281193e+00 -1.1765188e+00 -1.4941583e+00 -3.0596157e-01
+1 4.8626831e-01 1 1 -7.2283932e-01 -1.2116087e+00 1.2156972e+00 -1.4545255e+00 6.3278600e-01 -5.6814911e-01 -1.5679241e+00 4.9102552e-01
+1 1.1418028e+00 1 1 -2.2160465e-01 2.9601265e-01 -6.9510605e-01 -1.4780275e+00 9.4322444e-01 1.5595817e+00 -4.2147772e-01 -2.9801677e-01
+1 6.6506864e-01 1 1 1.4194627e+00 -1.1981075e+00 9.3569394e-01 -6.3494837e-01 2.9664637e-01 -1.5602453e+00 5.1537381e-01 -1.0691410e+00
+1 9.6956462e-01 1 1 -3.4488323e-01 1.0168584e+00 -6.0482724e-01 4.1298508e-01 2.8046959e-02 -1.6943167e-01 5.1675756e-01 8.5666179e-01
+1 7.5647262e-01 1 1 -2.1406105e-01 7.5004892e-02 8.6243616e-01 1.2619845e+00 1.4634805e-01 -1.3550932e+00 -1.3593331e+00 -4.3478108e-03
+1 4.4981860e-01 1 1 -6.0052656e-01 8.2856217e-01 -3.4400196e-01 1.2812507e+00 -1.9543489e-01 1.4954923e+00 -6.4894220e-01 -8.1702542e-01
+1 1.2607316e+00 1 1 8.8732139e-01 -1.0358005e+00 -1.1103859e+00 1.5050347e+00 1.4317410e+00 -1.1437893e+00 8.3818875e-01 1.5524544e-01
+1 8.1910982e-01 1 1 7.0356332e-02 -1.1338790e+00 -1.1958800e+00 -9.8642108e-01 -1.3285739e+00 -2.6069839e-01 5.3685980e-01 -1.4533955e+00
+1 3.7211522e-01 1 1 1.2400354e+00 -2.0267105e-01 7.5458544e-01 -5.9461995e-01 1.0996875e+00 9.6396560e-01 3.4854613e-01 -1.3358151e+00
+1 1.0448773e+00 1 1 -5.0524761e-02 -8.0583742e-01 -2.9211391e-01 -3.7126131e-01 4.5785929e-01 1.7659340e-01 -1.0554870e+00 -1.2226433e+00
+1 7.4465620e-01 1 1 -9.3965001e-01 -3.0360514e-01 7.5075341e-01 -5.8582560e-01 1.4807251e+00 -7.9979810e-01 1.0043743e+00 1.9240083e-01
+1 3.7805981e-01 1 1 8.8557229e-02 -7.4515312e-01 1.2764686e+00 -2.1940866e-01 -1.1494854e+00 6.6834417e-01 7.4086010e-01 9.8191372e-01
+1 1.2914766e+00 1 1 -7.3357289e-01 -1.4002178e+00 -3.2924363e-01 6.2836687e-01 1.3939564e+00 -1.4748403e+00 1.5040960e+00 2.3768786e-01
+1 1.2155871e+00 1 1 -1.5499410e+00 2.1028320e-01 -1.2530494e+00 -1.0724916e+00 1.3689257e+00 -4.7448865e-01 -1.0537940e+00 -1.2860156e+00
+1 5.3489076e-01 1 1 2.2806373e-01 -6.1943472e-02 1.2366343e+00 1.0927250e+00 -1.4899475e+00 -1.3686314e+00 1.1832093e+00 9.2999502e-02
+1 1.0562870e+00 1 1 3.2410042e-01 -1.2167659e+00 -6.6358269e-01 -3.2098549e-01 8.6707486e-02 1.5396566e-01 -8.3341464e-02 -1.4705036e+00
+1 9.1770555e-01 1 1 -3.6590997e-01 -1.5571895e+00 -1.8033469e-01 -6.8856080e-01 -4.0627491e-01 -9.7152987e-01 4.3034493e-01 1.5553833e-01
+1 2.3852559e-01 1 1 1.3895220e+00 9.2379924e-01 7.5171462e-01 9.8605097e-01 1.5599719e+00 1.4960270e+00 8.6090000e-01 3.2762797e-01
+1 5.9118136e-01 1 1 -9.0392390e-01 5.4292591e-01 -1.4179763e+00 6.5737495e-01 -1.2845812e+00 1.5597688e+00 -1.0294617e+00 -7.6855608e-01
+1 7.2358960e-01 1 1 4.9306126e-01 -1.3709536e+00 1.9469562e-01 -4.8065534e-01 -9.3192921e-01 -1.5559221e+00 -1.4118807e+00 1.1070257e+00
+1 1.0714481e+00 1 1 -6.4075969e-01 -1.1762539e+00 -1.2902493e+00 -1.3396044e+00 1.0467741e+00 2.3412203e-01 -1.0295182e+00 1.2696919e+00
+1 5.0740434e-01 1 1 1.3144199e-01 7.4333141e-01 1.1941618e+00 1.0630022e+00 2.1338206e-01 -1.5267199e+00 7.7931585e-01 -1.1273444e+00
+1 9.8804130e-01 1 1 6.0590091e-01 -9.4293574e-01 -1.3582638e+00 -3.5964086e-01 -1.3865791e+00 9.4800529e-01 6.6171769e-01 -3.3189939e-01
+1 8.0033385e-01 1 1 1.4748084e+00 1.4139592e+00 -1.5271504e+00 -5.9694085e-02 9.9411411e-02 -1.0330178e+00 2.5113833e-01 1.2354653e+00
+1 5.4281878e-01 1 1 -6.0751501e-02 1.4055840e+00 -4.8658345e-03 -1.1104266e+00 -5.1970762e-01 -1.4892763e+00 -1.4186430e+00 -1.4622013e+00
+1 7.3513284e-01 1 1 -3.2864806e-02 -1.1267954e+00 -9.8671464e-02 1.2628997e+00 -1.0984460e+00 -1.1987067e+00 1.5555435e+00 1.4618984e+00
+1 7.6927551e-01 1 1 5.6150422e-01 -5.3047858e-01 3.8962440e-01 9.5591590e-01 1.5583698e+00 3.7029956e-01 -3.1402234e-01 -2.6953074e-01
+1 6.3940733e-01 1 1 -1.4286166e-01 8.6384449e-02 1.3382073e+00 -2.6343590e-02 6.3698745e-02 1.2958048e-01 1.0225799e-01 1.7348336e-01
+1 4.9108021e-01 1 1 -8.9909683e-01 4.4762448e-01 5.8789368e-01 2.0784333e-01 -6.9827929e-01 7.3539434e-01 1.9879294e-01 3.3681872e-01
+1 9.7855433e-01 1 1 -5.9743717e-02 -8.8973024e-01 4.2019180e-01 -2.2819779e-01 1.0101655e+00 7.4724826e-01 -1.5416470e+00 -2.3774822e-01
+1 9.4117690e-01 1 1 1.1969940e+00 2.8486063e-01 -1.3670090e-01 5.6433993e-01 6.8533638e-01 -1.0858749e+00 1.3951124e+00 2.7144675e-01
+1 7.8049366e-01 1 1 -8.8135768e-01 -1.3453311e-01 -1.0278743e+00 3.9302929e-01 1.3699508e+00 -7.8721766e-01 -1.1938830e+00 6.1294797e-01
+1 4.4004617e-01 1 1 -3.6910142e-01 8.4865382e-01 1.3452668e-01 -1.1260072e+00 3.0139321e-02 -1.5205979e+00 -2.3991669e-01 5.3426168e-01
+1 8.4365459e-01 1 1 1.1579559e+00 4.9409150e-01 -9.5676402e-01 1.5170305e-01 7.5515683e-01 1.6805871e-01 1.5252011e+00 6.6428010e-01
+1 7.2655044e-01 1 1 -4.0182571e-01 9.6641526e-01 1.4799142e+00 -1.3000397e+00 -1.1345071e-01 2.7092223e-01 -1.3406061e+00 -6.6467241e-01
+1 5.2387484e-01 1 1 9.3948648e-01 5.0723817e-01 9.2921643e-01 9.6893797e-03 1.8061619e-01 1.2221837e+00 -6.4573590e-02 3.5429108e-01
+1 8.3299117e-01 1 1 3.0454810e-01 -1.1305828e+00 4.8352570e-01 -5.1341341e-01 8.3782327e-01 1.5078455e+00 -1.4388537e+00 1.2521738e+00
+1 9.6775268e-01 1 1 8.8547648e-01 -1.3535526e+00 -6.8382169e-01 1.0158235e+00 6.7740890e-01 -8.6826774e-01 1.1660130e+00 -2.4451749e-01
+1 8.9313507e-01 1 1 4.7884145e-01 -8.8655920e-01 -1.0451862e+00 1.5306450e+00 7.9588706e-02 -2.7809932e-01 -7.4427990e-02 -4.0226704e-01
+1 7.2104059e-01 1 1 -8.7208100e-01 1.7355732e-01 1.3415325e+00 -9.5175592e-01 -6.7109420e-01 6.7451678e-01 -5.5735251e-01 -1.9481407e-01
+1 9.3371790e-01 1 1 -1.5356057e+00 -1.5616910e+00 -7.3529230e-02 8.2806759e-01 -7.6264103e-01 -1.4044363e+00 8.0569220e-01 -7.0053231e-01
+1 6.5375166e-01 1 1 -7.4195284e-01 6.6543749e-01 -1.1598596e+00 7.6490617e-02 -9.7376384e-03 1.5658499e+00 1.0044693e+00 8.4275146e-01
+1 7.6369997e-01 1 1 -1.0201446e+00 -6.1940521e-02 -1.7743333e-01 6.6640056e-01 -2.9767126e-01 1.1782147e-01 -8.0413396e-01 -1.3175170e+00
+1 9.1744559e-01 1 1 1.2420374e+00 -1.1671733e+00 -7.5058442e-01 4.1643313e-01 -1.5453555e+00 1.0220973e+00 5.2086056e-02 -1.5638047e+00
+1 7.2147967e-01 1 1 -9.6029917e-01 -5.7789641e-01 1.5636801e+00 -4.7675814e-01 -1.2427764e+00 1.6150966e-01 -1.0939999e+00 -3.0200113e-01
+1 3.6121000e-01 1 1 -1.3867386e+00 1.0995238e+00 1.3487589e+00 1.3287930e+00 1.1071017e+00 1.5673666e-01 8.8465298e-01 1.0807377e+00
+1 8.4889177e-01 1 1 5.6054970e-01 8.4865342e-01 -1.1421552e+00 -5.5877181e-01 -5.9442028e-01 -1.5231582e+00 -7.9545068e-01 -7.3044214e-01
+1 8.4561937e-01 1 1 -4.7757193e-01 4.8735459e-01 -1.0711074e+00 -1.0574525e+00 -1.5703663e-01 1.1186113e+00 1.4787679e+00 8.0311675e-01
+1 6.8057215e-01 1 1 2.1783403e-01 8.3649799e-01 -7.7559601e-01 -6.1389339e-01 -3.7674472e-01 1.2088516e+00 5.1280683e-01 -1.4404835e+00
+1 4.4161218e-01 1 1 1.1811210e+00 3.9458605e-01 -9.7423103e-01 -7.1596541e-01 1.5022002e+00 4.8983396e-01 1.3558069e+00 -1.0937447e+00
+1 5.5865691e-01 1 1 -6.2333050e-01 -9.4284991e-02 8.0030778e-02 -9.3073192e-01 -1.5019292e+00 -1.4750580e+00 1.0744053e+00 -1.1080301e+00
+1 2.5777771e-01 1 1 8.9584300e-01 -1.2851383e+00 4.7562291e-01 -8.2161656e-01 -2.2688342e-01 -9.9172678e-01 -3.4499406e-01 6.9859268e-01
+1 9.2263555e-01 1 1 -1.2202725e+00 -8.7027649e-01 -1.5590032e+00 1.5317442e+00 6.6391390e-01 1.3386248e+00 1.0648988e+00 1.1153747e+00
+1 9.4588855e-01 1 1 -8.0284721e-01 5.1842615e-01 -1.2843210e+00 -1.3268841e+00 -5.3622024e-01 1.3226512e+00 1.0105839e-01 2.1960442e-01
+1 9.6083356e-01 1 1 -3.1259670e-01 1.5518396e+00 2.9959353e-01 1.2249468e+00 9.7568688e-01 -1.1114670e-01 -1.1132078e+00 -4.7983936e-01
+1 6.0029567e-01 1 1 -1.0698255e+00 2.6577916e-01 -7.0454778e-01 8.2482285e-01 -7.4419056e-01 1.2051177e+00 -1.4985362e+00 -1.9174000e-01
+1 9.0814870e-01 1 1 -1.2224248e+00 -3.9448906e-01 -6.7188441e-01 -1.0507157e+00 -9.3040050e-01 5.6539983e-01 2.5094456e-01 6.9981812e-01
+1 1.2838719e+00 1 1 7.2205553e-01 -1.4171475e+00 -1.4773270e+00 -4.8714788e-01 -1.5345080e+00 -6.4278328e-01 -1.5337318e+00 -2.7983404e-01
+1 4.2692948e-01 1 1 -3.8519243e-01 1.5581166e+00 -1.4286173e+00 -5.0395939e-01 -1.1418158e+00 6.7860343e-01 -6.6302004e-01 -2.0645673e-01
+1 6.9375399e-01 1 1 8.9328657e-01 -1.0509116e+00 4.2226595e-01 -3.1168240e-01 1.4909798e+00 1.3065175e+00 -1.4860498e-01 1.5415466e+00
+1 6.9988539e-01 1 1 -2.0389984e-01 -6.3656054e-01 1.6599644e-01 -1.4111175e+00 1.5538324e+00 -1.0935428e+00 -3.7774700e-02 5.9769369e-02
+1 7.1294643e-01 1 1 5.3299274e-01 -1.5499306e+00 1.6792264e-01 -7.6839350e-01 -7.9884585e-01 -8.5756383e-01 -2.7767417e-01 -7.6585631e-01
+1 3.2940560e-01 1 1 1.3283620e+00 4.0342010e-01 1.1256780e+00 6.9784033e-01 9.6487042e-01 5.5173023e-01 1.5369068e+00 -6.4195319e-01
+1 3.5052410e-01 1 1 -1.5193388e+00 7.2466931e-01 5.9971663e-01 1.0370071e+00 -3.2412239e-01 -1.0515387e+00 6.1726637e-01 -1.0781528e+00
+1 2.5846990e-01 1 1 -6.6134793e-01 -4.3767056e-01 1.2080998e+00 -5.7737449e-01 -3.3907362e-03 1.3889057e+00 8.5692328e-01 1.9312774e-01
+1 1.3908578e-01 1 1 -3.1981885e-01 -1.4607166e+00 4.1940804e-01 4.4662115e-01 -4.3943496e-01 1.3048158e+00 1.2487625e+00 6.3275797e-01
+1 8.9490412e-01 1 1 6.9538015e-02 1.2824274e+00 -7.4300624e-01 1.0967981e+00 3.0092859e-01 -1.4190163e+00 -1.0284077e+00 4.7213246e-01
+1 7.6554398e-01 1 1 5.2954304e-02 -7.1042981e-01 1.2485999e-01 -9.8048260e-01 -2.5738366e-01 1.5645508e+00 5.9407510e-01 -5.3279951e-01
+1 7.4795997e-01 1 1 9.3226907e-01 9.9978892e-01 -6.2063610e-02 -1.3176429e+00 1.2583403e-01 2.7415175e-01 6.3868484e-01 -1.2222229e+00
+1 3.7530538e-01 1 1 1.5236973e+00 -9.2676986e-01 -9.4328512e-02 -5.3703643e-01 6.0061618e-01 -1.0479348e+00 -4.4596581e-01 9.7407084e-01
+1 8.7450169e-01 1 1 -1.4830070e+00 -2.0473547e-01 1.1249832e+00 -1.7561975e-01 6.1889441e-01 -8.7143529e-01 4.9268235e-01 3.6920727e-01
+1 3.7853167e-01 1 1 4.9826772e-01 -9.4505405e-01 1.4884399e+00 1.4559131e+00 -5.4957343e-02 -1.0795869e-01 -7.2602003e-01 6.2117854e-01
+1 8.3638677e-01 1 1 -1.1004856e+00 3.6907071e-01 -2.9315814e-01 -3.3396413e-01 -3.9828680e-02 1.3788791e+00 -2.7274940e-01 6.3540325e-01
+1 1.0260341e+00 1 1 -1.3053657e+00 1.4674517e+00 -1.0915741e+00 1.0909132e+00 -2.4138691e-01 -7.0745646e-01 -5.1540584e-01 9.4896895e-01
+1 7.6760472e-01 1 1 -1.5397084e+00 -1.1825557e+00 8.1457451e-01 6.4398318e-01 -1.1936049e+00 7.0742914e-01 -1.0550219e+00 -5.4473548e-01
+1 1.2692030e+00 1 1 -5.8086416e-01 -1.4991115e+00 -5.0693691e-01 6.3860977e-01 1.2929721e+00 -1.1666455e+00 -6.0497298e-01 -7.6829776e-01
+1 5.7023059e-01 1 1 1.4860282e+00 6.8792340e-03 -8.9297974e-02 1.4338576e+00 5.8651273e-01 -1.1307043e+00 1.5546210e+00 -8.3471258e-01
+1 6.3243422e-01 1 1 1.4703755e-02 -6.1964192e-01 8.5023146e-01 -3.1223117e-01 -7.9822562e-01 -2.5348969e-01 -1.1150088e-01 1.3383853e+00
+1 8.2600181e-01 1 1 -1.0598053e+00 5.7875236e-02 -1.2647712e+00 -1.2095878e+00 -1.1773853e+00 -4.0157615e-01 1.5354559e+00 4.3891530e-01
+1 1.2798435e+00 1 1 6.8326166e-01 -1.1846343e+00 -9.9361586e-01 -2.9621724e-01 5.7692511e-01 -1.1494066e+00 1.3651704e+00 3.8986304e-01
+1 3.2872345e-01 1 1 1.0576398e+00 1.2658499e+00 1.0047959e+00 9.0117122e-01 1.4254656e+00 -4.2366124e-01 1.3673272e+00 -9.3408221e-01
+1 3.4528729e-01 1 1 6.2104414e-01 2.7465936e-01 1.5436014e+00 3.6647338e-01 1.4621917e-02 1.5160023e+00 -8.1945107e-02 -5.8127514e-01
+1 8.2514173e-01 1 1 1.5180164e+00 1.2002918e+00 3.6513355e-02 -1.3451790e+00 7.0632666e-01 1.1345062e+00 -1.2338281e+00 8.6191340e-01
+1 7.7894454e-01 1 1 4.2801925e-01 1.1373583e+00 1.0693885e+00 -1.5226955e+00 -8.4651899e-01 1.3191663e+00 7.0482706e-01 2.9486138e-01
+1 8.5957331e-01 1 1 -5.2771431e-01 -1.0104696e+00 1.6146808e-01 -5.2919047e-01 8.2851015e-01 1.0080706e+00 -9.1749382e-01 1.4435281e+00
+1 1.1807550e+00 1 1 -5.7829612e-01 4.8674680e-01 -5.4205797e-01 -2.5535839e-01 1.2315182e+00 3.3991632e-02 -1.3818123e+00 -1.1437669e+00
+1 6.0464309e-01 1 1 6.6475551e-01 4.6128242e-02 2.5034368e-01 -3.9290454e-01 1.3144559e+00 -4.7249863e-01 -1.4665856e+00 1.1514253e-01
+1 6.3775660e-01 1 1 1.0424376e+00 -6.9602067e-01 9.3369049e-01 8.1216401e-02 3.8151875e-01 6.6171883e-01 3.2588646e-02 -2.0516679e-02
+1 4.0796470e-01 1 1 -4.1295684e-01 1.2717242e+00 2.8082707e-01 1.5528398e+00 1.9510248e-01 2.7036557e-01 1.0802449e+00 7.5136371e-01
+1 5.4336781e-01 1 1 -7.8737653e-01 -1.5272281e+00 1.1883530e+00 1.3687677e+00 -7.3534763e-01 1.2911388e+00 4.1172249e-01 -1.0325380e+00
+1 8.1871524e-01 1 1 -1.0490100e+00 -1.3110151e+00 1.5439038e+00 -1.0047875e+00 3.7896844e-02 1.1891143e+00 -1.1086700e+00 2.9132504e-01
+1 7.4045735e-01 1 1 -9.2780915e-02 9.0060781e-01 -1.1646320e+00 -1.4029377e+00 -8.1105404e-01 -1.3683309e+00 -6.3141834e-01 -1.4430404e+00
+1 7.0276358e-01 1 1 -1.1388773e+00 3.2198287e-01 1.2942715e+00 -1.5203317e+00 -1.4662382e-02 -1.0790448e+00 5.1866860e-02 -8.4920311e-02
+1 6.8356529e-01 1 1 6.1341851e-01 -1.3979885e+00 4.3310834e-01 1.5005859e+00 -1.3864350e+00 9.0905586e-01 1.5051526e+00 -9.7259576e-01
+1 5.4682723e-01 1 1 -9.8221946e-01 -2.1427786e-02 1.8166377e-01 -3.5811691e-01 -6.1984398e-01 9.3672365e-01 9.9622214e-01 -7.1041334e-01
+1 8.3394708e-01 1 1 9.0698052e-01 1.1463543e+00 -4.0508783e-01 4.2068328e-01 -1.9647586e-01 9.9364382e-01 -1.1832837e+00 1.2766169e+00
+1 4.8733601e-01 1 1 6.1408603e-01 -6.1154372e-01 -4.7984117e-01 -1.3011908e+00 -3.5595364e-01 -5.3481031e-01 -1.1680765e+00 -9.7717137e-01
+1 6.4036889e-01 1 1 8.1212205e-01 1.0758800e+00 -2.2212986e-01 -4.8680094e-01 -9.2035589e-01 -4.6031630e-01 -4.9593708e-02 9.2725135e-01
+1 1.3371871e+00 1 1 -8.8481381e-01 -6.9160932e-01 -1.1245240e+00 -9.5612748e-01 7.8070396e-01 1.2067209e+00 -9.9939322e-01 -1.1277838e+00
+1 5.7811009e-01 1 1 1.2339441e+00 1.4895828e-02 -5.4199302e-02 -3.8807060e-01 -1.1411275e+00 -7.6380042e-01 1.2940953e+00 -1.4331792e+00
+1 9.2946567e-01 1 1 1.2453364e+00 -9.7323766e-01 1.3420797e-01 -3.5620055e-01 4.9365456e-01 -6.4608032e-01 6.1365677e-01 -8.5268082e-01
+1 8.2344278e-01 1 1 1.0783571e+00 1.0676558e+00 -3.0209259e-02 1.2129664e+00 -9.4074322e-02 -1.3276714e+00 -1.1938274e-01 9.3906847e-01
+1 3.9919645e-01 1 1 9.9210680e-02 -6.8540290e-01 1.2109925e+00 5.3119681e-01 -8.8601741e-01 5.5968124e-01 1.0119214e+00 -4.3773311e-01
+1 9.9804293e-01 1 1 -7.5180725e-01 6.5378191e-01 -1.2281280e+00 -5.8156396e-01 -1.4545029e-01 6.3416197e-01 -1.2193329e+00 6.2964756e-01
+1 9.2769719e-01 1 1 -1.3876636e-01 -1.1785106e+00 -8.8319625e-01 -8.5068375e-01 -4.2396363e-01 -1.0637196e+00 -7.1976300e-01 -1.5391377e+00
+1 2.2945316e-01 1 1 -1.1844741e+00 5.1412955e-01 1.4594491e-01 -5.3540435e-02 -4.2454336e-01 8.6846630e-01 1.2165610e+00 -4.1370780e-01
+1 1.1335824e+00 1 1 8.1594804e-01 -1.5460890e+00 -6.8783573e-01 -1.3585998e+00 -7.4332938e-01 4.7366228e-01 1.2554342e+00 -8.4241081e-01
+1 6.6237451e-01 1 1 5.8679850e-01 -1.0051239e+00 6.0584151e-01 -8.9116793e-01 9.7708745e-01 4.6074439e-02 1.1462643e+00 7.5952537e-01
+1 2.0426624e-01 1 1 8.6303332e-01 -7.7312659e-01 4.7641798e-01 1.2543451e+00 8.0396666e-01 1.5413016e+00 1.0185960e+00 1.0518656e+00
+1 8.9029331e-01 1 1 2.6774132e-01 -3.1133856e-01 -7.6266291e-01 -1.4508185e+00 2.7765789e-01 -9.1725060e-01 1.0053496e+00 9.6325536e-01
+1 1.0094154e+00 1 1 1.1676459e+00 1.2262067e+00 -3.7753852e-01 1.1363804e+00 1.3311034e+00 -4.3564936e-01 1.4259143e+00 8.0584726e-01
+1 2.9356586e-01 1 1 -9.0521981e-01 7.9311321e-03 7.2720161e-01 1.4039017e+00 5.7349568e-01 1.0937111e+00 1.2729160e+00 4.6895449e-01
+1 8.3183209e-01 1 1 7.0385233e-01 1.3516458e+00 1.2820317e+00 -1.1271515e+00 3.3556226e-01 5.4417042e-01 -3.4613002e-01 -5.3779395e-01
+1 7.3386167e-01 1 1 1.5498384e+00 2.5492928e-01 -1.0772881e+00 -2.3153833e-01 6.3613677e-01 6.9597448e-01 8.2241952e-01 -3.4087875e-01
+1 1.0890726e+00 1 1 1.1901338e+00 -5.3596942e-01 -9.8238551e-01 9.6860465e-01 7.1094764e-01 1.0936239e+00 -6.0275561e-01 1.1158999e+00
+1 5.0653371e-01 1 1 5.8594829e-02 -1.0918890e+00 1.2576482e+00 -3.9481999e-01 1.4201059e+00 -9.2167310e-01 1.1226959e+00 -3.7891121e-01
+1 7.7906007e-01 1 1 1.4847925e+00 -1.3364873e+00 6.5847699e-01 -6.9592094e-01 1.0406704e+00 6.3360281e-01 7.4428236e-01 -3.5237153e-01
+1 8.5873012e-01 1 1 1.2378017e+00 4.5117271e-02 -8.0808424e-01 -1.9385297e-01 1.3014071e+00 -1.0366858e+00 -6.6834133e-01 -4.0616751e-01
+1 9.5489507e-01 1 1 1.0604755e-01 1.1621375e+00 -3.6684297e-01 -2.5530229e-01 9.8038612e-01 -3.0455438e-01 1.5225887e+00 2.2357618e-01
+1 6.3528835e-01 1 1 1.0581086e+00 7.6415861e-01 1.4165149e+00 5.5004163e-01 -3.0396097e-01 -9.9110337e-01 -1.2647455e+00 3.0005530e-01
+1 4.2857941e-01 1 1 -9.2464667e-01 3.8291453e-01 3.7763073e-01 -1.1574725e+00 -4.4232808e-01 -7.5007985e-01 -5.6176515e-01 7.7318767e-01
+1 3.6843010e-01 1 1 9.2224991e-01 -1.4788317e+00 8.2253365e-01 -8.9850879e-01 -1.1998158e+00 6.1929542e-01 -1.1009793e+00 1.3379552e+00
+1 4.3198841e-01 1 1 -3.6391755e-01 1.5574450e+00 1.3153952e+00 3.9867338e-01 5.7936537e-01 4.0159527e-01 -1.7837141e-01 -5.0739103e-01
+1 4.3661018e-01 1 1 3.1855346e-01 2.2742149e-01 4.5983303e-01 -5.1368747e-01 -1.5434801e+00 1.4706392e+00 -8.0883550e-01 -1.4385404e+00
+1 6.8190884e-01 1 1 6.5414339e-01 -1.0452011e+00 9.5875616e-02 -4.4866359e-01 -1.1387154e+00 -1.0176949e+00 -4.2677013e-01 1.4880500e-01
+1 4.2483446e-01 1 1 -1.3864042e+00 1.0920701e+00 -2.5556158e-01 -8.6664023e-01 1.9302132e-01 -1.5677303e+00 -4.6952500e-01 2.5787574e-01
+1 6.6371034e-01 1 1 -1.0284757e-01 1.2384046e+00 -6.6628618e-01 -1.1988068e+00 -1.1559409e+00 -3.0520870e-01 3.7415357e-01 -1.2802923e+00
+1 7.2293446e-01 1 1 -6.8319877e-01 8.1432042e-01 1.5060205e+00 -1.3117152e+00 -2.8985967e-01 5.7821995e-01 -1.0694800e+00 -1.1043814e+00
+1 4.4547909e-01 1 1 -6.0873557e-04 1.5057111e+00 -1.2605969e-01 -1.4414888e+00 9.3877161e-01 1.1966029e+00 1.4428551e+00 -8.0800115e-01
+1 9.5981705e-01 1 1 -8.0624083e-01 9.5721430e-01 -1.2517074e+00 8.6077103e-01 8.5610620e-01 -1.1715283e+00 1.1125742e-01 1.0297136e+00
+1 1.1375746e+00 1 1 -8.0045628e-01 -1.9531172e-01 -1.3413735e+00 -5.5506833e-02 8.2629789e-02 -1.5144774e+00 6.5581856e-01 -6.3693515e-01
+1 1.0275553e+00 1 1 -9.6893389e-01 3.6017471e-01 -3.9545240e-01 1.4967781e-01 1.7491176e-01 -6.3802414e-01 -1.5060832e+00 -1.5629289e+00
+1 4.2630380e-01 1 1 1.1444202e+00 -3.9262567e-01 1.2416458e+00 -7.8073563e-01 -7.8872108e-01 -1.0159112e+00 -9.2794715e-01 -1.2902086e+00
+1 1.3516110e+00 1 1 1.4402845e+00 -1.5151200e+00 -1.2585344e+00 6.0878862e-01 1.4858718e+00 1.3716245e-01 -1.1418787e+00 -1.2635853e+00
+1 1.0618541e+00 1 1 8.9063343e-01 1.1278252e+00 1.5584935e-01 -2.5693897e-01 5.2727860e-01 -6.3964640e-01 4.3360447e-01 8.8444744e-02
+1 1.0763400e+00 1 1 -8.1296664e-01 -1.0121758e+00 -7.2820662e-01 1.3166853e+00 -4.6144181e-01 -6.9108506e-03 -9.0471236e-01 5.1748044e-01
+1 8.7239659e-01 1 1 -7.4382997e-01 8.4708604e-02 6.7629503e-01 1.5086502e-01 1.1397947e+00 8.8261968e-02 -1.9214461e-01 1.3652430e+00
+1 3.6068333e-01 1 1 -1.1532186e+00 5.5604248e-01 2.0827875e-01 3.2308470e-01 -9.0273300e-01 5.8716489e-01 1.8285460e-01 -5.5365531e-01
+1 2.6429697e-01 1 1 1.4819634e+00 -8.3214364e-01 8.0677021e-01 1.4124872e+00 -1.4826528e+00 7.3782667e-01 7.5958598e-01 1.1269094e-01
+1 7.5858141e-01 1 1 8.1299597e-01 5.3230756e-01 2.7299784e-01 -1.3441283e+00 1.6726567e-01 7.8670606e-01 -1.0709292e+00 -3.8366581e-01
+1 5.5294619e-01 1 1 1.2368784e+00 -7.6277240e-01 1.5494437e+00 4.2921750e-01 -4.9131554e-01 -7.9470275e-01 -9.2236154e-01 1.4184373e+00
+1 5.6300937e-01 1 1 2.9639830e-01 9.2389411e-01 8.3832295e-01 7.6183822e-01 -1.4347419e+00 1.4828328e+00 -1.5122382e+00 1.2713609e+00
+1 1.2443745e+00 1 1 -9.9964736e-01 -1.0042564e+00 -3.4924476e-01 -9.1671847e-01 1.1574637e+00 -2.8361675e-01 -7.0327935e-01 -1.3508800e+00
+1 5.9320344e-01 1 1 1.6433924e-01 1.2395457e+00 -1.2616535e+00 -9.1690833e-01 7.5086227e-01 -9.5070401e-01 -1.3443997e+00 5.0575469e-02
+1 6.0807545e-01 1 1 5.8968074e-01 1.1432731e+00 1.1393121e+00 -9.6627540e-01 -3.5561185e-02 -3.4199145e-01 -9.9167634e-01 -1.3496989e+00
+1 4.8213130e-01 1 1 -9.6064586e-01 1.0106962e+00 4.1124743e-01 -1.2982884e+00 -7.7423917e-01 1.2643335e+00 -9.5529730e-01 1.0512522e+00
+1 1.5191665e-01 1 1 -9.3026772e-01 1.7875253e-01 3.3168892e-01 1.1699988e+00 -1.6093796e-01 -7.9634511e-02 9.9838863e-01 7.9109784e-02
+1 4.3594377e-01 1 1 6.9698292e-01 9.3127177e-01 1.5103749e+00 9.4138147e-01 2.7016104e-02 -9.8757626e-02 6.7138632e-01 7.0445274e-01
+1 7.7638862e-01 1 1 -8.0699651e-01 4.7010459e-01 8.0233375e-01 7.3768503e-01 -1.4712765e+00 -1.0584917e+00 -6.1088561e-01 -9.2555014e-01
+1 3.7921026e-01 1 1 -9.3485826e-01 -5.7727924e-02 1.1076137e+00 1.5477106e+00 -2.6825575e-01 7.6923887e-01 -4.2961475e-01 1.4456106e+00
+1 7.8026111e-01 1 1 -1.0578581e+00 5.1890537e-01 -1.4138279e+00 -1.4719429e-02 -3.8888100e-01 9.4395764e-01 -1.1551524e+00 -7.0070086e-01
+1 6.7308773e-01 1 1 -1.1477729e+00 1.8133304e-01 8.0141803e-01 7.9637732e-01 -1.4102891e+00 5.3191275e-02 3.9645263e-01 1.1514487e+00
+1 6.4638383e-01 1 1 -1.2410530e+00 3.1950714e-01 1.4250561e+00 1.5288526e+00 5.8693825e-01 -1.3681483e+00 -1.3868190e-01 1.8770081e-01
+1 1.0797595e+00 1 1 -1.3442654e+00 9.7474057e-01 -5.8500398e-01 3.3904318e-01 7.0311188e-02 -1.1510158e+00 2.3499781e-01 5.2845618e-01
+1 6.4579114e-01 1 1 1.2657296e+00 -9.4099087e-01 1.0230430e+00 -5.5040049e-01 4.8129703e-01 8.0443618e-01 6.2614898e-01 4.8056974e-01
+1 8.9777082e-01 1 1 1.3927448e+00 -4.5607081e-01 3.4645890e-01 1.4093773e+00 -4.4198075e-01 -1.2559360e+00 -6.4954085e-01 -9.9119339e-02
+1 6.0556355e-01 1 1 -1.4564944e-01 3.0405161e-01 1.5635490e+00 -2.0409381e-01 1.4962228e+00 -1.5501634e-01 2.0146482e-01 -8.5463039e-01
+1 1.1705655e+00 1 1 -6.2950901e-01 -1.1758623e+00 -8.5398953e-01 4.1456004e-01 -1.4332963e+00 -9.7927668e-01 -6.1771569e-01 -4.1139470e-01
+1 7.2564102e-01 1 1 7.2618027e-01 1.0421567e+00 9.3474557e-01 -5.4192208e-01 3.2143895e-01 1.0069775e-01 1.0160486e+00 3.3467926e-01
+1 1.0349441e+00 1 1 -1.7572645e-01 1.1490066e+00 -8.3614806e-01 -6.0723965e-01 -1.1149275e+00 -8.9137316e-01 -9.6873246e-01 1.5034487e+00
+1 4.0979032e-01 1 1 -3.3738361e-01 -1.6245788e-02 -7.9654695e-01 1.1576602e+00 1.0140533e+00 9.4661501e-01 1.3881988e+00 6.3214669e-01
+1 8.1744063e-01 1 1 1.6832624e-01 2.7560308e-01 -1.2382270e+00 9.1165883e-01 5.2987761e-02 7.3333985e-01 -1.1516115e+00 -3.7697626e-01
+1 1.1446040e+00 1 1 -1.5159163e+00 1.3533513e+00 -9.7097003e-01 7.0252105e-01 1.4945798e+00 7.7495457e-01 2.1708347e-01 7.5234193e-01
+1 2.9771916e-01 1 1 3.1090534e-01 6.4504265e-01 1.4805492e+00 1.1661341e+00 -7.7213202e-01 -3.8164580e-01 1.1328236e+00 -2.9953866e-01
+1 4.3900113e-01 1 1 9.1749556e-01 -4.0445605e-01 -9.6561767e-01 -1.1814245e+00 6.9637431e-01 8.1130757e-01 1.3151221e+00 -1.5147766e+00
+1 7.4597163e-01 1 1 1.4111941e+00 7.1373513e-01 3.3139223e-01 -1.3365654e+00 1.5303346e+00 1.1341410e+00 -9.8845103e-01 6.1669684e-01
+1 1.0164071e+00 1 1 -1.0854658e+00 1.1455269e+00 -3.3455090e-01 -1.2664657e+00 1.1442992e-01 1.4644607e+00 -1.5443770e-01 7.0963342e-01
+1 1.1251361e-01 1 1 -1.9482042e-01 1.1904039e+00 6.5381330e-01 -1.1996198e+00 5.6888123e-01 -1.1873330e+00 -6.7883276e-01 1.3232120e+00
+1 9.4929194e-01 1 1 -8.0721645e-01 1.4555653e+00 -6.5101543e-01 7.3177767e-01 1.3203122e+00 -1.0994609e-01 1.1222945e+00 -1.1101162e-01
+1 8.0083122e-01 1 1 -1.4897641e+00 1.0347618e-01 5.5090762e-01 -3.4793718e-01 1.4174237e+00 -6.0753363e-01 2.8212385e-01 3.3376550e-01
+1 6.7819342e-01 1 1 2.8677394e-02 -1.3181228e+00 8.3078461e-01 -1.2762382e+00 -5.7117431e-02 -6.4155788e-01 9.9226509e-01 -1.2877301e+00
+1 9.8110503e-01 1 1 1.3172795e+00 8.2186493e-01 -1.3823340e+00 1.0584486e+00 1.3546878e+00 -7.1734295e-01 1.4254917e+00 -4.4857141e-01
+1 1.1381684e+00 1 1 7.1259780e-01 -4.9900950e-01 -8.0984728e-01 -1.4941944e+00 1.1157860e+00 1.0496825e+00 4.5325871e-01 6.8262787e-01
+1 6.5716006e-01 1 1 8.7996014e-01 1.1997118e+00 1.4177421e+00 9.6712532e-01 8.4797284e-01 -1.1712423e+00 -4.4305494e-01 -1.6971938e-01
+1 7.3989050e-01 1 1 -1.1281356e+00 8.1451537e-01 -9.8799955e-01 -1.2521204e-01 -1.5264283e+00 1.4948614e-01 -8.4982407e-01 9.2441111e-02
+1 7.2240369e-01 1 1 -1.0630097e+00 -1.5009016e+00 1.1503264e+00 4.2837297e-01 -4.3400395e-01 -8.6059091e-01 -1.3129454e+00 -1.4306106e+00
+1 8.7927635e-01 1 1 2.3365572e-01 1.3350264e+00 1.7383390e-01 -8.6587125e-01 4.7373050e-01 -5.8926443e-02 -1.2717211e-01 1.4777691e+00
+1 7.9628195e-01 1 1 6.0867641e-02 5.3370012e-01 -5.4864697e-02 -8.4090656e-01 1.1927507e+00 -7.7504828e-01 -1.0986513e+00 -5.6667626e-01
+1 2.8473774e-01 1 1 -1.1567695e+00 6.5086790e-01 1.5172828e+00 9.0876146e-01 5.7922064e-02 -1.1932422e+00 1.2484515e+00 1.1811013e+00
+1 5.9769429e-01 1 1 1.4914100e+00 1.1115779e-01 6.6377853e-01 -8.6969850e-01 -3.9759596e-01 1.1052401e+00 2.7180994e-02 -9.5454553e-01
+1 7.1255620e-01 1 1 -6.3963449e-01 -1.0185987e+00 3.3023909e-01 8.0797791e-01 -2.2766803e-01 -4.6718888e-01 1.3000278e+00 1.0669213e+00
+1 6.9103562e-01 1 1 1.9325407e-01 -1.0502706e+00 -8.6575844e-01 -1.4202823e+00 4.3323359e-02 -1.2033946e+00 -2.0946090e-01 -4.6407634e-01
+1 5.4877255e-01 1 1 -3.8569983e-01 7.1181717e-01 1.0550666e+00 -8.6400678e-01 -7.1380879e-01 1.1963777e-01 1.3160003e+00 8.4357624e-01
+1 4.0402217e-01 1 1 -1.3514240e+00 3.2639448e-01 1.3546141e+00 -9.2063537e-01 7.5807244e-01 1.3268534e-01 1.2045196e+00 -2.1858572e-02
+1 4.4864263e-01 1 1 3.3169411e-01 4.9129979e-01 -1.2324005e-01 -7.7490351e-01 -1.3762944e+00 -4.8826139e-01 -6.1390846e-02 1.8932790e-01
+1 1.0760627e+00 1 1 -1.5441051e+00 1.1701584e+00 -9.8595669e-01 1.2398151e+00 1.6682279e-01 -3.6912253e-01 -1.3535573e+00 -3.9940616e-01
+1 7.2663967e-01 1 1 9.2291873e-01 4.8201346e-01 9.2715129e-01 -6.1206914e-01 1.4899632e+00 8.0316167e-01 -9.6437789e-01 7.6414994e-01
+1 2.1039722e-01 1 1 1.4521099e+00 -9.6723048e-01 3.3223672e-01 -1.4716719e+00 1.7718762e-01 -6.8545782e-01 -8.2264005e-01 2.3721040e-01
+1 6.7046133e-01 1 1 -1.4219414e+00 1.4993246e+00 1.2924455e+00 -6.3019657e-01 -2.3749981e-01 -2.6939610e-01 3.7867369e-02 1.1416776e-01
+1 6.1216617e-01 1 1 -4.7305652e-01 4.3418755e-01 1.1604657e+00 -1.4048346e+00 1.3049191e+00 -7.0517126e-01 -1.3064382e+00 -6.9551469e-01
+1 4.1031666e-01 1 1 7.1002066e-01 -5.2959691e-01 9.3962607e-01 1.1544641e+00 3.1654951e-01 1.4156647e+00 -7.1635441e-01 3.5094333e-01
+1 5.7228940e-01 1 1 1.5483738e+00 -8.0335104e-01 -4.9082946e-01 6.0200359e-01 1.5312167e+00 -1.3466083e+00 -1.1854723e+00 1.5351495e+00
+1 5.5194965e-01 1 1 -1.4346505e+00 6.4435207e-01 4.5160926e-01 -1.1956051e+00 -7.6733930e-01 -4.1281777e-01 -2.5183151e-01 -6.4252312e-01
+1 6.6674036e-01 1 1 -4.4784292e-01 5.5532441e-01 1.0896648e-01 -9.0857917e-01 -4.3371505e-01 1.5498642e+00 -8.0688537e-01 -1.2321303e+00
+1 8.4853478e-01 1 1 3.6010013e-01 -3.3448082e-01 -1.4892198e-01 7.9175272e-01 -9.5388812e-01 -1.5183542e+00 9.3308538e-01 9.6413618e-01
+1 6.8941445e-01 1 1 1.4954837e+00 -1.3098773e+00 9.1754716e-01 -7.9850286e-01 -4.5025240e-01 1.7840934e-01 -4.6459716e-01 -9.8075078e-02
+1 4.0935358e-01 1 1 -1.2888541e+00 1.1736737e+00 -8.6323034e-01 4.4626755e-01 7.0459705e-01 1.4463095e+00 1.5148456e+00 9.8831184e-01
+1 1.0046065e+00 1 1 -4.8987771e-01 -1.2714108e-01 -4.3751223e-01 1.4369958e+00 1.4999343e+00 -1.5202847e+00 5.4281395e-01 9.5667510e-01
+1 6.3506870e-01 1 1 7.3965290e-01 -5.7705712e-01 1.2003876e+00 -9.7662499e-01 1.2562503e+00 -8.5249316e-01 -1.1099966e-01 1.6721535e-01
+1 6.5478224e-01 1 1 6.4192403e-02 -5.0255389e-01 -3.9408819e-01 6.8534939e-01 -8.4576737e-01 9.5150548e-01 5.3469262e-01 -1.3371174e+00
+1 1.0702081e+00 1 1 1.3154339e+00 1.3193339e+00 -9.6293064e-01 -1.5529873e+00 8.9451036e-01 1.2459256e+00 -1.5176799e+00 -1.1203066e+00
+1 4.4943399e-01 1 1 1.1106825e+00 6.8395717e-01 1.5100722e+00 -7.0640721e-01 1.5148234e+00 1.5568128e+00 -1.0558633e+00 -1.4283294e+00
+1 9.3377869e-01 1 1 -1.0270465e-01 1.8064468e-01 -1.1439408e+00 -5.0735413e-01 1.6972680e-01 -9.7279336e-01 9.6184659e-01 -1.0226867e+00
+1 7.2904751e-01 1 1 -1.4227141e+00 1.3165619e+00 3.3466178e-01 -8.1835123e-01 3.2265493e-02 -8.8982246e-01 -8.8014616e-01 -6.4178483e-01
+1 2.2843921e-01 1 1 -8.9360508e-01 1.2186203e+00 1.2096309e+00 -1.3655176e-01 -1.2093908e+00 -1.2650713e+00 1.1432117e+00 -1.3900218e+00
+1 2.5403882e-01 1 1 1.1338722e+00 1.3086692e+00 1.0199188e+00 1.4788464e+00 -1.2627422e-01 2.4532009e-01 -2.1280500e-02 -1.2127362e+00
+1 6.0255281e-01 1 1 8.9520457e-02 5.1240244e-01 1.2453415e+00 -1.3087940e+00 1.4258048e+00 1.3252318e+00 4.8020737e-01 1.9584444e-01
+1 3.5649165e-01 1 1 -2.5256840e-01 8.4233473e-01 1.1636503e+00 5.3174906e-01 -5.6714564e-01 -7.2175572e-01 9.3776046e-02 -8.3152501e-01
+1 2.7293955e-01 1 1 -6.2534100e-01 1.1033820e+00 1.0560992e+00 -7.2469887e-01 -4.2463546e-01 -8.5920189e-01 -9.8551181e-01 1.5047952e+00
+1 1.1328913e+00 1 1 -1.4788027e+00 -2.7969409e-01 -1.3962804e-01 -5.9164286e-02 8.5037206e-01 1.2951881e+00 -1.0205905e+00 1.2715586e+00
+1 4.6922445e-01 1 1 -1.0968035e+00 -9.9588417e-01 4.1270908e-02 1.5107150e+00 1.0981878e+00 1.3071342e-01 3.2057271e-02 -1.1690121e+00
+1 1.0212401e+00 1 1 8.8872293e-01 5.8034654e-01 -6.5182783e-01 2.3576112e-01 3.8595015e-01 9.2717470e-01 -1.5673772e+00 -6.6218541e-02
+1 5.5039488e-01 1 1 -1.5067286e+00 -7.6096194e-01 -5.3676718e-01 8.8882271e-01 -7.2468371e-01 7.2560836e-01 -6.5406110e-01 -8.1122645e-01
+1 6.2193223e-01 1 1 7.9130930e-01 -6.3645674e-02 1.2081227e+00 1.7024578e-01 1.9563353e-01 -3.6294602e-01 -3.7220401e-01 2.2919825e-01
+1 6.4464733e-01 1 1 1.1737278e+00 -1.5513366e+00 8.0555102e-01 -6.7003298e-01 -1.2347274e+00 9.3913985e-01 -7.2179701e-01 5.4243502e-01
+1 1.2965592e+00 1 1 7.8300568e-01 -1.2367427e+00 -1.3683001e+00 1.3653659e+00 1.2974746e+00 7.6200245e-01 -1.5531037e+00 -1.9650587e-01
+1 1.1354683e+00 1 1 -1.5512962e-01 -1.1569567e+00 -5.6131074e-01 1.5126338e+00 8.6154465e-01 -1.2981203e+00 4.8007996e-01 -8.6028760e-01
+1 4.2587435e-01 1 1 2.5837658e-01 1.4872835e+00 2.5310680e-01 1.0682936e+00 3.8035959e-01 8.5380243e-01 1.0939163e+00 -1.2442867e+00
+1 8.2638252e-01 1 1 8.5416899e-01 -8.7887564e-01 2.4956140e-01 6.0804686e-01 -4.3740458e-01 -9.3776565e-01 8.5170377e-01 8.5494336e-01
+1 3.3067119e-01 1 1 -1.0601693e+00 5.0575786e-01 3.5221829e-01 -1.5727019e-01 -1.3204960e-01 3.4306769e-01 1.4890963e+00 -6.1178801e-01
+1 5.5929127e-01 1 1 8.4729160e-01 -8.7744836e-01 9.7226882e-01 -1.1606563e+00 -1.3931481e+00 1.1160863e+00 1.3141726e+00 1.1171920e-01
+1 6.6623883e-01 1 1 -4.0955977e-01 -6.3866496e-01 1.4987385e+00 -1.0019752e+00 -3.4965270e-01 -3.8683246e-01 -1.2384828e+00 -1.0077436e+00
+1 1.0575835e+00 1 1 -2.4151559e-01 7.8013132e-01 8.1518821e-03 -1.2610330e+00 1.3069904e+00 -1.5378935e+00 1.0132059e+00 -8.2057110e-01
+1 1.3865717e+00 1 1 -2.1483095e-01 -1.3406653e+00 -1.2213951e+00 -9.9802619e-01 5.7167050e-01 -1.4934128e+00 1.5193684e+00 2.5330451e-01
+1 6.6861776e-01 1 1 -9.7379381e-01 -1.0586121e+00 -8.2069726e-01 -8.6307693e-01 1.0757296e+00 1.5366481e+00 1.1588220e+00 4.3093750e-01
+1 3.7834132e-01 1 1 1.1451919e+00 -1.2542438e+00 1.2745407e+00 -1.0007122e+00 -7.8718442e-02 -5.8846433e-01 -1.5523583e+00 1.3954393e+00
+1 9.5226694e-01 1 1 -1.2972822e+00 1.1254578e-02 -1.3150777e+00 1.1162847e+00 -4.1034818e-01 -5.8631550e-01 4.4092044e-01 1.1585485e+00
+1 6.0951579e-01 1 1 -7.6910068e-01 6.6012810e-01 -1.4061560e+00 -1.9515429e-01 -9.2600843e-01 9.7158627e-01 -4.6727003e-01 1.3318071e-01
+1 5.8371374e-01 1 1 1.3785799e+00 -1.3321991e+00 9.3839568e-01 -1.3548409e-01 2.6319045e-02 -5.4813879e-01 5.7417035e-01 1.5542435e+00
+1 7.1493288e-01 1 1 5.4687112e-01 -1.3975144e-01 8.2112683e-01 5.7351849e-01 -6.2036845e-01 -1.4189988e+00 -8.9155551e-01 -1.7200184e-01
+1 8.9917593e-01 1 1 -1.0372440e+00 1.1088049e+00 -3.3797091e-01 7.1900065e-01 4.1352202e-01 -1.2828799e+00 1.0234544e+00 -5.6974248e-01
+1 1.1977111e+00 1 1 -2.6235019e-01 -2.4379406e-01 -2.7760053e-01 -1.4630563e+00 8.6164220e-01 -6.1147156e-01 9.7770402e-01 -8.7387633e-02
+1 8.2026262e-01 1 1 1.4764015e+00 -8.0994048e-01 -3.6696301e-01 -3.4148706e-01 -1.1216068e+00 -8.5292123e-01 -1.3996589e+00 1.5414117e+00
+1 7.2046157e-01 1 1 -1.5598743e+00 -1.4866328e-01 -6.0087008e-01 3.1680165e-01 -1.2889643e+00 4.0186827e-02 1.7867612e-01 9.3397370e-01
+1 5.1511019e-01 1 1 -2.1728678e-01 -1.0175526e+00 1.3970237e+00 -5.1420607e-01 7.9948257e-01 -2.2418149e-02 -3.5299480e-01 -1.2425835e+00
+1 8.5996331e-01 1 1 -1.4082706e+00 8.2402043e-01 -4.8652435e-01 2.6000298e-01 3.1178624e-01 2.0928061e-01 -1.4565967e+00 1.2065531e+00
+1 7.8742655e-01 1 1 -4.4803374e-02 1.1709610e+00 5.5096932e-01 -8.5273949e-02 1.4753415e-02 -1.2044929e+00 1.4100423e+00 -4.4312917e-01
+1 7.8301187e-01 1 1 9.7193449e-01 1.4054699e+00 -1.2737910e+00 -6.3301276e-01 -2.2516600e-01 5.1099356e-01 1.5482772e+00 1.0441862e+00
+1 3.6663954e-01 1 1 -9.7884220e-01 9.7777399e-02 1.3486227e+00 1.5288612e+00 1.2542659e+00 -8.4557650e-01 8.3592594e-02 7.0110394e-01
+1 4.1047513e-01 1 1 1.1199545e+00 2.9178320e-01 -2.8936637e-01 4.8317372e-01 3.6104578e-01 9.6099018e-01 6.4881054e-01 -6.6015429e-01
+1 4.9075662e-01 1 1 -1.3481095e+00 -2.5961739e-02 -1.9510711e-01 -3.1630755e-01 -1.4606434e+00 4.3406385e-01 9.0574716e-02 8.9203792e-01
+1 7.1312698e-01 1 1 -5.1015015e-01 3.4242572e-01 6.5747976e-01 -6.0627259e-01 -6.2881859e-01 5.3297044e-01 -1.3831895e+00 8.0110904e-01
+1 5.0845021e-01 1 1 -6.8718971e-01 -2.4874026e-01 1.2810221e+00 -1.4385093e+00 -2.3630479e-01 9.5357830e-01 5.2044281e-01 -6.2650110e-01
+1 1.1952791e-01 1 1 -1.1028424e+00 8.8226706e-01 8.0459683e-01 6.7074344e-01 -6.0140973e-01 1.5264207e+00 8.8828204e-01 1.0145471e+00
+1 4.5615751e-01 1 1 -7.5973137e-02 -5.4852935e-02 1.4441882e+00 1.1506118e+00 -1.3898361e+00 3.0649440e-01 5.0798889e-01 -1.0721379e+00
+1 7.3545358e-01 1 1 -1.3939010e+00 -1.4266283e+00 5.2613846e-01 -1.3124008e+00 -1.2334182e+00 -9.6058095e-01 -1.0795563e+00 7.5387965e-01
+1 1.0776135e+00 1 1 -4.3736346e-01 -7.0653181e-01 -7.7421609e-01 -3.9752153e-01 1.3096163e+00 1.6064460e-01 -1.4048679e+00 4.1210651e-01
+1 2.4145238e-01 1 1 5.5914757e-01 5.4006748e-01 2.2695072e-01 1.0232828e+00 7.2279950e-01 1.3256851e+00 5.9621027e-01 -9.3762475e-01
+1 6.8215186e-01 1 1 1.0896535e+00 8.5288332e-01 4.6729695e-01 1.2358253e+00 -4.4756233e-01 6.1470131e-01 -1.1745036e+00 -4.3035344e-01
+1 9.6511706e-01 1 1 1.4624731e+00 -6.7724284e-01 -1.2176469e-01 1.4462958e+00 -1.2072233e+00 -1.4133124e+00 -1.2547941e+00 -1.0040471e+00
+1 5.8334143e-01 1 1 -3.6013350e-02 -4.3025642e-01 -1.3223191e+00 1.3908269e+00 -1.3969692e+00 4.0306817e-02 1.8706596e-01 -1.5246612e+00
+1 3.1753466e-01 1 1 1.0510088e+00 6.2670324e-01 -5.9013955e-01 -9.6315908e-01 1.4016131e+00 -1.1473388e+00 -7.1660584e-01 9.9032351e-01
+1 1.1177474e+00 1 1 -8.7002823e-01 -7.5874533e-01 -4.6742332e-01 8.1236353e-01 1.2504171e+00 -2.2764804e-01 8.7180160e-01 2.0934874e-01
+1 4.8217974e-01 1 1 1.5494152e+00 -5.0823320e-01 1.1394357e+00 3.2213234e-02 -1.4943246e+00 3.7928374e-01 -1.8723194e-02 -5.9439414e-02
+1 5.6969273e-01 1 1 3.5909258e-01 1.1510041e-01 -6.5296728e-01 1.0538956e+00 -1.2210428e+00 3.3025928e-01 -5.2146209e-01 2.8230090e-02
+1 6.1223746e-01 1 1 2.6955883e-01 -7.2853154e-01 -8.3786251e-01 5.2444999e-01 -1.1839086e+00 -5.2645419e-01 8.3012216e-01 8.2638296e-02
+1 8.9423366e-01 1 1 2.9866588e-01 1.4985998e+00 -1.3369377e+00 -8.7798618e-01 8.9567209e-01 -1.3907375e+00 5.0112020e-02 3.1788670e-01
+1 5.3783665e-01 1 1 -5.8768836e-01 8.1830639e-01 -1.2408129e+00 -2.5302586e-01 -9.5113614e-01 -6.7659431e-01 2.8588295e-01 -1.1272652e+00
+1 5.2729703e-01 1 1 -1.1096193e-01 -6.1722000e-01 -4.5096507e-01 1.1108028e+00 -1.3217610e+00 1.0448686e+00 1.3396247e+00 9.9876334e-01
+1 5.2713037e-01 1 1 1.1689211e+00 -7.7605350e-02 1.2931344e+00 -1.2232488e+00 -6.3610559e-01 -3.9572592e-01 -7.2155885e-01 6.8598286e-01
+1 9.7211489e-01 1 1 -1.4635027e+00 -5.5216783e-01 1.7191814e-01 -5.5988325e-01 -1.8691928e-01 -2.1396523e-01 -6.9196347e-01 -3.3111110e-01
+1 8.9283366e-01 1 1 -1.5607612e+00 -1.9965949e-02 -8.3711619e-01 -8.8770168e-01 4.0353582e-02 1.0098901e+00 3.4592246e-01 -1.2237244e+00
+1 8.8612782e-01 1 1 5.8533603e-01 5.8270722e-01 -1.3599434e+00 -1.7870411e-01 -3.6135773e-01 -8.0270528e-01 -1.1691696e+00 8.7051788e-01
+1 7.4840525e-01 1 1 1.4160095e+00 1.2159764e+00 -1.4815037e+00 -1.1735957e-01 -6.4085050e-01 -1.0688067e+00 4.2924357e-01 3.9705190e-01
+1 3.0907391e-01 1 1 1.3072385e+00 8.5553479e-01 6.3085823e-01 4.5792472e-01 -1.3946649e+00 1.9181387e-01 1.1999095e+00 5.0844244e-01
+1 8.1216347e-01 1 1 -1.5422032e+00 -9.6353048e-02 -4.0937668e-02 -5.6122671e-01 -7.1033926e-01 5.4171579e-01 9.9579312e-01 2.6012168e-01
+1 1.0069779e+00 1 1 1.4709765e+00 -1.4854543e+00 -3.0599984e-02 -1.4760950e+00 -6.1982750e-01 2.8175760e-01 1.0309594e+00 -1.2318560e+00
+1 3.6469339e-01 1 1 1.5099701e+00 2.0639706e-01 9.2726375e-01 4.2769629e-01 8.0499668e-02 1.1198567e+00 1.4508675e+00 -7.0800278e-01
+1 7.5381168e-01 1 1 2.8133792e-01 5.9718068e-01 -9.1925917e-01 3.2748821e-01 -1.0685189e+00 1.4992289e-01 -3.1223991e-01 9.5031458e-01
+1 6.7360801e-01 1 1 3.4942307e-01 -5.7280019e-01 3.6375282e-01 2.4067708e-02 -1.2535076e+00 1.9675150e-01 -1.3563984e+00 8.0120792e-02
+1 8.0281104e-01 1 1 1.1169042e+00 -1.2129754e+00 5.4414898e-02 -7.5948258e-01 -1.8145241e-01 -1.2946715e+00 1.5506214e+00 -1.1530908e+00
+1 4.2668548e-01 1 1 7.9228238e-01 -6.8248224e-01 3.4772285e-01 -3.3271271e-01 8.1586310e-01 -8.7262197e-01 -1.3588240e+00 4.8819125e-01
+1 6.6972607e-01 1 1 -1.3213635e+00 -5.2430947e-01 8.1557541e-01 1.3242346e-01 -8.4078723e-01 -1.2030260e+00 -1.5182865e+00 -8.0968927e-01
+1 1.5523664e-01 1 1 -2.3750517e-01 9.8123186e-02 6.0721423e-01 1.3934840e+00 -2.2727265e-01 3.3106889e-02 1.3152015e+00 9.3189366e-01
+1 3.6808325e-01 1 1 1.2149543e+00 -1.7975965e-01 1.5565566e+00 -2.8765749e-01 4.0528876e-01 3.6557901e-01 3.4560475e-01 1.4973480e+00
+1 6.9562747e-01 1 1 -6.1577094e-01 9.9162470e-01 1.0052358e+00 2.5167990e-01 7.1538301e-01 -6.6878720e-01 -2.2572335e-01 -1.3702795e+00
+1 5.6620626e-01 1 1 -8.5599756e-01 8.7317697e-02 -4.8798293e-01 1.4003523e+00 5.6712332e-01 3.1196933e-01 1.3115913e+00 7.2895158e-01
+1 7.6713149e-01 1 1 -1.3982739e+00 4.2476217e-01 1.1693476e+00 -1.0908310e+00 4.9532155e-02 -4.9644778e-02 -6.4058535e-01 -7.2209311e-01
+1 6.6998904e-01 1 1 1.4659379e+00 1.2792784e+00 -5.7824654e-01 7.3737850e-01 -3.5115921e-02 1.2838580e+00 -7.9889694e-02 -2.4642980e-01
+1 3.8936716e-01 1 1 -1.4931826e+00 -2.2778505e-01 1.4981162e+00 -4.6263830e-01 4.2612736e-01 1.3437825e+00 -1.2460198e+00 -1.1265172e+00
+1 6.8021191e-01 1 1 -8.7829669e-01 1.2181070e+00 -1.0253859e+00 -1.2000725e-01 -9.0875083e-01 4.2522045e-02 1.6796940e-03 1.0046231e+00
+1 3.2805340e-01 1 1 8.1141428e-01 -1.0351527e+00 1.1163406e+00 -5.9382409e-02 1.0483496e+00 1.5264805e+00 -4.3716614e-02 -1.3599824e+00
+1 3.7440321e-01 1 1 -2.1395830e-01 3.2912457e-01 7.4437424e-01 9.8632201e-01 1.5594278e+00 1.3127036e+00 3.8754409e-01 1.0040762e+00
+1 5.2063744e-01 1 1 1.1264829e+00 -7.4798514e-01 8.7598473e-01 -1.0703558e+00 -1.0041756e+00 -7.9582964e-01 9.3192379e-01 -1.1275711e+00
+1 6.1996132e-01 1 1 1.5603736e+00 1.2675668e+00 1.1722172e+00 -7.1070223e-01 -5.4387109e-01 1.3927945e+00 -1.1378945e+00 -1.0010131e+00
+1 4.8375392e-01 1 1 -8.1610379e-01 8.5475852e-01 5.2686417e-01 -4.3708665e-01 1.1931592e+00 6.9107974e-01 1.4232531e+00 -7.9768219e-01
+1 9.0796889e-01 1 1 -6.2888925e-02 -5.7674701e-01 -1.1436317e+00 -1.0717340e+00 6.4122202e-01 5.0921874e-01 5.2790625e-01 -1.4687077e+00
+1 4.0181567e-01 1 1 -1.3990351e+00 1.5679846e+00 -7.5483278e-01 1.2596806e+00 1.3557104e+00 7.4100739e-01 6.6277381e-01 -1.0764972e+00
+1 7.5859000e-01 1 1 1.2382518e+00 1.4387758e+00 -7.2345888e-01 2.5812611e-01 -5.4707562e-01 8.3787539e-01 -8.4808480e-01 -2.5641396e-01
+1 1.0170770e+00 1 1 1.3886831e+00 6.6581609e-01 -1.2098773e+00 -2.1394679e-01 7.4183217e-01 1.5534039e+00 -3.5530884e-01 7.1568634e-01
+1 6.0432839e-01 1 1 7.0437438e-01 1.7959790e-02 1.1216156e+00 1.3199109e+00 -1.0078867e+00 1.4251830e+00 4.9199787e-01 -6.1801570e-01
+1 4.5912259e-01 1 1 8.9907488e-01 2.5728853e-01 1.4382090e+00 9.5649455e-01 -8.3981689e-02 1.5481871e+00 3.3641225e-01 -8.8451818e-01
+1 8.3969783e-01 1 1 -3.0911442e-01 1.4168980e+00 5.6514369e-01 2.7424786e-01 -9.0514905e-01 -1.4321139e+00 -7.8606051e-01 -8.0573105e-02
+1 2.8132569e-01 1 1 9.0819440e-01 5.3259596e-01 1.3353688e+00 5.6727636e-01 -1.2485281e+00 1.3447114e+00 -9.2179993e-01 -1.6573718e-01
+1 7.4381644e-01 1 1 -9.7546046e-01 9.4281738e-01 5.0410541e-03 -5.1983927e-01 -1.3146685e+00 -5.2971046e-02 -1.4980638e+00 1.0479626e+00
+1 6.0445172e-01 1 1 1.4080917e+00 -2.6164834e-01 -9.8006211e-02 -1.6943665e-01 -8.1225889e-01 -1.2136457e+00 -1.2350975e+00 1.3389129e+00
+1 1.0877144e+00 1 1 1.8006206e-01 7.0611512e-01 -9.9583536e-01 -1.4387637e+00 -1.4150297e+00 6.1746301e-01 1.3597871e+00 -1.1834290e-01
+1 5.4763555e-01 1 1 9.4936355e-01 -1.2601956e+00 1.4008235e+00 -4.6201226e-01 -5.4790614e-01 1.0202277e+00 -1.1454734e+00 -3.6103172e-01
+1 1.8377057e-01 1 1 -1.9597344e-01 5.1092679e-01 5.4591025e-01 9.7706403e-01 -6.5040506e-01 1.5483882e-01 -2.9124760e-01 -1.4446656e+00
+1 1.2380429e+00 1 1 -1.3365062e+00 1.1737797e+00 -1.4786138e+00 4.1034915e-01 1.3845264e+00 1.1373524e+00 -3.9712376e-01 8.7431538e-01
+1 1.0580844e+00 1 1 -2.7186174e-01 -1.4871406e+00 -1.0646967e+00 9.4226061e-01 -4.2200385e-02 -1.1102939e+00 1.4253254e+00 1.3897289e+00
+1 7.7584719e-01 1 1 -1.3045302e+00 1.3963081e-01 1.5407950e-01 -1.9446348e-01 7.3807611e-01 3.5033928e-01 8.0077925e-01 -5.6799226e-01
+1 4.0690207e-01 1 1 -6.4636697e-02 5.2727832e-03 9.4177726e-01 -1.0914289e+00 -1.3042032e+00 8.0762482e-01 1.1392807e-01 1.0541617e+00
+1 2.0650890e-01 1 1 6.4209355e-01 6.5507295e-01 1.1066578e+00 1.1343994e-01 -8.5092112e-01 -1.0715529e+00 1.5591211e+00 -1.2868283e+00
+1 2.3697174e-01 1 1 2.9546222e-01 -1.4711035e+00 1.3692540e+00 -3.6167680e-01 -9.0142809e-01 1.1618191e+00 1.2483068e-01 -9.9934687e-01
+1 7.7100971e-01 1 1 -1.0244106e+00 -5.0220771e-01 8.8608776e-01 2.7972956e-01 -1.5421584e+00 -1.4464782e+00 -5.5471862e-01 -1.0685974e+00
+1 6.1845788e-01 1 1 -1.3408372e+00 8.5440503e-01 1.3277535e+00 -1.5494919e+00 -9.1745905e-01 -1.3146022e+00 1.0911168e+00 5.6838826e-01
+1 4.2807668e-01 1 1 -8.0621968e-01 -2.3472986e-01 8.2005768e-01 1.4925538e+00 -7.9744680e-01 3.0134748e-01 9.2442137e-01 -6.8172212e-01
+1 7.9802894e-01 1 1 -4.4499820e-01 7.3553874e-01 5.4242556e-01 -2.6490030e-01 -6.5413577e-01 4.9977284e-01 -1.5673664e+00 -3.1530973e-01
+1 6.6812295e-01 1 1 1.0473503e+00 3.2492345e-02 -3.5546253e-01 -5.4252773e-01 1.5144547e+00 -9.3666925e-01 -4.7265626e-01 4.5612235e-01
+1 7.0070718e-01 1 1 4.7256855e-01 -5.3828555e-01 1.0504280e+00 -1.3617366e+00 2.5615934e-01 -7.9341818e-02 1.1539846e+00 5.6220688e-01
+1 7.5285476e-01 1 1 5.1338029e-01 8.2164414e-01 -1.2078694e+00 -2.0427676e-01 1.2880119e+00 -1.4626461e+00 -1.1739754e+00 -8.9962507e-01
+1 3.7170155e-01 1 1 1.5690643e+00 -1.0682989e+00 3.1112461e-01 4.8119567e-01 -1.0993035e+00 2.7028495e-01 1.3392769e+00 4.8689279e-01
+1 2.4384735e-01 1 1 7.3570265e-01 -6.9702817e-01 1.4610667e+00 9.9620625e-01 -2.8774831e-01 -6.3791581e-02 -2.8433982e-01 -6.4180297e-01
+1 4.8225157e-01 1 1 -3.5422030e-01 4.6512429e-02 1.4590239e+00 -1.4504735e+00 -1.2747466e+00 -8.6200391e-01 -5.3695752e-01 1.4466396e+00
+1 6.2014502e-01 1 1 -6.2420651e-02 -5.2217242e-01 -1.4583857e+00 6.5045402e-01 9.9520152e-01 1.3256156e+00 1.1507156e+00 8.8695180e-01
+1 1.1276347e+00 1 1 1.8806451e-01 1.4580483e+00 -3.8198765e-01 -5.6178733e-01 5.1259854e-01 -5.5383301e-01 4.3314747e-01 1.4179063e-01
+1 4.7690344e-01 1 1 3.5808273e-01 9.9515315e-01 1.3488918e+00 -1.4737222e+00 9.9659108e-01 2.6769321e-01 8.3942226e-01 -1.3936694e+00
+1 7.3641760e-01 1 1 -9.9511553e-01 -3.0037935e-01 1.0920157e+00 -5.3295747e-01 -1.2657331e+00 3.5904451e-01 -7.2267644e-01 3.1325698e-01
+1 3.6445000e-01 1 1 9.3254250e-01 6.3648164e-02 3.2437303e-01 -7.3558762e-01 -1.4526885e+00 -5.3840326e-01 -6.2567590e-01 -3.9923095e-01
+1 6.0941295e-01 1 1 -1.6395624e-01 -1.5484085e+00 1.0742111e+00 -8.5402660e-01 1.1222842e+00 -1.1566963e+00 -8.2428139e-01 5.6725098e-01
+1 8.3327264e-01 1 1 -4.3569900e-01 8.5131769e-01 -4.6674604e-01 3.1172888e-01 1.0870988e-01 -4.1959007e-01 7.2629893e-01 -9.4655124e-01
+1 3.6896161e-01 1 1 2.5936690e-01 1.2834321e+00 -4.3867568e-02 -9.4928863e-01 -1.3200092e+00 8.2527938e-01 -1.3229232e+00 3.3851734e-01
+1 6.1204044e-01 1 1 -1.3511614e+00 4.6843500e-01 9.9205071e-01 1.4551610e+00 5.3221927e-01 3.3894813e-01 -1.3185494e+00 3.6632891e-02
+1 5.9225091e-01 1 1 -1.5377085e+00 1.5580063e-01 9.6414041e-01 -4.0788144e-01 8.9502804e-01 9.9378220e-01 -6.5063152e-02 -6.3154180e-02
+1 7.8163486e-01 1 1 -1.5251345e+00 -1.5470855e+00 -2.6968710e-02 -3.0818442e-01 7.9056848e-01 -1.3506936e+00 -2.4215452e-01 4.2601207e-01
+1 1.0290665e+00 1 1 -6.8113500e-01 1.0971613e+00 -8.7376256e-01 8.3079753e-01 1.2891570e+00 4.0392193e-02 -1.5286144e+00 2.9511954e-01
+1 9.5957722e-01 1 1 1.2771573e-01 -1.1591174e+00 -1.5233239e+00 -1.1652039e+00 -7.0246538e-01 2.8757393e-01 5.2290839e-01 -5.0071814e-01
+1 6.1801500e-01 1 1 8.1054992e-01 -2.6967676e-01 1.4746882e+00 1.1071748e+00 -2.3036737e-01 1.4855128e+00 1.4867313e+00 7.5693251e-01
+1 5.0004560e-01 1 1 9.6684122e-01 8.6097200e-01 1.0594484e+00 6.3422990e-01 -1.3422830e+00 7.7701974e-01 -7.3515064e-01 1.4560154e+00
+1 7.5400445e-01 1 1 1.3832003e+00 1.8064969e-01 -3.9784440e-01 7.7990011e-02 2.6387453e-02 -2.2988966e-01 2.0717601e-01 1.3851282e+00
+1 8.2311637e-01 1 1 -3.3768567e-01 1.4008470e+00 -1.2617304e+00 7.3398235e-01 5.2935661e-01 4.0337987e-01 1.1225202e+00 6.4817296e-01
+1 7.6227267e-01 1 1 1.3748562e+00 9.4070795e-01 -1.5321579e-01 -9.9303384e-01 -9.3809497e-02 4.8470368e-02 9.3245284e-01 -1.2003917e+00
+1 5.0604817e-01 1 1 7.9376105e-01 -1.1573413e+00 1.0081975e+00 1.3620118e+00 4.2329943e-01 9.6897908e-01 1.4707322e+00 3.2421119e-01
+1 3.7498865e-01 1 1 1.5395815e+00 1.3061328e+00 -9.7578687e-01 -1.4536753e+00 -1.3138129e+00 -3.8494421e-01 5.4460446e-01 1.4957639e+00
+1 5.9175272e-01 1 1 -1.5517614e+00 -1.2748164e+00 -9.3625060e-01 2.4456423e-01 1.0005927e+00 -1.2180547e+00 -1.4339097e+00 2.7961249e-01
+1 6.9333437e-01 1 1 1.0488281e+00 -1.7810273e-01 6.7383155e-01 1.1877810e+00 1.5692550e-02 -1.2274207e+00 -5.6351800e-01 -3.7556883e-01
+1 7.3498556e-01 1 1 1.7746360e-01 5.6521961e-01 -3.5469108e-01 1.3548647e+00 -1.4908916e-01 -1.5623131e+00 8.5478235e-01 -7.2575464e-01
+1 3.4624577e-01 1 1 1.2593195e+00 -5.3014487e-01 1.4499544e+00 9.4819501e-01 1.2494794e+00 -3.6453515e-01 -1.7617130e-01 1.0460090e+00
+1 7.4930317e-01 1 1 4.7324838e-01 -5.8807709e-01 4.9631603e-02 -9.8596193e-01 -1.5470435e+00 -6.3652637e-01 -1.5307428e+00 -7.9951997e-02
+1 1.3570480e+00 1 1 -6.2706738e-01 -3.6120280e-01 -1.5052909e+00 8.3905513e-01 -1.3390965e+00 -9.7569500e-01 -6.9150929e-01 8.4845044e-01
+1 7.1727804e-01 1 1 9.2186554e-01 -1.1785289e+00 -1.7925697e-01 -6.0991095e-01 1.7457813e-01 6.0775583e-01 -1.4454935e+00 2.1743975e-01
+1 8.1388293e-01 1 1 -5.4081462e-01 2.0582984e-01 1.5497867e-02 2.4356380e-01 -1.1298100e-01 1.2345494e+00 -4.7265671e-01 8.3762063e-01
+1 5.9789530e-01 1 1 -8.4381862e-01 4.8864036e-01 -2.7954503e-01 8.1571514e-02 -1.3496584e+00 -1.1482012e+00 1.1465592e+00 4.1324748e-01
+1 6.5256493e-01 1 1 -9.1024046e-01 4.5529259e-01 1.5092630e+00 1.2380408e+00 -1.4098141e+00 9.8604924e-01 -3.0819020e-01 -6.1093407e-01
+1 2.8106343e-01 1 1 1.1447402e+00 -8.1712204e-01 9.6411825e-01 9.8331698e-01 -8.5425668e-01 6.2833739e-01 7.3355490e-01 -1.2441662e+00
+1 8.5871042e-01 1 1 5.3575995e-01 -1.4686696e+00 -3.9946576e-01 -1.3103841e+00 -4.1361585e-01 -1.5680479e+00 1.2476898e+00 -2.6100295e-01
+1 1.0009007e+00 1 1 7.1300345e-01 -4.3644154e-01 -2.3755979e-01 -1.0605873e+00 7.0289874e-01 6.3995862e-01 -2.0930730e-01 -1.0132397e+00
+1 7.5749848e-01 1 1 1.4146511e+00 3.4583231e-01 2.9681666e-01 1.0547755e-01 1.2307165e+00 -1.0286884e+00 7.5589826e-01 1.0544306e+00
+1 9.6144624e-01 1 1 4.6744032e-01 4.5728211e-01 -2.5161273e-01 9.0295083e-01 4.0626818e-01 -9.8201356e-01 -2.1865162e-01 9.1087014e-02
+1 1.0104437e+00 1 1 -8.5375628e-01 1.2048439e+00 -2.7147725e-01 -1.1395135e+00 1.4683964e+00 1.2258486e+00 7.8556124e-01 9.4381469e-01
+1 1.0168628e+00 1 1 -1.4281480e+00 -8.9480905e-01 -1.1256662e+00 -6.5384581e-01 -1.0135390e+00 2.7284261e-01 -1.1861071e+00 7.9216565e-01
+1 1.1114255e+00 1 1 -1.1154586e+00 -2.5166898e-01 -4.0073190e-01 1.0448972e-01 -8.3524402e-01 -1.0594618e+00 -1.4966968e+00 -1.4161322e-01
+1 6.4874540e-01 1 1 1.5124987e+00 -1.2167592e+00 4.7365586e-01 8.4377289e-03 -1.3102202e+00 1.7348562e-01 -2.5134097e-01 1.2338480e+00
+1 6.9809721e-01 1 1 -1.2016764e+00 -1.4454896e+00 -6.1666953e-02 4.4124075e-01 -1.4484310e+00 3.7480604e-01 1.1543586e+00 -3.6923549e-01
+1 7.4453598e-01 1 1 7.2361116e-01 -4.0769715e-01 2.8910157e-01 -1.3669755e+00 4.2194352e-01 4.7188315e-01 -1.1706644e+00 -1.0954177e+00
+1 2.9771207e-01 1 1 6.2762214e-01 -3.5249482e-01 -1.1136688e+00 -2.9019143e-01 1.0301241e+00 1.5601997e+00 4.3830028e-01 -9.5225707e-01
+1 7.2353803e-01 1 1 -1.0228333e+00 6.6338264e-01 1.7734421e-01 -1.4956339e+00 -2.0712848e-02 -5.9828107e-01 -5.2189403e-01 -1.3116800e+00
+1 1.0152780e+00 1 1 3.5819734e-02 -4.0381028e-02 -7.4737006e-01 -1.2353974e+00 5.9595177e-01 9.2816023e-01 -1.4620522e-01 -8.4932910e-01
+1 6.0025490e-01 1 1 -1.1635160e+00 -9.9923928e-02 -9.6113781e-01 -5.3748503e-01 7.6394005e-01 -1.5601470e+00 -5.4565399e-01 7.2282256e-01
+1 8.4891371e-01 1 1 1.2007658e+00 1.3306080e+00 2.2628045e-01 -1.4320698e+00 -1.4873173e-01 1.4839635e+00 -4.9764500e-01 -5.9968695e-02
+1 1.0776108e+00 1 1 -3.2038387e-01 -1.4687388e+00 -1.3731211e+00 -1.0562883e+00 9.7350362e-01 -1.2955326e-01 -9.9992263e-01 5.5738505e-01
+1 9.3757406e-01 1 1 -1.9247152e-03 1.5424686e+00 9.3531386e-02 1.0321845e-01 2.6086365e-01 -2.7794829e-01 -1.3206044e+00 -2.5877310e-01
+1 4.4086719e-01 1 1 -9.3276243e-01 -1.5344754e-01 1.1856748e+00 6.3332750e-01 -1.3280088e+00 7.1288688e-02 -4.6552480e-02 -1.2351895e+00
+1 4.0059964e-01 1 1 -3.9087582e-01 2.5472491e-01 5.1493568e-01 6.1942231e-01 1.1721337e+00 1.2021749e+00 -1.5095311e-01 -1.8613718e-01
+1 8.6775322e-01 1 1 -3.7964374e-01 -8.2914381e-01 -5.6386899e-01 -6.0724892e-01 -8.7645394e-01 1.3706254e+00 1.3378875e+00 6.1875238e-01
+1 3.9388431e-01 1 1 -9.7680053e-02 6.8502643e-01 1.2389667e+00 1.0019736e+00 3.6666294e-01 -1.1986012e+00 1.4964260e+00 6.9950701e-01
+1 6.1635142e-01 1 1 1.3443025e+00 -6.9778482e-01 8.3646110e-01 1.2343804e+00 -1.3007294e+00 -9.9850218e-01 -1.1593983e+00 7.7454991e-01
+1 5.6450663e-01 1 1 -6.4163103e-01 -1.0404338e-01 -2.2543099e-01 -8.4597040e-01 9.8468935e-01 5.6186582e-01 1.2914507e+00 -8.9961739e-01
+1 8.2350149e-01 1 1 1.1949111e+00 1.2100004e+00 -5.7853845e-02 6.2378415e-01 -2.3622013e-01 -3.4864077e-01 1.4837629e-01 6.1592675e-01
+1 6.9276661e-01 1 1 -1.3312344e+00 9.4809108e-01 1.5441493e+00 4.4545772e-01 8.2140607e-01 -5.3511233e-01 -6.6426130e-01 3.3307148e-01
+1 3.0678067e-01 1 1 3.6655334e-01 4.0882854e-01 -1.8030959e-01 3.9266831e-01 1.2136780e+00 7.4677915e-01 9.8054499e-01 -3.8575434e-01
+1 6.2428320e-01 1 1 -1.1407901e-03 5.1811432e-01 1.1736813e+00 -9.0992599e-01 -7.4846674e-02 4.5450509e-01 -7.7537673e-01 8.7404719e-01
+1 1.0111092e+00 1 1 -3.2370332e-01 -5.4744146e-01 5.1599973e-04 1.4690700e-01 -1.3109930e+00 -1.4862970e+00 -4.3041407e-01 2.3861336e-02
+1 1.0646501e+00 1 1 7.5676541e-01 8.7620987e-01 -7.5237044e-01 -2.2591096e-01 1.2709904e+00 -1.3907504e+00 1.1186494e+00 -1.0863907e+00
+1 1.3534297e+00 1 1 -1.3523665e+00 -1.3270619e+00 -1.7949501e-01 1.3000886e+00 -1.2951815e+00 -8.9318352e-01 -1.2919969e+00 -3.1859874e-02
+1 7.5747787e-01 1 1 1.9855023e-01 1.3781788e+00 -8.4369993e-01 8.1243497e-01 -2.0169080e-02 -1.2056922e+00 9.6377784e-02 -1.3981502e+00
+1 6.3975973e-01 1 1 6.6228990e-01 8.8720334e-02 1.0844997e+00 1.2329077e+00 3.1028448e-01 -7.9559794e-01 -1.2403923e+00 4.0243621e-01
+1 1.0236208e+00 1 1 4.4354581e-01 -1.1338577e+00 -3.3427676e-01 -4.6554765e-01 -9.2487627e-02 -9.9625986e-01 3.3540110e-01 -1.0360570e-01
+1 5.3454043e-01 1 1 -3.2491868e-01 1.5472943e-01 -1.0218908e+00 1.2479716e+00 6.4880936e-01 5.4935029e-01 1.0690981e+00 -8.5873524e-01
+1 2.1113781e-01 1 1 -8.2028599e-01 -7.0125867e-01 1.6810306e-01 1.3856644e+00 7.0880317e-02 -2.1042825e-01 1.5626554e+00 -2.8657224e-01
+1 4.4215414e-01 1 1 -1.2381181e+00 1.2011028e+00 1.0163097e+00 2.3477484e-01 6.2187456e-01 7.6580723e-01 -1.6550081e-01 -3.5803538e-01
+1 7.5001716e-01 1 1 8.5962555e-01 -9.3893397e-01 2.7840319e-01 2.0372111e-02 -2.3310928e-01 -1.8294952e-01 -1.2625355e+00 -1.3507595e+00
+1 4.6944445e-01 1 1 -4.5800004e-01 -4.4340483e-01 1.2909112e+00 -3.9533679e-02 -3.0161399e-01 7.8663745e-01 -1.1174379e+00 -1.0662560e+00
+1 9.5673541e-01 1 1 -7.0469776e-01 -4.4715015e-01 5.0586297e-01 -1.5665012e+00 1.3042030e+00 1.1936980e+00 -3.3846279e-01 -9.1976066e-01
+1 2.7407999e-01 1 1 -5.1027256e-02 -5.6289777e-01 8.8922033e-01 1.5020533e+00 8.4841321e-01 2.7225309e-01 8.8010325e-01 1.3600166e+00
+1 8.6653847e-01 1 1 3.9697756e-02 -1.2873750e+00 5.6987888e-01 -8.2938960e-01 -4.0815860e-01 -1.5428349e+00 1.2771627e+00 -4.2868501e-01
+1 1.1223244e+00 1 1 1.1825424e+00 -7.6376385e-01 -7.6171310e-01 -3.0443469e-01 1.3167716e+00 2.7926887e-01 -1.2288836e+00 -1.2370487e+00
+1 6.8455571e-01 1 1 1.2741872e+00 -3.1447887e-02 -1.2195007e-01 1.0206266e+00 -1.5402512e+00 1.3248610e-01 -1.0171557e+00 -1.7648342e-02
+1 7.8331355e-01 1 1 -9.7350310e-01 -7.5707018e-01 -1.2963999e+00 5.7512522e-01 -2.7778910e-01 -6.9525742e-01 1.2121221e+00 -1.3059682e+00
+1 6.2658958e-01 1 1 -2.5211058e-01 -6.2833015e-01 1.4928127e+00 -5.5106724e-01 -3.9464412e-01 1.5332915e+00 -1.0922591e+00 8.9973358e-01
+1 3.2639471e-01 1 1 7.8593508e-01 -1.4518624e+00 9.4370711e-01 -3.7188377e-01 -8.8158352e-01 -4.5360227e-01 -1.2721833e+00 1.3368675e+00
+1 5.7512392e-01 1 1 -1.1862875e+00 -7.0117720e-01 -1.0159080e+00 1.5189100e+00 -1.0233398e+00 9.5204420e-01 9.4462772e-02 6.1976554e-02
+1 5.4490987e-01 1 1 -1.3872302e+00 -5.7120048e-01 1.9036929e-01 -2.6174802e-01 9.4806886e-01 8.7540769e-01 1.1315129e+00 -1.3688104e+00
+1 2.9510055e-01 1 1 -1.4186676e+00 5.4062887e-01 1.3953942e+00 -9.6926106e-01 3.5323409e-02 8.9859798e-01 1.2777539e+00 2.8654434e-01
+1 7.8066167e-01 1 1 1.1419857e+00 8.6349258e-01 4.0123616e-01 -1.2127075e+00 -8.0483747e-02 1.1003384e+00 -7.1703842e-01 -1.1089292e-01
+1 1.3726606e+00 1 1 1.3648556e+00 -1.4383322e+00 -1.4232039e+00 6.7851703e-01 1.3361021e+00 -1.1691703e+00 -1.1524583e-01 -8.1284113e-01
+1 5.4179349e-01 1 1 -7.8216104e-01 5.0593086e-01 2.9908638e-01 -1.4565553e-01 -2.3639789e-01 4.1623690e-01 1.4260518e+00 1.3656344e+00
+1 1.2204059e+00 1 1 -1.3569833e+00 -1.1113020e+00 1.9646496e-01 -7.3176744e-01 9.7540025e-01 -6.3317817e-01 4.4198530e-01 -2.5932947e-01
+1 7.1153779e-01 1 1 1.1446244e+00 -8.8401899e-01 1.7268017e-01 5.1990050e-01 7.2158749e-01 -1.2511225e+00 -1.4197564e+00 -1.1613169e+00
+1 7.7972337e-01 1 1 -1.4119448e+00 -1.1154635e+00 -5.9600549e-01 1.1986103e+00 1.1733083e+00 -9.3542562e-01 -1.4490486e+00 4.6135239e-01
+1 7.5483523e-01 1 1 1.0352506e+00 1.4299101e+00 1.4747345e+00 1.1520496e+00 1.6235559e-02 -1.1688079e+00 -5.3333301e-01 4.9902438e-01
+1 7.4177962e-01 1 1 1.3166240e+00 -6.8466569e-01 -1.3032935e+00 8.6280546e-01 -4.4751723e-01 2.2368574e-01 -7.6402679e-01 -9.4958556e-01
+1 9.8131188e-01 1 1 -8.7983310e-01 4.7769592e-01 -1.2695892e+00 -4.2030453e-01 -4.4924714e-01 -1.0001480e+00 -1.3090226e+00 -3.9379712e-01
+1 2.7383530e-01 1 1 1.2177471e-01 -1.2755331e+00 -2.8849278e-01 1.3835744e+00 -1.2495252e+00 1.1754046e+00 -1.6900841e-01 7.8758007e-01
+1 1.0040163e+00 1 1 1.4906927e+00 3.4328680e-01 -1.2206381e+00 -3.3398129e-01 7.7603606e-01 6.9012683e-01 -5.2459288e-01 1.3283909e+00
+1 1.0235446e+00 1 1 -1.2999767e-01 -1.4844186e+00 -6.6382252e-01 8.0250462e-01 -1.0546733e+00 2.0160364e-01 -1.5235257e+00 -1.0328797e+00
+1 9.1827734e-01 1 1 -1.4638821e+00 -1.2353512e+00 -1.0695781e+00 8.3796107e-01 -1.0281281e+00 -1.4261491e+00 1.2257217e+00 8.3134342e-01
+1 7.1524687e-01 1 1 1.4872606e+00 2.3760388e-01 -2.0643404e-01 -1.4813723e-01 -9.8920549e-01 1.0642101e+00 1.2810967e+00 -1.4152934e+00
+1 8.7625003e-01 1 1 -1.2632729e+00 4.4419431e-01 -1.2185500e+00 1.5405227e+00 -2.6835848e-01 1.0916467e+00 -1.0837338e+00 1.3037444e+00
+1 9.8521032e-01 1 1 -9.4496627e-01 1.1496655e+00 -1.2771827e-01 -1.4422459e+00 1.0260219e+00 4.0478168e-01 6.4037161e-01 -5.7601705e-01
+1 1.0510174e+00 1 1 -1.2971877e+00 -1.5091765e+00 -8.5325800e-01 7.0283904e-01 1.4716192e-01 -1.5240167e+00 -3.7083988e-01 1.2699950e+00
+1 7.7591609e-01 1 1 8.1852355e-01 4.9004631e-01 6.6321181e-01 2.2733484e-01 9.1692552e-01 -7.4402953e-01 2.1389146e-01 8.2542115e-01
+1 8.9471051e-01 1 1 -1.0890705e-01 -1.0475388e+00 2.3018138e-01 6.4001418e-01 1.2552741e+00 -1.3654763e+00 8.9179144e-01 -4.1981899e-01
+1 5.6309742e-01 1 1 1.1477304e+00 -4.9892195e-01 1.3578263e+00 -9.4839546e-02 -1.5443446e+00 -2.2558471e-01 -1.9983434e-01 1.1935859e-01
+1 6.0147938e-01 1 1 5.2622748e-01 -4.7038227e-01 4.5766189e-01 -1.1807775e+00 3.9379538e-02 5.0015826e-01 -2.5315337e-01 -1.4179555e+00
+1 6.6616404e-01 1 1 7.2186976e-01 -1.4677110e+00 1.3044878e+00 1.1291518e-01 -1.0241605e+00 -7.4199559e-01 -1.0321986e+00 5.4378560e-01
+1 7.3902787e-01 1 1 -3.6576434e-01 -3.2763997e-02 -6.4893488e-01 2.4350197e-01 -2.7867151e-01 1.4029098e+00 -2.8729535e-01 5.1150453e-01
+1 5.6595045e-01 1 1 6.9551771e-01 -8.8578006e-01 9.6110048e-01 -9.5753544e-01 4.8262563e-01 1.0525344e+00 5.4998075e-02 1.4592008e+00
+1 7.9326727e-01 1 1 -3.0012146e-01 7.0216690e-01 -8.5359991e-01 1.0809533e+00 -1.0334481e-01 -3.6319497e-01 7.2441188e-01 1.5149522e+00
+1 4.8899336e-01 1 1 1.2564951e+00 1.4971607e+00 1.1999355e+00 -2.4858508e-01 3.8449103e-01 -1.0325765e-01 1.5188693e+00 -8.0698183e-01
+1 6.8477274e-01 1 1 1.2793331e-01 -1.3773564e+00 1.4326842e+00 3.4876845e-01 -1.1527976e-01 -1.2921924e+00 -9.4586406e-01 -6.8807589e-01
+1 1.1218350e+00 1 1 1.3258211e+00 1.1666150e+00 -1.1839969e+00 -4.6050390e-01 8.5570102e-01 -4.7994482e-02 -6.7840391e-01 -2.8886030e-01
+1 4.5283680e-01 1 1 -2.4194771e-01 6.1884665e-01 -5.8812013e-01 1.1951936e+00 -4.4416864e-01 7.4604806e-01 -1.0948499e+00 -1.1144128e+00
+1 8.8524914e-01 1 1 -1.1942563e+00 -8.5760858e-01 -1.0844618e+00 2.7598175e-01 -7.1810979e-01 7.3348878e-01 -8.3343927e-01 2.3981245e-01
+1 2.9511664e-01 1 1 -2.3049147e-01 -2.0034501e-01 9.7165241e-01 1.4345056e+00 7.2772883e-01 1.3641917e-01 7.4777021e-01 -1.3550023e-01
+1 4.4421076e-01 1 1 -2.8635421e-01 5.8880077e-01 5.6347601e-01 1.1535015e+00 7.1825787e-01 -5.6559755e-01 1.4032577e+00 3.0237014e-01
+1 7.7374848e-01 1 1 1.6475947e-01 -4.2389145e-02 -1.5605598e+00 1.3223548e-01 -1.3805494e+00 4.6138259e-01 6.1602836e-01 -1.1619577e+00
+1 5.3993216e-01 1 1 1.3692117e+00 7.0717407e-01 8.2896708e-01 1.3756624e+00 9.0906019e-01 1.0065301e+00 -1.1006652e+00 -8.8341099e-01
+1 6.2361342e-01 1 1 1.7404059e-01 8.2955363e-01 -5.1372282e-01 -1.3642839e+00 1.0096003e+00 -7.2500861e-01 -1.1827694e+00 -3.2155319e-01
+1 4.1085976e-01 1 1 2.7737886e-01 -8.0360145e-02 -1.0427657e+00 9.6579087e-01 6.1038226e-01 1.0182088e+00 1.1922434e+00 -8.0504281e-01
+1 4.6440850e-01 1 1 -2.1707872e-01 2.7188739e-01 1.1830137e+00 -5.6204950e-01 1.3946773e+00 7.7932721e-01 9.5632856e-01 4.8511311e-01
+1 9.6294324e-01 1 1 -1.0529396e+00 -1.4059493e+00 -2.2931190e-01 4.0308112e-01 9.1881467e-01 8.5258862e-01 6.2602199e-01 8.6310202e-01
+1 5.0947123e-01 1 1 -1.6443943e-01 1.2696803e+00 6.8904684e-01 1.3106413e+00 -1.5513094e+00 6.5278892e-01 3.5782810e-01 1.4223838e+00
+1 1.8421755e-01 1 1 8.6810230e-01 -1.3215592e+00 8.9975931e-01 -8.9961602e-01 -7.7941955e-01 9.8189885e-01 1.0085827e+00 -1.5150575e+00
+1 1.0186313e+00 1 1 6.3911827e-01 -3.8527047e-01 -1.3723335e+00 6.3903878e-01 7.3698216e-01 -1.2192507e-02 -7.8477671e-01 -9.6322743e-01
+1 5.0837123e-01 1 1 5.5553892e-01 -4.1839480e-01 7.6425536e-01 -7.8055760e-01 -8.4065918e-01 -7.1594504e-01 -1.3362227e+00 -3.3650097e-01
+1 7.4732710e-01 1 1 1.2930460e-01 -1.0770171e+00 -1.1325748e+00 4.5934308e-01 -1.2167421e+00 -5.8837886e-01 1.3505739e+00 -7.0508331e-01
+1 6.1497608e-01 1 1 -7.5977763e-01 4.3017325e-01 -2.7510958e-01 1.2859854e+00 -1.1573515e+00 8.5022000e-01 1.0888312e+00 -2.4761872e-01
+1 6.8624797e-01 1 1 9.9154105e-01 1.1171280e+00 6.5765729e-01 -6.0067733e-01 1.1358906e+00 -1.4574616e+00 2.0939975e-01 8.8238969e-01
+1 3.7240221e-01 1 1 -1.3186067e+00 1.4130821e+00 1.1231678e+00 1.4948523e+00 -5.4485201e-01 -5.5896294e-01 7.9779555e-01 -1.1353936e+00
+1 1.2563191e+00 1 1 -1.0274824e+00 -7.7027395e-01 -7.4984896e-01 6.6538282e-01 4.1487012e-01 -1.1280629e+00 2.3238213e-01 -5.2615708e-01
+1 6.3327629e-01 1 1 4.3755642e-01 5.0897787e-01 1.3583107e+00 -9.8084035e-01 1.5280755e+00 1.5789551e-01 6.4673743e-01 4.6131857e-01
+1 9.4716396e-01 1 1 -4.5772926e-01 -1.6581594e-01 -8.2644502e-01 -1.0470271e+00 -1.5425910e-01 -8.9603575e-01 -1.9466567e-01 -6.9531514e-02
+1 5.9089784e-01 1 1 7.0476300e-01 -2.7584030e-01 -1.0803276e+00 -1.3246731e+00 -8.1868927e-01 1.1223456e+00 -1.3480175e+00 5.6311498e-02
+1 3.0455553e-01 1 1 1.1475209e+00 9.4291074e-01 1.3395095e+00 6.8678019e-01 4.6527901e-01 1.1395801e+00 1.0365609e+00 8.0795495e-01
+1 8.6902752e-01 1 1 1.4628463e-01 1.3074617e+00 4.8398345e-01 5.0319194e-01 5.2013148e-01 -1.3676248e+00 1.3474273e+00 1.3353149e+00
+1 5.7946117e-01 1 1 -1.2612436e+00 -9.3202526e-01 7.2642173e-01 -2.0548707e-02 -1.2025902e+00 1.3626794e+00 -1.5300886e+00 -9.0087669e-01
+1 7.3284478e-01 1 1 -1.3958194e+00 -5.6762567e-01 7.4088261e-01 2.1307474e-01 1.0741971e+00 3.4236268e-01 8.7859636e-01 1.4419895e+00
+1 8.5688357e-01 1 1 -1.2641917e+00 9.3227434e-01 -1.2592953e+00 -2.6848955e-01 -7.0202157e-01 -1.3081317e+00 1.0835712e+00 1.2720921e+00
+1 5.3023062e-01 1 1 -6.7819829e-01 -1.5293812e+00 -6.6525857e-02 -1.1768003e+00 9.4543648e-01 -9.0428670e-01 -2.3148125e-01 1.5135730e+00
+1 8.6565788e-01 1 1 -7.8057960e-01 2.0100394e-01 3.0691227e-01 9.8434822e-01 -2.2477635e-01 6.7865423e-01 -1.2137405e+00 1.1463866e+00
+1 9.8708443e-01 1 1 8.9599801e-02 1.0611151e+00 -2.2053718e-01 3.1365774e-01 1.5198493e+00 -9.8125785e-01 -9.7517703e-01 -6.8730688e-02
+1 6.0540201e-01 1 1 1.0809711e+00 -6.5917060e-01 5.1091382e-01 5.3240170e-02 -1.8308952e-01 1.3607669e+00 -1.1145868e-01 9.4942727e-01
+1 5.9256663e-01 1 1 5.0150178e-02 -1.4245744e+00 9.5578897e-01 -5.4636812e-01 -1.5663391e+00 -3.8501004e-01 -8.9679419e-01 8.7509696e-01
+1 3.2314324e-01 1 1 9.2721715e-01 -7.4466312e-01 9.8205802e-01 6.6329671e-02 1.0844098e+00 8.1713566e-01 9.4164577e-01 -1.1821689e+00
+1 5.8793666e-01 1 1 1.4391062e+00 5.5205187e-01 -4.7859247e-01 -4.6261927e-01 1.2972645e+00 -1.4439665e+00 -1.1033930e+00 -1.2801702e+00
+1 1.0035491e+00 1 1 -6.4261845e-02 1.2126491e+00 -1.2264503e+00 1.9975012e-01 4.7100469e-01 5.9083453e-02 9.4945382e-02 9.4813887e-01
+1 7.5430004e-01 1 1 6.5905046e-01 1.4820192e+00 -9.6073264e-01 -1.1622863e+00 -6.3761471e-01 2.7230834e-01 -1.8202491e-01 1.2120945e+00
+1 6.1543131e-01 1 1 -5.9460548e-01 -1.3914777e+00 7.5268548e-01 -1.2198429e-01 -4.1783426e-01 -6.1427230e-01 6.1851358e-01 -1.5567862e+00
+1 1.0248996e+00 1 1 -1.2799492e-01 -5.4987954e-01 -8.0872461e-01 1.2700228e+00 -1.0808160e+00 -8.0110281e-01 -1.7237782e-01 1.4188063e+00
+1 3.2959757e-01 1 1 7.8037730e-01 7.4014871e-01 1.4369199e+00 1.2933906e+00 -5.8583705e-01 7.3126744e-01 -6.0558241e-01 1.1897720e+00
+1 2.5082645e-01 1 1 -3.4803239e-01 -1.0275192e+00 8.9016719e-01 1.3354571e+00 -4.1195153e-01 5.0131937e-01 7.3663972e-01 2.6147264e-01
+1 4.3966042e-01 1 1 2.6521526e-01 -1.7970685e-01 7.7570271e-01 1.4893988e+00 4.0085603e-01 -7.6812054e-02 -3.1283609e-01 -5.1740372e-01
+1 8.2658311e-01 1 1 -4.4716712e-01 -1.2625152e+00 -3.7408951e-01 1.1501888e-01 -1.5288962e+00 2.1439730e-01 1.1899982e+00 -7.5862279e-02
+1 4.9238139e-01 1 1 -8.4818380e-01 -7.7685515e-01 -9.9555929e-01 1.0427637e+00 -1.0724075e+00 -3.1349841e-02 9.2171030e-01 4.6929731e-01
+1 8.2366028e-01 1 1 1.1223653e+00 -1.4543907e-01 -2.4259749e-01 -1.2157639e+00 -6.3588672e-01 8.9079285e-01 -8.3732684e-03 -1.0592489e+00
+1 6.4999620e-01 1 1 1.4713115e+00 -2.3540390e-01 4.5118917e-01 -4.2518805e-01 3.5008701e-01 -1.2751868e+00 6.4214787e-01 6.0850393e-01
+1 7.5231258e-01 1 1 8.5611265e-01 -1.1681669e+00 -6.6830241e-01 9.8765520e-01 -2.9065954e-01 -1.1888830e-01 1.2085103e+00 1.2415401e+00
+1 1.1292861e+00 1 1 1.9088751e-01 -1.5688899e+00 -9.6481057e-01 -6.5463881e-01 6.1735903e-02 -1.0273006e-01 1.0357287e+00 1.0682513e-01
+1 4.3963759e-01 1 1 6.8033494e-01 -9.4600167e-01 1.3299874e+00 -6.5701043e-01 8.6974536e-01 1.2918224e+00 -7.2765615e-02 1.5604836e+00
+1 8.8394746e-01 1 1 -1.0078986e+00 1.5033856e-01 6.6599327e-01 3.2387865e-01 -2.0349491e-02 1.1220013e-01 -8.9214545e-01 1.0320717e+00
+1 9.2949341e-01 1 1 -2.8431872e-01 8.9969308e-01 -1.4574636e-01 -9.5164822e-01 4.1970196e-01 7.9193750e-01 5.3317217e-01 1.2957215e+00
+1 7.6430112e-01 1 1 -1.8226164e-01 6.5616912e-01 8.8312822e-01 -5.0338609e-01 1.0553021e+00 -8.3455194e-01 1.2024956e+00 -3.2819573e-01
+1 5.3027592e-01 1 1 -2.1860486e-01 1.2442686e+00 -1.2892773e+00 -1.0100658e-01 -9.6957913e-01 8.9679392e-01 4.7829607e-01 6.5113975e-01
+1 9.6997740e-01 1 1 -1.5700012e+00 -1.1594074e+00 -1.3186569e+00 -1.1575286e+00 -2.7538350e-01 -9.4612065e-01 -6.1363182e-01 1.5385427e+00
+1 5.8372284e-01 1 1 -7.7283326e-01 1.1382229e+00 1.2694148e+00 1.3003590e+00 -8.0446940e-01 1.2922736e+00 5.3871853e-01 -1.6233477e-01
+1 4.3533605e-01 1 1 1.4769628e+00 9.5420829e-01 4.9815253e-01 -9.2667969e-01 6.9763297e-01 1.4124893e+00 1.7238607e-01 -1.4580256e+00
+1 1.0962874e+00 1 1 -1.5517484e+00 -4.5178886e-01 1.0510588e-01 1.3107497e+00 6.9362554e-01 -1.3081079e+00 7.4422999e-01 -6.1373092e-01
+1 5.0463876e-01 1 1 1.2668680e+00 1.4121515e-02 9.3949580e-01 9.2308705e-01 -6.8592790e-01 -5.0427650e-01 -1.5484670e+00 -1.1268227e+00
+1 4.6287688e-01 1 1 -1.4652587e+00 -1.4207339e+00 4.6126732e-01 1.1395279e+00 1.2547563e+00 6.4182000e-01 -1.3197618e-01 -9.8927693e-01
+1 6.0247126e-01 1 1 3.4196574e-01 9.7183834e-01 -9.3079879e-01 8.9625165e-01 -8.2286803e-01 -1.1603701e+00 -1.5926081e-01 -1.4691021e+00
+1 3.9715159e-01 1 1 1.4451626e+00 5.4672793e-01 1.1961414e+00 -6.3525142e-01 -6.5207170e-01 6.6646320e-01 -5.9494644e-02 -1.4226038e+00
+1 3.4665552e-01 1 1 1.1946208e+00 -3.0212983e-01 4.9746767e-01 -1.5387970e+00 -1.4939206e+00 1.4691123e+00 -9.0001289e-01 9.5921738e-01
+1 6.7430396e-01 1 1 7.3837710e-02 -1.0823515e+00 1.1610471e+00 -9.7012588e-01 -7.1565993e-01 -1.5484762e+00 2.5192060e-01 -1.0869161e+00
+1 7.4267051e-01 1 1 6.1292313e-02 -1.2596424e+00 1.2870563e+00 -3.9849648e-02 1.0618404e+00 -2.8515484e-01 -8.3736748e-01 5.6159078e-01
+1 7.8445267e-01 1 1 -3.0249334e-01 3.8269176e-01 -1.4524788e+00 -5.9379616e-01 -1.0362083e+00 1.4730475e+00 6.9978923e-01 1.3119176e+00
+1 6.0405980e-01 1 1 -9.0858497e-01 1.0602051e+00 1.5050054e+00 9.0775158e-01 1.4367074e+00 -1.3825992e+00 -7.6528498e-01 -1.4399256e+00
+1 7.6670162e-01 1 1 6.9423963e-01 -2.4701813e-01 -1.4777484e+00 1.0068264e+00 4.5957458e-01 1.0153474e+00 -4.6434724e-01 -1.1413826e+00
+1 7.0675138e-01 1 1 2.1036378e-01 1.5517163e+00 9.1453687e-01 1.1132295e+00 -1.1063883e+00 -1.8755390e-01 -5.6797445e-01 -6.5338634e-01
+1 8.2299637e-01 1 1 1.2922739e+00 1.3358456e+00 -1.1916990e+00 -1.2783044e+00 1.9110879e-02 -1.2009466e+00 1.3534625e+00 1.5436478e+00
+1 1.2506521e+00 1 1 1.4168167e+00 -1.4052231e+00 -1.2316938e+00 8.8972722e-01 7.5409849e-01 4.2345783e-01 -6.2868013e-01 8.1570834e-01
+1 1.1360972e+00 1 1 -8.3482474e-01 9.0887022e-01 -1.1232612e+00 -3.3565792e-01 9.4852271e-01 1.3484223e+00 -1.0509096e+00 -3.0020749e-01
+1 1.1923939e+00 1 1 -5.4657269e-01 9.5834001e-01 -8.2122805e-01 8.9771926e-01 1.3800172e+00 -5.1652395e-01 -6.0346608e-01 -1.8955563e-01
+1 8.2501450e-01 1 1 -2.3021317e-01 -1.2504163e-01 -1.3632957e+00 -1.1018525e+00 -4.2989114e-01 -9.9756121e-01 -1.3932818e+00 -2.8654977e-01
+1 7.2938236e-01 1 1 1.2493376e+00 1.5082778e-01 -1.2748960e+00 8.5310966e-01 4.8266275e-01 6.6877509e-01 5.4404933e-01 1.9502058e-02
+1 8.2124895e-01 1 1 -7.8866976e-01 -3.0273493e-01 -1.5150352e+00 -1.4866094e-02 5.2065537e-01 -5.1557646e-01 -1.3391134e+00 1.0454493e+00
+1 1.1595476e+00 1 1 -7.9329798e-01 1.3140874e+00 -5.8846835e-01 1.4729738e+00 1.3191943e+00 -7.8106650e-01 -1.0874092e-01 -6.1818736e-02
+1 6.7969050e-01 1 1 -3.9914246e-02 4.7087717e-01 -6.5390589e-01 5.2055750e-01 1.4789905e+00 1.3309740e+00 7.9829207e-01 8.7966722e-01
+1 1.0989807e+00 1 1 1.4620967e+00 3.6070613e-01 -9.0513711e-01 -3.2564451e-01 1.1123631e+00 1.5410087e+00 -8.4740461e-01 2.3196641e-01
+1 1.0303979e+00 1 1 -7.9057352e-02 -8.8590781e-01 -1.0477485e+00 -4.5293567e-01 -1.3089441e-01 4.4287598e-01 -1.4898310e+00 -5.7015539e-02
+1 8.9133302e-01 1 1 1.7677940e-01 -1.4450389e+00 -8.8245453e-01 -4.1081987e-01 -8.2746919e-01 9.8358294e-01 -1.0957720e+00 -7.4401911e-02
+1 9.9174819e-01 1 1 -8.1531681e-01 8.8442904e-01 4.5587685e-02 5.7117171e-01 5.5593055e-01 1.7864965e-02 -6.2317283e-01 -1.1903535e-01
+1 6.0822335e-01 1 1 5.9753298e-01 -1.4175289e+00 -3.5638434e-01 -1.0242849e+00 4.2812991e-01 -1.3364333e+00 4.0409357e-01 5.6739997e-01
+1 5.9371007e-01 1 1 -9.3488054e-01 1.4304432e+00 1.2656119e+00 7.7066790e-01 1.3321647e+00 9.5228897e-01 -5.2270837e-01 1.5576370e+00
+1 8.8968257e-01 1 1 -1.4324450e+00 -1.1493774e+00 -5.8532523e-01 -1.7108339e-01 -4.3866395e-01 -1.2938612e+00 -1.2665811e+00 3.1396452e-01
+1 1.2484089e+00 1 1 -1.0792936e+00 6.6830088e-02 -1.2345063e+00 -8.4128038e-01 6.9300509e-01 1.7972092e-01 3.6604763e-03 -1.0740450e+00
+1 1.3882997e+00 1 1 -1.3233357e-01 -1.4768810e+00 -1.2696899e+00 9.0921232e-01 1.4526643e+00 1.4990201e+00 -1.3102276e+00 1.1681595e-01
+1 4.6252633e-01 1 1 1.1732962e-01 -2.1458022e-01 1.1604634e+00 4.2486184e-01 -1.5285150e+00 -1.5416900e+00 1.5685288e+00 -1.6974954e-01
+1 2.4524499e-01 1 1 -9.6122602e-01 9.8600157e-02 9.0178628e-01 -1.8718393e-01 -9.4856975e-01 6.7195176e-01 1.1600667e+00 -4.1435158e-01
+1 6.8884507e-01 1 1 -1.2562578e+00 1.5535112e+00 1.2789681e+00 -1.2660620e+00 9.7087365e-01 -5.3234175e-01 5.1685637e-01 9.0394081e-01
+1 7.0041102e-01 1 1 7.1914296e-01 8.6795707e-02 8.3931051e-01 -6.9637597e-01 4.1185352e-02 1.8816804e-01 3.0124159e-01 -2.0895543e-01
+1 1.4556544e-01 1 1 9.2884194e-01 1.0764601e+00 5.4076887e-01 -1.5582657e+00 1.0518279e+00 -1.0436168e+00 -1.2799763e+00 3.8673678e-01
+1 9.1970080e-01 1 1 4.7251890e-01 -3.6797961e-01 7.4827342e-02 -1.4556617e+00 3.2885477e-01 -5.5516638e-01 1.0651701e+00 -7.0187331e-02
+1 3.2850497e-01 1 1 -3.2108687e-01 1.1625780e+00 9.8607234e-01 1.4177174e+00 1.0005956e+00 -1.5124473e-01 1.5189526e+00 -1.5412335e+00
+1 6.6866406e-01 1 1 7.4913445e-01 -1.2580088e+00 1.0164965e+00 -1.4037210e+00 6.5186713e-02 -4.2176968e-01 4.5435605e-01 -1.0807638e+00
+1 1.0494967e+00 1 1 -8.0063033e-01 -4.3526551e-01 2.7625995e-01 1.0217663e+00 -8.2274862e-01 -1.2500368e+00 -8.4963025e-01 2.9133818e-01
+1 9.2741191e-01 1 1 -7.5266017e-01 1.2618305e+00 -1.7301803e-01 8.8135929e-01 1.3547654e+00 -1.5380598e+00 -1.1969715e+00 -1.2220747e+00
+1 5.9862377e-01 1 1 1.2342072e+00 -1.3062146e+00 1.2006884e+00 3.9617200e-01 -7.2169821e-01 -1.1462611e+00 1.2600015e+00 3.2380731e-01
+1 6.2661870e-01 1 1 -6.1563276e-01 -9.9291987e-02 1.5198787e+00 1.4279039e+00 1.0744640e-01 -9.6334846e-01 -6.3012169e-01 9.9099567e-01
+1 5.3690438e-01 1 1 1.4663433e+00 -6.1472831e-01 3.1062275e-01 1.5508420e-01 -5.6419227e-01 7.7093814e-01 -1.4648305e-01 -1.0599608e+00
+1 8.1866999e-01 1 1 -9.6252400e-01 9.5957904e-01 -6.9050736e-01 -1.0218111e+00 -1.0529064e+00 1.2292309e+00 1.0679427e+00 1.2111544e+00
+1 8.1705940e-01 1 1 -1.0803315e+00 -1.2917364e+00 -3.1400831e-01 1.5072976e+00 3.9290468e-01 5.7071640e-01 9.9402603e-01 1.4927724e+00
+1 9.0533195e-01 1 1 1.2742795e+00 1.3338998e+00 3.3797609e-01 -6.5279710e-01 -7.8831436e-02 7.4819879e-01 -3.9417946e-01 2.6740982e-01
+1 8.2475491e-01 1 1 5.7901052e-01 4.4902189e-01 3.6459027e-01 -1.1193417e+00 8.3214878e-01 -8.1836159e-01 6.4476095e-01 -1.2622110e+00
+1 6.3329051e-01 1 1 -1.2242553e+00 6.0529390e-01 1.5629499e+00 -9.1845946e-01 -4.4603085e-01 -3.1065417e-01 1.1442303e+00 1.1957031e+00
+1 8.8187021e-01 1 1 1.3729711e+00 6.9759287e-01 -1.4988764e+00 1.2382315e+00 -6.0036907e-01 1.6227458e-01 1.3893439e+00 -5.8547008e-01
+1 5.0732564e-01 1 1 5.2676026e-01 1.9565690e-02 8.1518139e-01 1.0463054e+00 3.9267067e-01 4.4645639e-01 -7.5587984e-01 -5.2751997e-01
+1 8.0305279e-01 1 1 2.5165047e-01 -1.0266712e+00 2.6813956e-01 -1.3807003e+00 -8.7029132e-01 1.4692501e+00 5.2830363e-01 -4.5364284e-01
+1 9.4317809e-01 1 1 9.0580408e-01 1.5063728e+00 -1.5638149e+00 1.5144765e+00 2.6916046e-01 7.6816046e-01 1.0582517e+00 2.7014101e-01
+1 9.2405315e-01 1 1 -3.0879662e-01 -4.8786958e-01 -4.7339895e-01 6.2366517e-01 -1.1350672e-01 -1.4728759e+00 1.4796190e+00 6.5858639e-01
+1 5.6823524e-01 1 1 -3.3727403e-02 -6.7150047e-02 1.2380650e+00 -1.5541261e+00 -7.6075639e-01 1.1245272e+00 -8.9166303e-01 1.0305268e+00
+1 7.6136260e-01 1 1 -1.3697842e+00 -7.5908070e-01 1.3910722e+00 -9.9641369e-01 2.4941981e-01 1.0676687e-01 -7.8353744e-01 4.6335291e-01
+1 4.0646879e-01 1 1 -3.7200479e-01 1.3837097e-01 1.7499807e-02 1.1056167e+00 1.1141818e+00 5.8141872e-01 6.4260917e-01 -4.3580445e-01
+1 8.5135328e-01 1 1 -5.1514520e-01 8.2241038e-01 -1.1904505e+00 -4.2055513e-01 -9.8101597e-01 1.5513020e+00 -4.6328861e-01 -1.5129323e+00
+1 2.9676016e-01 1 1 1.8392614e-01 -7.5649978e-01 9.0277550e-01 3.1334411e-01 -8.5713555e-01 6.5505717e-01 1.5165376e+00 1.9813094e-01
+1 4.1863182e-01 1 1 -8.0487378e-02 -4.6628793e-01 -9.4472900e-01 1.0651373e+00 1.4667370e+00 1.4051680e+00 7.0704412e-01 -1.0148058e-01
+1 6.4704032e-01 1 1 1.2750765e+00 1.3723506e+00 -4.5104579e-01 9.6807494e-01 -6.2932570e-01 1.3064956e+00 -1.3544347e+00 3.0072991e-01
+1 8.7249415e-01 1 1 1.4073143e+00 -4.7756786e-01 -6.3492486e-02 1.2718007e-01 6.6549475e-01 -1.4610487e+00 -3.6097950e-03 -4.5496277e-01
+1 7.5563338e-01 1 1 -3.2022299e-01 2.8626039e-01 1.0232942e+00 1.2324798e+00 9.0040500e-01 -1.1570185e+00 -9.7956383e-01 7.7233791e-02
+1 5.1337096e-01 1 1 -4.3963134e-01 1.3999782e+00 1.4271634e+00 -1.3735470e+00 5.4993921e-02 4.4884040e-01 1.5577719e+00 5.9055684e-01
+1 9.0030062e-01 1 1 1.4197607e-01 -1.0957894e+00 2.7469324e-01 -7.8188986e-01 6.5458405e-01 6.9668891e-01 -5.6070697e-01 1.1976814e+00
+1 9.0271712e-01 1 1 -1.4185313e+00 -9.1585963e-01 -1.3718353e+00 5.9238984e-02 -2.6341380e-01 5.3471421e-01 9.7593533e-01 1.2464609e+00
+1 7.1526455e-01 1 1 2.9158189e-01 9.5126458e-01 -2.8669052e-01 -2.5526474e-01 -6.9175644e-01 -1.1549194e+00 2.8992103e-01 1.1284164e+00
+1 2.7645144e-01 1 1 -2.6774875e-01 3.3885642e-01 7.9552944e-01 1.1810984e+00 6.8387026e-01 1.1700376e+00 9.2614950e-02 -4.9988806e-01
+1 8.3290396e-01 1 1 -1.2925000e+00 -5.4769174e-01 -1.5506337e-01 -1.0039413e+00 -1.2800601e+00 -1.5485258e+00 1.4910940e+00 -9.9987285e-01
+1 4.1776307e-01 1 1 1.0657923e+00 -1.8858663e-01 1.3718354e+00 2.5194074e-01 -3.4363096e-01 -1.1187614e+00 3.3223460e-01 -4.8385066e-01
+1 5.9173541e-01 1 1 -5.9020870e-01 2.9150065e-01 2.8954264e-01 -4.9892379e-01 -1.1582656e+00 -5.9151046e-01 1.2568186e+00 1.5054134e+00
+1 6.4392147e-01 1 1 1.5120523e+00 1.5084885e+00 1.6206030e-02 -5.0138681e-01 1.4792971e+00 -1.5171967e+00 -7.1900789e-01 -9.0391452e-01
+1 7.8244376e-01 1 1 7.1985531e-01 5.1418791e-01 -9.4381116e-01 -1.0566362e+00 -1.7921710e-02 7.8264105e-01 1.3413985e+00 6.5078856e-01
+1 6.7208067e-01 1 1 3.3489539e-01 -5.6515552e-01 -7.3278741e-01 5.3802793e-01 3.8271795e-01 -3.6908180e-04 8.1594379e-01 -1.2222341e+00
+1 1.3238454e+00 1 1 -1.1472634e+00 -1.5341814e+00 -9.1472103e-01 1.1316994e+00 1.5004646e+00 8.0027549e-02 5.1529873e-01 7.8533900e-01
+1 7.0416095e-01 1 1 1.0397517e+00 1.2058704e+00 1.2381239e+00 1.2692672e+00 7.4457687e-01 4.2135882e-01 -7.4511001e-01 1.3617564e+00
+1 1.1250895e+00 1 1 1.5679537e+00 6.4893076e-01 -7.6152237e-01 1.1593328e+00 1.1398511e+00 6.2786436e-01 -6.7560652e-01 5.3807346e-01
+1 8.6910048e-01 1 1 9.1944358e-01 -1.0303874e+00 -5.7928982e-02 7.4868169e-01 4.5474840e-02 -9.3488032e-02 -1.2029485e+00 -1.2445655e+00
+1 2.8391872e-01 1 1 -4.0597331e-01 -1.2622219e+00 2.8132278e-01 1.0145369e+00 8.8862052e-01 -4.5703127e-01 1.3343387e+00 -6.8878846e-01
+1 9.1959843e-01 1 1 3.4589367e-01 1.0123805e+00 9.5092412e-02 -1.2433882e+00 -8.6416519e-02 -1.3055672e-01 1.5416716e+00 3.0125064e-01
+1 8.7289780e-01 1 1 1.4885211e+00 2.1328489e-01 -8.5249917e-01 2.4904325e-01 -9.8662649e-01 -1.4350534e+00 -9.8148083e-01 -1.1279286e+00
+1 3.3429183e-01 1 1 1.0726152e+00 1.2190288e-01 8.5055017e-01 1.0684823e+00 -9.0534965e-01 -9.3530172e-01 7.5471959e-01 -7.2653712e-01
+1 5.3827048e-01 1 1 9.8519383e-01 5.0333774e-01 9.5011917e-01 6.3892432e-01 -1.4782674e+00 9.1365957e-01 -1.1790299e+00 4.6121747e-01
+1 4.6156103e-01 1 1 -1.1821046e+00 -7.1167626e-01 -6.2530365e-02 4.3732751e-01 -1.5248311e+00 -2.2857052e-01 1.2116581e+00 1.3730074e+00
+1 5.1891933e-01 1 1 -2.0054339e-01 -1.0997419e+00 1.4856861e+00 -1.1634288e+00 1.2770152e+00 5.8313290e-01 5.3395504e-01 1.1377292e+00
+1 5.2069963e-01 1 1 3.9608994e-01 -1.3717187e+00 5.4815734e-01 -4.7458994e-01 -5.6723621e-01 -1.0544240e+00 -1.3479129e+00 -1.0599721e+00
+1 1.3120422e+00 1 1 4.8755109e-02 -1.4697601e+00 -1.4109011e+00 7.0612874e-02 1.1947597e+00 2.0047420e-02 -3.4689486e-01 1.0209473e+00
+1 7.4347033e-01 1 1 -5.2856572e-01 8.5693905e-02 -2.7365272e-01 -7.3145349e-01 -7.3444816e-01 7.8658211e-01 5.3400292e-01 -3.1781875e-01
+1 7.5227336e-01 1 1 8.2000234e-01 1.4080196e+00 1.0388960e-02 -4.8675956e-01 -5.5270999e-01 2.6358642e-01 -5.4309795e-01 -8.7227360e-01
+1 9.5218002e-01 1 1 -3.8771064e-01 -1.0317704e+00 -1.3219330e+00 -2.6070130e-01 2.9274732e-01 4.5136261e-01 -1.5205333e+00 1.5104941e+00
+1 9.1591989e-01 1 1 -5.8959116e-01 6.2589193e-01 -3.8491795e-01 9.1506154e-01 4.7016392e-01 -8.9482902e-01 1.2534635e+00 -3.3534770e-01
+1 1.1017060e+00 1 1 -6.7537026e-01 1.3135146e+00 -7.7678706e-01 1.3431905e+00 9.3948234e-01 -5.8730972e-01 -5.5953397e-01 -1.7161374e-01
+1 7.6949876e-01 1 1 -3.7374720e-01 2.6868396e-01 9.9897514e-01 -4.8245277e-01 2.3494155e-01 -3.0323999e-02 -1.3006777e+00 -3.3007412e-01
+1 6.7136523e-01 1 1 -1.5254231e+00 1.3026092e+00 1.1040114e+00 -1.3311506e-01 -3.1925592e-01 -7.1743582e-01 -1.2879402e+00 4.9684698e-01
+1 6.6971371e-01 1 1 7.5100768e-01 -8.0632565e-01 8.7299359e-01 -4.5079170e-01 1.0603766e-01 -5.1121542e-01 -8.3780824e-01 1.5391606e-01
+1 6.1698553e-01 1 1 -7.3327813e-01 9.1554221e-01 1.1655221e+00 1.0654522e+00 8.9184953e-01 2.5836302e-01 -4.2487311e-01 1.3364070e+00
+1 1.7686445e-01 1 1 2.6245586e-01 -2.8763332e-03 1.0993804e+00 -2.3218086e-02 7.7645216e-01 6.2614670e-01 -2.2363534e-03 -1.3950072e+00
+1 9.7818116e-01 1 1 2.9963491e-01 -1.2186424e+00 -1.5608001e+00 -6.6888611e-01 -3.4440469e-01 -6.8772487e-01 1.1272092e-01 -1.8084423e-01
+1 1.0330601e+00 1 1 -9.0724291e-03 1.4613362e+00 -6.8980247e-02 -1.3502527e+00 1.5455674e+00 -6.7247909e-01 1.2020099e-01 -1.5288196e+00
+1 4.2327299e-02 1 1 1.4577240e+00 -2.9435143e-01 -1.0332147e-01 1.1687672e+00 -1.4786241e+00 1.0942469e+00 1.7402867e-01 2.1542422e-01
+1 5.0670241e-01 1 1 -1.3135130e+00 8.4396434e-01 7.7683001e-01 -9.0836729e-01 -1.2371518e+00 1.2492053e-01 7.7140176e-02 1.5200858e+00
+1 1.0715221e+00 1 1 -2.4225265e-01 2.1783437e-01 -2.7711765e-01 1.2113056e+00 1.3917224e+00 9.5543114e-01 -9.8283136e-01 6.5031624e-01
+1 2.8593780e-01 1 1 -3.6163292e-02 1.1868007e+00 1.4655667e+00 8.9362583e-01 1.5206789e+00 1.2511739e+00 4.7422214e-02 2.6417678e-01
+1 5.6558008e-01 1 1 -1.4690628e+00 5.8690229e-01 -1.4489910e+00 -7.8507730e-01 1.1945429e+00 -1.3410150e+00 -9.3938986e-01 9.4879969e-01
+1 4.1850913e-01 1 1 -7.6194404e-01 -5.3411753e-01 4.3424960e-01 -1.0503176e-01 -1.2363930e+00 -6.5284017e-01 1.3192932e+00 -2.4784012e-01
+1 1.4137050e-01 1 1 -8.6175211e-01 -1.3830683e+00 5.1327190e-01 3.0629170e-01 -1.5635154e+00 1.2983282e+00 -5.5226401e-04 3.0294578e-01
+1 1.2575211e+00 1 1 -7.2560981e-01 -5.8534896e-01 -2.5267982e-01 -1.2257750e+00 1.4190540e+00 -5.0093017e-01 1.4287674e-01 -9.1189310e-01
+1 6.3772068e-01 1 1 3.3867839e-01 1.5081826e+00 6.4353809e-01 9.6367549e-01 -9.3019935e-01 3.3501920e-01 1.1526653e+00 -1.4983575e+00
+1 4.1065849e-01 1 1 -3.9814785e-01 -1.4866949e+00 -5.5885546e-01 -1.5577881e+00 -1.2953764e+00 9.3372888e-01 -1.3564576e+00 1.1271081e-01
+1 4.6082917e-01 1 1 -7.8558411e-02 1.3466113e+00 6.7828960e-01 2.8914064e-01 -1.5431304e-01 9.2594770e-01 5.5503390e-01 -4.9770763e-02
+1 1.2028231e+00 1 1 -8.6229083e-01 4.6277909e-01 -8.2642355e-01 -4.5716427e-01 1.4161988e+00 -1.0469364e+00 1.0661164e+00 -8.3357256e-01
+1 1.1464483e+00 1 1 -3.5511646e-01 -6.5518416e-01 -7.1946033e-01 7.7575858e-01 1.3480246e+00 2.0069621e-01 -1.4262577e+00 -1.4923754e+00
+1 8.7764872e-01 1 1 5.8365505e-01 -3.9797116e-01 2.0406870e-02 5.6489810e-01 -9.1704219e-01 -9.6934615e-01 -7.6183687e-01 1.2187203e-01
+1 4.5902988e-01 1 1 1.4381016e+00 -2.5045212e-01 5.4465972e-01 3.4944822e-01 -7.4491184e-02 4.9874237e-01 9.3943710e-01 -1.5133903e-02
+1 1.1523879e+00 1 1 -1.2401024e+00 3.8532203e-01 -5.0512582e-01 1.5394855e+00 1.5221441e+00 5.9374072e-01 -5.2534583e-01 1.1349894e-01
+1 5.5968526e-01 1 1 -1.0757440e+00 1.2848746e+00 -1.0663390e+00 -2.4642246e-02 6.8683186e-01 1.3020821e+00 1.5296186e+00 6.2992756e-01
+1 4.5782274e-01 1 1 -1.6449878e-01 -4.2091954e-01 8.2665227e-01 5.2800593e-01 1.3717125e+00 -2.4033897e-01 6.4710500e-01 2.5247404e-02
+1 6.8667491e-01 1 1 -1.2937842e-01 4.7196485e-01 1.4220618e+00 -8.0356560e-01 1.3643545e+00 7.1112511e-01 -3.0000581e-01 2.1810674e-01
+1 6.3581777e-01 1 1 -4.8094490e-01 -2.0826806e-01 -6.4357823e-01 1.7982903e-01 2.2061839e-01 1.2613418e+00 5.8550302e-02 -5.1862946e-01
+1 9.3428505e-01 1 1 7.7023687e-02 -6.2701272e-01 -1.1576989e-01 1.7445089e-01 8.5387604e-01 -9.5623613e-02 7.3642998e-01 1.3143307e+00
+1 1.0655022e+00 1 1 2.0092662e-01 -1.3010240e+00 -1.0987323e+00 8.9015894e-01 2.9941631e-01 1.3493711e+00 -6.9634408e-01 1.4177777e+00
+1 1.0453433e+00 1 1 -2.3844470e-01 -8.2527337e-01 -1.1237980e-01 6.3712889e-01 -5.4153007e-01 -2.7812200e-01 -1.0223863e+00 -3.8981600e-01
+1 8.5266194e-01 1 1 1.1321897e+00 -2.3791906e-01 -6.7012804e-01 -1.4641404e+00 -3.0202165e-01 2.9348794e-01 1.2652484e+00 -1.4168332e+00
+1 1.0755741e+00 1 1 8.5574659e-02 5.4173869e-01 -2.3233907e-01 2.8748005e-01 7.3577837e-01 3.5139084e-01 -4.1069818e-01 5.5674278e-01
+1 7.1589008e-01 1 1 -5.9613746e-01 6.6667122e-01 7.6890346e-02 -9.2251929e-02 9.1836732e-01 -3.6835975e-01 -5.2525231e-01 1.5129772e+00
+1 8.9532837e-02 1 1 -7.4333178e-01 -1.3177887e+00 1.1014639e+00 1.4685938e+00 3.5490448e-01 1.0568611e+00 -4.0282367e-02 5.5632926e-01
+1 7.3202031e-01 1 1 9.3683810e-01 1.5406654e-01 -1.1016786e+00 -8.3786718e-01 -1.0049045e+00 9.8851829e-02 1.5582658e+00 8.4612969e-01
+1 6.1596786e-01 1 1 -2.2446257e-01 7.2395869e-01 6.3486895e-01 -1.4154940e+00 -2.2773604e-01 -4.9982867e-01 1.4561780e+00 -1.0882909e+00
+1 4.8937035e-01 1 1 5.1041085e-01 1.8533813e-01 1.3938142e+00 1.0738085e+00 -1.0998123e+00 -1.6545099e-03 9.7709841e-01 -5.5255205e-01
+1 9.9965914e-01 1 1 -1.2144222e+00 -1.4818963e+00 -1.0214727e+00 -9.5049217e-01 5.8560376e-01 4.6698637e-01 9.8812527e-01 -1.9447805e-01
+1 3.1986581e-01 1 1 1.3377435e-01 3.1582991e-01 9.1242501e-01 7.6799276e-02 -3.6738683e-01 9.4142150e-01 9.6262937e-01 -1.3362689e+00
+1 5.7860039e-01 1 1 -1.0347628e+00 -1.1382593e+00 1.0133858e+00 -4.2914247e-01 -1.4409594e+00 1.4105155e+00 -2.9038805e-01 5.7432940e-01
+1 4.0879031e-01 1 1 5.9832223e-01 -1.5657673e+00 1.4017879e+00 4.9931632e-01 3.3279626e-01 7.6102350e-02 1.4829494e+00 -1.3600700e+00
+1 8.2587405e-01 1 1 -2.3637296e-01 1.2704738e+00 1.0460436e+00 8.1545623e-01 1.2717798e+00 4.2397843e-01 -1.4658011e+00 -4.6801251e-01
+1 7.8783674e-01 1 1 1.3942935e+00 -5.5189607e-01 5.0281534e-01 -1.3959594e+00 -5.9357594e-01 6.7341565e-01 6.4966321e-01 6.6171761e-01
+1 5.9311271e-01 1 1 7.5079361e-01 1.4058699e+00 -6.6838228e-02 -4.7503469e-01 1.4675011e+00 -1.0615420e+00 -1.2865541e+00 2.4981062e-01
+1 6.7585509e-01 1 1 -1.1895644e+00 5.3770902e-01 1.3400774e+00 -1.1210252e+00 -3.5320273e-01 -2.3230613e-01 4.6735305e-01 1.3992382e+00
+1 6.5188812e-01 1 1 8.6285472e-02 -1.0865840e+00 6.0334217e-01 -9.3895248e-01 1.3318778e+00 6.3059554e-01 8.2100937e-01 -9.6617331e-01
+1 1.2636813e+00 1 1 -1.2158760e+00 -1.4001510e-01 -6.8925945e-01 -7.5445831e-01 1.0220000e+00 -1.3144555e+00 8.2951030e-01 4.1763221e-01
+1 7.9093530e-01 1 1 8.3144658e-01 -1.8089131e-01 -1.3315075e+00 -7.1279631e-01 -1.4754120e+00 -3.7328202e-01 -8.0856115e-01 8.2661243e-01
+1 6.5432322e-01 1 1 3.1852673e-01 8.2138279e-01 -1.0823946e+00 -1.0747609e+00 -6.5939702e-01 9.6006435e-03 1.0426098e+00 7.5235394e-01
+1 5.9302315e-01 1 1 2.0483572e-01 8.2242087e-01 1.1574865e+00 6.5155637e-01 1.0531662e+00 1.1367896e+00 -6.6084978e-01 -9.7800154e-02
+1 6.6763610e-01 1 1 -5.1159798e-01 -5.8008616e-01 1.1337597e+00 -8.8415126e-01 8.3215161e-01 -1.1443840e+00 -1.3722646e+00 -6.7423809e-01
+1 7.4214911e-01 1 1 1.1185581e-01 -1.1460346e+00 1.3403771e+00 -1.9690375e-01 -3.9838073e-01 -8.3192185e-01 -1.2187362e+00 -1.9487516e-01
+1 6.1311972e-01 1 1 1.2881168e+00 -2.9839005e-01 -6.4328960e-01 -1.2642481e+00 -8.5096317e-01 1.1183900e+00 -1.1578930e-01 1.4143945e+00
+1 1.3692629e+00 1 1 6.6384920e-01 -1.0597158e+00 -1.5479372e+00 1.5157028e+00 1.5334282e+00 6.3228444e-01 -1.4249561e+00 -7.0254050e-01
+1 5.5223104e-01 1 1 1.5180007e+00 -9.5489355e-01 -6.5097660e-01 -7.5703710e-01 -1.2976872e+00 -1.2032846e+00 -8.7695889e-01 -1.4929234e+00
+1 3.9192816e-01 1 1 1.6301771e-01 1.5010178e+00 1.2035028e+00 -7.2313755e-02 -1.2925061e+00 -1.1723288e+00 1.3046303e+00 3.3714598e-01
+1 1.1100496e+00 1 1 3.6989964e-01 6.1675982e-01 -1.4438136e+00 4.1908505e-01 9.6375515e-01 7.3960537e-01 -1.3945724e+00 -1.0206888e+00
+1 9.6595745e-01 1 1 -3.0863003e-01 -1.3734529e+00 -5.1380395e-01 1.1172912e-01 -2.1893777e-01 -7.3464781e-01 8.4436263e-01 1.5212382e+00
+1 5.9200684e-01 1 1 -3.7549452e-01 7.9956297e-01 7.3519274e-01 -8.4111570e-01 -8.8211497e-01 -7.6661504e-01 6.2870384e-01 1.1702382e+00
+1 3.2116001e-01 1 1 5.2318003e-01 -1.4784658e+00 5.0044545e-01 5.3530965e-01 -5.3064774e-01 -8.2742292e-01 1.4493954e+00 -1.3178276e+00
+1 4.7187809e-01 1 1 -2.3109080e-01 1.4233623e+00 9.4321134e-01 -5.7209079e-01 3.8505010e-01 1.3336749e+00 7.8607847e-02 -5.0027432e-01
+1 1.0085917e+00 1 1 -9.3463416e-01 -7.7773080e-01 7.6541184e-02 1.2852749e+00 -1.4391178e-01 -1.8977567e-01 -1.4484244e+00 -1.2086104e+00
+1 7.6742269e-01 1 1 -4.3300149e-01 8.4554677e-01 1.5162839e+00 2.4347517e-02 3.0098325e-01 -8.4322587e-01 5.3253703e-01 4.2271821e-01
+1 1.1351762e+00 1 1 -1.5274272e+00 -1.4606526e+00 -4.1550786e-01 8.0168161e-01 6.6136864e-01 -3.7277532e-01 -4.7533034e-02 1.4838901e+00
+1 9.4972395e-01 1 1 -1.5159704e+00 -7.8256275e-01 3.1984606e-01 -4.2802057e-01 6.6785158e-01 -8.9898498e-01 -9.2316916e-01 -1.3633176e+00
+1 8.1367386e-01 1 1 -5.9732361e-01 1.3163040e+00 3.8776051e-01 5.0553659e-01 -3.2906132e-01 -1.3214187e+00 6.2200622e-01 1.4980844e+00
+1 4.0830269e-01 1 1 1.3122171e+00 2.6658457e-02 1.4277464e+00 -1.4545811e+00 -1.3305280e+00 -1.1662891e+00 -1.1617498e+00 -1.5606506e+00
+1 8.3044866e-01 1 1 4.5301913e-01 -1.1990626e+00 6.4916942e-01 7.3010968e-01 -3.2714374e-01 -1.4238174e+00 -5.3068624e-01 -6.9839377e-01
+1 8.7050788e-01 1 1 -1.3280694e+00 6.7184606e-01 -1.6086295e-01 -1.0755933e-01 -5.1761616e-01 -5.8764086e-01 -2.6213587e-01 -9.1396000e-01
+1 3.7203320e-01 1 1 1.5395050e-01 8.3274731e-01 1.2877527e+00 -1.3339199e+00 -5.0473378e-01 6.8736195e-01 -1.2047004e+00 1.4622940e+00
+1 6.9656018e-01 1 1 -1.2262539e+00 1.8877528e-01 8.2719069e-01 -7.8714594e-01 -7.6045714e-01 8.5615425e-01 1.6498114e-01 9.5409726e-02
+1 6.4902196e-01 1 1 -8.0200142e-01 -2.6244265e-01 1.0465035e+00 -3.1520723e-01 -1.0041701e+00 8.9019848e-01 -1.1883147e+00 1.3390087e+00
+1 7.0250795e-01 1 1 1.3362824e+00 -7.7587328e-02 -1.1926119e+00 -9.6271447e-01 -4.5196390e-01 1.3016489e+00 -9.0050424e-01 1.4912378e+00
+1 1.1641846e+00 1 1 -3.4756106e-01 -2.4927732e-01 -8.6721601e-01 -1.1399023e+00 2.1377425e-01 -1.2385736e+00 1.4185987e+00 -3.9319219e-01
+1 6.5453696e-01 1 1 -1.2379642e+00 1.2806915e+00 -1.4512072e+00 -9.0556193e-01 -1.0781893e+00 -5.1349109e-01 8.4223521e-01 1.5298325e+00
+1 8.0824080e-01 1 1 3.0429345e-01 1.5313555e+00 8.8631165e-01 1.2370846e+00 -4.2182432e-01 -2.8980943e-01 -5.6928955e-01 1.1012522e+00
+1 9.8936315e-01 1 1 -2.5278676e-01 1.5646152e+00 -1.1924740e+00 6.2119192e-01 9.7324615e-01 -1.3584452e+00 1.2416932e+00 -1.5180352e+00
+1 7.1034139e-01 1 1 -1.1538647e+00 1.3569257e+00 1.4508467e+00 8.6013084e-01 -9.2497595e-01 -1.4349932e+00 -4.6202997e-01 -7.4337550e-01
+1 5.2369902e-01 1 1 4.7702419e-02 1.0290169e+00 -6.6226420e-01 -1.3903124e+00 -1.4704064e+00 7.6267504e-02 6.7938602e-01 2.0202312e-01
+1 6.9634901e-01 1 1 6.2843748e-01 2.1925916e-01 -1.1645929e-02 1.8613991e-01 -1.3522060e+00 5.8140382e-02 -1.2484151e+00 -6.5905933e-01
+1 9.3894196e-01 1 1 1.1418814e-01 4.5655845e-04 -9.5438018e-01 -5.7287254e-01 -2.4552450e-01 1.3009176e-01 5.8526317e-01 4.4550831e-01
+1 8.5111713e-01 1 1 -3.5301410e-01 1.3901925e+00 7.0432880e-01 7.1267871e-01 1.5224981e+00 -9.6306900e-02 1.9148998e-01 1.2427976e+00
+1 8.8927699e-01 1 1 1.3606161e+00 9.4077232e-01 1.3296032e-01 -9.0168634e-01 3.5278099e-01 -7.0984905e-01 1.3811825e+00 -7.5107815e-01
+1 2.5816714e-01 1 1 2.2239788e-01 -7.5427936e-02 9.9169107e-01 4.0056336e-01 1.0048345e+00 1.3358844e+00 3.0548904e-01 -4.5118873e-01
+1 5.2858221e-01 1 1 -6.5402859e-01 1.4861199e+00 1.2027681e+00 -1.6458981e-01 -9.4861702e-01 -7.5405400e-01 9.9182024e-01 6.7560482e-01
+1 8.1072251e-01 1 1 1.7410041e-01 1.5557351e+00 -1.2250933e+00 1.4822717e+00 1.7638538e-01 -2.0079942e-01 2.3220630e-01 1.1744273e+00
+1 5.1325678e-01 1 1 1.2828996e+00 -2.3542100e-01 -1.4495626e-01 -2.8889057e-01 -1.1543423e+00 -7.6528534e-01 8.3313762e-01 -2.6915395e-02
+1 1.4117899e+00 1 1 9.4337504e-01 -1.4556166e+00 -1.5455733e+00 1.5184694e+00 1.4452304e+00 -4.7032195e-01 4.6559499e-01 2.2295693e-02
+1 5.8504946e-01 1 1 -3.1385955e-01 -9.6658750e-01 1.3791440e+00 -1.3838779e+00 -8.0749964e-01 -4.5387972e-01 -4.5230312e-01 8.7418592e-01
+1 1.1625889e-01 1 1 -3.0331309e-01 -2.6057458e-01 6.0289305e-01 1.5166124e+00 3.3794049e-02 -5.6948532e-01 7.9573850e-01 -7.8612106e-01
+1 4.4683396e-01 1 1 1.0218556e+00 -9.6880645e-02 1.1871055e+00 -1.1780410e+00 -6.5168646e-01 1.0929690e+00 2.1708531e-01 1.2021013e+00
+1 1.1485744e+00 1 1 -7.5925465e-01 -9.2799940e-01 -5.7328065e-01 -1.0178907e+00 -1.3024187e+00 6.3788908e-01 1.1637544e+00 1.3371386e-01
+1 7.9353346e-01 1 1 3.5643957e-01 1.1216044e+00 1.3673035e-01 1.4238842e+00 8.6594561e-01 -1.2540342e+00 -3.3566706e-01 1.0900235e+00
+1 4.4803537e-01 1 1 -3.3734429e-01 1.2486412e+00 1.5226930e+00 -1.4308793e+00 -1.0508171e+00 3.9163999e-01 7.4412262e-01 1.3987100e+00
+1 7.4126495e-01 1 1 8.2928107e-01 7.3966409e-02 4.8746588e-01 1.0290259e-01 9.5081783e-01 6.5675020e-01 -2.1140746e-01 -4.1889754e-01
+1 6.5197975e-01 1 1 -1.5196207e+00 -9.1726036e-01 -4.3461854e-01 -1.5337898e+00 -8.8661371e-01 -1.5559669e+00 1.6039356e-02 -1.0175084e-01
+1 5.7171131e-01 1 1 8.8352735e-01 -5.9976935e-01 -4.3092085e-01 1.5039335e+00 -7.4261332e-01 -5.1832202e-01 -6.0351927e-01 -1.0999286e+00
+1 6.6272555e-01 1 1 -8.6427013e-01 1.0474171e+00 -1.1156608e+00 -6.4473156e-01 4.4559255e-01 1.9823270e-01 8.5429332e-01 -1.3691083e+00
+1 5.4234602e-01 1 1 9.3642440e-01 -1.5466401e+00 1.2557381e+00 -6.5029671e-01 -4.8286373e-01 -1.5328323e+00 1.0293793e+00 1.5625087e+00
+1 9.4211006e-01 1 1 -8.9430969e-01 -8.4224538e-01 -2.9629867e-02 6.4038605e-02 -7.5691024e-01 -1.2528892e+00 2.7101389e-02 5.1084981e-01
+1 4.6501514e-01 1 1 -1.2837810e+00 3.9835889e-01 1.5240497e+00 -1.2694497e+00 -1.0817234e+00 7.8597023e-01 -3.7888167e-02 -1.2002677e-01
+1 7.0193342e-01 1 1 -4.9090909e-02 4.8397366e-01 1.2979314e+00 -1.0859357e+00 -1.2927999e-01 -5.9545555e-01 9.5688110e-01 -3.8742569e-01
+1 8.0823459e-01 1 1 1.1679658e+00 5.6193293e-01 -8.8613054e-01 1.3326021e+00 1.1733846e+00 1.2927025e+00 4.8785371e-01 1.0580464e+00
+1 6.1402545e-01 1 1 1.3306435e+00 7.7920163e-01 1.0948584e+00 6.2868548e-01 1.2976500e+00 -8.0325364e-01 -1.9954801e-01 1.1720856e+00
+1 6.0238604e-01 1 1 -8.7289102e-01 -1.2580559e+00 9.7693055e-01 1.1407760e+00 6.6744864e-01 -8.6024512e-01 1.4175963e+00 1.4568078e+00
+1 5.6569769e-01 1 1 5.5838936e-01 -1.2269754e+00 1.3085015e+00 -1.1716607e-01 -8.1814288e-01 -5.3042012e-01 -2.9837182e-01 -1.0040862e+00
+1 5.8790329e-01 1 1 9.1274012e-01 -3.6167609e-01 8.3563076e-01 5.6846491e-01 2.2364751e-01 1.0690145e+00 -7.5323556e-01 9.5941883e-01
+1 2.4611786e-01 1 1 2.6321807e-02 2.9167897e-01 1.5270716e+00 6.0650300e-01 1.4989549e+00 1.5766535e-01 9.8827326e-01 -8.4289170e-01
+1 5.5602382e-01 1 1 -5.7394769e-01 1.3639113e+00 -1.3196255e+00 -9.7230481e-01 5.0328606e-01 1.5189336e+00 3.0828436e-01 -1.0395165e+00
+1 2.6790146e-01 1 1 1.4921691e+00 -9.4473588e-01 6.9837171e-01 1.0381058e+00 1.5613713e+00 1.3570511e-01 8.4890601e-01 -7.5633231e-01
+1 8.0980981e-01 1 1 -4.4887850e-01 -5.6660593e-01 5.4311030e-01 -9.6142786e-01 2.4370949e-01 -5.6562191e-04 -1.5505937e+00 -7.9317976e-01
+1 9.0076336e-01 1 1 -1.3369659e+00 -7.7853240e-01 -1.4134691e+00 -1.5070929e+00 -6.1147385e-01 -8.1629564e-02 -1.3170613e+00 -1.1946101e+00
+1 1.9755940e-01 1 1 1.4270815e+00 -6.0600259e-02 5.4838219e-01 9.5061848e-01 -8.9142488e-01 9.2790464e-01 -1.8682789e-01 1.0700162e-01
+1 7.8460609e-01 1 1 -1.1013576e+00 -6.3252774e-01 -7.7333291e-01 -1.0953800e+00 7.7332289e-02 4.2734825e-01 -1.5652481e+00 1.3851968e+00
+1 7.0234061e-01 1 1 -2.5296087e-01 2.5579393e-01 -6.3748447e-01 -3.1901209e-01 -8.9557531e-01 7.6126503e-01 5.7220765e-01 -1.3401049e+00
+1 5.1285620e-01 1 1 -9.3845151e-01 1.4299133e+00 -1.3705211e+00 1.0625273e+00 -5.6388605e-01 -1.1255994e+00 6.7887869e-01 -1.0652139e+00
+1 9.8549937e-01 1 1 1.3821175e+00 -6.3131132e-01 -1.9134557e-01 1.0829801e+00 9.5222998e-01 7.2155378e-01 -3.5042656e-01 8.8607939e-01
+1 5.3097524e-01 1 1 3.1237731e-01 -1.2910199e+00 1.0459493e+00 -7.4069564e-01 8.5629923e-01 6.0667025e-01 8.6701789e-01 1.1870652e+00
+1 7.2867944e-01 1 1 5.2416450e-01 8.0906807e-01 -1.0822272e+00 1.2601271e+00 1.8527747e-01 -1.3028110e+00 1.2630204e+00 -1.2509548e+00
+1 3.4817308e-01 1 1 6.0687159e-01 1.1939870e+00 8.2835722e-01 1.4805228e+00 6.4008712e-01 5.5699035e-01 -1.5757168e-01 -1.2597604e+00
+1 1.1302084e+00 1 1 -1.0605568e+00 -1.1548492e+00 -1.3387606e+00 -1.4083114e+00 1.1309585e+00 -6.0928084e-01 5.5315128e-02 1.5418871e+00
+1 8.6262796e-01 1 1 6.1866293e-01 -7.9102218e-01 -4.6292876e-01 -7.3007501e-01 1.3841063e+00 1.4090369e+00 -2.3007402e-01 -5.0193498e-01
+1 2.8257773e-01 1 1 -8.0383209e-01 5.1034811e-01 1.2813768e+00 6.9015456e-01 -8.1907587e-01 3.5692210e-01 4.4655925e-01 -8.4490286e-01
+1 1.4220235e-01 1 1 -1.1574681e+00 8.7281940e-01 4.8148730e-01 6.6755688e-01 2.5081260e-01 1.4893090e+00 5.6486338e-02 -2.8355997e-01
+1 7.9831385e-01 1 1 -8.2489452e-01 1.3796321e+00 -3.8568006e-01 1.0011180e+00 -6.1000875e-01 -1.3933852e+00 6.0490917e-01 3.6506528e-03
+1 5.6390482e-01 1 1 -1.5381433e-01 -6.1827046e-01 -1.0191271e+00 -5.8053647e-01 -1.4001686e+00 -1.1933113e+00 5.1457357e-01 -1.4753311e+00
+1 1.0614785e+00 1 1 3.7329300e-01 1.1168197e+00 -5.0646159e-01 7.1041467e-01 1.0373988e+00 -5.6237683e-02 -3.6654789e-01 7.0067208e-01
+1 9.8183223e-01 1 1 1.7492677e-01 -6.2805011e-01 -1.5254771e+00 -1.2542425e+00 -2.7810661e-01 4.3264464e-01 9.2728349e-02 1.5064633e+00
+1 7.8724189e-01 1 1 -5.3643116e-01 1.1306364e-01 -1.5611485e-01 3.2768434e-02 5.5207220e-01 -1.3284777e+00 2.5540771e-01 1.0332215e+00
+1 5.2474954e-01 1 1 5.7243531e-01 -4.0290135e-01 -5.9239578e-01 9.6035323e-01 1.5543629e+00 -4.2568595e-01 1.2218887e+00 -1.3700833e+00
+1 9.2324773e-01 1 1 1.3636053e+00 -1.4308034e+00 -6.8868350e-01 -8.4633007e-01 -1.3071508e+00 -1.0973365e+00 -3.0720676e-01 8.8478151e-01
+1 7.5307792e-01 1 1 1.9516258e-01 1.3791291e+00 -1.0762796e+00 8.6199386e-01 -1.2614512e-01 1.3558442e+00 1.5543308e+00 1.3648847e+00
+1 9.9507086e-01 1 1 2.7467260e-01 3.5252093e-01 2.5966857e-01 -1.4945301e+00 4.5396447e-01 -1.4392286e+00 1.2948252e+00 -2.9240733e-01
+1 6.6351595e-01 1 1 1.4227082e+00 -2.2440162e-01 5.7738571e-01 -1.5340837e+00 -1.1477425e+00 1.1476054e+00 3.1419188e-01 -1.0390477e+00
+1 6.7141579e-01 1 1 7.9439547e-01 1.5347409e+00 -2.5815977e-01 -2.9459617e-01 -7.2978544e-01 1.5673302e+00 -3.9428507e-01 8.3804513e-01
+1 8.5362482e-01 1 1 -3.6410398e-01 -1.2276425e+00 -3.5178157e-01 -1.2784313e-01 -7.2610474e-01 -1.3654238e-01 -1.1302920e+00 1.2646224e+00
+1 9.6621280e-01 1 1 3.2681893e-01 9.9245949e-01 8.4483492e-02 1.8993459e-01 1.4450194e+00 -1.5051418e+00 3.9314706e-01 -1.5075482e+00
+1 3.3100386e-01 1 1 1.3418141e+00 1.5512268e+00 -8.5828487e-02 3.7252314e-01 -1.2121281e+00 -8.1486648e-01 8.5329219e-01 -4.1743318e-01
+1 9.1024049e-01 1 1 1.5181723e+00 -6.0843316e-01 -5.2835692e-01 -1.9777497e-01 9.9140210e-01 -1.2585966e+00 -8.8681210e-02 -6.2313238e-01
+1 5.6443022e-01 1 1 -9.2989031e-02 -5.2082067e-02 1.1877253e+00 -1.9886115e-01 -5.1226318e-01 -8.9011745e-01 -1.3501732e+00 1.0840298e+00
+1 8.4804323e-01 1 1 -1.4950934e+00 1.1610494e+00 4.1956521e-01 3.9521663e-01 1.4982253e+00 6.0190511e-02 -6.3663057e-01 1.1925802e+00
+1 1.0978955e+00 1 1 1.5644445e+00 1.3256091e+00 -1.2429432e+00 1.0790560e+00 8.0734876e-01 2.9090814e-02 4.1454682e-01 3.3431165e-01
+1 6.6115545e-01 1 1 -1.5123343e+00 -6.6314798e-01 1.4441973e+00 -7.2047154e-01 5.7199111e-01 -1.1591376e+00 -7.6401883e-01 -1.5333693e+00
+1 5.4650083e-01 1 1 8.2398730e-01 8.4258555e-01 6.7877620e-01 -1.2671091e+00 1.8113826e-01 -6.1023495e-01 -1.1753662e+00 -8.5412055e-01
+1 2.4267573e-01 1 1 6.1420701e-01 -9.6439060e-01 1.0686070e+00 5.5459975e-01 1.8745310e-01 1.0811864e+00 -4.5178306e-02 -1.2672652e+00
+1 7.5483852e-01 1 1 -2.9625138e-01 -1.0363034e+00 -4.0815306e-01 5.2613076e-02 -4.9321426e-01 5.2836832e-01 9.5362527e-01 1.0715265e+00
+1 4.2746271e-01 1 1 3.2737823e-01 -1.6124352e-01 1.4098344e+00 1.4804258e+00 1.2109425e+00 -9.9611676e-01 -8.2572411e-01 1.5374979e+00
+1 4.2871294e-01 1 1 1.3172390e+00 1.1746350e+00 1.1945936e+00 1.0319485e-01 1.0733670e+00 -1.8714077e-01 -1.5303895e+00 1.1268741e+00
+1 9.9177009e-01 1 1 3.2710767e-02 3.2148199e-01 -3.8414926e-01 2.3666117e-01 1.0547100e+00 -5.4061473e-01 -1.0369687e+00 -1.2883193e+00
+1 4.0886652e-01 1 1 -8.8521371e-03 -3.9157017e-01 -4.2370595e-01 3.0797703e-01 -1.4960046e+00 -6.2588126e-01 1.2238720e+00 -9.2518308e-01
+1 5.8287334e-01 1 1 -1.1230127e+00 5.1682451e-01 7.6459094e-01 -1.1748184e+00 -1.1832886e+00 -1.1340522e+00 -1.5317227e+00 1.3315665e+00
+1 5.1109516e-01 1 1 2.1421126e-01 -2.3421985e-01 1.3659051e+00 -2.6276345e-01 -1.2507389e+00 2.7617419e-02 -1.4538659e+00 -1.0671757e+00
+1 3.9653783e-01 1 1 -1.6568746e-02 -1.1743049e-01 1.1487298e+00 8.1390599e-01 -7.7229742e-01 -7.8975456e-01 1.8430499e-01 -6.7010542e-01
+1 1.2268333e+00 1 1 1.1308302e+00 -7.3404126e-01 -1.5261947e+00 8.2361949e-01 1.0580571e+00 -1.7600982e-01 3.6419426e-03 1.4780462e-01
+1 6.8813263e-01 1 1 -7.7263934e-01 2.9047124e-03 3.4958801e-01 7.1553942e-01 1.3514497e+00 1.1832486e+00 1.5198690e+00 -8.4754691e-01
+1 7.8082705e-01 1 1 -1.5469840e+00 -1.4459819e+00 7.4740262e-01 5.4400952e-02 1.0015660e-01 5.7810512e-01 1.4778129e-01 -7.3986610e-01
+1 7.5160606e-01 1 1 -3.3871450e-01 7.4265503e-01 1.5083274e+00 1.1333246e-01 -5.6167009e-01 -7.3337442e-01 -1.2395663e+00 -5.0575093e-01
+1 5.7942194e-01 1 1 -2.0873959e-01 2.5553787e-01 9.4702626e-01 9.7348955e-01 4.9670113e-01 -1.3558779e+00 -1.4891176e+00 9.9381988e-01
+1 3.6959094e-01 1 1 8.7267532e-01 2.6787415e-01 1.3619541e+00 2.4334167e-02 8.4413389e-01 8.7386909e-01 1.4695032e+00 -7.1739948e-01
+1 9.1238584e-01 1 1 -1.0420413e+00 2.5855221e-01 7.1915451e-01 5.7729824e-01 -7.4217304e-02 1.7217586e-01 -1.2609118e+00 9.9483049e-02
+1 2.8433058e-01 1 1 7.9114984e-01 6.6440034e-01 1.1229830e+00 1.4134095e+00 -1.5793655e-01 3.5287866e-01 1.0392745e+00 6.8430612e-01
+1 9.5463754e-01 1 1 -1.5064069e+00 1.3562040e+00 -7.1382447e-01 -1.5496002e+00 2.0619088e-01 -4.9533698e-01 -1.6839055e-01 -2.3781427e-01
+1 7.6376323e-01 1 1 -8.5947994e-02 1.4660475e+00 4.9454614e-01 -3.2707582e-01 2.7339515e-01 9.1874220e-02 4.3498642e-01 -8.3859447e-01
+1 5.5228594e-01 1 1 6.0467754e-01 3.4941154e-01 -8.1713274e-01 6.2389675e-01 -1.1977776e+00 -1.5335696e+00 3.3067028e-01 -1.0725834e+00
+1 7.9124953e-01 1 1 -2.3683366e-01 9.2303359e-01 1.4930672e+00 -8.0353027e-01 2.7827327e-01 -1.0784506e+00 9.7931081e-02 -4.5056836e-01
+1 7.5033040e-01 1 1 -6.5419516e-02 2.4106007e-01 -1.0613680e+00 7.7356229e-01 -8.9263455e-01 1.4703707e+00 -2.6686818e-01 -1.4641676e+00
+1 5.9026815e-01 1 1 5.1622405e-02 -1.1578923e+00 -4.4877655e-01 1.3510027e+00 -1.4038780e+00 7.5173587e-01 9.4076920e-01 -1.6976930e-01
+1 8.8026224e-01 1 1 5.3818885e-01 1.4706095e+00 3.7649600e-01 -1.1288787e+00 1.5255389e+00 -1.0609446e+00 -1.2784798e-01 -7.4647634e-01
+1 6.4766612e-01 1 1 6.9482870e-01 -1.5171852e+00 6.0058472e-01 -9.8586284e-01 1.1953202e+00 3.8388744e-01 1.0832946e-01 1.4931709e+00
+1 6.2381411e-01 1 1 6.8613948e-01 9.7643786e-01 9.0243641e-02 -6.3711919e-01 -7.3915678e-01 -8.3508406e-01 -1.4304961e+00 6.8108224e-01
+1 1.1580694e+00 1 1 -8.4039125e-01 -6.8886122e-01 -6.6437249e-01 -1.5144387e+00 -1.1505685e+00 1.3781512e+00 2.6069535e-01 -1.0143571e+00
+1 1.1046587e+00 1 1 1.4474895e-01 -9.2167071e-01 -8.8816085e-01 1.2653224e-02 -1.1024907e+00 -3.7477418e-01 -1.0150088e+00 1.1241112e+00
+1 4.4756969e-01 1 1 1.2028802e+00 6.7375381e-01 1.5289430e+00 -9.6556582e-01 -4.4798674e-01 6.3578292e-02 -4.0419609e-01 -6.0092005e-01
+1 9.5069875e-01 1 1 6.5819278e-01 1.4803835e+00 -1.2827369e+00 1.2029370e+00 1.0844205e+00 4.1884721e-01 -1.2002933e+00 5.5702439e-01
+1 5.6546751e-01 1 1 6.9831197e-01 -6.0774590e-01 -1.3505689e+00 -1.5284305e+00 1.4763089e+00 -7.4410022e-01 -1.1636913e+00 -3.7258135e-02
+1 7.6592371e-01 1 1 -4.6091063e-01 -1.0675527e+00 -1.0040544e+00 4.7114805e-01 2.5442844e-02 5.8788765e-01 1.3969763e+00 -1.0205416e+00
+1 5.5082203e-01 1 1 6.4245565e-01 -7.2212378e-01 1.4942656e+00 -1.3697292e+00 3.6127423e-01 3.1889227e-01 -1.2825124e+00 8.5273097e-01
+1 8.4303817e-01 1 1 9.8091955e-02 -7.6190179e-01 2.2997940e-01 5.5173872e-01 -7.6259054e-01 6.5343873e-02 -7.1934418e-01 -9.6192466e-02
+1 3.6888687e-01 1 1 -7.0464857e-01 -1.5177027e-01 1.1048521e+00 -9.0878507e-01 8.3876885e-01 -1.3229561e+00 -1.1691783e+00 1.2134405e+00
+1 3.1151034e-01 1 1 7.7579326e-01 1.7027950e-01 -7.0506236e-01 4.7281088e-01 8.6179264e-01 1.2700757e+00 2.8245760e-01 -9.2479966e-01
+1 7.9870894e-01 1 1 1.1478621e+00 -1.0339489e-01 1.0442173e-01 1.4446188e+00 1.4067016e+00 -9.5996260e-01 3.1839364e-01 1.4925557e+00
+1 1.0319517e+00 1 1 -4.0152791e-01 -4.5718019e-01 -1.1343537e+00 1.4796243e+00 -1.1923454e+00 1.1285344e+00 1.1096020e+00 -2.3451044e-01
+1 4.8436933e-01 1 1 -3.3859240e-01 5.0812621e-01 1.2428021e+00 -8.0238667e-01 4.7049912e-01 1.4827060e+00 5.8709135e-01 1.2818144e+00
+1 9.5071060e-01 1 1 -1.2981562e+00 1.2283273e+00 -6.7510350e-01 1.1444855e+00 2.9000146e-01 7.2657973e-01 -4.9819968e-01 1.5542213e+00
+1 8.7251630e-01 1 1 2.4902950e-01 1.0910774e+00 9.6807401e-01 -6.0483908e-01 1.4442506e+00 2.5491118e-01 -8.9765176e-01 -5.4494147e-01
+1 6.1065876e-01 1 1 8.3731287e-01 2.6184377e-01 1.1151799e-01 6.6337767e-01 -1.5662173e+00 -8.4013846e-01 -9.0513622e-01 -1.0886411e+00
+1 9.7770841e-01 1 1 1.5239609e+00 -5.6304598e-01 -1.2480308e+00 -1.2387938e-01 -9.0145297e-03 1.2518110e+00 -1.0328978e+00 -1.5501687e-01
+1 2.4410835e-01 1 1 -1.9488433e-01 -6.3671812e-01 7.6088170e-01 8.3523856e-01 -7.1075389e-01 -5.9244157e-02 5.2756777e-01 -9.8820186e-01
+1 5.3916883e-01 1 1 1.2601832e+00 -1.0569272e+00 -1.2849658e+00 1.2185343e+00 -1.3054105e+00 1.6832417e-01 1.2570317e+00 8.9169707e-01
+1 7.3839826e-01 1 1 -7.1827119e-01 -1.2101470e+00 -1.1117276e+00 -1.3622601e-01 8.4926807e-01 -1.5506089e+00 -2.7885083e-01 1.3557077e+00
+1 4.0334550e-01 1 1 1.1567562e+00 -2.6969972e-01 1.3877829e+00 6.7055643e-01 1.3930140e+00 1.5681108e+00 6.1031144e-01 -5.9275875e-01
+1 5.1665614e-01 1 1 1.4253075e+00 4.7492737e-01 1.2834498e+00 1.1490669e+00 1.2381176e+00 4.1763796e-01 2.0430951e-01 -5.0604101e-01
+1 3.6598749e-01 1 1 4.9948691e-01 -6.8269653e-01 7.6532621e-01 9.9765922e-01 -8.6663292e-01 9.2319120e-01 6.9091885e-02 -7.3987314e-01
+1 6.3318943e-01 1 1 5.4100903e-01 -9.8413634e-01 1.1573147e+00 9.7859620e-01 -1.0759442e+00 -2.5159909e-01 -1.1619679e+00 -6.2416320e-01
+1 4.6757246e-01 1 1 9.6970126e-01 1.0591977e-01 1.3879962e+00 1.0287348e+00 -3.8705854e-01 -4.2176428e-02 -1.0542679e+00 -5.3295550e-01
+1 1.2972779e+00 1 1 -8.1361517e-01 -1.0894660e+00 -1.4150353e+00 -1.3797448e+00 9.4547765e-01 1.1407171e+00 -4.9776451e-01 -7.0241940e-01
+1 6.8316951e-01 1 1 9.2268680e-01 -1.4527653e+00 -6.4266545e-01 -1.2760307e+00 4.6715844e-01 -1.1068526e+00 1.3308724e-01 5.4233658e-01
+1 6.3491117e-01 1 1 6.9568688e-01 -1.6746530e-01 -4.8275555e-01 1.4047806e+00 6.9183203e-01 -1.5019965e+00 -1.6808894e-02 1.2905852e+00
+1 7.1528738e-01 1 1 -5.9839371e-01 2.7768095e-01 1.0612196e+00 1.0790471e+00 5.8652909e-01 -1.3583401e+00 2.3625131e-01 1.3096043e+00
+1 8.3522131e-01 1 1 -9.6493618e-01 -1.4229940e+00 1.0962863e+00 -8.6944577e-01 -5.2329083e-01 3.3111000e-01 -2.9727936e-01 5.2211825e-01
+1 9.2388166e-01 1 1 -7.8102596e-01 6.8515145e-01 -1.5706727e-01 -1.2277083e+00 1.5103949e+00 1.2051119e+00 -1.2418586e+00 7.7317631e-01
+1 1.0106791e+00 1 1 -1.1291580e+00 1.4033198e+00 -8.9172497e-01 -1.1345107e-01 1.1383679e+00 4.6746876e-01 8.2459791e-01 1.1469613e+00
+1 4.1848675e-01 1 1 6.0272859e-01 -1.4810481e+00 1.3169321e+00 1.7466607e-01 2.4980361e-01 -3.7577986e-01 1.4519318e+00 1.6636029e-01
+1 6.3219011e-01 1 1 1.5647700e+00 -1.1373719e+00 1.1575126e+00 1.3651562e+00 1.2814652e+00 -1.1309486e+00 -1.2735039e+00 -1.3960408e-04
+1 9.1029871e-01 1 1 8.1725568e-01 7.8166055e-01 -1.5683847e+00 1.1282652e+00 -1.1735348e+00 -1.2176751e+00 -1.0918908e-01 7.9526691e-01
+1 4.6498505e-01 1 1 5.7314811e-01 -7.7155247e-01 1.2614838e+00 1.0053708e-01 -6.8033342e-01 -1.1309486e+00 -4.5080641e-01 -1.4257044e+00
+1 1.1440411e+00 1 1 7.7725617e-01 1.0121853e+00 -8.5087476e-01 -4.5015056e-01 1.0335431e+00 -1.2170850e+00 8.1807972e-01 -8.8746565e-01
+1 4.9380575e-01 1 1 6.0226214e-01 7.3584202e-02 -1.2225769e-01 -7.2532862e-01 8.9351448e-01 -6.3801096e-01 -1.2851535e+00 6.4680914e-01
+1 2.9995859e-01 1 1 8.3061248e-03 -1.0578175e+00 -1.8339996e-01 -1.2186135e+00 4.8495739e-01 -7.9445367e-01 -1.1248776e+00 1.0106020e+00
+1 9.8585939e-01 1 1 1.3709631e+00 -4.6513215e-01 -5.0069423e-01 -1.1938466e+00 1.3875525e+00 -6.1412491e-01 2.8658848e-01 -1.4033887e+00
+1 6.7006329e-01 1 1 1.3366120e+00 -1.1934579e+00 1.1587622e+00 3.7186362e-01 5.5284338e-01 -1.4654548e+00 6.3100319e-01 3.2308634e-01
+1 7.6635082e-01 1 1 -1.0906211e+00 6.2289129e-01 5.8287762e-01 1.2840669e+00 -1.1924486e+00 1.8704553e-01 -7.4617832e-01 1.4400003e+00
+1 3.7018545e-01 1 1 1.1248696e+00 1.1471744e+00 9.3833289e-01 -1.4297430e+00 -1.2647962e+00 -1.0599670e+00 2.1892763e-01 -7.4475971e-01
+1 7.3885135e-01 1 1 -4.2071200e-01 6.0602559e-01 -2.3428149e-01 3.5194668e-01 -1.4142302e+00 1.1067569e+00 7.1167606e-01 -1.0713468e+00
+1 8.7271994e-01 1 1 8.1841984e-01 4.2878830e-01 -1.1533903e+00 -4.5113292e-01 3.2325321e-01 -1.0770709e-01 1.0962996e+00 1.4828263e+00
+1 1.2101775e+00 1 1 1.2895715e+00 -1.6856015e-01 -1.4037208e+00 -1.5279837e+00 1.1030031e+00 -6.7569014e-01 6.7045646e-02 -3.9352182e-01
+1 6.5901742e-01 1 1 -1.9341125e-02 7.2617754e-01 1.0250364e+00 -1.4437205e+00 -3.6500359e-01 5.3333445e-01 -9.9558940e-01 -8.6874928e-01
+1 1.2782674e+00 1 1 -1.4822462e+00 -2.2155711e-01 -7.0663467e-01 1.0507820e+00 9.1504080e-01 7.8826983e-01 -7.4862798e-01 1.0535348e+00
+1 1.2325060e+00 1 1 7.1840549e-01 -9.2309303e-01 -1.1887368e+00 -1.5405434e+00 9.9461683e-01 3.5479242e-01 -1.1184007e-01 7.4254732e-01
+1 3.1687923e-01 1 1 1.1004285e+00 -1.2401144e+00 1.4293728e+00 1.0944344e+00 1.1060922e-01 2.5335290e-01 -1.0237299e+00 -1.5547732e+00
+1 5.8320011e-01 1 1 3.4518385e-01 -1.2766712e+00 -2.9088820e-01 1.3423495e-01 -8.1374977e-01 1.2441121e+00 6.7395375e-01 6.9429696e-01
+1 1.0815363e+00 1 1 -1.0166136e+00 6.5451023e-02 -6.3988212e-01 4.2332742e-01 -1.3396120e+00 -6.4889793e-01 -1.4425096e+00 1.1738157e+00
+1 6.4512342e-01 1 1 8.9803194e-01 4.7791350e-01 -8.2711325e-01 -8.4348317e-01 9.3625484e-01 -1.5594916e+00 -5.8754561e-01 -8.8099074e-01
+1 5.0197572e-01 1 1 1.0116891e+00 -7.6016361e-01 2.5514625e-01 -1.5555661e+00 -6.0247931e-01 -6.8468369e-02 -8.5337852e-01 -4.8525995e-01
+1 6.6586121e-01 1 1 1.1597636e+00 7.8745047e-01 -3.1024924e-02 -6.5334563e-02 -5.1659449e-01 -9.2496652e-01 -1.3622870e+00 -1.8948060e-01
+1 1.0233186e+00 1 1 -1.4350732e+00 -8.4984399e-01 6.8488088e-02 1.4794294e+00 9.5853192e-01 -1.3118677e+00 -3.0530709e-02 9.7458018e-01
+1 6.1820368e-01 1 1 -1.2687050e+00 1.4938179e+00 1.2563783e+00 -9.3554714e-01 -4.1203207e-02 -8.6319217e-01 -1.0500236e+00 -4.9499833e-01
+1 7.9718891e-01 1 1 -1.1359382e+00 -1.0118413e+00 1.3051019e+00 -6.9630154e-02 -1.3519154e+00 2.0409243e-01 -1.4205954e+00 -4.9962989e-01
+1 9.0126485e-01 1 1 -2.5423408e-01 -5.7487764e-01 2.4787313e-01 1.5400587e+00 1.4973396e+00 -4.3769666e-01 1.5774987e-01 1.9757194e-01
+1 3.2756354e-01 1 1 -3.4611528e-01 1.5704756e+00 2.5184124e-01 1.8453375e-01 -1.5125414e+00 1.2423130e+00 -2.0210524e-01 -7.1791304e-02
+1 5.6007087e-01 1 1 1.0701116e+00 -6.7728685e-01 9.7048902e-01 7.0680896e-01 4.8503143e-01 5.2993076e-01 -7.2117133e-01 -2.2486784e-01
+1 7.1021919e-01 1 1 -2.5190960e-01 -1.1698905e+00 -1.4001449e-01 9.7639707e-01 -5.0970329e-01 1.3110235e-01 -4.6208085e-01 -1.7887400e-02
+1 9.4572054e-01 1 1 1.0222145e+00 8.7883829e-01 -1.7058925e-01 -1.3745017e+00 5.4002611e-01 1.1807349e+00 -1.7580820e-01 9.5936306e-01
+1 7.7429141e-01 1 1 -1.0105202e+00 -1.1335445e+00 1.1805712e+00 -1.1188376e+00 1.5765384e-01 -8.3005192e-01 1.4302727e+00 1.3614344e+00
+1 1.1777249e+00 1 1 -3.6313658e-01 -8.6407675e-01 -4.3852017e-01 1.2706101e+00 1.3255302e+00 1.1304209e+00 -8.7343041e-01 1.4094052e+00
+1 9.6371941e-01 1 1 8.7806924e-01 1.0448993e+00 -3.2175823e-02 -1.4022753e+00 1.1528223e+00 -1.3686017e+00 9.1754798e-01 2.6505578e-01
+1 1.3565147e+00 1 1 -1.4926249e+00 1.1893469e-01 -4.2512552e-01 1.8650378e-01 1.2828869e+00 6.5195611e-01 -8.4951065e-01 1.4118690e-02
+1 8.5436660e-01 1 1 -9.2883596e-01 8.8239221e-01 -1.1029548e+00 -7.4041846e-01 7.2909703e-01 -4.4889122e-01 8.1311115e-01 -1.4682119e+00
+1 5.6461982e-01 1 1 -3.7215369e-01 -1.0930789e+00 1.1761374e+00 -3.6450924e-01 -1.4191462e+00 -1.5507029e+00 3.0991863e-02 9.7350682e-01
+1 6.8549301e-01 1 1 1.2395570e-01 6.5675747e-01 4.4096749e-01 -2.0111051e-01 -6.1867536e-01 -1.1743848e-02 -6.2413567e-01 3.1463599e-01
+1 9.6547168e-01 1 1 4.4757736e-01 -1.4338174e+00 3.2353014e-01 2.8939366e-01 5.9491410e-01 5.4148853e-01 -7.0346124e-02 7.8673128e-01
+1 8.1124256e-01 1 1 1.4598575e+00 9.8879892e-01 -5.2576392e-01 6.5378253e-01 -9.6808903e-01 -3.9620747e-01 -1.0684655e+00 -3.7089208e-01
+1 6.7830796e-01 1 1 -1.4318474e-02 -2.8167491e-01 7.8598509e-01 -1.1681839e+00 -3.6395543e-01 1.1174230e+00 -3.5572821e-01 -6.6333295e-01
+1 7.9225050e-01 1 1 1.2520448e+00 2.6998758e-01 -3.4567354e-01 1.2865561e+00 -3.1796163e-01 8.7131780e-02 -2.7319866e-01 8.7543828e-01
+1 6.9188636e-01 1 1 7.2911773e-01 1.2215405e+00 -9.3032064e-01 -4.3322592e-01 -1.3206986e-01 4.4165777e-01 1.3585249e+00 1.4127914e+00
+1 1.1253906e+00 1 1 -1.0712118e+00 1.2384087e-01 -1.9231383e-01 9.8367835e-01 1.4077880e+00 -6.4131529e-01 -3.6666733e-01 6.2835628e-01
+1 7.0794255e-01 1 1 6.1044139e-01 -1.4824737e+00 4.8024171e-01 -1.5200726e+00 1.3592018e+00 2.1839500e-01 1.2269922e+00 -1.2505280e+00
+1 4.1866019e-01 1 1 -7.5309812e-01 3.5793419e-02 6.7081455e-01 -4.2802278e-01 -1.5573222e+00 1.1845999e+00 6.4320027e-01 -3.6850493e-01
+1 1.0068682e+00 1 1 1.5665407e-01 1.5358009e+00 -7.9591691e-01 4.6826230e-01 -1.3056755e+00 1.2986304e+00 4.6589629e-02 -1.3832774e+00
+1 7.9676584e-01 1 1 2.3036045e-01 8.8116178e-01 -7.4007872e-02 3.9491592e-01 -4.6388439e-01 1.4376239e+00 7.7532210e-01 -9.5749764e-01
+1 7.4190441e-01 1 1 1.2259607e+00 2.1828729e-01 2.2038353e-01 -8.3336186e-01 9.2807851e-01 1.5649122e-01 -4.8779731e-01 -1.4253291e+00
+1 6.3655067e-01 1 1 -9.8543937e-01 -6.2576032e-01 4.8327656e-02 -1.0927628e+00 2.0805029e-01 6.3482510e-01 1.1473870e+00 -8.6148521e-01
+1 7.2054580e-01 1 1 1.9704463e-01 8.9857695e-01 -1.4295823e+00 -3.1331675e-01 1.0866817e-01 6.5673718e-01 1.0382901e+00 6.1869471e-01
+1 1.0449029e+00 1 1 4.9035976e-01 7.4687185e-01 -8.9152989e-02 -6.0533090e-01 1.1205268e+00 1.3667253e+00 -1.0048531e+00 -2.6962460e-01
+1 7.1591250e-01 1 1 1.0790096e+00 -1.1290910e+00 1.4540880e-01 -1.3193802e+00 -1.1546694e+00 -7.7256432e-01 6.3569491e-01 -1.4040109e+00
+1 7.4373967e-01 1 1 -1.5007730e+00 -1.4125215e+00 -2.7338036e-01 -1.4619474e+00 -9.0997951e-01 -2.8614906e-01 -4.3220432e-01 -7.0917291e-01
+1 6.0842976e-01 1 1 3.5632618e-01 7.6704058e-01 1.4463548e+00 -5.5352793e-01 -7.5261806e-01 4.7111263e-01 -6.9585338e-01 1.3337845e-01
+1 1.1678008e+00 1 1 8.9858787e-01 -1.4452887e+00 -7.5881716e-01 -8.8806403e-01 -1.1997394e+00 1.1764582e+00 9.4166065e-01 -1.4055796e+00
+1 6.2858907e-01 1 1 9.3041578e-01 -1.7284376e-01 1.4261002e+00 1.4535499e-02 -1.2782558e+00 -4.5067336e-01 -8.5324219e-01 1.1998442e+00
+1 4.5303457e-01 1 1 -1.3502953e+00 9.8820109e-01 1.2557008e+00 -7.4609221e-01 -1.4340439e+00 -8.7202906e-02 9.2890179e-01 -1.0170859e-01
+1 5.6926471e-01 1 1 4.5273690e-01 -9.0467915e-01 -6.5603960e-01 -1.4755324e+00 3.2379134e-01 1.5045267e+00 1.4784576e+00 -3.8982384e-01
+1 6.6525130e-01 1 1 2.1171635e-01 3.6603547e-01 9.3271233e-01 4.5908178e-01 7.2250275e-01 -9.9226378e-02 -1.5603625e+00 -1.5486209e+00
+1 8.8354873e-01 1 1 -1.1077959e+00 7.1964731e-01 -4.5128715e-01 3.5850112e-02 8.4809644e-01 4.8796132e-01 1.0021802e+00 4.2308546e-01
+1 9.5031461e-01 1 1 1.4932243e+00 -1.9452115e-02 -9.7852796e-01 -6.5296146e-01 5.5104805e-01 -1.5325753e+00 1.5645095e+00 1.3730916e+00
+1 1.0265133e+00 1 1 -1.5625835e+00 -2.0606466e-01 1.1811352e-01 -7.4020190e-01 4.9397210e-02 -7.4401238e-02 -4.1970084e-01 -5.8943192e-01
+1 1.1588303e+00 1 1 1.3733256e+00 -1.2936232e+00 -3.5256030e-01 1.3362458e-01 8.3844914e-01 -1.0772521e-01 -1.0365666e+00 -1.1405900e+00
+1 1.0693738e+00 1 1 2.0163457e-01 1.0370009e+00 -4.3724166e-01 -4.1036509e-01 -1.3700138e+00 -9.8020340e-01 -1.4438094e+00 1.0162277e-01
+1 8.3039619e-01 1 1 -9.0622680e-01 -6.8167367e-01 -5.3533405e-01 -1.2102126e+00 -1.0888915e+00 2.3329302e-01 -4.4323850e-01 -1.0525142e+00
+1 4.1912061e-01 1 1 -5.1265558e-01 4.9909422e-01 1.6195063e-01 -1.3726106e+00 -1.2222967e+00 2.4818172e-01 -7.9334298e-01 7.0124526e-01
+1 4.7557247e-01 1 1 1.1863441e+00 2.2413667e-01 1.2850379e+00 -7.5206166e-01 -2.6598783e-01 -8.4493115e-01 -7.9616932e-01 -1.4265435e+00
+1 4.9736845e-01 1 1 -8.0256488e-01 2.9544503e-01 -8.1722121e-01 -1.2731202e+00 2.8831417e-02 -7.5897931e-01 -1.1746034e+00 7.1908694e-01
+1 1.0264508e+00 1 1 1.2908576e+00 -1.3133109e+00 6.1770056e-03 5.5832337e-02 7.6435692e-01 -1.2990784e+00 2.0839814e-01 -1.2751933e-02
+1 9.7827160e-01 1 1 -3.9545696e-01 1.3155704e-02 1.4437473e-01 -9.6212308e-01 5.7444517e-01 4.5828786e-01 -3.2825582e-01 -6.9343524e-01
+1 5.7842523e-01 1 1 1.1649336e+00 1.1964332e+00 1.1966187e+00 -6.2520494e-01 5.8574152e-01 -7.4116460e-01 -3.5880671e-01 7.4259740e-01
+1 5.8093436e-01 1 1 6.3302167e-01 -8.8183697e-01 -9.0551866e-01 8.0808337e-01 -1.1936706e+00 -3.3860225e-01 1.3934458e+00 -7.1312657e-01
+1 9.8537934e-01 1 1 -1.3791493e+00 1.0001020e+00 -1.1772905e+00 3.5213979e-01 1.8920069e-01 -1.4638006e+00 -9.2955719e-01 -3.4234716e-01
+1 9.8791406e-01 1 1 -6.9180059e-01 1.1937546e+00 -9.7109319e-01 -3.4710836e-01 6.0415176e-01 -2.8528856e-01 7.2498994e-02 1.5689780e+00
+1 1.0295160e+00 1 1 -5.8148785e-02 1.2226246e+00 -5.8935426e-01 8.7379417e-02 3.5120780e-01 -7.7449892e-01 -4.4736455e-01 -7.1553603e-01
+1 1.0206416e+00 1 1 -2.7132100e-01 -5.0571634e-01 1.6462488e-01 1.4620988e+00 -3.0315017e-01 -1.3849616e+00 -1.0248391e+00 2.6415012e-03
+1 1.2638494e+00 1 1 1.5004257e+00 -1.5663577e+00 -8.9274289e-01 -4.2446916e-02 6.1832531e-01 -9.8932540e-01 8.8105258e-01 4.1341364e-01
+1 4.9891086e-01 1 1 9.1047385e-02 7.7195489e-01 -8.3242679e-02 -2.6377699e-01 -1.9494478e-01 8.5793906e-01 1.5244898e+00 -9.5983150e-01
+1 7.9357091e-01 1 1 2.7777029e-01 -5.3180760e-01 -1.0509681e+00 -5.1270369e-01 2.4423747e-01 -5.2845439e-01 -7.2883381e-01 1.9025566e-01
+1 5.8548774e-01 1 1 7.8574836e-02 -2.5920968e-01 1.5541934e+00 3.7776737e-01 -1.1625115e+00 -4.5047493e-01 -4.4002808e-01 -5.1449530e-01
+1 4.5039919e-01 1 1 1.1383566e+00 8.5188825e-01 -1.0137960e+00 -2.2510180e-02 -7.6562554e-01 1.0619637e-01 -2.4288007e-01 -1.4595524e+00
+1 7.4375677e-01 1 1 6.0702960e-02 1.4481052e+00 1.1290654e+00 -1.3374796e+00 9.4996727e-02 4.1767999e-01 -1.1565433e+00 -1.1411437e+00
+1 3.7220275e-01 1 1 -7.8296521e-01 3.8524007e-01 9.8258859e-01 -9.2399359e-01 6.8091430e-01 -1.5120094e+00 -9.8947782e-01 2.2071134e-01
+1 7.9199050e-01 1 1 8.3541005e-01 -9.2553138e-02 -9.8620899e-01 -6.6777588e-01 -6.9545610e-01 1.7808928e-03 1.4377355e+00 -7.2549102e-01
+1 3.4868246e-01 1 1 9.5906077e-01 -4.5223291e-01 -1.7157563e-01 -1.5403371e+00 1.3355649e+00 -1.4844607e+00 -1.1103471e+00 -8.0647759e-01
+1 6.7767497e-01 1 1 -5.7753765e-01 -1.1659359e+00 3.1042411e-01 1.4192280e+00 1.5996126e-01 1.1981774e+00 -5.4387493e-01 1.5035262e+00
+1 8.8772821e-01 1 1 8.4606999e-01 1.3697834e+00 -8.8739803e-01 -1.1475795e+00 -7.3446930e-01 1.5836366e-01 1.1286422e+00 -1.2065423e+00
+1 5.7439772e-01 1 1 1.0499939e+00 3.5889978e-01 -1.3583110e+00 -1.1313242e+00 -9.0797137e-01 6.8902311e-01 1.5378480e-01 6.2497658e-01
+1 3.6680863e-01 1 1 9.2090840e-01 1.7069759e-01 8.2098665e-01 -1.2470240e+00 -1.5592243e+00 5.0092930e-01 -8.6968528e-01 -1.5044889e+00
+1 9.0135057e-01 1 1 -9.1948692e-01 6.4031238e-01 4.4764550e-01 -1.1677928e+00 1.2828927e+00 -3.4962404e-01 1.0301730e+00 7.3448752e-01
+1 8.4967434e-01 1 1 -3.2242440e-01 -1.3662799e+00 -5.3646043e-01 -1.5639808e+00 8.2715104e-01 -1.3529623e+00 8.0079682e-01 1.2142549e+00
+1 1.0170414e+00 1 1 2.6051621e-01 -1.1649245e+00 8.0468745e-02 -1.1923985e-01 3.8004114e-01 -3.9049900e-01 4.0927029e-01 1.9648593e-01
+1 7.7854850e-01 1 1 -8.8429872e-01 -4.8131825e-01 1.5533482e+00 2.7201273e-01 4.9352671e-01 -3.2964154e-01 -1.4822196e+00 5.2508943e-01
+1 1.9861439e-01 1 1 4.6626809e-01 8.5293305e-02 4.8767061e-01 7.0063830e-01 8.9878814e-01 1.4840173e+00 1.1651069e+00 4.4423068e-01
+1 3.7256716e-01 1 1 1.4356913e+00 9.5832685e-01 -1.3527275e-01 9.3859583e-01 1.1548196e+00 7.7533182e-01 4.0467560e-01 -1.3807124e+00
+1 7.0499285e-01 1 1 -9.0986612e-01 -3.4613031e-01 9.8397413e-01 1.0434161e+00 2.9337595e-01 -3.2439036e-01 -1.6534494e-01 1.3115824e+00
+1 1.8296885e-01 1 1 1.1532145e+00 8.1750207e-01 3.0946162e-01 3.2473869e-01 -1.5308380e+00 -1.3654473e+00 1.3571637e+00 -7.8951041e-01
+1 1.0710455e+00 1 1 -1.5497997e+00 -1.5689764e+00 -1.3559860e+00 9.3678460e-01 8.4964916e-01 2.6222661e-01 -1.2534271e+00 7.8598733e-01
+1 1.2428320e+00 1 1 -5.3891554e-01 7.4236073e-01 -9.4276092e-01 -1.1236188e+00 1.5148110e+00 -4.1179343e-01 1.1703308e+00 -3.0805502e-01
+1 8.1440241e-01 1 1 -3.4178817e-01 -1.5491632e+00 1.2105446e+00 -5.4803066e-01 -3.7961816e-02 -8.3541807e-02 2.3798071e-01 -1.3607619e-01
+1 5.2803230e-01 1 1 1.5391904e+00 7.3454478e-01 6.6945576e-01 3.9836884e-01 -2.8094013e-01 2.0476093e-01 4.9441780e-01 4.6896325e-02
+1 5.6530846e-01 1 1 1.2987018e+00 -9.6504139e-01 1.4995833e+00 6.5111788e-01 5.3037557e-02 1.3729462e+00 1.6732088e-01 -3.5321704e-01
+1 4.8611094e-01 1 1 -5.0487243e-01 5.9217690e-01 -1.5019695e+00 1.1710368e+00 -8.1008697e-01 1.0885053e-01 4.3653405e-01 1.0913897e+00
+1 3.4174725e-01 1 1 5.0902143e-02 1.5155428e-01 -9.0362327e-01 -4.6178942e-01 5.3090827e-01 1.0440070e+00 1.2089433e+00 -7.7218192e-01
+1 1.0606276e+00 1 1 9.9911830e-01 -6.5889805e-01 -7.3749043e-01 -1.5609154e+00 8.5207854e-01 8.3146976e-01 -1.1106290e+00 -1.4229727e-01
+1 4.0826582e-01 1 1 3.6860216e-01 1.4587765e-02 -1.4186562e+00 1.1344967e+00 1.5047009e+00 7.0816110e-01 1.0022789e+00 -8.3828038e-01
+1 7.1299001e-01 1 1 -1.2427027e-01 1.3233697e-01 1.3331025e+00 1.1605784e+00 -3.1284468e-01 -1.4309014e+00 8.1426142e-02 1.0646358e+00
+1 9.9531841e-01 1 1 5.4865771e-01 -6.0065884e-02 -3.8429766e-01 -3.0741953e-01 1.0455972e+00 -2.6799629e-01 -1.2052202e+00 -1.1778440e+00
+1 3.0630796e-01 1 1 7.1566765e-01 -1.0760698e+00 2.2368086e-01 1.1199518e+00 -7.1640962e-01 8.3015141e-01 8.5279771e-01 -8.4885745e-01
+1 8.3678549e-01 1 1 -9.3199506e-01 6.4300445e-01 -1.0821711e+00 -1.3940877e+00 1.0281724e+00 5.4170978e-01 1.0254785e+00 -7.7492308e-01
+1 4.1072942e-01 1 1 -6.0021600e-02 -1.0289679e-01 -1.3694779e+00 -4.3369581e-01 -1.4068767e+00 1.8075312e-01 4.4027914e-01 9.1093583e-01
+1 1.2873227e+00 1 1 -3.3178877e-01 -1.5103635e+00 -1.5069612e+00 -6.3049183e-01 1.3907688e+00 -2.4260456e-03 1.3208062e+00 1.1175215e+00
+1 7.5687533e-01 1 1 -4.6936790e-02 -6.1092190e-01 2.3035207e-02 -8.4170629e-02 1.2012865e+00 6.6156795e-02 2.9566649e-01 -1.3987545e+00
+1 6.6345183e-01 1 1 -3.2686669e-01 -1.0395018e+00 7.3682486e-01 -9.3907533e-01 -9.9334974e-01 -2.2655280e-01 -7.3285895e-01 -3.2912080e-01
+1 5.2624194e-01 1 1 9.9707810e-01 -5.1060719e-01 -3.4273835e-01 3.2241884e-01 -8.0569563e-01 -6.2574294e-02 1.0244561e+00 8.1134652e-01
+1 3.3269584e-01 1 1 6.3642769e-01 1.0561335e+00 1.2775043e+00 -3.5389863e-01 -1.0621018e+00 7.4737975e-01 -1.0363620e+00 -1.3527666e+00
+1 6.7948841e-01 1 1 -6.8283890e-01 4.3773010e-01 1.3702073e+00 -9.3945666e-01 -2.1554975e-01 1.1240038e+00 -1.1469224e+00 -2.4241406e-01
+1 3.0209506e-01 1 1 -2.3547458e-01 -6.8022356e-01 1.2003414e+00 1.9656493e-01 -4.8837544e-01 7.3601658e-01 4.8854608e-01 3.9261816e-01
+1 5.4174627e-01 1 1 7.8546748e-01 -2.6171810e-01 -1.1697180e+00 -1.2886680e+00 8.5552407e-01 -1.3611508e+00 -1.1291845e+00 1.3887907e+00
+1 6.5301428e-01 1 1 3.7961403e-01 -4.6640233e-01 6.3593656e-01 -5.0374908e-01 -2.7645476e-01 2.1583337e-01 1.5777287e-01 -6.2880041e-01
+1 9.3909566e-01 1 1 -4.0171187e-01 -5.5032433e-01 4.8750273e-01 8.1463807e-02 4.0423068e-02 -1.0280278e+00 1.8450490e-01 6.9241147e-02
+1 9.6890065e-01 1 1 -2.8877445e-01 -4.5230072e-01 1.8475923e-01 -5.7219654e-01 8.0648814e-01 6.9662028e-01 2.2187435e-01 1.3466707e+00
+1 5.3346560e-01 1 1 3.2841706e-01 8.3608620e-01 1.3548267e+00 -4.9213842e-01 -1.3261537e+00 -6.1882188e-01 -2.8270275e-02 1.4606532e+00
+1 7.9787532e-01 1 1 -7.2826857e-02 -2.4312552e-01 3.0959000e-01 4.4310652e-01 9.3512016e-01 1.2739447e+00 -7.5802586e-01 7.9350408e-01
+1 5.5029623e-01 1 1 1.2201506e+00 1.0014400e+00 8.0169400e-01 -1.4248954e+00 -8.2354309e-01 1.2350808e+00 -9.8234142e-01 3.6229830e-01
+1 1.1920503e+00 1 1 -1.2463046e+00 -1.4513519e+00 -2.1976644e-01 1.4363386e-01 5.6845669e-01 1.5001093e+00 -1.1428351e+00 7.4104744e-01
+1 3.8816808e-01 1 1 1.4990524e+00 -1.5459835e+00 8.9844168e-01 1.3110644e+00 4.6827340e-01 1.0561304e+00 6.7889655e-02 1.5110501e+00
+1 1.0982846e+00 1 1 -9.9973755e-01 7.6884724e-01 -1.5265895e+00 -7.0959751e-02 5.8138573e-01 3.8494124e-01 6.2329324e-01 -4.1605555e-01
+1 1.0318971e+00 1 1 -1.3514656e+00 6.4503398e-01 -3.0834107e-03 1.1846788e+00 9.9688377e-01 1.1681917e+00 -1.5220806e+00 5.3961948e-01
+1 1.2416304e+00 1 1 -3.6737099e-01 -5.5011100e-01 -1.5574016e+00 -5.1716776e-01 5.1184817e-01 -1.1558994e+00 3.8000953e-01 -3.9343680e-01
+1 8.8587150e-01 1 1 -1.1746302e+00 -8.3818104e-03 5.0173841e-01 7.4839702e-01 9.5149005e-01 4.0748432e-01 -3.7705721e-02 5.6026252e-01
+1 8.6791920e-01 1 1 -2.4110622e-01 4.9858284e-01 6.8280318e-01 -6.2833078e-01 9.8660374e-01 -8.3039833e-02 8.8166451e-01 9.7891214e-01
+1 6.3051629e-01 1 1 3.8223788e-01 1.0541168e+00 -3.6499558e-01 -1.4624595e+00 5.2306686e-01 -7.8333990e-01 -7.5712651e-01 5.5562612e-02
+1 1.4444019e-01 1 1 -2.8498045e-01 1.1002058e+00 1.0496561e+00 2.6396188e-01 1.0085049e+00 8.2103479e-01 1.5665053e+00 7.8780998e-01
+1 4.3256556e-01 1 1 1.2624042e+00 -2.5535593e-01 1.5267715e+00 4.7842489e-01 1.0487243e+00 1.2568370e+00 -1.4332335e+00 -1.0906354e+00
+1 5.8990018e-01 1 1 -1.0886298e+00 -3.5147500e-01 -8.0591198e-02 1.5515718e+00 -1.5668307e+00 -4.1033937e-01 1.3768719e+00 8.8450454e-01
+1 6.2493139e-01 1 1 3.5288556e-02 -1.0460718e+00 -4.6983246e-01 -1.0927122e+00 -8.9362726e-01 -7.7794393e-01 1.1373004e-01 -1.4870313e-01
+1 1.2920410e-01 1 1 -6.6625073e-01 -9.7624311e-01 1.4897844e+00 5.3644369e-01 7.6110472e-01 4.0507008e-01 1.3723850e+00 1.4541846e+00
+1 6.2835360e-01 1 1 -1.0397736e+00 8.2047270e-01 3.1279053e-01 -3.6186998e-01 -6.7830376e-01 1.8152389e-01 1.0188020e-01 -1.1096304e+00
+1 6.3104759e-01 1 1 1.2049775e+00 1.2345242e+00 1.1859470e+00 1.7457398e-01 5.8846801e-01 3.8554439e-01 1.3248939e-01 -1.0639613e+00
+1 8.7044008e-01 1 1 1.3500573e+00 1.5697283e+00 -1.1941579e+00 -1.8266130e-01 6.4810329e-01 -1.2611203e+00 -6.4008359e-01 -5.2838925e-02
+1 7.5727966e-01 1 1 -1.3099677e+00 -6.7154142e-01 1.4229283e+00 -6.5251260e-01 7.7030623e-01 6.7607560e-01 -1.0717278e+00 1.0069039e+00
+1 1.8731928e-01 1 1 -3.4613890e-01 1.1457365e+00 1.3524239e+00 5.2074765e-01 3.3466357e-02 -3.3807070e-01 1.3633159e+00 -7.2632003e-01
+1 7.6878095e-01 1 1 6.7302731e-01 -1.5693773e+00 7.6512300e-01 -2.7140916e-01 1.2397626e-01 1.1869194e+00 -1.5269990e+00 9.6827647e-01
+1 8.0337770e-01 1 1 -1.3052181e+00 2.8725877e-01 8.8358883e-01 1.8821780e-02 7.9300383e-01 -5.5857332e-01 -6.0214380e-01 3.7275352e-01
+1 4.7028749e-01 1 1 9.4067937e-01 -6.6972885e-01 1.6905883e-01 -9.6319483e-01 1.3793875e+00 -8.6294676e-01 -1.1609858e+00 5.3263474e-01
+1 2.5499318e-01 1 1 1.5039145e+00 1.9362698e-01 1.3719192e+00 2.1145080e-01 1.5538751e+00 1.1870133e+00 -2.5645649e-01 -1.5469915e+00
+1 8.4448389e-01 1 1 -9.6281700e-01 -4.0129645e-01 -1.4444783e+00 7.1223541e-01 -8.0922319e-02 1.0198799e+00 8.3621787e-04 -4.6514221e-01
+1 5.1541627e-01 1 1 2.7846738e-01 4.0991354e-01 8.8107273e-01 1.0725113e+00 2.4819771e-01 5.9136941e-01 1.4879432e+00 -1.3626674e+00
+1 8.2751958e-01 1 1 -7.7179229e-01 -9.5903733e-02 -1.2784378e+00 -7.6116578e-01 -5.7606941e-01 -8.5353190e-01 7.8323556e-01 -1.4069794e-01
+1 1.1058348e+00 1 1 1.2304018e-01 -2.1700564e-01 -1.3524592e+00 -3.4794406e-01 3.8994305e-01 -7.9857066e-01 5.6679748e-01 9.0895577e-01
+1 1.0341341e+00 1 1 7.6838814e-01 1.7529259e-01 -1.3582908e+00 -1.3918967e+00 4.1057068e-01 -6.9320462e-01 8.5634694e-01 -7.4551237e-01
+1 5.7485832e-01 1 1 -7.8795265e-01 -6.7127601e-01 1.1611514e+00 -1.3095439e+00 1.5238928e+00 1.4770394e+00 9.8706815e-01 -1.1549761e+00
+1 1.1330077e+00 1 1 -1.3071638e+00 -6.7672898e-01 -1.0119400e-01 4.9306530e-01 -1.3388806e+00 -2.6364622e-01 -1.0963612e+00 2.1747778e-01
+1 7.0460224e-01 1 1 -3.4470131e-01 -1.2185366e+00 -1.1659333e+00 -5.7294802e-01 6.6263117e-01 -1.4563179e+00 -1.1009647e+00 1.4768649e+00
+1 6.3054751e-01 1 1 -2.9812906e-01 9.8681254e-02 1.4143110e+00 -5.5587660e-01 -1.0387334e-01 -1.8592527e-01 6.7157014e-02 -5.4994544e-02
+1 2.2181899e-01 1 1 1.8520699e-01 -2.2508643e-01 1.0341359e+00 4.7859922e-01 9.2635761e-01 1.0386495e+00 8.7616526e-01 -6.6505822e-01
+1 4.2851042e-01 1 1 -5.4450268e-01 -5.5005000e-01 1.4312255e+00 1.3399205e+00 -4.4086862e-01 -1.2478082e+00 1.0646929e+00 1.5315097e-01
+1 9.5794838e-01 1 1 2.8284534e-03 1.0168825e+00 -5.6797899e-01 1.1080491e+00 1.3382247e+00 1.3605363e+00 -2.1751464e-01 1.0440319e+00
+1 7.0291717e-01 1 1 4.1392583e-01 4.8044888e-01 1.2772665e+00 -3.8021219e-01 8.8060506e-01 -1.1187144e+00 1.0453008e+00 1.2483468e+00
+1 7.0881577e-01 1 1 1.3652548e+00 1.0111719e+00 5.1609909e-01 -2.2687368e-01 2.8625893e-01 1.9842916e-01 5.8436330e-01 1.4093582e+00
+1 1.0887926e+00 1 1 -3.5467058e-01 -1.2501734e+00 1.4008867e-01 8.2754214e-01 1.3755384e+00 -1.3725029e+00 7.7538448e-01 -5.2537559e-01
+1 3.7486332e-01 1 1 -1.3471461e+00 -6.9193410e-01 1.4173357e+00 6.7008879e-01 -3.0587176e-01 1.0584461e+00 5.6070198e-01 1.0294399e+00
+1 1.0209201e+00 1 1 -2.5924725e-02 8.3953638e-01 -1.5367544e+00 -4.2728805e-01 -1.1410812e+00 -1.5352305e+00 -1.0597779e+00 1.0453829e+00
+1 8.9204144e-01 1 1 9.6453267e-01 1.1953023e+00 -1.1980217e+00 2.5052548e-01 1.2709809e+00 -7.1855406e-01 1.1430927e+00 -1.1767282e+00
+1 5.1291182e-01 1 1 2.8255206e-01 -1.0396131e+00 -6.8335507e-01 8.4763092e-01 -1.4538431e+00 -4.5596753e-01 1.1195727e+00 -9.4560864e-01
+1 2.5443756e-01 1 1 -1.2355994e+00 7.6023888e-01 5.1405603e-01 -9.8980291e-01 5.6621897e-01 -1.1018031e+00 -1.4815117e+00 4.7281682e-01
+1 3.4587937e-01 1 1 -7.9112310e-01 4.7761345e-01 3.5984610e-01 -8.8445370e-01 5.5801752e-01 -1.4581219e+00 4.9626755e-01 1.5444676e+00
+1 1.7320341e-01 1 1 -1.1858535e+00 4.8000170e-01 3.6749790e-01 1.0030614e+00 9.4643297e-01 9.0933131e-01 -1.5985416e-01 -1.1123227e+00
+1 8.8473679e-01 1 1 -3.7562009e-01 -2.2135477e-01 1.6598269e-01 6.6658643e-01 8.1536712e-01 -7.1690110e-01 -6.0718809e-01 8.0992088e-01
+1 7.9694299e-01 1 1 1.5544232e+00 -6.6392283e-01 -6.3246814e-02 3.9879992e-01 2.4797386e-01 -9.4890575e-01 -1.1173543e+00 -1.8068313e-01
+1 6.3920641e-01 1 1 -2.9359001e-01 3.8606582e-01 -1.1308781e+00 -1.5285309e+00 -1.1968199e+00 -1.5347119e+00 1.0666748e+00 1.1788037e+00
+1 6.0757783e-01 1 1 1.0746992e+00 1.2194313e+00 -3.2495210e-02 -1.2164726e+00 6.6532982e-01 -1.4279583e+00 -1.4664949e+00 1.2705083e+00
+1 7.3284907e-01 1 1 1.4536093e+00 -7.6912293e-01 4.9011910e-01 2.3027583e-01 1.2701033e+00 -1.0681077e+00 1.5553763e+00 2.7502811e-02
+1 8.3287674e-01 1 1 -1.3538678e+00 1.0046814e+00 1.7572679e-01 -1.9628964e-01 -4.9673854e-01 -6.2508999e-01 1.6410056e-02 4.2562264e-01
+1 6.4293068e-01 1 1 9.9054174e-02 -3.8035203e-01 3.4313703e-01 -3.6766132e-01 -1.4729286e+00 -4.0156500e-01 -6.5634101e-01 3.3224298e-02
+1 9.7337835e-01 1 1 -2.4060929e-01 5.6454533e-01 -8.5997166e-01 2.2889292e-01 2.3948401e-01 -9.6197789e-01 -9.9158117e-01 -8.0271358e-01
+1 7.7723151e-01 1 1 -6.9059067e-01 7.0351312e-01 9.2418287e-01 -1.4476294e+00 6.2757381e-01 -1.3266837e+00 6.4432552e-01 -1.2083149e+00
+1 1.9624321e-01 1 1 1.4275118e+00 -1.0097900e+00 7.0738182e-01 1.3276726e+00 1.3065683e+00 1.4511947e+00 1.0918850e-01 -8.9332341e-01
+1 7.7950798e-01 1 1 -1.5296134e-01 -6.5618419e-01 1.1796229e+00 -5.3986390e-01 -2.3987303e-01 -1.0961639e+00 4.4097151e-01 -4.1520747e-01
+1 7.7374436e-01 1 1 -9.9842662e-01 -1.4974191e+00 -6.6836576e-01 -5.7303523e-01 -8.8268297e-01 -9.2816955e-01 3.9107136e-01 -9.1471336e-01
+1 2.7810453e-01 1 1 -1.3099176e+00 1.7587934e-01 1.1119814e+00 1.1199217e+00 -6.5217014e-01 1.4035261e+00 5.2448317e-01 1.3670841e+00
+1 8.8071387e-01 1 1 4.9666334e-01 -2.3469241e-01 -2.6277220e-01 1.2427038e+00 -6.7066404e-03 -1.1563283e+00 -3.2042079e-01 -1.0263624e+00
+1 9.4304251e-01 1 1 2.0902026e-01 1.3650465e+00 6.6697250e-01 8.1562647e-01 3.7883011e-01 -5.1730815e-01 -6.2240891e-01 4.1304261e-01
+1 6.5744560e-01 1 1 7.0299536e-01 -7.1523866e-01 6.0426739e-01 1.4653589e+00 -1.0106972e+00 1.5303745e+00 6.7692184e-01 -9.1266483e-01
+1 7.6071097e-01 1 1 -2.8698570e-01 -1.2826414e+00 -8.4710585e-01 1.3425569e+00 -1.9670124e-01 7.8541635e-01 1.3184305e+00 1.2391355e+00
+1 3.8204460e-01 1 1 -1.0239240e+00 2.5404517e-01 3.8995957e-01 1.4354934e+00 -1.0022257e+00 -4.7966168e-01 1.2077112e+00 5.3273048e-01
+1 8.4463895e-01 1 1 5.5453755e-01 3.1268075e-01 6.8821006e-01 -1.0946107e+00 8.1202586e-01 -3.4711107e-01 1.7248644e-01 6.2048254e-02
+1 1.3190197e+00 1 1 -9.9276364e-01 -6.5917965e-01 -5.9761307e-01 4.5034939e-02 6.4019081e-01 4.1720868e-02 -7.1038129e-01 -1.6376400e-01
+1 8.5623179e-01 1 1 -3.7983207e-01 1.5648722e+00 -4.1117382e-01 -2.2160910e-01 -2.6783969e-01 6.2746381e-01 -1.3262934e+00 -3.4637762e-01
+1 7.8286046e-01 1 1 -1.2137803e-01 -6.0590849e-01 9.0544386e-01 1.3447912e+00 3.2067456e-01 -5.4222189e-01 -1.4125948e+00 -1.9745605e-01
+1 3.1169658e-01 1 1 -1.1068692e+00 1.5393484e+00 -7.9856306e-02 1.2879200e+00 -1.3957220e+00 6.3693338e-01 -4.6446172e-01 -1.1219245e+00
+1 4.7666326e-01 1 1 1.3615634e+00 8.1361550e-01 -6.8486468e-01 4.9793849e-01 3.7223829e-01 1.5332275e+00 6.4954184e-01 -3.4630491e-01
+1 5.7188389e-01 1 1 4.3454064e-01 -9.1710549e-01 2.7480596e-01 -3.5061491e-01 1.2979504e+00 -1.5298360e+00 -1.8469630e-01 1.0245802e+00
+1 9.0425493e-01 1 1 -8.7835097e-01 -1.1384067e+00 5.2261345e-01 8.4302487e-01 -5.6750418e-01 -1.1593027e+00 -2.9720558e-01 1.0493756e+00
+1 1.0274773e+00 1 1 -1.0082240e-01 -9.0200538e-01 -3.2886191e-01 1.3617622e-01 -1.6744438e-01 -2.4351176e-01 -1.8490765e-03 -4.5579918e-02
+1 1.2359896e+00 1 1 -1.2036093e+00 1.3217581e+00 -1.1206061e+00 -1.5072856e+00 6.2937717e-01 7.9312041e-01 3.3849747e-01 4.8691812e-01
+1 7.7532720e-01 1 1 -3.4586875e-01 5.8675895e-01 -1.7810789e-01 8.5379799e-01 1.9970649e-01 1.9708019e-01 -2.9726216e-01 -2.1595156e-01
+1 9.5151883e-01 1 1 -1.0697509e+00 1.9841498e-01 4.7850033e-01 -1.0124863e+00 1.2460158e+00 1.0880516e+00 -9.5273693e-01 -9.5827894e-01
+1 8.9676779e-01 1 1 3.1992814e-02 1.5308146e+00 -3.2210478e-01 1.1493946e+00 -6.8557053e-02 -3.2813501e-01 4.8155725e-02 1.1514124e+00
+1 5.7109285e-01 1 1 4.9087602e-01 -1.2434142e+00 -6.5081904e-01 2.2207027e-01 7.2612159e-01 -1.4700569e+00 -1.1776325e+00 -4.2280096e-01
+1 3.5458093e-01 1 1 3.3088042e-01 -1.8804455e-01 7.1003224e-01 1.2288808e-01 -1.1618724e+00 1.3806642e+00 -4.3500877e-01 2.6682562e-01
+1 9.1995074e-01 1 1 4.8827434e-01 -2.2466572e-02 -1.3985860e+00 1.3535200e+00 5.4978064e-01 1.0204008e+00 -7.0626532e-01 1.4854078e+00
+1 1.1103437e+00 1 1 5.8679358e-01 -6.0455783e-01 -6.3941622e-01 3.3823862e-01 7.3927112e-01 -7.8473877e-02 -1.2642526e+00 -9.8748527e-01
+1 6.9136767e-01 1 1 7.8032176e-01 -8.9280775e-01 7.1998288e-01 -1.5062630e+00 -6.9185208e-02 5.5845964e-01 1.4389906e+00 3.6900441e-01
+1 9.4162282e-01 1 1 -1.2814387e+00 -1.1734174e+00 -6.6266324e-01 -8.0798174e-01 -4.0650287e-01 -1.0476804e+00 1.1345190e+00 3.5327986e-01
+1 3.2452252e-01 1 1 -1.5225121e+00 1.2926962e+00 -4.3517784e-01 1.3558883e+00 8.7022953e-01 2.6301693e-01 1.5342802e+00 -3.5465091e-02
+1 6.1448270e-01 1 1 -5.8805653e-01 -9.1001154e-01 -4.0632114e-01 -6.9883236e-01 -1.3077511e+00 3.0468744e-01 4.5549108e-01 8.4082445e-01
+1 8.3284773e-01 1 1 -1.5530458e-02 -1.2908824e+00 7.8303894e-01 1.1394824e+00 -7.9035762e-01 8.5796154e-02 -6.2271469e-01 8.5282182e-01
+1 6.3621189e-01 1 1 -2.6821004e-01 -2.2452769e-02 4.0381266e-01 1.3183361e-01 -8.8674142e-01 -1.5070796e-02 -1.3207155e+00 1.4306766e+00
+1 5.3142016e-01 1 1 3.7932348e-01 -3.7257699e-01 1.0391813e+00 9.0465246e-01 2.5253576e-01 1.1741443e+00 1.2289652e+00 -3.6789997e-01
+1 3.7036887e-01 1 1 9.9822149e-01 -7.0735599e-01 1.4064279e+00 -8.1455634e-01 7.6872901e-02 1.5004783e+00 -7.5404124e-01 -6.4045941e-01
+1 2.4448121e-01 1 1 1.0037857e+00 -7.4548562e-01 4.9004645e-01 8.1240908e-01 8.0826078e-01 9.7522999e-01 1.3601527e-02 -1.1049369e+00
+1 7.3521923e-01 1 1 2.7364077e-01 -7.0537340e-01 -1.0451784e+00 7.9766394e-01 1.9226925e-01 1.0015914e+00 -7.3540060e-01 -7.2006465e-01
+1 4.3568442e-01 1 1 -2.1121773e-01 1.1599367e+00 1.4728285e+00 1.1620307e+00 -1.2295632e+00 1.0932824e+00 -8.5230964e-01 -7.1161730e-01
+1 8.3570298e-01 1 1 6.3242754e-02 1.4734772e+00 1.2201431e+00 -1.0309821e+00 1.2830782e-01 -3.7779452e-01 8.9433594e-01 -1.0872758e-01
+1 6.5874826e-01 1 1 1.0626484e+00 -4.4357075e-01 -1.3721668e+00 1.3082703e+00 1.3369016e+00 -4.3370651e-01 -1.4167407e+00 1.0224542e+00
+1 8.1871437e-01 1 1 -2.2049427e-02 -9.4220409e-02 4.2482403e-01 9.1403013e-02 6.3503192e-01 -8.1029849e-01 -1.0304184e+00 -1.2479275e-01
+1 1.0474710e+00 1 1 1.2321689e-01 -1.9970896e-01 -8.2269095e-01 -2.8374034e-02 9.9124276e-01 1.1737922e-01 1.3574815e+00 1.1922172e+00
+1 9.3383513e-01 1 1 5.9674030e-01 -1.2874945e+00 -8.1747438e-01 6.3969050e-01 -4.8838274e-02 -1.2766859e-01 9.4612077e-01 5.1665910e-01
+1 8.8461958e-01 1 1 1.4504490e+00 3.6936896e-01 -1.1071793e+00 7.4816769e-01 -8.6919566e-01 -1.8176162e-02 -1.2901837e+00 1.2736461e-01
+1 6.5243071e-01 1 1 -1.0618727e+00 1.9694574e-01 -7.0990950e-01 -1.3410131e+00 -1.6566561e-01 -7.5227519e-01 -8.4476583e-01 1.1923247e+00
+1 7.0172793e-01 1 1 4.9327234e-01 -1.1716164e+00 3.2001238e-01 -6.2092591e-01 -8.9079651e-01 1.4213572e+00 -1.1220636e+00 -8.1875313e-01
+1 7.5830026e-01 1 1 -2.3485270e-01 1.4661773e-01 4.1420159e-02 4.6910168e-01 1.2136694e+00 7.9451458e-02 4.5797324e-01 -6.0802884e-01
+1 8.9607666e-01 1 1 -1.3289309e+00 1.1954871e+00 -1.2849540e+00 -1.2055636e+00 -2.1897722e-01 1.6377050e-01 2.5420991e-01 4.6023446e-01
+1 4.7571427e-01 1 1 1.3821789e+00 -1.0751951e+00 -9.1451313e-01 1.3650571e+00 -1.5450860e+00 4.5564342e-01 -6.0041738e-02 5.5943560e-01
+1 8.3464687e-01 1 1 1.3439114e+00 -3.6248787e-01 -1.5508670e+00 -5.3693182e-01 1.4504761e-01 -1.2039126e+00 -6.7025705e-01 -3.5274208e-01
+1 1.0547093e+00 1 1 -9.3239172e-01 -7.8552165e-01 3.7329686e-01 -1.5589771e+00 -6.0765988e-02 8.3934403e-01 7.4100110e-01 -3.5083786e-01
+1 7.6220690e-01 1 1 -4.4340251e-01 -1.2900804e+00 2.3976339e-01 -8.4615139e-01 -2.7635248e-01 1.1040139e+00 7.3227309e-01 2.3744471e-01
+1 8.3887265e-01 1 1 -4.0825310e-01 8.9087374e-01 -9.6008330e-01 7.2346506e-01 -1.3822494e+00 9.1567708e-01 -1.4461890e+00 9.1049593e-01
+1 1.0998187e+00 1 1 -2.7141816e-01 8.4316832e-02 -9.0023453e-01 1.3137585e+00 6.1267348e-01 -8.7776910e-01 4.0460889e-01 7.2181146e-03
+1 5.9651498e-01 1 1 -1.3246366e-01 2.5470927e-01 -3.3160479e-01 1.2256407e+00 -9.3760156e-01 2.5378727e-01 -1.2865242e+00 -1.2072612e+00
+1 8.7456578e-01 1 1 1.0725244e+00 -1.0920800e+00 -9.6361339e-02 -7.9513320e-02 -4.0743656e-02 -8.8023999e-01 9.7031012e-01 1.1071986e+00
+1 7.6171842e-01 1 1 -5.4110976e-01 -1.4044670e+00 1.5167777e+00 -1.2034921e+00 8.8570337e-02 -4.3364329e-01 -5.2475435e-03 1.0335517e+00
+1 7.0777297e-01 1 1 4.7893532e-01 1.0510909e+00 -1.5409040e+00 -1.5189067e+00 -5.1327100e-01 2.5214178e-01 -2.3086889e-01 1.0368582e+00
+1 6.2515732e-01 1 1 7.0553622e-01 5.1010409e-01 1.3167116e+00 3.1716771e-01 2.6772723e-01 -2.6161167e-01 -3.4643718e-01 6.1800176e-02
+1 8.1948739e-01 1 1 -1.5650160e+00 -8.6964891e-02 5.9289485e-01 -6.4496944e-01 9.3079675e-01 1.3224195e+00 -1.1985757e+00 -1.1916058e+00
+1 3.9604979e-01 1 1 1.3311632e+00 -7.7833533e-01 -3.4810011e-01 -1.5066670e+00 -1.2304161e+00 -8.6373412e-01 -5.6938066e-01 3.3377734e-01
+1 1.3076541e+00 1 1 -1.5634368e+00 1.0998203e-01 -8.7307673e-01 -1.3150120e+00 1.5016010e+00 5.2037086e-01 -2.8945407e-01 -1.0887946e+00
+1 8.5679413e-01 1 1 -4.0094858e-01 1.2115198e+00 5.7875176e-01 -3.0248284e-01 9.9465362e-01 -3.2096878e-01 1.4725036e+00 4.0670792e-01
+1 7.9131857e-01 1 1 -2.6518702e-02 1.3508219e+00 7.1005765e-01 -7.3219594e-01 7.2895432e-01 -4.0777424e-01 -1.0982351e+00 -5.6564665e-01
+1 7.4495852e-01 1 1 4.0634046e-01 -1.0270587e+00 -9.7152985e-01 -3.9874515e-01 -6.7604116e-01 1.4935457e+00 -1.1802909e+00 -3.6381517e-01
+1 7.0634360e-01 1 1 -4.5829035e-01 1.2766377e+00 1.4963712e+00 -6.9258830e-01 9.1683031e-01 6.9752283e-01 -1.1330077e+00 -1.1022503e+00
+1 4.3599187e-01 1 1 6.9921873e-01 -6.2830267e-01 1.0619176e+00 -7.3076598e-01 -3.4498798e-01 -1.1576479e+00 -1.2673695e+00 4.5050150e-01
+1 4.5837216e-01 1 1 -9.2892536e-01 -9.9013816e-01 2.6140915e-01 -1.4980749e+00 1.1670343e+00 -7.0547003e-01 -6.8105365e-01 3.4048046e-01
+1 2.2108009e-01 1 1 1.2668867e+00 -2.3583338e-01 1.5570525e+00 -1.4216657e+00 1.3827401e+00 -4.6410129e-01 1.4949643e+00 -1.5266710e+00
+1 8.4567583e-01 1 1 -1.1508122e+00 1.0383804e+00 -8.5541493e-02 1.0181815e+00 1.3513981e+00 4.2424044e-01 -5.9272705e-01 -1.3723236e+00
+1 5.6540602e-01 1 1 1.0858087e+00 5.1181227e-01 1.1535553e+00 3.2106978e-01 -7.6765089e-01 -1.2061661e+00 2.6740421e-02 9.3110453e-01
+1 7.5477799e-01 1 1 -3.2523310e-01 3.4811858e-01 1.0361125e+00 -1.0364366e+00 6.1255510e-01 6.6443084e-01 1.7851264e-01 8.0085661e-01
+1 8.1073932e-01 1 1 1.7843239e-01 1.1835155e+00 9.4419484e-02 7.4076900e-01 2.1443885e-01 -1.2727688e+00 4.0995674e-02 1.4141764e+00
+1 6.2457227e-01 1 1 -1.3078371e+00 -1.2192814e+00 4.0397580e-01 -2.7051240e-02 6.6692846e-01 -3.2043486e-01 1.0055096e+00 -1.2279416e+00
+1 5.3199663e-01 1 1 9.0648739e-01 1.4696265e-01 6.3953575e-01 8.8073958e-01 -1.3593220e-01 -8.5896298e-01 9.7288981e-01 -8.9224851e-01
+1 6.2412513e-01 1 1 -1.3907512e+00 7.0941316e-01 1.2889195e+00 -5.9441184e-01 -6.7467027e-01 -9.7260193e-01 -6.3070728e-01 -1.1989760e+00
+1 6.8037391e-01 1 1 -9.0587055e-01 7.6287236e-01 -1.5522217e+00 -1.5217286e-02 -1.1752594e+00 -8.1409784e-01 -5.6361813e-01 -1.0143281e+00
+1 4.1115812e-01 1 1 -8.0827655e-01 7.5607989e-01 -4.0409881e-01 -1.2879259e+00 -1.3922203e+00 -9.0632690e-01 -8.2809294e-01 -1.5302602e+00
+1 7.8084435e-01 1 1 -4.5739372e-01 -3.0751415e-01 4.3468597e-01 -5.9795948e-01 -4.6466807e-01 9.4660270e-01 -5.0261249e-01 1.1357833e+00
+1 3.0567455e-01 1 1 6.0986370e-02 -4.7032791e-01 1.5641479e+00 4.9894855e-02 3.2300254e-01 5.2636426e-01 3.3449104e-01 7.9284683e-01
+1 4.6127722e-01 1 1 8.3870824e-01 -5.5402365e-01 -2.1431513e-01 -2.2240541e-01 3.1543459e-02 -1.2071534e-01 1.4815947e+00 -1.2592931e+00
+1 3.7649799e-01 1 1 -1.5683313e-01 2.0519653e-01 1.4124165e+00 5.2752712e-01 -7.7823650e-01 6.0606390e-01 8.9950227e-01 -2.9128628e-02
+1 1.6905429e-01 1 1 -9.8199758e-02 -7.3065421e-01 6.0950614e-01 5.7384998e-01 -1.3706672e+00 1.0726550e+00 5.9074656e-01 5.2360603e-01
+1 1.1973107e+00 1 1 -1.1071869e+00 3.8031830e-01 -7.6387119e-01 7.0927030e-03 4.9587262e-01 -1.4878465e+00 1.2447126e+00 6.4558439e-01
+1 4.5662876e-01 1 1 -8.3739446e-01 -1.1313801e+00 1.3061280e+00 -1.7346099e-01 -5.1424669e-01 8.4107288e-01 1.9961553e-02 -7.2420128e-01
+1 9.0042487e-01 1 1 2.4640008e-01 9.5472048e-01 -1.3558315e+00 3.9169724e-02 -4.2273617e-01 -1.2551264e+00 -6.5659195e-01 -1.1209040e+00
+1 1.1714197e+00 1 1 6.2702691e-01 -1.2681722e+00 -1.4881844e+00 -1.4088978e+00 1.3557710e+00 8.8535256e-01 1.0740770e+00 1.0980532e+00
+1 6.0822524e-01 1 1 1.5395450e+00 1.5353860e+00 1.4463213e+00 -1.1618149e+00 4.7098464e-01 1.5377207e+00 4.1997320e-01 1.2645556e+00
+1 1.1285068e+00 1 1 9.7632987e-01 1.9085805e-01 -1.3224064e+00 1.5164781e+00 -9.7455857e-01 -1.4106136e+00 -6.6908479e-01 5.1158669e-01
+1 7.7274092e-01 1 1 6.3762583e-01 1.8514744e-01 1.0831017e+00 -2.9363294e-01 8.5812764e-01 1.4174060e+00 -1.5479055e+00 -3.0152196e-01
+1 6.9388177e-01 1 1 6.0472205e-01 -1.5452781e+00 1.3022110e+00 3.5321054e-01 -5.0067493e-01 -3.5467250e-01 -1.1954747e-01 -2.9065401e-01
+1 1.2115252e+00 1 1 5.1133220e-01 5.7521096e-02 -1.2162608e+00 -1.2005818e+00 1.4831911e+00 -1.3794783e+00 1.3849390e+00 1.5467576e-01
+1 8.3241118e-01 1 1 -1.4371790e+00 -8.5348471e-01 6.4803389e-01 2.7167235e-01 -5.4459427e-01 6.1438543e-02 6.0900960e-01 1.5383994e+00
+1 8.2113657e-01 1 1 1.0391791e+00 -5.4838633e-03 -3.9621193e-01 1.2631049e+00 -1.5365310e+00 -9.8639224e-01 3.1542381e-01 5.7064031e-01
+1 2.9577606e-01 1 1 1.3702846e+00 -1.0611029e+00 1.0424810e+00 1.2616544e+00 -5.8459819e-01 -1.0990662e-01 1.4611188e+00 -5.3063400e-01
+1 8.1086344e-01 1 1 -6.4265029e-01 8.6528564e-01 3.1590802e-01 -1.1252728e+00 1.5599959e+00 5.5855347e-02 -8.0691798e-01 6.1597368e-01
+1 7.1082773e-01 1 1 -2.2781021e-01 4.2327974e-01 1.7455312e-01 -7.1713426e-02 -8.8076000e-01 -5.7539000e-01 3.8505985e-01 1.1218555e+00
+1 9.8263948e-01 1 1 7.9520605e-01 1.4968105e+00 -5.3325110e-01 1.0840352e+00 2.5129657e-01 -7.5756116e-01 1.9962331e-02 -8.1369763e-01
+1 6.6470874e-01 1 1 6.9286132e-01 -9.7913281e-01 6.1254037e-01 1.2832089e+00 1.2409614e+00 5.4454398e-01 -6.4351153e-01 -4.6319893e-01
+1 6.0875583e-01 1 1 -9.6377198e-01 -6.2281124e-01 -3.3081141e-02 -1.4230850e-01 -1.9575789e-01 6.9119625e-01 1.0052864e+00 -1.1788030e-01
+1 5.5124038e-01 1 1 -6.3963291e-02 1.9828987e-01 6.7156838e-02 -1.0268893e+00 -8.5531298e-01 -6.7421961e-01 3.6352320e-01 1.1307677e+00
+1 8.4677711e-01 1 1 -6.0634139e-01 -5.7196203e-01 8.7321478e-01 9.8178306e-01 6.8273056e-01 1.1578493e-01 -6.6320943e-01 1.3179461e+00
+1 8.2588655e-01 1 1 5.4686723e-01 3.0773031e-01 -1.3999951e+00 1.1832936e+00 1.5561836e+00 1.3514156e+00 -1.9020248e-01 -6.4940571e-01
+1 2.7207632e-01 1 1 -1.1026461e+00 9.6187234e-01 8.1092133e-01 1.3340406e+00 1.0193326e+00 -4.7243161e-01 1.4081686e+00 -6.6890390e-01
+1 6.8909495e-01 1 1 8.1602490e-02 -4.4731197e-01 9.2587054e-01 -3.2717760e-01 8.1748633e-01 -1.3533837e+00 1.4720736e+00 1.4923097e+00
+1 8.7324758e-01 1 1 -1.3829411e+00 -1.4100076e-01 7.9777644e-01 -1.0868605e+00 1.3081556e+00 -1.1895276e+00 1.0991903e+00 -1.2269466e+00
+1 1.0264252e-01 1 1 1.5523415e+00 -1.0388677e+00 -8.8875067e-02 1.4968657e+00 1.3064360e+00 7.0504856e-01 1.5270981e+00 1.2229961e-01
+1 9.1538701e-01 1 1 -7.2261672e-01 7.2186616e-01 -1.4667372e+00 -5.1774967e-02 6.7871131e-01 -3.3630421e-01 -8.7427638e-01 8.8802177e-01
+1 8.1263529e-01 1 1 3.7792705e-01 -4.2632277e-01 6.2485081e-01 3.9296368e-02 -2.2010324e-02 -5.3973810e-01 -7.3433077e-01 -7.2473862e-01
+1 6.6587351e-01 1 1 -4.8047671e-01 7.6597673e-01 -4.7661416e-01 7.1959705e-01 7.8040988e-01 1.5412974e+00 1.4202459e+00 -7.2734778e-01
+1 8.8809082e-01 1 1 -1.4789692e+00 -4.7576340e-01 6.0702968e-01 -8.6404923e-01 1.9945223e-01 -9.8803733e-01 2.5107087e-01 -5.9707554e-01
+1 9.4980193e-01 1 1 -7.5402833e-01 -8.0211176e-01 -1.5451267e+00 1.5074840e+00 1.1419445e-01 5.1533567e-01 5.8913257e-01 -8.0170578e-01
+1 8.1758300e-01 1 1 2.3055955e-01 -5.1831035e-01 -5.4034697e-01 -6.6034954e-01 -2.4701840e-01 -1.2435535e-01 -7.4901083e-01 2.1789787e-02
+1 6.0437112e-01 1 1 1.4305471e+00 3.9441448e-01 7.3285599e-01 7.5211594e-01 1.5472415e+00 -8.8126381e-01 -2.6321556e-01 -1.3453965e+00
+1 1.1414286e+00 1 1 5.9710512e-01 1.6366415e-01 -1.0741961e+00 -9.5616199e-01 1.5247262e+00 1.2084420e+00 -5.0150434e-01 1.1054455e+00
+1 7.7183905e-01 1 1 1.2988603e+00 -1.3318507e+00 7.1923266e-01 -9.6805957e-01 1.0221157e-01 -1.1116883e-01 1.0961561e-01 -1.5670505e-01
+1 9.3795615e-01 1 1 -9.8287758e-01 -5.6679134e-01 -7.0525638e-01 1.3110914e-01 -5.8126260e-01 8.3306322e-01 1.3363084e+00 -1.0871774e+00
+1 9.3411558e-01 1 1 -7.2926487e-01 -7.5320337e-01 -1.4846944e-02 1.2948198e+00 1.0725771e+00 -7.8488868e-01 8.9993895e-02 -6.8824947e-01
+1 7.6720073e-01 1 1 -1.4017998e+00 1.5294144e+00 -1.3467716e+00 2.2344029e-01 3.4440056e-01 -7.6465507e-02 1.4213243e+00 -6.4694064e-02
+1 1.1163962e+00 1 1 -1.2458889e+00 3.5597136e-01 -1.4622881e-02 1.1577370e+00 1.5264679e+00 -2.4438476e-01 -4.7383575e-01 -3.2207143e-01
+1 1.0521056e+00 1 1 -9.3994291e-01 1.2181568e+00 -7.2252966e-01 -9.3942209e-01 1.1003680e+00 -1.3130572e+00 1.7996043e-01 -9.0401527e-02
+1 5.9132062e-01 1 1 1.4489543e+00 -1.9734165e-01 -1.3004529e+00 7.7756198e-01 -6.7122906e-01 1.1357077e+00 -7.5878746e-01 1.1523847e+00
+1 8.7575038e-01 1 1 -1.0519063e+00 8.0077495e-01 -6.5228982e-01 -5.4117687e-01 1.1239926e-01 -4.7784757e-01 -1.2162235e+00 2.1025117e-01
+1 6.6939045e-01 1 1 1.4949097e+00 4.1666099e-02 1.1233036e+00 -6.4900542e-01 9.9726159e-01 -1.2732073e+00 1.2755746e+00 -6.0028162e-01
+1 6.4314491e-01 1 1 -1.5106926e+00 -2.9303418e-01 1.5330539e+00 -2.2447281e-01 5.7876640e-01 -1.4072082e+00 3.5452434e-01 -1.2791937e+00
+1 1.0426662e+00 1 1 1.4197302e-01 9.9177852e-01 -1.3054731e+00 3.3830000e-01 9.5610240e-01 -1.0392356e+00 -1.1106460e+00 -1.4897379e+00
+1 1.0305908e+00 1 1 -1.4698941e+00 -4.6907165e-01 -2.0264885e-01 -4.7463053e-01 -3.3305935e-02 8.2278059e-01 7.1588643e-01 4.6940410e-01
+1 7.1708235e-01 1 1 9.7506857e-01 -1.4313017e+00 -4.3284862e-01 -6.1158536e-01 -5.6935411e-01 -8.1753366e-01 -3.9658695e-01 7.3562134e-01
+1 3.6331513e-01 1 1 1.4302253e+00 -7.1250115e-01 1.0417698e+00 3.7605273e-01 1.5673102e-01 1.0379653e+00 1.0228195e+00 1.4207139e+00
+1 6.2204380e-01 1 1 1.4717070e+00 7.4444664e-01 9.2849172e-01 -5.6614643e-01 1.5235276e+00 -1.8193368e-01 -2.6792351e-01 -1.3077987e+00
+1 3.1400879e-01 1 1 1.2204876e+00 -1.0488334e+00 8.6958693e-01 6.6116656e-01 -1.1931681e+00 -9.8969435e-01 -1.0881265e+00 1.5507967e+00
+1 3.6046566e-01 1 1 1.2767134e+00 -2.6644491e-01 4.5844245e-01 4.1313167e-01 -7.9090929e-01 9.4024093e-01 -9.3134759e-01 -1.5549362e+00
+1 7.2554660e-01 1 1 6.4433412e-01 -1.3700773e+00 -1.2844735e+00 5.8423240e-01 -7.3384536e-01 4.1832136e-01 1.3971793e+00 1.0967946e+00
+1 6.8648237e-01 1 1 2.5366326e-01 9.8551554e-01 8.7813601e-01 -1.4246839e+00 1.5374343e-01 -1.5721437e-01 -1.0119337e+00 -1.0385331e+00
+1 1.6881284e-01 1 1 1.7721322e-01 1.0831405e+00 -3.7043755e-01 5.5667116e-01 -1.5649393e+00 -2.2248008e-01 1.0121852e+00 6.2402847e-02
+1 7.6578437e-01 1 1 1.9275272e-01 -1.1877454e+00 6.9281848e-01 3.0923389e-01 -5.2188473e-01 -7.2745602e-01 7.3018695e-02 -4.8729152e-01
+1 2.9748901e-01 1 1 6.1299811e-01 -7.5759092e-01 1.4578564e+00 1.0997245e+00 1.0071432e-02 7.2533002e-01 -1.1375169e+00 2.2348356e-01
+1 4.9489977e-01 1 1 1.3769410e+00 4.4389848e-02 9.1146225e-01 1.0806055e+00 -3.7543798e-01 1.2421926e+00 1.4860406e+00 -1.2566873e+00
+1 9.2222506e-01 1 1 1.2756750e+00 1.5027123e+00 5.4020008e-01 1.8983872e-01 1.4734778e+00 -1.4930356e+00 2.2354798e-01 -2.1659084e-01
+1 3.2739521e-01 1 1 -1.1007016e+00 8.2286210e-01 -5.9972181e-02 -1.2387049e+00 -4.3368667e-01 -1.5483775e+00 -1.7396257e-01 8.6365393e-01
+1 3.3045519e-01 1 1 1.3469446e+00 5.5251787e-01 4.9879360e-01 4.2176341e-01 -4.7689519e-01 1.3720759e+00 1.0338845e+00 1.2735693e+00
+1 4.2768976e-01 1 1 -2.1957496e-01 -3.8005255e-01 1.4548113e+00 1.1445820e+00 -9.7461570e-01 1.1902929e+00 3.4833277e-01 1.2078218e+00
+1 7.8146664e-01 1 1 9.7502686e-01 -6.8533196e-01 -2.0603468e-03 1.0178958e+00 -1.0200503e-01 -4.0893615e-01 -1.4997993e+00 -1.1106041e+00
+1 9.8339306e-01 1 1 7.2911949e-01 -1.2955251e+00 -7.0728803e-02 -1.3394515e+00 9.1107202e-01 8.1488835e-01 1.0132526e+00 1.4206558e+00
+1 7.7036011e-01 1 1 -1.0416579e+00 4.8786127e-01 -1.2169643e+00 4.9080323e-01 2.6478185e-01 -1.5153918e+00 -8.3813645e-01 8.5740909e-01
+1 3.9351441e-01 1 1 9.5105710e-01 -7.2456439e-02 1.3914710e+00 -8.9245891e-01 -1.4482785e+00 -2.9906795e-01 3.4220866e-01 -1.0904618e-02
+1 3.9740249e-01 1 1 -6.6642582e-03 1.1625835e+00 4.3739281e-01 1.5480936e+00 -1.5618097e-01 1.1313787e-01 -7.5525834e-01 -1.0615481e+00
+1 4.4009017e-01 1 1 1.0911477e+00 -1.1657328e+00 -6.5902468e-02 1.3815588e-01 1.4378771e+00 8.4465644e-01 1.5489823e+00 -3.3385153e-01
+1 6.0910429e-01 1 1 1.4437044e+00 -1.4992636e+00 1.3594314e+00 3.4893758e-01 1.2701426e+00 -7.1649826e-01 -6.3314275e-01 -1.5814852e-01
+1 1.0532998e+00 1 1 -1.3220533e+00 5.9196192e-01 -8.3927988e-01 -7.5961212e-01 1.6478180e-01 -4.6169283e-01 -6.5591396e-01 -2.1483728e-01
+1 1.9052324e-01 1 1 7.3498690e-01 -3.1992695e-01 -2.5886970e-02 6.3162853e-01 -1.3969335e+00 6.2532441e-02 -9.7326081e-02 -1.0802812e+00
+1 3.6961438e-01 1 1 1.8256086e-01 1.3943531e+00 -1.5425119e+00 3.3909108e-01 -1.1390668e+00 -1.4507968e+00 1.0103254e+00 -1.0230111e+00
+1 9.2599440e-01 1 1 -1.0355752e+00 -1.3881058e+00 -5.7436006e-01 2.5468489e-01 5.7039494e-01 1.5005424e+00 2.3120547e-01 1.8978933e-01
+1 3.6840649e-01 1 1 -4.8908211e-01 -4.2760799e-01 8.4462257e-01 -1.5018268e+00 -1.5129402e+00 -1.0899568e+00 -2.7983332e-01 1.0727480e+00
+1 8.7568559e-01 1 1 1.5449921e+00 1.1564515e+00 -1.2855951e+00 1.4944709e+00 6.4572922e-02 -2.7757993e-01 -1.9438439e-01 7.5116689e-02
+1 5.9999387e-01 1 1 1.4196900e+00 -5.5290585e-01 8.7774292e-01 5.3997148e-01 1.4276419e+00 -2.0725152e-02 2.3795527e-01 -4.3404717e-01
+1 6.2371116e-01 1 1 3.3418827e-01 1.4252329e-01 -6.9392388e-01 -7.6050836e-01 -1.1070497e+00 3.8914829e-01 6.6722335e-02 -2.5257728e-01
+1 1.2106957e+00 1 1 -4.6546656e-01 1.4952971e+00 -1.1867569e+00 1.2764503e+00 1.4692106e+00 -3.8065548e-01 -1.4628783e-01 -7.7470863e-01
+1 9.1983462e-01 1 1 -5.3069985e-01 -1.2827277e+00 1.4815856e-01 -6.3646150e-01 1.0351754e-01 -1.3939491e+00 1.2075450e+00 1.3735656e+00
+1 1.0447821e+00 1 1 -4.9089578e-01 -1.1964067e+00 -1.1820895e+00 1.1460264e-01 -6.2304082e-01 -1.2452764e+00 5.2079378e-01 1.0949841e+00
+1 5.1554145e-01 1 1 -6.6302977e-01 1.3267927e+00 5.3270934e-02 3.3028227e-01 -5.1874437e-01 -6.9738316e-02 5.0385187e-01 -5.2345654e-02
+1 8.6109990e-01 1 1 -3.1228240e-01 3.8016309e-01 -2.9322542e-02 -1.4018827e-01 -6.1694975e-01 -2.7782527e-01 -1.4954323e+00 -1.2746660e-01
+1 6.6713025e-01 1 1 1.0710326e+00 -5.9837325e-01 4.0608306e-01 5.0159357e-02 1.3229548e+00 -1.0026872e+00 -9.9016813e-01 2.3506851e-01
+1 5.8093887e-01 1 1 -4.8071484e-01 -6.2120622e-01 1.4987412e+00 1.0814776e+00 -1.2909749e+00 -6.6010369e-01 -7.3947890e-01 -1.3271166e+00
+1 5.7756884e-01 1 1 8.0199961e-01 -1.1005943e+00 5.4056304e-02 -8.6027949e-01 1.5659132e+00 -1.3991304e+00 -2.8125292e-01 4.5893477e-01
+1 8.7906221e-01 1 1 -1.3666477e+00 9.3686451e-03 6.0402879e-01 -1.1079258e+00 1.1820320e+00 -3.6437064e-01 1.0791216e+00 7.0671776e-01
+1 6.2385458e-01 1 1 -1.0635430e+00 3.7918634e-01 1.4259704e+00 -6.8891996e-01 -1.0196734e+00 -1.0132812e+00 3.8172634e-01 -5.5637298e-01
+1 8.1545445e-01 1 1 6.9581038e-01 -1.3067116e+00 -9.2521412e-01 1.2326941e+00 -2.6210091e-01 3.5720956e-01 5.4234426e-01 1.5606480e+00
+1 6.2240303e-01 1 1 1.4772631e+00 9.7252848e-01 8.0999691e-01 -9.1359721e-01 -6.1716314e-01 3.7496546e-02 1.4197421e+00 6.5369413e-01
+1 5.2099025e-01 1 1 3.5476850e-01 -4.2042870e-01 1.0970678e+00 1.2765043e+00 8.7807702e-01 -1.2556818e+00 1.2090769e+00 4.8764951e-01
+1 5.3951037e-01 1 1 -1.4862428e-01 -7.0324507e-01 4.1154580e-01 2.7159534e-01 -1.3617960e+00 9.7503476e-01 1.1339670e+00 -4.8989486e-01
+1 8.3366216e-01 1 1 -3.6217906e-01 -7.6824636e-01 -9.3682551e-01 -3.1193323e-02 -1.2035032e+00 8.6196448e-01 -1.4600468e+00 4.5141640e-01
+1 5.9536422e-01 1 1 1.2630359e+00 2.9308466e-02 4.3608515e-01 3.7979159e-01 1.4371505e+00 1.1532765e+00 -2.7057743e-02 9.2446833e-03
+1 4.9119690e-01 1 1 1.0238946e-01 -6.4266172e-01 -5.2547129e-02 -5.5904992e-01 -1.5179915e+00 -5.0803732e-01 7.7144919e-01 1.4373526e+00
+1 5.0480970e-01 1 1 -7.3311770e-01 -4.1991051e-01 -3.7205655e-01 5.5159558e-01 -9.6177713e-03 2.6559490e-01 3.9371865e-01 -1.2627799e+00
+1 5.6226960e-01 1 1 -1.8272529e-01 -1.4187961e+00 -1.3851164e+00 -1.7305622e-01 -1.4246572e+00 -3.4963774e-01 1.0351517e+00 1.0586662e+00
+1 5.2256924e-01 1 1 1.4136823e+00 -1.0173661e+00 -4.4928658e-01 5.5898537e-01 1.0048232e+00 1.5583214e+00 -3.4493418e-01 -9.7830853e-01
+1 8.3412312e-01 1 1 -1.0687284e-01 8.1600083e-01 1.2291948e+00 1.5050103e+00 -1.1382094e+00 -7.5009052e-01 -1.0703617e+00 6.6451215e-01
+1 6.3408657e-01 1 1 7.7919545e-01 1.4740791e+00 -3.6908657e-02 -1.3962170e+00 -7.2803005e-01 4.3988215e-01 -8.0959221e-01 9.3766780e-02
+1 9.0989525e-01 1 1 -1.3618142e+00 2.4778609e-01 -1.4300508e+00 1.4778417e+00 5.0240974e-01 9.3177019e-01 -5.7840778e-01 -1.1412475e+00
+1 6.8530032e-01 1 1 -1.5080410e+00 -1.2111256e+00 1.4614061e+00 6.5319627e-01 -6.0047191e-01 -5.7779247e-01 -1.2118674e+00 -1.5243452e+00
+1 7.0638818e-01 1 1 7.2387089e-01 -1.0085017e+00 8.8091980e-01 1.5449635e+00 -1.3358140e+00 -2.9516831e-01 -9.1062777e-01 1.9142865e-02
+1 6.4815610e-01 1 1 -1.2902911e+00 -9.9539454e-01 -7.0712401e-01 9.3812388e-01 -1.2048912e+00 -3.1904583e-01 9.1839818e-01 1.2916744e+00
+1 9.4898233e-01 1 1 4.9135943e-01 -6.1512328e-01 1.1748789e-02 -6.0552044e-01 9.9042245e-02 4.9532366e-01 8.7352364e-01 7.6693853e-01
+1 9.6412886e-01 1 1 -9.6913444e-01 6.0442431e-01 -4.5843275e-01 -1.3634610e+00 -4.4109384e-01 -3.1576585e-01 6.4934920e-01 -1.8731488e-02
+1 5.6273975e-01 1 1 9.1534482e-01 -1.3512964e+00 1.4475363e+00 -9.1235263e-01 6.9446050e-01 -9.2660792e-01 -2.8095129e-01 -6.6084729e-01
+1 7.6803489e-01 1 1 -1.7881865e-01 -6.6586452e-01 2.4847357e-01 2.0304448e-01 7.8098086e-01 -6.2449339e-01 -1.3461244e-01 -1.3304170e+00
+1 5.0995754e-01 1 1 1.0991732e+00 -8.3201952e-01 9.1863540e-01 7.9899386e-01 3.7113264e-01 2.0063841e-01 -4.8461517e-01 1.5374314e+00
+1 4.3551025e-01 1 1 1.2397959e+00 -5.2315408e-01 -1.4226893e+00 1.5228690e+00 1.5649438e+00 1.2008775e+00 1.2226273e+00 1.0686116e-02
+1 7.5154161e-01 1 1 -9.3413771e-01 6.6719511e-01 -4.7667884e-01 3.0340147e-01 5.9638414e-01 1.5562145e+00 -4.6050036e-01 5.3076237e-01
+1 5.9125184e-01 1 1 -1.5140422e+00 1.2040204e+00 -4.8004703e-01 4.6363310e-01 -1.3939490e+00 1.5379025e+00 1.2547686e+00 1.5415588e+00
+1 1.0932104e+00 1 1 3.9360000e-01 9.7209808e-01 -5.4053078e-01 1.1316787e+00 -1.2452272e+00 -1.4963289e+00 -6.1603996e-01 2.6330274e-01
+1 1.8281954e-01 1 1 -9.5897374e-01 -1.3710378e+00 7.8505890e-01 9.2140656e-01 7.5673798e-01 -3.5107522e-01 9.0576197e-01 -1.1748595e+00
+1 1.0721055e+00 1 1 -1.1013341e+00 5.4989913e-01 -2.0422685e-01 1.1699305e+00 1.3281903e+00 -6.1014790e-01 -1.0164918e+00 -9.5341970e-01
+1 6.7023377e-01 1 1 1.4213188e-01 -4.1085148e-01 1.3201131e+00 -2.0667166e-01 -1.2624960e+00 -5.9739025e-01 -1.9758070e-01 1.1391584e+00
+1 3.8250061e-01 1 1 1.2000861e+00 3.9791753e-02 1.2140174e+00 1.0708768e+00 -4.5422107e-01 1.9224267e-01 -7.5412647e-02 9.6970211e-01
+1 8.5937344e-01 1 1 8.2267005e-01 -3.7924482e-01 -6.5378669e-01 4.1916197e-02 -2.3369302e-02 1.4652789e+00 -1.3985112e+00 -7.9935456e-01
+1 1.8761602e-01 1 1 4.6622072e-01 3.2386029e-01 1.0981348e+00 7.6876267e-01 -6.8780600e-02 -2.4156179e-03 6.1773059e-01 -1.3018212e+00
+1 7.1163128e-01 1 1 6.3958025e-01 -1.2601200e+00 -5.0479726e-01 -7.7635576e-01 1.1055899e-01 2.4141481e-01 -7.6565191e-01 1.4844996e+00
+1 5.9009364e-01 1 1 -1.1047777e+00 -1.3613238e+00 1.3142450e+00 -1.1769610e+00 1.4837621e+00 -1.4789365e+00 -3.4811495e-01 -5.4474625e-01
+1 8.5243052e-01 1 1 -1.1864154e+00 4.5074424e-01 -2.3060528e-02 1.4252020e+00 -3.7284009e-01 -2.0477344e-01 -1.1224162e+00 -9.4923544e-01
+1 3.6874195e-01 1 1 -3.9564626e-01 1.2786034e+00 -1.1624058e+00 -1.2736728e+00 1.1539328e+00 1.5583516e+00 8.1528366e-01 -7.9256166e-01
+1 7.8239975e-01 1 1 1.1249342e+00 9.9323508e-01 1.0100913e+00 1.9333676e-01 1.0970314e+00 -2.4300279e-01 -1.1547050e+00 -2.3104765e-01
+1 1.1256416e+00 1 1 6.6511076e-01 -1.1213066e+00 -5.6286067e-01 1.0041936e+00 -2.0011157e-01 -7.7404126e-02 -1.5087040e+00 -2.0926069e-01
+1 4.9519845e-01 1 1 7.2982686e-01 6.1408577e-01 -6.6376826e-01 8.4651573e-01 1.3704995e+00 -3.1178229e-01 -9.9351248e-01 1.5393714e+00
+1 5.6559815e-01 1 1 1.4222685e+00 8.0767175e-01 -1.5768567e-01 -8.8329058e-01 -1.7212796e-01 5.1533849e-02 -3.9926400e-01 1.2001519e+00
+1 7.0551774e-01 1 1 -3.1111339e-01 -2.8269507e-01 1.2810682e+00 -1.4394665e+00 4.5220672e-01 -9.5017659e-01 1.1800091e-02 -1.2137743e+00
+1 1.2002995e+00 1 1 -1.2725807e+00 -1.1680024e+00 -1.5635297e+00 2.9197280e-01 7.2572555e-01 -9.0256893e-01 4.0379343e-01 -1.5428232e+00
+1 2.9314247e-01 1 1 -3.0076920e-01 1.1960954e+00 1.1794757e+00 1.9053393e-02 -1.5349021e+00 1.2749564e+00 7.1603088e-01 4.7628662e-01
+1 7.4688563e-01 1 1 -2.0540197e-01 -2.7526087e-01 -9.4032644e-04 -2.1208264e-01 -1.4826116e+00 -6.1132471e-01 -1.1104577e+00 1.7111636e-01
+1 8.7104490e-01 1 1 4.1940819e-01 1.2565334e+00 -9.6103165e-02 1.2346499e+00 8.5986431e-01 -1.5264197e+00 7.3901890e-01 1.3953052e+00
+1 1.0601140e+00 1 1 -7.4054752e-01 7.7162789e-01 -4.2727177e-01 5.4202568e-01 4.1331928e-01 -2.9058644e-01 -1.1667074e+00 -1.0946284e+00
+1 3.5870947e-01 1 1 6.0797038e-01 2.5546031e-01 5.2410797e-01 -7.9300919e-01 5.9573509e-01 1.2902877e+00 9.7079789e-01 -2.5293812e-01
+1 6.5252018e-01 1 1 -1.4426924e+00 -1.0357180e+00 -3.4313112e-01 -1.4694015e+00 2.6388842e-01 -5.4818060e-01 -1.2321399e+00 -5.5604579e-01
+1 3.0076397e-01 1 1 -5.1840208e-01 2.5230182e-01 9.5930420e-01 -1.7107919e-01 -7.5612623e-01 1.0199390e+00 8.0372887e-01 7.7647808e-01
+1 4.3114506e-01 1 1 -1.1472562e+00 -7.1343138e-01 3.7223963e-01 -7.7071493e-01 -4.7123827e-01 -1.5559143e+00 -5.7726172e-01 9.1134103e-02
+1 4.6588412e-01 1 1 1.1614586e+00 8.1790954e-01 1.3205215e+00 -6.1932339e-01 -1.4656735e-01 3.6588517e-01 -7.9963766e-01 -1.4063385e+00
+1 1.0126877e+00 1 1 -1.2216193e+00 -1.0037481e+00 -1.3475946e+00 -8.7175293e-01 -3.4877547e-01 1.3352920e+00 2.2323678e-01 1.0116453e+00
+1 1.1478955e+00 1 1 -1.4482339e+00 3.5852238e-01 -1.2805553e+00 8.3659395e-01 3.4260797e-01 -1.2859133e+00 8.7892156e-01 4.2298167e-01
+1 5.9116295e-01 1 1 5.9353389e-01 1.1090966e-01 7.5762046e-01 -1.1342050e+00 -3.2715319e-01 -1.3281485e+00 2.6593802e-01 -3.7120270e-01
+1 8.1823864e-01 1 1 9.6737984e-01 1.0942424e+00 4.5205160e-01 6.0067693e-01 -6.7659741e-01 -1.1762943e+00 -8.6607694e-01 3.9921397e-01
+1 5.9742335e-01 1 1 1.0109121e+00 4.8036154e-02 1.2602568e+00 -1.5015646e+00 9.9274364e-01 6.5091730e-02 -1.1563078e+00 -8.5273370e-01
+1 6.7775229e-01 1 1 6.6687934e-01 -4.5679842e-02 5.1878784e-01 -3.8206194e-01 4.3748759e-02 7.2246673e-01 -1.7367655e-01 5.0386393e-02
+1 3.7855080e-01 1 1 -9.6149877e-01 -1.1924904e+00 1.3475603e+00 1.0039971e-01 1.5271187e-01 2.4273341e-01 -4.4214641e-01 -1.3859118e+00
+1 7.2341781e-01 1 1 4.4275502e-01 1.1755185e+00 7.0454951e-01 3.8262423e-01 -5.2846881e-02 -1.3084037e+00 -1.2880882e+00 -1.2514295e+00
+1 6.8071758e-01 1 1 -1.0492921e+00 -5.3707685e-01 7.0082362e-01 -7.4767637e-02 8.7319833e-01 8.0765904e-01 -1.8358617e-01 1.8758138e-01
+1 5.6779088e-01 1 1 1.4494144e+00 -8.5484293e-01 9.1176698e-01 1.7383090e-02 1.4649662e+00 -4.9640757e-01 -4.8876526e-01 -1.4787989e+00
+1 5.2522858e-01 1 1 3.9760301e-01 -8.4183979e-01 -6.2138434e-01 -1.0528088e-02 1.0256354e+00 9.4800306e-01 5.8706403e-01 -1.0335159e+00
+1 7.5094320e-01 1 1 3.4625240e-01 9.3201716e-01 -9.5255022e-01 -1.0163896e+00 -6.5239160e-02 -1.0704396e+00 -9.5729308e-01 -4.3619137e-01
+1 6.4109811e-01 1 1 1.2345264e+00 4.3151057e-01 4.4611010e-02 1.5213395e+00 -5.8729385e-02 1.0223844e+00 -1.1288108e+00 1.4089815e+00
+1 1.0141749e+00 1 1 -1.5340983e+00 -1.5392148e+00 -1.0633950e+00 -2.6922731e-01 -6.0468727e-01 -1.2970397e+00 1.5491245e-01 -5.7390255e-01
+1 9.1657036e-01 1 1 -5.3946074e-01 1.4317918e+00 4.1465374e-02 -1.0099591e+00 7.3254591e-02 1.6452276e-01 -7.6668953e-01 -8.9070980e-01
+1 7.4199817e-01 1 1 -8.0191820e-02 -4.7473194e-01 -5.2503546e-01 -3.5813322e-01 -3.1441322e-01 5.3253579e-01 1.0620879e+00 -4.7066066e-01
+1 7.8486240e-01 1 1 -4.0670061e-02 8.2564273e-01 4.6281808e-01 1.4646152e-01 -1.8422452e-01 -6.8481383e-02 -1.8225954e-02 1.3654255e-01
+1 7.7256024e-01 1 1 1.3254818e+00 1.6262456e-01 1.1560198e-04 -1.4298426e+00 1.3488789e+00 -1.1436948e+00 1.5524653e+00 1.5080431e+00
+1 3.0843027e-01 1 1 3.3969691e-01 4.5429811e-02 -1.1986702e+00 -1.3229623e+00 8.7461516e-01 1.3265570e+00 1.3580313e+00 -6.8851440e-01
+1 2.5905937e-01 1 1 1.0121077e+00 1.3182453e-01 9.8434189e-01 1.1646947e+00 1.4491658e-01 -4.3890829e-01 7.6197430e-01 -1.3758550e+00
+1 9.3345415e-01 1 1 -1.2300325e+00 7.5201472e-01 2.0724407e-01 -2.4041216e-01 8.7861918e-01 -2.7209005e-01 1.3704872e+00 1.2693566e+00
+1 1.1793590e+00 1 1 -1.4773060e+00 4.8421327e-01 -8.7524838e-01 -5.1895112e-01 1.4670096e+00 1.1414437e+00 -3.7905438e-01 -4.7948627e-01
+1 1.1633919e+00 1 1 -1.0751753e+00 1.4475129e+00 -1.3626622e+00 -9.5034890e-01 8.1091833e-01 -1.4623519e+00 3.8301310e-01 -5.4059241e-01
+1 9.5627010e-01 1 1 -3.1051552e-02 -1.4487348e-01 -5.2331315e-02 -6.5691342e-01 8.7541748e-01 -1.0688441e+00 1.7785820e-01 -2.5060584e-01
+1 3.3747894e-01 1 1 -3.7904929e-01 -1.5432755e-01 1.1353776e-01 -1.1873079e+00 1.0631114e+00 -4.3602192e-01 -1.5333636e+00 9.4335872e-01
+1 6.3616042e-01 1 1 4.6840467e-01 1.1724407e+00 1.2824736e+00 3.1211888e-01 1.4752575e+00 1.1153070e+00 -7.5712379e-01 -5.8803213e-01
+1 3.5914855e-01 1 1 -3.5389336e-01 1.1418367e+00 6.5765528e-02 -6.7768142e-01 1.2033944e+00 -9.1802370e-01 -1.5293550e+00 3.9451135e-01
+1 1.1280377e+00 1 1 -8.5074581e-01 -1.1406112e+00 -5.1937882e-01 -1.5181854e+00 -1.2401430e-01 -8.6286107e-01 6.4111597e-01 -1.3498828e+00
+1 6.6671798e-01 1 1 -1.0967043e+00 -2.5484339e-01 1.2862194e+00 -1.2620643e-01 -1.4324448e+00 -5.1423279e-01 -4.2671874e-01 1.1017586e+00
+1 7.6672965e-01 1 1 -5.8494348e-01 -1.1620066e+00 1.9115136e-01 -5.7641401e-01 -1.0754580e+00 -1.8910799e-01 3.9410266e-01 7.0998064e-01
+1 6.1360307e-01 1 1 -1.1016696e+00 1.4364999e+00 -1.1683652e+00 8.8145076e-01 1.5009646e+00 9.5384482e-01 1.2060741e+00 8.7566628e-01
+1 4.5844212e-01 1 1 7.8578558e-01 1.1405390e-01 1.3824014e+00 -1.2080528e+00 -2.7715934e-01 -2.7743227e-01 9.3153263e-01 -1.0384442e+00
+1 6.2293558e-01 1 1 -5.5729197e-01 5.3245120e-01 -1.1982233e+00 3.7006443e-01 7.6482964e-01 -6.8065147e-01 -1.4289256e+00 1.5577019e+00
+1 8.0628783e-01 1 1 -1.3184549e+00 -1.4901908e+00 -9.3045293e-01 -6.8063949e-01 -9.0537636e-01 -1.1704305e+00 1.5225051e+00 1.4043359e+00
+1 7.4398299e-01 1 1 1.5234954e+00 -8.5945546e-01 7.2587711e-01 -9.6903622e-01 1.2143618e+00 1.2277932e+00 4.7178335e-01 -1.1180414e-01
+1 5.0688410e-01 1 1 1.4070376e+00 1.7502107e-01 1.0122893e+00 -5.7540974e-01 -1.1478761e+00 1.5395616e+00 -1.1704516e-01 -4.1969462e-01
+1 7.5278547e-01 1 1 1.3122075e+00 1.0483901e+00 -1.3199523e+00 -1.0893417e+00 1.6745716e-01 1.2540922e+00 -5.4096577e-01 -9.3189863e-01
+1 3.3153602e-01 1 1 2.9160374e-01 -9.0031083e-01 1.4887130e+00 6.3592284e-01 -4.1458283e-01 5.8231072e-01 -2.4258210e-01 1.5606971e+00
+1 5.1448869e-01 1 1 9.9535806e-02 1.5277620e+00 1.1558881e+00 2.5697254e-01 1.5880333e-01 8.3507882e-01 7.0997012e-01 1.4789656e+00
+1 6.6365133e-01 1 1 -1.5705960e+00 8.5977715e-01 -5.9724882e-01 -7.5238298e-01 -1.3462493e+00 -1.4661736e+00 6.9898220e-01 6.9455174e-01
+1 8.7377102e-01 1 1 -1.3459991e+00 -1.0516391e+00 -5.7244998e-01 -3.9033080e-01 -6.6169836e-01 6.7234096e-01 1.3788681e+00 -8.2717789e-01
+1 6.6707913e-01 1 1 4.0149997e-01 -2.9802649e-01 1.5314263e+00 -6.4431350e-01 7.3684019e-02 -2.7423294e-01 -8.9225434e-01 -8.3136496e-01
+1 8.3306347e-01 1 1 -1.3102435e-01 -1.2324742e+00 -3.8660966e-01 9.2894226e-02 6.1979617e-01 -3.1665838e-01 -1.2969562e+00 1.0532705e+00
+1 6.9755662e-01 1 1 1.3025807e-01 1.4676179e+00 -9.3494418e-01 -9.8284230e-02 -6.0706052e-01 -2.1945746e-01 1.5677917e+00 -5.5727884e-01
+1 2.7947650e-01 1 1 -4.4272101e-01 -1.5316499e+00 6.3967538e-01 6.1468792e-01 1.0268272e+00 -1.9169215e-01 1.3373575e+00 -1.0977104e+00
+1 6.8388441e-01 1 1 -1.5206713e+00 -2.2900211e-01 4.9410749e-01 1.5032084e+00 1.1165966e+00 1.5040921e+00 -1.1286004e+00 1.3546723e+00
+1 7.4781497e-01 1 1 -1.0660253e+00 -3.8749023e-01 1.2352032e+00 -2.6415329e-01 -1.2361136e+00 -1.1199338e+00 5.4955848e-01 8.5594775e-01
+1 6.3910347e-01 1 1 -1.8354836e-01 -2.6719069e-02 4.1644608e-01 -5.5395282e-01 -8.9651943e-03 -1.4452046e+00 1.4701725e-01 5.6100375e-01
+1 7.5886847e-01 1 1 1.4671717e-01 1.8036307e-01 -2.5916085e-01 1.3955889e+00 1.1842700e-01 1.2414157e+00 -1.5144599e+00 8.7046571e-01
+1 4.8971965e-01 1 1 -2.7476170e-01 -2.7486922e-01 -1.4690307e+00 5.3230672e-01 -1.3670883e+00 1.1565088e+00 -3.4314908e-01 -4.7985288e-01
+1 1.0297123e+00 1 1 2.2129882e-01 1.5557767e+00 -2.2230276e-01 -7.7681173e-01 9.5572315e-01 4.0892334e-01 6.5759388e-01 -4.1900009e-01
+1 9.5535319e-01 1 1 -2.7646626e-01 4.6384079e-01 -8.8885097e-01 5.8436010e-01 -1.2422134e-01 -1.0301253e+00 5.7457374e-02 1.3162746e+00
+1 8.3956587e-01 1 1 -1.5290659e-01 1.4808137e+00 -6.4514879e-01 7.2161214e-01 1.3710525e+00 1.7806544e-03 1.2171359e+00 -4.6830776e-01
+1 8.5270274e-01 1 1 -7.8272850e-02 3.3831456e-01 -1.3794729e+00 -1.5540381e+00 -3.0240373e-01 -1.4884684e+00 1.4931314e+00 -1.1588914e+00
+1 8.9286326e-01 1 1 7.9552589e-01 -2.2993808e-01 1.5265729e-01 4.8324787e-01 5.9738496e-01 -1.8619516e-01 1.7644095e-02 3.8677446e-01
+1 6.7569970e-01 1 1 -2.1466290e-01 -4.1031105e-01 -9.7007477e-01 9.2997169e-01 -2.8115022e-01 -3.5581301e-01 1.2345914e+00 5.6318059e-01
+1 3.8709362e-01 1 1 -1.2909737e+00 -3.0200825e-01 8.1920477e-01 6.1079737e-01 -3.3632221e-01 1.4430949e+00 -4.4168617e-01 -2.4242824e-01
+1 9.1310072e-01 1 1 -1.5555179e+00 9.6102230e-01 -1.2259476e+00 -1.0534399e+00 -8.4218604e-01 1.0002550e+00 1.6402731e-01 1.5419546e-01
+1 7.7393264e-01 1 1 7.4530754e-01 9.7390182e-01 1.2041677e+00 8.5260062e-01 1.3957413e+00 6.2317838e-01 -1.5112968e+00 -2.5090590e-01
+1 7.2246436e-01 1 1 8.5386004e-01 6.7018412e-01 3.0612329e-01 8.5445366e-01 -4.8915765e-02 -3.1080949e-01 -5.8931353e-01 -9.5806861e-01
+1 9.2005854e-01 1 1 3.0407051e-02 1.1749164e+00 -9.1464364e-01 5.8272291e-01 9.7000961e-01 6.9351116e-01 8.4908514e-01 1.5447553e+00
+1 6.4670227e-01 1 1 -1.0282887e+00 -1.2309662e+00 -6.0282708e-01 1.4796011e+00 1.2271974e+00 5.3330950e-01 1.4601414e+00 5.8043251e-01
+1 5.4438095e-01 1 1 -5.4653224e-01 -1.4607626e+00 -7.8367381e-02 -1.1922669e+00 9.5043857e-01 3.6893404e-01 -1.5253617e+00 6.8395781e-01
+1 7.4044987e-01 1 1 4.4960009e-01 5.0935461e-01 -7.9325394e-01 -1.3521589e+00 -9.7755370e-01 -8.2951507e-01 -1.3576740e+00 1.9143848e-01
+1 7.4341418e-01 1 1 8.9843541e-01 -1.1709228e-01 7.0018699e-01 5.4625917e-01 7.8455516e-01 7.2845584e-01 -1.0396466e+00 5.1573535e-01
+1 1.0637781e+00 1 1 1.5095729e+00 -1.3329707e+00 -3.6329151e-01 1.2441265e+00 7.5424633e-01 3.7074947e-01 1.9832155e-01 3.0987202e-01
+1 2.6155083e-01 1 1 -1.1000927e-01 -5.4176120e-01 1.4157231e+00 -4.0688549e-01 2.9169438e-01 1.4081099e+00 -3.9524822e-02 -7.4150934e-01
+1 8.2851819e-01 1 1 1.4722826e+00 -1.0450446e+00 -3.6476512e-01 7.2271424e-01 -1.5186300e+00 4.8592763e-01 -1.4176253e+00 1.5054508e-01
+1 9.8975668e-01 1 1 1.4700851e+00 5.7944611e-01 -1.3600271e+00 1.2610108e+00 -1.3150169e+00 -1.1552381e+00 -1.9030006e-01 1.2290107e+00
+1 1.0033016e+00 1 1 -9.0657260e-01 -1.8643518e-01 2.5342699e-01 6.2461941e-01 -3.8541568e-01 -1.0435497e+00 -2.3177734e-01 1.1950385e-02
+1 1.2091590e+00 1 1 -4.1383188e-02 -1.2482282e+00 -6.5216023e-01 -1.2241612e+00 2.8266601e-01 5.7245472e-01 9.3130081e-02 -2.1180205e-01
+1 1.0546203e+00 1 1 -1.2352693e+00 5.8430012e-01 1.5984749e-01 -1.8689829e-01 6.7960099e-01 -1.4517390e+00 7.2413102e-01 -3.3262434e-01
+1 3.3900121e-01 1 1 -1.5265611e+00 -2.8656404e-01 4.9499641e-01 3.9308247e-01 -7.7708136e-01 1.3729798e+00 -5.9874801e-02 -1.5239509e+00
+1 6.6981169e-01 1 1 4.7550769e-01 -2.2032212e-01 4.6727305e-01 -2.3221094e-01 -8.0582425e-01 6.7371834e-01 -1.0061232e+00 3.6188103e-01
+1 7.9348425e-01 1 1 -3.5402642e-01 9.8391946e-01 -5.2344682e-01 -9.1117760e-01 -8.2270590e-02 8.8424073e-01 1.2801561e+00 1.1084452e-02
+1 9.4890242e-01 1 1 5.4364705e-02 -6.0943820e-01 -1.1113451e+00 1.1022496e+00 -4.2103858e-01 -1.4409318e+00 -1.1836849e+00 9.4241863e-01
+1 4.2579066e-01 1 1 -4.9586619e-01 -1.2358397e+00 1.5331099e+00 -4.6281972e-01 -1.5286763e+00 7.9653665e-01 1.5147753e+00 -6.8018904e-01
+1 6.2771605e-01 1 1 6.2233230e-01 1.4520551e+00 -3.6439553e-01 -2.7677925e-02 -5.1703453e-01 1.0651326e+00 -6.3914501e-01 3.1851675e-01
+1 7.6188856e-01 1 1 1.1770850e+00 7.9780100e-01 -1.4315105e+00 -2.2717468e-01 -1.5408266e-01 8.8919900e-01 -1.0049449e+00 3.7076817e-02
+1 5.6149436e-01 1 1 6.5797853e-01 3.2399427e-01 -1.0809372e+00 -1.0897932e+00 -9.9498410e-01 2.1129822e-01 -9.0745096e-01 1.1147150e+00
+1 2.5563171e-01 1 1 2.3895226e-01 9.9167997e-01 5.1963508e-01 -6.6842323e-01 -1.0575362e-04 1.2894256e+00 9.0404245e-01 -1.4435886e+00
+1 3.0232362e-01 1 1 1.1152255e+00 1.0161999e+00 -1.2076268e-01 1.4616911e-01 1.3641916e+00 6.6967193e-01 1.4993923e+00 1.2619839e-01
+1 2.3158091e-01 1 1 8.5273062e-01 -1.5666989e+00 -1.8957996e-01 -6.1258039e-02 6.2537808e-01 -1.1503912e+00 -1.5702933e+00 4.4123323e-01
+1 4.0845345e-01 1 1 -1.0209341e-01 1.3215869e+00 -6.9550974e-01 8.7852376e-01 -1.0396750e+00 -1.2635906e+00 6.0020163e-01 -1.4933049e+00
+1 8.7545041e-01 1 1 -5.7434296e-01 8.5083032e-01 4.3409746e-01 -1.3662096e-01 -2.7869596e-01 -1.2004216e-03 -6.5262507e-02 2.0883334e-01
+1 5.4847994e-01 1 1 1.1320723e+00 -6.2455587e-01 1.0978382e+00 3.1574592e-01 7.1600330e-02 -1.3259294e+00 -4.5111753e-01 7.0302409e-01
+1 5.8953817e-01 1 1 1.2536951e+00 -8.4948364e-01 7.9381198e-01 5.9165562e-01 1.5676527e-01 1.5631485e+00 -1.2693257e+00 1.9598193e-01
+1 8.2199758e-01 1 1 1.9231583e-01 1.2670658e+00 -7.4598093e-01 8.1522616e-01 -1.0423297e+00 -1.3025513e+00 9.9896599e-01 1.4792107e+00
+1 5.2358627e-01 1 1 -4.4670468e-01 -1.2816206e+00 3.9486994e-01 1.0204853e+00 -9.1404655e-01 -1.3618080e+00 9.5021804e-01 -1.4707094e+00
+1 7.4903619e-01 1 1 6.4093556e-01 -1.4376081e+00 1.5354531e+00 1.3414652e+00 7.7605954e-03 -1.4052909e+00 -1.5424665e+00 -1.6168240e-01
+1 4.9095324e-01 1 1 -3.1727668e-01 1.0993638e-01 1.3178399e+00 -1.2045926e+00 -1.5145653e+00 -2.2986433e-01 1.8757466e-01 8.1493489e-02
+1 5.8576581e-01 1 1 -1.1864621e+00 4.4422502e-01 7.0683193e-01 -1.1640384e+00 1.0259477e+00 8.2915752e-01 1.5499628e+00 -7.3320950e-02
+1 7.4204948e-01 1 1 -1.1801029e+00 -1.4758405e+00 1.3624171e+00 -1.2959396e+00 -1.0990190e+00 -4.5457001e-01 1.3858155e-01 -8.0088967e-01
+1 1.0149095e+00 1 1 -1.1154320e+00 1.5638450e+00 -9.2439361e-01 -1.9568096e-01 1.3528082e+00 3.9521258e-01 1.2199823e+00 1.1719162e+00
+1 9.1426192e-01 1 1 -1.1815320e+00 9.7923273e-01 -1.1076583e+00 4.3755913e-01 9.4064318e-01 1.0109738e+00 -9.3293573e-01 -1.3897827e+00
+1 7.3967934e-01 1 1 -4.6468496e-04 -8.3934834e-01 6.6450643e-01 -4.1207071e-01 8.9577315e-01 -1.4371799e+00 -1.6189048e-01 -3.3625355e-01
+1 7.6541252e-01 1 1 -1.5267748e+00 -1.1765218e+00 -2.2956615e-03 1.5393980e+00 7.4730289e-01 1.0226811e+00 -2.7403420e-01 3.1169427e-01
+1 9.7944052e-01 1 1 2.5540314e-02 -6.1702859e-01 -8.8407135e-01 -1.4942968e+00 -1.6776184e-01 5.4764019e-01 -1.1799744e-01 -1.5309741e+00
+1 5.3015604e-01 1 1 -1.1421428e+00 -2.1757725e-03 1.1460280e+00 -7.5442575e-01 -1.5646140e+00 -6.7774562e-01 -8.3793459e-01 -1.4382204e+00
+1 6.4906916e-01 1 1 -8.6245984e-01 1.1309041e+00 1.8858333e-01 -1.6558216e-01 -1.3373296e+00 5.4427225e-01 5.9319130e-01 -7.5569499e-01
+1 1.1885550e-01 1 1 -5.4065851e-02 4.7000099e-01 -3.4696952e-01 5.1178398e-01 -1.5454408e+00 -7.3417248e-01 1.4926950e+00 4.9348391e-01
+1 1.1792866e+00 1 1 -7.6448527e-01 1.3426930e+00 -7.2073434e-01 -1.2739911e-01 4.6385437e-01 9.3911812e-01 -1.0335269e+00 1.7953690e-01
+1 6.5087104e-01 1 1 4.0995927e-01 5.8172105e-01 5.9917094e-01 1.3694265e+00 -1.4325354e+00 3.9673405e-01 -6.2103842e-01 1.5477808e+00
+1 3.9261591e-01 1 1 6.7284167e-01 3.4941904e-01 1.4614594e+00 6.4389906e-01 5.4342076e-01 1.4495775e+00 -1.4218802e+00 1.1651988e+00
+1 1.0259436e+00 1 1 -1.2836263e+00 1.0491663e+00 -1.3651555e+00 -7.7525627e-01 6.6292120e-01 -2.8047336e-03 5.5451901e-01 -1.1925172e+00
+1 1.0369562e+00 1 1 -5.9124423e-01 -4.2227724e-01 -1.1176681e+00 -1.5474176e+00 -1.5124614e+00 -1.5267927e-02 -1.3044318e+00 7.2399796e-01
+1 6.0848305e-01 1 1 -1.8425150e-01 -3.5583471e-01 -1.0656762e+00 -1.3440794e+00 -1.3127689e+00 1.0025540e+00 -1.5516540e+00 8.4540783e-01
+1 7.2525620e-01 1 1 8.9546513e-01 1.0784657e+00 -5.9947482e-01 1.2496945e+00 -3.0149996e-01 1.5632226e+00 -2.8808395e-01 -6.5421073e-01
+1 9.8393466e-01 1 1 -1.2879038e+00 -1.2158187e+00 -2.8561435e-01 -1.0728822e+00 7.9089271e-02 -5.6394973e-02 -6.3271570e-01 2.5450492e-01
+1 3.3050320e-01 1 1 -2.2499527e-01 -1.3463745e+00 3.3225594e-02 8.0990603e-01 3.5969012e-01 9.3066383e-01 2.3843948e-01 -1.3850577e+00
+1 6.5230164e-01 1 1 9.8203161e-01 3.7576540e-01 -7.8092927e-01 -4.3026844e-01 8.8757186e-01 -3.2287141e-01 -1.2199662e+00 5.3676106e-01
+1 4.5182623e-01 1 1 -9.2256470e-01 8.8787891e-01 4.9593723e-01 4.2454676e-01 1.1382754e+00 -9.6928128e-01 1.2027810e+00 -1.3109221e+00
+1 6.9836459e-01 1 1 1.3564399e+00 1.5784746e-02 5.7164983e-01 8.0044560e-01 -1.3043574e+00 -1.5525035e+00 -1.0092171e+00 -6.7829210e-01
+1 3.8600154e-01 1 1 -8.5172841e-01 1.4004494e+00 7.2838530e-01 7.8937310e-01 -3.0060482e-01 1.1427435e+00 -4.5352382e-01 7.8442850e-01
+1 6.4183521e-01 1 1 1.2382747e+00 5.4100109e-01 -8.1489758e-01 4.7918471e-02 -5.8422210e-01 1.5333601e+00 -8.7098266e-01 -1.3745436e+00
+1 3.8695772e-01 1 1 -1.3679468e+00 8.3621700e-01 1.3602954e+00 1.1180149e+00 -1.5437652e+00 6.9821271e-01 1.2162785e+00 1.3182562e+00
+1 6.6569675e-01 1 1 -9.0679469e-01 -1.1863709e+00 1.1147272e+00 6.1131981e-01 3.5157617e-01 1.0124361e+00 -3.5106891e-01 1.4206411e+00
+1 4.5144399e-01 1 1 -6.3235852e-01 3.5313428e-01 -1.2389980e+00 1.4440032e+00 -3.9506566e-01 1.1484861e+00 -5.0415221e-01 6.1055296e-01
+1 1.1860183e+00 1 1 -4.1716110e-02 6.5935056e-01 -1.3631203e+00 5.5867156e-01 1.4582513e+00 6.6008853e-01 -4.1076492e-01 1.1219758e+00
+1 5.8459419e-01 1 1 -5.4750603e-01 1.3075103e+00 -1.4692133e+00 -6.2753734e-01 1.2658056e+00 1.1443326e+00 1.4945710e+00 1.2084573e+00
+1 7.3645553e-01 1 1 -2.0897362e-01 -1.1489213e-01 -1.4949572e-01 -6.9350942e-01 -4.7072814e-01 -3.1779567e-02 -9.2007359e-01 1.4579267e-01
+1 6.3333510e-01 1 1 8.0944973e-02 1.0875260e+00 6.9949516e-01 -5.0402607e-01 -9.9752042e-01 -4.8432345e-02 -7.5777864e-01 -1.0494131e-01
+1 8.2326423e-01 1 1 1.3253607e-01 2.6398793e-01 5.7544224e-01 -1.4323453e+00 1.3542926e+00 -3.2993150e-01 3.1092287e-02 -1.3151196e+00
+1 1.0277052e+00 1 1 1.4456977e-01 9.1629948e-01 -1.5059711e+00 5.9684474e-01 7.5699231e-01 -2.4761035e-01 1.0636817e+00 1.0310362e+00
+1 4.7802233e-01 1 1 1.3329509e+00 1.5817824e-01 9.5553563e-01 6.4190356e-02 -6.8057286e-01 1.0230534e+00 -1.5060386e+00 -4.0021343e-01
+1 5.0284325e-01 1 1 2.0924304e-01 7.1427838e-01 -1.3429797e-01 1.2810364e+00 1.5076614e-01 5.2238078e-01 -1.7956001e-01 -2.3719898e-01
+1 2.3879481e-01 1 1 1.3056496e+00 8.5122946e-01 -1.4824484e+00 1.0435605e+00 -1.3387439e+00 -1.0977753e+00 1.2055052e+00 7.7883357e-02
+1 4.0344152e-01 1 1 2.8837335e-02 -1.9935202e-01 4.6095639e-01 -3.9124659e-01 -1.8206844e-01 2.6466974e-01 7.9424979e-01 -1.0585521e+00
+1 9.9738711e-01 1 1 8.6381241e-01 1.5699102e+00 1.2658480e-01 -3.2797760e-01 -1.1300671e-01 -1.9090621e-01 3.2903973e-01 -2.4673147e-01
+1 5.6394178e-01 1 1 7.9546576e-01 -7.5578154e-01 6.5255247e-01 1.1755574e+00 1.3598623e+00 -9.9453559e-01 9.6764454e-01 8.6479205e-02
+1 6.4100117e-01 1 1 -1.2252978e+00 -9.6119698e-01 1.4942741e-01 1.1630511e-01 1.1841035e-01 1.2548445e+00 -8.2335526e-01 -1.1014019e+00
+1 2.7156818e-01 1 1 -4.4036809e-01 -7.6827438e-01 1.2939706e+00 6.6940165e-01 1.4946275e+00 6.6001446e-01 5.8374582e-01 -9.9775827e-01
+1 9.7909018e-01 1 1 3.2578247e-01 -4.4173434e-01 -1.4819649e+00 5.9019871e-01 3.0076647e-02 -1.0059432e-01 -1.7792506e-01 4.9826656e-01
+1 5.3110049e-01 1 1 -3.7002880e-01 -6.4563130e-01 -8.3805040e-01 1.4617077e+00 -2.9821074e-01 -5.1189991e-01 4.0967643e-01 -1.1199095e+00
+1 6.0471866e-01 1 1 1.2794623e+00 -6.4164762e-02 -1.3531365e+00 -3.3325678e-01 -1.1876229e+00 1.3204265e+00 -9.3931651e-01 -1.0378674e+00
+1 9.6148875e-01 1 1 -2.7870942e-01 -8.5088217e-01 -1.7646272e-01 4.1302576e-01 1.3014941e+00 1.9744867e-01 -5.8944488e-01 -1.3141563e+00
+1 5.5406598e-01 1 1 -1.5462709e-01 -2.4684136e-01 -1.4541425e-01 -1.1957380e+00 -6.9826432e-01 9.9793095e-01 -1.3584332e+00 1.5126799e+00
+1 8.8488052e-01 1 1 -7.2033191e-01 1.3811995e+00 1.8181739e-01 -3.9524609e-04 1.2617916e+00 -7.3775066e-01 -1.2329351e+00 -1.2977922e+00
+1 1.1727026e+00 1 1 1.0795978e+00 5.9205360e-01 -9.6482105e-01 -3.5971567e-01 1.1808405e+00 4.9079901e-01 5.7166340e-03 8.4581575e-02
+1 3.0667513e-01 1 1 -1.0392825e+00 1.2209077e+00 1.1539671e+00 -1.3170130e+00 9.4541902e-01 -9.6334399e-01 -1.3099045e+00 1.5626492e+00
+1 9.6096602e-01 1 1 3.4930881e-02 -1.0871678e+00 -1.4672277e+00 6.2413385e-01 -5.1822535e-01 8.4612599e-01 7.1689146e-01 -2.6903777e-01
+1 5.0863846e-01 1 1 -3.9450399e-01 -5.2626857e-01 -1.3348442e+00 3.9685805e-02 -1.3185844e+00 -1.1503491e+00 7.8697403e-01 -9.6605043e-01
+1 6.7174137e-01 1 1 1.4735813e+00 -1.4125998e+00 -6.1319489e-01 9.8168899e-01 -6.5282170e-01 -5.5687889e-01 5.6750130e-01 -6.5880236e-01
+1 5.2148305e-01 1 1 1.3066245e+00 -5.4869769e-01 -1.5426550e+00 -3.9774125e-01 -1.5328011e+00 -6.5890981e-01 1.1900747e-01 -1.5187765e+00
+1 8.8060721e-01 1 1 7.0491718e-01 -1.3876622e+00 1.6161466e-01 4.7201590e-01 -7.2822162e-01 -1.8309384e-01 -1.0360332e+00 -6.3677311e-01
+1 5.3923043e-01 1 1 5.9715542e-01 7.4573713e-01 -1.2200068e+00 6.4975370e-01 4.2425098e-01 1.5026473e+00 1.2376201e+00 1.1605040e+00
+1 4.1851598e-01 1 1 -9.9739766e-01 -1.3507449e+00 5.2168915e-01 2.3438947e-01 -1.0290886e+00 -2.6989426e-01 1.9672953e-01 -1.5583704e+00
+1 6.7172025e-01 1 1 2.7594022e-01 -8.2040793e-01 -1.5555013e-01 -1.7341641e-01 -1.4242564e+00 3.4688104e-01 1.4776942e+00 -7.2550161e-02
+1 8.6045697e-01 1 1 7.3654693e-01 -1.4584928e-01 -5.2587509e-01 7.8841743e-01 1.4589417e+00 -7.6627881e-01 1.3171795e+00 -4.1259960e-01
+1 7.2349561e-01 1 1 1.2691372e+00 -8.4658581e-01 -1.0824257e+00 -3.0614198e-01 3.0238623e-01 -1.4596190e+00 -9.6779419e-01 -1.0664503e+00
+1 6.7581717e-01 1 1 -1.0247539e+00 -2.9463607e-01 6.3431868e-01 6.0056593e-01 -8.9149781e-01 8.8128585e-01 1.4498675e+00 -1.0436271e+00
+1 6.5936678e-01 1 1 -8.2752056e-01 -7.9846076e-01 1.5702648e+00 -2.2562894e-01 -1.1483428e+00 -8.3813325e-01 -1.4113190e+00 -7.2971137e-01
+1 6.7073650e-01 1 1 -3.0735289e-01 1.1538644e+00 -1.0787927e+00 -2.4328684e-01 -1.3942684e+00 3.9588265e-01 -1.0146800e+00 5.1867468e-01
+1 9.7610097e-01 1 1 -9.0164184e-01 -5.2103540e-02 -1.1381126e+00 1.4316721e+00 -3.2924496e-01 -2.9347087e-01 -1.1614429e+00 -5.5428917e-01
+1 3.5346014e-01 1 1 1.1484834e+00 8.0015756e-01 8.9849124e-01 6.5481113e-01 -1.2753992e+00 -6.4482053e-02 1.4851702e+00 -1.1158484e+00
+1 6.5470277e-01 1 1 6.1445457e-01 -9.1011904e-01 -6.9359761e-01 4.1152704e-01 -5.4731723e-01 9.9596001e-02 1.3023103e+00 1.2434486e+00
+1 5.9538871e-01 1 1 7.2293574e-01 4.3964272e-02 1.1552988e+00 -1.2521326e+00 -1.7738313e-01 -5.5890387e-01 4.5402581e-01 7.6614030e-01
+1 8.9435259e-01 1 1 -1.2993431e+00 6.3324121e-01 -1.0776469e+00 9.3687026e-01 9.3078371e-02 -1.3532756e-01 -1.1674937e-01 -8.6825404e-01
+1 6.6004217e-01 1 1 -8.4842274e-01 -8.3090664e-01 -7.3033317e-01 3.1611302e-01 -1.4495501e-01 6.2812277e-02 1.2887897e+00 -4.7839596e-02
+1 6.0164216e-01 1 1 2.4814468e-01 -6.6853888e-01 -5.0711812e-01 4.7839838e-01 -1.5244774e+00 1.1080997e-01 -5.9299458e-01 2.0763200e-01
+1 9.5051623e-01 1 1 -1.4673332e+00 1.3439664e+00 6.5719174e-03 1.1060014e+00 9.3750592e-01 -5.8125675e-01 -1.3279645e+00 -6.3838297e-01
+1 3.9315973e-01 1 1 3.4055890e-02 -7.5909481e-03 4.9847221e-01 -2.3756042e-01 -1.5667963e+00 1.1709261e+00 -1.2253254e+00 -7.6368671e-01
+1 8.1321029e-01 1 1 6.0747236e-01 1.2242348e+00 -8.0509835e-01 2.8621954e-01 -3.1516270e-01 8.1926037e-01 -9.0423142e-01 1.2650631e+00
+1 1.0411493e+00 1 1 -3.8818133e-01 1.4232443e+00 -4.4836696e-01 7.1352635e-01 -2.1422897e-01 -2.9160702e-01 -1.5337611e+00 -3.8288584e-01
+1 5.6691240e-01 1 1 9.2435749e-01 3.8018597e-01 9.7725291e-01 7.7814812e-01 -2.8115844e-01 -1.5461128e-01 -1.1554538e+00 -1.1804818e+00
+1 6.7272159e-01 1 1 5.0069713e-01 -2.1382844e-01 4.4326735e-01 -1.1472322e-01 -4.7447805e-01 -4.5461735e-01 -1.5272016e+00 -1.2002005e+00
+1 7.1333521e-01 1 1 -1.1101040e+00 1.6735414e-01 1.2781055e+00 7.8465596e-01 -1.1903737e+00 -4.0048046e-01 -8.6524797e-01 3.9585433e-01
+1 9.3277430e-01 1 1 4.0132912e-01 9.9559926e-01 -1.0918304e+00 -6.9316089e-01 -9.4884634e-01 1.5579255e+00 2.0976855e-01 -7.6957866e-01
+1 6.6625664e-01 1 1 1.3902172e-01 9.1434614e-01 -3.5053802e-01 -9.2946780e-01 -5.3614938e-01 -1.1212516e+00 7.1308413e-01 -3.7150866e-01
+1 7.8171477e-01 1 1 -8.0680752e-01 -1.2557201e+00 -1.0063595e+00 -1.5666151e+00 -9.7497245e-01 1.5392553e+00 -3.7102772e-01 1.5401451e+00
+1 7.6200316e-01 1 1 -9.0007143e-01 3.3217615e-01 4.5031555e-01 -4.1231113e-01 1.8523169e-01 -7.5089671e-01 1.9852857e-01 -1.5050088e+00
+1 8.4507452e-01 1 1 -7.3184043e-01 2.7445903e-01 3.5666303e-01 6.4029511e-01 -1.2932214e-01 -5.4324760e-01 2.9827545e-01 1.4204355e+00
+1 9.0057450e-01 1 1 -7.0680728e-01 9.7497823e-01 2.7679225e-01 1.4850601e+00 4.6492716e-01 -8.9416857e-01 -8.6635211e-01 2.9628270e-01
+1 1.0330367e+00 1 1 -9.4812171e-01 -8.8161170e-02 -6.5142488e-01 -5.4788128e-01 8.8978471e-01 1.0880540e+00 5.0196390e-01 1.9893674e-01
+1 9.5311639e-01 1 1 -9.2371044e-01 1.1069468e+00 -4.7562682e-02 -2.3259368e-01 6.3052321e-01 -2.8700052e-01 1.3310668e+00 8.7525648e-01
+1 4.3065508e-01 1 1 9.4957020e-01 -5.7110649e-02 -1.4214547e+00 -1.0607828e+00 6.1159203e-01 -1.2730175e+00 -4.1013818e-02 1.4989002e+00
+1 5.0455679e-01 1 1 1.3572919e-01 1.4686744e+00 1.4236951e+00 -3.8304621e-02 -2.6386105e-01 -1.3597344e+00 -1.3104408e+00 -4.1613010e-01
+1 1.0677087e+00 1 1 4.0426368e-01 5.1632556e-01 -1.4679282e+00 2.4073615e-01 1.2162277e+00 -1.1106335e+00 1.1267982e+00 -7.1329833e-01
+1 7.8648240e-01 1 1 -8.0519560e-01 8.0485038e-01 -5.4191291e-01 -3.1879444e-01 -1.2043945e+00 9.2554203e-01 5.7665347e-01 -8.7471433e-02
+1 9.7284452e-01 1 1 1.0586890e+00 -5.7763084e-01 -4.5324962e-01 -1.5626386e+00 -9.7688429e-01 1.5597441e+00 1.4737488e-03 1.3297948e-01
+1 6.9246969e-01 1 1 -5.9548483e-01 -7.2016332e-01 5.9584020e-01 4.4682828e-01 -5.3112594e-01 1.1691623e+00 -3.6344525e-01 1.3137351e+00
+1 1.0743949e+00 1 1 8.0073597e-01 7.7151521e-01 -1.1111093e+00 1.4364916e+00 -1.3689233e+00 -5.5168814e-01 -1.1681771e+00 8.3190027e-01
+1 1.0035818e+00 1 1 -6.1351073e-01 1.5032681e+00 -7.8729684e-01 -2.5798454e-02 1.5311804e+00 -1.3827029e+00 1.4017721e+00 -1.4811013e+00
+1 7.1148587e-01 1 1 -5.6773709e-01 7.3910544e-01 2.9028289e-01 -5.4834860e-02 -1.3783082e+00 -7.2720119e-01 7.7966521e-01 1.1098836e+00
+1 9.8719374e-01 1 1 -9.4036546e-01 2.8770308e-01 -1.0893515e-01 -1.1228526e+00 8.7790752e-01 -1.2749260e+00 2.5024152e-01 -9.6351276e-01
+1 4.3702164e-01 1 1 6.3028043e-01 5.1458219e-01 6.7540907e-01 -2.3726424e-01 -1.0690313e+00 1.1225923e+00 -7.8331192e-01 1.1511352e+00
+1 6.7708435e-01 1 1 -3.2726850e-01 -2.2172891e-01 1.0260227e+00 -1.0189299e+00 -4.4123027e-01 -9.9701228e-01 1.2912908e+00 1.2009994e+00
+1 7.7740139e-01 1 1 5.2705167e-01 -6.6888116e-01 1.6191428e-01 -3.3344516e-01 1.5431433e+00 4.6987626e-01 6.0255638e-01 4.6473250e-01
+1 7.9102179e-01 1 1 -1.1338747e+00 -1.2671723e+00 6.7399523e-01 3.8844265e-01 -1.3803440e+00 -7.5356794e-01 -1.3295936e+00 7.5977140e-01
+1 1.1352264e+00 1 1 -1.3183514e-01 -5.0825850e-01 -7.4531309e-01 3.2607285e-01 1.2195932e+00 -1.4563605e+00 -3.3050835e-01 -1.0961844e+00
+1 7.9776425e-01 1 1 -9.3034615e-01 -3.1025926e-01 -9.4719329e-01 1.3688521e+00 -1.1892988e+00 -9.0269320e-01 -5.1798405e-01 -1.2726617e+00
+1 7.7282399e-01 1 1 -6.2111572e-01 5.1637206e-01 -1.0276861e+00 4.1488114e-01 1.4085106e+00 -8.1363335e-01 -4.0470449e-01 1.4790824e+00
+1 1.0594591e+00 1 1 4.2047222e-01 -1.5552607e+00 1.5554464e-01 -1.4284242e+00 9.3748903e-01 6.1719004e-01 -3.2027812e-01 -4.8455925e-01
+1 8.1870542e-01 1 1 1.4347899e+00 -1.2151909e+00 4.3374661e-01 5.2579877e-01 1.2908873e+00 -4.2591723e-01 -1.3661286e+00 -9.7911718e-01
+1 5.2163523e-01 1 1 -3.5075557e-01 -2.1888877e-01 1.4842600e+00 -2.0021811e-01 1.0317276e-01 1.2987253e+00 1.3768331e+00 -3.6012090e-01
+1 1.0328539e+00 1 1 -1.5210898e+00 -5.8515387e-02 -1.4295886e+00 -4.2004342e-01 -1.3460652e-01 -1.1007472e-01 -5.3810292e-01 1.2969944e+00
+1 6.8040664e-01 1 1 1.3255658e+00 -1.4960575e-01 -1.9438648e-01 -5.1105472e-01 -3.8506134e-01 3.7217465e-01 7.4940261e-01 -9.2613786e-01
+1 1.0380427e+00 1 1 -1.3908572e+00 -1.1496884e+00 2.0279548e-01 -1.8234326e-01 -4.4992166e-02 2.2835520e-01 5.6464712e-01 9.9262726e-01
+1 7.6296526e-01 1 1 4.5329298e-01 1.1236236e+00 -2.4441172e-01 1.5513135e+00 9.4049153e-01 -1.0602938e+00 -7.2719935e-01 1.2294245e+00
+1 4.8640896e-01 1 1 1.3290172e-01 6.2818514e-01 1.3754659e+00 8.4863270e-01 1.4884533e+00 -1.2441503e+00 -1.2439952e+00 6.8349403e-01
+1 8.8245986e-01 1 1 6.8482026e-03 -9.8525181e-01 -1.5246624e+00 1.3912516e-01 -6.7692927e-02 7.2195146e-03 -5.2819690e-01 -1.3201045e+00
+1 4.9510464e-01 1 1 -1.1411870e+00 2.0763759e-01 9.6957186e-01 9.3170876e-01 -4.5848895e-01 -1.1837312e+00 7.3556137e-01 -1.0682887e+00
+1 2.7181334e-01 1 1 -5.0623572e-01 -5.4450880e-01 1.5313562e-01 1.5312826e+00 5.0294275e-01 7.3543274e-01 4.1290650e-01 -5.2597458e-01
+1 2.5862707e-01 1 1 -8.7077159e-01 -9.9946311e-02 7.8598851e-01 3.3982521e-01 -1.0670523e+00 1.3926148e+00 -5.8695822e-02 3.8703629e-01
+1 7.4283435e-01 1 1 -1.5194809e+00 9.5442290e-01 -2.8816393e-01 2.6842706e-02 1.4047400e+00 8.1121727e-01 -4.0581670e-02 -1.3194253e+00
+1 6.3940127e-01 1 1 9.0436410e-02 1.3594730e-02 1.1647650e+00 -1.2439877e+00 3.9702100e-01 -3.8353251e-01 -3.3052373e-01 9.2073477e-01
+1 7.4400377e-01 1 1 -5.6610134e-01 -8.4963302e-01 9.4132552e-01 -4.0174460e-01 -1.0865164e-02 5.1723620e-01 -7.7651913e-01 -6.9605830e-01
+1 7.6287600e-01 1 1 1.4188477e+00 -1.2436381e+00 -2.0255654e-01 -8.3886531e-01 -3.9842956e-01 4.0194273e-01 -7.8120026e-01 6.3914310e-01
+1 7.0417864e-01 1 1 -1.2566895e+00 -8.0943432e-01 1.1187061e+00 6.5849123e-01 1.4698820e+00 1.0271750e+00 -9.1706411e-01 9.7280938e-01
+1 6.8765167e-01 1 1 -2.5266036e-01 -1.0664937e+00 -3.3869950e-01 -5.6880099e-01 -1.1774709e+00 6.7895955e-01 -4.4293134e-01 1.1591268e+00
+1 6.9824902e-01 1 1 9.7067164e-01 1.3679205e+00 4.3353628e-02 2.8225526e-02 -8.6182324e-01 1.0086099e+00 1.2276031e+00 4.2750240e-01
+1 8.2380299e-01 1 1 -2.1242813e-01 4.6407641e-01 -2.0507370e-01 5.9260317e-03 1.2205992e+00 -3.2772406e-01 1.4855721e+00 2.1050616e-01
+1 5.2695627e-01 1 1 -1.4303103e+00 -8.4234687e-01 -3.4659174e-01 -9.3214989e-01 1.1374878e-02 -8.4631085e-01 -1.3684691e+00 5.4368587e-01
+1 6.4572280e-01 1 1 2.4173442e-01 -1.3073826e+00 -6.5460290e-01 4.7932878e-01 -4.5958005e-01 1.1851197e+00 -2.6001426e-01 -1.1646093e+00
+1 3.5061992e-01 1 1 7.5109962e-01 -8.7964227e-01 -5.3466857e-02 1.0351694e+00 1.0143581e+00 6.0911734e-01 -1.0424468e-01 -1.4656777e+00
+1 4.8106974e-01 1 1 8.1200684e-01 1.8736938e-01 -1.2195875e-01 -4.8460951e-02 -1.1059166e+00 -1.0152677e+00 9.6831178e-01 -4.1654307e-01
+1 1.0909845e+00 1 1 3.2040886e-01 1.2413230e+00 -1.4422270e+00 -8.1071086e-01 -1.4789298e+00 1.5276336e+00 9.6611796e-01 -1.3708764e+00
+1 3.9712669e-01 1 1 4.2182601e-01 -4.0070103e-01 1.0196213e+00 -5.3006891e-01 -9.2262119e-02 -1.2995502e+00 -1.3477930e+00 1.2065053e-01
+1 4.9145621e-01 1 1 -9.4482327e-01 9.9239796e-01 -6.1190257e-01 6.8856743e-01 1.2973435e+00 -1.1872557e+00 -1.4739792e+00 1.4461408e+00
+1 5.3411031e-01 1 1 1.1061927e+00 5.1718483e-01 1.3279324e+00 -8.7462149e-01 -1.3427036e+00 1.1904251e+00 1.4312290e+00 -1.2133332e+00
+1 6.9799216e-01 1 1 -1.6399948e-01 -4.6146364e-01 6.8521697e-01 -2.5130567e-01 -7.5911817e-01 -1.3284056e+00 -5.0896955e-01 -4.1285001e-01
+1 9.0898798e-01 1 1 -1.1624739e+00 7.7280518e-01 -6.3700925e-01 -1.3938696e+00 -4.9123510e-01 7.8560562e-01 3.0554536e-01 1.0080839e+00
+1 8.6249828e-01 1 1 -1.3483928e-01 1.1926282e+00 3.3331880e-01 9.0500515e-02 -8.2811217e-02 -4.4032621e-01 -1.2030644e+00 2.5613756e-01
+1 6.6490449e-01 1 1 -1.1554991e+00 1.1404543e+00 6.2940047e-01 5.1131257e-01 -8.2582437e-02 1.0297404e+00 -6.1289889e-01 9.2210421e-01
+1 7.5944369e-01 1 1 8.5225963e-01 7.5829636e-01 5.9130785e-01 1.3744772e+00 6.2092880e-01 -1.8652106e-01 2.9066562e-01 3.2898029e-01
+1 4.9396061e-01 1 1 1.4066919e+00 -7.5453581e-01 1.2534041e+00 7.0749264e-01 -4.2039431e-01 4.5001828e-01 4.0473354e-02 -3.1409763e-02
+1 8.7607639e-01 1 1 -1.3552852e+00 1.1262369e+00 -1.5577769e+00 -9.9410684e-02 -1.2534601e-01 -1.4978764e+00 -1.4899419e+00 -1.1632608e-01
+1 8.4486321e-01 1 1 1.4100803e+00 5.6702771e-01 4.7683981e-01 5.3192749e-01 1.3183131e+00 -1.2266191e+00 1.8158974e-01 -1.0217863e+00
+1 8.8719506e-01 1 1 -9.5554637e-01 -1.5574668e+00 4.3840229e-02 -8.6730915e-01 -7.6396607e-01 -6.5604312e-01 1.4922663e+00 -1.2171967e+00
+1 7.8838340e-01 1 1 -4.6197137e-02 -5.9524697e-01 -1.4515375e+00 1.2503730e-01 -2.8860193e-01 8.7353078e-01 1.1859287e+00 6.2595068e-01
+1 1.1428958e+00 1 1 -4.6189195e-01 -1.4847569e+00 -1.5239245e+00 -2.2355691e-01 8.6351292e-02 7.6935963e-01 -1.5017938e+00 -8.4072726e-01
+1 6.6751747e-01 1 1 -1.4261954e-01 -6.3848710e-01 8.0526316e-01 2.3832733e-02 -1.0964586e-01 -1.6803012e-01 -1.0928756e+00 7.8063307e-01
+1 9.9073772e-01 1 1 2.8551912e-02 6.2778448e-01 7.6849251e-02 -1.5671209e+00 1.2969179e+00 2.0963585e-01 9.3210609e-01 8.0913847e-01
+1 8.6605372e-01 1 1 -7.9169312e-01 -1.4359527e+00 4.1078307e-01 5.1215787e-01 9.3005721e-01 -1.5172758e+00 -1.2154961e+00 -7.6439277e-01
+1 6.7280807e-01 1 1 -1.3413063e+00 -3.4152313e-01 -1.1896643e+00 -1.2662061e-01 -1.0934730e+00 -5.4644811e-01 9.3487690e-01 -1.1769069e+00
+1 5.3168849e-01 1 1 7.3384065e-01 -2.8949570e-01 1.5487401e+00 -1.2543749e+00 3.1635509e-01 -1.2779790e+00 1.3712228e+00 -8.0698150e-01
+1 1.2437873e+00 1 1 -2.3298818e-01 7.7284845e-01 -1.5619717e+00 9.4874652e-01 1.4052849e+00 7.5954239e-02 -5.8289939e-01 -6.8251916e-01
+1 1.2351693e+00 1 1 -1.4079221e+00 -1.2216978e+00 -9.0983979e-01 -1.1415134e+00 1.3004004e-01 1.0762827e+00 -1.3041668e+00 -1.1448183e+00
+1 9.5915514e-01 1 1 -4.7071226e-01 3.7464548e-01 -1.5458811e+00 2.9042453e-01 -9.6556504e-01 -2.0712558e-01 -2.3931292e-01 1.2945693e+00
+1 1.1661242e+00 1 1 -7.3067484e-01 9.1482686e-01 -6.5264500e-01 -8.6993971e-01 1.2160666e+00 -2.7499716e-01 -8.9363675e-01 -8.4425751e-01
+1 5.9540340e-01 1 1 3.3613288e-02 5.4059256e-01 1.4370945e+00 -1.0457425e-01 -7.7074477e-01 -5.9455163e-01 6.0163172e-01 1.1380878e+00
+1 5.6523254e-01 1 1 -5.4814535e-01 2.5323668e-01 6.8370378e-01 -1.4291144e+00 -1.1208790e+00 7.7693934e-01 -1.1624040e+00 -1.3162534e+00
+1 5.6201483e-01 1 1 -1.5291743e+00 -7.0917394e-01 -9.3647352e-01 1.4910376e+00 1.5179299e+00 1.5604115e+00 1.0404811e+00 8.2379042e-01
+1 5.6925079e-01 1 1 5.3664053e-01 1.1606901e-01 6.8693951e-02 -6.1575195e-01 -1.0262683e+00 -1.7875273e-01 1.2614815e+00 4.4682106e-01
+1 1.1440166e+00 1 1 -1.9504954e-01 -1.5711968e-01 -1.5668627e+00 -5.3690405e-01 -1.1469005e+00 -9.3454188e-01 -8.8940300e-01 1.3151780e+00
+1 1.2045600e+00 1 1 -1.5165549e+00 1.3690289e+00 -1.4309573e+00 -1.0922371e+00 8.5553559e-01 1.1178894e+00 -4.9835038e-01 -4.9192947e-02
+1 9.9151394e-01 1 1 -9.9650998e-01 2.4483147e-01 -1.2081149e+00 -9.0322684e-01 -8.2952989e-02 -1.4989559e+00 -2.8876860e-01 -5.4699586e-01
+1 1.2018456e+00 1 1 -5.1286454e-01 -6.0387669e-01 -6.7425503e-01 -3.5777302e-01 6.7625845e-01 -5.2037421e-01 4.2683987e-01 -1.0592382e+00
+1 8.7871467e-01 1 1 8.1584281e-01 1.1303182e+00 -4.7962026e-01 -8.2823014e-02 -4.0652579e-01 2.6463936e-01 -1.4998453e+00 7.8831060e-01
+1 9.8773218e-01 1 1 -1.1818618e+00 4.7948459e-02 3.4900355e-01 -2.8085414e-01 4.8509462e-01 -7.0143616e-01 2.4030273e-01 1.0399903e+00
+1 6.2192532e-01 1 1 7.3971861e-01 -1.5195634e+00 3.4915056e-01 1.4983015e+00 5.5234359e-01 1.3596703e+00 -1.3202008e+00 -7.0458162e-01
+1 9.2028593e-01 1 1 1.1686031e+00 -1.2952526e+00 -3.2166792e-01 -1.0528540e+00 -1.6758985e-01 3.3047519e-02 4.5369170e-01 -1.2405141e+00
+1 8.7512407e-01 1 1 -5.2438383e-01 -1.2153560e+00 4.0821989e-01 1.2737188e+00 1.3259877e+00 -6.3224593e-01 5.5102444e-01 1.4304482e+00
+1 9.8077825e-01 1 1 -1.1516966e+00 1.4729351e-01 -2.8661439e-01 5.8003104e-01 -5.8314932e-01 -1.2909992e+00 -3.4741665e-01 -1.0650923e+00
+1 5.1778313e-01 1 1 -1.2128626e+00 -1.3042720e-02 -1.0664928e+00 2.1973398e-01 7.7840737e-01 1.1577155e+00 1.1891676e+00 -2.1108225e-01
+1 4.0218302e-01 1 1 1.2123599e+00 7.0249039e-01 1.3829679e+00 -1.4440331e+00 1.1008424e+00 -1.3009532e+00 -4.7244475e-01 -8.0129878e-01
+1 7.8656349e-01 1 1 -2.3785578e-01 6.5078500e-01 -1.1031814e+00 -1.0605714e+00 1.0187437e+00 3.6401260e-01 1.5673907e+00 5.7915018e-01
+1 4.0850776e-01 1 1 -1.5362581e+00 -1.2820795e+00 5.0997425e-01 3.7347873e-01 3.4468569e-01 1.2788811e+00 8.8117366e-01 1.1230416e+00
+1 6.7838060e-01 1 1 8.6031741e-01 2.7333372e-01 8.7250807e-01 1.5490859e-01 3.5561664e-02 -6.2242693e-01 4.1791129e-01 2.7202648e-01
+1 1.1281729e+00 1 1 -1.3962421e+00 9.1139587e-01 -7.1141220e-01 -8.3159991e-01 7.8227920e-01 3.7412969e-01 -7.6618343e-01 9.3170941e-01
+1 5.0407953e-01 1 1 1.0569815e+00 -5.7537327e-01 1.9686338e-01 2.4602559e-01 2.0132854e-01 -1.4708671e+00 1.4337232e-01 1.5421994e+00
+1 1.7920385e-01 1 1 -1.0191352e+00 -4.7630745e-01 5.8568874e-01 6.1621681e-01 2.3354871e-01 3.2950152e-01 5.7044347e-02 -1.5364032e+00
+1 5.7247158e-01 1 1 -6.4252751e-01 -5.2121441e-01 1.0607890e+00 -1.0750003e+00 1.4040249e+00 -6.9577009e-01 5.5857432e-01 1.5623371e+00
+1 1.1727103e+00 1 1 -1.3059413e+00 -1.2902672e+00 1.4228416e-01 -2.3006502e-01 9.4334202e-01 -8.0000694e-01 8.7969069e-01 7.6870059e-01
+1 3.7931449e-01 1 1 1.3523114e+00 8.9299239e-01 6.1788015e-01 5.9782010e-01 -8.6884327e-01 2.9985899e-01 6.2641989e-01 1.3219009e+00
+1 6.8231750e-01 1 1 -1.1259327e+00 1.1350079e+00 -1.3936640e+00 7.4912162e-01 -5.2622155e-01 6.1546452e-01 7.6210819e-01 -1.5437910e-01
+1 5.0734796e-01 1 1 1.4039570e+00 3.2767239e-01 4.0467243e-01 -1.0163344e+00 -6.2224217e-01 -1.1524335e+00 4.7909637e-01 3.0603469e-01
+1 8.5616635e-01 1 1 -1.9706447e-01 -2.2037561e-02 -2.1860095e-01 -6.9301822e-01 3.3785932e-01 -1.0319575e+00 2.7073089e-01 7.3789512e-01
+1 5.7328067e-01 1 1 -8.2388600e-01 3.2264419e-01 -1.5043532e+00 1.4682822e+00 1.5437013e+00 6.2265056e-01 1.1479343e+00 -1.2045223e+00
+1 3.5236029e-01 1 1 1.0883873e+00 2.9200465e-01 -1.2599711e-01 2.0869801e-01 -1.4267035e+00 2.4288356e-01 8.1064880e-01 1.7379643e-02
+1 8.1634699e-01 1 1 -9.6913329e-01 5.5436731e-01 -1.9998715e-01 1.5700981e+00 1.1714722e+00 1.2151347e+00 -5.1297201e-01 -6.8455683e-02
+1 7.0922136e-01 1 1 9.3474417e-01 -7.1246467e-01 3.2017661e-01 -7.3928763e-01 5.7145747e-01 -7.2410658e-01 -9.9031303e-01 -7.1174577e-01
+1 1.1055643e+00 1 1 -8.5955514e-01 1.3574071e+00 -3.3998163e-01 -2.0828207e-01 6.3699858e-01 4.7072798e-01 -3.3230170e-02 8.7373447e-01
+1 7.9602270e-01 1 1 -1.5001830e+00 -3.0409244e-01 4.8575673e-01 -8.6250954e-01 -5.1255996e-01 9.9493876e-01 7.0402030e-01 1.0511501e+00
+1 6.2325710e-01 1 1 8.4695259e-01 4.8968090e-01 -8.8600337e-01 -8.8927063e-01 -3.4815116e-01 -7.6200109e-01 1.2313063e+00 1.5045360e+00
+1 9.4867915e-01 1 1 1.7594505e-01 -9.0578490e-01 9.0489096e-02 -1.4151890e+00 1.4105188e+00 1.3209864e+00 8.9406705e-01 5.7050273e-02
+1 8.3091388e-01 1 1 8.6979208e-01 6.3123400e-01 3.1938439e-01 -8.3866553e-02 1.3058773e-01 1.8337231e-01 3.4725627e-01 6.5817732e-01
+1 8.3490796e-01 1 1 7.6494314e-01 -8.5153645e-03 -1.0884505e+00 1.0299424e+00 -1.1853385e+00 3.5970352e-02 -7.4307673e-01 4.3854752e-01
+1 5.4195632e-01 1 1 1.0022019e+00 1.3955304e+00 -9.4069190e-02 6.6354803e-02 -1.1443288e+00 1.3679150e+00 -1.0597544e+00 4.9183473e-01
+1 9.3295559e-01 1 1 -1.2117164e+00 -4.5162642e-01 -7.9976529e-01 -4.0210071e-02 9.6739119e-02 3.7155453e-01 1.5381608e+00 7.3598403e-01
+1 5.9228418e-01 1 1 -1.5144460e+00 -3.9732591e-01 1.2197627e+00 -3.6824889e-01 -1.4506217e+00 -7.6913766e-01 -2.9672046e-01 1.2333260e+00
+1 1.2320426e+00 1 1 -1.0952089e-01 1.1693762e+00 -1.4812030e+00 -2.2158248e-01 1.3015043e+00 7.5718599e-01 -1.2731706e+00 2.8224111e-01
+1 5.7116125e-01 1 1 2.5566775e-01 -9.8278554e-02 -5.9839034e-01 -1.3495100e+00 -5.2632558e-01 -5.6688550e-01 -7.9078093e-01 -1.7863376e-01
+1 6.0387434e-01 1 1 -6.9095954e-01 7.1008650e-01 -9.0836088e-01 1.0851047e+00 7.7092555e-01 8.0590379e-01 1.4234166e+00 1.0650174e+00
+1 4.4935179e-01 1 1 1.5110430e+00 -4.8661983e-01 1.3189733e+00 4.1004104e-01 1.0175346e+00 1.4190801e+00 1.3487469e-01 -1.0478594e+00
+1 4.9340326e-01 1 1 -5.3542672e-01 -1.0537922e+00 9.0611140e-01 -1.0945442e+00 -1.1268618e+00 -4.9146420e-01 -1.3910080e+00 3.9488258e-01
+1 9.2762811e-01 1 1 -1.3954804e+00 1.2132303e+00 -1.4268862e+00 1.1621573e+00 1.4964504e+00 -7.9180542e-01 1.0612418e+00 -1.3938040e+00
+1 4.3436097e-01 1 1 1.2909619e+00 -1.3159789e+00 1.2424843e+00 1.0959883e+00 -7.4810258e-01 -8.7179571e-02 1.4697914e+00 1.1932393e+00
+1 4.4849985e-01 1 1 1.3570003e+00 -8.4483256e-01 2.6775261e-01 1.1180120e+00 -7.0622505e-01 -1.2448745e+00 4.4153080e-01 -1.1543654e+00
+1 5.0219114e-01 1 1 -8.5872364e-01 8.9800560e-01 1.3574841e+00 5.6140766e-01 -5.8729147e-01 4.0109949e-01 3.6632412e-01 1.0562353e+00
+1 4.8789588e-01 1 1 -9.1619819e-02 5.6897085e-01 9.8998445e-01 1.3757994e+00 2.7635295e-01 -5.7862719e-01 -7.1205280e-01 -9.9394127e-01
+1 2.8489421e-01 1 1 -4.7389045e-01 -3.1494176e-01 7.9399301e-01 9.3941985e-01 1.3900435e+00 1.3836217e+00 -1.1449495e+00 -1.3227533e+00
+1 7.4260970e-01 1 1 -7.3940655e-01 3.5742077e-01 -8.4509634e-01 -8.1530343e-01 -1.5630717e+00 4.6031028e-01 -9.1179342e-01 1.5356878e+00
+1 6.0402068e-01 1 1 9.3461188e-01 4.4573933e-01 -3.9373135e-01 8.2233434e-01 -5.4872633e-01 -1.3078729e+00 1.7689577e-01 -1.0211303e+00
+1 8.2850792e-01 1 1 5.8611217e-02 -1.1575424e+00 -1.2486921e+00 1.1071452e+00 1.2725364e+00 3.0368144e-01 1.1406246e+00 3.8438063e-01
+1 9.2952541e-01 1 1 -1.3813736e+00 1.0680339e+00 -9.2957861e-01 1.3665743e-01 -4.4289719e-01 -1.1141399e+00 4.7998896e-01 1.1706875e+00
+1 1.0291650e+00 1 1 -3.7602575e-01 -6.1428024e-01 -2.8750773e-01 2.9721458e-01 -1.3400737e+00 -1.4577989e+00 -4.3541149e-01 -5.0362430e-02
+1 8.1041759e-01 1 1 1.0196831e+00 -9.3451330e-01 -3.7288993e-01 1.5308534e-01 -5.4059547e-01 5.4768061e-02 -1.1916588e+00 -1.3529415e+00
+1 9.1684950e-01 1 1 4.2595044e-01 -1.5433665e+00 3.1622012e-01 -5.9100343e-02 -3.0211616e-01 1.4898431e-04 -5.5620787e-01 -3.9860026e-02
+1 7.0147535e-01 1 1 -7.4056979e-01 7.6999394e-01 -8.6325901e-01 -5.5619289e-01 -8.5258348e-01 -6.3761338e-01 1.1941461e+00 -7.6821821e-01
+1 4.2809309e-01 1 1 2.3362928e-01 1.0679346e+00 -9.1932426e-01 1.4458459e+00 -5.6651221e-01 -3.9548444e-01 1.5193108e+00 5.0226908e-01
+1 1.0898061e+00 1 1 -3.8342422e-01 8.5832892e-01 -7.3010997e-01 1.1293673e-01 7.9655233e-01 7.0313557e-01 1.9202623e-01 1.7695694e-01
+1 8.8108622e-01 1 1 -8.0438257e-01 -2.5925673e-01 1.0261729e-01 6.0572155e-01 1.3287573e+00 -1.0720366e+00 9.6918582e-01 -9.7290073e-01
+1 3.4783288e-01 1 1 -9.8470555e-01 6.1137248e-02 -4.5539002e-02 -1.5396885e+00 -1.1586027e+00 -6.8536459e-01 -5.1913865e-02 4.4711418e-01
+1 3.6382394e-01 1 1 -3.6083822e-02 2.3292308e-01 1.1745993e+00 -2.4603480e-01 -1.0445077e+00 1.2975257e+00 8.4642664e-01 -4.1653879e-02
+1 8.4831437e-01 1 1 -1.3340886e-01 3.1371507e-01 -2.7753753e-01 -7.7089529e-01 1.7954640e-01 -1.4223951e+00 7.6096227e-01 4.9841160e-01
+1 4.4015128e-01 1 1 8.9450876e-01 1.0167659e+00 6.9186294e-01 -5.0906995e-01 -1.4341913e+00 1.3263749e+00 6.9251570e-02 1.3177456e+00
+1 6.3079834e-01 1 1 1.4879003e+00 -1.4799183e+00 1.1059842e+00 -1.3818294e+00 9.8713528e-01 -3.5933975e-01 1.5218549e+00 -8.7786642e-01
+1 1.0134504e+00 1 1 6.3295875e-02 -9.9751985e-01 -5.2690335e-01 1.3877295e+00 3.1923814e-02 -1.2821812e+00 -1.0314449e+00 -1.3818313e+00
+1 7.4714720e-01 1 1 -1.1861315e+00 1.3638079e+00 4.8511105e-01 3.8596547e-01 -6.6880689e-01 -1.4346943e+00 -1.8692214e-01 1.3556923e+00
+1 5.9923712e-01 1 1 1.2350999e+00 4.5893060e-01 8.2840939e-01 -4.6725505e-01 -1.8827724e-02 -1.1842561e+00 -7.8128683e-03 -8.5099879e-01
+1 4.0481259e-01 1 1 -1.3204720e+00 6.3657030e-01 -4.6200335e-01 8.2596852e-01 8.6329677e-01 1.3393576e+00 6.3601320e-01 9.3472836e-01
+1 6.5265027e-01 1 1 -9.6277644e-01 -1.4275667e+00 1.1266775e+00 -6.4497701e-01 1.5540199e+00 1.0713528e+00 -1.3660123e+00 -1.1253435e+00
+1 6.3053475e-01 1 1 9.6012469e-01 -7.7036419e-01 -1.4512303e+00 1.5075882e+00 -7.8896591e-01 -1.3834200e+00 1.8992792e-01 -1.2598192e+00
+1 8.1696745e-01 1 1 -1.5457598e+00 -1.0076629e+00 4.9736572e-01 1.0908046e+00 5.1246616e-01 -2.1193388e-01 2.6035604e-01 5.5311023e-01
+1 4.8416737e-01 1 1 1.3858113e+00 5.3499854e-01 -5.5243932e-01 -1.1820146e+00 -1.2283596e+00 5.9328700e-01 -4.3461810e-01 1.5104450e-01
+1 1.2705840e+00 1 1 -4.3717465e-01 4.8224399e-01 -1.4412778e+00 1.3128765e+00 1.5066450e+00 -4.0423387e-02 -4.2342173e-01 1.9800514e-01
+1 5.0247636e-01 1 1 5.9086100e-01 -2.3436204e-01 1.2653011e+00 -1.0318469e+00 9.4492451e-01 -8.1184816e-01 -7.4173151e-01 9.2577947e-01
+1 8.9726389e-01 1 1 2.6384970e-02 6.3430467e-01 4.7552517e-01 -6.5999740e-01 5.9531971e-01 -7.9516849e-01 -4.4190549e-01 -7.3290369e-01
+1 7.2989689e-01 1 1 4.8763203e-01 1.3347926e+00 -6.0184031e-02 3.8742934e-01 -4.3430782e-01 -6.1632486e-02 -3.8057644e-01 2.7240541e-01
+1 4.0007197e-01 1 1 -7.8378643e-01 -2.5380122e-01 7.9830766e-02 -9.9657828e-01 -1.4918204e+00 8.6837752e-01 -6.5572929e-02 1.0172156e+00
+1 5.9614708e-01 1 1 -4.0052595e-01 6.4577584e-01 2.5562022e-01 1.4808963e+00 2.5133290e-02 -1.0185142e+00 6.1479784e-01 -2.0441308e-01
+1 1.2343321e+00 1 1 7.9333532e-01 -6.4815702e-01 -1.4896768e+00 -1.4150074e+00 1.4417944e+00 3.7020945e-01 2.0905362e-01 1.3317962e+00
+1 7.6307871e-01 1 1 6.6757793e-01 1.4683437e+00 1.4951848e+00 -1.7297495e-01 1.1350222e+00 -1.3847737e+00 1.2636833e+00 -3.4846956e-01
+1 9.2446153e-01 1 1 1.3548304e+00 1.2428629e+00 -2.9289455e-02 -1.2167356e+00 5.6803749e-01 -9.7334783e-01 1.5593937e+00 -7.9925746e-01
+1 6.7590695e-01 1 1 3.7017302e-01 3.4772669e-01 9.6217321e-01 -1.0484545e+00 -2.9404643e-01 -7.8396184e-01 1.5640174e+00 3.3003556e-01
+1 4.4741073e-01 1 1 1.1444731e+00 8.8006781e-01 1.4678105e+00 -1.8086494e-01 -3.1312061e-01 -2.0709380e-01 7.3551962e-01 -1.1450164e+00
+1 8.3528416e-01 1 1 -8.1191302e-01 6.8141330e-01 -1.4364029e+00 1.2646174e+00 -4.5038611e-01 2.5918574e-01 -2.8878944e-01 1.1053253e+00
+1 6.4067278e-01 1 1 1.2563478e+00 1.4081482e+00 1.5151966e+00 1.5503494e+00 -1.5426051e+00 -1.2543326e+00 7.6594297e-02 9.6479798e-01
+1 8.4387201e-01 1 1 7.9339177e-01 1.1286879e+00 1.5867882e-01 3.5341677e-01 9.9972074e-01 -1.4811432e+00 -7.3264351e-01 -1.5416837e+00
+1 9.5732344e-01 1 1 -1.5253889e+00 9.2090744e-01 -2.9715576e-01 -8.7608321e-01 1.0689088e+00 4.0671243e-01 1.5038052e+00 7.7802122e-01
+1 6.1300128e-01 1 1 1.3263742e+00 -9.3568993e-01 8.3539644e-01 3.1418542e-01 1.5226561e+00 -4.8977035e-01 3.4129564e-01 8.9399802e-01
+1 8.6139502e-01 1 1 -3.6954347e-01 6.7219634e-01 7.3044839e-01 -5.0286243e-01 -1.3341172e-01 -5.9750502e-01 -3.9232958e-01 -8.1286921e-01
+1 9.8934486e-01 1 1 1.1582997e-02 4.3673654e-01 -6.9803078e-01 -7.2462581e-01 8.4644066e-01 1.4048169e+00 3.1977418e-01 8.9370641e-01
+1 6.8210261e-01 1 1 -1.0331475e-01 1.4705231e+00 -1.0963320e+00 1.1687974e+00 9.9663120e-01 -1.4523388e+00 -8.2040848e-01 5.6909086e-01
+1 6.1065914e-01 1 1 8.8980849e-01 1.7218531e-01 -6.1167813e-01 -4.0014854e-01 -5.9142740e-01 7.1651231e-01 -1.5509409e-01 -1.4395182e+00
+1 6.4194176e-01 1 1 1.0302138e+00 5.1173697e-01 -1.1832470e+00 8.5341830e-01 -1.2115643e-01 6.9773056e-01 8.5550288e-01 -5.7735910e-01
+1 4.5124983e-01 1 1 1.4858472e+00 -9.1741249e-01 -5.5039527e-01 -1.1106796e+00 -5.2403222e-01 -8.0782449e-01 -6.3267504e-01 7.0525458e-01
+1 3.7653852e-01 1 1 1.1349953e-01 -1.4981707e-02 1.4970555e+00 1.5183001e-01 -1.5253330e+00 8.5732817e-01 9.2171955e-01 -1.5346216e-02
+1 8.5642056e-01 1 1 6.3988540e-01 -4.7013310e-01 -3.8093633e-03 8.3366767e-01 -8.7551776e-01 -1.3709000e+00 1.4704283e-01 -3.1325806e-01
+1 9.0131273e-01 1 1 8.8228707e-01 -4.2147785e-01 -1.1921166e+00 -5.0651655e-02 3.9299974e-01 -2.7513066e-01 -1.0846007e+00 3.8113473e-01
+1 7.9087026e-01 1 1 2.8142708e-01 5.1313637e-01 1.1745513e+00 6.9243350e-02 1.5189473e+00 3.0330564e-01 -1.3636951e+00 2.3958832e-02
+1 1.0116286e+00 1 1 -1.2936496e+00 6.1119786e-01 -1.0848603e+00 1.3836991e+00 3.6601401e-01 -1.1469556e+00 1.4362311e+00 5.5222753e-01
+1 2.2588010e-01 1 1 5.9406135e-01 -6.0561572e-01 5.5591466e-01 -1.3796326e+00 3.5902590e-01 -7.0961701e-02 -1.2612060e+00 1.0233722e+00
+1 3.2442492e-01 1 1 4.0766291e-01 1.7678772e-01 1.6113681e-01 6.1008290e-01 -8.5115326e-01 1.1519040e+00 -7.6328743e-01 -4.0321508e-01
+1 9.2208073e-01 1 1 -2.2309304e-01 -6.7548904e-01 1.7341512e-01 -4.9504649e-01 1.4801518e+00 1.5566868e+00 -1.4491128e+00 -4.2052900e-01
+1 7.9524325e-01 1 1 1.5369247e+00 7.7158089e-01 -8.0998046e-01 -1.3089689e+00 -1.3611201e+00 5.1294929e-02 1.5288296e+00 7.5259558e-01
+1 9.3235906e-01 1 1 9.1816531e-01 -5.3443014e-01 -8.2055945e-01 7.3361464e-01 7.3204298e-01 1.3174905e+00 -4.7665314e-02 8.2193149e-01
+1 9.0545323e-01 1 1 1.0121723e-01 -3.5393550e-01 4.4914207e-01 -8.8983280e-01 9.6959181e-01 1.1176442e+00 -4.8061094e-03 6.1961267e-01
+1 1.0663500e+00 1 1 1.5564282e+00 -1.5590803e+00 -5.1630748e-01 -1.4387558e+00 4.8845673e-01 6.6421531e-01 9.0512818e-01 -5.4949758e-01
+1 5.6717589e-01 1 1 -1.1530835e+00 5.6162115e-01 -5.0085345e-01 -3.2938855e-01 5.1064267e-01 1.3879995e+00 8.9774162e-01 8.7652597e-01
+1 1.0460306e+00 1 1 6.1120133e-01 -1.3192189e+00 -1.5171436e+00 -5.4714485e-01 -4.5974485e-01 -1.3596402e+00 -7.2618373e-01 8.4398936e-01
+1 1.2292310e+00 1 1 -5.4719638e-01 1.2493394e+00 -1.4657455e+00 -4.2183386e-01 1.3862447e+00 4.7145855e-01 1.1755298e-01 6.3832576e-01
+1 1.1703944e+00 1 1 -1.2878711e+00 -7.5781275e-01 -1.5561873e+00 8.1286342e-01 5.6302696e-01 7.0725117e-01 -3.4876142e-01 -1.9784743e-01
+1 1.1248153e+00 1 1 3.2430880e-01 -5.4220895e-01 -1.0819071e+00 -9.9092445e-01 3.1700993e-01 -1.0161673e+00 5.7876864e-01 -1.4167421e+00
+1 8.2654898e-01 1 1 -5.2927169e-03 8.5443232e-01 -7.5036333e-02 -8.8455175e-01 -1.5528533e-01 -1.0255897e+00 9.9374551e-01 -1.0538747e+00
+1 7.1942733e-01 1 1 -9.9009902e-01 2.2404390e-01 -1.3569917e+00 -6.4475247e-01 7.8287625e-01 8.3268144e-01 1.1741767e+00 -1.7263083e-01
+1 3.9448073e-01 1 1 4.2212181e-01 -1.2638055e+00 1.0039360e+00 -1.0016733e+00 8.1110484e-01 -9.1836464e-01 -1.0979325e+00 1.4252847e+00
+1 9.5052108e-01 1 1 8.8510431e-01 -4.7108348e-01 -3.4136462e-01 6.7184142e-01 8.6845513e-01 -3.0976226e-01 7.6416416e-01 1.1654028e-01
+1 9.7200229e-01 1 1 5.0685464e-01 -6.8653241e-01 -7.6693534e-01 7.5480568e-01 2.8591393e-01 -5.5527629e-01 4.7624779e-01 1.4801871e+00
+1 3.3654830e-01 1 1 -1.2932685e+00 5.1968328e-01 7.2380898e-02 2.6797981e-01 -1.2814064e+00 1.1431068e+00 -4.8155257e-01 -7.6726392e-01
+1 4.2809211e-01 1 1 7.1627634e-01 6.8928932e-01 7.0939661e-01 -1.1071269e+00 -9.7901059e-01 1.3562989e+00 -7.1140367e-01 8.3319291e-01
+1 8.5925066e-01 1 1 -1.2655332e-01 -1.3080870e+00 4.8474122e-01 1.7085548e-01 1.4313809e+00 -8.0913533e-02 3.4020713e-01 1.3947969e+00
+1 3.6534992e-01 1 1 -1.2343455e-01 -1.5218688e-01 8.9600808e-01 1.5239856e-01 -1.0973469e+00 3.9586882e-01 1.6253152e-01 -2.1326088e-01
+1 6.7731919e-01 1 1 -1.1132654e+00 -5.4844711e-01 1.5541790e+00 9.6458241e-01 1.1805862e+00 -5.2594345e-01 -1.5183694e+00 2.8157412e-01
+1 6.6170794e-01 1 1 6.7434287e-01 -3.1775152e-01 -1.2566444e+00 1.1184453e+00 -1.8684494e-01 9.1008116e-01 -7.6781879e-02 1.1777393e+00
+1 4.6894786e-01 1 1 -1.1857531e+00 2.5770789e-01 5.0472573e-01 1.5609946e+00 1.2898046e+00 -6.8052854e-01 7.2153421e-01 -9.1146773e-01
+1 4.6847008e-01 1 1 1.3122710e+00 -9.5984232e-01 6.2517801e-01 1.9577262e-01 7.5635832e-01 8.9566190e-01 2.7784018e-01 -6.3232856e-01
+1 1.1817707e+00 1 1 1.3584451e+00 8.3344893e-03 -1.2606366e+00 1.1029067e+00 1.2304643e+00 -1.1225094e+00 1.2532560e+00 4.6180647e-01
+1 8.5093033e-01 1 1 1.4335425e+00 -1.2939071e+00 -6.1769410e-01 1.1567555e+00 -6.9172113e-01 -7.5119553e-01 -9.0566933e-01 -1.2940635e+00
+1 5.2783507e-01 1 1 6.7542294e-01 -5.9177825e-01 1.3789320e+00 1.4144891e+00 1.2773576e+00 7.1762019e-01 -5.6801396e-01 -7.8932947e-02
+1 3.9094399e-01 1 1 1.2590854e+00 2.6526531e-01 1.8176653e-01 8.8707531e-01 -1.0942971e+00 4.6835567e-01 6.8950799e-01 -8.7393690e-01
+1 5.9078134e-01 1 1 -3.1971133e-01 3.9415988e-01 1.3220691e+00 -9.2404683e-01 -9.6796864e-01 -1.1774684e+00 -7.7454748e-01 -1.3117956e+00
+1 4.5848445e-01 1 1 -1.2648415e+00 -9.7373854e-01 -4.6895270e-01 -1.5626048e+00 -1.4822129e+00 -8.1854965e-01 9.4048143e-01 3.4932876e-01
+1 2.8005810e-01 1 1 9.6559985e-01 -1.0675922e+00 5.6786418e-01 1.0160972e+00 1.2769052e+00 -3.2975433e-01 1.3186782e+00 -4.6813840e-01
+1 1.0387195e+00 1 1 -6.3101263e-01 -1.3868651e+00 -6.5282376e-02 -1.5186979e-01 7.2613180e-01 -4.1158697e-01 -9.1098162e-01 -1.4541148e+00
+1 1.2546371e+00 1 1 5.8749211e-01 -1.5650193e+00 -7.8506176e-01 -1.5022691e+00 -9.9032710e-01 2.4486613e-01 1.2544652e+00 -8.5860884e-01
+1 5.6049702e-01 1 1 -4.5777733e-02 1.2761123e+00 1.5620792e-01 3.4259051e-01 -2.6971048e-01 -2.1306054e-02 5.6841061e-01 -1.3037761e+00
+1 1.0414230e+00 1 1 3.0384550e-01 -3.3819355e-02 -9.8490596e-01 -6.2067595e-01 2.9421097e-01 5.0717042e-02 -3.0607790e-01 4.3997828e-02
+1 1.0774068e+00 1 1 -1.4982709e+00 2.2637597e-01 -2.6272507e-01 1.5284398e+00 -6.2994920e-02 1.0297090e+00 -1.4641046e+00 1.1972239e+00
+1 4.5454838e-01 1 1 1.5673671e+00 2.3220598e-01 1.4589529e+00 -3.1521563e-01 -3.8888075e-02 -7.1460632e-01 8.9001555e-01 -1.5928305e-01
+1 7.1266455e-01 1 1 4.8480237e-01 8.2780219e-01 4.9020834e-01 -1.1037962e+00 -1.4059987e-01 -7.9697403e-02 1.3687025e+00 -4.3329482e-01
+1 7.1183121e-01 1 1 -1.2178615e+00 -1.2424890e+00 -1.4658952e+00 -3.9794720e-01 -5.8428211e-01 -1.1557887e+00 1.0414180e+00 -1.7428344e-01
+1 1.1000334e+00 1 1 -1.1224372e+00 -3.4660397e-01 -9.3139623e-01 1.5209057e-01 5.8920868e-01 -8.7329501e-01 1.2988334e+00 -1.2174442e+00
+1 6.7923891e-01 1 1 4.6137458e-01 -8.6012784e-01 5.7977574e-01 -1.0702800e+00 5.3019077e-01 5.1678732e-02 -1.4345948e+00 -3.9112194e-01
+1 3.7758326e-01 1 1 8.7186566e-01 1.4407654e+00 -9.2951978e-01 5.6336063e-01 1.3594287e+00 1.4848723e+00 4.8890726e-01 -1.3746370e+00
+1 5.1524906e-01 1 1 1.0579531e+00 -4.5147483e-01 7.0136745e-01 -3.5821382e-01 -8.8447127e-01 -5.6351463e-01 -1.3420447e+00 -2.5166520e-01
+1 5.0874456e-01 1 1 -3.9660644e-01 -9.9126001e-01 6.2708319e-01 -1.2081246e+00 7.0781752e-01 9.1145600e-01 8.8969132e-01 -1.1532995e+00
+1 4.7845854e-01 1 1 6.9521878e-01 -2.4121768e-01 -6.5624933e-01 -8.3721942e-01 -9.2230554e-01 4.3518788e-01 -9.3895562e-01 1.2226315e-01
+1 8.2277300e-01 1 1 9.5890229e-01 -1.4910412e+00 5.4937644e-01 4.6722759e-02 -5.7103775e-01 5.7496518e-01 -8.0724716e-01 2.7508587e-01
+1 3.9012815e-01 1 1 -9.9507908e-02 5.5526728e-01 2.2899534e-01 -1.2875575e-01 1.3404972e-01 -9.9149171e-02 1.1356190e+00 -1.0562414e+00
+1 1.1652168e+00 1 1 -1.1021175e+00 -1.2945151e+00 2.7367578e-01 5.5940357e-01 4.5175444e-01 -1.3560139e+00 1.1726505e+00 8.9033054e-01
+1 8.8491079e-01 1 1 -4.5846921e-01 -1.3867704e+00 3.7725385e-01 -8.9108023e-01 -5.9253690e-01 -1.4122301e+00 1.5254430e+00 3.7952397e-01
+1 5.0639813e-01 1 1 8.3469870e-01 2.5702942e-02 7.7142503e-01 -4.1326569e-01 8.0951190e-02 -6.1951731e-01 -4.1686676e-01 1.2263134e+00
+1 1.0004862e+00 1 1 1.5699234e+00 -1.5504430e+00 -1.2462958e-02 3.0489640e-01 2.3703194e-01 -9.8937426e-01 -5.2794294e-01 -1.3402665e+00
+1 7.6137506e-01 1 1 -5.3484038e-01 1.2150581e+00 1.0217682e+00 4.5610079e-01 2.5640924e-01 3.6798201e-02 -1.2792995e+00 -6.3928460e-01
+1 7.1284941e-01 1 1 -9.6570751e-01 1.1298511e+00 9.1194584e-01 1.9991355e-01 -7.9510320e-01 -4.2638598e-01 -1.2592733e-01 -2.0939527e-01
+1 1.2748388e+00 1 1 -1.1784871e+00 -1.5209320e+00 -7.5676596e-01 -1.5571865e+00 1.0356725e+00 -2.9636519e-01 9.7277618e-01 -7.2250935e-01
+1 5.6984885e-01 1 1 9.0941899e-01 8.3558664e-01 1.3431463e+00 9.7565378e-01 -1.0167444e+00 1.5561801e+00 6.0109422e-01 -9.5900959e-01
+1 4.0299294e-01 1 1 7.5676117e-01 7.8551971e-01 -1.2248160e+00 -1.3005758e+00 -1.3014955e+00 9.5983137e-01 -7.7145407e-01 1.4376985e+00
+1 6.1759377e-01 1 1 -1.4236942e+00 1.2574531e+00 1.3734753e+00 4.2485778e-01 6.7411962e-01 -1.9237016e-01 -4.7559424e-01 1.4095320e+00
+1 8.1851951e-01 1 1 1.4830739e+00 5.2081705e-01 -4.2406628e-01 -2.5536441e-01 1.3453912e+00 -4.6646631e-01 -1.1006053e+00 -7.4654218e-01
+1 4.0758376e-01 1 1 6.2760770e-01 8.9503524e-01 9.9183473e-01 -4.9413030e-01 -1.1947464e+00 1.5159197e+00 -1.7569969e-01 3.8667024e-01
+1 4.7738395e-01 1 1 -1.2655834e+00 9.1168535e-01 4.7566939e-01 1.5229756e+00 9.5703666e-01 -2.5344491e-01 1.1236662e-01 -1.1884161e+00
+1 8.5542273e-01 1 1 1.0644327e+00 1.1482390e+00 -7.7793960e-01 -1.0456075e+00 -3.9178448e-02 3.5111376e-01 4.4862138e-01 5.3660091e-01
+1 3.2981225e-01 1 1 -1.4504880e+00 -3.5118149e-01 4.7784838e-01 5.4380702e-01 1.2622840e+00 1.2580223e+00 1.5715014e-01 -8.6102018e-01
+1 3.8494126e-01 1 1 4.0672047e-01 7.4525377e-01 1.2869024e+00 8.7163419e-01 3.1373449e-02 6.6247642e-01 -8.5709751e-01 -9.9043124e-01
+1 1.0026709e+00 1 1 -3.5473709e-01 -4.9795683e-02 -8.9699920e-01 3.0932423e-01 -4.9400358e-01 4.3682934e-01 -1.0356114e+00 1.1216870e+00
+1 7.7000326e-01 1 1 6.7651285e-01 -1.2523920e+00 6.3762839e-01 -5.2345704e-01 5.1123014e-01 -1.1132729e-01 -1.0975677e+00 -5.0492661e-01
+1 4.8771822e-01 1 1 7.2758221e-01 -2.8186710e-01 6.4787270e-01 -1.2829888e+00 -1.0892201e-02 1.3115355e+00 6.1137060e-01 -8.5985930e-01
+1 3.7909921e-01 1 1 1.3955920e+00 1.8137923e-01 3.6380542e-02 6.9964845e-01 -8.5285138e-01 1.5636179e+00 -8.4387046e-01 -3.2898496e-01
+1 5.9768607e-01 1 1 5.8352199e-01 1.0958992e+00 -1.1627908e+00 1.0226067e-02 1.2141549e+00 3.0284125e-01 1.3600287e+00 -4.7171133e-02
+1 5.1145503e-01 1 1 -7.9813465e-01 -3.8011463e-01 8.2235121e-01 -9.1808305e-01 -1.4839798e+00 4.7271824e-01 -2.2542210e-01 -1.1238833e+00
+1 4.8301371e-01 1 1 3.5152452e-01 1.4128756e+00 1.3907102e+00 1.2812755e+00 -1.4471767e-01 -1.1229597e-01 9.1513785e-02 1.2900477e+00
+1 8.4135441e-01 1 1 -1.2631682e+00 -1.0994195e+00 2.1617320e-01 -1.2210578e+00 -6.7717987e-01 7.3877137e-01 -1.3082190e+00 -1.4400303e+00
+1 6.5630047e-01 1 1 8.1521139e-01 9.0427099e-01 1.5418535e+00 -1.4354117e+00 6.2812696e-01 9.5623909e-01 7.6949545e-01 2.4084373e-01
+1 5.0932272e-01 1 1 7.7222765e-01 -9.4267227e-01 -1.0659422e+00 -6.7523393e-01 1.1784562e+00 -8.7761215e-01 -1.0268428e+00 1.4892792e+00
+1 5.2977248e-01 1 1 9.1091974e-01 -4.4115817e-01 1.2118281e+00 -1.2239544e+00 -1.4288495e+00 -2.4986240e-01 -1.3787460e+00 1.2469715e+00
+1 6.3111242e-01 1 1 8.4706159e-01 -3.8671526e-01 2.4898450e-01 1.4787775e-01 -3.3991050e-01 8.7198989e-01 -1.9612964e-01 2.8528211e-01
+1 9.5562569e-01 1 1 -1.1338227e+00 4.3176764e-01 8.1008627e-02 3.8154584e-01 -1.4604031e+00 4.3355106e-03 -8.2024324e-01 6.6601991e-01
+1 5.1404922e-01 1 1 7.4359440e-01 -3.6033343e-01 1.2023771e+00 6.5026191e-01 2.6777644e-01 6.1029570e-01 -5.1962902e-01 3.0198772e-01
+1 3.8942430e-01 1 1 3.3554867e-01 8.6672145e-01 -1.5134444e+00 -6.4884668e-01 -1.3836557e+00 -6.0126520e-02 2.2265231e-01 -1.3061783e+00
+1 4.6694327e-01 1 1 4.0774568e-01 -5.7772556e-01 1.0149569e+00 -6.9810143e-01 -1.0333411e+00 1.0464053e+00 4.8047280e-01 5.1059510e-01
+1 8.0376422e-01 1 1 1.1680052e+00 8.2935480e-01 -4.6764371e-01 8.5789245e-01 -6.3894209e-01 2.9811807e-01 1.4132228e+00 -1.2592735e+00
+1 3.0006956e-01 1 1 -1.1492075e+00 -2.8047174e-01 5.7690783e-01 -1.3118292e+00 -7.3608735e-01 -3.6993110e-01 -1.5457604e+00 2.9989814e-01
+1 6.8687253e-01 1 1 -2.1934523e-01 -1.4995377e+00 1.1350408e+00 -2.1632584e-01 1.7174192e-01 -2.2016826e-01 1.3759518e+00 1.2734443e+00
+1 8.2849092e-01 1 1 -1.4470728e+00 -8.7360699e-01 8.8059079e-01 -9.6562223e-01 -6.5723162e-01 4.2824314e-01 3.5873828e-01 -8.9247147e-01
+1 8.3424169e-01 1 1 1.2572176e+00 1.0914578e+00 4.6385584e-02 2.5477832e-01 -2.5204928e-01 9.3626297e-02 5.9797922e-01 1.3368890e+00
+1 5.4842975e-01 1 1 -2.9591854e-01 3.7247816e-01 4.8753232e-01 6.8365096e-02 -1.3253529e+00 -3.6074528e-01 2.8178734e-01 4.2215539e-01
+1 3.9350974e-01 1 1 -3.6176190e-01 -9.5368582e-01 6.8208582e-01 -8.1074681e-01 -1.3136026e+00 2.2785428e-01 -1.5219261e+00 1.4493820e+00
+1 1.1118804e+00 1 1 -1.1505362e+00 -1.9181982e-01 1.4481335e-01 -1.1342272e+00 1.3944027e+00 -5.4637649e-02 -1.6374197e-01 -1.4584929e-01
+1 9.5163401e-01 1 1 -5.5886630e-01 -6.4158926e-01 -8.5640571e-01 2.2822906e-01 -5.5432711e-01 -9.4990997e-01 2.3931167e-02 -8.4670875e-01
+1 4.2592167e-01 1 1 4.9604880e-01 -1.2446414e+00 1.1668049e+00 -3.8885510e-02 1.3880243e+00 4.3694108e-01 8.7257776e-02 7.8076584e-01
+1 7.6016603e-01 1 1 -6.9474595e-01 1.1772169e+00 6.6902511e-01 -9.7498392e-02 -9.4187803e-01 -1.3749693e+00 -5.8233217e-01 -1.0111079e-01
+1 6.5063175e-01 1 1 7.0478664e-01 -2.6564620e-01 5.4489268e-01 1.2558826e+00 3.4126574e-01 4.4671975e-01 -1.1956756e+00 2.3259030e-01
+1 6.3348618e-01 1 1 1.5447773e+00 -5.1253926e-01 2.6868041e-01 -7.4241880e-01 -8.9486867e-01 -3.8761298e-01 1.0477107e+00 1.0039862e+00
+1 3.0936184e-01 1 1 9.5066753e-01 -3.3972396e-04 1.2429605e+00 5.7317172e-01 -1.2536983e+00 1.0518792e+00 2.4608696e-01 5.0234735e-01
+1 8.6022277e-01 1 1 -2.7104281e-01 5.7344477e-01 -1.1540184e+00 1.1739717e+00 -2.4606359e-01 1.1915973e+00 -1.4939647e+00 1.4924985e+00
+1 2.9988641e-01 1 1 -1.0719625e-01 -5.2007453e-01 6.0605875e-01 -1.4014089e+00 -1.2547972e+00 -4.7768659e-01 -1.4561546e+00 -1.1948398e+00
+1 8.3605144e-01 1 1 -1.5147184e+00 -9.8186947e-01 9.8603406e-01 -9.5970146e-01 1.3430169e-01 1.4322523e+00 -5.8298915e-01 -6.1234382e-01
+1 9.4011642e-01 1 1 -1.5466177e+00 5.0607688e-01 3.7314617e-01 -7.6570132e-01 1.5450476e+00 9.8203058e-01 3.2884968e-01 1.9493495e-01
+1 7.3217412e-01 1 1 -4.6684703e-01 1.3428512e+00 8.4876948e-01 -1.1786236e+00 -7.9016824e-01 -9.3987413e-01 9.1513029e-01 -4.0939012e-01
+1 3.8379104e-01 1 1 1.4003679e+00 9.8626339e-02 -7.0350911e-01 -1.3844498e+00 -8.4553731e-01 -5.3669275e-01 -6.4277617e-01 -5.3182157e-01
+1 5.5507100e-01 1 1 -8.2902585e-01 -1.1480432e+00 1.0770607e+00 1.3287044e+00 -1.5220326e+00 -6.8254368e-01 7.9799918e-01 -4.9399347e-01
+1 9.2986015e-01 1 1 -4.7411970e-01 5.0084002e-01 3.0240429e-01 1.0941849e+00 1.1869635e+00 -1.5567779e+00 5.1326288e-01 6.8117731e-01
+1 1.0102198e+00 1 1 -1.4507611e+00 1.2915062e+00 -5.8809097e-01 -9.1728443e-01 1.8285563e-01 1.5595930e+00 -4.0413737e-01 5.8347088e-01
+1 3.8253006e-01 1 1 -1.0417357e+00 1.0815859e+00 -5.9446218e-01 -1.0041807e+00 7.7696918e-01 -1.3694482e+00 -2.1340973e-01 1.4844528e+00
+1 5.5382769e-01 1 1 -3.5612479e-01 9.5915348e-01 -8.6121587e-01 -6.2874633e-01 -1.0796747e+00 -1.0074955e+00 9.2151100e-01 -1.3314404e+00
+1 6.2638927e-01 1 1 -6.5542397e-01 9.8055728e-01 -1.1378031e+00 9.7813395e-01 -2.5331920e-01 2.0722157e-01 -2.1647572e-01 4.6431313e-02
+1 7.7144162e-01 1 1 -1.2868950e+00 -5.6879454e-01 -1.8303705e-01 -4.5699149e-01 -6.7769528e-01 -1.2533267e+00 -3.4319149e-01 1.2561056e+00
+1 1.1155595e+00 1 1 1.0219025e+00 1.3663077e-01 -6.8441857e-01 5.3809393e-01 1.3903938e+00 -2.8373957e-01 -5.5289253e-02 -1.3560927e-01
+1 2.6245034e-01 1 1 2.8275420e-02 -1.5081455e-01 1.4894331e+00 -9.0051593e-01 1.1818955e+00 1.2661571e-01 6.6494896e-01 -1.5303891e+00
+1 5.3586754e-01 1 1 8.4449926e-01 5.2512674e-01 6.9188527e-01 1.2221465e+00 -1.7315429e-01 1.1720076e+00 1.1520681e+00 -1.0308464e+00
+1 3.6402997e-01 1 1 -2.1648751e-01 1.0713043e+00 1.4812842e+00 8.8330442e-01 -1.0892711e+00 1.4581490e-01 1.1729246e+00 4.4761352e-01
+1 6.3541730e-01 1 1 -5.4131567e-01 9.4327700e-01 -1.1778469e+00 -1.4694323e+00 -1.3183508e+00 2.6868676e-01 -1.4974476e-01 -1.0739134e+00
+1 7.6911176e-01 1 1 1.5991972e-01 1.1800668e+00 -8.9832703e-01 -6.8898533e-01 1.3064732e-01 1.3496692e+00 -3.4452510e-01 -8.1334899e-01
+1 9.3010735e-01 1 1 -1.4326493e+00 5.0785607e-01 3.1197453e-01 1.3415974e-01 -1.8372707e-01 -1.5498574e+00 -4.7813657e-01 -8.8684579e-01
+1 1.0051941e+00 1 1 -1.3698864e+00 -1.7024134e-01 3.7861295e-02 -8.4082677e-01 2.8470505e-01 -1.5079242e+00 1.5271481e-01 -1.5016918e+00
+1 8.8387069e-01 1 1 1.0522904e+00 7.4465533e-01 -1.4085246e+00 -8.9179264e-01 3.9208106e-01 -4.5415826e-01 -3.3035433e-03 6.2171727e-01
+1 1.1059522e+00 1 1 -1.3219466e+00 -6.8305281e-01 -1.1715598e+00 1.7972195e-01 -1.3550414e+00 1.0322849e+00 1.0260152e+00 2.6500825e-01
+1 6.1425709e-01 1 1 -6.1318612e-01 -6.8905628e-01 1.0975302e+00 1.5163542e+00 -7.7524405e-01 -1.4041651e+00 3.4675184e-02 -7.8464776e-01
+1 1.4349819e+00 1 1 -1.3951314e+00 -1.0583963e+00 -1.2425257e+00 7.6468082e-01 -1.3419664e+00 -1.5802065e-01 -1.5504209e+00 8.3104626e-01
+1 1.1122235e+00 1 1 8.7390438e-01 -7.6963297e-01 -9.6261329e-01 -2.6502150e-01 -9.3643352e-01 -1.2072818e+00 -1.5544063e+00 -1.2637152e-01
+1 3.0567971e-01 1 1 7.6526985e-01 -1.2843108e+00 5.6067585e-01 5.6201008e-01 7.4098352e-01 7.6233763e-01 5.7826136e-01 -2.0949412e-01
+1 1.0295132e+00 1 1 2.1001658e-01 4.7079465e-01 -1.4989556e+00 -1.0656341e+00 4.3666041e-01 1.1937211e+00 -1.2490227e+00 7.5769728e-01
+1 8.5139768e-01 1 1 -1.4014289e+00 -1.0261877e+00 -5.1557969e-01 1.0691728e-01 1.9112480e-01 6.5908452e-01 -2.0193482e-01 -1.3984638e+00
+1 1.0449085e+00 1 1 -1.2951947e+00 2.0731682e-01 -8.3533060e-01 -3.2234366e-02 1.5268211e+00 -2.2238553e-02 -9.9847064e-01 1.4149972e+00
+1 9.2819825e-01 1 1 -2.4142987e-01 3.4752545e-01 3.7624896e-01 -1.4090587e+00 7.5382679e-01 8.6168033e-02 1.0918443e+00 1.8967633e-03
+1 6.5277378e-01 1 1 1.2258844e+00 6.3941181e-01 -4.0975099e-01 -7.2346903e-01 -4.7637886e-01 -4.8075202e-02 5.8448584e-01 4.6297358e-01
+1 6.7937091e-01 1 1 8.7419792e-01 -7.9411348e-01 -3.1374882e-01 -1.3804391e+00 1.4201018e+00 -6.1060341e-01 -3.0665599e-01 -5.2809674e-01
+1 5.4198146e-01 1 1 -5.8438255e-01 -1.1796649e+00 1.5575740e+00 -3.7892320e-01 9.7103929e-01 1.1716267e+00 1.3863873e+00 -7.2271341e-01
+1 1.0153178e+00 1 1 -1.0989529e+00 -3.6206881e-02 -7.4530400e-01 -5.5393792e-01 -3.1656349e-01 2.6894597e-02 -1.8071734e-01 -1.2471436e+00
+1 1.2574719e+00 1 1 -6.7785814e-01 9.3992772e-01 -7.9440803e-01 -1.4956316e+00 1.3753708e+00 -3.7185283e-01 6.0368300e-01 -3.6159800e-02
+1 4.9132955e-01 1 1 -1.3468080e+00 1.4373734e+00 1.5297315e-01 -1.1977788e+00 1.9077673e-02 -1.1026866e+00 -1.2440302e+00 -1.4103730e+00
+1 8.0995462e-01 1 1 -6.2704246e-01 -9.1258347e-01 1.1968950e+00 2.5675941e-01 1.9599218e-01 -5.9889922e-01 -1.1163243e+00 -8.2257584e-01
+1 3.2106888e-01 1 1 1.3407833e+00 -5.3501186e-01 5.9685738e-01 -1.1928597e+00 -1.4901482e+00 -3.6336523e-02 -4.7047212e-01 1.1171499e+00
+1 6.2686240e-01 1 1 -9.8370359e-02 -7.0623396e-01 2.7667349e-01 1.2518456e+00 -1.4431030e-01 -1.2389710e+00 1.6375651e-01 -1.3606359e+00
+1 9.6686772e-01 1 1 -8.3288726e-01 -7.3717543e-01 4.9427202e-01 5.2379364e-01 -1.1367266e-01 -9.1017372e-01 2.2041706e-01 -5.5543238e-01
+1 1.9796536e-01 1 1 6.0070133e-01 7.3390543e-01 8.5881724e-01 6.5706249e-01 -4.0804794e-01 -8.7503390e-01 6.1186775e-01 -1.4801822e+00
+1 9.1823384e-01 1 1 -1.0914736e+00 8.5583422e-01 -1.4768551e+00 5.5113291e-01 3.5057940e-02 -8.9956518e-01 1.2285326e+00 8.4977878e-01
+1 7.5218279e-01 1 1 -6.3725841e-01 -1.3469434e+00 2.2012261e-01 1.4756798e+00 -1.4006190e+00 1.4934708e+00 1.3999139e+00 5.5167456e-01
+1 9.5664019e-01 1 1 -7.1274220e-01 2.3956441e-01 -1.1954395e+00 -1.1233109e+00 -2.4953951e-01 -5.6166473e-01 9.6543889e-01 1.1544839e+00
+1 8.7838924e-01 1 1 -1.6542551e-01 -1.1628257e+00 -1.2673361e+00 1.4861187e+00 1.5582593e-02 5.8673969e-01 -1.9458454e-01 9.3533313e-01
+1 8.2298643e-01 1 1 2.9955698e-03 2.3574826e-01 -1.1950512e-01 1.5359178e+00 1.1444510e+00 -1.2542387e-01 1.5518437e-02 -3.8572183e-01
+1 7.1216731e-01 1 1 8.1059297e-02 6.7270066e-01 -1.0448770e+00 -2.9654773e-01 -1.1845330e+00 9.6314218e-03 6.6176490e-02 1.4204500e+00
+1 3.4862801e-01 1 1 -1.0876111e+00 -5.1197550e-01 2.5535723e-01 -1.5118187e+00 -1.7364017e-01 -1.4875116e+00 1.0446554e-01 5.3991790e-01
+1 6.8243215e-01 1 1 1.4485438e+00 5.0076308e-02 3.7345601e-01 6.3834999e-02 1.6928968e-01 1.8615821e-01 -3.9796516e-01 1.4805266e+00
+1 5.1476664e-01 1 1 1.4734395e+00 -3.1431675e-01 -2.2695621e-01 -1.5498633e+00 -1.0313713e+00 -2.6526128e-01 -1.4969351e-01 -1.3454171e+00
+1 1.0056645e+00 1 1 -1.0772091e+00 1.4371826e+00 -5.5949919e-01 1.5332787e+00 1.0515384e+00 -3.2634821e-01 5.1681594e-01 7.5797827e-01
+1 5.2537018e-01 1 1 3.4453996e-01 -9.7766181e-01 -7.1611547e-01 -6.7026524e-01 -1.3951755e+00 2.8641996e-01 -3.7825204e-01 1.8251772e-01
+1 3.9571797e-01 1 1 7.2782024e-01 -1.0324191e+00 -3.1117789e-01 6.0336160e-01 1.3360644e-01 9.4029054e-01 1.3014292e+00 1.3808161e+00
+1 2.2524348e-01 1 1 -8.8709793e-01 -8.5112634e-01 7.8493491e-01 -3.6269141e-01 -7.1524717e-01 1.2519771e+00 1.3520472e+00 4.3121201e-01
+1 5.7259358e-01 1 1 5.4380479e-01 -1.2090598e+00 8.5339847e-01 -1.0647796e+00 -1.4256410e+00 -4.0777278e-01 7.1770247e-01 -2.7392133e-01
+1 1.0102184e+00 1 1 8.3408944e-01 -8.4664018e-01 -1.4440091e+00 -1.2398217e+00 1.7935116e-01 1.5181330e+00 -1.2904001e+00 -1.3626335e+00
+1 9.4984372e-01 1 1 7.5479423e-01 -1.2084463e+00 -6.5805328e-01 5.0105764e-01 1.5675777e+00 -7.5455855e-01 -1.3399492e+00 4.2948071e-01
+1 3.4211621e-01 1 1 7.5559885e-02 3.8980625e-02 -1.4953615e+00 -1.3341268e+00 8.8281686e-01 7.4402783e-01 1.5518791e+00 -1.0975573e+00
+1 9.2583090e-01 1 1 7.3155297e-01 -1.4455041e+00 2.0118317e-01 -1.1229055e+00 -2.3919610e-01 1.3369796e+00 9.2914354e-01 7.8576807e-01
+1 6.1818072e-01 1 1 -9.8289913e-01 -6.5152905e-01 9.3180658e-01 -1.1252333e+00 1.0697301e+00 -1.1953465e+00 -7.4155933e-01 -8.5162611e-01
+1 9.0242458e-01 1 1 -1.0914599e+00 1.3431955e+00 3.3791138e-02 5.9201977e-01 -3.8169747e-01 2.9602051e-01 -6.8957715e-01 -1.8390595e-01
+1 1.1170562e+00 1 1 -4.0640859e-01 -3.9841350e-01 -7.0061512e-01 6.5235182e-01 -5.7212954e-02 -1.0660001e+00 -3.8791378e-01 4.1981621e-01
+1 1.0697120e+00 1 1 -6.8668936e-01 -1.4018162e+00 -5.4905980e-01 -8.1270740e-02 -2.5076221e-01 2.3942635e-01 -8.6221059e-01 -1.6604980e-01
+1 1.1753811e+00 1 1 1.0232592e+00 -1.5221022e+00 -1.1905132e+00 6.7548349e-01 1.4569171e+00 -3.4158238e-01 9.9344580e-01 -1.0647185e+00
+1 4.2591258e-01 1 1 8.3893765e-01 1.6634352e-02 -1.5157556e-01 -8.6486497e-01 8.3189402e-01 -1.2852307e+00 -7.2134974e-01 -2.1236909e-01
+1 7.2222900e-01 1 1 5.5729981e-01 -2.8189736e-02 3.0112877e-01 3.6362735e-01 1.5554299e+00 7.1835997e-01 -3.1895424e-01 -4.3799291e-01
+1 9.9543797e-01 1 1 1.4501688e+00 5.9560139e-01 -3.4553438e-02 1.0872071e+00 9.1834467e-01 3.3546950e-01 -1.1067866e+00 -5.9521203e-01
+1 7.5910939e-01 1 1 5.1204013e-01 1.1583035e+00 4.5500495e-01 1.1864858e+00 -2.5878483e-02 -9.2296624e-01 -3.9264374e-01 -8.9761301e-01
+1 7.6686135e-01 1 1 1.0362136e+00 -8.4310164e-01 6.3161704e-01 -1.5634711e+00 -1.3998811e+00 8.9101133e-01 1.3228937e+00 -2.5401629e-01
+1 8.5016740e-01 1 1 -1.3475294e+00 -1.4263683e+00 1.4593353e-01 -9.7776580e-01 -4.1505298e-01 -7.4472069e-01 8.2287015e-01 1.7254891e-01
+1 3.2858184e-01 1 1 -1.8450428e-01 5.2115531e-01 -8.7900171e-01 3.6143708e-01 -1.4598172e+00 -4.1550615e-01 6.8769865e-01 3.3951948e-01
+1 7.0375431e-01 1 1 -2.1149853e-01 2.9704009e-01 1.5285184e+00 -1.1671535e+00 6.9177136e-01 3.4858858e-01 2.3180156e-01 1.1715603e+00
+1 4.8940436e-01 1 1 -1.5144195e+00 3.6210582e-01 1.0061531e+00 -2.4496027e-01 -4.3310475e-01 -3.4211208e-01 3.1388749e-01 -1.0894410e+00
+1 8.3820030e-01 1 1 3.3531189e-01 6.4754622e-01 -7.7766623e-01 -1.5608106e+00 -1.2140038e-01 -7.6313231e-01 7.7297901e-01 -1.0322001e+00
+1 9.6181043e-01 1 1 -4.3025790e-01 8.3242610e-01 -1.2109116e+00 -2.4566433e-01 -1.4826363e+00 1.1581207e+00 9.7251883e-01 -3.1239894e-01
+1 9.6028643e-01 1 1 6.0177176e-01 1.0734579e+00 -5.5354309e-01 -8.2760182e-01 4.4416744e-01 -7.7378599e-01 -5.8263088e-01 -8.8773637e-01
+1 6.4852660e-01 1 1 1.1911873e+00 -5.5917756e-01 -1.1429356e+00 1.4684664e+00 6.9799741e-01 1.1724211e+00 6.7109957e-02 -7.6166814e-01
+1 4.7555390e-01 1 1 -1.0856476e+00 1.5479740e+00 1.5202635e+00 1.6318284e-01 5.3547196e-01 8.1197393e-01 8.5291317e-02 6.3361656e-01
+1 3.5545566e-01 1 1 -1.0868708e-01 1.2705757e+00 4.9555985e-01 3.5698412e-03 -9.8577565e-01 -2.3258330e-01 9.2491276e-01 -8.0559005e-01
+1 8.1910731e-01 1 1 -1.4384647e+00 1.1597955e+00 5.1225530e-01 3.0806106e-01 8.2823258e-01 -8.8631158e-01 4.0831033e-01 7.1228729e-01
+1 5.2920763e-01 1 1 1.4212697e+00 -8.9943966e-01 1.5109404e+00 2.3754783e-01 -2.9205203e-01 1.1936542e+00 1.2333457e+00 -1.1971186e+00
+1 3.4553567e-01 1 1 -1.3909899e+00 4.6141623e-01 8.8117266e-01 -4.9786671e-01 -1.3508226e+00 -4.6497144e-01 6.1276770e-01 -1.2131822e+00
+1 4.4666849e-01 1 1 1.3656813e+00 -1.5696538e+00 4.0106901e-01 1.5569644e+00 1.0154043e+00 1.5075269e+00 6.4599036e-01 -1.0166436e+00
+1 1.2633182e+00 1 1 5.3011841e-01 -1.2183136e+00 -1.0909766e+00 -1.5654735e+00 7.6881692e-01 5.9418031e-02 -1.8424867e-01 3.9340293e-01
+1 2.8341746e-01 1 1 1.4339183e-01 7.0401555e-01 1.4325384e+00 -7.4826644e-02 1.3531541e-01 -3.8762213e-01 9.4304149e-01 -1.1295069e+00
+1 7.9670076e-01 1 1 3.8496469e-01 1.1513977e+00 -4.9380366e-01 -9.7434421e-01 -2.6700951e-01 8.9801209e-01 3.6338036e-01 1.0226874e+00
+1 3.9015975e-01 1 1 1.5622518e+00 -6.6985379e-01 7.2961007e-01 1.3193560e+00 -1.4344589e+00 6.7801537e-01 7.7535224e-02 6.5311956e-01
+1 4.1374806e-01 1 1 -6.6540076e-01 1.2353935e+00 9.2039745e-01 1.0549544e+00 -3.6813515e-01 8.4773157e-01 -6.2644727e-01 2.5565653e-01
+1 3.6680564e-01 1 1 6.7922838e-01 4.7294346e-01 -8.2204368e-02 -5.3034395e-01 -1.4516137e+00 7.0175169e-01 -1.2222588e+00 -8.7939633e-01
+1 8.7289368e-01 1 1 -7.5639518e-01 5.3139445e-01 6.9195311e-01 -7.9236852e-01 3.3713881e-01 8.0179199e-01 3.7006010e-01 1.1792646e+00
+1 5.7197826e-01 1 1 1.2917260e+00 -4.0131887e-01 -5.2004947e-01 -1.2648216e-01 -1.1410926e+00 1.4270393e+00 -7.5329485e-01 -4.0721613e-01
+1 1.0073945e+00 1 1 -1.5072646e+00 3.3138299e-02 -5.6064046e-01 1.0725637e+00 1.0796920e+00 1.3319006e+00 -8.2239717e-03 1.4488828e+00
+1 9.4270611e-01 1 1 1.2067728e+00 8.9349216e-01 -1.0477974e+00 1.2021388e-01 5.4423571e-01 1.4053646e+00 9.7838754e-03 8.8850019e-01
+1 4.6092733e-01 1 1 1.0744929e-01 1.0985409e-01 1.4382923e+00 3.9061788e-01 -1.3482886e+00 1.4688657e+00 1.0747763e+00 1.0327753e+00
+1 9.2956780e-01 1 1 -5.1563243e-01 -9.3878400e-01 -1.1766714e+00 -8.1389167e-01 -3.7825991e-01 5.9153386e-01 -3.9196403e-01 5.5518573e-01
+1 6.4659780e-01 1 1 1.4199404e+00 -1.0644341e+00 9.0410656e-03 -5.8295935e-01 1.1691497e+00 -1.2312210e+00 1.8033151e-01 4.7641130e-01
+1 5.0009059e-01 1 1 1.3998207e+00 1.4263433e+00 1.1567423e+00 8.2971684e-01 -7.6318779e-01 5.3924751e-01 -8.0529027e-01 -8.7492836e-01
+1 7.5662086e-01 1 1 -6.0030268e-01 -9.4113037e-01 1.1921219e+00 -4.7885008e-01 2.2562410e-01 -3.6183387e-01 -5.3245126e-01 8.7425841e-01
+1 6.5157098e-01 1 1 1.5085145e+00 3.4083116e-01 -1.0850782e+00 7.2701614e-01 1.6192759e-01 7.8158436e-01 1.4892073e+00 4.3220247e-01
+1 7.9295041e-01 1 1 9.5007093e-01 1.2259428e+00 3.5603124e-02 1.3064264e+00 8.9769016e-01 1.0894125e+00 3.7892777e-02 6.6470132e-01
+1 6.2304079e-01 1 1 -8.7331999e-01 -1.2849860e+00 1.4791069e+00 5.1764014e-01 1.5505519e+00 5.5446955e-01 -8.7940663e-01 1.3157784e-01
+1 1.7025546e-01 1 1 -3.6817339e-01 -1.4518924e+00 -7.3706063e-02 9.0774363e-01 6.1487359e-01 1.0059884e+00 1.0061949e+00 -2.5242004e-01
+1 1.0975521e+00 1 1 1.0473416e+00 -1.2049702e+00 -9.9030165e-01 8.7319462e-01 1.4821330e+00 -4.0474705e-01 -7.5749014e-02 -1.2735884e+00
+1 8.3611563e-01 1 1 3.2718406e-01 -1.2286700e+00 1.5803416e-01 1.4026375e+00 5.2099348e-01 -1.0355216e+00 -7.6865100e-01 -1.5290052e+00
+1 5.3528921e-01 1 1 1.1952903e+00 -5.6851599e-01 1.4342960e+00 -3.8271845e-01 7.1861747e-01 4.1120516e-01 -4.8839267e-01 2.3684387e-01
+1 8.1265355e-01 1 1 -1.2403682e+00 -1.4650657e+00 7.7200970e-01 -1.5087751e+00 1.5217025e+00 -3.7876007e-01 5.6598445e-01 2.3708779e-01
+1 7.1935227e-01 1 1 7.4126307e-01 4.4444130e-01 3.8945260e-01 9.5259822e-01 -4.5194357e-01 -9.5385392e-01 -2.4187579e-01 1.1950772e+00
+1 1.1076553e+00 1 1 -1.1480216e+00 -9.8232911e-01 -1.5491981e+00 7.6207254e-01 5.5551263e-01 1.2442572e-01 1.4429000e-02 1.4609937e+00
+1 8.6075614e-01 1 1 8.6224822e-01 -9.3595786e-01 1.4759761e-01 -1.2007067e-01 -3.1252854e-01 -1.0775585e+00 6.0557220e-01 2.3263570e-01
+1 1.1064383e+00 1 1 -3.6113513e-01 -6.8939302e-01 -1.1851997e+00 -1.1252649e+00 7.5719725e-02 7.5599153e-01 -9.0828341e-01 -1.3746144e+00
+1 3.3981051e-01 1 1 -4.1122097e-02 -4.3485502e-01 1.1882896e+00 6.0639817e-02 2.7638939e-01 1.3490323e+00 -5.2062539e-01 1.2737206e-01
+1 8.7754428e-01 1 1 1.1300863e-02 -1.2638103e+00 4.7843927e-01 1.2973920e+00 -1.1391296e+00 3.1234945e-01 -8.1537665e-01 1.3176951e+00
+1 8.0026627e-01 1 1 1.4380446e+00 -5.5136090e-01 -1.3484509e+00 -5.2807835e-01 -4.8479208e-01 5.5900049e-02 -4.0828282e-01 1.4154902e+00
+1 1.0219688e+00 1 1 9.4256234e-01 9.7575248e-01 3.4392289e-02 -4.1355315e-01 1.3907837e+00 1.7592303e-01 -7.7100678e-01 -1.1372682e+00
+1 1.0458277e+00 1 1 -1.4064764e+00 3.5827778e-01 -2.1846965e-02 -1.3849084e+00 1.4531339e+00 4.9968000e-01 7.5875189e-01 -6.1726058e-01
+1 4.6536458e-01 1 1 -1.3054339e+00 -8.5851284e-01 3.8440325e-01 -9.4840728e-02 7.9705059e-02 6.4454185e-01 6.1843331e-01 -7.5958230e-01
+1 5.9488893e-01 1 1 4.5560138e-01 3.0973853e-01 1.5509295e+00 -1.2006440e+00 1.2844539e+00 6.0348671e-01 -1.5213827e+00 1.1328891e+00
+1 4.0358833e-01 1 1 1.2311404e+00 1.5649546e-01 6.7815291e-01 -7.7468785e-01 -1.2088101e+00 -1.4015812e+00 -4.5567900e-01 -7.2626422e-01
+1 8.0013689e-01 1 1 1.2481278e+00 7.0607899e-01 1.7759728e-02 -1.4187157e+00 2.0797719e-01 -7.1404595e-01 6.0592574e-01 -1.2353612e+00
+1 9.2798311e-01 1 1 8.6984401e-01 1.2740917e+00 3.6449876e-02 3.3269594e-01 -1.1200066e+00 -8.6372999e-02 -1.2494646e+00 6.9722043e-02
+1 7.8196009e-01 1 1 -1.5039492e+00 5.6318047e-01 2.4979641e-03 -4.1421809e-01 4.7226198e-01 -2.5517997e-01 -1.3460457e+00 4.3165468e-03
+1 6.9109125e-01 1 1 3.8095939e-01 -2.4451816e-01 1.1425777e+00 5.8130710e-03 -1.4976079e+00 -5.3571152e-01 -3.8116182e-01 2.9157100e-01
+1 9.8661326e-01 1 1 2.1866953e-01 -4.1352801e-01 -1.2524999e+00 3.1091257e-01 1.4436261e-01 1.0110545e-01 -4.7933955e-01 -4.5077634e-01
+1 7.5025837e-01 1 1 -4.8468689e-01 -9.6232705e-01 1.0466607e+00 1.0390058e+00 9.9288864e-01 -3.2230923e-01 -1.2162792e+00 1.3235201e+00
+1 6.1296383e-01 1 1 1.7162913e-02 -9.1176535e-01 1.4490192e+00 -1.5426915e+00 -6.6082803e-01 -9.4551784e-01 3.3953748e-01 -1.2150618e+00
+1 5.7437858e-01 1 1 -5.6944163e-01 6.4872537e-01 3.8883126e-02 -4.5242767e-01 -1.0067011e+00 -1.1426689e+00 1.4742049e+00 -1.1920814e+00
+1 1.0433234e+00 1 1 -1.3142267e+00 -1.3407483e+00 5.7421152e-02 -1.2976703e+00 9.9242384e-01 -2.8088484e-01 -7.7957231e-01 -1.3760619e+00
+1 6.2221937e-01 1 1 3.3062262e-01 6.8775167e-01 6.0835523e-01 -1.0092608e+00 9.5213353e-01 9.8231321e-01 1.3111481e+00 9.3290862e-01
+1 9.3449240e-01 1 1 -7.0309740e-01 1.1229178e+00 -1.2577553e+00 -1.1872324e+00 -7.6471451e-01 6.6866971e-01 1.3352842e+00 -2.9380988e-01
+1 5.5099054e-01 1 1 -1.4280006e+00 1.3319384e+00 6.8436059e-01 -1.5594186e+00 -3.0114943e-01 8.5497097e-01 -1.4157586e+00 5.2107194e-01
+1 4.5281068e-01 1 1 1.3623967e+00 -1.1003768e+00 6.7769251e-01 1.1584115e+00 -3.1271708e-01 -1.4777716e-01 -2.3191861e-01 -1.1042127e+00
+1 9.5446114e-01 1 1 -1.2671401e+00 5.2242694e-01 -1.4369375e+00 9.7283993e-01 4.8530359e-02 1.3090990e+00 8.6037981e-01 -1.1147068e+00
+1 9.9568954e-01 1 1 3.3472687e-02 -3.2192415e-01 -1.1851406e+00 -1.4690346e+00 -1.1643390e+00 1.4541355e+00 -3.4754606e-01 -1.5607333e+00
+1 1.0390153e+00 1 1 2.3036535e-01 -7.5664677e-01 -9.6056770e-01 -2.8849168e-01 -6.5707581e-02 1.2066662e+00 -9.8587095e-01 1.0533792e+00
+1 7.5819697e-01 1 1 1.3082542e+00 2.0475183e-01 3.8335604e-01 -1.2021484e+00 1.4933049e+00 1.4574909e+00 -7.7345557e-01 1.2694074e+00
+1 9.0385683e-01 1 1 -1.7812258e-01 1.2200134e+00 -3.4160522e-01 -9.2640725e-01 -2.0762857e-01 1.0522326e+00 4.4266278e-01 3.7391308e-01
+1 4.5259949e-01 1 1 2.3164420e-01 -4.0964499e-01 1.4723826e+00 -3.9350019e-01 6.9608928e-01 8.4879334e-01 5.4197523e-01 1.1718541e+00
+1 8.6607985e-01 1 1 8.1077566e-01 1.4677952e+00 9.4990731e-03 -5.0520199e-01 -1.1850778e-01 -3.0249084e-01 1.5006425e+00 7.0798225e-01
+1 6.9659721e-01 1 1 -1.5224063e+00 1.4477856e+00 -5.7030419e-01 7.9509317e-01 9.4533276e-03 -8.6656534e-01 5.9242673e-01 -1.2952493e+00
+1 1.0012682e+00 1 1 1.1896764e+00 1.2980997e+00 -1.0335691e-01 -1.2043166e+00 -1.3391479e+00 5.9889043e-02 1.2088762e+00 -1.1596658e+00
+1 4.2341084e-01 1 1 -1.3453788e+00 -1.1988601e+00 1.8117895e-01 3.3285468e-01 -6.8968880e-01 1.2455048e+00 9.0344091e-01 -6.2910004e-02
+1 7.0733190e-01 1 1 1.4018941e+00 9.3362251e-01 8.7127409e-01 -8.8789589e-01 8.7727722e-01 7.6786495e-01 8.1413308e-01 1.3882797e+00
+1 7.1931584e-01 1 1 -3.1029236e-01 -8.6171851e-01 5.4025612e-01 -3.0107077e-01 9.0386734e-01 -1.5646550e-01 1.4987079e+00 2.0784288e-01
+1 6.3438673e-01 1 1 -3.9865616e-02 -1.6088952e-01 8.8176921e-01 1.0092909e+00 -1.4437032e+00 -2.0258099e-01 -5.0700048e-01 -2.3579526e-01
+1 6.9630612e-01 1 1 -8.6216615e-01 8.4107583e-01 1.0025840e+00 -1.4475184e+00 1.3412068e+00 7.0770539e-01 -1.1577375e+00 -1.4625419e+00
+1 7.7689174e-01 1 1 -1.4011858e+00 -1.2054109e+00 -1.0740115e+00 5.1343530e-02 7.3508042e-01 3.3464873e-01 9.3007893e-01 -1.1213583e+00
+1 5.2417888e-01 1 1 -3.5062990e-01 7.8924378e-01 6.8077403e-01 -1.0072641e+00 -1.3872172e+00 9.9033706e-01 -7.2842589e-01 -2.5544283e-01
+1 5.3710447e-01 1 1 5.9112835e-01 1.0160953e+00 8.8635902e-02 9.5553081e-01 -1.1998164e+00 4.3705140e-01 1.3269935e-01 1.3295604e+00
+1 7.4214424e-01 1 1 1.3782378e+00 -1.8361194e-01 5.8868101e-01 -2.1538677e-01 5.6975175e-01 4.7920548e-01 -2.5278916e-01 -2.2683576e-01
+1 2.7717254e-01 1 1 1.0797346e+00 -9.2196827e-01 1.0863917e+00 -8.9065182e-01 2.4322171e-01 -1.0371190e+00 -1.1941140e+00 1.4649178e+00
+1 5.4362871e-01 1 1 1.2603152e+00 -1.1857031e+00 4.9046372e-02 5.0383097e-01 6.1529556e-01 -1.3032070e+00 -9.8072681e-01 2.1167399e-01
+1 4.1942386e-01 1 1 1.4996967e+00 -9.8924859e-01 1.2250922e+00 1.2948329e+00 -8.5062073e-01 1.8400985e-01 8.6119043e-01 1.3218479e+00
+1 3.7269548e-01 1 1 4.0526463e-01 -9.9269929e-01 1.2572902e-01 4.4411099e-01 1.0055068e+00 1.3263959e+00 7.1025521e-01 -1.0457904e+00
+1 1.0204112e+00 1 1 3.0974232e-01 7.0168792e-01 -1.1642085e+00 -2.5080053e-01 9.2580520e-01 -5.9470070e-03 -7.9273542e-01 6.1231129e-01
+1 5.0621139e-01 1 1 2.2020106e-01 -2.7001603e-01 -1.0127148e+00 8.1285368e-01 -3.0041372e-01 5.7961770e-01 -9.7089448e-03 -7.4165736e-01
+1 7.0052074e-01 1 1 1.2302791e-01 1.4419282e+00 4.5141551e-01 -1.1547248e+00 -5.1395585e-01 -4.4416303e-01 1.8458334e-01 8.0442293e-01
+1 1.7537636e-01 1 1 5.6217475e-01 2.4112351e-01 -5.8027223e-03 1.2996575e+00 1.3238898e+00 -6.2396516e-01 1.5402435e+00 -1.4786228e+00
+1 5.5783153e-01 1 1 -1.4396106e+00 -9.1763938e-02 -1.3698226e-01 -1.5044317e-01 -1.2856848e+00 -3.4609644e-01 1.4828798e-01 -1.2160805e+00
+1 3.7314439e-01 1 1 1.0118429e+00 2.4548787e-01 5.2649166e-01 4.8373807e-01 -6.2948097e-01 1.3867218e+00 9.9302280e-01 5.3684613e-01
+1 5.0138481e-01 1 1 6.0199739e-01 1.0035524e+00 -1.1212244e+00 -2.5598285e-01 1.1974689e+00 -8.4222140e-01 -1.5475965e+00 1.1877815e-01
+1 1.0445830e+00 1 1 -1.2997322e+00 -5.0523044e-01 -1.1465386e+00 -1.4634707e+00 8.1803196e-01 8.0146709e-01 -1.2079602e+00 1.3929755e+00
+1 4.2374256e-01 1 1 -1.1050317e+00 3.1701840e-01 6.5501815e-01 -1.0239475e+00 1.0537634e+00 -8.9192892e-01 -1.2152282e+00 5.9051368e-01
+1 7.1578829e-01 1 1 8.2775696e-01 -1.2875901e-02 7.4940107e-01 1.5973985e-01 1.4429606e+00 1.0308388e+00 -8.4596235e-01 4.7230789e-01
+1 5.1857945e-01 1 1 1.1388900e+00 3.6463264e-01 5.3885508e-01 -1.3140361e+00 -1.2570280e+00 -5.7509849e-01 7.5908786e-01 -7.2591203e-01
+1 9.8722726e-01 1 1 -3.9960766e-01 -8.6642348e-01 -6.7423135e-01 3.9093103e-01 3.4132707e-01 1.0003011e+00 -1.8090079e-02 1.5424300e+00
+1 5.3112834e-01 1 1 5.1916658e-01 -6.9742743e-01 -8.1552455e-02 1.3075179e+00 1.3587862e-01 1.3989557e+00 6.9453779e-01 -8.0208416e-01
+1 8.4512184e-01 1 1 1.4299931e+00 -3.8060923e-01 -9.1771791e-01 1.3010823e-02 -2.2591205e-01 5.6975221e-01 -1.0617404e+00 -5.4373260e-02
+1 6.5979765e-01 1 1 7.1024357e-01 -6.1662269e-01 1.1350713e+00 -1.2385911e+00 1.2817465e+00 2.5094211e-01 -4.2452521e-01 3.5207986e-01
+1 2.9885760e-01 1 1 -9.8837628e-01 5.3654748e-01 1.3924976e+00 -8.0765312e-01 4.1285594e-01 1.5667755e+00 -4.3827519e-01 -1.3542765e+00
+1 6.6253373e-01 1 1 1.1018486e+00 1.3824981e+00 -1.1576325e+00 5.9581388e-01 -9.0830874e-01 -3.3583058e-02 9.4359019e-01 -4.8569643e-01
+1 1.0090896e+00 1 1 -9.1983949e-01 4.2564254e-01 -4.4612357e-01 -1.5534588e+00 -9.4620634e-01 1.0562166e+00 1.6067050e-01 -1.2422252e+00
+1 5.5078346e-01 1 1 3.5107311e-02 3.6770944e-01 9.8288278e-01 7.9497735e-01 -1.4802374e-01 -1.3081419e+00 -1.3805163e+00 9.4604271e-01
+1 8.2902677e-01 1 1 -5.7084799e-01 5.7980678e-01 8.1674636e-01 -9.2730347e-03 3.0636079e-01 -1.0758075e+00 1.4665518e+00 5.3938337e-01
+1 3.0291065e-01 1 1 1.8172028e-01 -4.0782721e-01 1.4377717e+00 1.2277389e+00 -6.4567719e-02 -1.2302092e+00 -5.9949720e-01 -1.2200319e+00
+1 1.0457028e+00 1 1 5.4466901e-01 6.0331464e-01 -5.0166482e-01 6.2712819e-01 -1.3401850e+00 -1.3039862e+00 -6.6172573e-01 9.9378301e-02
+1 9.8202585e-01 1 1 -3.4889835e-01 -1.1519180e+00 5.5405915e-01 1.0012868e-01 7.2978344e-01 -3.4612414e-01 -3.8631911e-01 -1.0761912e+00
+1 5.2759842e-01 1 1 1.4189934e+00 1.3496549e+00 3.9148720e-01 -1.0309180e+00 6.9261689e-01 9.2111280e-01 8.0678888e-01 -1.3961403e+00
+1 7.6340775e-01 1 1 1.1917595e+00 1.3512473e+00 1.2303015e+00 -7.5581012e-01 1.2112995e+00 -6.2574703e-01 5.8682968e-01 -3.7451780e-01
+1 1.0491284e+00 1 1 -8.9348597e-01 -1.6051342e-01 -2.8619923e-01 -1.4416075e+00 7.8974464e-01 1.1219522e+00 1.3871109e+00 1.2310020e+00
+1 8.8515817e-01 1 1 -5.7516138e-03 8.7895651e-01 -3.7218136e-01 -1.1353460e+00 9.2589936e-03 8.1223357e-01 -5.8691554e-01 -1.0780487e+00
+1 8.1818278e-01 1 1 7.2199840e-01 8.5340152e-01 -3.4111240e-01 2.7332240e-01 -1.4637275e+00 9.8944875e-01 3.1138150e-01 -1.1992040e+00
+1 9.9562846e-01 1 1 -1.3453743e+00 -1.3926955e+00 3.3051305e-01 7.2118880e-01 9.4464015e-01 1.2152591e+00 -5.0447213e-01 1.4368092e+00
+1 7.1737286e-01 1 1 1.4785572e+00 9.7357639e-01 5.9695834e-01 7.5562820e-01 -1.0422371e+00 1.3650487e+00 4.9545617e-01 -9.7096577e-01
+1 6.3765982e-01 1 1 1.1326794e-01 1.4838342e+00 -1.1680537e+00 1.5256018e+00 6.4146672e-01 -6.7808730e-01 -1.2302933e+00 1.5520735e+00
+1 5.8975709e-01 1 1 -1.1088256e-01 8.3837772e-01 3.3377092e-01 -8.9010198e-01 -8.1481242e-01 1.0848561e+00 4.2356828e-01 1.0557638e+00
+1 9.3393299e-01 1 1 -6.3876330e-01 5.7122865e-01 -1.1967081e+00 3.2027459e-01 -3.4994969e-01 -6.2672598e-01 6.3118874e-02 5.0695155e-01
+1 9.9342794e-01 1 1 -8.7262458e-01 -6.7299449e-02 -5.9656648e-01 1.3068487e+00 -5.4297580e-01 3.7661007e-01 -1.0194011e+00 3.3534273e-01
+1 2.2064750e-01 1 1 -1.2467913e+00 -1.2848699e-01 1.4708622e+00 1.3324538e+00 5.3233117e-01 -6.2369307e-01 1.1720701e+00 8.7992455e-02
+1 9.5523590e-01 1 1 -3.9811721e-01 -1.2067079e+00 -4.1228684e-01 1.2781622e+00 -3.6588478e-01 1.0852470e+00 1.1954944e+00 -8.0095413e-01
+1 7.6178852e-01 1 1 4.3634808e-01 9.8220909e-01 1.0484683e+00 -1.3826252e-01 -1.3287026e+00 -3.4071063e-01 -9.5260296e-01 8.8429264e-02
+1 5.2584668e-01 1 1 1.2248554e+00 -1.0812551e+00 4.1321459e-01 1.0004648e+00 -1.0635984e+00 7.9977727e-01 -8.4185821e-01 2.5732260e-01
+1 6.0323895e-01 1 1 -7.1119272e-01 1.4598604e+00 -1.1637787e+00 1.0080633e+00 -2.3565353e-01 -1.0183439e+00 6.2234057e-01 -1.1522294e+00
+1 3.5676148e-01 1 1 7.4407338e-01 3.4462658e-02 -7.2874921e-02 -8.9829830e-02 9.1942304e-01 9.1238205e-02 1.3160522e+00 -7.4188115e-01
+1 6.6622572e-01 1 1 -1.0390885e+00 1.1608496e+00 4.1233600e-01 1.3361128e+00 -7.5115391e-01 3.4329120e-01 -1.0649382e+00 1.8480343e-01
+1 8.6414335e-01 1 1 1.5250303e-01 1.1091224e+00 -2.2223786e-01 -5.5829020e-02 1.4171524e+00 -1.4105092e+00 -7.6233286e-01 -1.0438371e+00
+1 8.1303073e-01 1 1 -4.2118454e-01 -1.1910267e+00 2.0201218e-01 1.0178624e+00 -1.4743724e+00 2.9426188e-02 -1.1135912e+00 -1.1173009e+00
+1 7.0749954e-01 1 1 -8.4025329e-01 6.4248258e-01 -8.4292289e-01 1.2414777e+00 1.1065379e+00 1.3359000e+00 1.4823870e+00 -1.1762042e+00
+1 8.2468024e-01 1 1 -6.7811717e-01 5.5074349e-01 -1.5637907e+00 -9.4233802e-01 -6.4606568e-01 -4.9106862e-01 -1.4928101e+00 -1.5631548e+00
+1 6.8668199e-01 1 1 5.8288255e-01 1.2138583e+00 -6.5987981e-02 -1.1065962e+00 -1.0816266e+00 -4.2642238e-01 -9.0053187e-01 1.1964081e+00
+1 8.8408840e-01 1 1 1.0210936e+00 -1.8559186e-01 -7.7792507e-02 -3.3358928e-01 1.4979052e+00 -9.0814550e-01 9.5419449e-01 -1.3042462e+00
+1 1.0594669e+00 1 1 -1.0002178e+00 3.5909842e-01 -5.5612223e-01 1.1079193e+00 -1.4315634e+00 -1.3442783e+00 -6.8376969e-01 1.5681010e+00
+1 8.1229898e-01 1 1 1.1906025e-03 3.6766202e-01 -5.0813272e-01 5.8039178e-01 1.1726865e+00 1.0489682e+00 -1.7133025e-01 2.5305081e-01
+1 5.7504214e-01 1 1 1.1608997e+00 -2.1726315e-01 -1.3377160e+00 -5.5162179e-04 -1.0110079e+00 -6.0889043e-01 1.2929270e+00 -6.9144238e-01
+1 7.9529310e-01 1 1 -1.1912908e+00 -1.0110633e+00 1.3856931e+00 1.5367055e-01 8.6503430e-01 -1.4541871e+00 -1.7168473e-01 -3.2079824e-01
+1 6.8774537e-01 1 1 -6.5441770e-01 -6.6896772e-02 7.1808669e-01 3.5183874e-01 -6.5929335e-01 1.0683238e+00 -1.5232203e+00 -6.8300822e-01
+1 5.2482178e-01 1 1 -8.2336453e-02 3.5611969e-01 -1.1159371e+00 8.7638679e-01 -3.4609910e-01 1.1158476e+00 7.5103172e-02 6.0363531e-02
+1 5.3749869e-01 1 1 -1.5280064e+00 5.6958984e-01 -2.4744935e-01 -1.4951446e+00 1.3419730e+00 -1.2570208e+00 -6.6123349e-01 -2.0456611e-01
+1 8.6274228e-01 1 1 1.3166712e+00 6.6354514e-01 5.8751048e-01 7.0425903e-01 1.0465845e+00 4.6266522e-01 -1.5379990e+00 -1.2401791e+00
+1 9.0637959e-01 1 1 -8.6057860e-02 -4.5069744e-01 2.6296454e-01 -1.0395817e+00 1.6785059e-01 5.7251126e-01 -1.2495527e-01 7.7664000e-01
+1 1.2080387e+00 1 1 -1.2418260e+00 -4.9200762e-01 -5.7578249e-01 1.2883241e+00 -8.5293903e-02 -5.0153958e-01 -1.5393787e+00 -3.2906639e-01
+1 8.1155937e-01 1 1 1.3720088e+00 -5.0026178e-01 -1.0709175e+00 1.0073291e+00 -9.6838304e-01 -4.8256864e-01 -1.3217605e+00 -1.4157474e+00
+1 1.2100555e+00 1 1 6.1196573e-02 -9.9779922e-01 -7.2691738e-01 1.3791401e-01 9.7773070e-01 1.0610188e+00 -6.2688537e-01 -4.4317786e-02
+1 6.5044803e-01 1 1 1.2300104e+00 -1.8990637e-01 3.5348438e-01 -5.7467885e-01 -9.5126096e-01 8.6224428e-01 8.3934653e-01 -2.9156829e-01
+1 7.3783235e-01 1 1 1.1051532e+00 1.0169143e-01 2.6026637e-01 -1.3716447e+00 -2.7797835e-01 -4.2727487e-01 1.1461811e+00 4.9631195e-01
+1 4.7668525e-01 1 1 1.2135269e+00 1.0139065e-01 1.1999720e+00 -2.2527568e-01 -4.3385665e-01 4.7205673e-01 -3.8083727e-01 5.8651683e-01
+1 7.8923359e-01 1 1 5.2693077e-01 1.3293607e+00 -1.0960709e+00 -5.8928712e-01 -1.9224428e-01 1.3360580e+00 -1.3077665e+00 -7.2940587e-01
+1 8.4899198e-01 1 1 -2.4321128e-02 -4.4204393e-01 6.3614596e-01 1.2929836e+00 -1.4924478e+00 -9.7738427e-01 -1.0500483e+00 -6.2990308e-01
+1 2.4526012e-01 1 1 -3.5815195e-01 4.3427423e-01 8.6535566e-01 7.7912936e-01 -1.0948041e+00 4.9058568e-01 1.3057184e+00 3.8622046e-01
+1 7.8652981e-01 1 1 -1.6837840e-01 9.2727225e-01 -1.5414435e+00 6.6899966e-01 -6.5111856e-02 -1.4071400e+00 1.1842912e+00 6.7688455e-01
+1 8.7045863e-01 1 1 6.3928200e-01 -7.7645634e-01 -1.4681320e+00 1.1724639e-01 -1.0607137e+00 1.0822745e-01 -7.4840268e-01 6.9162733e-01
+1 1.0599020e+00 1 1 1.6567911e-01 2.7413429e-01 -8.2599002e-01 7.8154800e-01 1.1227552e+00 -3.3487855e-03 5.3317806e-01 2.8774881e-01
+1 3.5579773e-01 1 1 1.1177615e+00 -1.3413592e+00 2.8374093e-01 4.7839443e-01 -1.4009606e+00 2.6562943e-01 1.3014839e+00 1.2831063e+00
+1 9.7245629e-01 1 1 -5.0579839e-01 -1.5503813e-01 -1.0387249e-01 1.0396158e+00 2.9232291e-01 2.3059710e-01 -8.6902287e-01 1.2756924e+00
+1 7.0991831e-01 1 1 1.9613527e-01 -1.3454794e+00 9.4056905e-01 -7.1517043e-01 -3.7973574e-01 -1.0797921e+00 -4.0305979e-01 -8.0850658e-01
+1 9.2286360e-01 1 1 9.1478127e-01 -2.8828359e-01 -3.5026023e-01 -1.3591603e-01 1.4976441e+00 9.1494881e-01 -9.5218356e-01 -1.1818041e+00
+1 7.8973549e-01 1 1 -2.2557118e-01 -8.4635028e-01 5.2102176e-01 -4.0285806e-01 4.6478686e-01 -5.5140575e-01 -7.6120754e-02 -1.4333325e+00
+1 3.9870689e-01 1 1 7.2756587e-01 5.2229622e-01 1.1940614e+00 -7.0324166e-01 -1.4682077e+00 2.2188237e-01 -7.3331081e-01 -2.8736630e-01
+1 1.0122799e+00 1 1 1.1209768e+00 6.2264893e-01 9.6077043e-02 -7.1100720e-01 1.0436543e+00 1.0656628e-01 -2.8672527e-01 -1.1374596e+00
+1 5.8932267e-01 1 1 1.2624505e-01 2.1537041e-01 -1.1758415e-02 7.2036711e-01 1.1858297e+00 3.5167947e-01 2.1155733e-01 -6.9303438e-01
+1 7.2696079e-01 1 1 1.2255424e+00 6.1576621e-01 2.9664855e-01 -4.8812655e-01 -2.3849193e-02 1.3411394e+00 -6.3888808e-01 1.1967896e+00
+1 1.0094099e+00 1 1 1.4092251e+00 7.7645776e-01 6.4681983e-02 -1.2445562e+00 1.2904650e+00 -3.9726144e-01 1.7172362e-01 -1.1744091e+00
+1 4.9099114e-01 1 1 3.7902190e-01 -2.5026006e-01 1.1902980e-01 -5.3246264e-01 -7.1068198e-01 -8.8863116e-01 -9.6484288e-01 3.3241215e-01
+1 6.5391954e-01 1 1 -9.2885037e-01 4.7174211e-01 -6.6061029e-01 1.2979429e+00 -9.6700567e-02 -9.2431241e-02 7.8697764e-01 1.0993084e+00
+1 8.1982494e-01 1 1 -6.1421530e-01 -8.1016013e-01 -4.8872537e-01 -6.9238289e-01 -1.0430228e+00 -1.5450918e+00 6.2813349e-01 3.7028776e-01
+1 5.3202086e-01 1 1 1.5686618e-01 -6.9882375e-01 1.2575341e+00 -4.2011004e-01 3.2962872e-03 4.7337819e-02 1.2882629e+00 -6.8740394e-02
+1 3.4463239e-01 1 1 6.5367523e-01 1.2841293e+00 -1.2590592e+00 1.5108093e+00 -1.1479680e+00 7.8378811e-01 -2.2164206e-02 7.8629078e-01
+1 5.0466505e-01 1 1 1.7008041e-01 -3.8085029e-01 7.6095437e-01 -1.3208873e+00 -1.3774836e+00 4.2877672e-01 1.3357174e+00 -1.4912271e+00
+1 9.8336231e-01 1 1 -3.0790760e-01 -1.5265932e+00 -6.3593418e-02 1.4822673e+00 -9.7038705e-01 -3.6319293e-01 -4.1899920e-01 5.7299885e-01
+1 5.4155024e-01 1 1 -8.0001024e-01 -6.4576158e-02 -6.7307952e-01 -3.6294741e-01 -1.2876492e+00 -6.9056766e-02 1.3311499e+00 1.4102103e+00
+1 9.1271082e-01 1 1 2.4453765e-01 -1.4820289e+00 4.2764948e-01 9.1585571e-01 9.1243201e-01 -1.3893829e+00 1.3549527e+00 1.2289337e+00
+1 1.0980704e+00 1 1 7.4105496e-01 1.2277265e+00 -4.5918130e-01 -1.0170355e+00 1.1310113e+00 9.9670342e-02 -7.1523591e-01 -1.2829625e+00
+1 6.7771886e-01 1 1 -1.5042132e+00 4.1897241e-01 1.4329726e+00 8.9709340e-02 -8.7027952e-01 6.9054713e-01 -1.2363928e+00 1.1417520e+00
+1 8.6153896e-01 1 1 -9.1508033e-01 1.3601762e+00 5.2139618e-01 -2.1960102e-01 4.6755510e-01 9.8238850e-01 -1.5599748e+00 5.7875570e-01
+1 5.3632275e-01 1 1 1.4825542e+00 -8.8847100e-01 1.2036175e+00 5.3698016e-01 1.0753113e+00 -1.2074656e+00 1.2350871e+00 7.7617281e-01
+1 2.5170142e-01 1 1 1.3167766e+00 -5.4223480e-01 4.8503267e-01 -7.7015395e-01 -8.2564664e-01 8.1375375e-01 -1.5360040e+00 1.2436458e+00
+1 9.7951005e-01 1 1 -1.4564332e+00 4.1999995e-01 -4.8885329e-01 -6.1572151e-01 -2.2837091e-01 1.4064401e+00 -1.1520601e+00 9.3940260e-01
+1 1.0565131e+00 1 1 1.0175517e+00 -2.1948207e-01 -8.9240082e-01 -2.5193906e-02 7.9637409e-01 6.9645654e-01 -1.0387273e+00 -1.1051381e+00
+1 1.1452186e+00 1 1 -8.3904325e-01 -6.0544663e-01 -6.1733553e-01 6.8102492e-01 1.4746868e+00 -2.2920794e-01 -5.9963818e-02 -9.6035183e-01
+1 5.3417126e-01 1 1 8.0953494e-01 -1.2293518e-01 1.1223065e+00 1.1638328e+00 1.0372707e+00 -7.0530106e-01 6.3935899e-01 8.6983550e-01
+1 6.5168362e-01 1 1 -3.8398692e-01 9.9636275e-01 4.8246088e-01 9.8225947e-01 7.1087107e-01 -7.6579117e-01 1.4596331e+00 1.4945948e+00
+1 9.8902655e-01 1 1 -8.3677614e-01 1.1798474e+00 2.6937767e-01 -2.3442050e-01 1.3313474e-01 4.5296685e-01 -6.4411710e-01 -5.2021091e-01
+1 8.1218058e-01 1 1 1.2137244e+00 -3.7436124e-02 3.9556843e-01 -3.4812864e-01 7.8166251e-01 9.3492199e-01 2.5224014e-01 -1.3244910e-01
+1 4.7995380e-01 1 1 7.0434831e-01 -8.7040765e-01 7.0859138e-01 -1.3525284e+00 -7.3867929e-01 -1.0125904e+00 1.3914885e+00 1.3171185e+00
+1 1.0984401e+00 1 1 4.6100360e-01 1.4556968e+00 -4.8248057e-01 6.2000467e-01 5.9128332e-01 -5.9976795e-01 7.3069428e-01 1.1488046e+00
+1 9.1857018e-01 1 1 9.1996664e-01 -8.2735261e-01 -6.0022390e-01 -2.4430417e-01 8.4112485e-01 1.0709717e+00 2.9310228e-01 -2.6956422e-01
+1 1.0171790e+00 1 1 -1.0396733e+00 -6.2627844e-01 -3.0910318e-01 4.1405989e-02 -3.8166384e-01 -1.5051678e+00 1.5270945e-01 -3.8926994e-01
+1 3.1439780e-01 1 1 -2.5101070e-01 -1.5263337e+00 1.0971475e+00 -1.5231063e+00 5.0812201e-01 -1.2509708e+00 -9.3391279e-02 1.4775467e+00
+1 1.1375280e+00 1 1 4.2204326e-01 1.1553906e+00 -1.3904589e+00 -1.1501827e+00 1.1578110e+00 -1.5279828e+00 1.1690966e+00 -1.1633067e+00
+1 6.0995053e-01 1 1 -4.3513343e-01 4.6505637e-01 8.6428539e-01 -9.0103097e-01 3.0449678e-01 -1.4292140e+00 1.4864035e+00 -1.5639328e+00
+1 8.9073592e-01 1 1 3.4012361e-01 -8.0088665e-02 -6.7990547e-01 -1.1509342e+00 2.2881494e-02 -1.8293711e-01 3.8963087e-02 6.8668150e-01
+1 6.2904360e-01 1 1 -1.2410570e+00 -1.4485410e+00 -1.1987962e+00 -9.6491667e-01 1.2949599e+00 9.9516204e-01 1.4013364e+00 -1.1554649e+00
+1 1.0400819e+00 1 1 -1.4121017e+00 -1.4263795e+00 -1.1342197e+00 -4.5327773e-01 -5.6269246e-01 -1.5096255e-01 -2.5884336e-01 1.4271345e+00
+1 6.1265590e-01 1 1 1.5398100e+00 3.3367742e-01 3.5327988e-01 1.2344510e-01 -9.7821893e-01 1.1793488e+00 7.2555059e-01 -2.1115110e-01
+1 9.4385057e-01 1 1 -8.5375768e-01 3.7358628e-01 -3.5145456e-02 1.2905642e+00 -9.7125810e-01 1.0074121e+00 -1.3339217e+00 1.1832418e+00
+1 5.9198713e-01 1 1 -1.4516534e+00 -1.1791022e+00 -7.0264919e-02 9.5611325e-01 -2.1945931e-01 1.5325774e+00 -8.1635561e-01 4.6362682e-01
+1 7.6981687e-01 1 1 -3.3045458e-01 -3.5674406e-03 2.9634897e-01 1.4895945e-01 -2.2279504e-01 1.1005277e-01 -1.1536742e+00 1.0261010e+00
+1 6.2631384e-01 1 1 3.8564708e-01 -2.6771336e-01 1.3127152e+00 -2.8779356e-01 2.6221425e-01 -7.4115572e-01 1.0818294e-01 1.4766445e+00
+1 6.4977063e-01 1 1 4.6485643e-01 -6.9775866e-01 -6.0045924e-01 1.1062882e+00 -6.1958040e-01 -1.8935756e-01 -7.5146547e-01 -6.1843214e-01
+1 8.0823102e-01 1 1 -2.9891117e-01 3.3555231e-01 -1.1227899e+00 1.4400490e+00 1.0918926e+00 -9.9174382e-02 -6.7772749e-01 1.5411016e+00
+1 4.4784633e-01 1 1 -3.9333933e-01 4.6894338e-01 8.1639838e-01 7.4561692e-02 1.3967507e+00 1.3618664e+00 8.4905597e-01 -1.1361469e+00
+1 1.3030297e+00 1 1 -9.4320366e-01 -7.2463257e-01 -1.2690852e+00 -3.3711172e-01 1.2087512e+00 -7.5470445e-01 9.6989594e-01 -6.2016218e-01
+1 5.6124985e-01 1 1 5.2566540e-02 1.0550814e+00 -1.2430074e+00 -1.5451931e+00 -1.1978113e+00 1.4334589e+00 -6.8328223e-01 7.3865985e-01
+1 9.9044344e-01 1 1 6.9830496e-01 -1.5382538e+00 3.6567693e-01 1.4862378e+00 -2.8829106e-01 -7.3089481e-01 -1.4032876e+00 -9.1802347e-01
+1 8.5699354e-01 1 1 -5.7865904e-01 -1.2659477e+00 9.7698591e-01 3.9622018e-01 -9.7196662e-01 -5.2178427e-01 -1.1181249e+00 -8.5892710e-01
+1 9.7730253e-01 1 1 8.4833233e-01 1.2239631e+00 -9.0261076e-01 -9.0378424e-01 4.3885670e-01 -1.4431876e+00 6.8229407e-01 -3.6957469e-01
+1 5.1722555e-01 1 1 1.3739305e+00 -4.5251348e-04 5.7190817e-01 -3.0125904e-01 -5.9500441e-01 5.8368531e-01 5.0329151e-01 -5.1315839e-01
+1 1.1216166e+00 1 1 9.4317401e-01 -1.3222087e+00 -1.2129842e+00 9.8665022e-01 -5.4968279e-01 -1.1948051e+00 -1.4886338e+00 -9.8130994e-01
+1 1.0427658e+00 1 1 -5.5090121e-01 1.2645761e+00 -8.3081721e-01 1.3041797e+00 9.0537098e-01 -2.9650247e-02 1.7541388e-01 4.8521444e-01
+1 5.4714763e-01 1 1 -7.2309240e-01 8.5679188e-01 8.3450517e-01 4.5555791e-01 -1.3047938e+00 1.1815245e+00 1.3671803e+00 -5.7550295e-01
+1 5.7743790e-01 1 1 -1.3335349e+00 -9.5954259e-01 1.4587193e+00 5.0045612e-01 -1.3527839e+00 -1.2497954e-01 5.9059448e-01 4.8562424e-01
+1 8.1432745e-01 1 1 -5.9975011e-01 -1.2371417e+00 -2.9362949e-01 1.1225017e+00 -5.3306011e-01 1.1944096e+00 -1.3113793e+00 2.8819114e-02
+1 8.9058367e-01 1 1 1.3706658e+00 1.5616450e+00 4.1123648e-01 6.2176817e-01 6.8103634e-01 -3.3452801e-01 1.0615397e+00 5.5757803e-01
+1 3.8984595e-01 1 1 -5.1839455e-01 -1.4397888e+00 1.4772701e-01 1.1204729e+00 1.3557610e+00 1.0385548e+00 1.9385165e-01 -1.5691221e-01
+1 2.0685701e-01 1 1 -1.0207793e+00 1.1580429e+00 9.8971596e-01 1.0822841e+00 3.0359455e-01 3.0185747e-01 2.3302622e-01 -1.4272643e+00
+1 7.6379805e-01 1 1 2.7008759e-04 1.0603051e+00 -5.7689034e-01 1.2725138e-01 5.6714133e-01 -3.5361437e-01 -1.0942788e+00 1.1700340e+00
+1 8.1810243e-01 1 1 1.3977695e+00 1.4347507e+00 -8.4107550e-01 -7.1058205e-01 3.5222596e-01 6.9652657e-01 -6.5969352e-01 1.5323364e+00
+1 6.7179924e-01 1 1 -5.1744713e-01 -1.0095959e+00 1.2110660e+00 -1.5588356e+00 1.1012290e+00 9.4788274e-01 -7.8858780e-01 -7.9937681e-01
+1 8.6785207e-01 1 1 -8.0551393e-01 -5.3642377e-01 7.7508552e-03 1.5335761e+00 1.2338985e+00 4.8899727e-02 5.8427726e-01 1.4657746e+00
+1 4.4790287e-01 1 1 -1.1498825e+00 6.9657641e-01 1.4633253e+00 1.1881098e+00 4.7912347e-01 -1.2395598e+00 -6.7076463e-01 -1.0956762e+00
+1 6.1129229e-01 1 1 1.0030764e+00 -1.3560956e+00 -1.4200758e+00 5.9847844e-01 7.2620996e-01 -1.3804173e+00 -1.5067337e+00 9.8660453e-01
+1 9.3654357e-01 1 1 9.1853213e-01 3.5623757e-01 -5.3427112e-01 -7.5256214e-01 3.2334584e-01 -1.1564887e-02 7.0505718e-01 5.3624564e-01
+1 8.6438091e-01 1 1 -1.6785344e-02 -5.9078566e-01 -8.2299089e-01 -2.5981745e-01 -4.8182233e-01 4.0768049e-01 -1.9148523e-01 -5.4892574e-01
+1 7.7318092e-01 1 1 6.3205709e-01 1.2398100e+00 4.2458416e-01 6.1838138e-02 1.0380131e+00 7.2396702e-02 -1.3013476e+00 1.0627129e+00
+1 2.9753182e-01 1 1 1.2587940e+00 -6.9807539e-01 1.4290190e+00 -5.5359092e-01 6.2155353e-01 9.7501283e-01 1.8717360e-02 1.0610196e+00
+1 8.6185609e-01 1 1 1.0655680e+00 1.2954966e+00 4.6555707e-02 1.1947764e+00 6.5454843e-01 4.9330304e-01 4.2340808e-01 8.7584104e-01
+1 6.5214371e-01 1 1 -1.2179912e+00 -9.6765714e-01 2.0519262e-01 -4.5260435e-01 -8.6201534e-01 2.8118480e-01 5.1228316e-01 -1.2428422e+00
+1 1.2607516e+00 1 1 -1.5974334e-01 6.1156057e-01 -7.9640056e-01 -1.1255308e+00 1.1335399e+00 9.1761431e-01 -1.1623141e+00 1.0991635e-05
+1 5.4910437e-01 1 1 1.2554201e+00 -7.9268392e-01 1.2221222e+00 -1.2660848e+00 7.8699568e-01 2.6534967e-01 -5.8975699e-01 1.8473641e-01
+1 3.2558402e-01 1 1 9.0941522e-01 8.5573817e-01 4.7513125e-01 -1.0803307e+00 9.3126987e-01 -1.3296819e+00 -3.2094070e-01 9.7129001e-01
+1 5.4048222e-01 1 1 6.9339979e-01 1.8020035e-01 -3.9758676e-01 1.2877042e+00 4.3811656e-01 1.3257185e+00 6.4227472e-02 7.5583047e-01
+1 7.3897239e-01 1 1 -1.3384943e+00 1.3198039e-01 -7.3087897e-02 1.2368760e-02 -4.6821588e-01 1.1757827e+00 -1.2367528e+00 -1.3579025e+00
+1 7.3492257e-01 1 1 8.7072948e-01 2.2994919e-01 -2.5559026e-02 5.3662597e-01 3.8531173e-01 7.6169206e-01 -1.3276415e+00 1.4031556e+00
+1 5.8171058e-01 1 1 8.1173655e-01 5.9714967e-01 8.2764708e-01 -4.3981576e-01 1.1118048e+00 -2.3159020e-01 1.0621466e+00 -1.1000397e+00
+1 9.8487251e-01 1 1 -1.0807660e+00 -1.0939518e+00 -7.0785940e-01 1.8404903e-01 -8.9452422e-02 9.6764847e-02 9.6792004e-01 -9.5115087e-02
+1 8.1239115e-01 1 1 2.5445729e-01 -1.4484613e+00 2.1844593e-01 -1.1566761e+00 1.3960237e+00 -1.0182055e+00 6.6530109e-01 4.7139657e-01
+1 1.2275110e+00 1 1 9.5604739e-01 -8.6865325e-02 -1.1011100e+00 -7.9523615e-02 1.5564317e+00 -7.2457137e-01 7.8708645e-01 -3.3443745e-01
+1 3.5282982e-01 1 1 -9.5791000e-01 8.9507387e-01 7.6583286e-01 -1.3765127e+00 -1.0938036e+00 -1.0578785e+00 -6.8475680e-01 -5.8096326e-01
+1 4.3792295e-01 1 1 1.0689138e+00 1.5609612e+00 2.4779476e-01 -3.6096328e-01 1.0435071e+00 -1.4914291e+00 -1.0536972e+00 -1.7951305e-01
+1 6.9696451e-01 1 1 -1.5338893e+00 -3.6484159e-01 -1.0652985e+00 -2.9435048e-01 -1.2872557e+00 3.1822977e-01 -3.3178834e-01 -1.1469592e+00
+1 6.5541767e-01 1 1 -1.6731205e-01 4.9624178e-01 -5.3531036e-01 8.5992147e-01 1.2425815e+00 1.4970277e+00 -3.9634372e-02 -1.3154472e-01
+1 7.9868313e-01 1 1 -2.8827285e-01 -5.9295882e-01 5.6021514e-01 1.3740175e+00 -1.2408031e+00 -4.7123784e-01 -1.1724996e-01 8.0912488e-01
+1 1.0288878e+00 1 1 -6.6587977e-01 -7.2700260e-01 1.8262900e-01 -7.3631239e-01 -2.8615664e-01 -1.3933869e-01 -8.4144258e-01 -9.9275928e-01
+1 1.2037622e+00 1 1 -1.0881942e+00 -1.0788713e+00 1.0957663e-01 -4.6887510e-01 3.4372601e-01 -1.3788732e+00 1.3247167e+00 -3.0661120e-01
+1 6.9692425e-01 1 1 1.0721006e+00 6.8316851e-01 6.8110702e-01 -1.2694479e+00 -3.8579413e-01 8.0745287e-01 4.5600651e-02 -1.0024908e+00
+1 1.1039118e+00 1 1 -1.3806582e+00 -5.0795424e-01 -5.9794716e-01 -1.0547344e+00 2.0537195e-01 -8.1994723e-01 -1.3846742e-01 -5.0164293e-01
+1 3.4389119e-01 1 1 -9.1883079e-01 -1.4796133e+00 2.5696879e-01 1.0858399e+00 -9.2391426e-01 1.3138145e+00 6.9829148e-01 9.2203214e-01
+1 9.1682464e-01 1 1 1.2804561e+00 9.8743042e-01 -8.1537555e-01 1.9877067e-01 6.6554228e-01 -9.7389091e-01 -8.0532903e-01 -8.8231128e-01
+1 9.9779948e-01 1 1 7.1572632e-01 -1.2909039e+00 -3.8974402e-01 1.2256537e+00 -1.4423966e+00 -4.8681231e-01 -1.1838662e+00 -6.8842006e-01
+1 6.5963418e-01 1 1 5.3978819e-02 -3.8270536e-01 -2.0711521e-01 1.3926416e-01 1.3105666e+00 -1.1471951e+00 -1.5335046e+00 2.0977772e-01
+1 1.1253719e+00 1 1 -6.9826025e-01 -1.2888912e+00 -1.0074722e-01 1.2615207e-01 9.8667386e-01 -9.5403373e-01 1.4625403e-02 8.6709875e-01
+1 7.0403093e-01 1 1 1.3301934e+00 -1.1131894e+00 5.9856476e-02 -3.3717496e-01 -1.4399845e+00 2.4397315e-01 7.6491811e-01 -5.1960957e-01
+1 4.1683593e-01 1 1 9.8645952e-01 -1.1907528e+00 6.9814316e-01 5.3354131e-01 1.0110152e+00 6.7834529e-01 5.8148927e-01 5.4956457e-01
+1 7.8557309e-01 1 1 1.2407487e+00 -1.0370080e+00 -1.5651615e-01 1.1233655e+00 -7.4227009e-01 1.0958901e-01 -4.0461903e-01 2.4934945e-01
+1 8.0613979e-01 1 1 -6.2922721e-01 5.6304012e-01 -1.0539642e+00 -5.6783359e-01 -6.9002597e-02 8.8921362e-01 1.1161099e+00 -6.8465649e-02
+1 2.3976686e-01 1 1 -8.2078493e-01 5.3817237e-01 1.4648605e+00 5.7935290e-01 -4.7896569e-01 4.5712168e-01 8.5799260e-03 -8.7925880e-01
+1 1.1576779e+00 1 1 -1.9899865e-01 4.1775482e-01 -7.5074529e-01 1.3884816e+00 -1.2159678e+00 -1.4914938e+00 -3.1044524e-01 3.4924363e-01
+1 7.8095409e-01 1 1 1.2259015e+00 -2.5424785e-01 -1.1400338e+00 4.5978442e-01 -7.1101085e-01 -7.6914199e-01 5.3225958e-01 1.2425984e+00
+1 9.2311169e-01 1 1 1.1618935e+00 -5.7767813e-01 2.5094757e-02 -7.2111000e-01 6.5907106e-01 6.8435851e-01 -1.5690626e+00 -9.5642683e-01
+1 7.7500269e-01 1 1 -1.9589615e-01 -1.5150696e+00 7.9416590e-01 5.6871561e-01 -2.4844138e-01 6.4285236e-01 -7.0560784e-01 8.6384743e-01
+1 9.7651878e-01 1 1 -3.7487250e-02 -1.1658757e+00 -1.0808678e+00 -1.4631383e+00 -3.7769100e-01 4.8243177e-01 3.6129732e-01 1.3840849e+00
+1 1.2377450e+00 1 1 1.4119093e+00 -7.5888772e-01 -1.4557345e+00 1.4225058e+00 1.3060637e+00 -2.1985971e-01 -3.7452975e-01 -1.1792793e+00
+1 8.6360925e-01 1 1 1.5102976e+00 2.4033021e-01 1.9455019e-01 5.3441389e-01 7.0505256e-01 -6.6914394e-01 1.0301241e+00 1.6097468e-01
+1 9.6224466e-01 1 1 -4.9685729e-01 -8.5830448e-01 -5.9282740e-01 8.0820171e-02 -2.6905805e-01 5.9957485e-01 -2.1622577e-02 5.9017340e-01
+1 5.8045976e-01 1 1 -3.2723168e-01 6.7010991e-01 1.4817943e+00 1.1765892e+00 -1.3067562e+00 -1.1746520e+00 1.0141035e+00 1.0363480e+00
+1 5.8962941e-01 1 1 1.1458639e+00 -7.2321719e-02 1.1114403e+00 -1.3907470e+00 2.2357583e-01 -6.0804655e-01 8.9778157e-01 9.1164682e-01
+1 9.3854657e-01 1 1 5.7217339e-01 2.8523199e-01 6.7791430e-02 -8.3486253e-01 2.9408059e-01 1.6248269e-01 -5.4656368e-02 5.0075796e-01
+1 1.1534166e+00 1 1 1.0299579e-01 -1.7641352e-01 -1.0275694e+00 -1.1817109e+00 8.8728240e-01 8.0254959e-01 -1.2645286e+00 -8.7642591e-02
+1 9.8488633e-01 1 1 3.2615613e-02 6.8138168e-01 -1.0247957e+00 1.3376134e-01 -5.8499261e-01 -1.5479666e+00 -5.7976258e-02 3.9793599e-01
+1 9.7100924e-01 1 1 1.5334865e+00 8.7674362e-01 -1.5305442e+00 -1.2535157e+00 1.2142581e+00 -1.1459674e+00 -5.1323924e-01 -3.4062571e-01
+1 6.1521878e-01 1 1 -3.1842564e-01 1.3604899e+00 -4.9577423e-01 -3.1808383e-01 2.5025827e-01 8.3043583e-01 8.0144297e-01 -9.1445093e-01
+1 9.3917607e-01 1 1 1.4941688e+00 1.2418884e+00 -9.7382786e-01 9.5569944e-01 -5.0176316e-01 -9.6109669e-01 -1.2973237e+00 -5.0558860e-01
+1 6.6346603e-01 1 1 -1.3962960e+00 -3.2402580e-01 5.7287419e-01 -5.2278089e-01 -1.0987951e+00 9.1733010e-01 -1.4668872e+00 5.8060217e-01
+1 7.9303352e-01 1 1 1.5005563e-01 -1.5215847e+00 -6.8496886e-01 6.5619630e-01 -1.1675914e+00 -1.3697484e+00 1.2452900e+00 3.9389771e-01
+1 6.2646257e-01 1 1 -7.1394033e-01 -7.0961212e-01 -1.4762252e+00 -1.4405172e+00 -1.3212349e+00 2.2920299e-01 2.9854740e-01 9.0306480e-01
+1 5.2751903e-01 1 1 -1.4527898e+00 -9.6512304e-01 1.3813421e+00 1.4813082e+00 -1.2175823e+00 6.2209776e-01 5.6263094e-01 7.7600653e-01
+1 9.1899381e-01 1 1 -5.7949868e-01 -7.8011208e-01 -1.5365768e-01 -7.7412407e-01 4.2965426e-01 3.7662614e-01 -5.5626350e-02 -1.5508934e+00
+1 1.0462531e+00 1 1 -6.9700981e-01 -1.4775803e+00 -1.3554458e-01 -1.3680538e+00 -1.3223628e+00 -3.5372491e-01 1.2825402e+00 -7.1953909e-02
+1 2.3563502e-01 1 1 3.5518094e-01 5.9821757e-01 -4.4309112e-01 4.3572326e-01 -1.3259872e+00 -1.1612625e+00 1.1852237e+00 1.8382581e-01
+1 9.5516162e-01 1 1 5.0007780e-01 1.1461485e+00 -1.4578917e+00 1.4833912e-01 5.9153358e-01 1.3759740e+00 -7.8486175e-01 1.3748124e+00
+1 7.7280273e-01 1 1 1.0471746e+00 -9.2896115e-01 -1.5047038e+00 -1.2890237e+00 -1.2358680e+00 7.3207130e-01 3.7616144e-01 5.7200379e-02
+1 1.5327431e-01 1 1 6.6137830e-01 6.6543301e-01 2.6482575e-01 -1.9817026e-01 9.7705371e-01 1.4455029e+00 1.2608840e+00 3.9410085e-02
+1 9.8698491e-01 1 1 8.3027505e-01 -1.3725131e-01 -7.1039007e-01 -5.5935132e-01 2.3693517e-01 6.3117080e-01 -1.5066538e+00 -5.1075380e-01
+1 9.4536982e-01 1 1 -5.2186566e-01 -8.5378403e-01 -1.4738907e+00 -1.3724275e+00 -1.3700137e+00 -1.0707835e+00 -1.0939479e+00 -1.4079037e+00
+1 5.5975983e-01 1 1 3.3061560e-01 1.2470488e+00 -2.2300627e-01 -8.1500921e-01 -1.0877359e+00 1.5255957e+00 -1.3823953e+00 -1.6224045e-01
+1 1.0495504e+00 1 1 -8.2109168e-01 -1.5562344e+00 -1.4637276e-01 -5.1578664e-01 -6.4965961e-01 -9.9304885e-01 1.3018341e+00 1.2726283e-01
+1 1.1743955e+00 1 1 9.2867993e-01 1.2694754e+00 -2.1986859e-01 -1.1718769e+00 1.3470634e+00 1.1096973e+00 -1.2679104e+00 -5.1813753e-01
+1 8.8076504e-01 1 1 8.9134251e-01 1.5178355e+00 -8.1843780e-01 -1.0910272e+00 -1.3642884e+00 -9.5347701e-01 -3.4628560e-01 1.5731534e-01
+1 4.7264134e-01 1 1 -1.4618657e+00 5.2969173e-01 1.5500650e+00 5.8147480e-01 8.9020962e-01 1.7602609e-01 1.3491075e+00 -1.2220504e+00
+1 4.5408853e-01 1 1 8.1895774e-01 -7.4464268e-01 -1.2862300e+00 -6.4773790e-01 1.4889055e+00 -9.0971531e-01 -1.5667364e+00 7.3126745e-01
+1 1.0847410e+00 1 1 9.0538306e-01 8.9565889e-01 -3.6803214e-01 -9.1225680e-01 1.2489222e+00 5.4624919e-01 6.9158742e-01 5.0161442e-01
+1 9.2031413e-01 1 1 -1.1017030e+00 -1.1731100e+00 2.7977227e-01 -1.3279348e+00 -1.4869644e+00 1.0764659e+00 -3.8301635e-01 -1.4011396e+00
+1 9.3878333e-01 1 1 2.2470421e-01 1.7630316e-01 -8.3164215e-01 -7.2672027e-01 -4.0352115e-02 -2.6921257e-01 -2.3239276e-01 4.2571297e-01
+1 6.0663070e-01 1 1 4.0929621e-01 6.0529859e-01 -4.6383331e-01 5.2458300e-01 3.8601876e-01 -7.6229163e-01 -8.2538849e-01 1.5513895e+00
+1 7.5689340e-01 1 1 -1.0465579e+00 7.7632129e-01 -1.3550744e+00 1.3575371e+00 4.2848357e-01 -4.2052536e-01 9.6885260e-01 -1.0155041e+00
+1 1.0966937e+00 1 1 2.7939174e-01 5.9761131e-01 -1.3302769e+00 -1.2621885e+00 9.9297510e-01 8.1376870e-01 6.3088276e-01 6.9619478e-01
+1 6.8413027e-01 1 1 -9.4399765e-01 3.8152158e-01 7.5024144e-01 -1.5686471e+00 7.9227928e-01 -1.4839444e+00 3.7131699e-01 -1.4869407e+00
+1 8.8168397e-01 1 1 -7.2553001e-01 2.4258049e-01 -1.0449543e+00 -6.5264557e-03 -1.3733901e+00 4.5009742e-01 1.5216415e+00 3.5712560e-01
+1 8.3440969e-01 1 1 -1.4618511e+00 -7.3701611e-01 -1.0436863e+00 2.6560161e-01 -1.2866705e+00 -1.6770540e-01 -1.4778226e+00 -1.3736403e+00
+1 5.7912533e-01 1 1 1.0645108e+00 2.6998878e-01 1.4180395e+00 -2.3695431e-01 -1.4895227e+00 -6.1608654e-01 -3.3252917e-01 7.9177296e-01
+1 5.1805986e-01 1 1 -1.3797069e-01 1.2416775e+00 8.6759713e-01 1.0483877e+00 9.4346700e-01 1.2285431e-01 7.5573556e-02 -4.5833806e-01
+1 9.2715013e-01 1 1 -3.7802846e-01 -7.2612177e-01 -1.5681705e+00 -9.4112568e-01 1.2316713e+00 7.8599677e-01 9.6132095e-01 -1.0257195e-01
+1 1.2050781e+00 1 1 -1.2239862e+00 1.1588482e+00 -1.4205279e+00 4.1963334e-01 7.4542874e-01 -1.4941799e-01 -2.8976892e-01 8.0752291e-01
+1 6.7499301e-01 1 1 -3.8741158e-01 -1.1125905e+00 1.2921325e+00 -9.7889755e-02 -2.5065319e-01 -1.1357024e+00 -6.7759929e-01 3.5721721e-01
+1 8.7129102e-01 1 1 1.2951660e+00 -5.4906223e-01 -9.5944408e-01 9.6143381e-01 1.4754275e-01 5.6695181e-01 -1.3785637e-01 1.6613711e-01
+1 9.5392410e-01 1 1 -2.4028381e-01 -1.2313280e+00 4.1844176e-01 -1.5346017e+00 1.0343214e+00 3.0856313e-01 1.5433187e+00 -6.0943245e-01
+1 1.0053026e+00 1 1 -1.5034293e+00 -1.2597043e+00 -1.2753244e+00 4.2550348e-01 1.4077897e+00 -7.4890565e-01 1.5686278e+00 -1.1391134e+00
+1 1.7646626e-01 1 1 -3.0705388e-01 -6.5653814e-01 7.1022298e-01 1.1721105e+00 1.3870100e+00 1.5044366e+00 -3.1736158e-01 -2.1406172e-01
+1 6.7917740e-01 1 1 9.8215643e-01 -1.1630732e+00 -1.3343928e+00 -1.2659654e+00 8.5931148e-01 1.5286022e+00 5.2833160e-01 -6.1171376e-01
+1 5.3222589e-01 1 1 1.1752453e+00 -7.8157023e-01 6.8938089e-01 9.2699815e-01 5.4666846e-01 -7.2784324e-01 1.5284339e+00 1.3595229e+00
+1 6.3185883e-01 1 1 1.1541910e+00 -8.5199791e-01 2.3092825e-01 8.9991163e-01 -1.3017496e+00 5.0043861e-01 -4.1437606e-01 6.9735037e-01
+1 4.9864998e-01 1 1 -8.4640341e-01 -1.4957383e-01 1.3441884e+00 1.1876679e+00 -4.5502175e-01 8.2826588e-01 4.9244835e-01 -9.1450033e-01
+1 6.1003828e-01 1 1 -3.7051652e-01 -6.1331722e-01 5.8107318e-01 -5.4590289e-01 -9.1400176e-01 2.6767703e-01 -1.5171849e+00 -1.3357284e+00
+1 1.3178256e+00 1 1 -6.3450039e-01 -4.5707396e-01 -1.1145926e+00 -1.5392803e+00 7.6042593e-01 8.7232305e-02 9.8152743e-01 2.3395545e-01
+1 1.0483410e+00 1 1 -1.4825333e+00 -8.4803767e-01 3.5967951e-01 3.3148715e-01 4.7962546e-01 -1.0104210e+00 2.8433951e-02 -1.1847315e+00
+1 5.1332943e-01 1 1 -9.6630971e-01 4.3672070e-01 7.0931419e-01 1.2608183e+00 -2.6171876e-01 1.3036832e+00 3.6733008e-01 -3.6740825e-01
+1 6.4896362e-01 1 1 1.2667821e+00 1.2044151e+00 -9.0050524e-01 5.3104444e-01 -4.7749119e-01 1.5369674e+00 4.8707192e-01 1.3407494e+00
+1 7.5032652e-01 1 1 2.3362706e-01 1.3236385e+00 1.4018548e+00 -9.0697776e-04 -1.5667629e+00 -1.5051842e+00 -7.7270971e-01 -6.6813103e-01
+1 1.0304196e+00 1 1 -4.2079686e-01 7.7436747e-01 -9.7119802e-01 4.6438811e-01 2.4513188e-01 -1.5265448e+00 4.1186293e-01 -1.2261036e+00
+1 4.8274051e-01 1 1 -6.0783818e-01 -8.2435163e-01 7.9031505e-01 1.2547951e+00 1.3035254e+00 7.4800834e-01 1.2516827e+00 -1.4166134e+00
+1 5.7917521e-01 1 1 5.2297701e-01 -4.5420938e-01 1.7122744e-01 -1.7042039e-01 -1.1165639e+00 -8.7771110e-01 9.2720103e-01 1.1091899e+00
+1 5.6119777e-01 1 1 -5.0166950e-01 1.7303376e-01 1.2077104e-01 8.7708648e-01 -1.3566176e+00 1.2286477e+00 1.1681545e+00 -5.6668690e-02
+1 7.2656853e-02 1 1 4.7542908e-01 -9.3632611e-01 3.3002242e-01 8.3974790e-01 1.0081321e+00 1.9343728e-01 1.3606850e+00 -5.2809441e-01
+1 1.1198653e+00 1 1 1.4663942e+00 -5.9531385e-01 -1.3658592e+00 -1.5327859e+00 1.0678615e+00 -4.4803270e-01 1.3795729e+00 -6.8344755e-01
+1 5.7108674e-01 1 1 -1.0745272e-01 5.3265688e-01 -3.7880424e-01 -4.7310416e-01 -3.7054254e-01 3.1208535e-01 1.5276855e+00 -1.0402771e+00
+1 6.4529708e-01 1 1 4.5797529e-01 -1.1749124e+00 1.4454492e+00 -9.0688183e-02 -1.0718341e+00 -1.2411723e+00 -4.2630888e-01 -9.7329832e-01
+1 7.8699122e-01 1 1 2.8873043e-01 1.2983844e+00 -2.7086216e-01 -5.2384793e-01 -4.2267841e-01 -2.0823130e-01 9.9955574e-01 4.8144939e-02
+1 8.8945839e-01 1 1 -1.0683216e+00 4.4481895e-01 -2.1260600e-01 -1.5694959e+00 -8.1509192e-01 -9.2577077e-03 1.4374268e+00 -1.3589144e+00
+1 1.0599687e+00 1 1 -1.0790651e+00 -9.1841052e-01 -1.2781356e+00 1.4364962e+00 1.2356913e+00 1.4853397e+00 -1.4951628e-02 1.0499337e-01
+1 3.5552600e-01 1 1 5.6753876e-01 -1.0809172e+00 5.8594742e-01 5.2684093e-02 -8.0577468e-01 1.0085376e+00 3.5405639e-02 -9.5143692e-01
+1 1.1234072e+00 1 1 7.4861354e-01 8.5471032e-01 -8.7465498e-01 -4.6757808e-01 7.5086886e-01 -1.5430479e+00 1.3015664e+00 -9.3766418e-02
+1 1.0020164e+00 1 1 -1.3081164e-01 -1.3868974e+00 -8.1420650e-01 -1.4615526e+00 7.5179852e-02 -1.5933919e-01 5.1637112e-01 1.1473206e+00
+1 1.0215509e+00 1 1 5.6370280e-01 1.0335390e+00 4.0902212e-01 -2.0201211e-01 6.2753255e-01 -1.3767573e+00 1.5705224e+00 -7.8389639e-02
+1 7.6317572e-01 1 1 -8.9048721e-01 8.2501436e-01 6.3008057e-01 8.4410308e-01 6.1305989e-01 -1.3304104e+00 1.0805496e-01 -1.1673492e+00
+1 8.2893277e-01 1 1 1.2884645e-01 -9.7361423e-01 -5.4464035e-01 -5.9192674e-01 -7.2635609e-01 -1.4920925e+00 2.3908579e-01 -3.9134869e-01
+1 6.9484712e-01 1 1 9.6495764e-01 1.0217843e+00 8.3056285e-01 9.1125065e-01 3.6227417e-01 -1.4054234e+00 2.1783536e-01 1.0976207e+00
+1 4.3646492e-01 1 1 1.1417457e+00 1.1834630e+00 1.1736679e+00 1.2556461e-01 3.3548052e-01 6.8488439e-01 1.2033725e+00 2.7922928e-01
+1 6.3072055e-01 1 1 4.7221908e-01 1.0395793e+00 -2.2332645e-01 -7.8588009e-01 -7.3775037e-01 5.6532009e-02 -4.9233152e-01 -5.3289444e-01
+1 8.1580650e-01 1 1 9.2308617e-01 -1.3285489e+00 7.5552098e-01 -1.0311191e+00 4.9566729e-01 1.3724990e+00 3.3920489e-01 3.2380383e-01
+1 9.7424207e-01 1 1 1.1247018e+00 1.5190724e+00 -2.7642340e-01 -9.9290096e-01 -8.2359950e-01 -1.1246842e+00 -9.7406778e-01 9.3252716e-01
+1 7.1424802e-01 1 1 -1.0053250e-01 -6.7294958e-01 5.6750025e-01 4.5372951e-01 -3.7955446e-01 3.9545673e-01 -3.1794283e-01 -4.2177829e-01
+1 7.5958780e-01 1 1 5.2710870e-01 -5.2995485e-01 1.0140299e-01 1.1864331e+00 1.4029053e+00 -1.1687200e+00 1.8397483e-01 -1.3946591e+00
+1 4.4375615e-01 1 1 -1.7543860e-01 -5.3593165e-01 1.5367543e+00 6.9263583e-01 9.7594504e-01 -1.4398435e+00 7.3777677e-01 -6.1213773e-01
+1 4.3819677e-01 1 1 1.3589122e+00 -4.5716882e-01 1.1954892e+00 1.5295324e+00 4.5295918e-01 2.3806122e-01 -5.1965519e-02 5.1719608e-01
+1 1.0943808e+00 1 1 -1.4160381e-01 6.9926760e-01 -1.0394698e+00 -8.0118321e-01 8.0598638e-01 -1.2940639e+00 -2.1725073e-02 -2.7243676e-01
+1 6.2707768e-01 1 1 1.3919933e+00 -1.0758780e-01 2.8345643e-02 -6.2004860e-01 -3.3451227e-01 -8.6850046e-02 -7.0855397e-01 -1.5440715e+00
+1 8.7532980e-01 1 1 -2.0884670e-01 1.3291308e+00 -1.1168555e+00 -4.9405137e-01 1.3030646e+00 1.1518633e+00 1.1112507e+00 1.4870489e+00
+1 1.0680270e+00 1 1 -9.2755499e-01 -1.1640448e+00 2.5121221e-02 -2.9203578e-01 5.6425851e-01 8.7188231e-01 2.1719046e-02 1.4615697e+00
+1 5.2059878e-01 1 1 -8.3398072e-01 -1.4034106e+00 1.2389495e+00 -1.0775843e+00 -9.7547324e-01 1.3378545e+00 6.0725444e-01 4.8975686e-01
+1 7.6056015e-01 1 1 1.0723837e+00 -4.3853991e-02 5.4832295e-01 3.2249348e-01 1.1932728e+00 9.4227822e-01 -9.0920589e-01 3.7085962e-01
+1 5.1080083e-01 1 1 2.3604863e-01 1.2202451e+00 1.3725739e+00 9.0059276e-01 -5.9168590e-01 1.0141965e-01 -3.1680081e-01 1.1781532e-01
+1 7.4480257e-01 1 1 -5.6217839e-01 3.4277032e-01 1.3450335e-01 6.9078274e-02 -1.3242071e+00 -1.3247157e+00 5.2829457e-01 9.1870790e-01
+1 7.2012675e-01 1 1 1.3784375e+00 -7.4012503e-01 -1.3489309e+00 -1.3907278e+00 -9.0660991e-01 -2.9668104e-02 9.0600732e-01 -2.0416903e-01
+1 5.1000807e-01 1 1 1.2940330e+00 1.4254886e+00 1.3928265e+00 -5.1259726e-01 -6.6845677e-01 8.8141235e-01 -3.4579011e-02 -8.4976626e-01
+1 5.4906316e-01 1 1 -4.3248215e-01 4.0162545e-01 1.2280164e+00 -9.7502805e-01 -4.1766603e-01 1.2879767e+00 2.5194982e-02 -3.4130593e-01
+1 7.0349252e-01 1 1 9.1794000e-01 -1.1635952e+00 -9.9177934e-01 -7.4915811e-01 -1.3950454e+00 1.4502524e+00 -6.6295328e-01 2.1938276e-01
+1 5.3036593e-01 1 1 -5.4394843e-01 -1.3095419e-01 4.5520444e-01 4.0298051e-01 -8.2185879e-01 -1.2252018e+00 9.7331188e-01 -1.0637090e+00
+1 7.7423808e-01 1 1 -1.0662191e-01 1.3094141e+00 8.4284207e-01 -3.8034781e-01 6.0220225e-01 1.1739579e+00 1.7985276e-01 1.0471174e+00
+1 4.2904420e-01 1 1 -1.2865610e+00 4.6596509e-01 2.0544269e-01 6.3543041e-01 -9.9834564e-01 1.5087684e+00 5.7323173e-01 -3.0052465e-01
+1 8.4149993e-01 1 1 3.5117822e-01 -5.1523022e-01 2.6502749e-01 1.4054807e+00 5.1110435e-02 -1.0654538e+00 -9.5902681e-01 7.6320915e-01
+1 1.0537751e+00 1 1 -8.0020631e-01 -1.2450119e+00 -4.6139900e-01 2.7871508e-01 1.3582849e+00 -3.2132228e-03 1.1483310e+00 1.3342372e-01
+1 4.1978267e-01 1 1 9.0773046e-02 1.2338497e+00 -1.2823009e+00 2.4963228e-01 -1.2593284e+00 -5.9755981e-01 1.1951853e+00 -6.4472674e-01
+1 5.2124374e-01 1 1 -1.1914375e+00 -3.4130436e-01 -3.0490541e-01 1.5434712e+00 -6.2259142e-01 4.8404847e-01 1.3612939e-01 -5.6933085e-01
+1 1.0327007e+00 1 1 2.0974012e-02 2.4581407e-01 -6.0758293e-01 9.9060170e-01 7.5108118e-01 -1.3223654e+00 8.4721954e-01 5.4764393e-01
+1 1.0779735e+00 1 1 6.5184774e-01 2.0273694e-01 -1.4700995e+00 -1.3982486e+00 5.0213355e-01 -1.3685969e+00 1.5208397e+00 -6.1497434e-01
+1 8.9026392e-01 1 1 8.7142443e-01 -1.2282711e+00 6.6374878e-01 -1.2519670e+00 1.0406379e+00 7.3294655e-01 7.5442671e-01 -3.3865219e-02
+1 6.7220118e-01 1 1 -7.4527986e-02 -1.4692647e-01 -1.6971834e-01 5.7764618e-01 7.5522557e-01 4.4795226e-01 1.8171140e-01 -5.4445935e-01
+1 4.2582998e-01 1 1 9.0360229e-01 -1.0141929e-01 1.1007018e-01 9.7810831e-01 1.0418802e+00 1.4775766e+00 3.9547349e-01 7.3110322e-01
+1 7.6625086e-01 1 1 3.8481071e-01 1.3307642e+00 -4.4856728e-01 -8.8795705e-01 -3.5619698e-01 -6.6037417e-01 -8.8704831e-01 8.8291786e-01
+1 8.1861035e-01 1 1 -1.0256069e+00 1.1552878e+00 7.5211148e-01 -1.3291135e+00 1.2728855e+00 3.3816476e-01 1.3778540e+00 1.4583824e+00
+1 4.9104390e-01 1 1 5.4324016e-01 -1.2618301e+00 -1.0311777e+00 1.4554039e+00 -8.5867612e-01 3.9409084e-01 9.1215611e-01 3.2676466e-01
+1 7.4193136e-01 1 1 7.6916692e-01 1.3130499e+00 1.1625949e+00 5.3252809e-01 7.0702370e-01 1.0073598e+00 -3.6443114e-01 4.2965123e-01
+1 7.2766990e-01 1 1 -2.6531777e-01 -1.2594308e+00 -9.7422259e-01 -1.9783498e-01 1.4438460e+00 6.5380398e-01 1.1115789e+00 -1.3733568e+00
+1 6.8386166e-01 1 1 -1.2758100e+00 7.9781898e-01 2.2180094e-01 -1.2074799e+00 1.0578218e+00 -8.0756254e-01 -7.4428088e-01 -7.2711358e-01
+1 1.1884959e+00 1 1 -1.1688504e+00 6.2609799e-01 -1.2620346e+00 5.7383123e-01 5.3746788e-01 -1.0233354e+00 6.9319905e-01 1.9745775e-01
+1 7.7324302e-01 1 1 -4.8951703e-01 -1.5065054e+00 1.0180068e+00 -3.0804226e-01 1.1437350e+00 1.0221503e+00 -1.5706431e+00 1.1505687e+00
+1 4.5317737e-01 1 1 5.1843299e-01 1.4013398e+00 5.2731190e-01 7.8398514e-02 -6.5161205e-01 1.0511752e+00 1.0039328e+00 1.1050724e+00
+1 1.1546258e+00 1 1 -1.4747830e+00 -2.0271063e-01 9.8188912e-02 1.3164955e+00 -5.1738368e-02 -1.2151146e+00 -3.9553036e-01 -1.4430477e-01
+1 4.4813744e-01 1 1 4.8788145e-01 -1.4711442e+00 9.2489695e-01 1.0302235e-01 6.5442054e-01 1.0623044e+00 -6.8707827e-02 -2.0806562e-02
+1 2.3268780e-01 1 1 2.6677404e-01 -1.1864221e+00 1.4259577e-01 4.7909574e-01 1.3018327e-01 4.7889979e-01 1.3336525e+00 -9.7910838e-01
+1 1.0744219e+00 1 1 6.1865759e-01 -5.0769042e-01 -4.2816872e-01 2.6018296e-01 1.4417248e+00 1.0840992e-01 -5.6684596e-01 -2.1217934e-01
+1 3.9215042e-01 1 1 -8.9357560e-01 -1.8731080e-01 1.1571524e+00 -2.0204302e-01 -3.5036497e-02 -7.8171979e-02 1.4704975e+00 -3.9044529e-01
+1 1.0846985e+00 1 1 -1.5122379e+00 -2.5679979e-01 -1.3394198e+00 3.2469713e-01 -1.3805735e+00 -6.5072572e-01 -2.5723125e-01 5.7310445e-01
+1 7.9413126e-01 1 1 -6.9742758e-01 5.1415283e-01 1.0235847e+00 2.3816208e-01 5.0368997e-01 -8.6318800e-01 -4.5420827e-01 4.3375513e-02
+1 7.0067319e-01 1 1 -3.8309254e-01 -1.1547827e+00 2.5926878e-02 4.0095746e-01 -1.0748876e+00 2.7409237e-01 1.9172008e-01 1.6275177e-01
+1 4.6278159e-01 1 1 -1.5129712e+00 3.2659191e-01 -9.2834022e-01 1.7571422e-01 -1.4786104e+00 1.0956608e+00 -1.0345983e+00 -9.5822646e-01
+1 5.7277550e-01 1 1 -4.5662790e-01 6.6793055e-01 -1.4649717e+00 1.3180950e-01 -1.0077772e+00 -1.2447216e+00 2.2164119e-01 -1.1081859e+00
+1 1.0503412e+00 1 1 3.6567974e-01 9.9823296e-01 -1.1173459e+00 4.9942976e-01 -1.3853651e+00 -1.7087818e-01 -8.0534661e-01 1.2219367e+00
+1 5.9800419e-01 1 1 1.0241443e+00 1.1966236e+00 1.2089367e+00 -4.1961538e-01 -1.4888074e+00 -5.3389455e-01 -1.4793314e+00 4.9967349e-01
+1 1.0233073e+00 1 1 6.8101272e-03 -8.2317591e-01 -1.2225748e+00 3.9987053e-01 3.9997351e-01 -7.7709476e-01 -5.5835459e-01 5.3517770e-01
+1 5.7934543e-01 1 1 1.3604730e+00 4.5650258e-01 1.3429864e+00 7.5737543e-01 -6.5344593e-01 -1.0310436e+00 -3.2830085e-01 3.5190275e-01
+1 1.0162852e+00 1 1 9.5770875e-01 6.6952199e-01 -7.7004585e-01 -5.2450121e-01 5.4213472e-01 2.7543306e-01 -1.1157502e+00 -1.1894393e+00
+1 7.6134146e-01 1 1 -1.3097173e+00 -5.2874724e-01 1.2010806e+00 1.7210648e-02 1.0396271e+00 -1.5041067e+00 -2.4755184e-01 -9.5213719e-01
+1 7.3060698e-01 1 1 7.2052623e-01 9.1068432e-01 -1.3124883e+00 2.3284080e-01 -5.2511088e-01 8.7398736e-01 -1.1351716e+00 7.0319717e-01
+1 7.4086678e-01 1 1 -9.5536248e-01 3.1874992e-02 1.2731135e+00 -1.0690973e+00 -8.0475373e-01 -9.8165942e-01 6.3195496e-02 -3.6716086e-02
+1 1.0493463e+00 1 1 -9.7195271e-02 -1.4893577e+00 -1.6962220e-01 -1.5491078e+00 -9.3962880e-01 8.9474821e-01 2.6838145e-01 -1.3350989e+00
+1 5.6534907e-01 1 1 6.7252176e-02 5.7617829e-01 -1.4156966e+00 -1.4765429e+00 4.4507256e-01 -7.7093993e-01 -6.4002639e-01 1.3883396e+00
+1 4.3531792e-01 1 1 -6.6602586e-01 1.4400378e+00 8.0920450e-01 -8.1552584e-01 2.0239577e-01 -1.2592766e+00 -1.1029200e-01 1.2157732e+00
+1 7.1615593e-01 1 1 -4.0205788e-01 -1.1370299e-01 3.4547634e-01 2.2592522e-01 -6.7918001e-01 2.4868287e-01 -1.3795776e-01 5.8129259e-01
+1 6.8914131e-01 1 1 1.7898196e-01 -9.1781569e-01 7.5755008e-01 -1.0603382e+00 1.5692501e+00 1.2947672e+00 -1.6067705e-01 -5.6851358e-01
+1 7.2184811e-01 1 1 -1.4959912e+00 -5.0831686e-01 -7.3081709e-01 1.1509730e+00 7.1661879e-01 -6.5963589e-01 1.2705866e+00 -1.4244967e+00
+1 9.4100820e-01 1 1 -9.5880692e-01 -1.2911190e+00 7.8446331e-01 -1.5235153e+00 -6.5430266e-01 1.8007665e-01 1.3437574e+00 5.6178116e-01
+1 6.7481223e-01 1 1 -1.4392164e+00 -8.5644862e-01 -7.8951423e-01 1.3999716e+00 -1.2904604e+00 1.1944986e+00 -3.7878073e-01 1.3700377e+00
+1 4.2920143e-01 1 1 1.3532779e+00 4.4556212e-01 7.2176540e-01 -1.2060878e+00 7.8749259e-01 1.1604022e+00 -1.3009523e+00 1.4916063e+00
+1 8.5378486e-01 1 1 -5.8906590e-01 -9.9437718e-01 1.0217729e+00 -1.1625300e+00 -1.4190290e-01 -1.2679733e-01 3.7903542e-01 -4.8223097e-01
+1 4.3821162e-01 1 1 -1.2721648e+00 7.7573292e-01 9.9143647e-01 -1.0765561e+00 -4.9313267e-01 -1.0829730e+00 -7.0161487e-01 4.5313952e-01
+1 7.5931210e-01 1 1 4.0605717e-01 1.3368667e-01 6.5291657e-02 -1.2460513e+00 -5.5932008e-01 8.6114864e-01 1.4976827e+00 6.9533954e-01
+1 5.0953205e-01 1 1 1.0636204e+00 6.3304464e-01 9.4104336e-01 -5.2829879e-01 -8.4741561e-01 7.8954237e-03 1.1131284e+00 -1.5306088e-01
+1 4.8188252e-01 1 1 6.0623278e-01 -9.9308008e-01 1.3383356e+00 -9.7684323e-01 1.4670130e+00 7.5149530e-01 1.6521801e-01 4.7017481e-01
+1 9.6349942e-01 1 1 7.6931776e-01 5.8478377e-01 -3.9687957e-01 1.5908774e-01 8.6791161e-01 1.1789635e+00 -3.4888505e-01 1.1225591e+00
+1 1.0105007e+00 1 1 -8.7174220e-01 1.5590461e+00 -7.5377831e-01 2.9231560e-01 5.7568728e-01 8.1394323e-01 -1.4991994e+00 -1.5546023e+00
+1 6.3729654e-01 1 1 1.0169169e+00 -1.1372336e+00 1.2910533e+00 -5.0267206e-01 -5.2924619e-01 1.4494391e+00 -1.4712333e+00 4.2602117e-01
+1 6.3164842e-01 1 1 1.0590610e+00 -3.5304622e-02 -2.4806046e-01 -6.6672695e-01 -1.1919365e+00 8.1393916e-01 4.5726524e-01 4.4810150e-01
+1 6.0447820e-01 1 1 -6.2632555e-01 3.9623339e-01 -2.5869694e-01 3.8118601e-01 1.0603147e+00 1.3809882e+00 9.2132816e-01 8.4425368e-01
+1 2.3795157e-01 1 1 8.2342613e-01 -6.8178583e-01 4.4725096e-02 8.8591455e-01 -1.5459183e+00 1.8184383e-01 -1.4784852e-01 -1.2024327e+00
+1 7.2556120e-01 1 1 6.0728585e-01 -1.3860851e+00 8.5404283e-01 1.5582878e+00 -1.2771861e+00 -5.2035707e-01 1.0970770e-01 5.7989061e-01
+1 9.7797637e-01 1 1 -3.8129275e-01 -1.0225425e+00 -3.8933182e-02 -1.3146633e+00 8.3592998e-01 5.5265457e-01 -2.5754053e-01 1.0010722e+00
+1 1.2041066e+00 1 1 4.6184048e-01 -1.3597617e+00 -8.9872357e-01 -7.2467905e-01 2.7281778e-01 -1.2240391e+00 6.3105728e-01 -1.3496999e+00
+1 1.1296727e+00 1 1 -7.2245876e-01 -1.5695548e+00 -6.9562333e-02 2.7389479e-01 -1.4768306e+00 -1.2769296e+00 1.6288660e-01 1.0351722e+00
+1 9.8554082e-01 1 1 -1.0878200e-01 4.4545738e-01 -4.6166840e-01 9.1657134e-01 6.3230351e-01 -1.1367391e+00 1.3079325e+00 -1.6713876e-03
+1 5.4160922e-01 1 1 1.0790628e-01 3.8686571e-01 4.7311517e-01 -1.5559066e+00 -8.8291255e-01 -1.1492922e+00 6.9778242e-01 1.8332310e-01
+1 4.2708196e-01 1 1 8.8187478e-01 -1.0447569e+00 2.7558441e-01 4.9514042e-01 -1.3690568e+00 1.4984481e+00 6.3744855e-02 -7.9104687e-01
+1 3.0194344e-01 1 1 -3.6464417e-01 -8.6737516e-01 1.0395933e+00 -2.5387555e-01 -7.1385812e-01 1.4110357e+00 7.6686692e-02 9.5438032e-02
+1 9.8462222e-01 1 1 6.7277418e-01 -9.8438923e-01 -1.0945027e+00 -6.0362599e-01 -7.1083869e-02 -6.0573952e-01 8.2023892e-01 -1.3268450e+00
+1 1.1020799e+00 1 1 7.2375581e-01 -1.0029125e+00 -1.2825831e+00 -9.3939678e-01 -9.0137843e-01 1.2376831e+00 4.4704742e-01 -1.2587152e+00
+1 4.9277565e-01 1 1 -8.2831008e-02 -1.3061545e+00 1.2341919e+00 1.2030446e+00 -7.0742082e-01 1.2555801e+00 -1.1637183e+00 2.5830863e-01
+1 5.4756487e-01 1 1 -4.1519895e-01 9.1080200e-01 -8.7362693e-01 2.8011027e-01 1.3064978e+00 4.5619403e-01 9.4294790e-01 -2.8788484e-01
+1 3.7091129e-01 1 1 -7.7141878e-01 -1.1317952e+00 7.5630885e-01 -1.4340876e+00 -1.4236023e+00 -1.3745361e+00 -1.2096145e+00 -4.2783417e-01
+1 8.0664766e-01 1 1 1.1745058e-01 2.6166297e-01 3.9889839e-01 -4.1129410e-01 -1.1384843e-01 1.4447331e+00 -7.4409885e-01 4.9665644e-01
+1 8.7631391e-01 1 1 1.0716490e+00 -4.6009496e-01 1.2656074e-01 -1.1161210e+00 -2.2061508e-01 2.5945255e-01 6.1104886e-01 9.3165076e-02
+1 8.0013483e-01 1 1 4.5378545e-01 -1.3564113e+00 2.4816574e-01 -1.9591029e-01 -7.9823506e-01 8.8349170e-02 3.1739490e-02 1.3122830e+00
+1 1.1019871e+00 1 1 -1.0148934e+00 1.3327291e+00 -1.1134978e+00 -2.7517233e-01 -1.3360961e+00 -1.0888301e+00 -6.2513576e-01 1.5593968e+00
+1 8.5034381e-01 1 1 1.5348785e+00 -3.7826549e-01 -9.0636536e-02 -3.9701340e-01 3.3683686e-01 -1.9059049e-01 -1.1708267e+00 -1.5247618e+00
+1 3.8847348e-01 1 1 1.0857240e+00 1.0755214e+00 3.4418085e-01 1.3852224e-01 6.7183026e-02 1.1701230e+00 8.5141965e-01 -6.9965751e-01
+1 6.1757560e-01 1 1 1.3927324e+00 -4.3613935e-01 9.7542228e-01 2.2311625e-01 1.3133514e+00 -1.1277705e-01 -1.4455116e-01 -1.6239665e-01
+1 4.1587881e-01 1 1 -3.5397733e-01 -8.5843560e-01 1.0918471e+00 -1.1468231e+00 6.6700178e-01 -1.0634668e+00 -1.0202255e+00 6.4359953e-01
+1 5.3407227e-01 1 1 8.7946412e-01 -1.5335974e+00 6.3154587e-01 -9.8556290e-01 1.0964061e+00 -1.1658431e+00 -1.1773664e-01 4.7380963e-01
+1 4.9890095e-01 1 1 -4.0038344e-02 -1.5453382e+00 -1.0501877e+00 1.2623658e+00 -1.2857744e+00 -2.1091136e-01 4.0366893e-01 -6.1886768e-01
+1 8.1436628e-01 1 1 -6.2361637e-01 -9.5198280e-01 -1.0370791e+00 1.4060720e+00 1.0061172e+00 -1.0707056e+00 -1.3764928e+00 5.0414207e-01
+1 6.8224300e-01 1 1 -7.6716164e-01 1.5651979e-01 -6.3199927e-01 7.9176507e-01 -1.3819720e+00 -3.0596298e-01 -2.6601070e-02 2.4042436e-01
+1 6.7001284e-01 1 1 -5.8938117e-01 1.1150635e+00 -2.8698237e-01 -5.9093717e-01 -1.0090862e+00 4.6744633e-01 -9.7802086e-01 7.2403350e-01
+1 1.0209154e+00 1 1 -2.8765784e-01 1.2727344e+00 -9.6793876e-01 -1.3067176e+00 -1.3942613e+00 -7.5272721e-01 -7.8383353e-01 1.4426079e+00
+1 8.5937652e-01 1 1 2.4572978e-01 -2.5699703e-01 -9.7999348e-01 8.7191739e-01 -2.0970168e-01 1.0737290e-01 -1.1922113e+00 -9.0134032e-01
+1 9.1094456e-01 1 1 -1.2139075e+00 3.4074300e-01 6.1987443e-01 -1.2140864e+00 4.1077513e-01 1.3421116e+00 -4.1693315e-01 -6.6971761e-02
+1 5.2471090e-01 1 1 -6.3997471e-01 -2.5573488e-01 7.0825977e-01 -5.0525694e-01 -1.3230502e+00 2.3510225e-01 1.4976830e+00 -9.0422347e-01
+1 3.4770454e-01 1 1 7.5832687e-01 -4.3735001e-01 2.2733746e-01 -1.2842906e-01 -3.1265568e-01 -7.6003595e-01 1.1173328e+00 -1.4002523e+00
+1 8.4650550e-01 1 1 -2.4169465e-01 7.8515371e-01 6.8404998e-01 -2.3312602e-01 1.0805070e+00 -2.0850999e-01 -1.4276896e+00 -3.6945990e-01
+1 1.0748603e+00 1 1 -8.2694842e-02 1.3892000e+00 -1.4011811e+00 -5.8294147e-01 -1.4657939e+00 -1.5516126e+00 3.0616873e-01 1.4161550e+00
+1 1.0848350e+00 1 1 -1.2682582e+00 -3.2542962e-02 -2.7244240e-01 1.1302470e+00 7.7178815e-01 4.0697342e-01 -1.5091404e-01 6.1198024e-01
+1 7.0025006e-01 1 1 9.0146637e-02 -3.1243379e-01 1.5027127e+00 -1.1499431e+00 -1.9267132e-01 7.5502951e-01 -1.1470285e+00 -2.2397822e-02
+1 7.9751043e-01 1 1 8.4686326e-01 -1.4734296e+00 8.2822213e-01 -1.4860944e-02 7.5523397e-01 8.8828775e-01 -1.2956779e+00 5.5092065e-01
+1 6.3226185e-01 1 1 -1.3254516e+00 1.2437633e+00 -4.6775262e-01 1.5595210e+00 1.1829374e+00 6.0397757e-01 1.0615355e+00 1.0498080e+00
+1 3.5954488e-01 1 1 1.6766129e-01 -2.2837366e-01 -1.2535402e+00 5.6144302e-01 -1.5113902e+00 5.6514573e-01 1.2190931e-01 9.3809905e-01
+1 5.1627903e-01 1 1 -1.2536700e-01 7.5015004e-01 -7.3016638e-01 -1.1715682e+00 9.8302157e-01 1.3697172e+00 6.1137418e-01 -1.0228155e+00
+1 8.8246865e-01 1 1 9.6558425e-01 5.6035234e-01 -8.4546761e-01 9.5595670e-01 7.7966329e-03 -7.5431319e-01 -7.8380377e-01 3.3507133e-01
+1 1.0275571e+00 1 1 -8.9311287e-01 -6.5292415e-01 -3.5062158e-01 6.5944438e-01 -9.0888265e-01 -1.4154799e+00 -6.9200797e-01 -1.3318441e+00
+1 3.4035268e-01 1 1 -1.8274829e-02 -1.1300538e-01 7.3093154e-01 -2.5715357e-01 -1.1672826e+00 1.3108297e+00 -4.0197294e-01 -4.5681251e-01
+1 5.1051824e-01 1 1 7.3102943e-01 1.3822121e+00 1.1390475e+00 8.5140004e-01 7.2783899e-01 -8.7422152e-01 -1.5349758e+00 4.0455635e-01
+1 9.1016992e-01 1 1 -3.5716539e-01 -1.2392307e+00 -8.9361912e-01 -4.7402050e-01 -5.7188920e-01 1.8771622e-01 4.2079102e-01 9.7211523e-01
+1 3.5506694e-01 1 1 7.0476837e-01 1.0084280e+00 8.9793284e-01 2.1642749e-01 1.5316597e+00 7.8750759e-01 5.0966124e-01 -1.0827521e+00
+1 4.2965464e-01 1 1 1.2377316e+00 -2.4333642e-01 -6.5382756e-01 -4.6745061e-01 3.9499073e-01 1.1028867e-01 -1.2467624e+00 1.4313232e+00
+1 7.6834109e-01 1 1 -1.0721987e+00 5.9845889e-01 4.1133878e-01 6.8085864e-01 4.2395707e-01 8.2070908e-02 8.6817398e-02 1.0732455e+00
+1 7.3949870e-01 1 1 -2.6872925e-01 -1.0811217e+00 -1.2746012e+00 1.5106895e+00 3.1426948e-01 2.0656802e-01 1.4410154e+00 -9.8814741e-01
+1 3.6356142e-01 1 1 1.0776634e+00 5.5868381e-01 2.9805008e-01 -1.9340958e-01 9.0989718e-01 3.2880655e-01 6.0837963e-01 -1.3347330e+00
+1 9.1234315e-01 1 1 1.0071612e+00 -4.2171735e-01 -1.5125996e+00 9.1366630e-01 -6.3110399e-01 1.9012564e-01 -8.4768887e-01 1.2552159e+00
+1 6.5736649e-01 1 1 4.5671662e-01 -3.7047658e-01 -4.9400884e-01 -1.1532158e-01 -9.4798254e-01 4.4183049e-01 1.5925966e-02 6.1894543e-01
+1 7.2975555e-01 1 1 1.1254149e+00 3.6805687e-02 4.2276517e-01 1.5289866e-01 1.4154727e+00 -8.8003718e-01 6.3233912e-01 8.0262184e-01
+1 6.1355957e-01 1 1 -6.8120193e-01 -3.0057295e-01 -8.6842680e-01 -5.5039296e-02 -1.4314794e+00 -1.6670351e-01 -2.8428643e-01 -3.3352787e-01
+1 8.9398871e-01 1 1 -9.9715160e-01 -4.8613136e-02 1.9031679e-01 -1.4172072e+00 -5.5811356e-01 5.1468558e-01 3.6047763e-01 -1.0015492e+00
+1 4.8997815e-01 1 1 1.2698271e+00 -2.2688212e-01 5.1303106e-01 5.5377602e-01 5.8098120e-01 1.5159514e+00 1.5568206e+00 -3.8322682e-01
+1 1.0000865e+00 1 1 1.1443713e+00 6.8564904e-01 -1.1588885e+00 -1.2254901e+00 4.8107585e-01 2.7874643e-01 -8.4152196e-01 -6.2819439e-01
+1 4.9228942e-01 1 1 6.1811100e-01 3.4155557e-01 4.3599816e-01 -5.3037792e-01 -1.0176874e+00 7.7656193e-01 -9.3883038e-03 8.2986030e-01
+1 9.1806091e-01 1 1 -6.5533715e-01 8.3464452e-01 -1.5145059e+00 -1.3632848e+00 -1.4415239e+00 1.5005498e+00 -7.0958999e-01 -1.2092435e+00
+1 8.3085105e-01 1 1 1.7233459e-01 6.5921109e-01 -1.1162464e+00 -1.0923356e+00 2.7116843e-01 -9.6453719e-01 -5.9331443e-01 -7.9266699e-01
+1 7.7388759e-01 1 1 -1.2104501e-01 -1.0364673e+00 8.3769327e-01 5.8379046e-01 -9.2308803e-01 -3.5845295e-01 -4.2061240e-01 1.1403357e+00
+1 5.4039942e-01 1 1 1.3485830e+00 2.2453480e-01 -1.5075137e+00 5.7240448e-01 -1.1560505e+00 1.0560511e+00 -6.4919811e-01 -1.2338375e+00
+1 9.7746572e-01 1 1 -9.5664013e-01 7.0368367e-01 1.6125267e-01 8.4535490e-01 1.0094585e+00 -9.4815563e-01 -3.2134248e-01 5.4542783e-01
+1 8.7944865e-01 1 1 4.2054320e-01 -1.2849010e+00 -1.0209154e+00 -1.5437042e+00 1.3679446e+00 -1.4937907e+00 -4.0528263e-01 -1.6187962e-01
+1 3.5647621e-01 1 1 -5.1382866e-01 -2.3175626e-02 8.5426368e-01 1.3774306e+00 8.6998755e-01 1.4674433e+00 -6.1223943e-01 -9.1572114e-02
+1 4.2026843e-01 1 1 3.1991385e-01 4.4734650e-02 5.3129050e-01 7.9737991e-02 9.0860237e-01 -1.3251127e+00 -1.1922335e+00 3.2787565e-01
+1 3.2979297e-01 1 1 1.5269868e+00 1.0146223e+00 9.9310279e-01 -1.3036549e+00 -4.0177412e-01 -4.1870409e-01 -7.8992195e-01 2.5249968e-01
+1 5.1015323e-01 1 1 3.9691391e-01 1.9132785e-01 -2.0318943e-01 -1.0606875e+00 -1.3350855e+00 7.9533860e-03 1.5230807e-01 -5.2952280e-01
+1 1.1844483e+00 1 1 1.3308906e+00 -1.3437011e+00 -9.3581106e-02 1.5632852e+00 -1.5269272e+00 -1.4159254e+00 -5.5631199e-01 4.4236270e-01
+1 5.2595864e-01 1 1 1.3825607e-01 1.3253412e+00 1.1202705e+00 9.9466140e-01 6.0423031e-01 1.0675051e-01 -5.5590162e-01 -1.3598701e+00
+1 4.0368337e-01 1 1 -1.1087225e+00 1.1180109e+00 8.2085186e-01 8.5956187e-01 -1.4701963e+00 3.0648393e-01 5.8009480e-02 -2.5002598e-01
+1 5.6072875e-01 1 1 -1.5134864e+00 5.4363107e-01 1.3238660e+00 -1.5282591e+00 -9.6289544e-01 -1.1364782e+00 1.0716160e+00 1.2643822e+00
+1 5.3611849e-01 1 1 3.0900736e-01 1.0559199e+00 1.4564140e+00 2.1145322e-01 -1.0399017e+00 9.3614396e-02 -1.0033772e-01 7.3870340e-01
+1 3.4352866e-01 1 1 4.3407768e-01 -1.1376720e-02 -1.3394236e+00 7.5300109e-01 -9.4835054e-01 -5.6076268e-01 6.5916274e-01 -1.8608520e-01
+1 5.5454704e-01 1 1 7.6536926e-01 4.2862469e-01 9.6098548e-01 1.3541637e+00 1.5135842e+00 3.9652315e-02 1.2925162e+00 1.4922887e+00
+1 4.3064074e-01 1 1 -1.2606994e+00 2.2319288e-01 3.5513873e-01 -1.4095145e+00 1.3336432e+00 4.1881275e-01 -7.9302119e-01 1.5619909e+00
+1 5.8544125e-01 1 1 1.4683181e+00 1.4113152e-01 -2.0938771e-01 1.0403846e+00 -7.2282756e-01 -1.3232041e+00 1.4705510e+00 1.2328673e+00
+1 6.8198752e-01 1 1 8.1243828e-01 9.5007694e-02 -5.9549154e-01 -3.6120418e-01 -2.4045987e-02 2.4380743e-01 6.4133490e-01 -1.1450167e+00
+1 8.2920244e-01 1 1 1.2885733e+00 8.6524502e-01 6.8785584e-01 -1.2016901e+00 1.1245543e+00 1.0346927e+00 1.1129562e-01 1.1010225e+00
+1 2.8946542e-01 1 1 -1.0889893e+00 -2.5941024e-01 -2.6788956e-01 4.9298262e-01 5.6229512e-01 1.3642128e+00 1.2978904e+00 9.0475295e-01
+1 3.7085054e-01 1 1 2.7548984e-01 6.2273910e-01 -5.1757904e-01 1.1791200e+00 5.8330659e-01 9.8063946e-01 1.5657648e+00 8.7441660e-01
+1 7.9598715e-01 1 1 -5.4987502e-01 -1.4107125e+00 1.1911887e-01 3.0316325e-01 -1.2767462e+00 8.1229668e-01 -1.3131573e+00 -5.0646372e-02
+1 6.3019655e-01 1 1 8.1604960e-01 -2.4444720e-01 8.3640988e-01 -3.9846600e-01 -1.1953593e+00 -1.0914247e+00 -5.4640540e-01 1.5802796e-01
+1 9.6243578e-01 1 1 -8.4797086e-01 7.7912641e-01 -1.0863540e+00 8.5751162e-01 8.1324522e-02 1.8393163e-01 -5.6027676e-01 1.3301443e+00
+1 3.4116256e-01 1 1 1.5595719e+00 6.1943174e-01 5.8412486e-01 -1.4292743e+00 2.2844269e-01 1.1665688e-02 -1.2182692e+00 1.6231901e-01
+1 7.7426364e-01 1 1 1.4171290e+00 -4.4880859e-01 -9.0599398e-02 -1.1953177e+00 4.1009837e-01 1.2864804e+00 1.4512471e+00 1.1932454e+00
+1 3.9030342e-01 1 1 1.2729143e+00 -1.6196509e-01 9.6835314e-01 7.8019292e-01 -1.3094473e-01 1.4347956e+00 -2.1544815e-01 -1.0526971e+00
+1 1.3999811e+00 1 1 -3.7474959e-01 -1.5280338e+00 -1.4803927e+00 -3.0534475e-01 1.4683216e+00 -2.5520946e-01 1.2193330e+00 7.6957742e-01
+1 8.0118025e-01 1 1 4.7689020e-01 8.5504530e-01 4.5319035e-01 1.4332462e+00 8.7036588e-01 -1.0314891e+00 7.2067273e-01 3.5068325e-01
+1 7.2383107e-01 1 1 8.9077313e-01 1.1015509e+00 1.5496732e+00 -1.1634298e+00 9.8392945e-01 -9.2921165e-01 1.5068799e+00 3.0552000e-01
+1 4.6518288e-01 1 1 1.5350187e+00 3.6062435e-01 1.5544720e+00 -4.9216983e-01 -4.4138425e-01 -4.0310075e-01 -1.3892757e+00 1.5122097e+00
+1 5.2736958e-01 1 1 3.0111564e-01 8.8120760e-01 5.2713286e-01 -8.4954152e-02 -1.0448876e+00 1.5009657e+00 -1.2403397e+00 2.2368017e-01
+1 8.9672825e-01 1 1 -2.5519955e-01 9.8833582e-01 2.3076759e-01 -1.5413729e+00 7.7222504e-02 -2.5854678e-01 1.2194362e+00 -1.0937763e+00
+1 8.0506254e-01 1 1 -8.6481205e-01 1.3596849e+00 -1.3560587e+00 -2.8206697e-01 4.0086610e-01 -5.7315700e-01 -6.8650972e-01 1.5024530e+00
+1 4.0314611e-01 1 1 1.2531454e+00 2.7995283e-01 9.7532029e-01 -3.6312255e-02 -1.3596867e+00 -9.2664839e-01 9.0090881e-01 -3.9393286e-01
+1 6.7482826e-01 1 1 3.7751955e-01 -9.3865007e-01 -6.2230319e-01 -8.3109292e-01 -3.0881827e-01 -1.3047246e+00 -9.0222531e-01 -1.4939213e+00
+1 9.2620399e-01 1 1 -1.0460984e+00 1.1866037e+00 -6.8784758e-01 -6.5769175e-01 -3.9766809e-01 -1.9032264e-01 7.6699981e-01 -7.2758475e-01
+1 3.3581598e-01 1 1 -1.4237559e+00 4.1826240e-01 4.0673384e-01 1.4393457e+00 -1.4399677e+00 -6.1133094e-01 1.0111307e+00 -1.4383246e+00
+1 3.4357631e-01 1 1 4.4573727e-01 -1.1482778e+00 -1.2993574e-01 8.1900688e-01 1.2931049e+00 1.5105050e+00 1.1983289e+00 6.3329289e-01
+1 7.1138843e-01 1 1 -1.1922596e+00 -3.0153661e-01 -4.2305403e-01 -1.4102988e+00 -3.2430203e-01 -1.5350030e-01 -4.3655393e-01 3.7712229e-02
+1 1.1187994e+00 1 1 -1.2295914e+00 -5.3684628e-01 -8.4490797e-01 4.2461314e-01 1.1905799e-01 -6.3191642e-01 -1.5431334e+00 -7.7227577e-01
+1 8.2731029e-01 1 1 -3.4634932e-01 -1.2138440e-01 -3.6949246e-01 -1.2255245e+00 -1.8691206e-01 1.1055173e+00 1.5453737e+00 1.4219486e+00
+1 5.1553055e-01 1 1 2.7818458e-01 -1.2139221e+00 8.6894090e-01 -1.1094080e+00 1.6166714e-01 1.0509476e+00 1.5501418e+00 5.9515688e-01
+1 8.9847278e-01 1 1 7.5835522e-01 -8.8633910e-01 -9.7456462e-01 -4.6765057e-01 -3.3796324e-01 1.2424399e+00 4.6751621e-03 -2.9376019e-02
+1 6.1600625e-01 1 1 2.3475735e-01 7.3119232e-01 7.5655765e-01 4.6169191e-01 -1.4868950e-01 -4.7898719e-01 3.5633868e-02 -4.9270438e-01
+1 5.9440556e-01 1 1 -2.7351946e-01 -7.6108912e-01 1.4389355e+00 -7.7850307e-02 -1.4582793e+00 1.5643150e+00 -1.1457844e+00 3.5568666e-01
+1 1.0746497e+00 1 1 -8.9147604e-01 9.4045317e-01 2.0900516e-01 -1.5275650e+00 1.4056786e+00 -5.4700955e-01 7.6389855e-01 -4.2520258e-01
+1 4.8967115e-01 1 1 -7.8241058e-01 8.4377523e-01 4.4910727e-01 -6.9037505e-01 4.6284495e-01 -1.2893750e+00 -8.4627242e-01 7.4360202e-01
+1 6.8409761e-01 1 1 7.3227861e-01 1.8110515e-01 -1.1012877e+00 -1.2317813e+00 4.5163612e-01 1.7979346e-01 -1.3105901e+00 4.6350080e-01
+1 8.4451277e-01 1 1 -1.3533720e+00 -3.6910421e-01 9.2211366e-01 5.4779174e-01 5.6043782e-01 -4.2341303e-01 -1.3821600e+00 -1.0918952e+00
+1 6.8350387e-01 1 1 -9.9292785e-01 1.1109696e+00 4.8774025e-01 -1.2722698e+00 7.8370970e-01 -5.9536353e-01 -1.0271783e+00 -1.4392129e+00
+1 2.5895757e-01 1 1 1.8155903e-03 -1.5601722e+00 1.0351548e+00 -1.3592592e+00 -8.8910064e-01 -3.0225285e-01 -7.3332199e-01 1.4120906e+00
+1 1.0471418e+00 1 1 -9.0129995e-01 1.0595873e+00 -2.9362056e-01 5.9202620e-01 1.4418265e+00 -8.3510320e-03 -4.7469490e-01 1.4164930e+00
+1 4.2206094e-01 1 1 6.1151379e-01 -1.2046796e+00 5.6126797e-01 7.6041285e-01 -1.4679126e+00 1.0158743e+00 1.4481185e+00 9.3872754e-03
+1 7.3846186e-01 1 1 1.5627555e+00 5.1416946e-01 -9.7198923e-01 2.5983990e-01 -2.8062406e-01 -7.5693362e-01 6.0930381e-01 6.9230515e-01
+1 7.8274737e-01 1 1 1.5178662e+00 -8.7520092e-01 5.8786770e-02 3.1542884e-01 -9.1797098e-01 -1.4747263e+00 -1.0228939e+00 -8.8658011e-01
+1 4.8559828e-01 1 1 1.0454834e+00 -5.6502671e-01 1.5691473e+00 1.5457727e+00 2.3313110e-02 1.4414985e+00 -9.8221594e-01 -1.7799138e-01
+1 6.2352820e-01 1 1 5.1111369e-01 6.3060428e-01 -1.0117184e+00 -1.1694434e+00 -8.7564080e-01 -6.9733948e-01 9.6611289e-01 -7.0496260e-01
+1 3.8113577e-01 1 1 1.1735296e+00 -1.1674236e+00 1.4905263e+00 -1.0314079e+00 1.4665822e+00 1.0975033e+00 -1.4330370e+00 -1.3605654e+00
+1 4.7276080e-01 1 1 5.9393377e-01 1.4990227e+00 2.1587553e-01 4.3592243e-01 -8.8991830e-02 1.4480628e+00 1.5372013e+00 6.3050972e-01
+1 1.1007930e+00 1 1 1.4050003e+00 -1.4989082e+00 -3.1952118e-01 3.5425331e-01 -2.8757707e-01 -3.2690545e-01 -7.1652725e-01 3.8489746e-01
+1 8.9132953e-01 1 1 -1.5127293e+00 2.8161318e-01 -1.2106308e+00 6.1723227e-01 -1.5383263e+00 3.4571230e-01 -9.4881570e-01 4.3229490e-01
+1 7.1469982e-01 1 1 4.6831624e-01 -1.3074964e+00 1.0241191e+00 2.8376956e-01 6.5815739e-01 -1.5598079e+00 -2.1218311e-02 -9.2341881e-01
+1 3.5602559e-01 1 1 1.3014238e+00 3.4911040e-01 -4.1559907e-01 3.7734944e-01 1.0349687e-01 8.9990933e-01 1.5254120e+00 -4.3224234e-01
+1 8.8386368e-01 1 1 1.2611727e+00 -9.9651456e-01 -1.2131207e+00 -7.6346368e-01 -9.7038510e-01 1.1490413e+00 -9.3863309e-01 -1.3348026e+00
+1 9.7714686e-01 1 1 2.0353378e-01 -5.8977351e-01 1.7004982e-02 -1.2695970e+00 -1.2549235e+00 5.6664448e-01 1.4719881e+00 8.5575155e-02
+1 7.8461201e-01 1 1 -4.0218020e-01 -5.9850633e-01 -8.2191666e-02 -4.2025593e-01 1.1536938e+00 1.4265052e+00 -3.3852535e-01 -5.8780238e-01
+1 2.9474365e-01 1 1 1.2647843e+00 2.8385512e-01 9.0544433e-01 -9.4105723e-01 2.2209778e-01 -1.3629536e+00 -1.7132192e-01 1.1143239e+00
+1 2.0796132e-01 1 1 1.2134998e+00 -1.3262325e+00 -7.2012968e-02 1.5700960e+00 5.8530075e-01 1.3320383e+00 1.4328777e+00 1.4087186e+00
+1 8.7665226e-01 1 1 7.1009126e-02 -3.8937118e-01 -8.0878663e-01 -7.7444742e-01 8.2316138e-01 5.7853991e-01 -1.0730387e+00 1.2910251e+00
+1 4.9880577e-01 1 1 -3.5483408e-01 -2.2384285e-01 3.9449367e-01 -5.1941612e-01 -7.0070328e-01 2.9097188e-01 1.3214728e+00 -7.2079979e-01
+1 7.4148976e-01 1 1 -9.5345066e-01 1.5011914e+00 1.4945973e+00 6.5924421e-01 1.1107814e+00 -1.0953190e+00 -1.0667058e+00 -5.0076491e-01
+1 7.7844725e-01 1 1 6.1891648e-01 3.9301157e-01 -4.7730614e-01 -4.7988545e-01 1.5590010e+00 7.0610472e-01 9.4448274e-01 -2.9196089e-02
+1 7.1867596e-01 1 1 3.1606447e-01 -1.4239310e+00 1.5434031e+00 -9.6641094e-01 1.2472434e+00 -1.4350356e+00 -5.4623408e-01 -6.1021107e-01
+1 7.0706588e-01 1 1 -3.3757915e-01 6.4374265e-01 -1.5538609e-01 -4.3458280e-01 -1.4273767e+00 -6.3641894e-01 -8.2252867e-01 1.4826227e+00
+1 7.4419336e-01 1 1 2.3486813e-02 -2.6233720e-01 -9.1057157e-01 1.6977060e-01 -7.1804664e-01 8.2994450e-01 -1.2316018e+00 -6.7339450e-01
+1 6.4990662e-01 1 1 -1.0978155e+00 -1.4469054e+00 -1.2785518e+00 7.6835901e-01 -1.3525546e+00 2.0590107e-01 4.2226961e-01 1.4169264e+00
+1 3.9204213e-01 1 1 -4.1098828e-01 9.2978486e-01 -1.2606686e-01 -1.2775588e+00 1.7986806e-01 -1.4557492e+00 2.2751378e-01 1.0088759e+00
+1 1.0016956e+00 1 1 8.8220475e-01 6.1225216e-01 -1.3723325e+00 8.5432955e-01 8.3029157e-01 -5.3707411e-02 5.0578816e-01 1.0009184e+00
+1 5.8148012e-01 1 1 -1.1021475e+00 1.4061918e+00 7.8112222e-01 -1.5032606e+00 -2.4407874e-01 -1.0233729e+00 -3.6809860e-01 -7.9353179e-01
+1 1.2932775e+00 1 1 -9.6194262e-01 -3.3529468e-01 -3.9454350e-01 -6.1253020e-01 6.8853863e-01 3.9185577e-01 -8.3715338e-01 -8.2790733e-01
+1 5.8333412e-01 1 1 -7.3386020e-01 7.1952706e-01 8.0952851e-01 2.0406098e-01 -1.3585234e+00 1.1416561e+00 1.1566656e+00 -5.2457307e-01
+1 1.0764222e+00 1 1 -9.5694366e-02 1.1012149e+00 -4.9219546e-01 -9.6634742e-01 3.9206597e-01 -1.0342672e+00 -9.6176975e-02 -1.1905649e+00
+1 6.6492421e-01 1 1 1.6023261e-01 9.9729527e-01 -5.1572302e-01 6.3289786e-01 1.5330074e+00 -4.9633981e-01 1.4737951e+00 -1.0213746e+00
+1 5.7395916e-01 1 1 6.8450674e-01 1.1447161e+00 -1.0267515e-01 -3.1840141e-01 1.0541954e+00 -1.0546092e+00 -1.3846074e+00 -5.8100957e-01
+1 6.4901620e-01 1 1 -7.4849289e-03 1.2925872e-01 -9.2686271e-01 -1.2401604e+00 -7.2019021e-01 4.9531699e-02 -1.3199341e+00 -9.5779831e-01
+1 6.3555189e-01 1 1 -1.3549428e-01 -1.5308834e+00 1.3764265e+00 1.0916028e+00 3.1969964e-01 -4.2787148e-02 -1.3458585e+00 -1.9551498e-01
+1 1.2117991e+00 1 1 4.0236654e-01 8.6411305e-02 -1.0887018e+00 -3.3200028e-01 1.0684877e+00 3.0112370e-01 -3.7607641e-01 8.5637471e-02
+1 1.2773078e+00 1 1 -1.2744758e+00 8.9899748e-01 -1.1758801e+00 -4.6014620e-01 7.2842196e-01 -1.1977290e-01 1.6822614e-01 4.5954131e-01
+1 5.2565668e-01 1 1 -7.3624192e-01 1.5315415e+00 7.4292972e-01 9.2388946e-01 -1.9869157e-01 7.3783090e-01 -5.6608864e-02 1.4761146e+00
+1 7.4788590e-01 1 1 7.1544424e-01 1.5493669e+00 -1.4110198e+00 -1.0822718e+00 1.0380423e-01 8.5766491e-01 4.7740176e-01 -9.9530071e-02
+1 4.7007316e-01 1 1 -1.5453448e+00 -4.5145117e-01 8.7354400e-01 7.9035762e-02 1.0537327e+00 1.1469793e+00 6.3768054e-02 -1.4746145e+00
+1 6.7328394e-01 1 1 -1.0636582e+00 -5.9351184e-01 9.9155474e-01 -5.3963824e-01 9.2746399e-01 4.6797226e-01 4.6659153e-01 1.7773356e-01
+1 1.0041449e+00 1 1 -1.2403383e+00 -5.9684976e-01 -1.0885436e+00 7.8055961e-02 -6.9551922e-01 -1.3383099e+00 5.8852879e-01 -4.8675336e-01
+1 6.3845945e-01 1 1 1.2426957e+00 -1.4864761e-01 1.4829129e+00 -1.2991918e+00 2.7477199e-01 8.2821395e-01 -1.4718394e+00 -1.5637753e-01
+1 4.4343438e-01 1 1 6.7929009e-01 -7.5419840e-01 1.0627327e+00 -1.4484791e+00 -4.8425764e-02 -6.0522002e-01 -3.0357520e-01 1.2758266e+00
+1 5.2183610e-01 1 1 2.8086774e-01 5.1378439e-01 1.3935623e+00 -3.8619068e-01 -2.1931339e-01 5.4416232e-01 -2.4190100e-01 1.4480634e+00
+1 6.8544546e-01 1 1 -1.2697137e+00 -1.0639490e+00 1.0284742e+00 -1.7631244e-01 -9.1202938e-01 5.5990856e-01 -4.0920956e-01 -3.1748852e-01
+1 5.0406022e-01 1 1 7.6010901e-01 1.5374327e-01 5.2267844e-01 -7.6128019e-01 -6.4719141e-01 1.3131597e+00 -6.3878032e-01 1.5362906e+00
+1 6.8221581e-01 1 1 1.4364717e+00 -1.5676439e+00 7.6352565e-01 8.7072784e-01 -1.1522655e+00 5.8675310e-01 -1.1586728e+00 -3.1310326e-01
+1 4.6870388e-01 1 1 -3.5925093e-01 1.1458087e+00 -8.3035616e-01 7.8417422e-01 -1.3497275e+00 1.0006593e-01 9.1893706e-01 -1.5880574e-01
+1 7.9437563e-01 1 1 2.1068376e-01 -3.5619253e-01 -8.4142438e-01 6.3498181e-01 5.7059580e-01 1.0559548e+00 5.0566113e-01 1.3056557e+00
+1 5.5587055e-01 1 1 3.8706085e-01 1.3476800e+00 -1.5110350e+00 1.4900602e-01 -1.2787507e+00 5.7466072e-01 6.3855732e-01 1.3112035e-01
+1 4.6325696e-01 1 1 -9.0670353e-01 -4.2528861e-01 6.6935355e-01 4.9486823e-01 -3.2738323e-01 1.0669347e+00 5.5242879e-01 1.4833303e+00
+1 4.6212232e-01 1 1 8.9972308e-01 -7.0232582e-01 -2.1825512e-01 1.4546034e+00 -1.4012783e+00 -2.3907828e-01 1.2643232e+00 -1.3466596e+00
+1 4.0268846e-01 1 1 1.1604293e+00 -1.0263842e+00 1.1663605e+00 -3.5500638e-01 1.2359904e+00 -9.1678103e-02 -2.5201582e-01 -1.2738392e+00
+1 4.6930870e-01 1 1 3.2848504e-01 4.6028515e-02 -5.1735126e-01 -7.0769680e-01 1.0801627e+00 -1.4534716e+00 -7.6299295e-01 5.3889032e-01
+1 4.8245321e-01 1 1 1.0697187e+00 7.6945819e-01 8.0576325e-01 -1.9039525e-01 -9.6976212e-01 5.2660059e-01 3.5863705e-01 -8.1948741e-02
+1 5.7978439e-01 1 1 -5.7219959e-01 1.4884385e+00 -9.4294456e-01 1.3099466e+00 -2.0923961e-01 7.0954324e-01 -1.1033857e+00 -1.2949028e+00
+1 6.5354690e-01 1 1 -5.4347662e-01 -3.1713072e-01 1.2656488e+00 -8.4586194e-03 -1.2479187e+00 -1.9242077e-01 2.1793088e-01 1.5220629e+00
+1 5.4893823e-01 1 1 1.5398314e+00 1.2666830e+00 3.6044112e-02 -7.9234688e-01 -4.9779368e-01 -1.3169890e+00 -3.3277018e-01 -6.7754001e-01
+1 1.0142201e+00 1 1 -4.9470986e-01 -1.4322584e+00 -5.3398784e-01 2.3721265e-01 -3.5708446e-01 1.0284468e+00 -8.3346263e-01 8.5837040e-01
+1 6.2760085e-01 1 1 1.2071401e+00 -1.0846086e+00 7.9654347e-01 1.5195839e-01 -1.0766077e+00 6.2896603e-02 3.5528371e-01 4.3779221e-01
+1 4.9189858e-01 1 1 -2.0952739e-03 -1.4969089e+00 1.1797339e+00 -1.5019585e-01 1.0288648e+00 1.5280691e+00 -9.1433331e-01 3.6365333e-01
+1 3.1460637e-01 1 1 -6.5774973e-01 -6.7409025e-01 1.1959144e+00 1.4988191e+00 8.0532533e-01 -2.6337737e-01 1.4713012e+00 1.5237540e+00
+1 6.9588417e-01 1 1 4.6475568e-01 -8.5165431e-01 -1.7698143e-01 1.3631560e+00 1.1217342e+00 -7.9484391e-02 6.8358381e-01 -5.3061927e-01
+1 5.9456886e-01 1 1 1.1493566e+00 -6.5777630e-01 5.6140828e-01 -1.0721551e+00 2.8946330e-01 -7.1727899e-01 1.8881595e-01 8.6339532e-01
+1 7.0762416e-01 1 1 -4.1680521e-01 1.8349311e-02 1.3862490e+00 4.6517599e-01 -1.3172842e+00 -1.0170042e+00 4.2100953e-01 6.8674529e-02
+1 5.8806949e-01 1 1 5.0651703e-01 5.2078195e-01 6.3644453e-01 -1.2111807e+00 -7.9282604e-01 6.1639313e-01 1.0404961e+00 1.2483095e+00
+1 4.1654069e-01 1 1 -6.8440576e-01 3.0503925e-01 -3.9979032e-01 1.2059052e+00 -1.5327916e+00 -1.2533113e+00 1.5135993e+00 7.8174369e-01
+1 9.9779418e-01 1 1 -1.4368489e+00 -2.8452093e-01 5.9081802e-01 1.2351649e+00 -5.6884697e-01 -2.3458796e-02 -1.5539139e+00 6.2576634e-01
+1 6.5318541e-01 1 1 3.0361825e-01 -4.3924358e-01 -6.9589050e-01 -2.2776483e-01 -7.4460136e-01 1.5686862e+00 -5.7068936e-01 -7.9725283e-01
+1 2.6053729e-01 1 1 9.6545501e-01 3.7589101e-01 3.1778341e-01 1.5579767e+00 -1.5515403e+00 6.6288347e-01 -2.9362945e-01 -5.3567848e-01
+1 4.1027853e-01 1 1 7.6293345e-02 -1.4265124e-01 2.7824530e-01 -2.5966466e-01 -1.5180168e+00 9.9497653e-01 4.1192493e-01 6.5638423e-01
+1 7.8653520e-01 1 1 4.9244982e-01 -5.0418034e-01 -1.3627184e+00 -5.1166395e-01 -4.3470698e-01 -1.2723169e-01 -8.4797543e-01 -1.4237283e+00
+1 8.9613463e-01 1 1 -1.4925730e+00 -8.8360260e-01 -9.9852300e-01 -9.9688228e-01 1.2242733e+00 1.0416250e+00 1.4827859e+00 9.0989564e-01
+1 5.8200688e-01 1 1 -5.7315798e-02 -4.0044957e-01 2.1186612e-01 -4.8694127e-01 -1.0699330e+00 -1.5049098e+00 -1.0726221e+00 -6.5704355e-01
+1 6.2125261e-01 1 1 1.1623212e+00 -1.0644333e+00 1.4093498e+00 -1.7306814e-01 1.1173346e-01 -5.6845277e-02 -1.1003114e+00 -2.3285078e-01
+1 1.0290132e+00 1 1 7.0907898e-01 1.4391779e+00 -6.6630979e-01 3.5859916e-01 -7.6814070e-01 -3.5440582e-01 -1.5194266e+00 9.0146128e-01
+1 3.3407904e-01 1 1 1.4295643e+00 1.1408829e+00 1.1092312e+00 1.4014214e+00 -1.3365920e+00 -3.9009427e-02 1.0044188e+00 -1.0415738e+00
+1 6.3615948e-01 1 1 -2.1304907e-01 -1.4625116e+00 6.3789694e-01 1.1692833e+00 1.4278354e+00 9.6143005e-01 1.4891243e+00 -7.7625153e-01
+1 5.1300586e-01 1 1 6.9982392e-01 -6.1073005e-01 -1.1219269e+00 1.4823179e+00 -9.9680454e-01 1.5438263e+00 -1.3563035e+00 5.7488156e-01
+1 6.4254443e-01 1 1 -1.8219801e-01 -9.5669608e-01 -3.8579206e-01 4.8673927e-01 8.1967512e-01 6.7501587e-01 4.2012689e-03 -1.5046310e+00
+1 5.5916753e-01 1 1 8.5086737e-01 -5.1979671e-01 2.4016293e-01 -8.0397819e-02 3.9599211e-01 7.0064317e-01 1.4956872e+00 1.4884355e+00
+1 1.1100039e+00 1 1 -1.8096450e-03 5.4580687e-01 -5.2816713e-01 -3.6130842e-01 1.5462220e+00 1.0205206e+00 -1.0090552e+00 -3.6618231e-01
+1 5.9281192e-01 1 1 1.0012226e+00 -7.4504783e-02 1.2358384e+00 1.8791242e-01 9.8636462e-02 -1.2062467e+00 -8.7367513e-01 -4.6148817e-02
+1 5.3273246e-01 1 1 1.1778463e+00 1.2935809e+00 -1.4740115e+00 9.4338670e-01 -9.7789928e-01 -6.9020448e-01 -5.3915270e-02 3.5022538e-01
+1 4.8715512e-01 1 1 8.8777909e-01 1.3928150e+00 8.8846515e-01 -1.1784988e-01 1.2595156e+00 -1.5066219e+00 -1.3752617e+00 -1.1066412e+00
+1 4.4143696e-01 1 1 1.4796408e+00 1.0353260e+00 4.4395951e-01 -1.4994837e+00 6.2809482e-01 -5.5676537e-01 -1.3254278e+00 -1.0905082e+00
+1 3.7573780e-01 1 1 -5.2381297e-01 -5.5712642e-01 3.4485468e-01 3.4228569e-02 6.3834774e-01 1.2489881e+00 5.6924507e-01 -1.1984018e-01
+1 6.7502558e-01 1 1 -9.8193401e-01 1.4639383e+00 -2.6580858e-01 3.6811119e-01 1.7150245e-01 -3.7866884e-01 1.1522991e+00 -3.9301114e-01
+1 1.0346758e+00 1 1 -5.7876239e-01 -5.4286382e-01 -1.0008376e-01 1.0488989e+00 -1.5403528e+00 5.7960457e-01 -1.2281038e+00 1.4310368e+00
+1 1.2568649e+00 1 1 -8.8858578e-01 -7.2710641e-01 -1.3556489e+00 1.3673888e+00 1.1551362e+00 -6.6483373e-01 -4.7652290e-01 -5.9843846e-01
+1 7.4555153e-01 1 1 6.7031487e-01 3.1798452e-01 -1.5614340e+00 9.5394092e-01 -6.6811731e-01 7.8457236e-01 -1.0006865e+00 1.4245321e+00
+1 1.0527127e+00 1 1 2.3073675e-01 5.1671303e-01 -1.2971262e+00 1.3377297e+00 -9.9549963e-01 1.0432204e+00 1.5490697e+00 3.2837236e-02
+1 8.1789992e-01 1 1 1.2672344e+00 1.0337249e+00 -1.2891746e+00 -1.1555317e+00 7.6024325e-01 1.7741596e-01 8.3574958e-01 -1.0248758e+00
+1 7.7240408e-01 1 1 1.5515699e+00 8.0743032e-01 4.0628719e-01 3.0366859e-01 5.5098184e-01 4.5853690e-01 3.8250572e-01 2.6489574e-01
+1 8.3566504e-01 1 1 -1.1255608e+00 -1.1989107e+00 -1.3536110e+00 -1.3300407e+00 -1.0632748e+00 3.0290483e-01 1.0749862e+00 4.6586464e-01
+1 4.1351719e-01 1 1 1.3705838e+00 8.2534364e-02 1.2740754e+00 -1.5624695e+00 -1.0812670e+00 1.5414529e+00 -6.9807971e-03 9.3817629e-01
+1 6.7847862e-01 1 1 1.2443935e+00 -1.4288909e+00 2.8937670e-01 1.4796594e-01 1.2587120e+00 -1.5164710e+00 -1.0873289e+00 2.7529371e-01
+1 8.3179855e-01 1 1 9.3931225e-01 -1.0349679e+00 3.6869320e-01 -1.2778774e+00 -3.1313823e-01 4.1374173e-01 -9.2250038e-02 -7.0459853e-01
+1 3.3669920e-01 1 1 5.1782218e-01 2.9344430e-01 1.4058689e+00 -1.3573891e+00 -7.4653970e-01 1.4126632e+00 1.5003851e+00 -1.5247674e+00
+1 7.0600183e-01 1 1 8.2569178e-01 -3.8207184e-01 5.2091592e-01 6.0789267e-01 4.2824731e-01 -1.5263240e+00 -5.9169177e-01 -7.9495774e-01
+1 9.5681061e-01 1 1 9.8693718e-01 -6.6006897e-02 -5.8490092e-01 3.9282482e-01 1.6372459e-01 1.3176419e+00 -1.4227775e+00 3.3879155e-01
+1 8.5303203e-01 1 1 -1.5599250e-01 -3.9570583e-01 -3.8642611e-01 -1.4210010e+00 -3.1602786e-01 5.2117765e-01 1.1825722e+00 1.5036770e+00
+1 7.3703091e-01 1 1 1.4639601e+00 1.2371625e-01 -9.9154821e-01 -3.7667060e-01 9.5285085e-01 6.7238927e-01 -1.3650631e+00 1.3286014e+00
+1 2.1996507e-01 1 1 -1.7688239e-01 -4.3529797e-01 1.1983012e+00 -3.9365416e-01 -1.2750644e+00 5.3763852e-01 4.3565688e-01 -6.3712728e-01
+1 8.3839361e-01 1 1 -9.1567576e-01 7.1623914e-01 -9.0270388e-01 4.8679459e-02 -1.2031416e+00 8.7012376e-01 -9.6733258e-01 1.4912110e+00
+1 9.4267899e-01 1 1 8.9987305e-01 -7.5178286e-01 -9.9312037e-01 1.3415703e+00 1.2306337e+00 5.6182365e-02 -2.1671890e-01 -8.4321288e-01
+1 9.6884835e-01 1 1 5.3937547e-01 2.7110333e-01 -9.2349483e-02 5.6207614e-01 -9.8478088e-01 -1.3623875e+00 -1.2886168e+00 -1.5448958e-01
+1 6.6875383e-01 1 1 -1.3528523e+00 1.1243714e+00 -1.7098335e-01 4.4505436e-02 -1.3021804e+00 1.4229741e+00 3.5678058e-01 -1.5509184e+00
+1 6.8134683e-01 1 1 1.4592746e+00 6.2971754e-01 8.4016886e-01 3.0380860e-01 -1.4116056e+00 -1.0183581e+00 -8.8913997e-01 -4.9187979e-01
+1 6.3145995e-01 1 1 -3.8488527e-01 -3.6290759e-01 -7.4101054e-01 1.0230342e+00 4.5323717e-01 -1.4701239e-01 7.8079789e-01 -1.4934193e+00
+1 1.0028716e+00 1 1 -2.2750758e-01 -1.5564716e+00 -8.9093471e-01 1.9977128e-01 -8.0512699e-01 -1.5453310e+00 4.3766993e-01 1.4272840e+00
+1 6.8089986e-01 1 1 -4.0158734e-01 4.2367769e-01 -1.1090157e+00 -8.0660689e-01 -9.2983477e-01 -8.3111181e-01 1.4501195e+00 -8.4004829e-01
+1 6.9443379e-01 1 1 -1.3373271e+00 -1.2395923e+00 -1.5687585e-01 -6.6974208e-01 -1.4510959e+00 -9.7518709e-01 -3.1728829e-01 -3.7417356e-01
+1 8.6639729e-01 1 1 -1.5022164e+00 1.2148218e+00 -8.1614787e-01 -2.8740235e-02 -3.8428855e-01 -2.8054529e-01 -1.3815375e+00 7.3349503e-01
+1 7.8996891e-01 1 1 1.2286172e+00 2.9885485e-01 -8.0375237e-01 7.6814267e-01 3.7683493e-01 4.0580733e-01 1.1154050e-02 2.4143138e-01
+1 6.0018064e-01 1 1 -3.1992021e-01 -5.5322116e-01 1.8234108e-01 1.3695635e+00 1.3875128e-02 6.0771643e-03 -1.0294349e+00 -1.2005349e+00
+1 2.9501772e-01 1 1 1.5076758e+00 1.1261451e+00 1.5537671e+00 -1.9578475e-01 7.2141524e-01 -1.5336569e+00 -9.6208128e-01 1.0593254e+00
+1 6.7407481e-01 1 1 -5.7862562e-01 -9.7523303e-01 1.2448763e+00 -1.3068089e+00 1.4199719e+00 5.9668386e-01 7.7253202e-02 6.7576263e-01
+1 9.0255104e-01 1 1 1.4100038e+00 -1.0526100e+00 -3.7129973e-01 -6.6313927e-01 -1.2112279e+00 5.0182322e-01 9.1680525e-01 6.8516119e-01
+1 7.9003001e-01 1 1 9.0027989e-01 -9.0764696e-01 -1.2315609e+00 9.8902729e-01 4.1252340e-01 -1.0334166e+00 -7.6609405e-01 1.5669973e+00
+1 5.7783603e-01 1 1 1.0939083e+00 7.5150721e-01 1.1097049e+00 4.1497649e-01 -2.1420197e-01 1.2329888e+00 -1.4960860e+00 5.5173720e-01
+1 6.8236163e-01 1 1 7.1708850e-01 1.3792513e+00 -8.2486103e-01 1.7414911e-01 1.7267329e-01 8.9803744e-01 5.8994900e-01 -9.3433124e-01
+1 5.9498864e-01 1 1 9.5694164e-01 -7.3542048e-01 4.0903732e-01 -1.0403060e+00 -7.1168857e-01 1.1040635e+00 4.0637729e-01 1.5165677e+00
+1 2.0381842e-01 1 1 1.5053730e+00 -1.1864997e+00 8.8551766e-01 -1.4590689e+00 -1.3064962e+00 -1.3928745e+00 1.6076778e-01 1.2123616e+00
+1 3.3310942e-01 1 1 1.5591926e+00 1.3290807e+00 1.1709238e+00 7.0134380e-01 1.4517547e+00 1.1070894e+00 2.5446305e-01 -2.0894116e-01
+1 5.1614114e-01 1 1 1.3254022e+00 1.1356799e+00 7.7933065e-01 2.2963006e-01 -1.1089618e+00 -8.0203514e-01 1.0527983e+00 6.2653636e-01
+1 4.5334141e-01 1 1 -9.9875999e-01 -9.4431714e-01 9.1046704e-01 1.5166479e+00 7.4869768e-01 7.6947220e-01 9.3080401e-01 -4.2189567e-01
+1 6.4490475e-01 1 1 -6.2960426e-01 1.8789515e-01 -4.7833118e-01 -5.8170148e-01 1.2833003e+00 -1.4176820e+00 -1.1083895e+00 -2.2582555e-01
+1 9.9876366e-01 1 1 -8.7479485e-01 6.5313405e-01 2.3488303e-02 -2.0392273e-02 1.3941742e+00 -1.1421222e+00 9.4253122e-01 -4.0614873e-01
+1 4.1659145e-01 1 1 -2.3475931e-02 4.9919338e-01 -1.0727611e+00 -2.9932800e-01 -1.2533389e+00 -5.1720548e-01 1.2120960e+00 5.3910454e-01
+1 3.6886511e-01 1 1 1.2806955e+00 -1.2507591e+00 -2.9473013e-01 -1.1157786e+00 -4.8788763e-01 1.1438982e-01 -1.5310926e+00 3.7682087e-01
+1 8.5730162e-01 1 1 -1.5428681e+00 -1.1118475e+00 7.6226916e-01 -7.2466771e-01 -3.7055689e-01 -1.0495734e-01 -2.8711426e-01 -2.2238389e-01
+1 1.9093862e-01 1 1 -2.7780477e-01 -6.2852028e-01 4.2914155e-02 4.6459362e-01 -1.3129614e+00 1.5571196e+00 -4.3109258e-02 8.8915660e-01
+1 1.1565909e+00 1 1 -6.5814583e-01 -1.5058273e+00 -1.3080993e+00 1.5671475e+00 -3.9468154e-01 1.0421288e+00 1.1706114e+00 -5.0124070e-01
+1 7.4320479e-01 1 1 9.0816276e-02 2.3109233e-01 -3.5871990e-01 -6.4030389e-02 -1.5106241e+00 6.7953737e-01 -1.3286789e+00 1.3990659e+00
+1 6.7956212e-01 1 1 -4.6488388e-01 9.6027867e-01 -2.8901565e-01 1.4075318e+00 1.2927307e+00 1.2952849e+00 -6.6538304e-01 -7.1965725e-01
+1 8.7604331e-01 1 1 -1.6237050e-01 1.0421972e+00 -5.8386464e-01 1.9440888e-01 -3.2918660e-01 -1.3832269e+00 9.7705391e-01 -1.4766752e-01
+1 4.5097546e-01 1 1 1.0830969e+00 -1.3114697e+00 1.3223680e+00 1.7375847e-01 -2.9446569e-01 -1.0943373e-01 2.4020528e-01 1.0198895e-02
+1 4.6212354e-01 1 1 1.2213926e+00 -4.5667464e-01 1.4127065e+00 -1.3225349e+00 -1.0763748e+00 -1.4209665e+00 1.8358499e-01 -1.3747669e+00
+1 5.7127358e-01 1 1 7.7956276e-01 -4.1983418e-01 -7.9957368e-01 -1.0754142e+00 -1.3399788e+00 2.0280204e-01 4.6894793e-01 7.0675051e-01
+1 6.8202431e-01 1 1 -1.4715800e+00 -1.3590639e-01 1.2986100e+00 -9.0450996e-01 1.0533477e+00 -1.3418701e-01 -6.4819077e-01 -6.0608338e-03
+1 2.5645846e-01 1 1 9.1388362e-01 -2.4085258e-01 1.0933039e+00 6.7910738e-02 7.4004357e-01 3.8242182e-01 9.0109096e-01 -1.3334682e+00
+1 9.3349113e-01 1 1 3.9559762e-01 1.5036834e+00 -1.6878067e-02 9.7764489e-01 3.4696223e-01 -3.3506885e-01 -9.8235935e-01 5.2275684e-01
+1 9.5657838e-01 1 1 1.1991811e+00 1.4361707e+00 -9.2633288e-01 7.4804278e-01 5.9824059e-01 1.3733966e+00 -1.4442012e+00 -1.0603618e+00
+1 7.5262973e-01 1 1 1.3191814e+00 8.6399835e-01 8.5639338e-01 -2.9887773e-01 1.5331520e+00 1.3957151e+00 -7.4474383e-01 7.5514268e-01
+1 9.3531564e-01 1 1 1.2627209e+00 7.7896356e-01 -1.3739772e+00 1.6870094e-01 3.4270961e-01 -4.8939660e-01 -8.0435373e-01 -3.5123414e-01
+1 5.2571932e-01 1 1 1.0923056e+00 1.0239210e+00 1.4125851e+00 -1.5014673e+00 1.3809978e+00 -5.9913608e-01 -5.0001681e-01 -1.3966645e-01
+1 9.3626148e-01 1 1 -1.0872393e+00 -6.0479392e-01 3.0193991e-01 1.2528436e+00 3.4365262e-01 -8.7561864e-01 -2.2205314e-02 -6.0439065e-01
+1 7.0652170e-01 1 1 1.4138674e+00 1.4224111e+00 1.0319025e+00 -1.5530683e+00 1.5222555e+00 -1.3024396e+00 6.4481526e-01 -1.2245924e+00
+1 6.3031735e-01 1 1 -1.3716850e-01 -1.0567509e+00 -1.5468858e+00 1.0746984e+00 -5.8263732e-01 5.1451985e-01 -1.0845356e+00 -1.1517680e+00
+1 4.9095514e-01 1 1 5.3807641e-01 -1.3893185e+00 1.3107713e+00 1.4390783e+00 -4.1172354e-02 -1.2694906e+00 -2.6966021e-01 7.2914198e-01
+1 3.8367684e-01 1 1 -1.1950714e+00 1.1815346e+00 1.2853804e+00 -5.3338684e-01 -8.3337001e-01 1.3690576e+00 1.1391031e+00 -6.6362874e-01
+1 9.0117448e-01 1 1 -1.3624479e+00 4.4057904e-02 -1.3445034e+00 1.4727300e+00 -1.2297138e+00 7.2711066e-01 4.0721506e-02 -9.5434177e-01
+1 6.7726136e-01 1 1 4.0653665e-01 -9.3466819e-01 4.0749066e-01 -4.3610421e-01 7.3760896e-01 -2.4663228e-01 -4.6084610e-01 1.3499658e+00
+1 2.7831191e-01 1 1 -3.0258336e-01 -1.0049750e+00 2.3521370e-02 -2.6784951e-01 2.6914830e-01 -1.3879986e+00 -1.4145682e+00 2.9248678e-01
+1 6.4449277e-01 1 1 7.2000579e-01 -1.4129651e+00 -5.1701512e-01 1.5554649e-01 -3.1794982e-01 1.3747614e+00 9.2550196e-01 -7.6711224e-01
+1 9.3634215e-01 1 1 -2.7755292e-01 -4.0576363e-01 1.7219033e-01 4.6477573e-01 6.6398532e-02 -7.9900192e-01 8.8615136e-01 2.4085698e-01
+1 3.1103579e-01 1 1 4.3308198e-01 7.2836900e-01 5.9607129e-01 1.4864234e+00 6.9472784e-01 1.4832970e+00 -7.4483411e-01 -1.4296512e+00
+1 7.1723983e-01 1 1 -2.6130038e-01 -1.0887259e+00 -3.6884853e-01 3.7342364e-01 -1.0090540e+00 1.2355482e+00 8.1990967e-01 -1.2467951e+00
+1 7.5152843e-01 1 1 2.7101060e-01 1.5602686e+00 -8.7497658e-01 -7.7097401e-01 -8.5402991e-01 -6.8152607e-02 1.1965001e+00 -4.6305218e-01
+1 3.3265107e-01 1 1 -4.3423990e-01 5.6031999e-01 6.3788418e-02 1.3094328e+00 2.5613707e-01 1.2404543e+00 2.4280908e-01 -7.9295237e-01
+1 2.2068420e-01 1 1 -3.5023375e-01 -1.1966469e+00 8.0884624e-01 7.8129675e-01 9.1386748e-01 7.0611541e-01 -3.6725806e-02 -5.1450592e-01
+1 2.1054418e-01 1 1 9.6605125e-01 4.3159914e-01 6.0741276e-01 -6.0277719e-01 1.2427716e-01 -1.2553765e+00 -1.4984567e+00 1.5036351e+00
+1 1.0235135e+00 1 1 6.7244829e-01 -5.0652686e-02 -1.3898911e+00 7.6013209e-01 -4.3285169e-01 -1.7580502e-01 -1.5555351e+00 6.2383204e-01
+1 5.4826791e-01 1 1 1.5296855e+00 5.1909329e-02 9.8396374e-01 -1.3173060e+00 9.9016109e-01 1.4836763e+00 4.5625966e-01 1.2504693e+00
+1 1.1035470e+00 1 1 -1.3708497e+00 -9.2267174e-01 1.3491663e-01 -1.1586845e+00 6.2118957e-01 1.3259227e+00 -2.7157598e-01 -6.1665757e-01
+1 6.1184815e-01 1 1 5.6995819e-01 -4.4265935e-01 -6.8606654e-01 7.2196849e-01 8.2066828e-01 1.4665721e+00 3.5660576e-01 -4.9588315e-02
+1 1.1341903e+00 1 1 5.7133460e-01 -4.8426892e-01 -1.0752804e+00 1.2935072e+00 1.3801012e+00 -2.5861937e-01 -6.8570080e-01 -9.0876456e-01
+1 5.9442616e-01 1 1 -1.4280366e+00 7.5875568e-01 1.3447330e+00 1.5401031e-01 9.8240131e-01 1.3485631e+00 -1.2114284e+00 8.1747515e-01
+1 7.2612744e-01 1 1 7.5742709e-01 6.8208974e-01 3.0937147e-01 -2.2105281e-01 -9.9215495e-01 -1.2905106e+00 1.8509536e-01 1.1201368e+00
+1 2.1263102e-01 1 1 3.4362592e-01 2.1068263e-01 2.7039196e-01 1.2695417e+00 4.2548673e-01 -5.5801397e-02 7.2090960e-01 -1.4250718e+00
+1 1.1288209e+00 1 1 1.0734887e+00 3.6798113e-01 -1.4068750e+00 -5.0975734e-01 8.9061094e-01 1.4821191e+00 -7.9513558e-01 3.2088759e-01
+1 2.9061009e-01 1 1 -4.1369776e-02 -1.1370564e+00 1.4191916e+00 -3.6847330e-01 -1.1909958e+00 2.8805373e-01 4.9145802e-01 -9.5681892e-01
+1 6.2185003e-01 1 1 -1.0098532e+00 -1.9898619e-01 1.3825033e+00 -8.5165157e-01 1.1615689e+00 1.2484117e-01 6.8787505e-01 5.5715419e-01
+1 9.5821115e-01 1 1 1.4216405e+00 1.4353112e+00 5.1383706e-01 -6.1174894e-01 6.3174405e-01 -3.7840335e-01 5.5039567e-02 -9.9717366e-01
+1 8.5938153e-01 1 1 -1.4421397e+00 -1.0141570e+00 -1.7878295e-01 7.6837127e-01 -8.6096826e-01 -1.2415824e+00 1.4217559e+00 8.9902652e-01
+1 9.6817307e-01 1 1 -6.5433292e-01 1.3451466e+00 -1.4424656e+00 -1.0714930e+00 -1.1778006e-01 -8.1675779e-01 4.9705784e-01 -1.1219202e+00
+1 8.4251177e-01 1 1 1.3425201e+00 9.7779253e-01 1.5144920e-01 -9.7344143e-01 -3.2603190e-01 1.5116961e+00 5.5628249e-01 -2.7367413e-01
+1 2.5085126e-01 1 1 8.1675486e-01 8.7919758e-02 7.1666518e-01 7.8446389e-01 -6.8055626e-01 1.0160172e+00 6.0001090e-02 -3.4947024e-01
+1 3.8608467e-01 1 1 -1.5609444e+00 1.1188236e+00 1.2545784e-01 -7.7980226e-01 4.2970865e-01 -1.4964981e+00 -1.2924671e-02 1.2319705e+00
+1 8.3439545e-01 1 1 6.4843110e-01 -1.5053202e+00 5.6123568e-01 5.8801622e-01 -4.0818378e-01 -5.2606267e-02 -4.5505757e-01 -5.0899719e-01
+1 4.9456596e-01 1 1 -3.4878593e-03 -6.7031381e-01 -1.5147039e+00 -6.6179950e-01 8.9355100e-01 -1.3659967e+00 -1.5160455e+00 -1.5893264e-01
+1 3.8890122e-01 1 1 1.0698092e+00 -2.1291098e-01 -1.3034005e+00 1.5154608e+00 1.0988522e+00 4.5244614e-01 1.2810492e+00 -8.2719109e-01
+1 3.3731534e-01 1 1 9.4886692e-01 -1.2087852e-01 7.2879566e-02 1.4572019e+00 -1.0142128e+00 -1.5336064e+00 1.2589941e+00 -1.0531667e+00
+1 3.7777930e-01 1 1 8.8194467e-01 1.0052423e+00 -3.3427144e-01 -6.6469188e-01 4.0733915e-01 1.4441331e+00 1.2866771e+00 -8.3918357e-01
+1 9.5544144e-01 1 1 8.0988944e-01 -3.7817621e-01 -9.3236859e-01 2.7108360e-02 6.1866025e-01 -3.9999002e-01 -1.5411568e+00 -1.5488017e+00
+1 7.9759557e-01 1 1 -7.0908802e-01 -5.6555971e-01 -5.4677866e-02 7.9270146e-02 -8.4890054e-01 3.7602783e-01 2.0937911e-01 5.2699538e-01
+1 4.3349677e-01 1 1 1.5601774e+00 1.0973814e+00 1.5157542e+00 2.5806681e-01 -1.4991655e+00 -9.8467084e-01 4.5099219e-01 1.0617229e+00
+1 6.1997919e-01 1 1 -9.7252382e-01 -6.0207247e-01 1.0602505e-01 -1.2106161e+00 -9.0203816e-01 5.4734737e-01 -8.3733570e-01 1.3080575e-01
+1 3.8383564e-01 1 1 4.9878831e-01 3.7987545e-02 6.7990731e-01 1.2703360e+00 7.7078210e-01 6.8395454e-01 1.2339967e+00 -6.6259278e-01
+1 4.9945074e-01 1 1 1.3659038e+00 7.1335634e-01 1.2296778e+00 2.7369924e-01 -1.3933696e+00 1.3641219e-01 -1.0118278e+00 7.4916608e-01
+1 5.4227531e-01 1 1 1.1268963e+00 1.0624794e+00 -1.3430458e+00 7.7141228e-01 -9.3150615e-01 -6.8300173e-01 -3.4862564e-01 -2.6897992e-01
+1 7.1574189e-01 1 1 -9.1533046e-01 2.7853403e-01 -2.2672184e-01 -2.2671638e-01 -1.2677359e+00 1.6940805e-01 -2.8078167e-01 6.3266899e-03
+1 4.8994619e-01 1 1 4.2019182e-01 3.4832970e-01 2.3798457e-01 3.2971965e-01 -5.5547819e-01 9.5810722e-01 -4.2541016e-01 -4.8147364e-01
+1 9.6238598e-01 1 1 -1.3638127e-01 -1.5513833e+00 5.5925441e-01 -1.7120496e-01 8.9138650e-01 -8.9584821e-01 3.9623730e-01 6.1525135e-01
+1 6.2531675e-01 1 1 1.2026290e+00 1.1191886e+00 -2.5633127e-01 2.5718438e-01 -7.2242834e-01 1.1326927e+00 -6.1618701e-01 1.5479448e+00
+1 5.4377421e-01 1 1 -4.2194617e-01 1.4867490e+00 -1.0361358e+00 -3.3354308e-01 4.0251016e-01 -8.8607729e-01 -1.5657252e+00 7.7944505e-01
+1 6.0301147e-01 1 1 -1.0747254e+00 -4.3683336e-01 -4.8626671e-01 -1.2573305e+00 1.1393051e+00 -1.1518808e+00 -1.1639154e+00 -3.0832780e-01
+1 8.4013618e-01 1 1 1.2473550e+00 4.3761483e-02 -1.4021529e+00 1.5406529e+00 2.9337608e-01 -1.1662656e+00 7.7197221e-01 1.5625924e+00
+1 5.7847705e-01 1 1 4.4688590e-01 3.6657189e-01 -8.9720862e-01 7.4729919e-01 -1.5286251e+00 -1.0297819e+00 -2.4069439e-01 -1.2236875e+00
+1 8.8670151e-01 1 1 -7.3673169e-01 3.1057655e-01 2.5940666e-01 -2.2986927e-01 3.4197072e-01 -5.1038036e-01 1.0207117e+00 1.4916168e+00
+1 1.0774965e+00 1 1 -1.2328423e+00 -1.4669978e+00 -6.8290413e-01 7.4617550e-01 1.5288822e+00 -1.4146981e+00 -1.1366934e+00 -3.0645662e-01
+1 1.0991838e+00 1 1 1.5650163e+00 -6.1210571e-01 -1.3317961e+00 -2.6618435e-01 8.3700904e-01 -1.2580930e+00 -3.8167786e-01 -1.5460210e+00
+1 5.8349033e-01 1 1 -1.3256556e+00 1.0552638e+00 3.5055948e-01 -1.3245689e-01 -4.4099998e-01 1.2915268e+00 2.7242850e-01 1.3754465e-01
+1 7.8629642e-01 1 1 -1.1899748e-01 1.5275567e+00 1.3669809e+00 1.1862897e+00 -8.6956411e-01 1.4270616e+00 1.4052518e+00 -4.9928600e-01
+1 7.8280038e-01 1 1 1.2039151e+00 5.5096526e-01 3.8138560e-01 1.4234718e+00 -7.4905719e-02 -1.4364328e+00 -4.2629599e-01 -3.0586059e-01
+1 5.1710084e-01 1 1 -7.9774237e-01 -1.3419961e+00 1.0987132e+00 1.0627243e+00 8.3823305e-01 1.0131738e+00 1.2161695e+00 -9.5333288e-01
+1 2.4925507e-01 1 1 6.6136493e-01 -1.4342764e+00 -2.0929538e-01 1.2526773e+00 1.2814605e+00 9.8002213e-01 9.5963312e-01 -5.4313094e-01
+1 3.9735946e-01 1 1 6.0549828e-01 -4.4381890e-01 9.5638281e-01 -1.2068509e+00 -1.2524845e+00 -1.3840662e-01 -3.8286814e-01 1.0664690e+00
+1 4.9427081e-01 1 1 9.9093937e-01 -1.1233408e+00 1.5378899e+00 -1.4203846e+00 1.3056629e+00 -1.4215037e+00 -8.8300050e-01 1.3591801e+00
+1 4.9258389e-01 1 1 1.1353173e+00 9.8321083e-01 1.4320921e+00 5.5851813e-01 2.5226180e-01 6.0021843e-01 2.9425113e-01 1.2197151e+00
+1 5.1366117e-01 1 1 -7.5670802e-01 4.7058345e-02 1.4313916e+00 -6.4656951e-02 -1.3859422e+00 2.1722057e-01 6.1197466e-01 8.5955789e-01
+1 1.2367759e+00 1 1 -8.2459399e-01 -7.7174560e-01 -9.1847458e-01 3.0168287e-01 1.3784284e+00 2.9547560e-01 -1.1629658e-01 1.5463825e+00
+1 7.9221109e-01 1 1 -1.3859396e+00 9.0784107e-01 9.8394997e-01 -1.4648711e-01 1.1426739e+00 -7.9951087e-01 -5.2605790e-01 -3.4585625e-01
+1 9.2376082e-01 1 1 1.4224888e+00 -6.3068955e-01 -9.6621635e-02 9.9976221e-01 3.6352263e-01 -7.8745145e-01 -1.0133559e+00 -8.5955434e-01
+1 6.9734486e-01 1 1 2.4957043e-01 -2.6557132e-01 2.8358307e-01 -1.3756350e+00 -6.7284764e-01 8.3332135e-01 -8.9927340e-01 -1.4868075e+00
+1 8.7653559e-01 1 1 5.0406924e-01 7.4605820e-01 3.8455766e-01 -1.3164205e+00 1.1832611e+00 4.1189226e-01 1.1419074e-01 -5.4616546e-01
+1 7.4436743e-01 1 1 -9.8375094e-01 9.0392770e-01 1.0045226e+00 1.1574192e+00 7.8837540e-01 -1.3970582e+00 -3.0937170e-01 3.3081072e-01
+1 5.9957714e-01 1 1 3.0012627e-01 -4.2923273e-01 9.2366864e-02 2.1063116e-03 -1.0124603e+00 -9.3931785e-02 -2.7435051e-01 -6.8318586e-01
+1 5.3810646e-01 1 1 -1.1755539e+00 -1.0176933e+00 4.6310463e-01 8.4326064e-01 -1.5546923e+00 1.5095935e+00 8.4897879e-01 2.1634928e-01
+1 9.9167530e-01 1 1 -5.7566139e-02 -1.5407089e+00 -1.4670393e+00 9.5716541e-01 -1.0867103e+00 2.3566308e-01 -3.2735271e-01 1.3597069e+00
+1 7.3123285e-01 1 1 9.6442847e-02 1.4541748e+00 -1.3109741e+00 -1.0169197e+00 8.8033592e-01 -7.5899115e-01 -8.8824043e-01 6.4895849e-01
+1 8.1504139e-01 1 1 -1.4687373e-01 -1.2745372e+00 -1.5525415e+00 -1.1060964e+00 -1.0955166e+00 -1.4980140e+00 1.9137125e-01 -5.6440956e-01
+1 7.7803391e-01 1 1 7.8504993e-01 1.3740871e+00 5.0440890e-01 -1.3584972e+00 5.2743322e-01 -3.9699147e-01 -6.1424614e-01 -1.5633093e+00
+1 4.8538083e-01 1 1 -3.5497137e-01 4.3443478e-01 -1.5581423e+00 8.3225176e-01 -1.0043573e+00 5.0710992e-01 -3.6138417e-01 -1.4001546e+00
+1 8.0445442e-01 1 1 -1.1929898e-01 4.8403349e-01 6.1849534e-01 1.2848880e+00 -4.5643463e-01 -1.4450647e-01 -1.0851915e+00 1.2729448e+00
+1 9.3099939e-01 1 1 -7.2192742e-01 1.5674783e+00 -4.7895642e-01 -1.9589690e-01 4.7238432e-01 -2.6910919e-01 1.2728384e+00 1.3661633e-01
+1 5.5340249e-01 1 1 -6.0339185e-01 -7.8869912e-01 -1.0601092e+00 -5.0051342e-02 5.5857583e-01 9.7519198e-01 1.4907149e+00 -3.9358920e-01
+1 1.3236927e+00 1 1 -1.4572404e-01 -1.2867644e+00 -1.2826581e+00 7.3392300e-01 9.0508934e-01 3.6278969e-01 2.4353205e-01 1.1405015e+00
+1 7.2405919e-01 1 1 1.2583545e+00 7.5042808e-02 -2.5364504e-02 1.1511519e+00 2.4482682e-01 -4.2496683e-01 -4.5204588e-01 1.5521208e+00
+1 1.3748995e-01 1 1 -3.8342668e-02 1.4658149e+00 9.5537376e-01 1.4816631e+00 -6.8208878e-01 1.5640995e+00 -1.1640714e+00 -1.2916602e+00
+1 1.0242443e+00 1 1 -3.9872941e-01 -4.1881338e-01 2.8681225e-01 -1.0939635e+00 -1.9450421e-01 -1.0277110e+00 1.2902267e+00 -5.2802409e-01
+1 4.5791986e-01 1 1 -4.2810310e-01 1.3126069e+00 1.2504014e+00 1.4972693e+00 1.3657526e+00 -2.6238967e-01 1.5679019e+00 4.9841306e-01
+1 5.5776042e-01 1 1 -8.8160309e-01 7.2133165e-01 1.3830779e+00 4.4714150e-01 -1.4129680e+00 8.1286503e-01 4.7284148e-02 1.3423083e+00
+1 8.5010948e-01 1 1 -1.3521453e+00 1.4932715e-02 7.4705940e-01 4.1756245e-01 -4.5513485e-01 -9.6387846e-01 -1.1826944e-01 3.9840671e-01
+1 8.9383517e-01 1 1 7.7578128e-01 -3.5326979e-01 -1.1185226e+00 -3.4583126e-01 3.2662656e-01 1.2880699e+00 8.7371610e-01 1.2876330e+00
+1 7.3266548e-01 1 1 9.4646786e-01 2.0474840e-01 2.8096446e-01 -4.3965304e-01 1.2502307e+00 -1.2370546e-01 7.4245702e-01 -1.1843426e+00
+1 4.3269656e-01 1 1 1.4016750e+00 1.1624792e+00 3.5587323e-01 -2.2280058e-01 -1.4853952e+00 6.1670281e-01 6.9047623e-02 -1.1438901e-01
+1 6.5219168e-01 1 1 -8.5128178e-01 2.2362389e-01 -4.3098473e-01 1.6915146e-01 1.1992800e+00 8.0994946e-01 1.2357125e+00 1.1862786e-01
+1 5.8088157e-01 1 1 -6.7998689e-01 1.1019443e+00 9.5227980e-01 -2.1283250e-01 -1.6006631e-01 2.9960449e-01 -4.4893972e-01 -1.1329725e+00
+1 4.1239885e-01 1 1 5.7436767e-01 6.8969200e-01 -1.4479004e+00 1.1982528e+00 -1.0310930e+00 -5.2031541e-01 7.7574814e-01 -6.7594745e-01
+1 5.6770696e-01 1 1 -7.1681798e-01 -8.2352946e-01 -8.4935377e-02 1.4258125e+00 -5.5441169e-01 1.2528015e+00 3.8946797e-01 -6.4977597e-01
+1 9.2320742e-01 1 1 4.4811801e-01 7.9763458e-01 -1.2258200e+00 -4.3742323e-01 -3.3488333e-02 8.8100126e-01 -1.2908351e+00 -6.0858304e-01
+1 6.6322030e-01 1 1 1.1217701e+00 6.6846599e-01 2.0793675e-01 -4.4546345e-01 -4.9332614e-01 6.6191944e-01 7.7301899e-01 5.7052079e-01
+1 5.6107881e-01 1 1 8.9305605e-01 5.7261497e-01 1.3419203e+00 -4.8895203e-01 -6.6939312e-01 5.0052280e-01 -1.4970793e+00 6.0205624e-01
+1 9.4316465e-01 1 1 -9.3664534e-01 1.2415499e+00 1.6100039e-01 5.8955150e-01 -4.4680579e-01 -8.9842806e-01 -3.9637295e-01 -3.1073407e-01
+1 2.9453912e-01 1 1 3.2261078e-01 2.7126475e-01 1.0221962e+00 8.7849438e-03 -1.0583886e+00 -1.3861940e+00 1.4778764e+00 -1.1804605e+00
+1 8.1457881e-01 1 1 -2.6959305e-01 6.9568827e-01 -1.3183527e+00 -6.3049304e-03 -6.3988597e-01 2.8788908e-01 1.2374880e+00 -8.4206246e-01
+1 2.1048879e-01 1 1 -8.7386033e-01 -5.7518333e-01 9.8339657e-02 8.4718460e-01 -8.9190069e-01 4.9908806e-01 1.1176988e+00 3.3120693e-01
+1 9.1160860e-01 1 1 -2.4971911e-02 -4.2561266e-01 3.1687435e-01 9.3374497e-01 1.5052747e+00 1.2069805e-01 -1.5598298e+00 -3.0737783e-01
+1 2.9954415e-01 1 1 1.2705004e+00 1.3451002e-01 7.0758426e-01 1.1964322e+00 -9.3932124e-02 -8.9670995e-01 5.3090367e-01 -1.3208301e+00
+1 4.6113586e-01 1 1 -1.0450621e-01 -1.2368375e+00 1.4405143e+00 -8.9863008e-01 1.5038893e+00 -7.8423680e-01 7.7480077e-01 -6.9798789e-01
+1 1.0675247e+00 1 1 -2.8558537e-01 3.8995517e-01 -1.5314417e+00 1.5017851e+00 -1.3878079e+00 1.4548169e+00 1.7496484e-01 -3.7558098e-01
+1 6.3580527e-01 1 1 5.2025012e-01 6.1434992e-01 1.2836962e-01 9.4734358e-01 1.4387579e+00 9.1322083e-02 1.0332946e-01 -9.2985352e-01
+1 7.0138182e-01 1 1 7.9146154e-01 -1.0359142e+00 -7.6587911e-01 4.1196772e-01 3.6548266e-01 -1.3885661e+00 -6.4258355e-01 1.3753127e+00
+1 2.2145302e-01 1 1 5.9088256e-01 9.6545648e-02 -1.0251457e+00 -1.2879795e-01 8.5336529e-01 1.2617954e+00 8.9388537e-01 -9.5890535e-01
+1 1.0207595e+00 1 1 3.8885042e-01 -1.5606947e+00 -1.1297635e+00 -1.4988983e-01 1.1400427e+00 1.2444477e+00 4.3528282e-01 4.8145113e-02
+1 9.4613283e-01 1 1 8.9626780e-01 -1.4394785e+00 -1.4913750e-01 3.5892067e-01 1.2456792e-01 -1.2905847e+00 -9.7091402e-01 -1.3559885e+00
+1 9.1320698e-01 1 1 -3.6388179e-01 8.9865484e-02 4.3701782e-01 5.2187748e-01 1.3123236e+00 -1.3005808e+00 -7.1976926e-01 -9.8514936e-01
+1 5.6921812e-01 1 1 9.1971207e-01 -7.3687204e-01 -8.5170585e-02 -1.3180298e-01 -8.9960418e-01 3.3983502e-01 1.1114258e+00 -1.2120844e+00
+1 4.6660693e-01 1 1 9.6491005e-01 -4.5005340e-01 1.1042250e+00 -3.8981974e-01 8.3794974e-01 1.9177407e-01 -1.7581918e-01 -1.4152280e+00
+1 5.7374895e-01 1 1 3.4187283e-01 9.0765912e-01 1.3213874e+00 -1.4796045e+00 -3.3851642e-01 -1.2720532e-01 1.2456715e+00 -7.3983017e-01
+1 2.1349106e-01 1 1 -1.1627622e-01 -5.4713787e-01 6.3913813e-01 1.1348802e+00 -2.1142915e-02 1.4847858e+00 4.2808939e-01 9.7989340e-02
+1 2.5541495e-01 1 1 -1.8382777e-01 -3.0452803e-01 8.8918810e-01 1.3232640e+00 -3.4900226e-01 1.1248969e+00 6.5126960e-01 7.1229503e-01
+1 5.9335468e-01 1 1 -1.4077101e+00 -5.4811463e-01 2.8098511e-02 7.6434416e-01 -3.2751376e-01 3.8430568e-02 5.7931559e-01 -1.0671012e+00
+1 7.5607097e-01 1 1 -4.9536575e-02 -1.0129401e+00 1.0127786e+00 3.5994588e-01 -4.5350886e-01 -1.2655375e+00 7.6153094e-01 5.8325495e-01
+1 3.1807773e-01 1 1 -3.9162204e-02 -1.9409438e-01 6.2174481e-01 -1.0970958e+00 -6.1970082e-01 -1.3060542e+00 2.0198576e-01 9.9694063e-01
+1 2.0967070e-01 1 1 1.5353009e+00 -1.1710016e+00 7.2786350e-01 -8.8212145e-01 -9.3195885e-01 -5.4535828e-01 -1.2869443e+00 1.4675060e+00
+1 8.6512485e-01 1 1 -1.2390881e+00 1.0538016e+00 -1.5990501e-01 -6.3939721e-01 5.4866071e-01 1.3307090e+00 1.9262325e-01 -2.7137631e-01
+1 1.0832240e+00 1 1 2.6468368e-01 -1.0564619e+00 -1.4617185e+00 1.0396419e+00 7.6614531e-01 2.2783163e-01 -1.5629994e+00 5.7085504e-01
+1 6.8021594e-01 1 1 4.3336658e-02 3.2617991e-01 1.5239286e-01 -2.7692703e-01 -7.8409184e-01 -4.3529767e-01 6.6760562e-01 -6.3381777e-02
+1 5.4807654e-01 1 1 -4.9028597e-01 2.6555476e-02 8.6883960e-01 1.5276699e+00 7.4964997e-01 7.2130412e-01 -1.3212270e+00 -2.5760808e-01
+1 6.2268423e-01 1 1 1.6127040e-01 2.1173419e-01 4.6453210e-01 -6.8791737e-01 -1.5610285e+00 -4.4772583e-01 -1.0860158e+00 -5.0430882e-01
+1 6.9346144e-01 1 1 -7.2289315e-01 -8.0802802e-01 5.3330226e-01 -7.6622618e-01 -7.6592669e-01 -8.1370001e-01 -1.4239103e-02 9.8662751e-02
+1 9.3022608e-01 1 1 -1.1264160e+00 5.7811935e-01 2.4725167e-01 -5.7516589e-01 1.3168445e+00 -5.0320241e-01 -5.5556585e-01 -5.3606615e-01
+1 1.0241145e+00 1 1 -4.3597344e-01 -4.9416493e-01 -7.6829649e-01 -1.3245871e-01 -3.1423182e-01 -1.5552069e-01 -5.8188237e-01 4.2401829e-01
+1 7.7374010e-01 1 1 -1.2115129e+00 9.4106884e-01 -8.1324790e-01 1.1556785e+00 -2.7694724e-01 -3.1179330e-02 8.0985166e-02 1.3432465e+00
+1 9.6233026e-01 1 1 -1.2346225e+00 -1.3749469e+00 8.1213416e-01 -9.7842103e-01 1.1880461e+00 6.1496877e-01 8.0807116e-01 4.5887064e-01
+1 8.9205663e-01 1 1 -8.0080166e-02 8.2290489e-01 -6.8123126e-01 -1.2263222e+00 -4.7261655e-01 -5.9713909e-02 1.4686072e-01 -3.7118790e-01
+1 1.3171804e+00 1 1 -1.3056890e+00 1.2716462e+00 -1.4901754e+00 1.1916856e+00 -1.3201376e+00 -1.4436086e+00 -1.0036799e+00 6.4801249e-01
+1 6.1903023e-01 1 1 -6.8952171e-01 3.0238812e-01 -6.0170717e-01 1.0073104e+00 1.5162795e+00 -2.0914731e-01 1.5047560e+00 -7.5572691e-01
+1 7.0864115e-01 1 1 5.4391894e-01 -8.5980483e-01 -1.0573331e-01 -1.7690132e-01 -4.9013021e-01 3.0334093e-01 6.1402142e-01 -4.3059365e-02
+1 6.1162694e-01 1 1 -3.8898358e-01 5.8647265e-01 1.0816677e+00 -1.2339087e+00 -3.6246707e-01 -5.5393542e-01 -2.7387282e-01 -1.1324326e+00
+1 8.8410404e-01 1 1 7.3183084e-03 -1.4719904e+00 -8.0815863e-01 -6.5079175e-01 -4.3581699e-01 -1.4535382e+00 -5.4729522e-01 -1.0262547e+00
+1 5.7398826e-01 1 1 4.7669589e-01 2.9913656e-01 1.5244627e+00 1.1686831e+00 1.4178492e+00 -5.9241498e-01 1.9258143e-01 -9.1823896e-01
+1 9.4181688e-01 1 1 7.6656242e-01 1.0398573e+00 -1.1849276e+00 8.1906428e-01 8.1075552e-01 -1.0114651e+00 8.7564342e-01 -1.3390876e+00
+1 8.6823627e-01 1 1 -5.6858037e-02 2.0161074e-01 -5.2161542e-01 -4.4564208e-01 1.2807181e+00 -5.3618559e-01 -1.4226939e+00 3.2387199e-01
+1 3.6752317e-01 1 1 -5.6885594e-01 -1.3067533e+00 1.3947482e+00 -3.4953810e-01 -1.1639783e+00 1.5581838e+00 -5.5518598e-01 -1.0634711e+00
+1 8.4899845e-01 1 1 -8.9537047e-01 2.7095548e-01 -1.0307137e+00 9.1465664e-02 -2.8623905e-01 7.8086444e-02 -4.8054196e-01 -1.2380804e+00
+1 1.0057243e+00 1 1 -2.6259786e-01 -1.3605405e+00 -4.6248821e-01 1.0246001e+00 -1.0413729e+00 -7.8686703e-01 5.6595772e-01 1.4917641e+00
+1 4.1838287e-01 1 1 4.5541953e-01 1.0489358e+00 -7.3909412e-01 1.3852376e+00 -5.4211116e-01 1.2309587e+00 -6.9108511e-01 -9.7154626e-01
+1 6.9303386e-01 1 1 1.3163886e+00 -1.1542359e+00 -9.7594354e-02 -6.5446445e-01 -6.4355089e-01 1.3357118e+00 -5.9940483e-01 1.2205759e+00
+1 1.0156088e+00 1 1 1.4482695e+00 9.1033477e-02 -3.5694359e-01 -8.6804707e-01 3.4361855e-01 -5.1309466e-01 8.9071413e-01 -3.8123456e-01
+1 5.6371611e-01 1 1 5.3381054e-03 4.4019169e-02 1.2909738e+00 2.8922306e-01 9.4969186e-01 8.9858808e-02 5.4341438e-01 1.4398235e+00
+1 3.5257788e-01 1 1 -1.3886492e+00 1.5559029e+00 1.5573865e+00 9.2813137e-01 -9.6111281e-01 -8.4908831e-01 5.5559780e-01 -5.7461170e-01
+1 1.0907863e+00 1 1 -1.3493334e-01 -5.5746914e-01 -7.5513476e-01 1.0963881e+00 6.4640304e-01 -1.5133728e+00 1.1187945e+00 -2.4294173e-01
+1 6.2141968e-01 1 1 4.0523081e-01 -1.1544783e+00 4.8447253e-01 1.5546981e+00 4.6843655e-01 -9.2291707e-01 1.1463713e+00 9.4874534e-01
+1 1.0549514e+00 1 1 -2.5869064e-01 -8.3990996e-01 -4.7836667e-01 1.1842725e+00 1.8193689e-01 -1.4242771e+00 -3.2608558e-01 -1.1613062e+00
+1 7.4137044e-01 1 1 1.5069620e-01 -1.1908683e+00 -5.7294955e-01 -1.0627263e+00 1.0436880e+00 1.1102205e+00 1.5588067e+00 6.4253594e-01
+1 9.0871961e-01 1 1 6.2743001e-01 1.6371522e-01 -5.8161946e-01 -1.2860668e+00 -1.3895428e+00 1.5576120e+00 1.1235736e+00 1.4476623e+00
+1 7.9262654e-01 1 1 -1.1104090e+00 -4.7343553e-01 1.3580435e+00 -7.6706300e-01 5.5333410e-01 -1.0699403e-01 -2.1119947e-01 -7.7485251e-01
+1 5.4898837e-01 1 1 1.5582174e+00 6.2323592e-01 9.6678622e-01 1.0684397e+00 7.7199171e-01 -1.2577364e+00 3.7019016e-01 -1.0446655e+00
+1 2.9169248e-01 1 1 6.4292966e-01 6.5615844e-01 4.5871920e-01 -7.7474798e-02 8.6930904e-02 1.0004790e+00 1.4325621e+00 6.6748481e-01
+1 9.2818548e-01 1 1 -1.3598715e+00 1.0646341e+00 2.2518034e-01 -1.4995684e+00 2.0712401e-01 1.2473957e+00 -9.4801541e-02 -2.1022277e-01
+1 1.2254924e+00 1 1 -2.7365434e-01 -1.2067832e+00 -1.0131141e+00 -1.3904805e+00 2.4849209e-01 1.1317150e+00 -5.4202499e-01 1.0775696e+00
+1 3.0578713e-01 1 1 -1.6804554e-02 -2.8329740e-01 2.4195504e-02 5.0277884e-01 1.2299839e+00 1.5315395e+00 8.0468814e-01 -5.6949714e-01
+1 6.0157967e-01 1 1 3.0920173e-01 1.2750785e+00 1.3883871e+00 -6.8021671e-01 6.6022204e-01 1.5161741e+00 -1.6281495e-01 8.9445144e-01
+1 8.7402470e-01 1 1 5.5917353e-01 1.4412201e+00 -1.1289217e+00 -1.4652677e-01 2.4649994e-01 8.8054016e-01 -1.0372207e-01 5.2447297e-01
+1 3.9126535e-01 1 1 1.5258561e+00 9.0691404e-01 1.4334543e+00 3.3325065e-01 -8.3623909e-01 -8.0457963e-01 3.2716183e-01 -4.9179402e-01
+1 1.1809585e+00 1 1 2.4321923e-01 -5.0328219e-01 -8.0696780e-01 -5.1597264e-01 8.1515237e-01 -1.1550420e+00 8.2176062e-01 -5.1843405e-02
+1 1.0733157e+00 1 1 5.7352179e-01 -1.4962642e+00 -4.5240696e-01 -1.1564320e+00 -2.1969634e-01 -8.8934250e-01 8.8938828e-01 -1.1109450e+00
+1 6.9989764e-01 1 1 7.7451869e-01 7.3666535e-01 -9.4953927e-01 8.8166215e-01 -1.0651014e+00 5.1845593e-01 2.5100250e-01 -1.1678872e+00
+1 4.7613795e-01 1 1 -1.4243342e+00 1.1790819e-01 3.8416851e-01 -7.9671201e-01 -3.6406421e-01 -1.0891564e+00 -5.5992864e-01 -1.0110710e-02
+1 4.5630049e-01 1 1 1.5116970e-01 -6.6193770e-01 7.4722518e-01 -8.7086451e-01 9.9532206e-01 6.0936445e-01 1.4909727e+00 -2.8470547e-01
+1 9.5444931e-01 1 1 -8.3931110e-01 -8.0729809e-01 -1.4739111e+00 6.0377863e-02 -6.0307731e-01 -3.8009413e-03 1.4359856e+00 -3.9928513e-01
+1 5.6284950e-01 1 1 -5.5057919e-01 2.7958878e-01 -5.6533475e-01 3.6315321e-02 -1.1424263e+00 -1.0505677e+00 8.9567089e-01 -3.4321542e-01
+1 9.9100016e-01 1 1 1.5475619e+00 -7.7398086e-01 -1.4049712e+00 8.8262782e-01 6.5608248e-01 -1.1406569e+00 -9.7132229e-01 -4.5738937e-01
+1 9.0164336e-01 1 1 6.2706149e-01 1.0388180e+00 -1.1400440e+00 -2.7472055e-01 -2.1201044e-01 -1.0225315e+00 -1.2982747e+00 1.3405972e-01
+1 9.5843910e-01 1 1 -1.0209030e+00 -1.5572430e+00 -1.4546709e-01 9.1293856e-01 -6.9336453e-01 -1.1757014e+00 1.3997422e+00 6.1975922e-01
+1 7.5908452e-01 1 1 1.0616573e+00 2.4544640e-02 -7.0637294e-01 2.1984401e-01 -1.2105207e+00 6.0405670e-01 1.2212735e+00 -1.2280610e+00
+1 7.4515868e-01 1 1 -9.7276901e-01 9.7312446e-01 6.8577949e-02 4.0539635e-01 -2.6681472e-01 -1.2464726e+00 -1.2222585e+00 2.4169567e-01
+1 6.7192791e-01 1 1 -4.8064121e-01 1.7139889e-01 -3.7491711e-01 -6.1796389e-01 -1.3022327e+00 -1.3256555e+00 3.7537095e-01 9.9905927e-02
+1 7.4776739e-01 1 1 -1.1021160e+00 -1.3929260e-01 8.0299524e-01 -1.3784804e-02 8.5089406e-01 -1.1629288e-01 5.4155101e-01 1.5084383e+00
+1 8.7317040e-01 1 1 -4.3398030e-01 -6.0422684e-01 -3.4110904e-01 7.9665162e-01 4.4671123e-01 -4.6377836e-01 6.5386540e-01 -3.2976993e-01
+1 6.8378925e-01 1 1 8.7125739e-01 1.5286156e+00 3.8694082e-01 -1.4412234e-01 -5.3083379e-01 -4.3147841e-01 2.2475833e-01 -6.7378555e-01
+1 8.9798907e-01 1 1 2.5956791e-01 -5.0176335e-01 2.1752869e-01 -9.6293612e-02 3.9963449e-01 -1.0617531e+00 1.3189512e+00 1.1277392e+00
+1 1.1653928e+00 1 1 -1.1143656e+00 -1.1018931e+00 -8.0923847e-01 -4.8652293e-01 -6.8186985e-02 -6.3732798e-01 5.3538463e-01 6.8506256e-01
+1 5.4824804e-01 1 1 1.0328747e+00 1.7147693e-01 -9.1641720e-01 5.7476979e-01 6.6265356e-01 1.2595785e+00 6.8812944e-01 -9.0676090e-02
+1 7.8754457e-01 1 1 -9.1663664e-01 1.1723396e+00 1.0049510e+00 -2.4152987e-01 2.7250850e-01 -1.4567864e+00 1.1889263e+00 -3.2060960e-01
+1 5.9980345e-01 1 1 4.5840488e-01 -5.5758586e-01 1.0098323e+00 -4.5480265e-01 -3.9166336e-01 1.3642404e+00 -1.3868901e+00 -6.5417151e-01
+1 4.6685247e-01 1 1 1.2256690e+00 2.5419520e-02 1.3684281e+00 -3.7315986e-01 -1.0494826e+00 1.4455354e+00 1.1551477e+00 9.1371406e-01
+1 1.0868705e+00 1 1 3.9597978e-01 -3.0720521e-02 -4.2948639e-01 -1.0788817e+00 1.3891797e+00 1.1782866e+00 -4.7591867e-01 6.8725590e-01
+1 6.0951125e-01 1 1 1.3389514e+00 -1.0986039e+00 1.0021342e+00 5.0823013e-01 -3.7329786e-01 -1.1371913e+00 -2.7013757e-01 -9.2629946e-01
+1 6.7973792e-01 1 1 5.2729407e-01 -1.0953582e+00 7.9082204e-01 -1.6665990e-01 -2.5653190e-01 6.7620163e-01 -6.0068338e-01 1.4181386e+00
+1 2.5269575e-01 1 1 -2.0150525e-01 4.7952832e-02 -7.3253907e-01 1.2477057e+00 -1.2665881e+00 -1.3614460e+00 1.3931839e+00 -6.0791333e-01
+1 3.7499377e-01 1 1 -6.1876288e-02 -1.4460721e+00 1.1742359e-01 5.8497176e-02 -1.1396500e-01 1.5387348e+00 9.5204067e-01 -7.4004617e-01
+1 5.4343475e-01 1 1 -8.7595751e-02 -7.7233842e-01 6.1801396e-01 -1.5645652e-01 9.6183978e-01 -7.4414860e-02 8.1612779e-01 -3.9058004e-01
+1 4.1175335e-01 1 1 1.1851710e+00 3.6897445e-01 8.5530851e-01 -5.1615190e-02 -9.9457529e-01 -3.3668181e-01 4.6629217e-01 1.4499642e+00
+1 5.8976016e-01 1 1 1.4717615e+00 -1.5039024e-01 -7.5789383e-01 -4.1692447e-01 5.8757074e-01 -6.0284531e-01 -1.3011950e+00 2.1407123e-01
+1 6.1832939e-01 1 1 -1.0049098e+00 1.3732561e+00 1.2366346e+00 -1.4979105e+00 1.2756648e+00 -3.8484763e-01 -5.5803024e-01 7.7150639e-01
+1 1.0763142e+00 1 1 -3.1733203e-01 -9.6567038e-01 -6.5952579e-01 1.3415986e+00 -1.2719027e+00 4.0517190e-01 -1.1602438e+00 1.3550807e+00
+1 1.1057520e+00 1 1 1.0248468e+00 -5.5446231e-01 -1.1110785e+00 1.0365857e+00 -1.4730082e+00 -1.2486722e+00 -3.5231424e-01 1.4357563e+00
+1 6.6503169e-01 1 1 -7.5206779e-01 -8.8423226e-01 -2.6968575e-01 -1.3762064e+00 -1.0987762e+00 -5.9543769e-01 5.5664517e-01 1.8316071e-01
+1 2.6915497e-01 1 1 -1.3760917e+00 -1.5583497e+00 7.0973574e-01 -1.4959689e+00 -8.4982562e-01 -1.5487288e+00 -1.2750968e-01 -3.7871430e-01
+1 7.1657228e-01 1 1 4.3201687e-01 2.7385980e-01 -9.8747439e-02 -5.8264637e-01 -1.3389096e+00 -1.3897335e+00 -4.8907559e-01 -1.8446925e-01
+1 8.7743738e-01 1 1 6.8693235e-01 3.2849315e-01 -8.8729058e-01 -1.9319541e-01 1.7472150e-01 4.8992770e-01 -1.4871380e+00 3.7721893e-01
+1 2.7198021e-01 1 1 -8.0931847e-02 1.2061289e+00 4.4759897e-01 1.3715754e+00 -8.4487424e-01 1.0044474e-01 1.8263393e-01 1.8455162e-01
+1 1.1443065e+00 1 1 8.8060862e-02 -1.2895866e+00 -1.3184338e+00 -9.3976724e-01 1.9746527e-01 1.1394940e+00 1.9248488e-01 1.0070932e+00
+1 1.1803796e+00 1 1 3.4877093e-01 -2.3457155e-01 -1.2635489e+00 1.2598495e+00 1.2768980e+00 3.2651557e-01 -7.4699308e-01 -6.8548473e-01
+1 8.9133345e-01 1 1 -4.1890225e-01 2.5470605e-01 6.9988083e-01 -4.4473500e-02 6.0604760e-01 -6.1522959e-01 -9.0850477e-01 -7.2167882e-01
+1 6.8756684e-01 1 1 -1.8102018e-01 -1.1461720e+00 7.7419739e-01 2.3293138e-01 7.9862993e-01 -1.1823076e+00 -1.0994300e+00 4.3330141e-01
+1 5.3327883e-01 1 1 -1.3444355e+00 5.3347501e-01 -5.4122513e-01 4.5324780e-01 -1.4521858e+00 -4.7016318e-01 7.2753774e-01 2.8499989e-01
+1 9.4405013e-01 1 1 1.5476759e+00 8.9969294e-03 -1.4600655e+00 -6.2645135e-01 1.4578858e-01 -9.2711494e-01 6.4816373e-01 -9.3561492e-01
+1 7.8475867e-01 1 1 -5.9898659e-01 4.1494452e-01 -3.4076665e-01 -1.2907835e+00 -1.7353978e-01 2.7873221e-01 -1.3555374e+00 -1.2086843e+00
+1 1.0767903e+00 1 1 -1.5047125e+00 -3.6318096e-01 -1.4161990e-01 -1.5017497e+00 -1.2850511e+00 5.3752455e-01 3.1339411e-01 -8.1962708e-01
+1 5.6925783e-01 1 1 1.1742510e-01 1.3206705e-01 1.1216072e+00 -3.5127453e-01 5.9482941e-01 -1.0453225e+00 -1.2361118e+00 4.1147823e-01
+1 6.2941133e-01 1 1 6.4351095e-01 -1.4550202e+00 1.2957996e+00 -8.1849623e-01 7.5002397e-01 -9.4864821e-01 2.0957506e-02 1.0691552e+00
+1 4.5302258e-01 1 1 -1.0149246e+00 -3.6674447e-01 9.8338729e-01 5.6807421e-01 -1.5585289e+00 -3.4771674e-01 3.7442964e-01 -6.1892754e-01
+1 9.6289449e-01 1 1 1.0099404e+00 -6.9469684e-02 -1.2869557e-01 3.2314307e-01 4.0420104e-01 -7.1292358e-01 4.2888832e-01 -5.0184584e-01
+1 1.0139134e+00 1 1 4.3416241e-02 1.0954922e+00 -1.5706690e+00 -7.4804907e-01 1.2835704e+00 -7.2309389e-02 1.5124465e+00 6.5322373e-01
+1 2.4184643e-01 1 1 8.4726120e-01 -9.3683575e-01 5.6851694e-01 1.9300497e-01 -3.4902192e-01 4.9245345e-01 1.0624460e+00 -1.1350279e+00
+1 5.9712994e-01 1 1 -9.2045853e-01 2.6385136e-01 1.4809736e+00 -1.4307282e+00 -6.5799118e-01 -1.4315474e+00 -2.8353083e-01 -6.6272304e-01
+1 6.2014988e-01 1 1 -9.4428932e-01 -1.3789462e+00 -1.1473452e-01 -4.9821100e-01 -4.5165668e-01 1.4405647e+00 4.9335519e-01 -1.4401823e+00
+1 6.0828090e-01 1 1 6.5542198e-01 -4.2006630e-01 5.9479311e-01 -1.0878097e+00 -9.0601182e-01 -6.8364822e-01 1.1577208e+00 8.2804092e-01
+1 8.5072348e-01 1 1 1.2533088e+00 -8.9557494e-01 1.3998935e-01 1.2523415e+00 -4.1076000e-02 -1.2712948e+00 -1.2119227e+00 -3.7163686e-01
+1 1.0700743e+00 1 1 -1.8536251e-02 -5.5766547e-01 -2.5181995e-01 -5.6656563e-01 7.8604556e-01 -6.8069606e-01 1.3012467e+00 -6.1451064e-01
+1 7.4493663e-01 1 1 -5.2109743e-01 -1.3126686e+00 -6.1257222e-01 -1.0112868e-01 6.7056727e-01 1.2217178e+00 1.4261328e+00 1.4763992e+00
+1 5.5715638e-01 1 1 6.7577960e-01 1.3845471e+00 -5.0218360e-01 -6.8136524e-02 1.3311848e+00 -3.9275192e-02 -1.3383089e+00 1.5423295e+00
+1 3.5194786e-01 1 1 9.7032428e-01 3.0617656e-01 1.2597015e+00 1.5107667e+00 -1.2002091e+00 -3.6369640e-01 8.4589219e-01 6.5124859e-01
+1 3.0517721e-01 1 1 2.3265882e-01 -1.9298417e-02 6.1004362e-01 1.1033473e+00 2.5169920e-01 8.9384212e-01 1.2032996e+00 2.2621789e-01
+1 7.3643855e-01 1 1 -9.8598815e-01 -7.6444558e-01 -1.1552883e+00 -8.6295317e-01 -1.4169097e+00 -2.9156588e-01 1.4245203e+00 7.1699721e-01
+1 1.9041565e-01 1 1 3.9842677e-01 1.0771347e+00 1.2538639e+00 1.0794195e+00 -7.2966288e-01 5.3675800e-01 -1.6440180e-01 -5.7722988e-01
+1 1.0266667e+00 1 1 -1.5168929e+00 1.5458314e+00 -1.1372600e-01 -8.9448391e-01 1.3336687e+00 -1.3623341e+00 1.5005359e+00 -2.6449585e-01
+1 8.3166273e-01 1 1 -3.9411371e-01 -1.8275648e-01 -1.3044996e+00 -1.0701873e+00 -2.9333723e-01 -8.2128171e-01 -1.1987555e+00 -2.8219639e-02
+1 7.0563688e-01 1 1 -1.3918801e+00 8.8948182e-01 4.5051566e-01 -1.0199650e+00 -9.5997895e-01 8.7638697e-01 -4.4946442e-01 9.3013119e-02
+1 6.2084653e-01 1 1 -1.0291262e+00 -1.3184067e+00 5.7843601e-01 1.1195887e+00 8.5364878e-01 -1.4921204e+00 1.3818366e+00 -1.2416453e+00
+1 7.0599288e-01 1 1 1.0851731e+00 -8.0878287e-01 -1.4553140e+00 -1.2128221e+00 -3.7859794e-01 1.2670689e+00 -1.2659488e+00 1.2668203e+00
+1 3.1717038e-01 1 1 1.5592498e+00 4.5775670e-01 9.7855599e-01 -1.2474771e+00 -1.3704401e+00 -1.2297906e+00 1.2057685e+00 8.7533007e-01
+1 1.0060188e+00 1 1 -8.5509889e-01 -2.4355510e-01 3.5297846e-01 6.4112928e-01 1.1707643e+00 -5.5275525e-01 -1.0621953e+00 -4.0592850e-01
+1 5.5879188e-01 1 1 1.1394103e+00 6.4599771e-02 1.1820062e+00 -2.0304840e-01 1.2404935e+00 -4.6805639e-01 1.3546217e+00 1.0990016e+00
+1 1.3608441e+00 1 1 -1.0806136e+00 -1.2627007e+00 -1.4540811e+00 -8.6486314e-01 1.3658409e+00 -7.5777383e-02 4.4907877e-03 1.4962206e+00
+1 9.0320971e-01 1 1 -3.2499491e-01 -7.5196869e-01 -2.9238874e-01 3.9433685e-01 7.0160313e-02 -1.2454472e+00 7.8444443e-02 -1.4688741e+00
+1 1.0198709e+00 1 1 1.0400889e+00 2.8947417e-01 -7.2659280e-01 -1.1411328e+00 1.0871314e+00 2.0028317e-01 -1.0531554e+00 -7.3155833e-01
+1 1.0232425e+00 1 1 9.5282127e-01 -1.1346746e+00 -4.7447545e-01 4.0437820e-01 -8.6052653e-02 1.5134636e+00 -6.4971411e-01 8.9286057e-01
+1 4.3680123e-01 1 1 1.3693984e+00 -1.0091167e+00 -1.1467559e+00 1.1194954e+00 -1.1543199e+00 -6.9224905e-01 4.3101566e-01 -1.0805750e+00
+1 1.0633075e+00 1 1 1.7118432e-01 1.2340968e+00 1.4454152e-01 3.6143084e-01 -1.3203738e+00 -1.3121647e+00 -4.3240669e-01 3.2255986e-01
+1 7.7910735e-01 1 1 -6.0408609e-01 6.7060494e-01 8.5822004e-01 -1.2721166e+00 6.8744697e-01 4.2794254e-01 -9.5544157e-01 -1.1253282e+00
+1 4.3552859e-01 1 1 7.5246532e-01 -1.1772858e+00 1.0524042e+00 1.2164534e+00 -8.5657413e-01 1.3247681e+00 -1.4263828e+00 -1.0032265e+00
+1 8.5394817e-01 1 1 -1.3674415e+00 -8.9219266e-01 5.9074586e-01 -5.5273780e-01 1.4777396e+00 9.1008886e-01 2.7828232e-01 -3.0028122e-01
+1 3.8009541e-01 1 1 1.3033954e+00 -2.6023425e-01 1.2328616e+00 -1.7470574e-01 -1.0617900e+00 -5.5117494e-01 -7.4053773e-01 -1.4287292e+00
+1 1.1228712e+00 1 1 -1.5967261e-01 -6.6010940e-01 -1.2404890e+00 1.1097037e+00 -1.2581564e+00 9.5944697e-01 7.7248377e-01 -1.4583155e+00
+1 8.5851376e-01 1 1 -6.9740291e-01 -1.4950699e+00 -1.2904563e+00 -8.4615360e-01 2.2552136e-01 -3.6978356e-01 -1.0677732e+00 7.9662744e-01
+1 7.7261907e-01 1 1 3.1399559e-02 -1.1825964e+00 8.5616482e-01 6.8636288e-01 -1.5648114e+00 -8.8206156e-01 -1.2874300e+00 -5.5047606e-01
+1 2.8604926e-01 1 1 -5.5170088e-02 9.5974205e-01 1.0677431e+00 -2.2726280e-01 -1.5129277e+00 3.6713163e-01 1.4540853e+00 1.3924842e-01
+1 6.6147510e-01 1 1 -4.7383892e-01 1.4479241e+00 7.8130117e-01 5.7083481e-01 2.7452357e-01 2.9330384e-01 3.6219198e-01 -1.3830854e-01
+1 7.0346233e-01 1 1 1.2667983e-01 4.8435548e-01 -5.2847447e-01 -4.0325153e-01 -1.0819473e+00 3.9875006e-01 -1.0459549e+00 2.2690030e-01
+1 9.0927779e-01 1 1 -8.9194985e-01 6.9604816e-01 -7.8805806e-01 -1.0330961e+00 -7.4939123e-01 7.7510316e-01 9.8815636e-01 -3.8017687e-01
+1 8.8549495e-01 1 1 6.7899509e-01 -8.0968036e-01 6.2744351e-02 3.3647970e-01 -3.7340738e-01 -1.0259592e+00 1.4851825e+00 3.6681040e-01
+1 7.6638524e-01 1 1 -1.5356352e+00 1.0814826e+00 -1.0308259e+00 3.4755990e-01 1.0442369e+00 9.0576308e-01 1.5085237e+00 1.1776177e+00
+1 5.8442850e-01 1 1 -1.2370174e+00 -7.7746958e-01 7.9294165e-01 1.2184419e+00 1.5524871e+00 -9.9785470e-01 1.1056837e+00 1.8662823e-01
+1 7.4901448e-01 1 1 5.0866664e-01 -1.0473858e+00 3.3425668e-01 1.4518449e+00 -1.4173094e+00 -1.1223292e+00 7.0583661e-01 1.3511218e+00
+1 7.1783137e-01 1 1 8.8652726e-01 -1.0699161e+00 6.8440603e-01 4.0790032e-01 -1.1641607e+00 -8.6447320e-01 3.4209098e-01 8.7166407e-01
+1 2.5539882e-01 1 1 -7.1024812e-01 3.9591306e-01 1.4413975e+00 6.2543389e-01 -2.1011273e-01 6.6488680e-01 4.0860854e-01 8.1154369e-01
+1 4.7673908e-01 1 1 9.1188530e-01 2.1755083e-01 7.4721561e-01 -1.0169542e-01 -2.1454446e-01 1.0742900e-01 -3.7725811e-02 -1.1804878e+00
+1 3.7163503e-01 1 1 1.3672582e+00 -4.3711023e-01 1.5069300e+00 -1.6848929e-01 6.9958666e-01 -8.5655943e-01 5.4400761e-01 -1.3008608e+00
+1 8.4982326e-01 1 1 -1.2420706e+00 -1.4680069e+00 -5.4667017e-01 -1.2245064e+00 -1.0283891e+00 -1.4168248e+00 1.1012997e+00 -1.2242796e+00
+1 7.9934016e-01 1 1 4.0295507e-01 1.2768603e+00 1.2729334e+00 2.9462699e-01 9.0640711e-01 6.9799661e-01 -7.2022763e-01 9.6398652e-01
+1 8.7564373e-01 1 1 -8.0792033e-01 -2.7689134e-02 -5.4820110e-02 6.4577385e-01 4.0156617e-01 5.2209649e-01 -3.0936551e-01 5.2811751e-01
+1 1.3105775e+00 1 1 -7.5358020e-01 -4.1556230e-01 -8.7493926e-01 -6.8157111e-01 9.8159853e-01 4.0734240e-01 -1.7027262e-01 1.0718280e+00
+1 7.2806550e-01 1 1 1.4791417e+00 -5.9509521e-01 6.9113246e-01 -9.1880828e-01 1.2234979e+00 6.7336691e-01 2.1895503e-01 3.2054292e-01
+1 7.4631611e-01 1 1 5.1183963e-01 1.0658030e+00 1.3952700e+00 -1.4828861e+00 -1.5358697e+00 1.2609259e+00 1.1722201e+00 -4.6658975e-01
+1 5.2529249e-01 1 1 8.0802336e-01 -4.1086919e-01 1.4550013e+00 -6.1212187e-01 1.1049770e+00 -8.0222870e-01 5.7576824e-01 -5.5870444e-01
+1 2.0965731e-01 1 1 -6.5642979e-01 -2.5783708e-01 4.9322887e-02 7.8369743e-01 1.3939278e+00 6.5789934e-01 8.3136383e-01 7.4889402e-02
+1 7.3992992e-01 1 1 6.5798253e-01 -1.2115327e+00 -4.1070682e-01 -1.0952648e+00 8.8804801e-01 -1.0918580e+00 -1.0721781e+00 -1.1124794e+00
+1 6.5587483e-01 1 1 3.0629678e-01 -1.5687142e+00 -6.7046470e-01 -1.5249478e+00 -2.8376604e-01 -8.1472099e-01 7.8000345e-02 1.3182421e+00
+1 7.8061672e-01 1 1 -1.1404326e+00 -1.1339755e+00 3.9270207e-01 -6.8448301e-01 -3.1821707e-01 1.1867789e+00 9.0766678e-01 1.1841116e+00
+1 4.1755585e-01 1 1 -3.9455237e-01 1.3171702e+00 -3.4250111e-01 4.0626577e-01 -1.2836594e+00 2.2136344e-01 -4.1832520e-01 -6.2573267e-01
+1 5.0018691e-01 1 1 6.6040675e-01 -1.1230382e+00 -1.0183890e+00 1.4279012e+00 -1.1469164e+00 8.0955320e-01 9.2795737e-02 1.3632517e+00
+1 8.7520050e-01 1 1 2.0936902e-01 -2.1390219e-01 -6.6691009e-01 1.0883555e-01 5.8854249e-01 -7.7187033e-02 1.3879955e+00 5.3531109e-01
+1 8.4693665e-01 1 1 2.8136465e-01 -1.0720407e+00 4.4477283e-01 7.9220887e-01 -1.2417026e+00 1.9530129e-01 -1.4275011e+00 -5.4794609e-01
+1 2.5878124e-01 1 1 7.9880450e-01 -7.5371719e-01 1.4479949e+00 5.8489126e-01 3.0494194e-01 -5.3548191e-01 3.3230084e-01 -1.3219078e+00
+1 1.3807817e+00 1 1 1.4818124e+00 -8.2320972e-01 -1.4685413e+00 2.2402723e-01 1.2215023e+00 8.1853308e-01 -7.7146274e-01 3.8253449e-02
+1 6.3474522e-01 1 1 1.4158061e+00 -1.1170910e-01 -1.4216820e+00 -1.5440020e+00 -5.1842765e-01 5.1303563e-02 -6.2147047e-01 -1.1007741e+00
+1 6.0181140e-01 1 1 1.0299966e+00 1.1775678e+00 7.4511533e-01 -4.8564061e-01 1.5645511e+00 1.4626045e+00 7.4131973e-01 1.2938323e-01
+1 6.6550160e-01 1 1 9.7765716e-01 -6.5125656e-01 7.6505499e-01 -3.0404895e-01 2.8012646e-01 -9.6829279e-01 -1.9573232e-01 5.6183700e-01
+1 5.8672470e-01 1 1 9.5435451e-01 -3.6024307e-01 -2.5954684e-01 1.2205619e+00 -1.1620295e+00 -6.4704904e-01 -4.2557678e-01 -8.3313281e-01
+1 5.2278346e-01 1 1 -1.1358599e+00 -7.5621424e-01 1.4684714e+00 -6.1584623e-01 1.0515125e+00 1.2405916e+00 7.3758643e-01 -3.8467830e-01
+1 1.0754453e+00 1 1 1.0617255e+00 1.1910616e+00 2.4645990e-01 1.0201870e+00 1.3119848e+00 -1.2739700e-01 -1.0942181e-01 1.0943214e-01
+1 8.9964880e-01 1 1 1.7380888e-01 -5.5535408e-02 -1.5091433e+00 -5.3058034e-01 -3.0991953e-01 1.4048814e+00 -1.2206049e+00 1.3943139e+00
+1 5.3725609e-01 1 1 -4.7538068e-01 -3.3058522e-01 1.0470462e+00 1.5177362e+00 -5.6888300e-02 -3.6929441e-01 -1.0684722e-01 1.0947940e+00
+1 9.8736793e-01 1 1 -6.5289995e-01 1.3316216e+00 -1.4966213e+00 -1.1403490e+00 -1.0774927e+00 1.0558983e+00 1.2096939e+00 -1.0510577e-01
+1 5.9051554e-01 1 1 2.9361880e-01 -1.4129313e-01 1.0183699e+00 1.0109294e+00 -1.2793463e+00 -3.7406345e-01 -1.0629463e+00 -9.3767634e-01
+1 1.2844967e-01 1 1 -5.9089562e-01 3.3045447e-01 3.4671014e-01 9.5754998e-01 -9.1385080e-01 -5.5756177e-01 1.2992432e+00 -1.2975708e+00
+1 9.1843287e-01 1 1 -6.0834093e-01 -3.8746654e-01 -4.9697035e-01 -8.3667881e-01 1.5609141e-01 4.3019965e-01 -8.3071530e-01 6.6311575e-01
+1 3.8594676e-01 1 1 1.4981449e+00 3.7144709e-01 9.1413426e-01 -2.9200384e-01 1.9848322e-01 1.5608298e+00 -5.9424032e-01 -1.3842922e+00
+1 6.6863669e-01 1 1 -5.4313131e-01 5.6659421e-01 1.4664426e+00 -5.4079514e-01 -4.6397891e-01 5.6775749e-01 -2.7395322e-01 8.3700414e-01
+1 5.2957140e-01 1 1 1.0603468e+00 5.8149006e-01 7.0623820e-01 -5.1634084e-01 -6.6060297e-01 1.2832103e+00 1.2431289e+00 -5.2336731e-01
+1 5.4911753e-01 1 1 -1.0061541e+00 -3.9126814e-01 8.0845391e-01 -1.0616644e+00 -3.6573987e-01 -1.1845885e-01 -1.4649531e+00 2.2499731e-01
+1 6.8608050e-01 1 1 7.6190580e-01 -6.9024635e-01 2.9668721e-01 8.5347161e-01 1.1067889e+00 8.3184814e-01 -8.0471880e-01 -9.4773237e-01
+1 7.4911292e-01 1 1 2.1904103e-01 9.3123412e-01 7.1442503e-01 -2.1474426e-01 4.3055730e-01 7.8437332e-01 -3.5250952e-01 -6.6326585e-01
+1 4.4426469e-01 1 1 -5.2405940e-01 -1.6272242e-01 1.7428876e-01 4.8314912e-01 1.2886159e+00 8.3969122e-01 4.1630522e-01 -1.1383366e+00
+1 6.6461833e-01 1 1 1.1594775e+00 1.4515207e+00 1.3067943e+00 -7.2979157e-01 -3.7234432e-01 6.5614860e-01 5.1494872e-01 2.7660972e-01
+1 7.6790435e-01 1 1 3.8597349e-02 1.2421545e+00 4.1726663e-01 -8.2927290e-01 6.1581963e-02 8.9933390e-01 -3.4459977e-01 -5.7760976e-01
+1 4.9784386e-01 1 1 1.5375582e+00 1.0072721e+00 9.6541583e-01 -1.4847013e+00 1.4240694e+00 9.0264016e-01 1.4085959e+00 -3.6600837e-01
+1 1.0036383e+00 1 1 -1.0010840e+00 -8.2138269e-01 -5.8217818e-01 2.9605022e-01 -1.4603636e+00 -7.7777917e-02 -7.7120705e-01 -2.6426659e-01
+1 4.5289562e-01 1 1 1.1522395e+00 -8.2079811e-01 1.3925027e+00 -5.6668193e-01 9.3227184e-01 -3.1091344e-01 5.3444643e-01 6.8350375e-01
+1 1.0988242e+00 1 1 9.1268887e-01 -4.2052990e-01 -1.0720196e+00 1.0857765e+00 1.5702656e+00 -1.0536352e+00 6.2771469e-01 -1.1568450e+00
+1 8.0606535e-01 1 1 -8.3506841e-01 7.3747442e-01 -4.0032444e-01 -8.6659549e-01 -1.0665237e+00 7.1021992e-01 5.3263080e-01 2.2263342e-01
+1 7.1013618e-01 1 1 -1.5003085e+00 1.1494749e+00 1.0385891e+00 -4.4680530e-01 8.6420118e-01 -1.3859278e+00 1.5283631e+00 1.6310039e-01
+1 6.6945639e-01 1 1 -1.2625609e+00 1.5706571e+00 8.7882221e-01 -1.0501765e+00 1.0463213e+00 -1.5197995e+00 1.5366767e+00 -1.3820700e+00
+1 7.4027891e-01 1 1 -1.5444204e+00 -7.6887856e-01 -1.4037339e+00 -8.4842100e-01 -1.1132647e+00 1.0202367e+00 -1.0834882e-01 4.8528271e-01
+1 5.8216441e-01 1 1 -1.2345358e+00 -1.1713244e+00 8.0488208e-01 2.7732977e-01 6.8673485e-01 3.0533747e-01 1.1050837e+00 5.7200925e-01
+1 3.0425846e-01 1 1 1.3763956e+00 -1.2291464e+00 -4.4873996e-02 -1.0421044e+00 -2.5884114e-01 -1.5556170e+00 4.5213858e-02 4.8597116e-01
+1 8.2940825e-01 1 1 1.5341733e+00 8.5057499e-01 -2.1501569e-01 -2.6905299e-01 7.6275112e-01 -9.2124182e-01 -3.5610558e-01 -4.2359484e-01
+1 7.6833819e-01 1 1 -1.3414937e+00 1.3672913e+00 -9.3713005e-01 -1.2218563e+00 -1.2815405e+00 -1.5426038e+00 -3.3249485e-01 -5.0959900e-01
+1 8.4381219e-01 1 1 7.2570641e-01 -6.8566079e-01 -1.5407513e+00 8.5183925e-01 -9.1111155e-02 1.0220706e+00 6.5243995e-01 -8.4888800e-01
+1 2.7778986e-01 1 1 1.2849908e+00 -5.3906506e-01 7.4067701e-01 6.2450558e-01 -1.3495537e+00 -2.8873233e-01 1.3998415e+00 -1.2884527e+00
+1 4.1536420e-01 1 1 1.5319977e+00 2.8674021e-01 1.5683713e+00 4.1980855e-03 3.4955215e-01 1.0364565e+00 -2.5185197e-01 -2.6022683e-02
+1 9.2562485e-01 1 1 -2.0838903e-01 3.9626164e-02 -1.4874162e+00 1.4421853e+00 1.4467042e-01 -4.0682478e-01 -1.1507383e+00 -6.8185512e-01
+1 1.0459976e+00 1 1 4.8140988e-01 -2.0709182e-02 -1.3505500e+00 1.4218244e+00 -1.1693959e-01 -1.3984824e+00 -8.1353704e-01 5.9095639e-01
+1 9.8892919e-01 1 1 1.4548529e+00 6.5756745e-01 -6.8609185e-01 -1.4931378e+00 1.2333250e+00 1.1031324e+00 -9.0577384e-01 -1.5119951e+00
+1 1.0306381e+00 1 1 6.9744732e-01 -3.8683449e-01 -1.5006893e+00 -1.2518879e-01 2.6448910e-01 -1.3342377e+00 8.1711372e-01 2.4094121e-01
+1 8.5555639e-01 1 1 7.1489767e-01 1.5695228e+00 -1.3784324e+00 8.1911377e-01 -8.5275172e-02 1.5539054e-01 1.3287927e+00 -1.3990273e-02
+1 7.0333599e-01 1 1 -1.3067621e+00 -9.8298415e-01 -1.2089119e+00 3.8614507e-01 -6.5356771e-01 9.8529227e-01 -5.6408266e-01 4.8493843e-01
+1 3.3151418e-01 1 1 1.2306309e-01 6.2119476e-01 -1.5032964e+00 -5.9026928e-01 -1.5046321e+00 4.7222485e-01 7.8929433e-01 1.0689016e+00
+1 1.0163425e+00 1 1 1.1533755e+00 9.0792848e-01 -1.2144264e+00 4.9374616e-01 1.4694788e+00 1.0200829e+00 -1.2759828e+00 1.4019080e+00
+1 9.4331606e-01 1 1 1.1557091e+00 8.3852243e-01 6.2520463e-02 1.4454572e+00 1.4696555e+00 8.6261196e-01 -9.3093987e-01 -7.7106745e-02
+1 5.8999984e-01 1 1 -4.6479308e-01 -1.3824101e-01 1.4894753e+00 -1.3641900e-01 1.2993846e+00 -5.3094307e-01 -1.1749068e+00 1.5446995e+00
+1 7.3227496e-01 1 1 1.3635889e+00 1.3618976e+00 1.4018671e+00 5.6847426e-01 1.5463814e+00 -1.4371079e+00 1.3926274e+00 -3.5676024e-01
+1 8.4910982e-01 1 1 -8.0091847e-02 -2.3133994e-01 -7.6441913e-01 7.6359103e-01 -3.6378036e-01 -9.0821009e-01 1.0239463e+00 1.2310013e+00
+1 2.6977787e-01 1 1 -1.5020183e+00 1.1612663e+00 1.5216724e+00 2.6839950e-01 -5.1727015e-01 7.1171288e-01 -1.7950801e-01 -1.0905390e+00
+1 8.5682331e-01 1 1 1.4177382e+00 -1.3124405e+00 -9.5735937e-01 -3.3664414e-01 -9.7246560e-01 -1.4264808e+00 -1.0622069e+00 -6.3747585e-01
+1 6.2551340e-01 1 1 -1.0535738e+00 -1.0661968e+00 8.9865915e-01 3.0350502e-02 1.4771893e+00 -1.3684989e+00 1.1588825e+00 -1.2257021e+00
+1 7.9600872e-01 1 1 -1.3983880e+00 7.5507205e-02 -1.0131133e+00 1.1628833e+00 -8.8597861e-01 -7.6075848e-01 -5.3690430e-01 -9.5295508e-01
+1 1.0150053e+00 1 1 -4.5258175e-01 -1.5383441e-01 3.7669325e-02 7.3146554e-01 5.0670230e-01 2.1433379e-01 -1.0964169e+00 -4.7663069e-01
+1 7.3543631e-01 1 1 -7.4570670e-01 3.5759038e-02 -1.4933711e+00 6.8921110e-01 -7.1207058e-01 -1.0988305e+00 1.1029189e+00 3.2921818e-01
+1 1.0241724e+00 1 1 -1.2794327e+00 9.5795106e-01 -9.0361742e-01 5.1877550e-01 -1.4437831e+00 1.3789649e+00 1.3609773e+00 8.2530472e-01
+1 5.4729853e-01 1 1 7.7640482e-01 -3.7892142e-01 -6.3914137e-01 1.1402405e+00 -1.6020643e-03 7.3333263e-01 9.7835126e-03 7.6487331e-01
+1 8.6688068e-01 1 1 -1.1399994e+00 -5.2401522e-01 -9.4379641e-01 3.0673081e-01 1.3484398e+00 6.5354266e-01 1.0686787e+00 -1.7142194e-01
+1 7.2824439e-01 1 1 6.0387896e-01 -1.2396290e+00 -4.8497237e-01 -1.2879795e-01 -2.2189477e-01 1.0835998e+00 7.9753261e-01 -2.4800598e-01
+1 7.5393009e-01 1 1 -1.0922572e+00 5.9819777e-01 1.5023157e+00 -1.4981607e-01 -3.1484500e-01 2.4870801e-01 -1.0452663e+00 6.5688360e-01
+1 2.9381670e-01 1 1 -1.2401953e+00 8.1348278e-01 4.4029257e-01 -1.5429575e+00 -1.1578227e+00 -1.4242195e+00 -4.9152475e-03 6.8609655e-01
+1 2.7994858e-01 1 1 5.0495073e-01 -6.1923779e-03 1.5465418e+00 1.3601046e+00 -5.0134241e-01 -1.0633224e+00 -9.2915549e-01 -1.5618799e+00
+1 4.4641610e-01 1 1 1.2651066e+00 -4.0273771e-01 -8.0881399e-01 1.0492800e+00 -3.1043736e-01 1.2616575e+00 5.4082890e-01 6.3215048e-01
+1 9.3966904e-01 1 1 3.4728215e-01 1.3195526e+00 -6.5386520e-02 1.4898005e+00 6.6473576e-01 -1.0722626e+00 1.0838395e+00 -3.1317231e-01
+1 7.8817665e-01 1 1 -3.0807885e-01 1.2173983e+00 6.0618815e-01 5.8403723e-01 7.1048498e-01 -1.3425780e+00 1.1360828e+00 -1.3193492e+00
+1 9.6540049e-01 1 1 -5.3652896e-01 -3.7963962e-01 1.9234094e-02 -1.5633273e+00 -7.2652360e-02 1.3513051e+00 -4.5624366e-01 -9.4101702e-01
+1 3.4117690e-01 1 1 -1.0713708e+00 -2.8343968e-02 -3.1663184e-01 1.4382280e+00 1.0113268e+00 8.1097856e-01 5.4051148e-01 -8.9559274e-01
+1 8.4379256e-01 1 1 1.0797181e+00 1.1450080e+00 2.2660469e-01 8.8337665e-01 1.3529541e+00 -1.2539175e+00 -1.1095616e+00 -8.5676954e-01
+1 5.5018395e-01 1 1 9.8238075e-01 -1.2479314e+00 9.3473373e-01 -2.5555908e-01 2.5131050e-01 -7.8811027e-01 9.1984299e-02 1.3350885e+00
+1 1.3876107e+00 1 1 -1.3376552e+00 -7.1086691e-01 -1.0350836e+00 -6.2426654e-01 1.4750075e+00 -8.1460300e-01 3.1652366e-01 -1.5646057e+00
+1 5.0971994e-01 1 1 -7.3375778e-01 -6.3257739e-02 1.4897664e+00 8.7166988e-01 1.4417920e-01 2.8222872e-02 1.0968090e+00 -1.1981903e+00
+1 1.2804631e+00 1 1 -1.5158097e+00 -1.3144958e+00 1.0047547e-02 9.0908137e-01 1.0518285e+00 -3.8675265e-02 -7.9762712e-01 -3.7569049e-01
+1 1.1696074e+00 1 1 -1.0391117e+00 -1.0510054e+00 -7.7687424e-01 1.3654764e+00 3.3905848e-01 2.9449221e-01 -5.4314471e-01 3.7123489e-01
+1 6.2298635e-01 1 1 -2.3713135e-01 9.2822628e-01 -4.6635204e-01 2.2693701e-01 -2.9316853e-01 1.5221664e+00 8.3515207e-01 1.4170584e-01
+1 4.3625569e-01 1 1 1.2145526e+00 -4.5003198e-01 2.9486287e-01 2.3679135e-01 -1.2661929e+00 1.0623777e+00 -2.3521226e-01 3.2287001e-01
+1 4.3176381e-01 1 1 -1.0838550e+00 1.2676167e+00 1.4686808e+00 -6.4566875e-01 2.4477948e-01 -1.4300350e+00 -1.0889509e+00 9.4577585e-01
+1 6.5466066e-01 1 1 -1.3964128e+00 -1.4480888e+00 6.2544384e-01 -6.9367249e-01 -1.4776835e+00 -1.4137835e+00 9.2100387e-01 -8.0408518e-01
+1 5.6431531e-01 1 1 1.3292896e+00 -1.1001024e-01 6.5645502e-02 -1.0315117e-01 -1.1361926e+00 1.5467318e+00 6.8505335e-01 8.7199755e-01
+1 7.0761894e-01 1 1 1.5041897e+00 1.4560058e+00 6.0492716e-01 4.9751454e-01 -1.3894731e+00 -7.5843884e-01 -2.4540374e-01 1.3317277e-01
+1 5.9543123e-01 1 1 5.2020887e-01 1.2249914e+00 8.1697233e-01 -1.1927942e+00 -1.4160116e+00 1.5014273e+00 4.1043654e-01 1.4208576e+00
+1 5.9206463e-01 1 1 9.8051520e-02 -1.5685794e+00 -1.0474681e+00 -7.8892601e-01 -1.3419065e+00 1.2160907e+00 -7.3048888e-01 1.1081950e+00
+1 3.3681111e-01 1 1 -1.3842406e+00 1.1323556e+00 6.8918383e-01 1.1830592e+00 7.1054214e-02 -3.6584171e-01 1.7479894e-02 -1.0688564e+00
+1 1.0349249e+00 1 1 -1.4373465e+00 -2.6737967e-01 6.0542659e-02 5.3606504e-01 4.0296999e-01 -6.0473058e-01 -1.5251323e+00 -6.4334173e-01
+1 6.8194586e-01 1 1 1.3643007e+00 -1.3725644e+00 -3.3554661e-01 -4.4253250e-01 -5.5708106e-01 -6.5465136e-01 -6.4405740e-01 7.1748834e-01
+1 5.3245119e-01 1 1 -6.8316027e-01 2.4576251e-02 -3.7307763e-01 -1.4938999e+00 -9.1532624e-01 -8.6801833e-01 1.2554989e+00 1.3939474e+00
+1 9.5693801e-01 1 1 6.4647888e-01 1.5044061e+00 3.0314384e-01 -3.6716005e-01 4.9110149e-01 7.7219069e-01 -9.0844830e-01 1.2171485e+00
+1 1.0647813e+00 1 1 -1.3984048e+00 1.0149988e+00 -7.2473899e-01 -7.7093603e-01 9.7882445e-01 2.8967334e-01 -1.5031245e-01 -1.4358060e+00
+1 5.4700569e-01 1 1 -7.3489272e-01 2.3707645e-01 -7.3354377e-01 -1.1938007e+00 -1.4182472e+00 -9.2885879e-01 -4.6093335e-01 -1.0180459e+00
+1 3.0352866e-01 1 1 1.4003672e+00 1.0044276e+00 -1.0605315e+00 1.1444446e+00 -1.2168305e+00 -7.5581336e-01 2.6064002e-01 -1.1830788e+00
+1 9.1288238e-01 1 1 -8.4058187e-01 -1.5046989e+00 1.0438505e+00 -1.2908483e+00 4.9830989e-01 -1.4959946e+00 1.1966690e+00 -8.6582943e-01
+1 6.5781674e-01 1 1 8.2694844e-02 3.4677510e-01 1.3417826e+00 5.5082388e-01 -3.9163476e-01 -1.0146692e+00 -6.0774024e-02 -1.3807962e-01
+1 4.9280300e-01 1 1 1.2682828e+00 5.9477794e-01 9.8772670e-01 -5.7656580e-01 -5.6887532e-01 -9.8008728e-01 -4.1141033e-01 9.3287027e-01
+1 4.1164399e-01 1 1 3.2309151e-01 -1.1502975e-01 5.4713749e-01 1.4719426e+00 -1.2210288e+00 -9.5671013e-01 7.2087277e-02 -9.3838959e-01
+1 2.4556497e-01 1 1 1.5269409e+00 -1.2255208e+00 2.9806158e-01 -1.1021320e+00 -9.4747749e-01 -7.5588362e-01 -1.0838959e+00 -7.1877004e-01
+1 7.3741319e-01 1 1 -3.7524912e-01 -1.0473743e+00 -1.3193683e+00 -7.0252240e-01 4.7900512e-01 4.6462261e-01 1.0567611e+00 -9.4438938e-01
+1 9.3226118e-01 1 1 1.5060764e+00 -8.7656189e-01 -1.2622004e+00 -1.1887543e+00 -1.2628505e+00 -1.0870518e+00 1.5601017e+00 -1.0262977e+00
+1 4.1498130e-01 1 1 8.1324757e-01 -1.4476805e+00 1.3722397e+00 1.1350386e+00 -1.2899703e-01 1.4237473e+00 8.9655498e-01 1.4995046e+00
+1 4.0690291e-01 1 1 -8.1778923e-01 4.6967539e-01 8.0097403e-01 8.4366072e-01 -3.5413209e-01 -5.8957276e-01 1.3211776e+00 3.1815610e-01
+1 9.0812277e-01 1 1 -1.1576338e-01 -9.8802794e-01 2.4598212e-01 1.3980313e+00 1.4201176e+00 -3.6616083e-01 2.5550719e-01 2.5888682e-01
+1 1.1073704e+00 1 1 -9.8924523e-01 6.7316132e-01 -1.1451668e-01 7.4139206e-01 1.2373931e+00 3.1496433e-01 -2.4779454e-01 5.0353779e-03
+1 2.2885070e-01 1 1 -9.3619775e-01 9.4712281e-01 1.1144900e+00 1.0198128e+00 -4.7722782e-01 2.1911541e-02 1.0689866e+00 -1.9340480e-01
+1 5.9682774e-01 1 1 1.5619727e+00 -1.5692825e-01 1.0574362e+00 -5.3499775e-01 -2.8195959e-01 7.0092776e-01 -3.1082038e-01 9.9399290e-01
+1 5.2357597e-01 1 1 9.2702629e-01 1.4446798e+00 3.4045843e-01 -4.6904063e-01 -1.3730276e+00 -4.7950752e-01 5.1043439e-01 -9.5113017e-01
+1 4.0420568e-01 1 1 1.3728231e+00 -6.3613855e-01 1.2445637e+00 -9.0983040e-01 -1.4769597e+00 -8.9764866e-01 -8.1873934e-01 -1.2212729e+00
+1 3.5148617e-01 1 1 1.1808102e+00 -7.4082116e-01 6.5807897e-01 -1.3881046e+00 -1.5376947e+00 -8.5303581e-01 -3.7634305e-01 1.2329540e+00
+1 5.7301464e-01 1 1 4.3668393e-01 -8.4963225e-01 -1.2145034e+00 -4.0764313e-01 -1.2931045e+00 1.2559820e+00 -1.1715789e+00 3.1244256e-01
+1 7.5048984e-01 1 1 5.8643883e-01 -1.2306314e+00 -1.2315564e+00 5.5541450e-01 3.3079307e-01 9.2867919e-01 7.7605169e-01 -1.5207378e+00
+1 4.1101176e-01 1 1 1.1013168e+00 1.0236533e+00 1.1851632e+00 1.1797504e+00 -9.7992955e-01 8.7887676e-01 -7.9195837e-01 9.5716651e-01
+1 4.0620174e-01 1 1 -4.3253206e-01 1.1804219e+00 1.3411785e+00 1.4742668e+00 -1.4473285e+00 -4.8689942e-01 4.8381461e-01 -9.9838095e-01
+1 3.2572807e-01 1 1 7.9120895e-02 1.9271281e-01 2.6054623e-01 2.6064108e-01 1.0107942e-01 5.3025055e-01 1.0304228e+00 -5.4220484e-01
+1 9.6063494e-01 1 1 8.9119301e-01 -5.7840805e-02 -3.7974347e-01 1.2143964e+00 -7.5986418e-01 -7.7730701e-01 -1.2841623e+00 9.2359630e-01
+1 7.4628311e-01 1 1 -8.3287018e-01 -1.3782725e+00 1.3677496e+00 -5.6737076e-01 -4.6321361e-01 -1.4566696e+00 -1.7428096e-01 2.7367493e-01
+1 4.6750074e-01 1 1 8.8773306e-01 1.4779597e+00 7.3454046e-01 -1.0666294e+00 -3.6453973e-01 1.8603916e-01 -1.1757442e+00 3.6282112e-01
+1 7.9337011e-01 1 1 7.0595340e-01 -5.0442545e-01 -1.0375492e+00 -9.1203196e-01 -7.1363203e-01 8.7544440e-01 -1.1438316e-01 1.0326595e-01
+1 6.8106476e-01 1 1 -8.3665120e-01 1.2800112e+00 8.9082538e-01 -6.9063711e-01 5.8723598e-01 1.5156891e+00 2.1697691e-01 1.4316514e+00
+1 1.0549975e+00 1 1 1.7205619e-01 -4.7856715e-01 -7.2839060e-01 6.4701365e-01 -1.2089971e+00 -9.8754270e-01 -6.5811270e-01 3.0665547e-01
+1 1.8245952e-01 1 1 1.4830610e+00 -8.0094310e-01 7.2579334e-01 1.3061614e+00 2.0783381e-01 -5.9621782e-01 6.4757029e-01 -1.3951404e+00
+1 7.6215307e-01 1 1 4.0996123e-01 2.7379265e-01 -3.9565123e-01 -7.9531562e-01 -3.8811336e-01 1.0477316e+00 1.2368374e+00 7.2279106e-01
+1 4.6135007e-01 1 1 7.0576402e-01 -8.0018521e-01 1.0413867e+00 6.0712066e-01 -1.0748617e+00 5.9871750e-01 -3.9197133e-01 -5.8952919e-01
+1 7.0806572e-01 1 1 -8.7805200e-01 4.4534598e-01 7.7379695e-01 -1.5995613e-02 -1.0427274e+00 1.2382216e-01 5.7641058e-02 3.6612166e-01
+1 1.3856386e+00 1 1 -1.3592806e+00 -1.4853561e+00 -9.8826247e-01 1.3387031e+00 -1.3159417e+00 1.3446724e+00 1.1627201e+00 -9.7326374e-01
+1 1.0019298e+00 1 1 2.3209324e-01 -1.2848247e+00 -1.2700246e-01 -5.0430963e-01 -2.1935714e-01 -7.0804953e-01 1.1308406e+00 6.2921575e-01
+1 1.3234561e+00 1 1 -1.0669907e+00 1.2599108e+00 -1.3889081e+00 8.5065994e-02 1.4942566e+00 1.6460397e-01 -5.9730756e-01 6.2829124e-01
+1 7.9024439e-01 1 1 -7.0246641e-01 9.8556076e-01 -1.3458274e+00 2.7950122e-01 7.8226808e-02 -1.2442424e+00 -1.5596532e+00 7.9796411e-01
+1 1.0303809e+00 1 1 -2.4779974e-01 -1.2984107e+00 1.4657507e-01 8.9606403e-01 -1.5693609e+00 -1.5416306e+00 3.5731343e-01 -7.6290536e-02
+1 1.7299678e-01 1 1 9.8157886e-01 -8.8581612e-01 4.7849787e-01 -6.4702457e-01 5.6398843e-01 -1.4709554e+00 -1.3582774e+00 -4.4524227e-01
+1 9.5552125e-01 1 1 8.9292216e-01 9.6041668e-02 -3.6343597e-01 -1.4898036e+00 7.6850970e-01 -1.1547579e+00 1.3852889e+00 8.6877544e-02
+1 1.1220840e+00 1 1 -4.5377449e-02 -6.0630305e-01 -1.0121709e+00 -6.3643269e-01 1.2551752e+00 7.4415742e-01 2.0817972e-01 -6.8969646e-01
+1 9.1823014e-01 1 1 7.4822742e-01 1.1912011e+00 1.6796108e-01 5.9877505e-01 -6.4408400e-02 3.7342520e-01 -8.5768923e-01 7.4856289e-01
+1 1.1468633e+00 1 1 -3.3716425e-01 -8.5359298e-01 -1.3699088e+00 1.0909376e+00 1.3374910e+00 -7.4476399e-01 -1.5557425e+00 -9.8209648e-01
+1 9.3988189e-01 1 1 7.1366761e-01 1.3164791e+00 6.7463002e-01 1.0536316e+00 1.1156267e+00 -1.1432646e+00 1.1093568e-01 -1.6778212e-01
+1 7.0876088e-01 1 1 1.0726284e-02 -1.7230583e-01 4.9883921e-01 -7.7168808e-01 1.3134385e+00 -8.6718029e-01 1.5315760e+00 1.2361500e+00
+1 9.5334999e-01 1 1 1.2058795e+00 6.0428310e-01 -9.2027339e-01 -1.2670541e+00 -1.0110094e+00 -8.5083536e-01 -1.0118188e+00 6.2045045e-01
+1 1.1132536e+00 1 1 8.0198648e-01 -5.8301404e-01 -9.7424076e-01 1.4779990e+00 8.3997988e-01 5.3982816e-01 -1.9689763e-01 9.6476625e-01
+1 7.0197000e-01 1 1 1.5542989e+00 -8.9502618e-02 -8.3548291e-02 1.5682443e-01 -7.7555150e-01 -2.7705393e-02 -1.1613995e+00 1.0666358e+00
+1 5.4897974e-01 1 1 7.5823271e-01 5.5238549e-01 9.5790172e-02 -4.8020702e-02 -2.2616352e-01 -6.8882515e-01 -9.2667243e-01 1.0196504e+00
+1 4.6902905e-01 1 1 1.3173387e+00 5.3671233e-01 1.4499873e+00 3.0537053e-01 1.9691139e-01 -3.1542254e-01 1.4328501e+00 -1.2335363e-01
+1 5.8518068e-01 1 1 -1.4327435e+00 1.0116442e+00 6.0274670e-01 -9.9996944e-01 1.3927411e+00 -1.4397770e+00 -1.5378610e+00 2.4675453e-01
+1 6.5749257e-01 1 1 1.8767179e-01 4.0473792e-01 -1.2725553e+00 1.0343187e+00 -2.0728971e-01 1.3560687e+00 -9.4639533e-01 3.0116360e-01
+1 9.0308065e-01 1 1 4.0694032e-02 8.8217087e-01 1.2650827e-01 1.3623524e+00 1.0802739e-01 -8.0785644e-01 -1.8271222e-01 5.5089391e-01
+1 1.0195994e+00 1 1 -9.2259492e-01 1.4700288e+00 -6.3365649e-01 1.1299256e+00 -2.2428579e-01 3.2031774e-01 -1.5082969e+00 6.0037736e-01
+1 7.9759713e-01 1 1 8.4844248e-01 1.2885825e+00 1.3443150e-01 -2.6737491e-01 3.3986943e-01 -1.1096163e+00 -4.3509483e-01 -2.5328546e-01
+1 7.9686698e-01 1 1 8.3709620e-02 -9.3384367e-01 5.8518123e-01 -1.2925575e+00 7.7014029e-01 -8.2755479e-01 9.8885858e-01 -1.1076214e-01
+1 1.1584370e+00 1 1 -5.2592392e-01 2.8630692e-01 -1.1857164e+00 9.9857035e-02 3.8610105e-01 -8.8274404e-01 7.2099373e-01 1.3851128e+00
+1 9.3832233e-01 1 1 1.2383949e+00 -9.5959195e-01 -1.2141729e+00 6.8670737e-01 -1.3301001e+00 1.4629780e+00 6.1870587e-01 3.8870356e-01
+1 4.2507287e-01 1 1 6.5177402e-01 1.0747046e+00 1.1822695e+00 -7.2063914e-01 5.8156866e-01 -9.7444791e-01 -8.2097534e-02 1.5696188e+00
+1 8.0874171e-01 1 1 -3.6767533e-01 1.5436233e+00 -1.7006459e-01 -9.4230715e-01 9.2978097e-01 -4.2348766e-01 -6.5408081e-01 6.2905524e-01
+1 8.4627025e-01 1 1 -6.5793051e-03 4.0492892e-01 5.7379428e-01 -5.8775574e-01 5.4697298e-01 1.2919098e+00 -7.0354198e-01 1.0721447e+00
+1 1.0390602e+00 1 1 -6.2263790e-01 9.5069142e-01 -9.2899362e-01 -1.2433776e+00 6.7474261e-01 -1.5597134e+00 5.2468323e-01 -6.3979474e-01
+1 8.7745065e-01 1 1 -3.0031614e-02 1.3051639e-01 1.1974327e-01 4.2779266e-01 -7.5039466e-01 -6.5398533e-01 -9.9557545e-02 6.4138569e-01
+1 6.5007978e-01 1 1 1.0550805e+00 7.5723168e-01 -1.2357722e+00 -1.1943447e+00 -1.5301682e+00 9.0126875e-01 1.2052293e+00 9.6494085e-01
+1 1.1619070e+00 1 1 -1.5526865e+00 2.0097476e-01 -5.5382727e-01 1.4264976e+00 -4.6020476e-01 -1.1358618e+00 -7.0084842e-01 8.5953309e-01
+1 3.6303447e-01 1 1 1.2074859e+00 5.7067299e-01 3.6417363e-01 -1.4901681e+00 -6.0289547e-02 1.0294670e+00 -1.3285457e+00 1.1296529e+00
+1 7.3838288e-01 1 1 -4.7351519e-01 1.8596311e-02 8.4373154e-01 -4.7913966e-01 1.4480178e+00 1.5008866e+00 -1.5684528e+00 1.4323756e+00
+1 9.6109387e-01 1 1 -7.1556520e-01 1.5305276e+00 -5.5321809e-01 -9.9834180e-01 -1.0828409e+00 1.5535141e+00 1.1746297e-01 -8.8625989e-02
+1 2.0932387e-01 1 1 -4.8770231e-01 2.1609410e-01 1.1778767e+00 1.1572577e-01 -6.0484516e-02 1.3572436e-01 1.2799277e+00 -4.2207770e-01
+1 2.4000660e-01 1 1 -3.9745950e-01 2.1249389e-01 1.3982599e+00 3.5708208e-01 1.3127674e+00 3.2310112e-01 1.2599287e+00 -1.4374912e-01
+1 3.8481576e-01 1 1 -1.0758836e+00 -6.0598648e-01 1.4405514e+00 1.0365058e+00 2.7691270e-01 -1.4531135e+00 1.2869023e+00 -1.0665315e-01
+1 9.9682638e-01 1 1 6.3139511e-01 2.2865055e-01 -9.0803159e-01 4.2213483e-01 1.3729921e+00 2.6333645e-01 -8.9901535e-01 1.3299460e+00
+1 5.8172693e-01 1 1 -4.4228803e-01 7.6206091e-01 5.7013526e-01 1.1038818e+00 8.8022677e-01 -6.0831974e-01 1.3096194e+00 -2.8965752e-02
+1 8.5563411e-01 1 1 -5.2666567e-01 -3.1553942e-01 4.0575982e-01 -1.3050938e+00 2.1157112e-01 -1.2873258e+00 7.7467863e-01 1.1946102e-01
+1 7.4773316e-01 1 1 1.3382604e+00 -2.6263300e-01 -7.9236965e-01 -1.1153675e-01 -4.0703018e-01 6.4212271e-02 1.2637668e+00 3.0371850e-01
+1 9.9133739e-01 1 1 1.4803376e+00 -1.3511738e-01 -1.4548812e-01 9.3264994e-01 1.4325773e+00 -1.4922391e+00 -1.7920048e-01 -4.9124619e-01
+1 1.1741291e+00 1 1 -1.3796385e+00 4.5372104e-01 -1.0596673e+00 -1.4998110e+00 1.6043885e-01 -7.2808925e-01 9.6481214e-01 -2.6925644e-01
+1 9.4193303e-01 1 1 5.1166009e-01 1.0441712e+00 -1.4026831e-01 8.1539884e-01 1.0092266e+00 -4.9263684e-01 -1.3037036e+00 -1.4995899e+00
+1 5.3553284e-01 1 1 9.3197191e-01 4.4871567e-01 -1.2950099e+00 7.8109951e-01 6.1257883e-01 1.4909298e+00 1.2626164e+00 1.3901220e+00
+1 1.2449308e+00 1 1 -3.2912103e-01 -1.3996704e+00 -2.7691344e-01 -7.7628536e-01 6.1321968e-01 7.1442319e-01 -6.6450360e-01 -2.4430922e-01
+1 4.4470536e-01 1 1 8.0751091e-01 -1.4727298e-02 -1.3854824e+00 6.2273138e-03 -1.1822573e+00 1.4335798e-01 4.9896605e-02 -4.3543008e-02
+1 9.0375437e-01 1 1 1.5552788e-01 6.6412242e-01 -3.1849862e-01 9.8990616e-01 3.7526989e-01 -1.8400919e-01 -1.9299904e-01 1.6374666e-01
+1 6.4161094e-01 1 1 1.5207491e-01 -1.7314426e-01 2.6751021e-01 -5.2184361e-01 -1.1569372e+00 -1.3153070e+00 1.5303066e+00 5.4969364e-02
+1 4.0253083e-01 1 1 -1.3334375e+00 -9.2082372e-01 4.2504088e-01 7.0117025e-01 -1.3266101e+00 1.0223856e+00 -3.5617032e-01 2.4186223e-01
+1 7.8667695e-01 1 1 1.0379092e+00 -7.9877360e-01 -3.1968885e-01 4.5441098e-01 -4.5274884e-01 -1.2770503e+00 -1.4205796e+00 -2.4240211e-01
+1 9.7179552e-01 1 1 -1.1240193e+00 -9.6243102e-01 -8.8698447e-01 7.3572347e-02 -4.1242219e-01 -2.3276116e-02 4.2223507e-01 5.9334858e-01
+1 5.5808805e-01 1 1 -9.9563351e-01 4.8245961e-01 -6.9087342e-01 -1.2570726e+00 -1.2262962e+00 1.4974035e+00 -3.5294236e-01 9.9452832e-01
+1 4.7080061e-01 1 1 -1.4898602e+00 2.4808510e-01 -1.8304824e-01 -4.0932211e-01 -1.5128438e+00 -4.3743865e-01 -5.7524167e-01 -1.3769694e+00
+1 1.0544280e+00 1 1 1.5541492e+00 6.7289399e-01 -8.7263407e-01 6.1128952e-01 -1.4565715e+00 -7.0461322e-01 -1.4062265e+00 1.3876954e+00
+1 7.1605185e-01 1 1 1.3838352e+00 -4.0418908e-01 -1.4063872e+00 9.3494849e-01 -1.3072233e+00 1.3699691e+00 -2.4752183e-01 -1.8728660e-01
+1 5.3114761e-01 1 1 9.0791727e-01 -1.0825695e+00 1.9318444e-01 -5.6716754e-01 -1.3446653e+00 3.3792269e-01 -6.3071470e-01 1.4997190e-01
+1 8.7640138e-01 1 1 6.5008563e-01 1.3587866e+00 -1.5558815e+00 -7.9275598e-01 8.2705188e-01 -5.3279570e-01 -6.8827556e-01 1.0204740e+00
+1 6.4459308e-01 1 1 -4.7001936e-01 8.8892634e-01 9.1695953e-01 -3.5525836e-01 -1.2864836e+00 -1.1582714e+00 -5.0320792e-01 1.1525613e+00
+1 7.7139212e-01 1 1 1.4901082e+00 -1.2296343e+00 -1.3148122e+00 1.3404552e+00 -1.4896990e+00 1.3818086e+00 -2.4809174e-01 3.6882224e-02
+1 1.0572804e+00 1 1 -5.2856936e-01 -1.0663874e+00 -8.5553558e-02 6.6939985e-01 1.1226631e+00 1.4041831e+00 -7.8444641e-01 9.8578354e-01
+1 2.9560750e-01 1 1 7.5880464e-01 1.3895670e-02 9.5078416e-01 5.5998096e-01 1.9367517e-01 4.6093575e-01 1.0735217e+00 -6.9578099e-01
+1 8.5551041e-01 1 1 1.5049271e+00 1.0666696e+00 -1.4524650e+00 -6.1156007e-01 4.0850968e-01 -2.2041526e-01 5.1285175e-01 -9.8323124e-01
+1 1.1881838e+00 1 1 3.4771261e-01 -1.5531651e+00 -1.4044097e+00 8.0104359e-01 1.4422104e+00 -5.8147789e-01 -1.0309568e+00 -3.9002609e-01
+1 1.0267279e+00 1 1 6.4353833e-01 -5.5170000e-01 -1.1279841e+00 1.4151557e+00 -1.2994736e+00 5.9580959e-01 -1.4071513e+00 1.3353259e+00
+1 2.5673592e-01 1 1 -5.5487232e-01 1.5596837e+00 1.4833457e+00 -4.7610839e-01 9.9494209e-02 1.5160440e+00 -8.3012288e-02 -7.1507074e-01
+1 6.7965548e-01 1 1 -1.4921687e+00 1.5508515e-01 -1.0874115e+00 -3.1719344e-01 8.7188235e-01 -1.3061036e+00 -3.2038631e-01 1.5395831e+00
+1 1.2791926e+00 1 1 4.5554165e-01 -1.0057557e+00 -1.4798077e+00 2.1257781e-01 1.3385921e+00 -1.3752522e+00 -4.2862510e-02 -1.5257480e+00
+1 7.2564109e-01 1 1 2.2716868e-01 1.1748406e+00 8.6095768e-01 8.0438817e-01 7.7305207e-01 -1.1667416e+00 -9.6548922e-01 -1.5681819e+00
+1 6.8320565e-01 1 1 9.8893620e-01 6.3612106e-01 -5.9985864e-02 1.0787764e+00 -9.4108750e-01 3.9609518e-01 -6.5119276e-01 1.5297021e+00
+1 2.0394123e-01 1 1 -1.1160233e+00 4.4685583e-01 2.6882892e-01 8.6413676e-01 1.0613364e+00 1.3677751e-01 7.1215505e-01 -1.0910958e+00
+1 7.6676746e-01 1 1 1.4465190e+00 -1.2420246e+00 5.9736856e-01 -3.6354271e-02 -8.3021387e-02 -8.2613250e-01 -2.7816547e-01 -5.7058605e-01
+1 7.3049629e-01 1 1 -1.1414729e+00 1.1764950e+00 -5.5679803e-01 -1.5372637e+00 -4.7331909e-01 1.0306570e+00 -4.3712261e-01 1.4426740e+00
+1 4.9833737e-01 1 1 9.7122129e-01 1.6708166e-01 6.9995452e-01 -3.3352104e-01 -5.6135803e-01 -4.8989947e-01 1.4654792e+00 2.0936475e-01
+1 9.6571671e-01 1 1 -3.9927920e-01 -4.4243191e-01 -1.1289102e+00 -8.8687416e-01 -5.4170110e-01 3.7396652e-01 2.2179150e-01 2.0961902e-01
+1 8.7273740e-01 1 1 -2.4353865e-01 1.9674497e-01 -1.5153496e+00 1.1632030e+00 -3.4876881e-02 -1.0715658e+00 -1.4208192e+00 1.3414650e+00
+1 7.5898375e-01 1 1 3.4118191e-01 -1.4043553e+00 4.1133187e-01 -1.7824695e-01 1.3020937e+00 9.4486107e-01 -4.6179586e-01 -1.2084282e+00
+1 7.3848996e-01 1 1 8.3770164e-01 -2.1311656e-01 -1.3907023e+00 1.2829260e+00 -4.6124168e-02 -4.7083324e-01 1.4723949e+00 3.4425610e-01
+1 6.5736643e-01 1 1 -1.3668746e+00 -4.3441116e-01 -8.3451147e-02 1.3869539e+00 7.6449620e-01 3.7757565e-01 2.1583539e-01 -9.0145068e-01
+1 7.9910152e-01 1 1 1.4057889e+00 -8.7022935e-02 -1.4131098e+00 -8.3782209e-02 -2.2639076e-01 -1.0317685e-01 -9.9404819e-01 1.2198560e+00
+1 8.4616243e-01 1 1 -8.2474505e-01 1.3877084e+00 3.0419777e-01 -6.9407154e-01 -4.8080781e-01 6.5909703e-02 2.1879104e-02 8.6677676e-02
+1 7.0803223e-01 1 1 -7.8327703e-01 3.2007210e-02 1.2807496e+00 -5.2685519e-01 -7.6049644e-01 -1.2378228e+00 1.5575436e-01 -9.0728959e-01
+1 1.1922517e+00 1 1 -1.2638218e+00 7.3283928e-01 -6.3368021e-01 1.2944992e+00 1.4768119e+00 -4.6165315e-01 8.1678745e-01 4.7452338e-01
+1 4.1353278e-01 1 1 -7.4562487e-01 -1.3549827e+00 -2.6420181e-01 1.1188430e+00 -9.4611076e-01 7.2936363e-01 -1.0132876e+00 -1.1892350e+00
+1 1.1976657e+00 1 1 9.5905101e-02 2.1173791e-01 -1.3693894e+00 -1.1795389e+00 1.4584835e+00 -7.9955826e-02 2.4848468e-01 -6.6092978e-01
+1 7.8179528e-01 1 1 2.3999473e-01 -7.4540426e-01 -2.0464386e-02 -1.0608361e+00 -1.1150858e+00 7.8408098e-01 1.1053265e+00 4.2474897e-01
+1 1.2377850e+00 1 1 -2.1351976e-01 6.6214565e-01 -1.5113326e+00 -9.3384654e-01 1.4941237e+00 -9.3216124e-01 9.8510706e-01 1.0574029e+00
+1 1.0253232e+00 1 1 -9.2786925e-01 1.1606867e+00 -1.1903246e+00 2.3804212e-01 9.8764010e-01 2.8867913e-01 5.0102069e-01 -2.1836091e-01
+1 1.0805760e+00 1 1 1.6739308e-01 1.5124806e+00 -1.2384528e-01 1.5264190e+00 -9.0847773e-01 1.2110695e+00 1.1864161e+00 -6.1164293e-01
+1 5.2754695e-01 1 1 -1.4915050e+00 -1.5064110e+00 1.4083185e+00 2.7910419e-01 -6.4483610e-01 6.5678450e-02 4.0707934e-01 -5.9152987e-01
+1 5.7822720e-01 1 1 -9.5684116e-01 -1.5398095e-01 8.5023297e-01 5.0624125e-01 7.3433922e-01 1.1586815e+00 -6.0634687e-01 1.2981475e+00
+1 2.6417706e-01 1 1 1.8335402e-01 7.1444544e-01 -1.2393971e+00 9.6385897e-01 -1.2782544e+00 -7.7247073e-01 4.5478792e-01 -3.9517619e-01
+1 6.0003023e-01 1 1 -2.7144421e-01 5.1737944e-01 1.3531456e+00 1.5259712e+00 -1.4111777e+00 1.2869441e+00 1.2566446e-01 -3.9941483e-01
+1 8.6192714e-01 1 1 -5.7033824e-01 -3.3218796e-01 3.2838742e-01 -9.6458510e-01 1.3609661e+00 -1.9589336e-01 8.9234822e-01 6.1849498e-01
+1 1.0432342e+00 1 1 -6.7567466e-01 -4.7285367e-01 -5.7089107e-01 -1.1636613e+00 -1.7929255e-01 9.4006626e-03 -2.6687167e-01 -4.8490653e-01
+1 8.4771354e-01 1 1 7.9349229e-01 9.7779641e-01 -5.4220254e-01 -1.2405282e+00 -5.8251357e-01 9.1730320e-01 8.8222693e-01 -5.3277628e-01
+1 2.8660442e-01 1 1 1.6414954e-01 1.5305142e-01 9.6219830e-01 1.1922222e+00 -1.1029037e+00 1.3197582e+00 -7.2937994e-01 -8.3180173e-01
+1 7.2657694e-01 1 1 5.4301826e-01 -6.2915606e-01 -1.2521106e+00 6.0111635e-01 -1.1065729e+00 1.5319882e+00 -1.9411841e-01 -4.4161306e-03
+1 4.8442595e-01 1 1 1.8124041e-01 3.7491831e-01 1.3064168e+00 -3.9947335e-01 5.7741620e-02 -3.6768991e-01 1.5666960e+00 1.1763174e+00
+1 6.9315512e-01 1 1 -1.2373092e+00 -7.8278450e-01 3.5681484e-01 -3.6502017e-01 -2.8871940e-01 -2.5161598e-01 -1.3691387e+00 3.2412466e-01
+1 8.6603258e-01 1 1 -1.2547524e+00 7.3086085e-01 -3.1330624e-01 6.3644251e-01 1.2536604e+00 -3.2606098e-01 1.0527164e+00 4.1525583e-02
+1 6.5868759e-01 1 1 8.8807345e-01 -4.8984477e-02 -4.2872058e-01 -4.3379450e-01 -3.9168087e-01 -1.1693019e+00 -4.4576315e-01 4.8690257e-01
+1 6.1416602e-01 1 1 1.4380648e-01 -1.8482960e-01 1.3067784e+00 8.5232105e-01 -1.3437675e+00 1.3465740e+00 7.5726175e-01 -4.7731417e-01
+1 6.9355988e-01 1 1 1.0707935e+00 6.0399556e-01 1.4978178e-01 -7.0267821e-01 2.0861227e-01 -1.6500752e-01 7.0636597e-01 1.4083206e+00
+1 8.0312182e-01 1 1 -1.3573204e+00 8.6756908e-01 9.6668124e-01 -6.6595120e-01 1.2903856e-01 7.4488338e-01 -1.8571168e-01 8.8571240e-01
+1 1.0209245e+00 1 1 -1.3800410e+00 1.1020351e+00 -1.3056875e+00 8.5287608e-01 1.0521645e+00 8.2631458e-03 1.4869696e+00 1.3022402e+00
+1 9.7707217e-01 1 1 3.0151402e-02 -9.2564624e-01 -6.6456564e-01 -7.9897439e-01 -2.9603885e-01 6.4861388e-01 1.2768608e-01 -7.2508103e-01
+1 1.1787893e+00 1 1 9.5819846e-01 -1.6945305e-01 -9.9277551e-01 -1.1955141e+00 7.5782332e-01 -7.2951029e-02 3.1211691e-01 -1.9895917e-01
+1 1.0703437e+00 1 1 6.3756111e-01 1.4271320e+00 -5.7935772e-01 6.2057655e-01 7.1990111e-01 -8.6681642e-01 -7.1089881e-01 -1.2522284e+00
+1 1.1757714e+00 1 1 -4.8304310e-01 -2.5221183e-01 -1.4695950e+00 -5.7551758e-02 1.1046489e+00 -1.0184059e+00 -5.9943221e-01 -6.7381683e-01
+1 9.8185954e-01 1 1 -6.2996204e-01 -9.1567572e-01 -2.8122599e-01 3.3813565e-01 -9.7908327e-01 -9.5059794e-01 4.3051431e-01 6.0211271e-01
+1 2.6907781e-01 1 1 -6.0484298e-01 9.0065985e-01 1.5317731e+00 -9.5171134e-02 2.0981188e-01 1.4406590e+00 5.6609455e-01 6.3845727e-01
+1 1.1962654e+00 1 1 5.9782802e-01 1.1966256e+00 -8.4135941e-01 -4.7059069e-01 1.4412851e+00 9.0070591e-01 -1.5329818e+00 -1.1292171e+00
+1 9.7462280e-01 1 1 8.8223707e-01 -7.8934384e-01 -4.1904086e-01 1.3125760e+00 -1.1417501e+00 -1.1707878e+00 -6.2327903e-01 -3.9135908e-01
+1 7.4218305e-01 1 1 -5.5896561e-01 4.4392516e-01 6.3097837e-01 2.0096679e-01 -5.4657097e-01 1.5050721e+00 -1.3806714e+00 9.2290361e-01
+1 1.1602154e+00 1 1 -1.1730085e+00 -2.3235593e-01 -1.1633258e+00 4.3669699e-01 -2.0137231e-01 -3.5787226e-01 -1.1400424e+00 1.1980743e+00
+1 4.3252682e-01 1 1 -1.2592038e+00 -2.0647787e-01 1.2552962e+00 8.0585558e-01 -9.6917507e-01 1.3909172e+00 -1.1906037e-01 1.5675131e+00
+1 9.1887276e-01 1 1 1.4710633e+00 1.1862607e+00 -1.1729539e+00 6.0878226e-01 2.3248273e-01 5.5380136e-01 1.4683482e-01 -2.0347306e-01
+1 7.9498304e-01 1 1 -1.7337654e-01 9.3615224e-01 -3.4298401e-01 -3.6374604e-01 -8.0396448e-01 -7.9954032e-01 -1.4390220e+00 1.4226500e+00
+1 7.2631921e-01 1 1 1.4584204e+00 8.1466099e-01 2.9025601e-01 5.9571659e-02 -2.4107204e-01 -1.2823439e+00 1.4793818e+00 -1.8294828e-01
+1 1.0521215e+00 1 1 9.6534508e-01 9.4641628e-01 -5.6065237e-01 -9.4718324e-01 9.5669472e-01 -1.0283857e+00 1.4062218e+00 8.0746286e-01
+1 7.5161421e-01 1 1 1.3703498e+00 5.3480185e-01 -1.2480114e+00 -8.5869787e-01 4.9690597e-01 9.6504774e-01 1.6835084e-01 -6.5196704e-01
+1 7.1842416e-01 1 1 4.5325325e-01 3.1802980e-01 1.0857778e+00 3.4158319e-01 1.1453729e+00 -4.8554193e-01 -1.1024323e+00 2.6505224e-01
+1 8.1222040e-01 1 1 -5.3476544e-01 1.2777134e+00 -8.4409814e-01 1.2988767e+00 -1.3975040e+00 1.3544850e+00 5.3390565e-01 -4.5357902e-02
+1 5.4506671e-01 1 1 2.9387345e-01 -1.3976139e+00 6.7498252e-01 -7.0745104e-01 -1.3038628e+00 8.4828067e-01 9.6368751e-01 1.0767624e+00
+1 3.1069716e-01 1 1 5.4734304e-01 -8.3556592e-03 1.4007814e-01 7.9850037e-01 -1.4126009e+00 5.0572957e-01 -1.3557053e+00 -1.5689037e+00
+1 4.7313134e-01 1 1 6.1112706e-01 9.3810477e-01 1.2403319e+00 -4.8816424e-01 -5.6723649e-01 -1.3528185e+00 6.3182791e-01 -1.1765810e+00
+1 9.5621114e-01 1 1 1.3461500e+00 -9.2665470e-01 -1.3499454e+00 1.2635456e+00 1.1900389e+00 -1.1149177e+00 5.4859501e-01 1.5283127e+00
+1 5.9161535e-01 1 1 -1.0064738e+00 -1.4107449e+00 5.0087567e-02 -7.5586603e-01 -1.5363564e+00 1.1781732e+00 -3.3814249e-01 6.9011258e-01
+1 9.3751766e-01 1 1 -1.4695318e+00 -7.9018611e-01 -1.2509317e-01 7.6033364e-01 -7.9216803e-01 9.9281817e-02 -1.9675977e-02 -3.7925491e-02
+1 8.8723238e-01 1 1 7.8042749e-01 -1.1458707e+00 -7.1538153e-01 -1.0714129e+00 1.0165892e-01 4.4379765e-01 -8.2691352e-01 3.2958623e-01
+1 6.2190901e-01 1 1 4.9553206e-01 -6.8662710e-01 -5.4236395e-01 3.7197367e-01 -4.4501213e-01 7.6608784e-01 4.7040359e-01 7.2790627e-01
+1 5.8815082e-01 1 1 4.5220216e-02 -1.0718749e+00 1.3910535e+00 -7.9488422e-03 8.1330412e-01 1.3916393e+00 -1.3154977e+00 5.5887907e-01
+1 3.9387183e-01 1 1 -2.4924933e-01 -1.1094745e+00 -2.9613533e-01 1.4922934e+00 1.3263146e-01 1.2468783e-01 9.5890543e-01 -2.8142657e-01
+1 3.9216641e-01 1 1 -1.3904976e+00 1.5566968e+00 -8.6380510e-01 -1.5004553e+00 -1.3937612e+00 1.8609980e-01 -4.6719052e-02 1.3021814e+00
+1 8.5521912e-01 1 1 2.1491115e-01 2.1949640e-01 -6.7270155e-01 -5.8881655e-01 -1.2288562e+00 -1.2470062e+00 1.9105988e-01 1.4279069e+00
+1 8.2362996e-01 1 1 -8.1977750e-01 8.4627888e-01 4.9700185e-01 -2.2285826e-01 -5.5653785e-01 -8.6777898e-01 4.3571210e-01 2.0509469e-01
+1 8.5985757e-01 1 1 1.0249346e+00 1.4192658e+00 -3.8469670e-01 -8.0034896e-01 -1.2102875e+00 -1.4882969e+00 -3.9187947e-02 6.9934522e-01
+1 8.0770153e-01 1 1 7.2361063e-01 -5.1214624e-01 -1.9977729e-01 8.3481240e-01 5.1028621e-01 -4.4552119e-01 1.1026389e+00 1.1969878e+00
+1 7.0976690e-01 1 1 6.1872155e-01 3.2196642e-01 7.0560241e-01 3.3915453e-01 -1.6768903e-01 -1.4592884e+00 -2.0380119e-01 -9.8464877e-01
+1 8.7201390e-01 1 1 1.8140418e-01 1.4671449e+00 -4.5254066e-01 1.3210345e+00 -3.4088130e-01 1.5346994e-01 -9.5065610e-01 9.1817249e-01
+1 8.1220741e-01 1 1 1.5151120e+00 -5.5639359e-02 -5.5025863e-02 9.9219495e-01 1.0730689e+00 1.2175527e-01 4.6314311e-01 2.2189153e-01
+1 6.3336175e-01 1 1 -1.2619979e+00 1.0639102e+00 -1.1914470e+00 2.4670448e-01 -8.1504892e-01 1.1640754e+00 -8.2039429e-01 2.6040879e-01
+1 7.9037631e-01 1 1 -1.5064701e+00 -8.0658431e-01 -1.3746632e-01 -5.4004047e-01 -1.1832325e+00 -1.2232018e+00 8.3353196e-02 4.5202324e-01
+1 1.0158246e+00 1 1 -1.1473310e+00 -2.9013931e-01 -1.3258062e+00 -3.9895325e-01 -3.0730099e-01 2.2912206e-01 -2.3315507e-01 7.8350977e-01
+1 6.5734107e-01 1 1 -9.6647094e-02 -6.1963881e-01 4.9224606e-01 -1.0486077e+00 -2.9408648e-02 -7.3809429e-01 -1.0711954e+00 -1.1076527e+00
+1 3.1208744e-01 1 1 -1.4430909e-01 1.1019693e-01 1.3660490e+00 3.8457252e-01 -1.0410987e+00 9.9873101e-01 8.8709729e-01 7.5946245e-01
+1 8.7418197e-01 1 1 -9.3363579e-02 -1.4597964e+00 4.2583553e-01 1.2542800e+00 9.2485922e-01 1.4255515e-01 -5.5457401e-01 -5.6326333e-03
+1 7.8948192e-01 1 1 -1.5069362e+00 1.0400500e+00 4.6964409e-01 5.9769819e-01 -4.9150978e-01 -1.1108341e+00 3.7997525e-01 -4.1988748e-01
+1 6.3297485e-01 1 1 4.4345284e-01 2.9816078e-01 -1.5141462e+00 -1.2997597e+00 -1.5577479e+00 6.9631912e-01 -6.1383449e-01 -1.0316942e+00
+1 8.6453714e-01 1 1 1.2540550e+00 3.4791866e-01 -1.3550216e+00 -1.5674444e+00 9.6470031e-01 6.0280464e-01 2.7391785e-01 -1.2343354e+00
+1 5.7454398e-01 1 1 -4.3017174e-02 9.6503724e-01 -4.4361103e-01 1.3581156e+00 -4.1635166e-02 -2.9875208e-01 1.3040420e+00 -1.5395885e+00
+1 1.1756956e+00 1 1 -4.2333589e-01 -6.6193096e-01 -7.7118155e-01 -9.6376074e-01 8.1293188e-01 -8.6109159e-01 1.2841037e+00 1.4353653e+00
+1 4.9395268e-01 1 1 7.0102456e-01 -6.9412292e-01 9.6292868e-01 1.2494066e-01 1.5971034e-01 9.5093412e-01 -8.1090613e-01 -1.0600180e-01
+1 1.2871159e+00 1 1 1.1473334e+00 -1.3903599e+00 -1.5430191e+00 1.2937765e+00 1.3315576e+00 1.0678771e+00 -6.7035969e-01 -2.8928944e-01
+1 8.5457354e-01 1 1 1.3684727e-01 -6.1282324e-01 3.2512827e-01 1.5386379e+00 -1.2169368e+00 -1.0846689e-01 -9.8409052e-01 1.0977404e+00
+1 3.3314553e-01 1 1 3.4626202e-01 1.5620730e+00 1.2011632e+00 1.4387879e+00 -1.2879548e+00 -8.7930526e-01 8.7586995e-01 -8.5055966e-01
+1 5.6543324e-01 1 1 1.3961877e+00 -5.2807674e-01 7.4725166e-02 8.6915276e-01 -1.0837546e+00 -4.3169706e-01 -7.5697331e-01 -1.1095676e+00
+1 6.3116762e-01 1 1 1.1706780e+00 -3.8658093e-01 -7.3120054e-01 -5.5535591e-01 2.8985557e-01 1.5466197e+00 9.9976473e-01 -8.3317391e-03
+1 6.1499693e-01 1 1 -2.0961414e-01 -4.5200113e-01 6.2293328e-01 -1.9505509e-01 -1.0076651e+00 5.0050700e-01 -1.3333695e+00 1.3401311e+00
+1 7.9425086e-01 1 1 -1.2594910e+00 -4.1202080e-01 -1.2886408e+00 1.5318521e+00 4.9828975e-01 -1.1640197e+00 -9.5998227e-01 1.5061127e+00
+1 8.9341528e-01 1 1 -2.1475832e-01 -7.6335093e-01 -4.6770185e-02 4.8563983e-01 -7.3015222e-01 -9.8151771e-01 7.9786028e-01 1.4249295e+00
+1 4.8658891e-01 1 1 2.4681633e-01 6.2539258e-01 -6.6833876e-01 2.9084559e-01 -6.0741372e-01 1.3492383e-01 1.3202456e+00 4.2971656e-01
+1 5.2473946e-01 1 1 1.3398280e+00 -7.9596600e-01 1.5657148e+00 -7.6369474e-02 1.3736881e+00 -5.6504802e-01 2.9939161e-01 -2.7533879e-01
+1 6.6460262e-01 1 1 -4.4711996e-01 -8.9898435e-01 9.8865734e-01 1.3696462e+00 1.0656993e-02 2.7244161e-01 -9.5656309e-01 -5.3107191e-02
+1 7.7171629e-01 1 1 -5.5490401e-02 -1.3108462e+00 4.8041150e-01 1.1942562e+00 4.1303699e-02 -1.5160144e+00 -1.4262841e+00 -3.6024222e-01
+1 7.0971905e-01 1 1 4.2584196e-01 5.9692636e-01 3.8289354e-01 2.2896706e-01 -1.0070430e-01 -1.3369823e+00 -1.2052190e+00 -7.4195363e-01
+1 2.0938624e-01 1 1 5.7780346e-01 1.4359384e+00 1.3099092e+00 -2.0166979e-01 7.8119763e-01 1.1511140e+00 8.7367230e-01 -1.0334463e+00
+1 1.0192800e+00 1 1 4.7991702e-01 1.0211694e-01 -6.3789258e-01 3.1423924e-01 8.7290538e-01 8.4600852e-01 6.2897395e-03 7.3327727e-01
+1 6.1596995e-01 1 1 1.4969549e+00 9.6982911e-01 1.1950986e+00 4.0167843e-01 -3.1691784e-01 1.6787847e-02 -1.1024988e+00 -2.7693776e-01
+1 9.4241972e-01 1 1 1.4474089e+00 1.3350904e+00 -1.3217970e+00 -2.7321664e-01 -1.4385882e+00 -5.8998828e-01 -5.8311835e-01 1.3473224e+00
+1 7.8030292e-01 1 1 1.2491056e+00 -1.5313883e+00 -1.2409523e+00 1.0563229e+00 -6.5505102e-01 -1.0666683e+00 1.2990427e+00 -1.5282883e-01
+1 5.6240945e-01 1 1 -1.5457567e+00 1.0246492e+00 3.4844480e-01 4.7856540e-01 -1.3017540e+00 -1.5660040e+00 -1.0584876e+00 1.2285648e+00
+1 2.5243333e-01 1 1 1.4391903e+00 -9.3241122e-01 3.8301967e-01 7.7141380e-01 -5.2757876e-01 4.3377336e-01 8.3872248e-01 -1.1994558e+00
+1 6.1017540e-01 1 1 1.3489403e+00 -7.7127368e-01 2.8818126e-01 -2.0117021e-01 -1.4418296e+00 -1.2076562e+00 8.2499298e-02 3.4604852e-01
+1 1.1000550e+00 1 1 -1.2339190e+00 -5.8545428e-01 -8.7345508e-01 -7.1403718e-01 1.4160581e+00 7.5258478e-01 1.1233450e+00 9.4949041e-01
+1 6.5144884e-01 1 1 -8.2361563e-01 -2.6190375e-01 5.0290835e-01 6.1052237e-02 -1.0174669e+00 6.4045289e-01 -9.1176024e-01 -1.2054323e+00
+1 3.2377273e-01 1 1 -6.5065363e-01 -4.4508103e-01 1.4964446e+00 -1.1958428e+00 -8.7784038e-01 9.9530227e-01 7.3460869e-01 4.3024514e-01
+1 5.3565543e-01 1 1 3.4842320e-01 -3.4468227e-01 -8.4613200e-01 1.3791265e+00 -9.4420259e-01 -9.3554629e-01 1.0907783e-01 -8.1622188e-01
+1 7.2690578e-01 1 1 2.0013298e-02 2.2021709e-02 1.0494184e+00 3.0905065e-01 -1.0284901e+00 -5.5344954e-02 -1.4190304e+00 1.0940444e+00
+1 1.7949574e-01 1 1 2.1308417e-01 -5.8907179e-01 6.7431059e-01 1.1616394e+00 -7.9090091e-01 -2.7121113e-01 1.3268411e+00 -1.3838033e-01
+1 3.8597448e-01 1 1 -1.0997546e-01 -1.3710548e+00 1.4133708e+00 -1.3247671e+00 -5.9303410e-01 2.0555790e-01 1.1935836e+00 -9.7971969e-01
+1 7.3279689e-01 1 1 -1.1010246e+00 2.6473604e-01 9.4087255e-01 -8.9285319e-01 1.1493540e+00 -9.4024435e-01 1.4896710e+00 -1.0617552e+00
+1 7.2656311e-01 1 1 -9.3983898e-01 9.2348695e-01 -1.5325225e+00 1.2045932e+00 -4.6010338e-01 -4.7575721e-01 1.5492390e+00 -6.7364337e-01
+1 7.7979466e-01 1 1 5.4163795e-02 -1.5640755e+00 8.1194505e-01 1.1747339e+00 -1.4979602e+00 -6.9815681e-01 5.4030487e-01 3.7580739e-01
+1 9.8598997e-01 1 1 -7.3096546e-01 1.4295898e+00 -7.1805883e-01 -1.1578395e+00 5.0634461e-01 -7.2932194e-02 -1.4404283e+00 -1.5480838e+00
+1 7.4397528e-01 1 1 1.4324402e+00 2.1572822e-01 -1.5574402e+00 -7.8350586e-01 -4.4059430e-01 -5.5025539e-01 -1.6505911e-01 2.5152727e-02
+1 3.5001258e-01 1 1 9.9825402e-01 3.4635526e-01 -1.4807839e-01 1.1734728e+00 -3.3445519e-01 7.0639870e-01 -1.2221108e-01 -1.3731318e+00
+1 7.1146623e-01 1 1 1.5506065e+00 -1.7838487e-01 -6.1217023e-01 -3.6155190e-01 -8.7905925e-01 3.6423166e-01 6.0002404e-01 -8.6889959e-02
+1 6.7978300e-01 1 1 1.5315606e+00 -1.0351859e+00 -2.9034586e-02 -7.6265165e-01 5.6145216e-01 -1.3225335e+00 9.1632975e-02 4.8104893e-01
+1 6.5847158e-01 1 1 -1.2719274e+00 -2.2846541e-01 -1.0374189e+00 -1.8831494e-01 -1.0179224e+00 -1.0527940e+00 6.9500372e-01 -1.4700930e+00
+1 5.7395372e-01 1 1 1.2536990e+00 -7.9184024e-01 -6.0730477e-02 -1.4253625e+00 8.9198793e-01 -8.5812406e-01 4.8597041e-01 7.7235073e-01
+1 8.4457594e-01 1 1 2.5639024e-01 -6.7235646e-01 3.2047877e-01 -1.4242631e+00 -3.9062365e-02 5.6081538e-01 -4.3615894e-01 -1.6214638e-01
+1 9.3279623e-01 1 1 -1.1143688e+00 1.3780054e-02 -1.5447659e+00 1.3461845e+00 7.1690721e-02 8.4607929e-01 -1.1875853e+00 -1.4333687e+00
+1 5.2051577e-01 1 1 9.7856139e-01 -8.7648647e-01 -7.5834595e-01 -4.2739451e-01 -1.4656295e+00 1.2062705e+00 -1.2080338e+00 -8.9582732e-01
+1 8.4273374e-01 1 1 4.4375464e-01 -1.8008405e-01 -7.8997036e-02 -1.5386897e+00 3.9291885e-01 1.0911244e+00 6.9006767e-01 1.4837496e+00
+1 3.2115259e-01 1 1 4.3222274e-02 -1.3189347e+00 1.1905123e+00 8.3241563e-01 1.5927163e-01 1.0516359e+00 -7.9275450e-01 -5.8279074e-01
+1 8.8479095e-01 1 1 7.2885309e-01 -2.5796653e-01 1.3660192e-01 8.9736394e-01 2.4134205e-01 2.4381157e-01 -3.3044981e-01 5.2192932e-01
+1 9.3467829e-01 1 1 7.6408822e-01 -2.4559333e-01 -6.3574916e-01 -7.9052030e-01 4.3971022e-01 1.1042254e+00 4.6592450e-01 7.3937297e-01
+1 8.8178239e-01 1 1 -7.9997875e-01 3.6569187e-01 -4.7954061e-01 -4.7935089e-01 1.1836709e+00 1.3292307e+00 -1.1974285e+00 -1.4990863e+00
+1 1.1939847e+00 1 1 7.7372933e-01 1.2280465e+00 -1.4538126e+00 -1.4068305e+00 1.3914681e+00 5.1521617e-01 -1.3750567e-01 4.2978018e-01
+1 4.8126825e-01 1 1 1.0169314e+00 -4.8680611e-01 1.0797732e+00 -9.7320248e-01 3.8873461e-01 1.0088758e+00 1.1544628e+00 7.9393674e-01
+1 7.5300359e-01 1 1 1.3023274e+00 -1.0430435e+00 -1.2333785e+00 -1.4828098e+00 -1.0501092e+00 1.0000824e+00 5.8056350e-01 1.3507718e+00
+1 9.8837816e-01 1 1 7.3987734e-01 -3.4434304e-01 -1.1635716e+00 6.7020231e-01 2.8207682e-01 8.6433442e-01 -2.5611579e-01 1.2729365e+00
+1 6.5877603e-01 1 1 6.9480241e-01 -5.5981961e-01 2.6654811e-01 1.4805115e+00 2.0180913e-01 1.4416127e-01 -5.5622114e-01 -1.8345556e-03
+1 2.9201988e-01 1 1 2.4413423e-01 1.8184431e-01 -3.7006835e-02 1.5435905e+00 -1.1140179e+00 7.5058530e-01 9.7109042e-01 5.8255066e-01
+1 8.4972629e-01 1 1 2.4403171e-01 -5.1239080e-01 6.1465957e-02 -1.4585038e-01 5.9304938e-01 -1.5489769e+00 5.4285974e-01 -1.4154018e+00
+1 1.0233705e+00 1 1 -1.4790684e+00 -6.4666929e-01 -5.2565149e-01 -8.6512461e-01 -8.9258923e-01 7.2342719e-01 6.5860629e-01 -5.1785220e-01
+1 8.1462395e-01 1 1 7.2089203e-01 1.3398913e+00 -4.6612549e-01 -8.5852764e-01 -6.4221369e-01 6.7714504e-01 1.3650365e+00 -1.3303454e+00
+1 7.9957806e-01 1 1 -1.0905024e+00 6.1632839e-01 9.6105065e-01 6.1038356e-02 8.2685219e-01 -1.2135251e+00 -8.8248123e-01 -3.9977866e-01
+1 4.7487071e-01 1 1 -2.2032043e-02 8.0031955e-01 1.4503784e+00 -1.4291514e+00 -1.5012001e+00 -4.9735229e-01 -4.0310530e-01 7.8670476e-01
+1 3.9600777e-01 1 1 4.1538735e-01 -1.3290656e+00 8.9259766e-01 8.6996330e-01 -5.3876487e-01 7.7817499e-01 1.4245977e+00 -8.1665918e-01
+1 2.1405211e-01 1 1 7.9634612e-01 -8.8144762e-01 7.8391009e-01 5.0099471e-01 -9.5113849e-01 3.3679729e-01 1.1351581e+00 2.7506304e-02
+1 8.9090561e-01 1 1 1.0044800e+00 1.2607679e+00 -6.6263150e-01 7.4977089e-01 -1.3611252e+00 -5.9782871e-01 -2.9082439e-01 4.8433703e-01
+1 1.0837008e+00 1 1 -6.2356509e-01 -3.1660150e-01 9.8390376e-02 4.7123181e-01 6.4566792e-01 -8.9379308e-01 4.3268811e-01 3.8583064e-01
+1 6.6890100e-01 1 1 9.4548210e-02 7.3659372e-01 1.1693148e+00 3.7940815e-02 6.7978068e-01 1.1157802e+00 -5.9799008e-01 4.0839992e-01
+1 6.3237602e-01 1 1 -5.7410972e-01 -1.0859334e+00 -1.1298864e+00 -7.2034637e-02 -8.9854660e-01 7.5045975e-01 -4.6437236e-01 -4.0244914e-01
+1 4.6486799e-01 1 1 -1.2309934e+00 1.3700976e+00 9.2692827e-01 -1.1729732e+00 -2.3678447e-01 -5.1756161e-01 -9.9013778e-01 -1.1369654e-01
+1 9.7517788e-01 1 1 1.2233102e+00 -6.4326082e-01 -2.7457281e-01 -6.6647865e-01 7.6137642e-01 4.1200237e-01 -2.2934234e-01 -8.0936126e-01
+1 6.5908180e-01 1 1 -1.5488968e+00 -1.0642565e+00 2.5441371e-01 1.4128143e+00 7.4654864e-01 4.5355140e-01 1.7750881e-01 1.6141885e-01
+1 1.2184821e-01 1 1 -1.0716194e+00 1.2696937e+00 2.2369114e-01 1.0125815e+00 -2.7809289e-01 1.3345509e+00 -1.1224283e+00 -1.3694194e+00
+1 1.3142273e+00 1 1 4.4131236e-02 -1.0964628e+00 -9.0939638e-01 4.4912178e-01 7.8274991e-01 -1.1740000e+00 6.1086514e-01 -5.2428202e-01
+1 5.7534419e-01 1 1 2.9781760e-01 3.3242778e-01 -3.7661748e-01 -8.5743118e-01 -1.3122513e+00 9.2517821e-01 8.5688097e-02 5.5955237e-01
+1 5.5180740e-01 1 1 8.6334978e-01 1.3620233e+00 4.9925693e-01 -3.6033848e-01 -1.0271317e+00 -1.4135159e+00 1.3104082e+00 -1.5316810e+00
+1 5.0281336e-01 1 1 -6.9672700e-01 -1.2593622e+00 -1.8281129e-01 7.8174786e-01 4.8331726e-02 -2.3799228e-01 1.4657363e+00 -7.5170276e-01
+1 6.5706946e-01 1 1 -1.1749420e+00 -1.1907047e+00 -3.1680027e-02 6.9588922e-01 -1.3611805e+00 -6.8875553e-01 1.4014597e+00 -1.5242383e+00
+1 7.3068520e-01 1 1 8.0159877e-01 -2.2951304e-01 -1.5170584e+00 -3.3929727e-01 -2.8353396e-01 8.5470995e-01 -1.3286394e+00 -1.3259076e+00
+1 8.0028498e-01 1 1 1.3212937e+00 4.5006278e-01 -3.4053669e-02 -5.7847042e-01 4.4073845e-01 -1.3930442e+00 -1.2810371e-03 -1.2118480e+00
+1 7.8879462e-01 1 1 -9.3579908e-01 -7.4990723e-01 -5.7014889e-01 8.7684940e-01 -3.8438222e-01 1.3965594e+00 4.6075749e-01 -5.8494487e-01
+1 6.8155734e-01 1 1 -1.1623332e+00 3.7890159e-01 -6.3483936e-01 -3.2223002e-03 -1.1974384e+00 1.1349936e+00 -7.4731567e-02 -1.1250767e+00
+1 1.0065064e+00 1 1 -9.1096501e-01 1.9063651e-01 -8.9646300e-01 -7.5012378e-01 -3.0499411e-01 8.6569679e-02 6.2360668e-01 8.2149525e-02
+1 8.3102331e-01 1 1 1.5336536e+00 -3.9673060e-01 2.2469743e-01 -1.1906013e-01 1.0432101e+00 4.1919746e-01 6.0429560e-01 1.5278876e+00
+1 9.3735019e-01 1 1 -6.5183309e-01 -1.3916499e+00 2.9538341e-01 1.5096548e-01 4.2232668e-03 -1.1406765e+00 -3.7291587e-01 -1.7153979e-01
+1 4.3756893e-01 1 1 -6.2515839e-01 -3.0183907e-01 7.9261698e-01 -1.1300513e+00 -1.2761867e+00 -1.3516567e+00 -1.1966290e-01 9.1273832e-01
+1 6.8747826e-01 1 1 -1.5512901e+00 6.6287298e-01 1.1607413e+00 1.2962085e+00 -1.2172790e+00 -4.3689962e-01 -5.5509454e-01 -3.9942894e-03
+1 7.1500811e-01 1 1 -4.5464638e-01 8.1866125e-01 -7.1171206e-01 -1.5681685e+00 -7.5671412e-01 -1.0699186e+00 1.0562604e+00 -1.1585754e+00
+1 7.4902059e-01 1 1 -8.8834096e-01 -9.3612511e-01 1.4402496e+00 -1.3870646e+00 -9.2717205e-01 3.5364755e-01 -5.7158124e-01 -5.8556178e-01
+1 6.6352329e-01 1 1 -1.4981918e+00 -3.5878852e-01 3.0400589e-01 1.3641681e+00 -6.8113000e-01 -1.3888742e-01 4.2436400e-01 1.0728692e+00
+1 2.4068759e-01 1 1 -2.4412830e-01 -1.4423796e+00 1.1973784e+00 2.3072790e-01 2.1170583e-01 -7.7551348e-02 8.7037592e-01 -1.0291015e+00
+1 5.3318394e-01 1 1 -1.4437953e-01 -1.5455187e+00 -7.0419015e-01 1.1184814e+00 -1.2846275e+00 3.5544644e-01 1.1527456e+00 1.5003537e+00
+1 1.2725664e+00 1 1 -1.2771912e+00 -8.4551579e-01 -9.4429501e-01 -9.7307136e-01 1.4311077e+00 -1.3208633e+00 -6.4200972e-03 -1.1202442e+00
+1 7.6170882e-01 1 1 7.5053841e-01 -1.1603785e+00 5.5985128e-01 7.2106962e-01 5.9419138e-01 -1.2555533e+00 -1.0884232e+00 -3.7924001e-01
+1 6.2725381e-01 1 1 8.0456934e-01 5.2511101e-01 3.5046996e-01 -1.2472995e+00 -5.4853995e-01 -6.1979253e-03 3.6563889e-01 4.0467863e-01
+1 1.0914432e+00 1 1 9.8214433e-01 8.0704035e-01 -1.3756294e-01 4.8479930e-01 1.2635825e+00 -4.9597261e-01 3.3756952e-01 -1.1435095e-01
+1 3.0627594e-01 1 1 9.7188401e-01 -1.4699279e+00 1.9184685e-01 -1.2694702e+00 -1.3486550e-01 -1.1663666e+00 -1.8544312e-01 7.5829012e-01
+1 6.8947698e-01 1 1 1.3142686e+00 4.0722571e-01 1.0959619e+00 -1.4297394e+00 1.5454652e+00 4.1509283e-01 -2.8263332e-01 -8.5935131e-01
+1 7.6137225e-01 1 1 3.7372874e-01 -1.2879346e+00 6.7389221e-01 4.1245594e-01 -5.4722296e-02 -1.0120430e+00 -1.3017398e-01 -1.2161059e+00
+1 3.7381997e-01 1 1 1.2152302e+00 -7.4285223e-01 6.6486901e-01 -1.3480682e+00 7.6901440e-01 -8.2431129e-01 -1.2856449e+00 1.0996205e-01
+1 9.9991259e-01 1 1 8.8031076e-01 -4.2821008e-01 -1.9165048e-01 1.8323529e-01 3.1285589e-01 2.2378443e-01 4.0939967e-02 8.7565774e-01
+1 6.9807801e-01 1 1 -1.5184421e+00 4.6194752e-01 -9.3715691e-01 8.7469526e-01 -8.5708669e-01 6.5843511e-01 6.9226576e-02 -1.1818863e+00
+1 5.9581508e-01 1 1 -1.2993836e+00 1.0765914e+00 1.1494192e+00 1.4911431e+00 -8.5369024e-01 -1.5119930e+00 1.1017815e+00 3.2790653e-01
+1 3.4112014e-01 1 1 -1.5294654e+00 -1.3027178e+00 6.3452162e-01 1.1566947e+00 -3.1815595e-01 2.7612559e-01 1.0950664e+00 7.7146307e-01
+1 9.0200744e-01 1 1 -1.2133047e+00 -1.0185903e+00 -1.3021506e+00 3.9323252e-01 -2.5640351e-01 7.1038193e-01 1.3306880e+00 6.2687967e-01
+1 9.5122876e-01 1 1 6.6331183e-02 -9.0835287e-01 -9.1068922e-01 -8.5201084e-01 8.9131316e-01 1.3369888e+00 -1.2563488e-01 -9.3511393e-01
+1 8.1415292e-01 1 1 -4.3719604e-01 1.4535885e+00 -1.1426691e-01 -3.6692525e-01 1.1865802e+00 -1.0411844e+00 -3.9521832e-01 9.2826025e-01
+1 9.9489583e-01 1 1 2.3139519e-01 1.4382660e+00 -9.7091173e-01 3.3702626e-02 2.2825426e-02 -5.1472510e-01 -1.1074543e+00 1.2093347e-01
+1 5.5604448e-01 1 1 -2.3267909e-01 1.5235061e+00 -6.8121643e-01 9.5334970e-01 3.5262842e-01 9.6149007e-01 9.5249291e-01 -8.1646296e-02
+1 1.2883410e+00 1 1 6.4530702e-01 -1.5551910e+00 -1.2408360e+00 8.2590907e-01 -1.5594205e+00 -5.8892631e-01 -1.0078663e+00 6.4670010e-01
+1 4.4239757e-01 1 1 8.9718957e-01 -4.4443686e-02 -8.3823907e-01 1.4973892e+00 1.1279725e+00 1.0739520e+00 2.5937945e-01 -8.2200972e-01
+1 1.2383310e+00 1 1 -5.7963119e-01 7.3401982e-01 -1.3825633e+00 -6.7804962e-01 1.4636141e+00 1.4608300e+00 -1.1401043e+00 1.2071514e+00
+1 1.0608479e+00 1 1 2.1746846e-01 -3.6318189e-01 -1.5227509e+00 -1.4233932e+00 2.9217715e-01 6.2330689e-01 -1.1595442e+00 1.8897236e-01
+1 6.5071087e-01 1 1 1.3201211e+00 1.1642955e-01 -1.4598676e+00 2.5884117e-01 3.1198191e-01 -1.2925831e+00 -1.1604405e+00 -9.1786601e-02
+1 7.6505684e-01 1 1 1.3480426e+00 -3.8069997e-01 -1.5594833e-01 -7.6223479e-01 1.6180569e-01 -3.3088725e-01 -5.1547118e-01 -1.3541802e-01
+1 5.5036452e-01 1 1 -6.1456966e-01 9.9989573e-01 -9.3531850e-01 5.3476362e-01 -1.1509453e+00 -6.0294934e-01 9.8840514e-01 -1.4576150e+00
+1 4.0071806e-01 1 1 4.8430308e-01 8.6834629e-01 6.3164365e-01 -3.2448459e-01 -1.1513619e+00 1.0083693e+00 -6.1681561e-01 4.8025911e-03
+1 8.1557157e-01 1 1 -1.8476600e-01 -1.5433294e+00 5.9317587e-01 1.9235677e-01 1.2713074e+00 -1.2302692e+00 4.3586678e-01 -9.6426055e-01
+1 6.3534153e-01 1 1 -1.4685428e+00 1.3940925e+00 1.2332994e+00 2.4141909e-01 8.9263828e-01 8.2837300e-01 -5.8114457e-01 1.1493815e+00
+1 8.2437201e-01 1 1 -1.4476953e+00 5.1399781e-01 -1.6539463e-01 -1.4071417e+00 1.4666492e+00 -1.0736853e+00 -8.5265922e-02 1.1045229e-03
+1 8.9528950e-01 1 1 2.2053264e-01 -6.1855491e-01 5.2203272e-01 7.9042370e-02 1.0379162e+00 -1.2082826e-01 -4.9810244e-01 -2.8583955e-01
+1 6.9374802e-01 1 1 -5.8718351e-01 -5.2221239e-01 -6.6441644e-01 -4.2857757e-01 -1.0056070e+00 -1.2916549e+00 7.3668828e-01 -6.1007144e-01
+1 4.9673906e-01 1 1 -1.0507242e+00 7.8617672e-01 1.5147320e+00 5.6873831e-01 5.3114187e-01 -4.3877232e-01 5.0328897e-01 6.8778605e-01
+1 1.0660064e+00 1 1 -6.2928685e-01 -2.6650670e-01 -1.3654282e+00 -1.0816669e+00 -1.5048403e+00 -1.1283948e+00 -1.5312435e+00 -1.4408004e+00
+1 4.7182304e-01 1 1 1.3183112e+00 7.3309687e-01 5.8242656e-01 8.2177998e-01 1.1112956e+00 8.6264856e-01 3.1682686e-01 -1.3633289e-01
+1 5.8481067e-01 1 1 -7.9664255e-01 -1.6727442e-01 -3.5959590e-01 1.2148007e+00 7.7755613e-01 8.4181101e-02 -9.0592094e-02 -1.1258629e+00
+1 4.0377057e-01 1 1 2.9661256e-01 3.4430828e-01 6.9592172e-01 -5.4906709e-02 -6.3950134e-01 1.1150710e+00 1.0911173e+00 -5.6440517e-01
+1 7.0675102e-01 1 1 -5.4031224e-01 -2.4324614e-02 2.0685963e-01 8.1118571e-01 -7.1062709e-01 1.3975640e+00 9.3290397e-01 -1.4894000e+00
+1 8.7996056e-01 1 1 1.3165576e+00 -4.1674341e-01 -1.0532027e+00 -9.1392897e-01 8.2581358e-01 -8.3080767e-01 -3.7187444e-01 -1.3537713e-01
+1 7.7208658e-01 1 1 1.1471943e+00 1.5452060e+00 -1.4447187e+00 -1.1577536e+00 -1.0742151e-01 9.9488789e-01 -1.4659143e+00 -7.7035176e-01
+1 6.7284092e-01 1 1 9.4024028e-01 -1.2691815e+00 -1.7735153e-02 6.5952068e-01 9.8249540e-01 1.5246678e+00 -1.2515470e+00 -7.9864661e-01
+1 7.1670385e-01 1 1 4.0728168e-01 2.8108749e-01 3.7659157e-01 1.0251460e+00 5.8917494e-01 -8.7948412e-01 1.3540545e+00 1.1719156e+00
+1 7.5569824e-01 1 1 -3.4717666e-01 -7.1795509e-01 -9.3459903e-01 1.1349760e+00 -3.6816134e-02 -2.9621708e-01 -1.0296770e-01 -1.4000602e+00
+1 5.7307662e-01 1 1 -1.0606245e+00 1.8616560e-01 1.5743707e-01 -2.0896924e-01 1.2499530e-01 9.0387582e-01 4.3945986e-01 -2.8220385e-01
+1 7.8132423e-01 1 1 -5.1982575e-01 -1.4102183e-01 8.2388041e-01 1.5463300e-01 -9.2950644e-01 -1.3012200e+00 1.1752206e-01 8.0484679e-01
+1 1.2744012e+00 1 1 5.7774262e-02 -1.3930965e+00 -1.1823106e+00 8.1976281e-01 9.2555412e-01 -9.7891503e-01 -8.6851159e-01 -6.3799257e-01
+1 4.0780848e-01 1 1 2.5989622e-01 5.1793351e-01 -5.2108341e-01 -1.2718153e+00 -1.3786595e+00 -1.0422081e-01 -1.2348840e+00 -4.8539176e-01
+1 5.9323219e-01 1 1 1.2620385e+00 -4.4478549e-01 9.1147312e-01 -3.9683445e-03 1.2580103e+00 1.3695759e+00 -1.3338790e+00 7.3675038e-01
+1 6.9804600e-01 1 1 -9.5228508e-01 1.4808442e+00 7.2288346e-01 -7.2252027e-01 4.6110673e-01 1.3280756e-02 -9.8604198e-02 1.5470183e+00
+1 6.2957925e-01 1 1 1.3592387e+00 8.5127865e-01 9.6345159e-01 -1.1426519e+00 -4.8832224e-01 1.5658447e-01 1.5201714e+00 9.1639227e-01
+1 6.6494494e-01 1 1 -9.3691175e-01 6.2732097e-01 9.6231646e-01 5.9501874e-03 -1.3918052e+00 -9.3942782e-01 -1.0524297e+00 -1.4238442e+00
+1 7.2293933e-01 1 1 -1.0134816e+00 1.9864570e-01 7.3375356e-01 -5.2616499e-01 2.2900411e-01 6.8137661e-01 -1.0195969e+00 -1.0390384e+00
+1 2.6948015e-01 1 1 1.3017491e-01 -8.7471331e-01 1.4448755e+00 3.2839982e-01 4.2110102e-01 7.9140123e-01 1.0224853e+00 9.9444472e-01
+1 6.5433841e-01 1 1 1.3012332e+00 1.3470428e+00 -4.8933215e-01 -3.6258777e-01 -5.6340903e-01 -4.2287493e-01 3.9844882e-01 3.5943648e-01
+1 8.4217692e-01 1 1 1.1998562e+00 1.4310173e+00 4.8420337e-01 6.7717884e-01 -4.5532958e-01 -9.7630646e-01 -1.1461661e+00 -2.3377535e-01
+1 6.8706873e-01 1 1 9.9710281e-02 -9.2628504e-01 1.2810325e+00 -6.4538722e-01 1.9548224e-01 -2.4425419e-01 6.3246333e-01 1.0700769e+00
+1 5.4459505e-01 1 1 1.3618040e+00 -1.4810236e+00 9.7867466e-01 8.9648009e-01 -6.3587586e-01 8.8147904e-01 -1.3383220e+00 -8.3551290e-01
+1 1.2414818e+00 1 1 1.3378726e+00 -7.2543688e-01 -7.9407074e-01 6.2457225e-02 5.3269662e-01 -7.3265804e-01 6.2551654e-01 4.5377675e-01
+1 5.7446980e-01 1 1 1.2458080e+00 1.0339871e-01 -4.6132336e-01 4.2664168e-01 -5.0695021e-01 1.2595553e+00 1.2875096e+00 -1.1610893e+00
+1 2.3783005e-01 1 1 -4.2010161e-01 5.2142671e-01 -1.1016363e-02 1.4522329e+00 -3.1296832e-01 1.2951227e+00 -1.1643977e-01 1.1463003e+00
+1 5.3373692e-01 1 1 -1.4890132e+00 -1.4247160e+00 2.0194640e-01 6.4533123e-01 -1.0323954e+00 -9.6809142e-01 2.0903169e-01 -1.5194284e+00
+1 2.5587147e-01 1 1 8.3047827e-02 1.7964200e-02 1.1931280e+00 1.3041088e+00 -4.5303395e-01 -4.0408184e-01 8.9499730e-01 9.7275038e-01
+1 8.9561183e-01 1 1 9.1768472e-01 3.3141914e-01 1.1662815e-01 -7.3547376e-01 1.0790496e+00 7.1979988e-01 2.7406382e-01 1.6754699e-01
+1 6.1851710e-01 1 1 1.4486855e+00 1.1763347e-01 -1.8444857e-01 1.0596739e+00 -8.2850798e-01 -5.9666688e-01 6.1586495e-01 1.0952227e+00
+1 6.8232486e-01 1 1 7.1445109e-01 1.0039807e+00 7.2478449e-01 2.5098476e-01 -1.1949816e+00 -2.1646343e-01 -7.0561750e-01 8.1671164e-01
+1 6.2205765e-01 1 1 6.1240922e-01 4.0921080e-01 1.4982814e+00 -8.5804922e-01 1.4686587e-01 -1.3660930e-01 1.9902138e-01 8.5416840e-01
+1 4.2184430e-01 1 1 9.0418952e-01 6.5953197e-01 -1.3904618e+00 -1.3228928e+00 -9.1713271e-01 5.1175559e-01 -8.4388918e-01 -1.0701026e+00
+1 8.4336009e-01 1 1 8.2955729e-01 1.2148859e+00 8.1702867e-01 -8.0878164e-01 1.5456416e+00 -6.0451497e-01 1.0454347e+00 4.0349009e-01
+1 7.1709499e-01 1 1 -1.8842810e-02 1.3772277e+00 -1.0068630e-01 4.7831165e-01 -2.3190227e-01 -1.7240091e-01 -3.0710128e-01 -1.2406686e+00
+1 6.0388847e-01 1 1 6.0975291e-01 -1.8926712e-01 1.0837931e+00 -3.5165452e-01 1.1350195e+00 -9.9374155e-01 1.8545530e-01 -1.1671962e+00
+1 9.5965187e-01 1 1 2.4186670e-01 1.4209086e+00 3.5629773e-01 -9.2170527e-01 5.2296903e-01 -1.1076681e+00 4.8739606e-01 -9.6241663e-01
+1 3.3675432e-01 1 1 -1.6718967e-01 -1.1758676e+00 4.2041475e-01 9.2928870e-02 -6.3574385e-01 5.0014057e-01 1.5335223e+00 7.2420159e-01
+1 7.7533126e-01 1 1 -1.3729933e+00 9.5256073e-01 4.6890385e-01 4.8396677e-01 -3.9026425e-01 -1.0393786e+00 2.8386398e-01 1.1262640e+00
+1 1.0986663e+00 1 1 -9.0085549e-01 1.3207307e-01 -1.3889559e+00 4.4617609e-01 4.7421032e-01 1.5614107e+00 -1.1772582e+00 1.0232690e+00
+1 9.0199663e-01 1 1 -1.3431862e+00 -1.3539173e+00 9.9382708e-01 -1.0015082e-01 -1.6767510e-01 9.0685259e-01 -4.2877190e-01 1.0035494e+00
+1 1.0669221e+00 1 1 5.5510814e-01 -7.3310178e-01 -5.9640556e-01 6.5876520e-01 -1.0671219e-01 -1.5360948e+00 4.4420797e-01 -5.5642112e-01
+1 1.5775147e-01 1 1 -8.2769719e-01 8.4734971e-02 1.0339669e+00 8.9416167e-01 3.3760404e-01 4.6305684e-01 1.3791384e+00 7.5157947e-01
+1 7.3081409e-01 1 1 -1.3440192e-01 9.9917874e-01 -1.4086527e+00 -1.2041059e+00 3.9474255e-01 8.7123822e-01 5.0828125e-01 -5.4782884e-01
+1 5.2986934e-01 1 1 -8.7977571e-02 1.3844250e+00 -1.8346725e-01 7.3197559e-01 -6.0563047e-01 -6.2549840e-02 6.9259122e-01 6.4871221e-01
+1 1.7542429e-01 1 1 1.0511050e+00 1.3953719e+00 1.5099826e+00 -1.6306969e-01 -7.1150255e-02 1.1583805e+00 7.7986674e-01 -1.5619353e+00
+1 7.4195660e-01 1 1 7.4552714e-01 2.6796719e-02 4.9241958e-01 -1.2434605e+00 1.1244688e+00 4.5065561e-01 4.9579038e-01 -2.9852664e-01
+1 6.3371270e-01 1 1 1.4031600e+00 1.1247043e+00 1.1408255e+00 -9.6709201e-01 -8.7483048e-01 -2.1096685e-01 1.2451975e+00 -2.1376225e-01
+1 7.7887572e-01 1 1 -1.0266468e+00 -5.7332678e-02 7.1380970e-01 6.8496569e-01 -6.2217581e-01 1.1383167e+00 -1.2559578e+00 1.2798295e+00
+1 1.2012681e+00 1 1 -1.2251535e+00 8.7863333e-01 -7.4275457e-01 1.4229200e+00 1.4530393e+00 -6.0996384e-01 -5.2158786e-01 -3.9058977e-01
+1 6.9396396e-01 1 1 -1.1563042e+00 -1.4366275e+00 1.2130636e+00 1.2138500e+00 -1.5101812e+00 -6.4551167e-01 -1.2836449e+00 1.2863360e+00
+1 8.6712924e-01 1 1 -1.1250343e-01 8.8227536e-01 -9.7699012e-01 -3.2492789e-01 -6.8844969e-01 -1.1952322e+00 -9.0382212e-01 -9.9223781e-01
+1 6.5486297e-01 1 1 3.9357033e-01 8.4704377e-02 8.3177485e-01 -9.7496447e-01 -2.8816356e-01 -9.2479048e-01 -9.3792166e-01 -9.6711132e-01
+1 1.2683005e+00 1 1 -1.4576035e+00 4.8498529e-01 -4.4739944e-01 3.1940439e-01 1.1709364e+00 -1.4946782e+00 8.6260073e-01 3.6036463e-01
+1 7.2833641e-01 1 1 1.9820601e-01 -1.2851856e+00 1.5304948e+00 -7.5226887e-01 9.9154333e-01 -8.8094351e-01 -7.1967491e-01 -3.4227511e-01
+1 2.6592434e-01 1 1 1.1602149e+00 1.4767295e+00 -3.3480814e-01 1.5275496e+00 -1.2803243e+00 3.0858905e-01 -4.4455873e-01 -3.6154437e-01
+1 1.1371558e+00 1 1 -1.3407102e-01 8.1153856e-01 -5.2792023e-01 4.3038932e-01 1.4994141e+00 -3.1336686e-01 -9.9131517e-01 -6.3607642e-01
+1 1.2691371e+00 1 1 -8.0962207e-01 -1.2667891e+00 -8.9768053e-01 -1.5346167e+00 -1.2039677e+00 -1.4474693e+00 -1.1682559e+00 3.0344912e-01
+1 9.9973293e-01 1 1 -1.0803814e+00 -3.5095749e-01 -1.3888169e+00 1.7264806e-01 -8.6218947e-02 8.7727891e-01 7.7354486e-02 1.2644649e+00
+1 7.4292656e-01 1 1 4.3595217e-01 1.3685368e+00 1.8802452e-01 -1.1357451e+00 -8.0763535e-01 9.3229022e-01 -5.2251275e-01 -1.0130941e+00
+1 4.8328901e-01 1 1 8.5413697e-01 1.3976424e+00 -3.1405931e-01 -1.5111924e-01 8.9447538e-01 -1.2624865e+00 -1.1203894e+00 3.5890193e-01
+1 1.0506046e+00 1 1 1.5432819e+00 4.8726639e-01 -5.1920970e-01 -1.4541931e+00 9.2686813e-01 -2.9319908e-01 3.2250925e-01 2.0686546e-01
+1 5.2243473e-01 1 1 9.4917631e-01 -6.4581899e-01 9.8691453e-01 9.6817986e-01 -1.2852323e+00 1.3619931e+00 1.1655943e+00 -9.5534539e-01
+1 1.1692062e+00 1 1 -2.0123097e-01 -7.7191864e-02 -5.3672628e-01 -1.2510632e+00 6.9178114e-01 1.3740117e+00 -8.2853567e-01 1.9015608e-01
+1 8.4507279e-01 1 1 1.4064464e+00 1.1411415e-01 -1.2461329e+00 6.0948670e-02 -2.6881265e-01 -8.3281740e-01 1.4811988e+00 9.5358980e-01
+1 5.6634559e-01 1 1 8.0139498e-01 1.5449547e+00 1.2418163e+00 2.0509444e-01 -3.2403194e-01 -1.3668003e+00 5.2765278e-01 -1.4218915e+00
+1 1.1127200e+00 1 1 1.0377329e+00 7.9096910e-01 -1.5354895e+00 6.9516538e-01 1.5168398e+00 -4.8684452e-01 -4.5577045e-01 3.6477909e-01
+1 2.0367727e-01 1 1 -9.4558537e-01 -1.4024232e+00 1.2119233e+00 6.1540911e-02 -4.9774012e-01 1.4529860e+00 -9.3102414e-01 -1.5466835e+00
+1 8.1739399e-01 1 1 8.6395102e-01 8.4239779e-01 -1.2921740e+00 7.3410157e-01 5.4305528e-01 7.3584494e-01 5.5023814e-01 1.5702365e+00
+1 8.2868279e-01 1 1 -1.6483613e-02 -9.7845037e-01 2.6229679e-01 1.0107790e+00 8.0339654e-01 -1.1043819e+00 -9.9635630e-01 -1.5543596e+00
+1 1.2695774e-01 1 1 -5.7993122e-01 1.4222466e+00 7.6768222e-01 -1.5701683e+00 1.2045937e-01 -8.1675422e-01 -1.0715159e+00 1.3629147e+00
+1 5.9335750e-01 1 1 1.4580272e+00 -6.7984859e-01 -8.5945076e-02 -4.4036013e-01 1.3749894e+00 -1.5698053e+00 -1.3590189e+00 1.1556561e+00
+1 1.4212039e-01 1 1 6.3994094e-01 -2.4279420e-01 6.5372913e-01 4.5961095e-01 -1.0800560e-01 -6.2278134e-01 1.4894572e+00 -1.3560076e+00
+1 3.5464528e-01 1 1 -1.3258747e+00 2.8665535e-01 1.0759982e+00 -4.9512430e-01 5.9046392e-01 7.0075520e-01 1.0967883e+00 -1.3074146e+00
+1 6.7154916e-01 1 1 -6.5920011e-01 -1.3867302e+00 1.2936893e+00 5.2475344e-01 -3.6412625e-01 -2.3820396e-01 -1.1441600e+00 -1.4187672e+00
+1 8.2188204e-01 1 1 1.2210439e+00 7.0133637e-01 7.3654983e-02 1.0805574e+00 -4.7374642e-02 -1.1048417e+00 -2.0883555e-01 -5.3230860e-01
+1 3.7952081e-01 1 1 1.2022999e+00 1.0480052e-01 1.3178815e-01 -6.1935273e-01 -1.4026741e+00 8.8049249e-01 -7.4007710e-01 7.4526627e-01
+1 9.0616243e-01 1 1 3.3038323e-01 -1.0511341e+00 1.4057864e-01 -1.3648259e+00 -2.3294665e-01 1.5358616e+00 -9.1052691e-01 1.6025332e-01
+1 8.5644846e-01 1 1 1.5567755e+00 -1.2358464e+00 2.2749632e-01 1.2801761e+00 -7.0986507e-01 -1.2407724e+00 -5.2800096e-01 1.0325641e+00
+1 1.0513516e+00 1 1 1.5426109e+00 1.3407977e+00 2.1238834e-01 -8.4873256e-01 1.0666047e+00 2.2963499e-01 8.8716230e-01 1.4622992e-01
+1 7.6736645e-01 1 1 -9.0360912e-01 1.4280612e-01 7.6153672e-01 1.3240425e+00 4.9675307e-01 -1.5421103e+00 5.3796107e-01 9.6073618e-01
+1 4.3854411e-01 1 1 -4.9960865e-01 -3.4407830e-02 2.9913004e-01 1.2813240e+00 -1.4244142e+00 -1.0792337e-01 8.0613903e-03 -6.9320889e-01
+1 4.6562825e-01 1 1 5.5457902e-01 -2.3934354e-01 9.3039479e-01 -4.0569496e-01 -1.1933111e+00 -1.1691770e+00 3.9930317e-01 1.4053430e+00
+1 6.7717131e-01 1 1 -2.9583763e-01 -1.4083220e+00 1.4386668e+00 -1.2590729e+00 -5.1811976e-02 3.0478284e-01 6.4654849e-01 1.1054906e+00
+1 1.1169949e+00 1 1 9.9808592e-01 -9.0796387e-01 -1.1650500e+00 5.3017831e-01 -5.8271224e-01 -1.4524856e+00 -2.2844443e-01 6.0104984e-01
+1 3.7723899e-01 1 1 -1.2747898e+00 -1.4332392e+00 5.5248201e-01 1.1500682e+00 -1.3003353e+00 1.3911910e+00 -4.3923428e-01 -1.5172841e+00
+1 1.2602505e+00 1 1 2.6911502e-01 1.2817191e+00 -9.8273557e-01 -1.0235371e+00 1.3242558e+00 -1.1272136e+00 5.3219225e-01 -6.8691515e-01
+1 8.0929931e-01 1 1 -8.7731008e-01 -4.7245530e-02 -1.4841226e+00 7.7279040e-01 -1.4174562e+00 -1.2752677e+00 4.4080292e-01 3.7015184e-01
+1 8.5622085e-01 1 1 -1.4562694e+00 7.6732404e-01 5.9678919e-01 9.4419845e-01 -4.8935910e-01 -1.4790312e+00 6.9915393e-01 7.8844955e-01
+1 5.7318473e-01 1 1 6.2850327e-01 1.7724530e-01 -8.6941265e-01 9.5883441e-01 3.1133851e-02 1.3458511e+00 1.1235252e+00 2.3369600e-01
+1 5.4073023e-01 1 1 1.2199020e+00 7.3187766e-01 -6.7100350e-01 -1.2403078e+00 -1.3793376e+00 2.5252541e-01 -1.0245953e+00 7.3777961e-01
+1 3.5479564e-01 1 1 8.5923410e-01 1.3326761e+00 7.6179394e-01 -1.3857853e+00 -7.1549857e-01 -9.7180342e-02 -1.3046160e+00 -4.2908141e-03
+1 6.7177069e-01 1 1 -7.5385029e-01 -1.2685949e+00 1.4806423e+00 8.7438538e-01 6.3227216e-01 3.1816521e-01 -1.5056717e+00 1.4091898e-01
+1 4.3553273e-01 1 1 8.1286116e-02 7.1472062e-01 5.9950921e-01 -5.7531400e-01 -1.4097193e+00 4.1194254e-01 -2.9480881e-01 -3.3558491e-01
+1 7.2524449e-01 1 1 -4.1704675e-01 -1.1408677e+00 8.6371010e-01 5.1974721e-01 7.4005529e-01 -5.5187101e-01 -5.6008308e-01 -1.0168460e+00
+1 5.0286230e-01 1 1 -4.1159185e-01 -1.4236932e+00 -9.2394621e-01 -1.3778153e+00 5.4393080e-01 -1.3145429e+00 -1.1047785e+00 1.3379016e-01
+1 7.4810780e-01 1 1 1.6272008e-01 1.4998179e+00 1.2853184e-01 -2.6231472e-01 -1.8960545e-01 1.2989511e+00 -1.1995204e+00 -7.6919577e-01
+1 5.9540440e-01 1 1 -1.4907866e+00 -7.0055173e-01 -1.1811130e+00 -1.0689500e+00 -1.1238936e+00 5.4443410e-01 -7.4009387e-01 -2.1959225e-01
+1 7.0615777e-01 1 1 -1.4490210e+00 5.1640470e-01 7.5814247e-01 9.2626419e-01 1.1161912e+00 -1.1555040e+00 -1.1924199e+00 6.8438081e-01
+1 1.1420956e+00 1 1 -7.0133538e-02 -1.0066942e+00 -1.9937582e-01 1.1306551e+00 1.3757793e+00 7.7031028e-01 -7.8165648e-01 1.0175377e+00
+1 2.7823541e-01 1 1 -6.3713525e-01 1.1083036e+00 1.1699492e+00 -5.7355212e-01 6.0139414e-01 1.0152390e-01 8.3997882e-01 -1.0746876e+00
+1 9.1580881e-01 1 1 1.3571366e+00 7.5608407e-01 1.0752899e-01 -1.2841389e+00 1.1277358e+00 4.2744650e-01 -7.9332809e-01 -1.2581406e+00
+1 5.6762503e-01 1 1 1.4326864e+00 -2.3729292e-01 8.2393090e-01 2.1879563e-01 6.2765130e-01 -7.2899779e-01 -5.4604308e-01 4.9123593e-01
+1 6.1450523e-01 1 1 -1.1466734e+00 -1.5010124e+00 -3.3377955e-01 -1.5068082e+00 -5.3280912e-01 -5.4544806e-02 -7.5388517e-01 9.6703021e-02
+1 4.1420381e-01 1 1 1.5304518e+00 -5.2637704e-01 1.0516186e+00 -5.4702466e-01 -1.3838104e+00 6.1049616e-01 -5.0492344e-01 1.0842802e+00
+1 8.3940864e-01 1 1 -1.0565673e+00 -9.3956059e-02 -4.5850990e-02 -1.5433861e+00 -4.9099103e-01 1.6735070e-01 -8.0643117e-01 -8.8165888e-01
+1 1.2255408e+00 1 1 -1.4445457e+00 1.1016170e+00 -9.2738634e-01 4.4089340e-01 8.7758776e-01 9.3777002e-01 -8.5798633e-01 8.5181207e-01
+1 8.8951791e-01 1 1 -2.5124455e-01 1.4718212e+00 -1.1410060e+00 -9.2161809e-01 -1.6003188e-01 -2.6965012e-01 -2.6593553e-01 1.6772338e-01
+1 7.2877139e-01 1 1 -3.6661368e-01 -2.2166054e-03 -6.0697389e-01 1.5581577e+00 -4.5248088e-01 1.3087061e+00 9.0789987e-01 9.1831319e-01
+1 8.1693071e-01 1 1 -1.0128626e+00 4.4462440e-01 -6.5875683e-01 -3.5983732e-01 9.4968351e-01 1.1329358e+00 3.5764471e-01 -5.5484888e-01
+1 8.2876481e-01 1 1 1.1093503e+00 -1.0465798e+00 -7.5347334e-01 -2.1994972e-01 -1.1014815e+00 5.9126755e-02 1.0679405e+00 -1.0982069e+00
+1 3.5424451e-01 1 1 -5.0258746e-01 -8.9097585e-02 1.3352576e-01 9.5954518e-01 8.0589381e-01 1.0000914e+00 9.5697303e-01 -7.0691229e-01
+1 7.0957724e-01 1 1 7.5517913e-01 1.0765777e+00 1.0702103e+00 1.2807349e+00 1.2513704e+00 1.0147347e+00 -1.1087244e+00 4.2847418e-01
+1 3.9066673e-01 1 1 2.6125919e-01 -1.5328054e+00 1.4073127e+00 -8.8149525e-01 -1.1802676e+00 -1.0601680e+00 -1.5456220e+00 8.3519862e-01
+1 6.1070643e-01 1 1 -9.6326502e-01 -8.0063111e-01 -3.4576916e-01 4.6035409e-01 -7.4123423e-01 8.6919885e-01 5.6068317e-01 5.4727742e-01
+1 5.9968762e-01 1 1 -9.6824614e-01 -7.6574059e-01 6.0412549e-01 -5.7155812e-01 -1.5089069e+00 2.1929043e-01 -1.3759701e+00 -4.9171008e-01
+1 8.3000706e-01 1 1 1.3708799e-01 1.3029978e+00 -9.0281118e-02 8.1306406e-01 -1.2616079e+00 5.2610768e-01 -6.6632496e-01 1.3588755e+00
+1 5.2158017e-01 1 1 1.2504545e+00 -5.5918277e-01 3.4495957e-02 -7.6044758e-01 -1.2344449e+00 -1.2915567e+00 8.5428585e-01 -7.5867038e-01
+1 7.8777084e-01 1 1 -8.6587408e-01 1.4604679e+00 -1.4210877e+00 -8.4361531e-01 -2.3722152e-01 1.2115249e+00 9.0391049e-01 7.5151987e-01
+1 1.8820906e-01 1 1 -8.8845833e-01 8.2136560e-01 1.3074628e+00 -6.3494102e-01 -3.0100638e-01 1.4362134e+00 -7.1850189e-01 -1.5495877e+00
+1 8.6120919e-01 1 1 -3.2928451e-01 5.3354510e-01 -9.1348647e-01 5.3658525e-01 -1.0501179e+00 -1.5588102e+00 4.2091266e-01 -1.1815783e-01
+1 4.8858457e-01 1 1 1.2015751e+00 1.1871449e+00 -3.7341035e-03 -1.1241777e+00 1.3649563e-01 -1.1823372e+00 -5.8759875e-01 -3.9213876e-01
+1 9.5626247e-01 1 1 7.1575602e-01 8.8829784e-02 7.2775223e-02 -5.1588266e-01 7.1940664e-01 -9.6788317e-01 1.3951064e+00 3.8531968e-01
+1 6.4369927e-01 1 1 5.5314946e-01 7.0566306e-01 1.0536346e+00 3.5588148e-01 -9.2273488e-01 -4.5726615e-02 -1.2951088e+00 1.2453383e+00
+1 8.1071212e-01 1 1 8.1025364e-01 5.6677355e-01 -7.2106290e-01 -2.9243550e-01 -1.5037473e+00 1.1629737e+00 1.2018425e+00 1.1097796e+00
+1 4.8227935e-01 1 1 -8.7127391e-01 4.5417306e-01 1.3602780e+00 -1.5125001e+00 6.3167158e-01 -8.9070795e-01 -1.0732462e+00 4.2999917e-01
+1 5.5426615e-01 1 1 -5.3728106e-01 -7.8353553e-01 8.2253213e-01 1.1784415e+00 1.0625959e+00 -4.3958236e-01 9.7602589e-01 1.3329592e+00
+1 4.3636449e-01 1 1 -1.1454357e+00 6.7469555e-01 1.2897507e+00 1.4654198e+00 -9.0470762e-01 9.6518227e-01 -1.3297446e+00 3.4776769e-01
+1 5.6633211e-01 1 1 3.4278418e-01 -1.5414407e+00 -1.4936273e-01 -7.7536959e-01 -1.1258022e-01 -1.3661144e+00 2.7340818e-01 1.5692242e+00
+1 1.0089197e+00 1 1 -5.0725905e-01 -1.4210228e+00 -2.0682013e-01 -3.1037904e-01 -8.9696599e-01 -1.5249108e+00 -9.7870504e-01 2.8137504e-01
+1 1.2116698e+00 1 1 7.7955048e-01 -7.4304543e-01 -1.4245092e+00 -1.4967840e+00 1.1957101e+00 -6.3334960e-02 2.8358996e-01 9.7327573e-01
+1 1.9429575e-01 1 1 1.4635042e+00 -5.3370988e-01 3.5087161e-01 1.4260555e+00 -4.6828718e-01 5.2923355e-01 5.0041285e-01 -4.2782147e-01
+1 6.4382914e-01 1 1 -1.5550394e+00 -8.1496330e-01 3.2970972e-01 5.0460906e-01 -8.1309611e-01 9.7945332e-01 3.9523499e-01 7.1009848e-01
+1 1.0499717e+00 1 1 -6.3830403e-01 2.5578630e-01 -3.3822624e-01 -1.3357301e+00 2.2169145e-01 -2.7355036e-01 1.3875770e+00 -2.8527472e-01
+1 7.7648960e-01 1 1 5.6314041e-01 1.3015923e+00 -1.4273214e+00 2.0580303e-01 3.9324263e-02 -1.4109312e+00 9.6394243e-01 -5.4187881e-01
+1 1.0409532e+00 1 1 -9.1771745e-01 9.5294258e-01 2.1009799e-01 3.8078742e-02 1.1884270e+00 -7.7879806e-01 -2.1284428e-01 1.1990410e-01
+1 4.8442298e-01 1 1 1.1426933e+00 2.6665546e-01 -3.3196811e-02 -8.9549085e-01 -3.5340120e-01 -1.3840302e+00 1.0002516e+00 1.4672533e+00
+1 2.6340886e-01 1 1 6.9102499e-01 -1.3744598e+00 1.2646837e+00 8.5568424e-01 1.1376671e+00 -1.0434135e+00 5.6561960e-01 -1.3760534e+00
+1 1.0887837e+00 1 1 -4.1103338e-01 -4.1517466e-01 -4.7714511e-01 -7.2620914e-01 1.0383584e+00 -2.8112089e-01 -9.0778758e-02 1.0763753e+00
+1 4.2712412e-01 1 1 1.2420398e-01 -3.6314726e-01 1.1082043e+00 -3.0960156e-01 1.4165101e-01 1.5660326e-01 1.0954489e+00 1.3492237e+00
+1 5.7103237e-01 1 1 1.4787631e+00 6.9855762e-01 -9.1265355e-01 -9.9590880e-01 -5.9875900e-01 -6.2360441e-01 1.4759166e+00 3.8615627e-01
+1 6.1987708e-01 1 1 4.3142299e-01 5.2619011e-01 1.4287525e+00 1.6639536e-01 -8.2121532e-01 -5.6618534e-01 -2.8484013e-01 -4.0200460e-01
+1 4.9943077e-01 1 1 1.3033831e-01 9.3886446e-02 -1.2912086e+00 5.8929088e-01 -1.1493373e+00 7.1453315e-03 4.7909903e-01 1.0744501e+00
+1 8.4120505e-01 1 1 9.0596419e-01 8.6999066e-01 7.7910034e-01 -1.2298189e+00 7.4148003e-01 7.1106584e-01 3.1550430e-01 4.0858100e-01
+1 7.7619474e-01 1 1 -7.5948532e-01 9.6087490e-01 1.8123752e-01 -1.0286418e+00 -6.4320009e-01 2.6513962e-01 -3.2763345e-01 -5.0065482e-01
+1 7.0750321e-01 1 1 -3.7883842e-01 -1.5034126e+00 -1.2859183e+00 -1.9753231e-01 -4.3565395e-02 1.4231410e+00 6.7647677e-01 -1.3204496e+00
+1 9.0994744e-01 1 1 8.7104156e-01 -2.5308421e-02 -1.4124828e+00 7.3786029e-01 -2.1251224e-01 -1.3550356e+00 1.2128486e-01 -5.8575533e-01
+1 5.8559772e-01 1 1 -2.2627228e-01 -1.2436169e+00 1.4167344e+00 1.3516968e+00 2.9758842e-01 -6.7834564e-01 -4.5894616e-01 9.6151763e-01
+1 5.8843265e-01 1 1 1.5104410e+00 -4.5402542e-01 9.2508661e-01 1.1117217e+00 1.5312622e-01 -1.1541619e-01 -8.9817879e-01 -1.2572684e-01
+1 3.0262298e-01 1 1 -1.2290702e+00 1.2331417e-01 1.8854521e-01 -1.4869188e+00 6.2791699e-01 -1.4372827e+00 -3.3821523e-01 1.2008435e+00
+1 7.7102466e-01 1 1 -1.0106113e+00 -9.0994681e-01 -9.8759069e-01 7.2603291e-01 7.9116173e-01 -7.0361532e-01 -1.2422285e+00 9.8539655e-01
+1 4.4890679e-01 1 1 1.2474563e+00 -2.0301895e-01 -1.4026801e+00 4.8924026e-01 -1.3064633e+00 -7.0787632e-01 8.9015586e-01 -9.1659091e-01
+1 7.3366472e-01 1 1 -9.9115357e-01 -3.6979858e-01 -3.3284470e-01 1.1130140e+00 -1.1374605e+00 -6.6004132e-02 5.8527435e-01 1.2269290e+00
+1 4.6892934e-01 1 1 1.5478008e+00 -1.1344744e+00 1.0556056e+00 1.3844554e+00 -7.0699994e-01 -3.4923590e-01 3.7936126e-01 -4.1850239e-01
+1 4.0193388e-01 1 1 1.5014542e+00 -7.8562263e-01 9.8987415e-01 -1.2347073e+00 -1.0446226e+00 -1.1127531e+00 -1.5083313e+00 2.5635437e-01
+1 6.8067494e-01 1 1 -1.4727767e+00 1.5432715e-01 -1.0598621e+00 -1.5058464e+00 1.3896865e+00 -1.3980307e-01 -1.0131414e+00 1.4243195e+00
+1 5.5188494e-01 1 1 -3.4921300e-01 -1.1791284e+00 -2.7234695e-01 -9.0705783e-02 -1.2800886e+00 2.4107117e-01 -4.3553716e-01 -3.9777996e-01
+1 6.4108962e-01 1 1 -7.2788863e-01 -4.4527764e-01 -3.4610188e-02 -8.1965730e-01 -8.2268922e-01 -9.7144708e-01 -1.6218590e-01 -1.7861229e-01
+1 6.8466708e-01 1 1 -2.6233208e-01 -5.0761792e-01 -4.9878421e-01 -9.6494649e-02 -7.8838764e-01 -2.5397568e-01 1.0440727e+00 1.4258847e+00
+1 1.1749844e+00 1 1 -1.3608008e+00 1.0313324e+00 -1.2969365e+00 -7.2376129e-01 8.0668950e-01 8.5521430e-01 -1.2060072e+00 7.7463054e-01
+1 3.9390537e-01 1 1 -1.8443100e-01 1.4363035e+00 -1.2415778e+00 -9.3220585e-03 -1.0834569e+00 8.0035277e-01 1.9267085e-01 4.5555885e-01
+1 8.6944173e-01 1 1 1.0201513e+00 -4.4456039e-02 -7.4051269e-01 4.0379509e-01 -9.8969854e-01 -7.7066422e-01 -7.6300354e-01 5.1624115e-01
+1 3.0320290e-01 1 1 -1.1298211e+00 5.2640496e-01 1.1933931e+00 7.4393742e-01 8.6967549e-01 2.3289577e-01 1.8069902e-01 -6.1398229e-01
+1 7.4857047e-01 1 1 -1.1179741e+00 5.6332693e-01 1.4310346e+00 -1.8246411e-01 -1.1947356e+00 -1.4518163e-01 -9.1166307e-01 9.3158214e-01
+1 1.1618276e+00 1 1 7.5722117e-02 -9.2450769e-01 -6.3551605e-01 -4.7979121e-01 1.1394004e+00 9.4991937e-01 -7.7392247e-01 -5.9676969e-01
+1 7.7442178e-01 1 1 3.1658956e-01 1.1657029e-01 2.9674894e-01 6.1740227e-01 -1.2462580e+00 -2.7899249e-01 -1.1213248e+00 1.1971609e+00
+1 1.0954525e+00 1 1 -9.3717662e-01 -1.1569732e+00 -1.3897572e+00 -5.3712427e-04 -8.5931297e-01 1.3710455e+00 3.0851525e-01 -1.2179861e+00
+1 9.2760213e-01 1 1 8.1803201e-01 1.2096195e+00 9.2277873e-02 3.9733034e-01 -5.7172288e-01 -4.1973416e-01 -1.5536468e+00 -7.3958374e-02
+1 7.9937495e-01 1 1 1.0545256e+00 8.2939207e-01 -1.0325632e+00 -1.0949259e+00 1.1854915e+00 1.5451249e+00 7.7619683e-01 1.0522936e+00
+1 9.2457590e-01 1 1 -1.4546201e+00 3.4583964e-01 -1.3246105e-01 1.0295173e+00 5.7495734e-01 5.0865399e-01 -1.4942240e+00 -1.2678054e+00
+1 6.1917813e-01 1 1 7.4268993e-02 5.8043972e-01 1.1163635e+00 -7.9517464e-01 -2.3105984e-01 6.7392119e-01 4.6967579e-01 1.4169409e+00
+1 4.9828974e-01 1 1 1.0266784e+00 8.0517303e-01 1.1298288e+00 -1.6494817e-01 -4.1426930e-01 1.1519181e+00 -9.8138938e-01 1.2529782e+00
+1 2.5437238e-01 1 1 -1.3853297e+00 -1.4381196e+00 1.2463933e+00 -1.3991794e+00 -8.5476576e-01 -1.3476142e+00 -8.4987401e-01 7.0925507e-01
+1 7.6642272e-01 1 1 -8.9276291e-01 9.3745779e-01 -7.0234280e-03 -1.1867900e+00 4.5504005e-01 1.5315926e+00 9.8933637e-01 1.2473685e+00
+1 6.9220282e-01 1 1 -4.1979315e-01 7.6587540e-01 1.3377663e+00 -4.0844793e-01 1.2215884e+00 -7.3408103e-01 -6.7360834e-01 6.7537534e-01
+1 1.1301740e+00 1 1 5.5361885e-01 9.6274323e-01 -5.4050592e-01 -4.0438193e-01 9.2890166e-01 -6.6545089e-01 9.6450025e-01 4.5916335e-01
+1 5.3087472e-01 1 1 -7.2550392e-01 -1.5183048e+00 1.2028949e+00 -1.1822667e+00 1.4762694e+00 -1.6325423e-01 -2.6235089e-01 1.4069097e+00
+1 2.9314647e-01 1 1 -1.0232389e+00 1.0089671e+00 9.0529478e-01 2.1670663e-01 -6.3944595e-01 -1.2034775e+00 1.4647226e+00 -8.3617843e-01
+1 6.5919321e-01 1 1 -4.9810900e-01 -6.0677322e-01 5.5622037e-01 1.0824034e+00 2.2032050e-01 -1.2729603e+00 7.2342112e-02 -1.3070031e+00
+1 5.4761905e-01 1 1 6.2651275e-01 -4.2768987e-01 -9.8402332e-01 -1.0084385e+00 -1.0111621e+00 -3.9756096e-01 5.7514477e-02 -7.8589933e-01
+1 1.2020709e+00 1 1 -8.1878328e-01 -2.1959930e-01 -1.1362330e+00 6.6553989e-02 1.4140966e+00 3.6045933e-01 -9.6471749e-01 -1.3545399e+00
+1 4.8314574e-01 1 1 -1.1148215e+00 5.6596854e-01 1.0742979e+00 1.6590082e-01 5.7391562e-01 1.2493569e+00 -2.4724060e-01 1.3693718e+00
+1 8.0088062e-01 1 1 -3.4680679e-01 -5.0923770e-01 9.9125414e-01 -1.4392731e+00 1.1103970e+00 -4.6465880e-01 9.5429914e-01 -2.7640224e-01
+1 7.5076681e-01 1 1 -1.1272889e+00 -1.0597075e+00 1.4242605e-01 4.0123445e-01 1.3821531e+00 4.7895955e-01 1.0751540e+00 9.2305668e-01
+1 1.0877698e+00 1 1 6.0067095e-01 -8.1528706e-01 -1.3891999e-01 -1.4520447e+00 9.1134765e-01 1.1128488e+00 -3.2750452e-01 6.2904710e-01
+1 9.5333123e-01 1 1 1.5394662e+00 1.0975150e+00 -6.2496220e-01 -6.2399363e-01 -1.3857449e+00 -1.3922335e+00 -2.9816653e-01 9.3534114e-01
+1 1.3609411e+00 1 1 -3.4924331e-01 -1.4974710e+00 -1.3954110e+00 -8.2468754e-01 1.5532889e+00 -6.8646978e-01 -4.4457120e-01 -2.5103280e-01
+1 1.0902866e+00 1 1 -1.2371892e+00 -6.9659973e-01 -6.8278493e-01 1.8334667e-01 -5.0806441e-01 -1.5694515e+00 -1.2007987e+00 5.0726397e-02
+1 5.4016764e-01 1 1 7.6263264e-01 9.6410083e-01 6.7169712e-01 -3.9484769e-01 -1.8976123e-01 -9.5997938e-01 -2.3191984e-01 1.1869446e+00
+1 2.7185809e-01 1 1 -1.3131950e-01 -6.9225090e-01 1.4710614e+00 -1.1614562e+00 -6.0045123e-01 8.4646930e-01 8.3967733e-01 -1.3606577e-01
+1 3.8590625e-01 1 1 1.4528645e+00 -1.3433414e+00 -2.0482365e-01 1.2623358e+00 -9.8815009e-01 1.4779761e+00 4.2271712e-01 2.2200682e-01
+1 3.6199718e-01 1 1 -1.3063732e+00 1.0879429e+00 7.1439373e-01 9.0340995e-01 -1.3798015e+00 -2.2926938e-01 1.4655726e+00 -9.4343698e-01
+1 8.6767176e-01 1 1 3.7630361e-01 9.8689437e-01 -3.5163282e-01 2.9369446e-01 9.1351848e-01 1.4037494e+00 -1.3496585e+00 -7.2726357e-01
+1 8.4324059e-01 1 1 5.0880461e-01 -8.7548961e-01 -5.5707614e-01 6.8075768e-01 5.4180179e-01 -5.4403579e-01 -1.4109206e+00 8.1821656e-01
+1 3.1736394e-01 1 1 6.3956191e-02 8.6613247e-01 -8.3259010e-01 -1.8610219e-01 -1.4143744e+00 1.5666439e+00 -6.0041746e-01 1.0146409e+00
+1 9.9253505e-01 1 1 4.8701939e-01 -1.0519523e+00 -6.8807300e-01 1.2068060e+00 1.0414022e+00 8.9631142e-01 -4.2065145e-01 5.0420079e-01
+1 8.9531186e-01 1 1 1.4861018e+00 7.2168942e-01 -2.4039880e-01 6.6582605e-01 1.0336106e+00 3.6928584e-01 -1.3053830e+00 1.2272342e+00
+1 5.6727478e-01 1 1 1.2514677e+00 -2.5519127e-01 -2.9451858e-01 1.8547282e-01 -1.1145315e+00 -1.1999059e+00 1.3107464e+00 1.5695213e+00
+1 3.9960247e-01 1 1 4.5532641e-01 -7.2564813e-01 1.1762900e+00 7.8177937e-01 1.3854848e+00 -9.3543139e-01 8.6756901e-01 -1.0090712e+00
+1 6.4933064e-01 1 1 -2.4881202e-01 -3.0545875e-01 -1.3735370e-01 1.2254497e+00 3.5764155e-01 -1.2657309e+00 1.1008058e+00 -1.1431024e+00
+1 8.5182370e-01 1 1 -3.2376284e-01 -4.8288846e-01 5.6697059e-01 -1.4803388e-01 1.0147582e+00 -1.4161027e+00 4.0359490e-01 -1.2825371e+00
+1 3.4369265e-01 1 1 -2.4349367e-01 -1.1725579e+00 6.2421443e-01 1.3602022e-01 -6.6482942e-01 2.6848969e-01 5.2086133e-01 -1.1337379e+00
+1 5.6634097e-01 1 1 1.0971419e+00 2.9430982e-02 1.3940507e+00 -9.8755588e-01 8.5693267e-01 1.1791115e+00 -1.5024239e+00 -9.7402685e-01
+1 1.0799442e+00 1 1 -1.4844561e+00 1.4164725e+00 -1.8848491e-01 -8.1765072e-01 1.4067357e+00 1.6092593e-01 8.8390786e-01 3.7010717e-01
+1 6.3694812e-01 1 1 1.2759469e+00 -3.3608837e-01 -1.1405149e+00 -9.2933551e-01 -6.1909333e-01 -2.2914800e-01 -7.5218509e-01 3.7775783e-02
+1 4.4758923e-01 1 1 3.2808474e-01 -5.3701213e-02 1.3638100e+00 6.5673742e-01 -1.4672784e-01 3.0211292e-01 -2.0590588e-01 2.9586875e-01
+1 5.7189688e-01 1 1 6.2504176e-01 -9.1919664e-01 4.9426250e-01 1.3707577e+00 9.5495958e-02 7.9807352e-01 1.3749555e+00 -4.7516398e-01
+1 9.5531996e-01 1 1 -4.0897875e-01 1.4147846e+00 6.9877874e-01 1.0250464e+00 -3.5328766e-01 -1.3790017e+00 -6.7882352e-01 -1.5250410e-01
+1 6.8576303e-01 1 1 9.8907222e-02 -4.2992521e-01 1.1009379e+00 -5.3976091e-01 -9.5511266e-02 -1.3526121e+00 1.2775631e+00 4.0316207e-01
+1 9.3092497e-01 1 1 4.3116809e-01 -8.9876281e-02 -5.1828414e-01 1.1579328e+00 9.6006523e-02 -7.8633766e-01 -7.8246098e-01 -4.7041511e-01
+1 6.3418799e-01 1 1 -1.0121539e+00 5.5541803e-01 8.3494449e-01 -7.9072247e-01 -1.1969875e+00 7.0318066e-01 -1.1480181e-01 1.1220205e+00
+1 1.1300500e+00 1 1 4.5292747e-01 1.2389812e+00 -5.8230652e-01 -7.3559521e-01 9.9069724e-01 -3.1428171e-01 -5.3617187e-01 -1.1815027e+00
+1 4.6973020e-01 1 1 2.7303284e-01 1.0800963e+00 -7.6461173e-01 -9.8156074e-01 2.0744723e-01 -1.1154713e+00 -1.3528295e+00 4.9194445e-01
+1 4.6598750e-01 1 1 -1.0039724e+00 1.0561588e+00 1.4262780e+00 -5.8835972e-01 -6.0230931e-01 1.2988600e+00 -1.2998877e+00 -5.6141629e-01
+1 5.3181967e-01 1 1 -2.7075991e-01 8.6306518e-01 1.1021984e+00 1.1718952e+00 -8.0097493e-01 -9.8754916e-01 -5.7728653e-01 -1.5207905e+00
+1 9.1261037e-01 1 1 1.5059208e+00 8.0322734e-01 -1.3239641e+00 1.3978763e+00 -2.6120163e-01 -7.0469683e-01 -1.2165393e+00 7.1115275e-02
+1 8.2618497e-01 1 1 1.3410173e+00 4.1833823e-01 3.6750089e-02 1.2770789e+00 -1.2108926e+00 -3.5242233e-02 -8.9119846e-01 1.4292178e+00
+1 7.1586575e-01 1 1 6.9274530e-01 1.2620302e-01 -1.2350119e+00 5.0454722e-01 -2.3388407e-01 1.4448064e+00 7.4118427e-01 2.4634767e-01
+1 7.3716681e-01 1 1 2.2795227e-01 5.1919945e-01 -3.4278679e-01 7.6663269e-01 -7.5719940e-01 1.4923563e+00 6.6920261e-01 -2.5388559e-01
+1 6.8758112e-01 1 1 -1.5491541e+00 -1.1592713e+00 4.6341996e-01 1.1241174e+00 3.4151864e-01 -4.4305547e-01 3.8654655e-01 -7.7227004e-01
+1 5.2287538e-01 1 1 8.8757591e-01 2.8572910e-01 6.9110363e-01 -4.9647336e-01 2.1396362e-01 -8.5862631e-01 -1.2575040e-01 1.5183061e+00
+1 3.3004394e-01 1 1 1.2064067e+00 -1.2461195e+00 9.1063042e-01 -1.5761244e-01 -1.0370098e+00 1.5442446e+00 8.0489019e-01 -9.8634684e-01
+1 9.8673396e-01 1 1 2.3882734e-01 1.4680437e+00 -8.7399358e-01 -6.2973523e-01 5.3196182e-01 1.4225588e+00 9.1486971e-02 6.5315912e-01
+1 7.5931903e-02 1 1 -9.8437936e-01 -6.5839230e-01 8.7711437e-01 6.5696738e-02 -2.9046734e-01 1.4248417e+00 1.3827136e+00 9.2059451e-01
+1 4.9713094e-01 1 1 -8.3707142e-01 -9.1000416e-01 1.3085287e+00 1.4660469e+00 1.5031967e-01 -1.0470191e+00 9.0735207e-01 8.8033700e-02
+1 6.8743898e-01 1 1 -6.0752390e-01 -1.1669381e+00 1.2929785e+00 3.3930617e-01 5.8214856e-01 -1.1898365e+00 5.7552491e-01 -1.0774081e-01
+1 7.4664573e-01 1 1 -4.7810175e-01 2.3512651e-01 6.9265595e-01 7.2815769e-01 1.2513945e+00 -1.3451071e+00 -1.1666775e-01 -1.2423528e+00
+1 6.3477038e-01 1 1 7.3789170e-01 -3.5237911e-01 -1.2737641e+00 -1.4987144e+00 -7.7494653e-01 -3.1491989e-01 -4.8105491e-01 -1.1989502e+00
+1 6.2628115e-01 1 1 -1.2619581e+00 -5.3357871e-01 -1.3401955e+00 3.9655449e-01 5.1677740e-01 7.2502496e-01 1.3696787e+00 -5.8102672e-01
+1 3.1261873e-01 1 1 -8.3799154e-01 1.3896783e+00 5.5373863e-01 -1.5683617e+00 -1.0259298e+00 -7.4344608e-01 -1.4016959e+00 -1.2461332e+00
+1 5.5340870e-01 1 1 -3.6386796e-01 -1.4177035e+00 1.2877504e+00 -1.4927611e+00 1.4006555e+00 -9.8421403e-01 5.0101162e-01 1.2381774e+00
+1 8.4957521e-01 1 1 1.1521355e+00 -1.5044156e+00 7.8999016e-01 -7.7055223e-02 8.6385231e-01 -1.1998115e+00 1.0339505e+00 1.3711755e-01
+1 6.4284971e-01 1 1 -8.3612947e-01 -1.1747669e+00 9.9412230e-01 -7.3095427e-01 1.4661080e+00 6.5167651e-01 1.4569233e+00 -1.3943033e+00
+1 5.4603975e-01 1 1 -4.8401823e-01 6.0315082e-01 1.2237363e+00 -1.5211582e+00 1.3656032e+00 1.1351516e+00 9.3742255e-01 -9.1587250e-01
+1 9.9801194e-01 1 1 -1.3110331e+00 -7.6373013e-01 -6.7133645e-01 1.7493100e-01 -7.8352994e-01 -3.9964762e-01 1.7371573e-01 7.3494583e-01
+1 4.2148962e-01 1 1 5.9747143e-01 5.3533773e-01 1.4490163e+00 -4.6537397e-01 7.6874183e-01 -1.5243454e-01 1.1006917e+00 -5.0767740e-01
+1 8.0889263e-01 1 1 1.1721292e+00 -1.0018742e-01 -9.8242447e-03 1.0254773e+00 -1.1266259e+00 -1.5692324e+00 -1.5138429e+00 3.1540437e-02
+1 4.0411982e-01 1 1 -9.5193684e-01 4.3616435e-02 1.3883308e+00 4.1918327e-01 -8.2299741e-01 -4.1876867e-01 6.0125988e-01 -8.2903379e-01
+1 3.2146623e-01 1 1 9.2897787e-01 1.0703373e+00 1.0665777e+00 -1.3791484e+00 3.1490037e-01 -1.0774514e+00 -1.1287357e+00 -6.0748102e-01
+1 6.1758721e-01 1 1 -3.8444975e-01 3.9950123e-01 4.3142634e-02 -6.7623685e-01 -1.0530682e+00 -5.8546916e-01 1.4162883e+00 2.4267390e-01
+1 9.7688841e-01 1 1 8.0905860e-01 8.3360425e-01 -6.0965299e-01 7.6940922e-01 8.1517050e-01 -5.1198082e-01 -2.9040109e-01 8.3295446e-01
+1 3.8556224e-01 1 1 1.0348090e+00 -1.1165833e+00 1.4374926e+00 6.6540438e-01 8.5062794e-02 -3.9322984e-02 1.2639014e+00 5.2881300e-01
+1 3.6749215e-01 1 1 1.7831568e-01 1.4586775e+00 1.0908360e+00 -6.1847325e-01 2.2572888e-01 -1.1669377e+00 -1.0578797e+00 1.9439027e-01
+1 9.3104105e-01 1 1 -1.2769340e-01 -9.9616139e-01 -6.5422437e-01 8.5024869e-01 -1.2186760e+00 2.4038818e-01 -1.5111727e+00 -1.3904070e-01
+1 9.9736352e-01 1 1 -4.3512699e-01 -9.3719985e-01 2.5327027e-02 -9.7520699e-01 8.9600121e-01 1.1599045e-01 1.4968175e+00 4.8783694e-01
+1 6.2639630e-01 1 1 4.4840592e-01 4.2773378e-01 1.5563424e+00 -6.1495667e-01 1.4386680e+00 -1.4775049e+00 -8.6254000e-01 -4.8136723e-01
+1 8.0257925e-01 1 1 -3.2239572e-01 9.5761062e-01 5.4553182e-01 2.6300141e-01 -1.1452080e+00 -1.2771310e+00 -1.4013250e+00 -7.3793747e-01
+1 9.7964141e-01 1 1 7.4252493e-01 1.8251247e-01 -1.5555883e+00 4.3816568e-02 1.0268469e+00 -1.3794113e+00 4.5099282e-01 4.9267179e-01
+1 8.7509226e-01 1 1 1.2105114e+00 1.2925970e+00 -4.3770868e-01 1.2923807e+00 1.4472707e+00 1.1887646e+00 -8.2666483e-01 -9.0344173e-01
+1 2.1947254e-01 1 1 1.1043972e-01 5.6446626e-01 1.0402303e+00 7.1421996e-02 -1.0736532e+00 -9.6255897e-01 1.5085721e+00 -8.2780360e-01
+1 9.9018915e-01 1 1 -5.2093590e-01 -6.2545310e-01 1.8724348e-01 3.0109666e-01 4.1822292e-01 1.4735272e+00 -1.2232261e+00 1.2187377e+00
+1 1.2764617e+00 1 1 2.4913725e-01 -2.2120912e-01 -8.7465693e-01 -5.7419471e-01 1.3299013e+00 3.9687111e-01 -1.7848560e-01 1.4081914e-01
+1 7.1660714e-01 1 1 -4.9332943e-01 -1.3576075e+00 -8.4695673e-01 4.8210380e-01 -7.8094264e-01 6.1161475e-01 4.1345073e-01 1.1279761e+00
+1 9.8695416e-01 1 1 -7.2464070e-01 7.8778896e-02 -2.4547783e-01 5.5115602e-01 2.7116046e-01 1.1797917e-01 -3.3654435e-01 1.5248118e+00
+1 8.0871847e-01 1 1 9.1849910e-01 1.4263923e+00 -8.3481004e-01 -1.2775078e+00 -1.0571378e+00 5.3088884e-01 -1.4341694e+00 1.5411320e+00
+1 8.6627476e-01 1 1 -5.7194118e-01 -1.1839134e-01 -2.9951986e-01 -1.4298069e+00 1.5330870e+00 5.2553508e-01 1.3544936e+00 -6.2532186e-01
+1 6.9483104e-01 1 1 6.5807424e-01 -1.1750914e+00 -1.1987811e+00 -7.2155786e-01 -7.5051392e-01 -1.4903815e+00 9.9354222e-01 -1.1571029e+00
+1 8.5895734e-01 1 1 -1.2939695e+00 1.4310615e+00 -8.7979072e-01 -6.7534248e-01 -3.9297854e-01 -9.2320609e-01 8.9922143e-01 -9.6982015e-01
+1 4.1759824e-01 1 1 1.5012168e+00 -1.8318415e-01 8.3404316e-01 9.3164950e-02 -1.1625549e+00 1.3253270e-03 -9.8762871e-01 -1.1846164e+00
+1 3.4775666e-01 1 1 8.1947766e-01 -1.5247437e-02 -2.2974693e-02 1.3101685e+00 -1.4962361e+00 2.8362193e-01 1.0998404e+00 1.5667735e+00
+1 7.0022895e-01 1 1 2.1891879e-01 1.3469232e+00 2.8022732e-01 5.7843523e-01 1.2090850e+00 1.0377429e+00 -1.1352829e-01 -6.7808530e-02
+1 3.4022419e-01 1 1 5.6304605e-01 -5.7852443e-01 5.3313942e-01 -1.4683944e+00 1.2710655e+00 -7.7713802e-01 -1.1231973e+00 7.4016891e-01
+1 3.3849329e-01 1 1 6.3784914e-01 -3.0814041e-02 6.5191301e-01 1.0473465e+00 -3.1543657e-02 1.3835282e+00 2.5402219e-01 -6.8801822e-01
+1 9.0995371e-01 1 1 1.2163261e+00 4.7119874e-01 -1.1732074e+00 4.0942845e-01 7.7491722e-01 -1.1095620e+00 -7.3511410e-02 6.8039424e-01
+1 7.1710415e-01 1 1 4.4939406e-01 -5.1787888e-01 -1.4617987e+00 1.1761308e+00 -1.0094078e+00 8.6255466e-02 -8.6036211e-01 -1.1253855e-02
+1 8.2532546e-01 1 1 5.7728071e-01 1.3629231e+00 -1.1967103e+00 3.2980847e-01 -5.1697940e-01 1.4214072e+00 6.4502737e-01 -6.4798200e-01
+1 1.0508406e+00 1 1 1.1187803e+00 1.2965903e+00 -6.3420958e-01 1.3214879e+00 7.7258674e-01 9.2075388e-01 -6.6127002e-01 1.2683222e+00
+1 1.0319914e+00 1 1 9.0927627e-01 -1.4357990e+00 2.6337956e-01 -8.1372746e-01 6.6282595e-01 -3.7502239e-01 9.8957590e-01 9.8493149e-01
+1 5.9138164e-01 1 1 1.4995220e+00 -8.9992864e-01 1.1629153e-01 -9.6465619e-01 2.8131537e-02 -9.6652558e-01 2.1061929e-01 6.9184660e-01
+1 8.8858124e-01 1 1 6.0966270e-01 -1.4735686e+00 4.4103514e-01 7.8316247e-01 1.5678361e+00 7.8020431e-01 -6.9652447e-01 8.3131989e-01
+1 4.9161981e-01 1 1 -1.2741594e+00 -1.0921252e+00 1.4604944e+00 -6.6165600e-01 -1.0572249e+00 -1.1393289e-01 -9.1255084e-01 1.3309361e+00
+1 4.0573236e-01 1 1 1.4398006e+00 9.7792016e-01 1.2661984e+00 7.8563284e-01 6.8595738e-02 1.5013581e+00 1.3308714e-02 9.0277247e-01
+1 8.0566905e-01 1 1 -9.6006624e-01 -9.0870456e-01 -1.5238054e-01 1.7218193e-02 -7.5935978e-02 5.3727761e-02 6.2647168e-01 -9.9567381e-01
+1 9.4489240e-01 1 1 -6.1335034e-01 -1.3155971e+00 -6.6171649e-01 3.5963732e-01 -7.6935988e-01 1.3653817e+00 -1.5090953e+00 9.7430412e-01
+1 3.9784617e-01 1 1 -1.0136067e+00 -7.1143036e-01 -2.3102595e-01 2.1749276e-04 1.6380111e-01 -1.3637606e+00 -1.2874203e+00 1.1484473e+00
+1 8.4984919e-01 1 1 1.1693844e+00 -1.0841210e-01 1.5544220e-01 5.1380820e-01 9.7003357e-01 3.3499216e-01 -1.5249855e+00 8.3293355e-03
+1 4.3378634e-01 1 1 3.9410126e-02 4.1635305e-02 -1.2880257e+00 -6.6371756e-01 -1.5115821e+00 4.7925789e-01 -1.3192524e+00 -1.3805280e+00
+1 6.0978794e-01 1 1 -5.1006535e-01 -8.1059609e-01 8.6633919e-01 6.9445973e-01 8.9886352e-01 -1.5625569e-01 6.8562721e-01 1.2692144e+00
+1 5.2321031e-01 1 1 7.3798647e-01 1.3988020e+00 -7.1926615e-01 7.6792502e-01 -7.1996346e-01 1.8213178e-01 -2.5409350e-02 2.7296192e-01
+1 7.5242595e-01 1 1 3.3082945e-01 1.1267562e+00 1.4242931e-01 8.5316133e-01 9.8910835e-01 1.1776107e+00 2.0165118e-01 9.4577716e-01
+1 4.7871841e-01 1 1 -3.6846888e-01 -1.2841092e-01 -8.4139567e-02 8.5360525e-01 -1.3642850e+00 6.8584770e-02 -6.2706300e-01 -7.8203040e-01
+1 1.1483430e+00 1 1 -7.7737344e-01 7.1805232e-02 -4.1701395e-01 -1.1101920e+00 9.4624400e-01 -2.6026670e-01 9.9545522e-01 8.3868399e-01
+1 1.8691186e-01 1 1 5.6841541e-01 4.5896319e-01 1.3975296e-01 -1.0779145e+00 7.8085075e-01 -1.2054057e+00 -1.5065405e+00 -5.6434245e-01
+1 4.7865122e-01 1 1 -2.2538250e-01 1.1843008e+00 -1.0833571e+00 1.0565300e+00 1.3259832e+00 8.7662692e-01 8.1095038e-01 -4.3529480e-01
+1 4.2268755e-01 1 1 7.5706644e-01 -5.8779867e-01 6.8867728e-01 8.1739833e-01 -6.5868140e-01 -6.0088537e-01 1.4140507e+00 7.6956892e-01
+1 8.0514319e-01 1 1 5.6538675e-01 1.1766772e+00 9.7175912e-01 -1.7086665e-01 5.1424600e-01 1.1399884e+00 -1.9878833e-01 2.0785583e-01
+1 6.5662043e-01 1 1 -8.6266718e-01 8.8717897e-02 -7.8474618e-01 -3.4009773e-01 4.1110639e-01 -7.8823426e-01 -1.5224712e+00 -1.8099620e-02
+1 1.3402954e+00 1 1 -3.9720156e-01 -1.1748201e+00 -8.2313569e-01 -1.4655869e+00 1.1029218e+00 2.4297315e-01 9.8936223e-02 5.3417965e-01
+1 4.5731186e-01 1 1 1.1775015e-01 -2.9123551e-01 1.1324311e+00 1.1088508e+00 1.4098322e+00 -4.2078302e-01 9.1858602e-01 -7.1445074e-01
+1 4.1360195e-01 1 1 -1.7660554e-01 -1.9378709e-01 1.0004380e+00 5.2782805e-01 1.1583028e+00 -3.7516890e-01 8.8886194e-01 -6.0645910e-01
+1 5.0840446e-01 1 1 5.9572380e-01 8.5200974e-01 5.5796881e-01 -6.5158757e-01 -8.5468224e-01 -2.8727367e-01 8.2962703e-01 -1.4315224e+00
+1 5.7806877e-01 1 1 7.4197678e-02 3.4843563e-01 1.2772625e-01 3.5972950e-01 -1.2827919e+00 4.1933216e-01 1.1533550e+00 -1.2804136e+00
+1 4.2841980e-01 1 1 -1.7190160e-01 2.2888211e-01 9.8730777e-01 1.5494118e+00 8.6639513e-01 1.1232204e+00 8.1097105e-01 -2.1055641e-03
+1 9.6491049e-01 1 1 1.1150752e+00 1.5121650e+00 -2.1075663e-01 3.0318114e-01 2.2097542e-01 1.3551384e-01 -1.3800256e+00 -8.3069655e-01
+1 3.7285142e-01 1 1 1.4689408e+00 -5.2714112e-01 1.5297910e+00 -9.7788344e-02 5.7143384e-01 -7.3585648e-02 2.8846520e-01 -2.7917911e-01
+1 9.4980707e-01 1 1 -1.2888551e+00 -3.6943976e-01 4.0309684e-01 -4.7574511e-01 2.3984051e-01 1.0335252e+00 7.5714354e-01 1.3760655e+00
+1 1.2634967e+00 1 1 -5.0600696e-01 -1.3869447e+00 -1.5667120e+00 -4.9469720e-01 3.3600974e-01 5.9288600e-01 -1.2803341e+00 -8.7242395e-01
+1 5.0023463e-01 1 1 -1.6760457e-01 2.3728050e-01 1.1003507e+00 1.4199428e+00 -1.2679134e+00 -4.9690224e-01 1.3336959e+00 -1.0163636e+00
+1 5.7977968e-01 1 1 1.0786398e+00 1.2922665e+00 -9.6192428e-01 1.4416437e+00 -3.9772216e-01 -1.0826016e+00 1.6359249e-01 -1.1836571e+00
+1 8.2751996e-01 1 1 -1.4318466e+00 1.2934869e+00 -4.2565885e-01 -1.3989658e+00 7.9287970e-01 8.1936658e-01 6.0533483e-01 -1.1598561e+00
+1 8.8169292e-01 1 1 -4.4537266e-01 -1.8622825e-01 -6.4178367e-01 -7.3881424e-01 -7.0698937e-01 1.4935759e+00 1.3855445e+00 -1.1866977e-01
+1 1.0477357e+00 1 1 1.0369828e+00 -9.1192775e-01 -1.3706224e+00 1.4648975e+00 -8.6688124e-01 1.2045860e+00 1.3620067e+00 4.2849822e-01
+1 6.8148344e-01 1 1 -9.8687538e-01 1.0607875e+00 1.2481200e+00 -1.2853999e-01 1.0336514e+00 1.0534203e+00 -1.5390177e+00 1.2392165e+00
+1 6.2105805e-01 1 1 1.1947552e+00 1.1691010e-01 7.3808086e-01 1.0442111e+00 -4.2911237e-01 -1.1812340e+00 -1.5388006e+00 -1.2467769e+00
+1 9.5281759e-01 1 1 -8.0902133e-01 1.4127114e+00 -1.2243683e+00 1.1192595e+00 1.0051009e+00 -1.2756669e+00 -1.0304139e+00 -1.5664569e-01
+1 3.1568525e-01 1 1 -4.0854682e-01 -7.1725551e-01 -5.2671472e-01 -4.6172203e-01 3.8769663e-01 1.2370872e+00 1.4346364e+00 -8.9500015e-02
+1 7.1609958e-01 1 1 1.0751854e+00 -6.2242776e-01 5.1380023e-01 -4.2832770e-01 3.5416810e-01 6.6402293e-01 2.0966609e-01 5.9612624e-01
+1 6.4192118e-01 1 1 2.0045780e-01 3.6011494e-01 -7.9766898e-01 -1.5148931e+00 -8.1475459e-01 1.2962686e+00 -1.0090079e+00 5.5469828e-01
+1 1.1755403e+00 1 1 1.3069511e+00 -1.3971629e+00 -1.2466355e+00 -1.3415066e+00 6.2205863e-01 -5.5945139e-01 -7.7859155e-02 -1.4329290e+00
+1 6.3556670e-01 1 1 -8.9308924e-02 1.2875816e+00 -9.2160880e-01 5.0837958e-01 -2.8103401e-01 8.7273391e-02 1.4653238e+00 2.1179604e-01
+1 2.6294213e-01 1 1 6.6619579e-01 1.0931307e+00 -1.4273796e+00 -7.9634388e-01 -1.5247764e+00 -3.1988771e-01 7.5305266e-01 2.3159527e-01
+1 6.8784930e-01 1 1 1.1644807e-01 2.1370545e-01 -7.6717200e-01 -9.6695983e-01 -9.4498923e-01 -1.0877599e+00 -9.2072789e-01 -1.1569977e-02
+1 1.2091835e+00 1 1 -6.9474377e-02 9.0701510e-01 -7.6350817e-01 -2.3514306e-01 1.4585078e+00 -1.0533579e+00 8.1169221e-01 3.2214140e-01
+1 5.6374124e-01 1 1 1.0166163e+00 1.1953044e+00 1.1241248e+00 7.4223392e-02 -7.0698643e-01 -9.1156432e-01 1.3156113e+00 1.2663120e+00
+1 8.0369256e-01 1 1 -8.5271761e-01 -1.0044288e+00 -3.7282400e-01 2.6026874e-01 -8.1743626e-01 8.8576704e-01 9.4931214e-01 -1.3840591e+00
+1 5.2951423e-01 1 1 3.2079712e-01 1.4846111e+00 1.4242944e+00 1.2398033e+00 -4.6648441e-01 -9.2096897e-01 -1.0599453e+00 -1.5292825e+00
+1 6.1725576e-01 1 1 6.6427273e-01 1.3296638e+00 -8.2085301e-01 -8.0950487e-01 1.2117507e+00 -9.8450403e-02 1.4710172e+00 -1.2808746e+00
+1 4.2123357e-01 1 1 -7.8856763e-01 1.5115084e+00 -1.3432653e+00 8.8942730e-01 -1.0513376e+00 9.6341324e-01 -9.4861298e-01 -1.4668835e+00
+1 3.6790813e-01 1 1 9.2318811e-01 1.0036048e+00 -7.7567753e-01 9.0686777e-01 -1.5132357e+00 3.1771215e-01 2.4431999e-01 1.3076679e+00
+1 8.1685629e-01 1 1 -3.0360115e-01 3.7467399e-01 7.9718716e-01 -1.2809282e+00 1.3812292e+00 -9.1932658e-01 2.2452986e-01 -6.0821514e-01
+1 1.1755284e+00 1 1 -6.7810365e-01 1.3940326e+00 -5.6814216e-01 7.7459397e-01 1.0913226e+00 -7.6910537e-01 6.2057872e-01 4.7058985e-01
+1 6.4679544e-01 1 1 8.1004428e-01 -4.9144918e-01 -1.4652215e+00 -1.5909817e-01 1.2407815e+00 1.2997777e+00 -2.1113433e-02 -1.3267628e+00
+1 8.2416991e-01 1 1 -1.2483155e+00 -5.3929421e-01 9.6714610e-01 -4.6759820e-01 -7.6603857e-02 -1.2708889e+00 1.4650487e-01 1.2166297e-01
+1 9.3584861e-01 1 1 -8.8218267e-01 -4.2306537e-01 2.2414840e-01 1.3418176e+00 5.7196573e-01 -1.4207116e-01 -7.0122365e-01 -3.8728258e-01
+1 1.0144341e-01 1 1 1.4732430e+00 -1.0354593e+00 4.9256113e-01 -1.5648780e+00 -2.4542619e-01 -1.7964090e-01 -1.3518215e+00 3.2157997e-01
+1 8.5198333e-01 1 1 -1.2376861e+00 1.4593602e+00 3.7827192e-01 5.0854293e-01 3.3243323e-02 -1.5407220e-01 -6.6439164e-02 1.2551373e+00
+1 7.0227689e-01 1 1 -1.3046317e+00 1.0535189e+00 -9.6743578e-01 -1.1926456e+00 -4.8295621e-01 -8.1906223e-01 -1.3776391e+00 -7.0266919e-01
+1 6.5833055e-01 1 1 1.3725668e+00 4.7521000e-01 1.1904881e+00 -1.4327477e+00 8.3037392e-01 4.8016260e-01 -4.4256810e-01 -5.1429695e-01
+1 7.3072358e-01 1 1 1.5427228e-02 9.2592108e-01 -2.6940757e-01 1.1749973e-01 1.1399629e+00 -6.5874176e-01 1.0493617e+00 -1.2674562e+00
+1 9.4819161e-01 1 1 -1.4667657e+00 -1.4943508e+00 -8.9805835e-01 -1.2437378e+00 -1.2164215e+00 -5.0027370e-01 -2.7942939e-01 1.0031289e+00
+1 1.0934810e+00 1 1 1.4694816e-01 1.4789134e+00 -1.4555876e+00 6.5577407e-01 1.0893794e+00 -1.1980625e+00 3.1129358e-01 -1.3399843e+00
+1 9.0415204e-01 1 1 4.6590090e-01 -1.8409873e-01 -4.7875160e-01 8.8778619e-01 -1.9648211e-03 -1.3688972e+00 1.1593768e+00 9.6087499e-01
+1 8.8674764e-01 1 1 1.5474733e+00 3.2139754e-01 -7.5928813e-01 -1.5426790e+00 1.5347704e+00 -1.1717509e+00 1.4877503e+00 -1.5018636e+00
+1 5.5421793e-01 1 1 -8.6218910e-01 1.3306981e+00 -2.0621538e-01 -2.4166564e-01 -7.3161907e-01 1.0271410e+00 6.8270238e-01 8.7595373e-01
+1 7.2063721e-01 1 1 1.3546819e+00 4.4459810e-02 -6.8525641e-01 4.0482143e-01 -1.2802723e-01 1.0681391e-01 1.0825837e+00 6.5118848e-01
+1 9.1094737e-01 1 1 1.0165272e+00 -4.6301900e-01 -2.5838806e-02 -8.5588240e-01 2.3731840e-01 1.3719976e+00 -1.1197000e+00 -7.8402362e-01
+1 4.5948534e-01 1 1 7.9126478e-01 -2.3528863e-01 -7.3302537e-01 5.3728475e-01 -1.2123685e+00 -1.2618297e-01 -6.5817038e-01 -1.2453648e+00
+1 3.3781487e-01 1 1 4.2548819e-01 7.6906363e-01 1.3690261e+00 1.2075677e+00 9.3208906e-02 -1.8208347e-01 -3.2183178e-01 -1.5557680e+00
+1 3.3931472e-01 1 1 9.1505068e-01 1.1401927e+00 1.9752557e-01 9.0125710e-01 -1.0926507e+00 -3.6561626e-01 7.9584226e-01 -3.1671060e-01
+1 3.0626536e-01 1 1 1.1606792e+00 -4.9569914e-01 -8.5113382e-01 -1.3316748e+00 -1.5706644e+00 4.2795459e-02 -1.1806310e+00 -1.0971490e+00
+1 7.3391219e-01 1 1 1.3867905e+00 2.8823641e-01 -1.3347007e+00 -7.5164255e-01 6.4626187e-01 -1.6144345e-01 -5.6675471e-01 1.3652078e+00
+1 8.4767898e-01 1 1 3.1202772e-01 5.3460190e-02 -1.3433179e+00 -5.1220188e-01 1.2374566e+00 9.5598457e-01 -1.3748910e-01 -1.1448561e+00
+1 2.6637995e-01 1 1 9.3173128e-01 9.9145828e-03 1.4832815e+00 -6.1308723e-01 5.8907265e-01 1.1277580e+00 1.4329382e+00 6.5896395e-01
+1 4.8276850e-01 1 1 -1.2316908e+00 1.2998197e-01 9.7462819e-01 2.6679553e-01 1.3855858e+00 1.0002713e+00 -5.7215912e-02 1.0929701e+00
+1 5.0042403e-01 1 1 -1.0726361e+00 1.2000608e+00 3.1195568e-01 9.7981991e-01 -1.0852170e+00 8.9717886e-01 -3.0047766e-01 6.5684586e-01
+1 1.2004812e+00 1 1 -1.3354886e+00 3.9622854e-01 -2.7906854e-01 -3.9541314e-01 8.4442992e-01 -7.5970831e-01 1.5530258e+00 5.1720549e-02
+1 6.7728530e-01 1 1 1.1228301e+00 -7.6339096e-01 9.2876611e-02 -1.2402459e+00 -1.3820222e+00 -9.8500868e-01 1.3535194e+00 -9.5389342e-01
+1 7.3496389e-01 1 1 -1.4196973e-01 -4.7511668e-02 -3.9433948e-01 -3.4623577e-01 1.2892617e+00 1.1524237e+00 3.2842830e-01 -5.3940582e-01
+1 5.7206411e-01 1 1 1.5252154e+00 -5.6407217e-01 1.0969003e+00 -9.5501839e-01 1.0562370e+00 8.6560011e-01 1.1612627e-01 8.4276490e-01
+1 5.6779850e-01 1 1 -1.1006590e+00 9.6568336e-01 7.3765083e-01 -5.9723476e-01 -9.6409233e-01 -5.7450433e-01 8.0515208e-01 -1.0915601e+00
+1 2.5089458e-01 1 1 -1.0784457e+00 7.7262510e-01 9.7288497e-01 -3.3609261e-01 8.3512750e-01 1.5616159e+00 1.3514818e+00 1.0508581e+00
+1 9.1031070e-01 1 1 1.5530084e+00 1.3077007e+00 -7.1199277e-01 -1.2495510e-01 -6.4815537e-01 1.2139680e+00 6.3908484e-01 -2.6144011e-01
+1 2.6248081e-01 1 1 1.0612014e+00 -5.6353999e-02 -1.3613408e-01 -1.5365511e+00 1.4961028e+00 -1.4848362e+00 -6.3046510e-03 1.0641261e+00
+1 9.2525598e-01 1 1 7.9098624e-01 -1.5222641e+00 -9.2609548e-01 -9.2326317e-01 -3.0857235e-01 1.1696399e+00 8.5188077e-01 -3.1917053e-01
+1 9.1798083e-01 1 1 -1.1143588e+00 4.3710531e-01 -1.4367215e+00 -9.5797137e-01 5.9405506e-01 1.1920077e+00 1.3224151e+00 1.5411471e+00
+1 1.0785131e+00 1 1 1.1462711e+00 1.3852462e+00 -6.9748095e-01 3.7502671e-02 3.0201143e-01 1.3784727e-01 -9.3791389e-01 -3.7226974e-01
+1 9.1430994e-01 1 1 1.1325580e+00 -5.1092400e-01 -1.2800851e+00 -1.1527349e+00 -9.0756958e-01 1.4452428e+00 9.9315910e-01 1.3150653e+00
+1 8.1450142e-01 1 1 -7.3489097e-03 -1.1268917e+00 -7.6397483e-01 1.8561208e-01 -1.0896650e+00 -5.9848331e-01 7.4322354e-01 1.1978035e+00
+1 9.7686914e-01 1 1 -9.9101228e-01 9.9253447e-01 -4.3578130e-01 -1.9302429e-02 1.4848556e+00 6.7071113e-01 3.8564123e-01 1.5733929e-01
+1 8.5033613e-01 1 1 7.8082157e-01 -3.3017021e-01 -1.1237896e+00 -8.3188844e-01 -8.4383403e-01 6.0760204e-01 3.6648279e-01 -8.1955691e-01
+1 3.5008398e-01 1 1 8.3556563e-01 -1.1180199e+00 -2.7759119e-01 -1.4617525e+00 -1.1692919e+00 -1.3502605e+00 -1.1870091e+00 -1.5508109e+00
+1 9.0687494e-01 1 1 4.3232366e-01 -6.9553119e-01 -2.1007167e-01 -4.1891681e-01 1.5150213e+00 1.0364877e+00 -9.4906854e-01 1.3156775e+00
+1 9.1480742e-01 1 1 -4.4003320e-01 7.3623578e-02 4.7552169e-01 -4.2563887e-01 3.5456971e-01 1.1799037e-01 -1.1291163e+00 -1.0786250e+00
+1 5.1786794e-01 1 1 -3.2883715e-01 -3.9602665e-01 -1.1860337e-01 -3.0599541e-01 -3.4819496e-01 7.1922728e-01 1.3038098e+00 -1.4602591e+00
+1 6.6887232e-01 1 1 -7.0449120e-01 1.0148899e+00 1.5444896e+00 -7.7628728e-02 6.7444983e-01 -7.9563916e-01 5.2330412e-01 -4.5332299e-01
+1 1.1979676e+00 1 1 2.7907720e-01 1.5486882e+00 -7.4417761e-01 -9.4507231e-01 6.1199394e-01 1.4525620e+00 -1.2871179e+00 -6.3735862e-01
+1 1.0016177e+00 1 1 5.2729167e-02 7.0755989e-01 -7.1280321e-01 6.2172474e-02 2.0786191e-01 -1.0635891e-01 4.1563389e-01 7.4462285e-01
+1 8.5032566e-01 1 1 2.8998012e-01 1.0308167e+00 -1.1907390e+00 -1.2175783e+00 8.4035876e-02 -7.9782571e-03 -1.3432951e+00 -1.2288163e+00
+1 6.5457170e-01 1 1 1.0856208e+00 -9.4762013e-01 -8.0534677e-01 4.9621198e-01 -1.3257313e+00 9.9791729e-01 -1.2756596e+00 1.1430107e-01
+1 5.5326400e-01 1 1 -3.4155490e-01 1.2232658e+00 -1.4820114e+00 -1.0936785e+00 -1.3914376e+00 -9.6734654e-01 1.3597776e+00 1.5449260e+00
+1 7.6650216e-01 1 1 -8.2340814e-01 8.4529221e-01 1.5225770e+00 4.8140179e-03 1.2442618e-01 -4.5125681e-01 -1.3039875e+00 3.0800147e-01
+1 6.2931210e-01 1 1 -3.0493626e-01 5.4415208e-01 -1.4623533e+00 -7.7220943e-01 -1.0699119e+00 -4.6853893e-01 -3.6702332e-01 -7.6396520e-01
+1 3.9104620e-01 1 1 -1.1261037e+00 3.8787147e-01 -1.0933330e+00 -6.0468536e-01 4.6775705e-01 1.2390390e+00 1.5270634e+00 -2.7394792e-01
+1 5.6736285e-01 1 1 -1.4714006e+00 1.5107315e-01 -4.7258060e-01 1.0531638e-01 1.3278429e+00 -1.0889717e+00 -1.4567733e+00 1.3320611e+00
+1 9.6291509e-01 1 1 7.8740259e-01 6.7962047e-01 -7.1593017e-01 1.3357892e+00 -8.1802377e-01 5.7132380e-01 -1.5566078e+00 9.6092104e-01
+1 8.3505123e-01 1 1 1.4870567e+00 -4.4962818e-01 -3.3849849e-01 7.8759620e-01 -9.1607468e-01 1.5319546e+00 1.2767124e+00 -7.2790567e-01
+1 1.0377469e+00 1 1 -1.5495383e+00 -1.3704863e+00 2.8014942e-01 -1.5421026e+00 4.7848023e-01 -9.3307405e-01 6.2719680e-01 -5.4877371e-01
+1 6.8720618e-01 1 1 7.1294087e-01 3.9424930e-01 -7.7608323e-01 2.1602334e-02 -6.5995837e-01 6.5492717e-01 1.2531976e+00 4.7630247e-01
+1 9.5591178e-01 1 1 3.6283250e-01 5.2915798e-01 2.6190613e-01 -1.3543175e+00 1.0432946e+00 -7.7965630e-01 1.2550636e+00 4.3759312e-01
+1 8.2286618e-01 1 1 2.9453028e-01 -2.9067557e-01 4.8493698e-01 -1.1754184e+00 1.4240148e+00 -1.0048050e-01 1.2007580e+00 1.5923896e-01
+1 8.4464596e-01 1 1 -9.7966560e-01 -2.0776510e-01 1.0444864e+00 -9.2188638e-01 7.6451749e-01 1.4011613e+00 -4.5126188e-01 -3.0771615e-01
+1 1.0316974e+00 1 1 -1.5264112e-01 1.5430017e+00 -5.3652889e-01 1.9049528e-01 1.3150146e-01 -5.9731541e-02 -5.5373380e-01 -7.2376928e-01
+1 3.2076223e-01 1 1 1.2418378e+00 -6.1705285e-01 -1.0701169e+00 3.7130592e-01 -1.5362440e+00 1.4016338e+00 -1.2064895e+00 -1.4349476e-01
+1 8.6960637e-01 1 1 -1.1736633e+00 -4.0998014e-01 1.6371509e-01 1.3355159e+00 1.0964043e+00 -1.5442001e+00 1.5108803e+00 1.0267418e+00
+1 5.8943573e-01 1 1 3.0114514e-01 -1.0234561e+00 -4.7572215e-01 -6.6432677e-01 -1.3150578e+00 -6.7353234e-01 -1.2833124e-01 -3.1868499e-01
+1 7.0096072e-01 1 1 2.4067640e-01 -1.0061515e+00 -1.0880009e-01 -1.1980884e-01 -1.0720642e+00 -8.9963650e-01 1.4110735e+00 2.7693128e-01
+1 4.4831498e-01 1 1 -1.3231350e+00 8.0520397e-01 -1.9613983e-01 1.3369723e-01 -1.1493017e+00 2.9471873e-01 2.9570799e-02 -1.4562439e+00
+1 1.2286052e+00 1 1 1.4043755e+00 -9.1807439e-01 -9.9141978e-01 8.1056469e-01 1.3398603e+00 -9.5392688e-01 6.2478302e-01 1.0563463e+00
+1 7.5656956e-01 1 1 5.5301090e-01 1.4267829e+00 2.1524903e-01 1.2149267e+00 9.5545550e-02 -1.1018149e+00 1.5255063e+00 8.7134694e-01
+1 6.2663595e-01 1 1 -1.5184553e+00 1.6322289e-01 -1.4243374e+00 -1.0789212e+00 4.8022060e-01 1.4856416e+00 6.4707334e-01 -1.3769154e+00
+1 9.8839177e-01 1 1 -1.5215541e+00 6.7667079e-01 9.6512212e-02 -1.5641280e-01 3.1609409e-01 -1.9978724e-01 -8.3214797e-01 -8.4512738e-01
+1 2.7929952e-01 1 1 -1.9571371e-01 2.4047977e-01 1.0189314e+00 6.8317520e-01 1.6016542e-01 5.3840901e-01 4.5957843e-01 -9.1554686e-01
+1 9.3209764e-01 1 1 -1.1277760e-01 -1.4862428e+00 3.5849958e-01 -3.9556585e-01 -4.4466337e-01 1.2534718e+00 -1.0416746e+00 -7.5237405e-02
+1 9.8713864e-01 1 1 -1.0727854e+00 -4.7898092e-01 -2.7218450e-01 -6.6521944e-01 3.9174717e-01 -4.2005042e-01 6.7086064e-01 1.5467725e+00
+1 1.0480099e+00 1 1 -7.0346881e-01 -1.4718721e+00 -4.4600844e-01 5.8507959e-01 -6.8345654e-01 -6.2877854e-01 -2.1221392e-02 -7.3093437e-02
+1 7.1541249e-01 1 1 -1.3871774e+00 -8.5332184e-01 -2.2379053e-01 2.4770061e-01 -1.1913904e+00 4.3677157e-01 1.4736312e+00 -1.1867100e-01
+1 8.2110053e-01 1 1 -5.3160828e-01 -4.0967805e-01 -7.6103777e-01 4.9393160e-01 8.1349530e-01 -1.0822292e+00 -9.9700963e-01 4.0791868e-01
+1 7.5531593e-01 1 1 -5.0812180e-02 9.1214758e-01 -1.3380282e+00 1.4205462e+00 2.0425002e-01 7.9575451e-01 5.1440380e-01 9.3407781e-01
+1 7.0492476e-01 1 1 5.1290009e-01 -5.0777489e-01 -7.1912006e-01 -9.8457039e-01 -9.3074921e-01 4.8616833e-01 -7.8331835e-02 5.0731665e-01
+1 6.1029583e-01 1 1 -2.1837229e-01 1.5347362e+00 -5.4387914e-01 -9.0605914e-01 -1.1121889e+00 -2.5136521e-01 -1.9583260e-01 1.8842553e-01
+1 5.7724533e-01 1 1 -8.0283349e-01 -1.3067152e+00 1.0579047e+00 -8.3635106e-01 -8.1715813e-02 7.4707060e-01 1.0306081e+00 1.4241954e-01
+1 8.5138966e-01 1 1 -8.2091099e-02 9.1226509e-01 -1.2103465e+00 -1.0667322e+00 -5.2168669e-01 -9.3020875e-01 -1.3116796e+00 -2.4845625e-01
+1 9.4581543e-01 1 1 -5.4592144e-01 1.4672955e+00 -4.8173614e-01 5.0046134e-01 1.9683214e-01 -1.4534479e+00 -8.4337898e-01 -6.2762054e-01
+1 6.8806947e-01 1 1 1.2905213e+00 -6.6757134e-01 -6.5507010e-01 1.2101799e+00 6.0750645e-02 9.2501261e-01 1.9548968e-01 1.0496580e+00
+1 6.3223163e-01 1 1 2.3506714e-01 -1.2441139e+00 1.5191470e+00 8.2205261e-01 1.8481257e-02 -1.0550294e+00 -5.1082503e-01 1.5592513e+00
+1 7.5624221e-01 1 1 -1.3501303e+00 6.1836055e-01 5.8023869e-01 -4.8620368e-01 -4.0318700e-01 -7.3076142e-01 5.3643668e-01 -8.3011823e-01
+1 6.1940040e-01 1 1 8.3923791e-02 3.9731324e-01 5.6810677e-01 -3.4283521e-01 5.1398950e-02 -1.4214856e+00 -4.7971674e-01 1.5953959e-02
+1 7.7893614e-01 1 1 -6.7941100e-02 -1.3823511e+00 8.7045557e-01 -3.5036931e-01 -7.5824745e-02 9.0377280e-01 -1.2725019e+00 1.1028164e+00
+1 1.3389810e+00 1 1 -1.4879290e+00 -1.0965348e+00 -6.5014427e-01 -1.3123276e+00 1.1001327e+00 1.0893746e-01 1.0227386e+00 -3.6101631e-01
+1 6.1511278e-01 1 1 -5.4464075e-01 -8.7753607e-01 -5.1551195e-01 8.3223508e-01 -1.4832685e+00 -6.3661037e-01 1.5149278e+00 -1.1856880e+00
+1 3.7163931e-01 1 1 8.2397346e-01 1.0287245e+00 3.0323185e-01 1.0044702e+00 -7.5572778e-01 7.5409694e-01 -1.2177121e+00 -7.3568013e-01
+1 5.8567005e-01 1 1 3.8158690e-01 -1.5531342e+00 7.5435706e-01 -7.8800472e-01 -5.7713374e-02 9.2255856e-01 1.3892993e+00 7.3269205e-01
+1 5.4148760e-01 1 1 1.3404756e+00 -3.3474229e-02 -9.8888825e-01 9.5934353e-01 7.6345030e-01 -1.4596819e+00 -1.5043653e+00 -6.8787685e-01
+1 1.1955001e+00 1 1 1.0123922e+00 -2.5628032e-01 -1.2195989e+00 1.0331453e+00 1.0447711e+00 -1.7611404e-01 -3.3044021e-01 -8.5257314e-02
+1 6.2177655e-01 1 1 4.0963878e-01 -1.7988432e-01 1.0940724e+00 4.9034082e-01 1.1065847e+00 -5.6832349e-01 6.2716778e-01 -3.5343098e-01
+1 9.6760110e-01 1 1 1.5694737e+00 -1.1036774e+00 3.3239201e-01 7.6060449e-01 1.3974329e-01 -1.3712202e+00 7.6548464e-01 6.3724253e-01
+1 5.3955127e-01 1 1 1.3330419e+00 -1.5424393e+00 7.6081556e-01 3.3908050e-01 -1.2459035e+00 6.2521407e-01 6.7837523e-01 4.4584745e-01
+1 6.1705834e-01 1 1 -1.4029726e+00 6.4482402e-01 7.4498750e-01 7.6968145e-02 -1.1847091e+00 -6.5451132e-01 6.1274279e-01 6.5962852e-01
+1 9.3753600e-01 1 1 1.0338958e+00 -9.3740544e-01 -1.3834047e+00 -7.3255345e-01 7.9655151e-03 1.4857696e+00 2.2726925e-01 -3.0387352e-01
+1 7.8775454e-01 1 1 5.3856444e-01 1.1400444e-01 4.3724489e-02 -1.2429381e-01 -1.2120724e+00 -1.1896255e+00 -4.6238039e-01 1.0273510e+00
+1 4.9792484e-01 1 1 7.2403008e-01 -2.9896714e-01 -2.5519085e-01 1.5307322e-01 -1.2133420e+00 -9.3961813e-01 1.0729872e+00 4.9585404e-01
+1 8.2759556e-01 1 1 1.3851475e+00 -1.3340726e+00 -7.1856700e-01 -2.6285500e-01 -5.6145543e-01 6.2443665e-01 9.5479568e-01 -8.2640660e-01
+1 1.0072680e+00 1 1 9.7164301e-01 -2.1219321e-01 -6.7339271e-01 -7.2474041e-01 9.6287151e-01 -1.1542555e+00 -4.3130958e-03 -4.3454311e-01
+1 6.7603399e-01 1 1 4.0540449e-01 -6.2360631e-01 1.4470949e+00 -7.5736883e-01 6.3762950e-01 -2.3676393e-01 -2.3356964e-01 8.3687225e-01
+1 4.2680670e-01 1 1 -4.8123411e-01 -5.9822254e-01 -8.8592533e-01 6.3556188e-01 6.6638691e-01 1.1065324e+00 1.3858470e+00 4.0163430e-01
+1 3.8488232e-01 1 1 1.4993315e+00 -1.2298189e+00 1.4021951e+00 4.7347170e-01 1.8703396e-01 -7.3794828e-01 1.6231202e-01 -1.0149161e+00
+1 5.8542566e-01 1 1 5.4908383e-01 -1.0285434e+00 -1.5358528e+00 -1.5315811e-02 -1.2545014e+00 3.1099650e-01 1.0757674e+00 1.1539726e+00
+1 3.1339758e-01 1 1 -1.5472091e+00 1.4554203e+00 1.3881731e+00 1.9776364e-01 -1.1771175e+00 -6.9206466e-01 5.5720656e-01 -1.3754434e+00
+1 6.2585931e-01 1 1 -9.8031501e-01 8.0829885e-01 1.5580566e+00 8.5065519e-03 -1.2050943e+00 -1.3547294e+00 -1.1707254e-01 -1.2388273e+00
+1 3.7810435e-01 1 1 1.4990741e+00 8.3207904e-01 1.0831442e+00 -1.5436441e+00 -1.7254453e-01 1.3261023e+00 -1.0012394e+00 1.5063364e+00
+1 9.0682131e-01 1 1 -6.3439539e-01 1.5234869e+00 -1.1250233e+00 -7.5360091e-01 -2.6583144e-01 1.3436808e+00 -1.4596164e+00 -1.0998712e+00
+1 7.1190838e-01 1 1 2.8214380e-01 1.2646035e+00 9.7938797e-01 1.1310106e+00 -4.8433352e-01 1.4753490e+00 9.2475613e-01 -4.0356646e-01
+1 6.4749937e-01 1 1 1.3274633e+00 1.3172130e+00 -1.3719126e+00 -8.8158966e-01 -3.2694415e-01 -3.9994526e-01 9.1741837e-01 -4.3032434e-02
+1 2.6781406e-01 1 1 -9.1604490e-01 -4.0467208e-01 1.5545063e+00 -1.1264342e+00 -3.0471919e-01 1.1283489e+00 1.1379792e-01 -6.7980564e-01
+1 5.1872017e-01 1 1 9.7902775e-01 2.2452648e-01 1.1031633e+00 -7.4193735e-01 -6.1936437e-01 1.5073712e+00 -6.2826022e-01 4.7901411e-01
+1 7.4859413e-01 1 1 -1.1428494e+00 5.6378214e-01 -8.1443835e-01 -7.5986384e-01 -1.5605651e+00 5.8394229e-01 -2.7661576e-01 -1.1118356e+00
+1 9.5214761e-01 1 1 -1.7203287e-01 4.4292930e-01 -3.4607320e-01 -4.5748478e-01 7.3878099e-01 -1.7448138e-02 4.7608895e-01 -4.2715059e-01
+1 1.1875052e+00 1 1 -1.0911892e+00 -1.2618531e+00 -1.3642530e+00 -1.4694233e+00 1.1179987e+00 -1.0827446e+00 -9.4975385e-03 -5.8067572e-01
+1 4.8414278e-01 1 1 1.0014540e+00 9.2673476e-01 1.4851968e+00 -5.3757695e-01 3.3852411e-01 1.5575296e+00 5.9609623e-01 1.5115702e+00
+1 1.0961281e+00 1 1 -1.2158797e+00 -3.8521135e-01 -1.3921383e+00 1.6463126e-01 1.5042275e-01 -1.4919700e+00 5.0388909e-02 -1.0987826e+00
+1 4.5987221e-01 1 1 7.7061769e-01 5.7532407e-01 9.1337432e-01 -7.8561618e-01 -8.2692711e-01 6.5213726e-01 -1.3436217e+00 -9.5687856e-01
+1 8.0301292e-01 1 1 -1.0150412e+00 -3.5053766e-01 1.2604917e+00 2.6278157e-01 2.4201250e-01 -5.4579377e-01 -4.8175308e-01 -4.4521939e-01
+1 7.6205759e-01 1 1 -9.4991041e-01 -1.0001881e+00 1.3242870e+00 -5.0939273e-01 -8.5844017e-01 2.9460997e-01 -9.3976603e-01 4.7137318e-01
+1 6.9359371e-01 1 1 4.2954031e-01 5.0053335e-01 -8.9151004e-01 -5.2357806e-01 1.5311846e+00 3.5977479e-01 1.2802323e+00 -7.2761239e-01
+1 1.0068066e+00 1 1 -9.5945964e-02 -7.2110472e-01 -1.3538432e+00 -1.7545131e-01 -1.3067347e+00 -8.3095912e-01 9.6352696e-02 1.2387408e+00
+1 6.8338009e-01 1 1 -9.2679078e-01 6.5750022e-01 5.1320205e-01 1.1453226e+00 5.8417264e-01 -1.5506070e+00 1.4795534e+00 1.8268989e-01
+1 1.1765237e+00 1 1 -5.5628417e-01 -1.5166930e+00 -1.4265496e+00 8.9899975e-01 7.1254359e-01 -1.5404857e+00 1.1474121e+00 1.1330215e+00
+1 4.7696187e-01 1 1 -8.8325618e-02 -1.7713526e-01 6.1645970e-01 1.5697009e+00 -3.1145521e-02 -1.0786659e+00 1.4596913e+00 1.4992766e+00
+1 1.0236980e+00 1 1 1.4846605e+00 1.1175763e+00 -1.3441862e-01 -1.1315200e+00 1.1832050e+00 9.9338188e-01 3.3393968e-01 -3.7320903e-01
+1 7.6703021e-01 1 1 -9.8169067e-01 -4.7683045e-01 -3.6864119e-01 -1.3956253e+00 -1.5452159e-01 1.3458286e+00 -1.5017910e+00 1.2363330e+00
+1 7.0997515e-01 1 1 3.6951507e-01 1.1354285e-01 -5.3179170e-01 -1.1432756e+00 1.0527049e+00 -1.2501204e-01 -1.0460369e+00 5.5516712e-01
+1 8.2166155e-01 1 1 -4.8892014e-01 1.3679143e+00 8.0292924e-03 -1.0531584e+00 -6.3892069e-01 6.4820355e-01 -3.8897631e-01 1.6358754e-01
+1 6.4738019e-01 1 1 1.1255293e+00 3.6049027e-01 -1.4016599e-01 -6.9950332e-01 -3.7642485e-01 -6.8627204e-01 1.2954160e-01 5.2220529e-01
+1 8.3716642e-01 1 1 1.2410550e+00 -1.3723381e+00 4.2472174e-01 -7.1259000e-01 5.9511852e-01 -1.3874853e+00 8.1938625e-02 -9.0549872e-01
+1 5.3885059e-01 1 1 1.3773107e+00 6.8683006e-01 5.9976020e-01 -7.4900837e-01 -6.7402950e-01 5.7617921e-01 1.1248819e+00 -8.4211693e-01
+1 7.6784161e-01 1 1 1.2060355e+00 1.3414455e+00 -1.2012104e+00 -2.2193355e-01 1.6933184e-01 1.4553803e+00 -2.1454779e-01 -5.8427527e-01
+1 1.0946678e+00 1 1 2.8346152e-01 -1.5353896e+00 -8.6882004e-01 -9.6662878e-01 -3.2271713e-01 1.3630433e-01 6.4360145e-01 7.0420331e-01
+1 5.1159163e-01 1 1 1.4832683e+00 -2.5109685e-01 -1.3570203e-01 -9.5432883e-01 -1.5178765e+00 6.4582111e-01 5.0614189e-01 1.1655312e+00
+1 8.8450944e-01 1 1 7.5255602e-01 -1.0257778e+00 5.2223464e-02 1.5674401e+00 -1.2173729e+00 1.1272046e-01 -7.0623095e-01 1.2529033e+00
+1 7.7022149e-01 1 1 1.5706728e-01 8.1316330e-01 1.2154080e+00 -1.4299350e+00 8.0622865e-01 1.1240683e-01 -6.8652567e-01 -5.4936699e-01
+1 3.8660848e-01 1 1 8.9189708e-01 9.0750324e-01 7.2702961e-01 2.6670678e-01 5.9579189e-01 1.1244269e+00 6.3288304e-01 -7.0137026e-02
+1 3.9293422e-01 1 1 -1.5658577e+00 -2.5318216e-02 1.5327768e+00 -5.1181564e-01 1.2185381e+00 1.5634681e+00 -5.6742122e-01 -6.9575129e-01
+1 2.1101425e-01 1 1 -2.4884700e-01 -1.4082533e+00 3.1933541e-01 -4.0481681e-01 -7.2200770e-02 9.2696851e-01 1.2268748e+00 -4.8410977e-01
+1 7.8885082e-01 1 1 -9.1174267e-01 2.4645736e-01 1.2300589e+00 9.3347980e-01 -8.2358402e-01 4.0174907e-01 -1.3296326e+00 2.9201149e-01
+1 1.0990194e+00 1 1 1.0299017e+00 -1.5519006e+00 -1.2218880e+00 -1.1863806e-01 -1.1932285e-01 9.1395482e-01 -9.8713582e-01 6.6943570e-01
+1 9.6283564e-01 1 1 -6.1714655e-01 -1.2909697e+00 3.1937745e-01 9.6137800e-01 -1.1230932e+00 -1.5494312e+00 -4.0996514e-02 1.1625902e+00
+1 8.8782331e-01 1 1 1.1568228e+00 -1.4892552e+00 -1.2049696e+00 6.6896227e-01 -1.1391947e+00 -6.2923285e-01 -1.0196227e+00 -1.0524839e+00
+1 1.2272887e+00 1 1 -5.9554846e-01 -8.4327320e-01 -1.2174336e+00 -5.1117949e-01 1.5619297e+00 -9.1571636e-01 5.8945439e-01 1.2120948e+00
+1 5.3218669e-01 1 1 -2.6876085e-01 -1.1682471e+00 -2.1424116e-01 8.6220164e-01 2.0418531e-01 2.1757647e-01 1.5183488e+00 -1.5502460e+00
+1 8.2269424e-01 1 1 5.4665226e-01 2.2551734e-01 -4.8604411e-01 -1.1440182e+00 1.1232750e+00 -6.0709016e-03 -2.6945597e-01 1.3844111e+00
+1 9.5618570e-01 1 1 1.5675882e+00 1.5091909e+00 -8.0242450e-01 -9.6698799e-01 1.0524221e+00 -1.5026777e+00 1.4300401e+00 1.1615470e+00
+1 8.3735176e-01 1 1 1.0594518e+00 -2.4805846e-01 5.0875715e-01 -7.0832495e-01 8.9149727e-01 -2.4083239e-01 1.4998390e+00 2.6441032e-01
+1 9.9553052e-01 1 1 -3.4139205e-01 -2.2508615e-01 -7.3380218e-01 -1.3229460e+00 1.1393193e+00 -1.2985804e+00 -3.4583127e-01 -1.4093485e+00
+1 8.9313767e-01 1 1 -1.2279220e+00 -5.4540300e-01 8.7948571e-01 1.4401704e+00 5.3231512e-01 -5.9639529e-01 -4.3967763e-01 6.8799575e-01
+1 7.2054327e-01 1 1 -5.6218908e-01 5.7907632e-01 3.2282050e-01 -1.0277633e+00 -6.3570542e-01 1.2065941e+00 -6.3603873e-01 -1.0579317e+00
+1 8.3264358e-01 1 1 1.1989012e+00 -1.1832016e-01 1.1364448e-01 -1.1408926e+00 2.5564318e-01 2.4637148e-01 9.3693998e-01 7.5663775e-01
+1 5.1770150e-01 1 1 -2.4198277e-01 2.1177304e-02 -6.5502769e-02 1.2992767e+00 -1.1038289e+00 1.4629672e-01 1.4878683e+00 -3.5645525e-01
+1 9.3104515e-01 1 1 1.3580288e+00 9.2697508e-01 -1.3476142e+00 -2.6695392e-01 -9.4737421e-01 -1.0580299e+00 -4.7548484e-01 7.3842579e-02
+1 4.8501222e-01 1 1 7.1919247e-01 5.1219506e-01 1.5309779e+00 -5.0016741e-01 -9.2677585e-01 -8.9373319e-01 7.3793197e-01 1.4311873e-01
+1 5.5546447e-01 1 1 -1.3807669e+00 4.9846141e-01 1.5013359e+00 5.8820226e-01 -3.0539573e-01 -1.0191853e+00 -5.8521825e-01 -1.0635161e+00
+1 6.3714065e-01 1 1 3.9610025e-01 -9.8674906e-01 -3.2029370e-01 -6.7677729e-01 5.7640464e-01 -1.4845184e+00 5.6341279e-01 1.1476260e+00
+1 4.2979098e-01 1 1 2.2207073e-01 1.7624825e-01 1.5135605e+00 1.1111109e+00 -1.0389568e+00 2.2855403e-01 5.1856802e-01 -1.2295491e+00
+1 5.6176459e-01 1 1 1.3075600e-01 -3.1746144e-01 9.3537866e-01 8.1377732e-01 -7.7451474e-01 -8.6018219e-01 7.9471982e-01 3.6545198e-01
+1 8.3370008e-01 1 1 -1.4987565e+00 -1.1500688e+00 3.7958136e-01 -1.3389533e+00 1.4907198e+00 5.2727481e-01 -1.1960224e+00 3.3777036e-01
+1 8.6061090e-01 1 1 -3.0986220e-01 1.0131121e+00 -9.5084383e-01 -5.6043770e-01 3.2644031e-01 -5.2512282e-01 1.5034931e+00 4.8598897e-02
+1 7.6659956e-01 1 1 9.0661282e-01 -5.6576931e-02 4.4962426e-01 -7.8161978e-01 1.2614467e+00 -1.0055087e+00 1.3782226e+00 -1.2425720e-02
+1 2.9385951e-01 1 1 7.1731167e-01 1.0140926e+00 1.3046170e+00 1.4568241e+00 -1.4746291e+00 -9.5860461e-01 8.2513348e-01 -1.4939557e+00
+1 4.0881712e-01 1 1 1.5661853e+00 7.1357379e-01 1.5229565e+00 -7.3040534e-01 -6.6172105e-02 -1.1805625e+00 1.0284775e+00 -1.3047708e+00
+1 8.2535850e-01 1 1 -5.2831554e-01 -1.5661041e+00 -1.3668893e+00 1.4216094e+00 -3.0777509e-02 5.8464228e-01 5.7886034e-01 -9.6575578e-01
+1 7.3290561e-01 1 1 -1.2584658e+00 -1.2490528e+00 1.1586869e+00 1.1766540e+00 1.0851919e+00 -8.1896037e-01 -6.0669284e-01 1.1518488e+00
+1 4.6909892e-01 1 1 1.3094592e+00 -7.0762108e-01 -6.8265345e-01 -3.0244089e-01 -1.2666916e+00 -9.4954179e-01 9.2315901e-01 6.2881262e-01
+1 1.0963826e+00 1 1 1.2242363e+00 1.0822415e+00 -2.6016434e-01 -2.7106966e-02 1.2878574e+00 3.4185383e-01 -7.9256808e-01 1.3596416e-01
+1 5.5932356e-01 1 1 1.4494789e+00 -5.8784461e-01 5.1486678e-01 -5.5838484e-02 -5.5351127e-01 -4.3568937e-01 -3.3878904e-01 1.2117791e+00
+1 3.6965133e-01 1 1 1.4823193e+00 4.0458798e-01 1.4197619e+00 8.5880740e-01 -6.0813803e-01 4.2122486e-01 -1.4614607e+00 -5.7466427e-01
+1 6.1689631e-01 1 1 5.1149864e-01 1.5036181e+00 1.5415950e+00 1.4992407e+00 -1.3749344e+00 1.5179275e+00 1.3429532e+00 -1.1265097e+00
+1 2.4786103e-01 1 1 1.3601878e+00 3.3839849e-01 8.7336194e-01 -9.7635921e-01 1.0339128e+00 -1.0669848e+00 -1.3284472e+00 1.1311000e+00
+1 6.9545745e-01 1 1 -6.9255968e-01 1.1807808e+00 1.0732624e+00 -1.1307972e+00 8.2333413e-01 -6.0207661e-01 8.6737220e-02 6.2042172e-01
+1 6.2521094e-01 1 1 -2.4976533e-01 -5.8036408e-02 -7.0443497e-01 1.3275001e+00 -9.3893343e-01 -3.1692762e-02 9.3461232e-02 4.8187238e-01
+1 4.4213635e-01 1 1 -6.3806568e-01 -1.5241938e+00 1.2242116e+00 -2.9629832e-01 -4.3433213e-01 1.4105021e+00 6.5925928e-03 -1.9678441e-01
+1 5.1024254e-01 1 1 1.4275015e+00 -5.7845474e-01 1.0347163e+00 -4.6143038e-01 1.2412794e+00 -1.4855148e-01 8.4596402e-01 7.4153178e-01
+1 3.2290025e-01 1 1 -3.2475255e-01 1.1404495e+00 -1.3795088e+00 1.3319442e+00 -1.1335244e+00 8.6138155e-01 -7.3108297e-01 2.2664814e-01
+1 8.8906753e-01 1 1 -1.1697243e+00 6.7733050e-01 -4.5039454e-01 -1.0038472e+00 -5.2742793e-01 7.8076734e-01 -5.4255636e-01 -1.4765434e+00
+1 3.8088453e-01 1 1 5.2984251e-01 -1.2381411e+00 1.4573403e+00 -1.3080024e+00 1.0932649e+00 -7.5884256e-02 1.2986833e+00 -8.2484441e-01
+1 1.0675354e+00 1 1 -1.3520752e+00 4.7176146e-01 -1.4796163e+00 1.2692766e+00 -6.7252205e-01 9.9922841e-02 -8.1536040e-01 6.8829947e-01
+1 9.0124706e-01 1 1 -1.1880077e+00 -4.8504274e-01 9.3614139e-01 1.3181173e+00 3.7221734e-01 -1.3488764e+00 -1.3504455e-01 9.0498840e-01
+1 4.0095092e-01 1 1 1.1182043e+00 3.1959456e-01 6.3229725e-01 -9.1310827e-01 9.4586075e-01 -8.3271846e-01 -1.4639176e+00 -1.4515223e+00
+1 6.5598166e-01 1 1 6.5318777e-01 -6.9766470e-01 -9.8809686e-01 6.9453884e-02 6.2276294e-01 2.9613474e-01 8.9052773e-01 -1.2683645e+00
+1 7.3244365e-01 1 1 1.4020869e+00 -1.2268987e+00 -4.8519387e-01 -1.3610347e+00 -1.0100630e+00 8.5387185e-01 5.5219618e-01 1.4454254e+00
+1 7.1388785e-01 1 1 -2.1197204e-01 9.2755710e-01 9.2112613e-01 -9.7360427e-01 1.0381325e+00 2.2890004e-01 4.9649172e-01 -6.7173292e-01
+1 9.2509329e-01 1 1 -4.7973434e-02 8.6948473e-01 -4.0178164e-01 1.1891990e+00 -5.1293158e-01 -1.3281107e+00 4.6618261e-01 1.0688563e+00
+1 9.4968518e-01 1 1 1.0998096e+00 -1.2591009e+00 -1.4613411e+00 5.5001245e-02 -3.1079481e-01 -5.4098393e-01 -9.6715489e-04 6.4083383e-01
+1 9.7236719e-01 1 1 -6.3091809e-01 5.9528898e-02 2.1181198e-01 7.7769248e-01 9.4019518e-01 -5.4780839e-01 -5.4700900e-01 1.1145176e+00
+1 3.4879355e-01 1 1 -9.6509942e-01 1.4757237e+00 4.9952269e-01 -1.4895610e+00 -3.5064532e-01 9.9239299e-01 -1.2802040e+00 1.5222584e+00
+1 4.1770684e-01 1 1 -3.8307694e-01 -3.8603716e-01 1.1422660e+00 3.0051004e-01 3.3185565e-01 4.3361272e-01 3.7958298e-01 -5.3326610e-01
+1 7.2821608e-01 1 1 -1.2507481e+00 -7.3776676e-01 -2.0817214e-01 -1.0087867e+00 1.1709682e+00 -7.6601560e-01 -9.2360114e-01 3.6057009e-01
+1 8.0475226e-01 1 1 -9.2626287e-01 2.2019158e-01 9.8510043e-01 4.9669189e-01 1.5254558e+00 -1.7749562e-01 -3.5503418e-01 -3.0734030e-02
+1 3.6102859e-01 1 1 -1.1084774e+00 -3.6248384e-02 3.8964038e-01 6.8884072e-01 -2.0253957e-01 1.3440579e+00 -1.1750515e+00 -1.3256427e+00
+1 1.2238194e+00 1 1 -5.3516335e-01 2.4238704e-01 -1.5347695e+00 5.7712938e-01 1.4038200e+00 1.5305145e+00 -1.0394956e+00 9.8648985e-02
+1 7.8549550e-01 1 1 -1.1072628e-01 -8.4672034e-01 7.4602720e-01 -1.4246738e+00 6.4207842e-01 -2.8308964e-03 -4.0525076e-01 -7.6743230e-01
+1 9.0122229e-01 1 1 -1.1536739e+00 5.8598553e-01 3.8294816e-01 7.2696255e-01 4.1205324e-02 -4.5498656e-01 -7.6655059e-02 1.1447423e+00
+1 1.2001702e+00 1 1 1.1209232e-01 -2.3418133e-01 -9.1364421e-01 4.0574575e-01 1.3874932e+00 -3.2257971e-01 -2.8858851e-01 5.7015754e-01
+1 8.7798203e-01 1 1 -1.0200455e+00 5.2990300e-01 4.8658927e-01 -1.0288254e+00 -4.4434230e-01 7.9170361e-01 3.1193944e-01 7.8012550e-01
+1 4.1156411e-01 1 1 -2.3398937e-01 -3.3541640e-01 5.4013970e-01 -1.4205930e-01 -4.9524668e-01 1.5176707e+00 -5.5196259e-01 -1.4383996e+00
+1 8.9151205e-01 1 1 6.1460198e-01 -1.3262317e+00 -1.0747869e+00 1.9835574e-02 -1.5319958e+00 9.0152908e-01 2.8793621e-01 -6.2729614e-01
+1 3.5247830e-01 1 1 5.8805002e-02 -3.7572524e-01 2.1395224e-01 3.6766845e-01 2.4013119e-01 9.7824629e-02 1.2912160e+00 2.1867393e-01
+1 6.4103640e-01 1 1 -1.2660143e+00 -2.1293392e-01 -1.2283233e+00 -1.0912836e-01 -1.0617108e+00 1.0855830e+00 -6.5552475e-01 -4.1058088e-01
+1 9.2438903e-01 1 1 1.0497215e-01 -5.0643140e-01 -1.0247902e+00 5.6976175e-01 7.3440652e-02 -9.7632430e-01 1.6095483e-01 1.4462529e+00
+1 1.0481709e+00 1 1 -1.3082227e+00 -1.0181189e+00 -1.4371864e+00 4.1127566e-01 -3.2887468e-01 -5.4404670e-01 2.5657340e-01 6.6973162e-01
+1 3.1761439e-01 1 1 7.0783060e-01 7.3062586e-01 9.1474300e-01 8.0624771e-01 -1.3353512e+00 1.3833459e+00 -1.1775622e+00 -1.4713247e-01
+1 1.0757045e+00 1 1 -7.0254457e-01 -8.5684407e-01 -8.6887236e-01 9.1613936e-01 2.8985859e-01 -1.0332881e+00 7.4510615e-01 -4.2193472e-01
+1 7.8775938e-01 1 1 -1.5614235e+00 8.2490285e-02 -1.0150409e+00 6.0857189e-01 -9.5684325e-01 2.5092017e-01 6.1074532e-01 -8.8220716e-01
+1 8.9123555e-01 1 1 -1.1214256e+00 9.7186291e-01 -9.4509131e-01 -7.5787574e-01 1.4834175e-01 1.1979665e+00 1.2133625e+00 1.0616276e+00
+1 5.9495701e-01 1 1 -1.3864570e+00 9.5964645e-01 -2.5719150e-01 1.5406807e+00 -1.2447420e+00 -2.4351103e-01 9.0611970e-01 -1.4705136e+00
+1 7.9395497e-01 1 1 -9.8973478e-01 -1.5882898e-01 2.1395063e-01 1.2137688e+00 -5.1372299e-01 8.0541404e-01 -1.2873534e+00 -1.2491033e-02
+1 8.3173654e-01 1 1 2.6067354e-01 9.1501327e-01 -1.2553201e+00 1.4506210e+00 -1.0457161e+00 -5.2896050e-01 -4.0073289e-01 5.4991397e-01
+1 7.4127846e-01 1 1 -1.3815803e+00 5.3205663e-01 7.7065712e-01 -1.3141668e+00 -1.2816744e+00 4.6809312e-01 4.5688735e-01 -1.6151204e-01
+1 3.6289703e-01 1 1 -7.0856435e-01 1.3031316e+00 -3.5221777e-01 1.3369793e+00 7.9912407e-01 6.9308982e-01 8.5325432e-01 -1.9674014e-01
+1 5.5573593e-01 1 1 9.3677945e-01 -1.4512620e+00 -9.6344200e-01 -1.2005098e+00 5.6961659e-01 -2.6488315e-01 -7.2509796e-01 1.4855178e+00
+1 1.1724439e+00 1 1 -1.2102397e+00 -3.5636995e-02 -8.0109777e-01 1.4806035e+00 1.1131724e+00 -2.5424206e-01 -4.8343382e-01 8.6103442e-01
+1 4.6951041e-01 1 1 1.3129620e+00 1.0932169e+00 8.1592139e-01 -5.1635304e-02 9.0499961e-01 -4.8031257e-01 -9.1359243e-01 1.2297637e+00
+1 8.3672215e-01 1 1 4.0606545e-01 -1.4795252e+00 1.3879396e-01 -7.5497476e-01 -1.2631839e+00 1.2798202e+00 1.3569784e+00 9.9857847e-02
+1 8.2535239e-01 1 1 1.2027352e+00 -6.7482031e-01 -1.4932798e+00 3.1890608e-02 5.5205390e-01 -5.4674349e-01 -1.2263770e+00 7.0035330e-01
+1 7.4475693e-01 1 1 1.3627450e+00 -5.5545953e-01 6.3035740e-01 -1.2268886e+00 1.2467762e+00 4.0718039e-02 2.7108929e-01 -7.0973021e-01
+1 4.6763762e-01 1 1 1.4444868e+00 1.2051200e+00 9.6641499e-01 1.0973322e+00 1.4511427e-01 -5.1911792e-01 8.8835822e-01 1.9166271e-01
+1 3.6610634e-01 1 1 -7.3839283e-01 6.0387890e-01 5.0273870e-01 -1.4288192e+00 1.0595527e+00 -6.1207317e-01 -1.3533449e+00 1.1427064e+00
+1 8.2073425e-01 1 1 -8.7737145e-01 -1.0931669e+00 -1.3549404e+00 1.6953761e-01 1.3551292e+00 -1.5394344e+00 -5.3722750e-01 9.1117935e-01
+1 3.1610588e-01 1 1 6.5403504e-01 -8.2204354e-01 9.2167058e-01 -5.9389668e-03 -8.9057184e-01 8.8359832e-01 -2.4522215e-01 -1.0727941e+00
+1 3.8535599e-01 1 1 -6.5744341e-02 6.3879225e-01 -6.7599125e-01 7.1474930e-01 -1.2934530e+00 3.2848265e-01 3.2091017e-01 -8.4951716e-01
+1 1.1679363e+00 1 1 8.7547616e-01 1.3591819e+00 -1.3859432e+00 -6.5878522e-01 7.5625938e-01 1.0295431e+00 -5.7743744e-01 7.0367323e-01
+1 6.2240708e-01 1 1 -1.0921140e+00 1.2508426e+00 1.3614632e+00 -1.2307613e+00 -4.3242160e-01 -3.6091438e-01 -6.1129507e-01 -1.4603065e+00
+1 5.2122265e-01 1 1 1.1656439e+00 -6.2691876e-01 -1.2483101e+00 -1.1593761e+00 -1.2059612e+00 5.2750341e-01 -1.0282080e+00 -1.2502208e+00
+1 8.0944887e-01 1 1 5.5380907e-03 2.7824058e-01 -7.9155401e-01 -1.4760959e+00 9.6586655e-01 1.7538877e-01 8.0960290e-01 -1.4895204e+00
+1 5.4831211e-01 1 1 -1.1690891e+00 -1.4420616e+00 9.9662288e-01 4.1343567e-01 7.0984967e-01 9.4518908e-01 7.5823903e-01 9.8307708e-01
+1 5.6033618e-01 1 1 -1.3593611e+00 6.5884827e-01 -7.3120600e-01 -5.8959648e-01 -1.3254840e+00 -1.2411359e+00 1.4235557e+00 9.4068661e-01
+1 8.0892487e-01 1 1 -1.1204522e+00 -8.5116943e-01 5.3127196e-01 -7.6474497e-01 -3.7539762e-01 4.0347524e-01 -6.6856749e-01 -1.5159712e+00
+1 5.4098165e-01 1 1 -7.3312035e-01 1.2083642e+00 6.8153298e-01 -8.1313003e-01 -9.8970307e-01 -1.4901064e+00 8.6308871e-01 -6.1079743e-01
+1 7.8366957e-01 1 1 -2.2737576e-01 -1.4198997e+00 2.7794124e-01 -3.4841344e-01 7.9357790e-01 5.5797573e-01 1.1985906e+00 1.0523826e+00
+1 4.4963751e-01 1 1 -1.3277446e+00 -7.1695865e-01 -1.8984848e-01 1.4395917e-01 -1.5385964e+00 2.4397484e-01 8.1931020e-01 2.2771490e-01
+1 1.6891035e-01 1 1 -6.7005078e-01 1.2254485e+00 1.0748062e+00 4.9537365e-01 -7.4075544e-01 7.0664523e-01 5.4585979e-01 7.4452635e-01
+1 2.7634075e-01 1 1 1.0662127e+00 -1.6826919e-01 1.0949322e-01 5.2433179e-01 2.5492600e-01 1.3662077e+00 8.1489032e-01 2.9077911e-01
+1 8.7426778e-01 1 1 1.9232186e-01 -6.6696973e-01 -7.2071126e-01 2.7707847e-01 -5.9102030e-01 -4.7842266e-02 -1.4822974e+00 -1.1936885e+00
+1 3.4060933e-01 1 1 -3.4528221e-01 -5.5772369e-01 9.8713338e-01 1.0174561e+00 4.3772838e-01 1.6276024e-01 -1.4241922e-01 -1.1226376e-01
+1 9.2097968e-01 1 1 -6.3651113e-01 8.5035097e-01 -1.3797878e-04 6.9609133e-01 -7.0916277e-01 -8.1576785e-01 2.5376710e-01 1.2801583e+00
+1 7.5489475e-01 1 1 -7.1954488e-01 7.4376241e-01 8.2258337e-01 -8.4134787e-02 3.0384195e-01 -6.9995324e-01 -1.2191262e+00 -1.1468777e+00
+1 5.5921778e-01 1 1 -1.4007370e+00 1.7704961e-02 -9.9064844e-01 -3.3666277e-01 -1.5579934e+00 1.1504240e+00 -3.8756862e-01 1.2385314e+00
+1 3.5070021e-01 1 1 9.0859854e-01 -8.8402353e-01 6.1268556e-01 -2.8281748e-01 -2.0040062e-02 -1.3260180e+00 -1.3442768e+00 -1.9565478e-01
+1 8.2076095e-01 1 1 -4.6624193e-01 -1.1918561e+00 -7.3455994e-01 -8.3724492e-02 -6.6290817e-01 7.4537176e-02 1.0742931e+00 8.7764657e-01
+1 6.9125767e-01 1 1 -9.9604641e-01 -7.3121586e-01 7.1026816e-01 2.7596979e-01 -1.4100341e+00 -7.4914510e-01 9.1139470e-01 8.2844990e-01
+1 4.1621970e-01 1 1 9.9528535e-01 3.6545545e-01 -5.7508895e-01 1.2335539e+00 -1.4102689e+00 6.2170881e-01 -5.9501849e-01 2.1886717e-01
+1 6.4537097e-01 1 1 -1.2199226e+00 3.9614053e-01 1.1605363e+00 9.7021320e-01 9.2675883e-01 1.2282011e-01 -7.8635979e-01 -3.0454016e-01
+1 6.3225569e-01 1 1 -1.2053490e+00 8.9905647e-01 -1.0145247e+00 1.5073159e+00 1.9322909e-02 2.1114653e-01 3.3124911e-01 -7.5196764e-01
+1 7.1573156e-01 1 1 -1.3115700e+00 -6.1864349e-01 1.4490361e+00 -3.4444822e-01 1.1760856e+00 -1.2599295e+00 4.0162052e-01 3.0715241e-01
+1 8.5040561e-01 1 1 9.9904307e-01 1.1305722e+00 3.2291520e-01 8.1399793e-01 -4.3106901e-01 -1.3004253e+00 -1.2465035e+00 6.7384499e-01
+1 8.2550420e-01 1 1 -8.9584708e-01 1.1752704e+00 -1.4363162e+00 -7.7286031e-01 -4.6416790e-01 -1.8729548e-01 1.2971459e+00 -1.2875870e-01
+1 1.0917286e+00 1 1 1.1517478e+00 -1.5654596e+00 -1.6861719e-01 1.0224180e+00 -6.9529145e-01 6.5344820e-04 -1.5216210e+00 5.0978647e-01
+1 1.1683530e+00 1 1 -1.0689626e+00 1.5885071e-01 -2.3257824e-01 -7.3207358e-01 9.6119508e-01 1.5577260e+00 -1.3192287e+00 8.5798114e-01
+1 8.7855723e-01 1 1 7.1461702e-01 -5.4979405e-01 -8.0121506e-01 -1.4838836e+00 7.3626176e-01 -1.3328208e+00 1.0834491e+00 1.7879827e-01
+1 5.4991783e-01 1 1 2.5955324e-01 -9.6463799e-01 -1.1553625e+00 1.4721654e+00 -3.8199176e-01 -1.1639952e+00 8.5867301e-01 -1.4417230e+00
+1 8.3521485e-01 1 1 -1.3608775e+00 1.0890526e+00 6.3306573e-03 -4.9972361e-01 1.2798262e+00 -5.7066452e-01 -7.5932081e-01 6.5647641e-02
+1 5.9740952e-01 1 1 -1.4736888e+00 7.8857319e-01 -4.1479298e-01 -1.3774882e+00 -4.4625534e-01 1.2373936e-01 -7.5544569e-01 6.4087374e-01
+1 8.5026769e-01 1 1 2.9107386e-02 -8.2973192e-01 -2.3146617e-01 -1.0479107e+00 -1.2318150e+00 -4.6892962e-02 1.5417824e+00 -1.3562361e+00
+1 1.0018395e+00 1 1 -8.8061311e-01 2.2547833e-01 -9.6019661e-01 -4.6658140e-01 -1.9756077e-02 4.0974316e-01 8.7992259e-01 1.1358793e+00
+1 5.0072818e-01 1 1 -4.2153806e-01 8.5349771e-01 3.3697616e-01 -4.1828658e-01 9.6842807e-01 1.8213320e-01 1.3823758e+00 -7.3555083e-01
+1 9.2902098e-01 1 1 -4.9875248e-01 2.2401547e-01 -7.3323492e-01 7.4187492e-01 -2.2091012e-01 1.2014357e+00 1.5118137e+00 -2.3570608e-01
+1 5.8437731e-01 1 1 -7.6378624e-01 1.3999583e+00 9.8866530e-01 -2.8939765e-01 5.2606787e-01 1.5140840e+00 -1.4900528e-01 3.6199341e-02
+1 8.4816414e-01 1 1 -4.0780514e-01 -1.4304466e+00 6.1414163e-01 -7.2095493e-01 1.1809427e+00 3.1011209e-01 -4.8242708e-01 -1.0666505e+00
+1 6.2876769e-01 1 1 9.7418893e-01 1.0921383e+00 -1.3951546e+00 3.3323787e-02 -4.7811397e-01 1.5169264e-01 2.9878483e-01 -1.2669737e+00
+1 6.5671311e-01 1 1 -7.8750472e-01 -7.5788873e-01 4.8476175e-01 8.6939249e-01 5.3258805e-01 -1.4750027e+00 1.4115021e+00 -3.1210546e-01
+1 5.6321213e-01 1 1 -6.1925525e-02 1.3223458e+00 1.2409920e+00 3.3219100e-01 8.0982487e-01 -6.2254433e-02 9.4949499e-01 9.0326956e-01
+1 8.2798483e-01 1 1 -9.1512930e-01 1.0392259e+00 3.1860768e-01 5.2399518e-01 1.3471736e+00 -1.5989860e-01 -1.1283758e+00 1.0758687e+00
+1 3.3808549e-01 1 1 6.5947093e-01 -9.8493359e-01 1.5653720e+00 9.0275887e-01 4.8875539e-01 -1.3540017e+00 1.1824305e+00 -8.8277530e-01
+1 6.2722750e-01 1 1 1.8895775e-01 -7.2722767e-01 1.5100386e+00 -1.2241141e+00 -7.5302807e-01 9.9135473e-01 -6.0548460e-01 9.3757275e-01
+1 8.1035787e-01 1 1 -3.3729043e-01 1.4215880e+00 1.4329070e+00 6.0488538e-01 1.3340644e+00 -1.3085463e+00 -7.6102386e-01 -4.4350251e-01
+1 1.0782983e+00 1 1 -1.4071806e+00 8.1772909e-01 -5.8097381e-01 1.1471089e-01 7.3471865e-02 1.5522393e+00 -1.1043508e+00 1.0526525e+00
+1 9.8801148e-01 1 1 -5.7527390e-01 -8.9504364e-01 -3.5691017e-01 -9.9187743e-01 1.9571918e-01 7.0064580e-01 -2.9456990e-01 -1.5187759e+00
+1 1.0697371e+00 1 1 1.1936841e+00 -1.0528162e+00 -1.2887753e+00 -1.1932979e+00 2.0480773e-01 1.0646793e+00 3.1371955e-01 -6.2696279e-01
+1 4.9852026e-01 1 1 3.8329857e-02 -1.2327602e+00 8.3481032e-01 1.7028478e-01 -9.8200152e-01 -4.4639748e-01 1.0920029e+00 -4.6188525e-01
+1 9.1520432e-01 1 1 1.8341874e-01 -1.9718162e-01 3.0426520e-01 -1.4585692e-02 1.4283001e+00 -4.7921932e-01 1.0857061e-01 -2.9911523e-02
+1 9.8336129e-01 1 1 8.1637012e-01 3.4878312e-01 -7.2766518e-01 -9.7496821e-02 5.3091682e-01 8.0444973e-01 -5.1909954e-01 -6.8143645e-02
+1 6.2047144e-01 1 1 1.3974323e+00 -2.1391823e-01 3.5146023e-01 1.2822893e+00 9.9584027e-01 -1.0281350e+00 -3.0310961e-01 1.3910759e+00
+1 5.6420639e-01 1 1 9.8004973e-02 -1.3417138e+00 7.9793713e-01 1.1078896e-01 -1.3181857e+00 -1.1050115e+00 1.3000810e+00 7.9336777e-02
+1 7.8268816e-01 1 1 9.7503453e-01 1.6846481e-01 -5.2970427e-01 -9.3442821e-01 -2.3644468e-01 1.1674054e+00 6.8404028e-01 1.3779183e+00
+1 7.6977296e-01 1 1 8.5807969e-01 8.1301393e-01 5.3383147e-01 -1.1332203e-01 1.8895202e-01 1.3368273e+00 -1.5641455e+00 -1.1474740e+00
+1 7.9361380e-01 1 1 -1.3064979e+00 1.5387362e+00 -2.8303430e-01 -7.9818236e-01 -4.3354957e-01 -6.1348477e-01 2.5390062e-01 6.4203223e-01
+1 7.2700374e-01 1 1 1.4220287e+00 -5.0983198e-02 -5.8628402e-01 -4.5024158e-01 -1.3143170e+00 -1.3138691e-01 1.0249534e+00 -7.3503919e-01
+1 4.9726371e-01 1 1 -1.2006519e+00 7.8019239e-01 1.5005813e+00 8.8651822e-01 -1.1873705e+00 3.1980959e-01 1.0384751e+00 -1.0614080e+00
+1 8.6064191e-01 1 1 -9.0640182e-01 -3.1422075e-01 -4.3657487e-01 -8.6224659e-01 -7.3923253e-01 -2.2532292e-01 -1.0371649e+00 -1.1217546e+00
+1 4.6501991e-01 1 1 -3.1265862e-01 -9.0870825e-02 1.2466646e+00 3.8847617e-01 7.1774806e-01 -1.3831853e+00 1.0665668e+00 -6.3132462e-01
+1 3.4433600e-01 1 1 1.0310374e+00 -4.5192603e-01 1.4113133e+00 8.8941625e-01 -5.2411340e-01 5.9039357e-01 -1.3865560e-01 -1.5145673e+00
+1 7.5833660e-01 1 1 -3.7889627e-01 8.5024017e-01 9.1883882e-01 7.2106182e-01 2.5191237e-01 -1.5464294e+00 6.7712599e-01 9.9263196e-01
+1 1.0692024e+00 1 1 -1.0128639e-01 -1.1184524e+00 -1.1454228e+00 -1.3785217e+00 -9.7562167e-01 -4.4346869e-01 -1.5336759e+00 1.3083743e+00
+1 5.8057535e-01 1 1 4.2287529e-01 1.4611531e+00 5.5829155e-01 4.3084144e-01 -1.3013510e+00 -1.5205563e+00 2.7692649e-01 -1.3025023e+00
+1 1.0227151e+00 1 1 9.8242869e-01 -2.2899433e-01 -7.3121353e-01 -2.1893591e-01 -3.8718489e-02 8.6584527e-01 -1.5368656e+00 -5.3882314e-01
+1 6.7384858e-01 1 1 -5.3200431e-01 -2.5673516e-01 4.0459838e-01 -8.5091374e-01 -4.3196310e-01 4.0421216e-01 7.4889705e-02 1.2111680e+00
+1 1.1060168e+00 1 1 -4.2366974e-01 -1.5411007e+00 -1.4631837e+00 -7.7740993e-01 2.1687089e-01 1.4705074e+00 -1.1073898e+00 -1.4194456e+00
+1 7.1492906e-01 1 1 1.3731749e+00 1.1514401e+00 6.5926792e-01 -4.4864715e-02 7.0156716e-01 -9.2029427e-02 -1.1060553e+00 6.3191496e-01
+1 8.3561621e-01 1 1 8.1088654e-01 4.3693202e-02 -8.1399659e-02 -5.9034085e-02 8.4197173e-01 -1.0749916e+00 -6.6848026e-01 -1.1301046e+00
+1 1.2022216e+00 1 1 3.4113622e-01 -7.8103866e-01 -1.4912692e+00 5.5741348e-01 1.2854836e+00 -8.4237953e-02 -8.1241456e-01 4.0113377e-01
+1 1.1253365e+00 1 1 6.9939725e-02 -1.3427230e+00 -1.3469637e-01 2.1905580e-01 3.9025103e-01 1.0710114e+00 -8.8984160e-01 -2.5230063e-03
+1 2.3403750e-01 1 1 5.2130880e-01 -1.0850224e+00 1.2463570e+00 -2.7582638e-01 -6.9633167e-01 -8.3686136e-01 1.5549199e+00 -1.5634625e+00
+1 8.1931664e-01 1 1 -2.6488139e-01 9.7468909e-01 -6.1828740e-01 1.1767848e+00 -8.1368960e-01 -2.1858212e-01 -1.3703033e+00 -8.3306975e-01
+1 5.2060247e-01 1 1 -2.2476193e-01 1.3354743e+00 8.3212373e-01 -1.2452683e+00 -3.2833779e-01 -1.1878659e+00 3.2741697e-01 6.7522948e-01
+1 1.2007319e+00 1 1 -1.3794113e+00 -1.3627772e+00 -8.6696481e-01 6.6450540e-02 1.4050632e+00 3.5909300e-01 -1.1732829e+00 1.1492091e+00
+1 4.0267649e-01 1 1 1.1880270e+00 1.1558418e+00 -3.7082235e-01 1.5688297e+00 -4.5513270e-01 2.7661538e-01 4.1168119e-01 2.4521103e-01
+1 8.1306446e-01 1 1 -7.9333282e-01 -1.3754849e+00 5.0854523e-01 -6.6870677e-02 3.6281901e-01 -4.8250623e-01 1.3386766e+00 -5.0777337e-01
+1 8.4496539e-01 1 1 -6.2555829e-01 1.2054706e+00 -1.1538469e+00 7.9470731e-01 6.7811114e-02 -1.0315091e+00 -9.4867525e-01 1.5601594e+00
+1 2.7309673e-01 1 1 1.1524117e+00 2.1303145e-01 3.4737200e-01 -1.4062681e+00 -6.9674780e-01 -1.2652212e+00 -8.0226149e-01 -1.2750701e+00
+1 2.9732884e-01 1 1 6.6496804e-01 -9.9600211e-01 1.2019726e+00 -9.4577554e-01 -1.5244991e+00 8.6794753e-01 1.0675123e-01 -1.2997204e+00
+1 4.1272978e-01 1 1 1.4727106e+00 -1.4017804e+00 1.1121682e+00 8.0924850e-01 5.7309808e-01 1.1794767e+00 3.1853169e-01 -9.0700589e-01
+1 5.5687985e-01 1 1 -7.6136913e-01 -9.1907500e-01 -2.6565305e-01 1.0850121e+00 -6.3726610e-02 1.5705251e-02 2.8828489e-01 -1.0404046e+00
+1 1.1565505e+00 1 1 -6.2410406e-01 3.1757379e-01 -6.2773060e-01 -1.1475376e+00 2.2996567e-01 6.4377471e-02 8.6835589e-01 2.4457013e-02
+1 1.1301818e+00 1 1 4.6088631e-01 -1.0317278e-01 -7.9999271e-01 -4.2645651e-01 8.7400227e-01 1.2842777e+00 -1.3820861e+00 -4.9962808e-01
+1 5.1631235e-01 1 1 -1.0513418e+00 1.3421312e-01 5.3909307e-01 -1.4816680e+00 -7.3111520e-01 -1.0274011e+00 2.1541290e-01 2.2803556e-01
+1 3.4301166e-01 1 1 1.5562179e+00 5.6436260e-02 1.8405672e-01 1.0105143e+00 -1.0842630e+00 -1.3376974e+00 1.3298787e+00 -1.4932735e-01
+1 4.8374378e-01 1 1 -1.5463280e+00 -2.3676206e-01 -1.0274454e+00 2.6436954e-01 1.1712968e+00 -1.4428545e+00 -1.1602750e+00 3.8772450e-01
+1 6.8533913e-01 1 1 1.2609205e+00 1.1379795e+00 1.0596634e+00 1.0468004e+00 7.6656156e-01 -1.0149628e-01 -8.7550664e-01 8.2253090e-01
+1 8.7786120e-01 1 1 -8.9389002e-01 6.0783566e-03 7.3563063e-02 6.5514143e-01 -7.1290761e-02 3.6908567e-02 5.7991213e-01 1.2691466e+00
+1 1.3816404e+00 1 1 -5.1351950e-01 -1.5136183e+00 -1.4131034e+00 -3.2019824e-01 -1.2370150e+00 1.4285264e+00 1.3627017e+00 -8.6773961e-01
+1 5.8099884e-02 1 1 -7.6714657e-01 1.2353613e+00 4.1125072e-01 -2.3664006e-02 5.4874388e-01 1.1921626e+00 7.1680213e-01 -8.2653070e-01
+1 8.7955017e-01 1 1 -3.3623070e-01 -6.8886076e-02 3.8705944e-01 1.2613249e+00 -9.7771055e-01 -4.0192109e-01 -7.1444725e-01 6.2126275e-01
+1 1.1596763e+00 1 1 6.9587027e-01 1.4794099e+00 -9.3033189e-01 -3.7916394e-01 1.2899259e+00 -6.6357856e-01 -5.4786765e-01 -1.0909465e+00
+1 1.0162514e+00 1 1 -6.5780069e-01 -1.2636396e+00 -3.8146366e-01 -1.4584992e+00 -3.4564701e-01 -1.1092485e-01 -3.5141435e-03 -1.2027533e+00
+1 8.0733398e-01 1 1 -3.9156956e-01 -8.2438203e-01 7.3092765e-01 8.5104321e-01 -4.8440601e-01 -1.3494582e+00 6.2804985e-01 1.4732526e+00
+1 5.7335304e-01 1 1 5.2705281e-01 -9.6510815e-01 1.0737438e+00 -1.8818526e-01 -1.5453168e+00 -1.1860496e+00 -1.1751394e-01 -1.0774509e+00
+1 4.9940843e-01 1 1 -1.1147459e+00 -5.2973997e-01 1.1032862e+00 7.5420008e-01 -5.9379553e-01 -5.2999937e-01 1.0050201e+00 -5.7651940e-01
+1 5.5000425e-01 1 1 9.2499404e-01 -6.6073184e-02 1.2506214e+00 -4.8565656e-01 9.1834869e-01 -1.2842450e+00 -9.7114311e-01 -8.8974199e-01
+1 9.9137333e-01 1 1 -1.3672139e+00 -1.5098039e+00 -1.2028221e+00 -5.7209930e-01 4.1687319e-02 -1.5648383e+00 -1.4283701e+00 8.7400315e-02
+1 8.0309532e-01 1 1 -1.1558065e+00 -6.3107131e-01 3.1777408e-01 1.1421279e+00 6.3604084e-02 1.1768494e+00 1.4354538e+00 -1.3282647e+00
+1 3.5141560e-01 1 1 -1.1725958e+00 -3.9872764e-01 1.2152608e-01 6.1181727e-01 8.5234526e-01 -1.6025689e-01 1.3817244e+00 1.1914026e-02
+1 8.8256967e-01 1 1 -6.0646943e-01 -3.9832792e-01 4.5355682e-01 3.8012443e-01 -2.9566064e-01 -1.0926307e+00 -1.1305723e-02 -8.2289392e-01
+1 3.7684948e-01 1 1 1.5364350e+00 3.6563309e-02 1.4257697e+00 -1.2481901e+00 8.3115883e-01 -1.2357859e+00 -1.5197234e+00 -1.0871925e+00
+1 9.3846488e-01 1 1 -1.0286460e+00 -1.2326228e+00 -1.1576825e+00 1.2254130e+00 -1.3760725e+00 -7.8418534e-01 -8.4370337e-01 -9.4174416e-01
+1 1.3266893e+00 1 1 -2.6846657e-01 -1.0296614e+00 -1.2873030e+00 -7.6463329e-01 7.5386416e-01 -8.2189419e-01 1.0267196e+00 -5.5037096e-01
+1 6.1921023e-01 1 1 -7.9058358e-01 1.5154873e+00 4.4627377e-01 1.0638863e+00 1.5175197e-01 7.2396297e-03 -6.9179672e-01 -1.2358722e+00
+1 6.1756209e-01 1 1 -1.5428238e+00 -1.2385991e+00 1.5415654e+00 -1.2083156e+00 -4.7781700e-01 -8.4565635e-01 6.9582901e-03 9.0592276e-01
+1 6.1893558e-01 1 1 4.6571409e-01 -9.4229298e-01 3.7492892e-01 -9.0564163e-01 -7.5945640e-01 -3.8113023e-01 7.0905383e-01 -1.4558212e+00
+1 6.5402689e-01 1 1 1.5494936e+00 -3.4957891e-01 -6.0447767e-01 -1.0240493e-01 1.0730097e-01 5.1720767e-02 1.0068601e+00 -1.2638188e+00
+1 8.5122948e-01 1 1 -1.4644506e+00 -5.9446983e-01 4.5452515e-01 4.7303362e-01 1.3322962e-01 -9.5022992e-01 -1.4623152e+00 -6.9450795e-01
+1 5.8267559e-01 1 1 1.3572065e+00 -9.8983185e-01 -1.1491810e+00 -1.0950326e+00 -7.6527395e-01 1.3428179e+00 -4.5219552e-01 1.5632222e+00
+1 8.6496908e-01 1 1 -5.3540527e-01 -1.3708144e+00 2.2595471e-01 -7.6368106e-01 -2.7898386e-01 -4.6038970e-01 -5.3741170e-01 -6.3279407e-02
+1 1.0432523e+00 1 1 -1.0349820e+00 1.1633226e+00 -5.6465896e-01 1.3600683e+00 1.5161104e+00 -2.6969655e-02 -1.9951028e-01 1.4629103e+00
+1 6.4772780e-01 1 1 5.6472251e-02 -1.3090931e+00 5.2833755e-01 4.4025349e-01 -1.9055483e-01 -8.8964594e-01 -1.0898417e+00 1.0296150e+00
+1 1.3958503e+00 1 1 3.6813381e-01 -1.3550243e+00 -1.5131623e+00 8.8971767e-01 -1.3721551e+00 -1.4397926e+00 -1.4839090e+00 8.4644323e-01
+1 9.0423025e-01 1 1 1.4290918e+00 -4.8779434e-01 -5.2689416e-01 -4.9613899e-01 6.2105498e-01 1.0944356e+00 1.0452322e+00 1.0398556e+00
+1 3.0298265e-01 1 1 1.2694279e+00 1.1973238e+00 6.3961741e-01 -8.2118183e-01 -1.4413108e+00 1.5471614e-01 -5.6932031e-01 1.7333539e-01
+1 1.0108726e+00 1 1 7.1862653e-01 1.5197320e+00 -4.8018744e-01 -5.8643646e-01 7.0957979e-01 -9.2448645e-01 7.2481975e-01 9.9145878e-01
+1 7.7982827e-01 1 1 -1.4677442e+00 9.8820272e-01 2.4122543e-01 -1.0614117e+00 4.2184285e-01 4.7357736e-01 -1.0507090e+00 4.4022285e-01
+1 1.0847536e+00 1 1 -5.9069820e-01 -8.7723976e-01 -1.5203373e+00 -1.1827801e+00 -6.6177468e-01 -1.3810195e+00 -3.7330885e-01 3.7471284e-01
+1 4.9892138e-01 1 1 -4.3178393e-01 -2.7431044e-01 1.4054824e+00 1.0123875e+00 -1.2091073e+00 -7.0901936e-01 -4.4125602e-01 -1.0946452e+00
+1 7.0861719e-01 1 1 8.6505066e-02 1.5224485e+00 3.0738383e-01 3.3140211e-01 1.4962352e+00 -4.2751037e-01 1.1103336e+00 -5.3554413e-01
+1 5.9934540e-01 1 1 -6.6674824e-01 -4.7954707e-01 1.4216379e+00 -1.6858687e-01 -1.2243046e+00 -3.4440840e-01 3.1710659e-01 -2.2723702e-01
+1 6.5919576e-01 1 1 2.3318384e-02 -1.5624883e+00 -1.4856346e+00 2.7704198e-01 5.4511789e-01 1.4832878e+00 1.4693919e+00 1.0040132e+00
+1 7.5251462e-01 1 1 -7.8700372e-01 -1.6751325e-01 3.1846996e-01 4.0432351e-01 9.1214955e-01 1.0810910e+00 9.9342634e-03 9.5627742e-01
+1 1.0908598e+00 1 1 -1.0664015e+00 -5.2816664e-01 -7.4919930e-01 2.0027598e-01 -4.7468043e-01 -1.0746721e+00 4.6075443e-01 -2.3335206e-01
+1 5.5184647e-01 1 1 -2.2349437e-01 1.2441981e+00 -2.8934768e-01 1.3926664e+00 -1.4502078e+00 -9.9835156e-01 -1.2611895e-01 -1.2405237e+00
+1 4.4570043e-01 1 1 1.0750120e+00 7.9688237e-01 1.1904436e-01 -1.4624204e+00 -1.1660859e+00 -4.8271287e-02 8.9385521e-01 1.2686394e+00
+1 6.3115660e-01 1 1 4.2796791e-01 5.9255712e-01 -4.1594243e-01 9.2167119e-01 -1.1515176e+00 -7.6461389e-01 -7.1534455e-02 3.3887813e-02
+1 9.5193096e-01 1 1 -1.3905798e+00 2.5874645e-01 -7.0068921e-01 -6.6564001e-01 -1.3453676e+00 1.3899380e+00 9.5039923e-01 9.2420965e-01
+1 3.7535351e-01 1 1 -1.1662046e+00 7.8738169e-01 1.3472617e+00 -2.0027850e-01 -1.5501553e+00 -1.9481091e-01 1.5028874e+00 1.1574271e+00
+1 8.4357437e-01 1 1 -4.9601371e-03 1.1357293e+00 -1.1727823e+00 -1.4350549e+00 -2.3235323e-01 -6.4747299e-01 6.2394699e-01 1.3559057e-01
+1 8.5307442e-01 1 1 1.4579770e+00 -1.1525918e-01 -6.0004801e-01 -9.6020862e-01 -1.6104061e-01 3.9836316e-01 4.0747207e-02 1.2160164e+00
+1 1.1315935e+00 1 1 -2.0382020e-01 1.2016192e+00 -4.9442154e-01 1.3523766e-01 1.4433450e+00 5.5576847e-01 -2.8897046e-02 1.5267179e+00
+1 9.0463497e-01 1 1 -1.2701922e+00 1.4569391e+00 -2.3019051e-01 1.5678192e+00 -1.0787540e+00 8.4574874e-01 1.2742019e+00 -9.8058342e-01
+1 9.0584301e-01 1 1 -9.9799501e-01 1.2022766e+00 -1.5113492e+00 -1.3413554e+00 -4.8770574e-01 -1.2077275e+00 -7.2603229e-01 1.2959224e-01
+1 1.0372685e+00 1 1 -3.3899940e-01 -6.1734456e-02 -1.4690950e+00 -9.0619494e-02 -4.5519040e-01 -4.4631480e-01 -4.7881526e-01 9.3305136e-01
+1 1.0053180e+00 1 1 1.2862235e+00 -8.4542856e-01 -1.3033310e+00 6.3059789e-01 -6.0692727e-01 9.1035450e-01 1.3123651e+00 -1.0363002e+00
+1 6.8294145e-01 1 1 2.6002029e-01 3.0583379e-01 1.2413647e+00 -1.2749191e+00 1.2466717e-01 7.7188618e-01 -2.0115377e-01 -1.0825796e-01
+1 2.4156483e-01 1 1 2.0559339e-01 5.0286961e-01 2.9983930e-01 1.2376115e+00 -1.6114614e-01 1.4549458e+00 -4.3770092e-01 -5.0946778e-01
+1 8.1978214e-01 1 1 -3.4388026e-01 8.4530010e-01 2.8447077e-01 5.1566320e-02 -3.3023270e-01 -8.8241149e-01 1.1706657e+00 1.3565404e+00
+1 1.0603377e+00 1 1 9.3497941e-01 6.7677579e-01 -4.0380453e-01 -4.0443768e-01 9.7330313e-01 7.6901876e-01 -4.1604881e-01 8.3690030e-01
+1 7.7770547e-01 1 1 -4.7564888e-02 -1.1363374e+00 -9.0267280e-01 1.0224282e+00 3.2820922e-02 3.8610135e-01 6.5289300e-01 8.7307050e-01
+1 8.5147190e-01 1 1 -1.4585323e+00 -6.8110986e-01 -4.7086230e-01 -5.6057742e-01 -1.2990730e+00 -1.3249613e+00 -4.1043289e-01 -6.8332140e-01
+1 9.5387638e-01 1 1 2.9591196e-01 5.5022328e-01 -1.1070283e-01 1.1741621e-02 5.4948202e-01 -1.0162525e+00 7.9185869e-01 1.0799811e+00
+1 1.0449495e+00 1 1 2.5107004e-01 -1.2460891e+00 -7.5956467e-01 -5.7891035e-01 -1.1380853e+00 6.8320471e-01 9.8254938e-01 -8.8023574e-01
+1 4.0885267e-01 1 1 5.7524076e-01 -1.1636091e+00 1.4290673e+00 -2.3372443e-01 1.3582977e+00 1.0048220e-01 1.4964942e+00 -3.6229105e-01
+1 3.5593457e-01 1 1 1.3908841e+00 -3.6394310e-01 8.5771414e-01 -1.2157560e+00 -1.0449029e+00 -1.3724680e+00 -1.3385950e-02 -6.1914378e-01
+1 9.0231064e-01 1 1 -2.4854898e-03 -1.1083852e-01 -1.1671536e+00 -2.9290857e-01 -1.7946853e-01 -1.4966173e+00 1.2170118e+00 -9.9471799e-01
+1 9.1553735e-01 1 1 -9.3292210e-01 1.0143629e-01 -2.4604211e-01 -3.8702460e-02 -3.9869504e-01 1.0846572e+00 -5.9282749e-01 1.3308479e+00
+1 1.0605218e+00 1 1 6.7238236e-02 -1.0450602e+00 -8.9373326e-01 -1.6256044e-01 1.4964843e-01 -8.2863245e-01 1.4803436e+00 -5.7934782e-01
+1 8.1133368e-01 1 1 -9.0031790e-01 3.1842771e-01 -1.0204884e+00 1.0322546e+00 -1.2744725e+00 -1.4527334e-01 -1.2784619e+00 -1.3031392e+00
+1 6.7991006e-01 1 1 1.4088089e+00 -1.4592795e+00 -1.3949917e+00 1.2278320e+00 -6.8028131e-01 -5.9145622e-01 1.3850172e+00 1.3235804e+00
+1 6.2603417e-01 1 1 -3.3345954e-01 3.0340308e-01 8.0641328e-02 -9.5032107e-01 -1.2323249e+00 -6.0552553e-01 -1.2171890e+00 -2.0228784e-01
+1 7.1621971e-01 1 1 1.4672526e-01 4.9067909e-01 1.3123642e+00 -1.8911613e-01 8.3508178e-01 -1.4490001e+00 7.5564850e-01 -6.4848723e-01
+1 5.3310818e-01 1 1 -1.3886789e-01 1.6270769e-01 -2.1622576e-01 8.1689376e-01 -1.4164582e+00 2.8156269e-01 -1.2747934e+00 -9.3992547e-01
+1 1.6322441e-01 1 1 2.5068863e-01 1.4424536e+00 7.1631875e-01 7.7349344e-01 5.7623218e-01 9.8556521e-01 2.0909751e-01 -1.3994598e+00
+1 6.6404051e-01 1 1 4.4803455e-01 -3.5328605e-01 5.8613312e-01 1.9382773e-01 -7.9585834e-01 -1.2235916e+00 -1.1403897e+00 3.8250039e-01
+1 1.2060943e+00 1 1 -2.8083494e-01 -6.8563624e-02 -8.9523867e-01 -1.6900013e-01 9.1034325e-01 -3.9190454e-02 3.2629704e-01 9.8553769e-01
+1 1.1609474e+00 1 1 -1.3207062e+00 6.1567560e-01 -1.1890747e+00 -3.8545355e-01 5.8276094e-01 1.0604963e+00 -1.1464087e+00 1.4555146e+00
+1 8.9152041e-01 1 1 1.3843321e+00 -7.4637903e-01 -1.1078075e+00 -3.5377532e-01 -1.0227227e+00 1.5059513e+00 -3.0322544e-01 -7.4854628e-01
+1 6.4749268e-01 1 1 -1.6567348e-01 -1.2901535e-02 1.2996980e+00 1.1331022e+00 -1.2472708e+00 -1.2884472e+00 -6.4676319e-01 1.2612111e+00
+1 8.8890015e-01 1 1 -1.0230268e+00 -6.6209986e-02 5.2993560e-01 -2.8625469e-01 9.6752106e-01 6.6277907e-02 -2.3834064e-01 8.4941662e-01
+1 1.6047541e-01 1 1 -7.5089266e-02 -6.6744013e-01 2.1253537e-01 -1.3042845e+00 2.4287560e-01 -1.3326150e+00 -2.6043709e-01 7.4813510e-01
+1 4.5841886e-01 1 1 8.9496002e-01 9.6114241e-01 9.1087049e-02 9.2322625e-01 1.0813063e+00 -8.4670075e-01 -9.2763928e-01 1.2528737e+00
+1 3.1854220e-01 1 1 -3.5256719e-01 -1.4895351e-01 9.4440478e-01 3.3753635e-01 -5.9901107e-01 9.1518441e-01 8.9104129e-01 -1.0474558e+00
+1 7.1554820e-01 1 1 -5.5302309e-01 3.8774079e-01 1.2851033e+00 -7.4293475e-01 1.2254368e+00 2.6673132e-01 -2.4119811e-01 8.9586437e-01
+1 6.9278448e-01 1 1 1.3136680e+00 1.0963101e+00 2.8101812e-01 1.3264642e+00 -3.6432804e-01 -9.9487222e-02 -1.1620636e+00 -8.6105256e-01
+1 1.6324873e-01 1 1 -2.9503240e-01 2.4269706e-01 1.2577341e+00 1.1419340e+00 -2.9727545e-01 -7.5445358e-01 4.7862925e-01 -1.5345720e+00
+1 1.2101238e+00 1 1 -1.1763095e+00 1.2222446e+00 -1.0402366e+00 4.9535155e-01 -1.1761122e+00 -6.3337944e-01 -1.2969939e+00 9.2442824e-01
+1 9.3567433e-01 1 1 -1.9179601e-01 -6.0907290e-01 -2.9424725e-01 1.5296576e-01 -1.7205992e-02 -1.4924177e+00 9.3412872e-01 -1.4517571e+00
+1 7.4076858e-01 1 1 -2.4140694e-01 -1.3793393e+00 -5.4676923e-01 1.0726802e+00 -1.5457954e-01 -5.8877366e-01 1.3628797e+00 1.0688599e+00
+1 1.2089377e+00 1 1 -1.5304013e+00 -7.4367557e-01 -3.9196864e-01 -1.0647489e+00 7.8803345e-02 4.9791739e-01 5.6671732e-01 7.0230199e-01
+1 6.2763771e-01 1 1 -1.2348224e+00 1.4418442e+00 1.0293080e-01 -7.2262858e-01 -1.3042734e+00 -7.0528620e-01 -4.9093679e-01 6.2590684e-01
+1 6.3383032e-01 1 1 -2.9848468e-01 -1.1700133e+00 -1.0596244e+00 1.7864727e-01 1.1101386e+00 -5.1600915e-01 -1.3522846e+00 1.5640588e+00
+1 6.9255924e-01 1 1 4.9137590e-01 -1.1859018e+00 5.8107285e-01 -8.3790482e-01 1.8129070e-01 1.3715363e+00 -1.5651967e+00 1.4312654e+00
+1 1.1672586e+00 1 1 -6.9238020e-01 -1.1878849e+00 -1.1202476e+00 1.0935667e+00 -3.9214663e-01 1.5458618e+00 1.4354665e+00 1.0325333e-01
+1 9.3896795e-01 1 1 -3.7477113e-01 3.9015998e-02 -4.3731513e-01 1.2587296e+00 2.5299102e-01 3.2789641e-01 -1.5461804e+00 1.2195125e+00
+1 3.7549519e-01 1 1 1.1494109e-01 -8.5098406e-01 1.3714862e+00 -1.5927381e-02 1.4452196e+00 6.0146672e-01 6.0104331e-01 5.9556858e-01
+1 5.6194305e-01 1 1 -2.6463948e-01 1.1822729e+00 7.0318249e-01 -6.5611501e-01 -9.8831438e-01 -7.9395971e-01 1.5146001e+00 6.0693408e-01
+1 5.4142073e-01 1 1 6.9951835e-01 -1.1233369e-01 -2.8349846e-01 -3.3473656e-01 -9.9945694e-01 1.4047516e+00 -4.4064788e-01 -1.0262631e-02
+1 6.3883403e-01 1 1 9.6527332e-01 1.0483794e-01 1.0374959e+00 6.7515919e-01 2.2312324e-01 5.9207177e-01 -1.2350375e+00 3.0354897e-01
+1 2.7961977e-01 1 1 1.6419696e-01 -4.2226568e-01 1.3549795e+00 -3.2135211e-02 -1.0293206e+00 1.5262324e+00 -7.7257216e-01 -1.9892406e-01
+1 9.9091395e-01 1 1 1.3400144e+00 -1.6139862e-01 -2.6509227e-01 2.5744152e-01 9.5936424e-01 2.8336193e-01 -4.1791221e-01 -6.6208490e-01
+1 1.1941426e+00 1 1 -4.5523790e-01 -1.4322051e+00 -6.2747258e-01 8.4651851e-01 1.3812272e+00 -1.9046054e-01 7.5069345e-01 -1.3977431e-01
+1 9.7817723e-01 1 1 -1.4053249e+00 -1.8887002e-01 3.9484583e-01 -8.3652560e-01 1.0572938e+00 2.1266620e-01 2.6878412e-01 7.2445678e-01
+1 7.2979058e-01 1 1 -8.0228043e-01 -1.3299023e+00 1.1302058e+00 -8.5867067e-01 1.0890464e+00 -8.5169116e-01 -1.5554265e-01 -8.6804188e-01
+1 7.5781976e-01 1 1 -2.1148173e-01 7.6316605e-01 1.2995427e+00 7.9878337e-01 6.8439696e-01 -1.2771541e+00 -4.0018499e-01 3.7633574e-01
+1 1.8477627e-01 1 1 -1.2321331e+00 -5.9104002e-01 1.0620819e+00 1.1266248e+00 1.2889319e+00 1.3741944e+00 2.4072826e-01 1.0487163e+00
+1 9.0285002e-01 1 1 9.1759249e-01 1.0634123e-01 -1.1876328e-01 8.0354889e-01 -1.3445330e+00 -9.0446884e-01 -4.5139355e-01 1.4408843e+00
+1 8.9734595e-01 1 1 -1.0132020e-01 -2.8915883e-01 -1.1430705e+00 -4.6064018e-01 -9.0893186e-02 7.5908332e-01 3.7480838e-01 1.5465846e+00
+1 8.2272083e-01 1 1 -1.4541015e-01 1.5137246e-01 -7.4734611e-01 -1.0951838e+00 -8.2774236e-01 -9.4384359e-02 5.1122277e-01 -9.0202024e-02
+1 6.8937628e-01 1 1 2.5076008e-01 -5.7303517e-01 -5.5871806e-01 -1.6251830e-01 -8.9363205e-01 1.8636441e-01 -1.3481201e-01 1.3638310e+00
+1 7.3768726e-01 1 1 -1.4927407e+00 1.1209052e+00 -1.5391968e-01 -1.4010282e+00 6.8058143e-01 5.8819301e-02 -6.9719250e-01 8.4731102e-01
+1 1.1484279e+00 1 1 2.6591253e-01 -1.0773261e+00 -1.3972851e+00 -8.4373163e-01 -6.8077090e-03 -1.0256984e+00 4.2616852e-01 -8.3163836e-02
+1 9.8964923e-01 1 1 -1.2945346e+00 1.5200120e+00 -7.6503701e-01 5.5174285e-01 -1.3198302e+00 -9.9351302e-01 -2.1686521e-01 2.7413789e-01
+1 7.0030463e-01 1 1 1.4276641e+00 -5.8922610e-01 5.6167514e-01 -8.3942440e-01 3.9934555e-01 -4.0841047e-01 -6.0614398e-01 -1.2809237e+00
+1 1.1281745e+00 1 1 -7.3396254e-01 -8.2297591e-01 -4.1182589e-01 6.8675444e-01 1.3587186e+00 2.2524873e-01 7.2303082e-01 8.4990476e-01
+1 7.6102792e-01 1 1 1.3259454e+00 6.7638233e-01 -6.2910861e-01 7.0529849e-02 -2.5347171e-01 1.3619302e-01 2.9868158e-01 -4.7248749e-01
+1 7.8639979e-01 1 1 -1.2939917e+00 -1.4659952e+00 1.1724308e+00 1.0147382e+00 -9.9447852e-02 -1.2249992e+00 -3.2376867e-01 8.4904919e-01
+1 5.5707131e-01 1 1 1.1271461e+00 5.3068958e-01 9.7555300e-01 -1.0022650e+00 -9.2761127e-02 1.4360786e+00 -3.4149850e-01 8.5598314e-01
+1 7.9770421e-01 1 1 1.4118013e-01 3.1829318e-01 1.4724944e-01 1.5131690e-01 -8.0630996e-01 -6.8354865e-01 1.2443090e-01 1.1558926e+00
+1 1.0472863e+00 1 1 9.1204248e-01 -5.7875624e-01 -7.5370947e-01 -1.5069086e+00 1.1792898e+00 4.0221271e-01 -9.9064252e-01 -5.2193803e-01
+1 6.9132734e-01 1 1 8.6744412e-01 -7.8527009e-01 -6.9341355e-01 9.0643102e-01 1.5512702e-02 -7.1835692e-01 7.1226398e-01 -8.8583930e-01
+1 2.2716738e-01 1 1 -9.9813520e-01 -2.0372089e-01 1.1071774e+00 8.0339583e-01 -3.0205586e-02 -2.8420505e-01 1.5526514e+00 -2.9351895e-01
+1 6.0478146e-01 1 1 4.4644491e-01 3.9901259e-01 6.7647082e-01 1.0846079e-01 1.2727311e+00 -1.4134730e+00 1.3434715e+00 -8.7244414e-01
+1 2.0963213e-01 1 1 1.2762893e+00 -1.0957009e+00 2.1190110e-02 7.7670261e-01 -3.1271177e-01 4.8216869e-01 1.0994877e+00 -1.3557662e+00
+1 6.6915952e-01 1 1 -2.0121360e-01 5.7117811e-01 1.1422120e+00 7.2326852e-01 1.3770837e-01 -1.4998685e+00 2.4102836e-01 -3.9080558e-01
+1 6.5447083e-01 1 1 -1.4432463e+00 -9.1664190e-01 -1.1157864e+00 1.1519784e+00 -8.8926875e-01 -1.5095441e-01 1.4506976e+00 8.0091375e-01
+1 9.0112475e-01 1 1 -4.0302619e-01 3.6991532e-01 -8.5559489e-01 -3.3400421e-01 -1.3835944e+00 1.3161523e+00 -2.5326973e-02 -7.6716069e-01
+1 1.0534869e+00 1 1 -3.8734034e-01 -4.5103736e-02 -9.1369176e-01 4.1732054e-01 -2.0036733e-03 6.1865017e-01 -1.5554326e+00 -5.7349780e-01
+1 5.0542140e-01 1 1 -6.4912522e-01 -9.3465617e-01 -3.1259517e-01 -1.2700132e+00 8.8178181e-01 -1.0183560e+00 -9.6368358e-01 -3.7118921e-01
+1 1.1891210e+00 1 1 9.0366878e-01 -8.0306440e-01 -1.0440580e+00 -1.1313851e+00 1.2143541e+00 -1.1195095e-01 1.4217467e+00 6.2598231e-01
+1 5.3184863e-01 1 1 1.5023510e+00 -8.2135222e-01 1.4529617e+00 8.7146800e-01 -1.2783115e+00 2.5444314e-01 3.4363331e-01 -3.0917520e-01
+1 1.9210647e-01 1 1 1.0338537e+00 -3.0866999e-01 3.2740131e-01 6.5777909e-01 7.7074945e-01 7.1828855e-01 1.1978019e+00 -1.1333267e-01
+1 1.3716935e+00 1 1 -1.6957336e-01 -1.0469973e+00 -1.4365633e+00 2.8612364e-02 1.1994599e+00 -8.6495450e-01 1.3159643e-01 -9.7698094e-01
+1 1.1090615e+00 1 1 -5.9492459e-01 -8.2309289e-01 -1.1799610e+00 2.2432640e-01 -2.7772051e-01 -1.1410886e+00 5.9887386e-02 9.8610911e-01
+1 4.8948695e-01 1 1 7.9174917e-01 -1.2896645e+00 1.2702211e+00 3.4264843e-01 7.5800683e-01 1.1465939e+00 1.2176475e+00 -1.5070707e+00
+1 4.1437790e-01 1 1 -8.5817615e-01 -1.5433270e+00 1.4841344e+00 3.5285677e-01 6.6253487e-01 2.7506888e-01 6.6634763e-01 1.3250579e+00
+1 9.5817924e-01 1 1 -3.1466334e-01 1.4330387e+00 -3.9881254e-01 -8.6318704e-01 1.4192627e+00 -1.3417487e+00 -4.7323243e-01 -5.0169556e-01
+1 5.9758485e-01 1 1 -1.2462918e+00 -1.5096389e+00 1.3163674e+00 2.9027079e-01 -5.6559896e-01 -4.1907246e-01 8.9509315e-01 3.7406967e-02
+1 8.4641630e-01 1 1 -1.4286065e+00 -9.9922057e-01 1.0921475e+00 -3.1219807e-01 4.3772964e-01 9.9918052e-02 -1.2566696e+00 3.8035888e-01
+1 7.2942388e-01 1 1 6.0340032e-01 1.0542670e+00 -6.0200547e-01 -6.5315343e-01 -6.8789479e-01 -1.4293751e+00 8.0939645e-02 -4.4930482e-01
+1 6.3050639e-01 1 1 2.8815806e-01 4.8239747e-01 1.1639367e+00 -8.2499922e-01 -3.8672176e-01 2.5201574e-01 4.2989256e-02 9.2261617e-01
+1 6.0403257e-01 1 1 -1.2633599e+00 -7.9633270e-01 -4.1299815e-01 1.2280432e+00 3.2257560e-01 7.6164065e-01 -4.5887457e-02 -4.9143540e-01
+1 1.0613596e+00 1 1 7.3461848e-01 -7.7903937e-01 -1.4818192e+00 -5.4102103e-01 -8.6084300e-01 -1.0955867e+00 -1.5402977e+00 -3.0775595e-01
+1 7.1086595e-01 1 1 2.7373874e-01 8.4341213e-01 -1.5305794e+00 -1.1712922e+00 -1.1540636e+00 -6.5054261e-01 -1.0592707e+00 -1.3927150e+00
+1 8.2758827e-01 1 1 1.4353176e+00 3.6160855e-01 -1.0877864e+00 -6.8908709e-01 -1.5435157e-01 -9.2716821e-01 2.4291590e-01 6.4629532e-01
+1 1.0952066e+00 1 1 -9.0732533e-01 -1.4268975e+00 -1.4980432e+00 1.5653394e+00 7.6871783e-01 -6.1661302e-01 -1.3828581e+00 -1.3420221e+00
+1 5.9073712e-01 1 1 -1.2609431e-01 1.0512938e+00 -8.8780244e-01 9.6171800e-01 -1.5300292e+00 6.9914305e-01 -1.9330918e-01 1.2705235e+00
+1 3.9911060e-01 1 1 1.3080523e+00 7.7719139e-01 1.2694899e+00 1.0020138e-01 -1.2643600e+00 9.4076811e-01 -5.4064993e-01 2.8249733e-01
+1 1.0633400e+00 1 1 -4.3099844e-01 -4.8658485e-01 -1.3805399e+00 1.9094607e-01 -3.6532121e-01 -1.4614091e-01 -1.2174754e+00 9.8608538e-01
+1 4.2661918e-01 1 1 7.2187255e-01 -4.6591075e-01 1.0694183e+00 -1.4771771e+00 -1.2815075e+00 5.3522673e-01 -9.1640425e-01 1.2358149e+00
+1 2.1685945e-01 1 1 -3.1885184e-01 1.4284750e+00 6.6231065e-01 1.0920445e+00 4.6311037e-01 1.1758957e+00 1.2224991e+00 1.2723655e+00
+1 3.2282674e-01 1 1 6.1414976e-01 3.2787104e-01 7.9231615e-01 8.0711937e-01 -1.3706573e+00 -4.7977223e-01 5.2712502e-01 -1.7467058e-01
+1 6.4467623e-01 1 1 -1.2584494e+00 1.7509897e-01 -7.5366814e-01 -1.4179760e-01 6.6235298e-01 9.3647120e-01 9.8881504e-02 -1.4408357e+00
+1 9.8363182e-01 1 1 -1.5569528e+00 -7.8385695e-01 1.2258354e-03 1.2765111e+00 1.5037978e+00 -1.0773853e-01 -1.0760136e-03 -7.3026284e-01
+1 1.0723407e+00 1 1 -1.3803799e+00 1.5558868e+00 -1.3885333e+00 3.8555731e-01 2.1700702e-01 -1.2040459e+00 7.6499615e-01 6.7486543e-01
+1 8.3325968e-01 1 1 6.1622173e-01 -8.2773234e-01 -1.3292393e+00 -1.0438919e+00 -1.5205763e-01 -1.4004082e+00 -1.2484466e+00 1.3137553e+00
+1 7.3474746e-01 1 1 -9.9238706e-01 -7.2523388e-01 -6.5887956e-01 1.1044577e+00 -1.5177550e+00 1.5125333e-01 5.5260103e-02 1.1728273e+00
+1 6.5443220e-01 1 1 -3.3383760e-01 3.7368236e-01 3.2537078e-01 -1.0511444e+00 8.2447643e-01 5.6626903e-01 -1.1548748e+00 1.3556638e+00
+1 7.3708698e-01 1 1 7.5946819e-02 4.3569100e-01 -1.0060438e+00 -1.4083014e+00 -5.8984376e-01 1.3995166e+00 -1.2210780e+00 -1.3298849e+00
+1 9.9159063e-01 1 1 9.5157610e-01 -3.9383464e-01 -5.2730696e-01 -5.6315208e-01 1.3622830e+00 5.7195261e-01 1.3665816e+00 1.0556807e+00
+1 8.9545763e-01 1 1 -7.0871686e-01 1.5684298e-01 -1.5256070e-02 7.2170778e-01 -3.7453076e-02 -4.6592477e-01 -4.6694962e-02 -8.8928543e-01
+1 3.3981604e-01 1 1 1.5151006e+00 2.6377039e-01 1.2018337e+00 5.3477248e-02 -1.1553249e+00 1.1928552e+00 5.9593836e-01 1.4777035e+00
+1 1.0286180e+00 1 1 -1.4536802e+00 4.0179054e-01 -1.2209419e+00 2.9660208e-01 6.3923142e-01 -1.3265663e+00 5.3862236e-01 1.4720793e+00
+1 3.4584001e-01 1 1 1.6298369e-01 -1.5306135e+00 5.1266178e-01 -7.1633246e-01 -6.8432720e-01 2.8253329e-01 -1.4439807e+00 1.1938267e+00
+1 9.1782069e-01 1 1 -2.0200013e-01 1.4814394e+00 -1.0820941e+00 -8.1666331e-01 -1.1648821e-01 -1.5510786e+00 -1.8000310e-01 -7.0674216e-01
+1 6.4711870e-01 1 1 1.0455465e+00 1.4293865e+00 -7.6384484e-02 -4.1903542e-02 -6.0505263e-01 -4.1412378e-02 4.1552375e-02 1.4638035e-01
+1 4.1720361e-01 1 1 -1.5686534e+00 -5.9349938e-02 1.1173809e+00 -5.5608284e-01 2.1589361e-01 1.4157337e+00 9.3719373e-01 3.4750108e-01
+1 1.0011844e+00 1 1 -1.1163701e-01 1.5320609e+00 -6.2066179e-01 1.5390396e-01 -1.5647182e-02 -1.8663039e-01 -5.3055772e-01 2.2988634e-01
+1 7.6348817e-01 1 1 -7.5241362e-01 8.5464134e-01 -1.3751481e+00 1.1330949e+00 9.1158939e-01 -1.3874371e+00 -1.2435898e+00 -4.5921754e-01
+1 6.9972190e-01 1 1 -9.0533564e-01 5.9535661e-01 5.8261771e-01 -4.0845340e-01 -4.6443968e-01 1.3861575e+00 1.4044738e-03 8.2389690e-01
+1 8.1319515e-01 1 1 -1.2428197e+00 1.8597968e-01 -2.8849368e-01 -4.9628913e-01 1.0200473e+00 -9.0284114e-01 -1.5277506e+00 -9.0516298e-01
+1 9.6033094e-01 1 1 3.7853192e-01 -1.2422458e-01 -1.2358822e+00 -2.0288175e-01 2.6433006e-01 -1.5859989e-01 -6.6684089e-01 -1.4825743e+00
+1 6.0502076e-01 1 1 2.6091521e-01 1.3165426e+00 7.3912276e-01 -1.2054747e+00 3.8326388e-01 -1.5178065e+00 -1.5338176e+00 1.4869871e+00
+1 8.4716434e-01 1 1 -4.6147984e-01 8.9367500e-01 5.7881629e-01 -2.8165451e-01 1.2511373e+00 -4.0896920e-02 1.0361854e+00 4.2219233e-01
+1 3.0382253e-01 1 1 5.0067334e-01 4.1325236e-02 -1.3470891e+00 6.1283240e-01 1.1851585e+00 6.5425367e-01 1.3191357e+00 -1.0713576e+00
+1 7.0869906e-01 1 1 -1.5098929e+00 2.6126940e-01 9.3128206e-01 -1.4082305e+00 1.2609011e+00 4.6718046e-01 4.9434434e-01 1.3014460e+00
+1 1.1423503e-01 1 1 1.0157140e+00 -7.9174427e-01 6.4292847e-01 6.2842051e-01 -1.2187615e+00 1.0619687e+00 -1.0672794e+00 -1.5064723e+00
+1 8.5469415e-01 1 1 -3.0877741e-01 9.4061725e-01 -1.3799839e+00 -1.7104871e-01 -5.4114897e-01 1.1201685e+00 7.2884029e-01 -1.1843594e+00
+1 6.6990468e-01 1 1 2.8915255e-01 4.5981637e-01 9.8954645e-01 -2.5839011e-01 -1.8005253e-01 -8.9236412e-01 5.4907260e-01 -3.9795393e-01
+1 9.4592151e-01 1 1 -2.5692559e-01 -1.8424709e-01 -2.8432234e-01 -1.0814782e+00 -7.8922669e-01 -4.4107053e-04 1.4055534e+00 3.9112087e-02
+1 4.9025651e-01 1 1 1.5415112e+00 9.6959574e-01 -2.4311512e-01 8.5014953e-01 -7.2886690e-01 -1.1298871e+00 1.5008742e+00 7.6398121e-01
+1 2.5535245e-01 1 1 -5.3546371e-01 5.5442436e-01 1.1761817e+00 4.9981173e-01 -9.9624117e-01 9.1453629e-01 1.3455305e+00 5.4308012e-01
+1 5.5834408e-01 1 1 1.1243986e+00 2.4638945e-01 1.1846339e+00 -2.8306601e-01 8.6345259e-01 -1.2014847e+00 1.1468463e+00 1.2208883e+00
+1 3.1190829e-01 1 1 1.0882946e+00 4.4842502e-01 -1.2725869e+00 -1.1191392e+00 1.0312659e+00 8.0393360e-01 1.3742138e+00 -1.4137604e+00
+1 9.1285026e-01 1 1 6.1502829e-01 -1.3843952e-03 -4.0457663e-01 -6.5751897e-01 3.1967293e-01 -2.7791593e-01 -5.7807291e-01 -1.2062346e+00
+1 6.7511770e-01 1 1 9.4066811e-01 -1.2763819e+00 -1.3129439e+00 1.2016318e+00 6.1952421e-01 6.1525732e-01 1.2747368e+00 -4.8738414e-01
+1 3.2395224e-01 1 1 1.3146664e+00 -1.3558978e+00 -1.0106044e-01 -1.4728834e+00 1.1053770e+00 -1.4932335e+00 -1.1604771e+00 -1.3331607e+00
+1 2.1129326e-01 1 1 7.7650900e-01 5.3808083e-01 1.0788839e+00 9.9797652e-01 -1.3082496e+00 1.4087902e+00 -1.1315297e+00 -5.9351325e-01
+1 8.1919925e-01 1 1 6.1095804e-01 -1.1208178e+00 -4.7046409e-01 2.8240964e-02 2.5645760e-01 -6.4719304e-01 -1.5588601e+00 -6.2045354e-01
+1 7.7496548e-01 1 1 -1.4945641e+00 -5.9552172e-01 2.9874059e-01 2.6539543e-01 1.7776341e-02 -1.1795820e+00 1.1206330e+00 -1.0165962e+00
+1 6.0861178e-01 1 1 1.0359042e+00 1.8057140e-01 6.6795863e-01 -5.6056773e-01 3.1566285e-01 1.3568092e+00 6.3157080e-01 1.1901040e+00
+1 7.1725797e-01 1 1 -2.6474712e-01 8.5084176e-02 1.4702101e+00 1.7448472e-01 -8.0450759e-01 -9.2955540e-01 -6.3109778e-01 -4.4165765e-01
+1 4.6295783e-01 1 1 -1.1096863e+00 5.8509633e-01 1.1946796e+00 1.4587886e+00 5.5708682e-02 1.0261839e-01 -8.4356042e-01 6.4335603e-01
+1 4.5249966e-01 1 1 1.1378569e+00 5.2902809e-01 1.0610410e+00 8.7094628e-01 1.0120648e-01 -2.7049379e-02 2.8759772e-01 -4.7714783e-01
+1 6.7916000e-01 1 1 1.0864961e+00 6.6788766e-01 1.2354052e+00 1.3139273e+00 1.3757364e+00 9.1201458e-01 -1.2561680e+00 1.0623983e+00
+1 4.1946612e-01 1 1 -1.3386876e+00 2.7730979e-01 6.6917442e-01 9.2082825e-01 -1.2014371e-01 3.9854041e-01 -9.1276708e-01 -1.0851248e+00
+1 8.8195683e-01 1 1 7.6486087e-01 -1.3778680e+00 -8.7225444e-02 8.7504329e-01 7.8866107e-01 3.9309498e-01 -4.7944050e-01 -7.4747665e-01
+1 4.7369021e-01 1 1 -3.8056120e-01 -1.1488085e+00 1.1257353e+00 1.0573662e+00 6.4717587e-01 -2.1965243e-02 2.2869392e-01 3.8892843e-01
+1 4.4626453e-01 1 1 1.9047884e-01 2.0354742e-01 1.5621605e+00 -8.3523078e-01 8.9105044e-01 1.5380910e+00 1.4908274e+00 -9.3420899e-01
+1 2.9788559e-01 1 1 9.4945066e-02 -1.7295314e-01 9.4162697e-01 -1.0878038e+00 -8.7429357e-02 -1.4703689e+00 -1.0065624e+00 4.2953603e-01
+1 1.1828219e+00 1 1 -1.8733576e-01 -8.5013948e-01 -1.4192656e+00 1.3501988e+00 8.4015837e-01 -7.2269831e-01 1.8268732e-01 -1.6788830e-01
+1 4.3279427e-01 1 1 -6.7633228e-01 -3.3084805e-01 5.1603103e-01 1.0683092e+00 -9.1722747e-01 -9.9325550e-01 1.0898217e+00 -5.4844283e-01
+1 7.1358369e-01 1 1 -8.3446720e-01 5.5866405e-02 -1.0037846e+00 8.7019627e-01 -4.6875537e-02 7.7814217e-01 1.1477519e+00 -2.4580919e-01
+1 7.1334495e-01 1 1 -8.2055687e-01 -3.8953487e-01 -2.5561831e-01 1.2749730e+00 7.0260206e-01 -2.1481798e-01 8.8797989e-01 -1.2064007e-01
+1 6.0496356e-01 1 1 4.9246483e-01 1.6650870e-01 1.5218861e+00 -3.3144788e-01 -6.1396343e-01 -7.5577854e-01 -1.4286228e+00 -1.2703173e+00
+1 1.3904763e+00 1 1 -1.2401847e+00 -6.4728055e-01 -5.0714612e-01 -6.0077321e-01 1.2485366e+00 -9.1076850e-01 3.2885893e-01 4.0648937e-02
+1 9.2404552e-01 1 1 6.8220031e-01 4.9122511e-01 -4.6402832e-01 -1.1659704e-01 1.4566599e+00 -1.4468475e+00 1.0705956e+00 1.4610707e+00
+1 1.0263501e+00 1 1 -1.0725063e+00 -8.5021448e-02 -1.4909886e+00 7.0737051e-01 -3.4784794e-01 -1.2380784e+00 -1.5430485e+00 1.5274748e+00
+1 3.8341469e-01 1 1 8.4606560e-01 4.6918097e-01 1.4384172e+00 9.8951422e-01 2.2353569e-01 1.5265305e+00 -1.6819060e-01 -8.2629034e-01
+1 4.0656596e-01 1 1 9.7620748e-01 1.2699235e-01 9.2285965e-01 -8.2600436e-01 -3.8039724e-01 -9.8903729e-01 6.5395645e-01 1.5193576e+00
+1 5.2448437e-01 1 1 -1.4192709e+00 1.2189856e+00 4.5912867e-01 4.2736565e-02 -1.9532407e-01 -5.8293209e-01 -1.3866951e+00 9.7808107e-01
+1 1.7299982e-01 1 1 4.2645963e-01 1.1647024e+00 8.2394569e-01 -1.1512775e+00 1.5265820e-01 1.2878513e+00 1.2912094e+00 -1.3458948e+00
+1 4.8194273e-01 1 1 1.5341127e+00 -1.1007507e-01 -8.5202307e-02 -4.5231309e-01 -9.5475690e-01 -6.5601558e-01 -7.6518395e-01 -9.8763543e-01
+1 1.4453834e-01 1 1 7.8051427e-01 3.6639664e-01 5.7107474e-01 6.2805336e-01 6.5597395e-01 1.3363860e+00 1.2336984e+00 9.8691110e-01
+1 3.8110364e-01 1 1 -1.1875195e+00 5.0676247e-01 4.8761466e-01 -5.8479917e-02 1.1054777e+00 1.3941024e+00 2.5739967e-01 -5.9438342e-01
+1 8.2896482e-01 1 1 -1.0202485e-01 2.9922818e-01 -1.0755635e+00 4.4653706e-01 3.8431311e-01 6.8079781e-01 1.4319982e-01 4.6253784e-01
+1 4.9512295e-01 1 1 5.7798835e-01 -5.6173666e-01 -2.7150670e-01 -3.1650246e-01 3.5911474e-02 4.8840023e-01 2.9938057e-01 -1.5682772e+00
+1 7.5787033e-01 1 1 4.4568740e-01 -6.2204398e-01 1.5210586e+00 -7.4046573e-01 3.7835133e-01 -4.3894206e-01 -1.1421723e+00 -7.3264588e-02
+1 4.0799750e-01 1 1 1.1111778e+00 5.2715252e-01 1.2923919e+00 -1.1590713e+00 3.6728386e-01 -8.3961328e-01 -1.3595651e+00 1.4638386e-01
+1 1.0052344e+00 1 1 -1.2033906e+00 5.6112207e-01 2.5902282e-01 5.0524005e-01 -2.8973811e-01 6.5378707e-01 -1.4080944e+00 4.0651051e-01
+1 8.9499722e-01 1 1 1.8826082e-01 -2.8250902e-01 -8.5085144e-01 -1.5543090e-01 -1.5971774e-01 -1.0917913e+00 -2.2540098e-01 -7.4183483e-01
+1 3.9652697e-01 1 1 5.1585505e-01 -1.1826114e+00 2.6966330e-01 1.4779378e+00 -1.4559692e+00 3.0608945e-01 4.4650470e-01 9.6321163e-01
+1 9.5015532e-01 1 1 -8.1984315e-01 7.0713250e-01 -1.0871011e+00 -8.7301313e-01 -6.0898204e-01 -1.4833471e+00 -8.6027439e-01 7.0909346e-02
+1 6.5487356e-01 1 1 -7.8468036e-02 1.3085734e-01 5.9520572e-01 -1.4939588e+00 1.4777566e-01 1.0652337e+00 -1.0223375e+00 1.1097596e+00
+1 4.2178760e-01 1 1 6.5663659e-01 2.0450168e-01 7.9151897e-01 -1.3562811e+00 -1.3342272e+00 -5.5306948e-01 -1.0563590e+00 9.4653475e-02
+1 5.5102462e-01 1 1 -3.2389494e-01 1.5740519e-01 1.5560310e+00 3.7989467e-01 3.3148452e-01 5.3390751e-01 -1.0854037e+00 1.1950669e+00
+1 8.2397609e-01 1 1 6.7786903e-01 2.8800099e-01 -1.5453158e+00 1.1733687e+00 1.2166350e+00 9.9486416e-01 8.4917941e-01 1.2871371e+00
+1 4.1354817e-01 1 1 1.5298356e+00 -7.6162806e-01 -5.7614188e-01 1.0308536e+00 -6.4204289e-01 1.1258870e+00 -9.7146303e-02 -9.3147332e-02
+1 4.5431529e-01 1 1 1.1526150e+00 1.3073322e+00 -8.2796249e-01 -3.2698841e-01 5.5589639e-01 9.6970163e-01 8.9026167e-01 -1.0140640e+00
+1 7.3410155e-01 1 1 9.4007079e-01 3.3004417e-02 -1.4517588e+00 -1.0485823e+00 -1.4598271e-01 -8.0741918e-01 -7.7792149e-01 -2.3417131e-01
+1 4.1845273e-01 1 1 7.0024308e-01 -1.3566605e+00 1.0399945e+00 8.1244009e-01 5.2427063e-02 1.3861428e+00 7.8216495e-01 6.9837494e-01
+1 1.0664542e+00 1 1 5.7940879e-01 2.8654512e-01 -6.3401617e-01 1.3189631e+00 1.4956987e+00 -1.1498694e+00 1.4226313e+00 5.9739898e-01
+1 4.3575855e-01 1 1 -8.1375464e-01 -9.7689558e-02 3.7254287e-01 7.3535285e-01 -8.1678280e-01 1.2232062e+00 -4.9778820e-01 -4.5505876e-02
+1 7.3442914e-01 1 1 -1.4214138e+00 1.1845591e+00 1.3383346e-01 4.9855102e-02 1.0914014e+00 -1.5646670e-01 -2.6500516e-01 -1.4102393e+00
+1 7.3676316e-01 1 1 -1.0310769e+00 6.1183439e-01 -4.1314405e-02 -8.9053973e-01 -5.7661482e-01 -2.2271796e-01 8.3667441e-01 1.4241838e+00
+1 5.9868272e-01 1 1 -2.8488610e-01 6.6782001e-01 -7.9225295e-02 -7.5378716e-01 6.4802342e-01 1.5576680e+00 2.1811911e-01 4.6226210e-01
+1 3.3928238e-01 1 1 -2.9350657e-01 -8.5970365e-01 4.9575412e-01 1.1423987e+00 -5.7208463e-01 8.3491947e-01 -3.1074414e-01 8.0528402e-02
+1 5.9444039e-01 1 1 -6.6441130e-01 -8.5471399e-01 6.3585133e-01 -1.1197491e+00 1.3886889e+00 -1.0028717e+00 -1.3497438e+00 -5.8557585e-01
+1 9.1064456e-01 1 1 -1.5404118e+00 1.3251342e+00 -9.4495128e-01 -1.4832206e+00 8.0326436e-01 -6.1967808e-01 2.9622652e-01 8.3638890e-01
+1 1.1098569e+00 1 1 1.6409737e-01 7.7939925e-01 -1.0452912e+00 4.8816677e-02 1.0403960e+00 -5.4989735e-01 -7.4523879e-01 -1.4389108e+00
+1 7.6585338e-01 1 1 -3.3393569e-01 -1.0781305e+00 -4.2353801e-01 5.0621388e-01 -1.6898095e-01 4.4087253e-01 3.0159385e-01 2.0605245e-01
+1 7.5352128e-01 1 1 1.5689142e+00 5.6793600e-01 4.4566538e-01 5.0380667e-01 -6.3089930e-02 -1.2724292e+00 1.4989705e+00 1.0883933e+00
+1 7.4628452e-01 1 1 1.3544207e+00 1.1418294e+00 7.4121322e-01 8.8648761e-01 1.5058601e+00 -8.9593267e-01 7.6600098e-01 -8.6709614e-01
+1 6.6357493e-01 1 1 -2.3139528e-01 -1.2634984e+00 1.1556370e+00 -1.3767105e+00 3.2062129e-01 -2.8675470e-01 -6.8278668e-02 5.6347325e-01
+1 4.2683657e-01 1 1 2.3130221e-01 1.5488545e+00 1.4659997e+00 -5.4356874e-01 8.5062375e-01 -2.8304008e-01 -8.7825487e-01 1.5346121e+00
+1 5.6097959e-01 1 1 1.3460979e+00 3.6040815e-01 -4.5343640e-01 -8.3303215e-03 -9.5478327e-01 -6.8332995e-01 1.5143150e+00 -2.4967995e-01
+1 2.8442802e-01 1 1 1.2582633e+00 3.8922059e-01 5.9820473e-01 1.3639562e+00 2.1288686e-01 9.3619477e-01 1.0498650e+00 7.9679789e-01
+1 5.2308276e-01 1 1 -1.5704980e+00 8.3457006e-01 9.3037063e-01 -1.8998063e-01 -2.8461465e-01 1.5294128e+00 -1.2455738e+00 -8.2740656e-01
+1 3.4817861e-01 1 1 3.0100336e-01 -5.9228065e-01 1.0325590e+00 -1.1462843e+00 1.1272643e+00 3.2909748e-01 1.2147087e+00 -1.5330322e+00
+1 7.7584084e-01 1 1 9.9927141e-01 1.2461621e+00 6.1280918e-02 -1.3547777e+00 -1.0134665e+00 -1.2033904e+00 1.5394094e+00 -1.4700644e+00
+1 1.0280875e+00 1 1 -1.9978578e-01 -7.5218549e-01 -4.9400354e-01 5.1462427e-01 3.8342373e-01 1.9027698e-01 -1.3031308e+00 1.2537939e+00
+1 1.2261533e-01 1 1 5.6297169e-01 -2.1276573e-01 5.1194317e-01 4.8552375e-01 7.9612125e-01 -1.5613593e-01 1.4644900e+00 -1.2886284e+00
+1 1.1871794e+00 1 1 -6.1184774e-01 -8.2115253e-01 -5.9335650e-01 1.4814634e+00 3.6676428e-01 -9.4664908e-01 -6.9531730e-01 1.6197569e-01
+1 1.1911460e+00 1 1 -8.9217879e-01 -9.4125669e-02 -1.1275700e+00 -1.3077210e+00 4.0243042e-01 -1.3058543e+00 5.2678730e-01 -1.4354487e+00
+1 7.1376457e-01 1 1 -2.7220750e-02 1.3925869e+00 -9.8227756e-01 -2.8506475e-01 -2.0099586e-01 -3.2695376e-01 7.0597394e-01 -1.2956935e+00
+1 6.5318362e-01 1 1 1.1733814e+00 3.4204309e-01 -6.9478087e-02 -1.5448603e-01 -9.2527052e-01 -4.6635586e-01 -4.9142142e-01 7.9896807e-01
+1 4.7190768e-01 1 1 1.2432630e+00 -3.9632931e-01 9.5426297e-01 -1.4911222e+00 -1.3791589e-01 2.3069011e-01 -7.2726290e-02 1.0893955e+00
+1 8.6822196e-01 1 1 7.8812546e-01 -9.3027814e-01 4.6728308e-01 -8.0635082e-01 5.4305963e-01 4.8339239e-01 -2.3121520e-01 2.6820004e-01
+1 8.5925695e-01 1 1 1.0700401e+00 5.2189702e-01 -3.5495030e-01 4.9251833e-01 8.7654365e-01 2.1737945e-01 1.1622966e-01 -5.4742660e-01
+1 6.9828479e-01 1 1 -1.4542514e+00 1.9646159e-01 2.3470844e-01 -3.4105308e-01 1.1412248e+00 -1.7576805e-01 -5.9868650e-01 1.1259427e+00
+1 1.0420214e+00 1 1 -1.2556935e-02 1.1600653e-01 -1.0955455e+00 1.3274037e+00 1.1419886e+00 -1.0365225e+00 3.9723114e-01 -1.2349687e+00
+1 1.2088958e+00 1 1 -5.5769311e-01 -1.2073647e+00 4.1982275e-02 1.2240839e+00 1.4129728e+00 -7.0191331e-01 3.7945351e-01 3.8310301e-01
+1 1.1044063e+00 1 1 1.3644215e+00 -6.3097346e-01 -1.2622478e+00 -1.1121698e+00 5.3558438e-01 -3.7657569e-01 4.1994049e-02 -1.4525766e+00
+1 9.5704070e-01 1 1 1.3471822e+00 1.2459390e+00 5.7563693e-01 2.3826284e-01 9.0375560e-01 1.2015430e+00 -1.0643695e+00 -1.3850565e-01
+1 9.9221293e-01 1 1 6.3369731e-01 -1.3590688e+00 -1.3755152e+00 -1.0470399e+00 -1.8015959e-01 1.7483621e-01 -6.3036088e-01 5.5629564e-02
+1 6.7710907e-01 1 1 5.5155317e-01 6.5108066e-01 6.9575201e-01 -1.5383856e+00 5.5306997e-01 1.0830131e+00 -1.0248097e+00 -1.2285219e+00
+1 3.6623369e-01 1 1 -8.8586559e-01 5.4543849e-01 4.9613295e-01 -3.3880700e-01 -5.2571995e-01 -1.8590861e-01 1.3751582e+00 -1.2212874e+00
+1 5.8123524e-01 1 1 -7.3540126e-01 1.7361534e-02 7.1951349e-01 1.3782495e+00 1.5249553e+00 1.3187231e+00 -4.1264595e-01 9.8872869e-01
+1 3.6780291e-01 1 1 -8.6342309e-01 -3.7282143e-01 8.7309431e-01 1.2770966e+00 8.1113201e-01 -1.5784913e-01 1.2960949e+00 -1.4620849e+00
+1 9.7032659e-01 1 1 -5.3534080e-01 1.4676417e+00 -2.8321285e-01 8.0109422e-01 1.3252127e+00 -1.4661898e+00 -3.3619488e-01 2.7730446e-01
+1 9.3697683e-01 1 1 4.8480408e-02 -1.1314921e+00 -4.4549320e-01 -8.7559468e-01 -1.0414393e+00 4.0072545e-01 1.2977665e+00 -1.4673903e+00
+1 1.2243525e+00 1 1 1.1377215e+00 -9.2800010e-01 -9.8890946e-01 -8.9972484e-01 1.4834164e+00 -5.8193818e-01 -5.1626017e-01 -9.2602760e-01
+1 7.7685566e-01 1 1 -1.1896945e+00 1.1098517e+00 1.5653801e+00 -1.1900078e+00 1.0012882e-01 -8.5699437e-01 2.9420033e-01 -2.9589705e-01
+1 7.1159355e-01 1 1 1.0417753e+00 -1.5004494e+00 -1.4948489e+00 -1.0823389e+00 -1.0285822e+00 6.9786448e-01 -2.4191644e-01 -5.7499337e-04
+1 1.1033860e+00 1 1 1.0215053e+00 -4.8945941e-01 -6.0880752e-01 -1.0483641e+00 8.0270218e-01 1.4429674e+00 -6.6872813e-01 -2.3913558e-01
+1 6.8079795e-01 1 1 -3.6363727e-01 1.4868024e+00 -6.0753074e-02 1.3384067e+00 1.0167063e+00 -1.1415416e+00 1.3047539e+00 -1.0546629e+00
+1 4.8372894e-01 1 1 -1.2539333e+00 4.5976582e-01 -5.9296115e-02 7.9798770e-01 6.6089896e-01 -1.8334747e-01 6.8174829e-01 -8.5346016e-01
+1 6.2015923e-01 1 1 -1.0537265e+00 -1.0338600e+00 -7.0494169e-01 3.2030203e-01 -9.4282721e-01 3.8154598e-01 7.5512671e-01 4.0706584e-01
+1 1.1406760e+00 1 1 -8.2316481e-01 6.3971060e-02 -1.0090659e+00 -1.3735114e+00 9.6397335e-02 6.5269605e-01 -6.1962872e-01 -8.3318897e-01
+1 4.2493751e-01 1 1 6.4304615e-01 7.3692435e-01 -1.0526950e+00 -1.8378007e-01 -9.1180811e-01 -5.7897444e-01 2.7975071e-01 -1.3284850e+00
+1 4.3913912e-01 1 1 5.9788941e-01 1.3292694e+00 8.0488473e-01 -6.0604236e-01 -6.9862009e-02 -1.3109417e+00 -1.1940584e+00 -5.4884356e-01
+1 1.0295157e+00 1 1 -1.2275019e+00 1.1650576e+00 -3.4646069e-04 -7.1058294e-01 7.8486502e-01 -1.0070730e+00 -4.5992786e-02 -6.9766563e-01
+1 3.3264605e-01 1 1 2.1498146e-01 -4.2450530e-01 4.6022041e-01 1.5678572e+00 -3.2115973e-01 1.0253791e+00 -1.6896344e-01 -1.2424379e+00
+1 6.7840193e-01 1 1 3.6183724e-01 -1.0366712e-01 3.2339786e-01 -7.0292246e-01 -4.7538507e-01 -1.2311877e+00 2.3126880e-01 5.1323725e-01
+1 7.7793848e-01 1 1 -7.2486154e-01 1.2507086e+00 3.9254996e-01 1.5122428e+00 -7.2668633e-01 1.0997142e+00 7.8454935e-01 -8.3502917e-01
+1 1.0081018e-01 1 1 3.4842294e-01 2.6380821e-01 2.4263075e-01 7.8075382e-01 1.0950321e+00 9.0699485e-01 6.5651195e-01 -8.4090268e-01
+1 8.8784216e-01 1 1 1.5661352e-02 1.0373959e+00 1.0780228e-01 -3.0314434e-01 7.5505093e-01 8.5484453e-01 7.2301033e-01 9.7406523e-01
+1 9.6409553e-01 1 1 -6.7343715e-01 -3.2624847e-01 -8.6600924e-01 7.1637932e-01 1.2481961e+00 8.6873825e-01 -4.5712231e-02 2.7498888e-01
+1 5.5583510e-01 1 1 7.0010925e-01 -1.1789114e+00 -1.8507601e-02 -1.5373501e+00 -1.1234496e+00 -1.2388244e+00 1.4047403e+00 4.5528937e-01
+1 5.7978680e-01 1 1 1.4717093e+00 6.1412550e-02 -3.9580450e-02 1.3564395e+00 -8.4635208e-01 1.5546749e+00 4.0070909e-01 -8.7128778e-01
+1 7.4082153e-01 1 1 1.2599010e+00 -1.4232587e+00 7.8901201e-01 -8.5863743e-01 4.9205388e-01 7.9542494e-01 -8.5699590e-01 -7.7044208e-01
+1 1.9120085e-01 1 1 8.2141618e-01 -6.2330484e-01 2.6230312e-01 1.3572831e+00 1.2777357e+00 1.2302610e+00 6.7221997e-01 8.2483001e-01
+1 3.1295080e-01 1 1 1.3836498e+00 1.3270544e+00 8.7412049e-01 7.5232811e-01 -1.0241333e+00 -9.6616003e-01 8.3377168e-01 -9.3041026e-01
+1 5.3300687e-01 1 1 9.3275456e-01 -1.5038689e+00 1.2557816e+00 -5.3196207e-01 1.7700426e-01 6.4088457e-01 -1.4442373e+00 1.4430384e+00
+1 4.3708061e-01 1 1 2.5852258e-01 -1.4118743e+00 7.0223464e-01 2.8626292e-01 -1.7765026e-01 -1.1742166e+00 -1.3522951e+00 5.1604568e-02
+1 7.5905559e-01 1 1 1.6628695e-01 -9.2202272e-01 -5.0604163e-01 1.4425879e+00 -1.2549388e+00 4.2665099e-01 1.3987038e+00 2.3839634e-01
+1 3.5929473e-01 1 1 -1.2326254e+00 1.0407270e+00 -7.5032273e-01 -1.2372023e+00 8.9624057e-01 -1.5328864e+00 -5.2361469e-01 1.1966955e+00
+1 8.0057910e-01 1 1 -1.0730579e+00 -8.8875682e-01 -3.2118788e-01 5.4191277e-01 -8.2147536e-01 9.7985977e-01 -7.9114099e-01 3.8550941e-01
+1 6.7028427e-01 1 1 9.9965010e-01 9.3718918e-01 -9.4846862e-01 4.5074172e-01 7.6333888e-01 2.7451604e-01 -1.4865557e+00 1.2925662e+00
+1 9.7362381e-01 1 1 -1.1828730e-01 -6.0697493e-01 -4.7090308e-01 1.2361658e+00 -8.2784411e-01 -1.2084733e+00 5.4439849e-01 4.7592788e-02
+1 4.2506163e-01 1 1 5.7357937e-01 -6.7636131e-01 -7.9622034e-01 8.8572245e-01 5.3789179e-01 -4.1467899e-01 1.3876347e+00 -1.2141321e+00
+1 8.4172264e-01 1 1 -1.3994176e+00 -1.3222785e+00 1.1094592e+00 1.4711793e+00 -1.1563177e+00 -1.4572192e+00 -1.2081498e+00 -1.2739040e+00
+1 5.6438522e-01 1 1 1.0926789e+00 9.1394825e-02 1.3285736e+00 -1.3655188e+00 -3.3907507e-01 3.7325903e-01 -1.2604892e+00 -5.5044842e-01
+1 8.9877164e-01 1 1 -1.0958531e+00 -1.6598895e-01 -1.1036706e+00 -9.3984473e-01 1.4324366e-02 -3.9594033e-01 -1.2822428e+00 6.0384937e-01
+1 6.9361472e-01 1 1 1.1543184e+00 -4.2035852e-02 -1.4289937e+00 -4.2537915e-02 -1.1530073e+00 -6.7580826e-01 6.7039760e-01 1.5520089e+00
+1 8.0501811e-01 1 1 1.2947785e+00 3.6178847e-01 3.7890231e-01 1.3483895e+00 -1.2499604e+00 -1.4519150e+00 -1.5203969e+00 -3.0181892e-02
+1 4.7644421e-01 1 1 -4.7016643e-01 -1.5445518e+00 2.0285638e-01 -1.0674262e+00 -2.5379320e-01 1.5559870e+00 4.0328092e-01 -1.4706462e+00
+1 1.9106412e-01 1 1 -9.8169867e-01 -3.0119910e-01 7.7910692e-01 1.4036173e+00 7.8044028e-01 8.5578222e-01 1.5270051e+00 8.9999566e-01
+1 2.4284916e-01 1 1 2.3509650e-01 -1.1474547e+00 2.9175727e-01 3.7708103e-01 7.1047392e-01 9.2062122e-01 7.0366462e-01 -5.4150940e-01
+1 4.9814285e-01 1 1 -8.5676225e-01 9.6616614e-01 -4.6169723e-01 1.0085488e+00 -2.5843373e-01 5.3709549e-01 1.5364917e+00 4.5470150e-02
+1 9.9697650e-01 1 1 1.4576068e+00 -5.3818357e-01 -1.1573573e-02 -1.3551029e+00 1.3269714e+00 1.1682568e+00 -7.5373152e-02 8.0979375e-01
+1 8.6770888e-01 1 1 -1.4209787e-01 -6.0599492e-01 2.6170590e-01 1.3324541e+00 2.4141301e-01 -6.2356255e-02 -7.3472887e-01 8.2417792e-01
+1 6.2064750e-01 1 1 -6.2855517e-01 8.6782041e-02 2.6136914e-01 1.2844320e+00 -1.5092280e+00 1.2703713e+00 1.0125235e+00 6.7633488e-01
+1 4.4538615e-01 1 1 1.0493591e+00 8.4676583e-01 8.8454164e-01 1.5649079e+00 -3.7616300e-01 8.6669487e-01 -5.2411590e-01 8.7806042e-01
+1 6.5876517e-01 1 1 -3.2260462e-01 1.7860462e-01 4.7497741e-01 -6.8643883e-03 -1.2871678e+00 -1.0244024e+00 2.0986815e-01 1.5007066e+00
+1 9.4366092e-01 1 1 3.7300709e-01 -1.5546482e+00 1.5838461e-01 8.6915348e-01 -4.2195585e-01 -1.2032468e+00 -7.5450923e-01 -1.4718995e+00
+1 6.0978493e-01 1 1 -1.4888155e+00 -3.4547801e-01 1.0411127e+00 -5.4333274e-01 -1.2373948e+00 -5.3773147e-01 -1.5687036e+00 -1.3149231e+00
+1 1.0262904e+00 1 1 2.6368631e-01 -7.8565332e-01 -6.8933782e-01 8.1646989e-01 4.4937045e-01 7.0916954e-01 -9.5520146e-01 1.1911689e+00
+1 8.5055926e-01 1 1 -1.0114608e+00 -3.6148907e-01 4.9299457e-01 -6.7210587e-02 1.8044227e-01 -1.9000292e-01 -5.3241858e-01 -1.3947832e+00
+1 5.6222192e-01 1 1 -4.6412031e-01 2.9346969e-01 1.3798750e+00 1.3650172e+00 1.0562607e+00 -1.5208959e+00 -1.1032534e+00 4.4231583e-01
+1 6.8164122e-01 1 1 1.0443390e-01 4.4640131e-02 3.2213907e-01 -1.2071315e+00 -5.6695884e-01 1.4420561e+00 -7.0050594e-01 9.9402038e-01
+1 5.1414703e-01 1 1 -9.2973851e-01 -5.7396088e-01 1.2271691e+00 1.4681591e-01 -4.2668035e-01 -7.5046042e-01 1.2859861e+00 -4.8916006e-01
+1 7.9390038e-01 1 1 1.6672154e-01 1.2704903e+00 4.7526511e-01 1.3847803e+00 1.0393954e+00 5.0622689e-01 -5.8958848e-01 2.3485977e-01
+1 7.3852964e-01 1 1 -2.1174590e-01 -2.7514182e-01 -1.2894939e+00 1.0838184e+00 -1.2781409e+00 7.2236286e-01 -6.3030181e-01 1.4478349e+00
+1 4.9967980e-01 1 1 6.1118238e-01 1.1575399e-01 1.3234742e+00 7.8170658e-01 4.9699070e-01 -1.5030115e+00 -3.2049778e-02 -1.0154185e+00
+1 6.9843875e-01 1 1 -8.6567521e-01 8.3146875e-01 1.1549579e+00 1.9874525e-03 -5.7217459e-01 4.3193263e-01 -1.4482795e+00 -1.0066987e+00
+1 6.9866819e-01 1 1 -6.8773206e-01 6.9119589e-01 -5.2395803e-01 -1.1544054e+00 -1.2323110e-01 -7.2885149e-01 -1.7358875e-01 1.0330420e+00
+1 6.3356335e-01 1 1 -7.9327632e-01 -6.8029266e-01 -2.7843906e-01 3.8473250e-01 -8.3560557e-01 -7.3726352e-01 1.0333845e+00 -1.2456430e+00
+1 6.0918083e-01 1 1 3.2407561e-01 -1.4230729e+00 1.2477280e+00 8.0137847e-01 -1.1036543e+00 -7.4654292e-01 1.3688888e+00 5.2075288e-02
+1 3.9330069e-01 1 1 -7.8283621e-01 -6.4197072e-01 4.3291204e-01 7.6026562e-01 -1.1551653e+00 3.7422909e-01 1.0309396e+00 -1.2749868e+00
+1 4.2011378e-01 1 1 -1.3815142e-01 -1.3727574e+00 2.3989793e-02 9.2699488e-01 1.7892910e-01 1.9978834e-01 1.1188411e+00 1.0032760e-01
+1 6.1512383e-01 1 1 -2.7387266e-01 -7.6350320e-02 1.0725924e+00 8.4490992e-01 7.5726356e-01 -5.1989481e-01 -1.2116499e+00 -8.2930661e-01
+1 7.3306046e-01 1 1 -5.4456603e-01 -1.4500254e+00 6.0160793e-01 4.0216893e-01 7.3675583e-01 -1.1028184e+00 -3.9592214e-01 1.0904008e+00
+1 7.5440247e-01 1 1 -1.0618738e+00 -1.2428024e+00 -1.5623405e+00 -1.4541554e+00 -1.5029622e+00 3.2833983e-01 -3.7009021e-01 1.4564326e+00
+1 1.0830810e+00 1 1 4.7411886e-01 6.7030899e-01 -8.2456286e-01 -1.5403645e+00 1.2613348e+00 -1.3706902e+00 2.4723978e-01 -1.0273128e+00
+1 8.9233043e-01 1 1 1.4366726e+00 1.3189595e-01 -8.6277180e-01 9.5883150e-01 -2.1297863e-01 1.0901660e-01 -9.6804342e-01 1.4631612e-01
+1 6.5577478e-01 1 1 -1.2427460e-01 -1.1892031e+00 9.8598372e-01 -1.2892119e+00 -1.2577198e+00 6.9351145e-01 4.0257712e-01 -7.3197817e-01
+1 1.0604584e+00 1 1 4.7597776e-01 -1.2414063e-01 -4.7285241e-01 -2.1918822e-01 1.2794707e+00 5.3815319e-01 -8.7690390e-01 1.1977152e-01
+1 4.5911388e-01 1 1 1.2632418e+00 -4.1408536e-01 9.9889228e-01 1.1917307e+00 -1.3716054e-01 9.5440378e-02 -9.1267788e-01 -7.6101669e-01
+1 1.0829513e+00 1 1 4.2098708e-01 -9.0485417e-01 -2.8858668e-01 -1.3767732e+00 6.7175736e-01 -1.2874070e+00 1.0198417e+00 -9.8375027e-01
+1 8.5752121e-01 1 1 6.6320455e-01 5.6603242e-01 3.4274728e-01 1.5437958e+00 -6.5800310e-01 -1.3007743e+00 -5.0136902e-02 3.1128889e-01
+1 8.5020369e-01 1 1 1.0817937e-01 5.6434060e-01 -1.1273499e+00 1.6212554e-01 -6.5201830e-01 2.2983575e-01 -7.0408773e-01 1.0805992e+00
+1 8.2734144e-01 1 1 -8.1145840e-01 4.0421650e-01 -4.2373282e-01 1.0830986e+00 -5.9636256e-01 -1.3094943e+00 7.7705935e-01 8.3228346e-02
+1 4.6031741e-01 1 1 -5.2756900e-01 1.5433840e+00 3.1297207e-01 1.2497909e+00 -1.3849569e+00 1.3272128e+00 4.3590886e-01 8.1008670e-01
+1 1.4233536e-01 1 1 -1.2777588e+00 -4.7529099e-01 1.0954371e+00 5.4754140e-01 -9.1017900e-01 1.1580712e+00 1.2618184e-01 -5.3540773e-01
+1 4.9316706e-01 1 1 6.3587586e-01 8.5449604e-01 1.2789235e+00 8.0339532e-01 -9.6374475e-01 1.5369292e+00 1.6320045e-01 -1.0764361e+00
+1 8.5876881e-01 1 1 -5.3267203e-01 1.2948930e+00 8.9767764e-02 9.9904419e-02 3.9370404e-01 9.9500051e-01 2.9957591e-01 7.7052230e-01
+1 9.2564656e-01 1 1 9.2018836e-01 1.4545738e+00 7.6234055e-01 1.4830889e+00 7.8974625e-01 2.7585192e-01 -1.0006276e+00 5.2341262e-01
+1 7.7140715e-01 1 1 -4.5482021e-01 -8.5248049e-01 1.2427235e+00 8.7829944e-01 3.6255810e-02 -7.4751575e-01 -6.0291018e-01 5.3649485e-01
+1 6.7066788e-01 1 1 -6.6830538e-01 1.1644804e+00 1.1454400e+00 -7.6516563e-01 -1.1758209e-01 -2.6821538e-01 -1.4750961e+00 4.9797123e-01
+1 5.4455068e-01 1 1 -1.0148211e+00 -7.0085370e-01 -2.6914532e-01 1.5415309e+00 -1.4032844e-01 2.8955538e-01 1.5091218e+00 1.9967265e-01
+1 9.4027388e-01 1 1 -3.9116898e-01 -1.4173303e+00 3.6800949e-01 -2.0407656e-01 8.3594788e-01 2.3021358e-01 -1.4095116e+00 6.7726324e-01
+1 1.2029087e+00 1 1 9.7630300e-01 -1.5148980e+00 -6.6035853e-01 7.0439471e-01 5.7369213e-01 -1.2425515e+00 1.0879855e+00 7.7302747e-01
+1 7.7281259e-01 1 1 1.8610531e-01 -1.4244887e+00 6.0097803e-01 1.2407641e+00 4.9581790e-01 -1.3965293e+00 -1.4382746e+00 -1.3545961e+00
+1 5.1708262e-01 1 1 -1.1543859e+00 6.9676524e-01 4.1739348e-01 -3.6992992e-01 -1.4338350e+00 -6.2962696e-01 1.4746445e+00 4.2509789e-01
+1 8.7408157e-01 1 1 7.1196439e-01 -1.3240134e+00 -4.4165972e-02 -2.0027716e-01 6.9311248e-01 -1.2561925e+00 3.2539563e-01 6.3857519e-01
+1 6.0623241e-01 1 1 -3.4083425e-01 -7.9164402e-01 -8.8161760e-01 -1.4125083e+00 1.1592440e-01 -1.3246283e+00 -5.8842917e-01 8.5268846e-01
+1 5.8602438e-01 1 1 -1.2778957e+00 -5.1608396e-01 1.5454926e+00 9.8805549e-01 5.5397274e-01 1.4385358e+00 4.6639840e-03 -8.1079671e-01
+1 4.7939793e-01 1 1 1.4755351e+00 1.1426658e-01 4.0528083e-01 -2.1008478e-01 -1.0607841e+00 -2.2605818e-01 -1.5223742e-01 1.1685956e+00
+1 7.7779209e-01 1 1 -4.1435754e-01 9.6530583e-01 5.8202169e-01 2.5517063e-01 -6.0875729e-02 -1.1743737e+00 -1.3978633e+00 -6.5174586e-01
+1 1.1123015e+00 1 1 8.0369853e-01 7.1069808e-01 -8.8103430e-01 3.7884477e-01 1.0208265e+00 9.2867790e-01 -1.0590637e+00 8.4088182e-01
+1 7.6081052e-01 1 1 -1.0872262e+00 3.6743093e-01 -1.2173703e+00 -7.6425907e-01 7.9431653e-01 8.5709245e-01 5.8108499e-01 -1.3246059e+00
+1 1.6444067e-01 1 1 -1.5073250e+00 -9.5947474e-01 8.4982187e-01 1.0701478e+00 1.4507107e+00 9.5044112e-01 -9.1619793e-01 -1.3250523e+00
+1 4.6291553e-01 1 1 1.9185966e-01 -9.6907299e-02 1.2759416e+00 3.5539582e-01 1.9448317e-01 -9.3472269e-01 1.5484975e+00 5.9689745e-01
+1 3.2316258e-01 1 1 1.3112480e+00 -1.3759794e+00 2.3910343e-01 9.6996085e-01 1.4222506e+00 1.2206929e+00 6.4442394e-01 9.5004490e-01
+1 7.9300840e-01 1 1 -1.2761296e-01 -8.2147059e-01 5.1428400e-01 4.0777762e-01 -6.1314334e-01 -1.5564853e+00 -1.3782960e+00 -1.3108749e+00
+1 6.5914651e-01 1 1 9.1682832e-01 8.4346877e-01 1.0497852e+00 -1.4367491e+00 -6.7627357e-01 1.9282787e-01 1.0840471e+00 1.1413084e-01
+1 7.3948430e-01 1 1 -3.7840207e-01 1.3136274e+00 5.5498030e-01 -1.1615656e+00 1.5231806e-01 -1.2656451e+00 1.4845048e+00 -1.3161218e+00
+1 1.0898701e+00 1 1 -1.2201177e+00 -9.7715687e-01 1.6528821e-01 -5.7558674e-01 -3.8830722e-01 2.6137079e-02 -4.5687137e-01 -1.0556314e-01
+1 5.7728310e-01 1 1 -1.3430090e+00 1.1709111e+00 8.3103317e-01 -9.2248838e-01 -1.1914258e+00 -5.3708723e-01 -5.8463846e-01 8.0021311e-01
+1 9.8313840e-01 1 1 3.9154951e-01 5.6704421e-01 -3.4650130e-01 -5.0250890e-01 2.1875397e-01 -1.0294617e+00 8.8323148e-01 2.3557732e-02
+1 6.5487198e-01 1 1 -8.6402126e-01 -1.2800487e+00 8.6550471e-01 -1.0660037e+00 9.3449000e-01 -1.4116348e+00 4.4619018e-01 9.4125920e-02
+1 2.3907820e-01 1 1 -1.1641231e+00 -1.5271085e-01 9.6362990e-01 1.7906461e-01 1.1516914e+00 -3.8729402e-02 1.3664912e-01 -1.3883578e+00
+1 5.8260834e-01 1 1 4.2293556e-01 6.9861267e-02 8.1751791e-01 -1.0681082e-01 1.1244960e+00 -6.1538409e-01 1.5748516e-01 -1.5217125e+00
+1 1.0025415e+00 1 1 -1.1462424e+00 -7.9733076e-01 -1.3027209e+00 -1.3199956e+00 -4.1694185e-01 -6.3732673e-01 -1.5096026e+00 2.8359457e-01
+1 1.1421564e+00 1 1 -6.5057387e-01 1.2961260e+00 -1.0712562e+00 7.6211019e-01 1.3514625e+00 1.2805515e+00 -3.8911219e-01 5.7786273e-01
+1 1.0340395e+00 1 1 -1.4526718e+00 1.8667788e-01 -1.3533950e-01 5.1275634e-01 3.1551645e-01 -8.2302258e-01 9.8727246e-01 1.4760454e+00
+1 9.2250499e-01 1 1 1.4029724e+00 -9.5600374e-01 -1.3794273e-01 5.0707909e-01 -1.2346081e-01 -1.0809892e-01 -8.0419484e-01 -1.2615242e+00
+1 8.8640043e-01 1 1 -1.0367480e+00 -1.4499987e+00 9.1834158e-02 -6.6260930e-01 -1.5547051e+00 -9.7800684e-01 -9.7108835e-01 1.7199580e-01
+1 8.8190675e-01 1 1 -1.3502999e+00 -7.9371598e-01 9.3470081e-01 4.7145294e-01 -1.3031274e+00 -5.4816461e-01 -5.0814252e-01 4.6824625e-01
+1 5.8154712e-01 1 1 3.7484445e-01 -7.8204793e-01 1.5531727e+00 6.1281149e-01 1.5224422e+00 1.2887024e+00 -1.5025736e+00 1.2511987e-01
+1 2.7793066e-01 1 1 1.1173972e+00 5.4410398e-01 6.7948001e-01 1.3819855e+00 -5.8672296e-01 1.0816481e+00 1.5086252e+00 1.1642220e+00
+1 8.2568154e-01 1 1 -3.4646462e-01 -4.2058236e-01 3.3119372e-01 1.2362233e+00 4.0660383e-01 -1.1364970e+00 -3.3021665e-01 1.2408108e+00
+1 1.0617826e+00 1 1 1.4818582e+00 -1.4427405e-01 -5.2937624e-01 -1.2883859e+00 8.2648840e-01 -2.2107800e-01 1.2429762e+00 4.1585446e-01
+1 2.3634223e-01 1 1 -9.5502502e-01 4.9552599e-01 -2.3600406e-01 1.0955254e+00 -1.3321789e+00 8.4619820e-01 -8.8936107e-01 -7.7779216e-01
+1 6.8561502e-01 1 1 -7.0861507e-01 -5.6890692e-02 1.3112048e+00 -3.7961459e-01 1.9997079e-01 6.3155279e-02 2.0629603e-01 -1.8574144e-01
+1 1.1125085e+00 1 1 8.4314409e-02 -1.1176929e+00 -8.5323230e-01 3.9231953e-01 -5.9513598e-01 -4.0754703e-01 -1.1009633e+00 9.8669249e-01
+1 6.2081531e-01 1 1 2.1399276e-01 -1.4812993e+00 1.0952592e+00 -4.8856575e-01 3.8055591e-01 -9.7094242e-01 9.0465740e-02 -1.1269886e+00
+1 6.5118747e-01 1 1 -5.4725611e-01 9.2491776e-01 1.4303114e+00 7.9868247e-01 -2.7941097e-01 -1.1970081e+00 -7.3151285e-02 -6.3504407e-01
+1 9.2145367e-01 1 1 8.4989735e-01 4.9234960e-01 -2.2326938e-01 -5.6915884e-01 6.2077347e-01 6.4500031e-01 -1.0909252e+00 -1.1954400e+00
+1 1.0272082e+00 1 1 -5.9704657e-01 -3.5355480e-02 -1.4269225e+00 2.9697262e-01 1.1052263e-01 -1.1161098e+00 -8.4481195e-01 -1.2748106e+00
+1 8.4530688e-01 1 1 -3.1470584e-01 -4.5854285e-01 6.3185962e-01 -7.7188339e-01 8.7259648e-01 -8.0144190e-03 1.2442926e+00 -8.0196244e-02
+1 5.9601915e-01 1 1 1.1809424e+00 -4.0282748e-01 1.0815240e+00 -1.4080825e+00 7.7446994e-01 3.9014470e-01 -7.5612714e-01 -1.1502195e-01
+1 8.8466545e-01 1 1 -4.8266261e-01 -1.8922031e-01 -8.1920464e-02 -2.5432758e-02 8.9791247e-01 6.5816028e-01 -4.8660531e-01 -1.0943970e+00
+1 8.7528075e-01 1 1 -5.1824581e-01 -9.3406367e-01 -8.1965560e-01 -1.9176963e-01 -9.9630356e-01 1.5205672e-01 -8.0981282e-01 4.9522360e-01
+1 8.0622819e-01 1 1 1.4790325e+00 -2.6965615e-01 -6.7875074e-02 2.0185225e-01 -1.8509587e-01 1.5024617e+00 -1.1446237e+00 1.1440579e+00
+1 6.5369962e-01 1 1 -1.3240422e+00 1.2072590e+00 -3.7823197e-01 -3.8923455e-01 -7.2963808e-01 -2.4800745e-01 1.4222714e+00 -1.5068883e+00
+1 6.5575241e-01 1 1 -1.2766278e+00 -1.1444483e+00 -1.5028508e+00 -1.0691080e+00 -1.3911452e+00 6.3222257e-01 -2.6282400e-01 1.2477760e+00
+1 4.3346126e-01 1 1 7.9436506e-01 1.2291835e+00 -8.5277657e-03 1.4123586e+00 -1.2450927e+00 8.9846348e-01 -2.0376087e-01 1.2404316e+00
+1 7.5909329e-01 1 1 -8.7527321e-01 -2.2652564e-01 1.1871041e+00 -3.6390364e-01 -1.2489170e-01 -1.1601901e+00 -2.7295734e-01 3.2425061e-01
+1 6.1646613e-01 1 1 1.3616109e+00 3.9388827e-01 -5.9560589e-01 5.5235376e-01 -4.7088993e-01 5.5021046e-01 -8.6872068e-01 -9.8327574e-01
+1 5.4963991e-01 1 1 1.2329629e+00 7.4435401e-01 -1.2339831e+00 3.2916352e-03 -5.7513166e-01 -1.4615473e+00 1.5342158e+00 -1.1379461e+00
+1 6.2620086e-01 1 1 4.6183478e-01 5.3591828e-01 1.2411040e+00 -1.2261555e+00 4.4278492e-01 -1.1317833e-01 -6.2794672e-01 5.5628155e-01
+1 1.1771503e+00 1 1 -8.1827533e-01 2.3241664e-01 -9.3982183e-01 8.5252476e-01 -5.4677756e-01 -1.5245681e+00 -1.2907258e+00 4.4265241e-02
+1 6.2401754e-01 1 1 1.1391830e+00 1.2267756e+00 3.4244947e-01 -4.2037140e-01 -5.3194393e-01 -5.8555216e-01 -5.3067567e-01 -5.9155707e-01
+1 8.1667838e-01 1 1 1.3835795e+00 1.4450094e-01 1.5045856e-01 2.5983807e-01 5.9104665e-01 1.2346042e+00 -8.4419127e-02 8.4114407e-01
+1 7.9277083e-01 1 1 -2.4772917e-01 1.7614475e-01 -2.2505547e-01 2.8469476e-01 5.0636634e-03 -2.2620338e-01 1.1676189e+00 -5.8611771e-02
+1 4.6950434e-01 1 1 -9.7387499e-01 1.0845085e+00 -2.9685138e-02 2.1928177e-01 2.8198996e-01 -4.7316532e-01 -1.3578468e+00 1.3720550e+00
+1 7.5852363e-01 1 1 -2.1927829e-01 -1.8599097e-01 5.9511824e-01 3.8045273e-01 -1.2581089e+00 -1.1184604e+00 -8.0141643e-01 8.3839999e-01
+1 1.1039746e+00 1 1 -3.2198421e-01 -6.5589096e-02 -6.7867649e-01 1.1279190e+00 1.0246320e+00 1.3262920e+00 -1.3981576e+00 9.4564350e-01
+1 4.4437292e-01 1 1 1.3754912e+00 3.4308398e-01 6.0713804e-01 5.6458081e-01 -1.2203281e+00 1.3896548e+00 2.7819676e-01 1.1314686e-01
+1 3.5117412e-01 1 1 -1.1003600e+00 1.3899885e+00 2.7605191e-01 1.2999264e+00 1.4042819e+00 1.3291652e+00 9.6314254e-01 9.9572059e-01
+1 9.6657347e-01 1 1 8.0498378e-01 6.5290878e-01 -5.2788187e-01 1.2274230e+00 -1.0200085e+00 -5.8597363e-01 -1.0902488e+00 -1.8817552e-01
+1 1.1635774e+00 1 1 -1.4772092e+00 -1.4525925e-01 -2.5292871e-01 -1.5411693e+00 3.8826511e-01 4.3422332e-01 1.0985038e+00 9.1777915e-01
+1 1.1403307e+00 1 1 5.5139512e-01 -3.5468087e-01 -3.9790051e-01 -1.2353912e-03 4.8373054e-01 7.1537107e-02 -5.8690243e-01 -1.0582382e-01
+1 5.1749282e-01 1 1 -4.0058261e-01 -1.5200437e+00 9.3686686e-01 1.2279293e+00 -3.8260726e-01 -9.0582252e-01 5.3178174e-01 -4.3949719e-01
+1 7.5812719e-01 1 1 -1.5885565e-01 5.6616781e-02 2.5899681e-01 6.8574008e-01 3.5988155e-01 -1.1750195e-03 -1.7544397e-01 -7.4493987e-01
+1 1.1409248e+00 1 1 4.6676286e-01 -3.4433549e-01 -1.2880622e+00 -1.2699470e+00 9.6339483e-01 -8.9899613e-01 1.2686277e+00 -9.5762659e-01
+1 8.7064958e-01 1 1 3.2654734e-01 -4.3287556e-01 2.5411631e-01 -1.9573571e-02 8.3797842e-03 -1.5088475e+00 -1.6283489e-01 -4.5093163e-01
+1 2.8371636e-01 1 1 -8.1145038e-02 5.8899529e-01 1.5083594e+00 8.9421956e-01 -5.3263620e-01 -2.6326658e-01 -4.3874813e-01 -1.2864180e+00
+1 7.6379827e-01 1 1 -3.5344849e-01 8.5386718e-02 1.4853890e+00 -2.3108951e-01 1.5225026e+00 -1.3590098e+00 -7.2181985e-01 -3.8634550e-01
+1 1.1408788e+00 1 1 3.4290839e-01 -6.1327064e-01 -1.3039725e+00 -9.1287443e-01 4.2858353e-01 -1.4985634e+00 1.2046572e+00 3.6316087e-01
+1 9.8240252e-01 1 1 -1.5611963e+00 3.2593205e-01 -1.1608570e-01 8.5801247e-01 -4.6856980e-01 -2.0689489e-01 -8.9094470e-01 -4.6972395e-01
+1 1.1585792e+00 1 1 -4.4405066e-01 -9.9757369e-01 -1.2332266e-01 7.0533453e-01 7.2022315e-01 4.6069881e-01 -1.2769958e+00 1.7185371e-01
+1 5.7389757e-01 1 1 1.2646318e+00 4.5899655e-01 7.6721774e-01 1.3283232e+00 2.3405472e-01 -1.0610743e+00 8.9188644e-01 1.2216042e+00
+1 3.6020428e-01 1 1 -1.3495750e+00 -1.3965055e+00 1.5323519e+00 9.7034718e-01 4.8366194e-01 1.3464584e+00 1.3969118e+00 1.1933377e+00
+1 4.5578435e-01 1 1 -8.1187850e-03 -2.3005933e-01 -5.3779290e-01 6.1754786e-01 -1.5356024e+00 1.0343634e+00 7.7426553e-01 4.9895596e-01
+1 6.9352722e-01 1 1 -1.3639353e+00 6.9346456e-01 -3.2327427e-01 -6.9527901e-01 -6.8638562e-01 -1.0285419e+00 6.0404963e-01 1.0420608e+00
+1 5.4686160e-01 1 1 5.4084089e-01 -2.4991780e-01 -1.4568876e+00 1.1703589e+00 -1.5494622e-01 1.4809910e+00 -1.3652783e+00 -4.6401629e-01
+1 6.5290947e-01 1 1 1.2852584e+00 -5.9080631e-02 -3.3678028e-01 7.1101509e-01 1.9911713e-01 1.7778016e-01 -3.9463266e-02 -1.2887584e+00
+1 7.8376058e-01 1 1 -2.5388196e-01 -2.2487950e-01 8.8382777e-01 -5.8784175e-01 7.6537185e-01 2.9654771e-01 -3.8306702e-01 1.1189407e+00
+1 6.0479893e-01 1 1 -7.1134280e-01 -2.1387248e-01 1.0431811e+00 4.5255773e-01 -1.2172291e+00 1.5113516e+00 -1.0840464e+00 4.6348043e-01
+1 8.2127691e-01 1 1 1.3632340e+00 -5.7282086e-01 -4.8398145e-01 3.4193465e-01 8.2277094e-02 1.5094181e+00 -1.4722603e+00 -1.4341990e+00
+1 1.2682108e+00 1 1 2.3883785e-01 -1.5603197e+00 -6.9286011e-01 9.2268321e-01 5.3035355e-01 4.2988203e-01 -1.0956456e+00 8.5701948e-01
+1 4.7454454e-01 1 1 -8.0759694e-01 -1.4186614e+00 9.8410565e-01 6.3542350e-01 9.5378391e-01 -6.3589058e-01 1.5002571e+00 -2.7587327e-01
+1 3.0423300e-01 1 1 1.5401615e+00 1.2463341e+00 -6.2168681e-01 1.2893304e+00 -1.3011230e+00 2.8517663e-01 3.9780224e-01 3.8876298e-01
+1 1.0957796e+00 1 1 -1.2287218e+00 -1.0027339e+00 2.4694776e-01 -9.2926245e-01 6.5198279e-01 -1.1067218e+00 5.5310091e-01 -5.7331298e-01
+1 1.0959901e+00 1 1 -1.4380200e+00 -1.4450767e+00 4.0710597e-01 -1.2568935e+00 -4.6869189e-04 6.9617867e-01 -5.7238989e-03 -4.0659902e-01
+1 5.7474077e-01 1 1 -5.2993887e-01 2.4887285e-01 -1.5868655e-01 -5.4010591e-01 1.5474734e+00 1.3838724e+00 1.1878041e+00 -7.4567006e-01
+1 6.5207582e-01 1 1 -2.6748790e-01 1.3461750e+00 1.6735960e-01 -1.4988891e+00 -8.6039423e-01 1.5331468e+00 -1.3975361e+00 -6.6364466e-01
+1 4.1266335e-01 1 1 -5.0109685e-02 -5.8637576e-01 1.0873098e+00 6.0232945e-01 1.0514022e-01 2.5554775e-01 1.2989492e+00 -1.2219496e+00
+1 3.8635644e-01 1 1 -2.4664168e-01 -4.1212314e-02 -2.2935138e-01 1.1395170e+00 1.5166327e+00 4.3393653e-01 5.1146258e-01 -7.1495957e-01
+1 7.7346341e-01 1 1 -1.5459963e+00 -1.5049711e+00 2.5584106e-02 7.1297819e-01 -8.3777783e-01 1.5347335e+00 7.5403803e-01 2.6632746e-01
+1 1.1164306e+00 1 1 5.5220886e-01 -1.0873467e+00 -4.0612302e-01 9.8997985e-01 8.6222352e-02 -1.3514148e+00 -6.7668921e-02 -6.0386206e-01
+1 4.2549743e-01 1 1 7.0958953e-01 -3.9140328e-01 9.7125030e-01 7.1664148e-01 8.6484992e-01 4.8595460e-01 -5.5011948e-02 1.3761909e+00
+1 5.1454789e-01 1 1 5.8559403e-01 1.8007319e-01 8.8310840e-02 -2.7295419e-01 -6.1665489e-01 -7.0189809e-01 -9.5757290e-01 1.2350980e+00
+1 5.2806546e-01 1 1 -5.3086755e-01 1.1363251e+00 1.4085516e+00 -8.1578430e-01 -4.5444475e-03 -1.2074521e-01 4.5139638e-01 -1.3523617e+00
+1 4.6426947e-01 1 1 -1.6783957e-01 4.7425721e-01 -1.5150456e+00 -9.7636326e-01 -9.8030529e-01 1.0413949e-01 -3.2733038e-01 2.7968820e-01
+1 3.5876145e-01 1 1 2.7063270e-01 6.2029755e-01 -7.6210361e-01 -1.1989039e+00 -1.4791853e+00 4.0535823e-01 -5.1289126e-01 8.9696961e-01
+1 6.7143533e-01 1 1 -5.0236291e-01 1.5364489e+00 -4.0213823e-01 1.9755359e-01 -1.2453515e+00 -1.2586588e+00 3.6690395e-01 -1.1349058e+00
+1 4.8672042e-01 1 1 1.3876332e+00 -7.9536201e-01 -1.1714981e+00 -3.8031229e-01 -1.3321468e+00 1.2061477e+00 -3.9166860e-01 1.3886170e+00
+1 1.1585631e+00 1 1 -1.2331059e+00 -1.7254149e-01 -1.0076355e+00 1.2323108e+00 7.3943995e-01 -9.7359110e-01 -1.1376279e+00 -4.0596188e-01
+1 6.6257560e-01 1 1 2.7620528e-01 -2.1473911e-01 9.9549341e-01 -1.0721522e+00 -3.7330923e-01 1.4105335e+00 -3.7944426e-01 5.3787103e-01
+1 5.5705939e-01 1 1 -1.0918687e+00 5.6974546e-01 -8.6476371e-01 5.1371125e-01 -4.4764871e-01 3.7911579e-01 1.1339746e-01 -1.5052601e+00
+1 1.1618339e+00 1 1 -9.9428178e-01 1.3757024e-01 -1.0760595e+00 8.4842792e-01 4.8256515e-01 6.4923401e-01 -1.0756172e+00 3.3859999e-01
+1 6.6162864e-01 1 1 -7.6247506e-01 -6.9180990e-02 8.1752485e-01 -1.6098283e-01 -1.1198069e+00 9.2471394e-01 -1.1740560e+00 1.4257396e+00
+1 1.0787808e+00 1 1 -3.6192976e-01 -3.3561779e-01 -1.1860543e+00 -7.2719822e-01 6.8702758e-01 2.0837085e-01 -1.5579695e-02 1.4775354e+00
+1 1.0959520e+00 1 1 -8.3008622e-01 -1.5693956e+00 -6.1005550e-01 -1.2251368e+00 1.5195269e+00 -7.8700499e-01 -1.0957436e+00 -1.3524811e+00
+1 4.3712836e-01 1 1 5.5384954e-01 -1.9246063e-02 9.5559053e-01 -8.7539471e-01 6.8258718e-01 -1.0878170e+00 -1.4637661e-01 1.4151076e+00
+1 4.7878554e-01 1 1 1.0142878e-02 1.1545885e-01 7.8843747e-01 -6.8041060e-01 -8.5371249e-01 1.1292331e+00 -2.8458227e-01 -1.2841934e+00
+1 7.5734783e-01 1 1 8.2535483e-01 -9.8744373e-01 3.0703543e-02 -2.6363176e-01 -6.9210365e-01 6.5958155e-01 -1.4701876e+00 -6.9715372e-01
+1 4.1706698e-01 1 1 -1.5346055e+00 1.0672581e+00 8.1324409e-01 -1.2133219e+00 1.1314897e+00 -1.0933952e+00 -8.1620782e-01 1.0780261e+00
+1 1.2506206e+00 1 1 3.6027347e-01 -1.0866833e+00 -8.7620857e-01 -2.2374936e-01 8.8708689e-01 -1.5170722e+00 1.3302542e+00 8.1935536e-01
+1 4.4530058e-01 1 1 1.2671376e+00 1.3328399e+00 1.3488954e+00 -6.9078390e-02 -7.2934029e-01 -2.6598533e-01 -1.1325980e+00 1.3048932e+00
+1 5.2624959e-01 1 1 -7.5049751e-02 1.4851541e+00 1.1525496e+00 1.3887854e+00 4.7234398e-01 7.0875639e-02 -6.6452267e-01 -1.1798121e-01
+1 8.4553667e-01 1 1 1.5590866e+00 1.0311866e+00 -1.5932414e-01 -7.1728997e-01 -1.1944257e-01 5.4324448e-01 -2.7064756e-01 -5.6526183e-01
+1 1.1341663e+00 1 1 -4.5562546e-01 -1.0136944e+00 -1.1239511e+00 -1.2015316e+00 6.4498383e-03 8.4179770e-01 2.5265465e-01 -1.7941899e-01
+1 3.5297317e-01 1 1 1.5058442e+00 -3.0489258e-01 1.5096897e-01 1.6034724e-02 -1.5533104e+00 1.5022245e+00 -1.0664882e+00 4.3405101e-01
+1 1.1239884e+00 1 1 5.2988920e-02 -3.9197721e-01 -1.0713615e+00 -6.8136255e-01 1.4717255e-01 -1.0932151e+00 1.4603932e+00 3.1724179e-01
+1 5.1968227e-01 1 1 1.5140529e+00 -4.1101395e-02 1.2355767e+00 -5.5514221e-01 1.0956258e+00 1.5093250e+00 -4.3560910e-01 5.9998210e-01
+1 7.6399266e-01 1 1 -2.1315407e-01 3.5923524e-01 4.1073354e-01 2.5513357e-01 1.3075635e+00 -1.1353678e+00 -1.3713384e+00 -6.1330848e-01
+1 8.3193242e-01 1 1 -1.0647549e+00 -4.7443134e-01 1.1195019e+00 -2.4407357e-01 7.7880575e-01 -9.2806546e-02 -1.3603304e+00 -3.1006671e-01
+1 9.4127322e-01 1 1 -8.2301838e-01 -4.0544988e-01 4.7005737e-01 7.7555296e-01 1.5132854e+00 -1.5696707e+00 1.4375333e+00 6.1102888e-01
+1 9.0605554e-01 1 1 -3.7459711e-02 -2.8173328e-01 -8.5130646e-01 2.5070160e-01 -5.4575398e-01 -1.5027145e+00 -1.3661489e+00 -3.0399960e-01
+1 1.1555711e+00 1 1 -1.2668281e+00 -7.1111802e-01 -1.0947740e+00 6.6612359e-01 9.6340814e-01 -8.5922667e-01 1.0364962e+00 -1.0916531e+00
+1 1.1075211e+00 1 1 -1.0065523e+00 -1.1420690e+00 4.4089404e-01 -1.0970809e+00 2.3214848e-01 8.7882736e-01 2.5966219e-01 -5.1321151e-01
+1 7.5741383e-01 1 1 3.5197064e-01 3.7777094e-01 -9.1092263e-01 -6.3204438e-01 -1.3864940e-01 -1.3172605e+00 4.7020982e-01 1.2675191e+00
+1 7.6270151e-01 1 1 -4.8467299e-02 3.7384395e-02 -8.9562143e-01 -1.0451552e+00 7.8120388e-01 -3.9394685e-01 -1.4306603e+00 5.4541421e-02
+1 8.1867581e-01 1 1 -9.1739500e-01 1.0019840e-03 -1.3390241e+00 -1.2796953e+00 9.7789300e-01 1.4125679e+00 6.4222008e-01 -6.6739109e-01
+1 2.9924469e-01 1 1 2.7900821e-01 1.1323826e+00 1.3910822e+00 -4.9529350e-01 -1.3650934e+00 1.2793682e-02 -7.1952878e-01 -1.3562606e+00
+1 8.6854068e-01 1 1 -1.1068308e+00 1.8586196e-01 1.8592257e-01 8.2260771e-01 -7.2856920e-02 1.3951066e+00 -1.1300558e+00 7.2502609e-01
+1 1.1588313e+00 1 1 -1.1351299e+00 1.0388801e+00 -1.0841114e+00 -5.8146719e-01 7.1488229e-01 -1.2911257e+00 1.2212174e+00 -7.2436636e-01
+1 3.3781068e-01 1 1 7.6329326e-01 -5.1417754e-01 5.7748568e-01 7.7564084e-01 -1.5653218e+00 -9.6861572e-01 9.7572411e-01 -7.5386115e-01
+1 4.9402886e-01 1 1 1.5469455e+00 7.3952839e-01 1.4221585e+00 -1.4138603e+00 -6.6667083e-01 2.0871899e-01 -1.1859221e-01 -1.0110221e-01
+1 6.1693103e-01 1 1 -3.0719293e-01 1.1131876e+00 9.8018929e-01 2.5629379e-01 1.3243781e+00 -1.2189378e+00 -1.4095514e+00 3.7679461e-01
+1 8.7949731e-01 1 1 -1.3548139e+00 1.1595761e+00 -4.7056012e-01 4.0623468e-01 6.3801449e-01 -3.6121522e-01 4.1899064e-01 -6.6379905e-01
+1 8.4750867e-01 1 1 -9.2976203e-02 -1.4445843e+00 -1.3152412e+00 9.0537264e-01 8.5383192e-01 -1.3872748e+00 -1.4749608e+00 -6.7507547e-01
+1 9.4345869e-01 1 1 -1.2794877e+00 -9.0091383e-01 -1.0128785e+00 -1.2768381e+00 -4.4220934e-01 9.7293974e-01 6.4145765e-01 1.4391660e+00
+1 8.2226184e-01 1 1 -1.4815007e-01 8.1784182e-01 8.4137367e-01 4.0168601e-01 7.9583410e-01 2.0845605e-01 -9.6717970e-01 9.4096386e-01
+1 4.6657722e-01 1 1 1.3247448e+00 9.9955259e-01 6.5869292e-01 -1.4585462e-01 -1.3178034e+00 6.4498186e-01 -7.8874575e-01 2.2390832e-03
+1 9.2881094e-01 1 1 5.1927430e-01 1.3844413e+00 -3.2052294e-01 -9.3625557e-01 -9.3379689e-02 -1.4261060e+00 1.0712322e+00 -6.6841089e-02
+1 7.4186949e-01 1 1 9.8686946e-02 -1.4724415e+00 8.0227967e-01 5.9030861e-01 1.3639015e+00 -1.3539761e+00 -2.6835879e-01 1.2919847e+00
+1 5.3586334e-01 1 1 -1.2941738e-01 -9.9965279e-01 1.9874553e-01 1.6723327e-01 -1.1088805e+00 1.4208942e+00 1.0209077e+00 -3.0116511e-01
+1 4.2661917e-01 1 1 -1.1358513e+00 7.3095904e-02 8.0307242e-01 -1.0359234e+00 -1.0261381e+00 -1.4180030e+00 -9.8337141e-01 -5.7619420e-01
+1 5.8521592e-01 1 1 1.2063478e+00 1.6012512e-01 9.5618878e-01 -5.8747512e-02 1.0400383e+00 -2.5424324e-01 3.9571326e-01 1.4341683e+00
+1 7.2731311e-01 1 1 -7.5211317e-01 -1.1219687e+00 1.4183753e+00 -9.0934806e-01 1.0188065e-01 -5.0005614e-01 1.0641142e-03 -1.3736717e+00
+1 7.8740385e-01 1 1 1.0027549e+00 -1.0893566e+00 2.2888547e-01 4.3537692e-01 1.4006226e-01 -6.8318474e-01 -9.6498896e-01 2.6474495e-01
+1 2.4124425e-01 1 1 -1.3438117e+00 3.8528027e-01 1.5686665e+00 6.1063716e-01 9.7356012e-01 2.3528148e-01 1.4734828e+00 1.0732234e+00
+1 9.1508824e-01 1 1 -5.3296420e-01 5.8303112e-01 3.3314367e-01 -6.0452143e-01 1.2104484e+00 -8.8936911e-01 -3.4959823e-01 -1.3594643e+00
+1 7.9459631e-01 1 1 -8.4871362e-01 3.7653434e-01 8.2760256e-01 -2.8110121e-01 -9.4814035e-01 7.1213598e-02 -9.1912007e-01 2.8734497e-01
+1 8.2527932e-01 1 1 -1.4991943e+00 1.2450415e+00 -1.4560498e+00 4.8732655e-01 -1.2370014e+00 -5.9864816e-02 -4.3991064e-01 7.7902651e-01
+1 8.1483338e-01 1 1 -1.3850058e+00 -7.3610512e-01 1.1769672e+00 3.6533225e-01 7.7836434e-01 -8.3831515e-01 -1.4106317e+00 -1.0595834e+00
+1 8.3521781e-01 1 1 1.4092401e+00 -1.2684582e-01 -1.3208783e+00 1.4670184e+00 3.7758342e-01 4.8031947e-01 1.1119830e+00 1.2712865e+00
+1 8.5441917e-01 1 1 6.3187732e-01 1.2437486e+00 -1.5071548e+00 9.5881072e-01 2.7332353e-02 -1.1638175e+00 -2.3656217e-01 5.4099123e-01
+1 6.6234566e-01 1 1 1.3790053e+00 -4.7520520e-01 -8.8463887e-02 1.5030941e+00 7.0233186e-01 -7.2470788e-01 1.3558677e+00 6.7042508e-01
+1 1.1518869e+00 1 1 1.4125312e+00 -8.4532403e-01 -8.3922938e-01 9.5633806e-01 1.1279542e+00 -2.1064642e-01 -1.0442097e+00 -1.0585252e+00
+1 8.3689803e-01 1 1 -6.0353527e-01 -1.0790234e+00 8.2288998e-01 7.8581462e-01 1.1559537e+00 2.4052907e-01 -1.0951640e+00 2.0646098e-01
+1 7.2486065e-01 1 1 5.8540700e-01 1.2676119e+00 1.0209790e+00 -6.9161015e-02 5.0472777e-01 -6.5767655e-01 1.6965564e-01 -1.4701452e+00
+1 6.6604263e-01 1 1 -5.3278121e-01 -1.5276532e+00 2.1520855e-01 9.6714246e-05 6.5945265e-01 -1.4468345e+00 -1.1637820e+00 -1.0457864e-01
+1 6.3754335e-01 1 1 -9.1475916e-01 9.6981035e-01 1.0369010e+00 -1.5161163e+00 -1.1811259e-01 -1.0202598e+00 -1.2775369e-01 -1.5028271e+00
+1 5.7317242e-01 1 1 5.9720767e-01 1.0198817e+00 7.8095307e-01 9.0927238e-02 3.6819780e-01 -6.9374248e-01 -1.4485648e+00 3.9057271e-01
+1 7.0543603e-01 1 1 -1.1914058e-01 6.2234936e-01 -9.5927025e-02 1.4000601e+00 -6.3707854e-01 -1.2794796e+00 1.3137523e+00 1.5684217e+00
+1 5.3811822e-01 1 1 -1.2012603e+00 1.4637479e+00 -6.0848406e-01 2.8131871e-01 -8.3130614e-01 -1.2674245e-02 1.1222021e+00 -6.4087665e-01
+1 8.0785519e-01 1 1 1.4343223e+00 -6.0157406e-01 -9.0749757e-01 2.6543119e-02 -1.0997666e+00 6.1227142e-01 -1.2716683e+00 1.3073812e+00
+1 5.1473295e-01 1 1 1.2148263e+00 -1.0099833e+00 1.2059386e-01 4.0455646e-03 1.3537837e+00 -1.4117832e+00 -6.7441801e-01 8.5719410e-01
+1 5.9241527e-01 1 1 3.7551794e-01 -7.6379849e-01 4.9382692e-01 -1.1212336e+00 -1.5137070e+00 6.0833778e-01 -7.7245535e-02 -4.8268089e-01
+1 5.0004638e-01 1 1 -1.2966087e-01 -6.1369889e-01 -3.3874634e-01 -1.3010450e+00 -2.5632345e-01 -1.5510567e+00 -7.8794340e-01 -8.2556203e-01
+1 5.7223387e-01 1 1 1.0551281e+00 -5.8855835e-01 -7.4378305e-01 -1.1779777e+00 -9.0476604e-01 3.2535584e-01 -1.1516985e+00 1.1937319e+00
+1 9.3120167e-01 1 1 -7.5183017e-01 9.7502910e-01 -3.6450832e-01 4.6172289e-02 -1.0944726e+00 -1.2571782e+00 -1.2449736e+00 8.4075981e-01
+1 6.5819917e-01 1 1 -5.2404879e-01 7.6681177e-01 -1.8569429e-01 4.4277272e-02 -7.7623301e-01 9.5876660e-01 -1.2643188e+00 -2.3361562e-01
+1 1.0153120e+00 1 1 1.3377843e+00 9.9230096e-01 -1.3624772e+00 -3.8935141e-01 8.8613174e-01 7.6146847e-01 3.2590055e-01 6.1309386e-01
+1 9.4311888e-01 1 1 -2.3773835e-01 -1.1130983e+00 -8.5946254e-02 1.0842944e-01 -1.0746723e+00 -8.4789042e-01 -1.5270604e+00 -1.5543981e-01
+1 3.3222756e-01 1 1 4.3736161e-01 3.4096000e-01 6.3393638e-01 2.4979754e-01 -1.0004169e+00 -2.2996711e-01 1.5074476e+00 1.3281276e+00
+1 7.4175983e-01 1 1 -5.9029964e-01 2.4975054e-01 1.4281096e+00 1.1794281e+00 -2.0275660e-01 -8.9831907e-01 -1.2727691e+00 8.2425380e-01
+1 7.8206907e-01 1 1 -1.6414988e-02 3.8948844e-01 4.6969868e-01 -8.0226385e-01 8.9776909e-01 4.4563090e-01 -3.2616370e-01 -1.1899410e+00
+1 1.0558265e+00 1 1 5.7345734e-01 -9.4695764e-01 -5.9662328e-01 6.7091974e-02 -2.6445949e-01 1.6169140e-01 2.4592059e-01 4.0930267e-02
+1 8.8050535e-01 1 1 -3.0867323e-01 -2.0871310e-01 5.1623704e-01 -2.1695992e-01 5.8289681e-01 6.9693598e-02 -1.1486570e+00 -9.3786985e-02
+1 1.1376915e+00 1 1 -1.1015564e+00 1.3179015e+00 -6.8297415e-01 9.4366919e-01 1.2608194e+00 -4.7375822e-01 -3.9149311e-01 8.0164825e-01
+1 2.8264600e-01 1 1 -4.5349045e-01 -1.3993419e+00 6.3302550e-01 1.4883090e+00 5.4995204e-01 1.4830117e+00 -1.3297078e+00 -9.8870854e-01
+1 7.6947995e-01 1 1 -3.1014716e-01 -7.7595729e-01 -1.3147307e+00 6.4878410e-01 4.7837151e-01 -4.1899838e-01 8.9165494e-01 -1.3408428e+00
+1 3.3534281e-01 1 1 -7.4109854e-01 -7.6314107e-01 1.2842767e+00 -3.5374174e-01 6.5443174e-01 1.3449925e+00 6.4764363e-01 -9.0092982e-01
+1 1.0463294e+00 1 1 7.7173401e-01 1.0108921e+00 -1.0447843e+00 -1.4440406e+00 3.1844795e-01 1.5301742e+00 -6.7199898e-01 5.4912761e-01
+1 7.6127820e-01 1 1 -1.1025968e+00 3.3118942e-01 -1.3289519e+00 -1.1878842e+00 -1.1191639e+00 5.5961107e-01 -2.6121221e-01 -8.1153353e-01
+1 4.4378787e-01 1 1 9.1085715e-01 -6.0153986e-01 1.0296958e+00 5.0940821e-02 -1.0719127e+00 -5.4516616e-01 -1.3886093e+00 1.3512464e+00
+1 9.1530200e-01 1 1 -2.0490451e-01 -4.3520680e-01 -9.3603922e-01 -1.4924117e+00 1.3967833e+00 1.4181126e+00 5.3538924e-01 -1.7588047e-01
+1 6.7581359e-01 1 1 -6.4456894e-01 -8.9300145e-01 1.0848281e+00 -4.8722826e-01 -1.3852339e+00 -1.0456404e+00 7.6562850e-01 2.1571104e-01
+1 1.2307268e+00 1 1 -1.0587691e+00 -1.2872031e+00 -1.0977688e+00 1.2866614e+00 7.1735867e-01 -8.8163248e-03 -4.5379627e-02 5.7553252e-02
+1 4.2601861e-01 1 1 -7.5111046e-01 -1.0153941e+00 3.7364049e-01 1.3366883e+00 -7.8549231e-01 -5.2111647e-01 7.1161698e-01 -3.1303206e-01
+1 8.1118234e-01 1 1 -9.9419846e-01 -5.9668148e-01 -2.6794733e-01 1.9099008e-01 -7.9685990e-01 3.5575177e-01 1.0339215e-01 1.0379056e+00
+1 8.7299553e-01 1 1 6.3774505e-01 -4.6186892e-01 -1.4884318e+00 -7.3744462e-01 -2.1487215e-01 6.6920114e-01 4.1105449e-01 -1.1849219e+00
+1 7.9462700e-01 1 1 -5.3315609e-01 2.4458069e-01 4.2981415e-01 -6.4873063e-01 1.4752986e+00 3.6186094e-01 2.3049189e-01 -4.2732326e-01
+1 3.7013277e-01 1 1 -9.3220782e-01 1.4645352e+00 1.3649759e+00 1.2523571e+00 -1.2480829e+00 -3.2662162e-01 2.9350910e-01 -3.4124079e-01
+1 6.7251172e-01 1 1 -4.9430230e-01 6.4748796e-02 1.2412233e+00 -3.0557182e-01 -1.1572803e-01 -1.1672241e+00 7.0702103e-01 1.3142045e+00
+1 2.7002148e-01 1 1 -1.3677490e+00 1.2419547e+00 1.0643598e+00 7.5847748e-01 -3.9514316e-01 -1.4313449e+00 1.3989988e+00 -7.0358683e-01
+1 9.6140838e-01 1 1 -7.2438592e-01 7.9181801e-01 4.6724897e-01 -8.5197928e-01 1.5574101e-01 -1.4393990e+00 1.2936750e+00 -2.2903935e-01
+1 5.4739133e-01 1 1 -1.0826912e+00 2.9877757e-01 -9.2827613e-01 1.6349580e-01 5.9247784e-01 1.4256424e+00 -1.6658718e-01 -1.0134328e+00
+1 6.0902865e-01 1 1 -6.8662793e-01 1.2895001e+00 -3.8777905e-01 -1.0196620e+00 -1.0737357e+00 -1.5582115e-01 -6.7160489e-01 9.5028311e-01
+1 2.0159209e-01 1 1 -1.0858651e+00 -1.2197897e+00 1.4023256e+00 -7.2016775e-02 -9.6842501e-01 1.2022491e+00 7.8993471e-02 -4.4887420e-01
+1 7.3830759e-01 1 1 -6.2253217e-01 1.0279859e+00 6.5843755e-01 -8.7276269e-01 2.7232209e-01 -5.2375374e-01 -1.2504315e+00 -1.2646547e+00
+1 9.2275606e-01 1 1 -1.3946043e+00 -1.3998160e+00 -1.4709815e+00 -4.2648224e-01 -3.8307826e-01 1.3555138e-02 1.2532710e+00 9.6412046e-01
+1 7.2189488e-01 1 1 3.0769641e-01 6.7932614e-01 1.5485668e+00 1.2274101e+00 -1.2729012e+00 -1.5150627e+00 -6.5283849e-01 -3.6228982e-01
+1 7.9605245e-01 1 1 3.9213626e-01 8.8679627e-01 -1.3326667e+00 1.3836374e+00 5.9569075e-01 -1.0510531e+00 1.3266035e+00 -5.9841672e-01
+1 1.5955360e-01 1 1 -4.2729014e-01 6.6943747e-01 1.4262730e+00 7.2548392e-01 -4.8140073e-01 1.2537834e-01 3.4245038e-01 -1.3517430e+00
+1 7.4481364e-01 1 1 2.1548863e-01 1.1922670e+00 1.0189213e+00 6.8718018e-01 -1.3009858e+00 -7.7486084e-01 1.6575184e-01 1.2532085e+00
+1 7.4701008e-01 1 1 -5.3890504e-01 1.3543226e+00 1.8874911e-01 9.4268099e-01 -1.8386541e-01 -1.1846654e+00 -8.0152445e-01 1.4377470e+00
+1 7.7244835e-01 1 1 -1.6539914e-01 1.2611787e+00 -7.0223505e-01 5.8757533e-01 1.1012768e+00 7.4236251e-01 -7.2063950e-02 -9.1741087e-01
+1 5.1704699e-01 1 1 4.4620559e-01 3.0552175e-01 4.9915719e-01 1.3528442e+00 -1.1043299e+00 -1.5193388e+00 1.4759645e+00 1.2260982e-02
+1 1.5809767e-01 1 1 3.9574971e-01 1.5416652e+00 1.2825692e+00 1.5464734e+00 5.7175502e-02 -6.6240518e-01 5.1896671e-01 -1.2747915e+00
+1 8.3462411e-01 1 1 6.1368039e-01 -1.0886567e+00 -1.4679184e+00 1.1819718e+00 -3.7869634e-01 7.6049666e-01 1.2122524e+00 2.4044627e-01
+1 9.8554414e-01 1 1 2.7760322e-01 -4.1778096e-01 -3.7739953e-01 1.1090224e+00 1.1729024e-01 -1.4730746e+00 1.0983678e+00 1.0922770e+00
+1 4.1178288e-01 1 1 4.1227733e-01 -1.8502821e-01 -7.8330488e-02 2.6970680e-01 1.5184775e+00 9.2645632e-01 2.6962365e-01 -1.5687563e+00
+1 6.1874599e-01 1 1 -1.2082363e+00 4.0764582e-01 -1.7318773e-01 -3.5594959e-01 -1.2476398e+00 1.2181816e+00 1.3881276e+00 1.3006350e+00
+1 4.0767343e-01 1 1 4.2701268e-01 -5.1027228e-01 1.4902321e+00 -8.5242128e-01 1.0481510e+00 2.1916661e-01 7.9270428e-01 5.7085266e-01
+1 5.4344756e-01 1 1 1.4044762e+00 4.0166143e-01 1.5550292e+00 -9.8201654e-01 1.3637911e+00 -1.5550075e+00 -5.1363097e-01 -1.0338526e-01
+1 4.4803893e-01 1 1 -8.9648623e-01 -5.5889607e-01 4.6594730e-01 1.1758135e+00 1.7711137e-01 -1.0235084e-01 5.0084737e-01 -2.9524847e-01
+1 7.5097251e-01 1 1 -1.6574832e-01 -4.1545038e-03 -8.1413759e-01 1.2800408e+00 -1.5189634e+00 1.3821723e+00 1.4151064e+00 1.4753369e+00
+1 2.2158900e-01 1 1 8.6063223e-01 -7.0970616e-01 1.5670577e+00 1.8636503e-02 -6.3652309e-01 1.2336867e+00 -1.3045763e+00 -6.0431460e-01
+1 5.4996075e-01 1 1 7.5329537e-01 5.9585275e-01 1.5671666e+00 -9.3555460e-01 -9.2057036e-01 6.0652384e-02 -8.3797992e-01 5.3625656e-02
+1 5.5480787e-01 1 1 1.6903276e-02 -9.0027351e-01 2.5668588e-01 -1.9485309e-01 3.1785286e-01 1.5085966e+00 -1.6859591e-01 -3.5068638e-01
+1 4.8794563e-01 1 1 1.3500206e+00 -9.8668327e-01 7.1295250e-01 -1.3563484e+00 1.4454519e+00 -8.1207785e-01 1.2519104e-01 -3.5821051e-01
+1 4.7582968e-01 1 1 1.2144354e+00 1.2818883e+00 5.5827667e-01 -7.5136536e-01 -2.2584288e-01 -1.5139976e+00 -7.8124938e-01 -1.1524345e+00
+1 1.0732776e+00 1 1 8.8789561e-02 -3.4492769e-01 -9.8133977e-01 1.0048773e+00 -6.9738488e-01 1.1429215e+00 1.3988882e+00 -1.0474229e+00
+1 8.8313436e-01 1 1 2.9636231e-02 -9.6116966e-01 -1.6119880e-02 -2.2852982e-01 3.3458511e-01 1.3834965e+00 -5.6522049e-01 1.4480452e+00
+1 8.2936215e-01 1 1 -1.4170951e+00 -3.0908264e-01 -7.4986210e-01 1.2671506e+00 -7.8840125e-02 1.4992739e+00 5.1534334e-01 -6.2340327e-01
+1 7.0340304e-01 1 1 -7.0298155e-01 1.4423773e+00 1.1374433e+00 1.4335892e-01 6.8612501e-01 -4.1889217e-01 4.5310881e-03 -3.2717669e-01
+1 5.8211418e-01 1 1 5.1904030e-01 1.5063512e+00 4.1777995e-01 -1.6824875e-01 -1.0835347e+00 -1.1540166e-02 7.5577440e-01 -1.0715426e+00
+1 9.6561981e-01 1 1 -6.9250248e-01 -8.4999080e-01 1.6811217e-01 -3.2343648e-01 8.4473680e-01 8.2318067e-01 8.4118655e-01 1.3336349e+00
+1 5.4065376e-01 1 1 7.1162129e-01 -9.7363704e-01 1.1694392e+00 -1.0416046e+00 6.3415392e-01 -3.7659397e-01 6.5535321e-01 -8.6194230e-01
+1 6.2400731e-01 1 1 1.7577705e-01 6.3834593e-01 9.6121125e-01 -1.2935922e+00 -1.1989741e+00 8.9439885e-01 9.7486051e-02 -7.8055819e-01
+1 6.5305494e-01 1 1 1.1878079e+00 1.4106342e-01 1.0080002e+00 1.5594557e+00 -9.8310225e-01 -3.5939000e-01 -1.4633007e+00 4.4938524e-01
+1 7.4598616e-01 1 1 -1.3338059e+00 -1.0495786e+00 -1.1496884e+00 -5.3571447e-01 -1.3637843e+00 1.0148881e+00 -1.3083525e+00 4.2894575e-01
+1 4.2480737e-01 1 1 1.1291363e+00 -2.2524465e-01 1.1228122e+00 5.1390003e-02 -6.1920042e-02 1.5185688e+00 -1.4732318e+00 -6.6399767e-01
+1 8.0121453e-01 1 1 -9.6824286e-01 -6.7643725e-02 -4.4230316e-01 -2.2620045e-01 -8.2297623e-01 2.8724471e-01 1.4256557e+00 -8.7172026e-01
+1 8.6517403e-01 1 1 1.9213888e-01 3.6845450e-01 -7.8097174e-01 -4.2389244e-01 6.7087478e-01 -9.0603705e-01 6.8070480e-02 1.3856521e+00
+1 9.3646396e-01 1 1 -2.7916291e-01 5.3570522e-01 -2.1790481e-01 7.7192209e-01 2.1643910e-01 -4.6510796e-01 5.2083396e-01 2.9274487e-02
+1 8.2372271e-01 1 1 -1.4931986e+00 -2.0687986e-01 7.7081688e-01 -1.0831032e+00 -2.7227690e-01 -7.8693203e-01 1.1791903e+00 -1.2137501e+00
+1 8.3861403e-01 1 1 -1.1471830e+00 7.1323460e-01 -8.0885659e-01 -1.3282489e+00 1.1425543e+00 1.3842364e-01 1.4841387e+00 -1.1368383e+00
+1 1.2491891e+00 1 1 -7.5074623e-01 -9.8372190e-01 -7.8122013e-01 2.7843997e-01 1.4951310e+00 -1.4339670e+00 -3.2608341e-01 3.2535766e-01
+1 9.1720428e-01 1 1 -1.1558188e+00 7.8808512e-01 -1.2510083e+00 -1.2324839e+00 -9.3247802e-01 -1.5262323e+00 -1.5463230e+00 -1.2266408e+00
+1 1.8338807e-01 1 1 -1.3800139e+00 3.9192334e-01 9.8260227e-01 1.3057353e+00 1.2477137e+00 -2.8277184e-01 1.3451810e+00 -1.0206477e+00
+1 8.7070910e-01 1 1 4.8435193e-01 -8.6425085e-01 -7.5626889e-01 1.4692084e+00 1.9262070e-01 6.8339815e-01 1.5565521e+00 -9.2930476e-01
+1 9.8288174e-01 1 1 6.3637487e-01 1.2604600e+00 2.7262897e-01 6.8062705e-02 1.5357131e+00 2.0996514e-01 9.2985120e-01 1.1736109e+00
+1 7.2121387e-01 1 1 -1.5706113e+00 7.9118599e-01 -1.5086423e+00 3.9015265e-01 -5.9500839e-01 8.7557721e-01 -1.4143081e+00 -1.1821560e+00
+1 5.2830706e-01 1 1 1.5397876e+00 -8.9880645e-01 4.2619421e-02 7.9169371e-01 -6.1651097e-01 6.0615291e-01 -9.8552686e-01 -1.0638514e+00
+1 1.0075773e+00 1 1 -1.2294511e+00 -1.4625292e+00 2.1489944e-02 1.3512887e+00 -7.2734040e-01 -5.7302393e-01 -1.2734951e+00 -1.3469200e+00
+1 5.6727776e-01 1 1 -1.1293349e+00 -9.0730163e-01 -1.0166600e-01 5.3643717e-01 -4.7310656e-01 1.3099567e+00 3.9317993e-02 6.3286228e-01
+1 5.7422384e-01 1 1 7.7122926e-01 2.7229314e-01 3.2591142e-01 -4.7148001e-01 -1.3088836e-01 1.6062800e-01 1.0830460e+00 -9.1633908e-01
+1 1.0208791e+00 1 1 -1.6103965e-01 -8.6975856e-01 -1.3443771e+00 -1.0677988e+00 -7.2580086e-01 1.0466443e+00 3.6614923e-01 -8.2380465e-01
+1 4.8609293e-01 1 1 1.4595234e+00 -2.0155057e-01 -6.1072127e-01 1.4241806e+00 2.6927269e-01 1.1727813e+00 -5.0981840e-01 -6.8600597e-01
+1 6.9675204e-01 1 1 6.5497974e-01 -8.2351597e-01 -8.0924626e-01 4.0844058e-01 -1.3688382e+00 5.8222224e-01 -1.3946965e+00 -5.7293909e-02
+1 8.0388768e-01 1 1 1.0386245e-01 1.0243292e+00 -1.0472214e+00 2.8090469e-01 -1.8115460e-01 -6.5193433e-01 -1.2418421e+00 1.5302204e+00
+1 8.8795855e-01 1 1 -1.1093114e+00 -2.7689953e-02 -1.4487363e+00 -6.4856568e-01 -4.6214201e-01 8.1497099e-01 1.1006145e+00 1.3371587e+00
+1 4.9685261e-01 1 1 1.1550105e+00 -4.2933117e-01 -1.5672604e+00 8.8307680e-01 -1.2037771e+00 -1.2650646e-01 3.3104203e-01 -1.3273843e+00
diff --git a/library/cpp/linear_regression/benchmark/machine_cpu.features b/library/cpp/linear_regression/benchmark/machine_cpu.features
new file mode 100644
index 0000000000..152d0f766c
--- /dev/null
+++ b/library/cpp/linear_regression/benchmark/machine_cpu.features
@@ -0,0 +1,209 @@
+query 198 1 1 125 256 6000 256 16 128
+15 269 1 1 29 8000 32000 32 8 32
+15 220 1 1 29 8000 32000 32 8 32
+query 172 1 1 29 8000 32000 32 8 32
+2 132 1 1 29 8000 16000 32 8 16
+2 318 1 1 26 8000 32000 64 8 32
+2 367 1 1 23 16000 32000 64 16 32
+2 489 1 1 23 16000 32000 64 16 32
+2 636 1 1 23 16000 64000 64 16 32
+1 1144 1 1 23 32000 64000 128 32 64
+1 38 1 1 400 1000 3000 0 1 2
+1 40 1 1 400 512 3500 4 1 6
+1 92 1 1 60 2000 8000 65 1 8
+1 138 1 1 50 4000 16000 65 1 8
+1 10 1 1 350 64 64 0 1 4
+1 35 1 1 200 512 16000 0 4 32
+1 19 1 1 167 524 2000 8 4 15
+1 28 1 1 143 512 5000 0 7 32
+1 31 1 1 143 1000 2000 0 5 16
+1 120 1 1 110 5000 5000 142 8 64
+1 30 1 1 143 1500 6300 0 5 32
+1 33 1 1 143 3100 6200 0 5 20
+1 61 1 1 143 2300 6200 0 6 64
+1 76 1 1 110 3100 6200 0 6 64
+1 23 1 1 320 128 6000 0 1 12
+1 69 1 1 320 512 2000 4 1 3
+1 33 1 1 320 256 6000 0 1 6
+1 27 1 1 320 256 3000 4 1 3
+1 77 1 1 320 512 5000 4 1 5
+1 27 1 1 320 256 5000 4 1 6
+1 274 1 1 25 1310 2620 131 12 24
+1 368 1 1 25 1310 2620 131 12 24
+1 32 1 1 50 2620 10480 30 12 24
+1 63 1 1 50 2620 10480 30 12 24
+1 106 1 1 56 5240 20970 30 12 24
+1 208 1 1 64 5240 20970 30 12 24
+1 20 1 1 50 500 2000 8 1 4
+1 29 1 1 50 1000 4000 8 1 5
+1 71 1 1 50 2000 8000 8 1 5
+1 26 1 1 50 1000 4000 8 3 5
+1 36 1 1 50 1000 8000 8 3 5
+1 40 1 1 50 2000 16000 8 3 5
+1 52 1 1 50 2000 16000 8 3 6
+1 60 1 1 50 2000 16000 8 3 6
+1 72 1 1 133 1000 12000 9 3 12
+1 72 1 1 133 1000 8000 9 3 12
+1 18 1 1 810 512 512 8 1 1
+1 20 1 1 810 1000 5000 0 1 1
+1 40 1 1 320 512 8000 4 1 5
+1 62 1 1 200 512 8000 8 1 8
+1 24 1 1 700 384 8000 0 1 1
+1 24 1 1 700 256 2000 0 1 1
+1 138 1 1 140 1000 16000 16 1 3
+1 36 1 1 200 1000 8000 0 1 2
+1 26 1 1 110 1000 4000 16 1 2
+1 60 1 1 110 1000 12000 16 1 2
+1 71 1 1 220 1000 8000 16 1 2
+1 12 1 1 800 256 8000 0 1 4
+1 14 1 1 800 256 8000 0 1 4
+1 20 1 1 800 256 8000 0 1 4
+1 16 1 1 800 256 8000 0 1 4
+1 22 1 1 800 256 8000 0 1 4
+1 36 1 1 125 512 1000 0 8 20
+1 144 1 1 75 2000 8000 64 1 38
+1 144 1 1 75 2000 16000 64 1 38
+1 259 1 1 75 2000 16000 128 1 38
+1 17 1 1 90 256 1000 0 3 10
+1 26 1 1 105 256 2000 0 3 10
+1 32 1 1 105 1000 4000 0 3 24
+1 32 1 1 105 2000 4000 8 3 19
+1 62 1 1 75 2000 8000 8 3 24
+1 64 1 1 75 3000 8000 8 3 48
+1 22 1 1 175 256 2000 0 3 24
+1 36 1 1 300 768 3000 0 6 24
+1 44 1 1 300 768 3000 6 6 24
+1 50 1 1 300 768 12000 6 6 24
+1 45 1 1 300 768 4500 0 1 24
+1 53 1 1 300 384 12000 6 1 24
+1 36 1 1 300 192 768 6 6 24
+1 84 1 1 180 768 12000 6 1 31
+1 16 1 1 330 1000 3000 0 2 4
+1 38 1 1 300 1000 4000 8 3 64
+1 38 1 1 300 1000 16000 8 2 112
+1 16 1 1 330 1000 2000 0 1 2
+1 22 1 1 330 1000 4000 0 3 6
+1 29 1 1 140 2000 4000 0 3 6
+1 40 1 1 140 2000 4000 0 4 8
+1 35 1 1 140 2000 4000 8 1 20
+1 134 1 1 140 2000 32000 32 1 20
+1 66 1 1 140 2000 8000 32 1 54
+1 141 1 1 140 2000 32000 32 1 54
+1 189 1 1 140 2000 32000 32 1 54
+1 22 1 1 140 2000 4000 8 1 20
+1 132 1 1 57 4000 16000 1 6 12
+1 237 1 1 57 4000 24000 64 12 16
+1 465 1 1 26 16000 32000 64 16 24
+1 465 1 1 26 16000 32000 64 8 24
+1 277 1 1 26 8000 32000 0 8 24
+1 185 1 1 26 8000 16000 0 8 16
+1 6 1 1 480 96 512 0 1 1
+1 24 1 1 203 1000 2000 0 1 5
+1 45 1 1 115 512 6000 16 1 6
+1 7 1 1 1100 512 1500 0 1 1
+1 13 1 1 1100 768 2000 0 1 1
+1 16 1 1 600 768 2000 0 1 1
+1 32 1 1 400 2000 4000 0 1 1
+1 32 1 1 400 4000 8000 0 1 1
+1 11 1 1 900 1000 1000 0 1 2
+1 11 1 1 900 512 1000 0 1 2
+1 18 1 1 900 1000 4000 4 1 2
+1 22 1 1 900 1000 4000 8 1 2
+1 37 1 1 900 2000 4000 0 3 6
+1 40 1 1 225 2000 4000 8 3 6
+1 34 1 1 225 2000 4000 8 3 6
+1 50 1 1 180 2000 8000 8 1 6
+1 76 1 1 185 2000 16000 16 1 6
+1 66 1 1 180 2000 16000 16 1 6
+1 24 1 1 225 1000 4000 2 3 6
+1 49 1 1 25 2000 12000 8 1 4
+1 66 1 1 25 2000 12000 16 3 5
+1 100 1 1 17 4000 16000 8 6 12
+1 133 1 1 17 4000 16000 32 6 12
+1 12 1 1 1500 768 1000 0 0 0
+1 18 1 1 1500 768 2000 0 0 0
+1 20 1 1 800 768 2000 0 0 0
+1 27 1 1 50 2000 4000 0 3 6
+1 45 1 1 50 2000 8000 8 3 6
+1 56 1 1 50 2000 8000 8 1 6
+1 70 1 1 50 2000 16000 24 1 6
+1 80 1 1 50 2000 16000 24 1 6
+1 136 1 1 50 8000 16000 48 1 10
+1 16 1 1 100 1000 8000 0 2 6
+1 26 1 1 100 1000 8000 24 2 6
+1 32 1 1 100 1000 8000 24 3 6
+1 45 1 1 50 2000 16000 12 3 16
+1 54 1 1 50 2000 16000 24 6 16
+1 65 1 1 50 2000 16000 24 6 16
+1 30 1 1 150 512 4000 0 8 128
+1 50 1 1 115 2000 8000 16 1 3
+1 40 1 1 115 2000 4000 2 1 5
+1 62 1 1 92 2000 8000 32 1 6
+1 60 1 1 92 2000 8000 32 1 6
+1 50 1 1 92 2000 8000 4 1 6
+1 66 1 1 75 4000 16000 16 1 6
+1 86 1 1 60 4000 16000 32 1 6
+1 74 1 1 60 2000 16000 64 5 8
+1 93 1 1 60 4000 16000 64 5 8
+1 111 1 1 50 4000 16000 64 5 10
+1 143 1 1 72 4000 16000 64 8 16
+1 105 1 1 72 2000 8000 16 6 8
+1 214 1 1 40 8000 16000 32 8 16
+1 277 1 1 40 8000 32000 64 8 24
+1 370 1 1 35 8000 32000 64 8 24
+1 510 1 1 38 16000 32000 128 16 32
+1 214 1 1 48 4000 24000 32 8 24
+1 326 1 1 38 8000 32000 64 8 24
+1 510 1 1 30 16000 32000 256 16 24
+1 8 1 1 112 1000 1000 0 1 4
+1 12 1 1 84 1000 2000 0 1 6
+1 17 1 1 56 1000 4000 0 1 6
+1 21 1 1 56 2000 6000 0 1 8
+1 24 1 1 56 2000 8000 0 1 8
+1 34 1 1 56 4000 8000 0 1 8
+1 42 1 1 56 4000 12000 0 1 8
+1 46 1 1 56 4000 16000 0 1 8
+1 51 1 1 38 4000 8000 32 16 32
+1 116 1 1 38 4000 8000 32 16 32
+1 100 1 1 38 8000 16000 64 4 8
+1 140 1 1 38 8000 24000 160 4 8
+1 212 1 1 38 4000 16000 128 16 32
+1 25 1 1 200 1000 2000 0 1 2
+1 30 1 1 200 1000 4000 0 1 4
+1 41 1 1 200 2000 8000 64 1 5
+1 25 1 1 250 512 4000 0 1 7
+1 50 1 1 250 512 4000 0 4 7
+1 50 1 1 250 1000 16000 1 1 8
+1 30 1 1 160 512 4000 2 1 5
+1 32 1 1 160 512 2000 2 3 8
+1 38 1 1 160 1000 4000 8 1 14
+1 60 1 1 160 1000 8000 16 1 14
+1 109 1 1 160 2000 8000 32 1 13
+1 6 1 1 240 512 1000 8 1 3
+1 11 1 1 240 512 2000 8 1 5
+1 22 1 1 105 2000 4000 8 3 8
+1 33 1 1 105 2000 6000 16 6 16
+1 58 1 1 105 2000 8000 16 4 14
+1 130 1 1 52 4000 16000 32 4 12
+1 75 1 1 70 4000 12000 8 6 8
+1 113 1 1 59 4000 12000 32 6 12
+1 188 1 1 59 8000 16000 64 12 24
+1 173 1 1 26 8000 24000 32 8 16
+1 248 1 1 26 8000 32000 64 12 16
+1 405 1 1 26 8000 32000 128 24 32
+1 70 1 1 116 2000 8000 32 5 28
+1 114 1 1 50 2000 32000 24 6 26
+1 208 1 1 50 2000 32000 48 26 52
+1 307 1 1 50 2000 32000 112 52 104
+1 397 1 1 50 4000 32000 112 52 104
+1 915 1 1 30 8000 64000 96 12 176
+1 1150 1 1 30 8000 64000 128 12 176
+1 12 1 1 180 262 4000 0 1 3
+1 14 1 1 180 512 4000 0 1 3
+1 18 1 1 180 262 4000 0 1 3
+1 21 1 1 180 512 4000 0 1 3
+1 42 1 1 124 1000 8000 0 1 8
+1 46 1 1 98 1000 8000 32 2 8
+1 52 1 1 125 2000 8000 0 2 14
+1 67 1 1 480 512 8000 32 0 0
+1 45 1 1 480 1000 4000 0 0 0
diff --git a/library/cpp/linear_regression/benchmark/main.cpp b/library/cpp/linear_regression/benchmark/main.cpp
new file mode 100644
index 0000000000..735d41e988
--- /dev/null
+++ b/library/cpp/linear_regression/benchmark/main.cpp
@@ -0,0 +1,114 @@
+#include "pool.h"
+
+#include <library/cpp/linear_regression/linear_regression.h>
+
+#include <util/datetime/base.h>
+#include <util/datetime/cputimer.h>
+
+#include <util/system/type_name.h>
+
+#include <util/string/printf.h>
+
+template <typename TLRSolver>
+void QualityBenchmark(const TPool& originalPool) {
+ auto measure = [&](const double injureFactor, const double injureOffset) {
+ TPool injuredPool = originalPool.InjurePool(injureFactor, injureOffset);
+
+ static const size_t runsCount = 10;
+ static const size_t foldsCount = 10;
+
+ TMeanCalculator determinationCoefficientCalculator;
+
+ TPool::TCVIterator learnIterator = injuredPool.CrossValidationIterator(foldsCount, TPool::LearnIterator);
+ TPool::TCVIterator testIterator = injuredPool.CrossValidationIterator(foldsCount, TPool::TestIterator);
+
+ for (size_t runNumber = 0; runNumber < runsCount; ++runNumber) {
+ for (size_t foldNumber = 0; foldNumber < foldsCount; ++foldNumber) {
+ learnIterator.ResetShuffle();
+ learnIterator.SetTestFold(foldNumber);
+ testIterator.ResetShuffle();
+ testIterator.SetTestFold(foldNumber);
+
+ TLRSolver solver;
+ for (; learnIterator.IsValid(); ++learnIterator) {
+ solver.Add(learnIterator->Features, learnIterator->Goal, learnIterator->Weight);
+ }
+ TLinearModel model = solver.Solve();
+
+ TDeviationCalculator goalsCalculator;
+ TKahanAccumulator<double> errorsCalculator;
+ for (; testIterator.IsValid(); ++testIterator) {
+ const double prediction = model.Prediction(testIterator->Features);
+ const double goal = testIterator->Goal;
+ const double weight = testIterator->Weight;
+ const double error = goal - prediction;
+
+ goalsCalculator.Add(goal, weight);
+ errorsCalculator += error * error * weight;
+ }
+
+ const double determinationCoefficient = 1 - errorsCalculator.Get() / goalsCalculator.GetDeviation();
+ determinationCoefficientCalculator.Add(determinationCoefficient);
+ }
+ }
+
+ return determinationCoefficientCalculator.GetMean();
+ };
+
+ Cout << TypeName<TLRSolver>() << ":\n";
+ Cout << "\t" << Sprintf("base : %.10lf\n", measure(1., 0.));
+ Cout << "\t" << Sprintf("injure1 : %.10lf\n", measure(1e-1, 1e+1));
+ Cout << "\t" << Sprintf("injure2 : %.10lf\n", measure(1e-3, 1e+4));
+ Cout << "\t" << Sprintf("injure3 : %.10lf\n", measure(1e-3, 1e+5));
+ Cout << "\t" << Sprintf("injure4 : %.10lf\n", measure(1e-3, 1e+6));
+ Cout << "\t" << Sprintf("injure5 : %.10lf\n", measure(1e-4, 1e+6));
+ Cout << "\t" << Sprintf("injure6 : %.10lf\n", measure(1e-4, 1e+7));
+ Cout << Endl;
+}
+
+template <typename TLRSolver>
+void SpeedBenchmark(const TPool& originalPool) {
+ TDeviationCalculator speedTest;
+
+ static const size_t runsCount = 1000;
+ for (size_t runNumber = 0; runNumber < runsCount; ++runNumber) {
+ TLRSolver solver;
+ TLinearModel model;
+ {
+ TSimpleTimer timer;
+ for (const TInstance& instance : originalPool) {
+ solver.Add(instance.Features, instance.Goal, instance.Weight);
+ }
+ model = solver.Solve();
+
+ speedTest.Add(timer.Get().MicroSeconds());
+ }
+ }
+
+ const double multiplier = 1e-6;
+ Cout << Sprintf("%.5lf +/- %.5lf: ", speedTest.GetMean() * multiplier, speedTest.GetStdDev() * multiplier) << TypeName<TLRSolver>() << Endl;
+}
+
+int main(int argc, const char** argv) {
+ for (int taskNumber = 1; taskNumber < argc; ++taskNumber) {
+ TPool pool;
+ pool.ReadFromFeatures(argv[taskNumber]);
+
+ Cout << argv[taskNumber] << ":" << Endl;
+ QualityBenchmark<TFastBestSLRSolver>(pool);
+ QualityBenchmark<TKahanBestSLRSolver>(pool);
+ QualityBenchmark<TBestSLRSolver>(pool);
+
+ QualityBenchmark<TLinearRegressionSolver>(pool);
+ QualityBenchmark<TFastLinearRegressionSolver>(pool);
+
+ SpeedBenchmark<TFastBestSLRSolver>(pool);
+ SpeedBenchmark<TKahanBestSLRSolver>(pool);
+ SpeedBenchmark<TBestSLRSolver>(pool);
+
+ SpeedBenchmark<TLinearRegressionSolver>(pool);
+ SpeedBenchmark<TFastLinearRegressionSolver>(pool);
+ }
+
+ return 0;
+}
diff --git a/library/cpp/linear_regression/benchmark/pool.cpp b/library/cpp/linear_regression/benchmark/pool.cpp
new file mode 100644
index 0000000000..7f2c6a7004
--- /dev/null
+++ b/library/cpp/linear_regression/benchmark/pool.cpp
@@ -0,0 +1,109 @@
+#include "pool.h"
+
+#include <util/string/cast.h>
+#include <util/stream/file.h>
+
+TInstance TInstance::FromFeaturesString(const TString& featuresString) {
+ TInstance instance;
+
+ TStringBuf featuresStringBuf(featuresString);
+
+ featuresStringBuf.NextTok('\t'); // query id
+ instance.Goal = FromString(featuresStringBuf.NextTok('\t'));
+ featuresStringBuf.NextTok('\t'); // url
+ instance.Weight = FromString(featuresStringBuf.NextTok('\t'));
+
+ while (featuresStringBuf) {
+ instance.Features.push_back(FromString(featuresStringBuf.NextTok('\t')));
+ }
+
+ return instance;
+}
+
+TPool::TCVIterator::TCVIterator(const TPool& parentPool, const size_t foldsCount, const EIteratorType iteratorType)
+ : ParentPool(parentPool)
+ , FoldsCount(foldsCount)
+ , IteratorType(iteratorType)
+ , InstanceFoldNumbers(ParentPool.size())
+{
+}
+
+void TPool::TCVIterator::ResetShuffle() {
+ TVector<size_t> instanceNumbers(ParentPool.size());
+ for (size_t instanceNumber = 0; instanceNumber < ParentPool.size(); ++instanceNumber) {
+ instanceNumbers[instanceNumber] = instanceNumber;
+ }
+ Shuffle(instanceNumbers.begin(), instanceNumbers.end(), RandomGenerator);
+
+ for (size_t instancePosition = 0; instancePosition < ParentPool.size(); ++instancePosition) {
+ InstanceFoldNumbers[instanceNumbers[instancePosition]] = instancePosition % FoldsCount;
+ }
+ Current = InstanceFoldNumbers.begin();
+}
+
+void TPool::TCVIterator::SetTestFold(const size_t testFoldNumber) {
+ TestFoldNumber = testFoldNumber;
+ Current = InstanceFoldNumbers.begin();
+ Advance();
+}
+
+bool TPool::TCVIterator::IsValid() const {
+ return Current != InstanceFoldNumbers.end();
+}
+
+const TInstance& TPool::TCVIterator::operator*() const {
+ return ParentPool[Current - InstanceFoldNumbers.begin()];
+}
+
+const TInstance* TPool::TCVIterator::operator->() const {
+ return &ParentPool[Current - InstanceFoldNumbers.begin()];
+}
+
+TPool::TCVIterator& TPool::TCVIterator::operator++() {
+ Advance();
+ return *this;
+}
+
+void TPool::TCVIterator::Advance() {
+ while (IsValid()) {
+ ++Current;
+ if (IsValid() && TakeCurrent()) {
+ break;
+ }
+ }
+}
+
+bool TPool::TCVIterator::TakeCurrent() const {
+ switch (IteratorType) {
+ case LearnIterator:
+ return *Current != TestFoldNumber;
+ case TestIterator:
+ return *Current == TestFoldNumber;
+ }
+ return false;
+}
+
+void TPool::ReadFromFeatures(const TString& featuresPath) {
+ TFileInput featuresIn(featuresPath);
+ TString featuresString;
+ while (featuresIn.ReadLine(featuresString)) {
+ this->push_back(TInstance::FromFeaturesString(featuresString));
+ }
+}
+
+TPool::TCVIterator TPool::CrossValidationIterator(const size_t foldsCount, const EIteratorType iteratorType) const {
+ return TPool::TCVIterator(*this, foldsCount, iteratorType);
+}
+
+TPool TPool::InjurePool(const double injureFactor, const double injureOffset) const {
+ TPool injuredPool(*this);
+
+ for (TInstance& instance : injuredPool) {
+ for (double& feature : instance.Features) {
+ feature = feature * injureFactor + injureOffset;
+ }
+ instance.Goal = instance.Goal * injureFactor + injureOffset;
+ }
+
+ return injuredPool;
+}
diff --git a/library/cpp/linear_regression/benchmark/pool.h b/library/cpp/linear_regression/benchmark/pool.h
new file mode 100644
index 0000000000..43288319c8
--- /dev/null
+++ b/library/cpp/linear_regression/benchmark/pool.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#include <util/generic/vector.h>
+#include <util/generic/string.h>
+
+#include <util/random/mersenne.h>
+#include <util/random/shuffle.h>
+
+struct TInstance {
+ TVector<double> Features;
+ double Goal;
+ double Weight;
+
+ static TInstance FromFeaturesString(const TString& featuresString);
+};
+
+struct TPool: public TVector<TInstance> {
+ enum EIteratorType {
+ LearnIterator,
+ TestIterator,
+ };
+
+ class TCVIterator {
+ private:
+ const TPool& ParentPool;
+
+ size_t FoldsCount;
+
+ EIteratorType IteratorType;
+ size_t TestFoldNumber;
+
+ TVector<size_t> InstanceFoldNumbers;
+ const size_t* Current;
+
+ TMersenne<ui64> RandomGenerator;
+
+ public:
+ TCVIterator(const TPool& parentPool,
+ const size_t foldsCount,
+ const EIteratorType iteratorType);
+
+ void ResetShuffle();
+
+ void SetTestFold(const size_t testFoldNumber);
+
+ bool IsValid() const;
+
+ const TInstance& operator*() const;
+ const TInstance* operator->() const;
+ TPool::TCVIterator& operator++();
+
+ private:
+ void Advance();
+ bool TakeCurrent() const;
+ };
+
+ void ReadFromFeatures(const TString& featuresPath);
+ TCVIterator CrossValidationIterator(const size_t foldsCount, const EIteratorType iteratorType) const;
+
+ TPool InjurePool(const double injureFactir, const double injureOffset) const;
+};
diff --git a/library/cpp/linear_regression/benchmark/puma32H.features b/library/cpp/linear_regression/benchmark/puma32H.features
new file mode 100644
index 0000000000..2a50f1a9a7
--- /dev/null
+++ b/library/cpp/linear_regression/benchmark/puma32H.features
@@ -0,0 +1,8192 @@
+1 0.052627 1 1 0.736460 -1.761829 1.590594 -0.268853 0.572145 -1.941886 0.727704 1.869884 0.224501 -1.442215 1.222878 2.184147 -17.700874 -48.591059 -69.920646 -56.304775 35.642548 0.539676 2.083801 0.439963 2.451373 1.973873 2.381104 2.220872 2.440442 0.510303 1.157391 0.265448 1.141465 0.356314 0.568853 1.954376
+1 0.001308 1 1 -0.389711 0.342256 -1.522463 0.237098 -1.771509 -0.885488 -0.679111 -0.410219 -0.331288 2.092878 1.735358 1.185432 -13.448750 16.857753 -21.747815 34.470520 46.036460 1.896749 2.166890 1.924542 1.270063 1.697582 0.504973 1.580327 0.809171 2.235141 1.517466 1.795334 0.929355 1.663727 0.754457 0.650492
+1 0.003834 1 1 -0.269351 1.622452 -2.047811 1.720603 -1.749964 -1.618348 0.327188 -0.317671 0.046938 1.911881 -0.803160 2.281413 -31.820684 -60.239108 61.312743 -16.728557 -56.860861 1.217600 1.947443 1.424887 0.571197 0.853634 0.271240 1.723625 1.718983 2.438604 1.113059 2.180270 1.794781 0.627965 0.961728 1.258398
+1 -0.002010 1 1 0.256840 0.165040 -1.776401 1.723357 2.117348 -1.692605 1.077334 1.761624 -0.333281 1.573860 1.228959 0.708848 21.786179 10.305694 -42.206506 -14.753722 -15.809157 0.557422 1.096861 2.183588 1.308812 0.454540 2.206350 1.369922 1.528851 1.901706 2.222391 0.968513 0.546513 2.236340 1.412382 1.898374
+1 0.015778 1 1 0.968270 1.834561 0.299747 0.308144 0.064617 2.174855 -1.213028 -1.563548 -2.277270 -0.059009 -2.169927 -0.781419 3.957141 57.666741 54.922653 -14.973708 36.882913 0.491771 2.437949 1.362933 1.056741 0.646724 1.235894 1.171433 2.273871 2.199479 0.646400 0.302676 1.323917 2.324899 0.334220 0.491228
+1 0.045423 1 1 1.973219 -1.900328 1.755539 1.069326 -0.896503 -2.026054 -0.159037 -1.017832 -0.739092 -0.066928 1.403939 1.067098 -20.289144 -49.643000 -49.894246 -72.587127 -21.835739 2.225960 2.466990 1.196056 2.107127 0.989808 0.696371 0.906589 1.540755 1.722584 2.211768 2.437457 2.087463 1.235701 2.424325 1.883450
+1 0.020295 1 1 0.825565 2.000705 -1.759389 0.185671 0.969628 1.097870 -1.805552 1.879531 2.132396 1.460123 -1.826648 0.743513 -32.964663 62.907365 -65.911658 -27.237363 21.645967 2.181548 0.776967 0.981137 1.213539 1.197058 0.948815 2.477833 1.189986 1.349215 2.250026 1.944250 1.762353 2.363805 1.722101 0.849889
+1 -0.067276 1 1 0.734112 1.180068 -1.034351 -0.341260 -0.574536 -0.540296 0.018133 -1.545991 0.647626 -0.970310 1.576308 -0.039210 23.303159 6.200741 -34.151271 69.594734 -21.298284 0.471062 0.892202 0.487894 0.289095 0.325768 2.435523 1.090482 0.724301 2.331182 2.427710 0.269038 0.718057 0.878972 0.876069 1.594595
+1 -0.016086 1 1 0.805596 0.964388 -2.149934 0.664719 -1.144362 -2.030436 1.578742 -1.538290 -1.874612 0.435958 -0.624537 -2.103455 -13.362686 -36.667202 -65.666743 39.042332 -65.526356 1.353083 2.018219 0.708041 1.302717 1.506095 1.934665 0.416524 2.271327 2.189305 0.642488 2.047515 0.337190 0.898273 1.266921 0.634945
+1 -0.015369 1 1 0.104635 0.871885 -1.757680 0.638052 -1.665193 -0.016683 2.346091 2.186103 -0.671349 -1.900788 -1.250359 -2.239485 -37.447745 15.757451 -64.518820 -17.800315 -69.891474 1.134948 1.067419 2.355897 1.563933 2.023823 0.393097 2.281937 0.513909 1.016225 1.435360 1.093416 0.546241 2.168585 1.158092 0.802747
+1 -0.031368 1 1 -0.738308 -1.022457 1.650859 -0.564279 2.200874 -2.167051 0.419951 -1.039498 -2.018085 1.818563 0.037510 -1.029719 67.552069 -2.381588 22.647423 -64.760967 -37.579637 2.110736 0.898740 2.372549 2.427109 1.414839 0.448595 1.277976 1.937175 2.100187 1.340036 0.978518 2.199210 0.624324 0.518687 0.318753
+1 -0.002328 1 1 2.274685 -0.981603 0.275510 -1.786229 1.475403 0.510749 -1.821545 1.678368 -0.022703 0.136170 -1.604116 -0.807144 41.505545 -66.301838 15.011442 -2.689907 -59.262101 1.103040 0.297207 1.657771 1.906804 2.404041 0.720151 2.332524 2.489013 2.348398 1.531804 2.029784 1.574799 2.395579 0.253445 1.894690
+1 0.001888 1 1 -2.228374 1.786055 0.304217 0.031585 -1.643102 -1.011521 1.668651 1.586223 1.661224 -0.711590 0.344496 -1.588419 -27.791741 4.203880 4.613673 -8.003721 31.470057 1.633638 1.295397 2.236482 1.551616 2.004339 1.420437 2.277906 0.267256 2.272580 0.745151 1.757535 2.388301 1.674575 0.839515 1.485700
+1 -0.030350 1 1 -1.214474 -2.308954 -0.066199 -0.478112 -1.005956 0.950234 0.295624 1.696103 1.155250 1.238914 -1.620552 0.983607 13.225268 -22.917454 26.349220 51.342213 -41.422143 0.895562 0.704556 1.216561 2.488302 1.644604 1.101292 2.417500 1.923540 2.435912 0.880446 0.909283 1.817779 2.404749 1.371171 2.270846
+1 0.001927 1 1 -1.343737 2.294629 -0.369010 -0.453836 1.742390 1.556630 -0.897989 1.287400 -1.951639 1.737758 -0.896182 -1.329748 56.624365 -64.301235 39.143507 -15.080150 47.921645 2.411231 2.302139 0.305917 1.790440 1.929076 0.978193 1.237993 0.450371 1.891675 2.382647 1.148710 0.611101 1.031307 0.673738 0.756461
+1 -0.017214 1 1 0.853334 2.184567 1.796832 -2.348315 -1.880052 -1.465282 -0.046863 -0.664311 -1.417508 1.777056 -0.140663 1.502941 48.546645 73.463460 50.377487 -55.578609 -59.674220 0.705858 0.598444 2.042083 1.288022 2.031514 1.410007 2.494380 0.301667 2.372471 1.118049 0.542665 0.574490 2.195622 1.073935 1.634544
+1 -0.038949 1 1 -0.922407 0.857579 -1.873574 -0.981105 -0.783243 -2.255939 0.324079 -0.727312 0.003880 -0.758561 -2.125854 0.105586 -63.450075 -55.418833 -74.331096 67.261691 67.233460 2.016356 0.899690 0.342891 2.221260 2.217710 1.058107 1.113253 0.947311 1.961948 2.202564 0.737460 0.747175 2.022986 2.078472 0.873429
+1 -0.009716 1 1 -1.932189 -1.223255 0.903497 1.764707 -0.338144 -0.047503 -1.982679 -1.591497 -0.772903 1.872101 -0.225976 0.213854 -41.645185 -30.618122 51.229587 15.665187 34.791768 2.053589 1.167811 2.156990 2.031386 1.503569 2.229924 1.589216 1.708371 1.847288 1.123260 0.386161 0.455860 1.888753 0.527461 1.533234
+1 -0.009839 1 1 -0.327488 -0.017718 -0.906712 0.757062 0.484575 1.236466 -0.352568 -2.138922 1.951140 -0.705228 -1.100420 1.371851 -32.252242 36.570264 -63.570850 14.717209 2.129847 0.570186 1.868800 0.424185 0.519766 0.450781 2.033368 1.073135 1.671893 0.763045 0.992240 1.080800 2.248817 1.868345 1.782193 0.564604
+1 0.017550 1 1 1.857900 1.442575 0.123121 0.553377 -1.655568 1.519563 -1.849801 -1.970042 -1.251403 -0.945162 0.123784 2.275591 3.656886 -38.721372 59.892456 -37.487810 -57.630404 0.712080 1.678498 1.524591 2.295986 0.385595 2.189108 1.845669 0.911949 1.623242 2.073450 1.981997 1.672500 1.952790 1.285496 2.325770
+1 0.074438 1 1 -1.325761 -1.886558 2.294248 -2.054092 -0.168004 -0.924841 -2.344445 1.913879 -0.208020 0.403319 2.160072 0.081895 12.601505 -6.505779 7.376562 -72.131397 -12.381414 0.708725 1.545798 0.984516 1.767348 0.825130 0.455221 2.396621 2.014234 1.225722 1.203884 0.926158 1.943980 1.722949 1.605153 1.806753
+1 0.021054 1 1 -1.962938 0.339262 -0.021231 1.305596 2.263559 0.527997 0.613874 1.957753 2.061619 -0.572363 -1.726767 1.824526 41.247526 -52.831999 52.596061 32.003338 -19.889855 2.293056 0.638266 0.834324 1.989725 1.054610 0.824608 0.685211 2.334286 0.597131 2.480092 0.905122 1.642816 0.314299 0.929439 0.823072
+1 0.003106 1 1 0.893150 2.211860 -1.298749 -0.290286 -1.511595 -0.889229 -2.284750 1.457406 -0.375322 1.845831 1.231515 1.267685 40.368370 21.187890 4.871813 -19.441443 -52.327871 1.007067 0.532415 1.541664 1.251848 1.554804 1.595872 1.067014 2.307956 1.314610 1.146794 2.161084 1.089741 1.768940 0.571326 0.776044
+1 -0.005671 1 1 -1.570820 -1.975718 2.315516 1.963024 1.117276 -0.818200 -0.735446 -0.050339 2.188729 1.059711 -2.273351 -0.156573 -63.837749 28.945621 39.055475 5.369786 -50.005899 1.387871 1.705744 0.435252 2.037851 2.166787 2.442840 0.311369 1.185966 1.283533 0.837541 2.054808 1.408135 0.265888 1.776097 1.605734
+1 0.057615 1 1 1.355238 -2.200063 1.658482 0.328624 0.260591 1.939151 0.430382 -0.093475 -1.811712 2.019151 1.963775 -0.401240 -6.834808 27.375177 44.603234 -53.448849 35.196449 0.575888 0.956932 1.650594 0.539227 1.289893 1.982131 1.680861 0.733861 0.996058 2.240537 2.211471 1.949931 0.488137 2.120815 1.537454
+1 0.007472 1 1 -1.331712 1.767296 0.757531 -1.046880 1.144546 0.412096 -1.109103 1.525543 -0.314211 1.646203 1.298496 0.755655 13.016521 68.673430 -55.665382 -18.074303 -24.818360 1.792425 1.537435 2.170093 1.758502 0.648282 0.419190 2.084151 1.819295 0.900120 0.809618 0.741858 0.407728 0.679355 0.663940 0.338861
+1 0.004567 1 1 1.933949 -2.179457 -0.730275 2.048552 1.296278 1.176073 -2.205159 0.832315 2.340413 1.011607 -0.214732 0.688373 18.073331 8.475727 -48.460646 21.917458 -33.279198 1.772896 1.807344 0.287579 1.845471 2.088857 2.165320 0.292436 2.468682 0.387960 1.444356 1.547362 0.259258 0.600467 2.302040 0.888665
+1 -0.024026 1 1 2.006699 0.021016 -0.213804 2.144117 0.534742 0.877829 -0.825351 1.598391 -1.171097 1.023420 0.398963 -0.360865 -7.010078 -68.382948 -12.207516 28.276283 39.489434 0.608780 0.261847 1.365659 1.887913 2.144863 0.719036 1.592076 0.269553 0.380861 1.386685 2.011468 2.000718 1.315371 0.448988 1.149560
+1 -0.016630 1 1 1.949928 -2.224216 0.981995 1.599287 -0.241385 0.408522 0.074118 1.623495 1.353547 -2.344009 -0.181006 2.043110 -20.198023 -18.172410 -23.703271 19.124521 -24.168347 1.413995 2.012430 2.403387 0.979604 2.461248 1.451871 1.844089 1.348608 1.051301 1.461383 1.960275 1.098618 2.464999 1.488644 1.140096
+1 -0.001917 1 1 -0.473972 -2.109563 0.596368 -0.101880 -1.701546 1.602349 -0.627633 -2.307374 -1.792778 -0.210390 -1.734285 -2.006500 -44.004546 65.589537 13.346036 56.829108 -73.178546 0.447675 1.572090 1.865105 1.318663 1.773632 0.681632 0.697488 1.681605 1.979741 2.009927 0.849858 2.055468 1.249530 0.850217 1.354520
+1 0.007352 1 1 0.199545 -1.467072 -1.859633 -2.284086 -1.518348 -1.284922 1.191173 1.815967 -1.182159 -1.114397 2.081161 -1.992382 8.831151 -74.847348 -59.370978 -48.020700 66.094259 0.568067 2.248839 2.244569 2.468091 1.706949 0.441724 0.547639 0.924471 0.579064 0.322942 2.187153 0.485214 2.489708 0.518824 0.373621
+1 0.001899 1 1 2.295467 -0.413175 1.820744 -1.005273 -1.715130 -0.510185 1.863245 1.737394 -2.299162 -0.419330 2.057435 -0.196269 -0.862132 60.141579 -50.477304 27.957617 -66.326319 2.178260 1.760117 0.789860 1.680417 2.273139 1.153377 0.298995 2.463711 2.347851 1.324994 2.429070 0.630158 1.812774 1.549204 1.975460
+1 -0.007666 1 1 2.204809 -2.000548 -0.308344 1.283238 -1.222005 -1.646110 0.264885 -1.288912 0.107589 -1.313487 1.763831 -0.940575 58.010560 -16.526128 45.367512 41.772618 72.392899 2.236745 1.478108 1.817321 1.467801 1.830070 1.990762 0.491897 2.318502 0.816154 0.354589 0.825512 2.379017 0.883329 2.112131 1.844190
+1 -0.022550 1 1 2.122157 -0.976226 1.111666 -0.854920 -0.557972 -0.174620 0.974785 -1.762951 1.578928 1.575122 -1.134769 -1.024463 29.145876 -45.257861 1.126030 25.194537 -5.416455 1.609608 2.428106 2.429433 2.223638 1.681365 2.446676 1.785786 2.454237 0.616110 1.968665 0.349717 2.190504 0.542247 0.289562 1.416305
+1 0.052654 1 1 -0.418317 0.224614 0.467404 0.108843 0.922982 -0.619562 1.404661 -0.930169 -2.352551 2.332289 1.121767 -0.736129 -66.750586 -27.104868 -1.521492 -71.715543 -73.127654 2.027816 2.249122 2.499933 1.380469 1.045557 1.681081 2.183229 2.027757 1.264233 0.455829 1.367711 0.366331 2.420007 1.311823 1.565641
+1 -0.006126 1 1 -0.344191 2.003138 1.439684 -1.354081 -1.916614 1.362675 0.275037 -0.313341 2.123349 0.211425 0.275732 1.941987 30.752715 -39.120860 -54.301208 -40.401546 21.211475 0.643885 0.781213 0.348532 0.277379 1.410993 1.065166 0.490694 2.343464 1.845008 1.046781 1.992881 2.343861 1.776974 0.603390 1.932443
+1 0.041081 1 1 -0.266810 1.914124 -0.803062 -0.788301 2.266405 1.222660 -1.481446 1.608011 0.297289 1.400760 -0.523507 -0.546223 -20.349103 -7.378045 47.197758 52.719058 -0.797400 0.596360 0.767934 2.165795 1.518512 1.377406 1.306561 0.865328 1.072875 1.806382 2.109623 2.432645 2.215801 0.464433 1.974268 2.268730
+1 -0.004473 1 1 -1.228050 0.420980 2.112620 -1.051620 1.593197 1.071380 0.642825 -1.553070 -0.524847 0.494845 -0.506755 -1.752639 17.309137 64.671224 29.259448 63.537251 20.582074 1.718794 1.517181 1.508819 0.463695 0.827035 0.972911 2.468106 1.959643 1.718058 0.404480 2.340605 1.051242 0.467671 2.390199 2.079760
+1 0.002107 1 1 -0.597136 1.326050 2.025998 -0.776004 1.594898 1.390657 -0.671950 2.140861 -2.350050 1.946716 0.347711 0.616621 32.238508 32.610149 -21.222851 7.537688 -64.078106 1.963998 0.659939 0.590376 1.456152 1.801009 1.812109 1.613933 0.878246 2.181678 0.712285 0.620031 0.359629 2.280144 1.880681 2.106635
+1 -0.018181 1 1 1.108690 0.964889 1.563340 -1.234713 1.539284 -0.265464 0.975511 1.005796 1.069886 -0.894082 0.976223 -1.159869 39.229567 -68.662629 -62.800026 69.954731 29.168004 1.774662 2.251519 2.275907 0.416011 0.404077 2.330172 1.196768 0.579148 1.738944 0.424549 2.139343 2.432126 2.496787 0.252325 1.081444
+1 0.030707 1 1 -2.057996 0.187430 2.266987 1.583896 0.253862 1.946345 -1.188741 1.360903 -1.232912 -1.179988 -2.322370 0.652355 -50.646967 26.430543 68.139732 -25.523931 19.285850 1.184130 1.921261 2.387027 0.506522 0.622749 1.041702 2.134766 2.015731 1.648278 2.103183 2.194445 1.544008 2.394907 2.450737 0.290081
+1 0.002555 1 1 -0.202373 1.067198 1.040531 0.528994 -1.474458 1.236945 -1.731041 0.684926 -0.814357 -2.122329 -1.910073 -1.805801 -73.664315 23.862138 -49.041644 7.083320 -50.633258 0.727448 1.215313 1.768231 2.150830 2.005936 1.270898 2.228027 1.205075 0.697703 0.801097 1.536775 2.325704 0.360969 2.300823 0.680268
+1 0.020373 1 1 1.622066 0.895739 -1.397403 0.390919 1.104077 -1.169936 1.691456 -1.548610 -0.972828 1.672808 0.766968 2.044124 72.251544 -68.307314 58.980728 -60.906798 -60.559690 2.474255 1.800512 2.447765 2.082655 1.440710 1.012999 1.220932 1.702934 0.455301 1.501219 0.989028 1.089394 0.442030 1.195569 0.673649
+1 -0.004606 1 1 -1.365718 0.421233 1.646845 -2.054991 -1.143670 0.179750 0.410903 -2.323307 -0.971160 1.432418 -0.952766 -0.438777 11.790711 16.483033 -19.668638 29.201437 -11.442091 1.266682 1.122711 2.408713 0.489999 1.912878 0.984258 1.921788 2.244414 2.122493 0.495471 1.636729 1.513350 2.368909 2.007576 1.831825
+1 0.019751 1 1 2.127532 -0.181155 -0.469180 -1.683473 -0.942911 0.252781 -2.092058 -2.082573 1.814831 -1.424773 2.192165 2.256716 -44.285920 -13.452608 -47.989195 -4.399033 15.452409 2.254576 1.904264 2.464938 0.460893 0.979295 1.754134 1.481054 1.832875 1.885660 0.291617 2.205423 1.539292 1.875976 1.776952 2.481534
+1 0.030228 1 1 0.382161 -0.005071 -0.402129 -1.024313 -1.264981 1.756890 0.217051 0.582309 -0.770773 -0.021046 -0.283608 2.331952 5.631577 -0.091539 -38.487907 -66.260269 -36.333661 1.227371 1.925602 1.090353 0.821983 1.571371 1.041461 0.334233 0.699247 1.991578 0.706731 1.777106 0.576604 1.727307 0.605954 2.274888
+1 -0.006858 1 1 -0.994741 0.938109 -0.849445 1.924179 -1.451136 2.077644 0.168883 1.556334 -1.166475 -1.412337 -0.846954 1.378359 -0.583482 -56.575883 -20.858677 -21.792318 36.518889 0.969528 1.855164 0.747813 1.485640 2.404620 1.443496 0.578602 1.568215 1.995923 1.724138 1.341092 0.732703 1.789684 0.470369 0.491481
+1 -0.004468 1 1 1.428557 0.144122 0.093816 -1.877312 2.167098 0.370333 -0.884456 -2.171964 -2.030494 0.605087 0.357942 -1.782748 -40.645454 -28.139783 4.667100 -10.042896 -40.946001 1.683492 2.202616 1.618702 2.270582 0.926660 1.374676 0.431595 1.314611 1.161251 2.144263 1.881672 0.760396 1.475605 2.498401 0.374604
+1 -0.043980 1 1 1.149375 1.469366 -1.999456 -0.808290 0.889751 1.629881 0.289206 2.211103 0.109198 2.167928 0.169202 2.215611 14.965727 -21.020230 -36.999692 46.178818 27.395943 0.529303 0.988201 0.693096 2.115385 0.281218 0.674309 1.359128 2.370624 1.580406 2.126278 1.111046 2.092743 2.234686 0.610506 2.274153
+1 -0.007904 1 1 0.302244 -0.145252 -0.228739 0.897209 -0.259548 1.448377 -1.322003 0.003692 0.790000 -1.980504 1.978456 1.297945 28.961956 13.599030 -41.098603 5.772977 -23.569120 1.732014 0.960027 1.920935 1.402724 1.578979 0.648938 2.452370 0.724643 1.327529 2.286360 0.609148 1.945769 0.284930 2.310488 1.116114
+1 0.018471 1 1 2.149208 1.277042 -1.684981 1.974405 -0.820628 0.867269 0.771238 -1.582216 -0.298746 -2.338057 0.891508 -1.826124 3.903987 64.307822 71.558138 -22.367902 -37.320793 2.116585 2.439006 1.124126 1.439304 2.137334 2.429882 0.771085 1.127161 0.689695 1.200320 1.783267 0.620737 0.973563 2.176657 1.821557
+1 0.013721 1 1 0.506754 1.725089 -1.763008 0.620541 0.910850 -1.888292 1.415008 -1.390746 -0.825304 -2.327402 0.892673 -1.095686 26.201432 -32.540774 -12.781177 -13.246755 -38.205311 1.875068 2.260032 1.356474 0.514710 0.980689 0.434352 0.411806 1.721914 2.208719 0.690113 1.481110 0.511979 2.328411 0.849639 0.626509
+1 -0.070124 1 1 -0.252992 -1.466912 0.833705 2.153064 0.109638 0.137438 0.841578 -2.182687 1.523850 -0.489800 0.469172 1.555127 67.288390 65.975559 51.223406 61.792440 -54.463137 0.445934 1.567585 0.406640 0.393914 0.255522 0.814645 1.982325 0.443588 0.390822 2.293222 1.185385 0.512309 1.126160 1.871146 1.603765
+1 0.012628 1 1 -0.632668 -2.099770 0.238811 -1.263365 0.650794 0.445885 1.286266 -2.173269 -0.398483 -1.006064 -0.860950 1.760056 50.723471 59.373445 -60.503456 -31.585994 -15.799481 0.746772 2.005051 2.145028 1.237205 0.711782 1.171902 1.150560 2.459831 2.383015 0.575623 0.988282 2.059316 0.673795 1.718793 1.507901
+1 -0.024441 1 1 -0.484229 -0.144539 2.318096 -1.793062 -0.265226 0.270858 0.142600 -1.929328 -0.263160 2.000639 1.846167 2.162235 -39.834439 -47.420069 -39.106788 32.206193 -60.520312 1.151867 1.932860 1.575876 2.498623 1.857941 2.409070 1.993319 0.716149 0.308418 1.082594 0.913037 1.917576 1.191680 0.562761 0.822124
+1 -0.019795 1 1 0.918536 0.050479 0.174968 0.150629 1.072160 -0.376139 2.251724 -0.465203 -0.805426 1.903360 2.073558 2.177030 -74.827635 -28.057288 41.164765 56.198741 -17.760831 1.280760 1.483091 2.314164 2.157837 0.512948 0.613097 0.826166 2.128245 0.412897 2.054478 0.356159 2.463975 2.271966 1.683374 2.461318
+1 -0.006534 1 1 1.429979 0.468016 0.967566 -0.578064 1.416132 -1.346035 1.373283 -0.515078 -0.257928 0.410217 0.285703 -0.117003 -44.464894 -21.467936 -61.597066 38.109102 -0.324031 0.685165 1.561149 2.472307 0.563832 0.828528 1.315309 1.657379 2.068220 1.823435 0.724392 1.606203 1.453610 1.816403 1.792150 1.421360
+1 0.033472 1 1 0.555334 -1.740475 2.349794 -1.548286 -0.230274 -1.344861 2.257920 -0.005472 2.287681 0.664400 -1.784792 2.062295 43.465021 16.607642 -25.366269 -30.880830 -14.105852 2.469301 1.800622 2.045547 1.009823 1.840464 1.183196 1.967383 1.309948 1.548056 0.674278 0.832557 1.528047 1.882019 2.092765 0.348970
+1 -0.058562 1 1 -1.764741 -0.224511 1.270387 -0.443237 0.807296 1.258402 0.760491 1.580010 0.916551 -0.322011 -2.218120 -0.231966 -48.091027 -65.889811 39.943012 72.206934 -68.055097 0.594856 2.498491 1.894448 1.734139 0.668069 2.242587 0.664497 0.700721 2.019456 1.254027 2.185699 0.794466 0.347058 0.253991 2.083503
+1 0.036429 1 1 1.615365 1.358633 -1.692767 -1.644881 2.064721 -0.259940 -0.428375 0.839901 -2.102102 -1.248435 1.814684 0.808703 42.644935 33.414602 -0.780985 73.983078 -66.401673 1.181137 1.127357 1.740176 0.895572 0.870506 0.343821 2.093554 2.362001 0.647794 1.228087 0.457582 1.583369 2.431436 2.137448 2.095830
+1 0.008837 1 1 0.058462 -2.323230 0.333760 1.762379 -1.765606 -0.632137 2.115857 1.525954 1.891961 -1.008034 -0.993604 1.205914 -6.243385 67.425679 -26.618646 70.420711 60.886196 1.589330 1.361306 0.721249 0.523720 1.663837 0.363033 1.001154 2.393626 1.165952 2.404320 0.897154 0.472799 0.829333 1.353310 1.335429
+1 0.047883 1 1 1.068128 -2.167173 -1.621591 -2.331930 0.184438 -0.905446 -1.519590 1.393584 1.393060 2.015585 -1.421079 -1.682297 -1.204554 5.057728 -44.760777 -44.373486 14.819392 2.417884 1.631744 0.978506 1.997143 1.983057 1.483774 0.295659 0.394563 2.171952 1.490183 2.248165 2.166486 1.885088 1.923471 1.274524
+1 0.002574 1 1 0.385332 1.454533 -1.540512 -1.520985 1.521407 0.871935 -0.914214 1.906697 1.603879 1.531417 -0.543925 0.285084 -34.813774 34.907272 36.520063 -7.305502 66.429084 1.729327 0.806515 0.352373 1.828713 1.682646 1.486850 2.485314 0.924782 1.308260 2.427628 1.138783 0.279509 1.202152 1.068128 0.780989
+1 -0.016312 1 1 -0.998677 0.768618 1.506695 -1.360031 1.755201 0.103532 1.187020 -2.004401 0.904497 -0.282097 -0.533288 -0.015621 42.917402 -37.229608 -68.028001 -46.620550 48.409217 1.580646 1.672656 2.330965 1.023016 0.837917 1.628442 1.724230 0.626872 0.590177 0.355466 2.073732 2.205630 0.514916 2.189619 1.427893
+1 0.059219 1 1 -1.186544 0.581560 0.788570 2.261020 0.265498 -0.412266 -1.735742 1.778661 -1.439424 1.008870 0.899244 0.960613 11.956031 -54.993483 24.531290 -52.608890 52.380971 1.629704 0.440955 1.132692 1.403966 2.204964 0.578307 1.099443 0.594022 1.978506 1.494600 2.233275 1.662045 1.734366 2.245211 2.010216
+1 -0.061501 1 1 1.876758 -2.061053 0.645338 -1.718500 -0.596486 -1.883824 1.107543 0.536358 -0.228857 -1.089455 1.879717 0.544114 -58.079122 64.200867 73.972994 64.107343 2.120687 0.510863 1.579422 1.339567 2.104664 2.338422 0.355738 2.141750 2.399319 2.362223 2.126781 0.564546 1.569619 0.839151 2.106825 0.416683
+1 -0.011346 1 1 0.312604 -0.371304 -1.298985 0.451543 2.132337 0.461426 -1.410851 0.571418 -0.031511 -1.812571 1.718996 -0.484174 24.995756 -46.336182 27.791743 -4.171009 -52.154962 1.848191 0.547907 0.930698 1.749032 1.227329 1.216862 0.791335 1.715216 2.132725 1.455975 1.078237 1.932892 2.110548 2.232811 0.607836
+1 0.013439 1 1 1.283408 1.630327 -1.641411 -0.866026 1.267808 -1.375050 -0.915236 -1.141011 -2.267876 2.315989 0.488698 -0.143157 63.192523 -73.271654 23.318099 -42.717203 -48.024066 1.517785 0.412623 1.952543 1.643464 2.201004 1.524457 2.299898 0.888660 1.706593 1.208971 0.925676 0.581097 0.750804 2.266619 1.816813
+1 0.058134 1 1 -0.899463 0.061695 0.181136 0.149460 0.264641 -0.671261 -0.431821 -0.543021 1.341851 -1.012679 1.056121 -1.346490 -49.740741 -42.640544 40.373190 -47.798622 48.555109 2.360657 0.560728 0.409212 0.880016 0.420985 0.746152 0.577563 2.095498 1.280462 0.967901 1.511642 0.667038 0.662523 1.271185 0.301593
+1 0.006265 1 1 0.205367 2.135366 -0.451703 -0.115757 0.694880 1.547388 -0.719353 1.816476 -2.059715 -0.428849 2.291472 -1.590068 -10.248137 -40.444861 43.213563 -9.641150 -38.808924 0.451112 0.839130 1.756453 2.200099 2.057407 2.333624 0.725852 1.401603 0.736678 1.096703 1.787169 0.956707 2.376387 1.677428 1.540304
+1 -0.001520 1 1 -0.393181 -1.423194 0.460938 -0.179348 1.620749 2.323024 0.920344 2.163717 0.090555 -0.141733 2.355800 0.434669 40.784330 -37.758676 39.925560 -71.109341 65.297763 2.267582 2.247816 0.786167 0.362580 2.381456 1.373854 2.363500 1.096430 1.694181 1.841704 1.770299 0.917020 1.359781 2.093579 0.537618
+1 -0.041038 1 1 1.046923 -0.425479 -2.333547 1.283305 -0.104182 2.023997 -1.423515 -0.219914 -1.578510 0.731588 1.176068 -2.303852 27.225235 74.521333 -19.962492 40.395769 31.694197 1.890466 2.307676 1.104431 1.167835 0.309803 1.866919 0.314995 1.378902 1.702967 1.013993 2.174879 1.191657 2.423049 0.680848 1.011304
+1 0.023485 1 1 -2.189946 2.049601 0.085601 1.420100 -0.626391 -0.279835 -0.225161 -0.240906 -0.966742 0.276876 2.334153 -0.522722 -47.771732 50.507976 37.554369 -23.721594 11.174892 1.621077 1.690953 1.595491 1.421974 1.123966 0.999567 0.473572 0.326270 1.863684 2.180884 0.867634 1.583037 1.353117 0.329340 1.724185
+1 -0.024555 1 1 -0.624838 2.267497 0.736397 1.897426 1.300592 -1.729577 1.728956 1.976634 -1.060957 0.178061 0.309370 1.814665 15.578881 -65.749859 -7.876534 69.090206 49.086937 1.437204 0.584342 1.280686 2.484959 1.713671 0.921165 1.271871 0.592801 1.707789 1.058701 2.095296 2.392092 2.386173 1.915536 0.667635
+1 -0.059609 1 1 -0.301183 -0.875968 -0.895629 -1.464745 -0.448619 -0.124824 -0.904372 -2.319304 0.344405 1.605731 -0.329231 -1.039872 35.914059 7.581983 -69.609601 71.441837 -27.047060 2.425836 0.274168 1.449664 0.758098 1.109170 2.077377 0.468826 1.559294 0.552559 0.355350 2.375048 1.677529 0.973545 1.872596 1.229834
+1 0.009771 1 1 1.960824 1.828205 1.860469 2.195295 -1.676854 1.918682 0.406568 0.228913 2.037847 0.449250 1.297772 -2.001179 -47.774359 6.348470 48.738550 -1.191547 73.670527 0.333171 0.861259 2.427353 1.027797 2.443362 2.331626 0.891742 1.752203 0.530650 1.135737 0.838691 1.127474 1.453846 1.285652 0.457167
+1 -0.024957 1 1 -1.701274 1.467211 -0.517605 -0.323778 1.078117 0.774820 2.062279 1.104967 -0.340319 1.106919 -0.520267 2.064950 -36.200399 -20.100574 -30.350855 43.183224 -69.561587 1.051176 1.613566 1.446737 1.058931 1.455050 1.277684 1.529736 1.027047 1.084412 2.208447 0.613430 1.925088 1.459580 0.915552 1.439655
+1 -0.059847 1 1 -1.923374 0.849406 2.137115 0.658928 0.484208 -0.213316 0.927994 -1.215522 -1.064752 -2.346687 1.926210 -0.303926 4.724482 54.363804 42.459277 63.075223 55.275713 2.408606 0.941928 1.480856 0.750609 1.232567 1.502263 0.539491 1.218358 1.192636 0.890767 1.115858 1.976908 1.637570 2.140066 1.082459
+1 0.002074 1 1 -1.672767 -0.077000 1.767919 1.803387 -0.555826 -1.808272 -1.439620 -2.288282 -1.354503 0.414898 -1.140808 1.142057 31.842630 -20.912327 -23.472233 2.178021 5.995775 0.939805 1.800724 1.525593 1.148274 2.291554 2.400133 0.279899 1.004443 1.425126 2.345968 1.180604 1.164120 0.858505 1.149768 0.397107
+1 -0.002865 1 1 0.022658 -0.886844 0.095493 -1.976596 1.689444 2.345177 0.964368 2.223372 -1.024315 -1.310861 -1.226092 0.344187 -65.579158 11.099039 -58.454070 62.447080 -1.927832 1.358834 1.918211 0.625366 2.284671 1.457991 1.210034 0.786485 1.209512 1.024857 0.274148 1.111055 2.242810 2.156004 1.214756 1.411108
+1 -0.003531 1 1 -1.123605 -1.881640 0.122404 -2.064343 1.903531 0.236736 1.563495 1.378446 1.437690 -1.870038 1.901247 -0.455801 54.183758 16.426083 73.171489 -56.788910 -1.203084 1.821507 2.070159 0.666246 0.850239 1.708714 0.850891 1.417441 1.422405 1.602244 2.419940 2.437045 1.915112 0.278813 0.756193 0.584278
+1 -0.020396 1 1 0.391225 1.542879 -1.102041 -2.309569 -0.970985 -0.346944 -1.868488 -0.323520 0.695766 2.308960 0.170055 -2.300259 -0.291333 53.568839 31.471076 34.371683 34.873149 2.320308 1.920784 1.119551 1.045784 0.990895 0.976195 1.403759 0.979252 1.034863 1.947942 0.809147 1.833261 1.617813 0.839842 2.474406
+1 0.011708 1 1 2.295651 -2.040699 -1.257617 -1.704735 -0.152339 -1.533687 0.082816 1.736822 2.226512 -0.096202 -0.522183 -1.856116 8.591655 -50.046887 61.964640 -10.292133 -29.880620 1.321194 1.551064 1.731917 1.572676 0.466046 2.091070 1.114204 1.181583 1.860477 2.294007 0.879546 1.524944 1.475734 2.417888 1.695437
+1 -0.022708 1 1 -0.891706 -1.506950 1.780848 2.336841 2.242736 -0.740762 0.147498 0.283973 -0.908614 1.781841 0.167962 0.209389 -30.606834 -59.067440 -46.464901 -35.583813 -7.145557 2.194250 0.518532 2.212889 1.022503 1.204168 1.204767 2.273589 1.959364 1.535403 1.761038 0.514341 1.536272 0.622908 1.472494 1.950837
+1 -0.012442 1 1 1.663296 1.116368 -1.940541 -0.223596 -2.207027 -2.291497 1.166934 -0.304997 0.988522 -1.795675 -1.763567 0.659647 -49.839740 -56.509822 39.420197 -14.745844 -33.394033 2.072293 0.526962 2.145293 1.191310 1.090081 0.744843 1.070390 0.536151 1.340342 1.622380 1.081623 0.333324 1.171268 1.753624 1.906490
+1 -0.018009 1 1 -1.214534 1.398799 -0.487246 0.987551 0.739543 -1.780817 -1.816636 -0.638159 -0.140127 1.078245 -1.783061 -1.827761 27.928999 52.678331 64.705605 7.101421 -46.412111 0.649812 1.382723 0.671326 0.727565 0.929229 1.801752 0.789059 1.720778 1.117193 1.915668 0.631128 2.374579 0.554168 0.399637 1.957146
+1 0.032159 1 1 0.677232 1.811700 -2.214436 0.427346 0.730254 2.323758 -0.871902 1.478528 1.202049 0.832590 2.265207 -0.061619 35.101997 9.264678 11.447648 -49.374207 -32.294379 0.300461 2.347968 1.045197 2.370319 0.958362 0.938335 1.840783 2.042067 1.021681 0.886162 2.466387 2.307078 2.316619 0.667661 2.130953
+1 -0.006344 1 1 1.938313 0.488672 -0.582188 -1.906381 -1.009550 1.810894 -1.630371 0.893872 0.208988 1.727973 -0.413414 -2.190865 23.757368 -9.910160 -60.062140 35.616767 -38.989334 2.218993 2.360573 1.392878 0.346014 0.714129 2.372473 1.151929 0.719750 2.339929 0.942043 1.173306 2.258861 1.934298 1.004456 1.638446
+1 0.037676 1 1 -2.337726 1.744003 0.406499 -0.933609 1.083022 -1.602340 0.775600 1.033173 -0.617361 0.702030 -0.800243 -0.518137 5.454584 25.197074 37.230996 -58.644331 14.728779 2.073916 0.802089 2.467337 0.279516 1.330013 1.283858 1.794039 1.661475 1.155137 0.635964 0.397417 0.636687 1.300708 1.498303 1.481556
+1 0.009471 1 1 1.992181 1.069642 -0.287975 -0.370550 1.945747 -1.816663 -1.080066 -0.544344 -2.045930 0.356926 -0.023099 -1.803795 -50.610392 41.149977 -42.328789 30.046015 -66.629769 2.177040 1.511078 2.430751 1.880279 2.099389 1.437239 1.181527 0.922957 2.132366 2.168000 0.325640 0.288365 1.546958 2.470861 1.011476
+1 -0.027708 1 1 -1.575155 0.574069 2.113057 1.592697 2.091186 1.565374 -0.021080 -0.863265 0.543995 0.889204 1.862649 1.134477 26.510004 53.631382 32.644819 -38.534790 45.786744 1.942141 2.320352 0.406185 1.752045 2.372081 1.321216 1.933275 1.794223 0.253092 0.468552 1.445068 2.259768 1.414221 1.317507 0.333107
+1 -0.038915 1 1 -1.951493 -0.509549 -1.583146 -1.781524 0.441378 0.945807 1.291250 1.482371 -0.196561 -0.221404 1.651851 1.980189 68.329913 20.853712 -61.659475 39.199919 33.041441 1.787460 1.345550 1.415741 2.114807 1.807662 1.126711 2.128583 1.589546 0.503356 1.403072 0.682937 2.369291 1.676758 1.527007 2.399810
+1 0.020342 1 1 -0.663541 2.095975 1.939794 1.811632 1.361948 2.185301 -0.000799 0.715121 -2.268874 -0.316219 0.880341 -1.009996 -31.080118 -63.548494 -59.546629 -0.199187 -47.740995 0.881553 1.508698 0.693412 0.675479 0.776250 2.440352 1.240512 2.281618 1.901339 0.560322 0.335632 1.712898 1.430920 0.726307 2.289896
+1 -0.016481 1 1 -1.836909 -2.069980 1.405911 1.225974 -2.329338 1.339307 -1.348055 0.413243 -0.686288 1.487649 -1.019419 0.878025 -71.275517 -27.617240 -62.956200 -4.848687 -41.873668 1.814040 0.316715 1.029987 0.993764 1.941405 1.199656 1.872121 2.238755 1.501607 0.766771 0.628119 1.300916 0.490427 2.359741 0.911950
+1 0.002378 1 1 -0.138225 0.053871 0.639592 0.667972 1.699161 0.714012 -2.055862 -1.638003 -0.130917 0.362661 2.123835 -1.049988 23.803622 17.480750 -51.027216 -64.411197 -8.980417 0.866922 0.864926 1.057106 2.276021 2.337172 1.846662 1.846526 1.805939 1.418025 2.252549 1.595864 0.928270 1.438932 0.382359 1.811918
+1 0.012730 1 1 2.098992 0.810027 0.029690 -0.520477 -1.470674 -1.144800 0.029116 -0.734595 0.112656 -0.966513 -0.580094 0.287841 -59.603823 -61.445599 33.812579 -61.976454 -38.264812 0.374665 0.739925 1.671295 1.948009 1.937870 0.278836 1.145183 2.091193 0.931769 1.735801 1.607791 1.141871 0.428750 0.748568 0.687162
+1 0.053207 1 1 -0.008226 -1.600063 1.342151 -0.675188 -0.451355 1.024484 -0.569923 1.587816 0.173338 1.029059 0.924539 1.975163 -70.772215 31.382882 52.100390 -48.743332 70.826083 0.984626 1.351360 2.311559 1.117411 1.071911 1.356731 0.324048 0.521636 0.386748 1.315483 2.319452 1.023237 2.290843 1.694066 2.170544
+1 0.019409 1 1 0.313677 -1.191966 -0.997893 -0.202032 2.081158 -2.040364 -0.338293 2.160600 -0.469487 -2.122054 -2.004052 2.056097 27.806466 -56.722345 67.554096 31.699511 -26.323439 0.354330 0.973260 1.583492 2.258051 1.815119 0.450698 0.636244 0.604884 2.287802 2.334744 1.548854 0.581652 1.079154 1.583414 0.934305
+1 -0.001204 1 1 -1.813350 -1.960008 -2.256632 -1.905396 1.410040 -0.066795 -1.068342 -1.412966 -1.996150 -1.793490 1.963204 -0.574420 44.605899 -8.663625 40.458430 34.841358 -21.288810 0.609609 0.705725 0.626287 2.004820 0.507680 2.082257 1.492754 0.474688 1.079696 1.705681 1.630947 1.069335 0.812624 1.766268 0.671283
+1 0.022210 1 1 1.329336 0.713738 -1.950856 0.766628 1.044916 -1.175372 -0.137645 0.385824 0.296718 1.238976 -0.579515 0.593166 -66.060292 24.673616 -60.529215 -14.514914 -52.164860 1.602879 1.828763 0.263402 0.492870 0.667956 0.333648 2.118169 2.062078 2.092466 2.081191 1.576863 1.083320 1.855386 2.218523 1.220888
+1 0.011462 1 1 1.532938 1.452775 1.910256 0.161239 0.317562 -1.871620 -1.120521 -1.898526 -0.939687 -2.106123 1.865401 0.277377 41.948498 28.409046 20.839355 -2.955440 -22.076991 2.155181 0.872238 2.446374 1.212978 0.770519 0.608930 0.535969 0.525402 0.688400 1.942161 0.394610 0.714055 1.113952 1.435022 2.167013
+1 0.029756 1 1 -1.408490 -2.154063 1.951329 -2.248957 -0.155086 -0.575017 0.799784 2.232594 -1.537903 -0.078408 1.673904 0.340747 44.147158 -68.714254 -30.462237 -28.813083 -61.491560 1.545267 1.045967 1.821630 1.886315 2.293663 1.838594 1.249554 1.251992 1.728412 1.165802 2.128349 2.161609 0.910554 0.675942 1.811476
+1 0.016487 1 1 -2.202899 1.119198 -1.493459 2.331403 0.371849 1.041397 0.941894 1.496653 -0.489270 -0.049680 -0.885866 -2.306327 53.459051 -13.733221 35.751860 -18.488000 72.177275 1.876935 2.141673 1.101917 1.665584 0.476804 0.641564 2.263180 0.263216 1.867901 1.056257 1.512463 0.968281 1.146961 0.481095 0.765755
+1 -0.019711 1 1 0.773312 0.293576 0.264909 -0.878501 -1.058697 0.458491 1.097819 2.046222 -0.166995 1.895865 -1.371214 2.303832 -38.225197 -0.882568 16.682147 26.843812 -36.046380 1.652489 0.874203 1.730176 1.565689 2.277218 2.200532 0.339340 1.044189 1.180513 1.881087 2.170795 2.301454 2.279940 0.708695 1.037223
+1 0.000791 1 1 -0.124512 -0.374399 -1.490771 0.378866 1.161362 0.299531 1.389941 1.424601 -0.386433 -1.107643 -2.221483 -0.209763 -19.738044 62.690100 32.503627 -11.548256 8.465215 2.497904 1.016212 1.223696 0.903936 1.950302 2.225767 1.468156 1.051553 1.198311 1.763607 0.940572 1.187655 0.423701 1.394222 0.433380
+1 0.017048 1 1 -2.238318 -0.409173 -1.602450 -1.065310 -2.306474 -0.804241 -1.754703 -1.161473 -2.157038 -0.922000 -1.717015 0.792196 61.970536 -61.200907 -53.637382 16.518283 -27.212094 1.320112 1.363425 0.335469 1.220368 1.229008 2.436994 1.058030 2.062558 1.156149 1.891031 0.552539 2.269206 0.294163 2.240039 0.585716
+1 -0.019126 1 1 0.840909 0.696217 0.462579 -0.869870 -2.072082 -0.927795 -0.153762 -1.883582 0.461900 1.843034 1.335951 -1.211521 6.578402 13.209509 12.225297 -29.438895 70.490352 1.845113 0.559862 1.602336 1.705016 1.706118 2.226415 1.103663 1.771290 1.817523 0.359833 1.221483 1.960159 1.389562 0.866444 1.831320
+1 -0.027832 1 1 2.138820 1.043853 -0.183730 -1.337927 0.974715 1.771093 -1.400863 -1.205396 -0.530240 -0.615594 2.112576 -1.777547 41.970439 -52.830435 -71.120251 31.934149 17.243938 1.658114 0.921042 1.458075 0.374028 1.284438 0.300876 0.323517 0.597315 1.076728 1.317144 0.983833 1.536047 1.343964 1.747449 1.621127
+1 -0.040931 1 1 -2.238682 -1.820415 1.831621 -1.991232 0.753731 1.049775 0.387646 -2.075615 0.953802 -1.000378 0.455131 1.178884 -66.367277 -34.821577 53.749454 67.074355 68.682759 0.641886 0.932680 1.307873 0.429644 2.272497 1.609860 2.174420 2.479456 1.475275 1.440192 1.302843 1.376716 0.966434 1.601218 0.923098
+1 -0.007355 1 1 0.475351 1.727777 1.012334 -2.143695 1.838280 1.542958 0.222537 -1.462935 1.692206 1.629846 -0.288275 -0.704390 -36.744366 -12.557567 -5.024628 1.084148 71.275624 1.816289 2.117979 1.119612 2.065998 0.480806 0.413575 2.200356 1.885252 2.428556 0.995933 2.398179 1.195540 2.444957 2.136655 2.265003
+1 -0.011715 1 1 0.519307 0.654894 -1.339060 0.795277 1.893169 0.433062 -2.170338 1.739809 0.591440 1.895369 -0.277056 -0.636925 55.588989 -65.854878 27.059233 -15.463478 55.323734 1.014880 1.340282 0.612731 1.417725 1.713129 0.802349 2.333394 1.357699 0.843080 0.639703 2.488938 1.077956 1.699961 2.251240 2.086859
+1 -0.005666 1 1 -2.153430 -1.541717 1.794086 -1.376405 -0.116623 0.266601 -0.722791 0.594908 -1.076464 -1.261464 -0.378779 0.291671 39.332215 6.529383 -60.661817 6.843480 -31.639181 1.229207 1.277414 1.490614 0.503756 1.370856 1.472234 2.086611 0.414120 2.367157 1.814793 1.718790 1.459264 2.346302 2.295410 1.951396
+1 -0.054279 1 1 1.105692 -2.292111 0.268712 1.775810 -2.240820 -0.054803 -2.152428 1.153447 -0.788797 -1.365878 -2.264250 2.004780 24.357244 22.192465 -61.237216 -63.893438 -7.012618 1.958998 2.131399 1.677847 1.832012 0.869813 2.203472 0.251457 2.242871 0.934319 1.846278 2.149996 1.484841 2.475568 1.370110 2.435394
+1 -0.042930 1 1 -0.908435 0.068385 -0.474313 1.581490 2.227931 0.194904 0.648006 0.700720 0.744324 -1.545402 1.119136 2.169226 -50.068065 6.034280 18.140466 -63.185269 45.185747 1.177690 1.694244 0.649849 2.008100 1.645594 2.004243 2.055995 1.117008 1.051282 1.141404 1.570692 0.863921 2.169018 1.683334 1.798502
+1 0.035137 1 1 -0.729606 -0.849752 1.467489 -0.556890 -0.841858 2.205154 -0.917325 1.454937 0.542220 -0.673808 -0.822592 0.841570 -74.151783 -69.015211 11.350224 -36.789574 -22.369669 0.369496 1.618394 1.604920 2.395739 0.677052 2.459071 0.856600 0.622621 1.145089 0.516003 2.465762 0.819419 1.221689 0.928299 1.920195
+1 -0.007483 1 1 -1.819208 -1.453613 -1.854547 -1.628456 0.094951 -1.654282 -0.416420 -0.872230 0.666971 -0.997847 0.578368 -1.030917 26.345853 -5.249480 -28.014428 11.513183 2.064784 2.167306 2.158596 2.020873 0.308074 2.051786 2.360621 2.208331 0.912774 1.999465 0.505668 2.018697 1.984251 1.309627 0.643488 0.853720
+1 0.032825 1 1 1.530137 1.502590 0.338354 -1.142908 -1.162291 -1.773863 1.965129 -1.211877 -1.063063 -2.227599 0.672159 1.383994 13.689028 -28.506391 -6.911717 -65.235405 -61.447390 1.430685 1.280355 1.429990 0.848554 0.397999 1.415835 1.444100 1.732354 2.169183 2.212016 2.106343 1.301264 1.844984 0.642735 1.690146
+1 0.048715 1 1 0.825820 1.565984 0.794233 -1.515972 0.942302 -1.066066 -0.862200 -0.397230 1.204294 0.861308 -0.458978 0.140137 -28.865062 -35.097506 66.210088 -57.057022 -7.360407 2.029587 0.511075 0.638391 0.682001 2.385583 0.993400 0.328854 0.306361 0.253380 0.812720 1.133844 0.513066 0.341963 2.379747 1.911541
+1 -0.015743 1 1 -1.262609 -0.782268 -0.020090 1.644875 -2.171418 -2.279195 0.587667 -0.250059 0.709036 -0.867079 -2.286275 -0.599595 -73.320247 -43.396796 -69.945542 -24.717737 68.989728 1.530352 2.377495 2.308840 0.425300 1.270075 1.907855 2.063611 0.867420 2.476928 1.725701 0.598665 1.254799 1.657419 0.490086 1.132165
+1 -0.008478 1 1 -2.253241 -1.467362 -2.025111 1.543034 1.497989 -1.598052 2.158060 -0.738071 -1.752078 0.546942 -1.418429 0.446670 11.115830 73.747196 19.127499 25.878546 -59.283390 2.486033 1.759379 1.879825 1.221661 0.459697 1.128014 1.540031 0.810206 1.634780 2.498830 0.836875 2.113198 1.765312 0.350215 1.570573
+1 0.000170 1 1 1.547539 1.810750 0.663553 -1.888594 1.061916 1.810907 -1.410524 1.349820 0.978642 1.791290 -1.235716 -1.174357 -61.299043 -53.023572 -17.180861 -8.730327 -30.606746 0.511229 0.975536 1.582667 1.886829 1.935547 1.745799 0.901927 1.936312 1.094729 2.368304 0.840618 2.010840 0.431175 1.006333 1.688943
+1 0.009464 1 1 0.196360 1.553179 -2.350579 -2.218864 1.401581 -0.859105 -0.211272 2.299698 0.014992 2.215935 1.216588 0.145913 61.242618 4.677756 19.047521 31.683190 -0.626334 0.973161 2.159532 2.002274 0.470669 1.035269 2.016944 1.776658 2.044212 1.077331 2.458674 0.938545 0.874430 1.043987 2.291580 0.578638
+1 0.005964 1 1 -0.643544 -1.107948 2.079469 -2.157718 1.774713 -1.820132 1.871593 0.670169 0.918674 -2.342913 -0.611799 -0.078162 34.577187 38.780213 29.032302 -4.101106 72.712590 1.832451 1.509851 2.062619 2.193532 1.941965 1.599094 1.229530 2.208290 2.475447 1.587835 0.985063 1.946811 2.049927 0.375965 2.341203
+1 -0.007256 1 1 1.226105 -0.123492 -2.076662 2.206597 -0.225802 -1.588853 1.247008 -2.251728 0.400735 1.144465 -0.951944 -0.756119 39.133321 -36.271020 -7.041084 10.506473 32.283649 1.994253 0.655569 1.402317 1.499130 1.870052 1.222442 2.326042 1.543306 1.844789 1.863349 1.055002 0.671503 1.458948 1.532898 2.409893
+1 0.009684 1 1 1.847823 1.716492 -0.155067 -0.251903 -2.015577 1.564509 -0.436119 -2.086983 -1.618023 1.084752 -0.810065 -0.670495 -53.793036 -49.557950 29.533793 24.460701 -38.996467 0.420745 1.218951 2.158109 0.587165 1.484716 0.362888 0.816312 0.751201 2.183177 1.158402 1.513841 1.627738 1.146394 2.198407 0.628850
+1 -0.068119 1 1 -1.165378 -1.820080 -1.973357 -0.419443 0.151394 -0.217141 -2.094204 -0.454859 -1.319997 0.738316 1.154601 -0.237637 68.041974 -18.542588 54.731139 66.247231 -32.782764 0.926196 0.324500 1.367544 2.064528 0.516656 2.195603 0.747001 1.340751 1.749228 2.277811 0.912113 2.128574 1.438300 1.002716 1.641319
+1 0.007129 1 1 0.817384 1.165312 0.707753 1.126586 0.153111 0.376494 -1.007517 -1.718400 1.088086 -1.318285 1.242772 1.966218 -55.834337 -7.709209 31.316775 -8.959165 23.315827 2.411622 2.126601 2.026584 1.796396 0.771234 1.385117 0.408136 0.798015 1.488717 2.365582 2.335342 0.350400 2.430645 2.345344 1.953545
+1 -0.010807 1 1 1.849695 0.197104 -0.089514 -1.218053 -1.203590 1.557292 0.799295 -1.275400 1.018101 0.532959 -0.813787 -1.966188 72.191058 -34.890461 -53.973654 64.802378 -16.427998 2.044650 1.686834 2.123141 2.386455 2.150034 2.117386 2.405566 1.592362 0.571019 2.366580 1.118443 0.429428 0.901719 0.697745 1.500469
+1 0.029876 1 1 -0.067693 -2.023575 -0.911869 -1.100554 -0.883932 1.921293 1.884367 -1.415953 -0.363770 -1.910749 0.967919 0.649952 13.807315 9.541276 10.225290 -43.555946 -44.788808 0.392615 0.926292 1.931334 0.673712 0.332129 1.339904 1.020308 0.312286 0.832667 1.133965 0.292717 0.444252 0.285979 1.943503 0.455667
+1 0.009915 1 1 0.533135 2.144835 -1.528394 -0.490911 0.657991 -1.127542 -2.088049 -0.675581 -2.336995 -0.115144 1.561273 1.742141 66.786467 30.146968 -19.903828 -23.635492 -41.717301 0.734746 2.369885 0.399997 1.241775 1.018048 0.586425 0.299411 0.451499 0.592185 0.359225 2.251996 1.290424 1.905466 2.417119 2.275929
+1 -0.014125 1 1 -1.938529 0.606365 -1.723757 0.581203 -0.508967 -1.227405 1.842837 -1.977945 -2.137108 -0.550240 -2.171895 -0.875790 66.751856 48.448551 74.800427 20.769967 30.834929 1.264757 0.269053 0.965943 2.358220 2.352340 0.284886 1.582131 1.867629 0.992922 1.294139 1.350759 1.211903 0.705635 1.349805 0.914238
+1 0.014224 1 1 -2.341159 0.589411 0.789502 -0.921457 -2.017755 -2.051804 0.589074 -0.162904 -0.024432 -0.654334 1.320791 -1.528508 73.693249 12.434794 41.584372 58.534993 -52.364586 0.751057 2.019396 2.484165 1.864988 1.609326 2.189717 0.822517 1.542973 0.754143 2.133224 0.854975 0.308841 1.440794 2.432012 0.567491
+1 -0.012424 1 1 2.115061 2.284687 2.183962 1.047461 -0.802304 -2.173197 0.803059 0.735635 -1.493391 -1.243395 1.705810 -0.626020 39.479292 -71.544366 -46.158619 12.096694 59.130793 2.293496 1.282230 1.442557 0.556770 1.381407 1.055345 1.931234 1.247216 2.458108 0.429330 1.502236 2.326400 0.811665 1.397919 1.833136
+1 0.005088 1 1 -0.414380 0.430876 -1.214040 0.275837 -0.991305 2.150642 1.811120 2.175737 -0.521087 -2.292110 0.284165 2.314592 18.466973 24.416369 -34.093039 -1.699789 -68.354069 1.722553 1.700587 1.513940 1.036942 0.887672 0.849022 1.509456 2.170767 1.833855 0.357481 2.185313 1.047116 0.885333 2.038374 1.956432
+1 -0.027748 1 1 -1.879065 0.990820 -0.876468 0.129894 1.287895 1.643320 -0.035497 1.872883 -1.212337 0.622923 -1.460241 -0.157065 -27.118377 71.444927 24.895770 73.201855 3.574108 2.425573 0.351268 1.262527 1.033577 0.577417 1.894032 1.501775 1.329422 0.342844 1.436113 2.498150 0.665481 1.488031 2.088479 0.312156
+1 0.011228 1 1 0.126302 2.181378 0.040743 1.465390 1.862584 0.044094 1.234773 -0.536308 1.067270 2.260662 -1.051329 1.781210 -32.279665 25.676552 -4.183933 30.633942 64.658395 0.829744 1.514215 1.168302 1.399566 2.499103 0.916798 2.125863 0.888314 0.394228 1.046193 1.115772 0.524860 0.570007 1.106724 1.462195
+1 0.020946 1 1 -1.700490 0.511092 -0.763623 2.334603 2.321711 -2.303243 1.677738 -1.201220 -1.021329 1.761772 2.154225 0.768970 -64.056115 -41.119500 -45.434560 31.341734 -39.472034 2.027951 2.273403 1.078866 1.242257 2.354693 1.578135 2.221102 1.816872 0.670037 1.556994 2.395728 0.502033 1.662399 0.943681 1.694384
+1 -0.009031 1 1 -1.881846 1.367215 1.166570 -1.715575 1.442855 0.110059 -2.210782 0.580690 0.299806 1.301015 0.671548 0.529660 9.418352 44.250464 17.550505 71.338638 38.485507 1.763618 1.136123 0.573714 0.417183 2.091080 1.288766 1.033294 0.320485 1.391212 1.603201 0.495375 2.270616 1.486249 1.392297 1.839935
+1 -0.013950 1 1 -2.028173 1.912538 0.829655 0.057652 -1.790909 -1.779826 0.702642 0.060139 2.312447 2.217608 1.053316 -1.359336 -22.181244 -50.169198 -43.718118 -70.417384 -4.974222 0.598701 1.871724 2.320876 2.463016 1.916789 1.473324 2.401054 2.268696 0.725797 0.465931 2.400839 0.896915 0.943960 1.885597 1.484564
+1 -0.007275 1 1 0.623609 0.643912 -2.131387 1.353981 0.230382 -1.547456 -0.420819 0.583448 -0.478074 -0.366736 0.068754 1.009289 -47.398403 25.036564 39.528471 5.009448 43.800085 0.595317 1.250101 1.450754 1.075395 1.409270 1.354156 2.047938 0.685000 1.050833 0.350771 1.911425 1.314237 1.624086 0.511376 1.202588
+1 -0.037857 1 1 -0.778102 -0.675077 1.411905 -1.705899 -0.869242 -0.941252 -0.139559 1.203665 -0.295707 1.618722 1.234196 -0.805748 38.368920 16.436655 -49.136276 66.614429 -11.286371 2.274361 1.427985 0.892058 0.326437 2.431582 2.341696 1.386200 0.615674 1.379289 1.467556 2.220581 2.050120 1.360306 1.910607 1.063216
+1 -0.014940 1 1 -0.931767 -0.937099 -1.011590 0.500006 1.407657 2.293417 -1.874279 1.308406 -2.341163 0.527636 -0.745771 0.780117 49.927228 26.920643 55.255242 24.854790 -15.537815 1.464249 0.631780 2.071737 2.429946 1.860874 2.205124 1.019488 2.281928 0.356816 2.256857 1.986431 1.953306 0.959060 1.415057 1.866794
+1 0.076893 1 1 0.896039 -1.066993 -2.319419 -1.596526 -0.463840 -1.466289 1.879488 1.404404 -0.539815 -1.324566 -0.646425 2.298403 57.600526 -7.963577 -43.834302 -73.117254 68.308919 0.895075 1.521658 0.257363 0.254556 0.320583 0.785571 1.600179 1.451595 1.706583 1.046666 2.312141 1.899024 2.149706 1.106458 1.486467
+1 -0.002848 1 1 -0.084810 -2.258127 1.247442 0.338116 -0.426933 1.501513 1.087909 0.418074 0.400486 1.682231 -1.071240 1.705493 -39.726581 -34.641594 -71.273911 -0.623310 24.028885 2.177021 1.199445 0.576218 1.998658 0.453774 0.578188 1.359906 1.938667 2.427353 1.023888 1.990237 0.656768 1.296001 1.134968 1.410537
+1 -0.012540 1 1 -1.617860 -0.879900 -0.999362 -1.314587 2.130746 2.012674 1.475689 0.603719 0.933168 0.923680 1.675118 1.900637 -40.827096 68.991576 41.418491 -29.416527 -3.561001 1.378941 2.368828 0.650355 1.508987 1.050893 1.360032 1.814201 0.781968 1.789823 0.559628 2.162899 2.350319 2.305869 2.233248 1.200451
+1 0.009019 1 1 1.683927 -0.840551 0.608586 -2.096783 -1.394307 0.593917 1.117790 -1.593744 -0.834408 0.180335 0.829857 -1.263575 58.205891 -33.588058 -64.487171 64.121220 -64.658987 1.771016 1.724587 2.132710 1.215731 2.045639 0.305218 1.292111 1.010116 2.272433 0.528648 1.228988 2.104195 1.209549 1.646343 1.091251
+1 0.041643 1 1 1.467021 0.996067 -2.227128 -0.831340 -0.095049 0.011127 -1.483027 -1.408188 -1.794775 -0.786869 -1.938497 1.130885 54.694552 51.334094 -27.874500 -36.721944 64.291505 0.584797 2.186113 1.007618 0.793320 1.331570 0.440476 2.077321 1.787257 2.432140 0.478861 1.459473 1.357162 0.825060 1.526399 1.194780
+1 0.024840 1 1 -2.316817 -0.266472 -1.827751 1.056915 -2.141292 -0.176838 1.402100 -1.561071 1.659015 -0.143353 -1.310831 -0.716951 -7.169385 -45.858222 -39.140281 69.302801 22.182169 2.360668 0.745521 1.213697 1.605080 0.588575 0.429778 2.282391 1.389453 1.294724 2.174987 0.762954 1.726341 2.362192 1.609455 2.100980
+1 0.013332 1 1 2.047178 1.762447 -0.628384 -0.784359 -2.171899 -0.939484 1.315945 1.850079 1.931569 0.233016 0.297123 -1.390386 16.365264 -49.004382 33.353302 18.942852 72.514562 1.408537 0.279051 0.254374 1.761613 1.182040 0.548676 0.348270 0.367580 0.918113 1.723954 0.489261 0.762475 0.415635 0.819596 1.952702
+1 -0.015559 1 1 0.829686 0.571108 -0.522869 0.752119 2.244237 0.934190 -0.751586 2.006243 1.781796 -0.583855 -1.665253 -1.029839 3.491671 34.514902 41.964192 -7.820787 -43.971303 1.739758 0.604850 1.720341 0.522993 0.690461 0.580524 2.374646 1.673910 0.905600 0.677408 1.698181 1.570132 0.456418 2.261918 1.562515
+1 0.021334 1 1 -0.450805 0.836010 -1.524128 0.525028 -2.161942 1.480829 2.162895 0.398898 -1.449442 2.280378 0.459099 1.891189 4.609364 69.587885 13.584824 20.142350 -17.529906 0.998000 1.138395 0.508351 2.102475 1.551121 0.440216 2.217145 0.559723 1.506473 1.548589 0.639153 2.238510 1.884264 1.577958 1.496587
+1 -0.063206 1 1 2.143226 -0.306345 1.894717 -1.821910 0.256173 -1.615447 1.968030 0.423655 -0.045786 -1.411616 1.846077 0.647463 32.160368 69.310951 9.160457 59.809944 -74.275442 0.664794 1.186645 1.436420 0.908723 1.413956 1.353295 1.073754 0.838270 0.811800 1.428328 2.156156 1.512791 1.984562 2.037907 0.858252
+1 -0.018333 1 1 1.282175 -0.236670 -0.457031 -0.128805 -1.836966 1.693832 0.690047 0.430114 0.114539 -2.305001 0.394246 0.472011 68.077100 -28.180380 72.358359 -73.066558 20.361045 2.246162 2.242621 1.227450 0.996707 1.899183 0.322679 2.266278 0.583479 0.278063 1.662792 0.793799 0.378805 0.573654 1.648413 2.119891
+1 0.010339 1 1 -0.132615 0.095275 -0.926628 0.612598 -0.627941 1.941243 -2.101394 1.223310 0.015353 -1.140534 1.049702 -0.850741 -32.446419 73.034155 35.037529 -24.257405 5.791278 1.135214 1.033885 1.248133 2.115480 1.881536 0.725268 0.585299 1.617637 2.376385 1.658041 1.938319 1.072603 1.735334 0.510809 0.666078
+1 0.016390 1 1 -1.886976 -0.032746 0.987532 0.413332 0.802815 1.345024 0.490850 -1.677379 -2.192167 -2.299682 0.253132 -0.897787 -1.121359 53.324295 -28.570220 -29.685065 -16.893539 1.679358 2.475354 2.265885 0.725701 1.101032 0.294980 2.478029 2.231751 0.794254 1.281838 1.595750 1.262833 1.683355 2.152397 1.340655
+1 0.022812 1 1 -1.116756 0.122688 -2.016589 -1.304475 -2.271551 1.823746 2.329398 -0.332938 -2.084331 0.540671 1.563498 1.432181 -6.653298 -71.982001 -51.495105 21.771150 57.713930 0.595404 0.460830 2.176609 1.013940 1.287193 1.596881 2.278392 1.686260 1.469319 0.340549 1.112909 1.908983 0.784601 1.045505 0.810441
+1 0.067747 1 1 -0.181774 -1.454035 0.480911 0.931726 0.254027 0.015513 1.544359 0.198828 0.618820 0.257506 1.927418 1.146944 -54.105035 -43.330227 -1.128489 -66.521289 -73.296946 2.098538 0.635557 0.309186 0.480830 0.817480 2.385411 0.353621 0.309227 1.180713 0.748607 1.335855 0.464981 2.185392 2.379650 0.272218
+1 0.002048 1 1 -1.704891 1.941986 0.949897 -0.647635 0.808882 -0.355322 -1.301442 1.569311 0.171831 -0.738353 -1.782461 -1.172806 18.207269 9.565708 -29.148594 -0.425439 49.650799 1.839689 1.655971 0.905770 1.271896 1.008628 2.007780 0.752878 1.114780 1.864566 1.266182 1.716563 2.268340 1.486634 1.114519 1.966706
+1 -0.013561 1 1 -0.869267 -1.363871 -1.513288 -1.064818 1.250608 1.714037 0.982950 -1.202800 0.683307 0.245342 0.125021 -0.500502 -10.117500 55.172206 -20.739854 25.272501 -45.081495 0.854799 1.861286 2.376331 0.738974 1.442781 2.078407 2.033042 2.338585 0.850910 1.737666 1.455429 0.888509 1.413401 1.024523 1.403919
+1 -0.035242 1 1 0.156710 -0.400668 -0.016684 2.337497 -0.868961 -0.935431 -1.266880 -1.885430 -2.321907 -0.994537 -0.331891 1.384556 14.682972 26.710918 -19.605685 37.255733 57.097883 0.536671 1.078497 1.793032 0.496163 2.008254 1.974182 0.818338 1.052822 2.275236 0.387253 0.805100 1.310335 1.307363 0.842859 1.424205
+1 0.000346 1 1 0.488041 -1.759524 -2.078005 -1.510788 -1.463151 -1.936543 0.995968 0.827354 -0.917060 1.195916 1.427764 0.940916 -25.669461 -26.624376 -25.889415 26.595974 -1.465499 0.915417 1.415621 2.340174 0.553981 1.752392 1.456017 1.785023 0.880348 1.504886 1.873587 2.134704 0.966409 1.186448 0.380708 1.063345
+1 -0.018344 1 1 0.947529 1.960453 0.311484 -0.351253 1.122246 -2.100882 0.406644 1.496768 1.446645 -2.170079 1.371215 -2.287125 -23.782099 44.264211 -51.405683 24.689970 64.323091 1.797737 0.808660 0.392686 2.120046 2.107275 1.214605 1.122089 0.943435 2.060259 0.765836 0.648215 1.544923 2.016462 0.420256 1.985356
+1 -0.036293 1 1 -1.633247 -0.321365 -0.786453 0.338265 2.073739 0.503369 1.386044 1.895620 -0.778716 -1.575586 -1.951713 0.495646 -37.701379 -47.074138 74.955407 -74.469556 -9.821945 2.463631 1.003026 2.358013 1.127544 0.381364 0.836452 1.744819 2.431444 2.285578 0.961546 0.451436 1.781417 1.023381 2.456737 2.133506
+1 0.000363 1 1 0.516388 -1.280369 2.320219 0.900786 -1.399544 2.115188 -0.306350 1.816566 -0.542841 -0.345494 -1.048215 2.280103 17.307991 45.411312 27.916606 -5.600138 -71.527576 0.415376 0.967256 1.927378 1.690969 1.869158 1.936697 0.814169 0.733393 2.128754 2.226878 2.134540 0.463155 0.744881 1.723203 1.366136
+1 0.019867 1 1 -0.129131 2.098902 -0.690325 -0.388579 0.515719 1.611149 1.192615 -2.226511 0.104058 0.604880 1.591910 -1.719078 -28.039877 33.781363 13.367621 -30.391676 -42.892741 1.400506 0.311454 0.357620 2.274096 1.477614 0.257284 1.177235 0.787865 1.895349 1.122405 1.759199 1.104419 0.967934 2.071619 0.445780
+1 0.009092 1 1 1.049051 -2.353847 -0.593817 0.559442 1.329810 -0.752548 -0.029306 2.259848 -0.588786 0.282613 -0.213710 -0.977525 -59.796915 -6.744312 48.351779 -51.649023 -15.133466 2.152517 1.099669 2.130997 1.661321 0.825370 2.242547 2.243088 2.336952 0.400076 0.326510 1.399936 1.973790 0.983522 0.807661 1.603439
+1 -0.010104 1 1 1.156992 2.244397 -1.087664 -1.012084 1.626730 -0.836294 1.468407 0.740709 -1.035295 -2.063542 1.232280 -0.019293 28.712769 25.504963 -38.093393 -35.652228 43.002706 2.072127 2.242662 1.926206 2.236392 2.292461 1.888420 1.673960 1.752292 2.027249 1.732160 1.155329 1.613614 2.252012 1.560798 1.075664
+1 0.027691 1 1 -0.292984 0.256095 1.773582 -1.985260 2.166433 -1.384264 -0.252429 -1.422077 0.388664 0.898331 -0.242977 1.934801 -63.421730 -29.014823 -2.129472 59.972484 -42.463642 1.578465 1.004007 0.844080 1.702898 2.113646 0.290395 1.926782 0.671383 1.687608 1.623741 1.456513 1.118780 1.579065 2.097922 1.522889
+1 0.019590 1 1 -0.523765 -0.171212 1.709488 -0.061750 -1.103232 1.227599 1.411718 -0.132664 -0.729640 -1.424762 -2.329070 1.127420 1.071821 14.092455 1.899531 -24.579622 -9.710715 1.255188 1.439125 1.369817 2.016245 1.283172 1.514259 1.902364 2.039098 0.616890 1.567947 1.979746 2.086757 0.623439 1.394015 1.453213
+1 -0.016088 1 1 -1.006142 -2.173246 -0.019237 1.835862 -1.381536 -1.541884 -1.019484 -0.220841 1.679647 -2.095551 0.469407 0.790912 -25.217164 -74.881697 -36.688193 31.537357 -51.640917 0.941508 1.175343 0.494024 2.067680 1.750421 2.077936 0.862347 0.474135 0.784470 1.089690 0.924079 0.751327 2.053710 0.960371 0.947975
+1 -0.013135 1 1 -1.749677 -1.515641 1.790593 1.188669 2.138879 2.029606 -1.399520 -2.190627 0.035659 0.841440 0.206685 0.719625 -62.455194 15.555305 -11.996195 -20.051997 36.089334 0.676528 0.405779 1.679820 1.243886 0.489774 0.374565 1.308480 1.632508 0.305970 0.438252 0.700865 2.187235 1.861189 0.759970 1.068434
+1 -0.042193 1 1 0.282824 -1.371407 -0.946260 0.514230 0.144685 0.127181 -1.890002 0.944150 1.713278 -2.341519 -0.747441 0.980123 -50.413650 47.779641 -67.568094 33.045699 -50.934803 1.206452 1.342070 1.412790 2.008124 2.046682 2.085694 0.756449 0.383631 0.689856 1.666524 0.524945 1.992647 0.671048 0.558539 1.858845
+1 0.023672 1 1 -2.322632 0.950175 -0.696546 -1.270707 -0.231972 -1.616082 0.715752 -1.089989 2.327463 0.134792 -1.207542 1.102675 -37.355438 67.151237 10.842542 -19.400221 40.484250 1.656751 0.514649 2.200138 0.465908 2.008697 0.413155 1.900390 0.356075 1.048942 2.312372 1.285403 0.776853 1.319327 1.675727 2.190163
+1 -0.014572 1 1 -1.915942 -1.480639 1.025127 0.816639 -1.945100 -1.450745 -0.775917 -1.650737 -2.106715 1.324519 -0.141129 -1.628905 62.991951 5.726013 -62.903853 -25.052473 -6.919116 0.781306 1.913579 1.520412 1.812878 1.040697 0.987927 0.580913 2.153957 0.553078 2.324452 1.816955 2.070912 2.064729 1.653670 0.488409
+1 0.030048 1 1 -1.043475 1.834955 2.222231 -1.350207 1.937617 -1.789522 -2.032934 2.006654 -0.738878 -1.177897 -0.174654 0.406008 7.518205 58.466995 4.787495 63.428875 -0.895411 0.637528 1.929889 1.146256 2.126775 0.463415 0.621205 2.096079 2.044483 1.131633 1.599506 1.398623 2.412574 2.372864 0.973890 0.914094
+1 0.004585 1 1 -0.563538 0.510972 1.941966 0.611441 -1.223875 -0.086668 -0.507347 -2.267189 -0.261230 1.451513 -0.462710 -1.325908 11.162517 -41.577500 56.958738 5.504215 -40.664185 0.730556 1.707672 1.345701 1.701696 2.159686 2.333397 1.403008 1.848220 1.027815 0.479214 0.650685 0.309431 2.354284 1.454421 1.955799
+1 -0.007827 1 1 -2.112168 -0.781262 -1.960050 1.755905 -2.193171 -0.317494 -1.692114 -0.083910 -1.269332 -0.670259 2.273927 0.414727 21.856625 -5.707469 74.574921 -19.302744 28.785953 2.207698 1.530155 1.311623 0.444528 0.440195 1.861507 1.601091 1.045027 1.777945 1.163117 2.014124 1.629859 0.786359 1.338609 1.757728
+1 0.023554 1 1 1.232495 -1.111674 0.713813 -0.684108 0.429265 -0.010653 0.031382 -0.343560 -1.540729 -0.450510 1.080782 -1.551911 3.415590 -44.181960 -66.206671 -35.517777 52.727129 1.147780 0.731095 1.756526 1.185006 0.891922 0.286203 1.212868 1.178459 1.118770 1.422606 0.493115 0.277991 0.449051 2.203231 0.710820
+1 -0.008999 1 1 1.328644 -1.487338 1.525271 -0.170664 1.491953 0.625007 0.581331 1.642922 -2.003419 -1.438239 2.071162 -0.393518 74.232028 67.699772 -69.932001 52.860559 -22.591530 0.687366 0.307437 0.341386 1.667356 1.002597 1.904599 1.352724 0.476000 0.629079 1.681204 1.989470 1.279680 1.339546 1.751615 1.885914
+1 0.016597 1 1 -1.111335 1.697937 -1.003875 -1.779666 -1.313975 -1.716023 -1.384797 0.204206 1.470134 1.481129 -2.208684 -1.870095 30.005115 -4.036999 -49.846416 -18.708260 -29.733734 2.352031 1.843708 1.705135 1.457753 1.706306 0.881743 2.450442 2.085519 2.321273 2.379064 1.675538 1.261661 2.231719 0.251024 1.711078
+1 0.054301 1 1 1.253971 1.693825 0.577782 -1.459682 -0.180460 1.790057 1.603112 -1.939616 1.178265 1.639594 -1.394256 1.450070 -36.687537 42.561972 -10.935650 -45.462355 14.197884 0.982559 0.370547 1.291401 0.319687 1.475579 2.051353 1.837492 0.727778 2.264101 2.251380 2.184693 1.893031 0.416673 0.280445 1.191108
+1 0.003850 1 1 -0.408752 0.767400 -0.115966 1.887651 1.951720 -0.375857 2.290591 -2.262352 0.923278 -0.356017 1.154143 1.494191 17.688325 -12.325289 -1.124028 8.454546 45.559687 0.949930 0.971539 1.912051 0.587467 2.058263 0.976928 2.478195 0.526335 0.603995 0.852148 2.309643 0.425406 0.792155 2.002882 1.681985
+1 -0.011829 1 1 -0.591418 -1.535596 0.989208 0.306672 -1.124170 -1.963024 -1.100495 0.109898 -0.205045 -1.430247 -0.260924 1.892270 -16.841941 -12.499208 -74.182552 13.844527 34.961314 2.046964 2.325862 0.755327 1.775605 2.345321 1.551331 1.714231 1.328933 1.118371 1.465300 0.300031 1.877297 1.479553 1.355220 1.927448
+1 0.031759 1 1 -0.928407 -1.018533 1.633438 -1.193376 -1.148890 1.983270 2.090778 -0.573970 -0.446520 2.167944 0.442637 -1.454580 23.644540 43.791482 -46.554966 -49.310066 -4.286365 0.761077 1.671195 0.272640 0.505291 2.425428 2.422730 2.073790 0.940889 2.024181 1.904729 1.278339 1.290921 1.263471 1.152789 1.673154
+1 -0.040706 1 1 -0.419963 0.838423 1.339402 0.253867 2.033494 -2.019095 -1.017080 -2.221280 -1.514652 -0.434788 1.436630 -0.849740 53.041592 20.036698 6.787435 -73.581071 72.942256 1.232530 0.879175 2.040025 0.456237 1.471034 2.159927 1.899198 0.566832 1.752001 1.636011 0.692241 1.252722 0.499315 0.994413 1.607077
+1 -0.046729 1 1 0.886832 -0.295350 -1.808743 0.076566 0.364141 -1.273781 -0.054876 1.331680 -2.307786 0.720815 -0.819211 1.128318 31.302926 58.272482 35.612878 45.637786 -65.724400 0.925136 0.512574 1.074154 0.801317 0.737851 0.565526 2.295525 1.645572 1.624497 0.678093 1.952268 1.523568 0.859085 1.897272 1.950336
+1 0.025518 1 1 -1.931559 -0.059823 -1.703992 -1.801819 -1.357556 0.950219 0.047047 -0.964946 2.192580 -0.183705 -0.919255 1.997167 1.118275 44.853792 -42.317081 -73.175583 -12.022486 1.196279 1.365082 1.180505 1.742607 1.241172 2.120883 0.424506 1.425196 1.273381 1.205644 1.251100 2.486990 2.085307 1.000276 1.145934
+1 0.001999 1 1 1.484422 1.295117 0.502174 0.145284 0.778670 0.799058 -0.537038 -1.768268 1.756849 -0.472917 1.482655 -0.131620 -64.670105 -10.449160 30.959661 -10.970444 -30.260014 2.424071 2.103027 1.827047 0.684022 0.351288 1.596505 0.461379 2.401133 1.350437 0.294481 0.834260 0.901274 2.219608 1.453325 1.532776
+1 0.025929 1 1 2.274168 -0.242497 0.566102 0.159946 2.144710 1.071457 1.938303 0.314668 1.324990 -1.651488 -0.591666 -0.996871 -59.312490 34.977931 24.092160 66.936674 4.678160 1.762636 0.366863 2.363716 2.473829 1.387265 0.507758 1.132706 1.640477 1.494037 1.782242 1.391768 1.936745 1.620377 1.171140 1.855303
+1 0.075260 1 1 0.825149 -0.273992 -0.976962 -1.832597 -0.290903 2.261229 -0.947189 -0.959881 -2.205880 -1.857802 0.203751 -1.464621 52.282096 5.184217 -18.862572 -73.251240 66.401865 1.617218 2.078867 0.767307 0.624269 1.831870 0.745512 1.071607 0.753652 0.635049 0.771971 0.260004 1.880686 2.187955 0.466336 2.466882
+1 0.044824 1 1 1.627899 -0.030323 -0.708529 -0.041347 -2.198275 -1.271343 -1.489045 1.111836 2.011316 2.225841 -1.950156 -1.599816 24.676925 -4.922470 68.046732 61.429601 -2.688278 0.896665 1.252904 1.308127 2.434305 0.857572 1.214573 0.583613 0.281882 0.586177 0.625471 1.797171 0.300766 0.717493 0.410857 1.524569
+1 0.005518 1 1 0.236077 -0.083114 -2.029724 -0.581501 0.207878 1.923393 -0.526587 -0.486555 -1.538329 2.176429 1.681833 1.662679 5.920112 49.322123 56.913413 -6.275437 -21.273100 2.320018 1.548811 2.109899 0.315678 1.593897 1.625151 0.418076 1.352824 2.157127 2.090585 1.971227 0.663758 1.780578 0.429647 2.326311
+1 0.023581 1 1 -0.749982 0.693983 0.614652 0.903531 2.331530 -2.202997 -0.527239 -2.011531 -1.121805 0.092926 2.007377 1.997488 22.776380 2.622473 -24.103780 37.762934 31.625847 0.409102 1.270294 1.082922 1.920479 0.486590 0.862626 0.651208 2.358585 1.730458 1.806842 0.849857 2.048776 1.284721 0.557667 0.708657
+1 -0.011988 1 1 0.176936 0.247841 -0.295477 0.769275 -1.595745 -1.479374 -1.275829 -1.494810 -1.524175 -0.262748 -0.499197 -1.957717 -46.175613 26.468652 -41.370165 -58.363654 -67.939280 0.542712 1.353562 1.058974 2.177931 0.732601 2.326420 1.131820 2.497104 1.068952 1.127646 2.094946 1.002281 1.091213 1.763167 0.289018
+1 -0.013219 1 1 1.771560 1.731499 2.306404 -0.388597 0.215251 -1.397052 1.585817 -0.448173 -2.038586 1.262300 0.307839 -0.356482 -62.212630 42.327878 -45.346175 16.830839 -24.093958 2.167791 1.319587 1.555801 0.352524 2.114087 0.960844 2.158890 2.456839 1.586451 2.488809 1.160423 1.730691 1.218245 1.536198 1.620762
+1 -0.047344 1 1 0.288742 -0.869958 1.164002 2.247782 -0.744894 1.386200 -0.196640 -1.537019 0.634076 2.201420 2.299772 1.254117 -18.473680 12.867479 -36.285578 48.289004 -56.710906 0.771998 0.717952 1.367052 0.549976 1.940831 0.542629 2.211491 2.281250 2.475976 1.477623 0.417476 0.275567 2.456501 0.410911 2.435412
+1 0.026612 1 1 -2.296860 0.564049 -1.347001 -0.730754 -1.288979 -1.012521 -1.003241 -0.541661 0.646762 -1.352599 -0.563706 -2.307134 71.725217 -64.278351 -26.241707 -44.365426 0.292670 0.908616 1.853540 0.453297 1.561611 1.243129 1.262524 0.991948 0.677922 1.329324 0.941723 0.290486 1.198932 0.955799 0.616721 0.987898
+1 0.009419 1 1 -1.789537 -2.281364 1.825034 0.404110 1.332446 1.144291 0.834463 0.742609 -2.087366 1.372846 1.562214 -1.300447 -17.467150 -20.393105 3.089932 32.482308 -69.847658 0.931140 2.422369 0.496881 0.570681 1.182077 1.171395 1.632574 1.427350 1.468497 2.281541 0.610100 2.199692 1.974845 0.726895 0.928680
+1 -0.007367 1 1 -0.863286 0.198347 1.962919 -0.649430 -1.075805 0.387285 1.281997 1.486707 1.993222 -0.285903 1.461981 1.124782 -60.123517 54.052776 64.999110 -9.952122 -15.313492 1.767161 2.171439 1.882724 0.442806 0.733024 0.438036 1.567039 2.468742 1.404265 0.481142 1.559883 1.460114 0.889232 2.325620 1.187871
+1 -0.021239 1 1 -1.169743 0.216140 -0.591038 0.133332 -2.187916 -1.527047 -1.411268 -1.721498 0.846732 -0.386220 -2.242511 -0.202104 27.442570 -22.723518 -14.175382 -45.647544 51.731050 2.031326 0.495311 1.196869 2.277867 1.864513 0.376435 1.244464 1.210582 1.002399 0.821558 1.177389 1.131719 0.806784 0.366313 2.129171
+1 0.006736 1 1 -0.191975 1.467531 0.148384 1.029539 -0.431068 -2.017796 1.963315 1.279804 2.314770 -1.152551 1.714157 -1.706338 37.518965 -18.757318 45.757482 -3.999227 -15.006560 0.396188 2.481682 0.623672 0.806403 0.713314 2.171251 0.970423 1.145857 2.174453 0.777019 1.852200 0.422052 0.686010 2.270523 2.172206
+1 -0.023421 1 1 -1.630610 1.598524 1.072184 0.014798 -1.044336 1.497108 -2.259677 -1.241139 1.919817 0.635758 2.201383 1.672207 2.869311 74.501950 -45.729243 28.617651 -73.138180 1.624160 1.757448 0.925758 1.964838 1.289437 1.065610 1.203388 1.583668 0.699091 1.624374 0.852305 0.434719 2.073962 1.584595 0.542893
+1 0.018688 1 1 -1.097208 -1.190708 1.287038 1.376063 -0.920314 -1.653249 -1.907060 1.712205 -1.524176 -0.287016 1.612591 1.867320 -14.943634 -57.657681 -52.641856 -51.667275 -21.886835 0.594383 1.290729 0.284148 0.431992 1.238406 0.642410 0.731869 1.275967 1.932289 0.980481 1.448075 1.042349 1.753228 1.996166 1.309098
+1 -0.053297 1 1 0.903157 0.758972 -0.400758 -1.536472 0.409311 -0.794114 -1.192899 2.162234 -1.273527 -0.505493 0.620622 2.277398 70.343407 -38.358408 10.231891 67.396925 -59.873860 2.125590 0.794145 1.699904 1.282603 0.963856 1.029676 0.259602 1.875993 2.066449 1.314318 0.735498 1.522699 2.009594 1.999016 1.964490
+1 -0.012983 1 1 -0.902104 -1.912262 -0.897117 1.804636 1.586856 -1.838275 -1.471004 -1.965062 2.339362 2.202148 0.391204 1.180672 -9.971649 -43.496243 58.650735 -57.099375 30.798829 1.163885 1.413839 1.644943 2.313601 1.685426 0.947202 2.379538 0.648497 1.785460 1.480500 1.514581 0.562039 2.188063 2.266151 0.698946
+1 -0.025382 1 1 -0.370985 -0.659809 -1.154389 -0.908701 0.314129 1.686214 -0.117661 1.674333 -1.879126 -0.044980 -2.001692 -0.697007 12.651700 -62.870913 -71.442113 22.408763 -25.925870 1.583419 1.015325 2.074353 1.398403 0.957746 1.843557 1.415482 2.261270 1.907056 2.143259 0.748286 0.439035 0.366833 1.867872 0.581492
+1 -0.022645 1 1 1.074084 -1.037421 -0.087377 1.721384 1.950985 1.402817 1.062992 1.042800 0.970372 -0.540361 -1.068526 0.200469 -2.667401 18.991021 -17.907019 -63.267988 4.917338 1.310471 1.336802 0.638078 2.168801 0.282092 1.875547 1.314399 2.103462 2.381151 0.758255 1.496925 0.817150 1.341888 0.612519 2.358845
+1 0.028010 1 1 1.971086 -0.056639 -0.034905 -2.305741 2.095839 -0.350215 -0.282277 1.146753 -0.189702 1.962829 -2.177332 1.999089 -20.265535 47.157444 -24.843382 57.270557 -3.754661 2.056191 2.156167 1.694238 0.556643 1.491697 0.702911 0.575159 2.197773 1.227318 1.035186 0.621774 0.409970 2.372550 2.446902 1.073905
+1 -0.041931 1 1 1.458786 -0.737819 -2.227368 -0.158368 0.810747 -2.008220 -2.021884 -0.769399 -0.493410 1.057393 1.185912 -1.782058 28.576430 -15.946779 32.490433 66.703311 -17.455140 1.846957 2.313519 0.315877 0.452348 1.370799 0.523936 0.797435 0.734046 1.856623 0.506937 0.841061 0.454251 1.845153 1.237804 1.767273
+1 0.006586 1 1 0.098781 1.455066 -2.007437 1.717421 1.305988 -0.560903 -2.312728 -2.235821 -0.852907 0.285562 2.221437 -0.569162 8.025207 29.649187 13.878440 4.940134 -71.167502 1.191934 0.332442 2.111099 2.489649 1.780976 0.358232 1.308596 1.331755 1.304792 0.383206 0.290697 2.494536 0.664575 2.012652 1.633114
+1 -0.032943 1 1 1.348929 0.142570 2.285759 1.360091 -0.742746 -0.219645 -1.765207 1.360790 1.575169 -0.341904 -1.969912 0.930802 -36.177448 65.636514 52.882689 49.357452 50.693005 1.334905 2.492156 1.160877 0.360990 0.405950 2.306058 0.920255 1.729312 0.549947 1.464833 1.447238 0.484697 0.544889 1.955788 2.184651
+1 0.021696 1 1 -0.578817 -1.803890 1.536280 1.077622 1.883619 0.160613 -0.776497 -1.985161 -0.882775 -2.194351 -1.300418 -0.072688 -36.927702 56.114766 70.867738 74.077419 19.185911 0.739157 2.264852 1.376195 1.217854 1.722231 0.792268 1.653897 2.046303 2.467808 1.442815 0.391254 0.553268 1.017640 0.477785 1.375887
+1 0.008937 1 1 1.617020 0.901826 1.941994 1.093401 -1.526337 1.093080 -2.204165 -1.314068 1.428854 0.410285 1.441661 -1.111817 -53.822860 49.194796 16.931265 13.775664 -72.413129 2.163011 1.982457 0.401041 0.801465 0.980065 1.195707 0.743115 1.276281 0.458044 0.353469 2.245766 2.346278 1.897967 2.383670 0.334888
+1 -0.028775 1 1 -0.334584 -1.477124 -1.156828 0.514626 2.079119 1.382233 -0.883496 -0.180340 -0.913429 0.959023 1.933496 -0.364167 26.903174 61.651347 -25.806064 -72.518365 -66.154140 0.585560 1.498927 0.709988 0.267965 0.691983 1.415738 2.051131 0.366218 0.521809 1.051109 0.495303 1.051416 1.148075 1.189600 1.613733
+1 -0.036798 1 1 -0.134157 -2.246631 1.247814 1.874937 0.314968 1.655178 1.343808 -1.094561 0.878365 -1.235184 -1.663963 1.803954 -14.471545 -73.264177 -1.024064 38.547888 24.347501 1.501632 1.176629 1.847662 0.657132 0.674523 0.464005 1.530838 1.553243 2.358268 0.913585 2.117201 1.540704 0.861716 1.114108 1.813338
+1 -0.002545 1 1 -0.248902 1.311977 1.123981 -1.217769 -1.145139 -0.962900 -1.117382 -0.974912 -0.375366 1.109873 2.001697 0.776633 -14.139010 -34.345494 -44.712664 14.261073 -14.141637 2.447566 0.989753 2.027763 1.356012 1.749470 1.851324 1.456428 1.931400 1.796202 2.007855 2.027635 1.456829 1.920544 1.585007 0.711001
+1 -0.026964 1 1 0.831210 -2.083801 0.038598 -1.585797 0.783826 -2.082823 2.338141 0.516125 -0.988303 0.764847 -0.608528 -1.648883 24.657589 -29.899149 -14.991673 34.954500 -69.711175 1.589227 1.883179 1.342440 0.884836 0.430845 2.211683 1.006399 0.554247 1.735834 2.153715 0.994514 1.050197 0.909196 0.349425 1.778205
+1 -0.043413 1 1 0.421413 -0.024383 0.180907 1.020556 -0.615568 -2.163807 -1.590317 0.216402 -0.896972 -0.470552 -1.185660 1.302563 -50.323315 66.052624 -3.549265 47.502530 -74.984873 1.813600 1.924371 0.650077 1.337021 2.055185 1.001737 0.950649 1.814061 0.665626 1.681889 2.262435 1.252262 1.762251 0.651086 0.308313
+1 0.018051 1 1 -1.105503 0.760663 -0.256038 -0.817149 -1.928568 -1.634779 2.203612 1.443569 -2.024663 -0.350812 -0.904445 1.155731 -2.956070 -32.671938 32.731349 65.777581 23.808862 0.708263 0.530541 1.559192 1.089312 1.312761 1.580782 1.703100 0.995905 1.923995 1.084032 0.329696 0.942462 1.463622 1.351946 0.902551
+1 0.043785 1 1 -2.173753 0.888599 1.115085 0.066770 0.655902 1.473828 2.305668 1.395645 -1.661687 -2.349997 -1.872307 1.477941 23.785599 14.560346 65.728924 -43.967288 -58.201527 0.728911 1.056885 0.808480 1.874728 1.057409 0.616562 0.552634 1.616601 0.715758 0.497622 1.776905 1.693974 0.628547 1.746352 1.195357
+1 0.015327 1 1 0.481675 -0.378486 0.506091 0.003390 0.432151 1.370180 -0.836132 -0.518852 2.282442 2.156203 1.038378 2.038911 -16.472439 47.716582 72.594373 -6.379303 33.059932 1.949178 1.342524 2.308867 0.876011 0.616872 1.273853 2.401396 1.266663 0.812769 1.966343 1.819128 0.335691 0.452930 2.145351 2.171762
+1 0.032653 1 1 2.202956 -0.149599 2.098767 1.739727 -0.786689 1.082343 1.117460 2.287208 2.154659 -1.352211 1.245111 -1.135521 15.004199 25.575615 -50.633995 -55.554202 50.535142 2.037007 1.475287 1.642365 1.719870 1.612300 0.431304 0.927687 0.631539 0.269090 1.598259 0.690737 0.723136 0.754995 0.695543 0.487170
+1 -0.009573 1 1 0.312287 -0.987282 -0.931146 0.079622 -0.119288 -2.114485 -2.016132 1.650896 0.062881 1.258808 -1.844234 2.048050 72.942578 -4.093119 56.941475 15.370532 32.530223 1.156846 2.358138 0.984377 1.676434 0.583469 2.369720 2.140262 2.136920 2.219336 1.376906 1.916155 2.063216 0.969616 1.082763 1.503370
+1 -0.014271 1 1 0.945449 -0.008943 0.488115 -0.521063 -1.894571 -0.442398 0.758410 -0.410519 -0.655833 -0.312043 0.389179 0.127655 43.563986 29.914595 -25.403354 -54.176008 -36.168689 2.317775 2.101125 1.357131 0.302080 0.309667 1.819236 2.155192 1.068300 1.415274 1.009707 2.144299 2.477378 0.292025 2.313605 1.767855
+1 -0.032124 1 1 2.008625 -0.598258 1.318514 -2.104242 0.475501 -0.462069 0.023183 -1.497051 -1.493035 0.038468 0.936309 1.885760 -49.629481 27.320124 19.324467 36.317695 41.495684 2.394387 0.464079 0.526030 2.228412 0.926240 1.066874 2.200207 1.635167 2.254245 0.848291 0.480099 2.031344 0.801379 1.778034 0.424104
+1 0.017550 1 1 2.059890 -1.355160 -1.198592 0.733298 1.637300 -2.256998 1.367833 2.138701 -0.960808 1.058104 -0.995280 1.314381 -28.102789 26.423223 -54.886097 29.369131 -43.015863 1.860874 2.201585 2.281523 0.309421 2.182294 2.062873 1.962139 0.927378 2.192491 2.453258 2.151932 0.271619 1.356620 0.716316 0.877056
+1 -0.023950 1 1 1.264586 1.018373 0.402210 -2.338973 -0.373562 -1.555737 1.770756 -2.346888 -1.458018 -0.487604 -0.322673 0.790126 4.288451 -74.009275 -73.878556 23.114387 -16.495875 0.682501 1.798811 0.859703 1.027233 1.953764 1.908898 1.598895 2.378844 2.481012 0.618968 0.488817 2.296436 1.193026 0.694238 1.052178
+1 0.024722 1 1 1.433035 0.001589 -1.574686 -0.965131 -0.914377 -0.833480 1.629404 1.699986 0.457450 -2.260573 -2.175793 -0.415540 -7.090020 -61.959629 -55.488307 -41.981171 22.459233 2.459980 0.391710 1.474385 2.240680 2.357203 1.015144 1.272216 1.877361 0.299690 0.641797 1.682277 2.034086 1.888819 1.632394 0.636817
+1 0.018092 1 1 1.138306 -0.789236 0.689986 -0.589864 1.014281 2.309414 -1.622885 -0.520974 -0.383634 -1.195888 -0.943518 -0.511342 40.351524 38.059199 60.963499 -36.478501 -44.162867 0.695481 1.698449 1.574704 0.806144 0.855780 0.337720 0.811552 1.760005 1.163075 1.307092 0.788962 2.340453 0.750354 1.448692 2.419510
+1 -0.005266 1 1 -0.043470 -0.177373 1.834725 -1.642850 -1.485262 -1.276989 -2.143778 0.447132 -1.309775 -1.816765 1.915960 1.785534 30.803379 62.385376 11.010543 -45.808589 45.037200 1.978314 0.523765 2.415210 1.681269 0.829013 0.464203 0.367772 1.885743 1.677295 1.549658 0.600600 2.278458 0.548254 2.252871 0.261543
+1 0.044038 1 1 1.526333 -1.168797 1.982310 0.099560 0.415006 0.668199 0.805161 -1.633607 -1.651432 0.360561 -0.176198 -1.986757 18.141351 -48.312428 -36.978555 -48.579933 -32.938902 2.063143 1.994447 1.664141 0.962713 2.069868 0.271680 2.373876 2.234943 0.445624 0.850575 0.606290 1.169770 1.329483 1.370789 0.352474
+1 -0.030237 1 1 -0.303550 1.745176 1.266537 0.821459 -1.030744 -0.969459 1.741073 -1.715639 0.360179 -1.884737 -0.089445 -0.047343 22.289911 -73.468489 15.112987 53.965349 -54.375108 2.388287 1.442537 2.474288 2.360206 1.991146 2.441667 0.846244 2.079215 2.118183 2.301618 0.536664 0.954386 1.616788 1.606963 0.734462
+1 0.012601 1 1 0.218560 -2.317969 -0.779055 2.154524 1.086582 1.669105 -0.199157 -1.435651 -1.561594 2.287773 2.215685 1.713897 -43.695797 4.742366 54.938646 -46.171969 -62.283748 2.080784 1.491502 1.918947 1.740410 0.315567 1.985338 1.570450 1.299793 1.871395 1.290190 2.476771 1.348036 0.443984 0.295899 2.168876
+1 0.042856 1 1 -1.017467 0.686164 1.137687 -1.769813 -0.640415 -0.363539 1.974100 -1.233172 -0.826847 0.017412 0.473884 0.631745 23.141397 -12.546109 37.543971 -48.484811 65.788765 2.301704 1.985278 0.559745 1.878294 2.494482 2.003503 0.882965 0.489755 2.305202 2.277498 2.401730 2.378687 2.088362 0.602308 1.734626
+1 0.050029 1 1 -0.341744 0.706276 -0.122317 -1.188411 2.201155 -2.160161 -1.581067 0.171718 2.085844 1.327058 0.119895 -1.835109 -3.072361 -37.167960 68.092111 74.114373 40.265836 0.593536 0.555082 2.261894 1.159772 2.034009 0.583387 0.977985 2.235779 0.987093 2.321651 1.993763 1.420407 1.783771 2.333042 2.180451
+1 0.056676 1 1 1.645116 1.882309 1.700163 -1.281343 0.082637 -1.278966 2.337374 1.775553 -1.841357 -1.430919 -2.141062 -1.031817 -5.049816 27.747617 4.200283 -55.843856 -17.686458 2.030454 1.581564 1.340488 1.833424 2.112562 2.332717 1.227827 0.591648 0.326907 1.319153 1.005343 0.792015 1.891629 1.606498 1.914722
+1 0.036266 1 1 -1.384297 -0.821833 -0.535729 1.375582 0.429982 -2.096729 -0.472653 1.203350 -0.875542 1.548462 -1.525890 -0.808954 -26.840949 -65.829667 0.783170 -37.267624 43.050300 0.570879 2.259114 1.674361 1.738671 0.350331 1.267724 0.645404 1.558720 2.164021 0.952745 1.035117 1.712834 0.346995 1.453031 1.097391
+1 -0.017426 1 1 -1.846498 1.698727 -1.854884 2.133924 -1.128805 0.247981 2.071465 -0.021618 -0.472463 -0.309917 -1.578541 0.214186 -14.109085 18.606344 -33.179878 45.785284 13.273758 2.005865 2.315909 2.229591 0.492742 0.765479 1.410197 1.180912 1.839608 0.285120 1.009874 0.454871 1.018820 2.314009 1.799719 0.373894
+1 -0.018236 1 1 -1.545227 -0.647576 1.807027 -0.644200 2.008728 1.131862 -0.711680 -1.155782 -0.766974 -2.140272 -1.888210 -1.921207 -14.114817 72.278608 -63.430123 -20.080824 1.585031 0.469343 1.242490 1.781979 1.470417 0.794089 0.755709 1.452113 1.409872 2.466473 1.504970 1.037617 0.974577 1.207997 0.299033 0.851328
+1 -0.006125 1 1 1.565109 0.236170 1.484767 -2.338623 0.801383 0.841262 1.927148 1.325048 -0.671637 -2.024443 -1.363494 0.100319 -31.027534 70.241515 49.141212 16.347824 -42.121085 2.438796 2.100904 2.145718 1.583725 1.659381 1.962326 1.808634 1.711918 0.714417 0.462538 1.632019 1.096958 1.570340 1.701060 0.462387
+1 0.001344 1 1 1.996810 -1.247174 -0.547274 0.554205 -1.873553 -0.624172 -0.676207 1.270381 -0.543110 -0.155588 0.413883 0.644768 -59.758556 37.953247 -69.773038 24.547059 62.416235 0.319820 1.458495 0.670190 1.886250 1.206304 1.103114 1.535213 0.831251 2.079090 2.266509 2.222834 1.672455 1.194585 2.134771 2.104465
+1 0.010785 1 1 -1.551372 -0.263214 1.095361 -1.577608 1.746421 -1.374609 1.787205 0.787442 2.156193 0.863267 -0.512462 1.301156 -52.907374 -14.232112 50.888194 -22.115736 0.827211 0.669021 2.484660 1.173317 2.441770 0.321061 2.067540 1.636016 0.775604 0.577472 0.579405 1.556294 1.877307 1.642686 0.378876 1.764784
+1 0.026064 1 1 -0.003835 1.524135 -0.412209 -0.787571 0.388484 -2.112220 -1.647779 0.488826 2.005450 -2.121776 -2.043373 0.918160 -49.659629 -29.382501 -31.693286 -19.057178 -43.995436 2.405610 2.345072 1.882216 0.902949 1.118194 0.734445 1.825163 0.522515 1.663195 0.816013 2.480534 1.587088 1.932779 2.472986 0.731951
+1 0.023459 1 1 1.095992 -0.388138 -1.494044 1.926500 -0.141730 -2.297322 2.231152 -2.216480 -0.947014 1.993910 1.853619 0.169725 49.845456 2.586331 -31.532952 -24.318890 22.413525 2.186804 1.367609 0.900337 2.207655 0.800090 0.355016 1.252160 2.294602 1.868491 1.986053 2.343854 1.660277 1.276316 1.040385 0.251440
+1 0.047244 1 1 0.173871 0.564937 -0.564186 -0.945147 0.384237 1.897940 0.514426 -1.276637 -0.935345 0.187813 -0.731000 -0.716286 48.915937 -19.842616 -44.850253 -48.197426 -54.134967 2.179219 2.140599 1.044464 1.301589 0.552327 0.955482 2.042523 1.928887 2.300783 2.257345 1.195725 1.056578 2.410656 1.651310 1.323215
+1 -0.005228 1 1 -0.695547 1.383444 0.625092 2.008290 -1.521159 -1.411915 1.541189 -1.240786 -1.572189 -1.422547 1.913664 0.900184 -66.713914 -10.759506 64.985474 60.860089 25.521634 0.506629 2.420503 0.646443 1.016400 2.129622 1.063356 1.568339 1.816252 1.494080 0.255986 1.848726 0.538915 0.541326 0.571420 2.356059
+1 -0.007675 1 1 -0.335525 1.553515 -1.423325 -1.743507 -1.483139 1.426041 0.269905 -1.734213 -0.797949 0.322403 -0.621722 -1.907827 -55.730478 -62.142028 28.932637 -29.174614 12.262091 1.209554 1.727681 2.380599 0.480198 1.441957 1.719458 1.437607 0.611733 0.394662 1.581314 1.645100 0.449788 1.084757 1.260299 1.838075
+1 -0.018072 1 1 2.071515 0.827602 -1.466260 -2.344967 -2.153746 -2.149508 -1.601440 1.759489 1.497462 -1.016575 1.541487 -0.946151 74.934740 28.181698 -50.204646 -39.493435 -16.155773 0.923777 2.421088 1.474862 1.255937 0.526979 2.432889 1.810410 2.318856 2.261240 1.418063 0.629371 2.088854 2.114130 1.686648 1.243171
+1 0.083183 1 1 -1.830510 1.803815 1.921569 1.799756 -0.331546 -2.247671 -2.099699 1.440022 -0.387992 0.958720 1.552338 -2.347351 5.927518 23.788395 61.550258 -74.814175 48.167438 1.376846 0.895888 1.685425 0.931900 1.690278 1.501191 0.509790 1.537359 0.894632 0.828053 2.337825 1.571853 2.390661 0.845439 2.050776
+1 -0.063612 1 1 0.615422 -0.301718 -0.448617 -0.081600 -0.139609 0.364108 -1.832932 -1.206612 -2.119155 -0.397619 -0.617911 0.876194 -0.598494 -8.892940 -63.648851 53.763574 4.388263 0.677996 0.327508 2.430096 2.127494 1.285897 2.322274 1.213073 2.374993 0.756455 0.488565 0.315635 0.883783 0.741251 1.452575 2.421079
+1 -0.023236 1 1 -1.792059 -2.263015 -0.802108 1.114477 -0.737664 0.383320 0.621105 0.970696 0.191940 -2.048110 1.416785 0.200479 3.164809 -59.049255 -40.820919 22.810321 -26.937343 0.836256 0.701522 1.987883 1.594025 1.529283 2.411769 2.350606 0.384101 1.828203 2.102412 0.485686 1.424965 1.892213 2.432663 0.271376
+1 0.010707 1 1 -0.249711 1.853001 -0.787359 -0.756083 1.818324 0.723796 2.162253 -0.964392 2.085097 -1.811863 -0.524561 0.584054 9.026562 59.427858 -45.994556 69.497199 -10.582588 1.951576 1.132973 1.623548 0.476575 1.289382 2.390398 0.917802 1.000392 0.841783 1.346677 2.349435 0.949563 1.554012 1.781562 1.219140
+1 0.059718 1 1 -1.903466 0.864454 0.581954 -2.020697 0.332467 -1.126218 1.319131 -1.155125 0.855257 1.520114 -2.013712 -0.077178 -38.691335 -35.271508 -8.232530 -64.124874 3.239989 1.442483 1.567108 1.387685 0.822533 1.814263 1.814262 1.808310 0.773823 2.135975 2.082550 1.913066 1.894605 2.117174 1.090557 1.985640
+1 -0.010878 1 1 1.020121 1.503768 1.284951 -0.711131 -1.364283 0.988356 0.125347 0.267315 1.864060 1.290489 -1.874885 0.555237 42.430735 33.361833 12.320372 68.485787 -59.382661 2.209353 2.342913 1.589139 0.401442 0.786277 2.212704 2.421306 0.638501 0.284749 1.523477 1.574731 1.262560 1.593624 1.539999 0.255283
+1 0.049750 1 1 -1.404150 0.090268 -0.260189 0.107142 0.608426 -0.073676 1.091781 -0.484673 1.823143 1.604000 -1.145183 -1.701440 -42.198520 -30.518967 67.717959 -64.261019 -34.939938 1.591826 0.564515 1.061132 2.447517 2.423437 0.458961 2.265190 0.300098 0.746969 0.801676 2.275034 1.499922 1.685013 0.770836 1.443765
+1 -0.063467 1 1 2.351004 -0.055372 -2.299570 2.136529 0.234257 2.306775 1.139372 -1.724523 1.841921 1.483425 -1.320568 0.558903 53.709871 1.802054 -12.883674 64.098151 -2.369494 0.263714 1.243744 0.349430 1.873119 1.008666 0.406578 1.603977 2.290385 0.751853 1.887396 2.464150 0.719979 1.692798 1.107266 1.573087
+1 -0.026549 1 1 -2.007940 -2.030078 -1.823016 0.517168 -2.321498 1.157163 0.400604 -1.044490 -1.097094 0.718468 2.159494 -0.202075 43.114875 -18.302762 35.482313 -48.758367 -31.876032 2.267885 0.597971 0.845802 1.393657 2.202375 2.070088 1.713740 2.082166 2.212169 2.425421 2.296947 0.781344 0.291052 1.713923 0.652881
+1 0.006440 1 1 1.177664 0.962584 0.515271 -1.210381 0.510503 -1.229380 1.645014 0.166831 0.057058 -2.346138 1.721435 -1.916463 -25.737995 21.525815 -15.628280 -14.500741 36.043602 0.397171 0.999709 0.616469 1.241919 1.179734 2.291419 2.384939 1.416338 0.900435 1.608793 2.241676 1.104346 1.993804 2.114638 1.211730
+1 -0.003128 1 1 2.309441 -1.171537 -1.654533 0.077864 -1.382901 -0.917828 -2.290164 0.004823 0.943105 -1.716073 -2.222030 0.018874 47.332936 74.649095 27.336919 1.599692 36.030212 1.521585 1.284959 2.301657 1.197507 1.742141 2.418984 2.106803 2.284454 2.327106 1.416865 0.748261 2.268472 1.453596 1.593575 0.714015
+1 0.007108 1 1 1.356607 1.948902 -0.613971 1.116829 1.095230 0.943945 -1.737114 2.287132 0.874007 0.918428 -1.767085 -1.923343 43.571414 4.757707 12.777990 -40.318482 67.275702 1.415740 2.091474 1.160631 0.728344 0.527877 1.777220 2.481282 0.651310 1.817500 2.216881 0.623562 1.211438 1.889751 1.539413 1.664274
+1 -0.002722 1 1 -1.359036 -0.364037 -1.694842 1.177184 2.321547 -0.345820 -1.815257 -1.021973 0.363150 0.914166 2.002205 -0.106529 8.621083 -5.452438 10.870357 -1.911228 -22.008599 1.397075 1.143713 2.134844 1.074087 1.932050 1.472809 0.498287 1.708196 1.154223 1.028603 2.471677 1.231663 2.066152 0.824978 2.402290
+1 -0.006656 1 1 0.772122 -0.857820 -2.190073 -0.093843 1.437250 0.147212 0.182410 -2.006002 2.272447 -0.895952 -2.190149 -1.365459 2.039466 -72.699701 36.121492 43.910172 -1.733576 0.831739 1.281992 1.936293 0.783784 0.806212 2.013364 2.361773 1.322449 2.398381 2.332818 0.677163 2.075819 1.282712 0.542973 1.239218
+1 -0.065431 1 1 0.663738 1.220466 -0.655559 -0.410226 -0.439201 -2.051989 2.201070 1.136961 0.157417 2.063111 0.954106 -0.604873 -47.156062 48.071264 33.730873 64.790404 -67.686214 1.342092 1.790299 1.799104 1.297201 1.054132 1.800529 0.489463 1.910442 0.545575 2.226728 1.871829 1.835507 1.116953 2.387798 2.215194
+1 0.008880 1 1 -1.944785 -0.866521 -2.340871 0.718377 0.626687 0.542421 -2.004477 -0.377704 -0.483516 -2.298697 -2.044241 0.472842 62.509609 -0.997098 41.767453 -14.417580 -66.273287 2.047898 2.264384 0.255265 0.986430 2.422233 0.471156 2.473027 1.411108 0.741310 2.439965 1.491507 1.999650 1.375197 2.428748 1.970835
+1 -0.023271 1 1 0.355773 -0.541619 1.341635 0.077453 1.132167 -0.294305 1.629017 -0.087145 0.907933 0.915905 -1.764632 1.609613 -33.701010 -12.866951 45.153637 47.178741 33.101485 1.174969 0.960399 1.422758 0.793844 1.133330 0.868733 2.046315 0.411810 1.784392 1.524882 0.437400 2.135113 1.092835 2.029595 0.656810
+1 -0.000881 1 1 1.722103 -0.116355 0.056189 1.891280 1.680970 1.300011 -2.057214 -0.803098 -1.394365 -0.374760 1.871746 -1.470220 56.582734 -13.983343 31.960835 15.752421 0.937609 1.500956 1.062641 0.802171 1.595337 1.085181 1.642500 1.750560 2.170681 0.383850 2.121281 0.364960 1.884537 1.666915 0.336745 2.418058
+1 -0.039880 1 1 -1.221483 -2.291759 1.466966 0.081900 0.472342 -1.722553 1.974538 1.417710 1.620781 -1.855403 -1.887784 0.532546 53.373957 56.097974 -61.347615 30.628981 -18.710047 0.478688 0.812315 1.080285 0.352495 1.629214 1.201602 0.825660 0.361228 2.158217 2.396119 0.320031 0.515738 0.258541 2.056196 2.228928
+1 0.024794 1 1 1.497426 -1.637170 -0.279197 1.076611 -0.971718 1.477683 1.126610 0.551130 -1.716704 1.313981 1.826371 -0.683649 -40.831476 -4.616601 -41.209663 -60.812569 23.150740 1.292197 2.458959 1.225272 0.391610 2.032023 0.956679 1.895740 0.948592 0.983948 1.221348 1.942447 0.703718 0.646424 0.694307 2.224836
+1 0.066867 1 1 -0.836424 -0.726559 -1.481000 -0.331973 -0.002350 -1.793708 -1.696782 1.560199 -2.184623 1.981327 -2.287316 0.756541 36.667606 72.458075 -47.126671 -57.955310 45.113101 0.863335 1.319468 1.791769 1.766776 2.457177 0.529883 1.737589 2.414048 2.410198 0.701719 0.782817 0.311869 0.581250 1.066572 1.621817
+1 -0.008834 1 1 1.961916 1.336484 -1.676527 -2.021464 1.573122 -1.756537 0.993669 -0.109592 0.631050 -1.534811 0.053152 -2.029023 56.229723 52.950604 -9.201028 8.327417 8.905703 1.047362 0.521888 2.369573 1.910129 2.035316 2.298561 0.922676 1.908839 0.601344 1.289483 1.837744 0.458490 1.093545 0.453806 1.124483
+1 0.029359 1 1 -0.060835 0.139746 1.941464 1.612807 0.787736 -2.337130 2.334786 0.686590 -1.125300 -2.106908 -1.909456 -0.866973 -16.432744 -35.125744 41.613969 -44.029585 -55.241773 2.147750 1.987444 0.977655 1.190407 1.670189 1.359511 2.057451 0.827531 0.307038 0.381984 2.255030 0.538578 1.631529 1.856284 1.566306
+1 0.015747 1 1 -0.254672 -1.428518 0.515493 -2.198648 1.882908 2.345530 2.183976 1.285232 -0.688640 -0.347089 0.413818 -0.440674 46.945018 4.917619 0.422066 43.662417 34.244311 1.287095 2.206660 2.082020 2.006354 1.544608 1.230810 1.217735 1.974735 1.112983 0.902132 0.878408 0.400488 0.506046 1.608514 2.037608
+1 0.012936 1 1 0.659725 -0.258039 -1.460087 -2.279308 -1.328554 -1.705521 0.776304 -1.267181 -2.226683 1.933578 1.008798 -0.298795 49.550750 -0.536897 -23.626293 -37.109725 -3.140192 1.716760 1.086413 2.095949 2.113621 2.120624 0.581746 0.402125 1.008457 1.386578 2.471075 2.357267 2.080544 1.945547 1.052068 0.862824
+1 0.001615 1 1 -0.680818 -0.821736 1.096546 -0.512071 -1.547573 2.321318 0.528227 -0.230779 -0.401361 -2.246712 -0.110620 2.198439 -21.599117 -16.360420 -19.573594 -23.397465 58.806870 1.630981 1.650355 1.013593 2.210881 1.033764 1.479804 1.065487 1.397304 0.495384 2.424785 0.616254 2.122638 0.674221 2.126986 1.757381
+1 0.017919 1 1 -1.563785 -1.543039 -1.583552 0.807933 -2.178547 0.416186 1.657873 -0.477728 0.742155 -0.287123 -0.196823 0.098175 22.149534 -32.776025 -66.657057 44.836659 -30.274250 1.085166 1.378554 0.355771 0.442289 1.043489 0.663007 0.411661 1.543094 0.534622 0.395634 2.166469 1.593055 0.972444 1.367532 1.858005
+1 0.049523 1 1 0.609409 2.308369 -0.340438 -0.894423 -0.039950 -2.283685 0.514853 1.186853 -0.106430 1.940511 -0.271456 -0.769932 -0.595362 43.747219 -40.485800 -44.839342 -14.824420 1.314578 0.619817 1.261426 0.538779 0.500282 1.488546 1.737671 1.542771 1.850224 0.968796 0.809995 0.336289 1.502610 1.872581 0.976083
+1 0.013136 1 1 -2.036650 0.808843 -1.016043 1.057228 -1.584913 1.504902 1.499757 -0.151141 -0.250589 1.225123 2.208512 -1.025203 -66.383173 -1.995041 69.352938 -35.172610 3.939209 2.219228 1.815892 2.203516 0.997265 2.287739 1.276793 2.316612 0.554310 0.536283 1.306987 1.274155 0.726916 1.278226 1.637194 0.321309
+1 0.009449 1 1 1.848529 -0.547017 0.150021 0.271452 0.695801 -1.823624 -0.274948 1.805505 2.058286 -0.043048 2.201512 -0.859747 -50.294768 -54.160026 -67.561826 -11.605892 -60.229944 2.354859 2.119531 2.462079 1.916915 1.348664 2.000109 2.333399 1.443597 2.286073 0.285917 0.903461 0.714770 1.886511 1.089425 0.966559
+1 0.027748 1 1 -0.222242 1.697012 2.304587 2.073209 1.021964 -0.511964 0.240486 -1.377696 1.740398 1.068408 -2.186394 0.483041 -30.958657 27.858967 -74.346951 -49.213269 -27.415465 1.799277 1.946401 1.912372 1.486083 0.844333 1.455869 1.536558 0.934359 0.267546 0.396085 0.753326 1.897383 1.566063 1.814806 1.936459
+1 -0.021490 1 1 1.521223 -2.223073 1.349414 -1.123526 -0.565803 0.146934 0.229107 0.581267 0.564230 1.685309 -1.176530 -0.751834 -68.950051 56.489770 73.559516 14.782154 43.668872 1.266031 1.432650 0.554824 2.423889 1.295906 1.799318 0.394276 1.854056 2.373762 0.311934 1.677237 0.572463 1.891025 0.464633 0.836770
+1 -0.002575 1 1 1.236900 2.224847 0.199030 -0.702998 -1.328320 2.229413 1.536084 -2.216063 1.347783 -0.258337 -1.759886 1.262126 66.536275 25.177292 4.745699 -39.036681 10.507564 2.134524 2.441337 2.055961 0.544757 1.988404 1.352554 2.125683 2.355864 1.006492 2.113325 1.648418 2.217640 2.134657 2.429219 0.885525
+1 -0.000403 1 1 -1.960845 -2.191113 1.288183 1.780215 1.124099 0.769189 1.674454 0.152679 -2.173630 -1.752854 1.632882 -1.111083 39.209187 38.800668 72.826312 -8.181779 38.844110 2.169465 2.450898 0.750139 2.335064 2.417164 0.770522 0.665385 2.133803 1.584394 1.661127 2.058628 0.356701 0.320394 2.104587 1.039646
+1 0.023739 1 1 0.565748 -1.072386 1.289612 2.225669 -0.129561 -0.404898 -0.439172 -1.559850 -1.379191 0.182322 1.228828 -1.489954 -0.922517 -54.749898 68.461222 -22.242814 -34.968611 1.113231 0.566862 2.245644 0.283345 0.431235 2.015805 0.643240 1.180872 1.160962 1.781781 0.394472 0.640644 0.306554 1.260825 1.681674
+1 -0.005711 1 1 0.048911 2.087685 -0.723969 -0.366921 1.672120 -1.365768 -0.419615 1.976562 -2.270540 -0.033232 2.252043 0.172978 -9.483930 53.585041 3.781768 -39.827664 66.453603 1.160660 1.219662 0.608488 2.101433 2.025276 2.313365 2.223080 1.298515 0.633609 1.321731 1.589352 1.745207 2.195717 0.414886 1.734771
+1 0.006323 1 1 -1.698653 -1.610894 -1.621325 2.144304 -1.034436 -1.763313 0.207555 1.203226 1.753297 1.096999 -2.313198 -0.717311 -49.687503 -47.870530 40.000906 -4.764837 17.377600 1.604836 0.984791 1.880183 0.487079 2.337504 0.679102 0.909279 1.753786 2.386024 1.664254 0.618043 0.694391 1.387368 2.248493 0.918892
+1 0.028206 1 1 2.150416 -1.978613 0.776354 -0.429136 2.170730 0.141627 0.570300 0.030769 -1.225554 -0.041304 -1.482269 1.907724 0.860977 70.440025 -64.505748 51.897219 -13.448503 1.690274 1.431105 1.588897 0.841699 2.182701 2.147442 1.308311 1.037315 0.407122 1.746125 1.875893 0.385322 2.102811 0.445475 0.598412
+1 0.005519 1 1 2.168857 1.644567 2.079376 0.997043 0.045528 1.784009 -1.095665 1.181440 -1.542491 -1.788364 -1.424461 -1.983872 61.612112 64.769107 24.373614 -2.665262 54.935187 2.060389 0.704429 1.335673 1.911840 1.544628 1.565211 0.998578 1.851139 0.586495 1.464268 0.957042 1.249328 1.948236 1.245694 1.628319
+1 0.042314 1 1 -0.724940 2.169403 1.401030 -0.693423 -0.625323 -1.180676 0.249575 0.585349 -1.514544 1.375474 -1.387066 -0.229427 -39.497108 72.098869 65.692694 -52.889730 -17.693329 0.298294 1.927910 1.625961 0.530952 1.702893 2.019242 2.148710 2.376484 1.068829 1.315998 1.983295 0.992591 2.482849 2.235994 2.348538
+1 0.037499 1 1 2.011081 -1.723882 -1.516066 -0.640257 2.296275 -0.977066 1.124113 1.005632 -1.677187 1.027867 -0.260420 0.936784 14.077770 55.088324 69.464163 34.189341 -29.750307 0.423866 1.908975 0.636841 1.644950 2.420859 2.127928 1.829242 1.564934 0.840294 1.066369 0.465204 1.435809 1.899457 0.420528 2.066247
+1 0.068635 1 1 -0.844739 0.904796 0.023013 0.361715 0.369208 -0.933224 -1.869011 0.320175 -0.372025 0.716279 -1.648267 1.705945 52.276105 54.497585 40.916077 -73.501546 59.522163 1.960003 1.015666 1.047209 2.446382 1.348482 1.182898 1.470577 1.239690 1.974159 0.443012 1.960885 2.338602 1.132201 2.153079 1.544116
+1 -0.008660 1 1 0.675140 -0.360246 0.763557 1.273388 -1.846070 -0.530662 1.723663 -2.167782 2.280316 -0.588540 -0.287867 1.441740 7.240773 45.662935 56.945324 -69.935134 0.194572 0.927561 0.763946 0.392446 0.332825 1.786568 2.092559 1.389511 2.263167 2.292430 1.371128 1.552315 0.262917 1.338130 0.448836 0.828949
+1 0.031628 1 1 -1.937959 0.761363 2.088247 -0.706058 -0.918394 2.340583 -0.844688 1.754347 -0.104458 2.098687 0.396488 0.448984 49.236098 -38.898348 -64.528964 -38.293856 45.162721 2.122827 1.610435 0.587646 0.568015 1.372194 1.466728 1.793643 1.753035 1.001118 1.796000 0.874680 0.754114 1.643756 0.350166 0.746386
+1 -0.007309 1 1 2.246392 -0.542755 1.094300 -0.559486 -2.073328 1.686502 0.013776 0.630451 -2.179771 -1.306127 -1.762963 1.388954 -32.534335 -54.573013 41.365892 -13.460110 -24.073178 0.656550 2.130566 1.168234 0.252617 1.484903 1.273534 1.543018 1.499247 1.589691 0.692970 2.250663 1.396057 2.027127 1.914894 1.132431
+1 0.041583 1 1 1.213503 0.128869 -1.795883 -0.550622 0.833874 0.267374 -1.859036 -1.680063 -0.191796 -0.240503 1.089730 -1.962115 1.038172 48.560578 7.635864 -64.040371 73.486523 1.194858 2.233941 1.601436 2.336226 1.696775 0.438428 1.401079 0.941662 1.521135 0.461062 1.573906 0.886302 0.319486 0.353075 2.379606
+1 0.035569 1 1 -2.347487 -2.088189 1.671637 -0.067290 0.029468 0.463474 0.031849 -1.919715 1.082634 1.286553 -2.054961 -0.629255 -40.918038 40.534530 -36.147159 -25.298863 52.004904 1.321278 0.726909 1.160965 1.839399 1.275668 1.407026 1.888826 1.743227 0.409204 0.739880 0.921119 0.505055 0.717626 0.381728 2.456751
+1 0.011230 1 1 1.278245 -0.314033 -0.073523 -1.046949 -0.006507 -0.975080 1.519912 -0.692189 1.262179 -1.728835 0.061626 -0.977625 36.892597 -46.118917 -70.641151 -15.820140 60.913815 1.802393 0.327768 2.298267 0.470879 2.312400 1.763655 1.755127 2.410454 0.503326 0.897315 0.915107 0.703259 1.923271 2.409399 0.764531
+1 -0.021902 1 1 1.021030 -2.070422 -1.294465 1.022802 -0.561809 1.304833 -1.124602 0.202230 1.238713 -0.289736 -1.694242 1.846228 -48.709343 42.064557 29.016928 37.505443 53.983702 0.686207 1.088455 0.413840 2.167192 2.492648 0.432455 2.274865 0.903602 0.844724 1.271543 1.823174 0.834439 1.660269 1.138593 1.587043
+1 -0.003352 1 1 -0.104235 1.131885 -0.328155 -1.808642 1.776517 0.228749 -0.726598 -2.125826 0.578989 -0.018623 -1.977051 -1.236754 7.300604 1.250816 22.461143 -45.561463 -1.507460 1.586788 1.391210 1.572349 1.723414 0.424436 2.487429 0.473847 0.452822 0.328491 0.950396 2.049133 0.535858 0.911895 0.718932 2.092413
+1 -0.011361 1 1 -1.702940 1.734450 0.068845 -2.173097 -2.218820 2.138019 1.716469 -0.554929 -0.877233 1.410786 -1.662207 -1.672593 -59.755469 -60.162620 -3.160322 -15.529982 -12.399192 0.726675 1.728942 1.083871 2.122560 1.620197 0.399379 2.115301 1.114705 0.604073 2.151752 1.751284 0.839380 1.460487 0.400107 0.840192
+1 0.026610 1 1 1.766401 -0.152449 1.324404 -2.070332 0.208173 2.173107 -2.316504 0.279064 1.399136 0.457304 0.007829 -0.359671 32.090062 -62.333845 -44.937868 -20.748368 32.181426 0.973455 0.356398 1.979906 0.277005 1.870042 1.050874 1.037535 1.852334 0.431259 2.423162 0.336459 2.121188 1.056341 0.666913 0.805901
+1 -0.016183 1 1 1.385752 1.707755 -0.926201 -1.633756 0.559621 -0.373947 1.406401 0.043118 -1.030286 2.016818 0.440681 -1.351012 -69.064399 -65.362075 59.611513 40.698088 12.758605 0.383088 0.552903 1.639223 0.674508 2.456257 0.813977 2.014266 1.768811 0.656963 2.329578 2.458597 1.890279 1.425750 1.588523 1.302421
+1 -0.006162 1 1 1.442341 0.899839 1.533619 -1.234975 1.842230 1.966264 -0.988219 2.178603 0.513175 1.267217 -1.885469 1.730314 39.381754 -60.854497 68.467582 -65.349480 -28.704373 0.858997 0.407364 1.318723 0.530287 1.782326 0.548647 2.116848 2.366503 2.056830 1.643051 2.011378 0.480786 2.321919 1.983984 1.312714
+1 0.016224 1 1 -0.305635 -0.308862 2.012312 0.113426 -2.172279 2.098925 -0.316758 1.243114 -1.716499 0.042801 -1.637892 1.720578 -69.450089 52.361496 -10.333734 20.931507 45.841557 2.260694 1.233494 1.326167 1.885637 2.150338 0.473704 0.301209 1.412630 1.578917 1.867014 1.899043 2.462800 0.525672 0.727381 2.347772
+1 0.008623 1 1 1.468261 -1.724373 -0.348331 -1.611766 -2.142580 1.727206 0.840518 -1.154866 0.505325 1.271632 1.640915 1.953177 17.210260 52.831715 -57.368190 12.830341 -60.455353 1.778175 0.539389 1.760218 2.478454 0.378974 1.160640 0.879890 0.559838 1.190876 0.553111 0.639712 0.383704 1.915307 1.320507 1.267392
+1 -0.007861 1 1 -1.309829 1.992559 -2.015494 -1.757803 -1.422079 0.364396 -1.702270 -1.130329 -1.796406 0.077030 -1.265638 0.143474 -43.975071 -39.018898 9.375475 73.612079 -1.790588 2.208703 0.429636 2.140445 0.705646 1.534720 1.540443 0.976870 1.496581 1.780794 1.812064 0.868002 1.011658 1.188420 2.018211 0.574633
+1 0.059174 1 1 0.481399 -0.298707 -1.669000 1.961289 0.229184 1.875860 1.692562 -1.811190 1.353697 0.169756 2.100272 -1.240693 -0.046757 -35.852194 -17.826131 -53.775994 -63.132792 1.782377 1.411892 0.419111 0.755738 1.937056 2.352954 1.600150 0.978432 0.760757 0.787899 2.471790 0.873768 1.174698 0.906573 1.272847
+1 -0.002985 1 1 -1.105422 2.123781 -1.968285 -0.003281 1.411931 -1.271479 0.938461 0.355079 1.933439 -1.316099 0.270985 2.271550 -58.589325 39.206909 0.512113 57.082268 -18.319287 2.241043 1.711707 1.654709 2.189784 1.946397 1.849542 0.750720 0.844806 0.412610 1.731176 0.380011 0.593367 2.220138 1.361780 1.932814
+1 -0.001507 1 1 1.629302 -0.008410 0.017207 1.746207 -0.250363 0.319727 1.532960 1.820035 1.218921 1.658829 1.439175 -0.476045 23.669311 10.111282 -9.683584 -1.998563 10.156237 1.313235 0.537752 1.245198 2.293013 2.165332 0.491527 0.592706 2.353949 0.315737 0.346731 1.502520 0.344937 0.602140 1.170285 0.980665
+1 0.007458 1 1 -0.269859 -2.207623 1.829999 -0.972729 -1.370647 -2.305561 0.404401 1.495933 1.543992 -1.252060 2.153221 -1.967722 1.427191 -13.193496 -43.080762 -8.372645 -19.042992 2.041576 1.774227 1.687518 2.372140 2.307444 1.720341 0.515491 0.611491 0.832823 1.508495 1.766513 0.283220 0.585143 1.256349 0.714527
+1 0.027110 1 1 0.923536 -0.746555 1.739261 0.806541 -2.002853 -1.348779 -2.328876 -0.317285 1.822341 2.267137 -0.598464 -2.138775 -9.280537 22.018694 18.191871 50.782504 1.540668 0.535199 1.086718 0.463784 2.317119 2.314125 1.493313 0.869548 2.237499 0.646102 2.044459 0.721564 1.328443 1.891063 1.094924 1.133884
+1 0.012258 1 1 -1.871292 -0.314053 -0.415925 -1.974465 -0.194113 -1.483192 0.525447 0.169773 -2.329683 0.250220 2.003923 0.488654 -28.100515 64.641341 -22.982147 -10.941260 10.240852 2.395055 0.438284 1.240855 1.301350 1.044901 1.899135 1.759938 2.277362 2.365388 1.317139 0.899872 1.148656 1.960067 2.098834 1.094204
+1 0.023078 1 1 -2.016340 -1.838295 -1.800977 -1.345809 0.450554 -0.355409 1.953487 1.049479 0.119417 -0.436352 -1.290903 -0.367578 1.835734 -46.816473 55.546528 -29.504707 14.386062 1.173259 1.456739 0.409276 1.953885 1.701087 0.924720 0.264802 1.520486 0.803596 0.792020 1.977457 1.865652 1.510487 1.512366 1.580983
+1 0.007820 1 1 0.449123 -0.838960 -0.932852 -0.322527 -1.468946 -0.366355 1.756012 -0.404079 -0.797673 0.259662 0.471679 1.269170 -64.815700 -57.468774 -27.686550 -27.846305 -12.850155 1.786627 0.833929 2.096904 2.417132 2.483966 0.763475 1.471927 1.427975 0.721248 0.514211 1.595425 0.302567 1.741244 0.831432 0.630541
+1 -0.016388 1 1 -0.290491 -0.249488 0.886605 0.594039 -1.545054 2.260814 1.516910 0.675755 0.551437 -1.264034 -1.171257 -1.667595 64.492602 27.163203 -68.041447 27.395385 -65.762081 0.425695 1.148192 0.918713 0.560754 0.850220 1.402840 1.275285 1.722436 1.978624 1.226688 1.697541 2.065832 2.184814 1.677032 1.621087
+1 0.009166 1 1 -0.702356 0.039543 0.158946 -0.521060 -1.832685 -1.759942 0.314176 -2.225159 -0.733944 1.636599 0.110516 0.763804 22.469335 -57.883497 52.069550 32.924841 17.808928 2.344779 1.445528 0.990211 0.726580 2.374169 0.405026 0.268060 2.286596 2.325649 1.691022 0.507284 2.180473 0.711625 0.777051 2.388897
+1 0.006623 1 1 1.958762 0.166985 -2.063821 1.262418 2.283032 -2.063395 -1.018420 -1.184454 -1.979868 -1.459010 1.700416 -1.738267 56.052476 73.963671 57.424213 28.755840 -0.598926 1.132780 0.637323 0.739448 0.410740 1.799560 2.200022 0.774708 1.263606 1.169374 1.417556 1.116686 2.390339 2.183317 1.263368 1.681600
+1 0.042619 1 1 -1.069741 -1.367498 -1.216094 -1.267621 -0.202462 -0.441968 -1.439556 -1.213573 -1.301977 2.012816 -0.835237 0.375343 -47.553930 -38.894853 -5.794802 -43.232067 -1.356068 1.503516 1.335159 2.268511 2.118701 2.003656 1.193309 0.939266 1.736022 0.822268 1.857271 2.398519 2.417006 0.362094 0.968545 1.079283
+1 0.004908 1 1 -1.286489 -1.577777 -1.080352 -0.645650 1.195683 2.210530 -0.094815 -0.766255 0.516468 0.051953 1.389978 2.042429 65.853501 -50.203764 -24.660508 -19.162795 -19.094639 0.271026 0.381463 2.491905 1.446612 1.208208 1.608108 1.969521 1.245926 1.026250 1.185454 1.680741 0.961587 1.151019 1.181223 0.321921
+1 0.003598 1 1 -0.330754 1.632445 0.971299 0.906569 1.548996 -1.966740 -2.296056 -0.055089 -2.249123 1.766600 -1.523872 0.123462 50.338332 36.348959 -33.052450 -62.520941 -39.463076 2.036224 1.824674 1.288868 0.497210 1.609555 1.539733 0.292216 1.024614 0.690228 1.154366 1.173806 1.658090 0.512383 2.363814 1.875425
+1 0.029183 1 1 1.497755 -0.809311 -2.133358 1.225052 1.020763 -1.847360 1.357376 0.750218 -1.444479 0.871416 -0.214903 -2.181809 68.280331 -62.472651 22.156852 -59.790111 -42.392839 1.428268 1.157407 0.548149 0.483680 1.453960 0.949593 2.056142 1.331627 1.412106 1.763528 1.865698 2.293381 1.599043 0.359277 0.863937
+1 -0.049450 1 1 -1.799410 1.437450 -1.192751 -0.067886 -0.562753 -0.429103 -1.984721 1.801042 -2.276122 0.387225 0.273231 2.327485 15.930335 -8.861837 9.114658 40.053265 -24.774922 1.493386 2.090579 1.855516 2.160445 1.594791 0.902109 0.495898 2.056862 2.173726 2.062641 0.305263 2.052764 0.799284 0.309302 2.443619
+1 -0.007437 1 1 0.309060 1.316558 -1.994810 1.872483 1.486767 -1.705569 -0.035998 -1.831649 1.509199 -1.690983 0.073842 1.698886 25.899932 0.154749 50.872924 21.235311 51.871300 1.389172 1.059980 1.081797 1.005469 0.665418 0.435081 1.408884 1.616614 0.935945 2.181753 1.977040 1.606786 2.252005 1.444101 1.748590
+1 0.017279 1 1 1.944620 -1.897886 0.385652 2.123546 -1.195182 1.492011 1.600101 -0.702415 -0.953069 -0.821373 -2.225255 -2.349401 -40.634862 -0.130579 55.350859 -18.110634 -35.425428 0.697415 0.446134 0.424505 1.403766 1.090032 2.169370 0.852376 1.637102 1.020315 0.430356 0.744623 1.884756 0.853270 0.903987 0.559003
+1 0.025569 1 1 -1.034536 1.262807 -0.597083 2.209126 -0.137934 0.231668 1.212058 -0.594519 -1.808778 -0.515557 1.121947 2.291387 54.073046 -44.310818 18.080428 -22.252754 -52.030681 1.680192 0.732044 1.965915 1.392023 1.725145 0.264856 2.440397 2.005215 0.391591 1.713963 1.326737 2.473248 0.636556 1.339804 1.579495
+1 0.008763 1 1 -2.225537 2.349975 1.500695 1.468465 1.706841 -2.147899 1.880823 0.284411 1.726889 0.218012 -2.116808 1.348531 -58.355134 -74.731984 -70.461561 2.536561 31.978049 1.451159 1.124692 1.947515 0.389807 0.991086 1.929121 1.730481 2.196150 0.934053 1.874318 0.918233 1.498358 2.395462 0.535338 1.172683
+1 -0.024262 1 1 -0.798692 1.984791 -0.617718 -0.598753 -2.287436 -1.265270 1.615900 0.939137 2.288290 1.478165 -0.197169 -1.005000 -58.268969 23.439426 46.435090 -15.438042 32.831328 0.566973 1.867075 0.684824 0.331372 2.112038 0.279091 0.927808 0.410785 0.314298 0.901915 1.737555 1.843946 1.204443 1.326530 1.237270
+1 -0.000192 1 1 -0.231927 -0.859508 -2.271027 1.207676 1.143741 1.016519 2.226604 1.447890 -0.085928 -2.195294 1.707539 0.152129 -63.397260 -67.750075 -25.515452 11.806382 -20.141250 1.915243 2.484487 0.524874 0.809811 1.740322 1.087070 1.885819 0.718922 1.921409 0.363849 1.217643 0.422472 0.986927 1.781541 0.857867
+1 0.061314 1 1 -0.439584 0.933237 2.088157 -2.216736 -0.538293 0.693120 0.248333 -1.444477 0.898192 2.124488 0.501726 2.050822 55.879503 16.812243 -36.631405 -64.025172 28.929824 2.478253 1.498792 0.700323 2.085853 1.173135 1.635723 0.346893 1.984625 0.838515 0.425164 1.230176 1.812382 1.702502 2.207283 1.309660
+1 -0.003312 1 1 -1.159787 -2.095004 0.232177 0.341140 -1.432006 -1.556254 -2.200720 0.042374 0.604368 -2.297691 0.735638 -1.439471 6.658449 8.544776 62.047084 25.334456 -53.794804 2.435886 0.431937 0.307489 1.215777 0.562314 2.312713 0.267276 0.356364 1.417393 0.630020 1.743115 0.781292 1.675113 0.879776 0.896513
+1 -0.071451 1 1 1.604253 -1.612213 -0.218012 2.107919 0.062326 1.357882 -0.171854 0.343248 1.008101 2.116148 1.695305 1.888793 72.684124 2.079413 -1.307571 73.661362 -73.480537 0.814279 0.336017 1.444928 2.157425 0.344506 2.359334 0.832893 0.424813 2.086738 0.299657 2.327066 0.744329 1.443050 2.091925 1.980460
+1 0.000579 1 1 0.857309 -1.691819 0.151827 2.346702 -1.669039 1.307649 -0.921672 -0.919177 -1.400123 1.799684 -1.538104 1.245438 -11.052836 -65.022572 65.624029 -6.950097 39.719545 2.370995 1.054600 0.656122 1.689707 0.912910 2.027091 1.317005 0.901759 1.366318 1.714675 2.036414 0.504408 1.086239 1.416637 1.413741
+1 0.011539 1 1 -1.954499 0.793743 -0.341746 0.680718 -0.855976 0.534023 -1.778653 1.573486 -0.349796 2.047631 -0.050040 -2.218587 42.489828 -23.454299 3.595763 -16.015689 74.321222 2.376661 1.793961 0.353859 2.051685 0.671041 0.436013 1.319003 0.733035 0.616154 0.452675 2.351369 1.957955 0.347507 1.047265 1.136774
+1 0.024088 1 1 -2.240672 -2.281161 0.522726 1.567916 0.292425 -0.229381 -0.464717 -2.064626 1.867763 2.265613 2.053605 1.407030 37.896180 21.096017 -39.235232 -26.545153 -44.392735 1.244511 2.004657 2.273691 1.420956 2.007749 2.494778 2.484268 1.333641 1.511642 0.668359 0.359525 0.529583 1.198803 1.025095 2.019353
+1 0.013150 1 1 1.338584 0.632136 -2.122164 0.863407 1.837847 -1.014394 0.507297 1.423501 -0.014169 2.189512 0.083750 -1.422937 2.285517 12.681422 -13.348200 56.808798 35.461054 2.034013 0.662241 1.036969 1.337203 0.616497 1.717952 0.867045 0.668438 1.685225 2.083979 1.178724 1.062291 1.678931 2.048759 0.988180
+1 0.019685 1 1 0.516956 -1.157937 0.723028 -1.326594 -1.752735 -1.071896 0.111771 -1.710087 -0.572073 -1.554724 -0.052955 0.625072 53.093753 -3.295680 -40.488824 54.342477 -15.990391 2.117407 0.514268 0.298037 2.101949 1.698752 2.172852 0.876336 1.574092 1.764881 2.102990 1.197214 1.331867 0.946280 0.383151 1.618373
+1 -0.026467 1 1 0.312792 -1.928126 1.079317 2.086611 0.077440 0.921356 0.318320 1.440420 1.589740 -0.494140 -1.773498 -1.326504 -7.372668 -12.439374 31.444069 30.472397 49.581330 2.326206 2.043056 1.890311 1.948571 2.391615 1.126957 1.760049 1.888298 1.874692 0.450538 2.446278 1.843641 0.582734 1.261827 0.519135
+1 0.000499 1 1 1.357743 2.207081 -1.522178 0.307203 -1.624767 0.832415 -0.692272 -0.133394 1.146178 -0.435021 2.222125 1.572463 41.539485 54.117216 -51.953084 -25.485713 61.615541 0.960891 0.688349 1.081311 1.842910 1.790048 2.080666 1.751894 2.079752 2.138809 2.467005 1.447394 0.844540 0.438026 1.401370 1.326843
+1 0.002156 1 1 0.971852 0.768401 -2.149972 0.013070 -1.809651 -1.042898 2.100965 0.986053 -0.884365 -0.654131 0.031982 0.308371 -26.679443 -51.398277 -0.848454 -9.962737 -43.719492 2.222417 1.404608 1.746490 1.259399 2.471045 1.854802 1.407238 0.950454 0.775624 0.907031 2.221241 1.901905 1.061049 1.055095 2.226513
+1 -0.025014 1 1 1.057774 -1.831880 2.346438 -1.401056 0.250963 0.348026 1.194576 -2.255322 1.259329 2.205577 1.479005 -0.215185 -70.544244 -37.103782 -53.262416 18.574951 39.201134 2.176777 1.598426 1.242347 1.620927 1.419984 1.412592 0.941530 1.548010 2.145998 1.787406 0.429090 1.972288 0.487183 1.835864 0.365977
+1 0.022902 1 1 0.787547 -0.804280 2.314741 -1.624515 0.351924 0.737940 -0.450560 0.247938 1.339932 -0.266793 2.206220 -1.843171 34.030374 -1.501375 -33.603477 -23.642519 -9.811344 0.636200 2.105766 0.602450 1.871218 0.569514 1.816797 1.657976 0.852122 1.870484 1.728384 0.699612 1.382692 2.397184 2.477470 1.846295
+1 -0.017842 1 1 0.217210 -1.445262 1.851028 -0.960508 1.382945 1.656110 -1.840513 -1.383952 0.274298 1.407687 -1.901348 -1.248207 29.752405 -51.331289 -74.978278 -9.911614 65.510196 1.823086 1.610186 0.887116 0.514051 1.161692 0.561172 1.125815 0.573344 0.949927 0.919486 2.304222 1.556469 0.326236 1.292032 1.930647
+1 -0.025235 1 1 2.088072 1.066739 -1.952311 -0.120253 0.527725 0.752220 -0.773364 -1.158212 0.809962 -1.059108 -1.739014 -1.377943 73.180685 -52.230639 -40.347717 25.911978 52.609226 0.673916 1.504168 1.047196 2.230510 2.424556 1.260198 2.388651 0.804173 1.477663 1.073125 1.505116 1.225664 2.481726 1.361151 0.362180
+1 0.018779 1 1 -0.266039 0.742657 -1.280670 1.966795 -1.476276 -1.044396 0.477536 0.746106 0.129544 0.115457 -1.014889 1.604294 -29.034295 -29.395363 52.131047 16.504515 41.377820 1.930314 1.540925 2.328958 1.045231 0.700688 1.458811 1.478805 2.270641 1.912941 2.049622 2.003199 0.268898 0.621701 1.435664 1.705968
+1 0.057940 1 1 1.644343 -1.681516 -1.050057 -0.412165 -0.047003 1.702232 0.502542 1.625677 0.329204 0.593908 0.969050 0.800623 70.000318 45.342945 -71.125101 -49.580617 -51.434688 1.183022 1.302282 0.949807 1.161388 2.207002 1.087295 1.166737 2.091489 1.413660 0.877919 1.186845 0.300647 0.979259 1.156544 1.781703
+1 0.001699 1 1 -0.478166 -1.914849 -1.958493 -0.352613 1.819326 -1.275395 1.096657 1.359930 1.256536 -2.320649 1.298213 0.709044 -23.218773 62.079418 -31.226333 29.023603 -0.297292 0.676104 2.287876 1.336874 1.832272 0.743742 0.575785 1.464576 1.636087 1.959867 0.980961 0.509943 1.868306 1.117370 0.389884 2.279068
+1 0.015484 1 1 1.420794 1.602641 -0.430696 -0.471460 -2.305235 1.179815 -0.578460 -0.526010 -0.204355 0.736641 1.279148 0.727207 -56.372410 -51.091411 56.656886 32.275959 62.038070 1.732762 2.274548 2.336976 0.798522 1.013958 1.583593 1.695993 0.813154 1.684056 0.430134 1.512854 0.786614 1.123541 0.598083 0.484861
+1 0.021044 1 1 -1.954961 -2.255158 -0.696176 0.232035 -2.039079 -2.307432 1.948426 0.804775 1.305444 -0.281407 1.635074 -1.955594 39.464220 -24.859286 -60.016780 47.974005 49.108346 2.334622 1.745130 0.902012 1.119852 1.608308 0.833960 0.367982 0.920182 0.497416 0.574596 1.731402 1.925861 0.940034 1.157344 1.730301
+1 -0.022628 1 1 -1.209541 0.494220 -1.581637 0.017126 0.379881 -0.629415 0.742092 -1.348371 -0.196134 2.251048 2.309624 1.904920 0.754954 -61.488077 69.891567 17.566016 32.024824 1.993141 2.228550 0.980861 1.084926 1.854928 1.266202 2.056687 1.486190 0.399430 0.725939 0.614885 1.626736 2.301484 0.549697 1.764743
+1 0.023493 1 1 0.324918 -0.767236 -1.836183 0.709536 -1.887991 1.757404 -0.567824 -0.831694 -1.332471 -1.561266 -1.617816 -0.147777 -8.315800 36.343035 17.389090 58.429868 -19.206187 1.399277 2.143418 1.170167 1.249334 2.056903 0.614998 1.269316 0.400951 1.534316 1.498295 1.348394 1.956391 1.064542 1.250816 2.207571
+1 -0.009143 1 1 0.793971 -1.215313 -2.270395 -2.311297 -1.745447 -1.102705 0.653756 -1.608155 2.008917 -0.403496 -0.430425 -0.640860 50.333617 -42.907118 60.074582 23.502254 52.380962 1.627327 0.986352 1.117575 1.588988 2.376915 1.569454 0.309641 1.388864 0.392222 1.081632 0.494520 1.389322 1.328642 0.743932 1.521244
+1 0.029758 1 1 -1.432175 0.321506 -1.554458 -0.284942 -1.235770 -2.095531 0.810556 -0.507161 0.853488 0.068372 -0.695746 -1.966373 -27.235920 45.895190 60.452648 -72.338590 -44.688806 0.853665 0.794201 0.394398 1.644414 2.419744 1.386246 1.392580 2.089558 0.457779 0.387214 2.405051 1.946074 0.923808 0.686214 1.193424
+1 0.027623 1 1 1.246552 -0.482724 1.599564 -0.308773 -1.201864 2.279088 2.328069 0.894010 -2.185289 0.201799 -1.276153 -2.212580 -43.451586 59.194460 -68.716008 -59.946126 35.454534 0.390376 1.549624 2.285340 1.461710 0.703858 0.747093 0.647821 1.672370 2.028971 1.408497 1.852799 1.501598 0.611440 2.214754 0.863185
+1 0.006809 1 1 -2.253975 0.337866 0.079927 0.304651 -2.092435 1.009275 -1.711051 2.077992 1.296326 1.970967 -2.045183 -1.234024 -32.558336 -7.959346 27.266306 14.803579 -46.240269 1.221865 1.629059 0.849383 0.833213 1.314131 2.105915 0.869475 1.009072 0.474876 1.983087 1.996857 1.682859 0.557177 1.471963 2.027925
+1 -0.009071 1 1 -0.128941 0.582501 -2.244908 1.922402 1.667814 1.660593 -1.888300 1.285667 1.893680 -0.391128 0.094706 -1.061562 -18.356733 28.381072 0.674918 -56.655468 -8.444664 0.932902 0.540330 1.820227 0.806593 1.662313 1.748888 1.062350 0.417343 0.284868 1.273333 0.412660 0.329330 1.544534 2.236640 1.958247
+1 0.031212 1 1 1.309350 -0.615487 -0.800984 1.163356 0.818955 -0.710008 -1.342548 -1.280600 -1.559467 0.346497 -0.937109 -1.186443 72.817640 -3.917775 3.960428 -37.081048 28.822497 2.420495 0.507276 2.044335 0.894684 1.711372 0.534515 0.838740 1.958476 2.353306 0.769862 0.813512 0.953260 0.689346 2.088016 1.527863
+1 -0.007247 1 1 -1.849246 -2.071772 -0.429614 -1.142201 1.299754 -1.662029 1.315571 0.265313 1.193793 -1.272722 -1.114120 2.019416 54.112582 20.159672 -26.399535 3.009588 32.144818 0.744299 0.932415 1.343168 1.883411 0.732147 1.448427 2.464877 1.691912 1.956585 2.074592 0.921853 1.587715 1.228039 1.903153 1.787583
+1 -0.011364 1 1 2.200096 -1.106928 0.367027 0.105060 -1.407957 2.086201 -2.099522 -0.298329 -0.031274 2.172521 1.966973 1.503885 -46.598536 -31.590567 57.335790 42.616364 3.232803 1.880906 1.383749 2.168151 0.617847 1.899052 0.362444 2.343951 1.028944 1.467620 1.033233 1.553687 0.817546 1.237544 1.899561 2.167515
+1 0.049062 1 1 1.647457 -1.185205 -0.470720 0.715003 0.464265 -0.820155 -0.605103 -0.623485 1.443104 -0.411628 -0.439908 0.211005 -65.878339 -67.239511 5.539639 -45.292710 15.425600 2.245762 2.278113 1.486717 0.250215 1.606902 1.945617 2.235715 2.157711 0.656062 0.680147 0.478813 0.657456 1.607900 0.725161 1.030818
+1 0.026938 1 1 0.067554 -0.311207 0.293528 -0.551265 -0.554532 1.081763 0.800518 0.442967 -0.624729 -0.625778 0.594377 -0.567568 -39.734835 -23.371424 46.470353 -22.784273 14.722916 0.595841 1.055612 1.918496 0.918239 1.591898 1.785106 2.280149 1.959060 0.924699 2.171349 0.366191 2.319637 1.889630 1.770010 0.560719
+1 0.054845 1 1 -1.739762 0.189034 0.944659 0.841733 0.420588 0.234134 0.251329 1.780215 1.122624 -0.463155 0.617875 -1.477832 34.207797 -19.550205 69.708541 -58.555160 13.430752 1.084649 1.702208 1.754800 1.420781 1.307975 2.139351 0.327122 0.431619 1.724327 2.263114 1.399584 0.560066 0.524850 0.403229 1.569343
+1 -0.027209 1 1 -1.311303 0.780130 1.783600 1.450716 0.276180 0.062524 -0.023830 0.045431 0.159663 2.114400 0.591423 1.625364 -7.041010 11.741474 -61.053382 25.803357 27.028767 2.462368 2.275524 0.724659 1.595226 1.470635 2.211391 0.594206 0.571902 1.449976 1.503689 2.002638 2.083255 0.270485 0.285909 0.766619
+1 0.013091 1 1 -1.033200 0.166934 1.790793 -0.178992 -1.810072 1.307055 -1.491580 0.923136 1.961179 -1.626699 1.343185 -2.150006 -17.645263 -13.933562 -31.378769 17.033843 -62.205106 1.656813 1.554480 0.639515 1.578028 0.411849 2.450236 0.865284 0.321397 0.962387 1.081092 0.420290 0.321624 0.277061 0.559025 1.027197
+1 0.000534 1 1 0.194085 1.005216 0.748150 1.503240 1.831538 1.335984 -0.642301 0.933422 0.474095 -0.529493 -2.199352 -0.537130 44.331848 35.363495 54.264861 29.524468 17.734135 1.489059 1.371755 0.839686 2.102992 1.243597 2.390569 1.541222 0.573158 2.313406 0.658012 1.959582 0.688987 0.546677 0.496902 0.927358
+1 0.006174 1 1 0.910176 0.911835 0.520012 -1.643432 -1.842958 -0.054671 0.053677 2.076478 -0.583536 -1.012726 0.270263 -0.437893 34.528459 -30.192198 9.728973 14.850036 -15.447236 1.799536 1.803143 1.677702 1.639914 1.041859 0.274563 1.336868 1.734329 1.614092 1.302980 1.437501 1.070494 2.295129 1.741111 0.857444
+1 -0.020993 1 1 0.028077 0.647652 -0.537623 -2.187333 -1.162455 0.182379 2.198648 -1.877892 1.844440 1.408391 0.488595 -1.873277 -22.184415 46.537923 62.867299 10.701661 12.817458 1.720305 2.161474 0.886731 0.791971 1.152600 0.756239 1.365357 1.311037 1.844380 1.735990 0.275974 0.289467 2.074721 0.835160 0.276580
+1 -0.067906 1 1 1.199423 -0.890761 0.241038 -1.525269 0.199062 -0.153178 -1.491625 0.175486 -0.555431 0.111741 -2.216904 1.349240 21.260951 32.797453 -23.209822 62.522975 73.636917 0.860054 2.434917 2.148148 1.924922 0.919752 2.265017 1.899577 2.441727 1.857724 1.022955 2.050023 1.994667 0.874427 0.989627 2.162988
+1 -0.044183 1 1 0.293772 -1.154901 -0.088826 0.924014 -2.137199 -2.069438 1.105245 -0.378312 -1.278103 -2.003016 0.621405 1.303613 61.522343 56.018076 -54.195270 -59.906844 -54.331738 2.072132 2.322538 1.150871 0.944310 1.025707 1.060845 2.121416 0.389645 0.520550 2.381277 0.631025 0.635816 2.415505 2.143120 0.668624
+1 0.028457 1 1 0.370543 -2.065351 -0.902607 -0.937119 -1.351817 -1.555046 -0.755788 2.069735 -0.827022 1.786742 -2.277944 -1.955855 49.859793 -56.462847 -71.072499 -65.484206 -43.042441 1.910453 0.728870 0.374611 2.087376 2.036259 2.408845 0.466681 1.511867 2.193377 1.585484 1.984322 0.255335 2.170992 1.107042 2.303598
+1 0.059901 1 1 0.909908 1.113543 -2.296305 0.461471 -0.644761 1.998967 2.012500 -1.433033 0.027510 0.553581 1.778486 0.325112 -70.466951 61.954163 -36.381920 -70.921837 66.685914 1.227428 0.635469 1.075265 1.475625 0.581464 2.412485 0.888380 1.497964 0.274495 2.434249 2.171002 1.284773 1.428114 0.808570 1.130027
+1 -0.005700 1 1 -0.985555 -0.179218 -0.906262 -1.109309 -1.938348 -1.071021 0.668543 1.868505 0.606249 1.041616 -0.092253 -0.113925 -47.734191 -68.540308 43.035346 -4.933149 38.565389 1.652318 0.265275 0.482509 2.036221 1.771265 1.392117 1.057590 1.416392 1.802913 2.309989 1.730392 0.697683 0.465868 1.345811 1.294037
+1 0.034386 1 1 2.307066 1.316763 1.454291 -0.889226 -2.237285 -1.892474 1.811460 -1.534272 -0.316813 0.327435 -0.869231 -0.753307 43.042960 -26.977881 32.748188 48.801790 11.687705 0.403853 0.813377 0.934139 1.076701 0.859037 1.083827 1.373019 1.831804 1.883166 1.118854 0.580419 0.609099 1.130052 2.028769 0.273473
+1 0.071251 1 1 -2.018382 1.540229 1.481897 1.268987 -0.402932 -0.369658 -1.913754 2.312813 -1.055658 -0.295202 0.686360 -0.272239 6.620340 -31.939457 43.540148 -70.736422 32.954016 2.247217 1.973280 1.415333 1.993153 2.419681 0.330954 1.850302 2.279124 0.491290 1.118456 0.636285 1.294113 0.913115 0.967443 0.572721
+1 -0.012050 1 1 0.823379 -1.753469 0.734881 -0.023521 0.517132 1.790691 -1.886872 1.715298 -1.384946 -2.294143 -0.892218 -0.687186 16.907399 62.658587 -47.131043 18.560953 -46.064222 0.604264 0.858200 0.520011 2.328673 0.752235 1.571740 0.480912 2.184950 1.706982 0.999147 2.412178 2.469037 1.861397 2.003468 0.281501
+1 0.017386 1 1 -0.604359 -2.262011 1.933661 -2.302006 -1.097249 -1.887794 0.364664 -1.904678 -0.666521 -0.868892 0.224915 0.815480 68.181928 -66.341003 -43.233562 -26.476365 61.729097 0.339119 1.828585 1.773672 1.354151 1.956739 2.408040 0.420915 1.815446 1.457999 1.337578 2.424934 0.870547 1.031395 2.148625 0.934174
+1 0.026490 1 1 1.228913 -0.065688 -1.318751 -1.878673 -1.851013 1.210561 -2.201941 -1.636862 0.181255 2.146745 2.285864 -1.584412 15.938846 -15.823590 2.922767 72.944096 21.428671 1.400029 1.289893 1.984156 1.966264 0.496738 0.421779 0.594060 0.367161 0.622725 0.644383 2.388760 0.389241 0.471693 2.492033 1.348173
+1 -0.017161 1 1 -0.657620 -2.060455 1.283181 -2.181941 -0.070051 0.758149 -0.090239 0.740673 -1.641949 -0.485255 1.458735 -1.602750 -44.530460 -73.443424 -13.627210 17.488607 -68.984235 0.354375 1.734899 2.196421 1.001191 0.770007 1.009942 1.587380 2.345800 0.615453 2.173071 2.307408 1.103327 0.622234 1.388001 1.638385
+1 -0.044669 1 1 -1.545724 0.416524 -2.091746 -1.553265 0.910712 0.490421 0.542827 0.106063 1.315310 0.595624 1.545461 -0.130285 49.627748 -56.447131 43.066290 65.134958 23.240843 1.507776 0.944084 1.720031 2.068485 1.771728 2.435883 0.392192 0.575716 0.313049 2.422282 1.287490 2.087788 2.202042 0.972645 2.493047
+1 0.053902 1 1 -2.162565 0.426048 -2.249550 -0.684388 0.433697 -0.921415 -1.317276 -0.651234 1.587556 0.506046 -0.740055 -2.106570 -30.198549 52.981210 55.188657 -44.239315 19.828036 0.622123 1.770373 2.164272 0.662273 1.574652 2.180555 2.085540 0.419990 2.025406 2.242977 0.470926 0.858325 0.360749 0.866282 1.346908
+1 -0.031653 1 1 -0.632323 -1.019425 0.777119 -1.708517 2.260644 -1.349953 1.491536 -1.656365 2.266936 0.734123 1.374578 -2.305308 -1.492245 -30.168682 -45.036640 -30.810508 -32.214524 2.432381 2.282511 1.160881 0.433681 0.378927 0.368291 1.612680 2.321413 2.492870 1.915228 2.242729 0.789714 1.472507 2.173084 0.273915
+1 0.020307 1 1 0.012980 1.389257 -0.648056 -1.553997 -1.961376 -1.681332 2.040747 2.058707 2.328166 -2.188760 -1.578772 1.034792 -53.411820 57.544246 -53.860522 16.206268 -21.259076 1.355532 0.422493 1.341667 1.396211 2.363603 0.569080 1.279422 1.495764 1.562862 2.014496 1.137845 0.263487 1.932151 0.914502 1.785807
+1 -0.027873 1 1 -0.404908 -0.606205 -0.309382 -2.022452 -0.884787 1.686786 0.083254 -0.335602 0.267183 -0.362919 -1.754946 -0.537368 67.036343 29.816236 -28.520375 58.061240 -64.744012 0.585794 0.946798 2.329537 1.771851 2.245330 1.758840 1.821409 0.426064 0.608669 0.645698 2.002188 1.271368 1.137470 0.701071 1.142591
+1 -0.006777 1 1 -1.407687 1.912191 -0.296939 -0.237432 0.873429 0.628741 2.073820 1.858484 1.824059 -1.844352 0.077983 0.623235 -29.517473 -50.173068 41.242405 11.101810 -11.883260 0.295831 1.038128 0.572984 1.639905 0.874940 0.619502 0.475457 0.508978 1.387645 2.396194 1.581687 1.163529 2.181210 1.844700 0.371011
+1 -0.027034 1 1 -2.187575 -0.519578 -0.489698 2.187048 1.077451 -0.994824 -0.450825 0.502533 1.469745 -0.338863 2.010913 0.154948 -55.497347 -43.915651 59.647342 42.871461 -59.361199 0.869961 2.427759 1.094334 2.476470 0.776901 2.126468 2.049356 2.022646 0.858644 1.230574 1.757714 0.892770 1.031835 0.544456 1.414170
+1 0.054007 1 1 1.872245 2.199165 2.093141 1.441669 -0.970969 -0.075427 -0.072143 -1.424419 -1.272734 -1.308261 0.064167 -0.686432 -29.984495 50.589804 62.836063 -64.284145 26.372824 1.345784 0.840509 2.434805 0.264636 0.994868 2.492800 0.742306 1.187495 2.231287 1.994536 0.912748 1.548578 0.449271 1.401578 0.326838
+1 0.003991 1 1 -2.084828 1.613770 -1.886560 2.255855 -1.728171 1.786976 1.644413 -0.509884 2.213054 -0.082885 1.825658 1.464719 0.311106 -21.247895 36.627723 2.137766 -70.566455 1.968764 2.018447 2.296154 0.953440 1.462041 1.763899 1.348697 0.303236 1.733692 2.160842 1.519485 1.977229 0.289215 2.331260 1.480659
+1 -0.015204 1 1 1.714267 0.143460 -1.604905 0.073001 1.701486 2.105958 0.079666 0.634963 -1.740767 2.151713 0.962171 -1.714763 30.217035 -42.286872 -15.459834 -33.438057 56.569113 2.231342 0.670065 2.025613 1.233869 0.881910 0.756348 0.947555 1.563583 0.645036 2.119111 2.149663 0.394002 1.739883 0.468851 1.971141
+1 -0.007791 1 1 0.657469 -0.477541 -0.832813 -1.285681 -2.132890 -0.335022 0.583314 1.981630 -1.912870 -1.689343 -0.640320 1.230638 20.971426 -33.245286 -3.526499 -19.870190 -58.291448 0.559592 1.558741 0.257879 2.164120 0.371652 1.850367 1.125147 0.589102 0.287888 0.282722 1.216767 1.450226 1.201349 1.065117 1.925505
+1 0.002132 1 1 -0.819165 1.895699 0.544017 1.264909 1.746949 -1.921897 2.099969 -1.614511 -1.155180 -0.063114 -0.470694 1.152411 20.503110 45.761845 69.323679 73.069217 24.327915 1.064046 1.919929 0.250337 1.416753 1.119345 2.083983 1.255870 1.663153 2.369493 0.577772 1.108031 0.926314 2.303542 1.380725 0.848943
+1 0.073405 1 1 -2.259427 -1.753974 1.659977 1.893154 0.190238 2.330950 2.185406 1.757904 -1.589400 1.479333 0.580034 -1.294506 11.014717 24.355202 -12.115207 -70.285321 -35.383812 2.189036 0.632069 2.439062 2.056153 1.511419 1.413944 1.156792 1.455854 1.288742 0.638951 1.091723 1.333645 1.578329 0.968967 1.433574
+1 0.050958 1 1 -2.110746 -0.443243 0.699567 0.212821 0.180179 -1.798939 -0.087661 1.658214 0.527676 -0.061557 2.142213 1.521091 8.507760 39.923513 44.478504 -49.779813 50.684030 1.322352 0.772599 1.823665 2.339077 2.360601 1.878526 1.877498 0.352286 0.374447 1.574120 2.239400 1.087738 1.864603 1.883354 2.023460
+1 -0.010320 1 1 -0.575981 -1.272572 1.416094 -1.986324 -1.583929 -0.816664 1.509500 -1.342833 -1.365678 1.100763 -0.314704 -1.922755 57.897970 41.174007 61.530648 45.604894 -18.551732 2.140554 0.282455 1.223499 2.106835 0.579375 1.060027 1.881929 0.587009 1.103336 0.760643 1.133785 1.768508 2.315806 0.505515 1.684739
+1 0.022633 1 1 2.253502 1.129306 -1.262071 -1.163924 -0.950423 1.238627 -1.723518 -0.106411 2.258535 0.908277 1.985371 -0.301034 51.530450 -27.726244 55.019500 -37.256387 -68.091975 0.297711 1.122858 0.375375 1.432186 1.747991 1.736949 0.653497 0.322787 1.827081 1.244597 1.192670 1.461115 1.965054 0.403664 2.130596
+1 -0.005489 1 1 1.981484 0.348488 -0.456226 -0.727511 1.369807 2.331434 0.889509 2.287326 -0.583495 -0.325856 -0.861812 1.416529 19.537000 8.362237 -5.888101 38.689893 11.025807 2.286126 1.174255 2.448757 0.763570 0.813723 2.234283 0.593223 2.041230 0.457883 2.137775 0.836930 0.777615 0.627403 0.514850 1.084686
+1 0.030751 1 1 -1.639174 -0.979927 0.161732 -0.823545 -1.040149 1.183822 0.794749 -2.267986 0.471575 -0.476329 0.694880 1.546540 -26.703101 0.981858 2.094264 -51.697654 67.530617 0.431239 2.090029 1.614738 0.902846 1.634150 0.913069 2.448655 1.300023 1.239813 1.788114 1.075426 1.935243 1.134092 2.442517 1.631779
+1 0.012051 1 1 1.407826 0.421743 0.795732 0.103621 -2.021845 -0.114689 -0.216251 -1.272037 0.983948 1.441209 0.725638 0.140029 63.458510 47.172773 -67.211829 20.795769 14.483484 0.983732 2.081587 1.485426 1.059058 1.346134 2.214999 0.494545 1.819588 1.315852 1.779928 0.750222 1.482276 2.115214 1.905174 2.003500
+1 0.016460 1 1 -1.874804 1.917064 1.487695 -0.240642 -1.233434 -0.533379 -1.545330 2.324514 -2.309759 0.541728 0.482974 -2.108526 -26.722255 -20.935493 37.177244 -62.052309 36.844289 2.004497 1.837493 0.745158 1.876644 1.761899 1.481974 1.535873 0.670286 1.254777 1.279928 0.995066 1.331758 1.360208 0.269399 2.293082
+1 0.003273 1 1 -1.595842 1.602879 -1.135569 -0.341410 1.605648 -1.732512 -0.480516 1.001490 -0.604708 1.297413 1.405226 -0.852547 51.513909 -5.730620 -14.522027 -21.708738 -58.753094 1.176355 1.741801 1.195352 1.536582 1.338792 0.331402 0.367814 0.342881 2.043952 1.196236 0.630632 0.779852 2.222356 0.386842 0.645022
+1 -0.064542 1 1 0.027839 1.356361 -2.175968 1.361277 0.334335 2.006113 -0.404430 -1.983461 -0.592191 -0.381980 -1.663575 -1.095856 -64.649802 30.776235 56.176920 65.494332 63.234275 1.802008 0.604472 2.117933 0.358220 1.096510 0.789234 2.406166 0.423281 1.081330 2.169546 1.552520 1.457689 0.629812 0.503597 0.955190
+1 -0.063636 1 1 -1.347450 1.146017 1.575289 1.675260 -0.425263 1.295975 0.797018 -1.843205 0.500872 1.825056 0.776497 1.978264 -61.535365 25.119073 -73.742596 58.192725 45.122525 0.989256 0.429654 2.449876 1.565175 0.402344 2.440709 0.495135 0.485930 1.033786 1.836375 2.210000 1.964685 0.960057 2.433314 2.201522
+1 -0.044038 1 1 0.208946 1.021151 -0.044480 1.692145 0.606033 2.119761 1.162922 -1.755952 1.403219 -1.604615 0.229406 0.898325 -10.814642 38.313222 -19.676546 46.293252 0.685883 1.039551 1.986631 0.811176 2.188027 1.667222 1.006633 2.229385 1.520992 0.313041 2.283890 1.837666 1.407777 1.006422 0.932778 0.692495
+1 0.075510 1 1 1.396472 -1.908623 -0.993199 -1.406410 -0.184187 0.408064 1.798533 -2.027600 2.130050 -0.275479 2.309495 -0.258956 62.989064 -42.807651 -68.189465 -60.337001 66.017787 1.539266 1.439546 1.703734 0.406347 2.228674 0.822093 1.159416 0.552735 1.072065 1.694017 1.342394 2.373778 0.584597 1.072238 2.356283
+1 0.020268 1 1 1.808686 -1.032630 0.323481 -1.349923 1.999349 -0.978700 1.935567 1.458259 -0.170652 1.695683 -1.190480 0.410741 -10.204845 -62.837877 33.801220 47.096137 -5.221679 1.213509 0.688500 1.373341 0.493997 1.604414 0.634128 1.032099 0.485089 0.383051 2.183354 1.877723 1.884894 0.909176 2.277121 0.571898
+1 0.037505 1 1 1.354930 2.040921 0.273924 -0.171177 2.290252 1.472368 1.333114 -1.771237 -1.011922 -0.366837 -1.617588 -1.035064 57.938790 -22.758246 2.153956 51.534099 33.595316 1.922111 0.915165 1.680313 0.515165 1.872328 1.220313 0.303779 1.855449 1.024643 1.173287 1.929725 0.645503 0.961532 2.471810 1.212713
+1 -0.059844 1 1 0.185886 -0.123307 1.036565 -0.152847 -0.640198 -1.430583 -1.199610 -2.243267 1.235716 1.179077 1.156878 0.334446 -26.736606 37.861285 34.623124 60.841366 10.833501 1.054698 2.304725 1.013051 2.096116 0.416093 1.770456 1.302221 2.185351 1.700405 0.706238 2.492532 0.744231 2.047018 0.978745 1.513602
+1 -0.033127 1 1 0.073063 -1.962489 -1.547541 -1.840660 0.857860 -1.862074 -0.898194 -2.160705 -1.303341 -2.071681 1.098177 -1.364278 33.943259 34.353204 24.297381 66.089218 11.483615 0.701836 0.513673 1.558932 1.227199 1.279624 0.392798 1.756921 1.065694 0.362944 1.749694 1.112237 1.868409 0.596448 2.250534 1.473999
+1 0.019380 1 1 1.335175 -0.113189 1.440924 0.650592 1.755421 -0.907638 -0.668403 0.482394 2.283527 1.550447 -1.154838 0.971647 65.046307 33.286012 -61.988246 63.552735 -19.175495 2.386764 0.589785 0.521619 2.356372 0.539991 0.636587 1.861586 0.670946 1.090696 2.070690 0.588665 1.946576 0.344960 0.984527 1.942192
+1 0.043801 1 1 -2.282911 -0.619180 -1.595797 -2.349284 0.694850 1.036994 2.336866 -2.057362 1.431337 -0.267678 1.461245 -1.827779 18.429352 -7.888917 10.965525 -52.428707 -69.284882 1.059906 2.091395 2.081426 1.027904 1.975673 1.129427 0.525173 1.334721 1.662777 0.539679 2.129708 0.257743 2.143292 1.300884 2.210527
+1 0.023017 1 1 -0.074520 1.045071 1.438967 0.746636 -0.373487 -0.300570 0.006173 0.084376 -0.327329 -2.054988 -1.086135 1.117277 -25.275172 0.177701 -13.379423 -17.955131 28.112714 1.230656 0.882245 1.894310 1.672262 2.464488 1.891733 1.114790 2.023050 0.906392 0.474337 1.933511 1.273192 0.288042 0.620185 0.694714
+1 -0.061414 1 1 0.615223 1.064910 0.281498 -0.098653 0.696049 2.351588 0.337286 -0.233474 1.418036 -2.336035 1.879024 -1.675403 -62.764683 63.966766 39.442725 63.872379 -46.932584 2.185890 1.758381 0.852835 0.340761 2.427478 0.866704 1.701128 1.614653 1.728515 0.657664 0.605976 0.387834 1.574528 2.333794 1.329603
+1 -0.031796 1 1 -0.612883 0.561709 1.735966 1.978912 -0.464348 -0.572283 -0.380688 1.193969 1.687191 2.169120 1.363160 -1.009685 -14.729466 -58.130843 -55.082576 27.152365 49.805287 0.286792 2.114313 0.264213 0.630487 0.591858 1.603087 0.834023 1.427764 1.682265 1.836404 0.441597 0.675363 1.072460 1.583844 1.416668
+1 -0.017290 1 1 2.089803 1.892355 0.890625 2.185731 -2.203854 -0.805228 0.508371 0.624525 1.909018 -1.781917 -1.445811 2.046509 -1.373678 12.601807 -1.421378 -39.099371 6.866168 2.120152 1.642262 2.248329 0.422540 2.134298 0.898780 0.803819 2.278491 1.096925 1.025278 0.600458 2.146427 2.239939 1.155910 2.372053
+1 -0.003627 1 1 -1.209571 -0.006696 0.556664 1.753707 -1.439534 -0.839674 1.196043 -1.159769 -1.801100 1.290739 2.314748 -1.512582 43.780140 62.812288 -13.869211 0.176939 -26.179058 0.753539 0.975828 1.990282 1.419569 1.192291 1.835499 0.974969 1.062130 1.212340 1.295961 0.463806 0.440208 2.069139 1.515726 1.815324
+1 -0.066051 1 1 -1.353691 -0.072133 -1.249567 1.652027 0.222476 2.233164 -1.395776 -0.539070 1.770873 -0.393344 0.545219 -2.097774 25.554669 47.320263 11.659543 61.932165 43.899614 0.937188 0.560573 2.305972 1.721888 1.767394 1.590009 1.524794 1.210365 1.850277 1.850601 0.554123 1.893546 2.321624 1.539988 2.326566
+1 0.062243 1 1 -0.193156 0.468895 1.602415 0.481744 0.787098 1.072786 0.713089 1.274582 -0.628952 -0.901517 -1.470515 1.530872 -8.824407 38.195088 -55.150903 -71.219014 22.036362 1.602123 0.382717 1.071947 1.960731 2.002848 1.112376 1.960679 1.127030 0.744656 2.441493 2.425367 1.394187 2.094788 0.600545 1.359181
+1 0.002589 1 1 1.927305 -0.748255 1.446611 1.981278 1.593483 1.161584 -0.680253 -0.754551 -0.706137 -2.253003 -2.173601 -1.267834 29.994019 -40.528030 -4.608074 -47.908451 2.665222 0.540706 1.394918 0.880290 0.530016 1.730736 1.985659 2.474014 2.250630 0.831801 2.330099 2.226882 2.198532 0.481880 0.451798 1.126006
+1 0.058245 1 1 -0.377892 1.067221 1.431505 -2.147209 -0.663830 1.944032 2.347455 1.563006 -2.133937 0.916519 -0.867701 1.395748 2.164206 73.806182 -39.496524 -68.075124 61.385708 1.518884 0.888210 0.887293 1.226786 1.093696 0.750732 1.052456 0.623205 1.951585 1.285311 1.473710 2.145270 0.799537 2.321482 1.403624
+1 -0.048787 1 1 1.788767 -1.228320 0.596465 1.542381 -0.055939 2.319006 -0.633140 -0.602689 2.247643 1.628029 2.156603 -1.668803 18.002413 16.557646 34.363422 46.032967 -23.917999 1.527844 0.725459 1.534333 1.787194 1.368537 0.743452 2.446186 0.304234 0.507495 1.222977 2.331437 2.203273 1.408660 2.355684 2.478004
+1 -0.042897 1 1 0.928161 1.593143 0.161676 -1.765594 -0.426231 -0.827165 -0.620474 0.212874 1.062997 1.122906 -0.442988 0.283176 -5.799253 31.947060 -65.764495 46.126984 56.217737 1.397515 1.792943 1.235124 1.724613 0.315724 2.372705 0.549103 0.770392 0.721439 1.474498 1.883436 1.166270 1.000882 2.325395 1.920742
+1 0.028327 1 1 0.332395 -2.331891 0.839258 1.231286 2.120709 -1.749145 -1.989020 0.226542 -0.114989 -0.536961 -0.472863 -2.327517 -32.852902 -8.720576 -16.722574 43.698984 48.815827 0.589104 0.326100 1.265973 0.459752 2.059495 1.437385 1.383344 2.120844 2.023084 1.476053 1.031092 1.555900 2.019669 0.333335 1.361960
+1 0.005266 1 1 0.366353 -1.791602 0.715259 0.047762 1.637652 -1.038976 2.050167 0.160457 1.313217 -1.585505 0.975453 0.029042 -62.961633 53.837542 47.560061 -8.047125 51.965960 0.503425 0.313386 1.330794 0.897544 0.269367 1.749324 1.631897 1.298517 0.678707 1.025351 1.826120 0.851930 0.883731 2.112457 0.567611
+1 -0.022821 1 1 -1.462026 -1.867453 -1.770051 0.071982 -1.277217 -1.260622 -0.372491 2.300916 1.636251 -1.024377 -2.339875 -1.394923 -10.658367 -35.178777 50.295383 64.507269 -26.328470 1.336035 1.248540 2.218609 0.419572 1.753227 1.988717 2.118008 1.612057 0.838050 1.612186 0.753188 1.830893 2.320955 1.534614 2.012499
+1 -0.002507 1 1 -2.349679 -1.240506 -1.577322 1.848095 1.582350 -2.158449 -1.089408 -2.049617 -0.349742 -1.767114 2.297793 0.976115 55.323961 -20.185593 40.741169 -13.178582 57.572801 1.015910 0.647348 0.482253 2.220614 0.368549 1.449859 1.775157 1.572297 0.852087 1.276522 2.246797 1.672697 0.777555 1.859619 1.367422
+1 -0.006502 1 1 -0.767099 0.459247 -0.325323 -1.324163 1.406617 -1.038642 -1.770412 -1.285966 -2.215755 1.817529 1.506980 -1.270638 29.680206 -64.784407 18.467936 40.599344 3.168394 1.393078 1.456843 2.164381 2.493450 0.411518 1.374717 1.114819 0.267556 0.555767 0.268817 1.512772 1.654704 2.114750 0.860738 0.422417
+1 0.012986 1 1 -1.299995 2.325523 0.508144 1.529699 -1.134572 2.282942 1.131308 -0.601467 -0.782080 -1.563193 -1.009385 -0.134949 -45.281028 61.757899 -34.995816 -24.679916 -45.342778 2.483980 1.009125 1.364252 0.740025 1.102264 0.745875 0.426886 0.915458 2.107544 1.247370 0.553812 1.166568 1.507902 0.802467 2.059584
+1 0.015291 1 1 -0.433035 -2.085429 0.943214 0.113035 0.683643 1.177906 0.324427 0.418461 2.182270 0.887841 -2.187328 -1.081981 8.123378 29.607093 56.413008 -16.572846 10.172146 0.823830 1.116904 1.547938 0.947841 1.871459 2.360204 1.941629 0.452081 1.381371 0.449830 1.799872 0.696846 2.135377 1.027322 1.208428
+1 0.004804 1 1 1.127513 1.598713 -0.471288 0.586744 -1.628206 -0.410065 2.261108 1.728452 -1.781487 1.074328 -1.638843 -0.129349 -49.780065 46.442529 -40.414141 -40.464421 14.472010 0.341012 2.136636 1.941079 2.466498 1.931979 0.272222 2.489857 0.773857 0.462698 2.069273 1.530357 2.458163 1.351707 1.388257 1.441648
+1 0.012708 1 1 0.548995 0.103271 1.508407 -0.861734 -1.989170 -2.289841 0.717761 -0.306682 0.947917 -0.954367 0.922203 0.413270 -7.667363 -15.366551 34.372321 45.594884 -36.786583 1.793451 0.785775 0.512937 0.437955 2.457774 1.564542 1.010919 2.272855 0.878008 0.426031 2.297900 1.048756 1.436346 1.916103 1.198950
+1 0.009334 1 1 0.545114 0.842709 -2.031648 0.062999 -1.457108 0.677297 -1.802413 -1.913818 1.232645 1.400726 -1.090071 0.945241 38.306963 25.122964 -8.347411 -44.933998 44.293457 1.226854 2.227314 0.473193 0.710954 0.760213 0.654855 0.647614 0.448190 1.234049 1.666737 1.848688 2.145540 0.845914 1.030304 1.813314
+1 0.021877 1 1 0.463438 -0.572850 -0.475718 1.530957 1.156665 1.471675 -0.887583 1.808076 -1.864540 0.071387 -1.853764 2.104726 -56.206901 30.621710 9.082371 -52.585308 -1.277602 1.035098 1.395038 0.656455 0.532220 0.514797 2.438988 0.817724 1.984898 0.938971 1.277217 0.433740 1.375016 1.642970 0.646655 2.328979
+1 0.016754 1 1 0.304120 -1.604267 1.379457 -0.418071 -0.341661 2.100743 1.968898 0.871998 0.134716 2.218810 -2.302840 -0.973679 47.636212 71.807257 -35.424310 -26.380860 16.881823 0.366888 0.532255 1.101663 1.898685 0.949513 0.709028 2.139843 1.846023 2.359571 0.304959 1.443434 1.794477 2.269886 0.470083 2.426932
+1 0.018111 1 1 -2.169227 1.563751 0.974815 -1.256614 1.024248 0.187174 -2.041144 0.678606 1.342913 -2.008340 0.665412 1.075929 54.398801 30.643798 -69.687108 -31.218977 2.651671 1.624637 0.768073 2.258047 1.753134 0.421416 1.242092 1.845839 1.521281 0.677989 2.455493 1.473095 0.801619 1.315678 1.097851 0.834619
+1 0.023015 1 1 -0.279392 -2.197601 0.622220 0.868400 0.931461 0.504934 -0.579340 -1.169157 0.639631 1.312909 -2.064619 1.987626 -3.211581 22.962856 -13.273521 -38.075582 -36.300648 0.550228 1.675065 2.314077 0.686313 0.613599 0.255912 0.605049 0.566308 1.932984 1.416931 1.863512 1.554629 0.895305 0.893386 2.395771
+1 -0.003675 1 1 1.881981 0.901993 0.044650 1.170182 -2.266029 0.373355 -1.932273 2.063650 0.587534 2.229782 -1.687061 0.016147 -61.837263 51.121876 5.371975 -13.216485 20.538822 2.064814 0.835379 1.722145 1.588495 0.832252 0.901988 0.715190 2.196972 1.260776 0.862911 0.940172 1.212687 0.382714 1.031216 1.405197
+1 -0.072936 1 1 -0.060354 -1.213869 -1.565927 0.157294 -0.015865 1.966715 1.883211 -1.990090 1.089986 2.335173 -2.229337 -0.260743 7.046582 -68.095052 26.457409 69.679367 51.124763 2.183320 1.316637 1.460671 1.241319 2.346526 1.556305 2.067417 1.827098 1.537757 0.835139 2.175274 1.081695 1.548843 0.403798 2.132918
+1 0.038974 1 1 -2.010509 1.910708 -1.659879 -0.235173 1.135197 -1.212892 0.720633 0.839366 -1.661105 -1.994293 1.132197 0.210300 6.855836 26.028831 66.566154 -72.644507 63.768126 1.388521 1.380361 1.482201 0.855760 2.252386 1.094828 1.777667 0.995535 2.462462 1.599446 0.381544 1.603546 1.805415 1.616670 1.881373
+1 -0.000047 1 1 1.881900 -0.470050 -2.164492 1.032598 -0.862717 0.341470 -0.611154 1.338826 -0.002443 1.358508 0.927774 -0.192550 38.981686 -34.799035 -17.376401 4.821476 34.549954 1.841195 2.212552 2.106806 2.342424 2.377503 2.435486 0.469788 1.975399 1.034290 1.303047 0.314973 1.002907 0.364549 1.723104 1.955241
+1 -0.005015 1 1 0.383344 1.029487 -1.301015 -0.666974 0.934412 -1.732882 -1.990451 -0.253837 -1.529886 -1.993518 0.030657 1.597131 38.706907 -3.006878 13.405825 11.704398 65.821663 1.595311 0.645142 1.647477 2.152419 1.702351 1.912735 0.836290 1.269652 1.546115 1.806672 2.494997 1.667875 0.731120 2.185120 2.306013
+1 0.015036 1 1 1.257515 -0.008383 0.480984 2.159417 -1.490067 -1.916730 -0.596991 -0.951942 -0.731777 0.357336 2.156888 -1.592097 -45.537024 -40.756905 48.700520 -40.355080 52.165340 1.268080 2.120638 0.805754 1.059581 1.132890 2.485317 0.968136 0.961838 0.853310 1.581189 1.793620 1.376565 0.671780 1.602088 2.042047
+1 -0.044309 1 1 1.369254 -2.256912 -1.909778 -1.562541 0.518172 0.427032 0.153775 2.111838 -0.050174 0.236728 1.423938 -2.103964 14.182225 10.659953 61.834608 54.257254 51.659595 2.017192 1.442973 0.797850 0.970266 0.760515 1.231202 1.069297 2.427878 0.841268 1.685034 1.125083 1.771554 1.757434 0.694354 0.754172
+1 0.012879 1 1 -1.910671 2.279699 -1.536367 2.177824 1.562161 -2.199419 -1.649495 -0.073902 1.996328 0.071330 1.904664 0.425099 20.703515 -36.025140 -74.522064 7.667657 20.315947 2.126873 2.113163 1.181950 1.286563 2.261067 0.752292 0.272749 2.347931 0.432269 1.389788 2.410850 0.409265 1.775010 1.339170 2.187278
+1 -0.023859 1 1 -1.749547 0.667781 -1.507449 -1.891892 2.162959 1.492343 -2.239508 -1.552714 0.737654 -0.544858 -1.259691 1.143700 10.753681 -12.881614 -51.283078 -14.694311 -67.283792 1.544659 2.088824 1.619871 1.680713 0.500258 1.090328 0.397704 0.960570 2.043537 0.972606 1.838156 0.635649 1.847519 0.502508 0.649499
+1 0.025912 1 1 -0.028601 -0.028372 -0.897809 -0.398358 1.104741 0.563270 -0.316198 1.230673 1.239932 1.356012 1.385190 1.691798 -16.202548 -66.219581 47.495353 -45.602919 51.733581 0.419506 0.632517 0.954953 2.141587 1.903778 1.051146 1.118321 0.617041 1.859748 1.283352 2.299667 1.511385 0.840778 2.453993 1.011182
+1 0.068216 1 1 1.860509 -1.843095 2.343183 0.444944 -0.389067 1.742833 -0.416694 -0.774268 -2.223793 -1.332884 0.915040 -2.154555 -51.131519 -17.436516 44.468510 -67.748176 6.405570 0.751090 0.317592 2.265651 1.300880 2.143154 1.237670 1.763983 0.521355 2.413520 0.280147 0.685198 2.115983 1.330722 1.941939 1.162330
+1 0.052581 1 1 -1.706418 -0.171517 1.303104 -1.912267 -0.980136 1.373165 2.210869 0.888092 2.020634 -1.386043 -1.889682 1.615560 -1.979025 38.525647 -49.448113 -74.434271 -16.798380 0.919413 1.067166 0.364831 1.959996 0.905555 2.159183 0.646203 1.485113 0.297443 1.129045 0.857224 2.106741 1.252055 0.532858 2.251998
+1 0.029338 1 1 0.264955 -0.115915 -1.968916 -1.184969 -1.217011 2.178960 1.807947 0.677851 -1.909601 1.416882 1.838655 -1.571240 12.530934 7.413047 -58.916973 -67.566594 58.248173 0.280759 1.960330 2.019392 2.418658 1.143702 1.942779 1.788113 1.060740 0.354584 0.740705 1.285544 0.894058 2.429302 2.278406 1.916977
+1 0.017809 1 1 -1.816279 0.651265 -1.073399 -1.597886 0.239584 2.302083 -2.311990 0.738943 2.266990 1.639660 -0.287423 -0.526495 34.011122 -25.071655 -29.301353 -17.841221 -7.405534 1.902849 1.190527 1.445526 0.951594 1.936249 2.278608 0.810612 1.711319 1.887231 1.945752 2.252793 1.188994 0.422051 0.666499 0.596817
+1 -0.017084 1 1 1.683963 -0.246768 -0.529979 -0.939009 -0.135515 -1.514772 2.262429 0.377548 -2.144727 -1.364697 -1.264212 0.543379 -1.255565 47.722804 27.159753 23.969852 -38.692083 0.657455 1.591382 2.114659 1.575785 0.975064 0.396723 2.470998 1.072138 0.668042 1.773616 0.407156 2.318605 0.286251 2.025627 1.463336
+1 0.020903 1 1 1.808611 -2.295431 1.012121 -1.002299 1.148683 -0.744066 1.169616 -2.347745 -1.715871 1.182335 -0.647410 -0.112962 17.308214 49.144490 71.441550 -31.861451 4.585351 0.864959 1.620235 1.031607 1.218018 2.234942 0.414367 2.021533 2.407535 0.935806 2.090329 2.152539 1.468038 1.318725 0.553725 1.955117
+1 -0.062271 1 1 0.187265 -0.515050 0.217430 2.250647 0.271555 -2.277396 -2.165388 0.102886 -0.247818 0.666315 2.116874 -0.234949 6.151413 36.796738 -7.225944 53.558403 6.072749 2.345411 0.818146 2.322760 0.374118 0.547802 1.401240 1.396755 0.262037 2.312317 0.352866 1.121898 2.239470 2.271895 0.492331 0.613220
+1 -0.076570 1 1 -1.381131 0.562128 -0.656252 2.073426 -0.041872 -1.594374 -2.005843 0.225699 -0.157457 1.984426 -2.045999 -0.795381 34.266834 72.680412 -60.318664 74.215122 -66.451434 2.136215 1.614822 2.319006 0.285186 2.118205 0.428739 0.566523 1.052441 0.382045 1.029065 1.251814 0.993208 1.588808 1.595910 1.700440
+1 -0.060686 1 1 2.003939 0.755561 -1.170388 -1.193841 0.460826 -2.056697 -1.527267 -0.399397 -2.225954 0.039910 1.601057 1.214967 37.385024 -19.905997 -60.087981 51.303754 62.187454 1.143080 0.500147 1.462962 1.507697 1.872697 0.675841 2.365997 0.315417 1.714245 1.565831 2.418565 1.821699 0.795537 0.341998 0.709904
+1 -0.042982 1 1 -1.049347 2.098563 -1.679317 -1.779353 -0.762058 0.361216 1.407197 -0.726347 2.082432 0.521395 -1.952193 1.861911 -58.438439 25.150121 -1.915903 49.409175 20.002274 1.798335 1.859150 2.484077 0.379518 1.309638 0.843847 2.286865 2.339819 1.338961 0.912172 0.875403 1.643300 1.691393 2.241322 1.901970
+1 -0.026105 1 1 -1.249081 0.382685 -0.627854 -1.304466 -2.126092 0.810755 -1.876924 -0.728212 -0.981706 -1.461949 -0.585510 -1.195242 15.100395 -7.664763 28.333938 -41.503135 -43.187310 1.388313 2.379380 2.486124 1.043574 2.100897 2.027366 1.436408 0.706797 0.640368 2.419278 0.306363 0.293970 1.250574 0.391946 0.937312
+1 0.026327 1 1 -0.147813 -0.858461 1.182261 -1.889927 2.205145 -1.074032 1.907035 -2.129771 0.247885 0.459216 -0.843499 -1.823315 6.557493 -38.214036 36.693198 52.581242 -67.058341 2.131944 1.836901 2.039142 1.360778 0.853172 1.510015 0.323146 1.116588 0.745716 2.246939 1.805469 0.266190 2.361284 2.099349 0.762450
+1 0.033613 1 1 1.240946 -0.455565 0.945062 -1.807102 -0.615541 -1.708217 -2.126130 0.181271 -2.286751 0.819152 -2.114808 1.972401 -47.946193 -31.672181 35.652269 -42.322986 -22.418250 1.622171 2.080254 1.576126 2.206619 1.398954 1.217049 1.701100 1.143921 1.125172 1.014350 1.426491 0.536805 1.086347 0.991263 0.403477
+1 0.026078 1 1 -1.055613 0.455472 2.194984 -2.200888 1.926994 -1.265651 -0.068112 0.351272 -0.791019 -1.005170 0.024062 -0.851949 71.335750 -10.056375 32.507610 55.404768 -12.064778 1.784058 0.418441 0.731135 2.434644 2.059544 2.253965 0.641546 1.963346 0.951899 0.311303 2.325715 0.550022 0.477633 1.082431 0.414643
+1 -0.065382 1 1 -0.950695 1.375130 2.251616 -2.290770 -0.753473 -1.432273 -1.332934 0.077733 1.132788 0.713896 0.705970 -0.556694 -72.309257 -1.682718 68.555933 69.560865 9.454270 2.093633 1.445890 0.323601 2.010077 1.107479 0.650669 2.295097 1.198374 0.573565 2.412256 1.527763 1.610331 1.075445 2.256561 1.516638
+1 -0.027517 1 1 0.290991 -0.767774 -1.450507 -1.481528 0.219335 1.275878 2.309324 1.580965 -1.888266 1.857136 -1.979775 0.101163 -29.416287 0.460971 -52.467910 21.830308 1.993099 2.095237 1.397781 1.753456 1.342871 1.388313 2.370012 0.285392 1.084003 2.096689 1.054983 0.342262 0.644392 0.289302 1.551480 1.978967
+1 -0.011661 1 1 1.782947 -0.086541 1.625365 -0.214119 1.571732 -1.558861 1.097269 2.221898 -2.245743 2.039517 0.249687 -2.248807 -74.468934 0.619215 57.138589 28.262074 -49.324789 2.099115 1.333121 1.769789 1.346101 1.671470 0.392465 0.663370 2.002165 0.894441 2.113170 1.304247 2.478925 1.538733 1.483916 0.426793
+1 0.020671 1 1 2.001289 -1.364997 -1.601666 -2.041677 1.150288 -2.044523 0.436447 -1.832510 1.187837 2.297116 -0.968897 1.759354 -24.857729 -33.849315 44.568662 -34.496895 -39.309101 0.354004 2.252605 0.274967 1.371021 1.996954 1.053446 1.508123 2.277016 1.064117 0.859175 1.160512 0.978981 0.976829 0.813585 2.175330
+1 0.026110 1 1 0.635105 0.651033 -0.258030 -1.316953 0.068195 1.047694 -1.605797 -0.780441 -2.301069 0.507236 0.397180 -2.057312 71.958427 -44.714839 -22.295898 -27.150054 -10.955581 2.418260 1.191273 0.480622 1.818436 2.194937 0.803753 1.173646 1.223142 0.599747 1.440659 2.411905 2.381085 1.890961 1.629405 2.162452
+1 -0.071583 1 1 2.014301 0.554478 -1.999913 0.927817 0.525447 0.176891 -0.506964 -0.542275 -0.260496 -0.340364 0.338284 -2.306464 -19.848593 4.689689 69.600190 70.388806 -25.343755 2.087557 0.564289 1.760616 2.421444 0.706558 1.120299 2.363634 1.093380 2.193156 2.379706 1.223174 1.140881 1.792176 1.852895 0.847831
+1 0.030358 1 1 1.533119 -0.204658 0.353307 0.423499 2.044076 1.467468 -0.902427 2.091430 0.950416 -1.355982 -0.883573 -1.477589 14.400624 -68.713775 -22.415947 55.186907 -73.659811 0.618276 2.365919 1.250722 0.634864 2.155894 1.608117 2.116049 2.429280 1.907994 2.147887 2.032151 0.870214 2.182085 0.806169 1.279055
+1 -0.019625 1 1 -0.137241 -2.254602 -0.783633 0.606732 -0.260403 1.213428 -1.136625 0.767070 -0.953156 -2.285618 1.010908 2.162703 60.234494 11.140460 37.708519 17.086424 71.526206 1.989129 2.297086 0.875674 1.698957 1.121147 0.860023 1.901248 1.283681 1.081410 1.255231 2.166249 2.401100 0.789914 0.340978 1.569985
+1 0.001815 1 1 -0.537936 1.983835 2.160508 -2.018005 -1.542952 -0.122221 0.439328 -0.530713 0.859986 0.886210 -1.326712 0.972253 -60.637951 -42.041791 53.617396 -52.428009 -57.539458 1.139939 1.711705 1.619208 1.784377 1.270656 0.412544 0.618531 2.145937 0.768231 0.400821 1.591514 2.076391 1.904715 1.039116 1.424004
+1 0.012581 1 1 0.133983 -0.665153 -1.435893 -0.912632 0.219579 0.671984 -1.563970 0.060216 -1.105792 0.620042 1.952232 -1.203218 -51.827125 -8.491960 -74.380674 -15.980148 71.657899 1.439568 2.069497 0.791992 1.504505 2.221345 1.403064 0.555569 1.440443 1.016844 0.590097 1.262596 2.208313 0.616533 2.313992 1.521914
+1 -0.029973 1 1 -1.163508 1.329437 -2.299180 -0.719614 2.148521 -0.849092 -1.579224 -1.837375 -0.481655 0.702706 1.137099 -2.235237 -14.759332 39.903442 7.145945 -48.101249 62.306513 1.908572 0.621020 1.226709 2.048072 0.696056 2.363788 1.428465 2.216500 0.967851 0.675674 1.806851 0.996737 2.401331 2.418704 1.909355
+1 0.033897 1 1 -0.896904 0.672460 1.731922 -0.016220 0.704030 -0.176372 -0.191130 1.524124 -0.587135 -0.239658 1.161113 0.820886 -39.701491 -62.953297 43.943247 -45.841047 -50.470520 1.254477 0.741810 1.852594 0.295168 1.144222 1.685865 1.577572 1.756633 0.729097 1.936978 1.044546 0.428498 1.008470 1.611027 1.527532
+1 -0.032930 1 1 1.288071 -0.098940 0.589802 -2.069443 1.007548 2.243657 0.613929 -1.834310 -0.794253 1.195772 -0.994500 0.286602 27.377871 -60.129046 -38.882229 56.380026 29.088941 2.092450 1.799600 0.630130 1.342728 1.238302 1.136513 0.374104 0.310498 2.293966 2.437781 0.781387 1.026911 1.041378 1.182090 1.382390
+1 -0.012984 1 1 -0.757546 0.792513 -2.163010 -2.343738 -0.351549 0.851215 -0.446878 0.866829 -1.910882 -1.261347 1.584870 -2.222604 -6.542341 -7.124517 -41.758586 13.437130 -62.164015 0.765977 0.779120 1.161796 2.306257 2.014126 1.670061 1.463092 1.444248 1.978793 1.829770 1.436479 1.908123 2.079119 0.508320 1.590325
+1 0.062597 1 1 0.119476 0.553679 -1.289089 1.843800 0.077187 1.374186 0.521699 -1.559897 -2.165971 -0.268345 -0.318430 1.416344 70.556126 -63.198189 -21.958434 -55.393556 50.497532 1.555245 2.254769 0.649347 0.319956 1.495859 0.897420 0.431235 2.013798 0.653797 0.868107 0.517203 2.376985 0.481441 2.073700 1.677755
+1 0.062424 1 1 -1.915929 -1.269053 -0.707663 0.381843 -0.645391 0.837784 0.019779 -2.145711 0.941638 1.906406 1.428775 -0.915362 46.750934 42.954610 -11.874138 -68.642436 -23.417741 1.645343 2.283691 0.745486 0.629190 1.304026 1.021791 0.488663 1.960840 1.586842 2.302845 0.922757 1.020357 1.138427 1.047161 1.637269
+1 -0.008525 1 1 -1.557100 -2.283573 -2.308275 1.916026 -1.811208 1.052970 2.247333 1.130475 -0.454552 -0.868802 1.733123 1.316446 26.788804 -60.566771 -45.722552 -8.931510 38.109419 1.450015 2.159830 0.269067 1.205553 1.986257 1.275983 2.202663 2.400679 0.467338 1.299131 1.996595 1.769696 2.035932 1.409363 0.671598
+1 -0.027348 1 1 2.080617 -1.708829 1.723701 -1.521776 2.355229 0.272996 -1.627549 1.210506 1.589864 1.592397 1.762510 0.422279 12.309367 33.529115 -26.160954 -37.153253 15.284854 0.513066 0.356879 1.057887 1.906383 2.086642 0.940551 0.842055 1.412283 2.496602 1.631529 1.862271 0.942714 1.187995 1.635781 1.314667
+1 -0.013443 1 1 -0.207051 -2.156683 0.323499 -1.055171 -1.534929 -1.931852 -0.270517 0.872799 -0.539080 1.604134 1.103592 0.113274 -0.361192 -70.547382 60.148055 58.353057 39.824421 1.810630 1.507377 0.981566 1.672781 2.184646 1.091243 2.264892 2.032002 0.611043 2.292402 0.900748 2.368172 0.871842 0.297901 2.072333
+1 -0.002427 1 1 -1.882715 0.897666 -2.002662 1.849533 2.180823 0.123516 -2.232951 0.263563 0.064279 1.202865 0.407040 -1.267136 -46.617730 -54.193508 -30.291472 -8.764515 -5.205081 0.898014 1.418842 2.481946 0.563407 0.431323 1.244884 1.509439 1.886095 0.844118 2.347294 0.974739 1.688006 1.573369 0.861026 0.770653
+1 0.030224 1 1 0.007077 1.140146 1.867110 0.725590 -0.675001 -2.028794 0.906993 -0.741467 -2.283346 1.496174 0.881826 0.389529 41.670863 12.191124 -3.786004 -31.360991 15.825446 1.799179 0.306338 2.129640 1.357185 1.207288 1.884666 1.575308 1.952763 0.842938 0.508464 1.748824 2.236032 0.748798 2.290736 2.143266
+1 -0.025480 1 1 1.470413 1.457556 2.151019 -1.271471 1.064557 -0.928115 -0.825209 -0.727988 -1.938255 0.487713 2.143889 1.412993 -72.326154 14.333951 10.721153 40.422623 33.024868 2.109312 1.706777 2.047560 1.083966 1.470942 0.615554 1.613232 0.346406 0.550794 2.193436 0.335483 1.462127 0.964168 1.774298 0.625268
+1 -0.057752 1 1 0.497954 -0.092504 0.374348 0.625545 0.203068 1.190786 0.020464 -0.067596 -0.399709 1.957089 0.324172 0.837544 22.376148 25.927357 11.096593 50.443404 2.291310 0.775616 0.777391 1.363550 2.427545 2.000939 0.532191 2.277071 1.984222 0.816354 1.461315 0.817078 2.373903 0.445586 2.463874 0.579727
+1 0.030719 1 1 1.548393 2.020842 2.097025 0.750434 2.191572 1.714911 1.543336 1.860743 2.094051 -2.117104 1.080929 0.918777 -19.389585 69.238915 -1.558518 55.982445 -53.045176 2.421020 0.340152 1.183954 1.211538 1.314187 0.786111 1.661747 1.224036 2.127655 1.750323 0.421989 1.873674 1.344236 1.816982 0.267379
+1 0.024863 1 1 1.737045 1.264467 -0.969876 -0.550441 -0.844767 0.434085 0.886369 1.347890 1.539607 0.441610 0.128594 -1.708211 -64.399132 43.795723 24.719388 -41.250336 5.602600 0.818361 1.440086 1.778069 0.999805 2.230927 0.448777 2.095820 2.204558 0.508125 0.552611 1.225568 0.877480 0.561106 2.261039 0.278108
+1 -0.007846 1 1 2.194372 1.650344 0.216576 2.023885 1.405957 1.993797 -0.042834 1.090506 1.654192 -1.089464 1.723157 -1.236748 10.231971 68.729365 -15.565428 -8.154551 46.461313 1.004236 2.449625 1.854045 2.180446 0.262798 1.597976 0.434880 0.273878 1.063251 2.061227 1.287245 2.470885 1.412230 1.593912 1.878814
+1 0.002932 1 1 0.790400 0.021864 -0.100009 1.479799 -0.999034 -0.515974 -1.181738 1.242102 0.124472 -0.291707 -1.826711 -0.321017 11.027792 -55.895610 12.477166 3.731538 15.952841 2.415993 1.336795 0.505356 1.268105 0.288137 2.221947 0.264395 1.438840 1.086788 1.650670 1.818651 1.311348 0.317782 0.969827 2.390764
+1 -0.051057 1 1 1.618046 -0.697613 -0.357843 -1.265981 -0.899807 -0.998661 1.025826 -1.582114 1.427427 -0.007138 -2.164476 1.287703 -50.429037 -60.828643 52.990734 65.263344 -68.973976 0.690763 1.159284 0.592852 0.318938 2.391722 0.671207 0.968745 2.197649 1.377987 2.069086 0.622458 0.651221 0.321129 0.967939 2.158380
+1 0.004762 1 1 0.513614 -0.786693 1.018244 -1.769706 1.146575 1.523532 -1.114040 -1.351725 -0.021244 1.098694 -2.104785 0.783137 15.454197 -61.313056 11.468063 -6.263439 30.376043 0.327264 0.582634 1.827547 2.330785 2.494969 1.190187 2.473567 1.497575 0.501224 1.569369 1.140558 0.858465 0.468498 0.545724 2.489457
+1 -0.011207 1 1 -0.442974 0.506268 -1.727473 -0.614616 -0.300565 0.077907 -0.664904 -1.965583 -1.703884 0.008443 0.531138 1.570533 58.958847 21.346980 -21.302740 14.843821 30.103605 1.394341 2.440509 1.633743 0.814959 0.509226 1.053977 1.445792 0.924734 0.497333 1.422594 0.282225 1.860752 2.408039 0.416777 2.014841
+1 0.030899 1 1 1.201717 -0.039858 -0.730557 2.019680 1.428732 -1.640993 1.440536 -1.170322 -0.096635 1.635141 -0.839320 -2.274536 -38.916254 -65.485341 -62.129782 -65.237765 48.884657 2.191497 1.496722 1.907086 0.387412 1.228460 2.231276 1.806838 0.774859 1.555037 1.007820 1.928115 0.583413 1.413851 1.838276 0.408697
+1 0.012844 1 1 1.141104 -0.893560 0.316374 1.729019 -1.675835 0.185439 1.786657 0.998045 -1.966387 -1.074825 -1.993845 -0.751212 -35.998694 69.957403 74.077667 23.356975 10.674670 1.512700 0.440013 1.042342 1.636707 1.128691 1.668160 1.011596 2.386491 0.504298 1.485586 1.497986 0.645735 0.363461 1.431658 1.874456
+1 0.041895 1 1 1.214874 -0.398006 2.311994 -0.681925 -0.582686 -0.858213 0.631918 -1.084440 1.339078 -0.480093 -1.318552 1.466424 12.688103 -51.058193 14.954850 -53.837954 -54.500486 2.280049 0.283515 1.032520 0.816822 0.324110 1.564971 1.472169 0.999886 1.333201 0.856848 0.294712 2.473615 2.295666 1.751401 0.544298
+1 0.002442 1 1 0.555725 0.114812 2.284937 1.677655 2.117404 -0.760035 1.381335 -1.837807 1.680020 -0.535569 -0.646640 -1.316699 -12.229211 -36.356609 54.478508 20.275989 -21.451541 2.334341 1.525231 1.803121 1.306762 1.992023 1.433107 1.478248 1.917691 0.889994 1.625701 0.661143 0.585225 0.382325 1.234789 0.602887
+1 -0.024319 1 1 0.973148 -1.003794 -0.421638 0.968872 -2.191155 0.571587 -1.891789 -0.814626 -1.926596 -1.470703 -1.623846 2.176410 42.987600 -57.398573 -47.812078 -27.595658 -0.215724 0.989876 1.846031 2.498632 2.001263 1.477700 1.704683 0.611352 0.741645 1.327434 0.679333 0.297419 0.726936 1.610091 1.549794 0.631589
+1 -0.038344 1 1 1.840369 -1.037906 1.177429 1.727500 1.061539 0.182363 1.926246 0.298745 2.311392 -1.371327 0.399929 1.743245 57.085281 32.318104 20.379273 64.442248 -69.134193 0.799326 1.013869 2.350112 1.089789 0.329938 0.510200 1.683050 1.518045 0.276655 0.495323 1.393653 2.131128 1.615833 1.310690 0.510690
+1 0.013745 1 1 -1.867609 0.324385 -0.297250 -0.750328 -0.416937 -0.134895 -0.521250 -0.319566 1.176016 1.542795 2.184016 1.967308 -72.942008 13.676117 54.503217 -14.433770 -38.376189 1.545812 1.210497 1.822328 2.362104 2.383793 2.401026 1.796520 0.603731 0.913435 1.850405 1.750331 0.557810 0.863334 1.307898 0.846034
+1 -0.015115 1 1 0.341360 2.265968 -1.410445 -2.038398 -0.280766 -1.726564 0.528304 1.063519 0.480502 -1.242138 -0.733929 1.884734 1.453633 -18.796205 -7.817528 10.812500 -74.319608 0.780273 0.296218 0.783770 0.576587 1.444660 2.151620 1.777578 1.757635 1.820291 1.888123 1.185026 1.226165 1.903406 1.538265 0.364306
+1 0.008697 1 1 -0.090149 2.263190 -0.968218 -0.961627 1.433976 1.682232 -1.054349 -1.855627 -0.931198 -0.797259 -2.204289 1.315473 -44.005981 41.474145 5.959431 -39.850171 -11.830042 2.462345 1.887977 0.986466 0.780882 1.533402 1.893329 0.923218 2.016596 0.426927 1.604265 0.379817 1.827382 1.810573 0.543900 1.074850
+1 0.008164 1 1 0.440858 1.617716 -1.537053 0.069097 2.072411 1.744037 0.964913 1.958149 -0.706821 0.384627 -0.973914 2.263296 25.728919 -24.051969 8.559605 11.277813 -53.802125 0.590357 1.137652 1.522067 0.386818 0.252827 0.515944 1.473371 0.946344 1.461229 1.632921 0.501724 0.976011 0.567812 2.464965 0.911815
+1 -0.003234 1 1 0.688703 1.411509 1.056935 -1.796750 -0.996714 0.765550 1.782522 2.184597 2.291626 1.002032 -0.932850 -0.286384 -60.703140 62.320906 -22.535020 3.921676 61.609676 1.732358 2.246911 1.329559 0.400600 2.385049 1.022802 1.735894 0.913751 0.419532 1.072855 1.481296 1.391632 1.915476 1.900609 1.778501
+1 -0.003783 1 1 -0.744976 0.005748 2.350830 1.727678 -0.659182 -0.049671 -0.727204 1.819674 -0.139064 0.100434 0.956620 -0.757911 -19.931882 -45.135891 -48.917765 -10.879796 -6.737103 1.667577 2.470632 1.653924 2.495112 1.350922 1.696720 1.777057 1.990072 2.396399 0.536585 1.882225 1.050357 1.349549 1.121788 0.385736
+1 -0.003144 1 1 -2.085048 -2.077639 -0.082729 -0.273277 1.609594 -1.383485 -1.300639 0.924393 -0.470705 0.966752 -0.115633 -1.942037 -57.390937 -69.471753 -11.753681 5.880025 -24.419093 1.199596 0.867667 2.133065 0.414445 1.076878 1.582143 2.086284 1.678532 2.084532 1.482808 2.046174 0.292122 1.694054 1.956414 1.453831
+1 0.055283 1 1 1.144872 1.173902 -1.003751 0.311481 -0.406426 2.156469 0.794589 -0.255906 1.403523 -1.206160 0.757512 -1.369588 43.085091 -68.867948 -63.601978 -58.439575 6.066302 0.720122 1.845873 2.087809 0.303859 0.957951 0.780194 1.223634 2.114299 2.266485 1.814879 0.916594 0.950461 0.902657 0.712639 2.079029
+1 -0.003120 1 1 -0.789947 -1.836048 -1.729293 1.780546 1.972722 -0.822140 -0.977224 -1.530389 -1.031541 -0.230790 -0.589638 0.107558 -58.296624 8.639965 11.888835 15.642650 -43.988460 1.914184 0.438762 0.264705 2.149617 1.867290 2.035175 2.179860 1.656098 0.796642 0.907692 2.072093 1.666767 2.349603 1.524364 0.731153
+1 0.036178 1 1 1.479596 0.298848 -0.664423 1.400936 -2.275761 1.743771 1.219139 0.601779 1.313158 2.137886 -0.519915 -1.442731 62.747718 -49.098225 -43.871025 59.688614 -13.471171 0.475482 0.932817 1.349446 1.641319 2.144244 1.556463 2.470685 0.307652 1.709469 2.297588 0.309416 2.108687 2.449976 0.994084 0.572887
+1 0.024956 1 1 -0.894359 1.021593 -2.037905 -1.426704 -1.985776 -1.805744 -1.347511 0.129985 -1.886081 0.869342 -2.086307 0.331710 9.376243 -63.490847 9.330493 67.590678 46.528123 2.097403 1.798293 1.157066 1.557947 0.415077 0.452929 2.126897 0.255657 0.834910 0.582372 1.929845 0.412440 1.130683 1.397196 0.917536
+1 -0.030987 1 1 0.134579 -0.080529 -0.999401 -1.981246 -1.059816 0.496208 -1.162234 -0.812747 1.374945 -0.859878 0.927629 2.080500 32.854850 41.458670 45.867266 41.144024 7.618515 0.540783 0.432265 1.333755 1.166056 1.902961 0.819390 0.742134 0.548984 1.020782 1.526951 1.459296 0.630005 1.501797 1.695132 2.090609
+1 -0.012957 1 1 -0.073876 -2.275003 0.355998 -1.469180 0.410621 -2.349523 1.379513 0.517192 -1.911973 -0.748530 1.538635 -1.746330 -57.810954 71.290311 -23.748400 10.640162 29.208436 0.717771 0.573139 1.992264 0.985067 2.017495 2.033461 0.375432 2.389869 1.033859 0.826706 2.200202 1.551752 2.041615 2.417866 1.322331
+1 0.027323 1 1 -1.276091 -1.185041 2.283804 1.482100 -0.031956 0.133647 -1.610441 1.283851 -0.341707 1.327756 -2.274616 2.135163 27.070884 30.347585 51.860403 -32.209865 -1.203915 1.612027 0.329722 1.384192 0.620807 2.160837 1.439309 2.221243 1.929393 1.804646 2.179888 2.120439 1.966497 2.160359 2.399083 0.630154
+1 -0.034663 1 1 -2.178101 -1.507312 0.403464 -0.111613 -0.352852 -2.200581 -2.332356 -2.264706 -0.941739 1.112449 -1.823172 -2.104290 -10.062103 -63.770819 -46.157412 32.382643 55.077660 1.978423 2.349359 1.932748 1.939934 1.226085 0.565537 2.475493 2.357010 2.268881 1.587876 1.684893 0.990058 0.400035 1.891436 0.621189
+1 -0.015002 1 1 0.847443 2.130557 -1.178409 0.648282 0.627764 -0.216723 0.205277 0.616537 -0.400768 -1.710328 0.083528 -0.433564 -49.479436 -0.887522 -66.578291 18.661541 -5.486285 2.005049 2.109950 1.184839 0.338728 2.002010 0.537802 2.084758 0.779045 2.153962 0.631791 2.265756 0.817483 2.444614 0.871219 1.085687
+1 -0.059810 1 1 -1.556277 2.132570 -0.320124 1.230612 0.224822 -0.746094 0.061536 2.227921 0.030821 -0.349227 2.170616 -1.774151 58.592444 13.210200 23.823976 59.563133 -22.422155 0.637545 2.225550 2.315048 1.256835 2.118774 0.985517 0.576740 1.772472 1.443474 2.469478 0.259500 2.412306 2.374860 0.767252 1.962000
+1 -0.007451 1 1 -0.422943 -2.127255 0.124832 1.032791 -2.324387 -0.260846 -1.512617 0.779362 -1.712697 -2.026673 -1.147949 -1.064297 18.657713 -69.817867 21.115404 -13.410958 52.035708 2.337081 0.326994 0.542473 1.842614 1.310622 1.622951 1.688516 1.145767 0.659980 1.281173 1.671907 0.993674 0.430666 1.447335 2.115567
+1 -0.022202 1 1 -2.130534 1.550943 -2.235424 1.112802 -0.608027 2.065459 -1.998487 1.332259 -2.000654 -2.095740 2.002516 0.397479 -55.396339 3.722453 13.271725 7.882623 33.244660 1.269889 1.023764 2.144621 1.138232 2.270311 0.870369 0.290362 1.358863 2.414671 1.626304 1.791580 0.835122 1.900163 1.048251 1.949458
+1 -0.062123 1 1 -1.821848 1.303702 -1.295963 -0.586244 0.610723 0.839409 -0.950889 -1.885031 -0.320682 1.273370 -2.146981 -1.552371 57.292321 62.033403 -54.598794 58.066001 15.283353 2.384624 0.630017 1.701434 2.243917 0.510069 1.723836 0.761399 0.328615 0.788721 0.540219 2.215190 1.443896 0.566425 1.660019 1.440670
+1 -0.002932 1 1 1.106837 -1.910197 0.817949 1.229398 -1.326658 1.879228 1.757877 -2.046097 2.268985 2.178926 1.228585 -0.863637 -31.385443 54.862405 22.446332 5.507167 8.949517 0.843062 0.339957 2.407421 1.271918 1.379234 0.532431 1.809502 0.553802 1.007943 1.750012 1.943797 0.888710 0.298988 2.344567 2.382333
+1 -0.000021 1 1 1.712590 0.224931 1.074605 -1.700957 2.076846 0.884059 0.217246 -0.854024 0.353816 -0.447234 -0.406515 0.673968 -38.377951 -18.216173 -9.227411 14.910380 -51.249566 0.603084 1.289972 1.067324 0.757710 1.324136 1.511202 2.263583 0.281838 2.093785 1.746848 0.526419 2.031214 0.866079 2.435100 0.728126
+1 -0.025756 1 1 1.602281 -1.760135 1.788349 1.163639 0.875340 -0.243093 -0.026045 0.507083 -2.175226 -0.309889 -1.111629 1.478981 -19.602237 -54.793134 -58.196033 49.280121 -49.000050 0.717325 2.074029 0.456732 0.799419 0.340838 1.458081 0.467480 1.444282 0.295127 0.450080 1.487705 1.113632 0.565145 0.387701 1.594605
+1 0.015937 1 1 -0.810395 -1.498723 -1.321981 0.386700 0.883917 -2.163010 -2.349307 0.297790 0.396923 -1.654051 -1.243628 -2.206995 -55.710468 -25.837854 -6.811289 -27.336434 6.553428 2.026909 0.506081 2.196665 0.602387 0.813479 0.388793 1.940798 2.248659 1.460411 1.372233 2.113219 2.123979 0.713970 1.951278 0.634071
+1 -0.033431 1 1 -2.064389 1.131835 -1.161331 0.216875 2.342788 -1.491887 0.476662 0.197484 1.592506 -1.115755 -1.906856 0.425720 52.985718 -19.038392 -28.258960 -48.343802 35.722946 0.558386 1.535805 1.775469 2.301740 0.350213 1.529719 0.738571 1.417310 1.474073 1.498893 2.391101 1.483452 1.624521 1.075623 0.749795
+1 0.026623 1 1 0.170083 -1.833974 0.142848 2.239394 -0.360851 0.025104 -2.198422 0.967076 0.608775 1.088214 0.829216 2.101973 -29.408214 -13.852092 -12.104204 -35.357998 38.127776 1.577889 0.321640 0.546977 1.034262 0.843549 1.784124 1.531033 0.327328 1.659444 0.782973 0.678052 1.269995 0.552464 1.020616 0.998709
+1 -0.014145 1 1 -0.097703 -2.183525 1.575612 -2.308295 1.589630 -2.326862 0.548266 1.994431 1.177358 0.540709 2.218503 1.955810 -74.074971 21.969443 -59.574639 -20.956472 -15.428474 2.029490 1.145208 0.254731 1.006956 0.915420 1.472112 2.279929 0.513196 0.289044 1.719937 0.482430 0.698388 1.050413 2.285045 0.998027
+1 0.004480 1 1 -1.729458 -0.986590 1.271959 -2.291081 -1.263493 -1.497665 2.319952 1.133400 1.574094 0.437267 -2.176811 1.320542 -31.758148 -59.200370 -30.620575 9.993230 -43.786761 1.013645 0.828387 1.208353 1.796137 0.930710 1.948968 2.307434 1.538225 1.946930 1.803446 2.273578 1.781264 0.695727 1.328523 0.992614
+1 0.054173 1 1 -0.760085 0.540156 2.337972 -2.307550 -0.027616 -2.320250 -1.416233 -0.354064 0.995069 -0.137763 -1.604085 -0.275174 -63.336028 61.373263 -49.563128 -57.495042 -19.166561 2.389015 2.422728 2.043326 1.930049 1.580464 0.859090 1.981867 1.742288 0.392302 2.421879 1.261895 1.661734 1.017109 0.551421 1.484505
+1 0.067371 1 1 -0.058071 -0.529926 -0.047340 0.755616 -0.243018 1.245682 -0.972557 1.513255 0.509355 -1.677679 2.188964 0.291107 37.181924 16.603876 61.345796 -61.204649 33.456218 0.604925 0.716642 1.843643 0.615487 0.497470 1.477409 1.305838 2.216704 2.140665 2.155207 1.321980 1.265370 1.572818 0.600350 0.328228
+1 -0.051338 1 1 -0.064388 1.679641 -2.192548 0.731497 -0.349474 -1.969597 1.521886 -0.505394 2.275652 1.138145 1.214805 -1.560049 -0.301278 36.419896 -40.800966 58.164765 25.208140 2.473241 0.507990 0.535673 2.311966 1.212387 2.080456 0.482845 0.928691 1.761737 1.021687 0.986764 1.286000 1.796791 0.670077 2.240923
+1 -0.022352 1 1 1.345797 -0.659226 -0.779360 1.746148 -1.249503 -1.990373 1.043891 0.450031 0.289503 -2.220960 -0.849622 -1.060592 50.829733 45.324692 72.099224 71.661083 57.827508 2.228881 2.047153 1.002338 2.050094 0.924316 2.486389 0.990828 2.100747 1.756749 0.422710 0.478592 1.453667 0.540235 2.473360 0.263798
+1 -0.021858 1 1 -0.088187 2.243489 -2.217049 -1.083239 -2.040829 1.270575 -1.998916 -1.160773 0.178027 -0.266378 -0.241872 1.645446 -63.831277 -12.278020 43.311541 -12.938622 40.582666 1.717911 2.426389 0.570363 0.343456 0.471124 1.935132 1.516236 1.370923 0.354373 1.698430 1.263213 1.319291 1.075055 2.447807 0.542312
+1 -0.007708 1 1 -1.632611 0.952157 -0.376611 -0.957424 1.387229 -1.749498 1.498634 -0.172470 -0.587982 -0.333796 2.342102 1.118303 73.742675 -56.868503 11.071228 74.136766 -33.374632 2.463373 1.153239 2.496892 2.017943 0.559143 0.764639 0.794487 0.692377 1.280049 0.779332 2.475572 1.445777 0.675614 0.800883 2.438484
+1 -0.033306 1 1 -0.425196 -2.291177 1.823924 0.599604 -2.253402 0.545235 -1.839940 -1.173190 -1.167372 -2.352412 -0.053543 0.171228 -45.850706 -62.809767 56.240782 -61.168822 35.613156 2.129687 2.151947 0.521020 1.288431 2.152217 0.566147 1.484090 1.103957 2.201674 1.526573 1.861361 1.389078 1.736287 0.772392 0.598605
+1 0.008742 1 1 -0.775216 0.701661 -2.286315 -1.278904 -1.335121 1.019094 -1.616743 -0.963829 2.123773 -2.100503 2.056172 2.141974 70.419128 34.290236 16.000077 -36.699077 -1.394241 0.879752 0.493013 0.822528 1.720792 1.358459 2.363948 1.865297 2.296859 1.552987 0.309214 0.963291 0.530199 0.303300 0.570329 2.011961
+1 -0.021030 1 1 1.292865 0.352487 0.777427 -1.239508 1.053595 -1.388994 0.346586 0.554613 0.269294 2.139037 -0.019946 -0.646283 -0.749636 0.861301 -74.119866 17.410791 -26.843324 2.038873 1.337875 0.659062 1.599588 0.524669 1.866676 0.722922 1.642722 0.982119 1.967303 2.212236 1.293631 1.804388 2.341864 1.960614
+1 -0.001865 1 1 2.207640 -1.538123 0.925866 0.713362 1.161130 1.103172 -2.235775 -0.078002 -0.937460 2.331823 -1.992671 0.122176 -37.631223 -67.956868 -51.074948 33.349953 -37.338917 2.047280 0.890234 1.168645 0.418858 0.993664 0.252811 0.251100 0.734620 0.262241 1.240765 2.039607 2.422859 1.986198 0.285793 1.074591
+1 -0.013824 1 1 1.467803 0.003288 -1.288269 1.489208 1.628119 -1.043595 -0.196703 2.117921 -1.493387 -1.171698 0.336673 -1.112592 -18.142239 33.382063 52.340115 -69.693218 16.082232 1.285975 1.378957 0.380644 2.233981 2.273831 1.523756 1.772425 0.655862 1.815514 0.351197 2.312292 2.194347 2.145317 1.591763 1.766972
+1 0.000745 1 1 0.231180 -2.278675 -0.113451 1.739777 0.051614 0.393978 0.688508 -1.871481 1.208913 -1.624091 -1.939867 1.668418 -73.900101 -38.995674 -50.300793 -5.433636 26.882712 1.641170 1.886957 1.834502 2.227246 1.566789 0.516223 1.656819 1.657987 1.042532 0.336216 0.289169 1.563334 0.960002 1.509968 1.787699
+1 0.007325 1 1 0.862886 -2.202965 0.003367 0.034391 -1.622400 -1.794631 1.640964 -1.933523 -0.081355 -0.734356 -0.581043 -1.515284 -51.715826 62.108513 7.784784 38.871259 59.246759 2.279123 0.471550 2.347270 0.560761 0.963818 0.390950 2.197636 1.164438 1.711883 2.364538 0.538384 0.617481 0.252321 1.010743 1.557867
+1 0.000153 1 1 -1.918571 1.452376 -0.084368 0.462829 -1.385840 1.528882 -0.737531 -2.095451 2.143505 -0.324608 1.266081 -2.131993 18.877899 30.845228 15.741964 -24.815252 -69.942390 1.798873 1.901858 0.283333 2.480665 1.531140 2.117845 1.124616 0.668585 1.905233 0.758570 2.285113 2.137914 0.918634 1.482183 0.554341
+1 -0.016869 1 1 -0.421173 -0.648626 -1.706560 2.150474 -1.006912 -0.985589 -0.742869 -2.282356 -0.714123 0.182386 2.313938 -0.996083 62.045926 5.877320 -69.889907 10.334208 -12.963872 2.368055 1.149280 1.198009 1.179124 1.035358 1.256236 1.049671 1.064381 0.798910 0.785432 1.510550 0.315016 1.729257 1.873591 2.191846
+1 -0.011409 1 1 -0.542814 0.109100 0.529383 0.353685 2.058903 0.903414 0.363049 -0.779405 0.987951 -1.974498 -0.737885 1.376529 69.994929 -45.227713 57.821612 -42.171719 -30.086372 1.200198 1.974525 2.092490 2.482349 0.592154 2.084221 0.749860 2.152003 1.466641 0.341683 2.165271 1.718337 0.585551 1.347645 0.617428
+1 0.005997 1 1 -2.293142 1.796381 -0.507319 -1.803891 1.518614 1.046518 2.190163 1.605369 -1.697801 -1.426508 1.311449 1.687718 51.159636 40.001693 8.448030 -63.951567 66.007620 1.226069 0.294511 1.354774 1.183604 2.079475 1.991636 1.683010 0.846759 1.734606 1.776726 0.939875 0.736449 1.743764 0.438107 0.506479
+1 -0.015883 1 1 0.261159 2.068996 0.902379 1.810354 -1.275786 -0.761655 -2.279616 -1.779195 1.885142 2.188773 1.799320 1.773665 -18.614171 51.624090 46.072481 40.183869 70.279821 0.519234 0.510647 2.451248 2.124242 0.633684 0.319652 0.888325 0.580535 0.303240 1.800466 1.691250 2.094094 2.430155 0.859284 0.741037
+1 -0.011542 1 1 -1.190052 -1.830154 -1.641943 -0.379960 -0.707149 -0.409597 0.703357 -2.069493 0.177322 2.021473 -1.419033 -0.293923 -43.774051 39.526099 -34.859251 20.576615 -68.830898 0.761558 0.757417 0.911309 2.124295 1.523694 0.731151 0.447762 0.794212 0.577095 0.979656 1.081484 0.250263 2.427778 1.418064 0.655538
+1 0.037294 1 1 -0.005451 -2.075963 -0.177587 -1.766288 2.041784 0.644484 -1.937812 -1.485428 0.654506 1.568163 -0.271527 -1.956538 -15.114720 66.901774 18.112524 67.196183 16.246442 2.184244 1.084666 1.975663 0.968002 0.959639 2.158247 0.659818 0.815832 1.682271 1.927250 1.799358 1.053041 1.468529 0.562744 0.540163
+1 -0.002212 1 1 0.174406 0.133381 -1.356104 1.787052 -1.776776 0.140251 0.998813 1.524599 -2.033875 0.338992 0.160635 -0.414290 61.702974 -58.119201 -9.406517 4.662189 57.411605 0.877730 0.260086 1.020520 1.628756 0.254070 1.162585 2.063847 0.324765 1.322969 2.139829 1.597996 0.762642 0.977792 1.247441 1.734764
+1 0.014331 1 1 0.126475 0.377933 -0.376294 -0.352731 -0.161362 2.320572 2.115341 2.277267 0.010179 1.434646 -1.204602 -1.315490 34.759909 -40.217058 -28.087072 -9.415683 0.615763 1.361914 1.934379 2.351887 1.657510 2.023789 2.066356 1.999253 1.446506 1.670703 1.002101 0.303057 0.984383 1.769869 0.447353 0.663859
+1 0.008075 1 1 0.766136 2.195428 0.547913 0.759407 2.196573 0.944763 -2.118186 1.745142 0.696395 -1.264559 -0.572114 -2.253064 48.111613 -38.119709 -27.943443 4.558260 -39.317792 0.413069 0.452463 1.043157 1.841802 1.171403 1.766687 0.958887 0.771298 2.460202 1.859480 1.284309 0.381389 1.252684 2.101891 0.728196
+1 -0.007324 1 1 0.700963 0.106647 1.703543 -1.035312 -2.342767 1.832666 1.451471 -1.172114 -1.935479 0.028483 -1.943723 -1.875939 53.511862 -26.143118 -37.387266 -17.776797 25.368740 2.461160 2.218373 0.941924 1.415279 1.095482 1.515572 1.472808 0.482808 0.309336 0.755797 0.683304 1.791274 2.435133 1.273663 1.450284
+1 0.009476 1 1 0.694494 -0.233178 1.680769 -2.086245 1.366072 0.807301 1.336405 1.714382 2.076019 1.128745 -1.251732 -1.753106 67.520779 71.740400 40.894940 21.264249 -61.758982 1.626834 1.701197 0.518522 2.055004 2.444934 1.750201 0.626331 0.493725 1.536219 1.980837 2.433672 1.478298 0.509136 1.793748 1.276312
+1 0.040319 1 1 -0.553004 -1.509599 -0.336317 -2.328630 -0.887359 0.871442 0.228406 -1.784962 -0.795569 -2.082398 0.046681 2.312930 29.050195 -3.364258 6.913558 -53.832045 44.824358 2.319742 1.407378 1.058871 0.451547 1.403835 2.248620 0.813145 1.519655 0.347356 0.767456 0.881943 1.314952 2.391415 2.265652 1.318877
+1 -0.011298 1 1 -1.160716 1.130771 -0.192482 -2.351664 -1.611484 -2.118208 1.370395 -1.921174 0.122397 -2.193131 0.348649 2.245226 -41.171512 -19.601658 -45.058695 48.504860 -28.820132 0.925511 2.305673 1.195568 0.668137 1.128442 1.973881 0.273441 0.465740 1.445536 1.115590 1.961946 2.171430 1.730139 0.949203 2.262761
+1 0.020603 1 1 -0.490797 -2.139579 0.335290 -0.802872 -2.295703 1.160536 0.553991 -0.750487 1.634864 -0.775953 -2.255141 -0.416250 63.157717 -58.246580 -50.272653 17.520120 10.650434 2.152737 0.302840 1.840061 1.159203 1.473692 1.835205 0.535447 0.749828 1.602698 1.039674 1.798737 1.867787 1.400628 2.356619 2.450689
+1 0.012102 1 1 2.185293 -0.143233 0.720126 1.747239 -1.762025 -1.697670 0.778932 0.501829 -0.938676 0.755411 1.011787 -1.900490 -30.800816 -19.311779 26.937171 33.040088 4.761361 2.487779 1.847123 0.591321 1.575716 2.065947 1.874148 0.300360 0.652999 0.959112 2.292284 1.161316 0.988577 0.271361 1.518967 2.271651
+1 -0.074798 1 1 0.931352 -1.314880 1.922560 -0.384135 -0.177778 -0.260066 2.161777 0.467890 -1.145747 -1.741075 1.696203 -1.870097 29.392310 46.554189 36.256856 68.986410 -45.408423 1.684467 0.589807 0.878525 2.374124 1.909499 0.458553 2.145913 0.366720 2.216329 0.338373 0.542661 0.496709 2.190199 2.179342 1.954870
+1 0.000263 1 1 -2.169932 -0.864511 -1.546869 0.026644 0.129137 -1.999988 -0.325912 -1.809872 -0.046112 -2.168480 -0.021408 -1.667521 -46.036670 -38.309854 -73.720021 -12.394285 39.246360 2.328661 0.549887 0.445112 1.244208 1.400452 1.643251 0.864124 1.085387 0.591499 2.322648 0.752316 0.681163 1.798752 2.129303 2.452935
+1 0.047936 1 1 0.413618 0.911940 2.278640 -0.475278 -0.503774 1.231295 2.282395 1.368870 0.714631 -1.082661 -1.756932 -0.927746 21.487913 -52.649345 -27.536424 -54.672205 24.243583 2.303579 1.999411 1.858403 1.171668 1.728680 1.177277 1.494404 1.199364 1.465175 0.452496 1.599119 1.641659 1.106676 0.646108 2.145132
+1 0.007152 1 1 -0.778109 -0.796378 -1.546463 2.130435 1.485615 -2.220401 -0.878291 -2.235167 0.712491 0.648541 0.268464 2.312285 -15.698240 9.683151 -5.287004 -58.683220 -38.876753 1.351131 0.709482 0.770389 0.677169 2.180999 0.551931 1.061799 2.403004 1.282758 1.312870 1.157398 0.386319 0.861065 1.424910 0.961490
+1 -0.042183 1 1 -0.123679 -0.512574 -0.581945 2.164680 2.134586 0.575707 1.367473 0.793661 -1.719210 1.600344 -1.342194 -0.049263 44.851198 64.088086 -21.539987 -72.568442 -7.812064 0.664519 1.069390 1.738505 2.048335 0.608813 0.827952 0.638489 2.337683 1.434856 1.621620 1.816901 1.147778 0.702427 1.433608 0.902711
+1 0.047311 1 1 -1.903993 1.418233 0.979115 0.317812 2.335790 -1.297664 -0.905337 0.312394 0.811842 2.256226 -0.208648 -0.728433 0.400183 -24.121371 42.119878 58.794292 -44.340476 0.919355 2.349146 0.600429 1.654510 1.096688 1.527890 1.491324 1.177668 1.307208 0.494496 0.997003 2.385283 0.449243 0.922094 1.131363
+1 0.026663 1 1 0.825404 -0.700968 -0.200214 -0.343399 1.173373 -0.462917 -0.091351 0.907289 -0.487548 0.617015 -1.795543 0.455188 67.997417 -17.412252 2.280655 -69.029395 72.951581 1.333340 0.950368 1.588456 2.425688 2.282519 1.290204 0.464092 0.751270 1.103071 0.808512 2.403008 1.358108 0.975810 1.686539 1.655126
+1 0.012505 1 1 -1.444531 0.001027 -1.589979 1.184704 1.470684 1.303978 -1.362281 1.642063 -2.308774 -1.750666 0.711326 -0.077841 56.621523 37.938738 -13.631747 -58.778579 8.424088 1.129811 2.489840 0.494643 1.220568 2.343799 0.728250 1.204201 1.763775 1.524529 1.264009 1.194388 1.076929 2.447924 0.256791 1.883892
+1 0.007016 1 1 1.439327 2.083673 -2.177211 -0.684260 -2.130712 -1.428849 -0.329701 0.490735 1.100644 -2.312099 -1.091161 1.474728 -44.902700 -29.675917 -13.137080 5.099526 57.736476 1.779274 1.003318 0.519432 1.587649 2.362294 1.080115 1.992739 2.221427 0.516872 1.317455 1.712678 2.221532 2.293354 1.152488 1.109045
+1 -0.067024 1 1 1.437161 -1.339310 1.303539 0.688936 0.612662 0.441088 0.783537 -2.215108 -1.449916 -0.968859 -2.314037 -0.669163 58.822538 -19.603482 74.276416 63.720247 -53.813291 2.275295 1.376404 2.471530 1.000192 1.971586 2.195693 2.268887 1.685766 2.176662 1.912526 1.831223 1.110850 1.057951 0.739815 2.073037
+1 0.003281 1 1 1.655063 -0.591738 -2.200368 1.241624 1.509436 2.306759 0.875342 -0.211966 0.058274 -0.761059 -1.700635 -1.933079 -65.151251 2.925845 -25.329081 -5.868155 73.924594 1.384647 1.511690 1.470517 2.476467 0.730377 0.950086 1.353518 0.326937 1.823801 2.377691 1.100993 1.881460 1.704350 1.762536 0.936070
+1 0.023242 1 1 0.929651 -1.641201 -2.058060 -0.876547 -1.190258 -0.574095 2.149864 -1.833142 -0.027450 0.464922 0.801818 -1.283717 -67.226569 73.050093 2.915365 -51.459956 12.517241 0.284045 0.942313 1.209822 1.730070 2.031282 2.010175 0.503775 1.703250 1.263634 1.650249 1.493873 1.274498 1.980395 1.750686 2.022654
+1 0.063637 1 1 0.364533 0.607950 1.353332 -1.243255 -0.656860 1.277881 -1.725311 -1.971699 -0.821187 0.892360 -1.631670 -2.081949 -58.187817 37.367798 -9.419831 -69.100752 73.664583 1.084635 1.459234 1.848398 1.775750 0.285305 1.864082 2.129702 2.407986 1.779759 2.416546 1.641283 1.546319 0.733871 1.168576 1.510886
+1 -0.002902 1 1 2.068701 0.656316 -1.007310 1.751724 -1.784179 -1.767068 -1.627484 2.293108 2.344945 1.774426 -1.932133 -0.286997 61.502688 25.678769 33.073889 -27.148713 11.574971 1.233027 2.490296 1.410619 1.523281 0.540521 0.534370 0.659850 1.350539 2.008379 1.827370 1.599683 2.126660 0.783838 1.709730 2.176201
+1 0.014540 1 1 1.166190 1.330283 -2.213192 -2.229769 1.903994 -1.405030 -0.552511 2.069980 -1.408640 0.028481 -1.981526 -1.057081 -20.806426 -43.600901 -50.350018 67.248305 -7.741003 0.579407 1.591037 0.806433 1.213613 2.441474 2.101743 0.490878 0.936912 0.438265 0.917530 0.929362 1.788929 1.280222 1.446634 1.580716
+1 -0.011276 1 1 0.035901 0.207562 1.327477 -2.248425 -0.626178 -1.407032 -1.222372 1.612809 0.820781 1.705432 -2.272193 0.453412 18.097284 -38.950317 -37.983470 11.821325 -68.995799 1.938992 1.139398 1.607962 1.772511 2.095125 1.766101 2.353244 1.977565 1.439732 0.325463 1.811402 0.979255 1.090826 2.008896 1.515003
+1 0.023289 1 1 -0.518501 -1.244085 -0.464618 -0.411329 -0.130446 -1.149063 -0.924088 0.887342 -1.154319 0.267173 -0.537403 1.518865 17.578150 -64.029777 -48.453793 -12.906952 -27.150657 1.058645 1.145378 0.874594 1.545797 0.964424 1.576962 0.497366 1.985670 0.399931 2.391263 1.950431 2.138440 0.752460 0.853643 0.427241
+1 0.027110 1 1 -1.955095 0.205173 -1.129515 -2.255113 0.067332 0.681080 0.512115 2.287294 -1.127120 0.300905 0.917355 -0.953541 21.175082 -60.398735 -71.534551 -31.199103 36.672502 1.446232 1.577855 2.004778 2.047866 1.729677 2.179157 1.086311 0.371907 1.647537 0.907718 0.264122 1.355272 0.560398 1.604490 1.908339
+1 -0.012384 1 1 -1.738358 0.231453 2.306616 -1.533829 -2.299247 -1.857132 2.054274 -1.485041 -2.267322 2.215734 -2.169557 0.716382 2.525614 -2.006587 25.292242 -13.282961 -46.728609 1.859098 1.617487 2.094850 1.649128 0.640690 1.068968 1.395995 0.979741 0.258667 1.922274 1.403011 1.906859 1.074692 0.852091 1.336798
+1 0.044706 1 1 1.505697 0.722068 1.392696 0.610245 2.229978 1.618095 0.119631 -1.555509 0.893870 0.175906 1.777943 0.632859 18.887364 39.925575 -70.868681 60.084749 44.369113 2.300189 1.275055 2.357505 1.580785 1.750205 0.688967 2.473528 0.834514 0.672506 0.303065 1.113406 1.268960 1.167793 1.855272 0.302346
+1 -0.021473 1 1 0.087645 -1.934894 0.431358 2.176820 -1.168114 -0.671990 1.467748 -0.918292 -0.657988 1.179176 -1.903800 -0.043289 -59.083430 -15.214986 31.732249 73.915321 -5.195924 0.956474 0.706180 1.511076 2.412332 0.556095 1.282264 2.004154 0.563834 0.852512 1.662861 1.959889 1.351549 0.988634 1.224819 1.774429
+1 0.028862 1 1 -1.432760 -0.086495 -2.299765 -1.130086 2.284281 0.070287 -1.497138 1.763813 -1.235511 2.257448 1.479993 2.249436 -39.167020 69.900939 25.080306 24.702772 -20.515540 2.054851 2.131314 0.252126 2.224683 1.253874 1.867590 0.326585 0.416857 1.113628 0.489671 0.903041 0.414681 0.535614 1.309027 1.809258
+1 -0.018186 1 1 1.930916 -1.314199 -0.781529 -1.730349 -1.827678 2.288847 1.424749 2.106679 -1.942015 -1.447826 1.158092 1.889172 -24.004412 57.855349 74.851081 -27.874063 -29.378853 1.819319 1.285200 1.863408 2.040526 2.120169 1.925737 1.112785 2.075113 0.671401 1.994503 0.365027 0.758013 1.916403 1.730746 2.144495
+1 0.057103 1 1 -0.737306 1.687422 1.346781 1.738936 0.059857 2.276641 -1.085761 -2.017280 1.220300 1.257791 -0.075144 -0.016607 -34.283658 -55.445177 -67.082502 -55.604698 -48.152427 0.657347 2.025244 1.777654 0.777250 1.242013 0.511404 1.670714 1.192528 1.314750 1.245280 1.415554 1.223390 0.269302 0.650942 2.375443
+1 -0.038827 1 1 1.982922 0.958541 -1.459429 -0.645497 -0.953337 -0.605466 -2.015991 -0.677807 -2.056171 -2.119108 0.395689 1.162538 38.462191 -65.947843 -35.401430 58.165837 43.217790 2.295959 2.175797 0.876939 0.471892 1.331361 1.431236 1.525994 1.122556 2.040100 1.708771 1.811532 0.924593 0.380973 1.018700 0.284921
+1 -0.004156 1 1 -1.592200 1.549505 1.877313 -2.155038 -0.309747 1.275303 2.071086 -1.669265 2.220716 1.449680 1.729792 1.889170 -25.173671 56.109800 -12.584054 -0.203772 25.195878 1.631782 1.608216 1.527577 0.737281 2.223389 1.997581 0.350695 0.631772 1.945302 1.436979 1.306894 1.962243 0.414767 1.996272 0.851041
+1 -0.028259 1 1 -1.251410 -1.058313 2.206971 1.346645 -0.538275 0.998900 -1.731806 1.966003 -0.665173 -1.771878 2.342451 2.271895 -24.015363 23.787362 44.188632 28.333498 -48.899054 1.429043 0.682871 1.263760 1.510534 2.297108 1.243462 2.370004 2.409855 1.684997 0.498420 1.692204 2.372582 0.734303 1.681897 2.391706
+1 -0.010436 1 1 -2.246374 0.849088 1.511031 0.831892 -0.056691 -0.910494 -1.545295 -1.796379 0.532030 -2.294389 -0.314288 0.346410 73.392295 54.297735 -17.973385 21.311212 -22.455946 1.118715 0.486987 0.795156 0.678539 0.451730 2.228301 1.296972 1.713185 1.750242 1.315490 2.435198 2.368470 1.376854 1.035530 1.898410
+1 0.021779 1 1 -1.497827 -0.400604 1.055739 1.657988 1.447455 2.026475 -2.182359 2.333195 2.217774 -0.861472 -2.306905 1.384689 -64.305640 -34.899033 -48.055546 -69.569780 -9.288544 1.936670 0.362525 1.450714 0.406821 1.195065 1.202803 0.766430 1.644169 0.548122 2.279148 0.883838 1.659296 0.532430 1.808780 1.919442
+1 0.001485 1 1 -0.992279 -0.091514 -1.832704 -2.075127 -0.260440 0.587743 1.037785 1.500831 -0.950744 0.559804 -2.017255 1.635320 69.246243 -28.388293 27.961574 0.174732 -63.286614 1.253162 1.136412 0.928237 0.880452 1.010220 1.760632 0.446590 1.331922 1.869907 1.032334 2.191571 0.477051 0.291995 1.810877 1.155149
+1 0.014987 1 1 -2.227492 -2.230742 -0.319536 1.673761 -2.066948 0.531986 1.694840 -1.223543 0.774494 1.307665 -0.650339 -2.222118 -46.313998 -49.361199 36.325463 22.053611 5.033387 1.317036 1.422590 2.475928 0.676557 0.900055 1.981715 1.436910 2.403518 0.922635 1.230633 0.497006 0.426880 0.822587 0.464381 1.106815
+1 -0.048812 1 1 -0.498419 1.692742 1.215993 -0.429232 0.569583 2.113600 1.279713 0.799702 0.862764 0.457666 1.368876 0.810595 4.736528 -43.167632 31.615431 60.540675 57.121079 1.884659 1.468402 0.679462 2.463138 1.712324 0.781553 1.558287 1.631101 1.418419 2.124186 1.943433 1.534207 1.909423 1.426999 2.313296
+1 -0.034923 1 1 -2.117570 -2.035685 -1.807771 2.281509 0.607372 1.064936 0.730707 0.515181 1.981704 -0.670906 0.831859 -0.596849 45.651305 11.479404 34.344653 30.591154 -54.469109 1.190178 2.321951 0.281775 1.037120 1.619689 0.857251 0.321628 0.346670 0.488997 0.819834 1.457311 1.019551 1.090653 1.361298 0.589126
+1 -0.021198 1 1 0.106385 2.017811 -1.715364 0.268450 2.089340 -1.180851 2.028126 2.001379 0.145275 0.624581 -1.862871 -0.155504 57.676605 70.694545 13.224510 -35.666610 -48.707665 2.429085 0.887694 1.228115 0.936838 1.431364 1.428945 1.286927 1.630380 0.544237 2.234488 1.797680 2.110926 1.824231 0.593554 0.869549
+1 0.073126 1 1 2.043512 1.412639 1.207311 -0.277864 -0.083287 -0.231294 0.357955 -1.566368 2.173511 -0.241148 -0.323091 -1.515366 54.085927 22.180643 40.068486 -68.951259 36.188559 0.941709 2.310350 1.047387 0.942399 0.394930 1.584090 1.056904 1.132228 0.349757 0.616068 1.252581 0.385368 0.637043 0.525114 0.335216
+1 0.007609 1 1 -0.136314 -0.816303 -1.841032 -0.672876 0.712298 2.128430 0.774964 -0.230871 -1.945122 -1.816641 -0.711810 1.363300 42.747343 -45.403618 -48.605420 -11.295266 60.463544 0.786695 2.482946 1.619964 0.979102 0.765109 1.936285 0.636429 1.462737 2.226358 2.397089 0.880903 1.834820 0.826784 1.262274 1.283089
+1 -0.009797 1 1 1.019147 -0.728135 0.315432 0.025030 1.274880 -0.329153 0.269437 -0.176979 -0.965617 0.349986 1.159126 0.422984 -60.306238 -16.941737 -39.766838 38.748043 -61.634026 1.628782 0.695519 2.334410 0.420947 2.350119 1.192187 2.337473 2.411334 1.796713 1.611387 0.833909 1.765320 0.489893 2.375478 2.154011
+1 0.001111 1 1 -1.002051 0.600221 -1.312583 -1.883604 0.089476 0.577358 0.852726 1.384854 0.755361 0.180013 0.117656 -1.753811 -9.775569 -47.988632 5.060700 5.176938 8.791319 1.460481 0.301336 1.300421 1.171709 2.410883 0.964541 1.282425 2.470076 1.320151 2.022630 0.598942 1.412150 0.256307 0.505442 0.466596
+1 0.004750 1 1 -0.502707 0.310133 0.507808 0.599828 1.504098 2.114138 0.900012 -0.264921 0.678386 -2.353254 -0.055479 0.619301 -34.387789 -5.566131 50.039606 -34.345968 -52.677951 0.500158 1.653126 0.329989 1.381915 0.592084 0.911140 1.530987 1.792569 1.701005 1.792810 1.256011 1.783140 0.741152 2.048143 1.884968
+1 0.021716 1 1 -2.025038 -1.933992 1.449695 1.963912 1.898026 1.954514 -0.541440 -0.365072 -0.228285 -0.908566 -2.133072 1.306442 74.747317 28.163553 -55.171256 36.707995 1.276648 1.474306 0.903163 2.463632 1.010087 1.787983 1.122446 2.448446 2.275692 1.300745 2.127449 0.541269 1.856728 2.278101 1.296166 1.666802
+1 0.002721 1 1 -0.864090 0.827849 -2.025860 -1.614806 -1.403161 -2.126631 1.183264 0.837654 -2.160361 -0.229044 0.482600 1.033443 -24.976456 70.705926 54.491191 -66.546626 -49.139871 1.467758 1.117544 1.060339 0.361055 1.507854 2.254518 0.927087 1.801324 0.347180 2.299773 1.035173 0.393927 0.483229 0.623706 1.380273
+1 -0.003971 1 1 -0.162474 -2.234090 -0.031791 -1.808249 -1.051338 1.622216 -1.294034 -1.146840 -1.265802 2.095438 2.346787 -0.243519 71.411864 69.199291 -67.523453 33.321762 -61.143790 1.469748 0.797485 1.579734 2.086743 0.384533 2.354378 0.784049 0.753731 1.952615 0.592836 2.288193 2.151070 1.535990 0.385875 2.404500
+1 -0.005744 1 1 -1.512496 -1.901185 1.490900 1.782871 -1.369112 -0.062238 0.112522 1.491679 0.733960 -1.375151 2.110810 1.527025 33.148446 25.925399 -21.818768 41.967810 52.987754 1.602718 1.389835 0.963800 2.344409 1.980843 0.278780 2.458384 0.563912 2.174814 2.346973 2.318199 2.469926 1.044039 0.919405 0.935801
+1 -0.028493 1 1 0.918537 0.058003 -0.608661 0.826790 -0.979487 -1.862821 0.685675 2.348573 1.496116 -0.092493 0.553110 -1.430662 69.313351 49.482303 49.071347 42.124773 -8.934915 1.088327 0.516559 0.551948 1.338424 0.889010 0.841772 1.166445 1.698596 1.803499 0.914787 2.068044 1.112778 1.965671 1.779856 1.798579
+1 -0.021658 1 1 -2.034898 1.981987 -0.620828 -1.024253 -0.262927 1.199432 -0.741430 -1.660391 0.576219 0.549590 0.669343 1.174388 -71.866436 -59.194132 74.228902 15.164094 12.934420 1.956918 0.919006 0.987423 1.111705 1.930740 1.948731 0.567318 0.910580 1.124417 1.821350 1.686120 1.374038 0.950803 2.149639 2.225851
+1 -0.031974 1 1 2.258676 -1.434514 -1.299691 -1.988301 -1.816567 0.519127 2.330362 1.735176 -1.865577 1.485721 -0.440603 -2.053654 -70.901803 -46.610767 62.845148 -61.592464 -34.534282 0.359916 0.363641 2.217683 0.592077 0.781236 0.733895 1.566529 0.661453 1.289011 0.666697 1.674839 0.774866 1.666575 1.368608 1.937364
+1 -0.038898 1 1 -1.161709 -1.408718 -1.280533 -0.429805 0.358046 -0.036954 0.950818 0.687692 -1.443128 0.014125 1.786328 0.193494 16.210058 42.446787 3.143825 38.261676 13.986639 1.726748 2.451814 0.396153 1.893055 0.817972 1.663417 2.292905 0.347750 0.635800 2.134988 1.249948 1.134863 1.898476 1.943178 1.741105
+1 -0.003629 1 1 -0.034904 -2.299840 2.312826 -0.836290 1.527380 2.290723 -0.031979 -0.265478 0.736596 0.526114 1.959222 -1.532868 -8.850453 50.438863 -74.024008 -21.508010 14.882422 0.308016 1.077990 2.271331 2.266116 2.370110 1.935950 1.758909 0.742324 1.491855 1.104330 1.729911 1.607728 2.333674 1.553068 1.669658
+1 0.017106 1 1 -0.004728 0.640377 -0.287003 1.819161 0.656949 0.215759 -2.285488 -1.515735 0.216554 1.653969 -0.120928 -1.405633 -40.486916 -63.596801 28.558737 -13.303809 52.883274 2.262857 1.596550 1.222807 1.712542 2.192233 0.365815 0.508787 0.440512 0.440320 1.701629 1.030100 0.635781 1.820151 1.780692 2.332863
+1 -0.028470 1 1 0.560827 1.048082 0.205934 2.236002 -0.818173 -0.282623 0.048446 -1.005583 -2.209180 -0.783572 1.638328 0.886932 44.094678 -50.753896 29.276240 45.770214 59.990535 0.788913 1.507092 0.692250 1.399478 1.030150 1.477613 2.485026 0.583765 0.596329 2.494373 2.432382 2.289273 2.309530 0.776680 0.652641
+1 -0.008619 1 1 -2.209522 -1.810330 1.686270 0.835083 1.748228 0.723471 1.410479 -2.114582 1.059114 1.828008 -1.446273 -1.000104 10.645889 -24.550701 26.365514 25.189613 61.823212 1.565844 0.384209 1.398145 1.116782 1.758408 1.311980 1.952409 1.647112 0.514669 0.290262 1.933758 0.921493 2.274576 0.548569 0.798614
+1 0.001211 1 1 -0.824924 -0.647299 1.749118 1.539885 0.399338 1.238358 -1.542647 0.287114 0.042144 1.459347 -0.736946 -1.697150 2.788001 57.939222 -15.493810 -4.471090 4.394160 2.164716 1.390357 0.733916 1.932504 2.348618 0.716187 0.949503 0.553203 2.189597 1.055157 1.020782 1.526070 2.411294 1.124407 1.653657
+1 0.001121 1 1 1.218204 -0.974934 -0.745835 -0.290092 1.740341 0.114188 1.219755 1.536255 0.653824 -0.475985 1.759256 2.292842 -67.438395 -37.101107 -8.301099 -16.562835 28.436346 1.819933 0.366384 1.057570 1.084879 1.059514 2.251949 0.498779 0.976658 2.433174 2.106435 0.602928 0.908399 0.459518 0.373951 2.239853
+1 0.015775 1 1 -0.257566 1.771779 0.709191 1.749658 1.189614 -0.820064 0.926967 0.372042 -0.438603 -1.424178 -1.929921 -0.808948 -23.818014 40.641003 -46.661133 -33.654168 24.395750 2.415665 0.323859 1.846815 2.162223 2.227297 2.432886 1.764010 0.964194 2.216187 2.446093 0.985612 2.184578 2.198362 2.117458 1.364605
+1 -0.023055 1 1 0.922877 2.318266 1.064359 0.456769 0.428948 -0.628955 -0.952671 1.154699 1.415033 -0.973402 1.444232 -0.301895 41.148583 -65.767982 -12.475695 20.990789 -7.810765 0.992088 0.767744 1.221462 1.620281 1.815152 1.005216 0.917379 0.630975 2.046274 1.975433 1.604603 1.560323 2.091505 1.682008 2.012714
+1 -0.014275 1 1 0.969223 -0.998618 1.759977 0.261424 1.802267 -0.527734 -0.917447 -0.589887 0.631162 0.355925 2.014670 2.035166 -70.120799 29.729580 15.045917 -23.278355 -39.308051 0.618831 0.445395 1.508958 0.559522 0.391542 0.889653 0.392086 1.031590 0.926073 0.513715 2.257935 2.110324 0.724469 0.656018 2.196771
+1 -0.001755 1 1 1.279331 -0.916802 0.817807 -1.152739 -1.447937 -0.702033 0.758752 0.612330 -0.435196 -0.703932 1.831476 0.291591 -3.507766 -5.015355 6.925552 -2.248643 7.056672 0.647295 1.835110 1.195306 0.763762 1.791249 2.017158 0.866549 1.342447 1.004878 1.990324 2.125016 2.396785 0.271327 0.936573 1.485800
+1 -0.024279 1 1 0.644155 1.954168 -1.654610 -1.226798 -2.086251 1.258011 -1.104606 1.696460 -2.267052 2.038294 -1.465029 -0.501169 -66.846150 16.750414 -25.787366 -58.268116 37.768726 1.059571 0.960195 0.255368 0.469998 1.002689 1.194641 0.832523 0.968880 2.217438 0.987113 0.402319 2.031081 0.873073 0.731169 0.765206
+1 0.006585 1 1 0.374816 -0.931689 0.370735 1.163202 -1.760384 2.313982 -0.255957 0.537080 -2.229959 -1.296309 -1.687906 -0.063497 -70.092609 53.522713 6.241417 49.496954 -4.689163 0.463683 0.627944 0.598887 0.502117 0.838262 0.668689 1.411218 0.346136 0.501142 2.436051 0.954966 2.362162 1.099030 0.403745 1.234314
+1 -0.007710 1 1 0.128843 -2.239228 -1.567326 0.213826 -1.774201 0.992143 -2.190787 2.054451 1.490067 1.928090 -1.694932 -0.337183 62.929284 2.472021 -2.741468 -25.860708 59.086943 2.488763 0.386669 2.247266 0.548066 1.340905 2.087835 0.743159 2.022653 0.973633 1.099526 1.988910 0.859833 0.964470 2.352301 1.867193
+1 0.037208 1 1 -1.738030 1.024460 -0.976388 -1.607009 -2.306585 2.051157 -2.033539 1.272109 0.233122 2.078986 -0.840468 2.001061 -15.633319 50.799552 -11.937910 59.552730 -47.274593 1.463792 1.947666 0.680200 1.367890 1.133073 1.061403 2.494810 0.772180 1.524474 0.332141 1.535914 1.351327 1.758679 1.360559 1.656234
+1 0.006580 1 1 -0.175777 0.380474 -0.079090 -0.377178 -1.064292 0.670385 -0.156189 -0.267073 2.203018 0.882512 -2.213064 -0.074818 23.550195 -41.877105 -28.505721 4.341819 72.950166 0.976681 0.576056 1.520515 1.301201 0.780359 1.741645 0.820365 1.367826 2.296912 2.451204 1.388084 0.774909 2.388539 1.183604 2.078225
+1 -0.039607 1 1 -0.463933 1.681576 2.046726 -1.109056 2.300595 0.942196 1.862247 -0.904440 1.243360 -2.289856 0.473278 -0.137025 44.020995 60.862870 72.252103 -58.912149 13.518504 0.707533 1.764868 1.880707 0.293840 1.318408 1.979896 2.361266 1.794303 1.596966 1.453691 0.940548 0.782570 0.659325 1.518350 0.911202
+1 -0.028865 1 1 -2.211191 -1.582774 -0.246806 -1.161859 0.771945 0.873006 -1.763163 -1.983804 -1.638127 -2.217343 -1.313775 1.632393 3.288367 67.580390 23.617408 37.768512 -24.625598 0.888684 2.112277 2.035988 2.355354 1.440011 0.506939 0.875522 1.398017 1.214288 0.288997 0.924612 0.697976 0.891039 1.200694 1.312420
+1 -0.009610 1 1 0.134124 1.696368 0.901982 -0.137984 -0.597562 -1.123537 -0.736193 1.539062 0.716422 0.752753 -1.248328 -1.101790 60.630857 72.819578 28.640704 14.312883 -43.380185 2.263545 1.895260 1.888942 1.448954 2.321314 0.826041 2.273261 0.943629 0.819217 2.337352 0.371417 2.399732 0.289874 2.167636 0.966382
+1 -0.026198 1 1 0.669294 0.356407 0.679937 0.164611 0.441001 -0.676061 -0.987548 -0.678173 1.210050 -1.353595 1.551512 -2.099751 17.891301 -50.907193 2.812784 24.453898 -3.331504 0.736194 1.963376 1.455437 1.038170 1.277639 0.776198 1.555729 1.392780 0.956445 2.468278 0.346710 1.159842 0.962883 0.423108 0.424259
+1 0.007436 1 1 -0.372709 -1.348522 1.979255 0.588006 0.733290 1.509434 2.259773 -1.853801 1.478932 -1.450953 0.438430 -1.483881 -51.757970 -46.198644 -60.617311 4.858504 56.884837 0.826838 2.172482 1.410735 1.222740 0.590863 0.630668 1.383236 0.292555 2.223663 2.100255 2.493711 0.299446 1.035248 1.666959 1.071195
+1 -0.019652 1 1 -2.202076 0.808790 -1.911032 0.927615 1.834615 1.209193 -1.622437 2.287169 1.484976 1.177602 -0.081146 -1.932365 16.879660 46.439813 63.944822 -29.383536 -49.085435 1.691397 2.306160 0.376775 2.465172 2.151439 0.979474 0.261438 1.237877 0.755843 1.460140 1.317702 1.374907 2.062445 1.510310 0.788960
+1 -0.045441 1 1 1.933345 1.798941 0.114805 2.167361 0.063809 -1.981278 -1.592340 -0.795566 -2.035191 1.782578 -1.575675 1.252727 -12.054675 47.077333 -21.265732 36.849997 -12.107265 2.322919 0.794855 2.370699 0.584031 0.566299 1.782653 1.556212 0.507582 0.438232 0.369017 0.320596 1.001022 2.421064 1.071608 0.771403
+1 -0.012366 1 1 1.463297 -0.329979 0.526294 0.274201 -0.216510 -0.924244 -1.732566 -1.389261 0.572192 -1.147287 0.641211 -0.407770 -50.290081 24.612380 -39.724165 5.962001 3.347865 1.638528 2.482687 1.773012 1.517545 0.873535 1.760074 2.309548 1.080370 1.779203 2.060304 1.523812 0.451459 2.164772 2.323088 1.394432
+1 0.044457 1 1 0.478142 1.513953 -1.885672 -1.673018 0.409945 0.427774 -1.503597 1.585416 2.233118 -2.165222 -1.824959 0.857437 14.824116 -1.076254 61.400118 -48.219544 24.132059 1.187834 1.183734 2.024848 1.873704 1.843038 1.680603 0.889181 1.463343 1.163409 2.408461 0.758741 0.658674 1.828360 2.491152 2.299221
+1 -0.004878 1 1 0.185666 0.895166 -1.610784 0.234227 1.810653 -0.963890 1.089743 -1.746915 -2.215224 1.323202 1.293200 1.271848 17.514357 63.790897 -66.393808 -30.725053 54.038891 1.099674 2.226122 0.687367 0.330259 1.405576 2.262475 1.926382 0.703864 0.837711 0.408101 2.448593 0.259523 0.553955 1.321738 1.707687
+1 0.055549 1 1 -0.025163 1.196331 -1.029475 1.501389 -1.006852 0.025575 1.007960 -0.250758 -1.606334 -0.386172 -1.437069 -1.833744 -22.862717 46.311143 1.379295 -68.197011 -37.162924 1.416067 0.842277 0.652717 0.707075 0.816350 1.393871 1.290188 2.445040 1.278074 1.342206 1.448939 2.064112 0.283940 1.437755 0.845018
+1 0.039395 1 1 0.948086 1.888966 0.478187 2.262009 -1.975410 -1.942802 -0.529584 0.983254 -0.800620 -2.156454 -0.532808 -1.368831 -1.688987 -36.811259 63.165315 69.441026 -54.682208 1.466980 1.532279 1.014488 1.503934 1.619048 1.336187 1.546082 1.255184 1.368987 1.561044 0.720249 1.725352 1.487469 1.644876 1.187008
+1 -0.028641 1 1 2.197472 1.919359 -2.349080 -0.598127 -1.196548 2.089217 1.462705 -0.856921 -1.205630 0.243527 -2.100040 0.420013 -0.111844 70.232695 50.911735 73.524840 31.977871 1.406255 2.426633 2.411979 1.384675 1.989061 1.150789 1.811996 1.959836 0.470924 0.823828 1.075064 0.346923 2.481789 2.427854 0.436552
+1 0.000106 1 1 -1.543012 -1.131024 0.660249 -0.871786 -1.293851 1.912357 -2.225005 1.861070 -1.841854 -0.352805 -1.401150 -1.328166 3.056766 -74.937538 74.806085 -34.134951 43.883541 1.385175 1.383447 1.589867 1.390561 1.907047 1.989318 0.965762 1.560150 1.448063 0.852696 0.263776 2.290196 2.069776 0.977342 0.429831
+1 -0.008851 1 1 1.545954 -1.257083 -2.149051 1.355037 -0.872308 -0.631237 -1.611130 -0.869944 1.397642 -1.089117 -1.877205 -0.741040 5.808118 -32.958034 24.329819 11.270579 -25.386336 0.352662 2.190632 0.449126 1.203018 2.131556 2.053117 2.236129 2.363485 0.845074 0.410808 0.693374 2.283337 1.548040 0.407074 0.935163
+1 -0.068056 1 1 1.384171 -1.304166 -1.800662 -0.757307 0.103203 0.365394 0.933073 -0.670386 0.137564 -1.743152 -0.227055 0.916128 63.325770 66.223170 12.820127 67.874802 21.802979 1.265070 1.026512 1.086466 0.739570 2.446924 1.453016 0.847796 1.164868 2.182571 2.226141 1.003596 0.680357 1.766422 1.000381 0.652993
+1 0.061721 1 1 1.179614 0.756929 -1.739786 -0.210607 -0.673916 2.070388 0.737121 -0.075868 1.939575 -1.874060 0.283480 0.216119 -30.165486 8.682384 -25.163362 -70.623776 -23.799911 2.048549 1.956048 2.041516 0.762730 2.447819 0.740188 1.582432 2.433851 2.237592 2.209441 1.579370 0.462587 2.453582 0.861846 1.044531
+1 -0.011353 1 1 0.440829 1.138227 -2.115657 1.837215 -2.217584 -0.644455 -2.279008 -0.996780 -0.330697 -2.125061 -0.702198 -2.027379 35.890931 68.878310 -62.241740 3.070231 1.365843 1.460787 0.948385 2.001598 0.350976 0.848731 1.118869 0.831370 1.835392 1.425806 0.280587 1.321748 1.875046 1.900626 2.062398 0.729301
+1 0.059836 1 1 -0.081123 -1.546222 1.475793 2.343575 2.324056 -0.579221 0.826763 -1.424308 0.600520 -0.990951 -1.323514 -1.829184 17.043901 -43.161400 -13.641922 70.220731 -0.170388 1.169318 0.474929 0.626637 1.146321 0.964803 1.195376 1.939801 1.231406 2.245404 0.751935 1.027336 1.430711 1.708385 2.080277 1.970329
+1 0.035154 1 1 -1.543056 -1.869379 -1.161177 -1.901681 -2.121541 1.911919 -0.165268 -2.065371 -1.236932 1.937205 0.711052 0.030927 45.691446 -63.871913 54.758171 70.575011 -45.797044 0.461169 1.118649 1.631879 0.981972 1.751328 1.562490 0.262884 0.798245 0.860481 0.595910 2.205272 1.260539 1.378747 1.347015 1.278021
+1 0.014936 1 1 -0.242621 -1.521062 0.223532 1.124979 1.409496 0.225351 -1.279404 -0.319261 1.590367 0.623192 -1.658335 2.144203 63.278721 25.462082 -8.795172 -70.449406 56.841191 1.073489 0.888269 1.892187 1.981477 1.933658 1.489696 0.816589 0.904290 1.159740 1.496660 0.863275 0.311069 0.641034 2.354531 1.107617
+1 -0.041928 1 1 1.310979 -1.504797 0.271927 -0.733531 -0.840482 1.767420 -1.866624 -1.984163 1.752199 1.491797 -1.986787 0.055697 -53.019440 52.270340 -42.398345 61.022412 53.685954 2.122508 0.739959 2.245693 1.118010 2.140380 1.873306 1.897847 0.358015 2.165525 1.484250 1.539080 0.573910 1.450848 0.394509 1.269068
+1 0.067650 1 1 -1.776078 -2.266800 1.562745 -1.796950 0.365008 -0.834733 -0.569558 -1.694338 0.235676 -2.113032 -1.170485 1.888891 -24.368140 -55.322462 45.378675 -70.601136 56.710728 1.933028 2.150149 1.796964 1.317041 1.512239 1.708407 2.446622 0.872654 0.447228 0.809650 1.287835 1.148251 1.901138 1.670456 1.347302
+1 -0.060810 1 1 2.112138 0.284772 -1.629396 -1.561978 0.552902 -0.212886 -1.269936 -1.398718 1.849811 2.139510 -1.499988 0.975583 70.663258 -62.615936 13.962291 64.223098 -2.386355 0.513033 2.045634 2.470024 0.437518 1.868381 2.386422 1.590885 0.498765 0.750025 0.427674 0.665318 0.991733 1.551122 0.448880 1.579477
+1 0.010310 1 1 1.154539 -1.276683 -1.698780 0.978483 -0.873170 -0.988336 0.208720 1.944138 -0.577538 0.843728 0.958968 1.010736 -22.910684 -9.871024 -2.293761 -1.248072 23.655346 0.256018 2.396323 1.507760 0.673411 2.018513 1.147318 1.971578 2.064169 1.243473 0.299426 0.696533 1.375910 0.917357 0.264313 2.316668
+1 -0.039082 1 1 -2.303814 1.496480 1.325387 0.308393 -0.462527 1.742251 -0.779664 1.343857 -0.269314 2.242825 0.766118 1.895549 -62.622708 50.141446 27.285685 40.511632 29.004438 1.038752 2.047225 2.213297 1.128977 1.974609 1.254001 1.749939 0.717729 2.126126 0.802621 2.402875 1.366071 2.049681 0.729777 2.119872
+1 -0.048867 1 1 1.197734 -1.004685 -1.260291 0.484836 0.911834 0.505997 -1.569727 2.256715 -1.407363 -2.074204 1.112838 -0.003696 -27.524918 -11.292404 -41.433634 74.910042 63.074594 2.045564 1.288596 0.433594 1.155871 1.720420 1.845753 2.319533 2.391746 1.074055 1.396199 2.159299 0.340890 2.330289 0.913396 1.190513
+1 0.028635 1 1 -1.504855 -0.701802 -0.077013 1.554747 0.444261 2.277440 -1.797729 1.413108 -0.328385 -0.967530 1.178006 2.001291 -42.387961 -64.458553 -54.906909 -20.427313 28.158194 1.446373 1.688791 1.252984 0.410682 0.827736 1.508255 2.245035 1.300774 0.363203 1.598512 0.445557 1.971852 2.160715 1.642401 2.328132
+1 0.003720 1 1 1.036835 -0.321251 1.132903 -2.067077 -1.638786 0.834017 -2.041892 2.244218 0.615760 0.675029 -2.217716 1.851356 -5.433870 22.951136 -60.263236 -44.203145 27.739703 1.692920 0.904580 1.523278 0.491461 1.739745 0.397888 1.802187 1.356951 1.781710 1.450506 1.413183 1.864318 1.587311 1.193428 0.695567
+1 0.053179 1 1 1.632415 0.468354 1.939445 0.654685 -0.137621 0.781999 0.197382 -0.116444 -1.429078 0.525610 -1.794583 -2.272511 -5.810925 -14.216190 18.498369 -47.910641 -34.148845 0.780335 1.333495 1.308944 0.422471 0.963207 1.373390 1.307037 2.124651 0.754122 1.786391 1.376355 1.653383 2.401548 1.569118 1.422190
+1 -0.007537 1 1 0.607185 -2.068612 0.840828 -0.665720 -1.551687 -0.838476 -2.223216 -1.062301 1.142934 1.586680 -0.085984 1.571248 -8.364567 -33.271529 5.410244 29.964324 60.390663 0.413084 0.702691 1.385088 2.182966 2.112746 0.917185 1.881472 1.905290 1.712362 1.413816 1.252924 1.651561 1.042639 2.141419 1.335000
+1 0.002716 1 1 2.073311 -1.985384 0.069939 2.076671 -2.064532 -1.265386 -0.335210 2.147365 -1.426770 1.629295 -0.127241 0.890161 -28.468708 26.421953 73.771394 -24.179135 -28.729489 1.277227 0.607738 0.756006 1.949394 0.471050 0.693393 0.349231 0.774898 2.215792 0.315775 0.979751 0.423438 1.470212 1.850761 0.982749
+1 0.009686 1 1 -0.433142 0.818026 -2.192565 0.443642 1.288381 0.388767 -2.079697 -1.675424 -2.325757 0.274696 -1.325716 -1.128618 -42.009201 1.362675 -47.518565 -44.514196 49.909740 1.870102 2.060470 2.063552 2.122193 2.204290 0.497213 1.657276 0.341396 1.845668 0.893794 2.488458 2.008004 2.278353 1.035701 0.272217
+1 0.048180 1 1 -1.938595 -0.512970 2.178713 -2.347682 -0.657426 1.196387 -0.095393 -1.054798 0.011001 1.118336 -1.839162 -2.233202 23.718017 -71.289625 35.267250 -63.323573 -29.295229 0.401192 1.079162 1.719692 0.868925 0.778860 1.293291 0.589631 2.435495 0.621387 0.645240 1.048282 2.470765 1.649554 1.047086 0.380526
+1 -0.036370 1 1 2.343641 -1.283897 -0.435004 -2.203404 2.048019 1.767739 -1.218117 -2.275053 -0.496467 1.525849 0.121199 1.235901 -13.377577 13.067814 30.751134 -65.686297 10.407608 1.685096 2.157043 0.666801 1.169501 1.310136 2.460604 1.864666 0.692696 2.136543 0.379026 2.036669 0.299130 2.480367 1.026093 0.788296
+1 -0.018118 1 1 0.513319 -1.029363 -1.321223 -1.024455 1.046793 2.104815 -0.282590 0.602397 2.281675 -1.304688 -1.137088 -2.301673 -6.721270 -14.384991 31.453209 34.078590 58.864769 0.477567 2.215207 1.730964 1.306725 1.385434 1.248184 0.721047 1.645229 0.365683 0.529746 1.682880 0.916196 1.004918 0.410870 1.736744
+1 0.000073 1 1 -0.806277 1.736566 -2.067826 -0.081951 -1.335097 1.423420 -1.386913 2.340250 -1.733807 1.326458 -0.537716 0.964478 -20.497218 53.264814 21.732807 13.292251 52.858806 0.594203 0.524621 1.047314 1.953036 0.932528 1.003182 0.483300 1.827621 1.325148 0.510017 0.852896 1.374605 1.490447 2.190753 2.486930
+1 0.005039 1 1 -0.911220 0.394659 -2.012004 0.359787 0.943119 -1.482912 0.520093 -0.278728 -0.463289 -1.639273 2.083922 2.010910 3.441218 -63.445989 13.270470 -13.202790 -49.287266 0.308707 1.439970 2.071830 1.754855 2.341520 0.669715 0.644185 1.315879 2.232840 1.092022 1.862272 0.948349 1.395203 1.171613 0.792762
+1 0.017118 1 1 -0.784177 0.881913 1.849939 -0.418740 -2.163823 -1.872308 1.451386 2.126999 0.288573 0.990063 0.539445 -0.182013 -23.891152 11.402881 -51.779825 36.482454 -39.397128 0.662039 2.138773 1.859782 1.857909 1.883308 1.264903 0.472913 0.495193 1.461928 2.118078 0.542586 1.498014 1.118985 0.539087 1.190984
+1 -0.027023 1 1 1.434447 0.174676 -0.031851 1.888440 1.066007 -0.124069 -2.352592 1.634797 -1.906647 -0.773137 -2.056010 0.590495 5.058732 -27.882820 -26.556466 65.476972 71.467621 0.719532 0.925005 0.558149 2.068634 2.033735 0.475130 1.765641 1.382609 1.014940 2.345440 1.306822 0.759367 2.181534 0.547376 1.004353
+1 -0.005021 1 1 0.863230 -1.135786 0.734928 0.762152 1.221638 0.189321 1.052529 -0.450240 0.912562 -1.391913 -1.575216 -0.445282 -18.678267 24.372102 -28.084918 26.776188 27.386363 0.363989 1.315442 1.634502 2.316210 0.535354 1.437158 2.064268 0.652906 1.638183 1.198603 2.172032 0.587472 2.149550 0.733689 0.358673
+1 0.045087 1 1 1.372438 -0.578790 -1.345128 -2.240480 0.957941 -2.126666 0.592580 2.207947 -1.099321 0.993760 1.424727 1.738755 55.037550 -33.889879 -37.194191 -72.759834 -74.530833 1.529375 1.700331 1.719764 2.067575 2.231687 1.965313 0.265249 2.284933 1.370308 1.275197 2.493710 0.281625 0.773705 2.403640 0.724844
+1 -0.012923 1 1 2.182947 -1.877175 -0.236878 0.755324 -0.447516 -0.426461 0.015422 0.013359 -1.670395 2.088449 -2.024593 0.826795 -28.553074 -41.521280 -48.149223 6.011647 -62.245733 0.414504 2.070555 0.560300 2.204918 2.057194 1.010022 0.690639 1.327633 1.770615 1.732045 1.473621 0.640975 1.368585 1.555911 2.199742
+1 0.019832 1 1 -0.643567 -1.505745 -1.532968 -1.964535 1.773191 0.878075 -1.397786 -1.324258 -0.187965 -1.829419 1.284581 -2.214796 -29.171182 69.946737 44.814680 50.319556 20.769793 1.793624 1.436419 0.889899 2.282691 1.933593 0.405524 1.899873 0.660217 0.774265 0.566796 1.135111 1.564474 2.119535 0.282024 0.720128
+1 0.009710 1 1 -1.414447 1.399143 0.571893 -1.462871 -1.934853 1.130472 -0.507771 0.031131 0.138074 2.107466 1.863601 -1.705340 -28.529732 50.800524 4.402375 40.723704 -6.702648 1.353961 1.018816 2.239257 0.949420 1.398560 1.346417 2.473252 0.694367 0.976560 0.797109 2.006628 1.649448 1.526908 0.749182 1.996105
+1 0.027358 1 1 -0.938181 -0.354348 0.934333 1.650393 1.031090 2.080674 -0.745057 -1.360653 0.732063 -0.258981 1.561589 2.337725 -55.981762 64.524111 -43.260825 -34.684067 -35.115095 2.434069 1.397392 1.968968 0.951457 1.886540 1.583402 0.737133 1.997904 1.279423 1.509482 0.365720 1.151725 1.786864 0.321263 0.962865
+1 -0.030102 1 1 -1.381430 0.239758 0.523680 -1.248592 -0.815219 2.238456 -1.979277 -0.946451 2.019862 -0.228259 -0.472044 2.019770 -56.725639 12.191534 3.116854 34.968151 9.719622 1.490425 1.816889 0.959675 0.507457 0.587492 2.476115 1.562321 1.935248 1.221540 0.679993 2.387846 0.783464 2.182355 0.847087 0.490269
+1 -0.010611 1 1 -2.341420 0.911240 -0.054322 1.214238 -1.651390 1.052189 -1.457304 2.097033 0.880587 -1.593163 -0.494341 -0.453230 -70.433587 22.700998 -64.321923 -8.555078 64.798018 2.279423 1.015955 1.397471 1.037326 0.590523 1.669768 1.042112 2.277851 1.587061 1.480308 0.530187 2.354755 0.371066 0.999444 0.648700
+1 -0.018063 1 1 2.348281 1.307992 0.133410 -0.868059 0.088474 -2.129128 1.635000 1.511769 -0.893268 0.517443 2.303108 0.770128 -44.523463 44.151687 7.408536 15.257248 -71.427019 1.016261 2.053711 0.979635 0.728241 1.042196 1.431561 2.494360 2.206278 2.412573 2.371772 0.624368 1.257152 0.698291 1.674455 1.066291
+1 0.006651 1 1 -1.535001 1.570623 -1.348136 -0.956550 1.929138 1.783249 0.278610 -1.515703 0.761948 -2.206368 -0.632201 1.036095 43.799112 -68.329688 -17.073576 -5.588852 -31.829299 0.549584 2.111175 1.513754 2.422503 0.510067 1.694798 0.973320 0.343969 2.332069 1.590577 2.071869 2.396609 1.808609 1.300529 0.746353
+1 -0.031490 1 1 -0.268513 1.577438 0.107219 1.899700 1.816174 2.286563 0.733097 -1.727566 -2.170474 -0.550938 0.237553 1.151885 39.631935 -56.071480 56.641808 -71.135225 -69.734885 2.361739 0.753262 0.832547 1.363452 0.793681 0.646135 0.342708 1.390930 1.364671 1.020779 1.489055 1.303325 0.489035 1.467858 0.536169
+1 -0.018160 1 1 0.516555 1.513654 -2.204833 1.598214 0.564082 -0.804741 -0.730287 1.845006 1.498662 0.300638 1.140269 -0.781129 9.135260 -63.685071 45.009007 16.382017 -67.440574 0.269213 1.415436 1.483835 1.317986 1.649677 0.872769 2.372315 0.751320 1.929160 2.385126 2.305976 1.796833 1.373253 1.266574 1.558457
+1 -0.006368 1 1 1.615011 0.121912 -0.912651 -0.099698 1.979050 1.851220 2.255285 -1.887927 -1.875998 0.702306 -0.882087 -0.068327 46.048016 -71.003398 45.889903 -28.392295 -39.309592 2.480405 1.659201 1.189015 0.774150 0.887165 1.335756 1.044261 2.386259 1.105803 1.737943 1.608078 1.466071 1.998859 1.574887 1.619093
+1 -0.031332 1 1 1.038945 2.148287 -0.061863 1.701935 0.220852 -1.500664 -0.953903 -0.692640 -1.596305 -1.472539 0.509610 -2.110630 48.033287 -4.540454 38.593065 33.647759 17.879755 2.200675 0.501097 1.683023 1.066489 2.473777 0.523950 1.021654 0.443023 2.132400 0.489229 2.472837 0.470720 1.888124 1.202794 0.599828
+1 -0.010176 1 1 -0.549614 -1.083958 0.014009 -0.169281 1.177364 0.640214 1.695203 0.179990 -0.262844 -2.108938 1.671581 -1.005319 71.122442 4.888136 -45.104504 28.606133 33.269533 0.790554 2.092109 0.568784 0.808220 2.001380 1.201777 1.507138 1.464190 1.899021 2.088795 1.130737 2.299146 1.739930 1.259721 1.127708
+1 0.014494 1 1 -1.487002 -2.250534 1.619734 -0.600395 -1.620887 0.073429 -0.521706 1.435571 0.215589 -0.417501 -0.198023 -1.220107 62.731308 -24.912000 -45.985651 69.165945 -27.960364 1.677373 0.601903 1.686244 1.209229 0.761005 0.459039 1.318474 0.847384 0.984346 1.150232 1.456052 2.373685 1.277967 1.798096 2.357923
+1 0.017395 1 1 -0.964142 1.572668 0.034338 2.201491 -1.214320 0.284658 1.175108 0.411012 -0.478746 -2.239093 0.700038 -1.293481 -40.874903 15.502463 -0.101665 -58.676220 -71.232336 0.596988 2.330715 1.326185 2.185559 0.691455 1.530862 1.941564 1.618702 2.282856 2.460796 0.602723 1.959664 2.076831 0.293995 1.671983
+1 0.004192 1 1 -2.010753 -2.189415 1.549336 -0.965024 0.887956 -0.267198 0.104901 0.631674 -0.475014 -0.769212 -2.065760 1.657198 73.318505 14.110131 -1.034579 11.821817 -60.715892 1.345036 1.779157 1.291568 0.888993 0.563193 1.328877 2.427153 2.152054 2.314971 2.215806 0.559664 0.526074 0.724291 2.154948 1.459796
+1 -0.015905 1 1 0.380099 -1.681412 0.713514 -1.006146 -2.236866 0.439351 -0.139480 -2.189605 -1.652552 0.372573 -0.936950 1.483439 -34.648471 -36.845123 -55.987041 -24.203437 12.834996 1.641673 1.350089 1.201511 1.542961 0.546758 1.862030 1.386246 1.382983 0.541346 0.896752 0.467490 1.599226 1.197372 1.735347 0.728355
+1 0.009205 1 1 -0.358388 -0.989878 -2.142590 1.563824 2.195794 1.995002 1.353157 0.523014 1.691830 0.032172 -1.206186 0.325784 -10.797543 25.699849 -62.634592 0.405850 71.125152 2.131370 1.191777 2.197488 0.928969 1.934391 0.309835 2.399426 1.896101 0.265024 0.757943 0.746826 0.657917 0.357344 2.128385 0.508301
+1 0.005535 1 1 1.224464 0.567472 -0.370322 1.062000 -1.489977 -0.400999 -0.879654 -1.576185 2.110367 -1.207540 1.142027 0.479644 -48.216946 67.796156 49.996127 -15.097979 48.274227 1.299118 1.770984 1.179877 2.451309 0.902011 1.090445 2.355069 1.146962 0.490111 1.547287 1.258274 1.554450 2.397229 0.969616 1.081478
+1 0.026881 1 1 -2.231727 1.971567 -1.400038 -1.487849 -2.334936 1.509416 1.958050 2.337186 -1.382152 2.240123 -2.241832 1.790742 -32.558757 -15.035949 40.798267 46.471251 -7.689555 2.299824 1.885615 1.783254 0.391058 1.766979 1.366168 1.430798 0.914818 0.341886 1.081552 1.396701 1.609137 1.258081 0.561463 1.511453
+1 0.068671 1 1 1.087250 -1.232813 0.487102 1.311352 0.048104 -2.046983 1.512060 -0.719086 1.604958 0.808195 2.220975 1.088869 -73.395554 40.929029 -5.813824 -62.938860 -13.424827 0.909044 2.310811 2.043362 0.291498 2.450354 0.597196 1.326062 2.365054 2.461913 1.364848 1.755913 2.132209 1.785317 1.322354 0.797552
+1 -0.033633 1 1 1.717791 -1.897757 -2.151022 1.222235 0.806510 2.185828 -0.578735 -0.423069 0.474994 0.433264 1.228311 -0.756565 -49.926258 -10.624969 -73.849660 58.766818 -56.090001 2.055302 0.706267 0.737478 1.042607 1.594297 1.607075 0.363272 0.510059 1.560615 0.257943 0.990720 0.275558 2.296291 1.016619 1.316664
+1 0.004877 1 1 1.852266 0.991757 0.742216 0.728060 -1.567391 -0.881536 -0.229989 -1.260705 -1.761573 1.173465 1.076160 0.867324 53.734978 -26.220856 6.077867 0.716804 47.320969 1.727835 0.480018 0.665001 2.421250 1.939675 1.366772 0.340043 1.605313 2.242916 1.686149 1.859474 1.180766 1.636452 1.344271 2.410645
+1 0.017546 1 1 -1.342023 -1.884795 -1.071436 -1.579563 1.891038 2.317541 -1.695094 1.660994 0.129817 -0.007547 0.395439 1.675373 46.733149 44.028001 28.615291 37.197389 -23.476531 0.324151 2.248742 0.599875 1.347873 2.198602 1.648463 0.711423 1.894122 0.758817 1.930138 0.825884 1.876191 0.891003 0.586921 1.875807
+1 -0.008344 1 1 -1.654147 1.845559 1.369087 -0.343267 -1.328227 -0.928631 -0.065745 -2.280604 0.451534 1.981088 -1.595387 -0.173502 29.560137 17.230890 -50.439387 65.221691 -19.042315 2.212176 0.284933 2.372332 1.027716 1.067686 2.342684 2.244035 0.254590 0.885878 2.194240 0.344798 0.521299 1.467758 1.109215 0.571248
+1 -0.051427 1 1 -0.108701 1.467896 1.562944 1.546340 0.515960 0.946844 -0.130792 -2.246447 -0.380705 0.909986 -2.275781 1.410516 -47.511650 71.701518 -12.589675 55.337429 56.169442 0.472054 1.817657 0.363300 0.975667 1.539592 2.418672 1.369031 2.297238 1.170944 0.806688 1.006116 0.294639 1.247090 0.338121 0.802122
+1 -0.009828 1 1 -1.154495 2.019021 -0.221049 -1.808216 -0.494104 -1.184289 0.783249 -2.349238 1.468279 -1.418372 1.390673 -0.398994 -5.178768 -39.555994 -17.590134 12.616598 -52.831629 2.257288 2.489134 2.120231 0.727842 1.086298 2.415280 0.602624 0.293804 0.712664 0.251054 2.209440 1.556055 2.361516 1.505328 0.293103
+1 -0.041921 1 1 -0.306228 -0.850888 1.227788 -0.117886 -2.113852 -0.806452 -1.199817 -1.010443 0.933368 -0.421852 2.074161 -1.822795 -15.245603 -32.842920 9.036475 -73.964393 -69.560564 1.308941 0.376387 0.435826 0.430351 0.660398 1.557965 0.717694 1.525930 2.301186 2.286321 2.196104 2.413011 0.718737 1.065299 0.475336
+1 -0.038691 1 1 -0.269517 -1.167662 2.208660 1.466913 -0.806450 -1.180307 1.739188 -0.408647 -2.184664 1.291286 2.085705 -1.013330 -14.927637 61.206278 -6.083100 61.329285 -38.714790 1.682890 1.085281 1.063062 1.136053 1.643519 0.880460 1.136408 0.860159 1.949002 0.627324 1.442460 1.170775 2.465440 2.152313 2.177595
+1 0.014065 1 1 1.864740 -1.418948 1.147383 0.965727 1.505602 -0.872920 -1.504121 2.196581 1.088377 -1.137316 -1.425708 0.619176 49.091203 -74.150232 -42.956923 -27.007264 -11.089059 0.267656 2.246826 2.151777 2.165949 1.856009 1.447273 1.060046 2.196731 1.714346 1.005111 1.409562 1.763567 0.268600 2.353165 0.650737
+1 0.030656 1 1 -1.085606 0.598314 -0.382218 -0.959623 2.127220 -0.711791 1.682024 0.162801 -1.703512 1.556992 0.467299 -1.656977 44.715666 36.195529 -61.738204 66.007799 -6.916353 1.477931 1.092102 0.950140 2.261121 1.652499 1.045102 0.772202 1.902405 0.476161 1.089120 0.336873 2.322190 2.040187 0.917228 0.358544
+1 0.036453 1 1 1.754465 1.881320 -0.779984 0.666804 0.915761 0.540062 0.754676 -1.917576 -0.670771 -1.614162 0.009255 0.032969 -62.132072 46.270586 69.735011 -63.662460 -24.964024 1.069680 2.111359 2.355988 0.844519 2.323090 1.425847 0.956274 1.853803 0.371637 1.595103 1.638648 2.265913 1.205185 0.296507 1.143946
+1 0.041684 1 1 1.988231 0.639846 0.212856 0.763745 -0.279563 -0.356206 -2.012561 0.414567 -1.987956 -0.746659 -0.003767 -2.055789 -13.222617 67.484323 59.008472 -44.615240 1.665875 0.600365 0.577523 1.431661 1.929502 1.396670 1.078127 2.333577 2.184859 2.423315 0.656876 0.859832 0.951210 2.244403 1.932876 1.847940
+1 0.005994 1 1 -2.335398 -1.548078 -1.451444 1.624421 -1.931348 -1.236403 1.402825 1.203951 -0.194549 0.610069 -0.725066 0.045395 -14.317367 -31.988925 -37.866798 22.722447 -3.830746 0.874875 1.781563 1.223296 0.940942 0.662131 1.438905 2.174675 2.264951 0.786350 1.190973 2.178893 1.148865 0.971790 1.630524 0.724694
+1 0.003017 1 1 -0.520857 1.567549 -1.164401 0.468176 -1.052186 1.506576 1.364146 1.422407 0.446055 -0.556384 -1.764077 1.513452 -28.211738 -4.678348 -28.988575 -10.981689 -69.253919 2.115876 1.776294 0.418349 1.438258 0.305280 2.348636 1.019595 1.840705 0.732532 1.158586 2.359033 0.271038 0.578229 2.049206 1.747820
+1 0.011485 1 1 -1.541047 -1.095514 -1.002948 -0.328163 -1.944769 -0.607839 0.515054 -0.149975 0.494860 -0.261498 1.669928 -0.514655 68.177818 14.578766 -74.674386 -2.413252 -59.525338 2.239653 0.851274 1.113530 1.094502 0.791902 2.253310 0.879357 0.607201 0.727139 0.524716 0.407916 1.594650 0.774092 2.166469 1.585430
+1 -0.009396 1 1 1.037240 1.763657 0.852544 -1.674527 -1.384722 1.460406 -1.788003 -0.060391 -1.821592 0.886056 0.795826 1.695327 71.821772 58.523620 56.475562 -15.225358 7.404570 0.604107 0.469231 1.608996 1.147884 2.493577 0.303340 1.242353 1.734331 1.652534 1.633711 0.281942 1.595280 2.364608 1.713895 2.428838
+1 0.004894 1 1 0.846003 1.499334 2.168311 1.897730 1.701296 -1.089292 -0.105773 -1.147729 -2.077606 0.478119 1.117557 -0.793090 59.845737 -72.693742 -13.723678 46.138819 -44.864914 1.455787 2.416200 0.325344 2.053656 2.301236 0.873891 0.988653 1.538987 1.247205 2.282279 1.768497 2.134166 0.927874 1.529717 0.706100
+1 0.027405 1 1 -1.935972 1.164907 -1.386449 0.711761 -2.183494 2.102419 1.865779 1.902638 -0.637544 0.770782 0.170819 1.108077 2.753680 -68.903715 -64.745792 67.476259 73.488236 1.626639 0.673713 0.347062 0.314004 0.465262 2.416737 0.352556 0.408092 2.303845 1.968131 0.383521 1.087549 0.927631 1.946413 2.108012
+1 -0.019034 1 1 -1.336350 -0.797154 -0.451229 -1.579424 -0.497597 1.381743 0.305483 -2.255651 0.437666 -0.189195 1.055804 -1.956862 -38.970469 73.322183 -74.075248 17.300622 71.557844 0.965329 1.027530 2.445058 1.593669 2.287743 1.355754 1.901357 0.856406 1.857464 1.145645 0.853386 0.610049 1.344354 1.558633 0.687937
+1 0.027138 1 1 -2.230839 -1.944361 1.538070 -1.822256 -0.835605 -1.101546 1.293283 -2.041686 1.006231 -1.038902 -1.422065 0.582989 39.485627 34.932214 5.718401 -40.835641 -74.621909 1.068744 2.135522 1.216761 1.346419 0.267011 0.405025 0.254818 2.474659 1.841444 1.904999 1.315119 0.701530 2.112134 1.887950 0.519378
+1 -0.033667 1 1 0.625470 -1.062537 1.894167 -1.639411 -0.246323 2.236783 -1.829023 -1.480909 1.206882 1.949570 1.184845 -0.863846 6.609821 -58.731269 53.559335 21.739184 -29.538536 2.062451 1.616283 2.126380 0.571070 0.974648 2.408460 0.735743 1.134883 2.232120 2.497740 0.512694 0.842729 1.494751 0.273650 1.742889
+1 -0.016355 1 1 1.922298 -0.067432 2.353634 1.738311 -1.017311 -1.398019 -0.531165 -2.022066 0.894415 -0.086109 -0.525652 1.092113 12.298663 3.625148 27.856778 38.865982 -29.432657 1.754921 1.213075 2.409560 1.225981 1.058372 1.058606 0.483479 0.329237 2.236883 1.546817 2.353392 2.212101 1.281343 2.274231 1.506332
+1 -0.014348 1 1 2.306243 1.623889 -1.459150 -0.658227 1.861220 0.690425 2.079126 1.506522 0.447028 1.657189 2.154075 -1.747820 45.413784 69.461713 -6.982449 -54.015502 -38.547166 1.191727 1.357329 1.380296 0.391955 1.082836 0.469681 2.432188 1.287235 2.300303 0.947484 0.359211 2.005201 2.410697 2.336137 2.458522
+1 -0.023603 1 1 0.951688 1.166167 0.935105 0.485122 1.016938 -0.151378 0.475454 -1.248444 1.678556 -1.575653 1.626035 1.626373 -67.361978 47.229568 -12.653441 33.625337 -58.964620 1.849349 2.006693 0.497390 2.384362 0.730819 1.626487 0.370114 0.750240 1.776070 1.162243 0.823364 2.270802 2.370147 0.305728 0.867890
+1 0.047302 1 1 0.562297 2.190842 -1.118599 2.144947 0.357658 -1.853037 0.189446 -1.555915 -1.222128 0.991802 1.501852 2.065542 -19.468409 -55.545089 53.697580 -54.775354 -59.378602 0.982578 0.691988 1.495666 2.163677 1.924472 2.350944 1.569713 2.420733 2.256320 1.973712 1.923969 0.648606 1.376199 1.273658 1.369545
+1 0.019473 1 1 1.967269 1.773478 0.981962 1.051496 1.027344 0.380952 -1.482900 0.719766 0.407325 -1.183275 -1.018113 -0.734919 -19.235534 -41.625954 -7.409420 -30.118350 50.898004 1.266248 0.579243 1.094333 2.461995 0.497762 1.884425 2.025937 2.169640 0.893629 1.971556 1.697420 2.284067 0.317324 2.257363 1.503589
+1 0.029116 1 1 1.302542 -1.942091 1.990180 0.419512 1.011240 -1.680852 0.690746 -1.963733 1.105075 1.473631 -0.992111 -1.970897 -47.057335 57.370333 23.192480 -53.990271 -64.481609 1.489032 0.905812 1.987469 1.390135 1.507993 2.343090 2.306064 1.021931 0.602487 2.496491 2.018022 1.892803 1.092966 1.975021 1.426757
+1 -0.008387 1 1 -2.224978 2.322450 0.692138 -2.131351 1.959491 -1.713922 0.941532 0.134611 0.453875 -1.081631 1.416945 -1.811859 -14.614696 70.796430 -74.397202 6.227963 -26.632681 1.143050 2.244847 0.390093 1.294577 1.950243 1.225117 2.289831 0.438577 1.662381 0.642508 2.390105 0.489443 1.576745 1.353133 0.604803
+1 -0.008241 1 1 1.015382 1.960238 1.407074 1.928272 1.371382 0.526335 0.950117 -1.663010 -1.024430 1.476419 -1.270697 -0.063943 -8.517079 -46.539727 56.804737 -32.784495 -59.001496 1.552802 1.693701 0.532125 1.169145 2.067435 2.121227 1.708027 0.555456 1.799870 0.656820 2.168244 2.172803 2.306991 0.850167 0.504799
+1 0.002908 1 1 1.505823 -1.876824 0.942603 -0.715851 -0.576438 0.483856 -1.411275 -1.844017 0.995021 -0.955855 -0.525968 0.491735 -29.919977 -65.055778 -42.463798 10.953428 44.261003 2.045048 1.617638 2.396390 0.368627 0.515522 1.132340 2.238393 2.170489 1.662117 0.709254 1.428473 2.349081 1.750867 0.568734 2.204748
+1 0.027925 1 1 1.299281 -0.185970 -1.277430 -0.118562 0.670564 -1.866842 -0.924089 0.870229 -1.312343 2.148031 0.340698 0.557546 -71.981218 -38.335065 -47.438088 -41.936799 18.223786 1.182476 1.124686 1.846772 1.452514 1.400477 2.069960 1.817409 0.698763 0.613992 2.357967 0.345073 0.647728 2.360845 1.477942 1.279007
+1 0.022061 1 1 2.169300 -0.327799 -0.530172 0.528820 0.310399 0.263614 0.911360 1.956461 -0.803855 0.034568 1.353040 -1.445283 47.820310 15.958040 6.772307 -27.833981 44.280186 2.381222 1.940563 0.548851 1.035259 1.856030 1.793965 0.420985 0.751294 1.497890 1.278194 1.113598 2.245976 1.367827 2.325351 1.176642
+1 -0.009895 1 1 -1.313251 1.025137 0.979468 1.538933 -1.462538 -1.057093 -0.862104 1.214612 -0.079865 0.743504 -1.187675 0.419789 29.976830 -29.411451 -68.252010 -61.538919 -34.611777 1.072874 1.800606 1.784735 0.545917 1.232004 1.032212 2.382388 1.299803 2.047982 1.427304 0.699656 2.120963 1.771162 1.922020 1.636552
+1 0.011500 1 1 -0.416587 1.026995 -0.783815 2.267080 -1.571013 -0.496382 -1.763454 -2.154446 0.231984 1.813358 2.091083 -0.168839 -26.152109 -38.497630 70.340403 61.148596 74.461017 1.619800 0.475038 2.459381 1.573628 0.718931 2.069345 0.474005 0.858344 0.691928 0.486440 0.602821 1.356964 1.999132 1.668915 2.445737
+1 -0.020167 1 1 -0.835946 -2.112630 0.886762 -1.470265 1.021910 -1.425504 -0.659638 1.714428 -1.858773 -1.968589 -0.391188 -0.907790 47.185819 2.063081 24.198180 48.817817 -18.945883 1.773125 1.156251 1.361797 2.220058 2.261285 2.166706 1.073802 1.649356 2.230475 1.835894 0.862578 2.095441 0.319837 1.756709 2.003185
+1 -0.004639 1 1 -2.308474 -1.424055 0.129139 -1.964840 1.349399 -1.376935 0.394853 1.258262 -1.585429 2.260346 -1.643851 0.537569 40.629454 59.227692 39.816747 50.073605 -62.924356 0.330223 0.803847 0.512519 2.400087 1.753133 0.411854 0.285800 1.185037 1.415483 2.269616 0.442107 2.496335 1.648651 1.635294 2.136806
+1 0.030243 1 1 -0.700980 -0.396752 -0.177867 -1.751899 -1.153532 -0.640854 1.691883 0.922588 2.171744 -1.656747 0.556775 -1.080338 -12.889265 -29.868760 45.754054 -61.606392 31.373144 1.951466 1.535278 1.926181 1.827380 1.778999 0.887578 1.524078 0.436890 0.305953 2.395233 1.176077 1.573972 2.000250 2.454601 2.236498
+1 0.010605 1 1 -2.142709 -0.429257 0.152460 -1.149183 1.768887 -0.769486 -1.952677 -1.561109 1.017287 0.999336 0.891710 1.581302 -29.659031 -29.334539 24.411400 32.391775 58.562935 0.883792 0.889187 1.562731 2.061780 1.590448 2.156766 0.519822 1.391067 1.410734 1.202260 0.639356 1.150441 0.460503 1.173887 0.762212
+1 0.029267 1 1 -2.180002 -0.471653 -0.838439 -1.593106 0.460321 -1.133482 1.763413 1.460863 1.183411 -1.406628 0.857078 -0.871029 64.183396 -69.660250 -29.820217 -38.379821 -49.651177 0.815044 1.950303 2.238446 0.809373 1.132175 1.711525 0.846531 2.404453 0.899934 2.184542 1.604399 0.385871 2.337690 1.556466 0.271541
+1 -0.014371 1 1 -0.672967 -0.820398 0.020109 -1.326667 1.738048 -0.723917 0.511914 -1.089558 0.138533 0.400311 -1.272629 0.455347 2.866174 21.785483 -1.385728 -39.931324 -25.764283 1.820369 0.942358 1.964153 1.019589 1.727953 2.450502 0.841611 0.701245 1.826640 0.587972 1.539181 2.263560 2.157005 2.288729 2.163350
+1 0.003493 1 1 1.587699 -1.806466 0.652043 -2.135219 -1.784060 0.236155 1.230584 -0.257801 -2.176284 0.762522 -1.992618 1.010674 -56.103099 -24.784318 -0.025723 17.677428 -45.475243 0.588941 2.082496 1.010499 1.963609 0.877898 0.837405 2.019944 0.457228 2.386804 1.257320 1.274183 1.201118 1.685694 0.952567 0.297465
+1 -0.005421 1 1 -0.292826 -1.784716 -1.363467 0.551557 0.744500 1.410860 -0.414821 -2.280159 -1.485168 0.300074 1.095324 -2.195659 9.052249 41.146430 48.051887 8.060387 20.927080 0.946403 2.446736 0.535626 1.518401 1.773936 1.284306 0.329406 0.578695 0.871341 0.874020 0.900216 2.427809 1.942241 1.747553 1.118606
+1 0.043778 1 1 0.320913 -2.103676 0.580489 1.628779 0.617028 -1.574626 0.037439 -2.218611 0.934036 1.371100 0.496357 1.336410 57.170793 -30.488142 -14.202614 -53.337531 -43.888457 2.375657 0.659712 1.280457 0.887426 1.224335 0.405313 0.592541 1.842066 1.103759 1.134357 2.393539 1.967074 0.609561 2.133968 2.105839
+1 0.008544 1 1 0.370172 1.119253 -0.575936 -0.509728 0.132486 -2.266785 1.805827 -1.959237 1.282410 -1.008999 1.639901 -0.940369 18.161620 -7.657575 -0.866052 -5.743145 74.960771 1.610107 1.814022 2.261739 0.798343 0.254470 1.127727 1.209141 1.525288 0.515911 0.921037 1.364253 0.749023 1.587836 1.003095 1.259875
+1 -0.030937 1 1 -2.302999 1.056436 -0.766618 -0.872534 0.268811 -1.279484 -1.654792 0.429308 0.717782 0.044830 -0.528669 2.223318 -61.484272 -16.164257 -22.666629 41.969020 73.314792 0.650522 2.078682 2.149627 2.040020 0.357043 1.578222 1.429172 0.602763 0.391674 0.858534 1.630784 0.591104 2.430250 2.467879 0.393208
+1 0.034020 1 1 0.622650 -1.336463 2.024831 -1.546421 -1.871591 -0.638082 1.144766 -0.594648 0.732506 -2.242706 1.243965 -1.553762 62.813249 2.282068 -45.289670 66.524356 -25.153499 0.552046 0.731374 1.959186 0.789034 1.295389 2.110910 1.560689 1.505845 2.243732 1.910774 1.621851 1.203474 0.780485 1.616527 1.724459
+1 0.066213 1 1 -1.333636 -2.303285 0.966858 1.669255 2.312285 -0.506267 1.737173 -1.296548 -0.999113 -1.845125 1.219945 0.015907 -39.853576 -69.055671 -68.663435 73.643137 70.198110 2.419433 0.668285 1.360389 1.059368 2.055748 1.462139 1.171659 1.571253 1.294668 1.243348 0.451961 1.602195 1.588463 0.296664 1.527879
+1 0.024186 1 1 -0.618670 2.258988 -0.900596 -0.119882 2.050604 -1.904849 1.176608 2.067671 2.190660 0.518772 1.079184 -0.136901 -39.791400 -74.062803 -73.538094 45.253528 -73.954701 0.525115 0.359658 0.514365 1.939402 1.285722 1.635936 1.675145 1.403284 1.992047 1.829405 2.058573 1.687687 0.712736 1.460727 2.183242
+1 -0.027098 1 1 0.842778 -0.872481 1.159484 1.725058 -2.274325 2.317496 2.267138 -0.594407 0.072074 0.257839 -1.892939 -1.292725 63.609078 27.776836 45.281084 -60.828126 61.685047 0.483883 0.369677 2.407237 0.426145 1.969254 1.246900 1.653932 0.376865 1.723817 0.434517 0.922702 2.360131 0.714822 0.509177 2.480301
+1 -0.007310 1 1 1.889764 -0.233375 -1.626341 -2.055439 0.757037 0.065903 0.214014 1.383393 -0.236519 2.075174 1.063411 -1.338316 -27.172498 61.827900 -58.492944 9.091600 -47.481148 1.140077 1.779339 2.101718 2.321846 0.772198 1.823709 0.830817 1.538704 0.995134 2.464426 0.850828 0.371851 0.704100 0.303508 1.814953
+1 0.034225 1 1 0.561412 1.450403 -0.258992 1.369514 2.107757 2.046450 -1.035436 0.281905 2.023172 -1.142575 -0.267419 1.103973 57.507583 -70.059140 16.032829 63.765083 -50.257197 1.034465 2.002557 0.730999 2.408374 1.537129 1.529525 1.970614 1.610222 1.493652 2.061095 1.318557 2.237746 0.303947 2.441326 1.860639
+1 -0.048963 1 1 2.183255 -1.412003 0.064367 -2.030821 -0.176930 -0.137161 -0.906643 1.924195 -1.189061 0.699377 1.730661 2.347249 -60.531705 -56.359380 17.897053 45.776251 11.455500 0.363729 1.435086 0.986780 1.562220 2.475717 1.626516 0.859354 1.907568 1.737070 0.434628 0.535717 0.792718 2.461434 2.327193 0.624988
+1 0.004741 1 1 -1.867050 0.294019 -1.710924 -0.493572 -1.653685 0.190332 -0.800134 1.309865 -1.381516 -1.198007 1.140377 1.023343 -28.460668 11.554784 -48.740300 -28.224253 -65.024152 1.961073 0.996941 1.338144 0.686456 0.763504 1.963650 1.565666 1.898036 1.293350 1.578184 0.789285 1.007436 2.222728 2.144423 2.315070
+1 -0.010469 1 1 1.349956 -1.447169 -1.925243 -2.298968 -1.883434 -1.756345 -0.484892 -1.863177 -0.587263 2.327074 -1.691949 -2.036870 58.192253 37.195979 -47.188082 -40.093366 -49.195215 1.015305 1.724385 0.988899 1.182357 1.364933 0.929311 0.922814 1.986475 0.439147 2.240554 2.494154 0.996185 2.135671 1.469593 0.440494
+1 0.042643 1 1 1.159963 0.343156 -0.548531 -1.726448 -2.234044 0.728988 -0.104750 1.901380 1.786779 -1.658898 2.105159 0.790417 9.906803 3.639496 -30.992828 53.540033 -2.662257 0.706757 2.220192 2.272711 0.694821 1.853848 1.125651 2.307341 2.233303 2.130911 2.465947 1.676656 2.051644 2.236725 1.133547 2.267545
+1 -0.038035 1 1 -0.635117 -0.850227 -1.794657 1.202229 -0.866297 1.422308 -1.214876 0.365882 -0.282902 0.058779 -1.699359 0.668475 22.867742 38.139686 63.700554 65.206423 24.343950 0.606638 0.258443 0.406536 0.897984 0.911130 1.362553 1.434946 0.879965 1.818658 1.439103 1.007752 0.782206 1.280855 0.827194 1.391236
+1 0.026221 1 1 2.011903 -2.042293 0.216623 -1.885497 1.275241 1.026251 0.849327 0.812759 -1.180951 0.335698 1.353142 0.274252 20.495469 67.339343 22.334927 -66.882415 7.245690 1.049641 0.564822 1.709009 1.308815 0.507967 2.399061 0.259654 0.503977 0.587252 0.697276 0.368586 2.066502 2.203254 1.093436 0.875306
+1 0.052825 1 1 1.531393 -0.939251 0.503969 2.047343 -0.179301 -2.302241 -0.340336 0.808737 1.915957 1.739654 -2.015265 2.087031 -73.104074 -10.175091 -12.746969 -38.304451 17.094820 2.314570 2.225853 0.656698 2.367778 0.995768 1.868405 0.538179 1.668817 0.803474 0.981235 0.617847 1.911449 1.718300 2.222781 0.780753
+1 0.071047 1 1 -0.476772 -2.039353 -2.198885 -2.114096 -0.195993 -0.089272 -1.856505 -1.546869 0.026238 -1.976903 1.243745 -0.538683 -36.675953 -62.750440 3.351532 -70.808230 26.082092 2.300801 0.308676 0.913644 0.872693 1.108036 1.005485 0.939807 1.834165 1.053678 0.910914 2.238905 1.781346 2.087762 1.764327 1.794345
+1 -0.045079 1 1 -1.509485 1.582227 0.478725 1.887581 0.776547 -1.884205 -0.574478 0.434060 0.474410 0.042118 1.014416 -0.133177 2.586988 -20.490727 12.346401 55.962610 63.591408 1.837038 2.093077 1.086390 1.703525 1.394501 0.625263 0.540819 1.036882 2.121155 0.510716 1.345590 2.086358 0.660375 1.172004 0.615902
+1 0.007527 1 1 1.472975 2.112321 -1.365987 0.622867 2.303202 2.353277 0.444240 1.924564 0.306085 -1.563815 -2.045873 1.308895 37.272879 45.269886 50.970390 9.339790 73.848836 0.285866 2.301715 2.174402 2.170395 2.330905 2.274920 1.823795 2.281702 1.072905 2.321085 1.475145 1.505561 1.956389 1.034993 1.879897
+1 0.036121 1 1 1.135990 -2.018168 0.425387 0.791741 -0.987524 -0.275139 -1.405567 -0.152119 2.157722 -1.721014 -0.446435 -1.111253 -52.143326 -72.877654 45.263522 -55.981642 66.542141 0.981368 0.597224 1.792321 2.044551 2.276785 1.675783 0.880466 1.235214 0.991850 1.277293 1.720578 2.245640 2.475763 2.391959 2.399647
+1 -0.011907 1 1 0.731907 1.833685 -0.286456 1.596720 -0.986692 -0.434704 -1.872368 0.450476 -1.661915 -1.468390 -0.451600 1.623030 -55.797315 14.532931 54.970218 34.446475 -58.092987 1.092561 1.919965 0.859585 1.291640 2.093454 0.682828 0.537850 0.650493 1.581165 1.391089 1.776391 2.062145 0.964515 0.857917 0.261794
+1 0.016904 1 1 2.037048 1.166233 2.057353 -1.572517 -2.214116 1.096765 -1.530764 2.093021 -0.580437 -0.753484 -1.623943 0.543139 20.345412 -54.652584 54.024087 32.838023 58.649295 2.405511 0.667062 1.055633 2.282745 0.601321 0.908100 2.185559 0.683337 2.343291 1.189944 0.633853 0.920039 0.345380 1.305694 2.057237
+1 -0.007724 1 1 -1.346651 0.438033 1.264422 -1.733052 -0.133159 0.376062 1.154233 -1.716961 1.713371 -0.789460 1.631082 1.634080 5.611610 -35.672556 1.347643 -0.166678 48.647192 0.825408 0.624634 1.228126 1.106292 0.954668 1.856480 0.364921 1.223413 0.643799 1.582758 1.156814 1.816880 0.811140 1.584661 1.642983
+1 0.025923 1 1 -0.809939 1.440715 1.840302 -2.164507 0.777750 -0.514547 -0.755463 -1.894864 -0.647966 -0.040036 0.989538 1.138920 3.146296 -70.204956 -34.702353 -42.446050 9.240231 2.133361 0.896424 1.698796 0.661757 1.904874 1.472672 0.455799 0.856600 0.626654 1.419935 0.591645 0.285243 0.827738 1.540410 0.418037
+1 0.045131 1 1 1.575311 2.042889 0.369586 0.701515 -0.029936 1.096489 -1.453972 1.545774 0.415989 -1.666423 -1.844660 -0.395045 7.616920 67.578232 -12.657814 -39.879532 -55.293972 2.488262 0.970096 2.398559 0.828412 1.620570 2.174323 0.851932 0.916079 1.291020 0.673309 0.298627 0.777800 1.485098 2.289766 1.596024
+1 0.011801 1 1 2.227670 0.522118 0.767945 -0.375657 0.935949 0.540794 -1.077844 -0.902839 -0.129532 0.086134 0.946795 -0.950728 26.277459 45.253317 72.505824 5.376320 59.803540 0.896533 1.279656 0.921342 1.997021 2.176621 1.226291 1.769114 1.247187 1.967759 0.876521 2.434182 1.040360 2.079556 1.088539 1.823274
+1 -0.085173 1 1 -0.638899 1.557040 1.271376 2.051000 0.025159 -1.265372 -0.095558 0.887024 -1.787816 -1.629052 -0.497122 -0.067430 -74.081284 65.861485 -66.021837 70.986538 -29.254559 1.654295 1.986581 2.217548 0.585230 0.452727 0.982962 0.400562 1.753420 0.732726 2.169465 2.440192 0.806445 1.416983 0.483783 0.944941
+1 0.022539 1 1 0.423759 1.702479 -0.064950 1.653284 -2.216710 -0.095391 -1.016073 0.551407 -1.777011 0.906458 -0.321861 0.307558 -11.762572 6.460157 -24.139654 34.835881 36.656652 1.950341 0.625323 1.545537 1.081972 1.709998 2.180051 0.372460 1.940862 1.060026 1.858896 0.471298 0.356872 0.953305 1.449805 0.871623
+1 0.000651 1 1 -2.128682 -0.294547 2.273333 -0.146736 -1.607795 -1.371968 -0.938024 2.292299 -1.823580 0.468202 -0.614631 -0.546524 -31.346519 -40.948606 -23.225914 -57.942259 -35.553292 2.212372 1.340081 1.746989 0.644628 2.010911 1.625140 2.483794 2.381180 1.235310 0.349917 1.050663 1.996017 1.056284 1.961307 0.443315
+1 -0.002598 1 1 -0.933914 0.677376 -0.480491 1.426985 1.993995 -1.442359 -1.202742 1.671493 2.241018 -1.340518 -0.162931 -0.481091 24.037977 56.277174 -49.543934 -34.896797 -10.461973 0.859280 0.671445 0.481313 2.174323 0.843268 1.553748 1.835928 1.447613 2.275295 1.389981 1.156708 2.286524 1.114902 1.663658 1.858336
+1 0.029017 1 1 -0.468250 -0.190331 0.811530 1.730458 -1.059292 -0.107840 1.805226 2.079240 -1.288724 -1.450635 1.072185 0.038955 -9.654556 35.877340 -9.552277 -45.125611 -26.150272 1.260555 1.652959 2.036498 1.921695 0.678716 1.178940 2.439444 1.728575 1.663245 1.653108 2.282163 2.060040 1.598252 0.574357 2.223342
+1 0.002003 1 1 -0.320151 0.778342 -0.000882 -0.689857 -1.948617 0.698127 -0.423933 0.083706 -2.155465 1.940037 1.185794 0.952335 -66.621624 40.357227 -16.090865 10.831777 -50.317312 1.629030 0.350405 0.259992 1.691210 1.408104 2.011486 2.297189 0.348324 1.284199 0.775207 0.652585 0.748724 1.061745 1.501318 0.399764
+1 0.004034 1 1 1.308863 0.626379 0.069835 0.337478 -1.722768 -1.643220 1.718114 -1.173053 1.125697 -0.646632 -1.180240 -1.845899 74.597210 55.301725 56.092753 0.896871 73.718090 1.073999 0.445700 2.125120 1.896818 1.074404 0.514755 1.730512 0.458106 1.379811 1.229766 1.672626 1.817617 1.946417 2.173624 0.348989
+1 -0.015536 1 1 -2.115789 -0.386408 -0.692290 -0.437514 -1.966831 0.877441 2.085523 0.636395 -1.227674 2.030456 -1.247884 1.658444 -10.027449 68.673060 -61.887346 -40.615877 18.950495 2.139602 2.288129 1.081796 1.001454 0.686533 2.059551 2.371367 0.557021 1.109883 0.547865 2.469440 1.877730 2.004549 0.457535 0.787991
+1 -0.005469 1 1 -0.340297 1.476540 0.760149 0.540676 1.650685 1.221685 0.973704 -1.088412 0.558176 -1.109025 -1.893286 2.307674 67.560870 -4.458513 65.766002 -20.808288 -74.896204 1.667448 0.298697 1.944647 1.684123 1.559561 0.546830 0.818463 0.903404 2.004498 1.844519 1.833208 0.721322 1.765055 0.523761 2.356483
+1 0.034743 1 1 -0.880588 1.567383 0.753928 -0.339018 -0.597931 2.094002 1.773468 0.814523 0.195923 -1.084573 -0.898928 -0.367279 11.704979 -74.418072 -44.536994 -33.259907 50.744681 0.862745 0.412370 2.202848 1.019116 0.527868 1.628773 0.538285 1.207361 0.871122 1.704306 1.015196 2.142680 2.273233 0.484835 0.626770
+1 -0.021694 1 1 -1.569303 -0.031093 0.494249 -1.092522 2.157240 -0.384549 2.283075 -1.335588 -2.117767 -0.640511 -1.971841 1.503496 45.213390 1.437705 13.500878 -40.745412 -58.134512 1.873831 1.732061 1.740596 1.190889 0.766237 0.643874 0.588937 2.011037 1.504725 1.409215 0.422869 0.906144 0.813094 0.666360 0.512506
+1 -0.028391 1 1 1.074604 -1.717849 0.925576 0.567209 -0.073793 -0.888871 -0.981238 1.690144 -0.029713 0.119066 -1.626714 1.105561 6.867828 -72.408898 -26.353560 25.724634 53.928216 2.447883 1.824729 2.214308 2.380276 1.794286 1.312558 0.403355 1.432040 1.551439 1.281109 0.596259 1.321610 1.790788 1.031854 0.869224
+1 -0.018133 1 1 0.076948 2.071315 2.168524 0.763157 -0.745245 0.193920 -1.758417 -2.327234 -0.990620 -0.472752 -0.455516 1.772005 -6.478980 7.786852 73.614469 38.372773 -68.798574 2.160522 0.651650 0.779280 1.606006 0.393865 1.696180 1.696013 1.135845 0.401483 1.482075 0.981106 0.695772 2.084492 0.806416 0.925718
+1 -0.005042 1 1 1.192625 -2.048155 0.654199 1.110699 1.742885 0.459743 -1.415165 -1.258335 0.371752 -0.589956 -0.523579 -1.755917 63.733232 14.436755 -61.451305 -62.089010 20.005865 0.453683 1.301829 2.341044 1.682791 1.674087 1.628302 1.622785 1.151118 0.587716 1.735355 0.858100 1.089658 0.389407 1.017139 1.053815
+1 0.071108 1 1 0.580532 2.352493 1.399364 -0.428397 0.468805 0.097527 -0.780740 2.108608 2.203839 0.551193 -0.660509 1.215854 61.917749 -48.389517 17.390275 -71.639891 -1.651791 1.200275 1.025819 0.696294 1.857073 1.328914 0.809169 2.203251 1.033863 0.892547 1.794730 2.020426 1.800512 2.455442 0.621226 2.439531
+1 0.049498 1 1 -1.870559 -2.145135 1.211299 0.775035 0.975356 -1.592168 2.083652 2.168471 -0.119846 -2.053987 1.595271 -1.765290 -1.057872 70.341740 -66.378376 -71.357219 -50.777597 0.338857 1.926639 0.528962 2.012879 0.960713 2.208973 0.467085 1.547534 0.908564 0.984467 0.938266 0.685312 1.783217 2.024221 0.333322
+1 0.006943 1 1 -0.200572 -1.649345 -2.270830 -0.195686 0.358788 -1.713283 2.260233 1.174926 2.063467 2.220479 2.179375 -0.638966 14.004180 18.259406 -14.155249 -7.276034 -38.306138 1.206087 1.946167 2.471210 2.377303 1.333110 1.580348 1.158170 2.116843 2.286697 1.766004 0.735581 0.655983 1.603266 1.595095 1.520032
+1 0.029827 1 1 -1.251504 2.084093 0.170731 -0.363766 -1.845802 -0.737754 -1.136173 -1.060612 1.256858 -1.624381 -2.096089 0.858476 -29.346748 -30.785437 -60.837325 57.082166 -20.028566 1.073249 1.348671 2.116877 0.594314 2.386103 0.731379 2.039907 0.719781 0.608683 0.878370 2.021976 0.850893 1.461904 1.721463 1.384981
+1 0.057191 1 1 1.119229 -0.979413 -0.620008 -1.385963 -0.534715 -0.425853 0.804587 -1.865944 0.027714 -0.728922 1.226003 -1.845608 -69.924139 35.000977 -38.576521 -55.582337 27.656520 0.971933 1.770885 1.772100 1.932794 0.460466 0.548826 0.615224 0.571594 0.773027 2.262393 0.533238 1.872579 0.928926 1.203393 1.667347
+1 -0.002705 1 1 1.137090 2.341430 -0.741994 -1.703824 1.013890 0.451877 -1.670207 0.532290 2.086361 0.581129 -1.746948 1.934916 -1.918207 10.693300 22.294998 12.034204 58.871561 2.189951 0.255755 2.469743 2.464977 1.125487 1.806535 2.430180 1.288970 2.211566 1.297626 1.441053 2.280301 2.272010 2.426294 1.218742
+1 -0.020474 1 1 1.670022 1.064401 1.154149 1.597790 -1.849287 1.947072 1.605638 -1.887154 1.696864 -0.191291 -1.170209 1.801514 30.349506 -65.848780 -20.449765 -49.205070 -39.618929 0.994894 0.689795 0.641538 1.829867 0.824922 1.462533 1.047716 1.954788 1.128710 1.986501 0.876897 2.010774 1.577739 2.309352 2.272369
+1 0.002406 1 1 1.347968 -1.870739 -0.453402 -0.388380 -0.839918 1.815316 2.012593 0.131602 1.719843 -0.388007 0.709700 0.877781 -51.788834 35.073906 -12.869656 -0.313655 -21.601477 0.534733 2.255848 0.791413 0.771863 0.708375 2.414740 0.531687 0.570630 0.332022 1.793189 0.877208 0.487259 0.854581 0.443737 0.644393
+1 0.024598 1 1 0.680724 -0.751824 -1.997879 2.129943 -2.064608 2.169817 -1.059049 -0.738067 -1.681561 -1.808070 1.962126 0.159461 -41.240481 21.241835 11.523429 24.279343 62.925804 0.534872 2.335316 2.159058 0.784580 0.688917 1.619968 1.060263 1.344856 1.002377 0.452960 0.392181 0.387860 2.011521 0.627733 1.558373
+1 0.041018 1 1 1.228849 -1.144602 -1.349166 0.580744 1.207519 -1.488523 0.474522 1.929461 -2.214652 1.500882 -0.098500 -1.441979 14.956574 -24.858866 -52.955439 -72.056642 44.010297 1.840845 0.833729 0.990900 1.059927 2.443670 0.761693 0.767962 0.391423 1.148742 1.151849 1.621703 0.962264 1.270026 1.075321 2.415629
+1 0.034353 1 1 -1.241916 -1.709214 -0.035401 -1.218701 2.044751 -1.322848 -0.059024 2.301778 1.972476 -0.254241 1.101210 -2.228208 -4.121205 34.908101 50.446696 57.611609 28.319664 1.653986 1.296425 1.506234 2.031848 0.269953 0.346690 0.824419 2.016359 0.940209 1.846905 1.428914 0.764106 0.827287 0.719701 1.509051
+1 0.015542 1 1 1.428009 0.358560 -0.824669 -1.068301 -0.729821 0.239642 -1.428831 -0.032994 1.534555 0.369362 1.647775 -0.561371 -24.059845 26.187917 40.321164 -22.199336 -54.248297 0.608027 1.114879 1.264790 0.817847 1.810070 1.097919 1.972903 1.839533 1.273975 2.194924 0.585450 1.907237 0.684989 0.856954 2.080914
+1 0.026485 1 1 1.296461 -0.463510 -0.631717 -0.257994 -0.708307 -1.024524 -0.108575 -1.119822 0.434031 -0.022855 2.285226 1.831737 -1.198460 -42.512316 -54.497117 -33.037662 36.015980 2.433631 0.792327 0.386427 0.431764 1.915561 1.089027 1.023006 0.658478 0.795804 0.333205 1.425973 0.819341 2.168722 1.208293 0.784833
+1 -0.032469 1 1 1.759724 0.723253 -2.258027 -1.795312 -0.381904 -0.386684 -0.618486 0.643083 -1.931880 -0.745469 1.138409 0.943724 -23.398664 38.655926 40.145389 23.553667 16.479043 2.324213 2.306290 0.307920 1.711541 1.120991 0.487377 0.595175 1.106694 0.952264 1.956097 0.621814 1.073789 1.427549 0.318021 0.475457
+1 0.000257 1 1 -2.256010 -0.873665 0.115227 -0.177281 -1.331985 1.885321 0.489479 -1.149619 -0.848248 -1.534432 1.705520 -0.778701 -42.157808 53.725627 -33.386481 23.408381 -25.341122 0.501464 1.099089 1.382295 2.482810 1.584924 1.568596 1.634905 2.347880 1.817615 1.910723 0.762657 1.222016 1.917004 0.587744 2.221601
+1 0.058041 1 1 1.961390 1.924525 -0.343462 0.116035 -0.730808 -2.207129 0.715815 -0.034826 -0.989499 -0.485980 -1.300497 -1.391770 25.992689 59.121722 58.774982 -68.874573 -24.952820 1.644234 1.645060 2.016880 0.709093 0.967798 2.038851 0.964117 0.907567 2.222920 0.864307 1.901294 2.053279 0.468269 1.198984 1.818322
+1 0.038829 1 1 1.844817 -1.682536 0.661352 -1.181389 -2.316327 -1.460504 0.150122 1.977525 -0.215850 0.752165 -1.705381 -1.589133 40.467315 34.164962 10.516957 58.499048 -56.493769 1.513456 1.895973 0.359290 1.081888 0.288854 0.772329 1.785635 2.165306 2.303988 2.124006 1.171707 2.386125 1.094748 0.424988 0.530384
+1 0.029701 1 1 -0.110690 1.023008 -1.813516 -0.029656 1.089292 0.091389 -0.264750 -1.155449 0.117756 -0.077168 -1.063980 1.195194 -40.892195 24.883937 24.326768 -40.006619 58.756418 2.411709 1.337629 1.033759 1.386844 2.442524 1.756189 2.263780 1.348731 0.873778 1.338448 1.288830 2.114102 1.208836 0.913898 0.633782
+1 -0.008278 1 1 -1.220503 0.041123 -1.566859 -1.373503 1.527981 -1.740082 -0.477434 0.957976 -1.526762 -1.322243 0.681938 0.799988 30.414938 -16.130808 -60.494612 -32.939763 31.410722 2.425039 0.384385 2.117131 0.364594 2.487719 0.835414 2.300101 2.042420 2.457381 1.702943 0.610563 0.980745 1.376311 0.905373 1.361677
+1 -0.027496 1 1 1.111395 -0.699718 1.954712 -1.925919 0.486812 1.141337 -1.681379 1.254667 -0.751839 -2.251509 -0.628544 1.244428 48.523844 -9.754319 9.157946 17.600378 9.548655 1.138735 1.714285 2.232872 1.634248 0.313310 2.296281 0.843643 1.101355 1.223109 2.293098 1.348362 1.422265 1.505114 1.204392 0.462017
+1 0.010183 1 1 0.396009 1.831035 2.300432 -1.784814 1.694518 -1.908784 1.010547 0.809475 0.184897 2.096801 1.684412 -2.119592 53.139288 12.021100 -11.376557 44.203697 -18.472500 1.865504 1.279350 0.291040 1.503826 2.053843 0.935063 0.853482 2.216161 2.016161 2.121643 1.950710 2.326677 0.965230 1.615403 0.824417
+1 -0.065845 1 1 0.031825 -2.337428 2.039303 1.353096 -0.506442 -1.202898 -0.963831 2.087150 -0.295770 0.566657 0.070497 2.033839 -29.680567 58.704492 -53.598655 67.406109 -55.523379 0.903497 1.316498 1.386468 0.615721 2.167289 1.882640 1.281347 2.353315 0.912797 2.371022 1.512161 0.381368 0.899264 2.184223 0.730859
+1 -0.022679 1 1 -1.229648 1.842407 0.225442 0.249567 0.444537 2.202234 1.841435 -1.981787 -0.725700 -1.175682 -0.639403 -2.203219 14.058647 33.685166 46.579824 17.104354 72.877032 0.539236 1.440717 1.129731 1.139927 1.495216 1.336682 0.857757 2.070032 0.771606 0.878998 1.321286 0.851865 2.043290 1.333973 0.333675
+1 0.045382 1 1 1.597821 -1.325689 -0.682544 -1.557509 0.261332 0.266510 -2.247926 -1.677185 1.058773 0.817146 1.866350 2.085997 -26.069933 -7.366116 -52.302401 -46.455397 -25.850747 0.272430 1.480009 2.254519 0.956019 2.063642 1.381155 1.314648 1.792457 2.081299 1.145414 1.466848 1.569262 1.580477 1.081708 1.758482
+1 0.040292 1 1 -1.021754 -0.682282 -1.877162 -0.022379 0.867365 -2.329861 1.972933 -1.990865 2.212290 1.211174 -1.317697 1.688281 52.400111 38.659328 -52.678288 -63.981274 16.720871 0.290270 2.071234 0.731395 2.298764 2.082124 1.504714 1.231484 1.298353 2.425981 0.462585 2.421974 0.613604 0.343536 1.802126 0.323495
+1 -0.015292 1 1 0.241085 -0.746787 -2.158866 1.341314 -0.610480 -1.469857 -1.542653 0.195428 0.028284 -0.589746 -1.699348 0.850593 -47.092580 65.001836 35.853269 35.899174 57.413264 1.295846 0.784880 1.229253 2.053404 0.310962 1.088155 2.125424 2.493399 1.804154 0.673101 1.312984 0.812904 1.970443 0.977873 0.369155
+1 -0.012969 1 1 -0.044392 -1.533465 -0.888485 0.787821 -0.897484 0.344085 0.939890 0.796881 0.574971 -1.570926 0.954808 1.765597 15.154530 2.192926 -43.490363 7.470778 11.359504 0.912697 0.696233 0.846262 2.381655 2.481584 1.224787 1.247699 1.578317 0.770845 1.587351 1.862864 1.911814 1.102159 1.227705 0.784984
+1 -0.056193 1 1 0.216495 0.668696 -0.271773 -1.387643 -0.509820 -1.417139 -1.433844 0.539030 2.269694 -0.041839 -1.047320 -1.534550 -8.754174 18.599014 -6.368887 58.115464 -53.398922 0.989779 2.473279 1.144602 1.332437 1.510084 1.481417 1.183082 2.310980 0.381863 2.475537 0.849930 1.026305 2.111987 1.663328 0.803261
+1 -0.003099 1 1 0.023657 1.765279 -0.152867 -0.983117 -1.611323 0.599176 -0.023386 -1.920517 1.732715 -0.826291 -0.062042 -1.301682 71.679317 64.275649 -19.172757 -36.534722 60.923963 2.110589 0.670156 1.315426 1.366188 1.773334 2.429191 0.420023 0.321876 2.270381 2.045845 1.509799 1.183526 0.777248 1.201952 2.202351
+1 0.003432 1 1 1.553994 1.915570 -0.061935 0.495413 -0.378570 -0.899883 -2.275331 -0.444790 -1.741548 -1.555358 -1.282736 0.233216 -33.476384 12.415096 10.513691 3.597851 19.076186 2.326836 1.373816 1.725884 1.429945 2.339680 1.250794 1.840275 0.257370 0.373137 2.065380 1.339611 0.587652 0.674393 0.516695 0.593168
+1 -0.085169 1 1 -0.100809 2.157173 -1.519264 2.174088 0.035962 1.234584 1.010741 -0.639581 -0.483752 -1.551890 0.457414 1.855157 -72.008131 -40.662424 -13.365158 71.785343 46.254230 0.547730 2.446762 0.981160 1.602952 0.807013 1.975028 1.553122 0.323035 1.491969 0.775473 0.626535 1.673970 1.910882 1.193220 1.690606
+1 -0.055637 1 1 -2.071920 1.797998 -1.591766 -0.572818 0.056400 0.716691 0.560966 -1.336422 -1.991690 -2.229780 1.715570 -1.530189 74.274371 29.360920 -31.010797 51.534140 34.284428 2.400644 2.130894 2.192474 2.167493 0.812674 0.354490 1.414353 1.286177 0.270285 1.433656 1.698899 2.392983 1.622647 1.081265 1.064243
+1 0.010557 1 1 0.519423 -2.120510 0.379234 -2.072109 -1.382278 0.128212 1.300177 0.718368 0.473300 0.233001 0.057028 1.856446 17.768141 -20.858205 -13.854031 -44.702597 33.446828 0.487597 2.034946 0.590181 0.414933 0.280730 1.483769 2.453281 0.288281 2.384531 1.313350 2.480079 0.681730 2.343961 1.193785 2.199398
+1 -0.026049 1 1 1.088545 1.690674 -0.548935 0.904279 0.757471 -2.051479 1.343356 0.726077 -1.914655 1.305098 -1.394650 -0.466366 -48.070992 -29.166535 -1.952359 36.710118 36.950804 1.857494 1.655858 1.249102 0.404411 1.184429 2.453990 0.965732 1.058848 2.308120 1.814994 0.596876 0.450338 1.327014 0.378539 0.608121
+1 0.019906 1 1 0.704174 2.245043 0.343634 -1.928036 -2.121435 -1.026757 0.055484 -0.525549 -1.892922 -1.009221 -2.096834 -2.246440 -8.184302 -3.565028 -67.425157 35.386919 -2.059765 1.848048 0.390800 1.925310 0.692618 0.822817 2.077446 1.632891 2.246636 1.204662 0.506035 1.426063 2.345806 0.713344 0.414841 0.979877
+1 0.003137 1 1 0.095268 -1.042987 0.604486 -0.320654 1.747252 -1.538895 2.089292 -1.991013 -0.283735 0.200716 -0.643805 -0.779259 -40.763926 -69.312519 -35.508712 55.072493 -46.602260 2.212194 0.600633 0.593630 2.135202 0.346707 1.107507 1.119694 1.190318 2.430827 0.902659 0.736835 1.478101 1.685374 2.339346 2.391042
+1 -0.004190 1 1 -0.373804 -0.913266 -1.007362 0.885244 1.284554 2.043183 0.605249 -1.634554 1.274650 0.519925 1.613195 -2.123692 -39.731897 26.007487 7.837084 17.875052 -23.999739 1.170806 0.743526 1.447453 1.835611 0.614098 1.903432 1.975011 1.264805 1.069573 0.308603 1.948601 0.631084 1.631765 1.322504 1.076199
+1 0.030288 1 1 2.182798 0.339152 -1.867194 -2.131490 -0.364005 -1.151513 0.303954 0.331065 -1.129285 1.610374 2.308428 0.651954 34.350148 -27.070211 -19.029481 -28.488080 0.846558 1.046383 2.058079 2.387688 0.369384 1.982347 0.806622 2.152663 1.301697 2.380404 1.703383 1.266977 1.582714 0.422522 1.829868 0.841897
+1 -0.041653 1 1 0.167962 0.218056 -1.379153 0.817448 2.229031 -0.174003 1.921579 1.977300 0.718903 0.033224 2.338123 0.221779 -1.921733 -48.565620 57.624515 -54.783860 -52.332324 2.134578 1.106688 0.853934 0.815327 2.196546 0.843532 1.489978 1.064804 1.156899 1.002886 2.259122 1.815993 1.645139 1.100946 1.094499
+1 -0.052324 1 1 2.082624 -0.968710 0.199249 -1.733641 -0.601129 0.194151 2.126875 -1.802427 -2.150446 1.484999 1.571563 0.327197 -5.101328 61.986041 49.384319 52.249075 50.205025 2.062756 2.240863 0.932567 1.657457 1.127967 0.738050 1.652864 0.435105 1.817174 1.245715 1.982196 0.521161 1.394665 1.129098 1.749066
+1 -0.032775 1 1 -1.172662 -1.723623 -1.868506 -0.627529 -0.557671 0.166374 1.805078 -0.416896 0.553634 -2.034083 1.545409 -0.994921 -66.158037 31.876838 -45.987632 35.867874 -18.633798 1.701315 0.259134 0.763920 2.202917 2.170643 1.991673 2.301150 1.681458 1.765262 1.766783 0.328629 1.016163 0.409880 0.861458 1.275380
+1 -0.009865 1 1 -0.762694 -0.901204 -0.921180 -2.082782 -1.690440 -0.227820 2.208011 -0.026382 -0.432526 1.754751 1.972668 -1.737044 -39.792580 56.102046 7.091636 -60.875043 23.150952 1.345818 1.407230 0.816235 1.718326 0.403558 0.350804 2.460167 1.270483 2.013449 1.536051 1.411055 2.105138 1.297751 1.306480 1.753863
+1 -0.007107 1 1 1.560001 -0.801878 0.270488 -1.364126 -1.093356 2.287817 -1.749461 2.124466 0.132549 -1.216085 -1.115635 0.114328 -36.638379 -31.243444 41.438578 8.177825 44.699449 2.329575 2.410312 0.367895 1.718715 2.446534 1.644950 2.415911 2.213161 1.097777 1.833388 1.498208 2.129424 2.221246 1.973592 2.164304
+1 -0.034890 1 1 -1.984652 -1.752291 1.673180 2.312050 0.262374 -1.084425 1.585959 1.941857 -1.214753 -2.284717 2.019139 1.754919 2.453991 -5.775747 -22.979385 35.473414 -48.329675 0.972208 1.901382 1.281953 1.277387 1.051631 0.266334 0.279432 2.171672 1.289072 1.688619 0.622873 0.873107 1.313563 1.551057 1.618900
+1 0.015390 1 1 -1.433373 -0.962256 0.282973 1.124102 0.810975 1.826729 0.627830 0.892248 1.193708 2.013445 0.309939 1.956201 -14.775160 73.883977 67.996291 -36.343457 -24.475084 0.583851 2.037212 0.423282 1.094731 2.395123 1.587733 1.531377 1.610515 1.916464 0.507335 0.771935 1.911339 2.127773 1.481143 1.077133
+1 -0.006456 1 1 -1.044461 -0.601857 2.082324 -1.288719 -1.361457 1.347255 0.291865 -0.227819 2.216530 1.788968 2.134922 1.510557 73.176750 31.643976 -59.696629 28.764486 -5.287902 0.268507 0.797469 1.312477 1.301469 0.785090 0.255011 1.215234 0.430696 1.961299 0.300768 0.754702 0.274386 0.611172 2.225748 1.142119
+1 0.003073 1 1 1.120326 -1.396340 -0.582024 0.841910 -1.325766 -1.971273 1.623678 -0.288950 2.096991 0.176235 -2.105296 1.624145 -59.459674 -38.738602 70.319924 16.966008 -2.309491 1.890763 0.558338 0.739934 1.816255 1.540921 2.259648 1.646579 0.559954 0.903242 1.542150 0.418087 1.535820 2.023690 0.404229 0.378612
+1 -0.053604 1 1 -0.085055 -1.663822 -0.533305 -0.296506 2.329435 0.290607 2.201040 0.631065 -1.274395 -0.944357 -0.477799 -0.454998 33.370109 1.421172 35.632681 -71.529425 54.945743 2.471599 2.162953 1.007886 0.789511 0.304324 2.031037 2.388235 0.569396 2.092492 0.258041 0.397828 0.797592 1.133581 0.593652 0.254910
+1 0.002470 1 1 1.342918 -1.918683 -0.426152 0.494130 1.607534 1.703275 -0.823720 0.741426 1.591866 2.264360 -0.147569 -1.479615 -19.610999 -52.058793 -2.140407 26.174506 -35.072401 1.947332 1.812647 1.660850 1.911948 1.109587 2.322895 0.389611 2.192682 1.157152 0.756455 0.494676 1.763764 1.322638 1.082341 1.160595
+1 -0.044983 1 1 0.623876 0.415133 -1.900930 1.066616 0.685307 0.870245 -1.041526 1.591867 2.272216 -0.064872 -1.743822 -2.065260 19.854442 -56.394404 29.249994 54.655303 -8.324352 2.014217 0.954221 1.092244 1.099729 0.891579 1.261100 1.801500 1.055495 2.195811 1.996626 2.297906 1.152792 1.718164 2.177651 0.535154
+1 0.034936 1 1 0.537580 1.459931 -0.344546 0.742334 -1.993904 -1.742276 0.360807 -0.753206 -1.661088 -1.722334 0.942051 -0.573626 19.766756 -30.129867 7.322152 63.405488 56.031455 1.684839 2.337544 1.356920 1.252497 1.213926 0.948000 2.286385 1.016293 0.337468 1.073902 1.072313 1.366530 0.773961 2.206128 2.137343
+1 0.045756 1 1 2.024308 -0.897969 1.623976 -0.001395 0.108074 2.124950 -1.170429 -1.889526 -0.468917 -1.977494 0.746750 1.540225 45.075914 -59.118987 -12.809933 -46.541883 20.570604 1.077113 1.033871 1.021078 2.006940 2.387731 1.096966 1.708591 1.033203 1.041502 1.024307 2.280641 1.229652 2.014813 1.962731 1.864940
+1 -0.060786 1 1 -1.849479 -1.277462 -0.657982 1.275213 0.567378 -1.945874 -0.324900 1.057710 1.796690 -0.014375 -1.276665 -1.405097 -53.542870 -45.016767 3.190365 70.470499 -2.316055 2.485874 1.327266 2.366753 1.766534 0.642187 1.480219 1.288958 2.026140 1.088580 0.261957 0.962051 2.184238 0.985772 0.364172 2.139151
+1 0.047453 1 1 0.409094 0.263820 -0.327476 0.182250 0.025810 0.248392 -0.453119 -0.347079 0.574398 -1.781209 1.029844 -0.021401 -49.295180 -54.092992 9.083161 -39.313743 3.926642 1.300975 1.484456 0.507097 1.282823 2.403416 1.461642 1.820927 1.317073 2.043689 1.281911 0.576025 1.009862 0.256484 1.233198 0.852499
+1 -0.002423 1 1 -0.404981 -1.822058 -2.223845 -2.214042 2.324825 -1.788675 -1.931272 0.042036 -0.360135 -2.081109 -1.852495 -0.127336 -22.894352 -35.368557 10.664461 -12.397137 -8.685064 1.076869 1.428062 2.186080 0.448751 1.660060 2.127821 2.287193 1.101240 1.544940 2.308424 2.437442 1.841901 0.573176 0.362835 2.162249
+1 0.014876 1 1 0.542891 1.180662 -0.491735 0.936202 0.079408 0.995959 0.681712 1.709035 1.735874 0.441126 1.422425 0.749475 6.497209 -1.404452 -54.630023 -16.802409 51.905541 1.021301 1.255332 1.622136 1.482399 1.937375 0.954958 2.230039 1.260975 1.963597 0.667449 0.819167 1.481732 1.969844 2.158981 1.749539
+1 0.003293 1 1 -1.540007 2.255613 -1.083082 0.607220 -1.494709 0.178837 -0.786270 -1.293906 1.003980 -1.168120 -0.773560 0.265766 -19.788738 -39.313894 1.388550 -62.639704 64.491099 1.403531 1.636596 1.526454 2.113107 2.483512 2.129707 2.480097 0.986055 0.625084 2.028936 0.830453 2.169074 0.375909 1.400671 0.825749
+1 -0.024692 1 1 1.092432 1.039786 2.153395 0.961506 1.257266 0.514373 -2.163586 2.117025 2.297109 -1.093960 1.548995 -1.995064 73.761082 -47.486648 41.912980 31.446861 -72.604606 1.140852 1.301844 0.346045 1.229889 1.495596 0.981563 1.628106 0.584067 1.157162 0.925276 0.613419 1.737267 1.499972 0.271228 1.524464
+1 -0.039398 1 1 -1.022722 1.908109 1.783753 -0.681744 -2.254872 -0.601435 -0.246827 -1.525874 -0.537953 1.699889 -1.182607 0.784097 -71.218548 29.865471 48.967908 -46.368153 -59.544074 2.016320 0.290178 0.528604 0.495472 1.639424 1.795233 1.486041 2.397884 0.736946 1.107949 1.805744 0.393007 0.765492 1.620540 1.673391
+1 0.006217 1 1 2.000994 -1.612241 -0.692817 0.140570 1.650788 -1.760769 0.556613 0.906073 -2.066210 -1.203094 0.460995 0.775055 41.822284 7.123312 21.512552 61.458723 36.756029 2.253629 1.737384 1.205417 1.947978 1.408833 0.751855 1.931120 1.582888 1.098013 1.306423 0.794630 0.843321 2.449429 0.796555 1.693106
+1 0.011735 1 1 1.673048 0.091451 0.779680 -1.067693 0.057057 2.340692 0.987776 -0.194029 -0.076002 -0.302489 0.740294 1.420358 -31.943717 -28.050000 13.654096 -15.609699 -2.203955 1.497018 2.384856 2.274884 1.231312 0.660758 0.855397 0.650823 0.380587 1.278798 2.264286 0.849900 0.514437 0.896029 1.808440 0.708683
+1 0.038854 1 1 -2.109110 -1.219992 -0.803646 -1.177751 2.291608 0.704919 0.629678 -1.023758 -1.367301 2.085742 -0.402620 0.163597 71.485812 -37.952922 -74.768069 73.060171 22.295996 1.807186 2.118727 2.440297 0.318047 0.915796 1.035532 1.939210 0.309235 1.314703 0.458424 2.237872 2.419902 1.793688 0.265659 2.437808
+1 -0.019256 1 1 -1.526100 0.367221 -1.343702 -1.830137 -1.351174 -0.172984 0.199327 -0.420718 2.290959 -0.777238 -0.295075 -1.892506 40.760306 8.462889 35.782789 51.327706 14.759062 0.708318 1.448481 1.113288 1.526341 2.469434 1.784524 1.488146 1.764852 1.608907 1.900880 1.840075 1.384127 1.771070 0.365461 1.296250
+1 -0.003842 1 1 -0.412174 -0.197182 -1.228277 1.327814 -1.311730 -1.688597 -2.242040 -1.696641 -0.788051 1.751615 1.097110 -0.445919 -59.100676 -5.068093 20.556363 40.785433 -19.224269 1.340732 1.426220 0.483103 0.758156 2.084992 2.452069 2.423917 1.777680 1.219596 1.757799 2.324215 2.326170 1.446786 1.887961 0.706988
+1 -0.052066 1 1 -2.283679 0.623172 -1.987018 0.896514 2.201754 -1.509041 -0.378189 0.782581 0.552865 -0.831083 -0.499012 1.162886 74.854610 31.437685 73.171701 -53.224781 51.105636 1.861463 0.859210 1.749245 0.310440 1.320487 0.925771 2.191189 0.809577 2.304936 2.303178 2.011324 1.827198 0.975242 1.138214 1.955720
+1 -0.001815 1 1 -0.919131 -0.624149 -0.297035 -1.839796 1.239669 1.644575 2.204439 1.207402 1.259664 -1.596672 1.796338 -1.219047 30.145036 -52.387174 28.774820 18.392928 -20.056173 0.863601 1.298454 1.861581 0.597938 0.290439 0.406442 1.570910 2.277401 0.784190 0.878824 0.652680 2.345679 0.834340 2.256101 0.541882
+1 -0.019631 1 1 -0.972232 2.269012 -2.081709 2.201066 1.066518 -0.960245 1.091580 0.851602 1.348773 2.231695 2.192477 -1.916702 -3.629869 42.799099 74.460933 14.895978 6.701964 1.223556 0.802756 2.413948 0.724985 0.327487 2.066816 0.722213 0.975854 2.429776 1.239831 2.086962 1.812982 0.535570 0.574717 1.526286
+1 0.004878 1 1 0.077933 -0.228714 1.320933 0.860342 2.153100 0.710759 -0.171653 -0.990851 0.354935 -0.487386 -1.357926 -0.566612 21.904272 45.106200 -0.097800 6.277558 56.909690 0.342450 1.550301 2.402762 1.719405 0.537489 1.319181 1.470951 0.770991 1.802358 1.984809 1.686402 1.600347 2.029143 2.053488 1.726594
+1 -0.067452 1 1 0.845928 0.230816 1.026861 1.685404 0.422884 1.129627 -0.582731 -1.616964 0.033843 -1.406265 2.238371 1.308846 10.928146 69.344328 -29.884917 74.198216 -50.587379 1.043890 0.663192 1.267402 1.966447 1.333530 1.892148 1.322483 0.721705 1.449258 0.672843 1.470558 0.913072 0.257647 0.516101 1.864929
+1 0.005875 1 1 -2.218548 2.004910 -1.780468 -0.652829 -1.654871 -0.892319 2.335837 -0.505204 0.755563 -1.141104 0.884340 0.228156 -40.235975 -46.036454 -34.674114 -17.840539 4.058140 0.702477 2.283963 0.812237 2.013759 2.243271 0.907632 1.067023 2.452476 0.258521 1.715772 2.479758 2.036355 1.764535 0.785448 1.772190
+1 -0.006981 1 1 -0.325555 -0.512740 1.336273 -0.502086 1.331500 -0.608492 -1.042635 1.802703 2.077968 0.899708 -0.655594 -1.006737 62.191980 60.610994 38.977188 39.595890 -61.871201 0.335912 1.925208 1.221041 1.291136 0.380216 1.790059 2.271463 2.228747 2.043000 0.955713 1.416294 2.398657 2.483478 1.561242 1.798624
+1 0.048250 1 1 2.276807 1.702582 1.672214 0.206096 0.242620 1.499818 0.880270 -2.202540 -2.269394 0.368745 0.711602 -0.141134 -54.534482 -61.046271 -4.679766 -52.831609 59.146732 1.811980 1.701472 0.645462 0.280932 0.366909 0.884881 1.201130 1.890983 2.004519 2.202869 1.369682 2.000012 0.707970 2.353644 1.950227
+1 -0.030047 1 1 0.249261 0.012336 -0.008554 2.323966 -2.095837 0.370020 -1.434012 -2.277453 1.580426 -1.510409 0.203232 -0.759925 -47.181522 70.168046 14.356151 -66.178215 -7.256569 1.207688 1.865586 0.400783 0.953616 2.174546 2.348422 1.936801 0.314360 1.950111 1.257944 0.509254 1.539924 1.258595 2.464794 0.292674
+1 -0.023287 1 1 0.958253 -1.594002 -0.453200 -1.719823 0.725135 1.113624 -0.933151 -0.630919 -0.982575 -1.923974 0.174018 -1.666363 -26.715330 -54.558947 -22.220624 37.967667 22.575964 0.388500 1.527126 2.155671 2.365148 1.787331 1.428335 2.273751 2.433827 1.832331 1.735464 0.452378 1.870781 2.216878 0.576739 1.753736
+1 -0.010452 1 1 -1.877446 -0.085550 -0.555944 0.918154 -1.660235 -1.512574 1.509198 -1.706620 1.148162 -0.076066 -1.390106 0.507633 -74.931326 29.197720 -73.924692 -2.306626 -67.469523 1.970815 0.482250 2.174478 1.203288 2.156484 0.282630 1.909433 1.587684 0.698509 0.839291 2.220385 1.012933 2.364872 1.657909 1.972044
+1 -0.062569 1 1 1.084207 -0.549563 -0.219101 -2.054108 -0.429379 -1.906453 -2.226250 -0.223119 1.104797 1.516604 0.250635 -0.456488 -13.442720 -31.788809 25.493086 62.294277 -20.092598 0.680494 1.809931 1.017659 0.787057 1.821777 2.105108 0.797012 0.387256 0.869744 1.029581 0.918423 2.428286 0.948394 2.155996 1.078460
+1 0.007731 1 1 -0.240757 1.535258 -1.968352 -1.129181 -1.347627 -1.833554 -2.224623 -1.144515 0.114268 -2.155111 -1.529509 -0.370580 45.701582 -43.506333 39.061139 -49.430650 69.072185 2.068255 2.414827 1.995815 2.166769 2.142178 0.589931 0.724106 1.300740 2.034965 0.909226 0.868636 0.409492 1.085722 1.726097 0.518991
+1 -0.034597 1 1 1.237320 -0.142181 -0.458981 0.089094 -1.134425 0.038881 -1.556888 1.271230 -0.417439 0.853784 0.316980 -2.231823 11.554849 -47.659087 -6.278821 71.851109 -48.412769 0.273849 0.576318 1.424662 1.290914 1.135627 1.233020 2.360216 2.153927 2.296123 0.431341 1.543309 1.893954 2.433734 0.267636 1.911632
+1 0.037584 1 1 -0.870965 -1.634723 -1.569273 0.471003 -0.658176 -1.983841 -2.258758 0.054505 1.860669 0.857582 -1.814971 -0.917274 73.597159 47.450193 -54.613211 -34.228999 -36.792214 0.373893 1.264455 1.936190 1.289051 1.337102 1.168887 2.237864 2.272213 1.326973 1.926526 0.865831 0.528065 0.445420 1.924838 1.747393
+1 0.011307 1 1 -1.544972 -1.074479 -0.888899 -1.458366 -1.629099 -1.283460 2.207801 1.154772 -2.075271 2.024374 0.209380 -1.099366 7.425416 -1.028257 -31.915263 0.179511 17.044805 0.955637 2.398633 2.078498 1.322626 0.873424 2.140878 1.244993 1.094454 2.242245 1.662691 1.344463 1.144634 1.867848 2.424593 1.886016
+1 -0.001164 1 1 2.232445 0.663893 -0.888242 0.160766 1.799559 1.084613 1.570234 1.549240 2.120770 -0.726548 -1.290400 -1.334349 -4.829030 -11.513229 -2.847812 -13.176090 -50.552211 0.909942 1.641494 0.595216 1.787171 0.985446 1.633144 2.010172 0.453589 1.967183 2.444506 1.306279 0.623963 1.198715 1.806794 2.280689
+1 -0.009639 1 1 -0.740924 2.133836 2.095366 1.130013 1.195143 -2.142774 -1.525984 2.323900 1.511121 2.339214 -0.295132 1.867545 -44.554509 -27.631569 -3.773191 33.987038 20.142657 1.189638 2.247863 1.581757 2.336434 0.690483 0.953015 1.067019 2.392516 0.514642 2.084497 0.896434 1.873357 0.513468 0.364882 0.569877
+1 -0.001672 1 1 -1.741960 0.943593 1.781742 -1.500235 1.541895 1.206470 -0.266486 -2.061428 -0.938432 0.142702 -0.210936 -1.487613 51.498876 41.604832 -47.589994 -45.029152 -54.949577 1.561843 0.637326 0.795922 2.304534 2.308663 1.954712 2.089901 1.718354 0.881563 1.685637 2.249726 1.400603 1.938433 0.742055 1.469796
+1 -0.018801 1 1 -0.833940 -1.388517 -1.049553 -1.365032 -2.189659 2.166692 -1.750903 1.447106 0.869675 -1.202499 1.035550 1.636529 -34.230697 -65.324026 -50.900942 -42.132297 32.491702 0.445441 2.272957 0.331094 1.949686 0.877556 1.830651 0.498920 1.100941 1.019079 2.154128 1.178787 2.122021 1.553135 0.537411 2.259293
+1 0.003723 1 1 0.170845 1.542386 0.034641 -2.125683 -1.732675 1.493024 -0.220070 0.514782 -0.003662 -0.293989 2.224195 -1.337674 16.528769 -0.975563 -46.284491 -3.444876 1.963597 1.407601 0.308690 1.158713 2.248338 0.566391 1.081729 2.113504 2.407906 0.423506 0.371510 1.717085 2.053670 0.284190 1.129040 0.769969
+1 0.006430 1 1 1.762632 -2.240749 1.141982 -0.261699 -1.708362 0.138511 0.033014 -1.201152 0.109440 1.519482 1.490619 1.772919 32.468744 2.178423 12.755410 30.174612 -5.301591 1.317378 0.414218 1.767293 2.136658 2.311738 1.879029 1.338940 0.557133 0.729412 0.485661 1.007483 0.771981 0.427961 0.997388 2.105972
+1 0.000843 1 1 -0.542366 -1.789061 1.001878 1.195074 1.400454 -0.957773 0.230097 -1.635964 1.141357 -1.356200 0.164588 0.059284 66.064217 41.302676 -25.916738 17.381018 72.776975 2.314292 2.060349 2.278319 0.450578 0.862562 1.833044 2.469530 1.138170 1.225550 0.562185 2.396889 2.006127 2.234231 1.967123 1.438150
+1 -0.008820 1 1 -1.781966 -2.267517 -1.072714 0.491331 1.692091 -0.299356 1.548803 -0.510233 1.061639 1.860739 2.028329 0.708734 -38.895575 -17.934674 71.927854 41.448409 23.415568 0.556654 1.690383 1.019854 1.688572 2.084010 1.705982 2.197310 2.431685 1.828821 1.250581 0.511778 1.195271 2.418038 1.963660 1.729045
+1 -0.024560 1 1 -0.124949 1.703520 -1.420496 -1.309149 -0.721378 0.782416 -2.213682 -1.038909 -1.545321 -2.241089 0.142553 1.998715 -70.497714 -5.075748 41.911983 14.700388 19.413215 1.793530 2.102548 0.515601 2.461105 1.289833 0.969894 1.260841 1.947205 1.928608 2.107544 1.241929 1.352165 2.331968 2.131397 1.646045
+1 -0.070580 1 1 0.614450 2.210006 0.525756 0.643760 0.033380 0.242839 0.471462 2.339497 -0.243910 0.377450 0.931146 -0.074790 38.514604 64.950714 -73.349418 66.326563 -49.453540 1.140364 2.100932 0.369744 1.281592 1.973634 0.618854 0.821478 2.077176 1.600971 1.270993 1.586904 1.092606 0.428294 2.082029 2.163729
+1 -0.009435 1 1 1.901860 0.431394 -1.932713 -0.618248 -0.084842 1.915691 1.971641 -0.154423 1.138162 1.501664 -1.084493 0.453273 -56.471188 -61.265077 67.847454 12.161878 -45.318777 1.784740 0.628699 2.040073 1.258606 0.389496 0.262065 0.534035 1.779971 1.471483 0.708871 1.751596 1.569369 1.133373 1.606775 2.072812
+1 0.011683 1 1 -0.906844 -1.458484 1.099319 -1.018507 2.053695 -1.791398 -0.570932 -1.229386 1.537875 -0.385812 -0.100623 0.581983 -48.528736 -72.468342 24.570490 6.225440 -69.037123 0.521048 1.750200 0.611909 1.102466 1.894511 0.553307 1.676845 0.741258 1.567669 1.815791 0.502860 2.066093 2.073535 1.155764 2.178265
+1 0.014054 1 1 -0.687807 -0.481317 1.673922 0.637196 -1.908256 0.459386 2.010677 0.899911 -1.960373 1.038135 -2.034068 1.804903 43.312292 -0.300992 41.226070 36.554733 -24.606875 1.108812 0.558648 1.450535 1.887156 0.674305 1.301229 1.254067 0.612232 2.032602 1.699023 2.232683 0.698615 0.369331 1.089343 1.831920
+1 0.018049 1 1 -1.049158 0.567152 -1.046785 -1.972376 1.942280 1.182241 -2.222187 2.092361 -2.244343 2.005814 -0.716251 2.117245 40.875190 -10.684550 -25.235955 59.312563 -33.746452 0.975682 1.788412 1.583802 0.701236 1.681557 1.173339 0.566619 0.422077 1.101150 2.278072 0.812015 0.541921 1.566582 1.541057 2.288136
+1 -0.004849 1 1 -1.195642 -1.533508 -1.605524 -0.897692 1.559206 -0.013419 0.654179 0.775673 2.264700 0.842640 1.516891 0.355260 8.045947 -71.772936 12.270770 -15.175154 -48.806777 2.192589 1.852002 1.592956 1.555721 1.251324 1.759578 0.718783 1.839563 1.791601 1.189809 0.626953 1.953650 2.244112 1.543839 1.803025
+1 0.001398 1 1 2.272809 0.477006 1.273662 -1.939606 1.344745 0.516046 -2.325309 -1.628555 -1.570516 -1.576230 1.350068 0.434716 65.794276 4.397114 -47.706833 -58.747767 -73.718363 1.607219 0.534449 1.987506 2.006497 1.700730 1.662436 1.567879 0.839330 0.623727 1.721718 1.169366 1.291597 1.364639 0.489383 0.553432
+1 -0.001558 1 1 0.786411 -1.049255 -1.062836 1.572904 -0.713318 -0.419713 0.330125 1.923777 1.225950 1.973119 1.138959 0.757647 28.721484 21.978203 -62.350068 -17.585485 -59.250801 1.701878 0.709780 1.273077 0.598075 0.342295 1.208771 2.058050 1.890277 1.386605 0.669391 1.953500 1.981313 1.436391 0.424537 1.947154
+1 0.062154 1 1 0.576729 -0.300269 0.341156 -1.161890 0.247462 -1.949174 0.766037 0.544270 0.798729 -1.362463 -1.415031 0.995568 -37.839744 27.429414 56.160810 -55.265565 -48.353657 1.676220 1.486975 2.336477 1.420725 0.369222 1.510508 1.857738 1.244920 2.126117 0.656111 1.515481 2.184439 2.119211 1.577093 0.453904
+1 0.026717 1 1 2.061156 1.073606 0.367127 1.788046 0.778056 -0.092488 0.640591 -1.394691 -1.140807 1.168649 0.240471 -1.639809 -70.460466 20.954747 -13.568224 -41.137764 -52.399242 1.014188 0.953824 1.177799 1.273342 0.563431 0.839049 0.403264 2.152106 0.952692 2.402502 1.854545 1.584588 0.413729 0.288576 0.589480
+1 -0.001880 1 1 2.216314 -1.838896 2.240450 -1.452255 2.122074 2.337898 1.148602 -2.101725 0.372953 0.747726 -0.908433 0.110061 -69.442765 25.442501 -37.885390 10.250741 -65.791256 2.070506 1.993931 1.998237 2.366036 0.964761 0.490105 1.444907 1.796698 1.353428 1.065528 2.075000 1.016882 1.234141 0.954489 1.103684
+1 0.002937 1 1 0.020239 0.864907 -1.230828 0.855020 2.240367 1.867696 1.136283 -1.804007 -0.433492 -0.344233 1.296205 -0.050954 40.475881 28.132981 31.014298 7.302157 27.345496 1.311316 2.030557 1.071436 2.374632 1.446996 0.914740 1.284499 1.325581 1.033234 1.563249 1.773838 1.898346 2.005359 0.575887 0.931627
+1 0.009171 1 1 -1.616539 -2.243049 0.189915 1.613955 1.224344 -1.455482 -0.272387 -2.272146 1.250814 0.467309 -1.493816 1.042754 5.887338 -51.510659 60.346546 -55.600305 25.669410 1.761493 1.416564 2.444207 0.782178 0.815669 1.201257 1.783194 1.633276 1.974844 0.707842 2.449935 0.309574 0.264861 0.263934 0.434272
+1 -0.005116 1 1 -2.213772 2.159777 -0.157234 1.014046 -1.635735 0.275276 -0.998410 0.537111 -1.720782 -1.245872 -2.220038 0.519526 -12.420652 46.101680 -69.062864 -39.560883 50.237685 1.296456 2.044728 0.739361 1.194146 1.519017 0.874190 1.503174 2.345028 1.133749 1.168118 0.558811 1.937729 2.413181 1.329690 0.348368
+1 -0.003928 1 1 -2.108379 1.633802 0.224208 -1.640075 -1.972300 -1.498050 0.568927 0.525926 -1.198299 0.935509 -2.134983 2.185910 25.836421 -17.274754 63.216534 30.287251 -62.174087 0.476747 1.935677 1.665234 1.334880 2.081400 0.597373 2.049062 1.591751 1.566753 2.175800 0.913197 2.353580 0.861917 2.242634 1.453413
+1 -0.015289 1 1 2.142092 -0.508243 1.514862 -0.759127 -2.206980 -1.490702 1.543897 1.854977 -0.565085 -1.913362 -0.534516 -1.791965 -21.400136 27.919167 37.447632 -17.654563 -20.241026 1.511053 2.021492 1.723377 2.046980 0.339878 1.083956 1.304445 1.313533 1.054509 1.388162 2.093777 1.610446 0.770079 2.213856 1.532255
+1 -0.032599 1 1 -0.083138 2.275906 0.689593 2.229029 -0.208044 -0.007571 -0.019397 -0.855373 1.238841 1.870046 -1.767701 1.861652 -47.153008 -50.606928 -50.646488 34.470964 53.486381 1.309057 2.327483 1.010450 1.137062 0.606324 1.731526 1.750187 0.392902 1.247656 0.851879 2.282003 1.618049 0.301607 1.356413 1.724703
+1 -0.008441 1 1 -2.176698 -1.491190 -1.940604 -1.293031 1.557028 1.065950 -1.085001 1.336878 0.236774 2.196961 -1.952981 -1.969301 56.674721 32.029032 -38.060931 59.932973 43.482622 1.561472 1.164823 1.428240 0.686622 1.306925 2.490030 1.428586 2.002385 2.339988 1.921545 0.403644 1.787355 1.832909 2.455287 0.256451
+1 0.010373 1 1 -2.306648 0.984820 1.962244 2.135982 0.462783 -2.158089 0.257734 1.053924 -0.564454 -0.746057 0.681947 0.949319 -30.109433 50.761627 -49.336988 -6.758120 -33.727462 1.263254 2.011672 0.927212 1.650550 2.037520 1.098418 1.352145 2.002990 1.256242 1.154129 1.699239 1.363146 2.388743 2.354868 2.263276
+1 0.030216 1 1 1.456123 1.619965 -1.427788 -1.342549 -1.297713 -1.717491 2.227355 -0.059008 -2.147761 -0.525957 0.684143 0.156330 -66.110894 74.196939 -72.044935 -59.227736 -40.565731 0.801401 2.147425 1.027513 2.158783 0.671569 0.317367 0.736566 1.458155 1.712548 2.297731 0.462315 2.379629 2.179628 2.259488 1.216721
+1 0.037686 1 1 1.983370 -0.932023 -0.530849 -1.431313 0.659243 1.067879 -1.651350 1.722794 2.084537 -1.806835 -0.837792 -0.147977 34.497377 47.411741 49.138435 -30.316903 13.817111 1.737793 1.329730 1.025922 2.421497 1.606518 2.249211 1.736337 1.616038 2.497362 0.910762 1.918876 0.553823 1.345355 0.390018 2.289348
+1 0.001913 1 1 -1.519571 1.724443 1.513214 -0.174048 1.172307 0.461306 1.295107 0.334439 -0.956757 -1.544563 1.078032 -0.656712 -30.242632 62.085050 63.436734 -18.813690 -1.683215 2.278189 0.530527 1.321008 0.684036 0.598188 2.251992 1.231380 1.801508 1.191667 0.354671 2.212528 1.716214 0.903147 2.193786 1.718690
+1 -0.007984 1 1 1.924332 1.121085 1.943324 -0.125212 2.003073 0.333035 -0.990619 -0.471314 0.156971 -0.732122 -0.734370 -0.801886 4.525709 13.583778 2.560020 -23.747859 19.730099 0.681587 2.184793 1.311074 2.479883 1.887271 0.367037 0.794842 2.157591 0.875829 2.061178 0.468886 0.320721 0.858418 1.936855 1.222209
+1 0.003390 1 1 1.107346 1.937138 -0.422409 2.147530 1.348887 -0.566981 -0.803240 0.932236 -0.600847 0.209746 0.328103 0.930213 -51.603999 -8.415910 3.801997 0.158034 -43.914780 2.489387 1.869363 0.881469 2.355851 0.788154 2.254996 2.210041 0.410923 0.377459 0.460579 2.446583 2.476938 1.889133 2.403641 0.744038
+1 -0.007691 1 1 -1.573466 0.689764 0.380810 0.850486 1.450073 -1.106804 -2.251855 -1.728031 -0.557328 1.219539 -2.102046 -0.301850 65.093751 -69.328269 -0.212173 34.001915 -29.809541 1.240766 2.048077 0.779630 0.740058 1.659898 1.661934 2.122796 1.081345 2.422785 0.753616 2.268001 0.286793 2.136290 0.622322 0.620232
+1 -0.006753 1 1 1.730518 -0.047390 -0.097033 -0.347275 2.002285 1.230957 1.297608 -0.044015 0.091907 -0.984309 1.923447 0.390272 -11.075547 3.279920 -74.380165 -7.437274 -48.269454 0.404410 1.162770 0.673162 2.328003 0.744608 1.624790 1.095445 0.900901 0.442234 2.374211 1.115950 1.266122 0.707249 1.477683 1.418567
+1 -0.055972 1 1 -1.888518 2.331689 0.465557 2.056088 0.715494 -0.702659 -0.348954 2.058676 1.810174 0.411374 0.886984 2.254816 -10.789238 15.278449 -15.105732 67.964005 21.037927 1.891654 2.027467 0.885039 1.602567 1.091695 0.864586 2.091187 0.836291 1.290555 1.850663 1.589587 1.184837 0.305975 0.516367 1.829528
+1 -0.032466 1 1 -0.109288 1.025669 0.501589 -0.249476 1.079824 1.190024 1.359112 1.638973 2.306503 1.275063 -1.961471 1.432638 -62.201741 -74.668912 -60.399803 60.519193 -3.924205 2.063327 0.580957 0.649149 1.489345 1.663008 2.168592 1.269806 1.873135 1.280326 0.931858 0.981414 1.380452 0.752239 1.624973 1.918062
+1 -0.021595 1 1 1.082779 -0.980227 -0.159310 -0.890698 1.301143 -1.891976 0.761633 1.917408 -2.144421 -0.942048 0.624779 1.466183 33.817150 14.837795 -71.181744 48.427261 16.976476 1.729521 1.807339 2.440358 1.350183 0.520643 1.698719 1.624621 0.502930 0.987976 1.417127 0.657584 1.520431 2.141785 0.732012 1.429394
+1 -0.002786 1 1 -1.180483 -1.219508 -2.086155 -1.834828 -0.073108 1.208791 1.046903 -0.752871 -0.735790 -1.112687 -2.164538 0.257951 -0.416449 50.741205 57.440719 6.157976 -2.890196 1.742122 2.100325 1.414221 1.308156 0.678334 1.516026 2.356030 1.549878 2.047784 0.361115 0.258064 0.783842 1.787263 0.288183 0.750121
+1 0.002867 1 1 2.256641 2.063098 0.736840 -0.082316 1.954101 1.944086 -1.446341 -2.151821 1.927011 -0.973923 2.117985 -0.411670 -36.797386 -3.668362 -4.159498 -8.681245 44.322314 1.751937 0.559430 1.084296 0.256910 1.639806 1.465578 0.464585 2.273835 1.590707 2.012434 2.481590 1.338068 1.658529 1.148652 1.887517
+1 0.078285 1 1 -1.507943 -0.763730 0.531496 -1.836795 -0.155346 -0.230543 -1.155213 -0.618983 1.708584 -1.125634 1.705409 2.060618 46.395228 64.600879 46.976019 -74.044587 -67.370529 2.177885 2.218743 0.422528 1.924571 1.764903 2.470197 1.101581 0.516881 1.466483 2.172355 1.519176 1.294504 0.723031 1.225132 0.286185
+1 0.013903 1 1 0.606377 -1.527330 -1.443901 1.158964 -2.308415 -0.427091 -1.145613 0.500067 -2.277415 2.223150 -0.054120 -0.108022 -39.811804 33.015436 40.429067 -8.664834 20.134915 1.487697 0.967158 0.269671 2.356294 1.478061 1.022929 1.619229 2.128657 0.585072 2.301766 0.773172 2.443519 0.478097 2.131727 0.430693
+1 -0.009172 1 1 1.619859 1.493812 -1.101468 -2.108359 1.977938 2.010681 0.967108 1.158522 -0.314805 1.078655 0.400171 1.095094 -43.007381 24.953190 -11.737552 -23.038414 -56.628067 1.406065 1.492971 1.865523 1.590278 1.557171 0.880968 0.670946 1.095063 1.218776 1.466435 1.373349 0.629078 1.663753 1.193087 1.718713
+1 -0.032527 1 1 -1.421799 0.349232 -2.099178 0.778403 1.022083 1.494947 -0.889170 -1.287159 1.295448 1.360534 1.975038 0.388020 -15.593691 -33.158033 -37.053124 48.144034 56.779903 1.372394 0.317326 2.291120 1.858954 1.440322 1.240996 1.415174 1.580552 2.330315 1.349896 2.447571 1.070051 1.605469 0.366618 0.499824
+1 -0.040853 1 1 0.195598 -1.834724 1.662655 -0.231026 0.146290 -1.177887 0.005288 -0.664325 -1.656460 0.677517 1.900356 -1.297183 -71.293034 -22.021773 -69.932781 39.746303 66.113768 0.986494 1.251033 1.370065 1.682948 2.047930 0.559657 0.407387 1.703734 0.400237 0.780546 0.383237 0.818325 0.844715 1.119680 0.963933
+1 -0.000634 1 1 0.166238 -0.479952 1.059307 0.370100 -0.084208 -1.563487 -1.250838 -0.868684 -0.983715 -2.233675 2.221257 1.119473 -50.270267 57.616566 -38.376461 6.816077 -42.188924 1.086297 2.398973 1.043642 0.990115 1.365115 1.730514 0.507975 0.288597 0.946879 1.441266 1.360454 2.154352 0.441919 1.574965 0.682291
+1 0.011143 1 1 -0.874662 2.208796 -0.972137 -0.857056 1.232719 -2.058376 -1.480649 0.851271 0.490856 -1.584549 -1.812289 1.746356 71.414749 -32.306960 16.919439 -34.980853 -73.196366 0.455094 0.271140 2.297499 1.060123 1.230381 0.766206 2.367637 0.869600 0.864778 0.828504 0.922938 1.826139 1.173194 0.378396 0.455328
+1 0.014895 1 1 -1.254584 2.155711 2.185091 1.177958 1.193157 2.174295 -1.194796 -1.450175 -0.621509 1.668329 0.895782 -0.679590 30.438930 -62.898263 68.887437 -58.848033 41.102721 2.326581 1.597672 2.069580 2.188623 0.435875 1.252302 2.436406 2.434619 1.645161 1.472696 0.856552 2.064811 0.774979 1.329265 2.204421
+1 -0.068425 1 1 1.036087 1.234146 -1.648697 -0.810027 -0.026702 -1.107366 -2.280241 1.854772 0.697281 -0.510917 -1.005117 0.910163 21.916306 -52.643592 69.154064 72.354520 12.416376 1.855414 0.442355 2.163196 0.577050 2.481700 0.929493 1.744128 2.057983 0.769144 2.249800 0.390283 2.228115 0.424979 0.368730 2.247981
+1 -0.006792 1 1 1.948238 -2.352192 -1.065487 -0.564030 1.669746 1.141599 -1.999446 -0.649518 2.162934 1.068692 -2.119683 0.151587 -53.629555 -1.931798 -67.723200 -23.820854 -7.096719 1.006695 1.016839 0.505766 1.410045 0.872065 1.796699 1.363818 2.431942 1.641065 2.374932 1.982649 1.372809 0.555412 1.066776 0.545089
+1 0.008949 1 1 -0.362147 1.807625 -0.012737 -2.017455 -1.733307 0.297579 1.563694 0.003114 0.505329 1.337981 -0.072129 -1.185394 33.948359 -29.929269 -71.231759 -42.179973 -18.811506 1.900202 1.692559 1.580752 1.196074 2.418953 1.599901 1.279223 0.403795 2.085795 2.463444 2.360412 0.944371 2.044160 2.454754 0.297599
+1 0.015116 1 1 -0.734340 -0.298793 1.588732 1.426716 2.184269 1.505921 -0.217737 2.014199 -1.161554 1.196290 -1.711292 -1.981488 -13.387811 -8.934260 -8.103335 7.246492 -8.204206 0.803570 0.345377 1.247425 1.475520 1.056109 1.268894 2.299178 2.290750 2.389250 1.880284 2.190888 2.495521 1.463349 1.251649 0.464138
+1 -0.026824 1 1 0.716867 -1.199993 0.751327 -1.654688 2.178459 -1.908535 0.485984 1.355376 0.111078 0.789018 0.364039 1.723868 40.564962 25.311159 4.655855 -49.046191 -69.337654 1.255863 1.538215 1.783128 0.533309 0.831987 0.963327 1.143831 1.872233 1.872319 1.069542 2.044059 0.746719 1.109177 2.178842 0.290480
+1 -0.011461 1 1 1.123981 -1.218655 -1.884546 -1.596847 -1.153211 0.031589 -1.577122 0.501641 0.622130 -0.651757 2.229480 -2.040558 35.388397 22.785827 11.398765 29.042506 17.396167 1.785696 0.940310 1.295025 0.491843 1.412185 0.845674 1.491463 1.264285 1.334623 2.252675 1.454440 2.273383 0.747035 1.921577 0.944637
+1 0.019130 1 1 -2.006921 0.964337 1.708958 0.440912 -2.173389 2.298586 0.167815 -2.261595 -0.491565 -0.917807 -1.931866 -0.515369 -14.124277 63.280438 54.327297 28.875058 53.099914 0.628866 0.355365 0.367335 1.291489 1.814208 0.898718 2.004778 2.052022 1.826242 0.655583 1.629531 2.021310 0.914865 1.138409 0.741287
+1 -0.002759 1 1 -1.402790 -0.606775 -0.465819 -1.734554 -1.805788 -2.085350 2.274171 -0.189979 2.026048 0.075023 -2.012617 -0.528182 31.380303 8.746218 -2.320751 -4.856217 -18.430754 1.139686 1.945369 0.312638 2.255425 0.420129 2.104592 1.125262 0.281851 2.327461 0.636358 0.262327 0.427528 0.463870 1.509006 1.362754
+1 -0.002501 1 1 1.038366 1.842373 -0.351965 -1.426211 1.590005 -0.749915 1.823203 -2.099696 1.486713 2.094682 -0.943493 -0.091970 -2.220130 36.277001 -42.438986 -22.040009 73.573294 0.570226 0.282513 2.203424 1.690213 0.410557 0.975745 0.602191 2.028810 0.965643 1.804113 2.228167 1.296623 0.343925 1.590629 0.693795
+1 -0.027742 1 1 -1.122979 -0.791600 -1.355047 0.709220 2.232982 0.259924 0.158923 -0.910965 -0.030178 1.729741 1.024830 0.530486 1.160156 -1.257818 9.849829 -53.927740 -63.525048 1.892830 1.548801 1.946185 0.525341 1.902866 1.467029 2.359812 2.109824 1.316084 1.178722 1.029186 1.024088 0.838246 0.398122 1.235460
+1 -0.028518 1 1 -0.859043 0.830171 -0.697091 -1.007181 -0.788565 -2.170441 0.002202 -0.687270 -0.880934 0.466015 0.326177 1.543254 15.137872 22.218653 -71.093166 37.158830 -71.539820 1.828636 0.384768 1.799291 2.182313 2.388804 1.136211 2.049922 0.291898 2.428052 1.511986 1.956423 1.597470 0.934961 1.396380 0.713620
+1 -0.050909 1 1 -1.802528 0.852219 2.291842 -0.084965 -0.157311 -0.271437 -0.455780 2.049467 -2.178148 -2.300030 -0.884047 -0.021113 -45.121967 35.103198 29.446145 51.365044 42.289871 2.363025 2.104012 0.384555 0.469191 0.937852 0.473516 1.625876 1.355265 0.437485 1.303527 1.626754 0.349065 2.478132 1.707008 1.431579
+1 -0.046517 1 1 2.302369 -2.217692 2.246571 -2.249167 1.035030 2.323485 -0.758560 -2.113167 1.278966 -2.331547 1.914109 -1.053742 -34.444295 -55.264344 -27.823525 70.007220 11.346173 2.051868 1.495982 0.725285 0.872067 1.826617 2.449897 1.922187 2.195857 0.510889 2.008878 1.212616 1.435509 1.347111 0.642357 2.089182
+1 0.004932 1 1 -0.755988 -1.288492 -2.263533 -0.089815 -1.554180 -0.323341 -1.014444 -0.334547 -0.845760 -2.121005 1.492497 0.343114 -39.651560 26.224060 47.777336 43.687856 11.802386 2.315469 1.588269 1.528513 0.715230 0.627819 0.759118 2.492310 1.499748 1.015739 2.268170 0.880559 0.562376 1.105379 1.356217 0.686513
+1 -0.018940 1 1 -1.284079 1.231133 -0.444210 -1.405207 1.178943 -1.102704 0.684736 0.709125 0.635117 0.850522 2.041126 -0.990913 -22.044740 -5.952792 1.421718 44.807142 73.642725 2.324270 1.010856 1.208864 1.381479 2.260281 1.041790 1.359213 1.544444 0.724051 0.380124 2.494946 0.805177 0.353617 2.499355 0.666634
+1 -0.007868 1 1 2.114977 0.863444 -2.246645 1.015907 1.358403 -0.845533 1.692738 1.153480 -0.224483 1.742868 0.172220 1.089015 5.082190 66.368966 63.213688 -17.538518 -19.866762 1.365000 2.053297 0.755143 0.933724 0.842506 2.240547 2.372438 0.570504 0.461700 1.042741 1.594418 1.378855 0.921430 1.216238 1.555207
+1 0.019686 1 1 -1.974320 2.255701 0.390347 0.919058 -0.607710 -2.029292 1.965303 1.714733 -1.448995 0.360125 1.915846 -0.130614 23.935932 -8.791821 -14.130070 -34.081552 41.358349 1.521484 1.836944 0.514488 1.750099 1.165532 2.089579 0.807518 1.449237 0.328985 0.259182 1.576538 2.370113 1.987950 0.478858 1.422986
+1 0.008872 1 1 -0.249050 -1.180619 1.211577 0.734571 -0.528599 -1.310394 1.914531 1.332335 -0.714138 -0.056860 0.967930 0.833619 22.535058 -3.283044 21.873837 -16.429599 17.723379 1.027539 0.355444 1.697561 2.407611 2.222907 0.650353 1.487011 0.692784 1.370288 0.924631 1.021566 1.202428 1.208345 1.660774 0.636011
+1 -0.010310 1 1 -0.254756 1.880368 2.068094 -0.127723 2.209145 0.190933 -0.133745 -0.047761 -1.616040 1.421357 1.647734 -1.249126 -11.560839 -53.019327 54.172148 -28.715826 73.115706 2.210020 2.309088 2.346194 0.473319 0.579903 0.925780 2.328911 0.262919 1.380692 0.284212 1.499593 0.656740 0.831114 2.040353 1.454398
+1 -0.001958 1 1 -0.391198 -1.079840 -1.457116 0.541575 -2.080728 -0.158857 2.022038 -1.348640 -0.005306 0.360020 0.156553 1.680970 41.174030 61.919227 -23.543925 -2.747485 23.015949 1.060855 2.293354 1.143313 2.163873 0.716026 0.494464 0.450181 0.938679 0.872085 2.131364 1.084061 0.810025 0.844018 0.667963 0.451155
+1 -0.003897 1 1 2.350956 -0.871657 0.877216 -1.692740 -1.195340 -1.167508 0.085347 1.864005 0.367987 2.108522 0.762940 0.316304 17.325424 38.401228 -40.562019 24.142885 19.473643 1.277749 0.379844 2.287584 0.929822 0.520253 1.890582 2.008895 1.500775 0.275330 0.729469 1.431564 0.296096 0.986826 2.341556 1.278469
+1 -0.026208 1 1 0.391333 -1.362014 1.421251 -0.136048 -1.044897 1.488712 -2.006266 -2.163255 -1.750392 0.600972 1.886011 -2.049014 11.255469 20.665982 -66.844198 49.562467 46.389424 0.880678 0.301702 0.709214 0.756026 2.273670 1.074880 1.755411 0.444135 0.569421 0.265979 1.050642 1.640713 0.970893 2.301989 2.279964
+1 -0.055459 1 1 -0.622547 -1.640975 1.748049 -2.291506 1.021033 -2.017903 0.165481 0.937879 -0.006747 -0.294806 -2.077064 0.162332 -5.067026 38.489705 -53.526816 74.811009 48.627730 0.418937 2.329296 2.228660 0.594175 2.298834 1.003444 0.377586 0.329721 1.367710 0.352226 1.606029 0.772131 0.713441 2.051346 1.728684
+1 -0.034016 1 1 2.141170 -1.865479 -1.574367 -0.325401 2.065161 -2.300204 0.915452 0.044647 1.108517 -1.941731 -1.380119 -1.286773 -52.335114 3.737858 -27.813588 -62.971799 32.975378 0.882767 1.657013 0.411188 0.335121 2.122803 1.192143 1.603252 1.358162 1.877918 0.672573 1.441491 0.632954 1.558028 1.780646 1.560817
+1 -0.025861 1 1 -0.034820 -0.880590 1.545476 0.125078 0.464155 2.049591 -0.091316 1.482446 1.076051 -0.961637 1.261890 -1.877127 18.274035 -68.293772 -13.430411 25.087958 3.308411 0.691862 1.621594 1.373744 0.517831 1.684465 0.557863 1.757043 0.871002 1.928986 1.719073 1.713994 1.854119 1.179987 2.040093 1.593606
+1 -0.017735 1 1 1.069427 0.812041 0.893618 0.652229 0.989699 -0.856712 2.304657 -1.475846 1.476480 -0.235451 1.188201 -1.014985 -0.159264 23.257861 -5.130460 22.355075 -28.256157 1.356453 2.398700 0.951604 2.106953 0.315074 0.446097 2.058671 1.089830 1.024045 2.366439 0.996766 0.645607 0.470599 2.102380 2.198337
+1 0.048778 1 1 -0.328527 1.363644 -2.296398 -1.097706 -0.133615 2.137506 -2.195555 2.017713 1.353760 1.221821 -1.448419 0.632109 68.002730 71.879969 -13.363751 -54.567674 -18.895785 0.903241 1.523379 2.174702 0.466455 2.201348 0.562010 1.705003 1.490791 1.227250 2.134434 0.930210 0.292520 1.635740 0.632957 1.605204
+1 0.018770 1 1 1.589295 1.458606 0.939235 -0.773605 -0.505303 -0.906954 1.401635 0.051595 0.083736 -1.648242 2.124764 0.431794 2.603412 -44.449205 -57.789338 -15.399845 74.799441 1.438047 1.249675 1.034567 1.460064 2.290621 2.466136 0.341686 2.222396 1.062652 0.998797 1.034958 1.285494 2.289090 1.478250 1.941799
+1 0.012566 1 1 -1.597715 -1.602254 2.210967 -2.175131 1.284251 1.665640 -1.892985 -2.061101 -0.161247 -0.452878 -1.013044 -0.368250 -57.668146 71.462061 12.851765 -0.382104 27.973896 2.234118 2.325335 0.906884 2.007326 2.129481 0.943404 1.538600 1.496105 0.531069 1.429029 0.449019 1.664650 0.523507 0.331166 0.908408
+1 0.034980 1 1 1.188304 0.720482 -1.691290 -0.381262 0.972659 0.208087 0.730880 -1.304308 0.532946 -1.020246 1.103755 -1.872326 36.593763 31.377091 -45.226381 -69.792233 1.940596 2.358954 1.198770 0.486038 0.591119 0.443369 1.202548 0.966337 2.232234 2.154513 0.905939 1.867599 0.490317 0.503154 0.254771 1.679756
+1 -0.017098 1 1 -1.658517 -0.920820 -0.742499 -0.783006 1.712962 1.773295 -2.088520 0.829947 0.247472 -1.777714 -1.499787 -0.355123 65.093822 -68.135530 -53.853260 -11.746982 -31.529435 1.896670 0.838777 0.323623 2.374801 2.031482 0.869894 1.308545 0.467172 0.759567 1.035460 0.731298 0.681435 1.883782 2.470376 1.858409
+1 0.064795 1 1 1.163396 1.494355 -1.409731 0.543658 -0.056010 1.109718 -0.597964 1.551300 -0.952897 2.075953 0.023019 0.470994 -26.277796 -50.920000 -62.441329 -51.409855 -45.431559 0.351693 1.659361 1.638842 1.023006 0.654939 2.057840 0.610698 1.001450 0.625358 2.144430 2.432366 2.018265 1.484771 1.303385 1.495197
+1 0.016717 1 1 2.043833 2.102084 0.949147 0.875380 0.429762 -1.084415 1.748788 0.713501 -1.226546 2.146495 -1.904617 0.363858 -42.248921 22.382999 -8.934620 -14.156249 -24.078858 1.474594 1.253389 0.462656 1.351905 2.460927 0.546528 0.251290 1.676893 1.533149 2.139918 0.851304 1.619833 1.037092 1.161406 2.497644
+1 0.000207 1 1 -0.458208 -1.050876 -0.041530 -0.566215 -2.061156 -1.074897 1.499815 0.821740 -1.026656 1.756653 0.944791 -1.652159 72.273249 -3.505372 35.207878 -11.189176 43.524512 0.872158 1.105970 2.281963 0.947098 0.632798 1.189943 0.628218 0.712832 0.809548 1.827600 0.964826 1.576020 0.411665 1.601857 0.403220
+1 -0.013072 1 1 2.350468 0.353649 1.463092 0.936554 1.286771 1.610336 1.672565 1.391773 -0.765099 1.096137 2.041391 -1.249971 -13.587666 -67.895333 -66.861339 61.479685 -60.938785 1.402588 1.541175 2.022708 1.904586 1.118079 1.058689 1.887013 0.526936 1.711734 2.109575 1.633146 2.038822 0.480547 0.549366 0.697976
+1 0.003385 1 1 -1.584939 1.061041 1.229830 1.215204 0.435828 1.914535 1.389464 -1.882651 1.981927 -1.628340 2.042115 1.498603 -22.466467 -43.909199 18.090297 -6.382249 -16.456332 1.651355 2.069533 1.400060 1.800071 1.787952 0.610402 0.522887 1.169684 2.136539 0.314558 0.777024 1.939190 2.214568 2.239166 1.666739
+1 0.012631 1 1 -1.143604 1.273637 2.346735 -1.127038 1.681504 0.849314 0.599808 1.179066 0.971257 0.194546 -0.658936 -0.630072 -28.002761 57.603647 44.500490 19.728516 -72.839920 0.317024 1.722715 2.165241 1.211135 1.298999 2.022431 1.742991 0.942825 0.816347 1.349548 1.108810 0.513199 0.327715 1.398148 1.178327
+1 0.028592 1 1 -1.436055 1.081266 1.867200 2.235088 -2.040977 -1.226594 1.336996 2.228563 1.394849 -0.911400 2.078758 0.024764 48.501557 65.670561 25.117852 55.736664 16.112213 2.094516 0.529568 0.944207 1.535078 0.800420 1.403029 2.213067 1.773538 1.349223 2.387872 1.219313 1.488893 0.818579 0.601453 0.878038
+1 -0.009403 1 1 -1.688729 0.244366 -2.143099 -2.271635 0.397452 -2.198646 1.907213 0.853599 1.919645 -2.247000 -0.247516 1.038842 13.532561 41.750187 -4.605265 -0.689617 -40.397574 0.444562 1.002532 0.798892 0.476899 2.244981 0.403103 1.709094 0.490366 1.328063 2.252063 2.425222 1.207249 1.233120 1.804445 1.059691
+1 -0.008039 1 1 -1.339912 0.602188 -1.241852 -0.631775 -1.237329 -0.022308 2.068096 -0.087855 -1.596820 -0.707469 -1.072488 -0.418232 52.791904 23.527718 30.362834 8.151300 48.892238 1.852638 1.038053 1.559726 1.059751 1.742082 1.422384 1.249283 1.197233 1.642619 1.502812 0.759173 1.165849 0.669131 2.088376 0.839012
+1 -0.023245 1 1 0.886955 1.758916 1.276927 1.096545 -0.520147 -0.637025 0.070844 -1.565859 1.295918 -0.175458 1.038903 1.437998 -44.908447 23.739251 -14.403665 17.598583 -20.609085 0.971696 2.287761 1.640585 1.054734 0.667600 1.105703 2.293291 2.349273 0.490050 0.527144 0.702203 2.167518 1.228483 0.358521 1.658418
+1 -0.006149 1 1 -1.157564 2.273826 -1.278254 0.165329 -1.624642 -1.783591 -1.300389 0.421368 -0.782137 2.181811 -2.122371 2.091178 45.774919 -10.937699 70.085576 -21.722412 11.428704 0.358349 1.021139 0.780394 2.334287 0.604950 1.136342 2.004839 0.834298 1.548769 1.419666 0.570643 0.554815 2.279404 0.693915 2.380564
+1 0.011377 1 1 1.859394 -1.729699 -0.314872 -0.047835 1.860064 0.110388 -1.396494 1.526131 0.152504 -0.397476 1.783957 -1.958530 -31.107302 -70.416713 6.301619 11.315017 -28.517092 0.823540 0.728976 2.148505 1.166286 1.266167 1.463147 2.357644 1.675203 2.387910 1.846751 1.090484 0.758358 0.967867 0.944269 0.335087
+1 0.011180 1 1 1.995673 -1.502660 -1.513379 2.113989 -1.597120 -1.021540 -1.796350 1.024906 1.810105 -0.740638 2.233076 1.840861 -70.117352 -62.335722 73.522646 -4.880806 18.293512 0.760955 1.876047 0.725531 0.500522 1.016205 1.102086 2.254015 1.477003 1.240692 0.814438 0.754236 1.445542 1.224204 0.443370 1.212092
+1 0.009733 1 1 -0.828398 2.225804 2.136660 -2.278224 -1.946039 1.619393 -1.622174 1.997168 0.053240 -0.546264 -1.319001 -1.369526 -73.715450 64.429355 14.174774 35.420044 -45.312595 1.093148 0.544803 0.499743 1.434162 1.216920 1.767385 1.437388 1.439272 1.589878 1.578717 0.739896 1.185770 2.488246 0.700497 0.500602
+1 0.037989 1 1 0.134376 1.226794 2.026763 -2.061248 2.087683 -0.766530 0.600968 1.820363 2.016538 0.459755 -1.222684 1.077673 -62.540282 -64.523106 60.165782 56.306456 -7.388964 1.580205 1.011100 0.808669 0.544108 2.330286 0.870147 1.062695 1.719406 0.561032 1.017732 2.020661 1.255251 2.499400 1.418781 1.458368
+1 0.016188 1 1 -1.963586 -1.136810 -2.342100 -1.095253 -1.321826 -1.732040 -1.967308 2.286820 0.339240 -0.380931 1.833158 0.290448 -15.403837 7.710238 -14.024412 -58.297933 -13.356437 2.400375 2.111565 1.328249 0.879797 1.252644 1.446014 2.401167 1.919588 1.268394 0.653402 0.970831 1.251839 1.408013 0.473117 1.683591
+1 0.036891 1 1 1.451672 2.207246 1.250048 1.725261 1.133175 -2.209591 1.734300 2.247110 2.101224 0.621368 0.680879 1.859491 -3.361713 49.683101 -26.127400 -73.210911 -5.776250 0.903364 1.331293 0.292828 2.302406 0.283600 2.459211 0.951951 1.196208 2.408807 2.076987 0.672099 2.475663 0.722964 2.354597 2.212021
+1 0.046879 1 1 -1.048385 -0.592218 -0.843950 0.021885 0.260060 -2.273969 -1.117971 -1.452618 0.734031 -0.178513 1.522111 -1.440442 -62.524496 50.793160 30.645172 -46.589535 -30.321720 0.367882 1.492664 1.207715 2.307527 0.859488 1.913851 1.594858 2.031976 2.428874 1.841510 0.752659 1.937213 0.481376 0.981112 0.792148
+1 0.032485 1 1 2.153797 -1.709605 -1.893897 1.467245 0.055044 1.501031 -2.296718 -1.767051 -1.345271 0.064878 1.835655 -0.153839 48.733398 62.218678 59.313179 -23.399209 29.488508 1.575359 0.553893 0.274705 1.470660 0.388646 1.722252 1.138750 1.963316 0.449522 1.117798 0.831182 0.933392 2.015472 1.787521 2.358967
+1 -0.056578 1 1 -0.261281 0.594954 -0.298387 -1.013043 -0.352944 0.960044 0.247977 2.005042 0.451712 0.257084 -0.446046 0.712648 -45.006439 26.787845 73.303082 54.896085 -11.500554 2.277813 0.950871 1.036585 1.634756 2.102831 0.787871 1.995105 1.485937 0.643537 1.673663 1.252334 0.730147 1.588219 0.702723 1.919937
+1 -0.007726 1 1 1.646229 1.735092 1.435823 -0.270581 -0.197522 -2.226821 -0.384755 -1.184171 -1.950738 -1.964851 1.168093 0.320625 -70.796011 -68.555544 -63.026629 11.445051 56.974610 0.959037 1.036897 2.375293 1.305772 1.111613 0.373441 0.428108 1.214702 0.498680 1.566749 2.103496 0.701341 1.193811 0.372673 1.022511
+1 0.058655 1 1 -1.610688 1.833125 -0.273498 -2.106489 0.426094 -1.473391 0.318180 -0.914020 0.454726 -0.909601 -0.669724 1.841781 -27.697068 -54.627551 24.745046 -60.015433 70.613735 1.450675 1.994059 1.897667 1.838403 0.282646 2.183011 0.622606 0.888152 2.163303 2.381936 0.450250 2.106477 1.302952 0.957206 1.760858
+1 -0.040072 1 1 -0.006840 -1.865711 -0.760178 -1.030343 1.048510 -2.031569 1.392851 -1.506282 -1.128925 -1.771985 0.541557 2.318100 -55.197781 40.896088 40.558206 61.773238 72.809483 1.509763 0.585003 1.142015 0.596036 2.068850 1.158298 2.018651 1.213667 1.099006 2.243465 1.911730 1.953573 0.944773 2.041598 2.140730
+1 -0.007039 1 1 0.735353 -1.516694 -1.760280 -0.656965 -0.485542 1.348098 0.323822 -0.337733 2.152031 1.598507 0.786578 1.764832 55.615497 -70.338808 -34.350717 17.502474 14.083476 1.389725 1.365508 1.584401 1.777842 1.681662 0.698871 2.419811 0.262398 1.627991 0.900580 1.792561 1.580540 2.130290 1.039991 0.375647
+1 0.005816 1 1 0.341410 -1.613835 0.783489 1.685090 -0.154812 -0.688026 0.545416 1.215310 2.228719 -0.693796 -2.184752 -0.191548 -24.856452 -12.392932 61.991746 -4.725831 72.960073 1.224300 2.065964 2.152481 0.494489 0.872875 1.913078 2.109931 0.866339 2.309786 0.576720 1.426696 1.722456 2.320738 2.388021 1.472990
+1 0.000817 1 1 -0.341322 -1.618892 0.611662 -2.224534 0.358824 -1.095307 -2.229834 0.811029 -1.981598 -2.266516 1.614483 0.678568 22.583557 61.845836 -57.030592 -13.154471 12.803418 0.430600 0.349306 2.028313 1.604292 0.836039 1.559666 2.311619 2.136040 0.925420 0.784033 0.493993 1.542271 2.441205 2.086939 1.438379
+1 -0.014786 1 1 0.066340 -1.862467 1.925604 -1.052632 -1.285301 -0.465990 0.094819 0.831091 0.630676 1.616969 0.056405 0.807639 73.683933 5.869060 -58.713654 49.625014 47.611299 0.671442 0.419997 2.141522 0.803371 1.509289 1.621007 0.511867 0.454250 1.824356 0.459016 0.935031 0.317876 0.296092 0.910331 1.441215
+1 -0.038389 1 1 1.001108 -2.317856 1.110796 -1.335754 -0.195566 -2.336142 0.077835 -1.875667 1.549638 -0.606474 -0.110219 -0.485028 18.322413 -5.197008 -46.121530 35.441178 9.881695 1.849725 1.574164 0.727477 1.706156 0.607921 1.572020 0.686935 2.067343 0.581837 1.928748 2.216719 2.394134 0.703783 1.733747 0.837867
+1 -0.050575 1 1 2.143938 2.246870 -1.945201 1.564016 0.711369 0.644287 -0.530763 0.024191 1.313365 0.898423 1.305468 0.115985 -50.003876 34.853498 32.739941 60.188182 -17.231877 1.882524 1.588105 1.026861 2.456026 1.430503 0.470523 0.824418 1.991565 0.478496 2.089244 1.925296 0.457498 2.414585 2.432357 1.865628
+1 -0.001148 1 1 -1.880776 0.503255 -0.536816 1.963194 -0.753662 0.111789 -1.411942 1.084235 -0.077745 -1.336297 0.108345 1.979301 43.005942 -49.133149 -30.835806 -7.384773 -65.887017 0.428659 1.476717 0.934067 2.112432 2.389669 2.162483 2.096401 0.712152 0.646448 1.099604 1.040733 1.592437 1.842554 0.297945 0.553930
+1 -0.015136 1 1 -1.253798 1.225740 -1.546719 -2.175852 -1.413537 -2.166822 -0.438642 -2.085194 0.182281 0.537901 2.143660 2.279589 42.514384 -60.752630 -19.452314 64.955364 4.807836 0.704411 1.038040 1.345526 1.002028 1.330019 1.376923 2.192762 0.253262 1.078518 2.154376 0.845841 2.055980 0.850772 1.681689 1.148454
+1 0.005929 1 1 -1.138325 0.478108 0.946246 -0.760226 -1.827229 0.402967 0.964584 1.141207 0.841907 -1.369912 0.617090 -0.541998 -9.828739 -41.608170 -8.512160 36.125515 -38.461780 2.468060 1.182279 2.312829 2.211346 2.092939 1.029427 0.572790 0.624888 0.993176 1.057781 2.375446 1.623723 1.165854 0.752635 1.530807
+1 0.059565 1 1 -0.394808 -0.494053 -0.325407 1.970819 0.180105 1.676907 -1.025242 1.963376 2.310735 1.729453 0.900031 0.051333 12.073686 -27.560721 -13.033761 -58.427925 51.865626 2.208572 0.471725 0.784841 0.565892 1.693365 1.642754 1.517636 2.407572 1.567505 1.314245 1.769416 1.819449 1.226717 2.180230 1.126031
+1 -0.039373 1 1 0.561961 1.252562 1.564294 0.666036 2.142180 0.976692 2.014205 -1.055595 0.763058 2.313515 1.325803 -2.115764 1.527088 15.774023 63.996227 -65.418111 17.808150 2.148681 1.884708 2.293258 1.788874 0.358268 1.913653 0.518156 0.402251 0.874905 2.275821 1.229231 1.683855 1.543913 0.788249 1.604169
+1 0.032555 1 1 -0.807041 -1.682649 -1.238198 -0.492336 0.265498 -0.400427 -0.681911 -0.345173 -0.371161 1.095027 2.246510 1.438081 -0.707852 -46.871542 29.994230 -36.983859 12.279286 1.044426 0.660662 1.495358 1.479931 0.942607 1.638322 1.271397 1.620828 2.007751 0.266191 2.371656 0.919803 0.878403 0.319521 0.931858
+1 0.020115 1 1 -0.950773 0.077254 -2.207730 0.032940 2.277571 0.396832 1.528777 2.212025 1.470896 0.149268 1.753529 0.283954 -39.541674 73.093026 -25.515303 14.301037 57.528721 1.153190 1.655430 0.818228 1.458420 1.672393 2.408997 0.771760 1.219331 1.790717 2.073378 0.770704 1.470376 2.350369 0.910590 1.290860
+1 -0.045176 1 1 2.350070 -1.624968 2.176545 -1.083945 0.230094 -1.677713 1.608938 1.729355 -0.739952 -0.376672 -1.985663 0.098233 52.854338 22.851307 61.923244 43.966728 48.789927 0.809582 2.395412 1.945778 0.436652 0.802049 1.780890 1.165887 1.315006 1.060112 1.046029 0.610721 1.395371 1.751080 1.899309 2.440131
+1 0.065281 1 1 -0.895575 -0.551980 1.571670 2.118834 -0.281794 -0.168764 0.442906 -1.658980 0.721056 -1.479311 -0.217200 1.618528 -64.240754 5.644477 66.727456 -61.643415 9.123960 2.070904 1.933522 1.455537 0.454083 1.279685 1.419475 1.864160 1.194168 1.889887 1.588241 1.061478 1.513492 0.258020 2.291820 2.373801
+1 0.006071 1 1 1.301386 2.197452 1.576994 2.055649 -1.937416 0.456677 -1.107031 -1.355901 0.485298 -0.739889 0.674544 -0.941513 5.901622 38.560870 -57.463499 60.976431 30.871122 1.389155 0.776857 1.386542 1.855136 0.267571 0.813884 0.450839 0.754100 1.415380 0.544624 1.994183 1.727382 1.855037 0.857222 2.085205
+1 -0.012105 1 1 -1.045121 -2.268640 -1.095740 -0.085160 1.274301 -0.627138 1.301747 -1.160308 -1.435340 -1.043608 -0.416955 -0.444068 31.216393 -46.084499 57.825367 20.945992 -10.709444 1.470530 0.454296 0.361159 0.998818 1.388183 2.447601 1.585195 1.619991 1.442333 1.289483 1.831897 1.199762 1.406369 2.092158 1.397356
+1 -0.020072 1 1 0.594079 -0.862388 1.150851 -1.996111 -1.143501 -1.703137 -1.572512 -2.133309 2.035915 0.972744 1.633276 0.800374 -63.047568 -40.478600 -73.822151 71.109191 -67.832333 0.504728 1.960430 1.456154 1.837373 0.969557 2.345162 1.131422 0.301455 1.051404 0.951079 2.284819 1.711070 2.197549 1.953163 0.811267
+1 -0.039039 1 1 -0.282176 -1.867787 2.042156 2.182485 -0.210035 -0.486500 -0.612619 0.284322 0.237896 2.220208 2.342653 0.963170 29.893460 69.383572 29.694874 31.754442 -3.090877 0.649511 0.833599 1.053839 1.370991 1.486495 1.014289 0.412194 1.489462 1.386591 0.434165 1.769509 1.135552 2.227351 1.088833 2.269330
+1 0.039201 1 1 -1.115676 -0.570440 2.326185 2.203952 -2.265444 0.778589 -0.552368 -0.250387 -0.099240 0.264039 -1.367708 -0.032211 17.429604 -10.643136 70.820979 38.191767 39.035736 0.979326 2.281921 2.494874 1.838988 1.124607 0.515806 1.406071 1.587075 1.725887 1.488672 1.616358 1.124230 0.936203 2.009528 0.888132
+1 -0.014753 1 1 0.392596 1.010768 -0.190888 0.876858 1.720156 0.162913 0.187962 1.778487 0.347388 -0.098751 -0.948876 -1.026671 47.789873 -45.611804 52.404108 -44.158727 24.272023 0.473271 2.010787 1.799335 0.670285 1.231462 0.928857 2.296812 0.763015 0.496608 0.489983 1.647170 1.493466 1.182198 0.957773 2.291591
+1 -0.045812 1 1 1.483470 -0.573546 1.962718 0.677957 -0.139318 0.539581 2.100029 -0.598922 -0.419707 0.425831 -1.183759 0.263732 -57.629803 -34.098651 53.979939 40.838345 -29.930756 2.181639 2.299364 0.908993 1.444220 1.508695 0.630987 2.247196 1.629299 0.382237 2.005834 1.808408 2.411719 1.515624 2.347675 0.618687
+1 0.016874 1 1 -1.823404 -1.289806 -0.774584 1.903634 1.972093 -1.982363 -0.990824 0.799903 -0.471298 0.424357 2.326049 -0.081299 6.493657 -61.103606 -68.301090 13.580153 -58.368265 1.443572 1.859452 0.812432 0.790644 1.352091 1.094824 1.709959 1.529246 1.781918 0.452492 1.528981 1.832886 2.060679 1.088289 2.118342
+1 -0.062856 1 1 0.709147 1.003299 1.518451 -1.691409 2.327867 2.207123 -0.801710 -1.621619 1.909379 -0.438389 2.172779 1.599375 38.970637 -70.510560 -70.974361 -66.088624 -1.497951 1.734122 0.388785 1.816617 0.888574 0.270763 0.470589 1.945463 1.898570 1.257045 1.154816 1.988000 1.311868 2.311889 2.174968 0.443151
+1 0.035912 1 1 -1.338215 0.852461 1.650587 -0.413504 1.016526 2.336693 -0.247167 2.184910 -1.862392 -1.543050 -1.765006 0.026064 -6.073098 -70.549738 20.550539 -57.086054 -45.303225 1.205493 0.969811 2.121517 2.089245 1.944121 1.838763 1.834286 0.850586 0.804025 1.254872 0.636850 1.781035 1.349919 0.593270 0.587736
+1 -0.030604 1 1 -0.119937 1.114530 0.165771 1.088568 2.072391 1.411924 -1.380831 0.893497 -1.387469 -2.296595 0.310340 -0.737407 -0.787390 -33.672153 22.130413 -54.153357 44.533305 0.943739 0.413478 0.572514 0.498776 0.927369 2.041069 2.243017 1.139059 0.423529 0.759303 1.098719 1.919582 1.168902 2.479270 0.588172
+1 -0.001612 1 1 0.799816 -1.937830 -1.783905 -1.868127 1.031552 0.409330 -0.473324 -0.647764 -1.348060 0.323254 -0.461050 -1.702573 -48.397386 35.139505 39.662287 4.053225 22.557426 2.465002 1.532896 2.387634 1.720832 2.030237 2.442877 0.937029 2.395595 0.512002 0.475712 0.299685 0.552887 1.380119 1.918725 0.258658
+1 -0.006061 1 1 -0.777424 1.290625 0.413722 -2.055872 -1.811748 1.402872 1.980552 -1.178473 -0.420674 -1.687205 2.306014 -2.223600 60.783619 -59.715334 14.385102 -29.584272 27.145218 0.320293 0.407206 0.907038 2.330842 1.207090 0.807981 2.491542 2.098906 2.309213 2.183762 1.988124 1.154420 2.083381 2.381174 1.146224
+1 -0.011890 1 1 2.061937 0.074079 0.969449 -1.903349 -1.895313 1.225928 1.599258 -0.739203 -1.933839 -0.682876 2.285677 -0.023274 -1.276670 -6.996035 17.641957 -41.630920 59.121178 2.119607 1.476940 2.429431 2.191712 0.605842 0.393666 0.587235 0.413484 0.676850 1.311914 0.840821 0.920640 1.446251 1.888712 2.087069
+1 -0.048249 1 1 -1.097481 -1.077662 2.161262 1.241664 2.186791 1.472746 -1.728972 -2.246196 -0.869678 1.144707 -1.599689 -1.794582 -71.482812 -61.615128 34.544196 -65.704745 0.356598 1.275256 1.233566 0.286456 0.968040 1.596375 0.526730 0.508720 1.558602 2.425981 0.453992 1.993482 1.208960 0.745691 1.823699 0.656308
+1 -0.009795 1 1 2.331246 -2.257906 0.238190 -2.271455 -1.278976 2.172775 1.525097 1.614931 -1.221401 -0.916692 -2.044267 0.029275 61.762910 49.221396 13.996956 46.847766 20.406617 2.485299 0.675997 0.485051 1.995646 1.568390 0.424566 2.427537 1.863868 0.779369 0.855458 1.685811 0.680958 0.610125 0.377669 1.737252
+1 0.000124 1 1 -0.743516 0.988223 -2.099087 2.292917 -0.866312 1.177124 1.314661 -0.879046 -0.782779 0.828810 -0.006059 1.834279 8.972081 43.763786 -62.055278 -13.065250 12.337724 2.276991 0.628814 1.727399 2.142492 1.358643 0.963084 1.553642 2.303776 0.813452 2.192872 2.095128 1.813117 0.566507 0.776538 0.530400
+1 0.022367 1 1 -0.819679 -2.039302 -1.350883 -0.001236 -1.924623 -1.302791 -2.247210 0.943964 -1.402272 -1.333969 1.537135 1.316850 -57.185795 -71.653996 61.282006 66.672374 62.588279 0.943028 1.968699 0.923534 0.593823 0.891062 1.579259 0.861001 0.349050 2.237905 0.720370 1.504017 0.765996 1.094837 1.929054 0.613856
+1 -0.014812 1 1 -1.482255 2.135095 -0.300633 -1.053636 0.697551 -0.678584 -0.972038 0.801957 1.064601 -0.200713 0.681792 -1.652702 -68.213794 -19.242099 -1.953107 24.121794 -35.004535 1.056787 1.418787 1.557157 0.630862 2.400735 1.404683 0.751173 1.707021 1.649371 2.486039 1.853712 1.087670 0.721511 0.434400 1.204719
+1 -0.016118 1 1 -0.624601 1.538651 -1.487685 0.419883 -2.189408 1.673145 1.732135 -1.152195 -1.735141 -2.253103 0.848389 -0.810646 -32.156604 -6.050017 17.357993 -14.210375 -33.775715 0.348482 1.684121 1.523357 1.803022 1.888242 0.937893 1.173258 1.439323 2.454813 1.293142 0.339881 1.134425 1.275872 0.334453 2.159885
+1 -0.000764 1 1 -1.859564 -1.127723 -0.407122 -0.110255 -1.088510 -1.087044 -0.021365 -0.940525 -2.045324 1.115479 1.978891 -0.823936 57.768495 -34.901399 62.187280 -18.379768 -58.764762 0.484593 1.048185 0.839155 2.177633 2.471936 1.085623 2.319799 2.361117 1.549694 1.216222 1.290874 0.462898 0.922249 1.482438 0.329199
+1 -0.027508 1 1 -0.395180 -2.026965 -1.335888 2.260893 -1.881044 0.707655 -0.515056 0.105866 -1.999029 1.656528 0.471581 -0.378889 -49.455845 -54.382915 -63.655820 -63.361955 -74.380194 1.256256 1.399269 2.008724 0.871949 2.092838 1.573470 0.307650 1.676980 0.751345 2.352822 1.637327 0.299982 1.039762 1.028924 1.129468
+1 -0.023822 1 1 0.778243 -1.654806 0.195557 2.195110 -0.080200 -0.173054 -0.975219 -0.816271 -1.303161 0.962805 -0.475135 1.909417 6.276419 37.767174 -47.112713 26.629152 -43.840211 1.038615 2.003381 1.072779 2.442786 1.654806 1.572045 1.118839 0.328835 2.228246 0.380266 0.376291 1.071050 0.396212 0.642296 1.069496
+1 0.054530 1 1 -2.108537 -1.023282 1.920919 0.313505 0.625384 2.198257 0.971464 -1.026218 -0.296003 1.361705 -1.897893 0.267154 -27.042425 -2.028853 -48.938909 -66.237267 50.261588 0.572651 0.550069 1.258977 2.124626 0.333083 1.632233 2.449034 0.922910 1.356093 0.862292 1.789449 1.022392 1.596172 1.620786 1.308889
+1 -0.000407 1 1 -1.398310 -0.707080 0.743853 -0.030248 0.552724 1.510343 -1.299111 -1.661474 1.215795 0.952812 1.218623 1.356817 24.697639 43.224566 25.283825 -4.758673 -29.017315 0.714775 1.966915 2.442891 1.177837 1.898914 0.293260 0.566959 1.631621 1.153352 2.134155 0.737482 1.109945 1.595427 0.335267 2.339007
+1 0.072606 1 1 1.542510 2.110777 0.968980 -0.364186 0.512264 0.091399 -0.100298 1.327967 1.268199 0.492740 1.806390 -1.919639 74.899360 33.549814 21.727812 -70.663169 64.120947 0.336316 1.955205 1.387101 2.254063 2.292139 0.980172 0.747758 0.562101 0.985237 0.370858 2.007760 0.419515 0.795579 1.044769 1.928475
+1 0.009891 1 1 -1.937343 1.682524 -0.857263 -2.252673 -1.337997 -0.186480 -0.430816 2.210857 0.682370 -1.361835 -0.285640 1.171317 -64.922659 -55.130226 -23.704739 -5.556717 58.262965 1.759834 0.526589 0.381989 2.334254 2.312723 0.435304 0.656907 1.385858 1.619027 0.989318 1.475543 1.449501 0.265815 0.550698 0.589631
+1 -0.038006 1 1 0.895849 0.444281 -2.101988 0.667564 -0.448998 -1.773246 -1.803417 0.063687 0.676145 -2.318130 1.216872 0.195180 18.086024 71.809248 -1.970103 38.471447 -60.388189 0.710709 1.135175 0.381512 1.067149 2.317145 0.505802 2.012618 1.078103 1.928369 0.348762 1.896660 0.660958 1.969307 2.144078 1.021160
+1 -0.055432 1 1 -0.725187 -1.985783 -1.920738 -1.982851 0.236511 -2.221186 0.076500 -0.742065 1.815578 1.707398 -2.212305 -1.462001 -46.330964 -34.509093 55.667808 58.843426 31.464355 2.446241 1.216573 0.446304 1.024399 1.573940 1.462056 2.028409 0.964207 2.435211 0.346863 1.478357 1.487845 1.205884 0.799767 1.681712
+1 -0.019027 1 1 -0.097742 1.867552 -1.271044 -1.172761 1.328020 2.153046 -0.192380 -0.630433 -2.230821 -1.645147 2.320681 -0.757355 -22.320103 16.026272 -46.451719 35.956830 -23.553478 1.175377 1.063810 2.446155 2.023594 1.048153 0.298725 2.414517 1.285426 1.147389 0.910138 0.431903 2.001333 0.410360 2.175810 1.081701
+1 0.004959 1 1 0.296923 -0.043195 -0.265672 2.194467 -1.455808 -1.038102 -2.108917 2.021138 -2.347614 0.477805 0.558597 1.259054 72.881335 16.600405 3.004909 -46.492584 -50.857552 0.431773 2.065223 0.953265 0.774681 0.810289 0.770494 2.434985 1.048407 2.329606 0.684067 1.106869 1.649186 1.616000 1.860820 1.297838
+1 0.012270 1 1 0.749049 -2.243294 0.778540 -1.377025 -1.121910 -1.677910 -1.700791 0.161799 0.309878 0.935781 -2.290331 1.906187 -71.781218 23.067835 -48.890183 2.690534 69.799525 0.934129 0.907880 0.740293 1.110323 1.195686 0.392918 1.519297 1.081199 2.209328 1.926153 1.353267 0.601331 1.072765 2.207737 2.180415
+1 0.006424 1 1 0.210237 -0.840997 -2.183439 -1.693959 1.884836 1.758379 1.687203 -2.339981 1.534164 -1.497248 -0.087977 1.062520 -69.627320 73.641052 35.153193 -30.278850 53.373920 2.206978 0.682333 1.224080 0.616402 2.365221 0.769562 0.276927 0.559309 1.312498 1.652793 1.483515 0.439023 2.404993 0.968792 0.734433
+1 0.021095 1 1 -0.287856 1.633152 -1.275209 -0.489892 -1.065847 -1.905087 1.882478 -0.175790 0.171065 0.526164 -1.918221 -2.079572 13.482923 -42.510644 -26.400842 -18.955117 21.342394 2.149248 2.408486 1.174392 2.499064 0.271416 2.441009 1.034433 1.457725 1.227878 1.443869 2.358195 1.938292 0.626858 0.349264 1.326387
+1 -0.046809 1 1 -0.705517 -1.252658 1.533044 -1.473177 -0.788143 0.211174 0.765664 -1.026002 -1.379385 1.622195 -1.650524 1.472022 7.551608 19.873593 -34.516968 73.324295 -38.577185 0.373695 2.434266 2.456379 0.612911 2.192780 0.547655 1.188188 0.376373 2.449879 1.611999 2.110046 0.538450 1.734212 1.899120 1.511858
+1 -0.001453 1 1 -2.218357 0.504330 -1.310086 -2.325309 -1.629477 1.782609 -1.058494 -0.847099 -1.069389 -0.166588 -0.691785 -1.365007 -56.109289 21.183278 -72.651505 -53.848116 74.713658 2.311816 0.943513 1.116801 2.065726 0.406307 1.556596 2.461842 2.435780 0.910632 1.984703 2.152330 2.456544 1.134514 0.524690 2.221839
+1 -0.007013 1 1 -2.107500 2.268209 -1.441881 2.126306 -1.927588 0.701201 -0.598485 2.206981 1.512572 -1.534903 -1.506467 0.468614 50.549975 -6.566213 41.658619 -43.583299 -54.503868 1.427282 0.327465 1.709910 0.704460 1.856346 0.357810 0.955503 2.391187 0.687349 2.267887 0.620722 0.726152 1.938329 1.248309 0.574447
+1 0.030563 1 1 -0.234856 1.753572 1.010876 1.631397 2.206281 -0.829389 -0.294102 0.325566 0.710643 -2.129033 -1.485793 -0.781999 -6.281702 23.437189 8.829777 52.066820 -12.961553 0.702702 1.568014 0.865688 0.375941 1.946719 0.500112 0.888352 1.036177 1.518843 2.447818 0.728618 0.636697 1.460284 1.488034 2.146273
+1 -0.015135 1 1 1.481515 -0.449619 1.919361 -2.307589 -0.692320 -0.932714 2.001559 -1.538418 0.693854 -1.558149 -1.062716 -1.117712 -57.204387 65.863732 -28.254518 26.313891 57.568491 2.179432 1.209869 0.273511 1.648013 2.155541 2.433475 0.412162 0.955424 1.056964 2.138301 0.683769 0.613532 1.383053 1.714162 2.426226
+1 -0.011605 1 1 0.028785 -1.585321 -0.641154 1.357638 0.428831 2.125243 -0.947306 1.792842 1.279530 -2.276238 -1.562263 0.480843 -7.172736 47.831834 59.627808 14.570140 -69.652007 0.755721 1.653775 2.244059 0.648810 0.292920 1.601023 2.145931 0.656623 1.106193 1.531817 2.246185 0.377526 1.571640 1.044255 2.291996
+1 0.020413 1 1 -0.276903 1.938394 1.843787 -0.144172 -0.933963 -0.152850 -0.702675 -0.605977 -1.178007 -2.023309 -1.156765 1.570858 -67.212404 11.121202 14.046671 -17.603573 -63.254766 0.282118 2.313086 2.033098 1.035703 0.310764 2.260238 0.324456 0.631703 0.783033 1.687560 0.816212 1.321764 2.133833 2.079128 0.657982
+1 -0.060244 1 1 -2.035470 1.801431 -0.454102 1.985441 0.879080 1.365091 -1.535023 1.195618 1.120073 -0.932593 -0.684077 0.947884 -47.682555 49.305039 69.787404 66.890954 -13.728470 0.859170 1.074226 2.024866 2.178152 2.195881 0.916537 2.243975 1.492071 2.480497 0.955793 0.515943 1.458685 1.615685 1.067842 0.475948
+1 -0.011789 1 1 0.764725 2.051476 -1.396169 2.279897 1.788262 -0.301307 1.758994 -2.123350 -0.223448 0.283540 1.227872 1.296090 -63.197049 -2.803003 -10.080187 -67.696130 -18.853269 0.371548 2.352694 1.730712 1.575925 1.076191 1.295197 1.121444 1.366919 0.556600 0.771740 0.877357 0.747064 2.398825 0.803190 0.705937
+1 -0.009568 1 1 0.240777 -1.196064 0.804569 -2.159368 2.314908 1.175150 1.129637 -0.413706 2.330525 -0.252710 -1.436639 0.693882 -34.845496 -48.250438 -45.106061 2.429275 28.829530 1.943737 2.135665 1.370100 2.266362 1.999463 0.469499 1.616809 1.954255 1.158042 2.209700 1.433840 0.299074 1.542969 0.686171 0.477535
+1 -0.003986 1 1 0.897689 -1.616556 2.175178 -0.495258 -1.722652 0.312722 1.600570 -2.244381 1.366484 -1.694343 0.146240 -2.014714 61.306369 26.139796 -18.450748 -51.726489 32.899527 2.010372 1.564647 0.514914 2.166938 0.481383 1.112372 1.878161 0.258361 1.269942 1.913827 1.193999 1.298006 1.079877 2.490403 0.947526
+1 -0.009711 1 1 1.288749 1.865177 1.212092 -0.020947 1.375294 0.304261 0.777243 0.387941 -1.820147 1.613833 -0.826492 1.269291 -0.443030 53.992482 -48.350964 65.353778 -49.045716 0.454679 2.284022 1.799645 1.380146 2.372042 0.657538 0.745955 1.773999 2.357242 1.673627 0.651328 2.114552 2.016515 1.312467 1.141858
+1 -0.032357 1 1 -0.682359 1.544137 1.187058 -1.373442 -2.165721 -0.772882 2.230325 -1.985882 1.130388 -1.926911 -2.054337 0.434046 7.318780 6.741009 46.137740 -62.997829 45.484467 2.236635 1.877984 1.777471 2.203154 1.658821 1.563715 0.611346 0.647646 0.992829 1.981611 1.930010 0.926031 2.050784 1.270431 1.126907
+1 0.041897 1 1 -1.454361 -0.286131 2.342039 0.073431 -0.496959 -2.042851 0.268232 -1.575625 2.096045 -1.589493 -0.069997 1.659444 -74.802403 -53.994078 21.523735 -50.583976 35.122296 2.131488 0.922932 1.725872 1.226822 1.690811 1.459163 0.649414 1.449682 1.061155 0.581172 2.004465 1.298559 1.388645 1.199651 1.790502
+1 0.002868 1 1 0.713313 0.337100 1.344444 0.168892 1.713188 0.860856 1.365311 2.164315 0.714199 1.081633 -1.396845 0.342039 -14.650214 73.851855 -21.881140 43.685520 -27.469944 1.564809 0.992371 1.027071 1.474846 0.984084 1.246139 2.354220 0.368753 0.382481 1.604424 0.799796 2.173998 2.138549 0.339043 0.550235
+1 -0.020523 1 1 -0.809748 -0.048653 2.251721 -0.519381 -1.884614 1.977729 -1.493927 -0.815675 -0.706366 -1.392934 0.104439 2.300768 -27.340451 -60.965442 3.808496 -40.603069 -65.775435 1.558879 0.321533 1.009665 1.433815 2.128317 1.624172 1.960642 0.508467 1.806917 2.108150 2.418203 2.486002 1.241277 1.644019 0.277135
+1 0.013453 1 1 2.077588 -0.777075 -2.273557 1.091188 -1.022310 -0.596596 0.981717 1.643440 1.987236 -1.944196 -0.392872 -0.948728 46.389450 -32.513406 -2.821934 -28.245576 26.602486 0.744753 1.814351 1.055156 1.013685 1.504181 1.266169 1.493400 2.316964 1.967576 2.299995 0.258507 1.477218 0.359322 1.619430 1.014526
+1 -0.021374 1 1 -0.367947 -1.429545 2.114821 -1.758382 -1.727440 -0.052625 1.456287 -0.327832 -1.085672 -0.518108 0.652693 -0.623668 -52.010009 67.786429 36.511099 -7.954501 -41.301105 2.160032 1.398650 0.603229 1.476487 1.575951 1.501122 1.606520 2.273512 0.661169 1.020563 2.356022 1.403034 2.287150 0.377356 0.970301
+1 -0.012997 1 1 -0.425659 -0.645576 -2.280754 -2.057215 -0.822608 0.568393 0.967256 -1.077831 -0.687344 -2.130901 0.095076 0.441254 -36.417382 -66.943684 27.507199 13.486923 24.711215 0.945883 0.452470 1.166845 1.665006 2.007915 0.773372 1.312307 0.702279 1.203316 0.387466 2.134707 1.017916 0.619516 0.708235 2.304526
+1 -0.000729 1 1 -1.461559 1.261590 -2.209122 0.192518 -1.758829 0.182229 -0.337614 -0.568568 0.796395 1.828159 1.100501 -0.008512 -53.866283 69.380775 -17.312647 26.337518 4.662423 2.295201 0.685728 2.035426 1.909815 1.259261 2.394254 0.473080 1.061541 0.328258 1.526790 1.012497 1.786274 1.653283 0.720649 1.705092
+1 0.035826 1 1 -0.956930 0.263271 -0.140145 0.770437 -0.908347 1.555644 1.376924 -0.585159 -0.009417 1.946103 -0.538820 1.271831 8.478422 -3.162404 -50.518548 -65.234865 -52.375063 0.359746 1.995697 2.438484 1.355278 0.660331 0.427622 2.043797 0.838258 0.609258 1.546140 2.218220 0.626702 2.234842 0.983645 0.617107
+1 0.017288 1 1 -1.000250 -2.106807 -0.209616 1.850452 -1.226407 -0.233693 -2.264780 -2.189530 -0.386026 1.028455 0.205189 -0.853056 -70.693475 4.767531 27.887772 -40.217141 -29.484079 2.291337 1.000986 1.826186 1.950101 1.088665 1.695550 2.363509 1.250230 1.359024 0.619693 1.433367 1.342386 2.236231 1.840855 0.997602
+1 0.055633 1 1 -1.138887 0.451382 -0.564100 0.504936 -0.545262 1.379851 1.484645 0.336133 -0.759629 -1.224866 2.110278 1.998449 -62.791673 60.359796 17.087292 -63.875659 -8.198709 2.189494 1.583052 1.610301 0.575481 0.859579 1.187446 1.397996 0.870272 0.913982 2.037069 0.272778 0.574352 2.130700 1.169270 1.914318
+1 -0.006750 1 1 0.128141 0.109219 -2.195089 0.440010 1.505063 -0.506717 -1.112571 -0.218148 -0.181388 0.320926 -1.889729 0.819449 -58.183254 -35.947088 37.289732 28.527712 65.252208 2.032970 1.126165 1.957344 1.328080 0.284904 1.885117 2.405790 0.869563 2.496022 0.885205 2.138363 1.717384 0.329021 0.855646 0.334448
+1 0.029596 1 1 1.541984 -2.007522 0.286073 1.392895 -0.761435 1.402425 -0.805535 0.061196 1.220710 -1.264137 1.817614 -1.780294 72.305079 -68.531554 40.177741 -32.708938 10.887179 1.087310 1.419008 0.764784 0.967813 2.276947 2.139592 2.121580 0.891896 2.092395 0.882401 2.256355 0.310402 0.674066 1.779275 1.030701
+1 0.001879 1 1 0.355315 1.177154 1.812553 -2.009360 -2.329151 -0.223085 1.679586 1.594020 0.764033 -0.162878 0.413639 1.258177 54.044641 -71.713864 -44.919854 -17.982925 10.977081 1.252016 2.125625 1.386048 0.304168 1.646417 2.329346 0.816266 2.228644 0.325034 1.345838 1.742019 0.358199 0.747193 2.330251 0.284919
+1 0.007826 1 1 -0.530805 -0.684143 -0.169902 0.164148 2.085681 -1.427613 1.585758 -1.444547 -0.270896 -0.779976 0.816946 -1.485976 27.580694 48.725131 73.275187 36.075826 26.414532 0.610509 2.325995 0.746273 0.352213 1.395139 2.354892 0.422429 0.264892 0.782705 0.666559 1.607980 2.064597 1.684032 2.273429 1.520155
+1 0.002504 1 1 1.779129 1.712780 -1.288151 -1.241496 0.631131 -0.170992 0.693414 0.464818 -0.951463 -2.107963 -0.799169 -1.327107 -30.339536 -66.573784 -55.584292 -5.196622 -39.621339 0.387267 1.043231 0.827731 1.421600 1.575760 0.549746 0.324280 2.166468 1.574706 0.832100 0.600854 2.052771 0.924715 2.432548 0.591217
+1 0.046188 1 1 1.110315 0.009600 1.123088 -2.085079 2.117827 1.643708 1.780401 -0.465031 2.077296 -0.979988 -0.853784 -0.319303 28.009042 47.974857 63.415341 71.628428 -41.015420 2.182617 0.747078 0.383417 1.582620 1.097667 2.237102 0.727643 2.239187 2.017886 1.868875 1.683234 2.365473 0.506878 2.091379 1.803727
+1 0.015323 1 1 1.365365 -1.645119 -1.926308 -1.344761 -0.778675 -0.881893 -1.507537 1.346256 2.351429 -2.331969 -0.456921 1.723427 -44.853008 55.490034 71.003696 -40.879462 -61.115735 1.792553 1.436812 0.754580 0.476051 1.495300 0.500711 1.947630 2.311619 2.134191 1.349618 2.272276 2.387899 1.676011 2.462098 2.222649
+1 0.006998 1 1 1.841389 1.969380 -0.442708 0.267015 1.534314 1.021090 -1.055017 1.054110 -2.154617 2.055603 2.000290 0.686454 41.293207 -35.062827 49.074242 -59.207732 -4.353125 1.930360 2.316264 1.448785 1.725488 1.522632 0.877103 0.967996 0.863158 0.593279 0.746308 0.941668 1.610960 0.403141 2.345090 2.178528
+1 -0.013763 1 1 -1.633575 -1.120420 -0.199866 0.791863 1.050847 -0.454149 1.188850 0.480007 -0.139830 1.366869 0.066714 -0.291125 -47.185198 8.372209 11.711640 37.538532 10.099283 0.454815 2.332215 1.792289 1.493996 1.086656 1.674886 1.563623 1.307939 1.534189 1.614960 2.383488 1.790851 2.085631 1.958940 1.155684
+1 -0.015571 1 1 -2.052241 -2.032119 1.573690 -1.628020 -1.999638 0.843317 -1.242962 -0.449670 1.075711 -1.963132 1.797022 0.849664 56.128240 -2.677441 0.246674 -54.157174 -19.619836 0.616344 1.394383 0.901556 2.453524 2.136395 2.384999 2.422606 2.240008 2.307489 2.473738 2.119129 2.452227 0.579123 1.313837 1.653626
+1 0.050048 1 1 2.050357 -1.357751 -2.340036 0.609265 -0.105449 -0.419117 0.930533 -0.947011 2.037946 2.118074 1.078060 -0.185854 21.198552 34.057320 1.371874 -42.915684 66.106563 1.420074 0.678668 0.369738 1.188492 0.982991 0.876842 1.084171 0.411312 2.417230 1.890000 1.231948 2.352386 1.055277 0.787191 1.816421
+1 -0.024808 1 1 -1.158467 1.244056 -0.013137 0.691680 -0.394249 -0.518223 -1.275624 1.952816 -0.805839 -0.330989 -2.316614 -1.574349 -0.464921 -13.922789 -0.310237 35.838987 -54.152398 2.284670 1.449099 0.250222 1.729938 2.068300 0.918084 1.231773 1.656609 0.382775 2.055463 1.169953 2.156872 2.298505 2.221103 1.821098
+1 -0.016321 1 1 -1.012689 0.884219 -1.806563 -0.980232 -0.247566 0.193495 0.530497 0.229703 1.176327 2.061924 -0.154694 1.304501 -63.557526 -61.344931 -74.253565 20.331041 3.807269 0.456523 1.778839 0.441255 1.671267 1.491399 2.444465 0.625326 1.599861 0.618644 1.805440 2.035280 1.693047 0.791314 1.358468 0.278612
+1 0.010741 1 1 -0.343597 -2.152915 -2.315417 -0.298737 -2.181202 -1.793550 0.951524 -1.578473 1.356129 -1.364361 -0.322170 -0.175133 56.581083 -41.733300 -11.574584 15.961514 65.164848 0.259050 1.608836 0.710736 1.585938 0.616189 1.033483 1.250818 2.251224 1.826435 1.636296 0.981169 1.764905 0.251348 0.404862 2.014965
+1 0.008892 1 1 0.518290 -2.308246 -2.307285 -0.290951 1.440223 -1.713904 1.254578 -2.255769 -1.534872 -0.976452 2.021597 0.664848 32.590668 -48.646053 55.786709 -42.776926 -1.787621 0.706924 0.521027 1.398260 0.804883 2.164535 0.586054 0.809791 1.410675 2.465433 2.039649 0.875365 1.015369 0.552921 1.948408 1.890597
+1 0.003315 1 1 -1.295981 -0.893056 -0.627973 1.401713 1.356073 -2.312200 1.934333 -0.442705 0.324291 -1.867159 -1.546854 0.281675 -58.318679 -62.041145 74.475231 -44.793006 13.948236 1.045050 2.151192 1.331772 1.587545 0.613300 1.988679 1.471164 2.112520 1.624875 0.272770 0.440591 1.768363 2.118708 2.124914 0.674029
+1 -0.009696 1 1 0.484829 0.805949 2.178943 1.526878 -1.440290 0.596634 -0.339215 0.806094 -0.100782 -2.089853 1.985862 -1.464086 38.249411 -42.151709 6.224846 70.986604 -28.148693 1.448637 1.492061 2.326503 0.285389 1.036722 1.694027 1.504330 1.522152 1.814319 0.502118 0.843193 0.287496 0.442571 1.295719 0.894501
+1 0.027579 1 1 -1.296161 0.797054 -1.227036 -1.375477 1.344948 -0.789175 1.706055 -1.221026 0.668516 1.419407 1.851987 1.013302 -0.334957 70.376174 62.364022 -47.884055 -37.313249 1.768252 0.253845 1.866524 0.415659 1.236215 2.070894 1.766022 1.033795 1.988978 1.999562 2.135060 2.449655 2.345292 1.077217 0.536563
+1 -0.013950 1 1 1.104287 -2.342164 -2.169188 2.217871 0.759037 0.703714 -0.772398 0.939850 0.127161 -2.227463 -1.745500 -2.003374 -21.838926 3.174851 -40.284950 30.850595 -44.044260 1.346723 0.880690 0.511958 1.971892 0.593006 0.659464 1.616713 0.343952 2.047749 2.020040 2.063921 1.575292 1.674025 0.591729 1.686012
+1 0.008992 1 1 -0.088029 0.193974 -0.843955 -0.067846 0.111909 0.611197 -0.626804 2.210375 2.017213 -2.344097 -1.672211 -0.159404 71.303130 41.709980 69.640186 -7.392599 -47.413457 2.455526 2.031381 1.418199 0.665731 1.196362 0.502732 2.172262 2.216456 2.473487 2.399528 1.373558 1.897352 1.042572 1.015232 0.507668
+1 -0.055788 1 1 1.637013 2.354676 0.389994 -0.297452 0.562158 -0.146152 -1.229262 -1.091739 1.185816 1.310080 2.226136 -1.693286 -30.148916 -12.837788 -64.701205 66.851898 -70.143277 0.654050 0.613663 1.340946 0.523806 0.865867 1.134636 0.334383 0.981926 0.987893 2.261639 1.358323 2.333152 1.781156 1.143641 0.917617
+1 0.007894 1 1 -0.424742 0.627017 1.377619 1.683225 1.492922 -1.924594 -0.813898 0.886150 -2.335147 -2.033031 0.374268 -0.710797 -14.568488 -52.582774 41.319369 -45.363705 22.203255 0.926537 1.565441 0.366468 2.470261 2.181790 0.342591 1.685361 2.116201 0.485627 0.424579 0.403289 0.321367 0.464888 0.618514 1.856774
+1 0.072134 1 1 -1.194268 -1.999271 2.304974 -0.849836 0.063802 -2.103575 2.275092 1.149480 -1.487788 -1.309499 -1.899237 1.252975 -29.364845 -34.954930 62.487827 -67.083347 -69.810732 1.240471 1.602338 1.743440 1.740889 1.620744 0.596486 0.642042 1.297648 1.825377 1.857810 2.465863 0.264334 0.419894 0.405999 0.871353
+1 -0.042000 1 1 0.676778 -1.090747 -0.982880 -2.336370 0.959331 -2.314532 0.437387 -0.165880 1.781878 0.793904 -2.338410 -0.332305 -27.561589 -27.631897 -9.287259 59.038401 8.412905 0.560381 1.330506 0.566336 2.407168 1.528439 1.728774 0.498822 1.696686 1.192568 1.984978 2.279727 1.627433 0.509400 1.740404 2.463521
+1 0.013186 1 1 -0.899546 -1.322814 0.517757 -1.847628 1.556060 -1.058113 0.850633 -0.801697 -1.398268 -0.009294 -0.693653 0.218075 -33.331856 41.495497 64.818810 -40.265558 56.766438 2.477931 0.583430 1.706271 0.300424 1.718152 1.989003 2.415424 0.776971 1.044055 1.178702 0.697144 0.401888 1.526846 1.957625 1.552645
+1 0.025802 1 1 -0.590103 1.711115 -1.002619 0.488853 -2.253783 -1.156665 -1.465663 -1.748247 -1.036811 0.733432 -0.820376 0.394560 33.245341 4.449228 -71.824587 44.158934 -20.788897 0.640118 0.471443 0.534283 1.450600 0.735326 0.879240 0.884322 0.799966 0.529492 1.924011 1.346675 2.323443 0.612568 0.938737 1.854474
+1 -0.004300 1 1 0.686670 0.216353 -1.722108 0.024559 -1.929621 -0.485324 0.297392 -1.571699 2.107096 0.359899 -1.877354 1.464481 22.827768 -33.702070 -30.685246 -26.928628 -39.458300 0.990192 0.407428 2.394706 1.325592 1.224330 0.321422 1.388990 0.258617 1.082995 0.902339 2.120021 1.695833 0.358660 1.755794 2.382687
+1 0.030686 1 1 2.282021 -0.206713 -1.187533 -1.901686 -2.207400 0.875331 -0.397071 -0.828403 2.145956 -1.535759 -1.738762 -1.840178 -14.613472 -58.631176 -64.167289 40.377884 31.104093 1.622454 2.336604 1.312266 2.251498 1.928228 2.481311 1.143244 1.006711 1.295013 0.286254 2.078913 1.538366 2.075810 1.134917 0.550497
+1 -0.004318 1 1 0.602148 -1.916071 1.053822 -2.278273 1.942468 -0.372295 0.888150 -1.703457 -2.243185 -2.097881 -0.987633 -2.118372 -44.076948 48.738992 6.238417 -0.930299 -35.542616 0.403800 2.166006 0.561351 1.870458 1.284911 1.492385 1.012715 0.946109 2.004730 1.242961 0.692971 2.260894 2.348830 2.042184 0.735279
+1 0.013150 1 1 0.853411 -1.232712 2.178387 1.593571 -2.077819 1.618076 -0.184526 -0.575986 -1.354374 -2.122034 -1.668731 1.780751 22.344876 -49.672427 55.512479 -1.762175 -66.875846 0.889843 1.339834 2.096065 1.810050 0.765842 0.758784 1.377909 0.769552 2.364657 0.287694 1.530649 0.615620 0.470806 1.093993 1.243682
+1 -0.008344 1 1 0.309144 -1.974442 0.202836 2.009695 -1.453366 2.296804 -1.510782 -1.362724 -1.100579 -1.297588 0.376422 -2.212084 71.946857 60.820625 -37.756117 -67.052497 -1.311029 1.608012 0.358197 0.719952 1.230095 0.461693 0.930833 1.768469 1.667255 1.547856 1.810702 0.462542 1.689602 1.386234 1.186498 1.219405
+1 -0.033648 1 1 1.980347 0.082823 1.855468 -1.745728 -1.121988 1.727862 -2.269851 2.115769 0.041867 1.512167 1.074064 -1.376762 -44.659600 6.107939 56.122208 45.950337 -62.684919 2.193494 1.311234 0.652979 0.618811 2.364833 0.997400 2.307529 0.885920 0.649846 1.962933 0.758135 1.717027 1.071422 2.134089 1.883078
+1 0.017739 1 1 1.102480 0.269121 -0.784475 0.597715 -1.015193 1.214359 0.375104 -0.800510 -0.299759 -0.500441 0.698661 -0.884367 -21.656303 72.512912 -25.491861 -41.716013 -21.024147 2.082315 2.465934 1.455377 2.267991 2.379648 2.489042 0.573058 0.634233 0.548068 1.381987 1.812569 0.354396 2.091858 0.852054 0.721035
+1 -0.008243 1 1 1.957092 0.379125 0.796567 0.005204 -2.066168 -0.484617 -1.953394 0.526626 1.140564 -0.537020 -1.473442 -0.537715 31.288426 -35.432439 -12.995223 -10.709779 0.750142 1.489625 1.875247 0.774873 1.784187 0.335603 1.235245 1.515288 1.188987 0.299033 0.839776 1.364560 1.406039 1.052386 1.695739 1.038665
+1 0.013641 1 1 0.741968 1.281796 -1.894681 -2.297729 0.098816 2.033616 0.034360 -2.143490 0.573775 1.887906 1.517294 -2.288154 25.473166 27.497461 -0.170676 -18.553536 20.719501 0.364853 2.331747 0.667607 1.223086 1.912807 2.045698 1.304054 1.486554 2.011559 1.266194 1.930939 0.785664 0.899817 2.479607 1.760490
+1 0.077636 1 1 -0.822461 -1.661432 1.924499 -0.790126 -0.139151 -1.371962 -0.848772 -0.905305 0.838353 0.153977 0.783603 -1.106210 -54.150833 -63.056383 -38.630596 -64.421033 -24.299163 2.184518 1.196391 0.992131 1.493231 1.728463 2.033537 1.650418 2.079398 0.691293 1.061048 1.028082 0.473837 0.282998 1.340026 0.820509
+1 0.001486 1 1 -0.434883 -0.161752 0.487634 0.822557 -1.434873 2.101477 0.175693 -1.792312 -1.796760 -1.165371 -1.695755 -0.022976 8.479875 21.258216 -13.158205 -49.948020 73.631578 1.763909 1.520934 1.588224 0.778919 2.288958 1.511270 1.166782 0.611845 2.276800 1.926487 2.463318 2.479401 0.546189 1.293401 2.444933
+1 0.038784 1 1 -0.297784 -0.290559 -1.385530 2.024703 1.014668 -0.602640 -1.646764 -1.309659 0.132354 0.222165 1.718018 1.914068 -55.255125 -22.883719 -6.670242 -56.749534 60.583744 1.839694 1.743120 0.861925 2.376060 0.692509 1.254160 2.168157 0.718343 1.192905 0.901485 1.255632 2.159848 0.567791 2.121389 2.185800
+1 0.014177 1 1 -2.218020 1.450503 1.421965 -2.262287 2.010564 -0.989681 1.156517 -1.029108 -1.749011 0.252601 -0.401321 -1.568841 -53.839242 73.851777 -23.185404 22.913126 50.903112 0.304142 1.207469 0.433845 0.875066 0.492008 1.924948 1.355653 2.459435 2.471405 1.148800 2.128163 1.283276 1.020490 1.133370 1.556694
+1 -0.015912 1 1 1.327043 -0.130674 -0.269336 1.870623 -1.492803 -0.785384 -0.540116 -1.661983 2.100765 2.336453 0.427132 1.843621 56.709136 10.441548 -8.905537 24.632991 6.672504 0.546592 1.315439 1.587062 1.499907 1.433693 2.329383 1.445658 0.931798 2.227242 1.510122 2.116868 0.446484 1.801707 2.291350 1.212228
+1 0.002748 1 1 1.784360 0.090935 1.532985 2.248481 1.569923 1.032212 2.092230 0.263786 -0.911079 -1.956984 1.446037 1.757829 59.262059 17.427452 -46.817397 40.010402 4.832050 2.308915 1.677605 2.263094 1.071064 0.629871 1.485845 1.355291 0.881786 0.920875 0.901993 0.802391 0.791008 0.715276 1.392681 1.532731
+1 0.010958 1 1 -0.591784 1.744825 0.067914 1.029186 -1.651856 -2.065532 0.782377 1.839055 0.446065 -0.399234 0.509723 -0.209973 18.020081 13.501444 -31.224634 57.584764 27.129868 0.950343 1.160760 0.648641 1.962871 1.977795 0.800102 0.569656 1.958884 2.459464 0.713022 1.760731 2.104279 0.370638 0.560892 0.914139
+1 0.031856 1 1 -1.912001 -1.219831 1.909054 -1.182787 -2.240469 1.143894 -1.120440 -0.528806 -0.082438 -0.098357 0.957086 -2.350109 30.731654 56.909285 74.347321 55.427015 61.842361 1.893406 2.232683 0.695850 1.153607 1.921763 1.813761 2.374163 0.307012 2.204570 0.713344 0.420722 0.830524 1.121914 0.267222 1.699343
+1 -0.026074 1 1 2.174097 0.180904 0.968369 -1.209189 1.693138 -1.542894 0.849554 -0.082900 1.564578 0.729576 0.339284 0.349016 -32.263323 0.325764 -74.892183 -62.915332 -67.992041 0.741380 1.378225 1.577920 0.855607 1.942764 1.529678 2.301438 2.011240 0.404699 1.528598 2.142766 1.469030 2.236590 1.120360 1.143428
+1 0.019457 1 1 -1.798321 0.875582 -0.888552 -0.332473 1.025865 -0.915381 1.145315 -0.794038 0.083733 -1.699396 0.037590 0.315955 -19.556534 -36.672949 -12.248053 -53.032249 -13.004904 1.023788 0.306820 1.220458 0.491421 1.055517 0.325222 2.251289 0.660518 1.323212 1.724683 1.490566 1.937581 2.169735 2.482308 2.142940
+1 0.014855 1 1 -1.148448 -0.025792 0.046250 -0.228342 -1.863413 0.160282 -1.623682 0.218655 -0.735225 -1.042109 1.223365 0.947149 9.028303 -61.317174 -57.742477 22.191564 73.610542 0.960577 2.174550 2.415179 1.171249 1.438857 1.371073 0.629287 0.676374 2.318739 0.304914 0.693312 1.239403 1.649977 1.418863 0.584678
+1 0.010655 1 1 -2.110371 1.138904 -0.161019 -1.334965 -1.067117 0.321370 0.865415 -2.117642 1.465241 -0.645059 1.698947 1.834792 -16.834203 -32.443734 -31.834304 10.846635 49.393565 2.239630 0.468482 0.284543 0.310391 0.484625 1.591344 1.476074 1.381500 0.364405 1.547859 1.861029 0.316288 0.609626 0.985907 0.396218
+1 0.003818 1 1 1.643482 -2.029875 1.591897 -1.940732 1.276872 0.175408 -1.876357 -0.630084 -1.086966 1.287391 -2.118857 -0.111061 -15.705973 29.718071 -28.373799 -28.443857 -5.899981 1.210389 2.251540 0.391653 0.505696 2.479797 0.447462 2.491690 2.339323 2.001471 0.469930 2.108628 1.467886 1.007624 0.877933 1.419482
+1 -0.012725 1 1 1.436558 -2.050840 -2.061839 1.578886 0.878404 -0.570959 -1.684865 -0.779129 0.906659 -1.651608 2.111709 -2.212354 -72.619880 27.682491 -40.366373 12.373146 55.471303 2.217761 1.912354 1.179945 1.329328 1.009184 2.363335 0.577908 1.155274 0.687116 0.611345 0.619348 2.385072 1.401667 1.815795 0.572892
+1 0.015996 1 1 0.832023 2.151774 1.984288 0.350491 0.223114 -1.188259 0.038416 0.056405 0.808746 2.061010 -1.379379 1.734534 47.077582 -17.072363 14.796884 -8.775633 -42.064734 0.895142 0.395679 0.681612 0.352028 0.537867 0.933017 2.463779 1.237615 0.837504 1.426648 0.922183 0.371518 1.849208 1.891725 0.974338
+1 0.014875 1 1 -1.700641 -2.043131 0.268128 1.381787 1.032700 0.864453 0.558977 -1.775851 1.547718 0.103564 1.724449 1.617771 -19.095705 58.478946 55.652436 -49.507762 -26.960477 1.754028 1.945838 1.451671 0.733753 1.435237 1.283459 1.846753 1.119645 0.368156 1.603298 2.124661 0.925813 0.646619 1.718111 1.290652
+1 -0.017699 1 1 1.624450 -1.454810 1.589902 2.233940 2.232923 -0.734237 1.418934 -1.368373 -1.787693 0.440188 -0.218424 -0.104154 -70.436029 -18.345178 72.594382 -6.227862 28.316133 0.763623 1.715725 1.694558 1.428915 0.771572 0.314337 1.567178 0.311277 1.874248 1.976945 2.256820 1.370246 2.470170 0.640833 1.222871
+1 0.024946 1 1 -0.484057 -1.956025 -1.280924 -2.300951 -2.221920 1.872250 2.280893 -0.320834 -1.284947 0.766453 -1.902901 0.934220 -7.710233 14.119503 6.482059 43.961102 -45.759266 0.985264 0.827063 1.444084 1.470450 1.355756 1.946613 0.973665 1.645239 0.540033 1.329936 2.241544 1.129847 0.843858 2.469403 1.261421
+1 -0.017837 1 1 -1.971012 1.298345 -1.782894 0.986214 1.827893 1.327325 -0.104679 -1.626763 0.271168 0.635544 -1.402102 1.525518 -23.172248 -55.966507 20.915968 -65.321255 -4.328958 1.273101 1.004533 0.691554 0.943376 1.073326 0.390368 1.422467 0.408012 0.953139 0.900502 0.494595 0.413181 2.326730 1.844199 0.959967
+1 0.006116 1 1 0.340239 2.275065 0.696361 -1.833041 1.673497 -1.783881 -1.472100 -1.547213 -1.051747 -0.543461 -1.332967 -0.482192 35.052819 -67.276223 -11.473704 61.450106 41.935718 0.829192 1.224043 2.242838 0.374835 1.354417 1.942328 0.962860 2.294067 1.884757 0.856915 1.417712 1.482182 0.536643 0.614843 0.915618
+1 -0.029063 1 1 1.134244 1.627884 -0.283511 -0.741118 -1.127726 -0.469561 1.334208 -2.218590 1.294252 0.096761 0.483076 -0.379661 -12.188037 55.667788 58.512371 17.415917 59.310914 0.453065 2.155491 1.594795 0.974131 0.472393 0.764839 1.901565 2.103143 1.527175 0.730844 2.051841 1.034477 2.204994 1.087428 1.145638
+1 0.042702 1 1 1.822933 -1.910712 1.589547 0.977083 -0.849388 -1.830376 -0.659946 1.256853 -1.703933 -0.809649 1.609254 2.337441 -57.625102 44.917939 -14.203410 -66.707709 -56.468831 1.050374 1.635419 1.986806 1.503537 1.694284 1.327227 1.702318 1.352934 1.767148 1.959969 0.448804 0.298099 0.891797 0.434089 0.485084
+1 0.034974 1 1 -0.666468 0.021155 2.116663 0.924998 0.274166 -0.803617 -0.688857 0.712579 2.138197 -0.001081 0.684479 1.097155 9.906098 -8.212758 -31.819192 -35.159899 67.577958 1.116192 0.843316 2.357209 1.103913 1.456693 1.891826 0.424149 2.170996 1.172108 2.375885 2.242154 2.382053 2.407316 1.761549 2.347622
+1 -0.044759 1 1 -0.424315 -1.624795 0.361704 0.171084 0.852781 2.316576 0.939813 -0.492659 -0.455923 -0.346132 -2.352642 0.792696 28.962036 14.942035 30.785842 67.646266 -69.206482 0.574883 2.060972 1.513777 0.550505 1.837928 1.298452 1.836717 1.202385 0.482330 1.274973 0.969396 1.894066 2.073444 1.875619 0.277999
+1 -0.005364 1 1 0.589668 0.397305 0.044419 1.996431 1.802003 -0.252449 -1.764516 -1.158710 1.862408 1.799962 -1.570271 -2.162311 -0.404056 -40.963890 19.903255 14.005536 41.045881 1.496724 1.939293 1.698294 1.233262 1.941231 0.527212 1.846650 1.655394 2.455846 0.652649 1.828353 2.370775 1.866501 2.288837 1.737676
+1 -0.026912 1 1 0.757530 -1.072439 0.410887 2.134530 -0.376521 0.546800 0.917060 -1.190274 -0.837388 1.922399 1.623889 -1.456679 -48.997258 3.077968 -18.589249 20.491372 -1.506097 1.930416 1.005105 1.307428 1.945432 1.369145 1.968944 0.538289 1.276513 2.106134 2.294031 1.283099 0.290798 1.941864 2.159303 0.405692
+1 0.003404 1 1 -1.736773 -1.411997 0.152992 -1.628831 -1.498334 0.504982 0.222783 -2.039279 -0.961863 2.169240 -1.335864 -2.049273 22.792127 -32.728068 -10.643940 57.293491 -68.298149 2.320249 0.922018 2.108948 2.344789 1.624985 2.118809 1.567716 0.357031 1.374588 1.197463 1.007885 0.773891 1.037784 1.531715 0.537234
+1 -0.001434 1 1 -2.212394 1.748893 -2.239817 -2.044884 -0.909737 1.755459 -0.266869 0.922175 -0.050729 0.339158 -1.757732 -0.226953 -66.097198 4.384938 47.649263 -8.832134 58.316882 1.852476 0.568591 2.065444 2.417126 2.381480 1.776139 2.320233 0.654497 1.384274 1.993666 2.046175 0.319099 0.604809 1.027960 0.670836
+1 -0.020493 1 1 1.811472 -1.338766 1.011209 -2.199287 0.564982 0.185050 -0.049010 0.959716 -0.564613 1.298700 -0.542116 -2.295442 26.486744 -37.295762 20.127067 25.621568 -28.302832 0.839510 1.399996 0.727486 1.862931 0.790008 1.918933 1.501715 0.327451 1.467517 1.564739 2.065011 1.889911 1.988201 2.451488 1.656779
+1 -0.034027 1 1 -1.424490 2.240694 -2.071455 0.189426 -1.898170 0.329784 0.909854 0.214313 1.688724 -0.334761 0.262296 2.325146 -35.372279 -51.889751 -11.053319 -73.124039 -45.717368 0.298009 1.645532 0.960907 0.970574 1.432605 2.037532 1.307792 1.316822 2.334372 2.043896 0.259648 0.404871 2.174241 1.717081 1.981965
+1 0.002544 1 1 -1.967422 0.379451 1.565454 1.313418 1.791347 -0.290200 -0.070363 0.211986 0.282468 2.069335 1.877688 -0.571231 -49.372781 -8.337472 -27.889538 10.536027 -71.000565 0.527601 1.633622 1.027172 0.923407 0.696013 1.647017 1.171676 1.858672 1.204169 1.221003 0.648730 1.212605 1.255101 2.236672 2.495173
+1 0.007304 1 1 0.454206 -0.233377 -1.660566 2.340902 -0.193636 1.822104 -1.708623 0.468601 1.377927 2.138993 -0.760588 1.512644 -10.661684 59.068908 71.130877 -3.346186 10.659253 2.126074 2.169425 1.777905 0.499968 0.705606 0.862995 2.349393 0.255474 2.243733 1.917958 0.873541 1.849159 1.071306 2.446851 2.478992
+1 0.062595 1 1 0.225703 -0.076061 -1.295876 0.880141 0.339556 0.215538 -1.284313 2.004384 -1.181878 -1.111379 0.968580 2.335803 -34.276288 68.423552 -55.355781 -64.609785 -46.649462 1.562495 0.359313 1.475333 2.423655 1.874185 0.930404 1.306674 0.515463 2.389191 0.889038 1.305215 0.742339 1.745553 1.250386 1.743134
+1 0.038987 1 1 0.518448 0.353928 1.425688 -0.955530 0.226654 1.761474 1.871649 1.615611 0.782953 2.098205 1.726167 2.222101 37.388415 37.090711 -16.415160 -39.596563 50.570706 2.002903 2.046921 1.605076 0.519652 0.792247 1.294121 1.037067 0.730048 2.160913 0.464542 1.554212 0.638394 0.736466 2.039935 1.189739
+1 0.026594 1 1 -0.918585 -0.866580 1.388716 -0.313534 -1.119846 0.030111 1.853355 0.449804 1.189698 0.590114 -1.528813 1.904037 -21.994533 -62.119528 -42.914027 -56.057781 -13.120887 1.033706 0.489614 2.187416 0.400842 1.945356 2.347100 2.204739 1.299556 2.379959 0.965544 2.395860 0.468730 2.202055 1.189310 1.235174
+1 0.054304 1 1 1.787209 0.850251 2.197913 -0.098702 -0.129935 -1.985239 -2.192305 0.104147 2.101101 -1.440385 -1.001305 -0.988332 8.889549 6.652143 52.563605 -63.487946 58.083686 1.562669 1.023129 0.480392 2.452148 1.508176 0.918647 1.703938 1.578914 1.814767 1.285654 0.480570 0.942054 1.356496 0.880984 0.949174
+1 0.022069 1 1 -1.284333 1.677804 -0.084429 -0.570057 -0.666233 -0.745569 -0.528275 -0.583957 1.337817 1.883044 -0.078178 0.812581 17.491341 -23.032099 49.504543 -27.137736 46.078496 1.244133 2.388726 2.061620 1.141008 1.669031 2.154511 0.872164 1.216274 2.175549 1.198509 0.597758 1.761388 1.888990 2.259653 1.728868
+1 -0.004278 1 1 1.428743 -1.458396 -2.123967 -1.161132 -1.148425 0.365588 -0.523913 2.050942 -0.943554 -1.131273 1.179649 1.337693 -6.546627 70.847450 33.092685 -11.244362 16.009360 0.914812 2.487146 2.461333 0.630674 1.494421 1.484142 1.980673 1.913355 2.251469 1.443126 1.124588 2.458559 1.245584 2.033337 0.539008
+1 0.005694 1 1 1.236684 -1.399512 -2.070063 0.021660 1.189206 1.748961 -1.089465 1.702172 -0.506335 0.606884 2.291497 -1.170216 53.678896 -68.796681 -65.821164 -6.306545 55.897649 1.701912 1.279988 2.004592 1.173935 1.579619 2.414579 2.322228 0.431642 2.102998 1.337455 0.357493 2.388049 1.934865 1.524500 0.776054
+1 -0.024232 1 1 -1.424884 0.337941 1.343282 -0.510908 -0.865744 1.293286 -1.985700 -0.528300 -0.997060 -0.333974 -0.639092 -1.680992 -53.008674 -66.785568 -15.044032 54.950497 3.005998 0.952141 2.128900 2.427463 0.615226 0.596035 2.065539 1.767814 1.897600 0.704661 0.738465 1.873729 2.261858 0.543797 1.602393 0.416503
+1 -0.026465 1 1 0.560455 -0.497959 0.008563 -2.165083 0.516204 0.326132 0.796747 -1.675022 -0.278984 -0.053131 -2.327576 -2.025491 -4.269121 -51.125572 -67.496520 35.984873 -2.245608 2.245940 0.768388 0.800197 2.164903 2.273356 0.303386 2.004749 1.573541 1.500489 2.213000 0.636415 1.230717 1.907091 0.471708 0.489092
+1 0.052837 1 1 1.242209 1.925219 1.895049 -0.952744 -0.079077 -0.157146 -2.221447 0.394014 1.289040 2.038879 -1.046148 -0.681151 -54.408879 -50.027951 -69.777228 -45.867959 -52.794358 0.403451 0.797978 0.868939 1.006601 1.694273 1.137803 1.810347 1.248420 2.443343 2.011330 1.924878 2.415491 1.909339 2.253354 1.629251
+1 -0.004662 1 1 2.025983 -1.030630 0.949823 -1.903983 1.587590 1.080540 -0.909107 -1.804488 0.903748 1.265113 0.448477 -2.266386 -28.817765 9.825254 -16.955769 24.397264 -55.190969 1.455844 1.122528 1.572290 0.734791 0.886806 2.050932 1.518508 1.311776 0.763554 0.547998 2.447531 0.403521 1.972626 1.678255 1.926001
+1 -0.011565 1 1 -1.077346 -1.952630 -0.770383 1.819231 1.838650 -1.658500 -0.635547 1.353530 2.078202 0.104956 1.559265 0.971264 9.933996 10.665025 -2.931535 -70.307195 46.981492 1.644093 1.516109 1.501570 2.381726 1.421798 0.412764 2.066085 1.943754 2.430392 0.353010 1.290487 0.710793 0.301317 0.986587 0.572173
+1 -0.015143 1 1 1.709609 1.956262 0.560966 -1.333987 1.219775 1.869769 -1.720192 -0.763777 -0.252260 1.416941 -1.892813 0.834676 -12.255902 -34.953138 -57.384955 31.055221 -54.903208 2.001726 0.264969 2.080037 2.429357 0.957509 2.359728 0.695566 0.878731 1.335679 2.001084 0.720026 2.482700 1.986032 1.995947 2.128096
+1 0.046741 1 1 0.698479 0.772624 -1.849302 1.698826 -0.189084 -1.790190 0.876729 -0.456480 -0.295040 -1.295994 -1.112497 1.022119 66.867848 47.922392 -68.358987 -59.502077 -1.411700 0.978441 0.902864 1.935287 1.875428 1.563539 2.145812 0.907999 0.485466 2.222885 0.282670 0.341724 0.604747 2.237090 0.519817 1.318992
+1 0.026131 1 1 -0.299943 1.118304 2.335061 0.597037 1.721241 -0.461763 0.450442 -2.236519 1.553480 -2.011023 -2.001058 0.539375 -43.085518 61.702124 -72.396846 26.206573 53.872909 2.004639 1.968662 0.301432 0.668120 0.835211 1.147573 1.758834 1.721247 2.255451 0.871755 1.091310 1.147083 0.281702 2.060471 2.090424
+1 0.023151 1 1 -2.330943 -2.072218 1.491156 1.366664 1.335165 -0.284796 1.227320 1.444327 1.288594 -0.747208 0.193521 0.960234 -40.942201 -65.574205 -55.666350 -34.346499 -61.610578 0.790340 0.751108 0.625068 1.773618 0.456075 0.995549 0.447318 2.318277 1.524953 1.641368 0.717867 2.198674 0.607977 0.271585 0.785233
+1 -0.012503 1 1 1.691513 -0.584286 0.528288 0.788572 2.298491 -1.419687 -1.849510 -1.789774 -1.560004 0.740213 0.053810 -0.389348 55.349506 -40.846628 40.723126 -16.413607 -13.490143 2.442559 2.343002 0.835597 0.880184 1.002020 1.193142 0.379662 1.472381 2.306443 0.629111 2.222426 1.570787 2.471230 0.466107 0.853959
+1 -0.011849 1 1 -1.390212 -1.269695 -2.059741 -0.854971 -1.420026 1.878756 -1.470007 0.648927 2.043535 1.801216 0.651889 -0.006079 48.017373 27.979681 4.492143 49.452430 -3.016460 1.410457 1.050527 1.951715 1.220805 1.822205 0.292479 0.952251 1.740612 1.459008 0.303552 0.298804 1.504481 1.817440 1.218010 2.087199
+1 -0.003923 1 1 -1.402418 0.932406 2.247833 0.109636 0.116452 1.571992 -1.897250 1.656150 -1.171014 -2.300661 -2.065809 0.822620 -11.972679 -74.815262 29.890126 13.349507 -34.830005 2.306641 1.712382 1.745241 0.516523 2.209042 1.614439 0.368814 1.404403 0.552457 0.898038 1.820987 2.320998 2.270579 0.865714 0.807035
+1 -0.059997 1 1 0.391303 -1.873810 -0.227548 2.054949 0.425930 0.494617 0.365816 -1.400504 0.107816 -2.208667 -1.569664 -1.381407 20.106191 -25.250218 -30.420867 66.496040 -51.048013 1.915671 0.689310 1.476496 1.724133 1.254718 0.298789 1.240447 1.192851 2.239057 2.087024 0.607867 0.665474 1.368974 1.352761 1.105093
+1 -0.008155 1 1 -2.271105 -0.109415 -1.106379 0.181172 0.749217 0.582778 -2.302928 2.246914 -1.198916 -0.004535 -0.826309 -0.366899 64.862655 -53.359673 33.977077 2.729575 -24.029850 0.329565 0.995152 0.525952 0.929601 1.302800 0.657938 0.720202 0.930625 0.515657 1.141335 0.424025 2.335082 0.477546 1.861893 1.339056
+1 0.021696 1 1 0.066991 -0.344387 -1.306885 -0.374341 -0.515567 0.954692 -0.177289 -1.459187 -1.290034 0.099500 -0.604419 1.441021 72.622464 15.756206 64.551904 -26.153367 -59.644088 1.552206 0.675224 0.996056 2.213243 2.473435 1.526370 0.695802 0.345075 0.667292 0.422431 0.302347 0.289674 1.054730 0.592849 0.255404
+1 -0.005956 1 1 1.391882 1.055600 -0.666357 1.890315 -0.396733 0.139604 -0.445246 0.027456 -0.356529 1.976415 -0.016705 1.983515 47.386520 -74.758072 -58.920986 14.993190 -9.449146 1.948134 1.793541 2.290545 1.184810 2.106549 0.274652 0.571704 0.379455 0.255931 0.937971 2.486509 0.749982 1.955568 0.732641 0.749976
+1 0.041583 1 1 0.880551 -2.194322 -0.805108 -2.181507 -2.199308 0.213802 -2.184428 0.545326 -0.296401 -0.610015 1.631525 -0.348133 54.458704 -12.569713 -59.159034 64.109789 43.217344 2.183400 0.399328 1.261196 1.165694 0.322952 2.360218 2.180323 0.440197 1.899191 0.455541 1.034654 0.678330 1.437366 1.052606 0.899686
+1 -0.063472 1 1 -0.880047 1.240237 1.769109 -1.760002 -0.692451 1.580615 1.661533 -0.232809 -1.534004 -0.518115 0.537404 -1.505477 -55.345586 -43.260430 -28.046523 72.083030 -50.521648 1.865045 0.317379 0.940746 1.864626 2.260898 2.406360 1.443580 2.001102 1.014859 0.991370 2.210829 2.399054 2.402272 2.489755 1.304429
+1 0.015641 1 1 0.033671 0.415841 0.573102 -0.000679 -1.982428 -2.076118 1.919135 -1.403485 1.850175 -1.168166 -1.551451 -1.595758 -53.907098 -16.601273 -17.597175 44.286591 24.734320 2.270662 2.267065 0.305691 0.255015 1.290742 0.507276 2.041447 1.857241 1.893008 2.292616 2.247630 2.162536 0.743843 2.268781 2.153139
+1 0.003835 1 1 -0.405341 1.556318 -1.428108 -2.020561 -2.091758 -1.750836 -2.142592 1.537934 0.595810 -0.054586 1.483254 0.510759 -52.549698 -2.774014 27.151214 30.458502 -33.959485 1.268966 1.267321 0.621324 1.835229 0.938718 1.530322 1.867036 2.269684 1.579371 0.482521 2.230329 1.638602 1.476417 0.383500 0.726223
+1 -0.045422 1 1 0.376342 1.162119 -1.119001 0.103486 0.409534 -1.759884 1.301294 0.644213 -1.787405 0.556430 -2.174477 -1.862778 44.842282 64.238550 -42.685118 41.228820 -67.225470 0.497975 0.967378 1.715922 0.503069 1.081937 1.109872 0.362457 0.306354 2.398746 1.718261 1.568489 2.090127 1.010383 2.254906 0.698544
+1 -0.009480 1 1 0.560473 -0.193839 -1.590817 1.234843 0.652806 1.262200 -1.382966 -2.005335 -0.663254 2.200157 -0.076845 -0.337839 11.841489 -30.088966 -55.253009 12.681259 -16.076472 0.666038 1.846686 2.252473 0.322357 1.349384 0.590905 1.332893 2.427046 0.357892 2.336075 1.407016 1.716184 0.401158 0.511402 1.626620
+1 0.069541 1 1 1.599330 0.465880 -1.946904 1.220471 -0.574458 0.775393 2.275623 0.641802 0.104788 -1.260464 2.283228 1.231433 -3.710406 39.198013 1.004198 -72.438410 -72.349711 2.401016 1.624512 0.916224 1.469664 1.637805 1.591987 1.022813 1.916759 0.969151 2.269627 0.612742 1.598961 1.233689 2.354795 1.044499
+1 0.009933 1 1 1.071721 1.656601 1.691527 -0.346109 -1.964397 -0.629052 2.122022 1.458731 -1.668435 2.046730 -1.049457 0.251015 38.721132 -63.930863 -36.010871 15.284151 -69.273406 1.703084 0.731307 0.828685 1.701497 1.056710 2.381316 1.281971 1.594038 1.754771 0.929868 1.284445 0.417714 2.018272 1.590269 1.399885
+1 0.001005 1 1 -0.651283 0.762383 0.381300 -0.332333 -1.343407 -1.580976 1.698219 -0.981679 -1.008941 -2.099828 -0.723191 -1.412587 -10.668193 -50.313212 -64.149990 31.110284 -29.449522 2.003272 1.487165 1.023995 1.532426 1.238141 0.692250 1.398615 2.278109 1.422126 1.418849 0.346178 1.206078 1.807704 1.837547 1.646844
+1 -0.002603 1 1 1.653455 0.667929 0.979504 2.142525 2.059693 0.058343 0.401095 -2.231994 2.210561 0.423952 0.225835 2.139707 57.567076 29.838579 46.999779 25.289252 -63.537643 0.967392 1.965675 1.854080 0.520077 1.188219 0.897345 1.427169 0.674777 2.479390 0.355568 1.526149 1.482804 1.990317 2.006928 2.188869
+1 -0.027859 1 1 0.039502 -0.539873 -2.302389 1.891776 0.583530 0.909754 -1.464875 2.086948 1.030326 -1.342303 -1.879810 -2.109118 -43.096188 32.362829 22.072300 19.149804 -49.237584 1.583837 1.293438 0.817141 1.189057 1.475477 0.337014 2.445381 0.276570 1.307979 2.202710 0.941285 1.934505 2.226470 2.030284 0.983677
+1 -0.013777 1 1 0.200150 -0.732233 2.127225 -0.617265 2.301001 -1.644679 0.748288 -0.882002 1.373937 1.054302 1.076186 1.310005 30.945641 53.381490 32.707889 -28.510597 72.387993 1.000024 1.409710 2.003209 0.438617 2.334406 0.364879 0.513404 1.535659 1.567928 1.666845 1.423102 2.083757 1.947078 2.035869 0.349986
+1 0.034859 1 1 1.114318 1.316055 -1.011885 0.260766 0.166243 -0.395273 1.110020 -0.243360 0.201848 -0.462781 2.190581 -0.800642 69.695876 28.582075 -71.061834 -36.250567 36.728273 2.006226 1.648876 0.910048 1.173365 0.994015 1.667803 1.768894 2.047114 0.347659 1.348347 1.161312 0.923529 0.495035 1.055331 1.701080
+1 -0.017524 1 1 0.249392 2.214642 -1.669759 -1.369560 1.834190 -1.218928 -1.769287 -1.230301 0.297257 0.872072 1.388814 1.327924 17.204728 -40.130291 -69.792644 -4.966958 70.345153 1.239910 1.166942 1.035663 1.892701 1.628874 2.226351 2.277117 0.505264 1.971935 1.314249 1.840099 1.802982 1.226184 2.228896 2.313336
+1 0.003824 1 1 0.408211 -0.439074 0.086661 0.378596 1.332164 1.118038 -2.147111 0.979066 -0.495522 -1.447514 1.698612 0.926090 -7.439174 69.801308 0.579688 -7.181635 48.267569 1.870526 2.427721 0.455978 1.629664 2.017698 0.943120 1.272828 0.921353 2.176284 2.299659 1.366196 1.900386 0.280760 1.977922 0.683455
+1 -0.027831 1 1 -0.522550 1.397898 -1.504587 -0.912951 -0.435308 2.112521 2.005481 -1.606550 0.703480 0.005611 0.053150 -2.062032 -52.718335 12.936099 67.018762 34.325795 13.634939 0.811267 1.458064 2.436436 0.672310 1.508007 0.323842 1.566210 2.039251 0.942976 1.105719 0.310672 0.706268 0.740278 0.850251 1.912101
+1 0.004738 1 1 2.118287 -0.041946 1.879370 -0.576174 0.203334 0.951459 2.042537 -0.840913 -0.764447 -2.087920 1.483206 -0.297044 -63.375753 -6.279819 55.075286 0.338346 -13.418207 0.327951 0.876061 1.455675 0.533604 1.285211 2.032528 0.440590 1.745576 1.646438 0.430018 1.814170 0.258513 1.582170 0.281061 0.286801
+1 0.006322 1 1 0.966502 0.388646 0.594986 0.236238 -2.088519 0.847539 -0.961138 0.219107 2.157559 0.257357 -0.577312 -0.065761 68.917232 -8.089145 -54.252731 24.351669 -71.506784 1.157180 1.229319 0.909182 2.370627 1.619622 1.979250 0.510414 0.773892 1.048120 2.010249 1.752964 2.061344 1.007024 2.059094 1.437746
+1 -0.045301 1 1 -0.022616 1.604067 -0.023082 -1.526119 0.049972 1.068789 -0.496444 1.907751 0.468955 -2.095233 1.097667 -0.509588 -70.892702 -43.636162 -42.970916 37.815427 13.876801 1.035829 2.421700 0.513994 2.447564 0.953936 0.795075 1.578255 1.987142 0.392062 0.639712 0.381714 2.221825 0.457854 1.655596 1.359571
+1 -0.023129 1 1 0.409956 0.623169 -2.035147 -2.198647 1.895706 0.666093 -1.609277 1.999611 -1.300160 -0.446814 1.942903 2.226806 4.322942 55.682853 11.705199 -70.715417 -64.009424 1.279270 1.196831 1.645446 1.756236 0.804967 1.332579 1.654812 1.676909 1.810778 1.745646 0.566701 1.795288 2.405689 1.410102 1.834838
+1 -0.017141 1 1 0.068929 -0.764652 -0.821166 1.250437 -1.158616 -1.271073 -1.667186 -0.536144 -0.886206 1.392545 -1.938520 0.752819 -4.385386 -55.189579 28.750148 53.735449 -18.301353 2.262485 2.091135 2.205842 1.835349 0.702028 1.481708 1.569354 0.890171 2.352893 0.576326 1.566716 1.550422 2.188929 1.076902 1.985151
+1 -0.018755 1 1 -1.315960 -2.092091 2.069410 -1.562495 1.294884 1.302680 0.380373 -1.791065 0.317486 1.558383 0.291162 2.094479 11.528263 -44.481770 -5.102601 40.576616 71.187964 2.216649 1.222550 1.891512 1.883830 1.039069 0.631813 0.388722 0.750777 1.816243 1.343256 1.108386 2.389661 2.027560 2.450702 1.954201
+1 -0.031361 1 1 -2.203793 0.222126 1.057960 1.293002 -2.058460 1.819128 0.095585 -0.428299 2.103588 -2.051336 -0.962112 -2.011210 -13.764784 -44.721014 23.924098 -57.682169 -14.209484 1.093095 1.890300 1.763145 2.182570 2.197860 0.441798 1.800526 0.434170 1.845969 1.443974 1.863546 2.121297 0.638856 1.746740 0.958573
+1 0.053867 1 1 -1.315461 1.580908 1.869904 0.550897 -0.926561 1.727582 -2.275340 -0.602972 2.190595 -0.571538 -1.991554 0.050935 -50.868908 46.261254 62.898093 -71.744844 34.401582 0.435912 1.875971 1.702552 0.800436 1.671536 1.511503 0.580932 2.467949 1.566253 0.521077 2.245586 1.559285 0.402545 1.321912 2.371133
+1 0.022953 1 1 -1.778053 2.237883 -2.192989 -1.969469 -1.045584 -0.624699 -0.107270 1.959855 -0.307328 -0.483935 0.088505 -1.616336 37.254631 38.581084 -17.718461 -44.178938 -15.410795 1.986482 0.560951 1.896035 1.418685 2.082851 2.475379 0.436149 1.357617 1.723426 0.619089 0.279527 1.511618 0.269578 0.798836 1.793798
+1 0.035477 1 1 -0.300296 -0.104660 -1.297527 1.391938 1.996063 0.340198 1.587384 2.328743 -1.912387 1.718925 -1.679779 -0.119589 71.663580 -50.204761 -41.416374 65.009680 17.690808 1.816027 2.211209 2.031855 0.394046 2.476975 0.263507 2.258188 1.864334 1.859023 0.356588 0.673340 0.831274 2.476586 0.472116 0.600444
+1 0.034663 1 1 1.212190 1.622134 2.035027 0.175656 2.294761 1.863833 2.188730 1.070480 -0.345823 -1.868329 -2.355000 -1.126241 29.467836 -34.076024 -15.731300 54.040673 11.598426 0.396117 1.294408 1.361020 0.406717 1.685664 0.448993 1.228678 1.395250 1.958891 0.323485 2.304173 0.735769 1.563389 1.873328 2.272538
+1 0.031591 1 1 -0.004244 -0.651094 -0.772938 1.282412 -0.969094 -1.546207 1.721936 1.793159 1.899566 -0.433229 -0.640946 0.147791 15.480450 -70.074879 51.503114 -37.166599 -59.026324 2.043530 0.861491 1.830409 0.929087 1.662271 1.039655 1.476451 0.957440 1.201263 1.873512 0.862236 0.849164 1.645027 1.467047 0.403324
+1 -0.016144 1 1 -1.795514 0.937295 -0.399221 0.738384 2.307793 -0.597854 -1.315569 -0.241709 -0.325844 -0.671580 -1.072031 -2.155925 -34.030694 -3.876515 -52.587645 -40.554628 -1.626807 0.748693 0.527161 0.996930 1.150429 0.252607 1.319851 1.490236 0.893477 1.661952 2.428230 2.257950 2.364991 1.398327 1.925400 2.192739
+1 -0.004887 1 1 -1.539493 1.461518 -1.952554 0.510491 -1.444653 -2.059251 -2.039819 -0.606540 -1.226309 1.416210 -0.028797 1.390442 13.557685 14.006679 60.255313 61.039037 33.102598 1.455539 0.491450 1.556855 2.307086 2.439215 2.391344 1.060523 1.202761 2.301069 0.314182 1.199252 1.822489 0.577269 1.663828 2.466330
+1 0.006022 1 1 -0.580624 0.805809 -0.170923 1.855936 1.419642 1.100127 -1.585791 0.878868 -2.210622 -1.455732 0.239932 -1.265529 63.019321 15.726344 12.670714 -43.316735 -74.360223 1.791046 0.855297 1.224150 1.796967 1.367105 1.426586 2.126752 2.316853 2.351480 1.574403 2.492299 1.315713 1.687535 0.397920 2.337370
+1 -0.039030 1 1 2.270590 0.884959 1.205340 -0.411846 0.609655 1.740508 -1.799014 -1.348287 1.219318 -1.100539 -0.627794 -0.293819 11.825650 3.703736 -1.309579 39.911319 -10.461236 1.045111 0.937571 0.262984 2.477718 1.501745 0.825408 0.625057 1.581166 1.408980 0.971775 1.375911 0.938717 1.513822 1.302494 2.264763
+1 0.015740 1 1 0.340511 2.127572 0.499334 -0.451607 1.491734 1.665792 0.668873 -2.016910 -1.987318 0.556109 1.864399 2.279924 71.358270 68.436234 7.787560 -64.487494 58.695198 0.477887 0.853468 1.992540 1.119825 1.149673 1.055153 0.951595 1.949139 0.671345 1.042578 1.108086 1.854871 0.321532 0.985276 1.029183
+1 -0.022111 1 1 0.271522 1.882038 1.858720 1.089680 1.913151 1.706855 -1.912598 -1.836836 -0.837347 -2.100317 0.477074 -2.307147 64.622787 -34.821091 61.928401 -19.360146 -35.975281 1.576692 0.458702 2.407339 2.139286 1.486083 0.840494 2.186584 2.162148 0.966469 2.195216 0.996604 2.427942 1.914239 1.371176 2.347940
+1 -0.002143 1 1 1.369264 -2.090912 -1.666692 -1.658885 2.328879 0.357927 -2.036083 0.923456 -2.076075 -2.057628 1.672397 -1.430796 -1.854173 36.913381 3.195031 -1.119846 -71.254875 1.664792 0.654429 2.493999 0.648316 0.995350 1.600154 1.033004 2.190869 2.184909 1.024497 0.976523 2.422365 0.436921 0.826801 1.550803
+1 0.035234 1 1 1.172773 -1.125027 -2.228510 -0.506499 -2.148340 -0.828110 -2.353968 2.078653 -1.733606 -0.017820 2.086917 0.495332 -55.800051 -31.456771 56.042641 58.671927 -0.930702 0.740378 0.286186 0.920694 2.359752 1.110882 1.595881 1.226608 0.343647 1.429439 0.575621 0.967398 2.050728 0.340992 1.810916 1.818528
+1 0.006041 1 1 -1.249164 -1.005402 0.843673 0.026730 1.573061 1.939304 -1.720924 1.070882 1.698000 0.051545 -0.757628 -0.571749 -25.998933 -14.074507 -0.244650 -61.836860 57.886207 1.277234 0.721952 1.102718 1.625664 2.281751 1.882072 0.730117 1.070505 2.478038 2.377874 1.920528 1.311006 1.323038 1.043539 1.510844
+1 0.037476 1 1 2.060719 -1.555737 1.774555 0.237349 -2.271621 0.647910 -0.911602 -1.317272 -0.592889 2.024775 2.238414 2.014378 58.611222 28.816366 -33.331363 49.785970 52.797790 0.961784 2.197768 1.132950 1.235421 2.221701 0.621342 2.148393 1.541773 0.821684 1.043414 1.667922 1.512252 1.925794 2.073110 0.754985
+1 0.020646 1 1 1.637311 -2.070233 1.873751 -0.757762 1.886738 0.743742 -1.893840 -2.295608 -1.962360 0.627473 -0.382091 1.179580 5.660360 33.668476 66.080793 19.892856 -10.771768 1.508376 2.026007 1.100064 2.027832 0.277684 2.041542 1.201801 1.915040 1.332171 1.542808 2.475021 1.176384 2.232978 1.158283 1.759899
+1 0.054593 1 1 -0.364774 0.057867 1.822275 1.168087 0.221084 -2.320680 0.773767 -1.493279 0.648079 1.927305 -0.745931 -1.913884 3.536322 34.965885 -28.375230 -52.488811 -29.446493 0.516918 2.089536 2.329900 1.131074 1.202181 1.556417 1.706476 1.484560 2.249981 1.176131 2.486136 1.229458 1.004903 2.409373 0.335691
+1 0.029564 1 1 -1.618021 1.122370 -0.015821 -2.002081 2.188972 0.434463 -2.190026 0.700166 0.857819 2.159315 1.495706 -2.261158 68.182603 -54.987680 -27.941192 42.384277 2.542972 1.221014 0.825739 1.702760 2.030673 0.776706 1.091782 2.330246 2.435849 2.056189 2.118060 2.486747 0.264329 0.324205 0.909232 0.962881
+1 0.072171 1 1 1.314977 -0.280549 1.917563 0.461251 0.359844 1.904751 1.892516 -1.114301 -1.016029 1.294188 -0.970941 0.393698 21.803392 -0.385914 -36.060674 -71.754259 26.170005 1.964169 1.283429 1.346982 0.728223 0.740196 1.717161 1.073990 0.294312 0.256800 2.034170 1.040240 2.314890 0.848231 1.712333 0.929876
+1 -0.022624 1 1 2.013672 -0.600177 2.049537 -0.999988 2.292863 -1.769894 -2.007553 -0.242283 -0.540848 0.172344 -1.527691 1.911425 30.552429 44.680631 47.371203 -32.190054 31.767400 2.345361 2.239398 1.056182 0.254241 1.782695 2.246128 1.675336 2.375298 1.389434 0.967683 2.355434 0.533356 1.613278 1.117642 0.461935
+1 0.012402 1 1 -0.425326 0.237162 -0.703217 -0.303172 -1.321114 0.813688 0.308650 -0.867486 0.295032 1.163702 1.932236 2.011289 56.428671 -53.334482 7.368784 -52.853677 -11.749211 0.340092 2.424446 1.665321 0.544887 1.922894 0.581327 2.366510 2.186699 1.848223 1.087193 1.706413 0.428264 1.587982 1.209314 2.197768
+1 0.021186 1 1 0.125115 1.075382 1.935376 -1.754768 -2.246767 -1.037806 -1.854187 -0.291198 2.010371 0.476709 0.989944 -1.458983 68.218100 -58.389421 -51.004380 19.391213 -41.888102 0.425001 0.744055 1.339918 1.253948 0.859875 1.668351 1.966353 1.993055 0.782841 0.708907 2.341896 2.491271 2.036997 1.313651 0.775310
+1 -0.027207 1 1 -0.396665 1.280588 1.366912 0.790169 0.864599 -1.699136 -0.297811 -0.753008 1.666564 -0.497062 0.948675 -2.338637 18.196254 -25.554143 -38.489771 52.426819 37.552868 0.640664 0.631922 2.214176 2.400635 1.974013 2.484627 0.619909 0.556117 1.652024 2.072724 1.015083 0.257319 1.767376 1.296126 0.997965
+1 -0.035131 1 1 -0.105479 -0.923647 -1.128507 0.557148 0.464929 0.912608 -0.626265 1.838825 1.281755 2.131022 1.933631 1.910758 -26.288920 62.114691 -38.392949 29.707430 -57.230599 0.254949 2.426671 0.800441 1.757241 1.948937 1.775914 0.780881 1.517078 2.038387 2.169417 1.637083 0.707661 1.660142 1.256508 1.135299
+1 -0.033525 1 1 -1.165211 0.983458 -2.084082 0.024332 -1.034110 -0.997893 -0.202143 0.221586 1.414685 -2.109918 -0.658831 1.147440 61.282842 -69.280076 59.764217 57.194663 70.701721 1.132251 0.741477 0.746787 2.243464 1.897784 1.553234 2.206088 1.477063 2.249513 2.318214 0.469168 0.562209 0.554298 0.337227 1.524883
+1 -0.031413 1 1 -0.031896 1.135516 -0.554795 1.371395 0.746071 -0.453506 -2.150697 1.979652 -2.165313 1.362737 1.311242 -1.794466 -9.341831 41.845839 -46.977842 43.410221 -4.416711 1.650129 1.712073 1.065087 1.410503 1.819262 0.336533 1.109071 0.408100 2.438415 2.444630 1.139234 1.097242 1.843895 0.340142 1.016665
+1 0.041866 1 1 2.269836 2.339302 1.187370 -0.844577 -1.083349 0.825339 -1.793122 -1.277090 0.879908 1.143418 0.308965 -0.272235 9.046906 -48.648244 18.970294 -66.263019 67.435976 1.321653 0.266029 1.895415 2.230912 2.442667 1.903241 1.025995 1.391208 1.527534 2.255155 0.389459 1.892111 0.715454 2.137781 0.939258
+1 -0.028963 1 1 2.274681 -1.056287 -1.439899 -2.261132 -2.136724 1.200380 1.041927 0.427946 1.386058 2.137891 -0.440695 1.116892 68.782530 -22.025719 13.732870 -41.661551 -5.695826 0.928659 1.222346 0.720212 1.106859 1.483570 1.361981 0.807695 2.187734 1.250503 1.462561 1.514750 1.156527 1.498510 0.453799 0.995406
+1 -0.051796 1 1 -0.926653 0.190718 0.970696 0.201050 0.260177 -0.305525 1.550968 -1.816125 -1.464340 1.639349 -0.793312 -1.853713 -55.544484 63.853468 -64.764570 51.867745 -58.817762 0.623073 1.981488 2.125371 1.606470 1.435660 1.633260 1.692796 1.066148 1.256433 2.111458 1.765967 2.358037 1.528632 0.462815 1.786905
+1 0.034569 1 1 -1.944932 1.373262 -0.870278 0.493993 -0.696526 -0.936788 -0.499948 -0.435218 -1.082993 2.088836 -0.233847 -0.138738 27.734726 -62.452010 69.066539 -48.677324 -19.782553 2.344545 2.018013 1.750449 0.302137 1.269815 2.039508 0.760626 0.839797 1.715919 0.446385 2.386622 0.449424 1.724214 0.356446 0.532099
+1 -0.005723 1 1 -1.028661 1.047661 -2.158826 2.003953 0.989091 -1.654470 1.128896 1.274351 0.215369 0.591271 -0.934207 0.466644 46.996625 -27.724225 -61.053189 29.055214 -69.020259 0.272539 1.062471 2.446466 0.508355 2.176206 0.985739 2.059055 0.795376 2.126674 1.016228 1.494157 1.553934 0.470125 0.892364 0.955155
+1 0.072108 1 1 0.280013 -1.499764 0.030983 -2.341761 -0.104232 1.174371 2.176630 0.346480 -1.216076 -0.959445 0.409006 -1.205035 26.252860 -68.173856 52.000940 -70.208101 62.449697 2.005939 1.322828 2.014136 1.835289 1.955991 1.094909 0.885716 1.728494 0.298081 0.602300 1.601306 2.394216 2.093071 0.999787 1.922130
+1 -0.021832 1 1 -0.312272 1.239732 -2.008632 0.478469 2.287708 1.133083 0.958816 -1.554773 -0.868761 -2.277165 1.716400 -1.710076 -12.182557 -2.237760 39.973009 -23.636750 -62.856716 1.632606 1.953552 0.595914 2.277576 1.472395 0.288516 1.836259 2.498144 0.558487 0.984929 1.958119 0.856202 0.690479 0.878879 1.575321
+1 -0.002265 1 1 -1.069612 0.789813 -0.408487 0.512326 1.120855 -1.917958 2.323970 -2.025137 1.114294 0.900518 -1.182751 -1.648530 63.636232 34.148471 33.360177 -15.500023 41.110274 1.980678 2.004994 1.177431 1.825844 0.708983 1.380141 2.288697 1.628748 2.365978 2.244082 1.035739 0.922512 1.411449 1.964465 1.769265
+1 -0.015536 1 1 -0.365494 2.094560 1.717950 0.773231 -1.068620 -1.375968 -2.210106 -2.202029 1.599295 -0.115842 -0.747753 0.453544 -61.565179 -25.963828 -24.051573 15.219454 43.358633 1.803202 0.415304 2.011862 1.871862 2.376061 0.701789 1.975092 0.377168 2.312737 0.671657 1.782340 0.788786 1.623686 0.543505 1.183490
+1 0.071568 1 1 2.173026 1.037562 -2.250251 1.662952 0.059773 0.868529 -1.617089 -2.070065 -0.014520 1.007449 0.576420 -0.786833 -42.517163 14.038597 -3.297555 -72.002482 54.284740 2.329289 2.108089 1.405895 0.882142 2.404174 0.698718 2.099236 1.110114 2.182114 1.285424 1.127050 1.076311 1.052572 0.334303 1.881502
+1 0.036762 1 1 1.247056 -1.436660 0.330605 0.567765 -0.160660 -0.021236 1.220069 2.093298 -0.644173 -2.259062 -0.338234 -1.549735 -32.688645 51.943525 14.821701 -41.676327 45.970346 0.979166 1.835615 0.688022 2.343609 2.045082 2.194626 2.322514 0.737598 0.808523 0.347767 0.925966 0.964253 0.945072 0.317829 1.760187
+1 -0.000176 1 1 -1.495319 -0.657351 -2.255967 -0.149435 0.150785 -1.017444 1.083777 1.650838 -0.916971 -2.020805 -1.477611 0.084374 -11.051957 -50.242474 74.736937 3.700868 -49.506317 1.334912 0.370950 1.312488 1.479974 1.681846 1.540101 1.972105 1.919039 1.037160 2.306136 2.220880 0.336635 0.570416 1.237007 1.870588
+1 0.044239 1 1 1.519691 0.306736 -0.042269 1.151937 2.113951 -2.238663 -1.491953 -0.639833 -0.007319 -0.480562 0.225184 0.625684 -69.166077 25.735719 -59.774455 70.726956 -42.049624 2.454462 2.151764 1.954479 0.422089 1.302566 1.218819 2.192785 0.632391 1.097820 0.315196 0.254857 0.882878 1.281156 1.390510 1.052501
+1 0.006348 1 1 0.133786 0.729800 -0.606718 0.507063 2.201768 -1.274257 1.363318 1.647215 -0.546348 1.978600 -0.997676 -1.259155 22.772748 -58.424382 -38.581965 2.909014 -8.200676 1.693598 1.052836 0.256975 0.471160 0.278690 0.940742 1.795262 1.974366 1.665291 2.292123 0.718268 2.184331 0.296698 2.102559 0.714833
+1 0.005026 1 1 -1.778181 0.087100 -1.670814 -0.252154 -1.515613 2.264070 -0.309286 -0.400504 -1.974070 1.737960 -2.199891 -0.158572 66.569148 -22.332301 -38.983906 -2.504572 55.662996 1.044562 0.706919 0.432399 1.331463 0.891313 1.295778 1.896666 0.761225 1.915680 0.831663 2.267325 2.429339 0.641968 2.302070 1.389087
+1 0.032896 1 1 -1.502598 -0.478317 0.266847 -1.298508 -0.946366 -1.266121 1.446968 -1.454854 0.853464 -0.341633 -2.135809 -2.269695 0.736591 -70.111557 35.061487 -71.588359 -35.547419 1.442842 0.837122 1.761058 0.852846 0.525800 0.625403 0.643337 0.566197 2.330448 1.330558 1.433525 1.754477 0.492757 1.018666 1.973412
+1 -0.012314 1 1 0.880557 -2.100054 0.187257 -0.639597 -0.739706 -0.949881 0.924242 1.704758 0.543424 0.717056 1.985152 0.741890 -1.304246 -20.456013 -4.211858 11.300665 30.271468 0.963508 1.921597 1.284603 0.825402 0.534791 0.990087 0.884996 0.880479 1.454978 2.322941 1.174741 1.616282 2.099667 1.599715 0.404782
+1 0.009550 1 1 1.397539 1.889132 -1.438003 1.321810 1.458568 0.305253 -1.407790 0.175691 -1.829488 0.134893 0.483189 1.511813 -5.137630 51.850902 -41.887755 -57.503395 -9.564582 2.095986 0.481197 2.484602 2.458819 1.119372 0.287969 1.651232 2.249979 1.152359 1.190104 1.078292 0.605128 1.878890 1.247163 1.563431
+1 0.020995 1 1 1.870470 0.644635 0.603392 0.155504 -1.826495 -1.400454 0.958216 -2.216588 1.952938 1.232752 -1.503245 -1.919905 -67.206765 -44.107727 -18.569146 58.363951 72.922721 0.807587 0.371772 1.623098 1.915146 0.851327 2.008471 1.124807 1.632693 1.166570 1.546572 0.480678 0.505481 1.115658 0.862275 1.509954
+1 0.020084 1 1 0.995850 -1.158276 -0.271349 1.031258 0.181560 -2.147089 1.344150 -0.059321 2.025915 -2.176593 0.279942 2.014032 23.999694 12.854530 46.086572 -22.985893 -73.905183 1.758722 2.089391 2.145639 0.255330 2.073101 0.615272 1.381130 0.897219 1.560105 0.676933 0.467315 0.910282 0.607360 1.147066 2.233452
+1 -0.022400 1 1 -1.270865 1.834839 0.268134 1.485864 1.973473 -2.348364 2.022986 0.434938 1.089786 -1.027848 0.575714 1.497404 -63.592854 -55.091652 24.602732 -51.876753 57.413910 1.458680 1.527216 1.414685 2.363386 1.432912 0.448246 2.173947 1.282982 0.575350 0.909821 1.861332 0.910087 1.827692 0.276562 1.178568
+1 0.021165 1 1 -0.613522 -0.755110 -0.678353 -1.817834 -1.923175 -0.528286 -0.766997 2.176422 1.556881 -1.400497 0.229191 1.989416 54.603360 18.666071 70.652939 63.952112 -56.846072 0.445953 1.879341 2.082893 0.926318 2.374877 1.064780 0.752554 2.418831 1.787954 0.636252 0.742202 1.684064 0.557925 0.544743 1.749216
+1 -0.079707 1 1 0.528386 -2.270926 -1.805758 -1.590629 -0.327585 -1.651800 -1.117729 -2.093983 -1.454079 -0.262017 -2.353772 0.661129 -6.744828 39.673901 49.251484 69.685284 0.568176 0.614976 0.901810 2.215264 0.447399 1.434726 1.680843 0.430399 1.466976 1.460873 2.396594 1.549876 2.009907 0.501105 1.817206 1.781866
+1 0.047982 1 1 -1.953628 1.298623 -1.822695 1.214911 0.228933 -2.349216 1.838600 2.214553 1.546372 1.042877 2.268100 1.439556 38.658577 -65.290090 69.450022 -53.475580 35.929592 0.904763 2.354683 1.398062 1.983904 2.221816 0.318476 1.382012 2.223289 0.325980 1.503561 2.102327 1.312887 1.447001 0.994862 2.402605
+1 0.015371 1 1 1.992642 -0.615864 2.290422 -0.376035 -0.707642 0.732432 1.231149 -0.179183 -0.318786 0.141488 -1.763154 -1.834657 -61.320902 29.608220 -74.648744 -21.433097 73.930793 0.697669 2.469320 2.109524 0.776276 0.624087 1.031846 0.739673 1.926988 1.887428 0.748998 1.163768 1.693813 2.413294 0.986516 1.629493
+1 -0.015696 1 1 0.568506 -1.843923 -2.147644 1.453773 -0.178556 0.807064 2.072001 -0.437388 0.140728 -0.409496 -2.315203 -1.428627 -41.510797 -21.963172 14.967658 11.426723 48.939281 2.462558 0.955681 0.875071 0.567341 1.291928 2.434682 0.446280 0.622448 0.490448 0.456116 1.695608 1.088045 0.269840 0.705941 2.004795
+1 -0.004365 1 1 -2.169733 -2.244084 1.635413 -0.981097 -0.641472 0.718793 -1.811300 -0.486475 -0.197524 -2.270709 1.830219 -1.986849 -31.142470 -61.495034 -47.033216 12.741825 -48.147972 1.780540 2.039372 0.719863 1.992283 1.299323 0.720071 0.981766 0.533504 1.859137 2.261548 2.082703 2.244611 0.929984 0.982812 2.368534
+1 -0.023663 1 1 -2.192319 -0.138972 1.643531 -1.206103 1.724013 -0.996008 -1.506516 -0.347597 1.292186 -1.626529 -0.510566 0.177721 -22.366762 -18.174754 -63.092996 -53.986314 2.025312 1.216273 2.149417 0.743835 2.131587 0.328597 0.479185 2.404929 2.146894 1.101854 0.605802 1.964720 1.552576 2.396178 1.319255 0.471301
+1 0.057046 1 1 1.870687 -0.423147 -0.830295 -1.382881 -0.579188 1.385361 -0.145652 -2.235348 -2.334462 0.055226 -0.152345 -1.642818 -30.411146 -70.137502 49.011019 -71.800539 -1.656443 2.277476 2.042306 0.538651 0.602842 1.709662 1.032440 1.711661 0.878595 1.297716 0.711214 0.621235 0.338471 2.178656 1.662676 1.093231
+1 -0.020422 1 1 -0.385259 -0.222416 -1.218939 -1.953913 1.228777 -2.342825 0.860007 1.234292 0.811037 -1.840898 1.581912 -0.108818 -15.862519 -51.364834 -38.759788 14.251037 -32.820243 0.477575 2.350746 0.485263 1.068597 1.903082 0.594393 1.460976 1.875654 0.864566 1.754726 2.428125 0.501049 0.887504 0.276475 1.965197
+1 0.070315 1 1 0.555019 -2.318060 -2.320676 0.837202 -0.338764 -1.042942 1.353463 0.948872 0.959733 -0.281257 -0.563513 0.945540 48.278342 64.089500 2.218522 -63.304976 -16.735477 1.027601 1.391929 2.404534 2.248456 0.303128 2.179440 1.346852 0.796532 1.319066 1.794138 1.075239 1.050060 0.865580 0.806387 0.443469
+1 0.016433 1 1 0.353986 -2.297740 -0.080020 -1.862279 0.363250 -2.117523 -1.256207 -1.566721 0.954899 -1.416419 1.232522 -0.671685 59.593262 33.948240 -31.924994 -13.367736 28.462867 1.756073 0.315519 1.173671 1.635095 1.038532 0.610201 1.649574 1.383777 0.386172 0.643347 0.725122 0.369658 2.091131 2.147766 2.259192
+1 0.009590 1 1 -1.535709 -0.900459 2.183847 -0.888048 -1.288253 1.750768 0.996628 -2.207815 -1.390183 -0.779031 -2.159957 1.846201 -62.997554 50.101634 -41.839538 2.892097 7.476720 0.793630 2.033401 1.623285 0.554942 2.161366 1.323939 0.437370 1.625340 1.346120 1.988033 1.865805 1.826343 2.347364 2.146851 0.379079
+1 -0.001094 1 1 1.264357 1.881245 -2.046880 -1.475262 1.865672 0.112734 0.342943 0.594082 -0.810312 -0.115100 2.314381 1.749841 -14.111650 -24.498950 -3.855634 -1.647769 55.942164 1.674162 0.643251 1.365101 1.494726 2.103263 1.289252 2.465029 1.996321 1.667568 2.317677 0.445161 2.072498 1.722069 0.310216 2.048199
+1 -0.031870 1 1 -0.544514 -0.186537 -1.380426 -1.723842 -0.853095 1.825640 1.171294 2.296967 1.236550 1.054328 1.499062 2.310345 -3.460716 35.743385 -10.920486 59.393968 -15.576580 0.691423 0.988036 2.427885 0.966963 1.497681 2.274360 1.421998 1.515651 0.538366 0.314231 2.024760 0.382423 0.626542 1.797781 1.555806
+1 -0.017700 1 1 -2.056107 -1.042444 0.313925 -1.730064 -1.744923 -1.723276 -0.756259 -1.125067 1.818031 0.515019 -0.727493 1.671899 -11.884763 52.793080 43.292431 -34.106989 63.831971 1.734031 1.108359 1.930991 1.656832 1.884091 0.919232 0.273975 0.441480 0.958823 1.940895 1.628931 0.939370 1.238872 1.728949 1.203368
+1 0.051897 1 1 -0.850709 -0.485078 -0.267224 -0.319119 -0.734685 -1.391052 -1.243122 1.586679 -0.104129 -1.805611 0.878473 0.576443 -12.811877 70.776373 38.497986 -64.343839 73.104679 1.680053 0.646166 0.868822 1.288547 1.860146 1.223260 0.334248 0.951448 1.731032 2.460436 1.298283 1.234446 1.577607 2.345190 1.600957
+1 0.037871 1 1 0.604654 -2.205716 0.891373 0.626941 0.099549 0.219980 -2.026456 -2.215215 1.467628 1.773762 1.038310 0.898554 -38.733847 0.232241 3.282512 -30.826420 0.353742 0.555228 2.474172 0.407913 1.541240 0.877341 0.476848 1.392267 1.334934 0.736819 1.223892 1.956478 0.272876 2.226107 0.430887 0.672519
+1 -0.001488 1 1 -1.974001 -1.813492 0.375407 -0.420901 -0.788632 1.405316 0.647362 -0.689271 -1.533203 -1.199766 -0.159970 2.165161 25.381498 -13.171068 33.852834 14.579906 -55.515435 0.656382 1.559551 0.372497 0.314232 2.044852 0.572809 0.954306 0.267332 1.302496 2.303486 0.446321 1.322226 0.895815 0.455888 2.365191
+1 0.013203 1 1 0.905489 2.244079 -1.731414 -0.870224 1.392374 -0.088715 -1.926185 0.718504 -1.956678 1.870825 1.899428 1.960421 -7.243686 55.372560 46.613826 -11.422380 24.052569 1.397852 0.706473 1.943785 0.688105 1.472403 0.418948 0.262151 1.977542 1.056923 1.450516 1.577179 1.890015 1.480134 2.112955 2.183452
+1 -0.016808 1 1 -0.490025 1.403556 -0.649997 -1.175297 1.119772 -1.266580 -1.551222 2.264381 0.203648 1.509719 2.350272 1.781979 -70.780126 48.424217 -34.190369 12.460292 20.127395 1.841859 2.115087 2.014337 0.709624 0.907580 2.451771 1.910770 1.556521 1.191787 2.365058 0.284551 0.449945 1.467810 1.978746 1.031239
+1 -0.028401 1 1 0.698634 -1.323766 -1.345780 0.950068 2.226050 1.569351 0.848669 -0.825589 2.312006 -0.479043 2.194667 1.897957 25.270921 -71.632844 -33.203214 -46.416776 23.250319 1.646605 0.992968 2.060216 2.295614 0.883261 0.965148 2.488071 2.265233 1.016234 1.599197 0.705473 0.888056 0.550447 0.857440 1.244354
+1 0.010097 1 1 0.872227 -0.714990 -0.237742 0.372925 0.265287 0.760664 -0.234979 -0.307848 0.195018 -2.156793 -1.518739 1.564656 64.924353 -66.403704 -47.052226 -6.765396 -6.003133 2.205105 0.698699 1.778183 0.666969 1.740587 1.039713 2.449437 0.932569 1.688326 2.445888 2.034342 1.683647 0.302282 1.446945 2.301442
+1 -0.001554 1 1 1.279570 -1.604600 0.486024 2.028968 2.025075 -2.153376 -0.644368 -0.816939 1.606982 1.845426 -0.866006 1.614378 -34.679934 34.349020 -46.026068 -10.129253 7.641298 1.784418 1.963072 0.856621 0.971497 1.205071 0.634451 1.962693 1.234561 1.265338 1.036156 1.172679 0.715680 1.427415 0.312037 1.148989
+1 -0.023696 1 1 -1.141755 -0.634071 -2.118069 -1.001974 1.893892 -1.543515 -0.149980 0.422536 -0.005156 -1.826839 2.251948 -1.423301 -42.265892 37.151754 -40.469719 -74.563115 67.728205 0.744233 2.068642 2.167653 1.251108 0.367211 1.459679 0.328331 0.510817 0.799011 2.483254 2.292159 1.311192 2.204276 0.267006 0.321891
+1 -0.018283 1 1 0.168114 -1.946712 -0.268011 0.576368 -1.657923 -0.350912 2.127576 0.568080 0.426957 -1.107994 1.306925 1.037054 -43.211732 40.416391 -71.723650 -59.379264 -37.294072 2.103087 0.583808 1.310475 1.403119 1.473525 1.290498 0.903985 0.528733 0.415064 2.486017 1.491330 1.276350 1.617179 1.422004 1.616517
+1 -0.067902 1 1 0.580989 0.614763 -1.948106 -0.137643 0.413890 0.769167 1.312726 -0.425183 -2.065245 0.883756 -0.162843 1.001484 -22.830188 -6.970789 -8.045955 71.629713 -19.412293 1.188966 2.207640 0.562804 1.543702 1.743297 1.595914 1.781812 0.917223 0.259897 2.330643 2.358411 1.070146 0.947828 1.643647 0.775382
+1 0.002825 1 1 0.578643 -1.110586 0.149953 -0.865476 1.094492 -2.036941 0.631637 -1.095572 -1.970039 -1.194681 0.492673 0.693915 -16.980243 63.058557 -74.837087 -36.914583 -23.397629 2.215756 1.966846 1.287438 1.214946 2.351566 0.772383 0.443097 1.123188 1.424392 1.262815 1.383310 1.539560 1.882714 0.279761 0.939168
+1 0.016541 1 1 -0.013207 -0.481427 -0.177315 -1.904082 -0.066407 0.726240 0.825596 -2.193102 0.845804 -1.857454 1.344286 2.229434 60.295352 -16.020385 -4.606147 -15.508456 49.377466 0.431102 2.036147 0.527007 0.652829 0.345553 1.957131 2.252399 1.326409 1.447933 0.918118 1.805203 0.298809 1.579127 0.891979 1.242671
+1 -0.013405 1 1 -0.747708 1.216130 1.868042 2.253252 1.641956 0.610872 -1.375295 -0.321190 2.164019 0.446892 -0.632230 0.553103 -49.031917 20.575392 60.607274 -23.550024 44.745078 0.332923 1.183428 1.365860 0.761631 1.987852 1.071979 2.498432 0.892160 2.031531 1.694680 1.234117 0.561854 1.333044 0.477159 2.104629
+1 0.004844 1 1 -0.657646 2.213715 1.603630 2.047719 1.433826 -0.845547 1.450467 0.815459 1.795429 2.342677 1.359824 -0.526839 -0.330397 -2.979800 18.500197 -17.183533 -53.638816 1.261167 0.677740 0.520706 0.507392 1.741223 0.484863 1.091322 1.341332 0.266719 2.245667 0.672036 1.406830 0.837428 2.408054 0.666142
+1 -0.026613 1 1 1.975962 1.789033 -1.475207 -1.930079 1.244586 -0.530367 1.962460 1.060123 -0.060356 -1.234559 -0.589045 0.654047 -45.913593 -69.760544 -65.471063 27.849005 58.229401 2.298075 1.744462 0.925007 0.597383 2.217566 0.883215 2.438242 1.777802 1.025010 0.599601 1.244266 2.369705 1.874854 0.927449 1.131649
+1 0.006492 1 1 1.176896 2.191917 -1.915657 -1.398401 -2.240219 0.622023 2.263537 0.147533 0.878604 -1.927629 0.012856 -0.698755 -22.409637 11.237341 15.984644 3.909610 8.808882 1.388329 0.403240 1.756407 1.435008 1.936313 1.118537 2.006256 2.142008 2.224541 1.109111 1.080178 0.798665 1.168265 0.781337 2.434604
+1 0.021425 1 1 -0.233991 2.151646 -0.156390 1.067542 2.109407 1.499654 -1.887826 -0.170035 -2.068917 0.436361 1.442004 -0.055038 -44.584979 60.255046 56.559224 40.872665 -53.117168 2.271418 1.467354 1.073512 1.264140 1.158885 0.621582 1.679556 1.302231 2.355211 1.280790 1.986348 0.555671 0.907969 2.227718 0.511573
+1 -0.010098 1 1 -1.655419 -0.688170 -1.876810 1.180854 -1.968821 0.414961 -0.082327 1.775967 0.400700 0.562521 1.240452 0.674662 33.068578 33.593111 -0.591244 -37.043415 61.328529 0.603780 1.737358 0.773936 1.789526 2.315111 2.317445 1.040979 1.229767 1.695993 0.806568 1.245007 1.338255 0.308768 2.462984 1.369385
+1 0.022817 1 1 -2.093612 0.077541 -2.096983 -0.034059 -2.238710 -2.290867 2.321588 0.357942 -1.796062 1.149299 0.183218 2.160236 -59.388801 -47.585940 23.100176 44.649988 -17.653592 1.316278 2.177098 2.478728 0.479992 2.483414 0.487038 1.645281 1.240585 1.257544 0.546243 2.205793 1.021621 2.139350 0.307346 1.068513
+1 0.010841 1 1 1.584121 -0.677129 -0.082724 -0.181776 -1.475832 1.711633 -1.720149 -0.039215 0.649625 -0.363589 1.125434 -0.366294 -61.429712 0.826385 -60.950816 -50.366419 -58.408160 0.385809 1.286571 2.406714 0.637645 1.648894 1.212224 1.597365 1.415505 0.399397 2.411930 0.561298 0.990291 2.065065 0.545542 1.666241
+1 -0.012181 1 1 -0.026680 -0.728858 2.301708 0.805896 1.292474 -1.499776 -0.165703 0.056731 1.577227 1.263183 1.009479 1.716180 -22.049644 61.629670 59.859229 4.060437 -6.234027 2.495490 0.944085 1.732481 2.062221 2.250894 0.783581 1.891675 2.385042 0.899273 2.326330 1.878247 1.700512 0.257972 1.484239 1.351171
+1 -0.026793 1 1 0.829908 -0.408344 -1.801035 -2.318986 0.980152 -1.098254 0.063673 0.441140 1.645997 -2.162444 -2.248856 1.544423 40.618956 32.785719 -70.424936 18.107113 -23.756011 1.865890 1.008985 1.266981 1.656796 1.276340 1.450947 2.059384 1.809473 2.318577 2.079500 2.414542 1.708930 2.235949 1.603135 1.637167
+1 -0.001589 1 1 -0.658233 1.760388 -2.251579 -1.808363 1.744683 -2.312674 -1.332423 -0.767515 -1.823859 0.501328 0.059850 2.161905 -66.669687 -17.435607 59.759279 -25.794591 -29.696192 0.566519 0.977443 2.138306 0.752164 0.372263 0.867963 0.357665 0.779113 1.059574 1.008322 1.364112 0.626025 2.107013 1.313576 1.767300
+1 -0.014928 1 1 0.368569 -2.251962 1.183206 -0.137735 -1.123084 2.155632 0.859407 0.585164 0.093727 1.330815 2.017409 0.962791 -22.592713 -65.732604 -17.882552 47.946279 33.112624 1.733165 2.297238 1.179625 0.464980 2.161320 0.552298 0.469148 2.468599 1.236363 2.302260 2.334828 0.712407 0.430604 0.417718 2.083003
+1 -0.020110 1 1 2.215652 1.162933 -1.575457 0.205967 -1.922952 -1.496527 -2.104127 -2.289466 2.317427 1.096796 -1.012071 1.845396 -43.488170 44.334151 74.072326 -66.411872 -34.332221 1.800312 1.340828 0.789569 1.294480 0.317188 2.234474 1.555499 2.022725 2.184239 1.009210 0.536963 1.488189 2.499055 2.366119 2.369563
+1 -0.014796 1 1 0.590881 1.928907 -2.104329 -0.978233 0.362621 1.460532 0.330178 -1.899229 1.385045 -0.749017 -1.933842 -0.741221 58.838229 -55.883796 61.047024 17.338527 -41.372959 2.045225 2.342858 0.664050 2.187577 0.853786 0.579136 1.534693 1.084238 1.540545 0.445646 1.220617 0.910220 1.822812 1.495696 0.404925
+1 0.061639 1 1 0.387150 -0.978691 2.090836 0.393674 0.293077 1.304815 -1.425772 -0.446091 -0.048057 -1.877704 0.297870 1.748608 -73.659745 -49.327135 8.849419 -67.822795 -47.711015 1.689495 1.846668 1.953168 0.889840 1.296146 1.319247 0.332240 0.966143 1.218873 0.842991 1.404743 1.772091 1.785333 1.591230 1.811148
+1 0.019964 1 1 -0.499592 0.836355 -0.434267 0.765274 1.851643 -0.058451 -2.206156 -1.792222 -0.284533 0.926587 -1.295079 0.124801 16.735217 18.785768 -17.598408 23.549843 -47.789144 2.242737 0.926221 0.754608 0.941114 1.299516 1.707969 1.835094 0.922784 1.486441 2.358325 1.860914 0.628575 2.214620 0.864297 1.742018
+1 0.001566 1 1 0.446234 -2.268217 1.305422 -0.664599 -1.558129 -0.727063 -0.526731 1.803312 -1.819255 -2.232427 -0.362945 -2.182580 -44.202982 30.479715 22.574288 56.061956 -66.703581 1.568609 1.853912 2.202690 0.610248 2.432027 0.821453 1.661666 2.128261 0.678833 0.892750 0.697205 1.416132 1.936310 1.057046 1.263854
+1 -0.000792 1 1 0.827998 0.476398 0.478965 1.208893 -1.959338 -0.424807 -0.463366 1.779556 -0.537963 1.534625 1.546674 1.408730 47.095280 -19.633156 25.550818 -17.406941 -58.463517 2.180132 1.732728 1.714783 1.609754 0.389063 1.980572 2.472472 1.078110 2.041069 2.242911 1.613299 1.472858 1.317526 0.656361 1.213633
+1 -0.020427 1 1 -1.175929 -0.078328 -1.701036 0.747658 -2.046504 0.142734 0.320518 0.677857 -1.809469 2.006378 -0.666216 -0.463319 -68.011630 -71.458321 50.002980 -49.910650 -48.290550 1.835987 2.428646 0.254155 0.328217 0.836082 2.276542 2.094169 1.444540 2.380879 0.681062 2.358063 1.961504 1.502109 2.439473 2.220915
+1 -0.027168 1 1 -1.678146 -0.958815 1.572771 1.766191 1.030253 2.153717 1.664893 -0.314316 -0.128690 0.091869 -1.629429 -2.124449 5.178361 32.708312 -21.397602 70.506747 6.898702 1.322296 2.085765 1.954464 2.431898 0.907847 2.441481 2.220236 0.755875 1.990392 1.015925 0.896696 1.776183 0.806180 1.461752 1.414043
+1 -0.079167 1 1 -0.223488 -0.381755 2.122471 -0.421138 -0.052041 1.852523 0.603358 -0.420060 -0.783746 -1.290458 -2.311988 0.773390 50.604659 12.497634 47.734511 73.931112 -39.806873 0.863186 1.069682 2.148779 1.271038 2.332465 1.494033 1.719201 1.604884 1.785875 1.693564 0.481043 2.139057 2.135221 0.664714 2.099568
+1 0.039433 1 1 -1.412269 0.302735 -1.319626 2.265806 0.581461 -0.876344 2.212152 -1.106089 0.328025 -0.375740 -0.457596 -0.191158 33.626285 -43.023480 54.367038 -53.186588 -56.986123 1.138575 1.286099 1.218885 1.054092 1.123503 2.214447 2.455341 1.171925 1.547281 1.143197 2.455698 0.415472 0.342738 1.905211 0.377152
+1 -0.015125 1 1 -2.054017 1.102506 0.702176 1.650456 2.094809 1.198919 0.049936 0.463536 1.074472 0.781760 0.905723 1.471418 -15.941191 -23.600180 -48.222981 -33.633589 70.261791 0.473896 1.263467 1.098165 1.605162 1.956485 0.400350 0.430716 2.291474 1.051205 2.104232 1.826827 1.479001 1.066421 1.336866 1.706964
+1 0.052634 1 1 -0.909142 2.324814 -1.982263 0.698948 -0.770079 2.210273 0.297567 1.367155 0.168646 2.292446 0.647366 -0.621632 -12.757849 -71.165612 19.559302 -66.813765 -38.946344 1.807043 1.968047 1.210317 1.052504 1.427705 0.681210 0.350998 1.226046 2.154289 1.630657 0.702239 0.533898 1.717179 1.377979 1.952195
+1 -0.044952 1 1 -1.840049 1.696556 -0.653586 -0.246481 -0.420596 -0.378781 0.261355 0.651030 -0.301808 -1.954796 0.522859 -0.920702 39.679269 -10.525349 -49.539223 44.282972 -36.082439 1.561654 1.966203 1.723002 2.489863 0.884285 2.428005 0.721468 1.969056 2.420691 1.561086 1.426031 1.803087 0.725425 0.963773 1.886478
+1 0.020564 1 1 -0.431523 -0.235146 1.602256 -2.181057 0.653718 -2.245973 -1.829363 2.242783 0.062578 0.883108 -1.623941 0.586031 17.112554 60.695873 -34.460398 -25.917411 6.079350 1.759510 1.836310 1.104504 2.390381 0.630383 1.090891 0.864128 1.149907 0.489024 1.282925 1.864004 0.814268 2.398284 0.715120 1.013660
+1 0.003631 1 1 -2.106998 1.281743 1.924600 0.911042 1.331189 -1.131199 -2.281408 1.081404 -0.521508 0.059576 2.262965 -0.041137 42.526892 -0.532439 51.306105 -48.287816 -73.323635 2.120119 1.086406 1.974233 1.687939 0.446653 2.404894 1.556048 2.255191 0.998707 1.766998 1.689563 0.736626 2.471237 0.588650 1.689761
+1 -0.062882 1 1 -1.236322 -1.938406 -2.038702 -0.690912 -0.829072 0.313320 2.234909 -0.333201 -1.794552 -1.746737 0.772682 -0.873212 -54.059526 -28.450159 38.175199 60.562953 -18.456415 1.420458 0.381801 1.425845 0.922940 1.851479 1.809668 1.089528 0.449793 1.163999 1.080404 2.341962 1.350729 0.702307 1.668520 0.309362
+1 -0.057496 1 1 -2.073852 2.317325 -0.614293 0.421999 0.389630 -1.709616 -2.075424 -0.554338 -0.366224 -0.741827 1.094588 -0.433987 24.138528 -53.755346 -16.105710 61.338082 -40.850413 1.031668 2.238972 0.655174 1.506450 1.160568 1.910039 0.521142 1.084036 0.394287 2.023828 0.474346 2.091484 1.330561 1.492569 1.858435
+1 -0.025479 1 1 1.863505 1.387830 -1.061460 1.143247 2.139223 -1.608338 -1.078199 -2.149703 -0.164149 -2.098368 0.254233 -1.247553 -70.365453 -32.166566 -23.466621 -53.506403 -32.119312 1.685871 1.691822 0.445264 1.555591 1.311604 2.380677 1.794700 1.515778 0.428164 2.146465 0.631394 2.341679 1.100964 1.405216 0.715519
+1 0.057479 1 1 -0.367804 0.968857 2.274574 1.868780 0.519093 1.767375 2.091735 1.361263 0.099035 1.011382 0.717328 1.843745 -27.096216 -6.100116 -74.650944 -58.416214 -51.310188 1.070122 0.545331 0.385394 1.065971 0.519362 0.412701 1.021658 0.508811 0.839047 0.357567 1.385846 1.412117 1.959044 0.659837 1.136638
+1 0.016192 1 1 -1.399523 -2.245173 2.182676 -1.704529 -1.412233 0.895189 -1.211105 -2.239729 -0.569685 0.880914 -0.802037 2.309049 52.863132 20.659335 -28.563663 -69.478829 19.316420 2.141118 0.764868 2.394538 0.753996 1.911913 0.529342 1.644166 0.499925 2.236564 0.677362 0.927121 2.368591 1.153371 2.456934 0.934709
+1 0.050986 1 1 -1.338596 -0.846009 -1.589471 0.289887 -0.481221 -1.422900 0.697560 -0.536297 1.255916 1.392575 -1.422556 1.759650 -16.616760 22.112263 -59.202143 -60.412041 4.825773 0.726611 0.643750 0.751474 2.271993 2.130880 1.943390 0.812964 0.728788 1.240729 1.431064 0.886373 1.516568 2.465460 2.491663 1.873204
+1 -0.039104 1 1 1.220801 0.253512 0.780804 -1.030985 -0.306482 -0.400824 2.065765 -1.564995 1.676104 -0.380582 -1.733089 -0.757368 -29.589235 -56.271356 -2.674974 41.714300 -7.763587 1.635993 0.388216 1.252919 1.566068 1.906726 1.097781 1.905621 0.526224 0.988745 0.832638 0.648810 0.298114 1.159230 1.928963 1.335648
+1 0.021673 1 1 -1.407755 0.764716 1.893367 -0.936701 0.960351 0.689731 -0.174764 -1.436156 -0.616657 -1.604372 -0.393592 1.093829 30.244904 -23.895107 -55.068821 -41.675861 53.799455 1.486561 2.132376 2.347914 2.399199 0.332413 1.610853 0.857306 1.249992 1.859100 1.642316 0.898483 0.307012 2.208233 1.523029 0.794013
+1 0.028410 1 1 -1.214807 1.515054 -2.234111 -0.383081 -1.324909 -1.714342 -1.405525 0.553523 0.802912 -1.736897 1.216916 0.941244 -0.226524 -57.181350 3.057698 -59.261711 -11.581154 2.208177 0.582479 1.477248 0.847981 2.010077 1.121831 1.108088 1.886357 0.748054 1.035487 1.178663 2.295828 2.228505 2.485229 1.749659
+1 0.005886 1 1 -0.137109 -0.026406 -0.844854 -1.037205 -1.172862 -0.363264 1.870827 1.933543 0.416897 -0.534235 -1.788246 0.567623 69.164723 -48.506931 -5.997037 7.807851 -23.441714 2.351803 0.257727 1.865575 2.465356 0.744570 0.995450 1.030172 1.849029 1.123838 1.095541 0.255639 0.529159 0.828487 0.635625 1.442399
+1 0.067949 1 1 1.661172 -1.578660 -1.792098 1.799201 -0.235053 -1.553796 1.415070 -0.340637 0.472685 -0.676469 1.576941 1.173569 -60.061721 42.662848 34.481331 -72.262247 38.418607 0.648035 0.780346 1.528149 1.351042 1.460242 0.779963 1.843735 2.150440 2.194823 1.137928 1.656949 1.590717 2.175303 1.565846 0.423724
+1 -0.019020 1 1 -0.391899 1.276057 0.604167 -0.965104 -0.463397 1.259166 -0.529437 -1.250849 -1.060981 -0.220437 -0.943187 0.327876 58.377566 1.750105 14.022225 21.528476 29.097072 1.892457 2.031675 1.865804 1.823684 0.407400 1.929943 2.052696 1.918976 2.227325 0.656172 0.281557 1.873745 0.280277 0.612433 0.909227
+1 -0.015952 1 1 1.284332 -1.693110 2.025075 -2.145262 -0.935059 0.281853 1.150017 -1.883053 -0.060088 -1.449544 0.560954 -1.535283 48.839498 45.439304 48.381576 -0.849046 -19.915531 0.320130 2.173093 0.424016 2.195053 0.503440 0.571468 0.920895 1.238649 2.466117 2.281744 1.780026 2.391782 1.671610 0.503630 1.509057
+1 0.020687 1 1 -0.014562 0.300737 -1.907464 -0.358872 0.295581 0.979175 1.329308 0.240556 -0.206433 -1.195063 -1.222651 1.634833 -41.335460 74.917255 34.297228 -16.495206 -34.924785 0.911994 2.381975 1.102975 1.456661 1.353527 0.472196 1.948034 2.351372 2.012104 1.424578 2.141588 1.922374 0.834931 0.936566 1.369754
+1 -0.014481 1 1 1.528295 -1.180458 -0.796926 -1.332283 1.585338 0.931628 -1.397130 0.266329 -0.577511 1.299613 0.669624 1.186921 33.231422 70.502224 -69.118431 -73.472918 -59.329873 2.017481 1.808819 0.313415 1.811405 1.034460 1.925499 1.609937 1.218371 1.417930 0.653305 1.598466 1.908930 2.141650 0.708683 0.832304
+1 -0.005734 1 1 -0.905137 -1.039481 -1.732000 -1.298104 1.123641 -2.212183 0.592855 2.123078 0.358475 -2.253139 0.243579 -1.226221 -57.908406 -66.577029 39.869045 29.035136 43.525090 1.017875 2.175163 1.458555 1.689242 2.092800 0.936294 1.290166 2.075279 1.209504 0.890956 2.044131 1.959597 0.947703 1.791339 1.292037
+1 0.055923 1 1 -2.019403 -1.473806 -1.946891 1.429917 -0.559855 1.164753 0.739851 -1.313174 2.315931 -0.476438 -1.143965 -0.067826 14.433001 25.442723 -34.159256 -64.608324 -22.097359 1.520423 2.001157 1.945266 0.835163 0.327137 0.685387 0.804223 2.326784 0.515449 2.154547 1.471727 0.313149 1.838072 1.467816 2.080281
+1 -0.010038 1 1 0.209671 -0.934072 -1.980741 -2.002615 -2.071429 0.622887 -2.069588 -1.416855 -1.375652 -1.607773 -1.009982 -0.733550 -37.098256 39.610369 31.468620 -6.902241 -55.960181 1.033493 1.422773 1.050852 0.669870 1.003007 2.043334 2.071927 1.130372 0.661272 0.506121 0.629960 0.739172 0.258442 0.391198 1.866803
+1 0.020735 1 1 0.761062 1.739581 1.480238 1.666121 1.484561 -1.078839 1.225324 0.877843 -0.580314 1.301814 -0.031827 2.302723 -31.471813 -46.761608 -72.345559 -11.806117 24.590541 2.023246 1.939898 0.614126 2.362806 0.684140 2.335895 0.633054 0.981179 1.922262 1.200116 0.605470 0.884517 1.826746 2.362552 0.910531
+1 0.002525 1 1 -1.517938 0.889237 -2.286790 0.158062 -1.242321 0.910227 1.775364 -0.301020 1.857939 2.088065 0.944811 -1.311085 -8.507039 -27.802423 -25.329117 -6.477437 33.707787 1.026532 1.422998 0.331575 1.036877 2.044027 2.455813 2.355140 2.339307 1.739250 1.079222 0.491210 2.009878 2.274526 1.955135 2.451377
+1 0.017007 1 1 1.691492 -0.934138 1.624114 2.333829 -1.260076 -0.618647 -2.070245 1.672750 -0.196730 1.655803 -2.287356 0.078559 27.793691 28.562389 48.067057 -36.974112 26.104761 1.265680 2.286765 0.653655 0.732887 0.390124 1.809755 0.306685 1.201056 0.643415 1.874747 1.369781 1.401415 2.088957 1.604654 2.421313
+1 -0.013019 1 1 1.338325 0.992948 1.913418 1.466754 1.229639 -1.986759 0.533710 -2.319395 -1.182575 1.327500 -1.870912 1.356793 11.624472 72.503252 -37.846370 66.060962 -13.410688 2.223402 2.217011 0.558546 1.977092 2.483713 1.015206 2.320341 2.463909 1.164551 1.349427 1.319438 1.290977 2.209673 0.972722 1.539904
+1 -0.006387 1 1 1.892133 1.884276 1.777090 0.433942 -1.518929 -1.627828 1.219622 -0.709644 0.064083 -2.086210 1.955133 0.437624 -28.229990 -11.443456 -30.170860 68.347691 19.647664 2.399284 1.762748 2.259707 0.402583 1.960127 0.850259 2.044770 1.451976 1.354370 1.150419 2.344651 1.558442 1.985821 0.687189 1.837183
+1 0.036556 1 1 0.327394 -1.564214 0.669458 -1.600979 0.080400 -1.166319 1.217861 -2.030238 0.196293 0.419018 2.125904 0.727001 -16.714825 23.941116 -71.659678 -34.204004 -66.688756 0.806119 0.435022 0.418923 2.086023 1.790938 1.297241 1.732796 0.599828 0.554977 0.506632 2.456567 1.522571 2.095724 0.589430 1.304786
+1 0.028876 1 1 1.247349 -1.217151 -0.184368 2.083790 -0.213008 1.386934 -1.997589 2.287935 0.224147 2.038026 -1.245323 2.292334 -39.535427 28.079856 38.143743 -18.104378 69.723408 1.994784 0.575505 1.268291 1.169587 0.496934 1.476787 2.101037 2.133177 2.310248 1.587028 0.937253 1.669028 2.101560 1.920374 0.979566
+1 -0.061986 1 1 0.354150 0.453059 -0.657446 0.864127 -0.208176 -2.225109 0.109780 -2.180533 0.030198 -1.408287 1.252957 -1.209125 -61.977679 -58.855989 57.390377 60.058979 61.255881 0.288985 0.713581 2.163057 0.499132 2.408537 2.026630 0.326313 0.340667 0.844487 1.790408 1.385141 0.819033 1.479199 2.151540 0.435483
+1 0.027163 1 1 1.646230 1.750767 0.981360 0.352689 -0.544796 -0.218985 -0.113066 -1.212625 0.487945 1.338404 2.320181 0.265881 41.997708 -44.514729 40.945417 -30.375715 -74.638065 1.495636 1.648287 2.266509 2.223662 2.082576 2.349848 1.137023 2.194600 1.895769 1.442393 2.294922 0.511349 0.743195 0.386179 0.766806
+1 0.016038 1 1 -2.015966 -0.255226 -1.302299 1.301058 1.400425 -1.443384 0.427751 -1.896452 0.923234 -1.102745 -0.003203 -1.997493 -25.694833 -3.063671 -41.120866 -68.397128 49.471322 1.592690 1.585645 2.437284 1.435075 0.808697 1.018504 1.493315 0.886752 1.140442 1.155502 2.272111 1.877144 1.155474 1.806890 1.659288
+1 0.016749 1 1 1.040690 -1.505953 -0.301988 -0.273021 1.207733 2.113413 -1.850848 -0.718021 0.643337 2.346636 1.927703 1.222396 -38.487192 -54.231922 74.092936 -20.022247 -63.905457 0.489861 1.847585 1.614431 2.499211 0.493925 0.391923 0.556722 0.572064 1.936713 1.084754 1.205111 1.299361 1.367214 1.012623 1.648583
+1 0.019096 1 1 -0.628558 0.997216 -1.763855 0.530127 -1.276027 -0.101111 1.791800 -2.097340 -1.316660 0.270813 -0.618548 -0.406622 -35.772567 -29.531075 21.228469 -63.127022 -25.852854 1.991139 2.320145 1.426123 1.106476 1.792922 0.891530 0.452638 1.730869 1.964613 2.001846 2.274193 0.868698 1.455698 0.912627 1.778752
+1 -0.015096 1 1 -1.104618 1.502872 0.363168 1.226179 1.105380 1.877508 1.119616 0.822213 2.201559 -0.072045 0.229874 -0.671965 59.865817 -35.207395 19.315295 32.160917 -71.471151 1.140510 2.301376 0.982749 1.313577 1.788590 2.323654 1.911676 1.043558 1.822687 1.654957 1.867316 2.476570 2.463805 1.662862 1.976107
+1 -0.044917 1 1 -1.579036 1.321252 1.508517 0.995883 -0.597539 -0.740086 2.083622 1.673530 -1.237232 1.605541 1.195800 -0.522756 -65.899951 19.529300 28.946569 54.977832 12.422874 1.243628 0.649285 1.530336 2.108002 2.186643 0.911636 0.861433 0.850802 2.172989 0.933105 1.699267 1.833262 1.633486 0.994263 1.324063
+1 -0.000062 1 1 2.310901 -0.192601 0.362702 -1.892685 -1.733347 -0.377415 -0.342932 -0.414436 -0.506489 -1.988867 -1.914806 -1.235185 -53.358860 47.647787 -33.638986 -20.433306 -72.577744 1.162732 2.280333 0.557352 2.156963 1.572892 1.842442 0.664433 1.873875 2.472110 1.756536 1.346747 1.284736 0.814693 0.541157 2.229380
+1 0.032022 1 1 -1.642323 -2.060690 2.036000 -2.316116 2.083529 0.113431 -2.085351 2.261816 -0.497033 1.423886 1.734754 0.451847 -69.511668 67.388338 -54.205805 63.034856 -23.174238 2.283848 1.129595 1.105239 1.253910 2.458717 1.658608 2.475744 2.072754 1.532305 1.445124 0.956304 2.357395 1.986384 1.147362 0.460712
+1 -0.034383 1 1 0.174199 1.366943 1.313915 0.714412 -0.044237 1.071248 -1.565714 -0.975177 -0.117267 -1.134935 0.904709 -1.436696 -8.603779 -3.704810 -16.741159 31.334108 -17.653875 1.244925 2.197083 0.875005 1.716740 0.744510 2.236136 2.489515 1.780961 2.362212 1.951111 2.317353 1.752557 1.978290 2.363415 1.908786
+1 0.040608 1 1 1.000518 1.895731 1.091035 1.116345 -2.314476 1.370916 2.117241 1.225418 -2.259068 -0.433128 1.057493 -1.839803 35.925109 43.306421 51.025710 39.100718 15.773562 2.218898 0.767175 0.654207 1.013850 2.028496 2.425923 1.734827 0.991679 0.646196 1.359242 2.025197 0.978648 2.137152 1.611262 0.981461
+1 -0.027247 1 1 1.477641 0.417906 2.294068 -0.358929 -0.669628 -1.261347 1.579596 -1.326797 -0.448510 1.722540 -2.187046 -1.044184 -21.271033 -52.249696 -60.633270 36.623786 -64.035751 1.391908 2.056961 1.589516 2.242967 0.297756 1.887455 1.209588 2.294138 0.822629 1.182208 1.121205 1.846568 0.265595 1.356965 2.015139
+1 -0.008046 1 1 -1.943869 0.382173 0.203085 1.479416 1.974833 1.663036 1.466079 -0.698813 -1.680515 1.644148 -0.261780 1.632942 -2.912862 -56.467831 -4.829520 -19.739135 44.359960 2.242750 1.153399 0.684869 1.085703 1.401557 2.225761 1.368135 0.748620 1.562293 1.464921 0.675278 1.889254 2.193506 1.503140 1.775313
+1 -0.001339 1 1 0.286915 1.400806 0.247193 -1.747134 -1.183954 1.708806 -2.112979 -0.275312 0.405402 -0.518711 -0.060386 -1.748716 16.004448 36.749441 -52.136965 34.030941 8.026447 2.132497 2.129151 2.137889 0.498722 2.269467 2.434186 1.119813 0.951181 1.743770 0.539413 2.164493 2.128670 0.799694 0.462530 1.487922
+1 0.024148 1 1 0.138934 -2.283414 0.354931 -0.556943 -1.736182 -0.904197 0.621468 -2.348192 0.199440 1.487721 0.191049 1.828724 37.066447 25.779739 -69.931334 64.069485 -34.171351 1.856502 0.738221 2.279947 0.817556 1.412087 1.455312 1.177410 1.483483 2.154210 0.303125 2.118001 1.492331 2.355852 0.800868 2.188132
+1 -0.005358 1 1 2.179895 -1.338203 1.055785 -2.270940 -2.052749 -1.159763 -1.688724 0.327717 -0.845301 0.876373 -1.726431 -1.944382 37.872630 -74.704216 -53.756771 -40.042660 53.013046 1.229075 1.310240 1.960038 1.605103 0.967070 1.044520 2.239180 1.897809 1.967476 0.619677 1.161162 0.642346 1.905323 2.259942 2.086701
+1 0.004215 1 1 -1.189930 0.231709 1.899813 -0.987186 0.679591 -0.950698 1.326668 -1.709871 -1.656451 0.819177 -1.696874 0.022487 29.980474 31.822062 -66.597578 -5.498065 -5.979608 1.385857 1.600713 1.440894 1.859089 1.458192 2.340479 1.186203 0.755229 2.391001 2.060196 1.957145 2.485653 2.112877 0.881154 1.547324
+1 0.011203 1 1 1.372858 1.772398 1.686523 0.368902 -1.361184 1.230337 0.306077 -1.688841 -1.636375 -1.056923 2.000591 1.040799 10.224142 -62.847555 21.140309 -44.831294 -29.556584 2.012306 0.322017 2.392728 1.826147 1.295174 0.743478 0.630978 2.103170 1.972268 2.416394 1.332119 0.676130 0.460553 2.015313 1.370006
+1 0.046177 1 1 -1.024631 -1.900913 1.361589 0.870172 -2.280614 0.295638 1.932878 -1.330065 1.173734 0.895142 -2.005631 -0.913522 -18.952040 73.071564 63.781034 67.836648 -19.461934 2.174050 0.760985 2.382439 2.147922 0.370585 1.920353 0.623840 1.374988 1.166567 1.494184 1.999609 0.672355 2.276337 0.901580 0.601900
+1 0.030093 1 1 1.138654 0.351853 -0.455268 1.236193 -0.218537 -1.995111 1.531304 2.269577 -2.005600 -0.392616 -1.350699 -1.617695 59.950527 38.505829 67.470220 -28.006078 1.854854 0.992920 1.253462 1.683105 2.453241 1.871574 2.042088 1.373867 0.336628 0.455885 2.313015 0.842303 1.081046 1.888683 1.590028 1.856941
+1 -0.041386 1 1 1.893806 1.723106 -2.095409 -1.859369 2.144535 -1.866770 0.277159 -2.346930 -2.156100 0.703433 -0.782313 -0.763535 -28.452010 7.068903 7.047088 -59.589745 25.148674 0.981449 1.962335 1.955249 2.125073 1.096721 2.084785 1.227061 1.218875 0.880658 2.213233 2.311606 1.903755 0.666752 0.356972 0.372740
+1 -0.005115 1 1 0.034151 -0.928148 -1.372780 -0.452505 0.548856 -2.238445 2.166631 1.945307 0.218696 -0.041901 -2.084116 -0.546363 54.723194 -67.277281 -29.255607 1.018556 18.863425 0.438708 1.617017 0.949548 1.309031 1.885718 1.261345 1.427947 0.255640 0.535234 1.684695 2.174256 1.969564 1.956779 0.840472 1.805659
+1 -0.032914 1 1 0.460828 -2.024168 -1.450318 1.692405 0.268861 -0.428015 2.175979 -1.172557 0.037293 0.031683 -0.006844 -1.928039 -69.026521 -28.746024 15.566659 28.838471 38.182081 1.768650 2.452892 0.504356 2.463837 2.215161 0.966279 1.242713 1.022923 1.513731 2.032157 0.964230 0.562650 1.204003 0.678427 0.828432
+1 0.048170 1 1 -1.812409 -0.271066 1.072300 1.969264 2.318165 -0.630797 1.062987 0.959449 -0.327426 1.024020 1.055357 -0.053796 20.168434 -29.133876 -53.046037 55.250433 -55.974386 1.952407 1.604550 0.679293 1.869619 0.679678 1.600064 1.769781 1.208185 1.212567 0.615478 0.330745 0.577908 1.145659 1.092943 1.600206
+1 0.022822 1 1 0.368212 1.164549 2.026411 1.450158 0.323659 1.634221 -2.161445 0.404079 0.795755 0.494485 -1.845231 -0.561402 -40.768752 -0.412879 -39.261456 -17.298486 -35.661810 1.854305 2.046328 0.631380 2.109923 0.721097 2.481514 2.303150 1.547547 1.128064 2.376158 2.334033 0.851574 1.656349 0.508301 1.258390
+1 0.057628 1 1 -0.767730 -0.720228 1.250447 -1.001245 0.009481 -0.875930 -0.252869 0.611401 -1.911556 1.545714 -0.586692 -2.221760 -5.001532 -60.745155 -43.815608 -58.931573 -12.954967 2.362928 0.474973 1.372798 0.360389 1.559517 2.054966 1.818640 1.136011 0.943830 1.954893 0.637196 0.850390 2.008827 0.347628 0.833203
+1 -0.006245 1 1 -1.839210 1.671089 0.158544 2.151305 -1.168322 0.541472 0.895198 -1.071548 1.242681 0.422458 -1.324016 -0.843382 4.733467 55.387295 -5.727371 40.076290 62.208907 2.051434 0.952109 1.603825 1.991487 1.426357 0.529359 1.945198 1.936524 2.400775 2.081374 2.402949 0.359994 1.665728 0.639687 2.221840
+1 -0.004669 1 1 1.989907 0.541631 -1.138495 2.326512 -1.725388 1.448494 0.642089 0.215314 -0.334218 -0.035345 -0.287127 -0.250226 -66.882568 4.673554 -51.584679 16.298977 36.901388 0.649527 1.093918 2.230864 1.626316 1.992520 0.784948 2.377909 0.275725 0.615087 0.521392 0.790940 1.835778 1.174865 1.450434 2.448227
+1 0.010059 1 1 -1.515654 1.583544 -0.946716 2.288361 -2.031722 -1.188738 1.405529 -0.475520 0.150979 2.232907 -1.004722 -1.870964 15.028386 -17.914156 -33.226272 16.046463 -7.097609 0.782334 1.190181 2.379093 2.172050 0.900478 2.338964 0.474043 1.497387 1.831174 0.300011 1.532717 1.633817 2.064094 2.229440 2.447032
+1 -0.025074 1 1 -1.376883 1.263915 -0.831966 -1.190473 0.524814 -1.044518 -1.562900 -0.800166 0.768306 0.970526 2.060370 1.995500 9.456895 -57.964474 41.083110 33.834326 3.512251 0.331049 1.185934 0.749424 1.574074 1.458496 0.694544 1.698962 1.211165 1.807662 1.123664 0.427499 2.220175 1.973792 1.023425 0.953074
+1 0.009763 1 1 1.551759 2.052521 2.039009 1.137681 -1.873153 1.391179 -1.334822 1.325347 -0.355721 1.417946 0.870285 -0.369335 -38.170303 21.717233 51.530722 -23.157209 46.780218 0.401961 0.502826 1.490409 1.548453 0.595079 1.750511 1.346617 1.342639 1.981189 1.601957 2.090617 2.492569 1.356208 0.545708 2.220210
+1 0.025241 1 1 -1.939372 0.571236 1.627103 0.730253 2.301999 0.978677 -2.325030 -1.642244 -0.735080 1.389080 1.086680 -1.395666 41.532762 -58.873642 60.691935 49.356693 37.930935 1.453491 2.074876 1.193313 1.007554 1.968992 1.356507 1.058997 0.309050 0.445386 1.349893 2.402632 1.780072 0.919709 1.547561 1.350347
+1 0.007832 1 1 0.803794 -1.060631 0.942817 -1.832979 -1.998629 -1.054157 1.372853 1.683700 0.044818 -0.718716 -1.613614 -0.207913 70.216273 74.897213 -2.534053 10.178689 73.218585 1.146328 1.086519 1.621058 1.363771 1.658258 1.091480 1.755201 1.415207 2.134788 2.376089 1.174195 1.444638 1.781120 0.528688 1.901682
+1 -0.004649 1 1 -2.254046 -0.861833 1.056756 -0.098379 0.592961 -0.807189 0.535005 0.596790 2.284160 -1.953442 -0.279037 -0.946939 -46.833386 71.279100 -62.161196 6.774625 11.121381 1.630657 0.696886 0.562051 2.383139 0.411289 2.039404 1.271740 0.629414 0.558617 0.934123 0.813512 0.940528 0.460249 1.407058 2.418761
+1 -0.026769 1 1 0.055787 -0.151731 -0.739212 -2.072437 -2.186165 -0.375884 1.827772 -0.696441 0.493564 1.526556 -2.125973 -1.893211 -36.745007 -23.325086 -74.713555 -60.718128 -39.575876 0.598810 1.457251 2.259867 0.834836 1.590879 0.406281 1.117983 1.689582 1.046709 0.781288 1.610417 0.272650 0.685117 0.769186 0.716218
+1 0.000431 1 1 -1.359435 2.345725 0.757011 -0.367669 -1.474140 1.872691 0.277362 1.077830 0.666654 -1.604605 0.401677 -1.867807 54.054354 -58.471846 63.688347 10.047153 -37.503766 0.988009 1.972033 0.699839 0.698986 2.103439 1.994679 1.073624 0.889411 0.829648 2.146129 1.743679 1.260412 1.501628 1.105998 0.502009
+1 0.008679 1 1 1.124509 -1.768819 1.915633 1.009455 1.309458 1.198241 -1.906768 1.910434 -1.555204 1.303131 -1.460992 1.358980 -18.282452 -73.173722 19.256382 -57.990625 51.569474 1.797263 1.855722 1.125433 0.898580 1.935418 1.815430 1.177799 1.271687 1.993189 0.778524 2.398761 1.971836 1.892825 1.452566 2.274657
+1 -0.052344 1 1 -1.240296 1.960921 -1.258401 -0.737109 0.281184 -0.663146 -0.695000 1.155139 -0.615679 0.692219 -0.756358 1.920933 17.087470 -60.897334 -51.493431 49.904991 -46.822142 0.778884 1.699256 1.652009 1.816966 2.241705 1.580995 0.789715 1.495575 0.630715 2.170602 1.303078 0.830398 1.252790 1.642055 1.024167
+1 0.034807 1 1 -0.523566 -1.551006 1.172627 1.128217 -0.704702 -1.692481 -1.552206 -0.139423 -1.225944 -1.884089 1.369071 -0.610396 -1.508714 -6.961536 -2.528563 -47.558983 26.164779 0.646551 0.574684 0.968457 1.861950 2.295982 0.319648 0.818821 2.426323 1.711275 1.143307 2.068607 1.572300 0.888679 2.031450 0.329481
+1 0.027929 1 1 -1.703576 0.471882 -0.026572 1.077200 -0.499876 0.771156 1.749389 1.382397 1.867007 -1.004235 1.601661 1.946451 18.799854 69.137913 -49.088619 -32.420462 59.297108 1.472510 2.223042 0.662501 0.899487 1.427420 0.407057 0.649275 1.367960 2.310627 1.204122 0.432686 1.656366 0.799823 0.376576 1.357108
+1 -0.008910 1 1 1.775105 0.055661 -2.269432 -0.267008 -1.401395 -0.728034 2.004946 -1.171564 -2.118937 -1.448141 0.585854 2.274998 -13.656212 -19.957628 -27.851151 55.698472 -25.780766 2.164884 1.954135 1.390083 0.624868 0.651960 1.490409 1.555708 1.030609 2.446645 1.265289 2.467868 2.456355 2.462316 1.398209 2.200337
+1 0.037371 1 1 0.872697 -2.245891 -0.456582 -2.000486 0.728451 0.295051 1.496184 1.051773 0.983892 0.504840 -2.162600 -0.159326 -36.771401 -16.935826 59.570919 -41.568392 60.038999 1.756724 2.266233 2.083374 2.268950 0.492995 0.524542 1.985278 0.563619 1.739500 0.769116 1.785319 1.352747 0.874552 0.842287 0.815532
+1 -0.009151 1 1 0.683938 1.424227 -1.943686 -1.246051 -0.515397 -0.900018 0.171317 0.061901 -1.069391 -0.199154 -1.388591 -2.305126 -54.319262 -43.837318 26.204266 15.092466 9.081909 0.469682 2.442402 1.944048 0.615249 0.985906 0.370456 1.996939 0.803921 1.754593 2.440332 0.901286 2.407729 1.944254 1.829004 2.072493
+1 -0.047340 1 1 -1.011549 1.201886 -1.911533 1.939454 0.814896 1.748049 -2.283318 1.970056 1.489912 -0.681197 2.230613 -1.849576 57.201766 40.080070 -24.262497 70.206409 59.108885 1.270576 1.314356 1.373185 2.373024 1.414543 2.217778 2.189419 0.314952 0.641141 1.911830 1.372691 0.811543 1.605255 1.266390 0.723056
+1 -0.014233 1 1 -1.951809 -1.109890 -2.289626 -0.378493 0.393530 -2.132874 -0.074164 2.311702 -0.862561 -1.760268 -0.451539 -2.061931 1.157999 -37.507213 66.276486 8.901449 56.658922 2.372628 1.499851 0.497951 0.559704 1.195422 0.460737 0.611227 0.897667 2.333181 2.264057 1.505360 0.838305 1.399212 1.062786 0.991416
+1 0.007478 1 1 -1.524789 -1.154663 -0.807752 0.507910 2.312650 0.928983 1.277092 -0.846273 -1.320308 0.219076 1.633739 -0.832171 2.264933 -33.266796 -65.043713 10.312343 69.544655 1.930234 2.446981 2.409978 1.499304 0.300034 1.918802 1.557328 1.269145 2.013760 2.270812 0.289108 0.542152 0.942290 0.816430 0.483149
+1 -0.018430 1 1 -1.554266 -1.772023 -0.092315 -1.168903 0.204245 2.133879 -1.885528 0.755331 -0.331857 1.941532 -1.971838 1.553432 60.538161 14.878642 15.342672 14.280507 12.476231 1.195255 2.143420 1.217096 2.482796 1.355316 1.295851 0.874864 1.584972 2.375596 1.890854 2.079467 1.858668 1.138874 1.801237 1.133527
+1 -0.010969 1 1 -1.786723 -2.117786 -0.949573 1.389673 1.632615 -0.879723 1.979840 0.999142 2.330182 -1.290680 -1.329733 2.036815 62.261638 31.346223 35.975731 -5.884672 -53.679463 2.263892 0.983088 0.259914 0.370774 0.595756 1.865045 0.316868 1.357905 2.061378 1.583976 1.393298 0.656493 1.181440 1.718937 1.667280
+1 -0.022881 1 1 -0.345665 0.782264 -0.049246 1.696012 -0.363874 1.043380 1.285949 1.931108 1.911625 -0.384851 1.922276 -0.449592 -74.265605 -32.020127 37.717938 25.382569 4.829190 1.587830 0.910610 1.627832 0.476497 2.237260 1.126473 0.387815 1.261381 2.026699 1.488353 0.742606 1.733713 0.265371 2.082634 1.081621
+1 0.036745 1 1 -0.861513 1.720237 1.516147 1.999982 0.225670 -0.639195 1.293643 -0.711066 -0.267703 1.049875 2.071775 0.476416 24.575361 -61.899390 56.956647 -29.632270 -29.564054 2.379146 0.811163 1.968016 0.692691 2.057618 1.386201 0.634798 1.041875 0.539161 2.432178 1.116864 0.887078 2.114126 1.619151 0.828401
+1 0.028081 1 1 -0.826111 -1.749312 -0.097503 1.172489 -1.192587 -2.016605 -1.579901 0.913073 -2.231482 1.390760 1.053781 1.745882 -32.169006 -64.488145 47.753934 -49.635331 -71.009205 0.599274 2.490857 1.825536 2.279551 0.908482 1.853508 2.161317 0.504013 1.196764 0.511563 2.094374 0.394789 1.466128 0.720648 1.674734
+1 0.010006 1 1 1.391583 0.746139 0.693711 0.744774 1.315923 1.467956 -2.135331 1.049469 -0.051673 -1.396733 2.228829 1.149990 -74.246419 -9.566279 19.550335 -67.517940 -24.017939 1.082484 1.307929 1.371039 2.295344 0.846041 0.905539 1.886609 0.481002 1.451853 1.545311 1.794892 0.251422 1.648609 0.921412 0.917460
+1 0.007072 1 1 -0.265823 -0.350831 -1.215056 2.045186 1.283039 0.145029 1.190046 1.716487 -0.240483 1.437406 -1.930406 0.463197 2.779624 67.147926 -44.802944 -3.073919 -63.356557 1.620181 2.388779 0.702916 0.657588 1.586643 1.201473 0.903038 0.359510 0.292861 0.608209 1.919816 0.593476 1.793708 0.593915 2.428603
+1 0.003139 1 1 -1.499026 -1.694287 1.085190 1.852029 1.718169 -0.245167 -1.893946 0.645981 -0.338282 2.352491 1.373584 -0.168810 -10.295494 63.638038 64.503436 59.248380 -62.477624 0.453692 1.446208 1.167276 2.150874 0.487058 1.985106 2.177115 0.518437 0.614296 0.725626 2.088971 1.840108 1.952785 1.208103 2.081467
+1 0.003017 1 1 -1.753403 1.831240 1.031244 -0.051121 -1.543458 0.807043 1.714035 0.949130 0.587192 1.201291 2.214315 2.257110 16.232456 -31.104461 -22.669600 -7.960477 8.264664 1.438116 2.418970 1.872035 0.795424 0.684256 2.038858 1.079440 1.899759 1.006244 2.438663 2.109729 1.971630 0.682450 0.940303 1.170686
+1 0.004904 1 1 1.684339 1.357766 -2.128349 0.587712 0.505114 -2.270372 -1.929358 -0.777833 -0.873134 -0.379359 -0.017673 -0.152498 16.263149 34.750321 -51.362392 2.278171 39.220055 2.447004 0.551064 2.225462 0.836885 2.280557 2.069374 0.964425 1.594994 2.060430 1.400332 1.879835 1.386978 2.432396 0.279235 1.106768
+1 -0.012210 1 1 -2.345469 -1.162154 0.533553 -0.248858 2.046165 -1.125013 -1.994612 0.495602 -1.917653 -1.963151 1.462217 0.378233 -1.638993 53.437919 -68.900511 -10.881197 -30.273735 1.215070 2.175646 0.581810 1.481841 1.547287 1.252322 0.519962 1.509381 0.916190 0.911994 2.379827 0.995853 1.043000 1.454065 0.477589
+1 -0.038257 1 1 0.046082 1.668301 0.419686 -0.779998 0.442126 -0.630870 -0.155594 0.299442 -0.117492 -0.196531 0.290577 1.687548 -40.006218 65.499618 2.072176 27.054216 50.204263 1.870621 1.771048 2.260809 0.911381 1.075480 0.594765 0.969297 2.476023 2.260235 0.268793 1.102069 1.979080 2.153159 0.642428 1.029291
+1 0.030481 1 1 -1.287783 0.228017 1.106955 0.078273 0.777354 2.249873 1.408944 0.363593 -1.053110 0.109952 0.714248 1.919825 24.433701 -42.788922 -53.417980 -45.997446 20.933012 2.442016 2.219396 2.395994 0.464624 0.693430 0.970594 1.770281 0.616940 2.405024 1.485414 0.859598 1.506949 0.546659 2.451945 0.346967
+1 0.052081 1 1 -1.685403 -0.393637 0.328698 1.501743 0.248272 2.248929 -0.315478 -0.794587 0.292049 -1.841623 -1.182004 1.490907 60.379242 43.915299 -65.573468 -43.284643 15.011233 1.281841 1.651959 0.967227 1.440779 2.177645 0.424954 2.208732 0.910758 1.860202 2.165025 2.072255 2.139979 1.883369 2.290840 1.649832
+1 0.024469 1 1 -2.236943 -0.864684 0.269964 -0.742818 -1.423363 2.333019 -0.743319 -0.418199 2.216478 0.905006 -1.152941 -0.131062 -65.777541 -23.127968 -61.763315 -56.039729 -9.717987 1.671933 1.428977 1.812442 0.465356 1.735905 1.100234 0.386179 0.758670 1.717314 1.402982 1.415488 2.356201 2.177542 0.946916 2.059724
+1 -0.022885 1 1 0.764903 0.319616 -0.329526 -1.282136 0.894847 -2.260287 -2.073860 2.168031 1.906993 1.881217 2.200441 -0.021530 31.919252 66.863907 -18.313345 7.609289 -60.684612 2.480865 0.392761 1.136297 1.250632 1.366499 0.252883 1.453078 1.873892 0.505427 2.457351 1.198312 1.784175 2.371879 2.418442 2.006248
+1 0.031503 1 1 -1.638249 0.430675 0.118067 0.443436 -2.170346 1.588966 0.640667 -0.111014 0.292957 -0.721753 -0.812787 0.699729 -56.444565 -63.808459 71.232074 47.467468 -64.258824 1.404133 0.517878 2.482432 1.986320 2.331187 0.265140 0.460554 2.024012 1.324258 1.302070 1.892405 1.159397 2.486049 2.027005 2.130260
+1 0.057566 1 1 -1.663229 0.009127 -2.118331 -0.682985 0.444951 -0.263635 -1.273014 -1.294609 -1.391126 2.212330 1.872448 0.909102 54.253700 -8.070081 -33.855652 -61.946658 12.514034 1.725653 2.055523 2.169389 1.163956 0.353754 0.301599 1.230083 0.257496 2.478403 1.770008 0.526663 1.617864 1.696571 1.521460 1.430274
+1 0.071828 1 1 1.621816 1.394449 1.788958 1.975855 -0.009095 -2.063601 0.249478 -1.051204 -0.844495 0.288952 -2.051296 -0.292539 -53.737227 -11.571116 74.250747 -67.696619 -27.078001 1.375624 0.618198 1.049357 0.299578 1.013057 2.207389 0.837480 1.028026 1.775135 1.186741 0.807376 1.324830 1.921361 1.810706 0.526939
+1 0.028309 1 1 1.711055 -2.006369 0.807212 -0.154173 0.624663 -0.490828 2.053638 1.949548 0.817622 0.447345 2.270770 -0.805373 -60.948102 -4.753557 56.974917 -22.567803 52.938628 0.467759 1.628152 1.359810 0.334070 2.458108 0.420508 1.726264 1.070301 1.298303 1.586051 0.261393 0.480993 1.302121 0.497233 1.992769
+1 -0.033814 1 1 -1.675081 -1.271596 -1.033449 0.680617 2.170181 0.349242 -1.924436 1.843592 1.295480 1.892319 0.294445 0.732688 25.844140 -37.538596 -11.176974 -51.407786 -10.667219 0.865864 1.075275 1.653145 0.654459 0.741305 2.355335 1.107634 1.011499 0.761995 1.350226 1.255674 0.616053 0.998567 1.662032 1.521804
+1 -0.000006 1 1 -1.431881 0.553038 2.083687 -1.938776 1.162055 -2.185338 -0.613121 1.273406 -1.530222 1.776607 1.742415 1.977847 15.377892 6.236946 -25.649104 15.507313 -68.596290 1.407356 0.680711 0.960046 2.249173 1.097559 0.416192 1.185471 1.960307 1.622918 1.128733 2.372586 0.800409 1.215825 1.362059 2.133132
+1 0.004168 1 1 1.882546 0.968993 -0.144929 0.475274 0.438421 -1.631663 -1.964926 -0.087259 -1.014078 1.103028 0.046052 1.171478 21.527416 11.277604 -57.315773 -6.199490 55.167420 2.107416 1.349050 1.726927 0.955737 1.828651 0.644523 0.255595 2.034056 1.372020 0.797629 1.750577 2.440949 2.278288 2.189872 1.179966
+1 0.015794 1 1 2.148011 0.012605 -0.197206 -1.624931 -1.918605 0.878399 -0.662092 -1.825645 -1.253908 -0.622398 0.856120 1.884811 42.491591 6.172813 -53.530332 15.711747 67.328125 1.131895 1.508178 0.950062 0.946619 1.578678 2.336396 2.313345 1.882744 0.779144 1.569470 0.576757 2.056458 2.140770 1.675297 1.723524
+1 0.024157 1 1 1.792514 0.479701 -0.569486 -0.485271 1.193746 -2.069313 -1.513194 0.514495 -0.110500 -0.495569 -2.240564 -0.455225 62.291872 -60.507187 55.715397 -41.327854 52.760996 0.685998 2.071643 0.849703 1.704341 1.606605 1.460063 2.283912 2.205367 0.599024 0.544571 1.097938 2.296035 1.205960 2.078715 0.462246
+1 -0.039722 1 1 -1.903999 1.318802 -1.970260 -0.209733 -0.118214 1.810288 2.327521 1.102731 -0.221475 0.450862 0.111571 -0.358986 -51.580681 -66.507339 11.158381 38.909080 -55.098661 2.227191 0.651949 1.301091 1.189497 2.126767 0.314616 1.759008 2.399891 0.708850 1.394531 1.137976 2.462858 1.497144 2.249948 0.625206
+1 -0.039311 1 1 2.345186 1.122882 -0.842445 1.763886 0.000441 -2.010298 0.752199 -1.128306 -0.779680 1.066218 -1.289401 1.315119 66.657320 -40.427282 38.664090 27.360817 -46.752602 0.310152 0.981795 1.030563 1.672715 1.072264 0.546569 0.941435 2.192127 0.821671 0.825851 1.331834 0.378802 0.525439 1.309869 2.463304
+1 -0.004378 1 1 0.216323 -2.220922 -0.204391 0.134487 -1.630596 1.820031 1.147373 0.795005 2.031404 0.554762 -1.935120 1.350510 -49.666903 -1.631171 34.902139 -49.750397 -54.921093 1.992734 2.129277 2.008070 1.131490 1.451362 2.286887 0.463154 0.737415 2.236153 0.518658 2.089251 2.037239 0.875366 1.026410 1.619856
+1 0.026879 1 1 1.416968 -1.432871 -1.956209 0.340551 -1.919006 -1.142041 -0.720772 1.542777 1.886978 0.057161 -0.619891 0.579679 68.403699 60.973227 -22.977038 74.923011 -18.954761 1.785014 0.729207 1.530006 1.062507 0.798019 1.548712 0.451381 0.866841 1.747649 0.491095 2.331727 0.335812 2.494327 1.652975 2.302681
+1 -0.020253 1 1 -0.207136 1.121334 1.418392 -1.065495 -0.691085 0.973819 0.857277 -2.233673 2.257400 0.681374 0.744937 -0.653892 -21.592562 -56.183532 -26.630341 23.866534 24.836542 1.041478 0.612196 1.428215 0.259103 2.489479 1.171502 1.185805 0.825658 0.334955 1.585862 1.579052 1.881538 0.766122 0.962553 1.627419
+1 -0.026354 1 1 1.659030 0.111789 -1.412532 0.591297 -0.500377 1.781410 2.350143 -0.392666 -2.196009 -0.892478 -0.350199 -0.020349 63.707997 40.311326 -37.535692 37.631395 70.854190 1.320462 0.501105 1.819266 0.409189 0.490127 1.820109 1.066915 0.639278 2.096840 1.335937 1.834494 2.088326 2.238165 0.582853 1.002315
+1 -0.010190 1 1 0.143165 -1.850452 1.220949 -1.969785 -1.644560 -1.958407 1.094999 1.770894 -0.028961 -1.371089 -0.304318 -1.726300 8.366108 59.173681 32.053395 71.410013 38.085951 2.283650 2.307155 1.347839 1.627038 0.628026 1.976941 2.195663 1.751085 1.981281 0.884039 0.546486 1.784836 2.247384 0.277337 0.701566
+1 0.000167 1 1 0.752464 -1.392748 -1.477758 2.332308 1.452551 -1.855689 -1.983299 2.131574 1.786981 1.728686 2.147177 0.130938 -0.305582 -35.916887 -55.115437 74.853313 9.633812 2.357062 0.896918 0.996559 1.668187 1.469033 2.290017 1.313071 2.283159 0.810670 0.426997 0.538950 1.136346 2.060608 2.139692 1.553394
+1 0.016294 1 1 1.515032 2.102241 -1.133708 -2.040557 1.128429 -1.852036 -1.839729 -2.339813 -0.345108 0.716678 0.334443 -0.889191 -52.580790 74.657354 16.152448 -25.805791 -67.930547 0.494459 0.373158 2.409537 0.832307 1.826091 0.355294 1.423193 1.354428 2.120852 2.155577 0.779269 1.423591 1.293984 0.986232 1.343400
+1 -0.019618 1 1 -1.809344 -0.602436 1.788101 1.707971 -2.006706 -0.148292 0.511124 -0.230731 0.400171 1.102617 -2.134746 1.460088 72.956485 -70.360949 43.523034 -58.363710 -68.874923 0.912573 0.864318 2.084625 0.793082 1.834040 1.213661 1.007666 1.598824 1.180916 1.912546 2.151537 0.373674 2.094776 0.393089 2.154146
+1 0.020483 1 1 1.826511 1.670385 -2.253786 -1.198230 2.101204 0.291284 -0.559440 -1.286659 0.277597 0.303694 0.664917 2.180008 18.341354 13.132735 71.873405 26.316139 -54.652451 2.218942 1.513335 2.118276 1.608564 0.638086 2.304762 1.639432 1.940105 1.849153 0.969102 1.444876 1.279089 0.404503 0.474136 0.810550
+1 0.004707 1 1 0.786266 1.239764 -1.463311 0.090806 -0.632587 -0.747864 -1.414474 0.945286 1.966662 0.991837 2.077636 0.029547 57.075108 11.333850 -11.985848 3.847189 9.703649 1.963488 1.086836 2.453022 0.441153 2.213374 2.420657 0.984240 1.617587 1.535011 1.938126 2.338156 0.390170 0.343476 0.803483 1.134612
+1 -0.003940 1 1 -0.369655 -1.860018 0.666103 -1.447001 0.898174 1.826122 -0.161335 -1.940838 -0.504401 0.118427 1.771732 -0.083785 26.595904 -2.638280 58.423588 25.250528 35.622663 2.276423 2.336881 1.461481 1.366856 1.741852 2.048929 1.606793 2.366554 0.664052 2.226987 1.712318 0.679736 0.317432 1.833662 1.609528
+1 0.017158 1 1 0.359574 2.072934 1.112660 1.719902 0.592287 2.002822 0.828131 -2.001598 0.881200 -0.709804 2.091396 0.377766 48.752264 -70.700668 33.877127 -27.133671 -35.606692 2.249810 0.554771 1.540693 0.670937 0.933215 1.300202 1.987273 0.353283 1.385800 0.642519 0.322185 0.716085 1.484566 2.348452 2.434582
+1 0.005680 1 1 2.029573 -1.955388 -0.011349 -2.242386 1.902725 0.829652 -0.000693 -2.228128 1.200195 -2.051790 0.824632 0.458438 6.901228 38.930784 9.693889 25.194549 -5.212187 1.356652 1.247590 1.990959 1.552011 1.903886 0.614643 2.061323 0.648780 2.048379 1.359728 1.201226 1.263437 0.577228 0.969792 1.793931
+1 -0.046041 1 1 -2.131751 -0.045975 0.132815 -1.459137 -0.438085 -2.148752 1.671395 0.583590 1.919516 0.293325 0.758603 -1.882110 52.402136 72.698164 -61.953206 52.466282 -49.192861 1.608880 1.444851 0.863351 1.584312 0.280520 2.450879 0.427642 2.373197 2.066455 1.403861 0.442217 2.092092 0.290416 2.272171 0.631281
+1 0.005565 1 1 -1.028468 -0.410911 2.182975 -1.391085 -1.801166 0.181103 -0.406335 -1.028756 -0.540283 0.239750 0.388770 -2.027215 -26.589521 -40.075111 -42.385496 -23.032016 50.913290 0.619962 1.450547 2.099489 0.860267 1.501423 2.161472 0.853767 0.254807 2.292983 1.671884 0.599753 1.554944 1.692456 2.107802 1.079512
+1 -0.046395 1 1 -1.770089 -0.570003 0.238861 -0.421079 0.933564 -1.842695 -0.354999 -0.579689 -2.331047 0.902195 -1.273737 0.682410 -21.822905 -27.559698 4.162337 56.400183 67.879553 0.649620 0.414336 1.491704 0.812353 1.716704 2.393698 2.376100 1.369042 2.492296 1.270122 0.447034 2.058017 1.335689 2.171630 0.592852
+1 0.031472 1 1 -0.892677 1.027493 -1.828626 0.483952 0.193745 0.007963 1.881028 -0.978988 1.817997 -0.050992 0.637051 0.376559 2.579043 -4.025805 -11.702455 -33.165746 -16.689496 1.369665 1.711642 0.566628 0.569943 2.277466 1.868326 1.453620 1.996529 0.667229 1.616752 0.998948 1.326777 0.885060 1.952112 1.148158
+1 0.002330 1 1 -1.187009 2.192567 -0.405950 0.745578 0.688670 0.856525 -0.736770 1.271541 0.100400 0.382016 2.263959 -2.185601 -10.494196 24.048403 -68.498245 -0.005197 62.661828 1.485125 0.494456 0.329786 2.459999 0.706512 0.351722 2.142456 0.756122 1.644926 2.022307 1.914720 0.444913 2.400953 0.568304 1.734025
+1 -0.025647 1 1 1.310758 -0.516419 0.759094 1.661290 0.392181 -1.243940 1.974537 1.394254 -1.480128 0.194557 -0.481060 1.286703 14.667581 68.041587 -25.041605 25.751865 61.587681 0.687215 2.277487 2.218875 0.379805 1.625614 1.450625 1.160891 0.595123 2.490420 1.244877 1.397602 0.993987 1.182965 0.351572 1.864108
+1 -0.012737 1 1 1.138469 1.940946 2.329157 0.329929 -1.373412 -1.647655 -2.133301 2.173592 1.116769 0.100184 1.464550 1.883919 15.717785 18.810698 -48.592599 54.190115 -26.731063 1.090255 1.414117 1.823056 1.099356 1.382800 1.965770 1.202919 0.460395 1.604984 1.209483 0.530141 1.573253 1.165231 1.529996 0.889777
+1 -0.007148 1 1 1.636394 1.377418 -1.701925 -0.050020 -1.877956 0.783561 -1.817126 0.549418 -2.208068 -0.930604 -0.239116 0.851670 -70.835447 18.650375 -43.152446 -13.157276 -34.342631 1.426064 2.352392 1.152392 1.756719 2.183962 0.858145 1.845803 0.912809 0.325343 2.036311 1.030613 0.263596 1.505298 2.043597 1.978909
+1 0.035032 1 1 -1.096627 -0.860858 -1.400975 1.619539 0.839257 1.205395 0.520725 0.913656 -1.858923 0.214287 1.254673 -0.656281 50.493604 -53.998692 -56.014844 -41.489336 38.733447 1.270721 1.500589 1.646452 0.664645 0.935521 1.800467 1.704475 1.610071 1.214248 1.863345 0.984477 1.101610 1.010488 1.771896 0.761124
+1 0.036223 1 1 1.864402 2.321267 -0.331836 2.308165 0.936422 -0.932315 -0.732545 1.594192 -1.057668 -1.103956 -1.520569 -0.915695 18.539811 48.595917 1.576288 -57.336412 -53.073959 1.914620 1.021621 2.141657 0.828109 1.033182 0.685705 1.652036 2.268187 1.171342 0.750241 1.804421 0.657881 2.003643 0.980905 1.819464
+1 0.030641 1 1 1.914939 -1.235215 -2.177751 -0.330412 -2.046216 0.266647 0.060264 -0.298948 -1.018968 -0.980600 -1.726595 0.015733 17.025934 -45.120335 62.531492 66.778472 45.777208 1.788133 1.403928 1.569478 0.722985 0.458492 1.120610 0.844362 1.946588 0.554528 1.954764 0.724805 1.801446 2.408528 1.880103 1.392959
+1 -0.054452 1 1 -0.993210 -1.606267 0.742863 2.174074 -0.204538 -2.337013 -0.413843 0.031886 -1.309151 -0.764233 1.503836 -2.276754 -25.787500 -60.518589 14.077745 54.661004 -62.499070 1.797081 1.044287 0.587498 0.331401 0.357301 1.404747 1.827103 1.614446 0.491040 1.412925 2.029675 2.001811 1.680125 1.861351 1.228111
+1 0.049068 1 1 -0.391493 -1.334090 -0.511414 0.061270 -2.256574 -0.939042 -0.695809 1.679863 1.527038 1.259687 -1.201640 1.330984 4.487438 -29.620510 18.094815 69.551534 2.625569 1.794118 0.737158 2.413573 1.165773 1.652651 1.347539 1.085663 0.732949 1.419636 2.316559 1.903188 2.374010 2.226893 2.391953 2.306776
+1 -0.017359 1 1 0.599701 -0.617882 1.368739 -1.493023 0.234638 -0.715406 2.190693 1.080025 -0.136330 -1.070929 2.226281 0.744873 -55.403463 33.998961 70.534494 23.246611 -44.215933 0.817250 0.765690 0.454656 1.902286 0.728259 1.352754 0.982532 2.169150 1.652163 2.149321 1.391245 2.151784 2.287982 0.858971 2.223259
+1 0.022121 1 1 2.343110 -0.793295 -1.565747 -1.523264 0.904993 -1.373820 0.906544 1.136668 -0.046307 -0.729196 1.318691 0.871825 61.677139 -42.327733 47.799742 -29.734256 56.362466 1.884454 0.268347 0.349772 0.874784 2.497244 1.180504 1.734454 1.461681 2.469038 1.875731 2.164927 0.422648 1.696915 0.543781 1.329959
+1 -0.016217 1 1 -2.163902 1.521994 1.314678 -0.599636 1.716121 -1.687978 -1.262385 -1.725504 -0.496641 -1.405371 -1.576798 1.236856 47.344671 -28.106443 -34.980513 -67.487421 38.912519 1.415674 0.982580 0.716043 0.777058 0.266635 0.835652 1.811048 1.790772 0.762361 0.747027 1.791215 1.452585 0.342241 0.302418 1.495649
+1 -0.004891 1 1 1.233073 -0.821213 0.465132 -0.376939 -1.761753 -1.842766 -1.538876 -2.290284 -2.005149 -2.251499 -0.464719 -2.097339 -41.649977 38.828581 -58.031766 -39.893772 5.376439 2.302147 0.442213 2.021021 0.545762 0.870240 0.379433 2.124601 2.173666 1.061691 0.595617 1.787884 1.719986 1.309857 2.267964 1.911891
+1 -0.005268 1 1 0.679267 -1.674369 1.268784 0.898601 -0.413299 -0.250339 0.709890 -0.642935 -0.306649 1.500466 2.340262 -1.533248 -62.403752 -19.854726 51.612884 7.738340 8.273102 1.315394 0.823627 2.199056 0.279132 1.614290 2.366334 1.479529 0.939587 0.383018 1.630016 1.175910 1.016305 0.542212 1.951093 2.024246
+1 0.004692 1 1 1.528625 -0.341055 -1.843724 1.193397 1.492546 1.169836 1.351114 -0.830656 1.978604 -0.934720 1.261993 -0.140885 -71.058103 26.469174 -32.591327 37.573306 -5.449374 2.310506 1.428715 1.906764 1.727121 1.970895 1.828096 0.307141 2.111308 1.509120 1.035077 1.037991 0.521022 1.311816 1.437128 1.564850
+1 -0.051326 1 1 -2.310428 -1.282131 0.983213 -1.484908 -0.045875 1.817976 -0.400659 0.119775 0.875790 -2.095633 -0.909569 -0.141664 -37.666695 -64.146590 -61.739219 48.940836 -51.370956 1.500040 1.416961 2.367421 1.746656 1.799580 0.290780 1.647119 0.630433 1.931455 0.469881 1.294919 0.951168 1.533373 1.409054 2.226616
+1 0.043258 1 1 -0.604265 -0.681001 0.811651 -0.940352 0.852998 1.250343 1.978184 1.434558 2.032183 -0.499792 2.180855 0.660244 -30.662401 57.027569 -37.648448 -57.470702 -60.087719 2.210662 1.841739 2.363434 2.238486 1.481433 1.446465 0.985048 1.706672 0.293089 2.198963 0.964543 1.316218 1.167361 1.335031 2.359237
+1 -0.053993 1 1 1.818842 0.014822 -0.642998 -1.357607 0.082928 -1.096301 -0.092008 -0.712618 1.916347 -1.127664 0.577819 -0.825736 -5.288156 71.961778 11.596279 48.666682 -9.076595 1.370142 0.721933 0.775677 1.806111 2.052152 1.769009 1.735567 2.172986 0.874660 0.407950 2.161617 1.048963 0.421726 1.941599 2.211926
+1 0.001296 1 1 -1.274024 0.570926 1.121436 -1.590210 2.003208 -2.109187 2.199721 2.026264 -1.020088 -0.946387 -1.612027 -1.818317 -19.656975 -74.771492 15.537531 -10.716188 43.035040 1.223645 2.301098 0.810412 0.602709 1.727943 2.288884 0.270517 0.823539 0.722091 1.178135 2.422504 0.518713 0.761170 0.978300 0.787702
+1 0.000643 1 1 1.964744 1.742369 1.219133 0.504893 -1.277569 2.254841 0.074333 0.538674 1.001551 0.407488 1.554689 -0.535959 70.793184 21.038526 44.499697 6.401774 44.614430 1.145884 0.381045 2.224463 2.055598 1.185411 0.959832 0.904193 1.766877 1.906284 0.416573 0.841939 1.722351 0.560632 1.045810 1.430759
+1 -0.004426 1 1 0.765529 1.432338 -2.298292 0.064861 1.553369 0.834677 -0.368729 -0.439753 -1.908583 -0.328015 0.551809 0.275700 45.055973 55.733185 -42.357809 -7.693709 -8.163741 2.005148 1.523768 1.967643 1.168680 1.006869 1.690762 0.641879 0.802811 1.102702 1.353829 1.046871 1.253515 0.320422 0.332856 2.313879
+1 0.008150 1 1 -2.264971 -0.694040 -1.573703 1.411935 -1.204319 -1.274890 0.153821 -1.827564 -0.519049 -1.026438 0.708196 -0.838551 39.020163 11.876639 -39.325265 -39.737257 -64.079501 1.612287 2.450393 1.253901 2.313211 1.890935 1.200495 2.464164 0.957019 0.860672 1.564561 1.324295 1.927430 0.320714 0.735963 0.330853
+1 0.005550 1 1 -0.745302 -0.763397 1.416004 1.219554 -1.845797 -0.657391 1.789468 1.125922 -1.576996 -2.096513 -1.567985 -1.449563 7.585961 -2.755189 43.535713 4.736194 -48.787356 0.338600 2.097086 0.975908 1.081937 1.113746 2.473662 0.830989 2.180561 2.188044 1.953286 0.627212 1.798418 1.006627 2.121528 2.265849
+1 0.016819 1 1 0.921659 0.706743 -1.699025 1.561871 -2.348485 -0.016860 -0.618396 2.151179 1.421904 1.409176 -0.451812 -1.953901 45.614557 -6.133830 -41.283992 39.953327 -54.439769 1.836977 1.079748 0.316848 1.009927 1.345357 0.421240 0.526470 0.626392 1.513358 0.259449 1.564522 0.675497 1.076331 1.395109 1.848677
+1 0.016275 1 1 1.520570 0.928124 0.964324 1.484501 -2.098965 -0.354363 0.674212 -1.818019 -0.308818 -1.969061 1.105378 1.847819 52.450576 -13.170817 38.074378 16.062831 -32.004643 1.344599 1.179269 1.221274 0.702222 2.489276 2.260029 1.304527 0.432641 0.900363 0.394102 1.169268 1.880315 0.450079 1.475555 1.651216
+1 -0.006320 1 1 1.884709 -0.377762 -1.463921 -0.739001 1.460457 -0.924179 -0.634954 1.891094 -1.454164 -1.681784 -0.839645 1.686153 -36.066607 -21.461812 41.325951 65.253415 64.147091 2.427488 1.041935 1.549321 1.678916 1.790307 1.932918 0.297418 0.705030 2.435822 1.610497 1.619870 1.652662 1.535941 1.811952 1.230969
+1 0.057038 1 1 2.126893 -1.485952 1.269618 0.774700 0.048435 -1.201199 -0.684385 0.485810 -1.567509 1.841534 -0.308943 0.645580 74.507500 47.549731 -31.677475 -53.325332 11.140504 1.951810 0.565911 2.018997 0.285505 0.738277 0.963611 1.413952 1.299111 1.654762 0.843724 2.462274 0.697551 0.496969 2.061152 2.284411
+1 0.011446 1 1 1.060472 1.103525 -1.011557 1.067787 1.521925 0.144263 -2.257015 1.080420 1.790064 1.714529 -0.169370 -0.312366 -10.502821 29.093087 -32.487560 -18.419700 20.108421 1.558460 2.284352 0.597464 1.335494 1.149746 2.286679 1.461786 1.980218 1.021504 2.413988 1.399810 2.107500 0.507919 1.600513 0.314516
+1 -0.016770 1 1 1.799994 -1.032842 1.459861 -1.517100 0.832348 -1.805449 -1.099714 -0.905784 2.218375 -0.197813 2.302313 1.551689 28.054830 67.534311 -0.837441 25.134809 40.738988 0.627505 2.228784 0.419716 1.922943 1.401482 0.954596 0.651932 1.015485 0.263879 1.760645 0.660015 1.867405 1.727044 0.671432 0.254135
+1 -0.020447 1 1 -1.582434 0.752808 -0.322987 0.232309 -2.159501 0.081401 1.512322 -1.030109 0.283778 0.521449 -1.045918 -1.540113 14.998905 -63.396116 -48.517164 -27.977979 24.105410 1.219382 0.397956 0.703274 2.171756 0.451288 1.544610 1.252927 1.693524 2.065375 1.258256 1.252345 0.907068 0.598574 1.977736 2.050156
+1 -0.046378 1 1 1.589104 -1.748926 1.686456 -0.749437 0.427875 0.192740 1.965072 -2.164510 0.722614 1.139533 0.988325 -0.396075 56.321600 -52.871914 -18.257224 50.840181 70.927287 1.748697 2.349352 1.801488 0.853920 0.591424 1.064849 1.919771 2.083017 0.760100 1.008277 0.615222 0.538153 1.244943 2.499752 0.585886
+1 -0.024765 1 1 -1.346538 2.344296 0.292048 -1.863641 1.041963 1.036739 -1.939622 1.087280 -0.734146 -1.763377 -0.858414 1.972803 16.715071 -19.795880 -9.350832 40.562904 -9.268871 2.396391 0.390973 0.338792 0.824436 2.299182 2.354144 1.345334 2.283394 0.256956 2.410144 2.032758 2.063040 0.268345 0.320735 1.086706
+1 0.022354 1 1 -0.434379 -1.116389 1.578555 0.019123 0.952413 -0.776480 -1.687348 -0.092793 0.222995 1.526145 0.377072 -0.710417 38.906156 45.756045 -28.151011 -34.043880 74.501839 0.661063 1.477828 1.599887 1.053313 1.532656 0.599269 2.412724 0.400912 0.882718 0.839552 2.104985 0.987020 1.095848 0.920579 0.425720
+1 0.003434 1 1 0.590916 -2.188077 0.468879 1.341778 -2.239891 1.433581 -0.248956 0.401756 -0.537661 1.895462 1.280535 0.472403 -22.475171 -40.201650 -69.130122 30.033951 30.615222 2.125452 0.721774 0.354148 2.415013 0.614322 1.161139 0.272268 1.009473 0.456676 2.106563 0.503309 0.612607 1.583450 1.542848 0.898772
+1 -0.029337 1 1 0.365100 0.697705 1.912152 -0.955706 1.986948 -2.058926 -1.297007 0.714792 1.627642 0.358813 -1.286276 1.998748 -52.837903 -46.633692 -22.458750 -64.209434 -67.953926 1.350370 1.409911 0.879957 1.686729 0.356608 1.018835 0.316932 2.423534 2.082190 0.360140 1.871948 1.577580 1.890552 1.505075 0.538548
+1 -0.002760 1 1 0.470770 0.136577 0.513689 0.475630 1.696238 -1.282621 2.174183 1.637737 0.375407 -0.427724 2.347506 -2.303262 43.065019 43.768970 25.079212 6.322152 56.412117 0.901659 1.939804 1.294694 1.675728 2.204373 1.901628 0.902976 1.571846 2.256566 1.609862 2.198087 1.999728 0.425769 2.398191 1.390969
+1 0.011291 1 1 1.878383 1.695935 -1.654484 0.886183 -1.789567 1.918307 -1.183029 -1.599546 0.606106 -1.353909 0.972968 0.675436 -3.037014 -43.096053 34.630911 41.723304 -6.427823 0.888560 2.273018 1.359021 0.570088 2.463981 2.376953 2.197033 2.278912 1.429539 2.264339 1.737674 1.589013 0.541245 1.462843 1.744299
+1 0.040508 1 1 -1.304556 1.065328 -2.103307 2.065049 0.537345 2.218614 -0.881591 -1.150868 1.722086 -0.391634 1.007853 -2.058290 -1.180747 -44.818361 37.811822 -46.715733 -51.321008 0.592226 1.036199 1.889132 2.395189 0.433227 1.750388 1.526587 2.104017 0.468200 2.279301 1.219733 1.796801 0.825726 1.481569 1.476820
+1 0.034195 1 1 1.595347 -0.492567 1.086105 -1.635159 0.541359 -0.994875 -1.300414 0.010146 0.884456 2.184909 -1.881903 0.419707 -13.464215 56.941682 18.846614 -44.961173 37.560243 2.499980 2.162905 2.437273 1.256464 0.386180 0.782742 1.294666 1.206052 1.358631 0.765032 0.641259 1.644394 2.077876 2.118354 0.668698
+1 0.067714 1 1 2.103322 -1.811050 -1.005064 1.805078 -0.421580 1.942380 -1.854428 0.374066 0.600510 -1.172773 1.120823 2.250622 -4.728657 25.466534 66.039789 -69.272959 29.371488 1.323936 0.393980 1.379843 1.770214 1.731701 2.454240 0.666614 0.282012 0.520861 0.859805 0.489230 2.483191 1.245213 0.303965 0.496918
+1 0.034621 1 1 1.929758 -1.925549 1.984023 0.603427 0.733685 -1.270882 1.543074 2.174569 -1.311899 0.177140 -1.036506 1.145902 -11.649320 -40.127316 -19.797406 -34.999410 64.923601 2.439538 1.073206 0.619117 0.743110 1.205192 0.417430 1.751426 0.961956 0.588269 2.036938 0.315659 1.286949 1.995985 0.516241 1.959312
+1 -0.013067 1 1 2.117347 -1.718791 -0.769119 -0.499281 1.355669 0.326309 -0.943558 -1.184013 0.712948 -1.092066 0.408409 -1.813484 16.347218 -52.314540 49.527592 60.241716 -17.483119 1.543399 1.158497 0.863420 0.498377 0.967862 0.852983 0.578326 1.424212 0.484732 1.143660 1.234461 1.842135 2.256660 0.933044 0.674651
+1 -0.031815 1 1 -0.390288 0.072006 -0.884030 0.267886 2.023004 0.741381 0.842299 0.501898 0.217319 0.380453 -0.433885 -2.231606 -22.357399 -10.801338 -38.095235 -66.607084 -15.256958 0.269572 0.697636 1.911544 1.075786 1.229470 1.202498 2.376795 1.792162 1.615996 1.797637 1.393275 0.269440 0.730128 1.257727 1.375006
+1 -0.007546 1 1 0.190519 2.344479 -1.338647 -1.701055 0.427053 0.507647 -2.105386 0.105648 -0.950720 0.960441 2.200298 2.297953 -33.296294 39.186708 -38.992264 7.024622 12.826287 1.696089 2.416501 0.890140 1.825564 0.507468 0.763515 2.142508 1.631623 1.185366 2.439477 2.291052 0.718310 0.629811 0.487819 1.275009
+1 0.010323 1 1 -2.140969 0.539235 1.003899 2.170050 -1.855166 2.104020 0.497202 1.403699 1.748368 -1.635401 1.186228 -1.181385 -71.359585 59.460534 53.191167 -16.063450 21.602224 2.403634 0.628521 1.306383 2.384174 2.066686 0.799697 0.499897 1.765092 1.143698 1.879104 0.346668 0.455838 1.527111 1.896462 1.833604
+1 -0.053305 1 1 1.866853 1.117640 0.592082 -1.436248 -2.167388 -0.517592 -0.096628 1.743681 -0.294047 1.243089 -2.130487 2.343993 -2.596977 2.608063 33.713919 -70.168484 -21.706285 1.111967 1.832773 2.423241 1.659149 0.316420 0.567114 1.988471 2.483284 0.560701 2.195999 0.651602 2.225484 1.214781 1.832657 0.472356
+1 -0.020369 1 1 -2.222371 -0.999180 1.737197 -0.897644 -2.352904 1.110320 0.088156 1.950060 -0.014755 1.763366 0.673973 -1.126828 15.952484 63.399417 -45.992313 -42.796528 -31.249983 0.348099 1.996044 1.513070 2.164312 1.347945 1.166040 1.640635 1.902923 2.424043 1.649199 1.845326 1.898203 1.856088 0.522709 0.425042
+1 -0.027478 1 1 0.404736 -2.291084 -1.319035 -1.949626 -2.117305 -2.292972 -0.063271 1.603420 -1.466145 -0.424284 -1.093784 -0.198723 36.260120 -26.165220 41.141552 -33.930114 36.575809 1.819248 2.356449 1.845406 0.995036 0.812512 2.137001 1.317594 1.806092 1.739516 1.044755 1.697564 2.455491 1.438211 1.754813 1.643855
+1 -0.028135 1 1 -2.319996 -1.860802 1.631295 0.487447 -2.330833 -0.228321 -1.509430 -2.197370 -0.210519 0.802832 1.620709 1.645227 -30.925110 -8.318435 -7.936214 -33.954888 70.198485 0.264136 1.591290 0.562590 2.455290 0.305705 0.477773 1.185037 1.423759 1.870827 0.744735 1.518849 0.300005 1.434634 2.386487 0.440394
+1 -0.005013 1 1 -2.271211 -1.883718 -1.820069 -1.781281 -0.189476 1.058613 -1.867009 0.977201 1.144726 -1.280595 -1.488545 0.097526 -25.473918 -40.135091 -0.472728 4.859522 73.979975 1.846698 2.453061 1.102982 1.574890 1.679123 0.773996 0.546252 2.349644 2.219052 1.104073 1.911434 1.463529 2.023164 0.560700 2.183179
+1 0.014979 1 1 1.591201 0.500839 1.275457 -0.053444 1.834483 -1.010815 -0.612193 -1.985857 1.550756 -0.665361 -0.219039 -1.006986 -70.535416 -38.738126 -71.681918 42.008601 -11.450474 1.403298 2.230512 2.470041 0.724938 1.777882 2.364077 1.787654 2.359176 0.416664 2.367682 1.632612 2.062589 1.680378 1.620925 1.386033
+1 -0.015822 1 1 1.227292 0.976345 0.897495 -0.162557 1.081693 -0.375613 1.667887 -1.820379 -2.287871 0.843186 1.277558 2.272738 -22.744564 -67.886967 73.747994 32.535244 69.840303 2.214615 0.783136 1.162270 1.278776 1.888925 1.166043 1.677579 1.827052 0.758967 2.207147 1.273070 0.495043 1.180199 1.103605 0.793725
+1 0.013580 1 1 1.558497 2.204985 0.958333 -0.243939 -0.112623 1.524300 -2.353331 -1.348634 0.103456 -0.087952 1.476471 -0.396067 60.761499 18.515300 -63.357943 -6.939978 59.781071 1.981893 2.175513 0.600796 1.076686 0.610622 1.975778 0.643389 1.432629 2.451475 1.440061 1.349017 1.183837 1.502658 0.425232 2.379907
+1 0.026903 1 1 1.840942 -0.834742 -0.720327 -0.405395 0.638316 -1.932733 -0.946488 1.393366 -2.265930 2.036794 1.596640 -2.333730 -56.763189 -18.917491 53.726335 -21.487270 63.461474 0.579861 2.476372 1.388705 2.215498 2.132327 1.523657 2.352427 1.741090 0.496259 1.377397 1.156406 1.714209 0.968064 2.009613 2.320598
+1 -0.024428 1 1 2.267448 -0.090140 -2.312481 1.909075 -0.825300 -2.260353 1.532139 2.158104 0.002903 1.667710 -0.082029 2.067799 -11.797021 27.467707 -50.245149 29.781489 -12.508005 0.294437 2.351571 0.846624 1.710555 0.295275 0.679544 1.592829 1.680151 2.304789 2.093418 2.335466 2.435979 2.001967 2.057208 1.249351
+1 -0.032932 1 1 -2.302746 0.594275 -2.285038 1.335410 -0.869217 -0.516200 -0.266754 -1.853082 -0.565395 2.289819 -1.100216 0.085845 25.748206 0.098245 1.207582 45.830890 29.766841 1.994492 2.426026 1.219082 2.114576 2.424047 1.715287 1.083294 1.418445 0.312465 1.592454 2.121151 0.431474 1.525485 1.582470 0.827789
+1 -0.001194 1 1 -2.092731 0.743776 -1.326243 -0.568237 1.646899 -1.137174 0.974058 0.151702 0.256256 -0.224078 -0.884871 0.265249 3.774117 -18.413346 -23.098031 -8.611905 9.706655 0.471129 2.016840 2.270744 1.390487 0.661750 1.788389 1.197118 1.965084 0.922699 2.302284 0.486145 2.391339 0.982513 1.849857 1.555020
+1 -0.009770 1 1 -1.705942 -1.590780 1.861266 1.450762 1.056728 -0.570123 -1.762518 -0.560619 -2.263388 -2.351911 -1.047274 -0.764440 -62.671041 -12.191073 4.641817 15.018124 -40.383464 1.751700 1.065123 2.018165 2.057747 1.300564 1.331264 2.054715 2.086519 1.129766 1.732445 1.458080 0.454414 2.341944 1.062042 1.983684
+1 -0.018949 1 1 2.062099 -1.921037 -2.283904 1.552356 -2.056619 -0.226663 -1.906896 -0.238800 1.439029 1.773659 -0.690224 1.308274 4.730057 -1.925207 43.050057 -57.698144 17.292831 0.484241 1.880287 2.237957 1.596663 0.862658 1.188205 0.659496 2.145134 0.762332 0.257893 2.409647 0.442257 0.511634 1.032423 1.429682
+1 0.019087 1 1 -1.461096 -0.384970 -0.083566 -0.193633 1.876651 0.856748 -1.697818 -1.715544 1.963429 -1.511570 -0.471331 -0.142133 10.976543 -17.250158 26.589706 43.181397 49.733610 2.466766 1.934861 1.459786 2.122968 1.730634 0.260825 2.189729 1.032684 1.325852 1.090564 2.109205 2.153176 0.934091 0.265157 0.745402
+1 0.006308 1 1 -0.558210 0.530143 -1.014836 -2.218785 -1.992758 -1.342253 -1.045343 -1.289188 0.182426 -1.726444 -2.174002 1.405306 15.485386 12.885026 -41.365679 17.028935 5.304571 2.183854 1.286337 0.709670 1.678217 1.300271 0.911129 1.344398 2.300162 0.814519 2.115015 0.802304 1.577179 1.900457 1.484428 2.279356
+1 0.000071 1 1 -0.448207 2.092855 1.341286 -1.082482 1.260442 2.053308 1.117226 -1.645107 -1.719148 -2.062194 0.329183 0.238671 35.049498 26.915112 -37.710285 -46.761668 -73.357508 0.330368 0.997336 1.221315 1.387841 1.192784 1.119773 0.276021 1.090516 1.296182 1.928899 0.264208 0.542828 1.052862 0.695676 0.473221
+1 0.015672 1 1 0.751415 -0.165659 0.796119 1.905099 -1.679707 1.093571 1.327765 -2.135797 -2.067182 1.314310 -2.066789 -1.500341 -7.853264 10.186400 52.820912 61.065522 28.221871 1.749902 2.348092 0.884826 0.262447 2.445980 1.335583 0.394021 2.066378 2.363643 1.247268 1.087800 0.658255 1.546056 0.809879 0.631917
+1 -0.003558 1 1 0.302951 2.323875 1.085958 0.606837 1.504274 0.365608 -0.177859 -1.629122 -1.675209 1.291780 0.967538 -1.046563 56.398465 38.993206 8.819080 22.272030 -73.991676 2.453404 2.369792 1.089088 2.049348 1.892478 2.372152 0.252855 0.988719 0.408077 2.052648 1.098399 1.036199 1.888252 1.097187 0.927628
+1 -0.043536 1 1 -0.929112 1.273708 -1.178938 1.188673 2.211423 0.780018 -0.100461 -1.413980 -0.185089 -0.606585 -1.976282 2.260096 -36.050652 -53.305748 40.291768 -66.251418 -37.585296 0.684046 0.763610 1.500451 1.583272 0.810021 0.776381 2.385513 2.071059 2.290302 1.601629 1.080181 0.860351 0.666227 0.523585 1.650281
+1 -0.007210 1 1 -0.821902 -1.689474 1.862718 2.308839 -1.870897 1.612636 -2.096387 0.553588 1.902184 1.162699 -0.798887 -1.293220 -51.184777 -12.555195 34.832332 -22.999065 4.719701 0.985204 2.074053 0.857116 0.292470 0.786812 2.196192 1.657004 0.263076 1.765365 1.230981 1.853059 1.366476 2.110301 0.320318 0.827523
+1 -0.020247 1 1 -2.252901 -0.465278 -2.067306 -0.761125 1.903446 -1.188858 -0.612040 0.586180 -1.682851 0.086570 -1.154211 2.076660 -71.331116 -62.064599 -19.708466 -40.184404 70.730029 1.518908 1.281848 1.777654 0.779874 0.340056 1.828089 2.433171 2.052744 0.470817 1.266987 1.754951 1.707510 0.875095 0.970013 1.009781
+1 -0.023294 1 1 -1.513517 -0.201799 1.280947 -2.028983 -2.269632 1.083319 -1.329612 -0.639306 -0.568142 -1.460728 1.088194 0.497067 -27.490131 -26.637967 45.684693 -27.365224 -27.322809 0.408336 1.902698 0.898920 0.897480 1.439915 1.149894 0.267834 0.729072 1.507487 0.579577 2.197429 2.185856 1.176956 0.594785 1.293573
+1 -0.054278 1 1 0.833050 0.566940 0.103684 -0.973543 -0.915370 1.318471 1.891624 -1.956789 0.008229 1.650074 0.379005 -1.205918 3.803906 32.245757 4.439718 68.333169 -74.434097 1.166995 1.931591 0.496768 0.925934 0.429528 0.323003 0.967598 0.927899 1.942145 2.385806 2.489592 0.818256 1.927797 1.986815 1.643690
+1 0.001761 1 1 1.618310 -0.975295 -2.102382 -1.236000 -1.246342 -0.698504 -1.196533 2.342515 -1.357524 1.486799 -1.162719 0.457407 54.907404 28.733047 66.319473 -18.610012 -28.466867 2.235476 0.395866 1.563748 1.169456 0.554626 1.341763 0.760493 0.860861 2.484047 2.122933 1.131687 0.272552 1.281126 0.882076 1.298748
+1 0.025860 1 1 0.422973 -2.080788 -1.165078 -1.490925 -2.196896 -1.661943 -1.942162 0.799886 -0.761292 -0.902784 0.796179 -1.805973 -15.824509 -12.515920 -55.073684 26.589843 45.485871 0.340530 0.786573 0.427831 1.059482 1.710955 0.264942 1.636564 0.972130 0.587533 0.908653 2.472825 0.275397 1.849546 0.810767 2.068486
+1 -0.034010 1 1 -2.249991 1.315381 1.783042 1.501292 2.079606 0.143723 -1.895975 -0.485039 0.389699 -0.549638 -1.479247 0.852752 57.935126 65.659576 -9.508938 -66.723859 -27.900230 1.087422 1.045581 2.086589 2.300646 2.206316 0.803518 1.724701 1.800032 1.139031 2.187582 0.946499 1.808658 2.124241 0.618363 1.584431
+1 -0.013492 1 1 1.630716 0.190826 -1.925751 -1.412413 -2.120267 -0.233917 -1.308341 -1.286375 0.339624 1.360985 0.132345 0.072761 -74.250767 67.352650 -54.007788 -58.895533 -7.219814 1.473841 2.101578 2.222779 0.751046 1.836364 2.025683 2.401121 1.138016 0.878719 1.133506 1.584056 0.484442 0.767829 0.409564 2.287506
+1 0.006300 1 1 1.044474 0.825724 -0.035385 -0.952937 1.391149 -1.832014 0.095781 -1.841766 1.123759 -0.237727 0.625964 -2.181553 55.430017 -37.696341 37.603264 48.054222 47.313934 2.204206 1.340509 2.186773 0.846390 2.279606 1.843308 1.733266 1.755731 1.313008 1.229012 0.255794 0.873841 2.400044 1.034796 0.814623
+1 0.032088 1 1 0.355842 0.615556 1.952553 -0.522956 -0.721973 0.199747 1.927925 0.251574 1.187644 -0.950062 -2.121345 0.484216 -2.487509 42.437992 5.334624 -40.982085 14.091398 1.136888 2.171553 1.534039 1.338444 1.223182 1.275135 1.441394 1.256591 0.282194 1.338864 1.540828 0.698175 1.983431 1.030801 1.166159
+1 0.063461 1 1 -1.489062 0.828185 -1.085329 0.526869 0.508936 0.695951 0.704082 0.692911 1.437785 -0.278628 1.220582 1.286147 17.162633 2.370233 -63.495003 -60.510461 0.676846 1.011309 2.066694 0.924195 0.437262 2.056754 0.370671 1.123933 0.439925 1.818071 0.567594 1.054038 2.460847 1.448358 1.301904 1.354091
+1 -0.002571 1 1 -0.886151 2.323935 2.091995 1.020514 -1.313834 0.640334 -1.003931 1.993219 -0.341409 1.629878 0.248231 1.558519 -68.151070 -15.037203 19.725768 30.976675 -25.019565 0.567621 1.498814 1.069116 1.626621 0.368226 0.532577 2.021463 1.224663 1.413159 1.468636 2.365587 2.427351 0.991522 0.265714 1.100958
+1 0.001331 1 1 2.226825 0.448301 -0.514131 1.517058 -1.549756 -1.366248 0.936065 -2.215543 0.664184 -0.716826 1.882879 1.857854 20.892220 -14.466087 18.475741 21.774771 -31.425874 1.004933 0.665835 0.691922 0.381964 1.922002 1.342617 1.613859 1.875870 2.254819 1.498627 2.425921 1.696298 1.431148 2.301194 2.424642
+1 -0.001714 1 1 2.106738 -0.945973 0.630546 -0.571654 0.777581 1.341859 -0.864971 0.155308 -0.407238 -2.063209 2.113580 0.945757 14.254569 26.533767 3.026267 12.472451 74.487201 1.470798 0.457460 1.784083 0.833721 0.856365 1.175349 0.588181 0.565925 2.249151 0.733010 2.451789 2.217366 2.016487 0.841383 1.369314
+1 -0.009286 1 1 1.437855 0.890755 -0.340875 1.182243 -2.195264 2.198792 0.544851 1.132120 -1.092850 1.364233 -1.813935 -2.356133 -42.279515 -41.815331 -40.268967 -0.528454 -31.733827 2.118493 0.761972 0.964124 1.036203 1.960890 2.432284 0.639525 1.748785 1.586195 0.436057 2.058524 0.870174 1.518654 1.512290 0.310399
+1 0.024753 1 1 2.192754 -1.975238 0.957254 0.464235 -1.310265 -0.631806 -1.750343 1.435550 -0.146876 0.744659 -0.617927 0.601247 57.269915 -14.544485 50.841126 -63.199662 -46.721849 1.313365 0.470464 2.082009 1.822530 1.267925 1.761903 1.558099 0.721054 1.754354 0.679947 1.623654 2.256332 2.172979 0.757593 1.615715
+1 -0.000383 1 1 1.617104 2.313110 -0.767624 1.061635 1.800365 0.485685 1.057864 -0.327840 -1.223016 0.204193 1.245418 -0.685359 -55.788827 7.184946 7.388482 -21.785344 3.726595 0.368256 1.034742 2.163448 0.317852 2.146237 1.296082 2.498600 1.462822 1.408067 1.380826 0.284913 2.038054 1.068593 1.842065 1.092912
+1 0.008576 1 1 -0.160472 -1.568581 -2.031937 -0.085993 1.415242 -2.170562 -2.037275 -0.254421 -1.911590 0.967200 -2.008631 0.487468 -62.896934 -58.778062 17.114880 -50.209065 36.252713 1.365228 1.391250 2.242226 1.338661 0.384074 1.384183 0.470424 1.412238 1.733043 0.258958 2.306926 2.003880 0.467587 0.984904 1.536059
+1 -0.004387 1 1 -1.415066 0.407428 0.540169 -2.145128 1.323011 -1.920638 -0.303959 -0.408183 0.914801 -1.472436 2.227596 -0.728735 -10.898939 -28.473665 -56.888965 -32.829611 -67.273369 1.922218 0.467744 1.378100 1.727479 1.244026 0.586393 2.007273 1.230261 0.994813 1.570599 1.565885 1.073368 1.089617 1.949033 1.154425
+1 -0.000382 1 1 -0.270610 -0.682764 -0.542983 1.975095 1.361528 -0.153163 -1.239212 1.328241 1.154342 0.118823 -0.996523 -0.739897 17.263956 55.315790 -7.519590 68.249948 26.869668 0.602768 0.470282 1.274078 1.680640 1.523029 0.794383 1.193947 0.409333 0.661340 1.639475 0.413021 1.895991 0.666009 1.363574 0.589234
+1 0.025349 1 1 -1.281712 -1.396650 -1.083340 0.978764 -0.863845 0.222111 0.807096 -2.100083 -0.302631 -1.659546 0.648118 -2.126575 67.337361 -10.966666 33.252146 -31.180516 49.065553 0.546318 1.224722 2.400902 1.958264 1.046486 1.534551 0.946254 2.197743 0.710836 1.027702 0.837549 2.191139 2.230635 2.282798 1.482070
+1 -0.067270 1 1 0.510630 0.896620 -0.730984 -0.451444 -0.476126 -0.614804 1.261015 2.262963 -0.070605 0.870943 1.261968 -0.562729 -0.441220 -65.582116 -38.622668 68.824078 -73.725357 2.093786 1.755794 2.374111 1.688097 0.853180 1.638052 1.248476 1.130758 0.397212 1.685751 1.923018 0.404350 2.418336 2.468725 1.104554
+1 -0.028951 1 1 -1.800890 0.107556 -1.860320 0.299292 2.074825 -0.088447 -2.120591 -0.967951 -1.187713 -0.209879 2.145026 1.669401 1.692640 -51.795570 71.859996 -49.051599 -10.222932 0.372777 0.519339 2.287323 1.041841 2.221841 0.738107 0.359368 2.391652 1.749429 1.150913 1.646500 1.477597 2.225958 2.419902 1.798953
+1 0.012095 1 1 -1.527906 -1.705595 -0.479786 -0.861862 0.572178 -1.394278 1.072078 -1.768909 0.399607 1.045649 1.722385 -0.085050 -50.203465 -19.635979 -21.902807 -20.477790 -70.213582 0.929959 0.568869 2.236266 2.425432 2.482496 0.812109 2.120932 1.255913 2.381737 1.610165 0.547133 1.413881 2.349792 2.455454 0.817446
+1 -0.000140 1 1 -1.345472 1.408897 -0.415589 -1.047691 1.647878 1.179186 -1.724854 0.999789 -0.927710 1.267665 0.933921 -0.552571 33.875756 -50.160806 -52.663857 28.561431 31.967433 1.024628 0.930947 1.427885 1.454503 1.089522 0.350687 0.500988 2.100209 1.705341 0.419202 2.272130 2.192544 1.095452 1.012474 1.394942
+1 0.024724 1 1 1.556238 1.930826 1.873054 1.658767 0.404887 0.250932 -0.178412 -1.493314 0.052010 2.333834 -1.185208 -0.516341 65.922664 62.210470 71.361681 -24.221915 2.276837 1.627104 1.728239 0.513238 0.991745 1.754668 1.450790 1.673795 1.222783 1.309288 1.707699 1.801589 0.310740 1.858605 2.318244 0.977779
+1 -0.001124 1 1 2.058828 -0.357913 2.284033 0.624797 1.767795 -0.275773 2.069886 1.725837 1.382219 -1.124365 -0.525732 -0.245963 -36.075081 -13.879036 -14.958669 -10.355100 -38.168533 2.147049 1.458792 1.165535 2.141826 1.420907 1.181467 2.162604 1.880067 0.793326 1.428210 2.419084 1.541840 1.949086 2.041988 1.936893
+1 -0.012071 1 1 -2.148129 -1.998568 -0.023409 -2.311750 0.069917 1.712472 -1.761327 0.607521 -1.136564 1.787011 2.239634 -1.035962 27.587942 20.533568 -42.320821 13.969672 38.270268 1.501029 2.294977 1.426524 1.081568 1.655629 1.905320 2.204560 0.542428 1.082736 1.043696 1.891009 2.429908 1.209152 1.724661 1.125295
+1 0.007460 1 1 0.270074 1.097797 1.669815 2.308584 -1.440122 -1.292264 0.313201 0.224827 -0.674988 -1.800538 1.318719 1.338294 15.168804 -57.910464 48.830027 36.268563 -34.269232 1.930142 0.900459 2.016890 0.865217 1.449365 2.481621 1.846273 2.064802 0.630248 1.083833 1.484099 1.247631 0.439504 1.490177 2.145820
+1 0.018116 1 1 1.363648 -2.235102 1.804202 -1.000481 -1.271817 -0.031869 1.594388 2.240406 -2.203335 -1.492590 -1.914498 -0.783179 -37.618475 -3.702965 14.259481 -40.910168 22.807606 0.286500 1.712069 0.999281 2.407896 0.250812 0.391561 1.218947 2.094522 0.625521 0.380374 2.195229 1.215700 1.512552 2.457432 0.302294
+1 -0.048463 1 1 -1.592626 -0.893589 -0.174953 0.096583 2.216116 -0.460429 -0.687992 1.119246 -0.686394 -0.300853 -0.046302 -0.651120 -38.200142 -29.778900 56.026531 -62.091492 -21.710639 2.264254 0.322800 2.043059 1.944283 2.316043 2.234818 0.592929 1.606110 2.135587 2.306127 2.071342 0.294117 1.469525 1.558936 1.286982
+1 0.048642 1 1 -0.934777 0.311388 -1.962173 -0.946720 2.211575 -1.379881 -1.991168 1.831649 -1.518787 0.749330 -2.229212 1.839956 46.177809 10.436984 64.387044 53.040731 5.568872 1.315484 2.341305 1.559626 1.629804 2.109897 0.289862 1.966503 2.260996 1.810616 1.270091 2.170251 2.163919 1.485958 1.004563 1.196061
+1 -0.007215 1 1 -0.677741 -0.954576 2.132382 1.222094 -1.566923 2.266795 -1.638572 -0.284477 1.875533 0.906968 -1.171388 0.845697 33.938560 -44.618775 -57.753877 -19.414391 -47.672558 2.384700 1.898629 2.253434 0.710815 0.673878 0.862801 1.341227 0.752158 0.275570 0.251475 0.292811 2.021396 2.353547 0.322314 0.639640
+1 -0.064604 1 1 2.040162 1.662656 -0.216127 0.811992 0.068777 1.393809 0.457054 0.508936 0.705909 -1.580471 0.756231 0.662765 -31.795877 56.699366 -3.753723 61.183666 63.874669 1.248509 1.694855 1.930599 1.822756 0.569251 1.902138 0.480129 0.280005 0.547320 2.298941 0.546584 1.190800 1.532017 1.107348 0.701017
+1 0.054323 1 1 -0.881797 0.092873 1.114306 1.113727 0.796232 -0.921090 -0.562404 0.730684 0.119965 -0.652228 -0.984905 1.327538 -39.055712 -9.344799 -8.036699 -72.801241 -20.451587 2.427549 2.071588 2.173804 1.126315 2.218963 1.856206 0.255890 2.488828 1.485703 1.204241 2.436646 1.952981 2.242683 2.274818 2.356974
+1 0.038512 1 1 -2.086490 1.962405 0.131978 -1.379714 0.822218 2.289188 -2.269033 1.729570 -1.837275 1.197237 0.058013 -0.439304 29.546009 -70.232111 -41.084554 -58.101158 -6.155057 2.154317 2.111092 2.379555 0.938910 0.258165 2.477191 1.645026 1.455918 2.356590 1.950725 0.331995 1.339608 0.538927 0.753008 1.056860
+1 -0.002672 1 1 -1.258366 -0.149117 0.785204 2.238044 0.525760 0.721911 -1.245689 0.844506 -0.095770 2.027424 -0.364002 -1.094974 -43.210449 61.981951 -19.348421 11.086044 23.144443 1.954927 1.214377 1.782075 0.829029 0.742220 1.984620 0.753603 2.055931 2.290233 0.437776 1.694360 0.359591 1.649096 2.357285 2.393902
+1 -0.013356 1 1 -1.148003 -1.966146 -1.739572 -1.330760 -1.088122 0.722584 0.649939 0.214845 1.203064 -0.966153 0.765499 0.919324 -26.751856 -68.440177 -74.054993 57.727728 29.920712 0.286157 0.445242 1.189123 0.337559 0.350367 1.866935 0.573078 0.969004 2.044072 0.960743 0.457300 1.339785 1.266313 1.673751 0.489583
+1 0.026868 1 1 1.385932 0.016649 1.786272 -0.747854 -1.236708 1.002490 2.049850 -0.451870 1.785866 1.835702 0.638768 0.958944 19.315572 36.810954 -68.294326 -22.730485 18.734307 1.637561 1.982585 0.311970 2.285727 1.221069 1.760320 1.939077 0.323519 0.638222 2.341862 1.927261 1.983410 0.677205 0.538891 2.387897
+1 -0.017388 1 1 1.281214 -2.249205 0.396032 2.211719 1.042456 -0.097140 -2.138248 -0.855921 1.466335 -1.101264 1.323445 0.671308 38.627286 8.797853 -34.491839 45.666486 -33.377827 1.657798 2.370053 0.974375 2.315876 1.677821 1.381371 0.456857 0.637921 1.791524 2.138533 2.319110 2.029038 0.289315 1.767617 0.842293
+1 0.003183 1 1 2.257408 0.808392 0.821007 0.782112 2.106928 2.242196 -0.386877 0.851851 0.827787 1.642689 -1.209625 -0.919830 56.104659 50.996394 -3.614228 5.667668 6.497081 1.321532 0.489107 0.416930 2.342037 0.364938 1.514301 0.357424 1.232472 2.150254 1.326369 0.781438 1.877195 2.017064 1.538912 2.237997
+1 0.008252 1 1 1.433425 1.842197 1.413899 -1.183561 -1.124360 -0.443561 0.065959 1.169414 -1.036881 -0.444470 -1.074269 -2.068984 -21.941664 -73.555042 60.401471 -32.483964 42.012002 2.060747 2.222594 2.133244 1.180395 2.150072 0.510091 2.104497 1.779223 2.399178 2.228500 2.406304 0.506834 1.361701 0.608241 2.448430
+1 -0.004510 1 1 1.534255 0.033162 1.288308 -0.829741 -1.499990 0.943533 0.776368 -0.181260 -2.233120 2.136713 -1.373388 -1.248161 54.693087 26.715076 50.282227 -6.603707 11.504020 1.345892 0.401646 1.969164 1.981371 2.400484 1.689854 1.127670 0.255595 2.040025 0.452468 1.135588 0.585965 1.559159 0.539408 2.073153
+1 0.055572 1 1 -0.960366 -0.940152 -0.492423 -1.203431 -0.487907 -0.702540 1.652388 1.578359 1.446420 -1.240748 -0.931347 1.407746 -29.374406 -45.642422 -12.186323 -65.536260 -17.926825 2.182872 0.530107 1.010089 1.817725 1.498925 0.687571 1.510856 0.949439 1.727097 1.572572 0.962368 0.774267 0.612844 1.070572 1.357289
+1 -0.031554 1 1 2.330217 -0.705233 -1.184361 -0.418884 0.128515 1.678089 -0.009604 -1.192203 -0.279669 -2.138438 0.663726 1.019686 -34.624880 59.636004 2.322066 26.957101 67.990692 1.668355 2.036244 2.158388 0.777270 1.569247 1.336518 0.351544 1.407181 2.245288 1.062039 1.933286 1.995216 1.090798 1.546633 1.518431
+1 0.010955 1 1 -2.143105 2.331475 1.592201 -1.532172 1.999854 -1.923528 -1.737494 0.612488 2.221040 2.192197 -1.907733 -0.180584 -9.211831 -23.237697 44.027902 26.947100 49.917847 1.663736 0.905016 2.108692 0.282616 1.684474 0.698386 1.018029 0.264562 1.992105 0.554821 2.376185 0.540203 1.945978 1.557060 1.254552
+1 0.031429 1 1 -1.596383 1.939983 0.277086 1.142894 0.925147 -1.939394 0.192100 0.644749 -2.204209 -2.049215 1.698727 -1.855843 4.927543 17.208256 19.157978 -61.855455 45.371065 0.647305 2.013440 1.382462 0.797732 1.228492 0.518237 1.765829 2.289311 0.696601 0.268403 1.303670 1.779248 0.562926 1.355208 1.737267
+1 -0.016457 1 1 -1.287863 -1.118320 2.110900 -1.676087 0.668659 -0.898011 0.913686 -1.350373 -0.848071 1.451593 0.883111 -1.583077 -19.765650 48.717103 -61.652201 11.454459 65.099357 1.748419 2.169249 1.072249 0.293893 2.211060 1.785398 0.437499 1.552400 1.679763 0.281606 0.458339 0.805582 0.419485 0.285982 2.007654
+1 0.007190 1 1 1.900810 1.623999 0.398504 1.353260 2.259293 -0.494765 1.857555 0.353194 -1.483759 0.417472 -0.293231 0.827386 -12.165053 -8.051583 -22.954699 0.379771 -67.182832 2.247063 1.634814 0.817664 0.983509 0.580324 1.259538 0.305373 1.657414 0.400860 2.252727 2.329307 2.409262 0.710174 1.147249 0.813888
+1 0.039966 1 1 -1.647061 -1.584268 -1.791125 -0.701755 0.718103 0.721477 0.892604 -2.254963 -2.132914 -0.749416 0.778465 2.069279 30.179111 70.324615 -54.194670 -49.823741 62.377616 1.833885 0.851000 1.010926 2.385326 1.174677 0.541215 0.944283 0.563533 0.294073 0.732522 0.994080 0.500495 0.574968 1.231781 1.798259
+1 0.006826 1 1 -1.933329 -1.538377 1.367115 -0.510479 1.647646 1.983786 1.340940 -2.172232 -1.832622 -0.702936 -0.284258 0.830986 -36.445026 68.448210 59.059863 69.117742 61.887152 1.935478 0.577438 2.250340 0.456887 1.145123 1.078075 1.463747 1.193547 0.442201 1.822564 1.826299 1.608283 0.408712 1.479379 0.666099
+1 0.026424 1 1 2.008720 1.001488 -0.646088 -1.461211 -2.313657 1.006736 -1.985868 1.364655 0.561373 0.796689 2.062826 0.877842 -18.946258 20.248070 -40.695597 29.099948 -67.166400 1.889676 0.276260 0.609881 0.763425 0.637403 2.086510 0.964644 0.765307 0.758091 0.989268 0.635578 0.656389 1.674610 1.425290 0.595876
+1 -0.022456 1 1 -1.288836 1.385475 1.762861 1.616845 -2.031865 1.125065 -1.853510 1.655732 1.234923 1.997040 -2.086885 0.043867 68.169449 23.928345 13.696667 -50.120282 28.426319 1.542272 2.468676 0.284576 0.863059 1.189957 0.855678 0.878453 1.155928 0.441046 0.412238 2.241592 1.931107 1.366839 1.464487 2.382602
+1 -0.026849 1 1 0.520077 -0.540066 -0.825044 2.039628 2.108263 1.121944 2.253215 1.031430 -1.634793 1.968128 2.061942 0.143120 66.669447 13.388982 28.627361 -59.937250 34.645481 1.173980 2.329847 2.495412 1.892808 1.174638 2.137609 0.296097 1.007359 0.930943 1.359032 0.750812 2.401700 1.876152 2.481217 1.806767
+1 0.044903 1 1 1.977984 -1.924075 -1.510369 0.867383 -2.020541 -1.761969 -0.756986 0.792242 -1.998810 0.617661 -0.370108 -0.057894 -72.497309 -12.280549 0.807312 68.487751 -26.361643 1.972889 1.592544 1.388688 1.924363 0.525262 0.572375 0.411507 1.199434 0.378747 1.852957 1.898087 2.147385 0.343355 1.019957 1.171119
+1 0.012683 1 1 0.030882 0.669165 -1.821041 0.722292 0.455731 1.836864 1.313996 2.073805 1.611382 0.395354 0.249557 0.285876 -61.235408 -33.499733 69.987636 -17.798048 -31.786056 2.451345 1.502013 0.836319 1.770391 2.465338 0.440792 0.639088 1.148492 1.458821 1.646710 0.499463 1.230622 0.314890 1.858319 2.014542
+1 0.004655 1 1 -1.112798 0.683928 1.255682 2.166970 -1.794207 -0.661966 0.295633 1.851371 0.090665 1.702643 -2.011420 0.748315 -14.048566 -14.242315 29.417922 27.022499 -32.858357 2.118991 2.376140 2.035802 1.472619 1.809942 1.186373 1.380041 0.594609 0.590664 1.793541 2.295176 0.272296 1.485999 1.680867 0.836717
+1 0.036669 1 1 -1.609751 -1.259400 1.310543 0.595878 1.090602 -1.439089 1.928526 0.918515 -0.296902 0.389728 -0.068637 0.951558 -32.164266 15.188208 -31.793875 -59.652725 16.658841 0.402181 1.950803 1.641266 1.263302 0.564376 0.968915 0.554815 2.279651 0.337355 1.432132 0.837008 2.087063 1.260697 1.791419 0.370221
+1 0.007305 1 1 1.419747 -1.841205 1.129131 0.516848 1.738289 -1.382653 -1.460832 -0.655203 0.860942 -1.896515 -0.131818 -0.638600 59.680239 -4.230770 -6.548931 32.119836 -11.921273 1.962393 0.694436 2.133423 1.936801 0.312934 0.477349 0.798874 2.420268 1.193095 1.853284 0.640913 0.319579 1.921362 1.829283 2.264764
+1 0.037770 1 1 0.853706 -0.988641 -0.201905 -0.504125 0.042188 2.192060 0.494104 1.181818 0.097818 -0.598628 -0.193855 -1.858646 5.193664 -10.098019 -67.411636 -37.372885 73.926530 1.872813 0.365456 1.224686 1.799121 1.570427 0.919854 1.737932 1.424219 0.597467 1.379729 2.101325 2.467960 1.752331 0.430644 1.078825
+1 -0.006994 1 1 0.363518 -2.320301 -2.278582 1.452843 -1.661038 -0.879421 2.337616 1.121132 -1.976642 0.915831 1.701257 -1.755804 -26.002942 68.559237 -24.909871 -10.208186 31.010663 0.568143 1.275569 1.984140 1.686610 0.605607 0.943505 0.992884 0.645042 2.218340 0.384395 2.274981 0.600243 0.791462 1.599925 1.682512
+1 0.000359 1 1 0.490223 1.925129 0.381715 1.921526 1.084008 0.828388 2.311622 -2.208603 -0.509854 -1.994583 0.982909 -1.876209 59.479275 68.172789 -69.934282 14.520350 -6.484975 2.230376 2.434455 1.139671 1.694207 2.284825 1.808326 1.034758 2.421601 1.091794 0.287789 0.870683 1.075926 1.331584 0.674733 1.733511
+1 0.009021 1 1 2.147121 -0.811959 0.484769 -0.212591 -1.021217 -1.075224 0.724142 -1.442867 -0.319653 -0.283250 -1.075708 2.015392 1.155879 -73.134411 -70.042699 -7.646247 39.528380 1.427355 1.559731 1.150422 2.390242 0.548942 0.325724 1.688870 0.339533 2.026452 1.826634 0.484534 2.320004 1.305819 1.907537 1.220535
+1 -0.070183 1 1 1.712688 1.873249 0.218672 -0.434904 -0.513337 0.724505 -0.051763 1.808629 -1.998651 -1.416733 0.675442 0.006454 3.009574 31.915897 10.472960 69.038636 -67.638457 2.131785 1.413804 1.057602 1.612983 0.650613 1.360077 0.313056 0.277920 1.501669 1.809526 0.946860 1.131624 1.449404 0.885385 0.658099
+1 0.000076 1 1 0.598467 2.199260 -1.018617 0.216474 0.306009 1.883633 0.390160 -2.231714 2.197204 2.125714 2.250778 -2.233586 -31.460036 1.171966 47.239255 0.155389 61.616964 1.319663 0.577864 0.412688 0.802933 0.889361 2.248206 0.597668 0.256670 2.104997 1.191394 0.257879 2.170160 0.635940 2.238775 1.838386
+1 -0.031839 1 1 1.408395 0.564644 -0.785096 -0.422804 0.220657 -0.069937 -2.049010 0.430940 -0.129520 0.276771 0.564276 -2.251769 -9.342754 26.330845 42.510943 31.419502 67.561764 1.533557 2.241709 1.646379 1.689282 0.511338 0.558579 0.291295 1.292860 2.352883 0.408351 2.154054 2.182293 2.045810 0.926877 0.518874
+1 0.054361 1 1 -2.168355 2.072763 -1.767959 2.235999 -0.865233 0.460909 -0.669680 -2.125098 -1.318515 2.081930 1.501997 -0.203414 -73.237400 -0.974179 -23.021391 -70.523400 13.223289 0.532383 1.018738 0.922995 0.529597 1.428657 0.941279 1.830962 1.231533 2.121871 1.292432 1.899205 0.694130 1.497010 2.245478 2.001300
+1 -0.013474 1 1 -2.040700 -1.279967 -0.347094 0.333861 -1.260274 0.756943 -1.511272 -0.172271 -1.943546 1.110086 0.858715 -1.625686 -14.995108 -22.785321 -2.896980 60.456754 -3.334667 2.188879 2.485440 0.785436 1.576655 2.098944 0.699611 1.361930 2.210317 0.545452 2.412158 2.130815 0.857229 2.202765 1.872062 1.243458
+1 0.040088 1 1 1.462085 -1.855127 -1.947279 -0.375285 -2.246516 -1.533270 -2.329391 0.448338 0.113323 0.821460 -1.015623 -1.297003 25.147401 -47.627378 -73.350033 55.996930 40.396780 2.105097 0.610283 0.777169 2.132361 2.096084 2.124905 0.531059 1.260896 0.622716 0.495513 2.342723 0.642605 1.758209 2.460027 1.166010
+1 -0.016878 1 1 1.587867 1.021598 -1.943859 0.558907 1.753842 0.822999 1.274724 1.760119 -2.056805 1.364275 -1.116332 -2.180537 -1.079117 13.271469 3.575381 -58.577045 -54.396473 1.502262 0.517884 0.325409 0.905243 1.422415 1.778707 0.485334 2.259146 2.214298 2.214907 1.183707 1.561001 2.240730 0.943506 0.998571
+1 0.068220 1 1 -0.051417 -1.802060 -0.704573 0.473017 0.204425 0.435950 -0.749305 -2.067345 -1.422621 0.669893 0.992700 -2.255562 61.683146 58.638301 33.920130 -54.373948 -62.948123 1.088525 1.584192 0.512262 0.334726 2.243858 1.771164 1.950846 2.373110 0.611871 0.468055 2.092751 2.369186 2.153164 0.729418 0.571806
+1 0.032821 1 1 0.466775 -1.042345 1.977955 2.291787 -1.007283 2.212993 -1.109759 -0.090566 -0.038467 -0.912079 0.094983 -1.114198 22.650377 -15.113220 -57.889882 -55.248756 -65.841293 0.705833 2.433744 0.433534 2.401012 1.557649 2.156015 1.394495 0.525066 1.778286 2.399744 0.502842 1.758158 1.620607 0.547658 1.244837
+1 0.015858 1 1 -2.257103 -0.392271 -0.261797 1.355819 -1.858374 0.024301 -1.551734 -1.623965 0.171564 -0.506956 -0.414557 2.168083 -61.649516 56.578957 72.524454 18.500745 -7.984419 2.213160 1.088602 0.638216 2.239869 2.226806 0.934851 1.798686 1.016253 1.911780 0.541847 0.325723 1.672053 1.197710 0.669516 1.802163
+1 0.067158 1 1 -1.138625 0.140986 -0.772484 -0.510860 -0.056135 -0.980322 -1.759351 0.827435 0.446795 -2.256354 -1.942467 0.384281 -65.803535 -10.017814 -69.403274 -60.819557 55.697677 0.787824 1.205978 2.379412 0.775604 0.574849 1.481361 2.489609 1.114850 0.782470 1.222808 1.743076 2.386914 0.859980 1.182277 2.281889
+1 -0.020116 1 1 1.284198 0.778765 -2.313290 -2.255171 -0.913921 2.121227 2.231183 -1.696607 -0.208763 2.053389 -2.235511 -0.362876 -32.850971 23.722855 10.024395 30.001611 -62.927297 1.838694 0.677265 1.547254 0.696712 2.139307 1.826348 2.426025 1.200275 1.029271 2.454458 2.079020 1.093622 1.759521 2.014252 1.530539
+1 0.006174 1 1 2.106433 -1.355123 -0.585373 1.104650 -0.955965 2.341085 -1.832555 0.415809 0.032723 -1.375150 2.121211 1.968370 45.253574 -73.174021 14.235375 3.941392 -57.024980 0.342381 0.403405 2.276443 0.426477 0.800531 1.026292 1.894388 0.735320 0.769587 0.691257 0.452698 0.497156 0.705439 0.314256 2.443087
+1 0.024173 1 1 -0.285073 1.281541 -1.464423 0.256537 -0.217593 -0.279541 0.007809 -0.702663 -0.412315 2.143876 1.197830 0.595503 -15.883501 45.990707 15.813164 -28.159088 -19.789516 0.589071 2.013288 1.087668 0.680921 2.246546 1.946617 1.035597 0.786642 1.583849 1.493093 1.661885 1.308628 1.869667 1.495624 1.453704
+1 0.013959 1 1 2.307164 -1.736576 1.906030 -0.183246 2.086495 -1.885840 0.209426 -0.332538 -0.079197 -2.172392 0.192145 1.402393 -43.044875 -5.208454 61.521183 36.530417 16.712253 0.367613 1.477597 2.215815 0.696929 1.284456 0.597135 0.304949 1.281182 1.818822 1.938149 0.464873 0.362949 1.838956 0.583595 2.236010
+1 0.051039 1 1 -0.948032 -0.993571 1.757467 0.499509 -2.228498 -0.305055 0.016526 -0.280201 -1.661150 1.959197 -1.945307 -0.217184 60.291147 63.312197 -11.910407 71.795316 63.876277 1.653700 0.984992 0.757142 0.786712 0.511050 2.466612 1.597522 1.803559 1.920491 0.686896 1.407891 0.674923 0.435398 2.241941 1.043518
+1 -0.013067 1 1 -0.645411 0.500176 -0.436911 -1.255632 -1.335896 2.135940 -0.231832 0.750860 -0.075141 0.033293 -1.215468 -0.167919 15.961772 69.506135 -10.385562 49.861304 -31.056105 1.975737 2.216099 0.968212 2.244695 2.336969 0.688675 2.065332 0.535093 1.562067 2.158594 1.982396 1.635423 2.057120 2.021910 1.991400
+1 0.001741 1 1 1.281576 -0.883069 2.283592 -2.071006 -1.683694 0.054760 1.435131 2.246817 1.882489 0.016175 -1.458539 0.176043 -19.968357 -58.174221 -34.132351 -62.426535 47.226853 0.500706 1.867314 2.437953 1.423473 1.567301 2.381694 0.873990 0.392398 1.782657 1.613108 0.504418 1.250023 2.390814 1.155220 2.029567
+1 -0.032594 1 1 -1.510243 -1.721625 -1.282513 -0.721379 0.763680 -1.371090 -0.320287 -1.518305 -0.571756 -0.947265 -2.236144 -1.570455 -17.461872 68.313312 41.842083 39.885663 8.342602 0.836625 2.408952 2.263784 1.416087 1.170867 1.766752 2.046528 1.742139 2.376334 0.791626 2.113251 0.413212 0.601805 2.280175 2.398836
+1 0.025134 1 1 -1.772686 -1.807301 0.742936 -1.307268 -2.090293 -0.687443 0.918602 1.151632 1.700559 0.660061 0.680979 -1.170613 -8.661459 -73.141909 -46.059767 23.504187 -65.127475 0.662893 0.735482 1.251903 2.486356 0.427066 1.690600 2.421871 1.133769 1.506604 1.502379 2.490111 0.552061 0.996324 2.223697 0.423809
+1 -0.014406 1 1 1.984008 0.363959 0.380923 -1.955861 1.470944 0.960316 0.092408 -1.993825 -0.417329 -2.018765 -0.182065 -1.632864 44.627019 46.301744 -6.583447 52.009780 -71.622915 1.129977 0.778383 2.290097 0.402472 2.344453 0.477708 2.331249 1.307577 2.202014 0.502705 1.707904 0.750641 1.770708 1.040576 1.211445
+1 -0.057983 1 1 2.122978 -1.318167 -1.496267 2.253167 0.217432 2.274029 2.132749 -2.023990 1.529990 -0.960095 -1.095464 -0.152290 -22.583233 -56.390466 -54.554183 57.844307 39.271040 1.800442 1.283207 2.108433 0.435471 1.217356 2.355580 0.740227 2.251692 0.690498 1.193312 0.987498 2.370526 2.178967 2.403371 0.709812
+1 -0.026955 1 1 -2.083699 1.747880 -0.406148 2.123381 0.739965 0.596371 -0.037818 0.565763 -0.817724 -2.157844 -0.343763 -0.227763 -49.222169 -27.002034 -73.190324 40.229491 -62.944173 2.084227 0.847751 0.393773 2.389110 1.772871 1.384685 2.155099 1.757849 0.917807 1.087048 1.511058 2.097706 2.388358 0.381607 0.424863
+1 -0.021700 1 1 2.137268 -1.477626 -0.165162 -0.274988 1.128335 1.279195 1.515241 0.905265 -1.515929 1.673282 -0.693971 -0.402808 54.197973 -44.669300 -6.922768 49.034287 19.263958 2.415242 2.228232 2.393297 2.392257 0.664204 0.272856 1.882690 2.118513 1.088784 1.436197 1.664346 2.158437 1.593392 2.132488 1.976108
+1 0.055435 1 1 -1.807461 -1.934433 -1.240023 1.828696 0.696458 -0.201062 -0.460624 0.739637 -0.207589 -1.781629 -1.315664 -1.842820 72.128550 -35.454921 59.149626 -72.236884 14.695897 0.534024 1.589790 2.353231 1.749542 0.803390 1.825500 1.675146 1.422601 0.410192 1.602241 2.371761 0.440421 1.158748 0.578601 1.541079
+1 -0.043457 1 1 -2.053447 1.247103 -0.639554 -0.017098 0.086294 -1.078157 -1.442954 -1.772797 1.034378 0.784273 0.724914 2.100710 45.230512 -10.781219 0.047354 45.875425 28.271405 0.737682 2.220351 0.442637 2.403557 1.581488 2.324905 0.436548 1.314923 1.916509 1.269783 1.499025 2.359630 1.302950 0.931796 2.190544
+1 0.010932 1 1 2.177959 -0.885852 -2.078882 -2.120890 -1.288993 -1.254865 2.131413 -0.930773 1.636284 -0.473819 0.469187 1.791829 -51.282964 -12.780764 -6.294591 -43.188103 -12.454459 0.293715 1.463529 2.036388 2.326677 0.967272 2.196766 2.287406 2.432151 0.653563 1.428864 2.168066 1.427967 0.589865 1.856477 0.309980
+1 -0.015151 1 1 -1.651743 -0.159490 0.803248 -0.806214 -1.922062 -0.665029 0.649722 1.264112 -2.226291 -0.906854 -1.623932 0.729314 20.758594 -10.302618 -56.096020 -55.809809 -45.454817 1.238262 0.462516 1.254211 0.774657 0.417917 0.939254 1.539960 1.853368 2.060542 1.024740 0.548558 0.606038 1.430341 2.249828 0.862935
+1 0.026739 1 1 -1.138252 1.699530 2.211370 -0.114344 0.882720 1.276496 -1.437166 1.252418 -0.846574 -1.660344 1.367904 -1.381735 -5.117216 -55.058288 -14.638693 -32.510074 53.188652 0.499989 1.066474 2.221753 1.494096 0.519069 2.241474 2.211820 1.065511 1.792106 0.669107 1.685263 0.472158 1.315929 0.820375 1.542651
+1 0.007158 1 1 -2.027026 2.337234 -0.582243 1.877679 -0.715805 0.201307 -0.134049 -0.445073 -1.778128 0.973827 0.982451 -0.163742 0.524809 -29.529035 55.512662 1.307718 -71.178447 0.682657 2.172548 0.265298 0.861163 0.814603 1.279062 2.188137 1.268879 2.045005 0.903774 1.473004 1.529275 2.275702 1.467506 1.368870
+1 -0.000965 1 1 1.992943 -0.269448 -0.008053 1.318654 0.253664 -1.383963 0.080157 -0.547562 0.424612 1.888856 -1.358998 0.266884 -21.407241 58.507947 -56.931852 -3.638220 52.438645 0.419606 2.310492 1.189615 1.861567 0.356725 0.730039 2.022609 2.494519 0.374761 2.352588 2.190230 0.452674 2.340803 2.131941 1.780322
+1 0.014723 1 1 -2.322554 2.257160 1.358698 -0.604338 -1.912528 -0.648349 -1.755213 -0.302504 0.479436 -0.308031 1.840650 -1.033818 -25.746437 29.641567 35.810473 66.613185 -32.198039 2.088465 2.333375 1.038759 2.165137 1.711613 2.328762 2.247497 2.175200 2.089040 0.741917 1.401951 2.082271 1.736045 1.208370 2.076742
+1 -0.004564 1 1 1.073325 0.353819 -0.393536 2.039307 1.434308 -2.173641 -1.943123 -1.210805 -1.902091 0.402268 -1.354843 -0.588735 36.341964 -0.617038 -20.559313 59.629039 35.259930 0.829671 0.279167 2.216106 1.096091 0.506384 0.550131 2.302506 1.965608 0.718718 0.747574 1.968635 2.096020 1.049996 2.039315 2.025721
+1 0.007237 1 1 -0.343116 1.220759 -0.444717 -0.507587 -1.596282 -1.080716 -2.047044 0.485628 0.090588 0.418746 2.260451 0.124035 56.692557 31.797366 -31.661246 69.445550 21.363100 0.619411 1.185680 0.968578 1.646444 0.537277 2.256672 1.140553 0.767565 0.472858 1.817710 1.247499 0.470358 0.312077 1.834626 2.063212
+1 0.010291 1 1 -1.910712 1.592977 2.075137 0.429060 1.253704 1.919395 -1.743975 0.063917 -0.176216 -2.280513 1.990795 1.326659 -59.223671 27.763169 -34.426767 -60.679022 17.675962 0.323428 1.347652 0.733262 2.181022 0.936167 1.409508 0.846297 0.710985 1.270391 0.458651 1.541752 0.474340 1.981955 0.959216 1.796085
+1 -0.004185 1 1 1.039707 0.822990 1.137601 1.489174 1.050601 0.133444 -0.308576 2.106536 0.381340 0.327319 1.884008 1.985326 -33.505089 -20.026567 13.485403 -0.838750 3.129015 0.465448 1.028535 1.336157 1.045519 1.045560 1.735987 2.486582 1.976895 1.424233 0.834383 0.725883 1.907836 1.745428 1.415758 2.403653
+1 0.009707 1 1 0.927489 -0.270879 -0.490977 -0.454890 -1.847394 0.783694 0.418962 1.190751 -0.555505 -1.130887 -1.758370 -1.525886 -23.573284 -46.182066 68.010435 51.384858 -74.698899 1.909000 1.067495 1.393280 0.359318 1.560087 0.379248 1.263121 2.017345 1.776280 2.429232 1.097101 1.734773 2.325817 2.265383 1.285425
+1 -0.007961 1 1 2.020508 1.206690 -1.283188 2.064733 -0.057611 -2.236491 2.021757 -1.373455 2.337996 -1.907650 1.217571 -2.185906 -23.573035 -41.996915 57.842645 11.330901 -61.540853 0.368203 2.393869 0.749908 0.702928 0.866382 0.784639 1.679160 1.385920 0.407062 0.740773 2.426242 0.342449 1.532815 1.014459 1.008214
+1 -0.028861 1 1 0.486181 -0.043339 2.029912 -0.968757 -0.592326 2.057255 1.486317 0.157482 -1.563947 0.454731 -0.824369 -0.745931 -60.789351 -36.628837 -20.864702 26.946986 48.000778 2.111018 1.122161 2.163445 0.262594 0.423683 1.094704 1.949343 1.859743 1.196732 2.222313 1.910580 0.615780 0.919401 0.875647 1.253617
+1 0.007667 1 1 0.186879 -2.295653 1.997696 -0.500391 1.536004 1.160537 0.560113 -1.526745 -1.048919 -0.135436 -0.184699 1.220009 34.568661 45.484870 64.207852 41.373229 -40.147836 0.404752 2.418397 1.252744 0.877124 1.316714 0.509500 1.160719 2.205573 1.818273 1.720685 1.808345 1.350563 2.418659 1.149953 1.258587
+1 -0.037557 1 1 0.356661 0.250011 -1.523329 -0.182957 2.239581 -1.927484 -2.257391 -0.521016 -1.092227 -2.305766 1.671598 -0.723327 31.811664 58.632161 -69.268201 -40.649279 57.560332 2.372609 1.191265 0.344502 2.297455 0.329371 2.231333 0.519470 2.225494 1.376259 2.286071 2.499166 1.984892 0.831078 1.430154 1.347670
+1 0.016035 1 1 -0.652046 2.076763 -0.512731 1.486526 -1.044251 -1.797137 1.939202 1.283990 1.989903 0.474656 -0.538246 1.481745 -41.216736 -29.688466 -74.044035 -58.099803 16.612634 2.253010 0.332734 0.266037 2.036465 1.370699 1.089586 1.425244 2.073531 1.083143 1.139129 1.594515 0.758933 1.644828 0.381646 1.069347
+1 0.022334 1 1 -1.697923 1.239175 -1.937993 0.192217 -2.111183 1.643859 -0.394545 -0.788480 -0.741786 1.789608 -1.236895 -2.152524 -14.494932 -16.317355 -45.781965 42.518471 7.949587 0.755700 1.302328 1.723914 2.064014 0.879421 1.671844 2.174189 0.844609 1.596649 0.637065 0.894346 0.524985 0.419744 2.379905 2.314087
+1 -0.002539 1 1 -0.936963 1.258908 -0.155716 -1.747522 1.718843 1.657358 0.292358 -1.362362 0.285252 1.726501 -1.581954 -0.606745 1.437686 13.195649 -70.719149 23.257922 -4.099727 0.563227 1.899472 0.669788 1.880378 1.505477 0.543593 0.412322 1.396147 1.294487 0.448184 1.131088 1.438481 1.793970 0.509067 0.643331
+1 -0.001248 1 1 -0.551893 -1.684403 2.272648 -2.226326 -1.498792 2.233160 -1.463932 -0.924697 0.080843 1.560206 -2.064760 -0.385181 34.787054 -33.979253 -39.304155 15.061410 -62.876266 1.203912 1.406664 0.305136 2.178409 2.023990 0.950870 1.015736 2.218089 0.670253 0.693919 2.453185 0.928665 1.316679 2.178057 0.606709
+1 0.023902 1 1 1.685092 -0.120660 -1.611693 -0.912934 -0.151178 -0.869856 -1.842646 0.469806 -1.941127 -0.646718 2.087598 -2.185596 -7.791751 -5.953352 -7.980491 -28.114643 -22.811094 1.584231 1.162046 2.009587 1.875733 2.198367 2.200732 1.459555 0.491132 0.711173 2.176846 0.496871 0.413148 1.773709 1.969667 1.443394
+1 -0.042941 1 1 -0.684647 0.796611 0.746916 -0.386402 -0.585299 2.348090 -1.914808 -1.271254 0.001496 1.581698 1.017457 -0.860389 56.109621 -15.596424 70.901571 42.707365 32.683015 1.426570 1.866715 1.375189 2.297946 1.829782 1.651260 0.482528 2.344878 0.858553 1.954814 1.551493 2.190701 1.615304 1.405563 2.047096
+1 -0.025680 1 1 -1.301113 -2.319534 1.192598 2.210082 1.802498 -1.358299 -2.110551 -1.876478 2.055884 2.005447 -2.173520 0.088904 12.085882 27.420108 49.752386 -61.654049 -19.596661 1.958873 2.286681 1.503273 1.762033 1.485317 1.468338 1.848936 1.810147 2.391430 0.262377 1.264764 0.383179 2.082854 0.283930 1.253227
+1 0.026229 1 1 -1.355338 0.515049 -0.237530 -0.780827 0.647829 -2.266864 0.477672 -1.670964 1.947503 -0.578055 1.575089 -1.685954 -7.446248 -49.085154 25.808899 -29.828438 -26.561414 1.109727 2.434922 2.237339 2.462441 1.236905 2.406583 0.698206 0.255354 2.489932 2.034984 1.231688 2.488583 1.859977 0.638457 1.801813
+1 0.005923 1 1 -0.928166 -1.679776 -0.078098 2.157185 -1.313394 -1.388792 -0.958783 2.106548 0.571166 0.445107 -2.354346 0.440742 -10.559445 -22.586763 34.281351 16.665908 53.919142 2.410202 0.770219 2.317308 0.997451 0.916530 2.111817 1.062096 0.640125 0.575003 1.825181 0.809125 1.458535 1.338517 2.457015 2.306089
+1 -0.060243 1 1 0.226053 1.091103 2.258141 -1.002627 0.358553 -0.948478 0.946930 1.310329 1.707585 0.929173 -0.249710 1.870188 19.428973 -7.254863 17.523262 63.469035 74.073762 0.740817 0.910216 1.752181 2.400042 1.005793 1.618464 0.533583 0.933940 2.221982 0.856914 1.401705 2.454521 0.884858 0.810661 0.273426
+1 -0.002929 1 1 -0.785925 -0.216178 -0.056074 0.045594 -1.822248 -0.712349 1.722532 -2.321182 1.769416 -1.311758 -2.162332 -0.370697 -16.560316 70.773873 -3.519051 -44.690153 -57.408324 0.449591 2.283729 1.390287 1.797364 1.304213 1.903522 1.249011 1.125023 0.760444 2.278855 0.464865 2.482341 0.453463 2.103077 0.417946
+1 -0.008166 1 1 0.708162 -1.409431 0.879858 0.303456 1.378089 0.146164 1.430484 -0.462538 1.559801 0.551878 1.440325 0.003050 -18.537174 -4.277927 -49.120259 35.814140 -21.756505 1.951334 1.566925 0.566283 1.521225 1.983706 1.145202 2.418550 1.578602 1.067415 2.296184 1.463494 1.444116 2.007253 0.901107 1.660057
+1 -0.010108 1 1 1.840417 -0.229993 -1.335278 -1.617410 1.955903 -0.764343 -0.336004 -1.777709 -1.409097 1.772149 2.202788 1.726796 -42.657741 51.348895 70.877255 -65.971159 22.731087 1.245743 2.445920 0.332415 1.643413 1.337390 1.507033 1.958311 1.837215 0.573438 0.274377 0.455171 1.565901 1.350134 1.943304 1.608944
+1 0.039575 1 1 0.728685 -0.487051 -0.447823 -0.869136 0.835964 -2.293427 1.718568 1.742670 1.560460 2.201512 -0.871881 1.832032 6.717323 -51.945836 -53.669058 -65.865790 -6.327860 1.339925 1.362915 0.760499 0.961251 2.252140 1.461302 0.601592 0.961098 1.925349 1.335129 1.766188 1.563076 1.109459 2.422566 1.573283
+1 0.050660 1 1 -1.134690 0.297274 1.157162 0.385557 0.522768 2.262974 0.109374 0.420468 -1.782366 0.439332 -0.465692 0.394027 48.036401 47.796825 71.243715 -56.881126 -51.093033 1.815877 1.937598 2.454953 1.396805 1.106599 1.600995 1.673296 1.839597 2.350785 1.150350 1.182718 0.682263 2.297266 1.654003 1.582048
+1 0.024665 1 1 -0.532037 2.175522 0.567385 -1.835305 1.325797 -2.218551 1.952649 1.098586 0.795092 -1.217735 -0.567990 1.086267 34.585670 31.354747 29.226464 -40.825615 -56.104134 0.742212 1.859188 0.880357 1.658334 2.369231 0.660453 2.490221 2.387288 0.403995 0.943613 0.554532 2.012241 1.488321 2.466932 2.485097
+1 -0.000506 1 1 -1.139386 1.493206 -1.865517 -2.221295 -1.759578 1.721361 1.554700 -0.357419 1.161071 0.120739 -1.781503 0.795804 41.827582 -53.826302 -8.649508 -22.284011 22.619587 2.385915 2.072811 2.486484 0.334948 1.473778 1.043504 0.918818 2.322920 0.819754 2.358172 1.542364 1.761693 0.281619 0.674863 1.680029
+1 0.014787 1 1 0.060887 0.733926 -1.947763 0.905859 -0.962211 1.032208 2.020239 1.386454 -0.635824 1.412103 1.626769 -0.166389 -65.401568 -4.161647 -44.805026 -38.069529 65.423761 0.282208 1.577805 1.172385 0.267563 0.686622 1.297751 1.294857 2.170247 2.099768 1.053594 1.746639 1.505592 2.488191 2.027697 0.261540
+1 -0.007165 1 1 1.710045 -0.134676 -1.549016 1.632599 -1.155112 1.071932 0.504620 -1.159507 -2.105743 -1.180088 0.707218 1.565629 -14.593134 -16.802367 52.613436 24.013002 -63.476446 0.645702 2.064349 2.010251 1.782741 0.779743 0.396374 1.108183 1.233893 1.287329 1.643965 1.625554 0.443055 0.420277 2.338141 2.393111
+1 -0.011931 1 1 -0.649036 0.831411 1.289437 -0.712005 -1.917625 -1.492182 0.225472 0.755056 -0.229691 -0.971343 -1.651821 -1.473999 -14.908574 -68.396643 57.618573 -4.649897 -0.816588 0.259094 2.345487 2.106391 2.120186 2.215868 1.600129 0.620012 2.290442 1.708761 1.651023 0.998980 1.860322 1.927807 2.144841 0.338939
+1 -0.024924 1 1 0.677506 1.716430 -1.197985 1.512542 -2.049982 -1.773892 1.486821 -0.804606 1.550317 1.384160 -1.487538 -1.828383 -4.555125 -57.983351 23.825188 -70.060523 -7.213835 0.731094 1.753814 0.607162 2.324678 1.113932 1.109021 1.809101 0.567811 2.445982 1.366910 0.406903 0.315581 2.225458 0.781328 2.276683
+1 -0.023312 1 1 -2.017526 1.796717 0.439186 1.794486 0.641269 0.576655 -1.548614 -1.030399 0.115423 -1.588793 2.266285 -0.791590 -37.600792 -6.516159 -17.080253 32.186883 64.942069 0.345340 0.627612 1.774619 1.514815 2.242371 1.531428 2.458509 0.417347 0.349600 2.472379 1.774280 0.324571 0.312355 1.998070 1.814268
+1 0.056844 1 1 0.480462 -1.912375 1.922803 -1.015837 -0.184521 -0.491566 -0.930273 0.613896 2.337516 -0.555621 1.633047 1.668077 43.713016 -15.341231 9.929975 -56.905500 -10.733027 2.275339 2.115063 1.606628 1.847204 1.965024 2.167136 1.551112 0.291928 0.687789 0.666782 0.847761 0.574550 0.964709 1.872405 0.264757
+1 -0.005149 1 1 -0.192966 -1.052559 -0.049607 0.352042 -1.995973 1.173541 -2.355614 -2.023172 1.139624 -2.197269 1.495259 -0.355288 -23.147709 56.456935 -28.300477 3.880594 -28.854534 1.252721 0.488627 1.346679 2.389109 1.747496 2.406292 0.293744 1.949459 1.553232 2.166626 1.980651 1.548577 0.439586 0.623565 1.265252
+1 -0.004162 1 1 -2.145207 -0.004665 1.713389 -0.473575 -0.154181 0.501149 1.770872 -0.407285 1.858638 -0.301467 -0.939582 -0.332446 46.673678 -55.497574 -47.729832 4.706290 48.617689 2.387455 0.958263 1.531367 1.436429 1.055673 0.700350 0.287726 2.053294 0.709112 1.294223 0.499803 2.439796 0.901931 2.012050 0.518790
+1 0.002372 1 1 -1.567633 -0.248101 0.635710 1.390372 -0.759203 1.216238 -1.035412 0.676641 1.311349 0.006134 -0.586156 2.082935 -14.466727 7.719962 -0.607474 -9.820167 -47.547408 2.435620 0.457775 0.330723 2.465296 1.986859 2.387155 0.422294 2.496017 0.813500 0.739148 2.111422 1.176512 2.142216 1.230383 0.790154
+1 0.041060 1 1 -0.740981 1.180133 0.042349 0.196834 0.093568 -1.332207 -1.835113 -0.158260 -2.083082 -2.023321 -1.348804 1.960747 17.250695 -17.564337 -3.804110 -35.676055 -57.452261 0.622812 2.096219 2.154803 1.271239 1.208403 0.377985 0.286252 2.038552 0.447993 2.419163 0.626187 0.319853 2.026889 2.417823 0.600577
+1 -0.002071 1 1 1.812074 -0.649659 -0.217875 -0.299672 0.962366 1.562400 1.820046 1.393958 -1.741902 1.923887 -1.637526 -1.549885 37.156029 31.378699 -18.206624 1.267553 3.754942 0.764686 1.582927 1.756461 2.343615 2.131597 0.496220 0.722647 1.520819 1.900757 2.027353 1.218915 1.554549 1.807366 0.646774 2.088027
+1 -0.000761 1 1 -1.733282 0.722816 -0.176605 0.612732 1.617552 0.424943 -1.959825 0.814662 -2.184155 0.414836 -2.194975 2.345609 -38.196015 39.579558 -36.364276 -74.385402 54.555986 0.961850 1.060096 0.789743 1.958542 1.215688 1.314535 2.136969 0.793136 0.478717 1.304566 1.096777 0.782642 1.867237 1.146150 0.342122
+1 0.007576 1 1 0.480805 -0.861349 -0.236928 -0.076635 -1.528655 -0.166611 -1.066901 -0.756370 1.716281 0.993042 -1.224821 -1.851364 1.094931 -47.500882 -47.327389 18.570007 -43.896125 0.442487 2.122392 1.037736 0.729628 1.854132 1.398836 1.481263 0.835230 1.466619 2.212536 1.850009 1.857404 2.394572 1.322020 1.944386
+1 -0.039554 1 1 1.877300 2.334664 -1.370811 -0.350167 0.518370 -0.955713 1.864615 1.188649 1.799722 -0.899143 0.737347 -0.996569 -47.992236 -55.517746 63.235373 46.915933 -33.917405 0.627620 1.903572 2.080066 0.662364 0.844989 1.231088 1.403120 1.491980 0.956603 0.621335 2.025744 1.180210 1.291779 2.172535 2.289353
+1 -0.002027 1 1 -0.289842 1.232964 2.057827 1.674102 -1.039342 0.603593 -1.180071 1.000384 -0.348176 0.986862 -1.423693 1.496308 -50.001180 -69.828302 -4.274705 5.026086 23.424519 0.563273 0.421412 1.169331 0.689023 1.158601 0.357712 1.568487 2.059539 2.177822 1.160405 1.429166 0.494765 1.018851 0.571792 1.852951
+1 0.033711 1 1 0.876179 -0.279587 -0.768055 -1.458762 1.146717 -0.791119 2.025450 -0.556218 1.020320 0.139279 -1.192557 -1.518234 20.229861 -46.728158 39.854633 -63.178862 2.865631 1.564870 2.015033 1.155425 0.977790 1.223510 2.275092 2.477398 0.629948 0.536453 1.916654 1.452143 1.911086 2.376616 1.042113 2.294703
+1 0.026395 1 1 -2.107355 0.002683 -2.033029 0.406760 -1.253705 -1.926587 -1.318459 -1.680444 -1.882041 -1.911682 -0.563136 -2.145202 2.430703 52.816961 -5.340439 -56.756745 -60.604845 2.340527 1.983835 1.060446 2.163018 2.097041 2.462913 2.430086 1.961984 0.557638 2.469822 1.544746 1.296648 0.762322 2.350783 1.104319
+1 -0.045166 1 1 -1.429000 1.851110 0.411314 -0.127056 -0.720987 -2.074686 -2.278539 2.187031 0.802356 -1.656263 -0.734032 0.166379 60.159858 -43.271962 -71.859514 57.143673 -36.281018 0.999066 1.050219 1.282954 2.350919 1.154873 0.694503 1.018415 2.244144 2.080166 2.357455 0.752794 1.959908 1.673906 0.832821 1.474632
+1 -0.003440 1 1 -2.102403 -1.592786 1.126051 0.593223 -1.108771 -2.323950 -2.352632 0.970240 1.960318 -1.962076 0.692599 0.906928 -58.778034 17.576245 53.943547 29.186456 36.773827 2.240680 2.356886 2.437863 2.170200 1.302030 1.222617 0.773950 2.026970 1.540065 1.377315 2.027331 0.854983 0.448747 1.593180 0.821652
+1 -0.024131 1 1 2.130110 0.734689 1.461347 -0.118645 -0.720805 0.986060 -0.765683 0.705876 -2.145487 0.007365 1.258712 1.262951 57.587793 -71.963905 -47.344395 32.755306 18.426670 0.580732 1.363988 0.790411 1.943771 0.451488 0.407569 0.264341 0.528050 2.442462 0.709103 1.138873 1.790477 0.301953 0.426138 1.848771
+1 0.003584 1 1 -2.351888 -0.669761 1.218531 -0.196643 -1.595254 2.056428 1.726393 1.316964 0.125651 0.661087 -0.931478 -0.797769 -43.064718 -38.723310 27.332804 -67.570933 -14.672066 1.473910 1.005007 1.900267 0.535517 1.931519 1.546023 0.253864 2.194181 1.593813 2.469733 2.302655 2.215992 1.424350 0.547119 1.180082
+1 -0.012844 1 1 -0.192394 -0.865143 1.979775 -0.100757 -1.682209 1.454174 1.861099 -1.343482 1.862636 0.930157 2.155386 1.432838 44.385190 31.890921 40.702906 -56.266648 -73.556250 1.976486 1.305097 1.018685 2.296139 0.700235 0.602865 2.103811 1.505642 1.067996 0.801876 1.138135 0.629016 0.620435 0.403626 1.484422
+1 0.016627 1 1 -1.248986 1.986266 0.611638 2.085669 -1.618398 -0.511152 -0.249163 1.627573 -0.803156 2.344369 1.521472 1.963610 48.679022 48.322582 57.638798 35.280626 11.473622 0.432557 1.742937 2.289238 1.719671 0.503778 1.751816 0.771379 1.559076 1.397267 2.111589 1.731626 1.186052 0.467654 2.117801 0.374159
+1 0.027240 1 1 0.026279 -1.289111 1.470934 0.798003 0.573987 0.743965 1.848243 -0.645631 1.517321 -1.837174 -1.819479 -1.294982 55.901298 -66.886675 -64.340936 -28.108083 -62.553204 1.649621 2.178732 0.705465 0.748343 1.403622 0.919031 1.401524 1.657614 1.513943 1.085861 1.814617 1.010088 1.802105 2.232385 2.438249
+1 -0.020429 1 1 0.759450 -1.791106 -0.386312 0.919331 -0.728427 0.113073 1.317883 1.438703 1.006432 2.333192 2.173702 -1.745784 -65.685069 31.039874 -12.832947 16.666817 69.196997 2.033946 1.777461 2.031146 1.971314 2.119944 0.398747 0.489303 1.457832 0.785035 1.591263 2.349623 1.870317 1.161771 1.893882 1.222300
+1 0.040906 1 1 -0.784652 2.323268 0.307525 -0.918578 -0.753909 0.672163 1.450121 -0.289744 -1.836418 1.477845 -0.863527 0.867889 56.361894 24.355949 0.434376 -49.442033 27.750328 2.121334 1.266047 1.704891 1.846784 1.655021 0.690745 0.857672 0.639573 0.301031 0.682938 2.387411 2.469622 0.442229 2.289528 2.094197
+1 -0.004589 1 1 0.091612 -1.233248 -2.119191 -0.998741 -0.308820 -2.003766 2.155964 1.731855 -1.131462 -1.987572 1.004846 -0.762928 -3.759428 -34.714402 55.048993 8.433363 -10.472807 0.377897 1.062228 0.612880 1.674907 1.909329 2.095117 1.632481 2.108587 0.777899 0.906030 1.140419 0.771214 1.036523 0.583515 0.881359
+1 0.028863 1 1 1.202280 0.002285 0.698714 0.014789 -1.192708 0.665269 -1.318194 -1.945550 0.399619 1.235143 0.973848 1.329352 31.453208 34.073894 -20.057904 -63.192073 -69.176291 1.436059 1.586093 0.962033 1.888401 1.357380 2.232993 1.414164 0.354998 0.954192 0.605047 0.523764 2.393568 2.446400 1.641395 1.181926
+1 0.004195 1 1 -1.747906 -0.017023 1.342199 0.129627 1.516599 0.173148 -2.157156 1.807672 0.773527 -0.820012 1.800343 0.119274 59.484068 -1.266870 7.711080 0.124098 -14.284528 2.424175 1.616003 1.910742 1.094505 0.838655 0.527172 1.176651 2.218427 1.845424 1.282156 2.440692 2.462752 1.970997 1.288156 2.030965
+1 0.038839 1 1 2.133945 -0.781572 2.266182 2.185073 0.878411 -0.455780 2.049762 -1.931679 -2.088715 2.269488 1.214183 2.124630 -58.443263 -55.916194 -33.479269 -36.078653 -73.929202 2.453507 1.841931 1.091489 1.900161 1.008119 2.456565 1.493832 0.588966 0.256687 2.391501 1.460973 1.829711 0.454865 0.912583 1.037188
+1 0.026484 1 1 1.646768 1.367119 -0.434541 0.876255 1.000586 -1.672059 -2.324245 2.111481 -1.339746 -1.309429 -0.717978 1.365207 13.064842 -19.193624 62.764889 -60.516512 48.991178 2.046009 2.017649 2.370659 2.163979 2.491451 0.571895 1.339830 2.023743 1.302234 2.405961 1.487577 1.209060 2.422451 1.887120 2.318562
+1 0.044637 1 1 0.855700 -0.466230 0.782691 -2.309800 -0.142007 -2.245756 1.816572 -0.437989 -0.524886 -0.172035 2.008316 -1.071397 -29.443679 -9.906809 -3.741630 -35.575307 -14.189488 1.634170 1.254056 0.418547 0.268306 1.917411 0.673880 0.908215 1.872127 2.340942 2.207623 0.266562 1.858229 0.509543 1.885783 2.359533
+1 -0.039541 1 1 0.417108 -1.694219 2.223372 -1.033462 0.473384 1.647900 1.544750 2.057103 -1.073881 -0.267469 0.272678 -2.254223 28.346519 19.936796 -22.264608 48.733828 69.450243 0.628441 2.213777 2.458156 1.229269 2.328215 2.063086 1.035636 1.436831 1.065790 1.977543 1.074233 2.129219 1.037250 1.559444 0.828071
+1 0.036225 1 1 2.107858 -0.975281 -1.866012 -1.114966 1.932211 1.604419 1.184281 -0.911742 1.040825 0.751527 1.714972 -2.149628 34.629599 19.662334 14.854959 67.288444 66.875983 1.894689 1.287771 2.323518 1.868994 1.436401 0.593886 1.944699 0.301295 0.610910 2.311036 1.326393 1.179268 1.206042 1.196802 1.142418
+1 -0.033772 1 1 -0.288367 -2.256559 -0.680065 -2.305805 1.022826 -0.163643 1.691064 1.302553 -1.744815 0.084626 -0.839315 -2.195279 62.289754 53.890268 33.740244 72.281215 -19.621630 2.413978 1.227344 1.475032 1.861237 1.556880 0.489289 1.232028 1.439656 1.305408 1.740680 0.353175 1.806067 1.324376 1.037205 0.807755
+1 0.034680 1 1 -1.842253 -2.349973 -1.458208 1.036320 0.448281 -0.844695 1.643373 0.851193 -0.806098 0.027757 -0.006314 2.262178 27.514124 -20.118922 -38.726630 -28.475862 56.192486 1.781742 1.994512 0.506183 1.673560 1.763994 0.694525 1.384389 1.681309 1.507342 0.390262 1.881158 1.124639 1.062488 0.484995 1.063337
+1 -0.008148 1 1 -2.177830 -1.661370 -1.743202 -1.075759 1.163148 2.038096 -0.072326 0.215828 -1.113524 -2.098687 -0.394533 -0.583274 -42.173787 -64.833104 -49.971499 -20.980613 28.841978 0.581790 1.145661 1.124482 0.664608 0.318208 1.375890 0.579081 0.622265 1.915630 2.238564 0.543328 0.468202 2.327181 0.435036 0.651260
+1 -0.021712 1 1 -0.532765 -0.638810 -1.660087 0.972350 -0.274198 0.271610 -1.349694 1.140461 -2.270865 -0.787772 1.736451 0.700202 46.562778 30.614629 40.065600 32.539730 -4.753020 2.364793 0.325622 2.228599 1.814188 0.551110 0.753918 0.591636 2.380633 1.048733 1.057270 0.534681 1.388465 0.438544 1.106314 1.316892
+1 -0.002836 1 1 -1.208883 2.118811 -0.661889 1.582150 -0.822138 -0.943921 2.138784 0.436867 0.528230 -0.171105 -1.211226 0.436576 10.865865 72.587005 19.795405 1.367936 40.893190 1.252603 0.756591 0.520294 0.335657 2.142936 2.070650 2.160847 1.603358 0.884820 2.422551 1.320061 0.513951 1.723944 0.318697 0.593689
+1 0.002474 1 1 0.168364 2.258079 -2.043516 -1.483967 1.648009 -1.327614 -0.055045 -1.520947 2.153435 1.640410 -1.817077 1.375661 55.875188 -55.717069 13.224536 -35.227550 -19.437750 1.520964 2.091780 1.801746 0.690993 0.519408 1.193605 1.414852 0.674452 1.511235 0.573366 1.305019 1.953356 1.812196 0.836267 0.891756
+1 -0.023292 1 1 -2.016021 -1.189566 1.627276 -1.079794 -0.684535 -2.033340 -0.100161 -1.087369 -0.767275 2.218804 2.306689 -0.308720 -9.850329 45.524567 -18.598082 22.043539 -14.233371 1.821073 1.527484 1.420068 0.577273 1.731924 1.693740 1.191207 1.610898 1.608432 0.674786 0.385391 1.015414 1.318135 1.891221 1.506468
+1 -0.009610 1 1 -0.281730 0.908933 -1.132411 0.900412 1.736599 -1.519628 0.755360 0.161130 -1.519180 -1.140847 0.499334 -0.455923 -11.004810 -7.849588 71.981064 35.734754 -5.992023 0.506027 1.304048 1.388804 1.637469 0.444622 2.005453 2.156060 2.154320 2.154112 0.909892 0.812465 1.343277 1.465503 1.458934 1.298412
+1 0.011667 1 1 0.846204 0.154503 0.207474 -0.145730 1.158880 1.001505 -0.368043 1.664916 0.082706 -0.108477 0.522079 0.107888 -31.726690 19.524484 -51.997656 -24.596039 14.378072 1.408786 2.221991 0.999567 0.473854 0.561630 2.065475 0.692289 2.047255 0.465568 0.796723 2.268470 1.428855 2.019742 1.556690 1.796700
+1 0.014697 1 1 1.573550 0.727938 1.092171 1.357669 0.958293 -0.907242 1.267543 -1.122742 -1.517460 -0.494583 0.193151 -0.547046 -10.292407 -34.486047 -6.998525 -24.214249 -18.875689 1.469463 0.518048 0.840004 0.695065 1.452033 2.309958 1.217045 1.621084 1.801575 2.316358 0.775401 1.664256 0.648084 1.602191 1.528398
+1 -0.000409 1 1 0.546268 1.384538 0.156790 0.952345 -1.923807 -1.730001 -0.686404 -0.469510 2.204782 2.255772 1.594103 2.153078 10.972669 67.654015 61.036825 -4.085960 27.261337 0.344308 1.289377 2.305855 2.013730 1.762800 0.888395 1.761787 1.847564 1.261857 1.037624 1.101962 2.432805 0.409060 0.570200 2.100275
+1 0.010722 1 1 1.108258 -1.587263 -0.287423 -0.514324 -1.723740 0.860539 0.750218 -1.440828 0.976224 -1.134163 -0.266868 0.938513 39.071266 -29.230597 -28.649065 -4.841213 -66.259267 1.082495 1.498145 1.081211 2.404897 1.608172 0.796860 2.330153 0.876877 1.669364 1.004807 0.788381 1.577664 1.053824 1.118666 1.925320
+1 -0.010340 1 1 1.572357 -0.473027 -0.358071 -0.371981 1.447812 -1.403092 -0.972738 -1.536832 -0.935544 1.546769 -1.696685 -1.515158 15.631647 71.083043 -57.296663 14.986486 27.878138 0.592976 2.396522 0.347194 0.282234 2.003440 2.072108 1.924110 0.759384 2.460765 2.335466 2.429939 1.737679 1.668801 0.536111 0.670201
+1 -0.025740 1 1 0.736144 2.347674 0.525466 0.489678 2.188434 0.818368 -1.147514 1.539599 0.304634 2.337078 1.504853 0.678973 -60.832239 -7.443316 0.193971 -39.931168 -23.136971 0.428901 1.042958 0.746892 1.769013 1.796935 0.843667 1.514892 1.298297 1.472717 1.212683 0.310322 1.589561 0.744868 1.494792 0.968673
+1 0.024095 1 1 -1.417022 0.531133 1.490059 1.779423 1.939149 0.392984 -1.880965 2.034556 1.683470 0.898876 -0.517235 1.183723 -27.948258 73.619906 -20.238322 54.530463 -6.504296 1.859495 1.524324 2.316507 1.028902 0.754812 2.117449 1.221054 1.495493 1.496287 1.339528 1.449720 1.697274 2.091054 0.849448 1.922632
+1 0.020260 1 1 -0.199043 0.488572 -2.256396 2.061956 0.387197 -0.181215 -1.483073 -2.179847 2.139403 1.427218 1.187182 0.711914 12.236221 4.158336 -10.845155 -24.526842 -22.627761 0.553371 0.501420 0.359761 2.250716 2.281542 0.626899 1.045554 1.631670 1.969403 1.513556 1.326625 0.579876 0.468888 0.350146 0.407617
+1 -0.025980 1 1 -0.335823 1.257810 0.236426 1.073059 0.590011 1.445195 1.745492 1.868500 0.527324 -1.271539 -0.070526 2.189103 -66.017400 -4.439120 -58.286458 29.492736 -65.580885 1.106024 0.952772 1.492678 1.438080 1.806552 0.474344 2.051159 0.832108 0.736146 1.163630 1.635018 2.002716 1.155258 0.423276 0.992315
+1 -0.007365 1 1 -1.645819 0.444267 -2.336919 1.159017 -1.419290 0.105393 -0.518359 1.147457 2.211416 0.658938 0.660314 0.224646 31.850983 -30.534263 -39.358314 4.819838 7.019526 0.282688 0.636627 0.297258 0.262334 0.550776 1.888073 0.342719 1.570369 2.197308 2.411804 0.689955 1.074161 0.925780 2.333296 1.956965
+1 -0.009861 1 1 1.718690 -0.924636 1.098129 -2.177612 1.995445 -0.636875 -2.117638 1.530151 1.741799 1.064504 -1.820928 -2.082358 22.781457 -62.055624 -18.868112 -16.355294 66.566556 0.386709 0.673376 1.433161 2.390183 1.799419 2.088840 1.883061 1.599222 1.123836 1.056290 2.060747 2.229567 2.333413 1.674737 1.307340
+1 0.024446 1 1 -1.257203 0.536843 -1.504653 -2.029852 1.966238 -1.429204 -1.578740 1.583654 0.891981 1.423298 1.282680 -1.177772 61.332564 16.398894 66.207006 41.144545 16.365657 0.738916 0.466591 2.238554 0.375599 0.698980 2.010620 1.239396 1.533404 1.913509 0.343404 1.844919 1.806292 0.594587 2.466079 1.631925
+1 0.009745 1 1 0.497568 -1.867059 0.138640 2.206479 -2.214642 1.677947 2.318583 1.673625 0.372250 -1.650368 -0.612529 1.794595 -71.563851 -73.636996 33.004309 3.414452 -63.304520 1.239080 0.718274 2.273909 0.595337 1.572176 1.059581 1.123416 0.758824 2.057894 1.515853 1.688569 2.031094 1.096112 0.860825 1.883480
+1 0.000483 1 1 -0.384529 -2.099525 -0.341738 0.817067 0.535134 -1.949990 1.187974 -0.120728 1.969227 1.689235 -1.167544 -0.527724 -23.564728 -52.377227 45.944893 -4.183002 46.285115 1.583907 2.472594 0.892223 0.837123 1.768278 0.696455 2.321710 0.730149 1.621114 2.306047 0.729106 2.083259 0.334459 2.258673 1.023424
+1 0.001507 1 1 -2.147027 -2.326243 1.529360 -2.134333 -1.035359 1.565286 -1.501922 1.468097 0.238176 2.208216 -1.295201 -1.925039 36.195467 -62.785372 16.251746 -6.908462 -10.525562 0.578256 2.499054 2.342576 0.421012 1.197215 1.343560 1.713736 2.007502 0.591670 0.700647 0.774688 0.931899 1.670415 0.658284 2.033482
+1 -0.011758 1 1 -0.786870 -1.961732 1.749120 1.570533 1.850292 0.804925 -0.891114 -0.987237 -0.169518 1.902670 -0.093329 0.636959 -37.742520 11.473181 -70.243032 -74.640697 -36.192263 0.874609 1.797294 2.365477 0.576188 1.490031 1.944460 0.793904 2.146482 0.928675 1.488793 1.391325 1.251152 1.112649 2.039386 0.968454
+1 0.018291 1 1 -0.694352 -2.091136 -0.722646 -1.682641 -1.108341 0.188850 -2.155070 -0.838139 -1.278297 -0.555840 -2.048330 -2.285320 41.905386 53.828519 45.914374 -67.114634 4.341779 2.459145 2.095627 1.211782 0.923870 1.732314 1.494570 1.733523 1.566583 1.556518 1.141037 2.158271 1.061839 0.833164 0.488659 1.887902
+1 0.079149 1 1 1.657650 0.473326 0.681547 -1.061790 0.310446 1.043128 1.772267 -0.521832 -0.666308 -1.999630 0.982468 0.133407 -29.481330 -42.716896 -42.870402 -72.847507 -48.053810 0.769221 1.301852 0.470367 0.457654 0.536139 1.138909 2.385673 0.250741 1.460891 0.441303 2.486826 1.583919 0.430472 0.450298 0.658987
+1 0.009612 1 1 -0.393115 -0.321968 -1.486145 -1.973282 0.839855 1.837374 0.460154 0.774484 1.134731 0.383141 2.333086 0.380626 -71.197633 -68.618241 -66.777204 -24.465222 -36.991318 1.928865 1.933135 1.703978 2.257913 1.737306 2.153295 0.684053 0.878846 1.012844 0.866036 1.724564 1.741185 2.090573 1.755988 1.144393
+1 0.014532 1 1 -1.857814 0.001164 0.716884 -0.902364 -1.557978 1.808683 -1.089279 0.125360 0.488970 -0.293711 2.176354 0.421429 7.338260 34.137210 -5.916650 8.862628 4.195648 1.618945 1.866196 1.650804 1.818031 2.152807 1.471237 1.083569 1.538852 1.237224 1.022886 0.897634 1.778821 2.396563 1.030277 1.367498
+1 0.010353 1 1 -0.373168 0.356605 -0.702328 0.508816 -1.316897 0.996893 2.240132 -2.088260 0.487059 0.581995 -1.324607 -1.344138 8.379031 -23.622267 30.557064 -27.423907 36.399703 2.422022 1.428969 1.680495 1.336901 2.296877 1.852998 0.330132 1.521008 0.580368 2.003004 1.487558 0.884996 0.870142 0.976445 1.107212
+1 -0.039983 1 1 2.159482 -0.404183 2.169365 0.757827 -0.783077 0.520640 -0.512934 -1.921048 2.243122 1.039067 -0.512602 -1.053984 -13.918661 69.068178 -21.130461 60.347264 -43.530870 0.275041 0.362708 2.276078 1.049134 1.050816 2.313493 2.119604 1.437477 0.683018 1.490776 0.977215 0.548063 1.290278 1.702768 2.171231
+1 -0.064946 1 1 -0.524742 2.260186 0.378077 2.037782 -0.647440 -0.623320 -0.492559 1.230788 -1.527985 1.670820 0.345647 -1.084245 -3.143835 -38.442465 -52.509546 72.067198 -16.605680 2.249999 1.487587 1.381068 2.109959 1.330891 0.281161 1.980730 0.637239 1.570559 0.885900 0.327067 1.765705 2.455634 1.588961 1.918633
+1 -0.001445 1 1 -0.640727 -0.886909 -0.997325 -0.073736 0.081097 1.110253 -1.043165 2.319269 -0.925464 1.326071 -2.318430 0.885171 1.912127 37.120927 41.420332 1.516024 -20.184033 2.379369 2.306562 0.389216 2.309089 2.352727 2.274488 1.321446 1.283977 1.556363 0.789100 2.401185 2.216534 1.542268 2.391635 1.459474
+1 0.012276 1 1 2.188876 -1.185457 0.004681 -1.432505 -0.507570 -1.306029 -0.126963 0.845824 -1.509889 -0.483576 1.402675 -1.315641 -46.253579 66.099647 36.761025 -7.458769 40.472776 1.014313 0.805058 0.607582 0.384752 1.524163 1.852909 1.089308 1.249473 2.150458 0.250662 2.371613 2.451730 1.220572 2.403407 1.302929
+1 -0.028678 1 1 0.256347 1.306885 0.364494 -0.052698 0.239328 -1.988456 0.286498 -0.887574 1.969651 -0.606097 1.517697 -0.222203 74.985591 -17.177605 45.991255 25.031061 -52.952213 1.107384 1.310952 0.412072 1.689613 1.568156 0.999499 1.576218 1.504990 1.367844 0.362894 0.907863 0.447362 0.815335 2.332983 1.191793
+1 -0.008840 1 1 1.923690 -0.242611 -1.340567 -0.973720 0.806642 -0.316437 1.935288 1.483271 0.794520 -1.407069 -1.843225 0.165514 47.127199 66.837456 -12.877337 20.591167 25.736881 0.771297 2.434932 2.406847 0.623625 2.264775 2.330466 1.637418 1.832891 2.155752 1.476455 1.022894 1.034669 0.939723 0.417952 1.514762
+1 0.009941 1 1 0.034214 0.118348 0.440258 0.966006 1.479521 -0.964396 2.010708 1.431586 -0.788148 0.125462 2.208505 -1.152147 -29.343192 28.977110 -31.710174 -2.897286 55.311308 2.382198 0.348093 1.892501 0.518133 2.255900 1.656700 1.905489 0.560600 0.502650 0.793839 1.057750 1.858313 1.915718 1.477486 0.351180
+1 0.039673 1 1 1.624669 2.227526 -1.902358 0.621310 -0.293993 2.149991 0.292672 -0.790345 0.892672 -1.113278 2.031753 1.693269 20.801884 -32.742591 45.264907 -32.704455 -63.768364 1.301607 0.855559 1.137084 0.970731 1.828248 0.617396 1.081019 1.439381 1.170033 1.249901 0.327564 1.111207 0.309687 2.156684 1.387119
+1 0.039380 1 1 -2.082368 0.551876 1.392232 2.240135 -2.040094 -0.510312 -0.263639 -1.338404 -2.314833 0.078026 1.332602 -0.937605 -3.258003 -7.261983 47.858468 57.265216 56.477666 1.677048 1.893891 1.377016 1.502597 1.642128 2.247258 0.418919 2.020094 0.716611 1.328007 1.314085 1.318620 1.042792 2.452785 0.950192
+1 0.038430 1 1 1.072445 -0.313301 -1.903682 1.939538 2.225258 -2.320833 -1.797348 -1.612797 -0.621587 0.347256 -2.325472 0.344690 53.280106 -21.264879 51.179296 70.429046 50.978988 1.432753 2.273723 1.969645 1.076116 2.283805 0.413054 2.445930 0.497537 0.360551 2.037379 0.972179 1.414678 2.242868 0.882512 1.881890
+1 0.045456 1 1 0.438514 -0.065958 -1.146289 -1.440925 -0.665123 -0.934940 2.281314 2.043705 -0.059653 1.156896 0.638087 -1.072701 22.653930 44.603543 -48.258792 -35.519343 26.395309 0.264456 2.469497 0.580993 1.254452 0.319186 2.062034 1.357770 2.037098 0.755044 1.531510 1.597357 1.284386 1.681063 1.878165 0.316313
+1 -0.001803 1 1 0.566957 0.397145 2.071510 0.741264 -1.136214 -1.742061 -0.739835 1.582220 0.361481 1.140062 0.449888 -2.114025 31.656639 3.128570 -68.124311 -15.299590 -40.201258 0.436801 1.069320 0.562184 2.372817 2.428776 2.431161 2.023980 0.779320 2.273188 1.977229 0.288686 2.452459 2.227300 2.484199 2.441518
+1 0.014391 1 1 0.348985 -1.525637 -1.265177 -1.524809 -1.497914 -1.854818 -1.465326 -0.782342 -1.260763 1.969120 -0.112286 -2.234134 -24.773964 23.986163 -64.564108 -28.961292 -2.438236 0.933421 0.252951 0.348846 1.058770 0.991188 1.398689 1.272719 1.330614 2.383126 2.444695 2.231118 1.394448 1.987013 0.475322 0.488642
+1 0.007048 1 1 0.327628 -2.340637 -0.064315 -1.810257 -1.801120 0.965301 -0.934174 1.025685 0.768607 1.322512 -0.887444 -0.567908 -71.518305 -58.153515 13.871462 37.669034 -46.538818 2.456309 1.690816 1.547667 0.894491 0.712468 1.456172 2.129476 0.854424 2.302602 1.330295 1.523057 1.265116 1.797290 2.302647 2.090825
+1 -0.002074 1 1 1.699660 -0.316305 -0.566939 -0.095238 1.549177 1.073795 -1.172952 -1.874201 -2.088073 -1.076918 0.517720 2.254640 45.086541 -30.507544 -40.293377 39.219921 69.218828 0.787619 2.261030 2.378129 1.719723 1.378980 0.760935 1.536645 2.392041 1.542317 0.965259 2.101684 1.760461 2.066654 0.253948 1.356854
+1 0.004164 1 1 1.447857 -0.643936 1.731377 0.253650 -1.622066 -0.899833 -1.433303 0.211368 -0.680738 0.523569 1.586154 0.502684 -22.131465 36.467719 12.949939 -0.376066 -20.534138 1.866014 0.855904 2.436559 0.490772 1.406187 1.276866 1.294176 1.973496 0.542168 1.215516 0.682152 0.420552 2.464518 2.398319 1.292741
+1 0.065469 1 1 -0.787169 -2.267321 2.220750 2.020412 -0.403641 1.853172 2.087433 -0.249454 1.458554 0.066338 -1.887472 1.065026 71.432401 -35.630824 -47.260970 -65.131075 42.016989 1.068000 0.880379 2.027919 1.728200 2.110583 0.575400 1.754541 1.563651 1.781524 0.583056 2.176414 2.240946 2.335538 1.384435 2.449234
+1 -0.023053 1 1 -2.176170 -2.040396 -0.873693 -0.356148 -1.046577 1.534924 1.850751 -0.915102 1.124767 -2.154710 0.492148 1.293832 -71.272277 26.834333 -45.372083 31.400219 43.486683 0.335279 0.280579 1.188463 0.503630 1.503087 0.885989 1.820056 2.440322 0.749317 2.022727 2.227910 1.490068 0.314661 0.255926 0.840240
+1 -0.007216 1 1 -0.599683 0.922223 0.751025 -2.017147 -1.267176 -2.134444 1.820519 -0.080184 0.096951 -1.031075 -1.822065 -2.351122 -61.011191 -15.093543 -27.176083 1.565247 57.115243 0.413364 0.916533 2.173732 2.157538 2.233828 1.956197 2.296796 0.495248 2.378493 1.087292 1.120882 0.911589 2.322077 2.396796 0.453601
+1 0.007321 1 1 0.343773 0.409880 -0.651508 1.692193 1.424494 -2.184561 -1.696036 -0.041926 2.206835 -0.934217 0.295960 -2.090287 -18.938893 -5.974770 -67.960998 29.512592 -31.869978 1.544174 0.682992 1.051230 0.269073 1.303056 0.466906 0.795989 1.180669 2.248115 1.315621 2.392721 1.712954 2.364144 0.673703 2.424120
+1 0.022773 1 1 -1.014854 2.190664 0.592497 0.815472 2.007420 -1.996461 -2.318705 0.985641 1.620487 -2.085055 -2.187545 -0.000774 35.722296 -65.374010 9.007190 33.843070 0.480900 1.112328 1.154189 0.453922 0.816316 0.827361 1.960278 1.142694 0.752937 2.118917 1.142976 1.001329 0.831126 2.237242 0.833419 0.271107
+1 -0.007640 1 1 1.282102 -1.465468 1.540902 -1.345190 1.437695 -1.787757 -0.639648 -1.608103 -1.839390 -1.351448 -0.067130 -1.988882 -69.125584 -43.690645 -58.678424 41.719980 -62.295186 1.447010 1.144242 2.031483 0.884950 2.354365 0.562911 1.087758 2.196433 1.204033 1.183516 0.599781 2.016837 2.223868 1.044905 1.963673
+1 0.038239 1 1 1.367637 -1.155317 2.349419 1.579522 2.131236 0.815765 2.228589 1.820196 -0.792126 -0.766673 -1.803777 -1.282275 -45.885051 -40.048328 -42.246390 64.929490 19.943063 0.370852 1.909500 0.462585 2.420759 0.442362 2.285809 0.346693 0.861381 2.236448 0.975245 1.186815 2.055385 2.103603 0.257249 0.578042
+1 -0.002521 1 1 2.218511 2.096105 -0.584746 2.210622 1.451122 -2.323861 -0.858181 1.171522 1.410197 -2.141167 1.923603 -1.707557 -14.543990 59.155078 19.392682 -17.188081 19.926122 0.600008 1.337163 2.204967 0.637756 1.260482 0.422049 0.634908 0.644535 0.447255 1.262949 1.390756 0.680710 0.937454 0.532463 2.353895
+1 -0.015646 1 1 -1.814421 -1.112350 -1.211578 -0.765993 0.197811 -2.345169 -0.830269 -0.944441 -1.892882 -0.329617 1.893721 0.294820 73.712841 41.717541 46.713813 19.058366 63.960895 0.486506 1.709285 1.459070 1.334966 1.269290 2.213077 1.942376 1.763926 1.811488 2.428609 1.876505 1.675105 0.744959 0.776575 1.143222
+1 0.043355 1 1 -1.456096 -1.178206 -0.647424 -0.351323 -0.062848 -0.704820 1.038961 -2.295240 -0.483737 -1.300805 -1.855136 -2.098380 1.506589 -28.759579 -62.244080 -36.252579 2.903096 2.010074 1.072542 0.715983 2.022939 1.284185 0.550618 1.478448 0.770596 1.908234 1.696290 1.287473 1.813364 2.461039 2.427627 1.134821
+1 0.002267 1 1 1.400632 2.041418 -0.785566 1.099136 0.610639 -0.580948 0.070300 -1.282638 1.875854 1.594532 -0.055547 -0.526294 -8.404084 52.556166 -38.520065 -6.735242 50.785191 2.075453 1.887496 1.893834 0.412764 2.073640 0.660604 0.528430 2.065050 0.294063 0.561148 0.711133 1.510755 1.513029 1.477584 1.998956
+1 0.020421 1 1 0.613894 2.292005 -2.052420 -0.331866 1.789361 -0.675525 -1.403872 0.061937 -0.463843 -1.523602 -0.051286 0.411642 21.471399 -30.205269 -59.962691 57.060405 64.235024 2.095663 1.813775 0.363227 2.010289 2.424742 2.140274 2.328756 2.157830 0.396761 0.868863 1.987356 1.737712 2.216874 0.495877 1.705309
+1 0.004485 1 1 1.992787 1.814144 1.167862 1.148276 1.836540 0.580404 0.207942 -1.707538 -0.137524 -2.301472 -1.548610 -0.963423 -15.432480 -23.683082 58.434021 50.598375 56.881563 2.251559 0.710029 0.962917 1.004304 1.334828 1.212908 1.849023 1.026458 2.436612 1.386418 2.024893 0.372136 0.985949 1.089762 2.121972
+1 -0.034976 1 1 -1.850270 -0.439436 -1.279033 1.216933 1.219473 1.505908 -0.446067 0.362759 -0.937949 -1.173884 1.295368 0.015045 -51.370658 13.346421 63.289385 54.688677 -47.408467 1.463361 1.455847 1.166569 1.518309 2.464841 1.075761 0.815369 0.656589 0.543592 0.405032 0.368697 1.698130 0.715586 2.108406 2.227999
+1 -0.001746 1 1 0.611977 -1.646616 1.183232 0.291227 -1.518859 -0.457376 -1.215531 -1.225626 -1.252621 2.159872 1.430820 0.475042 39.368190 11.166888 31.890976 41.637374 49.345256 1.310788 2.168873 1.491219 1.674588 1.053046 1.546943 2.222728 2.138788 2.107862 2.092718 1.810811 2.306785 1.878804 2.063481 0.932172
+1 0.021592 1 1 -1.586570 1.932979 0.372284 -1.082439 1.981168 -0.248902 1.301982 -1.923712 -0.129407 2.180932 1.959152 2.002504 6.603927 -7.799016 21.929461 18.449775 35.361551 1.698782 0.428698 2.123966 0.490684 2.178183 0.464229 0.795784 2.240070 1.098958 1.437398 1.591663 2.327920 1.597748 1.095940 2.463033
+1 -0.000235 1 1 -0.734870 0.205676 -2.095143 -2.098474 -1.539027 -0.125406 -1.256719 -0.753079 0.481470 0.899000 1.580993 -1.418256 -43.249710 2.115714 8.812307 58.434750 62.841555 1.795307 0.469346 1.300037 1.479335 2.186351 0.498509 0.943206 0.459010 0.828935 1.408736 1.371442 2.334481 1.615352 2.226580 1.637223
+1 0.044655 1 1 0.020723 -0.419298 -2.127004 -0.368567 2.282868 -0.105641 1.067300 -1.945574 0.007095 1.439287 1.410007 -0.618533 -4.802958 -23.319119 25.564540 63.230682 -31.923389 1.578953 2.457719 0.628025 1.968999 1.467692 2.250584 2.316059 0.258485 1.107651 1.296312 1.869412 1.711309 1.721950 0.564973 2.001796
+1 0.004121 1 1 0.666102 -1.465220 0.993989 0.558352 1.850076 1.890262 -1.285894 -1.012737 0.079183 1.931118 2.068811 -2.203583 -30.329582 -49.281619 23.829273 -1.412308 -36.658916 2.478941 1.810322 0.825356 2.003782 1.071132 1.768684 0.766514 0.796823 1.697819 2.248399 1.598456 1.752736 0.476243 2.465465 0.322296
+1 0.016884 1 1 0.504081 -0.777814 -0.555552 -1.925523 -2.291733 1.903452 -1.097504 -1.464506 -1.136749 -1.322934 -1.494686 0.551224 -4.470705 10.854437 30.514990 15.437021 -49.987512 1.523246 2.196523 0.460863 0.482711 0.931476 1.323361 1.982005 1.804446 1.081244 0.724524 1.573006 1.519026 1.012704 0.774717 1.425823
+1 0.025298 1 1 -0.389950 1.037578 -1.974308 -2.268448 2.128609 -0.920826 -0.842041 -0.879564 -0.071924 2.260056 -1.799998 0.967342 11.864404 55.032969 39.110387 28.277163 54.277750 0.567194 1.072396 0.501011 2.492914 0.409821 2.116355 0.824462 0.487408 1.115284 1.331943 2.209556 1.259264 2.451343 1.475476 0.324564
+1 0.043097 1 1 -0.985634 -1.501435 0.218855 -2.081974 -2.248798 -2.193647 1.112502 -0.942604 0.705377 -1.104621 1.439215 0.201899 12.812558 -59.333830 -23.674832 47.105154 -3.679300 0.805039 0.293009 0.854895 1.223842 1.119506 0.292967 2.403938 1.239154 1.962232 2.481877 1.655470 1.488069 0.481748 0.481808 1.491826
+1 0.001573 1 1 1.353342 -1.089536 0.518885 -1.723991 1.355413 0.732485 2.109394 1.278590 0.762883 -0.633269 1.941841 -1.480738 -20.304014 0.433638 -61.851915 -45.143442 -25.823517 0.387322 1.969341 0.457277 0.960586 2.313171 1.212483 1.452716 0.299994 1.244382 2.084395 1.430616 2.370605 1.252854 0.473885 1.078200
+1 -0.000349 1 1 0.168779 -0.194181 2.087069 -1.652729 2.122504 0.133551 1.495195 -1.427084 1.065098 -1.271821 -0.094972 1.306200 -54.791616 -32.690678 17.777901 -6.815549 51.069897 1.851279 0.698117 1.004916 0.374225 2.343936 0.777659 1.368087 2.185351 1.694576 1.743470 2.255469 1.164546 1.268618 2.158891 2.477125
+1 0.011583 1 1 1.610330 1.572359 -0.437437 -0.669251 0.377929 -0.449503 -0.835795 0.420314 0.338956 -0.443327 -0.710316 -1.797320 -36.303257 51.151503 53.316893 -2.983664 -46.441841 2.154717 2.076076 1.111209 0.338425 1.413442 1.719862 1.477360 0.489645 0.469623 1.450627 1.179574 1.858708 1.809226 0.407404 1.996189
+1 0.001797 1 1 1.512795 2.210868 0.868176 1.877351 -1.512684 -0.339642 -1.656290 -1.183536 -0.693923 0.393008 -1.490470 0.724987 -44.040772 56.751619 -25.537653 -61.341208 -11.688787 2.073449 1.949701 1.131817 2.447428 0.915726 2.111765 2.427896 1.145434 1.802517 2.409226 2.364944 0.606541 0.878911 2.107898 0.436047
+1 0.004217 1 1 -2.298247 0.806277 -1.725723 0.522679 0.779218 0.595906 1.562198 -1.563039 1.576298 -0.216054 2.034151 -0.406121 -68.258657 -23.240774 -7.693051 2.897267 -55.634145 2.228796 0.621114 0.567730 1.082139 2.263104 1.234444 1.546967 0.374749 2.156120 0.914250 2.053370 1.981879 1.942788 1.943128 0.896825
+1 0.019136 1 1 1.379367 -1.928011 -1.701583 0.981569 -0.835214 0.761413 -1.788163 1.966073 0.522835 -1.323109 0.262584 -2.261190 50.722365 40.783862 -45.634743 -33.127538 25.474668 2.166062 1.512941 2.254158 1.635924 1.479963 1.482385 1.700916 0.303765 1.626439 1.814540 1.967053 0.253553 1.460177 1.942041 0.637534
+1 -0.048187 1 1 -1.734896 1.873242 0.105485 1.028426 -0.290601 -2.089992 -0.347002 1.875814 0.923374 1.241921 1.803260 2.021012 7.828202 18.589015 -24.424123 53.767555 71.297850 0.669525 1.959520 1.899701 2.282060 0.338253 0.765052 0.975784 1.246957 0.355064 2.065605 0.621919 0.591062 1.725490 1.555826 0.761747
+1 -0.013897 1 1 -1.665905 2.155362 1.033897 2.128336 -0.801879 0.249171 -1.500039 0.132449 1.817633 -1.464188 -0.506977 -0.771232 53.719848 19.489841 -34.234918 13.731502 -64.642902 1.326146 1.536638 2.268635 1.954473 0.330538 1.606404 0.336661 1.018204 0.954440 0.267998 1.249037 1.565115 1.643347 2.477333 1.779083
+1 -0.027362 1 1 1.344930 -1.097500 -1.384843 -0.563617 -0.816371 1.729931 -0.498542 -0.367388 -1.466807 -2.114818 1.805552 -1.868909 64.556177 45.672745 71.829707 41.877908 42.001512 1.666301 1.268011 0.967631 1.481307 1.577798 1.054842 2.484408 1.439189 2.446082 0.796911 0.926968 2.048438 2.354127 1.063743 1.336661
+1 -0.017611 1 1 -1.478406 0.849930 1.521044 -0.526730 1.833665 -0.614770 1.835214 1.847442 0.020162 -0.430129 -0.372669 -0.677843 65.203257 -28.865578 -43.761297 -46.121387 37.851309 1.629153 2.429609 0.693786 2.462538 0.633377 1.918764 0.917863 2.026858 1.897503 1.323808 0.492825 2.153394 2.341355 2.406441 0.551365
+1 -0.032013 1 1 0.856824 -0.413736 1.824260 1.541683 -2.352057 1.210544 2.223441 0.120541 -0.387141 1.132042 2.311116 -1.303497 0.758338 -4.607590 -39.771766 -44.073335 -40.546383 1.179062 2.252165 1.893787 1.879765 2.461203 0.681639 0.802669 0.950824 2.498568 0.923713 1.341953 1.702713 1.243888 0.532864 2.338742
+1 0.018156 1 1 -0.391442 -0.463812 -0.995910 0.149805 1.358596 -2.312698 -1.732913 2.206749 2.331556 -1.769019 -1.445433 -1.032173 -45.292808 13.770322 -12.191368 -0.318145 52.944889 2.046154 2.208883 1.196572 1.787400 0.339864 0.842849 1.269806 1.880373 1.419895 2.177879 2.118124 1.306955 0.734746 2.379482 1.948209
+1 -0.070062 1 1 -1.563509 -1.619500 -0.169979 -1.128859 -0.663124 -0.329584 -2.254722 1.917382 2.131888 2.343396 -0.682106 1.093151 -32.155124 18.824923 40.486938 63.965423 16.871084 2.159717 0.618069 1.137196 0.598115 1.014215 1.405380 1.230677 1.244716 0.935430 0.277155 2.136697 0.723567 1.240546 0.597406 0.346889
+1 -0.008712 1 1 -0.832201 -0.431384 2.093809 -1.469064 -2.346528 -0.107188 -1.371787 2.104060 1.175073 -0.177090 1.870051 -1.685235 -72.967640 32.872056 30.647319 -10.515060 -26.617942 0.358760 1.177448 2.117701 0.950410 2.286014 1.540091 1.818182 2.432475 1.608388 2.169329 2.404430 0.511577 2.332188 1.334904 2.478350
+1 -0.006624 1 1 -0.955793 0.516470 0.093924 -0.070849 1.471555 1.804249 -0.214770 0.052546 1.927467 1.982739 -2.126915 1.125994 -11.735042 19.148847 -65.334860 66.999794 15.535861 0.793271 0.504248 0.646660 2.416515 1.111137 1.373857 2.412753 0.896615 0.407374 1.491647 2.107716 1.881920 0.423312 1.608959 0.519724
+1 0.003085 1 1 -0.160372 0.119753 0.497982 0.387317 1.819278 -2.082939 0.383158 -2.099599 -1.586394 0.170177 -0.258495 0.290034 63.505145 -69.035912 -36.573761 4.800296 -21.429712 1.087363 2.308279 2.245961 1.122547 1.898186 1.566943 0.859126 0.336413 1.345849 1.936514 2.236656 2.233957 1.859342 1.216727 0.786759
+1 -0.039872 1 1 -0.365871 0.481838 -2.345092 0.451084 -0.862570 -1.913103 -0.887878 1.573889 1.703874 -0.176620 0.353312 0.501650 24.350917 65.862630 -46.780708 56.638688 26.430057 2.274535 2.110379 1.634942 0.723064 1.786323 2.486169 1.787832 0.851283 1.259987 1.094016 1.623198 1.337891 0.935863 0.795195 1.334803
+1 0.027943 1 1 -1.253038 -0.140015 -1.746617 -1.912843 -1.239728 2.079554 -0.727440 -2.150886 -1.207521 1.451088 1.830520 -1.643900 -8.988016 -11.586446 -33.400764 -66.643191 -22.109717 0.654716 0.564430 1.882980 2.497706 2.192046 1.712213 1.166091 2.487256 2.068924 2.407575 1.606545 0.457617 2.167664 1.430969 1.552889
+1 0.027289 1 1 -1.968077 -1.217775 -1.234354 -1.857828 -0.218609 1.500651 0.737006 -2.011009 -1.772581 -0.042145 -1.471518 -1.183211 1.558519 -55.969532 -29.917474 -22.985913 -74.237413 1.252035 2.457702 0.350168 0.765791 2.150840 2.159613 1.114021 0.355233 0.394403 1.731985 0.478940 0.543098 1.093568 0.855370 2.446854
+1 0.043501 1 1 1.776059 1.945383 1.491714 1.323906 -1.005421 0.521481 -0.511035 1.723412 -1.677702 1.791756 1.883996 1.783919 67.315754 -74.126243 60.229837 -67.121276 42.711535 0.666487 0.398043 2.151395 2.490234 0.359659 0.537169 0.457633 2.430730 1.527758 1.525683 0.395613 1.818297 2.121474 1.358476 0.399113
+1 0.035976 1 1 1.772797 -1.042823 -1.359908 -0.883339 -2.246230 -1.438382 -0.328825 1.067201 1.103376 1.190571 1.124278 -0.931580 70.205139 37.769898 -1.317887 50.265804 17.361815 2.125357 1.367000 1.925303 0.560512 1.280722 0.837410 2.097989 0.402052 2.033076 0.666435 1.779075 2.162124 0.564607 0.341524 1.741224
+1 -0.012101 1 1 -0.940622 1.033536 0.777543 0.702160 1.383143 0.276353 -1.757518 -1.345668 -1.878223 0.998214 0.878938 -1.033273 -34.215747 35.942342 32.941173 -7.702693 -9.157883 1.126948 1.621551 0.662715 2.244009 2.063141 1.964053 1.587140 0.569444 0.652081 1.270113 0.295876 1.787176 1.074496 2.052983 2.226429
+1 -0.023198 1 1 -2.064935 1.377290 0.857321 -1.499596 -1.851166 -1.352809 0.614055 0.284313 0.092807 0.006994 -0.255464 -0.590123 43.946663 11.567720 18.666846 -66.314982 -55.899961 0.465343 1.514960 2.439822 1.331229 1.471458 0.298627 0.770932 0.810689 0.746096 1.880533 1.865444 0.258449 0.508688 1.012079 1.510697
+1 0.047104 1 1 -0.694770 0.305434 1.640158 -1.344405 0.482609 1.185061 -1.954052 -1.108107 -0.593917 -1.119339 -0.878315 2.081195 -45.236083 67.151233 10.777974 -54.586973 -43.259658 1.148797 2.084703 2.103938 1.394136 1.249188 1.850225 0.982144 2.397693 2.021166 0.730410 1.507105 0.910976 1.018928 1.870991 1.237512
+1 0.022986 1 1 -0.960114 -1.417323 0.176271 -1.499490 -0.073691 0.832324 -2.220432 -1.397500 -1.240766 -1.227722 1.230251 -1.131909 -2.511442 -59.814300 1.060540 -25.507210 0.328422 0.921793 0.577838 2.216662 1.431502 1.503148 1.912525 1.809616 2.467901 0.770558 1.271463 0.485886 0.288348 1.256668 1.569877 0.665570
+1 0.001619 1 1 -0.074451 2.201214 -1.168950 -0.593378 -1.484030 0.582336 -0.311569 -1.071908 -0.086316 0.695775 -2.250558 1.226252 74.389566 15.428191 -48.401300 -30.654825 34.361814 1.660163 1.608413 0.350405 0.255801 1.002724 1.781454 1.654340 0.500333 2.345680 0.841807 1.743151 1.389360 1.970679 0.446383 2.353851
+1 0.045473 1 1 1.020614 0.366939 -1.378364 -0.055099 2.287565 -1.277711 -0.127850 0.079974 1.095488 0.569081 -1.606460 2.222752 -64.674687 62.538192 29.393664 69.318358 -16.355661 2.281102 2.234467 1.435844 2.474366 1.423369 2.072005 2.441862 1.875929 0.995679 0.373179 0.526638 1.210913 2.060432 1.433719 0.520039
+1 -0.039041 1 1 1.809505 -1.416099 1.902272 -2.066377 0.701073 1.960465 0.510936 1.328046 -2.112420 -0.310582 1.373720 2.115409 -41.359197 -24.017440 -11.108462 50.075748 -26.896839 2.047379 0.290246 1.668790 0.361022 0.939689 2.104365 1.814216 1.021684 0.943621 0.683943 1.272453 1.361225 1.611526 0.924559 2.067580
+1 0.052989 1 1 0.667285 -0.431289 -1.017691 1.644741 0.293449 -1.868319 -2.184794 -0.905267 1.484469 2.088462 -1.809909 -0.674267 28.234000 -71.158591 -12.435876 -59.774810 64.760915 1.925417 2.485406 2.466831 0.777502 0.983273 1.120901 1.240214 1.778032 0.386472 1.193315 1.048690 0.331607 1.568080 1.974090 1.533649
+1 0.036441 1 1 0.321254 -1.089752 1.592126 1.913174 2.090748 -1.079275 -1.385395 -0.416893 0.605415 1.165886 0.932197 -1.255114 -65.377838 -55.318522 -38.391457 54.777247 -58.810729 2.396174 1.242197 1.350239 1.472445 1.133940 2.126978 1.624061 2.342362 1.333833 2.476824 2.233257 1.354357 0.924879 0.688673 2.024267
+1 0.001398 1 1 -2.091311 1.047902 1.883652 0.710028 1.666546 -0.795354 1.525328 0.791116 -2.077969 -0.903729 -0.935397 -0.694341 -61.121637 -71.355326 -18.959884 -58.775365 62.433080 2.316644 1.091359 1.975074 2.321998 1.075533 1.481131 0.867071 1.112281 0.357613 2.156307 1.801018 1.958284 1.378087 1.507750 0.504854
+1 0.001434 1 1 1.002936 0.138042 1.580512 -0.077512 -2.124005 -1.806179 0.755782 -2.165367 0.461884 1.584499 0.959455 -0.237510 -14.035315 58.459371 26.640873 3.147155 -55.759435 2.142552 2.366161 0.815818 1.460288 1.555197 1.437801 1.630025 1.324990 2.363863 0.440191 1.798131 0.690968 2.342030 2.493839 2.447221
+1 0.029550 1 1 0.662946 2.053882 1.351850 2.120172 -1.348163 -1.408341 0.336799 1.004777 -1.908485 1.318053 -0.416302 1.108569 -34.040826 -24.165788 45.602820 -53.397076 5.342749 0.558815 2.003764 0.763268 2.499596 2.458856 1.741246 0.866193 2.105627 0.516149 0.421084 2.413351 1.934691 0.846949 0.422177 0.526308
+1 -0.036871 1 1 -1.539222 1.313877 0.083380 1.786267 -0.846990 0.772775 0.686260 -1.963007 -0.821011 -0.863877 -0.312810 1.636103 38.213312 -48.860072 58.773310 53.024457 32.041962 1.813890 2.301592 2.355816 2.450496 0.727097 2.073214 2.498467 1.483904 2.472155 0.257486 2.311942 0.809908 1.118164 2.473546 1.137007
+1 0.024188 1 1 -0.530687 1.292009 0.102306 -0.569223 -0.782427 2.031822 -1.849000 2.064421 -0.604254 -0.497150 -0.527261 2.323124 -67.212084 16.501440 -10.300870 -26.724830 -64.221576 1.794679 1.165475 1.145420 1.568947 0.795477 1.579708 1.652003 1.723478 1.489941 0.436520 0.849227 0.457732 1.858494 0.460900 1.094319
+1 -0.003484 1 1 1.612389 -1.530001 0.779821 1.299470 -1.727081 1.266266 0.988094 0.429731 -1.600859 2.108592 1.932470 1.234276 17.381243 -73.448758 46.717817 -63.643467 -5.752640 2.355581 0.758576 2.392037 1.457175 0.998546 1.310286 0.470338 2.225070 1.001700 0.320235 1.695226 1.406923 2.413763 2.111462 1.839803
+1 0.012550 1 1 -1.709918 2.263662 2.257563 -1.289400 1.331899 1.385799 -2.210552 -0.265917 -1.925018 1.483205 -0.320279 -1.372773 -10.982767 62.637820 53.834411 -5.061315 -15.519485 1.585325 1.553020 0.856424 2.171016 1.509820 1.547212 2.239609 2.364570 1.079994 2.209918 0.596334 0.340485 2.282189 0.250432 0.762475
+1 0.013459 1 1 -1.343772 1.705714 -2.232294 1.875099 -1.675537 0.485754 2.210834 0.305189 2.233910 1.714156 -1.726327 -0.204304 50.529988 -42.498243 32.024371 33.611592 10.018568 0.356159 2.471705 1.698416 1.032531 0.992986 2.358183 1.735169 2.227989 0.557633 2.385526 2.284114 1.110624 1.756414 1.548060 0.749663
+1 0.012576 1 1 -0.587250 -2.167791 2.124494 0.602964 -2.325911 -2.313126 0.502782 0.951230 -1.808935 1.556676 -0.122605 -1.302256 64.821465 4.370574 -43.766445 17.362797 66.526059 1.427048 0.899334 1.111547 1.526098 0.633295 0.536872 2.205033 1.739624 0.617021 1.528657 0.892994 0.294315 0.296879 0.639183 0.495095
+1 -0.058088 1 1 1.085260 -1.691125 -2.322716 -0.454729 0.863426 2.152662 -1.925960 -0.213556 1.600339 -1.422521 -2.355048 -1.929175 73.089987 73.403550 -56.534616 72.711818 17.531593 2.177353 2.275968 1.446404 2.208882 1.182273 2.217862 1.348940 2.139058 2.154063 2.341939 0.969381 1.642042 0.793590 1.373034 2.076451
+1 0.010992 1 1 1.113196 1.306971 1.810594 -1.953331 1.580867 1.176727 -0.640057 0.948825 0.176124 0.739518 -2.195322 1.231332 -57.545653 30.214713 68.674415 -39.100871 -18.345698 2.332691 0.787488 2.315305 1.076861 1.307456 2.405880 2.381835 0.996864 2.301501 0.821392 0.631943 0.319937 1.180986 0.836243 0.479011
+1 -0.008329 1 1 -0.528646 -2.101747 -0.000208 1.222073 -1.919947 1.891180 -0.008765 -1.222538 -1.178079 1.485029 2.075135 0.407116 0.159060 -26.678767 -40.036737 2.558594 -47.716506 0.305155 2.495395 1.600370 2.416530 1.378041 0.739930 1.759958 0.356726 0.751664 0.961518 2.232024 0.875075 0.638465 1.924462 2.186949
+1 0.017015 1 1 -0.778117 -0.938775 -0.921601 0.282476 2.201147 -2.287806 1.942458 -0.535235 0.256935 1.763384 0.978756 -0.993555 64.309877 -43.897050 72.275184 29.010844 -64.743723 0.658644 1.333414 2.192777 0.501941 2.375967 1.385686 0.974458 1.468565 1.169438 0.250847 0.985401 0.878814 0.470653 0.756918 1.526855
+1 0.041953 1 1 1.618598 -0.838953 -0.815866 0.798380 2.207104 -1.128733 1.462322 2.133727 0.265078 1.950853 -0.809152 0.542831 5.472770 30.841056 -54.374870 71.563884 74.195799 2.256906 0.577083 0.788859 0.604631 0.287015 1.360875 2.468775 1.954275 1.496511 0.607309 0.286110 1.905992 2.260877 2.068842 1.027813
+1 0.003192 1 1 2.066348 -1.201104 0.917242 1.859592 1.600757 0.895659 1.966288 -0.576886 -2.340809 1.767418 -1.914016 -2.106957 62.848377 -7.327550 -4.126412 -52.610274 29.130785 1.391442 0.973291 2.109501 0.379908 1.109922 1.211402 1.289079 1.797057 0.644696 0.912649 2.140466 1.057515 2.407906 0.427926 0.407476
+1 -0.067724 1 1 -0.301887 1.431504 -2.175976 1.223601 0.190310 -1.173184 -1.068605 -1.135690 2.354737 1.420262 2.096968 -0.216915 54.063116 -61.212056 58.979381 66.448776 54.580986 0.514370 2.020123 1.216469 0.949229 0.442605 1.864570 1.337095 1.047577 1.869263 1.450817 2.135265 1.401154 2.193703 0.324753 1.122592
+1 0.058681 1 1 -1.383864 1.751968 2.317272 -1.510978 0.053287 0.237898 2.245693 1.836597 1.544102 0.596263 -1.862722 2.350368 -42.071087 11.237027 10.706540 -55.174714 -21.420406 1.183595 1.929866 0.765278 0.281671 1.540838 0.856096 1.152921 1.634992 1.558521 1.063670 2.348708 2.230765 2.221109 1.934168 1.059752
+1 0.009145 1 1 -0.701737 1.015694 -2.207685 0.795268 1.740740 2.102763 -1.778251 -1.092315 0.935481 2.091795 -2.328824 0.551187 -24.217809 71.284283 24.946294 22.356658 -1.642589 1.270181 1.437172 2.298208 1.731816 2.125770 1.574359 1.750717 0.301251 2.121934 2.348657 1.377364 0.610499 2.157526 2.046729 0.630949
+1 -0.037904 1 1 1.716254 0.550656 -0.262404 0.571559 2.351327 0.661217 1.267840 -0.831131 -1.295528 2.003527 -1.456659 -1.212566 47.067742 -32.456850 47.719179 -33.762662 0.942499 0.483679 1.448113 1.690865 2.368966 0.719979 1.684980 2.451016 0.473370 1.431437 0.414627 1.893684 2.387885 1.437616 0.755302 1.356732
+1 -0.026477 1 1 -0.321622 -0.392411 2.090916 1.736471 1.043895 0.523387 -1.460393 2.015411 0.352567 2.115724 -0.713048 -0.594203 -38.612498 -60.256235 73.453012 24.770196 62.684814 0.530004 1.518931 1.678499 1.527179 0.802109 0.552055 0.887640 0.308433 1.332700 1.433248 1.607956 1.659283 0.322175 0.546102 2.082461
+1 0.018956 1 1 1.190514 0.170354 -1.991351 -1.242300 1.254142 -0.157307 -0.208519 1.445511 2.344838 -0.023997 1.945394 1.681245 38.045241 -23.640920 17.053451 -32.641783 -60.453327 2.289092 1.523506 2.059058 0.847041 1.973383 0.894762 0.773003 1.866852 1.429194 0.957398 0.480583 1.163597 1.079550 1.489741 1.573121
+1 0.007337 1 1 -0.930056 -0.451341 1.262476 -1.449505 1.216217 -1.385043 0.779222 0.658898 -0.009185 1.141356 -1.371654 -0.374195 62.092575 39.903426 6.881805 12.498401 60.626889 1.466943 0.907606 0.628621 0.731735 1.270793 0.469982 0.740187 1.568573 1.263313 0.749468 2.304720 0.931784 1.990608 2.399328 0.262149
+1 -0.003692 1 1 -0.040962 -0.444152 -0.432141 -1.210227 -1.617199 0.802926 -1.501966 0.725463 1.911536 -1.885756 1.630926 -0.987709 41.869082 43.655814 73.260917 -53.772651 -6.948461 2.383133 0.320901 1.626605 2.346972 2.314378 1.246601 1.119741 1.983478 1.812197 0.846234 1.905129 1.257392 2.494633 2.302454 1.096341
+1 -0.007616 1 1 0.215453 2.007903 1.412470 -1.625511 -2.245321 -0.294392 0.161563 1.057719 1.943882 -0.168412 1.648978 0.822339 -12.436193 -65.099872 -33.550138 -27.166747 8.477299 1.044406 0.330047 2.345920 0.377601 0.591096 2.302336 1.364270 1.029822 0.466367 0.738647 0.438633 0.353917 0.783035 1.727181 0.726264
+1 -0.032685 1 1 1.926607 1.652415 2.032326 1.911223 2.274274 1.540178 0.615712 -0.128200 -1.093754 0.304221 0.106269 0.072307 -17.081092 18.092375 28.539402 -38.268748 17.151551 0.866851 1.910835 0.402631 0.519399 1.035050 0.590802 1.866229 2.218212 0.491903 2.410863 0.626477 0.691897 2.220381 0.948377 1.875427
+1 -0.023797 1 1 1.316827 -2.173836 -0.514904 -2.044703 2.137695 0.982139 -0.680769 -0.012053 0.062652 2.123302 -0.581551 -0.638391 21.310483 -34.720258 -43.376600 -30.520994 33.654470 1.085048 1.651836 1.159313 1.072654 0.341693 2.342703 0.311532 1.663810 2.154786 0.983467 2.129702 2.398090 1.950226 0.953616 2.178191
+1 -0.040648 1 1 -1.894143 2.039975 -1.488227 0.729215 -1.002732 -1.417373 -0.661552 -2.177760 -0.479448 0.101682 -1.623525 -1.849116 3.623220 -4.545565 -47.307598 51.192657 -5.015593 1.418906 1.301431 2.399463 0.282009 0.473386 1.701582 2.487345 1.311491 0.479151 1.847541 0.874276 0.707511 1.387394 0.431647 2.193545
+1 0.040016 1 1 -2.286447 1.210563 -2.169707 -1.806382 2.061741 1.488025 0.582644 0.160722 1.052058 1.047432 -1.298057 1.922113 48.551030 -2.845012 33.883085 73.014115 -1.762055 0.402168 1.737043 2.232543 0.604038 1.567985 0.380551 0.677299 2.111809 0.925060 1.479223 0.303614 1.340696 0.821181 1.592661 1.110810
+1 -0.068188 1 1 0.746045 -0.891873 0.402712 1.391265 0.117990 -0.858607 -1.275335 2.105939 -0.227625 0.762900 -0.343754 -0.076772 28.133529 40.226326 33.855690 62.589986 -0.107849 1.185709 1.460090 0.482615 1.562721 1.902257 2.488597 2.092385 0.718845 0.629659 2.420379 0.803609 1.009548 1.721625 1.848878 0.846917
+1 -0.026631 1 1 0.444259 2.234548 -1.696165 -2.210670 -2.260952 0.878326 -1.882849 -1.358118 0.931865 -2.127378 -1.950383 -0.702609 15.972086 -57.146438 -10.185311 -34.516599 -70.486612 1.847585 1.614026 2.442131 1.891349 1.406779 2.236017 0.490927 1.752154 1.953505 2.051522 2.429004 1.770981 1.132825 1.396127 0.952813
+1 -0.006500 1 1 -1.609156 -0.681083 -0.575992 -1.455317 -2.211222 -2.101172 0.247288 -0.164759 1.779198 -1.842692 -0.303845 1.507485 -70.512234 50.877710 -48.320570 -23.819491 15.809499 2.278670 1.851694 0.913858 2.207302 1.618263 1.649440 1.382618 1.152751 1.028582 2.133138 1.650215 0.913434 1.840209 1.389477 1.692977
+1 0.010557 1 1 2.066264 2.107782 -2.242546 -0.781872 1.926994 -1.258938 -0.351433 -1.909880 1.444180 -1.176525 -0.680101 1.796980 4.342520 -65.264496 49.623669 25.011483 68.002179 2.314368 1.075720 2.373674 1.096873 2.395217 0.906372 2.400255 2.335242 0.912405 0.294729 0.511651 1.313767 0.482975 0.859765 2.074266
+1 0.026737 1 1 -2.216539 -1.934278 1.357498 -1.910967 2.029321 -1.479102 -1.419450 2.132115 1.452680 0.301290 -2.042018 0.139499 -70.173808 38.807791 42.548630 64.824784 60.139325 2.299411 1.704811 0.515554 1.669178 2.375664 0.784157 0.329942 0.578753 1.855421 0.553963 1.457823 0.636747 2.311906 2.456682 1.211605
+1 -0.002829 1 1 1.553520 -1.333963 1.630850 -2.276254 -1.828949 -0.224819 0.801563 -0.849291 -0.199688 -0.927125 1.677768 -0.688022 19.738400 -56.712319 -63.941043 -57.106652 58.505549 2.166335 1.599186 0.516472 1.349125 0.748620 1.550742 0.815146 1.401822 2.171659 1.079063 2.319381 2.087460 1.184792 1.803898 0.859731
+1 0.014376 1 1 1.904751 1.895392 0.110673 -1.311896 0.232535 1.648414 0.765112 -0.872565 -0.240920 -1.203002 2.015414 0.412941 -33.550533 -33.810161 -47.374167 -17.617352 5.171968 0.253878 2.425021 2.333759 0.737612 1.052958 2.318851 2.180290 2.139835 1.714622 1.155877 1.819402 0.437044 0.648944 0.304627 0.364499
+1 0.001452 1 1 -1.910866 -0.998533 -1.533420 -0.132538 1.400637 2.129232 0.116732 1.552808 0.827239 1.863803 1.681101 -1.220288 -33.756086 -38.533123 73.799668 1.014527 -48.846800 1.102443 1.508638 1.931316 0.373139 2.090491 0.378604 1.697329 0.753341 2.150376 1.123718 1.323549 0.645961 1.921637 1.950341 0.640044
+1 0.008860 1 1 -1.328853 -2.013876 1.882532 0.735906 -1.647338 -1.530489 1.999005 -2.050785 -1.126392 -1.604528 1.695496 0.380690 -37.399457 -72.680145 64.806695 56.129489 18.323447 1.557557 0.615762 0.613175 2.130842 1.306373 2.209120 0.678095 1.986554 1.757734 1.227100 1.878837 0.370412 1.259830 0.713305 2.017434
+1 0.015280 1 1 0.031234 1.882503 0.250037 -1.076296 1.558413 0.788685 -0.522018 0.907849 -0.500764 -0.018777 0.141062 0.501677 38.864528 -53.886148 35.509036 -49.624167 -33.366524 2.257481 1.238707 1.195055 1.041361 0.904936 0.767583 0.763200 1.356574 2.193742 0.972952 0.911051 2.282521 1.324384 1.172498 2.168614
+1 0.045153 1 1 -1.289263 -1.082146 2.195772 1.618116 0.482981 -1.978263 1.947722 -1.609620 0.943016 1.508909 -1.840307 2.079865 -6.640135 -0.753630 -66.260773 -44.806097 -56.074483 1.467479 0.914849 0.864390 1.057364 2.119222 1.759244 1.864385 0.464661 1.304121 0.364203 0.403572 0.586734 0.982559 0.370724 2.001001
+1 -0.021952 1 1 1.891576 1.937065 -1.639552 2.100009 -0.945307 -2.318358 2.097852 0.503092 1.442330 0.712152 -0.331563 2.179223 48.061803 24.717442 -73.950863 7.839290 54.953259 2.116380 1.257423 0.756501 1.268412 0.951228 0.292705 2.495671 1.744796 2.030762 2.261207 0.863668 2.419957 0.463547 0.579398 1.437043
+1 0.014467 1 1 0.019899 -0.144591 1.454567 -0.972030 0.945793 1.052225 -0.856883 -0.564567 2.080575 2.290542 1.629179 -2.076396 62.519209 10.339591 -72.498870 -38.503191 -23.128751 0.251132 1.276583 1.023879 1.837018 1.758605 2.371707 1.776673 2.293138 2.018221 0.741552 2.014641 1.319183 1.509867 2.342643 1.549823
+1 0.001103 1 1 -1.853381 -0.884483 2.088376 1.462945 -1.536384 1.891038 2.326319 -0.253133 0.879051 0.877821 -0.956610 0.924576 -67.178425 -17.796459 -5.090311 -52.848324 -71.778444 2.420319 2.056093 0.512107 2.228581 1.502326 1.599097 1.270841 1.280504 1.688140 1.572556 0.696925 1.222876 0.624934 1.763373 1.507281
+1 -0.042934 1 1 2.245422 1.994933 0.195982 -0.087904 2.292239 1.886312 -1.700238 0.026876 -0.677934 0.527674 -0.101757 0.369464 -43.052347 19.211191 -67.519804 -55.348460 58.425436 2.219542 0.347917 1.188272 1.784820 1.970424 0.668090 0.340424 1.262838 1.762562 1.380582 0.694319 2.412516 1.407151 1.730251 0.573277
+1 0.004766 1 1 -0.283817 -1.177413 -1.456831 0.615257 1.643497 -1.769237 -0.398858 2.125174 -2.113775 0.486740 -0.064115 1.557891 45.943900 -20.866082 3.759020 27.842067 -58.380762 0.542998 1.671879 0.528436 2.166850 1.238957 0.908475 1.738061 1.347404 1.069905 1.398668 0.912044 0.977417 1.689655 2.282690 1.919365
+1 -0.038321 1 1 -1.452797 -2.269291 2.098976 0.540981 2.064666 -1.184102 -0.776598 1.037051 -1.418833 -1.632189 -1.386400 1.543868 43.833642 62.013984 69.031042 -45.275583 3.280635 0.439441 0.434479 0.296462 0.383821 1.632657 0.566233 0.677457 0.263228 2.079811 0.889178 1.409970 1.858578 1.869065 0.379504 1.069306
+1 -0.042960 1 1 -1.718714 0.518578 -2.186914 1.166346 -0.760575 1.733523 -1.372553 -1.347426 1.554362 -1.316279 1.968028 0.395921 11.080073 72.786519 73.027576 74.465018 -66.435849 1.565174 0.373306 0.402630 0.510488 2.029279 2.084143 1.693054 0.912712 0.956869 0.600568 1.738996 1.312939 2.322519 0.831262 2.269887
+1 -0.066920 1 1 -1.634089 -0.329792 -1.048305 0.761827 0.467762 1.406381 -0.300981 -2.196901 -1.742048 -0.528803 -0.023650 -1.647629 -54.302467 -61.559744 65.378119 60.050736 72.715058 2.454712 1.849195 1.669478 0.662883 0.582669 2.410821 2.164637 2.303915 0.893906 2.134278 0.564115 1.083575 1.650407 1.893972 0.482247
+1 -0.026776 1 1 -1.862563 0.309963 -2.352711 -0.353895 -0.872807 0.404096 1.089917 1.179658 1.491375 0.350220 0.375549 1.959023 -5.082617 -73.551225 -25.441867 48.534339 16.640696 0.327593 1.614024 2.402193 1.154016 2.052820 1.744394 2.029714 0.403426 0.384828 0.554872 0.979445 2.033133 1.621724 1.314380 1.786652
+1 -0.010874 1 1 -0.388511 1.669464 1.124013 -0.686242 2.260046 -1.981231 -0.807772 0.162779 -2.072800 1.142902 1.051206 0.869943 -45.036565 -29.554376 -70.399527 -4.853701 23.846901 1.298005 1.077922 1.138840 1.235097 1.268778 0.344560 1.024121 1.410144 0.291799 0.772070 1.931393 1.676300 0.566057 2.215197 1.572145
+1 -0.009447 1 1 0.075359 -1.067772 -1.261435 0.097943 1.504874 1.020748 -2.096379 0.682819 1.470575 -0.528818 -0.280231 -2.158415 -16.236443 -35.904913 -3.872482 15.191843 29.305807 0.515583 2.152730 2.437904 0.608989 1.528342 2.352517 0.998748 2.455576 0.614355 1.715182 1.562482 2.382540 1.602153 0.881642 0.757288
+1 -0.032382 1 1 1.836417 -1.489536 2.289124 1.361603 1.094039 -0.233674 -1.946018 1.962570 -1.814823 1.561380 -1.174443 1.334659 20.299216 68.929715 51.713119 42.387802 61.784283 0.751671 1.076331 1.391376 2.105152 1.535900 1.119835 1.318212 0.938536 0.723307 1.365067 0.930611 0.273916 1.702135 0.536833 1.549807
+1 0.037227 1 1 0.687680 -1.649809 -0.635076 -0.156239 -1.104012 2.264155 1.110702 1.804513 -0.484412 1.489991 0.647216 1.568952 -36.658829 -74.932971 1.548722 -70.622645 -4.788877 2.325166 0.319370 0.647048 2.186176 2.054211 0.381346 0.536688 1.367342 0.925295 0.932888 0.294010 1.931421 2.140288 0.316711 0.965625
+1 -0.000864 1 1 -1.812716 -0.723699 -0.534994 -0.400842 1.769759 -0.256307 -0.625031 -0.974149 -1.685247 2.228262 1.049207 0.266910 -7.617961 64.936877 -5.914677 42.029216 35.034242 2.432461 1.379132 1.065785 1.896629 2.387926 2.114694 2.168198 1.412168 0.563784 2.263409 1.871790 1.174171 1.042318 1.232467 2.070396
+1 0.018847 1 1 -1.611758 -2.002617 -2.109121 -1.411072 1.565364 -0.193683 1.036541 -0.553558 -1.385077 0.210150 -2.300817 0.037367 40.600141 16.567921 57.052260 -72.671654 57.516234 0.255257 0.861861 1.301028 2.379046 1.368202 1.871374 0.927420 0.654331 0.841240 1.228407 1.335718 0.417932 1.180149 0.273079 1.135185
+1 0.021730 1 1 -0.130721 -1.059362 -1.291200 -0.652145 0.418745 2.254366 1.520151 -1.399239 -2.192624 -0.554503 1.577258 1.790986 -52.274362 -25.207398 -60.743951 -23.580139 -11.403440 2.010788 1.805657 1.169933 1.821661 2.403501 0.639548 2.127298 2.496897 2.092958 1.348842 0.491653 0.456001 2.016348 0.753850 1.701978
+1 -0.029761 1 1 0.732649 0.161671 -1.851969 -0.716042 0.927424 -1.367901 1.433995 1.994097 0.281786 0.022752 0.697006 -0.421401 7.667238 13.263997 28.000895 61.035308 -29.571358 0.537774 1.613444 1.659021 0.406952 1.147534 1.106760 2.071584 2.109019 1.289389 0.257007 1.015077 2.391890 1.249424 1.312131 2.231831
+1 -0.000418 1 1 2.100668 0.714579 -1.956259 -0.510919 -1.037388 0.459825 -0.040283 1.555924 1.365152 -0.503870 -0.382945 0.974946 30.170411 74.103776 12.155672 0.381157 -43.902123 1.180285 0.305389 1.921888 1.674450 0.984478 1.128552 1.579324 1.943218 2.414204 0.519549 1.307974 2.125264 2.059103 1.592039 1.904089
+1 0.014360 1 1 -1.607469 -0.600536 0.728838 2.081925 1.419089 1.224686 -0.419467 -0.245002 0.875441 1.458923 1.563844 -2.178913 -32.498874 -58.578167 -73.260762 56.376484 -30.429423 2.465227 0.822583 0.398294 1.868847 1.211780 0.877769 0.908973 1.101419 2.304921 2.051171 1.027430 0.774725 1.555656 2.416361 0.774661
+1 -0.029161 1 1 1.500249 -1.308107 -2.063941 -0.760167 -0.845238 1.935187 -0.226196 1.227974 -1.700599 -1.335535 -1.220971 1.587773 -17.913468 -21.651072 10.435127 33.173918 4.034059 1.381343 2.238642 1.856861 2.264222 2.029728 0.635940 2.240976 0.583389 1.016214 1.264990 1.930191 1.712883 1.178526 2.231293 2.084960
+1 0.023838 1 1 -2.173718 1.467407 -1.928896 2.281247 0.915887 -2.065064 -0.778730 -1.817229 -1.176940 1.786506 -1.540984 -0.022464 -18.132916 40.081629 1.934317 -39.932229 -40.976397 0.770387 0.641387 1.540232 1.924398 1.113396 1.091194 1.451358 2.224885 2.387912 1.893151 2.445145 0.803412 2.189837 0.588028 2.489363
+1 0.010929 1 1 1.527490 -0.570540 0.649726 1.347721 -1.301882 -1.108236 1.956772 -0.291733 -2.267290 -1.972319 -1.826806 -1.918476 -53.135553 50.765556 16.705046 -38.286653 16.223349 0.862352 0.557515 0.405181 0.619892 0.267922 2.220283 1.540142 0.411951 1.902953 0.673779 1.448701 0.323063 1.970415 0.509307 2.418894
+1 0.011927 1 1 2.327667 -1.148596 2.212958 -1.701993 -1.192332 2.269361 -0.930073 -0.735803 -1.333861 -1.373401 -1.462623 2.226050 49.972791 42.704657 -12.826539 -25.646255 63.392953 1.305407 1.724814 1.443194 2.255178 0.775896 0.984823 2.422744 2.311358 2.237564 1.734835 1.114821 0.294639 1.242282 0.541035 2.421553
+1 -0.017246 1 1 -1.288314 0.728540 1.784191 1.973416 1.410359 0.589827 -1.649923 2.149549 2.293326 1.298406 -0.763063 2.319433 57.939029 -18.732753 8.615287 47.131570 -9.709329 1.604539 0.490027 2.391288 2.376171 0.313923 1.359679 0.368182 2.032613 1.880030 2.405762 0.399605 1.414919 1.796818 1.115241 0.610312
+1 0.006078 1 1 -0.535192 0.980280 1.059536 -0.495353 1.386377 -1.920016 0.725116 0.791174 -1.097527 -1.843567 -0.879390 -1.848372 -48.485732 50.296076 -73.848267 -67.830381 -25.219006 2.037522 1.134622 2.345953 0.933211 1.221752 1.985370 2.104435 0.741540 1.816923 1.530041 1.652613 0.714360 1.751104 2.306666 2.133350
+1 0.004121 1 1 -1.700737 1.068369 1.866712 -1.258190 -1.918558 1.677461 -1.144085 -2.085247 -0.717835 -0.928865 0.713481 -1.561572 -65.065058 -48.437859 -45.087814 9.113381 18.595708 0.446070 1.596708 1.624578 2.036494 1.854427 1.861427 0.251195 2.341560 1.344170 0.709038 2.304631 1.689921 2.257432 0.412812 0.624001
+1 -0.006785 1 1 1.637626 -1.490730 1.077685 -1.769698 1.287460 -0.953532 0.829023 -1.146718 0.783853 -1.615210 1.243056 2.023525 2.294741 17.716318 8.158465 19.317756 73.519365 0.474554 1.085387 0.600709 1.859741 1.160879 0.397705 0.982599 1.039526 1.562687 1.323615 1.742230 1.662889 2.421341 1.233960 2.422938
+1 -0.006107 1 1 0.056968 0.845946 0.540025 0.144776 1.661943 1.943601 -0.187399 -1.742836 0.371958 -1.842696 -0.364514 -0.281628 -66.125486 -21.042342 41.363599 -51.998718 -42.449552 0.630636 0.855871 1.881777 0.270237 0.628416 1.788952 1.672593 1.277874 2.475742 2.041480 2.407303 1.546257 1.940377 1.919514 2.275475
+1 0.010251 1 1 -0.742231 -0.974720 -1.847805 -1.419970 -1.900399 0.566646 -0.118849 0.549416 -2.241187 -1.500491 1.958840 1.474560 15.417674 74.847976 69.937750 43.765362 -35.568497 0.629067 1.486444 2.421613 1.291238 2.081013 0.838912 0.336562 1.605478 0.521158 1.344989 0.975872 0.483184 2.131033 2.266290 0.781971
+1 0.030900 1 1 -0.523829 -1.254478 -0.778244 1.636956 1.386441 -0.842541 0.143045 0.835885 1.087156 1.902033 -1.385366 0.076463 -43.580236 -3.029446 -65.905031 -65.851301 -62.822511 1.255842 1.189093 2.079706 1.363294 0.387578 1.766017 0.952968 0.282471 1.485597 1.675822 1.546010 2.294296 1.223943 0.561200 1.580488
+1 0.068111 1 1 1.983843 2.295676 -1.612770 -0.159839 -0.344959 -1.483680 1.756765 -1.880181 1.070876 1.601224 -0.679611 0.616668 57.108753 -23.183579 53.589754 -67.005592 37.010580 1.177313 2.100376 2.275687 1.218457 0.606260 0.668010 1.244579 0.880175 0.854541 2.027946 2.191871 1.033958 2.473813 1.116944 2.225440
+1 0.020009 1 1 1.083774 1.603003 0.946726 -2.115537 -0.861330 0.088583 -0.300388 -1.657899 0.050462 -0.107282 1.759002 -1.979256 -19.391829 31.524424 30.994199 -30.504681 7.834098 0.890415 1.953807 0.384438 0.743776 1.142435 0.912167 0.789328 1.740706 0.794059 0.257171 1.527893 1.539749 0.567732 1.115139 1.142187
+1 0.020763 1 1 0.093552 -1.606822 0.849203 -1.276175 2.116211 -1.951927 1.619524 0.574304 1.358689 -0.745186 1.184393 0.969294 6.401777 44.659040 -15.508973 40.686674 -29.063358 0.357197 1.906422 0.482147 0.447126 1.346720 0.822527 1.706001 0.252039 0.769889 1.266548 1.116780 1.720125 1.394890 0.408976 1.409992
+1 0.007491 1 1 1.256311 -1.389437 2.334036 2.216760 0.938156 -0.067791 1.037693 -0.041196 0.338283 -2.334198 -0.229685 -0.866786 -66.134691 -25.755574 26.060027 -9.128934 20.012559 2.141097 0.421064 2.071043 2.017797 0.370268 1.097369 1.736070 1.626979 1.888416 1.615550 1.052895 1.255829 0.961562 0.730244 0.966466
+1 0.031978 1 1 1.274695 1.282475 0.083118 2.096921 -1.011993 -1.560819 1.189330 -0.878145 0.220953 0.196669 2.024732 1.513409 -51.356268 -44.802334 7.172364 -54.084320 4.833244 0.360069 0.685924 0.828089 0.698816 1.496783 0.675856 0.358601 0.756658 1.656924 1.167283 2.270582 0.923297 1.096312 1.960208 2.209716
+1 0.035147 1 1 1.253430 2.020713 -0.064011 -1.401696 -1.078138 -1.133634 -0.795310 2.268257 -0.635775 2.227318 -0.676321 -0.637431 -65.024163 38.890717 -63.726836 -56.940008 9.279009 0.659656 0.344292 1.014706 0.671412 2.167145 1.707096 0.655815 1.029663 2.293236 1.415187 1.790613 0.337433 0.485645 0.731774 1.925895
+1 -0.012139 1 1 0.794344 0.333789 2.251236 0.747896 1.952824 -0.676240 0.723585 -1.387792 1.708130 0.664319 1.553968 1.473626 -34.568752 -47.016882 -12.729881 -51.115048 -40.615488 1.757447 0.912692 0.612501 2.056351 0.349215 0.498485 0.531306 0.908104 2.259729 0.766955 1.464929 0.817244 0.668962 1.496248 0.687208
+1 0.021868 1 1 -1.842642 0.545006 -0.972495 -2.158208 -1.740657 -0.713460 1.912457 -0.545301 0.716068 -0.480944 -1.476199 0.253184 -0.699527 -56.943103 -42.737780 56.132198 63.852959 0.275142 2.058486 2.476324 0.582321 1.068151 1.154659 1.601302 2.329696 2.195546 2.039511 0.810443 1.110703 0.832696 1.619137 0.583280
+1 0.020900 1 1 1.547321 -1.849753 -1.167440 1.224229 1.331024 0.803174 -2.056882 0.066879 -2.229923 -0.691536 -1.892189 1.897202 71.636883 -48.903424 -69.847972 -34.860543 -1.145082 0.694225 0.839686 2.099788 1.378873 1.220189 0.473993 0.654974 0.399619 1.643242 0.714480 1.517108 0.289936 0.952801 1.976353 1.322040
+1 0.008765 1 1 1.614908 -1.603893 -1.757386 0.864236 1.629046 0.389873 -2.344785 0.912310 -0.912602 0.721086 -0.973379 1.834469 -39.409167 50.135705 -69.211100 19.045164 -7.936630 0.760778 1.144118 2.197102 1.188909 1.250115 1.690576 2.004952 0.484257 2.155486 1.501202 0.696607 0.377247 1.382574 0.421365 0.374974
+1 -0.011996 1 1 -1.447150 -1.601392 -2.141962 -2.023231 0.160695 0.594771 1.344146 -0.121797 -1.861868 -2.154990 0.499900 -0.378448 36.470448 58.817550 46.562016 17.797384 20.629958 0.290554 2.333889 0.671222 1.233730 0.804079 2.162985 1.545252 0.805582 0.421352 2.407745 2.219523 2.276089 1.222886 0.788366 1.318349
+1 -0.023381 1 1 -1.883502 1.809712 2.071432 -0.565500 0.527686 0.106251 -0.228420 1.540958 -0.401408 1.682733 -2.069582 -1.314105 25.853293 -33.712873 -62.258578 20.078892 -34.054290 2.118332 0.310507 2.440986 0.658015 2.016266 1.634302 1.207124 1.385145 0.877267 1.468996 1.671841 2.136452 1.102279 1.006687 0.890791
+1 0.004198 1 1 -0.297446 0.664503 -0.064335 -2.149266 -2.250440 -1.504563 -0.519543 0.099954 2.310309 -0.723194 -1.474031 -1.004099 -26.083228 69.182042 -57.422345 2.649815 -14.564813 1.512773 1.681418 1.086106 1.430604 2.159979 0.525015 0.934552 1.271187 0.337674 2.292711 1.599427 2.324137 1.029419 0.450669 2.392126
+1 0.055356 1 1 0.333556 -1.675510 0.937139 1.697132 -0.384995 -0.504155 -0.461937 2.239061 -1.245470 -0.178428 -1.765311 -0.377702 -14.099449 30.565229 -40.192044 -57.677212 69.103782 1.034030 1.436937 0.598911 0.889505 2.412815 1.932026 1.060786 1.125661 2.488207 2.288703 1.731005 2.005834 1.794320 1.893701 0.426044
+1 -0.028597 1 1 -1.646985 -0.309037 -0.932996 1.961808 -0.480675 -1.668797 0.665399 0.863200 -1.636628 -0.599446 0.195368 -0.987490 9.163660 -36.359506 5.785186 31.619499 -21.084642 0.331455 1.256416 1.827578 0.594431 2.102889 1.756384 1.046388 2.144559 2.347362 2.119293 0.701642 1.751404 0.596932 1.382945 2.165809
+1 0.002567 1 1 1.383866 -1.721762 1.120173 0.760572 -1.775863 1.347196 -0.702039 0.658804 -1.590269 1.023651 -0.429942 -1.934728 -47.627604 72.855743 36.477238 22.936579 -4.910843 0.826933 1.505966 2.023912 1.891862 1.031442 0.694320 2.433788 1.176859 1.215516 0.684335 1.119595 1.778403 2.111705 1.434800 0.683958
+1 0.005926 1 1 -2.187845 -0.334835 -0.984610 1.566078 -2.338067 0.715143 -1.890697 -1.312985 0.771833 -1.017287 -0.998783 -1.018630 -0.222430 11.621828 28.060823 18.246770 73.458611 0.908240 2.292462 1.906698 0.630465 2.468522 2.204633 1.760042 1.784509 1.236315 1.490558 1.807554 1.550923 1.605485 0.629649 2.254692
+1 -0.017303 1 1 1.994073 -0.118077 -0.602577 -0.589020 1.064273 -0.995601 0.626411 0.607633 0.733445 -0.606835 -1.472519 0.831506 -57.911196 36.521105 10.212260 37.460285 45.014499 0.755370 2.495985 0.273915 1.682113 1.530286 1.272492 2.021417 0.448761 1.822612 0.384796 2.270834 0.649818 1.487269 0.535985 0.792360
+1 0.009235 1 1 -2.008679 -0.320703 0.910130 0.135345 -1.348882 0.644652 0.890805 0.504140 0.210557 -0.172980 0.275302 -0.572251 4.968058 -51.849486 65.683831 -51.851755 27.546716 0.289906 0.450583 0.946488 1.628515 0.703202 0.972860 1.605020 1.821020 0.629831 0.811919 1.169239 1.396393 0.922678 1.948372 1.281596
+1 -0.066210 1 1 -1.946790 -1.587241 0.073641 -1.669114 0.048609 1.731348 -0.233473 1.435776 -1.065217 -0.730886 1.202516 -0.741683 -38.127940 -16.288216 -6.038299 64.303097 -7.848204 0.553504 0.491203 1.903007 1.593144 2.475559 1.219163 1.216074 1.059877 1.609252 0.945988 2.212030 2.334296 0.753766 0.294499 1.151139
+1 0.027767 1 1 -0.361861 1.898826 1.263163 0.672351 -0.107144 -0.637340 -0.518322 1.761229 -2.256540 -0.360012 -0.020647 1.696631 19.667813 -43.058807 60.634405 -17.562272 30.895663 0.826229 0.922971 2.379160 1.047727 2.144969 2.496962 0.945831 1.825103 1.754643 1.035967 2.493526 1.684989 0.361683 0.812623 1.753097
+1 0.007558 1 1 -2.285998 -0.656213 -1.986282 -0.870137 -1.842308 1.440726 2.024891 -0.531053 -0.142873 2.048570 1.600841 2.302591 48.120213 -43.588191 13.274644 56.944567 67.330971 1.849546 0.812969 0.813489 0.558441 2.469663 1.127425 0.639995 0.651254 0.882022 0.386602 1.125006 0.469819 0.254630 1.566830 1.218342
+1 -0.004811 1 1 1.320468 -2.242958 1.712727 -2.178235 0.959288 1.673295 -0.464498 1.614649 -1.236368 1.994874 -0.793569 -1.456352 -23.995729 53.789743 -5.782307 16.766247 -59.693942 2.483704 0.872218 2.124951 1.304672 0.626640 1.192000 1.435104 1.285839 1.351296 1.227387 2.200695 0.827838 0.971256 1.644184 0.793472
+1 0.047021 1 1 -0.399600 -0.927778 0.137929 -0.317342 0.850640 -0.683309 -0.284731 2.314311 0.564194 1.079651 -1.711654 1.365908 -61.820018 40.953852 -38.604166 -70.220967 -3.788190 0.353484 2.497492 0.844812 0.498649 1.041850 2.377121 0.513592 2.446763 0.989595 1.617803 0.660649 1.285208 1.993012 2.306298 0.444304
+1 0.037629 1 1 1.527725 -1.334349 -0.150381 -1.608784 0.861454 1.995999 -0.741703 -1.527577 -0.885702 0.436174 -1.706555 2.242197 -11.879146 -2.806820 -74.214543 -73.831737 59.993205 1.461994 0.987063 1.822268 1.363461 0.944910 2.100815 0.654349 1.137429 2.275999 1.969137 1.532174 1.506249 2.283485 1.788686 1.696812
+1 0.011277 1 1 -2.063706 -1.527407 1.968990 -2.299766 -1.146941 1.752868 -1.398245 0.373161 -0.472816 -1.538745 -0.095870 0.343479 5.833143 -62.365036 30.833527 -30.911999 62.028296 1.518494 1.082925 1.967091 0.892771 1.059023 0.756732 0.637059 0.796632 0.742815 0.748395 2.268345 1.581936 0.850165 0.472715 1.666854
+1 -0.019070 1 1 1.330690 -0.090039 -0.603089 0.235907 1.771596 2.334059 -2.102589 -0.012765 2.222047 0.257585 -1.452797 -2.262726 -21.128584 -58.117946 11.678895 -62.805885 -28.509603 0.461524 0.332876 0.403898 1.557548 0.454725 0.808762 2.106831 0.506596 1.857251 2.069137 1.484769 1.267603 0.854430 2.404137 2.335790
+1 0.004543 1 1 1.851581 -1.090968 -0.000366 -1.446333 -2.023845 -0.730188 -1.207337 -0.163010 -1.814483 -2.153276 1.038434 -1.730212 15.097993 -48.025349 -12.039516 1.850305 48.082361 2.428663 0.541521 1.599837 2.463401 1.627424 0.358400 1.883204 1.753336 1.566020 1.093668 0.281584 2.335514 0.989968 1.148752 1.319648
+1 0.016123 1 1 -0.767077 0.832371 -1.419527 0.839034 2.176549 -1.009704 -0.780395 -1.519784 -1.865433 -0.813219 -1.848108 -1.786560 19.995637 66.676586 -16.625733 21.303605 -0.303210 1.434295 1.192581 2.200693 0.790013 1.999126 1.553661 0.387385 0.776094 2.064237 2.380314 2.432571 0.975523 1.362110 0.737537 2.033061
+1 -0.019586 1 1 0.687801 0.378567 0.850610 -1.185848 -1.858203 -1.823733 -2.106306 -1.212346 0.466069 1.224817 1.777676 0.849171 -57.414180 -10.117148 61.088941 -28.172018 62.896080 2.041274 1.185272 0.858459 0.362279 1.814864 0.664024 1.745847 1.696601 2.020244 0.997935 2.285400 2.460370 2.438701 0.497416 0.571954
+1 -0.013499 1 1 0.190995 0.920938 -1.998089 -1.402103 1.505344 -0.497872 1.464510 1.214937 0.663722 0.944671 1.042882 2.338985 18.166816 -70.327034 13.542943 66.244568 72.457839 0.608387 0.405231 1.471990 2.477491 2.188638 0.687917 0.578116 2.389104 1.668130 0.514467 1.389073 1.643133 1.143869 0.256257 1.912959
+1 0.017127 1 1 -0.517654 -1.140284 0.535760 -0.856742 1.801822 1.416602 1.839509 -1.347097 -2.339093 2.332949 -1.919635 -2.292565 65.789963 -68.086414 21.645168 40.340990 11.017335 2.400255 2.341106 0.467093 1.682017 2.155262 2.239620 0.288145 2.357944 2.213655 0.403623 1.435468 0.663763 1.867692 2.043882 2.280251
+1 0.010547 1 1 -1.337369 0.927274 0.819253 -0.414931 0.597295 1.344275 2.036141 0.058534 -1.104095 0.866848 -1.585629 -1.111711 2.948449 54.579318 64.597670 -6.964883 -58.788027 1.369418 2.051297 0.893438 1.014968 0.561013 0.693879 1.769872 0.495920 2.421604 1.143689 1.731978 0.350674 0.270288 1.477943 1.288358
+1 0.003394 1 1 -0.405018 2.263208 -0.661922 1.023847 -1.854325 2.103264 1.923442 0.293423 -2.318819 -0.931686 0.418864 -0.454026 -46.292948 4.419649 31.039350 -21.643482 -11.998185 0.572583 1.653156 0.836698 1.381586 1.814163 2.390619 2.379814 0.781388 1.045876 0.290323 0.702687 1.306322 1.353782 0.261882 1.947595
+1 0.037030 1 1 0.951363 0.427670 1.451233 -0.456434 0.481857 -2.033449 -1.931925 -1.498872 0.884241 -1.438492 -2.171874 -0.525053 55.406643 19.440662 39.213615 -36.765865 -73.885774 2.151932 0.276832 1.210787 2.199461 0.338043 1.746708 0.413124 1.374364 1.938258 2.304026 0.519705 1.683843 1.342022 0.606582 1.570377
+1 0.006726 1 1 -1.543523 -0.282345 0.002560 0.619230 -2.276040 1.773098 -0.690617 -0.588578 -0.932066 -1.246892 -0.517849 0.294832 -69.855057 -3.951273 40.947859 10.669287 68.714962 2.010615 1.163553 0.333583 1.031233 1.679638 0.430813 1.677557 1.446972 0.507824 2.240280 2.388064 2.186925 1.146274 2.428863 1.657615
+1 -0.045580 1 1 -2.179560 2.244065 -1.956055 -1.796999 -0.454965 1.617388 -2.327884 2.224565 0.169753 2.035804 -0.901654 0.949947 6.083216 -59.395780 -14.874649 51.768836 -71.170290 0.489128 0.771952 2.192067 2.072465 1.166248 0.628040 2.213822 0.949896 0.407372 1.444824 0.400014 1.534178 1.434235 2.445769 2.291652
+1 0.006097 1 1 -2.308907 0.718996 1.593028 -1.772617 -0.645811 -1.521075 0.004717 -0.824523 1.379447 -0.581564 -0.845957 -0.719119 33.266745 64.182030 57.377183 -11.690629 15.604859 2.437926 0.978926 2.306513 1.804886 1.723184 1.047354 0.377174 2.420101 0.639919 1.615051 1.665958 2.257841 0.530363 0.803297 0.259291
+1 0.055614 1 1 0.436505 -0.850703 -0.379229 2.152362 -2.264041 0.800982 -1.193266 0.702458 1.671730 1.506270 0.930801 -1.154398 -34.006906 -54.063702 51.357874 71.791568 0.890048 0.760569 2.127200 0.857204 1.775387 0.922296 2.275826 1.308050 1.150919 1.745112 0.603728 0.853017 1.161565 0.666145 1.393454 1.033453
+1 -0.001171 1 1 -1.676155 -0.475350 -1.702182 0.341182 -0.730421 -0.409523 1.946390 -0.421987 -0.191285 -1.069635 0.404519 -1.234440 44.987683 -42.011302 -33.949903 3.981333 14.272060 1.682718 0.433474 1.402739 1.833927 1.558156 1.673543 1.482016 2.236672 2.491335 0.861043 1.053353 2.204998 1.148919 1.888039 2.022458
+1 0.003781 1 1 -1.100779 0.042744 2.112901 -1.034993 -1.699128 -0.168765 0.428485 1.021072 -1.360317 1.667615 -1.687418 -1.270363 26.592505 -59.771167 -24.006746 18.618238 16.727115 1.864351 2.141759 0.290722 0.671210 1.025940 0.475804 1.841681 1.384250 1.585429 1.054955 2.123184 0.861290 0.706514 0.376498 2.308209
+1 0.026739 1 1 0.166638 1.521531 -1.758564 -0.081992 -2.028937 -1.500186 -2.343182 -0.416177 -1.498363 0.010889 -0.775055 -1.306510 39.010332 -3.352886 48.045235 46.261094 60.200344 1.932694 1.033705 0.485405 1.202970 1.324080 0.556247 1.601518 1.459437 0.751313 1.820457 2.423902 1.514755 1.240488 1.885901 2.087695
+1 0.005341 1 1 1.927664 0.572038 0.971047 1.386395 -1.613868 0.231161 2.109604 0.102931 0.516575 1.854765 0.589626 -0.316783 26.215804 59.011113 -0.218595 -73.923325 20.668855 1.096574 1.862276 1.026147 1.696586 1.766318 1.504398 0.420721 0.806840 1.305683 1.866616 1.959381 1.821660 2.387177 0.784606 1.123497
+1 -0.001408 1 1 2.221948 -1.398330 -1.052949 -1.901575 -0.344619 -0.488418 0.138320 1.531859 2.181899 -0.637657 -1.128621 -1.373088 -29.183573 11.687051 74.272190 -7.304054 -59.240690 2.000811 0.627196 1.531337 0.930953 1.523204 1.486110 1.295643 1.865306 2.456364 0.358879 0.923483 1.982305 2.342881 1.050997 0.863129
+1 0.038276 1 1 -0.773998 2.326351 0.283816 1.155469 0.208124 1.339599 -1.157313 1.785701 -0.923984 -2.085338 -2.242860 -1.341386 -19.300122 72.850369 -53.855107 -42.791058 60.680116 1.385605 1.864578 1.455764 2.022174 1.923862 1.098105 0.601694 0.424556 2.269458 2.280739 0.624170 2.425431 2.469958 1.588573 2.141206
+1 -0.002643 1 1 2.237071 -1.701827 1.589852 1.402866 1.891190 0.159560 0.372441 1.567785 -1.911651 -0.046988 1.960915 -1.353922 24.106401 6.282699 -6.684845 -2.194257 21.125339 1.428534 1.121373 2.414061 0.369327 1.022955 2.062632 2.402044 0.904601 1.874990 0.951007 1.076221 1.790829 1.712261 1.968566 0.931479
+1 0.001364 1 1 0.810533 -0.885449 -0.009317 -1.080460 2.252310 -0.051043 -0.216520 -1.086962 1.355362 -0.120128 -2.087395 0.883510 13.220854 52.893261 -72.959704 16.250998 -19.482698 1.439307 2.178892 1.145537 1.285346 2.059361 1.433725 0.623600 1.840179 0.892383 1.287478 1.895934 1.967588 0.252678 0.258375 1.516050
+1 -0.010591 1 1 0.989245 0.940765 1.369586 -1.386677 1.593663 -0.516318 -2.253565 -2.193246 -1.575317 -2.145750 0.295374 2.204881 -25.329808 -18.076117 -55.294242 69.681306 -66.295627 0.915888 0.324165 2.492208 2.043157 1.346038 0.616231 1.738068 1.453271 0.631566 0.721861 1.822379 0.969837 0.300569 1.905213 0.422390
+1 0.013988 1 1 0.615730 0.172527 1.541058 1.274018 -0.679872 0.939640 1.316318 -1.308082 -1.634426 -1.282862 -1.883932 -0.706407 -66.112995 38.890231 -71.891696 -33.737489 -25.973371 0.858404 1.702986 1.327139 2.481974 1.032907 0.567465 1.130359 0.451528 1.076283 0.596227 0.780299 0.729672 0.339744 1.082850 0.708904
+1 -0.022966 1 1 -0.345062 1.494274 1.949498 -0.028647 -0.806559 1.706588 -1.681533 -1.335257 -1.268480 -0.499188 -1.791864 1.025396 20.038738 41.076324 69.776342 30.979857 28.459973 1.026483 0.599832 0.634325 2.102497 1.911126 0.796933 1.306361 2.007141 1.266627 2.452201 2.394454 1.586621 0.839636 1.266479 2.208649
+1 -0.012254 1 1 -0.218255 -1.969891 1.294042 1.293515 1.858543 -1.895791 -2.103747 -0.626844 1.529665 -1.719503 1.390793 1.600614 -47.809136 21.847822 -3.662240 -51.271700 26.543022 1.503542 1.785377 2.328428 1.131564 0.446482 1.778216 1.230679 1.262853 2.024254 0.892489 0.808378 2.411640 2.428460 1.623304 0.865870
+1 -0.041762 1 1 1.742134 1.974497 0.729365 1.520511 -0.054015 1.665064 -2.142767 -1.406305 1.570495 1.224940 -0.866728 -1.097720 -12.170262 54.412433 -40.230633 43.752350 45.754137 0.471683 2.328425 1.083596 2.001379 1.173196 0.414020 0.682455 1.023401 0.556036 0.296528 1.503968 2.195701 2.389071 1.112926 2.190891
+1 -0.002640 1 1 2.208384 1.530281 -0.787056 -0.373967 1.068240 -0.286653 -1.714521 0.305940 0.710230 0.360624 0.883500 0.252885 -10.700254 10.823655 -36.823671 4.565181 -72.995248 1.657940 2.497612 0.608844 1.334396 0.698760 0.558082 0.934893 2.489553 2.415848 1.154893 1.038255 0.454030 0.380007 0.525923 0.443249
+1 -0.002947 1 1 2.135789 1.942967 -1.405120 -2.074106 -1.956876 -1.450004 2.250407 0.949985 0.831879 -0.275395 -1.000424 -0.318003 -26.472870 -29.522653 12.771096 -6.190227 60.860906 1.963590 0.549502 0.728930 1.381724 1.883030 1.090330 0.425122 0.520326 0.867882 1.238681 0.754980 0.454418 2.406571 0.485327 2.144632
+1 -0.003608 1 1 0.918222 -0.516116 1.151169 -1.373347 -0.554947 -1.183344 -2.187790 0.580069 -0.711714 -1.726809 1.119990 -2.315590 47.897517 -36.424459 -35.877104 13.509681 -42.791814 2.094722 1.736033 1.003345 0.964191 2.149958 0.840445 1.364475 2.222499 0.538807 0.980083 1.511301 1.688652 1.183096 0.295289 0.925934
+1 0.000638 1 1 1.080668 1.235185 1.675802 -0.750123 -1.669197 -1.342464 0.118330 0.136249 -0.287432 -0.663065 0.670626 -0.818318 63.482870 6.596758 21.714420 4.257886 12.294848 0.467696 0.574058 1.692814 1.381250 0.665090 1.665137 1.958254 0.866166 1.653912 2.299631 0.898703 1.753686 0.708049 1.429592 0.898063
+1 0.075080 1 1 0.106521 -0.417515 -0.421447 -0.541149 -0.182997 1.561784 0.893020 0.029950 -0.860894 -2.017218 2.256173 -1.089659 -49.389218 15.409694 -59.274079 -69.445217 -15.762159 1.155861 1.548553 2.275925 0.726658 1.434849 1.505522 1.302467 1.809527 0.971707 2.481217 1.807401 1.234891 2.310886 1.062661 1.135939
+1 -0.014903 1 1 -1.180057 1.226870 -1.415264 1.798729 1.264537 0.193827 1.390259 2.052086 -0.566767 -1.919189 0.495920 -1.293597 46.818589 -19.982723 0.367809 31.758524 65.513902 0.507314 0.427303 1.177723 2.236311 0.937247 1.555025 0.806369 2.395449 0.302419 1.509455 2.159585 0.649241 0.786377 1.638937 0.355926
+1 0.011147 1 1 1.410980 1.593196 1.048735 1.753997 -1.278186 1.307420 -0.066324 2.127751 -1.212572 1.378176 1.617048 1.383675 -7.004086 32.334207 -8.988791 -24.612655 35.104650 2.182878 0.634161 1.587867 1.529385 1.867092 0.961185 1.127978 0.919373 0.403224 1.488111 1.188093 1.030263 1.133365 1.462590 2.002141
+1 -0.050603 1 1 -0.632955 -2.220143 -1.255699 2.249229 0.003610 -0.593144 -2.271111 -0.219394 -2.264138 -0.832326 2.187940 1.940408 -63.748530 28.464666 55.649466 50.573307 -64.434590 2.092630 0.323791 0.712615 1.673081 0.465103 1.991105 1.752772 1.094172 1.998644 2.451608 1.430654 0.756425 2.231416 1.916964 2.158905
+1 0.000997 1 1 1.353381 -0.423061 0.610162 0.838499 -2.100964 -0.979303 1.220902 1.953685 -0.347834 2.030880 1.165817 -0.227043 35.684932 56.649077 51.039486 -29.362408 6.005547 1.153491 2.225667 2.041783 0.749253 0.938521 0.469274 2.345770 2.365260 1.428609 2.376760 1.200083 2.302132 2.432704 0.958157 1.995587
+1 -0.030939 1 1 -0.267464 0.349390 0.566610 -0.716062 0.589927 0.034981 -1.130974 1.488188 -1.381638 1.457609 -1.684084 -1.792819 -28.544234 -42.939616 -36.125772 34.152189 -54.153699 1.956661 1.101744 1.014465 1.108921 2.393805 1.924365 0.556624 1.177177 2.060934 0.875175 2.310259 1.777156 1.417625 2.278021 2.203877
+1 -0.018667 1 1 -0.302079 -1.794911 1.646797 1.860733 1.929931 0.978195 -1.009881 0.951354 0.266390 0.439259 -1.691429 2.003831 -33.396071 12.226654 -6.626594 -73.164769 19.733984 1.660930 1.001490 1.288561 2.090828 1.549566 1.301119 1.664086 2.295355 1.032453 1.938345 1.521975 1.089169 1.168297 1.324691 1.827083
+1 -0.017497 1 1 0.853960 -1.438889 0.573220 1.989009 -0.417290 -1.362064 0.580662 -0.179719 0.102553 -1.121041 -1.209283 0.109177 58.149368 66.435502 -18.518670 6.705203 44.352947 0.474597 1.807458 2.191465 0.951273 1.045363 0.668988 1.930829 1.184624 1.220046 0.309138 1.927176 0.543936 1.675099 0.635499 1.589070
+1 0.043477 1 1 1.205419 0.922874 2.271022 -1.291395 0.784667 -2.072478 1.845845 1.466115 -0.090094 -1.533520 -1.815487 -0.165518 -49.533808 -14.707310 14.240762 -55.506733 -51.662385 2.279456 1.571775 1.079647 0.871703 2.464242 2.266202 1.554566 2.089450 0.880388 2.181754 1.984964 2.038797 2.302393 2.327359 1.175417
+1 -0.042715 1 1 0.100416 0.653090 1.334406 1.108915 0.040095 -0.002273 -0.502508 -1.046647 0.345958 -0.577139 -1.878205 1.299347 28.883485 44.728240 -52.466674 42.616363 3.204629 1.527865 1.081061 2.151044 1.098416 1.325256 2.322035 1.685256 0.346938 0.494203 0.574121 0.505203 0.945417 1.620650 1.262633 0.563704
+1 0.017794 1 1 1.927114 0.759922 1.432314 2.026553 -0.873271 2.021188 -1.500718 -1.867885 0.393727 1.178846 1.978960 0.332059 45.833229 69.081433 51.647532 -9.936351 -50.254322 1.759106 1.803477 0.538880 2.209426 1.322449 2.405847 1.819868 1.524640 0.878044 1.042657 2.430036 1.119782 0.427602 1.714396 1.860062
+1 0.022375 1 1 -1.899083 -0.872404 -2.250714 -1.402913 2.026748 -2.306027 2.010871 -0.542802 0.313863 1.932732 0.922700 -0.648212 17.311880 -39.233418 3.947164 39.983649 5.196570 1.956342 2.490196 1.974244 1.865688 2.117129 0.335169 0.688520 1.698304 1.390267 1.470799 0.475580 0.326947 1.998944 0.746083 1.664695
+1 -0.010204 1 1 -0.429924 -1.634997 -1.460431 1.367339 -1.447628 -0.225021 2.113828 0.414740 0.903653 -0.328474 2.256678 -2.032494 -0.850307 -41.108947 -18.078076 61.773962 -65.023643 2.089445 0.795511 2.154441 1.945245 0.478116 2.441704 1.464983 1.726555 1.452646 1.378410 2.432111 2.234479 1.631818 2.213466 1.719539
+1 -0.000430 1 1 1.151510 -0.359534 -1.402882 -2.156290 2.226694 -1.744010 -0.517621 -0.590168 0.618924 2.013037 -1.848546 0.267313 57.836898 64.744896 67.461893 -17.961517 70.781494 0.993604 1.494712 1.881685 0.974279 0.706049 1.558448 2.094734 1.949933 0.529748 1.724350 0.402051 2.018619 0.683256 0.987143 0.920668
+1 -0.047723 1 1 1.988477 0.069071 1.621837 1.757430 -0.119979 0.409368 0.153946 0.269742 0.232098 -0.989412 0.977048 -1.430003 -28.172499 54.805180 -39.347143 42.569350 -36.942481 0.740728 1.664761 2.393160 2.340682 2.347236 2.237507 0.781219 0.445718 2.430748 1.828983 1.717841 1.261056 1.073900 1.033291 0.269119
+1 0.029848 1 1 0.602025 0.729881 0.760383 -0.234051 1.156009 -0.128722 -0.446445 -1.278619 -1.253989 -1.992413 -0.247598 -0.334270 -28.975993 50.487591 -5.064511 -69.242031 -50.817501 1.528823 1.424916 1.058799 1.486679 1.871826 1.773469 2.449791 2.393310 0.360261 1.649293 1.159105 2.082115 1.349911 0.446919 2.363982
+1 0.004368 1 1 1.641273 -1.446185 0.475353 1.751713 -1.965781 -0.315976 0.254613 0.439963 0.715038 1.043848 -0.271912 0.985980 -66.822663 -38.494173 -21.560545 31.918877 60.570332 0.708615 1.938842 0.862177 2.109255 0.752316 0.672375 0.364701 2.023428 0.503499 1.555143 0.543758 0.943681 1.689911 2.080705 2.408018
+1 0.064123 1 1 -0.506211 -2.032356 2.301615 -0.763201 -0.004359 2.136149 -1.437401 2.025965 -1.337774 -1.155200 -0.401312 -1.420322 51.561685 47.246649 -25.573216 -59.037116 13.199614 1.313648 0.730953 1.618754 0.893723 1.308456 1.226841 2.024913 0.708685 0.873914 1.379827 1.494945 1.284617 1.053848 1.524174 2.042737
+1 -0.033881 1 1 -2.071982 0.744532 1.964295 -1.093175 0.610726 0.889309 -1.089305 -0.311088 2.288231 0.491453 -0.960500 1.517118 -17.113391 -74.761033 41.324437 39.812628 -19.163936 0.800879 2.376165 2.452016 1.533730 0.656581 0.409039 2.474494 1.313097 0.470399 0.998049 1.957335 1.175196 0.259982 1.512950 2.404788
+1 0.007817 1 1 1.172762 -1.320570 0.536000 -1.540483 -1.031501 0.435316 -1.984544 0.049709 1.373136 1.727914 -1.408424 -1.050402 -47.640757 1.803465 10.843139 -9.366424 -71.494461 2.013801 0.700673 1.213689 1.465280 2.211950 0.990809 1.779747 2.201483 0.581518 1.078769 1.872233 1.874468 1.176665 2.457720 0.646180
+1 0.043406 1 1 1.776298 1.256995 0.666993 -0.629407 0.872909 1.311935 0.426268 1.459451 1.015560 0.247262 -0.601835 -2.246725 -10.455708 70.921301 74.305152 -53.309810 -27.984303 2.392232 2.498870 1.509745 0.291649 0.493986 1.430645 0.600617 0.327130 0.576209 1.852078 0.632540 1.346109 1.801585 2.491078 1.040752
+1 0.014436 1 1 -0.567061 -2.150758 0.950306 1.511919 1.624075 1.663814 0.403411 -1.004537 1.242816 -2.014232 0.597128 -1.452219 -63.105502 35.829887 -57.082393 16.226125 12.482353 0.488642 1.605625 0.731252 2.144087 1.169219 1.063753 1.487837 1.083165 1.504364 2.101358 0.781406 1.335197 0.663506 2.042435 0.455074
+1 0.003063 1 1 -0.806670 -0.162056 0.085085 2.176134 1.435328 0.831507 -1.815867 -1.847133 0.447592 1.709879 1.791730 1.445630 -11.938562 48.586812 -1.446450 -10.477745 0.545419 1.627979 0.697931 2.384613 0.441932 1.802425 0.847912 0.865436 0.628395 1.429493 1.490637 0.892129 1.519170 1.191841 1.026095 0.822318
+1 0.056670 1 1 0.293738 -1.723309 -1.315889 -0.910169 -0.798094 -2.110261 -1.717380 -0.621590 0.309895 1.219284 -1.673115 -1.212889 24.753396 -69.669066 -28.000388 -52.514740 -15.238690 0.374940 0.872535 0.696350 0.556040 0.364571 2.093498 1.428372 0.643318 2.491288 2.322057 2.064508 2.437961 1.555808 0.456876 0.973185
+1 0.004370 1 1 1.153599 1.773945 -0.582280 1.256015 -1.662792 -2.076242 -0.165263 -1.974497 -0.722764 1.048985 1.247911 -1.201490 -26.993287 73.818240 13.157525 38.526608 -33.302704 0.346687 0.763016 0.503757 1.399753 1.142632 1.970362 1.865070 0.726990 0.266848 2.169275 1.497515 1.728456 1.915255 0.436942 1.177262
+1 -0.045129 1 1 0.349783 -2.250770 -2.353924 -1.900581 2.223342 -1.534267 -0.241133 -0.070567 1.496959 -0.046116 -2.236857 0.586211 -36.918941 53.361642 -0.878579 -66.269739 -45.502055 0.579529 1.393704 0.728471 0.416196 1.248812 2.278510 1.425692 0.598914 0.941030 2.141843 1.709665 1.083929 0.848769 1.756010 1.506934
+1 0.014905 1 1 -1.295290 1.294854 0.801542 -1.200470 2.143224 -0.332789 0.421652 -0.733424 0.952926 -1.587687 1.997546 1.691336 36.642276 -53.261585 32.541498 24.960964 -31.070448 0.609820 1.988950 1.525166 0.722031 2.433050 2.267546 1.641121 1.075484 0.654707 0.417216 0.407185 0.561595 1.483064 1.860477 2.293796
+1 -0.018135 1 1 1.737667 2.285761 1.386498 0.110461 -0.156448 0.089092 -1.177576 0.513832 -1.831277 -1.653535 -2.008661 -0.005040 3.759636 38.201049 45.035624 13.737675 39.106579 0.839167 2.382535 1.512768 1.588564 1.988903 0.740160 1.120152 2.141319 1.898026 1.122099 1.116957 2.450328 2.419237 1.859615 1.293727
+1 -0.004538 1 1 -1.068731 1.469657 -1.817492 -0.877792 1.433996 2.021279 0.014828 -0.537445 0.815509 -2.073310 1.998219 -1.129518 -73.504656 7.252974 -49.271712 40.339583 -12.623779 0.357306 1.486155 2.050291 1.982106 1.255050 1.374537 0.338392 0.848147 0.311194 0.482741 1.419942 0.708448 1.388078 0.670468 2.049641
+1 0.011768 1 1 2.137795 -2.052538 -2.311338 2.278671 0.036739 0.151779 1.554980 -0.357572 -1.422952 -0.178915 -0.515257 1.442141 71.269275 72.709065 -28.748076 -18.912411 -10.887194 1.659027 0.521307 1.611926 0.883926 0.887986 1.637509 1.111540 1.399417 2.246887 0.931324 1.014673 2.352736 2.434152 0.540977 1.449254
+1 -0.079833 1 1 1.958392 -1.345015 -0.332041 -1.141970 0.479296 2.052131 0.197958 0.135588 -1.971696 -0.772947 1.134704 -0.068281 70.885390 70.744164 -52.839844 70.733870 74.156698 1.399291 2.385828 0.605848 0.490781 1.556764 0.781026 1.701674 1.787371 2.100624 1.935521 1.308806 0.357988 1.707542 1.405963 2.026836
+1 0.013330 1 1 -1.767980 1.879324 -1.345657 -1.702412 1.189707 0.740256 0.781839 2.230448 0.085091 2.268041 0.455943 0.682891 -64.381532 39.597263 -38.808847 -60.295314 16.663712 1.630185 1.768989 1.399951 2.220901 0.690529 1.729005 2.137367 0.726916 1.269210 0.855662 0.613978 2.132338 1.709294 1.612993 0.821530
+1 0.009163 1 1 0.276856 1.990018 -2.309194 0.604413 -1.544067 -0.003439 -1.254964 0.476825 -1.778010 -1.764033 2.255274 -2.059350 32.139247 14.324451 1.050307 -47.492848 -62.296692 1.067353 1.246139 2.367303 2.017050 1.315678 1.102782 0.453425 1.469018 2.035386 1.231134 2.164002 0.628628 0.844928 2.451823 0.539757
+1 -0.073994 1 1 -1.789979 -0.288271 -0.634832 -0.776102 -0.056923 -0.091179 -0.913085 2.036677 -0.366272 -1.559476 0.186213 0.649895 -16.875183 28.796640 -64.879844 64.466861 44.533642 1.028704 1.920590 2.362793 0.469271 2.281690 0.866735 2.221132 2.314142 1.785135 0.519054 1.993148 2.333572 2.086440 2.052745 0.481048
+1 0.041304 1 1 0.141381 1.149041 0.564057 -1.226106 0.121574 -1.881580 1.132240 0.933571 -1.728180 1.646976 0.148495 -1.819000 65.058588 -60.303281 32.751795 -40.581023 4.741321 1.935679 1.712392 1.915823 0.981269 1.193743 1.488051 2.430329 1.534088 2.175151 1.263691 0.345624 0.903685 2.235984 2.185106 2.069978
+1 0.005899 1 1 0.106945 2.003083 0.509031 2.300160 -1.656020 -1.358394 0.989110 -1.331725 1.539741 -2.014074 -1.446670 1.750965 -12.960792 -32.030775 8.767222 50.702896 13.576668 1.870858 1.268208 2.022463 2.278684 2.092695 1.422737 0.439791 1.811101 0.417365 0.652322 0.821140 0.899241 1.797011 2.115906 2.284657
+1 0.005394 1 1 -0.916533 0.622554 1.753646 2.247787 -0.657228 -0.190931 0.151374 -0.540992 -2.251210 -0.315062 1.475353 -0.341348 -65.340179 -22.380474 51.380151 -3.803535 -26.016750 1.172288 0.894142 1.586111 1.274669 0.362655 1.395383 1.950488 0.850613 1.258135 1.471954 1.874459 1.037639 1.353336 1.762138 1.007502
+1 0.012319 1 1 2.211535 -2.050560 -2.060333 -1.385896 0.589304 -1.004679 -1.158573 -0.546142 0.720882 0.303665 0.183473 1.735694 67.559964 -19.690585 -39.654172 -17.666610 -72.715460 2.443911 0.308951 1.035883 1.077295 1.850113 1.356099 0.954688 2.191692 0.259925 0.554967 0.337600 1.036303 1.397723 0.784838 0.515828
+1 0.007752 1 1 -0.974870 0.328764 -2.097137 2.080919 -1.351865 2.346000 0.658865 -0.576192 -0.093078 0.154108 -1.727254 -1.647251 -1.876165 -32.707647 32.574831 -14.814610 10.842191 0.995492 1.737186 2.393965 2.369632 0.651834 1.615949 1.004654 0.471505 1.576985 0.881461 2.215698 0.992328 0.313787 1.318141 1.998427
+1 0.071024 1 1 0.804462 0.743017 0.052826 1.917835 0.316634 1.387791 -1.722071 0.649100 0.242340 1.496358 -0.733047 -2.135309 45.300142 -40.514398 74.509277 -72.583670 36.252747 1.373874 0.457622 2.247206 1.782395 1.708680 0.279344 0.692964 2.138034 0.685748 2.360935 0.730846 2.079117 0.476553 0.928443 2.097800
+1 0.027587 1 1 -0.029065 1.592040 0.462427 1.287595 1.319549 1.151806 -0.096690 0.706480 -1.411901 1.768633 -0.328753 2.282648 29.023457 -2.753207 -73.150954 -48.091685 73.046833 0.596885 0.602852 1.886776 1.048354 1.437904 1.110406 0.336682 1.367080 1.014422 0.386446 0.745968 1.980258 1.686996 0.335190 1.031567
+1 -0.004709 1 1 -0.616745 1.630457 0.556396 1.960800 1.420302 -1.946844 2.219501 -0.123929 0.007121 1.874003 -1.248210 0.889115 11.562789 -64.205013 6.353928 -9.535620 -65.160730 1.279108 0.714339 1.390747 0.530749 0.541895 1.128884 0.408717 1.554887 0.742679 0.707984 0.340032 1.417580 1.513107 0.542384 0.354097
+1 -0.019109 1 1 -0.017425 -0.694432 1.272187 1.535755 1.676912 -0.934810 -0.248353 1.105542 -0.107797 -2.185330 -0.476809 2.044659 58.882143 -67.815695 71.619202 -46.070274 -3.086878 1.657540 0.269174 0.763732 1.299332 0.873906 1.238529 0.461718 1.336130 0.584366 1.694470 2.203587 2.194858 1.732965 1.192097 0.824462
+1 0.003033 1 1 -0.822551 1.531390 -0.996933 1.799402 -1.565759 -1.728765 1.241667 2.241264 -1.913986 -1.592026 -0.237565 -1.354067 -53.155125 21.815039 45.354711 -23.364099 19.595968 0.616442 0.789887 2.135935 1.417023 1.149944 1.112624 1.615231 2.429372 1.212792 2.142186 0.718867 0.993397 0.270620 0.316564 0.733079
+1 0.041027 1 1 -0.542740 1.350585 -0.295169 1.231866 -2.273004 0.954052 -1.502444 2.122819 0.724524 0.266777 2.241585 -1.229741 9.082412 -51.905588 22.779298 51.662111 -64.900165 1.718973 2.281300 1.052170 0.329998 1.521117 2.406069 1.046302 0.696896 0.723845 1.413833 1.540115 2.213582 1.418839 2.422673 1.111968
+1 -0.010145 1 1 -0.575331 0.226366 1.632545 -2.058067 -0.999950 -1.781376 -1.777678 -0.881811 -0.132801 1.681086 -1.473217 -1.466456 -29.728065 10.408958 43.357401 7.838224 37.032830 2.286624 0.548125 2.344408 1.961684 2.274275 2.236556 0.538389 0.710617 1.834885 1.902978 1.109099 0.876438 1.041195 0.372715 1.721778
+1 -0.035559 1 1 2.221149 -0.691784 -1.354570 -0.701523 -0.105897 1.478012 1.951592 2.184385 -1.272396 -0.344274 0.594362 -0.824296 15.083675 11.331406 -53.064895 38.304783 -11.511488 1.771301 2.006700 0.608364 2.274430 0.336485 0.306033 1.493156 0.482022 0.595206 1.624496 0.656750 0.998720 1.987855 1.120176 0.291016
+1 -0.070437 1 1 -2.332112 1.843089 2.257235 -2.088271 0.305384 0.793372 -1.851533 1.904819 -1.675496 1.176054 2.176814 -1.274331 4.285430 25.220677 -16.087130 73.609042 -52.834169 1.616889 1.060966 1.898039 1.336809 0.757522 0.415639 0.891618 1.929198 0.774785 0.303824 0.364323 2.421848 0.748847 0.866455 2.004719
+1 0.007492 1 1 -0.123307 1.027492 -1.841276 -0.069572 -0.619734 -1.485842 -1.602193 -1.464368 1.175683 0.653049 0.643332 2.263101 71.397156 -27.998148 -14.869513 -11.900832 -67.290619 2.073541 1.252105 1.375553 1.668914 2.441969 1.423525 2.436780 1.953805 0.352864 1.087454 1.591664 2.352872 2.473101 0.404608 2.254316
+1 0.003062 1 1 1.349765 0.059016 2.287282 -1.323879 1.459683 0.189791 -0.475016 -0.810740 2.120965 -2.167343 0.229689 0.933799 66.758850 15.986139 29.033429 14.839490 -42.686325 1.689055 1.197615 1.312488 1.490435 1.982100 1.156614 0.708006 0.712452 1.176113 2.181265 0.523574 1.466281 1.037472 0.787533 0.820569
+1 -0.013505 1 1 -0.067002 0.155779 -1.917560 -0.406114 -2.013924 1.063850 1.321085 -1.303061 -2.075375 0.268917 0.512670 2.189288 33.078522 50.726791 -34.817889 -34.266875 -73.374219 0.617406 1.245596 2.231759 0.916551 2.474200 0.873416 1.994457 1.837399 1.413383 0.721589 1.753638 2.141786 0.748671 2.407576 1.637960
+1 -0.020085 1 1 -1.722751 -1.360528 -1.876750 2.195337 -0.979510 -2.244722 0.337918 0.967318 -0.021821 0.827632 -0.966044 -2.123388 -27.308125 32.339938 -62.669273 17.522912 57.585171 1.884470 0.529599 1.462678 1.236044 1.447298 1.483656 0.561052 1.358015 1.652152 1.969054 2.398486 1.855497 1.834831 0.998000 1.131580
+1 -0.054359 1 1 -2.218406 -0.335374 -0.614350 -0.543912 0.508988 1.573090 -2.296695 -1.374048 1.796339 -1.205991 -1.105791 0.636343 -66.903175 -41.666765 56.676621 63.975880 42.613380 0.671169 0.330829 1.999844 2.371582 1.934808 0.564087 0.616382 2.035029 1.973165 1.727285 2.474906 1.495943 2.319461 1.182918 1.806334
+1 -0.020256 1 1 -1.778543 -1.291060 1.713285 -2.224348 -1.239637 -1.102241 -0.964258 -0.376783 0.861806 -1.503015 1.949233 0.234541 -74.295803 60.434348 70.080402 41.314495 22.718862 0.413581 2.313038 1.233441 0.445084 0.775870 0.547672 1.465165 0.281580 2.261133 1.854830 1.875770 0.558794 1.654941 1.591166 0.731484
+1 0.001894 1 1 1.021456 0.372784 -2.095016 0.028521 -1.316047 1.147607 0.017550 -1.921204 -0.394120 1.639347 -0.841405 0.383373 48.054494 51.887664 -24.036208 -26.549101 39.255306 2.333993 2.425834 2.486414 1.411374 0.718024 0.330934 1.508223 1.709711 1.866065 1.709165 1.679489 2.416518 1.163507 1.808966 0.545767
+1 -0.073198 1 1 -1.034809 1.401855 -0.975691 0.669267 -0.101691 1.476960 -1.596442 0.943867 1.671388 0.463617 -2.285937 0.368190 25.815215 -73.682914 11.267167 67.277682 36.008198 0.471776 1.636129 0.411299 2.206570 0.570241 0.542392 0.481448 2.192739 2.117512 2.278247 1.501453 0.418814 0.257999 1.930917 0.423123
+1 0.027776 1 1 -0.718208 2.217531 -0.247030 -0.225226 -1.321000 -1.983033 1.891031 2.203321 1.261789 1.144126 -1.941083 0.086068 -4.902793 -51.247687 -19.871073 -73.117330 67.030482 0.344609 1.849717 1.449877 2.091632 1.565837 0.264501 0.961906 2.005577 1.975315 1.870700 0.862175 2.076185 0.689392 0.612087 1.838568
+1 -0.020162 1 1 2.117862 2.237454 0.021980 1.844426 1.174750 -0.886894 -0.740966 1.430296 1.082925 1.473422 0.205935 2.250017 -28.389331 10.507205 44.599615 35.723827 -39.646778 0.724019 2.086577 2.096906 2.448846 2.257968 0.415142 1.536924 0.334013 1.498611 2.150757 0.774974 1.231427 0.350531 2.377726 1.685534
+1 0.062159 1 1 2.009345 2.078693 -1.063960 1.544899 -0.147533 -0.869163 0.389853 2.036856 -2.060661 -2.178017 -0.100675 -0.297552 -35.504482 -23.826898 41.318573 -58.736231 -29.838456 0.701031 0.477222 0.925364 2.101056 2.440037 0.459614 1.988304 1.920951 1.673256 1.162817 1.469209 0.746817 0.506547 1.034983 1.715848
+1 -0.047209 1 1 -0.388982 -1.534004 -0.525712 0.081318 0.121728 0.702628 -0.181209 -1.378700 -0.992605 -0.862097 1.332373 -0.079122 -29.164475 32.675804 32.230647 50.479122 2.607485 1.735062 0.437120 1.923261 2.247675 0.667677 2.397523 1.420602 0.563755 1.780826 2.337351 0.355498 0.351871 2.388649 0.773268 1.817821
+1 -0.044399 1 1 -1.906765 1.961588 0.531970 1.418970 -0.764817 1.114682 -2.005082 -1.116563 -1.348977 -0.954208 -1.117575 0.495056 -53.375635 65.702443 -39.033733 60.054352 -16.512793 0.917240 0.545802 1.537581 2.376437 0.268116 0.967778 1.691683 0.362257 1.449981 1.576380 1.975614 2.395488 0.962910 0.878010 0.459541
+1 0.009608 1 1 1.700192 -0.793151 0.863487 -1.525660 -1.659692 -1.806232 -0.131941 2.007168 -1.517815 -1.755055 2.338279 -1.875607 -68.622157 17.399117 -73.032400 -5.553639 -40.010212 1.350381 1.610429 0.476743 1.861788 1.816976 2.415033 0.965505 1.741885 0.355384 0.693530 0.404962 1.438432 0.977567 1.960466 2.051948
+1 -0.007943 1 1 -1.974623 1.870301 -2.190584 0.756717 -0.594444 -0.548927 1.043504 -1.338834 -0.118969 -1.464059 1.651219 0.775782 -19.443520 62.752826 36.744915 21.781334 -71.115156 0.888525 1.687560 0.826126 1.447257 0.796875 0.324183 0.540880 2.071113 0.945245 0.987228 2.334574 0.928480 0.459971 1.226903 0.801642
+1 0.061164 1 1 0.951260 -1.303999 1.009368 -0.158107 0.483533 -2.128160 -0.945507 -0.961024 2.132783 -1.458016 -0.454412 1.486928 31.868987 -27.943740 -0.432224 -64.388401 74.137576 1.078613 1.507723 2.301925 1.201410 2.095386 1.658590 2.167422 1.858706 1.771735 0.308515 0.457795 0.655510 0.401967 0.602125 0.908980
+1 0.085069 1 1 -2.240218 0.642271 -1.439243 -0.666193 -0.068952 0.377734 0.995829 -1.511669 -2.133148 0.040726 1.192066 -2.032432 32.747122 30.884883 -67.770691 -72.007211 -25.188518 0.723590 1.627722 0.870438 1.458882 0.424091 1.195104 1.863576 0.370345 2.395917 1.420110 1.284235 1.388980 2.339198 2.151611 1.625029
+1 -0.030930 1 1 -2.120348 -1.597883 0.284357 0.826516 -0.875366 -0.197597 1.227561 0.774711 0.241137 0.141563 -0.506217 -2.120427 56.426958 67.880132 -38.616007 30.771290 -26.934426 1.571604 0.446136 0.463844 1.078458 1.140184 1.324258 1.306895 1.985452 1.240078 1.743855 1.978007 2.118598 0.276462 1.750381 1.406316
+1 0.015159 1 1 -0.072352 -0.216342 1.903341 1.750555 2.139574 -0.425353 -0.211605 1.408846 -1.271853 -0.636900 2.172059 -1.083292 56.553550 -54.490079 -64.758135 10.031298 -3.970508 1.639996 2.405737 2.220290 1.659551 0.316869 1.362255 0.913504 0.761634 2.038109 1.991885 1.368008 0.863982 0.946346 1.491095 1.831120
+1 0.035435 1 1 -0.511245 -1.814757 -2.043881 1.807850 -0.945351 1.666481 -1.888578 1.322148 -2.285888 1.186725 -2.253599 1.947637 53.421353 -47.312249 -26.964597 -43.983106 -24.062509 1.096269 1.248368 1.571734 0.378056 1.482454 0.602937 1.054451 0.401952 0.352671 2.339290 1.443642 0.798311 1.961486 1.200408 1.006393
+1 0.000690 1 1 -0.917522 -1.859623 -2.116020 0.450020 0.097944 1.514684 0.969155 -2.138717 0.687225 0.132658 0.616969 2.141315 17.997721 -62.309851 58.341635 -2.139590 39.905089 1.897347 0.956991 0.399519 2.213470 1.791895 1.635707 2.326784 0.503827 0.320932 2.147823 0.967703 0.428724 0.313424 1.969026 1.922629
+1 0.014498 1 1 1.994085 0.085247 0.188284 -2.228266 -1.112015 -0.308630 1.201295 2.289810 -1.240179 -0.790216 -1.651895 1.995246 23.457685 53.314073 -50.380939 -2.440615 -69.410622 0.860117 1.236212 2.007500 0.559938 0.630685 1.672909 2.084939 1.565651 1.638263 0.291086 2.276330 0.774106 2.397292 2.029416 2.139521
+1 0.042462 1 1 -0.129430 1.786269 -0.801700 -1.449569 0.136492 -0.915151 0.301327 -1.420501 -1.392942 -0.032684 2.029823 2.248481 49.855984 29.520192 -54.141284 -52.557898 9.405971 1.167450 0.586244 1.747186 1.700657 0.433569 0.747651 1.025159 0.849950 1.357977 1.019026 1.272376 2.322539 1.165100 1.580009 2.216183
+1 0.006455 1 1 0.070927 -0.167225 -1.967224 -1.020702 -1.840589 2.059771 1.365808 1.089704 2.312055 0.353064 1.042846 1.743764 34.912389 -27.471270 -9.628924 16.677879 -44.888384 2.288999 2.210484 1.101428 2.458034 1.423574 1.001053 0.691244 2.480697 2.079142 0.893771 2.109276 1.100822 1.267197 0.780797 2.349140
+1 0.053811 1 1 1.038565 0.476372 0.030715 -2.138209 -0.202022 2.243803 -1.655617 0.695939 0.497512 1.903281 0.752558 0.195491 34.457808 -17.621073 -57.371680 -45.821644 -24.370366 2.233795 1.396097 0.446334 1.533661 1.737815 1.700371 2.392493 2.378346 0.859466 1.540040 0.955483 2.054972 1.922623 0.529949 0.605042
+1 -0.003683 1 1 0.699030 0.616310 0.499648 0.107501 1.919019 1.361925 1.796577 -1.924806 0.337678 1.631144 -2.044169 1.682277 -9.687404 -66.197487 -31.166122 -9.015112 -16.983699 1.449621 2.288370 0.631097 1.850737 0.585394 0.968607 2.127866 0.788354 1.117955 1.221455 1.495449 0.754546 2.161426 2.333112 1.110346
+1 0.005299 1 1 2.011301 1.974645 -1.497177 1.096379 1.406480 1.364376 0.577865 -0.053487 1.105015 0.469291 -1.166689 -0.293918 -41.116216 9.758952 68.708167 -71.838584 -41.077072 2.389653 1.902692 0.798177 1.960186 1.849306 1.290733 0.354762 1.481685 1.187426 1.063225 1.624269 1.335226 1.142339 1.537389 1.399896
+1 0.030688 1 1 1.513523 0.303922 -0.205884 -1.405702 2.280071 0.012219 -1.978547 1.895357 -0.485544 1.327593 -0.312399 -0.887005 67.080270 18.094475 63.841415 32.655340 -11.701890 1.020114 1.558926 1.126438 2.046371 1.352078 0.865797 2.203896 0.622900 1.323783 2.318440 2.016832 2.142759 1.353037 1.247917 0.732781
+1 0.010662 1 1 -2.259598 0.075066 -1.281859 0.837159 -1.069449 -1.168569 1.105387 2.002497 0.090261 -0.372675 -0.789408 -2.201255 15.219476 43.741343 10.744637 -14.879488 -29.551054 1.156630 0.982624 1.459015 0.422362 1.391082 1.659976 0.720430 0.274249 0.551867 2.232329 1.507614 0.468582 1.961462 0.787452 1.697886
+1 0.020361 1 1 -1.499722 0.747358 2.323489 -0.680189 0.326907 -0.317074 0.644469 -2.183881 0.304703 -1.224369 1.032458 1.505006 -46.632199 2.633373 9.093132 -21.730437 26.545925 2.235509 0.955666 0.632890 0.479140 1.651937 0.600337 2.363693 2.094647 0.480083 1.746601 0.877802 1.467400 1.835679 1.755870 1.405384
+1 0.028781 1 1 -0.428557 -2.227188 -1.845454 0.401823 0.578761 0.860550 0.944580 -0.478824 1.164946 -0.727978 -1.759088 0.537545 27.840384 63.328087 -44.840252 -30.106971 -57.867011 1.812127 1.919737 1.520011 1.826235 0.528214 0.700682 1.361396 2.227956 2.251196 1.344749 1.445818 1.368207 1.954560 1.792571 1.733301
+1 0.083206 1 1 0.641750 -0.770359 2.225880 -1.292016 -0.224603 -0.275734 -1.984916 -1.484419 -1.243078 2.324407 0.604502 -0.046665 -65.249015 9.806228 -36.721259 -74.204906 -61.862286 0.333356 1.711065 2.112179 0.388970 0.418413 0.266883 0.494589 0.307437 0.336790 0.921790 0.523372 0.312309 1.235164 2.392218 2.252128
+1 -0.026914 1 1 -1.701828 1.571559 0.258967 -1.785604 -2.151704 -0.817671 -1.277350 1.226189 1.287092 2.285988 0.494859 -0.265407 61.704617 -30.506596 -24.359280 -56.420309 43.874551 1.368660 0.572885 2.227460 0.677018 1.898284 0.963697 0.606667 0.757862 1.628757 0.273705 0.408011 0.938699 1.213283 1.402776 2.453687
+1 -0.054675 1 1 -1.784116 -0.705820 -1.628173 0.140235 0.731169 -1.160183 0.662445 -1.659096 -1.214638 -0.352158 0.040401 0.430186 42.490909 -5.289687 46.225154 56.156860 28.344910 1.268456 1.693814 2.426889 2.217654 2.365938 1.568165 1.156204 0.574466 1.801455 0.304773 0.578097 2.072911 1.909951 1.303845 2.465093
+1 -0.031772 1 1 -0.502725 0.017262 -2.044307 -0.634175 0.841076 -1.206364 2.055025 1.708169 1.315893 0.979542 -1.922936 -1.218519 12.800622 40.061847 -30.529849 34.827449 44.936758 1.406325 1.357708 0.996703 1.844947 2.265807 1.671395 1.388065 0.451108 0.775631 1.024609 0.596317 2.299561 1.976644 1.700494 2.205109
+1 -0.010913 1 1 -2.248175 -1.133776 1.529852 1.429683 0.206352 -0.155921 -0.477190 0.351169 2.179891 -1.395442 0.364727 -0.854679 -39.091755 -15.129259 -27.452345 8.444897 33.387142 1.190388 1.353097 2.257371 1.641118 1.023448 1.342839 0.836331 1.957121 2.075426 1.428174 1.822585 2.192010 1.106047 1.334208 2.032743
+1 0.058680 1 1 -0.106357 -1.553960 -1.344100 0.900869 -0.003122 -0.640276 1.975927 1.203696 0.238992 1.782960 0.131314 1.595745 47.280120 -63.020837 -41.209394 -56.285797 54.607402 0.423973 1.457504 2.013823 1.081510 0.691113 0.286962 0.471357 1.344157 0.497973 0.927792 2.397790 1.401349 0.979569 1.873185 2.116892
+1 0.013337 1 1 1.591148 -0.384413 -0.145464 0.914723 1.932894 -1.067362 0.908262 1.727868 -2.171084 -1.379897 -2.262242 -1.951188 -3.212228 12.081464 -46.837266 6.064705 -70.511567 2.306300 0.476494 2.186844 2.042927 1.967231 1.001893 1.323348 1.758014 1.442950 0.406923 0.657748 2.024672 1.157113 2.345788 0.416521
+1 -0.006333 1 1 1.021120 -0.556977 -2.309164 1.117057 0.224282 -0.408806 -0.138911 -2.046188 0.732232 -2.140244 -1.422441 -1.022430 66.827284 -33.843983 -15.813931 15.253796 20.553757 1.329989 0.869686 2.314290 2.027824 2.390156 1.343760 0.577276 1.785597 1.529891 1.382506 1.533502 1.326147 1.546886 1.267369 1.419643
+1 0.057721 1 1 1.285510 -0.739874 0.933817 -2.305040 -0.260316 -2.038109 -0.138596 -1.462775 -0.332414 2.003947 0.885419 -0.489202 34.949767 0.735738 65.549752 -55.320170 -66.099152 0.948188 0.950007 2.260243 0.404438 1.632129 0.691623 2.112583 0.430995 2.475169 1.406288 0.737102 1.477602 2.298614 1.800959 0.960962
+1 -0.009089 1 1 -0.713894 -0.674326 -0.105763 -0.982872 -2.200538 -1.615171 1.900237 1.419618 0.690527 -0.919813 2.044202 -1.119069 -33.278186 43.528773 38.090813 -7.712510 -24.156139 2.241630 0.333586 1.073583 2.463494 0.950113 1.798083 2.133685 1.850721 0.310460 1.644763 1.529601 1.003207 0.904480 2.099459 0.353364
+1 -0.049281 1 1 1.943186 2.273897 -0.092459 1.121776 -0.576988 0.662335 1.207626 0.307135 1.943982 1.514427 1.355563 -1.462009 -50.405763 30.341510 -50.243193 62.652240 -3.797804 2.429735 0.559882 1.932581 1.389293 0.856096 1.156707 2.266397 0.332596 2.435671 1.324859 2.402272 2.478942 1.834975 1.169388 1.660547
+1 -0.005449 1 1 -0.220970 -0.481832 -2.261190 1.595113 0.280647 -0.271422 -0.189647 -1.830341 -0.066975 0.618597 1.228918 0.023601 25.970624 -11.727264 -0.124177 12.955610 -55.061454 0.357241 0.407372 1.447342 2.222297 1.650191 0.504915 0.613628 0.741771 1.188053 0.355808 1.068512 0.473838 0.295060 1.572642 2.147212
+1 -0.023041 1 1 -0.478884 0.152824 0.254461 -2.121268 1.783641 2.140868 -2.237269 -1.622654 -1.343682 -1.494042 1.965704 -0.967959 -41.857394 2.783316 -20.816749 -67.102116 64.732194 1.434724 1.663216 1.174416 0.654889 1.216114 1.721583 1.149048 1.803670 1.528046 1.871876 0.369791 2.084472 0.474937 0.774239 2.383236
+1 -0.056869 1 1 2.058738 -1.863575 2.141715 -2.142688 -0.077745 -1.324126 2.028503 -1.084901 -1.690570 2.288496 0.240141 2.240701 -62.083532 -37.917292 74.079488 53.957296 -39.727469 0.631438 0.832275 1.291665 0.264546 1.724866 2.315507 2.226853 1.722799 1.325890 1.726684 1.369087 0.998159 1.558164 1.803447 2.279108
+1 -0.017572 1 1 -1.259761 -0.047294 1.516912 0.713705 2.212008 1.176402 -1.402231 -0.642710 -1.230153 -1.932088 0.462681 0.841809 54.086408 30.258630 56.796518 -20.917955 31.922224 0.877271 1.541212 0.403897 1.545661 0.931709 0.733179 0.781943 1.366354 2.312987 0.370126 0.958981 2.336187 1.039594 0.460357 0.972175
+1 0.021051 1 1 -2.285874 1.421988 -1.878726 1.977562 0.402127 0.974487 -2.069278 -0.921809 1.496712 0.508432 1.647933 2.107331 -12.907339 -33.644978 28.853061 -16.604465 -71.239892 0.941993 0.329432 1.012624 1.668235 2.283306 1.027455 1.190904 1.024848 2.362776 2.433401 1.416672 1.998934 0.587088 2.441645 0.472416
+1 -0.002327 1 1 -0.661272 -2.190748 -2.003892 0.034575 1.479394 1.610523 0.106669 2.081646 1.440597 -0.147910 2.215088 1.120274 -71.872815 -16.397390 -40.931746 -39.857737 11.022372 1.420099 1.110308 0.941830 2.083222 1.955067 1.305520 1.371215 0.765985 0.914095 1.695375 1.664545 1.008964 0.907029 2.187960 0.537461
+1 0.016941 1 1 1.689482 -1.733893 -0.134100 -1.289277 -1.306750 1.888855 -1.380905 -0.361966 0.130645 -0.226786 0.738503 -0.405320 60.763340 49.460764 -12.943624 -43.496019 62.402696 1.406744 1.644854 0.816984 0.793043 1.180452 0.861436 0.901605 1.017657 0.756153 2.161936 1.908592 0.952304 0.372628 0.254657 2.012153
+1 0.010846 1 1 0.959174 -0.242446 1.425795 0.847208 -1.813413 1.705627 1.016108 0.025484 -0.512824 -0.065533 1.289614 2.261296 5.701453 -25.677133 -5.575158 48.321133 33.285094 2.463526 1.474184 1.114337 1.166172 1.595517 1.853403 0.394538 1.742953 0.312094 2.120232 0.738830 1.265353 1.285152 1.047409 1.299005
+1 0.013202 1 1 -0.366002 -1.733450 -2.103736 -0.440891 -2.176498 1.871500 -0.899593 -2.110811 -1.538643 1.623923 -0.888344 -1.551946 -15.219778 -48.809308 11.960651 22.653100 30.658127 1.692001 1.212060 1.084866 0.844927 2.433104 0.934252 0.728015 1.754675 1.573985 2.210118 1.706159 0.671015 2.246783 1.438141 0.590044
+1 0.000814 1 1 1.709433 -0.988382 -0.570389 -1.523118 -1.342978 0.918952 2.335503 -1.405830 0.140168 -0.390896 -0.715647 -1.864915 -48.552700 -25.227783 46.647735 -41.524563 46.671352 2.206199 1.078156 0.567165 0.589019 1.148371 1.669202 0.531048 1.079854 2.107717 1.894299 1.483209 2.037677 1.489570 0.962203 2.497663
+1 0.021814 1 1 1.121016 0.781428 0.032758 -0.777569 -1.145505 2.312542 -0.896400 -0.284058 -0.515542 1.367500 1.248033 0.851633 59.575934 42.720431 -47.713368 -18.572467 2.538850 2.431852 2.382843 2.194895 2.342107 1.541224 0.597899 1.887238 2.065337 0.617311 1.899416 1.981405 0.716695 0.488444 0.528113 1.237364
+1 0.004860 1 1 1.981815 1.199619 -2.308764 -1.583006 0.573653 -0.163631 1.889558 1.002731 1.402326 2.228810 0.825438 -0.129646 -58.591576 1.376196 29.728676 -0.143892 -18.394472 1.286536 1.802203 1.626004 1.254906 1.211372 0.772756 2.203214 0.411479 0.731483 1.537087 0.827335 1.518724 0.445109 1.195166 0.651787
+1 0.004656 1 1 0.558233 -0.138837 -0.795041 2.089046 -1.410059 -0.258126 1.785032 1.964841 -1.338630 -1.407926 -2.106609 -1.607740 -14.329240 68.463312 12.879584 17.163239 12.553122 0.329817 0.738614 2.130452 1.513098 0.383654 1.070447 1.500508 0.295059 1.554575 2.242228 1.379550 1.353248 0.294189 0.438038 1.604670
+1 -0.007250 1 1 0.321854 -0.420044 -0.527018 1.699757 1.310179 -0.812007 -0.329377 1.216803 -0.962253 0.330660 1.493365 0.800050 63.339691 0.190131 45.535331 12.300226 29.901791 2.266054 1.314325 0.856792 1.595340 1.130877 2.408761 1.291135 0.364139 1.578558 0.319230 0.546713 1.105903 1.158804 1.524891 0.590813
+1 0.020188 1 1 -0.650222 -0.253268 -1.392406 -0.445578 -0.844402 1.853034 -0.232043 1.903947 -2.190335 0.229166 1.579300 -1.584219 -31.011350 42.232891 8.200109 -30.768868 67.643677 1.934125 0.336819 1.410062 1.152899 1.267151 2.249594 1.424625 0.677845 2.287415 0.334612 0.325445 1.498343 2.151960 0.750135 2.274294
+1 0.005068 1 1 -0.764132 -1.505282 1.538725 -0.241848 2.052648 -0.550515 -2.089903 1.153829 0.927449 -0.947533 -2.016844 -0.882994 -36.899930 72.870037 -23.292749 18.766744 -37.326333 0.719936 0.961676 0.393058 1.624000 1.309557 1.732505 2.459382 1.583260 0.609064 0.530595 2.457655 1.811622 2.425947 2.136602 1.365571
+1 0.041929 1 1 0.166909 1.365224 0.694980 -1.479322 -0.407653 0.387945 -1.763166 -2.034109 1.106637 -0.547553 0.576930 -1.640417 54.238844 42.251913 27.896336 -46.276123 -12.792107 0.670808 1.023431 1.053341 2.003547 1.616253 1.607046 2.118062 0.272283 1.261656 2.150170 2.160156 1.242522 2.321723 0.941092 0.926233
+1 -0.004244 1 1 -1.204963 2.032976 -1.303224 -0.108253 -0.422853 -0.607762 1.806549 0.746628 -0.508066 -0.212867 -0.954309 1.901796 -20.566593 -62.722939 15.556552 8.961256 11.837093 2.065317 0.276377 0.317404 1.363458 0.884985 0.698856 2.173298 1.618032 2.260454 1.703387 1.323309 1.108828 0.830730 2.328855 1.567280
+1 0.045192 1 1 -1.937573 -2.182925 2.233887 1.337160 0.256314 0.749467 0.071713 -1.083955 0.059815 1.573987 -1.358796 -1.039923 8.496330 -2.174329 56.045420 -44.632824 6.128475 0.644293 0.888392 1.707374 0.831092 1.665855 0.522582 0.537744 1.119062 1.831366 1.263256 2.042013 2.366332 1.443482 0.359419 1.003805
+1 0.006174 1 1 1.247182 0.688269 -1.171697 0.361568 -2.111585 -0.411654 -0.888822 -0.156360 1.568421 -0.648751 0.914755 -2.229749 71.365315 36.850766 0.829723 -4.841618 -73.078774 0.850720 0.797683 0.409324 0.503912 1.756867 2.411965 1.148587 0.803028 2.499541 1.536779 2.386544 1.402849 1.437696 2.111731 1.861368
+1 0.056782 1 1 -0.510290 0.097572 -0.013765 -0.436826 0.169409 0.966559 1.353892 -1.257024 -1.165733 1.640172 -1.112167 1.865468 44.728731 -44.217289 -59.978045 -51.005512 0.362570 0.530660 1.309999 2.409082 2.185578 1.007683 1.880961 2.302410 0.356608 1.009467 0.366199 2.463963 2.077982 1.637757 0.777802 1.515175
+1 -0.031056 1 1 0.364237 0.333193 1.662813 -2.272833 -0.877349 -0.532358 1.488289 0.317870 -1.403681 -1.453874 -1.525489 1.210011 -64.199838 -56.681805 -1.095109 44.497904 -23.721921 1.460018 1.522608 0.465678 0.408011 0.946975 0.814494 1.705404 1.476202 1.272530 0.413840 2.162332 1.807681 1.451550 0.953133 0.805148
+1 0.024479 1 1 -1.986241 -0.187656 -1.339168 -1.026270 -1.176276 -1.201493 -0.898067 -0.021945 -1.266244 -0.619137 -0.881967 1.957319 -16.730588 59.004038 30.866768 -72.230152 -22.157109 2.207032 1.582047 0.459552 0.937537 1.940399 2.291599 0.910768 2.023106 1.841201 2.308135 2.077813 1.050224 1.371564 2.121757 1.618330
+1 -0.017594 1 1 -1.882212 -0.064717 0.865133 -2.144743 -1.635882 -2.194232 0.703911 -2.180849 -0.562399 0.820747 1.134442 0.234628 -27.807170 44.895918 65.694240 -26.901880 -39.890910 2.177083 2.238343 1.329714 0.754844 0.412898 2.082776 1.213917 0.793918 2.386181 2.036512 2.162996 1.718916 1.313332 2.175648 0.624847
+1 0.001923 1 1 -1.063818 -0.780927 -1.041611 0.169444 1.568123 -0.941689 1.939909 -0.966390 1.481880 0.976780 -1.222395 1.227994 -43.665949 56.395808 -5.647621 30.429290 -74.925238 1.097813 2.437722 2.050248 1.272291 0.902470 2.060939 0.950014 2.390358 0.253050 2.009512 0.614729 1.251097 2.432207 1.603674 1.701922
+1 0.019075 1 1 -2.062219 -0.087977 1.068420 -1.970420 1.827426 -1.798362 0.192732 1.834514 -0.485816 1.463210 -1.789061 1.007078 -29.935406 -24.369610 69.963429 25.351277 -71.087563 1.094862 2.347293 0.960370 0.934627 0.281997 0.279384 1.360005 1.353717 1.427358 1.611679 1.232491 2.470568 0.589193 1.818262 1.530469
+1 0.008305 1 1 -0.046732 1.551272 -1.412396 -1.832042 -0.385588 -1.046366 0.366642 -1.658615 2.143435 -1.499670 1.617304 0.972668 11.099917 -43.697451 -23.053376 -8.092834 33.745989 1.657603 1.338554 0.824029 2.199346 0.660632 0.988315 0.357019 1.168400 0.801550 2.396771 2.271503 0.651722 1.997212 0.885059 1.938500
+1 -0.001959 1 1 2.023250 0.157588 0.211573 -1.938235 0.831664 0.831075 0.353812 -0.523283 -1.494695 0.399828 0.035696 1.472694 66.696258 14.010584 -24.106494 -7.839363 -56.181216 1.559435 0.675451 0.310413 0.863895 1.728327 1.987791 2.296218 2.031113 1.419508 2.416653 1.189900 2.153101 1.920991 2.348644 1.163552
+1 -0.021311 1 1 -0.653143 -2.218036 1.181937 2.090308 0.951769 -2.184690 0.843330 -1.014928 0.955301 0.640791 1.965897 2.267455 0.743003 37.657548 60.404218 13.698267 -23.230833 1.515729 1.857058 1.076537 0.360115 1.448426 2.443059 1.747443 1.517848 1.472687 0.699987 0.934243 0.579410 1.648038 0.329028 0.976076
+1 0.053548 1 1 1.878611 0.810456 -2.186754 -0.854328 -0.035197 2.199273 -0.801278 0.933631 -0.720520 1.060037 -1.507378 -0.693190 -44.972325 0.130047 -64.297573 -49.311882 -34.798639 1.214111 1.810854 0.777587 2.410439 2.496952 0.765335 1.234864 1.856900 0.667299 0.549113 0.938754 2.145222 2.245090 2.229737 0.688273
+1 0.028136 1 1 -1.863081 1.023141 0.430428 0.694375 -2.234741 -1.558057 0.475217 -0.525055 1.699160 0.704939 0.968097 -1.067376 21.642913 2.432796 -61.990205 30.631504 23.695570 1.396651 0.757074 1.890432 1.743332 2.177603 1.979263 0.716091 1.586964 2.105988 2.085716 1.125963 0.808761 2.089539 2.373853 1.847292
+1 -0.039067 1 1 2.255045 -1.203264 2.316590 1.165856 0.426745 0.038971 -0.032011 -0.795678 0.796715 -2.217023 -0.652839 -1.824117 27.560149 3.428458 22.100537 43.722444 -6.878385 2.049818 0.786019 2.366246 2.246629 1.100063 2.003496 0.760932 1.486793 1.529216 1.275316 2.228581 1.507574 2.045184 1.654210 0.555418
+1 -0.010164 1 1 -0.995921 -0.035816 1.218696 -2.131679 1.159957 0.239299 2.229840 -0.711340 -0.154804 -0.555329 1.831718 -0.349442 -45.581460 -37.606192 52.730046 33.882218 58.431242 1.433159 2.361215 0.945181 2.154641 0.804260 0.694485 0.701147 2.432404 0.412714 1.233745 1.051332 1.987673 0.317492 0.595213 1.737108
+1 -0.008894 1 1 1.798387 0.224686 1.674737 0.207957 -1.452875 1.127409 -0.158514 -1.646812 -2.104885 -0.893948 -1.483518 -0.233593 -18.149280 65.048534 70.714058 41.175991 -55.114931 0.375256 1.678156 0.267537 2.493641 1.377404 1.278016 0.364131 1.441363 0.744688 0.724316 0.333753 1.632324 1.725094 1.660452 1.960066
+1 0.011003 1 1 -0.245042 0.202623 -1.575238 -0.829544 1.806087 -2.306108 0.645799 1.303736 -0.721875 1.851052 -0.555851 -2.233288 -22.045112 -12.198235 34.266779 71.760031 70.837450 1.600439 1.319396 0.584808 2.370818 0.332303 2.017825 0.839346 0.880471 1.318858 0.551961 1.559174 0.793862 1.445490 0.352066 1.181294
+1 0.000400 1 1 2.306357 -1.162617 2.177679 -0.873491 -1.667233 -1.324731 1.276846 -0.270925 -1.265218 -2.211605 0.873875 -1.300216 -44.056264 -53.626990 41.173496 52.952556 23.612199 0.628523 1.338397 0.439497 1.370257 0.408061 1.784281 1.917643 2.329700 2.275228 0.258616 1.067129 1.992358 0.319132 1.147353 0.306278
+1 0.042878 1 1 1.545361 -1.798408 -0.581066 -1.908692 -2.159963 1.753409 -1.739148 1.088657 -1.143519 -1.993758 0.699941 1.778261 40.349265 0.088786 -7.769457 68.740338 18.857093 1.092545 1.662623 2.449804 0.355238 0.489141 0.996911 0.831365 1.752945 1.740977 0.856320 0.421934 0.938584 1.525077 1.470889 1.978942
+1 0.033186 1 1 1.299616 0.718381 0.682488 0.620993 -0.916610 -0.671523 -0.121462 -0.954494 -1.203059 1.049245 0.905687 0.865686 -72.436061 -32.871940 -28.687987 -58.999678 42.410353 1.237148 1.996720 1.628783 0.713885 0.520714 0.637737 0.937316 0.463701 0.929944 0.313287 1.922488 0.500228 0.574463 1.748821 2.180264
+1 0.043247 1 1 -0.537700 1.244367 0.488326 -1.678134 -0.750511 1.221356 0.158605 -1.533545 -2.231835 0.163923 -1.690370 0.945362 -47.160710 -30.044902 -64.663252 -45.271223 -73.450461 1.646417 2.323059 0.908537 0.538669 0.914315 0.900554 1.363052 0.819611 2.199110 1.185413 0.992850 2.329236 1.226830 1.836528 0.278356
+1 0.010501 1 1 -1.378108 -0.467876 1.377506 -0.221821 -0.641360 -2.100426 -1.350707 -1.747516 1.822073 -2.233807 0.006301 2.227156 41.404473 34.970627 51.326949 2.038081 54.033677 2.035120 1.264421 1.378326 1.025513 2.289736 1.087484 2.089181 0.861411 0.486729 0.949507 0.618023 0.368443 1.917337 1.675837 1.787522
+1 0.025316 1 1 0.854616 0.175929 2.164418 -2.267702 0.537623 2.171954 1.863387 -0.594333 1.302162 1.105353 1.426049 0.393604 -28.540511 19.638076 57.143774 -34.592870 -2.361372 2.311239 2.495455 0.369316 0.847320 2.157359 1.485206 1.857665 2.279031 1.178427 0.574466 1.798285 1.031969 0.557941 0.819607 2.139220
+1 -0.031406 1 1 1.729527 2.141811 -0.526751 1.468802 -2.044217 0.876466 -0.158882 1.592782 -1.199334 -2.316002 -0.718577 0.732048 -16.388509 -41.669188 15.953283 -73.174055 13.660136 0.413709 2.214758 0.930611 0.277526 1.623940 0.309788 1.602181 1.352005 1.895471 0.924279 1.863036 0.301963 0.586946 2.305704 1.710976
+1 -0.028108 1 1 1.761021 -1.038468 1.151367 1.949807 0.445967 -2.043090 0.970156 0.542026 0.784395 -1.938188 1.616268 -2.303112 -26.594170 31.779375 -34.046327 33.386399 -24.788953 2.456129 0.916854 0.812662 2.415595 1.401183 0.435021 0.405364 1.446805 2.204717 0.935888 1.213557 1.503037 2.300180 1.123510 2.325544
+1 -0.000309 1 1 0.857428 0.309928 1.777550 -1.260785 1.603999 -1.168345 0.156509 0.935570 -1.110911 -0.595514 0.307362 1.051089 -34.601282 6.246267 -18.995323 -54.394546 40.873564 0.804927 0.664798 1.258808 1.530595 1.967597 0.397497 1.983607 1.736932 0.363154 0.783922 0.880838 0.742003 0.593697 1.013221 0.453881
+1 -0.044443 1 1 -0.643984 0.910777 1.592976 2.061048 -0.736950 -1.768035 0.956416 0.531709 1.749024 -0.039761 0.894121 -0.324058 34.325942 16.107289 -34.794951 51.258900 58.339045 0.689864 1.796111 0.494756 0.866671 1.135270 1.985264 0.330313 2.315151 0.735560 0.310224 2.178208 0.896468 2.430516 2.438606 1.157769
+1 0.008727 1 1 1.119648 1.353261 2.260989 -0.255666 0.716426 0.814565 0.906802 0.757342 0.479848 1.900760 0.784774 -0.272395 73.209636 -15.647261 -33.521944 -3.314916 -63.793790 1.641634 0.697470 1.377087 0.443058 0.473545 2.117212 1.731836 2.461809 1.879484 2.237535 1.247303 1.665615 0.994501 0.820289 2.355131
+1 -0.000642 1 1 0.686871 -1.118521 -1.255108 -1.955581 1.465332 0.885203 0.595803 -0.163127 0.937981 1.705523 -0.743000 0.223965 -32.381590 -37.387326 -18.788747 -32.467267 22.642516 1.416442 0.389867 1.993937 2.102449 1.107454 2.477429 1.145937 1.257056 1.347744 2.276015 2.238665 2.246291 2.170138 0.256054 0.743192
+1 0.033813 1 1 0.600639 0.995528 -1.849676 0.121105 -0.343855 -1.785059 2.303170 1.815480 0.048274 0.808631 0.135384 -0.677207 -44.550427 40.974384 6.477672 -29.758601 -52.800902 1.003685 2.191273 2.228343 2.008055 0.874887 1.971902 0.755188 1.701279 1.898002 0.721311 1.566826 1.151779 0.445981 2.349387 2.393795
+1 -0.031972 1 1 -0.176598 0.722674 2.155454 -2.122266 -0.847498 1.658814 1.196204 1.545813 1.083533 2.263546 0.305753 2.278707 20.666494 -58.230887 63.475208 27.826766 -15.552125 2.356449 1.842202 1.130311 1.892132 1.069772 1.399410 2.142305 0.474746 2.049653 0.275686 2.198750 1.894110 0.553809 1.113546 1.372271
+1 0.040646 1 1 2.234989 1.006755 -1.648850 1.328408 -0.751337 1.479541 -0.637300 0.166482 -1.096127 -1.881328 0.656212 1.968284 -0.868785 -51.667106 -19.049385 -63.016059 39.091502 1.538228 2.003421 1.743201 2.232794 0.317916 0.959646 2.275930 0.810654 2.414160 2.039642 0.765008 2.483903 1.951174 1.137560 2.222975
+1 -0.002818 1 1 -2.097691 2.199245 -1.268854 -2.063816 1.332787 2.160980 1.211502 -0.526203 1.265466 1.668122 2.127721 -1.721344 -40.699401 -34.840706 32.258249 64.389899 -48.962103 1.284087 1.143579 2.140253 1.983754 1.959053 0.802948 1.153748 2.041996 2.078860 0.646102 2.031428 2.211147 0.995582 0.988593 0.537473
+1 0.037832 1 1 2.289371 0.802556 1.697280 2.091225 2.222592 -0.005130 -1.396512 1.228945 0.475318 1.168515 -1.998974 -2.139481 62.924184 66.755668 -37.481659 45.749282 8.179584 2.489124 1.950442 2.331297 2.106636 1.729993 0.733792 2.083736 1.603238 1.120454 0.463563 0.861024 0.725696 1.026844 2.165402 1.656278
+1 -0.034134 1 1 1.460166 -1.119825 0.374579 -0.206236 2.116620 0.210615 0.806872 -1.157475 -0.938875 2.119752 1.009867 -1.199046 -69.647217 39.216380 9.696942 -73.498905 -46.088235 1.300405 0.899662 2.124483 2.434640 1.989177 0.847712 1.994094 2.490010 1.091667 0.399259 2.347571 1.127353 1.673648 1.008603 1.597465
+1 -0.025952 1 1 -0.000490 1.190731 -0.906427 0.838636 0.198965 -1.789804 -2.061289 1.392330 -0.829948 -0.260196 -0.015524 -1.722715 -23.840412 -35.798358 -13.002362 19.294371 -19.502116 1.044107 2.047969 1.217735 1.979419 1.088349 0.881917 0.880512 2.011680 1.053119 0.514716 1.088141 1.882415 1.995077 1.008900 2.086505
+1 0.017869 1 1 -0.104915 -0.874055 -1.722579 1.531783 0.893944 1.423365 -2.302297 -1.278402 -2.318599 -1.954658 -1.870533 -1.707469 32.396616 -10.076087 1.213878 1.640663 -25.375689 0.786905 1.514867 0.867801 2.138027 0.575232 1.165828 0.328091 0.980605 1.270394 0.505773 1.530774 0.473985 0.514399 0.250753 1.649346
+1 0.013375 1 1 2.156279 2.304056 -2.137145 -1.160987 1.288075 -0.047049 0.936954 -1.425315 -2.193410 0.375210 0.970068 -0.930591 -0.883348 3.569065 -14.720222 -52.763717 0.203196 0.851609 2.238425 0.466872 2.459721 0.533612 1.420133 1.678226 1.448542 2.144525 1.787227 1.926911 0.589831 1.296800 1.062558 1.669240
+1 -0.003925 1 1 1.380406 1.393722 -1.007081 0.892282 1.762965 -1.352332 -0.782637 -1.508412 0.771929 0.601305 -1.946406 0.163120 -33.471471 -55.015926 -52.667620 -34.692460 -26.167009 1.541307 1.993491 1.356967 2.039687 1.514848 0.553616 2.369291 1.677375 0.635607 1.153729 1.723549 0.437798 2.071147 1.516210 0.945024
+1 0.054410 1 1 2.158441 0.944355 0.456260 1.312331 -2.337230 0.654308 -1.760633 -1.862817 0.752282 0.262141 -0.279457 1.425547 44.250640 20.504177 63.699883 53.934103 20.467688 2.131454 0.351668 1.236755 2.144243 1.535719 0.329778 2.325746 1.057295 0.948025 0.458093 1.166932 0.869044 0.518961 0.419367 0.544367
+1 -0.046687 1 1 -1.208481 -0.538248 1.445491 1.996055 0.198133 -1.633816 -0.459582 -0.594370 0.685034 1.002580 -1.136813 2.313160 2.331947 43.028352 27.509306 48.911027 47.624798 1.824727 2.179864 1.732470 1.875263 1.043327 2.444743 0.792661 1.508083 1.597490 1.262777 0.738174 1.498145 1.080401 2.290736 2.153021
+1 -0.070957 1 1 -0.956520 -2.271971 -0.533564 0.074006 -0.258537 -0.405724 -0.174385 0.213742 1.514732 1.781604 0.905180 1.769391 -55.213955 69.059674 -14.052486 69.875309 44.317333 0.496304 2.129967 2.349923 2.399682 1.712112 1.724820 1.552777 1.264403 1.072716 1.389308 1.096411 1.373145 1.694519 0.778884 1.703271
+1 -0.012539 1 1 2.178607 0.592838 1.840349 -1.378907 0.242542 0.187449 -2.138737 0.343164 -0.414100 0.418809 -1.379220 -0.309006 -12.847239 -73.542065 -21.481140 16.479581 72.319183 1.652509 1.220015 2.043114 0.614652 2.212622 1.037301 2.410468 0.734079 2.407460 1.932427 1.043749 0.532498 0.702048 1.827996 0.873213
+1 -0.012424 1 1 1.509962 1.718164 -0.330804 0.788610 -1.783529 -0.270453 1.949463 -0.620844 -1.288468 -1.849656 0.461811 0.344563 -14.525210 74.799985 13.349395 -36.718899 -34.535780 2.232214 1.817101 2.265932 1.522047 2.301167 1.958823 1.431590 0.730501 0.774642 2.403866 2.268704 0.860896 0.821230 2.409911 0.365492
+1 0.001487 1 1 -0.315706 0.087537 0.965979 1.029464 -1.697779 -1.060576 1.867200 2.234387 0.318902 1.805823 -2.029310 1.650930 20.365735 -13.087915 -68.595538 14.793516 -65.373196 1.715345 2.046718 0.437281 2.388726 2.059031 0.384884 1.502571 1.205980 2.409401 0.795524 2.365542 1.664004 0.920471 0.861712 1.045678
+1 -0.008334 1 1 1.355522 -2.138699 0.983121 1.676786 1.660763 0.963257 -2.301858 1.386163 -0.811002 -2.274390 1.230395 1.287699 -52.292104 -23.399111 31.143785 -66.400560 5.785158 1.842249 1.924721 2.036665 2.471297 1.587064 1.531163 0.262734 0.528139 1.679623 2.420952 1.445493 0.394558 2.082831 2.136505 1.981460
+1 -0.019947 1 1 -2.145590 -1.731791 2.220333 -0.266566 1.311447 1.641764 2.096920 -1.025197 -1.987423 -1.198462 -1.805294 1.490136 -51.848149 -61.846663 43.138004 70.426738 12.189154 0.821662 0.673848 0.354912 1.762234 0.372577 1.654584 2.337987 2.045894 2.334549 0.517179 1.971706 1.961504 1.496597 2.053986 1.085866
+1 0.041862 1 1 0.423380 0.042255 -1.397970 0.296037 -0.791895 -1.594803 0.214584 1.530683 1.259828 1.157778 1.323721 0.588098 72.910441 55.781746 23.799457 -52.532775 -18.349276 1.430759 0.261054 1.530060 1.974371 1.745906 0.447110 1.080890 1.510015 0.315627 0.741658 1.547903 0.348825 0.699346 1.401152 2.163169
+1 -0.005759 1 1 0.557147 0.456188 0.090504 -0.996006 -1.460230 0.029036 -2.078683 1.228781 -2.287688 -0.794074 -0.509496 -0.687751 14.455403 -48.048653 46.291399 -30.449762 30.854175 1.616832 2.343879 2.069518 1.137258 1.642683 0.316838 0.847622 0.481822 1.739167 1.925371 1.716230 1.183012 1.136437 1.348308 0.506809
+1 0.008214 1 1 0.847225 -1.532343 -0.888621 -1.490127 1.781581 0.519738 -1.535991 -0.939251 0.508321 -0.207729 0.581410 -1.733382 -30.853137 1.320502 -6.323480 71.280383 -40.601506 0.782448 0.848240 1.877420 1.305095 0.979329 2.325486 1.199971 0.416014 0.450566 0.664633 0.742382 2.460932 0.626334 0.542115 0.334363
+1 -0.000368 1 1 -1.033102 1.808060 -2.127574 -0.529466 -1.746123 1.667695 -0.332930 -1.945143 -2.175492 -0.064698 1.175817 -1.794484 -19.186621 30.462134 27.087369 7.409274 27.675348 1.218721 0.550732 1.156176 2.356269 1.066355 2.477584 1.501255 1.588467 0.364548 1.703769 0.991136 0.515088 0.590668 1.861936 2.053907
+1 0.004355 1 1 1.438145 1.062540 -1.844968 -0.851513 0.140293 1.718212 0.469474 1.912349 -2.349552 0.903934 -0.329992 0.299882 -67.844116 43.947320 22.606422 -3.859867 -72.788292 2.082679 1.838593 1.229726 1.001006 2.152328 2.425692 2.362553 0.928510 0.973019 2.022182 2.064032 1.189891 1.993015 2.348419 1.880680
+1 -0.012845 1 1 -2.309977 1.584504 1.056083 -1.985783 -1.920886 0.250109 0.130853 -1.441759 -0.541148 -0.156959 0.928808 -1.664123 -27.997701 -7.352676 23.567790 -46.158917 7.088600 1.946502 1.365811 2.178939 1.926229 0.377020 2.073658 0.972360 2.204682 0.347454 2.413418 0.811283 1.731361 1.235998 0.660161 2.070614
+1 0.028739 1 1 -1.729380 0.332713 -1.697989 0.129134 -2.052728 -0.792613 0.472759 0.567966 -1.495313 -0.547483 1.754610 -0.393278 52.611094 -15.346200 -73.589907 74.434552 21.510637 1.814121 1.682301 2.433836 1.977308 1.624337 2.474268 2.020487 0.580376 2.131446 2.469968 1.751741 1.756782 0.985962 1.305899 0.985298
+1 0.012223 1 1 2.130239 -1.804677 -2.278041 1.132889 -2.295813 -0.683877 -0.411036 0.087551 1.196153 0.687042 1.755534 0.991544 59.484130 -0.234963 -49.031553 26.685829 8.735366 0.854579 0.412534 0.453232 0.469198 1.067122 1.866047 1.397884 1.244156 0.537137 2.157147 2.424441 1.577309 1.836691 0.763243 2.081269
+1 -0.006992 1 1 1.382181 -1.760634 -1.891953 1.153529 0.600469 -1.851529 1.962206 1.494992 -0.134550 0.572742 -1.341146 -1.276758 55.434101 30.937787 71.390164 4.487744 -24.489151 1.537684 1.857716 0.873768 1.176706 0.896016 1.585612 1.880548 2.112978 0.318497 1.732719 1.563114 1.756073 0.324623 1.185003 0.842986
+1 0.016701 1 1 -0.321999 -2.007567 -0.471202 2.027164 -0.026683 -0.780159 -2.264895 0.584399 1.375726 -1.873125 1.850124 -2.012296 5.081514 55.013296 8.459982 -13.080757 51.724324 0.335653 2.070826 0.614354 1.702309 1.215705 1.600686 0.987348 2.112728 0.624166 2.356684 1.292027 1.851422 0.858447 2.420988 2.051130
+1 0.052610 1 1 -0.866191 -1.506705 1.187244 1.757709 -0.155059 -0.130823 1.936037 -0.074117 -1.621836 -1.734306 2.354562 -1.518961 -68.855348 -1.827469 35.723570 -43.959890 66.126218 1.875181 1.915590 1.578478 1.231854 0.770822 1.201742 0.930274 1.359786 2.180834 2.269534 1.306394 0.310180 1.437120 1.418886 0.968051
+1 -0.054644 1 1 -1.463771 1.791397 0.554004 -0.541741 -0.703042 -2.066565 2.267558 1.763530 -1.272128 -0.545613 0.184473 -0.308860 64.919088 -4.887069 63.022585 70.582932 -62.664633 0.557614 2.067167 2.122853 2.036229 1.901010 1.775569 1.732621 2.168279 0.518175 0.715380 0.886040 0.416960 0.591684 0.934640 0.491478
+1 -0.009032 1 1 1.946214 1.320531 -1.189972 -0.476699 -0.823168 0.581904 1.849517 1.909269 -2.292687 0.019631 0.070726 1.170894 8.815049 -45.469892 37.529272 4.466843 74.237570 1.537586 2.452350 0.401776 1.900502 2.233300 2.071268 1.299348 1.147396 1.043651 1.150800 2.000327 1.502286 0.918496 1.415940 0.952673
+1 0.035015 1 1 -0.144291 1.778559 1.559811 0.717658 -2.035732 2.104413 -2.314905 -1.129971 -0.499164 -1.393403 1.658096 -1.444382 -70.519881 72.361292 -23.762779 68.965010 44.925690 0.866162 1.583933 0.654498 1.403715 2.483532 2.469796 1.106027 0.998627 0.422579 0.529663 0.287675 1.207588 2.433032 1.966514 2.454523
+1 0.016610 1 1 -1.319896 -2.279396 1.915017 0.066570 2.013015 -2.210384 -2.170121 0.668044 -1.813382 2.216612 -1.547174 -0.390436 73.312990 71.425179 -7.021333 42.452924 -43.700715 2.456174 1.674038 0.797705 0.780405 0.269484 1.466515 0.463983 1.157574 1.088629 1.084735 0.898180 1.966155 0.915491 0.401074 1.349450
+1 0.008624 1 1 -1.509746 1.908924 1.345442 -1.914793 -1.016223 -1.959777 1.632606 -1.029311 -0.457731 2.247044 0.987457 -0.837890 -57.095681 -57.110670 -9.032105 -2.587088 18.817841 2.446771 1.125997 1.374143 0.478007 0.619032 1.576809 2.436477 1.361398 2.265640 1.105646 1.334375 0.346204 1.642455 0.993042 1.062398
+1 0.072668 1 1 1.095568 1.913685 1.243028 1.557535 0.166560 0.211411 0.046996 -1.815493 -0.278927 0.900425 1.958401 -1.197971 55.605011 53.412921 -39.032143 -63.232294 4.842586 0.465229 1.859243 1.804178 1.063077 1.393660 2.242701 0.318541 2.470163 0.526971 2.295360 1.112628 1.694332 2.131797 1.615783 0.469069
+1 0.040376 1 1 0.602401 2.342271 -0.755289 1.028464 0.347476 1.374899 -1.630283 -2.337380 -1.875906 2.245107 1.421110 2.202281 -66.104191 36.857916 -29.007725 -32.834473 1.015814 0.966715 1.823953 0.421552 1.281922 0.757472 1.831943 1.960274 1.077856 2.278132 1.806626 1.705958 1.791150 0.363747 1.746119 1.778672
+1 0.030801 1 1 -0.096215 -0.733031 -1.863349 1.233000 -2.056723 -1.966003 0.667828 -0.722292 -0.440610 -2.164407 -2.265040 -1.854424 13.893223 -46.594556 35.300237 41.080381 -12.035633 2.381693 0.855852 1.553574 1.167323 0.691427 1.066345 2.312109 1.364916 0.636238 0.510146 0.772876 1.982319 0.339007 2.184243 1.078203
+1 0.019403 1 1 -1.742995 -2.299768 -1.185075 1.705401 1.919733 -0.777776 0.086433 1.270788 1.581113 0.597396 -1.666282 0.526745 -50.338692 -42.391307 29.303114 47.431941 -61.371275 0.369591 0.963729 1.149193 1.990220 0.378593 1.515512 0.466100 0.744235 2.107841 1.724665 1.200364 0.266396 1.324388 1.235416 2.133777
+1 0.020161 1 1 1.652151 2.315172 0.900381 1.229929 -1.831275 -1.628714 0.465020 -2.255762 -1.429725 -0.909376 -1.603297 -1.165792 20.499747 -10.750020 74.416833 23.719243 -50.679665 0.278178 1.340978 1.074433 0.989837 1.185981 1.529077 1.204106 2.416187 2.347373 2.305194 2.151609 1.583523 0.528178 2.336328 1.158102
+1 -0.013385 1 1 -0.577385 -1.292825 0.309599 0.949064 -0.519419 2.184609 -2.204457 -1.499646 2.013405 -0.366383 1.296660 -1.832646 -35.033905 -64.843659 72.622711 19.899094 -55.919943 2.177859 1.777049 1.857263 2.265904 1.042070 1.568811 0.756722 0.471637 1.548173 0.390923 1.739881 0.433632 1.801094 0.991634 2.148627
+1 0.009990 1 1 1.327213 -1.981032 -2.175802 -0.559966 -0.703301 -1.712981 -2.091540 1.902032 -1.387541 1.203999 0.606725 -0.379602 19.104918 -53.640100 -29.167365 -15.896601 -24.167017 1.749224 2.203393 1.185054 1.705368 0.863520 2.185439 0.917896 0.330742 0.524076 0.895868 1.350636 1.389936 0.411410 1.824497 0.575675
+1 -0.019467 1 1 2.170457 0.263267 -0.212801 0.160453 1.247643 -0.992627 -1.221760 -2.232596 1.508472 0.233186 -1.546891 -0.353967 -66.385476 -40.700350 -50.778324 68.706474 49.711781 1.463639 1.626053 2.066274 0.615406 1.382113 1.671040 2.173749 2.449289 0.699495 1.661397 2.106413 2.492324 1.739041 2.066495 2.089797
+1 -0.042702 1 1 -0.400222 -1.950362 -0.351503 1.631541 -0.086279 1.325849 -1.347793 0.101519 0.352412 -0.479068 1.772159 -2.328590 -6.914739 33.980459 59.576017 44.117438 31.781816 1.479663 0.948811 2.416130 1.396065 2.156854 2.002386 2.357350 1.238128 0.464051 2.302673 0.277025 2.216242 1.124932 1.488962 1.990920
+1 -0.003834 1 1 -0.108520 -0.197099 0.169767 2.284123 2.132783 -1.450382 0.621531 -1.291960 0.721171 0.454871 1.515834 1.456032 2.887035 72.394304 -68.937375 -30.465502 66.305676 2.117496 2.010550 2.317178 1.066571 1.609561 1.643945 1.283634 0.287282 1.346059 0.966515 0.724852 0.330677 1.685520 0.285106 0.778681
+1 0.030051 1 1 -0.139258 1.550929 2.237756 0.386652 0.069993 -1.726863 0.224338 0.534534 2.092618 2.067403 -2.316334 -1.572880 35.432471 13.534068 67.086492 -27.323709 70.419925 2.090117 0.855227 2.301140 1.511933 1.058118 1.288801 1.622784 1.128226 0.589685 1.089787 0.306464 1.995489 1.183787 0.661636 2.124519
+1 0.001575 1 1 -0.170583 -1.860970 -1.192049 2.314460 -1.643908 -0.433542 -1.181097 -2.115332 -2.126129 0.187062 0.783053 -0.924264 -66.105822 9.451927 8.542645 26.228531 -27.083649 2.201611 0.468992 2.094280 1.064087 0.364635 0.919217 2.284276 1.583643 0.284620 1.613305 1.566750 2.126370 0.403412 2.389266 2.142346
+1 0.001479 1 1 -0.442976 0.469645 0.077260 -2.104131 2.340347 -0.100536 2.037783 -0.623984 -2.234800 2.169870 -0.175936 -2.282142 -58.109772 -0.941323 -70.818603 1.733281 31.259808 0.378830 0.990836 2.237325 2.222689 1.491187 1.132045 1.774728 1.096995 2.198958 0.881972 1.809668 1.092310 2.211476 2.031691 2.130525
+1 0.004051 1 1 0.470958 -1.419545 0.532111 -0.921719 -1.704740 -0.245058 -0.053994 2.006508 1.518018 0.450719 -2.279897 -1.795306 -8.966745 45.917014 -22.737947 43.331219 17.793960 0.821310 1.514050 0.645325 2.482773 0.966185 1.921256 2.300441 1.021088 2.172168 0.630630 0.747627 0.615513 0.931927 2.153104 1.968484
+1 0.000619 1 1 -1.025315 0.744610 -1.448559 -1.726977 -1.702431 0.870687 1.673934 0.847638 0.705325 -1.972355 2.282359 0.757864 -5.233026 -51.468105 25.564779 67.245610 -53.038072 1.961907 1.520484 0.771917 1.609938 1.226014 1.614580 0.501902 1.720319 2.406138 2.205295 1.647751 2.243700 1.359232 1.857961 0.496307
+1 -0.029447 1 1 1.251257 -1.514536 1.526944 -0.323499 1.047905 1.945169 -2.093699 -1.398027 -0.661428 -0.096902 1.846327 0.138833 23.185589 -19.813883 -11.939008 41.098151 -13.379034 1.203546 1.992500 0.453013 1.281470 2.164998 1.616367 1.280936 2.184450 2.305993 2.075061 2.041622 0.285778 0.820647 1.614720 0.602519
+1 0.015559 1 1 0.919396 0.369628 1.406936 -0.391499 -1.434075 1.378519 -2.040590 0.568467 2.208925 1.196902 -0.855189 -0.368508 -45.786346 -31.115532 -58.753268 -16.180263 8.321494 2.265191 0.315665 1.375629 0.700662 1.030147 1.423957 0.694835 2.092578 1.705687 1.725385 2.052940 1.513145 1.182748 1.190345 0.631819
+1 -0.033338 1 1 2.165138 0.411093 0.873676 0.073235 0.922297 2.006782 1.423596 1.586720 0.590928 -1.988662 1.528321 -0.741206 66.891563 -3.499796 -21.076437 68.324276 -73.885662 2.180266 1.726509 0.690955 2.127601 0.838635 2.433702 1.976396 2.034355 1.911071 2.125983 0.643101 1.100963 1.394316 2.016265 1.614861
+1 0.053625 1 1 -0.626606 0.821508 -0.208079 -0.583504 -0.462831 1.346672 -0.082796 -1.396485 1.688112 -1.195401 -2.194899 -1.084099 74.714060 69.204651 22.576449 -57.622908 -68.212818 1.332441 1.591069 1.351565 1.248055 0.807882 0.824044 2.460457 1.655858 1.248679 2.301370 0.881742 2.436883 1.446301 0.485052 2.017710
+1 -0.042904 1 1 -0.432866 0.743299 0.079964 0.926426 0.714124 -0.168224 0.091787 1.714457 -1.375965 -2.151502 -2.138198 -0.017728 -34.428436 61.269314 3.358810 51.519096 -68.558562 1.918701 2.114068 0.641182 0.346586 1.324158 1.865801 1.760572 1.686677 1.728625 2.498033 0.933973 0.540447 1.538387 2.416480 0.527528
+1 0.003836 1 1 -2.166820 -0.402757 -2.149905 1.143507 1.794122 -0.766137 -2.209959 0.272568 0.614269 -0.821271 -0.522022 0.846221 14.113579 56.928294 -56.165416 -22.139183 56.744474 1.440712 1.046016 0.395976 1.162887 0.385545 1.363002 2.223095 1.558868 2.402554 0.477281 1.909304 1.663319 0.646749 1.662850 1.768158
+1 0.004032 1 1 0.168077 2.152016 1.347127 -1.859730 0.794663 0.996533 0.893395 1.626628 2.170428 -0.226290 -0.366424 0.607909 21.436042 -24.442704 41.474290 8.398910 10.478393 1.530233 0.381037 2.091196 0.980141 2.487985 0.815386 0.943674 1.579853 1.830559 1.208174 1.032741 2.271719 2.037257 1.173827 2.002845
+1 -0.022192 1 1 -1.857619 -1.418425 0.513314 -1.117361 -0.610418 -0.432102 -0.551719 1.244198 -2.340106 -0.568416 -1.352587 -0.367979 -62.782094 71.341950 -55.840833 33.117635 -41.905149 0.627391 0.312484 1.912098 1.387494 2.114043 2.464173 1.111981 2.058877 2.299940 1.596907 0.468731 2.212603 0.719364 0.352247 1.962371
+1 -0.024002 1 1 -0.100640 0.283838 1.531506 0.958750 2.055246 0.712304 2.232213 1.469267 1.057387 1.077740 -0.841148 0.000469 -49.072318 -58.455667 35.609286 -14.734043 14.931642 1.466713 1.543784 0.876264 0.362306 2.275876 2.147434 1.177351 0.482622 1.674364 1.788805 1.448518 1.736517 2.393487 1.082451 0.761829
+1 0.038563 1 1 1.679006 1.267341 0.211099 -0.490905 0.745952 2.254185 -1.528719 -1.238406 0.725404 0.910551 -2.201995 2.177329 -64.924345 66.530491 -72.035606 -52.428385 -63.864730 1.757334 1.258384 1.153659 0.547158 1.828440 1.590661 1.241568 2.035609 0.486253 1.955135 2.456835 1.533500 1.287019 0.923714 1.368561
+1 -0.013277 1 1 -0.277838 0.353014 0.202404 -0.532867 2.349913 0.460174 1.112129 2.211278 -1.658620 2.059568 -2.050691 0.455688 35.400976 -65.804764 -30.675907 -19.971967 31.152243 0.261129 0.551401 1.150174 0.480161 0.815153 1.522428 1.951859 1.395980 0.732577 1.913780 0.400593 2.273195 2.084734 0.374629 2.386066
+1 -0.014963 1 1 1.701768 2.124761 0.372194 2.131369 -1.670677 2.055189 -0.256926 -1.599301 0.018477 -0.476340 0.498120 -2.007071 -49.862188 16.213787 -44.887475 -73.786513 70.076492 1.008894 1.985797 0.294888 0.939783 1.439874 0.462795 1.453684 0.809922 1.351117 0.478694 0.918323 0.759626 2.026584 1.795251 1.783833
+1 0.040178 1 1 1.378045 -0.592597 2.215406 1.751300 0.519340 1.209103 1.574810 -1.649620 -2.180539 -0.069860 -0.758068 1.454463 63.841161 28.395056 -64.296865 -37.416192 -53.937551 2.448753 0.689875 1.971025 1.765668 1.828918 0.621731 1.933445 2.403908 0.727039 1.102834 1.325422 0.613413 1.630273 0.996870 2.390868
+1 0.040776 1 1 1.556262 2.330135 -2.087086 1.370479 -0.514131 1.527421 -1.728268 0.165728 0.373816 1.118914 -1.562272 0.317718 24.081721 41.480823 -31.802217 -49.853521 11.875823 0.579462 0.261829 1.056052 0.318782 2.026120 0.749142 1.336547 0.853622 2.319366 1.837918 1.135302 0.267101 1.914937 1.847018 1.075950
+1 -0.007762 1 1 -0.467038 1.328251 1.335464 0.034365 -2.043912 1.290190 -2.191280 -1.520518 -0.066069 1.694689 0.960292 -0.312913 -3.509172 -28.657643 0.998240 -22.586196 43.805651 1.998658 0.442240 2.474373 1.536562 1.003035 0.261637 2.332787 2.408234 1.429891 1.432923 0.631313 0.974350 1.897073 0.860586 2.368271
+1 0.009037 1 1 0.444405 -0.029946 0.931521 1.521778 -2.330667 -2.138315 -1.986172 0.961848 2.288339 2.303891 -0.199342 0.161593 49.401576 42.291189 -61.981505 26.848822 48.153223 2.293241 1.505382 1.197853 0.810969 0.949090 0.357802 0.821038 1.440449 1.132308 1.699970 2.396816 0.788372 1.414778 1.673608 0.332898
+1 0.021672 1 1 -1.954818 0.154529 0.644329 0.161049 1.842372 -0.361259 -2.121395 -0.354050 1.230074 0.610498 1.775231 2.168863 55.589490 -57.436444 65.681050 51.401341 52.338137 2.081064 1.692013 1.415852 1.730216 2.240813 2.338552 0.293539 0.761008 0.511198 0.452063 1.079054 2.158150 1.277486 0.459550 0.902530
+1 0.014786 1 1 1.676672 -0.259552 1.389479 -1.632303 1.409400 -1.397777 -1.175997 -1.215698 0.684146 0.217368 1.198361 0.101102 -62.149685 50.238951 16.052275 -59.413955 -20.339015 1.557504 1.971455 2.237430 1.744082 1.293773 1.946052 0.540312 1.518826 2.154834 1.795750 1.173658 1.413270 1.080118 2.049653 0.264222
+1 -0.002380 1 1 0.729081 1.460070 1.980610 -0.200834 -1.345772 1.073693 1.823922 0.575226 -2.001185 -1.599458 2.082006 -1.923138 3.038058 60.646686 38.859000 3.211718 -20.651338 1.569389 1.466612 2.104257 2.241826 1.368870 1.855334 1.354099 1.089303 1.167291 2.405029 1.578075 1.201240 1.496161 1.484896 1.149653
+1 -0.011885 1 1 1.793976 1.495332 0.882730 1.442718 -2.187326 -1.041633 -0.205007 -0.802976 0.656582 -1.239961 -1.841771 1.045424 -65.506392 34.069413 54.626988 -34.211822 -48.093105 2.112828 2.301331 2.477186 1.556856 2.334081 1.645931 0.913001 1.309490 0.600154 1.546042 0.582824 0.523376 0.385617 0.316741 1.458369
+1 -0.006991 1 1 0.692898 1.231879 -2.047994 -1.345379 -1.747155 -1.531851 -2.042047 -0.345853 2.332079 2.321693 2.110780 1.014676 -15.294487 45.555009 43.036330 11.598491 -64.164716 0.379149 1.865380 1.446043 0.648560 0.606407 0.881238 0.724561 2.193454 0.624487 1.008029 0.951901 0.347719 2.371044 1.881587 1.576697
+1 0.057724 1 1 -0.936129 1.146182 -0.372803 1.770907 0.187862 0.092846 0.655545 0.178097 0.915913 -1.623194 -0.994371 -2.253760 -24.378562 69.506958 3.450676 -54.483037 53.593004 1.189261 0.404084 2.437395 1.047350 0.310963 1.110413 0.468893 0.434935 1.205130 1.613125 0.782909 1.857792 2.161697 2.396852 1.385751
+1 -0.008060 1 1 -2.083500 0.383281 -0.030839 0.058938 0.968163 0.032966 -2.006557 -2.351452 1.948186 1.483169 -0.917528 -1.952120 -51.870911 5.602364 -41.061987 21.179176 8.403269 0.381069 0.369529 2.168721 1.197569 0.545179 2.328378 0.302904 0.659705 1.158900 0.875385 1.351372 0.266126 1.285002 0.772724 1.668541
+1 -0.018408 1 1 -0.145442 1.294633 1.795083 1.243706 -1.188709 1.894275 0.178411 1.478599 -2.330815 0.085867 1.178598 -2.189172 29.370034 -27.830750 -51.414986 18.332026 6.353340 1.083907 0.465713 0.987622 2.221143 0.250149 0.510862 1.551845 1.366171 1.479311 1.784682 1.900377 2.389057 0.887614 2.132393 0.375895
+1 0.052922 1 1 -0.862532 -1.265659 -0.200478 -0.068704 -0.166634 -1.454371 -0.454788 -0.119266 -1.732066 2.297236 1.045759 -1.147177 -70.408195 -0.533347 36.035294 -54.820041 -60.428301 1.848058 0.554901 1.476768 1.786112 1.184120 1.757688 0.464370 0.916387 1.970329 1.323248 2.333032 2.021491 1.705979 2.138477 1.379247
+1 0.070393 1 1 -1.196542 2.189275 0.812486 -1.058427 0.292004 2.116773 -1.929110 -1.313940 -1.134596 1.881973 0.759817 -0.323733 58.470484 63.431263 39.229211 -74.655671 12.138703 1.602689 0.892442 2.276982 0.481565 1.909684 1.306157 0.835736 0.963896 1.696030 1.432844 1.563237 1.570644 2.315637 2.163281 2.007174
+1 0.046836 1 1 1.560177 2.164194 -1.315062 -1.143460 -1.001183 1.060402 -0.078249 -0.377012 1.721211 -0.957627 -2.026209 1.940746 -33.204756 -72.338885 -49.634680 -60.060897 56.496738 1.985135 0.410579 1.350877 0.938568 1.264212 2.369103 0.770145 1.075146 1.727406 2.267817 1.706129 2.410010 2.032867 1.638740 1.561643
+1 -0.001670 1 1 -1.581691 -0.892283 -1.782069 0.708740 -1.119080 -1.228394 -0.646716 2.127835 0.207010 1.477153 1.638050 0.922934 -45.443801 26.040350 -39.840384 2.659892 4.798209 0.527458 1.485706 1.262916 0.825443 1.226081 0.492722 0.430796 1.393994 1.102716 1.604691 0.793363 2.048710 2.412426 2.137501 0.722158
+1 -0.031557 1 1 0.980240 0.379600 -0.639846 -0.214515 -0.382987 0.269009 2.056172 2.132606 0.277384 1.436570 -1.840029 2.037925 56.260759 -25.416407 26.455166 31.975442 -38.746506 0.437021 0.267491 1.718602 0.538897 2.499663 1.335554 2.151418 0.630686 1.681256 0.619990 1.918727 0.288629 1.487344 1.796302 1.447189
+1 0.012316 1 1 -0.502056 1.825336 0.762734 1.573986 -1.376904 0.915464 0.256491 -0.997661 -1.013529 0.911788 -0.273554 1.661897 37.379189 32.026466 68.811470 14.374521 -57.425600 0.594205 0.557321 1.645077 2.310974 0.287442 1.787892 1.849520 0.391789 0.541651 1.530225 2.483489 1.742161 0.491903 2.421711 0.687851
+1 -0.013220 1 1 -1.343922 -0.824389 -1.079371 1.703977 1.546087 0.966319 2.031290 -1.366585 -0.015345 1.280460 -0.793497 -0.249166 50.236497 -25.199343 74.635411 -52.651507 -63.880909 2.178555 2.222022 1.517352 2.132380 2.404141 2.399553 1.789949 0.418063 1.140332 1.557526 2.339384 0.776158 0.883687 1.374450 1.133033
+1 -0.000582 1 1 -0.226000 -0.201794 1.373629 0.583856 1.670748 -0.859215 -2.064426 0.512568 0.483289 -1.521831 1.426864 -0.053116 -66.382022 17.363484 -71.928090 -45.408161 25.040521 0.715654 0.999103 1.676389 2.075423 1.382636 1.469965 2.202442 0.950255 1.928037 1.518717 0.334469 2.428339 1.848248 1.509148 1.500492
+1 -0.056980 1 1 0.969855 0.198081 2.201803 -0.685011 -0.619461 -1.622086 -1.238326 2.082990 0.467500 1.718289 1.759605 -1.276208 49.677802 34.812822 -50.894196 71.240097 32.313854 0.609197 0.516135 2.424536 0.927064 1.416930 1.835831 2.055472 1.319281 0.897870 1.248052 0.765620 1.519988 1.441717 2.195145 2.055597
+1 -0.020331 1 1 -1.279338 0.804315 -1.714357 -1.656942 1.999747 0.984427 0.063474 1.809464 -2.097178 1.391762 -0.951827 1.210076 -29.482456 -61.630491 -73.666118 -6.449390 55.104877 2.090057 2.086087 0.614790 2.281383 2.461252 1.505104 1.031239 1.787108 2.174835 0.460940 1.765921 1.584336 0.683087 0.392972 2.437501
+1 0.005303 1 1 -0.039405 2.159166 -1.005114 0.969947 1.738227 2.286781 -0.316244 0.462075 0.073593 2.228207 0.118739 2.308048 -32.619009 22.310132 -33.609577 23.832435 51.740870 2.257092 1.448830 2.489874 1.055324 1.587711 1.159081 1.673701 1.899090 0.999884 1.300835 1.382325 0.738902 2.475994 1.786755 0.745686
+1 -0.024994 1 1 2.038118 0.297184 -0.363327 0.817251 -1.082358 -1.360801 -1.751533 0.277330 0.534279 -2.179260 -2.128804 2.354282 -47.985900 50.981139 39.995089 47.458766 -60.517230 1.928668 0.867369 1.615427 1.223480 1.770515 2.288890 0.371418 2.424473 2.113707 1.324961 1.874112 1.950023 2.033884 0.741662 1.616614
+1 -0.081310 1 1 1.859318 1.703956 1.201619 -1.686479 0.364474 -0.387502 -0.232103 0.909122 2.049414 1.652492 -1.383183 -0.940799 -61.775153 45.011226 53.669188 68.043477 6.717411 0.617789 0.928073 0.376758 2.169653 1.100327 1.950310 2.361782 1.463376 1.716447 0.328954 1.975426 1.482271 2.026041 1.663615 1.136459
+1 0.041590 1 1 -1.442926 -1.298472 -0.344028 0.030521 -0.691882 1.721082 1.581629 -0.146393 -0.568129 -1.239775 1.290303 -0.297040 -61.549078 -55.360067 13.357487 -50.720863 -15.544995 1.904062 1.329262 2.161049 0.500321 2.145039 1.423301 0.917309 1.705253 1.183397 0.849202 2.294547 0.952507 1.533520 1.619254 0.301474
+1 0.016027 1 1 2.337688 2.338349 -0.689407 0.906659 -1.649469 0.364317 1.675879 0.554060 0.400787 2.028795 -0.890286 -1.206549 -33.937190 67.651780 23.464383 15.877611 5.010809 2.374996 0.804652 0.531149 0.522111 1.615958 1.155091 2.107984 1.883587 1.439634 0.934344 2.271068 2.343639 0.286013 0.264116 1.244263
+1 -0.009652 1 1 0.237424 -1.008745 1.198984 1.149798 -0.856319 -0.518699 0.141979 1.775414 0.532967 -0.667886 -0.253282 -1.621400 28.097823 40.105027 -54.816455 -0.152736 -17.033660 2.354143 1.324608 0.438447 1.725162 0.539932 1.881922 0.454375 1.682440 0.267248 2.139999 2.212136 1.864475 1.990404 1.214382 1.866159
+1 0.066797 1 1 -0.731469 0.827672 -0.297246 -0.680218 -0.165600 1.777004 -1.021231 -1.306725 2.313649 -1.134712 -0.069322 -1.131241 54.737270 19.293514 -33.918288 -64.665326 69.861128 0.714590 1.120649 1.496031 1.539171 2.098385 0.301987 0.988404 1.852315 2.363781 1.309902 0.767663 2.113924 0.470163 1.532780 0.429283
+1 0.005764 1 1 -1.593943 0.540039 0.373290 1.700280 0.673971 -1.147702 -1.621242 -1.177860 0.459033 0.793724 -0.656119 -0.394207 5.788477 -63.060201 47.193959 -11.130028 -12.380630 0.906267 0.625340 1.840651 2.076003 2.136586 1.094563 1.826257 0.899120 2.006653 2.069924 1.210345 1.522919 1.203768 1.222509 1.205153
+1 0.001177 1 1 0.307092 1.221080 0.231783 -1.565743 -1.467832 -0.502618 1.806096 -2.151097 -0.045398 0.404467 -2.104940 -1.821318 25.125733 38.190529 18.215638 0.220825 -38.596975 2.134672 0.428338 0.581975 2.009202 2.158125 0.863121 2.224241 0.567648 1.955301 0.740800 0.629347 1.689809 0.364042 2.199184 2.434232
+1 -0.035479 1 1 -1.271079 -1.758171 1.802504 -1.255327 -0.915939 1.186856 -0.059185 -0.416123 -0.599355 1.731494 2.218885 -1.044426 -0.862794 49.016004 11.979961 47.211851 -10.421355 2.099264 1.588647 1.145747 0.328343 0.716054 0.963083 1.538321 1.318556 2.216034 2.135238 0.953261 0.700510 0.726670 1.648855 0.557685
+1 0.038409 1 1 0.414183 0.967765 -1.944508 -0.927086 2.337383 1.919536 0.625696 -1.981431 0.545541 -1.393282 -1.022598 -0.720214 47.378481 -59.868598 -11.526595 72.513476 -16.001606 1.540088 1.764843 1.469564 2.219215 1.604017 0.712516 2.249983 1.211367 0.702142 1.153520 0.462460 0.310668 0.644688 0.768076 2.308674
+1 -0.002062 1 1 -0.336320 2.333048 -0.248635 1.072577 1.906339 0.312279 -1.120164 -0.604345 -2.021990 2.159504 -0.042713 -1.591774 -22.713181 9.565320 -35.673438 -13.479414 -48.506315 1.440464 1.385284 0.961665 2.455448 0.715911 0.816576 0.700867 2.229550 2.053125 2.379046 1.375034 1.953863 1.320867 0.555896 2.447039
+1 0.022787 1 1 -1.798164 -1.186214 1.417201 -2.222608 -0.263769 1.198529 -1.786911 -0.560668 1.630983 -0.034080 2.128658 -0.104357 -29.269912 60.596014 -62.796329 -17.894897 -9.525683 0.652728 0.893946 0.544117 2.482149 1.729388 1.828367 0.366566 1.876507 1.701783 1.374394 2.446217 0.816859 0.949734 2.182680 1.800415
+1 -0.008908 1 1 -1.608777 0.977887 -1.468563 1.360033 -1.723299 -1.139377 1.633833 0.743196 -1.641230 2.165620 -0.910620 1.042828 45.791256 -36.367143 27.422556 -59.105174 69.344441 0.955324 1.627051 0.848037 0.701472 1.144678 0.344268 0.617475 2.405206 2.291214 1.190325 0.288296 0.396681 1.770218 1.797050 0.511887
+1 -0.002906 1 1 1.926066 1.995457 -0.430563 1.757769 0.852379 0.275483 -2.234516 2.220833 -1.292642 -1.314273 -2.024489 -2.138141 30.237927 8.844359 -2.864123 12.683021 13.535379 0.461666 0.471142 2.232061 1.494149 1.409045 2.061053 0.621034 1.465263 1.918508 1.112980 0.863796 2.323437 0.506719 1.673037 1.981393
+1 -0.043398 1 1 1.006687 1.908724 -2.023149 1.539597 0.287632 -0.673763 -0.069337 -1.383691 -0.052989 0.048033 1.478395 -1.050119 -46.483435 -47.087006 8.695215 40.484025 15.013832 1.937014 1.640586 1.083367 0.398598 2.487774 1.764799 0.728212 0.552234 1.639872 0.328769 1.123419 0.802442 1.650871 0.693215 1.860417
+1 0.010120 1 1 1.335766 0.394243 0.423218 2.023281 0.689373 -1.469019 -1.593567 2.133472 0.693455 1.166735 1.061594 1.098780 -21.041729 51.666231 4.345594 -13.603415 -32.590576 2.127741 0.949870 2.213229 2.241115 0.675782 1.368517 0.409896 1.121425 1.033205 1.068198 1.949702 1.150395 1.935252 1.283860 1.832515
+1 -0.003626 1 1 1.346015 -1.711997 0.312227 -2.000622 -1.554439 0.023862 0.488493 1.124740 2.118501 -1.166524 -2.231867 -0.381324 -2.005133 49.729298 0.306737 55.329413 71.445147 1.803818 1.767301 2.280773 1.198569 1.595432 0.422469 0.933042 0.643870 0.515224 0.622380 1.585998 1.612947 2.304643 1.889048 0.973376
+1 0.002132 1 1 -1.805225 -2.058070 -1.054792 0.119173 0.177426 -0.941876 -1.192533 -1.110110 -1.262782 1.022468 -1.469995 0.853210 3.219017 -47.983566 -59.787620 -0.534286 20.257333 0.849986 1.963632 1.268068 1.923642 1.900973 1.156918 1.315082 2.334376 2.101197 0.313564 2.069238 0.931182 0.872410 0.841648 1.322132
+1 -0.045766 1 1 0.169780 -2.215685 -1.713417 0.006110 -0.983695 -1.902891 1.101696 1.233206 1.403812 -1.067532 -1.936325 -0.053705 68.457915 72.172747 -42.647562 72.429414 71.157171 1.203540 1.904348 1.627136 2.270923 2.159237 1.542588 1.034140 1.047416 1.413255 0.819993 1.878188 0.710128 0.374340 2.036544 0.449552
+1 -0.004001 1 1 0.475437 -1.534713 1.695938 -1.615760 1.426588 0.027475 -0.048463 0.728313 -2.037112 -2.236185 -2.258911 2.203967 -64.369100 -51.459809 14.982547 -38.327076 -63.169288 1.581695 1.305267 1.613438 1.545986 1.889563 0.628767 0.937568 2.447566 0.986231 1.335758 1.083617 2.356911 0.606067 1.924794 1.011323
+1 0.065584 1 1 0.777928 -2.239546 -2.205101 1.812388 -0.085609 -1.552724 0.579804 -0.458778 -1.216238 1.037367 -0.810931 -1.089480 46.073312 54.157460 24.423661 -61.528574 -10.745462 1.390208 0.484430 0.570834 1.504783 2.384842 2.042001 2.160004 0.929889 1.647409 0.995715 0.976299 0.907437 2.296054 1.536223 2.058952
+1 -0.032846 1 1 2.225380 -0.266456 -1.564495 0.664522 0.265749 -0.908947 0.895710 -1.887772 0.737604 -1.385779 -2.169688 -1.480871 58.504983 43.251351 25.455802 35.661543 -36.445189 2.360623 2.240203 1.100417 1.202139 0.858331 0.463271 0.445537 1.648826 2.320047 2.038332 1.252587 0.478469 1.627686 0.267125 2.322523
+1 -0.012537 1 1 1.238450 0.001814 2.209553 2.323306 0.948404 -2.180817 -0.029691 0.499418 0.961373 -0.978786 0.492897 -0.255442 -7.440269 51.393687 73.701975 9.100563 -46.842715 2.342390 1.797627 1.221918 0.282453 1.190500 0.977751 0.569534 2.161746 0.968873 2.095599 0.739711 0.327565 1.130489 0.385912 0.779297
+1 -0.045284 1 1 -0.938646 1.251238 -1.843808 -0.213683 -0.532336 1.856656 -0.627303 -1.469852 -1.465572 -0.209945 1.042029 2.137671 18.437007 -29.219885 1.394603 39.090574 -4.723501 0.806831 1.154718 0.351336 2.399420 1.804603 1.456743 0.476121 0.418134 2.326144 1.005497 1.129776 1.900896 2.111663 0.725567 1.098059
+1 -0.018297 1 1 -0.355298 -0.891511 1.769659 -1.933871 -1.227422 1.553174 2.273628 0.105044 -1.672430 0.872861 0.512247 -0.204534 -72.074391 45.704710 9.069259 27.037438 68.222526 1.614939 2.024892 0.360936 1.755374 2.068545 0.543633 1.087957 1.040322 1.440742 1.546773 1.611159 1.497118 1.811599 2.042345 1.193454
+1 -0.006114 1 1 -0.518605 1.726235 -1.347828 -0.493296 -1.727858 2.335942 1.256965 0.168953 -1.978522 2.313623 -1.569132 -1.877025 72.727956 -11.248319 -50.499908 -51.956652 64.554515 1.641042 1.991771 1.688501 0.886347 1.076916 2.231558 2.045984 1.608056 1.090516 1.309442 2.036797 2.448525 1.360814 1.443754 0.417277
+1 0.011776 1 1 -2.039908 -2.099811 -0.441716 -1.900795 -1.372730 0.388232 -1.640433 1.432151 -0.715431 1.765972 2.073546 1.980050 -6.326606 18.738836 -56.388426 -20.273512 63.087042 0.683846 1.896072 2.039431 1.719633 2.122607 2.406700 0.407861 0.666550 1.451063 1.764829 1.236223 2.202946 0.420237 1.673495 0.677991
+1 0.026356 1 1 1.837924 0.284293 -0.246055 2.037104 2.092718 -0.954919 1.072542 1.320007 -0.572499 0.701588 1.187318 -1.708807 66.767498 11.344121 10.641944 59.147820 47.416370 1.028836 1.889472 1.351492 2.278785 1.535867 0.570899 0.356405 2.097941 1.847041 1.470610 1.797501 1.349818 1.140043 1.196400 1.141106
+1 0.023012 1 1 0.542951 2.198095 -1.750125 0.389675 -0.951713 -1.596898 -2.018142 0.859992 0.986342 -0.737217 -1.532618 -0.797076 27.415645 -25.253972 56.491945 -39.883513 27.790571 1.016933 2.087524 2.269140 1.430214 2.354924 0.952294 2.451993 1.152030 2.427116 1.531871 0.898910 0.722161 2.361923 1.585071 1.796228
+1 -0.030720 1 1 -0.545862 0.726186 -0.076880 -0.919229 -2.274901 2.059822 2.219380 -2.159164 1.037716 0.346717 -1.949791 -0.181679 5.002040 69.279810 -64.226421 -53.464573 70.923830 0.877158 1.899917 1.409512 0.919217 2.281441 1.184079 1.066592 1.967295 2.071819 1.558405 1.361499 1.720522 1.317224 2.325453 0.638304
+1 0.003150 1 1 0.440231 0.503630 1.058941 -1.077137 1.555002 0.004414 -1.218478 1.075699 -2.159670 1.962554 -2.075608 1.072706 -20.168667 25.221082 -9.271145 29.868736 -46.159069 1.442888 1.615771 0.271369 1.654153 1.856750 0.404236 0.502264 1.058587 2.420561 1.619623 1.997089 1.067917 1.737322 2.426434 1.319975
+1 -0.003264 1 1 1.850754 -0.850007 1.898522 0.877211 -1.781660 -1.843799 -0.057419 1.002057 -0.500716 0.789283 0.107784 1.974814 42.523094 -64.360393 -55.125096 62.507022 -44.474536 0.872048 1.511744 2.388720 1.969963 1.919086 1.836202 1.538154 0.751855 1.930504 2.474287 2.344094 1.187725 1.589210 1.600285 0.994665
+1 -0.076848 1 1 0.336951 -1.150991 -0.348629 -1.902677 -0.012002 0.909068 1.144246 0.088288 -0.541657 0.707652 -0.556732 1.813161 -38.733175 11.531562 10.964143 74.357499 -73.518293 0.295714 1.309051 2.217883 1.705265 1.390130 1.419876 1.859133 2.195742 0.830096 0.676161 0.985012 1.092688 1.804956 0.644732 1.517705
+1 -0.016187 1 1 -0.506873 0.982787 0.771883 -0.172235 -1.350611 -0.148028 0.230859 1.758615 0.937334 0.258882 1.493741 -2.303896 3.912829 62.911791 8.464286 59.247809 -72.075883 1.684541 1.830701 1.339449 2.364774 2.263866 0.552346 1.281783 0.681755 0.503782 1.821408 0.405391 1.901601 0.464240 0.977864 2.466711
+1 0.018463 1 1 -0.115791 0.124037 1.821249 -1.940696 1.878953 1.845438 -0.665816 1.553654 0.916509 -1.027727 -2.103025 2.087282 61.367820 8.947007 72.338454 42.397245 70.491312 2.087223 1.714223 1.191879 1.661510 1.743799 1.033584 0.690627 1.121022 1.021662 0.568243 0.704125 0.735483 1.260285 1.613327 1.930366
+1 -0.011262 1 1 -0.523820 -1.108097 -0.431973 1.625287 -1.524054 1.764189 0.374002 -0.483199 -1.674015 -2.209834 -2.346203 0.640751 40.956874 12.189362 -33.399028 -37.466878 -5.812409 0.787629 2.435820 1.577321 2.031186 0.391701 1.318032 2.411633 2.312978 2.467471 0.281538 1.565476 0.954109 1.452200 0.618506 1.723084
+1 0.004974 1 1 1.596746 -0.543420 -0.657715 1.051045 -1.830624 -0.109529 1.691080 1.571157 -1.793301 0.431276 0.804888 -1.517684 14.252858 -2.218748 59.500187 -30.360229 35.632541 0.266646 1.023579 1.296417 1.385769 2.369328 2.303932 1.189197 1.587909 2.241823 1.317715 1.591467 1.278812 2.487378 1.867435 2.233048
+1 -0.058254 1 1 1.324205 -0.698541 -1.817091 1.141689 -0.486444 0.322275 1.940216 -0.519326 -0.973877 -1.819794 -1.881161 -1.256954 0.639756 -47.616393 -38.712677 56.033467 54.476408 1.149856 1.882806 1.818711 2.319447 0.937198 0.730169 1.946957 2.250318 2.351090 1.772852 1.065622 1.405437 2.178975 0.283892 0.615505
+1 0.020121 1 1 -1.429049 1.012586 2.092924 -2.212785 -0.105546 -2.055411 1.227194 -0.670534 -2.346475 0.779650 -1.571339 -1.262576 -7.435443 -17.488343 73.414743 -18.416482 74.179632 0.431174 0.991805 0.521924 0.719417 1.242363 1.899630 1.079273 1.334820 1.066716 1.788909 0.946842 0.831473 1.310807 2.476772 1.352227
+1 0.010715 1 1 -0.741025 0.434364 0.864124 -0.251880 -1.623238 -1.738922 0.173747 -1.521009 1.105133 -2.271298 1.360590 -1.788000 -0.518243 -10.103897 -16.201156 -42.834390 -67.593675 2.171497 0.599917 2.047086 2.133248 1.244652 2.108197 0.968688 1.236743 1.931434 2.358837 1.476561 0.555346 2.200150 0.674050 1.506172
+1 0.007852 1 1 1.156803 -0.926807 2.320743 0.290284 1.477849 -0.793453 0.499369 0.121854 -1.896154 1.228270 -1.447455 -2.027397 26.199929 -57.787858 9.468052 -20.455624 2.334117 0.317600 2.403444 1.938063 1.269358 1.096555 1.547157 1.321529 0.442794 0.542069 1.797543 2.052782 1.114174 0.666439 1.845955 1.218292
+1 -0.033265 1 1 0.226990 -2.013888 1.675556 -0.159764 0.911168 -1.269142 -2.193779 -1.103376 -1.194185 -0.609230 0.699157 -1.959162 -69.448288 -67.382152 8.178338 53.326847 14.319066 2.283216 1.762489 2.408178 0.491420 1.039440 2.363720 0.299056 1.228484 0.386115 1.927774 1.599163 2.379736 1.725093 1.639426 1.833798
+1 -0.051108 1 1 1.460193 -0.666670 1.339690 0.371474 -0.549786 0.733908 -2.249007 -0.982177 0.054384 -0.166046 -1.008862 -0.774808 -59.302678 49.897532 -22.174751 58.967564 17.853091 2.228489 2.221794 2.187710 0.838428 1.202055 1.694425 1.445118 0.854734 0.759980 1.240512 2.285950 0.457505 0.287868 2.198480 1.849564
+1 0.014827 1 1 -1.141636 1.362882 -0.963172 -0.974758 2.223962 -0.531120 -1.261618 1.731589 -0.905412 -0.963574 1.693735 -0.935626 5.566407 -45.403656 -49.245226 35.490553 -60.271546 0.866971 1.677121 0.871261 1.790641 0.807250 1.449067 1.969265 1.443315 2.042032 0.425834 1.236852 1.527490 1.531922 1.765341 0.843189
+1 -0.020964 1 1 -0.297264 -0.989612 2.329587 -1.865899 0.788531 1.594435 -1.685351 0.480292 -0.050990 0.671019 1.065995 -0.331303 58.489920 -59.908607 66.045845 32.524234 34.804977 0.883619 2.483982 1.032123 0.888043 0.336264 1.095676 0.282402 0.338455 1.906063 1.201515 1.609859 2.148887 0.837423 2.312911 1.344136
+1 0.019003 1 1 1.159715 0.881918 1.931151 -2.085938 1.808341 -2.119282 2.174535 -1.887352 -1.632928 0.330830 -0.352678 0.731045 46.845043 -25.369425 66.073996 55.650561 68.980927 1.561647 1.848396 1.750446 2.490751 2.303174 1.949163 1.088316 0.329970 1.059541 0.451937 1.211215 0.388065 0.960484 0.607901 1.239785
+1 0.001241 1 1 1.167320 1.475200 1.814605 -0.513293 1.471602 -2.120623 -1.504126 2.128094 -0.163575 -1.886979 -0.074643 -1.024316 -41.990149 21.571921 9.276193 54.978890 30.204776 2.150101 0.995369 1.920820 1.715028 1.229933 2.227440 0.330132 1.531785 1.707903 0.721533 0.798790 1.005481 0.876942 0.506881 2.153927
+1 -0.025102 1 1 -1.211161 1.536807 0.507689 -1.404833 -1.966457 -2.255604 1.239678 1.793500 -1.803030 1.840234 1.397420 -0.116488 -69.241618 -43.879425 68.504043 -52.554158 72.261891 0.709019 1.981606 1.849254 0.403364 1.587267 0.439044 0.518168 0.598313 2.093805 2.072550 0.353011 1.302303 1.299969 0.326452 0.433624
+1 -0.014842 1 1 0.422255 -0.019644 -0.281906 -2.044452 1.626519 0.341541 0.587180 0.989225 0.601350 -1.185774 -0.612809 1.795523 -24.967808 66.058038 -62.553635 11.057713 -3.024776 1.563908 1.596110 0.570091 0.262178 2.419537 2.403508 0.761087 1.843379 0.669748 1.200182 1.707656 1.068337 2.035369 0.945968 1.887384
+1 0.064599 1 1 1.982291 -0.221045 -1.743232 -1.579920 0.590291 1.450205 1.118479 0.554482 -1.924418 2.142917 -0.774727 -0.497828 70.043087 14.157003 36.757576 -65.422816 -61.270659 0.985550 1.141965 1.997301 2.387646 1.911330 1.975769 0.504222 2.460565 1.216537 2.088077 0.315193 2.456326 1.967054 0.272553 1.301042
+1 0.005086 1 1 -1.690267 -2.029495 -1.442602 -0.576608 2.327575 2.018226 0.544359 2.292995 0.451922 -0.919128 -0.565435 1.626368 -70.011596 65.111392 -72.835270 7.623174 22.687154 1.419861 1.602371 2.302642 1.997390 1.626620 0.357062 1.893922 1.900471 1.710250 1.920695 1.873357 0.506442 1.526833 1.725199 1.176298
+1 -0.032250 1 1 -0.050291 -1.729651 0.480280 -0.261248 1.156724 -2.260678 0.778926 0.395427 1.481048 1.126019 0.042776 -2.058261 14.611301 22.130555 -51.769053 67.520462 66.410642 1.579918 0.685598 2.087518 2.159504 1.533109 1.457768 1.951921 2.432148 0.612269 0.402609 2.405484 2.475208 2.076728 0.823070 1.840823
+1 -0.008561 1 1 0.992419 -2.268464 1.862292 -0.140305 -1.907190 -0.467714 -0.600754 1.768627 -0.429511 0.580358 -0.566667 -0.238047 -1.164846 72.433758 -5.836892 -0.635280 -27.143632 0.579545 1.661084 1.335465 0.666423 1.571919 1.238409 0.697333 1.331182 0.675217 0.874252 0.307762 1.298905 0.439704 0.356094 1.378518
+1 -0.040703 1 1 0.706928 1.399118 0.149828 1.748870 2.083368 2.110132 -0.452471 1.120030 -1.645980 -2.264782 -2.227075 0.059444 1.804049 20.656232 69.289239 -55.761227 21.054635 1.603683 1.843325 2.018661 1.379828 1.527786 2.000060 1.512681 2.384790 1.167257 1.845845 1.617534 0.645476 0.517548 1.431742 1.039489
+1 0.002654 1 1 -1.616564 2.048713 -0.698247 -1.584342 1.673177 2.265691 -1.353975 -0.122579 -0.879637 -1.302234 -2.306600 1.791110 14.328823 74.523479 16.108461 -15.092458 -8.936339 0.729361 1.871483 0.519339 2.276810 2.103707 2.004992 1.156317 2.469776 0.774725 1.556748 0.515882 0.431603 1.451365 2.336792 2.213861
+1 -0.004131 1 1 -0.462299 0.874326 1.571988 -1.960538 -1.731325 0.625665 2.206143 1.569425 2.076286 0.902991 -2.029261 -2.230680 23.398092 -48.264751 14.335218 32.012008 -24.178512 1.101150 2.286595 2.306667 2.146117 1.536576 1.224578 2.234690 0.691544 0.782180 0.855273 0.815350 0.335025 0.517606 2.410257 1.696065
+1 -0.004204 1 1 -0.882255 1.820645 2.033940 0.759653 1.626167 -0.872461 1.495838 -0.043841 -1.706301 1.795378 1.499985 -1.028986 9.329157 45.139955 -32.770945 18.732936 -5.548916 1.965607 0.713118 1.132286 1.333027 2.431850 2.355038 0.624018 2.115299 1.071968 2.309096 2.479989 1.427577 0.780688 0.529110 2.251218
+1 0.022949 1 1 -0.048450 0.941927 2.047912 -0.040088 0.104654 1.204182 -1.025039 0.656679 0.397366 1.080404 1.508552 1.582879 64.295150 8.588543 47.648704 -18.227299 -46.220895 1.606341 1.520328 0.408992 1.673797 1.260836 1.878899 1.399677 2.123193 1.008240 2.242908 1.560929 1.037748 0.934512 0.599003 2.451664
+1 -0.036732 1 1 1.358375 -1.323251 -2.119443 -0.522897 0.269570 2.053762 -0.668190 -0.649450 -1.417469 -2.280254 1.622680 1.793850 -19.906871 -74.785902 73.337621 35.392372 -60.409067 2.197069 0.632683 1.510859 1.003623 1.146089 1.567119 1.561894 1.505044 2.272031 0.522211 1.057440 1.141091 0.813849 2.101999 0.291587
+1 0.020947 1 1 -0.757286 0.458476 0.853188 -0.263550 0.162391 0.829333 -0.641198 0.624888 -1.422076 0.397958 1.593515 1.701078 -1.438378 -24.820156 -2.357580 -23.842979 71.058781 1.149107 0.549337 2.449685 0.603163 0.360250 1.466032 1.353142 0.766791 0.963084 1.552479 0.770414 1.106062 1.583327 1.729193 0.797678
+1 -0.046206 1 1 -1.145137 -0.919270 1.753421 -1.535233 -2.339933 2.352256 2.137025 -0.854886 0.012723 1.784479 2.090470 -1.046002 56.293586 -73.694940 -40.862124 -69.715355 -55.966536 1.681344 2.091971 0.513036 2.098726 1.539494 0.775123 1.486214 0.796169 1.955265 2.387681 2.498549 0.604667 0.888250 1.573951 1.641935
+1 -0.002061 1 1 0.871933 -0.956922 0.395157 1.646464 0.980761 -0.282203 -2.329056 1.367736 0.505983 -1.799053 -1.993703 1.637342 -49.001998 73.420399 -73.350749 43.961539 -38.413827 1.057130 0.427690 0.935304 0.400810 1.417921 0.502481 2.450866 2.449865 1.380295 0.368059 2.215084 1.917731 1.558673 1.365667 2.013168
+1 0.065688 1 1 1.443512 1.724286 -1.112521 0.613737 -0.339963 -2.347948 -0.417694 1.280354 2.146580 -0.477289 -1.314041 1.884554 55.196334 -65.206357 -23.235737 -73.025040 -31.849264 2.266344 1.699629 1.158182 2.310211 0.973713 2.445601 1.719053 1.369309 2.482623 0.688189 0.650308 0.725319 1.441975 2.026812 1.123854
+1 0.020519 1 1 -0.976174 1.976597 -1.683322 1.590954 1.064238 -1.582856 -1.617632 -1.765269 0.327941 -1.797756 0.944352 0.400681 7.655799 -28.979415 -7.035050 -38.076695 -55.019366 1.967656 1.389624 1.917281 0.745712 2.179090 2.221499 1.734751 1.958628 0.406976 1.550524 1.651894 2.134130 0.327625 2.140402 2.239210
+1 0.018194 1 1 -0.581711 1.397736 0.482894 1.264459 -1.112126 -2.158539 2.125322 0.370190 1.436613 -1.128855 -0.586080 -1.354814 -2.842325 -70.948981 60.473937 -14.546337 19.718394 2.230827 1.005605 0.697658 2.287944 2.471284 1.372934 0.407280 2.151119 2.360529 0.668007 1.197614 1.304793 0.405904 1.533167 2.438872
+1 0.035597 1 1 1.554028 -2.226014 -0.955653 -1.843950 2.110004 2.109135 1.642205 0.071335 1.977577 0.661694 -0.142571 -2.303683 -32.397810 -9.985637 21.396886 67.456688 44.560023 0.929625 1.699679 2.004944 0.343893 1.058140 1.658649 0.921154 1.080035 0.654307 0.437934 2.105993 2.171156 1.623996 1.252063 0.673029
+1 -0.011628 1 1 1.580450 -1.118512 -1.113707 -0.467033 1.422003 -1.637783 -1.149721 2.143684 -2.035261 0.609065 1.247607 -1.601789 19.663174 28.968250 -30.618198 49.953497 18.428830 1.125160 0.810029 0.902341 2.137560 1.722016 1.670187 1.340740 1.564066 2.008165 0.484696 0.539765 1.331422 2.452066 2.374506 1.563855
+1 0.009323 1 1 -1.654447 1.514191 2.100305 -0.685635 -1.680439 -1.785598 -2.046852 -0.997064 -0.401171 0.954403 -0.328051 -0.065651 -22.071553 -6.589656 -52.343114 19.278878 20.101665 2.105373 0.760696 2.017808 0.553599 2.087172 0.851841 1.641657 1.077761 0.679750 0.561269 0.492105 1.310045 0.927659 2.406756 1.344941
+1 -0.030298 1 1 -1.171485 -0.787979 -1.751154 1.928260 1.172115 1.946322 -1.573630 -2.071398 1.136748 1.304493 -2.128642 0.378714 -44.289189 -68.397242 47.546035 56.216763 -14.866253 2.018297 2.023969 0.599299 0.673870 0.732509 0.783014 1.373656 1.282836 0.375699 2.365017 1.834386 0.283457 2.315574 1.105981 2.475454
+1 -0.010543 1 1 -0.526420 2.321151 -2.291022 -0.285448 -0.316723 1.837118 0.864080 -0.997132 -1.548240 0.538361 0.441336 0.234043 -41.064252 -16.881632 70.408860 11.715272 -51.420484 0.263862 1.477064 2.269799 1.264161 1.498163 1.383351 2.236977 0.879438 1.964528 0.575737 0.655745 2.100296 0.916634 1.615777 0.364259
+1 0.002150 1 1 1.992947 -0.193437 0.460271 -1.967912 1.563340 -1.227152 1.375512 -0.740986 1.085201 2.029721 0.535658 2.141386 56.164184 1.444698 -18.963883 24.026254 9.253415 0.957087 2.008906 1.683842 1.325733 1.343560 1.716800 1.754546 1.661154 0.262174 2.353061 1.154420 2.088382 0.933821 2.478025 2.165593
+1 -0.048180 1 1 0.812797 -0.543612 0.828223 -0.458428 -0.041809 -0.531246 1.331853 0.598060 0.072050 -0.143757 1.335165 -0.285939 27.416101 -17.590391 8.294095 48.847980 37.999751 0.802116 0.660053 0.260463 0.595175 1.110533 2.471549 1.330507 0.589703 1.396119 0.827030 0.893405 0.458601 0.704076 2.156030 1.655307
+1 0.006038 1 1 -0.575481 -2.289686 -1.380768 1.944233 1.023314 -1.374713 0.038239 1.800656 0.669014 0.361134 0.015644 -0.972732 -45.375892 -32.622612 -38.235443 -23.092432 -64.500598 1.201830 2.397712 2.346410 1.862041 1.575282 1.513833 1.493397 2.267376 1.044150 0.534673 1.251271 0.864002 1.283917 0.544742 1.727680
+1 -0.010719 1 1 -0.477962 1.513858 1.215538 1.343793 -1.352985 -2.350948 0.996167 -0.539937 1.332562 -1.618685 -0.612863 0.886409 64.060533 -34.620778 -21.416422 54.197381 -54.616224 2.351881 1.561751 1.343182 2.107436 1.685564 1.022972 2.345578 1.387699 1.053814 0.953209 2.084941 1.607684 1.594839 1.708370 1.821526
+1 -0.008742 1 1 0.311972 -1.582497 -0.300474 1.619971 -1.334073 -0.223264 -1.330116 0.308767 1.103687 1.709516 0.398671 -0.548362 35.602021 13.173422 5.705941 49.747153 0.396735 2.393983 0.420047 0.729831 0.776241 2.289968 0.491913 0.325352 2.189054 0.937855 0.534866 2.250598 0.295386 0.295869 1.665901 1.297815
+1 -0.007974 1 1 1.814674 0.643329 2.209439 0.417043 1.920779 -2.050229 -1.204813 -0.161259 -0.657161 0.929363 -1.771975 0.718474 71.802857 40.611805 62.598514 -6.776114 -36.144240 1.731446 0.416368 1.900935 0.516114 2.079833 1.259608 1.475020 1.664083 2.238459 1.035618 1.126554 1.750179 0.254545 2.389753 1.322092
+1 -0.028695 1 1 0.837864 1.356454 -0.618635 -1.868396 1.231268 1.819835 -2.150997 1.647915 1.792110 -1.599970 -1.804792 0.516837 49.158811 12.135276 -42.417339 41.785202 -16.115516 2.072827 0.500730 2.261058 0.604074 2.177233 0.255438 1.651408 0.710654 2.457040 0.466562 1.765286 2.154013 1.489542 0.478492 2.021783
+1 -0.021067 1 1 -2.295009 -1.304970 -1.178868 -2.349354 -0.492310 0.707774 1.489974 0.350214 0.278663 -0.631704 -0.042720 -1.716431 37.628230 17.666967 -71.290324 23.531218 -60.813783 1.416158 2.369112 0.912499 1.865975 2.432612 1.655067 1.459410 0.308650 0.477391 1.509076 0.283969 1.909157 1.444843 0.720680 2.216203
+1 -0.047815 1 1 -1.898194 -0.064436 0.874900 1.791601 -0.720533 0.848045 -1.880628 -1.727050 1.787061 -1.626781 -0.028526 1.219567 -51.957523 49.912944 -63.157929 54.681278 -21.766736 1.622130 1.394230 0.565538 2.494299 1.192315 2.238471 1.224143 1.674564 0.648982 0.948248 1.953351 1.720452 2.384546 1.558367 0.717843
+1 0.010309 1 1 1.184812 -1.413040 1.483753 -0.520222 -1.894626 -1.376038 1.328106 -1.111399 0.625514 -0.324366 0.616307 0.436508 -25.482142 -28.362468 11.997534 42.560243 -39.987524 0.320368 1.666924 0.499226 1.741193 2.229687 2.090172 1.778995 0.818004 2.186026 1.794477 2.270942 2.477684 0.933650 1.859095 1.562633
+1 0.014118 1 1 0.607275 -0.556495 1.073214 -1.522386 1.536855 1.313832 -0.683964 -1.866872 -1.432898 2.305975 1.840128 -0.383559 2.323651 53.607062 73.889987 19.019848 16.579674 0.693765 2.110369 1.478871 1.129377 1.943889 2.449900 1.976776 1.671929 1.358011 1.593548 0.264097 0.925833 0.983309 1.723757 1.681612
+1 0.005727 1 1 0.028405 1.453013 1.198817 -1.658351 1.882865 1.626205 -0.233574 -0.251968 1.610190 -0.781564 -2.319227 1.641285 -39.670652 5.352703 -37.114299 69.984513 -70.293811 0.953846 1.544161 0.471627 1.393070 1.325037 0.903606 0.905317 0.419983 1.908480 1.318423 2.227413 2.125354 1.318223 1.116038 0.500342
+1 0.013569 1 1 -0.425656 -0.595197 0.926586 -1.317983 1.609362 -0.562362 1.430241 0.161271 0.863989 2.199267 -0.892189 -0.200395 41.997254 -52.144265 61.332646 17.775943 -39.719171 0.473515 1.612845 0.594848 2.354623 0.401057 1.069303 0.282019 0.648846 0.897254 2.153064 1.288799 1.587847 1.193539 0.317527 1.175598
+1 -0.039200 1 1 -1.082270 0.112886 -1.813083 -2.185062 -0.681652 -0.702998 -1.322197 1.453154 -1.147699 -1.575546 -1.294164 1.377922 65.392033 -6.093829 31.016781 49.030401 -46.052571 1.291465 1.398170 1.547207 2.159258 1.898984 1.469052 0.363676 0.558300 2.341259 0.786875 1.016100 1.596101 0.416449 1.010974 0.942555
+1 -0.052156 1 1 -1.879315 1.492996 -0.684585 1.841595 0.707753 1.127213 1.265906 -0.352558 -1.963885 -1.449591 -0.220515 -2.261901 -29.336301 -5.207495 -72.367453 70.221088 5.828524 1.525037 0.797121 2.206529 2.137633 0.698048 2.090851 1.936883 1.691832 0.626975 2.317071 1.517073 1.954778 0.951226 0.255426 1.448302
+1 -0.011401 1 1 0.388673 1.057288 -0.582896 0.327588 1.692959 0.157210 -1.414204 0.763937 -1.772618 -0.669452 1.703508 -1.611686 -25.455564 -31.660703 -71.437512 -50.267492 -45.732795 0.908760 2.026901 0.379786 1.321378 2.399303 2.076300 0.373883 1.096409 1.339687 1.870475 1.566132 0.723957 1.050955 2.391974 0.413488
+1 0.006528 1 1 -0.120816 0.481341 -1.274797 1.728156 -2.046396 1.952074 0.849947 1.815907 -2.201436 2.137854 -1.049230 -0.643206 -4.389903 18.897770 64.820274 -15.647714 -41.120957 0.326045 0.343279 1.996450 1.592232 0.650757 1.523506 2.068092 1.924533 1.130826 1.541677 1.469587 0.350493 1.730442 1.536997 1.558460
+1 0.008369 1 1 1.738293 -1.312764 -0.216250 -1.257985 1.530101 0.902243 -0.472721 0.066127 -0.723320 1.123829 0.939548 -0.232938 32.182487 -8.940813 31.751474 -52.968719 4.733350 2.176120 1.800490 2.087355 1.668858 1.498919 0.580436 0.890074 0.718184 0.765441 0.771859 0.630067 0.280516 2.383735 1.432073 2.096236
+1 -0.031187 1 1 -0.574168 0.925603 1.009006 -1.529148 0.977963 -0.180461 1.778440 -0.443965 -2.013490 -1.059138 -2.232481 -1.262986 73.299039 -13.045409 45.806796 74.825017 -15.935516 2.451615 1.535870 0.617564 1.650467 0.644675 0.548453 1.095263 2.341649 0.603342 1.120917 1.501220 0.997498 1.696165 1.445890 0.319674
+1 -0.010442 1 1 2.044674 2.091259 -1.912021 -1.555557 0.078360 2.232527 2.037669 2.179855 -1.994462 -1.693433 1.305277 1.620805 -45.949766 72.282004 -6.353586 15.277436 -32.140999 0.718562 0.365701 0.829509 2.060357 2.422345 2.357609 1.078405 0.256759 1.351808 0.839336 0.725861 1.539854 2.318821 1.675818 1.477087
+1 0.040276 1 1 2.133887 -1.756518 1.316967 0.174333 -1.083061 0.948884 1.172830 -0.161846 -1.093413 1.324709 -1.644843 -2.010108 -24.212605 8.745133 -20.540538 -74.827014 -17.620824 0.577079 0.713438 2.007851 1.957426 0.464216 0.574100 2.399336 0.389306 1.557748 1.576471 1.254227 1.047232 0.583118 0.972514 0.292092
+1 0.013227 1 1 -2.166826 -0.511003 2.263680 -2.162803 1.143166 0.780273 -0.538059 -0.085331 -1.590865 0.427742 -2.047185 -1.880355 -58.944224 74.434668 23.462925 -8.624012 -43.765641 1.837967 1.959119 1.914872 0.753461 1.912542 2.087703 0.768590 1.938866 1.277951 1.521366 2.096156 1.095971 0.740996 1.675462 2.236974
+1 -0.033498 1 1 -1.296974 1.268817 1.442226 -1.040059 -2.029506 -1.632428 -0.694397 1.853540 -1.149579 -0.176500 -2.338963 -0.201402 -46.761396 -68.788474 72.118594 -52.790522 -0.298663 0.330539 1.618379 1.339477 0.594347 0.689142 0.901872 1.006592 1.543378 0.806363 2.300833 0.859214 1.807814 1.423478 1.642916 1.984034
+1 -0.005189 1 1 -2.160052 0.245275 -1.000400 0.085695 -1.714635 -1.606741 2.212394 -1.748708 0.626714 0.998859 2.291648 1.372795 22.714103 5.929718 60.763294 48.676562 6.970004 1.297761 1.459892 1.657586 1.049197 2.108925 1.959374 1.697954 2.268013 0.497982 1.084850 0.565238 1.950054 0.305754 1.312913 1.885104
+1 -0.012598 1 1 -2.173379 -2.245811 0.896468 1.424637 0.221659 -2.073443 -0.239677 0.842868 0.634398 -1.804854 -0.526266 0.209529 44.336130 -42.669518 3.418842 10.484446 -37.910270 2.006458 1.045504 0.785929 0.851403 1.035623 1.217419 1.153899 2.332336 1.567784 1.499718 0.516461 1.163629 1.605734 0.321198 2.119044
+1 0.072114 1 1 2.256508 -0.180588 -0.360578 -0.107674 -0.116643 -0.071191 0.433622 -2.181377 -0.023519 0.552206 2.226288 0.849430 -68.959055 55.162224 -38.496905 -67.485680 68.178053 1.653095 2.074003 2.266605 1.574596 1.242136 0.329937 0.502734 2.196000 0.670567 1.474429 0.735379 1.756590 2.250564 1.978893 1.261918
+1 -0.010400 1 1 -0.558055 -1.581958 -0.676708 2.273259 -1.391687 2.211235 2.335476 -1.851535 1.864103 2.010921 0.288825 0.528677 -66.817716 44.644174 34.632232 63.915757 -67.875765 0.805334 0.747729 2.330697 1.030119 0.959687 0.708820 0.890359 1.006548 0.806903 2.370308 0.767706 0.579162 1.978430 2.480866 0.412202
+1 0.014524 1 1 -2.016067 -1.963217 0.363499 2.064106 -1.173763 -1.365779 -0.603688 -0.403669 1.376081 -0.611953 2.057506 0.996238 20.564141 21.514757 -51.472462 -47.664210 57.623291 2.494656 0.436566 1.622329 2.490636 0.374530 0.723569 1.274373 2.136611 1.511993 2.058610 2.303486 0.434752 0.376490 2.172247 1.956331
+1 0.027703 1 1 1.642685 -1.288366 -0.133699 0.738281 0.574649 -2.272063 -2.073820 -1.870544 -1.884645 1.453504 0.022894 -1.635865 -60.430616 -7.365357 -39.556767 -30.590516 65.196714 1.542515 2.051276 0.544263 0.423665 0.790662 1.653580 1.226384 1.077082 0.514290 0.674630 2.253007 0.293448 1.479225 0.336649 0.811699
+1 0.020039 1 1 -2.236732 -2.022492 -1.558343 0.392647 1.873965 -1.878246 0.606207 0.336305 2.128883 -1.038409 2.151908 -0.459852 -13.286554 42.880778 -52.761420 38.818110 65.977060 0.271617 1.319148 0.913387 1.038773 2.406896 1.446773 1.666066 1.814734 0.738356 2.293045 0.461873 1.702771 2.218072 0.383274 1.433419
+1 0.020540 1 1 1.510637 -1.069128 -0.495388 0.808749 2.109840 -0.644098 -0.991834 -2.042231 1.272376 0.002868 1.077100 -2.184411 26.275642 14.721086 67.286719 37.893372 -26.091119 0.423334 1.975990 1.964490 2.191519 1.859545 2.367406 1.494543 1.289926 0.287635 0.535757 1.466222 2.294446 1.509898 0.606078 2.106223
+1 0.024412 1 1 -2.013399 0.470239 0.637358 0.817537 -0.978618 -1.390948 0.494411 1.625673 0.263151 -2.158969 -0.393453 -1.284073 42.081987 21.957538 40.338752 -26.586804 5.585884 1.104325 1.634785 0.331682 0.578785 2.390040 1.650271 1.857382 2.027259 1.891894 1.558701 1.829338 0.936542 0.956921 1.477917 0.855238
+1 0.031052 1 1 1.024860 1.032287 -1.362447 -1.142150 2.164685 2.221957 -1.247893 1.504171 -1.363848 -1.127403 0.254073 0.772235 33.009034 -67.170988 -42.791342 55.923249 2.039372 0.260855 0.442511 0.283270 1.422960 1.942339 1.142070 1.529224 1.424326 2.392298 1.355106 2.264371 2.276027 2.428846 1.364543 1.129467
+1 0.003791 1 1 -0.280884 0.994367 2.196742 -0.918429 1.747317 -0.452900 -1.389819 0.621146 1.656754 -0.439826 1.581388 0.520272 -63.195991 14.982421 -40.456631 -4.601442 63.571527 1.324753 0.623958 1.114067 1.126961 1.842425 0.389287 1.248511 1.722502 0.837835 2.498557 0.750842 0.652404 2.203455 2.215112 2.386932
+1 0.027202 1 1 -0.827398 0.181987 0.313672 -1.284868 2.094902 -1.944705 0.480443 -2.232022 1.743686 -0.220986 -0.753275 1.894568 12.498315 59.187620 -33.669720 63.021627 54.482134 0.343311 0.271878 1.197408 2.341865 1.979438 1.412959 0.358987 0.494658 1.463877 1.123441 1.175408 1.584165 2.314844 2.332454 1.298799
+1 -0.023142 1 1 -2.013544 -1.970022 -0.914386 -0.981410 -1.188926 -1.753947 2.127147 -1.927828 1.380664 1.017235 0.124190 -0.334335 -63.469150 73.993907 -34.401022 72.031543 -15.862948 0.496494 0.828860 2.401799 1.290938 1.541821 1.642878 1.343142 1.439761 0.815320 2.077330 1.944174 0.481908 0.926669 1.529955 2.457081
+1 -0.007100 1 1 -1.564960 2.270182 -1.272678 -0.363999 -1.057430 -1.802966 -1.793389 -1.051594 2.030826 0.257994 0.702923 0.060760 -44.300517 41.207151 18.581872 5.521329 -53.018114 2.493351 0.994108 0.966068 2.212024 2.242287 2.362644 2.459430 2.395526 1.607059 2.345663 0.555585 1.708932 2.269319 2.197379 1.349360
+1 0.014817 1 1 -0.219655 -1.949059 -2.012686 -1.688308 -2.089765 -1.237977 -1.479791 1.137595 1.399406 0.282593 -0.542097 -1.978746 -46.265238 20.139491 -65.570509 6.461717 2.077118 0.776779 2.325474 0.993519 2.330701 1.087772 2.432803 0.375426 2.286555 1.636403 0.519749 2.424473 2.124643 0.616136 2.393648 1.548920
+1 0.002209 1 1 1.793340 0.220557 -1.752702 -0.515879 0.411922 0.673616 2.299605 -1.560043 0.082258 1.777883 -0.384390 0.238650 24.026057 5.940512 -57.806597 -5.472482 -26.011403 0.270159 1.562207 2.257009 2.303027 1.718625 0.929631 1.806620 1.620166 2.123917 1.918205 0.523373 0.334215 0.409432 2.331514 1.263847
+1 0.020977 1 1 0.106282 0.278692 -0.133886 2.299640 -0.959438 0.519944 1.931846 0.168837 0.778036 -0.421650 0.759536 -0.346187 45.822875 45.060156 -23.956279 -33.176688 -50.600173 2.318372 0.869760 1.306840 1.058990 2.441331 1.952630 0.851341 2.231335 0.544862 1.499848 0.437727 0.876424 0.812468 1.397972 0.467335
+1 0.038161 1 1 1.221120 0.917362 -0.830875 -1.716014 -1.222189 -0.030905 -1.056340 -2.343296 -2.346523 -0.027304 -1.791900 0.412915 -47.168416 -9.561530 -50.634786 -68.846898 -9.821130 0.419115 0.810538 0.464649 1.101420 2.318374 0.914629 1.662979 1.694302 1.632537 0.807202 0.644356 1.938120 2.226284 1.156142 1.782099
+1 -0.013837 1 1 0.886102 1.566895 1.980600 -0.380370 1.830601 -0.277389 -1.516418 -1.832389 -1.498463 -1.661623 -1.280009 -1.050892 -9.714558 -72.570297 -38.975884 -17.684013 -65.206445 1.004100 2.410395 1.755053 1.173592 0.317248 0.982307 0.630221 0.617785 0.856121 1.584103 1.262123 1.000339 2.204713 0.860502 0.958697
+1 -0.003312 1 1 0.259322 -0.538224 1.848525 -0.619562 1.399608 -1.027607 -0.080846 -1.602877 1.173077 -0.723917 0.517815 -0.872571 -11.062632 70.345446 -4.095346 19.514603 -68.063037 0.843080 0.650920 2.015473 1.799284 2.060263 0.839883 0.910113 2.265777 1.170022 1.064280 1.362958 1.480879 1.139846 2.382922 1.277357
+1 -0.008381 1 1 -1.207558 0.830936 -1.976655 0.695836 -1.234120 2.081273 -0.100797 -2.353883 -1.213969 1.464656 -1.042844 -1.704302 -73.097392 -47.874518 -27.024902 -7.536274 -62.162211 1.220914 1.406322 1.304669 0.565113 2.107678 1.243863 2.357827 0.251659 1.129744 1.359444 0.932866 2.182561 2.055982 0.891890 1.998344
+1 -0.006679 1 1 1.200406 1.481437 -1.759444 -0.740998 0.882614 -0.501163 -2.009196 0.420541 -0.546671 1.257364 2.155905 0.736477 -47.020174 -68.072486 -44.276345 -2.530326 72.818600 1.558203 2.471087 0.307432 0.258129 1.868366 2.123180 0.784496 1.524852 2.188176 1.918452 2.418346 0.384305 0.766653 0.894446 2.200248
+1 0.043221 1 1 1.764082 -1.427593 1.922886 0.378777 -0.326266 1.674500 0.936251 0.898127 1.030638 -0.814249 -0.297130 1.264180 -34.711918 -53.207501 41.533982 -38.365816 35.735096 1.371441 2.302062 1.252949 2.070435 0.793714 1.204967 1.134048 1.694455 1.954028 1.849408 0.746056 1.215340 2.225563 0.278596 1.614037
+1 0.042374 1 1 0.505380 2.200662 -1.012710 0.530347 -2.301728 -1.136054 0.939881 0.656992 0.938624 -1.622702 -2.155135 -1.938960 -61.674531 -63.841469 -33.571025 71.780677 -32.163642 1.760092 0.367060 1.180257 2.084621 0.726625 0.880912 1.991068 1.130071 2.355827 0.388986 0.683187 2.071793 1.128244 0.900050 1.885198
+1 -0.010085 1 1 0.372236 -1.877112 0.827947 -0.380271 -1.216284 0.264417 0.277801 -0.977997 -0.387874 -1.765788 1.018806 -1.749508 42.244119 46.902872 46.571721 30.907920 19.403318 1.548463 0.776843 1.149872 2.152422 1.762628 2.483895 1.819580 1.178306 0.786186 0.675586 0.320870 1.114208 1.252214 0.956131 1.693139
+1 0.008975 1 1 0.478569 -0.745752 1.108247 -1.769270 -0.942372 -0.100883 0.922732 -0.111706 -1.905612 -2.219225 0.046104 2.033680 35.089097 -57.539055 -8.898157 -1.328057 29.346117 1.677752 2.472589 0.807522 1.519410 0.729678 0.455402 0.948283 0.294355 0.980755 1.542649 2.043754 2.369393 1.133226 1.374987 1.150965
+1 -0.009399 1 1 0.765503 0.990504 -1.462794 -0.650291 -1.408747 -1.764226 -0.986298 1.471110 -0.962845 -0.191082 2.338307 -1.396672 -46.164633 61.006221 -68.440427 71.748116 20.588836 1.173500 1.019159 1.248776 1.686168 2.172427 0.482301 0.776470 1.637096 0.924168 2.238629 1.633240 1.367886 1.057758 1.990383 0.865893
+1 -0.021540 1 1 -1.765363 -1.256758 -1.400412 1.653642 -0.913456 0.510736 -2.033463 -2.167557 1.352460 -1.766023 1.786230 -1.464450 -6.249170 -29.801307 -20.560748 35.503082 0.297311 2.078474 0.911730 2.442240 1.478055 0.925092 2.015339 1.806524 2.249773 2.178531 1.814383 1.588772 0.990272 1.747357 2.334801 2.495989
+1 -0.010894 1 1 0.971382 2.293733 -1.281794 1.932189 1.232402 2.024646 0.073689 -0.862418 0.642559 -1.307142 0.022577 -2.250331 10.235483 -22.231245 9.470098 13.934226 42.528997 1.897794 1.721615 1.675831 1.697768 1.377776 0.788943 2.016583 2.453605 1.239249 1.309750 0.475193 0.563837 0.902998 1.930248 0.430921
+1 0.000426 1 1 -1.652005 0.146960 0.660355 0.917527 1.945113 1.666425 1.873833 0.613654 -1.729304 1.610378 -2.340784 2.179857 -62.862314 73.081187 -74.487828 -16.925153 -61.039306 0.810718 1.236251 0.427782 2.482266 1.442899 1.804808 0.402220 0.356204 0.977374 0.980897 1.687711 1.112486 1.549216 2.175185 1.835624
+1 0.033505 1 1 1.136547 -2.082833 2.168341 -2.311198 -0.078357 -2.181373 0.049505 -2.064016 -2.021752 1.449134 1.976390 -0.438549 -16.245889 -44.664770 69.210587 -27.670214 -53.282793 1.016542 2.275213 2.260888 2.251521 2.317095 1.916506 1.215987 1.841154 1.517547 0.906606 1.822998 2.369837 1.856502 0.737164 0.272346
+1 -0.017339 1 1 2.261605 0.661033 -1.833585 1.962287 -1.853284 0.752181 -1.434491 -0.905582 0.899471 0.061192 1.156759 -1.671874 24.912146 48.432174 -50.453372 -19.815918 -46.126937 0.543673 1.763380 1.632977 1.435652 1.511808 1.206515 2.393857 0.559023 0.996276 1.402574 1.307921 1.236239 2.471365 0.488873 0.980329
+1 0.023716 1 1 0.618137 -1.795789 1.030057 -1.154462 -2.142994 -0.511273 -2.287828 1.560114 1.103500 -1.441293 -2.128661 0.045938 -24.108551 -42.420567 -12.475016 32.399287 34.823011 0.930260 1.132203 2.193492 1.272370 2.219208 1.471683 1.822940 1.408491 1.760949 1.274117 2.327378 1.496805 1.056887 0.841586 0.279572
+1 -0.015333 1 1 1.495487 -1.232727 1.922507 -1.277095 0.798033 1.077965 -1.782465 -1.230230 1.494042 -1.949587 -1.472996 2.255232 61.732832 -6.290839 19.876780 19.042399 -54.399437 0.754975 0.362374 1.173529 1.500034 1.325093 1.843979 1.762483 2.299669 1.535756 0.949450 1.908966 0.497693 0.718845 0.636033 1.557907
+1 -0.002136 1 1 -1.777753 -2.145277 -1.176813 -0.802945 1.183536 0.701152 -1.423105 1.955315 -1.217781 -1.338395 -2.178743 1.842524 69.963884 33.003118 -16.592096 -13.352350 -12.946458 2.258290 1.330574 1.714816 2.169889 0.581445 2.092383 0.677076 0.612483 1.754774 0.987855 1.630802 0.886447 0.521762 2.495923 1.473236
+1 0.017041 1 1 1.102615 -2.167459 -1.716147 1.246218 -1.374792 -1.293014 1.857201 -0.884707 -1.689519 1.117392 1.144122 -2.002637 72.254376 -20.695205 25.691786 -48.148959 10.450373 1.216162 0.287881 2.421889 1.444380 1.945456 1.777505 0.531885 1.634988 1.493772 1.818664 1.536976 1.203561 2.254562 1.680080 1.097881
+1 -0.003911 1 1 -1.030477 -1.193886 -0.283541 -1.242293 1.383962 -0.095979 -1.477404 -1.153539 -0.762155 -1.266485 0.046532 -0.185788 56.547522 -5.791863 6.150366 19.202668 -60.750579 1.600208 1.939655 1.034590 1.850163 2.193018 2.296717 1.413525 0.855770 2.419075 1.402409 0.787622 2.305370 0.605468 0.851676 1.111302
+1 0.021834 1 1 1.478329 -2.147916 1.584817 1.593099 -0.574246 -0.375555 -2.068965 -0.378227 0.145500 -0.313048 2.343485 0.809247 33.826959 29.706916 -65.867388 -33.196177 71.858056 2.400145 0.477968 2.212785 1.534620 2.113507 2.453849 0.833207 1.213653 0.858022 2.030546 0.879353 0.542698 1.125574 1.014552 0.328191
+1 -0.017844 1 1 0.557937 -0.413298 -0.239091 1.270784 1.522988 -0.833069 -0.883968 1.315561 0.109528 -1.707234 0.249940 2.004741 2.958385 71.572124 62.690838 44.915857 -49.193150 1.535889 0.940554 0.899215 1.348519 1.810072 1.132768 0.427790 0.361131 0.528350 0.724240 1.305967 2.135152 1.749857 1.594025 1.534707
+1 -0.005732 1 1 1.656040 1.700870 1.178121 -0.784034 -1.421342 -1.395026 -2.064040 2.284283 0.113880 0.753808 2.355174 -0.649027 31.487986 18.573369 12.612218 23.547281 59.153694 1.316961 2.419317 0.955108 0.257189 1.825842 0.683344 2.462348 1.925661 2.090916 0.770508 0.433788 2.167577 2.211700 1.286423 2.160538
+1 0.017986 1 1 0.353793 -0.836070 0.522295 -0.960816 0.922715 -0.407269 2.128975 0.509003 1.826646 -0.777923 2.332671 -1.880941 -72.174305 16.462487 -64.984094 -37.663905 -17.248246 2.255883 1.382399 1.986206 0.416366 1.868164 0.984511 1.671448 2.276843 0.395405 0.577230 1.000890 2.459332 0.742679 0.707350 0.935471
+1 0.003020 1 1 2.207287 1.942081 -2.162193 1.973232 -1.686161 1.001254 0.127347 0.900406 1.646536 2.178284 -0.131496 0.049813 -50.996077 8.935768 33.451380 17.341746 12.721732 2.337139 1.302551 0.977765 0.796025 1.799566 2.309095 2.451092 1.757178 0.896937 1.328160 1.641386 1.027633 1.931444 0.277728 0.529144
+1 0.003049 1 1 -0.986116 -0.175001 -0.719185 -0.066263 -1.563701 -0.133193 -0.193269 -1.432094 1.678981 0.855308 -2.334388 1.287270 17.853300 60.416465 69.534909 23.212447 -18.402209 1.586003 1.698300 1.322876 0.581790 1.147052 2.005324 2.223454 0.843269 1.575266 1.249077 2.234446 1.083833 1.483500 2.434991 1.135697
+1 -0.011901 1 1 0.919797 -2.317896 0.450259 -0.590186 0.316574 0.378840 0.731810 0.202369 -1.132071 1.904857 -1.046234 -2.133262 -60.008763 32.719431 15.476139 7.466246 -64.800852 2.006184 0.931859 1.009818 1.763969 0.282854 1.180964 0.463559 0.781077 0.317190 2.268478 1.554304 2.188948 1.404400 0.499664 2.359888
+1 0.048459 1 1 2.218884 -1.070686 1.599116 1.582345 -2.257364 -0.073171 0.148834 -0.819350 -1.209783 1.126586 0.157758 -1.632109 -1.129661 63.789132 53.935644 46.366318 28.701918 1.271947 1.868016 0.744798 0.317591 2.245154 1.053413 0.962815 1.532974 1.446589 0.817246 0.703670 2.083454 1.357911 2.155289 0.438781
+1 0.012775 1 1 -1.373464 2.183465 2.129301 1.282131 -0.979783 -2.129426 1.324322 1.266104 -1.732389 1.591785 0.892059 -1.983323 55.137352 -6.524810 -12.479324 -39.995020 -46.294202 1.125102 2.082412 1.839726 2.271047 1.993424 2.483069 1.437158 2.068160 0.810071 1.612930 2.012381 1.590540 1.464928 0.792485 0.799169
+1 -0.001461 1 1 0.819606 0.806116 0.271642 -0.824178 -2.243302 0.651928 0.652946 -1.089259 0.461972 -1.653318 1.637311 -2.065955 -51.599131 73.412303 -59.430962 -6.176022 -0.392961 1.307573 2.121733 1.220958 2.147411 0.782250 2.027579 0.511982 2.389533 2.126880 2.215174 1.178365 1.785234 2.171549 1.473656 1.241524
+1 0.022635 1 1 0.968365 -1.282398 1.210074 -0.961219 -1.132061 2.070821 -1.423005 -1.077923 -2.235863 -1.551800 1.976907 -1.175515 68.883034 17.152863 -11.837951 -60.443150 -68.017564 1.056984 2.473583 1.762614 2.245535 0.704704 1.462613 2.387768 1.716603 0.699891 1.573377 0.998397 1.054795 1.686300 2.143052 1.771042
+1 0.011480 1 1 1.543505 -0.008055 1.276647 1.094634 0.338594 -1.816581 0.291793 -1.434488 -0.862321 2.284091 1.592921 1.140759 -62.821992 0.780980 -74.067603 -4.206439 -47.613311 1.571322 2.451531 2.383040 1.008266 0.430095 0.860428 1.967750 0.724869 0.626461 0.426032 2.315949 0.657780 0.301120 2.177970 1.393391
+1 0.044846 1 1 -1.606311 0.004065 2.339139 -1.551406 -0.826422 -2.267225 -0.865450 1.528875 -0.849095 -1.632738 -1.183911 -2.288020 -52.833379 29.405747 -27.616709 -54.020051 34.997815 2.249248 2.364849 1.271190 0.393971 1.226906 0.857411 0.759199 1.607350 0.478836 1.045812 1.460254 0.994656 1.188339 0.665638 1.885242
+1 -0.029680 1 1 -1.253117 -1.475656 -0.054858 1.636795 -1.308188 1.299640 1.124845 -0.835075 -1.611474 -1.938709 2.286554 0.581591 41.424818 -73.087865 -37.748177 66.389838 -35.984962 1.386091 1.037350 0.987948 0.941534 1.619274 0.646212 1.640568 0.782529 2.217560 0.774794 0.462378 1.188373 1.230070 2.291869 0.947917
+1 -0.035401 1 1 -1.716057 -1.956340 -1.874442 -1.431181 -1.822700 1.118836 1.850286 0.705052 -1.853998 -1.831756 -0.285242 -1.554710 5.807744 -39.248087 57.409488 -68.726870 57.502637 1.327231 1.778161 0.302755 0.399424 0.623735 1.862910 0.426833 2.289412 2.392344 2.126729 1.936632 1.982656 1.506640 2.101590 2.417785
+1 -0.028225 1 1 -0.306399 0.993569 -1.795123 -1.913611 -0.000622 -1.022824 0.193885 -2.346151 1.507747 2.183577 -0.701314 -1.297598 6.365685 38.070421 -50.432350 33.485957 -1.525684 1.492531 1.217086 2.308200 0.911685 1.685620 1.963733 0.713864 2.419848 0.884272 2.206215 1.354975 2.308731 0.849265 1.103537 1.896389
+1 -0.001523 1 1 0.779723 -0.351540 1.003164 -0.749945 1.309452 1.098184 -1.256549 2.111940 1.659550 -0.570115 -1.631923 -1.619456 17.721018 -62.846077 45.982379 25.838941 25.076861 0.877049 2.318917 1.032247 0.726175 2.321790 2.073777 0.712813 0.499959 0.554429 0.296194 0.388089 1.354863 0.428583 2.447575 1.147973
+1 -0.006971 1 1 0.636265 1.301403 -2.236708 -1.622371 -1.306402 -1.670717 1.380489 -1.917083 -1.805535 2.160194 2.144496 2.197621 -9.018417 -72.531746 8.946530 64.336774 -41.837353 1.969148 1.728800 0.945870 2.483798 2.435275 1.424501 0.843904 0.990375 1.233162 0.252180 0.883695 1.506238 2.097848 0.278120 0.366372
+1 -0.033792 1 1 1.468185 1.710757 -2.311884 -2.193832 -2.007659 -2.018983 0.866243 -2.328951 -1.581672 -0.580935 0.300842 -0.138877 -46.959359 54.051730 47.432042 -59.671388 2.980309 1.225869 1.431323 0.745880 0.497622 1.786872 0.457348 2.141925 0.837295 2.424434 1.458904 0.801494 1.460324 2.163423 2.147007 0.747639
+1 -0.014030 1 1 -1.912718 0.866577 -1.432973 1.042325 -2.303170 -1.821565 1.347842 0.723469 1.385436 1.117372 0.795155 -0.167404 -8.379415 17.172556 19.151727 -16.922114 -9.973421 0.275772 1.407049 2.277481 2.126901 0.330603 0.440769 0.258938 1.963509 1.441506 0.883852 1.896440 1.476064 1.216747 1.112426 0.550221
+1 0.028833 1 1 -0.793884 -2.039764 0.310798 2.258053 2.222872 -0.006501 -0.873879 1.235711 1.103250 -0.924548 -2.137402 -0.767720 -17.554733 7.610060 -47.718275 48.954819 33.634955 0.665388 2.182440 2.275978 1.620402 1.589873 1.488698 2.042257 1.963354 1.094429 1.811732 2.032041 1.256900 0.968177 1.657653 2.167672
+1 -0.054484 1 1 -0.481485 -1.154696 -1.352372 -1.464307 2.200529 1.463848 -0.484375 2.121097 0.056427 1.183825 0.832516 1.005687 -24.011811 -66.501745 -44.833619 -68.641081 -0.650050 1.744036 0.505333 0.881967 1.726746 2.416561 1.884186 0.268881 0.328453 0.313396 1.491250 2.185276 0.439683 2.244328 0.675799 1.649755
+1 0.032127 1 1 0.763148 -0.900034 -0.108129 1.655533 -2.113309 -1.104167 -0.339415 2.153949 0.852068 -0.236602 0.687199 -0.317879 39.795738 -3.032219 37.495984 45.004315 -62.471393 2.024585 1.947968 1.256336 0.488053 0.711417 1.785067 1.628392 0.886677 2.130283 0.914313 0.858961 2.055477 1.405126 1.452983 0.293930
+1 0.014601 1 1 1.934316 -0.720528 0.917308 -1.748841 -1.600781 -1.299800 0.903168 0.939172 -1.844479 -2.066124 0.242231 -0.319473 -62.783493 47.825276 -50.586646 -9.754496 6.178447 1.992466 2.134037 1.017156 1.346976 0.616439 0.735968 0.406344 2.174155 0.279860 0.362741 0.595916 2.315489 1.924325 2.129598 0.652160
+1 -0.031607 1 1 -1.608924 -1.493096 -0.998586 2.297884 -2.195427 -0.536848 1.414590 1.015376 1.859295 1.317887 1.495831 -0.162081 -10.835572 -13.450771 -17.102429 -40.518126 11.856452 2.445760 2.142801 2.051370 2.134561 0.823371 2.403119 0.963762 1.697107 1.536346 1.862693 1.287936 0.584432 0.553171 1.642616 1.444912
+1 -0.009442 1 1 -0.609487 1.094084 0.532895 -1.885103 -1.540517 -1.612228 -0.478945 -0.860184 0.497493 1.594994 -1.718482 -0.298783 55.989896 72.178298 50.652543 67.286315 31.104388 1.696818 1.175783 1.135136 1.980389 1.649326 1.726760 0.399426 0.659535 0.549637 0.754478 1.019778 0.402880 2.450787 1.130468 2.279588
+1 -0.005326 1 1 2.116615 0.124130 -1.342511 -0.660226 1.254462 0.521443 -1.154496 2.007146 -1.894738 1.467300 0.988684 0.931336 -50.797110 52.966477 -42.429057 -5.164598 48.599640 2.337239 0.730157 1.747267 0.813654 1.081294 1.564736 2.009559 1.411798 1.085592 1.800641 2.367710 2.098449 1.389046 1.192564 1.914752
+1 -0.044247 1 1 -0.705028 2.260684 -0.679053 0.567456 -0.636528 -1.010295 -1.297785 1.782476 1.410946 1.027849 -0.566457 -1.422078 12.133234 73.269119 -65.916244 45.690118 63.815891 2.180169 2.355430 0.453128 0.969412 2.157484 1.339433 2.100652 2.409477 2.072834 0.621794 0.736218 2.373902 0.421461 1.998642 2.426321
+1 -0.055117 1 1 -0.767827 -2.345606 1.241675 -2.330867 -0.791456 1.080088 0.923812 -0.817778 1.637169 0.264408 0.117258 0.982395 -34.841543 18.189568 12.061933 74.910719 74.461961 1.857790 2.124753 2.472723 0.800827 1.504661 0.344502 2.291979 0.535803 2.246509 1.329040 0.671620 1.159568 0.866601 2.213580 1.397232
+1 -0.010491 1 1 0.471983 1.659954 1.508449 -0.142778 -1.057803 1.339409 0.367497 -1.416327 -1.924858 -0.540862 -0.073098 1.375235 -22.170342 -16.941763 -40.214115 21.363451 -44.478190 2.200957 0.730805 1.381647 0.591949 0.893340 1.615343 2.071988 2.154178 2.027028 0.266344 0.446968 0.935334 0.904402 0.782668 2.304740
+1 -0.018249 1 1 0.233755 -1.411108 0.954875 -1.819490 -1.484108 -0.721477 -0.895370 -1.822828 -1.026267 -1.129696 -0.578390 0.654769 40.568956 -57.552680 62.110105 34.528662 -26.775988 1.014603 1.173598 0.405030 0.343023 2.188416 1.452327 0.506648 0.485076 2.426300 1.316720 0.613025 1.859696 0.413874 0.477556 2.032510
+1 -0.082242 1 1 0.491849 0.980424 -1.230294 0.405429 -0.068838 2.286100 -2.343796 -1.314731 -0.283883 -2.278086 0.363332 -0.728884 59.133567 -42.131576 44.610443 67.717435 -73.075076 1.783046 1.401118 1.587837 1.024191 0.319983 1.948735 0.647299 1.911006 1.033007 2.246374 1.300903 0.277442 2.473259 0.807613 0.795470
+1 -0.045739 1 1 0.277254 -0.742500 -0.797058 1.166809 2.312262 -0.890161 0.903849 -1.747989 -1.419567 0.161532 0.531133 1.488952 64.720741 -38.498924 48.583488 -57.325552 -20.554419 1.253286 0.980813 0.275531 1.848415 2.069386 1.168694 1.231264 2.109339 2.168775 2.104732 1.221741 1.796879 2.148346 0.742961 0.937146
+1 0.018262 1 1 1.734285 2.003844 -0.835776 0.749992 -0.526765 1.234166 -1.306295 0.117490 0.160904 -0.599254 -1.285775 0.992809 -13.472319 70.741726 56.180895 -17.701737 -63.090582 1.173942 1.697426 2.387135 2.321340 1.262752 0.331839 0.970607 1.996579 1.499199 0.794014 1.739316 2.191076 1.157082 1.829976 0.405518
+1 -0.033639 1 1 1.350511 -1.535068 0.435945 -0.837266 -0.736683 -1.981951 1.232719 -2.069699 1.431131 0.988712 1.406989 0.491061 59.242529 -10.816345 9.694538 36.093551 24.311581 1.446227 1.490196 2.465781 1.140454 1.368874 1.919714 1.133944 2.198684 0.773276 1.948324 0.486341 1.190253 1.337322 0.377131 1.683415
+1 -0.024219 1 1 -1.701885 0.612545 -1.518099 -1.810075 1.244136 1.319517 0.627765 -0.192972 -1.159735 -1.222107 1.346043 -1.229189 4.116184 30.709160 -21.147787 69.145282 74.755457 1.599433 2.427029 2.323836 0.454938 2.150748 0.624308 2.497468 0.442474 1.904036 0.883447 1.841139 1.265451 0.692912 1.269964 2.290438
+1 -0.015087 1 1 -0.309998 1.763575 -0.516143 0.687060 2.059506 1.625124 0.450629 0.908647 -1.221952 -0.756248 -0.942654 -0.133369 49.982113 49.376048 63.231626 -16.064426 5.193849 1.270388 0.413448 2.312372 1.286900 1.183455 1.828845 1.642564 0.581897 0.687833 1.409895 0.610746 1.799893 1.044736 1.371598 0.439499
+1 -0.065937 1 1 1.756909 0.546582 1.949547 0.801063 0.162402 1.013553 -0.493927 1.796314 -1.622782 1.210142 0.185150 1.643860 -12.049264 -11.988083 -33.705296 65.088581 -6.224447 0.410891 2.096644 0.291636 0.271211 1.240390 2.484023 1.715788 0.489988 1.733579 0.269300 0.631659 2.299217 0.691468 1.749992 1.618094
+1 -0.020060 1 1 -1.429451 -1.024377 -2.343231 -1.253262 0.795734 0.133421 -0.690441 -2.333752 -2.151598 0.970720 0.602351 1.497993 -48.498531 -14.818335 -51.762502 27.624564 36.052466 0.381936 1.444349 1.426984 2.076539 2.135006 1.554361 0.895787 2.234187 1.234047 1.622379 1.075389 1.313475 2.331629 0.938794 0.557386
+1 0.000418 1 1 1.803456 0.589953 0.474711 0.400778 1.875813 0.906335 2.323612 1.380753 -2.202990 -0.406565 -0.165958 0.483302 -41.557324 -53.943074 -21.249344 12.274018 39.425512 2.493583 0.400544 1.441682 1.602433 1.087172 1.352800 1.755036 0.889413 0.864391 1.075255 1.314605 1.073011 1.838586 1.120566 2.344821
+1 -0.052535 1 1 -1.000291 1.909972 0.100355 -0.373711 0.657897 2.014753 -1.271471 1.069057 -0.703758 0.041160 -0.938556 -1.949551 -27.522511 29.158577 18.201273 58.798073 19.213947 1.057138 0.561133 0.470361 0.349356 0.631996 1.200263 0.814472 1.334094 2.363150 1.961427 2.446306 2.319904 1.867525 1.490301 1.984938
+1 0.018443 1 1 0.605365 0.319543 -1.561421 0.484069 2.172036 -1.467223 0.323501 -1.011614 0.096160 -0.188807 -1.845370 1.806358 71.460404 -14.985065 -3.986972 40.963913 -19.514676 2.377685 0.996375 0.832962 1.589107 2.121560 0.553216 2.393266 1.878787 1.765884 0.957778 2.379497 2.208792 1.919227 1.944778 1.627718
+1 0.022916 1 1 0.606248 1.019081 -1.833898 1.418300 2.104277 0.105004 -2.342814 1.050164 2.218407 0.344705 1.929392 1.336284 -10.429081 68.443661 -17.392808 29.080487 55.736758 1.640297 0.726907 1.129726 1.056317 0.277025 2.205025 1.598398 0.767634 1.630618 2.301363 0.759516 2.428361 2.219083 1.631279 2.158572
+1 0.003633 1 1 -1.843511 0.067859 0.114577 -1.678284 1.438671 0.477855 1.392695 0.592800 1.205629 -0.273069 0.395247 -1.550341 -56.701506 -32.216270 41.142028 -25.935478 2.426397 1.081798 1.023096 2.171402 1.247168 1.653644 2.291625 1.336773 2.387990 0.950098 1.552116 1.414080 1.186655 1.604113 2.336025 0.580293
+1 0.026070 1 1 1.863417 -0.089692 0.508385 0.858535 0.058302 -0.293889 -0.809228 -0.742653 1.351887 -1.969298 1.824414 -0.588895 -49.170121 -52.220959 -27.650414 -20.509876 -9.491121 0.365965 0.781166 1.800213 1.929722 0.584609 1.281772 0.484601 1.185361 2.367737 0.299917 2.212124 1.663377 1.626937 1.185628 2.351020
+1 0.028370 1 1 1.333121 -1.642743 0.296491 2.125746 -1.914188 -0.276109 1.131274 -1.169986 0.843674 0.057673 -1.441905 1.717186 66.340385 32.844057 10.062605 72.205689 61.008583 0.943800 1.451530 0.619929 0.899587 0.852279 2.256795 0.949436 1.663492 1.314967 0.407915 1.574645 2.063506 1.339265 1.525693 0.568695
+1 0.005670 1 1 0.621611 0.042723 1.762680 -1.425349 1.938179 -1.778765 -0.314595 -0.093094 -0.114717 -0.685523 0.203806 -0.534005 66.233328 33.548459 -1.045749 -25.895997 65.974158 1.790020 1.614019 2.311276 0.862416 1.624693 1.720474 0.505909 1.559298 0.629283 0.603172 0.512923 2.439434 1.573965 1.884240 1.169968
+1 -0.036892 1 1 -0.588195 0.795356 -1.507367 -0.513543 1.982740 -2.099881 -1.620392 -1.034522 1.499509 0.390277 -0.265077 -1.944916 52.393681 -69.410310 -29.072084 -64.512272 -57.760780 1.593454 0.930807 1.318216 1.015418 1.384769 1.303950 1.980182 0.412872 1.647702 1.429620 1.377354 0.431359 1.856209 0.307608 0.973417
+1 -0.026907 1 1 0.886188 -1.691759 1.155909 -1.817720 0.003372 0.128806 1.849394 -0.147063 2.321139 2.232831 -2.270179 1.311845 -34.443887 -48.413140 70.356215 26.906270 -36.328342 0.318462 1.149058 1.968141 0.544664 0.417722 2.152314 2.187966 0.652238 1.666849 1.475261 1.217346 2.178748 0.959673 0.477240 1.220092
+1 -0.002353 1 1 -1.149906 -0.966556 -1.303661 1.984935 1.799308 1.571226 -0.636237 -0.817378 -1.052862 -0.431060 -1.877612 1.846130 49.111861 -26.945882 -29.446413 -55.856597 68.173513 0.508559 1.106327 1.538682 0.620654 1.828570 1.519569 1.151014 1.090940 1.684881 0.800634 0.508064 1.786922 1.297383 1.868878 1.728948
+1 -0.024260 1 1 1.483504 0.003087 0.046272 0.155883 -0.163763 -0.328644 -0.600743 1.957900 -0.184803 -0.519921 -1.544596 0.522827 -46.383211 -12.620681 -15.777846 21.737933 -50.552337 0.878034 0.861932 2.492317 1.620583 2.393419 2.186542 1.459271 2.472138 2.225736 0.951569 1.518309 2.463414 1.852999 0.356299 0.317603
+1 0.063041 1 1 1.079674 -1.323925 0.690937 1.256411 0.291521 -1.297765 2.119567 -2.097976 2.124162 -0.273319 0.899009 1.733458 71.437949 57.610583 11.062520 -72.223774 -64.973808 1.153121 0.505471 0.944865 1.346009 2.373909 0.537736 0.972676 0.765692 0.482408 0.335283 0.354732 0.976122 2.425156 2.348425 1.972372
+1 -0.034683 1 1 1.184894 -0.034026 -1.676203 -1.280792 -0.070542 1.921569 1.813180 -0.898188 -2.057586 -2.341690 1.097310 -1.796319 49.153057 65.426005 -35.134756 40.159636 -36.998174 2.450263 1.313406 1.162070 2.411925 0.470346 2.356770 0.486714 0.707696 2.244983 0.430803 1.504210 1.766502 2.355542 2.348508 1.126522
+1 -0.065158 1 1 0.944516 -1.560651 -0.710300 -1.533400 0.199759 2.133278 2.147860 2.179291 -2.062494 -0.010299 1.260580 -0.340047 30.249521 53.692778 14.524604 65.026518 0.679798 1.755409 0.403439 0.605808 2.057204 1.184619 1.134271 0.937864 0.681746 0.353152 1.429369 1.647557 1.241837 2.059605 1.029885 1.522505
+1 -0.047623 1 1 -2.157178 1.431487 2.255860 -1.641317 0.710153 -0.944885 0.060601 0.643094 -1.737481 0.836391 0.175448 -1.201142 9.017596 58.736596 35.971199 67.942059 -47.817682 1.798286 1.045053 2.206239 1.752805 1.637578 2.279003 0.707043 0.270602 2.250828 1.919861 1.354040 2.353075 1.380224 1.433761 1.219675
+1 -0.027062 1 1 1.194610 -1.680423 -1.516072 -0.736074 -1.168149 -1.272189 -1.576287 0.396401 -0.998443 -0.017873 1.197903 1.822420 -35.743778 4.328726 2.903968 56.993961 -2.501780 0.663878 1.546495 1.433117 1.645202 2.164673 0.651628 0.414978 1.035044 0.477328 0.449839 1.946646 1.523640 2.068688 0.687234 0.342007
+1 0.028435 1 1 -0.273134 -0.695837 1.211475 -0.970101 0.375681 -0.526239 0.652800 1.169850 1.582910 -2.173694 1.881764 1.968484 -43.516434 19.288407 30.253834 -23.818998 24.095276 0.914514 1.992013 1.257278 0.567415 0.299622 1.741467 2.343754 2.219323 1.169116 1.587880 1.741912 0.808613 1.862610 2.136973 0.846897
+1 -0.021338 1 1 1.482038 -1.074874 1.898092 -1.644846 -2.054549 1.581232 -2.102255 0.893724 -2.277817 0.172984 -0.204490 -1.536292 -40.635266 -6.912520 71.280544 -37.902582 21.302753 1.155671 0.609890 0.926822 1.850460 0.425525 0.547435 1.996498 2.383244 2.175005 1.053420 1.086926 1.709218 0.335788 2.091038 0.576521
+1 -0.004638 1 1 1.047261 0.536184 1.557144 -1.696767 1.806674 -1.868713 0.616470 -1.538839 -1.677655 -2.126734 -0.555006 -2.173707 52.726721 -21.993363 -42.453428 35.240019 -71.004169 1.868959 0.846418 0.499265 2.393090 1.169750 0.985485 2.291733 0.915044 1.891452 0.875784 1.307534 1.471808 1.678418 2.414640 1.099345
+1 -0.002417 1 1 2.013204 0.970445 0.695371 0.369363 1.670383 -2.292400 0.120937 1.541502 -0.682711 0.348649 2.246370 -0.927423 43.963091 -12.335582 -24.127486 -60.659916 38.791502 2.406487 1.326493 0.612966 0.877712 2.203173 1.983273 0.627145 0.674485 2.062178 1.524615 0.458379 1.473381 1.111449 2.132408 0.632798
+1 -0.004358 1 1 -1.235181 -1.621218 -0.777038 -1.648905 0.410332 2.216713 0.144590 -1.474851 -0.657436 1.019616 -2.266007 0.753302 -46.162159 -47.407583 20.750651 6.188132 53.929824 0.603391 1.942146 2.392867 1.919561 0.813158 1.744879 1.176055 1.199615 1.186114 1.524126 1.239400 1.592096 0.598267 1.316617 1.126921
+1 0.003961 1 1 2.149612 -1.349923 2.000272 0.380563 1.417831 -1.056963 1.333453 -0.783130 -0.360555 0.276994 -0.403485 -0.243144 -28.065990 44.907532 -39.101632 -31.120681 4.714480 1.918977 2.246150 2.037437 1.951258 0.291975 1.468675 0.764016 1.563290 2.464776 2.231781 1.298920 0.700146 1.354839 2.284627 0.729934
+1 0.019409 1 1 0.817369 0.906482 0.084788 1.889281 1.064366 0.562764 0.615573 2.244170 -0.196431 1.970133 -1.936883 -0.001580 54.550787 35.070938 -62.743977 -38.022376 -42.077697 2.127273 2.068391 2.451751 1.574044 0.958955 1.900602 1.672457 1.240545 0.590432 2.396719 1.413735 2.143026 1.342800 2.445263 0.532472
+1 0.016191 1 1 -0.473787 1.006689 1.941326 -0.706485 1.328034 -2.319654 -0.832864 -2.143162 1.384558 0.495578 -2.317479 -1.968624 -31.050864 -21.872498 38.917889 -57.042929 -70.503168 2.173892 0.353139 1.202279 0.947096 0.597808 0.367377 2.005724 2.202754 1.690422 1.665817 2.140108 1.791587 0.947259 1.073592 0.361307
+1 -0.039622 1 1 1.180392 -0.309685 2.315602 -1.291721 0.024005 -1.811811 0.344464 -2.126032 1.830216 -2.029889 1.356154 -0.948971 66.261191 51.836916 23.046461 41.875946 9.022758 1.307326 2.472411 2.318743 0.362532 1.574508 2.005785 0.982249 1.901265 1.562208 2.281099 2.176338 0.971807 1.904737 1.414177 0.576541
+1 -0.013330 1 1 1.343091 0.980709 -1.164985 0.081345 0.571380 -0.670030 1.421419 -2.027085 1.354911 1.731601 -0.703563 -1.405056 -31.897481 -0.956100 -19.170040 9.140360 22.032456 0.617198 2.246692 2.158965 1.467579 0.344321 1.505655 1.286862 0.539006 2.079871 1.894618 2.339421 1.402011 0.848876 1.304151 0.872795
+1 0.014238 1 1 -0.734369 -0.799525 2.113930 2.117272 1.746766 -0.288473 0.682928 -1.401126 -0.908314 2.104358 1.467458 -1.075325 -30.800346 -11.409885 -65.935030 29.953642 30.867057 0.364398 1.429260 2.070272 0.312137 0.590189 0.564384 1.093448 1.084100 1.471537 1.628255 0.824413 1.915580 1.410996 1.106072 1.755828
+1 0.030407 1 1 0.491456 -0.915100 1.154345 0.169940 0.470794 0.527625 -0.922799 -1.017108 2.013612 -1.607689 0.403516 0.761542 12.338511 73.353784 7.039779 -32.435959 -51.166026 1.414055 0.779386 1.140694 0.896269 1.344728 1.093508 2.096020 1.064278 1.312894 1.566533 0.721501 0.262691 2.048531 1.667976 2.431495
+1 -0.018719 1 1 0.364748 -0.495201 -0.762421 -1.016869 1.318622 -0.289518 1.968695 2.176297 -0.543523 2.329017 -2.026650 -0.761032 -39.437319 26.972985 34.962235 60.278557 1.712608 1.131940 2.269007 1.448830 2.484608 0.313277 1.754231 0.852205 1.004542 0.844297 0.850618 1.344597 1.135668 1.924256 0.974972 1.099391
+1 0.002481 1 1 0.648184 -1.021919 1.266437 -0.860014 -1.364555 1.114126 -1.919579 -1.356970 1.362867 -1.216249 0.852225 -2.317465 -55.486849 -17.476026 -19.572312 -1.843644 63.875416 1.436841 1.237305 2.378171 2.414869 0.446860 1.381258 0.800013 1.310836 0.716205 1.265115 1.794701 1.546524 1.924364 0.541973 2.438437
+1 -0.064748 1 1 1.665183 -0.156546 -1.559079 2.157785 -0.646563 -0.020520 -0.876334 -2.324757 -1.780922 1.129711 0.836888 -0.898130 -34.913466 9.368877 -37.275051 68.211884 -12.866755 2.101699 2.000547 0.685612 2.330614 1.887626 1.828923 0.704178 1.618274 1.828174 1.626854 2.039296 1.700970 1.204922 0.380633 2.044857
+1 0.005782 1 1 -0.338889 1.578152 -2.033514 1.683110 -0.440227 -0.438793 0.088203 -1.966329 -0.108619 -1.866734 0.889787 2.243874 -14.629738 -32.007819 -55.414687 -4.647452 40.265981 0.630110 1.014050 0.894466 0.296501 1.038501 2.334404 0.329237 2.240317 0.759022 0.875227 0.944846 1.032968 1.592574 1.897157 2.270037
+1 0.016985 1 1 0.091053 -1.204432 1.534813 -0.008710 -0.312871 0.610483 1.509873 0.216116 -0.988172 -1.746453 0.836923 -0.323600 -20.563912 -17.674749 -59.511786 -14.584455 -20.936062 1.789019 0.548305 0.864285 1.533964 2.327193 0.632472 2.455042 0.638034 1.435213 0.883481 2.410783 1.526246 0.865189 0.984479 1.137005
+1 -0.017606 1 1 1.043623 0.661365 -0.965304 0.887630 -1.028930 1.239264 -0.457630 -0.772512 -0.970654 0.501789 -1.600245 -1.717857 24.965764 49.595549 2.393479 27.205568 43.988323 0.801196 0.953833 1.315152 1.261524 2.186836 1.898865 1.718280 1.885827 0.835707 0.478283 0.756467 0.694911 1.125189 1.295905 1.781304
+1 -0.025437 1 1 -0.756541 -1.162347 1.994707 1.100234 0.221631 2.162445 2.266264 -1.139930 1.766764 1.245441 -0.303310 1.074528 54.514839 30.895971 -31.413491 33.458271 -16.839337 1.843847 1.784251 1.406198 1.466783 0.473028 2.431145 1.760932 0.978491 1.750507 1.266970 1.465453 0.624727 0.534227 0.501633 1.699669
+1 -0.001915 1 1 -1.314256 -1.736154 -0.430240 -2.243120 -1.009894 0.731212 -0.436027 -0.541711 -0.195893 1.590837 -0.895465 1.282697 -28.150842 -31.201734 -7.550397 0.476923 65.650587 1.216221 1.278741 1.296442 1.795098 1.460071 2.406790 1.914410 1.980385 1.580967 0.309949 2.064740 1.829957 2.344202 0.755466 1.858577
+1 -0.005765 1 1 1.726323 0.125453 2.051503 -0.946517 0.907239 -1.321499 -0.949692 -0.605879 0.470347 -2.259384 -1.042394 1.142012 7.623931 35.402264 -44.141766 9.344784 7.779603 0.651774 0.607251 1.572598 1.407356 0.684057 0.942451 1.270448 1.420490 0.924186 0.290523 1.821880 1.587584 1.277947 1.453799 0.497547
+1 -0.017522 1 1 -1.639101 0.255398 -0.506420 -0.822287 1.250868 1.365801 0.973566 1.310697 -1.537356 -0.320285 -1.479654 -1.271065 -48.995739 28.622063 1.020582 52.922219 -36.273019 0.765634 1.754210 0.505988 0.634524 0.942758 1.930070 1.937123 1.233403 2.049808 0.616775 1.894462 1.970438 0.905622 1.045179 2.073268
+1 -0.005396 1 1 -0.585875 2.095542 -0.625414 2.013695 -0.199798 1.928089 -1.700354 -1.920804 1.628348 -1.908938 -1.578935 -1.693657 71.753155 -44.716152 -44.374477 -1.827295 38.650241 0.543940 1.746047 0.558433 2.340217 1.275294 1.866867 1.692735 2.295107 1.356400 1.518815 1.967119 1.361902 1.730005 0.939856 0.407929
+1 -0.018676 1 1 -1.155036 2.346757 -0.743292 0.035399 1.195097 1.799689 -1.445238 2.245174 -2.165269 2.109022 -0.257309 1.380246 -41.528910 -26.396805 48.892460 35.581586 -30.284836 0.666366 0.611259 1.435297 2.288652 0.882764 1.611510 0.650488 1.495777 1.780936 1.933425 2.074543 2.340763 1.458454 2.243270 0.886994
+1 -0.013919 1 1 -2.171399 -1.967625 1.677332 1.417005 -0.816296 -1.726517 1.329099 1.440482 -2.071913 1.916644 -0.851617 -1.598604 73.416412 9.643399 -73.388538 8.839934 72.771673 0.977568 1.984978 2.278301 2.404671 2.300330 1.401417 2.116692 1.991691 0.347674 1.602291 0.950808 2.238319 0.930528 1.137075 0.824538
+1 -0.040787 1 1 1.913093 0.721729 0.415986 -1.713188 -0.854660 -0.901855 2.273314 -0.463395 1.297633 0.384357 -0.796806 0.692441 -55.582427 26.142117 20.566833 66.762520 -72.327201 1.325887 1.681428 1.251827 1.210383 2.163776 1.326896 0.647613 0.427218 1.995661 1.833375 1.280997 0.962536 1.340035 0.962493 0.625589
+1 -0.029189 1 1 1.251554 -1.237861 0.463316 2.079630 0.560625 -2.352336 1.223495 -1.584362 1.339331 -0.939009 -0.125815 1.286452 30.645312 -44.234581 -50.601267 44.500248 15.668978 0.602641 0.579815 1.695363 1.469751 0.849186 2.018362 0.865501 1.727305 0.564749 0.478433 1.030466 2.282934 1.524893 0.619463 2.065794
+1 0.044124 1 1 0.385125 -2.021787 0.868297 -0.797442 -0.571529 -1.834220 0.711631 0.344845 -0.424722 0.963002 -1.877463 -0.369090 -57.073531 15.168193 -68.179052 -35.324906 -5.694423 1.282378 1.671334 0.369453 0.893559 0.798440 1.886626 0.774409 0.737762 1.311038 1.859013 2.428769 2.319025 0.600551 1.466263 0.734098
+1 -0.055837 1 1 -1.651557 -1.740765 2.194052 0.987527 0.334702 -1.263870 1.578066 1.235024 -1.016467 -1.348580 1.003129 -1.347084 -67.568032 34.090519 -40.640086 62.073993 27.597248 1.779183 1.723895 1.753526 0.262289 2.047501 2.356155 1.402767 2.297809 1.783050 1.473299 1.977972 1.533176 0.335487 1.527774 1.803135
+1 -0.007663 1 1 0.060242 -0.675982 0.343816 1.124853 -0.691276 -2.243707 -1.443196 -1.121142 1.804261 -0.009270 -0.284128 -1.687617 2.892792 19.155229 41.929443 8.155190 -35.720795 0.484017 0.374833 1.323583 1.216328 0.816792 2.077210 2.165033 2.212461 0.573685 2.174914 1.778628 1.408506 2.013309 1.427211 1.382091
+1 -0.023208 1 1 1.342556 1.414920 1.845153 -0.749013 -1.872509 -1.931846 -0.170091 1.708763 1.879753 1.153202 -0.191431 1.177635 15.012301 11.746223 18.765019 -66.333596 -68.752028 0.394888 0.874311 1.296244 0.718854 0.775305 2.305731 2.179754 2.123841 0.636721 1.874596 1.085463 1.880819 2.173636 0.550897 1.683221
+1 -0.028922 1 1 1.117350 0.427784 -1.335641 1.694211 -2.353746 1.099053 -0.778812 1.517806 1.602258 -2.154761 -0.352646 1.272272 -55.598807 50.846057 19.676892 -40.468085 -47.110168 2.416069 0.362767 1.018646 1.631809 2.062395 0.678499 2.025338 1.107845 2.295903 1.240196 1.474940 0.322551 2.366003 0.405031 0.354804
+1 -0.007586 1 1 0.075807 1.741514 0.973193 -0.244011 -1.317116 2.030302 0.878343 -1.606206 1.775380 -0.031716 -0.550426 -0.597702 39.563766 -1.777980 -32.510254 50.165716 -14.804732 1.778138 2.167551 1.773914 0.924283 1.926729 2.039367 0.641960 2.165140 1.753946 0.566658 1.066684 1.263764 1.577027 1.592156 1.616280
+1 0.023472 1 1 0.348091 2.291856 0.158707 0.173340 1.068595 0.964636 2.017128 0.947787 1.581938 0.337330 0.503627 1.013872 4.837094 -2.958317 -70.428692 -45.019990 -50.978284 1.494661 1.023511 2.408502 1.449062 1.883508 2.368001 2.496714 1.267013 2.189848 0.782206 1.290540 1.605206 0.452822 0.324018 2.276550
+1 -0.046840 1 1 -1.807538 1.482257 -2.114515 2.176568 -0.700458 -1.042623 2.017460 1.816621 0.380361 -1.976391 0.424054 1.950718 51.731027 43.364136 -28.958432 45.638759 -49.382941 0.938661 0.571265 1.996285 1.071193 0.539567 0.252906 1.838458 1.209003 1.455998 1.463160 0.323041 1.608208 1.407587 2.315682 0.660392
+1 -0.020999 1 1 -0.713116 -1.735777 1.194246 1.634039 -0.508216 1.983138 -0.121559 2.132075 0.774661 -0.597350 -2.269359 0.968761 20.892304 -13.044427 62.314957 27.481548 32.370589 1.412464 1.024878 0.626740 0.618601 1.084884 1.147085 0.311144 1.905630 0.677646 1.198985 1.845511 0.496900 0.895432 0.776827 0.886437
+1 -0.012240 1 1 -2.263984 1.766966 -0.072910 -0.171224 1.503287 -2.077585 0.831880 -0.246849 -1.894609 -1.078963 -0.854279 0.777658 -66.067371 55.689716 -22.945466 5.552021 12.812014 0.347798 1.445336 2.259181 0.547660 1.278559 0.493213 1.924534 1.145072 2.473336 2.110175 0.458395 1.750006 1.847456 1.691422 0.486373
+1 0.007419 1 1 0.202849 2.217925 1.667893 -1.719805 1.027522 -1.344712 0.047199 1.595363 -0.235286 -0.762989 -1.151066 -1.610693 55.969388 27.499126 27.809377 -7.807145 35.306881 1.416152 2.274004 2.182413 1.811198 2.051546 0.584406 2.362638 2.360712 1.493635 1.779328 1.912224 1.246035 0.617235 0.622053 0.587273
+1 0.001913 1 1 -1.138429 -1.272222 -2.125702 -2.046642 -2.188249 2.286413 -1.787564 -2.112419 -0.291883 -0.088730 -2.163919 1.224698 -7.069034 -9.262342 27.818811 0.764879 -44.683104 2.291167 0.398785 1.135248 1.613408 1.042500 2.050576 2.277180 1.557281 0.465648 2.153856 1.111508 0.858652 1.360531 1.192686 1.719145
+1 0.009453 1 1 -0.747482 0.302105 2.229958 1.273701 -1.293453 -0.813301 1.483240 0.267972 -1.242142 -0.793234 -0.531606 -0.017281 54.791975 38.724809 -2.143243 -21.481039 18.181816 1.851822 0.814873 1.316070 0.946226 1.718998 0.445682 1.833439 2.364992 1.419652 0.332988 2.278341 0.818190 0.824009 1.870633 1.974876
+1 -0.038984 1 1 2.213115 0.945244 1.255082 1.509802 -0.981112 -0.892410 0.798383 2.247894 1.136954 0.046185 -1.320238 1.398711 -62.573395 -21.054267 -9.064631 50.746498 -3.607508 0.904297 1.266100 0.345201 0.539604 0.866362 0.447790 1.259874 1.443951 1.490722 2.305683 1.368122 0.530406 1.525684 0.427327 1.592299
+1 -0.062981 1 1 -0.063067 0.316713 -1.996517 1.462331 2.287373 0.201109 1.252347 -2.051104 -1.774199 1.038871 0.911744 -0.999444 63.887891 63.786472 9.241988 -69.903542 -68.831275 0.666309 1.909651 0.755637 2.487527 2.113223 2.193113 1.653022 0.840892 2.120011 1.533439 0.265325 1.323161 0.871775 1.416836 0.264075
+1 0.003134 1 1 -0.318397 1.983572 -2.254615 -0.996510 -0.505925 -1.928211 -0.334881 -1.760990 1.556756 1.207357 0.508142 1.487545 61.731668 -25.864197 0.445523 -12.088145 -65.446871 1.141639 1.022719 0.330035 2.149329 1.529901 1.541008 1.469672 1.784033 2.244020 2.252653 1.085824 1.192215 0.553064 2.094351 2.257331
+1 0.045612 1 1 -2.145861 -1.577180 -0.472309 2.271894 -0.771209 2.075461 1.177035 -0.180343 -0.953408 -1.806972 1.574557 -1.197048 -51.049629 8.887650 -25.260661 -55.921327 30.250271 2.369586 2.137360 0.603457 0.793486 1.870606 1.522810 1.612360 1.432870 1.995933 1.900337 1.717085 2.053124 2.359429 2.425568 0.279123
+1 0.036101 1 1 -1.934216 -2.304891 2.239840 -2.289476 2.145931 -1.969625 1.039005 -1.562195 1.613639 0.637796 -1.242421 -0.771320 6.424708 -19.940797 -44.977209 68.051782 -3.696946 0.856482 0.892117 1.317226 2.372294 0.391966 1.272964 0.950053 0.791182 1.389552 0.697994 1.177737 2.475834 1.335484 0.978108 2.064332
+1 -0.076829 1 1 2.064080 -1.624300 -0.732528 1.872127 0.208887 0.035066 0.304983 -1.227178 0.942605 -0.696488 -0.306235 -0.963817 73.775613 46.723074 24.708415 74.337708 43.854361 0.778666 0.282184 1.160992 2.298633 2.117116 2.377221 2.196604 1.825992 0.941599 0.462110 1.175260 1.339733 0.393700 1.170756 2.140777
+1 -0.056880 1 1 -2.287918 0.055558 0.707342 -1.060150 -0.395123 -1.082445 1.881516 -2.205032 -1.740245 1.503813 2.052073 -0.777136 45.178787 19.871944 -62.229359 61.170259 -11.462546 0.609913 1.301602 0.767636 1.658688 1.561640 1.738004 0.377059 0.488780 1.678401 2.134088 1.864253 0.503897 1.502993 1.556309 2.134244
+1 0.048082 1 1 -1.840437 -0.105844 -2.354989 -0.937006 0.550611 -1.019126 1.078909 -0.051995 -2.088022 -0.231535 1.032218 2.184875 71.835133 -16.915150 -42.923025 -57.276148 59.774836 0.410102 2.329791 1.556025 1.859404 2.251223 1.800250 0.293742 1.914663 1.736226 1.995363 1.322164 2.115440 1.197044 0.713202 0.282721
+1 0.030729 1 1 1.336876 0.210035 0.477427 -1.075811 0.286305 0.572953 2.205948 -1.701579 1.049135 -0.942525 2.028811 -0.624006 67.018898 36.626747 -14.255347 -39.617500 -1.323595 0.689953 1.032321 1.974765 1.617244 0.263360 2.034922 2.437138 1.231919 1.867848 2.419275 0.256088 1.328103 0.680885 1.638161 0.823771
+1 0.036918 1 1 0.572991 -1.855050 -0.662902 -1.301402 2.255443 0.779779 0.587780 1.643701 1.662567 -1.705488 1.328005 1.907899 -55.875311 53.646212 -18.123278 52.059297 10.612843 1.675871 2.359209 0.978172 0.894946 1.603157 2.010291 2.465402 1.511967 1.637306 2.209928 0.755752 2.166576 1.145898 0.609632 1.081526
+1 0.040636 1 1 1.862330 0.497034 -1.414665 -2.279284 -0.916816 0.593498 -1.213187 0.476746 1.606556 -0.609434 1.980000 -1.025921 -0.688036 -13.813354 38.952671 -72.453060 -18.571593 1.633604 0.739224 1.135105 1.464999 1.991364 1.599477 0.912289 0.588649 1.680340 0.975367 0.991578 1.196666 1.119511 0.368159 1.653238
+1 0.002324 1 1 1.116474 -0.156464 -0.181356 0.864771 1.202653 1.554964 -0.626950 -0.254301 0.097828 -0.423665 -0.121911 0.929432 -19.372460 57.068123 43.945355 -10.423986 4.059053 0.932649 0.777428 1.975861 2.049476 1.794532 0.942562 0.887425 1.194083 0.445993 0.300168 1.929981 0.442003 0.747623 0.542575 1.315511
+1 0.003896 1 1 -1.066658 -1.398731 1.641581 -0.981750 -2.195768 -1.562721 2.201939 1.597474 2.258077 -2.083052 -1.524064 1.606044 6.799505 -20.723928 -7.050409 3.771689 -59.230600 2.294479 2.052565 1.956117 0.956955 2.034953 0.708656 0.383970 1.884098 1.029466 1.233721 0.642443 1.295931 2.217434 0.919070 2.062789
+1 -0.019890 1 1 -2.078005 -1.521225 2.188036 -1.165154 1.947930 1.896462 -0.754246 -0.282013 0.868333 -0.194218 1.464520 1.373267 -25.114410 2.117031 30.948409 -50.085266 16.934852 2.485804 2.402161 0.612477 1.644223 1.450829 2.327823 2.224009 1.168149 1.087936 0.694510 1.127804 2.497809 1.675755 0.410349 1.990471
+1 0.020194 1 1 -2.092296 -1.369918 0.527764 1.415892 -0.667346 -0.603220 -1.974476 -0.369039 -0.935279 1.298075 -1.609510 -1.929164 -70.548349 43.894642 37.251530 -13.528448 27.380524 1.141972 2.129212 0.924180 2.450134 1.409080 0.412817 0.712911 2.141782 0.683164 1.686290 1.971414 1.548694 2.405650 0.764209 0.317142
+1 0.006014 1 1 -0.392655 -2.007806 0.225927 -1.038400 2.296371 0.640567 -1.802630 -0.855588 2.344537 -0.367942 -1.349587 -1.777967 -33.120245 -1.963216 4.230492 1.882458 -11.526016 0.358719 0.485489 0.368585 2.050355 0.807913 1.340755 1.815422 1.041538 1.633026 2.276727 0.700402 1.154774 1.282922 1.822534 1.328413
+1 -0.009684 1 1 0.228625 1.901172 -1.703592 0.203758 -1.344721 -0.104160 -2.321022 -0.255278 -2.177372 1.314728 0.234204 1.423256 18.379422 52.941944 -4.753887 51.427978 50.024851 1.639998 2.443544 0.896460 2.299961 1.940994 1.027587 1.150593 0.772414 0.963840 0.752998 0.885715 1.716643 1.366986 1.676941 2.340343
+1 0.005588 1 1 -0.241935 0.584899 0.347879 -1.265269 1.628366 -1.606625 -0.564596 1.590059 0.157798 -0.966335 -2.296722 -1.825876 -13.237134 -26.508218 -23.613343 30.541605 12.748069 2.226914 0.488945 2.199035 2.188197 2.282278 1.748387 1.647819 1.149999 2.028203 2.010683 2.301397 1.336450 1.466605 1.987718 1.078392
+1 -0.002655 1 1 1.130719 -1.064568 0.746551 -1.816231 1.458403 2.246448 0.392987 -1.842646 0.468920 2.031856 -1.280665 2.051769 -37.531745 -46.044821 -25.313970 -51.893472 -73.581704 2.309417 1.125118 2.363562 2.137458 2.258839 1.561438 0.596922 1.217488 2.325430 0.256727 0.817365 0.452629 1.577421 1.468970 1.226096
+1 0.015592 1 1 -0.723546 2.036785 1.451329 1.158691 -2.183677 -0.978463 1.202885 0.742472 0.317090 -0.378779 0.290565 1.489497 56.305433 -24.587411 9.390911 33.044480 -71.420325 0.454045 0.638107 0.411985 2.484466 2.411629 2.246450 0.330503 1.008497 2.060030 1.416207 0.939636 1.215745 2.283559 0.771093 1.255004
+1 0.041987 1 1 1.340655 -2.261589 -0.389995 0.284175 -2.228477 0.061725 0.691826 2.052098 -0.362595 -1.008778 0.642304 -0.883005 -43.267464 3.725603 66.217113 61.019412 3.249309 1.542026 0.579180 2.278053 0.490663 1.817455 1.473151 1.751977 1.232177 1.691027 0.584801 2.246496 1.104538 0.727282 0.682000 2.372904
+1 0.025323 1 1 -1.138512 2.037291 0.539694 -0.704769 1.894008 0.400625 -0.701498 0.323360 1.328706 -0.450100 -1.449407 -1.847891 58.936857 -48.237655 19.727775 64.713805 -5.076216 1.885556 0.795669 0.315070 0.387089 0.296633 1.014602 1.166712 1.684661 1.599241 1.440962 0.750350 1.377304 1.847575 1.445065 2.205707
+1 -0.008069 1 1 -1.309840 1.808412 -0.923050 -0.520205 -1.611086 -0.138964 1.769737 -0.629726 0.222705 1.363727 -0.896326 0.964028 39.133069 -40.514869 66.593296 -66.479488 29.249613 2.098735 1.696287 1.253170 1.283239 0.392912 1.414099 1.516020 2.240390 1.980405 1.912445 0.461428 0.972556 0.997645 1.917776 2.302843
+1 -0.020082 1 1 1.546221 -1.491541 1.583562 -0.643960 1.316209 1.568966 -0.911023 -1.015451 1.578896 1.042820 1.292600 0.617261 74.542769 40.311503 -34.564411 25.952663 -13.585239 0.968301 1.477330 2.237093 0.566517 0.954974 2.493316 0.409284 2.087734 1.293225 1.725841 0.714020 0.538972 1.498341 2.110807 2.091561
+1 -0.027283 1 1 -2.310759 -2.125591 -0.180838 0.152404 -2.080794 -1.268382 1.160527 0.392527 -0.149358 1.445895 -0.635889 0.313274 46.252690 68.958249 -68.706148 -44.222366 4.695355 1.597542 2.141764 0.378699 1.037486 1.035367 1.411937 1.178197 1.204463 1.663960 2.423237 1.594083 2.494134 0.653367 0.385937 1.189664
+1 -0.004509 1 1 0.469282 -1.318085 -0.117770 -0.160013 1.443255 2.113718 -1.443799 -1.847241 -1.360494 -1.306350 -0.804422 -0.075141 0.989318 -22.529648 -55.792937 -61.889415 74.600998 0.909726 0.271896 1.512422 0.270722 2.032558 0.945432 1.873485 0.406647 0.521440 1.598011 1.025567 0.956900 1.119338 1.971283 1.611721
+1 -0.049771 1 1 0.978780 -0.588198 0.756631 -2.047772 -2.330585 -0.762879 0.701166 -1.182826 1.807769 -2.307879 -0.840722 -2.279816 -13.485791 -5.684920 3.547678 -74.179492 65.280208 2.341881 2.253034 0.743842 2.248742 0.600632 0.574154 1.053417 1.022863 0.506654 0.578423 0.810383 2.360299 1.297811 2.307729 1.994829
+1 -0.009889 1 1 1.313669 1.295366 -0.018628 -2.056824 1.042932 -1.534548 -0.244557 -1.064027 0.412508 1.095373 -1.367793 -1.465182 52.046527 -54.021420 11.987116 17.455406 -26.998102 1.268410 0.910075 1.634131 0.583986 2.047740 1.857436 0.669066 0.991315 1.279559 1.553221 1.980478 0.887244 0.414890 1.810861 0.888015
+1 -0.000600 1 1 -1.042623 2.000827 0.291963 1.426510 -1.275232 -0.886103 -1.586369 0.602015 0.570703 2.093548 -1.141518 -1.360262 -67.606854 -18.388016 -47.384241 -36.933415 -39.913611 0.954068 0.776723 1.387971 1.127838 0.819267 0.920432 2.444160 2.247154 0.917829 1.459415 0.381711 2.165528 1.523660 2.397613 0.674510
+1 -0.012891 1 1 -1.499661 1.773052 -1.458551 -0.022266 -1.940605 -1.308374 -1.834572 -0.497687 -0.135242 -1.637444 -0.173306 -0.491741 26.676338 -0.780518 -68.161986 -48.500603 -49.642548 0.740431 1.167744 1.021382 0.365442 0.982417 2.481120 2.429876 0.675695 2.161714 0.433127 2.307850 1.782986 0.391434 1.332020 1.253772
+1 -0.043249 1 1 2.094167 -0.165994 -0.127298 -0.078552 -0.760272 2.105277 -1.944123 0.822538 -1.760162 1.331985 -1.892771 1.533864 -58.247760 -70.098412 -44.004805 61.248250 -50.665047 1.713353 2.328899 2.307876 2.222180 1.930376 0.324787 1.687887 1.819392 0.268452 2.127681 2.182579 2.352682 1.522323 2.435009 1.451080
+1 -0.016175 1 1 2.305138 1.911068 -0.318748 0.791809 0.149219 0.939273 -0.146225 2.271774 1.930544 1.860594 -0.403265 -1.260620 -11.070221 -57.211851 -59.581619 11.731340 68.626822 2.289947 2.384883 0.485879 2.418763 0.642150 0.859455 1.356216 0.678800 0.336066 2.262987 1.526269 1.246414 2.473024 1.361150 0.352723
+1 -0.038323 1 1 2.056037 -0.129594 -0.970688 -0.067873 -0.340509 -2.093937 -0.676224 0.979649 -0.130229 -2.213747 -2.126047 1.567772 -68.048429 60.046804 6.642501 40.511977 34.801429 2.239347 2.450157 1.795587 0.689369 2.470649 1.943210 2.276375 1.540446 1.031546 2.452453 2.128477 2.056549 1.413115 0.715274 1.353870
+1 -0.023182 1 1 -1.621617 1.931876 0.683399 1.792238 0.546535 1.167820 0.447834 1.055827 -1.569761 1.700330 1.518691 2.346533 6.039204 -49.099201 -60.267660 31.445564 55.598564 0.551099 0.572806 0.892796 1.478971 0.561368 2.157437 0.545411 1.717240 2.410415 2.088362 0.604914 0.536709 1.724125 1.121328 1.651612
+1 0.023334 1 1 -0.721562 -2.311412 1.035822 1.488519 -0.525639 1.315611 0.947130 -0.035719 -1.858984 -0.807867 -1.430439 1.221584 -22.767335 -0.596424 25.907793 -17.720093 -71.610754 1.945973 1.469964 2.186277 1.508953 0.475244 1.426870 2.403741 2.418140 1.427593 1.064075 2.413765 2.153231 1.856978 1.984019 1.913897
+1 0.036170 1 1 -0.281064 -2.026215 1.836779 -0.124359 2.197564 -1.251704 -1.278227 0.615903 -1.638036 -0.698698 0.248393 -0.439399 -21.239301 31.060628 35.979722 61.192791 67.241375 1.761916 1.773373 0.832339 2.373248 0.675138 1.802478 1.752451 2.443954 1.030211 0.262478 0.713677 1.514309 0.485973 1.740642 1.967672
+1 0.039121 1 1 -2.113947 2.306192 0.764785 -1.653475 -0.989863 -1.890657 -0.629177 0.027888 2.179026 -1.790012 -0.842628 -1.315742 49.756213 2.668141 -6.554138 -55.393843 45.685489 1.165110 1.745783 0.633842 0.740917 0.340023 1.266685 1.181667 1.032871 2.214891 0.924321 0.319857 2.091339 1.131508 1.760406 1.135296
+1 0.049435 1 1 -2.157502 0.692105 2.032582 1.495569 0.139242 -1.820454 1.163855 -0.215566 0.801026 -0.454837 -0.948791 0.398259 61.887277 39.472445 -36.621343 -44.911029 -19.659532 1.858803 1.149489 2.465191 2.458422 1.200560 1.313497 0.445315 2.401156 1.720004 1.607490 0.584278 2.454492 0.388134 2.120323 2.264837
+1 -0.004107 1 1 0.714578 -1.963562 -0.720535 0.801133 1.342332 -2.339518 -0.111880 -0.118468 2.251869 1.970006 0.648880 1.261623 -52.562475 -67.515107 23.589474 18.287316 4.923279 0.558338 0.742346 1.862778 0.456262 1.888551 1.622080 0.554124 1.904745 1.552199 0.561204 1.654905 0.988205 0.764326 2.273680 1.234156
+1 -0.007979 1 1 0.328661 0.885611 -1.967911 1.577355 -1.300857 1.988229 0.611705 -1.499308 -1.719028 -0.044182 1.993381 -2.322915 28.939766 -59.345466 -69.240538 -25.721857 -7.250576 0.468604 2.327507 1.408456 1.175509 1.037181 0.404659 0.861662 2.452843 1.928091 2.427623 1.061073 1.457926 2.358007 1.016306 0.551897
+1 -0.035045 1 1 2.112713 0.518031 -1.949278 -0.990231 1.347867 1.150071 -0.982089 1.526227 1.766265 2.276607 -1.672684 1.317393 -66.621270 46.306833 -71.064319 71.997710 15.512976 1.773838 1.892007 1.209751 0.535576 0.675020 2.064579 1.371378 1.253215 2.032040 1.250983 0.525610 1.920029 1.928172 1.533735 0.738429
+1 0.054571 1 1 -1.152544 1.831254 1.274141 1.399695 0.419968 -0.749135 0.795240 1.256383 -0.186382 1.215547 1.489214 1.726554 -22.065191 -49.670495 -62.004175 -54.172487 23.013924 0.550431 0.596118 1.197608 1.190244 1.185953 1.054770 1.270878 1.900142 0.679441 2.112730 0.653820 1.253364 2.280593 0.426772 1.263510
+1 -0.066121 1 1 0.947698 0.090438 -2.111653 -1.545484 -0.258403 1.849137 0.244213 -0.004001 -1.263618 1.103624 0.649264 -1.714051 -38.725263 -5.496859 14.292253 59.902657 -16.046887 1.374470 1.464564 1.429459 0.914953 0.367047 0.958485 0.764087 0.516412 0.341449 0.482245 2.093088 1.276060 1.238936 0.550583 0.896547
+1 0.039594 1 1 0.960466 -2.096480 -1.003855 -1.440104 -0.991574 2.328156 2.346306 1.089922 1.268578 2.139834 -0.759869 -0.541161 -12.370946 -18.492882 -9.865771 -64.017012 16.079510 0.599898 1.730488 2.317988 1.181454 1.949073 1.818825 1.985518 2.347335 1.664162 1.318879 0.907300 2.236485 1.603405 1.672767 1.949755
+1 0.002594 1 1 -0.047403 -0.301759 -1.130766 0.281587 1.387020 -0.544630 -2.128980 -0.589809 1.946593 -1.725585 -1.872926 0.500130 -38.762282 -27.675606 6.094895 -13.099873 30.427995 2.174750 1.274740 1.562379 0.651772 0.579341 0.475961 2.229876 0.773024 2.211290 1.157250 2.397627 0.922889 0.999716 0.723340 1.923300
+1 -0.012588 1 1 -2.165868 1.461885 -0.489052 -1.090244 -1.966653 -0.844202 0.494225 -1.499319 -1.903912 -1.924104 -2.009699 1.385210 64.615594 -5.705625 -44.439700 -48.045706 -54.182945 1.333757 1.211699 1.781342 2.009629 0.339704 0.397512 2.240756 1.391152 0.598324 2.286644 0.880766 1.779248 0.576891 2.051507 2.176064
+1 -0.019896 1 1 2.249573 1.085578 -1.055452 -1.554027 2.241541 -1.978239 -2.350827 -1.677852 -0.718948 -0.785410 -0.986559 1.801975 -23.494354 -69.605433 -8.515289 -16.458294 -14.552756 2.302478 1.504684 0.715108 0.816630 1.592428 1.685531 0.472417 1.155449 1.386802 1.736971 1.025934 0.377280 1.945351 2.257750 1.253581
+1 -0.048840 1 1 -1.195087 -1.622698 -2.089783 -1.538593 -2.255032 1.425139 -0.755218 2.234690 0.700429 0.562802 1.249998 0.891863 -17.839731 17.646674 37.649809 -69.661821 -56.225995 1.520498 1.011580 2.125855 0.749993 2.128245 0.416630 1.798003 0.779898 0.740088 2.151938 0.376906 2.401600 2.435814 1.482618 1.108181
+1 -0.050640 1 1 1.339529 -2.337575 -0.439942 -0.365665 -0.773041 -0.438635 -1.962860 1.647095 2.153561 -0.954794 -1.542504 -2.021378 -53.703832 -50.312436 -51.117912 61.258211 -33.247269 0.822279 2.047645 0.272332 2.077567 1.411891 0.398403 1.456751 0.605374 1.514705 0.398040 2.112425 2.280702 2.261858 0.553500 0.426366
+1 0.035864 1 1 -1.618983 -0.917272 2.343914 -1.404726 -0.152212 0.604224 0.000364 1.403736 -2.340512 2.030114 -2.284083 -1.468227 73.077769 18.061143 -46.366575 -33.027943 49.357785 2.219356 1.722296 1.876052 0.809492 0.887913 0.400101 0.750701 0.530938 1.471154 1.935335 0.425120 0.496078 0.580930 2.434491 1.742209
+1 0.022585 1 1 2.135692 0.314823 -0.779293 -1.850520 0.075465 0.706089 1.438746 1.743423 0.069457 -1.308031 -0.776982 -0.707778 -49.747067 1.051926 -20.287606 -23.791328 39.150659 0.701993 0.900213 2.377464 1.792534 1.127416 0.486970 0.508652 0.408959 1.129898 1.693596 1.020329 0.664771 0.814454 1.025367 2.092021
+1 -0.009926 1 1 -0.380965 1.259033 1.945683 1.834331 1.153583 1.502871 0.347273 -2.038502 -2.032571 -1.318467 -1.814691 -0.928013 28.643369 59.102803 40.804469 0.714967 16.456508 1.142862 1.336085 2.081110 2.458512 0.463747 1.704261 0.267433 0.746250 2.218330 2.466631 1.913838 1.383458 1.781896 2.334615 1.628134
+1 0.009164 1 1 -1.209857 -0.101363 2.275241 -1.062864 1.113663 -0.282313 0.534678 -0.195037 1.840650 -1.034999 -1.794723 0.085955 -65.710161 59.330446 -33.202133 -28.249816 -44.658954 1.629417 2.367249 1.099463 0.930783 0.917992 1.936008 0.489802 0.853503 0.329195 1.528002 1.130118 0.895729 1.267752 1.106047 1.326971
+1 -0.001383 1 1 0.705861 2.323525 -0.076817 0.129995 -1.716319 -1.635581 -1.844570 1.116593 1.838313 2.101077 -1.844562 1.248294 16.731533 -43.129813 67.228923 -33.494840 2.219689 0.719783 0.641718 0.349374 0.932041 1.813100 0.272413 1.198189 1.960306 1.613972 1.531042 0.465703 0.813308 2.012872 0.841709 2.361136
+1 -0.044810 1 1 -0.252445 -1.699348 0.854760 -2.121425 -0.863560 0.313311 2.082997 0.589723 1.323532 2.117924 -1.433898 -0.368461 -20.575654 -65.015476 34.890852 60.557196 34.785008 0.349375 0.952714 0.520167 0.453872 2.222512 0.764964 1.744663 2.049395 0.436852 1.924764 0.504157 1.362447 1.899483 0.855320 1.615183
+1 0.001426 1 1 -1.268112 0.976632 1.006988 2.257242 -1.976485 -1.150575 1.923081 -1.057260 1.044792 1.459627 -0.745509 0.475438 -48.452287 12.410569 -65.559793 36.566431 22.003652 2.355638 1.711875 2.233859 2.469051 2.086515 1.056406 1.762988 1.791593 1.047403 1.198245 0.648109 2.010974 0.444379 2.426410 0.930298
+1 -0.007860 1 1 -0.407823 2.243761 2.346777 -0.406569 -0.247317 -0.328929 -0.670995 -0.668271 -2.008364 0.272667 2.273319 -0.369533 5.855570 14.566212 14.324742 5.933961 -17.913047 1.156365 1.032587 1.947482 2.075287 1.354658 1.489428 0.817140 1.178931 2.298463 1.522628 0.816773 1.758956 1.529532 2.088737 2.410058
+1 -0.005874 1 1 0.316690 2.328069 0.897587 1.392194 1.585905 1.028502 0.984409 -0.238617 -0.198121 1.846177 2.319016 -0.463819 -35.686372 69.149833 1.235129 58.804851 -16.875988 1.604161 0.876174 1.102499 2.459436 2.496815 0.719113 0.639743 0.905592 0.532519 1.039109 1.298802 0.966525 0.892052 2.471098 0.498722
+1 -0.020031 1 1 1.249785 2.023781 -0.332129 2.081722 -1.984428 2.010519 -1.746256 -0.569094 1.385617 -0.565289 -0.629126 0.876923 -60.926308 61.540482 60.881377 -66.695504 -1.329518 1.446769 1.602144 0.729850 1.081887 0.268093 0.585462 2.103616 0.481169 2.005699 1.780025 2.374102 1.527747 1.341207 0.418409 2.445248
+1 0.081022 1 1 -1.272287 1.488301 0.505557 0.461500 -0.155683 -1.193165 -2.312636 -0.681881 0.151613 -1.247636 1.112416 2.327926 -48.021281 56.328124 56.775519 -73.845338 -18.595866 2.264133 0.533639 1.872358 1.727585 0.774170 1.231111 1.776931 2.131355 0.933607 1.127586 1.087305 1.327827 0.533783 2.038006 0.273585
+1 -0.013296 1 1 -0.154095 1.945073 0.997774 -1.802297 0.027003 1.442644 1.280443 -1.068666 -2.150320 -1.114004 -0.738101 -2.256240 -0.824886 -63.863145 52.122443 21.895516 47.935631 1.437129 1.581649 0.526547 1.919286 0.694230 0.930761 0.555028 1.358008 1.531775 1.536335 1.683025 1.107818 1.841952 1.436755 2.038338
+1 0.018504 1 1 1.434942 -0.940393 0.166645 1.635641 -1.862630 -0.822465 -1.729662 0.299158 -0.176790 2.204112 0.421624 -1.199820 -33.697761 41.726670 50.148609 -2.335755 42.961731 0.742089 2.035901 0.889131 0.624629 1.133458 0.775207 0.652691 0.274485 2.262417 0.943095 0.842121 0.285142 1.387489 2.021611 1.470011
+1 -0.016778 1 1 -0.461288 -0.993384 0.186962 -0.894548 -2.146513 1.602230 2.094478 0.346939 1.782925 -0.466599 -0.716253 2.081544 -8.411649 -74.577333 -21.235110 -48.490309 -26.620307 2.012508 1.471058 0.326230 1.190109 1.164032 1.634481 1.974096 1.624021 1.661709 0.591051 1.548657 1.775271 1.237294 2.208663 2.003684
+1 -0.005102 1 1 -1.977854 -0.599027 -2.190543 1.430052 1.692941 -0.141930 -0.957100 2.108059 -2.296730 -1.965654 1.807368 0.372785 -66.213342 2.367136 34.450641 11.929930 -43.661871 0.998935 1.094527 1.218312 0.425275 0.840830 1.086326 0.634110 0.742284 0.825025 0.940167 1.139644 1.240538 0.466744 0.323516 0.577223
+1 -0.021303 1 1 -0.037032 -0.364097 2.022426 0.458075 -1.178832 -1.749450 2.305256 -0.818235 -1.323106 0.311967 -1.652829 0.441435 60.662859 10.664891 -5.174964 24.385834 52.715885 0.563188 1.250180 0.531808 0.351638 0.723232 2.358042 1.620306 2.230697 1.069846 0.409763 1.139055 0.339128 1.972911 1.962023 1.221897
+1 0.039378 1 1 2.267309 2.277767 -1.019659 1.556935 -0.496546 0.187662 1.454310 -0.571350 1.175409 0.757170 2.308556 -1.907402 21.299581 -67.945345 -7.419267 -45.620232 60.753477 1.880245 1.528072 2.310243 1.498612 2.171976 1.906802 2.366357 1.865701 2.342898 1.338628 2.074150 2.493322 0.509957 2.091187 0.833385
+1 0.004307 1 1 -0.492945 -0.541664 0.581446 -1.133109 -1.397920 1.135815 -0.247916 -0.967177 -2.313595 2.049027 -0.150719 2.128112 4.575807 -44.406111 66.496527 -42.872588 40.418255 0.769103 1.565414 2.153976 0.876209 1.690880 0.371696 0.338234 0.442044 1.431076 1.093001 0.311482 0.829374 2.043121 0.727423 0.790611
+1 -0.047277 1 1 0.131657 -2.062041 -1.809288 0.343449 -0.334112 1.753673 -2.007020 -0.707474 -1.155876 -2.335887 -0.337819 0.701690 -57.645734 -1.856744 -6.289351 44.873812 -5.839161 0.793291 0.838808 0.841143 1.843927 0.872314 1.474530 2.425311 0.448108 2.096575 1.384579 0.375958 2.232853 1.304531 0.507833 2.399662
+1 -0.001387 1 1 0.821210 -0.512008 -0.492632 -0.002398 2.105162 0.845406 0.890111 -1.735108 -1.693030 -1.353000 2.122453 -0.723229 -65.559916 34.488530 48.720900 2.162840 50.848311 2.238336 1.214091 1.481331 1.977671 0.965052 0.877135 1.500379 0.372543 1.078618 1.577544 1.283417 1.145390 1.077876 0.358306 0.307063
+1 0.011238 1 1 -2.335591 -0.072726 -1.789159 -0.633421 -0.621676 -1.144171 1.177649 0.704602 0.011856 1.337943 -0.703751 0.152172 -40.563828 -6.253168 53.012052 -26.433732 28.273900 1.366634 0.274504 0.342046 1.518771 1.238180 1.346736 1.094802 1.339881 0.633396 2.228653 0.472354 2.347393 0.378801 0.508957 1.041287
+1 0.007206 1 1 0.388536 -1.239765 1.452579 -1.398477 1.192661 -1.453709 1.248286 0.387739 -0.505743 1.130470 -0.547307 -0.008967 3.059210 -33.858491 40.348491 -12.919813 56.695981 0.465311 0.978105 2.006591 1.017449 1.771671 1.480401 2.101327 2.499956 1.761694 0.284102 1.905227 0.645817 1.753083 1.820938 1.510846
+1 -0.007302 1 1 -1.160669 1.930681 -0.554926 -0.825637 1.511469 -1.229394 1.397691 -0.268628 -0.363714 -0.969106 -1.752039 1.192284 52.082555 -48.492883 -69.882911 -22.084768 71.303855 2.183241 2.229085 0.975179 2.336038 0.798367 0.653938 0.980856 0.999292 0.351334 2.371668 1.121606 1.830270 0.852753 1.225510 2.146870
+1 0.005020 1 1 -1.589524 -0.592194 -0.430700 -0.539284 -1.824535 -1.450581 1.977574 0.609913 1.369848 -1.690471 -0.757614 -0.338219 -41.407755 59.860514 25.650651 10.485234 -24.678619 1.021881 2.007573 1.788612 0.445352 0.785849 1.757125 2.243403 0.869364 1.395952 0.266528 1.285803 0.737065 0.845814 1.594897 0.433522
+1 -0.034337 1 1 0.382772 0.837350 2.150881 1.117163 2.000355 1.783697 -1.620953 -1.035837 -1.756607 -0.172652 1.063735 -0.606938 48.379665 -32.975509 30.617920 -54.611752 -9.720333 1.080524 2.111594 1.801764 0.994824 1.763651 1.675620 0.400949 1.497759 1.335287 2.165934 1.601625 1.008776 2.242456 0.712168 0.914444
+1 -0.066004 1 1 1.250600 1.571935 1.854281 1.872946 -0.160014 1.413234 1.775559 -1.739418 1.257246 0.182666 2.309100 -2.191361 58.226269 8.898165 1.467758 68.603402 -32.628445 1.580984 0.590906 1.356912 1.116518 1.810625 1.433329 0.719668 0.951927 0.781085 0.447218 0.637290 2.431127 1.452240 1.299282 2.287586
+1 -0.013254 1 1 0.309169 -1.554663 0.971449 -1.290027 0.223309 2.092739 -0.599129 0.813559 -1.863008 2.244674 -1.157264 -2.114792 71.518888 67.956043 37.208187 7.997015 5.829052 1.658164 1.754897 0.803060 0.776377 2.318756 0.586611 1.165805 2.180666 1.708838 0.693231 2.137412 1.477267 1.171763 1.077026 1.830714
+1 0.036110 1 1 -0.220272 1.831805 1.111337 -1.673669 -1.107913 -2.045371 0.332793 -0.353459 1.738908 -0.414579 1.795475 -1.589349 74.493436 -38.817969 -63.609192 -29.683339 12.113725 2.055575 0.792142 1.784632 1.053456 1.691736 1.252180 0.381679 1.635258 1.529477 1.175711 2.178809 1.988991 2.228483 2.115363 2.155329
+1 0.001939 1 1 0.513058 -0.699568 -0.222779 2.104374 1.735619 0.862681 -0.937944 -1.088358 1.465630 1.187215 1.259079 -1.997112 28.242349 69.158427 -4.316705 49.145494 -61.686363 1.934533 0.453084 2.484275 1.464391 0.764815 1.499773 1.433291 2.322243 0.685709 1.714214 1.053030 1.266726 1.860877 2.256931 0.983876
+1 -0.018249 1 1 0.025632 1.967122 -0.706652 -1.476205 0.150950 1.755778 0.388424 1.587678 -2.151523 2.218696 0.487723 2.312730 71.976072 -48.151402 -30.620457 11.983084 -50.304125 0.453442 1.755328 1.299405 2.101734 0.347115 1.219282 0.974101 2.223257 2.027978 0.477635 1.117667 0.880650 2.085037 0.972636 2.338578
+1 -0.004418 1 1 1.864651 1.810387 -0.725965 -0.924959 0.378847 0.841679 -0.499443 -1.375915 -1.305491 -0.510906 -0.816545 -1.197638 -66.581836 -40.924913 74.986797 3.102474 -56.715219 1.934833 0.988032 2.353944 2.480825 1.977498 0.312576 1.220330 0.593998 1.572593 1.320102 1.202141 0.887615 2.144790 1.731752 1.052957
+1 -0.029717 1 1 2.247552 0.094337 2.161693 -0.949332 0.727028 -0.071550 -0.889105 -0.204889 1.184203 -2.229460 -2.322090 0.645231 38.004729 45.481390 5.714351 41.098425 -8.765390 1.076437 0.932562 1.566804 0.775767 1.061603 1.358386 1.142195 1.362919 0.827925 2.442181 0.480892 1.846851 0.524534 1.849228 2.226478
+1 0.003357 1 1 1.031812 0.069245 -0.153542 1.812842 -1.864350 -1.460246 -0.227987 -0.602977 2.107686 0.856562 -0.110200 -0.163463 0.018636 13.223624 -50.546494 65.072628 25.653534 2.259244 1.622464 2.494543 0.777715 2.305801 1.102553 1.107354 0.794364 0.878828 0.704716 1.657548 0.415226 0.706166 1.278052 0.973343
+1 -0.038427 1 1 0.333307 -1.140362 -0.780519 1.105220 -0.808601 0.364757 -0.340928 0.286405 2.267962 -0.879699 -2.337739 1.527033 37.418121 -63.634279 -1.335244 58.547281 4.154124 2.400480 1.617691 1.033495 1.446722 0.806484 2.072156 0.472411 1.061081 1.587037 1.086898 1.237306 2.403123 1.040222 2.005529 1.172541
+1 0.065580 1 1 0.525102 -0.919756 -1.703604 0.008658 -0.566702 -0.821171 1.169926 -1.851297 1.149123 1.946095 -0.681659 -0.829204 -60.433507 -55.956545 38.354877 -69.574162 67.055147 2.062887 2.186993 2.290916 0.672299 1.336210 1.937855 2.273782 0.710205 1.669348 0.732619 0.384301 0.696868 0.254873 1.156492 0.907998
+1 -0.025902 1 1 1.433475 -2.029344 1.084182 -0.968013 -2.234798 2.196535 0.303884 -0.855947 1.020925 0.869140 -0.775811 0.116927 4.138352 -46.716140 -58.166342 -51.711357 -12.781821 1.014064 1.122226 0.993442 1.036785 0.491218 2.154997 2.281078 1.827920 1.856785 0.989201 1.748279 2.078282 2.192709 1.608057 1.108812
+1 -0.029789 1 1 -0.274378 1.958586 1.912048 2.008529 -2.212535 -0.608792 -1.373598 -0.072428 -1.508132 0.760268 -2.170224 -1.062592 30.671958 -46.404645 -72.864153 -27.820293 -25.659777 1.166992 1.884292 2.048145 1.925170 0.577455 0.294204 0.687756 2.363761 0.973229 1.057977 1.173075 0.623451 1.584953 2.047745 1.957140
+1 0.055639 1 1 -1.736965 0.077591 -1.251673 -0.759276 -0.005110 -1.060822 -2.272607 -1.788313 -0.558572 -0.833153 -2.297281 -1.792634 70.753609 -44.098771 -18.039890 -46.434019 33.447691 0.705248 1.600834 1.224191 2.475102 0.287603 2.238741 1.264058 2.016057 0.367577 0.872787 0.422854 0.651038 1.740236 1.894179 1.717469
+1 0.035165 1 1 -1.024431 1.463510 -1.450832 -2.240420 1.958814 1.042390 -1.211164 1.488271 0.018877 1.532851 -0.004094 1.883361 16.916790 70.481627 34.712647 65.465943 36.103587 2.019729 1.344498 1.728419 1.284541 2.036786 2.266656 2.435693 1.687277 0.555512 0.483499 0.661296 0.905043 0.308328 1.825852 0.843642
+1 0.006636 1 1 1.822187 -0.326585 1.013048 0.427149 2.121998 1.061634 1.784027 -0.792504 2.315328 -1.185534 -1.297878 0.209284 63.528150 17.623905 -45.034995 -3.157989 23.675433 0.819951 1.166190 1.908505 1.746857 0.684780 1.849704 1.223069 1.626532 1.123599 1.583678 0.867366 1.568357 2.122337 2.371206 2.352334
+1 -0.041144 1 1 1.408974 0.876533 0.961707 -0.084099 0.271448 0.632108 2.107639 0.053075 1.387150 1.638793 -0.714633 1.042019 62.728504 -72.028700 63.645280 36.225000 -16.417076 0.297957 0.766281 1.380983 0.679553 1.748196 0.685437 1.642744 1.351175 1.447472 2.159006 2.169927 1.209851 2.221775 1.873013 1.486851
+1 0.021820 1 1 1.577402 -0.497738 -0.995304 0.901499 1.164478 0.822655 0.216138 -0.628768 2.191905 -2.113670 2.247176 -1.509681 -54.084134 7.955966 65.915427 -59.414831 -35.058068 1.060732 2.467513 0.987884 2.113931 0.595647 2.293906 1.427217 1.477569 1.750893 1.010393 2.428093 2.215374 2.283594 1.370197 1.656918
+1 0.018264 1 1 1.907914 -1.497061 -1.657302 0.654338 -1.260159 -2.014626 -1.301273 -0.292553 -1.922140 -1.985475 -1.458738 1.559341 71.533963 21.323790 38.946418 -27.544372 -38.260111 1.559720 0.961615 1.606872 1.448347 1.120616 0.945651 1.058642 1.098608 2.304772 1.798392 0.571236 1.509951 1.497269 2.097043 0.254383
+1 -0.048505 1 1 -0.089022 2.342385 1.173028 -1.548021 -0.480628 -0.876927 1.833361 -1.012930 1.553577 -0.385718 1.480388 -0.540026 -5.185958 -10.390048 -25.539502 57.585366 37.254059 1.809584 1.926432 1.545801 1.028346 0.411846 2.403835 1.760622 0.276343 1.990417 1.437334 0.516015 0.405855 0.707871 0.680459 1.216691
+1 -0.002427 1 1 -2.294707 -0.940151 -0.473872 -0.432920 -0.160504 -2.111467 1.567190 2.221462 -0.139573 0.969139 2.301786 2.117086 -44.142659 -5.677149 -15.850959 -7.070521 -34.246461 0.921066 1.853422 0.722511 1.498387 0.647628 0.677323 0.265873 1.523755 1.748600 0.721950 1.064012 1.355533 0.435630 1.627844 0.679744
+1 0.004866 1 1 0.038663 -0.497921 0.643099 -1.657818 1.409523 0.682011 2.023475 -0.766470 1.618328 -0.677740 -0.939012 -0.181653 18.717360 32.676642 46.320459 7.959116 -31.130967 1.102550 1.049983 1.806608 1.414013 2.319924 2.207314 1.834911 2.345607 1.860245 0.641040 2.458057 1.806594 1.177520 1.076810 0.453491
+1 0.008016 1 1 -1.640331 -1.573722 1.098816 -0.053654 -1.695167 0.438355 1.971349 -0.347009 1.759565 -1.937557 -1.905839 -1.331495 21.980956 -16.075094 -24.105531 8.337742 32.426876 2.102450 1.122792 1.508609 1.443467 2.346652 1.438337 1.631281 2.184352 0.651420 1.421269 0.520456 0.811388 1.248986 0.703139 2.150205
+1 0.034016 1 1 1.720153 0.103683 -0.988664 -0.587827 2.269516 1.672243 0.707750 1.076686 0.291527 -1.197448 1.095959 -0.936483 -3.132008 10.332835 -36.035617 49.381106 -1.757569 1.533162 2.361461 0.574358 2.228590 1.661039 0.586787 1.880071 0.861192 1.308140 0.400635 0.726459 0.340185 1.746572 0.384283 0.391786
+1 -0.018678 1 1 -1.256443 -0.826367 -1.345903 -1.122343 0.475910 1.690626 -1.357733 -2.034810 -1.243954 1.730717 -1.415825 1.786571 -14.210385 -33.943590 -39.920100 12.873912 71.845105 1.385163 1.188124 1.551288 0.998535 1.125705 0.967374 1.651349 1.967664 1.521325 1.402296 1.133172 0.478848 1.245378 0.825199 1.613668
+1 -0.006458 1 1 0.707256 2.201603 0.661295 -2.138670 1.477952 0.934602 1.456282 -0.408896 -1.651433 0.327774 0.120241 -0.729168 57.146259 7.176463 14.813948 -21.979505 40.451104 2.300507 2.124982 1.814110 1.500115 0.431434 0.868816 1.187241 2.452132 1.229068 1.202278 0.929135 2.468585 1.003163 2.403671 1.251944
+1 0.055386 1 1 1.537156 1.658478 0.251137 -1.440077 -0.543250 2.202583 -1.714376 -1.968401 -1.942736 0.574704 -1.351958 0.775943 66.695456 0.533577 -32.177676 -60.204183 48.291611 1.181693 1.459669 2.397976 2.288258 1.002164 1.370288 0.937556 2.256223 0.334618 0.419038 1.775867 2.247107 2.382401 1.504494 2.037293
+1 0.059116 1 1 -0.764028 0.247261 -0.609395 -2.082953 0.147046 2.118368 1.310440 -1.140549 0.797768 1.342259 1.148572 2.110411 -14.912286 19.212324 -48.474726 -64.717903 -63.803268 1.501995 0.534425 1.581751 2.245640 2.470603 1.175672 1.516839 0.259795 0.619121 0.819905 0.386854 0.855753 2.141183 1.857281 0.320545
+1 -0.069500 1 1 -1.242011 1.403429 1.929201 -1.861733 0.121520 1.920736 1.950027 -0.559929 -0.081932 -1.012463 -0.025307 -1.220290 -34.804428 41.980155 -39.533240 64.829356 -13.018252 2.158698 1.484243 1.422383 1.246835 0.558790 1.577055 2.059983 0.636219 2.436363 1.705928 1.273436 2.139061 2.204056 1.072445 1.337278
+1 -0.013283 1 1 -1.783469 0.744103 -0.533900 -0.871504 -1.257936 -2.349480 2.102931 1.053059 -0.977059 1.241690 -2.092911 -2.290895 59.211103 61.003516 36.101673 10.813244 -61.804069 1.510082 1.439983 2.289147 2.447502 2.173402 1.122590 0.375258 1.710346 1.282460 0.798331 2.305397 1.049663 0.943264 1.435870 0.665269
+1 -0.028996 1 1 -0.375990 0.053838 0.076052 1.151450 -1.360703 -0.106018 -0.563862 -0.207166 0.614886 0.113499 -0.934888 -1.556334 37.042016 65.155971 -73.600505 46.311475 6.952061 1.274275 0.499101 1.893464 0.945948 1.551046 1.428860 2.100675 0.538958 1.261337 1.284854 0.534490 0.425326 1.705008 1.574471 1.379280
+1 -0.061119 1 1 -0.199337 0.259253 -1.689830 0.588268 0.435139 -0.251468 0.588798 -0.083640 -1.452746 -1.422432 -0.866571 1.527794 -5.630243 22.504695 -63.594408 68.781971 -31.418537 0.604846 1.654165 2.055225 1.669659 1.464334 2.061270 2.014510 1.369848 0.286795 2.157421 0.274350 2.254602 2.336784 2.085031 0.861221
+1 0.040594 1 1 1.521593 -0.716015 1.379768 0.097518 -0.925608 -1.097852 2.120404 -2.171240 0.707457 0.878052 -1.783486 0.456137 -24.052043 7.305820 -61.075848 -51.774740 -28.060638 1.147981 1.863143 2.088605 2.440913 1.666681 0.906342 1.890852 2.053687 0.573194 0.674942 0.757702 1.198247 0.692995 0.413074 0.529803
+1 -0.010270 1 1 -0.301189 -0.981890 0.157460 -1.928846 -1.594573 -0.631433 -0.201204 1.864648 1.760634 1.891879 2.319145 1.702896 71.340972 -72.289122 36.725184 -9.830540 -71.890349 1.208516 2.278489 1.067729 0.823560 1.064804 1.152109 1.501760 1.078665 2.372112 1.841590 2.097924 1.553194 1.535701 2.278975 2.486627
+1 -0.001625 1 1 2.196314 1.305612 -2.175136 1.196806 2.249525 0.273682 0.486120 -1.061878 -1.170249 1.141531 1.572106 0.017754 47.933619 -29.662094 69.185170 -4.851449 61.703441 0.620878 1.088778 1.343149 1.561583 0.766761 0.451973 1.812802 2.020342 0.385884 0.302929 1.075831 1.990211 2.471465 2.164224 2.116948
+1 0.012677 1 1 0.997768 -1.905158 0.691962 -0.363349 0.454748 -0.540054 -0.629022 -2.091516 2.307538 -0.171836 0.640951 -0.061489 -45.716812 -62.457030 -15.306809 -11.533070 -36.299275 0.896374 0.861243 2.165168 2.229010 1.976167 0.437544 2.306097 1.564722 1.774246 1.998006 0.739271 1.931787 1.538374 2.207334 2.160331
+1 0.033528 1 1 0.609589 0.636847 1.648993 1.058487 0.723585 -1.381301 -2.294334 0.600874 0.245918 0.375798 1.443680 -0.158305 59.298644 32.310066 35.276965 -50.048684 31.771682 1.174778 2.246907 1.270022 1.009761 0.806462 1.706586 1.092327 2.486481 0.289375 0.529238 2.153713 0.949100 0.519297 1.570412 0.667372
+1 0.036461 1 1 -1.163478 1.841934 1.702129 -1.230639 -0.668389 0.722636 1.516124 1.612032 1.893886 -1.640032 -1.254524 -1.552559 -43.273394 54.070878 69.253129 -62.669162 19.389501 0.315215 0.562510 1.100445 1.687470 1.562533 0.999412 2.372181 0.743944 1.721850 1.130834 1.681126 0.677012 1.787222 1.843830 1.500441
+1 0.040530 1 1 -0.590709 0.962666 1.902657 -0.322028 2.211724 1.129938 -0.061168 -0.744209 -1.241804 0.165184 0.647928 -0.609437 61.434657 -67.711517 22.530228 65.547332 54.011667 0.986385 1.669152 1.944799 1.984306 2.240139 2.263040 2.420699 1.693878 1.260567 1.847490 2.256876 2.308682 2.271733 2.258201 2.084239
+1 -0.015054 1 1 0.595641 1.826530 1.987856 -0.947133 -0.017242 -2.326860 0.575817 -1.498732 -1.474889 -1.289354 2.110713 -0.105803 -52.725724 38.760968 5.587635 11.382518 55.979308 2.038558 0.540213 2.111805 0.862599 2.459020 2.256439 1.718655 1.439051 2.384135 1.409489 0.525666 0.620880 1.131551 2.480046 2.383570
+1 -0.026851 1 1 1.548755 -1.315343 -1.152784 -2.211630 0.462026 -0.746417 -0.651918 -0.487904 -0.646776 1.111103 -0.894480 -1.008738 42.115208 -19.702235 64.528895 37.143380 -31.217578 1.767437 2.316024 1.910595 0.876980 1.144427 0.636572 1.607782 0.999130 2.126801 0.890899 1.096731 2.264382 2.473339 2.160907 0.369223
+1 0.050033 1 1 0.484592 1.522772 0.249908 1.461891 -0.400464 -1.308112 -2.136375 2.348992 -0.886956 -1.782224 -1.898407 1.059073 36.524302 63.943025 -59.585886 -59.986769 -47.625496 0.749286 1.495662 2.098452 1.438546 0.636189 1.929514 1.588576 2.200461 1.403880 0.765419 0.392360 1.145604 2.417344 1.553500 2.181922
+1 -0.002671 1 1 -2.087598 2.191497 0.461772 -0.299046 2.060371 2.027218 0.874354 2.045871 -1.352452 1.910338 1.547149 -0.026429 -39.055897 -12.468694 -11.344836 -22.665595 59.348255 0.866907 0.608199 1.755926 2.343539 0.851557 1.366165 1.383076 2.113154 1.038434 1.212373 1.848471 0.755498 2.403533 1.183852 1.751619
+1 -0.005944 1 1 1.246152 2.221765 0.234836 -2.096602 1.661202 -1.089951 -1.758024 -0.433885 -2.247723 1.738576 -1.279577 1.488757 -39.499496 31.968378 -7.469789 5.260183 57.890220 2.288996 2.151052 1.236350 2.080118 1.549134 0.799844 0.719922 0.735643 1.700198 1.736689 0.785097 0.381921 1.199122 1.887700 0.817176
+1 -0.004472 1 1 0.320300 1.738337 -0.585399 0.670894 -1.031016 -0.835981 2.011804 1.002600 -0.810749 1.962488 1.518331 1.002193 56.781200 21.635976 35.842591 6.426048 2.586233 0.877229 0.844464 1.403654 1.465149 2.259727 0.730293 1.776161 0.434112 0.872419 0.998124 0.972900 2.276112 1.607509 0.897195 1.164106
+1 -0.010070 1 1 1.394588 -0.588059 -1.625255 2.065355 0.969546 -0.282987 -1.364123 -1.036817 0.626367 -0.133305 -2.066486 -1.129547 60.955697 -17.602274 -41.419196 17.570143 -48.612022 1.791119 2.094589 1.752712 2.327427 2.312857 0.436287 1.430728 1.999503 1.141383 1.221499 2.226658 0.698555 1.611073 2.306287 0.270571
+1 0.031554 1 1 1.106533 -2.305702 -1.957858 0.898080 0.241055 -1.250174 0.860502 0.130029 -1.155471 -0.244746 0.465135 -0.332202 27.222213 23.731327 2.407574 -35.903148 25.798066 0.446507 2.194642 0.343310 0.260837 2.380474 0.621657 0.688764 1.311579 1.962315 1.626465 2.255477 1.306037 1.057405 0.558609 0.798197
+1 0.057330 1 1 0.298475 -2.232777 -1.531325 2.082449 0.800510 0.300238 -0.866193 -1.533370 0.707425 0.331514 1.710833 -1.029536 15.502211 -4.347861 -24.503177 -74.899893 -42.496528 2.287745 1.381587 1.824711 1.920673 1.496887 2.427104 1.332920 0.642566 1.107068 0.496244 1.125513 2.244232 1.312520 2.022219 0.428844
+1 -0.021406 1 1 -2.093814 1.394417 1.250976 -1.519398 -0.079003 1.096177 -1.992169 -0.851639 -1.974605 2.175675 -1.564374 -2.013848 74.542121 29.435981 30.525186 36.796941 -3.808560 1.968004 0.492050 0.389112 0.560359 0.950690 0.254593 0.941981 2.372874 1.151550 1.104769 2.359699 2.468142 0.310579 1.399814 2.175737
+1 -0.053242 1 1 -2.173005 -0.676830 0.229135 1.049765 0.208552 -0.885733 -0.080306 -1.966609 -0.099540 -0.073710 0.513156 0.946205 -45.752557 -63.231048 25.769515 58.240338 -54.646088 1.572994 1.307819 1.768185 1.381690 1.314038 0.530056 2.406988 0.738435 1.374187 1.217916 0.517292 1.631772 1.449274 0.942407 0.526595
+1 -0.036860 1 1 1.153363 -2.196209 0.455303 -0.637063 -0.576121 1.092496 2.103800 1.518108 1.967815 1.522601 2.092078 -2.293056 -47.036343 -39.818506 70.374416 32.813217 -58.264526 0.596668 1.450730 0.665819 0.425088 2.199731 0.375246 1.510357 1.564475 2.126632 0.303913 1.865254 1.574436 0.793031 0.965442 0.689551
+1 0.005829 1 1 -0.848683 0.579704 -2.134978 2.266532 -1.348461 -1.705558 0.144350 -0.795941 1.085204 2.074900 1.166131 0.334278 33.125925 -52.575428 14.786605 -31.525516 -49.354861 1.267805 2.006200 1.211443 1.967108 1.191796 0.256179 0.608178 1.397312 0.617664 1.071187 0.443807 1.822299 1.879538 0.895313 1.032465
+1 0.001815 1 1 -0.566547 1.774359 1.657085 0.411379 0.968565 2.073801 1.541161 -1.715554 1.792707 -0.985768 0.956351 -0.573132 -15.954755 48.438815 61.160437 -26.534761 -19.725783 0.906581 1.414848 0.608417 0.911147 1.653460 1.444531 2.229791 1.594062 2.147318 1.470708 1.180590 0.932381 0.774598 1.676178 0.766700
+1 0.069293 1 1 -2.037708 1.890953 0.904191 -0.710757 0.213550 -1.709691 1.377556 0.612499 -2.300859 -0.669751 1.397956 -0.520199 -47.794646 -34.608089 41.844314 -72.613506 -15.191731 0.963553 0.428534 1.626206 2.388645 0.705613 0.989412 0.796401 1.359342 1.454651 1.323952 0.666538 1.249084 2.353362 1.701871 0.589667
+1 0.032383 1 1 0.443164 -2.022890 1.166135 0.410916 -2.090589 -0.954934 0.817842 -0.564783 -1.563774 -1.361548 -0.181827 -2.331505 -66.750438 -24.616083 -22.504862 60.776915 -22.385702 0.827538 0.434441 1.902753 1.815169 1.289413 0.666195 2.238138 2.393852 0.468933 1.114796 2.129710 0.286253 2.052569 2.032172 1.208295
+1 -0.003692 1 1 0.894906 -1.268855 -2.079417 -1.685425 -0.765655 1.169063 -2.225214 -1.654971 2.139961 1.374797 1.377618 1.666186 -68.047522 -74.710559 -10.361312 7.437484 51.798363 1.001421 2.373827 1.407006 1.543207 2.435849 2.061472 0.906067 1.770340 1.603168 2.192090 2.456683 1.217997 1.871221 0.610086 1.958691
+1 -0.064271 1 1 -1.369633 0.590714 -0.879943 -1.717654 -0.513301 1.333151 -1.144483 0.652360 -1.512676 -0.202260 -1.758733 1.784445 48.672946 -53.796275 46.002217 59.256359 71.619779 0.829276 0.386769 1.681669 0.808137 0.601756 1.457203 1.457146 0.497173 0.986502 1.382188 0.680319 1.116937 2.106841 0.673022 2.225432
+1 -0.003963 1 1 1.814677 0.698429 -0.064498 -0.175062 -1.739348 -2.265808 -0.615650 1.180154 0.397881 0.311240 0.259944 0.492769 73.011837 -40.054132 10.208483 -26.023700 19.669087 1.050101 1.543821 1.502645 2.456295 1.458937 1.346080 1.320005 1.826360 0.378462 1.556704 2.016535 1.648770 1.386383 1.441936 1.365564
+1 0.041808 1 1 1.149399 1.872437 0.717173 -0.758497 -1.055091 -0.193165 0.312520 -1.791550 1.581775 2.311276 1.388108 -1.110370 -29.804723 72.019920 -61.210299 -61.489772 41.407887 0.510444 1.288524 1.479802 1.032717 1.865701 2.336999 1.192020 1.786639 1.035785 1.686651 1.300701 1.373506 1.012870 1.312521 2.040955
+1 0.009432 1 1 1.951710 -0.544439 1.069000 -1.658825 -1.384628 -1.670973 1.802376 1.301263 0.128655 -0.688196 -2.303043 0.322174 7.724179 70.272430 -31.264959 -20.166683 58.560241 2.454635 0.553007 1.144081 1.570632 2.115120 0.316495 1.832116 0.368666 1.177228 0.672136 0.846075 1.486506 1.199698 0.325279 0.968446
+1 0.052611 1 1 0.852625 -0.306651 1.466388 -0.208746 2.334126 -0.983697 -1.928744 0.121569 -1.968065 -1.017143 1.430820 0.465157 1.549106 -64.167064 44.155673 74.394430 -52.814034 2.192885 2.313448 1.375487 0.554772 1.551293 1.088871 0.650624 1.541805 1.370496 2.183501 2.107733 2.164778 2.429167 2.257612 1.188130
+1 0.013313 1 1 0.092797 -0.159302 -0.745018 -0.705095 1.128772 -0.802781 -0.765883 2.043884 -1.760901 -1.657753 -2.205696 1.236468 -10.181292 33.018706 -54.605167 -49.048036 49.653489 0.267807 0.280509 2.267813 1.627239 1.759105 1.781219 2.195411 2.017890 1.921474 1.465824 2.349942 0.479752 0.686790 1.873678 1.413440
+1 -0.011628 1 1 0.650615 2.142892 -1.209220 1.167143 -1.504887 -1.238530 -1.346676 0.026737 1.691302 0.573412 0.497023 -1.604233 61.813477 -0.886557 -50.360097 47.843020 -52.357367 0.321087 0.263566 1.007447 2.411817 0.913153 1.617457 1.595062 0.961746 1.562617 2.400869 1.396597 2.105582 2.012998 0.710887 1.874183
+1 0.014440 1 1 0.108988 -1.365262 -1.339253 2.263365 1.965694 -1.137943 2.183180 2.043412 -0.269720 0.134093 1.171774 0.932620 36.092405 5.057539 -47.941022 55.246302 24.596718 1.330668 1.032241 0.617525 0.998446 1.882891 1.002357 2.358785 0.603525 1.949310 1.298657 0.772509 0.304455 1.979985 1.600188 1.602155
+1 -0.031586 1 1 -0.361462 -0.816875 -2.025534 -0.857427 -0.282452 -1.798039 0.911903 1.668040 0.751731 0.430625 -0.708249 -0.047328 30.329157 42.147492 72.899945 29.380861 4.131161 1.111430 1.805984 2.171846 1.959228 1.489287 0.691677 0.763705 0.843268 1.555262 0.288490 1.407242 1.024096 0.980441 0.775310 2.389658
+1 0.007898 1 1 -0.143396 -2.032443 0.845852 -1.043935 -1.197902 -1.812867 1.444719 -1.541327 -1.079022 -1.853125 -1.285974 -2.353321 -37.538717 -13.209091 -5.194478 -3.589126 -22.449158 0.580077 1.611854 1.927440 0.482949 0.415658 1.212478 1.366783 0.515080 0.447945 1.605947 1.646350 1.198739 2.202968 0.789293 1.153664
+1 -0.019640 1 1 -1.195918 -1.449523 0.909663 1.715261 -2.007864 -0.754331 -1.711664 1.194338 -1.535880 0.928656 0.481725 0.464980 56.491591 -45.834293 63.033356 -48.377886 62.873805 0.925605 1.645954 1.299315 0.580482 1.656661 1.245879 2.490046 1.708293 0.531396 2.418598 2.368610 1.471941 1.669716 2.410448 0.401403
+1 0.000330 1 1 2.120100 2.156045 -1.627005 0.927027 1.383316 -1.540591 1.864762 -1.050507 1.441924 -1.403810 1.104191 0.751448 12.463038 66.276755 13.422352 -10.537757 41.922864 2.088582 2.042871 1.036314 1.575260 1.153793 0.544760 2.027937 2.032806 0.627067 1.612343 1.147000 1.130915 0.782536 2.333042 2.180627
+1 0.048624 1 1 0.382131 -0.516867 -2.050929 1.166684 0.205846 0.762795 -2.123257 1.345060 1.087435 1.881705 0.973106 -1.712830 14.482299 -46.007739 -2.064576 -49.326695 16.228902 2.262365 2.313209 1.857636 1.790091 0.552420 0.265370 2.069269 1.447963 1.411214 0.277776 1.334331 1.851364 2.125389 1.906726 1.100017
+1 0.003915 1 1 -1.051397 0.628756 2.318487 0.075724 0.342990 1.383518 1.858574 -1.378389 -0.484430 1.197157 -1.285042 -0.816734 11.034051 49.287271 71.157806 -0.760556 -32.666667 0.944876 1.530784 0.632434 1.812689 2.358303 1.500592 1.694578 1.773389 1.091548 0.654791 1.823410 0.294848 0.253354 0.372205 2.147900
+1 0.015931 1 1 -1.362982 -0.709672 -0.396522 -1.027978 -1.602102 0.053576 0.385342 1.613674 1.218855 0.538166 1.876341 0.356539 -57.766983 60.319881 -53.758949 73.345193 12.663223 1.086912 1.486496 1.033413 2.324779 0.561067 1.598188 1.750910 1.296281 1.339072 0.533287 0.449601 2.441421 1.212295 0.550100 1.781058
+1 0.015437 1 1 0.927690 -1.608776 0.984009 -2.244821 -1.323750 -1.082782 0.931065 -1.442297 -0.154955 1.617589 1.049743 -0.161253 -17.604019 -70.741080 -45.330025 -11.731892 72.089539 2.258189 1.879619 2.252324 2.303782 0.917048 1.825689 0.353876 2.350251 1.173236 1.084548 2.248223 0.887183 1.635414 1.895977 0.441737
+1 0.041055 1 1 -1.560928 -0.647855 1.839120 1.523835 -0.734837 0.765749 0.415857 0.834624 -1.252027 -1.994964 -0.718548 1.223966 51.264229 -2.101073 -62.727778 -65.762164 -64.695777 1.496164 1.534343 1.955398 2.378679 1.963037 0.254822 0.287700 1.628328 2.055869 1.241931 1.391627 1.828380 0.582333 1.274673 0.423812
+1 -0.008652 1 1 -0.624941 0.531255 -1.169540 -1.079640 1.902549 -2.121816 2.004090 -1.413447 -0.656992 -0.938292 -2.223361 1.214768 -69.103296 30.910301 59.436371 -52.918743 -55.313309 2.113207 1.917439 1.148857 0.837924 1.742427 0.473461 0.701686 2.485361 1.710704 0.550061 1.125181 1.170368 2.382298 2.028903 0.276727
+1 -0.025256 1 1 0.944320 -0.133502 -0.670501 -1.793925 -0.638110 0.685599 1.076071 -0.616469 1.554809 1.469661 -1.751069 -1.351121 22.423316 68.672431 -72.458814 34.716788 -14.938460 1.814616 1.007940 1.694982 1.818724 0.288788 1.915248 0.324929 1.825554 0.334914 0.901246 1.745266 0.928177 2.116507 1.132077 2.313115
+1 -0.003290 1 1 -1.247981 0.024325 -1.145896 0.458066 -1.331851 -0.572686 2.274712 -0.532652 1.262732 -1.863573 2.173100 2.280632 0.544686 4.541102 -27.692889 15.606678 -48.567268 1.823893 1.672452 1.148078 1.254350 0.858739 0.577089 0.881308 1.894754 2.374883 1.165558 0.281767 0.909663 1.461040 0.696777 0.974904
+1 -0.067007 1 1 -2.078267 -1.199913 2.090988 -1.755455 0.329899 -1.873701 1.603441 -1.125772 -0.602192 1.175319 -0.754467 0.709536 -60.015627 67.356009 2.440683 70.555229 71.727050 0.872964 1.156227 0.948189 0.961030 0.781218 0.424534 1.890840 1.844277 2.266597 1.443337 2.406122 1.945276 1.002046 1.640278 0.396574
+1 0.033704 1 1 0.438575 0.960954 1.389791 -1.089423 -2.294322 0.813161 0.865637 1.620974 1.397307 -2.004532 -1.298731 0.019846 -32.926491 -45.531884 45.618037 52.345584 22.222793 1.352219 1.003165 2.438097 1.603790 1.398000 0.935691 2.405468 2.203056 2.264568 1.092497 0.855798 0.653455 1.874770 1.767716 0.256022
+1 -0.004959 1 1 0.402559 -1.182726 -1.226502 -1.832407 -1.793732 -2.092957 1.659535 -0.829203 -1.881499 -2.219760 0.475779 -0.512786 17.739785 -47.425395 21.381461 -41.784358 30.288679 0.802535 0.951144 1.125788 2.368355 1.684844 2.426278 0.949477 2.366738 1.524459 2.329746 0.790899 1.146391 2.135912 1.016727 0.886694
+1 0.012616 1 1 0.286421 -2.192162 -2.206374 -0.733623 2.313542 1.778258 1.209227 -1.054287 -0.824769 1.956160 -1.153701 1.234989 -51.569273 -24.773423 33.084317 -1.885392 -37.774240 0.300102 0.812123 2.353763 1.689342 1.512270 2.222265 1.106062 1.590195 2.403602 2.341349 2.295872 0.718379 1.791569 0.654398 1.962444
+1 -0.020785 1 1 -0.087109 1.505625 -0.491240 -0.163119 1.063155 -0.936936 1.728476 -1.385091 -0.018253 -0.479582 -2.148052 -0.704971 -47.557273 54.916120 25.232114 26.137500 -57.045706 1.867376 1.237205 0.701463 0.989328 1.634943 0.729632 1.929412 2.127935 1.959956 2.476187 0.521484 2.326210 2.110412 2.187400 2.376876
+1 -0.002587 1 1 1.762029 1.764461 0.233922 1.388963 -0.873761 -1.502480 1.509748 -1.879788 -1.746689 1.576464 -2.124093 1.423118 -55.303888 57.551023 60.038978 25.098452 29.676425 1.700006 0.744037 1.022563 2.212408 1.941863 2.134826 0.771259 1.807529 1.147176 1.834070 1.712287 2.411687 0.969506 1.489471 1.546008
+1 -0.014732 1 1 -1.222727 0.361963 -0.184970 1.380558 -0.769792 2.329650 -0.806901 0.675663 -0.991623 1.518546 -0.092475 0.863573 -2.774311 22.153686 37.003883 24.262027 71.889350 1.289530 0.375497 1.230133 1.102744 2.059522 1.894805 0.990910 1.229505 1.788695 1.840011 0.319696 1.625540 2.446912 1.241071 0.422956
+1 0.011302 1 1 0.409703 1.082158 -1.988169 0.390348 0.941850 0.760547 -2.198518 -0.646390 -1.818839 0.043782 0.706829 -0.259416 -33.380736 -30.032614 -8.149237 -14.232379 46.406033 0.567895 1.609888 0.385063 2.247707 1.204427 1.054994 0.533710 0.821765 2.406694 0.301007 0.281128 1.421599 1.564578 1.615131 0.753175
+1 -0.012566 1 1 -0.418284 0.786605 2.224257 -0.296895 0.502214 0.827913 -0.951150 -1.562280 0.194758 -1.821060 0.416550 -1.656662 63.251049 10.386741 -30.048459 25.543678 12.604252 1.970023 0.685286 1.347227 0.350004 0.260935 1.776911 1.791918 2.008197 1.019157 1.222433 2.179973 1.304913 2.415957 0.731949 0.370475
+1 0.037133 1 1 -1.593039 1.581537 -1.697567 -2.207246 -1.259785 -0.433954 1.318186 1.815472 -0.087558 -1.329256 0.633005 -1.659438 -71.810735 -23.028103 -33.320555 -68.571435 -30.100306 2.187330 1.205432 2.204722 1.005973 2.384450 2.198698 1.012111 2.054121 1.105058 0.451667 1.161915 2.049880 1.832207 1.897192 0.599172
+1 0.024808 1 1 1.727326 -1.864886 -1.044807 -1.707504 0.436969 2.241864 -1.246528 0.889040 -0.884167 -2.029352 0.959192 0.061342 -33.101379 15.123309 -72.552219 -35.148012 -32.633618 0.276801 0.699659 2.163824 2.137859 2.244567 2.433999 2.478344 0.774940 0.667665 2.190384 0.792848 2.396594 1.552447 2.470070 1.217453
+1 -0.029372 1 1 2.223906 -1.484233 1.890692 1.221041 -0.412305 2.317585 -0.955816 0.129295 0.641975 -1.695080 1.899982 1.849213 48.132951 20.515445 -46.916460 25.062259 21.394962 1.901801 1.574558 0.595275 0.534440 1.839446 2.074621 1.409244 0.919241 0.427281 0.819443 1.633677 1.959005 2.239961 1.521391 0.272337
+1 -0.014895 1 1 2.212444 -0.921986 -1.488870 -0.655650 -1.943106 -0.934419 1.604795 -1.924311 -0.770089 2.039256 0.576901 -2.128867 41.268919 6.718840 -26.455743 -41.669966 2.888333 0.538290 1.283733 1.949744 1.839941 1.387846 1.268574 1.431714 0.557961 1.158393 1.364109 0.579660 1.344271 2.418746 0.359256 0.511680
+1 0.011973 1 1 0.369732 -1.558737 -1.516892 -0.380081 1.985937 -0.206853 1.162339 -2.126150 -0.160946 -0.114981 -0.414479 -1.241009 -19.295906 -6.289684 39.278741 7.796095 -71.025449 1.004118 0.461673 0.585092 0.389372 0.418739 1.240303 1.018838 0.362047 2.423113 1.769069 0.498825 1.758688 1.517810 0.829242 2.070735
+1 -0.001108 1 1 0.808372 0.485796 -1.795359 -1.176540 -0.920048 -1.901537 0.286155 -1.945533 0.693559 -1.798827 1.795772 -1.302275 54.685535 49.781150 -28.219220 19.576943 -70.323114 0.316415 0.487097 0.396125 1.424470 0.321752 2.433763 0.762881 0.491328 1.751916 2.456204 2.172188 0.960805 1.498064 1.965043 2.484368
+1 0.030962 1 1 -1.860370 -0.539011 -1.949199 0.340506 2.038099 -0.022205 -0.915833 -1.737289 -0.658914 -0.249977 2.081743 -1.637674 21.739430 -25.399169 16.166225 55.740474 -69.853216 1.779948 1.087353 2.136923 2.258974 1.582919 1.618210 0.761472 1.552482 0.806302 1.272590 1.411532 1.119373 0.301846 0.867730 0.938216
+1 0.011590 1 1 0.124827 0.956521 2.293067 1.662722 0.897898 1.897861 -0.806021 1.327293 -0.640116 -0.050979 0.845760 2.131184 -1.843212 71.138678 -22.232978 -19.660431 17.132978 0.684389 2.022953 1.527599 1.106020 0.876277 0.592337 0.651661 0.960163 1.957366 1.694072 2.268029 0.762404 1.470560 0.946653 2.153411
+1 0.019665 1 1 2.119077 -0.906342 2.267070 -1.732772 -0.141722 -2.163739 -0.455528 1.565104 0.140501 0.499772 2.184301 2.033945 27.046131 64.323622 37.117413 -17.640190 71.328470 1.638892 1.863023 2.335931 1.249380 0.581995 2.341384 0.648005 0.275416 2.170440 0.840272 0.709005 1.752491 0.863390 2.246458 0.469317
+1 0.029860 1 1 0.455505 -1.967327 1.974808 1.236066 2.347421 0.984381 -0.703058 -2.343983 0.254226 -1.361884 -1.113284 1.927638 4.222034 9.728200 1.859045 44.978225 -50.971905 0.852834 0.322641 1.634614 1.951482 1.811410 1.125307 1.033259 1.987616 1.614440 0.396830 2.026800 0.930609 0.250848 0.994505 0.890146
+1 -0.056998 1 1 -0.778263 1.328373 -1.331068 -1.548131 -2.334040 -2.290669 0.938659 -1.030505 -1.673227 1.617284 0.631483 1.026930 -59.422795 -18.908940 47.450171 -54.968919 -12.621470 0.939188 0.439165 0.300390 1.160764 0.716384 2.021081 1.558563 1.760982 1.819671 0.464861 2.415901 2.046295 2.330596 1.572313 1.118745
+1 0.024924 1 1 -1.798408 -0.576493 -0.444620 1.115430 1.153128 -1.441620 1.799941 -1.927979 -1.149181 1.796769 1.316066 -0.832902 61.233307 -1.814019 -38.218406 -36.756495 -66.406702 2.163301 2.347598 1.578205 1.138125 0.475498 1.190952 1.827428 0.332759 0.686883 1.185063 1.846788 1.718468 0.534709 1.861117 1.801530
+1 0.072139 1 1 -2.085560 -1.252933 1.617839 0.541702 0.049734 1.782034 -1.290573 0.458658 -0.795873 2.227811 -1.825947 -1.621309 -73.399037 -17.606735 33.607317 -61.825154 -45.356522 1.269063 0.639176 0.381392 1.298345 2.276231 1.368547 0.919739 2.051980 1.125215 1.737054 2.421808 2.332369 2.121492 1.666692 1.087401
+1 0.002172 1 1 0.659284 1.762973 -1.214544 1.220960 -1.784164 -1.504660 -2.139426 -1.797871 -0.974045 0.072755 2.283621 -1.594947 -70.128234 54.767898 -65.932918 65.443488 -41.301940 1.949512 2.446571 2.264569 1.111252 1.053223 2.272709 0.665149 0.411209 0.686973 0.450029 0.629515 2.251895 1.858046 1.930798 0.669146
+1 -0.020916 1 1 -1.908230 0.901699 -0.191455 0.780354 0.824801 -1.424190 -2.139995 -1.936346 -0.408573 -0.943474 0.220264 -1.959819 29.475657 -52.636457 39.074781 29.844012 -11.693493 0.887073 2.031010 1.937841 2.049880 1.828509 0.495587 1.325658 2.329598 0.548246 2.117209 1.685523 0.336948 1.334990 1.675379 0.847175
+1 -0.007211 1 1 -2.134536 0.264993 0.535770 -0.683770 1.388199 0.422105 2.165224 1.849522 1.989632 0.632955 2.206166 1.949261 22.242258 25.625100 31.062918 74.461980 32.497091 1.804159 0.752396 2.020968 1.917127 0.398917 1.092331 0.308891 2.276991 0.639679 2.084733 0.361580 1.329689 0.327201 1.773732 2.363465
+1 -0.032494 1 1 0.285604 -1.786343 -0.430417 -0.503368 -1.373984 -1.835034 1.169563 1.474708 -1.748046 2.330157 -1.720342 1.425922 -55.466701 21.156102 70.598846 54.797623 -16.351507 1.078417 0.456854 0.595553 0.711708 2.169121 1.166621 2.393598 0.703760 1.341587 2.308148 2.295270 1.860552 1.304342 1.830335 1.939214
+1 0.009278 1 1 -0.061094 0.489568 0.330375 1.413229 1.698146 -2.200372 1.183868 1.565155 0.997023 -0.284408 -1.689270 0.576233 24.994380 -69.454885 -28.257542 -24.512507 68.287842 2.331477 0.630581 2.169037 2.012576 0.363059 1.425662 2.351908 2.015332 1.681463 1.841687 1.483285 1.064600 2.234702 0.881954 1.497912
+1 0.030129 1 1 -0.683116 -1.744409 2.197563 -1.267083 -0.577295 0.203949 1.862774 -1.471238 -1.193507 1.362595 -1.075284 -0.280530 70.939081 73.137844 -22.252698 -51.087995 -35.927304 2.421960 0.382041 0.969229 1.329655 2.012717 0.479224 0.823996 1.647980 1.606342 1.532267 0.819888 2.349716 1.181613 2.365319 2.421916
+1 0.045077 1 1 -2.005800 0.955055 1.215254 1.281581 -0.797173 -0.772351 1.721504 -0.759324 -0.817522 1.227527 0.205934 2.240280 12.714258 -61.463554 32.054391 -61.858775 -10.430557 2.029517 1.590935 1.344841 0.741266 1.707734 2.381817 0.693509 2.298179 1.242400 0.258842 0.362239 1.158705 2.101635 0.923437 1.198865
+1 -0.005792 1 1 1.547783 1.198410 0.927013 1.144623 1.698871 0.556389 1.853956 1.114127 -1.893210 -1.123620 -2.134643 -1.523287 16.413376 9.605524 40.048240 40.764858 -65.032786 2.034542 0.542098 2.297930 1.552805 1.746053 0.671274 2.102046 1.092829 1.934470 1.630764 2.498655 2.395677 1.890302 1.812698 0.264075
+1 0.048424 1 1 -2.152793 -0.269154 0.224807 -1.002675 -0.449249 -1.288588 0.836792 2.187590 0.761332 1.574496 -2.220567 1.050734 -74.947583 55.970169 40.622773 -53.050576 -21.022623 2.466709 0.977283 1.699678 1.983883 1.875705 1.724218 0.431144 0.494518 1.360865 2.307245 0.612981 1.119365 2.412573 2.369906 0.752606
+1 -0.009714 1 1 -0.371895 -1.803835 -2.264635 0.252465 2.024674 0.534590 -1.674182 -0.301279 2.230442 -0.014340 -0.681334 -0.071603 -56.376239 34.547659 -7.497689 -13.651644 56.813185 0.762958 1.783078 1.945387 0.620238 1.585112 2.476107 1.430727 1.975994 2.034752 1.822012 1.556325 2.398966 0.912417 0.496021 1.880677
+1 0.029654 1 1 -2.044146 2.072698 1.858767 1.869047 0.294630 -0.877096 -0.995625 0.223708 -0.622813 -1.408398 -0.610560 1.894646 54.164340 -9.935863 -42.055418 -25.406039 50.700669 1.017053 1.863795 1.797103 1.414946 2.250029 1.988361 0.642211 1.894302 1.538907 2.159231 1.443747 0.310529 0.568900 0.506076 2.119360
+1 0.044354 1 1 0.777563 1.054410 -1.833465 -0.730062 0.916339 0.821487 -0.562578 -2.191463 0.110398 -1.221900 0.111892 0.320243 24.806616 74.800415 20.576264 -74.725328 41.418735 0.995191 1.176106 2.069622 0.637027 0.256360 1.393340 1.362891 0.367776 1.960811 1.104875 1.877007 1.108003 0.448608 1.500029 1.243069
+1 -0.007235 1 1 2.234788 2.345464 1.088245 1.343262 -0.849438 2.030691 -2.011288 -1.748012 -1.802870 -0.178854 0.502324 -2.049209 57.235978 15.077550 58.379040 26.524086 -9.686298 0.660934 1.572358 1.863232 1.347021 1.376510 2.008454 0.839518 1.534355 2.152464 2.467300 1.916148 1.950481 0.733546 2.465900 0.877544
+1 0.028673 1 1 0.762683 0.720451 -2.220568 1.038120 -2.288214 -0.206807 1.943735 2.073142 -0.114005 1.865848 -1.642249 -0.824996 -59.153345 9.723759 -72.778690 58.554040 -32.248083 0.722137 1.952946 1.663530 1.945610 2.124230 0.434804 1.247148 1.323680 0.592708 2.388586 1.969103 0.966985 1.873341 2.489538 2.160759
+1 -0.007012 1 1 -2.193429 0.053756 -1.307719 -0.251952 1.882888 2.000656 2.137526 -1.850240 0.077672 0.093816 -1.882771 -0.036380 37.349903 -10.186028 -46.568425 24.473426 24.870030 0.483954 1.568097 2.262584 1.496711 1.729355 1.262896 0.498297 1.880768 1.312452 0.875957 1.957086 1.499248 1.616211 0.908765 2.119297
+1 0.015188 1 1 -0.841461 -0.564024 1.779688 1.679501 0.165734 0.462810 -1.705302 -0.263338 -0.988705 -1.282294 -1.766885 1.445026 -34.769250 33.209916 9.057795 -15.634468 31.492681 0.587388 0.726751 0.755724 1.711322 1.941415 1.364744 2.247340 1.788520 1.152828 2.325686 2.298456 1.398289 1.293049 1.018301 0.340223
+1 0.050006 1 1 -2.007715 1.750288 2.353858 0.784528 0.297753 -0.221828 -0.756207 -0.256337 -1.138523 1.850342 1.646879 -1.474671 -74.339669 73.183320 -7.946694 -60.081067 17.506554 0.364760 0.776808 0.555628 2.435475 0.283921 1.117353 2.352394 1.185727 1.759044 0.745931 1.363720 0.784659 2.014723 0.450124 2.240856
+1 -0.041152 1 1 1.735512 -0.932976 2.304985 -0.673324 -2.104585 -0.562284 -1.968266 0.320091 -1.776818 -0.576566 -1.679946 1.783582 36.665151 31.186500 51.501335 -67.061373 -0.492584 0.942088 1.928870 2.015582 1.388807 1.682179 0.387121 0.839758 1.059601 1.470355 2.013204 1.914024 2.246876 0.743820 1.882344 0.810427
+1 0.039940 1 1 -1.241656 -2.050516 -1.321351 1.548325 0.890147 -1.133359 -0.889326 0.797909 -1.008683 2.246733 0.476036 -0.895911 -47.771037 62.186484 -31.758164 -59.459814 -41.098252 1.550152 2.154421 1.595136 2.200932 0.315418 1.730657 0.650573 0.672926 0.611026 2.008434 0.499412 0.362464 0.439780 1.637842 2.216696
+1 0.001038 1 1 -0.340240 -2.283990 0.094638 -2.203063 -1.642075 2.115297 1.528069 -0.266100 -0.292516 -1.293100 0.410843 1.389314 10.132875 53.234159 -43.493908 -52.107458 -70.052736 0.979969 1.834294 0.987340 1.979567 1.324470 0.359930 0.589358 2.333262 1.377371 0.730366 0.757405 0.708943 0.701707 0.586878 1.164689
+1 -0.045365 1 1 -0.265531 -0.151938 0.486568 1.754599 -0.585575 -2.296285 0.808373 0.507113 -1.659447 2.310045 -0.449864 -2.186810 -57.129955 -33.160014 -70.352369 37.739932 -54.964707 2.247661 0.446275 0.542150 0.912741 1.445510 0.695255 2.396189 1.498589 1.778179 0.602800 1.012262 2.331676 1.727005 2.273989 1.941957
+1 -0.021296 1 1 1.508411 -0.797856 1.891242 1.048500 -2.194361 -1.471324 2.066217 1.313589 -0.050012 -1.747950 -0.768214 0.580352 -21.254216 -69.608196 -54.952268 -32.770463 26.828532 1.482087 1.187787 0.378565 1.048742 1.203762 1.126115 1.119985 1.587051 1.310272 2.490202 2.073525 0.988299 2.348444 2.291418 2.357310
+1 -0.020797 1 1 -0.681551 0.985631 1.454191 2.137780 -2.302516 -0.252627 -0.043942 1.306284 -0.302189 1.058460 0.262537 1.663423 -46.350846 -68.668451 -10.657426 -19.356206 30.241672 2.451807 0.274649 0.518894 1.545345 2.370118 2.081544 0.756382 1.518133 1.760259 0.923248 0.277654 1.528723 2.004002 0.254106 1.761602
+1 -0.024614 1 1 0.922496 0.626730 1.260123 1.413688 -0.002740 1.078958 0.766429 -2.299813 -1.938810 0.584906 0.477885 1.895345 -21.853387 60.116779 -17.294860 25.282910 -20.136315 0.909395 1.448015 2.286240 0.827295 0.848478 1.364701 1.533176 0.333814 0.411572 2.292498 0.255275 1.153577 1.424774 0.934022 1.363894
+1 0.045878 1 1 1.095792 0.960270 -0.668113 0.641676 -2.007049 -1.191130 -1.092512 2.337883 0.897628 2.070396 0.871441 0.209818 48.926097 0.913891 59.765234 74.282758 20.308352 2.462158 0.991947 0.656579 0.375775 1.406009 0.551576 1.842676 2.354098 0.576053 1.473815 1.665219 1.083401 0.976307 1.048259 2.088361
+1 -0.003880 1 1 -1.634754 -2.078377 1.660281 2.282979 1.755812 0.950637 2.351285 -0.042581 0.628788 -1.850720 1.435454 -1.753150 43.910189 -1.458871 -69.241058 -34.453737 -63.960807 2.285734 1.338224 2.032355 2.034047 1.222007 1.764190 1.746662 1.899883 0.829073 1.484928 1.690523 1.126370 0.900813 1.218720 0.531380
+1 0.022304 1 1 -0.348165 1.178495 0.792766 2.086554 -0.882422 -0.975259 -1.491782 2.249379 -2.180741 1.241040 1.133190 -1.953822 -62.611414 -60.035837 27.683757 -19.102519 -56.033358 0.585272 1.159900 1.941539 1.197364 1.597378 1.631572 0.328883 0.785863 1.994815 1.111797 1.230801 1.079784 0.923912 2.435771 0.755581
+1 0.056380 1 1 0.324054 -1.152807 2.117567 1.981212 0.482114 2.293934 2.096385 -0.580548 2.083917 1.912180 -0.488757 -0.840788 42.309997 -45.886973 -72.348536 -61.851835 -43.795741 0.999754 1.365869 0.912631 1.845052 1.782164 2.329414 1.970047 1.075332 0.361744 1.830248 0.486884 1.314105 1.670366 2.094258 0.689484
+1 -0.002048 1 1 1.896252 0.416213 2.099817 0.546347 -1.997741 -0.265772 0.509121 -0.901182 -0.549937 -1.802982 -2.052478 -1.301170 45.534934 5.635681 68.898298 -26.308536 32.435147 1.937676 1.524913 0.968233 0.350016 0.468320 2.048106 1.260646 0.934055 1.918606 0.507692 2.279974 1.281896 0.331943 0.457979 1.504400
+1 0.004491 1 1 2.041504 0.648326 1.370877 1.455672 -1.247850 2.225856 -1.686937 2.100323 -0.378417 1.664298 -0.879246 0.571347 -39.074390 -23.266340 12.627537 -18.978475 -71.230636 1.025529 0.313843 2.251207 1.532183 1.644306 0.610068 1.666570 1.285139 0.836854 1.755006 0.392478 0.872533 0.665322 1.074479 1.767271
+1 -0.042328 1 1 -0.584330 -0.214457 0.602360 1.659568 -0.265184 0.980778 0.005394 1.118867 -2.353626 -1.597020 0.646288 0.097349 30.205811 69.057323 -53.573694 36.929633 -23.658421 1.718749 0.759610 1.762655 0.696421 1.755552 0.569440 0.571007 2.170166 0.730343 0.380460 1.388684 1.854771 0.891249 2.479850 1.344534
+1 -0.012472 1 1 0.136698 -2.170324 1.961315 0.666628 -2.036812 -1.913705 -1.579271 2.070936 0.522757 2.082331 -1.172802 0.633147 23.013619 -60.104964 65.862371 -51.137257 36.128918 1.655912 2.160596 1.887138 0.380476 1.662280 1.185654 0.531004 0.335825 0.454811 2.263134 1.741117 0.954718 0.446604 1.571673 1.615625
+1 0.028833 1 1 0.083951 1.956091 -2.321387 -1.676846 2.055067 -2.294853 1.305607 -2.258967 1.265643 -0.063774 -2.137882 0.580695 12.064788 -27.112072 27.410837 43.932113 67.022247 0.518504 1.754888 0.648256 2.241812 1.134385 0.601664 2.163041 2.472701 0.428091 0.918848 0.574328 1.735458 0.346546 0.651041 1.793909
+1 0.021192 1 1 2.074944 1.907916 -1.458631 -1.363366 2.260064 -1.668075 -1.338580 -0.568627 -0.195996 -0.145405 1.910986 -1.694368 -8.989926 -43.687082 1.207388 42.567294 -71.490815 0.683202 2.319451 1.010012 0.524865 0.659973 1.166483 2.334275 0.414381 2.256970 1.643047 1.932911 2.432922 2.372958 0.307761 1.288392
+1 0.067326 1 1 -1.018730 -1.678836 1.592809 -0.743560 0.247471 -1.799732 0.724180 -0.809291 -1.791509 2.279488 -0.365945 -0.772592 -73.864831 -46.215119 -37.497037 -62.702867 52.917286 1.837281 1.680907 1.496204 2.197387 1.488156 1.944872 0.958225 0.895600 1.345747 2.462930 0.465534 2.473962 1.372752 1.836758 1.897813
+1 0.005936 1 1 1.654504 -0.563217 1.207167 2.020338 -1.648149 -1.026677 1.399461 1.211144 -1.829088 2.145522 0.593462 -1.814272 44.744619 72.807082 -31.376393 56.960066 27.821107 1.965081 0.859200 1.570440 1.132364 0.383494 0.625532 0.574499 2.358526 0.750111 1.870424 0.715988 2.115951 0.795028 0.792069 0.555941
+1 -0.006110 1 1 -0.833195 1.710056 0.055113 -2.051085 -1.454073 -0.148645 -0.717815 -0.607632 -0.727876 -0.042503 1.926811 0.375666 -24.910876 -27.095535 5.348297 38.825552 41.049093 2.306542 2.298846 1.197798 2.138363 1.715588 1.641099 0.694224 0.824242 1.292847 2.130671 0.688817 2.191042 0.593760 2.068830 0.823439
+1 0.003149 1 1 0.332106 2.237074 -1.650120 -1.162282 -1.619369 2.020709 -0.124753 0.281866 1.363041 1.709033 1.713377 -0.680661 57.390217 57.369447 8.294986 63.829999 -9.212407 0.881140 1.319266 0.655301 1.398731 1.973165 1.732462 1.737153 1.828864 1.966523 0.358446 0.397836 0.929469 1.328196 2.232232 2.124296
+1 0.026713 1 1 -0.930388 -1.317446 1.209598 0.462691 1.013564 -0.320181 0.262526 1.471716 -0.199939 -0.444164 -0.633511 -2.135379 7.764092 -8.900112 -34.176503 -54.481388 -68.694605 1.371571 2.247364 2.201177 2.180014 1.999706 2.314637 1.100032 1.494587 2.016258 1.500717 1.554387 1.335703 2.407490 2.431405 1.616969
+1 -0.015948 1 1 0.223112 -1.215883 2.291864 0.299629 -1.683867 1.859975 -1.381408 0.620443 -0.734296 0.439083 0.064403 -1.421069 -48.494136 59.052807 -49.464666 -52.640567 -30.014842 1.233368 1.459648 2.062554 1.091734 1.519265 0.542934 0.599295 0.603415 2.346456 0.385003 1.240506 2.178973 0.250363 1.857620 1.524489
+1 -0.012534 1 1 -2.309809 -0.294915 0.790579 -1.669021 1.619219 0.167994 0.747887 1.786934 0.940246 2.077269 -1.426873 -0.115724 39.382904 -41.538235 -33.117502 44.146230 65.686227 1.201277 2.104881 1.480982 0.620402 2.104214 1.531694 2.439010 1.189721 1.390391 1.304441 1.241300 2.026494 0.278841 1.232384 0.685229
+1 -0.020976 1 1 -0.385498 0.467005 -1.887771 0.739005 -1.393150 1.190256 0.539354 -1.719135 -1.843527 -0.200744 0.163062 -2.024935 -6.542295 -6.357924 -57.632238 74.978439 12.616407 0.534241 0.734904 0.532098 0.728242 1.070370 2.467598 2.423520 1.846753 1.124628 0.874843 1.234987 1.670132 0.415352 0.568880 2.423770
+1 0.034821 1 1 1.077186 -0.731414 1.740806 -1.503162 -0.528610 -1.491590 0.759274 -0.029300 -2.354512 -2.344430 2.162603 0.220069 -16.818038 -60.769326 -0.055827 -38.285606 33.827984 2.078862 0.686691 2.469282 1.469249 1.419828 1.052678 2.114554 2.051980 1.125954 0.667375 1.826511 0.674806 0.717996 2.108335 1.033117
+1 -0.011183 1 1 1.051711 -0.067914 -1.032247 2.039986 -1.304966 -1.102635 1.838113 -1.264194 0.848310 -2.139133 -1.588283 1.415393 11.897691 14.490801 -53.103323 -7.552644 -37.286874 1.667729 0.514211 1.599492 1.169332 0.717110 0.714838 0.786312 0.549148 1.527963 0.467602 1.241772 0.954919 1.569742 0.647981 2.114872
+1 0.028809 1 1 -1.731207 -2.107327 0.477119 -1.551863 0.910349 -0.898876 0.513215 1.937675 -0.823058 -2.279212 0.298262 -1.084263 -12.675179 -31.737755 -16.451181 -44.995965 52.814237 0.608323 1.588299 2.050136 1.643041 1.844741 1.061085 1.662300 1.520037 2.265887 0.762117 1.146360 1.626544 1.327093 1.697707 0.361348
+1 0.027256 1 1 0.290973 -1.080856 0.320015 1.658902 -2.047182 -1.839381 -1.199203 -0.123728 -1.334944 -0.721432 -0.132489 2.225811 71.746340 -9.262502 25.135149 46.457324 58.251916 1.224214 0.610500 2.168673 0.389424 1.301829 2.339512 0.684269 2.264345 1.847539 0.833598 1.039857 0.378732 1.597587 0.635829 0.373524
+1 0.008575 1 1 1.316772 1.611072 -0.101610 -1.868660 1.508508 0.838475 2.214438 -0.379659 -0.360991 -2.334684 1.035047 -2.100385 -21.128232 -52.198863 43.708068 51.499291 48.585171 0.939449 0.315366 0.851546 1.188328 0.482801 2.432320 1.246149 0.275629 1.243620 0.522445 0.480288 0.701446 0.708618 1.986211 0.494640
+1 -0.000489 1 1 0.088245 -1.274185 -2.136501 0.230664 -1.527547 -0.382131 0.516093 -1.541295 -0.543290 1.529949 -1.649251 -0.695425 -41.005119 -73.038001 50.319792 24.742458 46.489520 1.365342 1.052004 2.022436 1.838838 0.853232 0.275827 2.323052 0.775974 2.301614 0.471368 1.534620 2.101585 2.338913 1.857400 2.324839
+1 0.000956 1 1 0.119649 -1.248476 1.139321 2.128283 -1.698159 1.986499 -0.183114 -0.411861 0.359603 -2.152885 -1.818262 0.310971 14.531652 33.476268 -14.357992 35.230403 67.380914 0.940428 1.031164 0.526914 1.341727 2.397565 2.130329 1.686535 1.593864 1.065914 1.819655 2.446724 0.332626 0.691253 0.383088 0.567184
+1 0.074410 1 1 -1.724377 -0.419437 0.250308 -1.233378 0.419734 0.014749 -1.877328 1.909522 1.972958 -1.579864 1.538942 -1.306606 -12.383087 -72.546286 64.575977 -71.560208 -12.417571 0.593361 2.115486 1.971361 0.667347 1.356483 0.659864 1.579161 1.457362 1.881140 0.822674 1.940008 2.464849 1.215297 1.502594 1.593879
+1 -0.025659 1 1 0.650695 -1.229614 -2.303233 1.833264 2.073196 0.805399 -2.349287 0.643622 -2.289895 -0.187997 2.348565 1.366811 -28.666938 -5.232918 -49.643778 -62.976805 -51.153787 2.249615 1.782553 2.111279 1.013418 1.510420 0.385897 0.518291 0.416916 2.109664 0.876470 1.586680 1.826358 0.340426 1.283053 1.774669
+1 0.015991 1 1 0.113858 0.382934 -1.150831 2.333350 0.114008 -1.807281 1.086223 0.359655 -1.268739 -0.143502 0.906565 1.491425 37.823641 1.928085 5.318079 -19.040463 -63.060868 1.914952 2.091347 1.271274 1.795111 1.674042 0.867033 0.475017 2.110329 0.804046 1.599363 1.252786 1.571600 0.388114 1.775567 1.709500
+1 0.007132 1 1 1.290895 0.229385 0.545080 0.277878 0.318772 -0.387078 2.186651 -0.878927 1.213806 0.497524 2.113207 -0.599473 -7.953237 -20.059556 59.046230 -10.018393 70.871680 1.229873 1.232865 2.008015 2.457440 0.449138 1.411002 1.215391 0.825653 2.498722 1.269628 1.130711 1.859722 0.853508 0.415498 0.778076
+1 -0.019027 1 1 -2.100869 0.626896 -0.653633 -1.027434 -1.893990 -0.108749 0.654635 -0.980645 2.239251 1.957673 0.709565 -1.398508 21.368537 41.001024 4.208996 -59.397617 -45.748502 1.448879 1.062617 0.399534 2.469404 1.274874 1.563151 2.374073 1.041641 1.114763 1.577341 2.362241 2.440139 2.173161 1.562213 2.367120
+1 0.020216 1 1 -0.943223 -0.276454 0.051776 -1.588745 -1.637933 1.034704 1.549214 1.681851 1.953780 1.259288 1.515609 -2.333038 13.495297 15.455553 -38.525408 53.468910 1.972930 1.510490 1.553167 1.070357 2.239399 1.077578 2.095670 1.918744 0.580926 2.377772 2.454974 1.747654 0.564103 0.881984 2.000060 1.512083
+1 -0.044090 1 1 1.899535 -0.954430 -0.132111 -0.862608 2.165525 2.197081 0.057175 -0.387800 -0.516891 2.263442 -1.452507 -2.115652 61.446945 -11.189285 41.683750 -71.210585 13.692863 1.914297 2.344285 2.144789 1.716537 1.843497 0.405112 1.713011 1.082270 2.213865 1.680279 2.191259 1.989208 1.370938 0.604267 0.917121
+1 -0.055048 1 1 2.146191 -2.309341 -1.867419 -1.193639 -0.851218 0.398417 -0.115927 -2.167188 -1.878392 -1.849471 -1.134364 1.069665 2.888822 -47.563004 -41.406919 73.904542 -36.365416 2.221835 0.625759 2.134419 0.677252 1.326785 1.027220 1.737380 1.152131 1.872947 0.369997 1.032432 1.585384 0.299268 0.294744 0.755998
+1 0.018478 1 1 -2.096103 0.613366 -1.865093 0.196942 1.911539 -1.840245 -1.584664 0.977204 1.194072 -1.292091 -1.488917 -1.439295 -49.089369 -45.026395 -8.618254 53.008197 58.768627 0.989661 0.486066 1.055970 1.196065 2.258462 1.970248 2.208684 2.344865 0.644441 1.126890 0.639990 0.555055 1.802414 0.674883 2.012247
+1 -0.001177 1 1 0.535944 2.235758 -0.200596 -2.061747 -1.590111 -1.037850 2.122281 1.098841 0.367637 0.925647 1.755918 -1.984905 -41.022691 -68.373480 -3.076689 40.084372 48.043763 1.697853 0.558394 1.673158 1.763651 1.675145 1.410028 0.594736 0.472291 1.300324 1.799854 0.400815 1.501425 2.194912 0.381851 2.267447
+1 -0.034941 1 1 -1.822612 -2.102864 0.087188 -0.183150 -1.007266 -2.213606 0.239493 0.784250 0.337923 1.035659 -1.249297 1.471636 -48.945971 -34.935896 -67.602285 58.391014 -72.221220 1.044384 2.207134 1.050506 1.606308 0.964948 1.375816 1.592220 0.436187 2.000622 1.953677 0.457854 1.651053 1.501885 0.932628 0.425699
+1 -0.005827 1 1 -0.375556 -2.080509 -1.185590 -2.231739 1.772225 -1.219766 -1.708230 -2.353611 -1.350619 -0.277517 1.035857 2.087133 -18.255704 -73.625115 -67.308228 50.617588 -70.190310 2.296895 2.161760 1.193180 1.034377 0.516048 0.969671 2.005897 0.615672 1.351519 0.488600 0.893996 1.394789 0.968956 1.238674 0.637156
+1 0.016337 1 1 0.559728 1.427132 -0.252906 -0.023283 -0.185861 0.546736 -0.163144 0.646253 -0.480574 0.019942 0.588970 -1.907223 -32.461904 -37.225885 -5.453831 -12.543009 -60.358237 1.511643 0.681055 2.246701 2.310317 0.493979 1.306746 1.725893 1.589274 0.435971 0.613943 1.539661 1.332790 0.694252 1.299677 2.167517
+1 0.021910 1 1 -0.773400 -1.760293 -0.860068 -2.269649 0.789636 1.330970 -0.098232 -1.656706 1.246485 -1.607296 2.305310 0.080073 -62.229919 51.755136 -1.421682 -44.208425 -61.001932 1.232837 1.540170 0.891541 0.624188 0.473416 2.205473 2.383413 0.515654 1.094583 2.150163 2.037789 1.116320 0.743609 0.581616 0.477284
+1 0.017615 1 1 1.956959 -1.867770 2.320238 1.216080 1.034645 0.559625 -0.306455 0.059376 -1.098508 0.523584 1.847381 -0.995132 -29.256899 -20.699619 -48.498672 -17.188551 12.018359 0.513291 1.882900 1.153568 1.267505 1.465054 0.663846 1.011259 1.228208 2.491724 0.655463 1.866221 2.069924 1.212546 0.267922 2.217764
+1 0.054718 1 1 0.874352 2.003716 1.721478 -1.185151 0.429838 0.195278 2.211418 0.682726 -0.084840 1.946708 0.196389 2.032483 -5.057037 56.386457 -12.819117 -50.893538 -67.687156 1.104648 0.315344 0.489234 0.310848 1.428916 0.797775 1.952852 2.333797 1.371918 1.328958 1.552300 2.262195 1.709318 2.004536 2.492648
+1 0.018287 1 1 1.168634 -0.009840 -0.447424 1.116562 1.325373 0.086260 -1.650511 1.691095 1.813354 2.017395 0.714730 0.594792 54.057833 -0.000650 -10.919546 -74.810462 -39.435660 2.198045 1.297468 1.040039 1.182630 1.464631 0.305082 1.271564 2.174709 0.584384 1.995625 1.211906 0.759854 1.360716 2.059009 2.264472
+1 -0.002907 1 1 -0.473397 -1.873869 -1.224439 -0.142973 0.370047 -0.980672 1.786944 1.112111 1.917485 -0.857610 1.343301 -0.198490 10.933008 1.069232 -29.416679 -6.126093 -61.247301 2.374163 0.311643 1.292056 2.342793 1.826938 1.095537 2.441013 1.105874 0.667539 2.332160 0.866936 1.090730 0.402485 0.311876 0.696116
+1 -0.017698 1 1 -0.033545 1.693303 1.231877 -2.086129 -1.392847 1.570824 2.029601 -1.482797 -2.248710 -0.703326 -2.136780 0.261244 -38.570028 53.533294 34.075701 10.311148 49.464148 2.034035 1.031650 1.936338 1.536213 1.882049 0.347941 1.600119 0.447846 2.189294 0.463982 1.150759 1.302100 2.391401 2.028578 1.559083
+1 -0.009431 1 1 0.364994 -1.072836 -1.549547 2.132310 0.022432 0.029763 0.712082 -1.504228 0.409665 0.441021 -0.352542 -1.696868 3.896017 -69.639314 22.044736 5.883529 34.468857 1.646286 2.384554 1.700879 1.922312 2.045963 1.249230 0.313121 1.377728 2.230886 2.003032 1.965299 2.280428 2.158022 1.377123 1.051302
+1 -0.012903 1 1 -2.284832 0.077655 -0.187733 2.078111 -1.407825 -0.405773 -1.003726 0.730964 0.115717 -1.354569 -0.682272 -1.695266 -39.056677 -25.573558 -64.794193 4.002656 72.634856 2.485397 2.315056 1.398061 1.968161 0.883556 1.418371 1.307271 1.561991 0.889577 1.373316 2.315949 0.658167 2.312241 1.330434 1.596573
+1 0.038338 1 1 -1.048470 -2.007854 -0.591649 -0.707061 1.076887 -1.037630 1.099641 -0.324231 -1.826174 -0.712152 0.334034 1.652099 45.771685 -65.283616 28.261599 -57.299468 -32.154866 1.722476 0.396510 1.148453 0.794526 1.350790 1.725321 0.966075 2.314546 1.821543 0.414562 0.796833 1.879953 1.112921 2.106613 1.343943
+1 -0.006752 1 1 2.109199 -1.988873 -2.019031 0.057003 1.430840 0.812317 0.827152 0.401106 -2.035455 2.045029 -1.363165 0.916450 -64.399798 32.592667 -15.047450 -2.488792 20.871258 0.373431 0.253177 1.897830 2.336321 1.048326 0.956589 0.385088 0.426071 0.727954 0.728896 0.810706 1.037354 1.059319 1.217509 0.423109
+1 -0.056250 1 1 0.144286 -1.865598 1.130115 -1.794723 0.083336 1.049681 -1.189603 1.010775 -0.069771 0.735940 -1.070152 1.138535 -52.875831 65.906184 -64.764347 55.616184 -58.794131 2.080609 0.788699 2.408396 1.914004 1.915944 0.767102 1.677999 2.133586 2.431233 0.978529 2.378755 0.982722 0.860383 1.211429 1.741867
+1 0.006346 1 1 0.431206 -0.370728 -1.039541 1.978114 0.252599 -0.432559 1.199657 -1.680608 0.073906 -1.924631 -1.440467 2.321154 -71.152840 -65.777086 -15.476127 -7.267848 -50.716218 2.312740 0.719853 1.824924 0.995261 2.355861 0.957344 1.838900 1.885896 2.009475 2.239598 2.170269 2.457097 1.424387 1.168834 1.344665
+1 0.031803 1 1 -0.055945 2.217399 2.257410 0.845604 -0.490789 -2.018130 1.060698 0.178841 -0.717597 -1.655056 0.707618 -1.137274 -22.733756 -36.239676 69.772571 -32.398472 -21.125300 1.331292 0.274320 1.748421 2.215914 2.366311 1.090627 0.912472 1.410051 0.981648 0.805924 1.660638 0.586426 0.314731 1.436719 1.439604
+1 0.014876 1 1 -1.109156 0.625501 -0.541262 -2.087342 1.780011 -2.315229 -1.852941 1.795462 -1.817347 1.555167 -1.936265 0.946357 35.257408 71.260243 70.899024 -0.109136 -34.248358 0.442620 2.119589 1.180152 0.319198 2.254487 0.404865 2.060872 2.076451 0.661070 1.608489 1.623260 2.384167 1.946608 0.898298 1.686340
+1 0.014342 1 1 -0.513595 1.111429 -0.121832 2.263856 0.806294 -1.450371 0.810730 -2.286966 1.924257 -0.133345 1.967884 -2.028187 53.719212 8.793934 49.646916 -34.282076 -28.845695 1.230971 1.678058 0.865764 1.647493 2.424043 1.635711 2.389948 2.362431 1.122586 0.298376 1.048884 1.343577 1.998760 2.166440 1.104097
+1 0.021642 1 1 -0.979977 -0.677346 0.984985 0.012197 -2.346471 0.854039 -0.102399 -0.998990 0.225000 2.238050 0.613131 -1.101689 -35.300279 -41.794146 15.789355 21.681782 55.717839 1.370845 1.296510 0.701538 2.246722 0.410408 0.725203 1.732919 0.428257 1.466530 0.723034 1.275477 0.435892 1.539440 2.110547 2.210483
+1 -0.016917 1 1 2.058821 -0.466822 0.252577 -0.800778 -0.088130 -1.508780 -0.693822 2.089861 -1.857590 -0.946644 -1.223739 2.196775 -11.557088 10.020903 -28.675027 8.813657 -68.869171 2.362754 2.060118 0.656097 1.275289 1.789721 1.091873 1.604544 0.577387 1.398964 1.381679 1.131358 1.490774 0.945359 0.656381 1.537715
+1 0.003182 1 1 0.947566 -2.124887 2.222235 -1.285776 0.978721 -1.589256 -0.799323 0.801996 1.719568 -0.296942 -0.284640 -0.862468 -6.208414 55.186401 67.847795 17.897824 58.726153 1.531850 0.548924 2.266698 0.886421 2.324485 2.361330 0.629073 1.576323 1.001572 0.412758 1.969128 1.387866 1.613858 1.865851 0.353566
+1 -0.018338 1 1 2.233977 -1.861047 2.213982 1.372011 1.673060 0.290645 -1.880022 -0.952969 0.855159 -0.129310 -0.903940 0.220530 -70.168837 -27.645326 65.013948 -60.580518 23.230114 1.052877 0.958742 0.570009 1.141115 1.222121 1.435139 1.887726 1.264893 0.304691 1.439090 0.792231 1.027480 1.610394 2.134523 2.430243
+1 -0.001919 1 1 -1.599890 -0.453992 -0.882608 0.604393 -1.881970 -0.706598 -0.576200 -0.241855 1.928617 -2.254428 2.147956 -0.921477 -74.911294 65.877560 54.145213 -31.412981 42.028145 1.630580 1.661264 2.112668 1.858072 2.371418 1.430849 1.784120 1.454398 1.559307 0.772130 0.680881 1.571263 1.471642 1.141582 2.327309
+1 -0.026234 1 1 1.426592 0.088586 -0.245841 0.907472 -2.115957 1.511636 1.583438 1.982150 2.119201 1.183182 -0.537155 0.977484 37.769990 0.216472 38.249169 -46.214769 -31.617869 2.102254 2.329530 1.656967 1.902138 0.478315 1.296123 0.935786 1.756773 0.827777 2.197009 1.879427 1.280450 0.774075 1.879665 0.784530
+1 -0.023259 1 1 -1.225831 0.029218 0.979702 0.769886 -0.746980 -0.695868 0.696544 1.241903 1.499546 1.014043 -1.685340 0.660160 74.845864 34.432643 9.435671 35.326833 38.082679 1.458706 1.967942 1.702149 0.765895 1.647791 0.669687 2.422607 2.256455 1.984151 1.878323 0.722381 1.562576 1.721853 1.178098 1.787828
+1 0.067492 1 1 1.574521 -1.808091 1.609729 0.896640 -0.394852 -1.227098 2.289606 0.032218 -0.432609 0.349847 -1.179749 1.686326 56.286116 -49.254165 35.248917 -71.459862 24.102003 0.360346 0.830139 1.390800 1.430638 0.486967 0.451140 1.303523 1.564188 1.803102 0.980285 0.393191 1.607092 0.637995 0.782383 2.007536
+1 -0.051198 1 1 -1.400718 1.234386 -2.324251 2.018062 -2.212562 -1.065710 0.409300 -0.988218 2.184098 -1.375878 -0.687515 -0.288584 -37.574634 -16.880431 -59.407325 -58.905996 -33.074809 1.550228 1.178068 1.291703 0.899855 0.870587 1.705339 0.380637 2.119679 0.447319 2.346927 1.551911 2.473551 1.221338 1.776338 1.162818
+1 -0.004592 1 1 0.199928 0.259833 -1.373331 -0.293388 -1.814835 1.360380 -0.613411 1.103724 2.319010 -0.574499 0.081000 -0.521063 -60.121757 -66.367070 -31.353713 -11.856620 -74.207380 2.073343 2.429330 0.494912 1.239915 1.253984 1.466059 1.796193 1.870978 1.030373 0.736448 1.723724 1.135600 0.779051 2.260815 1.017213
+1 0.028403 1 1 1.962320 -1.293579 1.776998 -1.121731 1.329985 2.198181 -0.294067 0.916878 0.453145 0.793264 1.047422 -1.455317 -70.386542 63.386954 44.530610 -74.041964 -23.281460 2.252521 1.124074 0.567325 1.038900 2.285107 2.037312 2.099021 1.992471 2.200883 1.731405 1.972032 0.697215 1.600942 0.786754 1.232222
+1 0.013526 1 1 -0.100207 -1.851615 0.523703 -0.860679 1.609096 -0.321413 -1.592448 2.096824 2.079812 -1.098763 0.937394 1.263886 -41.743713 -36.580810 36.327066 48.994713 -45.861598 2.186749 0.436815 1.295424 0.438883 2.310575 0.331087 1.826650 0.754873 0.898282 1.424859 2.350394 1.316450 0.577478 0.666289 1.573049
+1 -0.025038 1 1 0.672100 0.394332 1.914423 -0.486594 -2.185220 1.362109 0.186351 -1.745857 1.423722 -1.014644 1.021902 -1.550235 -0.116857 -14.007995 67.621498 -35.481671 59.552887 0.705555 2.261724 0.549946 1.442381 2.098209 1.841929 1.042323 1.329776 1.795485 1.216437 0.400047 2.087358 1.722408 1.513350 2.370952
+1 0.035366 1 1 -0.449315 2.318997 -0.793608 -2.114971 -0.762428 -1.136842 1.825558 -0.214653 2.021101 1.743590 -1.835816 2.158727 33.451127 13.094375 27.164106 -52.865726 -64.256516 1.986069 0.358769 1.332868 2.010867 0.888701 2.389659 1.998276 0.769184 0.667986 0.843367 0.977004 1.503304 2.287583 0.912213 1.560230
+1 -0.070409 1 1 -1.872364 0.505723 -1.456423 -1.954838 -0.178764 2.025099 -1.748866 -2.027641 1.441115 -0.868686 -1.024136 1.699210 49.189835 -66.447742 -37.204098 60.726334 27.488633 1.396849 1.847229 2.383616 1.682850 0.412868 1.579572 1.610290 0.394123 1.517298 1.234216 2.213152 0.938271 0.777497 0.883939 1.110410
+1 -0.043909 1 1 1.745102 0.012144 1.465877 0.626987 0.876445 -0.517475 1.866505 -0.023818 0.251153 -1.170256 1.013997 2.242814 18.084495 46.110191 73.971860 45.055221 43.106121 1.143622 0.605192 0.710701 1.005235 1.242500 1.940886 1.463667 2.104551 0.437988 0.758101 1.157191 1.410360 1.674182 0.971841 2.479136
+1 -0.023154 1 1 2.207710 -0.363983 -0.784622 -1.873563 -0.791685 1.940895 1.461829 -1.433277 0.651209 -2.001802 2.168534 0.933362 -16.688049 23.956957 44.581665 34.041945 42.964336 1.398811 1.069011 2.115124 0.395174 1.181500 0.468970 1.737004 1.581174 1.542775 1.926032 1.576697 0.542047 1.436129 0.519264 1.016000
+1 -0.001369 1 1 -0.113115 -2.026845 0.677624 -1.011656 -0.596611 0.726280 1.498672 0.467671 -0.110199 -0.137868 1.354101 2.253705 -5.067761 26.142042 19.304831 6.294182 36.314595 1.215880 2.300672 0.394295 2.171218 0.409742 0.778715 1.109171 2.081568 1.157312 1.185944 0.909704 2.152206 0.377692 2.119921 2.255601
+1 0.033282 1 1 1.603209 -0.299560 -1.866405 1.701198 1.964341 -0.311042 -1.642394 1.464539 1.706781 1.549381 -0.221284 -1.039243 72.033922 24.123147 -12.276758 64.522566 -69.225196 0.356903 1.471724 0.262892 0.918165 0.348239 2.108459 0.871919 1.586534 1.630879 2.188147 1.432646 0.473222 1.195140 2.477015 0.933718
+1 -0.040858 1 1 0.742382 -1.184147 -1.536455 0.692815 -0.176898 0.400415 0.482570 0.525446 0.150780 -1.113703 -0.394156 1.038741 -40.714744 7.302341 30.444738 34.718475 13.411389 0.703220 1.262023 1.564563 1.359760 1.740917 2.096231 2.359036 0.315589 2.357088 1.332502 0.363696 0.887999 1.850775 1.233382 1.705545
+1 -0.022919 1 1 1.905330 2.199979 1.647860 0.865330 1.165834 0.051223 -1.458432 1.978338 -0.680900 -2.200418 0.410439 -0.691868 61.854475 -61.840485 -3.031512 49.377587 -60.902615 1.521227 2.020052 2.256691 1.449667 0.799815 2.488466 2.142645 1.688692 1.841861 2.159762 1.364916 0.643705 2.247196 1.620354 0.784545
+1 -0.016436 1 1 -1.460656 2.297224 0.835279 0.331774 1.371485 2.262613 -1.236477 0.162373 0.534950 -0.333125 -0.514010 -1.164559 -69.545970 -59.110631 -22.371998 43.836115 -46.406864 1.972572 0.761795 2.482548 1.676974 0.651518 0.805450 0.452541 2.352886 0.460457 0.399763 1.813627 2.373726 1.957952 0.294397 1.681835
+1 -0.012435 1 1 -1.750278 -2.191619 2.206567 -0.732177 -1.654032 -0.925751 1.205698 0.899448 -0.314624 -0.587113 0.127159 -2.256119 63.709789 70.430326 72.488199 9.153330 -59.978116 0.592009 1.889095 1.766782 0.303835 0.554451 0.652220 1.357840 0.968772 0.402409 1.295589 0.960838 2.061686 2.257510 1.718350 0.804170
+1 -0.012926 1 1 1.877344 -1.642542 -1.020827 0.764278 -0.745823 -0.097537 0.603675 0.186699 -0.607055 -0.453568 1.529913 -2.266970 -41.098116 13.963664 -62.696939 2.550879 -27.369314 2.184220 0.678771 2.097125 1.636980 1.217172 1.517397 0.639017 2.214423 2.060892 2.417403 0.289042 1.676548 2.486932 1.122481 0.794081
+1 0.017310 1 1 2.269669 -0.467260 2.306081 -1.098143 1.943234 -1.630911 1.240897 -1.282767 -0.285108 0.682116 -0.916234 0.947837 -73.015338 -18.784512 38.700257 35.211438 48.639113 1.038536 0.678737 1.525984 0.969583 0.535377 1.836045 1.150716 0.589362 2.409457 1.746392 1.864881 2.060427 1.347574 1.683605 1.851501
+1 -0.019574 1 1 -0.452958 2.354999 1.121263 0.216517 1.038870 0.881723 -1.337603 1.711478 0.396009 1.833506 1.419366 1.163052 13.372021 43.552252 -17.293475 48.564793 -71.524146 1.280082 1.334202 1.925907 1.724107 0.823342 1.916097 1.097397 2.200217 1.791274 2.439852 1.840949 0.330293 1.989853 0.966049 1.891711
+1 0.042902 1 1 0.298778 -1.849923 0.690958 1.600289 -2.261008 -0.053580 -0.454198 0.360579 0.123533 -1.950922 -0.351564 0.601015 -67.077788 23.616160 16.800494 65.909299 -12.420024 2.224763 0.335827 0.487794 0.846258 2.300846 1.071036 2.410934 1.820424 1.873399 1.212506 1.839928 1.164947 1.256599 0.414335 1.472879
+1 0.012049 1 1 1.037111 -0.408739 0.992337 1.057277 -0.766083 -1.313237 1.261138 -0.385682 2.097147 -1.923437 -0.220398 -0.297403 44.437184 5.756311 -3.678398 -22.828712 17.831367 1.251723 1.715140 0.861824 0.679172 2.096782 0.363919 2.387167 0.607421 2.173742 2.340692 0.264031 2.070848 0.991846 1.197329 1.016112
+1 0.003539 1 1 0.456335 -2.154405 0.908638 -1.373164 -2.193203 -0.856987 -2.327178 -0.058713 -1.901403 -2.174213 -2.132051 -0.379999 -43.105128 32.118845 -28.577352 0.438828 25.382362 1.395261 2.158281 1.228829 1.672065 1.400517 0.491104 2.491778 1.566464 1.812067 0.912835 0.775878 0.673508 1.395492 1.531753 1.167279
+1 -0.039825 1 1 -0.771163 -1.867297 0.849821 -0.312933 -0.430554 1.900313 -2.005444 2.229099 0.982914 -1.806504 0.013893 -2.127435 57.378118 4.032156 -31.555651 44.173783 -71.222417 0.847636 0.725747 1.877410 1.126448 2.214892 0.939501 1.187397 0.587861 1.933439 2.312463 0.556638 1.421348 1.842618 1.377819 1.506400
+1 -0.004024 1 1 -2.287449 -1.484490 2.272747 -0.559568 1.268603 -2.143114 2.190111 0.723510 2.071864 1.971789 2.332603 1.699905 -28.806008 57.428947 -41.688725 -12.405561 -0.267606 1.410176 0.823548 0.876894 1.962700 1.356875 0.503660 2.013934 0.686266 2.068449 1.181058 2.048821 2.036217 1.697622 1.187299 1.189311
+1 -0.015496 1 1 -1.656294 -1.248151 1.878076 1.238766 0.606396 -1.198610 0.423646 -0.206513 2.161879 2.185397 1.602783 1.954613 35.690849 6.094838 -14.055473 19.664063 43.906833 0.507024 2.299184 2.378022 2.167126 1.385232 2.348508 1.132985 1.827235 1.596164 1.484596 0.604069 2.084731 0.327436 1.213203 2.310082
+1 -0.001720 1 1 -0.566671 -0.297978 1.146659 -1.770712 -1.627551 1.173404 0.048842 0.937591 -0.132025 0.592675 -0.899496 -0.487056 -16.846729 57.019107 -29.873144 -27.925734 2.194692 1.167826 2.402411 0.326231 1.214163 0.445424 1.987439 0.885276 1.084125 1.882768 1.182679 2.289364 1.592775 0.765910 1.902298 0.929904
+1 -0.011015 1 1 -2.080850 -2.200767 -0.756577 -1.766456 -0.780748 1.971189 1.686426 -1.265106 -0.332487 0.788315 -2.022290 1.833888 -50.099982 69.598887 48.488668 -0.959427 74.910943 0.298314 2.271785 0.883297 1.567598 0.622389 1.746119 1.777439 1.672831 0.776759 1.991478 1.269757 1.056872 0.599405 2.441371 0.377930
+1 -0.001044 1 1 1.722793 2.068235 2.247222 -0.732010 1.155666 -1.192877 -2.185993 -2.196590 -1.226717 -0.739361 0.127146 2.224068 39.422667 26.764045 -26.696390 -36.225682 4.966316 2.407975 1.591516 2.103897 0.694271 1.614021 2.349893 1.902747 1.720254 1.314887 1.312650 1.958664 1.009180 2.291401 2.081213 1.947856
+1 0.022320 1 1 1.226883 -1.187303 1.963986 -1.579407 -0.199820 1.551867 -0.837878 -1.590426 -1.623180 -0.771315 0.293487 -1.232455 56.906639 29.888457 -14.709200 -17.531166 -46.311479 1.269575 2.488323 1.993621 1.278954 0.386843 0.676173 1.190865 0.365360 1.863943 2.039827 1.627968 0.500865 2.295992 0.488821 2.356765
+1 0.008209 1 1 -2.198982 0.973358 -2.191255 -1.101920 -0.283332 2.262093 -0.552398 -0.745772 0.769865 -1.105795 0.571101 -0.642621 8.460990 3.864116 -5.810567 -8.206712 69.788995 0.529540 0.480324 1.310183 1.000664 0.907072 0.666563 1.679385 0.682492 1.638090 1.882570 2.355238 1.729317 0.634102 0.607784 1.532367
+1 -0.000718 1 1 -1.263815 -2.198507 -0.462207 -2.291425 -2.345498 -1.655215 -1.957838 1.223517 -1.222413 0.923948 1.467288 0.780823 -22.400758 10.463506 60.144948 6.148434 -13.260720 1.781216 2.153765 1.822434 1.906653 2.123809 2.362280 0.843181 2.350626 0.714804 2.457441 0.455301 1.497010 2.254582 2.012632 1.302921
+1 -0.008130 1 1 2.173921 1.942121 -1.492767 -0.183192 -1.722903 0.805899 1.343739 -2.265419 1.207477 -2.187858 -0.560030 -1.784465 -59.064799 -2.078821 11.250973 -54.901527 70.042386 1.410610 1.375610 0.369765 1.645348 2.369836 1.831920 1.576972 0.666028 1.690773 0.822427 2.280931 1.600780 0.318384 2.087462 1.227724
+1 0.000610 1 1 0.703997 -0.732278 1.368290 0.397762 -1.687188 -2.127297 -0.591027 0.333153 0.977566 -2.141375 -1.569534 0.789698 -74.916947 -29.134172 -58.025956 57.755837 52.359101 0.616223 1.607653 1.073339 0.602279 1.255388 0.305518 1.843436 1.622606 0.393004 0.716732 1.107236 1.063332 1.172164 1.057647 2.374868
+1 0.028490 1 1 1.826126 -0.095946 -0.920613 -1.973553 0.998154 -0.130603 0.927670 -1.944282 -1.839931 -1.027215 1.785248 0.879651 48.879000 -40.640791 50.218217 -32.421121 48.223187 1.931610 0.816782 1.907438 1.814448 0.432910 0.920361 1.254808 1.811219 2.404930 2.160154 1.209751 0.540119 0.532706 1.943468 2.117780
+1 0.021473 1 1 1.735714 -2.251069 2.063682 1.118434 -0.190217 -1.976340 1.282125 -1.073793 1.217209 1.145410 0.798700 -1.844017 31.623186 40.886116 22.944378 -23.843420 63.646427 2.207520 0.792327 0.386586 0.845405 1.466569 1.376692 0.561542 0.592402 1.748458 0.580215 1.681725 1.746872 0.934639 0.476475 1.861882
+1 0.030039 1 1 -0.124220 -0.182662 -2.231724 2.032457 -0.604171 0.889019 -1.244641 -0.381624 -0.390526 0.785215 -2.298017 -0.029524 -44.664051 -68.709412 50.905785 -26.467985 52.581439 0.418678 2.463450 2.451998 1.232452 1.826542 1.193260 2.373003 1.055101 2.331782 1.253786 0.390343 0.990229 1.023279 0.754602 0.841692
+1 -0.040089 1 1 -1.162680 1.110567 -0.469932 -0.179967 0.640726 0.865703 -1.991405 -2.155508 1.220343 1.994450 1.507184 2.154417 -22.623402 18.474834 6.535656 44.769943 48.425782 1.256770 1.026027 1.936269 0.378135 0.571115 1.733909 1.316785 1.713767 0.274794 0.713315 2.190023 1.463808 2.215223 1.996794 0.619238
+1 -0.037500 1 1 1.825109 1.671707 1.114632 1.874352 -0.084292 1.731974 0.868405 1.012156 -0.415487 0.666828 1.311862 -0.798989 54.196128 74.324190 -33.331834 41.868815 39.171304 1.406625 1.890666 1.172889 1.998728 1.616694 2.278128 1.754731 0.261770 2.311160 1.169385 1.599760 1.165047 0.698944 1.402376 2.484231
+1 -0.002642 1 1 -1.234817 -0.216062 1.897397 0.809117 -1.129053 0.802861 2.110192 0.559135 0.884368 0.702592 -0.782884 -0.942690 -23.379555 59.820771 -42.295921 -17.543407 47.955187 1.867407 1.764939 0.827402 0.395105 2.278001 1.857643 1.902086 1.858168 1.727530 2.102657 2.347130 0.467171 0.736234 0.388429 0.332932
+1 -0.014716 1 1 1.331576 0.661649 -0.901802 -1.535124 -0.504924 0.762527 -1.902408 -0.207809 -0.770016 -1.446732 0.699748 -1.451325 -34.805554 23.060690 -18.982298 14.523481 46.152837 1.985902 2.055188 1.037555 2.183337 1.591818 0.427955 0.891151 0.829152 0.551948 1.336628 2.201088 0.680351 1.656240 0.928515 1.052366
+1 -0.017039 1 1 -0.199285 1.122709 0.961812 1.680615 0.043485 0.439190 1.872784 1.841629 1.283980 1.817116 -0.724824 -0.589774 -69.214815 -43.392828 -3.256658 15.351920 19.720418 0.490951 2.171520 0.991460 1.468205 1.873010 1.437439 2.287126 2.223081 1.320086 0.934638 0.458901 1.243778 0.934905 0.451974 1.831609
+1 -0.041265 1 1 -1.284240 -1.485882 -2.276634 1.214476 2.332447 -0.925424 1.988858 1.760570 0.806216 1.952193 -1.849630 0.903238 67.335723 -38.510007 12.314334 -32.990917 71.656275 1.030239 0.728755 0.689134 0.779293 1.828870 2.063921 1.563335 0.967169 0.465698 0.733273 2.374566 0.332783 1.090224 0.899397 2.161574
+1 -0.015851 1 1 2.076302 1.167685 -1.809166 -2.327767 -0.527863 1.643200 -2.046834 -0.694493 0.239780 0.888727 -1.432248 -0.902497 29.103142 -13.484942 8.577464 11.435900 53.179410 0.420222 1.417508 0.307132 1.970187 1.185493 2.337710 1.888138 1.428580 1.899247 1.402131 0.615708 1.947542 0.847509 0.834012 1.239573
+1 0.045947 1 1 0.632780 -0.726234 -0.734611 -0.145547 -0.476683 -0.546451 0.242727 -1.417430 -1.615882 -0.631182 -0.683575 -0.043524 -34.433691 -27.045002 -45.350155 -50.057617 31.622787 1.887795 2.425313 0.478308 1.168015 1.076616 1.692155 1.548430 2.463292 2.041246 0.718888 1.357241 2.146622 1.030190 2.148387 1.444235
+1 0.000133 1 1 2.011663 -1.372124 1.137160 -1.199953 1.408323 -0.645492 -0.869469 -0.054445 -0.854374 -0.817294 0.359861 2.184198 9.513760 -2.240348 -3.533778 7.798962 -22.842798 0.341355 1.157460 1.434162 1.212253 2.087979 0.907715 2.469131 1.177413 1.524302 1.939544 1.412683 2.457764 1.389858 1.337488 0.912064
+1 0.004286 1 1 -1.948330 0.806256 -2.089295 1.938679 1.923075 -1.161818 1.470654 0.794763 -2.032575 -1.386512 -0.340746 -1.360702 -2.780641 65.769849 43.849653 31.117430 -59.353886 0.463658 2.442201 0.818110 1.731298 2.418855 2.186787 1.084820 2.328322 1.609449 2.009535 1.009618 0.654620 1.193245 2.119393 2.388845
+1 -0.029997 1 1 -1.724866 0.793035 1.895763 1.628463 0.026129 0.893506 -1.222206 -0.313486 -0.314293 0.258043 1.530309 -0.322172 -6.830799 -55.233914 33.612488 25.079242 6.819909 1.708232 1.749137 0.742030 1.054639 1.312791 2.084937 1.538567 0.951747 2.268868 1.367548 2.133081 0.689027 1.231521 1.928169 1.482175
+1 -0.051580 1 1 1.763625 0.325110 -2.249006 -0.968678 0.727457 -2.279327 -1.640566 -0.808695 -1.207733 -2.115958 1.492200 0.073521 32.493078 -38.836651 72.411744 74.178154 62.237372 2.477712 1.402534 0.636636 0.444190 1.502769 2.285095 1.835650 1.264834 1.560134 1.162933 1.167998 0.800678 1.248590 0.793783 2.356265
+1 0.039731 1 1 -0.534174 -0.760781 -1.735604 -0.613698 0.992645 1.519683 0.169760 2.166215 -0.347388 0.103693 -0.813258 2.210014 21.077779 -45.766724 -1.324463 -60.244487 -29.091214 2.334596 1.299121 1.826542 1.183751 2.304590 0.994634 0.821871 1.941593 2.104931 2.331020 1.952648 1.159469 1.439823 1.854200 0.284866
+1 0.021719 1 1 -1.196654 0.312369 0.390367 1.248515 -0.480185 1.845909 -2.173925 -2.009318 -1.626127 1.536133 -1.389820 0.598833 -34.318152 -35.183088 -22.162317 -32.066029 16.257850 0.560252 1.413555 1.363746 1.227868 1.282550 2.318422 1.712490 1.315676 1.067774 1.584899 1.146412 2.493346 0.913281 1.509561 1.698059
+1 -0.042059 1 1 0.350047 2.184157 -0.379319 0.644081 0.707667 -0.307638 -0.984956 0.471828 -0.943099 1.804919 1.630775 1.174403 -64.107765 -9.207856 43.565061 47.972377 21.735228 2.184758 0.734210 2.375479 2.169084 0.547776 0.970499 2.418625 0.573018 2.220343 0.309229 1.210420 0.533166 0.674757 2.136219 1.686633
+1 0.003366 1 1 -0.862505 -0.819031 -0.565149 1.724133 1.026061 -2.343858 2.352601 -1.484434 -1.488336 -1.098159 1.662939 -0.156828 -50.568334 -1.982134 -13.725933 8.240017 39.972892 0.990900 1.061230 1.844712 0.569979 0.633209 1.347168 1.605446 2.234777 2.152678 1.565116 1.646393 1.928417 1.148455 0.829199 1.346076
+1 -0.060348 1 1 -2.068690 -0.470583 -1.705607 -0.675402 0.662934 1.841559 0.112274 2.026679 1.249261 -2.072721 -2.245758 1.778290 55.624772 -64.456316 -17.301596 62.067826 73.951075 1.310644 1.987852 1.072120 0.366112 0.993056 1.287234 2.284490 0.675383 1.408657 2.302609 1.454494 0.929101 1.904875 1.480896 1.419129
+1 0.016462 1 1 1.152485 1.901615 1.024961 -1.973438 -1.781160 1.856271 2.328934 1.297911 0.337106 1.455234 0.826344 0.951609 -4.848672 -41.623615 31.901650 71.037715 -69.129143 2.072462 1.127595 1.245788 0.968037 1.541557 1.703178 2.310142 2.058416 1.291058 1.309111 0.981229 0.520767 1.533840 0.250982 1.011882
+1 -0.012910 1 1 0.897928 -2.310882 0.513613 -0.810813 0.897072 2.160988 1.348330 -0.501726 -2.053256 -0.254582 0.084668 -0.125818 39.629522 53.374231 60.708097 20.986490 69.944020 1.362252 0.876806 0.480946 0.504753 2.381417 0.722432 2.414357 0.854141 2.044437 0.360274 1.866645 2.443673 0.814221 1.616712 0.325444
+1 0.009485 1 1 -1.335469 -0.125904 -0.202909 1.478764 0.449452 -0.026480 -2.086081 -0.586040 -0.688044 0.248451 0.544878 1.597003 -29.713561 -45.812162 -15.002400 4.656084 -45.197966 0.741892 0.972917 0.312263 0.457888 2.216788 1.309554 1.680047 0.544473 1.699687 2.141892 0.274994 1.828969 1.483320 1.665466 0.732618
+1 0.009436 1 1 1.067934 -0.725308 0.697013 -0.299767 -0.646822 0.352389 -0.872698 2.230143 -0.328670 -1.031807 0.008536 2.100678 28.039109 -46.686655 -12.603380 -25.004358 51.757706 2.001452 2.397292 2.029081 1.016281 2.385260 2.314954 1.936505 2.087734 1.300039 1.512370 1.657355 1.658574 1.905413 1.519519 0.305660
+1 0.032331 1 1 1.660523 1.649138 -1.215927 1.543293 1.136144 0.572309 0.815109 0.613734 -0.390859 -0.096122 0.829465 1.576377 35.509624 -39.744158 -30.062772 -65.009172 -9.159674 0.675463 0.502513 0.741789 1.499861 0.669941 2.201252 1.189081 1.891374 1.820845 2.190006 1.173905 1.075359 0.803351 1.165713 0.644992
+1 -0.037606 1 1 1.677425 -1.749669 -1.380657 -0.903458 -1.094582 0.534229 1.690733 0.441243 -1.326868 -1.637882 1.900999 0.093583 -34.453077 -52.866929 65.530320 68.092484 -69.614357 1.247432 1.591706 0.800343 2.357705 0.439712 0.486773 1.697851 0.531134 0.277042 2.490313 1.696735 2.031740 0.709890 0.865893 1.564515
+1 0.008248 1 1 -1.656134 1.435967 2.147368 -1.380669 -1.093357 2.260304 -2.348829 -1.087358 -0.588439 1.402311 1.977798 -0.334686 48.399803 5.488743 -0.696478 -5.704646 -27.992585 0.304241 0.631025 0.632541 1.366941 0.922293 2.223544 2.352741 0.268465 2.347569 1.085390 0.650913 1.891767 1.680120 1.773639 0.801235
+1 -0.031047 1 1 0.405099 -0.895628 -1.445825 1.808074 -1.889471 0.450524 -0.860382 1.880939 2.236664 0.884679 1.217628 -1.239911 -31.933154 -0.519770 -35.774780 -66.723155 -16.071456 1.930617 2.123841 0.643730 0.416685 0.480029 0.852012 2.266697 0.878849 1.061675 0.313181 2.385070 1.374020 0.658559 2.147092 2.167515
+1 -0.034081 1 1 0.103079 -1.705948 -1.690764 -0.961190 -0.651098 -0.830620 -2.134544 0.130194 1.616718 0.553455 -0.337630 -0.823157 24.547311 66.661257 25.750931 45.893071 24.844234 0.730494 0.658244 1.358111 1.028550 1.586809 1.740491 1.689412 0.444437 1.156511 1.223276 0.598634 0.745238 0.962224 0.599868 1.224713
+1 -0.006842 1 1 -0.089542 -1.685371 0.137964 0.261208 -1.819953 0.168169 -1.016944 0.050730 -0.318173 1.027318 -0.058484 1.944205 17.298775 40.517290 -25.909872 -17.213297 46.116487 1.821989 1.163091 1.565685 2.211905 2.484805 1.374025 0.744175 1.104725 1.611937 1.071711 0.255675 1.131610 1.212805 2.366511 2.203604
+1 -0.043587 1 1 -1.355929 0.009682 -2.206931 -0.674306 0.226682 2.229198 -2.076252 -0.332038 -1.097417 -0.003026 0.974074 0.430559 -58.260686 12.643534 -50.119212 46.405446 -63.664709 0.433572 0.794809 1.606102 1.999819 1.954347 0.458015 2.110953 2.289874 1.164451 1.930503 2.458227 2.428553 0.935604 0.939139 1.861914
+1 -0.047723 1 1 0.382884 -1.995367 1.938402 1.969403 -0.060733 1.854486 0.612203 2.149313 -1.666318 -0.075483 -1.018507 2.064428 -15.397513 -36.001015 30.945692 54.242000 -54.712305 0.629419 0.639550 2.166391 0.278148 0.841543 1.806251 2.164004 0.657137 0.754206 0.933110 1.787525 2.434899 1.844704 0.441800 1.840199
+1 -0.003647 1 1 -0.396658 1.403844 -0.521399 1.888094 -0.036689 0.695264 -1.421241 0.298361 0.563317 0.485887 -0.259307 0.790121 1.623572 -12.626137 42.509237 2.744467 -73.740214 0.598457 2.268433 0.808162 1.020840 0.259798 0.672037 1.429775 1.723339 1.403957 2.063667 1.795079 1.150956 2.374540 2.148801 1.655450
+1 -0.038473 1 1 -1.900388 0.757136 1.731591 -0.857283 2.131587 1.999783 1.601629 1.405961 2.068961 0.305941 0.730699 0.376988 -67.734237 -59.326937 -57.827740 -60.824083 -20.359371 0.925793 0.301458 1.105694 2.145831 1.230038 1.752372 1.120683 2.068299 0.898009 1.337346 0.778958 0.695187 1.257499 2.039640 0.737431
+1 -0.010163 1 1 1.900759 0.777583 1.377560 0.683421 2.162559 -0.532928 1.323518 1.889705 -1.225766 1.112484 -1.244954 -0.928819 46.974103 43.744425 62.554811 8.701131 -10.098389 0.270743 2.369723 2.191998 0.917469 2.148318 0.283604 0.273978 0.492917 1.458051 2.217974 0.992260 1.418846 0.293385 0.417928 1.122003
+1 0.020858 1 1 1.697608 -1.817941 0.994036 1.348008 -1.186672 -1.570735 -0.541457 -0.638949 0.716008 -1.498193 -1.830912 -0.246314 -73.890333 -24.834449 57.420625 -31.558466 -3.140141 1.729844 0.484710 0.779146 1.611979 1.774253 2.126766 0.298962 1.900547 0.750345 1.293924 2.226865 1.914864 0.611864 0.347994 2.487312
+1 -0.019254 1 1 2.108473 -0.064852 -1.406804 -2.101508 -0.688965 -1.088831 -1.781210 1.005687 -0.762430 -1.178665 1.053425 0.461880 47.946201 31.793099 46.606558 16.425213 58.562788 0.846636 1.913538 0.826463 0.370279 1.277988 2.148029 2.175506 0.480824 0.701047 0.747737 2.463243 1.221215 1.952522 1.292792 1.203100
+1 0.065179 1 1 -0.821148 1.544452 1.759517 1.959875 0.023862 0.502545 1.670893 1.579534 2.347506 -2.305770 1.614137 -0.421140 -3.152133 -27.903669 73.028416 -61.411124 13.233523 0.862344 0.417715 2.028555 1.180923 2.015278 0.782313 0.826936 1.565732 0.762231 0.821905 0.263174 1.171328 0.515615 0.433071 1.365927
+1 0.011662 1 1 2.190196 2.156517 1.604198 2.182875 1.629873 0.149575 2.201368 1.420421 0.050183 -0.098277 2.312311 -0.052522 -48.292939 -9.428567 -65.916787 36.566137 17.062474 0.909900 0.940573 1.202447 1.530121 0.738281 1.032129 0.994403 1.434805 0.772005 0.837695 2.395211 0.811405 1.537849 2.381361 2.037042
+1 -0.014216 1 1 -2.298730 2.120909 1.614651 -1.201848 -2.154998 0.368419 -0.059018 -2.308304 1.434436 -0.022563 -2.218828 1.995585 54.796226 -39.827093 -73.944616 -37.153922 4.033665 1.282203 0.983711 1.726442 1.813676 0.950748 1.220447 0.303300 0.564588 2.278993 0.542730 1.667624 1.005990 0.425004 0.789083 2.109698
+1 -0.013858 1 1 -1.719230 1.275423 -0.625503 0.502611 -1.925738 -1.188030 -0.820104 0.250424 0.705746 0.390634 1.035595 -2.317294 36.153282 -21.783990 26.486068 -48.651433 -34.626639 1.826190 2.024324 2.060163 1.417525 0.586698 0.381517 1.163207 1.279072 2.366625 1.869675 1.629983 0.628682 1.762620 2.362478 1.925219
+1 -0.010012 1 1 0.557905 -0.946079 -1.157477 -0.965171 -1.586273 2.204011 -1.281720 -1.542624 0.676429 -2.253300 2.259422 1.670107 -70.378249 52.763633 -1.615464 -1.101121 -56.542088 0.581884 0.472559 1.298610 2.241852 1.804701 0.865912 1.875479 2.418525 1.142824 0.694718 2.375140 0.980161 0.564761 0.695539 0.421593
+1 -0.022499 1 1 0.894043 -1.629236 1.121808 -0.044133 -1.891953 1.140215 -1.685706 -0.784274 -0.736568 -0.055256 -0.343149 0.652351 -53.214407 -74.540857 -8.186214 -35.699709 -5.006383 1.490714 2.176466 0.863471 1.358733 2.482681 1.673854 2.216653 1.293005 0.277565 2.281842 1.172219 1.985676 0.514057 1.258174 2.126140
+1 0.033550 1 1 1.635650 -1.707767 0.719299 1.977800 -0.304481 0.245581 -0.577972 -1.744456 1.405877 0.664241 0.252810 -1.604345 2.066192 -73.515021 -16.950267 -33.129096 -0.724495 0.976222 1.863997 0.690421 2.161440 0.327600 1.719310 1.197172 0.623515 0.408382 0.428847 2.382908 1.032887 2.482148 1.709595 2.169301
+1 -0.064572 1 1 -1.779651 -1.053042 1.252080 -1.819965 -0.032906 -1.695627 2.123161 1.752831 -2.021496 1.046647 -0.351896 -0.259705 -38.083403 -17.760172 4.787732 67.407410 -33.660808 2.317011 0.501808 2.379633 2.245311 1.440375 2.134387 2.400997 1.311488 0.430849 2.279197 1.717129 0.533559 0.531197 1.320289 2.095935
+1 0.048660 1 1 0.549424 -2.113800 0.061762 1.302795 2.311272 1.323345 -1.017800 -0.196242 0.426477 0.248166 0.460575 -1.575321 -70.603465 17.561663 -41.121989 62.733887 18.440998 1.942916 1.847612 2.059719 0.690321 0.475435 2.385167 0.748270 2.419190 1.075436 2.101968 2.033593 0.352696 0.505539 2.096674 0.795175
+1 0.053611 1 1 0.876420 -0.944556 0.888276 0.402036 -0.543015 1.446961 -1.565460 -1.417091 -0.626079 0.259284 -1.180874 1.631951 66.867839 47.768604 46.923476 -57.146658 -13.886792 1.445297 1.614644 1.568887 2.030052 1.590923 1.145081 0.370761 0.387490 0.295849 1.342541 0.333907 1.975615 2.415809 0.500777 0.807229
+1 0.053221 1 1 2.195740 1.080356 0.706872 0.466510 -0.774030 1.787594 -2.091271 1.708955 0.391308 -1.788504 0.935959 0.712437 -7.778941 59.337153 -70.466023 -72.449840 35.545403 0.798760 0.501045 0.806113 0.349247 1.047649 0.840593 1.600155 1.051511 0.494853 0.252595 1.117397 0.837848 0.456101 1.435677 1.922141
+1 0.013294 1 1 2.050984 -0.231421 -1.776158 1.100322 1.692994 0.749001 1.674053 -1.860864 0.583656 -1.691609 -1.033900 -2.187013 -15.968533 -33.141495 -59.106272 50.882819 37.533136 2.416133 1.451094 2.281927 0.352308 0.741090 1.007766 1.020830 2.335131 1.294566 1.769095 0.934357 2.487945 2.387286 0.365096 1.917922
+1 -0.038964 1 1 0.504225 1.635672 -1.343200 1.902277 -1.987157 -1.451693 2.150054 1.361444 -1.574663 -0.584041 -0.066312 2.322851 -63.362486 66.691876 -59.648072 -55.153382 37.110266 1.558558 1.677461 2.081281 0.833764 1.566356 2.237529 1.152899 1.273930 1.444203 1.217736 1.983522 0.297034 1.008007 0.577843 2.314904
+1 0.015997 1 1 -1.919742 0.616717 -2.091653 0.008899 -1.228278 1.313356 0.748466 2.094102 -1.256452 -0.965076 0.003625 -0.328856 17.676752 -56.822695 30.957042 -54.990250 -71.126315 0.325346 2.094034 1.437569 2.230650 0.279346 0.718356 1.412387 1.997216 0.951288 1.294148 1.492198 2.362810 0.755017 1.074989 1.333753
+1 0.009249 1 1 -0.014803 0.957371 -2.279857 -1.120754 -1.100970 1.543102 -2.076625 -1.877194 -0.555382 0.942225 2.344280 0.032812 3.811548 10.695260 55.233838 -34.876838 24.991083 1.752104 1.117836 1.472655 2.415121 2.444495 1.128283 1.560047 1.966873 1.726843 1.805408 1.495677 2.340052 0.760066 0.422485 1.209086
+1 -0.046330 1 1 -0.801182 -2.164555 -0.032928 -2.079631 -0.569735 0.044050 0.498814 0.233873 0.576219 0.548262 1.916428 0.223468 1.422851 63.862786 -58.150704 61.123167 -52.935051 0.933909 1.708882 1.423754 1.788979 2.122547 1.398390 0.736925 0.754865 0.761317 1.197797 2.129453 0.459816 0.884439 0.521049 1.768743
+1 -0.026928 1 1 1.945127 1.908142 2.338774 1.731818 -1.762457 0.462789 -2.065075 -0.975490 -0.658451 -1.904504 2.265031 1.695431 -22.803926 -15.587042 -71.408045 -5.014454 22.077794 0.797291 0.576111 2.441114 0.545260 1.434297 1.224700 2.031775 1.294255 1.049267 1.030404 1.245885 0.347199 0.375035 2.462763 2.162216
+1 0.045347 1 1 -1.856008 2.091979 0.750399 1.594839 0.388788 -1.727595 2.053317 1.274560 -0.984410 0.223791 0.772133 -0.683816 19.580466 -11.100586 32.447436 -55.940190 13.222444 0.319328 2.198415 0.768210 2.311718 1.539345 0.520090 1.397136 2.167062 0.305639 1.631399 1.918025 2.002088 1.835134 1.597556 2.378574
+1 -0.033958 1 1 1.766329 -1.358049 2.084245 -1.987287 1.083912 -0.787328 -0.228170 1.026169 -0.526957 -1.994129 -0.821907 -1.770612 1.822082 23.736295 -64.096023 38.143437 -23.261564 0.518469 1.152877 0.912939 0.263725 1.422249 1.246187 0.908209 1.765538 1.894921 0.679839 2.045753 2.218031 1.949644 2.423394 1.981238
+1 -0.013986 1 1 0.131311 1.539502 -1.319121 1.327691 1.337468 0.729121 2.126655 -0.780930 -1.093392 1.681864 2.181335 -0.681496 60.969027 56.434198 39.573522 12.182499 1.266899 1.266466 1.986948 1.634618 2.020757 0.618142 2.365816 1.774902 1.776818 2.481678 0.562251 1.247842 1.722746 0.435016 0.313144 1.754163
+1 -0.004595 1 1 -0.959632 1.970033 1.106941 -0.155257 1.261437 -0.072864 0.595419 -1.908472 1.540740 0.644762 -1.978350 0.483292 -46.878864 56.937878 -45.088171 3.116817 34.342433 1.274102 2.080742 0.780719 1.038566 1.170653 0.419236 0.597603 1.416107 1.504793 0.306674 1.019909 0.352655 2.072861 1.068490 2.354130
+1 -0.051619 1 1 -1.550717 1.328737 0.078587 1.350661 0.990351 0.671768 -0.486488 -0.417261 -0.867085 2.317906 -0.278542 -2.049027 4.680145 59.193273 61.344360 64.654132 41.994912 2.252272 1.433688 2.236336 1.342895 1.790122 1.085824 1.190436 2.161102 1.383042 1.529088 1.386381 1.398388 0.706426 1.152104 1.417376
+1 -0.008128 1 1 -2.278084 0.393464 1.468847 -1.301694 2.055924 -2.034640 1.607419 -0.243705 -0.877318 -0.015214 -1.231394 0.778873 -15.858092 23.052198 -11.701228 -12.542871 -58.040849 0.736729 1.952094 0.841262 1.596002 1.001205 1.005409 1.903533 1.434261 0.624468 0.688420 2.277478 2.065374 1.246281 2.499529 1.330925
+1 0.041304 1 1 -0.771200 2.215277 -0.426332 2.174798 -2.166141 1.588762 1.924571 0.434098 1.111232 1.281419 1.189238 2.278755 46.370248 -55.250178 60.254627 49.522535 -24.752654 0.357065 1.936414 0.552007 2.330446 1.296924 0.899880 1.290605 0.443815 1.951464 1.496309 1.716650 1.479580 1.795330 0.856311 0.271550
+1 -0.003824 1 1 0.020831 1.388935 -1.343735 2.333243 -1.688177 0.105866 -1.996005 0.648542 0.281372 -2.219969 1.683302 -1.922181 64.992960 36.674062 30.965598 -61.193628 68.693465 1.091044 1.185055 1.721392 2.437142 1.287336 1.754041 2.171660 1.093010 0.469720 0.826144 1.749327 1.695115 1.795001 2.080697 2.271792
+1 0.018232 1 1 0.664927 2.351504 -1.069757 -1.638499 0.953172 -2.153115 -0.961955 0.624631 -1.025342 0.276296 2.006405 -0.201960 -45.096331 15.957739 1.720777 -28.899338 -11.175025 1.095307 0.821363 2.390749 2.311046 1.507557 1.765988 0.458040 0.280055 1.388429 2.079455 1.645067 2.143791 0.692981 2.424802 0.894727
+1 -0.006263 1 1 -0.989906 2.091048 -0.754803 -0.220188 -1.479737 2.052905 -0.934046 -1.541637 -1.583657 -0.954753 -0.845161 -1.472393 -55.889023 -26.808275 33.320837 73.302475 44.693239 0.763929 2.354639 0.662204 0.406449 1.692608 2.407122 0.758049 0.273713 0.550030 0.606287 1.116361 1.432732 1.931169 2.409311 1.547868
+1 -0.018497 1 1 0.953104 1.408812 -1.856194 -1.036112 -1.648392 -0.389111 1.003334 2.108250 0.911281 0.632880 0.948490 -0.737336 37.678432 -38.597208 46.728469 -34.619966 -7.771538 1.881312 1.457241 2.105468 2.357352 1.259083 1.656479 0.435923 2.062754 2.200520 2.388154 1.450922 1.651199 1.706133 2.472998 0.931870
+1 -0.002024 1 1 -1.775226 -2.082266 2.262559 -2.147878 2.227245 -1.909470 -1.096815 0.692498 -0.784799 -0.142294 -2.351266 0.367907 24.209442 -61.907703 67.230129 -13.225327 21.937201 1.353142 0.761368 2.057397 2.167991 2.425873 0.898366 0.594611 0.627274 0.594430 2.077972 1.472951 0.637944 2.167201 0.399670 0.257983
+1 0.006044 1 1 -2.295419 1.228096 0.342086 0.322916 -1.426549 0.627419 -1.287480 0.608621 -1.495330 -0.837071 -2.178880 -0.454492 4.485714 -58.598424 36.280436 15.285574 -45.352891 2.184519 1.212908 1.852633 0.948263 2.209567 1.438791 0.263781 2.367061 2.435278 1.466112 0.447439 2.104972 0.761251 2.342389 1.784949
+1 -0.015627 1 1 -1.558733 -1.459173 -1.055656 -0.265033 -1.208441 0.129038 1.036459 -1.928920 1.879687 0.051459 -2.209960 0.245572 -23.296341 -41.606259 23.599042 29.093377 -27.605079 1.246441 0.692330 0.491732 1.786968 2.062790 0.567252 2.046051 0.472621 2.334233 1.946784 1.590059 2.379956 0.916977 0.638116 0.559904
+1 -0.012772 1 1 0.805516 -0.389952 1.004275 -0.931092 0.975532 1.369589 -1.339359 0.476743 1.564806 -0.141853 0.353167 -1.930461 -14.564948 6.916807 0.776838 6.318016 -13.101304 1.470798 0.459432 1.181606 2.246263 1.686198 0.432693 1.765896 1.171168 2.323060 0.915704 1.744399 2.109889 2.409412 0.994650 1.081486
+1 -0.019535 1 1 -1.036790 1.091508 -0.347322 1.205436 1.205271 -1.570312 1.865679 0.238314 -0.193475 -0.178174 -2.206597 0.226282 7.073466 -66.263102 66.042491 -23.859669 -59.459033 0.955575 1.342813 0.407420 2.258833 1.448052 0.660332 0.446482 1.766981 1.408184 1.091413 0.631990 1.105119 1.492466 2.379093 2.168159
+1 0.015733 1 1 1.021161 0.126168 -0.073372 1.481716 -1.771916 1.700170 -1.170885 -0.126238 -1.100178 0.721709 0.069084 1.847327 -60.753744 -38.178077 41.066564 55.733686 -33.944071 0.655082 2.205068 2.332513 2.295047 0.348741 1.548400 1.959577 0.604779 0.515845 2.061438 0.331263 0.293259 0.548082 1.612476 1.133315
+1 0.024532 1 1 -0.639810 0.386901 -0.445608 -1.352104 -1.677448 1.356666 -1.760953 2.174326 -0.676361 -1.324412 1.942097 -1.889975 44.872063 -35.239700 -73.635551 57.300489 49.323964 0.442866 1.741123 1.057451 1.327380 2.024935 1.086582 0.426015 2.032809 0.666565 1.700675 0.748160 0.573468 0.775591 0.365315 1.103044
+1 -0.007028 1 1 1.531340 -1.834978 2.114378 0.226192 -1.290266 0.912103 0.311112 -1.889549 -0.851999 1.401264 -1.479767 1.545313 67.081664 41.520755 39.325774 48.286000 42.805490 1.853115 2.302694 0.620900 1.473577 2.161579 0.408459 1.717797 0.518735 1.129117 2.062987 1.627418 0.269315 0.871446 0.386855 0.866231
+1 -0.024290 1 1 -0.854682 -1.271734 1.366286 -0.302120 2.229871 -0.193495 -0.521978 1.585646 1.391121 -2.306118 0.480941 1.426668 43.653478 34.007370 61.874027 -33.222197 -65.460284 2.260137 0.865400 2.277599 1.865417 2.070276 0.385427 1.625806 2.430423 0.872609 1.932895 2.164838 1.177563 1.803055 2.436773 1.842620
+1 0.001254 1 1 -2.175546 -0.971858 -0.873954 -0.023144 2.143168 -1.284869 2.080408 -0.504366 0.702436 1.304618 -0.035356 -0.461131 52.742383 -58.769086 17.975191 9.041404 8.882812 2.026397 0.911125 1.272922 2.498427 0.810012 0.628022 1.922317 2.127670 2.003738 0.332685 1.685106 2.320845 1.936938 0.361092 2.128072
+1 0.022591 1 1 -1.305985 0.616408 2.144831 -1.600017 2.117941 -1.158804 0.292978 -0.363197 -1.706368 0.675896 -1.789363 0.648860 29.413496 -47.368706 74.157785 19.890850 -44.491289 1.148626 1.459751 1.532651 0.512772 2.157089 1.450891 1.131460 0.946044 0.918058 0.799922 2.032997 1.586702 2.199834 2.106560 0.457930
+1 0.031111 1 1 0.699573 0.314686 1.628630 -1.884234 -1.069420 -0.683327 -0.578450 -0.357353 2.256950 -2.170251 -1.515047 2.350986 -11.318548 -30.836919 -26.090579 -54.354458 -35.369959 1.181512 0.679455 2.347163 1.019610 2.094086 2.301307 2.069794 1.271717 2.493541 1.936626 1.880417 2.162745 2.001463 0.341787 1.657539
+1 0.041247 1 1 0.065426 1.628815 1.220732 -0.905212 -2.302172 0.816212 0.306860 2.044599 0.841882 -1.790023 -1.017849 -1.014298 67.623350 -4.348374 -33.125880 53.342021 -30.660257 0.521002 0.987029 1.250458 0.699584 0.908860 1.454877 0.614449 1.041358 0.852249 1.755193 1.278171 0.723886 2.104700 0.689710 1.456695
+1 0.049854 1 1 -0.147832 -1.176411 1.242242 -2.236206 2.097762 -1.009725 -1.142565 -0.111155 -2.074022 -0.550718 -0.784386 2.081323 23.275953 -1.051361 29.768470 68.667885 1.136648 2.179554 1.013258 1.079910 0.805187 0.523354 2.258020 1.295961 0.457291 1.184999 0.777708 2.189492 1.536599 1.617759 2.180091 1.041721
+1 -0.057190 1 1 -1.529287 -1.361761 0.963331 -1.056722 0.666419 -0.852081 0.021033 0.074457 -2.100086 -0.354965 -0.020206 -0.312984 -41.371581 67.830878 33.570525 69.805585 72.464498 2.287384 2.055575 0.798464 2.284280 1.643655 0.916380 1.844916 1.745962 1.385547 0.882452 0.877383 1.176996 1.262795 1.037058 0.577621
+1 -0.031128 1 1 0.778959 0.948383 2.169328 0.139224 -2.118194 1.613588 -0.223889 2.297138 -0.595773 0.665150 1.382268 -0.293475 45.489797 -2.983683 -46.751765 -56.915287 -25.232351 0.923031 1.124686 1.851685 0.775360 0.981718 1.987580 1.012043 0.900392 0.896250 1.015293 1.523392 2.401193 2.354274 1.291570 0.917503
+1 0.005065 1 1 1.171432 -0.104465 1.980188 2.135768 1.580428 -1.482674 -0.190645 0.254192 -1.930403 0.512470 -1.163886 -0.299881 68.683494 -36.519542 16.064383 -5.913484 62.074504 1.917912 2.344434 2.393887 1.067087 1.284868 0.783275 1.248536 2.136990 1.144864 1.234223 2.341154 1.271681 1.891442 0.721509 0.401770
+1 0.012957 1 1 -0.090193 1.521626 -0.168555 -0.755287 1.065455 0.028925 0.772364 -1.507373 -0.614818 1.027227 -1.591955 0.956049 -29.754957 8.442003 -15.254526 -32.814547 35.901850 0.660848 2.366260 2.474864 0.787925 0.654803 2.030742 1.928162 1.371747 0.702175 1.701170 2.319185 1.043089 0.687669 0.905514 1.477738
+1 -0.054834 1 1 0.972155 1.152951 0.311409 -1.610219 0.302592 0.993845 -1.859560 -1.059309 -0.394884 -1.769616 -2.049862 0.247624 24.713526 10.226632 -20.997220 49.731736 41.288346 1.873395 1.155610 1.843092 0.353156 1.484803 1.829711 0.444334 1.678489 1.370227 2.160421 1.204022 1.003232 1.311062 2.270437 0.738754
+1 0.023956 1 1 1.136141 0.520602 -1.145146 -1.076419 -0.520379 0.188191 0.920041 1.781121 2.207273 1.703425 1.697126 -0.486823 -42.422720 -48.648104 21.319379 -35.195908 62.373433 0.779209 0.417323 2.204411 0.287536 1.111339 0.265484 1.747085 2.263436 2.319895 1.718884 0.791744 1.839758 0.558150 2.070096 1.848416
+1 -0.026822 1 1 -1.658265 -1.397291 2.278704 0.600906 0.781097 -0.826597 -0.493911 2.066245 1.794037 -2.204676 -0.473097 -1.544492 72.293446 35.943828 57.924118 30.647728 -3.628638 2.327228 1.215605 2.171214 0.346084 1.883231 2.204381 2.036057 1.261794 2.226662 0.760557 1.936315 1.150551 2.311578 1.445578 1.832906
+1 0.012064 1 1 -1.656100 2.017173 1.694994 1.372651 -1.718084 1.689607 0.374071 0.685004 0.491042 1.553388 1.154766 -2.176103 -29.209084 32.922151 -27.413008 69.581354 53.809430 1.751314 1.341387 1.188832 2.192288 1.285603 1.888686 1.639299 1.953086 1.771631 0.794254 1.269018 2.136853 1.081315 1.914439 2.479662
+1 -0.072719 1 1 -1.582133 1.101658 0.590003 1.314158 0.078432 -1.268583 -2.224328 -0.903947 0.108596 1.484500 -2.103870 2.027628 -52.865350 -57.939462 11.463622 69.087085 -3.354824 1.607002 1.382309 0.470589 1.933119 1.430593 1.978551 2.248895 0.930875 2.458491 2.360768 2.435594 2.272895 1.551987 1.499963 2.383628
+1 0.011405 1 1 -2.233604 -1.292355 -1.216619 -0.658521 1.639904 -0.893272 0.446890 -0.674126 -1.458745 1.439515 0.521282 0.850430 15.804626 -21.657525 51.980432 35.120945 27.721209 1.530321 1.859605 1.124554 1.882117 1.494221 0.367837 0.736854 1.807554 1.551451 1.484285 2.133008 1.713576 1.577538 1.185721 1.659181
+1 0.012445 1 1 1.576703 1.889507 0.157052 0.641359 2.087259 1.543960 -1.791960 -0.587885 1.301208 -0.800006 -1.260777 1.740126 38.706841 -4.131527 11.425669 31.219599 7.797705 0.715531 1.178616 1.492807 1.359522 2.228948 0.932198 2.197562 2.167662 1.400312 1.536488 2.008443 0.649109 0.818623 1.341679 1.603578
+1 0.037331 1 1 -1.151917 -1.777376 -0.523482 -0.137730 -1.051424 0.166638 1.524519 1.325981 0.879481 -1.318965 -0.773789 1.123695 -41.655232 -49.488082 3.797932 -68.152082 -32.037251 2.123789 2.018141 1.646446 0.562299 2.065865 0.499669 2.436700 0.612907 2.134968 0.910898 1.970574 0.942511 2.281488 1.965229 1.103227
+1 -0.062566 1 1 1.830030 -0.455290 0.868528 -1.633243 -0.248968 0.196920 1.531665 -1.082577 -0.335026 0.523124 -1.174117 2.102623 18.674255 58.198249 -12.036387 54.449377 -19.327976 2.195700 2.384633 0.781000 1.262674 1.253990 1.559089 1.602996 1.562542 1.139829 2.107407 1.186832 2.343192 1.774224 1.637367 0.977994
+1 0.045606 1 1 -1.746161 1.038360 1.736672 -0.292121 0.624369 -0.725089 -0.330052 -0.707482 -1.297978 -1.464555 -1.974462 -0.141631 -20.470597 50.681518 -45.725292 -54.989302 -55.196914 2.206903 1.663422 2.390760 2.497600 0.408044 1.502250 0.321910 0.586310 0.609074 0.708449 1.403891 0.942569 1.000195 2.022072 2.463080
+1 -0.003772 1 1 0.905627 -0.142749 -0.568542 1.246563 -0.291275 0.716737 1.327498 -1.895364 0.369295 0.523866 1.877027 -2.247751 40.569882 -41.997771 43.464039 0.106525 -9.638790 1.387868 1.644340 1.172651 2.497395 1.462515 0.734287 1.412333 1.085668 0.830681 1.497765 1.438020 0.796710 2.054887 0.479732 0.361598
+1 0.011120 1 1 0.793067 -2.266142 -1.514579 0.803857 0.006960 -0.827376 0.557434 0.571361 -0.991852 -2.342552 0.743604 0.501728 66.081509 31.925899 28.577502 2.074610 67.978301 0.794477 0.524067 0.744146 0.609075 0.725160 1.019953 1.098833 1.582889 1.113316 1.995683 2.191936 2.118992 2.392570 1.416504 1.427092
+1 0.019564 1 1 -2.298498 1.300672 -0.376822 0.195221 1.258526 -1.870598 1.919294 1.270675 -0.308370 0.861468 2.236204 -2.128963 -10.004757 0.053599 0.836429 -42.144249 -18.390849 2.200090 1.912253 1.735152 1.952843 2.182269 1.635917 1.365414 2.262434 1.222519 1.385771 2.411961 1.073149 1.910289 2.469840 1.858157
+1 -0.007276 1 1 1.506615 2.012733 -2.236564 0.800409 -1.398865 -0.611251 -0.294924 0.652866 2.279486 -0.408395 2.054869 -0.914948 -32.160395 -69.760576 -66.006386 30.664296 -25.174637 1.973040 1.875277 1.272882 1.829607 0.952367 1.425102 1.943330 2.054671 1.353813 0.779156 1.773280 1.518067 0.652456 0.828181 2.233310
+1 -0.019107 1 1 0.803656 1.345374 1.663251 0.360973 2.032113 -1.675998 2.166060 1.767959 -2.235667 1.731559 -1.401276 1.272164 36.879727 37.564541 -2.759644 -31.342683 23.525024 1.151092 2.405530 0.988502 1.259899 1.876736 1.050215 1.207691 1.917780 2.376292 2.335510 0.912276 0.373129 1.925615 1.304906 2.298907
+1 0.014787 1 1 -1.318784 2.283527 1.538497 0.644148 1.838140 -0.796397 -1.859877 -1.677758 0.854023 -0.377014 1.685326 -0.892916 54.906990 21.789101 59.416943 70.567871 -15.796416 1.519505 2.322795 0.958712 2.328656 0.468584 1.997684 2.077219 2.328219 2.123997 1.011357 0.624152 2.125104 1.621760 1.928840 1.515706
+1 0.003709 1 1 -1.542711 -0.774834 -2.309676 1.932248 2.222912 0.659826 1.450358 -1.019845 -1.573700 1.458405 2.271601 -0.979395 -10.228784 -15.165302 -33.235630 8.759920 -72.025922 0.779932 1.314662 2.031539 1.830536 0.815697 1.675741 2.426022 1.150441 0.462405 1.637569 2.124305 1.698238 0.286902 1.707658 1.109455
+1 -0.030258 1 1 -0.915271 -1.719083 -0.963918 0.629801 1.043969 1.771584 2.144123 0.632439 -1.744141 1.995007 1.429685 0.244561 36.009156 -44.122365 35.408545 61.416781 -68.160746 0.960145 1.650576 2.478546 1.917202 1.656557 1.761237 1.606029 0.777978 2.222169 1.738522 2.340333 0.967920 1.834720 1.395586 0.866927
+1 0.016855 1 1 -1.680483 2.183826 -1.239818 0.561721 1.922473 -1.854170 -0.011419 1.283065 0.580260 -2.214948 1.237743 2.258058 73.679369 -70.843055 40.771414 45.158189 -26.319282 1.402402 0.671928 1.848017 2.119793 2.356100 0.479615 0.639547 2.112876 0.855638 2.451251 2.171312 1.984826 1.968961 0.824881 0.775893
+1 -0.039018 1 1 -0.432297 0.886937 1.471503 0.928291 -0.940507 -1.747621 0.045889 -1.573493 0.231002 -0.554819 0.970168 0.747969 -48.980584 -16.676575 66.797913 72.527734 73.620298 1.170249 0.370608 2.305839 1.734710 1.276231 1.864153 1.061271 0.279591 0.343166 2.338251 1.976225 1.416817 2.188954 1.491760 1.757340
+1 -0.025835 1 1 -1.151569 -0.636213 -0.429022 -0.615038 2.038434 0.883326 2.029960 -0.152472 0.943277 1.174135 -1.796475 -1.080625 -16.231317 50.248151 20.676287 -43.641168 22.890527 0.941400 1.607796 1.230217 0.260187 0.460347 0.794514 1.149410 1.126494 0.735529 2.038001 2.437757 0.375739 0.791814 0.761923 2.387102
+1 -0.056285 1 1 -2.044312 -0.715977 2.015337 -0.888771 0.707317 -1.485571 -1.754112 -0.646038 -0.612618 0.292141 -0.299264 -1.604705 -40.356836 22.656798 -57.204415 65.402368 17.592871 1.875702 1.677148 1.330002 1.095209 1.424309 2.111887 2.237694 1.681282 1.050450 0.661497 2.025856 0.817913 0.660319 2.476136 1.919210
+1 0.027793 1 1 0.758732 0.286450 -1.697626 1.517362 -1.149420 -2.212147 1.193387 1.321050 -1.896585 -1.310199 0.474141 0.246075 -53.785533 -73.449314 37.375480 -30.301174 -21.825745 2.495644 1.294807 1.318326 0.599800 2.336358 1.668491 2.076690 2.428622 2.091850 0.720231 1.414301 0.399617 1.616951 2.096165 1.249930
+1 -0.027999 1 1 0.374468 -2.065291 0.112503 1.164988 -0.028163 -2.091170 -1.295627 0.338612 -1.505527 2.128235 2.218968 0.340341 -23.463083 5.970873 2.455461 18.931318 28.664004 0.713726 2.339077 2.365585 2.385212 1.509186 2.147758 2.113985 1.496382 0.695059 1.354847 2.406589 0.799055 0.968408 1.031212 1.335922
+1 0.002285 1 1 0.623697 2.116713 1.780045 -1.742358 -1.021378 0.935308 -0.815968 -0.925912 -1.497819 -0.259903 0.191778 -0.065313 8.611921 -9.443689 -20.072259 -4.450471 50.928182 2.124201 2.193680 2.172098 1.700699 1.150304 0.412521 2.482763 0.799706 0.665196 1.191831 0.844807 0.413878 0.540298 1.288073 0.644688
+1 -0.011795 1 1 1.210217 1.441018 2.231787 -0.979692 -0.592009 -2.048634 2.036396 -0.368627 1.285756 -1.310317 -1.503265 -2.251722 15.971246 -71.270295 60.145317 12.338701 -73.447188 2.471660 0.943592 2.456131 0.943180 2.272897 1.582997 0.685564 1.530816 1.179327 2.193133 1.985909 2.169173 2.036786 2.258151 1.237001
+1 0.072607 1 1 0.884398 1.201554 1.925495 1.811249 -0.368645 0.974334 0.079446 1.647719 -1.505817 1.978837 -1.727113 0.736214 -37.711684 -70.274821 -8.911316 -72.491861 -70.701463 1.682569 2.437369 0.615393 1.161591 1.113668 1.171487 0.929184 1.050238 1.603144 1.792024 1.540913 2.124038 1.708440 0.747635 0.757744
+1 -0.011131 1 1 0.227587 -1.405476 1.366894 0.493684 -1.172468 1.546828 -0.714436 -0.356327 0.663302 -1.400284 -0.905456 -1.696840 18.767684 -21.534285 23.277971 32.864210 48.773388 1.139974 2.297250 1.381904 0.407767 1.347576 1.708945 2.487974 0.632989 2.139753 0.320016 0.259910 0.301323 1.079424 1.623416 0.505598
+1 -0.021553 1 1 2.178416 2.096774 1.228306 -0.837003 -1.021446 -0.216962 0.903512 2.009523 0.358525 -1.422914 0.465763 0.806741 43.059553 -48.084821 38.405559 32.238476 32.071304 2.461006 1.886669 1.492905 0.748633 1.779839 1.505049 2.358616 2.257646 1.758021 1.552163 2.200988 1.252217 1.007938 1.657527 2.311754
+1 -0.000479 1 1 -0.594006 2.089305 -1.774780 0.687261 0.737947 -0.334090 2.115622 2.289985 1.698823 -0.249237 0.386309 -0.971849 -23.284994 -0.896032 -59.617712 5.122763 -1.717915 0.280032 1.004581 1.492866 2.354237 0.668746 2.357438 0.462029 2.068003 0.424975 0.313120 1.356227 0.863698 0.666311 1.938724 1.135635
+1 0.020675 1 1 -0.889967 -0.556124 -2.111206 1.250229 0.063439 1.211440 -1.556360 0.730617 -1.007853 2.054750 1.791858 -1.127778 -42.373721 24.867514 48.308725 -25.257516 -3.065160 0.382844 0.961146 0.480324 1.305675 1.734898 2.178407 1.984087 0.805457 0.562000 1.540391 2.356493 0.330508 1.096209 2.486906 0.673954
+1 0.066895 1 1 -1.091955 2.268608 0.556652 1.556136 0.219552 0.207838 1.249026 -1.320418 -1.633156 1.205873 -0.881610 -1.469445 21.303607 -0.282079 59.105014 -72.026929 -56.598473 2.117086 1.866973 1.208968 0.881406 1.287599 1.669299 2.162148 0.968934 0.879619 0.512281 0.652733 0.985919 0.593319 1.416994 0.671076
+1 0.019250 1 1 -0.372616 0.202209 0.892475 0.291042 0.083437 -1.958736 0.265997 -1.453352 -2.174347 0.320793 0.590148 -0.956790 -66.728519 43.787554 37.412391 -9.936188 -47.510788 0.417681 1.465162 2.485936 2.382752 0.664591 2.278200 0.710266 0.434966 1.726965 1.592456 2.151175 1.043313 2.216403 1.579039 1.656104
+1 -0.038005 1 1 1.121187 -1.059414 -2.171769 1.250578 1.207256 -1.188269 -0.131826 -0.784427 1.401719 1.453069 2.138100 -1.637671 23.385316 36.997677 69.965482 59.863218 71.096812 1.736701 0.989595 1.615672 0.849487 0.321659 0.875514 1.260417 1.582666 1.864025 1.167317 0.600792 1.010105 2.085774 2.102400 0.292054
+1 0.019651 1 1 0.017581 -1.404392 0.732260 -1.671673 -0.538405 -1.184449 -1.906438 -1.969191 -1.078967 -0.925791 0.533692 2.077368 7.298846 -28.296467 71.272677 -20.114612 33.716983 1.094941 1.427749 1.423972 0.944782 2.199149 1.845059 1.905324 2.273818 1.303199 0.623133 0.753375 0.481484 0.554487 1.268722 1.668257
+1 -0.010489 1 1 -0.552495 2.335892 0.417187 -0.375026 2.106241 0.129413 -2.087476 -0.466478 1.314482 0.826591 0.396656 -1.430767 13.208849 1.117331 28.978393 -10.143440 69.208611 0.461761 2.070738 1.398659 0.765728 1.095583 0.959255 2.453811 2.452670 1.273097 0.948536 2.288680 1.337296 2.181632 2.190785 0.769489
+1 0.035511 1 1 -1.585683 -2.016178 0.880934 -0.476231 2.331765 1.742816 -0.692748 1.297560 -0.837581 -1.315153 2.032951 -1.728129 -70.474374 -62.797380 -35.571143 55.802906 -70.551932 1.130114 0.822457 0.528095 0.940119 0.329773 2.243105 0.366905 0.822527 1.706687 0.544480 1.824256 1.013097 0.617105 0.683794 1.023055
+1 0.028619 1 1 2.017457 1.756063 0.450821 -0.581237 -0.063756 -1.837118 -0.877025 0.197140 0.523446 -0.473312 -0.447464 0.450788 -35.834792 -25.345711 14.635372 -23.296243 -39.963896 1.777058 2.018054 2.426877 2.014513 1.421109 2.326423 1.183380 0.568052 1.996815 0.964715 1.965506 1.255401 0.521144 1.123921 2.493739
+1 -0.038299 1 1 -0.612800 1.952082 0.996475 -0.070782 -2.107447 -1.552068 2.175148 -0.997355 -0.570226 1.204040 1.304180 2.028954 56.942123 26.256620 -4.983359 -55.320703 74.943568 1.773210 0.345638 1.134103 0.372889 2.400298 0.803174 0.452556 0.359947 0.884877 1.134373 0.406535 0.880022 0.531906 1.998339 1.832893
+1 -0.011323 1 1 -0.855908 1.674638 -1.452679 -0.284140 -1.892490 1.540349 -1.224577 2.252742 -2.203682 2.090328 1.277833 2.177026 72.842064 -43.433707 59.680081 -6.878039 50.794230 2.104294 0.620074 1.084623 1.250264 1.940801 2.296944 0.732795 1.079268 1.255208 1.781450 1.582671 1.943038 1.639942 1.503224 0.927174
+1 0.013381 1 1 -0.148364 -0.691857 2.127473 -1.175648 -0.075494 -1.200514 1.409479 -0.070286 1.515467 -0.000057 -0.951767 2.215154 70.687916 51.805578 -53.656842 -10.536296 66.466749 2.224789 0.783931 1.032507 0.595684 0.658137 1.808790 2.083367 2.145209 2.031912 1.337695 2.132705 1.114020 0.330544 1.708450 0.924997
+1 0.012057 1 1 1.048180 1.857055 1.365329 -2.257010 1.167644 2.199424 1.745569 -1.547451 -0.338206 -1.091121 2.141645 1.406515 61.980271 -47.586744 9.592645 -26.418568 -16.879168 0.802337 2.132472 1.703833 2.065446 2.444191 0.522035 0.348245 2.197052 0.346796 0.349880 0.435710 0.730082 0.495895 2.006517 2.024019
+1 0.035552 1 1 0.340582 -1.390761 -1.067870 1.800497 -2.011121 1.062976 0.775451 -1.467942 -2.345114 0.086922 0.060492 -1.191878 15.027580 -31.456906 53.785125 66.596937 -5.285889 0.775920 1.385541 0.789035 1.309459 2.332968 0.950157 0.294120 1.526034 1.794651 0.696310 2.132518 2.485599 1.210681 0.415319 2.260400
+1 -0.010691 1 1 1.350966 1.395371 -1.562877 -0.408823 -0.421714 -0.310895 0.818890 -1.806662 2.068607 -0.923662 -1.378854 1.129675 7.460075 -18.515115 66.464228 14.288093 -10.028692 2.091667 2.154235 0.722720 0.503437 0.510470 1.715375 0.300767 0.746989 1.143896 0.712127 2.476043 0.350007 0.317443 2.012626 1.201245
+1 0.016216 1 1 1.623671 -0.397453 2.171576 0.219316 0.963939 -0.266524 2.005951 1.585633 1.172454 -1.776190 0.556550 -0.159674 -72.889114 2.655009 72.744597 -31.558144 2.281185 0.473232 1.351811 0.883342 2.329959 2.119679 0.443850 0.292802 1.879852 1.676880 1.322260 1.472679 0.560292 2.083378 2.341113 0.587171
+1 -0.036547 1 1 1.082382 1.765273 -0.251597 -1.579983 -0.458896 1.511480 -1.050190 2.067381 2.022821 -2.338247 -2.307394 -2.116371 -23.579899 -7.368555 56.692511 31.034295 43.404410 2.093900 1.419629 2.197326 0.457870 1.915827 1.056796 1.566283 1.018312 0.518764 1.621121 2.436039 0.755998 1.809858 2.033826 2.006103
+1 0.016522 1 1 -1.566141 1.274422 1.406327 -1.207661 -0.900917 -0.805418 2.040188 2.098034 -1.141692 0.438905 1.787891 -1.823633 -13.472336 70.454106 22.167181 -36.197327 31.517070 2.236003 2.496174 1.203790 1.597165 0.300609 0.332380 1.065087 1.418304 2.429552 1.986138 1.518590 0.443844 2.435984 2.086351 0.547640
+1 0.031328 1 1 -1.382368 -1.386597 -1.770286 0.824875 -0.171678 -1.410408 -1.406923 0.614629 0.508647 0.563924 1.255026 0.570925 35.149336 54.890638 46.952057 -26.781723 29.589412 2.263763 1.061664 2.383478 1.613032 1.481316 1.728217 2.395361 1.090898 0.965399 2.216001 1.582992 0.600969 1.738864 1.341399 1.393857
+1 0.022634 1 1 -2.021812 0.447744 -0.445889 -1.360802 -1.775100 0.029239 1.326899 2.168229 0.518311 -1.957177 -1.797379 -2.142628 29.434589 7.144690 -69.191358 50.851915 -31.870513 1.409375 0.859014 0.694062 0.343863 0.553351 2.418621 0.511280 1.834502 2.216645 1.148855 0.798814 1.415215 2.274764 1.462314 1.864284
+1 0.008356 1 1 -0.669097 -1.752502 -1.875131 1.131138 1.261172 0.191726 -0.939464 1.643485 -1.980639 -0.279171 1.513945 -2.031573 42.222696 -13.149246 -49.371806 8.060337 20.084180 2.197106 1.266338 2.086338 0.332929 1.295370 1.783728 1.623456 1.175351 0.624967 2.326414 1.033067 1.003293 2.340997 0.880281 0.387944
+1 -0.012791 1 1 1.712782 -1.253225 1.427061 -1.450614 1.439113 -1.518705 2.134650 1.646248 2.061968 0.584842 -0.600587 -0.121562 66.521868 -66.956877 -44.228321 54.603919 28.063584 2.344781 1.480641 1.634497 2.249858 1.357986 1.165236 1.628450 1.852267 1.552202 0.604347 2.256962 1.512544 2.323178 0.653076 2.246671
+1 0.003598 1 1 -0.787985 -1.855896 -0.745164 1.553276 -0.722656 -1.851445 -1.336686 -1.722305 1.418552 1.632822 -2.108600 -2.078924 60.228257 56.308592 28.497678 10.477218 -9.395869 1.879405 0.907889 0.897862 1.110612 1.547638 0.396024 1.972088 1.636497 2.108586 0.759498 2.127805 2.023405 2.370091 1.617555 1.005728
+1 -0.016036 1 1 -2.054916 0.120276 -0.142873 2.060224 -0.444614 1.224782 1.198092 0.300929 1.317586 1.157971 -0.140789 -0.619333 16.974509 -9.435598 -34.101224 10.734945 -27.786929 0.401218 1.518092 1.069234 1.360013 1.483533 0.744650 2.337158 1.612229 1.480735 0.965217 1.397311 0.609528 1.587657 2.492075 2.055487
+1 -0.034635 1 1 -0.693565 1.705666 1.670412 -1.803397 0.401479 -0.480268 0.458155 0.163927 -1.618489 -2.036878 1.698195 -1.372211 -10.161394 67.446900 30.043089 34.194414 55.508203 0.270559 1.541155 1.684961 2.141338 2.220400 1.262246 0.816882 1.343250 1.001321 0.702719 1.846752 1.116898 1.448393 1.885830 0.888465
+1 -0.058777 1 1 -0.303475 -1.695154 0.653223 -1.142816 0.390985 2.210393 2.312666 1.186523 -0.945390 1.000818 2.232226 1.696970 50.803260 50.394426 -70.887383 45.753497 -70.969860 1.518451 0.358354 1.100011 1.135339 0.885822 1.266317 1.731369 1.370779 2.438179 0.727670 0.449020 1.671976 2.142877 1.077748 0.454932
+1 -0.006409 1 1 1.448917 -1.673454 -2.201585 -0.366654 1.457209 1.023945 -0.199922 -0.148784 1.657394 0.894807 1.793852 -0.596257 62.441993 62.568301 -64.566995 72.508566 51.468156 1.004489 2.192893 2.452985 2.062711 1.492061 2.324495 0.295947 0.723957 1.050268 2.099534 1.609121 0.997375 1.873318 2.103664 1.288768
+1 -0.039447 1 1 -0.857443 -0.558874 -1.212393 -0.322224 -1.078051 0.325522 -0.036380 1.179541 -0.476405 -0.586067 -1.141679 0.649974 25.524564 -8.659206 -35.266586 74.489063 37.680684 1.363802 2.168999 1.365997 0.802922 0.714166 0.741934 1.683629 2.258805 0.977196 2.485268 2.402384 2.113757 2.166071 1.654626 0.798506
+1 0.024045 1 1 -1.417773 2.041793 0.803883 0.448167 1.936721 2.001638 -0.222544 1.338241 -0.416381 -0.223643 1.720389 -0.643494 -8.406980 3.880454 -31.216532 43.743632 49.222199 1.787532 0.301825 0.519259 0.935314 0.573170 0.274630 2.448492 0.802721 1.832734 1.768455 1.431642 1.602744 1.812477 1.050320 0.731919
+1 0.007133 1 1 -0.860737 0.632011 0.476765 1.933357 2.012260 -0.759029 -0.560247 -0.726161 0.496031 0.575047 -0.295769 0.573222 64.302933 -10.598782 66.277955 33.589731 -57.388380 0.977460 2.427468 0.711707 2.161003 1.979050 1.641978 1.968911 2.228770 2.442732 0.748242 1.958125 0.954145 2.070129 2.401684 1.602397
+1 0.005614 1 1 2.109988 1.834114 2.220480 2.197152 1.251710 1.390751 0.900504 -1.416355 2.308227 1.979820 0.648994 -1.532849 1.377047 44.020409 51.011036 -57.515612 -64.891728 1.595987 0.746557 0.627511 2.334264 2.470256 2.093673 2.108635 1.575039 1.924365 0.559300 1.163100 1.727955 2.483520 2.266654 2.411198
+1 -0.009567 1 1 -1.531640 1.498630 -0.240884 -0.600220 1.325565 -1.408935 -0.216365 1.518931 1.664009 -1.037864 1.882186 -0.366716 13.105112 57.610441 8.685261 23.173077 69.909575 1.678457 0.834745 2.312072 0.748976 0.796543 1.493486 1.528169 1.684351 0.891563 0.999425 0.335553 0.391547 0.978650 2.174043 0.647511
+1 0.010257 1 1 -2.280178 -1.804557 -0.252431 -1.459216 -1.772215 1.395208 0.413540 -0.405409 0.401909 2.038765 1.739030 1.641494 72.174426 -14.424500 -32.575874 -2.710196 49.742599 2.482946 1.622182 2.270065 1.229218 1.463597 0.925941 0.537667 2.063507 1.355237 2.211434 1.320256 1.549623 2.266815 0.611765 0.936061
+1 0.051098 1 1 -1.133717 -2.189002 -0.943124 1.392812 -2.154427 0.543554 -1.809365 -0.954243 -1.694171 -1.681030 -2.306454 -0.462503 68.517812 28.866494 59.157722 63.835111 -73.281220 1.562927 0.865608 1.268104 0.265280 0.565837 0.769052 0.701130 2.140071 1.180367 1.674849 0.936942 0.932629 0.449225 0.622947 2.112487
+1 0.037507 1 1 -1.371647 -0.268789 1.644383 -1.008293 -0.622244 -1.262509 0.893157 2.329695 -0.058292 0.459005 0.312908 0.012362 13.464183 -57.477005 -16.031323 -38.442865 -59.229266 0.380834 0.934970 1.544950 2.478337 0.655707 1.472347 1.732202 1.872751 1.570924 0.263983 1.257103 2.133208 0.572856 1.733307 2.446844
+1 -0.006081 1 1 -1.474024 -0.890469 0.443139 2.267655 -1.327759 2.231429 -2.280069 0.026838 -1.327111 -1.018682 -0.878742 -0.382738 -8.389286 1.271529 70.580005 38.139592 62.125106 1.174745 1.689889 1.712564 0.317770 0.759273 0.596765 0.829117 2.227056 0.629746 1.645442 1.690923 1.089241 2.367264 1.354799 1.601121
+1 0.019293 1 1 -0.167319 1.165150 -2.012103 -1.310955 1.916978 0.040600 -0.938986 0.246129 -0.793627 2.280685 0.903286 -1.789541 -74.990634 -67.587844 1.109813 52.625575 -71.964117 0.611266 1.555939 0.410772 2.349904 2.088631 0.624261 1.696895 2.461933 1.713319 1.758815 1.398081 2.297103 1.166791 0.760063 0.372316
+1 0.011622 1 1 -0.455573 0.816569 1.596874 1.604265 -1.411617 1.827305 0.870198 -1.831736 0.043146 -0.553490 -0.242654 -2.077595 21.331776 23.162390 40.292053 -61.468724 -54.842961 1.440232 1.980045 0.361333 1.672654 2.294496 2.339808 1.156017 1.933490 0.912095 1.831804 1.874027 0.515602 2.472304 0.520408 2.241110
+1 -0.012964 1 1 1.558215 2.178843 -0.163669 1.249858 -1.461543 1.523370 0.878530 1.542980 0.590940 -1.788252 0.474352 -0.932903 -37.385906 5.075418 -47.443661 14.390953 68.745058 0.597772 1.999202 0.579105 1.021874 1.886439 2.129611 0.875077 0.663769 1.969016 1.747856 1.724555 1.597581 0.536583 1.842833 0.487785
+1 0.001251 1 1 1.916789 1.587243 -0.039490 0.745447 -1.506960 1.614553 1.847287 2.127764 -0.992615 -1.018693 -1.068346 -1.493772 56.566503 13.222296 -72.875126 -62.236945 -66.330688 1.076849 1.098539 1.136164 1.253364 2.290243 0.612865 1.424872 0.322958 2.455185 0.792729 0.394078 0.774554 0.936392 0.690161 2.279464
+1 -0.027564 1 1 -2.170206 -0.764300 0.386935 0.124792 0.360526 -0.773079 -1.079920 1.905728 -0.545779 2.113535 0.191616 1.933675 -66.110469 -68.658368 8.801861 32.870895 11.139702 1.749567 1.215043 1.732965 1.192784 1.116903 1.534538 0.722264 1.836246 2.286515 0.960926 1.289215 1.829227 1.313719 1.924601 2.268935
+1 0.005571 1 1 1.712989 2.224717 -1.982365 -1.011920 -0.329255 -1.443201 -1.214967 -1.174596 -1.234206 0.630379 1.329009 -0.060718 66.929681 37.153486 -11.353277 -14.529886 -3.791632 1.735520 1.377942 1.325567 0.802393 0.823303 1.255959 0.898043 1.902500 2.069946 1.588911 1.071501 1.211005 1.358715 2.172810 2.415324
+1 -0.007508 1 1 0.523102 -1.546725 -2.262338 1.149469 -1.669574 1.754695 1.028886 -1.982082 -0.968296 -2.275435 -2.197518 2.019674 42.391613 -24.161189 -27.105131 -5.932042 50.163949 0.707395 1.693588 0.884473 1.083192 1.950567 2.182389 1.418739 0.740506 2.438821 0.257785 0.598017 1.621018 0.691764 2.231848 2.418292
+1 -0.014573 1 1 1.392387 0.122243 -0.059381 1.012760 0.299400 -0.821843 -0.708664 -2.303326 0.272797 -0.261105 -1.158665 -2.093554 33.299803 19.790462 68.302374 8.001843 -63.027151 1.414976 0.494605 0.571577 0.487139 1.101414 2.215324 1.456572 2.107702 1.648015 2.186323 2.271596 2.207894 0.326393 1.680508 1.554781
+1 0.010629 1 1 0.666863 1.908226 -0.959049 2.353213 -0.621433 -1.771779 -0.710777 -0.129184 1.208856 2.130317 -0.498098 -2.328838 10.523392 16.655558 29.969476 -3.019562 -49.770386 2.261851 0.429020 0.784961 0.336651 0.835842 0.492438 2.408386 1.742313 0.805716 0.425346 2.040730 1.052315 0.514083 1.687260 0.284029
+1 0.013188 1 1 1.795541 -0.480710 -2.250003 1.117773 -1.890119 -1.011902 -0.028749 2.184857 1.952537 -0.791597 -1.293345 1.004779 -59.766376 56.524246 52.996895 18.810905 -45.114169 1.617401 0.655816 1.046022 0.490098 1.319211 1.984052 2.454151 1.415084 2.316783 1.172870 1.674082 1.547704 1.513759 2.488609 2.293995
+1 0.010906 1 1 2.354921 -0.201323 -0.144549 2.158254 -2.192549 0.708041 1.262007 0.080364 -1.783779 0.248762 1.059656 1.513365 74.974443 -54.535015 -70.003551 50.321704 56.877139 1.136061 1.780432 2.469641 0.757013 0.870905 0.295862 1.544590 0.929215 1.560416 1.406940 0.436162 1.567063 0.621943 1.000919 0.695033
+1 0.005657 1 1 -1.866347 -2.034106 1.166163 0.875542 -1.557830 -0.409009 1.168265 -1.499453 0.546572 1.786681 1.409562 1.325877 -27.584979 29.259750 68.613434 -14.008536 58.531562 1.974314 0.801271 2.217619 1.774106 1.897742 0.842839 1.086828 2.309770 0.306364 0.302458 2.153305 0.845918 1.093380 2.192118 0.668065
+1 0.027206 1 1 2.047150 1.295646 -0.033607 0.645554 1.905638 -2.046536 -0.410775 -0.240843 0.090338 0.918156 -1.625456 -1.323446 -21.587925 21.737756 -53.527140 69.355638 10.212505 1.998590 1.548179 0.497618 1.711663 0.912088 1.713680 1.074190 1.414474 1.065863 0.964493 0.490111 1.544787 1.981950 0.888550 2.108511
+1 -0.057777 1 1 2.303984 1.349729 -0.544429 1.244479 -2.333658 -0.582943 -0.458344 1.361841 0.395582 -0.633414 -0.507604 -1.868094 50.574948 -36.843117 -22.262825 -71.297439 53.948601 0.836938 0.910055 1.292739 0.307014 2.226881 2.194693 1.212595 1.077388 1.158117 1.215122 0.811783 1.132104 0.516644 1.979149 1.056394
+1 0.012604 1 1 -1.112274 0.057899 2.354577 -1.259282 -1.420641 0.965523 -1.914474 -0.372030 0.624261 2.183935 0.597219 0.077416 16.358984 -4.559407 20.050836 -55.598125 62.320297 0.883421 1.412422 0.322724 0.766770 0.603713 0.600323 2.135230 0.809304 2.227320 0.561275 0.602991 1.970312 1.032765 0.426487 0.974353
+1 0.039180 1 1 2.056266 -0.988999 -1.516076 -0.804820 -2.046713 1.327539 -1.217419 0.028220 -1.657816 1.437479 -0.705112 0.839884 74.122517 27.147860 -25.913662 69.083188 -68.863883 1.445781 0.733884 1.382600 0.859009 0.619433 1.565284 2.228801 0.710288 0.809288 1.949180 1.372707 1.084347 1.117936 0.901106 1.640704
+1 0.010850 1 1 0.996975 -1.088559 -1.924573 -0.453166 -1.134966 0.377570 -1.764706 0.357064 2.304197 0.218033 -1.765997 2.231825 -10.681426 27.276244 31.832778 -36.496386 -44.763536 2.263829 2.176370 1.494874 2.351270 0.290281 2.249458 1.392791 1.132063 2.077590 1.813436 1.424815 1.610115 1.953030 0.820163 2.482273
+1 0.004708 1 1 1.229965 -1.227572 -0.959300 -1.874591 0.779061 -2.056900 -0.235877 -1.257771 0.420164 -2.169904 -0.394206 0.196123 72.708400 -39.917088 63.510130 14.757502 -70.668117 1.089440 1.212104 1.823349 1.520425 2.028997 1.858063 2.212195 0.610318 1.371643 1.196789 0.926245 1.156963 2.081687 0.908031 1.025914
+1 0.037815 1 1 -2.351198 1.510994 0.205470 -0.854648 -0.705022 2.354251 -2.039197 0.429395 2.169156 1.960778 1.055845 -1.270251 -63.120190 -61.035322 29.350654 -53.550542 -23.966375 0.581974 1.982506 1.232730 1.993367 1.518641 1.298601 2.085516 2.271614 0.271798 2.109768 0.376574 1.323598 1.454987 2.462988 1.444806
+1 0.000162 1 1 0.724343 1.934279 -1.338837 -0.171340 -0.444577 1.841800 -0.558707 1.606451 2.338794 2.081043 0.741310 -0.353417 -72.018510 -65.105151 27.721140 9.198405 -52.401225 0.514259 2.398762 1.998831 1.099540 2.224223 0.273625 1.310791 2.221155 0.446529 0.307042 0.450590 1.065281 2.424832 1.408585 1.093887
+1 0.016879 1 1 1.707428 -1.701542 1.680352 0.326257 -1.811365 -1.580584 -1.140111 -1.269271 0.346695 -2.330217 0.702909 -0.167533 72.863192 11.665493 11.934381 31.141392 43.377380 2.029458 0.605763 1.315376 0.526716 0.267102 1.941122 0.939572 2.392457 1.770137 0.446220 1.872538 2.492443 1.497843 0.502116 0.813450
+1 -0.008163 1 1 -0.111954 -1.373488 1.783492 -0.355600 -1.261236 -1.265734 -1.472942 -1.561431 0.328985 1.623518 1.735412 2.096280 74.864316 44.554090 20.598402 -2.660124 -8.709828 1.583744 1.991193 0.987045 1.518578 2.486899 0.563790 2.370421 0.420852 0.754643 1.530234 0.392096 1.204091 2.150462 0.310621 2.115493
+1 -0.001058 1 1 -0.678948 2.324499 2.152098 -1.985031 1.298435 -0.272326 -1.253458 2.218015 -1.537321 0.274715 -1.012486 -0.419711 11.391010 48.698239 71.303537 48.541227 -17.601433 0.965693 0.405313 0.593774 2.309268 0.861598 1.371753 0.804379 0.453146 1.269088 1.055161 1.095023 0.543528 1.583381 0.379558 1.983671
+1 -0.010553 1 1 0.785842 -1.181645 -1.893481 -0.975426 0.414893 -1.224749 -0.648678 2.142115 -0.127780 1.250131 -1.586133 -0.158217 -43.427346 16.588676 -44.115114 7.275680 32.354184 1.776595 0.986121 1.727410 2.330436 1.139972 2.258193 1.942572 0.559407 0.704093 2.434047 1.022155 2.106831 0.515383 1.041303 2.175012
+1 -0.014108 1 1 2.140885 -1.946905 1.190671 -1.905862 -1.717934 -0.501419 -1.600955 0.486385 -1.317248 -0.179896 1.836994 -1.209180 58.746221 47.739904 14.561642 -62.489507 38.850894 1.629560 0.266643 0.974361 2.088152 1.572799 0.283311 2.113968 1.209614 0.486079 1.281335 2.142443 0.541517 1.530122 0.757668 0.634115
+1 0.008700 1 1 -1.491645 -0.176726 -1.431355 -0.033528 1.982966 1.692692 0.384108 -0.270657 -1.473933 0.641564 0.818808 1.537630 6.708139 -56.315100 12.113159 35.857905 -36.192451 0.827187 1.276951 0.463929 0.250376 2.070147 0.466011 1.488813 1.735447 2.401928 1.200863 1.906362 1.727500 1.585875 1.808326 1.031042
+1 0.000167 1 1 0.228849 0.955909 1.426821 -0.764991 -1.813957 1.987815 -1.622791 1.055869 -0.863676 -1.640971 1.819782 1.671604 -19.646758 -53.055863 40.108954 11.196231 -74.947974 2.115958 0.904171 1.402294 1.099961 0.298244 1.084194 0.793364 2.065896 1.019408 0.946788 2.167848 2.266917 2.317176 1.026439 2.116668
+1 0.013131 1 1 1.810458 0.478454 2.041713 -0.549461 1.488964 2.232198 1.216596 0.278021 -1.995031 -1.840428 0.055399 -1.962872 46.144480 50.282996 6.314499 -72.222871 -49.795739 0.370263 1.003195 0.691865 1.678137 2.201379 1.077382 1.067006 2.167962 1.932424 1.006593 1.556849 2.215781 2.386494 0.560753 0.833421
+1 0.002715 1 1 -2.249856 -1.121088 -2.001448 -1.305253 -1.220758 0.455781 -2.030805 0.095842 -0.827615 1.246745 -1.957044 0.443725 -64.416827 46.385865 57.232159 -49.099069 -58.060623 0.251527 1.169491 1.141157 1.928220 2.340155 2.477697 1.159120 2.331234 1.046361 1.681028 1.291669 0.321776 0.594941 1.679426 1.355943
+1 0.002566 1 1 -1.281265 1.403710 1.942288 1.313094 1.057976 1.563081 -0.874602 -1.490033 -1.342089 1.713385 -0.544202 0.341260 18.323265 9.118203 -50.353238 13.136005 -23.162004 0.868034 1.547880 2.217090 1.877960 1.373759 0.773659 1.641684 1.534635 2.362555 0.966458 2.016869 0.513488 0.693859 1.445033 1.671369
+1 0.030414 1 1 1.735554 -0.236738 -1.604580 0.821787 -0.232869 2.170467 0.442213 0.830277 1.088903 -1.719088 -1.055603 0.615941 -31.994065 25.757086 -0.653284 -29.749417 -48.455117 0.847752 0.413178 2.287056 1.046267 2.357687 2.401465 2.417152 0.564933 1.332113 0.576496 2.168741 1.531759 1.274502 2.053439 0.892862
+1 0.062360 1 1 1.068572 0.572924 1.720965 -0.391130 0.059596 -2.117017 -2.161313 -2.100399 -0.894932 0.815957 0.740918 -2.241675 -9.171444 55.536265 -51.990451 -53.503714 13.074449 1.258889 0.652521 1.917054 1.421353 1.923145 0.303006 2.368461 1.231683 2.391097 1.425288 0.568564 1.605770 0.926677 1.658486 0.419291
+1 -0.004331 1 1 1.521983 1.127729 0.507549 0.946219 -1.205046 0.636112 -1.273659 2.004885 -2.184092 1.469850 1.433412 1.619179 -16.344944 -59.481430 45.608339 39.358313 -4.830404 0.856067 0.666304 1.825707 0.664206 0.303742 1.246571 0.614916 2.151529 0.252100 1.786775 1.070015 0.982997 0.975754 0.741622 0.940275
+1 0.022248 1 1 0.391292 -2.052904 0.962334 1.020841 -0.540301 -0.060055 -0.886779 1.197642 2.147973 -0.622225 -0.950940 1.982823 -22.779223 -50.408327 -12.746175 -24.958926 65.331162 1.687501 2.078927 1.777096 0.405846 0.552961 0.370133 1.081647 0.743709 2.269612 0.363200 1.549470 1.946892 1.160001 1.394326 2.189699
+1 -0.024510 1 1 1.931461 -1.575956 1.253876 0.091903 -1.042470 -0.126875 2.324269 -1.720470 -0.716600 0.968374 -1.125986 0.511507 47.729175 -15.753210 -14.205653 45.590713 43.121236 0.454299 0.400199 2.392190 1.786432 2.059122 1.911367 0.343152 2.112640 1.386406 1.832194 1.681601 1.910607 1.070876 1.960244 0.569528
+1 0.015343 1 1 0.543112 0.186494 0.663682 0.284798 -1.191288 0.970391 -0.221710 1.224002 2.226719 -1.322498 1.109947 -1.470314 6.554626 63.590399 13.840034 -40.553367 19.564261 1.623074 1.498421 1.207375 1.108584 1.225220 1.775178 1.910995 0.847176 1.980247 1.519232 2.224047 1.814782 1.535953 2.006342 1.333666
+1 -0.011638 1 1 -1.753049 -1.638601 -0.771600 0.220986 0.741584 -0.468971 1.836846 1.005266 1.589256 0.800134 -1.302304 1.217744 22.997393 -32.807758 0.018531 11.455647 -64.932836 2.482455 2.373831 1.477461 2.179261 0.583861 2.194622 2.259930 1.895675 2.110564 0.251987 2.152752 0.557119 0.502798 1.026121 1.266478
+1 -0.019495 1 1 -0.121214 -1.483888 -1.747842 1.049424 -0.794012 0.523095 -1.653827 -2.195124 -0.159895 -1.292503 1.019292 1.700509 -5.726441 55.707506 -23.943724 27.825357 -39.216718 1.144299 0.735011 2.324253 0.717696 1.566396 0.667320 0.893639 2.146611 0.836012 1.097210 1.309487 0.545354 0.768450 1.834358 2.055153
+1 0.004705 1 1 2.123994 1.620336 0.097563 -0.168296 -1.112264 0.233968 2.172682 -0.034965 1.386670 -1.716809 -0.448188 -2.299408 4.894608 63.673029 52.592866 -21.698077 -29.576978 1.370874 1.782088 1.049181 1.834431 1.034530 0.852489 1.281936 1.002664 0.779307 2.069413 1.627839 0.592912 1.328974 1.816740 0.693865
+1 0.002281 1 1 0.367658 1.294235 -0.182501 0.463606 2.242785 0.094000 1.213897 2.031622 -0.498231 0.149712 -0.198552 -0.696128 32.993405 -29.839984 -70.613892 -7.680527 63.379251 2.350949 1.655118 2.326846 1.549399 0.743276 1.746447 0.540727 1.750573 2.384881 0.441574 0.283344 0.410421 0.941058 0.360885 0.900846
+1 -0.033131 1 1 -2.172329 1.261175 0.244687 -1.466009 1.875535 0.948533 -0.025866 -1.193834 0.588840 0.618351 1.800025 -0.519055 -35.592172 2.370723 -55.257358 -60.411551 13.058723 1.794254 0.779030 1.906568 0.689424 1.142621 1.772151 0.539047 0.516600 1.243607 0.306220 2.387162 0.526506 1.237435 2.326167 1.394980
+1 0.006188 1 1 -0.224518 1.142558 -0.018998 1.146368 -1.952418 -1.931437 1.992156 0.649643 -0.063342 0.414491 1.438211 2.173319 39.538351 21.059568 -51.833329 37.240844 -43.140100 2.040020 0.360143 1.917186 1.398880 2.228216 2.117500 2.066372 2.260452 1.671532 1.431627 1.356266 1.510031 0.583007 1.348652 1.798130
+1 0.072137 1 1 0.736930 1.423900 1.969500 1.573497 -0.167456 -1.143483 -1.403849 0.449813 1.340615 1.780601 -1.825795 0.944311 -9.464210 -64.970960 33.071405 -68.894567 -60.986985 0.501198 1.143241 0.953954 1.098783 0.750778 1.818374 1.154419 2.071935 1.257159 0.823440 1.312341 1.262097 0.568418 1.397261 2.013981
+1 0.024349 1 1 -0.761432 1.455645 -1.705468 1.656245 0.429690 -2.286143 1.620192 -2.320422 0.394994 -1.094044 0.139960 0.826733 -61.439087 -6.730168 -13.932820 -18.910189 26.461023 1.081209 2.383678 0.476344 1.911930 0.814983 0.911704 2.016270 1.705091 0.716418 0.335284 0.367710 0.848659 2.157682 2.405006 1.183643
+1 0.003144 1 1 0.923501 -1.326102 1.810876 -1.936224 1.634296 -0.898127 -1.031338 -1.538261 -1.382842 0.081902 0.512874 0.916523 -25.611138 53.601373 -21.729853 36.362540 45.214958 1.792001 1.155797 0.478328 1.509548 1.471269 1.613909 0.466874 0.259573 1.396438 1.687134 0.414904 2.042652 1.859802 2.199671 1.625441
+1 -0.050847 1 1 1.214262 -1.253704 -1.907335 1.804561 0.326931 0.075338 -1.419247 0.835008 0.480964 1.807611 -0.259950 -0.593343 -28.544077 -40.302912 28.955054 47.585237 -34.924254 1.045895 0.611992 0.254433 0.501768 1.718192 0.394915 1.334372 0.297813 0.594311 2.335335 2.478632 1.117083 2.321038 0.680805 0.294869
+1 0.006157 1 1 -0.439991 -1.187703 -0.046201 1.036218 -1.269151 -2.353510 0.356708 1.036422 2.153543 -1.256037 1.281849 -1.004782 58.154535 3.268286 30.086999 22.194425 -28.298376 1.962933 0.761604 1.521151 0.743481 0.680760 1.782156 2.188822 1.525221 1.631325 0.670774 0.449596 2.354061 2.204620 1.544592 0.963623
+1 0.028597 1 1 0.799749 1.651352 -1.705386 -1.680044 0.137292 -1.599162 2.344592 0.559612 -0.523167 0.455013 -0.801030 0.390812 -22.239085 27.697127 55.618370 -22.061067 19.649223 0.542395 0.524309 0.309436 2.440059 0.825695 0.951229 0.298798 1.397839 0.483539 1.339889 0.770502 0.323395 0.794191 2.459729 0.661650
+1 0.024602 1 1 -1.635294 -1.731389 -0.451331 1.421580 0.690004 -0.285339 1.520941 -2.246781 -1.273512 -0.242569 -0.638096 0.912417 27.861979 -23.713082 4.237791 -25.442726 34.111123 1.459764 1.751869 1.669102 1.101065 0.855749 2.074972 0.547593 2.399519 1.220357 1.045149 1.568391 0.438900 0.338996 2.005016 1.547086
+1 0.032458 1 1 1.051233 1.332982 0.738367 2.015918 -0.550991 -0.658284 0.902723 -1.833417 0.068262 2.174368 0.033596 -0.841760 -27.813286 -57.903834 10.270090 -40.589177 17.693769 0.312557 0.890437 2.328921 0.424854 0.529066 1.513933 0.929472 1.393649 2.065639 1.190507 1.094255 1.141048 2.352572 1.934737 1.618696
+1 0.030227 1 1 -0.145253 -0.254961 -1.569102 -1.368769 0.975990 -0.367772 1.511744 -1.324553 -0.438675 2.073908 -1.372326 -2.247326 -32.157051 -13.552766 68.657390 -25.252497 -68.724683 0.538800 0.855761 2.283536 0.398109 1.025750 1.787723 1.259259 2.361747 0.880877 1.404836 1.074935 0.428070 0.565517 2.136460 1.238681
+1 -0.022499 1 1 -0.662307 -0.736325 -0.677553 2.204863 -1.090143 -0.259805 1.836371 -2.265768 0.046842 0.300296 0.107610 -0.950173 22.957117 40.264912 -67.622004 26.982234 40.409190 0.733747 1.327627 1.671757 0.712474 1.544993 0.951834 1.469226 1.022949 1.955673 2.490862 1.924465 2.232962 0.887557 1.170501 2.355581
+1 0.002472 1 1 -2.346493 0.476895 -0.599186 -0.150876 -0.511306 1.871568 0.251976 -1.470412 -1.441661 1.113661 -0.302967 2.131417 -27.055276 -68.021384 64.607027 0.300529 -49.011742 2.269804 1.351485 2.163919 1.488635 0.990487 0.863081 1.556390 1.237803 1.758539 1.269768 1.236294 1.136082 2.132284 0.796867 2.444384
+1 -0.011281 1 1 -1.800108 -0.886292 -0.047765 -1.680471 -2.332136 1.447467 2.229652 0.841463 0.588291 0.820913 -0.792149 -1.146915 69.394630 65.553144 1.685930 -14.580986 37.371954 2.281458 1.459876 1.392478 0.371046 0.673143 2.009468 2.123746 1.299275 2.170414 0.391146 0.998610 2.396570 1.152257 1.732580 1.472711
+1 -0.037733 1 1 -0.489684 -2.283439 -0.070711 -0.922685 0.897933 -2.229191 2.192169 2.326642 0.473156 -2.177091 1.322872 0.458776 37.445001 -61.872767 54.409744 64.560345 -34.280859 1.249157 1.334377 0.379221 0.817499 0.452995 0.992642 1.078695 0.629754 1.777142 1.175937 1.476701 0.667021 0.378678 0.691569 1.196669
+1 0.002036 1 1 0.026987 1.185547 1.516434 2.113606 1.383644 -0.738954 2.256679 -2.011288 -1.750372 0.937768 -1.869379 -1.164017 70.206178 55.227789 13.449234 -8.722242 -44.721410 1.633928 1.686635 1.026400 1.454223 0.868637 0.428035 2.231626 0.944007 0.425816 0.940611 1.842018 0.298168 2.055210 1.420910 1.233045
+1 -0.068173 1 1 -1.537998 -1.684017 -0.671013 -0.967891 -0.184626 -2.260890 1.926149 -1.316896 1.011314 -0.439921 -0.006887 2.052522 65.323960 49.792728 16.381495 73.794676 67.111935 0.629431 0.849594 2.127549 2.213786 0.343783 1.463369 1.590646 0.990547 1.875477 2.390050 1.825466 1.113654 0.941298 2.139759 0.436502
+1 -0.002861 1 1 -2.270872 -0.907524 1.250141 -1.422640 0.346079 1.455552 1.444941 2.182132 -1.439269 -1.109870 -1.951982 0.698054 -52.464842 73.402169 70.248068 9.286402 -73.436964 0.549120 1.066246 0.645791 1.305789 1.390386 1.216570 0.400783 0.967739 1.034485 2.338226 1.570964 0.942840 1.061962 0.649954 1.520636
+1 0.003968 1 1 1.381152 -0.207850 -1.454932 -0.448948 -0.932804 0.473215 -1.189421 -0.647065 0.979629 -0.470455 0.443590 0.422897 42.783679 -34.713199 -74.727277 8.654814 -38.539989 0.750998 1.019925 0.635162 0.409515 1.464903 0.383280 1.530147 1.186737 0.746043 0.996069 2.431352 0.734284 1.363291 0.337004 2.268830
+1 0.003640 1 1 2.098177 1.259218 0.337449 -2.213542 1.309814 -2.240398 2.326812 -1.388966 0.814715 -1.287249 -0.209698 0.471438 61.546782 16.770979 19.847405 -24.661018 -27.727973 1.764250 0.504057 1.930897 2.334936 0.262609 0.673789 1.614916 1.639723 2.327346 0.956146 1.946290 2.303619 0.425821 1.024818 1.872850
+1 -0.043620 1 1 0.504920 -0.822459 -1.626727 0.873912 -0.674163 -2.072295 0.201836 -0.657475 0.362251 -0.048997 1.180891 -1.355750 -53.893528 61.470084 -72.297779 41.222805 -18.311246 2.018247 1.175552 1.745376 0.528917 1.264958 1.400643 0.353062 2.161215 1.046066 1.238142 0.701002 2.240747 1.233760 1.307636 0.935812
+1 -0.054957 1 1 -1.835162 -0.982290 -1.841810 0.381347 0.442387 -0.953326 -0.424565 -1.107202 0.472513 1.143056 -1.066833 0.371227 0.081108 13.177627 -73.617249 64.896758 69.819350 1.432203 2.037260 1.222252 1.392909 0.875650 1.303751 0.890343 0.746969 0.810199 1.519686 0.854118 1.655007 0.454358 1.390319 2.336421
+1 0.018836 1 1 1.028602 -2.038245 2.283932 -1.077256 -0.441951 -1.150484 -1.245695 0.745629 1.540324 -1.638196 1.327729 1.972963 -47.647231 42.989540 -24.794310 -17.963563 36.396341 1.574520 2.214967 2.191366 1.531415 2.248272 1.700629 2.212731 0.618548 2.431173 2.228688 1.064591 2.074897 1.544742 1.231740 1.103676
+1 0.043276 1 1 1.897773 -2.296415 -1.375529 0.459401 2.255824 -2.249483 0.436238 -0.623326 -0.602316 -0.920217 -0.026801 1.940403 -66.292491 22.106631 -3.860514 66.347925 9.574889 1.002377 0.446004 0.487972 1.593630 1.636216 1.880851 0.458396 1.764886 2.183676 0.536041 1.744937 2.149815 0.696985 2.228105 0.252865
+1 0.062410 1 1 -0.634760 0.433702 -0.838876 0.480830 -0.440538 -0.961869 2.075636 -0.595578 -0.759529 0.461403 -1.797473 0.992549 -2.591902 -62.095860 54.874886 -67.784275 -0.311011 1.717597 1.647376 0.444772 2.275049 1.754077 0.526030 2.236970 0.762811 1.571294 1.984127 1.466141 0.936115 0.541579 0.318667 2.341964
+1 0.019007 1 1 -1.812159 -0.786520 -0.785902 0.173136 -2.351518 0.845668 0.584805 -1.226197 -1.419826 0.520242 2.221576 1.764772 23.902266 25.389857 -22.676783 21.302907 -12.039242 1.471942 1.673167 1.918613 0.623350 2.145408 0.867348 1.263592 0.942214 1.783255 0.422209 1.070260 0.614251 2.222985 1.961615 1.104188
+1 -0.025971 1 1 1.447982 1.458866 0.593471 -1.664056 0.243671 0.310348 -0.599362 1.605472 0.029405 -0.589143 -1.004930 -0.654442 -15.550991 -65.506190 37.468014 24.911489 37.399341 2.435900 0.675421 2.046731 0.664054 2.261906 1.351044 1.501782 1.449658 0.657884 2.050678 1.740127 2.318549 1.608011 0.334918 0.960801
+1 0.031556 1 1 -0.397293 0.153484 1.923199 0.922506 0.801951 0.958679 0.852376 0.217691 1.913733 2.062780 0.098660 -0.589795 69.201767 -25.896169 63.086227 -59.775833 47.570686 1.682796 1.745757 2.435597 2.328523 0.489701 1.403692 2.104104 1.919173 1.043303 2.046244 1.467334 0.724090 1.029398 2.336966 0.633805
+1 -0.010335 1 1 0.780987 2.045878 -1.234580 -0.941737 1.144757 -0.752977 2.185220 -1.364543 1.314574 -2.353692 2.012040 0.248232 49.775903 33.603817 29.356160 38.973578 -21.081168 1.207167 2.098375 2.396091 2.104317 1.011001 1.397140 2.236108 2.014891 1.020452 0.494152 1.957848 0.797816 0.386922 1.992823 1.371809
+1 0.022983 1 1 -0.966684 1.262555 -0.121350 0.927944 -2.050136 0.348278 0.723711 0.736400 1.945850 -0.070168 -1.212213 -2.005031 -8.574389 40.240442 -28.894969 62.253537 45.189703 2.175171 1.599765 1.242669 0.290727 0.745962 1.876239 1.701138 1.773754 0.477326 0.419357 0.389845 1.629811 2.241087 2.442036 0.300716
+1 0.006683 1 1 -0.356208 -2.054126 -0.730954 0.051574 -0.269288 -2.023858 -0.957817 -0.506267 1.740566 -0.818351 1.431018 -0.922382 41.019941 22.143117 9.362127 -0.722578 5.626965 2.461076 0.812902 1.938622 1.678111 1.766816 0.875927 1.453688 0.890062 0.515183 2.188292 1.631012 2.162945 0.863912 2.020360 0.688817
+1 -0.006322 1 1 -0.218078 0.998800 1.306854 -0.144684 -0.103135 0.771460 2.140910 -1.525320 -0.654435 -0.376984 2.191738 -0.207880 -62.591151 -19.466683 -26.542521 -0.144009 -20.352630 0.375217 1.015429 1.562059 2.029464 0.707545 1.964311 1.423931 0.262068 0.579045 2.253791 2.207691 1.405780 1.195978 0.803649 1.686961
+1 0.013440 1 1 1.482841 -1.719718 -2.217118 -2.243106 -0.777434 1.120826 2.298788 -1.145926 -0.045580 2.060905 1.565419 0.737523 62.636056 24.196733 24.488766 -17.314105 1.837069 1.009250 1.208284 0.622158 2.367875 0.383823 1.661695 0.354311 0.662103 0.969880 1.029454 1.032499 0.457257 0.616394 2.228555 1.073821
+1 0.052791 1 1 -1.136724 -0.900537 0.872288 0.305025 -0.517627 -0.680785 -0.268633 -0.448134 -1.393207 0.224419 1.898426 -0.739795 71.870491 -22.651888 -10.285305 -65.117089 -22.923097 0.347510 1.101009 2.156765 0.493355 2.063152 2.142435 0.412177 1.203750 0.935213 1.117372 0.423130 0.801592 0.848555 0.416312 0.964260
+1 0.005028 1 1 -0.313863 -1.932768 -1.542558 1.799895 2.007182 -1.278052 -1.155825 -1.477816 1.350059 0.293720 -2.027909 1.650125 39.375015 -24.120061 64.136238 37.746117 48.991391 2.099647 1.261880 1.411735 2.272658 2.061713 0.458679 2.010107 1.623080 1.610152 0.323723 1.819065 1.529166 0.443451 0.327079 1.967878
+1 0.013912 1 1 0.156192 0.321510 -1.497219 0.406116 2.060357 1.792213 0.126093 -1.333445 0.915901 -1.825817 0.567277 1.065457 2.047720 66.026607 9.185223 26.048740 -48.820167 1.066740 2.197851 0.276464 1.781867 1.832837 1.247269 1.102891 2.295995 0.542018 0.951996 1.940343 1.337473 0.658824 2.105968 1.750980
+1 -0.029790 1 1 1.117484 -2.027715 0.188381 -0.605027 0.644148 1.845148 -0.833249 0.802676 -1.001412 1.917963 -2.251389 1.395406 -30.777958 64.854557 -39.463365 39.226152 23.934475 0.875739 0.549082 0.427644 2.405545 1.245018 1.509559 1.657875 1.402276 0.803473 0.969331 0.798872 2.385754 1.611450 1.883813 0.743831
+1 0.005729 1 1 0.954760 0.962073 1.353586 -1.689557 0.469543 -1.649319 -1.828701 -0.784714 1.285255 -0.310021 1.382043 0.622283 61.311074 -44.786091 -19.831354 -5.573425 -72.560077 1.116695 0.290952 2.279397 0.571090 1.309401 1.358503 0.864387 0.997651 2.018783 1.179537 1.228541 1.333831 2.450269 1.425542 0.335499
+1 -0.050705 1 1 -0.350383 1.595963 0.426381 -1.351727 -0.054252 -2.324010 1.350511 -1.534736 1.302271 -1.777633 -0.134198 1.763951 34.833559 -2.370321 62.021689 48.521843 -43.378749 0.375381 1.531819 2.289803 2.220503 0.749001 1.216103 1.537002 1.646084 1.229948 2.494010 0.822965 2.326862 1.810721 0.790022 2.158155
+1 -0.015508 1 1 -1.613488 1.901490 -1.074890 1.629156 2.249702 -1.460832 -0.665456 -1.813363 -2.171151 2.202056 -1.153626 -2.227949 -15.991266 34.792376 55.459712 11.384966 -52.877077 2.049495 2.114599 0.561946 0.622681 2.149878 1.744934 2.105053 2.116606 0.543464 0.503436 0.493248 0.266472 0.341256 1.737374 1.039590
+1 -0.007584 1 1 0.386136 0.831633 0.305375 0.638288 2.312338 0.395065 0.097282 -0.172789 -1.232027 -0.438405 1.896431 -1.287654 -73.631245 -20.326335 -74.710851 -15.266097 72.705655 2.334144 0.460855 0.345412 1.831174 0.300293 1.768078 1.835609 0.575499 1.159061 1.329562 0.452354 1.461558 0.401896 1.674554 0.470301
+1 0.022787 1 1 0.248682 -0.288968 1.785274 1.319530 0.834372 -0.783486 -1.626191 0.465112 -0.717682 1.642361 -2.019818 0.965435 41.622038 -58.414259 -18.448828 -19.460325 -69.684405 1.588003 1.562117 0.756835 2.376720 0.529256 2.455044 0.667019 0.335412 0.267791 2.271546 1.379710 1.780536 1.964215 2.062484 2.164374
+1 0.060858 1 1 -2.130490 2.297744 0.161637 2.301121 0.365182 2.083321 1.321692 -0.522379 -0.437781 -1.752104 0.100831 -1.800534 43.921361 36.316468 20.871636 -60.420175 18.126886 1.503615 0.755052 1.657523 2.237284 1.535679 1.906837 0.713454 2.278172 2.489744 1.133143 2.234994 1.296524 0.934861 1.967031 2.144076
+1 0.021967 1 1 -0.225285 -2.310515 1.980765 -2.306739 -0.544188 0.578588 -2.036592 1.795592 0.367145 2.095817 -0.716516 -2.324211 -64.306718 -53.004947 -4.151526 -24.702412 26.563758 2.231189 0.345580 2.420204 2.363133 1.671013 1.723602 1.323213 1.737080 0.596422 1.816411 1.921544 0.385612 2.474292 2.418247 0.975383
+1 0.046737 1 1 -1.360266 -2.185007 0.239559 1.892927 1.079885 2.221251 1.020264 -0.809519 -0.915175 -0.116386 -0.463832 -1.326399 48.250512 46.351628 -68.190292 -74.242503 56.252704 1.212923 2.090218 0.290898 1.370333 1.680846 0.478807 0.561080 1.818692 2.012322 0.598431 1.827214 1.233817 2.265196 0.399961 0.636261
+1 -0.028735 1 1 -0.299098 1.176742 -0.394319 -1.707632 -1.717022 0.672739 1.707021 0.878179 0.351733 2.247998 -1.838861 -1.893941 22.805649 44.539129 69.147723 -34.217150 12.355230 2.190329 2.109659 0.791118 0.318447 0.883615 2.416749 0.556754 1.110523 2.302306 0.858723 0.313512 1.201679 2.118713 2.205741 2.380536
+1 0.014567 1 1 0.595287 0.588334 1.535628 -0.458529 -1.733425 -1.679790 -0.314247 1.042905 -1.977266 -0.148466 2.299263 2.126952 -15.820875 48.550891 -5.174139 38.237334 54.870230 1.434380 0.379220 0.803235 1.475376 0.901942 2.188830 1.661464 0.974025 0.937124 1.745755 2.399322 2.400875 1.509033 1.810331 0.977958
+1 -0.031299 1 1 -0.134022 0.011254 0.658425 1.466986 0.407927 -0.498188 0.874201 -0.536382 -0.173292 -0.267911 2.265144 -1.114494 13.985610 6.153975 -70.147274 34.761747 -9.322074 2.483628 1.830609 2.049161 0.991534 0.469418 0.266508 0.943706 2.121692 0.520477 1.153643 0.277999 0.579484 0.629124 2.440219 1.254356
+1 -0.020526 1 1 1.277252 1.845037 2.011417 -0.783831 1.992243 2.106549 0.583410 -1.107410 1.702865 1.721775 -0.903240 -2.149455 -22.896762 74.128808 -17.119848 -33.280295 8.084712 1.071338 0.728565 1.991896 1.547659 0.748140 2.488715 1.825548 2.486672 1.240276 0.570557 1.357733 1.422567 2.092150 1.273809 1.659674
+1 -0.048328 1 1 -1.587605 -1.328601 2.213671 0.855427 -0.341972 1.597952 0.873408 0.277340 0.697588 -0.061861 1.737083 1.896163 -33.986811 -16.327302 -62.970821 49.403710 -71.844474 1.523990 1.198567 1.560741 2.381223 1.962452 1.677160 1.524444 2.085786 2.310736 0.795090 1.823324 1.112786 2.100417 0.715955 1.555411
+1 0.008070 1 1 1.235319 -0.778112 -0.846573 -1.654517 0.345177 0.435555 2.038608 -0.894561 2.346582 1.019363 -1.813251 -0.283034 -68.346793 -4.550598 18.107742 -13.183369 -22.876014 0.967432 0.373930 1.885712 1.155812 0.739527 1.734574 1.232193 1.968074 1.673848 2.108198 0.975221 0.787911 0.422977 0.467035 0.704012
+1 -0.002822 1 1 -2.189269 -0.715268 -0.196909 -1.349326 -2.108537 -1.018782 2.145277 1.179874 0.414816 2.186961 -0.380894 -2.254063 -36.197747 24.468642 -55.531827 -23.408206 28.277184 2.194555 1.130961 1.556660 1.281627 0.303157 0.413221 0.756573 2.472820 2.432983 1.151343 2.123123 2.077728 1.878905 1.504241 2.283812
+1 -0.053792 1 1 -0.875753 -1.994133 -0.876712 0.749794 0.860663 -1.865418 -0.562761 -0.561063 -0.298656 -0.818306 2.199837 -0.749288 -56.698088 25.240628 19.236792 62.757151 -40.562594 1.592324 2.191873 1.056867 0.517803 1.212623 1.559038 0.756674 1.927861 0.808202 1.693429 0.452889 1.448920 1.748800 1.823763 1.732732
+1 0.014258 1 1 0.613425 -0.871927 1.050341 0.477659 -1.890184 -2.108039 -2.076760 0.555402 -0.594844 2.153349 0.186454 0.000859 9.496118 1.252565 51.862856 9.024144 18.786696 1.345034 1.740998 1.196198 2.246344 0.799812 2.439019 1.336900 2.274266 2.090328 2.136356 1.730777 0.415820 1.679915 0.575662 1.644829
+1 0.049884 1 1 -1.633596 -1.463191 2.098824 -2.016082 -2.221088 1.719655 1.157382 -0.616392 -1.877186 -0.427589 -0.101871 -1.555498 34.450502 9.583194 -35.267646 56.673116 5.059755 1.214470 1.101594 0.745908 0.972546 0.828701 1.977312 1.678556 2.485180 0.915258 0.993828 0.759675 0.614471 1.415081 2.261824 2.231637
+1 0.020755 1 1 1.460596 1.402563 1.513794 0.140755 0.051552 -0.647538 -2.266806 1.454057 -0.109263 1.454114 0.852591 -0.876092 55.159245 61.429202 -9.407999 -20.233883 -20.869368 0.603078 1.175054 2.382211 0.576961 0.984924 1.873471 2.426370 0.252215 1.483715 1.548073 0.963282 0.378459 1.515780 0.455441 1.588541
+1 0.020127 1 1 1.601850 0.419170 -0.038679 0.225039 -1.812216 -1.752910 0.700090 -0.421838 2.316543 0.374798 -1.241526 0.140025 60.979116 -73.998511 -42.977900 70.433975 -16.177328 2.239678 1.275571 2.020292 1.792538 1.185492 2.313127 0.477945 1.822263 1.279183 1.980238 1.364903 0.430403 1.533433 2.414001 1.619187
+1 -0.041183 1 1 1.187497 1.290717 1.948226 2.151119 0.406093 1.666949 1.256951 -0.071695 1.395230 0.783382 -0.118239 1.392317 -33.575663 -6.166439 10.658457 36.686136 -66.117387 0.851167 1.560158 1.578513 1.824549 1.443287 1.570595 1.484089 1.089059 1.569494 0.981842 1.820835 2.016642 1.197476 1.222965 2.129616
+1 0.003197 1 1 2.313145 -0.180407 -2.026568 0.612560 -1.270148 -0.261822 0.935857 -1.013884 -0.342341 0.102069 0.164234 -1.186804 29.306356 -48.075398 46.786229 36.149572 65.855500 1.125852 1.197120 1.991833 0.485974 1.772374 2.037634 0.756565 2.330272 0.636595 1.994906 0.384283 0.388458 0.811025 1.895363 1.361575
+1 0.007895 1 1 1.497002 0.666534 1.083871 -1.479508 1.179854 0.080454 -0.270961 -1.878731 1.882962 -1.456565 0.372943 0.581024 38.463325 -46.905113 65.767791 9.255536 7.786280 2.335014 1.583961 1.126059 2.417179 1.032109 0.651532 1.047191 2.141741 2.240078 1.245732 2.264192 1.524974 1.987831 0.731326 1.151781
+1 -0.011732 1 1 1.488156 -1.929541 0.866766 1.743394 -0.409073 0.092486 -0.678283 -0.639268 0.063370 0.054523 2.171723 -2.018364 58.520800 9.084157 -22.570791 2.716816 61.530762 2.087865 1.241362 0.823633 2.291628 1.390974 2.102942 0.394757 0.933605 1.093582 1.088499 1.161603 1.313622 0.297552 0.700660 0.987796
+1 0.002855 1 1 1.978115 0.276203 0.435390 -0.744646 0.845630 -0.062602 -1.293740 -0.928917 -0.160302 1.297544 -1.107697 1.593520 56.703871 71.957008 -68.561395 -11.359480 31.213484 2.200374 2.191249 1.825882 1.341722 2.315700 0.962180 2.115963 0.998821 1.437419 1.951826 0.848277 2.487971 0.581023 1.761724 0.789578
+1 -0.024107 1 1 1.330473 0.967638 0.635723 1.605314 2.078735 -0.349134 -0.974298 0.523298 1.754964 0.835624 1.409870 1.797615 44.062905 15.236103 23.184988 -29.914596 25.391615 1.478040 0.666411 1.362597 2.161612 0.966287 1.389416 0.665877 1.396594 2.064217 2.052903 0.897858 1.043573 2.077829 1.319735 1.789721
+1 0.003362 1 1 -1.047129 1.679952 -1.678951 -0.338017 2.094134 -0.720609 -0.434820 0.897689 -1.611725 -1.446527 -0.569256 -1.330735 -21.169543 3.495745 -47.014150 33.188210 -55.758233 2.445555 0.950282 2.392571 1.444133 2.288368 0.606920 0.497625 1.831652 1.583687 1.026677 1.618688 2.035375 1.038628 2.229027 2.254518
+1 0.015893 1 1 -0.705058 1.741622 -1.917611 -1.267098 -0.834245 -1.793020 0.438314 1.283299 -0.200810 -0.940119 0.056438 1.366532 -27.769838 72.326941 -1.098778 -17.167624 63.737741 0.478198 1.580816 2.271423 1.559698 0.587874 2.151337 1.521791 2.492216 2.178996 0.631658 2.280005 1.799082 0.927827 0.746683 0.501743
+1 -0.053012 1 1 2.007093 1.936235 -1.461915 -0.008434 -0.385790 0.269293 2.108868 1.874856 -1.047560 -0.852026 0.952571 1.872011 -54.963619 -73.544083 -55.410799 60.706644 -3.434130 1.863755 1.132950 1.236706 1.326782 0.979516 0.981677 1.298791 0.785730 2.020493 0.671452 0.586687 2.449102 2.063326 0.569124 2.014013
+1 -0.016429 1 1 -0.933686 -0.197741 -1.191273 1.218452 -1.526273 2.173064 1.664943 0.526826 -0.211938 0.518732 0.413668 1.750943 -24.497252 24.692613 -41.257959 27.475934 -61.969640 0.269029 0.576460 1.564424 1.275679 1.581746 2.154177 2.004242 2.044074 1.002072 2.075475 2.252590 2.282997 0.334340 0.258306 0.352654
+1 0.035786 1 1 0.607555 -0.563620 -0.854100 -0.923886 -0.424296 -1.305554 -1.565220 -2.092423 1.208764 0.588105 -2.308357 0.535574 23.435916 -12.564386 30.369152 -35.670305 39.179529 1.230211 2.413212 1.858498 0.527868 1.630287 1.240847 1.166991 1.869923 1.294766 0.633798 2.245813 0.883556 1.428690 1.489845 1.077609
+1 0.027340 1 1 1.875890 2.204542 -1.775494 -1.883325 0.080840 1.510232 1.546330 0.344243 -1.126332 -0.594397 0.227490 1.672683 -42.129970 71.599678 -74.220154 -18.121486 -67.817007 2.118391 1.299148 2.274576 0.544624 2.003568 1.974074 1.264720 1.893393 2.006315 0.879750 0.464169 2.040009 2.437378 0.753397 0.850294
+1 -0.003281 1 1 1.438939 0.272828 0.258141 -1.533209 -1.305024 -2.086617 -0.179674 0.856399 1.859025 1.489906 -0.792319 0.706836 -4.699216 70.274643 5.927122 17.133242 -41.607890 1.318002 1.900416 0.797541 0.266726 2.369584 2.092720 1.844797 2.009630 0.344916 0.251679 1.473901 0.852140 2.171304 1.863462 0.712480
+1 -0.002330 1 1 1.519229 1.957906 -0.083897 -1.050591 0.039528 -0.105048 1.611355 -0.055625 -1.843089 -2.267673 1.027069 0.466005 5.048073 -57.033108 -55.449736 6.288734 -55.242186 2.043661 0.817747 2.365771 1.008315 1.249123 0.757073 1.875816 1.346512 1.834664 0.450141 0.273275 2.180684 2.000167 1.055857 1.539925
+1 -0.035920 1 1 -0.943315 -1.813576 -1.041188 -2.147721 0.151840 -2.136361 -2.131010 -1.737056 -1.456433 -2.112909 0.900562 -0.446129 -21.837960 19.401262 -22.988792 27.365102 25.274256 1.141423 1.901906 1.076000 0.325154 1.121580 1.391182 1.089572 1.183415 1.154531 1.695391 1.944040 0.486454 0.834295 1.501471 0.721043
+1 0.010489 1 1 -2.343446 -0.148600 0.051299 -0.188070 1.125927 -1.504046 -1.240061 1.199729 -0.460146 -0.640090 0.390669 1.623366 -26.102311 48.456256 54.288880 -16.794536 34.231444 0.293210 1.976924 1.904668 0.261699 1.130895 0.448822 0.594640 1.108590 1.319747 1.988583 2.112077 0.923469 1.742941 2.358284 1.178922
+1 -0.043964 1 1 -0.256578 -0.468207 0.537919 -2.274309 -2.121015 1.322844 -0.004780 -0.230086 1.810595 -1.935739 0.372256 -1.538840 -53.956703 49.697872 72.135990 -60.418106 52.891227 2.017786 2.420966 1.671825 1.868738 1.622045 2.204332 1.210391 2.288221 0.376381 0.338940 1.058303 2.144312 0.448657 2.325678 2.170683
+1 0.023422 1 1 -1.924423 2.058571 0.040887 -0.824736 -2.195492 -1.622437 2.287353 -0.128127 0.131577 1.300766 1.195890 0.977005 -68.276724 -26.906641 30.088769 51.934237 8.719679 1.399594 0.725136 0.604109 0.502882 2.438601 1.061869 1.324482 0.569269 2.212115 1.514420 2.351100 1.938432 0.727721 1.308337 1.475154
+1 -0.020599 1 1 -0.862954 1.073303 -0.014916 -0.934546 -0.514861 -1.317817 -0.320916 2.043818 1.842480 1.446348 2.261468 -1.635577 -56.805640 17.608773 0.653397 31.646529 -16.785037 2.033200 0.488701 0.354619 1.339335 0.446537 0.450646 2.004580 0.978436 0.831441 0.771433 2.471257 0.922435 2.362003 0.686464 0.906298
+1 0.001339 1 1 -1.672691 1.200591 -0.114590 1.445086 -0.088263 0.971430 -1.603736 0.881036 1.249832 -1.909277 2.141881 0.649454 47.224351 49.670875 68.399884 -3.147043 57.655373 1.582886 1.064679 1.304099 2.232661 0.337747 1.260573 1.944640 1.568324 1.576448 0.860483 0.631111 2.079359 2.284377 1.022378 1.350857
+1 -0.005195 1 1 -2.234980 -0.856650 -1.372744 0.149687 -0.633931 0.229437 1.409605 2.055824 0.999041 0.639009 0.286673 2.053530 4.563932 56.010908 -24.677138 1.344254 -57.123471 0.262256 1.492719 2.135621 0.624996 0.559895 2.161467 0.777677 1.661546 2.359140 2.060639 0.403479 1.278995 1.062936 1.265308 0.540031
+1 -0.019958 1 1 1.279040 -1.101643 -0.337664 -1.401118 -0.777682 1.665378 -1.576504 1.463556 -0.677551 2.249563 0.906964 -1.232204 41.047478 34.962115 58.271094 12.269949 -28.969129 1.612624 1.376884 1.539139 1.559117 2.072232 1.759283 0.273625 1.320054 0.396127 1.455428 0.869473 0.980615 1.453478 1.852136 1.594978
+1 0.054222 1 1 0.329266 1.636088 0.944627 0.306739 0.009880 1.125701 -0.591311 0.264966 0.076677 2.226663 -2.264141 -0.882484 -64.064480 -31.720615 -28.375442 -56.051766 -62.024545 2.177074 2.082447 2.445628 2.163530 1.696258 0.758982 2.461144 1.950447 2.410169 2.461580 0.281528 1.395158 0.428763 0.969178 0.474335
+1 -0.003146 1 1 0.786657 -1.616194 -1.162150 0.601303 -1.969272 2.267538 1.421054 1.273030 1.570146 0.066074 -1.612150 0.837814 16.667005 72.358459 -71.380758 3.600611 65.463859 1.391197 1.348394 1.953838 0.900338 2.234579 1.072965 1.076226 1.873276 1.397090 1.392832 1.831294 2.308197 0.859737 1.603551 1.883407
+1 -0.004746 1 1 2.171347 1.089491 -1.275534 -1.241334 -1.349711 0.840951 1.412444 -2.063988 -1.551484 -2.140120 0.673242 0.729333 31.010747 -52.377040 49.095789 2.930504 52.987831 1.622054 2.353941 2.436749 1.439560 1.932303 1.217450 1.682109 1.449195 1.876585 0.755772 0.260081 0.938073 1.943927 0.829804 0.262770
+1 -0.077874 1 1 1.857520 -0.239519 -1.218891 -1.152380 -0.134283 0.345438 0.121656 -0.507545 -0.885440 0.141342 0.483415 0.592329 -63.756397 46.232679 32.642335 69.731096 20.531471 2.461432 2.292925 0.686783 1.754129 1.390842 2.129676 1.962013 1.046209 1.380669 2.151491 1.854446 2.173077 2.401688 1.673292 1.771748
+1 -0.006440 1 1 1.068481 -0.947307 1.779270 -0.633257 2.140408 -0.540846 0.205906 1.768094 0.030443 -2.001338 0.546905 -2.032606 -60.599940 -3.198748 -61.349842 -6.793195 -23.220943 1.759263 2.184241 1.032524 0.888034 2.436444 0.817798 0.979720 2.148979 2.392837 1.415811 1.034771 0.391612 2.066326 1.486804 1.713867
+1 -0.001746 1 1 -0.365200 2.320781 0.919656 0.028105 1.114232 -0.139154 -1.419539 0.641537 0.362961 -2.265557 -1.117126 -1.371609 11.654997 -14.473547 43.089088 -1.705960 -22.073027 0.904493 2.307601 2.100840 1.069735 0.788420 2.217376 2.189551 0.286492 1.569803 1.688252 1.203250 1.523376 2.131911 1.283598 1.929249
+1 0.022691 1 1 -0.201011 0.386013 -1.232665 -1.735457 1.858354 -0.351029 0.169754 2.059629 -1.026951 1.520326 1.548208 -1.076010 52.270506 -39.607853 10.820775 64.763583 -68.461604 1.612337 1.044162 0.724378 1.378602 1.170308 1.369127 1.673001 1.384137 1.944662 1.939371 0.750099 1.669906 1.119203 1.940893 1.584661
+1 -0.039921 1 1 -0.413648 -1.411454 -0.147710 0.859414 0.704584 -0.286289 -0.318364 -2.180730 1.435513 -0.757624 -0.507760 0.210814 -17.789406 -36.547817 -9.163324 42.014449 -63.156363 0.340091 2.406062 0.933056 0.877986 2.303734 2.361086 1.031381 1.928895 2.445003 0.669936 2.112800 1.831884 0.978924 2.271716 1.987880
+1 0.034305 1 1 -1.912820 -0.854027 0.299159 -0.159788 0.502564 1.995814 0.862844 1.795631 1.029010 0.103164 -0.277735 2.083133 -58.180328 13.228729 35.250861 -38.771074 -25.441371 2.228288 1.084216 1.174183 1.247361 0.390978 0.424232 1.322469 0.492485 0.937634 1.315265 0.910831 0.843031 2.076258 1.911620 2.355385
+1 -0.000026 1 1 2.091177 1.415970 0.640635 -0.661388 0.583181 -0.242141 1.845383 -1.588060 0.451283 -2.225178 -1.052226 0.830255 22.428257 1.716861 55.280505 -0.550199 52.813860 0.513233 0.904174 1.445472 2.293938 1.972806 2.456971 1.570213 1.813727 1.814556 2.243431 1.346119 1.967623 0.848137 2.396564 1.052482
+1 0.064539 1 1 -1.336487 1.628656 -1.447085 -0.516172 0.211481 1.212322 -0.875410 -0.932227 0.750657 1.234580 0.938676 -0.756628 66.681755 70.248140 10.482663 -67.886047 -60.785144 1.886336 0.397874 1.574463 1.251930 0.683650 0.857618 1.984876 0.558873 0.730113 1.016761 1.458046 2.136126 2.370072 1.298386 0.730305
+1 -0.025227 1 1 0.395613 -0.121360 0.767807 2.016297 1.110229 -1.438676 -0.561132 -1.450778 -1.331786 0.528541 0.327629 -2.326586 15.337373 -74.778097 54.523614 28.374117 33.781832 1.693726 0.948761 1.583297 1.216762 1.361000 2.321910 1.847740 1.970014 0.520022 0.262408 1.799119 1.540086 1.730734 1.944999 0.852320
+1 -0.001079 1 1 -1.931058 -1.065356 1.638755 -1.358094 1.325753 1.753639 2.125085 1.104163 0.285458 0.486006 1.736982 0.212366 62.355538 -40.475024 -13.736766 -23.829898 -9.092245 1.924595 2.169107 0.936572 1.471853 2.440919 1.779610 2.147972 1.208948 0.531103 2.004855 1.091782 2.326231 2.456963 1.430659 0.830542
+1 -0.015680 1 1 -2.288822 -0.990919 -0.791913 -1.896673 1.926143 -1.436059 1.017942 -2.140132 0.471061 0.304489 -0.101966 1.558842 -45.403535 -47.208413 68.199918 -63.986444 -70.171785 2.467224 0.633185 0.941062 0.425388 0.502411 1.276658 2.289550 2.463694 2.056804 1.197729 0.978348 1.599052 0.514750 1.644983 0.730272
+1 -0.017090 1 1 0.267989 -0.952369 1.527153 -1.516418 -1.835856 1.496015 -1.788388 -1.813038 -1.428450 1.663816 0.442984 -0.344582 4.236665 -44.376278 -32.105953 -54.744528 8.725478 0.611591 0.260112 1.450716 0.432126 1.239618 0.763711 0.946969 0.713839 1.997911 1.386153 2.073183 1.994400 0.878236 2.016872 0.572426
+1 0.071665 1 1 -1.537510 1.816379 1.029287 0.047947 0.032036 1.223902 0.547532 -0.924274 -2.237355 1.637476 0.713353 0.999886 22.633597 2.862781 -35.239400 -68.594586 30.789832 1.145680 1.441115 1.071787 1.531630 1.348939 2.126397 0.858807 1.711429 1.488130 1.507843 2.072367 1.766606 1.843055 1.974009 2.425089
+1 0.003710 1 1 -0.524127 -1.544909 -0.014300 -0.015892 1.513227 0.051774 -1.627433 -1.558481 -1.934021 0.964932 2.281115 -1.289222 -12.385977 28.880136 -11.552355 -60.431879 -28.596340 1.094627 0.641075 0.805770 1.327666 2.328285 0.990023 2.069755 0.620788 1.831279 2.047473 1.875632 0.495650 2.392237 0.332250 1.130456
+1 0.023885 1 1 1.356991 -1.011392 -0.880194 -1.235245 2.014728 -1.688520 -0.954011 2.194440 -1.917741 1.267216 -1.904684 -0.772849 -61.174175 -54.362307 -17.292022 72.990109 44.758870 1.559832 0.602152 1.374976 0.969977 0.396484 0.699520 2.089692 0.446101 2.115778 2.388186 1.987179 1.021789 0.466106 0.836050 1.743402
+1 -0.004649 1 1 1.840932 -0.996096 1.740374 0.662976 -2.162385 -1.257276 -0.694094 2.240673 2.290307 -2.306971 0.270480 -1.492988 26.242641 60.074123 15.778801 -5.685268 -2.290402 2.203112 0.947352 0.390893 1.237223 1.004766 2.354770 0.613599 0.256845 0.540931 0.672242 0.377013 1.949424 0.974395 0.414699 0.849923
+1 0.012009 1 1 -0.114815 -2.322224 -1.605573 -1.726185 2.195978 0.373195 0.104886 0.383502 -1.030022 1.736775 1.436781 1.700832 16.863785 -70.373245 -13.136551 13.994586 7.009590 2.277708 1.435430 2.268487 1.708597 1.140673 0.535524 2.057690 0.349590 2.306165 0.457620 2.217639 2.115516 2.470674 2.363809 1.781532
+1 0.032252 1 1 -2.246402 0.384831 -2.247934 -1.806084 -2.355681 1.568296 1.950179 1.984706 -2.055336 -2.215016 0.090157 -2.123596 11.398556 25.531205 -47.032483 25.051921 -2.361001 2.404709 0.701259 2.063679 2.005846 1.996476 2.014768 1.211517 0.960345 0.515402 1.361722 0.963597 1.171701 2.277070 1.964323 1.631528
+1 -0.009214 1 1 -1.107990 1.376113 -0.070873 1.072098 -1.427429 -0.032140 1.750991 0.033330 -0.594689 0.039662 2.145056 2.178984 70.335456 -21.985054 -52.809086 -12.313700 43.638692 0.407567 2.485374 1.923812 0.258263 1.880302 2.484136 1.367789 1.678067 1.028104 0.852949 2.256340 2.300735 1.447562 1.428093 0.457299
+1 -0.046102 1 1 -0.276981 0.625213 -0.674913 -0.535781 0.495788 1.212540 -1.931611 -0.938695 0.437829 -2.154437 0.373570 1.688803 31.886018 -41.695849 17.861555 49.149817 10.982650 0.405937 2.084445 2.263362 1.070108 0.298149 1.744547 2.344178 0.357583 1.641850 2.078937 1.936936 0.334978 1.969358 0.746440 0.920129
+1 0.050269 1 1 -1.456871 -0.064310 -1.727201 -0.749791 -0.810395 -1.499203 0.044653 1.221409 1.060860 -1.814172 -1.625812 2.128176 38.848261 -27.278053 -62.237049 -68.079882 -18.572394 1.431696 0.261596 1.651201 1.729571 0.395789 0.280909 2.231757 0.897251 2.102014 0.550691 0.463232 2.033391 1.460029 1.709566 1.673246
+1 -0.055861 1 1 1.598105 -1.269341 -0.835486 0.910676 -0.112323 1.852534 0.776256 -2.073398 0.525122 -0.575030 0.575806 -1.673917 -17.621219 -59.833464 -21.032904 49.975537 -61.145983 0.917079 2.342153 2.315400 0.434364 0.610105 2.277737 1.919669 0.373168 0.337796 2.085623 1.809613 2.414686 1.879368 0.283075 0.394314
+1 -0.001844 1 1 0.696278 1.488680 2.166519 0.054497 1.729853 -1.802724 2.275016 -0.125677 -1.106202 -1.564039 -1.090172 -0.760316 43.555061 29.904227 -49.650031 -18.068117 -70.842305 2.175731 2.004943 0.333046 0.996766 0.639673 1.982071 0.664644 0.926875 0.484096 1.699495 1.166338 2.139642 0.718184 0.761937 0.375814
+1 -0.005597 1 1 2.355593 1.676234 1.801033 2.294976 0.758248 1.573901 1.909706 0.353032 0.510249 -0.787725 -2.185175 2.122003 36.619756 18.236414 49.416203 -11.873161 -52.210582 1.326180 2.112656 1.666958 1.067285 2.365585 2.391886 1.178035 0.740196 1.727885 1.313644 0.662505 0.972143 0.808477 1.819065 1.527775
+1 -0.009580 1 1 -1.574191 -2.077471 -1.970336 -1.487804 -1.581459 -1.709091 2.036900 -1.328132 0.666136 -0.888071 -1.669233 -1.950114 -28.723071 -48.656339 32.914735 -2.056547 -64.386393 0.743314 2.383324 1.276891 1.700371 2.383354 1.775094 0.501351 1.451349 2.066542 0.615383 0.986273 2.035676 1.606664 2.457579 0.531353
+1 -0.053812 1 1 -1.148437 0.162005 -0.941386 2.327189 0.240536 -0.542934 -1.905592 -1.896333 -1.776011 -1.149087 -1.339109 -0.030301 -10.746712 -19.985813 -51.564456 56.188411 -41.381789 2.069071 0.372670 0.958290 1.982765 1.075667 1.476039 0.784684 2.437294 1.602804 0.577919 1.335065 0.688954 2.254609 2.459504 1.380433
+1 -0.031977 1 1 1.513427 -1.306703 -2.028382 -1.594318 -1.065306 -2.240421 1.948635 -0.392200 0.923223 -1.279957 -0.187326 -0.506367 2.222583 4.949964 -55.954412 74.195736 57.726639 1.549422 1.137074 0.800449 1.894823 1.284599 0.750774 1.756213 0.415537 1.426663 1.178486 1.569657 1.479003 1.110233 1.935404 1.585557
+1 -0.010379 1 1 1.883412 1.388421 -0.556426 2.246321 -1.739319 -1.789675 0.104615 0.542612 1.214082 0.429215 -0.856442 2.123233 -55.463947 67.435771 -6.998527 -24.250641 -30.526404 0.515992 2.277202 1.929489 1.172661 0.420671 2.209144 1.086120 1.676254 2.052305 2.087066 1.315568 1.502851 1.419135 0.655603 1.965728
+1 0.065905 1 1 0.976804 -0.825667 1.001738 -1.152912 0.355508 -0.284996 -2.135517 -2.076113 2.000715 -1.584500 -0.982100 1.348683 22.785141 -0.136521 -44.503438 -69.288216 72.950282 1.005842 2.435855 2.155946 2.481592 1.371085 0.833573 0.608605 1.817761 2.105320 2.116934 1.566825 1.120311 0.315419 1.749288 1.026277
+1 0.000294 1 1 2.173477 -0.820547 2.227953 0.559915 -0.155507 1.765125 1.971221 2.212015 1.303235 0.286941 1.839320 0.173214 -33.520865 14.823869 -5.239100 -3.549396 45.309581 0.896903 0.754431 2.467866 2.429378 1.301560 2.326663 0.733332 1.117856 1.799819 2.056395 1.074877 1.715086 2.195681 2.062999 1.821174
+1 -0.065541 1 1 -0.277387 -1.482930 0.223681 -1.076080 0.479309 2.266778 -1.922961 -1.641100 -0.351728 -2.161586 -1.963859 -1.012331 69.783216 -3.493541 -65.941688 68.047519 74.649513 1.890499 0.607615 0.935959 2.414813 1.757948 0.338774 0.529621 1.836472 1.579459 1.974190 0.957945 0.673887 1.012973 0.788306 0.307081
+1 0.024467 1 1 0.456827 1.411861 2.262529 2.051203 -1.273755 0.376631 1.294552 0.436096 1.694128 0.955841 0.291775 -1.740305 15.850586 0.805121 31.670163 -69.578405 -4.257947 1.175310 2.184963 1.928860 1.845441 1.573062 2.450277 1.562578 1.746400 1.996370 2.493921 1.583691 1.099809 2.240665 2.100406 0.530124
+1 -0.059130 1 1 0.355859 0.900940 1.195765 -1.116797 -0.558355 -1.907242 -1.341607 0.398790 1.447669 0.914104 0.958808 -1.687839 34.095550 43.915225 -66.816687 61.937711 -12.894198 1.933239 1.200824 1.242226 1.845220 2.362741 1.831443 0.319234 0.621183 1.720841 2.182346 0.695559 0.754268 1.990234 0.609645 1.306978
+1 -0.018706 1 1 -0.176950 -0.479858 -2.080628 1.525273 -0.138320 -1.530384 -0.949555 1.694235 -1.953256 -1.875212 -0.221838 -0.924236 -51.083889 33.082489 -32.601934 9.291745 16.351840 1.755544 0.430537 1.538343 1.686908 1.107802 1.577530 1.051045 1.656923 1.150254 1.827239 1.665017 2.188287 1.541891 0.559267 0.597207
+1 0.019125 1 1 2.230252 1.498410 0.768441 -1.463324 -0.125758 2.242479 -0.344729 -2.326673 -0.983108 -1.465569 -0.167347 0.693997 26.666245 -20.427637 22.703997 -13.926366 -60.429667 1.503830 2.128365 2.437882 2.477360 2.232717 1.275796 1.301015 2.159545 2.226511 0.475606 0.761158 0.781199 2.357161 0.303339 1.226153
+1 0.063449 1 1 -1.336421 -1.990288 -2.237150 0.363125 0.490036 -1.223725 -2.279908 -1.974695 0.661714 0.197102 -0.121712 -0.428677 15.171615 -10.664629 9.572601 -63.302677 21.914656 2.419449 0.928480 0.465694 0.663910 2.088034 1.841714 1.938768 1.866563 1.081046 1.881657 0.501979 0.762263 1.355169 1.070561 1.162265
+1 -0.040936 1 1 -2.288610 -2.151272 1.733521 -1.405709 2.175219 0.191612 1.857663 2.167144 1.129600 -1.033157 0.875859 -0.945392 31.128001 -31.690999 19.380469 -72.456528 73.126261 0.370966 1.578213 1.266727 1.871548 1.608705 0.751733 2.130813 0.819492 2.460435 1.282100 1.497184 0.674702 1.221379 2.471502 0.526659
+1 -0.024442 1 1 -0.398775 -1.198059 0.253391 -1.256534 -2.345528 -2.161294 -1.776547 -0.737927 0.676160 -2.054432 -1.162012 -1.793195 70.352512 -35.328628 -68.242767 -56.177663 72.020653 0.641638 1.257138 0.471183 0.678034 0.972151 0.934630 0.326672 1.879963 1.294085 0.443333 0.595941 0.485454 2.024921 0.850088 1.432902
+1 -0.003116 1 1 -1.944497 -0.747181 0.647193 1.178568 2.017469 1.970304 0.936250 0.885808 1.343440 2.144295 -1.188451 1.526861 -54.567153 -10.142773 -69.588333 -21.115748 7.621010 1.169629 1.210658 2.282492 0.839494 1.117295 1.385272 0.765286 0.409268 1.817166 1.117466 2.005346 0.355647 0.609615 0.805570 2.469619
+1 -0.015401 1 1 0.109642 0.214814 0.682674 -0.957626 -2.019976 -1.688330 2.242788 0.139548 -1.381836 -1.867536 1.541823 -0.003260 55.869153 -7.143293 -57.317795 -40.180803 -18.754919 0.416190 1.153933 0.645905 0.972371 2.383364 1.953811 0.449627 0.637782 1.706967 0.738441 1.474032 0.811248 1.152190 0.610830 0.977305
+1 0.017184 1 1 -1.890254 1.435004 0.104553 -0.492376 -0.411450 -2.172763 -1.321330 1.901829 -0.100871 1.114513 -0.128207 -1.209708 -73.537222 59.912709 2.899381 -20.110255 -43.059898 2.009476 2.261962 2.289498 1.599305 0.267139 0.301215 1.520540 1.721941 0.403196 1.017062 2.007469 2.284934 1.378550 0.284488 1.646114
+1 -0.062026 1 1 -0.339702 2.048218 0.396649 -1.552732 0.436337 1.039781 2.060271 0.335159 1.712301 0.082798 1.430673 -1.991922 -45.029145 -54.833356 15.792322 71.560799 22.349233 1.728436 1.581822 1.183900 0.307017 2.281629 2.084406 1.610725 0.949723 1.998134 0.639371 1.400634 2.460514 0.364827 1.889629 1.749302
+1 -0.002515 1 1 0.941680 -2.100525 1.687068 0.114781 1.750164 0.273702 0.811262 1.940575 0.792558 -1.405218 0.987605 1.639695 9.734101 -48.960507 20.752248 33.034144 54.850713 1.014034 0.617384 0.865534 2.276575 0.399796 2.371156 1.514024 2.453190 1.018507 1.554718 2.399353 0.680898 1.859775 1.730664 0.776180
+1 -0.037027 1 1 -1.882851 -1.390204 -1.131576 0.810182 -2.071089 1.618259 -1.828461 -1.459862 1.506995 -1.027224 1.636470 -2.058228 32.098540 -69.835618 22.762859 -74.624768 -68.474084 0.716007 2.432955 0.667368 1.707842 1.950209 0.663397 2.461047 0.316688 0.581125 1.222770 1.087164 1.217965 1.339137 1.632021 1.125256
+1 0.012018 1 1 0.980817 0.647822 2.328686 1.836194 -0.528967 1.930454 0.333283 -1.547822 -1.861934 1.446399 -1.593956 0.306140 -20.015661 46.778579 57.582674 -8.005443 2.520317 2.259462 0.784095 1.533912 1.461448 0.803885 1.149906 0.469091 1.506178 1.087248 0.382382 2.190131 1.026072 0.441023 2.270695 0.570473
+1 0.002457 1 1 2.118095 1.433038 0.055472 -0.741967 -1.250816 -0.500428 0.923929 1.155202 0.437935 -0.384412 -0.130343 0.587179 31.253228 -26.992081 -55.904029 20.989715 -25.863851 1.468849 1.445793 0.947573 1.857483 1.467825 2.237973 1.858742 2.385685 0.454728 0.861801 0.288421 2.493864 0.629195 1.382705 0.371175
+1 -0.047817 1 1 1.789010 -1.865038 1.112142 -2.281485 -0.209427 0.314541 -0.818233 -1.293086 0.650126 -1.357210 2.049337 0.362620 45.581542 38.972676 -36.232236 44.807038 71.881792 1.634235 2.342894 1.264669 1.042052 1.273027 2.016210 0.690794 1.669075 0.635528 2.060612 2.214690 2.047134 0.672744 2.066337 1.678481
+1 -0.013496 1 1 2.063345 0.174179 1.035974 -0.665810 1.646705 0.303142 0.820603 -1.281737 -1.815801 -0.739158 -1.162954 1.215500 22.122034 -44.982219 -16.157212 -54.259140 66.627174 2.168738 1.482136 2.009156 1.387893 2.071701 1.826457 2.014915 1.417631 2.372478 1.233442 0.468698 1.658261 1.147830 1.577276 1.273527
+1 -0.009055 1 1 -1.486702 -1.912896 -2.120702 1.876236 -1.407585 -1.093903 -2.201836 0.140649 -1.726144 -1.839425 -1.947000 -0.407378 9.480486 38.524871 -62.493105 -21.619548 -59.749415 1.998814 0.820697 2.447254 0.250502 1.929904 1.390445 2.204419 0.416172 0.849309 1.833461 0.485316 1.958942 1.187821 0.955958 1.031947
+1 -0.024808 1 1 0.723367 -0.329119 0.833530 -0.787376 -1.043828 0.603361 -0.372889 0.332294 0.685009 0.579151 -2.010234 1.819754 38.007255 -62.069558 46.946571 31.025213 40.752643 1.820147 1.709303 1.760929 0.931686 0.338765 0.369341 1.258339 0.410264 0.548813 0.401306 0.749230 0.562755 0.728337 0.406337 2.061139
+1 -0.081996 1 1 -1.370535 -0.423382 -0.069288 -0.568033 0.369818 -0.106035 -0.848029 2.155354 0.902306 0.588195 -0.800888 -1.935826 -34.773174 -32.740550 -70.421551 74.996991 24.426002 1.042195 1.426120 1.042713 1.121678 0.786069 0.965350 1.392994 2.299382 1.217596 1.893629 1.471056 0.279001 1.675327 2.213715 1.410260
+1 -0.034952 1 1 1.386820 0.806840 -1.691178 1.495865 0.401533 0.415827 0.333929 -0.106972 2.256298 1.005287 1.940177 -1.169389 46.242468 47.162792 65.036990 26.690929 -55.552977 2.441842 1.537936 1.588991 2.423932 2.032716 1.358614 0.479532 1.491401 2.478944 1.865051 0.419108 0.701801 2.161505 1.409975 1.948104
+1 0.077317 1 1 0.033275 -1.516970 -1.682566 0.155051 -0.006853 -2.080062 1.607210 0.957660 -2.130311 0.592365 -1.391186 1.211308 29.805021 -67.010652 -48.028400 -63.323757 -32.390950 0.704610 2.133884 0.683797 1.077714 2.139267 1.165822 2.465550 1.750096 1.104762 2.231539 1.721092 1.895625 1.274579 1.095840 0.786854
+1 -0.013435 1 1 1.999796 1.812329 -1.066235 1.000218 1.569821 -0.686659 -0.029072 1.481249 -0.195024 2.049174 2.332730 -0.887628 33.912904 -25.816111 58.616370 -34.663122 16.916560 2.374343 1.075093 0.838928 0.604841 1.556434 1.977096 0.298198 0.320812 2.380393 1.511671 1.150203 0.963643 1.943553 1.296812 1.272409
+1 -0.051035 1 1 0.268046 0.007789 -1.042152 0.504999 0.508720 1.789402 0.018610 1.766203 1.229521 0.733730 -0.523749 0.094072 -72.888773 8.396825 -24.557132 68.286485 40.950471 2.193487 1.192916 1.097582 0.816452 0.856801 1.755497 1.887290 0.677173 2.242773 1.529693 0.304607 2.278495 1.164563 1.557728 1.230554
+1 0.003157 1 1 1.293040 -1.419204 1.557505 -0.342433 -1.452129 -0.466897 -1.016605 1.037509 1.580279 0.720228 -1.254319 1.889683 -51.085611 4.142141 16.965070 -18.068668 69.894013 2.255187 0.921349 2.114616 0.847657 1.074059 1.466671 0.841312 2.439013 1.245402 1.215985 1.808506 1.807663 1.149004 1.063972 0.681306
+1 0.014313 1 1 -2.163958 0.580573 -1.670998 1.372714 -0.655471 1.061691 -1.979564 -1.069885 0.913481 -0.086163 -1.439487 -0.054480 -46.002340 -61.320172 41.865488 -16.741843 19.842258 1.957524 2.098802 0.563265 0.293410 0.835921 1.825077 1.321031 1.066353 2.436255 2.133080 0.675662 1.597864 0.793180 1.222412 1.834231
+1 0.022965 1 1 0.286586 0.590428 -0.966828 -1.156094 -1.290713 -1.885491 1.363276 0.935303 -0.894709 -0.139781 2.190272 -1.287353 -62.603306 -73.758400 -57.426422 -65.869266 -64.746228 2.277244 0.390818 2.227803 1.943898 0.346322 1.384370 1.353001 0.628667 1.502601 1.716774 1.321797 0.443581 0.260390 1.617329 1.705986
+1 0.012717 1 1 -0.392295 -0.676301 -0.308601 1.684324 1.113651 -0.472508 -1.069294 1.422978 0.621412 1.412412 2.104666 1.928094 -51.511894 39.595711 -64.891788 13.718142 10.806433 0.980765 1.718407 1.770747 1.687015 0.653901 0.362029 2.122152 1.516311 0.385062 2.232527 0.336887 0.308472 1.981780 0.269708 0.735352
+1 -0.017469 1 1 1.090548 2.354155 1.057883 -0.004358 2.160195 2.156446 0.398636 -1.149815 0.561235 -1.525737 1.751539 -0.171814 32.435140 37.392007 -52.533937 -37.879198 -35.679287 1.948239 1.296972 1.713907 0.384603 1.270081 1.995672 2.016248 1.325839 0.875396 1.523680 0.484955 0.380676 0.528691 1.955232 1.837477
+1 -0.013826 1 1 0.801607 -0.115729 1.150912 -0.974916 -0.437510 -1.911584 1.082932 1.599076 0.909231 -0.825605 2.034514 0.980299 43.691788 -72.125057 -55.833222 11.029466 -27.757074 1.177957 1.664900 2.480570 2.186298 1.860453 1.883270 0.612002 0.413128 1.443498 0.627310 1.193640 2.005645 0.883234 0.517994 2.175199
+1 0.018105 1 1 -0.845242 1.878648 1.435255 -0.388182 -2.222036 -0.073439 0.360353 1.025129 0.852782 2.329190 0.873479 1.472502 -35.760698 19.941555 57.719321 38.621094 54.722012 2.317715 1.082971 0.494543 1.777801 1.002717 1.664211 2.152505 0.904804 0.787379 0.472207 2.125060 0.887487 2.237788 0.996575 1.936923
+1 -0.055997 1 1 0.320442 -0.586936 -1.606396 -1.428574 -0.419401 0.857847 -2.072258 0.827226 1.634035 -0.582826 1.507444 1.812562 -59.516485 56.440044 -12.179326 52.075286 -20.661724 1.200969 1.440945 0.454143 2.283752 1.764045 1.548860 0.680881 1.563885 1.214392 2.044665 1.934897 2.061990 0.613846 2.159953 2.324551
+1 0.045607 1 1 1.767766 -0.769940 -0.167666 0.049583 -0.753048 1.004626 0.255876 -1.899129 -1.643879 0.070362 -0.234852 1.821950 12.836066 35.769074 -29.170217 -63.831547 -16.811836 2.027063 0.848473 1.293419 0.487001 1.030539 1.276171 0.848499 1.725006 2.421213 1.324933 1.402358 2.180998 0.534076 2.458335 1.989461
+1 -0.006072 1 1 -0.054335 0.998633 -1.509592 -0.214094 1.989002 -0.529039 0.713753 -1.700730 1.187346 -1.239202 1.488046 0.933972 9.461411 17.932916 48.514297 -20.212890 31.964098 2.434047 1.029234 1.832761 2.210397 1.890347 0.312979 1.232789 0.733874 1.223993 1.397079 1.210875 1.426373 0.801160 0.338158 1.414857
+1 0.021468 1 1 1.056407 -1.248651 -1.809786 1.392428 0.807048 1.795652 1.387972 1.315624 1.167088 2.279800 0.168010 1.027075 18.038304 19.772318 63.346331 -38.220713 74.472455 2.253169 0.765217 1.494270 1.193944 0.359428 1.160634 0.772138 0.830455 2.205701 1.722757 0.633579 0.808367 2.216792 1.380802 2.134301
+1 0.050517 1 1 -1.896467 0.674067 0.455658 0.611496 -0.302406 2.135867 -1.454655 -0.506894 0.631422 0.015508 1.468126 0.723750 44.267491 3.723262 26.869650 -51.787368 59.711707 2.494965 1.120313 0.354195 0.953259 0.672846 1.523474 1.522943 1.594131 1.064306 1.787413 0.551282 1.388889 0.814177 0.875711 2.327663
+1 -0.010160 1 1 -0.016981 2.054775 2.210640 1.754246 -1.809830 0.650458 -0.499330 0.533336 0.806680 0.319980 1.068549 0.189436 -54.708162 19.928916 -4.713777 -24.446923 -29.439659 2.239815 1.318218 1.035528 1.871115 1.081825 1.481696 1.358289 1.763331 0.810762 1.970244 2.133474 0.549605 2.466197 1.363785 1.880030
+1 -0.024139 1 1 -1.625666 -0.140079 1.883761 -2.174987 -0.999125 -2.055899 -2.259962 -1.324373 -2.126204 -1.060914 0.897681 -1.739001 -36.580426 42.784994 -12.599401 41.870011 59.272942 2.130104 2.408013 2.221859 1.038892 2.152526 1.254296 2.205961 1.594573 1.740689 0.508049 1.524472 0.309196 0.650003 2.355424 0.361154
+1 0.009899 1 1 -0.638987 0.084828 -2.147118 0.857581 -1.840787 -1.277544 -2.040831 1.231075 -1.419156 -2.354421 -0.831797 1.648213 66.507685 -5.341432 -73.448042 58.754382 34.897808 1.786789 1.320137 1.799168 2.366246 2.241188 1.898416 0.918896 1.384428 2.330371 2.297841 2.317546 0.497886 1.726748 2.449948 0.524390
+1 -0.008608 1 1 1.771542 1.432100 -1.575494 -0.407473 -1.301059 -1.417943 -0.820681 -0.015549 -2.150607 -1.226890 1.076292 -1.628192 -5.528897 -74.174083 6.194835 16.597845 -40.019382 1.288717 2.458367 0.277232 1.195634 1.774021 0.463867 1.456020 1.819044 1.175113 1.121222 2.125711 0.573885 1.031992 0.939395 1.655633
+1 0.009773 1 1 1.269719 -2.241279 1.667806 1.522585 1.813738 -0.953263 0.627020 1.423131 -1.532365 -1.254553 -2.045878 1.234912 57.552426 -66.371563 43.145694 49.678053 39.029670 1.699991 0.495815 0.670074 2.184009 1.644278 2.389124 2.011706 1.490482 0.523816 1.019262 0.742400 0.509797 1.659850 0.842554 0.806951
+1 -0.019430 1 1 2.106050 1.632721 0.900076 0.804477 1.006863 0.153371 0.035118 1.179208 -1.360397 0.323196 -1.437619 -1.651172 0.603654 -54.386975 18.110371 31.009008 68.398515 0.982616 1.331453 0.737953 2.279935 0.621476 2.147228 2.208471 1.021667 0.666309 1.905495 0.659071 1.761101 1.570003 0.543710 2.385694
+1 0.008210 1 1 -0.877547 0.839802 0.949208 1.906791 -1.522189 0.133457 -0.090979 -2.262083 0.717809 0.495920 -1.288840 1.321819 50.980261 25.247861 -9.195432 -47.625842 -47.532406 1.717787 0.343505 1.280925 1.998725 1.565627 1.244061 1.180003 2.319659 2.254936 1.210694 0.633639 1.822770 0.789896 2.281230 2.133175
+1 0.067767 1 1 -0.329593 2.303726 1.734883 -2.093310 0.431813 0.399628 1.396423 1.985822 -2.148042 -0.533843 0.086183 1.766215 45.723933 32.134738 -61.452021 -74.122053 -19.343405 0.555940 0.933162 0.396632 0.936557 1.207625 0.810769 2.099426 2.046205 0.821053 1.695274 2.219806 0.270359 0.430449 2.306430 0.421145
+1 0.014456 1 1 1.514610 -0.280628 0.589630 -0.243722 -1.172771 1.166555 -1.958214 -0.381349 -0.490369 0.337594 0.224175 -2.209479 -34.566923 -16.269816 3.201507 -42.266007 35.225293 1.097556 0.372802 0.939973 2.384400 1.366586 1.717169 1.212857 0.985056 1.839834 1.842785 1.945717 1.667212 0.834378 0.648437 0.775653
+1 0.005982 1 1 -0.243284 1.472432 -2.308439 -0.830273 -1.009425 -0.807066 -2.104198 1.226765 1.539492 -1.482835 1.816641 0.715314 31.018304 74.628498 -18.832002 -9.461447 -18.536329 1.523834 0.820638 1.466661 0.670643 0.494467 0.510141 0.682558 0.503360 1.464687 1.247058 2.061091 1.264584 1.870275 0.460744 0.725353
+1 0.050314 1 1 0.616720 -2.048023 -1.832687 -1.788599 -0.651210 1.990849 2.229430 1.824419 -0.508163 -1.845289 -1.546085 -0.938695 13.612528 35.757710 -70.169237 -34.359176 25.322389 2.025908 1.678217 1.287258 0.446672 0.461649 2.429655 1.455795 0.290628 1.328869 2.294871 1.900358 2.073815 1.361277 2.477818 0.927907
+1 -0.069921 1 1 -0.892879 2.338689 0.309101 1.999370 -0.625344 -1.534880 -1.111916 1.369894 -0.929582 -1.906932 -0.840549 0.635324 -12.008229 -72.303379 -52.893198 74.017438 61.081070 1.218130 1.859173 0.623490 2.239474 2.335852 2.169136 1.419913 2.482574 2.114407 1.844457 0.787020 1.190377 1.162512 0.832039 1.829213
+1 -0.048004 1 1 -0.691208 -1.094166 -1.908221 1.057336 0.230144 -0.847967 -1.514633 -0.115362 -2.103397 0.553117 -1.308144 2.029255 67.614353 -5.567916 20.039176 48.427633 23.220745 0.940885 1.952933 1.450475 0.875288 1.969445 2.216925 1.357836 0.902491 2.408882 1.074115 2.402871 1.305952 1.892161 1.547495 2.498883
+1 0.033363 1 1 -1.896116 1.865609 -0.954931 0.873422 0.507034 1.721800 -0.486228 -0.746245 2.246551 2.126389 -0.541825 -2.122219 -1.893957 -31.741086 -72.426548 -22.987433 50.209100 0.840208 1.870344 1.615969 1.340763 1.960470 2.114250 1.455364 2.054285 1.608805 2.430114 2.422556 1.392048 2.148526 1.531697 2.482611
+1 0.000388 1 1 1.909251 2.122996 -1.024190 0.802008 1.923409 -0.252857 0.802112 -1.054361 -2.058693 -2.095448 2.204985 0.964197 -20.588588 17.602030 37.325614 31.589769 -70.751752 0.254608 1.196858 2.098252 0.322275 2.234291 0.723937 0.702483 2.389073 1.147616 2.482137 1.529205 1.104822 0.993635 2.023433 0.581385
+1 -0.006179 1 1 -0.825351 1.594777 -0.656048 0.790997 0.645360 -1.356071 2.333886 -0.312237 1.837239 -1.802674 -1.586383 0.359339 -59.630857 -65.813293 -24.015860 15.438191 -30.323759 2.103637 0.822103 1.337710 2.397971 2.205811 1.317335 1.946022 2.287741 1.319760 2.209069 2.077529 0.775507 1.199120 1.860088 0.251859
+1 -0.011411 1 1 -0.884218 1.820283 0.660059 0.648967 -1.994339 0.362087 1.904148 1.182681 0.471808 -1.267209 2.021302 0.407573 -55.221508 -57.880122 -41.207274 -20.648033 68.502601 2.473196 2.002127 2.497632 0.955554 0.991295 0.953434 1.373589 2.406702 0.436247 0.754107 1.531567 0.288858 0.832993 2.117915 2.301060
+1 -0.030945 1 1 -2.260419 0.414721 0.594038 -1.552430 0.811483 0.946407 1.947975 -2.056623 -0.283090 1.614127 -0.597616 -2.023172 36.376325 -23.103772 44.904223 55.277536 -50.450346 1.840457 1.053626 2.293532 1.886036 2.115797 0.446279 0.603747 1.180903 1.687199 1.501118 1.540731 1.316865 0.792831 2.107554 1.414624
+1 0.007700 1 1 1.186572 -0.112140 0.215015 -0.637410 -1.684496 0.701596 1.323519 1.915264 -0.492108 -0.609950 -1.977535 0.049923 7.781522 -15.967719 -19.457871 -28.437483 -48.771856 1.996357 2.269702 1.874714 0.824032 2.258373 0.468630 0.513655 1.246314 0.798905 0.691733 1.707266 1.269198 0.655215 2.201033 2.007728
+1 -0.010068 1 1 -1.676347 1.005793 1.029908 1.052312 0.617284 -1.992751 -1.216526 0.897668 -1.955787 -1.993285 -0.767415 -0.138881 -49.003215 52.958357 -28.897849 13.846660 70.816259 0.757996 1.645800 0.963067 1.273777 1.111125 1.183835 1.458142 1.488293 1.996834 1.286314 0.333412 0.400399 1.257703 0.962049 2.159884
+1 -0.067217 1 1 -1.869320 -0.170040 -2.153706 -1.473923 0.798123 -2.112719 -0.608426 0.068475 1.043741 -2.061669 -0.266493 -2.170337 55.465530 -40.835116 -65.790242 63.399984 -36.472708 2.172881 1.364255 0.784418 2.467483 0.478164 1.005096 1.154421 2.098789 0.346195 1.494202 2.305606 2.319681 0.372126 0.819100 0.368541
+1 0.040748 1 1 -2.339524 -0.208508 1.629805 -0.980566 -1.155936 1.354975 -1.910136 1.850503 -0.356534 1.888159 1.067488 1.212869 -35.078334 -61.557941 -54.320918 -71.671800 62.060734 0.696461 2.423316 0.669484 1.267209 0.981385 0.879766 0.720896 1.341189 2.369860 2.239012 1.330791 0.854665 1.856710 1.976665 2.052487
+1 -0.002848 1 1 -0.387114 1.582800 0.684619 -1.264630 -1.757872 2.122735 -0.687867 -1.482154 -0.875278 1.289257 0.972757 1.851795 -70.314084 -68.817467 34.826147 23.060099 -28.913960 2.021055 1.119985 1.580641 1.580823 2.399443 2.189067 1.151932 0.770870 2.011877 2.117107 2.211305 1.411264 1.120964 2.288128 1.063060
+1 0.045964 1 1 1.192838 1.530951 1.053104 -0.215874 0.338841 2.328463 -1.913561 0.837644 -2.331046 0.916616 0.758599 -1.948606 28.007333 19.238777 -53.881385 -34.433076 -16.704803 2.010633 1.460411 1.377656 1.018906 1.508467 1.308512 2.158974 1.622787 1.185967 1.292602 0.256953 2.362475 1.868975 1.109924 1.245054
+1 -0.014830 1 1 -0.315045 1.767707 -1.754845 1.167673 -2.024477 -1.939500 -1.582830 -1.181736 1.274778 -2.031538 1.905753 -0.111322 -5.452448 10.703655 46.333885 -66.401962 -17.776127 1.924581 1.927384 1.793332 1.034774 0.437607 1.113907 0.679282 1.700692 1.035174 0.425888 2.150671 1.576941 2.392750 2.192720 1.794980
+1 0.032521 1 1 -2.016825 -0.566519 2.260818 1.578980 -2.254892 -0.938822 -1.696763 1.878887 0.727763 -1.856494 -1.364677 -0.931916 40.616965 -0.662618 -36.623902 62.081116 -2.689825 0.506601 1.942427 0.377770 1.176392 2.371651 0.843467 0.391702 1.334109 0.373134 2.015211 1.899504 1.218636 1.362385 0.845511 1.010044
+1 0.011775 1 1 0.412390 -0.886754 1.615687 2.057630 -1.629135 -1.896974 1.589979 -1.175668 -0.402112 -0.722922 -1.609906 0.845952 20.240651 -15.384921 25.636141 66.620655 -56.657597 0.711439 2.157751 1.326326 2.306515 1.840915 2.007391 0.976455 1.273057 0.264079 0.618533 2.184942 1.569682 1.898845 1.389109 2.255110
+1 -0.011038 1 1 0.431660 -2.175876 -1.800270 1.107127 -1.745899 0.717342 2.080188 0.509496 0.683547 -0.432019 0.854439 1.909816 70.130002 -25.056261 -70.585064 26.821427 37.730267 0.364014 1.739035 1.952862 0.259767 2.400431 0.797924 2.206529 2.133953 1.842403 2.267448 2.256658 0.908039 1.161417 0.444341 1.780940
+1 -0.041044 1 1 -1.089744 1.729987 0.444097 -0.488369 0.966812 0.895088 1.795284 -0.088364 -0.736451 1.921634 -1.810964 0.447269 31.441297 -16.121892 -60.640380 67.128040 70.976653 0.694091 0.845834 1.939776 0.810578 1.142767 1.975958 1.430417 1.269972 2.413457 1.467741 0.825071 1.710311 0.701264 2.137762 0.609664
+1 0.070570 1 1 -2.155491 1.502077 1.132854 1.832604 0.403094 -1.611147 -1.166835 1.966924 0.688190 2.205788 0.313304 1.966343 10.667887 45.184201 -39.139469 -67.058185 53.085566 1.511593 2.089294 0.515667 1.307691 1.858365 0.542910 2.430087 1.979100 2.480780 1.228661 1.112585 0.958596 0.376063 1.737358 0.781455
+1 -0.050827 1 1 -2.101853 -1.777498 2.136227 -0.131485 0.242515 -0.259327 0.458894 -1.555331 -0.827368 0.690648 1.110886 0.169392 22.075740 -73.041110 -1.942354 54.854574 40.829498 0.945553 1.655285 0.616058 1.091333 1.529435 0.461688 0.841783 1.348632 1.450997 0.661992 1.351883 2.090180 1.904197 1.343769 0.732168
+1 -0.014282 1 1 1.874393 0.596640 -0.236944 -0.351804 1.282580 1.853549 -1.013341 -0.644961 -1.367927 0.993600 -1.270308 1.774895 39.540438 56.149095 47.839811 43.702905 -35.273621 0.718654 1.912821 2.285238 1.998251 0.359749 2.051484 1.789838 0.810015 0.668471 2.242490 1.284877 0.922283 2.056960 1.570920 2.459182
+1 0.007622 1 1 -2.297899 1.953488 1.065153 -0.335046 0.186918 -1.638178 1.640257 0.329360 -1.499237 -0.528660 -2.336052 1.604040 -15.191989 -31.757026 -40.340777 -7.435597 -20.081611 1.200530 0.801400 2.131876 0.694812 1.709909 0.698420 1.592058 2.219402 2.492264 0.728072 0.455597 1.961204 0.956877 0.729151 0.589087
+1 -0.023297 1 1 -0.227968 -0.288420 1.569508 -1.227289 -0.925560 -0.296504 -2.341942 1.563049 -1.412805 0.720349 0.785711 1.329914 31.833174 -29.848277 -59.989398 58.196215 -46.220794 1.631822 2.274482 1.221019 0.923964 1.067770 1.505270 1.565186 0.586995 0.877513 1.119304 1.397818 2.377602 1.849938 0.657152 1.009382
+1 -0.000252 1 1 -1.222010 -1.723449 1.043646 1.046733 1.100364 -2.316740 1.022036 0.696697 -0.907485 1.909756 1.184917 0.351674 39.973065 -22.699934 -67.783475 13.130778 38.990914 0.929489 1.668795 0.441003 1.940115 2.012955 2.239239 0.636467 2.097025 2.206398 2.180427 2.180845 2.455576 0.624040 2.493195 0.624068
+1 0.062626 1 1 1.425179 -0.083395 -2.042515 1.202530 -0.517263 0.722195 -1.179052 -0.726663 1.495368 1.481233 -0.464734 2.351499 -37.005088 -44.516279 14.891825 -63.095554 53.024614 1.895286 2.315863 1.453760 2.086034 1.982087 0.943294 1.948284 2.055987 0.978792 2.311059 1.712512 1.694699 1.561316 0.795048 1.113651
+1 0.019524 1 1 -1.923622 1.379390 -1.537553 1.081380 -0.933799 -2.112523 -2.034248 -1.218408 2.255187 1.186139 2.027628 -1.652110 -51.501762 59.892027 -44.698244 -43.394620 -33.378005 1.613000 0.947753 0.389510 0.502521 0.868154 1.308989 1.173473 0.566282 1.498897 2.456396 0.903218 1.139724 0.343674 1.876856 0.827894
+1 0.002578 1 1 -0.950420 1.290556 -0.756509 -0.613965 1.218915 1.550436 -1.339058 0.824376 0.872064 1.246417 1.952786 -1.307456 -17.354194 -71.938191 -65.179719 -25.544327 -23.506776 1.699240 1.374803 0.314279 0.578995 1.422648 1.190550 1.820675 1.583931 0.621763 2.464031 0.975370 1.050956 2.423865 0.897090 1.646710
+1 -0.015692 1 1 -1.334690 -1.154051 0.053884 0.851694 -1.811594 -0.722027 -0.714272 -2.317954 -0.533981 -2.234585 1.074169 0.397357 29.404526 -48.129231 42.014115 -68.771392 59.219950 2.270486 1.554999 0.370168 1.669711 2.328688 1.009015 1.760800 1.013730 2.266453 1.283658 0.690571 2.422513 0.680965 0.736825 1.310037
+1 0.015711 1 1 -0.407303 1.557542 0.289926 0.182672 -2.310128 -0.945156 0.222514 -1.839932 -1.037542 -2.128771 -1.804008 -0.453223 -66.864763 3.932392 -58.295002 35.905079 6.658278 1.460258 1.051129 0.832134 1.174742 1.639931 1.323978 1.100097 0.330818 1.810297 0.407891 1.179509 0.766542 1.276659 2.312495 1.099605
+1 -0.018153 1 1 0.401125 -1.723406 1.768061 -0.530811 -0.785824 1.480933 -0.796582 -0.263039 -0.670208 -1.573789 -0.040287 1.472573 2.143973 33.757090 55.415776 22.940025 53.006246 1.764683 1.030250 0.908494 2.053092 1.822221 0.573137 1.963103 1.375268 1.382064 0.853069 2.034706 1.047941 1.245620 0.376771 2.391794
+1 -0.011807 1 1 -1.175493 -2.169008 0.527982 0.364854 1.283196 -1.930413 0.343297 1.833975 -0.118986 -1.744833 -0.220453 -1.219056 25.038330 69.206063 46.302087 -0.818152 49.321416 2.050565 2.099273 1.723165 0.734366 0.483720 2.129859 0.533168 0.704076 2.159658 1.873072 2.462038 1.221083 1.988343 0.325419 1.073483
+1 -0.019763 1 1 -1.347866 -1.127020 1.976957 -0.332455 1.326629 2.339289 0.963429 0.581159 -1.250716 1.185361 -1.617188 0.984011 -70.228095 26.412011 56.668236 73.044883 65.354728 0.878801 0.260996 0.556881 0.993682 0.557611 2.023144 2.472794 2.006292 0.494018 1.959858 0.837198 0.792313 2.404142 2.423097 1.488500
+1 -0.033419 1 1 1.646143 0.293381 1.701242 -2.003090 -0.632508 0.581397 -1.956586 -1.283567 0.402407 0.976619 0.791124 -1.939960 3.393913 41.492724 18.217477 31.128722 -19.564040 1.182748 1.194853 2.147585 1.463482 1.237101 1.201219 1.134730 1.905417 1.601367 1.177849 2.104520 2.172492 1.574378 2.079237 2.481446
+1 -0.063937 1 1 -0.010437 -1.058860 -2.279178 0.862135 -0.701415 1.721294 0.425444 1.737073 1.729572 -1.803751 -0.839225 -0.671286 -27.037999 72.358830 -65.147055 73.448867 -44.897013 2.363648 1.334963 1.218716 0.465890 1.720784 1.216774 1.569600 0.514347 1.624195 2.351305 0.881585 2.041081 2.452797 1.160817 1.607487
+1 -0.028475 1 1 -0.601366 0.907692 1.579214 1.672186 -0.261739 2.330950 2.190127 0.989016 1.791650 0.099625 1.495210 -1.168327 14.271349 8.557766 -19.624215 25.818281 -22.143924 1.030951 1.450089 1.145829 1.703104 1.065074 1.204967 1.123870 1.629562 0.289307 1.624911 0.882264 2.208918 1.794039 1.665032 2.439062
+1 -0.047606 1 1 1.176125 -1.344064 1.512207 1.742235 -1.046387 0.018338 1.909270 -2.270484 0.894950 -0.521131 1.676907 -1.014842 -73.455366 -64.341884 -44.049223 64.703017 -36.392452 2.155914 1.951252 2.443063 1.811224 2.485053 1.028260 1.219237 2.470845 0.737299 0.288138 2.237038 1.902135 0.434803 1.228905 0.709096
+1 0.025921 1 1 0.653821 -0.516554 -1.499676 1.511272 0.166185 -1.372728 0.422015 0.662106 2.065850 -0.133353 1.835666 0.031266 -73.042799 -30.314508 54.064998 -29.584524 22.911935 1.838448 1.053424 1.149192 1.973861 2.181732 1.611488 0.272662 0.877517 1.178401 2.389656 1.953389 2.367084 0.582562 0.620198 0.923705
+1 -0.003546 1 1 2.196337 1.694152 1.361974 -2.092114 1.679985 -1.126622 -0.762531 1.836391 -1.925210 -1.744169 1.523374 0.933778 55.655580 3.326100 -48.237169 27.897331 -29.566042 1.878090 1.314660 1.981881 1.973270 1.249928 0.790654 1.517901 2.354404 1.214315 0.740941 0.738610 2.071813 1.466220 2.260777 0.384333
+1 -0.005104 1 1 -1.435684 -2.105071 0.681574 -0.611880 -1.435600 -0.703634 2.116080 0.550375 -0.274642 2.228671 -1.511888 -1.106636 18.314307 8.559599 11.178026 69.091076 63.722639 1.170815 0.880333 1.260874 0.255544 1.183067 2.057933 2.186328 2.366457 1.294540 1.329602 1.114095 1.593274 2.409803 0.804495 2.405334
+1 -0.022524 1 1 1.924305 0.675637 -1.418519 -1.072786 -0.712646 1.451316 0.945925 -1.436763 -1.388930 1.426200 -1.774852 -0.510151 -72.115567 -46.333774 68.267377 19.807931 61.889834 0.361500 2.232733 1.549057 1.758657 0.997172 0.725192 1.560084 0.330628 0.867496 1.508183 1.026997 2.495961 2.117896 1.981856 1.548480
+1 -0.011884 1 1 -0.042854 0.743531 -0.737397 0.159926 1.815326 2.183647 0.472126 -0.648206 0.645476 0.589285 -1.324289 -0.717833 -28.742569 73.639884 15.534051 -69.206167 -48.047759 2.294718 1.568672 0.670756 2.394743 1.944137 2.116110 1.204654 0.364192 2.468075 1.443848 2.003015 1.674622 1.618323 0.409652 1.517235
+1 0.014780 1 1 -0.271196 -1.112303 -0.430957 -0.158925 0.868146 1.371456 1.767893 1.365279 1.624194 -1.033661 1.835881 -1.072548 -45.541337 36.757220 -71.408815 -17.947920 -0.694002 1.913663 0.691978 1.323641 2.180210 0.780589 1.106382 2.462643 2.393077 0.953895 2.357519 1.819145 0.615080 0.404660 0.871946 2.043496
+1 -0.051512 1 1 2.189630 2.063406 1.187039 -1.686487 0.224659 1.215865 2.125145 2.121855 -1.346319 1.302478 1.698059 1.056587 56.323668 -18.104051 -74.787177 51.923501 -21.726656 0.476329 1.663692 2.416534 1.433194 0.686723 0.760663 1.464206 2.162386 0.466904 0.755434 1.334735 1.890237 0.705300 2.476089 1.121190
+1 -0.004476 1 1 -0.338811 -1.824817 -1.479195 1.736639 -0.844155 1.295352 -0.256030 -0.684304 1.837163 1.618515 -2.236518 1.573580 39.201347 57.039437 11.817138 10.636141 -38.384393 1.727508 1.725958 0.420311 0.671803 1.988085 0.485758 0.389375 0.479262 1.454903 1.053696 1.218180 0.445352 0.785197 2.056604 2.339260
+1 0.007257 1 1 -0.365090 -0.540077 -1.004986 -1.602428 -0.711475 2.281222 0.503263 -0.391099 0.576813 1.115404 0.708713 -1.584627 50.674036 -21.482916 -13.361191 -11.536339 58.747874 0.257682 1.119696 1.236649 0.351648 0.897265 2.330953 0.826954 1.869018 1.831713 0.350450 1.008424 0.834121 0.817263 0.994277 1.561719
+1 0.013248 1 1 0.268107 1.028984 -0.336161 0.296553 -1.548224 0.809398 -1.108074 -0.032147 1.630759 0.913655 -1.882822 -0.900130 -54.899844 -51.682899 15.518127 -36.831603 21.248460 0.967903 1.541842 1.988478 0.354560 0.337381 1.867170 2.279384 0.353403 1.151593 1.824269 1.240292 0.843326 0.278494 2.157059 0.945873
+1 -0.003144 1 1 0.901191 0.691560 2.298284 -0.188559 2.321433 -2.249575 -1.104092 0.904799 0.074941 1.328725 -0.138346 -1.972844 -39.051921 54.371630 23.981021 -0.971920 14.934934 2.296623 2.093723 0.703530 1.986958 1.796923 0.634292 1.550215 0.966915 0.685063 2.107164 1.604690 0.778465 1.416530 1.867695 2.096974
+1 -0.058606 1 1 0.402337 -0.192321 0.366089 -1.519083 0.502787 1.032147 0.989786 0.605136 1.189275 -1.814403 -0.807713 1.154654 20.611877 73.809958 23.958113 64.003583 58.217001 1.421978 1.191322 1.296656 0.901876 1.083967 1.491721 1.098381 0.745363 0.812507 2.047809 0.780076 1.488939 1.597950 2.246126 1.633937
+1 0.011465 1 1 1.058915 -1.507132 -1.268058 1.877817 1.600057 -1.437045 -1.429972 -0.361504 -1.527717 1.464797 1.324504 -0.389153 9.406564 -3.876813 -57.594565 -41.854592 49.868318 0.427364 2.209559 1.309838 1.948530 1.697068 0.871717 0.443533 1.711666 0.962592 2.277027 1.245334 2.333775 1.012846 0.908123 0.319019
+1 -0.060603 1 1 -1.581339 0.306266 1.482879 -1.079171 0.366706 -0.578522 -1.552663 1.598565 1.748137 -0.811844 -2.296205 2.155042 11.761355 -26.911634 -53.831432 55.116425 -58.248888 2.289063 1.026711 2.184881 0.538004 0.988959 2.178833 2.400733 1.365748 1.133561 0.259444 1.479628 0.352224 1.586500 1.052466 0.789261
+1 0.001536 1 1 -2.081771 1.167627 1.913044 -0.096621 1.867491 -2.309278 -0.797061 1.113959 -0.014011 0.135129 -0.253698 0.818137 -10.463325 -57.098534 44.935600 -17.367616 2.482759 1.790943 1.375515 1.025100 2.097556 2.129609 0.844965 0.822129 1.777539 1.091474 1.652609 0.652111 1.782422 2.160834 1.394863 2.218144
+1 -0.061670 1 1 -1.764987 0.347297 -1.632148 -0.697317 -0.095885 0.103975 -0.789366 -1.492551 -1.264805 0.016400 2.321162 -2.092124 48.407618 -13.156215 -16.498509 59.561212 -54.705928 2.236904 1.896239 0.338135 1.034020 1.269120 1.599888 1.072384 0.307361 1.320538 1.778433 0.371478 1.181515 0.725521 0.328584 0.262537
+1 0.016095 1 1 -2.050824 -1.793199 2.150258 0.073372 -1.477807 1.503336 -1.256432 -0.634365 -2.355650 2.088242 -0.784245 -0.259182 -57.989387 72.370790 -14.138891 -32.346248 -43.384683 1.129609 1.345518 0.878428 0.736615 2.290971 1.595891 1.393474 1.360828 1.690513 0.955084 2.097666 1.729540 2.129255 1.635544 1.847197
+1 -0.034629 1 1 -0.962116 -2.082943 0.316846 0.233302 0.400494 1.805672 0.139735 1.757392 -0.767423 -0.278033 1.796538 2.140250 48.059989 -5.771353 50.864757 33.965881 -35.433169 0.996054 2.182110 1.216114 1.728398 0.935577 0.497004 0.397649 2.278948 2.028503 0.298572 2.096390 0.521584 1.767076 0.737811 2.139345
+1 -0.059860 1 1 0.085209 -0.463770 -0.287206 -1.593133 0.000822 -0.329088 1.354805 -0.056496 -2.336795 -1.465545 0.249776 -0.755610 11.095348 29.521171 -37.677733 50.333240 -49.238259 1.413713 1.773653 1.035351 1.146476 1.330845 1.766441 1.324798 1.374503 2.022181 2.049557 0.910752 1.750971 2.325000 2.027674 2.124751
+1 0.047000 1 1 -0.544472 0.515307 -0.607083 -0.926123 -0.325258 -0.245323 0.197318 -1.194694 0.273158 1.104293 -2.243471 -2.192179 70.573352 -73.676137 -24.830985 -34.368797 13.625296 0.630175 2.105125 1.077511 0.984468 0.953392 0.664972 1.929403 1.980263 1.789200 1.337165 2.231470 0.557591 1.679004 1.026059 2.467965
+1 -0.017348 1 1 0.701686 -1.873950 2.132909 0.658726 1.806652 -2.227085 -0.103053 2.151358 -0.279640 -1.651942 1.205478 1.914122 -26.541350 19.530310 45.916094 -38.213027 53.662723 0.765856 0.987723 1.654172 2.175338 2.162978 1.428115 0.829507 2.026494 0.291220 2.292281 1.113947 1.356115 1.220149 2.039043 1.947947
+1 -0.001975 1 1 1.065514 1.006859 0.093735 1.464841 2.056627 0.348960 -1.960536 -1.706246 -1.986432 1.318419 1.013785 -1.308522 12.580113 -66.042530 23.196384 11.631488 40.410635 1.098207 2.312229 1.139302 2.246480 0.832897 0.497962 0.754675 2.064800 0.600524 1.003314 0.445085 0.794430 1.989536 2.383187 1.220368
+1 -0.001226 1 1 1.127641 -0.966765 -0.105025 1.986397 -1.903977 1.693660 -2.205509 -0.339348 -1.437961 2.028005 -0.023161 1.863684 -9.902442 69.651713 36.340563 -24.159539 0.620174 2.473890 2.421971 0.572768 0.262241 1.242456 1.201769 1.383608 2.054627 0.613516 1.119775 0.315854 2.302088 1.699469 0.728746 0.533063
+1 -0.043554 1 1 1.462034 2.005351 0.920830 0.909607 0.772253 1.339322 -1.095900 1.939386 -0.339513 0.502533 1.476273 0.990919 25.330642 32.093144 -10.527194 69.450746 -41.318098 2.375945 1.014376 1.861406 2.157461 0.951904 0.408419 1.045244 0.917564 1.502458 1.557888 1.674447 0.925857 1.377635 0.656559 2.289067
+1 -0.030921 1 1 -1.451470 1.187567 -2.238128 -1.919895 -1.946800 -1.755086 1.824417 -0.537299 -1.444042 -1.207757 2.201621 0.964309 39.094130 55.043742 70.171875 -71.301703 -17.714332 1.753274 0.524657 1.655769 2.009722 1.901598 0.413701 2.072598 1.145343 0.273552 2.338281 2.492496 2.372781 1.821835 0.827037 1.014540
+1 -0.015058 1 1 2.087478 0.505609 1.331963 -2.253282 -2.150655 -2.027943 1.072717 -0.438776 0.387713 -0.937249 1.167597 1.421201 -31.266939 -53.442448 -7.230496 -22.952966 29.502083 0.497556 0.674825 1.035915 1.620596 0.354713 0.660862 0.352859 0.993737 1.492420 1.606942 0.367096 1.783324 1.577540 1.211430 1.760815
+1 0.042579 1 1 -1.221536 1.516458 -2.210649 -1.897676 -0.784142 1.474368 1.958459 -0.211886 1.397420 -0.115050 -1.562803 0.829748 51.607314 64.134181 3.173131 -69.187731 -38.201017 0.707513 1.422665 1.489574 1.017831 1.435377 1.382016 2.285063 1.303742 0.746369 1.977818 1.194692 1.691859 1.068018 1.181815 1.271598
+1 -0.020723 1 1 -0.309535 0.130366 -0.196943 -1.918030 1.130320 1.648108 0.330846 -0.096245 -1.237598 0.170143 -0.823548 -1.078689 -30.866058 -65.836592 34.399580 53.746236 12.985534 1.343127 1.182753 1.278779 1.943056 1.947154 1.071790 1.580689 2.393565 2.388359 0.407158 2.362857 1.533790 1.657020 0.535844 0.686126
+1 -0.034617 1 1 -0.853568 -1.406374 0.415755 -0.886902 -0.879159 2.033047 -0.109980 -1.175149 -1.108061 0.176230 -2.193330 1.715092 -3.945286 -8.418337 -36.989431 68.629343 -46.634327 0.878085 1.727167 0.488063 0.872472 1.885441 1.102515 0.468417 1.430878 2.265929 1.466596 1.823053 1.056213 0.780743 1.441432 1.894067
+1 0.005998 1 1 1.267098 0.832364 -1.545364 1.748840 1.585808 -0.605617 0.153534 -1.937979 0.414277 -2.162913 -0.714008 2.114540 -56.367622 29.377361 -54.689873 27.297437 -61.968026 0.675911 1.278759 1.601717 0.308062 1.851268 0.513836 2.033272 1.702407 0.603267 2.107095 0.450346 1.461056 0.976237 2.110474 0.992868
+1 -0.029238 1 1 -1.395843 -1.667294 -2.340579 0.914762 -2.122868 -1.544350 -0.047616 0.818136 -0.343172 0.266392 0.482004 0.439968 25.769199 52.929363 -66.189122 -40.572051 5.541760 1.230475 2.346132 1.696889 2.366103 2.098873 1.749447 1.456541 1.578665 2.121034 0.722259 1.763291 2.374139 2.147014 0.867347 1.256231
+1 0.019034 1 1 2.097854 0.531343 0.301676 -0.260123 1.204681 -2.063323 0.203334 0.946997 -2.274353 1.853424 1.607459 0.433982 -26.897323 36.685026 65.229636 -35.509585 40.399225 0.471635 1.512620 1.347636 0.463804 0.400745 0.322727 0.814791 2.186696 1.805679 1.547777 0.485881 2.456147 1.215279 1.197178 0.713234
+1 -0.032343 1 1 0.527319 -1.346628 0.820414 0.245544 -1.186507 1.207835 -0.892902 1.949891 1.857768 -0.787096 -1.048002 1.140735 74.445288 51.953450 31.633718 67.893935 43.368144 1.950818 1.898239 2.457922 1.798426 1.152009 2.067480 0.640314 1.512045 0.695962 0.775021 2.027281 2.263785 1.438433 0.994137 1.458848
+1 0.058295 1 1 1.832745 -1.940804 0.070019 -1.290340 -0.335209 2.158392 0.127370 1.280538 0.515479 2.291644 1.314782 1.142691 70.853946 -7.735334 42.246894 -56.450011 -5.326499 1.787943 0.457782 0.437365 1.549198 1.864979 1.453853 1.408671 0.283890 0.593440 1.199780 1.704248 2.301912 0.991524 0.297868 1.523960
+1 -0.019644 1 1 -0.813072 0.632981 -2.061661 -0.140692 1.012388 -1.227463 0.864091 -0.799008 1.378143 1.065163 -0.178302 0.354677 -3.751909 -58.329886 49.597713 38.759095 -25.884935 0.653473 2.162753 2.147938 0.637261 1.938946 0.369588 0.919583 1.677415 1.309499 0.747862 2.308718 0.622070 0.877316 2.301689 1.733464
+1 -0.026609 1 1 1.537244 -1.576315 -0.078993 1.253659 1.147957 1.196958 0.080295 1.780323 -1.773012 2.135463 1.174744 -0.980682 51.325036 -30.122427 -17.622250 72.837780 34.573478 1.021771 2.404966 0.518398 2.214917 1.357846 1.059671 0.398050 2.273603 2.202796 2.386765 0.608979 1.368045 1.478424 0.379440 2.248236
+1 0.029798 1 1 -1.721736 1.566358 -2.329997 -0.299999 0.165782 1.267920 0.509121 -0.903358 0.577598 0.172857 -2.336907 1.369496 57.746135 39.290828 60.945554 -38.081728 10.403018 0.527775 2.322390 0.907584 0.260568 2.371288 1.480405 2.165566 2.162121 0.520178 0.634385 0.858711 2.362819 0.895293 0.692534 1.675745
+1 -0.022099 1 1 0.650408 -1.341468 -1.982394 -1.511472 1.181818 0.092618 1.536894 1.972193 -0.301996 -0.403173 0.280079 -0.389723 4.638354 -43.192454 64.432774 71.628150 -45.677197 1.425365 1.852425 1.959150 2.440546 2.252077 0.405218 1.241114 1.145625 0.520535 2.123688 0.327804 0.647847 2.113713 1.425035 0.814925
+1 0.030227 1 1 -0.713371 -1.305002 -1.710654 -0.668762 -0.836977 -0.594034 1.627593 -0.462709 -1.306214 1.487210 1.018153 1.408511 -69.840069 -52.033360 -24.689163 -50.758036 -40.311139 1.985211 1.687432 0.912168 0.807871 0.636610 2.261969 2.413996 1.536670 0.558802 1.778189 0.765370 1.815197 1.765429 2.307545 1.165045
+1 0.001566 1 1 0.438550 0.530959 -1.433269 0.783981 0.524214 -1.699584 1.595335 -0.703084 1.945198 -1.612441 0.659391 -1.161651 -14.248782 70.722567 34.182541 5.965136 56.039679 1.508214 1.558570 1.891185 0.898084 0.342804 0.748821 0.428440 2.295099 1.230071 2.301607 0.363810 0.560797 1.567642 1.360150 1.537256
+1 -0.013861 1 1 0.480104 1.501481 0.547788 -1.329786 1.154735 2.006528 1.868386 -1.391884 -1.099157 -0.964732 1.079029 1.971586 -34.159841 -74.447244 65.172277 50.464076 49.730451 1.670278 0.617046 1.945048 1.663705 0.392074 0.839172 2.470898 1.640165 0.750454 0.878217 1.698654 0.528845 2.298558 0.870112 0.468169
+1 -0.030188 1 1 -0.551557 -0.745790 0.456082 -1.687782 2.031559 -1.563056 1.285307 0.570216 -1.387006 0.774139 0.053906 1.211467 -34.996341 -33.495147 -2.930453 -52.122626 -24.967757 2.378585 0.369832 0.521712 1.656768 0.794285 1.795308 0.494070 0.577910 1.186548 2.062118 0.510212 1.885275 0.572952 1.112575 0.806082
+1 0.050329 1 1 0.273481 1.823354 0.442873 -2.211973 -0.587082 0.659166 -0.217568 0.148462 2.345302 -1.646253 -2.133369 1.030763 41.331699 11.871118 17.872387 -68.790833 32.471773 2.171235 0.688902 1.382964 2.484309 2.037786 1.065095 1.545901 0.455881 2.247508 2.371016 1.414499 1.487078 1.828251 0.668551 1.344887
+1 0.010494 1 1 -0.611912 -1.975721 2.260895 -1.842061 0.874672 -2.047405 -0.868706 -1.362998 -0.983070 -0.818863 2.260076 -1.476885 -58.824264 -9.401434 -59.896164 -24.824568 73.491876 0.294402 1.768209 1.782971 2.401049 2.181741 1.775202 2.312999 0.568548 1.336523 0.447920 1.196389 0.958127 1.494426 1.562240 0.563376
+1 0.006771 1 1 1.416858 1.425478 0.229644 0.174900 -0.980213 0.074736 -2.121557 1.637488 0.905945 0.483077 -0.368117 0.424464 -18.662335 -7.863935 -19.162287 -10.555288 47.282366 0.995968 0.739289 2.231603 0.553731 2.063819 2.108910 1.700552 0.927532 0.272206 2.208794 1.955925 2.225466 0.911073 0.410135 0.641124
+1 -0.018015 1 1 -0.010372 0.044137 1.964941 0.336095 -1.410651 -0.777360 -2.343624 1.564303 0.820493 1.577904 -1.496891 1.197796 0.777917 24.449757 -72.930623 55.016758 66.655299 0.259065 1.851687 0.795417 0.580185 1.165120 1.917668 0.499630 1.783904 2.328883 2.033945 1.768057 1.488494 0.861519 2.301811 1.528911
+1 -0.019632 1 1 -1.928039 -2.158759 -1.574533 1.598386 -1.250944 2.063391 0.938425 -0.255004 -2.298717 2.344297 0.315836 2.103594 -62.018361 7.400696 33.490148 68.910466 28.198015 2.485470 1.294047 2.040009 2.433116 1.131072 1.173196 0.406219 2.322165 1.623796 2.396517 0.260785 1.506399 0.303979 0.730664 1.274233
+1 -0.002996 1 1 1.007696 0.019844 -1.064659 -0.775340 -1.377167 1.205723 1.314838 2.089202 1.216525 -0.926362 0.370543 -2.063802 49.957190 -69.515888 -3.533829 6.934931 5.385391 2.308942 2.132842 1.171617 0.865841 0.682094 1.707744 0.304283 1.325977 0.944861 1.286032 2.334070 1.456349 0.607390 1.653968 0.988684
+1 -0.028929 1 1 -1.198763 -2.151378 -0.057452 0.448475 -2.301791 -2.207260 -1.487266 -1.965844 -1.384969 2.032177 -0.598006 0.837212 -5.529747 61.542402 -56.845415 -50.895427 50.557351 0.886017 2.286422 1.645580 1.764861 1.775438 1.794821 1.299022 2.406296 0.375539 1.933767 1.073355 0.883817 1.314241 1.695774 1.614631
+1 0.033810 1 1 2.189549 0.711536 -1.252208 -0.334433 1.070129 -1.531869 -2.346793 0.140732 -0.338796 -1.570929 0.905903 -0.209399 25.255946 -23.318313 39.106116 -43.511383 -45.814661 0.519814 1.265407 2.190007 1.203207 0.802837 1.539677 1.601807 1.825529 2.160318 1.713164 1.395326 0.991220 1.928343 2.158300 1.548596
+1 -0.028048 1 1 -1.617898 -1.532175 1.934944 0.402003 -1.103051 -0.444182 -0.937852 0.457247 -0.958303 0.752933 1.776163 -1.010406 49.479445 1.024874 -24.933527 42.211864 -45.203899 1.495926 2.031055 0.449656 1.122409 1.822769 0.770103 0.372164 1.457315 1.097666 2.219317 1.058019 1.876092 1.485462 1.655328 1.348483
+1 -0.003198 1 1 -1.141603 1.925353 -0.572953 -2.215206 1.626252 0.567516 0.371463 -0.730909 0.818365 -1.201618 1.700125 -1.924362 -51.570032 -37.529622 -10.356578 -63.000037 8.375737 2.440298 0.338456 1.933463 0.465311 0.984092 1.382999 0.805521 1.639022 1.797338 0.855104 2.489088 1.343202 2.445853 1.445292 1.524907
+1 0.012102 1 1 -1.684515 0.389878 -2.245575 0.142542 1.812651 -0.368160 -0.295414 1.835465 1.353822 2.263485 -0.726064 2.124617 -64.848363 -6.442011 29.125046 54.653380 -40.636300 1.010536 0.322223 1.348224 1.357483 1.718128 1.585062 1.638449 1.158377 1.099458 0.846469 1.361400 2.299872 0.451931 1.102055 1.731880
+1 -0.020121 1 1 -0.497350 0.815357 0.079250 -1.652937 -1.384943 -2.254348 -1.225509 0.717778 -0.017868 1.289183 -0.269760 -0.542487 28.190203 -57.259143 45.591885 62.811990 -18.882000 2.128354 2.254181 2.022396 1.164594 2.089899 1.688419 1.749524 0.495280 0.662972 2.065920 1.419545 0.796398 1.312254 2.057549 2.474531
+1 -0.005398 1 1 2.329889 -1.511074 -1.554167 -0.113157 1.972526 0.583102 -1.566275 -0.987741 0.778112 0.848602 -1.952448 2.285716 19.999431 -19.561201 34.888048 13.424061 18.186584 0.803694 2.428384 0.358584 0.471035 0.435345 1.351049 1.584018 2.082967 2.180807 1.816939 1.791874 1.282200 0.929316 1.005930 1.667785
+1 0.003318 1 1 1.871402 2.173440 -1.426021 0.079726 1.631632 1.450400 -0.307085 -1.105790 0.650026 1.670534 0.244083 -2.181633 12.472642 -72.307901 21.110800 59.210121 44.501226 1.856477 0.313167 2.146904 1.264705 1.644098 1.600264 0.644521 2.466854 1.172004 0.625676 0.729476 1.552751 0.842977 1.157438 1.059524
+1 -0.025050 1 1 -2.278977 -0.463445 0.460769 1.685208 1.840407 -0.392085 -1.846944 -1.077328 -1.660054 1.535263 -1.870471 -0.651864 13.582451 -19.746307 73.825265 -18.778955 -17.901027 1.936667 0.313201 0.466689 1.643180 1.917271 0.570481 2.330898 2.157236 1.672960 0.683374 0.715534 1.233328 0.790600 0.607428 2.287358
+1 0.045738 1 1 0.368493 1.182283 -1.519754 -1.353748 -1.023992 -0.584056 -0.316623 -1.197154 1.339552 -1.950141 -1.361382 -2.090825 -6.661271 -55.987835 -37.541918 -67.017336 -10.372409 0.938792 0.523470 1.960842 1.624667 1.274976 1.013279 1.426444 2.002486 1.776909 1.753899 2.030507 2.477403 0.714755 1.629925 1.905925
+1 0.021559 1 1 -1.180155 -0.424952 1.815289 1.557594 1.160352 2.177605 -2.115934 1.890588 -0.533494 1.250248 0.376115 2.047267 -46.252238 -61.370975 -61.985137 -34.198032 33.675038 1.770432 0.907984 2.482349 0.593510 2.373143 1.158482 0.613138 1.518565 2.276362 1.315751 2.331649 1.273653 1.283189 1.809163 1.594875
+1 -0.041563 1 1 1.157538 1.990239 1.403827 -0.817036 -0.029423 0.282516 -1.846869 0.170721 -0.534967 0.046634 1.524637 -1.390229 -49.587748 -21.274402 41.128088 39.777071 -16.761231 1.284847 0.425770 2.418142 1.463675 2.236163 0.693202 1.645002 1.047135 1.190608 0.551339 2.347629 2.107647 0.722187 0.542136 0.684401
+1 0.027698 1 1 -1.701361 0.008166 0.583036 2.022279 -2.022018 1.695247 0.910711 0.482639 1.699844 -1.933096 -2.337630 -1.354773 19.135294 6.890793 13.559459 43.821624 10.036133 0.284413 0.380690 0.756978 0.280975 1.089120 0.343318 0.393558 1.031170 0.615612 0.342364 2.361583 0.376936 0.670828 1.363062 0.984311
+1 0.050775 1 1 2.225640 -0.605693 -1.125163 0.198369 2.336338 -1.497165 1.298708 -0.401637 -2.166158 1.306512 -1.179445 2.095070 27.952677 0.638642 -66.343329 67.667854 -6.381481 1.321611 1.818171 2.249690 0.793345 1.757029 0.630599 2.482748 0.540391 0.607892 1.092888 0.660660 1.470617 1.906098 1.785282 0.730592
+1 0.016026 1 1 -1.003451 0.631195 0.907811 -1.135743 1.460449 -1.069231 -2.228311 -1.858706 -0.846119 1.270317 -1.624163 1.561390 -32.306323 27.623565 19.251990 18.202800 -65.541610 2.007399 1.104686 0.953947 0.979480 0.371620 1.309743 0.356471 0.951359 2.498063 1.437072 0.618313 0.737511 1.593585 0.887467 1.910659
+1 0.060001 1 1 -1.854639 1.542275 -1.842228 -1.927944 -0.577416 -1.830217 2.019673 1.301788 -0.477348 -2.298834 0.367075 0.917325 -46.579750 -15.851744 -20.254040 -59.650588 52.572485 0.411214 0.776340 1.697147 2.197787 1.463089 1.393938 2.421007 2.359857 0.618769 1.647129 0.804730 1.843766 0.428209 0.662682 1.693929
+1 0.029152 1 1 -2.211339 0.637462 -2.145701 1.107454 -0.949794 -2.333933 -0.486567 -1.728635 -1.287115 2.042508 -1.328183 -0.186034 74.911905 -55.619537 2.433707 -46.691218 60.699767 1.839691 1.685819 0.808009 0.711694 1.935568 2.098831 1.058474 0.531186 1.134880 2.182850 2.401594 2.349388 2.410823 2.208607 1.066093
+1 -0.012559 1 1 -0.453284 1.591092 -1.329228 1.103052 0.456942 -1.361441 1.613572 -0.488657 0.837330 1.804680 2.317798 -2.086038 4.458588 -64.505174 61.545958 2.913610 69.039719 0.633333 1.170227 2.249192 1.417027 1.222935 1.616920 1.579367 0.415165 1.933240 1.210297 0.718719 0.755463 1.808725 0.996184 2.119329
+1 -0.025821 1 1 1.956793 0.052366 -1.100675 1.786546 -0.857322 1.466551 -2.191396 1.247399 -0.380877 -1.978157 -0.976055 -0.723165 -31.286289 71.347256 33.328122 45.753066 71.772748 1.143587 2.266125 0.256001 2.109450 1.773020 1.649227 2.312590 0.447422 1.827343 1.155523 0.376992 1.609494 0.512105 2.203135 1.340093
+1 -0.038423 1 1 1.127618 -1.358883 2.205160 -0.821177 1.073298 -0.103024 -2.083312 -1.179848 0.024436 0.711426 1.603228 0.006589 74.867384 -53.882267 -49.261306 65.224892 34.751843 0.988324 0.515961 1.753571 1.012236 1.892975 1.724944 1.384358 1.152800 1.859162 0.429558 0.831737 1.252672 1.912855 0.597346 1.588156
+1 0.019428 1 1 2.351835 -0.235075 -1.916409 0.097802 -0.866199 -1.638923 -1.465692 -2.224637 -1.383687 0.007975 2.083615 1.551896 -11.126129 53.153082 -56.156756 -26.592194 64.990573 1.323365 2.043567 1.480688 2.422709 1.716462 0.570096 0.351985 2.065656 1.474580 1.021351 2.097428 2.226411 1.037153 2.180282 1.994594
+1 0.036627 1 1 1.828840 -1.604400 -0.854419 -1.567082 -0.409356 0.034405 -1.384297 -0.814641 -2.185684 -1.720279 -2.224150 2.095466 -60.488823 64.358834 28.923586 -31.291057 -8.803374 0.500290 1.616319 0.473601 0.805261 1.772278 0.426714 0.287671 1.136693 1.147978 1.815703 1.272303 1.089252 0.308906 0.287732 2.169744
+1 -0.001290 1 1 0.084702 0.453397 0.307057 0.647545 -2.332432 1.175145 1.038209 -0.800955 1.644430 -0.222914 -0.164207 1.637194 21.613965 -34.095405 -41.474572 -13.124080 73.582016 0.519068 2.218706 2.035510 1.070727 1.714209 0.966022 1.428251 0.857609 1.828752 2.327306 0.287344 2.384605 0.300811 1.478798 2.150545
+1 -0.019512 1 1 1.064439 1.799639 -2.292909 0.998641 -1.377005 -0.787364 -0.833091 -1.248978 2.119074 -0.954877 1.778258 1.204912 57.952810 62.873384 -37.043303 63.211553 -53.422812 1.716966 2.292262 0.796486 0.538814 1.101465 0.813742 0.310496 2.252655 1.115566 1.568694 1.042190 1.329515 1.906025 0.557383 0.438166
+1 -0.038301 1 1 1.474037 1.106037 -1.204795 0.150311 0.432504 -2.115963 1.415082 -0.140963 1.158738 -1.396454 2.198101 -1.645272 6.693497 -2.404324 -59.482100 34.348933 -47.480599 1.278592 1.050882 1.182513 1.741206 2.453149 0.322868 0.949957 1.425895 1.772573 0.876644 2.262347 2.012512 1.544278 2.428006 0.755701
+1 0.011509 1 1 -1.792415 1.176215 0.169639 0.124119 -1.512900 0.731902 1.741777 0.692929 1.745335 -0.779954 1.186567 -0.205560 -20.938450 -12.531549 -17.736811 -52.579367 -51.413913 1.920442 2.120298 1.853730 1.382309 0.474621 2.207964 1.506235 2.048031 2.257214 1.249595 1.948230 1.145814 1.443067 2.373410 1.151433
+1 0.007410 1 1 2.151007 -1.473800 -1.839715 -2.109971 -1.553856 0.397969 1.784079 0.078844 0.957136 -1.509077 -0.977356 0.957381 -67.011421 -60.960693 -66.364885 5.374655 31.829357 2.215137 0.561405 0.529857 1.298395 0.875107 1.167431 0.267603 1.350564 2.424470 2.066761 2.045539 0.875587 2.487207 1.229611 1.314983
+1 0.020894 1 1 2.294450 1.344519 1.428154 -1.933077 -2.022556 2.072662 1.243299 1.385516 -2.257679 -0.657506 -0.145783 0.266584 -31.908073 -28.989956 -34.197831 37.051334 71.763967 1.180024 0.407353 1.130303 1.758037 1.834194 1.546721 0.745607 0.424092 1.207695 1.974993 0.950408 2.249316 1.259403 0.284826 0.572006
+1 0.000794 1 1 -1.372969 1.070129 -1.525637 -1.263480 -1.285711 2.073346 -1.393446 0.925236 -0.442473 -0.487685 -1.669895 1.054665 -71.733719 71.390371 7.959130 -30.903220 59.586270 2.371706 1.757391 2.216912 1.145609 2.492290 1.159360 1.858488 0.353694 1.539697 1.933303 2.272968 0.518246 1.912814 2.167626 0.781256
+1 -0.013524 1 1 -0.798004 -0.593092 -1.387556 0.962429 -2.091176 -1.392108 -0.146075 0.080084 -1.777134 -1.169679 1.295865 -1.060931 19.455973 -3.454189 -4.561049 -7.551203 -13.069348 0.527050 1.374142 0.460028 2.193849 0.512483 1.802461 1.461862 1.011649 1.032401 1.062404 1.332535 0.919200 1.992895 0.333137 0.281771
+1 0.000166 1 1 -0.390598 -0.414779 -1.567657 -0.643870 -1.871303 -0.497941 0.303131 0.626130 0.609077 1.450526 1.795422 2.222224 -47.077873 12.182839 6.969974 -5.649408 0.394815 1.909885 2.433046 2.201528 1.336994 1.605690 1.826182 1.892377 0.681709 1.978496 1.339461 0.325470 1.925545 2.392126 0.716647 1.941745
+1 0.019181 1 1 1.921918 -1.755170 0.421247 1.881628 -0.313484 -0.279035 -0.919463 -1.491803 1.890417 1.319188 -0.203782 0.936523 24.279641 67.924506 -42.823280 -30.859635 42.109780 1.961098 1.427401 2.330914 2.423683 2.344073 0.827667 0.344613 1.910734 0.951358 2.479626 2.066927 0.351075 0.272462 2.027166 0.324364
+1 -0.010355 1 1 -1.551360 -0.061697 -0.212448 1.379324 2.049526 -1.185241 -1.073243 1.031464 -1.063250 -0.665613 0.250867 -1.265440 -39.248827 44.965561 36.189983 -4.959653 43.105668 1.029549 0.376161 1.135328 0.700238 0.643631 1.001265 2.014864 0.561870 1.603224 0.891796 0.422661 1.907029 1.688779 1.066044 1.749074
+1 0.004019 1 1 -2.001261 1.836040 1.604636 0.115135 -1.718202 -0.296798 2.139947 1.143739 0.980634 2.291315 0.486664 -1.342149 22.743337 47.259397 38.680686 6.297313 -61.060507 2.215846 1.220173 2.440589 0.724359 1.047494 0.483990 2.163663 1.676533 2.233816 1.743106 0.634553 1.440239 2.096689 1.050527 1.964376
+1 0.000481 1 1 1.240065 -1.121099 -2.185557 0.407048 -1.134844 -2.284278 -0.023559 -0.112720 -0.105320 1.752541 -2.181626 0.505285 19.227548 57.406460 30.380990 13.304568 -40.132945 1.908956 0.319609 2.425130 1.903631 0.818143 2.275232 0.328015 1.945581 1.633652 1.534514 0.327639 2.372123 2.027157 2.424649 0.583186
+1 -0.024239 1 1 -0.973873 -1.762445 0.669469 -1.415874 0.967077 0.639054 1.052984 -2.224556 -0.010316 0.970032 -1.540269 -2.153867 16.831884 -6.519845 70.956034 58.056817 10.924654 1.534998 1.706881 1.541130 1.269715 0.358028 2.379919 0.297534 0.402375 0.720961 2.443357 2.257720 0.747524 1.132245 0.632792 1.081523
+1 0.010018 1 1 -0.377010 1.751195 -1.239325 -0.578907 1.387310 -0.384536 -2.207475 -0.394073 -2.277927 -1.674675 0.831715 1.689662 41.218369 57.128499 8.683044 -14.080049 56.614903 0.275157 2.309313 1.630896 2.477292 1.096229 0.561851 1.274264 0.312601 1.630857 1.810022 0.283065 2.468784 2.108004 2.227514 1.584850
+1 0.018130 1 1 -1.139453 0.356648 0.019357 0.185727 1.910829 0.364403 -1.580194 0.707874 -1.543745 0.698767 0.899968 -1.011501 63.676879 -32.686973 -69.959027 48.634913 56.990885 0.562134 1.544051 0.866238 0.611173 2.226910 0.425481 2.059111 1.734640 2.338358 1.538859 1.357777 2.165206 0.614214 1.596128 0.876704
+1 -0.005493 1 1 1.524177 0.290372 -1.754251 1.714493 -0.769127 -0.630503 1.301711 -1.764749 -0.364732 0.767714 0.445355 1.807258 -47.099317 -48.216770 70.748654 22.626704 37.009820 0.985547 1.095722 1.056280 1.893600 0.977026 1.870547 0.533870 1.247450 1.894357 2.465263 1.432218 2.284301 1.995419 2.263806 1.781727
+1 -0.005732 1 1 1.771213 0.612207 2.220936 0.437220 1.741311 2.273362 0.339576 0.547060 0.568493 -2.065983 -2.095913 -0.900749 64.449751 56.959182 12.964701 -52.267638 -62.189539 1.081246 0.751237 0.544362 2.088891 0.500267 1.242490 1.788266 1.378145 2.484064 2.416428 1.897396 1.788838 2.005061 2.303054 2.182455
+1 -0.002916 1 1 1.483503 -0.009748 1.105852 0.388429 1.672910 -2.227730 -1.532839 0.207123 -1.338968 2.330371 1.880708 -1.638854 -9.917833 -39.011748 -20.442016 -68.959416 49.097571 1.868066 1.584252 1.527862 1.033111 1.751901 2.193508 1.540560 0.690363 1.177061 2.366336 1.509799 1.194867 2.375503 0.324064 0.786392
+1 -0.002370 1 1 0.091909 -0.950304 -1.479648 -1.173737 -0.935010 1.099207 1.811923 1.534139 -1.925140 -0.565898 -1.448939 1.305272 48.817783 -19.518773 -2.024448 25.107154 25.930135 2.241631 0.344098 2.261717 0.430343 0.531903 1.937675 1.500612 2.043401 0.945491 0.609660 1.555833 0.892373 1.110522 2.293660 1.792352
+1 0.000041 1 1 -0.209569 -2.065457 2.025484 0.013887 -2.225907 0.832333 -2.070290 0.913151 -0.914354 -0.451652 0.737446 0.672218 -74.716551 38.925056 63.410764 -5.290303 35.872041 2.145907 0.262667 1.638551 0.626714 2.424494 2.473096 0.323077 2.209408 1.028743 0.338618 2.402238 1.917152 0.822351 0.997052 0.951440
+1 -0.009293 1 1 1.677222 -0.434711 -1.990940 0.950041 1.772895 0.604240 0.270959 1.840818 1.788713 -2.135553 2.019369 0.904697 -51.969856 -7.374707 -46.707132 -56.761316 12.569166 2.124681 1.255971 1.101096 1.367529 1.811129 0.901921 1.834283 0.802354 2.419522 2.148173 2.340749 1.219742 1.959194 0.919061 1.914202
+1 0.025381 1 1 1.663988 -1.379603 -2.025067 2.277333 1.108566 -1.117554 0.858038 1.126607 0.497616 -1.063240 -0.492384 -0.536145 -28.550443 2.701620 -43.877320 -46.115290 -9.675299 1.183629 0.253790 0.944358 1.831158 2.272312 0.743150 1.867972 2.260788 0.565938 2.477703 1.248153 2.455112 1.812506 1.534929 0.551761
+1 -0.025441 1 1 -0.853933 1.883968 1.302439 1.050615 0.369186 -1.300337 1.301752 -1.071757 -2.273065 -0.061648 0.614901 0.376534 -10.632651 -52.965969 50.953147 19.546554 18.937029 0.994629 0.721392 0.693700 1.016002 2.201301 2.020471 0.301955 0.457518 0.499532 2.387960 0.445503 1.067648 1.705438 2.042711 0.602440
+1 -0.036931 1 1 -2.331837 1.759584 -1.624585 -0.823544 -1.016877 1.185445 -0.209186 -0.344232 1.301553 0.292953 -0.788802 -1.452253 68.701711 -30.335541 0.565899 61.061962 -31.599373 2.264993 1.492185 2.156588 2.017184 1.313650 0.767439 0.597922 2.275735 2.035371 0.987702 1.312639 1.780686 2.241224 0.259671 0.783226
+1 0.055407 1 1 -1.554364 1.279546 -2.022867 1.569612 0.521197 -0.572140 2.025384 -1.662866 1.383782 1.584579 2.314127 2.186996 6.828117 10.158723 37.650481 -58.371892 -56.389709 0.747361 0.647797 1.276530 2.393606 0.841412 1.861090 1.333456 0.648453 1.053916 0.413251 1.262806 1.231570 0.502039 1.767826 2.106340
+1 0.027529 1 1 0.263607 0.796844 -0.045513 -1.532039 -0.477479 0.211359 -0.824536 1.155802 1.090640 -0.802008 -1.917951 -2.256053 -51.093854 15.594274 42.962908 -22.405890 74.203612 1.976581 0.639532 1.863704 0.271308 0.616805 2.397737 0.507905 1.355866 1.541912 0.920469 0.829205 1.453475 1.805982 2.133757 0.797697
+1 0.014514 1 1 0.954321 -1.706401 0.114569 -1.813563 -0.826136 -2.162600 -0.156191 -0.303622 0.535077 1.802021 0.038135 0.055563 25.267147 14.940695 8.254116 -23.068909 30.851185 0.862924 1.157400 0.425535 0.714037 0.824278 1.892638 0.575025 2.202795 2.375865 1.909725 1.998732 1.693453 0.867870 1.042830 0.837601
+1 -0.002586 1 1 1.283941 1.174577 0.918174 -1.324545 -0.301736 -0.754433 1.278682 2.313983 -0.233866 -0.447172 0.633232 2.150469 -34.591452 21.461704 -43.133842 -0.482476 -8.976518 1.849805 0.669588 0.757099 2.311489 2.193449 0.555036 1.491697 0.710272 0.536449 1.844579 0.587767 0.352773 1.802889 1.905432 1.844816
+1 0.028753 1 1 1.672848 1.435877 0.634476 -0.492889 0.386701 0.907558 -0.675205 -0.732904 0.272977 -1.941368 0.008661 -0.510385 -47.408304 8.638953 -5.115909 -33.086538 -35.452260 0.683072 2.388535 1.111124 1.156769 1.067586 0.666188 2.120015 1.594016 1.367806 1.958355 0.323796 0.785254 0.758177 2.427000 1.837642
+1 0.026744 1 1 -2.258166 0.593728 -2.052455 -0.918605 -1.201458 -0.322429 0.175020 1.032783 2.261353 1.149268 -0.328283 0.757906 17.079170 -50.387887 30.777825 -67.093290 63.079067 0.923072 1.812929 1.903237 0.951789 0.715669 1.255671 0.563929 2.456898 0.330586 2.411926 0.481968 1.940386 2.060618 2.303142 1.404331
+1 0.002109 1 1 1.941552 -1.632718 -0.850065 0.916679 1.824420 -0.485223 2.002396 -1.609653 0.382574 2.224115 2.031033 -0.970958 3.718907 -46.322946 -49.758972 -49.041727 5.698053 2.382674 1.595317 0.749213 0.271215 1.314191 0.852480 1.135074 0.946070 1.345436 1.749688 1.000629 0.323781 0.536751 2.420328 2.196810
+1 -0.000595 1 1 -0.261298 0.317425 0.541098 -0.683409 -1.965725 0.613865 1.813070 1.954445 -1.701824 1.645100 1.608358 1.404742 13.763590 24.653420 50.033324 10.075528 -10.593781 1.379804 1.110956 0.580348 1.662122 0.793426 0.867385 1.884321 0.283036 1.980372 1.360797 1.171777 1.314717 0.699109 1.919471 1.550375
+1 0.015046 1 1 1.802592 0.211906 -1.067557 2.348615 2.194271 -0.043816 -1.290617 -0.266715 -1.197450 1.071028 -0.557347 0.894987 3.209458 -58.633491 46.919612 27.918347 23.661874 1.901628 0.906463 1.671930 1.378737 1.188496 1.045891 0.546045 1.134145 1.082422 0.267517 2.164981 1.329529 2.138116 2.060490 2.413995
+1 0.003676 1 1 -1.255720 1.900225 1.218986 -1.974647 1.469591 1.776927 -2.314939 -1.695650 1.731707 1.083279 -1.997414 0.516502 20.080134 -13.187233 62.183122 61.724102 -3.020001 0.517717 2.015224 2.124921 0.802894 2.495776 1.251274 0.905208 0.830372 0.806763 2.270625 1.637954 1.837898 0.804599 1.887863 1.312048
+1 0.033323 1 1 -0.184774 -0.039916 -1.712769 1.480706 0.104830 -0.558620 -1.655818 2.029153 0.411271 -0.839521 -0.942428 -1.054992 46.984589 69.991522 47.505569 -23.904900 -69.655019 2.246512 1.383329 1.866371 2.354787 0.907904 1.136715 1.512368 1.616466 0.689400 0.745407 1.551905 2.363228 1.031792 2.074815 2.415896
+1 0.004633 1 1 -0.487418 -1.902030 1.426783 -1.410370 -0.776075 0.397228 -1.239478 1.555913 1.177724 1.969949 -0.318137 1.634820 -48.294668 -38.483962 0.044732 1.807488 -71.552292 0.934367 0.400884 0.405382 1.751200 1.669681 1.821486 1.722463 2.435586 2.139293 1.603290 2.000409 0.631889 1.656523 1.188616 0.827991
+1 0.022068 1 1 0.526768 -1.190942 2.071058 -2.146467 -2.338242 -2.213089 -0.504149 -0.350557 -1.322939 -1.584418 0.403073 -1.967675 26.488791 -2.888304 56.281971 31.079800 58.204650 0.558173 2.468278 0.346464 1.516402 1.911315 1.725629 1.642091 1.619961 0.935008 2.181211 1.855899 1.851586 1.352122 1.610302 0.597722
+1 -0.057824 1 1 -0.598727 -1.856851 2.050728 0.165128 -0.284716 -2.153152 -1.591955 0.961581 -2.203976 1.871188 -1.433401 -1.431049 12.483542 -39.106293 40.540102 57.493393 -8.548177 1.836755 1.833767 1.128966 1.789834 0.745477 0.474986 1.582102 1.391226 1.840451 0.964769 0.629254 2.371011 1.331524 1.923449 0.900625
+1 0.039554 1 1 -2.203944 -2.303330 0.202280 2.093907 0.173169 -1.806345 -2.021423 2.271240 -2.327718 0.301626 -1.106982 -0.542161 52.911157 -72.177072 -30.051974 -33.520365 23.224693 1.936340 1.573052 2.280418 1.982193 0.466290 1.683232 2.330184 1.402991 1.566981 1.500282 0.990862 0.422857 0.701946 2.360663 0.667899
+1 0.010176 1 1 -1.999753 -1.084706 1.579991 0.589750 1.768684 0.520909 -0.697640 -0.806278 1.712409 1.903534 0.288037 1.417709 50.927775 43.113129 -47.641081 -3.647210 51.350586 0.614604 1.399317 0.577663 1.538793 0.250344 1.535299 2.272222 1.487799 0.429419 0.738498 2.444289 2.162573 1.371897 0.978973 0.846837
+1 -0.038715 1 1 -1.484993 -1.466121 -0.013652 1.459073 -0.624453 -0.696006 -1.621125 0.781585 -2.033131 -1.302522 2.279035 1.446247 18.180041 1.952027 -42.274666 39.681826 32.449636 1.090485 0.788311 0.395867 1.584739 0.703804 2.088100 0.691417 0.892224 0.859398 0.407707 0.338103 0.504648 0.618899 1.583698 1.206786
+1 -0.050399 1 1 0.035434 1.776635 2.213642 0.367714 2.222933 1.009937 -0.018857 -1.202103 -1.735324 -0.617946 0.290304 1.822317 59.184801 68.951789 -27.286455 -53.456838 50.917084 1.576501 1.749014 0.931968 0.579390 1.313179 1.853225 1.896760 2.350503 0.899705 0.587626 2.473664 0.873938 1.777058 2.011151 1.160547
+1 -0.043520 1 1 0.079988 1.330014 -2.028412 -2.104824 0.131341 2.053179 -1.044326 1.661929 1.709923 -2.182746 0.541158 0.337860 -0.637259 -60.413528 -20.167737 40.847602 -24.346449 1.513529 0.889403 0.688457 0.638662 0.745864 2.482708 2.114281 1.972797 2.293610 0.949076 2.374936 2.045690 1.159693 0.706283 0.993588
+1 -0.004978 1 1 1.948695 0.617746 1.068320 1.058061 -1.717850 0.898063 -0.032159 1.426771 -1.609859 1.637158 0.071189 -0.478727 -61.171836 -15.047715 -6.943953 -7.014643 4.899067 1.204363 2.231582 2.448569 2.096109 0.300487 0.542903 2.317106 2.099590 0.312349 1.905357 0.584745 1.313782 0.739983 0.396306 2.208540
+1 0.022530 1 1 2.026028 -0.266568 1.271947 2.221524 0.903271 -2.035021 -0.072832 1.132810 1.093843 1.188017 0.602691 -2.207295 -66.470745 26.186565 17.606301 -40.898754 64.644830 1.909871 2.210006 2.071873 2.468719 1.014905 1.759067 1.134005 0.980714 0.852363 1.410840 0.729975 0.941590 0.304647 0.700731 2.188453
+1 -0.006297 1 1 0.169638 0.103982 -0.662938 -1.909420 -0.251431 1.206996 -0.854564 0.698038 -1.924248 0.285294 -2.270951 -2.241580 42.062317 -8.641213 -32.869765 7.854896 17.240720 0.846711 0.925088 1.948494 1.092275 1.624716 2.097754 0.949408 1.208362 1.932205 1.813811 0.964198 2.283965 0.846223 1.716604 0.709383
+1 0.014288 1 1 2.037460 -1.342934 1.650817 -1.265385 -0.312491 2.275907 0.707370 -0.592684 0.742752 0.319297 -0.991052 1.681437 -9.240707 -58.555551 6.862471 -12.445407 -69.952806 1.422952 1.797221 1.135518 1.656439 2.018917 1.188990 0.359133 0.701336 1.096730 2.245065 1.805194 2.388071 2.306034 0.519872 2.236262
+1 0.014158 1 1 1.877065 -1.617088 -2.042146 -2.021500 0.975541 1.510179 0.649497 2.208491 -1.383722 -0.572051 -1.190525 -0.356160 -39.719843 -71.398336 8.174737 -7.194075 -10.819755 0.660572 2.234424 0.722049 0.484821 0.384465 1.210036 0.821933 0.727039 1.100263 0.865258 2.147064 1.713705 1.482832 2.462775 2.364354
+1 0.054076 1 1 -1.338453 1.570612 -1.525533 0.472430 -0.246100 1.278390 2.114501 2.283962 -0.579216 0.907164 2.121191 1.635372 -52.949797 22.757865 -8.570796 -49.366597 -54.398984 0.869242 1.596966 1.450134 1.906623 1.609951 1.452840 2.375641 0.394251 1.433105 1.449404 0.885173 1.606579 1.020640 1.397490 1.361144
+1 -0.001154 1 1 0.376261 -0.210957 -1.834589 -0.773704 -2.155945 -1.402915 2.005763 -1.575613 2.296308 -0.410502 -0.367351 -0.837102 64.112469 -61.736814 -60.636358 -15.272086 -27.955150 0.741944 1.859564 0.445398 1.545938 1.075571 2.126689 1.261526 2.217282 0.613745 0.461885 1.899502 1.183452 1.784258 1.521786 2.398376
+1 0.001237 1 1 1.156293 -0.068576 1.984850 0.375964 -0.492131 -0.995318 0.669186 -1.458097 -1.806502 0.040926 -0.161433 1.136732 32.614161 46.202102 -31.263680 1.333136 56.018049 0.555344 2.169668 1.367250 1.612344 1.159098 1.955451 1.009463 0.291483 2.205584 2.002872 1.519610 1.832178 1.416562 2.416296 1.935541
+1 -0.013181 1 1 1.404876 -2.034610 2.111027 0.456071 -1.863741 -0.639363 -1.530032 0.249621 1.359589 0.242170 -1.345795 0.696844 50.089369 52.032679 13.243098 -23.257123 17.527429 1.127520 2.231298 2.170682 0.400861 2.268663 2.423128 2.010599 0.886505 1.494536 1.169531 1.808956 0.370184 1.936580 1.102841 1.455995
+1 0.012666 1 1 -1.974837 -1.727909 1.479309 0.181573 -1.927205 -2.292434 -0.441350 -0.461819 -0.488288 2.328270 -0.436401 -2.113790 7.630270 -8.056588 42.922006 40.156357 57.890490 2.356968 1.556742 0.418573 0.706514 0.382591 1.210377 2.052414 1.675709 1.889483 1.544490 1.500640 0.263113 2.383153 0.646480 1.631476
+1 0.039318 1 1 -1.843182 0.876909 -2.136706 1.492144 -0.864508 -1.486679 -1.529998 0.826033 0.436389 1.917804 -0.201100 -1.097853 67.057838 -58.921298 9.742088 -64.728100 64.818028 0.573951 2.137876 0.274819 1.137771 1.260425 1.712852 0.646477 1.595148 2.401749 0.443524 1.557619 1.654308 2.197470 0.634788 0.876241
+1 0.000064 1 1 0.546189 0.063464 1.647926 1.976625 -1.206231 -0.422050 -1.242722 -1.120539 -2.197335 0.383742 -1.702367 1.943774 -63.194452 40.849354 5.086961 -3.451055 48.122547 1.309699 1.854059 2.421483 1.363597 0.980689 0.441643 1.439256 1.318272 1.941317 1.962795 0.691592 1.584039 2.440895 1.364241 0.542941
+1 -0.011166 1 1 -1.594734 1.372017 1.768212 2.022417 0.295836 0.542462 -1.315026 -0.531273 0.863723 -2.272467 0.551042 1.523842 -19.682064 -46.444528 6.819059 7.931927 -38.097798 1.979631 2.413290 0.910092 1.912992 0.656915 1.520975 2.270286 0.448502 1.976083 1.276280 0.431947 0.490714 0.429820 0.727413 0.635614
+1 -0.017517 1 1 2.348328 2.087765 0.620929 -1.983353 1.218219 -0.726247 -0.937603 -0.070082 0.222196 2.232322 -1.410731 -2.130704 -41.470268 59.198615 1.128468 66.159710 -3.748867 1.266973 1.519901 2.233119 1.280453 0.830601 2.411340 1.893970 0.448596 1.302347 2.045847 1.555160 0.826546 1.765695 2.288116 0.871259
+1 0.005766 1 1 -0.564041 1.491353 -0.028399 -1.353583 1.750558 2.185896 0.571138 -0.021768 1.713105 -0.538369 -0.576873 -2.125461 63.630392 -64.003591 -58.348484 37.033264 68.075796 0.623510 0.340780 0.488318 0.653036 1.577710 1.821943 0.394884 0.809667 1.576998 1.107794 1.439878 0.531542 0.381615 0.547072 0.383876
+1 -0.007170 1 1 0.138930 -2.340285 1.150056 -1.232732 1.852286 1.324386 2.341182 -0.193679 1.097653 -0.750936 -1.205917 0.131305 46.059588 -26.504817 33.539501 -1.606701 -3.826070 2.053714 1.029364 1.769347 0.658413 1.944499 1.447386 0.722948 2.084065 0.378183 1.373731 0.295812 0.720491 1.296083 0.270101 0.580011
+1 0.001497 1 1 2.202488 1.402730 -0.399298 -0.567716 0.991956 -0.630276 0.400815 -2.215944 -1.365514 -0.850833 2.155564 -0.284712 -66.163221 -55.262349 5.702293 -11.569711 -52.135140 2.345420 0.971206 0.807283 1.997404 1.868432 0.980102 1.831562 2.313597 1.619584 1.352675 1.910864 0.889599 1.747884 2.181605 1.739986
+1 -0.001457 1 1 0.455556 -1.095278 -1.743264 -2.119894 1.321861 2.310111 0.663349 -0.600633 -0.894511 -1.533811 -1.992029 1.487605 -55.760334 36.069524 70.492059 60.032319 63.188806 1.589003 0.375771 1.326503 0.792071 0.587109 0.542070 1.826880 2.372181 0.750724 0.916459 0.923945 0.736802 0.936631 2.460617 2.096229
+1 0.024660 1 1 -0.429223 0.722491 -0.922736 0.052917 -1.257505 0.169884 -0.462256 1.590258 -1.201048 1.858922 -0.240509 0.991406 -14.417536 -65.530174 -65.627178 -45.982378 -25.818983 1.530167 1.524854 2.224451 1.846100 1.399014 2.227667 1.892799 1.020274 2.002045 1.114525 2.071482 0.396336 0.467520 2.116324 0.313457
+1 0.073710 1 1 -0.148941 -0.970849 1.943802 -1.514601 0.419964 -0.826363 -1.278817 0.136980 -2.134372 -1.680665 -0.869507 -0.683486 46.527240 33.328432 50.957210 -62.175026 74.331458 0.457203 1.959619 1.313114 0.757783 0.315629 0.784766 1.558040 1.972940 2.444272 1.883096 2.190367 0.501819 0.315288 1.801837 2.220927
+1 -0.016112 1 1 -1.004641 -0.513084 0.275548 -1.143580 1.691977 -2.209529 -1.922632 -0.823383 1.691767 -1.030440 -0.578270 -2.032969 45.062311 12.253201 -10.446065 -67.016506 3.591790 2.383269 0.355412 1.158311 2.223817 2.443899 2.353626 1.642011 0.271667 2.163902 1.207625 0.810435 0.976185 1.244078 1.463760 1.419475
+1 0.002323 1 1 1.587838 0.542405 -2.275994 -2.174049 0.617383 -0.330197 1.572980 0.578730 0.349971 0.901513 1.405752 -1.438302 32.382541 53.360163 -25.739432 -2.630665 36.411727 0.953381 0.467184 0.956421 2.072561 0.533066 1.243541 1.444913 1.896050 1.659880 1.347290 1.409099 0.730577 2.061532 1.912370 1.451833
+1 0.046921 1 1 -0.149820 -1.604149 -1.356337 -2.132354 -0.758059 1.606745 -2.143501 0.394313 1.591604 -2.137153 -1.305819 -1.298528 -40.812640 11.963949 -71.910378 -47.727119 50.312109 2.059251 1.837457 2.398995 1.400055 1.720987 2.381487 1.907522 0.977967 1.939942 1.358701 1.940472 1.268776 0.318833 0.626527 1.546549
+1 0.005350 1 1 0.340910 -0.586727 1.915655 1.378559 -1.375738 1.660360 -1.103210 1.601829 0.063675 0.466772 -1.093019 -1.475854 42.692934 -59.854994 67.114130 -12.813041 51.221798 1.896361 2.394676 0.817263 0.996337 2.439041 1.718934 1.626972 1.769624 0.819233 0.347512 1.134801 0.854049 0.508235 2.399759 0.748175
+1 0.003901 1 1 0.427078 0.935318 -0.634219 0.102425 1.438130 0.813815 -2.273056 0.080159 -0.502899 1.801861 2.068140 0.645227 35.663862 2.528956 54.162483 -41.156033 -59.446100 1.966048 1.366891 2.340252 1.862442 1.561925 2.026315 1.780641 1.486894 0.970152 1.086555 2.230974 1.235139 1.986622 0.654911 1.588780
+1 -0.025989 1 1 -0.116278 1.360113 -0.377736 -1.023157 -0.700802 -2.124702 0.620197 -0.157804 0.860192 -0.369332 -1.152907 0.439043 -19.108173 -1.067395 60.297576 21.353659 -59.052648 2.157207 1.183262 0.831085 1.551623 2.129911 1.411363 0.526399 1.693960 0.389712 1.640556 0.576641 2.352967 1.815583 1.503358 0.930658
+1 0.010234 1 1 -1.761807 1.967886 -2.005025 -0.170310 -1.985006 1.711833 1.645933 1.479993 2.261975 2.175873 1.752141 0.510101 45.831880 46.402963 44.598829 22.521524 69.258403 1.764749 2.132964 0.971114 1.515075 2.114521 1.511778 0.710319 1.332320 1.803793 1.348586 0.693338 1.686029 2.084049 2.358884 2.257094
+1 -0.018964 1 1 -1.696808 1.128397 2.318425 -0.973870 -1.701776 -2.253807 -1.553688 -1.485877 -2.178457 1.938261 -0.394293 -1.271073 -52.734786 36.443778 60.577903 -67.178308 -15.820692 2.149365 2.120729 2.341710 1.626656 0.949792 0.908307 1.169547 2.077991 1.797421 2.247333 1.680451 0.596165 1.988495 0.642772 2.315083
+1 0.050856 1 1 0.735708 -0.262123 0.589994 1.157672 -0.462716 -1.425892 2.240614 1.304334 -0.097936 -1.391502 0.615208 0.827618 -38.158972 62.163320 28.913619 -48.807448 43.225430 1.972138 2.466988 1.175206 0.440460 1.807229 0.602420 1.364669 0.983483 2.395726 0.466162 1.791832 0.565588 1.086166 2.449110 2.191768
+1 -0.035271 1 1 0.422674 2.318083 -2.015859 1.526527 2.100436 1.530649 0.677183 0.997665 1.074530 1.743651 -0.804626 1.200022 -7.827587 -8.252338 52.957813 -38.038266 -9.136112 2.115407 0.645660 1.362952 1.376562 0.622667 1.919583 1.179749 0.290644 1.607149 1.601120 1.519898 2.181893 2.082746 0.704866 1.931564
+1 0.007158 1 1 0.410340 -2.347673 -0.509755 -0.324284 1.995542 0.995695 0.953567 -0.236089 -0.111396 -1.411709 0.287122 0.165363 -33.385009 48.149491 -1.508354 -0.910970 -10.664550 1.538734 1.503726 0.381819 1.734889 2.021349 1.566639 0.256752 1.235815 2.100663 0.338282 1.250911 1.558787 1.036458 1.740592 1.122512
+1 0.063313 1 1 -1.500725 -1.979855 -1.249600 1.095162 -0.197224 -1.936169 -2.141945 -1.729032 1.465725 -1.932694 -0.295282 -0.667242 36.349297 -27.359940 61.489264 -49.931977 43.255086 0.448426 0.688330 0.765734 1.193332 1.333345 1.025384 2.378155 2.152701 1.944033 0.364175 2.187893 1.673917 1.021382 0.364561 1.934416
+1 0.011865 1 1 -1.430305 -1.246787 1.248488 -0.933747 -1.225242 0.492098 0.444318 -1.491757 -2.045629 0.708652 2.114865 -1.017813 -13.168230 -68.444663 0.552418 -15.516124 70.511209 0.353382 0.794546 1.688836 2.019888 1.765657 1.654357 0.770020 1.223437 1.056703 2.253384 2.132402 0.530541 1.545052 1.933413 1.872845
+1 0.005792 1 1 0.849425 -2.250059 0.188706 0.143649 1.562611 0.652317 -2.242327 -1.821440 -1.267204 2.094473 0.270780 -1.164828 -63.600861 -39.677420 41.605818 -31.019614 53.352795 1.381283 1.216720 0.658828 2.165980 2.382740 0.453490 0.309441 0.267910 2.014958 2.146270 1.856323 2.216742 0.525305 1.304448 1.357557
+1 -0.015361 1 1 -1.819655 0.463653 -1.683450 -0.568128 -1.222182 0.081692 1.699781 1.723725 -1.126708 -2.202656 0.481337 -1.343801 38.928674 -25.772477 41.976910 55.929488 -43.093541 0.277818 2.045008 0.955985 1.494473 2.361281 2.045394 0.690938 1.850342 0.698068 2.420656 0.972160 1.089011 0.758197 0.511648 1.261925
+1 0.000973 1 1 2.093600 -0.273268 1.762207 0.046100 1.973638 0.426039 2.313509 1.217041 -1.667791 -1.271942 -2.139796 1.395142 -22.014183 57.622168 55.771239 -2.784565 -0.185313 1.906715 0.900785 0.750840 0.623560 1.170937 0.681697 1.781871 1.899841 2.375158 1.278956 0.414437 0.945530 1.266330 1.951063 1.518030
+1 -0.031173 1 1 0.665822 -1.450609 1.517817 1.787695 -0.401758 0.512361 1.709880 1.804897 1.252377 -1.547975 0.292211 0.887158 14.786683 -30.215382 70.070874 31.184632 20.112116 2.489976 0.523625 2.320827 1.635484 0.821453 1.661173 0.591380 0.325697 1.247792 0.882869 1.121704 1.222499 1.038568 1.218181 0.465339
+1 -0.023113 1 1 -0.506050 0.674407 1.459734 1.054869 1.176010 1.443843 -2.131993 0.605053 -0.210097 -1.523628 -0.490758 -1.493499 52.518507 -71.451069 21.877159 39.410763 -23.311998 1.303739 0.697838 0.811994 2.436089 1.602391 0.378379 2.415901 2.047933 0.604878 2.182727 0.341285 2.230699 1.109644 1.029416 0.392118
+1 -0.027392 1 1 0.508004 -0.822564 1.315268 -0.108358 -2.192878 -0.103849 -1.804216 0.766508 -0.969998 2.104547 -0.069633 -1.653026 58.572610 -20.146173 -46.724194 -43.530442 -66.141303 1.571890 0.761813 0.539302 0.300580 2.102121 2.347371 2.264411 0.708194 1.624189 2.252340 0.336253 0.911782 1.071879 0.819100 0.368576
+1 -0.046996 1 1 -0.894275 -2.273168 -1.804639 -1.627572 0.812303 0.583775 0.316924 1.548217 -0.934240 -0.095531 1.332693 0.580781 58.352675 33.405233 -8.251839 61.339854 -11.067165 1.287459 1.579776 0.551329 2.192280 1.148321 0.834344 2.316343 0.521122 0.751519 0.781166 1.809405 1.170854 1.543060 2.216352 0.719721
+1 0.001329 1 1 1.277965 -0.309380 -1.977531 0.119074 -1.483321 -1.632713 -0.757384 -1.182871 1.052412 2.284632 1.267582 -0.457779 45.645793 68.850802 -74.570026 -48.419419 -35.172983 1.340178 1.114424 0.368730 2.245921 0.439992 0.691722 1.526682 1.449159 1.256912 1.172551 0.819683 1.167253 1.765987 0.438828 1.387670
+1 -0.052402 1 1 1.255862 0.487961 1.598709 -0.536899 0.559765 2.038654 -0.120652 -1.475418 -0.761539 -0.331825 -2.225905 0.866706 23.083399 62.690557 40.183643 66.483249 33.967884 1.348521 1.833563 2.193439 0.377164 2.249502 2.129213 0.930238 0.760382 1.247600 2.158019 1.324753 0.616192 1.095697 0.627581 1.246832
+1 -0.013850 1 1 -0.931588 2.074964 2.245413 1.850877 1.201604 -1.946416 -0.004651 1.938953 1.812463 1.175423 0.992212 -1.035714 10.193246 17.893193 -19.104741 56.614903 -73.319362 0.947194 2.231232 1.073180 2.442407 2.039825 1.591816 0.394938 1.716107 1.369199 0.621704 1.474845 0.967020 2.460876 1.945716 1.646803
+1 0.007386 1 1 1.919196 -0.369898 -1.229312 -1.926132 1.605600 2.182770 -0.132813 1.482962 0.312788 -1.993258 -0.314297 0.206373 6.045058 49.286478 57.843978 33.731144 69.339481 1.954797 1.275995 2.396136 0.613456 2.347607 1.724380 0.902279 1.105002 1.764128 0.704313 1.638222 1.850941 1.761096 1.485584 1.461358
+1 0.022116 1 1 -0.077543 2.070576 -0.819148 2.175514 0.436568 0.216778 0.703395 -1.426954 -1.465676 -1.956144 1.420645 -0.902715 62.267580 -18.778348 -7.694659 -24.126012 -35.885935 1.601245 1.369494 1.087394 0.583741 2.443057 1.713879 2.168044 1.059263 0.278896 2.161946 2.072940 2.397202 0.517690 1.563439 0.474563
+1 -0.003362 1 1 0.663141 0.606190 0.055974 -1.729281 1.996115 1.211067 1.595826 -1.872479 -1.414923 -1.896528 -0.344916 -0.758011 -73.452508 -16.300108 -55.913596 10.193045 14.509854 0.881642 0.751512 0.658429 2.218043 2.140389 2.012367 1.344151 0.392282 2.075732 2.075716 1.810643 1.724412 1.438853 1.302872 1.876117
+1 -0.020210 1 1 -0.607258 0.841290 -2.322939 0.505914 1.744470 -1.179023 -0.245146 -1.532992 2.344008 0.176727 1.451676 2.282851 -12.339885 53.553340 70.985636 -44.407976 35.154266 1.191208 1.641767 0.676353 1.971078 0.416174 0.882590 0.947905 0.696949 1.618628 1.030498 0.579898 0.839177 0.297517 2.362226 2.187657
+1 0.015790 1 1 -2.037617 -1.297959 -1.155346 1.855842 -0.165093 0.877614 0.275181 2.115782 0.261382 1.101789 -1.928305 -1.915929 -40.070038 42.869492 57.555564 -13.630443 -36.853788 0.600757 0.421055 1.927034 0.406727 1.854537 1.455617 1.802518 2.418471 2.493956 2.165328 0.409379 1.439197 0.331586 1.209290 1.788615
+1 -0.063531 1 1 0.051942 1.195099 1.827203 -0.845870 0.744610 -1.444281 -0.509374 1.361646 1.829259 0.736166 -1.983256 -1.852675 49.464057 42.407198 -62.220045 67.703122 -13.623231 0.390427 2.407005 1.032916 0.713657 1.190473 0.531144 0.431423 0.671838 0.328420 1.999580 2.443223 2.250063 0.304854 1.926162 1.496536
+1 -0.041408 1 1 -0.928113 -0.786300 -1.800686 -1.167238 -0.097146 -2.241293 1.422142 0.706367 1.403519 -1.276197 1.745890 -0.872463 46.595013 -27.615525 -34.126203 40.901497 -18.548298 0.756404 1.886802 1.479307 1.717555 0.950768 1.562209 2.295433 2.337798 1.112954 0.422454 0.677373 1.100291 1.339460 0.304533 1.029078
+1 -0.053182 1 1 0.103970 -0.871868 2.041589 2.085206 0.014774 -1.450210 -1.204780 0.395421 1.375642 1.432331 2.304672 -1.219818 67.296622 54.327376 30.203976 38.216341 2.041460 0.787251 0.575488 0.980537 2.386846 1.967152 1.922724 2.214828 2.106034 0.609082 0.848267 2.326476 2.081650 0.284801 2.408768 1.418944
+1 -0.010804 1 1 -1.665525 -0.882751 -1.799320 -1.765772 1.287336 1.674681 -0.735235 -1.204975 1.831865 2.110625 -1.596529 -0.513187 -46.307501 59.837783 -56.377912 6.432601 -37.270925 1.188538 1.750177 2.467178 2.112583 0.434481 0.325253 0.528459 0.315736 0.325406 0.844931 0.259335 1.895193 0.762755 0.621623 2.360069
+1 -0.007893 1 1 -1.564747 1.132621 -2.091376 -0.042261 1.292343 1.003521 0.539110 -1.110004 0.514103 -1.997726 -0.014724 2.289103 32.128709 -12.787850 24.597069 2.944814 -6.512147 2.130311 1.393463 1.181196 2.102315 1.112828 0.545176 2.272715 0.773270 1.855752 1.624499 0.701601 1.058899 0.923055 1.529419 2.446861
+1 -0.039403 1 1 -1.946263 -2.145409 1.311695 1.095736 0.027479 0.021131 1.726426 1.861179 -0.008172 -0.695449 -1.679114 1.621361 -48.801700 -10.169781 -73.502880 37.093746 34.583810 1.376385 2.147976 1.280723 0.864158 1.661264 2.122142 1.334565 1.281661 0.876834 0.948861 1.004493 2.256815 1.287869 1.719181 1.267014
+1 -0.017691 1 1 -0.151300 1.784579 -0.940593 1.520770 -0.420728 2.124885 -2.260038 2.104634 1.398890 1.040803 0.392086 1.869146 62.154698 34.001740 -32.762038 18.420466 -7.236000 1.893196 0.943454 2.374603 0.948212 1.347079 2.362809 0.729360 1.861235 1.520605 0.561641 2.251359 1.846295 2.429263 1.614851 0.551378
+1 -0.040614 1 1 1.296732 -0.617678 0.074434 2.232909 -0.963932 0.394722 -0.944007 0.695634 0.089800 1.299849 -0.075266 -2.068881 32.952489 32.490994 -73.868653 39.541347 71.415211 1.006740 1.786666 1.490106 0.955253 0.439654 1.763664 1.901002 1.643287 1.480926 1.927123 1.913645 0.383533 1.287872 1.768856 1.420240
+1 -0.028220 1 1 -1.199566 -1.511439 1.727360 -1.288290 1.131279 -1.077894 -1.748813 -1.136967 -0.266732 -1.488219 0.864052 -1.463823 28.842308 -47.325505 50.232758 61.956477 2.504179 0.440985 1.634347 1.963110 1.494906 0.634463 2.163827 2.189947 2.444316 0.365221 1.774297 0.607289 2.200529 0.295828 0.976971 0.953823
+1 0.005223 1 1 -1.126850 0.120920 1.263236 1.896797 0.149994 -0.181667 0.350547 1.159372 -0.159592 -0.919569 1.433596 0.003346 -9.710401 -2.712907 4.167303 -10.138632 0.006090 0.660366 1.027413 0.488151 2.352237 0.794081 0.612105 2.148123 1.496716 1.809864 2.142123 1.910247 1.764675 0.889023 1.059107 2.155053
+1 -0.061322 1 1 -1.005679 0.885797 1.149926 1.301840 0.408458 -1.004833 0.973223 0.252258 -1.446814 -0.678306 -1.024637 -2.002298 -46.266208 3.843816 -46.976091 72.840109 73.704933 2.257228 1.487427 0.934305 1.608147 0.382601 1.370604 1.742666 2.244569 2.468972 0.754950 2.197322 0.395779 2.360785 0.461972 1.115461
+1 0.043541 1 1 -0.246555 -1.664921 -0.159345 -1.472641 -1.218850 -0.461195 0.571103 -0.600134 -1.941794 2.276517 1.537251 -1.446015 -44.063608 -27.054312 -51.821973 -71.902185 -60.023326 0.444457 1.493800 2.291563 0.293402 0.710648 2.365471 0.474441 1.433016 2.197469 0.612864 1.406012 0.599773 1.885260 0.310573 1.308228
+1 0.031389 1 1 1.030973 0.117504 0.402584 -0.754170 0.984071 -1.201682 0.630948 1.466305 -1.612064 2.273624 0.041203 -0.220596 34.862129 27.798565 -39.523700 -74.827121 -19.429890 1.252683 2.090885 0.253181 1.970222 1.777977 1.708654 2.105646 0.848842 0.743805 1.628893 0.307811 2.132636 2.212968 2.357660 1.939097
+1 -0.006250 1 1 -2.017386 -0.565031 -1.010038 -1.688839 -1.598019 -2.002701 1.197294 1.022596 0.688423 1.406978 0.317315 -1.317441 40.682726 54.578814 56.125234 -53.197437 60.670431 1.193913 2.093704 0.379431 2.092728 1.986024 1.859017 2.492955 1.093310 1.008700 0.970658 0.591404 0.727278 0.616123 2.186457 2.283285
+1 -0.015996 1 1 0.232948 -0.844267 -0.596195 -1.717240 1.738972 0.668650 -1.049038 -2.136372 -2.310731 -1.659969 -1.761489 -2.122771 2.453596 -12.417987 -59.100182 3.236467 -54.696639 2.328892 2.191461 0.880466 1.240109 2.268737 1.408422 0.606235 2.491547 2.184734 0.318366 1.779528 0.774796 0.496329 0.299298 0.795958
+1 -0.015339 1 1 1.685418 0.649443 1.302253 -2.074229 0.681553 -0.959814 -1.093921 2.215174 -2.150256 -0.043941 1.323028 -1.630349 40.414258 42.430797 34.397261 14.769743 -14.930087 1.675447 1.985936 0.367418 0.449179 2.108473 1.099995 0.860756 0.731179 0.920291 2.335478 0.381830 1.919346 1.702594 1.489577 1.067049
+1 0.027805 1 1 1.863622 -1.346341 0.936029 1.889086 -2.216080 1.073389 1.432733 -0.363120 -0.420110 -1.624225 0.525442 0.092803 -2.060706 15.718651 33.363049 32.770674 -23.273795 1.934864 1.501274 1.904783 2.194447 1.565175 0.388855 0.735331 0.959362 2.002428 0.809452 2.460218 2.128604 1.941345 2.442702 2.490107
+1 -0.050774 1 1 -1.788182 1.649635 -2.277372 -1.764493 -0.765339 1.777813 -1.562956 -1.747894 0.171991 1.960296 -2.333651 -0.453527 70.325234 -43.789904 73.088705 51.873208 33.010202 0.662057 2.440280 2.287301 0.675144 1.900316 1.356341 0.516086 1.615511 0.385713 1.922465 2.369056 2.223798 2.125011 2.313564 1.064256
+1 -0.018651 1 1 -1.023555 2.038502 2.031944 0.205672 -2.168647 1.884381 -1.168667 -0.548168 -0.338294 2.141938 1.612820 1.005591 74.664034 -21.585720 58.804224 -27.408715 -8.277914 2.471535 1.082286 2.487215 1.367721 0.529446 1.147703 1.699047 0.387028 1.532670 0.840499 2.269083 0.484857 0.991072 1.690919 1.029246
+1 -0.014031 1 1 -1.140073 -0.627285 -1.169384 1.542629 -0.603147 -0.736310 -0.432074 -0.078205 0.366101 -1.318782 2.301635 -0.416890 20.835848 -61.907958 62.956931 17.142347 -38.568717 0.258562 2.397693 2.031661 1.622584 2.273842 1.710803 2.209793 0.745259 1.324342 0.471787 1.827366 1.537152 1.922618 0.436215 2.459838
+1 0.005925 1 1 -1.864927 -1.727509 -1.217398 0.389284 1.899782 -1.502560 0.165698 -0.143807 0.492842 -1.188566 -0.410824 -1.072692 27.653806 -72.480502 -29.798708 23.117436 34.744930 1.495599 1.036293 1.221859 1.532085 2.247535 0.566567 1.795009 2.220268 1.300937 0.840994 1.581885 2.241147 1.200857 1.804492 1.848765
+1 -0.018495 1 1 1.801614 -2.085313 -1.817586 2.250562 -1.148396 0.849834 -0.094339 -2.200196 -0.584319 -0.029388 0.869180 -0.095765 67.513246 -54.881255 -39.248760 46.097254 6.554148 2.208549 2.333721 2.351687 0.548636 1.925100 1.657809 0.287535 1.100156 1.330870 2.175981 1.717060 1.628704 1.630947 1.076749 1.661793
+1 -0.006296 1 1 1.632528 -2.336850 2.326334 0.006361 -1.477721 -1.765608 -0.662895 -1.194668 0.702046 -0.531196 2.159276 0.834985 3.103932 -32.219465 -12.554691 43.300072 -55.689183 1.853471 1.532857 1.736741 1.650490 1.041307 2.252018 1.667387 1.521685 0.714167 0.753521 0.675325 0.432484 0.508716 1.497163 0.321459
+1 -0.005003 1 1 -2.327451 0.077089 -0.278779 -1.326155 0.914412 1.414207 -0.715143 1.888042 -0.905234 2.038715 0.909800 -0.694101 67.664791 -57.859425 6.639230 -14.462006 -62.930046 1.145784 0.946308 0.841152 1.992620 2.458750 2.220046 2.069167 1.992851 1.852156 1.935243 1.126714 2.185267 0.284861 1.163803 2.291315
+1 -0.015530 1 1 -1.130610 -1.808792 -0.745288 -0.522123 -0.844953 2.020744 0.459329 1.054466 -0.891895 0.022654 -0.950353 -2.298736 64.228265 -65.552397 10.871871 23.538951 69.147774 0.874580 1.315185 1.821959 0.660538 1.662579 1.716252 1.548547 2.174601 1.022683 1.990545 1.341589 2.331428 2.054421 1.658583 2.059160
+1 0.002182 1 1 -0.307836 0.395171 1.875015 1.638955 2.008874 -1.128021 -0.712453 -0.012013 0.724369 -2.348779 -0.248429 -0.164009 7.776530 50.137907 -32.200982 -1.908486 24.071498 1.669911 1.188953 1.988545 1.478194 1.000509 0.562179 2.293487 1.128871 2.426714 1.531580 0.517409 1.348136 2.121238 1.896200 1.934265
+1 -0.032010 1 1 1.216982 2.050842 2.094110 -1.128548 -0.149601 2.073577 -2.220138 -1.156305 -0.133642 1.682838 -0.300479 1.535108 7.267550 45.716342 54.568050 25.216360 61.368297 1.629494 1.412996 0.975859 0.270235 0.586471 1.062177 2.005869 2.392492 2.359733 0.779721 2.271683 1.420807 1.751290 0.932938 1.146091
+1 0.014373 1 1 -1.404289 -2.248645 0.383295 0.209293 2.144352 -0.227593 1.310065 1.987111 0.679849 -1.315161 1.898667 -1.393958 55.678910 -54.566930 -6.397856 21.243293 36.030922 1.700637 2.356476 2.290218 2.445225 2.140999 1.017248 0.643533 1.601447 0.270279 1.320938 1.758790 0.976232 2.028785 0.534320 2.059302
+1 -0.004707 1 1 1.562563 -0.142762 -0.789200 1.290924 0.714148 0.227877 -1.247263 -2.049986 -1.835815 2.184507 0.791311 1.203620 -33.369562 7.779117 -56.385829 23.365932 11.216839 0.946290 0.549119 1.041593 0.301758 1.649024 1.142470 1.499773 1.429347 1.277198 2.360627 2.304548 0.288342 1.161296 0.650390 2.109113
+1 -0.040132 1 1 0.679448 1.365355 -1.820193 0.854566 -0.677790 -1.778532 -1.099021 1.323396 -0.165446 -0.338454 -0.541442 -0.396494 -17.795876 4.719261 -33.384665 53.932395 -8.236695 1.612924 1.913769 2.464410 0.587868 2.050823 1.931978 0.253063 2.235352 0.552028 0.437175 0.605076 1.018269 2.042943 2.240880 1.220656
+1 0.025005 1 1 2.145798 0.517112 1.458873 0.726242 0.861961 1.087942 0.972320 -0.778175 -1.914349 1.728779 -0.999212 1.196043 -36.667724 -74.429147 69.334727 -41.245085 -56.148826 0.725234 2.257466 0.985432 1.402040 1.330825 1.434030 1.237437 2.360752 2.160465 1.943491 0.252491 1.613226 2.484164 1.851605 1.679708
+1 -0.009575 1 1 1.315399 2.093689 1.231694 -0.447984 1.133614 0.452871 0.896758 1.599852 -0.184380 1.883638 0.467573 -1.770761 72.274865 23.657607 -36.590813 18.202567 -69.462621 1.250921 1.730689 1.198205 2.233691 1.893334 1.019453 1.688123 1.288870 0.530950 1.668960 0.954277 2.032935 0.534175 1.873280 1.463706
+1 -0.032782 1 1 -0.426616 2.121475 1.691204 -1.069632 0.457148 2.085078 -2.126641 1.006863 0.153224 2.268078 1.073550 -0.580970 -9.372710 -27.136359 69.214808 43.284824 -11.964819 2.234420 0.638616 2.226230 0.253928 1.020304 0.256799 2.012634 1.331131 2.077944 1.007730 0.420087 1.408935 2.474541 2.108281 2.387172
+1 0.001452 1 1 -0.675009 -2.156697 0.091518 1.900970 -0.392064 -1.504578 -0.769669 -0.320765 -0.117962 1.325778 2.166742 -0.915514 -34.571303 60.105572 -55.656002 -10.433226 -1.228244 2.228644 0.315719 2.282985 2.382784 1.199879 1.120989 0.464080 0.540064 1.858551 1.415484 2.291223 1.335056 0.533728 1.117003 0.972445
+1 0.000702 1 1 1.886881 -1.565156 -1.016792 -2.091835 1.668287 0.194381 1.272965 0.475521 -0.129735 1.375681 2.082283 -1.981527 -33.939074 35.987855 47.881113 -12.134926 48.307073 0.579659 1.328511 0.784525 2.009038 1.654977 2.197315 0.267407 0.312215 1.895675 2.106673 2.344822 2.178006 1.993341 1.084289 2.398666
+1 -0.067126 1 1 -0.963963 -0.139608 0.377938 -0.293534 0.452129 -2.148374 -1.397993 -0.100986 -0.812108 -2.025013 -1.522733 0.402958 25.755433 -28.440808 45.333780 74.848430 -72.443279 1.312032 0.568190 2.067619 0.720029 0.273131 2.010246 1.703041 2.264678 0.689575 1.444565 0.548731 1.266455 1.815116 0.406710 1.578106
+1 0.006114 1 1 -0.087510 -0.513635 0.435955 -0.661824 -2.031373 -0.028582 0.284009 -0.308451 -0.506371 0.004951 -1.611494 -2.275100 -40.641572 37.091048 -10.753173 21.416269 -56.758952 2.159473 1.003790 1.695427 0.286066 1.162438 1.848893 1.090700 2.148717 2.487529 2.142736 0.972112 0.290692 2.410539 1.935264 1.478531
+1 -0.051781 1 1 0.274917 -2.317781 -2.340451 -1.643635 -0.553743 0.214490 -0.036755 -0.417764 0.091867 -1.647943 -2.275102 -1.316403 -3.646622 61.229421 -67.119983 64.439101 27.973247 2.070475 1.468838 1.266301 1.477055 2.116122 1.421037 1.120958 2.194024 1.202695 1.201595 0.708205 1.807872 2.411344 1.954264 1.315716
+1 -0.025362 1 1 -1.396526 0.996005 1.452338 -0.731590 -1.217817 -1.940956 2.230250 1.466692 0.191184 -0.617813 -2.195032 1.395077 -56.708087 7.184218 -4.841785 74.113125 19.289601 2.129839 2.454314 1.900641 2.318526 1.217841 1.498681 1.079772 0.732375 0.778597 1.387630 2.147356 2.120597 2.381211 1.764928 0.643578
+1 0.027697 1 1 -0.300901 -0.850158 -0.639953 -2.018176 0.297816 0.842592 0.714547 2.218628 -0.660416 -1.942005 -1.269729 2.081621 32.849361 -50.781353 17.803769 -22.062302 -1.106308 1.469182 0.294592 0.457188 1.709355 0.379263 1.516396 1.810361 1.486815 1.900138 0.627247 2.387221 1.521926 0.265634 2.005887 0.437959
+1 -0.004287 1 1 -0.034925 2.067897 1.273130 -1.457081 1.124552 -1.054289 -0.850032 1.468970 0.780048 0.408717 -1.363543 -0.717220 -0.749999 -5.235050 64.520060 38.645067 7.636414 0.553279 1.214002 2.228005 0.824520 1.455639 2.181207 1.788773 0.901977 0.525273 0.768121 0.803126 1.894147 1.177197 2.394332 1.786296
+1 0.013633 1 1 2.186153 0.178350 0.451171 0.592270 1.720757 0.823401 -1.386651 2.030038 1.157095 -0.735364 1.333322 1.732559 40.462556 -45.813097 -30.716967 39.931271 24.875599 1.887893 1.822877 0.340010 1.044614 1.579813 1.170755 2.132060 1.537152 1.907685 1.462115 0.764883 0.394714 2.458047 1.652741 0.624796
+1 -0.003810 1 1 0.754232 0.055048 1.565389 0.217060 0.736581 0.278053 -1.448604 2.230460 0.283731 -0.264741 -1.003648 2.047649 8.269574 -63.276103 18.536592 -5.490556 -29.770012 2.206044 0.738915 0.447256 1.274448 1.152651 1.603829 2.059160 0.300726 2.309679 1.028226 0.641634 1.186120 1.614409 2.126439 1.566191
+1 0.057052 1 1 1.419905 0.798324 1.260888 0.127154 -2.355402 1.531556 1.790746 -0.956146 -0.699229 0.763484 0.037214 -1.297468 -73.769882 49.597618 37.157820 61.483611 5.049247 0.815499 0.585286 1.401518 1.559019 0.433772 1.908913 1.854917 1.091623 1.909016 1.326071 0.270263 1.053558 1.151795 0.726004 1.705678
+1 -0.062568 1 1 -1.127096 0.710357 -2.228052 -2.224534 0.353108 1.786992 1.922606 0.383283 0.002686 -1.977524 0.238863 -0.377154 -21.057879 -69.763994 26.546107 60.414878 42.859121 1.873577 1.954560 1.795370 1.540944 0.401297 0.593458 1.500389 0.537806 2.163437 2.378429 2.254266 1.191567 0.924794 1.514184 0.634140
+1 0.000585 1 1 -1.341533 1.633931 -2.319768 1.961387 1.867913 0.078275 0.803245 -0.862531 -1.253857 0.233497 -1.040855 -1.259709 26.533323 -4.435393 4.345236 -19.626980 -20.649221 2.103198 2.448759 0.798665 1.162049 2.057449 0.795077 1.602715 1.325614 1.597595 0.786036 0.412523 0.274022 1.234041 1.527553 0.330663
+1 -0.079688 1 1 0.965062 -0.250764 -1.719706 -2.022129 -0.168308 -1.317764 0.570642 1.075377 1.856894 -1.342024 -1.908067 -1.073058 -18.322785 -1.041391 47.350601 71.556500 -49.901851 0.618801 2.190325 2.033569 2.197857 0.384603 1.272370 2.220475 0.280804 0.481003 1.459812 0.319242 0.745505 0.948606 1.222889 0.852904
+1 0.016565 1 1 1.439266 1.044185 0.685288 0.559782 2.327358 -1.638958 -2.048152 0.714536 2.033485 -2.166951 2.116694 1.446199 -7.469710 6.582056 74.622638 32.671967 -32.255897 1.002146 1.063217 1.486670 1.703604 0.467367 1.780095 1.302712 1.428068 2.285802 2.470363 1.644174 0.633139 2.424140 1.024453 2.475679
+1 0.023877 1 1 -1.813823 -0.476130 -0.674403 -1.401794 1.988699 -0.912299 1.097818 2.025163 -0.676296 -0.227721 -0.849200 1.313794 -42.079506 19.746053 71.919147 45.106652 7.507083 1.698194 1.804019 0.647447 2.149170 1.092382 1.168208 2.080169 2.403944 1.337256 1.505522 1.305689 1.970211 1.592199 2.330408 0.674311
+1 0.014625 1 1 -1.571295 -0.525143 0.228571 0.998218 0.936914 -2.082237 -1.962891 1.119772 -1.273735 0.718590 -0.503829 0.306728 -5.470750 3.099168 37.723821 -25.743387 -69.101193 2.368695 0.663248 2.201665 1.375485 0.524361 1.178333 1.245490 0.450874 1.341513 1.049838 1.629884 1.209159 1.838769 1.946246 1.564415
+1 -0.038392 1 1 -2.218321 1.105600 0.860253 0.660308 0.128719 0.389021 2.200663 -0.996114 1.435147 -2.196194 0.713838 -0.260568 -49.342215 55.388928 21.716184 33.907304 30.051450 1.745736 2.076455 0.723848 1.455972 1.022451 0.331538 0.405812 2.224671 1.042968 0.904390 0.585461 2.098439 1.218922 1.672778 2.132962
+1 0.002398 1 1 -0.358728 -1.997273 -1.824445 0.064301 1.575362 -1.799959 1.625113 0.261762 -1.942410 1.346983 0.434452 2.351199 -47.744234 62.660168 -20.556215 -38.302518 49.587557 1.646095 1.425095 1.822988 2.213872 1.788576 2.095402 1.927854 0.692138 1.770915 2.264862 1.532126 0.693861 1.463769 1.572834 0.875143
+1 -0.006059 1 1 0.626831 -1.746561 -0.984145 -0.047290 1.597091 0.540060 0.732178 1.673025 -0.290229 -0.561322 0.065733 2.082370 -16.714455 30.148992 14.113877 61.937561 -15.404115 1.420709 2.361421 2.155767 1.718424 2.059575 0.523317 1.640514 2.115823 0.880666 2.345603 1.793101 1.645471 2.181096 2.182450 2.434198
+1 -0.020843 1 1 0.395195 2.286274 0.592219 0.854092 0.792848 -1.242764 -1.831529 -1.186432 -2.252374 -1.029642 -1.292708 2.278485 51.932646 -18.014807 -74.867812 46.675355 -27.310905 1.159212 1.634113 0.281017 1.805538 1.430907 0.499147 0.405596 0.845758 0.647321 2.278707 2.474254 1.784522 1.466064 1.880982 0.418490
+1 0.029428 1 1 -1.100632 -2.202903 1.045178 -1.476215 -0.024234 -2.035309 -0.201946 -1.183803 -0.475693 1.954166 -1.689057 -0.549600 -26.713086 -16.839760 24.149332 -22.182014 -63.113231 2.214011 1.884104 1.128589 2.192692 1.322750 0.714515 2.097688 2.091905 1.644615 1.289765 2.077630 2.472008 2.283727 1.347866 2.079668
+1 -0.002867 1 1 1.459138 0.468365 2.113523 -0.012778 2.016510 -0.025598 -1.398418 2.180184 -1.190686 1.663481 -0.479659 1.263990 13.659938 -67.424766 41.963417 -20.856388 16.688766 1.196388 0.939954 2.063682 2.046682 2.077770 0.324438 0.333242 2.056598 2.239696 1.578768 1.609973 1.820523 1.270928 0.482288 0.566303
+1 0.018280 1 1 1.656455 -0.750468 1.955581 -1.470532 1.250319 1.570244 1.719777 -1.504318 -1.108205 -2.241313 1.095857 2.050285 68.632577 7.719808 -3.189002 -47.559586 16.037066 1.149429 1.458676 1.475409 1.450297 2.383956 0.648364 1.795518 1.773613 0.371145 2.330357 2.057263 2.161707 0.318085 1.551017 0.951453
+1 0.013055 1 1 -1.246673 -1.551332 0.416907 -0.373250 -1.022741 1.591302 2.209752 0.968923 -1.334228 1.893448 0.415685 -2.059567 65.688742 30.690222 -39.439964 -17.468270 -39.213957 1.840255 2.167052 2.399726 2.451352 1.626599 2.253484 1.562614 2.352126 1.179252 0.945635 0.789977 1.386532 1.696370 0.392001 1.854318
+1 -0.018035 1 1 0.177340 2.315709 0.505854 0.739318 -0.853294 -1.505479 -1.771889 2.163578 -2.243858 0.726108 -1.388069 1.760028 35.525444 -73.857350 -70.478627 15.722824 -46.497812 1.544113 1.915948 0.834123 0.851848 1.759763 1.581638 0.330766 0.935747 1.099293 0.318386 2.116201 0.484482 1.437178 2.396010 0.743785
+1 -0.015550 1 1 -0.149842 -1.976351 1.097131 -0.100898 0.669176 -1.630478 -0.899941 1.458055 1.107535 0.410705 -0.932154 1.986168 -33.316676 -3.376996 -57.171295 22.049751 -59.840562 1.520187 0.284743 1.429813 2.363367 1.116965 0.333508 2.014893 1.056481 0.778359 1.886948 1.693698 0.480899 1.971437 1.941699 1.641451
+1 -0.021535 1 1 -1.025795 2.087751 0.377774 1.651608 -2.108206 -0.162267 1.256503 1.824696 -0.556077 -1.325901 0.468552 0.554118 44.150198 -17.622541 67.949430 -73.928996 -74.632844 0.561880 1.772151 0.536300 1.596836 1.526139 1.320024 2.135861 2.421832 0.474775 0.294652 1.461941 2.346366 1.118329 0.749657 0.984684
+1 -0.004653 1 1 0.384605 -1.342539 -1.130531 -0.488530 -1.736115 0.228674 -1.988072 2.028119 1.877533 1.540649 -0.895974 2.156123 -9.807346 17.934451 74.321358 69.066623 -47.266230 1.322210 0.629139 0.437295 0.369443 0.727257 0.251980 2.029135 1.917755 1.966734 1.647287 1.207963 1.982400 1.699697 2.311205 1.930619
+1 0.006123 1 1 0.654091 -0.699895 -1.012134 0.779797 0.889539 -1.927429 -1.340421 1.477163 1.806485 -0.334904 -2.136843 -0.806974 -17.644395 0.650486 -17.287453 -0.228513 59.383227 0.683441 1.846916 1.618866 0.534877 2.435161 1.752390 1.419478 1.917974 1.148000 2.182083 0.766548 1.369003 1.826857 1.986801 1.415614
+1 0.007766 1 1 -0.994575 -0.971442 1.399711 0.687982 -1.290558 0.719259 1.305904 -1.979379 2.046845 0.891806 -1.525477 1.413151 12.320726 74.435393 35.643886 -33.210546 -19.642177 1.733947 1.943044 1.736036 1.057071 1.688222 0.691593 1.608938 2.428367 2.322573 1.738336 1.466649 0.461303 1.121710 1.328982 1.958829
+1 -0.009890 1 1 1.524740 0.333879 -0.952208 -0.491160 1.180710 0.320419 -0.978759 0.950257 0.687557 0.999021 0.296459 1.592117 56.031011 13.200137 4.695745 21.384470 8.784944 2.103295 1.825967 0.530580 2.209205 2.111653 0.546092 1.923501 1.786428 1.986906 0.929311 0.933943 2.283210 1.659915 1.941042 1.839166
+1 -0.011229 1 1 0.991233 1.352681 1.943199 -2.219457 0.863796 -1.045883 -0.939213 1.155360 -1.626369 2.182551 0.895728 -1.589368 64.315243 46.288551 71.669294 45.820094 -1.678530 1.209247 1.069291 2.331167 2.178819 2.170068 1.335403 1.866801 0.578769 2.114031 2.272866 1.052287 2.292381 0.556116 1.634556 0.980380
+1 -0.003775 1 1 -1.936805 1.295152 1.094702 1.493519 -1.317842 -0.741801 1.529044 1.993573 0.902983 -2.166827 -0.515133 -1.186883 -13.013562 -18.934114 74.347258 54.358716 -43.065721 0.541509 1.396537 1.104932 0.584673 2.347911 2.338253 2.014772 1.273308 2.234067 1.458322 2.269176 2.044128 1.909217 2.456076 2.270979
+1 0.005291 1 1 0.267603 1.982589 0.066472 0.360382 1.520477 -0.636180 0.138317 1.485721 -0.427695 -1.873519 -0.050969 1.021682 -16.874888 33.764819 35.308070 22.725390 45.637387 0.288338 1.099963 0.321629 0.369105 1.792067 2.262491 2.177914 0.446837 0.987161 1.214691 0.304837 1.638813 0.520876 1.104874 1.864874
+1 -0.012829 1 1 0.360163 -2.160458 -1.863679 0.398502 1.320473 -2.156657 0.762824 -1.629458 2.096429 0.143350 1.253149 2.012384 42.160798 -3.462727 1.946384 12.872086 41.150867 0.964393 1.060427 1.852002 1.601109 1.335212 0.903169 0.308352 2.229053 0.440296 1.300330 1.897128 1.783984 1.419974 1.257401 0.395845
+1 0.008569 1 1 -0.001057 1.086407 -1.264622 -1.635944 1.481509 -0.540863 -0.080991 0.672680 0.719387 -1.244416 -1.320802 1.343771 -54.610370 13.506375 51.639008 -3.198823 -62.620062 0.544357 2.005529 1.175517 1.162401 1.226385 1.107916 1.240291 0.820698 2.469864 2.263171 2.373680 1.180676 2.368968 0.739261 1.761205
+1 0.000335 1 1 1.339137 0.506286 -1.421546 -0.115326 -1.496817 -2.264884 0.768767 -0.709964 -0.596041 0.869992 -0.582464 -1.833830 -68.581236 -44.832074 -42.670840 -18.807655 -50.256991 1.086324 0.604826 1.310766 1.788810 1.536036 1.157833 0.950002 2.187552 0.431461 1.319896 2.249198 1.520482 0.738072 2.024773 0.610798
+1 -0.014576 1 1 -0.817581 0.239783 0.936156 -0.689596 -2.276421 0.085250 0.229812 -1.702602 -1.999864 1.765050 0.710779 0.160017 -43.640442 35.097315 -69.418508 -16.859228 -3.041427 1.866090 2.119990 1.176833 0.778893 1.855557 0.593176 1.260855 2.193489 1.225494 1.873625 0.523606 1.987975 0.899123 2.054903 0.750388
+1 0.018621 1 1 -2.150172 1.368818 -0.154246 -0.605536 1.514476 2.189698 -1.508405 0.893156 2.319958 1.233015 -1.802023 -0.081212 52.810893 42.680404 29.556192 -49.074111 61.419464 1.028981 2.080600 0.651645 0.701535 2.192503 0.399496 1.830432 1.319468 1.800028 1.072027 1.059694 0.770434 1.440217 1.720730 0.304029
+1 0.009041 1 1 -2.311591 -1.973033 0.322815 1.599646 1.062496 2.127443 -1.672323 -2.051837 0.039438 -1.612702 0.983469 -1.893297 67.521213 -70.966990 57.805932 -5.696529 -41.566056 0.614511 2.093744 1.061123 2.297151 1.970798 2.452808 1.334868 1.876357 1.438862 1.445226 0.416945 0.347901 0.914077 1.391297 0.776862
+1 0.030878 1 1 -0.728270 -1.955472 -1.425288 -1.750987 0.032650 2.107851 -1.086182 0.329354 -1.610728 1.173768 1.457944 -0.749086 51.504207 -18.800067 -72.721999 -38.641461 52.963163 2.153125 2.316145 1.691568 0.676269 0.559057 1.565744 0.953768 2.479079 1.881126 0.580669 0.311408 1.825977 0.700581 1.907270 1.242659
+1 -0.004893 1 1 0.625449 -1.422089 0.188769 1.205524 -2.037672 -2.229608 -0.100083 0.225148 0.018772 -0.221241 -0.328032 0.258864 38.078128 -70.905157 47.033505 -7.882824 -36.616259 1.982924 1.504644 2.308227 1.369879 0.815427 1.627321 0.885838 1.527762 1.599835 2.433271 1.489824 0.716811 2.444858 0.482664 2.377892
+1 0.010692 1 1 -1.584435 0.107104 -0.039129 2.091741 1.477032 -0.385790 0.281463 -0.683363 -1.189346 0.623187 -1.732355 2.161447 -11.703526 -51.160134 -48.371995 11.887550 -5.940520 2.240144 2.355525 2.052742 0.431971 0.879176 2.057934 2.197580 2.484912 0.916092 1.503829 2.100191 1.401844 0.298200 0.342242 0.313741
+1 -0.004439 1 1 -1.282608 -2.320977 0.495322 -1.908463 1.689444 2.342927 0.852189 1.790188 -0.919031 1.050981 1.806281 0.958110 22.808683 -54.463075 -60.894068 3.403071 45.412363 2.058840 1.673189 2.287757 1.583319 1.592738 2.403458 2.162687 1.035415 2.224907 0.514594 1.274010 0.540401 0.769599 0.893782 2.288926
+1 -0.041827 1 1 0.120052 0.819098 1.694183 1.887010 0.603146 0.725098 0.491037 1.472987 2.321657 1.501434 -0.245114 -1.004194 72.933063 -14.008149 65.047014 45.162919 53.182151 1.111142 1.454983 2.400581 1.062483 0.409979 0.273638 1.533902 1.284650 1.615251 0.525678 0.812610 1.544285 0.299229 1.894502 0.386177
+1 -0.007027 1 1 -1.023444 -0.807640 -2.326282 0.867827 0.724645 2.297882 -2.239574 2.051514 -0.751086 0.995546 -1.544856 0.874234 0.752941 54.680877 -28.505239 12.439763 -24.900442 1.349084 2.305428 1.584424 2.157252 1.936325 1.311483 0.340231 0.268917 0.940906 2.303007 1.385738 1.851350 1.889846 0.895454 1.152241
+1 -0.030475 1 1 0.436837 0.025249 0.241913 -0.953855 0.104356 0.908809 1.501038 -2.179511 -1.639389 0.133071 -1.866640 -2.243952 -27.052722 -25.098053 -22.970791 29.909841 44.704286 1.298933 0.912127 2.371600 2.232582 1.248082 1.259878 1.525923 2.184630 0.826927 1.404942 0.601258 2.099462 0.410877 1.851627 2.053871
+1 0.019376 1 1 -1.198409 -0.915727 0.036129 -0.684630 1.078529 -1.727783 -1.107007 -0.954711 -0.136457 1.497057 1.598809 1.141403 -18.394046 1.261147 46.095015 -31.078166 -30.730572 0.794253 1.252272 1.928870 2.024827 1.517819 0.990966 2.167589 2.421057 0.955140 0.791808 0.672150 1.082903 1.602859 1.505649 1.192934
+1 -0.023265 1 1 1.481941 1.998676 1.836105 -2.012870 -0.062444 1.369355 -0.549069 -1.342616 2.281142 -0.840603 -0.268221 1.770319 -8.521648 26.669503 34.335034 18.915192 57.634097 0.719101 0.437535 2.146644 1.396710 1.760313 1.824881 0.272768 0.412064 1.563125 1.937309 2.095183 0.487449 1.804091 1.854215 0.539568
+1 0.024644 1 1 -2.099743 0.704026 -0.237668 1.619351 -2.321399 -1.890202 2.309044 1.584438 -0.065760 2.177896 -1.933565 -0.785263 47.091035 59.027923 -17.695665 38.960186 53.853975 1.731295 2.381100 2.148497 1.044746 1.550086 1.040296 1.000420 1.316390 1.811225 0.267383 2.160863 1.874823 0.404540 1.098757 0.308537
+1 -0.018628 1 1 -1.342131 1.008591 0.930156 2.142772 1.499171 -0.570759 1.669416 0.306105 -1.221228 1.980929 0.450476 -1.651404 26.500134 37.752660 8.955792 70.002085 -74.961854 0.866913 0.713697 1.852425 1.964380 0.340673 0.935333 0.898168 1.762820 1.215101 0.458099 1.275035 2.017627 2.006375 1.888976 2.025026
+1 -0.008344 1 1 0.732999 1.328760 0.462333 -0.295444 1.336134 1.871649 1.601596 0.856657 1.485489 0.373475 0.094221 0.210951 55.547587 -11.704022 -59.491695 23.075638 -67.758192 1.195923 2.129706 2.460498 2.332549 0.650455 0.954343 0.898098 0.590532 1.814429 2.353704 0.697725 1.161437 0.766732 2.217047 1.165680
+1 -0.034474 1 1 0.464042 0.153286 -1.403495 1.676355 -0.874092 -2.342584 0.204037 -1.373052 -0.307815 0.760623 -0.914989 -1.692055 28.568018 -7.322704 -72.691475 24.382914 3.629288 0.586733 0.968172 1.571384 1.259517 2.207202 2.185833 0.786891 1.284308 0.363216 1.821939 0.336333 2.242590 0.704681 1.081494 0.424983
+1 -0.003832 1 1 1.922194 -1.826024 1.805338 -0.752555 -0.141940 -1.116131 1.208264 1.613849 -0.548963 0.429806 -0.343552 -1.403384 -37.331735 15.535346 -47.435164 7.194408 16.419523 0.818739 1.049696 1.490491 0.689555 1.095002 2.446308 2.343641 0.321636 0.491243 0.320788 1.989149 0.371873 1.062344 0.314223 1.892971
+1 0.023520 1 1 0.015136 -0.081751 2.034674 -1.045095 -1.845506 -0.468788 0.196930 1.712382 1.439314 1.861318 2.340440 1.462292 51.930533 -53.532828 -26.234853 70.821903 53.727893 1.445485 0.261202 1.777574 1.688518 1.177200 2.448621 0.731048 0.975499 0.970091 2.325498 1.390275 1.605986 2.310679 2.086579 2.127335
+1 0.016091 1 1 1.588590 -0.961137 0.232901 -1.635289 -1.644608 1.944520 1.135647 1.650203 -2.164123 -2.197296 1.032957 0.463846 49.945234 29.546386 -63.898621 55.870501 15.505829 2.221963 0.532620 0.501915 1.942391 2.007992 2.067411 1.730581 1.630869 2.021404 2.487185 0.862931 1.289417 0.737830 2.453513 1.949366
+1 0.000846 1 1 -1.913876 0.255522 1.579047 -1.124972 -1.300661 0.566390 0.295956 -2.147489 -0.666184 0.076875 0.850926 -0.590154 27.275323 16.348307 -34.010227 40.106501 -30.030734 1.726681 1.333622 1.184672 2.032646 2.430374 2.294371 2.499158 1.848208 0.839377 1.411004 1.252441 0.275542 2.034317 1.269352 1.000813
+1 -0.003197 1 1 -2.241528 2.196758 -0.658529 1.496585 -1.627673 -0.883333 -2.155761 1.682135 2.026688 1.391290 0.528622 1.694250 -54.146569 8.619463 -32.682333 8.020960 -41.728475 2.417799 2.440914 1.687477 1.685130 0.473095 1.301750 1.018936 2.004240 2.017009 0.611516 1.253369 2.375771 0.340698 1.368734 1.816262
+1 -0.004216 1 1 -1.232792 0.846876 2.023504 -0.282150 -1.424773 2.192534 -0.969490 1.229056 2.341196 0.036495 0.755231 -2.010012 26.935457 4.228875 -25.298131 64.312652 2.744197 2.450854 2.258927 0.785762 0.303915 1.892478 2.378632 1.166144 1.129926 2.170386 2.183920 2.396605 1.739141 1.488237 1.054611 0.853346
+1 -0.026588 1 1 2.230925 -1.322592 -0.458966 0.332139 -1.916570 2.107965 0.819896 0.970082 -0.695291 0.966979 -1.009632 0.422734 -44.517514 -5.855488 -13.195032 -68.904259 -73.881513 0.976242 2.205935 1.142154 0.685770 0.481189 2.336296 0.633502 1.776319 0.847294 1.728466 2.082878 0.680404 0.293152 1.001050 0.642096
+1 0.062483 1 1 -1.399133 -0.409359 -0.011955 1.711744 0.147204 0.061108 -0.251981 1.396392 1.458904 1.243091 -2.104191 1.337629 -40.607768 5.239672 13.169960 -52.483506 59.715419 1.180689 0.344033 1.154319 0.392357 1.090135 1.643271 1.200779 0.499112 2.082236 1.137398 1.751417 0.820042 0.446441 1.084532 1.977480
+1 0.046857 1 1 -1.339664 0.063831 -1.615493 1.196371 -0.354555 2.168300 1.714063 1.427106 -0.686404 -0.471722 -1.999929 0.670905 -27.109322 73.629460 -9.660008 -55.747531 -48.745627 1.858696 1.600379 0.321528 0.918167 0.375534 1.846495 1.295480 1.378869 1.156620 0.808309 1.250745 1.013922 0.991356 1.968489 1.897213
+1 0.041168 1 1 1.367719 0.226684 2.274008 1.780426 -0.047097 0.127381 1.468151 1.140947 1.180812 2.036819 2.023610 1.497317 39.659069 -50.030899 30.672463 -37.912251 8.789761 1.067722 0.708976 1.252932 1.773488 0.519841 1.716734 0.645405 1.573125 1.259320 1.144340 1.430685 1.270934 0.591378 0.288647 1.797902
+1 0.028170 1 1 0.740968 -1.399094 0.241109 -0.332541 -0.121057 1.148006 2.020361 -1.273772 0.104708 2.104555 0.068338 -1.262532 16.499160 -48.624644 -34.388920 -24.583034 -67.054914 0.745928 1.319485 2.083080 1.833442 2.409579 1.540431 0.766508 0.708142 0.743142 1.734494 2.133811 1.717168 1.199703 0.402919 0.856189
+1 -0.000821 1 1 1.221076 0.176093 0.215257 -1.298358 1.562825 -0.448916 -0.399839 -0.221502 0.000509 -0.868281 1.070803 0.374012 -9.617745 54.564743 -30.362210 2.342688 73.550994 1.698306 1.427388 2.104529 2.311623 2.204523 2.163951 2.019504 2.047310 1.388790 1.388825 1.989092 1.674367 1.841369 0.639187 0.570762
+1 0.008056 1 1 0.564542 2.226715 -1.400206 0.402525 -1.755007 -1.565128 -0.549621 -1.200428 -1.853675 -1.119334 -0.788251 -1.616717 -17.006563 70.694557 13.417038 50.162979 -60.816739 0.670984 1.728805 1.024055 0.296301 2.182444 2.339319 1.938605 1.392646 0.958878 0.610701 1.054789 1.588269 1.533602 0.747677 1.460180
+1 0.031437 1 1 -2.300188 1.172032 0.555433 -0.087362 1.964688 0.795452 0.122510 -0.280414 -0.533658 -1.509513 1.124683 1.148828 54.139507 22.687777 13.471801 70.563961 68.490257 1.611240 0.604885 2.309197 1.926173 1.684903 1.166450 1.781589 1.663089 1.292525 1.208705 0.959756 1.863622 1.152728 0.649753 0.395156
+1 0.009977 1 1 -1.049621 2.198295 1.621121 -0.846496 -0.353727 1.936964 1.376685 0.107249 -2.306093 0.888106 2.261614 0.818920 -41.374164 24.419182 13.190363 -9.575833 8.980239 1.838121 2.299135 1.557022 0.622959 2.314625 0.897032 0.667438 0.625411 0.783595 2.137783 0.972328 1.664234 0.288378 1.776795 2.091085
+1 0.037953 1 1 1.374927 -1.160199 0.398857 -2.133029 2.031078 -0.222534 1.513278 0.895277 0.261069 0.558908 1.775417 0.585523 44.942737 -47.424594 34.854947 57.094819 42.631104 0.639554 2.232707 1.113596 2.213240 2.428144 0.817190 2.007802 1.136761 2.293289 2.305620 0.305153 2.449558 0.716429 0.525060 1.678881
+1 -0.006576 1 1 2.130205 2.335689 1.722334 -0.933716 -0.710311 -1.719907 -0.679547 1.680350 0.292511 1.218342 1.346423 0.439149 37.294513 -41.112694 68.953305 -1.808102 61.235572 1.918948 1.765080 0.955560 1.092215 0.600328 2.215317 1.335490 1.086582 0.428075 0.660131 1.579666 0.940322 1.499135 1.964474 1.910087
+1 0.017728 1 1 -2.217574 -0.475761 0.802154 -0.342965 -0.963555 2.009325 1.745031 -1.169373 1.727033 -2.068979 -0.610909 0.749131 -27.061281 -18.956894 -8.515987 -28.199022 59.034361 0.482617 1.594752 0.253540 1.242279 0.482713 0.951956 1.274868 1.462232 0.477179 2.449913 2.185975 0.927006 0.438273 1.061575 0.882353
+1 -0.046241 1 1 -1.732592 -1.830320 0.287525 2.226557 0.655689 -2.120216 0.621204 -2.085151 0.904888 1.574076 0.141261 -0.868123 -31.213224 -50.651971 -57.677491 64.415004 72.979769 1.689709 0.939500 1.176726 1.236087 2.165582 2.443008 0.878510 2.120497 0.697284 0.495778 2.285751 1.612049 0.710717 1.275257 1.243497
+1 -0.009149 1 1 -1.656718 1.037997 0.357222 0.246531 1.261960 -0.697713 -2.032199 0.222927 0.391282 -2.211344 0.555476 0.641662 -71.343316 32.880614 24.473289 22.571426 7.948569 0.498850 2.179428 1.140647 2.354659 1.007840 2.259787 1.740452 1.022899 1.107554 1.918259 1.431416 2.308778 1.633532 1.775096 0.533417
+1 -0.021299 1 1 1.789907 -0.924299 2.051383 1.757301 -2.294735 -1.422590 1.195224 -0.777960 1.713256 1.996640 0.600602 0.380687 -38.846944 49.405938 -34.397645 -21.212410 33.022887 1.610035 0.602236 0.522734 0.842788 2.484606 0.278481 1.937224 0.680942 0.346056 1.411159 1.608076 1.434233 2.403137 1.272436 1.080356
+1 0.046975 1 1 -1.707928 -1.989308 0.101153 -1.087080 -0.616733 1.818513 -0.804628 1.166940 -0.195941 0.787018 -0.264442 -0.687068 -70.094633 19.507356 -39.870300 -50.134636 -62.825035 0.619599 2.107490 0.333939 0.265482 1.708204 1.283705 1.472654 2.395029 2.254108 0.800520 0.840496 2.220182 2.103872 0.280117 2.430232
+1 -0.019051 1 1 1.290742 -2.344938 -1.665738 0.244446 -0.802109 1.092901 -0.500188 0.246126 -0.841277 -2.181110 -0.237472 0.208651 24.718755 -51.878154 33.863191 38.643446 -19.607568 1.459018 0.465399 2.467379 0.983643 0.587506 0.461287 0.858433 2.180674 1.834692 0.919518 0.587697 1.415376 0.468516 0.854962 2.343426
+1 0.004261 1 1 -1.410197 2.140060 -1.669764 -1.441072 1.590224 -1.778382 1.422858 -1.398408 -2.350456 -0.162348 -0.112959 0.594059 -38.224056 18.290472 57.955540 -41.237874 65.046807 2.000162 0.967423 2.478688 2.057439 0.632243 0.860379 1.140182 1.287613 1.914087 1.052432 2.475498 2.444458 0.506357 2.343944 0.912142
+1 0.024588 1 1 2.120668 2.267486 0.553911 -2.103278 -2.163647 1.093838 1.105551 0.044300 -0.008968 0.071471 -0.438091 -2.240106 -69.663032 73.418792 49.643581 59.669772 -30.138593 1.534951 0.928249 1.076779 2.168520 2.309041 1.549811 0.931265 2.265836 2.158293 1.432709 1.547215 2.296963 1.056366 1.094696 1.812747
+1 -0.012434 1 1 -0.505062 -1.559641 2.125306 0.105533 1.836376 -2.183450 -1.874196 -2.003689 -1.272674 -0.307055 -0.612840 1.281846 -33.714796 55.418908 -74.409249 -46.254689 47.443148 1.029725 1.083613 2.279324 1.606205 1.481432 1.433240 1.469071 0.672579 1.539029 1.955523 2.228257 0.572577 1.555706 0.993929 2.461917
+1 0.037295 1 1 -1.601792 0.560977 -1.147628 -0.380347 2.217039 0.914583 -0.420476 1.636317 0.080723 -0.463006 -1.593436 -0.369936 -59.553504 34.254254 11.239307 49.027966 63.028039 1.558892 0.545172 2.201961 1.855897 1.805837 1.947981 1.469391 1.558375 0.866202 2.252946 1.517704 1.307867 0.314109 2.228784 0.425193
+1 0.015411 1 1 -1.375290 -0.221980 1.394251 -1.540244 -1.721475 1.231068 -1.539388 -1.474097 -2.119930 0.708421 -1.780385 0.741933 21.734629 43.907833 -41.044646 12.626514 -36.173400 1.130079 2.485432 0.654757 1.257322 1.317978 1.503696 2.114175 2.444043 0.279734 0.488264 1.998903 2.306272 2.272702 0.547043 2.157332
+1 -0.029742 1 1 1.007281 -2.243457 -1.954297 -0.522026 0.768845 0.602295 0.563394 1.779337 0.503007 0.009065 1.553206 -1.905647 60.152794 -11.995244 -4.067420 38.867838 1.745250 0.361221 2.036906 2.027518 1.748636 1.324031 1.983170 1.134068 2.025616 1.278227 1.655208 1.588413 1.711841 1.655093 1.900964 1.006235
+1 0.015568 1 1 1.036501 -1.227482 0.546989 -0.619478 -1.894894 -1.167729 1.081285 2.187400 2.287285 -1.261514 -1.224495 -1.089152 71.485726 -39.396888 -43.489982 13.878226 1.346657 1.123856 1.399179 0.494321 0.309943 1.962993 1.772943 0.347211 0.574425 1.118107 1.530109 0.532797 1.224617 0.637768 1.460929 1.084995
+1 -0.035309 1 1 1.390781 1.402564 1.523751 -2.143798 0.114872 -1.422558 1.725313 2.014739 -1.513336 -1.875313 -1.927579 0.853740 -13.006617 -52.207730 44.688519 29.936593 44.326852 0.645945 1.648305 0.308860 1.751969 1.091584 1.246200 1.140793 0.305526 1.973886 0.344459 1.572514 2.247130 0.521549 1.175050 2.311827
+1 0.006434 1 1 1.467026 1.082368 1.535358 -0.282564 1.042091 -1.518818 0.234620 -1.010453 0.766113 1.821861 -1.083781 -1.720764 -30.158852 -29.829420 -43.063705 -21.688043 -10.940635 1.686304 2.217064 1.441020 1.717701 1.145225 0.548806 0.289346 2.285402 0.250819 0.508875 1.904623 1.740499 1.811673 1.044879 1.533953
+1 0.012738 1 1 2.233838 0.517777 -1.511016 -0.586228 0.872909 1.320713 1.868229 0.677509 1.763564 -0.701802 -0.072698 -1.320181 -74.985315 21.802989 -7.158463 -12.285644 65.180180 1.874175 0.762235 0.888451 0.446102 2.144482 1.053024 1.169698 2.371148 1.389949 0.618866 1.029532 2.344852 0.423955 1.161438 0.787951
+1 -0.030545 1 1 -0.969567 -0.064394 1.578883 0.817551 -0.746969 -0.501026 0.291914 0.595916 1.728789 -0.827015 1.902585 -1.523054 -8.809254 -7.130552 6.821060 41.548140 49.586724 1.436034 1.167977 0.437239 1.679668 0.932732 2.176102 1.488594 0.293422 1.035558 2.373861 1.990491 0.428580 2.396138 0.648745 1.451493
+1 0.049725 1 1 0.891073 0.290299 1.726574 -0.365364 -0.432304 0.765046 -1.979803 -0.370396 -0.180333 -0.784973 1.647579 0.865373 60.169640 -28.853640 6.878244 -47.346323 0.352963 0.358796 1.790112 0.908832 0.996242 0.835641 1.624971 1.881206 1.929122 1.746153 2.350570 2.033710 2.321207 1.284626 1.214128 2.102306
+1 0.011261 1 1 2.190198 2.184842 1.703259 -1.092766 -1.935986 0.928242 -1.753952 2.034281 1.784825 -1.513691 1.577858 -2.269251 -61.526877 17.779306 16.790346 45.346494 -11.475254 1.906036 0.743038 2.244692 2.283507 2.154044 2.025376 1.746042 0.479068 0.448392 2.370623 1.560542 1.283372 0.384738 1.288708 2.321437
+1 0.014696 1 1 -1.750209 -1.033522 -0.535641 -1.850322 -1.311005 1.072405 -0.974206 2.068091 -0.168661 2.176418 1.501412 -0.612743 -57.265315 -58.144683 12.314599 -28.526365 -42.612479 2.306080 1.283272 0.945193 2.358311 1.627889 1.439587 2.382855 2.400607 1.497099 1.499315 0.487291 1.407690 1.798070 1.911526 0.769066
+1 0.022157 1 1 0.049779 -2.164707 2.123467 2.185696 1.921944 -1.316619 0.967124 1.423990 -1.214876 0.358174 2.113829 0.428644 -32.773902 -30.974683 58.497251 63.290968 -68.708320 2.413962 0.950825 0.264786 1.252894 1.145082 0.390449 0.520796 2.021037 0.826948 1.759893 1.517448 1.506541 0.434972 1.827338 1.064588
+1 0.006041 1 1 -1.498938 -0.212302 -0.880154 -0.557596 1.427185 0.630871 0.165294 -2.210606 -1.182186 -1.570687 0.264465 1.075166 -54.083673 15.713463 -53.828965 -53.419471 -71.047306 2.244017 2.202695 0.697238 1.974542 2.374609 1.057883 1.836105 2.160189 1.793659 2.028532 0.795683 0.547848 2.182637 1.076830 0.780813
+1 -0.026972 1 1 -1.010400 1.659553 -0.520584 1.455868 2.046536 0.401813 0.411985 1.737629 1.664318 -0.553735 0.347594 -1.356802 -16.356686 43.173147 61.088305 -38.863230 -74.299413 1.371518 1.350081 1.058188 2.474331 0.835394 1.966827 0.953019 1.138143 0.775050 0.266909 0.932234 0.551896 0.469703 0.543179 2.467713
+1 0.005233 1 1 -1.673055 -0.201172 -2.310828 1.417194 -2.338525 -2.258373 1.822790 0.393207 1.854774 0.741649 0.619864 -1.037149 -7.612318 9.764297 8.541581 8.355060 23.492679 1.996792 0.585410 1.236603 1.843461 2.042501 1.559760 1.636774 2.260126 0.691578 1.356209 0.560113 1.315509 0.508276 0.847018 1.581258
+1 0.006513 1 1 -1.898146 0.731196 -0.705147 0.253552 1.443849 -2.037762 0.977561 -2.228893 -2.225363 0.547341 0.583350 -2.124732 3.451670 -37.775304 60.463132 -46.140800 11.573887 0.959871 1.558415 1.523664 2.466377 2.148401 1.670849 1.208655 2.364191 1.455223 1.925915 1.860175 1.706443 0.931328 1.073928 1.508215
+1 -0.005581 1 1 0.251951 -1.903541 -0.403917 1.919933 -2.127365 -1.725372 1.710349 0.257067 -0.737590 1.625837 -1.697001 -2.123908 -5.448680 74.040896 5.345770 -3.650502 -3.988497 1.605065 0.320931 2.133384 1.280484 1.336904 2.353931 2.263473 0.692930 1.580470 0.953529 0.715472 2.442810 2.058781 0.690941 1.887656
+1 -0.031988 1 1 0.344498 -1.545084 1.751231 -0.639568 -0.260770 -0.244357 2.294200 1.849019 -1.740459 -2.091557 1.614693 -0.496464 50.164684 -32.164010 19.484884 32.451816 17.669161 0.858719 2.490381 0.579702 2.053681 0.464245 1.070278 0.914913 1.944423 2.423475 1.086981 0.383462 2.343572 1.418155 2.175875 2.185982
+1 -0.003471 1 1 -1.264210 0.575797 -1.822067 2.333718 1.576440 2.178069 0.976301 0.156963 -0.856448 2.027638 -1.487732 -0.374274 19.830181 -14.152547 38.141952 -48.213986 -32.455136 0.272850 1.793692 0.336555 1.472862 1.396222 0.301705 0.764049 2.125538 2.172360 1.607029 1.839060 2.331674 1.687525 2.481617 1.790909
+1 -0.034451 1 1 -1.668794 0.717512 0.217107 1.522181 -0.257155 -0.746608 0.847186 -2.190631 -0.030874 -0.544802 -0.321109 -1.188129 70.730362 15.199484 7.730657 29.155619 -31.518085 0.258063 0.770847 1.618766 1.105546 1.911577 1.623788 2.255396 2.187158 0.559032 1.154126 1.638223 1.861665 2.000750 1.853777 2.176702
+1 0.007611 1 1 -1.751633 -1.395550 -1.456857 0.168408 -1.710975 -1.364367 -0.422412 2.088189 -1.687311 0.521753 -0.652737 -0.116200 -64.925182 52.458288 -33.555577 31.422042 -39.734435 1.125365 2.014909 1.325076 1.556595 2.444902 1.222238 1.152912 1.486492 0.977644 1.019385 0.556442 0.372011 1.134768 0.297859 1.360898
+1 -0.000451 1 1 1.045409 -2.315778 -1.666053 -0.342249 1.643912 0.488310 -1.959167 -2.248795 -2.136481 0.563846 -0.055500 0.270444 -66.778496 -46.177527 -5.700074 48.859230 -72.919473 0.511352 0.795073 1.534408 0.796684 1.613245 0.552347 1.303267 1.752983 2.390392 0.816020 0.351457 2.194568 1.351711 1.461512 1.885345
+1 -0.004030 1 1 0.332473 -1.014395 0.483029 -1.177099 -0.901522 -1.541695 2.153232 -1.777048 0.282175 1.845179 -0.311126 1.653105 -16.193994 -72.461700 -13.796918 15.197288 -29.183196 1.645361 0.331289 0.719880 2.271567 1.725293 0.495993 1.411723 2.082371 1.167701 0.298677 1.620125 1.436854 1.445975 1.754447 2.241772
+1 0.010124 1 1 2.260168 0.076760 -1.089968 -2.039868 -1.431861 0.881905 1.718274 1.513794 0.140534 1.044798 1.550170 -1.097666 16.793566 -50.541206 3.945746 16.160573 -39.253648 0.834035 1.619160 0.971759 1.103460 0.595236 2.131346 0.774101 2.321695 0.473036 0.308813 0.971101 1.290309 2.230784 0.282530 2.487180
+1 -0.008467 1 1 -1.176708 0.963576 -1.658145 0.624446 0.575037 -0.470917 2.114381 0.278083 -0.943114 1.556231 1.822543 0.954393 -15.783699 73.369864 -22.703951 14.695307 -65.982648 1.069513 1.557267 2.477835 1.213741 2.349286 0.701081 1.312063 1.094110 0.959675 0.514272 0.374021 1.169449 0.431924 2.342321 0.630252
+1 0.070510 1 1 -0.469985 -1.070162 0.981938 0.650526 0.655854 0.658686 1.136084 -0.436678 -2.063257 1.318686 0.785781 -2.198230 -16.410235 43.186076 -21.628988 -68.404790 70.700156 0.737731 0.803114 1.688100 0.898964 1.634113 0.289611 2.234030 0.835550 2.346991 0.384022 0.512944 0.552310 0.672166 1.341708 2.077322
+1 0.038946 1 1 -1.620427 -1.627456 -1.954766 1.018132 1.063011 1.359054 0.671292 0.947048 -1.422515 -2.254400 -2.086457 -2.195074 21.835053 -68.265981 3.654742 -74.754759 -3.237934 1.825724 0.944458 1.257513 2.278652 1.552828 2.130342 1.906863 1.145675 1.366945 0.988169 2.409991 1.721639 2.091288 0.282598 1.369601
+1 -0.037605 1 1 -2.149009 2.072260 -0.799897 0.578437 0.128286 -2.168367 1.865566 -1.670383 2.279824 0.565254 0.054042 -1.200808 37.857960 -21.266544 23.188678 32.106642 66.324424 2.343788 0.542930 0.520916 1.785351 1.898055 1.618594 0.459815 0.857462 1.610293 0.447197 0.290809 2.121708 0.799021 0.399292 0.649219
+1 0.003628 1 1 -1.842332 1.026332 2.220042 -0.443403 -1.994287 1.234837 0.538585 -0.493306 -1.899834 0.636154 -0.569639 1.650692 42.977488 72.642036 44.696158 8.326225 -11.143107 2.392084 2.259580 0.508929 0.562648 1.169101 1.335661 1.706498 1.854796 1.309471 0.280404 0.503939 2.199583 2.392911 0.413749 0.629704
+1 0.000273 1 1 1.816982 1.737130 -2.023729 1.213030 1.594270 0.255550 2.034600 -2.280642 -0.184109 1.727662 -0.924946 0.603931 -6.940382 52.994435 -22.533456 30.212407 29.924496 1.240037 1.053746 2.054693 1.730300 1.404454 1.417304 1.382663 1.920412 1.609839 1.814574 0.286380 1.937067 0.280439 1.081225 0.407028
+1 0.049680 1 1 0.906310 1.908628 1.082967 2.174418 0.859728 1.262107 1.761469 1.776239 0.257227 1.956486 -0.389424 0.459273 3.619428 -68.274907 3.637331 -67.385445 -47.174833 1.863843 0.360056 0.455383 0.619464 2.082840 2.289847 0.701343 1.227849 0.963399 2.338959 0.383056 2.271946 1.352600 0.648240 1.964007
+1 0.023615 1 1 0.035748 2.350791 1.073669 1.416167 -0.752658 -1.871322 -0.825960 0.788093 -1.040809 -0.494910 -0.584329 -0.197934 8.513090 -20.496647 62.847812 -16.822501 14.229012 2.080193 0.546861 1.343256 1.104019 0.991575 1.149790 0.773929 1.670082 1.818273 1.707919 0.987328 1.769381 1.245631 0.573397 1.831415
+1 -0.059624 1 1 -1.095889 2.115049 2.084940 0.258194 -0.641577 -1.033750 0.336820 1.354630 1.708077 -0.227203 -1.570124 0.307529 -27.014600 15.618624 2.208452 67.458789 -70.135616 0.335406 2.417101 1.972133 2.389437 0.517263 1.147322 2.043072 2.161864 0.698091 0.568381 0.775247 1.318077 0.919926 0.693502 2.189336
+1 -0.026229 1 1 -0.227124 -0.239498 -0.861811 1.434084 -1.214695 -1.301177 1.311028 -0.682648 1.404660 -0.951043 0.237434 -0.837323 -53.689259 44.629834 -56.385506 28.807215 -37.135954 1.465294 2.446682 1.887920 2.272373 1.765565 2.352886 0.462165 2.107885 2.474488 1.224117 1.234401 0.832240 0.699322 1.011281 1.608253
+1 0.061982 1 1 -0.487765 1.684871 0.877859 -0.309793 0.499181 1.688376 -1.473231 -1.706477 -1.159777 -1.932286 1.856638 -0.927993 39.075137 35.820619 -62.861577 -64.524192 41.907254 0.403354 1.422619 0.712826 0.721202 1.996163 1.253048 1.468668 0.651897 0.435821 0.351831 1.724654 1.008669 0.445583 2.405429 1.538410
+1 0.084430 1 1 1.411390 -0.942194 -1.824112 0.951908 0.151051 -1.271596 -1.032527 2.039881 1.652446 -2.165980 -0.420331 -0.635220 67.653714 55.977077 6.734005 -71.579462 -36.023069 0.779092 0.699146 0.298564 1.972209 1.411500 0.577428 2.086168 1.971589 2.251180 1.088921 1.488600 0.391435 1.349048 1.697114 1.645418
+1 0.037231 1 1 0.892784 0.771225 -1.802432 -2.240877 -1.015661 -1.935632 2.164447 -1.787291 -2.236899 -0.113899 -1.074230 -1.414126 65.803276 5.660092 29.162835 -60.223841 17.908868 0.540209 2.046897 1.203953 2.096281 0.941570 2.213572 1.251039 1.469611 0.744959 0.780924 2.245348 2.057072 1.200364 0.272472 2.180596
+1 0.005057 1 1 0.724910 2.039894 1.864806 -0.306546 -1.478521 -1.071307 0.588001 0.660561 -0.340265 2.006739 0.700030 -1.428576 -14.312598 48.158183 -5.416650 12.365184 71.642736 2.117023 0.797435 0.735032 0.430384 1.213208 2.380977 2.332923 2.434011 0.415425 1.804228 1.907286 1.513138 1.060891 0.646984 1.106953
+1 -0.013757 1 1 -0.156729 0.076300 0.606455 -0.211308 1.679915 -2.306000 -2.248768 -1.683731 -0.577084 -0.946446 2.103655 -0.916953 -54.731823 72.256224 10.348871 -66.517765 -14.077940 0.505955 2.334021 0.640509 0.279510 1.216169 0.402307 1.820121 1.271993 0.389710 1.600900 2.324668 0.950799 2.085364 1.971766 0.714461
+1 0.022110 1 1 2.171388 1.770939 0.721160 0.264455 0.905108 0.559366 0.040601 -0.917116 0.255122 -0.445117 2.184214 0.577998 69.456752 59.627978 17.428722 -25.474888 -56.441331 1.233185 0.642561 1.021452 1.538611 1.681091 2.341114 0.605326 0.718200 1.034265 0.897575 0.789476 1.974573 0.639189 0.601684 0.258236
+1 0.002164 1 1 2.011618 -2.119221 -1.506370 2.112801 1.993967 -1.898650 1.692951 0.026652 0.264490 1.504533 0.011177 -0.650699 36.896413 18.007222 -52.620221 11.947798 -43.365257 1.526940 1.287605 1.769778 1.160041 2.057863 1.009338 0.444458 1.510247 1.968224 1.947987 1.563900 1.475821 1.617171 1.297277 2.331672
+1 0.036996 1 1 0.495840 2.083187 -0.929923 1.770180 2.104433 -1.983973 0.229897 -0.279774 0.810270 -0.601865 1.952209 -1.596516 -9.673039 25.234656 68.868302 69.546888 74.543448 2.151047 1.139481 0.754030 2.483160 0.722498 1.276633 1.873054 2.167222 0.758372 1.213658 0.954275 1.998033 1.191408 0.501345 1.363443
+1 0.006624 1 1 -1.323937 0.488941 -0.781535 -1.830702 -1.423927 2.279037 1.485968 -1.001863 -0.942735 -1.487414 0.258523 0.166699 -68.909890 -18.517578 25.058822 -36.380079 -39.985765 0.763823 0.578192 1.419091 2.160306 1.503701 2.200848 1.159278 0.480875 1.559150 0.379673 1.669782 1.268304 1.384350 1.025379 2.292433
+1 -0.066090 1 1 -1.176524 -0.648384 -2.338152 -0.709086 0.018929 -2.306014 2.222567 -0.416020 1.136408 0.291676 1.318271 -1.469442 22.726441 63.287806 28.152589 60.567055 50.485289 0.718787 1.907641 0.723051 1.572704 0.945126 1.229464 1.110594 1.261433 0.657765 2.302160 0.645160 1.960290 1.336273 0.741474 0.699858
+1 0.008707 1 1 -1.467096 -2.268347 -0.878702 0.280934 -0.157540 0.594938 -0.567101 1.888260 -1.956936 2.256606 1.463341 0.418703 49.317364 -23.065820 -67.240030 -3.181676 -74.426927 0.724522 1.544145 2.440547 2.279178 1.387693 0.963443 0.836369 0.360286 2.074611 1.231549 2.386645 0.847342 0.282861 1.286743 0.795419
+1 -0.022094 1 1 0.451477 1.024803 0.085481 -0.599498 -0.670116 -0.032168 1.277034 -1.814470 -1.932986 -0.492110 -0.643585 -1.800645 -15.218989 -35.556526 1.474203 26.925439 -14.140981 0.363023 0.830132 1.279879 2.428451 1.481637 0.367482 1.526659 1.060380 1.051517 0.600369 0.645055 2.438351 1.358926 1.223996 1.443427
+1 0.017708 1 1 -2.096977 0.070055 -0.678081 -1.942977 1.234546 0.366948 -1.222173 0.239580 2.233559 0.528589 1.140963 1.456718 69.962928 16.925799 71.906611 -15.585469 -44.979961 1.701828 2.126947 1.093774 2.052220 0.661819 0.699160 0.539936 1.946248 1.596340 2.191484 1.277345 0.337115 1.892428 1.535937 1.749228
+1 0.088266 1 1 -1.643136 -1.593649 0.761761 -0.649361 0.088783 -1.644998 0.100408 0.521684 -1.818838 0.063882 -0.762991 -1.178800 -38.732451 23.689044 41.764245 -68.335003 43.596637 1.055113 0.277052 0.404485 2.432033 0.925683 0.699045 0.841040 2.366627 1.903626 0.740908 2.444570 2.386893 0.506754 2.270169 0.735784
+1 -0.006968 1 1 1.443718 0.475309 1.010923 -2.286283 -0.733030 -1.849703 -0.326887 0.648043 1.335256 1.251589 -0.652082 1.475014 -41.903442 -21.147949 66.427575 -1.741476 -18.985906 0.683154 1.522488 0.701277 2.357104 1.587714 1.212314 0.860852 2.337590 2.123419 0.300392 1.187971 1.224620 0.694082 0.691084 2.043091
+1 0.033656 1 1 1.580058 1.717494 -2.178009 0.047512 2.147390 -1.010864 -1.426044 -0.309995 1.821036 -0.818330 1.785480 0.065721 59.432683 35.105804 73.249943 61.788392 27.497931 1.490863 2.427854 0.438824 1.314661 2.016008 1.793795 2.066936 0.484554 0.399439 0.875936 1.602364 2.180538 1.810588 0.800186 1.977029
+1 0.038359 1 1 -2.253411 0.396346 -1.925002 1.754685 0.856210 -1.321989 0.237517 0.552387 0.553548 1.233128 0.092917 1.858194 53.029050 -40.752862 -33.345072 -30.625080 -65.723371 1.184574 0.391597 1.823881 1.459203 1.322196 0.398333 0.289269 1.001787 1.790879 0.296573 2.258510 0.536740 2.237085 0.436807 1.163442
+1 0.003523 1 1 0.798353 1.742663 1.437794 -0.129629 -1.547174 -0.384387 0.287223 1.863470 0.809648 -1.617073 -1.800281 0.922870 70.007866 22.205260 3.805584 60.450035 33.743739 1.090195 0.414682 0.565972 0.794107 1.052303 0.306786 0.645866 0.315860 2.401775 0.879161 1.812636 1.474456 1.175101 0.924332 0.496690
+1 0.015314 1 1 -2.031291 1.353640 -0.784647 -2.305254 0.858546 0.243038 -0.893395 -1.624194 1.041037 -0.386550 1.643051 0.158503 46.259903 40.184404 -70.713593 -33.364492 -57.018723 1.919825 0.752294 0.307158 2.403817 1.451068 1.845093 2.472009 2.313328 1.606665 2.467898 0.713927 1.214028 0.425775 2.495993 0.402938
+1 -0.008304 1 1 -0.889367 0.101339 2.034556 1.691990 -1.998164 2.050213 0.939529 -0.551773 0.331617 -1.261110 0.854290 -0.593253 19.408479 -51.698070 60.544409 -30.123962 -43.422268 0.654134 2.032729 1.575385 0.997419 0.369813 2.440973 0.435610 1.291171 0.970058 1.767000 1.722176 2.104589 1.078615 1.533750 0.980839
+1 -0.021262 1 1 -1.313911 -0.653005 0.093327 -0.680773 -0.071984 1.245906 -1.922984 -2.025731 0.554970 1.571073 1.512819 -2.093914 -9.019917 52.261084 -47.961521 10.715048 -62.182252 0.668375 0.622590 0.626371 1.171596 0.517317 2.041313 1.841536 1.196608 2.385360 1.754376 1.045182 2.130498 2.278804 1.863348 1.039453
+1 0.059834 1 1 -0.591725 -1.983693 0.226129 -2.348748 0.278194 0.910778 1.603339 1.882535 0.795026 -2.330284 -0.421516 -1.694747 -61.396270 -37.117820 10.804248 -63.009524 -1.061492 1.517611 1.980916 1.502100 2.301204 0.342811 0.880310 0.861934 0.281216 0.646275 0.440771 0.292360 1.195633 1.754034 2.049240 2.328928
+1 -0.001118 1 1 0.483571 -1.494767 -0.804260 -2.064650 1.460635 2.050524 1.454417 1.224160 0.165440 0.236478 1.945809 -0.775552 -7.346340 -19.930977 -29.937864 -65.686970 -0.904626 0.564311 2.128052 1.673291 1.743027 1.556018 1.736279 0.648740 1.367321 0.559866 1.670484 1.820306 2.139461 2.172439 0.674383 0.358405
+1 -0.016029 1 1 1.653433 0.288868 1.236863 1.617087 2.031156 1.087218 -1.778466 0.008439 0.459626 1.326567 1.292793 -0.849609 -26.653742 -69.435522 -2.823021 -46.513496 47.674292 0.802311 1.691270 2.425448 0.509914 1.366317 1.684985 0.297814 0.615618 0.446963 0.864122 1.042068 1.529842 0.547190 2.373836 1.564504
+1 -0.031628 1 1 1.375144 -2.228645 1.944907 -1.790680 2.073416 -0.216134 0.686191 1.598440 -0.348616 -1.689911 -0.758917 1.319535 29.314151 -67.060803 9.090414 -67.416085 37.861418 1.927893 1.341465 0.250815 0.443826 2.128296 1.276863 1.241102 0.949985 1.904675 0.379647 1.221131 0.548830 0.681453 2.177241 0.394165
+1 0.025521 1 1 -0.739438 -1.168849 1.103107 1.375055 1.002755 1.796841 -2.202157 -0.540535 0.720757 -1.788219 1.015948 2.047301 -27.762441 46.653513 55.588549 -73.261363 46.273424 0.886598 0.801571 0.500753 0.409892 1.052643 1.513353 2.430824 0.853018 1.175529 1.362443 1.832250 0.379951 1.837663 1.351286 1.066667
+1 -0.012971 1 1 -0.646425 2.304083 -1.692582 1.461449 1.601702 -2.079548 0.825175 0.148774 -1.836193 0.541543 2.095745 -1.928828 -40.777039 10.311401 53.722084 57.069327 64.185520 0.865402 2.316446 2.253229 1.767293 2.145357 2.265989 2.484345 0.378561 0.977917 1.102548 1.025752 1.815616 2.059936 2.089115 2.009947
+1 0.030442 1 1 -2.021078 -1.351361 1.385203 1.906187 -2.256549 -0.507647 2.119880 -1.545986 0.728727 0.215309 -0.421257 -2.057809 -43.423580 -70.111649 33.515388 43.121593 -55.378819 1.347838 1.614606 0.930249 0.947887 0.379928 1.450328 0.664613 0.403666 2.169883 0.472496 2.487719 0.834287 1.358659 1.235254 1.661762
+1 0.006642 1 1 1.558870 -0.953655 -1.241028 -0.925108 -2.116736 -2.155271 0.491423 -1.469346 2.333007 -0.945869 -2.329226 -1.480059 42.828563 -30.349423 67.250483 28.867622 -71.881724 1.132863 2.034289 0.794059 2.493823 2.190195 2.104872 1.339932 1.480616 1.207295 2.009692 1.391474 1.497785 1.778795 1.965081 0.871826
+1 0.061525 1 1 1.297436 1.784620 -0.243581 1.203429 0.450990 2.260805 1.359170 -2.090983 1.852231 0.401257 0.499405 0.743075 33.019070 -48.495904 29.349388 -74.832006 48.480106 1.452092 1.060925 1.222650 1.336075 1.912835 0.264529 1.443715 2.017775 2.239061 2.154784 0.962036 1.946353 1.111817 1.551503 2.353728
+1 -0.046268 1 1 -2.065579 -0.021774 1.603753 -0.583334 -2.319422 -1.643106 -1.086942 1.693265 0.583031 1.946230 1.602190 1.421107 68.503032 -69.543641 -19.968610 -62.432157 -47.265990 1.382469 0.904339 1.970473 1.496134 1.018601 0.878235 1.999157 2.086643 0.959411 0.565240 1.982209 0.728757 0.717380 0.749170 1.808478
+1 -0.010415 1 1 -0.475633 -1.749789 1.316228 1.883523 -1.449201 1.613086 0.763536 0.909779 -1.049927 1.764877 -2.195399 -0.057544 -35.207989 9.335500 1.750366 18.402252 -13.348390 2.179235 2.395652 1.479442 1.723434 0.751476 2.306982 0.703446 0.565885 1.573041 2.097915 1.402511 0.255782 0.670806 0.980975 0.743725
+1 0.030189 1 1 -1.062347 0.369578 0.569371 -1.443157 -0.476833 1.640076 1.993396 -2.085181 0.402976 1.113398 -0.013445 0.217398 54.386685 -22.986982 57.795200 -36.074775 -8.738285 1.159562 0.760012 1.767559 2.119448 1.058915 1.184377 1.576165 0.608569 1.226897 0.712698 0.809727 0.337140 2.308572 0.413209 0.545420
+1 -0.016590 1 1 1.459486 1.591603 -2.162122 -1.546540 0.846537 1.045097 1.867708 1.344107 -0.788788 -1.206368 1.981300 1.971881 -26.369671 54.937736 -61.465086 6.301331 6.472451 1.862147 1.111643 0.882439 0.652582 0.701338 1.133322 0.749993 2.137878 0.306763 0.259253 0.513548 1.693365 1.635957 2.027067 0.914350
+1 -0.011510 1 1 -0.678334 -1.487861 2.169961 1.360523 1.790559 0.614138 1.688074 -1.833183 -0.700932 0.410497 0.289163 1.496314 -46.604927 10.994863 -9.345139 -13.749166 67.767194 1.573356 0.646580 1.069489 1.149153 1.308334 1.418610 0.829507 2.020719 2.216333 0.405553 2.380150 1.923893 1.628269 1.070116 0.445786
+1 0.006039 1 1 2.080202 0.743726 -2.160415 -1.141698 0.321882 0.047126 0.364389 -1.822206 -0.003536 1.839165 2.290773 0.812261 -3.724183 -42.338860 10.772213 -1.411292 -19.582561 1.013440 1.889109 2.006198 1.176312 1.026862 2.468405 2.490400 0.899241 1.794264 0.946143 0.317189 2.252066 2.469562 1.684588 0.365073
+1 -0.034646 1 1 1.923381 -0.725302 0.806512 2.224626 1.201385 -0.909392 -1.881489 -2.058959 -1.858002 1.556917 -0.787721 -2.125354 -29.310680 -24.605354 7.813511 71.685066 10.896873 1.281168 1.592964 1.704890 1.828682 1.158117 1.225635 1.999917 1.348953 2.348433 2.118741 0.423321 1.757036 0.747560 1.749223 2.184129
+1 0.004267 1 1 0.609952 2.019063 0.475742 -1.132312 -2.137068 0.120771 -1.236403 1.401387 0.591464 2.309579 1.140896 0.321450 70.533734 10.471628 46.652481 38.249228 -45.230994 1.415231 0.296089 0.864354 0.439594 0.749684 1.430939 1.045546 1.499159 2.370228 1.670944 0.556578 0.414587 1.216165 0.325988 1.629380
+1 -0.011425 1 1 -1.915463 1.859141 -1.266284 -1.283251 0.998507 1.085354 -0.115278 -0.689346 1.921289 1.819272 -2.189709 1.316698 11.556535 -19.316282 -48.755950 8.745172 -19.892515 1.622528 1.322498 0.970543 0.910347 1.705161 1.886840 2.114194 0.510236 2.287913 1.948886 0.922882 0.885431 1.442789 2.196583 1.470759
+1 0.034543 1 1 -1.716022 -1.365693 0.847797 -1.340538 -0.494453 -2.333897 0.113154 -2.030355 -1.767099 -2.152484 0.217705 2.148148 73.787544 -52.745388 8.262003 -40.514084 -70.207924 2.356350 2.422678 1.206460 1.475901 0.708967 1.109134 1.463938 2.155454 0.958535 1.596569 1.526515 0.885064 2.023465 1.128172 1.941011
+1 -0.038343 1 1 0.721914 -1.188782 0.669239 -0.571664 0.600294 -0.081978 -1.782868 1.422073 -0.464306 0.119528 1.437493 -0.480655 -42.418860 16.221149 -71.146707 37.297372 6.924387 1.047494 0.479781 1.179217 0.349771 0.844707 0.997524 2.139251 0.891997 1.537187 0.258885 1.083271 1.037820 2.136560 0.672116 0.495297
+1 -0.019813 1 1 -0.643068 2.182781 0.046022 0.666468 -0.016102 -2.019225 1.515685 -1.051390 0.752307 0.676645 1.384964 -2.117151 9.575543 -13.848632 46.044154 14.100348 -15.449380 1.259141 0.381947 1.641415 1.515605 2.029650 1.580666 2.000207 1.733359 1.055862 1.627901 1.636054 1.408836 0.799911 1.856024 1.688468
+1 -0.035723 1 1 -1.506352 -2.304836 -1.540311 1.860588 -0.513133 -0.558809 -0.103938 1.412985 2.305249 -0.948166 1.468382 0.323512 -26.273386 23.204717 1.680843 49.937453 48.765407 1.378003 2.338825 0.388095 1.466453 1.677251 0.807160 2.196216 2.057035 0.586926 1.959099 1.579837 1.568057 1.582107 1.463530 2.052307
+1 -0.013825 1 1 -0.073126 0.903122 0.174225 1.806379 -2.113190 0.890721 -0.909800 0.701956 -2.043055 1.553501 -1.657740 -1.998831 8.676049 18.356536 -31.692800 -10.889971 -27.736619 1.834620 1.960250 0.670975 1.575833 1.769333 0.423575 1.521628 2.004089 1.717089 2.120339 0.288838 0.502977 1.781118 0.502538 1.151048
+1 0.037796 1 1 0.951966 1.131382 0.641382 -2.233860 -0.885774 -0.770016 -1.439651 1.902611 -1.092138 -0.806816 2.097237 -0.407079 19.408428 -52.543317 -45.536711 -35.498759 72.363484 1.571209 0.568847 1.863107 1.486578 2.409635 2.488482 2.412244 1.336649 0.306197 2.010181 0.614327 1.240276 0.566613 0.312688 0.847485
+1 -0.020468 1 1 1.567784 -1.939570 1.959992 1.992823 -2.287681 -0.679005 1.365559 1.614747 0.399521 -0.407827 2.173687 -1.997091 39.541670 -73.159941 -49.132786 -24.726542 71.012651 0.769412 2.263054 0.398300 1.977180 1.707843 1.966638 2.294099 2.415520 2.387978 0.742748 1.872841 0.845575 2.074722 0.852117 1.786083
+1 -0.002603 1 1 -1.016793 -2.113779 0.419580 2.149237 1.759149 0.491985 -1.452578 1.415516 -2.274351 1.876216 -1.736674 0.264756 39.969906 74.207934 -37.253791 -24.473662 -28.841521 2.283287 0.703091 1.357274 0.462269 1.608059 1.145246 0.903194 0.734815 1.288898 1.002105 0.375344 0.900278 1.229527 2.154634 0.685256
+1 -0.019290 1 1 -1.848734 1.813550 0.610456 1.064683 1.193274 -0.572748 1.242415 0.679893 -0.589087 -0.059636 1.442797 -0.865478 33.723510 -58.972669 46.347206 7.483070 67.960391 0.779321 2.302367 1.882988 0.374229 2.414813 1.766753 2.068786 2.335608 0.317870 2.442601 0.803274 2.133138 1.646693 2.471430 1.567814
+1 0.003230 1 1 -1.838331 2.308409 0.337286 -0.242252 -0.023925 -1.554093 1.131020 -0.726340 2.211441 1.083032 -1.446002 -1.162682 34.531031 13.035187 -67.605776 -0.273884 46.826417 0.798772 0.712251 2.300633 1.992275 1.159434 0.863646 2.042237 1.621046 1.177535 1.335051 0.457233 2.466662 2.436026 0.531990 1.152401
+1 0.053216 1 1 0.775717 -1.705830 0.289445 1.521867 -0.835073 -1.571015 -0.539348 1.810784 1.237530 -1.310869 -1.361998 1.678975 23.578999 -7.761382 54.455451 -67.243163 -55.839445 2.221750 1.451886 2.102893 1.823071 1.346996 0.968608 2.140474 1.195731 1.148129 2.106818 0.283468 2.497796 1.450303 2.484171 1.956856
+1 -0.002822 1 1 -1.461278 1.270435 0.367959 1.625603 -0.913719 0.805974 -2.117392 0.950967 -1.517386 0.748082 0.354473 1.176398 -46.660653 -25.591443 -65.374904 -6.019439 -68.710165 1.948934 1.738529 2.457752 1.179356 0.431369 2.023515 1.973790 0.987291 1.143106 0.927402 0.341008 2.074546 2.386037 1.871674 1.481157
+1 0.001869 1 1 0.020071 -1.952535 0.813172 1.055869 -0.867585 -1.372391 1.376044 -1.235535 1.864666 2.057526 1.322597 0.541838 74.239173 37.780147 20.928369 -6.900737 -30.684922 1.052795 1.833594 0.459868 1.746768 1.433391 1.752155 1.975974 1.696512 0.521884 2.305510 0.707564 2.277951 1.017907 0.456454 0.618419
+1 -0.016408 1 1 1.149504 -1.075349 -1.370361 -2.208755 1.650819 -1.224041 1.826276 -2.278305 1.399139 0.500934 -1.833756 -0.919992 -30.444029 -22.787567 -40.630254 -72.681221 46.725434 2.340663 2.025214 1.266561 1.333533 1.942052 0.823189 1.589042 1.031824 0.363132 0.413809 1.643068 2.288514 0.799633 1.684180 0.264480
+1 0.022128 1 1 -2.099753 0.529912 -0.190063 0.616903 1.037248 1.907382 -1.019404 1.124352 0.309684 -2.338137 -0.449924 1.508219 22.387155 60.918074 -49.935735 -19.896670 -53.337936 0.614750 1.609042 1.911601 2.029789 1.659693 0.468852 1.993276 2.237334 2.364973 1.098176 1.786802 1.534126 0.555371 0.376965 1.153095
+1 -0.025624 1 1 -0.535802 0.150030 0.426683 -0.988641 -0.208212 1.885236 -0.940393 0.169632 0.007797 -0.901156 -0.112493 -1.003265 -30.123403 -34.035321 68.365376 16.872037 68.327236 1.012787 2.164534 0.570663 0.890731 0.512809 0.529949 0.602876 2.292125 0.752131 2.065456 0.362026 2.067018 1.865478 0.834468 2.157011
+1 0.019022 1 1 -1.144906 -1.744044 -1.082268 0.147149 -0.877178 2.326317 -0.276516 -0.982143 0.624415 0.060400 1.987556 -1.262827 8.260539 -65.124885 -3.936519 -11.072848 48.640383 1.358639 0.890041 2.411465 1.739304 1.981771 2.376245 1.549042 1.495714 0.722104 1.403183 0.291602 1.949753 1.995713 0.450212 1.459105
+1 -0.025133 1 1 0.526656 1.643730 2.149247 1.935550 1.176416 -1.168628 0.112922 -1.210781 -1.508277 -1.668818 0.311601 1.607750 19.626127 6.311704 30.802478 47.246047 -35.686841 2.293842 0.358330 0.704153 1.204014 0.868626 2.492644 0.364501 0.915135 1.171491 1.000291 1.386812 1.905299 1.857797 2.247648 2.477726
+1 -0.007375 1 1 1.392386 0.114646 -0.515466 -2.072424 -1.971629 0.356014 -1.206256 -0.848098 0.997884 0.044919 0.977288 -2.100283 33.333906 -7.038732 50.024159 6.037320 69.236874 0.837236 1.426495 0.608422 1.005762 1.096665 1.146172 0.715898 0.600387 0.949661 0.954834 2.395869 0.616455 1.010691 0.678668 0.371076
+1 0.006721 1 1 1.705599 0.533263 -0.411460 -2.326519 1.595456 1.342995 -0.630544 0.612112 0.621780 -1.817629 1.520911 1.944813 42.696904 6.865587 39.911830 -1.880796 39.461459 0.305996 0.879066 2.468129 2.340304 0.485882 2.475042 1.530384 0.667327 1.009315 2.308004 2.121575 0.810822 0.742448 1.316868 0.849639
+1 0.020441 1 1 -0.532429 0.285861 -2.163235 -1.405187 1.513748 -0.631273 -2.212842 -1.053791 -1.904949 -0.509033 -2.336561 -2.244881 -74.128913 15.363610 66.200636 -65.919013 -0.845473 1.976914 1.741483 0.350163 0.693223 1.999583 2.498164 0.895336 1.404216 1.900088 2.022543 1.375569 1.936999 1.387364 2.178232 1.288399
+1 -0.004361 1 1 2.267639 -1.594297 -0.707193 -1.147510 1.607828 1.929975 1.723742 -0.838410 -1.114613 -1.560053 -0.080498 -0.466435 64.821452 4.141653 8.753252 -34.092877 1.009700 1.675423 1.580991 0.720722 0.674204 1.841997 2.190364 0.443497 1.095691 0.530976 2.110144 2.186701 1.888355 0.580086 1.761604 1.021478
+1 -0.069969 1 1 2.218351 -0.603577 1.459996 0.751739 0.557385 -0.258792 0.025678 -1.966490 1.894278 0.229602 -0.526759 1.345731 -56.309296 -40.345236 67.619091 74.059130 11.803302 0.296451 2.445894 2.147288 0.971236 1.320489 0.956324 0.431829 0.753853 1.760388 0.843281 1.773248 0.977619 0.593380 2.441558 1.263113
+1 -0.016208 1 1 1.668177 -1.663863 -1.231461 -0.345183 -0.539228 -0.873340 0.863644 1.114570 0.824574 -0.515955 -0.859326 0.786621 -70.778924 68.632685 9.532395 10.962732 50.633034 1.966114 2.482812 1.622890 0.658406 1.826323 2.009670 1.021484 2.081735 1.726090 0.394757 0.933869 1.032983 1.840179 0.891045 1.294516
+1 -0.055506 1 1 0.816272 1.317987 -1.536817 -0.687225 -0.131182 0.615375 -1.084737 1.065096 -1.290777 1.740866 -0.489860 -0.525173 -9.044682 -63.975365 -33.955459 60.600226 7.999051 1.975783 0.734763 0.419190 2.082513 1.295013 0.289706 1.587077 1.760314 1.840518 2.085269 0.361498 2.196088 2.156249 0.825637 2.232592
+1 0.061025 1 1 -1.754788 2.113742 -1.047404 1.772566 -0.201232 1.387336 0.054494 1.684157 -1.686420 1.356128 -1.386305 -1.570877 56.650328 72.056809 -41.209239 -53.681964 17.229517 0.272333 2.100987 1.288722 0.297330 1.467270 1.911332 2.000070 1.679054 1.865090 1.075197 0.330349 0.683467 2.279859 1.592000 1.237893
+1 0.025520 1 1 -1.817665 0.929157 -0.523587 -1.897908 0.020753 0.074242 -1.002246 2.036738 0.662115 2.208948 1.594294 0.651208 -64.627983 -52.510625 53.931935 -15.968366 -30.319306 0.976302 0.957430 1.026561 1.904120 2.301333 2.496256 0.331562 0.805350 1.011640 0.883567 1.608287 0.486123 2.019641 2.108341 1.136291
+1 0.032086 1 1 0.179711 -0.240930 -1.375493 1.062403 0.572729 -1.556677 0.104754 -1.828135 -0.683857 -0.074461 2.037794 -0.433531 -31.965196 60.951674 64.791983 -41.140734 47.675958 1.222276 1.791866 1.145939 1.290655 1.289468 1.589663 2.473682 1.166042 1.661925 1.968591 1.359421 0.542221 2.105404 1.271930 1.579205
+1 0.004656 1 1 0.740191 -0.324846 1.974052 -2.030315 -1.099001 1.650566 -0.769958 -0.457144 -2.024335 0.443080 1.264347 1.716498 -2.049164 59.694822 -59.134712 22.901012 -2.686579 1.324977 2.138551 0.381693 1.865412 1.976982 0.639224 1.182563 0.341526 1.770755 1.829914 1.619490 2.020706 2.000249 2.430107 2.306105
+1 -0.016109 1 1 -2.346666 2.278976 0.445078 1.868007 1.653753 0.950431 -1.106852 1.650556 -0.940605 1.308373 1.812370 -0.377632 23.144286 36.014556 46.634952 43.638079 -74.805183 2.114449 0.290448 0.560982 2.416074 0.460093 1.039695 2.150694 1.970773 2.038671 2.447039 1.142931 2.487806 2.300475 1.582121 1.708511
+1 -0.032230 1 1 1.252724 -0.414557 2.163546 1.931398 2.062794 0.327653 -1.918093 0.069699 -1.950797 1.754667 0.561162 1.965820 31.173762 -12.575300 -3.064900 -61.771915 -50.581812 2.447319 1.335131 1.791580 0.837429 2.420927 1.012919 2.136585 1.082166 0.470400 1.020290 2.254844 1.916620 0.878994 1.254247 1.382056
+1 0.016506 1 1 1.230986 1.800847 -0.830422 1.197534 0.340109 0.080689 -1.032410 -0.707088 0.616983 -2.339278 -0.777623 -2.054361 0.753506 64.173480 63.677999 -13.864946 71.844568 1.249818 1.189385 2.490649 0.582478 1.465484 1.146685 0.335278 0.270682 1.358930 1.290700 2.039995 2.201818 1.696165 1.452405 1.824883
+1 0.011588 1 1 -0.372681 -0.882975 -0.841111 0.616196 -1.431509 2.078869 1.891307 2.124353 -1.775816 2.123539 -1.312574 -1.734938 37.171722 -4.864048 -0.054633 -18.208620 -32.284093 0.643858 0.314443 1.086194 0.659259 0.423138 0.927551 0.600602 2.317269 0.344145 0.799664 2.207547 1.242333 1.394982 1.956924 1.025842
+1 0.000266 1 1 -1.770175 -2.012341 -0.608515 -1.424537 1.454946 0.696714 -0.618228 0.264531 2.186498 1.261093 -1.131303 0.685961 -72.144730 63.526938 -2.752439 -60.243315 -9.394590 2.201867 0.277837 2.348347 0.663347 1.623353 1.702419 0.804365 2.470562 0.479100 0.976196 1.430402 1.016767 1.554281 1.807654 0.982015
+1 0.025703 1 1 0.667624 0.550954 0.036546 1.622965 1.859234 0.290238 0.699773 -1.041873 0.473534 -0.546520 -0.908473 -0.571646 28.885829 -65.873817 8.758839 59.808292 47.968731 0.781962 1.689221 1.740015 0.423187 1.746860 0.732607 2.427127 1.727193 0.937488 1.114187 0.893265 0.357016 1.110642 2.052673 1.529493
+1 0.015841 1 1 -0.096355 1.624734 -1.385259 1.863564 -2.334860 -1.925972 -0.417397 1.556254 2.203117 -2.163155 -0.065525 1.412980 71.064477 -69.328136 2.026559 10.386214 -38.907127 0.443819 2.019101 2.028759 2.346745 0.748682 0.352987 0.906339 1.842884 1.358584 2.218174 2.108284 2.427304 2.447394 0.356542 2.151224
+1 -0.021803 1 1 -1.575542 -1.213395 1.697215 0.997153 1.899863 -0.155375 -0.718699 -1.316206 -1.523972 -1.557790 0.254368 1.027813 -36.789529 -21.613642 39.516731 -42.299582 70.930765 0.375466 0.698913 0.876720 1.281575 1.673113 1.015095 0.460513 1.350086 1.138205 1.816677 1.894208 2.205775 0.715254 1.026864 0.259206
+1 0.006601 1 1 1.034554 -0.969088 -1.443641 0.810507 -1.324553 -0.428275 -2.197136 -0.992032 -0.648237 0.122431 -1.620408 -1.299216 40.725026 15.513284 31.762808 -12.478022 -18.118361 1.145622 0.461755 1.959130 2.104031 0.706031 1.265376 1.682066 0.736334 2.072920 2.072802 2.342140 2.100637 2.155920 2.044458 0.709467
+1 0.034676 1 1 0.302196 -0.947042 1.507710 1.558336 -0.513395 -0.246864 -2.135884 1.181994 -1.655469 -1.527469 0.924965 -0.281481 12.172643 -14.394642 19.248967 -32.618903 24.100414 2.209892 2.403248 0.894378 1.064676 1.252538 1.911713 1.659884 1.423504 2.074080 1.315205 2.146516 1.499728 0.676389 0.322560 0.272690
+1 -0.034172 1 1 -1.490317 -1.415513 2.328161 -2.283212 -0.958035 0.538907 0.192894 -0.156766 -0.535074 -1.758759 1.346485 1.476166 -25.776435 -24.545272 -32.385282 50.569132 15.395748 1.470115 2.480825 1.982323 0.405623 1.301012 2.101804 1.523595 1.308440 0.955147 0.907713 2.431024 1.969922 1.231988 0.772051 1.619004
+1 -0.000562 1 1 -1.408818 1.753333 1.701071 -0.157601 -0.436584 -0.474723 -0.586953 -1.888794 -2.299630 1.135913 1.404201 0.761128 -59.242047 18.918985 -28.622473 -7.903482 66.169999 1.662586 1.836489 1.863586 0.539166 0.264660 1.393614 1.461568 0.577867 0.453067 2.189266 2.246120 1.538899 2.027038 0.421852 1.819934
+1 -0.004862 1 1 -0.028938 -0.978750 1.104641 -1.116434 0.828803 -0.130237 -2.349063 -0.298322 0.079000 -1.135640 -1.520603 -1.493692 -50.492556 71.604501 6.846162 13.441880 17.670821 1.277363 0.643975 2.291794 1.937213 0.482925 2.275594 1.902001 0.436426 1.507167 1.962024 1.234840 1.454439 2.250966 1.989926 2.179033
+1 -0.018275 1 1 0.466951 1.910819 0.212270 0.335976 1.311276 -1.222332 2.278104 -0.073817 -1.289729 0.506843 -1.487170 -0.351494 56.724467 -31.889332 -13.998942 69.776682 36.695846 0.581253 1.121689 0.976690 0.732603 2.355123 2.046658 1.679623 2.418311 2.051489 1.877762 0.288411 2.327562 2.332735 1.525214 1.514522
+1 0.030086 1 1 -0.774947 0.511239 1.710753 2.342823 -0.898400 -0.908371 1.143943 -0.302237 0.252649 0.407994 0.623471 -1.676376 16.626016 -16.546738 -1.029157 -47.038156 -70.288518 2.288211 2.460889 2.156640 0.655962 1.257947 0.569038 0.574204 1.888750 0.478489 1.968409 0.547616 0.539126 1.835873 0.522594 0.745270
+1 0.020972 1 1 0.511153 0.266350 -0.229834 1.331322 1.100206 -0.251330 -1.798766 -1.893135 0.135752 0.791052 1.563030 -1.717773 70.033911 9.948571 -44.358661 -36.009750 34.124961 0.448313 1.050170 0.452233 1.686819 1.872455 1.099563 0.355959 1.345010 1.338184 1.360664 1.184917 1.650834 2.325268 2.031278 1.946675
+1 -0.009534 1 1 -2.297083 1.532511 -1.003117 1.537426 1.493724 2.129047 1.716557 0.932514 -0.639099 -1.801888 2.194745 -1.505529 66.686101 -6.700138 40.774081 -60.028412 2.478736 0.776821 0.787772 0.326463 0.610087 1.982904 1.160998 2.398372 2.184689 1.811447 1.733885 0.911665 1.357470 1.498699 1.377212 0.293129
+1 0.029322 1 1 0.092769 -0.625550 -0.277162 2.299132 -0.072735 -1.949849 -1.152457 -1.434039 1.972486 -0.079869 0.680216 0.137239 70.552355 23.432873 -63.698361 -28.346571 -20.823133 1.009151 1.809451 1.951335 1.583214 2.079305 1.374802 0.299293 0.717015 1.377357 0.490210 0.954607 0.831829 0.543084 0.857815 0.792577
+1 -0.074895 1 1 -2.067844 -0.391824 -2.185664 -1.384774 0.599790 0.877860 -0.296922 0.059459 0.304147 -1.148566 -2.009173 0.804139 1.279090 47.666545 -18.372092 70.248239 12.154375 1.053783 0.422675 2.151359 1.884103 1.119696 1.232880 2.266203 1.573302 1.990914 0.799529 2.190170 1.679730 1.977089 2.427205 0.779491
+1 0.005732 1 1 0.091110 -0.236493 -2.191509 -0.660523 0.972256 -1.858122 -0.451211 -1.263798 -1.909471 -1.114186 0.907863 -0.266939 -8.161174 -64.848441 -7.755667 0.507306 -23.699950 2.499086 0.635824 0.287731 2.151642 2.145842 1.419603 1.762023 1.326093 0.647807 1.436458 1.552538 1.758368 0.647210 0.415569 1.969946
+1 0.023626 1 1 -2.163781 -1.156671 -1.568119 1.022754 -1.374148 0.120508 -0.949427 -0.871280 -2.206851 0.676124 2.053442 -1.331118 73.895413 -39.794341 26.503109 -62.246232 -72.423319 1.844268 2.110015 2.266809 0.510441 1.232087 2.427927 1.673837 1.924937 1.169258 1.722588 2.286150 1.572595 1.360445 1.996555 1.094150
+1 -0.004850 1 1 1.258178 1.704759 0.563008 -0.005987 -1.660229 -1.410635 -0.515026 0.617109 -0.223310 -2.108783 -0.432591 0.655221 -17.619713 -34.512420 -0.250035 -2.345299 32.558336 1.494302 1.736205 1.652386 1.408790 2.284504 0.907650 1.371365 1.029559 0.543784 1.378790 2.066127 0.397494 1.926764 0.377977 2.401699
+1 -0.022331 1 1 0.755551 -1.337347 1.296341 2.226589 1.198870 -0.760485 -1.474936 -2.089190 -0.999517 0.777193 -0.456705 0.637721 70.406550 -27.106259 -24.887900 59.064177 -8.377599 2.090308 1.801162 2.131733 0.534377 0.768077 2.320842 1.896577 1.520719 2.471426 1.503769 1.090313 2.390467 2.076549 2.307807 1.060070
+1 0.002998 1 1 1.283617 0.436412 2.300628 1.505921 -0.234334 1.109398 -1.267087 -0.653602 -0.510844 0.225635 -1.222061 2.126775 39.389271 65.476016 55.405563 1.299530 -58.802411 2.243163 1.345614 2.484663 1.230142 1.254765 1.082404 2.211485 2.175735 2.083516 2.406670 2.146398 1.757672 2.448751 0.655395 0.731299
+1 0.000232 1 1 1.146172 -0.533752 1.625259 -1.987500 2.217305 0.673339 2.355743 -0.510551 0.423753 1.599729 -2.252808 1.104631 -40.450197 -46.464889 -35.386589 7.606704 45.870821 0.638282 1.098905 0.539075 0.987033 1.315630 0.297630 2.023279 2.499188 2.350427 1.869242 1.104530 0.581407 1.449167 1.395304 0.622375
+1 -0.010013 1 1 1.075842 0.239949 -0.984349 1.245134 -0.754837 -0.786605 -2.221233 -0.711091 -0.692423 2.043397 -0.524235 1.348588 -27.550544 8.002147 -57.913402 -0.544188 3.824504 0.301520 2.138833 0.620399 2.049608 1.759662 2.141776 0.573088 1.140184 1.321458 1.499251 1.667648 1.407993 2.396376 2.395358 1.038387
+1 -0.067838 1 1 -1.633678 1.857792 -0.380521 -0.705993 0.165609 -1.624095 -2.015104 0.079929 0.341532 0.441832 -0.850600 1.352624 31.230151 35.141276 69.430274 64.607317 5.180661 2.445641 2.385284 0.470832 1.519082 1.968645 2.260543 0.954494 1.185497 2.404132 2.249346 1.750950 1.962917 0.497675 0.422322 0.715200
+1 -0.024483 1 1 2.182988 -1.177581 0.424285 1.119859 0.185605 -0.135582 2.073819 1.848010 0.143000 0.078720 -1.131392 -0.818263 -57.178811 45.726281 71.605466 23.074921 70.199373 0.488004 2.131067 0.586128 2.048326 0.462955 1.891079 1.361001 2.339837 1.635044 2.434004 0.308149 1.065766 1.575135 1.295780 1.920368
+1 -0.035319 1 1 0.054312 -1.377916 -1.952191 1.886363 -0.848400 0.631442 0.340540 -2.101382 1.429216 1.784720 1.425427 -0.629386 38.843037 34.924171 20.548003 50.294670 52.517663 2.340355 1.342435 0.812496 1.877069 2.151690 0.703230 1.436672 0.646074 1.570328 1.497936 2.063518 1.542758 1.639722 2.312677 1.921447
+1 0.028363 1 1 0.944633 0.403846 1.607362 -1.188962 -2.354699 -0.789968 -2.187449 1.606864 -0.139799 1.885746 -1.794014 -2.122935 65.120706 -66.288319 -57.769492 18.144360 2.254526 0.502366 0.519510 0.646427 0.749108 0.752428 0.313688 1.905045 2.099984 2.435729 2.302969 0.751767 0.448590 1.208525 2.420843 1.858558
+1 0.013072 1 1 -1.289758 0.032038 1.257870 1.236968 -1.336600 -0.273366 0.123035 -0.882212 -2.166408 1.815659 -1.644270 -1.803771 -37.782581 -61.838366 32.574555 -19.455256 15.510711 1.202855 1.638251 2.328964 1.141889 0.725256 0.373441 0.422596 0.829215 1.613632 0.312394 0.402169 1.749334 1.812639 1.532197 1.878018
+1 0.009668 1 1 -1.445374 -0.042400 -1.047713 1.280987 -1.355685 -0.602104 -2.070391 -0.779165 0.296981 0.934665 -2.184016 -1.954731 51.099871 -64.463887 5.451031 -34.522036 -11.861430 1.299170 0.398457 2.367840 2.031020 2.108176 0.621185 1.761642 1.671720 2.355005 2.312069 0.689034 1.348623 1.312324 0.976808 0.470080
+1 0.048750 1 1 -1.820138 1.773121 -0.300085 -1.278290 -0.438411 1.798475 1.707704 -1.784161 -1.462063 2.224931 1.614592 -2.195013 54.239743 57.368936 -0.288976 -56.816037 -7.129791 1.669170 2.232676 0.588768 1.420705 2.290843 1.697993 0.669629 1.452685 2.028370 0.316572 0.867474 1.128649 0.950615 1.232565 1.473736
+1 -0.080411 1 1 -0.433635 1.962305 -1.552594 -1.945253 0.686988 0.859328 -0.743802 0.882308 -0.941404 2.022811 2.213304 -0.593470 53.412295 -49.563697 -67.056908 74.540775 6.798599 0.835748 1.167741 0.979260 1.179066 2.314573 2.276110 1.576604 1.237354 0.967590 0.783220 0.334594 2.265820 1.883253 0.333105 1.998279
+1 0.030994 1 1 0.333313 -1.031785 0.384611 -1.241227 0.444839 -2.148138 -2.151218 -2.072851 0.278045 -1.593066 1.130041 1.668952 61.688027 -9.337436 -34.291235 -32.794683 69.759501 2.094000 0.860477 0.528765 0.959703 0.983579 1.754603 0.353693 1.522422 1.846520 1.713120 0.662742 0.462329 0.369961 0.442026 1.137722
+1 -0.033110 1 1 -0.286139 2.216755 0.856317 0.486613 -2.205420 1.162147 -0.653674 -1.723635 -2.076957 1.956846 0.944257 -1.202790 27.393534 53.131624 33.197105 -56.253841 -8.300964 1.160403 1.386710 2.435149 1.548879 1.009489 0.723880 2.003957 1.752417 1.866086 2.056086 0.387908 0.572536 0.862567 1.915491 2.154359
+1 -0.018903 1 1 0.646785 -0.972873 0.911586 1.049960 -1.225568 -0.268823 1.078372 0.356252 -1.917584 -0.808115 -0.891861 0.601980 -0.914257 -65.910890 -14.330897 40.612394 72.506697 1.675955 1.527905 1.747451 1.666207 1.935884 0.643376 1.220807 1.848354 1.043114 1.118534 1.955365 1.817540 0.650933 2.236628 1.761217
+1 -0.026923 1 1 -0.851134 1.805755 1.535566 -1.491009 1.092222 2.226804 0.107780 1.896737 -0.857703 -0.214585 -1.554287 -2.127776 25.035845 27.451992 -14.374546 57.007672 -72.064902 2.202816 0.476167 1.192469 0.326250 1.529370 1.629841 0.491790 0.519339 2.284611 0.463997 1.404597 1.565836 0.255520 0.772294 1.198469
+1 -0.014308 1 1 2.341260 1.113970 0.173159 -1.965301 -1.681504 -0.833935 -1.300740 -0.767112 0.240322 0.577993 2.100837 -1.171922 40.990801 -17.613462 70.540152 -31.673569 12.333993 1.336212 1.964568 1.245138 1.280071 1.156911 1.200392 0.746744 1.521904 2.139868 2.264949 0.748526 2.218843 2.088370 0.742777 2.357732
+1 -0.037362 1 1 1.706282 -2.114030 0.919876 -0.997264 0.945615 -1.931440 1.937278 1.930334 -1.668944 -1.806912 -2.132127 -1.649698 39.180012 -1.545237 -20.791112 63.786470 9.196204 2.284006 1.538164 0.919760 2.409326 1.791968 0.609362 1.042844 1.084854 0.633720 0.938585 1.541225 0.616230 1.731623 1.131903 1.640583
+1 0.013552 1 1 -0.338099 0.715121 -2.273042 0.325749 -0.926396 -0.196943 -1.931602 -0.782467 1.352365 1.352263 -0.371181 0.755834 -41.446989 0.453293 -31.497347 -25.913914 64.848731 1.564238 0.391887 2.194075 2.076893 1.340993 1.317089 2.318958 1.728995 1.976418 2.402302 0.745759 0.715699 1.755741 1.486671 1.736762
+1 -0.034543 1 1 -0.420708 -2.251372 1.676697 0.157977 2.045912 -0.652821 -1.521030 0.760001 -1.944359 1.574508 -2.013886 1.699935 -13.113746 -52.728937 -15.237458 -45.958548 74.681767 1.021924 0.475664 1.742403 2.311578 1.446740 1.116267 2.100886 1.842274 2.350603 0.329829 0.929411 0.357305 1.476346 1.450557 2.269736
+1 0.040068 1 1 -0.037707 -2.273334 0.119444 0.015181 0.674824 -0.952105 1.252569 1.683161 0.412939 -1.081313 2.057597 -2.185447 72.218005 -31.991385 70.788841 -51.950977 9.933695 1.459097 1.789287 0.537892 1.352031 2.332534 0.402058 2.142254 1.868580 1.223319 1.331464 0.917568 1.572173 1.013620 0.417755 0.466570
+1 -0.000629 1 1 0.806689 0.471745 -2.333804 1.678084 -0.091553 2.215018 -0.067733 2.005669 1.564728 -1.465213 1.112266 -0.187683 -57.170000 43.814884 46.748264 -1.919835 -16.666904 0.315121 1.245825 1.583131 0.675172 2.364463 1.520635 1.067522 1.840909 1.913111 0.406490 2.373543 1.135264 1.888008 1.493104 1.846713
+1 -0.014582 1 1 -1.183215 -0.015210 -1.172827 0.222847 -0.963537 2.309499 -0.205626 -1.773891 1.507548 -1.161631 -0.098118 0.259662 14.928307 -49.939828 61.306022 20.312281 -11.487800 0.993259 2.455169 0.533097 1.759494 1.573596 2.426916 0.419827 1.527417 0.293458 1.646901 1.467991 0.527925 0.330998 0.326546 2.012406
+1 -0.063842 1 1 2.212415 -1.395426 0.628942 0.732050 -0.490482 -1.561293 -2.066509 -1.508388 1.179094 1.436251 2.213489 -2.205061 -70.926317 -8.603367 3.216831 65.278674 38.681057 1.562842 1.685096 2.159649 1.718884 0.786074 1.040630 2.122094 0.528075 0.608553 0.948494 1.584729 0.539404 2.005322 2.196019 0.987553
+1 -0.015157 1 1 -0.055958 1.988738 -0.260356 2.009576 1.248940 1.955017 -1.516768 1.702731 -0.534967 0.052166 0.255441 0.215745 70.040221 -34.011560 17.709781 48.280936 -42.305102 1.047384 0.884622 1.350093 1.266701 1.436967 1.111289 1.688304 2.070950 0.453525 0.899476 1.250412 2.166902 2.123703 0.577927 1.464018
+1 0.000429 1 1 -1.111517 -1.358051 2.046627 1.930858 -2.296891 0.046131 -2.219542 -0.568363 -0.458668 0.635331 -0.267418 1.119242 -23.995774 53.031368 -1.793978 -1.389474 47.108274 2.106525 2.115041 1.245602 2.324806 1.019314 1.615875 2.014834 2.314142 1.793165 0.476825 0.994208 0.408607 1.955626 1.704870 1.498824
+1 -0.020512 1 1 0.786910 -2.072011 0.262315 -2.072243 1.076467 1.315346 1.211499 -0.577357 -0.821709 1.552283 1.431545 -1.477046 4.841883 -72.473109 -55.546096 36.772665 38.180897 1.469978 2.424936 0.905149 2.092840 1.618655 1.491070 1.414308 0.517882 0.284468 1.298189 1.912073 0.965205 1.196723 2.078902 1.362150
+1 0.026084 1 1 0.015801 1.680037 -0.247308 -0.178455 -2.206406 -1.282227 -0.629810 -1.186625 -0.773333 -0.642691 -0.909105 -1.760342 -53.622943 -40.794615 14.906659 36.216178 -14.695860 2.225291 2.473062 2.006004 2.408777 1.572814 0.540672 0.819709 1.596128 0.872355 2.165978 2.341587 1.794916 0.647755 0.570854 1.841632
+1 0.015095 1 1 -0.229294 0.986805 2.330751 -1.154454 -2.007383 -2.092530 -0.587741 -1.000904 1.033436 -0.909132 -2.208518 0.920387 -58.175912 -62.553811 8.095823 16.499301 -46.240340 1.203974 2.433676 1.535617 0.859012 0.658227 1.065215 1.325482 1.624329 2.353292 0.525127 0.561108 2.297032 2.220396 1.190118 1.314627
+1 -0.042362 1 1 1.238817 1.468856 -1.145946 -0.375295 2.306769 1.039609 -0.827835 2.254743 -1.573063 -1.958518 -0.782239 0.482449 -47.556816 62.599658 12.455623 -58.337436 72.721310 1.780906 1.434923 0.492243 1.370865 1.623639 2.000891 1.976881 1.183285 1.213384 0.843729 0.310887 2.073682 1.374029 0.802814 1.151603
+1 0.001283 1 1 -0.669387 -1.920931 -0.512699 2.034318 -2.312981 -1.769566 -1.216169 2.187719 -1.776264 -0.686078 0.298861 -0.452616 -42.179225 -6.234922 59.662114 -8.856932 -58.453717 2.400757 1.765921 1.575091 0.554075 1.084186 0.657032 1.243396 1.252498 1.240815 0.628956 1.857370 1.823484 1.542504 1.862926 0.705853
+1 0.030089 1 1 -0.829330 0.705629 -1.583784 1.622343 0.835654 1.914216 0.757368 0.926143 0.669763 -1.194411 0.317815 -2.335440 -71.880198 9.513178 -12.024093 -38.922735 -24.414314 2.404409 2.406503 1.594278 1.277041 1.980515 1.511425 1.513877 2.229925 1.591312 0.927614 1.660613 2.426833 1.284589 0.582182 0.984949
+1 0.049791 1 1 0.715386 2.182060 2.070249 -1.604484 -2.270461 1.291567 2.105430 0.638461 0.509704 -0.522280 1.216474 -1.771192 -8.622203 -13.360197 5.171394 65.618002 41.753988 2.264221 2.009125 0.862713 2.109965 1.436917 0.256462 0.854932 1.835238 1.101516 1.680737 0.902244 0.515741 0.303868 1.107296 2.067152
+1 0.013893 1 1 1.442477 -1.537700 -1.377174 1.082947 1.836515 0.156569 1.940870 1.042788 0.770477 -0.233168 1.849167 0.748449 57.568583 55.172536 -15.180001 19.717198 36.939393 1.230605 2.278967 2.355420 0.296405 1.675204 2.410907 1.370541 0.686723 0.751770 0.504394 0.855838 1.325692 0.648661 2.292359 2.435791
+1 -0.004984 1 1 -2.045821 2.185222 -1.329507 1.130313 1.534294 0.681380 0.855543 1.616662 -0.393905 0.552239 -1.925438 -0.859021 37.857146 -34.941951 -19.365434 25.146904 -55.983593 1.881304 1.317916 0.469764 1.571406 1.619434 1.084118 1.774488 1.574496 1.800830 1.053537 0.797989 1.047216 0.305877 1.127907 1.979158
+1 0.019711 1 1 -1.581192 -1.931231 0.744322 -1.573284 -0.966416 1.049451 -0.345356 1.263849 -1.942486 0.061426 0.374693 1.716365 -72.891502 -37.479003 -59.609891 -13.430626 21.472175 1.117754 2.346979 2.426179 1.546789 1.880670 1.915275 0.775375 1.232951 1.199233 1.509589 2.163615 0.874146 0.769393 1.940856 0.967753
+1 0.035081 1 1 2.340086 0.225792 1.418316 -2.334308 -2.079004 0.550178 1.137718 -1.250050 -1.761736 -1.561401 0.825734 0.127186 -57.547419 0.520685 51.152421 68.746188 -32.811229 0.500059 2.241756 2.435629 0.617527 1.030055 2.131133 1.703352 0.732006 1.317205 2.020723 2.300100 2.037384 1.062814 1.470918 2.469203
+1 0.017286 1 1 0.999792 -0.875745 -1.857858 -0.725316 0.569147 -0.495386 0.843933 -0.307380 -1.362844 1.610469 -0.817271 0.740177 -17.824131 -20.173869 -62.216289 -19.170949 -6.131626 1.311543 1.360516 0.942668 0.428734 0.477455 0.336643 0.715676 1.361239 1.844269 2.128188 1.697553 2.275999 1.967693 2.013453 1.597067
+1 0.002747 1 1 -0.299284 -1.940985 1.740767 -2.159605 -1.664725 -1.581737 -1.661471 1.271043 1.158304 0.732176 1.629653 1.177968 43.353734 -53.790912 -13.856793 58.885076 -18.521308 0.810667 0.385774 0.696536 1.424212 0.485701 1.671461 2.490620 2.350089 0.686606 1.029244 1.996422 1.112854 0.981042 1.875212 2.444874
+1 -0.018688 1 1 1.778905 -2.048149 0.757281 -0.547507 1.351170 0.116298 -1.017305 -1.301096 -2.032969 1.421686 -2.250885 0.443092 46.979220 -20.249255 20.770052 32.268328 -66.203642 1.605774 0.992518 1.253013 0.887965 1.278208 1.343224 0.564680 1.577981 1.870222 1.817387 0.331450 1.183865 1.972281 0.383094 0.666166
+1 0.004442 1 1 -0.598736 -2.004375 1.338438 -1.820148 1.597752 2.234319 -0.822635 0.120585 0.346051 0.996458 -0.357014 -1.470209 62.660301 -18.313960 -2.726215 -69.487634 21.335822 0.492298 2.300092 1.888110 0.959697 0.871706 0.270574 1.792317 1.962774 0.338437 1.605771 0.945237 0.850350 1.337312 2.458099 0.263151
+1 0.012185 1 1 -1.436462 -1.042735 0.120971 2.117545 1.620295 -0.596056 0.627242 0.446149 1.020791 -1.377792 0.128002 -2.232903 34.042756 56.608045 -38.586520 -73.641095 -35.883394 2.242048 0.604743 2.162162 1.209918 1.092539 1.544658 2.063608 0.805118 1.620365 0.979533 1.264289 1.411206 2.382816 1.741419 1.529586
+1 0.018614 1 1 0.599268 1.522366 -1.865021 1.404091 -1.088634 1.542312 -1.219605 0.998164 0.030714 -2.152888 -1.860970 -1.200568 15.887187 15.948353 -6.027130 -47.980262 -4.268922 0.658409 1.874379 1.934573 1.127064 1.308208 1.550120 1.608901 1.799573 2.432060 1.389935 0.389099 0.343148 2.033803 1.623382 2.180882
+1 0.031344 1 1 1.202206 -1.240122 0.164003 -0.345656 0.942032 -0.889474 -1.686278 -0.965310 0.796792 -0.923242 0.975801 1.166848 -55.445670 74.631721 35.338995 -57.507035 -70.738224 1.415130 0.846295 0.685222 0.280877 1.694831 1.530180 1.737786 1.223053 1.350101 1.393153 0.475895 1.115381 0.713148 1.624397 1.231839
+1 -0.045840 1 1 0.926805 -2.350174 -0.135505 -1.350836 0.780233 -1.198006 1.153174 -0.656094 0.025018 1.077382 -2.142742 -0.986416 -16.351878 -26.019981 -67.826007 48.308168 -34.619810 1.297837 0.489844 1.557841 0.888208 0.856776 1.328066 2.299644 1.109205 0.409805 1.846597 0.762865 2.472064 0.977200 0.293995 1.679061
+1 0.028779 1 1 -1.123906 -2.239636 0.993659 -0.272200 0.866161 0.991663 -0.834811 -1.891185 -0.076283 -0.314358 -0.828800 0.177482 -0.241027 -0.941447 -72.891809 -42.626798 -28.590042 0.432531 1.290218 0.702998 2.040907 1.772235 1.947776 0.272506 0.501490 1.548003 2.041170 1.687387 2.412504 1.197758 1.469613 0.791783
+1 -0.003451 1 1 -1.672225 -0.390094 -1.383136 -0.156563 -1.848704 2.316827 0.443906 1.018628 -0.033360 0.095100 0.851554 0.542446 -50.562271 -50.085154 18.814354 12.853400 27.095496 1.284914 1.555004 0.446558 0.794292 1.914435 2.413627 2.085421 0.664869 2.445430 1.092727 2.463140 1.742524 2.102993 1.250324 0.697298
+1 0.070700 1 1 -0.278592 1.818679 1.985043 -1.103040 -0.259224 2.181785 2.156962 -0.343752 -0.059033 2.154660 -1.346162 -0.770862 -48.253835 47.797444 -68.350344 -64.238011 51.743357 0.634108 0.697381 2.126965 1.404631 2.134512 2.238513 1.938413 0.405030 0.340910 0.423213 2.188890 0.421113 0.637922 1.807319 2.114674
+1 -0.004412 1 1 -2.198987 0.898895 -0.187520 0.937859 -0.352210 -0.834193 -0.922778 -0.666039 -2.188872 1.253023 -0.111992 -2.012486 53.212710 46.009045 24.025759 0.937115 0.085443 0.415676 1.509389 1.048736 1.103089 1.122662 1.579824 1.355741 1.692105 0.713448 2.176866 0.831730 1.138951 0.853024 1.274212 1.672414
+1 0.066791 1 1 -2.140643 1.304766 -2.258616 -2.266637 -0.422154 1.716534 0.534643 -0.778861 0.694661 -2.129453 0.883853 1.474374 65.701903 -48.110756 52.527663 -67.565475 -72.940365 1.994172 1.554617 0.691248 0.308636 2.498206 1.589372 2.076615 1.163356 1.522254 1.274607 1.573423 1.768647 2.392175 1.534196 1.727748
+1 0.006943 1 1 0.840463 -2.083195 0.799070 -0.337955 -1.575152 0.614232 -1.446440 0.905611 -0.406410 -2.282190 2.083256 0.228063 59.867399 -8.627871 41.374497 -18.824111 -26.825619 2.002310 1.074986 1.291349 1.709700 1.675920 0.932833 1.620383 1.282238 1.567090 1.086055 0.573294 2.346244 1.323516 2.325789 1.782042
+1 0.013264 1 1 0.517338 0.535443 -1.466598 1.393404 -1.639103 0.228402 -1.852565 -1.308115 -2.198114 1.433576 -0.337064 -0.747011 -38.281486 -46.940345 73.621171 1.012619 69.086608 1.204406 0.700043 1.867520 1.414686 2.382598 0.325297 1.270411 0.795359 1.843358 0.315413 1.642593 1.054496 1.162939 1.265079 1.178287
+1 0.001582 1 1 1.798367 -0.110709 0.710369 -2.029485 -1.284641 1.196883 -1.170926 -0.816205 -0.199832 1.360861 -1.941542 1.802665 45.977582 -54.780098 10.898088 14.159627 -69.148660 1.652134 1.661719 0.758199 0.551198 2.238138 2.378162 2.268553 0.565027 0.650858 0.971134 1.844140 2.219477 1.504254 2.499103 0.930393
+1 -0.041873 1 1 1.266635 -2.233281 -0.571635 1.088966 -0.667761 1.848118 1.960454 0.317459 1.105449 -1.667195 -0.680939 1.859438 -31.648168 -10.767696 -72.663143 50.549785 -9.764067 1.304776 2.366231 1.990783 0.846884 1.576612 1.373457 2.442610 0.948675 2.375050 1.721270 0.388243 1.700742 1.875421 1.454361 0.943667
+1 0.042362 1 1 -1.726538 0.969768 -1.258161 -1.424686 -1.043845 0.320853 1.608872 0.630268 -0.540262 0.593106 1.630712 0.114999 22.447573 26.360136 -65.190865 -62.861823 -68.658863 1.382407 2.108978 0.599649 2.048853 0.329130 0.441101 1.339599 0.384300 0.678043 1.123608 1.736791 2.489769 1.541979 2.038856 1.046247
+1 0.002908 1 1 1.514286 -1.013740 2.069522 0.315038 -1.882591 -1.733313 0.196193 -1.251392 -0.746300 1.310145 -1.381707 0.310502 63.420246 4.082358 62.197784 8.152599 70.738374 1.372712 1.171795 1.605412 1.657174 0.867953 2.442226 1.234694 1.257569 0.967846 0.580672 0.352525 2.142632 1.462042 1.790401 1.268532
+1 -0.076533 1 1 -0.274768 0.119858 2.261848 0.039805 -0.159269 -0.192284 0.976431 2.339685 -1.794611 1.979494 -0.117569 -1.489169 -30.941151 22.075666 -74.277285 71.664009 -43.006066 2.080617 0.936776 0.386232 1.655601 1.441102 0.856425 2.190544 1.229486 1.471392 1.436351 2.002019 0.687904 0.347997 0.283519 1.104842
+1 0.001602 1 1 -1.257067 -1.881702 -0.919038 0.932446 -1.786685 -1.471153 0.238135 1.522157 -0.663435 -0.842148 2.033627 0.213379 4.434134 -25.501086 -46.745039 56.122529 51.349358 0.304873 2.258467 2.058136 1.095160 0.603732 0.920760 1.219774 2.496912 2.354334 2.283468 1.503697 2.129795 1.710584 0.779056 2.339265
+1 0.028738 1 1 1.125647 -1.494414 0.426044 -2.314976 -2.324470 -1.657857 0.749909 -1.925547 2.017879 -0.566709 -0.935981 -1.078517 61.166175 69.898631 -13.715398 35.310057 56.122073 2.030304 1.323801 0.377607 0.686961 0.258703 0.273861 0.785288 1.332259 0.769720 0.688137 2.017834 0.984711 0.530463 2.493212 0.904849
+1 -0.020374 1 1 2.018656 -1.648924 0.101196 -0.373877 -2.135314 1.327108 0.968413 -0.469026 0.900845 -0.396789 -0.802150 0.415141 -56.411377 43.983531 31.200157 -18.955168 20.495972 0.262071 0.627752 1.879215 2.217413 0.564876 0.372880 2.246146 1.969130 1.422327 0.307624 1.234986 1.654759 0.792252 1.371126 1.520249
+1 0.013073 1 1 -1.250029 -1.415609 0.710638 -2.209286 2.160526 -1.711193 -0.304256 -0.684525 -1.867634 -0.103544 -1.395029 -2.110104 29.106382 40.967805 45.892249 11.025605 57.337281 2.390187 1.874030 0.571459 0.757498 2.275592 1.877102 0.448953 0.548835 0.766629 0.485874 2.335787 1.078520 2.181829 0.997518 2.030549
+1 -0.000973 1 1 2.175900 2.215771 -1.556117 0.094489 0.000761 -1.346485 -1.479337 -0.661652 0.855664 -1.074469 -0.730938 0.315125 -13.216581 18.923460 46.588153 7.086794 7.755761 1.391128 2.434611 1.501856 0.450026 0.595300 0.951570 1.540479 1.577084 0.293976 1.347460 2.013994 1.703398 1.515357 2.348843 2.251929
+1 -0.034456 1 1 -1.619996 0.918094 2.038888 -0.896153 -0.849928 -1.488552 -0.016178 1.409820 0.948248 -0.101355 -2.304340 2.083010 25.663764 -69.117556 -58.757387 64.596284 -30.260854 2.212477 0.847387 1.031556 0.369055 0.956257 1.565943 2.063135 1.864648 0.392809 1.937346 0.472093 2.460239 2.490511 0.511745 0.644011
+1 0.024426 1 1 -0.137468 -1.346994 -0.615759 -0.653638 -1.119046 -0.668137 0.251181 -0.697480 1.875922 -1.976541 -2.089452 -0.703948 49.643291 54.795509 -51.873049 -30.331236 72.914422 0.965247 1.901801 1.568236 2.345626 2.194241 0.364802 1.481885 2.294962 1.168952 1.074306 1.117771 0.385490 0.435201 1.181386 0.809133
+1 0.040482 1 1 1.793325 -0.030086 -1.426643 -0.957758 0.476498 2.152620 2.079864 -0.218011 2.133957 -0.570650 -1.199260 -1.081378 30.976371 -30.133314 -50.616068 -54.263247 -2.388489 2.224927 0.849241 0.698293 1.718373 1.190589 2.488086 0.264775 1.065725 0.885994 1.900267 0.538229 0.259363 2.363267 1.676135 2.298028
+1 0.049389 1 1 -1.186724 2.277793 -0.586751 1.512436 0.894890 -1.531188 -0.327761 0.102188 2.163621 -1.532831 0.335063 0.096364 -46.592583 68.460955 -26.734367 -74.505227 -9.345700 1.027201 1.418880 0.873190 0.447656 1.258890 0.670130 0.877077 0.533328 1.135942 2.029290 2.276631 1.332069 2.086710 2.092201 2.127580
+1 0.041957 1 1 0.745404 -2.234952 -0.385386 2.349369 0.737826 2.341404 -1.185412 0.752146 -2.015181 -1.199985 0.872149 -2.042075 -26.202182 19.924275 67.289801 -60.312890 21.260144 1.663556 2.392623 2.319422 0.527288 0.872746 1.990404 1.220334 0.650647 1.925988 0.830325 2.276459 0.690071 0.776120 0.252445 0.845494
+1 0.042004 1 1 -1.640645 -2.124495 -0.612406 -0.848702 0.263413 2.256633 1.930807 1.556579 -1.761297 1.115187 1.774061 1.349984 -30.850349 48.177757 23.567912 -44.095103 43.603333 0.493354 2.056407 1.289746 1.769290 1.961999 0.823046 1.429293 0.382432 0.789922 0.464877 0.444709 1.231344 1.203495 1.139275 1.802002
+1 -0.013802 1 1 -0.778722 -1.681729 0.094622 2.229252 -1.161237 1.800430 1.579425 0.514267 0.762772 2.209075 -0.996559 -1.329291 1.455109 6.017690 39.316670 45.266785 -1.143838 1.007742 0.611941 1.643389 0.944508 2.092953 1.260038 1.965255 1.541312 2.077963 1.327199 1.226830 1.840385 2.093601 0.900529 0.941679
+1 -0.000275 1 1 -1.683651 0.776704 0.738654 2.125152 2.242197 -0.367072 -0.864437 -0.302913 -1.678976 -0.757205 1.818459 -1.710644 -16.450663 -36.288738 -4.819564 -2.410578 -14.575760 1.002986 1.688683 1.687058 1.375197 2.430544 0.658758 0.994432 1.912388 1.753797 0.324568 0.258224 1.216958 2.420057 2.149693 0.889511
+1 -0.000387 1 1 0.326060 -0.422351 -1.588253 1.917342 1.454312 -0.541734 -0.592473 -0.415867 -1.008702 1.919489 -0.159166 1.526144 11.835880 25.631851 -5.487207 26.508235 23.906832 0.656882 0.961773 2.013786 0.442626 2.215507 2.274399 2.079125 0.605841 0.366935 1.319920 0.393506 2.407324 1.895415 2.235720 2.239753
+1 0.011128 1 1 -0.528873 -1.195024 -0.571740 -0.672244 1.897970 1.016117 0.177286 1.417069 0.271432 0.365717 1.648446 1.291292 69.668918 25.501037 45.922097 62.679047 -3.248987 1.289206 1.684408 1.838487 1.703719 2.406893 1.408983 1.035856 0.624436 2.396194 1.576439 0.717442 1.797841 0.319786 0.900578 1.768771
+1 0.006051 1 1 -2.246738 -0.554888 -0.177529 -0.780868 -0.040332 0.732152 1.233036 -1.448594 -2.311945 1.497952 -2.220712 -1.387905 -6.191724 35.703042 61.019317 1.658599 -23.920381 0.927454 1.218463 0.716548 0.265636 2.045878 2.063172 2.477259 0.546060 1.382842 0.425831 1.198940 1.075560 1.940840 0.699440 0.735499
+1 -0.006839 1 1 0.878482 0.731600 1.385736 1.429894 -0.953042 -0.363755 -1.655644 0.246361 -1.602505 -2.002712 1.011230 -1.843202 17.585607 61.298179 38.493527 10.700284 -10.330594 2.480565 2.103552 1.644303 0.557099 2.418819 1.598319 1.692761 0.486344 1.226705 1.974571 0.608919 0.346404 0.515751 0.482990 1.112653
+1 0.031850 1 1 -1.793332 -0.088449 -2.166323 -1.471504 -0.954919 1.080545 -0.830256 -0.731048 -1.527002 -0.648202 0.714037 -1.631437 58.390655 71.739954 33.401583 -69.591008 -66.074718 0.358302 2.481325 1.381428 1.411987 2.009586 1.865044 0.300633 0.732764 0.558137 1.864278 0.917664 0.925661 0.337384 1.914081 0.966886
+1 0.001129 1 1 0.984532 1.836966 -1.688927 1.640351 1.904912 -0.112336 1.636043 0.178648 0.738762 -0.776790 -2.194601 -0.792784 73.933004 -8.004422 19.681197 31.872220 26.396307 0.516076 1.442270 2.481003 0.470856 1.919061 1.404614 1.853942 0.457461 1.804316 1.141788 1.285024 1.150602 0.924682 1.880161 2.371245
+1 -0.027988 1 1 -0.631722 -0.337952 -1.527908 -1.742403 -1.774338 -1.305352 1.831179 0.011413 -1.384340 -1.535773 -1.989515 1.338698 -68.701313 37.031782 43.165636 -65.148292 52.652247 0.269732 1.130012 1.364017 1.282592 0.776422 0.831187 1.017740 2.163984 0.323881 2.210764 1.313985 1.891595 1.039971 2.288851 1.973236
+1 0.038858 1 1 1.819060 -1.030721 -0.581509 0.072857 -0.714802 -1.804043 -1.043244 1.002326 -0.696154 0.596382 0.137145 0.637707 62.718317 56.747559 56.223842 -45.892918 -22.273271 2.171957 1.586981 2.390414 1.182012 2.334582 1.071855 0.416481 1.538603 1.542734 1.233211 1.075539 1.586505 1.141851 2.332339 1.622990
+1 0.000782 1 1 1.584310 -2.220785 2.102325 0.280379 -0.052527 -1.608226 0.802727 -0.136592 -0.770011 -1.359804 0.862640 -1.631600 -29.051412 -17.082523 -5.961971 -2.852456 58.773486 2.214566 2.215288 0.844947 0.528212 0.658789 1.522500 0.911567 1.961702 0.324919 1.662034 1.550137 1.911447 1.688734 0.305902 1.542747
+1 -0.003820 1 1 -2.018684 1.183892 1.972393 -1.640705 1.572121 0.265225 -0.291622 -0.405432 0.017057 -0.773680 -1.755381 1.574924 8.256066 9.709100 -19.161403 4.291726 -18.956637 1.312115 1.972781 2.022919 0.951598 2.003657 1.213577 1.839252 1.064905 0.611447 2.341224 2.448072 0.500800 1.201995 0.676412 0.700210
+1 0.015037 1 1 -1.039010 1.477849 -0.798026 -0.964703 1.558850 -1.295873 0.930742 -2.158739 -1.242937 -0.021482 1.800101 0.759643 46.405735 -58.810403 73.551230 25.521696 -56.848900 1.983004 0.595877 1.649363 2.348563 2.043810 1.063482 1.437956 1.978299 0.272392 0.835877 1.082826 0.310088 2.146497 1.172406 0.621476
+1 -0.040249 1 1 0.674855 -0.425261 1.334110 0.844485 -0.448794 1.651809 1.265806 -2.033036 0.301281 -2.187107 -2.073714 -0.090303 -10.635057 56.601833 7.008932 49.111296 -36.442008 0.912675 0.331386 2.350539 1.511647 0.744396 0.314905 2.113091 2.214159 2.125190 0.817328 2.083115 2.407841 1.579579 1.742941 2.360978
+1 0.004208 1 1 -1.405253 0.397990 2.136291 0.954768 1.102405 -0.996558 -1.320808 1.241206 -0.804207 -1.170362 -0.762261 1.663413 -51.444638 -30.037864 53.618624 -31.794569 -71.314797 2.308011 2.239822 1.432379 0.494359 0.947049 2.046637 1.324196 0.261200 1.741387 0.990670 1.697091 1.265074 1.098534 1.062962 1.697547
+1 -0.022591 1 1 -0.873089 0.367516 -1.093287 -1.267544 1.094417 1.418399 -0.942165 -1.339681 -0.231622 -0.433724 0.469551 -1.514777 69.268296 42.254076 64.263126 70.364042 8.458536 0.814328 1.166262 0.868108 0.536820 1.326451 2.156181 1.930256 0.558835 2.342497 1.350277 2.103546 1.545216 2.440048 0.638736 1.993661
+1 0.002960 1 1 0.037256 -0.589244 2.018535 1.035090 -1.384490 0.655733 -1.381123 0.702607 -0.526968 -2.164556 -0.049636 -0.131614 -61.516860 36.125682 -35.656026 -20.832293 -28.340061 0.453913 0.667165 0.545964 2.011850 1.667805 1.791310 0.804224 2.340203 1.036987 1.639872 0.327378 2.492577 1.493596 1.125810 0.493838
+1 -0.047334 1 1 -0.949091 0.060325 0.725824 -1.447884 0.195058 -1.478885 2.232718 0.534656 -0.561227 1.658287 1.767723 -1.498596 25.850980 -72.574318 43.431286 49.631799 11.648151 1.682147 2.097131 1.725643 1.875890 0.331191 1.321699 1.051264 0.844774 2.124099 0.477703 2.255705 0.639077 0.971642 1.382306 0.422145
+1 0.025922 1 1 2.024500 2.327893 -2.071878 -2.212842 -1.064892 0.013586 2.143090 2.122821 0.757201 -1.889234 -0.273344 0.485648 13.848264 -52.229725 -24.991207 -27.217017 63.592171 2.029261 1.792691 1.508708 0.859415 0.690619 0.981838 1.753637 2.133193 0.320179 0.752933 2.040116 1.971872 0.250241 2.047610 1.937121
+1 0.015954 1 1 1.995946 -1.638499 0.956529 -2.294775 -2.092531 -0.613964 1.245174 -0.075785 -1.381519 -1.254287 -2.283950 0.770186 -13.475865 11.134141 -68.498051 3.263095 -57.157844 0.596863 2.478883 0.833761 1.520342 0.643988 0.260309 0.255142 1.172422 0.901939 2.146462 0.581648 1.004613 2.034635 2.110315 0.563767
+1 0.008804 1 1 -1.473684 0.107006 -1.682984 -2.160215 2.229031 -0.167512 -2.080885 1.913856 -0.589147 -1.064603 0.155424 1.540553 70.106792 34.859494 -16.483033 19.670986 10.259899 0.446855 1.297244 1.774741 1.326603 2.471702 1.642014 0.322576 0.534330 2.231345 0.714880 1.493873 1.268845 1.477228 0.514742 1.512596
+1 -0.000813 1 1 1.096658 1.373834 -0.676739 1.747116 0.879281 0.017494 1.851127 0.705365 -1.301455 1.358279 1.777701 1.270757 33.854260 38.548553 35.537643 -18.828389 51.264918 1.517041 1.416073 0.942193 1.429889 1.392421 1.673259 1.216807 2.132641 2.290132 1.004482 2.079771 2.455795 2.043385 0.663054 1.206846
+1 0.007146 1 1 1.505490 1.948179 1.373670 1.270468 0.912062 -0.367791 1.184795 -1.713287 2.194696 -2.324728 -1.285428 2.120178 -39.735462 -33.910022 74.261728 -33.130875 -30.612225 1.379988 1.963227 1.199577 0.538971 1.493269 2.374321 0.709312 2.407323 1.878897 1.375218 0.534721 2.052707 2.096584 1.530120 0.735551
+1 0.039062 1 1 1.867412 1.083033 -1.419337 -0.682862 -2.201370 -1.456380 -1.225186 1.440416 1.533570 -2.058895 -0.769315 0.915882 -68.048055 66.334510 -65.898505 43.827829 -35.682583 1.117325 1.877312 1.730258 0.688072 0.921635 2.427299 2.359911 1.527146 2.494932 0.580957 0.644641 2.223578 0.684342 1.236116 0.395877
+1 0.004036 1 1 -2.001661 -0.165554 -2.149453 -0.690113 -1.545097 1.532859 0.136828 0.026154 1.322837 -0.131798 -0.306155 0.374591 -0.274630 34.294443 -63.298459 -57.205439 48.185138 1.339191 0.283478 0.410770 2.310318 0.520499 1.522541 1.594528 0.975246 1.217755 2.307146 1.200343 2.165883 0.740124 0.506555 1.164306
+1 0.000261 1 1 0.026972 0.931032 -1.981459 0.076306 0.702419 1.020155 2.080696 -0.385026 -1.021889 1.764808 1.355427 0.966752 -3.651368 -18.550239 -73.870978 0.466242 36.123459 0.279655 1.404973 1.135737 0.828090 0.709540 1.736437 1.044048 1.073944 1.780965 2.435749 0.380168 0.984960 2.479197 1.609252 0.953929
+1 -0.041292 1 1 2.207551 1.673840 -0.732118 -0.659464 -0.079723 -1.580626 -1.842655 0.317266 -2.130997 -1.511972 2.196239 0.051403 49.929051 57.566749 24.349164 36.395176 -6.283735 1.213897 0.473288 2.296076 1.897673 1.934391 0.310733 1.743387 0.851811 1.145127 1.142983 1.122393 1.556286 1.757070 1.327647 2.014311
+1 -0.015631 1 1 2.146163 1.933074 1.968304 0.320825 1.134437 0.149101 -1.043850 0.238277 -0.809090 1.571255 -0.152175 1.225299 14.464433 -46.273830 25.732413 34.662236 -31.799966 1.194482 0.405289 2.436734 1.193329 1.273297 2.051704 0.996321 2.159564 0.287404 1.149818 1.238076 1.834377 2.369708 1.933317 0.264726
+1 0.006768 1 1 -0.435394 0.664835 0.814198 -0.549618 -1.151450 1.361035 0.972344 -0.376506 0.809651 -1.581372 -0.251890 -1.782268 66.007021 -19.991868 -3.320561 -8.671690 54.900628 2.347767 2.175810 1.083497 0.332965 1.894827 1.354842 2.335307 2.002881 1.665133 1.895811 2.141923 0.806849 1.459553 0.465299 0.787818
+1 0.015152 1 1 0.077008 -1.639426 -0.494974 -1.663980 1.511673 2.198574 1.599355 0.899489 0.361108 -0.420510 1.072998 -0.429045 -32.091631 35.962111 65.206941 33.054699 -49.665955 1.589297 0.820488 1.197012 2.434746 1.522421 1.831394 1.733460 0.516556 0.506287 1.164083 2.498659 2.462240 2.369191 2.235963 1.833447
+1 -0.002418 1 1 1.462553 1.302130 0.565527 -0.075342 1.359168 -2.131183 0.079482 2.240026 0.835664 2.080033 -2.098832 1.875824 34.968180 10.205640 -73.808380 2.549800 -45.515142 1.780139 2.047974 1.298175 1.674805 2.449851 1.137973 2.412178 2.474197 0.827684 0.636276 1.146600 1.155999 1.629429 0.320372 1.748332
+1 0.015423 1 1 -2.073670 0.657826 0.815866 -0.794950 -1.109050 -2.305209 1.621759 0.445614 1.446482 -0.183004 1.442585 0.279791 -16.506871 69.012925 -49.766740 -29.597306 -41.914857 0.429941 0.512682 0.649150 1.506214 1.692710 1.875864 2.140165 0.502915 0.746852 1.086528 1.774312 0.853855 1.732776 0.263701 1.020052
+1 -0.025748 1 1 1.657712 1.512741 1.291722 -0.002467 0.954478 0.944413 1.427076 -1.189017 1.427480 0.877782 -1.609881 1.259903 -72.739232 -28.264473 8.998247 33.541562 33.028505 0.776177 1.207311 2.277759 2.290909 0.552380 1.848452 0.425305 1.357136 0.384210 1.417215 2.141488 2.479677 0.677689 1.922975 1.945909
+1 0.006406 1 1 -1.548603 -0.847064 -0.476713 -1.051314 2.029750 1.027096 0.921005 -0.870161 -2.249510 -0.014078 -0.983321 -0.324210 -47.008035 -14.048431 -11.984798 21.492912 31.377686 0.846583 1.019635 0.257799 0.836095 0.250533 2.455665 2.118861 2.447655 2.479397 0.469976 0.628420 1.860305 1.652608 0.631596 1.238994
+1 -0.031697 1 1 0.441095 0.901851 -2.341285 -1.535334 0.678701 -1.761285 1.315081 1.466868 -1.567709 -1.517172 -0.378820 -0.396268 -46.822121 -39.381853 59.201568 50.751562 -68.494568 2.301948 1.584395 1.679934 0.893933 0.326290 2.206661 2.094258 0.698570 1.872431 0.694953 1.832503 2.372162 0.429001 0.476833 1.128162
+1 -0.050502 1 1 -0.405126 0.457520 -1.086544 -1.033463 0.452583 0.765211 0.784162 -1.141075 1.373159 2.121802 -2.239796 -1.687323 9.870585 -5.082200 -66.540364 56.108751 -30.218038 1.756433 1.870963 0.768611 2.290701 1.559217 1.508625 1.712837 0.397129 0.301218 1.566184 1.600321 1.593435 0.614631 1.855998 1.254908
+1 0.039839 1 1 0.937004 -0.571264 -2.096523 -1.733839 0.786780 0.440322 2.035699 2.054467 1.753545 0.542452 -1.485600 -2.238431 -73.699105 39.136090 10.269267 -54.430112 43.115438 1.242372 2.049063 1.596030 1.485039 1.303009 1.930157 1.144067 1.327852 0.964278 1.372697 0.911036 2.029387 1.649049 1.562858 1.953409
+1 0.020048 1 1 -0.692088 -1.748968 0.981220 -2.000976 1.912414 -1.257840 -0.745088 -1.870273 -2.044271 -0.043823 -1.395543 -1.327037 7.312736 55.148084 23.840522 37.655555 26.919489 1.912729 0.732676 1.340875 1.587255 2.487576 0.689541 0.867208 1.157446 1.195133 2.350897 0.768031 1.544711 0.708549 0.835423 2.461156
+1 -0.012939 1 1 -1.967667 0.962950 1.949710 -1.170154 -1.976534 -1.976117 0.312152 1.442511 -0.955867 -0.716753 -1.605175 0.255420 -4.625644 -43.201668 59.572797 -10.008949 -70.407204 1.616947 2.022100 0.692072 0.648514 2.068935 0.344956 0.917154 1.349142 1.033785 1.827359 1.428468 2.257354 1.345105 0.685456 1.960540
+1 -0.020440 1 1 -0.416535 1.908559 -0.087559 -1.342533 -1.033313 -1.743865 1.918952 0.236910 -0.223575 -1.852934 1.922811 -0.874952 65.279122 46.202589 -23.085907 45.167967 -11.980789 0.458187 0.496964 1.974056 0.966136 1.095238 1.907668 1.168567 1.361295 0.528092 0.888224 1.135584 0.513115 1.172543 0.676167 1.093063
+1 0.036440 1 1 1.249557 -1.816774 1.760028 1.117466 -2.327668 1.145793 -2.198217 -0.305506 1.864271 0.132497 -2.090089 -1.975662 -46.599647 -50.262328 41.057727 57.218937 28.680567 0.389356 2.405567 1.617754 2.095373 1.428048 1.958797 0.992730 0.314799 0.334002 1.327043 0.862250 1.084002 2.067898 0.910344 1.659183
+1 0.007385 1 1 -2.202223 -1.662156 -0.821198 0.713783 -1.188565 -0.390060 -0.809860 -1.931349 -1.240202 -1.181412 2.017553 -1.330063 38.165288 44.000988 24.605654 -2.777243 -27.118395 2.441919 0.589230 2.442795 1.798657 0.519476 2.333562 1.932922 0.373261 1.904850 1.068098 0.274263 0.783976 1.781397 0.683556 1.520207
+1 0.000973 1 1 -1.488226 0.752819 -0.134784 1.350713 1.864686 -2.314268 0.151443 0.613233 0.607409 1.683761 1.072578 1.936914 16.664120 23.865884 13.907018 35.244024 -3.686045 1.354577 2.367397 1.341923 1.204404 0.667148 0.264197 0.355517 0.676094 2.104598 1.234951 1.066837 1.574953 0.482619 1.628351 2.445264
+1 -0.054591 1 1 0.179249 1.416546 0.905907 -0.157544 0.520734 1.063245 0.578648 -1.033616 -2.114991 -1.109071 2.050284 2.134581 15.278898 -7.556025 55.891338 65.711983 -28.706645 0.286200 1.169725 0.576402 0.594432 2.113754 2.113718 1.515477 2.115604 1.711480 2.339383 0.761331 1.435347 0.880167 0.720358 1.312569
+1 0.030877 1 1 1.783547 0.571954 -0.434816 0.967246 -1.233469 -1.108943 -0.502581 -2.277879 -0.867574 -1.180684 0.119828 1.763735 68.862028 -35.891915 64.577137 -52.065505 35.058915 1.902817 0.639690 2.270036 0.748906 1.858001 1.171712 2.470420 0.355379 0.611012 1.786292 1.963718 0.449901 0.729098 1.955768 1.833891
+1 -0.003552 1 1 -0.241772 -1.382445 2.032895 2.052870 -1.532143 -2.240533 0.058563 -0.621066 -0.309311 -0.817959 -1.390789 -1.544887 10.848819 -63.901546 6.714641 52.966059 -49.443441 1.436392 0.434944 1.359528 2.340609 1.114706 0.607595 0.593757 2.023680 2.481939 0.455744 2.181740 1.760269 1.088899 1.123593 1.482072
+1 0.052128 1 1 -2.122845 -1.166653 0.322251 1.544337 -0.173521 0.592859 2.183304 -0.578310 2.004462 0.128905 -1.184287 0.821347 57.001712 -22.218558 72.689745 -53.450049 15.025548 0.390768 1.382978 0.465819 0.524212 0.937229 1.260791 1.110339 1.474459 1.236047 1.491973 0.834235 0.495133 0.447630 0.820735 0.842830
+1 -0.014943 1 1 -1.926195 0.561981 1.594706 -1.847190 -0.509356 1.658095 -1.465921 -1.358114 0.984420 -0.047574 1.525401 2.013791 44.969083 -54.620360 -4.398595 22.816631 -70.879865 1.706683 0.467562 0.570874 2.173990 2.003608 0.397385 2.342171 0.374867 1.885814 0.627952 0.741928 1.585387 0.347834 2.052488 0.664825
+1 -0.010436 1 1 -1.468953 -0.481940 0.627734 -0.720185 1.984930 1.708618 -0.556046 -0.794042 0.027674 -1.404580 2.299114 -0.382424 9.513336 -9.367432 61.579450 -34.187695 57.414566 1.624084 0.479715 2.316466 0.339937 2.068899 1.986430 1.926628 0.329624 1.995415 2.193157 2.390113 0.635548 2.407059 1.932189 1.550128
+1 0.011749 1 1 -2.016149 1.372999 -0.583818 -1.031897 -1.508449 0.157751 -1.749169 2.316277 0.631310 -1.865860 1.441507 1.012639 -54.811961 -74.623968 -55.032295 -27.781718 22.671174 1.891392 2.123796 2.136247 2.150322 2.463315 2.440344 1.106857 1.445041 1.801450 2.462694 1.003135 1.937394 1.276487 1.664105 0.355526
+1 -0.029189 1 1 0.957469 -0.619958 -0.549467 1.390640 -0.971017 -0.874710 1.403096 1.032891 -0.639667 -1.928266 -1.271730 1.429795 66.593909 -56.166290 -36.830061 47.162351 57.630505 2.063577 0.285255 1.038557 1.023809 0.658601 0.613844 2.128344 2.076309 0.530201 0.333536 2.483689 0.604222 2.409356 2.300526 2.434835
+1 0.015441 1 1 -0.812613 -1.090254 -2.137080 -0.071931 2.133223 1.223219 -1.514688 -1.030636 0.849912 1.225665 1.894754 -1.196521 -68.904713 68.495995 -37.812602 33.592085 -17.819040 2.356006 1.151696 1.299737 0.929138 0.265302 0.935104 1.550741 0.799244 1.899921 1.470546 0.716658 2.119546 0.467133 2.351893 1.770509
+1 0.010007 1 1 2.141020 0.327097 -1.839671 -1.373570 0.401860 1.205994 1.158198 -1.035968 0.759562 0.092438 -1.487229 -1.345397 -65.053434 -3.063507 -38.359723 -11.865471 -72.971007 1.019188 1.739866 2.419298 0.645184 2.360778 0.355083 2.388120 0.879746 0.391883 2.124114 0.727720 1.296116 0.828897 0.779431 1.898089
+1 -0.042292 1 1 0.018513 0.132969 1.138053 -0.331685 0.124477 -0.209130 0.591252 -1.262004 -0.041639 2.324184 1.568280 1.685964 12.668001 61.097404 -35.937931 41.196458 -11.137785 1.483810 0.887597 1.840747 1.435989 0.419598 2.182208 0.620845 0.545830 2.007750 0.259059 1.757846 0.874453 1.433470 0.835375 1.655300
+1 0.001009 1 1 -0.469112 -0.537952 1.713461 0.730180 1.079840 1.453575 1.213188 -0.455060 0.015540 2.003969 1.254007 2.284768 -37.111730 -36.851495 -13.084644 -13.603946 -41.514985 2.239644 0.698636 0.732048 2.023903 1.738379 2.193879 1.018346 1.096051 2.078566 2.456913 0.592366 1.153632 2.346588 0.349323 2.325558
+1 -0.013431 1 1 2.006762 1.086284 1.376499 1.692323 -1.112660 -1.719238 1.140365 0.828833 0.376838 0.068625 -1.157981 -0.012119 -33.636456 22.075618 74.918555 56.156277 18.547078 1.686102 1.059271 0.415386 1.148087 1.390857 2.390840 1.595119 1.906909 1.920909 0.961011 0.467754 1.540159 0.697574 0.874531 0.490012
+1 0.019718 1 1 1.370278 0.812039 0.858175 -1.269551 0.345447 0.261176 2.355008 1.258386 0.487462 -2.068537 2.112555 -2.145360 68.016266 -0.612173 61.214898 -11.214658 65.249151 1.262210 2.455944 2.306201 1.066463 2.035446 2.237049 2.084374 1.075084 0.687734 1.992080 2.395017 2.044522 1.784323 0.357771 0.298974
+1 0.012283 1 1 0.420584 0.178776 -1.813735 1.009322 -0.921837 1.027735 2.230744 0.341296 1.188050 1.158117 2.312307 -0.127169 66.834581 -61.204385 37.903161 -11.567141 -8.946496 0.418718 0.890652 1.436615 1.938673 0.269820 0.359971 1.278217 1.493414 0.307719 0.583015 1.480916 1.753865 1.462976 1.731812 2.055914
+1 -0.074715 1 1 0.136528 -0.312037 0.477803 0.529645 0.047198 1.581938 0.331355 -0.953074 -0.909076 -1.267982 -1.545732 0.278442 11.795836 -47.390904 1.074762 63.530065 49.799674 1.121794 0.496639 1.016467 1.009948 1.691293 0.555898 2.476217 1.035535 1.991211 1.279184 1.995365 1.344563 0.576589 1.489476 1.619879
+1 0.010359 1 1 -1.539169 2.200236 1.250462 -0.745661 -2.078711 0.749292 1.846097 0.974044 -0.087102 1.636146 1.922598 0.247967 58.263799 39.664396 39.503156 29.545710 74.753926 1.213472 2.325238 1.519569 1.144358 1.718052 0.292555 2.218697 1.889529 2.312134 1.785937 0.494436 2.237355 0.471386 1.829048 0.553175
+1 -0.064458 1 1 -1.747226 1.986629 2.004587 2.220089 0.343119 -1.170232 1.419096 1.352478 -1.463563 0.567609 1.924924 1.640245 3.815796 -67.917687 7.437718 55.728766 33.371903 1.848719 0.418449 0.878807 0.355399 0.948566 0.543979 2.410165 2.394753 2.113240 2.470214 1.379949 1.302930 0.586582 0.690247 1.484276
+1 -0.031607 1 1 -2.042916 -0.819754 1.417919 0.413700 2.279889 1.657076 0.264593 -1.483748 0.616813 -0.473504 1.047768 -0.363501 -67.013851 48.205617 41.802367 -27.613631 -2.301447 1.668795 0.432304 1.985864 1.407640 0.949617 2.465682 1.723890 1.666307 1.372294 0.892890 0.794423 1.861481 1.161897 1.756086 0.535178
+1 -0.001113 1 1 0.510555 -0.364817 -0.669572 -0.304583 -1.467906 -1.735510 0.973324 1.947194 -1.059787 0.988900 -0.157026 -0.193072 59.832704 8.257922 40.892877 -13.421436 25.917746 1.368423 1.078402 2.451730 1.226735 2.489415 2.342121 1.770215 1.762042 1.643361 0.459547 0.853911 0.426249 1.459830 0.619446 1.771982
+1 0.015700 1 1 2.170299 2.319899 0.236825 -1.647436 1.542876 -1.162267 -1.372783 -0.516198 -0.232270 -1.910422 1.748276 1.525815 -14.415913 -38.241581 23.755630 -39.125214 22.528501 1.922643 0.863998 1.216685 2.319373 1.950160 2.084490 0.780829 0.645804 1.528353 0.279121 1.431822 2.378573 2.419244 1.991086 1.431261
+1 -0.039439 1 1 1.799820 0.746556 -1.716948 1.928349 -2.044053 -1.085972 -0.855857 -2.178831 0.354749 1.093520 0.477475 -0.268303 12.094069 15.017071 -58.086712 -63.363473 50.102712 1.019189 1.765381 1.515372 0.357436 1.424871 0.309469 0.749807 1.256956 1.910576 0.550221 1.560234 0.608765 2.256124 0.934201 2.111812
+1 0.018459 1 1 -1.210844 2.149577 -1.951450 0.203322 0.744336 -1.332562 1.611935 0.276327 -2.185963 -1.696669 -1.251607 0.345159 4.427904 19.779746 38.188269 -19.770037 -25.010817 0.522872 0.914455 0.991961 0.891593 1.508247 2.100427 0.877063 0.293665 0.620025 0.255311 1.762966 1.417342 2.009027 1.468441 1.342788
+1 -0.050082 1 1 2.001901 -0.499489 -2.146320 0.141888 0.245078 0.396397 -1.078991 -1.330412 0.057393 -1.438026 0.933343 -0.838828 41.087696 -39.087285 59.995668 47.199152 -73.847619 0.521065 2.031492 1.027321 1.191154 0.718228 1.506970 0.898441 1.845331 1.983891 1.997562 2.267579 2.206011 2.427072 0.796751 0.501776
+1 -0.024142 1 1 -1.592245 0.800750 -0.385458 1.147162 1.975864 0.142190 0.613069 -2.139554 0.752892 1.093276 1.092803 -2.159607 -53.851530 17.341284 4.967756 -56.920974 29.197114 2.363492 0.958918 1.292358 0.667292 0.422819 2.313467 1.692138 1.257911 2.214827 2.093883 1.146666 2.271005 1.272146 0.710514 2.350665
+1 -0.016695 1 1 0.098238 1.756543 -0.903458 -1.108891 0.361465 0.866701 0.647405 0.022345 -1.431311 0.707299 -1.789064 0.958063 -1.993472 -54.290590 -11.940370 18.202499 -70.601358 2.169698 1.872074 1.444292 0.469195 1.014910 1.844578 0.565879 1.474464 1.313704 1.675676 1.328045 1.951067 1.580543 2.193261 1.893034
+1 -0.015182 1 1 -1.735667 -1.663882 -1.545059 2.172116 -0.124795 -0.411864 0.299007 2.010106 0.728575 -2.338177 -1.129528 2.230053 -58.503658 -20.979069 54.781696 15.964360 -37.009383 1.874440 0.720583 0.593116 2.496030 1.017345 2.272378 1.857644 1.927848 0.597682 0.491350 2.114228 1.083684 1.226072 0.345350 0.791361
+1 0.009080 1 1 1.977513 -0.415597 -1.173603 1.317970 -1.820579 -0.931054 1.624894 1.302842 -1.608399 -2.101533 -1.108300 0.868454 58.425312 54.212007 41.207687 27.589632 48.938593 2.288912 0.743891 0.820886 1.132201 2.152040 2.082475 0.655619 2.231259 1.521267 0.441161 2.339139 1.167144 2.183965 0.895882 1.588133
+1 -0.022363 1 1 -0.181854 1.925921 -0.448419 -1.467258 -0.273600 0.888468 -1.082721 1.952333 0.503408 2.045622 -0.829069 0.378563 24.691454 -60.733879 -4.309860 14.186078 -74.584667 1.457406 0.365396 2.467767 0.759027 0.967588 0.755169 1.370276 0.737444 0.466518 1.012134 2.443815 0.950374 1.679672 0.998608 2.362549
+1 -0.005512 1 1 -0.888382 -2.194927 -1.561043 2.127255 -0.125643 -0.532483 -0.612926 -0.164697 -1.884446 0.082525 1.547850 2.332866 44.862224 -50.608926 65.785431 5.743839 -63.301046 2.114845 2.448113 1.192759 0.701111 1.826467 2.178311 0.380687 0.711493 0.816234 1.699889 1.033414 2.333566 1.995118 1.704064 1.450346
+1 -0.013707 1 1 1.365700 -0.728561 -2.138764 -0.108701 1.466236 1.943703 1.535787 2.215927 1.066889 0.561159 1.914556 1.744996 -56.284978 68.382594 6.259084 46.427839 12.685432 2.185729 1.292071 0.335397 2.268179 1.038216 2.042465 0.957891 2.019137 0.382935 2.485145 0.340542 0.996546 1.455149 0.694671 1.585344
+1 0.007767 1 1 -1.432015 -1.700089 -2.188344 0.698543 1.850726 -1.318579 1.014486 1.039230 2.224219 -0.937848 0.524739 -2.305328 -12.372464 -44.001759 -37.555556 3.776092 14.772025 1.726469 2.261129 1.794941 1.065730 0.977967 1.949469 1.723074 1.451051 1.560649 0.829753 1.654597 0.311608 0.692230 1.056519 1.412736
+1 -0.021075 1 1 1.762067 -2.298824 0.540563 -0.243076 0.268154 1.812113 0.009697 -1.949318 -1.657074 -0.229593 0.679630 -0.289534 53.918371 56.064759 -19.589230 13.814969 -11.813171 2.215615 1.842210 1.282333 0.915014 1.386451 0.334236 0.746317 1.092721 2.356040 1.713662 0.771961 2.352594 2.294037 1.387011 0.750896
+1 0.017382 1 1 -1.859534 -0.621237 1.517628 -1.392545 1.938077 1.233672 -0.179203 -0.640277 1.956233 0.067168 -2.085356 2.163861 -70.475863 62.163325 29.006361 9.915342 -2.851502 2.497199 0.416365 1.845202 2.052640 0.975433 2.097356 1.006331 1.650977 2.471986 1.920253 1.187024 1.068393 0.740376 2.495913 1.310121
+1 -0.065927 1 1 1.215417 -0.694098 2.171779 -1.067686 0.187099 1.408775 2.233572 0.750169 -2.256522 -0.066440 0.171588 -0.101783 -2.074670 -68.977337 47.902880 53.709488 -4.632396 1.274857 1.272738 1.651368 2.294951 0.984318 0.683462 2.193714 0.505566 0.290112 1.660482 2.467831 1.829463 0.785486 2.411901 2.324770
+1 -0.054811 1 1 -1.310848 -0.996767 -0.117784 -0.392547 -0.186074 1.682268 -0.449871 -2.306378 0.818186 0.501769 -1.945008 0.095265 -34.817018 -19.619434 -43.826820 52.634499 -71.972533 0.739606 0.812529 2.419472 1.312328 1.052282 2.204740 1.313079 2.427257 1.651541 0.693288 0.840517 0.313529 1.482407 2.063405 1.890845
+1 -0.037386 1 1 -1.939653 0.558740 -1.054786 0.216428 -0.458052 1.561508 0.977041 -1.547395 0.600376 1.289438 -0.686521 2.288708 -29.005994 -3.736814 45.358351 37.808369 45.255652 0.801232 1.557304 0.865151 0.348905 2.051883 1.748623 1.113740 2.378571 2.396863 1.575896 0.588941 2.081351 2.023098 1.706331 1.300317
+1 -0.005224 1 1 2.254129 2.243059 -0.012002 0.922677 -1.035498 -0.767652 0.598264 -1.219194 -1.518343 -1.205296 1.144448 -1.238176 -3.784066 1.197488 26.177901 21.979483 -40.830291 1.604405 0.488851 0.611906 1.061295 0.689977 1.441509 0.947826 1.619205 1.732870 1.837588 2.335017 1.627350 1.371556 1.993086 1.288440
+1 0.022155 1 1 0.943286 1.338550 0.067084 1.221502 -2.101352 1.938357 1.215299 2.044979 -2.207701 0.521501 -0.167784 -1.941912 9.407125 5.550049 -20.328747 34.755992 43.952220 0.699426 0.504658 0.788442 0.336802 1.134880 2.185614 1.617318 1.516968 2.428983 1.408634 1.913426 1.192019 1.754343 0.495102 2.181289
+1 0.004981 1 1 -1.444265 -0.238853 0.559014 -1.162927 1.672601 2.011372 -1.543393 1.894476 -1.152590 1.057161 1.996855 -0.485768 72.225169 -61.577607 65.158986 -22.925547 40.335923 0.262791 1.480363 1.467884 0.975997 0.333731 1.268375 0.323332 1.996154 1.102981 1.547349 2.297647 1.298867 2.056437 1.791736 1.201675
+1 0.029704 1 1 0.567426 -1.143383 0.291161 2.076555 0.704455 2.258499 0.292255 1.628759 0.284731 -2.307267 0.018811 0.431219 -5.190081 70.303148 35.000707 -43.125598 -11.921696 1.855945 0.366095 0.706534 0.721694 1.262546 1.358716 2.183287 0.761538 0.412855 1.361533 2.283281 0.607649 1.503948 1.855365 1.869700
+1 -0.028662 1 1 1.992057 -1.019255 -1.083344 0.902531 -0.338923 0.993996 0.666560 1.529023 1.635866 1.916113 -0.357363 2.087851 65.804975 34.214209 -61.794014 28.013922 -20.017316 1.659619 1.471548 1.802904 2.155925 2.126148 1.168015 1.073359 0.939551 2.027715 0.550174 0.776883 1.827127 2.024919 0.819184 1.773061
+1 0.009824 1 1 2.046102 -2.171103 -1.701609 0.545748 2.076842 0.817526 -1.168997 -1.381817 -1.553938 -0.975476 -0.417693 1.293705 10.829665 64.176407 -37.125052 39.248211 -55.319848 0.464745 0.461776 2.316547 1.704625 1.878786 1.764264 0.729456 1.219196 1.768215 1.886409 1.620226 0.889482 2.024670 1.131192 0.942634
+1 0.024500 1 1 -1.601046 -1.042512 -0.841332 1.617260 0.229038 -0.576904 2.066723 0.394431 -1.129843 1.653574 -2.049867 0.162650 15.253943 23.027281 19.517188 -24.625514 -31.006449 0.994105 0.920918 1.620524 1.405183 2.410033 2.425238 1.469980 2.456668 0.975111 1.194619 0.465615 1.595834 0.434329 2.260278 0.991462
+1 -0.015760 1 1 -1.847931 1.179217 -1.203837 2.104058 1.128713 -1.793438 -1.880492 0.561557 -0.824048 -0.059141 0.326252 -1.899326 -7.955262 -54.094870 -22.486847 63.556445 43.177971 1.257443 1.087222 2.193610 1.004230 2.335992 2.274014 2.357872 1.006870 1.717264 0.561714 1.221334 1.706711 0.936886 2.247415 0.808346
+1 0.009604 1 1 -0.029011 -2.203785 0.354565 -1.994738 -1.634749 -1.998972 -2.105588 1.426543 -0.724158 1.176182 -0.386009 1.310152 -40.624748 19.864031 -45.237330 46.191434 -60.572452 1.506995 1.312331 1.089719 1.415749 2.251138 0.380163 0.893621 1.834556 0.878438 0.912902 1.896764 2.416872 0.373033 0.309659 1.691445
+1 0.038237 1 1 1.298664 -1.138812 1.710681 1.121881 1.182231 2.323426 -1.742948 -1.524605 1.930903 -1.533604 1.488421 -2.183029 15.377998 8.011966 -42.878753 -63.205614 3.253630 0.381498 0.829863 1.255831 0.996940 1.313931 0.991424 0.859539 0.514804 0.317025 1.743053 1.999068 0.590466 0.716029 0.551289 1.513176
+1 -0.005992 1 1 -1.410034 0.156231 0.970023 -1.683515 -1.648554 1.607590 -2.076175 0.966464 -0.237666 1.656601 1.699051 -1.129738 -41.005850 64.670686 20.223513 -3.416049 36.457334 1.201147 2.170972 0.768890 2.483271 0.328152 1.997931 1.722861 2.374789 1.835473 0.538874 2.112152 2.189281 2.487297 0.507379 1.510646
+1 -0.004315 1 1 -0.197518 -2.158112 -0.126048 2.080172 0.241445 0.605113 0.795645 -1.356420 1.192207 0.340080 -0.411450 -2.164538 7.879784 -14.464887 38.636077 6.540138 -29.896166 1.902043 1.142313 1.110662 2.400651 2.245514 0.346266 0.446338 1.608518 2.113874 1.876377 1.766342 1.913780 0.399343 1.510033 0.626784
+1 -0.002227 1 1 -0.004182 0.405912 -1.371373 -0.373832 -1.380104 -1.032442 -1.245549 -1.511636 -1.574476 -2.153292 0.765220 0.946733 -63.536030 -0.051942 27.006271 -5.597542 -27.895176 2.361562 2.279029 1.138648 0.250773 1.995334 0.828011 1.635265 1.654803 1.523197 1.375734 2.468216 1.563448 0.613553 1.742529 2.192078
+1 0.019596 1 1 -0.839914 1.878272 -0.178647 -0.724710 1.322943 1.655635 -0.405576 2.315813 2.246927 -0.976450 2.049774 -1.715521 74.960591 12.659065 60.912117 -0.054172 -10.474602 2.175372 0.481548 1.635348 0.794954 1.791278 0.265484 1.739249 1.061226 1.770066 1.495440 0.608547 0.856872 0.704728 1.856798 1.202890
+1 0.022677 1 1 -0.240656 -1.483118 1.771800 1.055761 2.035206 -1.528432 -1.125004 -1.835766 -1.703889 -0.069818 -0.049364 -0.288475 20.621856 -58.464688 33.988251 40.542480 -52.535774 0.343651 1.499277 2.103074 0.361490 2.065180 2.489435 0.443215 0.871161 2.344599 0.667604 1.164201 2.222489 0.371254 1.920462 2.445860
+1 0.031314 1 1 0.857240 1.857937 2.049819 -0.962228 0.749553 1.522571 1.578770 -1.081668 0.808411 1.140432 1.954475 -1.202604 -23.309797 32.241801 -62.057811 -55.637569 -0.614659 1.666331 1.779950 1.117429 1.386643 1.300228 2.425376 1.542704 0.721625 2.344942 1.933409 1.808677 2.436331 1.167857 0.668963 1.517555
+1 -0.002780 1 1 0.585842 2.069682 -1.705451 1.942072 -2.313589 2.149379 -0.554469 2.137922 0.082534 1.713482 1.089769 -1.307295 69.052445 14.434914 57.599709 -21.695333 16.539511 1.818470 0.530799 1.393729 1.149053 1.875393 0.973221 0.927950 0.554263 1.996628 2.321661 2.152863 2.419218 1.545464 2.116911 1.172428
+1 0.013876 1 1 1.944179 0.105091 -0.886092 -1.402370 1.742531 -0.772552 -1.650406 -1.255806 0.465226 1.201084 -1.255919 -1.442586 -9.504738 3.866078 27.179927 63.031648 72.903644 0.498057 2.336362 1.740055 1.108225 1.933688 1.988656 1.093849 1.077100 0.825588 1.405922 1.332500 0.331770 2.062477 2.047765 2.284832
+1 -0.005105 1 1 0.900696 1.804822 0.001118 -0.051972 -1.695315 -2.048782 -0.449966 0.802282 1.811654 1.718365 -1.673275 0.799524 -68.005761 27.166845 -6.829065 -26.102211 50.144404 0.279847 2.384102 0.850974 0.561606 1.669371 1.117524 0.728491 0.744416 0.647686 1.665611 0.930262 1.158124 1.346647 1.837197 0.268444
+1 0.005095 1 1 -0.081046 -0.261955 -1.309895 0.875805 -1.846908 -0.481481 -1.073336 -0.540142 -2.098874 1.174128 -1.907745 -0.371442 34.580123 -61.869051 -33.137004 16.379059 32.849459 0.637986 0.623969 1.301166 2.452209 0.282159 0.744003 0.465280 0.465550 0.498192 2.358195 1.930544 0.904448 1.549995 1.762757 2.402237
+1 -0.005477 1 1 0.378073 1.978662 0.035506 -1.732293 -1.511196 1.108824 -1.488287 -0.273134 -0.691744 -0.670208 -1.572388 -0.047658 3.823791 66.449725 70.530343 -46.516862 -8.905662 1.713027 1.344526 2.196492 2.197921 1.463192 0.869758 1.279052 2.034073 1.664635 0.265337 1.511264 1.066744 2.262952 0.940670 0.595838
+1 0.030119 1 1 2.005014 -0.018704 1.366909 0.751444 0.324193 1.196211 1.668959 2.048039 2.104130 2.345230 1.853677 1.142753 -45.934856 22.868652 53.431629 -24.615193 -7.554541 0.337551 2.465215 0.623756 2.213670 0.654538 2.069841 2.059294 0.305584 0.694706 2.166505 2.195805 1.888082 0.500322 2.162578 1.449484
+1 0.007163 1 1 1.733859 -0.448102 -0.857328 1.374533 1.640807 0.138674 -1.945763 1.536073 2.307680 2.215870 0.112891 -1.738326 24.511817 70.100565 -69.804499 -54.208318 20.795941 1.635747 0.754989 0.608165 1.183534 0.912980 0.961811 0.415454 2.285209 1.509364 0.621622 2.342724 0.656710 0.322187 0.749718 2.018210
+1 -0.022839 1 1 -1.383783 -1.601729 1.620381 0.845545 -1.497749 0.921318 -0.315847 -2.293051 -1.395630 1.913804 -1.456106 -1.341625 2.800960 -24.260356 -43.810685 23.820542 1.847964 1.506041 1.032522 0.838569 1.334739 1.953260 2.446223 0.926847 2.266040 1.082075 1.190044 2.318503 0.823550 0.907799 1.622541 1.553391
+1 -0.045635 1 1 -0.581917 -2.077478 -2.074525 0.424241 0.374016 -0.232335 1.719070 0.746726 1.132470 0.088218 -1.727415 0.371062 62.271593 48.655997 -38.650681 48.011617 -68.754243 2.086460 2.390052 1.845295 1.364641 0.517381 0.879869 2.452298 1.768563 0.979572 1.917085 1.945230 2.483839 0.884260 2.011667 0.838637
+1 -0.009327 1 1 -2.057873 2.260616 -1.815427 0.839228 0.724469 -0.670366 0.473512 -0.905703 -1.127688 0.181239 1.879948 -0.279369 -57.768508 34.680695 -21.552906 10.309682 24.831042 1.904866 1.332080 2.260972 1.412592 0.935684 2.289282 2.458822 1.175757 0.701964 0.409775 1.344855 0.973920 1.431562 0.261230 2.235980
+1 0.008115 1 1 -2.162128 -1.660575 2.190317 -0.517796 1.178719 -0.146413 -0.891537 1.329117 1.747073 0.160029 -1.160341 -1.989439 -66.778451 -45.426196 21.927588 -13.029839 7.493192 0.446174 1.096301 1.778655 1.861876 1.050069 1.010118 2.296258 0.462559 1.980490 1.099859 0.836212 2.212846 0.306824 1.296900 0.503882
+1 -0.029149 1 1 2.119426 0.252929 0.406143 -2.199651 -0.834900 1.327196 -2.264056 0.552737 1.724400 0.799421 0.851596 1.241081 57.485849 14.657597 50.231708 44.320145 -11.324512 1.658786 0.957250 2.498143 0.541229 1.194106 0.848384 2.032661 0.438720 1.823873 1.341942 1.524401 1.352692 2.199005 1.683461 1.680130
+1 -0.051176 1 1 -2.041316 -2.206513 1.634653 0.380159 -0.665933 -0.410586 -1.774541 -0.009167 1.443631 -0.977172 -0.651185 -2.307036 -26.054899 -54.694523 -50.850425 56.909807 -66.869145 0.329300 1.040432 1.039052 0.352741 1.264272 1.126199 0.269839 0.679105 0.961720 1.122736 0.569486 1.349463 1.924917 0.830419 1.609819
+1 0.048244 1 1 2.154603 -2.294739 -1.486726 -2.311799 -0.766910 -1.079209 -0.275796 1.684333 1.273272 0.920225 0.155147 1.600970 -7.729323 -6.737767 8.358443 -69.652662 -52.285225 0.508356 2.194854 1.657403 2.477637 2.393977 0.327809 0.741229 1.089717 1.368838 1.313636 0.531861 1.244730 1.177735 2.437076 2.427473
+1 0.016650 1 1 0.950170 -0.784138 1.546138 1.829037 1.710566 -0.802527 -1.222254 -1.117121 -1.296372 1.954641 1.594517 -0.313234 -24.931312 -70.562011 -35.714596 44.776765 13.089527 0.560128 1.562955 1.338524 0.320490 1.472479 1.708708 0.762140 1.528923 0.858051 0.259748 2.089468 1.189872 1.679164 1.452924 1.534951
+1 -0.016016 1 1 -0.377248 -2.247358 -1.540517 -1.605368 1.717164 1.696711 1.953266 2.041286 1.704638 -1.475473 -1.686548 -0.799598 28.584340 -33.005723 -27.178831 -44.612288 51.280751 1.008830 0.909920 1.275343 0.448451 1.108876 1.633011 2.017518 2.418859 2.256503 0.540553 1.071631 1.150162 0.266894 0.693310 1.216300
+1 0.000030 1 1 0.949771 1.944028 2.289073 0.505929 1.997768 0.713138 2.098574 -1.490081 -2.154502 -0.710655 1.934339 -0.342536 48.817408 -25.825262 54.825867 8.338529 45.653831 2.184032 2.034413 0.633441 0.742511 2.376245 1.554642 1.111002 1.357712 1.067352 1.236560 1.115051 1.906136 2.427917 1.495683 2.447381
+1 0.016151 1 1 -1.732453 0.512650 1.854889 -2.038587 1.247474 0.881851 0.805878 0.979687 0.517215 -1.526346 0.943750 -0.302736 41.279486 34.324203 -13.121852 -38.972329 42.062099 1.190370 1.052841 0.343014 2.031833 2.275799 0.860967 2.021887 1.602181 1.350279 2.141388 0.813306 1.980682 2.076787 1.806446 0.932366
+1 -0.001611 1 1 -1.801112 1.100728 -0.902327 -0.940592 1.538067 -1.875807 -0.801998 -1.756228 1.481818 -0.053193 1.342043 2.218383 -2.001083 -32.200073 13.372891 58.179737 -23.167435 1.748680 2.058586 1.909583 1.854990 2.321723 0.946445 0.898080 0.281435 2.078139 2.038208 1.404752 1.918970 2.137888 0.475213 0.912836
+1 -0.001925 1 1 -0.357598 -1.859695 1.373878 0.058592 -0.135861 2.099384 -2.026127 -1.385438 -1.140680 -1.416635 2.323022 0.890544 26.493337 73.517409 57.092497 3.598262 25.982565 1.959653 1.882565 2.263018 2.036675 0.397690 0.718617 1.302816 0.934070 2.169328 2.386504 0.724274 1.868198 1.546777 1.674993 1.102202
+1 0.074416 1 1 0.802253 1.324420 -1.795754 1.616389 -0.269684 0.747643 -2.302936 2.111377 1.622055 0.704401 1.344996 0.011988 -36.388808 -36.704361 59.801903 -59.414142 -23.488738 1.746762 1.321026 0.981247 0.811462 2.491905 1.449465 1.903732 0.276248 0.397494 1.939584 2.086873 0.333217 1.626930 1.065127 2.096580
+1 0.027615 1 1 0.372024 -0.739809 2.020033 -2.065008 0.154135 -1.266760 0.147334 2.240954 2.297272 1.644114 -0.821669 2.221229 20.427702 -21.615740 4.255807 -22.650282 16.712147 0.340900 0.256241 1.645949 1.209366 0.816683 2.484693 1.729913 1.646187 0.710365 2.097622 0.976407 0.465017 0.546488 1.830339 2.008084
+1 -0.010911 1 1 0.744202 1.117921 0.610332 -1.016801 -2.245296 0.119153 -0.153137 -0.815561 1.208416 -0.549959 -2.171090 -1.480692 4.074343 -72.510075 73.166190 4.152487 40.844298 2.426864 1.808466 1.142876 1.566204 1.936694 0.771801 1.903576 2.159343 1.074389 2.499100 0.877600 0.318852 0.939058 0.495043 1.181484
+1 -0.012522 1 1 2.352660 -0.506869 1.059241 -0.746285 1.570561 2.333174 1.861726 -0.229101 -0.486888 2.287707 1.113942 -0.304633 -73.364287 -33.566277 1.586164 -41.337946 33.143226 0.447989 2.343056 1.736966 0.935898 1.383681 1.022823 2.081970 1.166090 2.470175 0.737701 0.298959 1.852632 0.943121 1.289240 2.256095
+1 -0.023036 1 1 -1.881415 -0.820425 -0.434854 0.321941 1.044127 -0.290507 -0.508982 -1.469012 -1.474921 -1.838768 -0.332330 -1.295609 20.621987 -56.269391 30.337826 37.835356 48.826230 0.961803 0.270054 2.043296 1.434786 0.454808 2.209795 0.778206 1.565546 2.131292 2.129759 1.104030 1.186052 0.482288 0.560580 2.417210
+1 0.017175 1 1 1.003332 2.081364 1.424707 1.404393 -0.728867 2.149869 -1.743854 2.107192 1.975172 -2.063459 -2.087265 -1.639850 57.302471 -67.362704 35.029823 -3.757598 -3.950901 2.083146 0.685804 1.052999 0.750174 0.669553 2.422258 0.887194 1.824538 1.256628 0.894347 0.547155 1.783413 0.820881 1.055248 0.306738
+1 0.003376 1 1 -0.848123 0.565677 -2.270462 1.265824 -1.727514 -1.305469 -0.139626 0.083112 2.001030 -1.003743 0.447424 -1.121357 -57.174811 -37.049512 -41.140167 57.209649 22.575023 2.401215 0.465812 0.396809 1.666460 1.700652 0.359504 2.439793 0.854193 0.664426 1.765226 1.148766 1.565650 1.636291 0.893563 0.863789
+1 -0.010844 1 1 -1.311292 0.962064 1.198834 -1.371749 -1.980579 0.725944 0.568358 0.380444 -0.595976 1.969117 -0.162296 0.757098 35.103501 34.549329 20.579802 -15.259791 28.686826 1.967170 2.219617 1.600821 0.993931 0.251837 1.873418 1.543209 2.469166 1.767836 2.267924 1.243952 1.593298 0.551346 2.475614 2.145096
+1 0.013537 1 1 1.660940 -0.776642 0.295191 -0.865638 -1.637165 -0.196067 -1.344735 -0.338391 0.522940 0.454402 -1.644815 -1.534971 65.986092 -71.749991 -52.093103 21.220923 -39.941205 0.747608 0.295270 0.602943 1.166728 1.943060 2.016623 0.884082 1.272430 0.986798 1.863551 2.193636 1.442631 1.806733 1.261742 1.353662
+1 0.002897 1 1 0.972448 1.369215 1.797669 2.293723 -1.451925 -1.761460 -1.629674 -1.524058 1.698209 -1.139161 0.563322 0.563964 61.570632 -32.379605 -4.027036 -32.389897 -27.001145 0.501435 0.621259 0.757062 1.694370 0.524432 2.380874 0.605483 1.097643 1.830908 0.317785 1.006261 0.482052 1.099678 2.287244 1.964608
+1 -0.051992 1 1 -2.073432 -0.054977 -0.376496 0.971115 -2.182501 -0.062920 -1.922332 -0.494743 2.215005 -0.286548 0.056168 1.534679 -72.324079 49.201600 -18.702001 -74.526200 -61.839893 1.478678 2.397061 0.409889 0.996117 0.981679 1.321384 0.252440 0.764157 1.679720 1.802510 2.279533 0.619372 0.531845 0.972912 2.488815
+1 -0.000267 1 1 -0.735972 0.533683 1.930803 1.496131 0.168734 -0.944707 -1.654515 0.381578 -0.375933 1.013442 2.346056 1.598553 49.354866 7.237872 -3.087911 1.486091 -73.267353 0.558855 0.421158 1.398152 1.243446 2.098856 1.467416 2.110807 2.085274 0.454880 1.172092 2.100052 1.324349 0.578077 1.742067 1.163033
+1 -0.010392 1 1 -0.703610 -2.182358 2.341714 -0.679265 1.705976 2.161290 1.710936 0.710948 -1.721690 2.343845 2.137875 -0.696796 -24.208349 -69.721069 -2.003131 -66.621619 40.449969 2.014479 0.846323 1.145301 1.828406 1.020401 1.872173 0.859413 0.653041 1.653148 0.714683 0.424584 0.488289 2.420400 1.155391 0.402934
+1 0.029867 1 1 0.922107 -1.197282 -0.823660 1.737653 2.057136 -0.511410 0.122750 -0.967770 1.860456 1.989168 2.259415 1.550429 -46.396628 61.873055 -49.567178 24.446069 15.073967 1.347380 0.661545 0.585727 2.065345 0.760158 1.977125 0.789745 1.998903 2.306061 0.971181 0.395700 1.023779 2.401241 0.913652 1.002122
+1 -0.006011 1 1 2.202317 -1.475898 0.602366 1.757340 -1.647439 1.497770 -0.553026 -1.869041 -0.182143 1.773646 -0.907084 -0.775518 10.835881 18.658437 -57.653341 20.299515 73.941330 1.104036 1.288838 2.250944 1.614178 0.484055 1.016676 2.270474 1.347702 1.578774 1.701542 1.812644 1.603197 0.438832 1.442981 0.926698
+1 -0.010483 1 1 0.751994 0.141805 -1.154109 -0.925931 -1.808061 2.115735 -0.524365 -0.842432 1.976431 0.246772 0.597877 1.698024 14.723297 -45.549375 51.657260 3.561590 9.639551 1.553968 1.044154 0.597204 1.455314 1.211625 0.533809 2.471777 0.656839 2.493171 2.477154 1.023153 0.877694 1.902195 1.434555 1.063269
+1 -0.016057 1 1 -1.073270 0.577866 -0.041870 -1.560296 0.543165 1.070713 -1.134232 -1.422974 -0.546101 1.415791 2.353574 0.727664 38.116713 -22.396938 74.657735 22.544635 7.682675 0.965745 1.281888 2.437775 0.683268 1.187661 0.517453 2.085386 2.329534 1.734255 0.370680 1.269773 1.330838 1.645447 1.783477 1.905123
+1 0.040118 1 1 -1.595520 2.294500 2.191120 -1.164005 -2.309263 -0.543911 0.526691 2.224051 0.957467 -0.657466 0.515860 -0.732823 52.013953 -1.484950 -57.561955 56.221743 68.826201 0.804320 1.706775 2.009048 1.819395 0.326052 0.462917 1.248849 0.652990 0.805999 0.669881 1.187694 1.072059 1.596320 1.856185 2.152541
+1 0.009506 1 1 -0.936310 -1.899553 0.639615 1.043678 1.583461 -2.342363 -0.788729 -0.225004 -2.311664 1.510153 0.214708 -1.085396 -18.716735 -22.169741 -6.839877 -57.814070 18.933074 2.247694 0.990632 1.054351 0.974223 2.011449 1.670878 1.688175 2.151586 1.204412 0.804836 1.375619 0.531049 1.093202 1.445414 1.329176
+1 -0.017859 1 1 1.452705 0.723687 0.324957 -0.106699 2.130638 0.197396 0.109415 1.103428 2.066529 1.850016 0.868588 -0.625251 0.968265 73.627284 -46.232240 -25.254634 45.364022 1.121686 0.930448 2.041581 1.861077 1.112353 1.574400 2.447958 0.838374 0.305582 0.665597 1.194586 2.160710 1.553579 1.255774 2.298624
+1 -0.004936 1 1 1.835469 1.427546 1.999772 1.418257 1.378240 -2.029225 -1.618862 1.113796 1.955288 -1.684177 1.362421 0.719826 45.214125 13.791237 39.322572 -5.524593 -1.833778 0.320520 1.973975 1.854213 0.501074 1.297414 2.383898 1.921750 1.602625 2.063483 0.964433 1.720636 0.985197 1.949273 0.684390 2.049015
+1 -0.030532 1 1 -0.267692 1.239038 0.456912 -1.881204 -1.977496 0.709206 1.985695 0.444322 -1.413532 -2.084983 -0.993046 1.157919 -32.501416 48.696900 48.799986 -18.637911 -47.364607 1.270841 1.271171 2.329328 0.513209 0.506643 0.397945 0.516104 1.912668 1.961106 1.562042 1.741252 0.979844 1.981617 2.038835 0.708975
+1 -0.034678 1 1 1.181454 -1.310989 1.334518 -1.732617 -2.234203 -1.928797 -0.760548 2.174988 1.018156 1.459776 1.752656 -0.261496 53.863343 31.210964 12.679210 -50.516801 -35.877763 1.411677 1.309903 0.789358 2.236673 0.258116 1.660945 1.260065 2.415543 0.535068 1.141274 1.647876 2.106643 1.852430 2.043834 1.462298
+1 -0.022465 1 1 1.008981 -1.945681 -1.791881 0.731345 1.803934 -0.788815 -1.660298 2.136354 2.017565 -1.138615 0.316171 -1.693786 2.530876 -63.567832 65.452039 -47.581625 -54.372861 0.704991 1.778008 2.227866 0.736934 0.900423 1.416869 0.823382 0.333931 2.381281 0.696866 2.480344 0.634179 1.902017 0.706201 1.864725
+1 0.000730 1 1 -0.540322 -0.418832 1.000047 -1.293206 -1.379171 0.510230 -1.115706 -1.080355 -0.696619 2.207794 1.048666 0.590921 -67.038960 -73.799649 -0.695211 15.588556 -53.132384 0.685243 0.622234 1.379883 2.450814 1.586603 0.532072 0.278711 1.302895 2.259102 1.477242 0.762170 2.046884 0.976177 1.103379 1.493174
+1 -0.006627 1 1 0.022460 0.485758 2.282310 -0.070702 -0.767343 1.073062 0.643562 1.411588 -2.312215 1.679965 -1.461169 -1.607351 44.072495 26.416656 -15.260209 21.673616 68.466019 2.250679 1.655072 1.553109 2.361934 1.773210 0.333118 2.206527 2.093275 2.174749 1.258786 1.172598 1.600323 1.621047 1.179948 1.381574
+1 0.000602 1 1 -0.673658 1.705962 1.928978 -0.911638 -1.918210 -1.896901 -1.901209 1.082702 -2.270911 -1.556222 -1.662849 1.678055 -18.559535 69.890821 5.024650 -0.703786 21.460879 0.519991 1.987967 0.767704 0.555249 0.564719 2.228804 0.756724 0.505869 0.894458 2.408602 0.875558 2.007528 1.028575 2.014786 1.502898
+1 0.062445 1 1 1.761150 1.137541 0.496525 -0.549575 -0.419069 1.725759 0.079291 -0.968760 -0.642705 -1.150085 0.747084 -2.274489 -13.788913 -0.262729 -65.682342 -73.124212 -48.622907 1.296952 1.368394 0.602985 1.873020 1.603636 1.057826 0.879900 0.734962 1.513308 1.666702 1.259726 1.216600 0.900800 1.002601 1.964013
+1 0.014138 1 1 2.002044 1.899540 -0.873771 -1.672390 1.535242 -2.227183 -1.752145 -0.584933 -0.922299 -2.038352 0.478575 -0.635551 40.513238 55.987802 36.992507 -16.935391 66.878791 0.352619 1.472629 1.975135 1.087352 2.130478 1.937606 0.341936 1.919827 0.777652 1.239591 0.315061 2.477495 2.260942 0.899773 1.737885
+1 0.020458 1 1 0.910461 0.989979 -0.863652 -1.235760 -1.923371 0.897240 0.273418 0.753660 -0.132073 -0.217524 0.881175 -1.136037 39.238556 -67.581614 -44.183932 50.654916 -42.820332 1.655078 1.651951 0.835545 2.251725 1.240296 0.907160 2.133579 2.312969 2.311012 0.926731 0.320579 0.714659 2.269165 1.850672 1.742401
+1 0.018254 1 1 -0.569261 -1.424339 0.075226 1.399566 -1.731626 0.273348 -0.424758 0.360811 -0.694676 1.875417 -1.035992 0.366006 56.981793 -56.998938 68.841023 61.068002 69.914897 0.770130 0.824882 0.793555 0.776430 0.950860 0.862059 2.374965 0.293048 1.504592 1.418903 1.250822 2.310356 1.160193 2.362308 1.312241
+1 -0.043995 1 1 1.561996 -0.260510 -0.580754 -1.373741 2.238682 1.819530 2.141362 1.357285 -0.789560 -0.043273 -1.589401 1.467383 -74.273435 -13.624048 70.618306 -68.132536 -3.531663 2.025195 0.951864 1.981956 0.990948 1.866047 1.401618 0.987681 0.960875 0.433260 2.304413 0.270841 1.776973 0.581713 2.105654 0.981053
+1 -0.020292 1 1 -0.378453 1.067307 -1.831981 0.649806 -2.027182 -0.275114 -0.980957 1.707177 -1.215998 0.347577 -1.628282 -1.690349 41.556646 42.545141 6.191582 -38.084997 -44.545138 1.072924 0.381291 1.856915 0.928111 1.013018 1.547215 2.296206 1.830085 2.239882 2.438347 1.302612 1.993841 0.485331 2.210632 1.344434
+1 0.029700 1 1 0.265088 2.124230 0.883265 1.016990 0.710418 -1.204533 -0.166650 -1.725520 -0.764950 -1.110417 -1.712133 -1.966201 65.096845 -17.318523 -72.417957 -28.609704 56.709650 1.661334 1.032949 1.269302 2.413049 1.364401 0.985514 0.531009 0.414292 0.752675 2.212094 1.167340 0.979040 1.981406 0.740996 1.663276
+1 -0.044562 1 1 -1.875509 -0.503196 1.528137 0.884067 0.355254 0.156327 -2.119643 0.819426 -2.220773 2.301039 -1.012688 0.896906 -20.154814 -41.967129 -41.533471 46.948604 65.180271 1.897208 0.877946 1.634914 0.253441 1.828461 1.949909 2.372004 2.270010 0.309271 1.920059 2.426146 0.987235 2.454969 1.657159 0.625543
+1 -0.053838 1 1 0.304801 0.422252 -0.062573 -0.800200 0.195841 2.245004 -0.323209 1.206892 2.120513 -0.334203 0.223153 -0.530488 -2.309458 34.933629 29.508607 51.155867 -23.343766 2.294822 1.073671 1.684560 2.154501 0.702358 0.273770 1.495775 1.731260 1.780199 0.808661 0.423713 1.601607 0.704574 1.533053 0.527801
+1 0.005307 1 1 -1.288926 -0.123728 -1.337083 1.025961 0.691667 -0.609670 -1.989527 1.124457 2.068644 -0.303657 -0.051108 -1.315718 62.565240 33.989106 54.896433 -5.655430 49.184599 1.308394 2.429350 0.842925 0.297856 1.316945 2.146812 1.973747 0.274377 0.451562 1.644096 1.577179 1.890931 1.120055 0.518778 1.845517
+1 -0.020792 1 1 -2.282624 -0.497663 0.264732 0.847457 -2.342328 -0.205790 0.181578 -1.851157 -1.204253 -0.167209 -1.703194 2.179130 -1.812518 -12.991279 55.572917 -35.991405 42.456126 1.526719 2.059604 1.007081 0.754275 2.091998 0.962620 0.504082 2.348326 0.317288 1.666975 1.351887 2.171482 0.351625 0.510758 2.054401
+1 0.045438 1 1 -2.078494 -0.314654 -1.095885 2.182763 -0.255331 1.631250 -0.256847 -0.276715 0.379543 -1.595725 -1.139996 0.659674 -35.555051 26.261097 70.254268 -36.525057 73.367692 0.486896 1.514464 0.853512 0.468309 1.862186 1.764720 1.651824 0.955397 0.605584 0.545024 1.963516 1.561161 0.432210 0.407310 0.413269
+1 0.019419 1 1 2.095826 -0.567000 -1.126354 -0.964792 0.067239 -0.892038 2.336679 -0.490249 2.347197 1.932595 -1.368783 0.737923 -23.169913 -16.732918 19.847930 -15.841091 8.782374 1.455518 2.390549 1.211470 2.425761 1.266563 1.372679 0.611184 2.422109 0.642340 1.800354 2.042242 1.719218 1.904665 2.459312 0.399825
+1 -0.012231 1 1 1.108213 -2.333031 0.534352 -0.963038 1.271842 0.453823 -1.953311 1.908812 -0.547950 -1.382140 -2.269864 1.902155 21.302328 -21.770158 -41.046112 -11.999548 73.599318 0.381181 2.251843 0.973494 1.016906 1.644421 0.277073 0.762589 2.325067 0.902805 0.944481 1.638756 1.813157 1.227085 1.624893 0.580915
+1 -0.038770 1 1 -0.484516 -0.246656 1.347628 1.835619 -0.762484 -2.088665 -1.601463 1.377403 -1.949580 -1.351805 -1.358361 1.558109 12.359187 -29.151899 -55.974660 33.891895 71.083935 0.740351 2.075455 1.922644 0.880040 0.836266 0.871382 1.568268 0.624135 1.842421 0.325506 0.281306 2.166929 0.318585 0.961956 0.592953
+1 -0.004737 1 1 -1.437800 0.023596 0.740691 -1.337055 1.507588 -0.477121 1.510446 0.423559 -1.668324 -0.815271 1.372272 1.335925 -52.116038 -64.255546 57.033597 63.656858 -69.187198 0.936450 1.658251 0.977706 2.057490 1.491737 1.373157 1.905567 1.859763 1.545291 1.455014 0.677012 1.787381 2.257470 1.051449 1.706167
+1 0.001614 1 1 -0.172815 -1.673676 -1.216011 0.135254 1.844530 -1.783842 -0.809424 0.672215 2.324346 -0.422963 2.256562 0.736714 -70.297560 58.908681 -71.800694 -4.256754 6.734969 0.544282 0.741056 0.424122 1.721817 0.573833 2.419628 1.685132 0.521996 1.932735 1.729890 1.264927 0.879900 0.723252 0.449892 0.592239
+1 0.055289 1 1 0.747320 1.685671 0.193921 -1.739202 0.175929 2.168438 -0.676710 2.238701 2.138328 2.200930 -1.223196 1.904703 34.622591 51.888782 -5.242356 -58.281544 -37.904241 1.276408 0.334917 0.951045 1.720212 0.594842 2.257296 0.380008 0.550418 0.373641 1.538673 0.475553 2.117977 1.096896 0.527568 1.086359
+1 0.002499 1 1 0.531484 -2.037796 0.405686 -0.461478 0.526078 1.353416 0.164968 1.734039 -2.124382 1.281133 1.098075 1.622712 74.091854 -38.215034 19.929115 -1.360960 -73.658483 0.953206 2.025563 0.380485 1.817260 0.429819 0.716496 1.640400 2.444838 2.397681 1.830369 0.253558 1.543856 2.094072 2.069639 0.919727
+1 -0.032899 1 1 1.504078 1.786930 0.884667 1.005452 -0.000059 -0.991045 1.801668 -1.170630 -0.551444 1.155383 -1.233588 1.605018 58.014101 42.994584 59.977009 33.588710 -74.556304 1.858079 2.489947 2.287766 1.737823 1.845983 1.685926 0.354267 2.159833 0.307684 2.245885 2.081818 0.870397 0.759404 0.550044 0.847236
+1 -0.003185 1 1 -0.332885 -1.198674 -0.644757 2.063988 1.546542 -0.810136 -1.856585 1.819515 1.896510 0.040759 1.737534 0.059335 -56.845588 -53.797445 26.345508 -11.052342 -56.707446 1.644206 1.163867 1.113283 1.449265 0.802412 1.144409 0.336984 1.939906 0.744100 2.093738 0.960627 0.753298 1.431757 1.291126 2.453964
+1 -0.018825 1 1 1.152526 -2.125969 -1.832395 -1.598226 -0.764935 -0.867187 0.605009 -0.943142 1.091385 2.283030 -2.106214 0.322858 73.630812 13.058377 22.143891 22.383641 1.849334 1.851430 0.992419 1.834846 1.253036 1.270598 1.693555 0.326327 0.584292 0.451410 1.339581 2.340435 0.447174 2.154971 1.841637 0.645538
+1 0.015795 1 1 0.451770 1.238743 0.219847 0.462236 -1.929636 -0.734455 -2.236737 -2.108683 1.251132 1.101211 -2.203940 -2.241260 63.153401 19.214716 -8.262058 39.591355 11.902702 0.605638 1.454563 2.094680 1.044779 2.092629 0.318614 1.450368 1.340160 0.818041 0.565578 0.911271 1.474158 0.679633 0.847036 1.881304
+1 -0.052946 1 1 0.286525 -0.440356 2.097918 1.609371 -0.407315 1.358902 -1.889681 1.642262 1.037504 1.484831 -1.258013 1.070897 62.169255 -21.327174 54.186009 54.245056 -3.351757 2.380439 2.288454 2.038752 1.553081 1.886447 2.260660 0.659570 1.147087 0.336150 1.418863 0.586651 1.836157 0.786834 0.321500 0.452981
+1 -0.004939 1 1 -0.759830 0.109270 -1.329088 -1.262089 -1.470478 2.149881 -1.548459 1.575642 -1.808890 2.311518 0.744050 -1.424168 -56.341023 26.427791 21.883542 -3.313194 -34.849920 1.786009 1.708212 1.419842 1.289594 1.460707 1.858491 0.403423 0.330803 1.549520 0.535906 1.721273 0.429484 1.839117 1.037667 1.811231
+1 -0.046851 1 1 -0.561295 0.523093 -1.687019 0.707663 -0.370963 -0.279899 -1.292200 1.402367 -1.782842 1.852620 2.231834 -0.179561 -61.997179 63.409711 -22.987681 46.048602 -61.140999 2.173504 0.589817 1.054812 1.979918 0.480481 1.688112 1.094744 0.367652 2.134548 0.596405 1.524378 0.970517 0.478619 1.903269 1.491550
+1 -0.004681 1 1 -2.184144 0.598834 -1.054459 1.002354 -0.231529 1.129141 0.683071 0.988130 1.035684 -0.819266 0.202165 0.149620 -55.855162 -57.704051 68.007902 8.812539 62.348717 1.298341 2.218631 0.783311 1.853469 1.501671 1.841539 1.252183 0.435194 1.057769 2.169769 0.810651 2.357986 0.677168 2.157808 2.272581
+1 0.040580 1 1 0.561602 -0.063564 1.397889 -1.644734 -0.175910 -1.850082 -1.989620 -0.423766 -1.818174 1.789490 1.485659 -1.484701 -40.587190 51.097495 45.604020 -33.228522 -21.777206 1.232544 1.124614 0.630830 1.866943 0.718496 1.506876 1.568761 2.159519 1.788955 1.710947 2.378805 1.819623 1.906452 0.983150 1.305749
+1 -0.003062 1 1 1.634461 1.862298 -0.047254 2.191832 1.380617 0.220534 -2.134456 1.615793 -0.863675 -1.623747 -0.875011 1.048086 8.794984 67.289118 -71.800043 6.671597 -70.474558 0.386656 2.032731 1.617102 2.376714 0.435081 1.410839 0.718177 0.648374 1.979624 2.285657 2.291843 0.501398 2.240564 0.402867 2.233875
+1 -0.024639 1 1 1.124509 -1.774536 0.085543 0.449506 0.881712 -1.529863 -1.617775 0.534814 2.101463 -0.067905 -0.883248 -0.727770 55.286897 -43.118019 -34.545188 49.026360 36.039979 1.733916 1.420980 2.409225 2.337350 0.337184 0.803446 0.522195 0.781959 1.642486 1.512113 1.826005 1.167598 0.813049 2.162346 2.050268
+1 -0.018474 1 1 1.214392 0.930567 -0.373439 0.509630 -1.774497 0.733356 -2.089300 1.859459 -0.636549 -1.351407 0.620146 -1.014916 36.651282 -51.909386 -41.058048 -62.614436 39.168287 0.646007 0.443419 2.036244 2.147682 0.833575 0.651166 1.653137 0.525964 1.121014 0.888253 1.625106 1.905803 1.335334 0.709956 1.985037
+1 -0.079305 1 1 -0.966531 -0.875252 1.716079 2.324375 0.062943 2.305377 1.208518 1.163195 -1.879878 1.454284 -1.015801 0.412544 54.140809 44.572654 32.588786 69.726415 -58.145845 1.266629 2.488476 2.322102 0.567289 0.432998 2.392624 2.334478 1.573108 0.968484 2.318595 2.381307 1.123382 2.428068 1.796324 1.822919
+1 -0.022306 1 1 2.154803 1.066365 1.174759 -0.731109 2.160061 -0.092367 -2.035936 -1.312491 -0.342573 0.913861 1.580073 1.970091 66.018483 22.640124 -37.433436 -43.755440 52.327686 1.696285 1.219484 2.111714 1.578704 0.519269 1.102638 0.285312 1.988615 0.408987 1.599873 0.820659 1.808828 0.469856 0.870252 0.579246
+1 -0.035983 1 1 1.487357 -1.219602 1.043343 0.661187 0.752393 2.127651 1.814728 1.559414 -1.244178 -2.030581 -0.856577 -0.139779 70.733983 -73.949712 27.187249 36.096217 69.122633 1.286277 1.964391 0.517699 1.721448 1.123852 1.334817 1.010436 0.900675 1.138971 1.178374 1.931602 0.691263 0.554392 1.916291 2.102094
+1 0.016504 1 1 2.341259 1.089813 -0.567870 -1.595313 1.071303 -0.657411 1.440612 0.108338 1.859548 0.864762 1.045983 -2.085470 8.332245 -59.958718 -26.169708 -34.279212 19.289997 2.229807 1.869366 0.936322 1.771324 2.386956 1.569108 1.242416 0.541120 1.601413 1.953663 2.465268 1.505772 1.009318 2.363139 1.772408
+1 0.048673 1 1 -1.761068 0.240808 -0.676744 1.669740 1.038185 -1.207567 0.682564 1.903895 1.637319 -1.938531 0.561075 0.498587 35.999907 -49.555233 -74.794646 -73.622811 -28.578265 1.151393 0.716311 0.781525 1.090601 0.478842 1.144477 1.474265 2.472052 0.775890 0.879009 1.498964 1.338500 2.173118 0.838593 1.731882
+1 -0.032556 1 1 -1.758320 -0.697356 -0.757491 1.723239 0.134852 -0.195309 1.979807 0.445965 -2.077241 1.893822 2.000377 2.150883 36.936278 -61.983567 -7.807515 29.096657 27.508604 1.931656 1.599217 1.049154 1.389831 0.885862 1.925346 1.285242 0.311441 2.395850 0.308855 1.681003 0.872690 1.044941 0.330722 2.438601
+1 0.007589 1 1 -1.576955 -1.401493 2.341495 0.351968 1.471722 -0.093206 -1.997561 -1.944486 -0.563883 -0.564800 -1.844659 -0.380403 40.692204 63.875169 -0.042458 36.409456 -66.274426 1.760865 2.116004 1.680073 0.992841 2.183801 0.392998 0.611727 0.297617 1.795626 1.328006 1.302815 0.904205 1.971128 1.246595 1.015370
+1 -0.025843 1 1 -0.553967 1.153189 -0.404418 -1.794594 2.258866 1.761473 1.858114 0.322681 -0.664473 0.568571 -0.750552 0.534965 -2.417708 15.588048 -61.682301 -44.440484 -61.218660 0.594834 2.127287 2.307156 1.373707 2.142312 0.592517 1.430289 1.374574 0.965935 2.225498 1.451645 0.290931 1.928531 0.817625 0.328301
+1 0.045211 1 1 -2.149509 -1.622315 -0.362914 -1.672149 0.887349 -1.032686 -0.620522 -0.601715 -0.233507 0.864896 -1.411213 -0.800545 -28.531518 20.781310 71.485284 -46.830373 -28.081160 0.474148 1.006770 2.289025 0.387651 0.749674 1.274322 1.277099 0.703254 1.843113 0.699373 1.854821 1.731250 1.614883 1.085962 1.272493
+1 -0.016820 1 1 1.854077 -1.553585 0.250808 -2.259011 0.519911 1.377858 0.974110 1.025226 -2.229471 2.188930 -0.279920 -1.657320 11.023344 19.346911 -36.475177 11.693931 39.892708 1.026216 0.614577 0.952745 1.031472 1.199109 1.673817 1.586732 0.461050 1.371997 0.408674 0.835581 0.617646 0.784032 0.473707 0.346324
+1 -0.043788 1 1 0.107457 1.185606 -2.221635 1.950025 -0.588954 2.178887 0.583206 0.174245 2.135799 2.106866 1.205216 2.214412 -26.111353 46.485383 -70.173726 40.180145 7.699781 0.778270 0.391599 1.860437 1.622211 0.504656 0.753100 0.345035 2.260147 1.036281 1.023666 0.502022 1.487257 0.325289 1.130681 1.352574
+1 0.003892 1 1 -1.603335 -1.804828 -0.087604 -2.097411 2.192563 -0.470270 -1.148343 1.745745 1.394538 -1.425071 1.908557 -0.115478 21.150004 -31.875720 64.768570 15.362333 44.725470 2.139508 0.713960 1.781472 1.941566 1.654273 1.622103 0.936986 1.667572 2.386758 0.496333 0.361776 2.362121 0.413429 1.996196 1.824682
+1 0.041752 1 1 -0.220378 0.051122 1.547293 -2.315337 1.033069 2.347722 1.334485 -2.276868 1.992152 0.579421 -2.174250 1.957641 5.302008 10.855881 54.794735 -64.882822 14.403533 1.077810 1.503532 1.617120 0.430405 1.561643 1.791959 0.448571 0.881871 2.362410 0.781423 1.618884 0.829482 1.596351 2.375731 1.907069
+1 -0.002506 1 1 -0.204173 -0.917363 0.820254 2.267915 -1.672786 -0.399044 -1.002806 2.059395 -0.239869 2.322056 -1.211611 -1.315592 -20.121332 70.774257 2.931834 -74.668276 -49.721504 1.085160 1.284661 1.796927 0.695238 2.117856 1.304460 1.558303 1.898834 1.194614 0.376653 0.405796 1.968631 2.034228 2.026275 1.096395
+1 -0.008270 1 1 -1.025189 -1.852328 -2.032942 1.881185 1.657111 0.851700 -1.719134 -1.828332 0.711427 1.621041 -2.195267 2.151142 25.319791 -0.274956 28.817941 -6.865712 -42.029645 0.741330 0.531075 1.533118 1.618717 0.276534 0.705599 0.752232 1.510847 0.801151 2.447741 1.679631 0.303656 2.050228 0.938401 0.704468
+1 0.070737 1 1 -1.792686 1.340304 1.271466 -1.151781 0.518755 0.794169 2.106070 1.964096 0.273453 1.340841 0.872255 -0.253646 53.361214 -8.083143 46.619386 -67.981401 -13.410343 2.310498 1.285287 1.062374 0.815085 0.383915 0.952511 1.606352 1.709910 0.714603 1.329319 0.872307 1.366074 2.107527 0.958454 2.487709
+1 -0.009730 1 1 0.082909 -1.418235 -1.003161 0.800730 -0.708461 1.109706 -0.811098 0.812031 0.728687 -0.464554 0.673965 -1.249678 -6.903362 -74.799817 -10.530728 10.053299 65.792568 1.010461 1.324707 2.106332 1.124731 0.345750 0.770186 1.763107 1.543597 2.242454 0.678675 0.498480 0.452222 1.501640 1.306850 1.222035
+1 0.007471 1 1 2.152671 -1.784042 0.528215 -0.429382 -1.961111 -1.938804 0.685960 -2.285745 -1.127262 -2.093845 0.862410 -0.787575 10.620174 -6.737682 9.782451 13.647891 30.103148 1.279229 0.499836 0.751763 0.374156 1.185506 0.297525 0.251815 1.512762 1.485972 1.225807 0.387794 0.904897 2.361987 0.421532 0.937747
+1 0.018870 1 1 -0.394960 1.656625 2.109830 -0.809840 -1.608309 -0.582888 0.453868 -1.203338 1.064926 0.555818 1.682951 1.602649 -9.194434 -30.857064 -64.667530 32.815791 -14.993704 1.387168 1.128014 1.532548 1.027196 1.337191 0.414641 2.128204 1.983476 1.778898 1.435830 2.243385 0.565744 1.453230 2.185856 1.183260
+1 0.008321 1 1 1.403619 0.401957 -1.871170 1.735234 -0.900367 -0.986146 -0.690891 -0.486301 -1.985369 0.330465 -1.773656 0.744033 -54.598709 59.494705 27.506578 3.059851 -23.083928 0.301321 1.058909 1.079989 2.125147 2.344782 1.501438 2.413285 0.832100 0.606049 1.610978 0.707747 0.861573 0.965471 1.164721 1.969660
+1 -0.003023 1 1 -1.559423 1.079320 2.153513 -1.762523 -0.642901 0.277507 -1.199608 -2.218040 1.103048 0.397011 -0.178188 2.279675 -61.524089 64.638909 -63.856926 6.652604 60.324624 1.764395 0.686522 1.868718 1.302594 1.693549 2.479053 1.451124 0.532860 2.277092 2.326442 1.503447 2.437436 1.732071 1.920510 1.014447
+1 0.019235 1 1 1.208824 1.587983 -1.738279 1.552932 -1.790868 -1.089453 1.908336 0.889643 -0.176546 1.604607 -0.374496 1.600850 -71.885985 62.243930 33.729749 45.890896 -11.713911 2.489407 2.221233 1.754655 1.243334 2.468760 1.703606 0.505579 0.513345 0.545697 2.037337 0.271838 0.538590 1.839513 0.940120 0.338842
+1 0.060353 1 1 -1.745437 -0.946331 -0.664668 2.004203 0.484739 -0.718818 1.393034 1.570064 -1.310247 -0.326506 2.348542 0.968350 -48.806403 60.781933 61.952427 -65.561755 3.588850 1.642040 0.760150 1.844949 2.313810 0.708419 0.893308 1.081692 1.503481 0.760778 1.144470 1.366302 1.441149 1.639371 0.915101 0.608116
+1 0.031892 1 1 2.039838 0.934743 -0.871757 -0.795296 -2.197694 -0.939722 2.014144 -2.089182 -0.869844 -1.640907 -1.831249 -1.181902 -48.152438 -48.031389 36.442691 42.315853 52.546839 0.695807 0.436097 0.484652 2.051230 2.018043 2.255837 0.604807 0.983496 0.371777 1.704982 1.129254 2.122011 1.385476 1.952028 1.993180
+1 0.013186 1 1 0.807531 0.487253 -0.869090 1.613709 1.801057 -2.027619 1.808559 1.539266 -0.572571 -0.509655 1.356784 0.223313 68.622604 -9.897543 2.002336 53.254963 6.161661 2.260575 1.475273 1.407227 0.765679 0.267099 1.882078 0.835614 1.167005 2.098879 1.866989 1.489696 0.826098 0.972703 1.220206 0.756570
+1 -0.007431 1 1 0.956534 -2.207257 -1.436702 -0.371607 -1.691761 1.133670 1.399493 1.746912 2.173843 0.630562 -0.299694 0.587435 17.759587 -14.621956 -51.215101 -72.206796 70.376006 2.268110 2.122883 0.296002 1.647725 1.817131 0.523627 2.345480 1.979516 0.478218 1.909089 0.308178 1.547134 0.938333 1.806727 1.155382
+1 0.002629 1 1 1.945229 -1.084343 -1.745867 1.253959 1.490279 0.780166 -2.335118 -1.547421 0.176614 -0.450309 -0.239560 -1.905392 46.660326 20.105549 -36.037694 14.468846 27.900193 1.653140 0.569846 0.653392 0.817295 1.526396 1.131703 0.539492 1.239119 1.379504 0.572785 0.549996 2.275197 1.981552 0.937671 1.940837
+1 -0.008524 1 1 1.712463 -1.908887 -0.724626 -1.970158 1.508142 -0.595890 -1.298463 -0.195988 -0.003967 -0.692997 1.823009 -0.644075 -19.333761 -42.520677 -45.017229 -4.562436 -30.862435 1.300777 0.403563 0.438886 2.352203 2.480582 2.391359 1.314925 1.937218 0.568771 0.580707 0.947879 0.255060 2.047803 0.670599 2.005474
+1 0.019520 1 1 0.943191 -0.272555 -0.388779 1.867595 -0.557398 0.034556 1.153588 1.587808 0.024597 -1.288963 -0.754318 -1.493071 -18.312487 22.023113 -57.540189 -27.953801 -19.534628 1.847614 2.107634 0.497544 0.480119 2.355937 2.232489 1.942068 1.094338 0.281481 0.606014 1.026278 1.651133 0.593558 0.922765 1.157181
+1 0.010951 1 1 1.290364 0.740715 -0.942687 -0.690418 -1.948752 -1.572113 -0.141600 -0.110506 -0.588693 1.845478 -0.000190 1.525382 53.901644 74.923575 -9.476245 32.749483 70.552836 1.847628 2.328525 0.520077 1.184732 0.797260 2.304998 1.096143 1.381586 1.809250 0.817772 0.548573 0.863768 1.851243 2.338693 0.420429
+1 -0.022849 1 1 0.523059 -2.263763 0.764537 -1.106230 -2.027078 1.468984 1.007677 -0.292353 1.445270 -1.713352 1.104534 1.796352 -31.574249 31.599943 -49.751062 -66.098323 -14.509874 1.863164 2.440281 2.308538 2.102932 2.485358 1.653474 1.679985 1.761263 2.041279 1.271874 0.639853 0.512971 1.007899 0.999889 1.388723
+1 0.012606 1 1 -1.261498 -0.957330 -1.750125 0.384180 0.937340 0.357833 1.097361 -0.941641 -1.958519 -0.782681 -2.243448 -1.811015 -12.970579 -46.525404 -2.463971 -11.958999 5.103901 1.093919 2.255534 2.266309 1.099397 2.064827 1.043434 1.989820 0.411479 0.722696 2.353036 0.721459 1.819288 0.780693 0.608739 1.832444
+1 -0.000411 1 1 -1.575068 2.029057 -1.198432 -1.302755 -1.648780 -2.203203 0.727529 -1.065171 0.034799 0.524025 -0.166328 -1.031059 -49.195828 -34.288196 18.294681 -21.290169 -73.864166 0.849432 1.647927 0.700570 1.736548 0.660233 1.029336 1.297734 1.007068 0.545586 2.419762 1.685605 1.712976 0.493132 0.575325 0.484045
+1 0.009570 1 1 -0.918947 -2.238985 -2.202015 1.834927 1.745214 1.902511 1.941211 2.070837 -1.144407 1.921284 1.734815 1.478722 -8.516378 -34.763781 -24.862333 38.763546 48.919502 1.976159 0.297797 0.317351 0.476088 2.117490 1.906215 1.504040 1.153120 0.479990 2.440711 0.533981 0.873742 0.730802 1.346305 0.600183
+1 0.044826 1 1 2.054693 0.835020 0.680010 1.380869 -0.250884 0.984186 0.728000 2.139625 0.437439 0.707385 -0.330461 1.843914 63.239651 -31.180474 49.780492 -39.268488 14.527642 0.866245 0.732571 1.825311 0.747436 1.910633 1.503643 1.223777 2.271424 1.567833 2.321405 2.353070 1.288603 0.553760 0.287070 2.284537
+1 -0.009635 1 1 -0.537481 0.200594 2.028628 1.020224 -1.476584 -1.499390 1.610881 1.397863 -2.085203 0.032360 1.946393 -0.380459 10.643642 -62.308628 -71.116494 -54.907051 -22.805746 0.682366 1.769512 1.182164 0.383533 1.285231 2.374853 0.653443 1.672369 2.003208 0.418983 0.838980 1.490026 1.874886 1.455852 1.254069
+1 0.006606 1 1 0.560070 -2.251197 -0.091232 -1.809954 -1.431321 0.528021 1.013921 0.969980 2.301620 -0.676126 -2.074428 2.061532 -64.809662 44.005582 -48.186822 -25.920321 -42.834675 0.289178 1.720762 0.842611 1.761024 0.285103 0.728688 1.815219 2.130804 0.682069 1.288413 1.858247 0.809518 1.314781 1.767027 2.165085
+1 0.019631 1 1 2.090826 0.233870 0.513447 1.126399 1.726715 2.002279 1.129313 -1.144089 -2.156428 -0.095475 2.283704 -0.204279 64.178393 -3.749500 -17.854253 73.576653 2.803891 1.750035 2.338298 0.531112 2.157563 0.407104 1.447277 1.138337 1.784995 0.412186 1.361706 0.696622 0.621787 0.629418 0.626361 0.992333
+1 0.042709 1 1 2.060881 1.174187 -0.925275 -0.205857 -0.939122 -2.033848 0.780014 -0.174555 2.075938 -0.237360 2.088359 1.183941 -61.409707 37.054252 -29.188176 -65.680131 -35.955610 2.035955 1.792190 2.092505 0.475869 0.673317 0.432722 2.263378 1.337787 1.436464 1.646678 2.210653 1.695828 0.288681 2.360661 0.637699
+1 -0.015176 1 1 0.340243 2.342852 -0.404196 1.949038 1.668514 -0.718022 0.634264 0.658206 -2.214060 2.033245 -1.495343 -1.062672 -11.853402 -20.130299 70.057168 -49.177112 -19.720979 2.117469 1.559892 1.608262 2.300908 2.117665 0.340880 2.175767 0.364191 2.457933 1.970875 1.488517 1.264051 1.901984 2.388546 1.297413
+1 -0.041038 1 1 -0.300502 1.146605 2.023453 -1.138930 -0.267205 -0.009283 -0.503975 -2.143565 -0.678774 0.538462 2.139554 -0.760305 49.335617 -16.285450 40.440942 40.919322 -18.960752 0.274556 1.212246 1.975244 0.671646 1.602267 0.551587 2.028630 2.441944 1.008508 2.250950 1.714780 1.553668 0.506389 0.623932 0.670964
+1 -0.018577 1 1 -0.417456 0.561724 1.976946 -0.528514 0.125527 -1.420692 0.095872 -0.317183 -1.189617 0.765111 -0.885989 0.325722 -44.343318 71.855421 24.053149 11.277893 -52.446206 0.424184 0.516983 0.939098 1.165676 2.273013 1.273141 1.673054 2.267879 0.494393 1.508945 0.335021 0.447204 0.412084 1.898389 0.470193
+1 -0.008069 1 1 0.494408 1.581822 -1.614407 0.599060 -1.972136 1.259461 -0.291819 0.991180 0.465474 0.656568 -1.473159 -0.491362 -70.590958 -72.224015 -69.016910 -17.213285 46.321929 1.864993 1.682686 2.159174 0.489005 0.949985 1.897843 0.297158 0.827685 0.647265 1.325654 2.275872 2.074215 1.325574 0.917030 1.523055
+1 -0.010485 1 1 0.079619 -0.160374 0.085749 -0.811311 1.951325 -2.306049 1.633285 0.946902 0.845003 -1.177684 -1.296725 0.745950 70.894759 -71.779112 58.456721 -17.896647 -38.943831 2.440503 1.537966 2.088392 1.100194 1.958325 2.073532 1.106951 0.777081 0.645905 0.972635 2.322765 0.455491 2.429069 0.618677 2.346839
+1 -0.013891 1 1 0.885342 -1.783906 -1.889924 2.262273 -2.242545 -0.766567 -0.013652 1.456381 1.249859 -1.446164 0.822439 1.290484 -62.319664 43.400903 -11.024708 -42.260172 -16.707169 1.414064 0.926741 0.484169 0.683275 1.309412 1.535054 0.409581 0.320312 0.727784 2.359262 1.869346 0.589806 0.869985 0.583513 0.855192
+1 0.029144 1 1 -0.190842 1.663344 1.924354 1.498856 -1.159483 -1.702377 1.783010 0.968326 -1.938066 -1.046207 -1.674759 -0.576213 -14.475740 6.242150 61.810572 -49.710187 20.879240 2.385720 1.038882 1.993655 1.852966 2.045724 1.726220 0.332153 1.746046 0.542286 0.944876 1.522613 0.556983 0.460732 0.527565 1.041596
+1 -0.013598 1 1 -0.289469 -1.920180 -2.030587 -0.961798 -1.446569 -1.274345 -0.102845 0.925136 -2.120185 1.142884 0.751770 1.080577 -8.978201 3.382461 -0.979610 35.701229 30.561044 1.967074 0.611004 1.652690 2.015020 0.950347 1.227359 1.719449 1.286361 1.111093 0.632909 0.802852 1.785045 1.258772 0.935787 1.779929
+1 0.067615 1 1 1.066931 1.261896 -1.770652 -0.605913 -0.107097 0.157369 1.254756 0.740915 -2.289325 -0.037535 0.603966 0.364864 46.205675 28.784138 25.012665 -62.147409 -61.506539 2.269104 0.832606 2.359612 1.002200 1.980557 2.228124 0.586826 0.287305 1.727143 2.337380 0.848101 1.787563 0.821036 1.400547 0.986895
+1 0.018313 1 1 0.535828 0.285607 -1.725637 1.978553 -1.792865 -1.665600 -2.141939 -1.625728 -1.185726 0.190272 -1.807867 0.657090 -67.948567 -61.564437 -13.499943 56.452935 54.475315 0.874393 0.430161 1.967087 0.825416 0.761934 0.328427 2.129361 1.168595 1.825318 0.870666 0.788876 0.887243 0.399429 0.707960 2.189701
+1 0.038705 1 1 0.087919 -2.035548 0.484045 1.761699 0.938778 0.960547 -0.735317 2.130576 -0.848104 0.895355 1.576205 -1.769072 -73.959101 19.395905 36.980569 -67.580803 -30.549614 1.414535 2.083172 1.121001 0.659015 0.817522 0.848113 1.993645 1.691189 1.060989 2.297506 1.189939 0.547673 1.491685 0.497375 2.129767
+1 0.006480 1 1 1.913133 1.401112 0.687398 -1.686609 -1.825034 -0.405733 -0.331830 -2.306527 -1.685547 1.888042 -0.901251 -1.702539 -30.233948 58.038228 -1.505963 39.279393 18.762013 1.872196 1.250076 1.026158 1.887312 1.059330 1.417199 1.859773 1.711224 0.286314 0.832152 1.472815 0.605246 1.619378 2.384359 0.670630
+1 0.043215 1 1 0.545122 0.984110 -0.543100 0.019670 0.732296 -1.068227 0.504398 -0.174670 0.136187 -1.321055 1.796564 -2.132113 -45.337461 13.293513 74.073354 -49.147684 24.874644 1.647015 1.135718 0.508305 1.325516 2.202972 0.849658 0.954624 1.108612 1.692730 2.217837 0.933818 2.427469 0.714366 1.850967 2.195958
+1 0.000313 1 1 -0.345853 2.337501 -0.807075 -2.252975 -1.711114 1.012318 2.312371 0.954105 -0.610553 2.020705 -0.201429 -1.919110 57.867219 -25.643418 -38.924501 -54.088384 -63.473350 1.426112 0.920662 1.822756 0.559971 1.181205 2.271118 0.935611 1.068568 1.418086 1.013430 1.726962 1.556304 2.045247 0.463429 0.846781
+1 0.008834 1 1 -0.712909 1.738182 1.526076 -0.780029 -0.081620 -0.480683 -1.810494 -1.069618 0.695214 -2.267178 -0.089218 -0.941231 6.754889 -20.572671 -14.878189 -7.730745 -30.627759 1.963902 1.301520 1.647806 0.928473 0.351110 0.852038 0.459413 0.859795 0.326836 2.389856 0.812581 1.043053 2.343125 0.657247 0.347128
+1 0.007615 1 1 -1.355560 1.509954 1.579419 0.398867 -1.978609 0.846944 -1.544434 -1.464470 -0.535296 -0.765698 0.444906 -1.021058 50.745452 -21.183968 61.055174 4.307424 -55.119555 1.459677 0.288252 1.905804 1.344156 0.485928 0.991136 0.521199 2.038796 2.300791 2.394997 1.715228 2.331886 0.763839 0.844674 0.432124
+1 0.017208 1 1 2.341818 1.064980 1.461650 0.267418 -1.119611 -0.732334 0.426020 2.004926 -1.500468 2.339008 0.963361 -0.553962 39.681956 34.640237 48.459262 -45.182906 60.896384 1.907985 2.003948 1.604921 2.404931 2.168184 1.167522 1.791180 0.857742 1.812654 1.769905 1.042372 2.153048 1.018495 1.351489 2.224724
+1 -0.017762 1 1 -1.348003 1.278247 -0.274976 1.333209 -0.170274 -1.370792 -0.030225 0.943956 -1.539248 0.874515 0.037810 -0.693408 -11.813757 46.183300 -47.273687 21.138607 -73.439413 2.181843 1.233588 0.670621 2.381909 2.239220 0.327106 2.421336 1.139222 0.908012 0.707484 0.936859 1.794450 1.828666 0.895738 1.421288
+1 0.060760 1 1 2.182489 -0.148112 -1.184187 -2.208535 0.631020 -2.041997 0.488282 2.285683 0.086004 -1.234857 -0.886262 0.461597 46.767747 25.531542 -41.379888 -71.780592 33.582954 1.055576 1.318318 0.462764 0.925456 1.397102 1.592205 2.440678 2.225977 0.492523 1.582541 2.009199 2.111690 1.166540 1.028963 1.781753
+1 -0.016693 1 1 -1.232147 2.248817 -2.210344 -1.494279 -2.018170 0.389797 1.102922 -1.737434 1.622176 -1.972863 -1.545171 0.281933 -70.449358 57.634785 -32.168981 -64.069043 41.602489 2.320445 1.970580 1.044557 0.619823 1.364124 0.827635 2.053320 1.145577 1.959361 1.475214 0.419678 1.281611 2.287432 0.626469 0.566871
+1 -0.034110 1 1 -0.931441 -0.180235 0.855895 -1.897399 -0.848100 0.962036 0.729488 -1.135620 -1.195166 1.755229 0.587852 -1.856081 27.561601 27.820903 35.924843 38.830130 -32.012219 1.684550 1.987459 1.225576 1.011575 2.046684 2.113728 1.674806 2.461895 1.074629 2.038769 1.836750 1.756463 2.364464 1.548264 1.928799
+1 -0.023531 1 1 2.324575 -1.292658 -1.582987 0.876814 0.970257 2.246514 1.493218 -1.676318 1.496088 -0.556492 1.133145 2.006750 27.716891 -62.209779 -59.757132 61.877284 21.514647 0.575143 1.931080 0.912765 1.839326 2.295216 0.950397 2.064577 1.342798 2.410097 1.250305 0.375364 1.242850 1.085820 1.132995 1.989505
+1 -0.033872 1 1 0.340221 1.959844 -0.498113 2.131544 1.283888 0.282133 1.147208 -1.972906 -2.261583 -0.290786 -0.485593 0.496777 -32.706991 43.601794 65.351994 70.960897 -10.197147 2.373174 1.682149 2.122312 1.948476 0.786014 2.287990 1.000286 1.302446 1.460827 1.621325 1.363889 1.380098 1.557012 0.443819 2.013307
+1 -0.043005 1 1 -1.412201 1.441506 1.000210 1.443651 -0.643178 0.320554 1.282852 1.705392 1.769369 -2.095182 1.957730 1.663858 36.524337 64.525306 -23.174448 57.049202 25.944319 1.317523 0.604114 0.600244 0.801570 0.480978 1.046786 2.076895 1.369133 1.761206 1.097894 1.555545 0.541020 2.170057 1.144676 0.323789
+1 0.079920 1 1 1.673053 0.172589 -2.127233 0.495448 0.199796 -1.957373 -0.377827 2.153474 2.291395 1.827949 2.268857 0.028179 -74.540934 -9.485783 22.450570 -73.270134 48.859846 0.436469 2.240878 1.182356 1.350388 1.716331 0.630323 2.335205 0.291236 0.304906 0.561735 1.576109 1.913301 1.342845 0.951883 2.296794
+1 0.072764 1 1 -1.982977 -1.886427 -0.233317 -0.647116 0.111378 1.119465 -1.726442 -2.128418 -0.570570 0.148036 -0.106202 1.058093 -37.937920 27.376417 65.442116 -64.357250 -2.292408 1.697495 1.297202 1.075757 0.739438 2.476969 2.410756 1.081452 1.960960 1.356104 1.038720 1.512923 1.944269 2.081434 1.159428 0.751087
+1 -0.019336 1 1 -0.387864 -1.601890 -1.083247 -2.173379 -2.248687 -0.328506 1.720503 1.283312 0.019590 -0.611091 -2.311983 0.863195 -55.218222 -2.658434 19.695196 -32.835424 -14.964067 2.108877 1.149750 2.343962 1.219741 1.944472 0.996482 0.370591 2.016835 2.188808 1.288498 1.040731 1.565495 1.273718 2.376623 1.150851
+1 -0.026255 1 1 1.848296 0.240285 -0.041495 0.026314 -0.712921 1.540980 -0.041044 -1.824567 -1.977204 0.902787 -0.749119 1.062442 38.683177 48.151171 26.722925 32.198421 -41.146328 0.680072 1.473408 1.575473 2.474983 0.533450 0.936566 1.369966 2.266224 1.931723 0.461229 2.128667 0.760936 1.554518 1.291465 1.405971
+1 0.013828 1 1 -1.281231 1.965665 -1.633106 2.059039 -1.524130 0.499949 0.450155 -2.343836 -1.993855 -0.928683 -0.941666 2.325905 70.412445 71.965011 65.933978 -47.624019 -16.885127 1.550156 2.216722 2.451699 0.697099 1.899793 1.574250 2.175175 1.671593 2.463604 0.547473 0.372210 2.230752 2.003810 1.537480 0.677981
+1 0.015383 1 1 -1.715696 -0.588471 0.872074 1.418060 -1.926141 1.459515 2.082967 0.090171 -1.877785 -1.058646 1.317963 -1.934062 9.097524 52.085530 1.502355 50.084637 -27.506320 1.394186 2.089505 1.812538 2.075588 1.912357 1.239447 2.378246 1.437548 1.865626 1.074023 0.847228 0.605572 0.350071 1.390098 0.871486
+1 -0.037495 1 1 0.895988 -1.921192 -0.183346 0.406865 0.498875 1.257540 0.401143 -1.424708 -1.414941 -2.191907 2.076568 0.924192 27.211506 -6.220773 -2.532091 43.143356 10.382244 2.040584 0.851854 1.855117 2.205164 1.687110 2.264292 0.952122 1.812373 1.546043 0.602476 2.314762 0.960581 2.237222 0.486902 1.619768
+1 -0.045437 1 1 -1.530958 -1.167287 -0.919774 -2.007392 -2.238025 -0.194607 -0.355288 -0.732628 0.190026 -1.237719 -1.864686 2.313088 -36.201965 -46.425350 29.144947 -60.878512 -35.145324 1.562979 1.746779 1.607671 1.368506 2.484190 2.282312 2.315919 2.393411 2.058839 1.657182 1.010096 1.931534 1.788556 1.761265 2.086412
+1 -0.013063 1 1 1.856652 -0.682920 1.550862 1.112925 1.465786 -0.904160 1.240182 0.846496 0.363833 -1.742088 -1.207706 -1.661696 70.138689 -29.046734 61.544313 -24.727170 60.456444 1.246883 1.356175 2.238831 0.530432 1.975585 1.909963 1.503147 1.890637 0.681307 1.978717 0.540802 0.754692 2.361782 1.466317 1.641771
+1 -0.019014 1 1 -0.326780 -2.251576 -1.749649 -1.044304 2.040032 -0.526558 0.012111 0.923580 0.006663 -1.105857 -0.477607 -1.947980 62.860498 46.388929 -41.269940 -23.876198 -37.260314 1.613536 0.945399 1.327067 1.267124 1.796858 1.792426 1.548969 0.273909 1.581846 1.583913 0.334907 0.775251 1.401299 2.376996 0.672696
+1 -0.012663 1 1 -1.649199 0.191487 -0.248052 1.460219 -0.217534 0.713809 -0.751895 1.529822 0.919657 0.036366 -1.409420 1.065295 65.459118 71.399928 18.582054 8.584179 -25.704724 1.085493 2.385044 0.942944 0.557188 1.655945 0.468248 0.849157 1.526498 0.610130 0.449621 0.529908 2.155864 1.102482 2.169939 1.414032
+1 -0.013007 1 1 1.341598 -0.551034 -1.391071 -1.568042 2.303369 0.447745 -0.428002 -2.322943 0.433037 2.127731 -1.537714 -1.624276 -11.005824 -24.890724 11.601161 -19.293794 29.210727 1.295286 0.378064 1.614594 0.736952 1.194711 2.000779 2.344707 2.496192 1.494943 1.250190 0.702002 1.055263 0.555470 2.028474 2.059842
+1 -0.016654 1 1 2.094330 -2.133780 -1.168180 -1.789776 -1.582502 -0.381575 0.434352 0.663492 1.795335 0.766166 -2.006198 -1.022123 -69.111277 46.770637 74.093380 -12.558239 -16.316904 0.801798 2.067047 2.366146 0.569851 0.740682 0.891131 0.481455 2.321287 0.375682 2.095664 1.829870 0.870689 1.162634 0.638738 2.026097
+1 -0.015577 1 1 1.444501 -0.497960 -0.012975 -1.307750 -0.772673 1.025088 0.155548 -1.072613 2.199470 -2.206667 -0.956747 -1.368826 0.948890 48.000234 39.939160 7.467990 -35.484838 1.469886 0.878098 1.934781 2.356738 2.192656 0.726815 1.835405 1.658232 0.656935 1.849706 1.252001 1.888850 2.157574 0.598553 1.624651
+1 0.039361 1 1 1.946380 -0.593336 -0.778277 1.087098 0.929889 -2.349321 0.073222 0.709864 -1.092366 0.072763 -2.299869 1.819507 55.961927 52.099559 -62.708705 -45.203080 21.838111 1.121929 0.513682 1.705830 1.875713 1.863719 0.526449 0.281583 2.320141 1.366868 1.950998 0.416126 2.336719 0.988691 2.186129 1.278063
+1 -0.015207 1 1 2.310067 -0.069216 0.647746 1.044567 -2.323468 1.044461 0.609602 0.853190 -0.232828 -1.859330 -1.907465 -0.379378 -10.842882 13.684232 40.892180 -25.130467 32.232905 0.451585 2.031466 0.605772 1.454155 1.987660 2.349577 1.089924 0.351418 1.531489 1.227033 0.745096 0.826230 0.950548 2.352557 1.673080
+1 -0.023663 1 1 2.115031 1.781226 -0.748774 2.139542 -0.957581 -1.256910 0.747205 -0.235381 -2.352224 -1.597937 -0.616090 -1.506576 -43.454973 2.264667 -37.740740 41.379695 68.529910 0.357951 1.084365 1.426698 1.764155 1.154073 0.753178 1.660893 0.372889 2.403608 2.443659 0.573607 0.868953 1.245419 1.504109 2.306407
+1 0.011235 1 1 -0.196396 -2.157325 -1.044733 -0.470887 -2.098124 -0.366663 1.293089 -0.593145 -2.290732 -0.116208 -2.179463 -0.841139 4.818755 -11.177956 -67.908903 5.060260 -2.203720 1.556203 0.356494 1.351232 2.408272 2.079799 0.679503 0.913972 1.875292 1.538043 1.145638 0.738485 2.220897 0.613718 2.251383 2.248932
+1 -0.015913 1 1 2.315657 -0.369957 -2.219379 2.164585 0.545905 0.001917 -0.775999 1.674487 0.724075 2.137979 1.042802 1.003749 -10.945474 -60.589746 18.136520 20.485078 42.700565 2.400994 1.264260 0.916066 1.078880 1.492908 0.799665 2.221987 0.929552 0.486801 2.166418 0.731395 2.306583 0.738374 0.354431 0.422966
+1 0.049232 1 1 1.532407 1.954663 1.960265 1.855620 0.809454 -0.174618 1.011260 -1.334725 -1.749604 -0.286364 -1.573974 1.570344 -41.785308 14.322886 -25.252164 -63.114350 37.116741 0.940890 2.033742 0.611022 1.939141 1.396720 1.921843 0.916175 0.649914 0.856800 1.729329 0.840695 1.060778 0.996057 2.222435 1.714567
+1 -0.059853 1 1 -0.802708 0.464353 0.658437 1.663745 -0.750851 0.229376 0.395676 0.939593 0.520650 -0.347892 1.055306 -0.896192 -48.024413 3.691486 -57.195527 64.779973 57.009376 0.723729 1.719305 1.108580 1.148637 1.645036 1.624016 1.590972 1.969638 0.948854 0.880717 0.953811 0.950797 2.052682 1.669962 2.056636
+1 -0.015365 1 1 0.488762 0.935056 -0.336842 -1.728897 -0.979891 0.779450 -0.227835 1.945345 0.858948 2.295454 -0.630847 0.237261 30.609415 -47.556082 74.925016 14.741281 -43.295777 1.043224 0.708163 1.103041 0.315450 2.272355 1.472810 0.517499 0.600582 1.976388 1.900014 0.782053 0.971726 0.548924 2.268142 0.405143
+1 -0.011917 1 1 -0.161940 2.033097 0.736179 -1.780817 -1.801220 -0.719234 -0.879856 -0.261227 1.500085 0.645960 -0.702886 0.549656 56.590251 -37.654003 -0.831852 -30.939368 52.042052 1.686396 1.508232 1.862261 0.767747 1.279203 2.323198 0.982318 0.811227 0.790864 0.557112 0.379691 1.969598 0.283661 1.240836 0.973958
+1 -0.001043 1 1 0.985845 0.330719 -2.227297 1.040962 -1.652265 0.486860 1.953676 -0.497054 1.079492 0.321670 1.194054 -1.594404 70.318895 -0.338095 17.640924 -58.983155 20.114196 0.764505 0.784840 0.556224 1.211313 2.031280 1.970060 1.306842 1.098170 1.702383 2.451774 1.968563 0.897317 0.959289 0.766957 1.504216
+1 -0.014735 1 1 -0.631133 0.135550 2.097195 -1.109070 2.069351 2.158314 -1.178988 0.338089 -0.879941 -1.696558 0.615857 2.305054 15.751306 -17.805763 -11.451777 -20.010079 -9.389514 1.231484 1.304851 1.385230 2.303904 0.716246 1.943603 2.134400 0.360918 1.450926 1.715702 1.307698 1.983162 1.011595 2.373654 0.749441
+1 0.007427 1 1 -0.258804 -0.191661 2.028741 -1.791582 1.053198 1.370779 -0.192794 1.841042 0.854145 1.682673 1.642229 0.475697 -60.005380 -60.424736 -58.531227 -34.329870 67.880026 0.768853 1.859654 1.949886 1.982450 0.292374 1.432162 1.339067 0.453288 1.403215 0.832719 2.005310 1.986591 2.384996 2.369091 0.567497
+1 0.015763 1 1 0.311895 1.850457 -1.136491 -1.698646 -1.483581 -1.298787 -0.920765 0.191989 -1.233153 -0.512917 -1.633561 -0.880916 24.597510 10.350125 -45.457005 -45.890047 25.985687 0.496596 0.290047 0.567066 1.172103 2.276603 0.869542 2.150738 0.451068 2.342758 1.240864 1.454041 2.314263 1.570070 1.659349 1.432972
+1 0.009437 1 1 -1.198094 -0.333200 -1.767924 -1.886775 -1.361829 -0.188053 1.402165 -0.476588 1.040091 -2.148479 1.550198 -0.619800 67.061711 6.182746 -36.590354 25.924845 -31.127060 2.087492 1.731967 2.419703 0.689128 0.677177 2.306694 0.364578 2.211076 2.053447 1.040974 1.156882 0.717457 2.043104 0.450991 1.060165
+1 0.057817 1 1 1.190756 -0.478203 2.182883 1.770057 0.032391 -2.247930 -1.740878 0.277647 1.145168 1.447995 1.666505 -1.490596 -44.273946 37.792694 -68.189329 -58.045440 30.282156 1.407841 2.080926 1.617441 1.325094 1.848628 1.145929 1.129230 1.723934 2.413189 1.470723 1.442195 1.214487 1.388098 1.015487 0.294378
+1 -0.021216 1 1 1.177831 -0.943907 -2.336092 0.923919 0.991340 -1.552544 -1.112224 0.894431 0.187400 1.756260 -0.938600 2.032780 3.900045 -1.944351 21.297059 39.678387 -25.350058 0.498737 0.275225 1.207565 2.046137 1.928842 1.544321 0.906663 0.535506 1.748752 1.026941 1.541676 1.452312 0.263710 1.170594 1.681493
+1 0.001296 1 1 1.073613 0.482896 1.303221 0.048137 -1.493179 2.319890 0.079749 2.030868 0.962935 1.707993 -1.635095 1.617692 -61.846465 46.464993 37.140478 70.011619 -64.718117 0.364137 1.548164 2.492230 2.403444 1.938116 2.157238 1.696891 2.393046 0.417708 1.920769 0.859620 1.879880 2.138033 0.673351 1.005078
+1 0.022712 1 1 -2.330662 -2.061087 0.087884 2.081251 -0.476060 0.487714 2.159379 -2.140756 -0.602899 -1.278871 -0.783604 1.094888 -3.164311 67.431296 67.792021 -19.510250 -8.771367 1.819413 0.627806 0.533877 1.367651 1.617477 1.929604 0.860269 1.539917 1.130083 0.298544 1.625481 1.458641 0.872642 2.488698 1.551054
+1 -0.031540 1 1 -2.197602 0.610972 0.307506 -1.234463 1.031354 1.805094 -0.144457 -1.003146 1.059671 1.774076 1.604352 0.049272 -40.336166 70.061894 30.250362 67.829549 11.231327 2.348800 1.531196 0.817323 1.993113 1.756162 1.807276 1.381087 2.420940 1.234903 0.258639 1.443723 2.143417 1.163828 0.453726 2.016592
+1 0.032153 1 1 1.133760 -1.799193 0.358825 -1.081292 -2.303538 1.423745 -0.628906 -0.138636 -2.134266 0.098728 0.561479 -2.144421 -29.535523 -53.536054 69.536625 52.064749 -47.769330 0.488011 2.247957 0.918763 1.391615 1.632001 0.786153 2.375928 0.724702 2.319023 0.565474 1.413897 0.361044 1.318360 1.178707 0.772125
+1 0.028976 1 1 -1.681864 -2.184397 1.069625 -0.573507 -2.093191 -2.278460 -1.200854 0.409275 -1.402096 1.632473 1.437769 -0.554534 33.723355 -61.572980 -7.082905 57.614771 -68.545941 0.600602 2.314522 1.424382 1.082196 0.971351 0.991033 1.040307 1.194264 1.244326 1.143846 2.113851 1.489799 0.305950 2.355594 0.970064
+1 -0.040445 1 1 2.339160 -1.193919 -0.846306 -1.878980 -2.299294 2.060585 0.901053 -1.616410 -0.073198 -0.308526 -1.762350 2.269842 -72.182540 28.044929 51.117917 -61.172512 -26.413951 2.285895 1.785639 2.234687 0.636480 2.315187 1.355127 0.367684 0.417935 1.225511 2.166099 2.123633 1.647767 0.269215 1.449757 2.309921
+1 -0.015029 1 1 -1.501720 0.154541 0.841088 -0.997728 -2.142453 -0.839784 -0.645420 0.339892 1.150093 -0.599339 1.993533 0.220760 53.127002 -44.484697 -54.300724 -32.267209 -64.988418 1.969760 0.751432 1.572955 0.655834 1.348321 0.735818 2.391485 1.189385 2.488271 1.127875 1.450368 1.331708 0.507230 1.261829 0.569128
+1 -0.017674 1 1 -0.113948 -1.901357 -1.404582 2.253123 -0.512589 -0.831334 0.003939 0.234604 -1.272455 -1.328294 -2.043282 -2.264410 -21.541802 46.932197 -60.572458 8.694000 20.061897 1.079642 0.789098 2.365773 1.040927 0.367086 1.614451 0.570916 0.637591 0.737594 0.735057 0.852550 2.308807 2.115464 1.609014 1.447947
+1 0.005512 1 1 1.367577 -2.158920 0.434818 -0.927599 -1.579251 -2.304140 0.732978 0.980937 -2.048805 -0.831683 -1.158577 -0.615626 50.367442 -74.398089 -8.687141 -54.772434 -10.306093 1.907513 0.822653 1.572537 0.371082 1.278604 1.252950 2.073780 0.776119 2.476243 1.456979 2.202449 1.059080 1.710981 0.710723 1.364554
+1 -0.031466 1 1 -2.292908 1.006939 1.431589 -0.734597 0.091855 -1.849203 -1.340682 1.802053 0.574531 0.458900 -1.450220 -1.380149 -56.740745 58.291985 63.385918 27.127895 -61.467679 0.815862 2.186021 1.705638 0.902625 2.412770 1.181340 2.284991 2.352170 1.914178 0.337209 1.213251 0.853858 1.787840 0.980694 0.520198
+1 0.063570 1 1 -1.803468 -0.809616 2.168627 -2.216457 -0.557219 -1.668168 1.818984 -2.312553 0.703255 0.927787 0.020400 -1.135372 -55.029482 19.502857 34.525799 -74.898767 -23.578237 1.683521 0.436063 2.155182 0.894742 0.433284 0.456082 1.118973 0.331121 2.403109 0.802196 2.013894 2.258976 1.604032 0.974278 0.695730
+1 -0.007165 1 1 1.026918 -2.070737 -1.877841 -2.005084 -1.145294 1.158311 0.852776 2.235512 0.374051 0.353223 -0.988375 -0.451632 34.269330 -35.377684 7.264885 0.917031 -37.461950 0.280170 1.063235 1.785764 2.084600 0.369261 2.168199 1.418649 1.477072 2.404616 1.384099 1.305444 2.340524 1.935409 1.670382 2.355087
+1 0.026933 1 1 -0.027749 0.148748 -2.267183 -0.168106 2.077860 -0.917745 -0.894333 1.468810 -1.909638 0.788764 0.801600 -0.224639 -28.028584 73.589992 -73.002326 49.904593 -53.500774 2.312311 0.262231 1.065658 2.013135 0.759380 2.398147 0.651623 0.331756 1.827973 0.498134 1.393661 2.266227 1.971132 1.319761 2.229267
+1 0.047144 1 1 2.005806 -0.844597 -1.424128 -1.102793 -0.818492 -0.934118 1.967180 0.281609 1.759185 1.094434 1.703636 0.534007 -64.909107 22.645295 49.466264 -70.501681 -71.757588 0.928395 1.285217 2.147376 2.441862 1.875877 2.357799 2.022844 1.930750 2.114734 0.582458 1.116168 0.437702 0.464031 1.974682 2.475631
+1 -0.000470 1 1 0.062389 -2.287358 0.044444 -2.295700 1.203982 0.325508 -0.264783 -1.711613 2.050565 2.145860 1.556158 0.582866 -26.571669 -40.037940 -17.662788 -8.476621 33.425800 1.936219 1.790125 1.129565 0.605134 1.989247 2.028629 2.415178 1.149273 1.080748 1.381329 1.989717 0.915971 1.731344 0.953632 2.441187
+1 0.033371 1 1 -1.060172 -0.774775 -1.318023 0.933446 0.884137 1.530427 1.664675 0.745425 -1.876986 -1.771904 1.902904 -0.872961 -69.649851 -5.053478 -33.801690 -55.003901 -0.559460 2.082228 1.010100 2.006409 2.460575 1.387383 2.492224 2.301574 2.059381 1.759463 1.042111 2.261492 1.140199 1.576283 0.336749 2.488037
+1 -0.015025 1 1 -1.615384 -1.690782 -1.272834 1.731911 -0.194318 -0.219499 0.680807 0.650092 -1.930007 -2.254901 -1.080592 0.040894 -22.221961 15.499335 -52.683126 4.694140 -5.589503 0.733318 0.880447 0.916784 1.896748 2.152451 2.237322 2.178244 1.488088 0.799420 0.350628 1.761854 0.729739 1.465597 0.786941 2.118022
+1 -0.065786 1 1 -0.815988 -1.257361 -2.110910 1.507099 0.716099 0.032881 1.278025 0.693080 -0.428948 0.629250 1.199140 -0.943384 55.338270 70.305038 66.779679 66.063158 23.489077 1.088855 0.386608 1.213176 1.841656 0.965289 0.354554 2.490847 1.664322 1.765537 1.883351 1.984103 1.072185 1.468474 1.886476 0.496977
+1 0.003143 1 1 1.292264 -0.323712 2.186646 -0.962647 -1.570175 -0.558434 1.473267 2.314532 -0.425880 0.353386 1.747044 -0.328126 -42.059388 57.867511 -20.750372 -1.499354 0.359052 1.893837 0.467265 2.319912 2.007167 1.703286 1.872899 1.821096 1.918094 0.905305 2.461101 1.230683 1.340176 1.084717 0.584171 0.657019
+1 -0.010575 1 1 -1.932954 0.044544 -0.613637 2.030731 -1.335445 0.278163 0.400309 -1.292545 0.312064 -0.036597 2.234451 1.397005 74.374583 63.621803 -58.350797 -1.851660 -70.847704 0.814565 0.637061 0.827607 1.586496 0.995359 1.740905 1.891470 1.185885 2.163545 1.943687 1.293270 2.484504 0.809705 2.213188 1.551516
+1 0.007328 1 1 1.459480 1.492946 -1.519273 2.014910 1.369127 0.327117 -1.505531 2.077598 -0.614984 -1.761891 0.551106 -2.118743 57.811037 -69.907391 16.475565 4.820270 14.269875 1.131792 2.028185 1.699491 1.095865 1.207629 0.870060 1.846824 2.323225 1.439790 1.306673 0.499861 1.168611 2.089828 0.486177 0.670851
+1 -0.005438 1 1 -0.209763 -0.613598 -2.032997 0.957687 -1.670849 -0.831885 0.169104 0.567330 1.945952 1.634283 -1.123248 -0.591479 68.802637 15.921992 0.924454 -62.705711 5.123214 1.462811 1.222183 2.476819 2.152906 0.888770 1.313937 1.092431 1.986232 0.857093 2.155628 1.637020 1.886327 2.498283 0.644065 1.550703
+1 -0.015272 1 1 -1.791887 0.637114 1.431426 1.229981 -0.958562 1.098255 -0.059284 -2.076354 -2.036968 0.180251 -0.581870 -1.279854 49.127444 -65.050523 45.865780 16.161080 -30.731906 0.457844 1.481986 1.739701 1.907556 1.550887 0.999301 0.501806 2.350067 0.328432 2.202369 1.968852 1.239566 2.138422 0.458050 0.448013
+1 -0.009291 1 1 -1.007133 0.023737 -1.605973 0.978710 -1.775098 0.054023 -1.531666 1.069189 1.521525 -1.864892 -1.134944 0.750694 58.998050 -69.777601 -52.147447 7.861326 -24.700208 2.328978 1.382045 0.528054 0.250555 0.581220 0.558278 1.985744 1.649965 1.205438 2.299196 0.331498 1.985195 1.429103 1.678626 1.415199
+1 0.006296 1 1 -0.502693 0.549638 1.480428 0.133124 -0.974823 1.126608 0.527526 2.127736 -1.454105 -0.699867 -0.547140 -1.913650 -20.899757 37.777517 -23.267529 -7.367271 -71.719623 1.499383 1.635173 2.357770 1.547268 0.938400 0.690627 1.113204 2.365411 1.718526 1.512644 1.751013 0.770058 1.865755 0.994513 1.037782
+1 0.013015 1 1 0.582556 -1.333508 -0.142470 -0.600155 -2.288105 1.617581 0.905907 -0.148877 0.103123 -0.976038 -0.444972 -0.089721 0.989053 -26.980113 -4.756164 13.144119 -36.796520 1.538383 2.354777 0.733607 1.224404 1.554040 2.248703 2.196639 2.414848 2.344779 1.456551 1.761186 0.746676 0.382880 1.557680 0.422074
+1 -0.067074 1 1 -1.899245 1.113749 1.173781 1.681738 0.058139 1.679761 -0.171216 1.634178 1.822436 -0.849083 -1.428160 1.832540 -21.421610 -32.991112 68.385635 57.374276 -60.547130 1.140782 2.377865 1.783210 1.914744 0.849857 2.047649 0.343280 2.000501 2.163038 2.426511 0.374949 1.025138 0.485912 0.726415 1.854168
+1 -0.043599 1 1 0.303368 -0.106294 -0.480099 -1.411123 0.713157 -2.284431 2.110118 -0.688324 0.252219 -2.098536 2.129079 2.266267 -34.707309 24.255946 -30.323424 54.211940 40.078342 0.575302 2.351359 1.790701 1.819205 1.633727 0.554129 1.999360 0.995404 0.262845 2.391012 2.244530 1.816669 1.757806 2.449435 0.897896
+1 -0.018584 1 1 0.457431 2.139693 1.573850 1.055471 1.869248 -1.047066 -1.986347 -1.971953 -0.388162 -1.900361 1.211103 2.196394 -65.401528 -3.478405 38.443879 -73.724902 55.580278 0.440906 0.304860 2.027309 0.490910 1.475265 1.278098 1.740828 0.595987 1.248889 1.325772 2.004650 2.147995 1.608310 0.858472 0.594334
+1 -0.053614 1 1 -0.005738 -2.186267 -2.097079 -1.645423 -2.321185 1.704616 -1.839045 -0.270549 0.344259 -0.859720 -1.128450 1.503954 -9.486284 14.023918 49.993372 -61.390561 58.834250 1.783610 1.882017 2.056313 1.961721 0.653720 1.827589 0.790934 1.720789 1.305912 1.219238 2.481164 0.919873 2.053755 1.717237 2.355738
+1 0.008953 1 1 -0.740050 -2.025396 1.476618 2.075912 -0.674509 1.535111 0.289133 0.992374 1.682150 2.272204 -0.271921 0.833183 -60.981104 40.578349 -49.685029 -6.280812 38.383989 0.920464 0.731667 2.380906 1.135752 1.091825 0.802809 1.063486 1.500857 1.647502 0.322366 1.506987 1.183113 0.585068 2.244077 0.958135
+1 -0.041496 1 1 -1.330110 0.414910 -0.942647 -0.024091 0.375485 0.884720 1.893839 2.272447 -0.892080 1.633803 0.229962 0.809873 68.384288 34.728676 34.862878 40.385714 12.700971 1.603188 0.288659 1.995902 1.371776 1.181025 1.492085 0.464120 1.207423 1.901515 1.259110 2.117297 0.913774 0.793026 0.884950 2.356284
+1 0.000360 1 1 -0.561585 0.356287 -1.325203 -1.939310 1.618358 -0.159453 1.419712 2.276295 -2.190854 0.922835 1.612808 0.806066 -18.251044 4.695319 14.222168 -68.021875 56.342381 1.320944 1.851520 0.251715 2.068445 1.100408 1.051914 0.523372 0.308013 1.020918 1.564896 2.453206 1.278685 0.364063 0.303783 1.931222
+1 -0.055991 1 1 -2.048128 1.109714 -0.664829 -0.701269 -0.540323 -0.434285 0.461265 0.598205 -2.201037 -0.571134 0.091141 0.278254 61.178467 -23.502830 -62.068441 65.704031 -12.357944 2.125425 0.271715 0.707872 0.703157 2.459161 2.364768 2.164779 2.435295 1.751700 1.077097 0.770981 1.633890 1.035266 1.965137 1.812270
+1 0.000833 1 1 -2.154537 -1.304953 -0.892709 0.486082 -1.709544 -0.864403 0.269442 -0.100635 0.369033 0.835442 -1.641102 -0.386691 -23.478883 40.411598 -2.272251 60.282056 60.510163 1.289708 1.127272 0.305509 1.690551 1.597684 2.270837 0.715730 2.265637 1.055107 2.429108 1.274835 0.909228 0.898607 2.383452 1.176303
+1 -0.001540 1 1 1.189791 2.153680 1.037217 1.374526 1.534885 1.191763 2.302524 0.390119 1.801071 -1.793351 -0.415546 -0.322097 33.620182 4.400994 17.500519 -18.781405 -59.075164 0.980769 1.785904 2.185516 2.216214 0.667301 0.579876 0.480915 2.240842 0.584096 1.654555 1.862095 2.476263 1.808426 0.472594 1.893876
+1 0.014209 1 1 0.222903 -0.024107 0.097218 -1.248162 1.695183 -0.155589 0.385890 1.412034 0.457903 0.648291 0.775250 -0.124291 -43.613321 40.906626 67.670508 38.226475 22.371821 0.672995 1.772044 0.994692 1.782143 1.983585 1.361149 0.326257 1.644377 1.794754 2.423099 1.518365 1.165973 0.514501 1.963471 0.813134
+1 -0.052391 1 1 1.800268 -1.145852 1.205494 2.178005 -0.113419 2.291552 -0.245981 -1.438079 0.050562 1.571573 0.494452 2.308413 12.506464 46.136560 67.162325 47.191524 -52.049417 1.456718 2.303268 1.280094 1.537290 1.982856 0.365514 2.200278 0.576333 1.674063 1.222724 0.321528 0.922111 1.420579 2.421578 0.705146
+1 0.012372 1 1 -0.947262 -2.187351 -1.455031 -2.123267 1.175961 0.612621 -0.240766 1.393192 -0.477164 0.794883 -0.029611 1.844944 14.570190 -68.810281 5.603852 -16.062607 35.758952 0.635555 0.278827 0.995750 1.574435 0.781549 1.499507 1.466543 0.944647 2.182370 1.095097 1.791238 1.830833 1.313542 1.207640 1.056525
+1 -0.036992 1 1 -0.606258 -1.185562 -1.754943 -0.487247 0.974348 0.312939 0.543779 1.968603 0.631024 -1.965653 1.822932 -1.941250 63.603553 -65.079513 8.616770 72.046425 -65.737665 2.080983 0.336465 2.209217 2.310497 1.276676 0.337922 1.960329 2.004107 2.025358 1.446507 1.699071 0.793698 0.933449 0.726448 2.417913
+1 -0.012840 1 1 0.886806 -0.737184 -0.973246 -0.638586 2.114415 0.839706 -0.672445 -1.469846 -1.362047 0.857748 0.967287 -0.544054 -59.917680 63.545519 9.530260 -24.920389 -36.971823 2.343488 2.257964 0.355288 1.318805 1.903410 1.607064 2.430117 2.479856 1.445964 1.562893 0.288638 1.637939 1.596421 1.304799 0.502351
+1 0.004599 1 1 -1.578604 -0.853405 1.326943 -1.805878 1.100022 1.376083 -0.579977 2.261375 1.513725 -1.004876 0.247997 2.330110 70.488129 -6.020281 67.141325 -5.751119 -59.066194 0.992124 1.380179 0.665114 2.064658 0.449263 1.256654 1.325846 1.001566 0.327247 0.287255 0.894116 1.152517 1.601015 2.005496 0.625437
+1 0.009551 1 1 2.195178 1.059899 0.899697 -0.846453 0.369027 0.740179 -0.520056 0.892500 0.707722 0.620322 1.947505 -0.538924 -15.624387 50.921445 -63.277752 -9.179320 73.163403 0.734833 1.596374 0.510072 1.780538 2.002674 0.439175 0.458927 1.688854 2.324495 0.282141 0.441299 2.412479 0.790701 2.307714 1.753370
+1 -0.000843 1 1 -1.378888 0.567131 -1.395568 -1.750245 -1.636930 -0.958586 0.700605 -1.192292 -1.777512 1.894472 -1.216283 0.276035 74.003167 -28.779147 58.872318 67.045175 28.251155 2.382543 1.654030 2.029871 0.787166 1.395716 0.802403 0.995153 0.529826 0.790806 1.827434 0.439754 1.189984 1.315422 1.302742 1.929370
+1 0.041610 1 1 2.044234 -0.582894 0.351118 1.321193 0.516274 1.501748 0.318604 1.507020 -0.601287 2.248682 0.231362 0.774546 69.488113 -13.290705 -26.883869 -37.181817 -14.804202 1.911529 0.814727 1.122124 1.542469 1.278332 1.174999 1.458637 0.815658 1.012063 1.238703 1.130218 0.316555 0.592645 1.330565 1.553022
+1 -0.013799 1 1 -0.052943 0.829908 -0.401337 -1.837887 0.343567 1.656498 -0.034314 -1.810701 0.151220 1.571995 -1.849932 0.539230 28.969714 -6.014441 15.298083 14.880214 41.763712 2.465492 0.782251 2.049960 0.927172 0.981853 2.001594 0.296281 1.846898 1.321075 1.804923 2.341553 1.229533 2.259286 2.325674 2.112114
+1 0.018285 1 1 0.198666 -2.101110 1.292640 1.282261 1.200763 -1.940054 -1.460373 2.351838 -0.176618 0.380382 -1.624879 -1.052531 13.242155 -39.107869 14.045103 -43.957698 -47.025670 1.218393 1.780260 1.826745 2.352462 2.325438 0.383673 1.393173 0.809856 2.497224 0.836752 2.298838 1.075818 1.773281 1.539938 1.484805
+1 0.037573 1 1 2.297299 2.105347 -0.767107 0.337024 0.069435 -1.682482 1.564307 0.890493 -0.030331 -0.842333 -1.073810 0.930238 -37.869895 -29.328387 -22.198349 -37.657960 -67.328207 1.597308 0.463034 0.967695 0.305318 0.725581 1.334306 1.427349 1.453987 1.410482 1.467833 2.362347 1.974387 2.026564 1.457962 0.715546
+1 -0.023691 1 1 0.858229 -0.363572 1.409343 -2.355426 1.132099 -1.440932 -0.773516 0.999216 -1.130653 2.172175 0.869109 -1.298488 -19.308125 -61.655570 -45.166583 35.240367 -65.149654 1.821595 1.304837 1.147733 2.191070 1.056040 2.361362 1.163005 2.380190 0.346764 2.056720 2.048791 1.526215 0.353427 1.544281 2.482789
+1 0.060903 1 1 -0.997194 2.130451 1.758275 -0.058038 0.017756 1.536748 -0.474154 -0.457624 -0.670020 1.590591 -0.312557 1.174016 29.341828 -51.897415 10.143818 -62.849294 -8.087659 0.935830 2.493811 1.984553 1.883720 1.432288 1.219074 1.981748 1.997591 0.520660 1.987917 2.176084 1.191894 1.912989 0.598892 0.582698
+1 -0.076874 1 1 -0.578314 1.938593 0.475315 1.119574 0.118562 -0.670453 -0.985976 2.181430 0.901395 -0.580616 0.947432 0.324380 -12.258127 -72.335399 8.946868 70.014022 -24.325834 2.210659 1.800886 1.986180 2.228704 1.327745 1.401486 1.018096 1.383776 0.369267 2.271724 2.117626 1.935373 1.063899 1.695924 1.892821
+1 0.014314 1 1 -1.488681 -2.191782 -0.541687 0.203896 0.976452 -2.018463 0.186737 0.043266 1.458806 -0.408546 -0.486741 0.050469 0.063543 17.960718 65.783760 -22.340696 -30.076908 1.336068 1.802125 0.313863 0.339729 0.817671 1.096913 0.812874 1.480657 1.895785 1.704684 0.619470 2.179216 2.079054 1.664182 1.660236
+1 0.024352 1 1 1.395668 -1.275433 0.455077 0.269660 -1.147653 -0.801822 1.209328 0.643045 2.153866 -0.550180 -1.170800 1.300020 -60.618294 -11.674309 -10.115726 -65.006980 27.694308 1.498475 2.117743 1.649870 1.864100 2.437848 1.912435 0.289209 2.233528 1.402530 0.571623 1.259784 2.189357 1.528449 1.888208 0.370873
+1 -0.012001 1 1 0.938386 -0.917127 0.067324 0.542518 -0.371317 -1.525950 -1.827125 2.155178 -2.049862 0.240469 -1.666179 2.265458 -17.716058 -3.794873 -30.423976 14.228025 30.410762 2.330211 1.859706 0.586146 2.354464 2.227961 2.337763 0.534224 0.446287 0.747316 2.142973 0.450131 2.343801 0.756126 1.708918 2.041032
+1 -0.038369 1 1 2.122753 -0.386845 1.399127 0.305835 -1.055738 -1.637003 -2.177869 -2.311912 2.050059 -1.651981 0.552059 -0.229980 -35.465349 33.872217 40.344309 66.801347 -19.757098 2.011931 0.775273 1.757588 1.036148 1.038285 0.948782 1.922822 1.621971 0.969988 0.596596 2.489225 1.412175 0.671324 0.691272 0.705621
+1 0.011621 1 1 -1.734806 -1.325039 0.823438 -0.758053 1.700459 -1.024216 0.361909 -1.094527 1.451568 0.462705 1.247905 -1.304572 25.789034 -63.713090 24.089716 25.862323 -31.941573 1.494857 2.052527 1.328485 0.349803 1.393942 2.490652 0.631749 1.561630 1.559991 1.017184 1.806825 0.566488 0.460081 0.832820 1.462340
+1 0.064257 1 1 1.624206 -0.832845 -1.824437 0.204412 0.218464 0.766498 -1.146473 0.180402 1.949782 0.039281 0.467719 0.687941 -62.997482 51.319026 18.863408 -62.700035 -49.495259 1.872786 2.169923 1.140136 0.516043 0.879705 1.946138 1.993592 0.803591 0.696014 1.653410 0.605164 2.499319 2.306664 2.108644 1.733646
+1 -0.003258 1 1 0.591996 1.831737 -0.027656 1.712129 1.911949 0.348409 -1.790577 -0.902694 2.309660 -2.200815 -1.554569 -2.158160 -29.705432 -59.190755 -19.026790 16.743248 3.762463 0.410665 0.552678 2.362691 0.995986 1.041888 0.758644 1.277909 0.812520 2.271377 0.788532 1.860573 1.647619 2.275030 1.422053 2.449790
+1 -0.008376 1 1 1.196976 0.382424 -0.304624 -2.155661 -1.342842 -1.515045 -2.330054 -1.264509 0.277769 -1.514209 2.308075 -0.567802 -14.710604 -41.118278 -24.897385 49.651601 44.453938 1.185119 0.541018 2.140878 1.238918 2.488246 0.703614 1.135526 1.783895 2.177566 1.349465 1.955857 1.082180 0.706559 1.140162 0.956540
+1 0.032404 1 1 -1.243376 2.020920 -1.291118 0.730741 1.082741 -1.623171 -0.622353 1.618264 -1.751306 -0.625520 0.217374 1.310479 -15.550433 -56.122764 -55.300892 -42.087465 35.975011 1.105090 0.992167 2.108871 1.036839 1.398292 1.351758 2.249019 0.763548 0.446409 0.554156 2.457537 2.079251 0.476321 1.531023 2.403718
+1 0.012234 1 1 1.028725 0.032027 1.069076 -0.374374 -1.071030 0.527621 -0.986677 -0.185131 -1.324730 1.304433 1.568158 -0.356758 -59.852782 -45.699659 -74.166457 -15.650325 64.994242 2.248454 0.257432 1.413179 1.806277 0.353075 2.374359 1.346189 0.893487 1.828695 1.373691 1.868241 2.270714 0.887511 0.405604 0.990048
+1 -0.001717 1 1 0.792511 -2.185028 -0.119771 -0.805717 1.727112 -0.739238 2.192734 -2.314431 2.121037 -0.959604 -2.277546 0.026597 -20.860636 -54.705331 67.504632 -49.653433 74.746168 1.507709 2.071207 0.283184 2.228291 1.132026 1.455647 2.301373 0.919972 1.466094 2.389399 2.126284 1.202473 1.967184 2.466060 1.311347
+1 0.023303 1 1 0.226932 1.722669 -0.013064 1.907938 -1.086134 1.142024 0.439924 0.058226 -1.578451 1.729991 0.513802 -2.343073 44.883430 5.803930 46.657471 -27.883399 -36.293252 2.414721 2.468294 0.620095 1.439204 0.451294 1.645529 0.899821 0.285253 0.994164 1.908590 0.926313 2.285633 1.889382 2.085065 1.431376
+1 0.007584 1 1 -0.342397 -0.833083 -1.118272 -1.792580 -1.589816 -0.784964 1.803807 1.779909 0.684596 -1.651215 -0.716883 0.921136 42.502106 32.894188 -47.389612 22.788241 51.969489 1.393084 1.555684 0.637991 0.721965 1.318696 2.325350 1.155123 0.405775 1.607992 2.272951 2.483028 0.748316 0.953967 1.329835 0.542244
+1 0.002296 1 1 0.602174 -1.466973 -0.191916 -2.249959 1.860738 2.015237 2.141702 -2.352393 0.281041 1.635905 -2.140312 2.145386 -54.102547 -1.508066 3.926901 -0.580809 -11.654480 1.722412 1.582836 2.479204 1.730792 0.670010 1.112851 0.942020 0.777801 1.496738 2.169341 0.370039 1.746103 1.503209 0.687388 0.682973
+1 -0.004970 1 1 1.700004 0.760463 1.106275 -1.924495 0.854373 0.793358 -2.094135 0.700472 1.284782 1.173378 -0.381484 1.960594 -64.637389 -60.595457 72.149231 12.128617 -4.334028 2.244875 0.858360 0.963517 2.077880 2.179810 0.819180 1.704613 1.685859 1.476248 2.052659 1.284793 1.773045 2.073507 0.673392 1.695347
+1 0.003272 1 1 -1.622636 -1.047196 0.543025 -1.280259 -0.551334 -1.711670 1.090703 0.249245 -0.253944 1.391825 0.107135 0.477351 74.859972 -28.444804 -21.812946 -10.181834 23.914682 0.385942 1.270914 2.498313 1.145473 2.466407 0.398065 0.286511 1.885944 0.558551 2.063536 1.851468 1.614891 1.225710 1.011238 0.873503
+1 -0.008570 1 1 1.316419 0.384751 1.119851 0.056817 -1.690464 -0.630080 -1.008926 -1.851250 1.937858 2.262471 1.087468 -2.281933 53.587387 43.217277 52.779232 -39.448920 -18.004570 0.583000 1.231709 0.577615 0.728306 2.144311 0.431541 0.402535 1.161843 0.844521 2.368610 1.482507 1.495730 0.977633 0.829081 1.616470
+1 -0.033251 1 1 1.312121 -1.164632 1.288746 1.805614 -0.830859 -1.446894 -2.017452 -1.670646 -2.140130 0.496066 1.165067 1.313675 44.337896 -12.975490 20.940836 52.637387 -23.444739 1.589090 1.841237 0.665604 1.310737 1.313024 1.492166 1.832382 0.347195 0.302080 0.300387 1.098304 1.696182 1.723906 1.936522 2.378852
+1 -0.018193 1 1 1.425652 -1.556984 -0.330582 -0.178118 -1.268458 -0.119056 1.789469 1.138757 2.075814 -2.329060 1.307731 0.449523 37.255487 52.973777 -69.726066 64.008579 -7.818188 1.370726 1.550105 1.371774 1.151900 2.474206 0.978913 2.090957 1.458241 0.902498 0.290758 1.268730 1.791451 0.925338 1.653303 1.064524
+1 0.000626 1 1 2.069686 -1.644118 0.751448 0.380252 0.901395 -0.592565 -1.965971 1.190873 1.487402 -0.465683 0.550734 1.057010 -17.151074 41.905296 52.317638 2.544373 13.277916 0.804007 0.948417 0.294564 2.232335 1.601366 1.159746 1.607616 0.457382 0.466623 0.538617 2.278848 0.346741 1.682505 1.352335 0.696636
+1 -0.009716 1 1 0.266176 1.556240 1.963723 -1.276202 1.658519 0.951136 1.327127 1.289941 -1.663914 -2.081160 2.015248 2.330532 -3.857688 -36.166754 -54.626221 47.110070 -71.055146 0.267441 0.873917 1.428499 0.528449 2.394115 0.399018 0.553623 2.499917 1.108828 0.816238 1.753756 1.875125 0.976097 2.019314 1.107767
+1 -0.022550 1 1 0.457823 -0.694690 1.637535 1.703162 1.994946 0.407752 1.278593 0.811418 -0.144456 -0.995843 1.269288 -0.064445 22.977019 74.755325 12.751668 -32.713005 -57.467547 1.268992 1.699155 2.198975 1.181190 2.012384 1.644989 0.823320 1.538712 1.128137 1.350482 1.046575 0.786856 0.683724 2.100661 0.302922
+1 -0.051290 1 1 -1.219122 -0.323254 0.446335 -0.576232 -0.772240 -1.110550 0.760848 -1.846016 0.371408 -1.656250 -0.515734 -1.849731 -25.654831 69.247667 -4.467778 60.057255 32.281488 1.449649 0.499928 2.289268 2.235712 2.112262 1.783242 2.441140 0.982834 0.494916 1.307165 2.025314 0.693691 0.862114 1.056658 1.491922
+1 0.012107 1 1 0.953747 -1.914803 -1.184400 -1.075327 -1.007600 1.587942 2.282040 0.108140 -1.479242 0.938168 0.130776 1.977586 25.546892 66.614418 -11.478900 -25.872217 15.641400 0.400160 1.735327 0.385642 0.732233 0.635120 1.955300 0.727611 1.705290 1.805939 1.423907 2.103197 2.433263 1.353844 1.313511 0.680188
+1 -0.044770 1 1 0.311433 -1.216773 1.457711 0.039950 2.285492 1.583817 -1.070642 2.339426 -1.442908 -1.005601 2.208088 1.264523 -0.918636 10.478585 13.579612 -67.465245 -38.376602 1.441758 0.632719 2.110668 1.993938 2.110179 0.533904 1.826586 1.927604 0.997895 1.624680 1.494335 2.287289 0.471316 0.663046 1.060231
+1 0.052720 1 1 0.461890 1.684225 -0.557090 0.501351 0.454218 -0.036101 1.146268 1.082074 1.312235 0.747458 -0.706356 -1.220073 -69.033643 1.557484 -73.365203 -48.959180 43.064444 1.886715 2.275956 1.248950 2.359141 2.076698 0.319021 1.531116 1.713007 1.003680 2.094281 1.080534 2.291297 0.323802 0.887529 0.693992
+1 0.002010 1 1 0.901784 1.238344 -1.778612 2.272121 -1.667753 -0.630805 0.936965 -1.230031 0.127857 0.046195 -1.138969 -0.918706 57.450393 18.755494 73.581151 -71.593382 30.035797 2.299485 0.685228 0.380264 0.343203 0.712167 0.885812 1.084201 0.912808 0.312735 1.628934 1.000439 1.628233 0.467279 0.300347 0.440032
+1 0.057263 1 1 -0.638797 -1.431315 0.637299 -0.180829 0.303505 2.208979 2.101000 1.582712 -0.797956 0.207777 0.229121 0.819038 21.578019 -38.228110 -49.840029 -61.374693 25.531087 0.639788 1.670259 0.300571 1.951508 2.251291 0.706689 1.080393 2.168281 0.547019 1.747898 2.419455 1.022021 2.105338 2.408721 0.624411
+1 -0.002955 1 1 0.016771 -0.878673 0.761566 0.787083 0.823766 0.038531 1.994939 0.286709 -2.053164 1.298362 -1.509791 1.162086 -53.204743 -62.115911 17.876905 7.134732 63.438997 1.663214 1.132787 0.755394 0.651405 1.161531 2.360112 0.409758 1.047732 2.240447 0.692209 0.702959 1.377387 0.998556 1.478560 0.414321
+1 0.023640 1 1 1.996819 -1.102490 -0.440100 1.683665 -0.533031 -0.408003 -0.785120 -0.821781 0.334734 -0.722016 -0.527507 -1.812036 40.805588 19.511167 24.185402 -15.953799 64.495003 2.387646 1.908460 0.984285 2.385970 0.750629 1.574153 0.534796 1.061581 0.982691 0.335097 1.723934 2.401655 1.116908 1.618851 0.278855
+1 0.005448 1 1 2.230455 0.204327 -1.211261 -0.147212 -0.184770 0.034251 0.749417 -0.770388 1.732561 1.302370 -0.115227 0.175880 42.633012 -16.961973 70.113632 -0.179751 -21.066776 0.335323 1.017741 2.166960 0.841125 1.529688 2.465697 1.976337 1.049201 2.177567 1.361545 2.484433 1.858995 2.133038 2.216393 1.420044
+1 0.015708 1 1 -1.723143 1.475257 -1.947806 0.195201 0.915017 2.168114 -1.416940 1.895874 -1.222805 -0.956861 1.418344 -1.874367 -5.013351 40.608680 10.083968 -18.757665 39.924098 2.189656 2.043498 0.323051 1.760776 0.605229 1.335832 2.336063 1.217610 2.120173 1.996755 2.219559 0.626708 2.327361 1.207607 0.505423
+1 -0.073060 1 1 -1.584130 0.530269 1.103086 1.028154 -0.149119 0.742865 2.212688 -1.523704 -1.777311 0.560152 -0.876203 -0.129791 14.030676 13.572382 -38.970802 67.731807 18.482681 1.201285 2.241529 0.880763 1.739328 2.385518 2.147660 0.466403 1.338720 1.368348 2.069687 1.729263 1.972767 1.788697 1.887328 1.314278
+1 0.018242 1 1 -0.603220 -1.966620 -0.286342 -1.199485 -0.151088 0.649710 1.078786 -2.119722 -0.514519 -0.289916 -0.002841 -0.619777 -70.182089 49.623640 24.524292 -20.225133 -23.806802 0.311159 2.152267 1.393733 1.217306 1.516443 0.357236 0.315750 0.567340 1.289692 0.847759 0.532059 2.313173 1.252210 0.888529 1.752609
+1 0.006874 1 1 0.118559 -0.725811 1.661350 1.410536 -1.143065 0.910274 -2.152089 2.143508 -0.271720 -0.500178 0.403423 -0.800438 29.077995 13.862943 44.481696 3.858209 44.915069 0.438487 2.402786 2.127589 0.640829 1.164760 0.368581 1.996259 0.618721 0.846768 1.875710 1.804393 2.437131 1.104340 1.887479 1.608017
+1 -0.019105 1 1 -2.151698 -0.714221 -1.449372 -1.257575 -1.004920 -0.484421 1.345529 -0.453203 -1.758216 1.051056 -1.643785 1.636104 38.313099 -21.753273 -57.258832 50.813639 74.824239 0.939835 2.298875 1.688693 1.865933 1.737114 1.167986 0.586848 0.656026 2.334071 1.482023 2.367104 0.917227 0.340442 1.551789 0.420585
+1 0.026127 1 1 2.019167 2.224597 0.707292 -1.907230 -1.148719 0.128450 0.579813 -0.310222 -1.997502 -0.950140 1.275391 -1.153417 41.213692 -21.485424 -55.514407 -30.640168 -19.297735 0.819537 0.955010 0.859766 2.081821 0.907641 1.214853 0.786871 0.948551 0.293451 1.536913 2.401686 1.628529 0.941369 1.082175 0.619481
+1 -0.043324 1 1 -2.234431 -1.055672 -0.535333 -1.399054 0.923516 -1.069116 -0.284687 -1.663447 1.041097 0.619782 2.303197 2.264099 5.384852 53.210409 7.340129 65.545212 18.380947 0.303717 0.820601 0.841952 1.942856 0.822044 0.347960 1.918901 0.962148 1.566376 0.336493 0.442681 0.892938 1.600948 0.876509 2.240461
+1 -0.037874 1 1 1.753972 -1.688965 0.987522 0.253748 0.029940 -1.031100 -2.238193 1.697463 0.463739 -0.235912 -1.856274 2.327617 -63.545469 -8.699100 44.233489 32.257040 44.078123 0.940245 2.446696 2.123269 2.278084 1.012110 2.035666 1.438953 0.734317 1.914904 1.284734 0.776445 1.215987 1.836170 1.010860 1.274917
+1 -0.002553 1 1 2.000891 1.370988 -1.395892 2.235080 -2.173011 -0.780244 1.021014 -2.330542 -0.050488 -0.317107 0.100845 -1.557120 66.331623 35.585441 34.502240 -20.855136 37.721351 0.366166 1.896097 2.459150 2.176789 1.791530 2.239962 1.548844 0.424014 2.145025 1.181014 1.303348 0.864590 2.157275 2.324258 0.810797
+1 0.003919 1 1 0.355986 -1.682647 -1.194974 0.272427 -1.763479 2.134625 1.218135 -2.135097 0.271091 -0.651157 -1.827880 -1.106261 68.957371 66.526668 13.702076 40.793172 -39.165273 0.613835 1.981588 1.545475 2.297002 1.705587 2.298836 1.041040 2.252235 0.818787 1.858281 1.382842 0.431220 1.762707 1.559825 0.471456
+1 -0.031339 1 1 -0.156781 -0.789479 1.315308 0.566525 -2.145824 -0.943640 2.148367 1.273926 -2.222784 1.489260 -2.211631 0.443659 50.368033 -64.468775 73.304677 -68.300166 29.116279 2.234425 0.725448 1.355105 2.256077 2.378856 0.426106 1.310066 1.279387 0.912262 2.381529 0.354095 1.518609 0.769335 0.961055 1.206096
+1 0.030780 1 1 -2.137826 1.527649 2.095506 -1.218126 2.278563 -1.769650 2.087038 -2.182301 -1.416972 1.373751 -2.073235 -1.449524 28.659634 32.470055 24.206522 39.013918 56.914462 1.545396 0.967374 1.652106 1.193945 0.376140 0.776696 0.928403 1.413149 1.296945 1.255360 2.085596 1.354253 1.434443 1.433808 2.007112
+1 -0.041749 1 1 -1.165157 1.892166 -2.274641 1.718594 2.173144 -1.695503 -0.506601 0.845030 -0.716451 -1.242162 -1.138255 1.654904 46.281549 -46.005647 33.098910 -56.621458 -36.838742 2.144018 2.261599 0.697779 2.076717 0.630864 2.437169 1.745971 1.532849 1.588048 2.314053 0.295791 0.358162 2.372643 1.766104 2.413504
+1 -0.008654 1 1 2.348089 -1.930777 -1.063260 -0.833089 -1.224563 -2.225674 0.038133 0.017649 -0.246922 1.589646 -2.060766 0.760991 17.344653 61.581755 4.554007 39.196543 -23.708737 0.283973 1.982570 2.302180 0.987503 2.469103 0.713178 2.130207 1.887549 0.527470 1.686734 0.442542 0.803749 1.113369 0.651982 1.866456
+1 -0.030027 1 1 1.856488 1.268197 0.447229 0.309592 0.827836 -2.238072 -0.994811 -0.239313 2.242418 -1.374074 1.350560 -0.721771 -35.427820 64.633751 -0.542965 24.380463 -37.564806 1.349514 0.538972 1.496844 1.704206 1.582043 0.395771 2.220333 2.384826 1.772349 1.624166 1.865217 0.951101 0.400125 1.151754 2.270469
+1 -0.014152 1 1 -0.541170 -0.529456 -1.576582 0.156018 2.106514 0.008880 -1.558214 -2.159923 -2.292026 1.697884 -1.895950 -0.064449 20.944902 -29.031366 19.829760 -21.219758 59.519259 1.227701 0.722136 1.940619 1.491513 2.117228 2.000272 0.576405 0.636430 1.478410 2.380779 1.246747 1.327792 2.201213 0.542555 0.969118
+1 0.065107 1 1 -0.191251 -0.508456 -2.050710 0.134898 0.567019 1.442977 2.151896 -0.671880 -1.410517 1.464962 -0.618978 1.790423 -53.477270 7.516350 27.287914 -72.029799 45.166048 0.711648 1.166146 1.171572 2.365842 2.198741 1.738619 1.726803 1.124808 1.640775 2.012221 1.147968 1.651602 1.720845 2.245758 2.197603
+1 -0.052923 1 1 -0.118512 1.514546 -1.344974 0.358591 -0.309664 -2.040591 0.555337 -1.690354 1.218133 -2.172051 1.209499 -1.200305 6.701962 -10.129149 9.391665 45.720851 -19.664869 0.513151 1.772387 2.258402 0.957377 2.384102 0.854178 0.426331 0.589750 2.184753 0.646674 0.408203 1.912457 0.660713 2.352140 1.414865
+1 0.021411 1 1 0.311671 -1.916373 0.691953 -0.518580 2.139190 -2.155466 1.923183 0.654382 -0.516197 -0.222681 -0.968770 -0.808743 -64.076664 63.506347 -48.833314 58.495662 36.598744 0.851325 1.967987 2.462713 1.325262 2.434100 1.924844 1.859547 2.405442 1.768194 1.531792 1.827276 2.284531 1.357868 1.431281 2.292422
+1 0.018251 1 1 1.629189 -1.907113 0.825810 1.401274 -1.315794 0.682975 -0.619804 2.051263 -0.257724 -0.874388 2.100470 2.097139 -65.380709 46.418998 14.107290 -48.782867 6.353245 1.059905 2.072201 1.235001 1.905851 2.136224 1.767777 1.277769 0.707800 1.747059 1.815243 0.295381 2.468898 1.774639 1.858373 0.672426
+1 -0.003743 1 1 -0.985834 -0.153727 -1.307724 -0.334381 1.944354 -1.665088 1.746187 -0.600399 -1.683732 -0.588148 1.591946 -1.108293 31.556538 -29.257506 -30.907161 -6.658858 -15.430024 1.638757 1.838250 2.220119 1.034458 1.877901 0.379994 0.315703 2.022490 0.496159 1.943434 1.545336 2.206158 0.397767 2.013784 0.412532
+1 -0.002446 1 1 -0.692942 -1.960092 1.041301 -0.667220 1.526356 -0.772991 0.396791 0.836191 1.514010 -0.943476 0.192493 -2.185799 33.854515 42.831143 13.015315 48.403916 74.617106 0.470526 0.883075 2.334402 0.301485 1.557320 1.132549 1.251859 1.752223 0.853693 1.272365 2.142871 0.984982 0.587529 0.849767 0.532507
+1 0.020618 1 1 2.252325 0.208341 0.279525 -0.275343 -0.122548 -0.346413 2.342050 0.246328 -2.150297 -0.733983 0.983660 1.312169 -11.180985 31.178999 -74.559169 -15.945663 51.242022 2.495002 1.751749 1.888711 2.068456 1.294815 1.450572 0.259575 1.427290 0.459095 2.261084 1.041473 0.528252 1.336784 0.325318 1.622826
+1 0.033024 1 1 1.779040 0.221575 1.221724 1.633097 -2.199997 -1.950910 -0.139646 -0.265449 1.229915 -2.068272 1.849846 -1.984481 35.334691 20.150312 -33.706036 52.659915 55.191093 1.325412 0.456514 1.626465 2.249173 1.102348 2.167318 2.365928 1.404187 1.426467 2.381756 1.913891 2.265615 0.695225 1.894112 0.586404
+1 -0.005431 1 1 0.066574 2.066345 -1.250746 0.682269 1.648648 -0.015958 0.402264 -1.422225 -2.094527 -1.171707 0.198370 2.342977 53.864026 42.682856 70.769070 65.764472 -46.514389 1.864926 0.565533 2.409334 1.935202 0.448191 1.253648 0.320243 1.823316 0.970133 0.778269 0.358846 0.374794 0.663938 0.303854 0.872211
+1 -0.004458 1 1 -2.097641 -1.663961 1.829881 1.765205 -1.403756 1.999069 -0.978510 0.427059 0.606230 0.724440 -1.152437 -1.083597 43.595628 -38.276570 35.684983 57.511934 3.080629 1.766865 1.707739 2.467310 2.079422 1.091817 0.671778 1.574952 0.467651 2.062331 1.850086 0.887550 1.050388 1.862262 0.793827 0.845998
+1 -0.002518 1 1 0.246417 -0.654150 -0.293603 -0.707591 1.594450 -1.442084 -1.295098 -0.179613 1.878664 1.691319 0.869381 -1.431523 58.842263 11.909780 67.675478 -28.239555 -22.200211 0.340683 1.116815 2.312169 2.366834 0.873685 2.031184 0.360127 1.661710 0.610862 1.503683 1.901243 1.195441 0.775733 0.494125 1.500674
+1 0.021869 1 1 -1.750858 2.195014 -1.699492 -1.577941 0.875448 1.574361 0.212693 -1.968465 1.688231 0.805498 -0.688724 -1.764827 -53.444854 -47.655650 51.486828 -10.888385 -1.090180 1.035230 1.351857 1.662537 1.015031 1.624458 2.265647 1.232151 1.261183 0.950631 1.513187 1.892668 1.068685 1.146089 1.564970 1.454771
+1 0.018451 1 1 -0.584475 2.056601 -0.075687 0.272700 -1.893232 -1.503972 -0.010341 0.561060 0.238503 -1.717584 0.663974 0.474249 65.193455 -43.605563 21.297851 52.989867 50.696906 2.318421 1.701378 1.314901 1.547118 0.666374 0.750127 2.126041 1.621687 0.691380 0.266987 2.252810 1.481925 0.717039 1.779202 2.047942
+1 -0.001503 1 1 -2.305492 1.569726 -2.276373 0.890692 -1.401828 1.429400 0.168924 2.253715 0.002367 2.079719 2.052789 1.829298 44.304660 28.421317 -72.918988 -49.431623 52.714291 2.411290 1.054568 2.376204 0.864726 2.193248 1.670646 2.296935 0.589472 2.010638 1.543844 1.886247 1.149444 1.698199 1.873646 0.873380
+1 0.050122 1 1 -1.945539 0.595714 -1.656287 -1.130243 -0.354142 -0.315309 2.041185 0.011805 0.482639 1.686161 -0.993066 0.821676 -67.003591 70.638532 -28.187926 -54.473434 65.000130 1.482867 0.799518 2.002331 1.424162 1.882652 1.480051 0.716218 1.476322 1.039221 0.939551 2.036150 0.565025 0.630519 1.137307 2.464809
+1 0.011046 1 1 -0.306882 2.303959 0.947506 1.570880 -1.732072 2.198063 -2.277005 -0.311724 1.038645 1.815886 2.162908 0.619962 19.488150 -62.668118 36.947178 -28.778437 70.813792 2.386035 1.837776 1.008113 2.347793 0.348768 1.997297 2.322491 0.359244 0.311462 0.491874 1.923314 0.881311 1.941647 0.766426 1.563747
+1 -0.020200 1 1 -0.536177 -1.432892 -2.304954 1.182538 -1.937510 -1.121530 0.000238 -0.710056 -2.136888 -1.567495 2.081186 -1.569284 9.056988 -29.208914 35.776036 -62.158561 51.062092 2.133701 2.104911 1.993396 2.011121 0.662573 2.117119 2.425153 2.299788 1.280787 1.944332 0.895055 1.190796 1.464485 2.350659 1.271593
+1 0.048375 1 1 -0.980214 0.062381 2.283777 1.035325 -2.146714 -1.764848 -2.023709 1.555690 2.148398 1.806154 -1.177479 2.150901 46.609670 68.722578 20.370718 70.659714 27.814046 2.434971 0.806402 0.701005 2.295195 0.592152 2.053862 1.264780 0.658958 2.112780 1.487569 1.072588 1.482270 2.019314 1.106887 1.943684
+1 0.004616 1 1 -0.335203 2.258634 -2.135952 0.033007 -1.317364 -2.131633 1.932427 0.517201 -1.759323 1.300912 -1.051159 -0.083347 -39.271607 -37.898858 -66.098423 -16.200370 -29.618000 2.279037 1.282111 1.687083 1.807594 2.228917 0.408303 1.340908 2.136296 0.725143 0.730808 1.435250 1.494260 1.034192 1.910097 1.494797
+1 -0.019262 1 1 1.021731 0.291677 1.327160 1.832090 1.189371 -0.204515 -1.957582 0.814981 -1.534726 1.483209 -0.248988 -0.135562 -73.219596 -1.756429 29.694898 32.154761 -24.933013 2.137695 1.732913 0.319502 0.617426 1.581476 2.123243 1.852361 0.882586 0.878560 0.706377 0.327671 0.661004 0.495791 0.251307 1.958695
+1 -0.014445 1 1 -0.782892 -1.084202 0.629779 0.665313 -0.577404 -1.625048 0.816673 -1.372930 1.740698 1.396346 0.696724 -0.453038 32.083241 -26.965893 -65.767022 3.657974 -20.435843 1.896710 1.506805 0.363067 1.572682 0.572143 1.000211 2.288853 2.007434 1.686340 0.559477 1.878124 1.884762 0.937636 1.348459 0.795475
+1 -0.029749 1 1 -0.106018 -0.554604 -0.131839 -1.001766 0.684561 -2.232790 -1.750693 0.259867 -0.803853 0.059978 -0.392730 1.439015 49.311445 27.452026 -13.795786 34.227105 4.948674 2.460475 1.948225 1.072946 0.760490 0.810058 1.389379 2.299885 0.669019 2.447222 1.962308 1.503711 2.368155 0.575459 0.494748 0.737682
+1 0.019309 1 1 1.659776 -1.495758 1.395305 2.039508 0.096299 2.154162 -0.278005 2.253603 -1.875608 -2.181092 0.059420 -0.360631 -31.854694 -31.843857 0.302366 -18.139063 -63.233489 1.146202 1.221550 0.842456 1.415021 1.266545 1.071119 1.545785 0.754539 2.029444 0.362737 0.521094 0.281350 0.648543 0.319674 1.264179
+1 0.013007 1 1 -0.872039 -0.833166 2.198433 -0.777139 1.368585 0.643162 -0.602176 1.438316 -0.773471 1.753578 1.102636 -1.827417 62.134339 -8.171038 69.371448 -24.068562 29.671241 0.393147 0.866866 2.162455 1.625404 2.419409 0.251454 2.190677 1.208810 0.464385 1.162266 1.210135 2.486754 0.379564 2.086597 2.441996
+1 -0.002108 1 1 1.456507 -1.345013 -0.305265 1.197421 -1.549558 1.957864 -0.796288 -0.032318 -1.244144 -1.452547 1.931996 -2.014297 -15.738372 -64.812918 -10.713653 -64.363293 46.128754 0.414557 0.708347 1.930835 1.300247 0.493559 0.994365 0.794900 0.880717 0.968638 0.399137 0.296965 2.082637 1.134167 1.440913 2.171672
+1 -0.014189 1 1 0.497370 -0.479667 1.131587 -0.610693 -0.342144 -1.292220 1.067710 0.225156 0.143467 -1.497065 -1.734236 -1.173250 -69.017419 -25.753810 55.710618 28.358336 68.555961 2.425457 0.650823 0.388423 2.481009 0.564115 1.073344 0.697634 1.878914 1.661862 0.921980 1.475435 1.886990 2.396574 1.225230 1.940917
+1 0.004940 1 1 -1.950443 -1.726754 2.043488 1.012371 -1.524059 1.679842 1.189615 -0.810106 -1.357586 0.435362 -1.213623 -2.144447 -43.584247 -70.442661 20.203019 -47.854561 8.401153 2.097700 2.286382 0.977112 1.076416 0.574758 2.205090 0.450548 0.359534 0.689018 1.070854 1.588916 1.160516 1.038923 0.424748 0.994748
+1 0.008647 1 1 -2.184737 0.055628 1.887531 -0.074221 1.349922 -2.005029 -0.231533 1.065190 0.275333 -0.046846 -0.374869 0.036553 55.150738 68.457871 71.431981 -42.699210 -45.614332 1.523833 0.807255 1.537043 2.335542 1.452742 0.728165 2.012349 1.057066 1.606021 0.650204 1.236239 2.476032 2.418279 1.510002 2.357044
+1 0.046815 1 1 1.494713 -0.110718 0.552039 -0.576771 -0.406479 1.267492 -1.970855 -0.777502 -0.023293 -0.364955 1.736618 -1.197252 -10.185218 -32.952891 -39.236541 -48.550947 4.231453 1.645541 1.112031 0.649494 0.543574 2.342255 1.776763 1.559231 1.742389 2.082146 1.883597 1.607346 0.407606 0.887518 0.507316 0.455143
+1 -0.031883 1 1 1.867294 -0.896623 0.683076 1.075427 -2.027630 1.620798 -1.565630 0.432603 -0.452265 -0.141782 1.537044 -0.219867 -24.938579 -42.697981 -24.975022 -55.199814 6.725769 0.474974 1.392344 0.376015 0.933809 2.283671 0.404816 1.236579 1.437759 0.919523 0.679969 1.995898 1.305265 1.590017 1.669155 1.990636
+1 0.054924 1 1 2.281761 0.139827 -1.417248 1.438336 -0.448108 -0.949604 0.867734 -0.830917 2.293979 -1.868612 2.309450 -1.017522 -7.394916 63.652313 4.423525 -53.817865 -16.863872 2.408517 1.688179 2.224665 0.938509 0.269532 2.271226 0.495128 0.374604 1.974518 1.978470 0.891198 1.617116 0.375111 1.497170 0.440357
+1 -0.050652 1 1 -1.549269 2.098669 0.094728 -0.692274 -0.162604 0.307711 2.206672 1.039765 1.800297 -0.653824 0.478050 -0.033975 -25.898727 20.099503 12.345901 47.558264 -38.262389 0.985409 1.021414 0.904921 0.513691 1.861584 0.642120 0.354137 2.237387 1.015567 1.631648 1.613536 0.957444 1.263723 0.893714 1.159411
+1 0.041363 1 1 1.089994 -2.246547 -2.048459 0.256002 0.209205 0.661408 -0.241369 0.676720 -2.080408 0.501490 -1.927409 -1.008751 34.918861 -68.698433 -64.564863 -41.652924 -10.692379 1.272860 1.453155 0.918988 0.681302 1.892660 0.934168 1.557471 1.409594 2.290966 1.521298 0.956815 1.936502 2.046106 1.400544 0.947662
+1 0.035860 1 1 1.667351 -1.411063 1.721260 -0.145473 0.771219 -1.900794 -1.351560 -1.955284 1.740494 -2.030626 -1.618352 0.270133 66.544492 13.279056 -18.906063 -54.202824 -36.859554 1.397142 2.263050 0.333727 1.191774 2.147231 2.259063 0.814815 0.338013 1.234611 2.099686 1.918021 1.928164 1.394956 1.527486 1.448753
+1 -0.010511 1 1 1.338298 0.536400 0.470110 -1.541086 -1.739086 2.133604 -1.802539 0.671539 0.389808 1.279397 0.186711 -0.397240 33.333998 -5.499677 -33.069803 -54.176070 -37.214683 1.867395 1.551355 2.128279 0.986961 2.351238 2.006542 2.451151 0.498830 1.839691 1.683917 0.344327 1.599600 0.733586 0.886393 1.851392
+1 -0.026714 1 1 -1.525506 0.930159 2.183083 0.419103 -1.152187 -1.607607 1.788578 0.298002 -0.753361 0.446403 0.567998 -0.961314 62.918264 -32.730007 -43.229420 43.135667 31.162626 0.628897 0.876548 0.646145 0.505612 1.067106 1.600551 0.958613 0.655910 0.384049 0.960961 1.867223 0.921032 1.289184 1.321444 1.260486
+1 0.014181 1 1 0.997867 -0.243084 0.135714 0.152422 -1.774941 -2.008806 2.267641 -1.560551 0.975489 0.637872 0.028569 -0.510937 -42.983270 -19.813845 -11.296854 33.773668 34.037652 0.937196 0.695778 2.187031 0.681631 0.677748 0.660419 1.904217 1.679632 0.327693 1.035660 1.841247 0.833685 2.499160 1.881825 1.077062
+1 0.011744 1 1 2.076798 0.086178 1.685114 0.250841 -1.705281 0.088026 -0.232331 1.789733 0.871143 -0.093706 -0.978418 1.957800 -59.318564 -67.105707 4.375625 41.136357 28.749910 2.121142 0.290440 0.431659 2.385663 2.337749 0.304915 0.704863 1.889179 0.923433 1.136458 1.699121 1.622393 1.312147 2.495989 0.337132
+1 -0.021182 1 1 2.165879 -1.279509 -2.082205 -1.415247 2.084003 -1.351823 -1.657354 -0.217748 1.838056 -2.219373 2.275339 0.583499 12.478387 24.251104 38.302684 -46.786500 -40.698649 1.042077 1.690245 0.947043 1.943816 1.213620 0.307379 1.610616 1.377897 0.566041 1.954667 1.343600 2.386606 2.435954 1.570345 1.781077
+1 0.029377 1 1 0.215378 0.741155 1.749833 -0.569943 1.260314 -0.088477 2.088116 1.804947 2.102076 0.803984 2.134841 0.135011 -71.555906 59.888690 49.207819 -64.183578 66.596226 1.116642 1.658443 1.946868 0.759354 1.961876 0.992045 2.307577 1.699682 2.054444 2.037519 1.072901 2.256071 2.290738 2.192149 1.199743
+1 0.016178 1 1 -2.211046 0.842145 -2.086662 -0.926549 1.932012 -1.738318 0.906410 -1.119004 0.035403 1.263622 -1.040890 -1.847259 -52.742113 63.306423 41.057485 53.144138 -56.468830 1.050691 2.462699 1.088822 2.078867 0.771357 1.195074 1.357625 1.846955 2.278653 1.565031 2.480638 1.084462 0.795894 1.834260 0.400280
+1 -0.003532 1 1 0.129582 0.764340 0.284998 2.169964 1.398915 1.464638 -1.340842 -0.881180 1.044646 -1.000107 0.285362 -1.133176 69.762938 -44.309226 44.844263 -52.478640 -8.510371 2.368034 0.793871 1.586858 0.319134 1.180229 1.613642 0.479841 2.186031 1.864104 2.496875 1.720433 2.064549 0.872823 1.033035 0.461806
+1 -0.046590 1 1 -1.097031 1.779016 -0.193704 0.677469 1.086800 0.625148 -1.758141 2.308732 1.042811 1.151162 -1.491144 -1.175547 51.823114 -58.917732 69.680728 73.999284 55.958325 1.248468 1.005767 1.172966 1.040953 0.801086 1.345185 2.030651 0.392681 2.045593 1.788296 1.891175 0.733384 1.978705 0.351519 0.980402
+1 -0.042592 1 1 0.209893 -1.905115 1.409259 0.948776 -0.638944 0.809648 -1.618622 0.440049 2.169657 0.958564 -1.075315 -0.805419 64.068953 -43.103978 51.445672 47.413578 -69.998277 1.209260 1.276078 1.539721 2.343741 2.009191 1.978158 2.401683 1.579857 1.907864 2.222676 1.274311 1.088397 1.695644 1.693189 0.936042
+1 0.002295 1 1 1.200128 1.528909 -0.292341 1.639780 1.728081 1.398913 1.423111 -1.866506 0.006668 -1.029034 -0.509592 -2.297234 -31.905783 9.512258 -27.472171 -24.785862 -25.979529 1.555966 0.867329 0.955429 1.141805 1.573694 1.823265 2.360287 1.096290 1.591222 1.663388 1.808208 1.298108 0.553689 1.359006 0.308977
+1 0.041101 1 1 -1.021815 -1.697798 -1.372920 1.897700 1.190717 -1.132359 1.778804 0.961412 -0.332301 -0.798823 -0.228616 -1.750366 32.929377 -55.961453 -44.137794 -73.899417 -27.502651 2.319116 2.139730 2.194022 1.171492 1.010434 0.859786 2.419796 2.268368 1.963988 0.498831 1.852123 1.381693 1.373381 1.165335 1.034343
+1 0.023327 1 1 0.275717 1.696655 1.016233 2.132785 -1.426372 -1.116869 -1.767606 -1.252209 -0.339301 -0.640412 -0.306189 -0.187659 -44.311666 3.823913 68.512365 -62.685591 43.265802 0.900049 1.875108 0.694929 1.425622 1.669863 0.391708 1.444449 0.858640 1.166846 1.678389 1.937533 1.358473 0.354033 0.484255 2.123525
+1 0.007772 1 1 -1.550078 -2.068049 0.887174 0.741439 1.810865 -2.111630 -1.163545 0.709211 2.078709 -0.788902 1.586481 1.287356 64.236278 69.117896 64.476898 63.219291 -73.369686 1.760269 1.097070 1.199044 0.584028 0.508769 2.381257 0.290390 1.835125 1.449462 1.854778 1.007383 1.336204 1.833009 1.877803 0.993506
+1 0.011594 1 1 1.914983 -0.504125 0.053916 1.386320 1.825319 0.478456 2.076934 -2.346824 -0.381465 2.283450 0.239773 0.777642 -74.362540 -11.211937 -39.026461 32.277195 -67.182919 2.225174 0.506505 0.328479 0.753752 2.313553 0.885434 1.483343 2.042517 1.828637 0.400370 0.769872 0.981523 0.957842 1.207699 2.045060
+1 -0.061528 1 1 2.114726 1.360458 0.700618 -0.970417 -0.216140 0.582630 -0.089109 0.877808 -1.169524 -0.807938 2.085792 0.443649 45.120452 -60.555725 -10.063855 56.786380 -41.316406 0.552408 2.324221 2.423215 1.232475 2.205055 2.103961 1.779904 0.345419 1.953260 2.441134 0.894400 1.433679 2.094827 1.258148 1.690292
+1 0.016199 1 1 -1.770054 0.017399 0.249943 2.057480 0.559641 -0.034126 1.355413 0.737906 -1.019374 1.627223 -1.962907 0.859540 -60.139216 -59.799568 -51.337007 -21.080614 -1.873560 1.541160 1.784612 0.729110 2.154066 2.389713 0.658925 1.545830 1.508658 2.267443 2.158064 2.077868 1.984470 0.484641 1.862475 2.122553
+1 -0.075548 1 1 -1.947846 -0.479425 0.494574 -0.341486 0.335064 0.113145 -2.172051 1.210273 -2.320470 -0.412845 -2.054012 1.181505 -14.557713 -21.474328 -19.032768 66.276145 3.176069 1.077850 2.176526 1.867291 2.059863 0.865813 2.463087 0.858483 0.771942 2.028846 1.569009 1.828352 2.364876 1.719894 2.001326 0.280139
+1 -0.049237 1 1 -0.602030 -0.814855 -1.057565 0.636195 0.116788 -2.207280 -1.824763 -0.562963 0.762451 1.526268 -2.261430 2.272068 68.677806 17.888793 56.943113 42.900960 -13.569315 0.482770 1.917687 0.814467 1.253161 1.130883 2.496790 0.295292 0.973901 1.110579 1.001925 1.844901 1.501985 0.359424 1.081040 1.782833
+1 -0.042272 1 1 0.349220 -2.287971 -0.832940 1.287653 2.295933 -1.998882 -0.590078 2.137126 0.849307 0.475077 1.835033 -1.183246 -17.019325 6.205864 51.948966 -43.736566 69.532780 1.186507 1.375336 0.273343 1.068141 0.991913 2.338766 1.644823 0.295378 2.411193 1.663643 1.591431 0.680341 1.490026 1.861855 0.695435
+1 -0.029494 1 1 0.291371 0.894368 -0.871635 1.249271 -1.913248 1.379935 -1.815316 -2.007467 1.205551 -1.582525 -0.778930 -0.452187 37.358402 -17.330918 19.255441 -73.800282 -11.339465 2.389297 0.412737 1.628564 1.521015 0.698263 1.205360 0.987230 2.375920 0.592615 0.822888 1.025549 0.660958 1.965186 0.389433 1.444958
+1 0.016100 1 1 0.022163 0.211518 1.845014 1.625717 0.996564 1.424591 -0.546902 2.092464 -0.519165 1.737754 -0.951134 -1.288771 -71.165146 27.394280 65.665945 -52.458294 33.449921 1.267267 1.960939 0.997983 0.849725 2.085688 0.666870 2.334993 1.220240 1.321777 2.354337 2.340540 2.210132 1.942705 0.552008 2.350943
+1 0.027246 1 1 1.449594 0.281885 1.691134 -2.248604 1.076951 0.033612 -0.565744 1.146923 -2.053632 -1.856424 -0.191275 -0.902380 -58.543391 61.226973 41.739924 -27.098052 -36.963403 2.216223 0.804936 0.803419 2.306111 1.812062 0.828733 0.270806 1.188716 2.491174 0.415019 1.731862 0.661411 0.580799 2.496479 1.821431
+1 0.008731 1 1 0.860818 0.731144 -1.569156 -2.271171 -1.222812 -1.079453 0.326918 -0.140636 1.948757 1.660775 1.163447 2.349807 -42.023733 57.122430 56.688626 -34.265799 -55.284741 0.315406 1.521018 0.746495 1.839864 2.343929 0.672021 1.153907 2.463613 0.699758 1.584491 1.049112 0.668077 2.372386 1.935829 1.976088
+1 -0.033439 1 1 -2.308098 0.174984 0.419823 1.516612 0.393143 0.778221 -2.029405 0.057417 -1.024665 2.231746 -1.666082 -0.826569 -0.807748 74.179723 -61.392068 33.514380 26.188461 2.116941 1.682712 0.333224 1.752326 0.346454 1.343953 1.574807 0.279058 0.380421 0.743460 0.333557 0.588376 1.581012 1.064755 0.345179
+1 -0.004096 1 1 -0.289315 0.666683 -1.125817 -1.372228 -0.603508 -2.090534 -0.026089 -0.222680 -0.941589 -1.075700 2.139164 2.113614 48.584782 -35.566289 -12.618934 13.582778 -14.249847 2.167208 0.517582 2.006299 0.623130 0.688749 1.058199 0.393539 0.715258 1.092794 1.333534 1.949008 0.727398 0.383272 1.407129 1.360014
+1 -0.010457 1 1 0.391419 0.078775 -0.203432 2.114198 1.905312 1.888778 2.044377 1.818605 0.742599 -2.257608 0.532014 2.155187 -60.745850 -55.502334 22.266282 -20.602335 -63.447652 1.154814 1.960723 1.869792 1.338440 1.164596 2.116137 1.668853 1.416366 1.369847 0.265135 0.376592 1.636621 1.940361 1.653455 1.365483
+1 -0.052920 1 1 1.557506 -0.312818 1.492379 -1.639935 0.378525 0.152012 0.751966 -0.331451 -0.649401 -0.584256 1.026475 -0.095273 30.667086 21.707271 34.104726 48.133048 22.144895 1.963766 1.256355 0.810286 0.733884 1.384097 1.265611 1.128951 1.532122 0.620535 2.086232 0.806571 1.282057 0.788144 2.094363 2.462708
+1 -0.009543 1 1 2.235370 -2.019961 -1.441744 -0.294119 0.032031 1.138265 -1.482301 1.358605 -2.169526 1.234448 -1.281075 -0.119772 -25.947288 -46.075372 61.224944 7.631824 18.067441 2.267229 0.819124 0.761475 1.612969 0.428982 2.407223 2.453739 1.244159 0.582657 2.213808 0.713896 0.701139 2.294135 0.784611 1.204518
+1 0.027818 1 1 -2.121282 1.550664 -2.214358 1.726697 1.709555 1.056626 -2.272434 1.113513 1.914061 -1.858778 -2.056808 1.312863 59.914531 33.518485 -54.821703 61.642126 -30.790481 1.440906 2.049869 1.639085 0.603616 1.221143 0.755792 0.599607 1.343283 1.552916 1.354489 0.904255 0.569545 2.350518 1.160323 2.295971
+1 -0.001078 1 1 -1.781420 2.191488 0.298611 0.062985 -1.699858 1.705910 1.052208 -1.137067 -1.943301 0.508367 0.570274 -0.409884 18.965480 2.826801 -39.948517 -14.718141 -17.792760 2.231183 2.487230 1.628180 1.824151 1.503925 1.460775 0.747497 0.689652 0.473566 2.467145 1.549419 1.086975 0.294183 0.326254 1.600442
+1 0.005127 1 1 -1.348192 -1.895796 -2.184074 1.779761 -1.808553 -1.436700 -0.338857 2.104332 1.027764 -1.987220 2.205460 -0.485087 -13.585694 -34.759268 50.979881 18.853326 67.854766 1.150685 2.310660 1.755717 1.084457 0.713869 0.252471 1.278701 0.631601 1.324417 1.732457 1.651396 0.503550 2.421205 1.199625 1.350832
+1 0.075468 1 1 0.362667 2.222086 0.913512 0.430096 -0.186188 -0.227424 -0.575550 1.258152 1.271372 1.974140 -0.562714 0.235564 22.927066 -14.803567 46.450407 -58.001365 21.065615 2.121957 0.488792 1.871681 1.591304 0.793290 0.827555 0.722688 2.222374 0.698086 0.488434 0.366741 0.309711 0.308828 1.226172 2.021247
+1 -0.022555 1 1 -1.014217 -1.228988 -1.206887 -2.033548 1.116951 -1.555111 -1.839791 1.322024 0.343394 -1.251229 1.988455 -0.299001 -60.444174 64.773424 -53.066551 10.476171 -27.001678 0.366935 1.328601 2.301798 1.312528 2.153074 1.457778 2.120231 0.718051 0.782525 2.153021 0.581309 2.051990 1.294722 2.148239 1.199679
+1 0.051488 1 1 1.850246 0.033856 -1.176387 1.649481 -0.161545 -0.758098 0.944769 -2.010420 -1.301809 0.125025 -0.436661 -1.769685 48.094114 -32.233100 58.285695 -42.328765 30.454551 2.119642 2.066007 0.634131 1.087498 2.325322 0.685324 1.988313 2.070613 1.537494 0.914492 1.621019 0.721506 0.358327 0.657418 0.976112
+1 -0.007381 1 1 -0.510119 -1.737185 1.097981 0.059220 1.001349 1.737973 -1.989485 1.835152 0.811273 2.121143 0.835020 0.685468 -35.906679 -33.547727 13.360541 0.605641 -20.999684 1.499719 0.524702 2.422919 0.758138 1.779787 0.622945 2.083168 1.048485 1.395639 1.756410 1.475316 2.138807 2.424848 1.669098 1.026472
+1 0.004677 1 1 2.182628 2.196148 -1.483764 0.341313 1.471406 -0.704095 -0.912426 -1.027407 -1.431393 -0.681415 -1.430332 -1.694078 -3.803589 -26.924217 34.679330 -44.494342 -66.408702 1.659251 2.037890 0.573034 2.485029 0.634339 2.343516 0.465965 0.729534 0.281161 1.973792 1.028990 2.226441 1.542558 0.528911 1.158386
+1 -0.074266 1 1 -0.900568 0.355329 1.411606 -2.024654 -0.204358 0.681541 -1.159303 1.319312 1.889135 -1.389505 1.190765 -0.327434 28.455020 43.526227 -4.708079 71.316140 -39.640828 2.223946 2.369443 1.984707 2.225954 2.365401 1.552681 1.911144 1.096433 1.744438 0.511611 0.639876 0.888842 0.274596 1.889994 1.134621
+1 -0.038241 1 1 -2.242140 1.331840 0.379061 -0.264349 0.872219 -0.853662 1.731643 0.014729 -2.206342 -0.204493 -1.585270 0.221084 -73.492701 58.174265 34.863725 54.632837 64.090506 1.662116 0.689162 1.238087 2.021317 1.031316 0.822043 0.331777 2.181639 2.309243 0.442566 1.207038 2.189824 0.366432 1.878429 0.261366
+1 -0.020024 1 1 -0.512221 0.628885 -0.215421 -1.460185 0.791475 -0.755942 -0.520337 0.889297 -1.278983 2.050552 1.919854 1.256611 -33.858974 32.227067 -9.682570 15.053139 -51.887846 1.689671 0.297376 2.244476 0.902921 0.642196 1.639055 2.348369 1.036154 1.143007 1.523040 0.988737 0.704724 1.795200 0.934728 1.981474
+1 0.029016 1 1 0.953641 1.009195 1.648289 -1.347131 1.803118 -0.372927 -0.309323 -1.025119 -0.673356 2.059644 -0.779738 0.096214 22.652200 15.524668 73.089362 62.906041 61.830148 1.064397 1.076645 2.166920 2.426619 2.182248 1.290211 0.578236 2.164142 0.728892 0.741361 1.046782 2.018361 0.848015 0.339002 2.103557
+1 -0.005194 1 1 -1.045584 -0.640004 1.833376 -0.755464 -1.908620 -0.947651 0.710246 0.629044 -2.264271 1.645561 -0.073866 -2.110624 50.920044 63.172703 43.616157 6.748919 29.075275 0.897114 2.037197 2.421785 1.943678 1.145897 0.595069 1.572587 1.216541 2.161244 1.529090 1.421582 1.272475 1.730264 0.795735 1.421218
+1 0.017698 1 1 -1.330792 -1.624923 -1.786793 1.425294 1.851598 -0.809788 -0.735043 2.017161 1.503877 -1.590585 0.417667 -1.726797 41.933410 74.828812 47.850176 67.901449 19.661090 1.284167 2.494391 0.483642 0.823352 2.075198 2.096208 1.961910 1.575143 1.431829 0.257508 0.438535 0.960966 1.962859 1.779919 0.597320
+1 -0.011312 1 1 1.689671 1.446531 0.625352 1.655776 1.964243 -1.962495 -1.638046 -0.868646 -0.345970 0.364889 1.878343 1.016184 41.390132 -56.045936 35.949076 -3.881310 16.828535 0.432800 1.314302 0.476430 1.108836 0.962219 0.512349 1.803397 1.447683 1.210210 1.493990 0.991389 0.281160 1.957838 0.639208 0.924992
+1 -0.007444 1 1 -0.542528 0.208046 0.028409 1.521944 0.464278 -0.591715 -1.806480 0.410252 0.872515 -0.598858 0.659022 2.069349 67.330104 17.051152 -71.290743 16.487486 55.176888 2.244308 0.342331 1.804794 2.416959 1.830293 1.231389 1.957931 2.204555 0.449345 0.388053 0.751796 0.935664 1.962770 0.268070 2.449518
+1 -0.019163 1 1 -2.258841 -1.343945 -1.201680 0.656801 -2.265957 1.589207 -0.017810 2.255241 2.090311 0.992854 0.327465 -0.361491 -41.869113 -44.186442 8.477047 -26.268194 -39.530483 0.792586 2.497607 0.529021 0.747611 0.341178 0.420724 0.858646 1.270072 1.846046 0.493930 0.474388 0.537511 1.696443 1.618491 0.969942
+1 0.008734 1 1 0.848065 -1.549659 0.252676 0.854769 -1.974160 0.222119 0.935589 -0.791670 2.189951 -1.956145 1.407072 1.896886 52.853795 13.734370 -16.446164 39.326903 67.251250 2.001259 1.412070 1.161676 0.294021 2.116301 2.174573 0.542336 1.793029 0.437136 2.200256 2.448841 2.179043 1.422317 2.385053 1.076757
+1 0.003157 1 1 -2.295984 1.146638 -2.120528 0.088133 1.566978 -1.348387 -0.463152 0.679061 -0.435497 -1.049536 -1.082746 1.534215 -20.561642 20.483497 16.128085 14.724439 -26.352856 1.938160 0.659438 1.175247 1.126167 1.990537 1.212724 0.995977 0.884989 0.754836 0.280212 1.774000 2.370185 0.954244 1.483629 2.357207
+1 0.012131 1 1 -2.019619 -0.392563 -0.459988 2.006704 0.112186 0.546833 1.467213 -0.487252 0.880707 0.433369 -1.727183 -0.447368 65.683752 -53.174803 -8.916369 -7.419315 -46.432610 2.231966 2.152758 0.659817 0.791654 0.329159 0.923509 2.414438 2.201853 2.298862 1.480163 0.357337 2.011106 0.414546 0.520191 0.847986
+1 -0.006333 1 1 -1.162307 -2.040918 -0.226716 1.907075 -1.466468 -1.132280 -1.606131 -1.679370 2.035023 0.116315 -0.741436 -1.759822 74.460088 0.701683 -56.807502 -13.688877 31.038613 0.864446 1.995061 0.740464 1.721909 2.133316 2.389293 0.351633 0.647283 1.632462 1.787358 1.875154 1.463383 1.825079 1.356338 0.466199
+1 0.019916 1 1 -2.017648 -0.262011 -2.250985 -1.243545 -0.814926 -2.250588 0.709845 -1.395711 0.551977 -1.610801 -0.052891 1.708485 61.203427 -54.003960 5.452484 -10.102590 5.768245 2.078361 1.256594 0.323277 1.063599 1.152066 0.767380 1.861852 0.652309 0.615111 0.916968 0.486904 1.651183 1.437133 1.637682 1.771341
+1 0.047018 1 1 1.104992 0.071346 2.166223 -0.206392 -0.513799 -2.325244 -0.525743 -0.425684 -1.056245 -0.741080 -0.479803 -1.148795 -36.385779 14.207736 -10.578668 -45.672199 -62.650549 1.858254 0.920509 1.500808 0.822805 1.876594 0.912865 1.269449 0.387001 1.084037 0.416985 1.016298 0.418682 0.291530 0.738742 2.028949
+1 0.024314 1 1 -1.262013 -0.184257 -0.770097 1.918029 -1.141753 -0.595899 -1.450744 -0.759246 0.493778 0.407842 -1.927691 -1.032754 -56.416813 -47.383069 -17.246184 -56.607537 47.125871 2.042826 0.277757 1.005336 0.680248 2.183361 1.995793 1.796850 1.659968 0.587674 1.031633 1.657688 0.514804 0.310158 1.068644 0.455398
+1 -0.005188 1 1 1.559942 -1.785565 -1.500830 0.967783 -1.641495 -2.272627 -2.123708 -1.522940 1.641793 -2.129047 -1.723159 1.210378 -17.659749 42.599830 25.338780 18.868339 20.165954 0.312737 1.676761 1.577862 2.132357 2.028235 0.290935 1.999620 0.858239 1.180343 1.283587 1.751184 1.394658 1.017842 1.623638 1.990625
+1 -0.028525 1 1 1.172646 1.448675 -1.025893 0.449981 -0.557909 0.871506 1.301640 1.747609 -0.254229 1.305051 -2.184123 0.957280 28.799972 -8.875128 -64.274965 30.658737 31.392601 2.356703 1.613415 1.167808 2.102102 2.023993 1.004543 0.851887 2.409388 0.592858 0.411634 1.075285 1.810643 1.720908 1.042808 0.480589
+1 0.019236 1 1 -0.442043 2.026775 -1.853092 -0.743161 2.232616 -1.183404 1.529552 1.100675 -1.803069 1.192236 0.836939 -0.048210 8.335697 -1.933625 51.568475 11.359808 -25.699416 2.423855 0.734697 1.553375 2.325635 1.449721 1.717085 2.046080 0.975420 1.880778 1.494004 1.223797 0.361548 0.785684 1.234201 1.964490
+1 -0.006491 1 1 2.133216 1.099188 1.493788 -1.505166 -1.225394 -2.055192 0.199502 -2.191044 -2.268580 -0.080925 1.770477 -2.325749 12.592071 -15.068411 -54.788108 26.260666 63.013311 2.345700 1.184854 0.590365 1.270744 1.887924 2.333125 1.327646 1.989200 1.233814 2.213566 1.145172 1.907950 1.421766 2.120590 2.252927
+1 -0.024119 1 1 -0.758178 -0.402195 -2.119270 -2.327117 0.972698 0.859035 -0.956341 0.740571 1.356806 0.590167 -0.641532 -0.282007 30.931672 -31.388456 4.215622 51.957921 -43.214354 1.320262 1.643710 1.831220 1.060047 2.213284 0.916767 1.610368 1.704591 1.316274 2.117279 0.602529 0.949614 2.405793 0.913851 2.085480
+1 -0.027735 1 1 -1.015233 0.534423 0.230612 2.310986 1.237271 -0.956548 1.963658 2.345766 1.440598 -0.118369 -0.792507 2.250602 -15.059464 -54.413815 17.014491 62.552902 -23.381896 1.682047 0.410579 1.358449 2.201378 1.062362 0.613106 0.972447 1.418159 2.243072 2.069431 1.925402 2.225386 1.821127 2.424081 2.270615
+1 0.016496 1 1 -1.292985 2.339345 1.912116 -1.555795 0.802485 0.513108 0.134162 2.337174 -1.599971 -1.822789 -0.380593 -1.921108 38.945619 -40.979117 63.972762 -9.781423 3.624515 1.633276 1.968258 0.268793 1.108056 1.355488 1.941230 0.509778 1.346227 1.544539 2.312677 1.913628 2.346765 1.078892 1.695345 1.156093
+1 -0.026995 1 1 0.943982 -1.113716 -0.619314 0.858744 -1.140038 -0.048882 -1.607016 2.288449 -0.555933 1.094850 -0.729335 -1.017308 -43.043443 18.851762 41.566383 56.192175 21.880319 0.512808 0.506775 0.369486 1.444766 1.689090 1.791666 2.273875 2.267909 0.997051 0.937811 2.031346 0.825240 2.303866 2.325830 2.469475
+1 -0.052909 1 1 2.090821 0.146204 2.090578 0.778385 0.730687 0.175176 -1.066594 -0.319669 -0.560963 1.376880 -1.321338 1.754010 -33.729068 -34.443657 -44.540261 61.830678 -11.800042 1.025342 1.666474 1.928358 2.418566 1.837741 0.415118 1.144007 0.328012 1.900114 2.464872 1.595395 2.049697 1.010858 1.233764 1.368952
+1 0.013395 1 1 1.710805 -1.504894 -1.353414 -0.122444 1.390603 -1.584567 -2.112388 0.224338 0.544713 -1.185181 -0.066985 0.451895 -43.502687 -49.657215 11.181180 -27.914229 45.547492 2.375587 1.744908 1.662794 0.830620 0.481214 0.507793 1.732621 2.156551 1.408799 2.440804 2.098817 0.815254 0.981343 2.438282 2.462700
+1 0.043785 1 1 1.739720 -0.900762 1.806266 0.706250 -0.563118 -1.846467 2.225608 -1.153485 0.143566 0.170799 0.779321 2.311494 11.219978 24.162813 54.403115 -46.839804 -36.580399 2.023519 2.038698 0.645937 1.505845 2.242271 2.096092 2.262557 1.050561 0.286204 1.225899 1.938877 1.451632 2.325076 1.050565 0.345036
+1 -0.045062 1 1 -1.689957 -1.529802 -0.578840 -2.200765 -0.716893 0.753070 -0.633125 -0.349464 -1.812300 1.562726 -2.123161 -1.763748 74.068412 17.807886 47.135325 53.401338 66.295530 1.809688 1.429283 2.452483 0.374443 1.520606 0.566889 0.447446 2.229664 1.704176 1.085284 1.113513 0.811520 1.214328 0.953873 1.987212
+1 0.016644 1 1 -1.456468 2.003595 -0.306012 -1.931431 2.093395 0.985299 0.580415 0.389101 -1.172138 -2.336596 1.889953 -1.771646 48.461774 -2.959253 63.840306 14.025842 -67.675896 1.693184 0.841304 2.289035 0.553883 2.362294 1.081365 0.505901 1.429377 1.786231 0.927021 0.691408 0.736910 0.491993 1.670088 1.926235
+1 0.008406 1 1 2.117454 0.088816 -1.098645 -1.780808 -1.659007 0.269007 2.014128 2.353718 -1.560765 2.090884 1.201108 -0.852995 -38.368613 -11.282991 -33.230232 -50.509764 -67.601757 2.384027 1.841378 0.791138 0.659804 0.568667 1.087384 0.405570 0.419541 1.230917 0.768465 2.096719 1.563540 2.167735 0.378228 2.124875
+1 -0.006108 1 1 0.659470 0.172663 -0.892313 -2.278744 -1.267602 0.120872 0.461814 0.407039 -1.280929 2.328308 0.199426 1.238922 -47.006534 11.184566 28.997954 18.612201 65.268021 1.519335 1.714325 0.656007 2.002100 2.043664 0.856152 2.104582 0.952532 1.959983 0.679099 0.863284 0.456205 0.943546 1.677429 1.544989
+1 0.017541 1 1 -1.505000 1.573313 1.455789 0.717275 0.943925 -2.071550 -1.410505 1.679535 0.732777 2.317101 0.329643 -1.461329 12.969823 33.806771 -9.595541 -22.250100 -7.433290 1.655518 2.285860 1.200604 2.054832 1.816336 0.665188 1.071788 1.535328 0.500544 1.399912 1.570994 1.443949 1.446346 1.236425 1.085945
+1 -0.034869 1 1 -1.787973 0.444435 0.483916 -0.406787 0.809991 -0.576300 -1.921928 1.587435 -1.523288 0.507528 0.592458 0.159361 55.310504 53.648380 18.316297 42.000892 8.992983 0.551084 0.323070 2.087746 1.490942 1.514983 0.571275 2.167254 1.297059 0.926732 0.329700 1.021951 0.927168 0.907401 1.682616 0.972851
+1 -0.011153 1 1 -1.336856 0.132146 1.443335 -1.251264 1.390948 -0.504959 0.165942 -0.749102 1.339307 -1.356869 -1.648575 1.247337 -45.253892 67.845437 -21.738432 42.174992 -64.917340 1.889015 0.421165 1.518653 1.497886 1.215100 0.438835 1.494770 0.595126 0.289075 2.232421 0.806989 1.557194 1.263689 0.316093 1.828726
+1 0.031068 1 1 -0.248099 0.656953 0.286570 0.318358 2.076136 -1.629509 1.244443 1.771745 0.129018 0.708478 -0.824100 -0.938935 35.294508 -55.201570 -22.789817 71.537860 -63.195326 1.767377 1.307573 2.121980 0.864399 1.198978 1.729729 0.809746 0.659197 1.621438 1.011118 1.113011 1.371191 0.365549 0.533165 0.649065
+1 -0.017102 1 1 -0.656669 -0.225354 1.239241 -0.833631 -0.903281 1.874404 0.793510 0.463850 1.633101 -2.136710 1.436565 -1.936325 -1.905549 73.436322 44.259426 18.166634 -73.389883 1.168443 1.526526 1.070931 0.631511 2.060068 2.058331 2.121887 1.548912 1.556945 1.575045 2.035146 1.693807 2.317535 0.305909 1.670573
+1 -0.013187 1 1 1.294744 -1.053604 1.239221 -1.171054 1.739315 1.718458 -0.102112 -0.890750 0.419210 0.637974 1.750906 -1.384113 72.298707 -25.639721 23.201218 -57.126104 31.574234 0.897320 1.015621 0.293072 1.912424 2.353043 0.844161 0.818731 0.910934 0.325508 0.307192 0.728163 1.983188 1.447267 0.970591 1.719813
+1 -0.069517 1 1 -0.112509 -1.264234 0.178074 0.517599 0.223535 1.185205 0.472711 -0.229436 -1.394078 -0.277327 -0.481429 -0.206857 35.125954 -38.093276 -33.696418 64.295963 22.245166 2.492682 1.004195 1.754902 0.889205 1.862811 1.016538 2.198613 1.834787 0.264430 2.028929 0.707170 2.402951 0.391972 1.379130 1.043034
+1 -0.016800 1 1 -0.596697 -0.726200 -0.163436 0.446918 -0.195707 -0.006444 0.083476 -1.318853 1.117168 2.091967 0.557843 -1.980884 10.067422 3.158130 -21.302869 12.683743 25.674077 0.688307 0.378963 0.977380 1.073927 1.494514 0.804049 1.658672 1.296144 1.298732 2.038813 0.335692 0.482214 1.576870 1.207976 2.206391
+1 0.002829 1 1 -1.368346 -1.328673 1.002428 1.024893 1.590148 1.656232 0.206082 0.005919 0.512458 -1.357916 -0.395559 1.028667 -30.271149 32.798979 2.444625 -13.184381 -39.897193 0.593054 1.450405 1.957121 2.073418 1.438732 1.509820 1.548251 1.701251 1.421177 1.215799 0.934769 0.413166 2.085658 2.401480 0.427030
+1 0.080237 1 1 0.215921 0.452107 2.192624 0.555167 0.155394 1.040669 -1.865172 -1.141060 1.631547 0.018869 1.392925 -0.260298 -55.039619 -0.873288 22.646816 -74.960292 -7.625145 0.537898 1.455961 0.838592 1.712934 2.036681 0.501109 1.891834 0.560445 2.401576 2.038794 2.267932 1.383593 1.806283 0.439307 0.440593
+1 -0.006332 1 1 0.965079 0.039378 2.086864 -0.386601 0.776940 0.001030 -1.540890 1.546596 0.107314 -1.225040 -0.828872 -1.021959 18.967074 29.615289 44.169629 8.958934 -27.188706 0.466261 1.203994 0.528149 1.855593 1.199465 0.914458 1.048787 1.954589 2.269590 2.244372 1.416782 1.601577 2.449222 1.822304 1.964344
+1 0.013379 1 1 1.567110 0.872728 -1.727235 -1.324064 -1.634588 0.713396 1.735439 -2.165167 -0.887668 0.392550 0.247333 0.599782 23.385857 46.094658 -37.086469 -62.290529 -66.922347 0.416677 0.347748 0.600317 2.025541 2.274319 0.729828 0.715014 1.486967 2.202576 0.940707 1.217764 2.465401 1.493073 1.322202 0.489779
+1 0.019496 1 1 -2.053281 -0.671631 -1.938400 -1.940009 -0.713903 -0.829816 1.952068 0.751107 -0.640531 -2.306351 1.278533 -0.183075 7.933223 -16.325621 -34.718411 -12.334872 -12.191882 1.240658 2.495322 0.372242 0.526624 0.968573 1.558591 2.242720 0.648029 0.678159 0.822134 1.851251 2.480132 1.571336 0.448379 2.150647
+1 -0.010825 1 1 -1.557730 1.263688 0.060116 1.911293 -1.253168 -2.335313 -0.122263 -0.269154 0.218980 0.020053 -2.266539 1.224431 0.052377 -19.699573 -40.723447 11.023978 29.992338 0.343364 1.165798 2.062032 1.326161 1.788856 2.304049 0.908290 0.883677 1.212973 0.679619 0.613290 1.807954 1.533445 0.363321 1.340691
+1 0.015429 1 1 1.986981 -1.513421 1.414617 1.460860 1.128606 1.113778 1.660499 1.230244 -1.245133 0.764573 -0.504702 -0.230128 35.179962 -30.376882 55.740445 -70.346277 -9.884115 0.290323 0.712548 0.543935 1.666488 2.161048 0.484314 0.867378 1.771516 1.113126 1.063060 1.107121 1.381201 2.096485 2.121533 2.352874
+1 -0.004772 1 1 -0.323887 -0.758404 0.512347 1.484427 1.378431 1.180114 -0.267413 1.205839 -1.457284 -2.286268 -0.478072 -0.338301 64.533699 -32.117838 45.489354 -10.432429 12.158370 2.060790 0.692569 2.254758 0.458602 0.730983 2.132946 0.676404 0.578125 0.290509 1.582411 2.077227 2.455200 1.041725 0.268808 1.357880
+1 0.029261 1 1 0.529194 1.877278 1.963531 0.208960 1.269211 -1.349044 -2.071183 0.044256 -0.743304 -0.158963 0.233094 1.610968 -58.932649 -31.035054 -56.159436 -71.636863 49.250915 2.276886 1.131053 0.853164 1.378755 1.487132 0.481927 1.245028 1.691217 1.531475 1.007410 1.781685 1.029679 0.310546 0.838341 1.990393
+1 0.027154 1 1 -1.986846 -0.931162 -0.196026 -0.653808 0.740384 -1.785631 2.111144 -2.297831 -1.622637 -1.066190 1.759005 -1.924636 -48.272193 39.246750 70.121005 -26.262889 49.617341 2.404837 0.600760 0.469886 1.374178 1.067233 1.487373 2.273603 2.193621 1.191593 1.350640 1.465428 2.442030 2.454534 1.100185 1.809826
+1 0.067946 1 1 1.751791 -0.651382 -0.903933 0.339803 -0.351475 2.089048 -1.376239 -2.048119 1.267048 -0.004132 1.241670 2.294004 -46.068503 26.665847 -27.108617 -64.528852 -36.409658 2.318278 1.552547 1.910724 0.793332 1.534376 0.262064 0.516937 2.402788 2.162755 2.172996 1.038374 2.448287 1.852648 1.207085 0.729990
+1 -0.004110 1 1 2.232697 0.177649 -1.907977 0.435334 -1.687764 2.333245 -1.661512 0.585685 -0.569810 -1.217351 1.180084 -0.770948 55.569804 61.693621 -65.311827 4.118627 71.765902 1.667679 1.928279 1.081225 0.403770 1.661182 0.729402 0.310360 2.225451 0.657270 0.738319 1.677229 0.443898 1.086895 1.197104 1.726390
+1 -0.003232 1 1 -0.705361 1.374110 -0.748295 0.778698 1.277514 1.535120 0.436399 2.078052 2.304428 -0.602463 1.328307 2.265895 66.391777 -3.399482 14.897247 28.029211 -63.046699 0.987004 0.832078 2.485390 2.198447 1.300787 0.576663 0.475915 1.452917 1.424875 0.370732 2.144728 0.696517 1.109146 1.668963 1.018005
+1 0.003699 1 1 0.161167 -0.889550 1.748409 -0.942372 -0.102247 1.549960 0.089057 -1.764499 -0.863884 -0.432156 -1.456555 0.546320 72.365893 53.556270 -29.764587 -3.414748 58.325775 1.844461 0.856841 2.421869 1.106492 2.064528 0.528930 1.479739 2.225047 0.618820 0.261448 1.410554 0.439832 0.258166 2.494888 2.084850
+1 0.035426 1 1 1.392042 -0.968614 1.813784 -0.179723 0.031226 1.734279 1.897627 -0.029155 0.074575 -0.113866 -0.507739 0.567084 -69.534387 -14.435957 74.877833 -28.258541 -41.295374 1.354824 2.030683 0.940437 1.178079 1.471388 1.375933 1.313179 1.853718 1.183641 0.453638 0.544663 0.401962 0.518093 1.587749 1.795535
+1 0.050162 1 1 -2.140885 1.949008 1.154468 2.233389 -2.320313 2.234318 -0.846313 -1.987078 -0.118670 -1.140067 -0.529330 0.547647 32.263760 7.013806 -18.970097 69.586487 -9.914241 1.695348 1.220649 1.448696 2.484365 0.719777 0.545289 1.922287 1.618866 0.534825 1.547281 1.152054 0.573590 0.571796 1.920025 1.864532
+1 0.007481 1 1 -0.606535 -1.128611 -1.205759 -1.920828 1.221736 1.841585 0.547874 0.107869 -1.321533 -1.522747 0.175661 -2.335863 2.219088 -53.780676 8.175804 10.736920 5.406659 0.920877 0.934183 1.817314 1.345698 1.643269 1.164328 2.111864 1.850448 2.474409 2.138009 0.267632 1.836141 0.522113 1.654470 0.419662
+1 -0.019949 1 1 0.417182 -0.462139 -1.155936 1.355713 1.062231 -2.333596 0.458722 0.264010 -1.858039 0.934331 1.618417 0.827221 49.757770 28.834433 -29.690149 47.660118 23.604055 0.825258 0.353718 1.933107 1.226184 2.224600 2.099090 0.906729 1.643784 0.834740 2.224307 1.684220 0.938460 1.690907 0.826369 1.026036
+1 -0.013180 1 1 -0.298486 2.032551 0.972192 1.775612 -0.855014 -2.153771 2.141259 -0.376191 1.382294 0.138842 0.891668 0.875070 -2.224804 -42.281745 70.704969 38.417394 -68.855914 1.204741 1.833144 1.907261 1.084685 2.307564 1.472522 2.420143 1.343042 2.002823 0.687005 1.000355 2.472164 0.401336 1.259373 2.024631
+1 0.054877 1 1 2.041232 0.796483 -1.411833 -1.806496 0.138882 1.555598 0.607699 1.848096 1.591829 1.636021 -0.191378 2.064694 -22.955636 -15.372362 -63.289028 -48.694461 -7.799594 1.558383 0.996194 2.279838 1.244303 0.757233 2.311539 0.781389 1.062746 0.320025 0.409959 2.176681 2.233562 1.978408 2.102265 0.271700
+1 0.011295 1 1 -0.794977 -1.548449 1.741754 0.293767 -1.239874 -0.386008 1.326158 -0.864401 0.306949 -1.165963 -2.219894 -1.769641 71.404172 -60.084895 -46.822680 -48.775844 -25.605540 1.340250 2.331281 1.844222 1.333725 0.665141 0.274138 0.934151 1.278416 0.331104 2.116500 1.006857 1.491389 2.282494 0.885031 1.469916
+1 -0.034544 1 1 1.991638 1.363522 0.359918 -1.569657 -1.269805 0.788798 1.382474 -1.543338 -1.899247 1.084687 -1.897646 -0.283300 -60.594968 -69.618994 63.574186 41.343857 66.200401 0.327065 1.732600 1.800790 0.378448 1.328575 1.854433 1.948135 1.808350 1.442924 2.228981 1.487262 0.403457 0.897224 1.649630 2.337692
+1 0.021973 1 1 -0.114692 -0.256598 -0.811826 -1.995330 -2.155495 1.444948 2.301367 -0.206183 -1.713025 1.892746 -1.957478 -2.142800 -62.311198 35.692514 34.078413 55.882922 74.273837 1.680791 1.795460 0.791964 1.033685 2.388202 2.259191 0.716270 2.345782 0.315373 0.968314 1.699243 1.425307 0.877625 0.750139 2.341949
+1 -0.004648 1 1 -1.228183 -1.802569 0.165238 1.564344 1.515661 -1.457965 0.410298 1.651771 0.635438 1.530120 1.214698 1.356351 -74.651659 -70.436343 -23.622107 33.240726 -73.116352 0.376970 1.238976 1.217254 0.647070 0.310885 2.037548 1.564061 1.923042 0.813944 1.448478 1.073262 1.559208 1.364915 0.633086 1.533302
+1 -0.027185 1 1 0.254226 -1.355098 -0.156891 2.075509 1.978125 0.443089 1.417882 -0.207042 -2.020224 -1.138208 -2.281843 -1.509067 -25.675984 13.737582 37.544045 -47.241592 -39.433588 0.470285 1.333879 1.010880 1.603296 2.090041 1.818408 1.726476 2.379252 0.344777 2.416858 2.384409 1.505383 1.224073 0.495443 1.165821
+1 -0.024125 1 1 -2.197248 1.846107 1.147863 -0.381176 -2.285110 0.122803 -0.072523 1.616682 -0.067361 -1.165068 -1.315076 -1.385546 56.025153 64.753412 60.589360 -24.622623 17.572999 1.365830 0.254553 0.273020 2.397549 1.847734 1.870081 1.696890 2.376951 2.160247 0.518424 0.395623 1.994056 1.848467 0.676097 2.169788
+1 0.000636 1 1 -1.466376 0.417344 2.273317 -0.412573 -2.193907 1.440564 -0.703115 1.414629 1.673884 0.008303 -1.825146 -2.283008 -71.305610 66.605212 -16.207394 2.325524 -64.919194 1.421575 1.162346 0.296278 1.795444 0.525887 2.077732 1.946261 1.801330 0.462116 1.280845 0.666033 1.765102 1.319686 0.953577 1.515746
+1 0.032732 1 1 0.109895 -0.255719 -0.171666 -1.211472 1.019153 -0.633646 0.314552 -0.630768 1.565342 -0.566364 0.144254 2.312608 6.974163 64.749175 -10.623948 -56.687606 51.405548 0.970612 2.069429 1.885816 0.657254 0.469407 2.321713 0.783928 0.983025 1.448018 2.343487 2.243331 1.912508 1.525754 1.592326 2.215522
+1 0.004366 1 1 0.627054 1.996370 0.785382 0.505632 1.719323 0.297953 -1.572449 -1.074459 -0.556381 -1.718971 0.904210 -0.390041 -15.311646 57.161128 -42.918958 11.080926 -62.875964 1.280179 0.709525 1.490100 0.859282 0.707527 1.653401 0.453759 0.335039 0.743904 1.042517 2.335055 2.261356 1.116236 1.574631 1.826977
+1 -0.030474 1 1 2.274088 -1.595362 0.240265 -0.379287 1.182726 1.223183 -2.118465 1.772625 0.780500 -1.419445 2.213106 0.778727 55.983480 -35.645983 -2.031595 54.982168 -64.695628 1.533796 1.750913 1.344689 0.433176 0.891106 2.315329 1.489976 1.029603 1.282812 2.229048 0.365491 1.812151 2.321459 1.006023 0.980719
+1 0.014283 1 1 0.421475 1.005295 2.082390 -0.181149 -0.365655 -0.615781 -1.017653 2.283445 0.158746 0.831738 2.070420 1.276652 37.530450 24.277341 29.263807 -13.189149 29.969786 1.407822 1.757108 1.958572 1.715987 1.584757 1.018289 2.388156 1.491177 0.965813 2.412107 1.289952 0.720156 2.405850 1.866551 0.864662
+1 0.003458 1 1 -0.473854 -0.129169 1.466321 -1.331880 -1.060030 1.613410 1.499672 -1.578100 -1.798896 0.633619 -0.770916 2.286746 -28.864906 -32.481934 -73.861115 16.241656 -26.486318 2.041748 2.403476 2.473052 1.830826 1.198465 2.108888 1.324769 0.890634 1.132660 0.872710 1.387020 0.900135 1.063826 0.470755 2.474198
+1 0.013565 1 1 -1.696802 1.218866 0.726553 1.381643 -1.377688 1.883828 -1.050009 0.401169 -0.976089 -1.294044 -1.328884 2.171780 -33.480684 -59.857120 31.385972 -45.969693 37.365445 0.640603 1.858943 1.258541 1.545675 1.159257 2.378600 0.628883 0.639615 1.004031 1.248989 0.757675 0.738397 0.742946 0.688960 2.353327
+1 -0.000767 1 1 1.049438 -0.575308 0.613025 1.831271 1.552555 1.299616 0.724282 0.899475 0.134917 0.893046 0.472447 0.036260 48.688312 54.458649 -13.487746 -38.541584 -68.394505 0.528353 0.779446 2.140640 1.736193 1.453225 2.100926 0.268067 2.408418 2.277091 2.315665 0.375913 1.468907 2.420840 1.800024 1.007647
+1 -0.002776 1 1 -1.474670 -2.318558 -1.261998 0.067197 -1.596463 0.584831 -0.780787 1.322159 -2.092890 -1.936433 -1.864115 -2.217454 49.064360 74.701059 0.706900 30.876400 -60.348747 1.654099 0.947704 1.809953 1.371782 1.293126 2.323593 0.876952 0.682587 0.993040 1.021016 0.960858 2.382546 1.695095 1.458645 0.948291
+1 -0.006866 1 1 1.769702 -1.217902 1.331788 -0.491438 1.213393 -1.730998 1.412697 2.178827 -0.426704 0.649005 -1.353903 1.086339 73.573902 -43.422950 -59.520223 -6.395918 53.804120 0.412671 0.506374 0.376609 1.912436 0.312207 1.757318 0.998769 0.565035 0.796311 2.100926 0.269054 0.982179 0.733361 1.605581 2.254585
+1 -0.022808 1 1 -1.271257 -0.046449 1.585824 -0.334616 -2.015732 -1.052486 1.173769 1.482876 -1.128222 0.624670 -0.366834 -1.574696 -36.179967 23.287247 38.757268 -56.601478 -1.035846 1.232929 0.841359 0.964035 1.787948 0.544226 2.055120 2.148883 0.770349 2.251182 1.117624 2.403437 1.823954 0.448407 0.370957 1.428234
+1 -0.002728 1 1 -1.980507 1.937998 -0.101416 1.385637 -0.228714 1.321118 -0.752761 1.107075 2.092671 -1.755788 -0.544135 1.463398 43.634572 16.248169 -67.016152 9.530831 -15.331521 1.721893 1.858100 0.580089 1.801577 2.350731 2.489367 1.532831 1.289464 1.515898 2.447144 0.646979 1.019769 0.254187 0.864350 0.384952
+1 -0.012959 1 1 1.637940 -0.916980 -2.168328 -2.189901 -1.900902 1.535261 -1.903331 -1.595139 -0.724730 0.994740 -0.958689 -1.026490 -5.413984 57.175061 41.248750 -32.259605 62.825974 2.367299 1.942704 0.522460 0.730024 1.756497 0.696646 1.032595 2.080802 1.788624 0.652420 2.479763 2.123838 0.593931 0.441739 0.813364
+1 0.052670 1 1 2.080580 -2.323633 -1.739567 -1.242430 -0.932600 -0.810136 -1.861453 0.108974 -1.590199 2.199893 0.204710 0.518262 61.671011 4.681161 -73.723328 -67.971681 -0.048581 0.377543 1.867159 2.095366 1.321160 0.981455 2.063042 0.300623 0.565457 1.141956 1.850404 1.739131 1.327235 1.842118 1.979559 1.206117
+1 0.038115 1 1 -1.393604 -1.735499 1.149430 -2.327234 -0.987153 1.245159 -0.328752 2.305035 0.174015 -1.724377 -0.410180 0.325635 59.280748 31.537999 -40.844050 -65.943832 32.011784 0.955867 1.753316 1.227604 1.333940 2.029650 1.574485 1.618239 1.244055 1.086921 1.624975 1.963037 0.255350 2.416501 0.881687 1.514753
+1 0.017992 1 1 1.702529 0.774016 -2.014818 0.185993 1.663278 0.817596 0.002746 -0.971523 0.032683 -2.043579 2.164224 -0.815990 -40.995073 -54.185649 -48.208577 58.447751 -18.644258 1.314248 1.811801 0.945225 0.646241 2.114682 1.960197 2.032373 2.341136 0.968853 1.766921 0.395876 1.737553 1.794887 2.409818 1.064568
+1 -0.021644 1 1 -0.181331 1.283443 2.225105 -0.180997 2.183036 -0.378335 -1.670810 -0.185768 2.103590 -2.026183 -2.334494 -0.489910 -43.856288 7.367374 73.448860 -45.017930 -16.348948 1.723429 0.676548 0.747083 0.476993 1.564184 1.742702 0.587405 1.009117 1.224698 2.006840 0.714862 1.190711 2.271083 0.349467 2.493231
+1 -0.022224 1 1 -0.448211 2.032075 -2.307399 -2.202009 1.941771 2.051388 1.848876 0.571943 -0.630838 0.386001 -1.432744 0.184838 35.322323 -37.718447 -33.936007 -62.477851 -65.245301 2.458452 1.702461 1.516082 1.036824 1.154791 1.566556 1.100630 0.281993 2.459352 1.076992 1.258393 1.311315 2.027246 1.680952 2.253581
+1 -0.017140 1 1 -0.644511 1.493545 -0.890540 -0.756818 -1.094517 1.618601 -0.787762 1.891166 -0.237463 0.352228 1.137575 1.063421 -37.392273 48.071733 41.609288 27.304838 62.411374 1.344421 0.442392 0.528078 0.659145 0.741641 1.256433 2.118519 1.195936 2.352939 1.345713 1.902055 1.342831 0.707448 0.325710 1.455881
+1 -0.008383 1 1 -0.400751 -1.416756 0.275764 -2.231978 -2.237503 -0.842137 2.220798 -1.887051 -1.288504 2.259177 2.271825 -1.922557 14.063451 -35.576052 -26.713244 -19.490552 22.300488 0.689430 1.256306 2.240061 0.961957 0.618416 2.470498 1.657361 1.757257 2.215383 2.447027 0.925174 1.146157 0.465793 2.330176 1.259281
+1 0.037817 1 1 -1.137678 1.913316 -0.238287 0.647737 0.889446 1.220546 0.686390 0.221043 1.706130 0.038899 -1.245097 1.367649 -30.178413 -58.590931 12.223544 -58.896958 -31.167330 0.935326 0.767401 2.213687 0.933575 0.602370 0.533649 2.038062 1.211405 1.327854 1.001029 0.291265 0.794728 2.485743 1.390804 1.490457
+1 -0.002467 1 1 -1.594917 -1.710120 -1.120270 2.320353 -1.549181 -1.144717 1.421923 1.737379 2.162511 -1.332986 -0.793467 0.258020 36.385878 -12.540719 -21.872458 39.605827 -44.871351 2.083070 1.654091 0.806741 1.899966 2.225423 2.430938 0.519688 1.398307 1.600243 0.290908 1.543626 0.473436 0.280752 1.856963 1.734055
+1 0.002606 1 1 2.152245 0.480789 -1.128551 -0.195813 -1.775731 -1.152634 0.311060 1.952304 0.005885 -0.050270 -1.374746 -0.518109 20.186550 -24.647414 50.909230 31.431495 -30.861878 1.441282 1.618589 0.382334 1.383359 2.367603 0.310891 2.145158 1.175763 0.807321 0.388595 0.864801 1.207334 0.410920 0.335056 1.038843
+1 -0.027297 1 1 -1.845116 1.374329 -1.788084 -1.422255 2.116245 -1.385916 0.254979 1.869644 0.904295 1.039832 -1.800280 0.939724 -63.076757 68.950097 -55.727873 -18.355840 43.395961 2.213822 0.957327 1.552501 1.142077 1.638314 1.146670 2.335983 2.114632 1.123701 1.043385 1.171990 0.390116 1.672244 2.154863 2.276643
+1 -0.008740 1 1 -0.298833 0.926868 -1.293020 1.745489 1.810966 -0.410204 -0.066593 2.312973 1.638270 -0.077503 -1.975412 -1.967586 74.133771 66.281465 -57.417837 -71.579583 -38.045795 1.589972 0.906213 1.976665 2.066821 0.811474 0.447212 0.547377 1.009248 1.180496 1.597242 1.591179 0.946530 2.321618 1.439720 2.380193
+1 -0.010282 1 1 -0.497201 -1.396544 0.694209 -0.308778 -1.289309 -1.849416 -0.217652 -1.271158 1.626468 -0.515571 0.878422 -0.272224 14.781678 35.666018 38.770133 9.621148 2.629189 0.456809 2.095167 2.467234 0.797533 2.385959 0.570450 1.811194 1.989068 1.268243 0.365351 1.706709 0.912779 2.078143 2.105053 2.119001
+1 -0.024756 1 1 0.480169 -2.118016 -0.115358 -2.024804 1.999945 -0.389503 -0.876258 -1.047351 -2.050329 1.817435 -0.077460 -1.246682 -54.356818 74.967958 -13.525034 -65.241233 -9.395184 2.052100 0.887838 1.396000 1.069760 1.206307 1.144689 0.546828 0.795623 1.793253 1.959266 2.138772 1.835217 0.743677 1.727103 1.676801
+1 0.012595 1 1 1.930769 0.928239 -1.805106 -0.052893 1.668986 -2.209867 1.822156 -0.838529 1.597208 -2.199902 -0.340137 -0.550109 0.917524 -29.173825 25.528961 65.251852 37.873970 0.592166 2.285936 2.471928 0.934676 1.100479 2.251268 0.314600 1.484514 1.475047 2.113385 0.408454 1.642658 2.157316 0.751320 1.927733
+1 -0.013328 1 1 2.015556 -1.920704 -1.410939 -0.911047 -1.411921 1.431763 2.186923 -1.011373 -0.550479 -1.481110 -2.171850 -0.123162 -39.501748 -5.879944 25.786751 47.922047 -74.147761 1.353594 1.601676 1.869889 0.733557 0.387855 1.927172 0.479221 0.772013 0.973992 0.375792 1.678091 1.429897 1.522801 1.461272 2.345870
+1 -0.044433 1 1 -1.977749 1.163105 1.315378 1.744317 0.960887 0.262564 2.110493 0.905072 -0.047473 -1.480399 0.355364 2.002142 -36.987186 -43.642079 7.580975 63.449049 38.168733 0.653384 0.670715 1.705161 1.899624 0.981171 1.791530 2.242903 1.474168 0.842713 1.232812 1.118303 0.327262 0.541604 0.740693 1.069883
+1 0.052080 1 1 0.527137 0.299446 -0.043103 1.272409 0.554164 2.146139 1.530630 0.364470 -0.458019 2.122909 2.240956 2.336624 -45.043227 8.477281 -22.342487 -60.175950 72.802032 1.881199 1.819715 1.196529 1.054870 0.698854 2.134804 0.399421 0.565677 0.332713 2.157652 1.908071 1.191785 2.332745 1.697908 1.494471
+1 -0.020687 1 1 -1.520956 1.996507 -1.626635 -2.291360 -1.245894 2.110708 -0.201619 -0.408462 0.922589 2.187529 -0.251638 -2.275003 10.950245 -9.232623 -72.688998 66.018415 21.508431 1.258036 2.060725 1.847779 0.374148 1.047009 1.321942 0.621133 0.875365 1.003747 0.969306 0.374504 0.295152 0.862966 1.862372 0.389109
+1 0.059099 1 1 0.794261 -1.054223 0.250088 -0.224273 0.549875 0.761133 -1.769163 0.854687 1.361207 -0.844747 0.766345 0.999153 -69.843169 45.862978 -30.936836 -55.410283 69.368087 2.416540 1.539906 0.954465 0.689231 2.408755 1.193668 2.475410 0.958776 1.155149 0.846730 1.242936 0.276915 0.363423 0.803199 0.857183
+1 -0.032702 1 1 -2.044138 2.200085 -1.291370 1.213002 1.131341 -0.038111 0.347545 -2.169693 -1.571266 -0.042814 1.412292 0.085916 63.786709 13.209957 19.755047 73.067077 -11.629164 1.354492 0.940249 0.261833 1.129395 2.242280 2.242496 1.374191 1.281521 0.774897 2.186226 0.648896 1.741745 0.257902 0.308781 0.427694
+1 0.048372 1 1 0.174861 -1.645249 0.595946 2.236603 -0.149350 1.571216 -0.798918 -1.821981 -0.935411 -0.929310 -2.048597 -2.060303 -27.958457 52.214202 64.086666 -45.411196 -25.976058 2.430921 2.483008 0.419128 1.027291 0.686576 0.529720 1.248440 0.536461 2.042384 1.856709 1.960587 1.840986 0.947782 0.874031 1.092563
+1 -0.005267 1 1 1.856005 -2.144054 0.515552 -1.192943 1.430259 0.467788 1.856217 1.425647 -1.640298 -1.008522 0.234579 -1.695626 68.031930 -37.359720 -4.820446 -17.234112 -3.723393 0.939079 0.844447 1.120267 1.830494 2.357714 0.603003 2.174069 1.086195 0.672149 1.065875 1.159517 2.247369 2.284909 0.969925 1.782147
+1 -0.058060 1 1 0.530432 -0.865586 -0.752134 2.218099 -0.115194 0.732338 -0.346985 2.167800 -1.976307 1.841977 -2.281936 1.635626 -67.190074 -63.576999 61.370394 52.214306 65.846425 1.087907 2.453210 1.343153 1.623708 0.913723 2.197021 2.077550 1.126672 1.483905 2.493092 1.153953 0.995080 1.563673 2.153715 0.994109
+1 -0.034917 1 1 0.790748 1.161699 1.241537 0.051571 -0.319114 -0.645728 -0.122736 1.207496 -1.881083 0.058809 -1.195086 -1.611486 -68.396702 56.627754 -7.333876 39.549622 60.499576 0.870504 0.302897 0.532460 2.301771 0.866254 0.888203 0.769997 0.837071 0.897831 0.596542 1.586677 1.777139 1.132160 1.470083 1.938652
+1 0.031808 1 1 -2.146941 -0.869042 -2.289809 1.267471 -2.329559 2.349038 -0.105118 0.430576 -1.534492 0.701623 1.772618 0.669526 -14.763016 -22.016835 13.050603 41.490874 -12.874732 2.340713 0.615883 0.398074 0.429217 1.845973 1.515996 1.840042 0.829275 0.366695 1.787242 2.180485 0.914167 0.659239 2.326833 1.327732
+1 -0.012751 1 1 1.533761 1.153579 1.433719 2.075057 -0.907430 -1.886475 -1.028985 0.313074 -1.911278 1.506134 -1.351241 -1.306039 -9.244327 30.601864 -24.479443 23.999583 10.989115 2.035821 1.802283 0.727538 0.482656 2.255560 0.449375 0.894251 1.168626 2.354496 0.515327 2.353835 0.651251 0.822995 0.578604 1.599666
+1 -0.000812 1 1 -0.655297 -0.726965 1.121918 1.813706 -1.493568 0.492263 -1.488985 2.122410 -1.443181 -0.877581 0.275340 0.073422 -20.223389 5.506864 3.862769 -28.447949 -74.682027 1.662622 2.440929 1.941386 0.882706 0.637661 1.923318 0.953227 2.392383 0.523731 1.849809 0.746840 0.883721 1.952723 2.414239 1.117245
+1 -0.007942 1 1 0.121622 -1.067840 2.309195 -0.594049 1.365554 1.535416 0.692715 -1.854757 -0.448446 -1.913812 1.330785 1.504654 65.166317 -49.711885 -7.650224 -27.317813 19.511151 1.733766 1.156808 1.716895 1.100128 0.848867 1.158223 0.752082 1.243029 1.845096 0.287340 2.325015 2.272092 1.549874 1.988441 1.975836
+1 0.053914 1 1 -0.215602 0.198576 1.101338 -0.067282 0.163087 -1.603349 -2.050639 1.329138 2.099101 -2.063333 0.030952 1.853558 -27.286286 -50.611171 28.056853 -48.471463 -9.877751 1.894480 2.282793 1.394516 0.881390 1.029358 1.665557 2.270035 0.734519 0.808662 0.430229 0.856815 1.996005 0.859288 0.806526 0.540652
+1 0.007072 1 1 -1.717274 1.151386 2.270670 2.230817 1.568029 2.177224 0.895293 0.524842 -0.580261 2.196065 1.837810 -1.645094 -48.009501 -45.680778 -56.836924 -58.184714 -60.490973 1.798138 0.811856 2.357590 0.762547 1.621821 0.693314 1.272650 2.422501 0.480272 0.430439 2.133859 0.262916 1.337197 0.512954 0.723015
+1 -0.000914 1 1 -1.321723 -0.002842 -0.644376 -0.959373 1.611987 1.149150 -2.311811 -0.963633 0.699426 -2.155043 -0.388192 2.307903 40.046679 14.541042 41.300483 -62.783633 45.476191 2.400194 1.304621 2.010120 1.841172 1.825041 0.710533 0.428304 2.254196 2.264877 1.784116 1.381794 0.816131 2.210457 0.648270 2.472794
+1 0.044410 1 1 0.527096 -0.381339 -0.307145 -2.114114 -0.495687 0.494751 -2.086696 -1.504325 -1.229949 1.499200 -0.097172 2.031033 -31.065028 40.078698 -47.330721 -37.424143 -37.578284 2.451618 1.592871 2.390160 1.412930 2.108248 1.825435 0.579757 0.729351 1.694791 0.856465 0.603254 1.889004 2.485457 1.074247 2.366998
+1 0.005447 1 1 0.360554 -0.305577 0.677813 2.155786 -1.257009 -0.914168 -2.039012 -1.188023 -0.714330 1.430295 1.064189 2.316015 29.429552 72.480202 24.747178 -24.182793 59.799859 2.218486 0.594506 1.120039 2.493702 2.403993 2.155456 0.992045 2.308493 1.339603 0.460267 1.699584 0.406668 0.874296 1.044959 0.619321
+1 -0.001287 1 1 -1.151750 1.025978 0.978896 1.352070 1.093549 0.970020 -1.742524 0.893964 1.755957 -1.323187 -1.048458 -1.814894 12.023356 26.550420 -17.098072 32.699124 -25.827911 1.529413 2.348513 1.212262 2.239260 1.000276 1.131107 1.769800 1.531809 2.115876 1.773353 0.493025 1.019558 1.217493 2.411346 1.995681
+1 0.039399 1 1 -0.929153 0.574261 0.639327 0.929796 0.798876 1.106787 1.968425 2.350528 1.373037 0.070412 0.611896 1.709220 4.224908 58.025899 -58.719655 -51.237711 -2.210286 2.150891 0.772382 0.425364 2.341445 1.661634 1.576279 0.265942 0.432783 1.041375 1.142028 0.823337 1.820831 1.953671 0.344432 1.122543
+1 -0.015033 1 1 -0.421140 -0.098400 0.236175 1.565204 1.826733 0.684552 2.330084 1.763839 -0.795596 2.176098 0.821593 1.206931 -62.025842 31.677117 47.307637 -50.545807 -73.386217 2.092792 0.810070 1.598719 1.672642 2.100177 1.170951 0.920374 1.474027 0.717549 1.348906 1.565012 2.153263 2.391668 2.014168 2.363904
+1 -0.003437 1 1 -1.009044 0.892989 -0.484613 -1.875096 1.726986 1.847889 -1.883679 -1.167867 -1.242912 0.397300 -0.030265 0.281022 42.242934 26.986719 -34.214657 54.264264 19.480106 0.657052 1.581002 0.898066 2.287599 1.169696 2.337691 1.565905 1.406114 2.300218 1.764912 0.373433 0.295704 1.141287 1.856741 2.488480
+1 -0.013547 1 1 -1.579417 -0.380279 -1.343412 -1.671223 2.296845 -0.822511 2.210220 -0.598602 0.251666 -1.969478 -1.192628 2.008767 56.822554 -33.327258 -31.228889 -13.945512 67.784465 1.427598 1.135587 0.557420 1.057961 0.907896 1.011459 2.348722 2.469988 2.088026 1.705347 0.524347 0.949429 1.561147 2.445312 1.357117
+1 0.010228 1 1 -0.858254 -0.049272 1.257867 1.196289 -1.742715 -2.312277 0.636236 0.803584 0.133321 2.333025 -0.644220 1.664850 -32.722214 -62.257087 45.135796 47.328230 -4.444975 1.274442 1.054796 1.703980 2.286915 0.933464 0.987718 1.576779 1.931036 2.420849 1.951623 1.927488 1.293841 0.828772 0.918812 2.221614
+1 -0.021074 1 1 -1.923396 0.465660 -0.929169 0.313145 -0.715673 -2.301400 -0.345924 1.144293 0.879679 1.992939 -0.333768 -1.901974 -74.378223 25.199859 -65.962228 22.828327 -24.301035 1.712588 0.717766 0.491202 1.890276 1.364047 1.794601 2.110060 0.786971 0.368021 1.579422 1.352809 1.916602 0.572627 2.391761 1.333916
+1 -0.053698 1 1 -0.388783 1.802131 1.895052 -0.905316 0.663574 -1.531070 1.661890 1.047468 -0.683031 -0.320253 -0.951778 2.029311 -52.149252 -22.477203 -74.359056 47.347306 16.165763 2.094692 1.235488 1.089682 0.781303 1.857458 1.045818 1.556014 1.675263 1.147259 0.979328 2.308775 1.583909 0.259750 2.117872 1.573390
+1 0.030816 1 1 1.041398 0.969223 -1.003265 -0.943810 -0.710604 -1.920127 -1.134087 1.020017 -0.248812 -1.899175 2.281656 -1.620019 16.592069 12.909769 74.484538 -38.366972 16.296743 1.365374 1.597981 0.512960 0.810621 1.859748 1.284268 1.939589 2.167207 0.502843 1.787760 1.879407 0.935888 1.224299 2.038652 2.118485
+1 -0.049655 1 1 -2.195593 1.394131 1.160920 2.283109 -0.771863 0.498041 1.373327 0.230100 -1.572640 0.436299 0.407827 -2.180879 -33.910930 59.002656 7.643582 65.691091 70.170342 2.168985 1.128693 1.695648 1.755192 1.261284 0.398224 0.697316 1.037388 1.628188 1.956062 2.290459 1.999579 2.430808 0.598246 0.975911
+1 0.019780 1 1 -1.893813 -1.842047 1.108792 -2.038550 1.876662 1.045209 -0.952802 -1.040747 0.559957 0.564629 -1.030022 1.733345 10.782022 13.444915 68.694444 -2.476207 -67.617200 0.740833 1.177702 1.884935 1.600941 0.770677 1.020721 0.511174 2.301310 2.120843 2.009824 1.368156 1.096774 0.737914 1.628777 0.611734
+1 -0.003599 1 1 0.975807 1.271627 1.551405 0.811780 1.228134 0.981785 -1.925198 -1.547594 1.977699 -2.005022 -0.111965 -1.547787 -40.367700 -9.932006 22.775095 -18.984176 -17.052397 2.130545 0.824112 1.351841 1.396689 1.406559 0.783972 1.723304 0.811439 2.100802 0.427347 1.916769 1.132530 0.936723 1.751645 2.399790
+1 -0.013808 1 1 -0.837955 1.817781 1.019224 0.569815 1.302103 0.110343 -2.145877 -1.849435 -0.528632 -1.867886 0.382036 -2.107946 -16.040831 -48.244020 62.751090 7.572123 64.676031 0.775695 2.113024 1.089398 0.520620 1.315153 1.273393 1.413892 0.274336 2.011205 2.077342 2.137313 2.071444 2.004810 0.347911 1.086965
+1 -0.009370 1 1 1.727596 -2.036426 -0.123291 1.301259 0.067248 -0.737286 2.018871 1.959872 -0.028066 -0.464464 2.178448 -2.093234 54.282884 32.424916 15.556635 10.366481 -70.553046 0.849351 0.285845 1.942766 1.575286 1.587898 2.051255 2.438343 1.229674 2.377424 1.121531 0.570728 1.970165 0.816279 2.443901 2.390359
+1 -0.005975 1 1 1.668428 -2.162056 -0.452210 0.795878 -2.154049 2.182092 -2.098442 -0.991530 -1.640604 -1.440465 -2.349597 0.149904 -54.015772 -43.076286 66.863808 -19.978014 -70.478249 1.705950 1.657619 1.598890 2.297013 1.904784 2.198620 1.957700 0.565393 2.310514 1.557492 1.762414 1.145994 2.214828 2.113412 0.866332
+1 -0.047427 1 1 -0.959572 -1.739011 -1.317459 0.988866 -0.732663 -0.390037 -0.419328 2.091329 -0.746548 1.863955 -0.469283 1.303333 61.481453 -31.225974 35.051864 66.684025 -41.593614 0.416838 0.796343 0.381971 2.035477 0.509007 1.885425 0.844133 0.346995 1.437870 0.525811 0.805828 2.299736 0.413493 0.821264 0.730065
+1 -0.004863 1 1 -0.130537 2.031331 -0.679900 0.465684 -0.531482 2.066010 -2.166197 0.640886 -1.151172 1.318210 2.209028 -1.785257 -32.652557 58.482838 -28.942987 5.210861 -21.063159 1.247327 2.083308 1.166254 0.726335 0.512672 0.474940 0.823704 1.234942 0.917915 0.641036 2.385647 2.068978 1.067079 1.145790 1.041011
+1 0.000619 1 1 -0.573348 0.570495 -1.405674 -1.960537 -1.724834 1.335589 2.142699 0.261375 0.978459 -1.279708 -0.710487 0.032163 -43.176794 27.627702 -61.209936 -55.395769 13.306625 1.291706 0.957403 0.567943 2.421273 2.335057 2.307176 1.704217 1.765990 0.494174 2.340023 0.268202 2.417114 2.181402 0.578354 1.897974
+1 0.005846 1 1 -1.700214 0.435037 -1.956398 1.866467 -0.662484 1.005714 -0.309607 -1.079881 -2.140887 1.905377 -1.716336 -1.918679 -11.323759 31.574270 -31.246583 -11.317803 -18.321380 1.713450 1.703448 2.349828 0.802428 1.408197 1.318133 1.867290 2.046797 1.763475 0.980002 2.392088 2.317039 0.976485 1.778022 2.463707
+1 -0.066738 1 1 -0.566736 -1.391718 1.690256 1.851065 -0.347253 -2.338234 -2.088837 0.206519 -2.073734 -0.416773 -2.089478 -1.135528 11.363764 40.773460 -70.449614 53.336934 33.854660 2.054024 1.733238 1.283519 0.599023 0.526292 2.141434 1.579805 1.028577 2.050832 2.083066 1.590063 2.446096 1.042825 0.758694 2.112168
+1 0.030030 1 1 0.645370 -1.188595 -0.903074 0.647998 0.566068 -0.407688 -0.202519 -1.386119 1.541612 1.160302 1.321046 -1.951612 70.138075 -39.378715 -38.066704 -37.093266 -26.515214 1.506856 1.221628 2.149579 1.231593 0.878333 1.387565 1.049133 1.027783 2.197782 1.373141 1.630139 0.999039 0.593891 2.024909 0.649201
+1 -0.019396 1 1 1.694428 1.289644 -1.940367 -2.010777 2.126800 1.648672 0.390396 1.737519 -0.199643 -0.175861 -1.033060 -2.194040 -24.783508 13.581594 -34.147217 -12.281808 -20.352060 0.518856 0.911339 0.375439 2.499998 2.467845 2.076997 0.845534 1.385933 0.625805 0.656183 0.467194 1.134311 1.610717 0.814237 1.881715
+1 0.012770 1 1 1.870017 -2.265372 1.998720 -2.132691 -1.707109 -2.350280 -1.910656 -2.184076 1.744539 -0.011189 0.433729 -0.390109 -51.923793 16.811305 -52.396452 22.831282 25.349060 1.999854 0.303522 2.043769 0.371012 2.355999 1.024997 0.367369 1.873478 0.292979 0.349490 0.625213 1.955714 0.928736 0.260856 0.457039
+1 0.019827 1 1 0.640401 0.119535 1.541312 0.833506 -1.196053 0.981413 1.250960 -1.796558 2.246666 -0.666239 -0.841127 0.346301 15.403594 -11.789733 -0.047657 -50.976261 41.975172 1.775787 0.901297 0.341658 1.746698 2.498582 1.173906 1.091964 0.893653 2.371306 1.785909 2.276010 2.154774 0.792740 0.586689 2.485289
+1 -0.021138 1 1 -0.166643 -1.603333 -1.779564 0.399586 0.681229 -1.693554 -0.726823 -1.209403 -1.903708 1.499770 0.073648 -1.556775 -48.837319 -8.817766 -0.186407 17.052927 -41.454666 1.696305 1.548496 1.328790 0.970843 1.462165 1.604531 0.360546 1.947236 2.452820 1.541478 0.375311 0.352663 2.214721 0.322437 0.456200
+1 0.033798 1 1 2.173473 -0.878155 0.050711 -0.644163 -2.094684 0.905468 1.904074 -0.067323 -0.518988 -0.000449 1.885013 0.030687 67.223160 19.643275 -5.484596 70.389514 -13.445717 2.392393 0.699155 0.453562 1.512334 1.047103 0.663966 0.774921 0.348795 2.446282 1.915206 1.864269 0.766893 0.415941 1.478655 1.998615
+1 0.004704 1 1 0.394732 -0.783796 -2.131084 1.736872 -1.639866 1.531090 -1.320999 -1.972153 0.965741 1.748906 -2.028453 1.927961 27.157403 -15.536094 34.860928 7.618271 -59.710427 0.577744 0.643074 0.647858 2.296956 0.935038 0.430136 1.541240 0.874172 1.204044 1.372112 2.331631 0.966088 0.295422 0.903408 2.082666
+1 0.029060 1 1 2.014921 1.541914 1.526596 -1.454003 1.021401 -0.546620 2.120118 -2.257351 0.148852 -0.522754 -2.025535 -0.862037 74.675740 25.166855 -20.663193 -36.290329 -31.556398 1.849310 1.356134 1.550288 2.197560 2.147253 0.382645 2.106709 0.713561 1.825345 1.327805 2.411081 2.044113 1.653635 2.142298 0.345775
+1 -0.036335 1 1 0.341688 -1.659647 -1.064373 -0.685135 2.012144 2.004242 1.133547 -0.658645 -0.450321 -0.441557 0.769050 -0.656345 16.089667 -30.961590 -21.450682 -71.604258 -2.765493 1.680413 2.199163 2.075318 1.878589 0.688002 1.998731 1.668025 1.001596 0.831138 2.433322 2.348279 1.767948 1.903636 0.919009 1.034246
+1 0.001968 1 1 1.363066 2.119075 -0.939092 -1.529023 -1.626867 -1.467398 2.090102 2.203402 -2.089916 0.932802 -0.514374 2.149940 -17.734231 -9.214628 -70.260480 -67.887709 61.270022 1.603941 1.682423 2.232047 1.271461 0.448590 1.195018 0.419505 0.622673 2.013300 1.278993 1.036575 1.463154 2.472404 2.196675 0.767650
+1 0.068192 1 1 1.102670 -1.247281 -2.339058 -1.803693 0.136902 1.263803 2.006579 -2.000721 1.489864 -1.496449 -0.798543 -0.226852 -11.973159 67.112621 -38.184565 -67.979805 13.423929 1.614711 0.444810 0.667984 0.800489 0.314347 1.730646 0.458173 0.263711 1.187588 1.532916 0.466031 1.829307 0.418458 1.017075 2.233503
+1 0.020590 1 1 -0.020033 -2.122588 -1.560362 -0.564074 0.941237 -0.111563 0.489028 0.688538 -1.377204 0.593648 1.309503 1.967024 -74.915229 -0.247826 34.796302 -28.560473 -15.868982 1.225171 0.954565 2.377948 0.929031 0.731953 0.425663 0.610703 1.080921 2.042943 2.249773 2.180468 0.619986 1.851089 2.006179 0.857249
+1 0.006141 1 1 -0.478725 -1.881975 -0.806029 1.186813 -0.769401 -0.525386 0.853524 0.668424 -0.131140 1.325664 0.264241 2.021241 -19.653118 -9.952719 -25.347288 -11.877236 29.292643 1.696700 1.429255 1.983652 2.484783 0.989385 0.339386 1.808856 0.948566 0.543486 0.873284 2.041618 2.468281 0.405878 1.085520 0.589119
+1 -0.017948 1 1 -0.416360 0.137716 0.812068 1.340172 -0.952157 0.373513 0.725696 1.106346 -0.732099 -0.332073 -1.677480 0.815365 6.929631 66.313874 37.272811 44.131149 -37.777785 1.656481 0.478820 0.771370 1.423291 0.749527 1.048151 0.266500 0.807674 1.830511 0.405470 0.991038 1.117454 1.795126 1.934889 1.922859
+1 0.076503 1 1 -1.843275 -0.680091 1.959293 -0.345155 -0.075745 -0.706599 -0.587375 0.436965 2.171717 -2.117722 0.128825 2.166865 36.910899 -38.523822 -69.876433 -63.205102 11.858723 0.768469 2.150639 1.043132 1.410603 1.248312 0.624757 1.035881 1.060778 0.989612 1.901066 0.473585 0.536437 1.646562 0.267305 0.843615
+1 -0.006523 1 1 1.818727 -1.921720 0.364606 1.826753 1.020095 1.061492 -0.605450 -1.743256 -1.988118 1.248899 1.263095 -0.482132 67.482162 22.702727 -35.260657 24.136744 66.260659 2.018459 2.485119 2.150450 2.363643 1.256672 1.630453 1.768050 1.364189 1.929714 0.461379 2.403528 1.101000 2.009709 1.681200 1.928049
+1 0.041633 1 1 -0.813256 2.252833 -0.679100 -0.223049 2.280671 0.665072 0.083286 0.213407 0.604186 -0.641769 0.440385 -1.606627 -18.996505 -74.260219 58.505920 59.005832 61.023334 2.412627 1.019056 1.767357 0.962835 1.862603 2.022265 1.213305 1.765264 1.790767 0.676181 1.318673 1.943210 2.276657 1.775807 1.233338
+1 -0.008970 1 1 1.132945 -1.359923 -1.141394 0.723029 -1.299081 -1.153366 2.139929 0.832759 0.383906 1.046882 -1.105710 1.987881 -16.835531 -54.771191 10.586791 32.203211 39.364707 0.664432 1.852762 0.866042 1.822278 1.523354 1.761922 1.867548 1.876544 2.322090 0.362176 2.340646 1.738340 1.531821 2.309349 2.236129
+1 -0.008462 1 1 -1.323002 2.071813 1.121057 1.474199 -0.882329 0.590777 0.193181 -0.044654 -1.229302 -1.763414 -1.482328 0.913637 -69.570265 -17.438142 17.145873 20.679637 12.665254 1.598956 1.162054 2.139420 1.488985 2.373958 1.362433 1.668448 1.359814 0.396072 0.533350 1.514772 1.517272 0.785548 1.197717 0.785262
+1 -0.000694 1 1 -1.997420 0.414637 -0.817615 -0.328994 -1.777090 -0.431729 1.011251 -1.499693 1.226146 0.549584 0.584111 1.250595 47.548625 -50.262363 40.466054 12.962154 54.918209 2.280106 1.247520 0.818037 0.496778 1.095459 1.136672 0.800986 1.923444 0.815836 1.762341 2.157477 1.208508 2.137879 0.326943 1.929440
+1 -0.010048 1 1 -2.332078 -2.301962 -0.354394 0.157990 2.260928 -1.287557 -0.677378 0.431402 -1.788878 -0.630624 -0.741011 0.669332 31.593158 -13.791436 -42.670693 -16.341175 3.876943 2.271584 2.008662 2.084689 1.863624 1.177698 1.821066 1.403937 1.714544 2.091657 1.980941 1.930130 0.701491 1.464586 1.800012 0.801724
+1 -0.014791 1 1 -0.445037 -1.177633 -0.448058 -0.120927 -1.382140 -2.263557 -0.487207 1.651813 1.338498 -0.803194 1.705997 -2.189887 -53.374641 -67.590997 -51.894273 62.955375 -9.008683 0.490990 0.564208 0.394431 2.204954 0.419206 2.350633 0.832328 2.194636 0.252622 1.566717 1.553803 0.513253 1.248401 2.122008 1.332825
+1 -0.049047 1 1 -0.465909 1.461883 -0.529879 0.736601 0.601167 0.448425 1.562374 1.385515 -2.273317 0.416815 -1.920735 -1.937193 -15.904373 -4.794207 -26.235422 61.255341 68.512556 0.483001 1.296371 0.607084 1.017097 0.352400 2.294322 1.661623 1.397579 0.613625 0.696462 2.432913 2.217697 0.828235 0.901109 1.685590
+1 -0.003755 1 1 -1.353823 -2.294022 1.134682 -0.433844 -1.555026 -0.416226 -2.320254 -1.495232 0.805456 -1.392228 -2.157411 2.225096 -10.345616 -28.771218 42.139734 -57.498323 -74.322508 2.299239 1.061810 0.335243 1.923039 0.771699 2.440382 1.754634 0.880459 1.120560 2.246138 1.848225 1.110807 0.338804 1.028423 1.700092
+1 -0.030985 1 1 -1.199755 0.025394 -2.033939 -0.746634 0.413540 -0.406110 -1.950600 0.358793 -1.627277 1.063861 1.512386 0.047072 -17.340317 11.295048 -64.132154 30.882141 36.142168 0.496296 2.001260 1.428112 0.781258 1.096030 1.734409 0.714218 1.603928 1.472731 1.440090 1.838064 1.335605 0.762426 1.846026 2.406271
+1 0.012048 1 1 1.392161 1.040436 -1.063265 -0.913342 -2.290633 1.557521 -0.068777 -1.403176 2.320437 -0.149625 1.663793 0.058943 33.583418 -13.496338 -32.949836 12.107572 -58.045613 1.785808 0.570423 1.354796 1.547184 1.766077 1.953583 1.118876 0.948349 1.397827 0.269656 2.109446 1.710454 0.853264 0.814743 1.383605
+1 -0.011294 1 1 -1.537266 1.197290 0.956210 1.781609 0.984843 2.342523 -1.228035 0.681802 -1.491237 1.968261 -0.415539 -0.201422 -57.633397 55.493127 -27.014733 13.378717 6.093486 0.823234 2.337949 1.415656 0.675314 0.259596 1.773208 0.297793 0.260720 0.418653 2.057379 1.863860 0.650310 0.764447 2.065147 1.925620
+1 -0.006404 1 1 -2.107137 -1.043893 -0.477987 1.097620 -1.307838 -2.245475 1.826044 -1.460502 0.179148 -0.283294 -1.811519 0.552613 -11.111588 -2.451712 44.084259 74.144788 -48.542334 1.359931 2.363897 1.019996 1.827859 0.827854 1.249078 2.255472 1.210101 1.917198 1.598570 1.414880 1.137295 2.274488 1.316515 1.665171
+1 -0.045665 1 1 0.432485 2.264351 -0.310804 2.355090 -2.072961 -1.567070 -0.198213 0.288106 -2.136066 -1.889041 -1.750098 0.830734 -21.232714 -8.223639 -64.700310 -68.116777 -38.667370 2.387777 1.865314 0.332288 1.769005 1.674216 1.548265 1.934539 0.549566 1.799243 1.377901 0.638979 1.571084 0.707400 1.776510 1.810223
+1 0.044087 1 1 -0.604255 -0.521012 -1.021821 -1.807961 -0.917577 1.930227 1.247529 1.809405 1.632298 -1.499721 0.756689 -1.073858 3.570904 16.178284 -41.576128 -69.984778 65.828084 0.964225 0.479886 0.691893 2.152145 1.603287 1.941524 0.941571 2.232079 1.805024 1.787296 0.837859 0.642249 0.279083 0.805828 2.295704
+1 -0.050383 1 1 -1.213611 -1.945991 -2.288919 2.085802 0.617543 -2.349248 1.297742 2.206716 1.772331 0.551919 2.119487 1.267707 52.264060 2.048979 -62.818717 55.826574 27.234634 0.362296 2.114381 1.398060 1.950428 2.101812 1.655612 1.620735 0.444623 2.032801 0.531976 0.928217 0.542335 1.781812 0.910601 1.478928
+1 -0.059627 1 1 -0.186496 -0.696469 0.011641 -2.263513 0.254985 1.964945 0.403107 -1.391042 -1.084276 -0.612812 1.743705 0.108176 -27.763615 26.931062 -69.637572 51.326706 -2.059023 2.035024 1.894328 1.964260 0.573594 0.648502 1.871887 0.552295 0.414154 0.685446 1.786665 1.482446 0.462643 1.140945 0.609847 2.455068
+1 -0.069015 1 1 1.732154 -0.827828 -2.324912 0.333097 0.037436 -2.281604 -2.206970 -1.333294 -1.268081 1.494551 1.879529 2.094851 60.656924 60.923293 37.791603 63.478184 -72.160387 0.630632 0.776806 0.521272 1.017470 2.115458 1.507936 1.387414 0.759639 2.244940 1.949540 0.672322 1.716519 1.536478 1.842105 1.760728
+1 -0.008961 1 1 -0.034688 1.333740 -0.675001 -2.025917 2.131967 -1.037334 1.367390 -0.596860 1.253240 -1.168009 1.080332 0.312873 -17.879121 -44.386684 -57.003000 0.573169 33.249587 0.262157 2.069569 1.994005 0.985697 1.364755 2.433576 2.111727 1.787075 1.614225 1.277637 0.751087 0.266736 0.283104 0.877497 0.834597
+1 -0.010222 1 1 1.398120 2.226100 -2.303296 0.772791 0.953720 2.334879 2.241083 -0.247701 -2.065791 1.127256 1.990099 -0.936856 -52.596421 -38.043339 55.601856 0.388878 -64.123703 1.718943 1.783994 1.595152 2.467713 2.109771 0.427077 1.886945 1.626131 1.132290 1.391789 2.300448 1.128698 1.783871 1.764909 0.322278
+1 -0.018135 1 1 1.590823 -1.124607 0.131566 1.114296 0.936440 -0.627605 -1.838987 0.704361 0.673616 2.302703 -1.328315 2.301072 -14.416575 -49.368330 66.482227 16.788221 9.635945 0.644922 2.449870 1.466722 1.689853 1.114657 2.041138 1.157276 0.581962 1.776865 1.011578 2.085724 1.257100 2.073054 2.073416 1.400801
+1 0.009788 1 1 2.072034 0.114424 0.462990 1.319153 -0.791811 -0.187354 -0.986740 -1.248186 1.289678 -1.371294 0.948938 2.080248 48.209210 -47.802324 -13.656309 -21.590600 -23.210647 2.104720 1.028038 1.986623 0.666621 0.402195 2.198020 0.874034 1.135318 0.540081 2.137219 0.482853 1.063226 1.646316 0.627175 1.182531
+1 -0.007637 1 1 0.352312 -2.168619 2.348896 2.216910 -1.259583 -1.759496 -1.612162 0.627704 -1.223646 -0.947807 -1.911690 -0.711323 3.891182 -0.896984 74.382451 45.845573 -23.458344 0.409074 0.814054 1.054678 1.969320 2.362487 2.063329 0.620702 0.380921 2.392072 2.053040 0.943815 1.699294 2.277457 1.725074 1.318831
+1 0.028121 1 1 -0.636488 -0.335523 1.602087 -0.314656 -1.120485 -1.284164 -0.202317 2.009947 -1.933267 -0.492435 -1.405317 -0.666282 -49.892606 -45.026176 -4.937904 -41.346929 32.171389 0.693029 0.992967 2.039331 2.287026 0.550459 1.057271 0.548698 0.722644 1.477676 1.298700 1.503014 1.910063 0.925153 0.794851 2.313328
+1 -0.018797 1 1 -1.157224 -1.436700 -0.327203 0.058877 -0.050045 -2.300869 -0.836637 0.415464 -1.057802 1.364341 -0.011639 2.302680 -54.146761 5.381694 0.134712 14.099168 -35.288052 1.580707 0.439683 2.252112 0.990129 1.599248 1.564985 1.696794 0.765943 2.461553 2.074284 2.497193 0.321222 0.273196 0.847640 0.780441
+1 -0.015894 1 1 -2.179736 -0.707992 -0.444209 -1.404949 0.805554 0.260295 1.676934 -0.566186 -1.566915 -2.310020 0.872703 -2.145096 59.382800 -53.275611 -53.191092 17.320756 -40.056559 0.916291 0.353634 0.529467 1.502725 1.549077 2.094555 1.184617 1.111114 1.000433 1.534499 2.322074 2.354305 1.802064 1.548579 0.468624
+1 0.014108 1 1 0.073994 -0.457362 -0.972228 2.331230 2.179462 0.816465 -0.145638 -2.004843 -1.810558 -2.144217 -2.210130 2.104633 43.826036 -65.809800 34.683083 18.579933 -27.066498 2.025441 0.585038 1.738830 0.773146 2.013904 2.441408 0.999874 1.134339 2.080305 2.430179 1.267750 1.079738 2.412696 2.175883 2.315129
+1 -0.021292 1 1 -1.598499 -0.644623 -0.403203 -0.216227 -0.879882 -0.706380 -1.615289 -0.090299 -0.265069 -1.809157 -2.168220 -0.374844 14.598258 -47.082135 -59.446049 40.248441 -44.459468 2.420874 2.375656 0.644850 1.240197 1.492919 0.997735 1.180329 1.039046 0.254340 1.189662 0.400483 0.411730 0.446629 1.987870 1.380776
+1 0.020732 1 1 0.270580 0.187970 1.905025 1.790091 2.171963 2.013345 -1.382968 -2.037790 0.499511 -2.195010 1.751015 0.438909 59.228894 60.021694 34.604365 45.555689 54.461264 1.831924 1.652269 1.691088 1.619578 1.245346 0.284522 2.207112 0.684637 1.694903 0.488444 0.534786 0.906213 1.977405 0.997142 2.466177
+1 -0.007551 1 1 2.296072 0.322844 2.081089 1.506810 0.581195 -0.641148 1.451905 1.421197 -1.045235 0.512296 0.629159 -0.324189 -35.549057 -22.995921 57.547693 4.083568 -67.471657 1.432973 1.475258 1.154427 2.213584 1.459587 1.024167 2.171079 0.316327 1.260731 2.357770 1.536491 2.060866 1.972098 1.801972 2.244925
+1 0.004681 1 1 1.677339 1.521009 -1.115238 2.076422 -1.529568 -1.369942 0.118903 0.341847 1.026278 1.303589 1.524030 -2.167002 39.736847 57.181340 -3.225574 -62.223844 3.846993 1.471143 1.749662 0.572634 0.265414 0.565200 1.314551 2.404473 1.221850 1.379729 2.101413 1.697760 1.252891 1.090458 0.322456 0.773450
+1 0.013695 1 1 1.973207 -2.096682 0.307968 1.810418 -0.205207 0.552698 1.072272 1.500766 -2.038546 1.940245 -0.033236 2.174224 73.796123 -58.568405 -59.181713 -17.048873 -40.410137 1.777489 0.250417 0.509975 2.403964 1.675320 2.096050 1.555384 2.341985 1.739402 1.381941 1.040031 1.042213 1.729405 2.112194 0.650222
+1 0.005835 1 1 2.062412 -1.371517 1.914117 -0.906882 -2.102462 2.129830 0.750849 -0.255156 -0.136089 -1.731841 1.381072 -1.557322 -41.462135 45.898677 -30.941151 22.080362 4.645388 0.250408 0.357760 2.375523 0.657408 0.809634 1.015384 0.804770 0.268661 1.142063 1.404233 2.200080 1.747500 2.483174 0.955205 1.888341
+1 0.007262 1 1 -0.552094 -0.349419 -1.047168 1.011154 1.590268 -1.030326 1.333120 -1.668191 1.422404 0.393131 0.590018 1.564579 23.733780 43.640409 -35.643205 44.657785 -36.611995 0.807921 1.476188 1.043961 1.852737 0.458897 1.180579 0.734382 0.750096 1.617131 0.627013 0.705304 0.292159 2.313197 1.660834 1.640870
+1 -0.017917 1 1 0.921103 0.776166 1.121379 2.181789 2.236367 0.602768 -0.915468 -0.325310 -1.120617 1.204233 -0.163207 -0.403451 10.423921 -5.167267 3.739283 -3.875464 -34.916095 0.852912 1.636157 0.884673 2.203917 0.980351 1.516296 2.391419 2.329645 1.337602 0.571215 1.154912 1.351279 0.939404 1.820473 0.446600
+1 -0.039281 1 1 -1.138103 -0.505548 -0.309809 0.226005 0.272789 -0.382886 1.961990 -2.134900 -1.134446 -0.308574 2.130546 -1.357060 -4.721416 -2.844772 37.915622 47.859456 73.880206 1.444375 1.861829 0.263355 1.950116 1.343666 1.242648 2.185018 0.603490 1.364345 2.302642 2.002813 0.532307 1.991551 2.488464 2.108166
+1 0.006445 1 1 0.353556 -0.108883 -1.585253 0.506174 1.400291 1.022442 -1.894641 -1.625943 -0.085858 -1.024989 1.505346 -0.469511 69.500669 47.746559 -23.580367 -15.229360 -59.861900 0.640730 1.753179 1.172701 1.080527 2.173138 1.182045 0.636177 1.723626 1.723983 0.991250 2.444860 0.507704 2.483045 1.042885 1.773238
+1 0.001210 1 1 -1.271722 1.571454 -1.505120 -0.444847 2.024551 -1.539186 1.915294 0.020758 0.165153 0.131780 -0.003165 -1.352077 -39.000958 10.907091 15.475433 -4.398921 17.335433 2.224453 1.883872 1.733264 1.717853 1.452998 0.538154 1.253818 0.913604 2.442322 0.600615 0.279109 1.243226 0.646723 1.219993 1.669532
+1 -0.056382 1 1 -0.352732 -0.184708 1.079235 0.710253 0.743227 -1.128623 -1.398277 -0.164304 -0.002457 1.117344 0.335914 0.263601 21.999789 0.456150 16.505689 61.109662 20.092414 2.023000 2.309647 0.486616 1.299196 0.842107 2.284667 1.402117 0.378880 1.831189 0.541558 2.216357 0.819777 0.497778 2.157880 1.239139
+1 -0.022887 1 1 0.488166 0.342466 1.996786 -1.653417 -0.022956 0.588963 -2.020594 2.056612 0.099276 0.344643 0.894846 -2.275740 66.836986 -20.783927 34.540695 25.460133 -41.542657 2.013408 0.854077 0.971272 1.918572 2.192556 1.284946 2.088285 1.549904 2.485341 1.375774 0.890417 1.995418 2.237973 1.858373 0.670524
+1 -0.065250 1 1 0.893959 1.670098 2.352613 -1.280261 -0.577925 -0.951775 2.073531 1.725424 -0.843832 2.006446 0.488045 -1.697232 -41.046319 -15.481500 52.437374 64.937527 5.012500 0.551335 2.292776 0.442174 1.373385 1.228024 1.652026 2.101691 1.869322 2.441518 0.596177 2.200864 1.420653 1.415501 0.321194 2.053467
+1 0.065098 1 1 -1.622846 0.130859 -1.331448 1.482938 -0.083829 0.092569 0.724150 -1.318173 -1.595477 -1.689454 2.204568 -1.349114 46.307226 -64.457298 -33.801539 -52.474027 69.030557 0.573534 1.889927 2.261551 2.138930 2.244966 2.387519 2.040022 0.401560 0.515161 1.812245 1.654714 2.271720 2.048386 1.470561 0.973613
+1 -0.010801 1 1 1.111155 -0.024312 1.359584 0.154283 1.224582 -2.165851 1.746717 -1.118920 1.453990 -1.236380 1.801213 0.596936 1.110860 70.227862 -30.324804 31.014582 12.074285 1.112677 0.266494 0.709326 0.393781 0.280090 1.978817 2.231157 2.049251 0.260480 0.889110 0.275242 1.490635 0.853512 0.478839 1.096280
+1 -0.067064 1 1 -0.520606 1.082264 -0.205015 -0.926675 -0.181005 2.057530 1.397797 1.510469 0.820803 2.071032 2.129621 1.940449 -42.089053 9.293353 43.378641 64.813405 18.894948 1.635852 0.263422 0.834174 1.715128 0.653946 1.121097 2.274918 1.793103 1.673382 1.027733 1.359930 2.345231 2.302372 1.959166 0.447290
+1 0.000404 1 1 -1.730959 2.060215 -0.606447 0.339728 -1.611216 -2.322830 2.341882 2.133862 -2.175485 0.048046 1.698979 -2.334194 -5.168627 -19.121151 -69.177740 -20.281960 71.091268 0.339225 1.352144 1.979341 2.031930 1.653747 1.773203 2.473746 2.248822 1.947799 0.653818 1.219835 1.272709 1.163572 0.656345 0.932500
+1 0.008464 1 1 1.145264 -1.652847 0.135877 -1.819716 -0.560751 0.231648 0.876553 1.293930 -0.591172 -2.118948 -1.628009 -1.816487 59.341991 10.839779 -65.830157 -7.443910 -9.790520 1.386034 2.325599 0.835314 0.625911 2.439163 1.511476 2.371997 2.157821 2.497963 2.006666 2.291167 0.402078 2.479772 2.284347 0.519543
+1 -0.006099 1 1 -0.830029 -1.619072 2.294470 1.679176 -0.579844 -0.223924 1.706343 -1.085052 0.468849 0.833448 -2.170779 -0.961047 55.860247 -6.836692 -4.284052 -2.057363 71.901808 2.180242 1.325457 1.201424 2.327372 1.385937 0.692580 2.436591 1.041803 1.587236 2.180786 1.474015 0.516380 2.051600 1.485810 0.760272
+1 -0.046397 1 1 0.327569 1.375709 -2.142688 -0.080511 -0.689528 -1.130679 1.748377 -1.490496 0.300156 -2.249632 -2.070446 -1.701741 -53.212371 -40.318884 60.523110 61.912387 11.492972 0.810624 1.904757 1.758088 0.425797 0.614116 2.197226 1.022040 2.432994 1.336875 1.857929 2.207496 0.388932 2.034371 2.180283 2.012819
+1 0.003885 1 1 0.813431 0.692660 1.930004 2.197809 -1.843427 1.481025 0.743343 0.815185 1.896267 0.676887 0.728920 -1.251820 47.279786 -68.634692 -43.264829 48.016592 14.867773 1.114882 1.316138 2.087275 0.336589 2.051434 0.958748 0.680754 1.683702 1.226331 2.449169 0.927327 1.342119 2.247771 2.294550 1.006198
+1 0.003725 1 1 -0.802812 -1.294276 -0.509716 0.324562 -2.036818 -1.999342 1.103284 -0.358574 0.590585 1.679303 1.545159 -0.486511 -25.567266 40.956883 12.326714 25.089154 23.406527 0.527461 1.538605 1.576826 0.461816 0.742323 1.466480 2.125937 2.118555 1.799338 0.719098 0.382646 2.139251 0.897684 0.382275 0.395053
+1 0.004583 1 1 1.115656 0.233902 1.055818 -1.725951 1.405651 1.572698 0.540233 -1.079086 1.793148 1.716563 1.025233 -2.118792 31.411128 -73.174356 8.602737 -13.804735 33.824636 1.234882 2.164693 1.002547 1.056323 0.366480 0.431943 0.417230 0.638642 0.410142 0.754863 0.729479 1.602075 1.827002 2.171080 0.337317
+1 -0.021900 1 1 -0.609540 0.186740 0.096227 0.932261 -0.176496 -2.269959 0.303774 2.006607 -1.527724 1.358543 1.511267 0.087113 -46.247947 10.761539 -30.806937 27.814511 -71.519076 0.308237 0.296534 1.603496 0.961752 1.671953 1.766653 0.391849 1.562587 1.904497 1.875460 2.099232 1.045681 1.514388 1.825708 0.675176
+1 -0.003137 1 1 1.861146 -0.551834 -0.688545 1.251735 1.802342 0.720094 1.200885 0.119191 0.483021 -1.308912 -1.448417 0.657004 36.203779 -73.081159 74.962106 38.115114 -49.278169 0.352252 2.049167 1.106118 0.281290 1.895129 1.925625 1.483623 2.247184 1.422108 1.116602 0.988337 0.734140 1.198260 0.899605 1.162027
+1 0.064351 1 1 -1.536181 0.583752 -0.079988 -1.324814 -0.107110 -0.061224 -1.687991 -1.486842 0.447008 1.322384 1.682644 1.149758 -48.470857 0.314529 36.293528 -64.669402 1.367875 1.972990 1.037583 0.408613 2.052847 2.200159 0.817038 1.701562 2.145936 0.738559 1.208181 1.152836 2.469078 0.300926 1.160101 0.816103
+1 -0.005553 1 1 -0.182554 -0.412795 -1.208849 -2.023141 1.670599 1.334836 -1.097386 0.520978 0.450499 -1.263933 0.530944 -1.690808 -54.301309 -42.108477 -17.180119 3.738253 -21.179566 1.150515 1.702401 0.504531 0.909245 1.172502 2.245655 0.467961 0.526119 1.489751 1.741202 2.377235 2.439208 2.267233 0.884278 2.313561
+1 0.001012 1 1 2.167643 0.094230 0.358328 -0.022060 1.511926 1.740360 0.432212 -2.312900 -0.420832 0.371493 -0.231467 2.160110 22.842276 60.129639 48.835023 -29.774844 -25.800705 1.638142 0.501837 0.625829 1.056848 2.445605 1.782077 0.860233 0.933381 1.833039 2.391679 2.198907 2.280508 1.254660 1.577986 1.964361
+1 -0.000152 1 1 0.789246 -0.510192 1.752492 1.699799 2.023124 -1.957200 -2.183781 1.997647 -1.322909 -1.082911 -1.242290 1.430764 -14.837125 -67.554154 -32.665676 -12.016507 -61.432354 0.721358 2.364776 2.284276 1.570013 0.711562 1.976636 1.577546 1.312226 1.585989 1.461067 1.149442 1.673264 1.294253 1.014823 0.382598
+1 0.059054 1 1 0.590124 -1.366905 -0.683584 -0.185036 0.282503 -2.063655 -0.673356 2.065876 0.303575 -1.330229 -1.588608 0.665205 73.704735 55.487062 21.050720 -50.542954 -25.425443 1.743585 1.934694 0.906821 0.936256 0.657023 1.082640 1.683445 1.418596 0.590583 0.435122 2.097057 0.484326 1.061926 2.287853 0.950225
+1 0.001029 1 1 -2.029367 0.694978 -1.525387 -1.777532 1.561106 -1.075227 0.669485 -1.155421 0.589426 1.038596 0.992815 -0.329088 43.137695 65.239029 -27.633717 -39.877015 -12.983446 1.933463 0.455784 0.619719 1.872420 0.513648 1.128103 0.769268 2.090045 1.891011 2.469652 0.940925 0.377388 1.515328 1.864040 1.426527
+1 0.030961 1 1 -1.424116 -0.900391 -1.386894 -2.055627 2.306114 -0.535525 0.100493 1.946688 -0.136240 0.433517 0.762868 -0.893611 -16.976250 -19.828762 38.003799 29.844304 -6.786359 0.499970 0.749065 2.292332 1.975748 2.389656 1.950202 0.548320 1.112295 0.584932 2.204248 2.046502 1.316028 2.485689 0.482057 1.177494
+1 -0.052545 1 1 1.466452 0.861169 1.915826 -0.463464 0.146248 -1.869145 -1.939813 -2.127775 0.796703 2.297020 2.126412 -0.153211 -65.501273 -29.901962 -62.275074 42.830544 2.954518 1.473659 1.284631 1.299357 1.298819 1.253892 2.163673 1.848417 2.099604 0.536094 0.373413 2.207499 0.433079 1.506150 0.611004 1.643551
+1 0.051567 1 1 1.179894 0.750801 -1.068122 2.279180 -0.827614 1.263931 -0.559305 0.971890 1.420861 -1.984991 1.962845 -1.906331 -5.416914 7.920589 71.332850 -58.794307 44.085727 0.607320 0.476555 0.963644 1.971887 0.496490 0.752576 0.552978 0.655862 1.828986 1.760614 2.397953 1.895887 1.170924 0.475263 1.742517
+1 -0.008716 1 1 0.343960 -1.173201 -1.359374 -1.342666 1.448261 1.431383 0.509365 -1.509170 2.170840 1.990946 -0.846664 1.527758 -24.975854 -69.176927 -6.610076 54.453376 47.885666 2.340876 1.095646 2.028969 1.387348 1.904812 0.417116 0.974121 0.294486 0.930724 2.170282 0.433007 0.295526 0.405361 1.395386 2.001449
+1 0.032714 1 1 1.020298 -0.233956 -1.957925 -0.226382 -1.906017 0.396012 1.878980 2.296307 -0.432741 -1.862527 0.906438 -0.653199 49.466562 -65.494762 -70.457623 68.731209 15.436386 0.464978 2.128954 1.077775 0.913338 2.470978 0.727453 1.296545 1.281818 1.267371 1.450318 0.495247 2.360162 1.242908 2.054316 2.138317
+1 0.017087 1 1 0.533919 1.195060 1.168473 1.998368 1.372961 -1.208691 0.642205 2.162625 0.585706 -0.219072 -1.573771 0.268774 -60.126850 -1.966028 -43.027082 -6.166797 4.637240 0.446332 1.508920 2.163982 0.293047 1.484763 1.167917 1.674738 1.320247 1.394397 1.129209 1.374706 0.934007 1.100036 1.556008 1.574820
+1 0.064859 1 1 -2.329811 -1.887359 -1.759688 -0.118627 -0.425684 -1.062035 0.901505 1.263613 -1.186827 0.532367 -1.328300 -2.151343 17.063719 -10.080907 70.199216 -61.773301 -73.868391 2.034296 0.913996 2.277542 0.902856 1.803482 0.614653 2.225406 2.154278 1.441762 0.689069 1.932742 1.852257 1.391129 2.458013 1.082727
+1 0.069073 1 1 0.565576 0.750643 0.983606 0.398408 -0.258140 1.556961 -0.059987 0.247973 1.926486 -0.375260 -1.813239 -0.091585 53.551945 47.533530 -3.967036 -73.973958 69.694420 1.436788 0.344106 2.397908 1.135164 2.447917 2.387945 2.449694 0.761682 0.592380 1.374031 0.832240 0.700802 1.121924 0.417658 1.085822
+1 -0.059098 1 1 -0.366454 0.094785 0.271719 0.472186 0.363843 -1.576678 -1.457558 -2.180671 -2.292893 1.260163 2.084036 -0.799900 16.694717 -61.884132 13.390766 58.611356 31.059795 1.704634 2.035774 0.997872 1.227713 0.917529 0.913038 1.933987 0.276422 1.067122 1.861451 0.652318 0.764931 1.194847 2.039587 2.090659
+1 0.083346 1 1 2.340015 -0.958638 -0.165358 1.129664 0.046346 1.399212 1.730212 -0.485935 -0.538316 0.304359 -2.295532 -0.670238 -66.065764 -67.292875 8.652983 -69.315230 68.932427 0.584502 1.730443 1.549975 1.430997 2.015398 0.543404 1.737360 0.803942 2.105406 1.305916 1.282050 0.670567 1.469288 2.065052 0.323893
+1 -0.014169 1 1 -0.253087 1.661369 1.723987 -1.427404 0.390183 -1.834138 2.090497 -0.582151 -1.290949 -1.145876 0.802496 0.701090 71.486431 -27.556374 60.029700 19.170175 -6.868756 2.227158 2.349474 1.601320 0.376395 0.575979 2.476177 0.351606 2.449865 1.380189 0.842299 1.014412 2.475954 1.116315 0.659718 1.378065
+1 0.010582 1 1 1.003124 -1.419776 1.359835 -0.333731 -1.273966 1.553211 -1.812265 2.142715 0.531122 1.295991 1.063888 1.961743 -50.040046 26.946527 40.276151 -28.729060 0.691074 2.348241 1.143644 0.982930 2.099162 2.107210 2.376454 0.568407 1.224055 2.451191 1.173831 2.079305 1.376140 0.292255 1.675526 1.056530
+1 0.003137 1 1 -0.961009 -2.327931 1.434761 0.727072 0.678755 -0.866665 -0.041488 0.139390 0.676567 0.060903 1.001828 0.363631 -13.606559 64.555604 36.038093 -7.764387 3.946020 1.686349 0.719687 1.272417 0.753510 0.485162 1.610192 0.999499 1.580920 1.776316 0.797742 1.396961 1.467780 1.487093 2.077388 0.660961
+1 -0.014148 1 1 2.186447 0.401879 1.527190 -0.903015 1.634783 -2.143275 -0.520783 -1.885173 2.007763 -0.946579 -0.132064 -0.072103 -23.926542 16.606644 -42.140917 37.600954 9.226822 1.002898 2.450747 0.452967 0.513650 1.170101 2.383924 2.357105 1.622281 1.681840 1.430659 0.830560 1.723115 2.138378 1.972279 0.350359
+1 0.030032 1 1 -1.736830 2.353475 -0.943631 2.298251 -0.754423 1.453018 1.273132 -1.429125 -0.262571 -2.237880 2.245065 0.703518 20.489200 -38.017284 43.515391 -36.828474 73.832269 0.609267 1.707423 1.666074 1.952281 1.732098 2.367682 1.623279 0.453776 0.621032 1.430643 0.561102 2.192838 1.524938 1.377562 1.690758
+1 -0.001872 1 1 -1.739060 -2.149270 -2.325234 -0.367155 -2.251786 -0.571409 0.180510 -0.955185 1.322858 0.232216 1.003742 -0.452292 -18.754317 -53.810568 -44.223101 -7.651134 -42.601539 0.564124 1.225964 0.783156 1.499401 1.933423 2.032685 0.843788 1.292290 1.767702 2.264616 1.903407 1.564872 2.059901 1.511564 1.613103
+1 -0.011746 1 1 -1.151508 0.393796 2.338787 1.955279 -1.821558 1.464865 -2.248155 -0.802585 -2.196057 -1.700317 -1.310167 1.021196 22.834550 -69.723915 -49.838291 -32.159639 -57.059553 0.626397 1.596421 1.302879 1.992708 1.694009 1.218214 1.013693 1.644950 2.420595 2.188527 1.077562 1.835492 0.859399 0.426497 1.127448
+1 0.013493 1 1 2.221960 -1.203599 1.395237 0.907486 -1.887000 -0.436518 0.630782 -1.316433 -0.618650 -2.121952 -0.287504 -1.886883 48.583105 -63.758828 5.383728 34.310901 63.312431 1.255494 2.081648 0.259268 0.766734 2.256580 1.845932 0.838160 1.200864 1.919023 0.772756 2.216385 1.289577 1.165240 1.695259 1.974595
+1 0.010613 1 1 2.279068 1.990646 -1.175783 -2.341235 -0.693823 2.081636 1.285918 1.409612 2.173990 -1.606565 0.447932 -1.998729 63.300193 -63.651118 15.653460 -12.294211 71.196899 2.219235 1.928733 1.965346 0.814801 2.355341 1.214822 0.270161 1.593587 0.907771 1.152566 2.426329 1.809869 2.223478 1.245554 1.531999
+1 0.003226 1 1 -0.337570 0.171631 0.623960 1.822582 1.610135 -1.712254 0.715157 -1.658827 -1.416309 -1.628373 1.496204 1.393327 57.036663 -34.797109 14.993071 -11.463653 -69.617713 0.401392 2.192385 0.670507 0.455131 0.885389 0.725032 1.116032 0.406660 0.736450 1.769896 0.892781 1.222649 1.317268 0.827530 0.294940
+1 0.000795 1 1 -1.132734 0.184375 -1.957731 -1.690044 1.718490 0.424363 -2.295392 1.672584 1.724808 -1.772480 1.643054 0.206817 -56.564727 16.630216 54.037330 -44.602341 68.461390 1.083832 1.456047 2.283314 1.161128 2.323441 0.574849 1.492367 0.714624 1.684834 2.259218 1.176736 1.404432 1.043405 1.513488 2.442848
+1 -0.006980 1 1 1.229048 2.207761 0.490215 1.791694 0.835436 -1.754400 -0.782933 -1.772215 1.395835 1.526335 -1.134461 -0.554459 73.452353 13.700971 22.214154 3.279454 67.781335 0.638365 0.253302 1.738815 0.517370 0.694566 2.064972 1.240250 2.385061 1.220397 1.703315 2.370222 1.574075 1.480490 1.348613 1.138819
+1 0.006060 1 1 0.927439 -1.117554 0.861467 2.224661 1.776063 2.020841 2.086957 1.175415 0.870911 0.718307 -0.555825 -1.795401 -59.821318 33.100328 -32.780772 3.571500 26.200341 0.612077 1.681158 1.228818 1.490513 1.052677 2.086643 0.955343 1.948474 0.756342 0.845351 0.561608 1.695133 2.107038 1.742310 0.755988
+1 -0.015242 1 1 -0.818579 2.325717 -0.934643 -2.148168 2.063389 0.917034 -1.630632 1.230453 2.263826 0.292285 2.120898 1.416859 46.170328 34.702840 50.628519 -36.482727 34.806962 1.384270 1.923405 2.415682 0.622319 0.573250 1.610086 1.464741 2.144677 2.077320 1.772395 2.391880 1.084354 1.232872 2.132178 1.271565
+1 -0.019233 1 1 0.676522 -0.681325 0.068840 -2.261684 -2.000953 2.307741 -1.476726 0.826252 -0.594327 1.405281 0.067004 -0.117349 70.394124 64.038860 51.120822 -12.344186 -18.730615 2.043268 0.964247 0.857025 1.017713 1.700312 1.400507 0.312352 1.951582 1.229807 2.357717 0.642325 1.552802 1.686235 1.045075 0.321667
+1 -0.006615 1 1 1.666244 -1.158182 1.305899 -2.055132 1.205133 0.828981 -1.842955 -0.018971 1.602068 -0.628660 -0.709227 -2.338387 1.476584 66.939709 55.685348 53.645930 -22.862536 2.115275 0.682150 0.392060 0.601200 1.117143 1.076936 0.305218 1.291213 1.666155 1.066722 1.898545 0.843948 1.728629 0.311180 2.496617
+1 -0.005257 1 1 -1.578767 1.122200 1.830665 0.792821 -1.688249 -1.100840 -0.982324 2.295348 2.290422 -0.387984 1.091344 1.598926 -51.207722 51.808677 -1.563745 -31.864637 -48.948189 0.291936 0.814065 1.246109 1.850734 0.529766 2.030893 2.224137 1.067879 1.091623 1.914298 2.364078 1.803855 2.392397 0.769681 2.273455
+1 0.027353 1 1 -2.169163 -2.086542 1.093676 -1.623857 1.997353 -1.552155 0.723369 -0.306954 1.088992 -0.227551 2.013237 1.513369 -72.698777 51.649400 21.458738 57.005925 48.576821 1.084553 2.325898 1.366846 1.579335 2.133874 0.523376 0.381902 0.869176 0.484743 1.319101 2.384174 2.057741 1.202005 0.843014 1.777991
+1 0.005357 1 1 -0.520408 -0.300776 1.259356 -2.061180 -1.484644 -0.313636 1.881417 0.844324 1.549271 -2.054928 -0.076742 1.389294 -0.965699 -30.503207 32.598687 -63.859539 -37.272110 0.889637 2.374741 1.016515 1.826070 2.254534 1.195488 1.573999 2.453902 1.726722 2.021196 1.239743 0.604819 1.199739 1.010863 1.330034
+1 0.052907 1 1 0.163562 1.668275 -0.015287 2.251607 2.283869 -2.137213 -2.308204 -1.607396 0.616681 2.016074 2.072753 -1.931636 -43.531505 65.995792 -58.721632 65.533482 -28.774295 1.231440 0.565418 0.477890 0.901964 0.316444 0.978204 1.425215 1.597339 0.982193 0.961103 2.006563 0.552757 1.432616 2.225494 1.385081
+1 0.002729 1 1 -1.023630 0.775405 -2.238273 0.341980 -1.460460 0.883720 -0.764407 -1.415323 0.798224 -0.418336 -0.094479 0.161367 -71.122554 -6.761768 54.958022 -20.520266 -34.111115 1.292296 1.875453 1.993999 0.888582 0.395226 2.066034 1.086902 1.311617 0.354422 0.262756 0.888531 1.797460 0.662631 0.846093 1.776690
+1 -0.044063 1 1 -2.130299 0.788941 -0.936861 -1.727492 -0.924084 0.954908 -1.261630 1.534571 0.626754 1.658252 1.180062 -1.136290 53.570402 57.745371 26.457148 65.280556 70.310937 1.613750 2.302037 0.833284 0.251159 1.725127 2.217593 1.339244 1.164966 1.577617 0.265560 0.764182 2.112874 0.827163 0.883893 0.340248
+1 0.004865 1 1 0.832210 0.585067 -1.537921 -0.381126 -1.446476 0.300765 -1.441842 -1.939524 -1.979594 -1.575338 2.207567 1.935731 -15.828999 62.017531 -21.349633 -23.289955 65.723786 1.670078 1.748821 2.191587 0.745699 1.958111 0.719166 1.529577 0.607490 1.090836 2.183158 0.835394 1.969133 1.473782 1.102812 0.962176
+1 0.001228 1 1 0.464603 0.148073 0.522839 -1.257978 1.656197 -0.380952 1.481019 0.654238 1.779829 -0.660008 0.211686 -0.051666 -40.655780 -51.689130 60.791915 -70.282304 15.311103 0.380723 1.317483 2.188517 0.903283 2.219141 0.351183 2.090696 1.583414 0.936224 2.371928 0.995411 0.380863 1.415089 2.394986 1.531333
+1 -0.020560 1 1 2.147500 0.841516 1.481252 -0.154898 -2.130180 -1.915062 -0.834173 -0.580376 0.261478 -2.001266 1.761135 0.882473 58.503454 17.545250 -16.986244 -37.799473 -45.735998 2.351178 1.004272 0.794504 0.975553 1.863184 0.530001 1.469308 2.413153 0.861634 1.980948 2.041386 0.826919 1.272044 1.240962 0.854387
+1 0.019186 1 1 1.354084 1.972193 -0.290858 -1.701851 1.188662 2.024622 -0.345757 -0.764705 -1.710475 2.331056 -0.739845 1.412015 4.472452 18.505014 63.766561 -25.411605 -42.840097 1.172395 0.441632 1.251452 1.654623 0.747104 0.829567 0.775771 1.134664 0.796523 1.156778 1.226563 1.843279 1.230925 0.904145 0.968699
+1 -0.021977 1 1 -0.972395 -0.472308 2.290187 0.372690 1.039866 -1.224090 1.009770 1.891727 -0.232423 0.240478 -1.522122 1.259836 41.442216 69.317421 -32.099577 52.415294 -6.148598 1.532775 0.356169 0.384662 2.262472 1.868747 1.776707 0.621217 2.293867 0.767465 1.039335 0.605640 1.492247 0.949130 1.034405 0.993014
+1 -0.020347 1 1 1.717487 -2.297945 1.174306 1.070572 1.202880 0.651855 -0.570467 1.872439 0.745904 1.446603 1.850314 1.166137 13.799509 28.354109 -2.487124 48.912356 69.969865 1.127811 0.361195 1.612345 1.181356 0.298920 1.200999 1.942458 0.895607 1.472798 0.314498 2.023433 0.585541 1.182892 1.365449 0.608351
+1 0.012338 1 1 1.652665 1.520966 -1.828662 -0.124140 1.159545 -1.973844 0.828397 -2.233475 0.879929 1.496405 0.064724 -0.750359 -29.891198 -31.363853 -32.273854 -26.659751 -20.433252 0.299928 2.393870 0.766778 0.732631 0.573654 1.654998 0.308940 0.852446 0.561732 1.533670 1.899644 1.322986 2.421543 2.366449 1.154017
+1 -0.000969 1 1 -1.077651 2.346773 -0.478008 0.748431 1.520641 2.131436 -0.527554 2.119953 -0.318368 -2.255082 0.586431 -2.172893 38.037597 -2.102163 68.952648 -12.839760 52.146295 0.966720 1.910679 2.274667 2.083398 0.424246 1.558892 0.551758 0.391010 0.947775 0.759923 0.271611 1.223547 0.646420 0.630861 2.380872
+1 -0.003177 1 1 -0.180016 -0.179985 0.345457 0.434369 0.948139 -1.933819 -0.355964 2.054553 -1.504963 2.197190 1.895098 -0.132698 -41.109202 -22.351274 -57.858364 24.470438 -25.342390 2.431837 2.128705 1.399838 0.326085 1.004140 0.830166 1.844540 2.182559 2.022225 0.536525 0.883688 1.387234 2.250010 1.671394 1.361791
+1 -0.008981 1 1 -0.719068 1.904209 2.210663 2.134193 -1.327784 1.809843 -0.434963 -1.502040 -0.524393 -1.312221 -0.513338 0.715211 -23.776064 -4.310739 -0.594020 66.302424 -5.157261 1.703784 1.253849 1.442676 0.311222 0.964902 0.601340 1.224434 2.061418 2.244855 0.522973 0.358913 1.495205 1.166382 0.628371 1.037122
+1 -0.019869 1 1 -1.477946 -0.836351 0.507217 0.091179 0.916072 1.047869 1.327746 2.269448 0.540184 -1.895407 -0.362311 -0.961024 68.331175 42.051825 -34.983400 33.995351 9.856262 2.187974 0.774112 0.256170 0.450240 1.931863 0.563360 1.896862 1.817765 2.171179 2.007422 1.485611 1.911171 1.551722 1.540841 0.906723
+1 0.025941 1 1 1.222119 -1.153267 -0.900723 -2.254511 0.751682 -0.398973 0.182362 1.903048 1.536837 1.011962 1.027595 -0.121225 -53.310024 -31.574259 31.432068 -21.236618 -73.832484 2.086672 1.445305 1.740163 0.671933 1.928210 2.171739 2.416034 2.038192 1.139045 2.428179 1.398298 1.438572 1.081934 1.065584 0.772998
+1 -0.002945 1 1 -2.306995 -0.123813 1.944733 -0.007298 -0.132259 1.369688 0.327215 0.144853 -1.765442 2.130279 -1.126880 -0.386155 -36.747323 -62.259316 7.674880 -8.294718 -59.319662 2.341596 1.949068 1.731799 1.851082 1.893955 2.454020 1.463583 0.690627 1.123875 1.717186 1.486383 1.382098 1.429141 2.320909 0.761089
+1 0.013812 1 1 -2.246882 1.740512 -1.727650 1.128639 1.673114 1.199132 -1.077335 -1.773389 0.519164 -1.753392 2.025454 -0.486181 1.016755 -11.390580 -41.470196 60.420703 -9.245914 1.433962 2.342039 0.391035 1.377056 2.173371 0.601337 1.162608 2.445776 2.401711 2.051593 1.380929 2.022373 0.775675 1.766824 1.015340
+1 0.038559 1 1 0.870840 -0.466307 -0.526397 -1.997793 -1.135903 -1.239343 -0.884060 -0.232146 0.188322 -1.600479 -0.941287 -0.714864 59.620246 37.474208 -20.985669 -56.134783 42.700126 2.290355 2.497433 2.112528 1.756628 0.645664 1.428388 0.914008 2.488766 0.443336 0.646621 1.758401 1.197185 0.839017 2.117148 0.649196
+1 -0.009007 1 1 -0.587454 -0.892517 -1.005314 2.308840 -1.850170 1.255610 0.967566 -0.570910 -0.853680 1.422176 1.270202 1.166510 63.502235 32.055932 -35.942536 -36.198899 5.098378 1.951638 2.176290 2.413010 0.710866 1.521168 1.025283 0.679013 1.674090 1.689459 1.241946 1.640007 0.344509 2.411740 1.859922 1.958051
+1 0.053296 1 1 -1.873032 -1.285016 -0.386297 1.183214 -0.008025 1.791062 -0.370594 1.201121 -0.628870 0.468165 -1.233124 -0.022069 43.465499 24.644540 50.788375 -49.775468 -26.285379 0.949443 1.788448 2.197293 2.152489 0.632652 0.975218 0.741634 1.140035 1.072765 2.205782 0.828852 2.264975 1.181557 1.421776 2.291946
+1 -0.008210 1 1 -0.300644 -1.239110 -1.675309 -0.391907 1.141405 -0.547845 0.377779 1.743737 0.631553 2.203800 -0.119376 1.129897 -23.693377 35.412954 -14.476111 0.001403 23.578307 1.084088 1.273961 1.956793 1.068055 1.793000 2.202087 1.731413 2.114492 1.013804 1.256819 1.865781 1.427861 1.067996 0.812970 0.842949
+1 0.002363 1 1 1.712636 1.002380 0.210231 -0.946071 -1.010801 -0.372430 -1.386626 -2.265338 -2.152083 2.230510 1.130885 1.728570 6.190528 -55.791766 -42.213923 10.600390 -39.238241 2.468371 1.914945 1.971639 0.835035 0.433905 1.890949 1.425753 1.634783 0.289402 0.978769 1.921188 1.157596 1.465574 0.404995 1.995116
+1 -0.017863 1 1 -0.622741 -0.188046 1.528260 -1.759783 -1.718557 -1.560368 -0.659042 2.308752 1.378944 0.375508 1.274587 -0.528525 -2.086619 30.185897 34.375555 -50.046286 72.074744 0.778339 1.541119 1.084800 1.981823 1.004070 1.906204 1.327665 2.317526 2.408449 0.551338 2.341519 0.659519 0.283331 2.451046 0.976381
+1 -0.012327 1 1 0.606562 1.592094 1.372500 0.469808 -1.899341 -0.494442 -2.149640 0.880281 -2.010611 0.193534 1.170307 -0.158839 73.613078 15.006365 61.981146 -32.881779 -44.057213 0.331320 1.237805 1.797773 1.418700 2.335774 0.849193 2.144445 0.439268 2.029046 0.418374 1.858628 0.462957 1.921701 0.785481 2.334561
+1 0.013991 1 1 0.650447 -0.683070 -0.980569 -1.199456 0.343743 -0.092474 0.874305 1.220513 0.135905 -1.348304 0.928402 0.925445 -52.200523 15.811366 -58.369656 -18.805527 -14.499484 2.232675 0.565471 1.365594 0.792700 2.161213 1.004755 2.165927 1.488309 2.256026 1.521897 2.031571 2.360806 0.809880 0.647642 0.921723
+1 0.054349 1 1 -1.846156 -1.966951 -1.139686 1.160731 -0.880461 -0.999902 -0.978479 0.944424 1.605690 -1.012265 -1.416092 2.020955 -22.484500 -46.995132 52.822217 -66.990904 -16.127733 1.242937 0.296690 1.976529 2.028946 1.001404 2.098980 1.312962 0.445503 1.060516 1.091628 1.997362 1.157508 2.232041 1.160910 0.911563
+1 -0.006685 1 1 -1.046328 1.003427 -1.039171 -1.242449 -1.249075 0.482189 -1.151153 1.632103 -0.061802 -1.988374 1.666249 -1.075164 55.302238 64.720151 -48.422369 65.245011 72.906171 1.135162 2.420006 1.291308 1.022214 0.850649 1.861219 1.260832 1.809377 0.699505 1.831116 1.569118 1.421538 0.546477 1.640422 0.579232
+1 0.029440 1 1 -1.561137 0.545728 1.743144 0.092256 0.164820 -0.752212 0.906098 -1.648018 1.185992 -0.440257 -0.950405 1.538690 -26.144621 -62.651960 8.512408 -31.952104 -19.012693 0.680011 0.445464 0.409112 1.438446 1.205185 0.289727 1.949337 1.749913 0.294066 0.623925 0.558616 0.909946 1.710400 2.186787 1.075329
+1 -0.040240 1 1 0.233026 0.480605 0.496907 1.157267 2.156910 -1.228230 2.112270 -2.212956 1.728842 0.059048 -1.889191 0.446092 1.603665 -47.198727 -69.011211 -71.416177 8.310138 1.652372 1.160833 1.871415 1.630931 0.803223 1.264751 2.424103 0.399498 1.854451 2.258940 1.002762 2.419282 0.372345 2.256177 1.820144
+1 -0.032653 1 1 1.277190 0.801787 -1.802852 0.122131 -1.948642 0.283586 2.004178 0.065698 1.484936 0.508656 0.708645 1.982057 17.465736 -3.383014 -8.313421 -73.670871 63.679381 1.515426 1.271730 0.465242 2.073320 2.040181 0.824357 0.965381 1.908137 2.313905 2.293311 0.433287 0.509773 1.251084 2.222533 1.107676
+1 0.052950 1 1 -0.347569 1.777871 -0.584469 2.158946 0.006130 -0.647304 1.660456 0.518037 -1.839963 -1.565123 -0.470290 -1.493622 -12.947115 47.835560 -27.741672 -54.280244 11.938859 0.720932 1.951036 1.057388 0.266928 1.266371 0.393339 1.844427 0.287249 0.798955 1.534551 0.945902 0.778542 0.458597 0.638446 1.613024
+1 0.001475 1 1 0.307721 -2.340601 0.543445 1.070006 1.121053 1.415447 1.286801 2.102143 1.938366 1.377502 -0.296173 -1.490442 38.091938 11.205781 -64.437750 -5.259558 -47.396233 2.297653 1.399892 1.229091 1.584136 1.822240 0.896761 0.616412 0.283144 1.544344 1.294720 2.106540 2.366344 1.641094 0.622801 1.910388
+1 -0.007034 1 1 -0.092720 1.458652 1.724319 -0.562037 2.183084 0.437765 1.477895 -0.022863 2.151275 -1.680155 -1.727184 -0.474512 -56.088059 -72.002373 56.109066 -24.922326 -69.526780 0.826082 0.702787 0.744969 0.940218 1.999719 0.269997 1.085824 1.200438 1.516395 1.796643 0.433957 0.512910 2.228228 2.329445 2.491213
+1 0.050644 1 1 0.431958 -1.865271 1.918069 -0.462776 2.281861 1.819567 -1.942392 1.647563 0.589836 -1.497052 -1.506644 2.218213 57.049071 23.740805 11.703929 57.929161 -34.595040 0.792334 0.511594 0.365610 1.561479 1.280587 0.819434 1.472745 1.680351 1.166622 2.413391 0.362826 2.017447 1.234332 1.913614 2.108335
+1 -0.002423 1 1 -1.225474 1.311892 -0.290106 1.506590 1.591516 1.094726 1.891870 2.167675 0.639329 0.963911 -0.744648 0.800119 -49.637278 46.273832 -25.707760 -70.318203 11.956731 0.726737 0.517963 1.659087 1.529529 2.053061 1.295051 0.917919 0.710909 2.255019 0.363295 0.895457 1.191685 0.658626 1.028491 0.599013
+1 0.010646 1 1 0.294599 -1.394682 -1.001840 -0.554268 0.809982 -0.727033 -0.013128 0.838392 0.818349 -1.470259 1.128753 -1.119330 -22.704172 10.986781 4.836440 -13.947713 30.786087 2.451503 1.906585 0.967915 1.750389 1.543035 1.780679 2.122784 0.882554 0.330082 0.689531 0.689987 1.615771 0.268217 0.427309 1.286707
+1 -0.007139 1 1 -0.878713 0.105381 -0.722421 2.096618 -1.390016 2.019971 1.597492 -2.137100 -0.403011 -1.706074 0.898171 1.773456 19.470314 -62.438800 -8.913844 35.027390 -44.661726 0.930644 0.831603 1.256074 0.583079 0.311583 0.274536 0.884766 1.506690 0.689248 0.440134 0.838881 2.064657 0.442307 1.352444 0.281616
+1 0.003993 1 1 -0.710090 1.990828 1.879357 -0.798898 -1.477587 0.477672 -1.671517 2.074422 -2.152369 2.141744 -1.645939 -1.574077 -4.935541 -1.636714 -58.245351 -29.620430 19.435472 0.654620 1.192259 1.295632 1.682575 0.279202 0.546915 2.245541 0.799654 2.029059 0.641537 1.810004 2.232016 0.736226 2.493681 2.041540
+1 -0.071732 1 1 -1.839015 0.228745 -0.793426 0.953852 -0.160120 -0.367524 0.971801 -0.077721 -0.924448 -0.445454 1.247151 0.154234 12.627878 -13.250747 44.699617 66.456974 42.355216 0.836747 2.211390 0.588342 1.017214 2.312689 2.110078 1.076785 2.278085 1.022306 2.396520 0.303787 1.990776 0.727422 0.783814 1.313819
+1 -0.011085 1 1 0.868650 0.417445 -0.740781 -0.167207 -1.657277 1.069580 -1.335761 -0.316646 -1.575367 1.716461 -0.689950 1.196961 4.244027 -70.629641 27.631273 -1.192641 55.286385 0.599206 1.357731 1.389955 0.724187 0.416432 0.714574 0.843443 2.243344 2.126462 1.940037 0.702821 1.313504 0.555531 0.814941 2.470855
+1 -0.000280 1 1 0.817476 -2.008000 1.666427 1.907431 -0.183093 -0.049579 0.810545 -0.686956 -0.309139 2.066681 -0.315895 1.613711 58.859078 -5.480417 -9.371562 -7.835358 11.131038 1.815252 0.445870 0.493258 0.431577 1.012434 0.737251 1.722773 0.900078 2.367360 0.711421 1.855769 1.907886 0.336256 0.960912 1.050344
+1 -0.019978 1 1 0.620310 1.741230 0.917915 -0.964766 0.515010 -0.890691 1.414072 1.730472 -0.824102 -0.972681 -0.573872 1.192799 27.479576 -0.765475 34.656351 19.284900 -28.677553 0.870504 0.315399 1.414076 1.131273 2.309840 1.483864 1.807297 1.740845 0.884216 1.272551 0.758578 2.421708 0.649815 1.437224 0.917598
+1 0.003544 1 1 1.790270 0.465219 1.087749 -2.272018 -1.325507 -2.333671 -0.791430 1.506173 -0.696937 1.577469 0.623884 0.546651 -50.945604 -42.761720 -46.230446 4.896062 -61.884046 1.597539 2.080959 2.178738 0.800837 1.667830 2.210078 1.029538 2.453079 1.394258 1.049636 0.481301 1.970618 1.677718 1.908421 0.340295
+1 -0.002633 1 1 1.952141 1.988571 1.656314 1.583140 1.692641 -0.469980 -0.987401 1.786798 -1.336485 1.649678 -1.557641 -1.953292 71.317914 -9.811796 -56.854725 -57.359027 16.827461 2.412109 1.316824 2.355151 0.276723 1.641779 0.870972 1.421256 0.303721 0.885421 1.270798 0.555035 1.477099 0.609412 1.893622 1.347420
+1 -0.012656 1 1 -1.047249 -0.339756 1.130142 -1.347690 1.824706 -0.401215 0.215863 -0.536375 -0.049520 1.809390 1.376676 -0.031386 9.012924 -19.791628 62.112528 -74.739782 -51.511375 2.099685 1.904796 2.412186 0.360863 0.523425 1.205314 2.459866 0.720691 2.399481 0.575222 1.003734 0.766077 2.449875 1.552849 2.480327
+1 -0.029177 1 1 -0.078155 1.197692 -1.723826 -0.578554 -2.098390 -0.119813 -1.512613 0.856332 0.734747 -2.270269 -0.192158 -1.605164 13.830993 -42.500761 -10.284981 -59.671110 7.646782 0.916962 0.376423 1.047997 2.184602 0.353095 0.462634 0.988237 1.294525 1.084022 2.405610 2.331672 1.656638 0.867736 1.044506 2.003743
+1 -0.016081 1 1 -0.313697 0.855575 2.146936 0.785691 0.992011 0.296910 -0.258948 2.109086 0.822527 -1.942465 0.430567 -1.690646 32.684089 21.484061 32.612885 24.764503 -32.996072 1.150223 1.292638 0.864669 1.238840 1.183342 2.178005 1.987847 0.994762 0.713729 2.401150 1.624667 1.279924 0.928045 2.157909 1.734032
+1 0.009386 1 1 -1.529423 1.066189 -1.779917 -0.817625 -0.501413 -1.490386 2.137083 0.118881 -0.023937 -1.762433 0.862578 2.032929 -66.796921 -55.844654 -31.094203 -0.264859 48.513192 0.793386 2.430533 0.463611 1.665453 0.521482 2.292083 2.289886 1.370392 0.432975 2.017774 2.233462 0.289497 0.326428 2.282184 2.416858
+1 -0.023202 1 1 -0.654194 -1.038707 1.846836 -0.734999 -1.953922 1.077602 1.552466 -0.206010 1.201820 1.692696 0.450715 2.355300 46.565047 68.742352 52.708097 -35.012132 1.094671 0.597050 1.127643 2.037451 2.192805 0.975615 0.654635 1.447700 1.491730 1.256883 0.681533 1.270393 0.494943 1.765360 1.155120 0.357279
+1 0.006396 1 1 1.076635 -0.575728 -1.720939 0.817215 -1.680344 -0.200125 1.148028 -2.329747 -0.822829 1.570637 -1.098711 1.824048 -64.774535 34.388921 24.592426 74.900260 48.664490 0.686217 1.256730 0.357823 1.187224 2.179134 0.710827 0.866330 2.159896 1.365001 2.073565 1.655130 0.262607 0.631685 0.474500 2.421991
+1 0.043582 1 1 1.448717 -0.327442 0.745126 -2.190320 0.476600 -0.838058 0.093894 -0.579658 -1.805088 0.244330 1.966029 -0.215152 -52.786994 58.983736 -10.346888 -50.140728 -15.213902 2.124245 0.691372 2.384688 1.705155 1.790658 1.080547 2.498629 1.957116 2.005922 1.023962 0.980620 1.534851 1.483404 0.812414 0.491268
+1 0.014234 1 1 0.044870 0.146878 -0.709364 0.060279 -0.062652 -2.137649 -0.211071 0.966042 2.087724 -0.070624 0.537466 -0.456548 -45.410699 -17.615148 42.213782 -12.967084 12.211106 1.855887 1.648057 0.646172 0.966096 0.421716 1.778695 0.285750 0.348242 2.145174 1.448567 0.320002 2.273311 1.782449 0.374928 0.671278
+1 0.011828 1 1 2.005319 0.390594 0.349869 -0.819202 1.278312 0.814633 2.051438 -2.038081 0.323300 0.324439 0.615036 -2.075794 -65.284039 21.155647 62.965788 15.992847 -8.222243 0.756312 0.338554 1.332137 0.972495 2.217746 1.649852 1.553877 1.760117 0.789772 2.450617 0.522579 0.493563 1.055364 2.250421 1.818599
+1 0.007671 1 1 -1.122719 -1.132054 2.190942 0.549487 -1.047131 1.644694 -0.501445 -2.028294 -0.118456 -2.254392 -1.966262 1.017133 -50.503192 42.851010 46.918751 13.443477 44.522703 0.520977 0.555178 1.626846 1.903511 1.053230 2.391484 1.165506 1.666480 2.026037 1.608815 0.358866 0.712752 1.728706 1.602877 1.802208
+1 0.014622 1 1 1.704460 0.254431 2.093487 -2.171823 0.337849 -0.193176 0.128779 1.406934 -0.424360 2.335039 0.227085 -0.425501 63.753580 56.417004 50.585620 -7.490908 -49.694621 1.112622 1.582477 0.943729 0.254518 1.941384 0.837978 0.399202 1.388902 1.017723 1.877621 2.421981 0.739828 2.284983 2.204762 1.682823
+1 0.035038 1 1 -0.114225 -1.835408 -0.406683 -2.160108 -0.686336 0.674720 2.015707 0.630569 -0.194989 -2.071387 1.328455 0.048278 27.712951 21.562702 4.325821 -45.919662 -21.766702 1.630548 1.113121 0.969062 0.772516 0.433479 1.479075 2.320628 0.543567 2.232267 0.460458 0.409835 2.352760 0.587775 0.490671 1.965832
+1 -0.058784 1 1 -0.657451 0.779854 1.847152 -0.142993 0.036496 0.773487 -1.485970 0.962290 0.282780 -2.115258 -0.878633 1.439068 -72.571150 -53.313401 61.664998 53.623559 51.164163 0.866286 1.420832 2.172822 0.373977 0.426547 1.970460 1.268322 1.683779 0.279615 0.746455 1.164705 1.690675 1.428790 0.918314 0.599152
+1 0.033103 1 1 -0.724016 -1.143227 -1.809877 -0.123709 -1.016330 0.951239 -1.666944 -1.174227 0.256698 -2.230559 -1.950895 0.103694 -25.500581 -38.263212 -39.799571 -61.382713 40.738704 0.555870 2.013409 0.864202 2.398285 0.732958 1.571164 2.052560 1.866732 1.663876 1.016568 0.465499 1.899352 0.901231 1.482904 1.419789
+1 0.003887 1 1 -0.251645 2.330984 -1.948654 0.080557 1.459785 1.916259 2.102371 1.056980 -1.036451 2.073419 -0.159411 2.124027 69.027756 49.488642 5.610146 -60.272791 -54.804938 2.026065 2.074300 0.516123 2.222698 1.633277 1.983473 1.728253 0.754803 1.971345 0.390740 0.916437 0.550961 0.507548 2.114890 0.956618
+1 0.024552 1 1 -0.013426 0.550949 -0.045551 -2.161632 1.965511 0.501382 0.983126 1.770722 1.786802 -1.266854 -1.444740 1.188967 -72.457845 50.999550 49.429772 66.180587 47.128790 0.528544 1.737531 1.433649 1.585900 2.217514 2.254104 0.725997 1.587678 0.596304 2.087316 1.020483 1.000860 1.957519 2.019894 1.866400
+1 -0.019831 1 1 0.954455 0.560041 1.960387 -0.805749 1.183967 -1.479111 -1.575198 -0.149055 1.823660 0.869099 -1.457887 1.719828 -20.585949 61.952891 -57.759647 33.609850 -19.251661 1.184898 1.329834 0.520003 2.190087 0.296852 2.440497 1.433701 2.459094 1.237190 0.456605 0.915204 2.327931 1.786942 1.640430 0.716092
+1 0.034018 1 1 -2.320885 2.043693 -0.254605 -0.298045 0.026734 1.638820 -0.266678 -0.569737 0.002042 1.339784 1.956431 -1.320519 44.169205 1.824808 69.540512 -32.614026 -43.928151 1.368520 0.471898 1.446667 2.127468 0.859205 1.664949 1.049809 1.134463 1.919863 1.388466 0.454921 1.849136 0.671029 2.479561 0.983690
+1 0.023926 1 1 0.346477 -1.269148 -2.292472 -1.080385 -1.193442 -2.247977 2.182960 -1.651833 -1.669984 -0.429754 1.212687 0.552871 -23.414838 66.815990 -73.657307 -8.366657 -68.405666 2.214576 2.373279 1.198276 1.182851 0.679002 1.494722 2.040662 2.151369 2.066958 0.868578 1.695628 1.417885 2.147037 1.253344 1.949943
+1 -0.079704 1 1 -2.158414 -0.500199 0.060135 2.245028 0.091959 -0.108424 1.409470 -0.218584 1.923343 -1.361940 -2.045892 1.003780 5.454682 26.845308 -10.910821 71.836523 6.446562 2.085619 1.744159 0.331279 0.563157 0.727359 1.978716 0.527102 2.247794 0.424665 1.849261 0.532722 2.209598 1.961612 1.066873 2.191596
+1 0.071294 1 1 0.248740 0.685610 1.248305 0.709930 0.032022 0.980120 -1.642690 1.190742 -0.717006 -1.149616 -0.795656 1.165229 -21.733178 -19.523606 66.754275 -60.904417 -20.543073 1.863570 0.267401 2.463620 0.815504 0.679725 2.385123 2.259541 2.100252 2.427975 2.480679 1.767246 1.349838 1.475976 1.975765 0.427252
+1 -0.038504 1 1 -2.241193 -1.606818 0.905889 -0.458197 -0.874364 -2.209917 0.975076 -1.592125 -1.904286 1.210784 1.554673 -0.807366 72.805742 -53.896379 13.551573 61.286757 -3.483398 0.692890 0.908779 2.354400 1.144300 0.753888 2.343398 0.737733 0.830514 0.951896 0.273197 0.868225 0.257709 1.560141 1.288752 0.802365
+1 -0.015329 1 1 0.786959 -1.250969 1.648886 -0.725995 -1.424695 -1.209367 -1.288867 0.870507 -1.357381 -0.819996 2.059468 0.988707 41.933129 70.107164 41.102589 61.210569 66.036501 1.757052 1.023235 2.253388 2.187097 1.782373 1.342846 0.959860 1.366684 1.110930 2.397194 0.387469 2.189067 1.146508 1.865183 0.377389
+1 0.019892 1 1 -1.563553 2.355050 1.974207 0.567243 0.493582 1.831746 0.113340 1.094637 0.399964 2.325041 1.833951 -0.521135 51.253937 -25.082225 -56.959544 -19.055182 -10.439095 2.126917 0.595764 2.006800 2.295056 0.509303 2.361893 1.080564 0.541560 2.252104 0.868625 2.475087 2.292358 2.403496 0.554583 0.620185
+1 0.016395 1 1 2.088014 0.085744 -0.885552 -1.750575 2.248411 0.395267 -1.222912 1.953158 0.232204 0.801820 -1.250524 -0.302384 -70.231411 -29.316825 22.117095 22.007395 -21.707152 0.893365 2.035044 2.233184 2.372989 0.828328 2.458601 1.961773 1.523445 1.043141 1.571376 1.113325 2.147088 2.106217 1.431752 1.208697
+1 0.012324 1 1 1.248914 1.523769 -1.853029 0.321848 -0.516082 1.714193 -1.110048 -0.221081 -2.347710 -1.129169 -1.159092 0.151177 27.349110 56.490126 -70.445094 -20.695239 25.125940 2.000034 1.077784 1.060094 0.751812 1.210652 2.174494 1.466670 0.830553 1.607439 1.976985 0.686716 0.636746 2.293522 1.724418 1.544703
+1 -0.014622 1 1 2.077103 0.484780 -0.019741 -1.911415 -0.791398 2.050867 -2.197394 -0.613775 -0.300695 -2.095448 2.208157 -2.276750 -23.279932 -65.811268 10.022976 6.163273 -63.876203 1.114931 2.140713 0.711327 0.279927 1.491359 1.765731 0.642187 1.483899 2.394603 1.849543 0.768804 1.045750 0.427608 1.806969 0.721905
+1 0.009052 1 1 1.700549 0.488675 -0.525870 2.137803 -1.908075 -1.210919 0.893450 -2.165988 -0.558524 -0.032469 0.932499 -0.890000 -35.091783 12.409862 72.550387 4.358684 56.398173 1.886432 2.012069 0.841921 1.416337 0.867347 1.249910 0.481275 1.546251 1.837116 1.159938 0.318854 0.977235 0.886373 1.524246 1.004031
+1 0.001283 1 1 -2.283907 1.500944 0.941984 -1.705500 1.117120 1.280809 0.359393 -0.960446 -2.280256 1.594835 0.328156 1.815539 33.086657 37.447984 -11.735480 11.788146 -26.624609 0.927914 2.201302 2.029469 0.787527 0.714737 1.332521 0.687091 2.443827 1.157195 1.480146 2.313754 2.015598 1.647700 1.386442 2.433376
+1 -0.028384 1 1 1.614935 -1.142808 0.530136 -1.125627 1.836152 -1.231179 -0.329072 1.627613 -0.127093 -1.335091 1.526944 -0.319221 72.113372 9.449269 -36.132228 -74.350637 38.835931 2.357377 1.690247 0.987650 0.427630 2.171834 1.763588 0.623428 1.197635 1.657032 0.744251 2.373002 1.040696 0.986483 1.062191 2.244775
+1 -0.034961 1 1 -1.218501 0.696637 -1.902310 1.437116 -2.104146 2.101580 1.899211 -1.679613 -2.042197 1.840969 -0.383172 1.865258 -68.169385 -22.849480 -31.212571 -39.686054 46.494366 0.337183 0.784182 0.741930 1.609459 2.175186 1.855558 0.607968 2.367275 1.537548 1.824243 0.803704 0.356468 0.902300 1.453438 1.175110
+1 0.034002 1 1 -1.838051 2.306153 0.120513 -0.869432 0.568178 2.071734 -0.209163 0.037190 -1.696445 -2.203472 0.906076 -2.023539 -9.912538 49.977593 -26.598823 -46.423663 57.490100 0.416585 1.051455 1.804709 0.992910 1.089167 1.126088 0.658515 1.408680 0.425857 1.623148 0.502522 0.888316 0.433215 1.551685 0.913684
+1 0.059397 1 1 -2.299228 -1.540362 1.008418 -1.984025 -0.636915 1.922633 0.848499 1.028383 -1.008967 2.183968 1.158768 -0.891629 -6.645655 56.476893 7.144362 -74.712470 -42.480731 1.770324 1.338341 1.749299 1.222692 2.029495 1.226633 0.773878 0.824728 0.461393 0.382450 1.081303 1.715383 0.447559 1.869743 0.527319
+1 0.008254 1 1 -2.050741 -0.394196 0.373299 1.848467 -1.593476 -1.043160 -2.298742 1.926473 -0.587067 0.912796 -2.171470 1.551815 -54.803139 73.641902 49.441404 -38.315926 -25.769615 0.476178 1.379938 1.116658 1.921456 1.155776 2.381812 0.608209 1.917826 0.899993 0.931054 0.982119 1.972533 2.362363 2.226887 2.297338
+1 -0.059844 1 1 -1.984939 -1.863260 -1.978964 -0.398739 -0.593176 1.908681 1.961507 -0.833730 2.152713 -1.071504 1.989371 0.959947 -44.341778 -52.260037 65.556764 62.540255 64.067611 0.390024 2.386957 1.584269 1.813996 1.837530 1.371381 1.306994 1.393952 0.392955 2.139991 2.080101 1.256221 0.800816 1.307331 0.316480
+1 -0.068309 1 1 -2.123413 -1.280639 -2.217312 -0.782248 0.325189 -0.915024 -2.279678 1.879654 -0.510901 -0.740607 -1.969029 1.637458 13.168332 70.148072 -21.352828 73.014499 4.690004 2.498456 1.302457 1.650075 0.803696 2.467284 1.634275 0.768388 0.791164 1.087411 0.865913 1.906471 1.308166 0.839900 1.199240 1.633400
+1 -0.040333 1 1 -1.002464 -1.626973 1.452211 1.845616 2.322569 -2.009394 1.802659 1.342084 -1.802785 1.262377 1.603538 0.518010 -73.285727 -63.206911 -18.558461 -62.049050 -58.375431 1.887066 1.412580 0.725147 0.791243 2.420050 2.028558 1.230510 0.688704 0.297634 2.084172 2.178949 2.087636 1.896594 1.800020 0.943356
+1 0.048008 1 1 1.324091 2.103823 1.903292 0.934197 -0.635743 -1.951256 -1.251488 2.338129 0.322870 -2.204146 -0.987635 -2.148025 -7.534198 -27.262865 43.032507 -52.659131 -42.020487 0.800089 0.349733 2.464152 0.761009 0.529652 2.368168 0.796404 1.405161 2.042632 1.515311 1.583735 1.834875 1.749918 0.374576 1.503152
+1 -0.020472 1 1 0.212882 1.211332 1.334887 -0.232787 -1.173751 -1.172597 -0.627559 -1.060210 -1.407098 -2.332966 1.624994 -1.738363 4.572184 44.700823 -63.264121 69.918074 13.066824 1.586743 0.636175 1.694429 1.522265 1.455596 1.450543 2.019525 2.405801 1.042944 0.518411 2.437710 1.844061 0.876378 2.291355 1.308551
+1 -0.011407 1 1 -1.057658 -0.930137 -1.814643 -0.124562 -1.217349 1.206196 -0.164209 1.597658 0.638926 -1.113104 0.238265 -1.008321 -35.055146 28.163551 -55.199430 13.171958 -18.902512 1.457198 1.383732 1.889836 0.719678 1.129288 0.440440 1.475029 1.816580 0.252261 2.255321 0.924375 1.219800 0.674291 1.054099 1.251100
+1 -0.003295 1 1 -2.249190 0.640515 2.042062 0.607413 1.748819 1.226477 1.408129 0.800761 -0.186080 1.586747 1.044563 2.322204 40.467418 35.900068 72.444589 26.198979 -73.759521 2.480904 1.044747 1.556161 1.896504 0.289052 1.843555 1.371794 1.484452 0.429246 2.343560 1.208375 2.154117 1.002025 1.275307 2.079130
+1 0.028248 1 1 -0.927086 2.342436 2.016974 -1.646009 1.953735 0.494231 -1.405494 1.074945 -0.699168 1.788183 -1.631416 2.181556 -53.480078 -39.663744 -28.537239 74.626146 -58.356732 2.101013 1.726983 1.900390 0.354103 1.651419 0.899831 0.455570 1.519509 2.391612 1.070483 2.116254 1.379194 2.120003 1.385345 1.991529
+1 0.005814 1 1 1.649831 1.012699 -0.713608 -0.578811 -1.704791 -1.093060 -2.166854 -0.977251 -1.980852 0.841424 -0.058341 -0.366795 -29.431988 36.578104 68.198598 63.841060 26.697516 2.202353 1.701841 2.347733 1.590546 1.556162 1.911366 0.329311 1.238061 1.598394 0.709436 2.232741 1.681286 1.122472 0.637992 0.733834
+1 -0.076734 1 1 1.970988 -1.694335 0.269127 -0.676819 0.403582 1.868485 0.270633 1.070493 -0.131987 1.223449 2.355778 0.068184 27.134214 44.728326 -51.028578 62.684934 -54.317418 1.182291 0.270760 0.407301 0.265139 0.446132 0.382753 1.682550 2.124540 1.135579 0.422356 1.294583 2.049048 1.356808 1.618122 1.531830
+1 0.014554 1 1 1.605111 -1.326330 -2.035359 -1.054300 -1.041592 0.492226 -2.113563 -0.669408 -2.273181 -2.008479 -1.671657 -0.274448 24.690272 69.409839 21.167842 -32.076863 -15.834370 0.951035 1.545122 0.864330 2.293929 1.823919 2.114974 2.373464 2.068280 0.583823 1.568610 1.881101 2.414966 2.083137 0.532585 2.154836
+1 -0.078168 1 1 2.246005 -2.343606 1.864956 2.215591 0.138677 -1.893319 1.756305 -0.186266 -1.551744 -1.795572 -0.042040 0.286779 -28.055327 74.118866 -34.213614 71.789070 -41.104684 2.178614 0.971633 1.234036 1.438749 1.804266 0.295801 0.523584 1.621102 2.117997 1.422017 1.837479 0.503752 1.310685 0.426834 2.303992
+1 0.018227 1 1 -0.272057 -1.438459 -1.626074 -2.279349 -2.014354 -1.447143 -1.490196 0.621530 -1.316154 -0.639715 1.976542 2.107303 -27.949229 57.303100 -56.795932 30.774485 26.768164 2.012871 0.818430 0.351985 2.062327 1.788136 1.450188 0.556460 0.667143 2.424759 2.424559 1.307373 1.015553 1.404153 0.855995 1.710840
+1 0.021267 1 1 1.798514 -2.353258 -0.125626 -0.251893 -1.840540 -1.836222 0.048593 1.463925 0.800888 1.934387 0.479945 -1.179686 -62.681721 -41.685330 44.662758 46.975976 -74.766569 0.599028 0.609021 2.061624 1.205863 0.439797 1.916915 1.341145 1.625179 0.885586 1.795483 1.179950 1.420878 0.705346 0.995493 1.752489
+1 0.031428 1 1 -0.354805 -2.029631 0.973287 1.331946 2.175825 0.951272 -1.106576 1.583242 -1.311277 1.209977 2.127231 -0.528346 -56.115766 62.313003 -5.361028 47.196426 30.323511 0.583674 1.310214 1.513659 0.814472 1.328617 0.319583 1.976602 1.005877 0.766029 1.650834 2.320831 1.699353 1.018458 0.717307 1.770444
+1 0.032596 1 1 2.100665 0.666117 -1.205357 0.123400 0.535262 0.195224 1.315138 -2.292334 1.232084 1.402398 -1.261641 1.343786 -46.796523 -59.165943 -52.007313 -36.907111 -47.810229 1.427131 2.295701 2.353517 2.055375 1.937195 2.435028 1.769879 0.607721 0.471792 1.904618 1.663775 1.563852 0.657004 0.772047 1.540554
+1 0.005654 1 1 1.334840 -1.023477 -1.355838 1.548796 -0.628399 -1.045144 2.051816 -0.398658 0.773630 0.921098 0.704432 1.870659 -28.404236 60.009778 -15.654815 -10.482872 64.378268 2.208228 1.429083 1.347289 1.381400 0.935461 0.785395 0.884891 1.355388 0.250787 2.235420 1.696969 1.461932 2.185575 0.957356 2.027214
+1 0.042569 1 1 -1.190477 0.459129 -2.311211 -0.305063 -0.121040 1.435345 1.129283 -1.645743 1.721895 1.112817 -0.350967 1.209611 21.750528 11.120037 -5.536079 -44.880176 48.888303 0.860704 2.109939 1.002177 1.595406 2.240494 1.487710 1.197012 2.435855 2.167903 0.938448 1.497116 1.786312 2.293752 1.082658 1.977733
+1 -0.023199 1 1 -1.645504 1.022517 -0.646186 1.605184 -0.105831 -2.129499 0.109318 -0.528810 -0.138350 -2.036501 -1.388121 0.884475 -70.538133 65.590314 26.401594 31.590399 -60.160326 1.905938 1.357096 1.966605 1.730811 0.996294 1.706123 2.316803 1.516463 0.696057 2.382559 1.921850 1.035865 0.790193 0.517893 0.480460
+1 -0.009381 1 1 0.373640 -1.844725 -1.477647 -0.515788 1.941004 -1.415403 -0.543577 1.429824 -2.134152 2.003442 1.829435 -1.028222 -31.626045 61.060368 -58.386687 -5.054592 -52.523931 1.079489 0.480832 0.839544 1.973320 2.093926 1.858612 2.434747 1.549293 1.216389 1.854334 0.291784 0.512597 1.460450 2.026349 2.344245
+1 -0.015287 1 1 1.761855 -1.153297 -1.410859 0.428320 -1.759157 -0.628112 -0.931778 -1.129211 -1.861415 0.744469 0.896187 1.423795 6.579600 33.336975 44.531954 -51.451540 3.967126 0.257255 0.684174 0.657212 2.010050 0.664094 0.673242 1.425680 0.407113 1.594456 2.022212 0.320882 1.307242 1.065989 0.833600 1.069317
+1 0.018670 1 1 1.867955 0.786166 -0.439386 -0.445229 0.304211 -0.075849 2.270175 -1.380518 1.443237 1.817306 -2.241151 -0.904643 -68.972400 -19.125475 8.147377 -17.028879 -4.370102 2.150324 0.252795 2.232716 1.257905 2.105631 0.595779 2.252310 2.069701 1.970458 1.237206 0.722418 2.181756 2.018193 0.265360 1.913690
+1 0.023227 1 1 1.908907 1.056738 -0.396487 -0.443489 1.276538 -0.732704 -1.088266 -1.707719 1.526032 -1.520782 0.217735 -2.049420 -55.814752 21.458490 52.840731 -55.834028 -2.515631 1.671895 0.785990 1.878151 2.326703 1.396341 2.308694 2.465787 1.237658 1.568203 1.787816 0.568583 1.917772 2.246370 1.242458 1.236125
+1 -0.043099 1 1 -1.025311 0.796907 1.004633 0.385808 0.021771 -1.655423 -0.757064 -0.522414 -1.037465 -0.830527 -0.570868 -0.156594 74.629313 -5.138987 29.052688 38.535384 -35.806949 1.264017 1.331547 2.309551 1.120097 1.215015 1.262919 0.881881 0.277956 2.101602 0.371560 0.311735 0.572149 1.105180 0.256552 2.374916
+1 -0.032778 1 1 0.491967 -1.745301 1.342830 1.309693 0.433768 0.272862 0.834663 -0.596838 1.627950 0.829702 0.845059 -0.227447 -30.609305 49.413280 -61.007889 40.401676 -19.027918 1.341758 0.677060 0.352270 2.353509 1.933201 0.566553 1.558146 1.511995 2.094762 2.409414 1.014636 1.746112 1.657309 0.883552 1.362866
+1 -0.050886 1 1 -0.437317 1.336148 2.108461 -0.263861 -0.360205 1.450132 -0.105156 -0.202964 0.557221 1.699590 -1.488196 1.255727 -56.898428 -41.879435 -67.665351 48.441955 -36.059703 0.543667 1.663395 1.921964 0.699859 1.027048 1.088673 1.830772 0.290528 1.910085 1.301341 0.888829 2.305448 1.917504 2.241093 0.304331
+1 0.006509 1 1 -1.688689 0.925187 -1.259200 -0.036796 -1.103749 1.963348 1.843971 -1.768302 1.178261 1.577819 1.782860 -1.560745 -72.533183 -15.206428 25.568785 -15.422179 -0.562229 1.384230 1.246696 0.467946 0.269235 1.774930 2.257711 0.603955 2.420174 1.869860 2.488840 1.686960 1.981348 2.016407 1.755785 2.235385
+1 -0.020839 1 1 -0.865125 2.280244 -1.804946 -2.075411 -0.324164 -0.708646 -2.000903 -1.565682 -0.432438 -1.483435 1.164341 -1.473439 -15.331594 21.904122 42.581022 9.234856 -39.779649 0.976669 0.382212 1.592579 1.968581 1.183891 2.412708 2.389238 1.666771 2.425605 0.887824 1.164437 1.695453 0.733836 0.583911 0.796192
+1 0.024977 1 1 -0.364749 0.481112 -0.403590 -2.004871 -2.281600 -2.147186 -0.283588 -2.039842 -0.994232 0.068519 1.778372 -1.584765 -23.120800 58.712683 -65.944168 26.369755 -53.533686 0.765164 0.614402 0.255418 1.314488 1.357527 2.464623 1.922371 0.785290 1.375261 1.254097 1.111580 2.070984 1.024296 2.101712 2.229855
+1 -0.008306 1 1 0.048388 -1.983701 0.082552 2.002629 2.297361 -1.563055 1.307141 -0.040649 0.113186 -1.483669 1.930400 -0.561153 -57.434421 -50.308289 18.590385 -1.393466 -19.983276 1.241192 2.465673 1.571763 0.867666 2.104942 0.266288 1.748054 0.537557 2.470408 2.403436 1.791465 1.152164 2.414363 0.956874 0.675214
+1 -0.021602 1 1 -1.415683 -0.531953 -1.130894 -1.866283 -0.958364 -0.274864 -1.499324 -1.995856 -1.564577 -0.709402 -0.569389 1.140623 14.506648 63.226066 40.493421 22.926093 -31.157939 1.052671 1.995057 0.667262 2.166093 2.017836 1.019947 0.996470 2.417273 0.362405 1.695945 2.246046 0.297054 1.334273 0.875156 1.989576
+1 0.029560 1 1 -0.024284 1.840880 -1.880831 -0.427324 -0.355249 -0.079578 0.847944 1.134686 -0.366684 0.944011 -0.617484 -1.368869 -22.223815 -15.659789 55.920939 -36.775115 70.640270 1.390284 1.747319 1.685826 0.935290 2.410742 0.844923 2.375927 0.702057 1.964433 1.221474 1.809740 2.299043 2.259955 2.305110 0.727066
+1 0.002710 1 1 -1.365221 -0.652272 -1.721527 0.365068 0.162711 1.501445 -0.064140 1.144309 1.138214 -2.342954 -1.307779 -1.254375 30.371916 10.784283 51.451721 -0.921886 -44.130298 2.156289 1.504283 0.735931 2.041197 2.152661 1.268240 0.306360 2.490631 0.287663 1.002774 0.372001 0.964134 1.195233 1.775861 2.143529
+1 0.016229 1 1 2.105019 -1.563617 1.282259 1.167533 0.342877 -0.519758 1.203104 -0.286327 -0.949580 1.262876 0.563300 0.198954 -62.852755 -66.260670 -43.080383 -1.992197 -32.861208 1.400160 1.242028 0.764873 2.469290 1.604295 0.887247 0.461414 0.737242 1.583853 1.571454 2.433989 2.306917 1.854113 1.077589 2.282557
+1 0.003217 1 1 -1.213833 -0.966465 0.228962 -1.858847 1.491915 -0.007980 -2.166265 -0.497185 -1.118499 -0.892053 2.087585 2.307868 20.961687 -46.932234 59.942044 45.937165 15.929400 1.006336 1.744888 1.326790 1.117415 1.144620 1.625667 2.336392 2.246024 2.177575 1.501064 0.625697 1.096173 1.874277 2.474743 1.000719
+1 -0.007079 1 1 -0.293748 1.565311 -1.077460 0.847964 1.471188 0.343845 1.617693 -1.919028 -1.518374 -1.717867 0.615814 1.576214 -51.714087 -58.662345 11.962163 48.068061 -20.105547 1.916146 1.924648 0.810192 1.401633 1.238121 0.354327 0.925768 2.129310 0.306055 1.861456 0.735910 1.687162 0.876392 0.266984 2.194330
+1 0.011349 1 1 -2.074385 -1.941785 -2.292811 -2.067348 -1.478791 -0.894862 1.996884 -0.013176 0.031660 -0.395458 -1.992475 -1.288635 1.787964 50.309567 2.896520 -68.186076 -3.384904 0.773878 0.821506 0.300709 2.011958 1.232112 0.598473 0.291114 0.499123 2.254772 0.703707 0.448548 0.491525 0.566573 1.899274 1.849566
+1 -0.010466 1 1 -0.109752 -2.060961 2.205732 -0.623913 -1.041445 -1.749844 0.396197 0.273474 1.706368 -0.678035 -1.175633 0.175296 30.330356 62.293741 -29.102706 20.820989 -11.631748 0.703193 0.812826 0.670328 1.953392 2.401933 1.287448 1.391797 2.428080 1.996947 0.945465 2.431260 1.440386 2.318246 1.019601 1.930619
+1 -0.003794 1 1 1.926656 -2.223552 -1.994423 -1.042964 0.984691 -0.211996 -0.442753 -0.482331 -1.221394 -0.811729 -0.364088 2.162795 -40.495772 -62.444953 37.673600 30.194428 27.754249 0.859834 0.981956 1.490604 0.328384 1.404983 1.307076 0.519117 0.799056 0.984450 0.650794 2.137931 1.205226 0.981563 1.626733 2.249185
+1 -0.031041 1 1 1.708588 -1.064338 -0.105072 1.193753 -1.951774 -0.519206 1.052470 -1.439533 -0.829274 1.637387 -0.779475 -0.202012 -72.860376 35.654301 -8.159710 -40.242337 -2.949745 2.479604 1.709722 2.052002 1.501051 0.411832 2.161689 2.264341 1.786575 2.219998 1.252200 0.723529 0.607191 0.553247 0.669486 1.302164
+1 0.033513 1 1 1.651830 1.621301 2.173902 1.619339 2.188919 -0.455473 -2.222202 1.847988 -0.215114 -1.014191 -0.790585 1.571950 67.339898 31.671394 -48.878050 56.614802 74.984272 0.784960 0.319429 1.636939 0.532927 1.148771 1.638007 0.486027 0.403668 2.198921 0.260574 2.472365 1.540939 0.308302 1.378575 0.709049
+1 0.069136 1 1 -0.160014 1.410873 -0.196191 1.282445 -0.409094 -0.274922 2.246011 -2.242516 -0.278817 -1.958699 0.892714 -0.408927 -69.025616 -13.535085 65.834805 -64.437577 -2.354019 1.915114 0.324791 1.757814 0.326644 1.413105 0.551947 1.324653 1.198272 1.104208 1.921538 0.294642 1.294811 1.389784 2.355574 0.640752
+1 -0.021027 1 1 -1.967952 0.884658 0.853945 -1.683483 -1.116694 1.166712 0.677516 1.878559 -0.066461 -0.179223 -0.985077 -1.562891 -20.985565 -54.391459 -57.257565 72.109189 -60.854223 2.471060 2.104009 0.333488 1.685123 0.363124 0.281405 1.569652 1.396574 1.721364 1.961249 1.717706 1.227919 2.127076 1.015180 1.882696
+1 0.042078 1 1 1.954602 0.932025 0.566624 -0.492969 -0.955357 -1.583282 0.634513 0.116973 0.899714 -0.555131 0.449084 -1.491420 -34.945102 -72.329606 -43.680576 -39.441016 -35.149212 0.582879 1.453801 0.525369 2.383160 0.776665 0.413928 1.395108 1.825485 1.430288 1.348477 1.103181 0.409552 2.082780 1.278578 0.809124
+1 -0.031332 1 1 1.105741 -1.478887 2.192444 2.234581 -1.131482 -2.328130 -1.916533 -1.986006 -0.944273 0.923159 2.346142 -1.667072 44.007858 -9.925268 -13.981647 60.464472 -23.623162 1.607816 1.557663 2.386820 1.542520 2.142721 0.714664 2.355151 0.273466 0.889174 1.350256 1.758139 1.289358 1.993660 1.938477 1.477597
+1 -0.000280 1 1 -1.940019 -0.885252 -1.416809 -0.603588 1.276477 -1.755411 1.065931 -1.404168 -0.208873 0.196915 1.451265 0.084314 -43.604566 38.058413 47.740065 17.274653 -64.915247 2.416538 1.495584 0.773086 1.007390 1.458395 1.249611 2.204798 2.283354 1.824542 1.321360 2.093393 1.908775 1.778654 1.838702 0.816678
+1 0.026381 1 1 1.436682 0.029574 2.250427 1.299063 0.856217 -1.197258 -0.418450 -2.005500 1.282773 0.379228 -2.169180 2.352486 41.099918 16.313819 -13.638961 -30.021170 34.202179 1.915376 2.468072 1.390192 2.462824 0.933434 0.477681 1.890664 1.137794 1.650401 1.793528 2.076274 2.193246 1.644038 0.601340 1.220278
+1 -0.050563 1 1 -1.169171 0.401491 -0.286938 -1.798677 -0.386956 -0.468706 1.572145 0.680577 1.492347 -2.162500 1.514587 -0.657624 -68.122056 22.601560 64.422272 45.127479 57.547709 1.440268 0.341810 2.058503 0.512775 2.214020 2.039647 0.843475 0.531767 1.900135 0.563783 2.247297 1.068369 0.321714 1.796358 2.397917
+1 0.030042 1 1 2.312197 -1.975787 1.156755 -1.739809 -0.596234 2.346193 -0.800629 -2.306043 1.742009 -0.120928 -1.395786 -0.703670 48.396353 -52.503479 24.024049 -27.801313 -6.672618 2.174529 2.060122 0.729299 0.831106 1.905201 2.461219 0.959708 1.057397 0.419020 1.473092 0.760466 0.407103 1.436166 1.137563 2.264339
+1 -0.016288 1 1 -1.018664 -0.582330 0.414614 -1.206155 0.846284 1.511831 0.137811 -2.300834 -0.251042 -1.672124 1.304546 -1.242578 41.358862 18.390671 -57.984323 7.477860 -19.615507 1.707541 1.399149 2.240307 0.592156 2.108046 0.683772 0.653505 0.462305 2.218345 0.481774 0.933910 1.719465 1.545728 2.056276 1.332188
+1 0.032085 1 1 0.693758 1.545348 -2.026258 1.113249 2.192592 0.005309 -0.301159 -0.466111 -1.934995 -1.267081 -0.547975 -1.810401 15.228607 47.197269 44.502544 54.255717 25.843142 0.560319 0.280532 0.403985 0.780551 0.464716 2.225353 1.262823 1.511541 1.220450 0.348116 2.282847 2.313970 1.138048 1.426017 1.571031
+1 -0.018012 1 1 0.821370 2.182179 -0.648322 -1.301172 1.402013 1.691093 1.773781 1.357440 1.824447 -0.025318 -1.408346 0.267611 67.249474 11.913358 -22.192179 66.048085 70.171810 0.289063 2.024543 1.248913 1.735330 0.442872 1.852308 2.249038 1.084390 1.838034 0.844340 1.569695 2.122149 1.458165 1.875065 2.212786
+1 0.001410 1 1 1.447564 -0.854114 -1.150998 -0.470004 -1.388370 1.415308 -1.058751 -0.443727 1.998303 0.288515 0.030090 1.495647 46.566637 -54.533728 -48.360509 54.921035 -42.164863 0.402184 1.998207 1.865649 1.464738 2.108225 1.440072 1.540607 1.478891 1.470946 0.680462 1.271878 0.709146 1.865663 1.698520 0.523495
+1 0.033221 1 1 -2.065249 0.810252 -0.892376 1.371844 -1.139994 0.699431 -2.070143 -1.330725 -0.503264 0.375019 -2.228391 1.505059 -18.277654 7.462926 29.395178 -55.234985 15.608708 1.158271 1.560051 2.026779 0.582843 0.836347 2.233112 1.156871 0.533157 0.525500 2.329062 0.537534 2.077315 1.687835 0.941848 2.396650
+1 0.057528 1 1 -0.572856 -0.580128 -0.276141 0.597460 -0.594818 -2.131886 -2.307991 1.984028 0.702784 -2.269043 1.560029 -0.325598 -39.540689 -60.351855 -33.632044 -53.760924 40.152779 1.341249 1.120933 1.770378 2.246454 0.407702 2.497239 1.100928 0.791108 2.405666 1.029159 0.581653 1.092660 1.334752 2.170190 1.127751
+1 -0.007682 1 1 1.724292 -1.013717 -2.262072 0.916634 1.062424 0.917934 -0.643902 2.299859 -1.991962 -2.091249 2.083738 -1.083656 12.262759 0.188599 19.777575 1.708779 69.445649 1.720328 0.310924 0.443900 1.132010 1.196684 1.413270 1.073268 1.671204 0.420664 2.095247 1.566690 1.102000 0.816935 2.225460 0.802529
+1 -0.007155 1 1 -0.142889 1.781773 -0.964393 2.072152 2.100534 -1.549355 0.649102 0.277450 -2.160577 0.851573 0.856708 2.339282 26.857409 42.480472 -30.702102 -10.220499 -25.929497 0.669072 1.087074 1.960166 1.512140 2.294167 1.310778 1.990015 1.425263 2.387259 2.156919 0.834075 2.293703 0.266412 1.592772 0.712131
+1 0.006765 1 1 -0.235101 -2.354812 2.031353 -0.302903 -1.516958 -1.485254 -1.130646 2.295025 1.587146 -1.669220 -1.720641 1.115096 7.790866 -8.917141 -20.393870 -9.777793 64.627933 2.149928 0.336924 0.933568 0.470687 1.344595 1.100714 1.693610 1.252701 2.403239 0.742075 1.806434 0.734067 2.215483 1.876252 1.922998
+1 -0.052408 1 1 1.610288 0.863508 -1.173927 0.582866 -0.826254 0.557520 2.012555 -0.510495 1.376350 -0.805805 0.244131 -1.372872 -63.703929 28.058661 -18.077758 67.122503 -22.099226 1.049602 2.168013 0.551392 0.995864 1.232477 2.233916 1.182440 0.513431 1.982443 2.415640 2.157874 1.133184 0.667039 0.670148 1.171875
+1 -0.039503 1 1 1.362299 -1.338459 1.456171 -2.287793 2.153269 -1.147860 0.445533 0.086499 -2.331560 1.695848 1.582226 0.462166 51.013548 -15.300176 -50.062483 -50.159641 -33.084629 1.324690 1.822029 1.850154 2.037915 0.980831 0.577249 1.327455 1.037964 2.319254 2.207417 1.314411 2.309297 1.357864 1.367130 1.860057
+1 0.014796 1 1 -1.862628 -0.783887 1.043703 2.010542 -1.364133 -1.214583 0.569164 -0.216492 -0.622779 -0.837776 0.108824 0.601307 -60.609492 -13.731277 68.424212 -44.260729 -40.064423 1.183533 0.892888 0.771425 2.337691 1.565658 1.762673 0.998650 0.817433 1.591265 2.398489 1.909381 0.722502 1.340643 2.187739 1.324251
+1 0.029016 1 1 -1.882086 2.041957 -1.161211 2.245361 0.975656 -1.264156 1.494095 -1.070974 1.470961 1.244852 -0.783929 0.339094 59.581164 -19.373789 34.723056 -59.593573 -39.179386 1.556011 1.626556 1.521834 0.969605 0.899679 2.407007 1.067254 1.835703 2.158824 1.358597 2.447677 0.605268 1.986673 1.518525 1.606204
+1 0.017484 1 1 -0.041137 1.331596 0.998630 -1.557906 -1.696152 -1.983410 0.264184 1.066800 -0.930415 -1.774142 1.999250 2.061583 -37.424805 -48.696816 -47.384196 -36.176214 -63.632608 1.776292 0.392727 0.566424 1.642357 1.592766 0.622852 0.523069 1.970219 1.725219 1.512425 0.320169 0.588303 0.359857 1.625018 0.430053
+1 -0.005739 1 1 -0.599393 1.086779 0.277030 0.196641 1.561176 0.106953 2.140981 -0.340189 -1.430640 -2.160984 -1.279694 -0.479281 -57.417130 -59.712068 69.279256 -73.538236 42.875094 1.400672 0.848254 2.103031 1.894914 0.563952 0.582839 0.781124 1.102478 2.105718 2.047827 1.069873 0.853043 1.590722 2.257873 1.072395
+1 0.002376 1 1 1.951704 -0.646452 1.853509 -1.679188 0.376557 0.052920 -1.218781 0.710290 1.354786 -0.376511 0.710293 1.421356 51.871408 2.750328 24.766383 -1.399063 35.950027 1.556443 2.143345 2.206779 1.827967 0.391158 1.186520 1.585979 1.297141 2.307585 1.830889 2.252578 2.071844 1.977701 1.465615 1.086758
+1 0.033453 1 1 0.517891 0.419846 1.908324 0.689306 2.117138 -0.507063 -2.200625 1.640275 0.633628 -0.619188 -1.735465 1.733513 -49.485524 46.801092 -14.044461 54.746348 21.866626 1.560657 0.957843 1.217807 0.926114 1.189614 1.841510 0.758259 1.552500 1.116984 0.645281 1.737106 1.038997 1.679677 1.085810 0.956584
+1 0.043131 1 1 -1.079438 0.585268 1.848963 2.020772 0.926463 1.326015 1.450213 1.259991 -0.809787 -0.710407 1.391556 0.299180 6.113320 -3.428051 -15.255203 -44.196045 -2.926557 1.575251 0.986944 2.073539 1.216974 0.435306 0.695524 2.426189 1.714588 0.583732 2.282284 1.848866 0.645712 2.238928 2.157922 1.942861
+1 0.010029 1 1 1.567697 1.325650 0.021933 1.063362 -2.158216 -1.874203 -2.119311 1.691579 0.528522 0.008425 0.220195 1.593662 -17.311867 39.457643 14.610466 8.108831 -64.870291 0.250378 2.107514 0.743180 2.376424 2.310501 1.349103 0.371498 1.520882 0.717090 0.386565 0.499557 0.561711 1.177504 0.812213 1.608181
+1 -0.005531 1 1 0.815205 2.229892 0.162443 1.698468 -1.491711 -1.283522 1.165067 1.306114 1.556688 0.067885 0.548185 0.629727 -6.439718 67.650740 5.992405 64.342471 53.909275 2.172691 0.411364 1.049616 2.400809 0.392900 1.226173 2.030651 0.395393 0.373437 0.355540 1.063446 0.837231 1.348064 0.902479 2.207026
+1 -0.009071 1 1 1.346026 -1.522503 -0.436310 -0.586220 1.010881 1.711207 0.546453 -0.217168 2.151088 -0.106551 -0.101400 1.662317 -37.807180 -25.278453 -54.967679 8.211542 11.384151 0.376273 0.762183 2.257403 2.178256 1.692039 1.858410 1.297522 1.954967 1.877562 1.432513 0.496117 1.243111 0.965208 1.252915 1.487337
+1 0.042823 1 1 2.152917 2.353404 -2.133224 -1.242434 -0.988475 -2.128422 -0.645954 0.792507 -2.261077 -1.207952 -1.079857 -1.743902 41.562785 -4.279441 -74.570437 -55.342234 13.076515 1.779861 1.879811 0.979832 1.790697 1.740263 2.344943 1.952146 1.710142 2.355472 1.176273 0.363730 1.455847 1.173647 1.244238 1.909855
+1 0.022159 1 1 -0.509963 0.879183 -1.624702 1.930801 1.467917 1.929245 -1.124115 -1.029421 -2.290048 1.962461 1.064659 0.783859 -48.379048 43.345057 -49.625520 -56.116605 48.212625 1.518744 0.788015 2.174700 0.432275 1.492943 1.394667 1.165215 1.263074 1.227743 1.428834 1.658275 1.385292 1.098190 2.033509 1.184053
+1 0.042315 1 1 -0.671049 -1.574324 0.400415 0.480246 -0.826447 2.020960 -0.618706 1.658862 2.007473 -1.108554 1.320436 1.919315 51.870608 -10.683243 -3.270075 -60.154345 -14.068913 0.531574 0.905915 1.460806 1.267818 2.216421 1.882201 0.653865 2.013664 0.650560 0.461402 0.539226 1.263391 2.062296 1.262339 2.379851
+1 0.004739 1 1 1.326523 0.562662 -1.102155 0.488886 -1.694411 -0.998174 -0.212537 -0.115164 1.228387 0.516563 1.656899 2.002242 16.533440 -72.477862 14.576806 42.376208 16.921776 1.439319 2.389835 0.450656 2.176694 2.441704 1.475884 0.425809 0.821959 1.163381 1.943681 1.189885 1.903207 0.452300 0.559608 1.829502
+1 -0.006559 1 1 2.123028 -0.478647 -0.578900 1.517794 1.409445 -0.644706 -1.788154 2.106885 1.518445 -1.789070 0.857305 -1.764917 48.648375 -16.764432 -59.811393 49.924085 -25.903827 0.390659 1.809286 1.411964 1.627640 1.742139 2.371896 0.459700 1.185034 1.358587 2.272781 1.880316 0.474538 0.814027 0.606749 2.134207
+1 -0.014536 1 1 -0.163237 -0.909051 -0.857866 1.753902 1.839104 1.263419 0.262672 -0.785475 -2.075025 1.449764 -1.585733 1.859605 57.563049 -37.828209 71.283493 11.673554 -2.578254 1.634373 2.398800 0.387803 1.054947 1.987346 1.575670 1.292739 0.315484 0.583653 0.948553 0.336700 1.664731 1.876696 0.379158 2.013123
+1 -0.018226 1 1 -0.377561 1.920307 -0.555323 1.931555 -0.006415 0.564218 1.485341 -2.109052 -0.243165 -1.228436 -1.354165 1.383975 3.395787 72.994643 -29.031468 18.111090 43.081965 1.803858 2.434166 0.786856 0.689060 1.776548 2.436851 0.897911 1.948006 1.880587 0.520880 1.180929 2.116215 0.725166 1.118777 1.526484
+1 -0.058370 1 1 0.306474 0.264475 1.255513 -0.663381 0.069658 2.074796 -0.585933 1.115764 2.047077 0.076953 2.159202 -0.401853 -34.585544 -29.232235 -56.178319 60.988994 -57.980088 0.304910 0.616782 1.997142 1.963334 0.758548 1.920247 1.096231 0.598513 0.963033 0.695733 1.427400 2.308145 2.247373 2.349289 0.749770
+1 -0.001032 1 1 1.593443 0.493561 1.468801 -2.070255 1.509442 -2.314128 -2.210084 -1.829237 -0.361235 -1.724667 -0.580306 1.448969 -25.646868 53.083277 -29.367857 64.429983 24.727459 0.540950 1.001854 0.656729 0.645371 1.004026 1.173286 1.925534 2.207017 1.334882 2.114664 1.665857 0.560583 2.469475 2.460704 1.307081
+1 -0.007178 1 1 -0.507530 -0.632178 1.413645 -0.733571 -1.526098 0.412695 -0.466760 1.286459 1.078594 -0.634781 0.089419 -0.392388 -71.047115 61.130009 62.058575 68.468901 -43.181680 0.557555 1.073419 1.960857 1.867147 1.894497 0.305174 0.554157 2.463419 1.929899 1.313721 1.956597 2.278297 2.337403 1.233041 0.473673
+1 0.004458 1 1 0.474667 -0.346060 -1.141105 0.869698 -0.810935 -1.147715 -1.842601 1.226380 -0.215516 1.650946 0.903876 -1.303869 -48.479500 5.035202 26.639784 -15.144244 20.699006 1.947870 1.853824 0.711585 2.353353 1.550325 0.557706 1.366101 0.312464 1.585657 0.380582 1.188251 1.437846 2.374125 1.911736 2.045476
+1 -0.012652 1 1 1.229661 -1.617397 2.187515 -0.494278 0.613181 -0.256416 2.258324 2.072281 -0.435255 -1.711259 -1.427648 1.007096 -20.165749 74.251329 -57.912875 8.310957 32.254898 1.496147 1.234210 2.112761 1.170178 1.439127 1.414034 0.421864 2.014341 0.772842 1.404064 1.603761 0.907210 0.733881 1.334615 2.117946
+1 -0.043665 1 1 -1.890714 -1.584281 -2.017758 -2.114096 -0.199423 -1.187326 1.577437 0.081439 2.159287 1.023926 -0.524105 -1.172116 -62.860815 -51.716339 53.497551 33.333380 -15.884486 1.816587 0.371829 0.323879 2.184685 1.747190 1.775760 0.453069 2.225224 1.346488 1.417552 1.045069 2.470925 2.077915 0.520674 2.211802
+1 -0.037452 1 1 -0.212901 -1.516448 -2.334485 -0.346038 -0.770305 -1.576399 -1.489946 0.117214 0.239356 -1.527260 -0.278797 -1.620096 -24.319102 18.852919 61.003562 36.865918 -44.521744 2.470835 0.567862 1.060794 1.259615 1.606104 2.040496 1.622001 1.466677 0.945014 1.597591 0.704822 1.194895 0.607593 0.571622 1.251930
+1 -0.001455 1 1 -0.861742 -2.120687 2.122121 -1.584613 1.830997 1.664348 -0.051749 2.047986 1.206928 -1.989094 -1.024052 -1.598723 9.777465 -70.150219 -14.725169 14.089718 -44.104259 1.970872 1.441377 0.979068 2.452227 0.574139 0.807150 2.021937 2.440684 2.328710 1.373299 2.035802 1.480156 2.480831 2.084299 2.060118
+1 -0.000973 1 1 1.604663 0.572237 -0.401814 -0.427033 -0.170372 1.695750 -0.055360 -2.086620 -0.223489 -0.401302 -1.247018 2.072561 -14.342002 3.972271 11.950174 -3.417903 5.307601 0.697888 1.649828 1.168039 1.480046 0.636289 1.363776 1.730967 1.360416 1.517546 0.889595 1.675615 0.311670 1.730441 1.517574 1.364554
+1 -0.007080 1 1 1.867115 0.797286 -2.044138 2.197024 -0.903240 -2.157495 0.811083 -1.073332 -0.470584 -1.720618 1.511713 -1.841070 -41.971908 28.133935 47.052876 17.691398 39.332270 1.487046 1.279051 2.017344 1.752612 0.658960 2.146607 0.776774 2.237692 1.632803 0.772506 0.253230 0.532277 1.474452 1.122379 1.320022
+1 0.008184 1 1 -0.733235 -0.580035 1.285175 -1.661079 -1.557513 0.199262 -1.515232 -0.757668 -1.244456 -1.991370 -1.578212 1.036550 -12.998420 -64.447587 -20.587696 32.598137 -73.118525 2.079214 2.106490 1.534162 1.162312 1.981089 2.162535 0.731939 2.449805 0.377444 2.444731 0.588111 1.636452 1.346789 1.982929 1.583657
+1 -0.023227 1 1 -1.391351 -1.565786 -2.192247 1.074926 -1.020105 -1.236381 1.773220 1.364202 -2.342217 1.662227 2.014553 0.078892 56.044729 -56.236199 -11.796226 40.835537 72.873889 1.996781 0.397747 1.690635 0.750144 2.414975 2.233750 0.628664 1.462557 1.453681 0.767166 0.510181 1.356819 1.812653 1.752208 0.602549
+1 0.043501 1 1 -1.507331 0.096725 -0.110595 -2.093914 -0.283332 2.261688 2.053951 -2.214428 0.557093 -0.448132 -1.354151 1.631150 -61.665793 -66.974954 -48.053846 -40.985140 -37.248019 2.463148 1.874664 2.237008 1.390584 2.296125 0.476033 1.189848 1.278146 0.305312 0.634945 1.278066 1.201014 2.191472 1.066297 1.506236
+1 0.029359 1 1 -2.185609 -0.453162 -1.075330 -1.052152 2.070264 -1.352292 -0.124461 0.486659 -1.430737 0.932370 1.654419 -1.978005 50.261673 -52.055341 55.881164 44.720684 -29.455776 0.426603 0.660516 1.298207 2.211450 1.581561 1.300409 0.978411 0.407707 0.335392 2.176804 2.051655 2.411427 1.102938 0.828448 2.229695
+1 -0.020450 1 1 -1.541870 -0.790601 1.303679 -1.682032 -0.292032 2.135121 0.134525 -0.985955 -2.190217 2.209671 -0.403563 -1.556879 45.801293 -17.669754 24.445982 13.614740 72.938051 2.422360 0.355971 1.548574 0.386054 0.905095 1.174848 1.176680 0.453705 1.661746 1.217961 1.271447 2.461691 2.144824 2.313106 2.377167
+1 -0.025880 1 1 1.820159 -1.416483 0.160652 -0.119095 1.130075 2.250342 -0.127490 1.413950 -0.320106 1.527282 0.648786 -0.325694 59.207941 7.865600 47.135296 52.917669 37.260223 1.113555 1.510610 1.327254 2.149278 0.660246 1.259296 0.739678 2.019349 1.697750 1.086307 0.308637 0.263173 1.155392 0.421793 0.831733
+1 -0.032071 1 1 -0.723579 1.491427 1.219134 0.518281 2.248321 -1.115781 -2.328995 -2.314643 -1.438597 0.771264 -1.141305 2.218882 -35.178632 52.726645 -23.278844 -47.535130 -22.934152 2.060675 1.013678 1.385723 1.593092 1.590144 1.553230 2.135862 2.438490 1.452957 2.100580 1.198747 2.341430 1.422957 1.884123 1.448233
+1 -0.033831 1 1 -1.823490 1.979028 1.484697 1.206596 1.855161 -2.182355 -2.317419 -0.959341 2.149342 -1.180781 -1.512852 1.545347 -64.939210 -33.295433 53.652187 -67.698439 -57.658365 0.412977 1.151363 2.450463 2.428602 1.760407 1.160672 1.406708 1.045855 2.190830 1.534104 2.433955 1.738153 0.641320 0.410910 2.416183
+1 0.015973 1 1 -0.874137 1.615997 -2.156172 -0.511534 -1.957369 -0.321178 2.351595 0.452502 -0.591379 -0.886197 1.542318 -1.114051 -49.055016 -67.657525 29.973091 57.738500 60.963416 0.807114 1.413570 1.613798 0.860199 0.372594 1.940137 2.375725 1.811679 1.143263 1.312603 1.166578 1.681371 0.304657 0.862649 1.040868
+1 -0.036837 1 1 -2.016375 2.288684 -1.326492 -0.041793 -0.273006 1.461879 -0.587266 2.278502 1.911770 2.052497 1.629189 -1.915485 47.424659 -33.757299 -58.920032 31.015334 24.710741 0.826368 1.021792 0.506871 1.983504 2.252624 0.602377 0.655734 1.928904 0.337727 0.925925 0.270357 0.390353 1.155457 1.516178 0.405263
+1 -0.010536 1 1 0.518891 -1.622938 -1.408217 -2.290123 0.702093 0.252375 0.518643 -1.093912 -2.349617 -0.198252 -0.362030 -0.949154 -31.722996 -68.386189 -66.686090 6.886797 -53.597833 0.343230 1.169904 1.320658 1.544877 1.253749 2.003765 0.785386 0.725385 0.299496 1.886518 1.216406 2.134287 0.714235 1.892774 0.604994
+1 -0.009191 1 1 0.740019 1.506592 1.623824 2.164921 1.468991 1.119242 -0.755067 0.060297 0.250061 -0.681965 -1.259450 0.468737 -33.534778 -69.006914 0.803210 -0.442213 67.723064 1.698168 1.364966 1.476186 1.007298 2.163969 2.325765 1.384036 2.486258 1.035788 1.736627 1.985247 2.291291 2.473288 1.297716 0.704839
+1 -0.008626 1 1 1.425779 0.578494 1.087890 0.101636 2.312669 1.240848 -2.099162 1.032106 0.307895 0.594934 -0.633487 -1.730943 74.271809 -13.705633 49.425498 -5.652569 -52.729014 1.126909 0.965956 0.321046 1.825182 0.838215 2.134493 1.923500 1.759556 0.351910 0.808437 1.158715 2.276900 1.363549 2.413352 1.957160
+1 -0.012484 1 1 -1.351297 -2.246797 -1.543443 1.053002 -1.935668 1.570664 -0.648727 1.317716 -1.372691 1.034459 2.153624 0.095979 47.368855 -71.657260 6.432462 -39.608270 3.808739 0.827234 2.079250 0.448551 0.552066 1.077134 1.384244 1.487662 0.384905 1.851500 2.153842 0.878184 1.138343 1.876863 0.935628 1.345879
+1 0.018509 1 1 1.450161 0.385987 -1.669814 -2.288705 0.963547 -2.141801 0.687810 0.536417 0.764530 -1.229301 -1.751870 -0.674965 -45.248167 14.053429 -54.016346 -52.720329 -20.575631 0.405456 0.743450 2.419526 2.220759 0.537965 0.331303 0.959842 1.068805 0.901175 0.553026 1.454798 1.535244 1.340917 2.300045 1.107400
+1 -0.046497 1 1 1.685256 -2.069785 -0.022492 -1.039414 -0.610710 -0.622475 -0.437994 -0.610155 -0.715686 2.199145 1.760254 0.216091 -44.952628 31.185467 34.140883 55.816968 15.781723 2.026249 0.664579 2.086575 2.073292 1.566455 1.657809 0.303031 0.544977 1.179408 1.303243 1.346190 0.917893 0.279287 1.978888 1.168677
+1 -0.047975 1 1 0.347346 -0.806643 0.293755 -1.443973 -0.056704 -1.123592 -1.664706 -1.266479 0.152860 0.867163 -1.003139 1.176768 1.342185 58.102796 33.693703 40.060652 -50.625617 0.403733 1.032264 1.017169 1.561175 0.674162 1.148031 0.451805 1.230676 1.223831 0.926843 2.194352 2.228820 1.034194 1.947957 1.058847
+1 -0.059246 1 1 -0.507743 0.501251 -1.218220 0.698660 -0.901480 -0.838377 -0.553470 0.077250 -2.271866 1.238305 2.288620 2.316756 -23.671392 -45.092805 -74.768079 72.889948 11.349104 0.540949 0.984121 1.874986 0.882612 1.317490 2.305918 0.818758 1.365678 2.197150 1.998833 1.135428 2.390751 2.351830 0.700971 1.725322
+1 0.025432 1 1 -1.367828 -2.049191 2.102204 -1.745562 1.673252 -1.191457 -1.878843 0.005319 -0.138661 2.151596 -1.006421 -2.150742 38.424615 52.499376 57.015463 58.888647 41.497161 0.516860 1.110492 1.794523 0.805491 1.134603 2.022470 2.397582 2.414772 1.078792 2.252595 2.360971 1.345324 2.104131 2.383919 2.270239
+1 -0.022719 1 1 -0.593897 -0.792833 1.496911 -0.869150 0.603393 0.169777 -2.273588 0.575261 -1.409284 -1.364018 0.714546 2.204760 60.247043 72.043893 41.715844 18.187871 -16.448747 1.313534 1.072506 2.359306 0.358215 1.026425 1.868341 1.710505 1.711350 2.400719 1.140032 1.017982 1.724150 1.530498 0.328714 2.444087
+1 -0.002191 1 1 2.244890 -2.238397 -1.742123 -1.785003 -1.477903 -0.106109 -2.093054 0.022281 2.200726 0.064396 -1.537908 -0.164967 -54.596300 -50.007356 -23.631786 20.579815 -15.043784 2.261947 2.037773 0.850771 1.666457 1.643034 1.728308 1.673411 1.521921 2.432025 0.787696 1.306302 1.013605 2.406151 2.434463 1.271494
+1 -0.004139 1 1 -0.558151 1.527624 1.676023 -1.740270 1.077212 -0.292790 -1.185991 0.448223 -1.819715 -0.545556 1.143819 2.334532 35.765229 56.197669 -35.770480 5.536147 46.018912 1.972898 1.747911 0.393973 1.262318 2.033018 1.934381 2.384534 1.367393 1.781390 0.575382 1.437784 1.334751 2.167319 2.386267 1.238014
+1 0.016753 1 1 -1.455080 1.765535 -0.569259 -1.378127 -0.787855 0.332063 1.513397 -1.812599 1.252195 0.110603 2.215178 -2.090546 -7.446846 -59.134213 31.288924 -27.062137 -33.330804 2.262735 1.780993 0.658031 2.277994 1.738128 2.471408 1.198194 2.046028 2.347366 2.176136 2.060598 1.962859 1.772840 0.871391 1.716380
+1 -0.060231 1 1 -0.755330 0.340414 0.493675 -1.324786 0.363712 0.934991 -1.416826 -0.885616 1.891604 -2.292147 -0.336282 -1.739052 -63.783320 43.740966 4.421714 65.741471 16.909145 0.505006 2.142857 0.752116 1.812181 0.569010 2.356482 2.394571 1.304323 1.504562 0.928782 1.045493 0.593758 2.039669 1.213641 0.657417
+1 -0.007547 1 1 1.708092 0.023034 0.710166 -0.719248 -1.126036 -0.330668 -1.636131 -1.661370 -1.745784 -2.054263 1.670330 1.540896 -46.358196 -42.201429 70.586965 5.117203 54.829366 2.382376 1.090816 1.844425 2.498385 2.365183 2.387422 0.404010 1.189633 2.162017 1.026643 1.040556 0.871849 0.412379 2.358444 1.621882
+1 -0.024386 1 1 2.193254 1.717714 1.520887 1.552585 1.791976 0.863164 -2.252871 0.037188 -1.733548 0.967895 0.251270 0.794315 -4.488663 9.036376 74.368590 -37.109439 1.662459 1.989216 1.494503 0.605751 1.102849 1.585195 1.615677 0.932127 1.012049 1.001012 2.261823 2.205117 0.908813 0.673181 0.403054 0.870678
+1 -0.011560 1 1 0.416039 -0.811192 -0.761898 -1.658830 -1.467020 -0.989649 1.697338 -1.641128 -0.823287 -1.417778 1.949075 2.283576 -74.501417 54.683000 7.188874 73.407037 2.072759 1.927922 1.828099 0.356059 0.788253 1.670187 1.327727 1.099609 1.125416 0.614189 1.181041 1.757035 0.728630 0.842198 1.563756 1.294782
+1 -0.011423 1 1 1.595440 1.061925 1.963704 -1.594042 -1.134317 1.862198 -1.721020 -0.538711 -1.618052 0.602534 -0.134214 1.499147 -31.364271 -39.302325 45.829607 8.207150 -62.422425 0.869606 0.972318 1.506367 2.006769 1.772939 0.294612 0.791836 1.133638 1.557234 1.937386 1.154665 1.712663 1.980883 0.953675 0.922238
+1 -0.013307 1 1 1.296963 -1.457278 -2.187242 0.365262 -1.279412 -0.443771 1.253088 0.983370 1.155690 -0.787814 1.016204 1.635778 14.112206 33.850679 -21.641313 24.447260 35.100472 1.129418 0.371725 0.839078 0.887027 1.265867 0.928868 2.484457 2.263024 2.139813 1.335546 2.024455 2.008917 1.873917 0.918225 1.352218
+1 0.022013 1 1 -0.409551 1.470332 0.097463 -1.857109 -2.275549 0.595368 1.945588 0.226250 -0.310267 1.958755 0.050147 -0.705299 -73.465096 72.128478 -36.671138 18.177348 -43.303953 1.231981 0.653594 1.945927 0.692230 1.065887 1.363468 1.056359 0.981803 1.163038 0.679971 2.014652 1.502690 0.959271 0.459534 0.634129
+1 0.034520 1 1 1.523621 0.371190 -0.605913 -0.106396 -2.202510 -1.777661 -0.605167 -1.711693 0.717505 0.103735 -0.113775 1.011606 -7.341108 67.993585 68.189251 56.744698 8.137455 0.868091 0.254295 0.443836 2.309655 0.619143 1.194332 2.384830 1.836676 0.516132 2.374261 1.961198 0.847241 0.832046 1.941931 1.030207
+1 -0.033375 1 1 -1.843326 -1.538568 -1.834626 -1.405842 -0.071602 -1.757392 0.765174 0.165854 -2.229723 -2.034966 0.851993 -1.498703 -31.322995 54.421959 -30.128945 22.823059 37.148684 2.243989 1.721608 1.569401 1.665387 1.651000 0.605799 1.914921 1.577630 0.479513 1.178466 1.223370 2.175145 1.158246 1.137004 1.883179
+1 0.028329 1 1 -1.696461 2.242046 1.813517 0.049387 0.667094 1.081277 2.045187 1.299045 0.556892 0.872948 1.971698 0.800866 49.997094 1.157782 -41.162910 -25.024356 15.655452 1.692735 2.288978 1.862312 1.629847 0.594065 0.455155 1.284962 2.353921 2.106856 0.924483 0.784565 0.426414 1.993901 1.491053 1.125444
+1 -0.009590 1 1 0.454256 0.611859 1.086891 2.165479 1.426123 1.631474 -1.206130 1.262707 -2.290285 -2.031335 0.614436 1.986766 -12.999426 68.639238 -30.324763 31.716607 -38.986118 0.779638 0.880246 2.047644 0.253366 0.578621 1.891294 0.474471 1.928542 1.012525 2.263839 2.339115 0.757410 0.786142 2.190449 1.877776
+1 0.055954 1 1 -1.118207 -0.691132 0.182245 -0.064216 -0.146228 2.220731 1.702942 -1.710293 0.672184 1.803108 -0.533986 -2.314542 8.103159 -10.202512 -23.618375 -54.034837 -63.513279 0.359791 0.511210 0.662618 0.623053 1.647034 1.456648 1.129730 1.116260 1.974944 2.386187 2.149758 1.981906 2.389026 0.366079 0.434382
+1 -0.009724 1 1 -1.684901 -1.386705 1.125682 -0.907417 -1.668914 -1.305073 1.801225 0.808375 0.535069 1.665820 1.126454 -2.067156 56.026568 -61.470470 65.812850 16.565939 23.741276 1.669263 1.560455 2.060897 0.253548 1.375476 0.374329 1.848934 1.791464 1.127845 0.943571 2.102236 2.034591 1.372537 0.476669 0.633431
+1 0.019409 1 1 1.446176 -0.631174 -0.560209 -0.072263 1.273499 0.020693 -0.923276 0.399426 -2.002483 0.143195 -1.351122 0.703122 -41.631625 47.272446 -41.993924 -41.881542 46.928154 1.697326 0.706940 0.795715 1.078664 2.351580 1.002203 2.017361 2.034573 1.070854 1.589550 0.565077 1.492954 1.575409 1.398894 2.462384
+1 -0.005848 1 1 -2.285730 -0.861904 -0.141099 -1.115412 -0.845541 1.560151 1.726750 -2.114779 -2.249582 -1.233102 0.343163 -0.431250 -11.429605 52.626841 -50.682654 26.637952 -45.945311 1.332353 2.359984 0.495923 2.480067 0.480966 0.853735 1.967159 2.041551 1.353065 1.711641 0.544035 1.103233 1.283802 0.860058 2.487798
+1 0.008413 1 1 -1.484209 2.283178 0.397040 0.303219 2.104132 -2.327402 0.900528 -1.012989 0.558936 2.240928 1.857688 -2.120599 -35.129823 -26.934461 12.522294 12.202983 45.538708 2.410985 0.424495 1.230490 0.343403 1.817537 0.588455 0.670466 2.013930 0.612553 0.679792 1.262331 2.252554 1.667991 0.430526 1.347581
+1 0.002506 1 1 -0.789424 2.235376 -1.915957 -1.740686 -1.203570 1.885753 -1.672159 0.708514 -0.216192 -0.291632 -0.575748 -2.063489 67.566322 -62.821904 2.266034 -14.772303 -28.096552 1.093738 1.460071 2.414115 1.283779 0.476967 1.127490 1.730083 2.260538 0.863718 1.011577 2.076901 1.481128 0.816955 0.310055 1.588933
+1 0.012412 1 1 0.340504 2.011324 2.350793 1.113021 -1.643022 0.335333 -0.082072 1.354191 -0.958074 -0.114328 1.148078 -1.483146 41.297556 38.020592 12.093702 8.851457 -33.556211 1.686456 0.257932 0.808745 1.824677 1.339142 1.713077 2.179243 0.293518 0.405757 1.313687 1.393081 1.511591 2.054093 0.641580 0.283853
+1 0.016057 1 1 -1.537674 -0.942422 -0.955413 2.192479 -1.880337 -1.545381 1.471090 -1.293851 1.921725 -0.290107 1.501759 0.500833 37.201627 47.744995 -49.876968 67.802478 6.255525 1.174081 1.784413 1.879710 1.531870 0.891408 0.643191 0.364221 0.718920 1.888831 1.837806 1.510489 1.541298 1.843301 1.613928 0.784652
+1 0.014310 1 1 1.127961 -0.306493 -0.581799 -0.082737 -0.411949 -1.133410 -1.741680 0.940120 -0.040764 -1.820995 1.495685 2.092897 65.010163 25.815753 -64.643457 -12.587528 -58.575182 1.028658 1.164164 1.604032 0.959275 0.537790 1.880472 0.846814 0.404940 1.081385 0.842134 0.490062 0.724280 1.974664 2.171078 0.301993
+1 0.023909 1 1 -0.960644 -0.903670 0.040397 0.374422 1.876177 2.306659 -0.805026 -0.799617 0.578099 -0.842634 -1.421996 1.749901 17.828154 -62.208649 -40.755490 72.473117 55.676405 2.174973 0.514716 1.077892 0.633681 0.279908 1.156553 1.927808 2.163207 0.775243 1.261762 1.689771 1.985406 0.472311 1.636839 1.095900
+1 -0.002941 1 1 -2.232587 1.657212 -2.161181 0.131965 -1.598122 0.978757 -0.984593 1.849212 1.505355 -0.311882 -1.621795 -1.058132 17.019209 -8.153456 64.872455 -38.647862 -54.618109 1.876587 0.804761 2.370866 1.149587 1.864428 1.186326 0.587797 0.853160 1.302912 0.287312 1.849651 0.331262 0.277111 1.402740 1.859795
+1 0.009606 1 1 -0.142286 -2.227825 1.578882 0.812461 -1.464264 -1.790027 -1.092201 -1.863380 0.709181 1.566138 -1.317536 -0.311518 -6.952200 4.376444 54.902158 -59.434525 -66.055964 0.586196 0.946067 1.295356 1.539381 1.132172 1.671587 2.359199 0.800494 0.408310 1.473330 0.255671 1.067195 0.841040 2.356907 0.533693
+1 0.051867 1 1 0.890039 1.758921 1.366105 1.371615 -0.267238 -0.561537 1.160254 0.523202 0.136114 2.156635 -1.134878 1.849966 1.295059 16.057400 26.727370 -43.096928 19.925946 0.555597 1.925985 0.772567 1.277582 2.072793 2.188147 1.430233 0.426699 2.279800 0.598111 0.958217 0.752506 1.624597 2.353022 0.485847
+1 -0.004271 1 1 -0.269685 0.720720 2.303022 -0.677816 -2.216640 1.080999 2.098007 -1.602334 0.877280 -0.617662 0.343370 -1.661639 -49.581479 -65.921297 -39.244380 -30.299265 10.259630 0.379042 2.305194 2.143526 0.737873 0.926781 1.165404 2.192738 2.091274 2.297813 1.834610 1.794247 0.655835 1.370245 2.456047 1.780894
+1 -0.016471 1 1 -2.071531 -1.087797 1.470523 -1.403965 -1.506276 -1.021270 -1.966119 -1.287154 1.374373 -1.038701 1.953311 -1.915008 2.689519 52.740779 64.268681 13.718149 10.926176 1.918687 1.879829 1.280952 2.457096 1.405034 2.158768 0.421605 2.164836 1.147081 2.496254 0.292944 2.015019 0.916079 1.289153 0.801546
+1 0.014652 1 1 0.759412 2.291172 -1.908934 -1.516643 -0.905160 -1.433775 1.705720 -2.129839 -0.895902 -1.338200 1.098678 2.339886 50.007414 24.599125 37.490799 -42.138393 -69.973473 0.712685 0.599560 0.554261 1.972151 0.437228 1.497218 1.240930 0.315929 1.322056 0.290391 1.854267 1.408007 0.376495 2.250943 1.601675
+1 0.058855 1 1 -1.140596 -0.000593 -0.535627 -1.624242 0.228256 0.415616 1.501253 1.423273 0.867180 -0.728782 -1.134159 -0.202917 42.852503 72.015569 15.668716 -55.890614 -53.556849 1.675681 1.423188 1.273073 0.535544 2.388253 0.861148 0.558158 2.213242 2.457446 0.544669 0.494129 1.572855 1.223826 0.838814 0.940196
+1 0.023889 1 1 1.471088 -1.335195 -0.217043 -0.448283 0.809990 -0.592786 -0.967157 -1.973147 -1.601556 -0.184982 1.182655 0.022968 -12.568762 -43.175632 47.157624 -21.813404 -17.874764 1.807687 1.552170 2.318706 1.994973 1.506490 1.828824 1.296964 1.570479 1.790213 0.358045 0.408692 1.140663 0.375051 0.473998 0.729162
+1 0.024186 1 1 0.199959 0.773252 -0.725148 -1.322148 2.277811 -0.276177 0.003124 0.670666 -0.151585 1.712262 -0.579657 -1.782001 59.175577 63.920414 10.398885 24.056599 69.251332 2.232139 0.553843 1.685779 2.389189 0.854048 0.482648 2.119845 0.985475 2.131260 1.581351 2.271024 1.598817 1.064906 0.627912 2.313846
+1 0.014680 1 1 1.527243 -0.017062 0.695824 -1.431470 -1.965275 -1.250993 1.242348 -0.448147 -1.601252 0.202446 0.156621 -1.896188 20.872555 -44.967400 -67.087315 13.502732 -9.576896 1.241602 0.346766 2.094316 1.673441 2.015282 0.843998 0.324898 1.307980 2.227909 1.460079 0.294741 0.715232 0.657597 1.727517 1.881659
+1 -0.043424 1 1 -2.222737 2.278622 -0.782459 1.483735 -0.826739 1.825535 -0.602418 2.076214 -0.303272 1.710317 -0.266900 0.405843 69.030143 -60.380867 -71.227371 31.577296 19.611513 2.285363 1.851158 0.905734 0.673531 1.787035 0.952871 0.907041 2.395644 1.339976 2.220049 2.114635 1.161631 1.791275 2.463184 2.487980
+1 0.001419 1 1 -2.304920 1.768022 -1.172280 -0.016523 0.334084 -2.218520 -2.244882 -2.353133 1.974593 2.344085 1.461326 -0.467685 -3.987977 24.071869 25.900286 6.098485 47.246129 0.860459 2.480710 2.290349 2.388291 1.502303 1.212607 1.290250 1.222878 0.668675 1.178071 1.335427 2.268593 1.248621 1.318963 2.318001
+1 -0.019871 1 1 -2.293095 -2.129413 1.556450 0.789392 1.942793 0.385085 2.008859 -1.374865 2.197843 -1.267495 1.924459 -1.458703 68.017156 14.336975 61.544030 -29.488733 -17.133862 1.842712 0.715071 2.455022 0.308898 2.396418 0.840557 0.994147 1.633268 1.841348 0.284905 1.901053 2.499611 0.470900 0.422353 1.232492
+1 -0.016720 1 1 1.923944 -0.690830 0.539983 -0.562083 1.411020 2.265903 2.223325 -1.822344 -2.322422 -0.226885 -0.935484 -2.142617 35.267974 -51.164917 21.235540 55.727744 16.189892 1.427818 0.329584 1.321312 1.297504 1.653601 1.567723 0.466174 1.984812 1.741483 0.363300 0.979400 1.283117 0.592411 1.895144 2.177210
+1 -0.031654 1 1 -2.223461 -0.457153 -2.182960 1.649325 1.931194 -1.366429 -2.099601 -1.628106 1.257615 1.675378 1.546832 -0.642666 -15.461873 -67.692902 35.401079 -64.064963 -39.825603 0.641367 1.211148 1.523483 1.670808 0.520447 0.654559 2.429018 2.005890 0.489536 0.889872 1.836523 2.444483 0.918415 2.308489 1.282355
+1 -0.011017 1 1 -2.220303 0.771613 0.000816 -0.419926 1.460493 -0.319959 -0.712316 2.277479 -1.147334 -0.147192 0.142179 0.422985 -59.968139 -34.509289 52.383080 52.433743 3.910630 1.764335 1.930430 1.238746 1.855018 0.531115 2.201533 1.419282 0.876879 1.699441 0.254527 2.079635 2.420121 0.978317 1.078819 0.467780
+1 0.026400 1 1 1.163269 -0.643188 0.158905 -1.215306 -2.149942 0.527522 2.057368 -1.332054 0.737625 -1.039357 0.348820 0.407814 73.608357 -64.349497 -21.998621 19.173558 49.997643 1.530688 1.273540 1.629198 0.927601 1.437697 2.118898 0.817098 0.465137 0.308918 0.483724 2.204804 2.389027 0.380642 2.193321 0.652137
+1 -0.010525 1 1 2.322568 -2.028130 -2.067138 2.060706 -1.775768 -1.780679 0.513720 0.995540 -1.658043 2.337564 0.246391 -1.096647 -37.902982 14.578337 68.110484 -67.100141 -52.071870 0.296304 2.229532 1.736422 0.788026 2.361165 2.352962 1.728646 0.598722 2.227838 0.270428 1.577486 0.300429 1.814969 2.427211 0.881062
+1 0.011785 1 1 -0.290537 -1.017016 -1.153431 1.054155 -1.393765 0.286428 -2.062747 0.461303 1.241224 -0.498280 -0.671072 -1.958512 -21.625264 -5.809488 9.929725 -61.117652 -4.370605 2.023573 0.682548 0.326720 0.439693 2.423838 0.442277 0.841228 1.016179 0.675517 1.418410 1.964522 0.473902 1.368930 0.602744 2.325780
+1 0.004593 1 1 -1.429861 1.511456 -1.456875 -0.134200 1.740606 -0.147008 -1.479554 0.414428 0.385557 0.516682 -1.053300 1.641475 61.793138 -42.723583 -5.255499 20.822315 10.640534 1.906755 1.587215 1.818510 1.188455 0.362720 2.480980 2.339966 1.553756 1.982597 0.498647 1.007935 1.608116 2.097929 1.636416 0.742771
+1 0.007899 1 1 -2.345539 -2.345809 -2.170287 -2.120668 -2.276670 0.610477 1.416564 1.202872 0.512888 1.152450 1.302928 -0.166872 -23.995766 53.165199 -2.497801 19.461535 -59.974470 1.511321 2.028072 2.062546 0.953606 2.008842 0.614603 1.383117 0.544442 1.185776 0.344571 1.207118 1.276706 0.855443 1.429455 0.844938
+1 -0.061277 1 1 2.156370 -0.878439 -0.014083 -1.066856 -0.008905 1.133604 0.300627 0.953357 0.945913 -1.634592 0.643544 1.110714 63.608570 19.242180 3.323113 51.568020 3.716185 2.243797 0.744786 2.374927 1.896539 0.878295 0.757855 1.518699 2.273559 1.458168 1.921219 1.674007 0.289218 2.388772 0.586096 1.508794
+1 -0.046897 1 1 0.092041 1.264246 0.019018 -0.810051 -0.436338 -1.061246 0.036777 0.784988 -1.403059 -0.415173 1.235377 0.201371 30.139362 2.257126 -14.482138 48.707836 -67.398515 1.872443 0.895999 1.308089 1.800580 1.348253 1.834819 0.806481 2.020367 0.803982 0.531763 1.834452 1.382896 1.329630 1.597136 2.072674
+1 0.000984 1 1 -1.352976 -2.184726 0.246007 1.878400 1.974128 -0.761317 -1.324186 1.028182 0.331513 1.687487 -2.270873 -0.918072 -53.177887 -60.752370 -15.074635 -9.382838 -47.355195 1.393681 0.338354 2.467839 1.968119 2.424710 1.593592 0.999832 0.431568 0.861734 1.411371 0.664492 0.612463 1.417820 1.042809 0.488161
+1 0.011338 1 1 0.237100 -1.740087 -0.554700 -1.735937 -1.494482 -0.719182 -0.012491 2.121835 -1.676219 -1.550944 2.218274 -1.890683 -34.117129 43.407693 -46.900982 -14.810358 -67.679188 0.863432 0.705005 2.012775 1.466897 2.379784 0.278431 1.085690 1.192094 0.781284 1.536193 1.551152 0.963143 0.295998 1.584930 1.673688
+1 -0.014314 1 1 -1.180167 -0.624994 -0.356947 -0.342760 -2.224630 -1.260063 -0.394153 1.089489 -1.297958 -1.123407 1.439854 1.504078 56.587447 65.223427 10.145738 -30.584304 19.597740 1.063349 1.459319 1.027747 1.600843 1.374310 1.034301 1.492189 2.221584 0.905630 1.176950 0.492122 1.596637 0.427038 1.229148 0.289460
+1 0.044881 1 1 1.197168 -1.103256 0.831461 2.130911 0.071073 2.281261 1.153400 -1.578012 -0.315621 1.513721 -1.077937 2.244361 -53.951770 -17.398572 -67.804878 -46.580892 -35.058828 0.869248 1.698219 2.220268 1.300479 2.146033 2.378974 2.410114 1.533974 2.495380 1.346655 1.974514 1.914706 2.469954 1.511655 0.887824
+1 0.013656 1 1 -1.892906 -0.728521 -1.464877 2.051764 -1.264843 -0.623557 0.230276 1.378312 -0.821707 1.579538 -2.308087 0.371780 -3.790993 34.775158 66.079709 1.668372 -9.665238 1.470077 1.835549 1.823229 1.752413 1.806285 0.475847 0.307641 1.526878 2.488106 0.598348 0.436447 1.857135 2.371527 1.010230 1.933063
+1 0.019867 1 1 1.676469 1.043383 1.338467 -1.321334 1.826702 0.170211 0.322637 -1.402054 2.339369 2.308549 -2.028519 0.810064 20.872941 -38.474252 13.238618 51.458291 -40.494946 0.646679 0.489100 0.302804 1.225126 2.439229 0.363415 0.662377 1.064877 2.383900 1.951351 1.861424 2.451713 0.943894 0.779520 1.143579
+1 -0.002147 1 1 -0.167590 1.331821 0.068229 1.618352 -0.266555 1.486926 0.966931 -1.813783 0.187431 2.284432 -2.104143 2.145026 53.180936 -38.003304 -21.526830 -1.429292 -22.108517 0.957350 1.933391 1.507381 1.060332 0.251966 1.785510 2.310833 2.417561 0.691993 1.579821 1.306629 2.009600 2.101150 1.782625 1.084124
+1 0.001389 1 1 1.506578 1.395089 -1.592559 0.223939 -1.463704 -1.803132 0.131579 1.330565 -2.185095 -1.242057 0.632065 1.397460 17.942152 53.741722 -62.876637 -17.636017 -8.545305 0.310885 2.051846 1.133600 0.913965 1.767734 0.564221 0.611695 2.009722 1.900753 1.957620 1.467223 1.111128 1.234690 1.190689 1.911677
+1 -0.053397 1 1 -1.265468 -1.714076 -1.638028 -0.560543 -0.974216 1.905188 -0.180019 -0.220812 2.172302 -1.710200 2.240766 -0.865671 -69.503562 53.639948 26.609316 72.770546 -45.432543 2.353842 0.772033 1.312795 2.146640 1.332489 2.394108 0.266508 0.954448 0.407306 0.338782 0.650949 0.251032 1.850967 2.197860 0.432043
+1 0.003594 1 1 0.981396 0.956318 -1.115096 -0.255231 -1.400919 -2.148625 -0.902197 1.240544 2.220377 0.474519 1.878418 2.270134 -65.890338 31.097258 51.621885 9.029492 -41.321192 1.595940 2.215143 0.651476 2.365376 1.121147 0.864812 1.402375 2.464138 0.525291 1.058780 1.169271 1.942405 2.255121 2.070378 2.102038
+1 -0.042133 1 1 0.958995 1.464998 -0.008489 -1.296158 0.840611 0.404053 0.367568 -0.229905 0.144384 -0.222259 1.416459 -0.560330 -67.460594 39.797087 19.647425 64.275355 -24.112762 1.927201 0.967669 2.111140 0.929952 0.459850 1.447762 0.282195 1.350821 2.247684 0.824206 0.686170 0.465948 0.431056 1.258766 0.825817
+1 0.032369 1 1 0.870263 -0.740136 1.246942 1.361278 0.353956 1.902927 -0.489105 -1.974648 1.444364 1.909594 -1.532873 -0.360585 -6.796616 69.269331 59.642704 -35.079177 74.268895 0.434825 1.598050 1.669065 0.474032 1.311239 0.737768 1.416324 0.653992 1.898267 0.674587 1.535004 1.819457 1.363559 0.335571 0.696188
+1 0.065071 1 1 1.866087 -2.336465 -0.626990 -0.916571 -0.015560 -2.331102 -0.029638 1.394629 0.097741 -1.883632 -0.380534 -0.919165 -37.990808 38.489093 -63.807143 -56.650606 73.256761 1.770725 1.333225 1.271072 0.662341 0.457601 1.906535 2.389784 1.842413 2.427077 0.884270 2.173092 0.404171 1.648107 1.477245 0.799396
+1 0.025566 1 1 -2.036690 0.150777 -1.151543 -0.195155 -0.144354 0.723507 2.023956 -2.116618 -0.171153 -2.006489 -1.209583 -0.212639 -58.332195 10.804357 -61.172283 -22.565725 -62.143243 1.502693 1.008735 1.561239 1.748666 1.832694 1.084403 2.068576 1.052965 2.435671 1.329085 1.432677 1.005816 2.006046 0.863697 0.648508
+1 -0.019358 1 1 0.014019 0.004133 -1.222750 -0.037310 -0.317362 0.517163 2.310564 -1.148622 1.774776 -0.761687 1.885645 1.222186 -0.737284 58.464746 -33.020912 17.528134 -4.646402 2.243693 1.251181 1.597258 1.859228 1.550005 1.926101 0.477414 1.891691 0.403355 1.442148 0.432492 0.645382 1.192904 0.890497 1.076578
+1 -0.053266 1 1 1.555287 0.093290 -1.294471 0.923297 -0.038509 -1.631736 1.523497 -1.711031 -2.304460 0.057216 0.299070 -1.648965 -18.924331 -61.226203 -28.788848 45.829872 12.650572 2.397352 0.793431 0.951504 0.435352 1.467940 1.916652 1.426257 1.099852 0.712013 0.556802 1.917065 1.613294 1.387399 0.523533 0.762947
+1 0.023355 1 1 0.809673 -1.197885 -1.524606 1.912905 2.281355 -1.977057 -1.340758 0.528297 0.948746 -1.148084 1.379068 -2.238174 64.246523 -58.694545 70.776946 48.132638 15.250255 0.790549 1.998726 1.592781 0.864417 1.502669 0.606291 1.190866 0.389591 1.854935 1.393905 1.858776 0.698233 0.693633 2.138952 0.371929
+1 0.002973 1 1 -1.757258 -1.692944 0.091514 1.842293 -1.695610 -2.296578 0.585803 1.410215 -1.833580 2.042134 1.819134 0.212719 -49.030920 37.334779 35.626804 -20.313076 -1.862421 2.099356 0.871452 0.485978 1.825202 1.167704 0.342489 2.218663 1.315447 1.719414 0.685442 1.725297 0.561764 2.072410 0.250598 1.298747
+1 0.053617 1 1 -0.818545 -1.827926 -1.888947 -0.165990 -0.059548 -1.798966 -0.538899 -0.061045 1.323518 1.897081 0.223565 1.682986 69.875852 53.451880 15.749693 -44.917088 28.496317 1.188900 1.085327 1.846677 2.107091 0.376404 0.724919 1.456054 2.398690 0.791201 1.707101 0.745094 0.796981 2.110949 2.216566 2.082874
+1 0.037658 1 1 2.244213 0.527394 -0.100349 0.466687 2.201410 2.136943 -2.229916 -0.568575 0.685421 -1.928578 -1.804284 -0.377242 -68.358889 -57.847974 49.099824 70.747559 4.229649 1.190622 0.780788 2.206733 1.066680 1.197429 0.445619 0.770346 2.212424 2.209612 2.206981 0.723838 1.301855 0.530327 2.451533 2.417414
+1 0.043405 1 1 0.377171 0.943765 -0.036530 -1.343260 0.886135 2.116679 1.197437 -1.282614 2.290137 -0.460191 -1.400537 -0.446504 -72.247407 -12.162831 29.306025 -53.630555 -18.735795 0.737378 1.614878 1.003075 0.938663 0.607804 1.863334 0.803541 2.112370 1.359946 0.354159 0.348555 0.655645 0.428254 1.420499 1.083533
+1 0.004266 1 1 -0.510075 -0.988761 -2.217963 -2.302614 -1.886746 -0.874817 -0.393078 0.310208 1.761759 1.941901 -0.470607 -2.105875 41.559078 -66.582428 -50.863619 -14.850366 9.903819 0.677234 1.018111 1.643971 1.724572 1.876266 2.149912 2.314948 1.831007 1.991235 1.679198 2.023255 2.088186 2.143482 2.255747 1.342852
+1 0.016090 1 1 0.440092 -1.823223 1.763011 -0.584139 -1.722338 0.863126 1.825609 0.642717 1.356470 -0.344352 -0.706649 -1.422838 55.081813 -39.976654 -37.624938 37.666247 56.606275 0.349858 2.321672 2.348520 1.331037 0.489618 2.255546 2.470172 0.678587 1.261161 0.576733 1.644012 2.415104 2.152620 0.590897 1.204063
+1 -0.023435 1 1 -0.967166 -2.121224 -2.186926 0.967816 -1.080610 -0.261935 -0.965686 -0.810397 -1.543091 2.259628 0.418732 2.033228 -56.698754 14.034050 70.277949 61.496300 68.313505 2.051215 1.776989 0.859078 1.771982 2.194771 0.257673 0.957303 1.143313 2.169015 1.636353 1.927160 0.283317 2.216754 0.728270 1.539677
+1 0.030897 1 1 2.341952 -1.400662 2.170939 -1.049116 1.271392 2.318165 -0.635813 1.585406 2.079472 -2.101254 -1.126452 2.099390 -61.422542 -28.671790 63.219445 -70.781115 31.808052 1.343974 1.927011 2.275485 2.320032 1.781359 2.307967 1.494419 1.444592 1.004460 1.711859 1.963027 2.353892 1.614340 0.968591 1.852737
+1 -0.006385 1 1 0.692588 0.730969 0.194901 0.585198 0.659000 1.706293 -1.927928 -0.306858 -2.012993 -2.124197 -0.312829 1.315498 -30.485537 29.580052 51.933789 1.185233 -29.789050 1.906480 1.466878 2.077590 1.808471 1.214088 1.428538 1.189521 0.279351 0.802670 0.968979 1.633352 0.989159 1.045596 2.339512 0.674461
+1 -0.020955 1 1 0.611190 -0.733463 0.291098 1.024822 0.407082 -0.554671 -1.243098 1.990155 0.006151 -0.287162 -0.853598 -1.904266 49.212887 20.991581 5.498367 11.058139 4.146918 0.583690 1.580165 0.330816 1.781048 1.568293 1.043519 1.176337 1.442301 0.757276 0.782113 1.965544 1.894760 2.487671 2.289507 1.748967
+1 -0.002831 1 1 1.799489 -0.098416 -0.020811 -1.051622 1.553956 1.277751 0.812175 -1.570696 0.114433 0.624086 -0.768159 1.489208 51.602766 -12.314968 22.327880 -35.315731 -1.487165 2.203161 1.780027 2.406556 2.482070 0.397577 1.075843 2.197789 1.498220 2.334185 1.144397 2.375637 0.327706 1.250177 0.476251 0.347764
+1 -0.000539 1 1 -1.284011 -2.341415 1.001930 2.072950 1.372043 2.215947 1.403906 0.524912 0.601845 -2.284542 0.244018 1.436942 -9.685471 -33.704750 74.268912 -62.398955 60.769008 1.295715 0.831178 0.858094 0.990412 1.858716 1.936048 1.161492 1.702633 2.150367 0.966924 0.845502 0.848936 2.324894 2.491507 1.511705
+1 -0.047196 1 1 1.801572 1.915127 1.926585 1.283864 -0.121787 -1.688970 0.904061 1.808768 0.336979 -0.678842 -0.599498 -0.680590 -54.533714 -48.137458 53.747997 42.586819 -43.325673 0.256201 0.970701 1.326312 2.072892 1.589285 0.621820 1.176029 0.771445 0.418147 0.301456 1.063995 1.062496 0.614882 1.564469 2.036842
+1 0.039475 1 1 0.889092 -0.012302 0.578068 -1.350742 -2.346130 1.869954 1.394805 -1.644408 0.601238 1.646869 -1.640045 -1.465741 53.043611 53.974575 -49.324950 45.557830 -59.558177 0.710679 0.634189 2.068848 1.131462 0.975575 2.243017 1.137704 2.384608 0.350681 0.387584 1.867658 1.484223 1.078790 2.224860 1.973935
+1 -0.004425 1 1 0.276136 -0.680294 -1.449756 1.709874 1.703880 -0.076525 0.322950 -0.851539 -0.288410 1.740599 -0.266908 0.267097 -57.743706 1.535819 12.503185 -8.974776 60.942668 2.326209 2.100762 2.001307 2.215513 2.383700 0.852990 0.700869 2.260015 1.063966 0.572763 2.420673 1.250334 0.869499 1.427065 1.177949
+1 0.015664 1 1 0.678614 1.480884 -1.617846 -0.656365 0.181252 2.096513 1.557954 -2.217987 2.001725 1.251290 -0.956269 1.939274 -70.632985 -28.587103 -13.432431 -8.864006 -27.347223 1.003435 2.475547 1.010879 1.600918 0.385438 1.803291 1.911498 0.301204 1.335924 1.627056 0.929251 2.169100 0.811106 1.006687 0.893098
+1 0.016003 1 1 1.456271 -0.603701 -0.626946 -0.177921 2.052335 -1.089892 -0.760802 -2.082027 1.580183 -0.896040 1.045197 -1.162248 -33.592823 5.430288 66.857824 29.442184 -15.208792 1.162386 0.963038 0.775767 1.065706 0.567071 1.268285 1.060251 1.131150 2.481534 0.394032 2.241679 1.145675 1.361979 0.777443 2.228414
+1 0.023428 1 1 0.571740 0.679436 1.164464 0.600411 1.880971 -1.937264 -1.699091 0.452826 0.135758 0.889598 -0.939390 -1.824174 -2.993214 -56.942674 -35.516780 69.472428 23.103482 0.628305 2.173860 2.066723 1.418048 0.386116 1.947091 2.267308 2.152573 2.038281 0.392160 2.279809 0.756366 1.250947 2.158825 1.374252
+1 -0.025497 1 1 -0.629509 -0.838402 -0.973138 1.168209 2.285197 1.333255 0.599726 -0.211823 -2.254865 -0.481757 -1.000232 -1.812055 30.828141 28.561953 40.740401 -26.074482 66.182388 0.285865 2.286025 1.724021 1.620626 0.852053 0.709800 1.615367 2.469008 1.368864 1.751615 1.899561 2.179771 2.406417 2.407215 2.321458
+1 0.026714 1 1 2.354447 1.262787 -0.938564 -2.071516 -0.843276 1.920723 1.721698 -2.211368 0.141672 1.329751 -1.731035 0.776243 -72.787275 64.260835 31.859479 -37.728460 -52.222512 0.568489 0.344713 1.341527 1.289624 1.967521 1.383922 0.576174 1.252058 0.590705 2.480675 1.701246 1.341670 1.456294 1.929202 0.851139
+1 -0.012206 1 1 -1.249452 -1.134810 -1.719410 -1.754121 -0.814325 -1.587740 1.106983 0.546365 -1.684364 -1.789826 2.292396 -0.193518 -29.022607 17.040244 45.383210 5.607352 42.768993 1.651993 1.547067 2.062427 1.214756 1.395928 2.117818 0.658955 2.051728 1.394168 1.784371 1.167254 1.785286 0.811014 1.710394 2.097490
+1 -0.003613 1 1 1.436561 -1.997843 -1.968526 0.659254 1.256525 2.192952 1.351566 2.062976 -1.314770 -0.949767 -1.876426 -1.776527 -12.420880 42.262846 61.652051 -13.971420 -67.652024 0.961507 2.052514 1.108597 1.446992 0.845711 2.121208 1.386639 1.239070 0.556215 1.053815 0.964831 1.668557 0.931587 0.940285 0.867717
+1 0.009252 1 1 0.150404 2.002340 2.153237 -1.692554 1.945990 2.277744 -1.406982 -0.374443 -2.226434 1.395516 0.881626 1.740667 28.030494 -41.487008 -72.144489 67.566519 -59.523089 0.556656 1.718065 0.519011 1.264597 2.079527 0.603701 0.405952 2.328492 2.223325 0.921968 1.270550 0.892119 1.343746 0.338089 0.260600
+1 -0.018616 1 1 0.171594 -0.000655 -1.589093 1.931818 -0.292101 0.969943 1.673870 -0.226997 1.892513 -1.161250 1.587074 1.833402 -10.148710 -19.372193 61.546763 16.444620 -65.278360 0.873956 2.073423 1.518343 0.795086 1.754490 0.705055 0.612707 1.023382 2.484366 0.744782 2.308522 1.831291 2.256038 1.726148 1.371881
+1 -0.000261 1 1 -1.746467 0.606011 1.758845 0.084752 1.289745 -0.247017 -0.003277 1.480087 -0.885852 -2.083898 -1.598471 -0.168970 53.593705 -0.606675 3.605187 -7.625628 -63.922337 0.734320 1.964509 0.254120 1.991879 1.255185 1.398113 0.578923 2.455456 0.841818 1.930743 2.001488 0.763548 0.446057 1.384956 2.205298
+1 0.041106 1 1 -2.169922 -0.691540 -1.960492 -0.967853 0.454852 1.196630 -0.709577 1.202523 -0.632700 2.073346 -1.389500 1.276513 -36.618920 -4.188864 -52.240265 -52.134032 -66.667628 1.632536 0.784997 0.938766 2.346919 1.421197 1.562298 1.540148 0.516497 1.767611 0.738574 1.461826 0.411012 1.881965 1.193051 1.113498
+1 -0.004709 1 1 0.750799 -1.098327 -1.158265 -0.077208 -1.725882 -2.144400 -0.571764 -1.074541 -1.938825 0.342931 0.386332 -0.585817 -52.380720 -12.759920 44.021915 -73.676138 -24.847421 1.216028 0.277812 1.932696 1.072957 0.930297 1.752563 2.069154 1.767135 1.736577 1.149948 1.177584 2.161757 1.142448 1.123549 0.743448
+1 0.026219 1 1 -1.779757 1.876229 -1.523428 -1.848793 0.831449 1.931054 0.998122 -0.665118 -0.849671 -1.887425 1.852876 1.821085 0.503085 55.356752 -69.072236 -47.062260 -25.402913 0.673563 2.320017 1.524897 0.696187 2.313616 1.938419 0.504857 1.888282 1.607999 2.385985 1.000417 1.267084 1.123160 0.953853 1.665032
+1 -0.051679 1 1 0.881418 -1.763793 1.577250 1.649806 0.588348 1.766096 -0.554482 1.931204 -1.186524 0.922598 2.343314 -2.063000 29.116539 61.673832 52.089002 59.851460 23.487249 0.627896 2.041077 2.382008 1.651524 0.407348 1.041658 1.395280 2.470512 1.896002 0.857493 2.132868 1.606849 1.063777 1.899667 1.700230
+1 -0.061212 1 1 -0.502713 0.213358 -0.223347 1.974123 -0.842418 2.202585 -1.686641 2.350111 -0.928619 0.126552 1.668506 -0.838954 -26.671835 -73.526361 -57.543098 73.154479 -42.674048 0.284194 1.203034 2.393987 0.495344 1.754891 0.705046 0.462887 0.745504 0.931684 0.305307 0.545296 2.045587 1.680950 2.218873 0.350784
+1 0.014015 1 1 1.058882 -2.072036 -0.157353 -0.981284 0.921140 1.410296 -0.477396 1.606453 -2.332915 -2.225231 -1.932168 -0.866617 24.320919 11.692227 11.252893 -22.634189 -12.810879 0.438353 2.405043 1.810412 2.347788 0.273559 2.452037 1.894246 0.596139 1.551502 2.348833 2.086313 2.161098 1.323011 0.601369 1.704658
+1 0.012090 1 1 -0.231712 -1.956979 1.535842 -1.566695 1.385631 -0.333382 -0.112593 2.037424 -1.951616 2.123679 1.042566 1.752585 -46.128568 67.154607 67.482367 26.149460 -6.018759 0.515810 1.461681 2.478829 2.179504 2.427185 0.443963 2.188729 2.211723 1.682774 1.378743 1.286791 1.594742 2.321089 1.550477 0.872540
+1 0.021928 1 1 1.535585 -1.176858 -1.551996 -1.325703 -0.920352 -2.291030 -0.413093 -1.505587 1.130165 -0.964830 -0.560806 -0.689379 43.924045 -68.569601 0.720719 -36.881180 -61.985161 0.855990 1.615838 1.382025 2.444744 0.819234 0.361758 2.066460 1.494637 0.616137 2.419323 1.058634 0.956166 2.284143 1.592626 0.524172
+1 0.050191 1 1 0.789262 -0.245498 1.972586 1.602712 0.760189 1.202282 0.031421 0.297467 -0.323539 0.379365 0.128611 -1.423011 -37.141775 58.189203 -14.060088 -57.893300 37.310781 0.359399 0.677011 1.776058 0.955175 1.379449 1.904089 1.769619 0.733352 1.450478 0.938699 1.221489 2.070147 0.455868 2.015840 1.220949
+1 0.043566 1 1 2.296686 1.224828 1.964662 0.361844 -2.185501 1.360567 -2.181114 -0.305074 -0.303895 0.660847 -0.242906 -1.586150 -14.184835 -54.524796 -48.252703 66.813174 29.013507 1.075200 0.384533 2.352459 2.274406 2.191526 1.968670 0.431671 0.338452 1.863378 1.544418 0.288432 0.421067 2.124910 0.609509 1.262800
+1 -0.020769 1 1 0.363005 -1.519973 -0.325797 0.123130 0.701048 1.536150 -1.101891 0.200693 -1.027477 2.106560 0.782604 0.945278 57.855668 -69.789812 42.626368 21.365520 -9.700935 1.470688 0.847950 1.497540 2.159392 1.898945 0.827192 1.370826 0.976813 0.547314 2.213817 0.875831 2.099514 1.273857 2.464491 1.941427
+1 -0.001697 1 1 -1.472502 1.118919 -1.470697 -1.527993 1.548302 0.493936 -1.653880 1.617777 -0.513866 1.260655 0.934151 -1.410390 -35.065744 0.035778 1.319320 -26.180935 -72.972583 0.621921 0.631739 1.393144 0.314488 1.845808 0.986785 1.653401 0.456718 0.556323 0.612716 1.162267 1.221070 1.777929 0.899101 1.685494
+1 0.021926 1 1 0.772429 -0.425583 0.640571 -1.728057 -0.999751 1.562099 1.472560 -0.146259 1.687876 -0.455159 -1.642883 -2.047364 -5.762203 54.654087 -28.766437 -27.511238 68.626759 2.274063 0.928942 1.484878 0.838320 1.641041 1.981786 0.379168 2.172857 0.954010 2.053755 1.708802 2.340886 1.278854 0.947052 2.102335
+1 -0.039787 1 1 -0.524687 -1.539585 -0.081062 -0.536607 0.754563 0.909572 0.191047 1.791696 0.863170 -2.148277 0.231183 -2.220367 -9.424812 -2.819032 20.521705 58.291074 48.086932 1.330895 0.343727 0.526693 2.135086 0.634376 0.710388 2.491542 2.102128 2.469897 0.554253 1.837316 2.271330 2.239826 1.501795 1.668771
+1 -0.026066 1 1 0.175658 2.321943 1.596875 1.628532 1.188983 -1.997732 -0.110983 0.811170 0.397257 -0.763862 -1.689435 -2.185814 25.520606 74.817438 6.687976 54.810937 57.424348 1.840183 0.951181 1.747996 1.819819 0.691367 2.299741 0.494003 1.700490 2.142015 2.343034 1.374108 2.133657 1.376325 1.147431 1.628158
+1 -0.016786 1 1 1.876768 -1.888820 1.971737 1.471102 -1.086027 -1.775445 -1.062983 -0.885098 1.176508 0.391250 1.954286 0.330652 43.089512 5.425819 -8.263582 13.982692 -42.893881 1.113017 1.468113 0.329517 2.449475 1.572298 0.870013 1.063825 0.460788 1.460825 1.580912 1.635635 1.123115 2.452393 1.116997 0.862809
+1 0.024312 1 1 -0.659837 -1.629636 -0.889559 1.585617 0.905842 -1.242137 -0.719915 1.811030 0.658384 0.762192 1.882285 1.303325 57.223516 -44.359613 -52.023676 -11.920248 56.390871 2.295658 1.626991 2.086733 2.467333 2.463957 1.970846 1.016975 0.546546 0.553519 0.738773 0.304975 1.717400 0.590520 1.611992 1.997276
+1 0.070348 1 1 -2.069361 -2.320037 2.153506 -1.890057 0.027807 0.827895 -1.256893 1.037716 0.344984 1.903642 2.111134 2.246823 63.270787 42.111315 64.870883 -65.072424 -22.229106 2.056144 1.354167 2.240936 2.156856 2.028078 2.163024 2.201499 0.847771 0.744322 1.315294 1.401956 2.168082 1.699239 1.354024 2.081451
+1 0.039628 1 1 -0.002851 -0.800087 2.091703 0.831285 -0.834091 0.782926 1.648516 -2.233422 1.771156 -0.338361 1.019505 0.571173 18.152612 -9.053210 -57.301230 -61.777282 9.213804 2.221047 0.881200 2.334198 1.357206 1.552519 1.430923 0.770577 1.583395 0.621739 2.071872 2.445651 0.307274 2.112379 1.512742 1.149281
+1 0.004095 1 1 -1.612043 -2.074824 0.111387 1.255887 0.904383 -2.203407 2.006344 -1.237354 -0.435927 1.143082 -0.623599 -0.471641 -20.204571 21.770446 45.881634 -17.378048 -22.851000 0.523580 1.551722 1.535505 1.230836 1.654059 0.272192 1.987498 1.876312 0.668277 1.234606 2.016922 1.405911 1.151881 2.169811 1.513950
+1 0.028571 1 1 1.627603 -0.299953 0.938104 -0.933607 1.126689 1.888321 -0.936404 1.229944 -1.576760 1.869179 -2.210069 -1.574538 48.496261 -23.344606 47.199959 -60.296652 -5.825751 1.924018 1.473885 0.588652 1.721475 1.587981 1.203151 2.111760 2.344111 1.467643 1.419741 1.830239 0.325283 1.038971 1.242772 2.021671
+1 -0.013092 1 1 2.020855 2.327347 -1.824948 1.038154 -1.724785 2.162533 -0.966131 1.121547 0.286953 2.051938 1.659259 -0.748280 32.525449 55.229452 41.406982 -72.858548 66.390801 1.077935 1.353093 2.180700 2.281177 1.235909 1.426821 1.582089 1.173452 2.452843 1.929975 0.345346 0.723055 1.627945 2.371719 1.980730
+1 0.028661 1 1 2.331765 1.748459 -0.102372 -0.551514 -0.020122 1.104127 -0.319683 -0.795895 1.868333 -2.291631 -1.079740 0.225428 0.053807 4.328946 6.593710 -29.515819 -22.372631 1.872948 0.393206 1.857743 1.332967 1.426234 0.715986 2.079465 1.815860 1.660057 2.079026 1.181968 1.590958 1.726030 1.637891 0.781655
+1 0.018986 1 1 1.712905 0.812732 -1.625255 2.052263 -2.309875 -1.413439 -0.519648 -1.660593 1.896303 1.276460 -2.052229 -1.837462 -61.441012 -39.087900 49.658991 18.665462 60.423092 1.838639 1.996559 1.172141 0.678501 2.059606 1.046050 0.963806 2.439799 0.946289 0.535348 1.350855 0.564194 2.404117 1.988516 0.991084
+1 -0.013029 1 1 -0.582684 -0.832323 2.231902 0.965149 1.208982 -0.467838 2.024176 1.585745 -1.660558 -2.235138 1.197474 -0.661908 40.043493 -39.012454 -32.322444 56.678183 -59.781521 0.654562 2.474256 1.827190 0.827200 1.502298 1.114347 1.333319 0.598058 2.316269 1.535405 1.802842 1.123437 1.102100 0.252588 0.998692
+1 0.045608 1 1 2.084848 -1.277268 -2.115300 -1.582173 0.426627 -1.936480 2.048290 1.617665 2.318740 -0.386437 -1.175430 -1.120926 22.935707 -19.579416 28.762745 -34.544044 68.251054 2.056942 1.267617 1.093741 1.500854 1.607529 1.243113 1.002804 0.877564 1.976403 2.160033 1.427758 1.575148 1.511582 1.910454 0.745670
+1 -0.011746 1 1 0.105372 -0.876768 -0.191923 2.340907 -0.104384 -1.375500 0.953310 0.154376 -1.936228 1.579307 -1.477006 0.818107 -26.066366 52.590134 -67.614994 -5.203125 1.079892 1.371215 0.768028 1.495458 0.908364 2.122229 0.561213 1.805377 0.966604 2.221152 0.395779 2.350255 1.227878 1.448500 1.445681 1.317742
+1 -0.018163 1 1 1.098316 0.968402 -0.660438 -2.308859 1.527646 2.052688 0.123151 1.063808 0.620459 -0.470671 1.532874 0.379394 19.437409 -15.462183 -72.907612 -8.227161 26.108859 2.298872 1.649213 2.073561 1.586066 0.507395 1.792519 0.866411 1.267505 1.448959 2.406385 1.858914 0.764212 0.355900 0.365896 1.868967
+1 -0.009072 1 1 2.015643 -0.452254 0.043176 -0.055708 1.479849 -0.168918 -2.153362 -0.406117 -2.069910 -2.114008 1.279243 2.321236 -27.161209 -48.446822 -45.740335 -7.808813 7.286913 2.442316 0.501386 2.044378 1.612247 1.786363 0.897381 2.040748 1.355830 0.931045 0.817260 0.944795 2.414053 2.491183 0.571866 0.847790
+1 -0.031844 1 1 0.467428 0.502953 -0.901635 1.258198 2.042293 -0.220017 1.407300 1.007018 -1.948994 -0.918061 -1.492498 -0.365206 70.981296 32.637741 -7.491689 -62.824138 -35.285277 2.280149 1.971809 1.449756 2.302419 0.507256 1.697467 0.824145 1.905690 1.681343 2.078395 1.827858 0.812393 2.396178 1.307157 1.896765
+1 -0.007798 1 1 1.084258 0.317987 0.550859 -1.564048 -1.244371 -0.569428 0.492515 -1.964312 0.797243 1.937677 -0.781420 0.106024 21.255304 -62.113318 61.456476 -0.999551 0.554575 1.686157 1.999909 1.211952 1.529452 0.747576 2.002762 1.916545 1.867004 1.733216 0.907260 1.571204 0.483724 2.192354 2.395291 2.151475
+1 0.012520 1 1 1.750602 -1.794370 1.309251 -2.277820 0.128653 -0.715414 2.056446 2.034054 -2.037179 1.348976 0.941005 0.690971 58.236084 23.863551 -25.303092 -19.074573 -36.350242 1.547162 1.409506 0.809071 0.551495 0.483676 1.389298 0.934387 0.744970 0.964237 0.689190 1.722731 2.433079 0.513090 0.752138 2.176570
+1 0.017054 1 1 -0.906132 1.077987 -1.412439 2.156227 1.438425 1.051138 -0.277496 1.395298 1.932959 0.036594 -2.293276 -0.467590 47.052082 4.334134 -56.210753 -34.133669 65.423275 2.409683 1.037963 2.293263 1.870423 0.699136 2.382209 0.537868 0.953673 0.874887 1.968961 0.829865 1.282579 0.560215 0.784021 0.292912
+1 -0.071640 1 1 0.627300 1.420653 -0.755892 0.315974 -0.284635 -0.778122 -1.010656 2.060639 1.815073 -2.082919 0.712357 -1.598686 29.469392 -7.921472 63.826006 73.686651 51.541794 1.569003 1.725760 1.601780 1.367528 1.786071 0.500808 1.324943 1.569295 2.132019 0.845598 2.465649 1.164635 0.521926 0.766082 0.286425
+1 0.010295 1 1 2.003572 -0.697282 0.498303 1.071451 1.837065 -0.020988 0.681233 -1.626098 2.018683 -1.199345 2.201213 -1.180273 73.797057 -42.863230 47.697754 56.151176 -67.190406 0.337718 0.781405 1.326446 2.071374 0.836783 0.569564 0.409668 1.784492 0.961803 0.269754 1.511976 1.782883 0.911441 2.081448 1.403018
+1 0.013052 1 1 1.071036 -0.430698 -0.515127 -1.083506 -1.820570 -0.775232 0.433390 -1.371504 2.146467 2.335549 -0.624987 -0.246010 -61.060373 58.309206 52.830489 72.031241 -20.935609 1.903234 0.895016 0.540554 1.094664 1.265872 1.013358 0.500649 0.900279 1.247312 1.824258 1.048351 1.379072 2.307968 1.512574 0.579376
+1 0.044723 1 1 -0.523955 1.341464 1.919549 0.849895 0.931835 2.075907 -0.761105 2.238546 -0.470958 1.414087 1.976799 1.724768 72.230640 30.367753 -59.175240 -58.259601 30.883279 2.204094 1.710836 0.526004 1.793849 0.724785 1.453556 0.922307 2.467926 1.185945 0.922454 0.427263 0.508762 2.260985 1.633431 2.320336
+1 0.049736 1 1 0.451342 -1.238282 -1.901998 1.974501 0.793575 1.554860 2.343959 -0.644573 0.438493 -0.426395 1.121296 0.770062 70.667585 10.108252 -60.602725 -50.002001 66.369504 2.458885 2.233902 0.939765 1.138349 1.989316 0.936337 2.010951 2.310953 2.192863 1.942156 0.308395 0.693780 2.365722 2.445169 1.203126
+1 0.062963 1 1 -1.373781 1.559742 -0.438374 -2.280632 -0.010621 0.567262 0.806554 -1.798348 0.427958 1.589530 0.695792 -1.974283 -58.531546 -39.690150 -22.351074 -54.494982 2.834893 0.565672 0.255250 0.729509 2.115493 2.087442 0.885821 1.244622 1.608620 1.582826 2.310014 2.146888 0.994155 1.764299 1.329881 1.318111
+1 0.001162 1 1 -2.209240 -1.789719 -0.634921 -2.264689 -0.661075 1.124550 -1.085675 -0.560964 1.374114 -0.686740 -1.405172 1.773647 -28.075078 42.168893 -17.421255 0.971893 -15.395125 1.437048 2.462383 0.267053 1.112339 1.331075 1.122356 0.941105 1.143655 1.165803 2.144004 2.020070 0.310099 2.340869 0.979143 1.457455
+1 -0.023769 1 1 0.851942 -2.355520 -0.446330 0.659583 2.070037 -0.453831 1.827658 2.100281 -1.088817 -1.544250 1.619658 -1.873635 -63.453445 37.956602 -13.382091 -62.804923 -12.336020 0.902765 0.275555 2.255349 1.409565 1.806322 1.109536 1.475040 2.006408 2.451313 0.962410 1.483325 1.739143 1.529355 1.371266 1.614808
+1 -0.013392 1 1 0.810513 -1.226892 1.042287 1.774904 1.390313 -1.743186 -0.801549 1.085181 1.687356 0.227999 0.802097 -1.294714 49.704963 41.317115 66.750406 24.078411 -14.141183 0.312062 1.571825 1.905824 1.678117 1.867770 1.114741 1.195641 1.882776 1.312971 0.597577 0.971277 2.008644 1.778075 1.107698 2.077990
+1 0.058019 1 1 -2.295585 -1.563382 0.513396 0.269988 -0.341923 -2.291587 -0.353739 1.739799 0.429422 -2.088971 -2.040339 0.069794 -11.382103 -49.010709 -72.990621 -53.368658 32.957108 0.776623 1.959872 1.071455 0.448503 1.993745 1.124183 2.394258 0.549399 1.252283 2.113557 1.053552 1.042213 1.716779 1.408858 1.169936
+1 0.010729 1 1 1.176493 0.136993 -1.916996 -0.343650 1.664670 0.654256 2.074765 -1.095000 -1.787491 -0.875840 1.265555 -1.545575 -56.838705 61.888815 65.314725 44.578216 -23.917407 1.677154 1.420496 1.033769 1.549748 2.118700 1.992069 2.201613 0.515586 2.204502 1.810373 1.688195 2.498965 0.857792 0.413765 0.905712
+1 -0.012070 1 1 -1.016400 -0.222680 -0.949702 -0.785009 1.040372 -2.141810 0.542426 -1.923265 -2.044903 -1.223741 2.166717 -1.321093 37.270265 1.346345 -21.981117 13.370301 14.645949 1.441944 1.496313 1.782191 0.542786 0.362100 1.071841 2.430780 2.363690 2.043950 1.161175 0.874225 2.106910 1.834428 0.972810 0.762607
+1 0.027157 1 1 0.121299 -1.800546 1.182739 1.433367 0.868505 -2.022115 0.059985 -0.286181 1.498721 1.284215 1.052016 0.342011 -29.809500 -8.266889 -41.609965 -38.687509 29.029551 0.619869 2.146330 0.621870 2.027247 1.683012 0.880904 1.851091 2.043846 1.665739 0.816714 0.757954 0.932006 1.223522 2.484872 2.499156
+1 0.003902 1 1 1.794486 0.643888 2.175017 1.504910 1.628140 -0.702300 0.984653 -0.843101 0.148036 -0.097203 1.506808 0.540884 13.971245 64.723005 -0.451030 69.540546 -32.051701 0.730929 1.222156 2.032078 1.886557 1.860731 2.061540 2.061398 1.911510 0.499732 1.239227 0.939461 0.527822 0.859228 2.039306 1.863944
+1 -0.007814 1 1 -0.027267 -1.168429 -1.253816 0.911921 1.963825 0.436288 0.217079 1.054458 -1.021642 1.201041 -1.984833 -0.089399 22.957082 39.684978 -64.572105 -13.372141 -45.565586 0.312962 0.954491 1.131666 2.154341 0.257038 1.540680 0.456666 1.941652 0.837690 2.313962 1.001858 0.721197 1.905017 1.613967 1.439086
+1 -0.009992 1 1 -0.146514 2.123556 -1.029660 -1.610658 2.338467 1.285233 -0.673335 -2.287735 -1.583251 1.160619 1.938537 -0.467250 -71.050575 2.991042 20.445575 -21.227557 -71.551687 1.087057 1.670246 2.326316 1.650611 0.825291 0.910472 1.551164 1.166496 0.292347 0.978017 0.530066 0.315454 2.332685 0.681850 2.101125
+1 0.030315 1 1 -1.080149 -1.939512 -1.777266 1.328934 -1.322967 -2.048011 -1.623240 -1.773996 -0.261850 0.455077 0.274454 -0.676827 8.780994 -17.828320 59.429896 -11.736190 -0.142762 1.383914 0.439913 1.613398 0.874243 2.402553 0.457259 0.652757 1.386003 1.805049 2.211065 1.865820 2.086926 1.213789 0.903856 0.614546
+1 -0.038170 1 1 -2.030656 -2.117313 2.274143 -0.663382 0.051329 0.311039 1.601345 1.355551 -1.653642 0.912386 0.362960 -2.266848 23.867401 39.412372 3.741804 38.498456 -56.446641 2.144647 1.583308 1.409901 0.700535 1.150052 0.665696 0.599899 1.744822 2.479447 1.322602 0.466790 1.082020 0.259268 0.759550 0.754891
+1 -0.026772 1 1 -1.771848 -1.871751 1.388049 -2.089521 -1.863446 -0.403221 -0.520347 0.719498 0.606083 -1.751891 -1.026366 1.914644 -47.073052 -56.784891 66.343961 -57.044731 49.198218 2.491650 1.663177 0.524455 0.520428 0.333119 2.224752 2.411899 2.290643 0.590281 2.104302 0.751528 0.926197 0.336157 1.543080 0.288655
+1 -0.054916 1 1 1.011622 0.036427 -0.384463 -0.976723 2.186092 -0.839673 1.216622 0.716166 1.157195 0.945667 -1.058764 -0.667999 -68.585483 33.789090 -6.760042 -66.027670 -27.055172 0.380794 0.252820 0.395567 1.040652 2.480884 0.713550 1.640042 0.940479 1.882769 1.199602 0.956947 1.900383 2.482158 1.878257 1.874404
+1 -0.021404 1 1 -2.327496 -0.691472 -0.825261 -1.605643 1.809298 -0.171326 -0.199061 0.178589 -0.254146 -2.003578 0.602276 0.249354 49.998162 19.113429 -60.592462 -27.513910 23.720617 0.961251 2.245677 0.843973 2.160497 2.480752 0.742802 0.529581 1.169096 1.240536 0.430452 2.349908 2.146443 0.261017 0.914509 1.895795
+1 -0.019879 1 1 1.414957 -2.237642 1.520386 -2.162533 0.972881 -0.785011 1.012601 2.344599 0.679992 1.075938 1.848804 -0.640664 5.279358 -69.821459 -39.258774 27.783748 11.459231 1.304366 2.231652 1.368145 0.918938 2.087639 1.947942 0.819448 1.719875 1.683319 1.538078 1.729282 2.287498 1.732194 1.738656 2.335346
+1 -0.053102 1 1 -1.290510 1.517546 1.944076 -1.615587 -0.393675 -0.301117 0.225590 -1.976386 0.513343 -0.627029 -1.576961 -1.502952 -54.536165 60.667274 -65.130563 50.632648 32.907428 1.752163 2.102885 1.680400 1.978887 1.161387 2.177894 2.365376 1.131642 1.756986 2.169112 1.013965 1.716156 2.183049 1.256102 1.049991
+1 0.006135 1 1 -0.856506 1.050036 0.057223 0.425535 -1.445976 -0.732835 1.428456 -1.569549 0.549382 1.886492 1.326503 0.230439 -18.942009 -58.349616 18.006969 -56.864070 -64.417823 1.819732 1.481430 1.392087 0.560496 1.010894 1.841973 1.782197 0.636116 0.700224 0.415308 2.083603 1.612996 0.882247 1.918224 0.835974
+1 -0.014472 1 1 1.830868 -0.505872 -1.039492 -1.908438 2.109997 1.991374 1.641462 1.731068 -0.236639 0.068927 -0.786670 1.402801 25.346046 -8.999213 -49.765625 -10.863325 -29.911379 0.316837 0.824994 0.423192 1.845279 1.103177 0.352955 0.367265 2.368691 0.580695 0.741075 0.750546 2.432769 2.049513 2.413993 1.474262
+1 -0.006234 1 1 -1.614455 -0.205349 -1.834050 -1.132936 1.508184 0.113661 1.790537 0.231868 -0.145866 -1.122387 -0.270301 -0.213497 -67.590587 -44.987893 38.476522 24.907888 -23.125103 1.170938 0.702441 1.672778 2.131747 0.777333 0.378519 0.265761 1.887285 0.597262 2.426187 1.671551 1.757435 0.708617 1.981791 0.458674
+1 -0.001455 1 1 2.121420 0.775783 -0.595752 1.024038 1.355014 -1.257676 2.015484 1.593240 1.791479 1.940209 -0.639263 0.152917 57.797976 10.586430 26.131514 -7.651335 -45.980182 1.541176 2.053701 0.794227 0.815155 1.563211 1.145273 1.355314 1.258414 1.663854 0.646913 2.172690 0.398774 0.938200 1.820747 0.539501
+1 -0.008436 1 1 2.041622 -2.076515 -0.028982 -1.718507 -0.709415 -0.793883 -2.019111 -1.285941 -1.799406 1.488088 1.641200 2.034345 -58.918322 59.753761 31.468803 -3.832347 -60.262782 0.826308 2.255487 1.470085 1.970982 1.051768 0.313612 0.632155 1.629698 0.341621 1.122200 0.572315 1.652827 2.063338 0.764711 1.991992
+1 -0.034307 1 1 1.431693 1.003010 1.370565 0.927101 -2.083753 0.838951 0.777657 -2.085562 -1.298149 0.367509 -1.211896 -1.387836 30.828960 42.325406 63.094630 -68.554870 -51.695612 0.652821 2.460401 0.713952 1.642992 1.011943 1.473702 2.016669 1.653487 1.903729 2.479319 1.414032 0.391171 1.406020 0.727670 0.442909
+1 0.013380 1 1 0.220847 -1.589695 1.250456 -0.839891 2.261169 -1.944301 -2.164557 -0.064056 -2.163951 0.698407 -0.430541 2.122005 37.211429 62.493198 23.178561 12.076813 24.992566 2.125898 1.461251 1.999547 1.889410 0.307329 0.783242 0.696201 0.304899 0.432658 1.189138 0.592524 1.555545 0.538220 2.362413 0.826872
+1 -0.028876 1 1 -0.755561 1.167474 -0.650989 0.986723 0.957012 1.109694 -1.003838 -1.150589 1.702201 -0.019654 -0.464467 2.139907 14.821988 -36.851370 -10.983263 54.292171 38.514024 2.203050 2.168685 0.590171 2.496095 2.116027 2.060153 1.243985 2.150668 1.528004 1.169845 0.331542 0.470367 0.464116 1.153468 1.830003
+1 -0.043882 1 1 1.684218 -0.665336 0.202547 1.860297 -0.687057 -2.019712 -1.958415 0.954335 -1.457676 0.542657 1.967153 -0.182943 -71.500319 -55.858829 30.669160 56.579616 -66.395755 0.423211 2.162053 1.628037 1.667272 1.846017 2.255816 0.258501 1.383678 0.969678 2.124619 2.478149 2.006455 0.981776 0.706604 1.896166
+1 0.043120 1 1 -0.280094 0.128496 1.352099 1.580783 -0.228250 -0.319800 1.963171 -1.128150 1.833220 1.338013 0.455415 1.248657 60.727661 49.793785 34.152832 -43.349788 -29.882957 0.732250 0.918084 1.236915 0.326936 1.815472 1.888600 2.448028 2.013057 1.706818 0.485222 0.368837 1.793675 2.294733 1.823356 1.640573
+1 -0.007604 1 1 -2.180379 -2.094886 2.222381 1.159501 2.008045 -0.910332 1.184813 -1.396923 -0.957201 0.420021 0.132208 -2.227648 -4.950414 48.397661 -30.507077 -32.445485 -61.263018 0.661835 0.958916 1.246239 1.797991 0.579556 1.852902 0.977999 2.486166 1.742665 2.213823 0.972771 2.359442 0.390279 2.169687 1.679621
+1 -0.003378 1 1 -1.020562 0.508356 0.371449 -0.976388 -1.610956 2.054527 -1.953287 2.322763 1.243390 -1.786764 1.919830 0.862944 -39.011570 -17.454299 45.591208 51.429319 72.558924 1.342645 2.092903 0.422345 1.100986 1.764552 1.075755 0.719134 0.985062 1.931649 1.478347 1.329554 0.321235 0.493224 2.118131 1.429568
+1 -0.024434 1 1 0.112179 0.439547 -1.564860 -0.750591 -0.124133 1.282100 -1.502275 0.246350 -1.788680 -2.015693 -0.382065 1.616323 -43.766561 15.402291 -33.689871 24.336671 -23.569094 1.738653 2.286956 1.613149 1.202698 1.248788 1.881068 1.857965 0.571639 1.540706 0.889609 1.914785 1.540706 0.901284 2.386280 1.464946
+1 0.053016 1 1 0.222679 0.925287 0.417369 -2.033382 -0.809971 0.909409 2.154260 1.368505 -0.700999 -0.725766 -2.291882 -0.597737 20.607909 7.122248 3.619124 -73.386309 46.307894 0.576679 0.751360 0.359602 1.826387 0.832800 1.121265 0.605600 0.820891 1.223241 2.265360 0.911385 1.153278 0.896148 1.564002 0.937659
+1 0.034785 1 1 -1.167232 0.001769 1.454859 -0.776309 1.175975 0.846188 -0.104991 -2.148142 -2.214690 0.865166 -1.591640 1.531827 52.107979 -71.189557 67.120351 -58.264096 -44.658402 1.768513 2.405473 2.283953 0.654915 1.656910 0.942887 1.852005 1.646400 2.044392 1.841168 1.766666 0.603056 0.807107 1.297524 1.987245
+1 -0.010304 1 1 -1.273985 1.231757 0.622337 -1.891035 -2.270628 -1.527867 -1.048525 1.769124 -1.500766 2.036554 2.286577 0.963050 -34.273768 -39.210746 -65.001004 -21.879678 68.244666 0.446639 2.157325 0.904080 2.130936 0.633746 1.374169 0.908362 2.086042 2.113365 2.325268 2.033057 0.338638 0.483241 0.827710 1.077144
+1 0.039747 1 1 1.567170 1.878433 -2.179884 1.510584 -1.962346 0.853811 0.783781 1.885789 -1.066907 -0.862402 0.909798 -0.728400 18.143345 -14.801871 74.945827 64.508375 -7.736539 1.704925 2.421887 1.413423 1.397735 0.980653 2.091288 0.274180 1.650710 2.483685 0.537588 0.746628 1.826812 1.237612 0.796421 1.701914
+1 -0.016537 1 1 -1.747593 0.522722 1.499281 1.273433 -1.084701 1.665776 0.386623 -0.408537 -0.326346 0.323037 0.603044 -0.993551 66.491086 15.684505 59.478479 54.802611 67.485343 0.267523 2.253432 0.686726 0.800566 1.609619 0.366121 1.144602 1.319194 1.698146 0.997212 1.397059 0.868814 1.152920 1.626046 1.960829
+1 -0.002919 1 1 -0.899309 -2.057229 -1.056987 0.932926 1.571278 0.234153 0.557698 0.293014 0.243346 -0.431837 -0.807900 -1.977530 4.151831 29.830249 56.995033 15.527827 -23.805592 0.616206 1.317751 2.183475 1.658836 1.801864 0.424702 2.461996 0.507694 2.305878 2.389091 1.446658 1.975253 0.830764 0.647038 2.013393
+1 0.072651 1 1 0.264264 -2.304194 -0.172226 -1.203125 -0.055596 -1.344570 -2.285192 -1.248355 -1.542258 2.113044 1.371781 -2.203454 38.445421 -47.814532 -68.841406 -67.513017 58.716567 1.365128 1.949363 2.199145 1.780221 1.180518 1.961526 1.866181 1.412955 0.285996 2.240361 1.499740 0.887648 0.454960 0.266054 2.314992
+1 -0.036174 1 1 1.227215 -0.330751 1.695069 -2.086267 0.990624 0.549612 1.043389 1.439447 -0.612290 1.107460 -0.847376 -1.012402 31.909067 45.688298 33.222613 72.464102 54.157504 1.752643 1.162446 1.985594 1.378361 1.617978 1.364720 1.854881 0.477480 0.757242 2.470833 0.535760 1.525671 2.455485 1.337925 1.512480
+1 -0.035632 1 1 0.486029 2.126924 -0.970283 2.029980 0.179124 -0.676592 -0.487209 1.612166 -0.561171 -2.102501 1.475600 -0.892945 39.456564 -3.535362 -18.829868 26.409934 21.761847 2.145340 1.975858 1.997000 1.833662 1.608877 1.388290 1.989756 1.574648 2.116017 1.892054 2.009602 2.131755 0.911146 1.628736 2.166658
+1 0.040091 1 1 0.558436 -1.445312 1.010734 -0.757711 -1.970678 2.199893 0.191765 -0.281730 0.912658 0.212111 -2.322214 -1.450563 73.052376 41.275531 -32.145151 36.443448 55.026268 0.272375 0.558160 2.247298 1.094131 1.311228 0.560178 2.409489 2.274725 0.803461 0.770011 1.077368 0.818309 0.574552 1.001002 2.096013
+1 -0.002834 1 1 1.397290 -2.297182 -0.131702 1.300524 1.845811 0.887933 -0.645707 0.235341 1.680549 -1.070207 0.219647 1.807215 -70.084189 45.030122 71.258165 35.986764 29.548626 0.981252 0.901005 2.198624 2.018857 2.434554 0.549403 1.314285 2.438799 2.147815 0.833220 1.432026 1.308272 0.369147 2.499997 2.447348
+1 -0.009834 1 1 0.549376 1.784480 2.111013 0.210076 1.166104 -0.109215 2.256938 2.334978 -0.797614 1.243128 -1.476146 1.134969 -10.153019 58.204151 -62.837156 45.914091 -71.869154 2.052032 2.005646 0.896300 1.870331 1.408284 0.538248 0.589837 1.395024 0.427569 1.143836 1.959347 1.236555 1.023482 1.914015 2.095647
+1 -0.067957 1 1 -0.450973 -1.975642 -1.122712 -1.017539 -0.519473 1.277671 -0.535084 -1.926014 -1.122191 -1.681777 -0.707759 -1.239626 -29.371781 -1.531048 67.672099 64.960961 -51.120771 1.573000 1.410816 0.338361 0.336631 0.514436 0.880093 1.714619 1.107345 0.653578 1.678441 0.559476 1.864988 1.598584 1.654103 1.004212
+1 0.016454 1 1 -1.341684 -0.900598 -0.151489 -1.379470 0.198002 0.878959 -0.672689 -0.863075 -0.976168 2.082629 -0.876839 -1.399993 -23.254865 55.487277 24.658285 -18.199509 -29.152178 0.465260 2.370566 0.595375 2.214494 0.997391 2.157814 2.383801 0.297835 0.965234 1.687267 0.387272 1.131436 0.541488 1.032482 2.427409
+1 -0.018678 1 1 2.060275 0.406671 1.956267 0.642252 -1.761472 -1.823815 1.233081 -0.688220 1.997903 -1.730376 -2.268921 -1.095107 36.039955 23.530916 -65.900532 9.758469 60.594961 2.417700 0.784985 0.744764 2.005342 0.287569 1.678165 0.422675 2.151447 1.113903 0.620256 1.892694 1.509834 1.786593 0.270166 1.686757
+1 0.009339 1 1 -0.437841 1.965644 -1.984913 -1.423234 -0.200742 0.200201 0.135944 -0.702409 -0.856257 0.529640 -0.038845 2.158453 36.464869 -34.950963 -20.831506 -15.128367 -12.465630 1.977331 2.005279 1.477452 2.042841 0.531560 0.677152 1.894143 1.113152 1.487727 1.479043 1.781589 1.661293 0.354602 1.047284 1.449550
+1 0.037128 1 1 0.894392 -0.482910 -1.539111 -1.535805 2.192306 -0.087366 1.902986 0.499894 -0.479281 -1.796252 -2.039682 1.700950 -70.046679 -74.532355 -15.293538 61.505541 73.625455 2.470381 1.941050 1.973173 1.861926 1.885244 2.302104 1.957006 2.394087 2.170696 0.641510 1.358342 0.403377 1.814180 0.429905 2.161077
+1 -0.049551 1 1 -0.080473 -0.056910 0.130734 1.268145 -0.426849 -1.790150 1.552903 -2.276368 0.967773 -1.807200 -2.269244 -1.816048 -5.733100 -56.219749 -35.313296 39.431050 17.651605 0.932913 0.719839 1.586705 2.248066 0.491064 1.814629 1.219727 1.706183 1.065446 0.705346 0.996268 1.274730 1.388152 1.923301 0.671460
+1 -0.036141 1 1 -0.324294 1.825963 1.887515 -0.334194 0.360940 1.473109 -0.348305 -1.179116 -1.813690 1.755644 -1.870531 -1.661626 -42.382785 22.536237 16.530975 36.092079 -0.435398 1.858936 1.129764 1.690024 1.740384 2.134667 0.343567 2.330423 0.920155 2.289221 1.444789 2.067814 1.753887 1.832120 0.441780 1.503245
+1 0.071285 1 1 0.609238 -0.557424 -0.398352 1.198086 0.196372 1.743448 0.493108 -1.427855 2.231106 1.714698 -2.047019 0.900944 39.938363 -5.940928 50.822736 -72.272767 11.602143 1.333163 2.465129 1.419542 0.743024 2.007424 1.518153 2.095294 2.358652 0.608089 2.152896 0.720284 2.318434 1.921055 1.166192 1.944006
+1 0.005374 1 1 1.525877 0.595413 -2.002076 2.281027 1.934506 -2.232983 -0.285999 -0.145804 -0.092599 -1.221636 -0.157861 -0.101883 -55.967440 5.236620 -38.126021 15.968557 33.532422 1.816282 1.999045 2.455614 1.259719 1.104077 1.966251 0.287081 2.471742 2.310886 1.068102 0.337586 0.806220 2.134059 1.371773 1.139925
+1 -0.005410 1 1 -0.387047 -1.996128 -1.431984 -1.178077 1.514903 -0.066135 0.597077 -2.320063 1.713443 0.424253 0.580549 -2.062563 -36.809670 -60.120157 -39.472926 28.524573 12.492305 0.747602 2.443787 0.485329 2.171416 1.491462 1.257047 1.195053 1.006653 0.317731 2.346880 0.764528 1.167068 0.914490 1.591841 0.815748
+1 -0.039320 1 1 2.176945 0.919161 1.123996 -0.967569 0.515293 -0.837995 1.156322 0.405528 1.599690 1.819919 -0.739786 -2.301418 -20.648101 67.368560 63.387553 54.597277 66.438036 1.735963 2.083504 2.201961 1.861127 1.955964 0.631238 1.962342 2.080082 0.935678 2.190511 0.669051 0.747690 1.672637 2.004047 1.025184
+1 -0.020376 1 1 -1.313836 0.616361 1.354326 1.317182 -0.919081 0.222267 -1.276091 -1.169957 1.336403 1.682738 -1.973912 -0.329109 31.884159 -72.946542 -62.526501 17.098293 -28.994120 2.062252 0.523980 1.526074 2.467891 0.589922 0.563544 0.487247 0.663978 0.972445 1.382376 1.602305 1.191898 1.976999 0.913577 1.989727
+1 0.006394 1 1 0.284869 0.012468 2.204411 0.730716 0.666319 2.178945 1.546793 -1.297006 0.723274 -1.889255 -0.634445 1.020581 -5.908178 1.254025 -73.594432 -1.626018 -28.483432 0.309265 1.812695 2.457884 1.154524 1.577796 1.023005 0.638685 1.136738 1.907345 2.499789 1.200998 1.920940 1.482459 0.685965 1.505961
+1 -0.025127 1 1 -1.693546 -0.590696 1.174953 -2.190013 0.923148 2.165352 -0.716289 1.489569 -1.739414 1.327910 0.307083 1.082924 46.294730 25.530301 -62.231684 22.090458 24.323030 2.082379 1.292058 2.368362 1.810892 1.408125 2.350994 2.406438 0.507201 0.776921 2.467966 1.852088 0.794176 2.213163 1.129403 2.377590
+1 0.002659 1 1 -0.562724 0.054331 -1.054839 -0.675020 -2.342429 -1.907954 0.824648 0.729181 -1.579070 0.745541 0.071837 1.000221 51.695838 51.955934 73.388963 -1.698763 -51.116882 0.303576 0.694715 2.323686 2.434973 0.837571 0.300247 0.993391 2.416303 2.049385 0.269740 1.264142 1.191515 2.285505 1.987046 1.029294
+1 -0.042739 1 1 0.752014 0.472405 -0.660567 0.233827 -0.206873 0.822261 -1.701774 -2.218733 -1.118091 1.250426 -1.347778 0.343790 21.977179 70.455008 37.317075 38.076071 44.519509 1.965896 1.058872 0.457464 1.846402 1.986244 1.052644 1.541687 1.630501 0.333186 1.103669 1.863034 0.269245 1.943223 2.497654 1.324099
+1 0.011081 1 1 -0.009968 2.113923 2.012125 1.679690 -1.375968 -2.198821 -1.021278 -2.098853 1.519076 -0.621581 0.460664 -0.069658 -66.073323 -44.346545 17.623377 -53.896010 19.758275 1.034945 1.064760 0.430197 0.324644 1.538140 0.525294 1.108844 1.083618 2.360750 2.125352 1.299205 0.979213 0.379409 1.723954 0.491216
+1 -0.033416 1 1 2.233993 -1.587428 1.643077 0.598639 0.378702 -1.593678 0.279211 -0.839836 -1.513597 -1.542862 1.389085 1.172022 12.340819 -37.859904 -11.412852 34.200041 0.090267 1.631758 1.212640 1.831613 0.921875 1.961121 1.810334 1.027581 1.058690 1.907052 2.079442 1.439161 1.983238 2.283658 2.433819 1.688287
+1 0.020479 1 1 0.529072 -0.165186 -0.688165 -1.783170 1.060425 0.302140 -1.881457 -1.514819 1.480849 -2.208641 -1.145644 -0.015049 49.264582 -10.165210 3.318413 -27.439177 -70.255120 1.707884 0.398560 1.846002 2.001749 0.647285 1.668103 2.310445 0.401791 2.156084 0.297078 1.746472 0.957381 2.460685 0.984320 0.713310
+1 0.012273 1 1 -2.120938 -2.102401 -1.565494 -1.993723 1.290367 0.781357 -1.156429 -2.212213 0.089099 -1.056127 1.239240 -0.849564 -2.400997 -3.560735 4.729663 -8.552185 -36.572054 1.877429 1.454404 1.674366 1.824922 0.962526 1.166178 1.699183 0.420060 0.953734 1.907938 1.213729 2.148874 0.630055 2.337676 1.325519
+1 -0.004772 1 1 -2.195867 1.499358 -2.140085 1.261234 1.233353 -0.836967 -0.424714 1.109161 -0.537946 1.816949 1.178015 2.156781 42.109261 30.347203 45.436519 1.573627 47.947627 2.211602 1.899495 1.058690 1.907493 0.478443 1.191961 0.782308 0.751815 1.250273 2.084546 1.718614 0.746846 0.991578 1.207866 0.350086
+1 -0.007398 1 1 -0.385605 -1.334000 1.011251 -1.497960 2.085101 -1.743228 -1.505569 1.439374 -1.846914 -0.584268 0.831338 0.062889 44.503125 64.030070 53.386754 -28.825181 35.185236 2.249027 0.902468 2.025034 0.487527 0.862041 2.080907 1.306618 1.834722 1.422159 1.970602 1.411588 2.064589 1.548017 2.278209 0.855261
+1 0.025247 1 1 -1.057829 0.902924 1.546901 0.520521 2.201728 -1.955780 -1.873090 -2.267597 2.300935 1.951362 -1.689474 1.862977 61.607297 -16.166900 -67.085579 42.675524 -52.471592 0.774179 1.372267 0.442478 1.978946 2.147386 0.367480 1.485189 1.574525 2.287816 0.327982 1.394656 0.978362 1.831266 1.839577 2.021597
+1 0.013821 1 1 -0.285422 0.117218 0.299066 -1.717268 1.252808 0.993224 1.828548 -1.787839 -2.017260 1.544483 2.281123 -1.155307 -70.329665 -30.681130 42.241997 11.243977 -22.475507 0.687380 0.546096 1.987582 1.034952 1.194383 0.991929 0.348891 1.816288 2.099471 0.565627 1.748312 0.387907 0.552250 1.916620 0.886496
+1 0.008083 1 1 -1.589585 -1.629174 2.170590 -2.211448 -1.191941 -0.585454 -0.262893 1.771639 -1.642519 -0.639811 0.372628 0.001484 44.072230 21.965017 16.045896 -16.633648 38.270981 1.680609 0.995295 0.668444 1.788170 2.016275 1.783329 1.666802 0.682789 2.128416 1.039539 1.787927 2.448273 1.624502 0.749023 1.579242
+1 -0.006221 1 1 -0.081769 1.724764 2.196869 1.210373 -0.643422 0.936323 2.117446 -0.049377 -0.495893 1.738676 0.404810 -1.044989 -1.899001 33.494639 -5.594811 18.010001 -5.909710 1.007585 2.479892 2.044663 1.907726 2.145674 0.841069 0.591357 2.189895 1.559641 1.879610 2.098788 0.328339 0.640739 1.892063 2.159405
+1 0.047375 1 1 1.480805 1.756135 1.669992 0.571709 0.148941 0.978115 -2.354042 0.827763 1.248580 0.614993 1.914799 1.124948 28.391546 26.706007 47.852338 -45.757588 2.226554 2.450463 2.434730 1.254495 1.049639 0.529762 1.952602 0.385873 2.370038 0.735029 0.377239 1.255857 1.443037 1.869202 0.428085 0.823071
+1 0.000746 1 1 -0.112655 0.986392 0.103520 0.990482 -1.838869 -2.020775 -0.972711 -1.082791 0.768973 -1.953963 0.385127 -1.998367 -43.386921 -53.976425 18.232742 -12.305675 28.514427 1.254647 1.350174 0.379540 1.671052 2.377366 2.385039 0.844261 2.497217 0.728437 2.098735 1.687060 1.420118 1.424564 1.894406 1.031526
+1 -0.019497 1 1 1.223107 1.318325 -0.571688 0.208988 1.727899 -1.653129 0.112501 1.136073 -0.620161 0.761840 0.675549 1.801743 2.477259 -64.703032 36.141225 -74.423951 6.652355 2.216898 0.911352 0.586099 1.569757 0.907402 1.697936 1.958071 2.305612 2.413979 1.238051 1.418726 0.529318 1.240261 0.314870 1.518195
+1 0.012342 1 1 0.414867 -1.661641 -1.575314 -2.102083 -0.926355 0.492877 -0.598988 -1.527278 -0.569971 0.779277 1.573250 0.390632 31.402657 -65.550491 42.891504 -22.485308 -60.577796 2.409863 1.824586 2.073525 0.979829 1.741672 1.287558 0.983204 2.217719 1.206167 1.045129 1.238797 0.455143 1.093161 0.757347 1.987225
+1 0.021441 1 1 -1.316234 -1.996859 0.433102 -1.496007 1.913783 -1.822666 1.702218 0.270377 1.482532 -2.194295 -0.360730 2.054032 -26.727071 48.121457 -22.665958 53.243687 -33.347609 0.275930 1.799382 1.466861 1.779077 2.194155 1.165889 1.345206 2.381552 0.738066 1.926918 0.710948 0.659840 1.182722 0.759357 2.010248
+1 -0.035495 1 1 1.523124 1.454985 1.344232 1.308887 1.030962 -0.073723 0.292166 0.124240 0.508431 1.634583 -0.798702 1.813442 -38.347142 49.592069 -56.088282 74.237447 8.778753 0.542509 2.455260 2.055793 2.218671 1.456181 2.281920 2.480346 0.671969 0.282227 1.896499 2.456887 2.394086 2.149319 1.346042 0.672404
+1 0.016444 1 1 0.378609 1.562411 2.015330 -0.997163 -2.070916 -0.185149 -1.625641 0.282723 1.644387 -0.952529 -1.163529 0.977040 -49.720012 5.765936 8.087959 34.329534 -73.522055 1.597275 2.152195 2.436913 1.939028 1.742465 1.100881 2.257317 0.725028 1.045155 1.667566 2.285751 1.619639 2.269487 0.523518 0.519463
+1 -0.023353 1 1 0.155559 -0.893371 -1.223372 -1.066901 -0.769942 -0.196507 0.697299 -0.203404 -2.126300 2.027830 1.747866 -0.649046 21.408405 -38.943981 68.517763 28.042377 8.228631 1.353920 0.337898 1.557076 1.519573 1.211132 1.248460 0.867164 0.421623 2.459598 0.721912 0.420603 1.068200 1.994289 1.271174 2.368773
+1 -0.014740 1 1 1.473905 -1.103018 0.119875 -2.168107 1.530718 1.846123 1.422700 0.653652 1.347487 -0.533241 0.782555 0.126891 -65.672167 -52.104738 -24.337739 5.615794 34.647372 1.650612 0.829799 2.426238 0.279830 2.098972 1.166276 1.098508 0.627765 2.091531 2.107414 1.314958 2.498321 1.288954 1.948677 1.910437
+1 -0.019334 1 1 -0.881824 -0.358697 -1.471278 -1.862453 2.152385 -1.873251 -0.262118 0.663387 0.027633 -2.090417 1.937634 -1.497241 0.835348 -60.299469 -53.174894 -10.440163 32.173333 1.183167 1.494256 0.956041 2.439513 0.647852 2.204753 1.538356 1.893835 0.434036 1.843348 2.395870 0.639488 1.126401 1.425131 2.428415
+1 0.012972 1 1 -0.026774 -2.315437 -0.639332 -1.010049 -1.864945 -2.035981 -2.075335 0.941035 1.194322 -1.809684 -1.599726 2.301122 12.013857 16.896009 21.215812 24.148740 -32.126590 2.100944 0.565471 1.377252 0.968236 0.385340 2.414126 1.472727 1.378017 0.328981 2.440893 1.343567 1.835874 0.536224 0.318328 1.144606
+1 0.001700 1 1 -0.631191 -0.842716 1.909498 1.571472 -1.204577 -0.909320 -0.672017 1.005151 -0.345627 1.426979 1.892609 0.454945 -62.139060 -71.176607 -15.236538 -30.490512 -54.033747 0.697306 0.867475 1.159923 2.325616 1.131433 0.489663 0.772134 0.747867 2.403192 2.197595 0.478062 1.532094 2.399979 2.192489 2.414376
+1 -0.035706 1 1 -1.070504 -0.065215 1.921820 1.312073 -1.963768 0.531024 -0.343807 -0.977219 -1.449251 0.773935 1.332351 -0.446899 16.612021 48.234864 -66.636684 -62.754599 -66.543424 1.445008 1.249467 2.049803 0.543168 2.281564 1.002383 0.551132 1.119311 1.512120 1.954113 1.026767 0.877667 1.441693 1.783985 1.435013
+1 0.033842 1 1 -0.759459 1.633588 1.338718 -1.816245 1.224578 -2.228327 -2.141066 -1.097318 1.673948 1.083528 2.192993 2.040907 1.586304 -38.988861 64.210337 -66.863308 28.374143 1.888260 1.244894 1.690304 1.941494 0.444213 1.887180 1.092404 1.530063 2.012688 2.254917 0.890768 1.131935 2.188409 1.339803 1.572099
+1 -0.038979 1 1 1.384436 -1.565474 -1.647153 1.575915 -1.936689 -1.461369 -0.262556 -1.986831 -0.687342 -2.098336 0.791882 1.381373 -38.207409 -1.923088 -71.348572 -55.453660 -59.657036 0.538017 1.203581 0.339598 0.865483 1.428316 1.959512 1.777211 2.334138 0.359355 2.181837 1.135751 1.066732 2.059776 1.653921 2.453871
+1 0.025116 1 1 -0.379306 0.865772 -0.830247 -0.573456 -1.239693 -2.054653 -0.171827 0.792642 0.008832 2.355777 0.054722 0.799231 -74.663064 37.876699 -6.321314 -42.332870 -38.539981 0.753111 0.535128 2.148598 0.495050 1.312058 1.002260 0.732194 2.230211 1.906073 1.363151 2.476913 1.476705 0.723935 0.671473 0.953472
+1 0.017023 1 1 -0.372659 -0.509482 -0.449132 0.687343 2.102245 -1.060463 -0.937635 -0.604929 2.290917 -1.482843 1.679591 1.684083 56.611712 23.044964 16.709864 42.688094 8.794593 2.285936 2.473389 0.749358 0.459773 2.404180 0.808882 1.875142 1.260629 0.641371 1.267058 0.696557 1.776328 1.002327 1.860512 0.618705
+1 0.025466 1 1 -2.111090 -1.506919 2.305774 -1.539859 0.030508 -0.894727 -0.436414 -2.326224 1.852953 -1.603939 2.174234 -2.222261 27.153502 68.916106 -26.999218 -25.856442 -19.227819 0.445667 1.574195 1.241529 1.371156 2.026693 1.379985 1.904623 1.744619 1.316319 0.621081 2.263247 1.392925 1.137237 1.289897 2.053731
+1 -0.007112 1 1 0.911169 -1.250775 0.189835 0.270052 0.727365 0.889707 0.895545 0.058771 -1.830101 -0.752117 -2.207356 1.600077 -35.277940 33.659093 58.369278 12.462646 59.699083 1.562325 1.989538 2.416292 1.875212 2.429149 1.956598 2.297491 0.933828 0.355094 0.313121 1.380458 0.854690 2.270389 2.169532 1.333002
+1 -0.053808 1 1 0.860168 -0.768900 -1.531767 -0.635667 -0.673481 -0.034712 0.933803 2.172344 -1.008578 -0.705035 2.129757 -0.486542 -41.771372 -51.456578 69.287376 62.923513 55.479827 2.116751 0.735720 0.745030 1.973164 1.718727 0.388335 0.991524 0.285542 1.351944 0.874464 1.616167 2.420617 0.317040 1.988263 1.242393
+1 -0.016680 1 1 -0.926196 -1.549557 1.976968 -0.152697 1.869399 1.492663 -1.577760 -0.797144 -0.274902 -2.134708 2.089719 0.468863 33.748128 54.780864 1.977855 -58.190574 -8.975265 2.165822 1.968166 0.966601 2.165841 2.285345 1.548541 2.082733 0.499242 2.006372 1.841678 1.326403 1.356752 0.687117 0.625397 0.545447
+1 -0.023192 1 1 0.791404 -1.951547 -1.425191 -0.116020 0.983073 0.880454 0.888301 0.821335 1.592232 -1.018052 0.288158 -1.272316 32.119700 -14.210486 -35.643478 40.072315 -4.602068 2.170547 0.379504 1.069095 1.279928 1.007287 1.978014 2.237919 0.951580 1.709123 0.986227 1.266360 2.455165 0.465618 1.640685 0.494508
+1 0.025735 1 1 1.479025 0.115858 1.003227 0.311081 2.302008 1.143018 -1.701185 -1.749141 -1.936797 1.440020 -0.411227 1.576955 44.709517 -67.155981 59.423582 32.145287 -34.165974 0.962051 2.194856 1.699666 1.781693 1.162717 2.038522 2.184311 2.219323 1.159766 1.933107 1.232453 1.836368 2.088953 1.535485 0.890342
+1 -0.030795 1 1 0.912465 1.682006 -0.151019 1.807033 -0.543257 2.097915 1.564303 0.821784 -0.289038 0.605712 1.446396 -1.639726 -26.014515 24.053612 19.056522 32.961429 32.742022 0.552475 1.199457 0.768706 1.637674 1.627772 1.713520 0.636918 0.685115 0.727928 0.281883 0.615514 0.944870 1.433721 0.550785 2.045483
+1 -0.020737 1 1 1.232890 0.801037 -0.273088 0.079547 -1.378181 -1.694424 -1.224771 -1.005021 -2.184372 1.480921 -1.000386 0.312734 57.415054 24.810374 -12.045481 51.603907 6.861593 0.966899 0.424375 1.464979 1.647013 1.101221 1.222619 0.806157 1.087853 1.544868 1.087270 0.747705 1.926775 0.549104 0.791206 1.796186
+1 0.007836 1 1 0.356499 2.229304 -0.294942 0.344800 -1.184801 1.612012 1.562180 -1.879735 -0.850520 -2.020436 0.014031 0.195803 51.361394 -19.058689 -69.391613 -14.838271 63.181238 1.931032 2.357244 1.694019 1.373035 2.094218 2.279433 1.187505 2.390018 1.278186 0.972090 2.161228 1.267997 0.722316 0.462222 0.817875
+1 -0.040007 1 1 -1.475827 1.787571 2.220849 -1.022415 2.349014 -0.515602 0.357148 -1.003104 1.757347 -1.523002 0.595335 1.390162 13.338353 -72.298941 21.701101 -69.593101 48.747709 1.416203 0.875996 0.366221 0.578881 1.757545 0.308213 2.142841 0.469962 0.394727 0.424836 2.466588 1.203320 0.442477 1.963820 2.167726
+1 0.006504 1 1 0.188797 1.665502 0.503689 2.056680 1.240334 -1.315874 -0.645807 -1.444326 -1.266981 1.129589 -1.208010 -2.048902 71.182370 -37.913317 -9.111885 6.555112 71.764651 1.352243 1.396381 0.725418 0.854190 0.627253 2.493616 0.962387 1.092186 2.375105 0.392168 2.413623 2.006584 0.901844 0.544118 2.495286
+1 -0.008587 1 1 -1.377571 -0.865981 2.021801 -0.627944 1.889610 1.890454 1.942180 -0.503880 -0.547396 -1.508470 -0.202612 1.758131 70.788929 -50.470619 -9.693678 -21.646856 -68.708448 2.381736 1.593982 0.809872 0.510976 1.225982 1.075999 0.314589 1.295566 0.573997 0.661894 1.947644 0.309629 1.185160 1.226673 1.436306
+1 0.013447 1 1 0.102732 1.874056 -0.343264 -1.265825 1.719437 2.216018 -2.110849 -2.177198 -0.474334 1.229646 -1.874198 -2.042414 -57.712121 -67.612120 43.096922 -20.037472 -19.786643 1.313378 0.690968 2.343421 1.124681 1.756067 2.462434 1.123694 0.929594 1.178319 1.016533 2.128651 0.485614 2.469554 1.540737 1.417643
+1 -0.005062 1 1 -0.395076 -0.289764 -2.163219 -1.143849 1.875503 0.402216 -2.237182 -0.164826 0.662334 1.178711 -0.284864 0.084603 -39.049817 -60.278226 3.862506 -32.852630 -4.149194 1.592492 0.516515 2.070368 1.929255 1.737011 1.697378 1.582969 2.464955 0.749193 2.186796 1.237388 1.525964 0.629600 1.435207 0.774144
+1 0.017764 1 1 0.067591 0.321337 0.315226 1.271869 0.898828 -1.317366 -2.172977 -0.206340 0.359024 2.261297 0.207293 1.525350 36.794766 -40.373748 38.410501 -34.708876 -2.074700 0.332786 1.126693 1.832605 1.843474 2.271281 1.422383 1.241552 1.770783 2.293462 0.721144 1.018334 0.888912 1.450812 2.039752 0.363987
+1 0.016947 1 1 -0.073291 -1.872054 1.003867 1.647669 -2.332207 0.248359 -1.012971 0.861064 0.155980 1.475040 -0.886515 0.918963 -69.886301 70.946699 51.167071 14.962200 69.696197 1.884787 1.363060 0.946662 2.300678 0.493313 1.354429 2.139377 0.755521 0.547067 0.298453 2.354035 1.762626 2.448007 1.653052 1.350101
+1 0.031093 1 1 -1.127348 1.175984 1.008280 0.406675 2.024165 1.401266 -1.434440 -0.057174 0.405982 -0.198782 0.156011 1.992147 15.480489 -69.415116 40.138654 60.362062 55.179797 0.727702 0.985382 0.568326 2.103521 1.132576 1.708822 0.414828 0.759443 1.206943 0.589946 0.964473 2.405058 2.063423 2.201403 1.482415
+1 0.001005 1 1 0.910920 -0.722413 2.228172 -0.469732 -1.541727 1.621151 -0.342924 -0.273809 2.102224 -1.408802 2.010393 0.845223 -69.652239 -45.183969 43.035827 3.146012 -74.975911 1.822930 1.233243 1.616797 1.759742 1.233624 1.272825 0.872786 0.418539 2.390832 1.462802 1.063294 0.529529 0.292556 2.238455 0.956675
+1 0.053533 1 1 -0.670700 -0.426375 1.451269 0.150810 -0.603492 -1.837273 1.246215 -1.439666 1.652374 1.339961 0.219961 -2.337805 13.186392 73.696543 67.798530 -60.102304 -39.415799 0.455030 1.432619 2.278657 1.638392 2.450095 0.750949 2.452905 0.727959 0.814214 1.487019 0.829873 1.419069 1.796356 2.351939 0.286550
+1 0.074807 1 1 1.894436 -1.832378 -1.320291 0.501621 0.271835 -2.281828 -1.254625 1.451544 0.059855 2.250419 1.160317 1.585888 23.806772 70.410877 45.610886 -67.836925 14.794288 0.588897 1.343802 1.283481 2.216372 1.070534 0.718510 1.752403 1.639366 0.820786 1.696231 0.301527 2.261658 1.691562 0.580633 1.950170
+1 -0.005927 1 1 0.416179 1.540113 -0.478470 -2.310501 2.211050 -0.789590 -0.545923 -0.310056 0.784388 -2.063104 -0.827051 1.300800 56.206306 -40.615592 23.739059 -17.630869 -72.008357 0.708045 1.355967 0.989205 1.823277 0.322022 2.469610 2.487608 1.234057 1.793049 0.769935 2.048736 0.615056 2.243940 0.900362 0.381793
+1 0.001055 1 1 0.554525 -1.203544 2.320136 -0.484313 -1.555861 -0.304532 -0.609614 -1.040877 -1.632354 0.561139 1.575141 -0.810365 -31.652002 74.807980 -2.273801 34.219072 19.944978 0.853753 2.271219 0.383274 1.436536 0.613253 1.200784 0.581841 2.002425 0.763456 1.162637 0.686125 1.954520 1.119648 0.416969 0.754482
+1 0.026042 1 1 -1.787135 0.382788 1.114289 0.818458 0.364898 2.018454 -0.340715 -0.845623 0.180068 1.048014 -0.942132 -0.779018 -61.754447 -56.989657 74.842085 -29.085387 11.900880 2.396387 0.317155 1.674374 1.955037 0.811138 1.543561 1.622289 1.808574 0.704947 1.036444 1.509363 0.621445 1.633123 1.655590 1.252559
+1 0.066752 1 1 1.027094 0.893270 -0.476284 1.448762 0.434074 0.708603 1.290687 1.456419 1.885317 0.420365 1.198023 -0.868859 24.605427 -6.582032 -74.214101 -66.399426 24.853715 0.870908 0.343530 1.708373 1.882331 0.583707 1.858991 2.061826 2.354059 2.167218 0.675503 1.175788 1.227321 1.081111 0.735515 1.802001
+1 -0.003330 1 1 0.698358 -1.258849 1.145673 0.509621 -1.916489 -1.248129 2.243787 -1.924627 -1.361616 -1.317795 0.046307 0.732626 -7.023089 12.943208 36.492202 -25.569306 6.680907 0.415100 0.832005 1.258319 2.316142 1.648037 0.313092 0.882255 2.053710 0.952394 1.878085 1.218970 2.485114 2.064798 0.564090 0.662026
+1 0.007463 1 1 2.085925 -2.038736 -1.257439 1.282249 1.004372 0.704907 0.432402 0.881797 -0.108474 0.579871 0.672027 -0.838670 -24.762007 74.941498 -8.239292 -27.784887 -30.595878 1.001294 2.493045 0.356304 0.393904 2.341544 1.084907 1.539615 0.556024 2.351664 2.410350 1.006586 1.438761 2.007865 2.185590 1.218238
+1 0.006886 1 1 -0.224813 0.898265 -1.357849 0.729383 1.809104 1.280497 -0.165010 2.274072 -1.860425 -1.466012 1.809850 -0.318161 39.214828 -16.383651 39.975887 24.736082 -60.672650 0.996533 1.230595 2.112454 0.507440 0.287570 1.684998 0.505164 0.294893 1.015468 2.226054 1.794064 2.079784 0.435491 1.545929 0.923656
+1 0.016868 1 1 -1.757932 1.121677 -2.243820 1.367614 -1.537513 1.755194 -0.013049 2.172153 0.500595 1.879646 -0.646069 -1.145842 43.297984 59.211899 74.379564 -2.664612 65.869408 2.382046 2.297363 1.037163 2.348451 2.412816 1.955710 0.877017 1.776268 2.228168 1.325555 0.606243 0.374603 1.958670 1.114449 0.790421
+1 -0.030789 1 1 -2.066518 -1.657608 0.227706 0.592104 -1.077803 -0.208151 -1.798766 -1.884357 1.577713 0.009110 2.311034 2.045553 -63.123137 39.441370 41.111732 64.871938 -47.338654 1.063676 2.447637 2.184176 2.200185 1.251160 1.254017 2.006454 0.967389 1.907265 1.154683 1.998656 0.417622 0.472260 0.780021 0.569045
+1 -0.054866 1 1 0.754919 2.168458 -0.333607 0.806338 -0.706483 1.362960 0.348903 1.797781 -0.533056 -0.827560 2.165411 0.280233 70.069793 13.003585 1.253370 65.387996 -73.947276 2.396864 1.588416 1.766518 0.360966 2.248646 1.250719 0.580275 0.429822 0.760994 0.281378 1.127799 2.417669 0.261689 0.950751 1.277783
+1 0.007743 1 1 0.699368 1.585571 0.134035 0.212613 1.388514 1.003747 -0.378235 0.013429 -0.486555 -1.533203 -1.198807 1.819151 15.779980 14.117012 -35.378843 -12.206339 48.053909 2.005854 2.145222 2.239085 0.307369 1.450090 1.156324 0.345278 1.831811 2.004793 2.314735 0.503830 0.376137 0.732496 0.568744 2.382092
+1 0.004981 1 1 0.758230 1.265245 -2.047518 1.950808 -1.577123 0.489286 0.315075 -1.253920 -0.823178 0.423906 -0.543832 1.847064 -51.553258 -55.601887 -0.921854 -43.599670 -29.652010 0.454896 1.433115 1.615478 2.084153 1.862615 2.211777 0.335076 1.370338 1.774387 2.118451 2.305891 0.355069 2.146344 0.848626 1.604467
+1 -0.056623 1 1 0.942258 -1.815375 1.714338 1.330656 -0.655829 -0.231790 1.455248 1.056849 1.475513 -2.351768 1.346960 0.037282 -4.725103 -64.801442 32.169565 73.886831 -34.024153 0.716001 2.334290 0.653358 2.480446 2.362658 0.450027 0.597325 1.236973 1.303356 1.002805 0.897498 1.753150 0.686789 1.859644 1.783302
+1 -0.040200 1 1 1.967353 -1.522943 1.595987 0.840074 0.813001 -1.821874 0.873486 1.586612 -1.227521 -0.113990 2.112581 -1.699728 -26.319614 -3.745960 41.646502 52.764790 17.826411 2.252429 1.831286 2.167762 0.828551 1.710551 2.480102 1.081498 0.478410 0.635840 0.568812 1.265534 2.083186 1.359766 1.830971 1.385790
+1 -0.028014 1 1 0.717678 -1.694215 2.292524 1.951143 -0.657688 1.501804 1.255268 -0.070662 -0.090616 -0.873745 -1.231701 0.333727 38.305813 5.791440 -13.261014 22.139914 -44.464901 1.051132 0.875242 1.184879 1.014046 0.818905 1.582041 0.358016 2.182043 2.344752 0.994113 1.055013 0.856102 1.257872 1.556731 2.475892
+1 -0.005055 1 1 1.170055 0.312874 -0.559550 1.570547 2.097431 -1.858902 0.575683 0.966209 0.175702 -1.652791 1.065792 0.978455 -42.960193 68.037536 56.870157 16.725687 8.625382 2.376962 2.351731 1.287717 1.413239 0.557509 0.298081 0.591030 1.186891 1.072552 0.886881 1.064965 1.620902 0.999561 0.367036 0.768129
+1 0.015043 1 1 -1.932381 0.250807 -2.279664 2.116651 0.722928 1.708894 -0.622475 -0.425307 0.563226 -1.053890 1.141899 -1.670696 55.172401 -17.450431 -39.395143 -14.164576 -14.029601 1.442334 1.304521 0.331757 1.845389 0.702597 2.054405 1.377433 1.761427 0.308691 1.165299 0.437387 1.908270 2.285815 0.437134 2.162061
+1 0.045220 1 1 -0.919943 -0.141028 0.080304 1.918885 -0.889580 1.236318 1.874749 1.877433 -0.132748 -2.140334 1.777794 -1.874674 -19.245014 -50.952832 -14.239102 -66.585999 39.107346 1.032412 1.247831 1.541581 2.098296 1.061145 0.420909 1.722293 1.829476 0.995231 1.841739 2.358504 0.369679 2.450080 0.496882 0.591689
+1 0.005933 1 1 0.070876 -1.018657 -0.465749 -0.570519 1.001238 -0.128864 1.875804 0.750365 1.035688 -0.762949 -0.466040 -0.748906 -2.042445 22.631678 -29.390469 -15.618117 6.312116 1.940967 0.589748 2.150574 2.188269 1.240859 1.372668 0.432995 2.352633 0.709265 1.618812 1.880973 0.261204 1.804604 1.487154 0.849081
+1 -0.060923 1 1 -0.899423 0.736837 -0.145198 0.672667 0.497033 -1.439154 0.825750 0.393540 -1.968570 -0.070176 -1.355901 0.486773 15.675320 55.103346 21.931487 52.505046 2.315988 2.497063 0.387471 2.224743 2.261516 1.542044 0.884015 2.392017 1.129061 1.125431 0.873857 0.407545 2.108217 1.302032 1.259984 1.051119
+1 -0.046501 1 1 -1.155403 0.893509 -1.180641 0.832035 -2.353824 -0.219328 -1.161990 -1.420145 -0.123729 -1.355708 -0.984264 -2.044759 37.846109 -70.446859 -50.365787 -47.782690 16.331985 1.250057 0.701988 0.809243 1.197984 0.764072 0.257608 2.116986 2.436549 0.335863 1.095861 1.141823 1.867453 0.278374 2.378253 1.549666
+1 0.025718 1 1 1.509089 1.178616 -1.891801 -1.013230 1.226044 -1.162796 -0.827266 -2.307775 0.901789 1.329292 -0.024728 -0.919465 -48.402420 -49.478025 22.827551 -37.349549 16.128590 1.723164 0.724716 0.297627 1.968496 2.017555 0.802073 2.182981 2.367060 2.421842 0.648614 1.512002 2.217358 1.883096 2.194206 2.021104
+1 0.030071 1 1 1.634902 -0.145326 -1.479296 0.033332 -0.567102 1.878745 -1.658874 -2.202130 -0.099919 -1.720473 -0.766647 -1.372639 60.695427 -41.952582 52.958000 -34.895587 9.862717 1.565164 2.460067 1.853214 1.722481 0.484152 0.391489 2.251825 0.679630 0.786037 0.425783 0.381919 1.168358 2.345539 0.721555 1.182092
+1 0.014266 1 1 -2.280002 1.161073 0.148510 -1.555523 0.658238 -1.685151 -0.872321 -0.854809 1.300789 1.583028 -0.190903 0.630937 40.658579 -51.257564 -35.878930 -17.179861 8.079540 2.017473 1.664598 1.900824 0.894330 0.259154 1.107231 0.989531 0.553706 1.638360 1.918786 1.295125 2.174397 2.096453 1.594767 0.504737
+1 -0.004384 1 1 -0.537926 2.152417 -1.330291 2.090858 0.764954 1.192735 -0.208905 -0.337784 1.287026 1.187196 0.941018 0.915687 -22.802443 9.347771 57.984979 3.542060 -18.601898 0.743567 2.135625 0.703322 0.740079 2.009532 0.948197 1.096058 2.202676 0.383158 1.731566 2.427424 2.219439 0.854100 1.359082 1.596166
+1 0.016660 1 1 1.200854 -0.401862 -1.241105 -2.213653 -0.548651 0.960811 -1.008573 -0.629319 2.351612 0.727966 1.556243 2.017348 -2.231195 0.313076 11.869386 -11.221749 -53.941366 1.487002 0.537241 1.655402 0.335556 0.444181 1.353160 1.058736 0.434311 1.958912 0.681623 0.539127 1.863115 1.622751 0.568496 0.454384
+1 0.003311 1 1 -0.997265 0.940083 -0.662244 0.331303 -1.827889 -1.268795 -1.071204 2.313105 -0.847213 1.728218 -1.009563 1.583744 -73.081902 62.475916 32.727910 7.990801 51.396329 0.896409 1.443830 1.706580 0.983589 1.933337 0.597930 2.408968 0.268908 0.784905 1.643160 1.593752 1.442933 2.373695 1.436733 1.673667
+1 -0.009716 1 1 -0.389621 1.867392 0.749630 -1.898138 0.862270 1.581771 2.238952 1.644450 0.105252 1.830260 -1.302598 1.003583 50.336369 3.351421 -72.674819 4.319620 -0.149292 1.987829 0.688853 0.546204 1.555921 2.366961 0.756915 1.470329 1.574995 1.198843 1.710380 1.849621 2.078762 1.261885 1.507424 1.769425
+1 0.024035 1 1 0.318737 -0.970977 -0.199052 0.329985 -0.430293 1.577120 -0.534392 0.294166 0.757662 1.157233 1.582010 1.547171 10.871293 13.820948 -61.323763 -18.489906 40.143554 1.265778 1.686213 0.683080 0.271468 1.063340 1.302068 1.854739 0.350907 1.946535 1.908583 0.804738 1.977632 0.316307 0.913915 0.925110
+1 0.054605 1 1 -0.250980 -0.626403 -0.474640 0.799326 -0.746601 0.965352 -0.083848 -0.221951 1.882185 -0.386005 1.381221 0.954193 27.582411 -72.416698 -7.438592 -70.419644 -42.954027 1.700027 1.099111 1.760473 2.270271 2.439698 1.501620 0.980584 0.924722 0.310515 0.332706 2.044283 2.267440 2.120890 0.556259 1.798091
+1 -0.031875 1 1 -1.962364 0.565919 1.801779 0.683447 -2.117439 0.169350 -0.011043 -1.813541 -0.457216 1.477696 1.351952 -0.881976 57.633407 -55.328773 -60.691716 -45.666951 25.559285 0.998446 1.884194 0.403398 2.167071 0.468772 0.655055 1.755361 1.855437 0.835431 0.332836 1.976555 2.455251 1.897609 0.859782 2.350310
+1 -0.015009 1 1 -1.937612 1.876229 -1.523318 0.010779 2.088790 -1.009711 -0.894836 -2.282044 -0.184594 -1.714979 2.031425 0.897828 23.079020 -10.905881 4.862170 -31.504810 -1.345177 1.999039 2.350275 1.576860 1.034243 0.514801 0.256449 0.640573 1.363875 1.138445 1.347611 2.307187 1.887847 1.037113 1.511849 1.898068
+1 0.012439 1 1 0.545055 -0.149498 -0.905926 -0.172540 -1.761053 0.502995 -0.195440 -0.223531 -1.111665 0.876679 -1.292607 -0.734211 59.508301 -43.983005 -22.370839 63.310861 -34.351738 1.380124 1.992631 0.402876 2.383344 1.603579 2.350724 2.360713 1.498900 0.271375 1.745704 1.552912 1.286394 1.676845 0.736538 1.000383
+1 0.002316 1 1 -0.688435 -1.612184 0.265828 0.431452 -0.945080 1.504347 1.587694 -1.892472 1.848415 2.239709 0.232335 -1.710993 -52.752687 35.587187 63.848777 6.389064 -19.002014 1.122161 2.155749 1.428064 2.224750 2.376962 2.355957 0.318123 2.190113 0.728580 2.242389 1.828990 1.840984 0.909499 0.956941 1.799129
+1 -0.050839 1 1 1.867487 2.351736 -1.890990 -1.516562 0.458954 -0.547044 -0.301512 -1.694275 1.280327 1.693867 1.283497 -1.574777 70.431815 -52.479551 -23.808183 55.864658 67.315026 2.329652 1.466925 0.601626 1.527256 2.086059 2.385235 1.902068 1.561838 0.562258 1.368342 1.977185 1.801260 1.534562 1.138126 0.478157
+1 -0.021399 1 1 -1.324688 1.997867 -2.326666 -0.869146 0.663325 -1.013477 1.772698 2.019440 2.109744 -2.265603 -1.889043 -1.776431 38.745965 53.437279 70.347232 25.928563 31.354367 1.717814 0.791609 1.825638 1.748151 2.172918 1.981814 0.852436 0.394444 2.413449 1.335883 0.926416 1.771843 2.113841 1.325346 1.585292
+1 0.045890 1 1 -0.129549 -0.201980 -1.754351 0.044637 0.944139 1.526956 -0.121539 -2.246395 0.506686 0.583514 0.644285 -0.564804 -60.636744 -21.751146 -21.513064 -70.069686 -11.207433 1.925035 0.565502 1.887288 0.654351 1.178582 0.934574 1.630822 1.229231 1.679576 1.625627 1.661039 0.587210 2.233112 1.163880 1.325247
+1 0.059424 1 1 -2.349819 1.129614 -0.792178 -1.631567 -0.355517 0.129506 -0.519042 -0.902297 -0.440708 0.893320 0.360396 1.761014 -36.832088 13.089470 -55.283955 -57.425588 -51.863978 0.956885 0.863105 1.956984 2.032374 2.355857 0.891433 1.060532 1.366774 0.372726 1.907116 0.900741 2.259100 1.445458 2.054328 2.344769
+1 0.022945 1 1 -0.388310 0.333116 0.358668 0.989429 -0.687902 -2.074793 0.629305 2.128428 0.741992 1.678672 0.358492 -1.973177 -66.744156 -69.031709 34.064309 -31.162150 57.746557 2.070811 0.367524 2.230663 0.496152 1.828163 1.441023 1.773170 1.919299 0.901527 1.972156 0.523197 1.874052 0.937592 0.608303 1.253775
+1 -0.013163 1 1 1.606464 -2.151793 -2.309688 1.732833 1.163470 -1.969579 1.821396 0.523685 -1.160520 -0.286310 -0.657262 -0.770478 7.097964 45.474750 44.115804 4.315956 -61.736165 0.629045 1.114535 2.245920 0.426327 0.526744 0.739790 1.646028 0.295316 1.369812 1.929783 1.619457 1.464462 1.965032 2.293042 0.415279
+1 0.036141 1 1 -1.050513 1.343341 0.478754 -2.350114 0.884325 -0.017618 0.772549 1.598552 1.528511 -2.261037 -0.551177 0.922585 67.426536 -12.204821 73.565134 -40.791918 60.236598 2.072623 1.578250 1.904765 1.891073 1.265893 1.359751 1.580267 2.052939 1.487488 1.968994 1.377198 2.312024 2.190620 0.251672 1.353277
+1 0.047257 1 1 -0.826049 -0.705104 0.983498 -1.402892 -2.317975 -0.891320 0.264728 0.791582 1.051775 1.009709 0.865110 2.190354 3.192348 -46.211473 23.778738 49.255621 -10.773121 1.167424 2.398036 1.032005 1.164160 1.539370 0.944070 1.476618 1.513082 2.373899 0.364143 1.648766 1.311843 1.893157 0.291574 1.480499
+1 0.008648 1 1 0.889093 0.005548 -1.003930 2.009078 2.303414 1.207123 1.282868 1.982220 -1.422625 0.607601 0.204204 1.432405 -37.327777 -67.941298 60.610274 26.872534 -3.324141 0.342358 2.267514 1.108492 1.922658 1.117801 0.888501 1.283268 0.879950 1.576424 0.463022 0.767424 0.351973 1.852090 0.821417 1.063319
+1 0.012969 1 1 1.508028 2.199577 -0.394045 -1.808692 0.942013 -1.211038 -1.111248 -1.544011 0.935807 -1.854141 0.480314 0.309152 -58.665626 -43.172652 -52.764961 -20.699080 -39.440433 0.994712 2.119274 0.388231 1.504909 2.254002 1.259088 1.735404 1.678748 1.214625 1.457775 2.079359 2.294837 1.322631 0.967370 1.587603
+1 -0.002054 1 1 -2.158159 -0.913050 -2.089638 0.891895 -0.031838 2.114741 1.612022 1.733823 -1.046274 1.916451 0.607730 -2.348182 11.640579 43.207973 46.400156 -2.570698 -5.727615 1.914723 0.499572 0.810865 1.465874 0.946546 0.349793 1.220209 0.799062 1.077005 1.466676 0.926471 0.451686 1.486913 1.288070 0.598816
+1 -0.001889 1 1 2.349653 0.796718 -2.165280 1.927273 -1.285646 -1.555704 2.334001 1.635554 1.390529 1.891279 1.662419 0.529501 74.095275 19.284127 -41.672065 -32.399592 -39.936761 1.867878 0.680034 0.826565 2.075936 1.011807 1.444034 0.623970 1.307435 2.063978 0.272022 1.372759 1.961837 0.351858 2.180929 1.628833
+1 0.046861 1 1 -0.596450 -1.288788 2.194568 0.236030 -0.882802 2.051864 0.407153 0.628174 1.961050 0.924653 -0.808946 -0.707327 41.682729 61.625013 -18.407203 -69.859220 -73.917841 0.817788 0.811445 2.204996 1.122805 1.729324 0.756399 1.800146 0.810033 0.966527 0.911845 2.130164 1.174582 1.198046 1.803093 0.832824
+1 0.005371 1 1 -1.573703 1.417209 -2.100127 -1.031914 -1.792542 -0.952403 0.947275 -2.311129 1.074135 -0.181710 -0.371249 -0.377110 2.155915 -65.530583 -72.507731 -37.428824 33.762009 1.196215 0.290103 1.504921 2.456985 1.790276 1.426139 1.363907 1.682503 1.328492 0.466764 0.660417 1.884389 1.428646 0.751609 2.295551
+1 0.022682 1 1 -1.492936 1.702424 -0.993943 0.214377 -1.945563 0.195962 -0.422045 -1.158929 -1.809233 1.267647 0.633969 0.404841 -16.837055 69.610754 -52.055138 59.302070 -60.112118 0.559458 1.566193 1.748908 1.404112 2.409476 2.058077 2.357294 0.292383 1.589078 1.638835 0.901096 1.473697 1.932637 2.332256 2.469385
+1 -0.042194 1 1 0.475660 2.210210 -0.761357 -1.992652 0.451338 -1.301164 1.528957 0.527447 0.800762 -0.179957 0.810488 -1.639220 -55.693677 -43.628370 -62.016192 43.855532 -20.069571 1.985815 0.588700 0.282773 2.058176 1.762061 1.951735 1.561475 1.214816 2.408747 1.054519 1.549305 1.423950 0.585129 1.011632 0.758083
+1 -0.022478 1 1 -2.237716 0.283954 -1.240542 -2.177005 -1.942716 0.910652 -0.514509 -0.124689 1.360410 -0.092727 1.341666 0.603411 15.097504 -56.243037 23.282933 -33.737999 -34.556158 1.594674 1.184337 0.897132 2.344110 1.459032 0.695289 0.725483 1.945476 2.111819 1.082927 2.010832 0.307469 0.887169 1.402319 1.523149
+1 0.039518 1 1 1.220700 -1.431613 0.342184 1.971861 -1.169687 1.164421 -0.121643 0.717877 1.639449 0.881965 -1.983357 1.158582 22.392342 -1.915739 52.179710 -65.620723 62.506362 0.541351 0.978108 2.052797 1.366551 1.115494 0.350780 2.059096 1.484992 0.513108 1.051391 0.721207 2.072675 2.449349 1.705199 0.280249
+1 -0.001265 1 1 0.082942 -0.862292 -1.942724 0.775410 -2.159459 0.795563 1.972862 1.521457 1.702936 -1.812195 -1.396124 -1.672303 -54.544479 70.944277 10.468386 -7.843702 20.899719 0.798546 1.420240 1.223251 2.429479 0.758803 1.696885 2.289415 2.442971 0.261796 0.508560 1.125697 0.844707 0.993826 0.737646 1.618482
+1 0.006582 1 1 -0.714185 -0.856364 -1.275975 0.776248 -2.202222 -1.649617 -2.127246 0.269921 -1.466384 0.273730 1.292447 -1.954112 -67.376301 -43.488811 33.558414 16.268721 -21.599736 0.973505 1.191749 1.731492 1.188872 0.621198 1.978343 1.005767 1.182968 0.396246 1.214687 0.250054 1.157180 1.222522 1.418613 0.877404
+1 0.011013 1 1 -0.486013 -1.855001 0.160280 -1.662223 -1.934854 1.114097 2.306572 -2.272111 1.831430 -0.478002 0.836872 -1.176655 59.080125 -40.340105 3.855506 -0.514657 50.166972 1.469580 2.481278 0.581084 0.528927 1.420325 0.405929 1.941017 1.418972 2.408072 0.961169 0.868962 1.393390 2.206185 0.847333 2.373179
+1 -0.007142 1 1 -0.177479 0.052604 -1.819380 0.377197 1.394819 -1.416557 -1.093077 2.257974 0.907072 0.588827 0.393377 0.006925 -45.391829 -0.462882 20.348491 -2.912848 -56.235387 1.402642 2.451084 1.619033 1.090555 1.949717 1.393245 2.019934 0.278106 2.381446 1.218311 0.398614 0.507355 1.116796 1.992436 1.620690
+1 0.028161 1 1 0.090249 -0.566189 -1.631862 -0.604347 -2.053560 -0.650714 0.908456 0.271915 -0.943309 -1.721411 2.318427 -0.933338 29.835176 -10.203545 -40.981176 29.382167 26.079431 1.630026 1.349467 1.998295 1.095837 0.726419 1.920503 0.886885 1.125876 1.596623 2.436882 1.426350 0.412345 1.790843 1.942450 0.757990
+1 -0.022688 1 1 -0.853989 0.941329 1.423420 -1.383004 2.071670 -1.290069 -0.478793 1.692785 1.952542 -0.706476 1.483266 0.708293 24.909296 0.541838 -43.332798 -44.342961 -72.149189 1.203636 1.266024 1.322310 2.319318 1.022254 1.517022 1.080422 0.398188 2.345535 0.649551 1.501556 2.159444 0.518424 0.399304 0.849701
+1 0.025641 1 1 1.704153 -0.197538 2.218846 -1.710274 0.994413 -1.751659 -1.836019 -1.248588 -0.747506 -0.101815 -0.606220 -0.561721 -61.608610 -5.905809 41.061679 -26.365710 -28.495471 1.774226 1.668835 1.108555 0.738639 0.307813 2.166904 2.151174 1.025563 0.888699 2.366168 0.937605 0.819809 1.029615 1.492504 0.771006
+1 0.008909 1 1 1.901444 -1.860195 -2.301555 1.759023 -1.636412 -1.668187 1.494949 -0.856456 1.889076 2.341225 0.524871 -0.077021 44.870809 -56.307503 -10.207453 43.333673 59.033839 0.350970 0.747618 0.466415 1.538410 0.555012 1.089483 1.937379 1.028829 1.782337 0.730710 2.047529 0.574211 2.020186 2.274103 1.604190
+1 0.004514 1 1 1.592297 0.080409 -1.024327 -1.513042 -1.650936 -0.732011 1.144085 2.092292 1.300840 -2.272654 2.124203 0.423729 38.245747 46.266113 -5.438048 -47.271354 60.355760 0.613948 1.622478 0.482779 2.070870 1.370710 1.277231 0.675252 1.466736 1.928706 1.516413 2.109966 1.450652 1.605280 1.692272 1.266220
+1 -0.000025 1 1 2.079414 1.629071 0.814003 0.881145 -1.626700 1.332932 -0.111922 -0.828978 1.896138 -1.500819 1.144664 -2.323698 60.128834 35.305187 -25.726096 71.498550 26.127234 2.431412 1.740428 0.631144 0.384916 2.027153 2.355075 1.245134 1.217241 0.421548 1.200866 1.953485 1.716522 1.585520 0.340770 0.322579
+1 0.005121 1 1 -1.251291 0.943250 0.733408 -1.214817 1.352852 0.107041 -1.100340 -2.000101 -2.234167 -1.323065 1.014290 -2.246120 12.873912 71.832191 -66.359803 -59.207177 4.979820 1.312546 2.456465 2.053019 0.599447 0.905078 0.887675 0.910619 1.777617 2.412456 0.389719 1.752023 2.003589 2.311768 2.390087 2.440736
+1 0.006487 1 1 1.846201 -1.974480 -0.434613 -0.342401 -0.899137 0.841240 1.557306 1.037877 -1.662044 1.069132 0.569260 1.406968 4.460756 -28.065598 51.487552 1.293750 -5.946046 0.847193 2.279800 0.595188 1.328853 2.033918 1.318773 1.364459 1.954590 2.303012 1.476497 1.729310 0.516965 0.631709 0.887509 0.368378
+1 0.012269 1 1 -0.869673 1.232041 0.669243 -0.506201 -1.852156 0.857894 -1.292854 -0.171439 -2.101599 -2.216903 1.366206 -1.653473 -30.435316 -26.350719 73.462356 31.820774 61.748815 0.809899 0.969928 1.832070 1.844402 2.110963 2.448710 2.223861 0.940517 0.262655 1.439636 0.962290 1.709625 0.421343 2.260971 1.392729
+1 -0.005529 1 1 -0.378812 -0.252174 -1.856725 -0.530388 1.605711 -0.660016 0.079689 1.014541 1.967485 0.690759 -1.737285 -0.581870 -40.591111 -14.808360 -34.109933 14.353273 35.461867 2.238951 0.294993 0.440133 0.820232 1.392992 2.273725 2.003843 2.080481 0.901260 1.984805 1.622374 0.989702 1.172002 0.586759 1.407824
+1 0.036894 1 1 0.023121 2.183816 -1.400656 2.275644 1.004452 2.041914 -1.886584 1.843785 -0.181127 0.004444 -0.701998 1.335753 5.795379 52.937157 64.790255 -70.187913 -48.247846 1.351680 0.936384 0.561489 1.949574 1.233355 1.252862 0.604000 0.926812 1.680142 2.150179 2.314414 1.852327 0.302623 0.435192 1.018482
+1 -0.036184 1 1 0.259254 -1.679762 0.163287 1.755800 0.745136 -2.024430 -1.139885 -2.191742 0.132975 1.244196 2.334369 -1.609129 -7.394869 64.436515 -15.490103 57.835419 39.879347 2.157674 2.283836 0.932723 2.022178 2.002030 0.864649 0.898751 0.307412 2.165433 2.190352 2.494036 1.256507 1.112636 1.817544 0.714080
+1 -0.009674 1 1 2.173958 -2.160147 -1.353143 -0.282883 0.393584 -1.227928 -2.229103 -1.044505 -1.341873 0.641657 -2.329167 -0.489180 46.691669 -53.120711 0.214641 7.472755 44.587137 1.015197 2.165572 2.271264 1.130403 1.178406 2.464126 0.318328 1.140626 2.003230 0.783654 0.875103 1.108915 2.292445 1.628471 2.212096
+1 -0.015761 1 1 1.684305 0.787329 0.251553 0.835026 0.780363 0.977119 -0.241074 0.922967 -0.875847 1.140344 0.477026 1.606955 44.309133 -46.400927 -10.387421 18.611786 58.286508 0.945076 0.398410 1.573254 1.176888 1.705531 1.363904 1.635521 1.457150 0.568015 1.383675 0.932663 1.016650 1.842778 1.820656 1.259127
+1 -0.020380 1 1 -0.983548 0.561823 -1.071451 -1.838909 2.014850 0.354239 1.944154 -0.314503 1.444581 0.851327 1.447767 -2.152623 -67.333490 -73.963335 -51.773966 -15.049690 -40.138715 0.454161 0.332283 1.674320 1.047171 1.796175 1.570581 1.248336 1.026267 1.470373 2.313918 0.273342 1.059072 1.572501 2.031099 1.183983
+1 0.019329 1 1 1.797596 1.067581 -1.948162 -1.076004 1.752474 1.399626 -0.738608 -1.352682 -1.964295 1.090298 -1.835700 -0.593442 68.467099 -73.474425 65.340866 33.934543 37.856485 0.684110 1.843098 0.441801 1.847560 1.193392 2.345054 1.566604 1.911451 1.761267 2.115238 2.303972 1.860148 1.256718 2.408292 2.414200
+1 0.046456 1 1 1.160915 2.201750 -1.584094 1.132608 -2.312661 -1.110695 -1.685572 1.471030 -2.304461 0.043976 -0.747391 1.827314 32.766065 49.258063 30.258968 62.477288 55.785568 0.445680 1.795245 1.677701 1.626778 0.755682 0.991030 0.992621 0.734521 0.841098 1.088592 0.463073 1.621477 1.663104 1.532874 2.017064
+1 0.004034 1 1 1.879568 -1.949551 -0.863317 -0.331041 1.522730 -0.455255 1.450066 -1.219291 1.563984 0.174678 -0.005518 1.501933 -40.737938 67.479888 -15.514216 -47.433939 27.787934 0.352022 0.433004 2.491078 1.046968 0.649159 1.672481 1.647250 0.583131 1.182893 1.376491 1.675286 1.525877 1.415789 0.666348 0.316004
+1 -0.023189 1 1 1.184499 -1.973586 0.443982 2.287773 2.220885 -0.421625 1.173598 -1.407664 2.292286 -2.047853 1.027611 0.158369 -25.114237 5.017875 35.429585 -34.972594 65.606249 1.288452 0.260497 1.168782 0.462332 0.419021 1.486651 1.399684 2.243324 1.797519 1.656801 1.361129 2.248459 0.348543 0.460340 0.685636
+1 -0.004670 1 1 0.351746 -2.260034 2.170836 1.918807 -2.203425 1.697356 -1.348515 2.102216 -1.546774 1.619899 2.167000 -1.293512 -57.519243 24.088419 4.059623 -19.911782 -7.316140 1.939465 2.333935 1.452284 2.040565 0.520728 0.872839 1.299587 0.658679 1.915244 0.257908 0.401705 0.708737 1.750841 2.393028 2.371185
+1 -0.013825 1 1 -2.070794 1.865207 1.728609 0.858964 -2.147040 2.166115 -2.025874 -1.857962 2.231801 -0.740667 1.747244 -1.680629 -8.453743 -32.063896 52.099882 -57.285031 60.484103 1.469896 1.040050 1.379115 0.786571 0.404499 0.412451 1.312588 0.914237 1.824237 0.700056 2.085770 2.043215 2.320415 1.472201 1.533977
+1 -0.004324 1 1 0.815050 -0.377366 0.481024 -1.895422 -0.607791 1.322045 0.690443 -2.332315 -1.564301 -0.780883 -0.298092 -0.764509 50.409236 28.024030 -0.124840 1.818295 -39.910871 1.644935 2.176318 0.631084 1.624246 0.947574 1.878385 1.772373 2.020887 0.548582 1.023784 2.489975 0.506210 2.116364 0.974740 1.710247
+1 -0.016870 1 1 -0.511669 0.481165 0.476204 1.924961 2.265671 -1.681145 0.481932 -0.760947 0.180660 1.566215 -0.032311 -1.118085 43.187978 10.346035 35.805559 -15.975750 -4.438088 0.760916 1.218656 1.695940 2.170273 0.281074 0.502445 1.839241 0.870375 0.391069 1.954237 0.855056 1.671539 1.557199 1.347192 2.008524
+1 -0.013604 1 1 -1.167629 -1.949409 1.527966 -1.994007 1.229999 -0.656692 -0.613304 -1.804931 -1.834468 1.260942 1.032911 -0.298261 35.417105 55.289710 4.152469 40.541418 -70.388114 1.929577 0.396474 0.544822 0.830887 0.462401 1.572608 1.577779 0.735163 0.376144 0.856396 1.693468 1.119948 0.960563 1.940522 2.106470
+1 -0.022313 1 1 -1.107064 -1.909741 -0.942389 -0.387042 -1.912704 1.105528 -0.333434 -0.998693 0.496953 1.943310 -0.364790 -0.209261 -51.225098 59.779056 6.601485 -48.834627 36.421779 1.237663 1.645860 1.971519 1.062392 1.123706 1.129283 0.364984 2.286329 2.336767 1.791677 2.463193 0.384120 2.150894 0.819839 1.537627
+1 0.072685 1 1 -0.884613 -0.106738 1.474195 -0.938720 0.019268 -1.317317 -1.345517 0.650442 -0.767195 -1.158201 0.988318 -0.508968 -39.253826 -39.055600 -7.465296 -69.236876 35.816884 1.740664 2.338330 1.067317 0.640273 0.816741 1.214441 0.603691 2.476248 1.556455 2.330621 1.991627 1.518820 2.065502 1.140552 0.755609
+1 0.013728 1 1 -2.019373 -0.971820 -0.246499 -0.718741 -2.035089 -1.215623 1.934372 0.214919 -2.266107 -0.931750 -0.649133 -0.789873 -19.130967 65.841613 49.990203 35.338865 -59.697636 1.552523 1.506185 1.203716 0.361976 1.230733 2.178010 2.066666 0.461826 0.914929 2.216628 0.873515 1.417889 2.214375 1.254473 0.678135
+1 -0.005924 1 1 -0.590047 -2.046797 -0.069768 0.798638 1.824385 -1.080776 1.662148 0.677067 -0.947876 1.633418 -1.517117 0.553676 -42.398291 61.922836 37.108480 -17.773823 -74.638370 1.418753 0.986826 2.327627 1.174091 1.943619 2.404281 2.494236 2.367054 2.327526 1.736730 1.462264 1.024618 0.755118 0.517052 2.086434
+1 0.062881 1 1 2.029016 -1.885523 0.822565 -1.305495 -0.563092 -1.410166 -2.053082 -2.044308 -0.652542 -1.542538 2.132597 0.133475 6.660060 35.634970 -33.053038 -72.403298 67.771836 0.493619 2.011850 1.661007 2.300741 1.561001 2.252563 1.828641 0.473819 2.219129 2.398570 1.024668 1.595030 0.422284 2.327302 2.470516
+1 0.017381 1 1 -0.658575 0.730237 2.030555 0.422046 1.184893 -0.063457 -1.521424 -1.153779 -0.083762 1.222932 -1.624181 1.261954 -25.601613 63.681929 52.188827 -62.377282 -24.986680 2.108111 1.773754 0.487029 1.493330 1.151544 0.991313 1.239269 1.646687 2.374279 2.256365 0.479152 1.858970 1.702331 1.580183 0.631249
+1 -0.035552 1 1 -0.117507 -0.454771 0.160550 -1.839515 1.249104 0.002204 -0.652233 -1.065195 -0.358389 -1.004483 2.150565 0.528476 -23.923536 67.128988 -63.103338 72.197851 -70.711560 1.387263 0.487718 1.830199 1.913049 1.620374 1.131731 0.996771 0.729005 0.387269 1.082693 0.324143 2.122536 1.204388 0.395348 1.871237
+1 -0.009545 1 1 2.149951 -0.363218 -2.053380 -2.335550 0.611710 -1.420309 1.833841 2.343115 -0.699360 -1.439707 0.959013 1.762111 -50.007008 -17.786662 9.576890 8.791098 1.980805 1.245942 1.295796 2.195531 1.794741 2.216118 1.304251 0.299820 0.573787 1.634727 1.609013 1.430937 1.004992 1.653226 2.012350 1.060623
+1 -0.024213 1 1 0.204249 2.187836 0.186906 -1.833720 -0.307622 -0.704624 -0.382398 0.734766 -1.966628 -0.424903 -2.082917 0.748058 -1.600918 -56.637825 -11.922316 21.628878 66.560506 1.111301 1.886356 0.733332 1.112907 1.885052 1.324930 1.343331 2.373000 1.008736 1.569040 2.358957 1.232299 1.493922 2.104320 1.050534
+1 0.058390 1 1 -0.612659 -0.397532 0.847551 -0.754236 -0.124937 1.902418 0.385723 -1.405741 1.635578 1.789507 1.777202 2.314499 -31.576397 -4.508576 -25.644218 -52.373334 -38.623529 2.190115 0.760312 2.312351 0.930769 0.687943 1.014263 2.226961 1.291526 2.419018 0.441679 2.050669 1.596241 0.529199 1.493063 1.166905
+1 0.050407 1 1 -0.288788 0.095164 1.918592 -1.100828 -0.772361 1.563174 0.693390 0.060640 1.298136 -0.593995 2.278983 0.575968 33.602019 -0.866148 -7.349116 -66.593356 65.461668 0.838916 0.404182 1.841968 1.701141 1.832129 0.584803 2.290554 1.346517 1.907444 1.902918 2.336067 1.282923 1.835900 0.962071 0.269572
+1 0.021119 1 1 -1.180433 -0.387106 1.720882 -1.777704 -1.329066 -0.880925 0.617301 -1.709542 -0.845778 2.279667 -2.076598 -1.429607 33.711187 33.920469 -48.679091 -49.476580 47.114340 1.385719 1.533466 0.719505 0.474083 2.159832 0.301292 0.562396 1.441171 2.017902 2.121763 1.715129 0.673545 2.024603 2.249546 0.617695
+1 -0.005335 1 1 1.715314 -1.119957 -1.827579 -0.777990 1.203415 0.213550 -1.698921 -1.407305 -1.099257 2.062053 2.007043 1.096752 -56.004255 -13.520047 18.574486 31.393156 74.777488 0.403680 2.407785 0.642411 0.750500 1.651672 0.650758 1.547120 0.700483 0.274692 1.242937 0.283624 0.624192 0.545861 0.285009 1.394078
+1 -0.006928 1 1 2.247654 1.814794 -2.049868 0.147124 -1.299280 0.205812 0.180998 -2.163821 -1.830891 0.117479 -0.018190 0.590628 -73.844181 0.846009 -31.128050 30.870404 -11.117556 2.083577 1.186111 1.469361 1.053727 1.743853 1.943968 1.527873 1.210015 0.466295 1.768408 0.638817 1.094614 0.421029 1.489319 1.228427
+1 -0.026692 1 1 0.342515 -1.884013 -2.058461 1.809243 -1.092537 1.917404 -2.223494 -1.022242 0.540848 -0.163751 -0.129635 -1.647342 -50.730319 -24.465684 -44.747641 26.399390 -5.445545 1.025779 2.273353 2.494782 0.299792 2.350888 0.628301 2.101926 1.320028 2.210631 1.318091 1.150221 1.258687 1.753744 1.672952 0.559070
+1 -0.006919 1 1 1.737207 -0.720284 0.310647 -0.275149 -1.568322 2.315952 -0.133851 -1.829551 -0.926244 2.343450 0.209638 -1.488392 -64.992321 -25.944110 7.341946 -53.909643 -59.362598 0.517193 2.210612 1.001140 2.165761 0.943250 1.205364 1.048563 0.454682 2.332623 1.899309 2.439197 2.089361 1.642083 1.482503 1.421066
+1 0.034416 1 1 1.918271 -1.784630 0.076178 -1.439144 0.997799 -1.379347 2.267057 -1.941629 0.336613 -2.130468 -2.037464 1.278282 9.591471 -46.141019 7.894711 -63.589447 2.165674 0.602258 0.908202 1.657698 0.685738 2.194104 0.305585 0.718267 2.161016 2.195627 1.154305 2.396090 2.089208 1.327301 0.701066 1.062028
+1 0.014592 1 1 -1.623032 1.723825 0.564539 2.172094 -0.492903 0.159921 1.728177 -1.698388 -1.862280 0.340162 0.980140 -1.298296 -67.117656 -46.448227 -55.353618 -28.257082 -16.777315 1.729911 1.619280 0.733449 0.826524 1.387253 0.311255 1.514806 2.090949 1.321187 1.445637 0.569257 2.002282 0.604782 0.566807 1.319745
+1 0.006925 1 1 2.215178 -2.086968 -1.368856 -0.473651 -1.424764 2.346806 0.079336 -0.198502 0.142875 -2.011726 0.313569 1.701605 -19.397944 -71.241283 -52.240573 -57.308827 -39.453149 2.288951 1.392988 2.203306 1.959709 0.582694 0.582036 0.778395 2.482355 0.694006 1.666996 1.697523 1.774820 0.399469 1.376534 2.403907
+1 -0.011804 1 1 1.181260 0.138657 -2.216285 2.338706 0.587477 1.279435 0.830652 -2.047608 0.429545 -0.025264 -0.492445 -1.572904 22.635183 29.519786 -60.956095 10.913076 -33.928330 2.373415 1.230164 1.616513 1.489163 0.861786 2.287471 1.267572 0.333440 0.880887 1.572899 1.967397 1.546758 1.368450 1.530117 0.668248
+1 0.005999 1 1 1.608144 -2.192952 -1.356877 -1.787026 2.223477 0.734793 -1.509342 -0.721618 1.453212 -0.180350 -1.082417 2.343781 34.007150 58.172546 5.980901 21.002584 40.429212 1.281426 1.426392 1.119149 1.034259 0.786900 1.430729 2.020810 1.503011 1.856988 2.151643 2.157359 1.477458 2.135255 1.229762 1.614796
+1 -0.047969 1 1 0.052108 -0.723378 0.154968 -1.405782 0.936611 2.241138 0.683616 0.725009 -1.014072 1.203749 1.128485 -0.910762 -42.446042 9.376409 -60.685094 65.627542 52.098685 2.464006 0.553222 0.251317 2.139490 0.402962 1.581500 0.263977 1.159319 1.167198 0.851059 1.993897 1.419788 0.375230 1.236496 2.294192
+1 0.001965 1 1 1.452125 0.400069 -0.616106 -1.776618 -1.929180 2.228624 -2.299037 1.668903 1.120153 0.411384 1.052616 1.011719 52.736059 -15.060181 -66.456249 -30.180125 62.643640 1.399902 1.397824 2.473079 2.295184 0.414280 0.561667 0.433721 1.052748 1.028583 2.147401 0.627834 1.004134 0.730074 0.357767 2.496094
+1 0.029537 1 1 1.612420 -1.006956 -1.722875 1.274397 0.988061 -0.124072 2.303701 1.309756 1.506560 1.079536 1.059030 0.416502 71.829543 39.132026 -58.031458 -34.707237 25.468641 0.646853 1.153849 1.493744 1.359554 0.517248 0.884151 2.420523 0.988399 1.764093 2.354064 2.248907 1.134051 1.745240 0.502735 2.222344
+1 0.024273 1 1 -1.860464 -2.113235 0.129204 -0.873277 1.933338 1.689515 -1.169874 -1.984211 0.935877 -0.663663 0.048015 1.177151 56.475628 -14.124188 64.771362 62.275938 -28.311064 1.014251 2.011247 0.531240 2.047325 1.647418 1.153688 1.033668 2.111964 1.284305 0.309719 0.445389 1.396153 1.389613 1.724230 0.635976
+1 -0.039859 1 1 -0.961483 -0.859468 -1.614325 1.970403 -2.115503 -0.282927 -0.349050 0.445432 -1.610686 1.881623 -0.404543 0.819899 32.301508 41.438081 -0.172520 -49.543610 -29.460209 1.558938 1.327836 0.691157 1.032735 2.174304 0.536408 1.154381 1.434653 0.463915 2.271067 2.328724 1.607873 0.269273 2.421774 1.757248
+1 0.015248 1 1 0.177769 0.110367 -1.746531 -0.477328 -1.968603 -0.625566 -0.543257 2.086408 1.376797 2.005251 -0.754816 -0.446932 -1.249710 -3.882125 3.116736 32.981819 -74.571008 0.400963 1.735837 2.214802 1.679835 1.488638 1.038138 0.730904 0.809394 1.479131 1.011864 2.402774 1.917439 1.153911 0.278451 1.424564
+1 -0.010765 1 1 -2.024100 -0.312284 1.039874 -1.081582 2.244479 0.284637 0.823670 -1.585077 -1.247408 0.224982 1.929947 1.241377 65.902911 30.219407 -2.419347 -11.967033 20.073204 1.680117 1.725953 0.341492 1.204738 1.786885 0.670280 1.140527 0.341296 2.418573 1.957132 2.274077 1.153197 1.785775 2.264321 1.437259
+1 0.022392 1 1 -1.186013 0.079599 -0.501153 -1.842384 0.163319 2.294298 -1.218777 0.771475 -2.315267 2.211672 0.241735 0.765612 -60.135074 9.803073 60.251176 -8.488470 -15.722819 2.073823 1.494808 1.242674 0.377013 1.950076 0.674916 0.318842 0.782546 0.252355 1.586251 1.373349 0.622686 2.230264 0.552440 0.616218
+1 -0.031183 1 1 -0.762928 -0.121905 1.037567 -2.169371 -0.870572 0.259916 0.019070 0.072546 -1.233637 0.781136 -0.169121 -0.851349 -57.817547 -39.508773 26.054189 42.753049 50.493276 0.482344 1.502468 1.726938 1.140671 0.500816 1.470484 1.928887 2.307492 0.268114 0.938388 0.484404 2.375371 0.354073 1.152212 0.979130
+1 0.008935 1 1 -0.460137 -0.499057 0.393034 -1.040302 -1.394447 -1.767346 -1.593474 -1.005394 0.974932 0.700545 -2.199952 -1.190573 -36.989025 -74.551150 -31.182628 13.569838 68.270221 2.389048 0.723777 0.270336 2.284081 0.542265 0.600701 1.733957 2.118433 1.997868 0.672341 2.037678 1.505384 1.234304 1.448217 1.180878
+1 -0.046083 1 1 1.729916 -0.741181 -2.191593 -2.067235 0.433558 1.449037 0.334195 -0.358875 0.252173 1.827515 -0.308079 1.035982 -16.626720 4.715616 55.354821 48.472594 28.884089 2.198297 1.030082 0.333165 0.747150 1.606402 0.302200 2.324438 1.585305 1.216805 2.091699 0.433078 1.494140 1.266268 0.917184 1.863141
+1 -0.046871 1 1 -0.893350 -0.856112 -1.758236 0.727648 0.925106 2.092874 1.660711 0.089881 -2.049090 -0.921187 -2.195379 0.265827 13.290977 31.455251 68.403872 63.872897 -38.226531 1.025423 0.788787 1.638936 0.344885 1.980461 0.603171 0.487794 0.854481 1.014177 0.773329 0.587560 1.375599 2.444764 1.144637 1.907029
+1 -0.039115 1 1 1.328223 0.852582 -1.022436 2.006464 0.789841 0.063884 -0.731790 0.145234 -0.075934 0.829091 -0.002304 -1.018324 13.558434 26.606742 29.517334 47.827505 -13.117512 1.884747 0.691581 1.399053 0.630850 2.187944 0.273761 1.348067 0.968584 1.740954 0.454722 0.757642 2.434883 1.581533 0.819252 0.666734
+1 0.002787 1 1 -1.995892 -2.166768 0.473385 1.675118 1.897649 0.345223 1.205960 0.591229 -1.650544 1.133640 0.900716 2.137820 -51.761027 52.413806 -31.157369 -11.906762 -16.948866 1.231201 1.046440 0.771767 1.345924 0.947324 2.178366 1.301250 1.613632 0.319948 1.369019 2.097372 1.274679 0.535772 1.728372 0.501314
+1 -0.014013 1 1 0.948814 -0.002933 -2.163131 0.331276 -2.285950 0.148085 0.728450 0.264920 -0.701547 -0.501186 2.316755 -0.771430 -52.285975 -70.389221 18.357547 -14.710361 -37.043479 2.278780 1.458439 1.984677 1.714051 0.557524 0.547570 2.002640 2.123352 1.421458 1.440876 1.545907 0.559178 1.349005 0.977861 2.408265
+1 -0.056112 1 1 -1.468212 -2.178480 1.547397 -0.570908 -0.824360 -0.592175 -0.114151 -0.591895 -0.125811 1.348965 0.758002 2.149433 11.194774 50.570360 36.042102 59.603043 48.341909 0.362031 2.154783 0.930234 0.692551 1.959590 0.826692 1.954059 2.372546 2.376429 2.391892 1.276331 1.289046 1.252929 1.729976 0.452623
+1 0.014392 1 1 -1.146016 -1.557438 1.455130 -0.927306 -1.358820 -1.459849 1.731268 -1.586633 0.863470 -1.815765 -0.134016 0.118947 34.509539 -48.173276 51.742500 -63.807821 -68.049713 1.952025 1.933449 2.474468 0.888853 0.451517 0.900349 2.409634 2.461557 2.139368 0.615439 1.935081 0.657693 1.089986 1.395035 0.602271
+1 -0.015876 1 1 -0.048935 2.211343 -0.574433 1.194176 0.445257 0.163181 -0.025990 1.434932 -1.102337 2.134408 2.281381 -1.545624 66.679210 27.475075 73.586013 10.126827 -48.418638 1.044172 0.897478 1.415632 0.271022 0.313420 1.902375 2.213941 0.703961 2.479746 1.838355 1.740033 0.726402 1.632502 2.460704 1.294526
+1 0.001599 1 1 2.321819 -0.483945 -0.077386 0.000150 -2.188316 1.172979 2.331893 -0.814991 1.369315 -1.233357 0.767963 -0.080462 4.060627 -3.036173 -28.960457 11.606966 -71.724013 0.392619 1.001748 1.120033 2.403525 1.042713 1.132032 1.560563 1.631192 0.687118 0.650437 0.650600 1.133656 1.859076 1.238146 0.774028
+1 0.010226 1 1 0.122831 0.399073 1.492732 -0.419589 -2.299637 1.015977 -2.181395 -0.315690 0.352600 -2.040132 -1.159674 -0.196892 -34.038889 8.385647 -62.428735 10.258998 72.971445 1.841223 0.429481 1.782785 1.511552 1.403023 2.111638 0.293803 0.704247 0.532163 1.805916 1.027838 0.870353 2.264723 1.446618 1.311927
+1 -0.075163 1 1 -0.607799 1.182561 -1.552252 -0.915434 0.250917 -0.430714 -0.786497 -0.400423 -0.614013 0.413842 -0.044130 -1.850720 45.181255 61.354832 -59.337085 71.620021 -32.303299 0.301890 1.620670 1.596893 2.476867 0.701683 2.431388 1.343232 0.706858 1.659209 1.324307 2.135009 1.597469 0.905924 1.608302 0.728973
+1 -0.058111 1 1 -2.212610 -1.866320 -1.580766 0.518171 0.407227 1.870064 -1.469851 -1.440899 -0.215692 -1.314352 1.369260 -2.147930 43.334463 72.321840 63.164912 62.670825 8.554159 2.421220 1.452830 2.210007 2.094272 0.929869 1.307337 0.415744 0.413839 2.141905 0.494054 0.321659 0.876289 0.782658 2.137593 2.270388
+1 0.004037 1 1 -1.531705 0.411013 -0.473546 0.337774 -1.466009 1.862258 -0.717786 -0.110293 -1.731270 1.549199 1.441572 2.101326 74.783269 32.401913 -71.045658 -64.369542 -58.895643 1.238951 0.790845 2.475106 0.349411 1.558423 1.657090 1.705474 0.396835 2.102961 0.707710 2.485139 2.483601 1.381325 1.925126 2.084606
+1 -0.031513 1 1 -2.343595 2.059171 0.698166 0.221740 -0.707707 -0.353562 -0.002129 1.921047 -2.259276 0.782030 0.724042 1.578200 -38.888837 -54.686720 -69.700825 38.240838 -36.242994 1.585110 2.445995 1.589087 1.784517 1.378369 1.750066 0.610855 1.394805 1.230419 1.403100 1.149760 0.269509 1.895214 1.110750 1.633603
+1 0.036542 1 1 -0.672015 1.034065 0.246371 -1.426030 -0.078567 -1.008185 1.176880 1.924862 0.604887 1.720550 2.068764 1.717342 -0.469615 57.186235 -70.945389 -29.149538 -16.279706 1.179647 0.827468 1.498400 0.857302 1.173321 2.499158 1.854777 0.982466 1.052771 1.424564 1.900446 1.295814 0.251546 1.488026 2.012019
+1 -0.029748 1 1 1.481582 0.686238 -2.318022 -1.682194 1.695744 -0.153389 -0.330977 -2.103479 -0.835080 -1.696189 2.103110 -0.660692 -59.390345 -73.526833 -65.475514 -46.970694 13.551641 2.311576 1.409532 1.252738 0.764283 1.554884 0.691964 1.093117 2.267544 1.614725 0.681409 1.436857 1.504984 1.266485 2.317000 0.313335
+1 -0.023714 1 1 2.202212 1.479375 1.286414 0.323052 0.858444 -1.468641 0.047737 1.209797 -0.897040 -1.612975 1.102084 -1.668411 -72.296284 66.360712 74.487380 9.397751 -2.005330 2.071299 1.818295 2.089284 0.343553 2.094423 1.213922 0.888533 1.829386 1.738154 0.649103 0.725240 2.365676 1.659775 1.840126 2.242212
+1 -0.053377 1 1 -1.838909 2.024439 1.295891 -0.612865 0.859043 -0.819808 0.518578 -2.173231 0.226316 0.792509 -2.228658 1.721814 -7.811179 -32.490217 -63.076963 65.489276 -21.737790 2.169560 1.799614 0.868736 2.101044 2.255562 0.482410 0.365254 2.328691 1.066703 1.575836 1.830560 1.226576 2.060965 1.388733 0.438379
+1 0.022565 1 1 1.236660 -1.809407 -1.650554 0.975679 -0.872776 0.923932 1.208311 -2.321570 -0.046704 2.019402 1.458132 -2.311035 -65.354979 28.874815 49.013375 -32.198328 42.705340 1.354839 2.275294 1.371121 1.433523 1.716599 0.632747 0.327808 0.721436 1.430651 0.692978 2.387453 0.913518 0.996948 1.451900 2.338207
+1 -0.046417 1 1 -1.678416 -0.777428 1.219519 2.275797 -1.146670 1.593168 0.577102 1.258090 0.225725 0.280651 -0.195594 1.891779 20.419799 -4.431183 -74.893429 66.130738 -40.689127 1.192740 0.374264 0.762474 0.399945 0.369215 1.402933 0.587955 1.260865 2.365392 1.387241 2.366725 1.294428 1.703961 1.978171 0.366376
+1 0.000512 1 1 -1.050053 -0.345189 -0.647252 -2.165390 0.072016 -0.705527 -1.414934 -2.077908 0.112930 -1.073621 -0.617475 -1.215518 -32.105350 -44.620336 66.008220 0.150859 -14.515217 0.516191 1.116177 0.593351 1.954678 1.514428 2.494792 0.472222 2.391437 0.374759 2.331632 0.997803 2.319424 0.555075 2.147663 0.517100
+1 -0.004743 1 1 -1.627356 -0.263187 1.546820 -0.851596 -1.247129 0.210002 -0.080064 2.104083 1.558413 0.783153 0.747178 -0.698125 14.432209 12.139460 27.908459 7.465009 64.408398 0.804171 1.448783 1.698686 1.071477 0.806677 0.820619 1.151753 2.267546 1.642019 0.419445 1.860418 1.297319 0.792226 0.937162 2.381434
+1 0.002095 1 1 1.198459 1.742044 0.454635 2.273854 -0.813665 0.078231 0.072966 1.117883 -0.033276 1.499894 2.144400 0.574124 -53.033526 -34.474200 42.125440 2.268142 20.655323 2.185135 0.322918 1.783354 2.075919 0.722010 2.079930 0.631198 1.295688 0.375519 1.596531 0.892949 1.789385 2.194719 1.638705 0.968032
+1 0.003260 1 1 0.328782 -1.788813 0.459427 -2.009274 -0.881502 0.348341 1.774337 1.287612 1.610391 -2.113893 -1.493580 0.305646 15.422926 13.118856 -11.388009 1.732537 18.741921 1.307101 0.946848 0.918023 2.454321 2.027128 1.949374 2.372157 0.337451 0.780672 2.496005 0.601924 2.029468 0.766044 1.893508 1.695912
+1 -0.035141 1 1 -1.990223 -1.139501 -0.449052 2.024386 0.403116 -1.250157 1.151049 1.330251 1.948713 0.913273 1.126266 -0.518484 -30.154806 38.167250 -73.029649 40.691986 60.203036 0.361410 0.720884 1.151255 0.645049 2.331251 1.330064 2.142964 0.295697 1.024396 1.524106 0.895190 1.211520 1.009492 0.789827 1.124244
+1 -0.039166 1 1 -1.420132 0.086787 -2.214801 -1.006982 -2.162790 1.355747 1.646461 0.918433 -1.690557 -2.201796 0.808267 -1.268849 -63.419365 10.728263 9.912498 -50.640878 -21.228722 2.258089 2.453668 2.303064 2.346679 1.889823 0.500319 2.105277 1.395568 0.564469 0.283258 1.209447 2.177056 1.784374 1.230313 1.868130
+1 0.013465 1 1 -0.891927 -0.514848 -1.099851 1.509036 0.288237 0.062514 -0.182381 -2.220998 -1.476856 -1.358240 -1.134977 0.185531 -43.761776 -54.171199 44.659314 -10.910590 -74.285902 0.277655 1.555472 1.567277 1.974196 1.063090 1.601186 0.381575 2.138166 0.651723 2.016230 1.021884 2.059433 0.390880 1.025119 2.416285
+1 0.036695 1 1 0.449021 2.167983 1.091594 1.085021 -0.994881 -1.415298 1.234378 2.248323 -1.090960 0.144686 0.147023 1.725955 -42.597275 17.600987 19.783198 -53.785464 -72.301186 1.134535 0.879994 2.307229 0.349950 1.614496 1.340004 0.441609 0.878099 1.960208 2.223012 2.404348 1.381094 0.296160 2.056628 0.504893
+1 0.041392 1 1 1.662957 0.138551 0.702254 -1.744474 1.118723 -0.057784 -0.421244 -1.839621 -0.527485 -1.443522 -1.896188 0.652448 -0.996871 45.581634 40.523471 -72.019516 68.001631 2.176082 1.151657 0.644335 1.593030 0.547707 2.061769 1.407170 2.054844 2.004386 2.222278 1.317568 1.366035 1.448533 1.996501 2.447271
+1 0.006874 1 1 0.305174 1.976333 -1.395608 2.290653 -1.205788 2.311335 -2.329235 -1.630976 0.155012 -0.656473 -1.639927 0.513251 -69.030293 57.872124 56.789382 9.136674 -39.911301 1.536567 1.088335 0.641990 0.425194 1.736021 0.810012 0.619094 0.370585 1.920899 0.798600 2.328459 1.657414 0.404699 1.522012 1.703717
+1 0.029344 1 1 -0.449676 0.968166 0.090574 0.170685 -1.147374 -0.825026 2.342826 -0.850381 0.327218 0.192650 0.463393 -1.335694 25.715931 57.659244 -71.081501 -66.785924 -21.024161 2.078899 1.299690 2.383654 2.317209 1.576749 1.413357 0.288083 1.309784 1.035187 0.638538 0.913913 0.879150 1.625484 1.511328 2.135032
+1 -0.001850 1 1 0.009739 -1.255404 -2.206144 -1.576690 -1.666046 -0.216153 0.360717 -2.270339 -1.371055 0.254354 0.792071 -0.164016 4.003437 -64.229757 40.473188 -17.137087 -23.013659 2.266555 0.735811 2.278345 0.896235 0.768832 1.516906 1.383992 1.752970 2.168497 1.923766 1.740461 1.181365 0.451804 1.225922 2.314625
+1 0.016676 1 1 2.154556 1.631829 0.041728 -0.816087 1.785504 0.468681 -1.988199 -0.104667 -1.415251 2.011052 -2.208276 0.287320 -38.425271 -63.532209 64.164591 64.288654 49.411866 2.353522 2.138033 0.673544 2.010639 1.553247 2.428899 2.259238 1.516332 0.743482 0.702842 1.666025 1.129238 1.856568 1.834085 1.964118
+1 -0.009288 1 1 2.098901 -0.717322 -1.734725 0.029892 -1.837832 1.260389 1.175247 -1.953650 0.939588 0.437520 2.073454 0.421979 1.863710 -26.627382 73.590588 -62.980269 40.619200 1.928418 1.178708 0.788519 1.638449 1.157884 1.812578 0.493334 1.716442 2.485536 2.407502 0.388244 1.713403 0.920678 2.084871 0.424918
+1 -0.017536 1 1 1.275180 0.002990 -1.581945 -0.458004 -2.349201 2.093410 1.246526 -0.917402 0.165249 1.744286 0.445328 1.361773 -23.840764 -41.719789 65.507128 -21.692401 65.808071 0.418729 1.080164 0.558386 1.543747 0.253439 1.802241 2.265434 2.155273 2.427406 1.905834 1.852045 2.314921 1.370717 1.392185 2.202285
+1 0.011719 1 1 2.187751 -1.233525 -2.052245 -2.114253 1.881625 -0.370060 0.762558 -1.383936 0.537812 0.641907 1.868691 -0.988118 -26.960899 18.176658 -54.910850 63.348690 1.433152 0.429755 1.885459 1.404568 1.070697 1.201584 0.523783 0.468548 1.388630 0.957893 2.055342 1.376743 1.415366 0.306053 1.827787 1.860345
+1 0.059538 1 1 1.065133 -0.682943 1.148454 0.128948 -0.464741 2.245651 1.130254 0.546402 -1.067826 -2.179991 -0.279762 1.004632 11.463566 68.147921 -37.889402 -57.171865 12.471449 2.239561 1.556584 2.250284 1.772060 1.265365 1.483662 0.654752 1.161299 0.697971 0.793096 2.071044 2.039615 0.314737 1.536106 2.337975
+1 0.030991 1 1 1.972925 -2.127877 -0.911472 0.863532 -0.776904 0.603079 -0.396044 2.294837 -1.572108 -0.059798 -1.284767 -0.906287 -48.357729 -48.346149 -3.724303 -44.354542 33.214877 0.511570 2.201139 1.550410 1.995032 0.261085 2.052195 2.485022 0.516075 1.425999 1.263942 2.317391 2.385436 0.781528 1.137794 1.651704
+1 0.020314 1 1 -0.917452 -0.682901 1.864386 2.068301 -1.357670 -0.975923 1.495995 -2.112681 0.016447 -1.605627 2.085057 2.222766 -57.187199 54.740109 67.005408 -40.100431 -17.939629 1.204906 2.348232 0.983963 1.467438 2.483773 2.018568 2.076509 1.644129 2.122751 0.324373 1.489263 0.290149 2.283253 2.390015 1.239569
+1 -0.025861 1 1 0.592554 1.769027 1.581007 -1.168941 -0.437703 -0.442574 -2.197667 -0.489665 -1.964862 0.982102 -1.305458 0.048946 -64.447837 -24.803370 -20.231447 20.074674 45.054066 1.730404 0.898676 1.303574 2.423893 1.367400 1.897013 2.098895 2.123011 2.452475 0.254101 1.679806 1.001652 1.763693 2.384237 0.878247
+1 -0.010615 1 1 2.136341 1.782486 1.585798 -0.759779 0.964280 0.746919 -0.328167 -2.007651 -1.889273 -0.932000 -0.142788 -1.239958 -57.135628 21.494851 63.966688 38.122025 66.870629 0.545039 2.227744 0.941311 2.362394 0.509077 0.801163 0.397677 0.509736 0.625020 0.955824 1.026631 0.845321 2.313070 1.770913 2.236916
+1 -0.074024 1 1 -2.233033 -1.124523 1.535806 -2.178328 -0.606195 -0.138587 -1.308539 0.096554 1.728071 1.238149 -0.335640 -0.375504 -38.176511 67.386643 67.315211 66.754471 -57.600907 1.398359 2.478667 1.710712 0.679384 1.155593 1.542712 0.867078 1.224734 0.358322 0.571379 1.665439 0.274335 1.993156 2.468318 1.022539
+1 0.069455 1 1 1.588684 0.610468 1.268524 1.237359 0.514004 1.050523 -1.183758 0.294122 0.013849 1.844717 1.355165 1.283934 33.424674 18.490468 -30.696735 -70.031376 32.656617 1.521546 0.628941 1.606948 0.475992 0.500108 0.819993 1.869366 0.934156 1.368241 0.273183 0.637684 2.299083 0.694165 2.081816 0.827853
+1 0.061232 1 1 1.559681 -1.458979 2.218704 0.620457 -0.493500 -0.455240 1.700303 1.060999 0.537207 -0.102669 -0.826860 -0.203578 -11.079785 -67.954519 -11.597176 -63.739095 37.027299 0.892212 0.657719 1.527560 0.455654 0.684736 1.106766 2.169685 1.652309 2.363201 0.571748 1.119206 1.990551 1.441927 1.211640 0.792454
+1 0.011835 1 1 -1.858992 -0.944769 2.017759 2.131283 1.597161 1.715491 1.867138 1.188703 -1.994443 -1.387764 2.177956 -0.938444 -2.105759 8.511555 -46.293143 1.144313 32.475012 0.737938 2.018824 1.876250 1.886864 0.264120 1.308326 1.280976 0.605965 2.445522 0.395113 2.410916 1.513899 0.347273 1.613358 2.463523
+1 -0.038952 1 1 -1.729033 1.447469 2.255653 -0.411370 -0.817169 -2.249948 2.039537 0.578886 -1.747894 0.172692 -0.399584 -0.653679 -57.283351 -61.288139 -19.756223 57.165862 36.637651 1.660074 2.370178 0.834994 1.992351 2.448913 1.128273 1.391825 0.660770 1.057147 0.714810 0.313484 0.726562 2.071324 2.234545 0.492315
+1 0.056974 1 1 -0.263612 -0.873077 0.570435 2.303923 0.336943 -1.294642 -1.949356 -2.292532 -2.096122 0.304046 1.869809 -1.036937 -43.952306 43.600164 37.954223 -53.374055 -57.748555 2.425421 2.308129 1.965958 2.112156 2.260299 1.344072 1.308973 0.916606 1.147422 1.465518 1.715079 2.082911 1.235010 2.054086 0.527700
+1 -0.037935 1 1 1.281580 -0.820999 -0.647054 1.151125 -2.116423 -1.607485 -0.881900 -1.635772 -0.335545 1.221845 -1.043171 2.221203 6.694772 19.027405 -6.403048 -66.036768 -29.959340 1.725636 1.768420 0.837168 0.288316 0.732315 2.018262 1.431292 2.472794 2.005129 1.210656 2.252468 2.477654 0.426378 1.388703 2.186971
+1 0.007617 1 1 1.248840 0.280182 1.338774 -0.883859 -1.570707 -0.069344 -1.509676 -1.622612 -0.648366 -2.050481 -0.733838 -1.293410 -2.748354 8.414292 -30.994325 28.373952 31.003079 0.906351 2.033717 2.427357 1.081647 0.739113 1.524046 2.133974 2.207180 1.829332 0.826219 0.767375 1.776394 2.108316 0.721696 1.301515
+1 0.007260 1 1 -1.853835 0.902446 -1.767468 1.066161 -2.238863 -0.140152 0.664294 1.137988 -1.423138 1.400110 -2.018240 -0.784785 2.785563 16.950570 38.225237 1.555244 38.990744 0.886504 1.480378 1.717672 0.668928 0.922096 1.160648 1.005673 1.852284 1.840713 0.863369 1.891560 0.441007 2.004618 1.614521 1.749403
+1 0.029404 1 1 -0.685319 -1.078512 2.012799 -1.135964 -2.259469 2.248642 -0.435777 -1.049382 1.501277 1.833868 -1.912209 -0.002829 -13.313608 38.189073 -6.254289 34.172416 -14.197350 1.902135 0.427671 0.615096 0.663746 1.581769 0.290984 0.562114 1.203715 0.346867 1.547033 1.481936 0.892587 2.454674 1.214220 1.396997
+1 0.051335 1 1 0.091349 -0.929344 2.091658 0.080500 0.510102 1.454235 -1.842118 -0.078220 0.111660 1.135428 -2.039030 -1.487828 -63.339788 -1.821929 -21.164158 -56.009904 41.545703 1.504411 0.640820 1.011171 2.005258 1.119613 2.089207 1.306117 2.411158 1.077322 2.306494 1.502023 1.006743 1.821497 1.899032 2.276740
+1 -0.017104 1 1 -1.928846 -1.595421 -0.750983 -1.986833 -0.722232 0.565354 1.721944 1.932606 -1.189985 -0.698427 0.094888 1.999404 -1.817024 61.279207 19.627286 25.789971 -47.950391 2.091579 0.666422 1.560349 0.292674 1.973766 0.581624 0.612048 1.197835 0.514058 1.267137 2.019792 2.396321 1.466572 1.422916 1.206604
+1 -0.035625 1 1 -1.869359 -0.824565 0.668421 -0.190518 -2.330391 -2.207731 0.010406 0.535926 1.929057 0.420279 -0.242102 -2.223914 43.112267 -62.134734 1.522928 -54.145587 25.127624 2.424613 2.219906 1.959922 1.906807 2.450090 0.655612 2.125339 1.071727 0.517632 0.582917 2.078544 2.095077 0.955807 0.752771 1.575039
+1 0.004875 1 1 1.179836 -0.235431 1.514302 -0.745800 0.288384 -2.169966 -1.443357 0.877255 -1.036150 -2.292185 -0.971703 1.726666 37.602265 31.272530 -2.588293 -1.431716 -62.844769 2.394541 0.797861 1.148332 1.008271 0.513493 0.777099 0.948063 1.100675 1.044143 0.405121 1.873380 0.890203 0.633621 1.515469 1.991529
+1 0.067429 1 1 1.057360 0.633879 -1.111075 1.366814 -0.855235 -1.147027 0.299650 -1.320332 -0.175882 -1.373581 0.216828 1.559032 56.081387 -40.132671 40.193087 -74.793286 -50.765899 1.037980 0.331545 0.531965 0.732278 1.395156 0.385867 2.260561 1.251564 1.281091 0.293149 0.961728 1.263364 1.606232 1.943695 1.429812
+1 -0.014028 1 1 -0.078375 2.219704 -1.413549 2.344308 0.495778 1.033261 0.871374 -0.926778 -1.910313 -1.124974 -1.325740 -1.533902 37.677713 -50.670165 -63.463521 18.610016 28.534956 1.930205 1.960629 0.290094 1.356668 1.519548 0.797559 0.581352 0.537320 0.743376 1.174088 1.902149 0.668426 1.480535 2.094667 0.827127
+1 0.017787 1 1 -0.548254 -1.790185 0.972767 2.014698 -2.197624 0.235266 0.423206 1.821912 -0.235778 0.392096 2.036290 -2.150638 -55.500232 57.597643 -56.411542 41.218866 65.476496 2.326971 1.410053 1.011672 1.417763 2.351555 0.582995 1.143046 2.168898 1.914513 1.461629 1.594700 1.618653 1.455147 0.655860 1.789453
+1 -0.017978 1 1 2.267624 -1.839555 0.582630 -0.089073 1.497665 -2.321206 1.353400 -0.115991 1.475470 1.639193 1.296660 -1.827445 46.990314 16.208905 23.073001 37.926166 -74.933152 1.352764 1.146880 1.364048 1.797225 1.208104 2.103655 1.130478 2.439639 0.508877 1.938309 0.912023 0.625881 1.939709 1.947334 1.846052
+1 -0.024416 1 1 -1.646263 -2.313016 2.347565 -1.309949 -0.026634 0.046821 -0.041479 0.292889 -1.866831 -0.743262 0.539303 2.141342 32.613465 34.509507 -48.719166 26.981777 32.720956 1.991554 0.294303 2.347400 0.504039 1.626643 0.737653 1.727906 1.670585 1.272178 1.241875 0.444368 2.250845 2.208865 0.899943 2.340808
+1 0.012302 1 1 1.430762 -0.495737 -0.354395 0.146815 -1.772640 -1.044457 -0.540672 -1.587729 1.299464 -1.830016 0.691512 1.485466 -0.198962 -43.960858 49.855196 16.283845 -67.425481 1.824114 0.885555 1.278596 1.115385 0.784078 1.251370 0.282874 1.507247 1.056831 2.155861 1.055853 1.467797 1.767522 1.490760 0.694162
+1 -0.015440 1 1 -1.150266 -2.304478 -0.239343 1.734678 -0.812025 -0.621437 -1.835620 0.741057 0.093180 1.569927 1.093177 -0.584577 10.736199 -6.700342 37.343783 36.959045 20.666018 0.381529 1.359569 0.779292 1.815258 0.536823 1.376778 2.009927 0.850280 2.408508 1.552217 0.867325 0.873950 1.984778 1.155586 1.431404
+1 0.008975 1 1 1.697866 -2.194428 2.125307 0.121392 -0.231190 2.106184 -0.839559 -1.579989 -0.554270 0.772953 -1.028339 1.741089 -46.023008 41.302906 -22.053251 1.010135 27.344277 1.003857 0.568550 1.366354 2.304200 1.186074 0.853105 0.386751 1.375178 2.123931 2.152832 1.894724 1.876170 0.531737 1.410525 2.191294
+1 0.035653 1 1 -1.114654 -2.239768 -1.218235 0.447353 -2.308073 0.600479 -1.693864 -1.223160 -2.214825 -1.410127 -1.406745 -1.103068 -23.280334 -72.566207 29.758030 43.209686 -74.805066 2.143892 2.385607 1.398204 2.107871 2.230440 1.264154 1.382541 2.109838 1.551750 2.011714 1.627746 1.282197 0.892107 1.142401 0.331182
+1 0.029408 1 1 -1.732764 0.001966 0.056845 -1.217356 1.098172 -1.456259 0.806029 -1.181171 1.359776 -1.323688 -0.036065 1.750857 -70.712353 -12.523262 -28.465787 -74.485580 20.855080 0.794881 0.564295 1.862979 1.587059 1.457468 1.420037 2.309524 0.665318 1.001453 0.671054 0.660690 1.972940 2.461723 0.429479 1.751334
+1 0.021037 1 1 -0.996276 -1.298538 -1.460744 0.818964 -0.567242 -0.481227 -1.524691 0.488823 1.958021 1.847961 -0.669450 1.747212 -70.459726 33.390456 43.400246 -22.061062 19.727878 2.371716 1.931811 1.950943 1.754720 2.333792 1.293205 1.387654 0.301772 1.888493 0.652828 0.322520 1.841421 1.505936 1.519070 1.763954
+1 -0.003899 1 1 -2.129181 0.739016 -1.216822 0.634972 -1.585720 2.080373 -1.088781 -0.936490 -0.212468 1.048539 -1.543303 -1.298973 20.882634 -25.570333 -10.585629 -12.661549 47.338508 1.649503 2.449954 0.631684 0.465607 1.462179 1.847752 2.160388 0.643834 2.172970 0.598915 0.969945 2.108202 1.043527 1.316842 0.407327
+1 -0.002617 1 1 0.713207 -1.455201 -0.266676 -0.546650 1.616768 1.381874 -2.214116 1.093594 1.710182 2.177572 2.040069 0.104253 -26.265222 10.413101 -37.009435 32.423781 -3.514270 1.909918 0.747671 1.363716 0.727358 1.960807 1.035758 1.233915 1.668501 2.244630 1.249364 0.309755 1.049424 1.416873 0.880577 0.862087
+1 -0.012692 1 1 0.638758 0.775941 2.065278 -0.321396 -1.306510 1.213117 -1.652103 -1.501801 -1.209610 -0.665500 2.161187 -0.026965 -25.917767 0.098047 -2.120582 59.386482 8.603578 1.379963 1.537010 1.783172 1.278730 1.115735 2.153338 1.410984 0.904569 1.335281 2.072252 2.094301 1.413069 2.200377 2.238337 1.222984
+1 0.047557 1 1 -0.054518 -2.075464 -1.216092 -1.226389 0.076733 -1.541132 2.192977 1.773005 -2.261559 0.108450 -0.973058 -2.200535 -49.555280 74.403542 -49.669206 -40.343524 -53.613132 0.986258 1.795995 0.794787 1.233488 1.235725 0.584957 0.375234 1.312780 1.893013 2.370273 2.431333 0.406346 2.199777 1.151694 1.275665
+1 0.058773 1 1 -0.910123 -0.015187 -0.771157 -1.765543 0.438700 -1.655568 1.528452 1.451732 -1.494644 1.268225 0.925205 -0.964005 -26.902801 -55.383599 67.843698 -50.959355 26.112291 0.914072 1.303039 2.425225 1.264162 1.525916 2.066348 1.863450 0.502806 1.157152 0.755011 0.975954 1.854582 2.201689 1.786786 1.262625
+1 0.024645 1 1 0.154591 1.679833 1.039805 -2.254432 2.088024 0.261777 -1.687305 0.625425 -1.818005 -0.085283 -0.788447 -0.195912 40.585339 67.784469 3.573433 58.687209 -44.079828 1.379841 1.735294 2.092975 1.632194 1.784388 1.457790 2.329711 2.458488 2.314579 2.382452 2.379185 1.463571 0.490920 1.641250 0.997278
+1 0.000537 1 1 -1.887335 -1.345478 1.299324 0.532692 -0.592532 -1.413016 1.879153 0.500607 2.085736 -0.489806 0.374094 1.063070 74.710297 5.969544 -19.867301 -9.724913 53.383773 2.441144 1.058783 1.220497 1.140113 2.380856 0.300155 1.696798 0.839374 1.364850 1.791220 1.532056 1.759827 0.407761 1.243751 0.478647
+1 0.026474 1 1 -0.183932 -0.011758 0.305469 2.229809 -1.221144 -1.318036 0.705854 2.205064 2.282320 0.109756 2.127936 1.906408 46.749536 19.446153 -18.505273 -68.128979 56.248494 2.401503 0.803852 0.591496 2.280791 1.505341 0.514998 1.323184 1.256926 1.404466 1.613190 1.891963 0.466021 1.663991 0.695759 1.865854
+1 -0.024474 1 1 1.304756 2.286924 2.083117 -2.111440 2.031336 -0.591533 1.241062 1.496504 1.715955 0.238539 -1.120556 2.236566 -24.060841 9.443791 21.800321 -52.005907 -13.273041 0.925036 1.081411 1.270727 1.611070 2.249638 2.167176 2.220108 0.859174 1.141829 1.965396 1.658024 1.651058 1.576742 1.308687 0.601704
+1 -0.000609 1 1 -1.054815 -0.273350 0.381571 -0.505717 1.571971 -2.249131 1.646552 -2.256650 -2.210696 2.023544 0.400405 0.318081 67.945192 4.838913 27.611482 -33.828204 -50.631497 1.171555 2.077101 0.342239 0.252566 0.632823 1.609926 1.024774 1.133434 0.372253 0.699477 1.362162 1.607737 2.489534 2.095235 1.360748
+1 0.056175 1 1 -0.087827 -1.132121 1.065005 1.882461 -0.457523 1.032661 0.200744 -0.166898 -1.179160 2.170818 1.615277 -0.111108 -40.741745 3.487580 -34.238969 -54.350867 24.984262 2.282271 1.636198 1.586511 1.236606 1.893225 1.425527 2.326201 1.963638 1.360605 2.443565 1.239402 1.621415 0.621705 1.503055 0.344978
+1 -0.067395 1 1 0.907253 -1.096341 -0.769694 -0.744932 0.748639 0.304082 -2.240130 2.119277 -2.262311 1.604911 0.027574 1.613907 13.322324 -41.699397 -41.773031 70.665503 -24.890880 1.509784 0.936661 0.713681 1.582175 0.365902 1.972193 1.152291 2.295885 0.937897 1.229220 1.500277 0.910669 0.370910 0.642012 0.802087
+1 0.027683 1 1 0.096339 -1.885003 0.149808 1.403259 -0.935449 -1.553629 -0.501415 -1.527304 -1.017041 -1.581950 -0.536561 1.536217 0.734870 50.961008 1.665842 -52.199990 24.767472 1.628473 2.247174 1.251685 1.065497 1.554644 1.148193 0.925281 0.703843 0.491987 1.574963 0.650189 0.983933 0.960818 1.713902 0.297049
+1 0.016210 1 1 0.114278 -1.991212 1.080827 -0.794451 -2.140068 1.543594 1.484552 -1.240599 1.579984 0.477558 1.118603 -2.077456 -54.261757 22.644936 43.430959 44.132992 -6.801798 1.107657 1.383390 0.641728 0.515025 1.777980 1.766448 1.446443 0.616344 1.395704 0.598558 1.711923 0.783604 2.289470 1.121969 1.178787
+1 0.016052 1 1 0.938883 -1.987202 -2.202993 -0.471364 -0.693245 -2.337304 -0.590607 -2.034134 0.692944 2.000108 2.344551 -0.125524 46.723536 32.472956 72.977325 -20.105489 37.040252 1.907827 1.602124 0.393089 2.142401 2.076684 2.328935 0.662158 1.886340 0.472908 0.410123 0.429055 1.377127 1.130315 1.951335 1.587370
+1 0.001277 1 1 -1.209732 1.986280 0.845021 -0.877842 0.598681 1.081799 1.405255 -0.381172 -2.224736 1.665447 -0.421652 0.722581 18.850975 28.342949 -40.054672 1.127938 57.257607 0.303910 1.817867 1.646013 2.291706 0.453556 1.417120 0.541257 1.658517 0.952079 1.085776 0.393561 1.082166 0.465840 0.866643 0.675843
+1 0.067200 1 1 -0.526621 -1.060237 -1.869585 0.099271 0.254912 0.746695 0.609425 -2.121475 -1.702342 -2.344079 -1.365731 0.212966 -66.662754 -50.900577 -35.998380 -74.766841 -56.299345 1.028570 1.925929 2.088621 0.445825 1.983979 1.227291 0.584299 0.565377 2.042852 0.715137 1.310395 2.311482 2.075308 1.709240 0.690458
+1 -0.012359 1 1 1.678932 0.022206 0.930843 -0.449826 -1.549471 -1.302266 1.859066 2.186143 0.010505 2.201947 1.724086 0.228105 -67.344953 33.372976 49.610866 -40.167496 54.901192 2.490033 1.486838 2.288143 1.310401 2.404477 1.290192 0.250579 0.985988 1.745375 0.509600 0.596813 1.627806 2.289874 1.158482 0.600055
+1 0.007959 1 1 -0.917889 1.399223 1.912551 1.035340 -1.892125 -1.739629 -2.289774 1.847202 0.698113 -0.666610 2.352034 -1.604210 74.073093 -53.518320 67.596855 0.342172 50.881678 1.650349 0.909152 1.871983 2.169641 0.908456 1.419896 2.191703 0.446742 1.644855 0.825542 0.629615 1.684872 0.645355 0.732579 1.949527
+1 -0.021872 1 1 1.880624 1.647018 0.866012 -1.500121 -1.247524 -1.713921 0.965800 -1.977178 1.341227 -2.062813 -0.652537 -1.457748 -21.311076 24.743985 72.158054 10.416792 25.022368 0.638989 1.739042 2.074103 1.694527 0.921379 0.361780 2.436996 1.085448 1.622314 2.230494 2.157105 1.719363 2.087975 0.853214 2.222858
+1 0.001669 1 1 -2.215793 1.176576 1.529505 0.308510 1.494889 -1.855338 -0.794413 -1.497234 0.147065 -2.281750 0.040226 2.206487 -66.006202 33.755321 25.674790 -33.808697 -22.778627 0.769188 0.748566 0.656434 2.439401 1.015063 2.159060 0.815995 2.181598 1.619732 1.581893 2.372547 2.404551 0.290049 0.605155 2.333633
+1 -0.002296 1 1 1.741224 0.812399 2.194364 1.519565 -1.823873 0.249800 -0.353498 1.086079 -2.065743 1.937751 0.455897 -0.076560 -8.301548 -24.121933 32.663668 -21.738232 45.528982 2.209026 1.358927 1.238875 1.779647 0.522275 2.129654 1.600951 0.931891 1.534735 1.786305 2.170715 0.959975 1.045364 0.678444 1.111361
+1 -0.054958 1 1 -0.352142 0.301665 -0.447773 -0.040644 0.199193 2.032347 2.267861 2.134841 0.142792 1.307377 -0.791771 0.486460 -2.100514 -53.345526 -28.261738 54.964471 -62.144226 1.254806 1.779487 2.334968 0.808375 2.362791 0.435355 1.512685 2.451072 1.410785 2.067319 2.425501 1.401210 0.882897 1.602597 1.594776
+1 -0.008091 1 1 -0.794278 0.759877 0.677842 -2.066308 1.868980 -0.833335 -0.649547 1.675480 -1.452181 -1.344700 0.251519 0.272813 0.533348 -36.027076 42.934719 -46.186110 0.045462 1.586183 2.471839 1.704841 1.007999 0.441230 1.257043 1.123771 2.210479 1.014456 0.961479 1.570529 0.386799 2.182126 1.491999 1.284083
+1 -0.009436 1 1 -0.648560 -0.588074 -1.871545 0.136343 1.288379 0.350448 -0.514062 -2.023810 -0.146216 -2.294308 1.037102 -0.560098 56.924675 33.017826 -69.406397 36.687027 -51.131846 1.030865 2.239518 0.833615 1.315566 1.474817 0.500778 0.827339 1.580955 2.367831 1.890885 0.358311 0.380089 1.901705 2.207951 1.281294
+1 -0.037055 1 1 2.336627 -1.356508 -0.289705 -1.167251 -0.305191 -2.263267 -0.319663 -0.450026 -0.198628 -1.977260 -0.038598 1.597451 59.941214 31.990575 65.590929 36.738271 60.124089 0.708534 0.588364 1.392028 1.821785 2.243464 1.904916 2.167044 2.251438 0.921996 1.733658 1.594772 0.588575 0.427683 0.813148 1.576129
+1 -0.073151 1 1 1.422801 2.355631 2.317519 -2.067554 -0.224539 0.798274 0.427490 -1.566473 0.408576 0.980060 2.067534 -0.111372 -32.336027 -21.598617 -7.947855 70.394881 -73.236637 1.552505 1.203534 1.788796 1.287463 1.636144 0.669364 1.500712 1.461234 1.707180 2.065142 1.848209 0.854926 1.743705 1.701315 2.498692
+1 -0.000009 1 1 -2.317227 2.259033 -0.143025 -0.507682 1.527167 -1.281118 -0.841125 0.374257 -0.903205 -1.553976 -1.618789 2.345470 37.634658 -24.308006 55.338080 67.111880 -50.637884 1.811376 0.538529 0.803362 1.356387 1.300124 0.689589 1.671285 1.784031 2.208133 2.086125 1.257619 1.802035 1.048897 1.557002 0.284243
+1 -0.004698 1 1 1.741012 1.972125 -1.443865 1.757652 -1.116581 -1.646680 0.115382 -2.277581 -0.559883 0.692825 -0.002525 -0.020579 -59.344833 -58.600980 -6.675766 0.404682 51.495444 1.133820 2.369444 1.997562 2.276771 1.447143 1.135523 1.731331 0.736896 0.265220 1.796908 0.384222 1.621924 2.426759 2.281385 2.495202
+1 -0.004415 1 1 -2.123105 -0.809418 0.780350 0.763578 1.626006 1.135894 1.083263 -2.263436 1.543492 -0.222997 -1.561292 -2.052383 8.832454 -52.942514 -4.832633 -72.064674 59.015993 0.351803 1.257619 1.806930 2.325783 1.688131 1.419901 2.269483 0.452165 0.539448 0.505215 1.153612 2.006006 2.436512 1.959851 0.717032
+1 0.026142 1 1 -0.658934 -0.595662 -2.176788 1.714320 1.023734 0.958292 -0.926826 1.990586 -2.189750 0.635065 -0.020531 -1.066602 -14.516682 68.132894 9.555228 -55.287687 29.845279 1.519154 0.923616 1.963019 2.216715 2.335759 0.596306 2.112550 2.131196 0.511320 0.260207 0.794660 1.345557 1.525254 2.190192 2.054034
+1 0.006482 1 1 -1.944702 0.517729 -2.304103 1.352467 -1.656929 2.204583 -1.084899 -1.670876 -1.287364 -2.147900 1.859801 0.394967 -49.286467 -57.646753 -18.978883 71.914639 -30.669820 0.360021 2.120436 1.919409 0.513256 1.299662 1.911636 0.358784 1.575260 1.150588 0.680036 0.857557 0.965577 0.708883 1.948556 2.132230
+1 -0.009079 1 1 2.004929 -1.452892 0.848700 -0.304904 -2.162441 -2.194641 -1.468921 0.050030 2.046427 -1.421542 -0.043740 -0.013136 22.396053 60.456511 -7.417683 -19.005490 74.732726 0.368829 1.656639 0.883831 1.551967 1.156088 0.876293 0.856195 0.566650 0.937995 0.637913 1.658714 2.008037 0.574595 1.715624 2.245680
+1 0.001699 1 1 -1.372498 -0.429497 0.819273 -0.086986 -1.127382 0.602191 -1.182547 1.784565 -1.174381 -2.334148 0.605926 0.319162 46.333055 69.650274 12.154734 -15.386238 3.492994 2.226350 2.263065 0.579165 2.032579 1.307938 1.506525 2.411763 2.257576 0.577297 2.136639 1.992956 1.364727 1.961857 0.684622 1.437490
+1 0.005780 1 1 -1.244089 -0.531225 1.675103 1.645126 2.045286 -1.761153 -1.187478 -0.977967 0.127315 0.361208 1.257940 -2.297592 -73.924970 -6.966055 71.508306 40.092410 33.127288 0.929856 1.093014 0.536300 1.600992 1.622705 2.046450 0.429081 1.821235 1.992103 0.525343 1.939106 0.802757 2.440256 1.889260 2.294777
+1 0.048628 1 1 -1.553297 0.375975 -0.293674 -1.914997 0.255621 -1.475250 2.060034 1.074738 0.531665 1.000268 -2.302532 -0.516068 62.438166 -1.742149 -30.302836 -49.764709 4.536621 2.079915 0.385724 2.112963 2.314588 0.285143 1.398547 1.134506 0.390331 0.796861 2.336263 2.325005 2.108220 1.345897 0.496402 1.530049
+1 0.022535 1 1 -2.060433 1.652322 0.465109 -0.759615 -0.989344 2.111763 -1.321016 -2.256616 -1.630596 1.825010 0.005096 0.826665 52.326780 6.195176 22.326747 -54.358461 47.343614 0.686816 2.311499 2.367500 0.823907 2.398458 1.380556 2.497042 2.277924 0.562987 2.375211 2.175658 0.790745 0.797517 2.125870 0.990906
+1 -0.009450 1 1 1.724412 1.008905 1.486056 0.478758 -2.280851 1.016113 0.108651 -2.314312 -0.583888 -2.216180 -0.612694 -0.985008 -12.835698 -29.584677 20.330407 -6.842854 42.146082 2.113002 0.724762 1.076417 0.596488 0.669759 1.388725 0.301625 1.667252 1.511035 1.708293 0.528402 1.605394 1.349574 1.538266 0.386247
+1 0.006094 1 1 -1.779962 -1.581060 0.289258 -1.632556 1.865033 -1.209138 -2.168814 -0.930959 -1.491917 -0.019792 1.940285 0.634751 -18.929474 2.335462 -47.889995 12.848888 -48.731457 0.931048 0.872430 1.187548 0.864871 2.380626 0.931314 0.845834 1.938032 0.760536 1.581681 1.061641 2.006515 1.996813 0.934268 1.000625
+1 0.056887 1 1 1.485239 0.884466 2.347923 -0.010973 -0.638110 0.677744 0.993374 -0.352262 -1.708418 -0.789560 -0.046630 -1.447741 -67.304388 -34.847736 64.103161 -68.174587 39.708453 1.824474 2.439256 0.823494 2.209906 0.390446 0.475892 1.072978 1.291412 0.504761 0.265424 0.728209 0.516487 1.591025 0.601460 0.988941
+1 0.018253 1 1 1.834277 0.251698 -1.442708 -2.350801 -1.238932 1.313113 1.377291 0.875872 -0.729085 -1.523763 1.950653 0.528857 29.520585 -47.529567 70.565525 -55.217838 3.794799 1.812676 2.147995 1.600033 1.257261 0.291706 1.453537 0.588276 2.152244 1.011892 0.620161 0.288378 1.775950 1.385004 0.767599 1.029911
+1 -0.051411 1 1 1.852493 0.095176 2.128481 1.639673 -0.066027 -2.310878 0.591357 0.516466 0.030083 1.380985 1.693920 2.165320 -39.849532 -1.080132 -3.781407 45.888796 -47.013576 2.017466 1.554258 1.415318 1.742695 0.480269 0.388335 0.993443 1.045184 2.164149 0.858409 1.777332 2.120358 0.604732 1.979835 1.339837
+1 -0.024054 1 1 2.166622 1.782699 0.453807 -2.227816 1.740310 -0.408525 -0.123612 0.620960 -1.458833 -0.052133 0.305259 -1.304339 0.116779 12.704905 -68.663224 -72.804474 -74.799852 1.208270 0.387708 1.706125 2.342989 0.609018 2.012564 2.411238 2.427835 2.368563 0.689717 1.579520 0.736409 1.082005 2.260430 1.298460
+1 -0.001724 1 1 -1.510490 -1.161656 -0.526490 1.148375 -1.207763 2.100715 1.494978 -0.355946 -2.355265 -0.864012 2.131515 0.790901 -30.861542 10.065494 -29.246560 3.062214 16.627461 1.491030 0.746685 0.535517 1.939162 1.742673 2.352461 2.316035 2.091021 0.283378 0.991722 1.377388 1.007290 2.024732 2.169861 2.348650
+1 -0.014299 1 1 1.052893 0.944811 -1.320268 0.897131 -1.560153 -1.756513 1.403231 -1.395427 0.617398 -0.075313 1.844668 0.523980 -29.200818 21.852727 -71.213005 -26.981169 -22.508718 1.314689 2.479767 2.196969 1.215907 0.506771 0.304859 2.021481 1.528142 1.238201 1.698412 0.962428 1.776133 2.212411 1.991274 2.348651
+1 0.037365 1 1 -1.971068 0.349842 -1.259043 -2.113012 -0.830332 -2.008160 -1.011126 -1.124610 0.069532 -0.047589 1.275016 1.966462 74.289226 -20.982205 2.085186 -54.270766 21.235213 2.128416 1.045139 1.403215 0.833881 1.288671 1.693981 0.744540 0.485026 1.582936 1.903323 2.400209 1.565468 0.815946 1.349857 1.789950
+1 0.000971 1 1 -1.297004 0.756172 -0.326123 -0.634693 1.566831 0.890585 1.507750 2.229752 -2.184252 -1.213419 1.283669 1.311854 -29.897158 18.464882 -10.731856 -70.299590 24.798233 0.383552 1.607605 0.265000 0.353369 0.565290 0.585293 1.512087 1.392006 1.436863 1.603314 2.407255 0.742268 0.543592 0.407074 0.950060
+1 -0.021264 1 1 -1.349009 -1.487027 2.056571 -0.589217 -2.235055 -2.121812 2.056535 -1.193215 1.561451 0.006483 0.580565 -1.801335 65.513343 -67.245591 53.359736 -32.924039 -4.320181 1.235889 1.091064 1.512325 0.888426 2.268196 1.315915 0.582033 0.723735 1.822443 2.046436 2.454474 2.351137 0.313863 0.339869 0.935351
+1 0.010507 1 1 -2.091049 0.738354 1.794817 1.479861 0.030165 -1.960246 -1.548734 1.668957 2.021337 1.004453 2.070718 1.558231 -72.147016 25.097508 13.823331 -21.276623 3.795133 1.896954 1.112667 2.335945 1.481207 2.145702 1.315535 0.938226 2.256947 1.265238 1.610610 1.280500 1.611152 1.385334 1.807371 0.731528
+1 0.019478 1 1 1.313891 0.308243 1.719795 -1.197358 -2.102469 2.014430 -1.990532 -1.617287 -0.683964 -1.867020 0.800062 2.200318 -66.616997 -31.869403 20.948139 25.380292 -33.428843 2.296630 2.211459 1.742246 1.935622 0.750183 0.818228 1.462735 2.182599 0.436431 1.602645 2.407270 0.991968 1.006723 1.494879 2.432519
+1 -0.031745 1 1 -1.888754 -1.633118 1.847047 -1.897380 -0.533912 -1.062326 0.737686 -0.002414 1.840062 -1.480729 -0.481458 -0.684944 16.473799 -24.862019 44.054563 25.041177 -32.944689 0.604122 0.726714 2.386457 2.185182 1.103592 0.579068 0.390104 1.478682 2.462286 0.895815 0.460872 0.621878 2.153541 0.308299 1.333988
+1 -0.004736 1 1 -0.693137 -0.533017 -0.158615 1.375621 1.078201 2.182895 1.973750 2.309435 -1.266837 -1.153344 -2.203651 -2.098906 20.203399 -41.478809 65.660264 2.055696 50.088791 2.009562 1.452933 1.698207 2.012214 1.032803 1.073049 2.488529 0.959066 1.527704 0.623063 1.826738 2.228686 1.022434 2.296601 1.726674
+1 0.012995 1 1 -1.953949 0.626807 -2.153284 0.906806 0.822178 1.626992 -1.142706 2.231157 -2.134715 1.971257 -1.884389 1.039989 27.147303 -35.277130 47.273453 -25.071357 -24.299129 2.193041 0.441042 0.346327 1.463224 1.411985 1.980091 1.132005 1.113075 2.445079 1.941611 2.411844 1.368267 0.704259 0.739055 0.540230
+1 -0.028044 1 1 -1.706154 -0.449383 1.171669 -0.836262 2.003807 -1.454932 -0.458205 -1.008131 2.089866 -1.760483 0.650838 1.173987 13.795137 -45.136672 -62.048456 -48.403854 -73.566416 1.663695 2.467143 1.522301 2.058539 1.121741 1.853547 0.561964 0.930915 0.884126 2.004943 0.331848 1.121484 2.032059 1.558601 2.401257
+1 -0.005465 1 1 0.483781 2.041189 0.069597 1.046778 1.844214 2.328022 0.097198 -1.591118 0.894587 -1.917510 0.444434 0.457583 -0.645537 -49.547199 60.226659 29.452014 0.000776 1.570508 2.271159 1.618202 0.616952 0.358570 2.487324 0.953916 0.464918 1.123778 2.337724 2.121584 0.970609 2.033699 2.132928 0.380057
+1 0.005991 1 1 -1.571656 -1.883165 -1.949681 1.667345 -1.506289 -1.250227 -0.017964 -0.334499 -0.039433 1.699151 0.546056 -2.164658 -56.134829 41.927664 -21.756019 46.583590 -69.599493 0.494733 0.476589 1.528833 1.604795 0.290437 0.380503 2.121795 2.262462 1.702990 1.405008 1.717197 1.678060 0.906952 0.897988 0.985952
+1 0.001417 1 1 -0.191996 1.104660 -0.795496 -0.859022 1.177515 -1.531708 0.363768 1.883089 0.665672 0.744954 -0.375331 1.701000 -43.133752 1.036622 22.508160 -5.353307 26.963106 1.658911 0.811160 1.913850 1.569659 1.513183 1.818638 1.102747 2.125346 1.193372 2.009473 2.206439 0.627545 0.646248 2.238440 0.717241
+1 -0.043396 1 1 -0.389468 -0.276501 -0.729214 1.030393 -0.216219 -0.733355 2.119321 -1.521300 0.932168 -1.753080 -2.163306 2.111855 7.496358 -8.708684 33.149201 38.617031 -13.564626 1.665078 0.969613 1.032577 1.767303 2.312329 0.558931 1.696091 2.449801 0.300544 1.487309 1.199117 1.804918 2.259106 1.544704 0.585020
+1 0.039044 1 1 -1.579452 -0.955731 1.558909 -0.303887 0.798265 0.274508 0.230148 -0.773652 -1.285408 -2.260799 -1.255092 -1.680634 -11.225452 33.828433 54.475027 -38.229252 -69.033026 1.553958 0.877288 1.830023 1.194239 0.832162 1.653540 0.542965 1.118577 0.418543 2.448485 0.685918 0.729900 1.925726 0.922410 1.951301
+1 -0.056637 1 1 -2.265121 1.505653 -0.016288 -0.428730 -0.419649 1.402289 1.617656 2.179368 -0.769561 1.498791 -2.246474 -0.822243 63.405814 61.522044 50.991199 59.083405 14.794710 0.695328 1.376183 1.010258 2.399516 1.172196 1.594485 0.262139 1.770650 2.322609 2.334923 2.296279 0.804902 2.489304 0.476764 2.224945
+1 0.000348 1 1 -2.271608 0.864843 -2.300485 0.899931 -1.629256 0.784901 1.851687 0.678098 2.228989 -0.878539 -1.689840 0.429422 -66.137135 -66.822882 -42.175697 53.063912 -54.824683 1.548224 1.252988 0.462823 1.915365 2.289813 2.386876 2.479302 1.124042 2.271507 0.712017 0.614331 1.318461 0.629116 2.309857 1.762303
+1 -0.036694 1 1 -1.230510 1.489291 -1.695962 1.204021 0.986783 1.962016 -1.695464 0.150838 -0.132265 1.264983 -1.726352 -0.625669 -72.354443 -11.119155 20.360788 53.758476 68.712999 1.515494 2.405577 1.785184 1.333274 2.092706 1.611069 2.232240 2.258672 1.009477 0.529931 0.300260 1.219125 0.577842 2.284792 1.250832
+1 0.034084 1 1 -1.360325 1.529090 -1.950992 -1.522901 2.296761 -2.225276 2.022798 2.000612 1.393159 -1.035836 -1.723488 0.397235 -36.103359 -39.146658 -37.873456 60.826889 67.527724 1.951984 1.247583 1.877520 0.727541 0.532544 1.460306 1.866600 1.694854 1.910189 0.805090 1.139472 0.607256 1.656366 0.789187 1.616722
+1 -0.003934 1 1 -0.873917 0.590333 2.141132 2.197253 -1.754089 -0.267677 1.489901 -0.862393 1.075356 1.501177 0.156673 -1.028417 13.765138 50.676489 19.755789 -64.447907 -25.972629 1.045345 0.364593 2.465865 0.299025 0.711140 1.626589 2.088062 2.314155 2.000233 2.170739 1.360922 1.009135 1.528002 1.122282 1.943519
+1 0.000457 1 1 0.844240 0.135147 0.049574 -0.900793 1.285582 0.468307 1.152480 1.817121 -0.638855 2.306386 -0.685304 -0.828570 -21.192097 74.431420 -31.129523 6.111685 -30.910347 0.472026 1.340726 1.332028 1.392938 1.359203 1.365991 0.715175 1.945370 0.333963 0.663013 0.505730 0.811539 1.532792 0.640894 2.262279
+1 -0.053528 1 1 -2.153608 0.166686 2.338923 -0.476801 2.183516 -1.732651 1.894067 1.391135 -2.066318 1.700029 1.171280 2.046029 41.894018 12.768453 -50.608003 -68.701922 26.793717 1.705121 1.221242 2.417233 1.927807 2.158118 0.742796 0.429402 0.452523 2.053510 2.094100 0.296077 0.664118 1.078168 0.776416 0.731977
+1 0.006949 1 1 -1.613061 -0.349732 -1.597868 0.539647 -1.508145 0.538540 -1.252167 0.354908 -0.943012 -1.441970 0.620201 -0.083415 74.138551 -3.365985 -22.100750 -47.297138 -73.006350 1.109219 0.637265 2.012219 1.109245 1.085511 0.424612 0.959567 0.948504 1.752176 2.323265 2.120092 0.630254 1.175789 1.237340 0.732364
+1 0.019662 1 1 1.106562 -1.817214 -0.930538 0.862701 -0.602476 1.115725 1.399707 0.629268 1.498428 1.078942 0.500038 1.953383 -22.300581 44.132715 -11.451836 -20.999723 7.657175 1.287089 2.110213 1.108972 0.993067 1.484370 1.306951 0.678942 0.482168 0.793361 2.012698 2.424178 1.658512 0.858239 1.164812 1.246847
+1 0.028909 1 1 -1.408405 -0.739422 -0.899950 1.301090 1.933022 1.088105 -1.002658 -0.169102 -0.529711 -1.151708 1.746520 0.289789 -67.785330 -18.047129 -18.095711 65.377227 45.055804 2.168348 1.674456 1.088391 1.588650 1.190088 0.805682 2.098006 0.695406 0.431105 2.081826 0.997307 0.743292 2.007048 1.953112 2.207690
+1 -0.030533 1 1 1.300211 1.295554 -1.570066 1.285242 -0.534072 0.948206 -0.802424 0.514541 0.661896 -1.457382 0.786028 1.946741 23.929840 38.828704 -55.974996 28.236952 -21.544888 1.300968 1.360663 1.158133 1.495639 1.704954 0.665864 1.183997 1.938856 1.101030 0.261012 0.821144 0.965752 1.388019 1.938835 0.758141
+1 0.034699 1 1 -2.300308 -0.832703 0.557553 -2.153738 -2.018322 -2.167340 0.289842 -1.242701 -0.766520 0.777259 0.645222 1.043148 66.779032 55.189983 -21.959990 68.449544 -68.521111 2.360332 1.841693 1.579009 1.153287 1.043397 1.381717 1.773993 2.255866 1.081773 0.606688 1.104730 1.699297 2.329387 1.511183 1.949045
+1 -0.033162 1 1 0.171287 -0.452293 -0.597409 1.453000 0.966947 -1.555027 -0.429318 -0.887287 2.086705 1.649931 -2.016003 -0.887475 -34.298798 -9.891789 -51.304829 69.743025 71.016050 1.626335 2.315669 0.447336 0.382762 1.825010 2.441128 0.791456 1.501383 1.490222 0.653638 0.436434 1.653131 0.424657 1.713000 0.894062
+1 -0.002159 1 1 -1.314652 1.034241 -1.521521 1.938285 0.004905 2.333994 1.510048 -1.545727 0.360170 -2.043398 0.496943 1.771186 5.359781 -68.166791 20.750049 -3.925494 24.223096 1.638727 1.332651 0.615929 1.169433 2.412078 0.800923 0.864348 0.346194 1.477720 2.037024 1.764872 1.954948 1.561298 0.490494 1.235047
+1 0.013187 1 1 1.873797 0.010615 -0.666066 2.069255 0.541751 0.874059 1.787231 1.228464 1.821004 -1.358894 2.024111 0.502995 -5.814857 69.695992 30.530841 -18.152587 9.474660 0.484167 0.641858 0.461437 1.121689 0.983082 2.416091 0.745770 0.899153 0.317264 1.253226 2.225179 0.590519 1.603751 0.737985 0.558057
+1 0.027984 1 1 0.829351 -0.347220 -1.789225 -1.751834 -0.072331 0.121598 -1.486032 -0.079891 0.307203 -1.621374 1.310611 1.737858 25.125761 38.671850 7.789608 -30.051860 -31.613861 0.862448 2.168188 1.230634 0.511903 1.059060 1.367317 0.504907 0.479251 1.270833 1.133572 0.447706 2.088237 0.749349 0.300761 0.635170
+1 0.053879 1 1 1.936551 -0.855710 0.295176 -1.123214 -0.034540 -0.891476 -2.346218 0.385498 -0.471172 -2.182649 2.166647 2.206202 -68.291696 21.473631 7.315519 -48.075664 42.315807 2.151475 1.586432 2.161522 1.697430 2.449524 2.407703 1.509480 0.326028 2.307832 1.484472 0.777119 1.283821 1.170440 1.329169 0.589768
+1 -0.007440 1 1 -1.162404 1.036135 2.049066 0.514133 -1.492384 1.544008 -0.990132 -1.704476 -0.511602 1.615179 -1.767318 -1.126561 8.257008 25.539888 -51.100437 54.957196 -34.402289 2.136058 1.218193 0.665381 2.055688 0.455731 1.964406 0.771661 1.806904 1.888755 0.552272 2.290907 0.516791 2.213244 2.499004 1.510324
+1 0.089805 1 1 2.282485 -1.831107 1.193486 -1.728011 -0.227244 -2.252531 1.044104 -0.685058 -1.410262 1.048644 0.225726 0.310525 -74.384705 66.263843 -53.589172 -73.211837 -21.352291 0.355774 0.495610 1.710439 0.602067 2.195010 2.036283 0.553559 1.410604 1.271785 1.389468 1.535144 1.917186 1.391748 1.614406 2.072150
+1 -0.009810 1 1 0.871653 -0.949650 0.089511 1.153622 2.162486 -1.757559 -2.032906 -2.232332 1.235842 -1.413914 0.923772 -1.477725 -58.464439 38.171055 -9.086647 -19.271327 -43.193566 2.061028 2.444131 1.756417 1.603900 0.988897 1.142489 1.811440 1.625799 2.309042 1.570168 1.061052 1.095279 0.357286 1.160294 1.810059
+1 0.036644 1 1 -1.852731 0.622790 1.020890 0.292286 2.133880 -1.875680 1.323595 -1.525878 -0.605113 -0.799149 -0.981349 -0.167289 53.410553 71.163725 -51.269011 71.734435 -59.357328 1.845852 1.736291 0.849873 2.322707 1.738844 0.999549 2.421924 2.031070 0.695553 0.658174 2.436386 2.098598 1.635996 0.435991 0.942463
+1 0.001383 1 1 -1.582281 -1.378693 -0.874918 -2.101069 1.976006 -2.187582 -0.632286 -0.393003 1.575075 -1.913989 -1.638902 -1.107136 50.744047 -44.802776 -0.258774 0.785838 7.579820 2.035566 1.998545 0.801878 1.165869 1.016053 0.796796 1.245030 1.728320 1.869245 1.143341 0.377298 2.245960 1.091308 1.115105 0.568299
+1 -0.006676 1 1 0.405869 -2.098554 1.838310 2.059291 -1.996838 0.773144 2.172148 0.410863 1.731495 2.239096 -0.654675 0.310851 -49.943152 5.446877 45.656967 -43.353902 50.964027 2.161116 1.622088 0.686405 2.156440 1.793355 1.415734 1.986752 0.586372 1.662429 1.445124 0.952008 2.143149 1.159062 1.348439 0.471499
+1 -0.028005 1 1 -2.298124 -1.831598 -2.342833 0.728932 -1.052626 -1.174363 -2.041498 -0.561103 -0.961516 -1.424631 -0.130231 -2.251697 29.468211 -27.777753 -60.696292 27.423710 -39.707909 1.062632 0.655486 2.248343 0.652430 0.392403 1.860613 2.328131 0.650131 2.249325 1.402074 1.902935 0.379227 0.925391 0.300058 2.328712
+1 0.086765 1 1 1.877508 1.127583 -1.947908 -1.517696 0.250417 0.596136 0.719058 -2.069952 1.885252 -0.674850 0.509276 1.696339 13.457788 -14.964361 43.986319 -71.937891 -60.141103 2.252255 1.152995 0.633564 0.558015 2.053141 0.388854 0.719219 2.405941 1.149971 1.563493 1.375668 1.346379 1.838242 2.079966 1.238632
+1 -0.005553 1 1 2.069618 1.922529 -0.911679 2.100560 -1.101363 -0.342797 1.869525 -1.108996 -1.393255 -0.570032 -0.248041 1.643517 -45.503273 -73.511053 49.739791 26.671229 63.346993 0.968784 0.606748 2.115699 1.060196 2.457980 0.527311 1.273746 0.592055 0.420227 1.507456 2.320931 1.142155 0.701460 0.931569 0.636066
+1 0.018355 1 1 0.030666 1.749781 -1.446934 2.028131 2.084140 0.950135 -1.362430 -0.869047 2.340557 -1.277412 0.185742 2.170470 15.503595 18.921109 7.071641 53.063791 -56.856800 2.241424 1.359159 0.635222 1.420167 2.248522 1.409857 2.220946 1.434365 2.376350 1.067300 0.367416 0.416180 0.979389 1.090154 1.962475
+1 0.017528 1 1 -1.835572 1.558005 -1.350954 -1.193927 -0.984646 0.956731 1.114532 0.191440 -1.030590 1.607298 -2.261422 -2.295047 -62.220069 67.293412 0.373560 -21.576815 58.465927 1.177442 2.025956 2.498688 0.702625 0.263920 2.454241 0.683413 1.377874 2.427685 2.102313 1.074105 2.229085 0.976482 1.737080 0.606653
+1 0.011493 1 1 0.331125 -0.111704 -1.880975 1.867559 -1.158594 -0.896068 0.576994 -0.560102 1.727008 2.227910 -0.161918 -2.311847 -49.919219 -42.311397 22.355037 -28.895963 45.549325 0.587674 1.031880 1.301128 1.816372 1.257637 2.100812 0.602612 2.356881 2.347017 0.812440 0.924352 0.826548 1.795050 0.653475 2.207921
+1 0.052167 1 1 1.413525 1.963719 -1.345465 1.526732 0.824868 -0.298401 -1.240008 2.080777 0.982886 -2.263310 -1.056027 -1.785885 -68.701982 25.781768 -35.827930 -60.018681 16.020114 1.375750 0.486776 1.749763 2.271283 1.457144 0.466638 0.791821 0.888023 2.256829 1.525560 0.587575 1.628451 1.884739 0.552485 1.360829
+1 0.007709 1 1 2.191295 1.775255 -2.141672 -1.855097 -1.448207 -0.519724 1.764763 0.604200 -0.414952 0.239624 -1.735127 -2.018467 3.516294 -1.644692 -42.335710 63.724645 20.109506 1.832003 0.727354 1.886883 0.595580 1.163845 0.738680 0.991689 0.820369 1.449832 1.332741 2.122671 1.238829 0.993214 1.697634 1.378854
+1 -0.025703 1 1 -2.009623 -2.048518 -0.726247 -0.949626 0.489189 -1.320334 -0.217852 0.087246 0.787703 1.823632 0.399421 -2.088084 -40.322901 -7.000456 -56.662376 25.454670 16.631726 0.316344 1.545509 0.623267 0.747350 0.463216 1.773566 1.819885 1.807376 0.812179 1.040526 0.374702 1.369001 1.797168 2.498202 1.526824
+1 -0.002874 1 1 0.581530 0.282085 0.336271 1.547787 1.273536 0.655930 1.936498 -1.739671 1.719702 1.947556 0.312471 2.100202 73.250876 -72.533434 -19.427971 24.085861 -38.932971 0.678349 1.764512 0.397919 2.329956 2.074810 2.337711 1.907490 0.438646 0.572308 1.529245 1.765894 1.128871 2.427084 0.996741 2.469761
+1 -0.004295 1 1 0.446439 1.171148 -0.164980 -1.937290 -2.139154 -1.945253 0.688500 -2.000860 -0.838907 -0.038232 -1.679097 1.915965 59.776053 -43.872727 31.085191 -1.202387 41.480868 0.909272 1.633532 1.775025 1.599577 0.344103 2.342597 0.774731 1.646203 0.992801 1.500436 1.322373 1.116316 0.667360 1.574715 0.992433
+1 -0.011905 1 1 -1.623854 2.049650 0.901038 -1.876235 1.417248 -1.437119 2.053840 0.643184 -0.229421 -1.142071 -1.230613 -0.240312 -13.131736 -55.094061 -15.875249 34.682971 16.687517 0.881445 1.944937 2.061010 2.142060 0.858177 2.383081 1.699080 0.941810 1.753205 1.618270 1.756997 2.356440 1.686694 2.007345 2.453282
+1 0.031849 1 1 -2.057228 -1.026855 -1.581732 -1.588152 -1.098710 1.833968 -0.226973 2.295363 -2.163764 -0.877815 1.057701 1.644040 -65.693354 41.798200 52.339972 -72.082217 64.172401 2.058106 0.584665 2.222656 0.924607 0.618294 0.421934 0.944007 0.430764 0.855377 0.323483 2.279714 1.397296 0.357855 1.727003 2.241729
+1 -0.073297 1 1 -2.215499 1.404752 0.596922 -0.214748 0.418921 0.496727 -1.866008 -1.041131 -1.184318 0.293692 2.209528 1.915735 -63.425869 51.420103 67.663729 74.285887 72.906250 1.155043 1.308872 1.467728 0.608212 1.962624 2.322292 1.515919 0.545474 0.532200 2.434745 1.510271 2.368978 0.906198 1.712226 1.385151
+1 0.019183 1 1 0.803848 -0.141891 -0.292581 2.333626 0.043891 -2.163212 -1.019671 1.346455 0.982404 -0.941302 -0.978710 1.772480 -52.597039 -48.442236 31.342750 -22.402722 -22.553989 1.151518 0.567931 2.222428 1.604474 1.642755 1.530315 1.748789 1.648127 1.827459 0.852340 1.033331 0.938995 1.691071 1.336208 1.906651
+1 0.071967 1 1 0.555493 0.935308 -0.809367 1.643584 -0.303923 0.203672 1.913381 0.847450 2.254403 2.138606 2.168837 1.321159 -2.041038 46.276313 15.998179 -68.598967 -42.841824 0.737057 0.717935 1.083208 2.220360 0.585907 0.584307 0.692516 1.374221 1.773596 2.331788 1.365254 1.817290 0.949030 1.597783 1.691981
+1 0.006629 1 1 -1.066659 -1.411233 -1.144902 -1.689571 0.243389 0.284095 1.131453 1.841929 1.621249 1.302886 -0.868532 1.572094 -5.523015 24.688223 34.957770 -14.752453 5.514569 1.125286 0.680773 2.005829 1.723038 0.847526 1.122770 1.142036 0.943661 1.365670 2.068795 2.496223 2.019243 2.163925 1.585944 0.715576
+1 0.027273 1 1 1.290175 2.263680 -2.150853 -0.655820 -0.086221 2.301828 -1.892132 -1.860525 1.570287 -2.272586 -1.446648 2.108967 -37.364366 67.098607 26.291809 -13.561070 -70.900079 1.110560 0.682773 1.865438 2.422551 1.315694 1.365865 0.846174 0.891924 0.309571 2.451819 0.477050 0.283402 1.382385 1.750505 1.241454
+1 0.068285 1 1 -0.271411 -0.011550 -0.906812 -0.924154 -0.222625 -0.029340 1.691366 1.656825 0.751796 1.515108 -1.327173 -2.052453 -28.601461 45.239908 -2.868958 -68.578171 6.681088 0.460761 1.006345 1.898670 0.695674 0.445292 2.025724 0.852307 0.470184 1.887449 1.110113 2.165966 2.140083 1.374369 2.016426 2.070570
+1 0.055552 1 1 0.515061 -0.021814 0.936947 -1.540936 0.770844 1.210786 1.591333 -1.992242 -2.087297 -2.172779 -1.597604 0.254514 -39.131121 73.255311 2.012733 -71.995908 14.779769 1.428604 2.297394 1.558258 1.147461 2.126379 0.548794 2.335218 0.516812 0.302805 1.246134 2.269536 1.347001 1.043993 2.395334 0.625096
+1 -0.042108 1 1 -2.105336 0.946495 -1.280437 1.175989 1.089860 0.225660 -0.808110 -0.794274 0.832827 1.534295 0.701407 -1.853991 -54.486552 -5.485127 61.469801 72.937136 54.440494 1.095825 0.531255 2.295564 2.295867 0.632199 2.363215 0.806392 0.536516 0.732617 0.346194 1.489377 2.212560 2.238999 1.114319 0.868098
+1 -0.024682 1 1 2.192526 -1.094590 0.398840 2.278743 1.255837 0.065011 -0.641346 -1.865015 1.503596 -1.611933 -0.233508 0.844685 -57.326485 -36.239637 70.427638 27.314395 73.040168 1.166533 0.913587 2.151680 0.530430 1.930963 1.197264 2.169402 1.396910 0.608903 2.332916 2.315922 2.457509 1.603324 0.314771 2.104676
+1 0.006399 1 1 -0.635225 2.049614 0.297002 1.300413 -0.015162 -0.362037 -1.064886 0.108075 2.142210 1.467024 1.047663 -2.126445 -12.685506 -55.295320 51.558956 1.379038 -72.511297 2.164470 1.754559 1.878999 0.833622 1.438303 1.066180 1.781243 0.358033 2.453156 0.445271 1.668079 1.904233 1.945973 1.473046 2.229281
+1 0.010605 1 1 1.644569 2.110135 -0.404821 0.869436 -0.505223 0.449415 -0.647149 -0.434090 -0.972302 1.088196 0.531956 1.185072 -56.242748 28.138413 -27.694235 -7.014269 11.186772 2.366248 2.281320 1.391309 0.974087 1.977642 0.477573 2.315809 0.550577 0.796438 1.988893 0.571445 0.527168 1.118487 1.162470 2.375570
+1 -0.052687 1 1 2.121497 2.059201 1.211400 -2.229363 -0.690442 -2.355216 -0.054550 2.090867 0.911593 1.165618 1.142424 -2.256082 -66.652285 -24.951665 37.362650 54.064353 -40.426002 2.277864 1.804360 1.876995 0.911958 1.775668 1.153412 0.901252 1.842469 1.127506 1.984609 0.566715 2.032204 1.751842 1.216613 1.112306
+1 -0.011143 1 1 -0.149157 0.107001 -1.759881 1.344444 0.169261 -1.513017 -1.231194 -0.583255 -1.003954 1.607629 -1.413831 2.319567 -20.167943 37.389130 49.104971 7.243418 -59.866461 1.740823 0.517696 1.660625 0.377932 1.648055 0.610936 0.500089 0.497654 2.321139 2.384455 2.289245 1.838551 0.529896 1.957759 1.552220
+1 0.041944 1 1 1.256313 -1.361592 -0.912658 -0.224171 2.261628 1.059715 -2.194131 -2.309338 -1.815933 1.759861 -1.675745 1.697076 -42.230555 31.069873 41.351544 45.401235 8.559454 1.506113 2.248358 0.898380 0.816048 0.824567 2.252514 1.010142 0.455975 1.564422 1.235811 2.028253 0.600666 1.140470 1.627767 1.623977
+1 0.005518 1 1 -0.711756 2.264448 1.316160 0.743387 1.570579 -2.076386 2.129288 1.068222 -0.598887 0.175550 0.519610 1.030593 -49.635756 71.851972 -33.908550 -51.004206 22.317883 0.575017 2.054155 1.677308 1.764545 0.950764 1.494889 0.340264 0.809717 2.419182 0.941869 0.495192 1.434263 0.664882 0.416674 0.284460
+1 0.014812 1 1 -2.226771 0.461809 0.316202 -1.175241 2.064845 1.823904 0.269557 1.838525 0.959791 0.704606 0.080270 1.350182 74.779809 -25.757011 1.919982 19.140428 -56.823486 1.640106 2.012482 1.041109 1.166300 1.506129 0.260385 1.533527 1.732235 2.430984 1.299623 1.263700 0.509725 0.455142 1.079479 0.296409
+1 0.065736 1 1 -1.460402 1.858704 0.804665 -0.556266 0.208646 0.687606 1.814273 -1.386774 -0.030608 -0.778928 -0.434558 0.584896 9.570683 54.469900 25.610640 -61.965805 -9.281225 1.531740 0.961848 1.033224 1.404747 1.837668 1.440460 1.308225 1.840603 1.265446 0.596712 2.190357 0.328719 0.278259 0.451123 1.026634
+1 0.034533 1 1 0.879022 0.380261 1.040030 1.530581 -0.456093 1.501165 -0.058048 -0.147213 -0.199891 0.361795 1.700461 -0.989769 -10.035969 -74.534236 -46.911679 -44.581668 -34.095947 0.616374 1.896038 1.460700 1.743467 2.192551 1.199382 1.768531 0.455818 1.178111 2.014760 1.064373 0.668390 0.879739 0.280592 1.406766
+1 0.054553 1 1 0.099196 -1.005308 -2.298549 0.449867 2.237448 -0.083647 -1.568405 0.921964 1.120688 -0.012280 0.963252 2.328028 6.618125 -69.180844 -72.447842 69.118179 69.233765 2.303304 1.878177 0.523522 0.585973 1.699946 1.989794 2.218393 1.276589 1.135522 1.723566 0.718526 2.015839 1.201315 0.495931 0.359671
+1 0.005584 1 1 -1.185359 1.657388 0.788738 0.367512 -1.166016 1.595146 0.841384 -0.740159 0.862717 -0.338372 0.842882 0.879988 -70.930587 69.624523 29.353775 -1.108781 -35.286254 2.034006 0.542603 1.784571 2.276445 0.461256 0.321577 1.747443 1.520912 1.219731 1.769471 0.495770 2.157784 1.870560 0.746995 1.251612
+1 -0.056614 1 1 1.309894 -0.899224 -0.634143 1.379758 -0.070991 -0.907484 1.914698 -0.577216 1.535017 -1.293057 1.128508 -0.524766 58.727564 34.171724 -25.842987 56.913555 -3.874698 1.044151 0.549007 1.412730 1.005150 2.051634 2.057937 2.251430 0.780663 2.358511 0.496061 0.305168 0.450526 2.238682 0.270927 0.962662
+1 0.007557 1 1 2.004223 0.822199 1.970832 0.397297 -0.085365 -2.157429 1.919206 -0.204450 -0.859306 1.115599 -0.729427 2.153681 33.408909 53.526389 68.024341 -14.895886 -5.154691 2.351755 1.694827 1.463018 2.446257 1.495980 0.693994 1.451105 2.477637 2.402007 0.285580 1.992290 1.414752 1.238024 0.965761 1.549638
+1 0.017504 1 1 0.475328 1.338020 0.581880 1.451646 1.769506 0.203862 0.407823 -2.252280 0.550262 -2.160879 0.491511 0.002681 -65.577368 41.175776 -58.734236 3.700275 -59.470851 2.476234 1.320507 1.262268 1.191274 0.499306 0.832020 1.513742 2.216280 1.772234 1.933460 0.407007 2.060455 1.812250 1.726701 1.656295
+1 0.069289 1 1 0.045793 1.530557 -0.859459 -1.461933 -0.319156 -1.355907 0.387859 1.508692 -0.782815 0.219390 2.206825 -1.098448 48.755095 -23.110864 -74.294511 -67.851000 -71.749505 0.715918 0.931636 1.753660 0.261195 1.648040 0.356587 0.653512 0.580288 0.650502 1.732007 0.834648 0.685569 1.605462 0.253866 2.217795
+1 0.007189 1 1 -1.920959 -0.974853 0.620492 0.088960 1.317976 -1.716870 -1.476464 0.504128 0.003028 -0.941730 1.259494 0.255751 22.781320 -64.350707 -42.324485 -47.616028 -32.584630 1.376824 0.526655 1.495656 1.984009 1.744354 1.358464 2.453297 0.566455 2.165020 1.982219 0.896380 0.960842 2.115060 1.562341 2.257746
+1 -0.002384 1 1 1.245543 1.411725 -0.008265 -2.251933 1.670108 -2.202331 1.240007 -2.090034 -1.058213 -0.832427 0.484965 -1.628602 74.888617 2.988432 -23.428660 -15.490998 42.792354 0.791451 1.422827 1.962557 1.204117 0.350398 2.385177 0.926564 2.014426 2.209182 1.725286 0.387221 0.266659 1.240702 0.983505 0.516420
+1 -0.011980 1 1 -0.460976 -0.452200 0.956531 -2.254870 -0.566251 2.048341 -2.244620 2.064350 -1.787541 -1.714806 0.221267 0.764112 37.181146 3.521317 -67.220864 18.938769 3.895695 2.499214 0.534004 1.246936 2.261577 0.319390 0.987736 1.874747 1.370591 1.515577 1.544108 1.824943 1.312722 0.923162 1.076029 0.814201
+1 0.007737 1 1 -0.340568 1.632073 -0.573230 -2.150990 1.765196 -1.552903 2.287396 0.586367 1.458443 -1.800425 -1.494857 -2.323126 66.170786 32.395848 -22.987248 53.324778 -20.459362 0.467525 2.195232 1.260322 2.225251 1.791176 0.796021 1.722772 0.877433 2.012770 1.367421 2.251612 1.595884 1.277851 2.087315 1.005286
+1 0.010173 1 1 -1.288422 -1.074752 -0.761211 0.454949 -1.879833 2.219968 -1.694293 0.987899 1.867650 0.366468 0.136310 0.745123 -71.587810 -26.322478 -51.886349 46.134744 36.647702 1.943987 1.833694 2.147740 1.810964 0.366301 1.918194 0.339039 0.474691 1.137279 1.994957 1.247105 0.587681 1.147573 1.758482 0.302047
+1 -0.044622 1 1 0.169996 1.417858 -0.608712 -0.031834 2.171943 1.683224 1.469245 0.680132 -1.278619 -1.250375 2.204927 -0.015175 -18.483209 2.702397 -30.812370 -63.508653 10.069307 1.897595 0.628606 0.487124 0.840109 2.464538 0.494976 2.311760 2.248684 1.881749 2.057711 0.692443 2.397819 1.887772 2.033294 2.066269
+1 -0.007182 1 1 -1.192782 -0.589382 -0.300388 -1.650818 1.253325 0.251905 2.045635 -0.606492 -0.419945 1.143834 -2.126920 1.044008 -73.010498 62.554161 -2.221350 15.764479 53.595180 1.737862 2.492650 0.475862 0.566322 2.179621 2.133018 1.881833 1.225561 0.755641 0.313705 2.186284 1.627517 1.924081 0.280797 0.359252
+1 -0.018382 1 1 0.696001 1.541278 0.258385 -2.139796 1.408383 0.354865 -1.666025 0.128203 1.153944 -1.860864 0.590626 -2.348318 -61.499190 33.116439 -62.017353 24.351437 74.608597 0.575463 0.558794 1.644287 0.285352 0.413740 0.470321 1.942881 1.242326 1.275837 1.991407 2.318220 0.566601 2.359018 2.273855 1.937382
+1 -0.023951 1 1 -2.025092 1.867328 -0.331497 -1.420875 1.736820 2.194536 -0.300071 -1.039671 -0.205198 0.697824 -0.807046 -1.765189 53.351438 -22.378199 -60.398210 -62.707580 -26.304746 0.567027 0.524502 1.300785 0.551552 1.436922 0.343241 1.345927 0.987051 1.614179 0.503866 0.971702 2.396445 1.305848 2.395843 2.441982
+1 0.031686 1 1 1.929806 -1.126303 -0.111073 -0.702200 -2.060719 1.550906 1.847150 -0.163351 1.879704 0.329873 -2.310039 0.549885 29.180542 -62.624976 12.033680 50.064548 -65.142934 1.265719 0.684841 0.620394 1.953901 1.966935 0.533192 1.105287 2.062829 1.224309 2.202401 0.250741 1.462071 2.270625 1.644328 0.975427
+1 0.024109 1 1 1.923256 1.891441 -0.325393 2.198153 -0.767433 -0.437985 -0.462521 1.856176 0.729373 1.649410 -1.351950 0.913915 -70.874727 -41.539874 -60.656147 -47.868909 67.239019 1.167989 0.633707 0.705648 1.582036 0.285026 1.677746 2.380616 0.758320 0.334565 1.787991 1.258020 1.794665 0.937787 1.632318 1.621111
+1 -0.027156 1 1 -0.799815 1.951181 -0.022451 -0.350811 -0.883829 -1.060866 1.713745 0.789847 0.165380 -0.769522 2.151989 0.890874 52.706389 -63.721211 37.603315 48.913558 -59.836928 2.436172 0.737276 2.154413 1.472170 1.012089 1.683497 2.284447 2.194930 0.690930 1.707777 0.855719 1.564107 0.451357 0.451014 1.447658
+1 -0.003097 1 1 1.065955 -0.998699 0.386975 0.785550 -1.378287 1.229462 -0.251654 2.178224 -1.145279 1.413010 -1.974822 -1.485602 -72.421918 54.824678 -11.639844 -30.857962 70.229533 1.341537 1.459537 2.435786 1.014368 1.735200 0.511974 2.249380 2.331054 0.273965 0.286465 1.122738 0.605180 0.510430 1.051890 2.369009
+1 -0.008932 1 1 2.279379 -2.205933 1.959413 1.687240 -1.711457 -0.035130 -1.375193 1.399009 -1.674153 0.180349 1.061654 2.105776 55.123390 58.823813 1.825900 -62.105869 36.652949 1.016694 0.324886 1.108625 1.914485 0.992411 1.693918 1.934969 1.024463 0.395292 0.919875 2.090964 1.580766 1.442341 1.419880 1.915870
+1 0.009872 1 1 -0.572669 -2.143810 -0.093947 -0.324366 0.606902 -2.118248 0.710449 -0.682669 1.057168 2.116534 -1.239173 1.982840 -13.625893 39.611796 55.458398 -10.697135 63.253677 2.193246 1.644391 2.020540 1.472518 2.354108 0.742954 0.832916 0.826517 1.276790 2.254029 1.712387 1.838324 1.211207 0.250941 0.319783
+1 -0.066019 1 1 2.305452 -2.245052 -0.496579 -0.367875 -0.212475 0.922627 -1.873211 0.413650 1.449847 -0.178210 1.897995 1.438551 -49.283000 0.610783 65.431608 59.031728 46.249685 1.651873 1.782085 0.994839 2.001799 1.488976 2.215298 1.012623 1.659554 0.375015 2.122252 0.933245 1.802790 2.482299 1.999160 2.135984
+1 -0.029319 1 1 -2.323171 1.320103 1.039528 -2.195674 0.023489 -1.055593 0.793080 -2.060715 1.621422 -0.507862 -1.495185 1.592494 -41.856134 23.963819 9.899303 27.581340 59.584218 1.854343 0.451906 0.677089 0.828638 0.914060 1.112348 1.474133 0.251586 2.150789 1.309417 1.618135 1.748971 2.448609 0.528259 1.449871
+1 -0.023873 1 1 -1.613031 0.154504 0.214703 -1.175828 1.623725 0.508710 1.622369 1.269078 1.122942 0.162412 1.191688 1.049459 -6.765612 -9.634177 -71.616480 -58.175989 -63.849858 1.006572 1.198869 2.144467 0.810156 0.789057 1.676790 2.059055 0.785955 1.288062 0.456321 0.644061 1.485372 2.398004 0.512407 0.521752
+1 -0.000422 1 1 -1.493162 -2.108074 2.056230 -1.605943 1.480438 0.298682 1.254754 0.713291 -0.035877 0.205688 -1.888647 0.163830 46.141091 -6.678493 -45.438276 -31.098605 -74.253397 1.722228 0.736165 1.475263 1.239551 1.884337 0.550874 1.282327 0.813936 1.325917 2.191499 1.529863 0.903849 0.498149 1.632444 1.484143
+1 -0.004204 1 1 0.173594 0.623105 1.590731 2.027241 1.269939 1.453597 1.581886 -0.533907 -0.990998 -2.117634 1.603065 1.978395 8.642514 54.734684 -24.159271 5.128162 -60.974685 1.351955 1.059908 2.121173 0.799825 0.417253 1.024762 0.925573 1.110137 0.327725 1.573308 2.092679 1.152504 1.387273 0.642733 1.666285
+1 0.041843 1 1 -1.732676 1.480411 -0.153736 -1.450379 0.663870 -1.266603 -1.941754 -1.758296 -0.290007 -1.535648 0.124720 -0.851417 55.903710 -26.348821 -44.636580 -57.000976 34.602614 1.616940 1.907974 1.825160 0.472804 0.918049 0.649908 0.749559 1.582788 1.658768 0.657345 2.002986 1.184184 0.585714 1.841038 1.821381
+1 0.024539 1 1 -0.569070 1.796544 2.234038 -0.843540 2.195307 -1.477881 0.252226 -1.993389 2.196155 -1.358627 1.791387 0.382176 7.572609 72.842064 -43.425490 47.794759 36.507549 0.360653 1.495378 1.818681 1.825575 0.692384 1.389720 1.268357 2.272952 0.260076 0.842912 2.325961 2.424691 1.285816 0.960545 1.624470
+1 0.034773 1 1 -1.070237 -0.276844 -1.782231 -2.007833 -0.225606 1.708262 -1.831492 -0.554331 -0.244185 0.476519 -2.213457 -1.973588 13.156818 26.636788 -65.510452 -34.159700 -72.079376 0.803951 2.257815 2.339918 0.751193 2.058574 1.695277 2.271507 0.708988 1.459207 1.399202 0.881515 0.878936 0.275098 1.320919 1.440747
+1 0.017350 1 1 -0.273769 -1.947267 -0.182620 -1.523611 -0.203419 2.327812 1.277946 -0.627514 -0.304447 0.818820 1.739775 0.015729 14.600543 -8.680881 50.442143 -18.897411 -58.789666 0.956356 0.967030 0.366842 2.013642 0.288565 0.411203 0.587357 2.454177 1.846072 0.938354 2.163457 0.463534 0.373509 1.572451 1.176818
+1 0.035916 1 1 1.315724 -1.869249 1.029991 -2.264209 -2.011260 -1.284788 -1.262741 1.719516 -1.167479 0.573245 -2.314002 -0.090022 -10.494380 20.952682 -48.270345 70.309609 -6.397854 1.693914 1.854864 2.452317 2.085918 2.271112 0.835097 1.478755 1.428933 1.069786 1.647332 1.963474 0.851241 0.553870 2.143041 1.583115
+1 -0.015185 1 1 -2.298285 0.169934 0.380730 -0.486852 -1.809656 -1.128425 1.930703 -0.186117 0.955088 1.762271 1.133017 -0.146210 -69.771206 55.346952 66.227693 -61.160392 27.295484 2.202982 1.015978 1.797044 0.416215 1.581346 2.187591 1.090226 0.934369 0.438180 1.748711 0.338363 0.366884 0.473756 1.172465 1.626704
+1 0.003299 1 1 0.551221 -0.177554 -1.200019 0.303851 -1.409566 -1.400008 -0.975720 0.180189 -1.621948 1.089707 -2.347594 0.819765 -39.463559 35.959034 13.484814 -10.725802 31.441254 1.122395 1.587860 1.413392 0.878418 0.573606 0.839035 2.409339 2.013863 1.751616 1.903841 2.098056 1.533627 1.174175 1.111945 1.458399
+1 -0.012824 1 1 2.136639 2.094086 -1.521662 -0.438394 2.087105 -1.050316 -0.053529 0.403725 -0.430971 -0.390095 -1.388410 0.739244 -66.580252 -14.298431 -13.727271 -14.250620 39.831105 1.245684 1.467969 2.396559 0.974773 2.251505 2.044115 1.694224 0.330151 1.853877 1.612689 2.469666 1.180306 0.657945 0.837515 1.616300
+1 0.002370 1 1 -1.934237 2.051191 -1.466790 -1.832458 2.056751 -2.272541 -0.679599 0.803248 -0.799244 2.133618 -1.563182 -0.835270 -5.810875 -13.372116 -45.151180 -5.876643 -68.732117 0.914533 2.304719 0.915372 0.655866 1.894968 1.472822 0.717523 0.910487 1.798311 1.465423 2.363915 1.325870 1.403464 0.522859 0.692859
+1 -0.023157 1 1 0.551857 1.085125 0.754970 -1.689105 -1.356886 -1.926104 2.086822 -1.092059 0.518646 -1.029112 -1.822330 -2.090035 -34.281514 -19.407094 74.970561 30.222414 48.110041 0.406818 1.145723 2.172818 0.302677 1.334412 0.967073 1.100957 1.291055 1.256688 1.908240 1.787418 0.630594 2.392834 1.368512 0.336148
+1 -0.035351 1 1 -0.561202 2.087876 -2.227647 -0.128267 -2.219175 0.890418 -1.290515 1.444669 2.327338 -1.974279 -1.772806 0.886117 57.677936 -56.934561 -49.161862 -63.413647 -43.170575 1.107157 1.981767 2.313080 1.940438 0.694060 0.321552 1.322001 1.626749 0.264417 1.798299 1.268744 2.036415 0.525222 2.160986 1.698991
+1 -0.024960 1 1 -2.226359 -2.050383 0.917652 -0.677900 1.095160 -0.233957 -1.991007 -0.176412 -0.859744 -1.532148 -2.325470 0.381239 -43.627687 -50.533735 -20.478594 66.278887 49.262036 0.580486 1.722326 2.380806 1.707601 2.397562 2.081710 1.290911 1.084701 0.316632 1.886385 1.217518 0.579709 2.163915 1.423991 1.271241
+1 0.064423 1 1 -0.264133 -0.212233 0.280525 -2.321299 -0.198143 1.471098 -1.164878 1.863504 1.367767 1.028217 0.910948 -0.243699 -25.001570 -51.389735 -7.267840 -50.585909 2.620167 0.432283 1.622794 1.303879 0.790918 1.456737 0.385363 0.540174 1.449025 1.269242 1.394508 0.740692 1.058771 1.020877 0.887289 1.161508
+1 0.002841 1 1 -0.331098 0.566925 -0.141021 0.189360 1.717381 0.641653 2.312817 -0.986986 -0.656352 0.389998 -0.241393 0.267342 73.361284 -16.898544 -63.821001 10.440166 -32.126375 2.155234 1.760223 0.322470 1.009538 1.558474 0.279262 1.559469 1.242842 0.938325 1.671839 2.101603 0.397393 2.485089 1.636416 0.744603
+1 -0.010503 1 1 -1.514787 2.005148 2.226641 2.083569 0.787355 0.694972 -1.620945 -0.902956 -2.083408 1.928959 -1.215057 2.033680 34.871916 42.287324 23.054152 21.130782 -54.944721 0.535990 0.890268 1.730083 2.262281 0.913760 0.572663 0.741218 0.905030 2.340114 1.789243 2.056048 2.003462 2.428856 1.528222 0.327884
+1 0.001508 1 1 -0.173401 -2.089606 1.428659 1.857682 -2.221320 -2.186069 1.236069 -2.309204 0.443096 1.536491 -0.086751 -1.894327 -33.406659 -15.717982 -22.123600 18.646878 48.076999 1.076953 0.604171 1.554529 1.467153 2.199124 1.424671 1.451687 1.000640 0.505351 1.180551 0.274901 0.265208 1.595369 1.621755 1.840371
+1 0.048632 1 1 -0.244177 0.609843 0.185640 0.444997 0.508651 0.617991 0.474642 -0.760786 -1.812280 1.897715 1.447556 -0.994962 61.940652 36.530498 18.078737 -50.661300 -64.470972 1.920510 1.014324 0.988565 2.306985 0.751643 0.608468 1.779516 0.580090 1.816351 0.911191 2.383313 1.099617 1.270816 0.856102 1.255618
+1 0.034845 1 1 2.140316 -2.088921 -1.201483 -0.745490 0.787782 -1.552673 1.433560 -0.608360 1.175787 -2.299457 -0.675314 2.144181 51.446425 60.057077 29.298468 -30.651354 -57.306690 1.321802 0.522224 1.267854 0.567410 2.451837 0.775458 0.371957 2.479913 2.392060 1.857066 1.204716 1.403125 1.563491 1.350257 1.776065
+1 -0.031124 1 1 1.154070 0.266832 -1.546274 0.604666 -2.003867 0.449891 -2.068883 1.005138 -0.557139 -0.312905 0.024039 -1.234478 24.844956 -30.816646 14.632364 -73.863198 -18.766868 1.903850 2.252543 1.490912 1.006531 0.521562 1.384090 1.153264 0.654002 2.067722 2.447891 1.962539 0.897451 0.956592 0.435134 2.294457
+1 0.011019 1 1 -0.504112 0.271403 -0.129483 0.904447 -1.124567 0.797045 -1.393406 1.607643 -1.179047 -0.651315 0.231040 0.075401 -11.460024 -8.629557 13.037562 -27.693640 2.984309 2.234320 1.219939 0.758460 0.443071 0.693714 1.255384 2.481858 1.342658 2.304215 1.442625 1.694685 1.318114 1.541165 1.867165 2.189700
+1 -0.007225 1 1 -2.170997 0.079849 -1.010374 2.095117 1.653137 0.036756 0.435172 0.312625 -0.021599 -0.161852 -1.199372 1.757941 -30.470593 -19.258062 29.746432 -1.716214 -44.417896 1.651349 1.968896 1.988526 1.160134 1.370568 1.139688 1.981450 1.484726 0.534861 2.161900 1.294748 0.331851 1.169293 2.313522 0.362613
+1 -0.021142 1 1 -1.772682 -1.736048 1.360290 -2.110813 -1.562246 0.755974 1.055958 0.634205 -0.341635 -2.164281 -0.135796 -1.519265 68.203166 -9.384605 72.937864 66.686023 -8.011447 2.149265 0.449498 0.709737 0.549562 1.738597 1.341581 2.203337 2.491212 1.044078 1.561775 1.761491 1.387790 0.345529 1.549211 2.088459
+1 -0.021190 1 1 0.867631 2.149176 0.739319 -0.841234 -1.444893 -1.381042 2.062701 -1.231229 -1.160478 0.419554 1.707072 1.728320 22.829196 -9.701726 -6.904126 62.352415 57.036256 0.750346 1.311040 1.900007 0.673703 2.429702 2.259942 2.101053 2.392316 1.657951 0.434852 2.051772 2.125026 0.309179 0.364662 1.369206
+1 -0.043520 1 1 -1.791020 1.067975 -0.032279 -0.591462 -2.280812 1.684063 1.432271 1.304757 2.302635 2.248511 2.072536 -0.866989 -25.002618 -69.003761 53.786165 -65.924042 64.633260 1.243115 1.029623 1.624680 1.496941 1.089373 2.337889 0.393540 0.721721 1.710122 2.024628 0.429354 1.909945 1.188820 2.004220 1.682554
+1 0.012638 1 1 -0.625465 1.153633 2.339145 -1.446516 -0.385958 2.169661 1.024101 -2.288050 -2.168913 2.113086 2.073550 2.042563 -12.843970 -18.607996 5.407616 -14.203400 -66.539834 2.350251 1.166386 0.706099 2.404665 2.203655 1.080889 1.501950 2.015936 0.590374 1.408942 0.332187 2.311904 2.421675 2.343078 2.115126
+1 -0.024442 1 1 1.614922 -1.373387 -1.233482 -1.335207 -0.428739 -0.575065 -0.012555 1.048269 -1.362728 -1.151917 -1.771659 1.306608 13.439647 -19.852315 -57.857480 39.328018 -64.005379 2.298992 1.399862 0.729690 0.657874 1.896631 2.431843 2.238993 0.997464 1.127384 2.187136 2.452883 0.362654 1.373530 1.414099 1.511652
+1 -0.050502 1 1 -0.263134 -2.277035 -0.812050 -1.042506 -0.737291 1.938175 -1.832095 -1.274233 1.766906 -1.095322 2.229442 2.018154 -20.975161 -29.523760 -5.841967 64.065122 42.503395 2.193446 0.494266 1.633657 1.623846 0.982837 0.540172 1.424425 1.813089 2.338079 1.338665 0.438152 1.277415 1.514299 0.319987 2.021462
+1 -0.004713 1 1 0.216957 -0.995493 -2.269852 2.093456 2.019365 0.846684 -1.203575 1.807972 1.093093 -1.985203 -1.597527 1.564561 13.934774 51.752765 -41.286859 -8.239890 -37.831597 1.590182 2.193012 2.205430 1.656764 0.725291 0.973937 1.705352 0.597672 0.326967 2.327411 2.038398 2.353364 1.735487 0.827351 1.793518
+1 -0.000822 1 1 1.626701 -1.312426 0.748143 1.378250 -1.851496 -2.181517 2.348666 -1.649757 0.225835 2.136756 -0.656165 -1.175750 -56.801804 -67.917597 8.952121 8.290772 -6.998252 1.080727 1.025356 1.907845 1.902398 0.353406 1.201797 1.856296 1.759533 2.219260 2.347131 0.475500 1.225325 1.291394 2.451335 1.328262
+1 0.019945 1 1 1.408964 0.697513 -1.321086 1.290817 -1.084497 0.386260 -1.793703 -1.617783 0.400679 0.202674 -0.711414 -1.404108 25.668002 2.102796 -58.308395 -39.191475 -41.127844 0.839959 2.190540 1.156953 1.912056 0.675126 1.597259 1.884339 0.588998 0.785777 0.556362 1.275372 0.933905 1.634799 0.569936 2.167901
+1 0.000330 1 1 -1.192134 0.887575 -1.952501 1.383978 0.162151 1.505440 1.116183 -0.327327 -2.030388 -2.331598 1.064262 -1.172740 53.539804 -6.512830 38.858721 -1.472364 3.982458 1.872609 1.435053 0.436383 0.785731 2.025828 0.347339 0.470615 2.383830 0.777390 1.344549 0.336680 1.330118 0.794333 0.351410 1.406057
+1 0.009090 1 1 1.517578 -2.228450 0.505661 2.201467 -1.617612 -1.438725 -1.389366 -1.187395 0.417828 0.971446 -1.339853 1.601439 -56.804577 35.479896 60.615733 -31.380505 -12.141297 0.493424 0.974012 0.715053 2.143901 0.287206 2.318044 2.121863 1.148158 0.348734 1.426720 2.125815 2.331032 2.152919 1.112814 0.313314
+1 -0.003716 1 1 -1.873695 1.707850 0.681327 -0.042986 -1.470577 0.489835 0.113214 -1.021626 1.484655 0.491955 -1.951134 0.813178 36.693333 54.849324 -47.407337 24.885322 47.601608 0.478323 1.426361 0.606119 0.534939 1.224622 0.726607 0.579247 1.149909 0.511828 2.051155 0.759011 0.706090 2.248822 1.957449 0.839911
+1 -0.004287 1 1 2.151551 -1.753849 -0.948209 0.747877 1.632477 1.504523 -0.161537 -0.610464 -1.195758 1.232197 -1.412653 -1.443016 60.144083 -8.391003 -27.586643 1.293784 -5.364938 1.097405 2.335227 0.666773 0.698364 0.649712 1.964714 1.450037 0.270963 1.567225 1.101935 1.979295 1.254619 0.886397 1.930405 0.821968
+1 -0.075313 1 1 0.641069 1.931038 0.734018 -0.392275 -0.329952 0.970193 1.163985 1.977851 0.550677 0.088628 0.461608 1.651333 -64.159449 22.141463 -18.425397 74.360619 -21.069488 1.901676 1.711755 2.469757 0.449463 2.379157 0.997593 1.046783 2.028170 1.447748 2.301372 0.906835 1.179917 0.855866 1.782037 2.452665
+1 -0.019269 1 1 1.703074 0.513735 1.252931 -1.647565 -0.633392 -0.134037 -0.236401 -0.643360 1.986581 1.182475 1.707214 -0.591052 -2.763253 57.997868 70.167352 2.682338 -67.943009 1.852673 1.619636 2.231416 1.907948 1.377373 0.755371 0.270638 0.617947 1.338878 1.778202 0.989290 0.992854 2.389302 0.496470 0.418475
+1 0.030175 1 1 -0.470114 1.464595 -2.074993 1.987672 0.669805 -0.479511 -0.961668 0.744414 -0.023770 1.053460 1.058908 -1.633522 -7.363548 -9.143105 -68.168902 -14.740970 48.512834 0.703120 1.839453 2.189628 1.574157 0.600549 1.426308 1.950805 1.684180 0.267879 1.487259 0.362251 1.350770 1.387609 1.794747 2.317090
+1 -0.013553 1 1 0.157686 1.864723 -1.703484 2.023720 -1.367192 -0.783525 -2.283040 1.935345 -2.276485 -0.991156 -0.061813 -2.159390 61.929821 4.494627 -58.797021 -1.531831 54.515581 2.025433 0.453285 1.365936 2.035350 0.618259 2.071350 0.431452 1.161747 1.482228 1.314835 0.430194 0.264015 1.797780 1.539764 0.810934
+1 -0.014241 1 1 0.584883 0.079866 -0.723846 1.704347 -1.656146 1.228401 0.758760 0.755206 2.285697 0.309318 0.939002 0.010157 33.675410 32.611127 -4.787476 -63.107211 7.098503 2.193153 2.327917 1.554746 0.611563 2.039591 2.148893 0.940156 0.943687 1.797398 1.870687 0.641513 1.401133 1.836234 2.086279 1.599501
+1 -0.053221 1 1 0.467719 0.691887 -1.627847 0.904290 0.948699 -1.941061 0.464946 1.201717 -0.038530 -1.977642 -1.741788 -0.873719 -25.291353 28.233283 66.788409 62.793494 -29.751257 2.434379 2.102657 2.363982 2.450913 0.993394 2.476826 2.263985 0.304598 2.120275 1.463753 1.301633 1.294824 1.609866 2.263946 1.890215
+1 0.053741 1 1 0.715257 0.023679 2.136338 1.740036 -0.299130 0.645805 1.405822 -0.266669 -0.431950 2.005640 1.064033 -0.320158 20.726417 48.897223 -34.372266 -44.672155 -54.908195 0.744561 0.836984 1.685922 0.291366 2.490629 0.257710 1.574774 1.981531 0.595416 0.661823 0.764315 2.092022 1.360556 1.608689 0.478736
+1 -0.077255 1 1 -0.492655 -0.390717 2.287195 1.936619 0.290511 0.591669 1.034157 1.791275 -1.490083 -2.192821 0.854981 1.585953 58.473674 -32.956543 49.385549 72.922429 -42.727595 0.284635 1.855715 1.002432 1.367817 2.153273 0.305294 0.324704 0.304375 0.628239 1.070917 0.406623 2.354610 2.428299 1.175008 1.615536
+1 -0.016394 1 1 0.769615 -0.586616 -0.938563 -2.069119 1.748331 -2.252824 0.836987 0.756826 1.236582 1.602599 -1.136301 1.503206 40.468460 53.406091 -3.830893 -35.816335 -15.144435 1.637253 1.313366 0.497124 2.415484 1.792060 2.159599 0.883498 0.442567 1.228539 1.307012 1.703154 1.905004 1.406159 0.814850 0.941045
+1 0.038436 1 1 0.366725 -0.258395 1.972209 -0.030995 2.139949 1.165572 0.369770 -0.920882 -1.771145 0.534346 -1.058117 0.779785 21.867544 27.818151 -10.331348 61.040867 63.852012 2.286430 1.774410 0.258392 1.794647 0.634642 0.680517 2.193463 0.776966 0.975871 0.471492 1.363577 0.641938 1.808674 2.385194 1.199949
+1 0.004535 1 1 -1.136747 -1.284467 -0.580893 1.005267 1.612970 -1.184735 -1.989266 0.803218 -1.306983 -2.016721 1.177210 -1.949120 53.205507 74.960157 5.364107 4.539789 -49.774990 1.101061 0.790242 1.353685 0.881046 1.997915 1.458580 2.106759 1.554953 1.841220 0.378079 1.875477 2.384697 1.853619 1.779614 2.224607
+1 0.008152 1 1 0.279769 -0.886724 2.120033 1.017384 -2.087269 -1.705867 -0.332809 0.081942 1.177136 1.515478 0.173025 0.494181 -71.122898 -12.551716 -56.697646 32.662374 -43.478712 2.174263 2.085363 1.939893 0.526819 1.993011 2.278968 2.364348 1.848137 1.881976 1.366045 1.624767 0.714415 0.417916 0.919320 1.763213
+1 0.014432 1 1 -0.033682 -0.601832 -2.199185 2.273747 2.111475 -1.435452 1.798108 0.244239 0.436431 -2.091745 -1.541168 1.591155 -8.607553 -67.134794 -34.475834 14.659580 -66.445568 1.365064 0.883541 1.172773 2.302826 0.600277 1.354450 2.487830 0.462463 0.362827 2.028277 0.999746 1.232479 2.265455 2.496841 1.163978
+1 0.018322 1 1 -1.839941 -1.184512 1.744408 -2.214971 0.862590 2.246838 2.233005 0.653001 -0.172141 0.227190 1.351051 -1.883642 -17.327476 -72.886167 52.183013 -10.093807 3.382569 1.387653 0.286435 0.607313 0.355297 1.482924 1.750827 2.150671 1.573384 1.108825 0.770101 0.338495 0.331751 1.733570 2.356449 1.843364
+1 0.008432 1 1 1.906273 -0.794774 1.849646 -0.627701 1.271923 1.810007 2.323396 -2.243238 1.726490 -1.773956 0.403002 1.546970 53.307630 -8.654844 38.029319 8.759471 70.424371 0.961022 0.644552 0.728793 1.321802 0.531011 0.451905 0.673285 2.151273 0.439874 0.958383 1.299255 1.837421 1.787105 2.131164 2.230082
+1 -0.069288 1 1 1.748052 -2.231611 -0.782078 -1.532323 -0.551677 1.946300 -1.940152 1.592302 0.167448 0.998136 -0.435977 0.301460 26.301420 -2.030678 70.393855 59.516784 -51.413167 2.108510 1.723347 1.549622 2.244980 0.371336 1.047212 2.488363 0.417177 1.999847 2.419885 1.503152 1.971235 0.790334 0.641226 1.084523
+1 -0.020412 1 1 -1.593100 0.569894 -2.081762 1.308253 -0.190631 0.483444 1.080300 -0.228870 -1.308933 -1.802437 -2.317590 0.875895 -10.473609 70.055318 69.730680 13.531175 18.454216 0.775218 0.842625 1.999296 2.170179 0.943821 1.803823 1.846156 2.339757 0.299993 1.224836 2.068769 2.056324 2.141900 0.416679 0.373317
+1 -0.013333 1 1 0.006003 1.933369 2.206364 0.576363 -1.734524 -1.312174 0.279122 -2.336278 -2.200446 -0.062927 -2.046731 1.027550 -28.006971 -13.155340 -1.795892 -33.549982 -24.547653 0.288972 0.494222 0.889046 1.454260 1.497977 0.493308 1.283499 0.262403 1.704486 1.800921 0.328981 2.426929 0.647269 1.397078 1.189726
+1 0.006008 1 1 -0.649204 -1.988060 2.228013 1.570341 -1.377045 -1.443954 0.263754 -1.444783 0.477756 -0.272182 1.163789 -1.317641 -66.330351 -14.213583 62.312732 -9.911279 71.126399 2.445838 1.195874 1.297136 2.220595 2.288374 0.699421 0.425627 2.269857 2.234259 2.435848 2.052051 2.317455 1.210433 0.753072 2.123528
+1 0.000901 1 1 -0.545338 0.095990 1.663985 -1.439829 -1.088282 -1.980269 1.223240 -1.159488 -1.782556 1.956655 -2.264234 2.277699 -68.697918 -55.899898 -59.590781 7.740089 37.684206 2.251858 1.228935 1.213005 1.218729 0.679404 1.486067 0.574470 1.868511 2.320542 1.354497 1.037241 1.409642 0.846153 0.543364 1.076869
+1 -0.023694 1 1 2.332374 -2.161229 -0.688746 -2.118368 -1.307858 2.119053 -1.304950 -0.845059 0.235487 -0.568786 1.849794 1.849368 -18.913013 -21.006689 40.575082 45.405556 -68.825536 2.113356 2.174568 0.457177 1.530356 2.445625 2.128170 1.408531 2.434136 0.279848 2.408068 0.902565 1.414004 2.170737 1.333997 0.736259
+1 -0.007553 1 1 -0.769258 1.877183 0.371309 1.389934 1.302340 -0.611533 -0.314280 0.487258 -0.791234 0.088170 2.191408 -1.035998 8.313942 -67.577292 28.452210 -3.710216 42.394694 1.789206 1.443332 2.324450 1.782688 2.132706 1.146826 0.454068 1.017060 1.971687 1.644166 0.501017 0.336085 0.334305 1.908814 2.439620
+1 -0.000888 1 1 -2.201807 0.626740 1.421957 2.298743 -1.905820 -1.009673 -0.257866 1.436686 0.095886 -0.082473 -0.687825 -0.779278 -50.785984 -60.027126 24.095951 -19.353941 68.311872 1.639404 1.455884 1.790432 1.790015 1.531889 1.203727 0.540165 1.300209 2.111085 2.248207 0.623096 2.372944 2.316689 1.845673 0.968633
+1 -0.008157 1 1 -0.846586 -1.871561 -0.125512 1.673400 1.303351 2.238272 -0.362154 1.690565 2.339030 1.322249 -0.581216 0.282445 53.305299 -47.842649 58.593418 29.570442 40.416310 0.278930 0.472204 2.087042 0.909796 1.446034 0.488897 1.386875 0.715962 1.667882 0.842235 2.192867 2.012575 0.352528 2.191568 0.434947
+1 0.011735 1 1 1.398694 -2.253509 -1.256545 2.179247 1.925628 -0.665715 -1.459964 -0.204758 -1.325806 2.061438 1.105797 -0.526844 -2.742875 -49.502995 53.159631 53.913302 -29.139749 1.348629 1.405196 0.369971 0.610636 2.204945 0.267132 2.439871 2.165313 2.413923 0.302432 1.720767 0.929865 1.242940 0.339939 2.104347
+1 0.055178 1 1 2.143019 0.922237 0.994623 1.786178 -2.336166 -0.324315 1.479357 0.982110 -1.176854 -1.495458 1.725235 0.695804 -56.327918 -53.322917 51.740577 53.883753 74.230163 1.920363 0.785317 1.828402 0.943377 1.093031 0.819635 0.347767 0.924381 1.327851 0.934994 1.941178 1.874821 0.375255 1.667238 1.272323
+1 0.005797 1 1 2.055686 -1.327996 -1.756207 1.825696 2.106668 -2.126162 -0.355382 -2.316700 1.700165 -1.257481 0.577197 -1.860270 36.396238 11.577996 41.376815 20.132425 -34.331358 2.018086 0.728436 2.074364 1.578388 1.965145 1.938053 1.107229 0.942620 1.866204 1.790059 2.269896 0.638304 1.483035 1.361024 0.479654
+1 0.013339 1 1 0.317873 -1.353081 0.760220 1.728425 -2.239547 -2.221181 0.160810 -2.177535 -1.418221 -0.770369 2.056670 1.085987 35.267936 -51.797679 36.405369 15.037444 -15.673274 1.064350 0.286831 0.517954 1.504319 1.336885 2.018913 1.124029 2.062607 1.988260 1.185973 1.393803 2.389207 1.155995 1.559168 0.689879
+1 0.000035 1 1 -1.354626 -1.644974 0.515392 0.819470 -1.483856 -1.202411 -2.191055 2.255422 0.413773 -1.207686 -1.311991 -1.371784 68.403024 49.626948 -69.885399 -63.892841 3.016483 1.345477 2.438001 2.236021 0.550657 2.148553 1.983324 1.469329 0.508560 1.117491 2.427336 0.741646 1.342983 1.012034 0.746293 0.700085
+1 -0.045623 1 1 0.527964 0.059997 -0.089791 -1.146240 -0.608560 -2.190332 0.273866 -1.135982 2.155771 -1.521076 -0.021468 2.041413 -28.057640 35.249203 -66.638427 57.956388 -26.984882 2.351345 1.559649 2.027739 0.964504 0.670272 1.011785 1.077566 1.899924 1.527125 2.136213 1.579322 1.913599 1.859444 0.681207 0.296550
+1 0.001008 1 1 0.380547 1.133886 0.312312 -0.576835 -1.477574 0.699917 1.376038 -1.329470 1.738627 -0.424752 0.465479 0.739034 -29.117964 64.384522 10.663290 -32.092587 19.894184 1.548265 1.938219 1.655210 1.622646 1.058126 1.422772 1.036641 0.330131 1.512644 1.749357 2.199816 1.805229 0.740011 0.857512 2.447511
+1 -0.016169 1 1 -0.310073 0.502396 -0.828119 2.196920 2.059925 -0.770893 -2.039094 2.144725 1.332832 -1.792474 0.196474 -1.250402 55.643228 -54.270301 29.047886 -42.175223 61.022156 2.115628 2.107302 1.678787 1.878303 0.395094 2.099583 2.440686 2.367556 1.761110 1.732819 0.990086 0.871014 2.138220 1.566070 1.944481
+1 -0.034618 1 1 1.432287 1.570742 0.655787 -0.458362 1.058201 0.628328 -0.155661 -0.821148 1.559388 -1.667313 2.054856 -1.138668 -18.393827 4.956758 58.238576 65.754975 -56.138277 1.134595 1.890188 2.145887 2.173617 2.474262 1.920748 0.512804 0.447220 0.682687 0.416067 1.340912 2.199372 1.103947 2.031902 1.175988
+1 0.030800 1 1 -1.367760 -0.908649 1.188464 -1.299822 0.520271 -2.007563 -0.404632 -0.679125 -0.650572 -1.423456 0.773953 1.627398 31.120545 -7.001345 -71.606828 -45.951790 38.268995 1.179941 1.259912 2.084773 1.021930 0.580563 0.776262 0.378613 1.849121 0.428742 0.615600 2.393026 2.344119 1.609380 0.851968 1.531525
+1 0.002893 1 1 -2.319253 1.188240 -0.351830 0.847791 -1.440338 -0.217623 -0.769393 -0.392283 -0.466522 0.572328 1.133317 0.180364 41.966558 31.941082 -16.238641 -72.843419 20.651929 1.329586 0.855185 1.593051 0.913435 1.855494 1.782777 1.390171 2.100582 1.239794 1.474245 2.133970 2.139402 1.179202 2.345228 2.242570
+1 -0.055357 1 1 -1.006684 -1.856537 -2.095620 -0.684153 -0.335055 0.040611 -0.744735 -0.651439 -1.862246 0.915246 1.304025 -0.573583 42.608406 19.481718 -20.764756 56.748013 63.852204 2.334838 0.868514 0.616211 1.410376 1.933197 0.497824 0.676175 1.224957 1.843966 1.530727 1.919802 0.362054 0.287081 2.472340 1.123527
+1 0.016272 1 1 1.663460 -0.835080 -1.703233 1.520105 -2.171562 0.008903 -1.172071 -1.214420 -1.407401 2.013054 -1.552061 2.304379 -45.485333 -71.993524 54.835127 13.973317 -50.468044 1.878886 1.188277 1.873113 0.913981 2.029533 1.851888 1.926427 1.450623 1.114420 0.306622 2.394919 0.395056 1.458938 1.369078 0.843796
+1 0.067333 1 1 0.817203 -1.875149 0.824363 0.642333 -0.397653 -1.183553 -0.985467 1.306197 -1.773553 -2.240486 0.854748 -2.328032 -8.691330 24.820765 12.597993 -65.538125 -49.274955 1.162369 0.690040 0.257525 0.729758 1.797832 2.414701 2.130653 0.382608 1.492196 2.346627 1.017756 2.422084 2.459942 2.001981 2.292698
+1 0.006502 1 1 -0.123659 -0.173970 -2.238666 -1.546500 1.507184 2.159101 -2.099480 0.400749 1.376667 -0.188941 0.615698 -0.367004 9.107992 -71.985515 39.442025 52.122259 18.809187 0.265133 0.342747 2.051456 1.325146 0.470959 1.413564 1.526245 0.846964 0.665855 1.021111 0.308640 0.315262 1.355141 0.603015 2.377686
+1 -0.057189 1 1 -0.971551 -0.422501 0.598274 -1.044378 0.786561 1.477124 1.152107 0.254262 -0.747780 -0.002525 -0.031680 0.054162 25.818723 -14.729222 -54.036087 65.488181 -40.143062 1.608315 0.944071 1.506008 0.470361 0.360785 1.460051 2.072934 2.308327 0.807452 0.348302 0.908327 1.508509 2.012480 1.002826 1.249209
+1 0.011384 1 1 1.856383 -0.489325 -0.974764 2.119036 -1.591441 0.165568 -2.319300 0.400907 -0.675577 -2.273781 2.032616 2.067960 74.403001 -58.756795 74.553773 -74.732999 62.483215 1.455830 0.877899 0.845646 1.029235 1.859633 1.595392 2.011221 2.338207 1.239099 1.030240 0.751683 1.279085 0.325084 2.194431 1.305543
+1 -0.024787 1 1 1.899968 1.615794 -0.856594 -0.420885 -0.515824 1.334719 1.649067 2.303217 -2.102200 1.821352 -0.211683 0.102599 -11.291406 -24.668377 -1.417087 33.015534 42.084344 2.298660 0.334908 0.805240 1.421218 1.917689 0.855339 1.926375 0.590777 1.432441 1.538998 1.433512 1.539326 2.453192 1.050556 2.451961
+1 -0.008405 1 1 -0.840770 1.635393 -1.315680 -2.106149 1.418663 -1.217524 -1.732327 -2.071822 -1.275256 -1.283310 0.006521 1.217830 68.877918 -68.832326 -64.901165 6.124022 26.443046 1.049025 1.468635 2.356906 0.519060 2.086319 2.258055 1.878900 1.417903 2.441817 1.124134 1.574403 2.492633 2.438953 2.489662 2.005213
+1 -0.029444 1 1 -1.040456 0.729271 -0.058397 -1.299255 0.630938 1.293518 1.900845 2.222097 1.097400 -0.288960 1.925606 -1.030615 38.296521 -0.376323 -24.862512 35.760568 -22.129808 2.339727 2.036962 0.725517 0.256491 1.352202 0.700337 2.313576 1.278157 0.483783 0.939782 1.412932 2.143960 1.282362 1.406842 1.049902
+1 0.006825 1 1 -0.300340 -0.850060 1.010430 -1.148826 -1.669310 1.477603 -0.222715 -1.529470 0.279851 0.495314 -2.047910 0.066606 -66.980799 3.703698 -1.955254 -11.956203 52.099683 0.465573 0.888115 1.550991 0.510005 0.656658 1.696105 0.442598 1.747345 2.131219 0.902159 1.342924 2.279943 0.759833 1.005131 1.738258
+1 0.004517 1 1 -2.016911 -2.001886 0.756733 -0.322631 1.493887 0.153921 -0.153798 2.211494 1.972230 0.326196 1.873596 1.342501 15.749288 -51.708420 36.580655 -38.925029 -62.963487 1.715123 0.579582 2.281918 2.452048 2.064211 1.952284 1.782284 2.103748 0.442408 0.797747 1.490942 1.506425 0.734704 1.662835 1.513140
+1 0.011139 1 1 -0.513271 1.845758 0.004009 1.398676 2.154428 -0.523491 -0.280312 1.186541 -0.635296 0.858140 -1.869677 -1.458873 -23.156916 51.720223 11.782587 29.934412 7.657181 1.288657 1.450656 1.668938 0.587756 2.421009 2.403528 1.099627 1.424827 1.822466 2.434951 0.470469 2.171640 0.759049 1.337877 0.702539
+1 -0.017334 1 1 -1.296599 -1.852389 1.650212 -2.006789 -1.536599 -1.736493 -1.414216 0.556076 1.304695 1.255107 1.929027 -0.085579 -33.551686 -53.179251 66.330847 22.551014 -35.107023 2.218915 1.057887 1.908232 1.662444 1.702309 1.198148 1.278543 2.475709 1.495820 2.494061 1.676489 1.509192 2.238146 0.276785 0.421150
+1 0.034710 1 1 0.468984 -1.620945 -0.900595 -0.111657 -1.092904 0.451284 -2.221121 1.158623 1.379650 -1.880073 -1.810303 2.139647 25.685969 4.081689 50.939552 -58.955645 32.482396 0.349490 0.636730 2.013569 1.301967 2.414525 1.424029 1.898732 1.741492 0.511077 0.675916 1.372810 0.574202 1.856120 1.064566 1.660919
+1 0.011409 1 1 -2.334191 -0.102999 -1.657043 0.298689 1.373658 1.080051 0.301336 -1.264458 1.134697 -0.192348 -0.096840 -1.812743 -37.696413 36.385872 -12.648723 -37.093934 -37.747620 0.261352 2.050252 1.329539 2.318506 0.874969 1.111067 2.449508 2.134758 1.879118 0.590417 2.134481 1.727068 1.075495 0.852830 0.263439
+1 0.033372 1 1 1.084092 2.246605 -1.674563 -1.986840 -0.829481 -1.846861 0.306922 -1.623286 2.169353 0.558302 1.010298 1.346283 -60.909250 48.237997 -13.978915 -43.631525 34.965634 0.886260 1.866944 0.731984 0.962254 1.104533 0.643022 2.013288 1.087104 2.460201 1.842963 0.423807 0.926356 0.771580 0.446636 2.114833
+1 0.003949 1 1 1.126252 -0.746076 0.373586 1.950953 0.863176 -2.051502 0.962339 1.117727 2.050427 -0.177009 -1.481027 -0.783764 -50.760509 68.124970 26.372337 -10.136077 42.956422 1.653780 2.324129 0.879036 1.952070 0.435860 1.004345 2.023318 0.907900 1.077019 1.707889 0.486871 1.085519 0.563303 0.940711 1.280418
+1 0.008287 1 1 1.131490 -2.249422 1.455442 -0.402903 0.119051 -1.879680 0.079726 1.644061 -1.715219 -2.008287 1.557155 -1.505614 21.561604 -14.125235 47.167901 0.905957 -73.582011 2.232112 2.360616 2.121992 1.070780 0.350452 1.042075 1.663725 0.731247 2.075182 1.827648 1.775594 2.167413 1.717215 1.982948 1.908796
+1 -0.010520 1 1 1.690054 -1.537515 1.724140 1.142346 1.136929 -0.363710 -0.900729 2.352730 0.684606 -1.486468 2.013002 2.282895 11.023001 13.581616 -33.786813 45.033336 -24.726973 2.331434 2.170308 0.871497 1.246067 1.143649 1.050990 0.734652 0.789993 1.662664 0.895496 1.847880 2.062935 0.751125 0.910674 0.449237
+1 0.070203 1 1 -2.315339 1.005851 1.994822 -1.666024 0.155680 1.133455 -2.209745 -0.849724 1.947457 -1.344920 1.267705 1.605817 35.724790 -23.460281 53.054701 -59.634180 28.329910 1.986852 2.278805 1.880270 1.957035 0.646411 0.476322 1.535707 2.379084 2.019360 1.881116 0.418030 0.574632 2.341777 0.492189 0.471310
+1 -0.018274 1 1 -2.291190 1.616580 -1.782249 -2.315235 -1.957240 1.847935 -1.119212 1.260298 -0.361137 -0.074247 0.908901 -1.669840 63.363668 -46.835594 34.170370 -48.583677 54.139437 1.697813 2.142814 2.272156 0.381334 0.327313 1.402665 0.593913 2.395233 1.188491 0.975789 1.329192 0.988373 1.338528 0.388180 0.642809
+1 0.030651 1 1 -0.505832 -0.362985 1.850389 -2.279947 2.082653 -0.481771 -1.245490 -0.522232 2.026932 0.787137 1.741105 -1.189496 -60.822286 9.835936 12.570185 67.104364 -26.947266 0.584586 0.890809 1.830163 1.299294 2.479722 1.428956 1.465450 0.573096 1.279438 1.773323 2.234749 1.679445 1.685449 1.337179 2.460215
+1 0.048829 1 1 2.218900 -0.795886 2.014086 1.654235 -0.362357 -1.728699 2.339611 1.675556 -0.168320 -1.524039 2.027482 0.601466 24.578581 -7.791786 -6.545025 -52.237275 -1.877001 0.673584 0.426183 0.362329 0.410992 1.543144 1.376243 2.008988 0.818199 0.972966 1.146470 1.222072 0.621377 0.483128 1.190307 2.239924
+1 0.008395 1 1 -0.028316 0.039999 -1.610022 -1.100032 -1.531130 0.651316 -0.210423 -2.291998 2.166640 2.087372 -1.272493 -1.965964 41.706760 15.518495 -30.658946 -34.898032 -31.222200 0.602228 0.391280 1.001214 1.148713 0.676203 1.695513 1.737709 2.172921 2.029659 1.725820 0.348679 0.506368 0.275197 0.728662 1.367343
+1 0.030458 1 1 -1.493476 2.038605 -0.940551 2.216417 -0.110841 -1.515025 -1.983005 -2.345595 1.437402 -1.996091 -0.803496 1.345161 -61.234817 -23.570418 1.979453 -31.325779 7.636315 0.528256 1.404809 0.618888 1.405386 1.315590 1.863948 2.125373 1.651761 2.144840 0.321259 0.901109 1.690151 1.623244 2.108652 1.856084
+1 0.023238 1 1 -1.776603 -1.666440 -2.129381 2.094395 -1.047601 -1.548005 -0.223642 1.739899 2.106138 -1.606129 -1.640903 -1.763572 18.155067 32.212496 45.417423 -19.375211 10.831890 0.648662 2.308507 1.581133 0.847946 1.435432 2.308390 1.854010 1.594408 1.213222 0.371450 0.713001 1.413140 1.149379 0.610365 2.147246
+1 0.026421 1 1 1.350520 -1.394036 0.438310 1.211455 -1.311102 -0.559206 -2.066290 2.164913 1.330650 -0.757435 -2.053629 -1.808848 -53.526453 -69.093815 40.257136 -48.312587 -39.657522 0.265528 2.475390 0.624041 0.251066 2.418198 2.412131 1.688979 2.174284 2.443202 1.893527 2.002261 0.259005 0.845789 1.171005 1.833840
+1 0.026687 1 1 1.339020 -1.456663 -1.267150 -1.706552 2.298440 -2.281114 1.316661 -0.251229 -0.104495 1.473629 -1.028696 0.453694 18.870722 60.230703 -52.572447 64.882804 -14.720501 0.512984 1.216235 1.502925 0.413499 0.920651 1.628437 1.641114 0.945562 1.811655 0.741065 0.585670 1.109071 0.401092 1.646326 0.800064
+1 0.029296 1 1 -0.371109 1.976223 1.456582 -0.079482 -2.248361 0.448273 -0.981117 -0.987452 0.926183 1.329378 1.413147 0.323411 69.302042 9.425970 22.270299 46.920057 35.396443 1.495277 2.364908 2.259479 1.058360 0.861275 0.455458 1.874446 0.811782 1.120076 0.875948 1.802670 0.475804 1.834303 1.127000 2.488511
+1 0.022092 1 1 -0.247709 -2.199411 -1.518309 -0.639802 0.526680 2.043556 2.154720 -0.339129 2.241793 2.269629 -1.128609 -1.160432 37.849392 -15.269782 10.771291 -16.920417 18.559565 0.334139 1.378600 1.133258 1.919238 2.137406 1.384413 2.074560 0.386582 0.790886 0.924337 0.580018 0.604723 1.835826 1.978766 1.367419
+1 0.011576 1 1 2.314730 -1.816665 -1.117758 2.134086 1.589022 1.580098 -2.323294 -0.749579 -1.965068 2.236465 2.247250 -0.263106 -57.498248 -73.060505 -27.915721 20.478849 -61.983385 1.303795 1.629231 1.479548 1.258668 1.428640 0.659002 0.591788 0.436575 1.758238 0.710096 2.088753 0.412435 1.043834 1.972361 1.715275
+1 -0.003386 1 1 0.908002 2.065999 2.355813 0.650017 1.512868 -1.282939 1.528184 1.667417 -0.292133 0.425138 1.314756 0.706907 33.278241 -42.608392 -19.246927 66.898400 -38.588347 2.059776 1.660419 1.413120 0.803866 0.828747 0.500185 2.113979 1.399760 1.262411 1.340440 1.026723 2.387934 2.253033 0.730142 1.491844
+1 0.055629 1 1 0.194121 1.624999 -1.643247 1.255554 0.019469 2.058981 2.228139 -1.023278 1.989444 2.185315 0.223363 -1.703860 13.151738 -58.740292 51.912473 -57.058993 -40.503516 0.736208 2.199799 1.514711 0.491546 0.910149 0.625289 0.984310 0.540069 1.941244 0.743754 0.767057 0.932350 0.252359 1.639766 0.795860
+1 -0.026356 1 1 1.124866 -0.490792 -2.057962 0.774132 -0.074440 -2.329906 1.226021 -1.535108 -0.233370 -1.533659 0.557400 -0.014972 -59.735026 -16.577575 -69.299938 25.939437 64.109873 2.044444 0.473308 0.384034 0.712440 0.983414 1.240730 1.448233 1.447396 0.875744 0.629187 1.249790 0.714919 2.143780 0.515426 1.759887
+1 -0.022093 1 1 2.142654 -0.487971 -1.777250 1.599862 -0.019559 1.140848 -0.474034 1.562969 1.972683 -1.478177 -0.007299 -0.151880 46.883032 13.110866 4.330278 28.978691 -5.134172 0.774549 0.839558 2.205992 2.113714 1.438136 0.509182 0.319686 1.458779 0.955491 2.180668 1.735270 1.679226 0.255486 2.453425 0.459916
+1 -0.025479 1 1 -2.190531 1.647870 1.043465 -2.003169 -1.957639 -0.138317 -1.481702 2.018686 -1.137791 0.017343 -0.684139 -0.098722 -14.585344 -35.869949 -16.229155 -63.408538 42.703088 0.786903 1.472622 1.859705 0.569399 2.146482 0.921473 1.941143 1.295527 2.178368 1.333599 0.792195 0.425646 0.334676 1.407556 1.787736
+1 0.013730 1 1 -0.439308 0.872119 2.180941 2.122497 0.027371 -1.790716 1.458206 -1.073054 -0.503119 -1.902161 -0.774085 0.863322 13.156462 20.650789 -22.187713 -8.890381 -20.632778 1.748628 1.193810 0.358797 1.806013 0.410733 1.697355 1.198047 1.824805 1.251533 0.762021 1.779542 1.011043 2.096002 0.751553 1.358840
+1 -0.005243 1 1 1.532972 2.028855 0.120730 -1.935149 0.859773 2.012559 -0.449051 2.045297 -1.567012 0.767771 1.408463 1.702641 -65.491747 -19.785013 23.294321 7.655469 -34.524007 0.700284 1.424992 2.339420 1.383415 1.065091 1.485906 2.370082 1.466010 0.973767 1.104049 1.500696 1.195985 0.911348 0.528464 0.392601
+1 0.004179 1 1 0.538758 -2.304533 -1.159854 1.491263 -1.534136 1.976773 1.286438 0.730069 -0.786039 -2.126793 -1.541017 -0.584529 36.483389 -23.684909 27.732740 54.163047 -31.676343 0.860497 0.870246 0.466476 0.304997 2.077159 1.303796 1.649640 2.497215 0.688447 0.473522 1.732765 2.332606 1.617172 1.317704 1.395299
+1 -0.024856 1 1 0.071718 -1.005067 1.753112 -2.008446 -1.110772 1.736244 1.933690 -1.819272 2.192512 -1.331439 1.644440 -0.065101 -27.697543 -62.610448 -43.798860 72.555928 -52.520827 1.861943 2.168508 2.115039 1.208235 2.047637 2.381703 1.040820 0.817659 0.893507 2.178645 1.487234 2.193519 1.717375 2.424957 1.251402
+1 -0.022203 1 1 0.930160 2.200343 -1.655833 1.785001 1.447255 -1.344845 -2.185902 -0.673814 -0.926375 0.147266 1.094585 -0.478650 -19.700688 -59.462123 70.097826 34.169406 -64.786609 1.096850 2.002335 1.492292 1.701982 2.463282 1.880279 2.098315 1.383678 0.974696 0.973226 1.010062 1.365852 0.618767 1.614182 0.563526
+1 0.028386 1 1 -0.466265 0.180942 1.598885 -2.292916 0.885379 -1.153390 1.738738 1.454514 -1.853041 0.122618 1.523762 -1.961237 20.464192 -8.329705 -47.358612 -56.195096 -70.975133 2.439017 1.310433 0.696351 0.572029 1.346272 2.295172 2.450591 2.336784 2.074905 1.684208 0.735125 1.990518 0.883394 0.951621 2.390833
+1 -0.010117 1 1 -1.891740 0.008408 -0.054457 -1.054269 -0.510101 -1.434835 -1.980211 2.191253 1.066293 -0.025345 -1.860321 0.288375 -74.234051 48.308350 -31.566352 14.323818 -9.593947 1.443076 0.275273 2.010674 2.144921 1.685683 0.771596 0.716306 0.696630 0.767328 0.989011 0.801833 0.414849 1.117018 1.221177 1.313709
+1 0.009296 1 1 1.350448 2.112495 1.571540 -0.068498 -1.427561 -2.244330 2.224075 1.360170 0.572980 -2.054686 -0.729098 -1.733099 -29.181623 44.462712 -15.201735 -45.555500 -51.285715 0.489939 0.900623 0.268277 1.435021 2.145001 0.790774 1.283271 0.933113 1.829735 0.851075 2.263108 1.306624 1.937103 0.883734 2.171625
+1 0.005394 1 1 -0.243724 -1.204820 -0.277028 -0.172337 1.659282 -0.371284 -0.960824 0.781313 -1.895817 2.172304 -1.680400 -1.140219 51.809894 18.892428 -24.970877 14.462699 74.578031 1.869567 2.064708 1.293718 1.019572 1.445605 2.277488 2.246205 0.709761 0.949399 1.056886 0.834084 2.450602 0.270220 0.340468 2.000651
+1 -0.044480 1 1 0.911874 1.183905 2.181729 1.226715 0.704140 1.670218 -0.353639 -1.289751 0.136006 0.339070 1.479200 -1.644216 -28.075159 40.808278 64.734277 38.986629 48.279440 0.363284 0.721565 1.336455 1.552874 0.645872 0.426957 2.113562 1.135611 0.965921 1.988582 2.105491 0.484420 0.401062 1.154198 0.605292
+1 -0.036351 1 1 1.185398 -0.998253 -1.526935 0.472793 1.143197 1.308001 0.282889 -0.290059 2.295620 2.154362 -1.637220 -1.119713 72.340827 -67.724665 -48.439873 71.060009 5.564547 2.475026 1.266861 1.875578 1.833610 0.734749 2.432732 1.431320 0.691414 0.843270 1.590534 1.346417 2.481528 0.295578 1.279188 2.069623
+1 -0.008019 1 1 0.863651 1.231740 0.332379 2.114070 -0.239792 -1.091203 0.760935 -0.385017 -0.863523 0.931951 -0.674418 -1.654908 -48.273751 13.061675 -72.433675 7.230377 20.938458 1.565069 0.860295 1.977016 1.199782 1.727986 0.756024 2.242466 0.883719 1.906991 1.056059 0.426446 0.275703 2.483757 1.757087 1.616123
+1 -0.004850 1 1 2.189944 -2.079475 2.055669 -1.610061 -1.760937 -2.271746 -1.456883 -0.259263 1.530247 -1.361144 1.901126 2.234814 -61.317475 -62.797529 -38.065798 -21.867064 -19.748382 1.959170 0.529103 2.129485 1.008048 1.257845 1.107165 2.116496 0.953219 2.247158 0.991419 0.776352 1.899654 1.488056 0.250801 2.466102
+1 0.013528 1 1 1.959836 -0.639551 0.023139 -2.233489 0.643781 0.382126 -0.599148 0.489966 2.318986 -0.964920 -2.082106 0.242623 49.333762 -47.463357 -16.645684 -14.002707 6.508704 2.001901 0.946588 1.050679 2.271057 2.155888 1.510244 1.920239 0.956923 1.508769 1.877199 2.088047 2.053766 1.889368 1.864966 1.227045
+1 0.015599 1 1 -1.468980 -0.937641 -0.696025 -1.942395 1.603084 2.311872 1.990028 -2.128957 -0.219451 1.486987 1.990819 1.730284 23.209345 -70.539916 35.629798 30.017914 61.076238 2.250057 2.462440 1.227959 0.558892 1.041323 0.268254 1.036979 1.514634 1.459692 0.546211 1.674185 1.034477 2.208939 2.132473 1.720720
+1 -0.008696 1 1 -1.162816 -1.168820 1.596647 -2.212576 -1.304329 0.176087 0.112433 -0.013541 -1.394850 0.886727 -2.073010 2.331616 -24.042296 21.137165 52.327800 23.336099 -40.186551 1.894569 1.523951 0.539291 2.363428 2.138993 1.057301 1.063807 2.395246 1.403167 2.274433 0.394279 1.896829 1.260658 1.133921 1.814871
+1 0.002193 1 1 -0.374566 0.424829 0.826127 2.017141 1.169183 -0.202444 -0.139803 1.807743 1.964484 2.093445 1.833633 -1.152788 -72.571355 -56.760134 32.423100 -14.960335 -38.353936 0.405916 1.726447 1.896088 2.293657 1.744490 1.389189 1.353598 1.669226 0.922539 1.863093 1.247143 1.241198 0.315958 1.814096 1.255363
+1 -0.005229 1 1 -0.500688 1.267260 -1.165813 0.301801 1.834048 1.104243 1.618961 0.541640 -0.988500 2.157734 -1.504634 -1.708398 -14.908496 -67.094727 38.929630 -9.704550 -54.367142 2.146543 1.953397 2.494470 1.807371 0.730225 0.642578 1.303571 2.364144 0.675041 2.417082 1.649125 0.594729 0.363307 1.103740 0.806841
+1 0.007634 1 1 1.186687 1.819091 -0.516638 1.799326 1.875751 -0.129576 -0.661184 -0.703489 -0.152655 -2.132074 -0.757954 -1.350667 -34.382434 -65.560145 30.641478 41.321138 -15.633285 2.145640 0.262303 2.273271 1.109614 0.538397 0.842828 0.902740 2.093686 2.335778 0.913379 0.918730 0.847417 1.533440 0.275680 2.097655
+1 -0.014137 1 1 -0.578797 -1.477715 -1.667210 -0.932356 -1.406727 -0.812742 1.462094 -1.690232 -1.450354 1.092131 0.697501 -1.522345 70.831483 64.742918 34.229564 46.282469 -30.537610 2.190751 2.451060 1.214230 1.561538 2.275637 0.382472 1.450113 1.552112 1.342762 1.798560 1.150615 1.136698 1.238842 1.219423 1.100093
+1 0.017552 1 1 1.849322 -1.358637 1.624279 0.392929 1.898005 1.611006 -1.215118 1.011083 0.396913 -1.823002 0.760987 0.488581 -67.148619 33.154958 -14.616174 45.955534 24.663232 2.349030 0.892729 0.344877 1.847986 1.595915 1.795407 2.148361 0.996341 0.255922 0.775103 1.152253 1.664326 1.831660 1.713239 0.404569
+1 0.022812 1 1 -2.052381 0.327195 -0.188551 -2.244243 -1.036977 -2.056128 -1.403212 1.715184 1.421291 0.537803 0.495711 -0.090684 -64.377362 -40.329340 34.777293 -48.043040 -9.380111 1.352088 1.035111 1.609520 0.949539 1.146074 1.321662 0.425129 0.644225 1.992606 2.226536 0.895219 1.692554 1.499450 0.498647 1.001965
+1 -0.054505 1 1 -1.492167 0.485630 0.130936 -0.041465 0.527341 -0.991650 1.061739 -1.162394 1.205124 0.664308 1.379263 1.028294 70.069562 9.131880 29.509575 67.435106 -18.167539 2.247578 1.301774 1.421943 0.595334 1.529667 2.112084 1.053109 0.350633 1.832644 2.489032 0.415736 0.277384 1.497684 2.326361 2.391947
+1 -0.028335 1 1 -1.617494 0.544951 -1.900787 -1.244606 0.210462 -1.768189 -1.628271 -1.500596 0.183615 -0.598393 -0.960357 -0.784441 37.206910 -13.455846 47.597973 29.128902 -30.550152 1.278943 2.440992 0.758794 1.545480 2.375134 0.880210 1.445669 1.109969 2.000758 1.993084 1.266446 1.659027 0.517063 2.285560 0.656940
+1 0.033717 1 1 -0.978495 0.669772 -1.042240 -0.978498 0.621864 -0.418258 1.230135 1.627858 -0.722873 -0.786688 1.104988 0.006288 64.054279 10.262082 -25.179641 -44.225819 -53.335608 1.201669 1.956619 0.393726 1.599807 1.956745 0.265633 1.986657 1.249613 2.250688 1.805174 2.066348 1.866408 0.724090 1.025964 0.874761
+1 0.021821 1 1 0.593557 -0.213751 -1.679074 2.306940 -0.798283 -0.567674 1.683657 -0.671667 2.181239 -2.294998 -1.132073 1.880183 -33.119706 7.102068 -35.549502 -30.472843 -57.078209 0.423085 2.291872 0.995269 2.485378 1.993316 0.662475 0.472267 0.891295 0.990433 2.199861 0.319580 1.930783 0.417896 0.574670 0.733637
+1 -0.023066 1 1 -0.881469 0.908783 1.059131 2.128661 -0.051175 2.273057 -0.061977 -0.212774 0.617592 -1.528500 -2.274545 -1.370741 26.420413 47.883330 25.125245 29.985754 -29.424562 1.545719 1.908058 0.986672 1.990393 1.043624 0.691813 0.802319 1.833659 1.558197 2.365343 0.567492 1.585719 1.431771 1.521843 1.122190
+1 0.020826 1 1 -1.456462 2.095871 0.200786 0.540293 -0.061911 0.908147 -0.192963 -0.998086 1.276050 0.488988 0.012658 0.689153 -14.573789 8.335143 -11.246613 -21.822526 -21.193338 2.178641 1.428243 0.727440 1.092259 1.349588 1.768350 1.899912 1.321624 2.032741 1.772574 0.907760 0.973708 2.360372 0.272540 1.077351
+1 -0.018640 1 1 0.324876 -1.470186 -2.355686 1.475577 -1.282517 -0.803992 -2.274140 0.721580 -2.093538 1.315670 1.932514 1.974697 -19.723543 6.418500 25.725092 61.615276 -32.058932 1.157941 0.506702 1.389984 1.219978 1.420888 0.867228 1.505988 2.381875 1.667217 0.907668 1.684054 0.391693 1.182123 1.942173 0.598755
+1 0.044082 1 1 1.558350 -0.274518 -0.387039 -1.873536 -0.340558 1.800581 -0.591354 -0.451150 -0.249573 -0.546771 -0.424479 0.335910 6.357380 48.482430 44.193443 -40.798585 -51.818617 1.142437 0.940131 0.523845 1.518522 1.550981 0.334511 0.869065 0.880163 0.651365 0.491197 1.799905 1.247208 2.319946 0.326987 0.423680
+1 0.043166 1 1 -1.446785 -0.191110 1.869625 0.572109 2.166763 -0.561568 0.648790 -0.259271 1.386743 -0.482442 1.616929 -0.628731 -60.915590 -58.326629 -45.656052 58.740936 -41.095648 2.206540 2.314290 2.019002 0.364184 2.337661 1.063915 1.973729 2.208149 2.351463 1.283250 0.589273 0.914319 0.964652 0.907537 1.727200
+1 -0.012580 1 1 0.925617 1.254006 2.266807 -1.443472 -1.062496 -2.119846 2.128409 0.424632 2.231590 0.434844 -0.485877 0.438069 59.398538 61.225930 24.204552 5.910724 41.531953 0.287926 0.930429 1.718345 0.718888 1.356942 1.615302 1.378286 0.355020 1.315888 2.373926 0.823729 1.659415 0.284277 0.340192 1.848864
+1 0.048273 1 1 -2.271986 -0.775502 0.602310 0.821007 0.796570 0.046732 -1.540503 -1.372465 0.120286 0.036110 -0.989229 -0.667846 13.349560 -33.953060 -49.081450 -61.931551 -33.569981 0.465058 1.224694 1.934677 0.620687 2.381837 1.037542 1.969154 1.830054 1.716004 1.877653 0.721357 2.350635 0.878377 2.130097 2.295436
+1 0.020340 1 1 -0.614794 1.426684 1.639723 0.773419 2.079165 2.159351 2.098193 1.514913 0.108828 0.669021 0.468014 0.941675 -69.329456 -20.163545 -38.704509 43.322854 27.202237 1.194877 0.304044 1.812740 0.971706 2.466495 1.884821 1.941280 1.339988 2.427487 1.023709 1.230696 1.563022 2.458812 1.001214 1.146213
+1 -0.006394 1 1 2.037977 -2.069353 -2.178783 1.162625 -2.039044 -1.715752 -1.535277 1.635023 1.890094 0.589395 0.514592 1.516390 43.462127 -32.023460 -18.297343 -23.451619 48.636909 0.482979 0.935961 2.443287 1.075306 2.169838 1.963463 0.676873 1.707719 2.134265 0.337501 1.624035 1.909402 1.064739 2.323696 0.363972
+1 -0.001350 1 1 -2.036628 1.192552 1.430383 -2.157695 2.166019 1.082380 1.741854 1.979740 -0.681705 -1.603223 0.063854 -1.234366 -65.192924 52.524102 22.588627 -2.944960 4.060928 1.405160 2.022733 2.330485 1.957203 1.216915 1.689217 1.670845 1.142215 1.707023 1.682741 0.830283 1.565905 1.407170 2.057819 0.271630
+1 0.008266 1 1 -1.525784 0.974311 -0.300685 -1.933614 -1.619177 0.532559 1.892398 1.620572 -0.661009 2.228321 2.038279 -1.710397 -34.088367 -73.177435 -43.148739 49.148058 -18.588112 1.968910 2.213908 2.402472 1.353735 1.731524 1.729162 0.266634 0.813958 1.688300 2.002819 0.634195 2.166245 2.336351 1.544909 1.779246
+1 0.007426 1 1 0.947583 -1.851931 -0.081322 -0.178414 -1.520606 -1.540605 1.636690 1.637053 -1.683863 1.930602 -1.876848 0.545949 23.877037 51.365388 48.076297 -31.668031 -44.604216 1.929181 0.491045 1.499968 2.460071 1.905303 1.922230 0.665374 1.937442 2.084174 2.212494 1.141480 0.609906 1.189148 0.766927 0.993616
+1 -0.018945 1 1 -2.003005 0.793344 -2.328845 0.198679 -1.883217 1.882877 1.830045 -0.189489 0.834783 1.418298 2.067175 -1.436017 54.582800 -26.877132 -73.962038 -29.968919 12.381856 2.152742 0.381149 1.724285 1.557155 0.612249 2.320990 2.136325 1.216496 1.403339 0.659687 0.852180 0.593699 1.050993 0.788131 1.870584
+1 -0.012796 1 1 -2.135151 -0.634150 1.257314 1.317012 0.931904 -1.470861 0.425447 1.796561 -2.179579 1.925562 -1.769154 0.994797 0.137134 54.803723 -63.828809 29.214259 54.049160 1.438563 0.926831 1.999699 2.186723 2.246423 2.131201 0.588502 1.452989 0.385446 1.938495 1.792557 1.510948 2.496278 0.697466 1.308674
+1 0.048528 1 1 1.774985 -1.964011 1.159518 2.284025 0.490514 2.101967 -1.024940 2.328454 -2.070047 0.296497 2.224034 0.669169 -55.561290 -68.600199 -63.538657 -44.210274 57.921121 1.079100 0.675970 2.272383 1.941993 2.076360 1.384042 0.343146 2.013129 0.666315 1.999423 2.059836 0.408375 0.309561 2.299710 2.224369
+1 0.018614 1 1 2.189551 0.734366 0.735906 -1.655342 0.619774 2.157554 0.177805 0.709128 0.685017 0.712106 -1.097321 1.618000 -46.933908 31.814073 -50.873422 -29.598569 -63.151710 1.513119 0.737056 0.692155 2.047734 1.756428 1.792372 0.649027 1.690957 1.659255 2.093219 1.229427 0.486854 0.811447 2.241500 0.397933
+1 -0.021670 1 1 2.343155 -0.019682 -0.921826 1.196907 -0.767117 0.160401 0.378250 0.231275 -0.676348 -1.099549 1.875626 -2.240343 -46.649787 7.037275 -74.511694 31.954248 55.050776 1.950785 1.341943 1.534825 1.061026 0.665295 0.605437 0.326090 1.092486 0.661603 1.556318 2.289911 1.781993 1.702560 0.935077 1.081875
+1 -0.061313 1 1 0.001832 -2.190492 2.292806 1.992074 -0.729555 -0.002672 2.221085 -1.767784 0.459846 0.310344 -0.660068 -0.803498 41.981944 -9.470591 -22.218829 68.145364 69.133266 1.716928 1.662781 0.613532 1.386046 0.277366 1.195261 2.258920 0.668889 0.267240 1.999300 2.241549 1.219796 0.607657 1.641371 0.777387
+1 -0.007139 1 1 1.471681 -0.781772 -1.104585 2.054610 -0.554284 0.545804 -1.693904 -1.902433 -0.626666 -0.179365 1.335254 1.220240 8.175598 7.272577 -19.795262 1.029281 49.131318 1.376049 1.011440 2.028778 0.422324 0.753553 1.223292 0.866490 0.343153 2.115475 1.785970 1.050222 1.327611 1.405539 1.638841 1.002156
+1 0.000963 1 1 -0.137863 1.423585 1.392247 -2.230647 1.277664 -0.649489 -2.068417 -0.593034 -0.422198 0.969990 -2.235806 -0.604182 22.716193 41.054463 2.356480 5.362573 -21.237924 2.188183 2.042316 0.701150 2.471937 1.092966 1.985129 0.307811 2.128181 1.585082 1.979330 1.852509 1.117069 2.082290 2.054809 1.426712
+1 -0.038543 1 1 1.345472 -1.403070 -0.607138 -1.847408 0.551492 -0.344040 -0.181065 1.040908 2.155878 0.281920 2.277466 -1.363825 -23.707738 -55.960491 -27.977124 38.479320 71.927149 1.818978 2.305758 0.376379 0.307912 1.576742 1.297012 2.380209 0.669965 0.356988 0.653979 1.671388 1.275647 1.042319 1.260783 0.974114
+1 -0.005918 1 1 0.919241 -2.232098 0.456321 2.332973 -1.504319 -1.128453 1.461467 1.909583 -1.714548 -0.149208 -0.740448 0.712728 -2.069020 25.978045 -36.998026 74.182350 -17.244302 1.000353 2.428756 2.109879 2.233354 0.736337 2.111960 1.216174 0.490389 1.712158 2.482092 0.767619 1.379773 0.600831 1.664433 1.368321
+1 -0.030505 1 1 -1.307095 0.802940 -1.269875 -0.371106 2.026012 -0.541405 0.237120 -1.411072 1.559316 1.822290 1.416959 -1.583788 49.837585 20.293298 -30.534830 -48.882614 -20.091443 0.971840 2.468517 2.120284 1.611531 0.998149 1.384518 1.591657 2.224923 0.777571 2.140999 1.012635 1.852006 1.672110 2.146026 2.254652
+1 -0.006616 1 1 -1.368013 -0.452094 -1.976023 1.902013 -1.710212 2.032868 1.591785 0.892723 -0.250671 -0.148543 0.999986 -2.325023 -48.805217 -69.273739 16.274841 -68.738939 4.652537 2.052881 0.529787 2.387165 0.587329 1.983356 2.012929 1.794480 2.324158 1.368874 1.922038 1.950667 1.613464 1.992365 0.430194 0.267220
+1 0.010474 1 1 0.725762 2.222731 2.325521 0.483655 -0.077655 0.175783 -0.279126 2.274318 2.278275 -1.901862 -0.461304 -1.258263 50.292016 7.912054 -72.112759 0.855711 -18.062124 1.823176 0.861892 1.811945 1.113162 1.667043 2.489961 0.271830 0.388453 0.734354 0.285421 1.574036 0.822218 1.021021 1.052972 0.299428
+1 0.008038 1 1 -1.542802 -2.311919 1.929606 0.221589 1.461634 -0.000632 -1.198045 0.495330 -1.784838 1.287316 1.348801 -1.997665 32.350415 -36.574791 -12.513198 -9.324643 30.730434 1.920951 1.680722 0.649867 2.316686 1.799043 0.266491 0.672047 1.596412 1.143039 2.063576 0.277613 0.841907 1.175212 0.536748 2.366637
+1 -0.054780 1 1 -0.115610 -1.544645 -0.296593 0.868030 -0.580502 -1.855818 0.576979 -0.811555 -2.159014 -1.151282 -0.522885 0.482483 -29.479077 -4.840399 -52.590904 54.669788 -64.875353 1.224054 2.425024 2.377236 2.462910 2.379424 0.984996 0.835486 1.262855 2.059226 1.419095 2.230760 2.139754 0.348860 1.292428 1.834738
+1 -0.041282 1 1 2.176133 1.416666 -1.798576 1.311778 -2.209831 -2.286640 -2.028687 -1.999744 -0.936703 0.925646 1.740317 -0.290727 15.819615 -69.724350 -57.157903 -52.876000 63.062864 1.338358 2.038040 0.829194 1.265548 2.320613 0.288760 1.440729 1.340180 1.158165 2.033428 2.074066 1.085579 1.577812 1.289575 1.131519
+1 0.022147 1 1 -0.376054 -1.023859 1.651369 -1.407942 2.336143 -0.065701 -1.536422 1.250233 0.115883 1.431672 0.662083 1.675392 57.170786 -30.600842 41.653236 15.945829 -48.450356 2.047933 0.614528 2.368820 0.502647 0.746312 1.011647 1.006093 2.148130 1.615245 0.416781 2.095826 2.301832 1.891294 0.471160 0.288058
+1 -0.020369 1 1 -0.834052 1.440107 1.044609 -1.614986 0.294768 1.449536 -0.706449 1.928418 -0.888722 1.518807 -0.420795 0.997473 -68.736114 52.128467 -26.854354 8.877728 -42.024545 2.026987 1.822378 0.958409 1.722513 1.032542 1.178535 2.388949 1.315049 1.769979 2.286489 0.524655 1.629637 1.555048 1.185428 1.230911
+1 0.025629 1 1 1.722582 -1.488190 1.357002 -0.832003 -1.823607 0.010178 1.422106 0.101447 -0.871628 1.369834 -1.927247 1.727701 -8.691110 28.515203 5.010886 67.954217 6.519819 0.303986 0.835299 0.368692 1.601102 1.225858 1.241424 1.862988 1.740085 1.600071 1.893099 1.566228 2.346728 0.450944 0.260913 1.413067
+1 -0.007919 1 1 -2.264272 1.634496 -2.247863 -0.610184 -1.204358 -1.927461 -1.870731 -0.322290 -2.193994 -0.006200 -0.535134 1.953825 64.175123 -58.714092 42.259618 7.398877 2.927393 1.385410 0.832815 1.366017 1.153964 1.177231 0.724154 2.111984 1.617280 0.867800 2.112723 0.530678 1.604920 2.397552 1.910934 2.070604
+1 0.025590 1 1 1.637025 -2.158852 1.576356 0.757639 0.757776 -1.649668 1.729801 2.039976 -1.459939 0.208419 1.585699 2.280209 73.812812 71.934148 -2.778210 -43.377678 -48.626908 0.288377 1.758058 2.189621 1.453832 1.055710 1.311183 2.049015 0.787480 2.184608 0.461568 1.076378 2.178002 1.935354 0.737932 1.929932
+1 -0.011230 1 1 -1.693812 -0.349673 -0.608021 2.154563 1.749257 -0.823855 -1.535453 -1.315154 2.027935 -1.205710 -1.093995 0.965723 45.977214 -60.964495 19.737897 -65.165971 55.517094 0.262069 0.588483 1.138363 2.217709 1.037839 2.463266 1.618428 2.172768 1.718611 0.687908 0.413380 1.183086 2.370605 1.252502 1.304684
+1 -0.016104 1 1 0.255916 -1.235973 -0.791084 -2.100643 -0.291297 0.350251 0.898667 0.696042 2.224275 0.014748 -1.880794 0.191611 58.766154 -67.255491 36.967995 21.084922 74.287824 0.706918 0.422450 0.614049 1.078047 0.986798 1.866315 1.409360 0.610212 1.824892 0.461769 2.200995 1.364952 1.244007 0.274391 0.687579
+1 -0.008294 1 1 -1.453690 1.562216 -1.263234 -1.860543 1.271478 -0.949157 -1.042893 2.187340 1.275864 2.073434 0.093297 -1.189139 -19.822092 0.094233 -66.223242 -14.021083 -2.348393 1.083405 1.036989 1.676499 1.674227 1.725485 1.476214 1.476481 1.472830 0.859225 2.000794 0.349373 0.920049 0.514324 1.246158 0.431524
+1 0.040499 1 1 1.557115 -2.169101 -1.041743 -2.044774 0.935783 -2.245742 2.043722 0.227576 -1.593753 -0.991225 -1.227138 1.612915 -67.274989 9.261870 -35.757098 -69.543392 -15.795199 1.826401 1.064081 0.260212 0.876279 0.620265 2.044258 1.837755 0.650361 1.623959 0.623885 2.141117 0.749302 1.765878 0.855010 0.906801
+1 0.041532 1 1 1.994365 0.062264 0.328537 -1.207011 0.604586 1.360673 -0.398365 0.984251 1.816982 1.745059 -0.701317 -1.354542 -7.786049 -60.122199 -73.802904 -55.406228 -12.473237 2.309534 0.841059 0.432486 0.538564 1.399403 2.011257 0.690252 1.566336 1.908552 0.277743 0.782014 0.315233 0.863295 0.643604 0.550114
+1 0.002247 1 1 1.920232 -1.807540 1.448437 -0.324523 -2.017838 1.268515 1.089466 -1.684469 1.157296 -2.065111 -1.574915 -0.110263 -38.617480 6.009049 44.080779 15.647765 41.990858 1.230332 2.189694 0.437982 0.663944 0.408946 0.911630 0.769107 1.632399 0.735905 1.602161 1.027359 1.826481 2.409909 0.346914 2.334188
+1 -0.012128 1 1 -0.292173 -0.248602 1.633719 -1.168746 -1.879089 0.584577 -0.352151 0.164652 1.140853 -0.388286 0.739986 0.947146 7.181671 -47.658286 7.181751 -46.307064 67.180874 2.259277 2.171892 0.493230 2.221445 0.827025 0.811346 0.534892 0.432273 1.459397 2.340822 2.451902 1.873946 1.404172 1.165021 0.263289
+1 -0.039027 1 1 0.755728 1.626217 -0.028000 0.651072 0.404129 1.649253 0.718291 -0.816204 -0.178035 0.130140 0.710334 2.095908 25.793179 5.951770 -18.596685 45.516777 0.477718 0.310012 0.873606 0.702120 0.777367 0.960402 1.468771 2.387385 2.025920 1.887521 2.318095 0.727606 1.621452 1.240268 0.440794 0.678321
+1 -0.031055 1 1 -1.915465 1.828309 -1.104135 0.196206 -1.034938 -0.768549 -0.350331 -2.241132 -0.580534 2.329175 0.622357 -1.547194 -23.256522 27.629315 -34.098610 54.656138 5.703241 1.440536 0.342210 2.015704 1.180098 1.664043 1.567368 1.249129 0.859190 1.397992 0.795855 1.186923 1.613863 1.947998 1.757075 1.407277
+1 0.062738 1 1 1.990188 0.545424 1.341148 1.318913 -0.103054 2.123550 -1.125477 -0.362693 2.043344 -1.415167 -1.282565 -1.608991 66.316616 -66.636527 -60.103808 -64.694580 28.189828 0.421463 2.023753 1.465315 0.541737 0.724577 2.466521 2.326569 1.394425 1.598991 1.746208 1.021274 0.803530 1.925817 2.459458 0.617896
+1 0.013367 1 1 1.261672 -0.828486 0.744335 -1.357162 -1.854991 0.329342 -1.807266 1.339300 -1.467327 -1.439701 1.068549 0.193973 -27.835970 10.847110 57.381157 55.108607 -39.642671 1.759412 2.444028 2.280808 1.797374 1.466025 1.230177 1.827948 2.331163 2.106269 2.314772 1.124066 0.430078 0.576478 1.862374 0.419273
+1 -0.004933 1 1 1.152355 -0.284315 -0.128176 -0.689060 2.020234 1.318298 -1.021450 -0.277926 -1.132069 1.936021 -0.342057 0.159302 23.895458 60.966773 18.553006 -29.628649 31.302011 2.018475 0.516728 1.143143 1.554347 0.655719 1.661189 0.857492 2.123570 0.589957 1.154654 1.523310 1.022752 0.899609 1.226284 1.651730
+1 0.033448 1 1 -1.397152 -0.091748 -1.050564 0.488737 0.508786 -1.815380 1.634270 -1.348516 2.081342 1.043211 -1.549712 -0.641465 26.887776 -47.154162 -69.999498 -31.554839 57.823363 1.183855 1.799569 2.357186 0.717916 0.762982 2.187336 1.299643 1.590846 2.105039 1.885413 0.634318 1.983317 1.353688 0.939087 0.982152
+1 0.003035 1 1 0.272272 0.343090 -1.646697 -0.167494 -1.782002 1.830141 1.416121 -1.532689 -1.985453 -1.073664 -1.333849 -1.168380 -13.772098 -17.644708 -4.614704 -9.334427 16.290980 2.162605 1.896057 1.775027 1.629883 1.191303 0.985306 1.532704 1.404139 0.607510 1.418951 2.056272 1.271823 2.031927 1.590635 0.802479
+1 0.021392 1 1 0.566606 -0.791557 -0.625174 1.335154 -0.456255 -1.219244 2.343720 0.042340 0.030870 0.470340 2.324844 -1.484481 -72.922815 36.242666 -19.520237 -26.617639 -62.661418 1.368189 1.653000 0.477171 2.315730 1.470597 1.573757 0.631762 1.767289 2.077103 0.374939 0.850330 0.990761 0.964840 1.809484 2.499654
+1 -0.035782 1 1 -2.175927 2.049770 -1.798355 0.310382 -0.024315 1.309500 1.905801 0.696665 -1.444286 -0.599622 1.960273 1.988428 -24.098015 -15.343484 -27.941826 31.737676 15.112872 2.155513 1.955135 2.454088 0.363737 1.569551 1.937518 1.117260 0.793634 2.100422 0.797134 2.431119 1.311770 0.676176 1.244362 1.741911
+1 -0.025600 1 1 0.241911 -0.992322 -0.809437 0.454765 -0.252383 -0.653774 1.308534 -0.185179 -2.130061 0.083255 -0.306503 -0.753922 14.337799 -74.618558 35.897594 30.856045 47.546565 2.351783 2.166863 1.467403 1.897857 0.540712 1.500767 2.395990 0.403097 1.609108 0.779353 0.592269 1.767303 2.307380 0.644164 0.964626
+1 -0.002294 1 1 -0.623264 0.442003 2.020356 -1.344841 -2.125749 1.862075 0.922203 0.422305 0.827695 0.098302 -1.892349 -0.791969 59.963514 -43.213602 8.996648 6.672071 -62.505748 2.363295 2.142817 2.330567 1.080731 1.098734 2.173262 1.018998 0.792381 1.294223 0.512887 1.838093 1.835129 1.510408 2.422419 1.344928
+1 -0.010755 1 1 1.257108 -2.131020 -1.892473 1.841112 2.030093 2.070856 -0.828485 0.755879 -0.549799 0.522248 -1.755931 1.755985 -27.234959 62.038250 26.871362 -23.020765 -59.994194 1.038798 0.586687 2.443062 1.799038 2.430716 1.300774 0.350982 0.952256 1.817846 1.289671 0.494674 1.737631 0.867964 0.366171 1.977805
+1 0.011220 1 1 -1.880380 -2.263747 1.032661 0.211919 -0.845718 -1.422260 2.034111 -1.077981 1.512939 -0.080548 -1.322957 -1.891783 -22.558746 55.153684 -32.041126 -15.211793 -64.596858 1.684076 0.766331 2.231619 0.824440 2.357258 1.930301 1.314628 1.446698 0.406241 0.446786 2.377333 1.828672 0.987324 1.709369 0.613872
+1 -0.065975 1 1 -1.720346 1.358651 -1.388758 -0.391444 -0.505082 -1.894963 -2.311737 0.277114 1.614896 -1.805152 -0.822966 -0.729698 73.788647 -34.212154 -53.678784 70.669140 36.236977 1.898198 1.767196 0.516512 2.009792 0.826775 1.101817 2.245357 2.214552 1.970853 1.123863 1.523888 1.733207 0.752950 2.323520 1.902487
+1 0.009699 1 1 0.534470 1.019900 -2.211946 -0.131676 1.736456 0.793326 2.089160 0.506752 1.690273 2.140395 -0.752763 1.072370 -49.947021 -59.579686 44.213511 -3.514158 37.545422 1.013509 0.793436 1.027647 2.166493 2.002120 2.373786 0.718710 0.603776 1.659084 1.481632 0.291797 0.740479 1.979111 0.425416 0.974799
+1 -0.016723 1 1 -1.814719 -1.402264 -1.194411 0.307156 2.308992 0.710914 -2.292422 -0.235112 2.173873 1.137306 1.251667 0.668143 -4.318519 18.654350 23.667921 -13.252778 10.557472 1.216496 1.403761 1.012727 1.154868 0.610806 0.570424 1.361927 2.160993 1.811427 1.398516 0.603021 2.474907 1.517233 2.385129 2.368296
+1 0.006737 1 1 0.954048 -1.572628 0.631768 1.115991 1.156471 -1.792469 0.281374 -2.192935 -1.063084 2.124353 -1.772645 -1.117408 -44.471865 11.361925 9.869085 -30.290544 6.820917 1.962193 1.834593 1.506933 0.272095 0.343262 1.701054 0.362841 2.272377 1.847589 1.684675 1.833744 0.740593 1.641520 1.025869 1.535502
+1 0.048631 1 1 1.078101 0.505515 -0.241745 -0.921655 -0.638440 -0.148308 0.233816 -0.384492 -1.467902 -1.679303 -1.554453 -0.208672 -36.313913 22.068131 -50.928289 -51.746397 -1.693020 2.056244 0.800333 2.202302 0.842506 2.248594 0.376169 1.271677 1.818698 2.110653 1.739201 0.252482 1.464075 2.202767 1.903177 2.204819
+1 -0.014181 1 1 0.118113 1.205801 -2.087320 2.143214 -0.505023 -0.904747 0.789363 1.442467 -1.696066 -0.544318 -1.599597 -0.254214 49.606126 30.167892 31.755683 17.760919 7.763025 0.972498 2.277036 1.397250 1.830897 2.378854 0.401171 0.730673 1.420831 2.152941 1.485110 0.250127 2.384462 2.406347 1.222706 2.274529
+1 0.013966 1 1 1.060256 2.181745 1.483333 1.834783 -0.677345 1.001728 -1.315962 -2.135279 1.924505 -0.685200 0.921170 1.913240 -48.073445 -70.398196 17.518367 -18.808802 -69.539208 2.192941 1.015638 0.571828 2.459593 0.625606 1.815235 2.405810 1.189753 1.937126 1.271245 1.317898 2.407410 1.082512 1.783223 2.128028
+1 0.032922 1 1 1.981616 -2.148613 -0.697582 0.164464 -2.028654 -1.453169 0.901224 1.259637 -2.053368 -2.126398 0.379844 -1.242265 59.107695 -26.965826 -64.629459 72.675480 6.797738 0.618660 2.072574 0.748833 0.641707 2.416942 1.536199 1.653040 1.137838 2.393885 1.021673 0.753968 1.444491 1.566482 2.121903 1.829446
+1 -0.002460 1 1 0.481192 0.929323 2.270215 -0.717325 -1.796500 -1.505382 -0.136258 0.134265 -0.639601 -0.806829 1.883328 -0.026183 -57.221881 71.841909 -53.033259 -29.990864 -56.452622 0.636654 0.750751 1.370815 0.784466 1.025980 1.140715 1.246202 1.162311 1.968674 0.510719 1.402997 1.666033 1.275413 1.620721 2.463589
+1 0.010894 1 1 0.040648 -0.131074 -2.266578 0.573852 -1.537340 -0.043420 0.660598 0.280035 -1.131435 -1.534048 -1.256249 -2.277268 -0.658589 31.093367 -13.783865 -65.419799 -10.559308 1.070678 0.878946 0.444236 2.266943 0.516267 2.394914 0.322365 1.485962 1.056845 2.401370 0.830498 0.678952 0.642835 1.132613 2.334358
+1 0.001737 1 1 1.330130 -0.071328 -1.856350 1.056959 -1.390397 0.338540 1.988132 -1.011202 2.323243 -0.100783 -2.119542 -2.198360 64.054040 6.245981 -23.795627 -33.096903 -59.650804 2.109051 1.823022 0.529554 0.708365 2.242485 1.200739 2.075291 1.421943 0.602677 1.194997 2.308778 1.631595 0.719493 0.271100 1.628643
+1 0.025436 1 1 0.767509 1.707426 -1.749155 -2.161586 -1.966183 2.348165 -0.649904 0.385244 -0.018601 -1.605881 -2.196668 2.170683 -20.510033 -12.117259 45.226218 67.045177 28.295766 2.379024 1.008285 0.744457 1.338765 2.116727 0.324718 0.538086 2.359669 1.957049 0.866862 2.099854 2.487521 2.021338 1.373711 2.218737
+1 0.004066 1 1 -2.293405 2.091250 -2.077432 -1.305706 0.597335 2.016503 -0.135024 2.029291 -1.971388 -0.318618 -1.731293 1.160696 -46.972397 -15.082304 11.709817 6.890078 1.544025 1.381486 2.379478 1.895188 0.667171 0.650616 1.402269 0.683272 1.246212 1.334531 0.707703 2.355834 0.499150 0.459093 2.222308 1.837501
+1 -0.048937 1 1 0.557670 -0.182196 0.882345 -0.312032 0.573067 -0.591400 -1.231993 0.136605 0.980601 1.740425 1.523665 1.123856 44.190256 55.625613 -50.324241 50.482454 58.598114 0.752414 2.327653 1.606893 1.799072 0.756401 1.825856 0.911667 1.380010 2.327528 1.770539 0.455509 0.489610 2.123688 0.321517 0.740119
+1 0.012717 1 1 0.189872 0.892896 -2.052161 -0.699870 -0.596266 1.816989 1.858468 1.554496 0.937402 1.400751 -0.667084 -0.907236 43.923001 63.877418 37.769471 -8.497799 -22.501039 1.000589 1.890891 0.457046 1.577940 1.179549 1.423353 1.789569 0.789048 1.529963 0.344380 0.252308 0.782262 2.226564 1.360246 0.904850
+1 0.033925 1 1 1.481720 -1.707522 0.121416 0.181064 -1.053964 -0.103053 2.148334 0.728347 -1.461733 -1.665831 -1.322882 -0.620130 40.881530 -54.119924 6.441182 -43.059897 42.314831 1.905402 1.341066 0.296784 1.299307 0.448429 0.752446 0.606179 1.551033 1.209888 0.587785 0.646549 0.553958 1.373510 1.080156 0.425770
+1 0.010242 1 1 0.793419 -1.064937 -0.743800 0.917787 1.600233 1.515381 -1.455635 1.866785 -0.024414 -0.346379 -1.786883 -0.093866 32.983483 -46.600347 -62.034752 31.916802 25.693292 1.032282 1.312178 0.779446 2.150079 0.620766 1.463243 1.732985 1.535356 0.973196 0.512898 2.026513 0.607378 1.458540 1.424345 0.466169
+1 0.028132 1 1 1.972560 1.163866 -0.032158 1.448604 -2.220723 -1.575039 -2.186620 1.397767 1.017999 -1.177651 -0.746351 0.455726 55.628227 -6.391308 -18.720694 61.293989 -31.922666 1.761385 1.853560 0.788086 1.103574 0.271996 0.939217 0.926063 0.345035 2.256871 2.237717 2.052839 2.056942 1.274168 0.940869 1.692509
+1 -0.013657 1 1 -0.449614 2.004003 1.835655 -0.154097 1.904393 0.591659 0.871181 0.540203 -1.583948 -1.132217 -0.551300 -1.150269 74.949816 -18.434119 -72.237060 11.736355 2.920341 1.857501 1.775020 1.510580 0.812145 0.476675 0.734755 0.283563 1.848413 2.032582 1.362245 0.747237 0.807094 1.080841 0.699158 0.494433
+1 -0.066389 1 1 -0.381631 -0.517101 -1.277346 1.295341 -0.440693 1.154916 0.348763 -0.554888 -0.189257 0.024872 -1.371546 1.435514 -23.748466 9.536644 -67.619692 65.834288 -73.126021 2.439557 1.386388 1.518131 1.734585 1.413534 1.014394 2.176966 0.261079 1.958495 0.431738 1.470257 0.351957 1.591384 2.133272 1.655530
+1 0.009052 1 1 1.464248 1.526992 0.491347 1.971021 -1.146212 -0.133276 -1.589616 -2.149305 1.805728 1.078464 1.904992 1.222457 -5.578874 -14.140337 -56.648298 -37.947535 15.774414 2.433661 1.295619 1.469854 0.332120 1.194257 1.134955 1.186141 1.968374 2.218868 0.266999 2.455705 0.533314 0.907215 0.804547 1.022188
+1 0.009689 1 1 2.268737 -1.984190 1.296794 0.414507 1.714707 -1.885001 0.172895 -1.694405 -0.893359 -1.011787 1.912698 -1.204738 35.116026 -54.958121 18.853249 66.562241 11.579946 2.487375 1.814678 2.036818 0.547225 0.711195 0.311081 0.844580 1.106441 1.201935 1.927188 0.744647 2.277445 1.511790 0.901028 0.329373
+1 -0.013156 1 1 -0.954409 0.217630 0.894382 -0.637072 -0.728365 1.149094 1.449862 0.067896 0.727721 2.165743 1.148772 0.753262 -67.370837 48.340328 55.888034 10.195632 57.993161 1.240905 2.149064 1.560424 1.539608 0.448977 0.960682 1.679655 0.704744 2.131680 1.888854 2.221091 1.626357 0.428544 1.795537 2.090229
+1 0.023808 1 1 0.650613 2.115674 -1.562120 -1.833366 0.927661 -2.097227 0.576547 1.351263 1.681118 -0.938075 1.423680 -1.719843 12.421089 -38.750371 22.507267 -20.359979 -40.168769 1.877535 0.980728 1.095759 1.670282 0.677693 1.981368 2.349347 1.721946 0.502495 0.435633 1.688896 0.773145 1.996066 1.883905 2.286443
+1 0.017784 1 1 0.462074 0.057918 -2.029719 -0.504531 -2.057067 1.679797 0.429204 -1.027422 -1.689965 -1.677768 0.695361 0.209374 -38.468814 -45.352519 60.208688 27.426163 1.526100 1.362491 0.388493 1.409619 0.464436 2.017939 0.499588 1.077840 2.015788 0.344198 1.687756 1.859403 2.239565 1.624714 2.069614 0.505291
+1 0.016676 1 1 -1.560630 -0.357055 -2.151030 1.084633 1.902199 1.415554 -1.632624 0.733527 0.773174 -2.033498 1.962225 1.812204 49.194528 12.437364 -65.222288 9.010866 -54.371658 1.008241 2.255570 0.606186 1.668258 0.415763 0.733202 1.172888 1.974832 0.498942 1.476179 0.881216 0.340202 2.024024 1.530410 1.106063
+1 0.054227 1 1 -0.701673 2.090219 -0.542055 -1.273178 0.664400 -1.792205 -0.006894 1.946674 -0.367373 -1.203182 -1.021027 2.120543 5.182221 -52.411869 63.712326 -36.932788 -29.372666 1.129118 2.082146 1.881924 0.491143 0.896969 1.851052 1.378319 0.902617 2.284733 0.256011 2.270822 0.450674 2.475366 2.469660 1.075090
+1 -0.015254 1 1 1.383464 0.953148 2.143184 -1.005902 1.853410 1.374261 1.784390 0.604280 0.941454 -1.189303 1.339894 -0.913167 20.534926 -19.501476 -11.301439 -43.291807 44.591585 2.136489 1.716017 2.101380 1.143453 2.273277 1.215711 1.697538 2.017477 1.728590 1.919549 0.601247 1.911958 1.278548 0.309318 0.464011
+1 -0.037563 1 1 0.308025 -1.938827 0.310033 -1.176800 -0.585569 -2.191838 -1.477060 -0.085364 -2.144005 1.352564 -0.014365 -1.101296 24.601770 -68.046814 -62.810173 49.422450 -56.889852 0.658847 2.489763 1.449688 1.162373 0.759386 2.498097 2.020716 2.167326 2.498808 0.468523 0.971430 2.323020 0.252431 0.614160 0.692241
+1 -0.033024 1 1 -1.989341 -0.458256 -1.865428 -0.718177 -1.975907 -0.868043 0.351988 1.817481 0.692650 1.771858 2.037420 -2.011290 -56.622373 -52.225775 41.399492 -48.737088 25.760085 2.121310 0.860240 1.056153 2.016322 0.322368 1.543527 1.050162 0.317416 1.566881 2.065175 2.392390 0.657527 0.554067 0.947625 0.487052
+1 0.013710 1 1 -0.845352 0.017048 -0.927510 -0.078310 -1.392933 0.119413 -0.506204 -1.915628 -0.916478 1.549850 -1.758934 -1.594619 -44.880174 48.920000 48.441673 -40.802482 32.678194 2.461016 2.042265 2.095671 1.938044 0.953112 0.450496 1.736199 1.551661 0.517457 2.144007 2.080452 0.407019 2.274831 0.329573 1.139884
+1 -0.015684 1 1 2.354054 -0.633438 -0.906434 0.725412 1.042437 -0.415385 -2.324736 -1.413515 -1.794583 -2.272253 -0.555944 0.916384 50.081008 61.494958 45.758300 9.752486 -39.959014 0.757862 1.643884 0.253365 0.554197 0.894741 0.419161 1.596143 1.129169 0.696958 1.774629 1.690345 0.371884 1.247594 2.063668 1.820948
+1 -0.015637 1 1 1.372854 1.695833 1.345119 2.081154 -2.104204 1.113541 -2.329424 -0.108416 1.553195 -2.090531 0.009833 0.332466 -36.034120 74.543665 55.385090 -42.784447 21.803211 1.323533 0.363789 2.458223 2.356055 1.968187 1.328138 1.271080 0.784303 0.526723 0.382074 1.514114 1.720657 1.327557 0.504047 1.761407
+1 0.019295 1 1 0.679812 -1.942800 -0.505021 -0.882066 0.298048 0.015900 -1.366995 -2.184931 1.510106 -0.572588 -0.789286 -0.148870 7.175333 -4.172433 73.923349 -20.280275 -50.587058 1.124788 1.303539 1.831814 2.053536 0.282080 1.663777 1.599158 2.306851 0.746557 0.625962 1.039782 1.360402 1.280947 2.370722 0.971120
+1 0.030062 1 1 -1.200862 0.275361 0.418259 -1.208744 -0.252231 1.906092 0.867159 -1.081437 -0.023592 -0.665159 -1.540377 0.752944 62.507766 -31.983651 50.779747 -44.789481 73.191895 1.167627 1.302007 0.834314 1.809476 2.357811 2.228432 1.264022 1.422041 2.248111 1.245536 1.221828 1.017294 1.402213 1.993092 1.394607
+1 -0.012412 1 1 -1.771653 1.416033 1.706898 -1.184496 2.022675 -0.082089 1.061246 -0.037514 0.955035 0.874770 -0.400083 0.388772 -63.287397 -21.273211 61.148723 -73.407080 -2.786524 0.878384 2.253820 0.460560 2.136166 0.793646 2.315238 2.213459 1.597101 1.475929 1.188117 1.431369 1.510776 1.863155 2.300727 1.325354
+1 0.043680 1 1 -1.303378 2.025055 2.227749 1.841827 -0.095962 -1.199175 0.359485 0.588183 -0.999786 0.970345 -0.995840 1.326859 47.521745 -52.036789 67.683715 -39.799692 -63.419526 1.495440 0.611594 0.307956 2.324099 0.386362 1.582537 1.953026 0.749215 0.309339 0.817641 0.594906 1.084530 1.938475 1.450373 1.415774
+1 -0.016149 1 1 1.812353 -0.674191 2.162707 1.968371 1.438169 1.458788 -0.704589 0.202090 -1.098983 1.959480 -1.898511 -0.691921 33.589151 -67.139253 40.567115 61.493638 23.581109 1.790487 0.460296 2.198668 0.505649 1.697890 1.184546 2.169667 1.345255 0.958274 1.719241 2.283917 2.300334 1.461430 0.498451 2.223301
+1 0.010650 1 1 0.788022 -2.237668 1.087035 -0.131543 -0.735529 -1.440269 0.941728 -1.286011 1.743858 -2.036233 -1.604286 1.048599 -17.132217 58.822771 -15.681297 -5.561056 -14.672535 1.355505 2.219810 0.347347 0.617671 1.195985 0.912493 1.765865 0.649879 0.268489 0.500910 0.799724 0.965699 0.499628 1.755659 2.359005
+1 0.000787 1 1 1.205204 2.008248 -2.216290 2.243811 -1.517683 0.466576 0.327418 -1.152734 -1.370524 -0.241079 0.832129 -0.770159 27.911995 66.892979 20.295105 -0.162256 -27.034388 1.120644 1.413320 1.914942 1.922438 1.922730 2.321047 0.836894 2.434515 2.147858 1.543422 1.545726 2.024333 2.210706 0.329764 2.093972
+1 0.071274 1 1 0.523503 0.488763 0.941473 -0.866632 0.511024 -1.898227 -0.627202 0.238213 -1.891655 1.436031 -1.485886 -2.343499 -33.043531 -62.623274 40.639451 -72.742899 60.089955 1.103189 0.548207 1.472003 0.460269 1.734186 1.468114 0.344327 1.601854 0.366469 0.250725 1.192630 0.786308 0.481000 1.412672 2.284259
+1 0.003858 1 1 0.417666 -1.753721 1.210946 -0.438377 -2.335437 -2.202603 1.370683 -1.804563 -0.347473 -1.331416 2.021657 1.671401 21.987768 -51.578051 -22.303222 -0.260408 -26.670631 0.575672 1.816696 2.202653 2.241544 1.126607 0.387214 2.398800 0.380266 0.384057 1.089421 0.895593 1.237889 0.957787 0.279687 1.951831
+1 0.010906 1 1 -2.111191 1.505777 2.067778 -0.724044 -1.618733 -1.417346 -0.215219 1.923490 1.102073 -1.859159 0.964082 2.128484 53.715034 -61.425034 -70.542083 -0.793342 16.305674 1.367009 2.072323 1.030747 0.265600 1.444801 2.263736 0.605107 1.527953 0.309858 0.531883 1.601847 2.497008 1.707927 1.132992 1.950694
+1 0.070427 1 1 -1.687229 1.892247 -0.915654 1.268172 0.028593 -0.093003 1.412115 1.825668 1.639829 -2.151243 2.226213 -0.400500 -61.035749 22.166047 -55.240058 -69.652150 -43.689524 0.777647 1.164734 2.189002 2.301490 0.637093 1.364339 2.198007 0.658355 0.966952 1.318612 0.906883 1.983325 1.485970 1.190782 1.223308
+1 -0.039162 1 1 2.157000 0.294435 0.553041 2.128719 0.924657 -0.750711 -2.129679 1.784528 -1.793574 0.550186 1.276242 -0.986475 -48.039282 53.783385 37.345490 65.654036 47.389356 0.968533 0.876212 1.745856 1.858888 0.337819 2.479896 2.104535 2.421805 2.276389 1.764578 1.510723 0.977670 1.450955 2.194694 1.216293
+1 0.023338 1 1 2.080674 -0.748155 -1.592381 -1.486751 1.971812 -1.984238 0.487774 -1.531336 1.910989 -1.646054 1.199631 -2.112447 -24.041689 31.329445 53.989299 48.147193 -40.119747 0.736168 1.532176 1.532346 2.146240 1.354633 1.065677 2.335139 1.434366 2.395720 0.373326 0.740589 1.575256 1.078302 0.764140 1.397900
+1 0.009536 1 1 -0.814803 -0.190975 -0.572966 2.276267 2.044001 0.209940 -1.109594 -2.030360 -1.846614 -0.246187 -0.183200 -1.855895 -23.137035 -64.146247 -55.966881 14.636481 -4.665571 1.911112 0.554101 1.517639 2.463007 1.749659 0.516742 1.388300 2.159791 1.864634 2.397247 1.274821 0.660602 0.489037 1.502478 1.893575
+1 0.032783 1 1 -0.381472 2.169967 1.456634 0.789063 1.120577 -1.882768 0.011344 2.162502 -1.482611 0.861493 -2.054784 2.351422 71.956953 -69.485298 60.604629 -67.994801 61.376881 1.543664 1.103902 1.287467 1.716002 1.848070 0.758518 1.412518 1.930878 2.019940 0.379712 2.320781 0.864406 1.323952 0.658015 2.004433
+1 0.000253 1 1 2.117494 0.752709 -1.985873 1.288865 -0.900196 1.885548 -0.415990 1.647503 -0.412034 2.159692 -1.594188 1.130435 -36.251574 19.796314 16.654009 3.924102 -47.624723 0.944168 0.885241 0.487679 1.170818 0.939976 2.427473 0.784803 2.191060 0.893858 1.319547 0.881716 2.002831 0.827686 0.674982 1.416731
+1 -0.031911 1 1 2.305919 0.896456 1.230975 1.612165 -0.582193 -1.991945 -1.799669 1.790407 -1.952256 0.799667 0.278202 1.051700 -8.080852 -64.886617 -49.370419 31.366873 -66.959619 2.270145 0.323743 2.149258 0.325563 1.243093 0.661482 1.784432 2.205993 2.125142 2.266192 1.381854 1.813541 0.932138 1.190642 1.127569
+1 0.066394 1 1 1.009236 2.346518 -0.058739 -2.343974 0.401307 1.336897 0.555019 -2.328940 -1.395387 1.291618 -1.760911 -1.826778 -45.861934 48.479252 -9.214483 -67.818653 21.902191 1.526958 1.586558 2.033094 0.961039 0.940265 0.535465 1.052197 0.782258 2.162396 0.631921 2.196813 0.834052 1.913606 1.969309 2.175793
+1 0.012832 1 1 -1.900602 1.867183 1.950921 0.321543 -0.939174 1.811692 -2.349826 1.015357 1.544848 -0.996752 0.124634 -2.287485 -66.855498 9.645834 -32.462105 -40.604529 59.683027 2.014591 0.480697 0.827397 0.310844 1.359289 0.571843 0.460103 1.202898 2.358191 1.858557 1.519872 1.742241 1.848843 0.259188 1.666416
+1 -0.055620 1 1 1.366179 -2.099879 -1.584728 -0.105988 -0.053946 -1.896751 0.611043 1.511778 -0.747220 -0.002612 -1.480583 1.969536 69.215559 55.908366 51.910567 60.899068 -69.361953 1.879964 1.307222 0.729510 2.129475 0.829700 0.774729 1.623082 1.647290 1.253413 0.855220 2.188705 1.807184 2.093158 2.456343 2.255459
+1 0.026638 1 1 2.056316 -0.157520 0.931697 -0.229961 -0.787449 -2.266282 0.831790 -1.758376 -1.634057 0.200334 -2.348138 1.095941 -39.561242 44.207076 38.321114 -37.032500 -55.235072 1.587225 1.984002 1.620754 0.765060 1.117345 2.219584 1.055231 2.264529 0.432517 1.070084 2.156747 2.441108 0.455312 1.670498 2.052732
+1 0.036499 1 1 -1.804169 1.550891 1.601450 -1.599426 -2.091221 -2.154399 1.010614 1.934859 -1.021157 -0.067121 -1.849288 1.930623 -48.768969 -60.066025 -29.680979 51.782851 14.381511 2.275887 2.339499 0.463325 1.353932 0.542589 1.546387 1.871170 1.996682 0.992787 1.275723 2.326515 0.487403 1.040110 2.378603 0.681535
+1 0.012773 1 1 1.970455 -1.237848 0.681909 0.309989 -1.924007 -0.376281 -0.136424 2.049349 0.554437 2.035342 0.768584 0.932053 33.167305 42.891006 -30.860306 30.835112 -4.264386 1.801994 0.360213 0.856450 0.355015 1.240555 0.756946 1.994700 1.422570 2.133233 0.998544 1.270911 2.453726 1.024694 2.032886 1.968264
+1 0.010458 1 1 1.159339 -0.719039 -2.317775 -2.228554 -1.240023 1.833306 -1.932001 1.922648 1.100432 -1.164618 1.535516 -2.344396 -63.165458 -71.851156 47.620349 -44.790968 48.206602 2.250450 2.318844 2.070109 2.067969 2.113995 1.664657 0.639042 0.374879 2.093076 1.077427 1.809873 2.287506 1.856199 2.389140 2.273874
+1 -0.005094 1 1 0.790935 -0.402906 0.064467 -0.352519 -1.314560 -2.136195 0.662127 -2.289126 -1.392951 -0.185113 -1.012865 -2.071822 -40.293302 40.471358 -47.888848 32.132280 47.224749 2.220348 0.393331 1.715492 2.267959 1.829074 1.002952 1.122049 0.285427 1.672067 1.431668 2.044386 1.739862 2.358652 0.608864 1.675137
+1 0.015235 1 1 2.277962 2.265102 -1.828619 0.598688 1.202474 -1.461561 1.223934 1.089165 -2.036602 1.625681 0.392640 1.748422 -22.981066 7.218656 -26.052430 -13.186982 66.385882 2.087745 1.480570 0.444529 0.455322 1.841167 1.747278 1.001070 0.983823 1.356485 0.689606 1.955640 1.946488 1.116304 0.471368 1.539656
+1 -0.028339 1 1 -2.187925 -1.691647 -1.661724 1.734789 1.056251 0.838150 1.457428 -0.014185 1.930756 0.700500 1.748781 0.593343 28.440769 -45.995891 47.054693 48.233022 52.396720 1.100186 1.823174 0.830353 0.497543 0.462615 0.671674 2.071186 2.171048 2.060411 1.079261 1.140730 1.495338 1.154721 0.402896 0.470368
+1 0.001536 1 1 2.293039 1.193154 2.127272 0.168593 1.392405 0.420315 0.357212 0.080715 -0.594229 -1.647394 2.251395 -1.292103 -53.620353 2.721563 -8.683708 2.928647 21.767661 1.361193 1.076080 1.668130 0.512758 1.930950 0.982272 2.293478 0.979808 1.375117 1.083712 1.702334 1.630140 1.019835 1.372678 0.607152
+1 0.004932 1 1 -0.400270 1.960052 -1.714340 -1.373696 -1.722037 1.214742 2.104001 0.171359 0.761126 -1.894410 2.257431 1.193096 36.733668 -17.237223 -56.005496 -34.370668 -17.823795 1.157110 2.305428 1.576147 0.306041 1.633697 2.288968 1.688878 0.469578 0.691224 2.153569 0.779789 1.163613 1.336399 0.612641 2.156387
+1 -0.014399 1 1 2.284067 1.199033 1.972131 -1.336690 -1.782237 -2.110583 2.298925 1.159609 -0.885562 -1.918678 -0.339814 0.164084 31.978295 9.210745 4.995604 -38.881395 70.387661 0.706332 1.828534 0.929692 0.582153 0.490004 1.995113 1.617567 1.194711 2.010676 2.174240 1.709122 0.958034 2.184362 0.825894 2.043180
+1 0.021948 1 1 0.443367 1.376385 -0.217444 2.234335 -0.563731 1.983264 1.992380 -0.304509 -0.234461 -1.029657 -1.550653 -2.317462 -53.610869 12.131792 49.023418 -13.407022 -31.817776 1.204595 1.636222 1.986260 1.325096 1.885168 1.012977 0.861578 1.046738 1.270229 2.236424 0.581747 0.414134 0.353193 2.112945 2.019702
+1 0.038644 1 1 -1.122785 -2.240473 1.075591 0.726894 -2.324494 -2.061850 1.386405 -1.457604 1.765554 -0.247768 1.519518 2.094212 18.549888 67.974200 42.387282 53.046533 -46.918871 1.142901 1.992279 1.235419 2.181146 0.775408 1.790515 0.931451 0.905052 0.451651 0.894482 0.555006 0.981643 0.728196 0.293095 2.292169
+1 -0.005609 1 1 2.111475 -1.445741 -1.496054 1.121286 0.608967 -0.404989 -1.963459 0.999995 -2.170713 0.135422 -0.043151 0.474306 -54.020739 23.437877 20.393238 -0.851199 -56.098010 2.286251 1.021913 0.298655 1.252248 1.536006 0.656707 0.269659 2.150969 2.084189 2.467301 1.933018 1.980183 0.440818 1.086259 1.757324
+1 0.009006 1 1 -0.584844 0.571414 -0.097048 -0.599835 -1.629898 -0.584474 2.069952 -1.882043 -1.946239 -1.745509 -2.155508 1.230080 22.381742 -30.054077 -68.877553 74.959199 -10.741387 2.417537 0.292191 0.603452 0.714350 1.576261 2.219594 1.221551 0.856949 1.990121 0.958700 2.126501 0.347517 1.212212 1.394312 1.950476
+1 -0.038673 1 1 -1.003352 2.308317 -1.215695 0.732350 -0.160146 -0.798956 2.248643 -0.412579 -2.287474 -1.911682 -0.565054 -1.391055 -41.290811 -74.654068 39.075109 35.361602 22.447148 1.663355 1.256155 1.951377 2.293275 2.075325 1.989968 0.635149 2.456972 1.582715 0.445344 0.644058 1.437017 1.941780 0.754924 1.751912
+1 -0.005637 1 1 2.158107 0.052065 -1.443072 0.963624 -0.850933 0.471619 0.262543 1.769529 0.590042 1.973182 2.193052 -1.685618 22.078532 -26.108722 -59.288196 -6.709819 28.075603 0.874942 0.643574 2.302809 0.312047 1.330788 0.805024 2.295404 1.861007 2.199363 0.940620 2.002686 0.637421 2.376870 0.799468 1.161661
+1 0.034468 1 1 0.213794 -2.309011 -1.031667 -2.345245 -2.118666 -1.609317 1.328858 2.103349 -1.360993 -0.271681 0.163973 -0.857194 -34.382411 -65.185653 24.724641 47.035805 30.775527 2.039324 2.170259 2.289544 2.364765 2.103393 1.218654 1.661356 1.404787 0.261155 0.977512 1.040819 0.789731 1.750910 1.301053 0.544238
+1 0.008951 1 1 2.013939 -0.811806 -1.654514 0.392495 -0.681365 -0.592656 1.217151 0.180606 0.664219 -0.125072 -0.361110 0.384735 27.097226 23.082555 48.497436 -3.595155 26.231448 1.704305 0.997745 1.346297 0.462266 1.559704 0.689022 1.145711 1.964975 1.336521 0.412772 2.210182 0.534625 0.446683 0.654577 0.467670
+1 0.045501 1 1 -1.520844 -0.819356 -1.307702 0.029413 -0.464892 -0.294263 2.334770 0.417617 2.149391 -0.361509 -1.605093 1.623701 3.165373 -49.583652 47.556951 -60.332750 -12.535288 2.416285 1.754341 0.459549 0.888002 1.904854 1.126614 0.499420 0.506069 1.993770 1.550998 0.623304 1.363448 0.716552 0.341233 1.352258
+1 -0.027340 1 1 -1.446661 1.895685 0.319855 -1.028499 -0.935099 -0.392736 1.349432 -0.831946 -0.859135 -0.721666 0.643529 0.853544 31.659062 43.855430 -21.782372 53.676049 33.355245 2.149052 1.366527 0.723792 0.516021 0.518326 1.004539 0.795642 2.113074 1.935210 0.572460 1.843533 1.010450 1.134773 0.381521 1.216969
+1 -0.009359 1 1 -1.638680 -2.087989 0.323375 1.586208 1.419949 1.549367 -0.456694 0.818844 2.127430 -1.898956 1.248211 -0.878087 37.907009 53.103713 14.104489 54.146218 -14.519763 1.620158 1.991900 1.605910 1.033897 1.459128 2.308480 1.123220 1.953500 1.973636 0.647821 1.675716 2.011375 0.429772 2.175731 2.009592
+1 0.039244 1 1 1.143987 0.444601 -1.442822 0.444630 -0.954371 0.852092 0.161933 -2.152776 0.017226 2.066997 0.294773 1.521822 -50.377263 59.348179 -35.150121 -68.087070 10.606466 2.318016 1.637360 0.854077 0.967856 0.752328 0.870833 1.334164 1.285386 0.474219 2.200366 2.051325 1.377536 1.251969 1.339316 2.383126
+1 -0.072184 1 1 1.691317 0.835119 2.344961 2.049594 -0.030979 -2.307156 1.878604 0.695314 -0.589134 -0.853460 0.409125 0.788783 35.907582 48.724622 64.718227 69.235160 -64.664490 0.383683 1.560110 0.760877 0.558746 0.844066 1.474012 0.475262 1.734945 0.724349 0.877141 1.616724 0.530417 1.718436 2.255743 1.267977
+1 0.032992 1 1 -0.145636 -1.977182 1.268240 1.173266 -2.268569 0.103885 -2.301704 -0.731692 1.789568 -1.903001 -0.757617 -0.397523 31.677745 57.856800 -50.761169 57.027570 -37.634361 1.814460 0.625028 1.094215 0.476455 1.525332 1.258690 1.810780 1.787468 1.471756 0.811229 0.817331 2.135027 1.897989 0.509682 1.969266
+1 0.014742 1 1 -0.401270 -0.721097 0.794839 -0.771507 1.778281 1.604443 1.579645 -0.510770 1.460481 -0.523578 -1.749647 -1.006980 -67.627529 -65.872941 23.475544 53.465117 -61.783413 2.217583 1.171920 1.452824 2.113631 2.305064 2.217030 0.874950 0.786791 1.845679 1.072740 1.784215 0.795894 1.834295 0.992201 0.414533
+1 -0.013448 1 1 -0.293504 0.949984 0.813844 -1.792683 1.398170 -1.637069 1.415296 -1.262260 0.378515 -0.028815 1.082893 0.927253 15.089411 -42.262204 -50.859880 48.004380 -40.388935 0.372484 2.338216 1.397952 2.385611 1.461809 2.365475 0.534894 0.463776 2.181879 1.841146 1.383346 2.145268 0.769637 1.531363 1.363491
+1 0.041482 1 1 0.766441 -2.099107 1.966078 0.604526 0.355447 -1.312350 2.027283 1.967799 1.255805 -0.473155 2.188893 -0.888898 -45.547822 -72.238668 -15.299837 -44.368800 -56.418767 2.421809 2.344255 1.644508 1.742275 2.412289 2.092054 1.899278 1.913682 1.004385 0.450415 0.366757 0.582567 0.709390 1.461224 1.534784
+1 -0.022550 1 1 0.991852 2.337315 0.772061 -1.896386 2.031689 0.632464 -1.332292 1.441208 0.697535 -0.952277 -1.640848 -0.833694 -62.507065 43.760771 37.283851 -70.321680 -46.473376 0.954456 0.544747 1.806763 1.774914 1.970662 2.409615 2.144871 0.844309 1.051682 1.116143 2.264198 1.625470 1.281684 1.270367 2.313462
+1 0.046930 1 1 0.274603 1.831111 -1.132521 -0.948797 0.300746 -1.759276 2.086070 0.400124 0.301675 -0.278748 -0.805544 -0.087360 63.724819 23.025611 -8.553260 -54.633357 -72.835300 1.481670 0.926737 0.421040 1.666592 1.657982 0.948428 0.475852 0.390775 1.504148 0.716740 1.244712 0.873234 1.196352 0.341202 0.830969
+1 0.034371 1 1 -1.770786 1.849439 0.601841 2.350950 -0.963712 -0.622828 -1.649783 -0.209175 -0.163885 2.337261 -0.131042 -1.735309 -11.458008 25.264883 -23.109547 -52.164278 24.975643 2.359597 0.746601 1.370819 0.852808 2.146830 2.275290 1.293816 0.419020 1.475029 1.816069 0.669421 2.452073 2.497454 2.456738 2.137204
+1 0.053777 1 1 1.935659 -1.715348 0.541553 2.265212 0.032170 -1.250628 -2.044711 1.996183 2.346409 -1.894781 0.739309 -1.011254 45.627117 54.959784 9.091585 -47.735897 52.783483 1.855041 0.915791 0.948243 1.865375 1.354175 2.375119 0.622234 1.381327 1.969536 1.495785 1.903021 1.824267 1.200865 1.938834 0.727783
+1 0.001190 1 1 -2.321333 -0.772747 -0.219421 1.988088 -1.760584 -1.052322 -0.781920 1.122437 1.112108 1.862901 0.669550 -0.050986 23.352568 -63.393697 -7.870133 26.678521 35.906762 1.899259 1.596820 1.249725 1.885538 0.478191 1.451810 0.818292 0.289369 0.428425 2.032579 1.308043 1.032285 1.362435 1.699353 1.019655
+1 -0.000560 1 1 -2.318874 -1.852934 1.915472 -1.704426 0.328619 0.172667 -0.822719 -1.280631 -2.081700 2.348885 2.025276 1.236347 -74.794623 -73.229536 -18.804411 4.260324 53.256500 1.854830 1.881088 2.188721 2.088757 0.493931 0.496822 1.840581 0.889099 2.339094 0.397229 1.969825 1.850114 1.360730 2.292174 1.571141
+1 0.078069 1 1 -1.206012 -1.458852 -0.359130 0.679665 0.303990 0.928719 1.556102 -0.348820 -0.399368 -1.736840 2.180024 0.836627 -18.618953 -28.749592 -44.396634 -74.232945 66.885020 1.922914 0.911749 0.510388 0.337797 2.098143 0.737190 0.694300 2.104916 2.077463 1.924273 1.247141 1.207511 1.144434 0.749888 0.360532
+1 0.012646 1 1 0.419362 -1.513073 -2.170514 -1.223793 1.295923 -0.089820 -1.643653 -0.844881 -1.478669 1.148819 1.541923 1.672534 27.971801 22.051192 -35.613644 -58.520773 -8.628663 1.796051 1.727694 0.353604 2.267934 1.410008 2.496317 1.357270 0.384788 2.133956 1.902556 0.766888 0.339165 0.342953 1.010404 0.364647
+1 -0.031638 1 1 1.378266 -1.593255 -2.051490 1.163340 0.556695 2.281362 -1.858300 1.258963 0.759852 0.258027 1.257611 1.607996 1.306355 55.904770 -8.530526 27.445685 29.636066 0.525369 2.384481 0.473667 1.922327 2.292317 1.729956 2.379651 0.287256 0.911602 0.290820 2.312206 0.744553 0.710637 2.172755 1.487946
+1 -0.044173 1 1 1.924740 -1.445469 -1.633700 1.492523 0.796380 1.578992 -2.053485 0.606187 0.002828 0.410367 -1.902300 1.612374 -56.841651 12.369029 -13.732194 53.023092 9.102874 1.255034 1.113602 2.302766 1.838903 1.936470 1.506662 2.461190 0.467421 0.448985 1.088649 1.421144 0.668466 2.155324 1.032761 0.368007
+1 0.002895 1 1 -1.473319 1.528611 -0.583178 0.297683 -1.393423 1.312928 -1.737301 -0.849846 -0.113927 -1.540920 1.040222 0.042136 41.844688 -66.330497 -16.655410 -27.477169 41.228196 2.459279 2.095167 2.466882 1.628332 2.133720 2.431195 0.336668 1.135905 1.401236 1.316439 0.388371 1.601599 0.570550 1.231316 0.725560
+1 0.002615 1 1 -0.779381 1.384863 0.898533 -1.565015 1.342221 0.507250 0.646753 -1.509675 -1.597791 1.825315 0.411185 -2.281675 41.682108 51.181506 -42.431701 -49.601157 53.346121 1.948764 1.124371 1.059958 0.716632 1.682465 0.693394 0.372563 1.421929 0.364159 1.916481 0.792077 0.695512 2.221974 0.716198 1.135158
+1 -0.006477 1 1 0.336923 -1.619046 -1.979442 0.985339 1.265883 -0.735603 2.034729 -0.115402 1.945911 0.940037 -1.440505 1.695986 -25.709862 44.350435 47.765938 2.115946 12.708664 1.292839 1.989268 2.379829 1.041883 0.682501 1.796768 0.278340 1.814244 1.496079 2.356649 0.700547 1.350199 0.797321 1.072606 1.783971
+1 -0.002837 1 1 -1.951705 0.636863 1.917227 -0.476182 -1.550103 2.211469 1.551530 -1.801680 0.978665 2.181048 -0.805262 -0.057309 -59.109918 -10.398827 -23.078694 16.395296 5.742433 2.321167 0.603216 1.245066 2.319324 1.129547 0.301444 0.862685 1.647509 0.434784 0.915776 0.697961 0.635563 0.412676 0.587888 2.375557
+1 0.012195 1 1 -0.784931 -2.354889 0.728167 0.226090 1.715459 1.330816 2.025081 -2.053798 0.072047 -0.183736 -1.430830 -0.644878 0.904650 54.456806 -44.469602 49.393384 54.596788 2.248182 2.444080 0.898896 0.488644 1.636053 1.400172 1.437580 2.400932 2.462772 2.301154 1.742633 1.680384 1.705784 1.117385 0.641275
+1 -0.006787 1 1 0.221893 1.851238 -2.154202 -0.380651 1.830349 0.200594 2.026969 1.400983 -1.487137 0.200576 1.730926 2.089814 66.074772 68.693206 -23.295132 -21.287439 -27.995381 1.849463 1.673011 1.550968 2.369923 1.050221 1.315637 0.402723 2.062698 1.267454 0.604398 0.867706 0.538484 2.296513 2.494585 1.487442
+1 -0.001085 1 1 0.878662 -0.962788 0.767195 1.143006 -1.900489 -0.949011 1.403528 -1.129706 -0.760656 0.373208 0.324954 -0.153796 71.757011 20.083837 49.050012 -16.441117 -25.852473 2.087374 1.991672 2.288066 2.283161 0.832065 2.268425 0.675000 1.721144 0.513043 2.219368 1.911614 2.242263 1.963335 0.769941 2.156382
+1 -0.005601 1 1 -1.872841 1.923106 -0.640580 1.581677 0.653479 -1.550430 1.437936 2.251918 -1.918832 1.774242 -0.308335 1.446842 36.346605 -72.615920 -55.770673 12.292430 48.867239 2.300171 0.965906 1.733335 0.664953 1.611344 2.350322 2.366709 1.025129 0.337325 0.915738 2.309324 1.803397 1.451680 0.893135 0.419408
+1 -0.050776 1 1 -0.693894 0.888207 -0.746472 -1.571543 0.008087 -0.734940 -0.967247 1.221077 0.182031 1.052101 1.776272 0.821431 -47.960663 25.137090 -70.923151 44.599118 27.369960 0.728772 0.977205 0.389315 1.710668 2.193314 0.526618 0.862160 1.822170 1.966056 1.496848 1.775224 0.438817 1.197366 1.626292 1.597930
+1 0.060027 1 1 -0.991944 0.827109 -0.319878 0.640143 0.497275 -2.076757 0.602020 0.648116 -2.157887 -1.068140 1.969639 -0.811855 70.911799 64.613174 -46.377309 -63.440233 -40.003823 0.711160 1.961642 1.569426 2.094702 1.406368 2.085748 1.667908 1.274438 0.985679 1.060888 0.597414 0.479487 0.737053 0.643465 0.468269
+1 0.023924 1 1 0.981856 -0.732028 0.858184 -1.116533 -0.831317 0.291721 2.069424 -1.327453 -2.049386 -1.182076 0.273358 -0.256692 74.140055 21.905753 69.994054 -59.931505 -18.797862 0.839938 1.839674 1.403488 0.930955 1.566399 0.726047 2.420317 2.020047 2.181939 0.599368 1.824481 0.306393 0.799569 0.604763 0.256970
+1 -0.031977 1 1 1.430019 1.141277 2.015236 2.132297 -0.194759 1.792034 1.844269 -1.460058 -1.787539 -1.682609 -0.568109 -0.916108 -52.584079 19.391056 -44.515414 29.431263 -48.769631 0.307179 0.504524 0.790892 1.025186 1.293071 1.396004 1.136764 2.334195 1.320754 0.915270 1.199135 2.107587 1.969987 2.319329 1.211572
+1 0.012142 1 1 -1.825913 -1.036599 -0.420504 1.175269 -1.586943 0.375173 0.360796 -0.950667 1.857569 0.582519 -1.945731 2.085155 -26.355784 -11.661149 61.068035 70.461960 4.166724 1.077062 2.438218 1.382878 1.029567 0.688339 0.914621 1.535329 0.530093 0.770831 1.358888 0.577522 1.409051 2.166832 0.952894 1.287896
+1 0.082027 1 1 0.419232 1.004128 1.313411 1.677237 -0.186134 0.670109 -0.087289 -1.516875 -0.097057 -0.742601 2.221170 -0.340383 0.689522 38.796299 -0.602250 -72.017696 -51.409788 0.710449 1.269276 1.966969 1.105090 0.998965 1.599439 0.280061 1.485932 0.560104 1.165072 1.121797 0.540416 1.023085 1.988317 2.150806
+1 -0.040210 1 1 1.374451 0.258216 -0.278853 2.143090 2.119723 0.525473 0.604341 1.957449 1.652210 -1.414894 -1.413462 -0.901217 -36.351731 -13.538318 11.491236 -66.800217 38.750522 1.075286 1.836370 2.118502 0.906404 0.678236 2.104621 1.619750 1.885266 0.421829 1.433655 1.695113 1.761578 0.598573 1.959263 2.088092
+1 0.001534 1 1 -1.049475 -0.054875 1.337027 -1.963879 -1.339575 1.557102 2.312303 -0.199013 0.989378 -1.541879 -0.931966 0.434988 61.179259 -10.189002 53.439858 -36.302117 70.313977 2.380214 0.758012 1.907105 0.713853 2.235373 0.907067 0.583166 1.762715 1.702178 1.262285 1.464888 2.376148 2.171887 0.401679 0.275284
+1 -0.005375 1 1 -0.234970 -0.153723 -1.235585 1.022380 1.774756 -1.101213 2.183102 0.738713 -1.592928 -1.250775 0.195994 0.113650 51.066074 -32.493941 24.325388 -63.201629 70.213698 1.849308 1.316690 2.349836 0.946737 1.300588 1.735768 1.052410 2.108696 0.347172 2.173919 0.808886 1.943642 0.545120 1.326953 1.602338
+1 0.010324 1 1 2.292937 -0.529479 -1.958409 1.047976 -1.578106 -1.898770 -0.329265 -1.615435 2.171023 0.348191 -0.744665 0.522000 -38.606336 43.313631 22.195515 -9.978802 -13.726884 1.258973 2.050596 0.367145 0.361491 2.077437 1.477612 2.471150 1.367267 1.908092 1.557689 0.586070 1.074636 2.149426 0.899537 2.260113
+1 0.008655 1 1 -1.753300 -1.139301 -1.804690 2.228553 1.223094 1.107956 -1.945554 0.337364 1.066504 -1.202258 0.380170 -0.477877 -56.392084 68.245271 -51.738384 -17.026249 39.829318 0.795203 1.468652 0.382017 0.552504 1.685703 1.112830 0.579637 0.966481 2.392405 0.906945 0.781837 1.833638 1.208106 2.134119 2.391318
+1 -0.003108 1 1 -2.043826 -1.977279 -0.365399 -1.024243 -0.090251 0.539340 -1.947243 0.224177 -2.174848 1.336136 1.908198 -1.442852 -2.000617 -24.373312 7.737924 1.282198 -50.103005 1.656816 1.610601 1.114109 1.834892 2.027283 2.290904 0.466869 2.416578 2.181555 0.895795 2.369374 0.819146 1.132011 1.203780 1.435159
+1 0.023672 1 1 -0.248064 1.251178 1.873903 1.793106 0.996648 -1.885254 0.633765 1.690958 -0.491518 -0.122360 -1.898810 -1.007394 10.782522 21.846914 -18.913095 -22.382565 16.231927 0.774849 1.382219 1.206151 0.779193 2.400524 2.364098 2.141003 1.093004 0.363553 0.733163 0.524230 1.241413 1.674234 1.844594 0.849812
+1 0.020634 1 1 2.133266 1.946232 1.627527 -1.564378 -2.085028 -1.748219 -0.575062 0.041218 0.021417 1.806636 2.202797 1.878709 -72.035337 -47.902787 -52.138736 4.266476 6.664360 0.743485 0.744400 0.381680 1.643499 0.538768 0.328116 1.387398 0.492892 1.042506 2.153344 1.499876 0.910766 2.000531 0.420451 0.764583
+1 -0.023969 1 1 -0.616568 -0.118146 -1.761190 -1.812425 -0.543579 1.389366 1.178876 -2.233177 1.173495 1.584046 -1.927686 -0.946600 -15.575848 -33.278172 43.760042 25.032452 -29.575239 1.809329 2.140709 0.637245 1.676109 1.870280 0.548245 2.100709 1.120981 0.332027 1.885849 1.218851 0.476471 1.792818 1.391445 1.011680
+1 0.010494 1 1 2.069260 0.626061 -0.561412 -1.446568 -1.249302 1.377590 1.189095 -0.124773 -0.040142 -0.787826 0.813359 -0.521718 39.721395 -52.508158 -54.612178 -16.881461 73.292095 1.678546 2.328703 1.264491 0.298818 1.738263 2.482710 2.154589 2.175290 1.349920 0.611918 1.259400 2.490239 0.451227 0.529291 0.789902
+1 -0.010559 1 1 2.349907 0.355137 -1.807765 -2.331265 1.943644 0.546457 -0.145767 0.535483 -0.804438 -0.352780 -0.989006 -1.635496 -13.521905 -12.653901 25.887797 -53.798868 2.421471 2.089900 1.692451 2.024369 0.570922 0.732452 2.074239 1.738266 0.286137 2.347300 1.065022 0.325046 1.547464 1.984286 1.890312 1.971217
+1 0.002867 1 1 1.634354 0.075013 -2.180794 0.356268 -1.654365 -1.820365 -2.045527 -2.291467 1.666670 1.283216 -1.593322 1.546764 -56.726034 5.543425 18.342716 36.027213 -40.634940 1.353477 1.893677 2.278936 1.832951 0.912513 2.102908 2.074726 0.911690 1.768842 1.170803 0.693058 1.476026 0.564691 1.758723 2.103901
+1 -0.010996 1 1 -1.840813 -1.709198 0.229257 -1.618464 -1.613043 -0.034732 0.589852 -1.227231 0.050603 2.258443 -0.637623 -0.549554 -2.484995 -65.309005 51.545251 71.031381 -25.576374 1.943308 1.674380 2.051149 0.660945 1.754720 2.325234 1.456633 0.883234 0.517853 2.057519 1.970957 0.629232 2.002853 1.195316 0.932389
+1 -0.023261 1 1 -0.339785 0.648514 -0.178902 -0.295410 1.898088 -1.703745 2.347540 -1.725449 0.422357 1.698232 -0.759582 -0.440815 -28.552053 -24.355704 3.681512 -74.835182 -4.911385 0.690231 1.218305 0.304651 0.764671 1.319298 1.188952 1.967238 1.116565 0.365020 0.637195 0.834683 1.262486 0.347746 0.572388 0.632944
+1 0.016495 1 1 1.014316 -1.813323 -1.499624 -2.321619 -0.862841 -1.749161 -2.265479 0.192331 -0.197433 -0.732001 1.302710 0.886046 20.180627 25.791777 -17.601297 -24.993212 -60.920102 1.612573 0.514573 0.922757 1.025816 0.636034 1.581873 2.045736 1.932478 1.911906 0.407608 0.922525 1.625842 0.777749 0.632560 1.681197
+1 0.011171 1 1 1.423629 2.132520 -1.163368 -1.031278 -0.529568 1.249054 -0.834365 0.895087 1.783335 1.710622 0.130043 -0.918253 -0.132515 22.820555 -4.927051 -8.947132 -74.445704 0.490799 1.866635 2.289556 0.322097 1.486707 2.337047 1.991326 0.958057 0.318439 0.759962 0.935466 0.870466 1.917763 2.096339 1.913059
+1 0.042849 1 1 2.225890 -1.122327 0.743149 2.269368 -0.810320 -0.249494 0.788981 -0.256666 -1.956388 2.039807 0.410076 -2.080834 -61.512077 -33.471287 -51.920206 -72.895520 44.992735 2.018390 1.332518 0.633084 1.484436 2.413768 2.200248 2.320241 0.782992 1.004564 1.210747 1.528704 1.674795 2.281470 1.668230 2.191473
+1 -0.036354 1 1 -0.458047 1.654301 0.737062 -1.062063 0.429466 -1.338334 -1.151573 -0.707172 -0.799908 0.399823 -0.048466 0.675204 22.994471 68.070427 9.668140 42.431156 40.446653 1.178546 0.328056 0.379739 0.522478 1.034964 1.396221 0.285716 2.032348 1.923865 1.150141 2.163563 2.255442 0.719523 0.766908 0.679060
+1 0.014961 1 1 1.987764 2.226548 0.510267 -0.487366 -1.036546 0.471461 2.312869 -0.103872 -2.200427 0.245987 1.537104 0.792772 70.018778 55.601745 -1.474189 -26.694170 1.082620 2.059036 0.466539 1.369199 0.625208 1.870890 1.789303 0.821473 1.992246 0.685779 0.630938 1.430335 2.135737 0.337943 2.315615 1.793538
+1 -0.005406 1 1 -1.421213 0.776521 -2.323382 -2.233150 1.620750 2.332170 -0.863901 -0.710275 -1.110007 0.453323 -0.934022 -1.134251 -55.448202 32.067621 10.501289 -54.832059 37.586804 2.446245 1.289053 1.367760 1.185288 1.132812 1.169442 0.309433 2.394398 0.651354 0.310878 1.919266 0.350584 1.020906 1.369837 2.354027
+1 0.061030 1 1 -1.837896 0.191692 -1.513110 1.932086 -0.497091 0.455246 -1.603822 -0.576312 -2.122818 -0.704350 -0.496883 -0.751946 21.387188 54.469418 17.506826 -62.768538 -0.812092 1.392554 1.654309 2.213882 1.969529 1.380602 1.028509 0.891839 1.132211 2.320209 0.250698 0.724979 2.475969 1.357281 0.576677 0.710330
+1 0.010261 1 1 0.673515 0.611898 1.735221 -1.120103 0.417477 -0.203205 1.222006 1.656363 -2.302969 1.563548 2.270927 1.828514 74.453603 41.699926 50.648134 -6.813749 -68.673751 2.128960 1.184047 0.532079 0.396747 0.622931 1.859670 2.223870 1.074453 1.334592 1.741317 2.071323 2.221743 1.329378 1.859011 2.394061
+1 0.051074 1 1 0.872395 2.106989 -1.437528 -0.113238 0.611621 1.787672 -0.795277 -1.882473 0.254752 -1.950442 -1.699573 1.776531 14.393125 -44.740234 0.889142 -56.195336 74.995852 1.454217 0.776135 0.500032 1.793422 0.293435 1.266645 0.507248 1.559938 2.376363 1.281166 1.551900 2.276115 1.667556 2.120875 0.295940
+1 0.029950 1 1 1.092820 -1.861646 1.577615 -1.644593 2.203203 -0.720817 0.781850 -2.295951 1.711174 -0.005027 0.326895 -0.517928 -32.705034 -73.502802 38.406228 43.470881 -34.895153 1.632383 0.456709 0.405992 0.751997 2.056337 2.354674 1.251641 0.326310 0.290745 1.047821 1.472959 0.770612 2.180017 2.043289 1.315694
+1 -0.002517 1 1 1.774396 2.284614 0.955496 -0.800668 1.753333 1.703948 1.067373 -0.732451 -1.536375 2.032403 -1.517379 0.855221 28.874425 42.465052 10.134333 -72.267740 -53.909462 0.530081 0.573853 0.500067 2.374970 0.373205 0.964618 0.328613 0.745473 0.412402 0.490179 0.443267 1.744671 2.191555 2.472120 1.928737
+1 -0.042054 1 1 -1.542429 -0.748876 0.425429 1.484475 2.189921 2.244890 -2.228218 -0.307532 0.792999 1.290326 0.100093 -0.053837 -1.643657 -24.949431 74.921005 -52.667238 -28.265054 1.363623 1.404370 2.239804 1.133373 1.593163 0.545714 2.318347 0.451891 0.425487 2.151825 0.714162 0.677906 1.072985 1.401664 1.760467
+1 0.025352 1 1 -1.333227 -0.141702 -1.824914 1.606894 0.368604 -1.656041 -1.702751 0.195884 -1.741200 -0.421941 0.588599 1.277455 17.397695 53.059998 29.388031 -25.368188 -63.131732 2.049651 2.493126 1.718667 1.637068 0.454597 0.918647 1.697316 0.547946 1.572664 0.267642 2.009487 2.452583 2.056751 0.311434 2.264414
+1 0.000059 1 1 1.406088 -0.516027 -2.077428 -1.240021 1.864028 0.758667 -0.814150 1.362252 -2.130145 -1.324894 -1.457688 0.344976 56.234753 -12.502303 23.793615 -0.717708 -62.516647 1.865623 1.020578 0.358557 2.265728 0.342982 1.505825 1.903943 1.566164 1.261183 0.949346 2.408106 1.534494 2.235401 1.389070 1.600924
+1 -0.010347 1 1 0.591838 -0.830621 -2.147526 -1.289656 1.743607 -1.542834 1.858025 -1.170147 -1.866371 2.280928 0.279624 1.385699 25.934542 -18.151529 27.245997 -26.533342 4.128991 0.564255 1.190179 2.342448 0.529242 2.217459 1.324384 1.174646 2.275737 2.056520 0.935690 2.397121 1.418005 1.911492 2.442132 1.909540
+1 -0.010002 1 1 1.533027 -1.760700 1.716038 1.629170 -2.233435 1.549871 -1.406796 -1.958410 1.038682 -2.273290 0.869564 1.650724 59.977536 42.448551 32.796764 -34.789718 -10.788362 1.825033 0.579027 1.948850 0.317967 1.816710 2.446225 0.960586 2.325445 0.496619 0.680763 1.828063 2.006602 1.217139 0.958336 0.500197
+1 0.023649 1 1 1.234799 -0.096393 0.985920 1.602262 -2.093833 1.063079 -2.214932 1.504945 2.216943 -0.698588 2.110767 0.803201 -50.946069 -50.582611 58.057863 28.497593 9.039123 0.933033 0.492236 1.253463 1.708163 0.604354 2.380914 1.275148 1.661370 1.639203 0.330985 2.368122 2.279570 1.234025 1.266459 1.881398
+1 0.027795 1 1 -1.995127 1.252189 0.017146 0.722504 -0.695144 -1.268009 -2.009399 1.724803 -1.844767 -2.193136 0.270757 -1.561482 -16.937583 30.036549 74.280492 -17.765369 67.445451 1.460376 0.789152 1.034927 0.766265 1.111842 1.976557 2.486771 0.666050 2.060217 2.313716 1.380165 0.430258 1.345827 1.555853 1.218832
+1 0.011600 1 1 -1.815279 -1.391445 1.562162 -2.168291 -1.565175 -1.342044 -2.241470 -1.551860 0.969506 -0.961964 0.470506 0.405260 57.598562 -40.969333 -71.571349 -49.662281 -73.959935 1.455595 1.437230 1.023747 1.871148 1.629070 1.031340 1.238134 0.571168 0.377495 1.058169 2.145935 0.726919 1.328606 2.378821 2.091670
+1 0.051195 1 1 0.817667 1.195327 0.941317 1.228209 2.247832 0.097318 0.429255 -0.181854 1.923819 1.918831 -1.794785 -0.947743 -26.879072 43.434873 -40.086766 61.730656 -42.870114 0.354785 1.871609 0.380222 1.892686 1.376479 1.481337 2.072180 0.882497 1.628104 0.544710 1.186510 1.425012 0.426568 2.334022 0.658963
+1 -0.018370 1 1 -0.682902 1.846425 1.790728 -1.262442 2.027687 -0.660604 -0.383818 0.437131 0.245790 -1.766613 1.301775 -0.691589 61.374129 -35.013125 -15.593105 -23.312069 -5.938751 0.436294 1.548676 2.089739 1.241391 1.308312 1.045310 2.022972 1.846962 2.387003 2.357055 0.769620 1.251551 1.058720 2.409975 1.447709
+1 0.003147 1 1 -1.846651 -0.870838 0.497656 -0.382529 -1.468057 0.441354 0.542625 1.427438 0.175238 -0.023344 -1.217789 -1.466925 19.269707 15.967193 10.607421 -71.070239 -27.506749 1.286118 1.532842 1.475348 0.419904 0.579151 1.796262 0.774425 1.003821 2.221030 0.600842 1.854666 1.374453 1.172830 1.009753 0.659864
+1 0.005399 1 1 2.329351 -1.123222 -0.160378 0.018330 1.775429 0.789585 0.462757 2.111545 -0.266032 0.856508 -1.011348 -0.136675 -69.047741 64.625112 4.251666 57.758817 -47.569353 1.403138 1.783608 1.850549 1.925752 1.361622 1.536202 1.703719 2.410785 1.566149 1.010602 1.438214 1.814702 2.453895 1.610377 1.863322
+1 0.010005 1 1 0.951732 1.909501 1.614254 1.546677 1.457118 -0.511075 1.052253 -0.380234 -0.591079 -0.543359 0.378749 -0.803468 58.184876 63.212202 -42.520288 -38.486515 -42.855120 1.884980 2.359815 2.167882 0.596281 1.697903 1.410527 2.224646 0.632230 0.636846 1.723646 2.066203 1.678344 1.170981 1.422698 2.029652
+1 -0.003883 1 1 1.324967 -2.023248 -0.124690 1.351559 1.937987 -0.285415 0.245121 1.114542 0.352683 -0.638474 -0.718413 -1.232345 -34.299327 -18.785675 19.152725 -0.145118 -38.993868 1.076006 0.437379 1.774808 2.454798 1.038476 1.916024 2.115043 1.279905 0.604932 0.837442 0.379403 1.633636 1.262256 0.989718 1.440879
+1 0.007236 1 1 1.795963 1.894893 1.149288 0.007776 -1.257462 0.893266 -0.546247 -1.035534 -1.372167 0.429158 -1.816895 -0.266320 23.465962 42.425438 -55.658031 -44.520195 -50.910722 0.527339 1.743950 1.316598 0.810182 1.228057 2.210171 0.350590 1.118480 1.034326 1.924481 2.494196 1.704503 2.081649 0.273672 2.112034
+1 -0.033994 1 1 1.762302 1.639945 -0.207951 1.555146 -2.285306 1.541876 0.877824 -0.894318 1.713073 -1.086050 -2.160961 -0.895690 70.461532 -3.024926 10.063970 -54.849353 46.918972 1.632351 2.164394 0.475153 2.153504 1.948083 0.931300 0.608003 0.701957 0.298203 0.392147 2.064447 1.415281 1.131493 1.503820 1.951797
+1 0.011832 1 1 -0.041629 -2.225007 1.826107 -0.417879 -1.831766 -0.460205 -1.626654 2.106767 -0.461247 -0.306514 -0.945112 0.959874 66.682903 -60.444990 51.052233 34.883276 -66.774702 1.638805 0.404126 0.889919 0.372480 2.278204 0.766193 2.154000 1.282597 0.856298 2.305853 1.975659 0.897230 1.746306 0.408220 2.201338
+1 0.008722 1 1 -0.687770 0.144773 1.605552 1.372091 -1.697897 1.668690 2.251702 -0.846477 -0.040387 -0.206946 -0.400747 -1.346425 -14.837874 69.856348 25.648317 -28.737790 3.965434 2.080687 2.098569 1.144731 1.243260 1.218586 0.521750 2.305918 0.814585 0.973152 2.020612 0.423650 0.537299 0.380765 2.015288 0.946361
+1 0.007546 1 1 1.050675 1.377068 1.831867 2.160561 -1.115087 -0.090927 -1.396931 -1.103839 0.447138 -1.219122 -0.309350 -1.486941 -38.861065 -37.916187 -57.362625 -43.639459 51.612520 1.399331 0.797375 1.982004 1.797456 0.585115 0.780070 1.383776 0.374691 1.177411 1.502114 0.279914 1.271594 0.434640 0.744740 1.588195
+1 0.006235 1 1 -0.487908 -0.706044 -0.685380 -2.109112 -1.247948 0.583476 0.005840 -0.803489 1.470371 0.766040 0.579307 0.614468 -69.610127 62.601953 51.021232 -36.155692 -18.712775 2.040745 1.292084 0.555760 2.411911 2.489470 1.024904 1.068611 2.143467 1.994671 0.939546 1.949793 0.427071 1.781394 0.641751 0.911112
+1 0.073910 1 1 0.560719 -0.780546 0.646016 0.242260 0.167465 1.295248 -1.998505 1.038834 0.286540 -0.191668 1.906149 1.829381 -61.289303 -39.322537 6.118614 -64.448102 -29.257356 0.949200 2.201287 1.783960 1.012882 1.503582 2.457208 1.045237 0.803632 1.391107 2.083410 0.625151 0.916798 2.129280 2.054559 1.715952
+1 -0.008093 1 1 -1.567807 1.547489 0.970050 -1.239690 -1.998484 1.392928 -0.211541 -2.233554 -0.450438 2.292357 -0.855051 1.947206 -26.859388 74.270763 -31.283267 -27.869782 42.574047 2.005108 0.848256 2.145188 1.673210 0.382020 0.601775 1.781848 1.526136 1.261543 0.252624 1.599963 2.326327 1.824662 1.094161 1.817232
+1 -0.000515 1 1 1.399445 0.936824 1.101697 1.238922 -1.478487 -0.507582 -1.508579 -2.037990 1.861676 -1.069396 -0.284091 -1.065916 52.767001 54.992665 -38.279482 -13.246651 -36.470205 0.553982 1.775531 1.097488 1.482158 2.379463 1.631224 1.226422 1.722112 1.029944 0.276272 0.800255 0.887237 0.297964 0.886306 0.394502
+1 0.005093 1 1 0.994123 -1.912343 -2.250461 -1.866955 1.882332 2.089072 -0.970439 -0.585945 0.915316 -2.231200 1.420332 -1.438552 48.718328 -41.062198 17.644396 -0.638746 64.594136 0.379547 1.803880 0.553822 1.329666 2.189638 1.739579 2.099008 1.778200 0.959319 1.268894 2.298720 1.345790 0.936339 2.049252 0.274004
+1 -0.017008 1 1 0.371444 -1.049264 -1.227694 1.695836 1.379971 -1.202392 -1.882583 -1.599030 -0.137978 -0.502225 -1.004868 0.393639 -9.421473 53.300731 25.385364 51.814406 -55.277098 2.242183 0.624850 0.348569 0.895167 0.826492 0.843583 2.341495 0.257692 1.271559 2.095890 1.117320 1.794425 1.396428 1.511006 1.222751
+1 0.017515 1 1 2.012084 0.988505 -2.081354 -1.253248 1.042172 -0.170526 -0.903615 0.965776 2.328378 1.372607 2.261703 2.318128 -39.710961 -72.128734 32.369766 -11.345712 -37.381126 0.406331 1.963301 2.454541 1.221954 0.873387 1.516962 2.335406 1.427070 1.268391 0.591716 1.472869 1.509591 2.192336 2.084944 1.652024
+1 -0.002847 1 1 -1.338874 -0.803958 -1.705990 2.322032 -1.622354 -1.015633 -1.463741 2.286965 -1.928203 -0.217932 -1.259939 1.672099 -54.633372 -73.088874 -54.713006 -61.496630 -73.861618 1.491714 0.993817 0.584744 1.297599 1.002722 1.743401 1.084730 0.808355 2.024076 2.394306 1.358847 2.146675 1.910709 0.537433 0.393317
+1 0.010490 1 1 0.339953 2.180951 2.288019 1.637091 -1.052351 -1.266535 -0.793319 -1.969482 -1.260157 -1.976454 -0.633948 -0.049825 44.249355 -1.086037 46.980622 3.312030 15.281257 1.856362 0.625278 0.792297 2.141975 1.670270 0.471417 2.355655 1.987672 0.309744 0.872802 0.687839 1.507469 0.275235 1.370346 1.900593
+1 0.002457 1 1 -0.042039 0.309313 0.860261 0.796288 0.033646 -0.002941 -2.308922 0.477942 -1.851650 -0.059125 0.592311 -2.306459 -17.436115 51.212884 34.940756 -0.708029 -49.842823 2.000094 2.086834 1.911350 2.318200 2.492836 1.338030 1.015084 0.269399 2.295952 2.072941 2.424443 1.617846 1.386664 1.671010 1.659627
+1 0.056053 1 1 0.324133 0.180733 -1.919331 -1.895954 -0.123569 1.340949 -2.021021 -0.395667 -0.788602 1.909551 -2.252456 2.307643 50.887182 -39.139263 -63.592669 -51.981844 -58.857149 1.943470 2.155657 2.134606 1.578706 0.562359 0.816815 2.459315 0.451579 1.942205 1.134413 1.086554 2.218243 1.006042 1.305664 1.545809
+1 0.018210 1 1 0.586530 -0.515798 1.781015 0.418070 0.324032 -1.511990 1.898352 -1.978293 1.454587 -0.628337 0.006367 -1.369955 -3.188510 -39.287896 -11.674646 -15.773017 -47.097139 1.200807 0.969757 1.205779 1.280152 0.271088 1.427439 0.721330 1.897811 2.016377 1.250662 1.872116 2.153033 0.768214 2.371678 1.283224
+1 -0.060692 1 1 1.815110 -1.450006 2.220238 -1.867602 0.430602 -1.103870 -0.074912 -0.829837 1.607010 2.317760 1.982411 1.790439 -44.844002 56.850450 -14.481173 64.930726 40.705638 1.219825 1.089889 2.006610 1.343821 1.594744 2.355745 1.249803 0.942907 2.188202 2.365165 2.082217 0.824885 0.848883 1.432823 1.202686
+1 -0.014253 1 1 2.100197 2.210296 0.679801 -2.131151 0.609534 -0.299522 -1.239246 0.759132 2.287159 1.317057 1.688663 -1.358353 53.383322 63.494869 58.263511 34.824178 -10.041921 1.006513 2.463698 2.115002 0.595606 1.598425 1.236095 2.305119 0.880232 1.815800 0.643699 2.154359 0.569111 1.794213 2.341086 2.386337
+1 -0.065088 1 1 1.145904 -0.327913 2.259505 -1.636567 0.441111 1.171561 2.068779 1.959945 1.189594 -1.163720 -2.226139 1.642538 30.749444 55.899287 49.313976 69.990300 26.967219 0.445818 1.871173 2.057382 1.916988 0.311701 2.252276 1.496905 0.482819 0.494885 0.786563 0.263184 1.333264 1.913989 1.662792 0.795806
+1 0.012484 1 1 -2.349060 -0.261552 0.753696 0.459533 -0.228553 -0.697601 -0.161674 1.794693 -0.594874 1.640520 0.031209 1.452251 -70.016541 -18.012867 -42.260028 -14.284125 -73.296512 2.207857 1.955382 2.104326 1.155873 1.760252 0.807326 0.472820 1.191592 1.342910 2.038977 0.842873 1.672866 1.359346 1.532890 2.274336
+1 -0.017976 1 1 1.603934 -2.253860 2.268986 2.201091 1.484047 -0.303811 2.071062 -2.078828 -1.205838 1.463332 0.270295 0.097655 43.561703 -8.459659 18.513822 61.808205 60.504464 2.102998 1.340889 1.819698 0.909884 0.667610 1.276126 2.344397 1.782967 2.325998 0.800122 0.897964 0.587559 1.347125 0.877406 1.563573
+1 0.061907 1 1 -0.617148 -0.437264 2.234493 2.096414 -0.101576 -1.303091 2.130454 1.816842 -0.614064 -0.447585 -1.590348 -0.312175 -58.488445 -65.299803 56.205656 -51.545117 -68.782083 1.818050 2.471236 0.566339 2.458411 1.022107 1.304621 2.010560 2.490172 1.577840 1.759603 1.146461 1.070650 0.411136 1.720256 1.342217
+1 0.041672 1 1 1.433600 0.064311 1.730520 -0.011727 0.831501 -1.900730 -0.284743 2.107077 0.041912 2.275159 2.269884 -1.551565 38.429785 -10.600924 30.269221 -65.196626 -9.695533 0.582593 1.146154 0.407682 2.162098 2.389764 1.510001 2.339717 1.870519 2.311376 0.298104 0.989846 1.339499 0.958561 2.030304 1.317849
+1 -0.045665 1 1 1.746174 -0.813423 -0.563429 2.350776 0.823063 -2.350306 -2.346220 0.354592 -1.548738 1.600174 0.522916 0.043475 8.538583 -42.034627 24.020608 64.366122 1.418787 1.308308 0.976862 1.376362 1.761715 0.647612 0.407988 0.557316 1.561098 1.627623 1.453434 1.107314 2.373871 2.154980 1.991158 0.392096
+1 0.036375 1 1 2.313545 1.832104 1.422089 -0.188290 2.140231 1.202963 2.052666 -0.248756 -0.948644 -1.849158 -0.602290 -0.469053 14.411242 -40.249077 33.767082 73.348920 -74.701561 1.237997 0.510807 0.626475 0.666945 1.345028 1.639709 2.084144 1.702264 0.449805 1.365432 0.317110 0.922843 2.473162 1.432271 0.935318
+1 -0.001213 1 1 -1.062062 0.454840 1.008427 -1.827981 1.890724 1.762969 -1.278164 1.679548 0.952883 -2.312729 -2.250094 -0.405814 -53.799246 -3.929628 -45.255105 47.444440 -1.290785 2.211724 1.701757 0.923648 0.257500 0.300637 0.798024 1.635984 2.479257 0.371789 1.905270 1.378559 0.445614 0.680328 1.264785 0.737197
+1 0.001523 1 1 -0.399651 -1.777956 -0.847395 -1.325262 1.779729 -2.334327 2.320451 0.087740 -0.328584 0.416395 0.453042 -0.942646 0.248645 -21.019935 -32.047948 20.137376 48.883296 1.848380 1.465668 1.975254 0.842316 1.296813 1.286849 0.312057 1.497091 1.351485 2.152896 0.717661 0.970391 0.604370 0.403736 1.083789
+1 -0.047273 1 1 -0.168460 0.844348 1.953671 -0.585384 0.923971 1.854390 -1.006942 -1.488533 0.290007 1.535721 1.114995 -1.451948 -68.308670 36.178992 -39.675664 71.114360 19.056801 1.939894 0.548144 0.400599 2.364570 1.071295 2.255667 2.241019 1.300863 1.861405 2.127296 2.472384 1.866606 1.792973 1.749440 1.329014
+1 -0.035482 1 1 0.216529 1.239207 -1.411960 0.774066 -1.174781 0.356584 -1.058487 -0.718385 -0.754221 0.128287 -2.157524 0.320419 -30.975246 49.039866 -36.972225 57.820339 -63.555317 1.011880 0.410574 1.272181 1.293224 1.713796 0.777364 0.912381 2.135788 1.182029 0.363373 2.210944 2.089268 2.323602 1.027265 2.497346
+1 0.011158 1 1 1.966783 -1.692251 2.323608 1.303303 1.428589 0.671740 -0.944807 1.373008 -0.430430 -0.722478 1.142435 -2.076399 61.163290 21.417795 -31.120940 0.361453 74.947367 0.480947 0.519386 0.824196 0.515483 0.475442 2.495683 1.943376 0.571945 2.173949 1.308128 2.456263 0.919721 1.754206 0.441221 1.093558
+1 -0.057432 1 1 -1.234178 1.113039 -1.333333 -1.913386 -0.940242 -2.014424 2.088450 -1.997928 1.306614 0.529174 1.542067 -0.613940 52.135404 -60.257104 58.845485 66.065516 63.131203 0.566923 1.017777 0.532899 0.680820 0.546347 1.710405 2.274305 0.496645 1.112385 2.104195 1.201220 1.157252 2.438287 0.294583 0.308266
+1 0.032425 1 1 -0.239313 2.242307 1.478743 0.093219 2.218994 0.779961 -1.064933 -0.682135 0.593489 -1.358682 0.869881 2.252171 74.385554 -51.987372 -1.754587 60.660320 -32.009561 2.354568 1.720387 1.286111 1.414032 0.383070 0.264409 1.676161 0.490023 2.309757 2.331263 1.545479 2.371929 1.015486 0.275290 2.292740
+1 0.003474 1 1 -1.323460 -0.917414 -0.043239 -1.003585 -1.613450 -2.168728 0.508318 -0.256412 2.325558 1.098644 1.772510 -1.149587 -10.242372 56.446373 -55.815445 9.808157 -4.310699 1.376250 2.138470 1.262251 0.896318 2.168915 2.206440 0.636895 0.301020 0.497899 1.939486 0.442990 1.577160 1.573734 2.492155 1.151773
+1 0.006541 1 1 -1.795087 -1.304928 -0.473484 1.381614 -1.871191 1.378928 0.105392 -0.529128 -0.780071 -0.789217 1.008416 -2.016480 16.738341 71.296792 -64.808862 57.459111 15.270996 1.519428 1.026131 1.442395 2.333381 1.138040 1.287749 1.942928 2.035010 1.666287 1.031958 0.373519 1.730283 1.116507 1.629003 2.151649
+1 -0.070584 1 1 -1.869658 -1.124843 0.864100 -0.649346 0.343040 2.226283 0.774709 0.210711 -2.302636 -2.270492 0.771288 -0.738861 -28.319176 -10.387263 21.262577 60.135352 -5.138948 1.820405 1.547203 2.099034 2.215704 1.086098 1.300911 0.414408 0.450320 1.028554 1.652104 1.160258 1.204615 1.962488 2.283572 0.999767
+1 -0.026516 1 1 1.898977 -0.912558 1.469067 -2.302832 -0.844338 -1.787891 1.821715 1.177393 1.125456 0.011366 -2.179861 1.903845 25.651818 30.110246 -37.097960 44.584418 -69.690126 2.395904 1.211967 1.786759 0.815436 1.788939 1.456932 1.405468 0.454385 1.843107 0.606501 2.461658 1.590694 1.793092 1.503540 1.743308
+1 0.019743 1 1 0.033451 1.441284 1.981433 -0.511759 -1.016568 1.656297 1.302292 -1.418745 -0.161453 0.799751 1.680709 1.612509 15.798012 17.195901 -38.494773 -31.642474 -65.059809 1.971914 0.962116 1.027513 2.163820 2.066136 0.549392 1.127925 2.293872 0.862785 1.070941 0.811760 0.756866 0.654507 1.543075 2.461156
+1 0.006566 1 1 -1.411605 2.029818 2.161368 -1.695906 2.153704 1.448808 1.194116 -0.560264 -0.997273 0.805726 -1.567787 1.885502 -37.548108 -21.043871 15.655150 16.097900 -42.592165 0.677349 0.698974 1.910529 2.002624 1.846938 1.986972 2.033205 0.575885 0.902695 1.343722 2.194344 2.094479 2.155176 0.793700 0.964670
+1 0.013120 1 1 -0.944025 0.377979 0.396250 1.164886 -1.741502 -0.769279 1.527810 0.100502 2.100481 2.279220 -0.159332 -1.258511 67.462486 -8.005202 6.578681 17.884200 -20.253845 0.529301 0.958212 0.673176 0.324692 2.348575 2.243447 1.612266 2.107416 1.340527 2.482275 1.601541 1.858658 0.961002 0.309041 0.302469
+1 0.029775 1 1 0.626903 -0.542142 1.982527 -0.975598 2.244376 -1.440688 -1.387700 -1.455852 -1.774355 -1.585204 1.318771 2.211228 70.354938 5.445191 17.325902 46.429909 47.477947 0.802940 1.010672 0.366807 1.419063 1.698378 0.380369 2.113522 0.461191 1.492988 2.150054 2.462335 1.716463 0.585839 1.690246 0.965761
+1 0.028100 1 1 2.116504 -1.740642 -0.464329 -0.265803 -0.008318 1.572032 -1.222256 -1.149613 -0.753465 -1.288843 1.261039 -2.047092 -10.387785 12.491957 -47.686931 -24.243266 -56.576672 0.863134 2.449852 1.157466 1.539924 1.248153 2.460500 2.376273 2.019193 1.332377 0.511723 0.277895 1.084663 1.930213 2.095182 0.470632
+1 -0.018910 1 1 1.934512 -2.142109 0.228170 -1.034024 0.444260 2.258336 2.271069 -0.488609 1.647197 -0.842317 -0.805243 0.261896 9.823538 -45.789287 69.455076 31.461267 19.506084 0.456262 1.894996 1.943449 1.795106 1.603129 1.536019 0.874094 2.146146 2.033300 2.164916 2.493279 2.048117 1.453204 1.756910 0.893052
+1 -0.007332 1 1 2.232924 -0.713732 2.055155 -0.819101 -1.743051 1.470240 -1.437483 0.634780 -0.097975 -2.042819 0.816246 0.874789 -2.358437 -38.248585 56.029036 -19.995800 -69.409554 1.129452 0.944768 1.970157 0.680916 2.149202 1.629608 1.066600 2.096301 1.274950 0.578733 1.520949 1.839280 1.530971 1.535384 1.454865
+1 -0.009466 1 1 -1.849412 -0.147026 -1.766598 1.551975 0.968844 2.053031 1.173734 0.890569 1.242687 0.523474 0.004885 1.998083 41.140168 -57.193214 -46.345668 18.356862 -26.222168 1.135359 1.230754 0.281253 1.274734 1.458044 2.088634 0.665889 1.596390 0.776642 2.273371 0.547750 0.541993 0.527417 0.798220 0.437645
+1 0.003005 1 1 0.565563 0.529578 -1.078075 -0.064825 -0.959771 -0.360138 -2.139861 0.316634 1.384029 1.025938 0.311020 1.268163 -3.708182 -73.409160 -37.751611 8.669974 66.250592 1.730619 2.272518 1.962734 1.917328 1.523322 1.227760 1.716200 0.679896 0.762611 0.449072 0.297740 1.622716 2.246597 0.560706 2.293942
+1 -0.012245 1 1 -0.412401 0.698182 0.492114 0.722621 1.260982 1.713733 0.585638 -1.364888 0.235777 -0.419941 1.210404 -0.120820 13.372792 56.512720 9.283690 30.978348 3.094319 0.718259 2.030390 0.514174 0.973674 1.796063 1.937633 0.789002 0.752899 1.470471 1.711077 2.327964 2.333096 0.840554 0.938995 1.686475
+1 -0.030696 1 1 -1.660819 -1.902466 -1.191496 2.171054 0.885177 0.151610 -1.299380 -1.467696 1.789456 0.912898 -0.456693 0.842410 -74.384820 64.324469 51.346926 37.789323 25.145019 2.309953 1.124314 2.345601 1.761915 1.750270 1.782789 1.576337 1.239949 1.823593 1.134933 0.818247 1.771567 1.979488 2.250248 1.166176
+1 -0.010694 1 1 -2.250482 -2.210722 1.582043 2.102228 -1.337438 -0.225070 1.299019 0.111481 -1.869037 -0.127559 0.246485 0.487203 -54.356211 -64.837413 27.597802 36.251459 -21.733341 1.041151 1.881380 0.350756 1.657463 1.228780 0.859183 1.293921 2.172117 2.025151 2.463734 0.475659 1.647295 1.331492 1.391964 0.735201
+1 0.017444 1 1 1.050998 2.091924 -0.172066 1.485714 -0.555192 -0.582954 -0.652264 -1.586653 0.523834 1.334509 -1.874829 1.489946 -3.513860 42.554689 16.661892 -13.584467 -14.139916 0.631548 0.424528 1.787385 2.329140 1.858744 2.411905 2.389203 1.078532 2.381026 0.897302 0.697209 1.493930 2.237693 1.651751 1.975491
+1 0.027988 1 1 -1.642755 0.109800 -1.852846 -1.321091 1.199020 1.754460 1.792216 0.184660 -1.889471 0.450560 -0.240525 0.729256 -10.007254 -41.924698 71.602165 -32.410906 69.896554 0.645620 0.691437 1.237032 2.302615 1.550289 2.201628 0.764018 1.608511 1.990115 0.869333 0.879382 1.029244 2.001018 1.858420 1.460268
+1 0.009089 1 1 -0.788763 -0.785188 -1.969847 2.032103 -1.843916 -2.035267 0.490751 1.373784 -1.516370 -1.029824 0.357312 1.766245 62.084175 48.727073 -44.086505 38.113720 -72.710318 1.490187 2.314148 1.878694 2.454658 0.938071 1.901911 1.169188 0.545598 0.364151 1.788302 1.999068 0.580447 1.064776 0.687575 1.576345
+1 -0.009762 1 1 -0.373184 0.084276 -1.998365 -1.327598 0.226061 1.217051 -1.504482 0.845456 1.726090 0.937023 -0.251802 -0.304303 -47.194671 -0.839621 -11.512556 8.469118 -9.534435 0.696155 1.781303 1.362874 2.319967 0.684897 1.561154 0.322187 0.749085 0.363650 2.358293 1.332863 1.925356 1.456827 1.895909 1.536934
+1 -0.001885 1 1 -1.175008 1.254086 -1.085489 -2.147734 -0.058418 -1.650656 -0.745294 -0.626827 1.813869 1.250223 -0.048311 -1.425132 27.840589 66.771298 -74.790358 -1.545472 -24.741472 0.926319 2.386147 1.479195 2.074218 1.375021 1.722776 0.937481 0.986449 0.499256 2.244749 1.002513 0.492208 0.787133 0.844826 0.739034
+1 0.004713 1 1 1.073552 -0.539774 -0.635114 -0.799995 -1.066746 1.835804 2.345100 -0.326095 -0.166785 0.718215 -2.103089 1.009291 -46.333626 70.752641 -60.367445 4.359897 -73.217266 1.936277 0.506402 0.843925 1.349535 0.883798 0.986021 2.296899 2.227530 1.853868 1.452603 0.647094 0.712342 1.584159 2.216866 0.360884
+1 -0.038527 1 1 0.872532 -0.306798 -1.000944 0.366039 2.352717 0.459116 2.179597 -1.619967 1.402119 -1.250682 1.762805 0.678448 -41.798504 -57.460766 -43.092565 -56.734713 9.678294 2.321283 0.302410 1.356007 1.663942 2.123491 1.512566 0.438096 0.332639 0.917128 0.912308 0.903487 1.149597 2.027367 1.454422 1.973901
+1 0.073688 1 1 1.057678 1.269294 0.031003 -2.012304 0.023292 0.337183 -1.962598 1.334818 -1.393208 0.216563 1.815729 -0.475589 -32.001224 55.434876 43.968692 -68.192578 37.349199 1.044707 0.899439 0.613394 1.313058 2.073010 1.323751 1.790688 1.594933 1.036870 1.928016 1.171180 0.267449 1.018402 2.030490 2.197204
+1 -0.002095 1 1 -1.465331 -0.870524 1.063145 -1.104891 1.619680 -1.510616 1.429860 -1.525728 1.903968 -1.841515 0.626893 -0.705561 -63.485103 -44.131634 29.630535 0.397132 74.604954 1.906820 0.416297 0.702779 0.600167 1.760947 1.228949 1.439919 1.209590 2.322313 1.858667 1.111368 0.761680 0.558623 1.018666 1.967584
+1 -0.029948 1 1 -2.296462 -2.167030 0.777622 2.039904 2.036523 1.766630 -1.014915 1.167145 -1.465387 -1.818290 -0.153027 1.036561 -7.107512 -55.954451 73.538320 -41.447565 -9.218925 1.487908 2.263730 0.506248 0.508382 0.381231 0.842741 1.702488 1.964046 1.463858 0.803321 0.668144 1.248573 0.513160 1.937334 0.265940
+1 0.033523 1 1 -1.677903 -1.571191 1.216373 1.238701 -0.494130 -1.611407 -0.814838 -0.771701 -1.487227 -1.311762 -2.220604 0.431798 4.978324 -29.307393 30.645682 -38.017313 43.017634 1.335523 1.635007 1.807042 1.947479 2.029010 2.071717 2.095158 2.318910 0.926256 1.342794 2.347813 0.689702 1.329309 0.690438 2.440953
+1 -0.016350 1 1 0.632668 2.105893 -1.015069 -1.420418 -0.010277 1.624557 0.349993 1.275117 -1.055086 -0.109814 1.610318 1.356458 -17.255806 -68.336327 21.349008 12.780707 5.334295 0.677522 1.370221 2.060717 1.728370 0.469229 1.587706 1.082216 1.308200 1.410319 0.982276 2.360604 1.929416 2.201965 1.925894 1.496929
+1 -0.008679 1 1 1.984284 0.284438 2.182626 2.161627 -2.046280 -0.820675 0.074072 0.850361 -0.657007 -1.186501 1.314162 0.160049 -26.411472 -47.615866 -29.862228 5.541188 -19.244988 0.617381 0.830262 1.218649 1.575510 0.849674 1.215277 1.158877 0.500183 2.081155 0.980276 0.253690 1.511787 0.850930 2.073106 0.697913
+1 -0.003017 1 1 -0.537402 1.526094 -0.477864 -1.546710 -2.015015 1.584928 -1.248801 0.377663 -0.210029 -0.378439 1.299288 -0.075733 -15.694540 71.872263 7.131360 6.767474 40.936524 0.927309 1.033340 1.088763 1.081070 2.288555 1.500238 2.499668 1.419515 0.288809 2.264582 1.329871 1.146913 1.912878 0.983272 1.098027
+1 -0.032481 1 1 -1.390660 0.622455 0.103595 2.244764 0.369531 -0.223458 0.122149 -1.643674 -1.196245 -2.235044 -1.923209 -1.096105 -47.782213 24.346578 -7.057609 32.762715 -7.049534 1.652326 0.391393 0.648196 1.238186 1.438815 0.669764 1.475398 1.266860 1.868393 0.331921 2.339064 2.141911 0.600996 2.186881 0.406312
+1 -0.026885 1 1 -2.308427 -0.632001 -0.316001 -0.174606 1.209126 1.965047 2.126588 -1.898200 -0.178029 0.232189 0.545682 0.964588 38.530433 30.993658 -39.586399 71.384737 63.278454 1.689611 1.537903 1.040179 1.283846 1.592905 0.706088 2.226159 1.306899 2.045799 0.745078 0.527594 1.514512 1.653574 1.116008 2.249656
+1 -0.040126 1 1 -0.491677 1.920258 -1.375480 1.284390 -0.718716 -1.611180 -1.708837 1.593069 -1.082796 0.686802 -2.265885 -1.917619 -44.484096 -44.197664 -30.136495 45.922003 61.105947 0.739834 2.389159 0.354260 2.045266 0.791772 2.317376 2.131862 0.457192 1.775355 0.387430 1.536078 1.856923 1.062928 1.132957 1.354495
+1 -0.021636 1 1 2.017370 0.297239 0.558216 -0.432888 0.379358 0.009781 -0.550057 0.904967 -1.803889 1.556159 0.601048 -1.550446 36.975636 -0.485532 -60.339415 25.457629 66.363998 1.070812 0.889104 2.413229 2.138927 2.191240 1.663488 1.248387 1.883067 1.701268 1.712171 0.455184 1.785155 0.848384 2.037504 0.827727
+1 0.004794 1 1 -1.638105 -1.855947 -1.602240 -2.248013 1.576601 0.172923 -1.232213 1.140324 0.146979 0.986493 1.806569 1.086818 29.511439 -51.251982 57.945932 -52.714264 -68.636389 0.298121 1.266682 1.127026 0.668919 0.767433 0.493763 2.172197 1.123040 1.177759 0.596669 1.457615 1.636188 1.418870 0.697184 1.077223
+1 0.055629 1 1 -1.352989 2.309476 -0.590699 1.119300 0.210844 -0.059061 1.679744 -0.460695 -0.439741 -1.693826 -0.589362 0.032462 -33.266460 -59.400510 55.634483 -51.237776 -3.306760 2.474229 1.367797 1.822112 0.981095 0.518904 1.712018 2.381739 1.641387 1.034254 0.712413 0.519831 1.547156 1.300380 0.494806 1.707587
+1 -0.057596 1 1 -1.655165 -1.132665 1.348262 -1.630134 0.160784 2.099549 0.747059 2.011741 -0.052157 -0.100136 -0.660473 1.824057 -59.632610 54.715731 -42.710892 58.036933 -23.260530 0.778999 1.381423 1.319608 1.903304 2.077624 2.373801 0.964677 1.323381 2.323150 2.437978 1.850535 1.689787 2.247310 1.285738 1.902242
+1 -0.045004 1 1 -1.037265 -2.184320 2.351826 -0.372087 -0.327782 -0.249840 -0.325406 1.988264 1.204455 -1.144319 -1.300858 1.958208 8.707257 -57.134283 44.100536 47.713961 28.534653 1.853675 0.468368 0.603451 0.696353 0.605117 1.705156 1.805573 2.008687 2.493472 0.779605 0.327084 2.055431 0.635898 1.531285 2.302529
+1 0.006222 1 1 0.358004 -0.741010 0.685154 -1.694895 0.295657 2.245148 2.112110 -0.191619 -1.976272 -2.287435 -1.255497 0.944450 65.205223 4.181267 74.549137 -2.648418 38.033355 0.274053 1.757073 1.382166 0.306543 1.069482 1.030061 2.230696 1.061324 1.165112 1.784859 0.369134 2.289389 2.015469 1.740310 0.890145
+1 0.048795 1 1 -1.524140 0.326941 0.243921 -0.197656 0.231482 -1.923519 -1.589823 -0.908183 -0.400414 -0.469698 -0.965168 -1.535009 45.784668 2.911254 29.449247 -46.499597 -18.734413 1.085832 1.321819 0.818836 0.418487 1.503515 1.333187 0.620989 0.706160 1.173823 1.935965 2.011551 1.130779 0.748359 1.674576 0.855910
+1 0.080070 1 1 -1.473796 -1.771854 -1.970813 -0.075142 0.003272 -1.553627 -0.463538 -1.106448 -0.985629 -1.423211 0.179500 0.928717 47.957998 -69.929358 -52.722839 -62.759370 3.262509 0.369855 0.900347 2.389189 0.851970 1.559365 1.756632 0.713865 2.431558 1.947687 1.030678 1.360235 0.711710 2.216948 1.744044 0.647722
+1 -0.007023 1 1 1.825118 1.822292 1.438792 -2.194652 -1.646503 -1.620276 0.917215 1.404076 -1.336104 -1.372576 -1.746035 -1.557767 20.753201 49.050417 -9.642741 -65.552802 4.054712 2.088229 0.611978 2.266619 1.811653 0.705970 2.487344 1.285905 2.449238 2.084842 2.182332 0.458220 1.055074 1.881036 1.315070 2.124120
+1 0.036844 1 1 0.743309 0.259242 -1.876558 0.702208 2.179918 -0.937676 -1.298622 1.846741 -2.333454 -1.856262 -2.175215 -0.122165 43.717007 51.740928 59.773487 62.992631 17.142729 0.892669 1.588169 2.109412 1.144420 0.514275 0.415420 1.721464 1.395177 0.736856 1.835746 0.633448 0.863557 0.555446 1.624357 0.573267
+1 0.016420 1 1 0.812872 0.719890 -2.220297 0.873920 -0.537224 -0.188247 -1.859545 -0.808555 1.138629 -0.070396 -0.342813 1.588050 -19.760298 -11.321522 69.184279 -19.828771 37.838271 0.592301 2.307416 1.243216 0.478659 0.327530 0.550843 0.769825 2.443417 1.016999 0.946260 2.300088 1.830492 2.328500 2.355325 0.938303
+1 0.013165 1 1 -1.813964 1.872526 2.207788 0.951079 0.360073 1.043281 -0.378154 1.381932 -1.235038 0.780982 1.966953 1.164654 -29.284837 -40.253600 -42.251225 -16.341093 5.243427 0.269051 0.939001 1.789384 2.181019 0.881807 1.280916 1.850630 1.041831 2.052352 0.622882 1.031609 1.249733 2.008944 2.316034 2.086530
+1 0.054690 1 1 1.042160 -0.367728 2.241653 -0.078762 0.432794 -1.956311 -1.389311 -0.262201 -0.727503 1.513901 1.945669 1.596339 64.717657 59.666250 60.658836 -56.934982 -56.243161 1.692935 1.152008 2.057566 0.514821 0.599003 2.450907 0.892123 1.410732 1.170018 0.986553 2.245415 0.936622 2.306060 0.955104 2.434198
+1 -0.024635 1 1 -1.967452 -0.132604 0.290043 2.141416 2.269976 -0.008985 -0.208639 -0.577111 -1.403290 0.413879 0.576280 1.583066 14.090750 -26.767285 -27.766922 -28.665117 25.376795 2.241991 1.899982 0.255658 0.838749 2.101657 1.304256 0.380330 1.453013 0.796677 1.492920 1.007508 1.188142 1.851193 1.493692 0.482750
+1 -0.034276 1 1 0.133040 2.328236 -1.010452 0.781161 0.254603 0.268540 -1.111670 0.791558 0.643171 -0.437724 -0.790656 0.376972 73.958854 -23.535272 -7.316718 27.925894 0.494840 2.376587 0.554123 1.900537 0.567754 1.484442 0.265797 2.492623 2.269023 1.725437 0.674655 0.422180 0.575843 2.444677 1.929065 0.792168
+1 0.066948 1 1 1.179151 -2.322583 1.787076 -1.377540 -0.347215 -1.698498 0.995294 -1.066209 1.437883 1.376292 -1.778243 -0.966293 -50.529417 52.091807 -43.003666 -62.607645 3.313143 1.885035 1.030854 2.060942 1.003018 2.230029 1.090094 0.967530 2.030844 1.402186 1.541870 2.464969 0.986831 2.417311 0.998490 0.363907
+1 0.015415 1 1 2.024228 -2.245818 0.775720 -1.660651 0.919918 -0.285242 -1.558841 1.444281 0.520955 0.065574 -0.603703 -0.660102 -43.534126 21.950160 66.337367 -17.879034 -42.919240 1.469984 0.273566 0.327240 2.420012 1.392280 1.556988 2.292714 1.635896 1.007346 0.711319 2.395621 0.954261 1.761698 0.361935 0.548530
+1 -0.023228 1 1 -0.764747 2.292326 -1.377801 -0.016018 -0.607424 -1.940710 1.642842 1.351016 2.231018 0.242929 1.972773 0.024498 56.113682 52.652646 -66.970705 23.359035 45.293441 1.327827 0.542042 1.343257 1.126101 0.875444 2.340207 1.105276 1.872842 0.861617 1.694303 1.654127 1.404191 1.481637 0.374509 0.364708
+1 -0.023587 1 1 -0.277415 -1.957329 0.362372 1.981038 2.285817 2.337583 0.565116 -2.276793 -1.467872 -1.170421 -1.750485 -0.952119 31.864129 40.419403 -21.100345 -33.504218 -5.388517 1.902812 0.558634 1.216049 0.633485 1.483247 0.434626 0.514867 1.376050 1.028856 2.233241 1.083068 2.114759 1.013587 2.105419 1.529185
+1 0.052105 1 1 -2.057678 0.831549 -1.101078 -0.273799 2.270106 2.172668 -0.273105 -0.213177 -1.450867 1.889620 2.045170 1.004514 -51.390006 -11.828657 -54.231950 73.618658 -41.212208 2.071180 2.076891 1.312166 0.580531 2.485655 2.155897 1.661490 1.420879 0.718676 2.287231 1.737254 1.279062 2.202735 1.369738 0.687833
+1 -0.012953 1 1 0.693539 -2.136583 -1.140346 -0.517853 0.219890 1.175807 -1.962034 1.394479 2.300127 -2.200530 -1.471040 2.134330 31.027708 -67.312496 -21.123999 18.944007 -58.067042 0.883283 1.331228 1.450996 0.643080 0.740818 0.919919 0.576153 0.911740 0.367294 0.616647 1.988234 0.757502 2.344515 1.514633 1.437223
+1 0.074636 1 1 -1.207476 2.217252 -0.214606 -1.903254 -0.292543 -1.746661 2.052081 -0.657052 -1.940420 1.806771 -0.235774 0.461469 -21.795943 -24.415265 52.634490 -72.126321 72.922881 0.847860 2.232345 1.779185 1.764062 1.838339 1.467704 2.454641 0.650810 2.406051 0.742541 0.636493 0.292277 2.055588 1.011713 2.110162
+1 -0.011031 1 1 1.266891 2.064561 1.751882 0.876962 -1.252930 1.680721 1.823136 1.496787 1.774848 0.444244 1.992130 0.198774 -9.435239 -28.065919 46.100271 57.257282 73.130422 1.419919 0.324882 1.036850 1.581430 1.336001 0.663558 0.676635 2.199765 0.949117 0.801557 0.263626 2.012218 1.094788 1.102331 1.882681
+1 -0.012039 1 1 -1.807213 2.236133 1.380814 -1.182311 1.046203 1.611988 1.154351 0.265056 1.582708 -0.857224 -1.588706 -0.985510 18.456479 -1.964559 -18.339974 10.055232 -51.714694 0.341987 0.523950 1.022623 0.970824 1.138558 0.997183 0.902783 0.566919 0.959895 1.962302 1.412759 1.484634 1.247109 0.656903 1.316425
+1 0.049201 1 1 1.161328 -0.277434 -2.272328 -1.825348 -0.964473 0.727069 0.617680 -0.049429 -1.372331 -2.332816 -0.560648 1.962764 46.006520 -18.420946 -0.833769 -63.159748 24.122045 0.913132 1.257311 1.120665 1.771634 0.859496 2.050905 1.051720 1.753477 1.695322 0.778179 1.111190 2.270770 1.840581 0.899946 2.400468
+1 -0.058583 1 1 -0.739815 1.918094 -0.040785 -2.169594 0.104712 2.180050 1.283439 2.149684 -0.156383 1.179844 -0.093329 0.642970 28.356401 36.023309 43.752693 51.518258 67.359843 2.378222 1.020929 1.747434 1.374807 0.389418 1.190415 1.800445 1.325804 0.285730 2.256339 2.285362 1.824462 2.230339 1.803777 1.081435
+1 -0.025480 1 1 -2.277708 2.015701 0.521438 -1.233200 -1.299254 0.641670 -2.111201 1.340772 -0.288719 1.263588 -1.621985 0.464687 49.639411 -10.415365 -1.031415 65.003170 58.285209 0.617613 2.475816 1.040968 1.046718 0.941551 1.892589 1.991734 1.078531 2.377099 2.398216 1.822239 0.866227 0.421731 2.038979 0.870855
+1 -0.045712 1 1 0.346317 0.752374 1.814089 0.239496 0.822164 1.378636 -0.084612 1.070780 -0.014085 -1.113363 0.607707 1.989792 -44.103206 57.423334 13.979263 49.480170 13.223445 0.571599 0.871710 0.322363 1.460745 2.492092 2.341022 1.309773 0.852913 1.656337 0.304860 2.032240 2.359717 0.506618 2.227681 2.134188
+1 -0.006644 1 1 2.021227 -0.848996 0.037118 1.815212 0.266910 -0.236559 1.405454 -1.739022 -1.512890 0.900558 -0.509306 -2.213963 -33.386276 26.859810 -67.176551 13.711329 46.314086 2.137570 1.897827 2.285060 1.258698 1.930630 2.341387 0.683858 2.100024 0.848421 0.416527 2.315720 1.304523 0.374777 0.375726 0.576152
+1 0.005803 1 1 0.710519 0.505007 0.639611 0.977034 -1.662353 0.584892 0.244281 1.139713 -0.705916 1.464813 1.588165 1.324495 -17.226180 -20.407845 55.352474 9.028867 -51.837484 0.886051 0.612071 1.578742 1.175322 2.389267 2.157050 0.794574 2.155431 0.572626 2.382657 1.322584 2.420372 0.686947 2.274393 1.979791
+1 0.026871 1 1 -0.034280 -1.236761 0.109087 0.299763 0.569187 0.179904 -1.715361 0.321485 -1.909879 1.460223 -0.144805 -2.148881 -15.879252 -32.595239 -28.177588 -30.715123 70.934259 1.256390 1.395039 0.678378 2.252449 2.154206 2.482670 1.481948 1.094319 2.222702 1.697005 2.062797 0.683491 0.428165 2.161767 1.320654
+1 0.012590 1 1 -2.006925 0.893636 0.964684 -1.893618 1.444299 0.815154 1.370604 1.581221 -2.299531 -1.913110 -1.018989 -1.332887 27.697935 69.195164 13.116914 -44.018099 -12.190679 1.543785 0.901163 0.349779 0.984209 1.092829 1.926316 1.851273 0.596811 1.596902 0.380033 0.961966 0.755346 2.105639 0.728078 0.549965
+1 0.020434 1 1 -1.154369 -0.566926 0.128850 -2.109518 1.346820 -2.312400 -1.432487 -0.221891 -1.816348 -0.509488 -0.549411 2.330807 -6.714120 -44.211874 31.036368 -71.759637 -64.224560 1.042373 2.161359 1.211626 0.554341 1.061164 0.737402 2.011792 0.692001 1.712578 0.549245 0.903779 1.568676 0.730082 0.484061 1.121381
+1 -0.048220 1 1 -0.969283 -0.016713 1.843552 0.612630 -0.097004 0.141102 1.170033 -0.061763 -1.317547 -0.497545 2.248039 -1.150147 -9.787655 48.873649 19.423660 53.456438 -57.640327 0.460446 2.459705 0.267095 1.815180 1.483486 2.191612 1.172214 1.905836 1.881311 1.450479 0.956819 2.014353 0.985369 0.345585 0.255186
+1 -0.065866 1 1 -0.409398 -0.657592 -1.589375 1.906008 -0.547777 1.523373 0.927434 -1.194413 0.273595 -0.986792 -2.120493 0.668749 19.788259 31.267603 64.611460 74.807956 -2.691730 2.276518 1.684312 2.474997 0.774662 0.496966 2.003799 1.342615 1.584363 1.142831 0.817261 0.960942 1.559395 2.243865 1.881750 2.079793
+1 -0.016183 1 1 -1.056843 -1.372616 2.306666 -0.692650 -1.762638 2.130438 1.546321 0.188568 -2.167788 2.185606 0.405586 -2.146751 73.861207 -14.699079 2.584361 -64.640842 31.375928 0.403286 0.272008 1.138942 0.704648 0.515055 2.278913 1.441232 0.781794 1.112025 0.562310 2.245498 2.337867 2.278956 2.165398 1.591793
+1 0.033795 1 1 1.729776 1.612896 2.274220 0.634272 0.791531 0.185037 -0.260559 -1.400026 -1.281500 2.160328 -0.320039 -2.059317 49.298953 -32.498156 -46.500514 -34.146099 6.509696 2.251812 0.461239 2.289828 0.387070 2.229313 0.314982 1.148924 1.965062 0.551600 2.240752 1.326385 1.057359 2.024801 1.071599 0.613975
+1 0.005908 1 1 -0.640659 0.260234 0.658431 1.565900 -0.608310 2.015750 1.343808 -1.093713 0.997914 0.550446 0.922917 -1.713154 -9.062353 -60.960251 -58.940791 -17.879512 -50.962008 1.097864 1.056426 2.100119 2.446239 1.191163 0.875990 0.262819 1.951624 1.950028 2.122670 1.222100 1.081192 2.091258 2.014197 0.602475
+1 -0.032623 1 1 -0.474783 -1.595756 -1.667872 2.071686 -1.017924 -2.282042 -0.137165 -0.972327 0.657501 0.068776 1.378503 -2.314689 -70.231362 -28.500926 -65.068492 43.862234 -57.430899 1.508133 2.432472 1.549203 1.947690 1.078083 1.584617 0.913147 1.510797 2.215201 1.633514 1.463956 2.465765 0.866066 2.219791 2.274920
+1 -0.068057 1 1 0.852599 -0.737125 0.009962 -2.213023 0.617215 1.564787 -0.475551 -0.372103 -0.596644 0.172034 -2.035055 -0.648137 57.364890 -68.295038 -34.695439 73.763794 -1.912526 0.717760 0.393682 0.863667 2.393930 1.784632 1.063899 1.696030 1.418581 0.335618 1.479944 1.175772 0.944990 1.204057 1.590221 0.592480
+1 0.026836 1 1 -0.736227 0.970875 -1.503886 1.433251 -1.078364 -0.216142 0.560685 -1.337817 -1.879725 -0.683339 -0.791474 0.762950 15.389805 56.444472 62.240054 -31.404818 29.225964 0.636586 1.847551 1.040808 0.601452 0.846341 1.453817 0.798015 1.482201 0.860373 1.043912 1.024166 2.151919 2.311822 1.038902 2.332247
+1 -0.059314 1 1 -2.032490 0.053577 0.394451 -0.790428 -0.503455 1.888654 -0.039209 0.747285 1.106973 0.385085 2.016051 1.687569 -28.584806 25.170744 44.699121 58.124238 -55.927820 2.441949 1.089459 1.529177 0.629529 2.486645 0.801117 1.873536 1.265190 0.802377 0.557349 2.121726 1.106885 1.918380 1.206876 1.722581
+1 0.039008 1 1 -0.146860 1.018352 0.050882 2.236899 0.115116 -2.032427 1.107706 -1.428957 -2.150806 0.147188 -0.216937 1.334281 -31.830075 -68.063323 -40.261616 -26.974346 -57.826190 0.853407 0.968487 2.360629 2.337883 0.290666 1.973264 1.155965 1.047969 1.720402 1.550920 1.560863 2.166949 0.670948 1.122023 2.083572
+1 -0.034084 1 1 2.340018 -0.911209 0.577293 -0.244260 -0.782706 2.052666 -0.241859 1.867321 -0.443947 -1.697568 -2.224543 0.195295 -70.647592 25.922390 -72.386896 43.434170 -51.900279 0.805245 1.505145 1.713161 1.339011 1.761065 0.970247 0.441276 2.021940 2.489304 0.474334 1.882462 0.535084 1.413427 1.460037 1.837216
+1 0.015111 1 1 0.511223 1.444030 1.017304 1.280184 -0.709292 1.272775 1.993471 -0.815482 -2.182088 2.170987 -0.258057 -1.772727 70.572842 67.763381 -50.863656 -15.470214 -57.889002 0.768111 0.641754 0.966493 0.351058 2.237262 1.158628 0.810818 0.665847 0.890767 1.112548 0.336423 1.516519 1.631060 0.721917 0.517383
+1 0.022694 1 1 0.099691 -2.100941 -0.590136 1.158418 -2.064288 -1.873743 0.899384 -1.391436 1.727610 -1.798286 1.476556 1.035317 -72.274157 -11.760744 37.182570 27.447702 63.528158 1.641243 0.867198 0.989611 1.900151 0.833663 2.130614 1.984497 0.933538 2.225390 1.877019 1.301195 0.676024 0.928506 0.906913 2.488255
+1 -0.015564 1 1 0.899204 0.286504 -0.791610 -1.511274 -0.205316 -1.273718 1.004676 1.091892 1.392860 -1.354333 -1.431993 -1.329363 -36.980190 73.940119 -38.420630 14.468909 28.953231 1.629281 2.320288 1.574021 0.574772 2.440774 1.579500 0.408207 1.979091 2.323441 0.575853 0.362088 0.871007 2.006714 0.836616 2.258252
+1 -0.012692 1 1 1.325254 -1.923823 -1.992298 1.685109 0.166421 -2.129382 2.064485 0.473812 -0.586283 -0.059919 1.390100 -0.607727 -74.102227 13.875615 -42.544014 12.764276 29.184769 1.501236 1.280356 1.452020 2.094543 0.988079 0.901294 0.300681 1.547723 1.838017 0.546478 1.655901 1.978093 1.307456 2.419968 0.649853
+1 0.025934 1 1 0.324259 2.297917 -1.644758 -0.580604 1.146294 1.510741 0.669991 -2.076866 -1.222441 0.446229 -2.344892 -0.895554 -6.674578 20.359576 33.393872 -49.188639 -63.462359 1.946941 1.980332 0.692013 1.906052 1.012021 0.534048 1.993924 1.885766 2.069367 0.849577 1.843722 1.930130 0.688971 0.287010 1.270398
+1 -0.024001 1 1 1.384504 -0.419068 1.748625 -2.025127 1.271038 1.068277 0.337556 -0.408886 -1.484400 -0.922693 0.763502 0.337940 42.568995 -42.900305 24.573973 64.765899 -29.535591 0.554790 1.857027 0.546796 2.494733 1.729884 1.156242 1.214636 1.632143 0.925510 2.303613 0.318246 2.005036 1.888795 1.222906 1.132435
+1 0.080881 1 1 0.484363 -2.323241 0.138586 1.300684 -0.179252 -1.463865 0.211014 -1.923581 2.079943 1.102731 -0.223504 -0.654563 69.807503 -45.290469 53.089610 -72.920626 73.040297 1.199127 1.985590 1.308945 0.443567 2.273315 1.857536 2.348468 0.448739 1.458609 0.345154 2.006200 1.196845 1.866249 0.298968 2.009021
+1 -0.016938 1 1 -0.921050 0.106948 2.046934 -2.325800 -0.457869 -0.077337 0.810460 -2.109415 -1.633089 2.341546 1.206498 0.201975 53.330455 74.949166 -29.361296 24.703135 -14.414494 1.159092 1.863248 1.612781 1.755182 1.098380 0.722048 0.461436 1.099554 2.461333 0.625339 1.818534 1.600214 2.045945 0.949291 1.476044
+1 -0.004939 1 1 -0.621743 -2.269481 -1.088972 0.565159 -1.556546 2.308941 -0.150956 -1.852148 0.986460 1.255274 0.017779 1.924477 -36.577780 -62.753793 -53.001849 47.925135 -22.260107 0.990665 1.600856 1.593546 2.486591 2.136277 0.408404 0.797868 1.271157 2.079434 1.294518 0.967607 1.063896 1.641405 1.350588 0.588272
+1 0.005752 1 1 0.537797 0.395210 -2.166362 -2.137942 -0.426338 2.078761 0.075070 -1.221043 0.393311 -1.101604 0.311440 -1.094476 73.296207 -60.641083 55.325093 -1.161646 -23.780302 2.491875 0.945715 2.125345 1.172981 1.287766 2.226773 0.364626 0.771211 0.990280 1.892493 0.387313 1.818887 0.774838 1.203872 0.723035
+1 0.004785 1 1 -0.508562 0.864953 -0.460866 1.394131 1.167410 -1.719355 -0.835308 -0.810009 0.275500 -1.952599 -0.253866 -2.013247 -53.593356 6.472931 40.543916 -28.405121 45.128720 0.300922 1.098363 0.430261 1.403849 2.494130 0.587790 0.730810 1.472670 0.409310 0.272138 1.081040 1.788151 1.704255 2.417676 0.382718
+1 0.056527 1 1 -0.843429 -0.653343 -0.862509 -0.881802 0.012989 1.534420 -1.907517 -1.259245 -0.797796 -1.814003 1.208338 -1.863841 -74.163329 36.927615 -57.568123 -47.434996 10.014249 1.517269 0.737703 0.324334 0.831026 0.554477 1.097630 1.620670 1.601066 0.619392 0.878221 1.756571 1.941362 0.466844 1.995750 1.078918
+1 -0.005098 1 1 1.899273 -0.647169 -0.775312 -0.913943 1.745853 -1.499180 0.419400 -0.873411 -0.326096 -0.193155 0.484864 1.394421 41.900064 -35.619838 -12.620093 -5.902533 -53.880987 0.958648 1.249081 2.297435 2.232837 1.034034 1.515915 0.479615 0.641713 0.265959 0.719411 1.132675 1.114645 1.831781 1.488558 1.950691
+1 0.002393 1 1 -0.208997 -1.885380 -1.486997 -2.161098 1.521416 1.015513 -0.553201 -0.112471 -0.634677 1.827615 1.379259 0.966924 -61.762358 -39.956540 0.436647 -11.267352 -70.380446 1.612535 2.132274 0.636200 2.105132 1.197889 1.417187 1.668853 1.412651 1.922282 1.541508 0.882442 0.705375 1.489488 1.819023 0.824458
+1 -0.042049 1 1 -0.267029 -1.764819 -1.544994 -1.457929 1.003675 -1.592834 0.324556 -2.136249 -0.236328 0.575738 1.899812 -1.013851 6.358918 74.341145 -48.377642 66.966213 51.149764 1.736299 0.971624 1.090308 2.313039 1.240326 1.415453 1.769652 1.295125 2.167142 1.660924 0.898634 0.586065 0.986783 1.604869 1.540893
+1 0.021180 1 1 -0.793114 1.486369 1.027060 0.311437 -1.136705 -0.575505 2.015169 1.010491 -0.123611 0.627673 -1.742154 -2.313285 -69.134704 -46.972827 -22.297434 -52.977072 14.343547 1.704811 0.509743 0.752370 1.588712 2.236434 0.750268 2.251557 0.674793 0.496911 1.080242 1.877272 1.061614 1.540026 0.719835 1.517940
+1 0.044065 1 1 -0.935093 -0.285781 -1.197211 0.371760 -0.456779 -0.603911 0.557011 -1.835407 -0.382932 1.187270 2.187408 -2.290857 -70.522905 21.529024 38.303231 -37.602647 -37.681152 1.268057 1.735205 0.582764 1.758674 1.281193 2.014409 1.916128 1.608578 0.873734 0.591794 0.537881 1.166252 0.704288 1.220723 0.434748
+1 -0.000277 1 1 0.227673 0.048037 1.535449 1.254042 -1.830556 1.026550 1.172840 -0.001156 -0.574377 2.137073 -0.049112 -0.752590 -23.436380 4.754060 -48.504829 29.339021 50.921318 0.393820 0.931988 0.918881 1.126469 0.311989 0.357520 0.594535 1.606550 0.527227 2.097636 1.223606 1.651825 0.968393 0.774081 1.977661
+1 -0.055802 1 1 0.585982 -0.296750 -1.765930 -1.361598 -1.011831 1.165454 -1.615308 -0.402090 -0.361489 -1.278513 0.526252 -0.441878 2.454075 -4.359957 72.206490 74.476199 -28.520810 2.136107 2.047134 0.687519 0.626797 1.572429 0.805507 1.412320 0.857997 1.613539 1.000041 1.691019 0.464582 2.227417 2.190085 0.267268
+1 -0.057800 1 1 -1.305390 1.190632 2.139978 1.663464 -0.760544 2.245135 1.889350 2.219991 -1.298376 1.261951 -0.850768 -1.475293 42.782933 -47.252216 -67.994551 65.587859 -14.848850 1.905557 1.688020 1.797184 0.512923 2.443854 1.609931 1.112346 1.442630 1.779104 0.400466 2.377973 1.346813 2.383506 2.082268 1.678057
+1 0.048705 1 1 -1.230061 -0.377927 0.473955 1.823293 -0.578986 0.061774 1.502099 1.511142 -2.016980 1.551926 0.153186 1.630223 42.265270 -47.599957 -62.477452 -58.542015 -65.654323 0.591838 1.273652 1.263907 1.732937 0.722262 1.815080 2.042567 0.426332 0.619933 0.960233 0.888600 0.692436 2.279308 1.326815 1.529702
+1 -0.045031 1 1 2.338109 -0.008247 -1.950911 -0.161000 -1.021219 -1.104987 0.012595 -0.375488 -0.935357 -0.015401 0.337710 2.180300 24.581903 48.035663 35.382247 69.427273 14.176542 2.352028 1.785421 0.827458 1.337116 1.409448 2.097742 0.751902 0.470740 2.226294 1.319081 2.050195 0.379939 1.628288 1.386609 0.735285
+1 -0.043346 1 1 0.711445 1.933275 0.627051 1.937472 0.475082 1.911340 -0.468454 1.102461 -0.054214 -1.688257 -1.248880 -0.947837 73.098689 69.661956 58.496425 49.412467 -74.668034 0.690194 0.586641 1.672654 2.298018 0.781813 1.428412 1.326049 2.157352 1.363438 0.544104 2.254725 2.155687 0.382211 1.567045 0.326547
+1 -0.013853 1 1 2.100064 -0.023543 0.150646 1.361860 0.704533 -1.142111 -1.894064 -1.339576 1.547144 -0.115533 -0.262333 1.764398 -26.152645 -47.512433 58.539130 17.158226 -71.693439 1.350664 1.852956 1.884264 1.568766 2.255455 0.929162 0.670986 1.762122 0.730419 1.658158 1.656056 2.329449 0.297862 1.411578 1.885978
+1 0.010091 1 1 1.682618 0.714527 1.882237 0.488626 -1.358346 1.803441 0.338167 0.434752 -2.038046 0.912362 -0.045237 -1.608241 17.911493 -11.536647 53.574252 -27.542686 -9.918480 0.626603 0.564914 1.002713 1.598300 1.374138 0.385682 1.400630 2.389725 0.855533 0.689490 2.258858 1.882069 0.687027 1.356328 0.304035
+1 0.043103 1 1 -0.500412 1.195262 -0.147739 0.383061 0.977565 -2.163429 0.034576 1.487213 1.073363 0.994145 -1.528855 1.189211 58.193998 66.527254 23.557432 -70.247109 6.836701 1.441515 1.038743 1.910806 2.160996 1.861508 1.608822 0.471478 1.127101 1.944785 1.754963 1.906795 2.254679 1.387234 2.232753 1.880571
+1 -0.004295 1 1 -2.139749 2.184689 -0.875527 1.804305 0.724918 2.179267 2.247930 1.731621 -0.352974 0.471483 -2.019056 -0.368603 53.633786 73.044145 52.950716 -7.320351 -33.142092 0.337969 0.501763 1.631395 1.857960 0.482448 1.003187 0.572456 1.773219 0.492077 0.837657 1.754073 0.452916 1.910954 2.397892 0.861761
+1 -0.029749 1 1 1.369961 0.208010 -0.572971 2.204423 0.933709 0.590854 1.480066 -1.231980 0.356452 1.436549 -2.202310 1.586983 9.598771 -73.453289 -29.430799 56.562347 -56.636268 1.588765 0.878153 0.619889 2.471856 1.988862 2.297215 0.797274 0.284993 1.130008 1.294090 0.525340 1.881770 2.406921 1.875666 1.068394
+1 -0.053386 1 1 2.002545 0.897621 1.953926 -0.996243 -0.740235 -0.428557 -2.228221 -0.351900 -0.337782 1.322358 1.249404 0.327930 -62.828830 35.849574 -26.217154 68.296329 56.401874 0.569374 1.724104 0.774353 2.055312 0.885883 2.279716 1.434751 2.114825 2.115174 1.226598 2.434001 0.255867 2.110457 0.692682 1.898236
+1 -0.031365 1 1 -0.705516 -1.234217 0.443983 2.309275 0.743695 2.018934 -1.686696 1.435317 0.658056 -0.035610 -0.017927 0.298820 -36.220487 -57.725448 8.391322 32.946923 -61.062685 1.666752 2.094725 1.798986 1.560428 1.614501 1.416956 2.286911 0.867429 0.387631 0.406873 2.070548 0.447283 1.733488 0.988539 1.872792
+1 0.000996 1 1 -0.426413 0.814336 1.764326 -2.035655 -1.308440 1.763682 1.269261 -0.517785 1.369836 -1.895566 1.685101 0.033133 25.584701 -47.930574 -69.154625 68.218618 -49.682194 1.995427 2.396386 0.314743 1.627851 0.789697 1.182235 1.568060 1.628120 0.807071 0.694898 0.893327 1.390278 1.656930 1.273027 2.010522
+1 0.017008 1 1 -1.856948 0.428116 -0.478241 1.544844 -1.074977 0.163989 -0.585787 -1.143382 0.306282 1.749011 -0.246589 -2.234509 74.487882 17.834968 52.307178 -23.262490 -72.672259 2.085088 1.827815 2.341150 1.215542 1.120888 1.014533 2.254373 0.751402 1.058111 1.172632 2.174510 1.739527 1.231115 1.842491 1.490522
+1 0.011733 1 1 0.754396 -1.898576 -1.782157 -0.775789 0.487617 0.536730 1.308406 -2.334045 2.350355 -1.538267 -1.484301 0.739492 65.789088 67.196882 27.988344 0.093134 65.309266 0.667557 0.378296 1.026648 1.123813 0.670839 1.541797 1.228548 1.449753 2.255103 1.762673 0.996590 2.190110 0.678164 0.908842 1.158406
+1 -0.062497 1 1 -2.203826 -0.327141 1.094345 0.208853 -0.533601 -0.548691 0.288030 1.289511 0.537999 -0.926828 1.953447 0.361761 36.030835 20.244039 41.557785 61.698224 12.043615 2.380596 0.429853 1.292250 1.099322 0.805971 2.453286 0.384956 0.455059 1.928093 2.455833 0.439031 0.287310 1.812407 2.125813 2.290284
+1 0.017209 1 1 2.206682 1.200972 1.572557 -1.827853 -0.654211 -1.327079 -0.480922 -1.102632 1.884877 -2.254195 1.355121 0.539235 31.771946 -8.909396 -40.216305 -15.440050 -0.926933 1.690543 1.447124 0.812638 2.008344 1.233724 0.695377 2.201761 0.754031 2.499238 0.933999 0.978866 1.305087 0.854320 0.555281 1.105061
+1 -0.002103 1 1 -0.080891 2.349839 -0.784261 -0.528007 -0.780059 -0.587736 -0.919250 2.092135 -1.332383 -0.081383 -1.215910 1.827460 -39.036766 9.068295 10.835680 15.270402 -0.361828 2.406333 0.989488 2.079980 1.477362 0.516729 1.156139 1.722844 2.088356 0.499733 1.267490 1.205299 2.207542 1.159517 2.244992 0.580306
+1 -0.000266 1 1 -0.773219 1.277513 1.517491 1.025152 1.232913 1.198133 0.986840 -1.793609 -0.030577 -0.257875 1.289568 1.489637 -19.069745 44.799424 -56.081693 34.984877 -9.173238 1.755889 1.729624 1.297264 2.112383 1.564091 2.418709 1.996680 0.950349 1.262067 2.306655 1.957063 1.109765 0.822415 2.082104 1.166157
+1 0.006136 1 1 2.345356 -0.733782 -0.359549 -1.649283 -1.232485 1.288186 1.830189 2.225398 0.039766 -0.818736 -0.320413 1.076493 56.023159 31.229942 31.627628 -34.459713 -14.402082 2.038059 1.157872 1.609384 0.910625 1.874363 1.666824 1.054909 1.355629 2.055794 2.225750 1.182110 1.726934 1.079390 1.059935 0.330811
+1 -0.024323 1 1 -0.893104 -1.442525 0.725066 -0.053620 -1.119087 -1.351171 -0.125039 0.195202 0.931355 -1.266086 2.037984 -1.958821 -36.540169 -30.619905 21.262028 50.897497 -15.767183 2.139274 1.281955 1.321904 2.238570 0.649407 1.331383 1.801718 2.478924 1.528396 1.005382 1.461064 1.096755 0.410874 1.809224 0.382135
+1 0.003590 1 1 0.999759 -1.435818 0.343531 1.053975 0.282147 1.374173 0.305761 -2.284425 2.220502 -2.136913 -1.978016 1.387900 3.621935 -26.135778 -64.026860 0.570584 -10.202024 1.143814 1.575041 1.955006 0.279741 0.607937 1.843221 0.267254 2.241869 2.090871 2.262251 0.395183 1.345936 1.143668 1.382626 1.299771
+1 0.027032 1 1 -1.879469 -1.086970 1.226611 -1.055153 -1.230588 0.187912 0.931702 -0.159739 1.323459 0.902957 2.103434 0.073895 -67.270047 -57.680787 9.019571 -58.061598 58.729839 2.461006 1.879555 1.175055 2.403395 1.116869 0.969630 1.324715 2.244090 1.169993 0.571730 0.815145 1.398828 1.358455 2.310028 2.385706
+1 0.007351 1 1 1.462788 0.550897 -0.920771 0.084997 0.693633 -0.564940 0.515134 1.203111 -0.172549 -1.919972 1.462771 0.260091 -55.627982 10.510718 -46.364517 1.567348 -57.580396 2.069146 1.633955 2.140921 1.953082 1.692952 1.444869 1.168714 1.577076 2.422277 1.217739 2.040136 2.308509 1.618007 1.838235 1.969908
+1 0.004528 1 1 0.364186 -0.511969 0.155070 0.311614 1.825569 -0.032904 -1.662951 -0.032850 -0.762098 -0.306107 1.196371 -0.362079 -56.037185 33.037468 -39.267836 25.473602 34.833508 1.326626 0.596428 1.921310 0.955403 0.702646 0.626672 1.730722 1.740097 1.811489 2.439139 1.110599 1.342066 1.358712 2.114893 1.002807
+1 -0.036405 1 1 -1.019903 2.163300 -2.216708 -0.056112 -0.602588 -0.769626 0.401953 -1.934605 0.580719 0.790654 -0.412304 2.326695 43.050473 -50.707240 63.422090 35.070085 72.916158 1.402980 1.376061 1.201709 0.376830 1.132213 2.361573 2.460792 0.538008 1.056579 2.415323 1.330717 1.852888 0.742492 2.066814 0.695112
+1 -0.017674 1 1 -2.288892 -2.174833 1.590024 -0.419093 1.323499 1.574742 1.918760 1.727679 -0.642365 -0.138116 1.893011 -2.211962 -13.147498 -19.994746 -51.698089 60.221571 -56.057722 1.192873 0.364365 0.883001 1.094389 1.138563 1.072269 0.626322 0.344380 2.499261 1.331178 0.607192 0.580682 0.525202 1.826620 0.260068
+1 0.003012 1 1 0.510195 -1.704399 0.775504 -0.565393 2.333117 0.904261 0.465891 -1.758147 2.211956 0.311655 -2.186932 0.874729 -34.603470 -30.512624 24.321326 18.528169 2.933946 0.787517 0.552203 1.121506 2.403563 1.677213 2.413592 1.495244 1.814687 2.192590 1.859591 0.901726 0.803982 0.527290 0.910606 1.554454
+1 -0.047408 1 1 2.022309 -1.521102 -0.443054 -0.825870 2.302054 1.910104 2.325342 2.186157 0.250194 1.561463 0.211357 -0.868904 0.796438 35.735768 11.054983 -48.898257 17.002422 1.520577 2.341842 1.583897 2.308916 1.693806 2.296315 1.424081 0.535644 1.814027 2.350807 1.514141 2.170839 0.795553 0.616686 0.390308
+1 0.009268 1 1 1.622266 -0.463550 -1.298044 2.130158 1.547249 1.652426 2.220861 -0.816435 0.645706 -0.253007 -1.711653 1.376751 38.996439 63.148561 -62.133348 24.814203 52.311928 2.223497 1.566502 2.449384 2.298000 0.478475 1.721051 1.197169 0.566214 0.354466 1.014481 1.375967 1.877558 1.372465 1.522438 2.111276
+1 0.048076 1 1 1.988268 1.275193 0.219813 -0.118011 0.501858 -0.444804 -1.965895 -2.235663 1.793630 0.380466 -0.218094 0.725882 -15.346374 73.486944 -4.929320 -47.077203 23.450463 0.353853 1.964994 1.659846 0.784760 1.466154 1.153538 0.759987 1.351222 2.236616 1.561492 1.487972 1.090628 0.941474 0.606210 2.066071
+1 0.015459 1 1 1.579754 1.322690 2.111083 1.396165 -2.343369 1.149755 -1.568378 1.365900 -2.082059 1.030399 -0.112878 1.947440 -51.623001 -27.774038 1.741699 22.743737 53.992031 0.535944 2.361636 1.265732 0.911086 0.614773 1.992555 1.374949 0.518491 1.527446 0.778595 1.345544 1.302901 2.352977 1.990127 1.059109
+1 0.034326 1 1 2.355507 0.232162 0.094702 -1.128059 -1.343079 -0.787859 0.274787 0.202481 0.755345 -0.084497 -1.715541 2.009641 74.412508 -48.982640 -51.231952 -55.421186 36.128912 1.654380 1.162074 2.477396 0.599713 0.873093 1.074393 0.322020 2.448056 2.482540 1.547000 0.920585 0.528963 2.035137 1.554183 2.400510
+1 0.058166 1 1 -0.411097 -0.946664 -1.549545 2.174060 -0.445149 1.656596 1.616622 -1.068272 -0.241592 1.640350 1.885181 -1.868722 14.749748 -50.986557 18.944713 -46.200701 54.813225 0.563071 1.530946 1.118360 1.279592 2.105625 0.496409 1.649898 2.337827 1.604396 0.324784 1.652369 1.118025 2.392599 1.908720 0.851664
+1 0.009967 1 1 1.013709 2.118126 1.948559 -1.663595 -1.443200 -1.196416 -0.404085 -0.906803 -0.778548 1.243812 0.582385 0.516666 -42.503626 -58.439457 8.049113 -18.559886 63.999913 1.322973 2.202553 0.557599 1.811497 0.329274 0.610465 1.583163 1.218649 1.578662 2.076518 1.785320 1.380218 1.322188 0.266968 1.927496
+1 0.048790 1 1 -1.014193 -0.824294 0.509126 -0.821519 0.023195 -1.296419 1.172139 -2.350936 1.203585 -1.630759 -0.908971 0.494077 22.933432 -57.815143 0.898772 -44.345628 33.031542 1.541866 2.391045 0.546653 2.347240 2.318668 1.360966 1.761810 2.247278 0.758427 2.129344 0.875488 0.820730 0.756843 0.268123 1.088243
+1 -0.008504 1 1 1.133498 -1.494551 -1.882737 0.526238 -0.669360 -1.454794 1.872262 -2.227250 1.829291 1.270460 0.787331 0.288176 -30.866767 72.252457 -52.960195 -1.993613 -56.650240 0.316248 2.172968 0.570758 2.479867 1.629154 2.435015 1.553513 2.396915 2.445956 0.927733 1.413921 0.772926 0.573306 0.297800 0.381942
+1 0.010116 1 1 0.877174 2.312531 -1.072875 -2.208203 1.503874 -1.652582 -0.124361 2.172485 1.360393 -0.390503 1.171542 1.746772 -6.077268 9.355733 41.812371 -9.472697 -57.614758 2.406517 1.835843 2.256641 0.616587 0.977072 0.391043 1.514690 2.396914 2.426533 0.733828 0.440413 1.017961 1.378214 1.395840 0.628966
+1 0.027726 1 1 -1.442603 -0.587857 1.766682 -0.147698 1.070779 -0.034960 1.476622 2.150485 -0.818672 0.752673 2.129636 2.195701 13.865708 -59.041411 -58.986903 -42.879076 -68.625766 0.726377 1.214509 1.757630 1.736577 1.144172 0.852697 0.275029 2.408651 1.691328 1.151569 1.415926 0.723312 1.446739 1.093199 1.393255
+1 0.000934 1 1 2.199839 -0.707539 -2.248804 -2.292598 1.508882 -2.304859 -1.925569 1.654492 -0.763812 -0.838150 -1.454330 0.245913 9.169197 56.694068 57.201761 39.999067 -35.678605 2.120370 0.806200 1.808462 1.070942 0.819508 0.479277 1.703776 1.106706 1.150721 0.675560 2.133771 1.044510 2.072772 1.825588 0.909313
+1 0.041002 1 1 2.206057 0.124615 2.109977 1.664056 -0.233455 1.744100 2.025681 -1.388294 -2.024985 -1.052207 1.152704 0.868981 40.316654 51.996016 -2.956694 -43.161230 -10.789210 1.611168 1.644543 2.338914 1.879799 0.785989 1.862760 2.407643 0.498475 0.373209 1.029015 0.404418 1.304965 1.050350 1.232201 2.094192
+1 0.022697 1 1 0.688648 0.476947 0.267367 -1.979895 -1.912534 -0.750878 -0.223927 1.663525 0.256225 -0.745906 -1.488832 -0.016098 -62.333371 -36.959667 -31.127135 46.246872 -28.825191 1.900225 2.084824 1.886231 0.890428 2.172216 1.426607 2.482601 0.327004 0.714270 2.478601 0.603049 0.701997 0.962145 1.518866 0.586350
+1 0.014108 1 1 1.173045 -1.262046 -0.744478 -1.048137 -1.120728 -0.649327 0.656012 -1.403811 1.089328 0.705603 -2.006808 -1.857426 57.642850 -46.620570 48.075814 -39.800020 -68.942986 1.753530 0.334752 0.422997 0.816932 2.179676 0.806469 1.821416 0.547639 0.916670 2.218773 0.923337 1.777634 0.449470 2.492139 0.877103
+1 -0.017902 1 1 0.486475 0.187825 -0.530515 -0.530541 -0.958322 0.423328 -0.830790 -0.278876 1.760709 -1.573788 -0.021073 -0.736653 -47.300097 27.264900 -8.824621 34.600437 -20.456997 1.063848 0.835462 0.852241 1.613403 0.958063 0.422264 1.990260 1.045670 1.323116 2.357935 2.058904 0.506938 0.851432 1.524705 1.961106
+1 0.035657 1 1 -0.490064 0.752572 0.417366 -2.068493 -1.865425 -0.675211 -0.837756 0.452370 1.894842 0.280448 1.104758 0.862263 46.462368 -6.974418 -69.038808 64.762266 59.410511 0.811857 2.383546 0.507621 1.086872 0.806476 1.945193 1.850643 1.253742 1.885272 0.520389 1.921906 1.971837 1.907352 0.369585 0.867037
+1 0.067425 1 1 -1.864672 -2.148031 -0.350582 -1.745668 -0.105329 1.589638 -2.192984 -1.891945 1.274941 0.706020 0.281866 1.378974 28.048894 -32.236636 -1.137579 -69.292799 -4.075279 2.226792 0.688955 2.262920 0.402635 0.583285 1.528015 1.347047 1.827256 1.947171 1.355741 1.686065 0.449160 1.788458 2.368491 1.725836
+1 -0.010775 1 1 2.166744 -0.875461 -1.792769 -0.056154 -1.305316 -2.282375 -1.029713 2.214118 -1.054205 0.562875 -2.241264 1.910519 -4.007049 3.526872 26.134416 41.137077 40.860434 1.994743 2.145574 1.409871 2.446011 1.849423 1.007502 1.083807 1.038054 1.580241 1.603179 2.372533 2.159042 0.515404 1.394000 1.208320
+1 0.009613 1 1 1.241680 -2.259982 -1.660284 -2.343796 -1.311964 -0.918481 0.881095 2.242444 -0.928959 -0.866313 1.166170 1.000236 59.802000 -57.779996 -8.398573 -4.824624 62.549268 2.358234 0.341634 1.335643 1.403758 0.960075 0.484398 2.276001 2.001661 1.420338 0.613067 0.318771 1.836133 0.386451 0.828450 2.257007
+1 0.003161 1 1 2.314016 0.322372 -1.140267 0.819227 -0.859382 -0.165570 2.287988 1.127876 -1.722645 0.417279 1.174709 -1.579517 -65.534876 5.335101 -32.951057 -8.407299 -1.472783 1.329046 0.770549 1.112980 0.845676 1.530573 1.591497 1.783319 1.492047 2.075517 0.717177 1.840744 1.378283 0.308601 1.915266 0.628760
+1 -0.000940 1 1 -0.578536 -1.800060 -0.076609 -1.081659 0.954902 -1.366114 -1.512242 -2.341476 -0.018527 -0.373064 2.108779 0.375758 24.183938 -40.550513 67.534426 1.103108 -60.070621 2.021179 0.962008 1.473332 0.283670 1.393632 1.769080 0.677754 0.758485 0.855587 1.603221 0.828508 0.992337 0.454591 0.814488 1.593778
+1 0.007314 1 1 -1.647723 1.432055 -2.334982 0.734474 -2.151174 -1.333906 -2.119981 -0.140541 -1.159976 -0.572407 2.250217 -2.244601 -74.271159 24.623418 -4.211038 25.077031 -30.336953 1.027534 0.255018 1.337548 1.919018 0.689077 2.064355 2.107472 2.278030 2.347957 0.862975 2.025998 0.949645 0.687313 1.671194 0.265332
+1 -0.007525 1 1 0.832930 -1.457232 -1.404113 0.711121 1.187107 -0.552621 0.214097 -1.941315 0.898302 -0.724678 1.863875 -1.809203 56.579219 -73.062648 -63.917411 40.076501 65.754252 0.350704 0.790274 1.881472 1.894866 2.004028 0.697527 2.330949 0.755601 1.889003 2.477991 1.587197 1.519521 0.333219 1.661497 1.534653
+1 0.001585 1 1 -0.128653 0.708259 0.213366 -0.089875 2.140260 1.681825 1.518475 -1.287822 -0.414670 0.270524 -0.762156 -1.282897 71.333815 -42.569069 41.651216 -18.004961 -59.375321 1.809618 0.250444 0.954681 2.078393 1.803135 1.534521 0.438965 1.431391 1.885062 1.493451 0.930755 0.444600 1.642701 0.629580 1.097636
+1 -0.047882 1 1 0.114527 2.202662 -0.389245 -1.248687 2.294769 1.984839 0.188240 1.735219 -1.141826 -1.824476 -0.446057 0.539050 -67.261757 -68.349891 -56.622563 -55.411890 42.365939 1.290044 2.264371 2.278175 0.285969 1.778204 1.028928 1.198866 2.091357 1.444726 1.001340 1.026995 2.450582 2.178916 1.543296 1.680353
+1 -0.005767 1 1 -0.312031 0.576902 -2.099695 1.515111 -1.278932 -1.810110 0.664848 1.017744 -0.752002 -0.276014 -1.984394 -2.126602 53.377858 -28.342487 47.819213 -2.488321 28.782543 1.348028 0.307776 1.545118 0.802750 2.321728 1.032343 2.341074 2.177649 0.492662 1.675022 1.591302 0.757156 1.017588 1.842916 1.884715
+1 0.002690 1 1 -1.066007 0.122077 1.867025 -0.704983 -1.708260 1.859669 -1.826038 1.575275 1.449439 -2.337912 -1.396626 -0.686243 71.259765 62.878560 49.965575 71.417456 13.186159 2.421615 1.339540 1.649357 2.246059 0.510514 2.461676 1.882516 1.442599 1.259189 1.180777 1.821913 2.145237 2.489965 0.349821 1.695397
+1 0.028839 1 1 0.757617 0.399957 2.216279 2.281924 -1.841053 -1.025162 -1.403340 -0.425862 0.652158 -0.196243 0.419801 1.151344 49.976052 -52.495105 14.766039 72.819755 31.616681 0.348352 1.758154 1.539235 0.916391 2.027401 2.029684 2.145943 0.862916 1.027866 1.343603 2.440350 1.205945 1.812092 1.331533 2.067352
+1 0.081448 1 1 -1.725816 -1.039743 -1.420793 -1.590028 0.364362 -2.275768 1.637702 -0.207201 0.032020 0.946632 1.013629 0.768358 59.029006 0.508861 2.432297 -70.386334 66.892384 1.529589 0.798728 2.216689 1.899206 0.701368 1.636580 1.241500 0.888009 2.021533 2.407728 1.941366 0.541560 2.254129 1.154027 2.237964
+1 0.019085 1 1 -2.009542 -0.675627 1.602444 0.973588 1.672757 -0.093168 -1.369036 1.198609 -0.441828 0.922186 0.131057 1.987353 0.844633 -54.249101 -64.640218 41.859349 30.086261 1.521944 0.566718 2.080366 1.202506 0.272864 2.030555 1.044828 0.679037 2.077802 0.868954 1.259084 1.669087 0.843300 2.092928 0.835882
+1 0.004043 1 1 1.845688 -1.181860 -0.797485 -1.302250 2.132686 1.615238 -0.762867 0.907589 -0.160237 -2.325051 -2.002571 -1.320313 4.616102 32.821752 -64.811873 6.845198 -2.758705 1.141741 0.482109 2.057379 1.869073 0.504477 2.247592 1.526135 1.248600 0.972007 0.767661 2.083671 0.510843 1.240407 0.517198 2.298923
+1 0.004756 1 1 1.557567 0.703804 0.734297 -0.411385 -1.078138 -1.125520 -1.086002 -1.345340 -1.092740 -1.501160 0.129597 1.011036 -12.488506 -44.327891 31.138730 -1.371451 50.019288 2.487503 1.707487 0.478216 1.873007 1.386090 1.017698 1.446562 0.366570 1.948793 1.617679 0.834051 1.903498 0.838256 0.561519 2.448516
+1 -0.035114 1 1 -2.337388 -2.000748 1.041503 -1.990734 -0.298568 0.670134 0.324560 -2.070674 -0.829206 -1.939439 -0.550939 0.212068 52.773912 21.140289 -45.157653 35.317650 33.745112 1.436360 2.146821 2.117176 1.118767 1.363597 0.981077 2.452763 0.591719 1.521453 1.313295 1.551274 0.770300 1.437842 2.316067 0.381539
+1 0.023529 1 1 -0.952510 -0.842702 2.142033 -1.511588 -0.773128 -1.903249 -0.212880 -1.173529 -2.153746 -2.144824 1.722203 1.579834 -65.049274 66.857276 20.239548 -33.916981 -42.692403 2.406673 2.210425 2.368317 1.055892 2.122125 1.050069 1.001524 1.867767 1.057915 2.382645 1.121433 1.169025 2.307858 1.913365 2.429447
+1 -0.044085 1 1 -0.956190 -1.442120 -1.902157 -0.707367 0.636462 -0.104909 -0.773960 -1.752941 0.178594 -0.159473 1.094828 -1.099546 61.170466 -7.977072 29.348125 53.937011 69.345321 1.177025 1.763745 1.007801 1.613084 2.358595 1.910619 1.273841 2.195473 0.810151 0.703335 0.943396 1.413961 1.441060 2.388511 0.696354
+1 -0.007988 1 1 -0.852893 0.522743 1.842163 0.834315 -1.731804 1.996946 1.032250 -1.993995 1.435131 2.232839 -2.136338 -1.748224 -20.686750 17.786173 -17.798100 -32.660653 72.408495 1.668592 1.524036 1.969310 2.185002 0.332254 1.192106 0.977892 0.679854 2.301352 0.577770 1.074961 0.863390 2.243253 0.604593 1.890982
+1 -0.062555 1 1 1.494412 -0.443451 1.910484 -0.718377 -0.617578 1.765866 0.282168 1.728193 -1.432034 -2.022945 0.253628 -1.982762 55.422227 -18.631107 66.984518 58.794165 -46.460639 1.915553 0.946919 2.125618 1.254841 2.356034 1.612092 1.424547 1.606722 1.182625 1.383804 0.848575 0.757599 1.715472 1.930740 1.944628
+1 0.027955 1 1 -1.409922 2.052536 2.282202 -1.877423 0.301589 -1.723852 -1.018322 0.462389 0.644245 -1.249534 2.192111 1.350479 -66.265458 26.450845 -40.645438 -27.882687 -24.316559 2.298879 1.760663 0.954548 2.094755 2.299936 1.531171 0.399964 0.694601 0.402244 0.757028 1.119425 1.179671 1.224893 0.770166 1.434464
+1 0.073875 1 1 -2.192539 0.878468 0.489736 -1.558634 0.206073 -0.140462 0.166187 -1.346247 -2.197452 -1.578063 -1.181953 2.349494 -59.664562 -32.299596 -9.312792 -70.091599 70.489890 1.728838 1.585828 1.012965 0.654669 2.016464 0.454523 1.923561 0.547907 0.930646 0.861152 0.626993 0.370973 1.695156 2.487241 1.815174
+1 0.007436 1 1 0.826125 1.987120 0.831024 -0.498063 -1.747705 -1.361486 0.867546 0.706506 -0.974383 -0.904324 -1.525996 2.124854 61.684070 74.170904 -59.608632 7.728746 -2.963801 1.185991 1.694429 1.518725 0.467631 1.728036 1.595003 2.211818 1.018652 1.742484 1.421142 0.632261 1.161516 2.102541 0.402497 0.509875
+1 0.014781 1 1 2.342557 -0.652914 1.625544 -1.918207 -1.848034 -0.546071 1.917040 1.081600 -1.949284 -1.093018 -1.459847 1.753101 -69.948519 -74.762282 20.334115 55.464828 -52.638063 1.556072 0.400204 2.473950 1.178820 0.429022 0.814633 1.779290 1.274520 2.349751 1.762175 1.621328 1.413618 2.421204 1.173229 0.956757
+1 -0.022059 1 1 1.877783 1.025343 -0.274747 0.465653 -1.044828 -2.054848 1.271586 0.870915 0.794208 -1.947073 -1.626919 -2.341291 -51.653482 59.920048 -23.755475 41.738439 -52.061040 0.776613 1.785188 1.398024 1.337712 2.422801 1.009444 2.225220 1.263565 0.491802 0.717779 0.708114 0.275843 0.343355 1.012332 1.270429
+1 0.039224 1 1 -1.540411 0.174430 0.541800 1.704432 -0.223545 -1.345305 -0.498810 -0.160296 1.393029 1.490401 -1.883379 -0.833069 -27.886343 64.238616 -41.582773 -31.673720 9.784161 2.011041 1.571359 0.821943 0.896582 2.103367 0.793353 1.884872 0.550369 1.795686 2.340296 0.360715 0.291196 1.884466 0.475767 1.212887
+1 -0.019706 1 1 -1.735503 1.086880 1.970047 1.337815 1.854831 1.682333 0.633174 1.174601 1.317188 -0.818765 -0.801340 -0.114598 42.012945 61.571899 -11.088750 -68.628171 66.328602 1.147266 1.101325 0.719817 1.209671 1.448006 2.143569 1.459186 1.041257 1.402121 0.452821 0.317327 2.311741 1.928141 1.021445 1.419431
+1 0.029985 1 1 0.291768 -1.850505 0.333447 1.209504 -1.109578 -1.754712 -1.312094 1.611334 -0.413702 -2.316143 1.633841 0.866231 69.267200 23.837064 -20.459932 -70.080147 -37.031906 0.696382 1.094903 0.787245 0.470044 1.771917 1.116340 1.073924 1.449734 1.927710 0.523919 0.514752 1.687791 2.459089 1.158160 1.938021
+1 0.028052 1 1 -0.482164 1.574989 1.347358 2.023865 1.080372 0.977836 -2.322614 1.263146 0.385749 -0.956089 0.262920 -1.320254 35.931362 -1.603440 50.983560 -69.314443 -67.850009 0.548405 0.291169 1.419105 2.390230 0.353725 2.062905 2.497516 1.249967 1.446865 0.968170 1.527150 0.307939 2.025920 1.895287 2.336466
+1 -0.040805 1 1 1.940910 1.723315 1.407907 1.790356 1.906820 -1.037242 -1.796850 2.050244 1.463459 -2.315062 0.940492 1.489861 -49.100896 61.246313 66.781170 -58.872895 73.255606 1.479520 0.792320 0.269343 1.343569 1.871040 2.068391 2.441942 0.974311 1.246585 0.847324 2.231917 1.329945 2.381767 2.109513 0.585514
+1 -0.026502 1 1 1.723780 -0.196019 -0.524651 -0.930940 -1.173782 -1.692876 1.240539 2.124045 -2.243128 -1.142702 2.297727 -0.128615 42.888055 69.541253 -20.166577 60.347001 -47.947290 0.623433 1.291458 1.282037 0.440853 1.670783 2.354339 2.369208 0.283050 2.225001 2.087441 0.877333 0.341891 1.154648 1.426758 0.523945
+1 -0.002803 1 1 -0.676365 -1.386925 2.146846 -0.716689 -0.531682 -1.297786 1.759019 -1.689963 -1.634580 0.840267 -0.667921 -0.834820 -64.787268 -29.610233 40.813001 -5.886382 67.579761 1.570601 1.591717 0.996722 2.153885 1.588456 2.435884 0.393372 2.405038 1.720552 1.813789 0.602151 1.345885 0.294018 2.061501 1.396980
+1 0.075890 1 1 -1.532183 1.805160 0.960532 -0.985849 -0.396182 -0.032642 -1.980833 1.162251 1.106651 -0.316383 -1.878903 -1.008205 27.092878 -49.991472 -56.676678 -64.927958 5.814692 0.288020 2.497342 0.583140 1.332642 0.470529 0.927521 2.337501 0.634110 0.731420 0.467690 0.471079 1.168598 1.876420 2.496654 0.263827
+1 0.035205 1 1 -0.602314 -0.874595 -1.382820 0.450269 -0.432299 0.850352 -0.816295 -1.712907 -0.850646 0.584542 -0.931992 -0.010202 -57.716842 3.034365 -1.421509 -41.300538 61.863252 0.410199 1.712018 2.386547 1.438473 1.664824 1.188256 1.522106 1.042836 0.947536 1.237459 0.465404 0.295335 1.698666 0.733219 1.460589
+1 0.043057 1 1 1.706148 0.349621 -0.274981 1.249083 -0.347906 0.816982 -0.882936 -0.196765 1.071868 -0.580527 -2.273236 1.780117 -16.988103 -69.052513 -15.585390 -43.654566 -52.287030 2.303366 0.679771 0.914195 1.122893 0.954247 1.526032 1.778943 2.199969 2.132637 2.224784 0.696836 1.964232 2.341856 1.820144 1.658588
+1 0.067767 1 1 -0.217014 0.027296 1.657174 1.907747 0.415699 -1.815157 0.654301 -1.879906 0.996629 -2.205270 -1.031535 -0.134531 28.275296 22.907314 -46.769976 -62.986588 -65.589718 1.129149 0.348223 1.832327 1.672793 2.380655 1.422262 1.461285 0.309894 1.133312 0.570484 2.371400 1.115290 1.430502 0.447807 1.535988
+1 -0.000478 1 1 -2.030049 -1.333054 -1.935558 -1.300298 1.944144 -0.481795 -1.643951 -1.154932 -0.611539 -0.419353 1.659896 0.530294 48.672677 -58.324221 -5.185113 3.797203 69.585954 1.091998 1.454211 0.666728 2.200407 0.497722 1.208579 1.080242 1.872042 0.911487 0.606770 2.476884 0.996234 0.704698 1.366237 0.348560
+1 0.027235 1 1 1.372417 -0.934543 -0.466289 -0.209147 0.302105 2.242793 0.214121 -1.525999 2.062415 -1.330063 1.200067 0.508635 11.488805 42.350831 40.419087 -26.399580 2.259431 1.738717 1.122747 0.758187 0.357073 2.074841 0.593750 1.910681 2.306470 1.087200 1.826473 2.283703 0.951427 1.381663 0.863573 0.826700
+1 -0.041229 1 1 -0.379134 -0.962347 -1.241536 -0.035196 2.217160 -1.763419 -1.570621 1.377973 -1.804577 -0.587494 -1.557259 -0.237635 68.943572 -15.389393 -49.535744 -47.257571 -7.997014 1.287670 0.617597 2.195775 1.388717 2.415981 1.137193 0.548492 1.748869 0.739835 2.409516 0.484047 0.874709 1.240765 2.044960 2.394706
+1 0.026676 1 1 0.194215 -1.520136 1.647448 -1.344899 1.609222 1.793928 0.675987 -0.264743 -1.044659 0.775208 -0.838748 -2.077162 -47.038608 72.117165 73.188003 70.768189 50.953851 1.845630 0.252250 2.072888 1.528533 1.059739 1.539716 2.249795 0.312467 1.630772 0.380162 0.875131 1.576531 2.260865 1.851965 0.984166
+1 0.003911 1 1 1.955544 -2.085152 0.886337 0.803565 -0.186142 0.540805 -0.895394 -2.234382 -0.225999 -0.186230 -0.940406 -0.050215 -14.265079 -53.183530 -5.596225 -5.760248 -62.479858 2.140316 0.797182 0.984861 0.815115 0.887048 1.622298 1.955700 0.700941 1.221994 1.558531 1.229550 0.292127 1.785569 1.060655 1.185765
+1 -0.083749 1 1 -0.699302 -0.470477 0.078138 -1.499488 -0.037290 0.020836 1.466791 1.843116 -1.988795 -0.696556 -1.441503 -0.945885 67.321442 21.468944 -71.456888 74.086675 24.747914 1.197808 2.302764 1.798366 2.386497 0.598895 0.632832 1.749515 0.349879 0.421059 1.991343 1.252732 0.663470 1.433751 1.050908 1.606105
+1 0.009300 1 1 -0.831909 -0.228582 -1.185536 -1.315913 -1.308003 -0.317999 -0.765395 0.832149 -0.433989 0.721085 -0.996835 -1.266439 25.843096 -55.086881 -45.205549 -19.661212 4.006983 1.305368 1.070962 1.151568 1.397436 0.465287 0.579165 2.032262 0.480657 2.404509 1.836433 0.930503 0.709450 2.481332 1.498935 0.853222
+1 0.031181 1 1 2.004841 1.781790 -0.680742 0.456408 -0.912884 0.703943 -1.646666 0.348617 1.704257 1.551539 -1.647186 1.034245 -45.970894 17.178108 -37.530559 -26.105189 0.085772 0.498492 0.659379 2.425354 1.174123 2.482376 1.051194 1.920109 1.018823 2.358191 1.863417 2.204839 0.723146 0.920575 0.357642 0.390070
+1 0.003520 1 1 -2.254752 1.406877 -1.383854 1.924607 1.037322 -1.565109 -0.223483 -0.311386 2.000419 -1.858629 0.440176 -0.409947 -14.675385 -49.201753 16.134560 -26.445201 -14.486053 1.118685 2.238555 0.396695 2.009088 2.494766 2.280827 2.107492 0.367996 1.152167 2.474763 1.349754 2.309288 1.195928 2.218756 0.630336
+1 0.008471 1 1 2.170042 -1.995608 -2.117796 -1.128888 -1.139589 -1.916174 -0.676814 0.498697 -1.731989 -1.114216 0.404586 -0.100389 -6.695175 -25.803476 -29.013926 12.948812 -19.324880 0.726251 1.358627 0.694401 1.545606 2.245262 0.625098 2.277228 2.366782 2.247921 0.301344 1.441278 1.555935 0.356571 0.384952 0.393972
+1 -0.010099 1 1 1.547000 2.173117 -2.148991 -2.338038 1.207688 1.347471 -0.798968 2.056014 -0.515627 -0.056619 0.304842 1.115945 12.146820 1.604616 -31.216499 44.305957 50.212277 1.641168 1.862005 0.959149 0.668577 1.775505 0.671078 1.060193 2.417990 1.152098 1.319451 1.504544 0.612836 0.930754 0.434704 1.813168
+1 0.034114 1 1 -1.512646 0.295447 -1.275944 1.284098 -0.904700 1.579720 0.758228 1.235297 -1.145962 -0.648177 1.137651 2.341270 40.800265 -69.947755 -61.925079 -74.808884 -12.905442 1.348612 1.127989 1.117284 1.197926 2.046598 0.667967 0.514971 0.868529 0.865084 1.463385 1.865739 0.728031 2.024749 2.462862 1.577478
+1 -0.072481 1 1 0.819490 -1.150674 0.269636 -1.538480 -0.358579 0.504358 -0.843468 -1.306983 -2.013365 1.035550 1.632693 0.432905 -2.767052 -5.843000 46.698800 66.728395 -45.866629 0.918613 1.125735 1.481549 1.138070 1.787220 1.803029 2.011067 2.009056 1.954283 1.629831 0.320645 1.833873 0.646327 1.317575 1.483841
+1 0.069923 1 1 -0.739432 -1.057100 -0.972710 -1.055942 -0.364311 -1.573793 -0.098854 2.028599 0.532696 -0.524782 1.578959 2.100527 -53.021336 20.403321 18.612783 -74.948235 45.011295 2.197524 1.533955 2.186952 1.606846 1.013273 1.336320 1.529086 1.353821 0.918305 0.449384 1.052893 1.222476 0.663278 0.468164 1.678929
+1 0.006096 1 1 -1.242706 -0.860345 -2.201598 -0.579715 1.957655 0.402163 1.582247 0.810985 2.000365 1.946858 -1.982984 -1.987998 -45.686985 -11.156948 -14.824211 -0.512108 -56.994221 1.346791 2.017355 1.935503 0.999763 1.509579 1.992382 0.708879 1.880549 2.134620 1.803366 0.920336 0.845391 1.240677 0.551513 0.775128
+1 0.016168 1 1 -1.400476 0.579154 -1.959228 1.427499 1.204215 -0.474371 0.612924 0.129070 1.575769 0.319248 -1.811873 -0.698381 27.951678 -16.155964 -33.282906 -35.793045 -73.699576 1.843390 0.850402 2.204061 1.156406 1.724669 1.268318 1.626126 1.056499 1.079849 2.018508 1.060821 1.715944 0.864148 1.492215 0.405918
+1 -0.045702 1 1 0.742342 -1.860174 -1.949527 -0.464340 -0.445118 2.174810 -1.976757 -1.019347 2.081633 1.227794 -0.020853 -1.756084 -26.029745 68.083205 74.426843 41.952920 -47.270186 0.324747 1.019578 1.544587 0.868779 0.575616 0.872642 2.489843 0.538455 1.819106 2.222393 1.001689 2.385197 1.247300 1.630291 1.298694
+1 -0.001325 1 1 -0.968374 1.124879 -0.257668 0.064304 1.628213 0.526314 0.599823 1.419308 0.203853 0.256131 -2.322601 1.470638 17.018201 -25.101850 63.215342 10.246658 15.588704 0.615223 0.548772 1.958837 1.667273 1.859453 0.823314 1.443938 1.271292 2.097833 2.272803 2.241994 1.947457 1.663881 1.090633 1.023357
+1 -0.056890 1 1 1.068270 0.205043 1.404098 -0.965673 -0.592468 -0.332996 1.655730 1.189818 -2.106107 2.129247 0.377922 -0.564866 55.865613 -66.638178 62.147409 61.500669 -8.260281 2.416834 1.980574 0.254168 0.556152 2.242624 1.275946 1.570611 1.757562 0.598221 0.558465 0.614077 1.540028 0.748010 0.303978 0.703335
+1 0.034707 1 1 1.726261 -0.904815 -0.342918 -0.167444 -0.937356 -0.627728 0.818066 -1.507613 0.065715 1.769251 0.625565 0.526882 23.170873 32.860717 -9.927903 -58.271462 -18.455520 1.646174 0.497380 2.211139 0.872070 1.874990 0.952081 1.129782 1.997659 1.661992 0.840869 1.733628 1.078608 1.408371 1.995473 0.919647
+1 -0.063907 1 1 -1.818786 0.926637 -0.463858 -1.766425 -0.262387 0.857239 1.841008 0.278693 -0.127395 -1.702824 -1.022882 -0.788106 26.547623 -64.103246 66.743536 58.606985 -42.398115 2.348095 0.929166 0.739786 1.577933 1.067905 1.536805 0.579648 1.144916 2.105322 2.141587 1.910857 0.777076 0.563335 1.466085 2.247714
+1 0.017243 1 1 0.265362 2.010926 0.382429 -0.211610 1.323504 1.657171 1.857294 0.681034 -0.251025 -1.387956 -1.057974 -1.529998 26.248832 14.125311 -45.904725 -70.706951 -71.718987 1.659857 0.968866 1.978198 0.824236 1.181028 1.534523 0.477776 1.227282 0.431855 1.189455 1.423485 1.763205 0.936953 1.119711 1.478513
+1 -0.000109 1 1 0.964562 0.767493 1.443174 0.756648 -1.747525 1.670861 1.041627 0.091967 0.033346 -0.328188 -2.353963 2.164180 -49.762793 36.744087 7.877007 -61.149571 59.152913 1.120195 0.612016 0.653900 0.354897 1.508343 1.470961 0.940129 0.498382 1.060328 2.439065 2.116306 2.260858 1.746450 0.591706 1.304841
+1 -0.057683 1 1 -1.212412 -0.635822 1.439248 0.739955 0.425096 0.614904 0.419131 -0.682067 1.748488 0.379772 2.245310 0.113602 25.121660 -30.261636 42.682312 61.611044 46.821677 1.853768 2.023148 0.301790 2.182956 1.946338 0.844965 0.823309 1.356860 2.498976 1.044116 2.216772 1.040519 0.252810 2.483719 1.122077
+1 -0.031176 1 1 -0.987735 0.882448 1.415986 0.910123 0.029533 1.563779 1.437892 1.516476 -1.895428 -0.703202 -0.036339 1.863977 -3.423581 59.880290 58.031466 34.848112 -57.788455 1.366584 1.681686 1.103410 2.009427 1.434799 0.659323 1.489506 2.128683 1.031468 1.138357 2.111736 1.950419 1.939401 1.266317 1.737990
+1 -0.005253 1 1 2.300886 1.124787 -1.806850 -1.089246 0.678389 -2.295425 1.128517 -0.374329 -0.310288 1.611263 -1.594665 -2.181906 16.303456 -37.808157 -41.689176 -19.978747 67.191697 0.487825 1.381546 1.143635 0.824851 0.266032 1.952011 1.696427 1.352554 2.131670 1.732272 0.794564 1.980676 1.965355 0.971418 2.123788
+1 -0.009323 1 1 -1.807647 -0.352826 -1.764501 -0.905412 -0.957821 -0.568707 -1.527359 -1.948432 -0.900076 -0.804256 -2.000108 -2.351079 -38.332721 -8.044840 -59.633959 32.052522 56.739092 2.333878 0.484299 0.618083 1.365465 0.877897 0.815746 2.489116 1.819499 2.072563 0.573990 0.554635 1.505142 1.677590 1.999764 1.034876
+1 -0.047030 1 1 -1.430019 -1.143600 1.345260 -0.262117 0.689757 0.260984 -0.875538 1.630596 -1.833825 -2.066914 1.106960 0.159153 -55.900637 -72.013577 17.808970 65.356286 -6.897196 1.807396 1.154258 1.609939 1.249927 0.778292 0.753964 1.375797 1.276432 0.735089 1.392575 2.014842 2.449400 0.312104 2.286904 0.750451
+1 -0.013416 1 1 -2.244549 -1.458778 0.886818 -0.540387 -1.512166 -1.062704 -0.915162 0.113898 1.053318 -1.328135 0.627190 -0.435230 -41.016377 37.745044 30.946523 68.208547 -68.952474 1.611584 1.900944 0.662994 2.432388 2.393591 0.576709 1.240019 0.750249 1.933691 2.050412 1.775651 0.869796 1.919116 2.339001 1.084700
+1 -0.027923 1 1 -2.177524 -1.238906 1.758893 0.893071 0.883079 -2.123271 1.103859 -0.124282 -1.222851 -1.721734 1.596527 0.487591 3.223755 31.648176 10.899179 32.497984 43.619628 2.351294 0.702568 1.561484 1.364460 1.977025 1.356082 0.669153 2.449913 2.194251 0.528217 0.740902 2.334089 1.783706 1.254224 0.985582
+1 0.004815 1 1 -1.688978 0.783718 0.829520 -2.208494 1.322131 2.136064 1.846075 0.611947 -2.151147 -0.875808 1.795386 1.620512 -52.929907 57.058097 25.434624 -20.271165 -47.473926 0.710829 0.907871 0.579591 2.429150 1.973803 1.200434 1.443228 0.582746 1.468701 1.207489 0.770517 0.584752 1.432857 1.771661 1.303480
+1 -0.020498 1 1 -1.686025 -1.430273 -0.706887 -0.722796 0.509713 -0.380399 1.338388 2.063158 1.741587 2.198303 1.745779 1.970212 -19.361143 -52.727625 6.810598 15.721319 -71.784811 0.815211 0.254008 2.355479 1.287687 0.902797 0.814313 0.902263 0.835438 0.458091 1.140201 1.601728 0.498983 2.149841 1.127868 1.323915
+1 -0.006701 1 1 2.044437 -1.886603 1.522294 1.633618 1.834766 -0.952697 0.713678 1.750222 1.248759 -1.092341 0.496266 -0.186734 0.303914 7.881658 17.027640 -16.458214 -13.203881 0.360545 1.933343 0.690361 1.153130 0.656664 1.807625 0.507426 2.306482 1.301612 0.935717 0.597110 2.130441 1.322899 0.969442 0.411006
+1 0.051907 1 1 -0.119099 1.065571 1.969524 1.975609 0.570052 0.575727 1.717583 -0.675555 -1.901469 1.438720 1.293845 -2.030560 -15.967543 -16.498329 62.577104 -66.619267 -70.028823 0.258664 1.865959 2.172856 0.948763 1.607668 1.325434 0.815973 1.808421 0.384918 2.058920 0.766957 1.497137 2.128127 0.673764 1.206203
+1 0.017504 1 1 1.459559 -1.896156 1.194302 -2.136891 -1.615071 -1.140894 -0.301018 1.893012 -2.188727 -1.031276 -0.480406 -1.861727 6.725506 -64.414614 -66.425576 35.340079 -39.289595 0.771569 0.252757 1.594977 1.769700 2.100347 1.781129 0.681202 2.461444 2.492861 1.766887 2.075492 0.296437 2.217906 2.102866 1.371497
+1 -0.044292 1 1 -0.164274 0.513470 1.504318 1.103337 0.530772 0.129824 0.108849 1.023409 0.216402 -0.888895 -1.381101 1.064814 -41.881295 51.080434 58.861895 41.866378 -1.791521 1.973531 1.133524 1.895020 2.342494 1.295195 1.090593 0.344958 0.960420 1.772920 2.208908 1.609951 1.448948 2.218476 0.419505 0.619327
+1 0.006288 1 1 1.444676 -2.266590 0.378973 -1.752567 1.754250 -1.729983 -0.389513 -1.038792 0.427475 -1.827221 0.539758 0.369203 -32.653252 46.799634 -38.553128 37.585888 56.019906 1.023347 1.899208 0.743207 0.587595 1.957552 0.331615 1.695184 0.713539 1.441885 0.502337 2.272715 0.772249 0.440071 2.018004 1.597759
+1 0.010124 1 1 1.277340 -1.397132 0.231956 1.339402 0.243282 -1.507137 -1.353364 0.714309 -1.769820 -0.766732 1.912902 2.218067 -20.758344 14.512422 10.272262 -4.087383 3.360779 0.394193 0.459679 0.825275 0.645311 2.235133 1.380377 1.746552 2.307630 0.333353 1.670334 1.556645 1.029972 0.738464 1.862987 1.726244
+1 0.006290 1 1 2.348453 -0.518762 -0.905106 -0.530562 -1.308174 1.519155 0.714467 0.874946 -2.150641 -1.794524 -1.270937 0.626621 -18.155962 -47.256734 6.069319 7.044621 48.952020 1.174006 0.527054 1.446165 0.436524 0.901826 2.490322 1.842963 0.433774 1.939730 2.284958 1.787579 1.093910 2.097068 0.672059 1.791735
+1 -0.024906 1 1 0.635729 1.703638 0.569561 1.742172 -2.099373 2.207765 0.554204 -1.893100 0.718729 1.817491 0.871855 -2.270841 -12.207822 23.127315 50.778615 -63.822820 -20.131980 2.002177 1.089182 1.385068 1.842578 0.705495 1.252710 0.290610 1.026217 0.629950 0.575845 2.479226 2.102631 1.911863 1.927314 0.618438
+1 -0.013958 1 1 -1.920585 0.588743 -1.010605 -1.786229 1.479608 0.488637 -1.166492 -1.685735 -1.269294 -0.045976 0.106887 1.033411 -42.525915 16.946683 -27.103033 29.330056 50.245318 0.970787 0.510116 0.275871 0.806621 2.128626 2.316266 1.477558 1.574166 0.755599 1.854313 2.186745 0.366606 0.302811 1.342439 0.874904
+1 0.052161 1 1 2.324403 0.534871 -1.664636 -0.084077 0.631110 -0.515312 0.520044 -1.096340 -0.751807 -1.707073 -1.755612 -2.309814 -12.489038 -53.260517 50.484232 -61.505939 69.691217 0.629206 1.571477 0.562625 0.789338 1.911798 0.841646 1.295120 2.078426 2.364326 1.484504 1.307494 0.803763 1.343013 1.516646 1.526722
+1 -0.018309 1 1 1.809502 -1.454861 0.742010 1.980652 0.506505 2.250906 -0.083319 -0.763744 0.305896 -0.030301 -0.333266 1.829445 -27.350253 74.295746 -61.401687 21.848984 15.867682 1.196873 2.335960 1.736630 2.045840 1.439731 0.308594 1.781699 1.271983 2.470466 1.129116 2.048477 0.756359 1.127047 1.034101 0.386396
+1 -0.020674 1 1 2.048094 -1.681221 -0.793962 1.360661 -0.602169 1.560023 -0.421451 -0.614100 -1.039450 -1.205931 -0.096398 0.908360 -42.593702 -72.347673 -47.345269 18.071472 -22.771444 0.330150 1.823325 1.122049 0.275390 1.724854 2.117842 1.075592 2.465880 0.543495 1.024144 1.781138 0.827571 0.981158 1.573597 2.441655
+1 -0.049369 1 1 -1.388420 0.579329 0.981507 -1.884955 0.949607 -0.818757 -0.666762 -0.202300 2.280358 0.116918 -0.029573 -2.240506 16.199287 11.420518 -55.357263 60.477708 48.840211 2.236275 0.326802 1.804857 1.224646 1.123134 0.507052 0.521360 0.250087 1.719622 1.935666 1.495092 1.519135 0.599499 1.772830 0.705705
+1 0.005290 1 1 -2.028953 -1.770560 0.938880 -2.030721 1.498164 1.346297 -1.669443 -0.760256 -2.342861 0.262462 0.408477 -0.684817 -66.013201 66.136730 60.025680 -48.393306 -46.286239 0.882777 1.826591 2.006213 1.413439 1.674536 2.426260 0.651422 1.447384 0.679171 2.077447 1.649813 0.914218 1.512270 2.222282 1.402022
+1 -0.000166 1 1 -1.043829 0.597755 -0.343407 1.029685 2.028888 0.670476 1.374221 1.109212 0.310757 1.569929 1.129357 -0.402820 48.059360 -16.333430 -15.957232 6.803313 43.281294 0.305675 2.236561 0.630187 2.300218 1.768610 1.775038 1.819218 1.853474 1.589260 2.446695 2.109146 1.168146 1.022306 2.401503 0.810473
+1 0.019343 1 1 0.336129 -0.832211 -0.595135 1.962902 -0.939535 0.449871 2.312463 -2.214302 -2.033870 0.424187 -0.535430 1.698247 -16.026315 45.728563 -40.048455 -44.378293 -65.964000 1.270800 0.576413 0.772568 1.295350 1.446457 0.851129 0.930695 1.691520 2.121893 1.651151 0.900840 1.675172 1.861144 2.248613 0.690865
+1 0.020330 1 1 1.289597 1.986422 -1.475568 1.424804 -1.680442 -1.847631 1.503652 -0.658488 2.192896 0.414865 -1.691588 -0.673759 0.360381 56.927152 74.639240 11.704727 71.350993 0.567021 0.422544 2.192250 0.653217 2.372328 0.968055 1.855127 2.363313 2.454080 2.469939 1.260000 1.323131 0.359061 1.744797 2.053812
+1 -0.018865 1 1 -2.231520 0.753200 1.554503 1.042771 0.474582 -1.777297 0.805373 1.926506 -0.036546 -1.610388 2.166964 -1.885782 37.679789 -15.791950 -65.310661 23.728378 -47.152127 0.838108 0.334837 1.855076 1.515829 1.286037 2.430921 2.486477 2.473252 0.699350 1.483247 0.428798 1.552100 1.138987 1.449170 1.454841
+1 0.011008 1 1 -0.465517 -1.379139 1.056842 1.342078 -1.898048 -2.328966 -1.829659 1.963343 1.760804 0.033186 1.696617 0.371223 -1.767872 -12.624821 64.625382 8.803092 53.559511 1.745586 1.822901 0.745412 1.636271 0.557700 1.268264 0.708575 1.263524 2.045283 1.065016 2.479058 1.519377 2.423910 1.661106 1.714242
+1 0.045380 1 1 -0.316936 -1.749955 -1.477095 -0.663693 -0.466657 -1.696622 -0.451292 2.088756 -1.578599 -0.755265 1.430871 1.331453 -44.785039 -2.155108 -70.902015 -50.159634 -32.964885 2.262613 1.983451 1.360359 0.557996 1.731964 2.373989 1.876908 1.686490 0.831274 2.471144 1.270469 1.765844 0.292163 2.386576 1.926251
+1 -0.028985 1 1 1.599371 1.167244 0.193073 -1.859489 0.130322 -0.946731 2.025142 -1.019473 -0.035072 -0.413413 -2.170912 1.509500 -42.538264 -40.603934 69.678083 29.548637 -26.063213 0.708649 0.266428 1.850942 1.782033 2.382052 2.394496 2.302652 2.166105 2.219604 1.379894 0.379479 0.646999 1.368169 1.323248 2.329774
+1 -0.000160 1 1 -2.158598 1.124964 1.166746 1.253964 1.575216 0.457490 -1.585579 -0.269167 0.002010 0.789079 1.380329 0.099460 -40.396277 -40.233548 -5.245026 46.854577 -15.120993 0.797173 0.844673 0.427369 2.295616 0.916472 1.145752 0.399256 2.297067 0.564006 1.502504 2.339302 1.650482 0.894745 0.476744 1.885420
+1 0.022042 1 1 -0.928789 1.984138 -2.167515 2.056480 -2.120216 0.608111 -0.652183 -0.225564 -2.293838 -0.482514 0.401814 0.429172 -50.198144 69.788899 -57.981704 51.494143 -37.941211 0.955930 0.562253 1.283606 2.067553 1.862437 1.479584 1.867246 1.307046 2.278856 0.476047 1.416956 2.274567 0.399453 1.109136 1.500953
+1 -0.012818 1 1 -2.108820 -1.051453 -0.306507 -0.823590 -1.787392 0.773253 -0.710543 -0.902915 -1.399230 -2.041191 -0.110793 -0.706116 -60.374899 29.067160 -18.244539 -35.964824 39.198980 1.633794 1.671107 1.039600 0.548087 1.695011 2.297944 1.794863 2.012534 1.910481 1.212651 2.034332 1.513664 0.900176 1.766051 1.514565
+1 -0.056486 1 1 -0.507912 -2.341049 -2.267758 -0.410475 0.089456 0.232817 1.672602 2.021404 2.124157 -0.345569 -2.317323 0.645716 -2.903317 -46.042131 19.905618 53.715751 -49.370860 1.734388 0.362859 0.313583 2.388495 0.436405 1.152515 1.577154 1.479665 0.973711 2.403603 2.354397 1.102249 0.501352 1.476002 2.410574
+1 0.008262 1 1 -1.719645 -0.988394 -0.768365 -1.970072 -1.764122 0.759164 -1.879873 1.549252 2.329073 -1.077963 1.814404 0.814241 5.574505 -59.290572 -46.648955 21.012040 49.362814 1.237263 1.685895 2.088472 2.444790 1.577826 1.523603 1.440228 1.919962 0.795733 1.390595 2.487433 0.535727 0.956344 0.771971 0.267664
+1 -0.030076 1 1 -0.462956 -0.749970 0.898709 1.398143 -2.088160 2.175467 -0.360760 1.557726 -1.329815 0.659682 -0.970430 -0.441814 36.586828 64.818583 -44.082087 -37.635950 2.593354 0.422377 1.647121 0.668715 1.848546 2.013315 1.532039 1.482110 1.572234 2.027795 1.893379 1.765542 1.968352 1.833136 1.762688 1.252894
+1 0.017248 1 1 -0.311307 -1.382930 -1.407496 0.409030 -0.805062 -1.402730 0.401622 1.919609 1.850252 0.135279 2.258555 1.247213 38.037267 -7.645580 50.737307 -8.089471 -59.742146 1.581206 2.078803 1.949142 0.735214 1.239583 2.414219 0.783935 1.101765 1.356456 2.448534 1.518470 0.673842 0.269789 2.091482 1.281290
+1 0.013188 1 1 -0.593621 -0.855610 1.970454 -1.252859 -1.843365 -2.194015 -0.371764 0.395299 -0.684894 1.355879 -0.849571 -0.196620 -38.536511 16.866353 -27.202210 12.456626 -41.487654 2.380034 2.238082 1.446945 2.310599 0.743568 2.144236 1.427774 1.844835 0.389339 2.125350 1.255903 2.213515 0.304062 2.127436 0.323283
+1 -0.009186 1 1 2.167765 2.147463 0.225163 0.258314 1.371235 -1.946419 -0.058719 -1.993052 -1.568216 -0.620438 0.818937 -1.008227 15.082141 -14.458046 3.615615 17.647086 44.573798 2.152290 1.792038 1.787074 1.599204 0.823737 1.805572 2.002470 1.519583 1.390078 0.544217 1.905053 2.227564 2.416098 0.864228 0.572230
+1 -0.001300 1 1 -0.996803 -0.724143 1.432209 0.251697 -1.460042 -1.515579 -1.872755 -1.352035 -0.510499 1.296134 -1.252017 -1.836745 21.694591 -29.015135 -7.375878 -66.383798 -12.491376 2.236725 1.146243 1.904722 1.157521 2.459201 0.795211 1.606040 0.962119 1.076132 0.309444 0.325299 1.298674 1.061196 1.273078 0.615702
+1 0.046004 1 1 -0.230420 0.921403 1.109046 2.242364 -2.283336 1.668039 0.722042 0.958793 -1.944235 -1.052745 1.529492 0.088773 -57.737463 -43.533701 29.090157 68.261490 70.856405 1.878942 2.123245 1.870551 0.609290 2.094230 2.473946 1.111922 1.076893 1.839240 0.852625 1.313366 0.491366 2.386557 1.605445 2.207765
+1 -0.005380 1 1 0.487924 0.978372 1.981418 -0.766864 -0.295010 -0.803634 -0.973615 -2.130227 2.002986 -1.121068 -1.652112 -1.654303 -24.816171 64.615401 -8.951612 0.262667 64.646913 2.435123 1.105582 0.261861 1.605023 1.872510 2.016939 1.689334 1.378457 0.972048 1.455165 0.954902 1.282569 0.381921 1.188785 1.409166
+1 0.027586 1 1 -0.966798 -0.652965 0.775697 -2.037205 0.916068 0.985503 -0.700465 -1.163998 -2.180622 -1.468458 -1.587457 1.148025 74.295741 -61.481516 30.163545 -41.306605 -40.106513 1.822573 1.985875 1.598014 1.073429 2.126244 0.523686 1.096165 1.749761 2.241418 1.258944 1.576729 1.082918 1.848245 1.458574 2.003305
+1 0.073079 1 1 -1.492091 1.757099 -0.975315 2.284017 0.354387 -0.282389 -0.738635 -1.807313 0.550639 -0.543990 -0.799805 2.131565 51.983619 -61.322036 10.536141 -69.084670 43.957245 1.966365 2.190456 1.994703 1.464146 1.144848 0.962916 0.985074 2.146483 0.940632 2.195649 1.517356 2.203891 0.547796 1.304283 0.840867
+1 -0.009989 1 1 -0.097382 -1.496477 -1.274159 -1.693893 -1.724999 -1.435789 0.844189 -0.710937 1.894956 2.201390 1.791332 -0.536343 15.280553 20.259674 4.344177 -37.412404 9.727224 1.156778 1.212387 2.095460 0.640785 0.424094 1.244040 0.836481 2.231524 1.470529 0.430453 2.381287 0.797204 1.360556 1.622213 0.526034
+1 -0.035936 1 1 1.245630 -1.845196 0.026000 -1.269706 -2.246801 -1.607358 1.265121 0.590063 2.321449 -1.994691 -0.832405 0.850049 -37.955289 35.451278 29.636818 -43.996189 56.056821 1.329861 0.975574 2.221851 0.893756 1.850014 1.931399 1.768590 1.442539 0.252058 1.089163 1.067730 0.846998 1.237594 0.501148 0.294242
+1 -0.059492 1 1 2.241037 -1.014049 1.592437 -2.279753 0.618364 2.029940 -0.488088 0.972154 1.134400 -0.459101 -1.937622 1.711519 34.347018 70.337762 16.764865 67.087568 -9.242448 2.307578 1.714756 1.146224 1.583369 2.433056 2.365771 1.006131 0.550080 1.443188 2.162430 1.204453 1.495051 0.824693 2.120019 1.656986
+1 -0.065867 1 1 -0.971476 0.831671 0.947102 -0.504402 0.109797 -1.903189 0.803816 -0.691896 1.483827 0.721189 0.753495 1.805508 66.791004 -43.595238 44.842503 67.942380 -42.426879 1.846713 0.459242 2.479402 0.553902 0.423891 2.343978 1.487298 1.011067 2.497829 2.013326 1.713996 1.887031 0.829271 0.299374 2.082073
+1 0.001759 1 1 -0.150856 -0.172961 0.588236 -0.109813 1.622378 1.417044 -0.151260 -2.247727 1.683328 -1.485069 1.975205 -1.513749 19.170132 -7.598957 -65.665081 66.988340 -26.969344 1.768647 2.392598 1.887236 2.030435 1.274545 0.527481 1.881141 0.841199 0.539953 2.232646 2.340160 0.312645 2.370273 2.421401 2.234892
+1 0.037838 1 1 -2.295488 0.065352 0.380507 0.469034 -0.779581 -1.977089 -1.882501 -0.218947 0.540758 -1.674872 2.236957 1.100611 58.491386 -35.268457 43.041146 -57.459633 -24.052182 1.449598 1.886296 1.975885 2.444013 2.028854 1.701360 1.013888 0.406480 2.202275 0.378078 1.848939 1.872942 0.284873 1.361679 2.494097
+1 -0.025964 1 1 0.391111 -0.376919 -1.422596 1.085983 1.036647 1.228048 -0.461770 0.334082 -2.244632 1.860768 -2.205014 -1.438559 44.733923 43.049859 -61.025134 50.579092 32.793569 2.297721 0.297668 0.403411 2.382662 1.407338 0.375964 2.325883 1.111334 2.449397 0.259118 0.493194 1.613518 0.649140 1.345635 0.583257
+1 0.018533 1 1 -0.013337 2.039167 -0.927582 -1.285311 -0.625721 1.554903 -1.650690 -1.318939 -0.338226 -1.414972 1.984639 1.546311 0.959008 68.046499 57.500373 -41.234815 -33.540991 1.023423 0.921253 0.507412 2.076329 0.854107 1.472205 1.593356 1.527907 1.780627 1.254891 0.946844 0.861285 0.621126 0.766345 2.465242
+1 0.011883 1 1 1.061252 0.064056 2.157017 0.578159 0.177012 1.524325 -1.924148 1.974734 0.005129 1.380358 0.592152 -0.263878 -20.508668 10.821829 -67.516734 -3.755469 31.832433 0.740617 2.048912 1.311009 1.376042 0.883209 2.347888 1.956923 1.000467 2.098491 2.079701 1.290638 1.006521 0.354009 2.324468 2.087822
+1 -0.010955 1 1 0.023778 -0.910547 2.281842 1.495089 1.500196 -2.195978 -0.370835 1.866865 1.307023 -2.016026 -1.279187 -1.373692 -52.510844 50.237497 -8.381258 -13.811648 67.625358 1.815814 0.881302 1.792954 1.429989 0.818231 1.504839 1.073014 1.904163 0.775692 2.061816 2.187651 2.094997 1.867340 0.627358 2.013935
+1 0.000431 1 1 0.410096 -1.737915 -1.751719 1.862072 0.861387 0.866153 0.859851 -1.381707 0.307515 -1.092140 -0.833223 1.244029 -14.969335 -39.615740 28.255384 -11.753322 11.909460 2.309393 0.724700 2.278592 0.541260 1.706802 2.474463 0.792812 1.785550 0.739637 1.334540 0.858403 1.681713 1.557431 0.746708 0.921848
+1 -0.009485 1 1 1.650621 0.156896 -1.983233 -1.471327 2.028635 1.139202 0.129891 1.246846 -0.248979 0.017642 -0.377739 -1.070660 64.592100 49.420392 58.535988 -35.653331 24.465950 2.113359 2.224578 1.733644 1.348365 1.469969 2.260817 1.057732 1.549234 2.475389 0.612102 2.090170 1.742279 2.491355 1.202559 1.152045
+1 -0.024964 1 1 0.989927 -1.742523 0.906061 -2.275989 -2.084023 1.012002 1.708342 -0.477041 -1.848968 -2.103422 0.128249 1.918337 -21.403571 -29.813611 72.645836 -41.434799 55.330814 0.549850 2.078046 0.463071 1.576626 1.602924 0.347674 1.607820 1.632256 0.573479 0.966846 1.787128 0.269204 1.255156 0.905703 2.398791
+1 0.039833 1 1 0.194012 -0.218197 -1.002541 1.787171 0.219071 1.548987 -2.122598 -1.724409 -0.941450 1.259450 -0.468700 1.673383 32.347712 67.994309 -69.642701 -34.879187 -14.487862 0.662480 0.552231 1.595761 1.448911 1.592922 0.985636 0.341529 1.834501 2.205199 2.274839 0.476030 1.139397 1.602680 0.734504 0.561533
+1 0.007912 1 1 0.679941 0.217646 1.154171 1.965013 1.551910 -0.116045 0.565914 1.710203 -2.183231 1.803198 0.978573 0.643741 -9.075761 13.679055 -46.127263 -60.912384 -4.443251 1.709270 1.195652 2.068977 1.044257 2.331600 0.445891 0.840373 2.395557 2.119684 0.537902 1.515287 1.177910 0.890178 2.469344 0.259961
+1 -0.054376 1 1 -1.764766 -0.640454 -1.006520 0.891200 -2.284916 -1.328245 -1.226739 -1.102195 -0.196877 -0.816176 0.296032 -0.874877 -44.767654 -9.965829 54.303633 -68.841071 -61.872162 2.343661 0.653167 1.530602 2.078940 2.002725 1.291625 1.837696 1.909449 1.861526 1.922832 1.780614 1.023839 1.155378 2.442062 0.737269
+1 -0.022272 1 1 0.418981 1.506526 0.512049 1.191230 -1.935416 1.080474 -2.019739 2.300228 -0.503713 2.254371 1.614381 -1.026731 15.946333 -39.987312 -66.750573 -26.882991 -22.425198 2.120430 1.819054 1.337083 0.861516 2.255656 2.067690 1.916354 0.909235 1.017487 2.409569 1.382246 1.657619 1.602271 0.621338 2.076283
+1 -0.008477 1 1 -1.931180 1.593431 0.285737 0.453582 -1.297378 -0.816091 1.722585 -1.432610 -2.283570 -2.258818 -0.948287 -0.554240 40.991115 -12.335359 -20.375525 -1.444280 25.982962 2.059586 0.705697 2.398475 1.675547 1.419352 2.053728 1.253760 2.187924 2.185309 0.996419 1.566426 1.165998 0.935540 2.117629 1.990455
+1 -0.003729 1 1 -2.011214 -0.513830 1.875349 -2.174542 1.765313 0.414583 -1.735175 1.892279 -0.386044 0.715115 2.349100 0.924376 -24.421598 -53.799827 -13.699285 6.123956 25.320744 1.611243 0.661587 1.300472 2.036732 1.355109 2.315085 1.890894 0.501334 1.167398 1.961166 0.309787 1.586174 2.324344 2.243685 1.120097
+1 0.024866 1 1 -0.921878 0.337767 -1.581299 0.980449 -0.822576 1.113456 0.952982 -0.648737 1.151900 1.483509 0.084778 1.724829 -45.169793 -18.706405 1.453565 -19.932594 -57.104366 0.578796 0.320219 1.413230 0.403110 1.820596 0.259233 2.437088 0.390493 1.260053 2.218777 0.977768 0.840066 1.745585 1.789144 0.390047
+1 0.002059 1 1 -0.231700 -1.741041 2.260370 -1.240779 -1.458191 1.326204 -0.084149 -0.572166 1.596423 -1.267091 -0.715599 -1.052871 -18.699799 -37.530170 -19.561562 28.830438 53.176038 1.820008 1.625662 2.250758 0.742431 1.033041 0.565983 0.969777 1.549496 2.373848 1.756727 2.309270 0.909671 1.592617 0.360071 0.711581
+1 0.018591 1 1 2.011709 -0.596113 -0.339701 2.059061 -1.148498 -0.855465 -0.302854 -0.686990 -0.889681 -0.460683 -0.237560 -1.268982 15.496462 49.036784 61.232864 -9.261592 40.422397 1.813284 1.106916 2.443754 2.174172 0.563353 1.773157 1.698601 1.884555 1.968774 2.183464 1.487532 0.452757 1.485410 0.777908 1.048401
+1 -0.004740 1 1 -0.765252 -1.481248 0.218702 0.058489 -1.868009 -1.688236 -0.893090 -1.206819 -0.886552 0.293279 -0.021133 -1.749772 51.243859 -44.465205 -26.693211 17.198680 8.215738 0.353731 2.154474 2.489637 1.582237 1.403409 1.844847 0.599630 1.729948 2.243108 0.413235 0.993348 1.701293 2.138598 1.173109 1.196740
+1 0.011150 1 1 0.882056 -0.459512 0.585228 1.178025 2.324995 1.058309 -2.270480 0.971515 -0.179727 -0.035344 -0.271821 -2.190872 19.548738 55.644266 -36.824150 -3.491674 -34.571252 2.289456 0.886937 2.000355 1.971381 0.997557 0.448840 0.909618 0.695527 2.472643 1.707130 1.229122 2.100142 0.588804 2.027963 2.472247
+1 0.031520 1 1 0.167309 -1.338527 0.319686 0.836796 2.256926 2.132834 -0.602601 -0.984752 -0.822882 0.676792 -0.862306 -2.184257 -41.464130 12.374033 70.366449 48.902474 53.872787 1.973911 0.768421 1.356036 2.143039 1.557845 0.959068 1.549910 0.328653 1.417938 0.783773 0.616278 0.288553 2.454012 1.321722 1.436680
+1 0.066556 1 1 -2.006727 -0.484092 2.153103 0.775559 0.355634 1.829755 -0.360020 -0.147923 1.993951 -2.181121 -0.417819 -0.827057 38.214925 -21.749920 -0.905451 -67.919726 -26.833562 2.249971 1.006694 1.008791 0.252035 0.708872 1.765067 0.728787 1.219034 1.308315 1.098420 1.388403 1.634678 0.786798 1.965528 1.626658
+1 0.034858 1 1 1.310682 -1.779922 -0.904775 0.328941 0.887597 -1.586938 0.453545 -1.911519 2.165682 0.121196 1.196918 -0.587286 61.843980 61.772718 64.068211 -55.571384 61.749160 0.897030 0.630124 1.236122 0.496320 2.408617 1.121332 1.721574 0.991410 0.619541 1.125646 2.240919 1.872095 1.808541 2.402278 0.331112
+1 -0.009985 1 1 0.396584 2.068277 -1.760705 1.639695 0.294520 1.993498 -0.362290 -0.597120 1.597013 -0.763126 1.261172 0.193053 -69.600013 -67.417525 13.665024 18.056796 30.569963 1.965609 0.746383 2.200770 2.094548 1.059573 0.998989 2.005299 1.816679 1.916730 0.488645 1.658470 2.407281 1.180124 2.089572 0.691331
+1 0.000790 1 1 0.902221 -0.837067 -2.110097 1.043930 1.101901 -0.038454 -0.693818 2.171404 2.053926 2.085153 -0.868228 1.953437 6.257058 12.367871 -33.191678 -2.533347 22.029768 2.189714 0.776715 1.250953 2.262896 2.247990 1.467909 1.404943 0.623939 0.795972 0.905100 1.269710 0.263325 1.456913 1.095333 1.256454
+1 -0.070383 1 1 2.171120 1.994886 -0.599981 0.625817 0.058267 -0.880553 2.152056 2.019466 -2.171323 -0.689628 1.900864 -2.185029 -4.327805 12.589895 -51.634774 74.358129 -62.925694 2.243004 0.919401 0.868199 2.062527 0.644791 0.257913 0.500899 0.601549 2.481596 1.439463 0.296343 0.643403 1.679301 1.509482 0.358606
+1 0.080352 1 1 1.845283 1.432971 -1.070650 2.204110 0.384817 2.218017 -1.502137 -2.142506 -1.731232 2.182592 1.582819 0.997701 53.388117 -5.917789 -10.285758 -72.733712 64.501482 1.771017 1.726383 0.820633 1.377153 1.555844 1.075299 2.043244 0.556856 0.571885 1.177173 1.991008 2.367922 1.165607 1.102890 2.275551
+1 0.016077 1 1 -2.309124 1.793785 -1.722526 -2.284068 -1.216773 1.469439 -0.765790 -1.095682 0.880455 0.908475 0.591230 -1.630518 -50.162270 72.724169 -74.897832 -7.869540 36.639533 2.134399 0.349366 0.801151 2.442247 1.590103 0.868720 1.827836 0.435800 2.245119 0.462462 0.340392 0.725207 1.807090 0.511875 0.588169
+1 -0.037547 1 1 0.538853 -0.706963 -1.996920 -0.602255 0.104666 1.403855 -0.338986 -0.063306 1.018526 -1.738438 -1.106660 0.167053 -29.668281 -34.800277 -38.250502 23.809830 -28.185138 1.260704 1.910493 1.401899 1.216702 0.367059 1.154354 0.977427 1.861910 1.613638 0.414704 0.929904 1.899909 1.266489 2.381908 2.221981
+1 -0.019727 1 1 -0.346038 -0.766727 2.001084 -0.105840 -2.290521 -1.276045 -0.400806 -2.336566 -2.327531 -1.274117 -0.985375 -1.854834 -55.625869 46.024042 -23.920149 -25.942394 36.190726 1.487969 1.036233 2.470962 0.460319 0.332991 2.333158 1.891743 1.272587 1.370819 0.859799 0.392959 2.219744 1.483046 1.563355 1.310322
+1 0.022595 1 1 -2.122545 -0.836796 -2.261167 1.981809 1.099230 2.187518 -0.441133 -1.526466 -1.070390 1.857017 0.741451 2.016070 64.222715 -8.834892 11.974993 -36.296292 18.225378 1.584039 2.447058 1.450249 1.582133 1.904662 2.396851 1.379623 0.318521 2.133279 1.765764 1.203167 2.382362 0.861789 2.338361 1.592040
+1 -0.022572 1 1 -0.217729 2.158661 -0.061135 -0.188930 0.798369 2.020597 -2.008040 1.009394 0.278378 -0.695871 0.647382 -0.359704 14.447860 -24.815878 69.544840 40.124250 -31.725148 2.056488 0.386790 2.027234 1.477634 0.599152 0.445128 1.511746 2.421086 1.444486 1.474896 1.833822 2.047064 1.757570 0.733514 1.919324
+1 0.001590 1 1 0.854167 2.044290 0.360519 -0.890028 -1.580971 1.790384 -2.334453 0.205442 -1.314368 1.092617 -0.569038 2.324973 22.125906 20.107737 0.742328 26.304225 45.111848 0.547564 1.914329 0.633835 0.609903 1.147450 1.933592 0.378459 1.509317 2.088112 0.897446 0.874497 2.169505 0.872430 1.185628 2.355228
+1 0.055118 1 1 0.003950 0.408498 -0.326815 1.871862 0.479599 -2.276076 1.173156 0.604349 2.089113 -0.280323 0.993138 0.381821 -31.831005 66.292548 -21.146335 -56.452881 -53.574892 1.626945 1.305724 0.298379 1.097644 1.856882 0.358819 2.171424 1.627177 0.720947 2.208044 0.593928 0.401203 1.263391 2.053456 1.190407
+1 -0.030467 1 1 -2.131011 -1.750518 -1.509648 -1.151311 -1.018785 2.098364 -0.309554 -0.197653 0.288020 1.127420 0.026333 -0.386746 -52.919336 -65.286060 -12.812752 56.080799 -50.006810 1.158140 1.611279 1.274427 0.801204 1.083684 1.224364 0.887227 2.380500 1.056484 0.829620 1.676576 0.719657 0.774601 1.713650 0.569630
+1 -0.002156 1 1 2.111044 0.740349 2.345700 0.330557 -0.233104 -1.777338 0.122155 -1.549000 1.902161 0.775523 -0.250836 1.794939 -37.547517 -11.123948 -60.198379 -4.156218 46.450048 0.414450 1.160504 0.846294 0.668053 1.969854 2.335656 1.116453 0.729659 2.381338 1.645974 1.633681 2.019405 0.382841 0.905465 0.654730
+1 -0.055824 1 1 1.114662 -2.332105 1.967377 -1.124629 -0.250742 -1.339501 -1.913471 2.354076 -0.261199 1.972345 2.254662 1.776541 19.736970 69.261510 -71.796864 60.114742 -51.534443 0.784203 1.107094 0.932462 2.147211 1.918076 0.594923 1.369730 0.557013 0.963919 2.085232 1.991280 2.438107 1.762380 0.563970 0.894137
+1 -0.015316 1 1 -1.143717 -0.622889 2.027802 1.264579 0.900502 -1.458104 -1.936581 0.352986 -0.255546 -1.968805 0.694518 0.183613 -20.217888 -52.045323 74.254542 -3.920319 -38.796201 1.408775 2.029098 1.303472 0.697280 0.441154 2.217758 1.864703 1.312121 2.076323 0.767856 0.860010 1.694902 0.474128 0.669288 2.465178
+1 0.048341 1 1 -0.172060 1.590382 0.878518 1.339250 -2.305962 -1.617662 -2.274520 -0.962211 1.037740 0.751042 -1.719961 -1.589989 32.211481 28.363373 3.207536 59.054561 -19.992516 1.161777 1.985908 2.159382 1.733013 1.995893 1.215686 1.291379 2.199539 1.645889 2.447640 2.229503 1.251284 1.089384 0.276256 0.527909
+1 -0.033708 1 1 2.325807 0.564455 0.756900 -2.227093 -0.252052 0.206725 1.390894 -1.399985 -0.583529 -0.890281 -1.117740 -2.277281 -7.705843 -62.107967 1.403764 43.068911 -40.818236 2.393688 2.209076 2.188221 0.430214 0.602994 2.028229 2.445281 0.844773 2.099992 0.308431 1.302412 0.882008 2.415359 1.933273 1.762966
+1 0.028684 1 1 -0.506933 -0.029668 0.887996 0.405952 -0.707001 2.084695 0.854859 -0.450573 0.022153 0.047140 0.601312 -1.828092 1.175927 -36.190431 -2.572444 -35.072977 28.468002 0.800535 1.086833 2.404949 2.470290 0.407682 2.162222 2.211484 2.160785 0.563456 1.261603 1.259983 1.039057 0.431965 0.788417 2.179974
+1 0.000408 1 1 -2.334733 0.202018 -2.307828 0.008165 0.572451 -1.518352 -1.356287 -1.285753 1.362172 1.230559 -0.664855 -1.151658 -68.119334 68.347080 9.370858 -3.984024 -59.498691 2.207384 0.752691 2.480513 1.235975 0.285874 2.440318 0.675745 0.751750 2.410079 0.949502 0.536246 0.680094 1.847325 1.740608 1.402659
+1 0.039491 1 1 -1.763301 0.420800 -0.910323 1.329055 0.696742 -0.144714 -0.613566 -1.504567 -0.581245 -0.195605 1.708518 -2.239032 55.141919 70.230741 18.070333 -41.918656 23.144610 1.997014 2.058833 1.549695 1.220114 1.448039 0.437644 1.736027 0.900946 1.206655 2.498823 0.726782 1.271132 1.665245 1.518810 1.883844
+1 -0.014403 1 1 -0.340657 0.136958 2.205225 0.279866 0.739318 -0.850933 0.466271 -0.081363 -0.882470 -1.786270 0.789197 -1.336914 -26.875304 -43.229060 49.194451 11.141317 52.119996 1.086543 2.022497 0.614423 0.610951 0.747359 0.618302 0.543491 0.956048 0.303727 0.994564 1.881023 1.099056 0.832514 0.814922 2.138955
+1 0.000779 1 1 -0.369339 -1.270299 1.924484 -1.032618 0.516073 -1.866732 0.920177 -0.644173 -2.256038 -1.346220 -1.739944 1.844366 4.980545 8.019692 -63.027548 -3.993636 -71.043171 1.036455 1.694156 1.425930 2.358188 1.823180 0.936185 1.717284 0.885584 1.768083 1.916154 2.046645 1.471234 1.027395 2.426378 0.380024
+1 0.001787 1 1 -0.659709 0.524098 1.052954 1.981459 -0.075494 -1.202727 1.917157 -1.655153 -0.930300 0.160003 -1.599962 -1.661620 -39.094536 -61.862075 -65.892905 -12.054994 41.719401 0.294468 0.616696 0.565186 1.086158 2.302970 0.769535 2.072254 2.121507 1.921305 0.873378 1.370858 1.505093 0.848014 0.323065 2.009736
+1 -0.014266 1 1 -1.876356 -0.605632 -0.099469 1.128718 -1.718128 0.947711 0.307408 1.831710 -0.479963 0.866568 -1.592520 0.889307 -35.605763 73.947179 -69.757219 -9.587264 -33.151648 2.428784 0.323092 2.461768 1.181838 1.643331 2.211079 2.113530 0.606574 1.438941 0.524519 1.597186 0.650665 2.221684 0.341037 0.306742
+1 -0.004135 1 1 -2.200059 1.731248 -1.914209 -0.638059 1.546658 1.136106 -0.062964 2.047866 -0.807875 -1.561993 0.301300 -1.865948 -1.349509 -31.202584 -21.832738 -42.832659 -38.501887 1.356835 2.074768 1.617155 1.019296 1.306743 1.686624 0.848422 0.436267 1.086906 1.380047 0.705072 0.897891 1.595960 0.297800 0.382277
+1 -0.002816 1 1 -0.420727 2.132888 0.302088 1.946086 -0.829699 -0.794717 -1.897459 -1.859854 -1.281731 -1.724742 -1.838092 1.615190 -50.233089 -67.531591 46.552437 6.816403 -36.711248 0.535766 1.621448 1.182052 0.746957 0.608132 0.628418 1.819205 1.631914 1.570247 2.387827 0.453236 0.544038 1.147221 0.341940 1.989771
+1 -0.009782 1 1 1.647847 0.650093 -1.918574 1.405280 0.039307 0.896386 0.045697 -0.091059 1.096150 2.258914 -2.145916 2.212966 -50.123620 -27.686400 -25.328171 9.433180 -6.545808 0.394128 1.614784 1.668905 2.283045 1.134315 1.676206 1.239564 2.098149 0.847477 0.291926 0.656215 1.010460 1.296990 2.015255 0.398482
+1 0.035020 1 1 1.425525 1.017752 -0.621518 1.517966 -0.421624 1.191706 1.349338 2.302715 -1.118500 -0.910530 -2.155600 -0.322901 53.404273 -34.390126 -44.840808 -39.465744 -0.754073 0.269463 1.112321 1.024074 0.605310 0.438933 0.904255 0.571764 1.391481 1.624432 1.823283 0.420405 2.248260 1.513212 2.310203 0.826798
+1 -0.036459 1 1 1.055025 -0.917872 1.686156 -1.084567 -0.805288 -0.487709 -2.073704 0.078058 1.880726 -1.340008 -1.015150 1.931361 45.860831 -67.020703 -66.959407 63.249841 -9.929731 2.290109 0.620317 0.665902 1.812949 2.243009 1.000439 1.626226 0.477836 2.237582 2.046273 1.963793 1.725027 0.536307 1.714097 1.323934
+1 -0.007154 1 1 2.034624 -1.888635 0.358524 -1.434494 -0.961457 -0.418816 1.276691 1.840291 -2.342752 2.087182 0.236975 0.865186 -39.924144 -55.087539 -56.268905 38.521469 30.323528 0.587971 1.524460 2.340981 0.613394 1.317831 1.278176 0.804097 2.452606 2.449756 1.797234 1.363471 1.108941 0.468433 1.697395 1.870882
+1 0.013117 1 1 -1.076830 1.999705 0.289296 -0.993189 -1.249408 -0.389816 -1.421019 -0.682014 -2.074113 -2.067482 0.991830 1.965961 -43.522869 61.137767 42.443930 -44.865081 2.584759 0.505584 0.608172 1.290423 1.890322 2.141499 0.429631 2.053754 1.694451 1.883468 1.687594 1.397372 1.640413 0.429342 1.697312 0.471539
+1 -0.008338 1 1 -1.141488 -0.851047 -1.453637 -2.261491 1.255741 -1.550262 -0.455241 1.686730 -0.851788 0.241464 0.918748 -1.101797 56.972812 -57.942601 -41.286890 -8.758778 -58.786951 1.640689 0.565456 1.118412 2.151853 1.189421 0.842976 1.145076 0.295587 1.434151 1.017829 1.393361 1.721400 0.317891 0.540509 0.335455
+1 -0.052239 1 1 -0.501978 -1.564320 -1.109160 0.560259 0.917942 -0.512532 0.120857 0.204754 1.262887 0.749659 -1.401168 -1.627307 17.606821 -32.152786 58.123080 74.605652 47.189495 2.332690 0.772080 2.100284 0.728883 0.590008 2.020382 1.055937 0.627776 2.286589 2.206593 0.955304 1.300222 2.330004 0.623217 2.165168
+1 0.000587 1 1 -2.090720 1.547256 1.776494 -0.167758 -1.493588 0.169961 0.826067 1.015419 -2.119422 -0.184331 -2.007008 -0.505735 39.962505 -50.186727 -38.319875 57.853773 48.366648 2.098763 2.158163 1.488622 0.770229 2.495109 1.305807 1.697140 2.090177 1.851387 0.259659 0.596355 0.693535 0.484697 0.545418 1.834589
+1 -0.016156 1 1 0.633882 -1.055384 -0.414186 -1.024709 1.499918 -2.157726 1.640799 0.000223 -0.969623 -1.019831 -1.333089 2.177185 7.675602 3.843981 -44.210252 58.294438 -45.374203 1.311578 1.936552 0.636951 1.241658 1.294465 2.320851 2.049708 1.189082 1.895160 2.452250 0.964080 0.295907 2.301510 0.974857 1.423547
+1 -0.008344 1 1 -1.852043 -1.956752 0.631811 1.842914 -0.682283 -1.882473 0.253571 1.776072 2.167553 -1.412834 0.223379 -1.437100 -74.925016 -14.745976 -35.626896 18.755237 69.265691 1.352054 0.463917 2.304243 1.917408 0.618834 0.487182 1.822094 0.675239 1.239259 1.467125 1.719921 2.464557 0.804513 0.447050 2.316979
+1 0.008840 1 1 1.923952 -0.551126 1.789433 0.535717 -1.573338 -1.870183 -0.522123 -0.856275 0.220136 0.596771 1.970599 1.183715 -32.349417 53.344744 15.108742 -17.371224 -58.160255 2.134018 0.691225 2.172904 1.743895 0.386561 0.431550 0.564101 0.845057 2.371891 0.377271 1.796164 1.384432 2.404929 2.142580 0.591648
+1 0.010736 1 1 2.176974 1.410525 -1.336100 -1.298814 -1.389890 -0.565128 2.066941 -0.652771 -0.687595 -1.638904 -1.147631 -0.425047 7.000658 60.064498 4.021836 -54.998168 -54.210594 1.113262 1.100108 0.507070 0.824170 2.328648 0.345143 1.817921 0.292275 2.019013 0.552745 1.227591 1.112943 2.481357 1.919199 1.485139
+1 -0.033576 1 1 -1.938487 1.310052 1.768113 0.343451 -0.299185 -0.290159 0.623624 0.902631 1.344394 -0.666054 2.259893 0.159232 -13.591285 21.269125 20.180756 27.969464 -17.211746 2.457815 2.252187 2.249830 0.895477 1.525224 1.687428 0.849408 1.256348 0.687532 0.846561 0.653520 0.702955 1.308024 0.712024 0.737491
+1 0.062917 1 1 2.215981 1.989428 1.909999 0.555170 0.210641 1.246160 -2.351620 -0.868224 2.033616 0.022926 -1.091281 -0.546124 32.862773 24.620430 -54.436372 -62.101488 -39.711873 2.313197 1.648402 1.943094 0.321933 0.983418 1.303560 2.183596 1.446922 1.919003 0.434569 1.804137 0.389098 0.319727 2.156972 1.724455
+1 0.009515 1 1 0.531034 -0.180314 -0.472924 1.370611 1.697727 0.188011 -2.114740 -1.604425 -1.277738 -0.580931 0.354578 -1.785587 -59.416193 -57.961938 -66.288222 -56.141216 -65.418817 1.464127 0.834765 0.402866 2.213308 1.313594 2.069494 0.727947 0.597901 1.914093 1.154373 1.288073 0.642681 0.788988 0.520403 2.160283
+1 0.006293 1 1 0.400667 0.013475 0.283592 2.105195 1.394600 -0.385988 1.652406 1.884213 0.705995 -0.133634 1.827964 -2.179797 -55.094573 -24.492082 -38.421775 -4.772220 43.301081 0.794011 1.700048 1.450224 1.157378 2.302939 2.495904 1.155000 0.591820 0.975579 2.298592 1.437537 1.688001 1.475267 1.317737 1.946840
+1 -0.001839 1 1 0.873940 -0.205554 -0.568402 -1.111866 2.210372 1.966907 0.400666 -0.002420 1.731301 -1.032756 -1.801375 1.392093 -3.113670 18.541909 -66.131419 29.233670 -69.709811 1.933084 0.844555 0.678974 1.022369 1.208996 1.347754 2.446896 0.984732 0.882896 1.587118 2.445915 2.498066 1.494901 0.551030 1.655236
+1 0.039416 1 1 0.279175 -1.439925 2.014329 1.029172 -1.892135 -1.917985 1.872474 1.341382 0.547137 1.866958 -1.826089 0.715397 -74.392523 -65.131114 41.370140 57.935161 66.245380 0.416418 0.480018 0.655932 0.751837 1.632008 0.905932 1.746007 2.136356 1.729967 0.301659 2.224764 0.355373 0.503419 2.470550 0.279551
+1 0.081272 1 1 -1.267305 0.399501 -0.736104 -1.680351 -0.314640 -0.853947 1.654458 -1.334876 0.428957 -0.477964 1.477530 -1.445648 2.087902 -8.623859 -41.192331 -69.510801 -68.028788 0.477323 0.361476 1.819249 2.361750 0.929373 1.978740 0.933314 0.703612 1.107703 2.167058 0.250645 2.098246 2.468328 1.182273 2.212948
+1 -0.058825 1 1 -1.737263 -0.216454 0.027320 2.067843 0.368073 -1.161713 -1.488971 -2.346602 -1.358999 0.251136 -1.457780 -1.194212 -33.472802 72.620224 -21.897239 73.099368 -68.918980 1.055593 1.605367 0.907104 1.200760 2.422653 0.779363 0.761495 1.943127 0.883460 2.056642 0.724217 0.913261 1.180672 2.302704 0.791693
+1 0.001904 1 1 -1.313773 1.672077 -2.089556 2.270724 -1.578691 -2.312192 2.054196 1.903177 -1.007914 1.021200 0.778812 -1.521494 -74.068275 -15.491672 31.473076 67.993765 71.211012 1.277270 1.335285 2.140330 1.025751 1.795964 0.268550 1.514151 2.339466 2.158737 2.138958 0.466050 2.160063 1.935576 2.220301 1.840715
+1 -0.015457 1 1 -0.643527 -0.829055 0.612756 2.024275 -1.466008 1.883096 0.784761 -0.501388 -1.084143 1.612765 0.084122 0.123104 8.568024 2.772308 -55.822727 37.431525 11.641890 2.353647 1.990640 0.688209 0.980782 2.007077 2.443409 0.872620 2.120029 1.832006 0.767521 1.971696 1.800995 1.570984 1.283334 1.994973
+1 0.002864 1 1 -0.018549 -0.736562 0.052105 -0.783752 -1.387676 -1.056653 1.830712 1.581556 -1.371872 0.668287 2.277336 1.165031 22.080209 2.074425 64.863797 -34.164328 0.133166 1.196846 1.888243 0.953037 1.448878 1.035622 1.192818 1.697747 1.025907 2.165757 0.879099 0.772999 1.790639 0.764213 0.372770 0.395599
+1 -0.002780 1 1 2.298315 0.328695 1.461322 -0.531231 1.573017 1.189921 -0.384101 0.389745 0.227590 -1.350376 -0.907043 -0.098421 -3.826241 42.374964 -3.987544 31.356262 54.696600 0.411282 1.912846 0.457052 1.674650 2.091997 0.938319 1.579249 0.693801 0.458629 1.174703 0.983614 2.347949 0.726679 1.795418 2.332959
+1 -0.007236 1 1 1.368871 0.730453 0.942304 -1.028004 -2.054447 -1.411843 -1.967445 -0.006766 -0.619763 -1.980231 1.865890 -0.942914 6.670379 59.064574 -1.706011 -22.925319 44.167713 1.026307 2.145850 1.544453 0.868589 1.869995 0.264036 2.155813 2.498958 0.737609 0.986606 0.891483 1.908369 1.704017 0.663983 1.069895
+1 -0.022753 1 1 2.246880 -1.768394 -0.357902 -2.248414 -0.445535 -0.124856 -1.435051 -0.892551 -1.564023 -0.829388 -0.271641 0.827497 47.166652 -20.079670 20.992862 27.029883 -58.756011 0.440936 0.813347 0.418943 2.424298 1.432986 1.698280 0.988123 1.631747 1.018409 2.142556 2.436792 2.161472 0.859419 0.757975 1.278927
+1 -0.065937 1 1 -1.690989 -0.035584 0.414207 1.374487 0.876930 -1.796554 2.307482 -1.110086 -0.873283 1.826310 -1.715945 -0.070214 -63.561837 16.211456 65.941156 73.006941 27.658639 1.506252 2.335873 0.269755 1.529938 2.162107 0.275655 1.683501 2.353827 0.527422 0.882111 1.891196 1.087278 0.887294 1.251879 2.086729
+1 -0.055676 1 1 1.747655 0.522925 0.194207 -1.640552 -0.571514 -1.587007 -0.712481 -0.491723 1.139010 1.617046 1.343106 1.233417 7.456044 63.739441 -31.206828 56.838906 -58.503128 1.193986 1.079263 1.164467 2.199450 2.405664 0.988746 0.853400 0.835677 2.230133 0.593367 2.227252 1.679629 0.278052 1.474355 1.725589
+1 -0.007975 1 1 0.287004 -1.815325 -2.165244 -2.181044 0.869951 -1.274976 -1.292131 -2.159891 -1.754930 -0.258659 2.252399 1.452333 -25.663333 -73.636792 36.441650 24.811005 -1.447012 1.076149 0.588834 0.277029 2.275268 0.932931 1.014302 0.630215 0.520511 1.722953 1.665553 2.199633 0.986346 1.010986 1.142967 0.849131
+1 0.006877 1 1 -2.063570 0.757623 0.492787 -2.116231 1.615573 0.149376 -1.142328 -0.836571 1.512339 -0.749814 -1.190305 -1.361392 -72.142225 -44.372674 28.471319 17.466369 7.260066 2.423870 0.985102 0.354907 1.667919 1.460692 1.604846 1.145247 0.917916 0.657395 0.582509 1.973003 1.260517 1.012508 1.970450 1.099166
+1 -0.015566 1 1 2.213915 0.248177 0.638783 1.207780 -1.817912 1.482118 0.269288 2.021682 2.085352 -2.230283 -2.024995 -1.223371 -33.339500 63.015471 -48.972685 -33.916308 -31.394257 2.225938 2.088072 2.478274 1.847651 0.464345 0.504188 1.888103 0.852139 2.147884 1.986631 0.813553 1.642630 1.682339 0.821610 2.057433
+1 0.014812 1 1 -0.690962 -1.673756 2.151332 -0.727743 2.192774 -1.643937 -0.909084 -1.408424 -1.055160 -1.347648 -2.172710 -0.440983 31.587532 41.645283 32.273399 19.012605 44.860458 2.420667 1.150472 0.980207 1.342055 1.166928 0.814279 0.333288 0.571125 1.890069 2.390272 1.056760 0.970876 2.018003 1.582668 1.895035
+1 0.023934 1 1 0.057081 -1.974416 0.634601 1.599179 -2.058876 -0.450074 -1.011041 0.311089 -2.272446 0.913655 -1.871278 -0.092768 20.770033 31.940795 -21.060076 43.302195 -20.006809 2.058380 0.686336 0.995950 0.435898 1.636361 2.074515 1.876793 2.003760 0.692954 1.981223 2.161740 0.863798 2.352140 1.421557 0.855556
+1 0.008159 1 1 0.905502 -2.244812 -1.170658 -1.019831 -1.341756 -2.117593 2.280419 1.144383 -2.332801 -0.314690 -1.686939 2.066872 -57.761476 2.872176 -27.337704 -14.796125 21.528310 1.769704 2.171242 0.816183 0.832013 1.393664 2.314881 0.708677 0.729148 0.542475 1.874399 2.268464 1.325066 1.381365 0.346710 1.157975
+1 -0.004284 1 1 0.483891 -0.830807 -0.556368 -1.492338 2.316552 0.527484 1.427774 1.110937 1.027648 0.768305 0.963740 1.103976 58.811847 -49.286746 -62.340227 -2.190432 -64.597082 1.627691 0.352337 1.223075 1.729564 0.285696 1.688843 2.131690 2.065846 2.415285 0.701817 2.436615 1.443419 1.547488 2.384599 2.449522
+1 0.018031 1 1 1.986041 1.533298 -1.912692 1.294654 2.144234 -2.204630 0.298451 2.086535 -1.200261 0.944294 -0.580720 -0.798768 22.377043 40.963378 -28.504826 19.388405 60.924761 2.311864 1.743223 0.345300 2.200956 0.714762 1.762066 2.039940 1.275232 0.825698 1.010396 2.474476 1.024075 0.628536 1.560204 2.351950
+1 -0.010170 1 1 1.496318 -1.397530 -1.741018 -2.069158 1.086098 -1.746355 -2.222133 -1.701952 -0.500004 -1.371624 0.121300 -1.771226 -26.471020 1.560164 -28.326404 18.127137 12.792346 2.139416 1.409849 2.079613 2.059218 1.277639 0.783893 0.390260 1.841713 1.924187 2.061664 1.888330 2.416461 2.456616 2.341299 1.461049
+1 0.028520 1 1 -1.081730 -0.235798 0.059430 -0.182534 -0.077216 -1.857584 -0.831723 -1.828113 -0.318773 0.361741 0.798834 0.403653 -52.532724 -17.500506 18.990369 -28.865893 -49.055836 2.403474 2.437763 0.476940 0.674068 1.805443 2.077295 1.353663 0.508486 2.121702 0.689526 0.619867 2.102958 0.672333 1.901452 2.458643
+1 0.054929 1 1 1.932167 0.851901 1.669520 2.052379 -0.360130 -1.994439 -1.316215 -1.670610 -1.530673 -1.096961 -1.766277 2.225192 41.127632 32.107621 -67.216722 -61.445676 32.521229 1.139328 0.427855 1.465588 0.641013 1.997308 0.262584 2.497696 2.020231 0.780266 2.423551 2.376248 1.596569 1.541817 1.574324 1.170771
+1 0.020149 1 1 0.894254 1.926377 -2.200053 1.830937 0.661777 1.252485 0.280470 1.465232 -0.785465 -1.903012 -0.942981 -0.910812 -69.174658 31.522343 -3.981454 -16.303003 45.429475 1.872809 0.301623 1.619601 1.643212 2.455289 0.287074 2.352069 2.466568 0.857120 0.368419 1.512392 2.029140 2.012547 2.119540 0.350048
+1 -0.013784 1 1 -1.782231 -2.019118 -1.406357 0.694021 1.245979 -0.680503 -0.251305 -1.387950 -0.953380 -1.336003 0.337812 -0.820225 -56.721929 74.530913 -8.939249 58.041031 45.615432 1.503567 2.200992 1.326898 0.674397 0.582413 0.365975 0.948789 2.043675 1.045611 0.338473 2.207271 1.097714 0.775190 0.372526 0.800514
+1 0.021750 1 1 -0.803105 -1.509912 -0.883181 0.403958 -1.238669 1.024772 -0.435203 -0.837440 1.045482 -1.080969 -1.587428 1.645401 62.087376 -47.475247 -66.484587 -56.462044 -57.568490 0.570885 2.367411 1.578505 1.677317 1.921532 2.434372 1.993145 2.288597 2.204541 2.466761 1.848065 0.672831 1.271044 2.436008 2.488971
+1 0.002766 1 1 1.560885 -0.066676 0.926546 -1.983351 1.264246 0.023775 -0.959082 1.793030 -0.279616 -1.249830 1.942987 -1.079056 72.816904 -16.291265 -57.282626 -49.095439 2.963926 1.595460 0.890173 2.381262 0.367924 2.197108 1.292488 0.586973 0.499212 1.510123 2.142260 1.970837 0.863175 0.881703 1.775530 1.075705
+1 -0.019341 1 1 0.051369 0.990644 0.879511 -0.815578 0.919233 2.334980 -0.763647 1.932564 -1.888472 -1.613430 -1.833407 0.232972 -13.623426 -68.925273 22.929313 22.959056 72.855088 1.756877 0.338270 1.050341 1.074122 0.261063 1.684336 0.630135 1.426919 0.973173 2.371865 2.188235 0.670863 1.942673 2.258478 2.248863
+1 0.037700 1 1 -0.252973 -1.136902 0.834310 -1.822199 0.116143 1.085760 2.004593 2.318709 -0.919587 1.132390 -1.264832 -0.440148 27.942980 -12.336889 -46.089844 -32.001003 59.136358 1.446484 1.305168 2.213936 0.628682 1.750646 1.359663 2.349076 1.671537 1.518828 2.200301 0.964530 1.112777 1.941212 2.441384 0.593046
+1 0.057027 1 1 -0.113510 0.759150 -2.107833 1.383995 0.460628 -0.684315 1.652795 -1.008184 1.198787 -2.158677 -0.198286 -0.926972 -14.588331 63.928197 -8.794310 -55.967492 4.364371 1.404812 0.681331 2.379628 2.162653 0.454026 0.308777 0.367629 1.740310 0.893403 0.417483 0.387422 1.394569 1.772176 0.963098 1.779921
+1 -0.006302 1 1 1.287032 1.278181 -1.397630 1.284807 1.592124 1.880682 -2.078733 0.389629 -1.718873 -2.150751 1.062314 -0.937286 17.700424 41.028438 14.955964 -35.118062 20.734974 2.015601 1.712273 2.171848 1.993988 0.714373 1.962715 1.608266 2.378953 2.062488 2.237153 1.584882 0.869082 1.168939 0.849787 0.877474
+1 0.019726 1 1 -0.498669 2.215276 -0.435331 1.726083 0.813509 2.009898 1.947163 -1.573575 -1.145467 -1.748604 -2.337151 1.972136 -39.805789 -15.889396 -53.077040 -15.816710 -31.448497 2.051659 2.475402 0.825703 1.085253 0.600535 1.200081 2.252386 1.095638 1.891828 0.450686 0.432751 0.490855 0.543819 1.972664 2.317914
+1 0.038058 1 1 -0.971257 -0.194657 -1.200635 -0.627269 -0.891892 0.083287 0.218902 -1.284867 2.115888 2.037271 0.195006 2.348067 -72.813046 -68.867657 -58.719497 -48.590442 -59.553446 1.903394 1.348489 1.303135 1.785616 1.854255 1.216136 2.096081 2.080864 0.585041 1.780846 0.433762 1.731077 0.954642 1.410788 2.116731
+1 0.031442 1 1 2.107751 1.943368 0.622770 0.673620 -2.345772 -1.540435 -0.224658 -1.203694 -0.204988 -0.473667 -1.695323 -2.182807 -15.571186 45.076306 -52.520183 43.276140 -7.914474 1.846440 0.367556 0.515440 2.006100 1.778730 0.869200 0.891694 0.955240 2.471915 0.717976 1.766432 1.173305 2.230422 0.958861 0.323616
+1 -0.032631 1 1 1.114498 -0.378923 -2.123363 -0.448753 2.336503 1.261267 1.797225 -0.454119 1.694783 -2.180713 1.715956 0.247722 -72.732013 -56.949097 6.521586 -41.699891 -50.074070 2.201658 1.259862 1.250847 0.493106 2.377766 2.364092 2.047973 1.286201 0.671989 0.623708 1.403271 1.778305 0.466642 0.849421 1.473259
+1 -0.013001 1 1 -2.063024 0.508664 0.848755 0.625158 -1.597230 1.834522 -0.342534 1.577754 0.692845 0.327375 -1.879546 2.327802 35.213528 -66.234968 -61.107062 23.609249 50.655218 0.808732 1.610459 0.985458 1.850901 1.101820 2.288271 1.219129 0.643736 0.517199 2.319842 0.841165 2.210341 0.958479 0.654505 1.507187
+1 0.044828 1 1 -1.737162 1.471696 -0.542046 -1.125211 -0.609802 0.510045 0.484746 -0.587854 1.820380 2.298124 1.831119 -1.002922 3.366998 39.138364 48.485037 -61.987498 -73.876550 2.227297 2.435792 1.097414 2.482670 1.490048 2.235930 1.274210 1.649892 2.226888 2.306249 1.869342 0.536749 2.392434 1.396133 1.051285
+1 0.060820 1 1 0.922451 -0.133164 0.296030 -0.905083 -0.131473 0.437320 -1.283814 0.964589 1.224964 -0.466644 -1.465636 -1.294022 -30.092901 28.618084 -65.859656 -53.246359 -11.553836 2.345098 2.317800 0.270086 0.338006 1.116188 0.768529 0.914989 0.978355 1.710695 0.401297 0.604904 0.374404 0.860590 2.439255 0.800514
+1 0.006407 1 1 -0.854317 0.140688 -1.081909 1.469064 -2.353359 -1.818718 2.079607 0.169171 1.690500 1.247576 -2.114507 2.322063 -34.810123 -53.738298 -29.566678 22.837580 -18.794208 1.761117 1.850414 1.911121 0.718783 1.835777 1.160196 2.415735 1.504952 0.727499 2.072606 1.286006 1.902218 1.832737 1.811317 1.798339
+1 0.027853 1 1 -1.127860 1.991876 0.647030 -1.557110 2.267352 -1.707146 1.727057 -1.671145 -1.091004 -0.595735 1.312704 -0.783149 -21.604549 42.342244 46.089490 26.057267 -55.509563 2.136587 1.117191 1.884887 0.793008 0.578847 1.183199 2.026093 0.290666 1.971380 0.988242 1.385988 1.550383 1.537208 0.596438 2.090958
+1 0.042514 1 1 1.425589 2.094637 -1.696527 1.140045 0.168376 -2.245674 -1.528605 0.680470 -0.313304 -1.967265 -1.694405 -0.901768 -30.798526 19.181045 25.817485 -35.523494 -43.362294 2.273911 0.615834 1.819643 2.239920 0.828112 1.076219 1.762002 0.975703 2.135263 1.358381 1.056807 1.752766 0.984959 2.454579 1.857140
+1 0.001773 1 1 -1.490089 -2.284248 0.467732 0.899859 1.866801 0.237072 -2.217584 -0.647737 -0.897634 -2.169569 0.518184 0.625635 54.543192 57.420899 -26.953039 0.271292 59.608099 1.124762 0.882359 1.559977 0.775320 0.295905 2.278512 1.451067 1.827307 0.552386 1.950233 1.074240 2.254351 0.379176 2.305138 1.205706
+1 -0.052886 1 1 1.667361 -1.247754 -0.873731 -0.991975 0.313100 -1.460999 1.246272 -0.477665 1.801596 2.325907 2.246482 0.963792 62.898820 -59.538056 -6.110251 55.015173 40.008859 1.058455 2.460079 2.053855 1.140986 1.309994 2.325596 0.789107 0.276810 0.845341 0.391097 2.414228 0.922785 1.496548 1.239378 1.225187
+1 0.033372 1 1 -1.436065 0.911651 2.139163 2.099009 1.107103 -2.152696 1.368579 0.540633 0.929110 -1.308044 -0.996682 1.315703 -70.882714 -25.773455 25.547405 -74.772271 2.433841 0.708477 1.870661 2.454907 0.618314 0.759927 0.350695 0.630011 1.599299 2.425782 1.610614 1.339614 0.648951 0.411234 1.106480 1.855664
+1 0.054817 1 1 -0.992461 1.572153 0.807558 0.948559 0.425187 2.138527 0.839023 1.990190 0.590418 -1.127665 0.557830 -2.208734 63.999150 -16.293948 47.619878 -52.715167 66.196107 1.494619 0.319966 1.667691 2.125327 0.873886 0.906769 2.324878 2.226522 0.655274 0.941276 1.773679 1.473577 2.157617 1.317454 1.692603
+1 -0.007160 1 1 0.419740 0.121445 0.661807 1.750230 1.383116 -0.186798 -1.057933 -0.835015 -0.598134 -1.315415 2.342314 -0.026191 -61.682912 -54.697332 51.933089 -10.566060 16.222053 0.535611 1.269282 2.077486 2.300196 1.401719 0.447952 1.736220 1.908602 1.127129 2.413739 1.716344 0.838800 0.705921 1.666907 2.462458
+1 0.041025 1 1 0.341919 2.226456 -1.039874 1.092351 -0.316951 -1.996393 -1.173147 -0.450518 0.946204 -1.464208 -0.853178 0.429403 73.645932 -32.828413 -47.143556 -41.750807 -5.814763 2.444177 0.287074 2.353653 2.102970 0.867198 0.995070 1.397758 1.368376 0.289081 2.339645 0.657571 1.289010 0.635159 0.360438 2.374319
+1 -0.004205 1 1 1.440793 -1.556545 2.325943 -1.852504 -0.277958 -1.663265 -0.602838 -0.264093 0.452176 -1.353480 -1.238018 -2.167325 17.093793 45.382021 -14.368673 5.718536 -38.558168 0.668117 0.785976 1.643348 2.495752 0.853267 0.866761 0.399514 2.133629 0.909150 1.828013 1.157463 1.478855 0.858792 1.472171 1.029294
+1 0.061290 1 1 -1.040661 2.000894 1.419375 1.325881 -0.808262 1.356442 -0.824467 2.314341 1.074330 -1.603180 0.799185 1.595047 -26.355835 -12.526354 69.565556 -61.706408 0.394640 1.865791 1.599147 2.121143 0.302151 1.495074 1.210126 2.343009 0.957894 2.072546 0.279686 1.924765 0.533705 0.733366 1.687377 2.238893
+1 -0.013781 1 1 -0.115360 -2.055968 1.295768 2.030321 1.200202 -1.934767 -2.146992 -1.729584 1.615769 -1.272426 -0.838220 2.075953 0.449807 59.901148 -41.410194 18.877731 28.023039 1.123233 2.183584 1.237301 2.310885 1.051619 2.319004 0.251411 1.466881 2.113971 1.261879 1.395428 0.463676 0.508024 1.111129 1.239568
+1 -0.003015 1 1 0.553706 -0.823984 1.009925 -0.211597 1.547666 -0.761810 -0.173046 -0.848127 0.499513 -2.170522 -1.354019 -0.871446 -9.217966 23.638540 -57.060677 -68.800536 19.387064 1.950755 0.833456 0.893192 1.377638 0.707573 2.435255 1.078795 2.306726 0.892083 0.739535 1.857769 1.768516 2.451451 1.035574 0.397282
+1 -0.042960 1 1 2.267179 0.105335 -1.499723 0.728032 -2.039245 -0.384198 -1.240759 -1.118333 1.895073 -0.541043 1.600084 -0.994954 66.002537 54.642544 -72.759043 -61.242832 -8.274755 1.017776 0.506661 0.700386 0.879505 0.835838 0.422142 2.185973 0.895309 0.960231 0.860020 1.849319 1.497572 0.451196 2.246943 1.872437
+1 -0.058490 1 1 0.003895 -0.506370 0.020146 -0.699323 -0.817121 -1.447125 -1.190465 0.657364 -2.237645 1.479079 1.030946 -0.336979 21.790167 -72.663802 39.487603 68.149282 -15.024272 0.430796 1.393008 0.278955 0.898421 1.503446 2.420038 1.823568 0.709879 0.685204 2.218716 2.211498 2.395200 0.633287 0.402213 2.498735
+1 -0.025359 1 1 -0.524419 -1.745018 1.390732 0.581116 -1.968861 -0.246313 -2.309126 1.759818 2.300427 -1.871743 1.531627 -1.728509 26.412561 65.909613 -7.134877 -65.880824 40.995852 2.384305 2.011989 1.747924 0.609476 0.721084 2.253367 1.845088 2.396800 0.518069 1.178420 0.454793 1.953967 0.820988 0.588774 1.525780
+1 0.011523 1 1 1.760650 2.158860 -1.441113 0.887311 -1.678028 1.037216 1.368404 2.311143 -0.836843 1.662008 -1.680323 0.164812 -28.495089 33.041308 25.266839 9.767073 55.199264 1.135493 1.227722 1.076189 1.262848 1.942882 1.261221 1.590942 1.461556 0.364301 2.049904 2.231234 1.101320 0.636525 0.818761 1.418365
+1 -0.011098 1 1 0.597406 -1.493347 -0.506736 -1.424251 1.545003 1.606596 0.074633 0.862667 -1.178998 0.179354 -1.533268 -2.287052 15.078172 68.843678 -44.299388 60.190009 13.487013 1.768455 1.418153 2.147366 2.276704 0.316818 0.507586 0.493772 2.326931 0.723765 2.311683 0.953764 2.415474 1.623522 2.276216 1.111785
+1 -0.024619 1 1 -0.491903 -1.885777 1.279193 1.482122 0.335378 0.682027 2.296172 2.015751 1.362691 0.543124 0.384950 -0.255997 -4.098796 -38.465879 3.964173 25.850004 61.023177 2.373023 1.404963 0.965525 2.078505 1.427190 1.034043 1.655786 2.290080 2.381130 0.396454 2.452286 1.566513 0.384264 2.332284 0.704099
+1 0.029361 1 1 -2.144106 -0.357308 -1.686952 1.848906 1.067807 1.845813 0.921126 1.163894 0.446409 0.667945 1.241284 0.517789 -41.451380 -73.347412 -49.955090 -45.200883 58.767225 0.636383 0.686078 1.159529 2.458435 1.411749 0.262057 0.388230 1.480978 0.544330 1.556914 1.047963 1.609728 2.192173 1.607100 0.780771
+1 -0.016189 1 1 -0.659924 1.616258 2.234425 0.952147 -0.532359 1.473795 1.758209 -1.181688 2.082765 1.407858 0.969867 0.393329 -25.756864 4.381767 -5.648311 18.830611 -13.927266 2.491500 1.395290 0.384561 0.559579 1.350651 1.648283 2.190913 0.667282 0.251867 2.383561 0.755085 2.213080 1.980060 0.618376 1.801114
+1 -0.048967 1 1 1.832064 0.758270 1.938653 1.479582 0.054439 0.744949 -0.467386 0.200956 -1.312130 1.018731 1.710738 2.083735 -36.541204 -48.022619 33.836312 36.903064 -20.200528 0.470838 1.617255 0.445775 1.134804 0.897087 1.584532 1.723426 0.615250 1.010242 2.137208 0.301688 0.476506 2.394318 1.543921 0.936520
+1 0.019791 1 1 2.102279 -0.495816 -1.674952 0.891173 1.977637 1.657515 -1.783342 -1.835722 -0.960259 0.855800 1.223506 -1.407149 48.493047 72.646402 -31.922239 32.935413 45.478858 0.822588 0.492151 2.085771 2.058606 2.239476 2.370067 1.219461 1.737481 0.586288 2.489578 0.579280 1.704321 1.267203 0.876574 1.075707
+1 0.031189 1 1 0.530647 -1.967925 1.344194 0.669409 2.285831 -2.150386 -2.227254 1.768253 -2.004836 -1.695194 -0.022693 0.303683 15.634451 -31.786170 69.840425 58.017011 -58.094912 0.607107 1.394043 1.922660 1.141257 1.357252 2.332418 0.704396 0.779835 1.933704 2.260139 0.909529 1.453418 0.846027 0.669045 0.643495
+1 0.015856 1 1 -0.735893 1.867001 -1.112849 -0.183327 0.732191 1.888225 2.174321 -0.763695 1.119045 0.653716 -2.283518 -1.383892 40.457316 16.116770 -25.446942 -36.759389 34.941064 1.442054 1.107020 1.944016 2.324730 1.992990 1.933385 1.398890 2.400628 1.862088 2.362718 1.458196 2.400580 1.047762 0.487400 0.980027
+1 -0.037685 1 1 2.304839 1.589768 -0.012512 1.770102 0.793612 2.181467 1.528813 -1.896070 -2.079141 -1.767712 1.670646 2.127369 57.398524 46.998527 4.242580 55.042482 48.993719 0.436654 0.839257 1.644419 0.252490 1.602396 0.468750 0.282741 1.522588 2.387951 0.296017 1.913010 0.954883 0.960529 1.365014 2.290987
+1 0.051344 1 1 -1.619592 -1.730041 -1.357120 -1.158532 0.138920 2.202526 2.041876 2.191896 -2.263075 -1.803498 -1.307803 -1.659917 -28.055848 65.365855 3.924127 -47.203273 4.587773 1.475440 1.962323 1.763554 2.304259 2.177761 2.387779 1.892732 2.142045 0.593350 1.940291 0.465089 1.753309 1.108617 1.782062 0.623035
+1 -0.011183 1 1 2.044962 2.227491 2.227312 -0.778518 1.760181 -1.017132 1.601062 1.305989 -0.544306 -1.407927 -2.130287 0.996986 -29.121767 0.455607 7.394621 -68.606405 -17.843419 0.709734 0.494955 1.966564 1.044347 1.586704 2.241004 1.061095 1.819727 1.402646 0.266943 1.509520 1.009341 0.490577 0.379548 1.811487
+1 -0.033519 1 1 -1.516394 -1.439829 -1.082750 1.462924 -1.883175 -2.113653 -2.182705 1.220947 -1.997077 1.475215 2.056839 -0.795129 19.205962 -5.391539 -15.595506 -63.670307 -6.850868 2.236820 0.481646 1.027541 0.388849 0.633725 1.020028 2.356333 2.134114 2.309558 1.240967 0.934615 2.331515 1.274519 2.335170 1.957275
+1 -0.052698 1 1 0.916526 -0.747211 0.142035 -1.993267 -0.461709 1.353655 -0.538025 0.490085 -0.400654 0.212088 2.002446 -0.775592 -28.760460 72.949995 -29.440188 48.754568 -31.981271 0.486646 1.811152 1.287865 1.640115 2.156509 0.698140 1.382143 2.179844 1.392663 1.234693 1.232546 1.158652 1.221556 0.933391 2.002582
+1 -0.010117 1 1 1.199480 0.054423 0.478705 1.552850 1.544831 -1.289992 0.798725 -1.429439 -0.814783 0.150801 -0.758245 -1.519464 -38.321546 29.780978 -21.102532 -70.259587 -52.879864 1.346988 0.835428 0.294818 1.998864 1.663497 1.389930 0.309734 0.701323 0.879132 1.317057 1.771519 1.173790 1.395341 1.242875 1.493036
+1 0.003114 1 1 1.979666 -1.935287 -1.459114 -0.053491 1.037081 -0.909581 -0.342037 0.490492 1.737178 -1.214673 -0.933659 0.246305 69.325995 -38.003596 -26.444529 -3.198472 -56.712718 0.315194 2.468987 1.012310 0.903063 0.782293 0.497061 1.346615 1.314605 1.062832 1.773693 1.705844 2.120325 2.294403 0.781893 0.526794
+1 -0.001257 1 1 1.554846 2.091657 0.062244 -0.013940 1.338147 -1.992044 1.242274 -1.701654 -0.217428 -2.218265 2.038354 -0.448849 23.148817 -37.829784 44.813147 24.566496 -60.898982 2.437230 0.518545 2.431403 1.590432 1.893665 2.081113 0.268049 2.104586 1.032848 1.833649 1.389817 0.645600 0.346788 2.457456 0.711041
+1 0.064082 1 1 -0.722142 2.076475 -0.644648 -0.815347 0.091103 -0.359048 2.049311 -0.078476 0.527461 1.037500 1.427260 1.896992 -40.898480 69.240865 31.224186 -65.107470 -11.251831 1.982122 1.521638 2.163330 0.583580 1.982928 1.578410 2.334765 1.888943 1.457583 1.091725 1.380909 1.685031 1.069508 1.471720 2.454041
+1 -0.042179 1 1 1.657856 -0.774766 -1.167991 1.384526 -0.046792 0.534872 -1.647560 -0.545911 -0.098065 1.157638 -1.029243 0.685429 -56.682167 -7.183242 21.252508 40.897943 71.730244 1.678098 1.540413 0.467907 1.864027 1.194383 0.991348 1.832210 1.962593 1.794699 1.507660 1.240593 1.394844 1.896545 0.978862 1.235548
+1 -0.003658 1 1 -0.253095 1.511522 -0.340196 -1.542500 -1.944740 -0.106037 -0.883840 -1.252609 2.350103 -1.057739 -2.294656 -0.095025 13.178474 -59.386562 -9.943061 -13.023303 -32.651585 2.497276 1.724580 2.011294 1.321371 2.273572 1.671733 0.324382 1.632039 1.434018 1.041146 1.794372 0.512281 0.654195 0.800601 2.202613
+1 0.015068 1 1 -1.797377 -2.107149 -1.246037 -0.282973 -1.130261 -0.654574 2.008737 1.282705 -0.760908 0.850601 -1.336986 -2.055444 21.357215 0.718117 69.388982 -29.376411 70.661536 2.251656 2.327939 1.927940 2.142337 1.012676 0.286446 0.796296 1.848268 1.834639 2.275563 1.381153 1.280856 0.845173 2.066419 0.808807
+1 -0.016039 1 1 -0.175819 -0.322402 0.641121 -1.914502 -0.848532 -1.582187 0.201137 1.729585 -1.584678 0.736888 0.721761 0.949689 17.967364 27.487963 -9.798086 23.565717 69.007479 1.505517 1.223982 1.215703 1.572635 2.023031 0.584352 1.457431 0.785714 1.737564 1.981757 2.137586 2.152846 2.128118 0.530319 2.315853
+1 0.039361 1 1 1.842050 -1.056826 -1.086973 1.176490 0.076508 -0.606822 -1.251861 0.787146 1.887633 1.636204 -1.816799 1.331471 -34.794679 55.831457 -40.708233 -33.266233 -55.586329 0.783633 0.520240 1.672526 2.385926 2.264189 1.480017 2.401892 0.595454 1.300760 2.377801 0.704920 0.598676 1.443184 2.087748 1.537994
+1 -0.015523 1 1 1.402579 1.776459 -0.744575 2.035961 1.738060 -0.531399 -1.244610 0.134635 0.862773 0.612270 -1.428361 -1.557331 -46.060518 10.871253 13.151794 -57.804650 27.255046 1.008359 1.991796 2.121057 1.098359 0.377469 0.615699 1.808429 0.513325 2.449410 0.483478 0.319851 1.990191 2.137134 1.317222 2.290992
+1 0.016170 1 1 1.261366 -1.263822 -2.318038 -1.941762 -1.899587 0.081017 -0.234978 -0.293059 -0.998851 -2.167470 -1.901843 -0.133396 35.319410 63.329961 -13.339507 52.913416 -34.225442 1.719854 1.342120 2.266666 0.359655 0.476347 1.961712 0.493968 1.128258 1.125097 2.004297 0.711062 0.324327 0.706458 1.683272 0.755519
+1 0.013155 1 1 -1.620948 -0.954368 0.915195 0.450122 1.808959 -1.159100 0.015898 -1.405609 -0.865765 0.950405 -1.546583 0.118803 -42.278883 -31.181643 30.123783 40.422812 36.200417 1.681175 1.509669 1.256925 1.388565 2.111289 1.190849 2.353615 1.464156 1.325432 0.782956 0.383377 0.924965 2.128676 0.905174 0.263069
+1 0.003820 1 1 0.479109 -1.079684 1.167034 1.374264 1.830012 -0.751738 -0.548681 0.461038 1.495745 -1.608181 1.560224 -1.764107 32.146664 -11.024966 -46.597937 -21.526248 8.354452 1.574207 1.440549 0.561340 1.692234 0.623515 0.409087 1.017248 0.637387 1.811399 0.931199 1.165922 1.903316 2.288531 1.087000 0.705801
+1 -0.002779 1 1 1.900075 -1.302487 -1.859192 0.410868 1.813592 1.311304 -0.760952 0.099706 -1.852364 2.070912 0.121087 -0.641668 68.033936 -3.634330 -32.183779 -12.779709 11.425092 1.697771 1.428333 2.240170 0.538063 1.968795 0.282411 0.481354 0.621652 0.610191 1.487955 0.812683 0.508466 1.788797 1.315286 1.252981
+1 0.016990 1 1 -0.671637 -2.037757 1.062719 1.167575 1.038856 0.656455 1.335217 0.593191 -1.653907 1.162998 -0.478361 -0.479291 -62.481574 22.185225 -32.924736 -16.038603 -10.804235 2.323330 0.959687 0.702657 0.804350 2.217357 1.869924 1.316109 1.587346 1.781527 0.622466 0.784946 2.341546 1.118277 2.133859 0.268217
+1 0.057321 1 1 -1.185856 -1.994331 0.504300 -1.820001 -0.635724 -1.625635 0.384330 -1.246163 2.311567 1.574903 -0.089189 -0.466095 -53.046413 48.932205 -46.430754 -61.682808 -52.948139 2.134431 0.883352 2.492898 2.387775 1.829954 2.294561 1.194160 1.742920 2.005886 0.426935 1.751990 1.438452 1.316740 0.946475 1.408698
+1 0.035808 1 1 0.098538 2.076405 -1.822181 0.416944 0.247898 0.671023 1.142854 0.256570 0.336579 2.014472 -1.285406 -2.225319 40.952005 -69.648242 21.988585 -37.859208 0.285614 1.379633 0.492184 0.391029 1.270061 1.670270 0.470977 1.706654 2.234873 1.510674 2.404645 1.871385 1.111209 0.339094 1.409923 1.074117
+1 0.053288 1 1 -0.921494 2.064893 -2.088243 0.773439 -2.288203 -0.027160 0.626933 -0.030825 0.285571 -2.331885 0.950491 -0.097754 53.352034 -12.357316 60.585729 64.346958 -20.675831 2.144589 0.604634 0.339684 2.327304 0.253692 1.555000 0.386827 0.397893 1.884616 0.745821 1.755865 1.318358 1.150919 1.747208 2.072971
+1 0.004001 1 1 0.424928 -2.218692 -0.428160 -0.269778 -0.835248 0.193078 -1.775511 -2.171475 1.472226 -1.055109 -0.496400 -2.061083 4.929324 47.141770 11.736290 1.820345 -5.469367 1.770099 2.061439 0.355617 2.355971 0.552943 2.317024 0.721766 2.466284 0.593990 1.437670 1.674403 2.444189 0.488666 2.004000 2.484859
+1 -0.049656 1 1 -0.112863 2.210475 -1.020931 -0.980188 0.491748 -0.718346 -0.109027 0.703508 0.479088 -1.444805 0.110975 -0.947482 -37.194816 66.723874 28.143239 53.420212 -66.493506 0.529710 1.085695 1.273925 1.357512 2.206541 2.332269 0.444186 1.428510 0.721676 0.963451 0.977719 2.281393 0.373434 0.296919 1.312528
+1 -0.021171 1 1 -1.420709 -0.174613 1.105307 0.650886 1.990014 2.342378 1.048260 -1.511911 -1.483448 0.944900 0.176654 0.217346 26.661380 47.821632 38.161058 -27.099620 -63.315180 0.801579 0.641434 2.334518 2.247210 1.864137 0.805108 1.449132 0.814266 2.375445 1.604969 0.968429 1.383381 0.490428 2.376505 1.415892
+1 -0.040290 1 1 -0.223721 0.415100 2.252750 -2.071612 2.263835 0.442132 -0.527308 1.531955 -0.926983 -0.637879 -0.147510 -0.475680 68.908658 -2.187473 -14.854244 -55.280054 8.129255 1.050703 0.409677 1.947643 0.281419 1.807202 2.397289 1.981906 2.389378 1.785279 0.686622 1.298790 0.756499 1.226854 2.235573 2.028444
+1 -0.057563 1 1 1.850995 -1.528179 -1.584140 0.350216 0.313847 1.663464 -0.761466 0.885872 -2.305304 0.022825 1.909908 -0.971625 -53.498108 -42.702718 45.421411 47.649424 -6.127341 2.391647 1.660467 2.210875 0.930803 1.251548 1.010770 2.010831 0.292801 1.852470 0.459044 1.398139 1.020530 1.790920 0.999925 1.993762
+1 0.032783 1 1 -0.247464 1.914137 -0.581777 0.280134 0.531931 0.755151 1.362125 0.454032 1.558783 2.288108 -1.567607 0.195392 -18.479362 67.356816 16.009259 -32.381468 -35.325860 1.048970 0.534619 0.341309 0.379797 1.497612 1.117216 2.296945 0.757553 0.949061 2.112645 1.471143 1.741826 1.620424 1.965585 0.341755
+1 0.027177 1 1 -1.376139 -0.366682 0.981003 -0.936034 -1.971404 -0.575272 1.230596 -0.052448 -0.279998 1.754169 1.607338 -1.590669 -31.390678 -33.120855 -12.214194 66.035582 10.031447 1.352968 2.330805 0.594356 0.833010 2.395262 1.671427 1.929428 2.400105 2.068076 1.656872 0.288471 1.089658 0.385075 2.460973 1.326269
+1 0.054282 1 1 -0.089821 -1.664822 1.498636 -0.147207 -0.100792 -2.267545 -1.544015 0.861750 2.255634 -0.723640 0.453046 -0.884595 6.320426 27.396635 -44.751801 -43.517871 -4.852812 1.956888 0.415062 2.453475 1.307206 0.469420 0.299930 2.425831 2.434220 1.685865 1.586130 1.593204 1.233517 1.720898 0.875520 1.360368
+1 -0.014490 1 1 -0.364589 -1.538455 0.067948 1.609507 1.868753 0.053841 0.121821 2.274860 1.967209 0.764896 0.209638 -1.487286 -73.072275 74.279840 -28.732460 -56.457074 25.953740 1.442705 0.783980 1.853648 2.257531 2.079640 0.265969 0.888724 0.538299 1.441284 1.654072 0.491781 0.358989 0.522639 1.494354 0.351369
+1 0.000096 1 1 0.539095 -1.349250 -0.831905 -0.168024 -1.255995 2.001322 -0.820193 -1.242552 1.736808 1.997334 -1.867191 -2.084208 -66.869980 66.249664 8.095536 11.677867 69.905274 0.594092 0.912469 1.366767 0.261911 2.430689 0.846083 1.617220 2.110951 2.256469 2.228287 1.068086 2.324802 0.944792 2.363056 0.390956
+1 -0.039996 1 1 0.189855 0.612491 2.274739 -0.074370 -1.147394 -1.148546 -1.660243 -1.650951 -0.987337 -1.853500 1.830068 0.194072 25.521476 -60.551556 60.006020 71.180515 -69.086528 1.565862 0.699944 2.461363 1.124493 0.851355 2.474256 1.813384 0.544542 0.614509 2.055515 2.031912 1.354054 0.329566 1.018045 0.523983
+1 -0.021343 1 1 -0.006280 -1.871403 -2.179600 1.582422 -0.956649 0.278902 -1.319060 2.351394 1.782249 2.316858 0.956624 -0.685698 62.716496 26.147238 -43.374019 12.857832 -48.424079 1.922634 0.709142 1.794240 0.534665 1.119324 1.735547 1.844889 1.297505 1.671633 0.880787 2.130836 1.214716 0.737198 0.845265 1.370196
+1 0.027657 1 1 -1.210967 0.091033 -1.542335 0.831654 0.670053 -1.031551 -0.395279 1.019477 0.108797 0.149701 -0.397156 -2.255878 42.794402 -4.484045 -63.349912 -21.963284 13.090503 0.806324 1.630041 1.604046 1.192352 0.614658 2.312572 2.406393 1.996038 1.404913 2.377849 1.510195 1.100542 1.063798 2.246447 0.290970
+1 0.014528 1 1 1.404642 -1.243841 -1.074966 0.337698 1.972956 -1.609590 1.447252 -1.390909 1.156608 0.499347 -0.238436 -1.861529 -37.161840 20.955256 -5.005393 24.356243 5.383772 1.900828 0.963341 1.376486 1.596061 2.001732 0.362014 1.865725 0.496451 2.354483 0.290280 2.234737 1.470211 1.838452 1.106692 0.928263
+1 0.015459 1 1 0.590706 -1.013820 0.722558 0.206189 1.804489 -0.885640 1.491889 -0.438048 -1.516650 -1.032805 2.089750 0.998767 23.989134 -14.628741 -15.257824 61.759497 -8.136891 2.024175 1.806733 1.260809 1.417781 0.390506 1.491018 0.530442 2.146431 2.314110 1.239528 1.493691 0.473716 0.498275 1.501251 1.532029
+1 0.024734 1 1 2.086466 2.344921 1.378214 2.259735 2.220106 0.620389 -1.636329 -0.273536 1.973061 0.157927 1.204549 0.423673 7.951828 -3.627342 -64.738934 32.730503 51.571547 2.319891 1.653255 2.498737 1.522427 1.932806 0.667235 1.711420 1.330034 1.628754 2.467056 2.304616 1.428476 2.388966 1.600320 1.572357
+1 0.042988 1 1 -2.144268 1.641606 -0.561750 2.291987 -2.347762 -2.002915 2.319881 -0.064123 1.423387 -1.941602 0.793014 1.545800 27.524841 9.996357 8.775918 46.848603 34.463559 0.310619 2.066785 2.457580 0.544173 1.157308 1.127094 1.811306 1.627986 0.808025 0.976679 0.541999 0.633830 0.534641 0.714310 0.905011
+1 0.037594 1 1 -0.375089 1.052259 -0.280139 -0.621440 -1.896548 -0.674668 -1.132004 -1.681706 0.473610 0.732178 1.667567 2.218681 7.694417 20.059431 -61.148784 72.391608 35.758512 0.524757 1.098360 0.391204 1.964517 0.395769 2.194306 1.455912 2.256850 1.883153 0.897769 1.802327 1.453254 0.337138 2.270271 2.450158
+1 0.075847 1 1 1.278902 1.301412 -2.081919 -1.320322 -0.007963 -1.884642 1.494036 -2.050420 0.297389 -1.632257 2.177555 1.755054 74.714467 -73.954711 -56.819825 -70.791043 14.934989 2.310499 1.310221 1.641767 0.673642 1.393235 1.848930 1.710320 0.844058 1.327591 1.067668 2.053874 1.453693 0.968089 2.414047 2.384453
+1 0.008590 1 1 0.229254 -1.664122 -0.876881 -2.105304 1.490562 0.818700 -0.286204 1.121651 2.027142 -0.403237 -0.784009 -0.994151 45.924958 -39.233392 4.382701 10.061560 54.632750 2.314540 1.717647 0.250425 0.636181 1.799451 0.377844 2.423414 2.326663 0.723084 2.119122 2.334649 2.204047 0.916180 0.738031 1.340756
+1 0.017049 1 1 -1.085977 -0.925968 2.282221 -1.557150 1.593501 1.464635 -1.405936 -1.654936 -1.987275 1.273701 -1.289396 1.397547 64.700795 -73.743017 51.120817 -12.422841 9.314614 0.635766 1.572740 1.542364 1.759615 1.358337 0.311650 1.408419 0.546627 1.916868 0.555698 1.374299 0.841056 0.376893 2.192771 0.395898
+1 0.040473 1 1 1.360873 -1.751089 -1.679140 1.189412 0.490468 1.332041 -0.944194 2.249728 -1.034047 0.066305 2.261857 0.181870 -52.535691 -67.365435 -10.873006 -42.615726 7.493627 0.555827 1.289366 2.125923 1.894212 2.268641 2.042537 2.176615 1.116391 1.932608 1.848351 0.987944 0.875781 1.254547 1.928098 0.291485
+1 0.011770 1 1 -1.524542 -1.715001 1.662431 0.730207 1.520271 0.625448 -1.431604 0.486831 1.459177 1.111457 0.343605 2.296308 -13.459955 -21.466997 -45.813236 -33.056660 16.709506 1.924968 1.686039 2.261392 1.722279 1.584794 1.630707 1.535847 2.485442 0.817961 1.464819 1.205762 0.984897 1.409377 0.899955 0.301116
+1 -0.017216 1 1 0.074312 0.185097 0.752855 0.462982 1.183283 1.162833 1.461949 0.582080 0.097188 -1.752840 1.869104 1.242911 -12.977514 -13.085087 -21.050345 56.856486 -63.040861 2.458616 2.211227 2.343136 0.829378 2.106356 1.519866 1.642713 0.832791 0.976305 1.012688 0.499114 2.105498 0.600589 2.099336 0.542897
+1 -0.012767 1 1 1.590647 0.613080 -1.957805 1.781230 -0.683163 2.166521 0.087948 -1.546323 -0.228658 2.254610 0.910503 1.702297 50.635143 74.843463 -5.925595 8.523553 5.361870 0.879211 0.396508 1.115400 1.027562 0.740613 1.981151 0.956839 2.345162 1.140367 2.149147 0.708288 0.938180 1.487772 2.231420 1.969545
+1 -0.018109 1 1 -0.472399 0.759297 0.363039 -0.945553 -1.734564 -1.983812 -1.769164 0.827985 0.261530 -1.119259 0.470899 2.302223 1.189196 36.817657 44.354912 -26.999957 -38.280412 0.941656 1.410636 1.811916 0.621263 0.819751 2.312053 0.423063 1.918431 2.071054 2.210725 0.658284 2.024167 1.670472 1.622149 1.701319
+1 -0.016789 1 1 0.833864 0.101521 0.377307 -1.478062 1.930460 0.446249 -2.017906 0.113037 0.717647 -2.225189 -1.239581 -0.168601 -48.827256 10.316335 -13.354403 -47.450181 54.816305 1.339519 1.296255 0.905671 1.865193 0.543674 1.773065 2.410989 0.497239 2.091346 1.255971 1.105850 0.276735 1.841363 0.531876 1.490380
+1 0.001828 1 1 -0.034010 -1.403579 0.261715 1.977187 -1.180242 -1.884071 1.676216 1.494627 -1.550069 -1.923180 -0.618755 0.824875 -5.700646 39.241014 -26.284211 -8.737237 3.258543 1.619962 0.948303 0.631028 0.690441 2.483497 1.890466 2.317220 1.764763 2.378526 1.633639 1.326566 1.835723 2.499811 1.578489 1.415960
+1 -0.074072 1 1 0.612631 -0.075613 1.516729 2.353252 0.018709 -1.293996 -0.514849 -1.117185 2.344258 -0.345586 2.109755 -2.070171 -57.319192 -63.655215 -53.196675 73.475936 -39.943515 2.415126 0.279619 0.799036 0.651334 2.225032 0.369701 0.564998 2.426445 1.512145 2.377424 1.109768 0.869432 0.295366 2.215130 0.444743
+1 0.005468 1 1 -0.989930 1.687202 -2.351267 0.353413 2.200900 -1.722895 0.936347 -2.194527 0.449033 -2.347942 -0.313653 1.601270 2.719855 -37.389265 -51.370705 12.566914 12.125686 0.570979 1.690576 2.009108 0.580822 0.631912 2.044422 2.346010 1.894575 1.613265 0.898529 1.081365 0.504299 1.497015 2.326041 1.518406
+1 -0.078352 1 1 -2.245751 1.904865 -0.902325 -0.905924 -0.132377 -0.608161 -0.184091 2.019353 0.641294 0.992671 1.968007 0.044188 -60.302755 41.592853 51.081353 74.293538 51.500149 2.320038 1.874495 1.640530 2.386654 0.995824 0.567777 1.880916 1.555722 1.263739 1.161394 2.297726 0.373335 0.893631 2.013819 1.001476
+1 0.008235 1 1 2.128131 0.474538 2.197769 2.202782 1.636217 -1.607832 -1.999680 0.130962 0.395168 1.827365 1.889549 0.868116 27.698401 -72.968684 15.327293 55.810749 61.253909 2.041732 2.144443 0.401109 1.933675 1.775724 2.095247 1.573099 0.831449 0.907694 2.109918 0.638897 2.440125 1.930451 1.595212 1.223770
+1 -0.007617 1 1 -2.022216 -1.632369 0.305296 -0.675667 0.913804 0.626849 -1.449559 0.306144 -0.567256 -0.714278 2.305146 2.043766 30.798203 -24.603545 38.226000 14.376011 -32.381609 0.809383 1.296082 0.257422 1.238794 0.414166 0.894187 2.346782 1.359797 2.349637 2.092318 1.829786 1.705550 1.677280 1.290096 0.899856
+1 0.013395 1 1 -1.480840 -2.352094 0.596108 0.246356 -1.692163 -0.911148 1.593030 -1.741747 -0.188103 0.560174 -0.512889 -1.172402 -65.764982 37.939819 4.537560 62.773485 -66.040170 2.318018 1.676540 2.365129 1.467000 1.869551 1.786815 1.748590 0.552495 1.540708 0.927998 1.357636 2.034812 0.580181 1.109580 2.209755
+1 -0.014435 1 1 -1.443662 0.459438 -1.834458 1.423402 -1.681628 1.781996 -1.932338 0.981491 -2.154038 -2.347663 -0.330698 -2.134023 -16.904049 -6.347469 -31.906378 -0.487494 56.695918 0.449410 1.476204 1.305477 0.655044 1.571837 2.110074 1.018428 2.466568 0.851221 2.471811 1.224881 0.571603 0.939241 1.329053 0.890169
+1 -0.029782 1 1 -0.841468 -0.667991 -2.013902 1.437269 0.473349 1.071452 1.848092 1.533151 0.332475 -0.983378 -1.292223 1.009807 -69.982179 -40.486688 -59.759141 28.113153 -2.234071 0.654632 1.399080 1.096106 0.747720 2.182251 1.337122 1.515738 2.012443 0.377783 1.398182 1.738145 0.503791 1.963128 1.791658 2.152776
+1 -0.010035 1 1 1.594033 0.985281 0.285700 -0.169152 -1.370669 2.030827 0.273631 -0.371398 1.835713 0.812035 0.791790 -0.176365 -2.441079 72.777879 -72.191880 21.075354 63.470023 0.485243 0.733227 1.594437 1.711830 1.479510 0.633572 0.689732 1.834115 2.476427 2.300939 0.378547 0.733077 1.324384 1.168853 1.654889
+1 -0.010650 1 1 1.068954 2.288949 -1.579833 2.053984 -1.659039 -0.255550 -2.047767 -2.238493 1.357022 -0.493474 -0.007653 -1.397636 37.701184 43.799977 -53.789077 16.983015 -16.460745 0.538762 2.473340 2.175259 0.826642 1.113865 2.231953 1.933769 1.100967 1.449134 0.839818 2.063439 2.467445 2.096447 1.485220 2.087432
+1 0.048219 1 1 -2.221995 0.614390 1.207399 1.210133 0.027927 -1.869654 -1.064137 -1.439319 -1.938842 0.051424 1.919379 -2.020582 72.022872 -11.596596 -53.989396 -49.773122 13.144260 0.858746 0.699350 1.481750 2.272196 1.042582 1.172149 0.807436 2.328897 2.265931 1.495405 2.263651 1.439404 1.571878 0.557633 2.382832
+1 0.024298 1 1 1.929972 1.663884 1.584558 1.960513 1.318443 1.421688 -2.213598 0.371011 1.084677 -2.072092 -1.102020 -1.965728 18.112407 65.219242 -60.198843 -11.954803 -74.378947 1.570600 1.581645 0.457588 1.689835 0.805737 0.764449 2.092899 0.358617 1.021661 0.559315 1.402394 0.528712 2.305147 1.359101 1.902674
+1 0.028906 1 1 -1.927099 -0.504890 1.318802 -1.975645 -1.173497 -1.618530 1.985027 -1.367071 1.253334 0.398138 -0.087522 -0.723819 68.798698 -50.276178 -41.725887 -36.982699 31.779859 0.986373 1.470678 0.679376 1.022237 1.237456 0.419091 0.420474 1.154172 2.421063 1.060462 2.428708 1.291873 1.502391 0.434765 0.594159
+1 -0.043761 1 1 -1.128980 2.032580 1.471522 1.257785 -0.193125 0.975897 -1.932001 1.925451 1.085691 0.842881 0.863576 -0.033865 32.969266 14.457469 -13.321878 49.188059 53.705616 0.329306 1.139044 2.415183 1.229800 2.255935 2.243390 0.655586 1.691269 2.407152 1.257449 1.199975 0.475639 1.321205 1.743780 0.718412
+1 -0.035928 1 1 0.752088 1.711456 0.015804 1.724848 -1.103018 0.106487 -0.981608 0.188950 -0.462938 -0.436372 -1.618590 0.983711 68.842579 -62.779793 -39.989133 52.639714 15.673803 1.818987 2.472466 0.979920 1.017979 1.668539 0.638744 2.125097 1.505574 2.184606 0.426895 1.081092 0.407524 1.750607 0.695879 1.635997
+1 0.028108 1 1 -0.304874 -1.657689 -1.128847 -0.458398 0.453908 -0.534024 1.761319 -0.738264 -0.284028 -0.000390 -1.837750 -2.073539 -59.135272 13.491760 -43.992374 -29.833475 38.782315 2.340525 1.960185 1.836135 0.412636 2.171005 1.323513 2.290165 1.554914 1.198180 1.805907 0.886488 1.199245 1.715900 2.381248 2.386044
+1 -0.009475 1 1 -1.312494 -0.387531 -0.709858 1.189473 1.524719 -0.014793 1.129494 1.899360 0.811507 1.350253 -1.167950 2.082165 23.830640 21.566695 71.440851 -43.617441 -28.326219 1.693642 1.794787 0.736597 1.989112 1.999171 2.323999 0.954565 2.374550 2.308747 1.110341 1.506843 1.006530 0.497895 1.863819 2.202769
+1 0.075294 1 1 0.899893 -2.266300 0.538845 -0.837817 -0.564695 -0.072975 -1.265075 0.187313 0.286852 0.340554 -1.865529 2.297027 71.214703 55.511807 -13.061496 -74.557478 12.472275 2.447915 2.355580 0.725171 1.205872 0.594759 0.865120 2.076525 1.897791 1.676887 1.437372 1.163351 1.442273 0.274181 1.664833 1.343623
+1 0.014763 1 1 -1.223802 1.143863 -1.646325 1.368773 -0.913181 0.409492 2.238676 1.707080 1.864669 2.108311 1.923588 -1.962662 8.423922 -19.146966 -53.051695 -39.835258 -61.177653 1.932885 1.995859 0.645179 2.278543 1.971775 0.865197 1.113485 0.340136 0.910463 1.406416 0.625104 2.371913 0.743827 2.000010 0.665303
+1 -0.026499 1 1 -0.328966 -1.297860 0.520264 -2.119865 1.798104 0.177558 1.283149 1.987192 2.042893 0.445265 0.303513 2.336254 57.412951 -10.525683 -55.158947 -56.425804 -48.484041 0.305745 1.163481 1.368346 2.034063 1.502136 0.646241 2.127959 2.364055 1.416802 1.941085 0.308472 1.981181 1.457067 1.431545 2.221239
+1 0.016845 1 1 -1.694168 -1.633749 0.669158 -1.942085 2.102925 0.942674 0.471530 -1.240464 -0.866959 -0.275602 0.235129 -1.874806 59.787035 -9.308156 7.820298 35.747745 62.351940 2.110765 1.380267 2.149386 2.489063 0.937518 1.618835 2.265614 0.665993 1.100473 2.150525 1.377307 1.893905 1.615886 2.200313 1.161068
+1 0.004128 1 1 0.118713 1.865219 1.924152 -1.905546 -1.113056 1.049276 1.423089 -2.227386 -0.451645 0.864980 0.001510 1.814712 40.748484 -40.223190 18.839645 -12.085529 -21.477546 0.278352 2.016628 0.964627 0.493577 1.298971 1.561383 1.917660 0.361098 2.216401 1.547976 1.582623 1.138380 2.496676 0.636529 0.887173
+1 0.008772 1 1 0.749706 -0.612433 -1.310930 2.322262 2.249550 0.695673 0.747054 1.935656 -1.760195 0.777407 -1.580435 1.358422 -16.552820 46.759243 32.602473 -0.235853 -63.977179 0.408231 2.380478 0.686213 1.178210 1.422079 0.637928 1.907023 1.590326 2.353553 0.423022 1.235013 2.112549 2.114978 2.432139 0.457078
+1 0.017324 1 1 1.243064 2.148994 -2.323898 -1.473023 1.800786 -1.871164 1.834443 -1.670135 1.739107 -1.780137 0.191664 -1.984374 -56.978315 -34.543953 69.783066 -6.015197 2.582972 2.305191 2.088655 1.026440 2.127867 0.819329 1.961636 1.468419 0.968008 1.064080 2.497145 1.773942 1.387180 1.327862 1.132852 1.848000
+1 -0.012175 1 1 1.428460 -1.494976 0.405218 1.104054 -1.545383 1.433767 -1.841627 -1.247763 -1.015501 0.745683 -2.263910 -1.701836 46.080974 32.928626 -68.579125 -9.359838 39.200140 1.926320 1.909014 1.299727 0.764068 2.436044 0.835451 0.681483 0.439056 0.722242 1.479023 1.441482 0.489403 0.891918 2.467826 1.750098
+1 -0.011256 1 1 -0.083636 -1.384480 0.822766 2.080799 1.345868 0.540141 2.089875 -1.622844 0.175006 0.792578 -1.063775 -0.064000 -38.695950 37.172303 4.902087 39.374302 -36.107319 2.039245 0.847816 1.487753 1.905559 1.729314 0.573438 0.275504 1.396613 2.373067 2.145752 2.161786 1.639066 0.288127 2.051366 2.049649
+1 0.041060 1 1 1.478640 -1.638929 -1.568626 1.912997 -0.886315 -0.428007 2.303402 1.009552 -1.770435 -1.682657 -1.369642 0.446952 11.845832 42.893493 10.928984 -66.568208 38.133741 0.831673 2.419751 1.509300 1.811223 2.472039 0.563803 0.336488 0.350338 1.378575 0.713751 0.513603 0.369827 0.434704 1.818292 2.041017
+1 -0.001370 1 1 -1.574895 0.222514 -1.847197 -0.627301 -1.441933 1.239837 -0.241853 1.975788 -1.138388 -0.588966 1.969662 -0.424643 73.197457 -70.345167 8.782950 15.043605 -62.129234 0.534367 0.613133 1.418597 0.611310 2.280070 0.628851 2.354538 1.212762 1.646518 1.786130 1.491526 2.331815 1.819117 2.390932 0.885072
+1 -0.003580 1 1 0.337958 1.637112 -0.692061 -1.301160 1.602424 0.637123 1.582084 -1.918533 2.093846 -0.853669 1.609678 0.036098 -38.250128 30.092839 -29.648817 -7.667042 -9.974574 2.234972 0.923224 2.128327 1.793275 2.314746 0.683762 0.495655 2.476656 1.664602 1.967264 1.551498 2.281636 2.202864 1.283802 0.852979
+1 -0.068244 1 1 0.926726 1.045382 1.953376 -0.823186 0.295044 1.373960 1.446531 0.625573 0.662530 -0.233465 1.580754 -0.711575 19.413419 31.327577 22.593036 71.156278 -26.430265 0.423130 0.796432 1.882268 1.783504 2.349160 0.833752 1.374819 0.580356 1.784948 1.864589 1.648410 2.074829 0.398868 0.271102 1.667243
+1 -0.007514 1 1 -0.089919 1.400429 -1.371946 -0.567997 0.966367 -1.879198 -1.243462 0.580869 -1.406458 -0.991215 -1.052212 1.065001 58.131487 65.898227 -48.506041 8.969721 4.097007 1.500943 0.845500 0.819124 0.764574 1.951934 0.398690 1.782676 1.929565 2.451997 1.212325 1.044236 1.965273 1.839526 1.160958 1.723494
+1 -0.020544 1 1 0.402991 1.365221 0.646371 1.504540 0.121008 -1.972368 2.066974 -0.093583 1.083998 0.660247 -0.896460 -1.288104 -14.121876 -46.364845 -3.952590 18.817626 67.842644 0.344885 1.979932 0.724370 1.234435 1.395597 1.052388 1.743584 1.912049 0.552231 1.592256 1.052866 0.770639 0.375040 0.294999 0.545525
+1 -0.012332 1 1 0.407428 0.549390 2.022731 0.858042 1.201475 0.599921 -1.634362 -0.210734 1.902479 1.398693 -2.268630 -0.929001 -50.359713 54.311515 63.624534 -12.462055 -49.761551 2.239273 1.208330 1.398783 0.592784 1.422254 1.316923 1.779623 2.365341 0.539475 0.963322 1.053619 2.169034 1.948672 1.824134 1.219305
+1 0.026650 1 1 -1.199963 1.248592 0.814592 1.361138 -2.004061 1.902820 -2.288671 1.536861 1.415660 0.144630 -0.800484 0.136395 68.952848 -9.479900 -28.681255 54.146142 -15.786461 1.779293 1.321079 1.868052 1.358237 0.880963 0.595913 2.259403 2.041651 0.772958 1.100652 0.662619 0.635256 1.997330 0.634246 0.779948
+1 -0.084359 1 1 -1.359636 -1.026000 -1.352573 -0.130946 -0.118672 -1.173296 1.753601 1.488262 -0.135138 0.110636 -1.925926 0.361491 41.519275 14.447312 -34.034949 74.607297 74.834971 1.395279 2.458978 1.542187 1.034149 1.197236 1.691133 2.372676 2.317664 2.473354 2.410044 0.361632 2.206827 0.391923 0.551316 1.962337
+1 -0.013378 1 1 -0.616272 0.145805 0.094332 2.080592 -2.134951 -1.987796 1.947048 1.207177 2.192535 -0.941608 -1.397781 -1.251418 -37.913379 -10.155531 15.991063 -38.205064 37.487768 2.228714 1.502306 1.253197 1.728103 0.480981 1.092922 1.242156 0.662507 1.003734 0.760759 0.819948 1.119032 1.327563 0.596989 2.338410
+1 0.070616 1 1 -0.566045 0.789110 1.916909 -1.110306 0.153266 -1.731588 0.921603 -0.237666 1.655531 -2.139642 -0.717660 2.006412 -2.866796 -32.248947 -58.060130 -66.604185 33.470408 1.932260 0.495379 2.341352 2.357663 1.992101 0.484489 1.561852 0.792975 2.286568 1.844281 2.327825 2.246338 0.695459 1.329921 1.973336
+1 0.005995 1 1 0.744205 1.169702 -0.902088 -1.630013 2.206899 0.143664 1.819929 -0.576920 1.802471 -1.812155 -0.715782 0.578229 43.162301 28.791816 4.052667 13.172827 -4.294985 0.837769 1.377036 1.852917 1.220832 2.274888 1.286799 1.730791 0.658230 1.115596 2.067109 1.144690 0.548854 1.081026 1.556131 1.384988
+1 -0.030525 1 1 0.120118 1.928734 -0.297122 1.403184 -2.193567 -2.253735 -0.333447 -1.206627 2.334552 1.458845 0.250442 1.008022 24.991024 24.147124 -59.289570 -29.805043 66.639682 0.822059 0.589472 2.010620 1.247884 2.436135 2.367481 0.499472 1.380988 0.767529 2.114473 0.694864 0.328877 0.687691 1.267685 2.237537
+1 0.013223 1 1 2.112061 -1.011813 1.469094 -1.848054 -0.879843 -0.047945 0.006393 -0.929966 1.058194 0.516358 -1.798988 -0.904831 -19.633205 24.727875 -48.605365 -10.363145 -23.385888 0.675603 0.611406 1.658633 0.649688 1.560316 1.978101 1.449458 1.791596 1.102819 1.084438 0.400494 0.597896 1.835995 0.321669 1.041464
+1 -0.000810 1 1 2.044548 -0.021868 0.024255 -2.321512 0.936209 0.198496 -0.250383 -0.027101 1.620800 -1.537306 0.531664 0.984483 31.982133 73.711376 17.099697 -5.398791 12.517402 0.324564 2.446327 0.417476 0.276465 1.800462 1.616622 1.065515 1.855605 1.400951 1.039045 2.480004 1.672910 2.095733 0.739145 2.056904
+1 -0.042341 1 1 1.136186 1.272936 -0.017282 1.717874 -0.501335 -0.194097 -1.207876 0.193641 -1.744728 1.549719 0.756460 -0.209364 43.763353 -69.333802 56.791777 49.388083 -34.489991 0.275852 0.496750 0.620096 1.445843 1.778223 1.337743 0.699795 2.205062 2.226294 1.314186 0.773309 2.498810 0.492630 1.140702 1.026314
+1 0.049399 1 1 1.640320 1.389244 -0.872698 2.231618 0.903674 0.024771 1.639048 -1.147621 -0.257792 -2.023781 0.332535 0.024318 -40.084918 -57.224094 34.651002 -70.602516 33.518065 0.446807 0.487972 1.589949 0.530571 2.057448 0.778172 0.981092 0.468118 0.913310 2.008803 2.210681 2.157651 1.886253 1.247316 1.894008
+1 -0.030620 1 1 0.954721 0.316694 -2.320921 1.432245 0.852855 -1.149275 0.212698 -1.886184 -0.852664 -0.346804 0.482042 1.080073 21.246851 -54.174834 -16.435672 65.653828 43.887447 2.369783 0.942191 1.400834 1.308383 2.238500 1.728193 1.984272 1.654153 1.851344 1.794509 0.567888 1.496008 1.161592 1.123565 1.001020
+1 -0.021040 1 1 1.440125 1.355589 -1.018258 1.539201 -1.670479 0.675911 -1.540564 2.316663 -2.310986 -1.234653 -2.157479 1.089865 9.955859 -71.884591 -64.316877 -73.748541 -41.729662 2.118493 0.758397 1.634240 2.413472 1.722443 2.090848 1.879917 0.511157 2.014736 0.667424 0.387544 1.205600 0.525226 2.218868 0.269588
+1 -0.000873 1 1 -1.326764 0.099098 2.066914 -1.113451 -0.869078 1.819615 -1.141966 0.538342 0.129471 -1.102092 1.543938 -2.158556 58.444927 -66.116666 -22.811691 3.917251 -12.756876 0.552761 1.503634 1.082269 2.186676 1.468003 0.718370 1.638650 2.287555 0.440054 1.734124 0.426223 1.027627 1.826633 0.473669 1.962670
+1 0.052364 1 1 1.280001 0.928337 -0.166377 -1.850478 0.779669 -1.261207 -0.785398 -0.774789 -1.543918 -2.218918 0.494901 0.436879 23.088890 4.975190 68.012533 -63.360088 -43.001540 0.971720 0.442247 0.342320 1.626799 1.103043 0.348450 1.151439 1.482651 1.665780 1.513638 0.467797 2.263638 1.215132 0.975021 1.931520
+1 -0.004762 1 1 -1.994120 -0.659225 -0.766009 -0.060208 1.243948 -1.842651 0.392356 1.690452 0.431587 1.308749 -1.295891 0.630347 24.992541 49.633695 43.517518 -1.073315 -39.205709 1.669688 1.948326 0.522511 1.592141 1.367319 0.528715 2.367202 0.322223 1.347274 1.125642 2.162082 2.109071 2.157229 1.554836 2.133538
+1 0.038437 1 1 -0.023002 -0.170672 1.354313 1.100839 0.962740 -1.572304 1.354960 -2.171880 -0.617292 1.853710 1.699729 0.836186 45.605020 -16.424525 -46.992284 -49.309752 1.005826 0.698862 2.275978 1.610928 2.113380 0.328455 0.346272 0.548613 1.544334 1.114224 1.516301 2.468601 1.272427 0.928388 1.164153 1.422215
+1 -0.017929 1 1 1.935441 -0.663056 0.816601 2.134302 0.514048 1.796365 -0.765818 -1.560529 1.340942 -2.152132 1.409947 -1.622320 -14.399942 -69.827246 13.468456 14.345585 56.250467 0.648984 0.970471 1.954900 0.761764 1.971595 2.350937 1.452453 0.372938 0.960679 1.633448 0.355643 0.537857 0.768475 2.263321 0.391321
+1 0.070778 1 1 0.093765 1.966163 2.024367 0.081035 0.071650 -2.153649 -0.515131 -1.143954 0.109461 1.877263 1.717204 -2.339910 -62.791788 58.423943 31.215395 -62.852104 -55.308840 0.989852 1.439731 0.313013 1.817665 0.500089 0.493128 0.509413 1.955678 0.324806 2.015896 2.166746 1.754209 0.498697 1.857074 1.346400
+1 0.050062 1 1 1.314245 1.543378 -2.152237 -0.344071 -0.706544 0.332139 -1.918598 1.002540 -1.810996 -0.093774 -2.119366 0.765500 29.744322 -37.177885 51.287138 -67.071880 -27.087171 1.313660 0.934816 1.197944 2.340057 0.841755 0.881033 1.778538 2.138610 1.361776 1.862430 1.359171 0.842607 1.691362 1.717251 0.335716
+1 -0.030135 1 1 2.255186 1.170759 -1.983829 -2.064064 1.882835 1.109024 1.866252 0.438712 -1.456632 -0.757862 0.203457 -1.688740 2.340651 39.327846 -66.886265 -57.460383 -36.661637 1.792987 1.983573 1.163484 1.424995 2.387458 1.012359 1.720559 1.930416 0.995385 2.187495 1.733621 0.975681 1.772035 0.840980 1.347100
+1 0.000808 1 1 -1.764138 0.477468 -0.398419 0.072149 1.529345 2.333056 -0.118925 -0.725667 -0.619887 0.653994 -2.334198 -0.229906 4.025336 3.820519 11.459307 -3.430487 -56.192201 1.040086 1.976424 0.250562 0.702689 1.340519 2.358147 1.129337 1.269346 0.905247 1.487464 1.555034 0.948969 0.579717 2.309192 1.844184
+1 -0.007250 1 1 -0.303940 -0.087356 2.079793 -1.422024 1.273326 1.826315 -1.633775 0.241708 0.305892 -0.091560 2.097073 1.544627 -0.030622 -64.661456 -15.082961 0.682854 -73.276526 0.496380 1.154935 1.743491 0.357004 0.914491 1.603973 2.232204 1.649936 0.717431 1.609069 2.378336 0.700207 2.377589 1.642782 1.983438
+1 -0.054158 1 1 1.668933 1.613287 -0.569899 1.989265 -0.821806 -0.083385 -1.871388 -1.929621 -0.476289 1.365965 -0.990643 -0.865091 -59.348070 36.992057 -24.494490 71.106113 30.440845 0.914180 0.876591 1.361401 2.309839 1.465304 0.365432 0.822824 2.195428 2.315047 1.246868 1.105401 1.722139 1.485797 0.543396 1.598950
+1 -0.018438 1 1 -1.613697 -1.613997 -1.932383 0.218683 -0.250573 1.493505 -1.559117 1.519156 0.727854 -0.311553 -0.808873 0.514537 18.720906 -57.726339 -6.576609 16.927099 -56.241383 2.141092 0.334602 2.407328 1.968000 0.432936 1.351314 1.534459 1.651582 1.380457 0.838507 0.283127 1.266628 2.459192 0.640583 1.531075
+1 0.069671 1 1 0.075978 -0.093317 0.845225 -2.156988 -0.095462 -2.219497 0.183713 1.042585 2.066626 -1.240573 2.012265 -0.679735 -46.896555 59.601979 30.456699 -64.261622 -45.077043 1.977024 1.347612 2.312381 1.446053 0.820146 2.190874 2.272322 0.920053 0.582367 1.835688 1.914195 0.631953 0.492121 1.578094 1.531133
+1 0.015003 1 1 1.234626 1.714834 0.245940 0.747152 -1.129337 0.736998 -2.151193 -1.655396 -0.305236 1.689782 -1.410675 -1.194483 -28.457466 65.364204 -23.831701 -39.392034 38.092874 1.779034 1.476786 2.096459 1.683571 1.281135 1.026701 2.018420 1.827904 1.580460 0.784515 1.841168 1.768075 1.779858 1.816065 0.604548
+1 0.044393 1 1 2.212492 -0.102677 -0.961254 -1.728979 -2.354589 1.064477 -2.267261 -1.471219 -0.865821 0.011306 1.532023 0.220972 16.474742 -9.006577 -23.540438 55.863412 46.357574 1.851316 1.317948 1.001777 1.615630 2.402421 0.494136 1.692986 2.013105 0.252707 0.740396 0.579768 0.916203 1.126599 2.494631 2.260491
+1 -0.018026 1 1 1.050454 -2.338535 2.274812 1.153100 -1.898242 -0.883081 2.079936 0.984196 0.895919 1.628564 1.714647 1.810323 -57.134119 46.869897 -57.639705 -50.522088 25.260858 2.263672 1.784072 0.647415 1.599318 0.490654 1.671791 1.291838 0.925721 1.335921 1.577204 2.316425 1.902099 2.074428 0.412577 1.177821
+1 -0.004324 1 1 1.849704 0.351450 2.199026 -0.236588 0.920765 -0.182105 -2.291115 -1.832786 1.248254 -0.148177 -2.275714 -2.172617 35.818624 53.605561 48.668730 25.343777 -47.131632 1.505038 2.174880 1.210763 1.789674 0.302341 2.440939 2.106879 1.315005 1.040002 0.559682 0.832846 1.893857 0.805663 1.783680 0.808989
+1 -0.016215 1 1 0.747136 -1.402477 -0.058732 -2.212531 -0.537981 1.230247 -1.192947 1.358194 0.350742 -0.277551 0.472059 -1.768389 -9.039764 18.689878 20.778024 16.255379 54.152479 0.485810 1.252409 1.980005 1.942795 2.050368 1.043367 0.872227 2.262638 2.416095 0.802172 1.609108 0.775920 1.380065 0.995468 1.324635
+1 -0.000950 1 1 -0.421947 0.489463 -1.425451 0.230335 -2.345928 0.554111 1.265681 0.580535 -2.302067 -2.129029 -1.422026 1.238842 59.958609 24.348903 32.012800 -10.868206 38.059662 2.406167 0.450857 1.054727 0.544898 2.106260 2.163050 0.382505 2.015302 1.185020 1.136710 1.426487 0.469432 0.493298 1.112847 0.863817
+1 0.008835 1 1 -0.463952 1.358573 2.009270 0.816370 -1.741954 1.057813 -1.175142 -0.983367 -1.099594 1.112855 0.282979 1.223938 36.733009 -28.312318 -45.129497 58.537893 -3.625480 0.873346 0.818259 1.983601 1.634129 0.548538 0.280213 1.782030 2.327956 2.205305 1.808665 2.226393 0.732459 2.183998 1.457091 1.834076
+1 0.031801 1 1 1.151289 0.641051 1.624300 0.735036 -2.133336 1.587296 0.851848 0.770253 0.705162 -0.004679 1.463669 1.211747 -35.453207 -62.054422 1.323921 51.138115 -21.702180 2.146815 2.015464 1.653672 0.516830 0.613962 1.859746 1.248134 2.129621 1.037435 2.415184 1.251425 1.194843 1.980895 1.155901 2.227146
+1 0.006027 1 1 -2.214576 -1.926429 1.327893 0.027563 1.436842 -1.998549 0.286759 -1.214714 -1.622963 -1.833085 0.936359 -1.999575 60.605386 -55.277342 53.705725 -67.887460 65.458695 2.339304 1.681949 1.025306 1.076843 1.002937 0.869197 0.845452 2.264219 1.977868 2.033671 1.661210 1.202952 1.017308 1.636681 0.700802
+1 0.007439 1 1 2.133132 -0.297971 1.276886 0.396656 -1.427780 -1.212875 0.996576 1.620355 0.407731 0.928740 1.907245 1.400800 5.028613 65.900573 -9.077575 -16.807393 -31.850307 2.003437 2.016480 0.736396 0.855655 0.490290 2.309134 0.872783 0.356308 0.468110 0.767083 1.356770 0.980841 0.738586 1.663189 0.713879
+1 0.077095 1 1 -1.564857 -0.715112 -2.294885 0.774670 -0.458825 -2.005784 1.221298 -0.804982 -0.062294 -0.819311 -0.552345 0.149291 68.092618 -67.363885 15.186455 -61.242546 -3.465060 0.815991 2.115422 0.901964 0.311091 1.006357 2.091175 0.630649 1.069402 1.943019 1.328045 1.959290 0.293874 1.895554 2.319660 2.281244
+1 -0.030618 1 1 0.305729 1.891200 0.330982 2.199148 1.820075 1.885654 1.376717 0.652275 1.772164 -2.243505 1.939520 1.922724 -74.545831 58.219945 52.608245 -63.233015 -7.277329 0.473949 2.153214 1.570263 0.412920 2.440721 0.693311 1.220033 2.343952 1.045691 1.675602 2.339722 1.950307 2.306242 1.755463 1.313278
+1 0.017404 1 1 -1.787325 1.905939 -1.706980 -0.192969 -1.103049 -0.404129 -1.644532 -1.487180 -0.515134 -1.201673 0.785036 -0.584155 -63.458178 -41.590615 -13.460778 -35.299713 -32.276890 2.459749 1.008008 0.583161 1.694831 1.526288 1.580621 1.248306 0.536323 1.974644 1.848440 2.472446 0.647667 1.344259 2.205796 1.064694
+1 0.028465 1 1 0.712076 -1.608748 1.455384 -1.375526 0.521729 -1.048211 2.335646 0.995707 1.151507 -0.408991 1.461431 1.299131 63.403841 28.356630 39.883274 -31.810194 -33.936836 2.479074 1.790244 0.880989 1.033505 1.615983 1.574228 1.798459 1.698814 0.968124 0.767360 1.520812 1.794538 1.046492 1.643482 0.254959
+1 -0.022337 1 1 -0.792686 -0.744090 0.766914 1.134198 0.854676 1.178610 -1.992633 0.757155 2.050943 -0.924635 1.125421 -0.584998 -64.292266 39.892292 -30.243162 53.175903 27.395601 0.443017 2.034087 1.894419 1.247681 1.272425 0.899280 2.442235 1.387121 0.337531 2.137101 0.750641 1.777241 0.591745 1.952987 2.359627
+1 0.010118 1 1 -1.564662 -2.148384 -1.558425 -0.993411 -0.261473 2.083842 0.656828 -1.823460 -2.226027 -1.183393 1.709937 -1.956149 42.451158 -73.380655 -8.675678 -12.127529 22.618383 2.082489 0.885649 0.607044 0.333996 1.221176 1.300590 1.760808 1.157563 0.917924 0.798269 1.262695 1.618802 1.712892 1.322781 1.235804
+1 0.000441 1 1 2.110296 2.303897 -0.106734 1.534717 -1.629036 -0.224204 1.721545 -0.068287 2.120824 0.176296 -1.078089 -0.305695 -41.544607 9.782548 15.284385 -65.345351 40.688130 1.305975 2.276203 0.889644 2.490945 1.056709 2.364992 1.427030 0.590238 1.375258 1.210602 1.340322 1.294406 1.326188 2.247790 0.364177
+1 0.022057 1 1 2.279272 0.721273 2.171012 0.179203 0.640093 -0.343130 0.978857 0.703445 -0.579726 1.767349 1.651008 1.942921 -69.387646 51.831830 -62.439796 -25.653274 -54.570780 0.308423 1.173124 1.443517 0.943239 1.012418 0.464588 2.327772 1.366258 0.705413 2.133637 1.036676 0.920501 1.368385 0.453429 1.534542
+1 -0.034562 1 1 -0.725428 -1.319339 -2.344724 1.925318 -1.155635 1.717213 -2.183645 -0.438269 -0.521930 -2.315142 -0.396920 1.702807 23.529291 56.786222 -43.968371 73.581033 -73.582062 2.219257 2.309799 0.790250 1.487938 0.530264 1.401612 0.892943 1.695950 2.330835 1.094566 1.873432 1.776022 0.356634 1.448257 1.848061
+1 -0.004231 1 1 0.485708 1.437589 1.147452 2.134077 1.437699 -1.716429 1.217421 -0.002625 -1.701057 0.400794 2.133869 -2.062925 69.528779 70.196688 45.730688 -4.327340 20.394350 1.642713 0.834781 0.669788 1.875341 2.360910 0.311568 2.270962 0.560430 2.144251 1.674974 0.781642 0.811243 1.069092 1.225480 1.648895
+1 -0.038173 1 1 0.008899 -1.228314 0.693499 1.900148 -0.067236 0.945331 -1.996897 -0.218067 1.184459 2.066612 -1.477385 -0.834667 17.097295 -45.771117 74.837265 39.916387 74.716271 0.720564 0.262025 2.105671 1.261993 1.057872 1.656049 2.218950 1.648715 0.458935 1.819427 0.868068 2.112435 2.445438 1.217877 2.101026
+1 0.021835 1 1 0.425432 1.545771 0.379440 1.378025 -0.925152 1.856154 0.369674 2.176972 1.387327 -0.098008 2.114144 1.009032 -34.577438 -43.006452 40.562101 -22.772879 56.216172 1.002926 0.670740 2.125989 0.752261 2.007148 1.388448 2.403643 0.769097 1.455250 2.378070 0.725694 0.981623 0.390062 0.768727 1.992026
+1 -0.046028 1 1 1.587065 1.673192 -2.204502 -2.255668 0.160875 -1.089733 1.913727 1.958001 1.517767 0.943049 2.056111 1.110415 53.628974 -7.839033 -50.628407 38.356360 -44.660481 1.244442 0.839219 1.001467 0.910119 2.363967 2.193112 1.638653 2.337513 0.828640 0.951797 0.854677 2.064095 2.247859 1.521216 1.825873
+1 0.000979 1 1 -1.980934 -0.523279 -1.438009 1.217806 1.757510 1.214703 1.450877 -1.726274 0.692086 1.709690 -1.394705 -1.390380 19.767387 -19.527876 -5.013140 44.155199 66.432665 0.381911 1.033471 1.041760 0.863827 0.597068 1.423972 0.952724 0.677119 1.345560 1.570545 0.649372 0.742034 1.111658 1.131347 1.297512
+1 0.022600 1 1 -1.645343 -0.986576 1.506411 -1.415900 0.541509 1.513026 1.383734 0.773126 1.869208 -1.716270 -0.823169 0.579470 -43.352158 -69.718785 36.385210 -23.770777 -65.444664 1.697935 1.945815 1.067435 0.386044 0.741944 1.855232 1.889232 1.818392 1.462723 1.990023 1.567616 0.928087 0.612124 2.471324 2.046984
+1 -0.005712 1 1 0.222215 -2.151200 -1.776145 1.321865 -2.324349 0.377526 2.198742 -0.292604 1.940033 1.121732 -1.314974 0.327093 -60.934646 71.405427 -38.984220 -7.792067 -11.266674 0.490227 1.246482 1.369215 0.899068 1.141172 2.180738 0.656889 1.083418 1.255627 2.066149 0.764507 0.825570 1.111758 0.570311 1.711229
+1 -0.027043 1 1 1.229881 2.077774 2.348064 -2.339454 0.961981 -0.185490 2.064158 -0.311303 -1.313115 -1.402628 2.109613 0.253811 34.606786 -63.755017 69.421820 72.531714 -9.479506 1.044098 1.901724 0.269742 1.299467 0.887321 1.710127 2.104416 0.424220 1.117303 1.512253 1.933014 1.916719 0.300894 0.632701 1.813405
+1 0.062573 1 1 1.550011 0.945689 -0.689107 1.232274 -0.118244 1.298418 -0.560993 0.884704 1.639066 -0.852057 0.420011 -0.039620 -46.091493 -59.729830 70.752967 -54.890943 -52.072850 2.299104 1.042724 1.314517 1.844285 2.391588 0.667582 0.800920 0.817208 2.311211 2.027963 2.472617 1.274609 1.609029 1.699814 2.018588
+1 -0.007682 1 1 -0.544514 -0.180562 0.076276 0.199105 0.566848 -1.433955 -1.319730 0.512045 1.123849 1.271181 -1.232949 -1.801984 18.357125 -21.798704 -70.818200 8.511700 -43.861881 2.325373 1.544025 0.432890 0.580959 0.671319 0.603014 2.353984 0.909753 0.716197 1.129770 1.795962 2.485884 1.508308 0.881753 0.367749
+1 0.030090 1 1 2.274802 0.989902 -2.156069 1.220762 -0.402710 -1.348557 1.393550 0.816022 1.825991 2.344728 -1.870624 1.488046 29.743335 -53.770570 28.022496 -25.915466 38.768138 1.016360 1.454252 1.358581 2.173764 0.447105 0.994903 0.837221 1.168853 1.667321 0.417457 2.198984 1.331908 1.634224 2.153382 2.142898
+1 -0.019028 1 1 -2.027868 2.326188 2.269932 -0.752282 -0.267931 1.922041 0.317869 -1.428207 1.031303 0.936549 1.198995 1.327896 2.139359 -43.795577 -22.257603 16.461596 70.051497 1.457624 1.788932 1.326112 0.968455 1.822523 1.141490 0.768936 1.004119 0.478173 1.149634 0.394292 2.117879 1.696831 1.389543 0.543859
+1 -0.000513 1 1 0.829265 -1.784210 -2.292694 -0.103293 -1.887026 -0.867398 1.780705 -0.076976 2.164057 1.084194 -0.759563 -0.106784 22.110029 53.254764 2.818236 -33.904796 12.091201 0.877182 2.293222 1.176633 1.920177 2.170508 1.985636 2.086802 1.385677 0.819584 1.750160 2.184619 0.638049 1.687731 1.450215 1.016503
+1 -0.020806 1 1 -1.807739 -1.893157 -0.236376 -0.228155 1.291121 -0.680251 -0.728218 -1.092644 0.113559 0.070412 0.597365 -2.182688 47.950366 -48.196898 -45.263386 58.274377 67.452896 1.087319 1.576118 2.070112 2.116853 2.449020 0.675499 1.117766 0.289044 1.712154 2.418099 0.748895 1.672856 1.198027 1.493116 2.048534
+1 0.014438 1 1 0.148178 2.283680 -0.597503 -0.132141 -1.361607 -1.162711 0.594825 2.242381 -1.993415 1.755466 -0.157112 -1.639209 -49.398928 2.214634 21.344449 -63.843362 -65.380520 2.118918 1.158472 0.446149 0.679664 1.364504 0.462549 1.810296 0.396234 1.003974 0.292415 2.117288 0.755695 1.209896 0.729751 1.676257
+1 -0.010416 1 1 0.820573 -1.790693 1.852905 2.307655 1.797272 0.330153 -2.305730 2.282751 -2.077256 1.639307 -1.497516 0.113583 15.252217 -5.989374 -13.409242 -69.137818 50.696938 2.326539 0.888949 2.066522 0.281968 2.029191 0.615543 1.423069 1.524115 1.041577 2.277194 1.790340 2.496557 0.885845 1.639124 1.251023
+1 -0.057559 1 1 1.144892 1.517263 1.902886 -1.170332 -0.252198 -2.259132 -1.514365 -0.324815 -2.222594 -0.030239 0.714447 0.535826 8.048684 -25.762102 66.350374 50.733765 -67.613705 1.621845 1.103629 1.187153 0.981629 0.495401 0.451586 2.061860 0.682772 1.847424 1.155447 1.351143 0.917924 0.799185 0.902616 2.274625
+1 -0.067065 1 1 -0.166128 2.332553 0.854743 2.299678 -0.323759 1.393227 0.109722 1.552742 -0.277048 -0.513374 0.104537 -0.759652 -51.249475 -49.926678 -17.685136 65.911656 27.205666 2.059390 1.915429 1.110038 0.903254 1.734691 0.944982 1.060154 1.754910 1.027420 0.603034 0.445429 2.074605 1.137392 1.638401 0.348612
+1 -0.018108 1 1 -0.998240 -1.317157 1.353722 0.592190 0.374714 2.073815 1.782694 0.362490 -0.755493 2.311556 1.392896 -0.744138 -1.676016 31.193430 17.984711 19.031567 63.540040 2.386678 1.396965 1.537108 1.181705 1.668233 2.248493 0.914489 1.569530 1.584398 1.730913 0.448200 1.400457 1.738957 0.656851 0.443970
+1 0.021527 1 1 1.798604 -0.843502 -1.864991 1.913305 -0.418339 -0.141502 1.524756 0.608199 0.829396 0.415440 -1.459730 -0.986271 61.609325 17.925939 -68.749759 -27.200196 46.300586 0.984198 0.908160 0.943552 1.776992 0.902960 1.304360 2.123812 2.408962 2.433203 0.347471 0.448178 1.030820 1.492108 0.856385 1.512902
+1 -0.036820 1 1 -0.089789 -1.113711 -0.531611 -0.098530 -1.943707 -1.603906 -1.981696 0.803788 -1.158660 -2.013928 0.999419 2.279981 -47.852402 44.671679 46.905341 -61.936000 41.645539 1.923692 0.491555 1.058631 0.910206 1.578482 1.300372 0.351273 1.337437 2.297516 1.353758 2.113770 2.383388 2.347274 0.630389 1.189750
+1 -0.025068 1 1 -2.343178 -0.361999 -0.419176 -0.063481 -1.919959 1.686195 -0.418867 0.406154 -2.014213 0.918103 2.192202 -1.826448 -19.355393 43.907687 -43.504083 -73.123410 -35.145899 1.418019 2.153867 1.285893 2.250763 0.819419 1.220263 1.705537 1.461125 2.130810 0.775364 1.034617 2.301490 0.648415 0.416634 1.870007
+1 0.013316 1 1 2.289874 -0.175981 1.673783 -1.691611 -1.069896 0.730515 1.992156 0.643373 -1.766512 -1.719772 1.577121 -0.514771 6.079099 21.421855 37.116391 -34.817505 -27.808947 1.600475 1.933380 1.322941 1.675048 2.029140 2.007176 1.851732 1.565896 1.265045 0.614471 1.417881 2.069468 0.299441 0.956693 2.139294
+1 0.072932 1 1 1.065278 1.756359 0.721077 -1.115075 0.099452 -1.406062 0.944510 -1.664102 -0.538278 0.950365 -2.220618 0.191298 41.290852 -74.653298 52.019141 -64.290588 68.089527 1.835153 1.912165 0.250351 1.649636 2.440654 1.814852 0.463858 1.318262 1.773782 0.949133 1.076262 2.489990 0.759027 0.964419 1.482365
+1 -0.044263 1 1 -0.274712 1.050400 1.460425 -1.478130 0.790177 0.986601 -1.100647 2.258216 0.258442 -1.189043 0.996711 -0.825113 28.231396 35.072830 -30.939178 55.241080 -63.169361 1.563364 1.460882 0.296872 0.522715 0.515501 0.771613 0.997315 0.876683 0.654225 1.301322 0.575876 0.753914 0.527485 1.948268 1.790808
+1 0.014711 1 1 0.578319 -1.849858 1.786247 -1.183638 2.295206 -0.093080 0.117964 -1.289155 0.740914 -2.307360 -1.554823 -1.709829 -30.373194 -32.271189 18.127821 24.290065 -56.874391 2.306531 2.123245 1.884445 2.371749 2.482578 2.192593 1.906960 0.534188 2.105195 2.257213 1.234310 1.554929 1.448620 1.199359 1.378995
+1 0.010888 1 1 -1.793288 0.652709 -0.359638 1.565889 -0.799169 -1.320874 0.130169 1.194469 0.665909 0.014227 -1.225409 -2.301778 -62.897383 -66.320725 -2.428443 -14.838330 62.188072 1.298852 1.812513 1.653493 2.000598 1.555407 0.480006 0.468516 0.849309 1.840259 2.225885 1.202164 1.275461 2.414303 2.198000 0.533557
+1 0.014033 1 1 -0.878926 1.228853 -1.069733 -1.246860 0.009622 1.489168 0.950101 -1.942235 -0.424043 -1.765207 1.367539 1.911705 30.482968 -72.758131 -45.910974 -25.747783 7.011229 0.440788 0.565657 2.245195 1.741885 0.361847 1.310858 1.096056 2.168779 2.160113 0.516014 0.399040 0.921342 1.987124 2.347088 2.013361
+1 0.008441 1 1 -0.313854 -1.786573 0.416817 -1.878138 -2.285225 -1.799577 -1.371583 0.807027 1.443071 -0.974135 -1.449984 -2.109253 34.349847 -32.125263 70.713157 26.034315 8.726348 0.831003 2.422003 1.095924 2.188574 1.869119 1.284500 1.342785 2.186177 2.072648 2.001491 0.803926 1.832391 0.491715 1.495991 0.869365
+1 -0.006374 1 1 0.741368 0.615334 -1.776770 0.240161 -2.130835 1.217435 0.243187 1.594590 0.916670 1.677376 2.148242 -0.817590 3.051748 -9.268623 72.254395 -20.382933 24.049533 0.632551 1.533859 0.577354 0.834954 1.328092 0.494913 1.254355 0.941204 0.557878 2.005687 1.576531 2.260072 2.033765 0.979127 1.187469
+1 -0.024325 1 1 -0.655821 -0.111079 -0.791710 1.510273 2.238363 1.169178 -0.286275 -0.070967 -0.505556 -0.447080 2.188020 -1.437851 -26.556286 68.503429 -62.869704 -51.119771 30.006345 1.624510 0.891394 0.416031 0.729921 2.274443 0.568752 0.268740 2.470106 1.821312 1.044894 1.785748 1.823348 1.506355 1.806939 2.468595
+1 -0.078005 1 1 -2.264654 -0.069874 -0.992520 0.579282 0.200628 -2.118635 -1.083727 -0.815190 -1.989613 -0.309989 1.923823 1.989384 37.638530 40.779602 32.776283 70.993649 -59.748249 2.292749 2.235406 1.466340 2.023506 1.819039 1.090606 0.559070 1.788343 0.434423 1.594554 1.422840 2.179628 2.253325 1.130713 1.890574
+1 -0.015158 1 1 0.361031 -1.716099 2.058078 1.176167 -0.633480 -1.604736 -1.802694 -1.931883 -0.799906 0.432610 -0.344905 -0.582384 -16.010437 12.581536 -42.124363 15.830729 -32.943352 0.941182 2.447521 2.479769 2.235076 0.423398 0.799085 1.472352 1.815160 1.140421 0.798438 1.840718 0.956628 1.045843 1.984026 2.029590
+1 -0.001337 1 1 1.976620 -1.281541 1.462136 -0.988573 0.936092 -1.776513 -0.156573 -2.009173 0.804545 2.146224 -1.746244 -0.364405 49.314181 73.437033 56.209118 6.638460 -27.403690 0.267752 1.611373 0.588435 0.332595 2.428962 1.064090 0.409609 0.801117 1.870260 2.466626 1.831550 2.112269 1.908638 1.722466 2.480208
+1 0.011526 1 1 -0.562492 -0.753477 -1.499544 -0.979154 -0.978349 -1.590222 1.809804 -1.092070 0.341581 1.266194 -0.225546 -1.992411 -6.607537 -52.865128 -54.209806 -4.203439 2.803377 1.620483 0.710407 0.557313 1.507267 1.377831 1.711126 0.897044 0.867621 1.348956 2.406527 1.990857 2.092726 1.952302 2.095572 0.278523
+1 0.006192 1 1 -2.167809 1.826755 1.052698 -2.334233 -0.817013 0.361846 -2.147218 -0.824926 -0.681045 0.066436 -0.245497 1.978598 -32.885182 48.747680 2.265554 -22.840898 -36.979238 0.474135 0.779768 0.818364 1.494182 1.967260 1.493793 2.170639 1.935922 1.291716 1.126945 1.571048 2.349368 2.072865 1.143840 2.017070
+1 -0.003007 1 1 1.607177 0.402787 -2.064444 0.205608 1.477553 -1.065185 -0.199137 -1.097933 0.754667 -2.057355 1.552454 -0.408596 -42.305416 -27.125033 -40.429499 1.406268 -64.856528 1.469962 2.156869 2.255714 0.788246 1.548999 0.780846 0.928997 2.407448 1.729902 1.457520 2.294675 0.847922 1.027001 0.311609 0.706863
+1 0.011717 1 1 -0.778323 0.321525 -1.244437 -1.667335 1.678081 -0.149272 -1.821796 2.183237 -1.705132 -2.114359 0.084567 -1.832149 -69.466413 -72.001270 74.657561 19.635574 15.086822 2.338271 2.328077 1.994043 1.626325 2.140403 2.257224 1.418275 1.949293 1.018422 2.364698 0.972486 2.074036 0.570101 0.440049 1.661732
+1 0.024315 1 1 1.192872 2.100761 2.272797 0.265863 1.019961 -1.187837 -2.293244 0.080460 -0.163933 1.526729 0.783303 -1.443922 25.449600 -68.571608 -33.015237 -37.093860 -36.506749 0.341097 1.318609 0.864216 0.372188 1.864654 0.494925 1.459521 2.171435 1.812498 1.404233 2.186468 2.470402 2.296617 1.997964 2.272924
+1 -0.027725 1 1 -0.357785 -0.289338 0.288506 -0.129051 -1.263720 -0.596216 -2.068161 -1.003894 -2.086404 -1.312957 1.255304 0.532452 2.733043 34.262904 6.634856 62.017864 -15.758084 2.183242 2.244193 0.658879 0.782113 1.972447 0.911090 0.681565 1.818924 1.399670 2.003379 1.046242 1.931031 2.336060 1.154111 1.388329
+1 -0.025419 1 1 2.190902 -0.122224 0.377257 -2.312455 2.350245 1.318939 0.335533 -1.423104 1.977591 0.897253 0.478771 -2.062443 27.361080 -42.333834 -54.754653 -11.448747 30.902019 2.428449 1.437613 0.717424 1.496722 1.903388 1.235807 1.954946 1.519089 2.074318 0.816643 1.826456 1.994241 0.460564 2.191019 2.459119
+1 -0.022420 1 1 -1.429428 -0.642180 -1.749006 0.339308 0.754816 0.448592 -0.341498 0.132514 -1.797881 -1.156199 1.650766 -2.120985 58.281030 29.263929 -11.145293 31.063159 -71.482004 0.654337 0.941033 2.183859 1.370280 0.801101 1.612002 2.166924 2.489326 0.845891 0.638954 1.147756 0.328440 2.334633 1.924587 2.030610
+1 -0.033869 1 1 -0.324657 0.428331 -1.570548 -2.116056 -0.151323 1.400280 0.832432 -0.399327 -1.053953 0.076815 -0.161713 1.139061 -71.024404 -7.152527 -62.515871 45.749650 14.365155 0.402486 0.340438 1.493273 2.445427 1.045886 0.459478 1.944671 2.081953 0.888408 1.976568 0.421969 1.527616 1.387857 1.466451 1.634496
+1 -0.007251 1 1 0.267596 1.875155 -0.732640 -0.008615 1.295063 -0.405096 0.948331 1.292669 1.773367 -0.885945 1.078092 0.354636 -25.858663 -56.543165 -70.975625 62.663958 43.137909 2.407488 2.394126 0.569600 1.018369 1.484619 0.982441 0.627752 1.883441 1.247819 1.341750 0.543951 1.940454 0.957091 2.076420 2.394571
+1 -0.007923 1 1 0.293427 -2.244614 2.150356 1.728476 -1.377346 -1.795128 -2.001129 -0.656451 -1.265180 -1.581569 1.156783 -1.273266 -26.025717 -14.219484 -36.859497 2.429375 30.505939 1.574650 2.145565 1.262974 1.797496 1.265328 0.873851 0.309144 2.033607 0.576317 1.401875 0.818643 1.690731 2.373161 1.458405 1.404256
+1 -0.011313 1 1 1.589170 -0.637815 0.927495 -0.176685 -0.738326 -1.322004 0.001922 -0.688813 1.463991 1.906798 -1.401441 -1.493645 -25.122206 21.075435 64.838855 -3.357971 -37.414022 1.113059 2.176677 2.168936 0.305122 1.941317 1.968236 2.143239 0.418639 1.817399 0.520662 2.024316 1.925452 0.823346 1.980090 1.116122
+1 0.012398 1 1 -0.489760 1.145458 1.594811 -0.078309 -1.379287 -1.440475 2.198562 1.385631 -0.332718 1.620059 0.156689 -0.746647 6.070350 24.375725 32.806974 -13.193833 -48.745097 1.992298 1.549076 2.071082 0.419906 0.611852 2.394025 1.132362 0.358735 0.755740 1.967062 0.418834 0.590956 2.193038 0.390345 1.027420
+1 -0.019143 1 1 -0.670905 0.844362 2.189634 2.141999 -2.078521 -0.767847 2.031535 -1.955653 0.249737 -1.402649 1.767211 -0.673706 28.635097 70.071266 37.767000 -50.031166 26.187954 1.989027 0.579102 0.969838 0.324570 0.298725 2.425012 2.177599 1.914126 1.709965 1.622769 0.875602 0.497191 1.283395 0.768181 1.818216
+1 -0.054950 1 1 0.264159 0.648940 2.259214 -1.813257 -0.385194 0.870291 -0.268982 -1.602906 0.692077 1.557667 -2.331353 0.470363 -63.609181 -29.510768 62.521953 56.468994 24.378225 2.497395 1.474207 1.501742 0.786685 2.308966 0.284933 2.372790 1.972676 0.270597 2.173717 1.910919 1.813702 1.387988 1.407826 1.833638
+1 0.015114 1 1 -2.099414 1.513187 -0.629379 1.334731 1.859435 -1.035305 -2.230576 -2.229641 -0.662554 -0.165070 1.259220 0.376469 -45.412253 -43.742699 -33.538155 24.225300 54.610693 1.253707 1.297843 0.589971 1.386534 1.724897 0.597238 2.035718 2.303994 2.224503 0.465560 0.675165 2.256429 1.555892 1.880556 2.249151
+1 -0.049693 1 1 0.798031 1.040309 1.515822 1.253039 0.166163 -1.739176 0.613041 2.101829 1.369780 1.868136 -0.890335 -2.020068 46.983181 46.322233 37.772887 48.919186 34.751005 0.777171 2.159321 0.710879 1.746339 0.966101 0.510837 1.132374 0.552455 0.861956 0.648899 1.791562 0.528808 1.675558 1.600447 1.456608
+1 -0.001094 1 1 1.800131 1.263657 -0.448693 -1.365350 1.899302 -0.154514 -0.389961 0.857415 0.089270 1.821910 -0.255362 1.115139 30.853219 0.060070 -40.410692 17.498452 -53.515223 0.919663 0.767767 1.602634 2.220946 1.438961 0.871916 1.546526 1.959706 0.533740 1.313171 1.717105 2.375780 0.484936 2.327285 2.183449
+1 -0.000015 1 1 1.683718 0.354655 -0.488006 2.346262 0.356435 1.157693 -0.115741 0.965696 0.991224 1.212165 1.194057 -1.542181 -41.054904 -9.767661 -65.071055 0.778071 27.045373 2.148652 1.397828 0.294573 2.392879 2.118899 0.830622 0.512435 0.994915 1.031152 0.326590 0.500501 0.673738 0.771552 2.226326 1.864530
+1 0.003861 1 1 -1.171885 1.919423 -1.271052 -1.307118 0.422477 -1.005144 0.455901 -0.022751 -0.667796 1.259867 1.829822 0.765659 -35.253090 1.316027 68.471764 4.943447 -15.483276 1.713720 1.743750 2.452441 1.923486 1.535917 1.409614 0.386356 1.481196 1.953091 1.854799 1.363444 0.647876 0.347142 1.665555 2.238973
+1 -0.012499 1 1 -1.566489 0.130936 -0.040027 1.139827 1.216611 0.530913 -2.208911 -0.965364 -0.114461 -1.091330 -1.362962 -0.376268 2.619034 68.095352 -21.417619 34.079308 70.922465 0.532966 1.815301 1.270850 1.424390 1.227491 1.687503 2.114938 1.765344 0.884835 0.416881 1.515384 0.567603 1.207750 0.645890 0.725787
+1 0.014627 1 1 -0.179955 0.851389 -2.226351 -1.908465 1.659423 2.004768 0.556570 0.182286 0.624129 -0.045958 0.419342 -1.849906 30.717530 -30.465669 63.502271 32.664041 -15.456397 1.740020 0.508204 1.891853 0.873222 0.993510 2.177693 1.241129 1.409853 2.150685 1.803872 0.429570 1.035741 0.949542 1.210084 1.636347
+1 0.008174 1 1 2.026909 0.393692 0.585985 -0.235601 -1.343452 -2.334121 1.070662 -2.000896 -1.453527 -0.402214 2.266613 0.010047 -25.125668 -37.098750 31.305808 -43.278379 -29.709622 1.680773 1.493759 1.608884 1.515218 2.269604 2.481764 2.003856 2.311111 0.339686 2.351341 1.489124 2.457846 0.516044 0.909271 1.613017
+1 -0.028296 1 1 -2.097448 1.575546 1.286529 2.258524 0.724536 0.471466 -2.307170 1.642640 -2.032069 -2.299031 1.768777 2.083036 39.976628 37.189401 -7.744157 43.957545 44.462926 1.200876 2.125299 0.398470 0.328060 0.451779 0.794933 1.443054 2.156023 1.524945 1.496918 0.707796 1.680143 2.167155 1.869876 0.510270
+1 -0.048370 1 1 0.714020 -1.927517 1.903371 2.256008 0.845488 2.265142 -1.153809 -0.593972 -2.046341 -1.831654 1.422528 -2.227263 51.474380 -70.094279 25.448744 67.041569 -32.354292 0.946339 1.373324 2.450484 0.542745 1.917729 1.526201 2.365384 1.256686 1.869112 1.164246 0.731786 2.121500 1.798709 1.399696 2.441288
+1 0.007621 1 1 1.477724 1.819602 -1.357203 2.166324 1.483527 0.395647 0.461985 -1.431959 -0.766929 -1.391406 2.234132 0.746321 -30.475511 48.091956 -68.488364 16.059011 53.796433 0.724764 1.105807 1.803767 0.906645 2.484633 0.725794 0.413737 0.425330 1.765021 2.206230 1.610891 1.495750 1.326597 2.368863 1.235477
+1 -0.041183 1 1 0.273215 2.063233 -1.706120 0.135658 -0.788999 -0.048228 -0.036456 -0.103951 1.189118 0.258309 1.293490 1.438691 25.728053 -38.612538 -60.918346 45.356135 0.559938 0.788255 1.698379 0.409724 0.478881 1.797854 0.524970 2.426770 2.473503 0.419057 2.087675 0.311240 1.265141 2.219738 1.383607 2.027103
+1 0.023157 1 1 -0.276938 1.345423 -2.230346 1.635366 -1.767213 0.640513 2.003190 2.299967 -0.173881 -0.739716 -1.120861 1.823433 56.323079 -28.004017 36.487712 48.971190 8.788967 0.867575 0.577351 0.780225 1.734340 1.796895 2.413982 1.299912 1.626288 1.522685 1.775566 1.690306 1.976343 1.149099 0.408779 0.346779
+1 -0.060058 1 1 1.073703 1.980519 -1.736444 -0.586535 0.419612 -2.019233 1.378857 -1.075866 -0.641361 -2.113039 -1.284373 0.999712 -70.753380 47.936431 17.594306 57.503757 15.644497 1.180975 0.648721 1.050723 0.744607 1.607286 1.661182 0.739598 0.671214 1.090285 1.913729 1.800838 1.176309 0.981271 1.227905 1.900497
+1 -0.013092 1 1 0.969217 -1.104835 -2.145792 -0.413993 2.215167 -2.269640 0.955932 1.820525 0.016739 -1.404853 -2.299713 -0.254976 -57.993532 2.700059 -70.105831 -18.704694 30.208428 0.820822 2.311149 0.975541 1.671823 1.832427 1.102477 2.073440 1.803104 1.014623 1.515236 0.325443 1.465449 0.548637 1.940966 0.567790
+1 0.009896 1 1 1.769159 -0.921847 0.852145 1.046005 -1.717730 -1.796203 -1.220778 0.122525 -0.030177 1.746632 2.176099 0.847335 10.424219 -0.148608 52.345930 28.037394 74.481001 2.157777 1.749830 1.145075 0.283912 0.962655 1.093589 1.202027 1.215874 2.185525 2.361703 2.389014 2.405013 1.307543 1.617402 0.675890
+1 0.055888 1 1 1.057065 0.377194 1.335551 1.499348 -2.307708 2.018764 0.167461 1.213631 2.275042 0.310403 0.320742 -0.257153 -22.827288 41.770665 39.567932 68.235545 -65.188193 1.105559 2.132169 1.115000 1.058106 1.085114 0.503194 0.933012 2.376014 2.172858 0.979421 1.624069 2.470382 1.963202 0.790882 0.852790
+1 0.032310 1 1 -2.238253 0.675641 -1.355047 0.701586 1.157039 -1.673577 0.438946 -2.243714 -1.559592 -1.749112 -1.449158 2.347790 -71.054263 -58.997324 -68.028524 -55.401737 63.010920 1.743074 2.340936 2.108359 1.439911 1.077027 1.835257 1.415719 1.745434 1.500213 2.077924 0.676956 0.857009 0.755598 1.835365 0.983760
+1 -0.004074 1 1 0.127650 1.280642 2.270457 -1.357400 -1.139164 0.513717 0.948848 0.571672 -0.472612 1.890699 1.338138 -2.144214 -69.194282 1.700750 -65.487609 49.747191 1.042411 0.921996 1.731633 1.309370 0.825698 1.001961 2.459625 1.170439 1.318357 1.120314 0.368687 1.528358 0.365001 0.328856 0.324674 2.051805
+1 -0.069991 1 1 -1.420514 -1.617326 -1.332847 1.545482 0.234393 -0.110737 0.231433 1.977380 2.057790 1.052622 1.112957 1.992408 5.431233 -67.264430 36.729880 69.088611 22.280839 2.486031 1.727506 1.692183 2.018987 2.357035 0.433440 0.828745 0.471007 2.208221 1.314217 1.300057 1.800987 1.442137 2.493843 0.275653
+1 -0.039462 1 1 1.065523 1.164414 -0.238814 1.210072 -0.990576 0.262432 -0.105532 -1.825938 -1.467737 1.102807 1.051727 0.203566 4.591334 66.551259 -22.995190 69.847224 22.294524 1.436087 2.057195 1.030537 1.234067 1.958083 0.257274 0.998166 1.670388 2.456675 1.092724 2.411615 2.013496 2.325354 1.227181 0.974190
+1 -0.027221 1 1 1.665803 0.844463 -0.832171 0.071708 -1.172027 -0.469094 -0.242684 2.144795 -2.209363 0.858151 -1.682507 1.153085 -68.605395 -0.866851 -19.157933 62.615004 -29.628726 1.825142 2.416490 0.693443 1.202104 0.256708 0.489074 2.119914 2.139873 2.336549 0.371980 0.624133 1.799102 1.263849 0.755848 1.538448
+1 0.015525 1 1 0.899402 -1.096720 2.285864 -1.599754 1.821523 -2.060750 1.041580 -0.682716 0.263122 2.076108 -2.099593 -1.491795 64.580884 10.919550 74.870334 -4.300261 25.511028 2.332635 2.095002 1.942937 2.183739 1.594644 0.677699 2.081301 1.172479 1.857404 2.391367 1.457296 0.774006 0.724088 0.999920 1.899887
+1 0.034252 1 1 -1.812489 -1.612904 2.300603 1.081274 1.998902 0.922412 -0.784628 -1.982362 -0.963569 1.772660 1.377528 0.153147 31.288691 -30.962016 -28.610635 41.050259 -68.294503 0.989315 1.417555 1.103144 2.047081 2.047208 1.933978 2.361088 1.048463 1.010118 2.303619 0.423849 1.627296 0.460308 2.403799 1.143961
+1 -0.008855 1 1 2.295103 -1.819106 0.266475 1.872487 1.560049 0.017210 1.791350 -0.239747 -0.335698 -1.352147 2.324726 1.247404 -9.806309 35.372385 53.667120 33.285006 71.092709 0.702435 1.573585 2.238936 2.296578 1.332084 2.340602 0.993818 0.592035 2.325049 0.599079 1.475998 2.357412 2.268837 0.846136 0.256790
+1 0.036422 1 1 -0.122441 1.450203 1.078242 -1.838124 1.066033 0.317838 -1.948375 0.046583 0.665755 2.134589 0.625201 -0.876983 28.614360 21.547390 46.985409 -66.239156 18.513138 2.129781 1.471819 1.857099 1.770996 1.385555 1.014382 1.959878 1.165912 1.728068 2.144379 1.572625 1.862047 1.667819 2.033756 0.831825
+1 0.027309 1 1 0.554175 2.333309 -0.569801 -1.063336 -2.110090 1.150884 -1.444742 1.165252 -0.291462 2.289160 1.967408 -0.603797 -71.484732 56.116360 -52.333208 35.771579 12.930171 0.885883 2.288468 2.276883 1.070477 2.000684 0.743561 2.035111 1.113509 0.750926 2.065887 0.868567 1.503228 1.008670 0.473599 0.777826
+1 0.000548 1 1 0.503626 0.993661 -0.237790 -0.430895 0.896311 -1.209102 -1.552682 1.285225 -0.820342 0.965587 -0.842531 0.315094 -29.825702 19.429462 0.973391 9.776827 69.124525 1.763349 1.113343 2.451324 1.157539 0.516343 1.429938 2.209107 0.457221 2.259981 0.503232 1.567740 0.755055 1.708995 1.078432 0.712982
+1 0.079633 1 1 0.042947 0.810778 -1.484290 0.927215 -0.160525 2.257560 -1.339447 -1.009114 -0.293801 0.672351 -0.101649 2.185995 71.280234 -43.107900 -14.480141 -67.721736 0.789947 0.274478 2.154137 1.334911 0.353588 1.995905 1.419567 1.166529 0.845984 2.211150 1.050558 2.475786 0.537059 0.854691 2.287276 2.495195
+1 0.020130 1 1 0.858383 2.213517 -1.726826 0.837188 -0.580297 1.591403 -0.810726 -2.348453 0.523187 -0.110251 -1.012092 1.487320 -58.545932 18.523172 68.952700 -11.978077 -15.543230 2.348909 1.121371 2.389760 1.444495 1.618430 2.203972 1.909772 0.536327 2.051456 1.326061 2.360880 2.069387 1.188310 2.430730 1.534080
+1 0.034420 1 1 -0.884313 0.223192 0.130491 1.907776 0.902306 0.586166 -1.906312 0.145671 -2.156287 2.259739 2.298551 -0.412211 -26.207912 73.617671 -57.808416 -36.044629 47.926773 1.454108 1.187052 1.527117 1.998983 1.412860 0.940978 1.273369 1.007274 1.761437 0.475592 0.524400 1.848685 2.101658 1.313536 1.101262
+1 0.022266 1 1 1.964564 -1.277955 0.485781 -2.050428 0.164876 0.180727 -2.016107 2.085279 1.250727 -1.005567 -1.932574 1.730069 58.137064 9.630347 7.236766 -21.669277 4.469482 0.903650 1.651706 1.231532 2.104649 2.093529 1.939694 1.684515 1.392704 1.925789 1.979622 2.253221 1.633480 0.895140 0.365092 1.849051
+1 -0.014455 1 1 -0.638665 0.783567 -1.710098 -0.757510 1.404662 -0.917961 0.187464 -1.883595 0.241463 0.894148 0.143666 1.842869 -45.888299 55.351007 -15.625370 34.399197 47.297699 0.361375 2.378048 0.361110 2.425300 0.271733 1.010981 1.063038 0.736585 1.790390 1.090308 2.310362 1.254403 1.748433 2.411307 1.338730
+1 -0.002624 1 1 1.343464 -2.174796 2.199629 0.467308 -1.502188 1.706833 -2.276834 -2.153488 2.187243 -0.350621 2.318503 0.327436 -27.271673 44.987341 -47.767205 -23.416193 44.047125 2.125488 1.327746 1.430470 2.168294 0.768087 2.480031 2.125188 0.782972 0.665109 1.989378 1.970163 0.777961 1.934890 1.946702 2.463573
+1 -0.030048 1 1 -0.936754 0.061379 -0.411017 0.392002 0.463099 -1.565788 -2.217769 0.961125 -0.449355 1.657538 -1.407304 -1.085095 -7.786235 -63.247269 53.158291 31.388620 -1.470914 1.800166 1.135013 2.158757 2.478343 0.753580 1.668156 0.954559 2.271975 1.841611 2.458087 2.323551 2.425925 1.764059 1.785318 1.332074
+1 -0.005060 1 1 -0.698029 2.080328 -1.850187 0.959604 2.276255 1.840345 -1.447247 1.470018 -0.456556 -1.567098 -0.682681 0.851778 -12.719959 -34.349989 29.728046 -10.737666 -17.944503 2.226074 2.119924 2.320016 1.507587 2.267484 0.603544 2.268989 1.156920 1.355302 1.057069 1.656948 1.566592 1.710071 1.162440 1.884693
+1 0.065775 1 1 -0.547048 -0.361849 2.095327 0.477774 0.036917 -1.577867 2.113945 -2.334738 0.129400 -2.297955 1.012472 0.185518 -51.134216 -62.767630 14.445806 -59.334862 -41.023544 2.384353 0.565045 0.958828 2.015982 1.352470 0.716831 0.528238 1.097825 0.397802 0.353326 2.108153 2.468636 1.865509 1.361973 0.685469
+1 -0.009610 1 1 0.974983 1.567430 1.549744 1.180221 1.530383 0.927906 2.015915 -0.592961 0.802542 1.473597 -1.568817 -1.294166 42.879190 70.553400 40.998768 -33.709763 -9.981171 0.571982 0.550542 2.453638 1.790668 1.251921 0.531576 0.946857 1.067860 0.778160 0.779923 1.170812 0.834109 0.615813 1.461610 1.280725
+1 -0.054021 1 1 2.044983 -2.144229 2.295873 1.701901 -0.354416 -0.211446 -0.632591 -0.809308 -2.083421 1.706494 1.443022 -1.789498 -51.767449 -55.509087 58.782362 55.162031 -41.740544 1.625170 0.738284 1.089888 1.993280 2.302083 1.609979 1.909907 0.564006 1.500673 0.809460 0.338836 1.570614 1.809210 2.398970 0.986887
+1 -0.003371 1 1 2.123040 -0.282957 -0.863981 -2.054952 -0.486821 -1.290483 1.969706 0.310209 1.783224 -0.155146 -1.590754 2.297271 52.138904 -1.445461 6.131376 0.039417 62.480048 0.657581 1.464082 2.319710 0.873692 2.148445 2.407923 0.707351 0.951126 0.822009 2.011992 1.803165 2.036070 1.472349 1.770661 2.499442
+1 0.018166 1 1 1.027212 -1.848093 -1.541228 0.578073 -1.267096 -0.801863 0.516889 -2.287931 -0.154848 -1.286382 0.219909 1.494532 49.981292 35.566810 21.381337 -43.875173 -10.031423 1.403107 1.275403 1.444276 2.444155 2.165306 2.295641 1.338955 0.818631 1.485759 2.148489 0.905016 2.107301 1.651775 2.375628 2.423325
+1 -0.029635 1 1 1.810387 -0.724675 1.920487 -2.230939 1.090279 -2.163608 1.751092 1.741358 -1.640630 -1.875069 2.168192 -0.100403 -13.988960 -62.445136 34.606055 73.958365 -31.751786 2.091046 0.710176 1.174808 0.491324 1.689597 1.303682 1.975909 0.594467 0.455744 2.197783 1.379850 1.890908 0.741701 2.271717 1.989623
+1 -0.007024 1 1 -2.159872 -1.439635 2.175529 0.696837 1.452229 2.148961 1.843355 2.013926 -1.037332 1.391695 -2.088791 0.988910 0.386650 48.429468 54.074640 -17.518808 11.390578 1.996701 1.299489 1.261449 0.926782 1.183436 1.505802 1.505937 1.527716 0.830325 2.276212 1.046631 1.724553 1.554966 2.063326 0.571853
+1 -0.003650 1 1 -0.340976 -0.526818 0.344230 -1.338471 1.265312 -0.912028 0.939630 1.140322 0.113528 -0.449720 0.232503 1.107224 -3.471211 9.350718 -42.474104 -12.258994 63.087597 0.823593 1.634818 0.878064 1.376389 2.214398 1.641931 1.186528 1.724934 1.217686 1.141179 2.299319 2.401686 1.637457 2.493100 1.288946
+1 0.004927 1 1 0.224141 1.944902 -1.871670 -1.965020 -1.673617 -0.235975 1.801764 0.431882 1.561745 0.245207 -2.143634 -1.838641 57.354872 63.337455 -37.401094 49.808211 -23.403075 0.842810 0.601708 0.657088 2.171566 1.759368 1.692902 0.606014 1.021083 2.092926 0.810525 2.493740 0.782928 2.163649 1.441342 0.391744
+1 0.013599 1 1 0.973107 -1.690591 1.950151 1.523473 -2.109898 -0.330812 0.662477 -1.120192 -1.072511 -0.799986 -0.922210 -0.536452 -42.764497 57.100132 -18.088414 38.019173 -11.765767 0.666258 1.045878 0.324573 0.344932 0.524113 1.521422 0.784505 1.667734 0.607805 1.877016 1.264479 2.349375 2.195039 0.264482 0.643952
+1 0.016299 1 1 -1.409789 -0.426752 -0.161010 -1.186335 -0.608666 0.742886 -2.150365 -1.872754 -1.336176 2.134324 0.873379 -0.217381 -44.978606 44.562109 5.362611 -20.601640 -51.765621 1.003006 2.024986 1.931583 0.363694 0.856038 2.433333 0.280148 0.693069 1.660114 0.780775 1.979309 1.492979 2.001273 1.646098 1.470386
+1 -0.036521 1 1 -0.629809 -1.171983 0.265757 -0.759026 -0.512782 0.636348 -2.029576 1.907333 -1.844098 -0.367028 -0.117304 -1.751915 -45.550898 26.053293 27.687679 46.827990 -11.975372 1.823896 1.722533 1.358385 1.122807 1.760933 1.004641 0.251141 1.433253 1.680207 0.983259 0.881608 2.439457 1.956405 1.294026 1.701839
+1 0.041607 1 1 -1.116506 -0.388783 1.808733 -0.247841 0.288581 1.127149 0.190533 -2.137736 -1.681069 1.752258 -2.233217 0.509196 11.625762 -55.819662 -61.057660 -46.097888 -17.207793 1.204239 2.400106 2.085932 0.260335 0.702014 1.249934 0.893527 0.266357 0.658561 2.190974 1.699893 1.097635 1.699771 1.303491 1.022384
+1 0.009380 1 1 -1.932162 -0.772571 -1.962714 -0.605449 -1.730127 1.911160 1.227668 -2.132432 -2.060139 1.881899 -0.474844 2.077071 -1.435184 28.861302 -28.091816 60.842223 25.246151 0.805904 1.329441 0.670308 1.608707 0.780436 0.795651 2.252012 1.559794 2.205943 1.280000 2.210832 2.457728 0.791070 1.762855 1.804468
+1 -0.020940 1 1 0.964815 0.317245 2.218300 -1.462606 -2.207003 -1.883262 1.128184 -1.269570 0.038081 -0.850601 1.342998 -0.580386 3.192912 -36.722391 56.769973 -17.071483 29.579330 1.971979 2.054017 1.620679 1.757050 0.983279 1.220095 1.133026 0.258787 1.682907 1.368474 1.942157 0.336834 1.669218 0.796562 1.815086
+1 -0.004317 1 1 2.234607 -0.699017 -0.386137 -0.842070 -1.366577 0.133101 -1.360376 0.674043 0.065532 -1.305141 0.672596 -0.696728 11.921302 -38.675885 74.406250 -4.152608 -42.875241 1.312295 0.497817 0.561486 1.887325 1.264673 1.107031 2.115513 2.429397 1.633514 1.469063 0.544172 1.148539 2.239002 1.155543 0.710513
+1 -0.006851 1 1 0.972919 -0.135796 -1.533575 1.969901 -1.118858 -2.214817 -1.268173 -0.045116 0.427917 0.891375 0.647115 -0.130557 54.418858 67.739218 -6.960652 12.317277 16.471345 0.383507 0.848079 1.417274 0.873665 1.695938 2.123203 1.179931 1.103136 1.902685 0.675017 2.015783 0.266154 1.742932 2.213130 0.580450
+1 0.042011 1 1 -0.400322 1.078451 1.681936 -1.324790 0.291315 -0.048381 2.102163 2.270700 -1.982389 -1.429227 -1.978934 0.091998 17.389981 73.417757 32.234997 -26.409284 -10.837018 0.808637 2.266181 1.198787 0.763138 0.318046 0.905407 1.919118 2.373145 1.201185 0.566195 2.290104 0.536144 1.226990 2.277709 1.460840
+1 0.000682 1 1 2.277964 2.294164 1.242808 -2.148663 -1.548129 -2.307044 -0.944524 1.424487 -2.293913 -1.741001 -1.784475 -2.023199 22.034112 -22.677434 10.371035 5.978280 -23.051266 1.785603 1.629454 0.740478 1.966609 1.793800 2.145297 1.256658 1.397728 0.860382 1.184328 0.759392 0.344808 0.683164 1.682292 2.288488
+1 -0.063217 1 1 -0.413237 0.780297 -0.121895 1.198330 -0.410621 2.350814 1.465934 1.585411 2.160573 -0.915635 1.588372 0.080791 21.850718 45.015820 -19.113896 52.745744 -2.272483 2.220750 0.399415 0.467840 0.728823 1.835519 1.322771 1.068550 1.123957 0.843161 2.006645 1.931708 2.470122 2.094028 1.327775 1.919904
+1 -0.023984 1 1 -0.455899 0.049342 -0.092099 -2.242696 1.406388 -0.175771 0.492887 -0.422255 0.023479 -1.226388 0.079167 1.670333 50.297321 -52.927208 -47.592006 71.148020 -15.231706 2.135733 0.257187 1.792948 1.330020 1.403178 2.469157 1.620217 0.735048 0.705266 1.899172 2.378906 1.272181 1.301307 0.309447 0.378761
+1 0.027176 1 1 -1.010465 0.568174 1.994764 2.055781 0.280785 2.060152 -1.662605 1.057712 1.830658 0.675061 -1.688991 0.558893 48.250978 54.194824 52.404095 -44.368865 -57.517589 2.153227 1.789446 0.977330 2.484473 0.284243 2.016092 0.960184 2.315451 1.291146 0.545039 2.225877 1.069548 2.150525 1.371020 1.986177
+1 0.067425 1 1 -1.849518 -1.932098 0.304573 1.301278 0.379629 -0.147928 1.910858 0.860082 -2.202829 2.289023 -0.329018 -2.167917 0.366499 9.749208 54.946086 -71.132807 -29.080810 0.457347 2.130955 0.954201 0.754673 2.046082 0.995019 0.534284 1.468632 2.298390 0.293902 2.364226 2.045681 1.011457 2.314806 1.700983
+1 -0.040497 1 1 -1.824413 0.605565 -1.023149 -0.557262 2.328842 -0.247288 0.154691 -1.354216 0.522031 -0.692759 1.105743 -1.440937 -27.354744 -1.189586 -43.368328 -41.483587 -14.654720 1.346800 2.165678 1.806779 2.042927 1.982217 0.863873 1.368639 2.458354 2.309018 1.159025 0.736427 1.380888 1.339906 1.049011 1.227124
+1 0.025105 1 1 -0.226297 -0.470243 -0.706252 0.536859 -1.239701 -2.183146 -1.480241 -1.699941 0.305432 1.596823 0.743649 1.254246 50.635900 -62.424991 73.171267 -60.518566 14.463976 0.565763 1.774354 1.562841 1.675235 0.672036 1.406178 1.136907 0.253911 0.733519 2.001859 2.489010 2.285022 0.621680 1.076786 2.290693
+1 -0.019731 1 1 1.321159 -0.055823 -0.449981 0.555365 -1.230154 -1.946140 -0.083472 1.380776 -1.814855 1.024505 -0.211146 -0.299010 -65.196345 -4.971537 -6.618188 68.116067 26.731765 1.836666 0.346237 2.201956 1.780863 0.720177 0.520856 0.775914 1.285679 0.899743 1.224449 2.321948 2.473400 0.929642 1.998492 2.150580
+1 -0.004621 1 1 0.891120 1.080730 2.282049 0.262634 -1.423662 2.025291 1.475704 0.855837 1.839453 -2.290252 -1.471335 1.885722 -70.077436 8.541042 -0.700832 71.118018 -69.465503 0.524395 1.762047 1.728343 2.262619 2.094302 1.428706 1.762878 2.187770 1.855948 0.410083 2.014673 1.851408 0.605612 1.026973 2.093394
+1 0.030434 1 1 -1.018335 0.245898 0.046636 1.562625 0.890198 -0.269092 1.262009 0.115179 -0.974793 1.622066 0.898136 1.194204 29.595227 6.982641 57.240358 -61.307230 -40.608796 1.194474 0.270806 1.190036 2.188176 1.923418 0.379072 0.565882 1.530162 1.435258 1.629852 0.676371 2.272304 0.608333 1.748034 2.453508
+1 -0.066946 1 1 1.838387 -1.365734 0.161591 1.524188 0.482780 -0.657958 1.681346 -1.816511 1.474416 -1.949484 0.269885 -2.074255 7.839478 58.101807 17.077538 72.182645 -26.285170 1.002306 1.510438 0.683442 1.854805 1.458957 1.685042 1.254494 1.031765 1.630338 2.088948 1.443634 0.662860 2.436987 0.939097 1.148560
+1 -0.002896 1 1 -0.624372 0.661949 -0.577993 -2.102570 0.312967 1.005048 -2.069366 2.307526 -0.376636 -1.382255 0.521178 -0.890459 19.072567 2.638939 -47.346145 3.334810 -51.849628 2.324528 0.844336 1.511004 1.187391 0.484952 0.343063 0.608081 2.016054 0.314943 0.498277 1.538161 0.864238 0.747372 0.838911 0.330663
+1 0.034214 1 1 1.250055 1.835277 -1.801597 -2.347777 -2.255475 -1.312302 -1.879554 2.195731 0.932759 -1.245132 0.784599 1.498152 36.728282 42.233207 13.514605 39.966171 11.437713 0.379706 2.220707 1.923594 1.087598 1.763440 0.392960 2.222790 0.934131 0.932727 2.089886 1.468319 1.545192 2.045705 1.409974 1.936094
+1 -0.001928 1 1 -0.137277 1.851833 -1.565226 -2.199230 1.522447 -0.509943 1.222249 1.035467 0.237673 -1.531390 0.990737 -2.262858 58.585533 47.044966 34.742125 -39.113143 -74.600269 2.024274 1.214387 1.957604 1.208542 0.458386 1.589778 2.157204 1.122562 2.156885 0.265646 2.204150 0.401861 1.083690 1.327678 0.284684
+1 0.006925 1 1 -1.958340 2.217248 -0.286745 1.452374 -0.122945 -2.310536 1.615165 -1.996164 -2.031224 -2.242991 1.160178 -0.760475 -41.305479 -21.178830 -2.598059 -15.583550 -12.720841 0.637309 0.503906 1.649468 1.851783 2.415652 2.361931 1.717934 0.564604 0.305037 0.512056 1.372943 0.554793 1.908235 1.698543 0.920356
+1 0.060871 1 1 0.830033 1.687081 0.324117 -0.094805 -0.594279 2.216255 1.878557 -0.091762 -1.286270 2.100355 0.161888 1.799055 64.708267 51.851427 -33.070176 -60.454384 43.171669 1.918553 1.864318 1.590111 1.001072 1.013371 0.727404 0.477500 1.089213 1.909192 2.046712 0.338317 1.843394 0.929732 1.253966 1.160854
+1 0.040773 1 1 -1.248731 1.562867 0.253480 0.246584 2.150532 -0.038309 1.733130 1.436973 0.207739 -0.403312 -2.055478 0.112100 -28.097443 -33.728101 -18.193766 67.369260 -74.838849 0.377033 2.294567 1.290853 2.359408 2.070740 1.434653 0.458016 2.124459 2.041212 2.400336 1.445968 1.631287 2.297369 1.122850 2.489924
+1 0.011385 1 1 0.728742 0.470783 0.343368 -1.689927 -1.036851 0.052979 -0.218091 0.780060 0.597067 2.234291 -1.299763 1.513731 -28.892830 -51.795254 -72.826682 1.952772 -29.769694 2.286396 1.204502 2.308197 0.870690 1.190686 1.853055 1.304473 1.785058 1.476054 1.036515 0.461588 1.404158 0.927876 1.569655 1.443433
+1 -0.003805 1 1 -0.148040 0.029637 -1.399497 -1.808282 -1.603076 -2.172721 -0.613659 1.652444 -2.198251 -0.870669 -1.364024 0.622786 30.277167 68.340799 53.814660 -37.017158 52.619534 1.022507 1.278849 0.871226 1.198475 2.263586 0.333574 0.874334 1.675831 1.683116 0.389037 1.545780 0.673536 1.863337 0.847652 0.992229
+1 0.003292 1 1 -0.896822 2.038603 -0.988312 0.607440 2.203450 -1.288457 -1.669972 -0.235134 1.801303 2.104591 0.662784 -0.668444 -6.513369 29.799307 -13.039029 3.041751 -27.286292 0.614318 1.093291 0.688298 2.478033 2.304020 0.414190 1.291383 2.271068 2.335503 0.802482 2.312383 1.477451 2.016867 0.490525 1.761989
+1 -0.033135 1 1 -0.100188 -1.537058 -0.014475 1.767859 0.793736 -0.454454 0.777413 -1.467949 2.254972 2.289658 0.917175 0.741843 -26.408108 8.934739 16.156669 45.137507 -73.919255 0.461217 1.916933 1.637616 0.658132 1.720796 1.421130 0.435670 2.313816 0.802453 1.819833 0.929639 1.934816 0.709135 1.689094 1.857366
+1 -0.002552 1 1 0.396641 -1.679750 0.360268 -0.396224 -0.725007 1.040294 1.262561 -0.019264 1.383150 0.379250 -1.802620 -0.691357 35.294512 -55.137003 12.396935 5.281768 -29.331737 2.447323 1.403772 1.193751 1.623907 2.011909 0.397975 1.018129 1.936973 0.953400 0.789417 0.978888 1.671590 2.420285 1.485815 0.846751
+1 0.016996 1 1 1.675020 0.248225 1.454994 1.503668 -0.397666 -1.410961 -1.277643 1.012065 -1.946561 2.270279 0.372468 2.021015 9.332039 -56.424993 -34.861463 -16.609596 -7.477481 1.764640 0.303865 1.057532 0.434126 1.106852 1.363915 1.813622 2.296826 1.000530 0.905403 1.850301 2.261374 1.413587 1.905585 2.167786
+1 0.020339 1 1 1.153349 2.285047 -1.181396 2.291431 -2.274357 1.788624 1.080172 2.325765 -0.130049 0.813032 -1.302628 0.498942 -74.396906 11.207881 -29.138085 26.203193 -2.931271 0.386991 0.900531 0.967582 0.649407 1.334376 0.364922 1.247960 1.462072 2.288851 1.962952 1.091321 1.326628 0.640099 2.402168 0.733101
+1 -0.007162 1 1 0.176003 -1.297856 0.582666 0.528203 -0.632522 0.347314 -1.345584 -0.468230 0.155538 -1.255431 2.044829 -0.018150 40.240218 -32.650452 -56.154104 17.975848 20.078933 0.874381 2.479186 1.425340 1.447446 1.720534 1.515346 2.171675 1.348134 2.088537 1.298437 1.576328 1.091520 2.426557 1.141096 0.903832
+1 0.014971 1 1 0.718815 -1.434820 -1.722340 0.835097 1.973017 -0.582715 -1.348914 0.112277 2.078460 -0.263159 2.026456 2.206437 57.384925 -31.570587 -56.860141 1.607776 21.890895 0.929124 2.293706 0.324171 0.341648 1.579409 1.128361 0.610144 0.695394 2.493953 2.118698 1.957238 1.792687 1.444100 1.732090 2.229783
+1 0.015135 1 1 -0.580479 -1.459495 -1.755317 -2.061317 0.924385 -0.601189 -0.827228 -1.678402 -0.547955 -1.475412 -0.663251 2.251532 32.374783 72.978330 -3.213445 -8.374709 -53.731026 0.514807 0.365592 1.250798 1.907895 0.493860 1.553121 0.302520 0.948542 2.395022 2.139877 2.407849 1.714115 1.627519 1.966467 1.656573
+1 0.002805 1 1 -2.199381 -1.025286 1.231733 0.205988 -1.561593 2.307541 -0.120461 1.734879 -2.143358 -1.909201 -1.279972 -0.433063 68.439489 62.483315 7.075613 -30.169844 -64.563040 1.209774 0.929303 0.795182 1.118226 1.277553 1.574203 1.376046 0.959775 2.182070 0.543790 1.474708 0.910374 2.157421 0.278119 0.340046
+1 0.034650 1 1 0.683488 -1.429979 -0.469786 2.266011 -0.689830 -1.487790 -1.353351 0.935595 -0.701385 2.211183 1.445393 0.349249 -57.490649 54.667015 38.517444 -37.322130 26.967126 0.422240 1.580702 0.357447 1.618803 1.717206 1.832987 1.513238 0.483144 1.444639 1.790541 1.367300 2.461589 0.423142 1.005666 1.729265
+1 -0.029666 1 1 1.602564 -1.723371 -2.353939 -2.147572 -2.058180 1.816982 1.738384 0.201861 -0.245073 -0.318467 0.793167 -0.582602 17.332442 6.349700 69.404861 -62.508176 25.084315 0.506247 0.488766 1.431765 1.418001 1.845932 0.832965 1.642657 2.135991 2.343731 1.842132 2.205417 1.439376 1.098804 1.091606 1.624625
+1 -0.061002 1 1 1.414006 0.626737 1.384191 -0.974930 -0.679892 0.603213 1.845503 0.427260 -0.722595 -0.824534 1.199395 -1.370803 -6.705086 -42.381875 37.818788 70.369882 -43.395271 0.710158 0.877703 2.053811 0.400356 0.527373 2.316042 2.215835 1.048024 0.385401 1.179692 1.579192 1.985836 0.937400 1.883154 0.925504
+1 -0.041691 1 1 1.665359 -1.895044 1.030600 -1.446461 0.547498 -1.499321 -1.941383 -0.238920 -0.572455 1.439242 0.656235 2.353505 -14.039212 -7.028557 71.044806 50.053156 43.396682 2.395515 1.422848 2.307859 1.934215 1.846114 1.643660 1.000271 1.048467 1.079411 1.406311 1.114470 1.150901 1.448237 1.513695 1.415232
+1 -0.023197 1 1 -0.380889 -2.180891 -1.273978 1.338712 -1.924306 -0.687329 -1.868273 -1.410111 -1.135043 -0.919826 1.834092 1.846065 14.193732 54.058538 11.848082 -69.285187 -26.132925 1.133973 0.442432 1.196370 0.637990 0.691202 1.776535 2.229730 0.566117 0.980956 0.434170 1.852326 0.285542 1.353969 1.159867 1.379044
+1 -0.004918 1 1 0.785859 -0.888847 -0.581081 -2.150447 1.467628 1.786928 0.845057 -0.274360 2.261341 0.939896 0.896829 -1.934820 53.559331 21.671094 26.082707 72.063773 -74.170583 2.350256 1.246896 1.585326 1.566614 2.087562 0.657460 1.685099 2.213903 2.321716 0.831068 1.268007 0.897775 1.907895 0.483594 2.258427
+1 0.016121 1 1 1.689129 1.752286 -1.765456 1.893541 1.978291 -1.472659 -1.508808 -1.168479 -2.110449 -0.163471 -0.132333 0.122376 69.216327 68.811310 11.684989 39.613505 -65.821957 1.080553 0.363160 0.881108 0.784207 1.159993 1.246373 1.783583 1.434317 1.568681 0.814871 1.281574 1.660540 1.199639 1.580563 0.278649
+1 -0.037362 1 1 -0.067530 0.706054 0.854221 -1.755075 2.007420 -1.995761 0.033805 -2.046776 0.274405 -1.507422 -1.432504 -0.501005 20.486739 70.620746 -27.118057 -73.176009 -19.182439 0.636097 0.382147 0.489407 0.961000 0.268997 2.289375 1.783713 1.360443 1.966443 1.252510 1.430080 2.357286 2.410877 0.859624 1.952606
+1 -0.003953 1 1 -2.008448 -1.139871 -1.955041 1.120335 -1.230007 0.527388 -0.194801 1.087425 1.705525 -0.704570 0.517902 0.588429 -50.371706 2.730461 -9.146444 25.716030 59.318043 2.250290 1.881432 1.223070 1.629138 2.175683 1.200250 0.597860 1.229847 0.785746 2.287063 1.164285 1.381764 0.301921 2.131816 1.928490
+1 0.043266 1 1 -0.236289 1.239041 0.519646 1.633190 -0.636100 1.481445 -1.609524 -2.149490 -1.305656 1.444046 1.283916 0.746132 18.053655 -22.215767 -30.391954 -47.563910 -56.628425 1.315906 0.427652 0.292211 0.940759 2.078597 0.721141 0.966968 1.573524 1.224181 2.304274 2.429416 1.952472 0.442966 1.172374 2.340678
+1 -0.019561 1 1 -1.233698 -0.254812 0.938615 -1.783908 -1.927395 -0.764931 -0.805301 -0.712535 -1.387376 -0.723256 2.204919 -0.157572 1.406788 -56.119952 -8.036274 -65.654200 -50.143455 0.459253 0.411095 1.019422 1.179249 0.886116 1.695098 1.508057 1.162117 0.947160 1.669706 2.249957 0.771750 1.060160 1.858066 2.261237
+1 0.026025 1 1 0.550042 -1.153545 -0.857160 -0.518828 -2.023667 2.251743 -0.148064 -0.365099 -0.687674 1.755399 -1.284339 1.560707 52.440937 -25.180183 -53.332191 45.870999 -46.128017 0.271204 1.123940 0.550388 2.125297 0.370013 1.306662 0.320827 0.393054 1.551379 0.270421 1.470720 1.394808 1.286064 0.636774 0.503601
+1 0.060269 1 1 1.341760 2.171661 1.651586 2.236296 -0.583727 0.487964 1.659452 -2.220461 -1.881414 -0.804013 2.083049 1.473500 48.131907 2.965986 49.324297 -56.531965 -32.728357 1.142579 1.077586 2.237847 1.999972 2.285012 0.445393 1.470992 1.469712 2.450124 1.227863 1.188217 0.860577 2.212640 1.340974 0.991070
+1 0.036139 1 1 -1.939635 0.859798 -2.266037 0.245857 -0.641709 1.462355 -2.020802 -1.428633 -1.413304 1.744471 -1.166668 0.061909 -29.629215 21.781233 -72.820913 -51.092601 36.657382 2.134182 1.197966 0.464555 1.773571 1.912404 2.031338 0.700495 0.473061 0.732599 2.295022 2.185098 1.947452 1.579285 1.298681 1.185430
+1 0.038549 1 1 -2.354679 -0.451917 0.995139 1.033758 -0.200545 -1.203234 -1.888724 -1.128846 -0.432914 -0.052148 0.046908 1.418451 -2.175517 36.078786 -73.837935 -44.169509 -6.930339 2.451751 1.577231 0.527719 1.370870 1.707724 2.210002 2.011561 1.305639 1.131391 2.036488 1.746482 1.126484 0.564789 1.159615 1.652048
+1 0.017417 1 1 -2.020525 -1.482375 0.128811 1.941818 -1.873225 0.186132 -0.701900 -1.729683 -0.046638 -1.582504 -0.413624 -1.009231 -72.034146 -27.897413 28.178426 44.810805 -14.800924 0.488093 1.382262 1.928116 0.594189 0.291385 0.556805 1.969928 1.335284 2.123548 2.475849 1.589252 2.308004 2.128002 0.836231 0.283318
+1 -0.006691 1 1 2.076535 0.367401 1.674889 -1.955740 -1.215430 0.474251 2.084662 0.298032 -0.250416 -0.586473 1.462309 1.921957 -35.059247 -40.766414 38.885277 -5.142743 -34.074415 1.544697 0.466667 1.278543 2.473068 2.101816 1.727264 2.132070 1.700249 0.339421 2.399227 0.804308 1.497558 2.458011 1.039021 2.076063
+1 0.041006 1 1 0.357580 1.548347 1.255600 0.789026 0.492053 -0.313474 -0.110711 0.675516 1.254061 -1.506263 -0.802935 1.350017 -13.445287 -74.935191 -35.756058 -52.066718 14.662614 1.143371 0.894237 0.948404 2.328444 1.414969 0.377098 1.130341 2.389931 2.063671 1.864830 1.198609 2.268073 1.503440 2.310261 1.808783
+1 -0.039450 1 1 2.002948 -1.756378 -1.039212 -1.924230 0.600294 -0.083232 0.703931 -1.832214 1.448431 -0.418089 -0.657694 1.406577 -54.628916 1.809479 -38.080476 31.436776 57.900889 0.478645 2.335015 1.589402 0.327706 1.251780 0.408613 2.057954 0.278565 1.099510 1.720773 1.026558 1.859428 0.404793 0.862064 2.459983
+1 0.025141 1 1 -2.212308 -1.514851 0.930586 -0.058845 0.591309 -0.297643 2.079334 0.288266 0.548752 0.732760 2.022828 -2.215102 -42.745430 -72.440570 41.338674 -20.897697 72.400984 2.024955 1.416968 2.477972 1.283683 1.102559 1.203219 1.000731 2.038419 0.460182 0.273439 0.446300 0.955670 0.691969 1.175018 1.777613
+1 0.007901 1 1 -0.264853 1.822505 0.310489 1.774366 1.770973 1.300558 -2.286589 -1.170173 -2.298357 -1.027699 -1.629548 0.589328 -19.463229 31.506051 22.207539 42.102357 64.308756 0.434003 1.280554 0.263525 0.310769 2.345415 0.883089 0.323326 1.887081 1.676596 1.053776 0.320083 1.388263 1.531737 0.904442 1.453548
+1 0.000688 1 1 0.131688 -1.540139 0.034387 -1.678570 1.353003 -2.067242 0.308863 -1.987528 1.740398 1.073239 -1.095711 0.409044 -18.483564 -3.264818 28.201060 -24.786561 -37.723778 1.771893 0.697132 2.449609 1.584059 0.521369 0.395998 1.544375 1.813491 2.338827 0.415126 1.265089 1.349133 0.870054 1.741062 2.287325
+1 -0.022391 1 1 -2.211340 0.613600 2.072127 1.688758 0.244158 -0.922114 1.084574 0.920356 -2.349626 -0.336187 -0.132667 -0.779060 65.552995 -0.806378 -52.789620 14.857101 -46.703996 1.313975 1.729184 0.650676 2.406106 1.680361 1.329455 0.905727 0.548258 2.327429 2.356282 1.273705 2.156858 2.069760 0.700400 1.116544
+1 -0.024645 1 1 -1.751978 2.218827 -2.026270 0.920104 -1.876069 -0.489832 -0.069030 -0.946880 -0.470662 1.689212 -1.558887 0.662296 17.224201 -12.859703 16.971466 -60.571921 17.721717 0.608508 2.440729 0.833005 2.320898 0.582249 2.106558 0.421214 2.346978 2.411423 1.032289 1.436835 1.130451 1.992749 2.385405 2.496609
+1 -0.045048 1 1 -0.764699 -1.611229 2.181145 0.833725 -2.228282 -1.383311 1.614168 0.104486 -1.623218 -1.408875 0.794209 -1.935566 -45.817945 37.803485 -36.827308 -56.573241 23.534446 1.276397 2.407116 0.642690 0.939601 0.616482 1.468005 0.760474 0.529066 1.505287 1.863101 1.388670 1.621905 2.115901 2.199094 0.918509
+1 -0.040315 1 1 0.742859 2.108905 -2.218008 1.646820 2.249679 -1.851696 -0.842070 -1.366650 -1.106614 0.942990 1.063757 -0.243292 42.768328 7.296017 74.163035 -41.867620 -19.083753 0.765334 1.225337 1.492527 1.156721 0.257240 0.427835 1.117152 1.230031 1.631660 1.814723 0.550711 0.793037 1.068668 0.857208 1.840788
+1 -0.005096 1 1 1.656863 1.395294 1.851231 -2.261820 0.433340 -2.205012 -1.406731 -0.870202 1.764281 1.923737 0.543432 0.850122 1.440306 57.215455 -29.852849 13.172874 -3.500217 0.952704 0.352844 0.741730 0.508526 0.554468 0.947511 0.811471 0.396480 0.636549 1.236648 0.345678 1.816817 1.992994 1.991566 0.500807
+1 0.033056 1 1 -0.362485 0.833275 -0.364420 1.300821 2.125473 -1.803539 -1.993492 0.458033 -1.890560 1.001475 -0.859149 -0.960765 56.562074 -61.226433 -32.661727 54.355409 51.356883 2.202085 1.695420 2.422204 2.234927 2.424863 1.919256 2.434564 0.709806 1.714138 2.008779 1.796932 0.780943 0.305289 2.499442 2.121235
+1 0.024319 1 1 -0.864806 -1.782790 -1.976287 2.173942 2.296768 -2.117768 -0.650764 0.066243 1.228860 -0.958095 -0.469860 1.033672 -52.505908 -16.793205 56.595294 47.110272 -67.663589 0.295948 0.747413 1.519019 0.898684 1.433566 2.450785 1.093999 1.346379 1.846324 0.675617 0.840028 1.107616 0.703459 0.783307 1.791449
+1 0.027445 1 1 1.297511 -1.674076 1.471881 -2.134275 -0.048832 -0.770668 1.734374 -1.206755 0.194980 1.922056 0.572974 -2.149765 -38.870574 -47.744344 60.812362 -26.627995 63.280912 2.309371 0.350924 2.231137 1.714480 1.014477 1.310355 1.630511 0.505247 1.679057 1.907142 1.327732 1.197746 1.260626 0.588226 1.309708
+1 0.021204 1 1 0.994553 0.606284 1.636763 -1.858045 0.843088 -0.381935 -0.904898 -1.737495 0.594158 0.457284 -0.332913 -1.667946 26.454298 17.380829 69.586164 -15.336741 -64.599955 0.903437 0.312537 0.567658 2.131693 2.122354 0.401000 2.361144 2.005230 0.656065 0.737553 2.308489 1.272494 2.056618 0.322847 0.596450
+1 0.004711 1 1 -2.264144 -0.922130 0.800075 -2.295839 -1.121838 -0.463975 0.967820 -1.020162 -2.191965 1.094208 -2.094211 -0.574685 53.042140 29.247552 13.610301 -1.677380 8.282517 1.438956 0.775171 2.292158 1.294516 0.930134 1.260966 1.803123 1.333757 1.198739 2.204765 1.727216 1.315085 2.384967 1.894344 2.235268
+1 0.004073 1 1 2.106332 1.658753 0.162506 -1.946661 0.584159 2.047259 -1.579817 2.334905 -2.020327 1.844946 0.487757 -1.823580 15.013692 35.118501 -13.361360 -14.379659 -28.930559 2.336479 1.455802 0.421588 1.883562 1.027629 1.857678 0.251191 2.260081 2.187142 0.290930 1.912770 1.433404 1.978083 1.143073 0.383150
+1 0.030104 1 1 -0.791732 1.138661 0.472380 -1.089123 -1.976747 -0.837598 -1.602419 -0.548646 1.052866 0.491471 -0.672276 1.365447 -8.774448 -22.143885 -22.281507 64.718801 -71.112579 1.538344 1.704341 1.608225 1.688385 1.194214 0.395944 0.631842 0.869122 1.836174 1.071031 2.320317 2.060144 1.097176 0.731954 0.444469
+1 0.083185 1 1 -0.117934 1.804491 -0.846878 -2.060237 0.227312 -1.322082 -1.323246 -2.028384 -1.621832 -1.664675 -0.739856 1.227647 70.862013 -22.145834 -55.034862 -70.924578 20.614035 0.776313 1.241012 1.695303 0.462603 0.461612 1.814068 0.785299 1.526208 2.473417 1.221429 1.056078 0.756004 1.917539 0.579368 0.940830
+1 0.006725 1 1 2.336875 -1.902314 1.359998 -2.318630 2.239518 1.722846 -1.756394 -1.305455 0.096006 1.944169 -0.061095 0.483925 -8.276085 -46.157670 28.033138 2.951899 -37.429634 1.677197 2.151865 1.391417 0.550403 2.379541 0.690830 2.273356 0.299688 0.603145 2.300026 0.788301 2.480480 0.678200 1.502136 0.643512
+1 0.005967 1 1 -1.476140 1.243547 0.846164 -0.517909 -0.720647 -1.070462 0.644263 -0.941284 -0.669095 -1.715953 -0.207190 0.211630 -31.513539 1.952661 -31.621021 -4.504064 50.194474 1.652867 0.479340 0.518753 1.426996 2.272742 1.221586 1.451986 1.525269 2.442445 0.431368 2.007385 0.874409 0.684722 0.865184 0.894125
+1 -0.039129 1 1 0.984178 0.595229 -0.386391 -0.406832 0.045413 -0.151648 0.651346 0.287358 -0.569495 -0.637073 -0.736147 2.306111 -18.757905 35.884517 -38.918970 38.879491 47.604445 1.193632 1.868469 1.604653 2.395709 2.435012 1.494099 0.577796 1.518152 2.085257 2.411438 1.294263 1.184102 1.446302 0.503278 2.336334
+1 0.019548 1 1 -0.138191 0.633897 -0.798657 -2.136360 -2.114930 -0.085479 0.635493 -2.247412 2.250735 1.750811 1.724104 0.538901 2.996149 -43.719503 56.310124 54.258955 -69.739330 1.241240 1.021019 1.007469 0.538727 1.891493 1.564168 1.476766 1.749132 0.668071 2.272541 2.342497 1.341190 2.388174 1.787437 0.947245
+1 0.030581 1 1 0.516634 -1.868884 -2.254007 -0.208008 0.594509 1.650633 0.355168 -1.289810 -0.838867 0.629570 1.877484 0.716988 26.466864 -71.417553 -14.816783 -25.672518 71.995118 0.954318 0.473132 1.937289 1.762137 0.995528 2.336309 0.841838 2.279355 2.122070 2.380316 2.463546 1.819204 1.609074 2.460097 2.342595
+1 -0.007142 1 1 2.094088 -1.497689 1.915738 -1.949247 -0.472644 1.354082 1.928047 2.297505 0.844862 1.168833 -1.379529 -0.789410 -71.202154 5.393974 56.530157 2.340522 37.147811 2.023943 2.405157 1.470162 1.008277 0.617353 0.349316 2.208492 1.367251 1.631767 1.353003 0.678959 0.764428 1.736574 1.107545 1.755848
+1 0.010636 1 1 0.529434 1.198626 -0.152497 0.516675 -1.170728 -2.205331 -2.051735 1.758457 -1.724360 -0.128336 1.323611 -1.267269 32.184223 20.240196 -23.028544 -40.744649 -45.317267 2.165366 1.054603 0.710411 0.634459 2.108129 2.068393 2.490139 1.016895 1.453060 1.579499 0.395757 1.985354 1.844275 2.228156 1.112606
+1 0.019171 1 1 1.148927 -1.356000 -1.173273 2.154127 -0.866145 -0.729846 -0.170068 2.089964 -0.125000 0.854485 -2.039802 -0.320123 39.334784 49.719202 -19.377949 -35.185987 -70.886162 2.369202 2.421460 0.976333 1.477856 2.079090 2.263428 2.179830 1.152859 0.601095 1.607672 1.389285 0.717018 1.414442 0.532019 1.640426
+1 -0.001518 1 1 -1.308197 1.136958 0.120241 -0.717624 -2.109724 -2.109694 -1.619879 -1.839645 -0.924103 0.642305 -0.857742 -0.872098 -57.827541 -57.481832 52.853056 1.305704 44.969376 0.629425 0.743639 1.086089 1.140032 1.023635 2.227317 0.516442 0.838772 2.485224 1.655484 1.719368 2.166654 2.452599 2.323162 0.390626
+1 -0.061750 1 1 -0.500934 1.849099 -0.400797 -2.192325 -0.233866 -0.461630 -2.018962 1.220779 -0.101134 1.405804 -0.563413 -2.095628 -26.221870 -10.975009 43.030219 58.884438 -29.250086 0.532014 1.562435 1.588535 1.514701 0.332692 1.804779 2.165163 2.147919 0.330260 1.421900 2.117417 0.680183 1.083376 0.556976 0.352224
+1 -0.044746 1 1 -0.919577 1.306984 2.033318 -0.272410 2.054654 0.178392 1.156997 2.336747 0.658849 -0.843726 -0.918289 -0.604621 -62.188759 -6.464650 -51.366809 -71.954550 -40.123593 2.016493 0.947532 1.166334 2.082870 0.543068 0.600930 1.077757 0.614243 2.089982 0.825558 0.908441 1.165881 1.218366 1.331504 1.581511
+1 -0.020635 1 1 -0.165985 0.019266 -1.345384 -1.817966 0.576692 -0.921528 1.500210 -1.970783 0.429020 0.576129 -0.965736 -1.654343 -45.999022 -5.561987 -30.316665 17.815603 26.842134 0.411117 1.391208 1.533221 1.100243 0.525627 2.216095 0.904044 1.516370 1.378932 2.216244 1.156753 0.788725 0.593259 0.396780 1.181165
+1 -0.041035 1 1 -0.401909 -2.035150 -2.254079 -1.409072 2.198565 1.448365 -1.530712 -1.750934 0.928929 0.370523 2.309282 0.873663 -4.860517 59.284117 -61.852698 -58.291742 -59.307597 0.883203 2.236016 0.472895 2.439090 0.288842 0.571618 1.183289 1.289016 0.742030 1.041819 1.853894 1.903419 1.769651 1.279013 1.363721
+1 -0.023721 1 1 -2.047882 0.537759 -0.241723 -0.552846 1.142284 0.102494 -2.116162 -1.928392 1.321188 0.423186 1.495257 -0.378043 -46.970002 25.184365 -26.370187 46.272772 -43.527229 1.193033 0.804683 1.063444 0.801696 0.350736 1.326513 0.956102 1.204726 1.585117 0.310332 1.757518 2.111570 1.412809 2.329829 2.190348
+1 0.058863 1 1 -2.037830 -0.170984 0.835110 2.199835 -0.783477 -1.477413 -1.309398 -0.190508 -2.152846 -1.157283 2.291301 0.261359 22.625918 23.806343 63.211009 -62.577316 63.046921 1.819081 1.800596 1.621250 2.353061 1.142428 0.789606 1.907566 1.711360 0.332994 2.372233 1.627035 0.571059 0.796265 1.333424 2.351437
+1 0.036630 1 1 -1.293353 0.869094 -1.536074 -2.333349 -0.096711 0.352202 0.699283 0.144155 0.645923 -1.308581 -0.605326 0.334871 50.678510 53.717145 -25.946928 -40.017762 21.472967 1.317268 0.824043 2.444855 0.435277 2.449469 1.482332 0.810254 2.441745 2.162859 1.668239 2.340325 0.846011 0.403479 1.270384 0.338485
+1 0.018333 1 1 -1.067234 -1.647480 0.802824 1.489597 -1.261548 -1.805259 2.089119 -0.190555 1.761146 1.057362 0.670170 0.930255 -29.147407 19.536499 -0.066763 -72.085931 1.757889 1.297506 1.681406 0.888600 0.692982 2.454069 2.280286 2.020549 1.617161 1.119740 1.962716 1.625330 1.164216 2.470992 0.959103 2.150652
+1 0.040447 1 1 0.060437 -2.116630 -0.369056 -1.213730 0.778297 -0.762141 -1.026722 0.645763 0.710507 0.289770 2.267592 2.331091 -5.239830 -15.821925 30.903994 -46.578845 -0.643151 1.233291 2.430877 1.741620 0.410226 2.162923 0.488904 1.505703 2.104199 1.273489 0.777188 2.447832 0.969901 1.380936 2.144564 2.442277
+1 0.024450 1 1 -2.131634 1.915388 1.598892 -2.181830 1.789300 -1.703654 -0.833296 0.016854 0.527042 -1.298714 0.301026 -1.769093 64.714578 7.908905 24.958288 73.948278 -51.295597 2.498518 2.338643 1.825727 0.992637 1.004137 0.785015 1.253040 1.345455 2.069614 0.502333 2.208142 2.236843 0.879459 2.310428 2.368475
+1 -0.000522 1 1 1.491963 0.808195 2.222155 2.074744 -1.460527 -0.237201 0.046147 -1.945738 1.960019 -2.278065 0.722884 0.976514 -31.423521 14.888843 36.780073 12.683562 22.619446 2.350326 2.437604 2.310183 0.488136 2.097958 2.131344 0.745187 2.355336 1.139173 2.325901 1.412542 2.345596 1.674449 0.966834 1.576609
+1 0.004570 1 1 1.143119 -0.001566 1.961529 -0.449246 -1.233414 -0.197431 -0.707881 1.423882 1.667741 0.432238 -1.876858 0.386255 -59.916362 -64.291378 54.815613 -13.988731 -58.595736 0.347007 1.651541 0.704734 1.964532 0.636313 1.758225 0.485489 0.368655 0.984195 0.858361 0.968606 2.110327 0.762171 2.056428 1.636509
+1 -0.014849 1 1 1.325351 -0.284983 -1.930311 2.053133 -1.825685 -1.917506 0.511299 -2.002237 -0.432854 0.953667 1.453831 0.798050 43.784155 -19.706408 -5.598504 -44.053498 -7.146575 1.937806 1.452712 2.482198 0.298293 1.903292 1.873849 2.024411 1.268903 2.449897 1.912590 0.647644 0.949863 2.089154 0.406791 0.686807
+1 -0.008016 1 1 -2.232367 0.647370 -0.551300 -1.142709 2.190846 -1.054647 -2.159704 1.392634 -0.442483 -0.666373 1.626027 1.489213 54.282906 32.800581 29.370466 -20.578054 44.653286 1.941762 0.436459 2.064890 2.107883 2.431310 2.280140 1.809839 1.709462 2.172474 1.263451 0.813105 0.854304 0.293835 1.236595 1.699628
+1 0.000547 1 1 -1.903481 0.598506 -1.863730 -0.465507 -1.204249 -0.110929 1.721133 -2.280102 -0.527703 -0.394918 -2.345806 -2.119908 34.589817 -48.938130 -53.155882 9.097580 53.025868 2.211514 0.415961 1.814606 0.823940 0.708699 1.098698 1.559524 2.174305 0.539718 0.544866 1.555704 0.972921 0.381609 0.448459 1.257745
+1 0.002913 1 1 1.985624 -0.757073 -0.675802 -1.346884 1.230978 1.663282 0.885125 -0.724422 1.447558 -0.964498 0.297591 1.760232 -5.169917 -40.800585 64.572214 15.195293 -62.706666 1.210935 2.433732 2.490254 0.693796 0.378612 1.832357 2.174800 2.109000 0.964444 1.906697 0.598803 1.332400 0.903302 0.290934 1.974650
+1 -0.004460 1 1 0.416172 1.413980 0.184867 1.599831 -0.538399 -1.090956 0.206093 0.196113 2.116431 1.736458 0.823679 -1.418744 -4.392565 -25.838148 -11.753641 6.550354 -8.207538 2.213534 0.618424 0.355773 0.472260 0.767448 0.753589 1.812342 1.025230 2.038826 0.552992 0.878902 1.958641 0.628889 0.738738 1.963002
+1 0.002122 1 1 1.509405 1.783014 1.025528 -1.866865 -1.310785 0.051646 0.941106 -2.312873 0.036823 1.560962 1.212612 -0.716865 39.139633 69.811110 15.331413 -24.934101 32.564298 0.747470 2.475716 1.610791 2.067053 2.457574 0.444292 0.972056 1.591972 0.768323 1.952502 0.950889 1.343287 1.620483 0.703099 1.483903
+1 -0.025852 1 1 2.115028 1.731842 -1.357136 -1.420792 -1.582098 1.686773 -0.130951 -0.201174 -2.351545 0.391222 1.486636 0.805879 31.766697 52.874900 68.450860 -46.389704 28.246079 1.102644 0.391655 0.541196 0.635204 1.123203 1.678689 2.471512 0.700340 2.364309 1.188984 0.256383 1.774600 1.193356 1.742145 2.487325
+1 0.046517 1 1 -0.270597 -0.469518 2.055857 1.550853 0.961271 2.015322 -1.135467 1.384653 2.076994 -1.333448 0.861686 1.187527 57.083451 1.560473 -23.128130 -64.473978 -14.152652 1.920680 1.619835 1.069987 0.514729 1.306814 0.613984 2.235582 2.172911 1.869502 0.969407 2.080267 1.804731 1.359642 2.002613 1.658078
+1 0.061981 1 1 0.496959 2.039200 -0.373041 -2.217504 0.701403 -1.916320 1.592290 -0.045060 1.371662 0.516555 1.516973 1.746038 51.544579 59.732061 -33.258005 -67.296732 -56.169312 2.310664 1.826066 2.194750 2.161209 0.943844 2.190206 2.300988 1.196711 1.877681 1.176963 0.724319 0.375504 1.353540 0.690587 0.444243
+1 0.053016 1 1 0.809590 2.117788 0.984388 -0.580688 -0.259311 0.718203 -2.299001 2.287617 -0.397548 0.575776 -2.177193 -0.387037 -58.367465 18.012061 28.717278 -48.704477 -26.153014 0.569319 0.788204 0.841034 2.254068 2.377157 1.125164 0.888373 1.378484 1.435737 0.674499 2.303426 1.676935 2.242436 0.363697 0.911543
+1 -0.074128 1 1 1.103442 2.301350 -0.501009 0.581539 0.436874 0.638320 -1.866163 1.059611 0.769477 1.803162 0.363252 -2.072750 63.044913 -4.141097 0.584389 71.827911 11.700211 1.306663 0.337873 1.132356 0.259770 2.460409 0.837763 1.287916 2.499239 0.954127 1.761173 0.533075 1.387797 0.449424 1.713349 2.249111
+1 0.036376 1 1 -1.551726 -1.505024 1.158182 -1.321426 0.276635 -1.722745 -1.261134 0.452768 -0.837824 -0.686844 1.561497 0.785629 -1.423195 -69.632777 -18.083605 -31.146955 13.125291 0.576404 0.626217 0.821596 1.815833 1.208325 1.316547 2.209475 2.149331 1.550662 1.727875 1.151691 1.218171 0.292310 0.346634 2.133430
+1 -0.013158 1 1 1.471432 -0.251898 -1.926436 1.219722 0.968473 0.539556 1.673170 2.141992 -2.191561 -1.537477 -2.352459 -0.837188 18.211987 -61.133606 27.489766 20.501702 22.112513 0.550185 0.965303 0.599377 1.973051 2.071110 0.894301 2.024880 2.410630 1.210109 2.044831 2.466819 0.576474 1.803647 1.142596 1.352926
+1 -0.017880 1 1 0.406554 -0.006571 -2.056170 -2.095356 -0.969323 -0.676107 -1.757252 -1.590674 -1.066383 -1.486735 2.247792 -0.583392 44.720241 -36.903349 15.414312 18.343156 43.414914 2.491903 1.408136 0.285557 1.613443 1.630810 1.028995 2.318150 1.652360 0.962077 0.370632 0.467070 1.289135 0.491182 1.541347 0.416185
+1 -0.021521 1 1 -1.978124 -0.427193 1.846798 -1.367396 0.503809 -0.639873 -0.680321 -1.901621 -1.122179 -1.483615 -1.873907 -1.864507 19.702042 -67.776056 -12.171680 30.569400 29.897789 1.257074 1.646909 1.590852 2.191007 2.262247 0.330980 2.275691 1.285408 0.846269 2.493739 0.767132 2.187508 1.940901 1.721116 2.290092
+1 0.020345 1 1 -1.712366 -1.179710 2.353870 0.985861 0.603047 -0.931260 -1.835013 1.517166 0.266702 0.985901 1.281619 -0.159540 -1.061828 3.859472 66.149574 -24.107403 -23.120741 2.270658 2.201857 2.365725 2.490372 0.432506 0.873846 2.478247 1.393260 2.261904 1.314787 1.870094 1.919102 2.096485 2.123259 2.106957
+1 -0.001362 1 1 -0.720747 1.965174 -0.458437 -0.189037 -0.997067 -0.442108 0.921676 0.982428 -0.544648 2.267709 -0.417649 2.033499 -61.696481 17.250094 -27.675614 5.950499 -39.972065 1.967647 1.243326 2.331408 1.715424 1.132174 1.703530 1.480681 2.303617 0.388824 2.462809 0.687590 1.829796 1.877382 0.655187 1.732748
+1 0.009363 1 1 0.352158 -0.041360 2.303082 0.334527 0.520065 -0.754528 -0.317228 -1.942098 1.870207 0.926448 1.086105 -1.628446 8.213623 46.357456 29.755154 -5.131449 5.738910 1.432988 1.721559 0.747274 1.429778 1.773226 0.608704 1.230892 0.345683 1.892519 0.825134 0.522946 2.158871 2.144889 1.154638 1.255173
+1 -0.000116 1 1 -1.447546 1.158824 0.044556 -0.419827 -1.592735 1.991351 1.251004 -1.051895 1.678730 1.346236 2.008990 0.833047 16.143267 -30.112835 -6.422914 50.083276 -50.385537 2.429292 2.107226 0.389591 1.849036 1.247297 1.571264 1.490696 1.870328 1.348466 0.912049 1.059458 1.317404 0.854381 1.584036 2.385584
+1 -0.064368 1 1 -0.626079 0.246781 0.745031 0.924131 -0.172516 -1.364878 0.403659 -1.550860 -1.073094 -1.179220 1.157441 0.372126 31.347641 59.807026 26.680224 64.526621 -1.088826 1.376657 2.220749 0.383619 0.491699 1.228382 0.914891 1.565295 2.404172 0.676160 0.974446 1.266674 0.987771 2.467054 2.281935 0.481966
+1 0.016494 1 1 -1.214193 -2.293876 -1.118194 -0.471469 2.251295 1.751462 -1.464821 -1.729825 2.272734 -0.778493 2.171919 1.281886 -12.364070 -52.918148 -45.310035 24.237705 -36.894830 1.503849 2.434592 1.182687 2.424604 2.065754 0.875878 0.626578 2.397766 1.005721 0.395725 1.457444 1.008736 1.571259 1.399919 1.696408
+1 -0.008109 1 1 -0.753545 2.065665 1.457621 -1.466302 1.650236 -1.606299 0.201525 -1.179518 0.856130 2.061360 -0.213617 0.583532 30.196896 69.226571 -59.028132 14.179669 -32.311510 0.481825 1.790128 1.183679 1.090286 1.933346 0.750304 0.601049 0.837827 2.358986 1.721697 0.814891 1.616327 0.610584 1.328283 1.443331
+1 0.044776 1 1 -0.056740 -1.724714 -1.355616 0.565950 2.327627 -1.833990 -0.135013 2.212553 0.909150 -2.190162 -1.578114 -2.041831 -45.742868 -50.377609 53.526535 70.466169 74.894015 0.530588 2.334372 2.045498 2.442010 2.115061 1.582855 0.551173 1.813858 1.767360 1.020628 1.203400 1.789767 1.865204 0.734929 0.944879
+1 -0.023412 1 1 0.627803 0.452812 -0.091576 1.837136 1.175502 2.325493 0.013166 -0.207545 -1.035750 -0.277867 -0.136765 1.042027 67.236493 -56.262729 -7.689135 68.700988 -42.488327 2.105327 2.231765 1.022137 1.800499 2.244817 2.143387 0.650199 1.141765 0.900507 0.567533 2.279597 1.690530 1.234104 0.334236 0.753783
+1 0.022456 1 1 -0.728777 -1.055160 -1.362437 -0.978841 -0.430305 1.375455 -1.706012 1.943965 1.233984 0.350217 0.315175 0.416379 6.030518 -45.091119 -46.437014 -16.893864 14.835184 1.899125 1.595537 2.194584 1.619989 1.412467 1.091283 0.691988 1.490859 2.366591 1.293903 1.875101 0.567438 0.675053 0.359165 1.231059
+1 -0.076982 1 1 2.050202 0.756452 -0.333026 1.157137 -0.032377 -2.239707 -0.185165 -1.885356 -1.079648 1.773135 -0.077103 0.029243 44.511635 57.051881 70.965508 67.294474 18.223552 1.123502 2.204568 0.671768 1.409107 0.866151 1.407751 0.574465 1.783405 0.695750 1.713323 1.811044 1.715510 0.329221 1.968447 1.182222
+1 -0.018201 1 1 -1.478733 0.080822 1.206076 -2.186536 -1.904001 1.288117 0.671318 1.375382 1.781304 0.574033 1.507362 0.437716 20.633555 -11.840074 53.877998 -22.486151 -74.743915 1.810262 2.073385 0.878455 1.199758 1.335544 1.990944 1.296993 2.060828 1.343022 1.676099 1.694733 2.122772 0.684431 0.483860 2.229700
+1 -0.000335 1 1 -1.083866 1.552459 -0.323402 -2.025128 1.260379 1.000321 -1.405736 1.712216 -1.341764 -2.238415 -2.044583 -0.566382 -4.930198 -61.837344 49.758914 48.066170 -51.883345 0.574275 0.843598 0.359245 0.329846 1.224138 1.590215 0.500471 2.411888 2.101554 1.821551 0.551915 0.785015 1.253357 2.172736 1.171630
+1 -0.022897 1 1 2.028182 -1.768113 -0.349094 -0.291190 2.139233 -1.441083 1.390477 1.008240 -0.266180 -1.629854 0.159561 0.389222 27.358197 59.213505 -48.624158 -26.218191 50.867787 0.398522 1.206994 1.454423 1.983938 0.552132 2.181045 1.322146 1.807259 1.100675 1.053528 0.651814 1.283062 1.926373 0.554730 0.852273
+1 -0.028490 1 1 1.950170 1.842677 0.055710 -1.442636 -1.142878 -0.646881 -0.640113 0.006555 1.783288 0.926239 2.270984 -1.926669 64.216623 38.779763 21.476725 59.318221 61.334543 2.119891 1.757486 1.564642 0.440445 1.552000 1.707842 1.941704 1.714706 0.306963 1.378658 2.096330 1.768874 1.711428 1.461734 1.113768
+1 -0.015429 1 1 0.973165 -0.717267 -0.812407 -2.340412 -0.999510 0.895175 -1.449208 1.492670 -1.455426 0.667671 1.340758 -0.520773 -55.143210 58.067519 40.796925 23.920742 35.904579 1.348897 1.412251 1.950061 0.420285 2.486905 0.663388 2.320313 2.004182 1.036222 2.276097 1.366701 1.393876 1.382849 0.536682 1.267286
+1 0.023718 1 1 -2.255575 1.721896 1.117649 0.739717 1.135613 1.075230 -0.628436 -1.664669 -0.642565 1.212026 -1.134492 -1.077209 10.960982 21.225452 36.168671 -63.144008 -11.344718 1.064987 1.989183 0.957488 2.008879 1.238061 1.597743 1.008915 2.328598 1.748662 1.769600 0.409640 1.317370 0.280264 0.399395 2.384865
+1 0.024235 1 1 1.029010 0.106484 -1.039253 2.104240 -0.515333 0.175503 -0.276464 -0.115257 -0.338277 -2.281194 -0.032405 2.007172 -46.388265 52.430734 -46.661020 -31.769970 42.118246 1.845384 0.624148 2.052501 0.878584 1.117167 1.483095 2.373156 1.373915 1.138064 1.688467 0.309218 1.033112 1.761691 2.497281 1.802818
+1 -0.028380 1 1 1.479373 1.260487 -1.896790 -0.039462 1.212507 2.237264 1.547638 -1.238053 1.959506 -1.467927 -2.088312 -0.395538 43.904277 49.191633 -36.231305 60.465255 -10.465470 2.227757 1.162678 1.375847 2.116714 2.355482 1.335795 1.715581 1.520228 0.974624 2.005647 0.900210 2.323456 0.833143 2.383989 1.207072
+1 0.013351 1 1 -0.687570 -1.203451 -0.833481 1.610890 1.549333 -1.021636 1.309692 0.420011 -0.026822 1.584945 -0.957332 -1.775241 -74.356235 -55.247202 -39.720786 62.756789 -46.654248 0.355763 0.310835 1.201914 1.577114 0.809383 1.301383 1.591389 2.222499 0.534968 1.710798 2.136891 1.720763 0.860766 0.895808 0.350549
+1 0.025643 1 1 -0.557130 -0.161546 -0.771965 -1.214487 2.194910 1.278462 -1.385208 -1.985407 -0.303075 0.318057 1.742001 -0.263694 -71.845935 -14.628833 -16.802749 46.200117 -64.627492 0.711134 1.532943 0.922658 1.618672 1.772080 1.594360 0.404778 0.596779 1.072232 2.251138 0.375672 1.923815 0.306002 0.977925 1.237700
+1 -0.025277 1 1 1.637975 -0.330279 0.202634 -1.391313 -0.928743 -1.946192 -0.947960 0.222687 1.065582 2.159756 -0.512950 -2.199646 -24.066955 56.683954 37.218891 37.893939 -16.572689 1.567203 0.733883 1.368847 1.464231 0.331981 1.102340 2.023573 0.694258 1.390136 1.514156 2.429098 1.095255 2.208910 1.656686 1.676850
+1 -0.042178 1 1 0.392994 -1.722636 0.581842 0.805308 0.828267 0.282694 1.145020 -1.054559 -0.673735 0.398424 0.000654 1.560068 10.472428 60.089574 -24.522309 53.546683 -40.906400 0.417137 1.329759 1.503117 1.392169 1.940927 2.159042 0.519912 0.659766 2.186985 2.159427 2.488805 1.100094 0.271651 1.884618 0.781656
+1 -0.015967 1 1 1.601225 -0.670427 -0.547720 -2.231551 0.232442 0.076846 0.349346 -0.184506 -0.238194 2.201602 0.654251 1.990714 -1.047812 -60.576987 -67.426441 13.803749 -50.395016 2.289389 2.004780 2.092576 1.672176 1.013461 2.239852 1.937943 1.506629 1.911849 1.698534 0.755815 0.977239 0.955983 1.454218 0.796667
+1 0.015670 1 1 0.123684 0.593564 -0.092008 -0.707197 -1.212420 -0.779030 -2.147971 0.667073 0.715086 1.862825 -0.610622 0.853019 50.901761 55.896923 9.593195 -17.168974 41.055749 1.734588 1.467348 0.968226 2.469161 1.689386 2.266020 0.745103 0.949038 1.725750 1.433470 0.831625 1.615815 1.000396 0.899119 1.992513
+1 0.021076 1 1 -1.966678 -1.265308 0.972697 0.849483 -1.278136 2.145907 2.344597 0.652774 0.723038 -1.151705 1.791883 -0.692841 -8.603385 2.902211 27.459591 -36.652895 24.787495 2.176452 0.627260 0.350981 0.930649 0.924898 1.002277 1.026322 2.400481 1.626390 0.987746 2.052038 2.096105 2.492940 0.845547 1.601172
+1 -0.005563 1 1 1.494193 0.573103 0.017282 -1.704855 -2.171347 -1.084475 0.753115 0.121311 -1.588850 1.309521 2.255912 -0.772551 -51.774512 -24.231195 -3.694876 0.226994 65.083243 2.186052 2.217629 1.940303 0.668442 1.749658 0.501704 0.638440 1.514165 0.318405 2.435000 1.294744 0.264372 1.050484 1.234434 1.381175
+1 0.018972 1 1 -1.337350 1.261267 1.790992 -1.537432 -1.591164 0.119534 1.538472 0.228390 -2.051870 -0.507985 1.142211 -1.136151 -21.851734 -62.094523 -72.647390 15.320162 -64.045401 1.209267 1.409539 1.370738 1.742399 2.255228 1.624666 1.257947 0.569936 2.168165 0.844461 1.358592 2.353449 0.923183 1.437495 0.985600
+1 -0.066994 1 1 1.960286 2.222363 0.864897 -1.403025 0.148478 -2.100918 -0.193814 -1.173878 1.398340 1.209656 1.449477 -1.695779 -13.791587 -45.204089 4.876803 64.434148 -55.275451 0.407341 0.928360 0.688490 1.200065 1.997367 1.252581 0.370207 2.315463 1.478703 0.565248 2.118522 1.255297 1.034178 1.673181 2.148643
+1 0.002114 1 1 0.198125 -1.770497 1.995370 -1.882379 1.828312 -1.049108 1.394943 0.676323 0.673427 -0.874734 0.996779 0.317494 54.063566 -53.654131 35.021390 4.508420 23.013384 0.414188 1.253417 0.931257 2.144085 1.140692 0.858515 1.306438 1.053434 1.317784 0.495124 0.303780 1.873304 1.878107 1.586829 2.090001
+1 -0.008116 1 1 1.040740 -0.676501 1.040361 -2.329054 1.403142 1.807906 -0.003118 -0.560540 -0.923615 -0.593107 -1.638493 1.042018 62.643979 7.363188 3.107801 32.803576 -70.303240 0.826569 2.145053 1.654899 0.883535 1.077947 1.558101 0.747292 1.734789 0.346790 2.498222 1.858496 0.483651 0.974669 0.509678 1.908408
+1 0.004989 1 1 1.071404 1.053567 -1.853030 0.306764 0.431318 1.513554 0.831909 0.241675 -0.247432 -2.266024 0.463528 0.941775 -16.060056 -71.362328 13.360480 -0.419223 4.126959 2.301965 1.871181 2.184873 0.417557 1.622399 1.412925 2.025202 1.077965 1.851683 0.742801 0.501635 1.730539 0.912831 0.705493 1.221295
+1 0.020988 1 1 0.569320 -2.308272 1.964672 0.537176 -0.627374 2.056595 -0.189059 -1.363257 -0.624471 -0.987992 1.278555 0.181530 65.319260 -29.193338 -2.437782 -21.798513 -67.614476 1.427579 0.822651 1.551845 1.368055 1.647034 1.446663 2.070396 2.402770 1.852038 2.208384 1.812576 0.464737 0.327364 2.253689 0.499920
+1 -0.018955 1 1 -1.339938 0.166477 -1.182613 0.681679 1.153461 -0.550768 -1.625603 0.924857 -2.104652 -1.686414 1.463377 1.025910 -4.961038 19.837873 -34.874232 68.787837 67.179629 1.945285 1.158716 2.296605 1.792815 1.338652 2.473530 0.866651 0.799548 0.257419 1.195510 1.944429 0.268952 1.532227 2.390590 1.895857
+1 0.017234 1 1 0.405984 -0.172043 1.875545 1.114976 -1.769272 -0.973204 0.061266 -2.310199 -2.145150 0.952874 2.258111 -1.505682 -14.901451 51.319806 31.971794 49.941326 -36.141114 0.269376 1.897612 0.911254 1.191458 1.337419 1.999390 1.500563 1.218034 0.253237 0.661283 0.677583 2.392707 1.479472 2.230195 1.639027
+1 0.038648 1 1 1.226320 -1.226753 -1.339598 1.175643 -0.021945 -1.263294 1.845551 1.231190 0.505953 -2.309816 -0.423667 -0.144445 -25.853549 29.399761 21.783532 -34.171954 21.966587 2.011300 1.413379 0.664694 1.756803 1.329995 0.976874 1.572952 0.609416 1.947700 1.240652 2.387553 0.346900 2.091337 1.106256 0.353732
+1 -0.052987 1 1 -2.212229 -0.175522 -0.036507 -0.967038 0.023658 1.786301 -0.263423 2.292152 0.417715 -0.921393 -0.934120 1.922112 48.087317 3.541040 -35.732255 47.993799 -68.220871 1.552191 0.426140 1.891526 2.129357 1.109674 1.543080 0.295998 1.591358 1.699097 1.215195 2.032567 1.106680 0.729418 0.582002 2.454771
+1 0.005419 1 1 1.682518 -0.967795 1.428876 0.786581 1.818899 0.966829 1.170920 0.716701 0.723131 0.414959 -0.122748 0.996463 -8.760289 65.823916 52.550996 24.584931 -51.066328 1.798505 2.471195 2.116667 1.578805 2.223007 2.326814 1.019111 0.453134 1.074434 1.013063 2.307252 0.726772 1.113035 1.786155 1.913499
+1 0.013202 1 1 1.784859 -0.939271 0.169091 0.336197 0.309253 -0.149612 1.890906 0.104650 1.137870 1.307861 -2.068822 2.032861 47.066385 -55.273847 -37.548374 -25.518989 -47.652111 0.789620 2.143936 0.882753 1.436033 1.158855 2.379947 0.771665 1.876003 2.235886 0.541662 1.712921 1.818731 0.403901 1.605921 1.206909
+1 -0.014481 1 1 0.757835 -0.661518 -1.606769 1.726120 1.428683 2.246960 -0.424233 -0.234312 1.481785 -0.621269 0.981306 -0.556167 59.801615 -64.263752 69.120839 -36.053796 43.847476 1.292967 1.890565 1.723959 0.571638 1.513464 2.039453 2.091560 0.344260 0.471723 0.744093 1.964398 0.634255 0.930842 1.915014 0.896569
+1 -0.004596 1 1 1.856187 0.925690 -2.235265 -0.941359 -1.938720 2.108825 1.144245 0.066529 1.308922 1.616483 1.311364 0.245491 -66.621165 48.083027 -68.563299 -43.374418 6.160416 1.946706 0.283817 1.611386 0.810788 2.419810 2.492869 1.908325 0.976399 0.345820 1.943091 0.272381 0.651912 0.688463 0.740286 0.981158
+1 0.008842 1 1 2.158534 -2.200153 0.147361 -2.017173 -1.703845 0.658063 0.091002 -2.047898 0.266168 1.434607 -1.860971 -1.211891 -41.427957 20.323266 23.134295 18.088455 -37.339452 1.912340 0.948576 0.710581 1.237946 1.904148 0.513261 1.369588 0.418888 1.503436 2.249526 0.292662 1.775626 0.439442 0.452106 1.802445
+1 -0.026227 1 1 1.433754 -2.048934 1.702630 -2.229017 0.404546 -0.777818 -0.616037 -0.615350 1.512444 1.025928 0.135872 -1.903067 -59.159447 57.169364 -54.493182 33.093593 4.018232 1.891404 2.320598 2.285468 1.351754 2.179533 0.655296 1.304556 0.928960 1.783620 2.050115 1.290696 1.980634 1.270579 1.368698 1.205817
+1 -0.008836 1 1 1.368789 -0.641443 1.212591 -1.059931 -1.430561 -0.826080 -1.231431 0.155180 2.161781 0.528154 -1.462674 1.364844 -30.860848 21.722871 -3.711121 27.189623 -74.001039 2.343032 1.342306 0.879855 2.224098 0.422620 1.228489 0.461201 1.651314 1.376624 1.669102 1.093969 0.833860 0.929846 0.916586 0.812827
+1 0.004848 1 1 -1.572597 1.153485 -0.139620 0.180478 -1.487265 -1.955407 -0.323767 1.260788 -1.549968 -0.231896 -0.336536 -1.301048 -39.038184 -14.762999 -21.729216 47.064318 59.986465 2.012764 1.278653 2.067135 1.581419 1.153392 0.558117 1.515455 1.745562 1.407550 1.686342 0.595118 2.401212 0.411399 1.630337 2.070458
+1 -0.023993 1 1 -1.912666 1.745818 -2.088611 -0.697107 -1.270474 -1.016030 1.286590 -1.427027 2.020903 -1.586054 1.165733 -1.630472 -25.432900 49.250254 49.018973 61.884805 -2.082054 0.728734 0.337758 1.442988 1.044522 2.278273 1.929060 0.716060 1.077086 0.583512 0.843481 0.643181 2.439202 2.172248 1.975912 0.659569
+1 -0.008306 1 1 -1.316798 -2.052278 2.049902 0.424457 -0.714603 1.543820 0.571780 1.346907 -0.857670 0.341800 0.232047 -1.836123 54.419375 -73.566468 18.368196 14.269703 -19.097101 1.900367 2.224481 2.345236 2.385875 1.401596 0.628275 1.666799 0.647852 2.193730 0.767381 1.873739 2.425325 0.690694 2.241856 1.877146
+1 0.025124 1 1 0.255851 -2.320013 -2.158652 0.221456 -0.778217 2.106044 1.523701 1.721437 -1.878438 2.091702 0.813324 -1.111664 27.952525 -1.918233 10.261285 -38.590907 2.620419 0.495764 2.058678 1.207548 1.766800 0.614992 1.168063 1.880817 2.140460 0.962214 0.422260 1.921918 2.174819 2.438541 2.310320 0.552196
+1 -0.016015 1 1 1.255519 -0.573207 -1.768682 -0.493396 1.297008 -0.694286 -0.991421 0.190459 1.330918 -0.968695 0.440892 2.203974 -60.223863 17.529681 21.341448 35.715297 -33.001992 1.907691 1.562981 1.773897 0.636106 0.540948 0.956897 1.070790 0.509499 1.153006 0.825083 1.919228 1.970980 1.016232 1.566285 1.056190
+1 -0.006340 1 1 0.405095 -0.975401 0.833860 0.044171 -2.173323 -1.319141 0.983481 -1.688719 0.425304 -0.614453 -2.272999 1.045628 43.424929 -57.226316 -2.696040 -12.350646 22.700817 0.364352 0.658693 2.155612 1.362226 0.430163 2.000914 2.364621 1.927038 0.478960 0.882553 0.314938 0.413910 1.093689 0.627766 2.113613
+1 -0.006153 1 1 -1.010662 1.970908 1.666922 0.802246 1.203525 2.064307 2.208990 2.297944 -1.189169 -1.116417 1.111163 0.120961 62.379028 54.315607 -17.589898 16.581046 -22.365045 1.535427 2.177499 2.468893 1.684479 0.793053 1.349114 0.566539 1.324100 0.907325 0.406503 0.341881 0.993594 1.326385 1.049822 1.353911
+1 -0.029936 1 1 -2.106917 -2.065758 1.691165 -1.719584 0.030957 1.931487 -1.143048 1.209378 1.483340 1.951068 -1.908946 -1.714583 -23.308485 54.296900 -31.993935 27.940643 -51.610392 1.887032 0.848975 0.728640 1.007373 1.168775 0.345107 1.213146 1.341234 0.873346 0.822450 0.422087 1.260779 0.905684 2.077068 2.034674
+1 -0.036628 1 1 -1.335145 0.612482 2.133780 1.162980 -0.787091 -0.963840 1.938225 -1.000689 -0.066174 -0.067259 0.553656 -1.673204 63.780451 58.042338 67.573094 50.989549 31.358101 0.409050 0.400816 1.510811 2.441604 2.041533 1.053618 2.161444 0.389902 0.325873 1.943340 2.207890 0.251976 1.953450 1.131575 0.635466
+1 0.025804 1 1 -1.710519 1.600519 1.613957 1.269597 0.414705 0.329528 1.326762 -0.137454 -1.121136 1.916748 0.887281 -2.186837 -71.283162 -6.096092 -7.017026 -35.158638 -61.236843 0.510773 2.314016 1.907840 1.818437 2.216015 1.817901 2.207680 1.232610 2.225109 1.652488 0.864817 1.483483 2.156006 1.241047 2.279422
+1 -0.004563 1 1 1.606222 -1.497114 2.164598 0.749082 -1.686651 2.191486 0.277626 0.793398 -1.414420 1.838210 0.370994 0.805488 -27.115185 -24.921747 -59.795864 10.914325 -12.936833 2.434592 1.182388 1.893283 2.413850 1.332510 0.498231 0.772577 1.456264 1.429150 2.474356 1.256733 0.402305 1.782243 1.411983 1.948852
+1 -0.061277 1 1 -0.009857 -0.738746 1.036505 -1.155417 0.664036 1.514290 -0.941306 -1.039637 0.356756 1.834820 -0.061102 0.365095 19.510906 19.790113 62.424379 66.546058 39.595614 0.377252 1.472100 2.082123 1.494254 0.931230 1.681840 1.440080 1.669172 2.283021 0.738475 2.040841 0.672479 2.106440 0.679335 0.328940
+1 -0.032453 1 1 -1.927437 -1.478503 -0.772903 1.870920 -1.211851 -0.631409 0.214702 -1.190691 1.577880 -1.889636 -2.317203 -2.054083 -0.338471 11.322697 -49.439523 69.937588 41.048829 2.239979 1.819957 0.774533 0.568991 2.030234 2.393219 1.079763 0.579825 1.876915 1.817591 1.503648 1.304798 0.483491 0.533030 0.632233
+1 0.001476 1 1 0.412727 0.067644 1.204229 -0.235604 -1.386823 -0.865923 -1.718408 0.955868 0.741168 1.972815 0.737590 -1.615289 -3.011657 -66.925594 31.539339 -18.326411 -61.996676 2.452968 1.784273 1.772172 0.903948 2.150203 0.463952 0.639296 2.393222 1.139089 0.919144 1.054159 2.250254 1.262499 0.570170 1.593443
+1 0.083367 1 1 -0.065602 0.134357 0.896231 2.153078 0.339701 -2.064556 -1.674838 -1.902192 -1.294032 -1.114643 -2.055179 0.415218 -15.064668 8.118291 -55.882686 -70.308216 29.811221 1.932792 0.428364 1.013703 1.811094 0.303415 2.495011 1.896550 1.067983 0.589226 2.374893 1.326807 1.387701 1.085018 1.144370 1.933361
+1 0.037203 1 1 -2.119816 -2.093575 0.697804 -1.142625 -1.116454 0.484667 -1.916709 -0.243856 1.283245 -1.104244 -1.645368 -1.394848 29.453340 22.293014 -21.307303 -61.836597 62.316715 2.230362 2.194546 0.980313 0.868660 0.823681 0.861430 0.809860 0.315935 1.422764 0.885765 0.294651 1.453242 2.392114 0.513013 1.710035
+1 0.002047 1 1 -0.230849 -1.590032 0.284257 -0.862408 0.814166 -1.093538 -0.771158 -1.783504 0.161127 -1.560339 -0.180328 -0.704868 7.455451 53.759647 -61.617379 -3.287691 -56.218850 1.071845 2.492166 1.330332 2.134294 0.833485 1.384052 0.513288 1.828875 2.148217 0.823966 1.153193 1.721606 1.535996 0.479222 0.788583
+1 0.041850 1 1 -1.996882 0.030842 -0.000555 0.088914 0.547719 2.209938 -0.614823 0.937643 0.739323 -0.765517 -1.223038 -0.166534 6.965936 -73.520465 41.542259 -49.255624 10.727336 1.290135 1.547597 1.971446 2.085515 2.246961 2.177765 2.453003 2.378658 1.606800 2.483550 0.522447 0.520948 2.323140 2.267168 2.038309
+1 0.024585 1 1 0.646800 -0.707368 0.631373 -0.822204 -2.062961 1.575334 -2.280702 -1.179081 -1.224407 0.392722 -1.579126 -0.192266 40.855121 -47.981891 -31.637344 21.158997 -30.739530 0.785891 2.471201 2.218308 2.110060 0.769326 0.816078 1.317224 2.326087 2.292865 1.929141 2.079674 0.833412 2.404516 1.946579 0.410449
+1 0.016962 1 1 1.906240 -1.358831 -1.632488 -1.701172 -1.532503 1.140240 -1.266481 0.111258 -0.898215 2.188075 -0.507199 0.223858 60.208469 23.744639 -73.849442 62.422515 35.210841 1.953992 1.238417 0.821127 0.680146 0.462401 1.572714 1.103539 1.935834 2.067921 1.298753 2.399417 1.755050 1.125237 2.111024 1.224824
+1 0.004541 1 1 1.003375 -1.923244 -1.677495 0.564354 -0.942424 -0.978906 -1.528287 1.321306 -2.299995 -0.285360 1.170721 2.075252 -74.758075 -58.969118 -43.964207 -6.421877 67.510643 2.145763 2.341560 1.344944 2.481279 0.609558 2.096284 1.001389 1.839771 0.781418 1.547231 0.318147 0.340725 1.819111 2.289819 2.482618
+1 0.053708 1 1 0.151158 0.529667 0.407451 0.927456 -0.833607 -0.507807 -0.577441 -2.241881 0.960369 0.987913 2.101401 -1.110860 8.318700 12.398419 30.224798 -61.824036 -26.569714 1.267316 0.531111 2.132029 1.015070 2.284914 1.042282 0.631883 1.557841 0.878646 2.150483 0.667263 2.193845 0.450833 0.646419 0.619838
+1 0.050093 1 1 -1.006790 1.078266 -1.427935 0.892993 -0.424866 -1.445247 2.106908 1.910157 -1.492906 2.196222 -0.242574 -0.729708 68.063266 39.318929 -66.752236 -54.834869 -9.635551 2.204307 0.784861 0.914257 2.170507 1.957954 0.337646 1.809652 0.824067 0.602441 1.725977 0.741241 1.293228 1.778828 0.257730 1.925904
+1 0.003498 1 1 -1.985412 -0.390077 -1.084548 -0.486747 -0.054752 -1.304794 1.780123 -0.425378 -0.630830 0.513314 -1.110206 1.832158 74.360633 -20.842915 -56.869327 -2.775575 0.905094 2.303636 0.712184 1.176718 1.093786 2.262634 2.338138 2.337149 1.463395 2.026618 2.368804 2.497752 0.724974 2.390810 1.094609 0.335166
+1 -0.001424 1 1 -1.009328 0.830446 -0.795127 0.643868 1.849838 -2.117400 0.817016 -0.316888 -0.941452 1.215525 1.126417 2.022389 -5.498356 -10.872654 -36.701339 -39.399873 56.330469 0.567937 2.308943 2.156068 2.292888 2.313535 0.591023 1.077713 2.120408 1.442637 1.895625 1.267940 2.018911 1.094639 0.855328 1.751374
+1 -0.020613 1 1 0.924872 -1.851981 -0.907048 -0.176240 2.025190 -0.210786 1.044445 0.330672 1.700045 1.449251 -0.779947 1.303479 -10.324901 19.392254 -24.393819 -36.915421 -37.486268 0.899516 1.923035 0.701913 1.800810 0.710877 1.711895 0.318295 0.591814 0.863143 0.343843 2.472577 0.605543 2.107943 1.195326 1.092123
+1 0.035991 1 1 -0.378213 0.390942 1.496416 0.239023 2.301321 -0.982637 1.750328 -1.683242 -1.774766 0.926618 -0.768863 -0.906452 13.245778 21.798110 60.843101 40.000422 -12.901522 2.336742 1.378738 1.200646 0.508307 1.373308 2.188475 2.453558 0.451654 0.951747 2.267002 1.495786 1.921212 1.550971 2.416535 1.456403
+1 -0.021348 1 1 1.993432 -1.478490 -0.555454 -0.264739 -0.981040 0.316619 1.136595 -1.269093 -1.367093 0.873571 -1.697011 -2.292933 18.898861 -66.837847 6.312579 45.512139 72.518862 2.492743 2.037687 1.648671 1.961014 2.259357 1.262156 1.556565 1.943970 1.547454 1.817561 0.990811 1.811038 1.622445 2.180498 1.126659
+1 0.015234 1 1 0.004546 1.000092 -0.547032 -0.094905 -2.284789 0.813871 -1.331303 -0.780227 1.296773 0.063549 -1.648016 1.224016 -71.694882 -25.889259 29.220938 16.308644 49.386206 0.384435 0.692145 1.887647 2.183856 1.324408 1.575241 0.820307 0.403838 0.557355 2.221360 1.648697 2.401934 1.302381 0.365897 1.873035
+1 -0.058685 1 1 -1.756553 0.733069 -2.211369 0.125850 -0.695215 2.252426 1.902944 -0.199774 2.332230 0.142579 -2.283089 1.101247 -51.255253 2.955514 23.324906 71.688272 64.786121 1.530079 2.283062 1.425115 2.160031 1.388718 2.431776 1.113334 2.298933 0.419498 0.497312 1.073894 0.931843 0.743424 1.980736 0.738897
+1 0.043713 1 1 0.128559 -2.287683 -0.711829 1.042141 -0.688371 -0.536442 -1.175199 -1.943413 -1.383106 0.348779 -0.289973 -0.962408 -72.253887 28.926980 25.753783 -56.173157 -2.241615 1.002542 0.981201 2.301021 1.754258 1.313939 1.122314 2.480392 1.447114 0.646494 1.875524 0.927240 2.126389 0.719270 1.024204 0.550841
+1 0.030850 1 1 -2.158072 0.544778 -0.083622 -1.147741 -2.282406 -1.545087 1.700225 -0.247313 -0.270952 -1.719959 -1.556243 -2.017754 -64.806156 -47.061858 -18.642104 32.155808 -7.341292 2.348644 1.160858 2.282012 1.780795 1.814142 2.041285 1.374871 1.460030 1.717913 2.458297 1.349925 0.696355 0.637712 0.527159 0.962838
+1 0.038574 1 1 -0.799897 0.578658 -0.864959 0.346314 0.696426 -0.743912 -0.954029 1.895410 0.398934 -0.843710 -0.657172 0.750380 40.663413 29.975453 -52.560677 -37.298670 -28.741174 0.581433 1.889277 0.324167 0.270964 1.595876 1.128893 0.561478 1.758090 0.464062 2.485247 2.040547 2.477198 1.765210 0.883077 2.370818
+1 0.012145 1 1 1.107426 -1.430648 -2.285310 1.482313 -1.165127 -2.320265 -1.679673 1.651431 -0.365946 -0.787566 0.486440 -0.395188 -69.290071 41.772375 68.302838 15.801602 -72.467488 1.958937 1.105427 2.159009 2.208016 2.371382 0.813977 2.008543 2.331803 1.620571 2.191669 2.122555 1.526374 0.774375 2.418699 1.816924
+1 0.037035 1 1 0.129806 -0.179264 -1.677737 1.211767 -0.770287 -1.275820 -1.334562 0.981353 0.232641 -1.277575 2.159245 0.329053 -62.202730 58.709054 23.068850 -31.844351 -8.006891 1.047869 2.283939 0.413526 1.386911 1.307935 1.455986 1.256496 0.936208 2.094070 2.042203 1.064010 1.324118 1.192948 1.628081 2.408114
+1 0.041808 1 1 0.844002 0.850975 0.233949 1.855322 0.517954 1.463022 -0.229509 2.086710 1.735347 1.007076 -0.972646 0.023783 -26.553512 -34.883498 63.042698 -41.381310 54.327067 1.750350 0.876662 0.311476 0.735428 0.346396 0.380036 1.019090 2.349662 0.268886 0.415390 1.218031 2.444070 0.735604 1.051348 2.247710
+1 0.007326 1 1 1.715881 -1.015891 -1.095995 0.333591 -1.071327 0.239920 -1.477188 -2.239503 -1.480170 -0.511934 0.754200 -0.483044 29.378513 -35.338393 67.632400 -2.248366 11.710231 1.582827 2.328979 1.395833 0.514752 1.688232 0.858090 0.910959 0.737091 1.280817 2.445353 2.049639 2.276707 0.369980 0.760896 0.881824
+1 0.001217 1 1 1.355775 2.101497 0.509539 1.412387 1.687469 2.137987 1.174246 0.064461 -0.450512 1.060940 -0.455479 -2.322702 -7.247606 -10.522730 -5.524113 6.226600 -49.530680 1.942795 2.060776 0.455741 2.138404 2.402652 2.113329 1.713150 1.166686 1.246277 2.424460 1.903346 0.536523 0.836459 1.872452 1.049693
+1 0.008843 1 1 1.342694 -0.964015 -1.001810 -0.048115 1.868405 -1.068955 -2.301415 -0.586793 0.798902 1.547145 -0.099416 2.009102 -63.908588 38.363502 -74.620021 11.313794 -49.067181 1.793331 1.018855 0.639746 0.962681 1.534914 0.302131 1.172189 1.487139 0.589837 1.388051 2.477399 0.649494 0.552079 1.290946 1.680847
+1 -0.008655 1 1 0.144764 1.461311 -0.721574 2.202005 -2.010111 -0.823912 2.219508 -0.000304 -0.395007 0.879877 0.614325 0.115245 4.241675 39.828020 -60.466431 -9.302765 -51.572651 2.401776 0.902617 2.281387 0.273606 0.999546 2.377743 1.967372 1.114608 1.213517 0.832140 1.269251 1.557376 2.074948 2.394428 1.144785
+1 -0.004386 1 1 -1.571135 2.157795 -0.488012 2.245909 0.760185 1.147883 -0.054522 -2.142845 1.990505 1.172577 0.294488 1.447735 64.039618 63.859412 35.136685 -7.727944 16.438461 1.093157 0.690819 2.100257 0.262659 1.502431 1.105733 0.558928 1.650676 1.918901 0.961760 1.805256 1.184030 2.489500 1.520959 2.012468
+1 -0.050311 1 1 -0.722095 -1.842016 1.628738 -0.060584 -0.367225 1.278755 -1.176579 -1.575090 1.667366 -1.156437 -2.346054 -1.563221 -47.374710 -26.753072 61.111868 57.165925 37.702429 2.345816 0.871739 0.825251 2.487091 1.539872 0.384574 0.784996 0.934910 0.531674 0.346675 0.562445 2.269092 0.624358 1.086376 1.477985
+1 -0.023333 1 1 -0.604596 -1.541426 1.969006 -2.028912 -1.083247 -2.179685 0.140674 -1.311087 -0.301925 0.797005 -2.063384 -0.821402 63.527311 3.523526 -30.091003 60.513278 46.665253 0.668552 1.348920 1.789513 2.097600 0.619236 0.507864 0.675301 2.278931 1.742862 1.031033 0.580044 1.053057 1.728020 1.329648 1.890226
+1 -0.021412 1 1 2.026122 1.314442 0.149937 -1.129211 -1.858871 1.103117 1.540688 -0.240343 -0.919842 1.557116 -2.153759 2.349857 -15.315074 -0.444863 23.191415 -71.893090 -57.171986 1.531414 2.223161 0.411635 1.103055 0.539599 0.797492 1.698139 0.871940 1.937453 2.272224 1.519583 1.387261 0.440613 2.137137 1.363516
+1 -0.045557 1 1 0.469881 -0.667592 -0.027688 1.179901 0.866644 -0.313232 -0.754104 2.094371 -1.460335 -1.733613 -0.125439 -1.811482 37.317370 43.037206 26.323413 67.606785 17.243409 1.524741 0.319826 1.559977 0.787805 0.881562 1.657902 1.862690 1.224243 1.097028 0.498157 1.783180 1.401943 1.948018 2.086827 1.804673
+1 0.024746 1 1 0.312796 -1.869301 0.149902 -1.728120 -2.057458 -0.191976 1.448832 1.610833 0.596478 1.757286 2.162143 1.905317 62.994349 46.019684 52.821513 71.168582 30.352585 1.163558 0.419922 0.873227 1.078651 2.144406 2.032528 0.449976 1.992268 1.056120 1.466189 1.735280 1.845317 1.750426 2.159572 0.433016
+1 0.028190 1 1 -0.361506 -1.570056 1.439441 -0.724961 1.824013 2.101357 -1.842503 -1.843407 1.810850 -2.355339 -2.114053 0.520861 -47.843398 46.002746 68.153767 60.354229 73.528918 0.632806 1.328177 1.914401 1.841835 1.717503 2.328930 0.581454 2.251553 0.609727 0.424625 1.166495 0.274738 2.017994 1.418091 1.102657
+1 -0.013236 1 1 1.108403 0.860965 -1.505799 2.277757 -1.190970 1.589799 0.508505 -1.838018 -1.862353 -0.879636 -1.285600 -0.781943 23.712858 -7.989753 -33.772910 -21.302584 17.475829 1.618926 1.545389 0.851099 0.428072 0.604574 1.575792 1.087041 1.406511 2.233047 2.323563 0.368483 0.336914 0.759764 2.095257 1.739402
+1 -0.021439 1 1 -0.086348 0.162515 -1.802309 -0.174994 -0.595302 -0.841779 -1.194828 -1.990849 -2.242449 0.848263 1.786734 2.300051 39.188195 -14.009319 45.375043 18.355532 -48.575452 2.010555 2.398639 2.177639 0.327557 1.003843 0.341425 2.323973 0.509947 1.929921 1.681492 2.331684 1.866894 2.130415 0.881486 0.389537
+1 0.066742 1 1 -2.056719 -1.903600 -1.396492 1.559471 -0.270854 -0.080751 -0.008073 0.970609 -1.264228 0.277505 -1.245415 0.751081 -34.160402 66.117677 39.791781 -69.532096 24.063910 2.007132 1.123340 1.725491 1.583314 1.505343 0.553862 2.006956 0.404055 1.946359 1.202100 2.438542 2.327824 2.236459 1.161886 1.567103
+1 0.016905 1 1 -1.230491 1.814322 -0.553081 1.909487 1.380798 -1.441915 1.543404 -1.714313 -0.910989 -0.435131 0.387116 -1.550197 20.118612 33.520138 -27.037701 -72.633076 -44.116422 1.154418 2.054836 1.879976 1.514713 0.526465 0.548875 1.447335 2.116536 1.614291 2.382394 1.395070 1.191708 1.033089 1.368387 0.480160
+1 -0.010410 1 1 -0.515311 0.536936 0.054929 -0.434958 -1.416034 -1.720765 -0.974760 2.182656 -2.050030 2.140911 -1.511231 0.511575 -65.814814 -49.582261 70.945664 33.770226 -23.810174 1.711086 2.478101 1.188255 1.495252 1.953801 0.276774 2.494193 1.657821 0.491627 2.276827 2.378659 1.624796 1.204694 1.036886 2.186926
+1 0.016118 1 1 -1.574454 -1.791122 -0.643409 1.155322 -2.258545 -1.065353 1.692933 -0.278906 1.251383 0.608735 0.405401 -0.540250 25.367603 53.310421 38.252891 16.339444 -32.961687 0.818838 0.467159 0.537020 2.442686 2.216159 1.985609 1.631002 2.006433 0.621225 2.425127 1.853479 1.673996 2.356328 2.047970 1.223124
+1 -0.062706 1 1 -0.286383 -1.893621 1.391227 -0.517874 -0.118787 1.592814 -0.659877 -2.300795 0.407909 -0.797218 -1.521513 2.065081 34.193488 39.957990 23.939362 48.862302 -21.283045 2.062978 1.470290 0.918027 0.272293 1.432819 1.131597 0.998552 1.420907 1.191205 1.578497 1.541990 2.218752 0.573845 0.359051 1.577103
+1 0.023231 1 1 -2.077537 1.636621 0.481390 -0.442579 -2.276482 -0.943248 -0.685795 0.344366 0.939588 0.445818 0.169660 0.474746 31.305662 -45.733119 -36.536873 24.775528 2.303394 1.572224 1.866986 1.436446 1.342987 1.084091 1.314709 0.558287 2.127165 0.254912 1.804709 0.992417 1.802286 0.772953 1.013556 1.594343
+1 0.033816 1 1 -0.764451 -2.148073 -1.052684 -2.145622 -2.266047 0.069603 1.153290 1.284063 -1.497635 -1.874555 1.386083 -2.149004 68.691518 -51.657894 -14.231670 58.316984 33.552770 2.445986 1.429599 1.024586 2.464212 1.763015 2.246900 1.139766 1.043469 0.328183 0.277778 1.364003 1.044003 0.314066 1.514039 0.453806
+1 -0.007411 1 1 -1.074397 0.488012 -2.251072 1.995194 -0.133518 -0.939879 -0.625275 -0.361367 0.777191 -0.487980 -1.926027 -1.338018 -17.403039 7.119501 -42.544324 7.547218 -53.904807 1.703620 0.737687 2.312413 1.971639 0.838962 1.182990 0.765919 2.053457 1.200744 2.152174 2.083405 0.541560 2.244568 2.447735 1.577162
+1 0.007968 1 1 -0.605081 -0.259434 -1.339530 2.322196 1.140874 -0.046289 -0.438538 -0.333905 0.520960 0.154899 2.150796 -0.301534 -65.941198 -73.712488 -35.790240 -26.569963 -11.367602 2.045748 2.132503 2.221811 2.479532 0.487934 0.957704 1.131894 1.487100 2.185914 2.162585 1.569210 0.711034 2.101516 1.179831 1.676745
+1 0.020257 1 1 1.483328 1.749846 -0.354669 0.252190 2.118173 -1.960674 0.685118 -2.305089 -1.083682 -0.064185 0.385337 1.533384 -14.867364 24.212383 -12.474790 36.207599 -8.889278 1.343507 0.819516 0.611558 1.955471 1.347861 2.005251 1.007407 1.731939 1.942613 1.244216 1.543440 1.838640 2.023361 1.623297 0.748926
+1 0.032010 1 1 0.150513 -0.876405 1.190736 -0.818835 -1.978209 -1.862044 -0.404064 -0.543010 1.524595 -2.097752 1.170969 1.534682 -70.491535 -51.225306 56.284191 68.402190 35.608747 1.018080 1.129515 2.002490 1.854918 1.106802 0.526556 2.072593 1.072194 1.605615 0.573137 1.969037 2.113796 0.569800 2.124532 1.005463
+1 0.051048 1 1 1.544545 -1.378906 0.254860 -0.125354 -0.384892 1.234484 -0.676781 1.042580 1.980251 -1.530384 -0.945535 -1.427162 -8.027058 -60.760178 3.683023 -49.436658 -31.904414 1.862809 0.983415 1.247809 1.174162 0.892409 1.724788 1.017154 1.298374 0.516774 1.926917 0.689025 1.189611 1.793313 0.715675 1.346025
+1 0.012895 1 1 -0.534442 -0.557930 0.526486 -1.224239 -1.493521 1.291509 1.128308 0.816783 0.474803 1.944207 0.579416 -2.264498 -68.631501 10.368497 -36.675041 -47.419757 -33.852164 1.325157 0.668395 0.967346 1.181708 1.713842 1.534953 0.954504 1.353173 1.285474 1.965571 2.350701 1.984595 0.338762 0.329702 1.052327
+1 0.023848 1 1 0.230058 -2.285879 1.335023 2.050915 -1.402869 -1.939983 -0.274984 1.202245 -0.597620 -2.098852 1.540798 1.620372 22.393617 19.521861 53.912102 -49.302433 -25.984780 2.482026 1.908936 2.236705 0.800889 0.286744 1.311469 2.354830 1.625325 1.094025 1.774339 1.312771 1.746944 2.131880 0.752500 1.524946
+1 -0.039848 1 1 1.043950 1.441168 0.037478 -1.573343 -1.963417 1.704347 -1.658581 -1.983064 1.371600 -0.521421 1.519285 -1.817413 14.147651 29.562601 58.640992 -70.848543 -51.458043 2.045061 1.833124 1.559195 1.138864 1.644267 2.195880 0.896410 1.461669 2.264083 1.947020 1.061650 2.157656 1.971693 1.745349 2.337311
+1 -0.001622 1 1 1.013197 -1.771291 -1.922217 1.444196 -0.913380 1.780324 -1.765710 2.345080 -0.663776 -1.863190 -0.800730 0.721480 29.602851 -14.880129 -40.323268 -13.169591 58.676121 2.418392 1.159979 1.009721 2.376830 2.379486 2.020654 1.132338 2.198437 1.137196 0.608046 1.435668 1.768534 0.507695 2.326340 2.044638
+1 -0.025105 1 1 -1.543954 1.898472 0.027733 -0.414475 -1.171747 -0.474411 -0.071327 -1.852883 -1.937518 -1.263632 0.871570 -2.346699 55.136983 -12.719772 -31.215529 60.612197 59.193874 2.446500 1.075252 1.267236 1.440548 0.537374 1.640642 2.021117 2.157720 0.800775 0.629619 1.749023 1.077720 2.240503 1.639996 2.409294
+1 -0.008786 1 1 -1.773972 0.130120 0.377852 -1.736019 1.837714 1.454899 -0.097184 1.820775 -0.490232 -2.067563 -0.376709 2.094587 69.473527 41.570974 -16.637868 -32.644142 49.898678 1.331225 1.391776 2.079521 0.514246 2.179033 1.259660 2.352317 2.142445 0.567051 0.922156 2.170032 0.730170 1.970800 2.480190 0.302704
+1 -0.048746 1 1 1.147810 -1.280406 1.699919 -0.673429 0.834534 1.942861 1.521275 -1.362199 -1.689837 0.476003 -1.454657 -0.546467 -0.908204 35.817040 26.993167 74.150817 52.786452 0.353384 0.828902 0.856842 2.438352 1.375074 0.369337 1.196108 0.737541 2.103094 0.694782 1.200542 1.008785 2.403071 2.413541 0.635768
+1 0.045759 1 1 -1.249430 -0.766665 -1.671338 0.377415 0.343117 -1.198667 -0.539536 -1.341611 0.330671 1.681900 -1.927608 0.361307 -56.888710 -28.547022 60.204303 -46.286496 -37.131526 0.331585 1.194481 0.386235 1.707989 2.172172 0.689551 1.029865 1.190181 2.379446 1.341251 1.152718 0.478220 1.948569 2.350550 1.698182
+1 0.015925 1 1 -1.009257 2.018232 0.646888 0.761709 -1.514107 -0.695917 -0.127560 0.243461 1.495190 -1.517442 -0.195848 2.342396 43.053467 -0.382120 27.707408 -71.587137 -15.005548 0.651330 2.146460 0.546077 1.665366 1.308446 1.045465 2.386672 1.305343 0.657107 2.499099 0.865801 2.275636 0.364035 2.079969 1.284874
+1 0.002183 1 1 -0.894312 1.818036 0.594129 -0.027442 0.604147 -1.294488 0.648793 -0.207011 -1.492311 -1.930363 1.179793 -0.953060 -21.140536 41.006547 -52.960481 -6.808004 27.879384 0.907038 2.343538 0.844267 0.338715 1.786719 2.380557 2.015753 2.001891 0.776411 0.643014 1.888931 1.267419 2.269434 1.871692 1.768788
+1 0.002196 1 1 -1.072352 1.861856 1.944437 -0.260663 1.552849 1.523329 0.187198 -1.641835 1.430855 1.054625 1.785031 1.941901 -15.085547 -42.792236 40.887228 41.640791 -43.221324 1.813009 0.997023 0.457129 0.710589 1.368660 0.565401 2.444450 0.379429 2.064096 2.255026 0.476945 0.771447 0.464372 0.946517 2.107929
+1 0.011615 1 1 -1.250132 1.569242 -0.993053 1.047461 -0.812188 1.351070 -1.563627 1.120942 -0.464298 0.259565 -1.159121 -0.323222 31.763777 3.801217 -12.942134 -18.441463 -45.676121 1.696513 0.544864 1.533340 0.853691 1.239401 1.605708 2.125365 1.503173 2.334163 0.776415 0.699029 0.587765 0.323612 2.193090 1.270002
+1 0.020948 1 1 1.183867 1.542141 0.622012 2.082525 2.091563 -1.529056 -2.186092 0.853540 0.942634 -0.209107 0.974924 0.564565 -67.000382 -25.420566 -43.444486 28.528199 73.439373 0.558173 2.457078 1.115889 2.495185 0.332976 2.085712 1.061495 1.799115 1.479598 2.108054 0.810365 2.060113 0.567293 0.498892 0.625031
+1 -0.013617 1 1 1.285667 1.897295 -0.906177 0.327129 -1.307959 0.418512 -1.662496 -1.814874 0.711755 -2.286687 1.901053 1.000153 15.102475 27.296803 -72.635758 60.811909 -34.250488 2.155782 1.982318 0.316484 1.651374 2.384987 2.227917 1.605990 2.369494 0.593057 1.501331 0.623508 0.297250 2.375140 0.976234 2.065676
+1 -0.055841 1 1 0.767150 0.394582 1.415455 1.412823 -0.420766 1.483083 2.355326 1.898152 -0.625532 0.025446 -1.152449 -1.290093 -28.415744 16.593584 38.371687 62.947594 10.207991 0.860552 1.789752 1.611013 1.301992 0.578521 2.444177 0.281263 1.436846 1.316018 2.319475 1.415397 0.820562 2.437748 2.482029 1.962063
+1 -0.000043 1 1 0.999945 1.701012 -1.147964 -1.304724 -1.745734 -1.208953 0.945114 -0.937893 -0.226341 -1.207603 0.071300 1.398252 -8.274040 -11.798344 5.230644 11.437400 -71.620463 1.748082 1.021162 1.170529 0.578603 1.585754 2.022106 0.785665 0.926038 2.164082 1.977221 2.397354 0.827312 1.128589 2.200792 2.464361
+1 -0.002220 1 1 0.933196 1.400918 2.141544 -0.300665 -1.599731 2.205379 -1.847283 -2.067685 2.288790 0.458248 1.733099 0.918059 46.110676 -67.870324 53.468692 -1.686289 8.539811 1.054141 1.942319 0.809571 2.212064 0.660015 1.870769 2.005408 1.392819 1.609029 1.700782 0.296390 1.419129 0.560248 1.342202 1.383731
+1 -0.013785 1 1 2.208856 0.047177 1.222939 -1.500962 -1.246214 1.445309 -1.061998 1.523354 0.597498 0.044697 1.945492 -1.383011 62.146722 49.954818 40.617761 12.704038 66.764468 0.781163 1.763057 0.704073 2.098342 1.840270 2.422141 1.176624 1.773421 1.639674 1.502437 1.208854 1.200824 1.256402 1.593039 0.702880
+1 -0.029599 1 1 0.220434 0.890632 2.304709 -0.597380 1.941008 -1.351489 -0.755696 -1.095906 1.827452 -1.362983 -0.732833 1.461427 39.257105 -55.838934 65.031612 -63.689548 -30.238011 1.221115 0.286134 2.299825 1.906799 2.323161 0.375764 1.218224 1.183888 2.348575 2.252833 1.858959 1.517099 2.376697 2.403385 0.938346
+1 -0.019504 1 1 -1.204976 1.823271 -0.944439 -1.860611 0.120721 -2.089864 1.797438 -1.589245 -0.624839 2.240574 0.629966 -0.891767 69.209671 -43.066639 -70.996517 11.532727 30.542197 1.715671 0.789632 2.339276 1.217292 1.278171 0.722160 2.350617 0.578736 1.574340 1.440071 1.520479 0.696584 2.242958 2.396985 1.377736
+1 0.002950 1 1 -0.617088 0.568773 -2.064219 -0.721694 0.173150 -2.129163 1.040407 -1.561747 -0.275966 -1.166892 1.014733 0.487375 37.481145 -54.393115 64.910301 -2.573005 -44.501013 0.947073 2.451264 2.393612 0.934160 1.432532 0.823228 2.246504 1.245255 0.993829 0.776792 0.287614 2.423920 1.829663 1.893585 0.738349
+1 0.014342 1 1 0.981064 0.091246 2.050860 -2.315819 -2.347170 -1.472617 -0.802244 -1.164025 2.068321 -1.015342 -1.288120 -0.725422 -38.670057 22.348174 5.766442 16.588570 -45.901874 1.032980 1.789887 1.629218 1.274716 1.151676 0.976148 0.617749 0.257651 0.586750 1.256543 1.712726 0.793219 1.879962 1.277462 2.307071
+1 -0.007788 1 1 -1.988439 0.575644 0.320018 1.713891 -1.468302 1.023562 -1.918565 1.553651 0.871146 -0.045097 0.750108 1.429139 15.812517 -39.022871 -57.393238 41.856982 -9.695565 0.574634 2.372223 1.457069 1.464914 0.565483 1.578509 1.745342 2.215102 2.216931 1.465429 2.468233 1.843049 1.866804 0.620468 0.947366
+1 -0.012130 1 1 -2.331863 1.310633 2.100581 -0.746200 -1.714574 -0.584439 -2.047843 1.191473 2.148848 -0.061175 -0.867133 1.512833 -59.622866 68.490725 23.620681 -57.210547 -37.667394 2.486725 2.144639 1.439475 0.508430 1.185924 0.577927 1.469407 1.817972 1.158866 0.303681 2.463255 1.430748 2.330840 1.175182 2.278419
+1 -0.015200 1 1 0.505380 2.198818 0.981152 1.565818 -1.983672 0.568125 1.185117 -1.002857 1.206119 -1.456921 -0.904678 1.948271 -57.297321 3.918435 7.138146 -29.181586 45.084908 0.505786 1.751014 0.795997 1.314869 1.009453 2.368982 0.981196 2.205966 1.662052 1.859498 1.587137 0.505910 1.578316 0.766108 0.724105
+1 -0.001402 1 1 -2.005262 0.571149 0.172742 0.442149 -0.243989 -0.950114 1.712356 1.012934 -1.476791 -0.266123 -0.677958 0.113907 38.394201 -8.656062 17.573146 1.865711 7.013484 1.009287 1.839050 2.160194 1.878818 2.291205 1.037194 0.619934 0.972947 0.821736 1.923282 0.356447 0.557192 1.728900 0.380625 1.913069
+1 -0.006934 1 1 0.698300 -2.234644 0.076910 1.425641 -1.752452 -1.038746 1.196921 -0.541332 1.453193 -0.489855 -0.446801 2.155927 35.221085 60.774092 -69.842849 51.239693 35.523618 2.056691 1.555131 0.332922 1.164321 1.999235 1.140138 0.558217 0.953961 1.214318 0.794491 0.753041 1.612329 0.915085 0.337408 2.307826
+1 0.024971 1 1 -1.926774 0.251235 0.213921 -0.188950 0.467880 -1.325762 -1.910456 1.179831 -0.321106 -1.135389 -2.023628 -1.805125 -11.816045 7.728044 -14.772618 -33.392265 -73.795125 0.254952 2.479939 0.579511 1.095965 0.636397 0.922923 1.571843 2.214498 1.061366 1.880579 0.390606 0.918676 2.187824 0.514395 2.441726
+1 0.023095 1 1 -0.536785 -2.225081 0.582335 -0.325362 -1.991449 1.815648 -1.826056 1.260423 1.741148 -0.465377 0.977587 -1.788498 33.073713 -30.104733 -20.247611 48.404962 -57.801738 0.267835 0.760011 1.759248 1.926317 1.856063 2.347937 0.527359 2.073914 0.765515 2.008368 1.646944 2.193284 2.279365 2.293021 2.310222
+1 0.043158 1 1 0.733396 -1.424743 -2.007506 0.552390 0.612373 0.303713 0.990575 -0.276705 0.552625 -0.149776 -0.877153 -1.955377 5.941726 -37.419688 37.311852 -49.707618 64.072580 1.642858 1.008776 2.250838 2.089139 2.417744 1.529490 1.388590 0.289531 0.892656 1.376734 1.267412 2.149937 0.486973 0.558926 1.624826
+1 0.030288 1 1 -1.574630 -0.031639 0.748888 -0.238258 1.127483 1.094662 0.815427 1.256193 1.334224 -1.964370 -0.166713 1.922745 -63.319296 42.600147 30.662667 -52.551277 -29.313623 0.264021 1.900460 1.532660 0.663860 1.244090 1.661636 1.622257 1.267563 2.425150 2.246238 1.266357 2.403817 1.446190 0.864166 1.790992
+1 0.027270 1 1 1.698244 -0.558287 -0.755378 -0.454738 0.707088 -0.621445 -1.977612 -1.240429 -0.286122 -2.214159 0.368109 -0.550966 -7.529665 48.925666 -6.330588 -48.188361 -51.783732 0.937206 0.872258 0.548385 2.203844 2.008898 1.545239 0.574389 0.512205 1.637626 0.829964 0.698704 1.863782 1.578642 1.734897 2.160868
+1 -0.003567 1 1 -0.238454 -2.165354 0.678375 2.182107 -1.852704 1.064402 1.178638 -1.507244 1.552746 -0.203250 0.462628 -0.054507 -60.343379 -41.163166 -29.326902 2.756420 -22.843576 2.395328 0.530481 0.537657 1.902399 0.366983 2.136975 0.892628 0.902849 1.687225 1.936579 1.086148 2.135893 0.700834 1.659836 0.608491
+1 -0.002273 1 1 -1.575795 -0.754442 1.124335 0.025442 -1.215331 2.140862 -2.339761 0.528490 -0.529336 0.444086 -0.673953 1.446769 -2.405663 68.026089 14.476478 6.164211 -48.108808 0.404004 1.094648 1.003652 1.622650 1.133230 1.442272 0.264214 0.651460 2.080246 1.436449 1.401714 0.360769 1.188145 1.904214 1.629322
+1 -0.030507 1 1 0.251559 0.945668 -1.041615 0.109882 -0.474828 2.344753 -1.452837 1.771091 -1.435494 1.084905 1.762820 0.927836 26.980009 3.017536 15.736245 29.074194 -50.019014 0.331596 1.389645 2.261174 0.299007 0.415849 2.172958 0.410355 2.080015 2.059174 0.535899 1.605791 1.273651 1.254785 1.425645 2.064259
+1 0.067950 1 1 0.033190 1.757728 0.173845 0.123620 -0.475465 1.065699 -0.593483 1.460805 0.205182 -0.974468 -2.326452 -1.983620 46.452628 -20.678975 -1.530288 -69.542353 1.668562 1.277707 1.929820 2.238777 1.878482 1.153191 1.674607 1.368693 1.130361 0.479879 0.571921 1.776506 1.740402 2.428989 1.519397 0.501972
+1 -0.068777 1 1 -1.039773 -1.925102 0.070076 -0.329187 -0.305536 1.358708 -0.432989 -1.325535 1.907307 -2.280583 0.812376 1.819543 -74.411887 59.410886 -31.242236 61.732745 -7.760631 2.381203 1.620443 2.291587 0.699667 2.304346 1.398845 1.638127 2.497118 1.314092 1.437131 1.603749 0.706376 0.309815 2.057540 2.332248
+1 0.042608 1 1 -1.593860 1.931113 1.986309 1.330558 -2.315211 -1.549854 1.689635 0.842975 -2.277023 -0.611344 -1.850007 -0.717671 57.796726 -10.421502 45.823690 58.762563 22.403202 1.834321 1.435762 1.101560 2.425911 1.542551 0.404184 1.873541 1.357463 1.382900 1.394098 0.606782 0.432614 0.447186 2.362902 2.287593
+1 0.050415 1 1 -1.214410 -1.238744 -0.238030 0.253437 -0.489817 0.194815 -0.846334 -2.353379 -2.160604 0.405314 -2.004827 -1.545605 -73.132032 -30.055431 58.374713 -46.198928 -65.390613 1.824423 1.572982 1.116106 1.651411 0.762619 0.585069 2.247000 0.587499 0.345277 1.823799 2.342983 0.513787 1.210758 1.705678 1.573030
+1 0.001977 1 1 1.930749 0.582259 -1.597716 -1.624604 -1.143781 -1.688932 1.557664 2.339767 -0.428690 0.252505 -2.008590 1.179390 54.169569 -72.060607 -22.616367 -13.287901 20.246918 0.474329 1.798395 0.621933 0.828858 2.369645 0.867935 2.137355 0.528811 1.718947 1.845944 1.032514 0.711641 1.054891 1.046145 0.308384
+1 -0.008691 1 1 -0.616708 2.244524 1.047297 1.153164 -0.819513 0.760437 0.666544 1.256142 0.466748 -1.494615 1.752250 2.348024 53.952029 21.746903 -49.800030 10.897904 11.072124 0.462909 1.107640 1.099563 0.358072 0.860213 0.601621 1.446200 1.032071 2.269815 1.527314 0.824752 0.856705 2.389013 2.395029 2.248209
+1 0.009112 1 1 0.602040 0.982073 -1.806006 -1.038959 2.332232 0.165187 0.698270 1.978046 -0.891446 -1.856587 1.778835 1.490395 -63.603163 71.643098 55.549257 16.357034 -37.329197 2.247672 0.615360 0.600294 1.637925 1.352286 2.115035 1.149930 0.874000 0.560954 1.962000 0.834932 0.952309 0.458015 2.114810 1.855119
+1 0.001981 1 1 1.494435 -0.072467 -2.148717 2.268976 2.029263 2.263688 -2.024758 -1.939014 1.867519 -1.822450 0.611017 1.068027 26.815222 -66.568625 31.113487 24.382202 -8.323925 2.121775 1.928043 1.626187 2.078492 1.211722 2.167197 0.335660 2.193298 0.266316 2.231095 1.016957 2.491993 0.674915 0.302166 1.758404
+1 -0.004717 1 1 1.804912 1.503941 -0.514769 0.216355 -1.692640 0.489637 1.504072 1.689233 -1.205753 -1.814906 0.168647 2.305686 53.916199 19.559443 -64.448245 -31.649877 -39.488514 2.373082 2.393780 1.508715 0.966233 0.484120 2.111078 2.139963 1.606833 0.784634 1.591377 2.025204 1.098867 2.156231 0.525715 1.441475
+1 0.049694 1 1 2.007462 -1.285176 1.629250 -0.879316 -0.611092 -2.325666 1.803225 1.424574 -0.833725 2.236765 -2.133586 2.104963 70.103656 -17.861668 -51.062191 -52.241183 -67.556283 0.348159 0.761521 2.389735 1.021571 1.296550 1.364670 1.009281 1.727160 0.380206 1.617329 1.699594 0.580384 2.269926 1.149591 1.932312
+1 -0.037484 1 1 -2.325576 -1.402727 0.446727 1.310367 2.346509 -0.198776 0.252639 0.243874 -0.993619 0.945202 0.554898 0.355700 -56.286031 50.680521 -62.487027 -69.470168 14.884541 0.842090 1.999537 1.717419 0.915781 0.789583 1.515565 1.345281 1.390319 2.348413 1.781223 2.257554 2.460812 0.866634 0.512534 0.404999
+1 -0.021466 1 1 2.094330 -2.144808 1.990069 -1.441018 -2.225222 -1.783058 -1.774801 0.350871 1.886989 0.249569 0.476402 0.546531 35.064436 -22.025136 23.534223 -10.312570 -73.370576 1.536050 1.388093 0.923267 0.601736 1.126993 2.364788 2.497419 1.870135 0.366907 0.854329 0.710489 1.946707 0.299067 1.412766 1.607759
+1 -0.024094 1 1 -2.328887 -0.501947 -1.050827 0.778738 1.940522 -0.091514 -1.840264 -1.911355 0.215082 0.478053 0.013860 2.035060 23.114936 -7.270933 47.424302 -39.752689 -23.442639 2.118374 1.011658 1.181235 0.516522 2.178947 2.068759 1.877449 1.779983 1.679237 0.445227 0.922676 1.916446 2.456074 2.237856 2.145672
+1 0.007830 1 1 -1.484630 -0.068710 -0.274732 0.726254 1.056950 -1.549648 0.431990 -1.328359 1.574629 0.019210 -2.295657 1.939461 29.346925 33.771979 5.657280 -18.091217 -9.081091 2.486418 1.473711 2.166507 2.227325 0.656524 1.700757 2.125984 0.669533 2.086959 1.762390 0.742423 0.903013 2.197170 2.342954 2.286204
+1 -0.020587 1 1 -1.859340 -2.070405 -1.010593 -1.586187 -1.060545 -2.323398 2.218491 1.751932 1.721313 0.755122 0.871351 -1.305323 73.614222 34.236928 20.057282 52.735653 -21.885557 0.916581 0.721276 0.982954 0.255285 1.333228 1.308932 2.476391 1.698347 2.126549 1.151295 1.307476 0.505408 2.142338 1.019455 1.731055
+1 0.016483 1 1 -1.765132 -2.076921 -2.152172 0.747345 2.110355 -1.419457 2.008490 1.854807 1.295415 0.807836 0.913369 -1.974576 -65.225241 -40.631011 64.591929 46.551245 -13.217146 1.516533 1.874914 1.926321 1.918012 1.785299 1.021287 1.019033 1.384583 0.429808 0.528604 0.496951 1.750066 0.604639 0.420916 1.840892
+1 -0.019705 1 1 -0.968943 0.988359 0.173513 -0.730055 1.018425 1.276693 1.866809 0.370027 -1.304670 -0.849491 1.146250 0.779872 68.674320 -40.709190 -49.361162 36.952355 58.230441 0.310295 1.135169 0.292426 2.305391 0.950664 2.056013 1.406347 1.720425 1.931264 1.751406 0.635496 1.535397 1.661034 0.507369 1.350366
+1 -0.031370 1 1 0.621761 -2.133514 -1.406216 -1.634645 -0.253215 -0.497712 -0.562433 0.237144 -1.004792 1.654856 0.635849 -0.987051 -55.830428 57.997074 56.817131 25.523324 -29.501609 2.371747 2.454333 2.222715 1.927353 1.265862 0.848235 1.783510 2.450290 1.782166 2.367891 0.642698 1.069998 0.700455 2.047179 1.444984
+1 0.054743 1 1 -1.012694 0.795520 1.264122 -2.067851 -0.499996 -1.244754 -2.282059 -0.440879 -1.979296 -1.273769 0.144945 -0.215227 56.986250 17.906459 53.857562 -65.953801 14.462523 2.449418 0.622029 2.433315 2.221210 1.370420 0.895625 1.775467 2.275379 0.548058 1.212093 1.640264 2.424062 1.964794 0.540864 1.805018
+1 0.030337 1 1 -1.542719 -0.920588 -1.543153 1.214866 -0.535350 -1.678095 -0.089200 -0.644377 -0.976928 -1.271934 -1.999354 0.904570 29.745855 -11.422478 22.417249 -33.297334 21.699469 2.169609 0.362391 1.449573 1.469360 1.030412 1.392783 0.995714 0.959130 0.346414 0.686879 1.122497 1.050825 2.470621 1.470892 2.036630
+1 -0.018560 1 1 -1.465219 1.011840 -1.023647 0.497507 1.827417 -1.948725 -1.124674 -1.006579 -0.092745 1.029543 -0.359335 1.945313 10.346993 51.913401 -41.477084 -55.344212 -20.169901 1.442001 2.458680 1.043426 1.862329 1.910910 1.661998 0.942387 2.443162 1.224143 1.673895 0.652502 1.593993 0.988765 1.168853 1.663535
+1 -0.004220 1 1 -1.958125 1.122580 -1.207006 0.685502 -0.552995 -1.349905 2.296130 1.304835 -1.099081 0.316031 0.667962 1.528734 47.309855 -13.269202 34.521820 8.222168 39.983854 1.504421 0.797490 1.667499 1.151499 2.492617 2.156958 1.485849 1.412046 0.760941 1.631771 1.418087 1.047205 2.378287 2.121072 1.349891
+1 0.029392 1 1 0.413882 0.635474 2.139835 -0.751718 -0.211995 -0.441536 1.123402 -1.527815 -0.173415 -2.337077 -1.486228 1.331252 -2.064605 -49.809191 6.924263 -23.910468 -13.233351 1.931133 1.807583 2.047911 2.485223 1.639917 1.090707 2.267668 1.447486 2.399127 1.380805 2.186742 0.316473 1.454624 0.873647 1.376821
+1 0.061515 1 1 -0.903584 1.500955 1.125983 -0.564984 -0.226135 2.249243 0.245106 0.865042 1.044760 0.916593 0.374190 -2.035153 -73.133653 -57.309979 -58.818717 -66.172940 -68.610024 2.445009 0.770925 0.693534 0.474061 1.785564 0.966956 1.382481 1.103888 1.039458 0.415034 1.971015 1.594488 0.301531 2.333223 0.723097
+1 0.041810 1 1 0.104663 1.355283 -1.447656 -0.686328 0.819552 -0.110079 1.865687 0.366106 -1.237571 0.634437 -1.157114 0.407603 -38.889440 -64.823825 -44.020917 -59.552736 47.173633 0.583646 0.842704 1.071000 1.791649 1.998324 1.585464 1.644867 1.033966 0.362451 2.460208 1.957018 0.356878 1.051618 2.294615 2.096779
+1 0.001245 1 1 -1.696182 2.214306 2.102800 -1.158726 1.602065 -0.675203 -0.712472 -0.330517 0.911270 0.443017 0.210844 -0.059688 18.046560 8.542063 16.444787 -62.472607 22.894096 1.841043 1.909428 1.500905 2.457514 1.687479 1.707722 2.189805 2.295414 2.027204 0.970063 1.847440 1.417562 1.216091 1.334671 0.815416
+1 -0.001104 1 1 0.976716 -2.293084 -1.945930 -1.268646 1.432529 0.926832 -1.890970 -1.186367 -1.153545 -0.855943 1.086904 -2.330087 -58.006635 -67.515189 22.226512 60.981511 -33.743581 1.699531 1.771130 1.386643 1.313963 1.524194 2.380044 2.402606 1.351443 1.456781 1.121979 1.343909 0.833049 0.804996 1.813701 1.374569
+1 0.007802 1 1 0.501357 0.555382 -0.940159 -0.618999 1.446398 -1.606939 -1.113709 -0.501922 -0.626697 -0.707721 -0.598489 2.154020 64.907108 -56.243898 8.809237 6.853498 -13.258760 2.275352 2.337979 1.914563 2.314695 2.082070 0.593167 1.110877 1.501971 2.371803 1.146485 1.471843 2.268348 1.621381 2.300617 1.723539
+1 0.033499 1 1 -0.494314 0.011506 0.179595 -2.195950 0.101314 1.615995 -2.183279 0.995138 1.011851 -0.829395 -0.400061 0.758798 44.506870 -23.043573 6.664762 -35.353136 -30.159059 0.875312 2.365655 1.317450 1.627272 2.315419 0.750276 2.382923 1.286567 2.332244 2.272706 0.625352 2.041556 1.433909 1.464108 0.508112
+1 -0.021250 1 1 -2.107267 1.471022 2.273903 0.004759 -0.133559 -1.634310 0.670571 -1.740267 1.138471 1.989260 -0.901174 -0.410048 -68.966126 -63.684323 57.575026 13.454660 -67.535257 1.148990 0.831582 0.896879 0.340523 0.677518 1.297407 2.266021 0.765354 1.553065 1.604521 2.440686 2.366852 1.172710 1.228340 2.461574
+1 0.004611 1 1 0.057200 0.035298 -0.509796 -1.015174 1.536624 2.152583 1.458163 -1.784855 1.008091 1.949188 -0.526902 -1.057834 26.312042 26.486848 -35.543047 -71.985278 43.433474 0.420913 1.787853 1.188642 1.262113 0.839232 1.216460 0.786043 0.531069 1.426899 0.637856 0.701101 1.656008 1.535286 2.046770 1.311620
+1 0.024532 1 1 -0.100423 -0.782432 1.950020 -0.674739 -2.330375 -1.951962 1.021500 1.115123 0.697544 -0.801213 2.029067 -1.025018 32.133989 -74.048563 15.807931 33.890522 48.008668 1.850132 1.674476 1.411910 0.716198 1.147291 1.526185 2.097299 2.311291 1.114405 2.312627 1.072835 1.143531 1.332425 1.317684 1.072203
+1 0.012467 1 1 1.383497 1.512336 -0.797611 1.293249 2.104582 0.511204 1.120806 1.973093 0.690930 1.129689 0.461920 2.189935 -70.810080 -5.014812 16.049533 44.504774 -58.258713 2.062152 1.085791 0.634598 2.182965 2.098553 0.873406 1.841220 0.393276 0.788977 0.331331 1.437513 1.280397 2.138607 1.325853 1.103982
+1 -0.010761 1 1 0.043286 1.806962 -1.743472 -0.890868 -1.564724 1.522784 0.445118 -2.168945 1.573887 1.684954 2.279075 2.117959 -27.159641 -22.088002 16.953242 -66.863926 17.998725 0.693574 1.155260 0.453106 0.598595 2.331313 2.381465 1.528077 2.381384 2.427106 1.374355 1.786501 0.970545 0.954705 2.478460 0.468905
+1 0.045401 1 1 1.164420 -0.137023 1.418809 1.227495 -0.329613 1.956492 -0.283318 -2.206919 -0.468216 0.382945 -0.963255 2.338960 4.929295 46.658101 -17.299018 -44.588567 -0.047520 0.644870 1.586273 1.745258 0.798378 0.845175 2.106709 0.715340 2.467308 2.039114 0.889324 1.615468 1.912110 1.583187 1.617782 0.308551
+1 -0.001630 1 1 -1.902654 0.360679 1.801355 -1.721919 -1.515889 2.346727 -1.259403 1.261529 1.473699 0.150607 0.700217 1.703940 29.723461 62.205077 -19.275892 30.076710 -0.739769 1.625449 0.918017 2.353966 0.600956 1.511228 0.466178 2.046357 1.121765 2.254652 0.939375 1.331480 1.182712 0.592244 1.349627 2.431587
+1 0.077130 1 1 0.380296 1.633849 1.011874 -0.450002 0.208905 0.343870 2.029247 1.993093 2.250550 -1.355851 1.320798 -1.413513 -56.083237 9.043985 52.251072 -66.228069 54.846860 2.292562 1.344817 0.338100 0.453000 1.068151 1.155275 0.709903 1.083615 2.314244 1.244931 2.303479 0.315466 0.293292 1.113729 2.190345
+1 0.038248 1 1 2.140668 -0.886758 1.548416 -2.300979 2.027171 0.092406 -2.026501 1.738681 0.496164 -1.897455 -1.782588 1.412182 -55.927751 72.295681 73.517445 57.691214 16.239055 0.321846 1.760679 1.232970 1.518684 2.020372 0.894952 1.711243 0.612914 2.252704 1.949614 1.919239 2.145770 2.465424 1.877749 2.318911
+1 0.051202 1 1 0.413620 0.934584 1.167468 -0.750162 -2.336041 1.792464 -0.352111 0.828804 -0.119763 -0.668003 -2.221394 1.288376 9.735780 -20.740968 6.554956 69.144382 59.631390 2.496453 1.384456 0.547124 1.264219 2.485554 0.453779 0.665636 1.847382 0.444735 1.654602 0.398616 0.530705 2.059787 1.840915 2.003359
+1 0.022057 1 1 1.176710 -0.932965 -2.223147 0.093804 -2.084841 1.398348 1.354525 -0.056453 -1.612344 2.289157 1.924294 0.491012 33.122022 31.815727 -23.068288 41.278256 13.656718 1.801962 2.069096 0.800893 0.364137 1.555771 2.096960 1.101817 2.246044 0.256993 0.775220 0.870413 1.024213 0.696875 0.381115 1.143899
+1 -0.015080 1 1 -0.500598 -1.937033 2.187971 -2.255943 0.243826 -1.793382 -0.925314 -0.865471 1.165709 -2.039444 0.979775 1.983526 53.322038 -66.499545 -7.844633 5.253241 -58.776292 2.077838 1.473095 0.805564 2.360723 1.672934 2.494285 0.952353 1.191233 2.048261 1.617532 0.605908 1.495376 1.780134 1.969084 0.647270
+1 0.006968 1 1 1.632394 0.115883 1.436910 -0.853582 -1.642338 -2.311628 2.115590 1.743078 -1.005430 0.357140 -1.134880 1.830309 -15.151103 55.411891 -42.350678 -37.837559 64.138999 0.387341 2.297473 0.626352 0.847127 1.157927 0.278062 1.645042 1.716095 1.165934 2.105154 1.582318 0.520457 0.813378 0.942468 1.565792
+1 -0.008591 1 1 1.881023 -1.067539 -2.056667 -1.032953 -0.394805 -0.444043 1.395749 0.089713 -0.151746 -0.997968 -1.455687 0.985553 4.636398 73.939143 -54.816091 5.956528 61.363765 0.486860 0.909003 1.610030 0.518274 2.385343 1.458891 0.585991 2.001558 1.943073 2.236299 0.735373 1.669318 2.472688 2.473946 1.104297
+1 0.015265 1 1 2.207892 -2.021491 1.131104 0.692063 1.324542 0.258770 -0.383718 2.113294 0.855552 1.770898 0.035064 0.276364 -50.060835 -22.455468 -9.045270 -73.854199 -17.528543 1.341734 0.278050 1.444102 1.766269 0.688188 0.627680 0.666689 1.548087 1.204618 2.010579 0.550396 2.255571 0.632265 1.235053 0.531598
+1 0.009744 1 1 -1.406216 -1.634498 2.226214 -0.392055 -1.341860 0.854792 -1.589898 -2.170763 -0.705020 -2.319782 1.727414 -0.373902 68.466954 74.102531 -8.758343 -51.473209 -60.224359 1.513060 1.996636 2.466603 1.449815 1.040884 1.881245 0.332956 1.741819 1.508200 1.312357 1.528139 1.182450 0.688978 0.407915 1.581918
+1 -0.024260 1 1 2.210589 0.891749 2.230037 -2.111308 -0.461560 -0.855001 -1.924298 -0.553672 1.397150 0.068107 -0.437242 -2.105141 -15.405354 -17.784551 45.053822 19.584751 60.906315 2.161662 1.804104 2.075406 1.093421 0.622542 2.063366 1.243279 1.547546 1.100946 1.097722 0.911592 2.378867 0.617871 2.314720 2.498794
+1 0.018966 1 1 0.287804 2.213716 1.610674 -2.081665 -1.767693 1.992136 0.312625 -0.027094 1.727201 0.755360 0.161056 1.953494 37.004123 28.299260 -24.342637 73.307434 -21.962972 1.649825 1.104188 1.579002 1.030268 1.216675 2.149460 1.481895 2.454044 1.871803 1.385888 2.119678 0.428742 0.609102 1.183778 0.502800
+1 0.028801 1 1 -0.191796 -0.239508 -1.023681 -0.070827 1.840069 -1.373885 -0.175283 -0.738578 -0.851729 1.229651 -1.797966 2.145053 67.718026 -63.138717 -72.421119 68.258249 16.396614 1.793460 0.928727 2.366407 0.446967 0.931759 1.574517 2.159937 2.066293 0.931494 1.614532 1.930990 1.655952 0.586090 1.413633 0.425835
+1 0.054675 1 1 1.059139 2.255310 -1.461289 1.088723 -0.040522 2.250360 0.173901 1.069025 -1.231044 1.946110 -0.416854 1.250462 -23.501503 -39.764463 -71.330430 -50.530487 34.106810 0.372388 0.720429 0.254650 1.898361 2.257701 0.433021 0.536228 0.382919 2.225971 0.400919 0.998499 0.526706 2.341220 2.392409 0.971167
+1 0.004705 1 1 1.691993 -1.931926 -1.522402 1.256007 -1.797555 -0.375437 -0.079720 -1.538987 0.542581 0.686759 1.714307 0.816942 -49.353326 18.641975 -34.331147 46.413077 64.591091 1.862080 2.228183 1.573618 0.545091 0.851994 1.968589 1.321614 1.866051 1.464994 1.897805 1.913873 1.967366 1.020310 0.347592 2.482514
+1 -0.001605 1 1 0.361092 -0.688155 -1.611784 2.267275 1.706113 -0.245489 2.110668 -0.859611 0.695753 2.079229 -1.474014 -0.724209 9.957904 -37.499437 46.955330 28.234523 -62.375057 1.561356 1.466174 1.492060 2.295475 0.803828 2.439423 1.375579 2.098617 1.958458 2.055938 2.392948 1.022592 0.447510 1.048585 0.819512
+1 0.000834 1 1 2.114336 -0.479045 2.170584 -2.315747 -1.139468 0.112681 -0.557762 -1.365621 2.049266 -0.838554 1.176471 -0.235246 -2.654228 -59.616254 29.620864 -12.133469 72.781695 1.254225 1.012965 0.644913 2.304611 1.342489 1.716172 2.453546 2.498020 0.720038 0.422123 1.878003 2.100461 1.451902 2.362666 0.575335
+1 0.019769 1 1 0.741004 -0.795243 -1.322437 2.145894 2.134339 1.138478 2.108754 -0.041476 0.349796 -2.042098 -1.219156 -0.887827 -72.861860 10.717141 -27.014070 24.519553 50.134908 2.385876 1.414891 1.328092 0.501340 1.279763 0.482074 1.474299 0.790780 1.396763 0.395463 1.551413 0.851300 1.554010 1.738525 2.392844
+1 0.043463 1 1 1.572238 2.246024 -2.028017 -0.166776 0.871344 -1.420281 2.297176 0.030427 -2.256037 -1.337885 1.688508 0.745450 -46.779983 68.829041 9.688869 -59.181147 -7.529269 2.208677 2.235493 0.686737 0.981414 1.369058 0.516104 1.902525 2.488133 1.047545 1.330682 1.263504 1.710512 1.819013 0.650302 0.624647
+1 -0.000284 1 1 -2.068138 -0.607350 -0.699557 -0.048037 -1.542825 2.009016 1.260054 0.245671 0.931489 0.982099 -1.352629 -1.067093 22.671099 33.168821 68.374056 12.754777 19.544446 1.127465 1.303444 2.491093 1.300789 0.616936 2.336488 1.609004 1.273791 1.357744 1.603961 2.026351 2.377263 0.658444 2.463974 2.268074
+1 0.021152 1 1 2.198622 -2.315521 -2.054563 1.348293 -1.125235 -1.006382 -1.496660 0.371510 0.048938 -2.166791 0.092111 -2.272233 -6.769071 -67.770796 -73.768144 -71.190851 45.375175 1.683527 0.531012 0.471628 1.398511 0.526685 1.988206 0.281822 1.826405 1.139854 0.276192 1.708107 1.906180 0.913458 2.245857 1.624574
+1 -0.013678 1 1 -2.197720 -1.375360 -1.399292 1.633296 1.131233 -1.860544 1.251083 0.274194 -0.334824 -0.798067 -1.647148 1.675567 0.618809 50.320256 32.541044 17.318515 72.279431 0.630863 2.411142 0.817056 2.017350 1.847034 1.346605 1.147017 1.411290 1.558027 1.765907 1.342278 0.416606 1.403765 1.076896 1.883193
+1 -0.005410 1 1 -2.043385 0.720736 -2.133978 0.230092 -1.722118 -0.141700 -1.799319 -1.751979 2.206877 -0.227284 1.786597 -0.003567 41.920413 6.386237 -66.508467 -7.806868 39.963962 0.989565 1.118208 0.978828 0.658367 1.176503 1.992889 2.489385 1.840607 1.328751 0.322996 0.842907 2.234974 0.949251 0.807242 1.308774
+1 0.005762 1 1 0.591317 -0.159487 0.856725 -2.079535 1.035986 -0.463851 -1.647595 -1.135341 -1.214572 0.760575 -1.719177 2.165175 32.460449 12.758307 -71.133241 -36.375769 32.450805 1.385142 0.837381 1.619544 0.668218 2.490717 1.737245 1.135934 1.889666 2.359606 0.894220 0.653694 1.391494 1.840956 0.447730 2.497249
+1 -0.037680 1 1 1.819177 0.933039 -1.236213 -0.110994 0.627872 1.609250 2.259365 0.708438 -1.493894 -0.268694 -1.474788 0.409712 39.340386 -6.129576 30.213413 46.840019 40.200877 2.217193 1.356633 0.927329 1.366015 1.115523 0.846500 1.879713 1.587199 1.547801 0.895016 0.541329 0.616905 1.820799 1.419721 1.494605
+1 0.019411 1 1 -0.627709 1.140037 0.023397 2.113072 1.843008 0.898801 -1.764768 -0.688141 -1.375783 0.902125 2.264327 -0.706389 -56.182507 -9.387284 27.921371 74.482402 -74.264180 1.253858 1.591405 2.489579 0.610642 2.309122 0.666630 0.552315 0.757219 2.078620 1.118161 2.431653 1.298111 0.607398 1.787077 1.650500
+1 0.054376 1 1 -1.389816 0.679344 -0.385455 1.186883 0.402858 -0.861869 0.453753 1.584716 -0.099844 -0.475706 1.739814 0.678331 45.785810 22.101903 66.682664 -64.469309 64.321570 1.414399 2.054912 0.905103 1.321921 0.284794 2.288919 0.865025 0.479886 0.702477 2.274119 1.870584 1.151165 1.376068 1.319639 2.421106
+1 -0.011465 1 1 1.108656 0.397366 1.075683 2.277440 -1.798171 -1.312789 -0.645359 1.370750 -0.674938 -0.955781 0.720422 1.997580 72.359560 -52.874525 -62.145546 -30.191279 25.181748 0.319538 1.217218 2.275831 1.387222 2.037184 2.198552 0.808462 1.576391 2.152693 1.819482 1.788930 1.295895 1.601055 0.430374 1.043330
+1 -0.049111 1 1 0.255905 -1.416505 -0.213689 -0.630624 -0.726701 0.842097 1.816560 -0.639432 2.022637 -0.719944 1.315498 -0.951941 -22.705037 -3.560874 2.395840 66.879391 -58.079132 2.335389 1.136551 1.019926 0.644354 1.900647 2.423354 1.317859 1.765268 1.854302 1.999945 1.822679 1.514981 0.531090 1.786481 0.641533
+1 0.003319 1 1 -0.136614 -1.137124 1.810959 -0.529292 1.179749 -1.690604 1.726505 -1.516712 -2.065949 -1.529644 2.073707 -0.029302 74.078014 29.189185 -67.365606 -13.733936 23.745818 0.564521 1.162491 0.493412 0.767965 0.436820 1.383682 1.040520 0.271793 2.028624 2.342786 1.707617 0.420419 2.482271 1.525962 0.598238
+1 0.020869 1 1 1.008031 0.939352 1.187573 -2.138512 -0.583623 2.247109 2.080828 1.844719 1.388948 -1.125916 1.683766 1.162974 -28.478315 14.960825 46.586885 -14.218148 -14.411122 2.009007 1.123774 2.267251 1.189571 1.122486 0.868586 1.830339 2.012064 0.753645 0.518740 1.206017 0.770409 1.016413 2.350848 2.209129
+1 -0.027124 1 1 -0.810107 -1.380452 -2.172609 1.258968 0.856959 1.855509 -1.057051 -0.155392 -1.013893 -0.507826 -0.887794 -1.725815 -32.248449 -49.682784 31.444244 33.407286 26.251884 2.356143 1.200048 1.706021 0.593995 1.517581 1.490989 2.302332 1.285838 1.323878 1.667631 1.126350 0.561763 2.054431 1.825414 2.484421
+1 0.032639 1 1 0.191102 -1.991442 1.928689 -1.056426 0.932029 0.622683 -0.787786 1.495508 -0.884904 -0.278744 -0.740855 -1.419645 -36.514912 -56.124680 62.506904 -46.471434 4.603226 0.871275 2.020003 1.436554 0.907541 1.784694 2.103166 1.914686 2.127118 1.715961 1.157784 2.375604 2.023100 1.739243 0.949600 2.179478
+1 0.053632 1 1 1.749044 0.299728 -0.023194 1.311098 0.486808 1.082918 1.354076 1.825665 1.595830 -1.795840 0.166195 -1.199756 0.267116 -10.580346 -73.874129 -52.493234 46.218652 0.578241 2.249283 0.695605 1.532759 2.336905 1.859945 2.350263 1.375620 0.553096 0.385151 1.485607 1.846598 0.766316 1.980228 1.199147
+1 -0.028603 1 1 1.708902 -0.491363 -2.230921 1.396943 1.308049 1.083130 0.213823 -1.831109 1.167411 -1.714893 -1.230807 1.208044 -66.730673 7.572204 66.028427 39.776153 -32.198744 1.910540 2.203300 1.857364 1.713038 1.531238 1.510620 1.485192 1.614727 0.714550 0.433621 1.615721 1.670469 1.569867 0.496009 1.679931
+1 0.058005 1 1 -2.228394 1.458073 1.409037 1.925352 -0.585751 -0.535769 0.707116 -0.146862 0.982984 -0.631183 -0.710720 0.843291 -53.261261 37.980434 -62.853165 -73.151788 -62.102843 0.437824 0.260464 0.626872 0.588575 0.423104 0.363542 0.547015 1.680824 2.357726 0.795508 2.109044 1.710305 0.589444 1.541613 0.398623
+1 0.005338 1 1 -0.554032 0.059228 1.132424 -0.687498 -0.004085 2.035753 -1.758102 -1.738547 1.761316 -0.797974 -0.094019 -1.531994 8.318050 1.473590 16.626329 -11.293288 -56.288866 1.420516 1.354188 0.338333 2.106196 1.087120 0.475080 0.923633 2.258134 0.960746 0.512347 1.760818 1.316347 1.089454 1.457947 0.471234
+1 0.048841 1 1 -1.501234 -1.101819 1.410607 0.050142 -0.776479 -1.685614 0.766162 -2.069817 -0.563535 0.565851 0.661274 2.217044 31.752299 -39.111350 -44.458964 -71.808515 14.289591 1.602413 0.755888 2.206881 1.298451 1.823316 0.976807 0.447117 1.201285 2.238694 0.481200 0.271300 0.489508 0.402728 2.148438 2.296808
+1 0.047316 1 1 -1.200904 -0.432421 -1.191928 -0.368705 -0.038674 0.322479 0.651591 -0.295551 -0.460814 2.269131 -0.085973 1.750231 44.568312 -40.377237 -20.226223 -42.125202 1.730350 1.105010 1.896251 0.542368 2.328370 2.417805 0.304406 1.149828 1.406808 0.473320 0.592652 1.450837 2.459981 0.403984 0.758521 1.468726
+1 0.009910 1 1 2.245843 -0.350999 0.667130 1.676092 -0.586931 -1.515964 1.072086 -1.624595 -0.979403 -0.445230 0.299084 -1.413001 67.890950 -6.798492 37.742759 -7.452384 -2.218309 2.378125 1.640463 1.262915 0.806936 0.672096 2.425037 0.337897 1.532669 0.818981 0.605935 1.948024 2.182534 1.597400 2.000963 0.932292
+1 0.003160 1 1 -2.189792 -0.075630 1.236840 1.220986 -1.342183 0.139272 -1.318616 0.384818 2.242506 0.105218 1.259528 0.830835 33.090898 -41.282358 67.401578 18.313917 2.004232 0.401900 1.736098 2.100582 1.233244 1.627116 1.942316 0.749242 0.753024 1.326389 1.116227 1.419158 1.045931 1.215605 2.172112 1.940045
+1 -0.042645 1 1 -0.039886 -1.203628 0.911286 0.724381 -2.136935 -2.354607 0.764193 -2.176175 -2.124041 2.294430 0.996917 -2.076230 1.443981 -31.003969 16.292975 -63.974250 -15.223827 1.872135 2.481658 2.474169 0.361354 2.022939 1.281280 1.217214 2.209972 1.496735 2.118398 1.407692 1.822159 1.784838 2.272248 1.922890
+1 -0.020597 1 1 2.053186 -0.923984 -2.071213 -0.456992 0.528671 -2.194404 -2.188805 -2.345194 -1.259083 1.930763 0.825784 0.965895 -12.421395 33.615491 -74.450068 17.708087 19.817214 2.393698 2.382440 2.164651 0.282607 1.526729 2.238497 1.664958 1.191828 0.802051 1.822941 1.418423 2.182402 1.637270 1.604396 0.328430
+1 -0.020986 1 1 0.436783 -0.882464 -1.680938 -0.756829 -1.295444 -1.293041 1.390326 -1.529645 2.043760 0.872254 -0.271755 -1.080610 -8.415122 17.037170 -6.288437 60.245584 47.530531 0.559491 2.109669 0.963108 1.959995 0.877274 1.597386 1.766371 2.402862 1.143031 1.920025 1.861503 1.529087 1.364492 0.270079 2.467241
+1 -0.012782 1 1 -1.380582 0.360156 -2.283530 -1.588471 -1.745447 -1.108717 -1.422802 2.332969 -1.572365 0.345492 1.028778 0.922369 -47.908711 -1.704240 6.833276 -53.123541 -47.349335 0.620786 1.807030 1.760521 0.821442 1.482879 0.996144 1.441951 1.624474 0.279241 1.207740 0.487336 2.151737 1.496935 0.992803 1.543121
+1 -0.028796 1 1 -0.547246 1.024473 -0.750418 -1.927320 0.491674 -1.957397 -0.785398 -0.787513 1.375233 -0.729031 -0.609190 1.357223 -58.049002 -29.583699 36.763435 33.050910 36.641095 0.278232 2.245288 1.055470 1.790198 2.353449 0.918675 2.171730 2.256934 1.039381 1.377351 0.394309 2.406320 0.772013 0.973692 2.094471
+1 0.039827 1 1 1.794662 -1.113641 0.648430 -1.592030 -0.304319 -1.747064 -0.000003 -0.053274 -0.029853 -2.223719 -0.094792 -0.387709 32.018302 -68.392218 -18.012527 -36.548735 -24.583228 0.320310 0.706864 1.758754 0.386319 0.868003 1.033159 0.305608 1.104933 0.601208 1.254373 1.243397 1.277838 1.877289 1.340088 1.851835
+1 -0.046194 1 1 -0.687316 -1.656060 -2.030106 -2.298891 -0.576486 -0.320959 1.333160 -0.992681 -2.130136 -1.175711 -1.126157 2.340806 -57.797702 -5.981003 -22.720081 43.603180 -61.349687 1.312036 0.644297 0.956840 2.353984 0.916339 1.155246 2.471649 0.750048 0.809515 1.262463 2.219797 2.382408 1.629626 1.379218 0.274595
+1 0.006924 1 1 1.353192 1.111191 0.582747 1.887338 1.396485 -1.691579 -0.522510 2.068134 0.551070 1.987620 -0.205120 2.013587 -64.369600 -59.866504 23.667413 -21.783912 27.791507 1.252774 1.380116 1.868820 0.757952 0.896048 2.123154 0.356220 1.231125 2.014833 2.301270 1.446388 1.944971 0.379404 1.639693 1.822504
+1 -0.021654 1 1 -0.855871 2.294459 1.488170 -1.683509 -1.543222 0.061563 -2.034705 0.517736 -2.201648 -1.418534 -1.319593 -1.894882 -30.425590 -12.892693 62.513510 64.557744 72.011608 0.611529 1.465438 0.372332 2.039213 0.296696 2.076903 1.501079 0.889661 0.536922 0.802781 0.597067 1.407719 2.281622 1.973766 0.593898
+1 -0.005607 1 1 -0.218545 -2.129173 0.872230 -0.677297 1.796217 1.450362 -0.957885 -1.651530 -1.289195 0.067247 -0.748682 -1.021452 -9.922016 40.673020 41.454191 -29.416145 2.852318 0.458549 2.080548 2.013114 0.400678 1.442472 1.370694 0.999585 0.773565 2.301227 0.721289 1.199091 1.368612 2.007608 2.370301 0.642803
+1 0.028950 1 1 1.918002 -1.595867 1.172258 -0.359035 2.261044 0.668163 0.198323 1.557783 -0.378952 2.107582 -0.893068 -0.829638 7.324072 -54.320131 -58.437801 35.883595 -54.416355 0.989924 0.410886 2.002751 1.732791 0.524160 2.314757 0.875475 0.612429 0.845728 2.393571 0.250320 1.120987 0.424793 1.753252 2.408735
+1 -0.002161 1 1 -0.789255 0.360492 -1.337246 -1.709237 -0.425084 -0.409440 -1.375663 -1.781335 -1.089296 -0.161684 1.626516 0.289576 -31.821009 -65.696827 -16.563819 11.900010 53.469642 1.589104 2.079614 2.076440 0.476542 0.743405 1.649875 1.946019 2.243877 2.083342 1.730140 0.958202 0.498333 2.487620 1.436775 2.384837
+1 -0.016365 1 1 -1.346891 1.113955 -0.077483 -1.639242 -2.123383 -0.769359 0.178265 -0.986852 1.582355 -2.082696 -0.247696 -1.986792 -1.026992 -10.663148 34.466325 -24.483040 -36.456772 1.690556 1.669336 0.532172 1.971356 0.572257 0.672357 2.305199 2.230058 1.585427 1.027026 0.730587 2.233698 2.013518 0.446612 1.702352
+1 0.027967 1 1 -0.231126 -1.522571 -1.578032 -0.658355 -0.280121 -0.325176 1.133764 -1.722924 0.453761 1.707529 -0.001664 0.305245 -48.879108 38.827030 65.899380 -29.112298 9.608740 0.536281 1.276346 1.553715 1.282080 1.162959 1.603460 0.346095 2.067618 0.701785 1.908547 2.444240 1.339584 2.384247 1.045712 2.033564
+1 -0.006673 1 1 0.696497 0.454791 0.182553 0.407152 0.618474 -0.840174 2.224331 0.958272 -1.262369 -1.453212 0.179539 1.582726 -18.102431 -47.552585 -16.304429 21.453784 -26.249818 0.914758 1.593402 2.306310 0.647498 0.754631 1.330315 1.857951 0.332839 2.026829 1.421117 2.467297 1.863567 2.463851 2.449189 1.274988
+1 0.046883 1 1 -0.179521 -1.279896 0.836267 -1.921157 0.400220 1.926242 0.230331 2.299154 0.288034 1.361281 0.408577 0.995624 -7.846357 -23.728196 50.217324 -47.432488 52.168639 2.099786 1.358499 0.794442 2.194438 1.424018 1.723308 0.887740 1.995583 0.512534 0.411567 2.213520 0.374570 1.401370 1.321631 2.146638
+1 0.037957 1 1 1.167336 1.747935 0.504294 -1.920612 0.141415 1.713946 -0.546649 1.632995 0.800491 -0.016532 0.179664 -1.034386 -29.379432 19.882096 -41.610204 -42.702437 50.144233 2.486915 0.833565 0.477979 2.386308 1.924690 1.516908 1.415248 0.582012 0.367252 2.157731 0.979616 0.399615 1.586240 1.191885 1.754646
+1 0.025849 1 1 0.718543 -1.294297 -0.868604 0.351816 -1.072617 2.126667 -0.583691 1.093586 1.574719 1.525868 0.445640 1.885845 -4.374674 -25.150606 -6.240738 -38.091978 -11.869066 1.624153 1.640627 1.776963 0.421997 1.998243 2.465441 2.159093 1.372203 1.624895 0.606572 1.408793 2.340959 0.255485 2.430356 2.002285
+1 0.048741 1 1 1.283954 1.391621 1.388863 2.149999 0.433520 0.825123 -0.724971 1.642781 0.326243 -2.052456 -0.932730 1.725063 -69.789009 56.120985 25.396726 -57.224141 33.869148 1.206587 1.353196 1.659585 0.886266 1.979609 2.034214 1.778670 2.102508 2.093788 1.790255 1.067877 1.057232 2.154373 0.795391 2.380513
+1 0.012072 1 1 0.749350 -1.882826 -0.973782 -0.221303 -1.358964 0.844181 -0.856322 -0.564727 -0.608043 1.796892 -1.330145 -0.166075 -47.221893 -8.362907 -5.377175 -74.182146 20.673425 2.248875 0.598322 2.253451 0.996122 1.068176 1.577019 1.452461 0.515415 1.573228 0.739437 2.466632 1.932223 2.115722 1.448798 1.953775
+1 -0.018377 1 1 -0.099105 -2.176192 2.308200 1.535552 -1.726973 -1.635160 0.516907 -1.982372 -1.141741 -0.390583 -0.174316 1.384083 61.510101 0.263611 -69.491775 -48.266819 -20.434993 2.111209 2.095849 0.427034 1.161510 2.007010 1.319370 2.402411 0.322445 0.582758 1.671349 0.615438 1.909125 0.912618 1.624935 1.281872
+1 0.001517 1 1 0.624853 -2.008815 2.119527 1.946611 -1.432419 0.925658 1.945448 -2.113584 -1.026047 -2.133747 -0.611094 2.349068 12.386172 -25.609496 -68.805980 -72.103975 -1.513529 2.306801 2.154584 2.093407 2.135812 1.591235 1.882395 1.663018 2.340740 1.074994 1.417802 0.748627 1.680012 2.207677 1.173830 2.060551
+1 0.009767 1 1 1.543594 1.476622 2.149379 -0.564833 2.316434 -1.449442 2.275731 -2.244688 0.919161 1.134802 1.579816 -2.348146 30.999103 51.926945 36.164606 18.530614 44.034124 1.097934 2.222445 1.889023 0.560772 1.139718 2.485623 1.616153 2.190816 1.288736 0.526990 0.377894 1.021709 1.358866 2.467252 1.112934
+1 -0.021773 1 1 -0.971738 1.141329 -1.816880 -0.016894 -1.194586 2.081134 2.260951 -0.904659 2.269356 -1.008444 1.536512 0.262179 11.553751 -66.113666 27.616737 54.501373 -45.423845 2.296661 0.489897 2.456586 1.845878 2.171753 0.395290 0.891735 1.646847 0.551831 1.615791 0.605277 2.148116 1.380019 2.482790 1.250065
+1 -0.010242 1 1 0.575757 2.217688 -2.313547 -1.862973 -1.879797 -1.892959 -1.622624 -0.855084 1.392850 -1.524722 -0.039864 -0.842048 -31.521613 16.244592 22.863244 -37.450128 -24.295559 0.843142 1.687634 2.069926 1.241584 2.306001 2.202411 0.424510 1.495581 0.725594 1.553207 1.756399 1.295948 2.490009 1.084271 2.096049
+1 -0.073857 1 1 0.408153 -1.407972 1.833862 -2.012562 0.400922 -0.428069 1.260964 1.407363 2.072839 -0.485610 0.204459 1.005834 54.434236 26.210150 -36.007662 69.226227 -64.799297 2.398220 1.889859 1.102716 1.601715 0.276119 0.479786 1.260713 2.052758 0.712927 2.421348 1.344494 1.664004 0.912776 2.027182 0.596745
+1 0.028809 1 1 0.549078 1.498991 1.112823 -0.259429 -1.255957 -2.085641 2.091175 1.373077 0.742198 0.427223 -1.349386 1.603716 -38.689682 -7.482810 -63.585059 -74.087622 -40.669097 1.742356 1.528632 0.472183 1.737637 0.971014 2.074227 1.533082 1.009945 1.642568 0.634513 0.766383 0.844476 1.615582 1.594030 1.607345
+1 -0.012508 1 1 2.125990 2.177563 1.891144 -0.600666 -1.457978 0.189381 2.069520 0.277862 0.049062 -0.084753 -1.308628 -1.389819 19.615550 -21.442752 61.673723 50.267023 37.854380 2.403524 1.021635 2.367884 0.526529 1.621724 1.311756 0.438609 2.197687 2.031258 1.594031 1.626504 0.657058 1.668820 0.850702 0.496018
+1 -0.009138 1 1 1.920455 1.931593 0.633726 1.042002 1.681270 1.615337 0.892237 1.008050 1.253688 1.642641 -2.024656 -0.229843 37.802380 -55.393413 52.908836 38.808868 60.651022 0.800931 1.003743 0.915738 2.314113 1.304524 0.382138 0.337016 2.472958 2.499966 1.933332 0.506449 1.646646 1.687198 1.488175 2.260114
+1 -0.039934 1 1 1.978191 1.552282 1.413068 -1.007842 2.233733 -1.257596 -1.351010 -2.136603 -1.483523 -0.325205 0.655677 -2.308898 27.674904 -17.896669 -39.307757 -45.473599 -24.783107 1.679925 0.745046 2.234293 0.759912 2.348811 1.717838 1.197610 1.229936 2.279845 1.357162 0.815022 1.579186 1.880954 2.199501 1.016232
+1 -0.000560 1 1 0.302741 -1.213187 0.465940 -0.940830 2.254005 0.168140 -1.500932 -0.752232 0.583575 1.660280 2.276709 0.052641 -37.676012 -70.734630 63.080059 -13.444312 -58.547948 1.144625 1.707057 2.263620 0.913572 1.909622 0.263949 0.691756 2.086659 1.227900 1.817715 1.339490 0.815520 0.947034 1.808277 2.459320
+1 -0.003694 1 1 -0.020531 -1.057382 -1.000585 1.675489 -1.290089 -0.833034 -0.288563 -0.823619 -2.282850 0.402643 0.222989 1.425607 -73.798990 10.370492 -3.132788 -2.767333 -10.562301 0.316188 1.175787 1.196557 1.538950 0.639895 1.212995 1.056706 2.301229 0.755785 0.484776 1.887971 0.872727 1.675091 0.510156 0.945624
+1 0.017052 1 1 1.110992 1.961472 -1.414493 0.618595 1.204540 0.275817 -1.328802 -1.158866 -0.753849 1.669828 -2.184511 -0.857254 -66.747187 30.022149 -17.744499 -31.787245 51.780295 0.946256 2.230954 0.891440 1.188887 0.869384 1.738911 2.133942 1.666627 2.244496 1.238925 0.355401 0.975649 1.230495 0.432383 1.053535
+1 -0.013483 1 1 0.863821 -0.634292 -1.119623 -0.939789 0.896984 0.685752 -1.062178 -1.504937 -2.078123 1.208631 -1.646914 0.889002 -48.671688 74.939212 -46.667548 8.521551 -28.288387 2.231102 1.136859 1.683792 0.487353 2.436850 0.885673 1.005789 1.552764 1.056736 0.566161 1.718787 1.409148 1.544075 1.276729 1.235276
+1 -0.006044 1 1 -1.843095 2.355649 -2.100819 1.470436 1.854727 -0.061728 -0.735603 2.022448 0.817258 -0.959618 2.210054 1.332783 66.973547 24.411558 35.057828 16.910466 -35.794206 2.226698 1.370122 0.388483 1.226676 1.485753 2.054631 0.688092 1.260474 0.290067 0.914533 2.305283 1.386093 1.059449 1.167777 1.582063
+1 0.010680 1 1 -0.245242 1.564825 0.170234 0.696056 -2.249789 0.001492 1.519628 -0.764285 0.629870 2.195465 1.172269 -0.167919 16.294002 -46.714758 -34.939635 19.559405 -65.086877 1.897999 0.671758 1.235321 0.536681 1.252671 1.883623 2.053707 0.902277 1.075858 2.450290 1.768995 1.489793 2.458940 0.911826 1.803194
+1 -0.012489 1 1 -2.187995 1.847856 2.274353 -1.848777 1.096328 0.538045 -0.144990 -0.546142 0.725676 0.774492 1.261159 -0.033727 -43.478907 50.013549 -22.284156 20.195369 -26.435546 1.341583 2.233309 2.215171 1.134659 0.712456 1.243627 0.641995 0.502886 0.261644 2.454045 1.888954 1.650951 2.028742 2.060506 0.418503
+1 0.017809 1 1 -0.269791 -1.053103 0.222697 1.237410 1.380115 1.207996 1.810431 0.009956 -2.314998 2.021581 0.392741 -1.265417 -27.056126 67.685710 -6.278570 -73.919130 -58.815167 1.277294 1.738275 0.435464 1.088297 2.264569 1.119563 1.246354 1.475561 1.751589 1.460015 1.471629 0.911411 1.583844 1.414678 2.251902
+1 -0.016359 1 1 1.598444 -0.275739 -2.073172 -0.400226 -2.013723 -0.266303 1.019196 0.097850 -0.060130 -2.157768 0.937259 -1.012218 -19.933001 -63.949700 -52.606683 -60.513821 -55.789234 1.380147 2.380811 1.795630 1.401719 0.441472 0.822932 1.767395 1.614820 2.282467 0.418137 2.385857 1.105936 1.709483 0.286740 1.242493
+1 0.024071 1 1 -0.421397 0.304161 -0.908214 -0.917005 2.123065 0.148143 1.705240 -0.779728 0.273721 1.142231 -0.792089 -0.139735 -55.786909 39.414717 43.153834 36.491988 -29.165131 1.699662 1.722120 1.179958 1.559710 0.804170 1.428303 1.747179 1.591250 2.133944 1.701951 1.940303 0.663546 0.472772 0.370575 1.752783
+1 0.071752 1 1 0.112219 1.107607 1.618333 -0.586571 -0.178374 -0.858557 -0.433971 1.029446 -1.998469 1.636858 -0.254279 0.469477 62.457984 31.344213 2.191643 -65.054749 -25.173783 2.188525 1.038082 2.043119 0.708352 2.015906 2.333119 1.234510 0.406637 0.341579 0.412333 1.581855 1.738893 1.829072 0.960743 0.455874
+1 0.005730 1 1 1.202889 0.800227 0.261372 0.930956 1.450315 -1.745587 1.250929 -2.318717 0.776379 -0.007219 1.191949 0.730138 11.779589 -20.441188 -55.046871 27.246663 -15.327937 0.375357 1.133056 0.775075 0.684831 0.451467 2.309397 0.792760 0.914082 1.474043 0.993012 0.551551 1.416636 1.397294 0.316931 2.415909
+1 -0.012438 1 1 2.022553 -2.124405 0.888978 -1.923987 -0.033178 -1.568788 -0.795462 -0.283532 -1.104948 0.661662 -0.688704 -1.415713 -32.939469 36.341335 -11.190854 15.312016 -50.941513 1.764988 1.652029 2.157037 0.571675 2.143455 1.805248 1.047575 1.845279 1.103266 1.832755 2.117825 0.778504 2.074326 0.954366 1.279798
+1 0.038390 1 1 2.218443 0.957592 1.434418 -0.316614 -1.044430 -0.083681 -2.130912 -0.088111 -1.199570 -1.575907 2.066399 -0.336874 -72.054851 74.119904 -16.765115 -71.289154 43.180884 1.991664 2.140395 2.112405 1.943043 1.728411 1.156381 1.289737 1.601702 2.310457 0.607380 1.489356 1.854386 1.162125 1.086749 0.994811
+1 0.002837 1 1 0.526450 -1.816878 0.011062 2.130680 0.897543 0.643659 -1.670112 2.132995 2.100880 -0.445258 -0.177602 -2.006346 38.072545 -14.741759 35.261226 -14.574878 -9.967995 1.643577 1.851861 1.475135 1.337145 1.894726 1.914065 0.687708 1.551495 2.225233 1.492909 0.825146 0.726140 1.741580 1.986968 1.973351
+1 0.009997 1 1 0.564080 -0.828308 -0.978378 -2.074763 1.133762 -1.764636 1.541199 -1.070987 1.255134 -2.332493 0.147496 0.242150 -53.499836 -71.747548 -11.041057 -17.042040 74.435571 1.954650 1.054701 2.366463 1.398893 2.438700 0.477658 1.504808 0.561763 2.046806 1.924724 2.085936 0.317442 2.000370 2.213069 1.798878
+1 -0.023628 1 1 -2.056538 1.142578 0.316987 -2.108715 0.707655 -0.504988 -0.319116 -0.678368 -2.059257 -2.141647 -1.435134 -2.292697 -4.872759 3.531999 -37.687866 30.029879 -37.815812 1.069732 0.744643 2.210758 1.211181 2.076979 0.536261 0.940043 1.309189 2.293582 0.487465 2.078884 1.060379 1.036937 0.795469 1.452340
+1 0.054917 1 1 1.297198 -2.211683 -0.432594 0.610153 0.675559 1.980209 -2.224851 -0.269546 -1.654379 -2.052235 -1.942203 0.108738 -26.955155 -35.297208 9.822325 -66.190284 -60.097277 2.051019 0.718108 1.740895 1.731331 0.725433 1.095244 2.024012 1.326441 2.001113 1.206290 0.872784 0.378108 2.366618 1.755707 0.926712
+1 -0.013646 1 1 -0.282467 -2.050525 -1.480565 2.261633 1.134362 -1.098579 -0.682753 -0.365144 -1.440376 -0.858649 -1.986583 -1.222158 15.458685 14.114752 -73.368039 53.370014 -10.180025 2.189749 1.362666 1.070729 1.738862 1.310054 1.085015 1.105524 1.545549 1.298743 2.227885 1.058463 0.334489 0.511420 1.932089 2.127154
+1 -0.000321 1 1 1.102223 0.665043 -0.405828 -1.926707 1.368616 1.158130 -2.194323 -0.837231 -0.152416 1.889935 -2.068243 2.338223 60.340583 -5.813833 -63.092648 -48.142364 -28.708282 2.123684 0.260219 1.003277 2.083953 0.751821 1.353446 1.364323 1.924675 1.266873 2.078877 0.942079 1.777500 0.443222 0.976271 0.429978
+1 0.013894 1 1 -1.354433 1.600176 0.562415 -0.536285 1.461896 -0.310733 -1.159961 -0.309151 1.857824 0.162439 1.646983 0.267177 -14.610237 -4.252388 -69.884602 -50.502706 51.018217 2.322663 1.005662 1.658018 1.559736 1.228061 2.277985 1.592640 0.749695 1.623057 1.219401 0.720806 2.084341 0.524704 2.457205 0.992304
+1 0.007996 1 1 -2.027310 2.291213 -1.227671 2.093154 1.646653 -0.560866 -1.704120 0.763991 -0.857492 -1.389801 0.925303 0.677231 57.563722 -26.517149 -23.728193 50.265456 11.524909 2.112121 1.660261 1.006277 0.743427 2.034304 1.049288 1.388401 1.613160 1.373650 1.178694 0.568121 0.902797 0.806406 0.766213 2.485161
+1 0.009481 1 1 -0.725642 -0.200957 1.303057 2.005228 -1.140111 -1.272885 0.861743 2.149749 0.949306 -1.162738 0.130789 2.202559 -67.376957 -54.515774 -46.608190 -43.849985 -36.703110 0.337517 1.903566 1.978812 2.142230 1.451133 0.695007 0.476986 1.457507 2.066880 1.809060 2.128493 2.340869 0.983651 0.723221 2.175187
+1 0.038121 1 1 -0.566950 -0.284363 -0.928491 2.279732 -0.974449 -2.017427 -1.252601 -2.230473 -0.510844 0.219034 0.920832 0.932879 24.633229 10.675692 26.351410 -61.848416 13.679941 0.906536 0.648050 1.029201 1.285199 1.833472 0.658486 0.929811 0.338982 1.778102 1.556225 0.725744 1.836961 0.806275 0.807686 2.020956
+1 -0.004310 1 1 2.146140 1.546710 2.016047 1.633907 1.988406 -1.121260 -0.178825 0.995089 0.195714 0.114431 0.588717 -1.450225 -46.422635 74.781289 -0.882070 25.048927 -52.683773 1.282350 1.201342 0.946430 0.654948 2.211393 0.632101 0.727872 1.590947 1.537628 0.911601 0.283635 0.810516 2.348868 0.419816 1.342431
+1 0.001562 1 1 -2.228170 0.508494 -2.010400 -0.955792 0.537492 -0.016632 -1.507969 -1.211796 0.283680 -1.125504 -0.817214 1.705460 -57.044771 48.540803 -24.730864 -1.635230 -33.314061 1.983709 1.194544 1.448536 2.042356 1.377172 1.877232 0.391684 1.036899 2.409861 1.775298 1.681419 1.116411 2.277804 0.802688 1.282989
+1 -0.044407 1 1 0.382368 -1.243574 -1.310015 -1.135015 -0.448672 -1.015756 1.176864 1.649620 2.176408 1.331686 -2.200352 1.519927 -14.330750 43.090614 23.947313 32.488949 41.757933 1.008637 2.167602 0.386049 0.831065 1.208910 2.155937 2.332107 2.216448 2.333018 1.776422 0.330334 0.430122 1.303004 1.831016 2.139135
+1 0.017892 1 1 -0.108108 2.006381 -0.610157 -0.758136 0.314217 -1.546551 0.657633 2.286572 0.875937 0.373469 -0.005542 1.107639 68.688106 41.004950 70.201725 -19.614215 43.888779 0.455540 1.011956 1.685860 1.493030 0.602561 1.491505 1.983591 1.459655 2.176627 1.320765 1.094639 0.847932 1.198164 1.543035 1.795260
+1 -0.025212 1 1 2.202806 2.025163 -0.677071 0.892444 -0.225807 -1.662800 -2.208423 -2.198342 2.316253 0.209946 -1.013999 -2.285079 20.569723 -34.665076 -15.929538 22.256667 -32.190251 1.801835 2.192136 0.973516 1.389132 0.397394 2.493999 0.642188 1.501262 1.711186 1.909950 1.284122 1.739867 2.438563 0.425450 1.533279
+1 0.076571 1 1 2.195815 2.338658 -0.206126 -0.747483 0.287205 1.564256 0.027038 2.030415 -1.934680 -0.682156 0.239580 2.238685 59.388391 40.688952 9.224023 -71.840172 -67.775166 1.416803 1.956158 1.650251 1.527031 0.567221 1.541244 0.936632 2.474247 1.669287 1.953671 0.348218 1.753948 0.604729 1.932255 0.405854
+1 -0.020230 1 1 -2.184204 -0.410043 -2.073252 -1.747743 -1.995653 1.846464 -2.278864 1.433561 -0.586932 -1.541117 -2.267921 1.566495 -1.083850 -66.260487 -40.004620 -57.641457 70.030415 0.642688 0.904893 2.279276 0.797302 0.761801 0.339559 2.476036 2.481989 1.293367 1.862170 1.486581 2.463256 1.436753 2.003208 0.413365
+1 -0.052747 1 1 1.414572 0.705429 -0.230987 0.813059 -0.840141 -1.933295 -0.967166 -2.132952 -1.381186 -0.363398 -0.377248 -2.241051 24.908084 -19.823940 -30.965105 69.487623 -21.522480 2.450058 2.382105 1.029806 2.442824 2.295645 1.399214 1.093831 0.768937 1.025180 1.196361 0.483556 1.621797 0.294515 1.416001 1.986605
+1 -0.023889 1 1 -1.915646 -1.224434 -0.054865 1.518813 -0.315684 0.444691 0.079769 -2.354314 0.978281 0.437620 -0.956650 0.255483 29.038701 -46.559749 20.305686 27.668506 24.587801 1.332608 2.137783 0.972469 1.781915 0.389274 1.032497 0.430896 0.814239 1.910929 1.975514 0.714642 1.986764 0.789778 0.296658 1.438547
+1 0.012155 1 1 -0.760159 -0.705718 0.085350 1.917630 1.574095 0.459838 0.184691 -1.363365 2.272124 -1.607489 -0.947733 -0.669505 25.994248 -64.680290 -31.632987 -55.619058 10.498780 2.169992 2.304764 1.674105 1.935391 1.369632 1.153849 1.486929 1.573025 1.823913 2.014548 2.013451 1.579687 1.299993 0.732611 0.251562
+1 0.008614 1 1 -1.362759 -1.688976 0.804741 0.718964 1.066774 -1.361220 0.615495 0.935341 -0.257813 2.339235 0.061728 0.734866 -8.989875 -42.830095 4.595190 -18.649926 50.698631 0.503389 1.959914 1.780794 1.810163 0.404320 1.899565 2.236438 0.805772 1.367551 2.177738 1.993646 1.715490 2.235822 1.702032 1.048598
+1 -0.044983 1 1 0.166883 0.938659 -1.030026 1.672528 0.782575 0.454540 0.678091 2.122071 2.287961 0.667160 2.188404 0.315092 -31.225057 50.472942 48.741782 53.133239 60.342476 1.764812 0.939682 1.986154 1.784579 2.419996 1.127366 1.884397 1.558162 1.787581 1.119127 0.661821 0.732407 1.312460 1.007657 1.442101
+1 -0.003749 1 1 1.070281 1.021801 1.460764 -0.480766 1.516870 0.013779 0.684518 1.752234 2.074552 0.032898 1.562229 -1.049583 -59.461908 73.717131 -36.180467 14.894640 -15.789848 0.925469 1.607428 1.788724 2.328107 2.489622 1.329261 2.141714 1.786215 0.672091 2.328150 0.965849 0.766583 1.959672 2.213919 0.342776
+1 0.015980 1 1 -1.041024 0.610786 1.890072 0.220180 1.340216 -0.203069 -1.209779 1.195517 -0.576780 -0.565473 0.987554 0.788041 -60.856469 35.324473 -1.574708 -66.122805 24.021110 2.466909 2.093289 2.412176 2.437781 0.782356 1.554712 2.297536 1.690044 2.062335 1.921773 1.990805 1.206237 2.232808 0.558530 1.707405
+1 -0.069305 1 1 -0.464011 0.370017 -1.472589 -0.338429 -0.130958 -0.323066 -1.090462 -0.907465 2.246810 1.768527 -2.112719 -0.612409 -28.732527 -57.582897 4.242916 60.688033 -16.222803 2.025141 2.298347 1.819120 2.445626 2.136904 1.954703 1.939676 1.383395 0.726305 2.261017 2.165796 1.533761 1.178786 2.103531 1.295110
+1 -0.004178 1 1 -1.257731 1.096449 -2.130220 2.125947 1.456542 -0.765504 -0.996737 0.379481 2.076734 -1.003395 1.586742 0.966966 -39.407900 71.427734 35.918433 -68.895539 72.679774 0.309394 1.735334 0.505561 2.469991 2.147669 0.621946 1.053606 1.957422 0.397071 1.578531 2.122375 0.765161 0.564427 1.820872 0.396704
+1 -0.041730 1 1 1.224352 -1.316957 -0.008812 -2.019608 -0.210519 0.814818 0.441580 -0.372949 -0.682705 0.442474 0.512837 0.297514 14.853433 41.642214 -19.301983 41.565631 43.567458 0.449114 1.008629 2.028858 1.767026 2.148814 1.874034 0.641544 1.928391 0.721252 0.589033 1.379564 1.578348 1.301167 2.469414 1.435102
+1 0.002660 1 1 1.466284 -1.952180 2.078144 -0.864901 1.327346 0.249525 -0.265272 -0.513377 0.050581 1.880303 0.979001 -1.592729 66.544613 15.318216 53.264638 18.763874 64.432319 2.334697 0.760290 1.945848 1.614804 2.007409 1.272573 1.136809 0.847049 2.104925 2.216137 1.609456 2.128944 0.914536 2.363922 1.432970
+1 -0.013940 1 1 2.300239 -0.328455 -2.139605 -0.098614 1.355037 -0.866038 1.071934 0.523134 -1.008854 -0.626657 -0.037964 -1.888587 37.462240 -72.133533 -48.289187 53.632795 56.388066 1.588450 2.326494 2.389707 0.559449 1.417658 0.576112 2.459603 0.803284 2.301870 0.285637 0.694373 1.085333 1.942173 0.598297 1.833644
+1 0.016511 1 1 -0.179657 1.151299 0.804175 0.642412 0.934559 0.739023 -1.101164 -1.709424 1.139410 -1.091942 -2.228913 2.154876 73.024415 21.338841 -8.095544 -11.809350 -29.740115 0.743366 1.007698 2.125889 1.310374 1.964067 1.830008 0.950086 1.346439 0.601007 2.378787 1.528647 0.713026 1.832876 1.902495 1.979399
+1 0.069239 1 1 2.078899 -2.305192 1.891469 0.143289 0.229372 0.327889 2.040150 1.450959 -0.342908 -0.010553 1.709832 0.998238 40.689045 10.785384 69.948562 -74.513388 3.488178 1.012116 2.135617 0.558045 0.319887 0.335738 1.255123 0.354214 1.272780 2.367469 0.305259 1.987891 1.732558 1.096787 0.942676 0.551929
+1 -0.021872 1 1 1.257682 -1.914799 -1.130664 1.990352 -1.398943 -1.931071 -1.290588 0.219043 1.084325 1.437174 -1.118651 1.259179 -10.074073 35.062533 -54.002507 29.862538 -0.318261 2.139819 1.430795 0.872221 2.164590 1.510685 0.328696 2.140255 2.017969 1.009378 1.120516 1.507462 2.417166 0.813683 1.563403 2.108254
+1 0.069402 1 1 -0.251118 1.755667 -1.488481 1.165559 0.155418 1.446506 0.216859 2.067914 1.565817 -2.004252 -1.307810 -1.773178 -20.937956 -4.225814 -73.259144 -66.431187 -58.961409 0.408903 2.426846 1.495214 1.310021 0.524282 2.100502 2.129931 1.757404 2.436818 0.344380 2.490632 0.310766 2.302325 1.168912 0.399323
+1 -0.023235 1 1 0.386216 2.166205 -0.512688 2.213116 0.963058 -0.946774 1.308915 1.507095 0.646542 -0.345375 0.940440 0.626405 16.494703 26.475828 -70.752119 69.142761 32.385059 0.560272 1.735629 0.972572 1.275890 0.632104 0.772159 1.180405 2.319245 2.048035 2.330240 2.345812 0.812590 1.195532 2.310967 2.426838
+1 -0.010776 1 1 1.195907 1.266262 0.922187 0.156283 1.854685 -0.755531 1.673037 -0.085503 0.222169 1.786432 1.926306 1.317137 -53.484512 35.813568 -31.355938 -49.251795 -74.912907 1.956494 0.536400 1.017856 1.856592 2.245773 2.463503 1.103842 0.279087 0.861227 1.885937 0.440920 0.550580 0.853475 2.103408 1.484132
+1 -0.024345 1 1 -1.703212 1.884672 -0.988584 0.756334 -2.319283 0.690053 0.532016 2.182847 1.170410 1.573825 0.641077 2.064399 -30.539190 27.840265 61.328841 -46.168233 0.513474 0.324352 1.131265 2.172875 1.256803 1.586356 0.884211 1.191178 1.127310 0.954272 1.949731 1.623064 1.344198 1.189491 2.027908 1.545046
+1 -0.012072 1 1 1.834627 1.407686 -1.922260 0.721921 -1.083229 -1.870033 1.984487 -1.017575 -1.119488 1.332923 -0.266416 -0.884559 25.751735 59.417037 72.142145 43.029669 49.644235 2.434905 1.950659 1.483261 0.663953 0.552251 1.934300 1.030359 0.495640 2.220405 1.354343 0.687804 0.928879 0.416748 1.541185 2.198977
+1 -0.005942 1 1 2.171367 1.421824 0.076964 2.338000 -1.838204 -0.263744 1.606727 2.266870 -0.373558 -1.480795 -1.599613 -0.508987 -49.849947 71.933033 -21.511016 -35.650488 72.254152 1.008028 0.932742 2.343214 2.149215 1.856064 2.362500 2.286298 1.816517 1.448748 1.105005 1.825250 1.981554 0.976887 1.793808 2.290028
+1 -0.003871 1 1 -0.548314 1.921036 2.269631 -1.105263 0.080905 -2.118227 1.054326 1.477192 2.301353 -0.457231 1.219383 -0.017789 -67.025656 -0.195192 19.411602 0.787128 29.259254 2.279316 1.466387 0.558847 0.294159 2.184464 0.285883 0.333165 0.753455 1.810091 1.442287 0.517120 0.979314 2.088430 1.736137 0.508608
+1 -0.001459 1 1 -2.273394 -0.876082 1.902420 0.418178 2.143883 1.318356 -0.038353 1.000454 0.825779 0.889477 1.747795 -1.838418 27.088930 33.650699 67.302103 -3.553519 -23.991354 1.034807 0.994326 2.390044 1.719370 2.204514 2.016649 1.313908 0.610640 2.269994 2.293458 0.653507 0.485884 0.258817 2.181709 1.232095
+1 -0.048275 1 1 -0.788132 0.385620 1.584384 -0.963921 0.576840 1.570514 1.539534 -0.785048 0.379134 0.963638 -0.625406 2.137800 -62.661203 3.159370 -0.469856 53.122002 21.481228 1.150100 1.475602 2.439251 0.744886 1.794362 0.340590 1.793967 0.458845 0.315344 0.488636 1.498208 2.125109 1.711040 1.696158 1.333419
+1 -0.001828 1 1 -0.224313 -0.109629 0.013147 -0.517418 -1.886317 1.626329 1.849939 -0.420363 -1.163207 1.677845 0.600302 0.045261 64.054919 21.020210 36.663941 10.850071 -42.864266 1.829338 0.926082 0.656668 1.861404 2.119337 1.448454 0.665993 1.095789 2.175159 1.397521 1.891801 2.254695 1.653240 2.254865 2.272064
+1 -0.048430 1 1 0.877279 -0.628727 -1.830627 -0.161199 0.350683 -1.270679 0.238517 -1.486193 1.927285 -1.091247 0.026157 1.371040 -16.211895 -73.321813 -69.718049 48.742265 61.242923 1.521978 1.138335 1.738682 0.537325 0.817212 2.384466 2.471660 0.938433 1.239844 2.310371 1.407798 1.356196 0.336721 2.016653 1.387762
+1 -0.068647 1 1 1.587866 0.998732 0.160559 -1.680891 0.042859 -0.664642 -2.281695 0.970030 -1.567303 0.592519 1.194644 -1.102757 -6.801720 -16.505720 -61.630898 69.490896 33.485547 1.248871 1.028914 0.960577 2.160322 1.779481 2.230774 2.362917 0.300236 0.811486 0.649262 1.142684 0.594048 2.421627 1.532626 2.351013
+1 0.018299 1 1 1.113838 -2.053894 -1.538062 1.959379 1.106550 -2.005860 -0.062452 1.233929 -0.580915 0.623661 1.511682 -2.354673 -11.257561 -55.823598 22.792301 -29.790832 5.487950 1.164564 1.571445 2.283412 0.552758 1.446615 1.263713 0.724101 1.222466 0.492661 1.661498 1.544004 2.321159 0.470160 1.471129 1.523241
+1 -0.027671 1 1 2.049157 2.042772 -1.594912 -1.616147 -0.374374 -1.061441 1.469274 1.168693 0.988415 1.123270 0.971684 -2.052840 64.367984 32.707046 -42.676717 32.414565 -8.411814 2.464641 2.223138 2.282489 0.787793 0.678667 0.356514 1.672514 2.198898 2.122782 0.840732 1.675027 1.673590 2.278345 0.890846 2.455065
+1 -0.019334 1 1 2.103748 0.639531 -0.356284 1.381299 2.264350 -0.319176 -1.693220 0.177637 -2.102303 0.093187 1.684221 -0.623992 74.526343 64.250024 0.149969 -29.478452 5.648892 1.238945 0.695543 0.489459 1.843403 1.075766 0.900440 1.689462 1.284543 2.067303 2.165376 1.229745 1.328803 1.198162 1.510106 1.850016
+1 0.052342 1 1 -1.457458 -0.497538 -2.339841 -0.812869 -0.667667 -1.278614 -1.170159 -2.061249 2.065702 2.077294 -1.004882 0.145210 -15.202613 -60.316815 -44.707931 -56.202275 -41.638964 2.483980 1.001201 0.932242 0.689636 2.469005 1.319047 1.480709 0.532784 1.007019 1.959760 1.427255 2.120715 2.098825 0.950054 0.805322
+1 0.036415 1 1 -1.345609 -0.898371 -0.434562 0.512314 0.930402 1.563847 -2.133402 0.475817 0.124626 2.289550 -0.892460 -0.034056 -69.359729 71.031276 -27.349046 -55.421827 25.353176 0.787326 1.834256 0.340884 2.241150 1.263758 1.473695 1.898739 1.859211 1.253833 1.174469 1.544107 1.809411 1.275982 2.174400 2.134842
+1 -0.017775 1 1 0.195022 -2.093173 -1.977327 -1.172390 -1.864661 -1.975466 1.842143 0.503567 0.007614 0.731531 0.210489 -1.318168 -48.215823 -63.344251 73.181105 -45.172819 -69.570370 1.086873 0.824473 0.666336 2.365081 0.669720 0.733535 2.267038 2.101001 1.521253 2.449438 0.945899 0.730064 2.430653 2.480179 2.369444
+1 0.008130 1 1 1.884110 -1.020289 0.388265 -1.085781 -2.352859 1.869034 0.066374 -1.288821 1.637003 2.176209 -2.019718 -2.060612 -43.304204 -13.751452 29.345982 17.914190 33.790945 1.741074 2.485324 1.091771 2.147161 1.089486 1.991985 0.800862 2.079571 1.347343 2.297737 0.557194 1.762235 0.382949 0.475037 2.453940
+1 -0.045408 1 1 -1.840544 -1.893425 -0.022608 1.728503 -0.925518 0.417068 2.338049 -1.020406 -1.588330 0.628502 -1.936462 -2.349357 -16.985531 -25.819258 5.733202 57.925506 53.974222 0.546234 2.052170 2.066378 2.362481 1.963907 1.380410 2.298711 1.180121 2.044440 0.395792 0.318012 0.319527 1.033182 0.697627 1.766972
+1 0.000636 1 1 -0.415870 -1.058233 -1.168301 0.887230 1.681054 -2.014518 0.512198 -1.024949 2.174328 -0.639444 1.829713 -1.069461 -43.842454 -60.127240 -8.517873 -59.886426 -11.162273 2.060189 1.854940 1.483677 0.912975 0.869081 1.139971 2.245549 0.943275 1.629009 2.254805 1.248575 0.543589 0.356254 1.809433 1.637959
+1 -0.062953 1 1 0.261509 -1.481503 0.639814 -0.315389 0.689574 1.911558 -1.514697 -1.188560 -0.303722 -1.139906 2.178134 2.058276 -6.390091 1.739000 -22.620247 71.510617 -71.066102 2.005241 0.834659 0.864110 0.844139 0.439179 0.538592 1.862000 0.881069 2.381834 0.979009 1.448037 0.407849 0.471667 2.061485 1.125603
+1 -0.014818 1 1 -1.709252 -0.673809 -0.837529 -0.443990 2.287861 -1.005647 1.436982 0.359394 -0.952848 -1.824171 -0.032370 -2.113205 20.298026 48.925515 -8.873375 -34.815729 2.047087 2.205788 0.931127 2.200790 2.431907 1.061700 0.744205 1.598561 1.264831 1.511937 1.120349 0.961523 2.318503 0.834750 2.388374 0.643757
+1 0.053121 1 1 -0.940018 1.756316 -0.008574 1.978134 0.590981 -1.096034 -0.313816 -1.138870 0.730829 -2.157732 1.548854 0.359750 10.525693 55.320953 -70.741982 -60.485789 -34.658631 0.510747 1.868482 1.823290 0.535359 1.525293 0.594185 2.463340 0.611982 2.323655 1.926169 1.618657 1.514843 0.460339 0.669048 0.684243
+1 -0.022895 1 1 -1.924743 1.388009 1.935887 2.121445 1.197405 -1.821001 1.401233 -1.998755 1.546469 -2.030488 0.716983 0.761555 19.235499 41.029585 34.229963 52.992798 -50.038056 2.280800 1.650407 1.883670 0.595634 2.066446 1.261595 1.131189 0.887446 1.562981 1.762521 0.695931 0.268612 0.308930 0.693610 1.752322
+1 0.003110 1 1 2.098926 -0.291569 0.490589 -1.346883 1.258786 -2.203270 -0.404124 -1.562288 0.064457 -0.515754 -2.192244 1.119331 23.253583 72.965946 -61.342822 -38.813026 19.473979 1.362521 0.881396 1.126632 0.798726 2.188585 2.047009 0.822656 1.623956 0.574350 2.105571 1.834316 1.354530 1.587973 1.059371 2.098169
+1 0.034236 1 1 0.965292 -1.085938 -0.284351 -0.720040 -0.304643 2.236012 -0.648263 -0.308117 0.395841 -1.000127 -0.047783 -1.985366 12.331629 -42.305475 -28.124069 -31.228156 -1.613110 1.951812 0.603894 1.404767 2.177035 1.432029 1.366206 2.077624 2.368394 2.354950 1.389005 0.510572 1.179009 1.354477 0.693718 1.321507
+1 0.000409 1 1 -0.087444 0.593456 -1.913998 -1.790150 1.548441 -1.880868 -1.050279 0.564705 0.252658 0.568131 1.269427 2.274062 -64.543062 24.754988 -42.911101 -6.879615 24.301578 1.174448 1.193136 0.280186 1.344209 1.373896 0.821272 0.867647 1.794789 0.772397 0.675839 2.326817 1.054365 1.215101 0.448608 1.502583
+1 0.012035 1 1 -0.399617 -1.201618 1.702080 -2.058652 -1.398251 0.274541 0.789889 0.871022 -2.124331 2.136106 -2.158164 -1.004072 -11.804409 53.299620 6.707734 -63.116998 -7.378516 1.964086 2.139668 1.157096 2.065518 1.416789 1.730495 2.422553 1.342073 1.463980 0.613912 1.022193 0.501544 2.453757 1.540929 2.396930
+1 0.002166 1 1 -0.637208 1.705153 -2.243493 2.143250 0.107237 2.199873 -0.134484 1.682045 0.513612 -0.820218 -1.657683 -1.040407 49.551121 5.682719 -40.546056 -7.560176 -13.880353 0.818614 1.189394 0.391297 1.270478 1.923430 0.588412 2.188639 0.711320 2.408987 0.587919 0.646687 0.621698 1.381779 0.568297 1.619089
+1 -0.009027 1 1 -1.658296 -1.906026 0.241776 1.450011 -2.140207 -0.785471 -2.016089 -2.332468 0.569266 1.496330 -1.197894 -1.674822 -52.122000 -14.453813 74.770225 -36.821342 43.701332 0.449369 0.790849 0.291369 0.296979 2.329784 1.433094 1.262481 0.269526 2.167965 1.985552 0.667983 0.794678 1.647539 0.943694 1.910450
+1 0.001402 1 1 -1.543506 -0.002235 0.141580 -0.217587 -0.166058 -1.209052 -0.714084 0.843329 -1.037978 -0.039567 -0.552981 -1.126997 -74.753179 23.319285 -22.775222 16.837012 -70.339780 0.614653 2.215933 0.427785 0.281519 1.243084 0.518002 2.302162 0.693621 1.942274 2.294428 1.203091 1.094592 2.305283 1.399634 1.402707
+1 -0.041936 1 1 0.275998 1.700595 1.262916 1.230844 -0.583466 0.175835 0.592112 -0.943446 0.697392 1.359424 2.179751 0.970031 -49.462659 -18.906959 -69.263497 38.397833 52.374357 2.212330 0.624227 1.130121 0.942623 1.909294 1.504236 2.193898 1.351268 0.766252 0.895564 0.745550 1.711495 0.348980 1.053994 1.736082
+1 0.014712 1 1 -1.352584 -0.310187 -1.408219 -2.313063 1.566796 0.315943 -0.802627 1.822012 1.455100 -1.431726 -1.558289 1.301651 61.429813 0.869981 71.766396 27.820005 20.824254 2.023672 2.354483 0.297095 2.021266 2.413545 0.708054 1.513764 0.336974 1.776685 2.490644 0.505843 0.447463 0.259370 2.483186 1.163894
+1 0.004694 1 1 -1.561552 -1.716245 -0.393580 1.296489 0.008381 -0.509198 -0.398906 1.310659 -2.170564 -2.074635 -1.422054 0.782994 -61.100608 -17.918447 44.668214 -11.326368 -12.271790 1.345390 0.973081 0.821681 0.985462 1.913485 2.193743 0.986230 1.314909 1.666950 0.924333 0.512116 2.382873 0.454051 0.730221 0.578867
+1 0.014572 1 1 -0.429366 -1.679488 0.052417 -0.245961 -1.096304 -0.134716 -2.224158 1.958933 -1.678320 0.839541 1.272512 2.295311 53.160458 67.810586 -7.489343 -23.387454 -72.947713 2.391724 0.698043 2.011821 1.168298 1.339289 1.927943 2.183508 2.217210 1.648243 1.525315 0.970320 1.669439 2.253766 1.798996 1.719599
+1 0.010653 1 1 1.003671 -1.648819 1.859087 -2.178090 -1.324420 1.797819 0.108892 1.748893 -2.234838 1.525229 -0.878077 1.367949 -19.958156 -36.722732 51.038722 -42.193741 49.801887 1.679605 2.122298 1.713497 2.495463 0.493797 0.488725 0.748910 1.930217 2.153768 1.879630 2.434809 0.337504 1.677444 1.806153 0.504359
+1 0.051768 1 1 -0.169163 -1.548693 2.347012 -1.172555 0.080111 -1.309595 1.207911 0.394241 0.389177 0.094131 -1.307324 1.669094 -12.348842 53.011171 -41.253744 -51.681728 35.204185 0.276157 1.121435 1.202043 1.482901 1.373318 2.359691 2.322865 2.140386 1.976021 2.482663 1.361165 0.604519 0.654666 1.964182 1.499214
+1 -0.013665 1 1 -0.481265 -2.168632 2.139191 -2.136694 1.700448 -1.215923 1.618124 0.618592 1.152870 -1.064580 0.541751 0.872952 64.969291 -61.120721 -55.961249 -40.707496 -20.886874 0.689651 0.464409 1.567932 1.741192 2.216321 2.456515 0.644006 0.558241 1.352777 1.366926 0.680499 1.896464 1.865213 0.887302 1.386961
+1 0.006080 1 1 -0.043824 -1.423093 2.166126 -1.830405 -1.149798 0.856762 -1.467792 0.174994 0.598695 1.319976 -1.087430 -1.798797 73.567242 -5.364292 -7.657814 -4.879806 35.102206 1.566569 1.329304 0.618856 0.863458 1.145872 2.417919 2.220301 1.850365 1.089681 0.775615 0.762370 0.909650 1.232031 1.486673 1.768670
+1 0.014971 1 1 -1.322365 -1.355400 -0.514555 -0.899299 -1.882488 0.008203 1.206323 1.968650 1.417767 -2.134844 -0.190516 -2.296497 62.209825 60.524899 -58.020267 3.367460 46.901731 1.785910 2.285678 0.386827 0.404215 2.384265 1.336019 0.980509 1.911094 0.265202 1.497497 1.425946 0.368014 1.463324 0.838376 0.328351
+1 -0.052264 1 1 1.547617 -1.589269 -1.029828 0.278092 -0.793378 1.760843 0.680298 1.517691 -0.331002 2.183857 -0.707885 1.360557 -74.471494 -42.392163 14.916290 48.092887 -52.854801 0.915516 0.823117 0.373329 0.793734 1.532606 2.016242 1.227861 1.153826 1.100651 0.643953 1.917631 2.128637 0.253682 1.380087 1.365915
+1 0.002723 1 1 -0.444982 -0.254099 -1.212630 0.410975 -1.109041 -2.148612 -0.689911 1.860264 -1.246836 0.428146 0.032191 -0.891518 52.431302 -37.106197 56.138685 22.875848 24.372513 1.057375 2.297340 0.644880 1.747011 1.018351 1.170486 2.101584 2.330231 2.199109 1.169635 1.312669 2.278907 1.338164 1.027778 2.106636
+1 -0.032445 1 1 1.007715 0.331155 0.398396 -0.471274 0.817692 1.621596 -2.292534 -2.134957 -2.095931 -1.204573 -0.841792 -1.399185 -41.003317 -42.742908 -30.056085 47.384143 35.285182 0.445831 2.088719 2.097510 1.350326 0.680093 1.816790 1.545928 0.908494 2.057988 0.849108 0.704266 0.848761 1.621175 1.091035 1.029477
+1 -0.004000 1 1 -1.304020 0.660954 1.550207 -0.475338 -1.505164 -1.190984 1.360142 0.104150 2.147054 -1.930077 1.280582 1.264493 -16.913779 -19.875933 -4.797624 66.327636 -31.418063 0.724202 0.671203 0.914191 1.063496 1.681088 2.298341 1.718430 2.146213 0.896632 0.691431 1.122783 1.363984 0.723795 0.577002 1.677887
+1 -0.000649 1 1 -0.659873 -2.235774 -0.058050 -0.174320 1.306781 -1.381374 1.192244 0.970964 -0.008993 -0.351958 -1.311512 1.978876 -33.987724 -31.679117 69.080846 41.783958 -37.010748 1.530372 0.457688 1.105237 1.224942 1.604479 1.724409 1.396943 1.168017 1.109616 0.571239 1.558271 1.361573 0.704302 1.460298 1.720865
+1 -0.050292 1 1 1.470055 0.153749 1.671812 -1.828396 -0.362213 0.694818 0.507126 -1.449078 -1.028477 -0.578240 -1.525414 -2.245662 -41.680192 -18.978736 74.391684 51.040127 -18.580802 1.561937 2.231869 0.521993 1.893977 0.571879 1.068470 2.029784 1.576701 0.609262 1.615538 0.846672 0.267995 1.200224 2.413931 0.432952
+1 0.007964 1 1 1.674939 -1.112828 0.180135 2.169009 -0.512971 2.160420 1.220808 0.378170 -1.114877 -1.285505 0.812456 -1.563547 -71.937181 -48.194933 -12.236499 -8.836548 -15.867707 1.546682 2.342671 2.022387 1.005776 1.326449 2.128516 0.477059 0.432923 1.128943 1.401284 2.137562 1.754258 1.322990 2.495766 1.087947
+1 -0.025326 1 1 0.538889 -0.108866 -1.298024 -2.244476 -0.229021 0.868005 -0.993421 -0.428322 1.721207 -1.032458 -1.508657 1.360185 26.627593 -70.047591 60.136961 21.910158 -5.979841 1.327218 1.553836 1.068018 1.172975 1.199666 2.038776 1.954416 1.611338 2.262681 0.873673 1.817829 1.008485 1.855022 0.599615 1.486024
+1 0.049786 1 1 0.219631 1.530792 -1.616114 0.180536 -0.507450 0.704348 0.461292 1.063126 -1.421809 0.186108 -1.117290 0.578880 -58.896105 -16.838030 53.224685 -52.722173 -51.561010 0.836600 1.987984 1.043466 0.289214 2.318246 1.016202 1.060334 0.282800 0.261510 2.456901 0.384418 0.411717 2.474276 2.150656 1.316868
+1 0.024923 1 1 -2.327882 2.261520 -0.768655 -2.127437 1.772307 0.161903 2.062422 -1.212339 0.580953 0.000585 0.413810 -0.587349 28.077501 -1.437337 -7.314133 71.366939 64.141707 1.070108 0.305457 0.817956 1.390648 1.122143 1.863258 1.782077 0.864846 1.974907 1.762377 0.515932 1.265194 0.856949 1.987462 1.268737
+1 0.005897 1 1 -0.005791 1.624015 0.662977 -2.145788 -0.352476 -0.588560 -0.621824 1.089859 0.198294 1.071951 0.811948 -0.667587 1.844599 -47.830968 -45.080153 -12.129540 -11.175097 1.077257 1.212339 1.275974 2.049180 1.313116 0.791364 2.211394 0.648302 0.761093 1.943963 1.443401 1.239783 1.279151 1.442872 1.348832
+1 -0.009763 1 1 -0.258536 -0.398938 0.782008 0.361613 -1.352171 1.919073 2.264658 0.149316 -2.153492 2.124988 -0.519260 0.142397 -19.790798 -73.936186 -45.478638 40.535969 -11.962504 0.567958 0.411869 0.536856 1.937089 0.661910 2.213211 1.932741 1.823854 1.007612 0.677398 1.526736 2.353345 1.416230 1.322129 1.513412
+1 0.046477 1 1 1.069489 1.845702 -0.946154 2.303285 -0.955351 -1.481749 1.216638 0.972045 -0.684529 -1.930184 -0.518652 0.929940 -47.760271 -56.878815 -12.249197 -72.258116 -42.158367 2.039975 1.852096 0.930102 0.728583 2.293738 0.848418 0.367502 1.863015 2.192785 0.640351 2.121751 1.515809 0.952041 0.457158 1.212649
+1 -0.022018 1 1 0.504636 -0.874750 0.737063 -1.044877 1.827205 -0.810169 2.293002 0.562970 -0.635064 0.035984 1.605385 -1.435357 -41.972103 24.865644 16.872548 -73.091150 57.037179 0.983071 2.218708 2.079868 1.844026 0.296274 1.730307 1.519760 2.113537 0.715875 2.462805 0.619548 1.240266 0.394711 2.400940 0.354386
+1 0.026578 1 1 0.611897 1.716522 0.342346 -0.015583 1.985149 0.689556 1.598365 -1.603747 0.694530 0.370525 2.350183 0.286532 -9.915170 5.733562 63.977246 65.568904 -33.435690 0.570387 0.750373 1.765343 0.872649 0.362545 1.787898 1.949348 1.939161 1.726437 1.727320 0.812794 2.371322 2.057744 1.260890 0.533331
+1 -0.003541 1 1 -0.151281 2.117466 0.284985 1.962029 -1.475875 0.980174 -0.725610 0.336103 -1.273343 -2.119518 -1.784667 -0.535344 -50.019160 -72.016159 -25.581595 -49.871848 3.855756 1.430462 2.032068 1.721346 1.663793 1.860992 1.936438 0.961512 2.130788 0.400901 0.694721 2.420343 2.459541 2.002201 1.494038 1.801964
+1 -0.008053 1 1 1.431374 0.354134 0.175272 0.555428 -0.169238 1.899234 -1.295978 -0.835485 0.929411 -0.954915 1.133911 0.749240 30.865199 51.405158 -33.504027 -2.180097 -40.896295 0.714662 2.320373 0.752420 2.418024 1.723733 1.273728 0.289474 2.189146 2.483391 2.354193 2.178414 2.106138 2.354378 0.788099 1.324536
+1 0.016007 1 1 2.167052 -0.412944 1.002646 -0.031751 -1.142217 1.026430 -0.844656 2.300258 0.000817 -0.398978 0.110223 0.546287 54.317502 14.263033 18.801899 -46.483977 -56.200421 1.217767 0.262999 0.473016 2.224870 2.135219 0.616817 0.338305 1.637277 1.717659 0.443300 2.286317 2.125913 1.716358 1.072405 0.661591
+1 -0.024180 1 1 -0.800020 -1.484902 0.066575 2.094669 -1.151685 2.119017 -1.917210 0.762709 1.159334 -0.808364 -0.359885 2.125268 -17.064079 4.018601 40.630088 69.890729 3.476203 2.493172 2.499218 0.611062 0.367999 1.201579 0.438589 1.863955 2.246895 1.071882 0.867579 0.646520 2.311196 1.774177 0.846761 1.760827
+1 -0.046901 1 1 1.298804 1.221860 -0.783382 0.110899 -2.221791 -0.667375 -1.085106 -0.432299 0.860236 0.371826 0.653778 -1.235953 -14.150503 72.493061 -59.131157 -67.355224 10.749880 2.473494 0.257245 0.511021 1.982303 2.309001 0.873913 1.347689 1.367902 1.330262 0.971744 0.848705 0.691579 1.361404 2.368320 1.098542
+1 0.012180 1 1 1.324609 1.381793 1.150867 -1.741154 0.367901 0.651136 1.482822 -2.039475 0.456582 2.006793 1.594576 0.687529 16.750878 -17.999346 34.984865 -9.375158 -68.282321 1.810365 1.549663 0.681462 2.326885 2.212443 0.276035 1.312640 1.785916 2.391351 1.192927 1.276176 0.943008 1.642451 0.922182 0.369264
+1 -0.026826 1 1 -1.420889 1.513248 0.394066 2.152901 2.084173 1.514856 -0.860033 -1.676310 1.637563 2.171771 -1.213549 -0.905950 -18.014702 -73.093966 9.715037 -69.364630 -11.333434 1.659528 2.187511 1.995472 0.901228 1.437102 1.127769 1.906945 0.283132 1.353142 0.760787 1.290716 2.314296 2.121101 1.840399 2.336891
+1 -0.033124 1 1 -0.070998 -1.035682 0.852754 1.853905 0.272764 -0.816716 0.647224 1.703789 -1.612762 -0.030608 -0.776568 1.537192 72.428905 62.611950 69.035379 27.618829 -60.337489 2.242301 0.350423 0.557625 2.257524 1.950705 2.246678 1.918844 2.256701 1.617431 1.160957 1.705251 1.152211 0.954001 1.896239 0.346394
+1 0.019382 1 1 -0.663591 1.257229 -0.097739 1.923611 -1.565860 1.278104 2.026398 1.239789 -1.050208 1.762597 1.889549 0.854950 33.849846 -35.633688 54.612728 26.125185 35.989481 0.253144 1.346359 1.506271 0.391606 1.977680 1.124046 2.350185 2.311401 0.714635 1.878238 1.538154 0.756557 2.201830 1.904184 1.128161
+1 -0.061564 1 1 0.271661 -0.503756 1.528039 -0.766316 -0.514095 2.123453 1.957735 1.756687 1.527324 1.360772 1.262382 1.675087 43.985117 57.863032 53.981478 66.707626 55.074172 1.099118 1.881555 1.041391 1.409638 0.777811 1.672514 2.192294 1.387773 2.298741 1.688978 2.151234 2.031531 1.696951 1.162961 1.626299
+1 0.047585 1 1 0.160964 0.402357 0.143259 -0.282645 -0.327665 1.716465 -0.621462 -2.263476 0.882993 1.142428 -2.200835 -1.888452 -40.435768 46.047294 66.862599 -40.296834 -18.883827 1.667888 0.945531 1.294364 0.619420 1.346294 0.419951 1.367768 1.319946 0.839110 1.425714 0.978941 0.304293 1.508374 1.998783 0.295868
+1 -0.034645 1 1 -1.059492 1.241491 -0.721969 0.276681 -0.956877 1.159661 -0.017902 0.710853 1.407587 1.120716 0.448695 1.391203 -29.258237 -43.182039 -60.525782 43.182645 70.716889 0.456223 1.236301 1.262817 1.406572 1.002751 2.230633 2.252615 0.456590 0.652701 0.451863 2.217732 1.421018 0.803374 1.555003 0.433227
+1 0.006454 1 1 -1.214753 -2.291282 0.069500 -0.590660 1.774857 0.607553 -0.602861 -0.647729 -0.754536 -0.441922 -0.666274 -1.435979 -74.924635 -8.332658 53.013598 -0.463490 10.116296 2.493744 0.855496 2.314905 1.102791 0.610430 0.998586 1.983755 1.961430 0.257552 1.168865 1.856974 1.906908 1.904955 0.571230 1.416305
+1 0.031580 1 1 -0.969390 -1.805142 -0.656006 1.492509 0.552376 0.382015 2.259238 -1.416713 1.001653 2.135211 1.645277 -0.126341 59.405197 23.139097 -51.193894 -15.784548 59.093392 1.864597 1.783702 1.185688 1.109171 2.091270 2.231284 1.947642 0.271205 1.150389 1.832343 1.943484 2.378134 1.793541 2.293397 1.880334
+1 0.009070 1 1 1.449041 0.413230 -0.898537 1.487787 1.296112 -1.626653 2.117647 -1.386537 -0.760930 0.477034 1.743709 0.176774 71.279277 -59.184045 -56.250765 43.385944 37.553963 0.916743 1.193168 0.819719 1.763364 1.354696 2.129404 1.892268 1.098437 1.672388 2.331974 2.242618 1.179552 1.485443 1.344611 1.383872
+1 -0.020830 1 1 1.674908 -1.634581 0.815888 -0.415704 1.732876 1.886594 -1.680181 -2.167395 -0.639631 -1.314974 0.339337 1.245554 50.550473 1.792349 -25.983644 -57.099195 33.837026 2.108425 0.303630 1.614662 1.867224 0.934768 0.388003 2.158784 0.691468 1.752193 0.363097 2.076115 1.773249 1.001462 0.823252 0.393172
+1 0.035052 1 1 -2.283743 -0.457032 -0.150491 1.253328 0.299297 2.168429 -0.828733 1.302054 -0.713318 -0.418422 -1.536817 -0.686008 46.936386 9.834342 -14.210085 -28.899104 -7.238753 1.199265 2.046814 2.062006 0.890277 1.890399 1.182334 0.983180 1.811965 1.445309 1.815003 0.752032 0.404103 0.513625 0.752742 1.085411
+1 0.015474 1 1 0.100861 -1.295340 0.459133 -2.243977 -1.278701 2.086726 1.997017 2.235157 -0.879524 0.601927 -0.911725 1.332995 30.275504 40.393617 -4.473021 -28.062185 -41.136552 0.894586 2.308473 0.996926 1.078213 1.520552 1.910642 1.660806 1.166985 1.770800 0.335795 2.203491 0.577230 1.003302 0.255855 1.908020
+1 0.024280 1 1 1.790569 0.784823 0.542415 -2.109182 2.281118 -1.254038 1.906052 0.188550 2.239375 -0.673564 -1.430580 -1.150042 46.612683 -30.632986 -48.602207 42.699638 52.817722 1.486870 0.579823 1.836678 0.548938 2.497785 1.269807 1.893932 2.059113 1.764100 2.479477 1.826193 2.081536 0.634279 1.331331 0.933825
+1 0.006420 1 1 1.358750 0.277632 0.889768 1.923084 -1.004742 -2.207650 1.374704 -0.190447 -1.124201 2.237754 0.349992 1.254869 -65.721282 22.406225 -68.580366 -30.204590 -48.544800 0.738093 2.377594 1.715825 1.125615 1.706581 1.011148 1.610774 1.773171 1.930745 2.025543 2.294939 0.799015 0.296136 1.665402 1.911055
+1 -0.010419 1 1 -1.164365 1.068450 -1.480826 -2.111483 1.314888 -1.784109 -0.592005 -1.978708 -0.811553 -2.123092 -0.596136 -0.713341 -25.857808 -42.185691 35.096723 70.627525 -63.195078 1.829943 2.103535 1.369827 2.178216 1.023466 1.644205 1.146170 0.673460 0.586731 0.929802 2.424494 2.465524 1.310267 2.411259 0.534741
+1 -0.055394 1 1 0.280240 2.317777 2.276204 0.989429 -0.692549 -0.066191 -0.342722 -1.593967 0.135640 -1.096254 0.699567 0.208875 -5.446226 -34.727442 -14.124956 51.868418 -47.498484 1.269618 0.961151 0.560658 1.475302 1.895728 0.742686 0.823396 0.562025 1.951464 1.497278 2.244451 0.485738 2.303284 1.536257 0.367749
+1 -0.018941 1 1 -1.449459 1.984925 1.640868 1.164368 -1.015415 2.193996 0.040168 1.224570 2.346238 -0.052132 0.330117 1.789199 41.814853 32.233242 -55.895522 13.969263 31.410847 2.456613 2.290707 1.667902 1.173889 0.803946 2.171511 0.839844 0.252404 2.408906 1.487758 2.003819 1.686244 1.198258 0.877910 1.039279
+1 0.024989 1 1 0.043081 -1.640849 -0.848705 0.223398 -1.129219 -1.988839 -1.437641 -2.008474 -1.574254 1.569502 -1.327679 -1.141667 26.908943 8.604801 20.890343 -46.006746 14.612634 2.043191 1.909150 1.325856 1.168802 0.809588 0.250681 0.444797 0.456038 0.375648 1.516617 1.026423 1.838617 1.629986 0.672336 1.947518
+1 -0.008175 1 1 1.879534 2.179640 -0.896511 -2.154547 -1.467451 1.201974 -0.442493 -0.825882 2.092866 1.522113 -1.413408 0.001738 29.598336 59.227177 31.168218 44.240817 5.414352 0.610299 1.037312 0.349786 1.100289 1.311303 1.814455 0.550030 0.600476 2.449553 0.645781 1.133446 0.579638 0.970672 0.830891 0.533595
+1 0.008828 1 1 -2.158655 0.175429 -1.528239 2.127522 -0.339411 2.223248 1.603713 -1.262016 -0.238325 0.010287 -1.462650 1.774776 -24.483567 -45.303700 -19.278672 -16.633801 35.702366 2.120078 0.400294 1.733845 2.475060 1.830201 1.932684 0.865800 2.256583 1.885289 0.808812 0.701128 2.105874 2.426001 0.807394 1.615190
+1 0.020096 1 1 -2.305164 -2.343312 2.095898 0.648409 -1.937788 -1.090175 -0.804094 0.730479 1.394132 1.184191 2.284731 -1.775799 -72.911874 70.133386 31.811312 52.714252 68.433295 0.750795 2.113946 0.843411 1.701434 2.252704 1.944120 1.829711 0.460834 2.243031 1.375148 1.609562 1.660551 1.373936 1.492874 2.486977
+1 -0.010121 1 1 -0.213776 -2.096197 -0.955842 -0.309109 -2.136862 -1.131784 2.021947 1.829651 -2.106257 -0.389165 0.105247 1.746909 67.226854 -68.259181 -32.058353 -4.742062 -49.838984 0.717921 0.845675 1.515605 2.025477 1.188140 1.823669 2.408176 0.457733 1.867915 1.299512 1.654225 0.815103 0.681037 1.935985 2.345705
+1 0.003988 1 1 1.928378 -1.554496 -0.932349 -1.303313 -1.604621 0.130012 -1.431193 -2.018980 0.910980 0.288013 1.006635 1.033577 46.574951 -64.796644 -37.191439 -26.513035 45.413084 2.240515 1.842750 1.343003 1.343494 0.601812 2.407790 0.721125 0.691804 0.652200 1.024460 0.353611 2.382500 0.925919 2.424826 1.307226
+1 0.025672 1 1 1.469955 -1.526434 -0.528942 -2.354597 0.938124 -0.610678 -0.075568 2.266259 -1.216532 0.805503 -0.603013 1.504721 -49.429536 -62.219662 74.145789 -31.716031 48.663033 0.318834 0.642763 2.171690 1.597394 1.902667 0.383442 2.009717 1.812072 1.002942 0.953317 1.646484 1.199123 1.914149 2.099131 1.589284
+1 -0.018945 1 1 1.212989 0.909503 -0.979626 0.507705 -1.135529 0.337567 -0.228981 1.537799 -1.663662 2.155275 -0.422714 1.728053 29.645379 -50.112694 5.946050 35.256369 53.789439 1.211418 1.556952 1.690932 1.248059 0.880714 0.914701 0.623586 1.603985 2.430591 1.435558 2.178940 1.951938 0.478654 2.487142 2.388043
+1 -0.031703 1 1 -1.413553 2.273496 -2.108068 2.153780 -1.994952 -0.517252 0.909403 2.052764 1.406238 2.004634 -1.692574 1.593778 44.621324 -49.409665 -28.232875 -59.937206 35.386247 1.174755 1.850504 1.163937 2.289093 1.541943 1.429203 1.114279 2.438431 0.461182 1.336107 2.442207 0.914750 1.459906 1.883373 2.348616
+1 0.017720 1 1 0.243767 1.927686 0.939814 -0.467064 0.897593 1.492141 -0.923886 -0.430345 0.710419 -1.184802 1.589736 -0.552854 32.323986 -30.774857 -33.024172 -37.255668 -56.009626 2.068271 0.425304 1.336480 1.973103 0.685869 2.149127 0.373745 1.039657 1.510472 1.252206 0.817598 2.125635 1.551417 0.914747 1.397974
+1 0.047188 1 1 -1.310744 0.747441 -0.981967 -1.134736 -0.465570 -2.271619 0.666018 1.845400 -1.306843 0.336464 0.086634 -0.075556 -71.044386 -43.002380 -41.003344 -43.199577 -55.286023 2.242204 0.970750 2.141307 1.694691 1.421710 1.173983 2.375913 0.476833 1.135735 0.789314 1.505569 2.089868 1.161970 0.728666 1.447677
+1 0.030665 1 1 0.642590 -0.787564 0.514359 2.310220 -2.208720 2.246077 -1.130262 -0.671760 0.610998 0.754540 0.506907 -0.419542 -47.804715 -53.845498 -31.286494 67.899349 -15.644444 1.582426 2.326857 1.734490 2.079082 2.123416 0.251685 1.562546 1.214898 1.534986 1.514182 0.600595 2.194374 0.339143 2.218191 2.389188
+1 -0.077390 1 1 -0.413231 0.894886 -1.592595 -0.376851 -0.288287 -0.911070 -1.803559 -2.337075 -1.455359 1.788960 2.016387 -2.082409 -4.149080 16.415376 43.218215 68.540757 -35.497379 0.558307 2.465510 1.080800 2.256195 2.125595 0.879110 0.957016 0.822882 0.934351 2.383997 1.335268 1.854108 0.991532 0.425923 0.495250
+1 0.004911 1 1 2.155584 0.059387 -0.911964 2.022748 1.148627 -1.690835 -2.159967 1.684995 -1.751386 -1.964371 -0.182166 1.383962 -3.113796 16.439355 -3.758204 -14.136138 13.932248 1.514309 0.493773 2.350932 1.367276 2.064305 1.269056 0.529399 0.366606 0.300293 1.770156 0.758891 0.938712 1.430670 1.029264 2.336018
+1 -0.053360 1 1 -2.211621 0.611799 0.078051 1.766543 2.236732 2.028688 2.021799 -0.667407 -1.623161 -0.454877 -1.618695 -0.791072 -60.373575 51.323006 -64.236396 -71.110098 52.579130 2.086689 1.734679 0.751226 0.362017 1.922850 2.090767 0.517729 2.227593 0.652803 2.153312 0.967105 1.640261 2.362729 1.636033 1.050855
+1 -0.060121 1 1 0.617111 -0.182225 0.403373 -1.637413 0.354792 1.815390 -1.458716 1.913398 1.129368 -0.220296 1.418001 1.799426 -37.031799 -43.437994 -12.366735 52.282541 12.659965 0.265490 1.839288 1.660118 0.856195 0.576089 2.072568 0.647932 1.290773 1.025325 1.389374 2.201431 1.956528 1.121170 1.258311 2.175056
+1 -0.056768 1 1 -0.016485 0.968657 -1.091398 2.209144 0.164083 0.999538 -0.427931 -1.132059 2.106780 -0.248002 2.292326 -1.369355 17.813156 -14.292089 -57.142688 52.847876 64.252216 1.929971 0.276035 1.324403 1.487212 1.816151 2.044075 1.025334 1.538666 0.350509 2.005852 2.101762 0.809748 0.681015 1.565907 1.449855
+1 0.036434 1 1 -0.971229 0.263256 -0.384555 2.179809 1.935720 -0.680028 -1.678977 -0.785566 1.099541 -1.995710 0.887708 0.283071 -61.761707 -29.007058 -21.620851 68.358665 54.086621 1.882588 0.405019 2.402754 1.590364 0.742438 1.148628 1.497576 0.504781 0.603294 0.313177 2.314950 1.861207 1.062675 1.371235 1.089451
+1 0.005462 1 1 0.006092 -1.277193 -0.855412 0.596745 1.526553 -2.185499 1.396083 0.980381 -1.964187 -1.811497 0.919320 -0.913495 -4.893924 -52.176484 -30.158973 -31.863885 -36.311733 2.255627 1.569364 1.043654 1.190457 0.252300 0.654453 0.648715 0.947532 1.168870 1.951113 2.359193 0.703573 0.444342 1.807020 1.582437
+1 0.004765 1 1 -2.255951 0.110612 -2.332907 -2.086559 0.810836 -0.508421 -1.476695 1.332479 1.703811 -1.240007 2.101394 -1.233710 -14.537145 24.199184 65.686382 -8.974209 70.472837 1.929679 2.109774 0.475292 2.225488 1.282718 0.646427 0.754355 1.198515 0.697057 1.179959 1.570417 0.747864 2.346384 1.430560 1.416831
+1 0.010837 1 1 -1.074359 1.124724 1.841046 0.912675 0.506790 2.328571 -0.100348 0.478637 0.402425 1.270450 0.609971 2.337013 13.234068 -25.020206 -64.606902 1.797329 57.715854 1.080295 0.516033 0.709951 1.891513 1.914154 2.182229 0.974634 2.178658 1.707439 1.923610 1.367622 1.119731 1.823585 0.995185 1.079502
+1 -0.026817 1 1 0.058565 -0.589828 1.634581 -0.828760 0.855426 -0.348647 -2.211259 1.982877 0.203478 -1.332839 1.674123 -0.690154 -70.820306 -26.884229 -43.239427 24.947775 47.249208 1.636696 0.944498 1.926316 1.840338 1.305636 1.077365 0.781136 1.302943 0.814623 1.622549 1.684352 0.903062 0.761320 1.258673 1.513253
+1 -0.010867 1 1 2.117528 1.332145 0.795330 -1.938099 -1.596580 -1.384535 -0.096601 2.203402 -2.091686 -0.546011 -1.782268 2.078282 46.341660 64.279230 41.018283 -5.713671 -29.664100 1.907108 0.764199 2.385079 1.527204 1.214802 2.171162 1.711884 2.388539 1.181896 0.370103 0.567613 1.374668 0.300951 1.587198 1.530509
+1 0.020460 1 1 -1.919864 -1.422870 1.194014 -2.279098 2.213672 0.871507 1.309606 -1.022511 0.738905 1.627512 -1.817861 2.348303 53.045537 -63.658301 44.928584 14.708565 6.859912 0.543060 0.462573 2.219854 1.084456 0.708287 0.933144 2.343205 1.999395 1.578185 0.809817 1.846823 2.303291 1.663044 0.529917 2.317975
+1 0.003475 1 1 -2.119563 2.163882 -1.850714 1.530164 1.965113 -1.474026 -0.924510 -1.486011 0.270957 1.810354 -1.275343 1.964243 -62.472842 18.936692 -31.013042 13.797344 -8.045552 0.301210 1.436790 0.386070 1.170643 0.252000 2.365262 1.452681 1.954112 1.003153 2.245275 0.841535 1.671874 0.443066 0.602656 0.846103
+1 -0.006043 1 1 -1.776287 -1.075541 0.114876 -1.358349 1.759663 -0.299676 0.889415 0.705947 -0.947669 0.404541 -0.863492 1.446661 -60.261706 -18.495870 -60.087583 57.996473 46.726985 0.481449 2.220051 2.151508 2.151920 2.325751 1.143281 1.620819 1.854866 2.491268 1.999489 0.918801 2.036804 0.311295 2.188803 1.210841
+1 -0.006399 1 1 -1.234085 -2.050131 0.440075 -2.115246 -0.669555 -0.032512 0.201520 -1.262095 -1.561832 -1.710043 0.174470 1.215725 -7.245833 19.292215 -55.743293 22.481768 1.079389 1.244235 1.850300 2.238007 2.424636 0.356994 0.753155 1.268240 0.306289 1.306791 2.487215 1.374923 2.327095 1.243501 0.771831 2.416078
+1 -0.039133 1 1 1.084565 0.756384 -1.487287 -2.321339 -0.879517 0.714119 -0.261643 -0.781029 1.958177 -0.248687 0.207461 -0.364544 -25.166245 30.922389 -37.400084 66.792997 -10.095247 1.062863 2.289452 0.828967 1.949958 0.952759 1.276030 0.741913 1.328925 0.986055 0.621685 1.158652 1.208842 1.000254 0.771736 0.817644
+1 0.026652 1 1 2.351704 2.279066 1.955646 -0.371666 2.043875 -1.914215 -0.727458 2.264833 -1.631485 1.030688 0.031984 0.336917 -55.142240 74.379629 -1.568137 44.313527 27.442040 0.900616 2.397512 1.241181 2.277077 2.089913 1.918414 1.783388 0.407784 1.629061 0.879918 1.027894 1.808296 0.529405 0.460851 0.278338
+1 -0.041832 1 1 -0.135037 1.810366 -1.068073 -1.606007 0.402556 -1.225287 -0.258613 -1.684163 1.588575 -1.213587 -1.539711 -2.193379 28.627544 -56.865008 69.804217 49.467886 -43.234219 0.812098 1.929237 1.435099 1.212778 1.913159 1.212803 2.337051 2.062485 2.182511 1.220930 1.671624 0.738380 0.452128 2.159175 0.504061
+1 0.014405 1 1 -1.715462 -1.376585 1.563898 -1.274114 -0.942962 -0.589764 -2.001439 -1.156992 -2.248491 -1.743042 1.614371 -1.203391 6.045552 57.588691 -56.870360 -20.143071 5.399425 1.347079 2.354568 1.720069 0.458830 2.312016 2.057740 1.187336 1.808314 0.834716 1.815736 1.819759 1.940417 0.340095 2.479123 0.371193
+1 0.014406 1 1 1.182703 0.826713 -2.265598 -1.795660 -1.523472 2.125204 -1.609834 2.052842 -1.990905 1.536226 0.178245 -1.323169 -23.595587 28.965760 -72.467359 41.092738 45.649989 1.215378 0.615450 2.123924 2.032983 1.340805 0.414068 1.492942 1.379435 1.659795 2.166215 1.829924 1.780598 0.758959 2.074707 0.607735
+1 -0.039505 1 1 -1.689609 -0.406784 0.851150 -1.536819 -0.717726 0.897293 1.154465 2.196693 -1.755294 -1.664221 2.184313 2.238044 16.564069 -7.698424 62.591923 32.443586 29.349041 2.414931 1.497046 0.595129 0.327974 1.258113 1.104341 1.913012 1.000050 1.847989 1.652230 1.025561 0.856456 0.463365 2.032578 1.295928
+1 0.024305 1 1 0.475996 -1.563271 -2.331455 -1.242792 -2.289553 0.850305 -1.604403 -0.916489 1.363565 1.080902 0.467134 0.277948 47.822575 54.014151 15.844043 40.825458 53.479170 1.741176 1.940436 0.650829 0.489695 1.297103 1.658082 0.391389 0.572494 2.406045 0.657435 1.261700 0.651102 0.579391 1.317582 1.593230
+1 0.032648 1 1 2.284924 1.462676 -1.340392 1.957020 -0.841117 0.517318 0.204585 -1.586752 -1.129352 0.479901 -1.915202 1.526875 -47.226410 65.725616 50.423620 -30.224511 66.651340 1.511162 1.593125 2.149910 2.280451 0.295322 1.471876 0.564079 0.468464 2.220833 1.782575 2.489791 1.924119 0.917322 1.926215 2.389769
+1 0.002746 1 1 -0.124506 -0.270875 -0.423079 0.304125 -1.520363 -2.162054 -0.408137 1.680190 2.314992 -2.120754 0.996885 2.100870 -19.474585 -9.350920 39.090764 -1.526820 -11.268382 2.309626 2.386032 1.781092 2.312797 1.687345 1.710525 2.047388 0.455844 1.626850 1.964034 1.267830 2.426341 2.021639 1.938719 1.042165
+1 0.010008 1 1 -1.612855 -1.587092 -2.139735 -2.286499 0.336190 0.196471 -1.292631 -1.130090 2.215313 0.184968 -1.412091 -1.420568 69.462355 3.805027 51.094785 0.048682 68.191143 0.453154 1.416214 1.051156 1.280573 0.592696 2.191485 1.288562 2.113650 0.363756 1.896239 0.337871 1.094619 0.517440 1.870446 1.091490
+1 0.012516 1 1 -0.042586 0.537655 -1.991500 0.960676 1.430182 -0.825182 -0.272731 1.371995 1.392949 0.151625 -1.043205 1.649438 -27.854666 -3.369093 -74.352330 10.390992 41.400814 0.977095 0.779083 0.539764 1.314393 2.008723 0.866226 0.405830 0.287078 2.419741 1.340938 0.387440 1.701447 2.467503 0.814485 1.545582
+1 0.081074 1 1 -0.973010 -1.385614 0.606005 1.655099 0.010306 -1.150195 -1.108541 1.531837 1.799628 2.240792 -0.417826 -0.942457 -49.045940 -65.107892 -18.344870 -72.222605 -45.327665 1.794111 0.629371 2.092270 1.030375 0.758371 1.193953 0.525009 0.822733 0.675039 2.376634 1.328952 1.437523 1.444763 1.629465 0.921027
+1 -0.036734 1 1 -0.706611 -0.787823 0.871077 -1.197293 -1.003086 2.061209 1.963395 -2.080126 0.534566 -2.081974 -2.249020 -1.200401 -44.632760 7.210862 -7.037676 67.775538 3.471497 1.306726 1.396687 1.366639 0.342599 1.819456 1.351778 0.338316 1.821277 0.453943 1.163326 1.015581 1.866856 1.501568 2.353093 1.690800
+1 0.025541 1 1 -0.259164 -1.519846 1.801751 0.219190 -1.164015 2.243764 -2.310032 0.665248 -1.674132 0.546392 -1.235413 -0.802603 70.507292 16.048510 27.314546 -74.433480 -3.499813 1.054557 2.185618 1.689393 2.381343 1.737296 1.982362 1.050107 1.641905 0.749975 1.829996 0.741715 0.251483 0.426008 1.913013 1.000526
+1 -0.017160 1 1 1.787728 0.150128 2.074337 1.135163 -1.773813 -1.909916 0.833027 0.177404 -1.320016 0.424091 -2.153284 0.905847 -36.826624 -45.072000 -25.108989 -56.772291 -21.890922 1.814096 1.261685 0.382719 1.102675 0.910972 0.948244 1.887457 1.238045 1.315535 0.953581 1.584088 1.012881 1.482169 0.319820 1.459076
+1 0.041688 1 1 -0.729474 1.361626 1.494713 -0.108653 2.277321 0.902439 -1.893674 0.489784 -0.737555 2.212502 0.054103 -0.173638 -43.301404 33.307724 2.912308 47.156016 -48.830813 0.632902 0.680696 0.710364 2.082002 1.709866 2.215696 0.945488 0.560125 1.520288 1.977387 0.699175 0.776623 1.944922 1.801395 1.553437
+1 -0.011969 1 1 0.317957 0.060085 1.388986 -0.490495 -1.781951 -2.022149 -0.502965 0.690234 -1.138511 2.058867 0.302219 -0.567575 -43.162785 -36.922631 -8.660769 -61.542056 62.672930 2.033987 2.472483 1.277306 1.940853 0.909572 2.176457 0.714584 1.016736 1.035933 1.928407 0.985921 0.618184 0.812547 0.479185 2.407218
+1 -0.017069 1 1 1.699343 -0.935234 2.048602 2.132073 0.748918 0.282095 0.499100 0.319431 1.261744 0.374753 -1.987257 1.581657 10.036898 -59.848635 23.991029 17.221842 -52.498307 0.789385 0.435587 0.916991 0.865523 2.087645 2.044706 0.369777 1.835177 2.318887 0.539010 2.135922 1.185372 0.295837 1.139593 0.394638
+1 0.010344 1 1 -2.000510 0.330986 2.261330 0.749000 1.652736 -1.996777 1.809460 -2.161794 -0.748628 -0.106068 -1.405447 1.862573 -4.104658 13.008741 -62.096983 36.009423 -39.622594 2.320898 0.575452 0.365989 1.177992 2.259339 0.953077 2.116236 1.078585 1.036445 1.523821 0.604625 2.425055 0.647046 2.156839 1.734813
+1 -0.010446 1 1 -0.568035 0.331204 1.213131 -1.407730 1.181359 1.810395 -0.591166 -2.005908 -0.858379 -2.144882 0.745819 0.018133 -49.344242 21.318395 -51.736939 7.258192 38.432147 1.811516 0.651067 2.233931 1.429393 2.056798 1.102779 0.411903 1.095283 0.421349 2.362859 1.567424 2.190665 0.999716 0.735068 1.032676
+1 0.015473 1 1 1.569830 -0.537217 -0.070929 0.127689 1.927127 0.978736 -1.330573 2.056602 -0.066356 1.587741 -1.100861 -1.322624 -31.812497 -72.639797 -7.065018 58.243615 0.433551 0.425368 2.411459 1.648686 2.221491 1.600022 1.068489 2.350256 1.253165 1.197094 1.556477 0.466318 2.154018 1.571408 1.646641 1.592354
+1 -0.033551 1 1 -0.204145 -0.440714 0.793742 -0.356019 1.127810 1.880698 -1.810867 2.081166 -1.900511 -1.321803 -1.348331 0.479119 -29.542441 -19.805770 -25.574698 66.057421 -72.926705 0.938100 2.390218 2.390635 0.400663 1.192507 0.968163 1.410101 1.811664 0.881623 0.438576 1.652855 0.278136 0.629526 2.447570 1.065825
+1 0.044594 1 1 -1.950355 -0.242151 1.676506 1.656270 0.843494 1.738157 1.109912 -2.063690 -1.261864 2.308633 -0.611223 0.177004 44.411936 31.413700 -29.936405 -41.155998 -58.861470 0.854140 2.022655 1.007725 0.328131 1.655693 0.739808 1.948557 2.138516 2.043541 1.050633 1.487019 0.831810 2.474672 2.058673 1.117846
+1 -0.029829 1 1 1.284958 -0.594624 1.123259 0.786726 -0.460089 0.322464 0.412972 -0.528763 0.639837 0.071491 -0.104946 -1.387916 -12.231724 71.415042 -27.388087 38.419287 -37.035853 1.951173 1.118225 1.258869 0.310618 2.057241 1.797247 1.583482 2.083472 1.667447 0.290579 0.507076 0.932503 0.574712 1.434013 0.953047
+1 -0.030596 1 1 -0.609276 -0.072502 1.975016 0.032304 1.008807 -0.162041 0.341444 -1.032223 -2.275233 1.194676 -0.566767 -1.916386 15.316399 22.724188 25.430092 53.563783 -53.497467 0.896007 1.443575 1.916999 0.509788 1.506578 1.056511 1.282321 0.716856 0.948309 0.724182 0.318964 0.575845 2.473661 0.829263 2.426479
+1 -0.019207 1 1 1.990034 -2.036645 0.907204 -1.905361 1.996852 -0.548650 0.987586 1.330818 2.054217 2.257344 -0.266281 1.388337 -62.627112 -23.863528 25.691672 -50.074246 52.154489 0.782523 2.118895 0.760783 1.234983 1.600822 1.016700 0.428147 1.868202 1.621106 2.172251 2.024849 1.882473 0.731129 2.336366 1.806654
+1 -0.058951 1 1 -1.291115 0.781489 1.063875 1.736401 -0.138949 2.031628 -0.394891 -1.881881 0.772731 -0.047375 0.159068 1.530145 52.238303 19.159973 -28.341376 66.487452 -45.402263 0.987364 2.370423 0.453147 1.295325 1.035596 0.761865 1.418096 1.185544 0.940230 2.200747 1.699623 1.064130 1.087727 1.675655 0.982303
+1 0.017458 1 1 -1.080362 -0.808516 1.804182 -1.338383 -1.974976 0.646895 0.875708 1.234644 2.018659 -1.599909 -0.776626 0.566118 13.934634 49.391940 30.339348 63.414670 60.356108 0.701625 1.457434 0.840302 1.213636 0.578879 1.722256 1.204327 1.618443 2.416517 1.147253 0.887865 1.842414 2.452311 1.994983 1.683552
+1 0.042971 1 1 -0.480098 -1.393863 -1.361779 0.652757 0.452590 0.890642 -2.231685 -2.018989 0.756301 1.845535 0.965537 -1.693262 -17.294105 37.979237 67.040501 -50.306417 50.044172 2.011003 0.925395 0.370408 1.189005 0.612091 1.917071 1.705250 1.140641 2.258266 0.922672 1.846836 0.276102 2.445219 2.046736 0.743244
+1 0.003178 1 1 1.890862 -0.627177 0.646226 -0.937160 -2.043223 -1.267187 -2.324897 0.589935 0.174833 -2.114485 -2.020743 -0.433033 -65.598240 -9.620878 1.910496 9.706721 -59.143976 1.632902 2.427008 1.973181 2.002994 1.320991 0.399135 0.260971 2.390350 2.355290 0.358956 2.225147 2.301268 1.419957 0.958976 2.261329
+1 -0.002082 1 1 -1.414546 -0.273185 -1.546163 -2.253278 -2.083679 2.084197 1.917484 -0.869301 -1.943491 2.031001 -1.504219 0.565081 59.074011 6.902406 58.735412 16.066785 34.462364 2.259200 0.869066 0.890905 1.186979 0.309502 1.297211 1.220241 1.341429 1.895723 0.665504 1.880613 0.971239 1.358525 1.229974 0.673695
+1 -0.002768 1 1 -1.316961 -0.075788 -1.419359 -1.055286 1.245344 -1.939605 1.371189 1.989111 1.298593 -2.325307 -1.598276 -1.605746 2.622463 -24.262264 74.122724 30.618072 -52.058399 1.442246 2.074069 1.130677 1.281432 1.526342 2.488241 0.619829 1.457735 1.401118 1.598579 1.559805 2.388287 1.446042 0.620333 0.932490
+1 -0.016112 1 1 1.655444 1.106215 1.786467 -2.187764 1.022787 -0.807805 -0.377711 -0.594454 -0.723189 -1.388319 2.265449 -0.693284 54.618030 -34.763383 -18.177831 35.188399 -38.574811 0.972324 1.595259 2.012967 2.438189 0.892810 1.712118 1.822077 0.389985 1.732841 1.353243 2.454575 1.797479 0.984829 0.276639 2.475495
+1 -0.019751 1 1 1.321617 -1.789496 -1.586602 1.395514 0.842643 1.573650 -2.299437 -0.328781 1.809872 0.049874 -0.579529 0.359489 20.425857 -52.624598 -61.614595 43.502649 49.024453 1.434830 1.183359 2.463840 2.260946 0.962339 0.283848 2.126195 1.952070 0.443397 1.675235 0.671243 1.587977 1.131869 1.065585 0.790836
+1 -0.023456 1 1 -1.157790 -1.518120 -2.169959 -1.327588 0.392430 -1.766069 1.019513 0.707596 -1.511283 -0.359404 0.776742 1.386209 -1.281662 59.108417 -14.831823 21.557278 63.167011 0.594434 2.153533 2.437411 1.318428 2.319562 0.634156 1.504187 1.377354 0.434987 2.073974 1.780675 2.057753 1.402188 1.566559 1.150922
+1 0.015753 1 1 1.910006 0.675439 -0.049826 1.382611 0.749510 0.799779 2.155698 1.966756 -2.138177 0.328399 1.190438 -1.110188 68.082025 54.597563 71.235991 -36.694765 71.076373 1.083912 0.555450 1.699901 1.241767 0.882562 0.470006 1.137876 0.779740 0.342155 1.097271 2.339122 0.873878 0.765736 1.231051 0.779715
+1 0.028230 1 1 -0.281081 -2.309682 1.839419 1.843033 1.326177 -0.540070 -0.902679 -2.140469 -0.479796 -1.038816 0.014667 1.459846 -56.374659 61.113095 -72.206505 -74.726252 25.888479 0.740043 1.394790 0.983783 0.687013 1.131439 0.598577 2.034878 1.690432 1.843090 0.319663 1.068838 1.466734 1.901095 0.951097 0.334389
+1 0.003186 1 1 0.640321 -1.221529 1.649450 -0.677878 1.461277 -1.291310 2.222027 -0.082826 -1.894746 1.332243 -2.269368 0.805563 12.685424 53.922966 -16.710107 -46.772285 48.210664 1.024503 1.078041 0.881899 0.582456 1.092325 2.457831 0.262417 1.947055 1.650242 1.371435 2.214455 0.351833 1.763359 1.278800 2.291703
+1 -0.011091 1 1 -0.697180 2.201279 -0.071928 2.194040 0.779371 -1.546844 0.449373 -1.349951 1.525836 -0.100603 0.914243 -1.411792 -35.216194 21.426265 -38.768283 21.459321 66.811974 1.507727 2.369879 0.311140 1.827498 1.503023 2.052153 1.776581 0.748377 1.971135 1.368662 0.610252 0.254630 1.564629 2.473339 2.160872
+1 0.030275 1 1 -1.085653 -0.201670 -1.259489 -0.182285 -0.606020 -1.909429 -0.408913 -1.933130 1.809228 -1.356862 -1.528897 0.493932 -54.363313 -34.202849 -47.285622 -29.441063 34.049602 1.700029 1.134048 1.695159 0.292429 2.353887 1.524568 1.914392 1.681889 2.262612 1.961862 0.763371 1.970714 1.045575 1.985564 0.877992
+1 -0.016408 1 1 1.554089 -1.189107 -0.084268 2.131579 1.867123 0.935184 1.819030 -1.533776 -1.408205 -2.078795 -0.657309 -1.545419 26.297294 -71.379745 20.630008 -71.462920 -27.299634 1.750725 0.427316 1.399741 0.950286 2.449027 0.791967 1.097360 1.579646 0.614092 1.793743 1.190026 2.017313 1.223311 1.192579 2.180865
+1 0.006166 1 1 1.225137 -2.253935 1.008619 1.388807 1.218830 0.122149 -1.640281 -0.718048 0.195087 -1.000466 -1.027370 -0.821383 73.562282 61.275484 -42.946884 -8.287570 60.817063 2.160582 1.658023 1.644613 1.255374 2.317704 0.903321 0.610385 2.485433 0.668264 1.008660 0.303863 1.019161 1.287235 2.312859 0.466980
+1 0.027033 1 1 -1.095336 1.994510 -2.202782 -1.629246 0.951123 1.101527 -1.615954 -1.841834 -0.021172 2.311227 0.571196 0.953621 21.512284 56.956604 -30.356601 -53.386347 35.670515 0.840117 0.353899 0.472601 1.997930 1.702258 0.351562 1.704462 1.392402 1.352399 1.779222 2.392345 2.146011 2.012858 0.605269 2.005903
+1 -0.077621 1 1 -0.448329 0.045228 1.444969 -2.060247 0.057254 0.936372 -1.776298 -1.254413 0.311512 0.122224 -0.375708 0.072125 35.502916 -2.487312 45.753242 74.741681 -66.567604 2.099309 2.339914 0.688222 1.205530 1.594855 1.972545 0.313796 1.463594 0.878220 1.736004 0.510054 1.486057 0.413204 0.466618 0.445076
+1 -0.039754 1 1 0.079914 0.082739 0.438725 -1.239588 -0.287173 -1.034388 -0.953483 1.653090 -0.768133 1.939893 -1.245062 1.955347 -21.980304 27.030446 -49.298626 37.992267 -13.972209 2.411234 2.363244 1.287197 1.678993 0.839981 0.308399 0.761840 1.001213 1.127952 0.489336 2.013495 2.303571 1.874632 1.685677 0.678214
+1 -0.007374 1 1 0.907645 0.780632 0.787545 -0.836846 1.617935 2.147754 0.408159 -1.304742 -2.057303 -2.298619 -0.721950 0.587439 20.152108 -3.520121 -62.668106 37.138533 37.320483 0.555459 1.845971 1.480161 0.311394 1.601406 1.822403 1.379254 0.871111 1.508631 1.807416 1.498414 1.102635 2.488366 0.459193 1.660462
+1 0.017305 1 1 -2.062770 0.066604 -2.139485 1.913718 1.809003 -0.426867 -2.098806 2.308069 -0.678592 -1.119599 -0.530190 0.231007 -15.265577 -68.555421 -60.962816 47.959784 -39.901927 1.649634 2.397704 2.218355 0.640752 2.111000 0.830375 0.855858 1.657170 0.800140 1.200176 1.603479 0.668839 1.672925 2.354062 2.222687
+1 -0.000458 1 1 -1.795611 -0.694648 2.354758 1.775573 -1.507769 2.147168 -0.019831 1.279342 -0.725722 -1.551203 -2.136807 -0.192870 17.712161 -61.716534 -19.785455 15.862010 42.794959 1.448227 1.343817 1.538887 1.820551 1.744619 1.306915 2.328429 1.153452 1.574791 2.267401 1.460435 1.779624 2.398359 1.964519 0.423275
+1 -0.008625 1 1 -0.146922 -0.025525 -0.163793 -0.840477 1.842989 0.588190 -0.875313 0.687766 -0.204336 1.063885 1.914351 -1.694849 34.020674 -14.536777 30.385929 -53.692091 -2.967014 0.376032 1.217196 1.918326 0.306828 1.363869 1.039851 0.267441 0.880239 1.928147 1.118648 1.618759 0.991754 1.917906 2.250206 0.461803
+1 -0.014029 1 1 -2.169595 0.073806 1.102485 0.353873 0.505952 -2.319110 -1.118850 -2.088500 1.167776 -0.289083 -0.153112 -0.391394 10.880289 15.015837 71.167149 6.267717 41.514637 0.422644 1.624487 0.510205 1.769406 1.655999 1.375780 0.990879 0.697351 1.626790 0.956129 1.653976 1.117232 0.317037 1.942391 2.016532
+1 0.020228 1 1 0.241199 1.181752 -1.016207 -1.684498 0.680943 -1.792130 1.260334 0.242677 -2.257650 -0.173370 -1.575781 -0.529506 73.134190 66.338870 7.388008 -29.747109 -9.665283 1.458842 2.013054 1.651789 0.360149 2.018915 1.159935 0.275095 1.266577 1.608116 2.096696 1.169214 0.984933 2.020773 0.881965 1.688886
+1 0.035237 1 1 2.117466 0.282072 0.117198 -0.028326 -0.119511 -1.143183 -1.067132 0.062503 -0.377407 -0.203265 0.215157 1.742994 72.899832 27.479053 -9.551357 -29.664619 26.750204 1.985265 0.352993 1.011661 1.229784 1.978306 0.387662 0.940190 1.515814 1.038556 1.008753 1.862782 0.518106 1.800153 0.915336 2.307466
+1 0.029624 1 1 -0.508236 1.640699 -1.668933 -1.616238 -1.894789 0.609967 2.273172 1.867594 -0.563668 -1.668615 -0.980675 1.726717 65.218392 -74.488228 -23.648395 41.423789 59.629164 1.935314 2.322353 0.278931 0.487736 2.123782 1.908558 0.387221 0.265479 1.661381 1.826003 1.124913 1.155952 0.840919 0.322448 0.634319
+1 0.059976 1 1 -0.234619 1.026681 -1.347496 0.375723 0.169851 -1.023805 -2.153086 -0.478336 -0.058590 0.164960 1.591900 -1.872908 25.342971 -60.688468 8.912583 -56.213763 65.292333 0.898544 1.335802 1.830676 0.914941 2.406492 1.414486 1.275203 0.337251 1.921269 0.268516 0.940017 0.858866 0.457906 0.273930 1.944281
+1 0.021350 1 1 -1.414638 -1.817941 0.997319 -0.033366 -0.013883 2.292772 1.420236 1.657717 1.597087 0.476109 0.324441 0.638049 -54.137599 9.374118 50.807995 -20.020791 -39.427313 2.052307 2.132375 2.320708 1.890963 1.659412 2.478332 0.575197 0.593120 0.320253 1.988844 1.994352 2.330833 1.059136 0.401865 1.150729
+1 -0.005669 1 1 0.491201 -0.483624 0.601954 -0.452889 -1.204050 -1.471914 1.581393 0.600266 -0.545903 0.036882 -2.156270 -2.160811 51.942799 2.616087 18.566174 41.690117 35.797796 1.428439 1.771037 2.067141 1.693044 0.743980 2.317926 2.377624 2.221477 1.367684 2.171942 1.322859 0.286024 0.452500 1.674592 1.126319
+1 -0.003731 1 1 -0.193139 0.756972 -1.028685 0.638062 -1.492848 -1.543102 2.080645 -1.244203 2.256460 -0.975851 -2.006737 -0.661674 15.367927 -11.257139 -48.737603 17.105686 -54.732117 2.384761 0.676415 0.756155 2.196345 1.964477 1.971103 0.827933 0.315816 1.666215 2.083027 0.935331 0.856469 0.679485 0.599945 0.270196
+1 -0.043141 1 1 1.649558 1.139649 -1.772659 -1.357834 0.983381 1.341385 0.591800 -1.468181 -1.646805 -1.992767 -1.483581 -1.294177 37.024675 73.710980 10.437500 73.059052 3.486883 0.685692 1.424664 1.332366 0.325522 0.546609 1.600640 2.455600 1.013453 2.103150 1.650282 2.037367 0.784657 1.986390 1.250447 0.510689
+1 0.003294 1 1 -1.655547 1.874984 1.117423 1.651382 -1.198053 0.364255 0.640633 -0.698084 1.148200 0.571710 0.163620 -2.075327 34.706239 -42.238594 45.947607 41.439252 19.513538 2.335477 0.360805 1.793078 1.268895 2.325997 0.787866 1.909788 0.809624 0.851018 1.313912 0.673487 1.051317 1.743097 0.478729 1.489993
+1 0.007202 1 1 1.656999 -1.028931 1.226613 -1.011154 -1.585990 2.247930 1.730958 -2.085626 2.352218 1.488363 1.564371 1.961736 -53.976318 20.015980 -41.420647 -6.812911 -54.590982 1.965400 1.727299 0.457789 0.567252 2.050330 0.390906 1.461442 0.713743 0.380547 0.595891 1.888621 0.557400 0.715213 0.342002 0.781979
+1 0.002353 1 1 1.104267 2.021663 1.772086 1.153342 2.161459 -0.159411 2.133874 -1.975554 0.360711 2.341992 -0.720836 0.455860 -22.458788 -64.848066 -1.437439 -9.036326 -73.523342 1.272858 1.430685 1.273998 0.338422 1.358131 1.359429 0.675647 1.344501 1.770364 2.011317 1.703511 1.152038 0.301702 0.699036 0.691132
+1 0.002144 1 1 2.033935 0.671913 1.963583 1.082890 0.889524 -2.179768 -1.253461 2.176413 1.409689 -1.246461 2.015936 -0.238020 13.496683 38.749176 -42.606557 11.589359 -67.639426 1.887420 0.626561 2.103725 2.315251 2.425968 2.492662 0.677243 1.165149 2.410166 2.409562 1.265619 1.264385 0.760661 1.431734 0.912103
+1 -0.000456 1 1 -1.583421 -1.697688 0.477136 -1.259287 -1.496394 0.123811 -1.977299 -0.689509 -0.807860 -1.313453 2.342492 -1.751596 -24.863654 16.559354 63.060761 -37.782359 -58.102840 0.858413 1.839475 0.313280 1.799891 1.026545 1.644893 1.473829 1.897873 0.807229 1.105720 0.340731 1.910027 0.331419 0.660745 0.637869
+1 0.038596 1 1 -0.920172 0.731507 -0.187419 -2.077788 2.133487 0.949224 2.177829 1.640791 -0.132733 -1.882537 -0.818077 1.335416 -24.581692 -44.504405 64.467763 59.694101 -71.237018 1.666635 2.380352 0.820505 1.469288 2.068626 1.903778 1.040158 0.939266 1.747169 1.414963 0.278151 0.880970 0.710743 1.714715 0.471839
+1 -0.009171 1 1 1.791548 -1.615226 0.964900 1.750215 1.130777 -0.099838 -0.358683 -1.231810 -1.509691 -1.875025 -1.801121 0.952135 -23.584222 69.983563 63.750962 12.411286 -53.512662 1.565256 1.754142 1.607859 2.291003 2.141992 1.955717 0.983395 0.920768 1.354609 0.662811 1.611726 2.022604 2.400855 1.163397 2.206993
+1 0.018243 1 1 -0.062103 -2.334089 1.604845 -1.089881 -0.570017 0.014883 0.384799 1.917880 1.068378 2.022718 0.649591 -0.926539 66.903933 54.394790 -36.771764 -23.040394 60.096167 0.419204 2.319041 0.880047 0.943753 0.661364 2.051763 1.975047 1.867660 1.510971 0.642066 1.694950 1.275423 1.784189 0.360485 0.926758
+1 -0.062083 1 1 1.117426 1.716182 -0.670766 -1.527528 -0.074323 -0.358622 -0.212312 -1.042799 -0.942342 0.392952 2.293958 -2.207474 -11.867534 42.356220 -19.006733 53.845711 34.872927 2.264381 2.451750 1.563919 1.781941 0.836217 2.293849 0.472932 0.811985 2.282747 0.632507 0.803301 0.333866 1.289450 1.287540 0.687561
+1 -0.010103 1 1 1.196397 0.075845 -2.327377 1.309316 -1.178659 1.168677 0.723832 -1.949642 2.326112 0.981719 1.682128 1.907784 32.611774 6.092743 -49.274135 -0.382581 19.956955 1.623119 2.260658 0.632945 1.405531 1.516844 0.341115 1.612509 1.687005 0.491050 1.573733 2.486608 2.424366 0.314386 2.379778 2.432513
+1 -0.006300 1 1 -0.208045 -0.022619 1.547861 -2.207695 0.629747 0.131020 1.364398 0.946490 -1.372049 -2.310546 1.449791 -1.126455 65.204410 -9.475356 47.685717 3.844618 -33.514344 0.991189 1.414591 0.774620 2.031728 0.495531 0.394529 1.601444 2.477347 2.020401 1.385795 0.550933 2.284104 0.933703 0.496060 0.273048
+1 -0.034674 1 1 0.127247 -0.777232 -0.195570 2.296584 -0.495297 2.330159 -1.674979 0.443292 0.116718 1.322782 -1.063299 -1.483853 -36.619815 -19.231929 18.977145 48.876177 61.913802 1.903931 1.363216 1.321914 2.408835 0.286872 1.214068 1.100001 0.963366 1.790235 0.722769 1.332695 1.359888 1.638498 1.992796 0.915163
+1 0.019379 1 1 -1.871389 -1.957245 1.777160 1.609188 1.229134 -1.066125 -1.866504 0.048048 1.729590 -1.503098 0.555873 -2.110513 -39.656683 -59.863263 -71.854013 -0.394426 -29.121226 1.518324 0.472060 1.913822 1.100987 1.787162 0.838425 1.162910 0.775293 2.096198 1.801436 2.241451 1.811402 0.980541 2.445908 2.367070
+1 0.001553 1 1 -2.216817 -1.902075 0.672716 1.315198 -1.277556 -2.244524 -1.045970 2.312140 1.770433 1.649501 0.179898 -1.809702 -60.816122 -36.555458 12.424740 22.601711 66.959190 0.371523 1.930193 1.761872 1.039311 2.442807 2.005460 2.273990 1.948596 0.554008 2.214743 0.682390 2.175037 1.595541 2.262204 1.856479
+1 -0.002582 1 1 1.466797 1.945719 -2.280366 -0.253561 -1.608006 -0.199186 -1.916689 0.100132 0.590288 1.397281 2.264881 -0.829251 64.302973 -9.936671 -55.625168 57.799989 44.412781 2.059085 1.286676 1.911325 1.890329 2.256189 2.017263 0.383047 2.118146 1.687756 1.870251 2.300940 0.393691 1.008697 0.920682 2.156858
+1 0.045809 1 1 0.646421 2.336536 1.822005 1.328488 0.598246 -1.525637 -1.270856 1.977347 1.502843 -0.121225 -1.682824 0.538471 73.138032 -19.095932 54.678853 -62.520597 -33.671954 1.757019 0.477046 2.461344 0.813970 1.892304 1.699690 2.181425 0.955247 0.330353 0.739799 1.805974 2.000208 1.736880 1.747867 1.900296
+1 -0.004950 1 1 -0.581607 -1.582026 -1.808509 -0.703287 -1.467686 1.950883 -0.308088 0.883959 -1.458991 2.008888 -0.880329 1.209190 -53.580818 67.200271 -65.048993 71.576577 -12.474202 2.066384 2.475057 1.786336 0.446266 0.386871 1.137256 1.608116 2.097312 0.277815 1.988852 2.139471 2.337385 0.931922 2.057274 2.354037
+1 0.027352 1 1 1.805731 1.137363 2.215291 -0.183250 2.012511 -1.248740 1.414495 -0.578358 1.188067 1.446120 -1.558508 2.332515 6.666609 -4.300842 15.746067 44.144061 29.239608 1.826393 0.928507 0.913992 2.214184 0.288692 0.300596 2.362510 2.458236 0.320185 0.842071 1.689754 1.688689 1.795918 1.750061 0.522773
+1 -0.005780 1 1 1.554896 -1.779220 1.465179 -1.679126 1.432678 -1.284922 1.203417 0.263450 -1.837337 0.166637 1.509656 1.280136 -48.346962 -17.384448 19.590033 -0.314482 -35.502282 1.572097 1.979953 1.069935 1.903933 1.392993 2.290313 1.798184 1.585962 1.010215 1.684965 2.206369 1.700766 2.275769 0.355491 2.489417
+1 -0.021589 1 1 -1.024185 0.874184 -0.812362 -1.574138 -1.185064 1.893161 0.312240 -1.782951 0.029044 -1.943035 0.267381 -1.739284 -37.998366 61.467120 27.891294 18.970168 -68.384357 0.836777 0.469314 0.759255 0.297019 0.747600 2.421019 0.309019 2.176633 1.413566 1.553962 0.938040 1.392103 0.830553 1.603811 1.759220
+1 -0.008875 1 1 -2.027926 1.352828 -0.299756 -0.449103 1.172732 -1.814553 1.397734 0.449627 -1.784857 0.980172 -0.756221 -0.494994 -63.394384 -19.407766 63.671241 22.540782 -57.073878 1.514899 1.405238 1.087939 0.742707 1.170388 0.454284 2.407930 0.824189 0.395881 1.814963 2.335149 1.602060 1.573022 1.789663 2.372303
+1 0.009842 1 1 0.497303 -1.611431 -1.225101 -1.838375 1.558842 -1.425177 0.122636 1.836143 -1.371880 0.534889 -1.361475 1.049811 31.451134 -0.790233 68.557255 -58.220856 -67.918971 1.162871 2.373783 0.667255 2.058588 1.931894 1.086340 0.863595 1.193308 0.934282 1.229335 1.190579 2.311799 0.658981 2.494744 1.906435
+1 0.012374 1 1 -2.274788 -0.745825 -0.119629 1.587927 2.035897 0.658556 -1.054752 0.792176 1.598485 0.405488 0.916767 -1.409119 44.889217 -46.930344 -58.288375 -2.719426 44.613786 0.983544 1.175590 2.392166 1.390574 2.127798 1.894170 1.569480 0.745771 0.930762 0.565506 1.954221 0.598400 1.304199 1.675164 1.739428
+1 -0.037936 1 1 -0.381364 -0.733820 -0.986302 1.398823 -0.086646 -0.127142 -2.158530 2.261154 -2.204312 0.938992 -0.146624 0.270328 20.877429 36.955903 -32.136147 37.773341 56.544026 0.406617 2.254448 2.007687 1.438095 2.061148 2.214361 1.020093 1.200224 2.420763 0.515441 2.019906 2.061389 1.756988 2.200527 0.256647
+1 0.027171 1 1 0.933504 1.850527 0.044435 2.259650 0.789754 -1.406115 0.054426 0.536682 0.503886 0.656859 -1.299382 -1.509888 -14.924306 -32.814833 31.100372 -46.043183 2.218806 0.497025 0.747423 1.682891 1.102661 0.675605 0.646572 0.940800 0.523302 1.390021 1.834491 2.037822 1.674818 0.411708 2.333014 1.709348
+1 -0.054401 1 1 -0.478242 1.520207 -0.449372 1.368686 2.343961 -0.618019 -0.941259 -0.257541 2.196168 -1.150656 0.573646 -0.285043 56.786697 -35.990171 63.202266 -59.516616 54.228312 1.603626 0.895169 0.847165 1.800650 0.272954 1.282015 2.326217 2.226580 1.635674 1.765574 0.257884 2.252290 1.743488 0.311026 2.162870
+1 -0.065691 1 1 -0.185665 -0.872226 0.746080 -0.297795 -0.489384 -1.952034 -0.182071 -1.732000 -1.300907 1.138382 0.492707 1.264794 -5.966843 65.275895 -8.028280 68.695602 16.989147 0.423889 2.297489 0.902836 1.465453 0.616045 0.875935 1.596430 1.442011 0.372852 1.778723 0.756271 1.900065 1.637145 1.744498 1.536315
+1 -0.050957 1 1 1.080262 -0.865840 -0.315274 -2.082916 0.762294 -1.117244 1.348068 -0.190999 -0.978546 -0.179153 0.198025 1.267868 -11.515961 -48.754164 38.773777 70.869922 -39.217692 0.898878 2.440166 0.363658 0.252197 1.168173 1.490415 1.656803 1.387103 2.289493 1.513706 1.605465 0.306905 0.399385 2.213473 1.841835
+1 0.002156 1 1 -1.032246 2.063700 1.422554 -1.789597 1.423587 1.418727 -0.137725 -0.962505 0.815097 0.414430 0.409271 -1.468186 -55.394237 39.054989 -2.806813 -74.110061 32.197735 0.584864 1.056683 1.923703 0.668845 1.784146 1.887569 0.879921 1.076601 1.433720 0.539128 1.869947 1.705240 0.961942 0.355949 1.186350
+1 0.012172 1 1 0.084884 -1.209311 -0.354083 0.666829 1.340445 -1.073317 -0.210021 -0.238697 -1.543794 -0.129615 -1.316078 0.632454 -47.415090 44.575100 73.698356 -51.733806 59.930048 1.289849 1.235496 1.225872 1.486123 1.523472 1.496088 0.255096 0.393544 0.794148 1.743698 1.585181 1.392338 0.271151 2.491871 0.866860
+1 -0.004385 1 1 -1.890753 -2.254260 0.265585 1.060720 0.562587 2.348686 -1.309273 1.907499 0.950810 0.559716 1.214071 0.247539 -20.533063 50.812040 47.953574 5.724047 54.058695 1.592237 0.720015 2.284278 1.608490 1.634213 1.971302 1.916257 1.529157 0.294088 0.994161 1.868106 2.264219 1.978203 0.906912 2.463337
+1 0.002043 1 1 1.252743 -0.110105 1.430492 -0.321432 -1.910509 0.297234 0.476193 1.734619 -1.817730 -0.168788 0.042121 1.068815 -1.503524 -69.735476 55.850961 -12.902321 50.682585 0.958191 0.319317 2.008023 0.348438 0.951045 1.707586 2.141505 0.527010 0.712683 0.563672 0.387734 2.143946 1.047048 1.993051 0.703581
+1 -0.020940 1 1 0.408781 -0.283892 2.285562 -1.954690 2.304648 -1.610498 0.324468 1.107433 -1.317054 -1.642599 -1.984156 1.862141 64.607347 5.678419 37.179381 -26.149231 9.870506 1.279027 1.605708 2.141107 0.591434 1.234268 0.851155 1.360327 2.274169 0.453857 1.979468 1.924722 2.049185 1.398874 2.116678 1.756712
+1 -0.024361 1 1 1.365105 -1.306509 1.233955 -0.149557 -1.892896 -0.562483 -0.601933 0.803737 -2.005188 1.817945 -0.927761 0.411622 11.187549 -70.858890 74.643945 -59.212942 58.085064 1.910101 1.564389 0.689658 0.578130 0.377763 1.064326 2.132063 1.580858 0.730463 2.390037 1.596545 1.133351 1.235623 1.123401 0.494807
+1 -0.043143 1 1 -2.222356 -0.737326 1.352175 -1.850548 -0.392849 -0.551336 -1.748625 2.029110 -0.299903 1.784484 2.179869 -1.764177 -5.611264 41.493027 23.305399 43.844794 -50.544081 0.709509 1.224569 2.078091 1.219057 1.686387 1.360120 1.042505 2.125926 1.940119 2.086421 1.734456 1.503626 0.945814 1.542455 1.050309
+1 -0.005305 1 1 2.160605 -0.372195 -2.137675 -0.652350 1.674620 -1.765502 1.112994 -2.101451 0.266029 -0.902757 1.254572 2.355862 46.957926 71.857531 59.525385 -56.851127 3.116111 1.712053 0.730386 1.098339 2.290954 1.319654 0.418588 0.954277 2.040119 2.035864 0.268966 1.754527 1.339924 1.359428 0.660415 1.839080
+1 0.028208 1 1 -0.667514 1.286969 0.218556 2.314831 -0.112472 -0.655404 2.184640 -1.684694 2.091422 0.815543 -1.514749 -2.055371 60.437016 -35.067459 -28.775435 -28.740171 -36.053531 2.099451 2.481455 1.314950 2.362958 0.994255 1.187925 0.462418 1.860433 1.544360 1.565393 1.808058 1.037511 1.441244 0.994515 1.059107
+1 0.064722 1 1 0.541496 1.294839 0.547027 0.014025 0.105924 -1.014014 2.180761 -0.909407 -2.133201 -0.859204 -1.887803 0.203753 -45.533237 22.880869 -41.236530 -62.359248 -21.881964 1.822493 0.634676 1.243505 0.831368 1.806917 2.108449 0.699523 2.137906 0.784645 1.772366 1.902323 1.349745 2.169857 2.284464 2.482138
+1 -0.021571 1 1 1.450854 -2.104229 0.695606 -0.379510 2.155835 -0.441536 1.121742 -1.147056 -0.183969 -0.637110 -1.366184 2.023204 -19.615764 17.853970 71.673524 -33.087515 -51.872374 1.090226 0.922342 0.797485 1.572232 2.007773 0.636832 1.488227 0.876651 2.381351 1.860350 2.401004 1.432587 1.747929 0.699249 2.025283
+1 -0.015310 1 1 0.371901 1.919457 -0.699619 -1.088042 2.066451 0.527061 -0.978661 -2.126206 -1.095287 -1.897795 1.917058 1.386420 -38.074796 -23.093650 65.032664 -46.014476 34.702731 2.107010 1.268003 0.822759 1.118195 0.756580 0.346913 2.313268 0.590430 2.364952 0.751853 1.891023 0.431915 2.193046 0.527134 0.544881
+1 -0.022994 1 1 0.615933 -1.132768 -0.379681 -0.727477 1.948874 -1.085936 -0.245404 -1.172881 -0.685308 -0.899898 2.189551 0.732853 -35.532794 -49.663888 49.029699 -57.841432 9.060704 1.873718 2.076801 2.049912 2.375648 0.519471 2.254831 1.695658 1.922621 0.499186 1.062882 0.349588 2.276898 1.322061 0.381537 1.493347
+1 -0.049571 1 1 0.536649 -0.056556 1.372065 -2.140431 0.151678 -0.143422 2.249878 1.495466 -1.579555 2.010347 0.077953 0.110775 12.847589 -70.565853 49.704944 40.987233 72.432636 1.004711 1.431336 0.969976 0.384879 1.411865 2.215900 2.132618 1.905157 1.726452 1.981775 2.435131 1.239360 0.920159 2.355697 0.443877
+1 -0.007268 1 1 2.145562 1.252523 0.920206 -0.163025 -2.058192 1.608605 0.850084 -0.599577 -2.003951 -0.954128 0.230495 0.350066 -70.515104 2.645753 67.175551 -30.518849 69.708987 0.609284 1.990810 1.300729 1.854293 1.859387 1.969773 0.971197 0.654046 0.553281 1.244026 0.589844 1.515437 1.452208 0.759521 0.270951
+1 0.031900 1 1 -1.693552 -0.704289 0.532242 1.276456 -2.104120 -2.184613 2.138034 1.972975 -1.283858 0.230253 0.994529 0.204541 -74.069165 -30.459603 15.453253 72.815067 -47.166291 1.767147 1.943628 0.297902 2.094186 1.730322 1.766097 2.298303 1.082293 0.340370 0.351537 1.285395 0.635767 1.587620 1.878584 0.604234
+1 0.020903 1 1 0.719711 -0.515951 -0.792092 -0.187016 -0.015820 -1.994558 1.405343 1.110623 0.470715 -0.786515 -0.708231 0.260701 -29.129857 14.495138 19.785219 -19.824109 -33.800207 0.923858 1.531743 1.009904 0.958128 1.510327 1.064141 1.264489 0.272369 0.456308 0.414523 2.396468 1.688411 1.627350 1.374638 2.036090
+1 0.046489 1 1 0.496919 1.371250 -1.696662 -1.124184 -2.185120 -1.668621 -1.092941 -0.163078 1.753897 1.754942 0.465930 -1.110261 29.057400 -32.275456 -53.582070 46.152425 33.800464 1.891050 0.876903 2.102835 0.856741 0.744757 1.873871 2.400035 0.892160 2.038434 0.711009 1.678012 2.341270 0.983748 2.349161 0.847981
+1 0.029808 1 1 0.178729 2.098376 -0.114417 -0.355814 -0.146652 -0.202190 -0.579430 2.030968 -2.072184 2.063916 0.338656 -0.782330 -33.583010 20.346368 -38.601092 -18.549320 -58.426421 0.282060 1.339994 0.282210 1.597968 0.296611 0.645775 1.034024 1.339346 0.638461 1.868940 0.524995 0.590959 2.249212 1.752819 1.884620
+1 -0.011450 1 1 0.780461 -2.086141 -1.597315 0.413944 1.671901 -0.334535 -0.653869 -0.277934 -1.266648 2.023724 -1.302540 1.976722 13.748061 63.656136 68.682321 -56.231427 68.414276 0.456127 1.868796 0.354874 1.121114 0.310048 1.477800 1.136480 2.069339 0.385923 0.966308 1.731829 2.358531 0.823947 0.830802 1.285499
+1 -0.013179 1 1 -1.182737 -1.397445 -0.313359 1.831658 -1.354815 -0.113009 -0.244059 -2.125582 -0.042461 -2.063450 -1.933914 -1.950288 28.341924 -57.275424 71.955797 61.086915 -62.223768 1.452005 1.843328 2.072387 2.103860 2.319422 0.518553 0.326574 2.484864 2.366787 2.332410 0.567536 2.328534 0.663435 0.845282 1.658848
+1 0.047053 1 1 -1.140274 0.695417 1.155848 1.874581 -0.956458 -1.226509 -1.939361 0.752911 1.415726 1.257179 -0.946959 -1.794981 14.934789 58.992666 -10.259039 -73.669949 -70.829103 1.003894 1.199351 1.246309 0.715366 0.657382 0.376057 1.637690 1.897723 0.530678 1.603494 0.924790 1.451864 1.731618 1.051939 0.936117
+1 -0.017209 1 1 -2.196332 -1.601692 2.244111 -1.194576 2.259010 -0.534664 0.435869 -2.115115 1.519215 1.725741 -0.227042 1.138299 -29.128863 31.192306 -0.920667 -23.649472 23.323745 2.157798 2.108884 1.269951 2.067081 0.684082 1.372524 0.252098 1.755254 2.301573 2.032562 1.012347 1.521573 1.082152 2.480068 0.507891
+1 0.044049 1 1 1.227840 0.753757 1.486814 -0.918678 2.274240 0.972950 0.374525 -1.117120 -1.277674 0.492192 2.027578 2.210801 -7.982907 -68.715890 -57.971533 72.438483 73.581191 0.311049 0.292950 2.112750 0.994208 0.410614 1.945069 2.017635 2.142583 0.639757 1.141152 1.839751 0.436997 2.115135 0.578029 0.930382
+1 -0.044559 1 1 -1.806890 -1.766895 1.265933 0.097574 0.009212 -0.681672 -1.045843 -0.263223 0.948575 0.682468 0.289433 1.323116 -5.152232 -43.569168 32.997872 45.242681 43.733549 1.821373 2.070285 0.537906 1.593649 1.950014 1.888466 2.453790 2.091925 1.986060 2.454617 2.498824 0.730638 0.836377 0.489767 0.268662
+1 0.032599 1 1 0.905717 1.367856 -2.188357 0.485003 -0.994583 -1.105652 -1.738793 2.347839 -1.421704 1.944589 2.283823 1.812405 6.847411 34.443942 49.325303 -39.627007 -11.105968 0.505018 2.341860 1.896340 2.027609 1.030577 1.912220 1.174541 0.519541 1.167434 0.318318 0.965431 0.496958 1.869616 0.627238 2.231114
+1 -0.005516 1 1 -1.351371 1.225435 -1.965975 1.125741 0.093789 -2.345921 0.663205 1.684035 0.960085 0.935769 2.232232 1.788398 63.129781 72.233484 -71.835827 5.250729 49.003576 0.671559 2.396028 1.045539 1.368639 2.464535 0.440986 1.648328 0.705369 1.383814 1.012923 2.202497 1.860534 0.989523 0.407038 0.337326
+1 0.037508 1 1 1.888836 -1.698302 -0.428904 1.358680 -0.900824 0.762795 -2.114774 -2.171837 0.094177 -0.523827 -1.211253 -0.013482 -12.478442 -25.175007 33.661425 -52.421786 47.050576 1.060337 0.337776 1.748703 2.456487 2.422270 1.085176 1.553080 1.865562 2.252072 0.326768 1.239210 0.646777 2.126275 1.048092 1.535660
+1 -0.011800 1 1 -1.571063 -1.344680 0.589607 -0.637131 -1.708033 0.968767 0.770461 -0.513869 1.217210 1.162634 -1.896093 2.244855 60.064927 11.231096 61.035380 -28.368054 68.119844 0.478219 1.920887 0.601394 2.122158 1.603406 1.703337 0.486355 1.424880 0.458673 1.919085 1.805720 2.231353 0.858027 2.102902 1.979089
+1 0.018942 1 1 -1.316626 0.845970 0.945051 -1.985274 1.933604 1.452328 -0.895194 1.130705 -1.305769 -0.465167 -0.208398 -1.236437 26.846763 13.547366 -9.421750 48.638954 -25.098143 1.007564 2.121577 0.850109 1.779260 0.766684 1.408638 1.982930 1.596231 0.346308 1.152261 1.803933 1.452725 0.450976 0.805622 1.094468
+1 0.037540 1 1 -1.077324 -1.581682 -0.737052 1.245878 2.324153 1.041104 0.738096 2.177020 2.178680 1.816731 2.224406 2.214841 53.414535 -11.917296 -43.988382 37.261597 5.663177 0.340229 2.479913 2.389454 0.804982 1.588143 1.672631 1.902001 0.436848 1.860208 2.264711 1.251947 0.973870 0.574762 2.280335 0.587728
+1 -0.050970 1 1 0.189719 -1.677149 1.667013 2.330775 -0.758575 -2.353188 1.053124 0.121549 -2.303755 -2.227980 -1.017939 2.192244 -35.560132 -59.144158 14.141155 70.396490 -46.196923 0.899722 0.882652 1.987895 1.799966 2.281756 1.971316 2.155515 1.987994 1.215492 0.272682 1.212130 2.260764 2.417404 0.310455 1.563936
+1 -0.015492 1 1 1.867182 1.934914 -0.090320 -0.622076 1.556482 1.321215 0.882058 -0.421930 0.759616 0.998122 -0.669802 0.539074 -54.359987 21.693863 -41.248924 29.330586 59.156813 2.103324 2.310118 1.655461 1.337844 2.396789 0.326549 2.067206 0.536953 1.326589 2.223921 1.938525 2.296977 1.285816 0.953800 0.771781
+1 -0.019176 1 1 -1.391471 1.141425 -0.203636 -1.308423 2.047554 -1.339728 -1.016521 -2.258395 1.447527 -1.477585 0.515733 1.848625 33.734785 -19.471616 40.542184 -57.509823 32.402173 0.374839 1.426704 1.858224 0.422517 1.751348 1.906153 0.468700 1.683548 0.896423 1.688072 0.422103 1.536682 0.757329 1.681491 2.327775
+1 -0.012974 1 1 -0.439156 -1.286968 -0.210073 -1.119339 -0.880786 -1.750127 0.343390 -1.328347 1.773971 -0.161063 -2.075275 1.958136 -29.615343 -45.067705 47.079876 21.477984 -69.520060 0.270399 1.088351 0.918861 0.804641 0.346603 1.611066 2.192461 1.934980 1.206526 0.325973 1.377584 2.054320 2.211819 1.035152 2.307025
+1 0.043584 1 1 1.937778 0.913147 -0.993132 -0.285378 0.864830 2.195819 -2.304026 -2.060830 -0.304240 -0.425547 1.234759 -0.760581 51.778816 -53.435544 -41.182658 -56.937937 44.098526 1.583948 0.915469 2.281260 0.393000 0.658445 2.479559 0.942695 0.875306 2.273646 0.676328 1.542203 1.309806 1.405441 2.243989 1.718298
+1 -0.042183 1 1 1.284953 -0.675172 -0.189279 -0.353784 0.991854 -2.333657 -0.561847 0.670814 2.333745 2.034906 -1.845159 0.645304 -73.035213 -52.832344 46.788504 74.387647 -16.819190 2.423100 1.539338 0.404361 0.347863 0.281162 1.996139 0.852259 1.918537 1.603348 0.712566 0.841603 0.574722 1.603872 0.533432 0.636486
+1 0.026730 1 1 -2.067347 -1.452716 -0.907980 -1.711942 1.238638 -1.540220 -1.318404 -0.764692 -1.489595 1.293450 0.769413 0.731735 -34.079819 70.490052 26.297537 -67.293206 3.086086 0.892841 2.228001 0.766920 0.870403 0.864937 1.238464 1.618301 2.290402 1.031506 1.778526 1.942424 0.321156 1.414917 1.761652 1.833075
+1 0.012682 1 1 -0.783426 -0.632361 -1.661226 0.680094 -1.914999 0.236222 2.347079 -0.052998 -0.103215 -0.578418 0.187230 -1.103079 -28.853100 15.951746 50.988361 11.383250 68.283535 1.245562 1.663822 2.363879 0.712784 2.259292 2.424340 2.126125 0.776718 1.295681 0.251356 0.532406 1.403413 1.919705 0.975689 1.905954
+1 0.000078 1 1 -0.081658 -1.116842 -1.317143 1.587215 -0.511749 -0.863255 0.726002 1.544153 1.449207 -1.511996 1.805081 -0.371680 57.421971 -8.928128 -55.048835 -5.774354 0.436329 1.125726 1.333507 1.502154 0.945846 2.091796 2.069196 2.481827 0.820084 1.144563 0.669656 1.916726 0.416905 1.917335 1.651096 2.213690
+1 -0.002698 1 1 -2.222536 0.946404 1.902759 1.405436 -2.036688 0.176557 -1.411130 0.597093 -2.046075 -2.083668 2.271220 2.050014 73.517603 60.359615 14.047922 3.424316 -47.525583 1.187814 0.830703 1.868301 1.028830 1.802887 1.866057 1.578204 1.124795 1.433760 1.206187 1.381591 1.896962 1.244648 2.056320 2.070459
+1 -0.005699 1 1 -1.225161 1.863846 -2.305398 -1.565488 -1.890088 -0.494758 1.963957 -2.066530 -1.854367 1.386483 -0.135460 -0.599278 -53.607387 70.654642 -57.435073 -61.269510 -6.658799 1.158588 2.388617 2.483877 1.516347 0.996704 1.857977 0.776224 2.004257 2.290534 1.008558 0.842676 0.603895 1.406071 1.578077 1.240315
+1 0.017812 1 1 1.332700 0.696809 0.974990 1.682536 -0.667732 2.331036 -1.075277 -0.172211 -0.945253 -1.411752 -0.437846 1.869827 -23.457767 -54.696992 57.653774 -13.019817 25.932311 0.540320 1.662465 2.050744 0.609130 1.644191 0.923570 1.192805 1.471255 1.388087 0.825535 0.523607 2.005532 1.221266 0.566542 1.367296
+1 0.019936 1 1 -2.213641 -0.345954 0.638878 -1.918768 -1.849238 -1.942615 -2.100938 -0.530352 2.208124 1.876341 0.349863 -0.911625 -54.364617 -56.110031 8.714697 67.921315 53.532829 1.768840 1.139952 1.921097 1.879846 1.565871 0.840273 0.716789 2.066821 0.812883 1.624014 1.556335 0.316272 0.328599 0.509895 1.059210
+1 0.019062 1 1 1.932260 -2.285968 -0.162415 -1.234913 -1.814222 2.241525 -2.232385 0.349852 -1.094813 1.363650 -2.194570 -0.269112 29.691081 -32.008945 -74.335326 -3.827178 26.619308 0.485714 1.892528 0.972753 2.055822 0.447557 1.839015 1.577079 2.458605 2.033267 1.621140 0.497759 1.840331 1.192038 2.089255 2.108786
+1 0.078182 1 1 -0.034495 -0.133905 1.978371 -0.137939 0.152559 0.512007 0.473233 -0.887662 0.494194 -2.023359 -2.000194 0.922070 -57.929396 30.641159 35.953814 -74.248394 -42.753998 0.378396 0.446699 0.926465 0.340430 1.361485 1.480613 1.157866 1.499906 1.427160 0.528215 0.704116 0.573600 0.749791 0.983941 1.096374
+1 -0.028252 1 1 2.277891 1.071857 -0.761723 1.283896 0.418482 -2.174071 0.255470 0.705044 -1.984999 1.833430 0.138381 -2.145024 -52.576349 -0.702562 42.037969 32.151983 -71.622393 1.261607 1.329558 0.377109 1.324378 1.073428 2.097523 1.562888 2.463534 1.618440 2.368848 0.983470 2.184749 0.569123 2.000260 0.369319
+1 -0.021688 1 1 1.700020 1.014388 -0.601159 -0.309826 -0.059085 1.276046 0.422270 0.239519 1.207385 0.964875 1.317750 -0.811216 -37.379136 -31.134260 -73.503622 24.632209 -6.459361 1.937771 0.862888 0.551217 0.297692 0.809412 1.786960 1.939032 1.810208 1.159091 1.838084 1.685907 2.295170 2.423543 2.242188 0.702912
+1 -0.020719 1 1 0.365096 0.644339 0.332656 2.055976 -1.154994 -1.654568 -0.514480 0.368150 0.132659 0.632606 1.066995 2.340368 7.838540 42.337934 -26.335340 31.942680 10.619110 1.005762 1.096542 1.324452 2.315114 2.376647 1.558577 2.006227 1.654916 1.174336 1.561772 1.707255 1.080919 2.000646 2.353797 2.261504
+1 -0.007239 1 1 -1.006092 -1.338115 -2.179044 1.491461 1.792669 -1.629893 -0.492567 1.090567 -2.030658 -2.152977 1.345609 0.890073 74.432202 -17.987092 -59.057576 -30.673051 28.035765 2.081477 1.890232 0.638015 1.112839 0.743334 0.460858 0.383324 2.283105 2.141375 0.583979 1.943299 1.518537 1.804943 0.419967 1.633968
+1 0.021771 1 1 1.251277 -1.178182 -0.241956 0.244525 0.525787 1.178017 2.184110 -1.177016 0.498846 0.766507 -0.984824 -2.033830 34.782577 40.779598 32.708194 -23.385108 -33.514552 0.938907 2.459281 2.142166 0.384184 0.977194 2.442425 2.331647 1.241322 2.400586 1.153577 1.411180 1.952884 0.627450 1.295718 0.885961
+1 0.048343 1 1 -1.894129 2.280991 1.336593 0.167407 0.310196 1.569794 -1.140884 -0.120486 1.315618 1.053642 -0.595871 -0.972252 61.521939 49.234962 -57.996254 -43.039591 -66.401076 1.331662 1.993636 1.547338 2.113559 1.082783 1.835851 2.402658 2.217100 2.055568 0.676555 0.853039 1.518453 0.387937 1.062850 2.073456
+1 -0.003071 1 1 2.326330 -0.068286 2.139117 1.320196 -2.113685 2.005569 -0.115050 -1.559926 2.054722 1.325425 0.953182 -1.993346 -57.365251 62.220992 -51.781939 0.945650 -6.454860 0.822446 0.342950 0.966434 1.602468 1.686259 1.458753 0.514535 0.295724 1.481305 1.548831 2.450604 0.300209 0.360388 1.541344 0.374222
+1 -0.025538 1 1 -2.306760 -0.889283 1.525384 1.738033 -0.981346 -0.118421 -1.679309 -1.642377 1.741847 1.860541 -1.294935 -2.151752 -51.551428 -24.847778 -16.606456 45.294162 8.973889 2.487362 1.599175 0.328052 0.326876 0.800488 0.298816 1.693905 1.709411 1.322524 1.411005 1.258411 1.605990 2.372277 2.354740 2.369023
+1 0.005120 1 1 1.823215 -1.886082 0.859347 -0.421611 1.420073 -1.091754 0.927428 -1.299376 -1.406584 1.592077 1.092058 -0.535538 -3.888384 47.920942 57.263829 33.172304 -23.089007 1.270965 1.101573 0.388403 2.142152 2.405386 0.818611 1.137534 1.789028 0.690712 0.292993 0.589505 0.310331 1.731932 1.831657 1.650109
+1 -0.067259 1 1 -2.270417 2.022583 -1.615007 -0.053830 0.058563 -0.619295 1.169502 0.449935 -1.319131 1.154498 -1.968052 -0.791063 -55.459398 -6.099819 -69.654590 65.307737 -72.872498 1.103786 1.574397 2.388562 1.565216 1.077891 0.605084 1.140830 0.924705 2.270226 1.681722 1.698376 0.360735 0.618096 1.586339 0.604470
+1 0.021857 1 1 -0.907658 -1.006306 -0.220765 -1.750098 0.831766 -2.160599 0.481252 1.936171 2.183584 -0.598121 -1.096232 1.065610 -66.469211 51.977191 -19.343541 -56.900258 -72.642936 0.477609 0.667326 0.999014 2.421390 2.056070 2.362586 1.487571 1.111839 1.927162 0.318906 1.851961 0.904572 1.386489 0.974000 0.519924
+1 -0.030623 1 1 -1.706599 1.504173 -1.328294 -2.058440 2.155666 1.425972 -0.906300 -1.749008 0.309766 -0.949977 -0.681736 -2.126342 42.234475 34.825417 10.786396 -63.050216 65.023795 0.698944 1.397340 1.089664 0.483652 0.995184 1.053105 0.288859 0.854882 0.996224 0.540245 0.395579 1.252826 2.253205 1.362736 2.259781
+1 -0.041634 1 1 1.181478 -0.899767 -0.332076 -1.735715 2.237718 -0.257326 1.100504 0.042494 -2.084514 2.189843 0.931709 -0.034529 -22.254373 70.752337 -65.465933 -35.932189 -12.304409 2.121850 0.938150 0.979496 0.641306 2.437501 0.571367 1.461593 0.991105 2.246934 1.716982 0.317073 0.298610 0.486295 0.412872 1.636133
+1 -0.022178 1 1 0.852124 0.697149 1.977075 1.640341 1.740497 -1.975895 -0.666084 1.770077 0.378997 -1.342525 -0.898219 2.134044 28.426421 12.856062 71.841979 -51.855782 -40.130638 2.490521 0.695340 1.573214 0.506959 1.202404 0.803929 1.892879 2.364395 0.380625 1.911572 1.541764 0.673607 0.815578 1.926325 1.987094
+1 -0.006432 1 1 -1.084838 -0.635260 1.450963 -0.274974 1.368319 0.885180 0.213828 -1.750598 1.860092 0.577300 -0.131699 1.353559 -68.545110 -37.668217 60.279966 25.384244 32.990031 2.326870 1.946665 1.851403 0.522602 0.871424 2.265544 1.753179 1.176293 0.706372 2.495981 2.452456 2.176339 0.975892 0.817462 2.090155
+1 0.015088 1 1 -1.665143 0.826820 -0.477796 -0.408897 -1.674300 -2.280197 -2.119557 2.272238 0.307662 1.381425 -0.324695 -0.201005 15.885361 -14.738841 -65.694440 23.551411 -21.436194 1.703340 0.539835 0.255471 2.198741 1.740099 1.837445 2.184213 0.575650 1.455229 2.031254 1.543034 1.776277 2.382778 1.104560 1.089383
+1 0.044128 1 1 1.880777 -0.480020 -0.081419 -1.815446 0.516078 -1.792417 1.149402 1.922780 -1.407733 1.132418 -0.784458 0.877862 -8.158782 -24.641643 -2.099750 -40.490715 22.555287 1.925593 0.935462 0.807618 0.886440 0.396700 2.087837 0.777990 2.431579 2.295119 1.571938 1.569500 1.087692 1.086535 1.889723 1.075847
+1 0.011435 1 1 0.475998 -1.545347 2.038650 -0.186337 1.970277 0.496298 0.347301 -1.558866 1.025462 1.731463 1.695877 2.078127 -36.723901 31.387883 -13.849100 38.178653 -31.376736 2.143027 1.358402 1.415844 1.581681 1.068016 1.144043 0.937348 1.004801 0.689540 0.854053 0.575309 2.461488 0.974687 0.819497 0.279059
+1 0.015589 1 1 -1.925378 0.151073 -0.898546 1.345943 1.794055 -1.900298 2.266523 -1.493956 -1.312424 0.789965 2.150383 2.184361 -53.052391 -51.532549 -7.555811 59.477771 42.903399 1.786484 0.682545 0.278524 0.397109 2.217362 1.960102 0.427388 0.360770 1.213009 1.299767 1.437431 2.151375 2.167261 1.406871 1.533437
+1 -0.026649 1 1 -2.345925 0.595086 1.918265 -1.881627 0.338268 2.132859 -0.179577 -2.217372 -1.798132 -0.656752 -1.615284 -0.007759 48.798067 -50.880595 -0.167309 38.029940 19.197108 1.311933 1.156591 0.325778 0.354185 0.795585 1.146797 2.220850 2.078060 0.698983 2.053058 1.253052 1.553263 0.443849 0.273749 1.151107
+1 0.003975 1 1 -1.223834 0.608684 -0.443929 -1.406025 1.574657 0.478377 0.746013 -1.423954 1.836836 0.835282 0.375035 -1.956284 -29.222340 -39.867581 -4.436074 -7.103178 16.896524 1.823282 0.402003 1.220036 2.396199 1.659080 1.407831 1.923340 1.321192 1.523030 0.813559 1.744412 2.331274 1.718826 2.052399 1.417767
+1 0.009037 1 1 1.923678 -0.440145 0.938376 -1.077891 -1.691427 2.033521 -1.577336 1.620098 0.797237 1.837177 1.855291 -0.009443 48.013880 -30.721611 -38.110935 -30.486428 14.601555 1.500069 1.914090 1.114839 0.607821 2.141297 1.532509 0.379895 0.892693 1.998555 0.957756 2.003996 2.407255 0.731473 1.370098 2.238434
+1 -0.014861 1 1 -1.384893 -1.415861 1.185412 -0.757199 1.917743 -1.240698 -0.094925 2.093386 0.835378 1.988907 -2.135018 1.595042 -29.199155 49.795213 58.152002 -39.299336 -53.942712 1.147705 1.729511 1.647868 1.976387 1.886138 1.565555 2.283490 1.862240 0.421830 1.440505 2.073562 1.605137 1.532101 0.263788 2.482120
+1 -0.000689 1 1 -1.434660 0.962995 -2.002268 -0.952838 -1.644155 0.137012 -1.596833 -0.911310 -1.116573 -1.504983 1.850399 -2.109594 2.249409 5.812227 36.098718 -38.842721 -29.608501 2.423766 1.477602 2.314779 1.242260 2.413755 1.978054 0.646666 0.270093 0.447994 2.432494 1.917924 0.304618 2.472726 0.853620 2.292811
+1 0.056756 1 1 2.339205 -0.439225 2.253309 -2.106550 -0.613911 2.135885 -1.163775 1.559654 -1.917150 1.776012 1.162770 0.399079 50.400704 34.626553 -31.517425 -63.356825 11.844482 1.678049 0.723604 1.862225 2.420069 2.350052 2.322656 0.883030 1.592416 1.479942 1.139144 1.848142 1.971149 1.607603 2.491808 2.074018
+1 0.034773 1 1 1.017752 -0.614990 -1.864641 -1.636751 2.044994 -1.950272 1.151836 0.421966 -0.161002 -1.046003 1.753578 1.111635 -43.885447 -32.710869 -21.576209 68.652338 39.837657 0.647563 1.839876 0.300593 2.308854 0.668045 1.828997 1.951429 0.920766 1.309247 1.019791 0.623278 0.936439 1.481947 1.075953 1.786397
+1 -0.005469 1 1 -1.965375 1.791060 -0.390141 -2.168367 1.864828 0.069639 1.751535 -0.250001 1.678192 1.724720 1.467881 1.323845 -64.700540 -71.972046 -34.181809 6.336743 1.632614 1.215171 1.629578 0.561547 0.666872 2.363396 1.603757 0.852392 1.910328 0.886037 0.367759 1.679379 0.571782 1.687424 0.778584 1.155134
+1 -0.045858 1 1 -1.188070 -1.504908 -1.604610 0.330534 -0.625590 -0.953336 -0.593369 -1.335548 -1.438642 0.004289 1.404128 -0.459077 -48.400154 -11.393739 55.435324 51.489050 26.468049 0.602549 1.298384 0.690015 2.081626 2.140634 1.639606 0.362497 0.986744 0.952127 1.894749 2.297033 2.226295 1.336726 1.602138 0.642138
+1 -0.013490 1 1 -0.913543 -0.954099 0.709763 1.921916 -1.785707 0.829864 -1.139987 0.806607 -0.897643 -2.324727 -1.270048 1.419247 -26.622559 4.655730 -51.147571 12.766230 62.028519 1.574809 0.313079 0.675187 0.359796 0.585680 1.277557 1.646595 0.817702 1.620104 1.081127 1.007544 1.792441 1.811313 1.736336 1.600048
+1 0.009479 1 1 1.070668 -1.903936 -2.335474 1.889854 1.282651 -1.662535 2.244023 2.040328 -0.263677 -1.971058 0.516286 1.709940 -60.236403 -43.223487 -7.140344 -7.763964 11.055494 0.770250 0.597807 0.339114 1.739886 0.523034 1.390133 1.460131 1.173746 0.651716 1.897050 0.464446 2.201587 2.316671 1.545627 0.355796
+1 -0.029562 1 1 1.032075 -0.227357 0.557615 -1.104919 1.146609 2.093379 0.725510 -2.021670 -1.891175 0.093001 -1.452647 0.247646 36.265247 60.001931 2.458340 67.326455 -44.269234 0.879781 0.973413 1.907924 0.975581 2.335519 1.065706 0.572812 1.001252 1.796754 2.301021 1.766303 1.250595 0.748905 1.842945 2.375892
+1 -0.012472 1 1 -2.001536 1.936178 2.298726 -2.195741 -1.097100 0.621287 -0.677702 -0.296436 -1.204794 0.171112 1.315194 -1.355375 -3.155375 67.621279 -39.169065 35.524003 51.922777 0.866579 1.850687 2.003071 0.372145 1.135258 1.784799 1.621407 0.490428 2.371081 0.260205 0.757610 1.895668 1.989658 2.190467 2.183932
+1 0.032658 1 1 -1.418339 1.951448 -0.247874 -0.262014 -2.301770 -1.844536 1.689574 -0.182941 -2.214126 0.928441 1.586646 -0.652843 -60.356187 43.565113 48.849321 60.544390 -30.439756 2.110420 2.324013 1.184737 0.868015 1.222371 1.146059 1.058103 1.041460 0.318296 0.605426 2.390241 0.530400 1.429819 2.470960 0.432708
+1 0.010366 1 1 0.784715 -1.277694 0.146249 -1.857565 -0.512593 -0.902219 0.872768 -1.053901 0.963321 -1.227591 -1.287208 0.469943 11.760325 -44.221606 17.465642 -4.954940 -27.678170 0.820002 2.032006 0.670932 0.852441 0.481575 2.073644 0.739934 1.828335 2.069497 0.786462 0.823058 1.636185 1.366746 2.155515 1.995777
+1 -0.022419 1 1 1.881586 -1.033916 2.269643 -0.892903 1.940338 1.535972 0.618240 -0.060211 1.203342 -1.009051 0.762468 1.813939 -72.771432 30.549136 -10.667843 -44.443435 39.191117 1.901529 1.497241 1.634693 1.028011 1.525927 2.260491 2.322707 1.737329 0.296987 2.462294 1.032270 1.105093 1.039572 2.333253 1.238275
+1 0.013260 1 1 -0.137883 1.096820 -0.609590 -0.643301 -1.739060 -2.146726 -1.966587 0.277346 0.796466 -1.697955 0.690314 0.204433 18.357715 -11.890521 -43.978411 54.849599 -42.794866 1.325211 1.578974 0.560152 1.971932 1.260066 2.421108 1.808436 0.626658 1.498120 0.654149 2.282412 1.742556 0.385112 0.820309 0.430956
+1 0.033373 1 1 1.459831 -2.024065 0.274233 0.311550 0.763030 1.834727 -1.612681 1.332326 -0.875713 -1.315303 -0.478380 -0.797941 14.544992 -42.312340 6.504291 -32.378289 18.090284 1.275991 2.329591 0.430527 1.374453 1.186971 2.415651 2.349780 2.255518 1.987342 1.500708 1.390920 1.188806 1.768026 0.970762 2.340873
+1 -0.000827 1 1 -0.562300 -2.244172 0.158960 -0.284948 -1.338262 0.055612 1.624902 1.430966 -1.786169 -2.229289 0.543667 0.083289 8.057307 -30.838483 -52.388353 8.946713 67.406667 0.682901 1.761963 0.311514 1.365103 1.534910 2.484036 1.944779 1.654132 1.489702 0.913510 0.868259 0.826050 2.419894 1.652743 0.651633
+1 0.030336 1 1 1.946148 0.211006 -2.051484 1.264468 -0.967220 1.667778 1.057074 0.541572 -2.133136 0.240768 -1.348087 -0.132078 -9.505545 -9.690758 27.423305 -46.507458 -0.854874 1.856927 1.119824 1.129792 2.166286 0.775175 2.363141 1.809370 0.581505 0.853000 0.868774 0.488837 0.381647 1.088030 2.275793 0.745978
+1 0.033299 1 1 1.544312 -0.593890 -0.668692 0.348006 0.862721 -0.262065 1.557675 -2.195262 2.234862 -1.132963 1.047321 1.545282 50.378626 -36.426700 -73.552854 -52.825551 10.967405 1.062683 1.513395 0.874719 1.407737 0.337901 1.606452 1.141478 0.575110 1.372142 0.595665 0.335129 2.264082 1.929410 2.101627 0.795681
+1 -0.067612 1 1 0.382100 -1.032314 0.907853 -0.435448 -0.238267 0.975276 1.771117 -0.990194 1.967319 -2.107653 -0.289408 -0.888327 -40.000105 18.240671 -29.037086 73.701597 2.743594 2.298833 0.986046 0.469082 1.369090 1.038467 1.760657 0.859757 1.941950 1.347175 1.725436 0.656376 1.465676 2.109613 2.267294 1.901182
+1 0.010634 1 1 -0.486372 1.532300 0.165018 -2.145026 -1.670470 0.820521 2.039284 1.037100 -0.580751 -1.327308 0.382356 -1.445682 -15.760915 6.296502 -74.690129 32.998335 53.009569 0.352518 2.012199 0.786149 2.311003 0.770096 0.256171 0.468642 0.710087 1.930374 0.297985 1.236732 1.748966 2.371075 2.416276 1.606845
+1 -0.024487 1 1 0.347746 1.199598 2.039242 0.333302 -1.219804 -2.346897 -1.599051 -0.489969 2.340995 1.364545 -1.288019 0.973939 -58.670416 26.312791 39.085737 63.988306 -48.537608 0.301238 1.901395 1.495325 0.924990 0.308432 1.309543 1.495818 2.460708 1.378205 1.247111 0.700609 2.389203 1.076577 1.029463 1.184872
+1 -0.000318 1 1 1.504968 -2.112917 0.761964 -1.949418 1.364768 -2.251834 -1.378547 1.573051 1.766332 -1.307301 2.065379 1.372285 49.889219 -11.903617 35.913171 -7.327250 0.903987 2.024546 1.291774 2.102027 0.765419 0.399756 1.698814 0.964374 0.727875 1.646962 2.486462 2.217794 2.457292 2.458826 1.244504 1.879895
+1 0.000799 1 1 1.363374 -2.120433 1.677811 0.027357 -2.026016 0.463475 0.048704 -1.388302 -2.161223 -0.583746 0.181668 -0.326021 33.990403 -73.289128 29.621461 -2.100846 -58.927684 2.161163 2.417026 0.709738 0.561325 1.439892 0.766380 0.804486 2.240369 1.639735 0.269834 0.595161 0.870289 1.188951 1.952833 2.021266
+1 0.040922 1 1 1.948399 0.345018 -2.229163 -2.053013 -0.874483 0.511899 -1.329468 1.772262 -0.601642 0.993520 2.100539 -1.462722 18.001212 -3.633212 -13.399319 -52.357498 -72.460842 1.384483 0.997606 1.263536 2.250097 0.876048 1.231438 0.528667 1.559322 1.018273 2.110087 1.236449 1.497616 1.187583 1.453198 1.655005
+1 -0.007806 1 1 -0.322002 -2.059237 -1.811600 -0.814672 2.005135 2.014761 -1.142499 1.010836 0.954116 -0.432381 -0.528441 1.350415 49.730924 27.645810 -56.869045 1.956639 35.228694 1.955007 0.304218 2.492369 2.498866 1.445542 1.221404 0.635726 0.894288 1.794585 1.845445 1.645700 1.535374 1.274474 1.592937 1.242292
+1 0.012956 1 1 2.351936 1.473765 1.249731 1.120384 -0.417521 -0.521247 -0.264319 1.381508 1.056347 -2.255536 -2.343012 -2.287483 -65.398619 45.405097 73.468621 -12.882471 -65.695728 1.403379 1.341027 1.887403 0.326233 1.255528 0.405519 1.800468 1.715886 2.142166 0.386808 2.325237 1.509109 0.844104 2.101538 1.556653
+1 -0.002736 1 1 0.791386 -2.251647 1.765180 -1.814868 0.812846 0.281930 -2.273237 1.754190 1.958850 1.645135 2.191518 0.818079 -41.533228 51.036316 67.367018 37.473661 -30.173044 1.849836 1.189186 1.399507 1.515533 0.819695 1.371503 1.106297 1.037626 1.124150 1.842435 0.550148 0.343324 0.495393 0.317984 2.113163
+1 0.018499 1 1 1.654985 -1.892195 1.786559 -0.639873 -0.669109 -1.960584 2.195427 0.541016 -2.056559 0.791361 2.040042 -0.362696 63.744426 52.565454 -32.407478 -22.475150 -39.852985 0.488175 0.508766 2.327179 0.397158 0.791250 0.291713 1.566359 2.304145 0.269667 2.297531 1.609463 2.249269 0.459376 2.479046 1.334761
+1 -0.056998 1 1 -0.966258 -1.000137 -0.211977 -0.129781 0.599965 -0.906776 -0.316836 -0.068260 -2.136529 -0.232597 2.024855 -1.128819 0.781671 -62.451315 -69.244387 59.586157 64.546412 1.848113 1.485625 2.147840 1.254435 2.295784 1.486712 2.419247 2.032714 1.330756 0.270775 0.664257 1.163800 2.230070 1.783885 1.996489
+1 0.026279 1 1 -0.414606 1.347889 1.508590 2.216862 -2.058312 -0.411177 -2.292927 0.694115 -1.883666 -0.943558 -1.182464 -1.527383 -74.447998 52.495907 -1.291379 45.790091 -55.933458 1.020630 1.222136 1.691232 1.784345 0.743344 0.639645 1.515441 1.519986 1.409651 1.001943 2.151691 0.717511 0.710251 2.436886 1.492156
+1 -0.008318 1 1 -1.204882 -1.320315 0.105925 -0.995463 -1.761117 -0.582004 1.170260 -0.944402 -1.244700 -1.382239 0.779418 -0.760432 -18.657531 72.872499 18.083309 26.168210 9.110782 0.998710 1.819562 0.880233 1.820871 0.380186 1.286608 0.774396 0.527383 2.476639 1.371248 1.319235 2.386108 0.813403 1.371696 2.091360
+1 0.006929 1 1 0.547341 0.577633 0.757567 -0.451512 -1.614492 -0.828599 -1.160564 -1.012015 -1.925165 -0.986894 0.889105 0.199025 -24.870603 49.778968 -64.891238 22.963040 -10.181323 1.862568 1.425432 0.740234 2.370097 1.725694 0.496231 0.905343 0.856061 0.562497 0.891370 2.254113 0.883055 2.005126 1.145009 1.413501
+1 -0.021300 1 1 2.285950 -0.151220 -1.580035 -1.332051 0.771002 -0.842859 -0.486137 0.777121 -1.672558 -1.276742 2.020296 -2.354345 14.484735 -5.060175 3.642989 27.719029 -26.280874 2.085157 0.730152 1.669117 1.343070 2.484350 0.463843 1.062310 1.994843 1.571577 2.247010 0.753449 1.722537 1.429051 0.810380 2.310289
+1 0.010025 1 1 0.277399 1.699863 -1.612564 -1.419106 -1.515676 1.205736 1.536234 0.304820 0.739391 0.377754 1.321155 -0.122319 -38.718140 -35.781584 -31.085193 1.153081 29.831067 2.436025 0.524030 2.378471 0.708780 2.460181 1.504687 0.781759 0.525318 1.516253 1.664717 1.651402 0.616620 1.530515 0.618616 1.333951
+1 -0.021204 1 1 -2.200355 1.456492 -1.604728 -1.667636 1.326169 -0.674133 -1.561753 -0.374954 -1.390369 0.804161 0.407481 1.426012 -7.361531 24.747813 -13.508017 70.765997 14.111609 1.732218 2.138141 2.484435 1.901557 1.968414 0.637037 0.424124 1.754482 0.579677 1.627341 1.226121 1.159253 2.313639 2.332357 1.926539
+1 -0.008749 1 1 -1.724090 -0.302089 -1.959584 0.156626 -1.804391 -2.183226 1.893741 0.626416 0.695889 -0.350749 0.163810 1.118190 13.267537 -62.511264 -26.813905 -61.297620 -29.094840 1.420443 2.376430 2.413587 1.399079 1.077000 1.381095 0.310758 2.157488 1.397720 0.728329 0.280114 2.369692 1.655794 2.434759 1.738681
+1 -0.008281 1 1 -1.277146 -0.064390 1.645158 -2.135207 -1.582174 0.414530 2.095466 -1.903263 -0.442796 -1.204495 0.468329 1.507643 14.175733 51.552539 43.530104 60.460533 60.170450 1.146340 1.292724 2.312931 1.674998 1.192609 0.426268 1.782363 1.173233 1.022915 1.388142 1.745271 1.015625 0.353983 1.888144 1.540364
+1 -0.063485 1 1 1.952484 -1.681570 -1.945378 -1.408105 -0.399497 0.804039 -1.653166 -0.510012 0.069537 0.029049 -1.856254 -2.049156 -64.464654 -7.434303 1.663565 59.536108 -26.632539 1.178762 1.701774 1.217178 1.615129 0.717147 1.335884 0.954415 2.098280 0.791881 1.896193 1.810084 1.336349 2.021619 1.605673 1.550244
+1 0.002646 1 1 1.459077 -0.570460 1.996285 -0.649470 -1.745230 -2.168680 1.318739 1.682061 0.776831 -1.832467 1.901040 0.778535 -46.482868 -37.560358 73.067833 1.062467 6.886915 0.600810 1.311630 0.559253 0.369747 1.341024 1.838713 0.996769 0.695917 2.278385 1.572292 0.766048 1.965847 2.499688 1.752472 0.550930
+1 0.026816 1 1 -0.451267 -2.210678 2.326152 1.661213 -0.899277 -1.520686 1.825779 -1.205427 -1.057674 -1.190073 -2.183768 2.201893 26.331104 46.871013 -38.878724 -34.713241 74.558958 1.561128 2.128819 1.067617 1.194345 0.348995 1.302480 2.027971 0.355796 0.870266 0.805895 1.184446 0.485476 2.386705 1.848767 1.233427
+1 0.058107 1 1 -0.510390 -1.580213 0.377089 -0.424184 0.585034 -2.083131 1.866108 -1.981228 -0.759053 -0.961512 -1.344120 0.562450 1.289014 64.453909 -23.145862 -62.510729 -17.816711 0.693154 0.846753 1.633317 0.414672 0.395796 0.386441 0.670177 1.668317 1.405056 0.267312 0.963640 1.894758 2.441588 1.762126 0.805928
+1 -0.023526 1 1 1.979483 -0.297474 0.201021 -0.231077 -0.698246 -1.572835 1.860683 1.082224 -0.888196 0.930065 0.606019 1.892390 47.447378 48.084605 -42.043647 22.420705 24.794674 1.736286 0.760577 2.259429 2.471019 1.416206 0.930937 1.261494 1.678243 1.731471 0.834220 2.486328 2.223167 0.525039 1.335605 0.760718
+1 -0.001329 1 1 2.037289 0.499015 -1.110884 -0.144903 0.913825 0.984299 -2.089301 1.846071 0.549950 2.019214 -1.688915 1.838402 -35.676414 -63.488739 44.758118 -0.303734 -4.859897 2.420685 1.460097 0.595297 0.910910 2.168785 2.268534 2.491878 0.988470 0.716282 0.294856 0.393436 1.234190 1.788661 1.275949 1.628229
+1 -0.014364 1 1 -0.390332 -0.665354 -0.106478 1.129279 -1.709621 -2.158517 -2.225524 -2.151234 -2.338136 -0.434987 -1.918610 0.798294 23.913588 65.673938 -68.126101 -45.377501 -59.651761 1.867891 0.900503 0.496057 2.477863 1.686023 1.997112 1.454249 1.304274 0.683052 2.051774 2.171638 0.715360 0.561059 1.474729 1.275187
+1 -0.014190 1 1 1.104143 -0.053182 1.522870 1.887457 -1.321570 -2.135044 1.163572 -0.260334 -2.331201 -1.697466 -0.499071 0.173704 -71.397758 17.885696 4.893453 44.264024 -54.544839 2.348247 1.240425 0.829218 1.664576 1.524741 0.326112 1.467706 2.477780 0.292280 2.103186 2.241656 0.762831 1.895112 1.642996 1.075248
+1 -0.017721 1 1 0.079587 -0.701638 -2.028129 -2.054008 1.247595 -1.796999 -0.463816 -1.064287 0.757424 1.866274 0.809992 -0.556975 -72.306711 41.107956 1.412605 41.659966 -20.949439 0.666692 1.586159 2.070188 1.152669 1.903963 1.901797 1.509227 0.583588 2.119013 0.507470 0.800107 0.647436 1.964307 1.354057 0.392696
+1 -0.026836 1 1 1.382029 0.392110 2.268566 -0.147921 2.037249 -0.176643 -0.037773 1.318281 -1.302962 -0.409576 1.057192 -2.194185 47.263506 -42.249648 10.162123 -55.190805 8.133143 2.031102 1.233976 0.431847 1.060132 1.393074 1.390861 2.452173 1.923880 1.396918 0.747330 2.374659 1.896157 1.217055 1.790644 0.850639
+1 -0.026192 1 1 0.061191 1.135810 -0.321604 -0.083607 -0.897210 0.244353 2.351840 -0.135976 0.166640 1.565715 0.985320 0.932001 4.845631 -9.479837 -27.619999 40.670215 -5.704771 0.923661 0.469639 1.731038 0.296986 2.441797 0.784802 2.174754 1.334876 2.015859 1.534166 1.232292 1.376222 1.657524 2.252094 0.688059
+1 0.013243 1 1 -1.882754 0.240079 1.207593 -0.237559 -1.267950 -1.006718 2.280141 1.180090 -0.679815 1.886557 -2.299448 -0.522775 74.295174 -71.011686 56.598923 -41.907442 61.627844 1.812598 0.836857 1.804577 1.019943 0.937743 0.890596 0.488969 0.350017 0.493888 2.032059 1.573234 0.844036 0.969170 0.347354 0.724736
+1 0.027298 1 1 0.998841 1.986680 -1.859763 0.240417 2.175194 -0.222413 -1.173391 0.162743 2.042008 -0.302771 0.707034 -1.524363 40.831266 1.091213 40.012994 48.395186 -72.102664 1.682771 1.338559 0.906018 0.939215 0.881987 2.057097 1.626598 2.234836 0.890949 1.933544 1.830651 0.494500 1.064975 1.790973 1.881466
+1 0.042672 1 1 -0.277138 -2.025638 2.105111 -0.008645 0.793224 0.373940 -1.509742 1.988476 0.059002 2.046818 0.436770 -1.116584 -53.787795 38.521575 32.109114 -42.122252 51.318226 1.456395 1.376073 1.400906 0.276614 2.048874 0.674731 1.702519 2.487219 1.436150 0.880097 1.782838 2.406476 1.137369 1.252316 0.425101
+1 -0.045635 1 1 -0.527736 -0.940387 0.274816 0.694730 -0.965344 0.218205 1.127494 1.276005 -0.262276 -1.988903 2.195171 0.940848 -61.958770 -41.040438 -66.647369 57.664271 13.408068 2.116090 0.868474 2.191386 1.880362 1.242094 1.869524 1.337513 1.328595 2.195455 0.509947 1.926857 1.934448 1.262201 2.305367 0.552041
+1 -0.006903 1 1 -2.089799 -1.814020 0.929592 2.082300 -1.693856 -1.090979 -0.181747 -0.988488 -2.339455 0.959916 -1.910772 0.584948 37.429818 -17.042536 66.095792 -28.023703 5.615429 1.802755 1.897370 1.345066 2.266513 2.281174 1.188012 1.915558 1.027517 2.234644 2.167350 0.649755 0.432294 1.820987 2.333941 1.551196
+1 0.046632 1 1 1.926330 1.710914 0.341180 -0.769146 -0.949928 0.129348 1.544783 -2.102626 -0.632069 -1.465579 -0.329439 0.182331 43.857587 14.472892 -54.097267 -62.769953 -24.592906 2.380361 0.986032 2.493507 1.371191 0.354068 1.067230 1.426057 2.240802 2.153725 1.147134 1.135719 0.529682 0.620985 0.638910 0.402494
+1 0.004243 1 1 0.639122 2.181761 1.759976 0.255892 -1.640925 -2.133709 0.036719 -0.189738 1.366870 0.088768 -1.895235 -2.179882 49.289042 -49.067164 28.177545 30.001358 -67.180538 0.575529 1.671580 2.246041 2.461384 1.488760 0.830397 1.240569 0.995799 2.396456 1.491398 2.426609 2.021862 1.186319 0.458368 1.296988
+1 -0.022051 1 1 -0.244032 -1.668407 -2.198747 0.215338 0.078442 -1.089452 1.918036 -1.021521 -1.476224 -0.162611 0.180546 -0.348826 -15.975876 -6.542990 -18.027041 19.525641 -32.556954 1.604046 1.194976 1.962702 1.379257 0.918850 0.606254 0.560981 2.399557 1.849592 1.584662 1.669591 0.315519 1.175309 2.159377 1.648946
+1 0.015372 1 1 -1.655750 -1.534470 1.066412 1.962351 -0.780750 1.932243 2.139266 -0.884440 -1.908966 -2.049498 1.649129 -1.366364 -32.271134 19.048202 43.133951 2.311499 -0.642392 1.424652 1.128450 2.108452 0.749939 1.221453 1.455229 2.031853 0.355675 1.080084 1.469513 1.361254 2.089761 1.606873 1.458596 2.369350
+1 -0.055810 1 1 2.081103 1.747901 -0.066659 1.206066 -2.337268 0.004799 0.539074 -1.699434 -0.602404 2.317600 -0.704657 -0.943541 -28.728675 7.153698 -67.788679 -74.328898 -45.791585 1.837356 0.690432 2.332832 0.906507 2.409162 1.291074 1.576438 0.700343 2.420659 1.011059 2.364702 1.055549 0.867466 0.998287 1.458562
+1 -0.003301 1 1 0.811154 0.122236 -0.185587 0.436382 1.800708 1.530810 -1.318854 1.097437 0.335581 -0.614822 0.951068 0.172681 -18.316572 -46.633320 -16.209785 -37.862491 -54.884420 2.238337 1.229922 2.049392 0.378336 1.699606 0.782064 1.150073 1.032040 1.752224 0.874349 1.933473 0.624218 0.977342 0.443460 0.487799
+1 -0.001416 1 1 1.851058 -0.463427 0.752939 1.884814 1.394438 1.617019 0.895925 1.725007 1.579477 1.376395 -0.050890 2.350501 29.101132 -47.271378 59.946050 -36.740015 60.559897 0.327763 2.215397 0.433009 0.335446 0.846733 1.299233 1.461110 1.871407 1.488260 1.435114 1.457530 2.461523 1.569143 1.837964 1.909109
+1 0.003469 1 1 2.119817 2.107073 -0.024731 -0.970655 0.484751 -0.518555 -2.140364 1.272710 0.905595 -0.674755 2.105296 -1.612785 -13.494514 -2.295513 -30.683829 -3.119639 68.223899 1.961156 2.394911 0.262476 0.675922 1.476019 0.445898 0.962405 1.398518 0.645671 1.540084 1.688436 2.049023 0.933356 1.417442 1.439169
+1 -0.001596 1 1 -0.020116 1.209976 2.099902 1.971572 -1.308389 -2.093845 0.865840 0.310479 1.612090 -1.839979 -1.825724 2.140321 -63.624455 13.778059 -32.159373 -52.583261 33.131030 1.873382 0.927024 0.736030 1.449609 2.075737 2.163816 1.998639 2.384622 0.598726 2.280472 0.644937 0.462179 2.337229 0.557832 1.232479
+1 -0.002973 1 1 0.130462 1.406381 -0.305149 -1.554932 1.163604 0.284250 -0.978841 -0.433661 1.517116 -0.575436 -1.529829 -1.036532 22.354845 -32.126688 46.750380 33.634578 -53.649149 0.906394 0.521090 2.457373 1.570485 1.899268 1.738469 1.452153 2.086264 1.336928 0.506040 1.510606 1.249878 2.200935 0.368228 0.564767
+1 -0.017980 1 1 -2.192061 -0.505095 -2.116100 -0.900743 2.117246 1.302978 0.681314 -0.254092 -1.104421 0.089922 -1.363438 1.053395 -1.099354 -26.848060 -35.352413 -18.009795 9.372878 1.824484 0.350434 0.745587 2.334813 0.445925 1.417571 1.373201 0.389999 1.964456 1.615430 1.277382 0.954146 2.081645 2.459539 1.975629
+1 0.004758 1 1 1.555764 -1.326378 1.870039 -1.894719 1.785583 1.795029 0.337247 -0.885971 0.633198 1.578262 -0.185634 -0.346341 -36.653361 16.964256 -31.742901 47.070569 15.060168 2.368692 0.600858 2.115302 1.128758 0.530171 2.091108 1.757596 1.172955 0.851706 1.618715 2.491791 1.776473 1.181305 1.698249 0.464192
+1 0.052283 1 1 -0.707961 0.084810 2.261446 -2.008960 -0.317009 1.739389 -1.741603 2.240577 0.684698 0.060501 -1.038158 1.647851 22.990531 1.847604 2.673767 -62.002597 -27.644617 0.278856 1.480729 0.859437 1.065451 0.786895 1.337136 1.743286 1.407864 2.474723 0.671442 0.429189 1.382654 1.761822 2.443869 1.856127
+1 -0.022519 1 1 1.702346 -2.299785 -1.474849 -0.614986 -1.807845 1.040798 0.311759 -0.436638 -1.385570 1.350999 1.953489 1.082413 73.287883 -50.556608 45.094453 -47.528921 -68.581257 0.697148 0.467130 2.308733 0.872492 2.224808 1.094084 0.526398 1.667898 1.118877 0.974833 1.021702 1.238066 1.681493 2.344786 1.561151
+1 -0.042713 1 1 -1.555882 -0.656449 -1.239068 -0.974830 1.008663 2.139887 0.121105 -0.337844 0.291500 -1.637954 0.684372 -0.700715 -20.708363 -45.449712 -73.313843 64.246696 -55.784310 0.371552 2.424575 1.589527 2.433007 1.548328 0.745889 0.652091 1.448197 0.839592 0.519579 1.814260 1.771894 0.728494 0.804411 0.983486
+1 -0.045959 1 1 -0.595814 -0.024413 -0.323734 1.814333 -0.368750 -0.796060 -0.902824 0.129003 0.462630 -0.027215 -0.303129 -0.596036 30.837741 39.919773 -18.373893 39.974278 -2.317720 2.066173 1.166071 2.147942 0.715235 0.699930 2.215413 0.700847 1.887401 0.299872 1.453373 2.337892 0.452161 0.472638 0.382887 1.678779
+1 -0.054489 1 1 -0.459083 -1.620520 1.531989 -0.360308 -0.269772 -0.732904 0.274895 2.016874 1.382213 -1.218153 1.827658 2.089806 61.832097 12.058253 13.059706 44.476045 58.885218 1.132839 1.629715 0.612523 2.421199 1.094938 1.368493 2.268493 1.817986 1.394338 2.381113 2.360584 1.587267 0.448712 1.000221 2.459787
+1 -0.007044 1 1 -1.967753 -0.476696 -0.771978 -1.423454 0.813673 0.054393 -0.026379 -0.379270 1.474675 -2.296355 -0.366726 0.238480 -67.338195 -3.044492 -18.777369 8.752456 -47.464229 0.905480 0.900028 1.524735 2.478345 0.797656 2.206095 1.584832 2.274856 0.753500 0.331485 1.767069 0.622294 2.391592 0.742034 1.119899
+1 0.003720 1 1 1.420789 1.534227 -0.442934 1.187901 -1.343883 -0.154853 -1.376224 -1.787813 -1.590032 0.289752 1.960927 -1.140566 16.022062 32.801033 36.967131 6.576008 -27.040725 1.773020 1.644244 1.805903 0.815733 2.281872 1.665985 0.454730 0.903834 2.494997 1.661149 2.424391 0.742345 1.846225 1.253840 1.283294
+1 -0.018906 1 1 -1.604414 -1.098755 1.082004 0.131345 2.121409 0.581015 1.048593 -0.633340 0.736057 0.892206 0.491201 -0.492549 44.339092 7.110887 -37.325894 -36.303200 52.118843 0.795813 0.472512 0.515717 2.155175 0.776408 0.581927 1.203610 0.828978 2.140491 1.490212 0.487599 2.079375 0.297319 1.297446 0.672867
+1 -0.039194 1 1 0.087918 -2.057124 0.721521 1.624505 -0.523605 -2.191259 -1.164728 -0.325052 -1.488326 -0.934925 -2.171766 1.300035 -52.745750 2.186784 3.277870 41.160722 -11.741579 2.264158 0.950434 0.450150 0.427920 0.301608 1.383531 0.753139 1.004153 1.043820 1.727503 1.641151 1.576839 0.682531 2.305255 0.919974
+1 -0.011661 1 1 -0.317666 0.132206 -2.256858 -0.993989 -0.550238 -2.140768 -0.791471 0.828930 1.996647 0.726735 -0.282650 -0.418355 -13.076385 -24.804852 -45.149824 16.911005 -26.731270 1.038078 1.984568 2.141274 1.143589 2.306820 2.469615 0.318224 1.639044 2.155670 2.345619 2.067665 1.504155 0.827009 0.546378 2.224421
+1 -0.007691 1 1 -0.494928 -0.883138 1.125495 0.671202 -0.565549 -0.288267 -0.563025 -0.285667 0.713846 -0.129788 0.490318 -1.198210 -72.278646 62.800883 -55.557342 -2.252936 -65.093452 2.490222 2.403242 0.793776 2.245062 1.762825 1.308255 2.336623 1.617383 0.350822 0.518418 0.300692 1.723570 0.794810 1.614660 1.836390
+1 -0.001701 1 1 -1.076717 -0.814756 0.600858 -0.024862 1.551820 -1.639521 -2.086938 -0.856396 -1.804588 -0.784106 2.080948 -0.859542 59.365579 -42.710790 59.750908 -16.484927 -12.167858 0.547106 0.959983 1.184231 1.369188 0.444395 0.453370 0.539545 2.127475 0.970761 2.321697 0.509170 2.368781 2.100873 1.627968 0.517119
+1 -0.053030 1 1 1.673104 1.041097 0.621848 -0.683911 -0.969080 -1.318025 0.893947 1.463897 0.336778 0.654851 -2.052373 0.454287 35.880940 50.954557 43.245192 71.936416 35.337773 2.454372 0.631199 1.306465 1.503053 0.315059 2.454180 1.909871 2.201518 1.169142 2.014747 0.858837 2.222998 2.172768 1.710827 0.373577
+1 0.010148 1 1 -0.329862 -2.225433 -0.612231 2.093213 -2.063166 -1.865101 0.063397 0.505687 -2.061122 -0.510841 0.269560 1.895211 56.588162 -72.764661 -5.657020 22.464201 5.820216 1.680689 2.337707 1.838902 1.924355 0.386166 0.534151 1.477017 1.475301 1.889828 0.596078 0.535884 1.354488 0.878158 0.706791 0.534571
+1 -0.016931 1 1 1.493353 0.602958 2.282327 0.218776 1.306575 -0.123065 0.383841 -0.049033 0.565422 -1.839282 0.466965 2.150730 -45.246469 42.587589 -30.394554 58.723862 -28.059652 1.396519 0.792912 1.219020 1.063827 0.489456 1.783743 1.863207 0.921069 1.899506 1.249892 2.441426 1.294267 1.244009 0.302302 1.784216
+1 0.015675 1 1 0.531782 -1.737518 0.210006 -0.002651 -2.147353 1.631791 -0.599335 2.059255 2.107311 -0.740485 0.084684 0.137659 -4.476704 60.037496 0.189466 34.358101 -43.391910 1.557414 0.448265 2.491373 1.508362 1.793810 2.321197 1.101331 0.816245 1.886759 0.761181 1.171844 2.434318 1.087392 0.538838 1.494998
+1 -0.004927 1 1 0.795694 -0.527411 -0.191342 -2.032927 2.122238 0.389400 -0.861791 1.755132 -1.042948 1.263916 -0.812382 -1.913516 50.669259 48.234971 -64.838185 14.629116 21.559616 0.662013 1.698135 0.802119 0.705961 2.328243 0.287094 0.437544 2.300972 0.940355 2.041661 0.946832 0.659923 0.318259 2.235912 0.970661
+1 0.010294 1 1 -0.584877 0.017278 -1.771204 -0.458303 2.054096 0.227272 -1.991065 -1.153313 -1.674668 0.947632 -1.028123 0.670652 -12.266806 -68.202878 14.228345 35.799217 27.447884 2.373671 1.045383 1.008109 2.278958 2.191037 0.509587 0.379918 1.288199 0.510678 0.722713 0.388413 2.299597 0.333954 0.519778 0.666901
+1 0.010271 1 1 0.167770 1.696543 -0.865283 -0.373263 -1.243141 1.262274 -0.134216 1.472260 -0.471911 -0.463206 -0.237577 -1.567349 -5.609450 71.978301 -10.702226 -22.304192 -16.550213 0.483657 1.071908 1.300927 0.676734 1.616787 1.596644 0.551888 0.335713 0.833362 1.565695 2.390868 2.076522 1.862027 1.332080 2.259951
+1 -0.063234 1 1 1.830036 -0.354531 -2.141571 -0.154777 -0.097416 -2.064591 -2.254753 1.395628 -1.944748 -0.241316 1.563742 0.819325 25.503528 -62.202915 55.614507 63.027418 1.811253 1.250964 2.455384 1.887005 0.391908 0.290275 2.150952 1.792420 1.455675 0.527705 1.138603 1.745016 1.233053 0.672271 0.855951 0.970139
+1 0.027073 1 1 1.733242 -1.393458 0.727296 -0.269570 -2.060511 0.331654 -0.650104 1.733321 -0.058996 -1.950338 0.047918 -0.469027 28.099562 69.342386 -62.524399 52.429654 -64.803327 1.382250 1.726313 1.892322 2.008152 0.263153 0.816712 0.722665 1.828119 0.699124 2.181427 1.001682 2.276934 1.935077 0.591869 1.791419
+1 0.037936 1 1 -1.342976 0.951371 0.552880 -0.571368 0.863359 1.034139 1.476202 -0.205128 1.877423 -0.314055 -0.442774 -0.841182 -18.279991 -31.805882 38.543170 -54.939098 38.571782 1.014065 1.144290 0.581352 0.527089 2.040603 1.159031 0.831764 1.708455 0.996138 1.345593 2.131226 1.016514 1.807316 2.057109 1.826235
+1 0.040554 1 1 -2.119174 -0.713172 2.033678 1.068758 -1.010896 -1.959268 0.758111 -0.731893 -1.589312 -1.742773 1.423285 1.061026 31.194332 33.134605 -56.695035 -73.457521 49.438070 2.209662 0.790782 1.430943 1.103869 0.718757 1.391089 1.781727 1.738032 0.848444 0.792644 1.225858 1.246196 1.068154 1.220430 2.261989
+1 -0.058503 1 1 -1.591307 -2.291886 -0.660988 -2.120201 0.868748 2.069451 -0.872047 -0.972096 -0.171182 2.214056 -2.095242 0.953315 7.943906 13.222638 -67.128614 69.383999 36.877133 1.284739 0.863700 0.697902 1.891006 2.386518 0.963655 2.148755 0.868964 1.427253 2.087310 0.912661 2.337637 0.671896 1.311689 1.565362
+1 -0.025674 1 1 1.041190 2.181983 0.784065 1.935351 -2.176242 1.457911 -1.309343 0.720155 2.234694 0.758848 2.239736 0.679000 -46.339760 -32.344122 -7.650654 -34.549379 -21.405093 0.544000 0.515979 2.062984 1.575805 1.310486 1.593247 1.953897 1.899492 1.006303 1.176423 0.645318 2.352640 0.821613 2.093761 1.345373
+1 -0.009386 1 1 -0.759822 0.243775 2.055884 2.001759 1.814203 2.159847 1.015799 -0.442602 2.053489 -0.544227 -0.080658 1.554423 -9.614683 -43.979618 34.556606 -7.125743 -62.359156 1.070068 1.877603 2.132818 0.780285 0.496242 1.093675 0.398510 1.010069 1.483482 2.131723 0.362175 2.325009 2.175839 1.582387 1.676386
+1 -0.006663 1 1 -0.456146 0.618678 -2.113567 -0.732253 1.777631 0.105173 0.496868 0.501340 0.274017 1.407620 1.675921 1.249154 26.661427 48.604660 -1.483238 -28.787134 74.630519 1.602011 0.744433 0.936726 1.803434 2.068218 1.795472 0.989875 1.828387 0.696688 1.739064 2.450978 2.080947 1.967866 0.429558 0.826930
+1 0.032270 1 1 -0.066442 0.151672 -0.245066 -0.191818 -0.616947 -1.766937 0.565970 -2.049773 1.736727 0.633773 1.831548 1.497338 51.228399 -4.295577 -45.760002 -38.354736 71.958466 0.713980 2.114534 1.729447 0.572167 1.416442 0.395925 0.304185 1.940968 0.602656 0.839271 1.870347 1.669589 0.289034 1.551433 1.190967
+1 -0.011101 1 1 1.894387 2.069664 -2.019050 -0.253018 -1.899156 -2.101534 -1.119107 -1.678931 -0.013465 -0.108740 0.819566 0.136138 -68.672290 74.823160 -47.150990 -16.693705 -71.102906 1.726797 1.018571 0.363955 0.736676 1.066415 1.235929 1.764110 0.400376 0.868220 2.418253 1.083222 2.469919 0.931357 1.571216 0.669273
+1 -0.008197 1 1 0.743664 1.504741 -1.214714 -1.624918 -1.698795 0.714490 1.259245 0.788723 0.125573 -0.637711 -2.037698 2.043677 -16.521591 -28.378216 47.326944 -26.051624 0.347549 1.243897 0.678704 0.979655 1.059860 1.311355 0.440273 0.917750 2.369661 1.151217 2.246250 1.480151 2.404460 1.005678 1.924483 0.276809
+1 0.026390 1 1 -0.886549 0.344027 -0.039999 1.609801 2.093277 -0.983551 0.517824 -0.716049 0.813462 1.215594 2.280125 0.915395 -28.645020 63.141370 -32.993230 32.790134 3.783132 1.121601 1.746820 2.298203 1.644861 0.925175 1.171427 2.168426 0.740860 1.625895 1.659449 0.850927 2.037782 1.002106 0.396897 0.905347
+1 -0.043861 1 1 0.798898 1.477698 1.381899 -1.783531 -0.302798 0.259411 0.953718 2.311017 1.746523 0.333603 -0.871839 -2.173313 -36.642203 54.498934 63.582807 36.240475 -56.343695 1.097684 0.272761 0.291141 0.955645 0.268377 0.856657 1.584056 0.470443 1.729611 1.070544 0.877082 0.622413 2.147700 1.145771 0.726420
+1 -0.045779 1 1 -0.140378 1.566628 2.201670 1.785904 -2.224559 -0.062577 -0.863303 -0.092348 -1.716731 0.853117 -1.454397 -0.891494 65.361247 -73.526406 -58.308517 -41.241202 9.125442 2.444451 0.383497 0.680861 1.230892 0.360351 0.927219 1.768409 0.647956 1.697866 0.779144 1.578010 2.367368 0.860766 0.892727 0.307545
+1 -0.048363 1 1 1.644024 -2.342637 -0.692833 -0.128661 0.586478 -1.378368 -0.131221 -0.040330 0.751515 1.503239 1.816122 1.417059 3.101229 72.348461 60.585137 54.404730 -19.704999 1.646273 2.161708 0.326784 1.505269 1.556769 0.868104 0.473989 0.591087 2.156654 0.886997 0.753453 1.788149 1.676098 1.677599 2.153670
+1 -0.012092 1 1 -1.429369 0.359284 1.912988 -1.041805 1.629823 -0.675008 -2.142830 2.250774 -2.304360 1.740054 0.005654 0.779077 -56.893900 34.215179 -45.481903 -14.351141 0.375469 1.532681 1.023266 0.538165 1.447045 1.732940 0.771023 2.328384 0.402626 0.431317 1.143014 1.630704 1.488320 2.439339 2.215740 1.697230
+1 0.058953 1 1 -2.354202 -1.859231 -0.245685 -1.182095 -0.036184 -0.240933 -1.419382 -1.435011 -0.229948 -0.584309 0.137682 0.238570 -19.231851 20.277888 10.456567 -56.481650 62.913972 2.051939 0.437166 0.441063 0.696612 0.450008 0.289390 0.784045 0.695250 2.319377 2.020967 1.889744 1.431080 1.168210 2.106742 1.257619
+1 0.058423 1 1 0.194035 0.178383 1.004163 1.900408 -0.417721 0.823769 0.083415 -2.333446 -1.731715 -1.218079 -1.634026 0.720723 74.985039 -26.450679 43.442974 -53.934941 -34.561022 0.368466 2.304073 1.299869 0.896716 2.102959 0.686332 0.939671 1.797663 1.828489 2.421416 2.497588 2.468251 2.145119 0.515044 2.091286
+1 -0.017974 1 1 -2.200893 1.837594 -0.547475 1.876686 1.444924 1.905488 0.139622 -0.146289 1.183456 -0.654627 1.118616 -1.848757 45.611884 -51.064625 56.851168 -2.421129 -41.914635 0.485903 0.573636 1.355006 0.583983 1.994841 1.543526 1.032693 1.475073 0.305802 2.108080 1.255917 2.440623 1.300483 2.221577 0.797474
+1 0.028397 1 1 2.037012 0.562198 0.521613 1.707462 -1.139034 -2.021961 -2.065873 -0.247737 2.028658 1.524792 1.202313 0.557158 20.144153 12.781622 20.720155 -56.360791 -5.815671 2.215133 0.485051 1.997195 0.612872 1.534420 0.990263 1.601781 1.383288 1.170292 1.101025 2.431646 1.179319 2.061081 1.081694 1.529473
+1 0.012726 1 1 -2.196218 0.312279 -1.124996 -1.695028 -1.947993 1.767587 0.935070 -0.101026 -1.480943 0.624349 -1.063360 2.192994 65.677862 -2.167417 22.216523 43.102369 71.508743 2.086779 0.995296 0.681827 1.717787 0.351376 0.825055 1.448778 1.602997 1.574710 0.898205 2.384781 1.023125 0.413054 2.451019 0.529984
+1 -0.034115 1 1 0.837958 -1.764893 1.926906 1.965601 2.016782 -0.165862 2.086846 -0.685927 -1.865243 -2.321212 1.265475 1.834529 -7.497537 -11.110031 23.709884 -57.974425 23.835556 0.687792 0.725174 1.251199 1.895859 0.703344 1.098764 0.419247 0.779014 1.646267 2.058359 0.337407 2.298088 1.967115 1.293542 0.313194
+1 0.006170 1 1 -1.528579 1.115185 1.740868 -0.459617 -1.180260 -2.186236 -1.571083 -1.683431 -0.233102 -1.743997 -0.301204 -1.232275 3.505559 -32.076939 -17.118678 -13.615368 66.508090 1.397030 0.387375 0.605882 1.064652 0.847964 1.730177 1.587260 0.328246 1.337701 2.243766 2.483887 1.686770 1.047810 1.291671 0.362172
+1 -0.043909 1 1 1.249251 -2.249270 -0.697229 1.388682 -0.882865 1.006216 -1.286336 0.995293 -1.095124 0.845885 -0.483088 0.192933 15.814831 -0.129729 69.644940 72.505631 2.135029 1.876429 0.387370 0.530374 0.988072 0.767815 2.423704 0.448953 0.560017 1.951244 2.306978 0.632163 1.769710 2.269766 0.712513 2.208513
+1 0.021723 1 1 -0.398875 1.829168 -0.805086 -1.814394 -0.657682 1.605734 -0.283388 1.323253 2.152820 0.719396 -1.104527 -1.684455 44.421633 44.382188 -18.573900 -21.531931 62.835572 0.286909 1.829708 0.408376 0.328122 1.491575 0.892390 1.404950 0.745250 1.164573 1.726496 0.461417 0.788697 2.379041 1.298645 0.579282
+1 0.016035 1 1 -2.199277 0.723643 -0.401338 -1.867539 1.491591 -0.731171 1.121606 1.276579 -0.052289 -2.310408 -0.941536 -0.187940 -44.993536 -56.364986 73.683612 0.459473 72.367182 0.253395 1.054602 0.690724 0.501153 0.382941 0.333987 1.064153 1.475062 2.362328 1.645304 1.625648 2.015374 2.394799 0.636272 1.069277
+1 -0.006336 1 1 -1.629474 1.834279 0.281903 1.994737 1.611182 1.750881 -1.814181 -1.791444 -1.341116 -0.775252 0.096151 -0.342010 30.064248 -60.178107 36.563203 -32.250696 62.544027 1.036953 1.073204 0.583828 1.639224 0.680795 2.363986 0.253952 1.424985 2.214094 1.035930 1.868165 1.006681 0.785117 0.717819 1.386567
+1 -0.021881 1 1 -0.405363 1.186477 -1.715279 1.701421 1.001818 0.181919 -0.835943 -2.059558 2.219790 0.019126 1.010316 1.647231 -8.656563 9.152364 73.782559 13.467068 -8.990300 0.625413 0.823146 0.863996 1.173824 1.952676 1.627613 1.287043 1.331053 0.765820 0.388512 1.726499 0.515055 2.282928 1.420117 1.407324
+1 0.046451 1 1 -0.859322 0.849024 0.424483 -0.274467 0.469224 -2.284328 -0.864738 -0.649329 0.619499 2.260495 0.857154 0.405751 20.186555 -24.562889 -28.482658 -58.031025 -27.440453 2.249574 1.089978 1.253562 1.109443 2.163621 0.981140 1.272495 2.071216 0.423707 1.489277 0.525586 1.518765 1.137120 1.582162 2.402178
+1 -0.000063 1 1 0.086822 -1.626477 0.363364 -0.201967 -1.533397 0.246746 0.150032 0.456963 -1.023871 1.450405 -0.227053 0.953525 -29.776653 -56.207324 23.505193 -48.228387 25.495220 0.597362 1.856364 0.651216 2.491412 2.156914 0.751469 2.195234 1.291138 0.405292 2.487132 2.230915 2.493769 1.279229 0.500946 1.397244
+1 -0.054777 1 1 0.227032 -1.300574 2.016547 0.606172 -0.256555 -0.085678 1.998470 -1.622106 -1.559448 0.671528 0.205772 -0.480977 -64.640463 37.731722 -42.943205 53.549357 4.034961 1.608750 1.516383 1.602905 2.281780 2.380962 2.073537 1.192867 0.266035 1.992231 0.419121 0.908305 1.134698 1.373105 1.025822 0.742958
+1 -0.015158 1 1 0.163538 1.266679 -1.499572 -1.453995 1.146833 1.149923 1.242204 1.838180 -0.127414 -2.029810 -2.031473 -1.715441 -32.262822 8.747720 22.921638 43.971882 -14.585079 0.903743 0.957931 0.448593 1.250435 0.305699 0.375058 0.600221 0.420609 1.181833 1.574320 1.093748 1.624701 1.844373 1.630633 0.297154
+1 0.017472 1 1 1.490046 1.563965 -0.152013 -0.767641 0.785914 0.026131 0.931531 1.678079 -0.176416 -0.934981 1.591752 0.337702 65.194835 -20.402335 -2.044751 -16.131155 -66.324474 0.393428 1.090093 0.947790 1.009658 1.326662 1.211575 1.942805 2.217023 0.759028 0.981957 1.508548 0.411648 1.319086 2.127165 0.271201
+1 -0.000038 1 1 1.319235 0.588014 0.864770 1.190003 1.001441 -1.440429 -1.748106 1.326996 -0.909046 -0.764226 1.633473 -0.602323 -32.881373 -37.236532 -34.396329 0.891996 -8.225170 2.268411 0.429737 1.589939 0.353456 2.041533 1.051928 0.749282 1.429152 0.257444 1.615616 2.162705 1.340339 1.568671 0.653552 1.241800
+1 -0.025916 1 1 1.742500 -1.293384 0.344611 0.354135 0.195852 -2.281026 -1.923332 1.554163 0.042899 0.009098 2.111730 -1.866706 43.202692 -42.355567 29.989085 26.555500 68.295443 1.997583 0.382638 2.003255 1.198424 1.417493 2.296373 2.394162 1.177369 0.782614 1.399322 0.646410 0.466724 2.237494 0.568058 2.099636
+1 -0.005802 1 1 -0.074620 -0.649126 -0.688082 -0.392280 -0.425843 0.978443 -1.540161 -0.332836 -0.367378 -1.296269 -1.027517 1.423895 60.242275 -8.087954 -34.235618 1.975513 52.445528 2.154829 1.711190 1.973626 0.475566 2.344768 1.266036 1.519693 0.985219 2.327381 1.538011 0.603341 1.103607 0.822517 1.537427 2.026736
+1 0.028452 1 1 -0.248346 1.219061 -0.704801 1.363956 -1.772216 1.373411 1.644262 1.655104 0.108667 -2.039512 -0.168918 -2.144289 40.817275 65.949122 56.898901 49.830635 53.481215 2.256777 0.649918 0.929456 1.110386 2.252704 1.939278 1.440705 0.930041 1.953262 2.475420 1.128566 1.801694 2.076392 1.928223 2.395747
+1 -0.037553 1 1 0.963347 -0.791106 2.245777 -1.466905 0.955265 0.025655 2.348692 -1.225221 0.845417 1.066402 1.802140 2.045968 9.077269 11.668990 70.715501 65.429910 30.490524 2.188658 1.029538 2.452568 1.811418 1.246389 2.054380 0.957556 0.890631 1.088760 1.044372 2.007867 2.216882 0.639199 0.773939 1.839184
+1 -0.002499 1 1 1.486644 0.939461 -1.688700 0.730309 -1.474427 1.760875 1.218059 1.293800 1.936613 0.193220 0.607290 -0.317544 69.160860 36.573336 -11.949684 11.660244 73.713981 2.288288 1.510968 0.589202 1.972960 0.539274 2.081873 1.784180 2.466934 0.260648 1.460689 1.541699 1.832604 1.816374 1.288805 1.700054
+1 0.021792 1 1 -1.234861 -0.943575 -1.469176 0.476490 2.016456 -0.924349 1.219977 0.549242 -0.460571 1.640821 0.385481 -0.763527 -24.482867 -33.541841 -37.713761 44.824660 68.053128 1.658719 2.092491 2.498867 1.452656 1.539253 1.230964 1.557258 2.330004 0.629345 1.659256 2.123401 2.254907 0.728779 1.095681 0.358352
+1 -0.004476 1 1 -0.070968 -0.521895 -1.725269 -1.266905 -2.295546 -0.909152 2.157190 -1.224733 -0.366945 1.280519 0.197640 -0.501192 70.850797 -60.652547 12.646143 -6.275500 -22.328486 1.751957 0.898145 1.375344 0.410748 1.944203 0.965654 1.994470 2.056019 1.507072 0.361758 2.071760 0.578604 1.599842 0.290125 1.875245
+1 -0.000137 1 1 -0.509197 -0.374159 -2.167763 -2.117922 1.479630 0.872014 0.413609 0.752098 1.879153 0.497988 0.487374 1.169059 -72.716138 59.867483 -7.205037 -45.055618 -49.776535 0.711525 1.358567 1.926687 1.332018 1.223783 2.367218 0.590360 1.180549 2.480684 1.859589 0.864200 2.363172 2.338671 2.297886 0.818743
+1 0.013451 1 1 -2.246267 -2.054662 -0.312048 0.289969 0.897424 -1.356650 2.029040 -1.476035 -1.702985 0.984219 1.286119 0.072526 -49.774773 -14.616263 44.471655 -14.901400 52.166227 1.491754 1.654854 2.378060 0.551027 1.604152 0.729382 2.229745 0.826013 1.804941 0.386809 2.341244 0.536770 0.495889 1.905721 2.198846
+1 -0.045041 1 1 2.263523 -0.084115 -0.011318 -1.725132 1.042614 -2.164394 -2.035973 -1.943007 0.741153 1.721620 1.190568 1.080906 17.081063 -18.573696 -18.113373 68.541433 -24.134665 0.905373 1.349316 1.698711 1.477900 0.564015 1.655001 0.353104 0.620185 0.692565 2.196365 2.305165 1.659674 2.394312 1.450046 0.423635
+1 0.008667 1 1 0.549620 1.186118 1.680911 0.295302 0.994413 -1.746459 0.740848 1.297754 -2.304156 0.464522 -1.203538 -2.289797 46.380152 -38.786826 9.816428 -15.296772 7.160798 2.147982 1.386837 2.319259 2.286026 1.729955 2.359153 2.289789 1.981263 0.586125 1.994811 1.040444 1.250787 1.726061 2.160659 0.696868
+1 -0.025904 1 1 0.846176 -0.315396 0.570523 -0.934631 -1.957568 1.061013 0.767676 -0.198622 -1.874620 0.289688 0.888763 -0.834445 -14.326167 -29.896739 25.513310 -47.799854 27.853579 1.151606 2.036162 0.777253 1.290720 2.386829 1.680437 0.351624 0.491652 0.437776 1.697723 0.637956 2.370483 1.462179 1.850622 0.901872
+1 0.054932 1 1 1.083366 -0.535677 2.253938 -0.965062 0.242282 0.524214 -1.697002 -2.138549 -1.210266 -2.269991 -0.228381 2.201016 6.991958 63.830745 3.334828 -51.542052 -17.263050 0.773674 1.885256 0.253678 1.311393 1.075864 0.298832 1.961285 2.316405 1.572752 1.734112 2.468310 0.877632 0.854545 2.088927 1.101432
+1 0.005222 1 1 1.143634 -0.776188 -1.490557 -0.736308 -0.395119 -1.016613 0.915249 1.355179 1.513591 1.454422 1.308212 -0.896642 11.206728 -48.515393 1.793530 -6.148493 12.271075 1.224484 0.651840 1.732928 0.567089 1.565354 1.155844 1.270167 1.193917 2.156446 1.884994 0.341695 2.369469 2.420767 0.584012 2.488237
+1 0.029459 1 1 0.081196 -1.925678 -0.186934 1.355707 0.961361 -1.183069 -2.277085 -1.659167 2.296429 1.625287 -1.524866 2.264497 68.407275 -28.926127 -11.417440 -42.906523 70.070812 1.827132 2.114181 0.290542 2.140662 2.101886 0.655029 1.326310 2.039469 2.357161 0.309291 2.260641 0.338957 1.352942 1.897422 2.222221
+1 0.011057 1 1 0.925181 -1.363979 1.382311 0.429095 1.845422 -0.944451 -2.065411 -1.902485 -1.507197 2.343215 0.972083 -0.061057 35.506615 59.686540 -48.327080 16.761997 18.877916 1.842046 0.759215 1.880541 2.002638 2.082991 0.331084 1.784229 1.037177 0.328534 1.676481 1.368775 0.252920 2.083897 2.049808 0.616705
+1 -0.007761 1 1 -0.222036 0.459578 0.523006 1.550429 -1.456376 -1.162857 -1.863619 1.406310 -1.499426 1.005518 1.109208 0.243855 -41.459764 -64.259625 -11.523050 -17.905940 -45.128030 0.373040 0.440708 1.475939 1.356621 0.722832 2.382264 1.465158 2.412541 1.821375 2.097879 0.807263 1.669113 1.285717 1.542554 0.449141
+1 0.003639 1 1 -0.603262 2.038098 -0.036957 0.897894 1.834094 1.885528 -0.753708 -0.668759 -0.779295 -1.889466 0.528305 1.086754 -4.384175 -34.835540 -30.924228 6.496882 -6.903259 0.278800 0.548473 1.439843 2.187386 2.144468 0.818925 1.927148 2.332553 0.726528 1.501644 1.381830 1.419814 0.811976 2.136995 1.221394
+1 -0.008010 1 1 -0.964493 0.386842 -1.437372 -2.212874 -1.596014 -1.285559 -0.082312 2.025982 -1.038153 1.733452 2.132245 -1.073152 -68.282804 20.911108 2.996103 -44.493140 -46.200234 2.315093 2.015427 1.030619 0.359285 1.002065 1.952068 0.414747 1.648277 2.089060 1.084507 1.554204 0.510744 1.822257 1.178229 1.741425
+1 -0.047490 1 1 -1.737404 2.121433 0.981984 1.420083 -0.911075 -1.882927 2.048651 -1.750606 1.717879 -0.410940 1.686706 -1.261387 28.884771 66.338411 -0.326053 70.032007 -22.051104 1.931304 2.432641 2.144958 2.317259 2.423793 1.932399 0.574301 1.284237 1.416908 1.481795 0.779203 0.318024 0.535840 0.606109 0.373127
+1 -0.008496 1 1 -2.096582 1.990069 -1.455365 1.694545 -1.455407 0.982412 -0.810523 1.061739 -1.165824 0.107070 -0.614139 -1.704818 -49.371358 15.588913 -47.140516 9.346775 41.250245 1.267998 0.749769 0.613899 0.792444 2.361120 1.592820 1.522319 2.365100 0.989787 0.352919 2.002294 0.806796 0.570194 2.004322 1.132524
+1 -0.024904 1 1 2.143169 -1.260233 1.454803 -1.709064 -2.227312 0.779255 1.212186 1.545422 -0.785806 1.782250 2.331167 1.129389 4.403294 56.154174 -16.799545 -49.949375 50.854495 1.547537 0.948396 2.196040 1.341553 1.735158 2.052072 0.417000 1.266896 2.475774 0.335045 0.851303 1.602699 1.067990 0.702454 1.897843
+1 -0.024683 1 1 -1.648941 -0.189131 2.145045 1.987572 -1.000051 1.233754 1.195791 -0.678836 -0.505415 1.924878 0.874708 -1.434592 67.131393 -22.680532 -41.703279 42.997312 -44.183555 2.229861 0.528941 1.659407 2.405165 1.611301 1.627864 1.014832 0.531133 2.499659 1.272477 1.772614 1.579591 1.940518 2.032440 1.217164
+1 -0.003044 1 1 1.124741 2.128053 -0.844729 1.075185 -1.369115 -0.125600 0.197722 0.879334 0.918088 1.951259 1.300835 -2.349625 -10.289091 21.241615 7.821948 63.482441 -0.611328 0.256173 0.501342 1.307850 2.288312 1.902899 2.021441 0.865186 0.935243 1.632780 0.377053 0.378986 1.367655 1.685924 0.326215 0.945516
+1 -0.006997 1 1 -1.597584 0.589135 0.855193 0.449831 1.630794 1.494639 -1.341950 -0.661493 -1.180316 1.591554 1.731880 -0.714892 44.631184 -33.697644 43.701263 -62.867443 -13.112965 0.780850 0.999699 0.436942 1.179481 0.288150 2.430706 1.120472 0.766303 1.755745 1.550769 1.281247 0.667679 2.435524 1.102333 1.905397
+1 0.009980 1 1 -0.571116 0.387405 -1.403823 0.873722 0.847402 1.439298 1.588879 -0.815169 -1.631462 1.402779 0.431333 1.760509 -6.965093 -62.321633 10.316492 -10.716525 37.361313 1.848852 0.409923 1.584215 0.908577 1.211011 1.463966 0.375869 0.734598 2.137867 2.380669 1.659020 0.393798 0.565397 2.373115 0.695375
+1 -0.031939 1 1 1.083974 0.257029 -1.380129 -1.443554 2.280616 -0.251197 0.437617 -1.005333 1.999631 -0.968085 1.279072 -0.553150 23.749613 9.753791 -18.040093 -49.836141 3.971186 1.280744 1.222649 1.315419 1.251727 1.783183 1.451354 2.161843 0.351029 1.742281 0.268332 2.363314 2.473591 1.893645 1.734068 1.737910
+1 -0.006381 1 1 -2.098006 1.623356 -0.987836 -0.819458 1.685668 0.141071 0.646914 1.201219 1.010891 1.889415 -1.382836 0.182993 -51.913113 46.302040 -1.609398 -49.148965 3.339606 1.806347 1.531650 1.682760 1.140559 0.881515 0.880169 0.742300 1.078758 1.678143 2.303091 0.542477 1.913773 0.285076 0.275442 0.350178
+1 0.079713 1 1 -1.190423 1.371009 -1.030328 1.304648 0.465708 -0.120002 0.026028 -0.806297 1.392615 -0.755012 0.977230 1.628382 -42.779565 -46.152569 -36.221160 -69.041204 24.480335 1.239877 0.619661 0.894098 0.862632 0.757111 0.262165 2.203875 0.281102 0.989730 1.645006 1.118945 2.115583 1.357972 0.941915 1.263434
+1 0.010185 1 1 1.550851 0.933537 -2.303190 -2.149584 1.832804 -0.943470 0.281449 -0.917483 -1.198201 -2.122181 0.571827 2.131179 -4.640747 2.956307 36.644603 -14.150087 -70.516035 1.179971 1.781482 2.124703 1.638516 2.286643 0.850073 1.170928 0.531718 1.090352 0.796150 1.648017 2.227194 0.694810 1.667788 1.512044
+1 0.022131 1 1 -1.987896 0.273504 2.195777 1.708548 -1.728748 1.528932 0.110472 0.017408 0.414875 -1.538126 0.875376 0.358840 -26.593008 51.310471 25.080874 34.248203 59.547769 1.665319 0.520815 2.345542 0.778257 2.423367 1.527868 1.134506 0.389715 1.688260 1.332344 2.206307 0.652800 2.102861 1.291639 2.069453
+1 0.057110 1 1 -0.663599 1.119590 0.378093 2.305021 -0.068698 -0.075907 1.292758 -1.448665 1.197020 1.130258 0.598884 -0.227737 -35.435237 -60.034441 51.145255 -51.698113 59.821252 0.861766 1.954689 1.715051 1.617338 1.847953 1.043581 2.213315 1.436155 0.951256 0.757292 1.058966 2.049031 1.055230 2.256763 0.414147
+1 0.033597 1 1 0.966821 1.046521 2.238994 2.340650 0.288219 -0.235336 -1.592219 1.225728 -1.752367 0.393782 2.095889 0.504463 29.520210 -53.837229 -42.314829 -35.327261 -45.279025 0.556351 1.095652 2.115907 2.291983 0.607632 1.217444 1.585786 0.297868 1.514082 1.169273 1.977307 1.597887 1.192313 2.202301 0.822255
+1 -0.014757 1 1 -0.237229 -0.423346 0.523351 -2.072615 -0.469353 0.124730 -0.674905 -0.412120 0.713518 -0.933269 2.092262 0.798042 39.459303 42.511864 46.900451 5.883601 35.678031 0.485110 0.749888 0.372560 1.360385 0.983877 2.275128 0.832103 0.647149 1.631673 2.019097 1.962741 2.042618 1.278888 1.524462 2.381500
+1 -0.001831 1 1 0.520852 -1.667497 -1.038198 0.990670 1.326176 -0.560392 1.560387 0.976623 0.857473 1.059385 1.680441 1.829375 -64.543508 17.265153 -74.574354 28.827044 -3.874672 1.050755 1.284016 2.204721 0.991199 1.573990 2.304751 1.445325 2.072768 1.764854 1.643192 2.135045 2.208090 1.365692 2.441145 1.070916
+1 0.007542 1 1 -1.057900 -0.285157 -0.141582 0.191364 -2.300252 0.099831 0.241696 0.110903 -2.166359 -2.074986 2.094810 1.222449 -10.244173 26.184151 -22.980859 10.708825 -16.775807 2.110097 1.396183 1.900988 1.403307 2.387728 1.051129 0.824650 1.391732 1.342342 1.489790 2.391426 2.451096 1.823883 1.493506 1.852321
+1 -0.035727 1 1 1.373704 1.848760 -1.385142 -0.879312 -0.539617 2.010832 -1.198028 0.783480 1.536165 -0.859731 -1.320858 0.407660 -8.431168 47.363182 -17.008265 42.098178 -5.930169 0.349847 2.130981 1.397428 0.318460 1.114491 1.498615 2.224857 1.924752 0.302618 0.349980 2.117929 0.291110 0.442861 1.662497 0.345947
+1 -0.025952 1 1 1.637556 2.054748 1.758075 1.282072 -1.964909 0.199158 1.447970 1.248792 -0.533927 -1.324364 -1.976578 1.996514 -47.807093 56.183669 28.921901 -59.602166 -33.598204 2.349902 2.051511 2.240531 2.110852 0.584358 1.548312 0.485394 1.015466 2.191751 1.263938 2.261657 1.671963 1.927127 1.975542 1.183015
+1 0.005426 1 1 0.455634 0.202708 -0.136736 1.526126 0.062441 -1.411953 0.897101 -2.069847 -1.060173 -0.790634 0.749543 1.356201 -4.790550 35.228186 30.120744 -10.650117 -46.520558 0.309705 2.468193 1.169932 1.794912 0.590225 1.169458 0.575810 1.881671 0.745199 0.312105 2.301767 0.790710 2.469702 1.789624 1.716672
+1 0.004865 1 1 -1.632897 0.859297 -1.271752 1.054606 1.461032 -0.694534 -0.439787 2.230418 -0.412801 -1.314034 2.002315 1.734786 31.962709 47.244948 -54.156682 -11.346972 -58.558107 0.833471 1.143385 1.127649 2.148513 1.312672 2.331841 2.243994 1.814374 1.436803 0.605270 2.031014 1.995864 0.738157 1.197466 1.063002
+1 -0.002594 1 1 -0.381798 1.401080 0.148420 1.643938 0.926160 0.946591 0.325984 -1.691791 0.623423 2.222752 -2.021267 0.173080 44.861987 -54.590982 39.358824 3.755906 -24.488168 1.785289 0.851603 2.148248 1.355592 1.436298 1.102130 0.742832 1.025742 1.638713 1.095541 0.264215 0.661691 0.783019 1.451507 2.472099
+1 0.000417 1 1 1.112350 1.225704 -2.160528 1.672246 0.757096 1.065190 0.291155 1.978120 0.354058 -1.090148 -0.354294 1.837251 -51.246966 -7.754679 17.109384 7.410038 40.509029 1.153696 1.174842 1.073471 0.582008 0.305461 0.884009 2.286696 1.742161 0.505709 0.454369 1.575639 0.769707 0.460871 0.607773 1.339562
+1 -0.017957 1 1 -0.131244 -0.418839 0.881955 -2.160275 1.220929 -2.306471 -0.741987 -1.586064 1.014633 -1.207855 0.544009 1.125057 -63.086778 50.516847 36.649051 60.603870 69.244304 0.460200 0.576496 2.168301 0.882758 1.521702 1.004369 2.424705 1.520672 1.679376 0.517880 0.253792 0.985828 1.317013 1.036013 1.015536
+1 0.082244 1 1 -2.281509 -0.616371 -1.513651 2.248943 -0.094045 -1.959112 -1.336767 1.623831 2.279215 -0.248178 -0.667255 0.926120 8.769628 -58.862558 -53.017780 -69.825915 35.854612 2.251869 1.404007 0.647556 1.731984 0.453530 0.972784 0.331989 1.233054 0.684826 0.375448 0.399977 0.909364 0.930688 1.572674 0.437695
+1 0.039823 1 1 1.299715 -2.321017 -0.179192 -0.469334 0.437185 1.154167 1.888891 -0.775985 1.913181 2.197002 -1.266038 -1.861661 42.384401 4.632613 10.323675 -39.996345 -68.564136 0.513459 2.458247 0.505470 0.933437 0.517954 1.501237 1.293880 1.499318 0.530540 1.535507 1.273080 0.662155 1.840820 0.416247 2.120667
+1 0.024324 1 1 2.261206 -1.334734 -1.898013 -1.738060 0.519191 -1.295405 -0.631140 0.017531 -2.242548 -0.812336 -1.137063 -1.871531 12.062197 -70.654077 66.926502 -16.277919 17.013291 2.010624 1.313391 0.907422 2.034028 0.901076 1.142765 1.955919 2.127911 1.542544 0.289794 0.817230 0.430074 0.502571 1.718156 2.049314
+1 -0.002596 1 1 -0.759638 -1.381425 0.329416 -0.567884 -1.830392 -0.916674 -1.733361 -0.613711 0.775748 -1.183965 1.513263 0.651531 -41.676179 48.454436 23.704994 9.836958 29.753370 0.848427 0.509768 1.174043 1.147431 1.617786 0.381401 1.451158 1.117314 1.690265 1.292890 0.598674 1.412808 2.306708 0.594838 2.184341
+1 0.022756 1 1 0.032435 -1.509280 0.327016 1.518857 0.414004 -2.028660 -1.563443 -0.503004 0.034824 0.944209 -2.004064 1.850265 10.947122 -61.717820 -41.403843 -24.393289 -28.006274 1.353323 1.549294 1.238700 1.085684 1.083656 0.759460 1.496652 0.724249 1.456685 1.756992 2.258250 0.663603 1.432973 1.478727 0.958552
+1 0.079333 1 1 -1.652623 -0.812927 -1.646928 0.647100 -0.380904 2.282146 1.897527 -1.712953 -1.611130 -0.872489 1.038995 -1.733618 -6.782158 12.271053 -10.419460 -69.869811 48.080000 1.833292 2.133133 1.563964 0.301240 1.941756 0.335698 0.581637 0.817162 1.540187 1.168342 2.069794 1.283550 1.128676 1.411874 2.359416
+1 0.052378 1 1 1.493507 -1.527842 -0.629485 -0.434630 -0.616389 -1.814415 -1.005727 0.087842 1.378080 -0.002318 -1.260927 -0.778396 -29.164668 29.432165 -33.605649 -60.146661 -34.939690 1.654339 0.472598 1.958643 0.665446 0.901746 1.145462 2.284062 2.482024 1.877010 1.161183 0.997878 1.338194 1.520716 2.415569 0.968575
+1 -0.002655 1 1 -0.339490 0.897306 1.384307 0.987945 -2.074002 -0.214585 -1.560040 0.134666 1.378258 -1.726654 -0.977912 1.048121 27.091078 69.753349 -55.458082 16.017501 -43.865297 1.464224 2.461005 1.856980 2.004305 0.859844 1.140564 0.952534 1.986943 1.543894 0.484717 0.891247 2.443487 2.187086 1.601930 1.640487
+1 0.042240 1 1 2.164304 0.530974 -1.179049 -0.676984 2.350198 0.540494 -1.399071 0.643111 -1.454604 0.340813 -2.214576 -1.924438 57.724239 -28.719533 10.802154 51.798816 -17.302767 2.010938 2.082155 2.034280 0.637265 2.015776 2.393170 0.258129 1.881097 2.352277 1.465454 0.633954 0.367279 0.360308 2.448175 2.227483
+1 -0.005335 1 1 0.052200 0.823997 -0.790152 -0.572170 1.525353 1.214840 -0.958079 -0.199006 1.097365 -0.869686 1.011345 0.093746 52.549931 6.685633 15.435300 71.081531 67.295421 1.887012 0.519698 1.572164 0.863554 0.496437 2.112319 0.498039 2.044857 0.667829 0.454592 0.821549 1.023748 1.880516 1.579802 0.990911
+1 0.061427 1 1 -0.268199 2.130056 -0.175421 1.659276 -0.460462 -1.235895 0.528404 -1.971305 1.082893 0.942928 0.019585 -0.704437 -61.913969 -38.084235 -31.740807 -67.740118 -8.159893 0.725140 0.685693 1.435670 1.807381 0.895506 2.023357 1.554568 2.116955 1.919944 0.506659 0.660853 2.449252 2.334454 1.165663 2.045465
+1 -0.048488 1 1 1.723335 1.745294 -1.472097 -1.497940 -2.302957 1.759533 2.232314 -1.532918 -1.116090 1.899560 -0.533582 -0.237195 4.392065 17.429106 -19.022829 -66.688786 -38.426707 2.310092 1.221110 2.437909 0.684815 2.432203 1.534681 0.880551 0.420956 0.250432 0.756946 1.993291 2.495768 1.124275 1.691520 2.122808
+1 -0.038669 1 1 1.203158 0.621017 -0.512912 -1.554488 -0.800721 0.856685 1.955093 -0.236042 0.671807 0.173864 0.450275 -0.333200 -56.626957 20.741620 4.412135 54.758143 70.106602 1.849995 1.616491 1.115493 0.340091 2.411362 2.267023 1.861690 2.424536 0.927698 0.821490 2.289862 0.956133 1.723427 0.633564 0.558666
+1 0.010149 1 1 1.044134 -0.167214 -1.777435 -1.522770 -0.214871 -1.646151 -0.423940 -0.022548 -1.968702 -2.296086 -0.562644 1.412212 -39.833996 -39.973670 12.521740 2.889995 -27.852293 1.922688 1.613627 2.484878 0.336146 1.356421 1.862408 0.989094 2.196757 2.138097 1.737113 1.154127 1.666310 1.417902 2.429350 0.834438
+1 -0.001118 1 1 -1.808957 1.193584 -0.073239 -0.993109 0.101761 -0.303078 0.259343 -0.181402 0.095989 1.649417 -1.239205 1.437076 61.945765 -27.521880 39.760568 5.865981 39.547785 1.819227 2.004210 1.507060 2.405201 2.210687 2.265138 1.676235 1.730811 0.994920 1.121242 2.458070 2.023365 1.695407 2.205222 0.415520
+1 -0.014535 1 1 -0.734836 0.787730 2.284422 -2.271914 0.423127 0.499178 1.636116 1.405823 -0.258556 -0.722641 -1.607958 0.607068 21.127886 46.379566 -48.630442 18.163391 22.109238 1.974361 1.578089 1.448088 1.263768 1.654561 1.954139 1.459305 0.793719 1.292133 1.386163 2.248731 0.419872 2.294514 0.403994 0.924753
+1 -0.033304 1 1 1.943771 -2.041187 -0.034966 1.375311 0.575115 0.840937 1.167776 -0.281228 -0.070415 -0.655600 -1.107349 -1.981432 16.913152 9.343205 -18.757659 40.029754 30.070521 2.053576 0.949702 1.646141 2.194464 1.862367 0.306169 1.525132 2.395484 0.905926 1.651374 2.397190 0.328213 0.783588 2.019713 1.060372
+1 0.012381 1 1 0.389448 -0.061181 -0.967191 2.163052 -1.671602 0.654065 -1.131180 -1.968252 0.550597 -1.252914 1.936380 0.974658 26.058244 -39.097667 35.514201 37.173399 23.319099 0.986460 0.690053 0.471602 0.965762 1.559111 1.986422 1.796090 2.377971 1.315345 2.252944 1.482169 0.310540 0.738143 0.977860 2.395551
+1 -0.002961 1 1 1.404862 -2.260026 2.304418 -0.767874 1.578159 -1.927519 1.869735 -2.279491 0.317447 0.903637 -0.605855 0.863203 -50.840542 73.003364 -32.467834 13.115868 -61.609821 0.981190 2.115841 1.188653 1.436411 0.751543 1.174788 2.403806 1.273830 2.007458 2.094982 1.607778 0.926615 0.613425 1.829787 1.723934
+1 0.013190 1 1 -1.697773 -0.962583 -0.508301 0.553672 -1.408657 -0.255612 1.620709 1.639363 -0.568671 -0.926939 0.102357 0.299912 -51.978109 3.928333 23.495842 -55.379925 -20.406248 0.357836 1.406566 0.907185 0.305587 0.744927 2.494491 2.165157 2.045979 1.517685 0.973677 1.834786 0.253724 2.085235 2.039089 0.469570
+1 0.033128 1 1 0.187636 1.007129 -0.079759 -2.191742 0.131131 -1.474331 -1.342548 -1.291074 1.471863 2.269569 -2.146485 2.084448 45.156303 -58.018425 34.323490 -25.107937 -39.094871 0.362667 1.600215 2.057479 1.303106 1.299387 1.806091 1.724284 1.539335 0.350706 0.807672 1.789975 0.855497 2.333271 1.539095 0.827220
+1 0.015518 1 1 -0.851641 -1.996954 -1.179073 -1.078174 -1.740435 -1.696452 -2.323335 -1.439805 -0.691333 1.512619 -0.755573 0.967543 -30.674068 10.940626 -20.892149 15.643564 -28.615515 0.760689 1.905073 0.317530 1.220309 2.476016 2.145986 1.580162 0.275576 0.354455 0.817027 1.526226 0.521983 1.723624 1.704613 1.685225
+1 0.003401 1 1 0.809439 -0.425261 1.337319 -1.776604 -1.685028 1.192640 -1.793714 -1.800012 0.738975 -1.898566 -1.608190 1.409565 44.067055 -65.014511 51.106698 50.277339 61.232330 1.101488 1.208878 1.607459 2.315260 0.328764 1.037785 1.548849 0.506337 2.008134 2.204497 1.729423 2.409968 1.334216 2.174815 2.369037
+1 0.002082 1 1 -1.410709 -1.754482 -2.165303 1.529402 -1.425409 0.940845 -1.990196 -0.687452 0.769898 -0.546533 -1.129980 -0.646835 4.051063 -13.777667 38.754654 49.477329 -34.526016 2.443611 2.017241 2.267565 1.967862 0.363716 1.232402 0.986912 1.523388 2.333926 1.286985 0.363826 0.819619 2.338065 1.105957 2.076444
+1 -0.004092 1 1 0.364473 -0.403841 -1.510292 2.166587 1.191720 1.577630 -1.378091 -0.190421 -0.701693 1.751911 1.361134 -2.063070 -8.500513 -68.127989 72.888137 -19.075124 -45.601011 0.382179 1.027143 0.442232 2.338376 1.837302 2.038253 2.162957 1.069695 2.359192 0.697356 1.720454 2.417493 1.799570 2.377348 2.092143
+1 -0.010934 1 1 -2.066807 -1.797970 2.062587 1.569033 0.214766 -0.115465 0.883630 -2.278110 -0.027236 -0.659030 -2.196625 -1.817918 43.853814 -48.950047 46.552068 0.600309 39.400519 0.692859 0.378439 1.176377 2.121951 0.380336 1.553897 2.101650 1.184424 2.372371 1.691024 0.539844 0.410556 0.968666 0.876262 0.333796
+1 0.010896 1 1 -1.837616 0.178224 -1.670919 -2.012700 -1.929619 -0.448665 -0.887484 -1.233867 1.627522 -1.663440 1.164169 0.344574 -8.442947 -0.607959 -17.974461 3.231125 5.522775 0.944189 1.227953 0.461653 0.250074 1.499928 1.788415 1.648093 1.251282 1.040377 2.369511 0.866283 1.367053 0.560911 1.232005 1.062165
+1 0.072840 1 1 2.168319 2.040865 -0.663589 1.286955 -0.006049 2.007915 1.600895 -1.500352 -0.418841 0.853188 -0.272844 -0.532793 -35.482679 42.615059 -18.710771 -71.923343 34.380891 1.969553 1.776143 2.382552 1.807020 1.580553 2.360004 0.838495 2.336360 1.709327 2.157984 0.738291 1.213576 1.816483 0.888595 0.616663
+1 0.010258 1 1 -1.036017 -0.066865 -2.257898 0.378596 1.330504 1.498797 -2.157665 -2.033356 -0.375477 -0.755563 1.147226 -1.660599 57.310087 60.624260 -38.059335 -63.242146 -10.748517 0.620100 1.514730 0.823834 1.175789 1.238256 0.372286 1.255051 1.400898 2.390547 1.165774 1.659501 1.725988 0.929221 1.666477 1.974160
+1 -0.036924 1 1 -0.260581 -1.779420 -1.890466 -2.137132 -0.951061 -0.063957 -0.492398 -0.775760 0.983259 -0.705763 -0.671151 1.431733 53.649664 39.911206 -12.357174 62.978250 -74.551207 0.893067 1.534769 2.358802 0.877033 2.050392 1.437851 2.468669 2.421101 1.696669 0.918390 1.887415 0.536278 1.216686 2.341156 1.302709
+1 -0.007293 1 1 1.170594 -0.049272 1.259748 -0.177716 0.782520 -0.468994 1.442663 1.590169 2.014862 0.552215 -2.321280 0.106641 51.068678 11.278159 -47.979306 11.804875 -45.463467 1.307540 1.569188 0.337347 1.283861 1.853611 1.644234 1.633948 2.016106 1.188436 2.299274 1.642565 0.596812 1.615973 1.404738 1.683234
+1 0.004929 1 1 0.328832 -0.949109 -0.236308 0.921718 1.692422 0.557860 -1.699851 1.814561 -1.255337 -1.074490 -1.079574 -1.695704 26.216813 -74.031101 9.283864 33.908541 50.842200 0.697749 1.559531 2.284979 2.148465 0.498628 0.691882 1.967617 0.738202 1.968139 0.503423 0.279347 0.740068 1.831096 1.235281 2.111416
+1 0.052846 1 1 1.491097 0.377334 -1.026529 -0.816202 -0.138278 -0.823009 -1.445408 -0.614460 2.332804 0.366065 -1.931522 0.563649 42.706541 18.842081 28.859688 -55.231317 -72.745721 1.565056 0.639967 2.425204 0.898751 0.309472 0.792756 0.853453 1.733683 2.007482 0.253641 0.702039 1.675217 0.374051 1.670664 0.342068
+1 0.013711 1 1 1.317384 -2.251004 -1.558434 -1.143074 0.773630 0.922721 -0.296184 -1.679494 -0.041261 -0.745389 -2.215583 0.000364 44.885399 38.904777 22.578644 -20.733708 -21.425295 2.201030 1.958034 1.677592 2.045707 1.444576 0.747540 1.405119 1.329313 0.766686 1.447854 1.835901 0.995599 1.277457 2.215696 0.953676
+1 0.005027 1 1 -2.004198 -0.399986 2.009245 0.402530 -1.673722 -1.992612 1.119178 -1.837115 -0.821703 1.642346 -2.266367 -0.590190 8.385207 -69.834045 49.203856 19.215584 6.326686 1.114080 1.345053 2.057314 0.776097 2.107750 2.447531 0.409261 1.705594 2.414759 0.845873 0.339366 1.479879 2.323410 2.301570 1.994314
+1 0.008590 1 1 -0.203921 -1.401320 0.532555 1.823984 1.608334 0.998352 -1.522716 0.703611 2.204229 -2.332721 1.027775 -1.802447 70.849763 71.958826 -38.011554 -10.180353 48.808406 0.968236 0.395342 1.769420 1.886329 0.282885 1.705511 1.020733 0.716587 0.924982 2.427031 2.355849 0.760261 1.454319 2.482673 1.531853
+1 -0.010976 1 1 -0.791997 1.405317 0.662778 -0.770346 -2.272932 2.173150 -1.589212 -0.073507 -0.782918 -1.519064 0.808567 -0.947992 -9.935176 -30.501349 63.830597 0.837825 -18.673359 0.727884 1.788805 1.444450 0.869752 1.167621 1.199045 0.606057 1.754758 0.721338 2.025849 0.691707 1.264832 1.523612 1.591845 0.885762
+1 -0.011486 1 1 1.435189 -1.495162 1.987489 2.312228 -1.447837 0.984457 0.570144 2.121111 0.286896 1.087871 -0.215245 1.498954 15.358178 -25.108441 -47.562611 -34.798725 -12.164039 1.509826 1.640418 0.506013 1.057254 0.259078 2.068140 0.486024 0.356581 0.551818 1.411153 1.503846 2.396855 1.440357 1.834642 2.319480
+1 -0.013392 1 1 -1.935386 1.587365 2.011051 -2.225794 -1.976744 -0.794964 -1.330594 1.712134 1.993235 -0.079075 -0.121778 -1.539382 -43.632543 17.852887 53.466650 -36.020962 -4.313662 0.629210 1.626400 1.161938 2.438588 0.853761 2.418926 1.145950 1.475782 0.967193 0.866856 1.998565 1.125467 1.477258 1.023704 1.145150
+1 -0.054270 1 1 -0.857331 1.329870 0.263557 -0.040610 0.762401 0.682544 1.555702 2.352387 -0.382721 0.014930 1.179582 0.218284 -71.788485 50.936560 40.772064 56.077148 38.625846 1.143881 0.457902 2.451186 1.083425 1.370545 0.751261 0.945256 1.164783 0.749489 0.407523 1.740851 0.984026 0.273963 2.493252 1.586841
+1 0.037923 1 1 2.247658 1.873767 -0.499854 1.150439 0.498783 -0.289872 0.726405 -1.106637 0.547368 1.036173 -2.025947 1.626514 8.172659 -42.115726 10.992660 -46.356430 -12.526184 2.461274 1.882260 1.653019 0.785387 0.754018 2.280494 1.018590 0.687914 0.513225 0.776418 0.755503 2.481560 0.832715 1.947780 0.335195
+1 -0.003088 1 1 0.760528 2.189946 -2.043110 0.624324 -1.483545 -0.681659 -0.817992 -1.957538 1.559680 -1.482804 2.344001 0.050078 -58.906386 -39.636046 -13.022839 -24.850651 -64.891241 1.718653 1.404079 1.857529 2.237106 0.797552 0.450480 1.462427 1.511178 1.876582 0.718405 2.232912 2.300462 1.368872 1.882629 1.092135
+1 -0.002142 1 1 -2.003639 -0.424820 -0.673624 2.265261 0.847754 -2.067534 0.104586 0.059473 0.530669 -1.595797 -2.348989 0.941318 39.734918 24.764909 -26.167174 8.311890 47.933073 0.792258 1.479635 0.475912 1.409704 1.888978 2.045946 0.958025 2.022216 0.375999 0.662115 1.166471 2.127154 2.332587 1.289921 2.446630
+1 -0.000850 1 1 -1.702064 2.321686 1.999105 -0.382182 -0.352858 -2.303884 0.319095 0.324717 0.570846 -0.211883 1.453442 -1.029724 64.927104 -20.155731 -57.377641 3.984785 72.288935 0.777070 0.467276 0.254158 0.386891 1.474879 1.549643 0.344208 1.850519 1.417899 2.374550 2.306845 0.646659 2.394750 2.054548 1.535456
+1 0.006820 1 1 1.380839 -0.751579 2.129241 0.266874 -0.848930 1.153651 -2.072517 1.188296 0.583839 1.383520 1.891435 -0.435114 21.231433 -13.303181 63.437133 -12.102187 -1.452992 1.818350 0.761837 0.939175 2.460790 0.494848 2.408561 2.440872 0.989902 2.274766 1.487319 1.377517 0.925914 2.343524 0.609798 1.631005
+1 -0.004470 1 1 0.411247 -1.240380 0.545653 0.480084 1.154284 -0.850555 2.117312 -2.296345 -0.211937 0.540529 -0.817053 -0.309571 -15.163057 4.508209 19.473909 -2.018838 -30.612489 1.313425 1.484338 0.776312 1.219599 1.807915 0.876441 1.094851 2.162906 2.462966 1.062138 1.349552 1.166463 1.986315 2.244321 0.544345
+1 -0.031237 1 1 0.096529 1.299810 -0.725955 -0.755049 0.353353 1.189073 -0.493987 0.785483 2.205104 -1.761824 1.679846 1.245932 -47.056097 -71.814264 67.670715 41.704905 -15.658239 0.354776 1.727811 2.320672 1.278299 0.618280 2.432500 2.025570 0.508241 0.257229 2.492197 1.856586 2.149591 1.429856 0.842235 2.198291
+1 0.026899 1 1 -2.302012 -1.208592 2.294063 -0.448071 -0.324842 2.046450 -1.046943 0.094399 -1.505750 -1.608353 -1.320064 -0.381683 -44.180456 -40.927890 24.961036 -29.862447 1.845577 0.904172 1.414884 1.211378 0.878306 0.937593 0.632657 1.066487 2.452435 1.820401 1.485941 0.704113 0.526143 1.887528 2.432168 0.956637
+1 0.013886 1 1 -0.905578 0.958665 0.617961 -0.037633 -1.042951 1.213426 -1.166904 0.802299 2.100615 -0.173329 -0.883011 -1.444593 -33.309993 -41.049422 -67.643859 -40.343711 -56.754637 0.997236 1.796350 2.262343 1.941952 1.382464 0.829323 1.180774 1.769120 1.357087 1.804265 0.275356 1.163997 1.041100 1.009190 2.450801
+1 0.000321 1 1 1.024146 -1.536455 0.698974 -0.333299 1.277338 -1.427965 0.394105 -1.893530 -1.790162 1.351349 -1.588417 -0.837476 14.029382 -8.175141 0.400395 -20.557242 -55.571401 2.296870 1.748944 2.002354 1.809348 2.462202 1.729391 1.870436 0.915062 2.194015 1.060905 0.881487 0.406583 1.693432 0.517304 1.820685
+1 0.010295 1 1 -0.731759 0.668684 -0.472590 2.272674 -1.786780 1.646064 -1.045580 -0.557870 1.525441 -2.013424 0.041573 1.279602 -34.075964 -14.722872 52.684676 21.344191 -68.189345 0.500286 1.554387 1.332199 2.011445 1.609122 1.006373 2.358890 2.360884 2.121757 1.623420 0.563744 1.591437 0.787300 1.401207 0.841991
+1 0.028497 1 1 -1.087986 -1.710049 0.069544 0.155403 1.199552 1.267583 -0.444908 0.994283 0.778783 -2.018022 -1.823837 0.858925 60.464164 -28.803827 -55.917818 -60.765514 63.999875 1.313429 1.542220 1.596908 0.487661 0.869628 1.339737 0.462253 1.343126 1.176695 0.718531 2.104537 2.451952 0.459949 0.856279 1.981032
+1 0.042226 1 1 -1.732182 0.364272 0.918456 -1.291100 1.029882 0.625637 1.745095 -0.098241 -1.797923 -1.855166 2.102397 1.497818 7.685998 28.561414 31.679814 -57.371815 -48.099117 0.596999 0.266564 1.888271 1.417343 2.026813 1.138065 1.705882 0.513681 1.693855 0.872897 2.287576 0.791747 1.897710 0.312586 1.388605
+1 0.004445 1 1 -1.612031 -1.884556 -1.757316 2.046896 1.733907 0.370395 0.170596 2.076280 0.803782 -1.259493 -0.243544 1.824318 -69.845046 14.303535 -50.490634 -46.091769 -64.356388 1.557843 0.910343 1.628525 0.868818 1.226879 0.408144 0.931124 2.150533 1.512001 2.192124 0.772383 0.433746 1.468416 0.914934 2.290570
+1 -0.040877 1 1 -0.228406 1.770210 -2.103093 0.941393 -2.214629 1.895729 1.049249 0.964070 1.922762 -1.694962 -0.829321 0.844854 32.859116 -36.845526 -62.763112 -59.620411 -40.252960 0.902410 1.051977 1.578558 0.324530 1.880680 2.089607 1.279606 2.341502 0.380922 2.399802 1.479490 0.292972 2.480961 2.018296 2.002010
+1 0.022050 1 1 0.507272 1.014234 1.518135 -2.297909 1.777788 -1.979157 1.060976 0.143429 -2.124114 1.067402 -0.238726 -2.024721 -42.039383 -55.902274 50.473604 59.868531 10.406642 1.441436 1.958200 2.217404 0.400282 1.534542 0.799516 1.962868 1.927749 1.181716 1.851423 0.870615 2.179365 2.328505 2.433933 1.353847
+1 -0.012689 1 1 2.052118 -0.021778 1.539212 -1.484009 0.935360 0.064047 2.010674 0.851745 -0.963002 1.883770 -2.020271 -1.936791 49.207691 -66.341309 -48.371965 12.388829 19.054810 1.437958 2.003639 0.908865 1.547009 1.077291 1.777211 2.331602 0.491112 0.365713 1.033108 1.700147 0.867000 2.161466 0.751703 1.620512
+1 -0.041089 1 1 1.652138 2.089203 1.220692 -1.568330 2.177280 1.835534 -2.187747 1.314515 1.378293 -1.140653 -0.959459 0.166736 -49.117002 -59.451364 -49.081347 -60.196444 28.357651 2.230557 0.965708 0.652125 2.019461 1.328708 1.852158 1.969352 0.651279 1.302163 1.196799 1.096616 0.320189 0.915044 1.898090 2.202713
+1 -0.005612 1 1 0.378700 -1.619089 2.024981 0.988256 -1.560442 -1.903957 2.035250 -0.777685 1.623334 -1.355391 -0.374592 -0.023237 18.408214 -63.151297 16.148342 55.180893 -24.723283 1.011788 1.126221 0.637469 0.936512 0.449420 1.660045 1.878121 1.824062 2.263436 2.312481 0.869715 0.544602 1.633420 2.144384 1.661006
+1 -0.009503 1 1 1.108736 1.741343 -1.900013 2.341275 1.356573 1.377507 -0.213191 -1.678828 1.724363 0.176724 1.398162 -1.776073 -69.838261 -21.647873 64.196414 -0.874880 -4.106453 1.117624 2.408826 2.387721 0.932671 1.151573 1.488477 0.578608 1.658076 0.279922 1.395546 2.447244 2.332931 0.324322 0.624891 1.046444
+1 -0.025602 1 1 -1.844034 0.700637 -0.647783 -1.664867 0.749253 1.189617 -0.781929 0.974434 1.766452 0.712334 -1.983427 -0.027065 70.870358 -31.900428 -50.486452 24.207028 47.518051 1.913126 0.656542 2.005874 2.475309 1.509723 2.156339 2.342716 0.530521 1.222660 1.497306 0.472808 0.989772 2.345083 2.055633 1.767259
+1 -0.007445 1 1 -2.318130 1.214253 -1.403182 2.227054 -0.402584 0.755830 -1.364830 1.212235 -2.330914 -1.586350 0.920113 -1.722238 -68.974697 -57.727476 -25.685081 10.840458 -54.415788 1.132648 0.666875 2.410308 0.291260 0.700694 1.559219 1.542858 1.059122 2.414808 1.686895 0.890080 0.827802 0.366586 2.218903 0.848477
+1 -0.016936 1 1 -1.202155 2.111950 1.823559 -0.812596 -0.798453 1.288732 1.574150 1.378505 -2.290421 0.394217 -0.008031 1.687021 -22.011433 -46.159209 2.179119 24.445658 8.168761 2.010523 1.852908 1.080556 0.407342 0.944807 0.365152 0.604650 0.600620 0.362930 1.512937 2.179724 1.612906 1.606645 2.125643 1.684913
+1 -0.014887 1 1 0.309441 -1.695444 0.491101 -2.169745 2.276745 0.658668 0.837681 -1.719597 -0.190845 1.609829 -2.134570 -0.307509 37.891297 -60.977552 -49.711932 -8.437948 -66.596190 1.642532 2.286729 2.311471 1.893263 2.074518 1.932861 1.590474 0.349482 0.500768 0.656229 1.237409 1.879771 0.308388 0.585007 1.220658
+1 -0.016817 1 1 0.131087 -2.218108 -0.035207 2.042787 -1.342425 0.776322 -0.967966 -1.444072 -1.713910 1.143197 1.306231 -1.195924 -49.591195 70.790900 -17.348642 21.379523 -74.362794 1.142723 1.245118 0.951569 1.522676 1.611500 0.480769 2.033073 0.601721 0.875989 0.250616 1.601328 0.522429 2.472452 0.754785 1.669081
+1 -0.037502 1 1 0.430882 -1.102475 -0.186876 2.336111 -0.598335 0.024621 -0.880065 0.939584 0.374011 -0.320775 -0.296023 1.022106 59.595194 66.432760 -64.604637 39.862833 74.632935 2.211082 2.159720 0.659715 1.332651 0.612935 0.356229 1.393043 0.867248 1.830880 2.094305 1.483154 1.121270 0.683997 2.184915 1.121754
+1 -0.031951 1 1 -1.942573 -1.399021 1.482705 0.702478 2.014464 -1.412276 0.178040 -0.043802 -1.040380 2.013575 -2.224227 0.793681 -43.885036 -25.799794 32.867611 -44.067898 50.836652 1.549198 1.868519 2.441818 1.131178 0.708412 0.787423 1.224072 0.480176 1.068481 2.203324 2.262731 1.712775 1.608901 1.794203 2.164253
+1 0.009746 1 1 0.863198 -1.684832 -0.221932 2.192685 1.577358 -1.252026 -1.988879 -2.114663 -0.308135 0.089692 -0.506172 -1.366213 48.592087 -62.794034 20.663668 44.272052 -69.630364 1.712007 2.208921 1.839718 2.135332 0.279525 1.470078 1.849883 1.984687 1.893561 0.324001 1.989042 0.831391 2.189093 1.578835 0.479715
+1 0.038121 1 1 0.936220 0.385519 -0.117854 -1.560565 0.748155 1.585410 2.143461 -1.073659 -1.243159 0.958892 -0.274858 -1.399377 6.580815 53.761450 -31.302329 -48.242208 -56.783594 0.447147 1.701002 1.742236 1.758824 1.561548 2.444000 1.806255 2.220706 1.898412 0.864765 0.603316 0.686160 0.294204 0.682949 0.316674
+1 0.002199 1 1 1.799803 0.461873 1.392349 -0.510227 1.158636 1.598649 -1.543674 1.886110 -0.383916 -1.210634 0.974803 -1.458352 -44.152330 -18.208925 -37.404886 -13.917610 -63.266141 1.914474 0.815208 2.448204 0.458165 2.382838 2.112694 2.300718 1.168525 0.645563 1.982944 1.837003 1.507707 2.033294 2.081254 0.387209
+1 0.004578 1 1 0.568186 2.205354 -2.275987 -2.045298 1.552407 -1.187005 2.268579 0.062374 2.171401 1.998347 1.013336 0.558586 34.317500 24.223041 16.643802 -17.627173 -9.902596 2.381158 0.879777 0.917046 1.789889 1.667149 2.022606 2.442871 0.824012 1.924165 1.693347 1.338482 1.874393 2.172757 1.532339 2.022781
+1 -0.002665 1 1 0.561595 -0.186193 -0.313394 1.240679 -0.230991 0.736716 -2.174791 2.293638 1.833062 -1.323276 2.174238 -2.165206 -49.502759 57.131122 52.763895 2.780999 -59.748632 2.196215 2.032558 0.952493 1.303454 0.401549 0.338522 0.787251 0.581493 0.652905 1.625029 0.616466 1.188387 1.461263 2.201016 1.718036
+1 0.016998 1 1 -1.227415 1.669312 -1.437402 1.995464 -0.309299 -0.616109 -1.832272 0.471678 1.246415 1.927744 1.924497 -0.809157 14.545872 -27.522850 23.462545 -15.000937 29.244580 0.829719 1.087207 1.933696 2.134285 0.683242 0.753133 0.907918 1.372292 0.865560 0.464466 0.287696 1.555637 2.082893 0.929699 0.699202
+1 -0.046620 1 1 0.357121 -1.458325 -0.933046 1.132467 0.036548 1.644577 2.241615 -0.724251 -0.388896 -0.091850 1.934766 2.130801 -56.708993 -8.041983 -11.608618 43.958794 65.457944 2.149933 0.427859 1.521128 0.348926 2.400477 1.573245 1.030396 1.114097 1.632384 0.487015 1.253192 1.644705 0.564310 2.112609 0.866350
+1 0.031712 1 1 0.012968 1.184162 1.794658 -1.182645 0.143254 -0.355300 -0.937649 -0.839934 1.542656 -0.149770 -0.764445 -2.052072 25.421420 57.800786 57.813481 -28.816605 29.324653 0.766651 0.850863 0.949191 2.049424 0.924719 2.497210 0.606422 1.141733 0.361186 1.449899 2.450141 1.515951 1.094198 2.442487 1.123996
+1 -0.014433 1 1 0.850310 -1.510689 0.202796 1.331161 -1.605229 -0.656534 2.046473 -0.663566 1.674500 0.932083 1.540095 -0.776099 -0.038071 -39.862624 -71.118113 67.881837 -9.964452 0.286899 1.653844 1.155623 2.059828 0.279123 1.462990 1.977814 1.117440 1.565236 1.426784 0.961026 0.709389 1.453599 1.634094 2.218029
+1 0.016683 1 1 2.132998 2.149378 -0.576303 -1.963603 -1.417658 -0.741098 -0.786726 0.465326 -1.838129 0.981687 1.133451 -2.275282 11.555030 -44.609151 -46.002782 -68.754832 37.543641 0.564735 0.252242 1.923966 0.594616 0.712767 1.980343 0.871610 0.902330 1.954053 2.272613 1.303297 2.256434 1.637459 0.267384 2.167819
+1 0.051842 1 1 1.411174 0.148528 -1.255128 -2.285665 0.225013 -2.260946 0.979011 -1.420274 -2.288675 1.473131 0.014677 1.624335 42.405609 61.073644 14.731752 -53.444423 -40.415867 0.332766 0.802224 2.473215 2.330224 2.074787 1.941871 2.272126 2.121561 0.580598 1.361103 1.802908 2.218033 1.977150 1.212950 0.306143
+1 0.075303 1 1 -2.105343 0.834783 1.415237 -2.257085 -0.094126 1.394511 -1.879591 1.570674 -0.492426 -1.240422 -0.169357 -0.100006 48.684799 -4.590133 -46.368618 -67.356747 -14.842347 1.294985 2.066191 1.472050 1.249308 1.610911 1.835487 0.783327 2.129196 0.643717 2.444843 2.475655 0.591352 2.099383 1.325121 2.304058
+1 0.010009 1 1 1.861651 -1.496292 1.836966 -1.686087 2.245468 -1.951661 1.377062 1.744792 -0.481759 -1.040469 0.507728 -0.753443 -29.532136 3.381999 -8.745325 17.330944 -18.819904 2.033173 2.286635 0.718901 1.564714 1.647617 2.249478 1.734060 1.587315 1.247665 1.002439 1.490202 0.325435 1.333520 1.716142 1.952050
+1 0.029661 1 1 2.169196 -2.074515 0.595221 -0.525174 -0.297019 -1.570123 0.317487 1.579147 0.553994 -0.705640 1.399011 -1.642694 36.000684 -36.505545 -48.686697 -27.308583 24.651704 1.692768 0.604520 0.664421 1.676035 0.611248 1.248497 1.494725 2.094934 0.800161 1.562065 2.127918 1.670036 1.040363 2.127928 1.840723
+1 0.021703 1 1 -1.074732 -0.430353 0.575103 0.642923 0.100964 0.449311 2.320848 2.043196 0.815912 -0.014219 1.357590 -0.377533 -73.681405 36.631647 68.095276 -22.703100 28.997605 1.566224 2.283704 0.960020 1.810155 0.268217 0.424545 2.070983 1.015316 1.912100 1.422748 0.626009 1.838347 1.601500 1.158898 0.851595
+1 0.011012 1 1 0.652208 0.638261 1.859588 1.535994 0.988229 -2.006000 2.299407 -0.169664 -0.552639 -0.077816 2.198080 -2.005119 -55.436340 -68.573623 -66.882676 2.858619 44.802251 1.246371 1.764037 1.418691 2.194388 0.586166 0.445398 1.559972 0.705710 0.365933 2.485875 1.352131 1.762306 1.574643 2.023656 2.081732
+1 -0.057165 1 1 0.229059 -0.221372 2.181129 0.560806 0.695132 1.070033 1.562444 -2.145948 1.684979 -2.022239 -2.028064 -0.962002 -4.932439 50.497471 10.999696 71.892574 48.491760 2.140174 0.648897 1.755445 1.014800 2.245897 2.294750 2.118999 0.263405 0.544184 1.345464 2.209943 1.007759 0.900470 2.198371 2.279217
+1 -0.003812 1 1 0.132030 -0.502428 0.300870 0.327887 2.022484 1.419855 -0.036364 1.434203 0.788528 1.556890 -1.239881 -0.491487 12.501803 -32.197961 48.863910 5.741408 45.847655 1.547953 1.201609 0.951355 2.423874 1.057494 2.046563 2.328248 0.359750 2.068600 1.462981 1.818854 2.486309 1.904438 0.898617 0.308858
+1 0.034274 1 1 1.016579 -1.486165 -2.321032 -0.431568 -1.002231 2.288118 -1.403966 -1.533273 2.344974 2.260442 -0.023747 1.442148 -74.781539 -3.323038 -50.302496 -34.055842 23.460804 0.711109 1.102007 0.938968 1.228421 1.578516 1.864733 1.824060 2.226121 0.673192 0.582440 0.815436 1.782424 2.201723 2.364037 1.128150
+1 -0.036024 1 1 -0.507954 1.670382 -2.301694 -0.574247 -0.402552 1.297279 -0.864055 1.408908 -0.245273 1.032855 -1.248460 1.397413 -7.038445 54.852637 8.275715 39.940403 28.347961 2.037702 1.911472 2.118402 1.480471 1.024936 1.597630 1.374487 1.758622 0.415888 0.584823 0.363791 2.488705 1.662856 1.862016 1.155740
+1 0.024725 1 1 0.075109 -0.570869 -0.173744 1.566668 -1.841294 -0.370520 -2.261300 -0.257931 0.353088 1.454216 -2.155790 1.199364 -59.935549 63.235991 57.292524 65.459005 69.491076 1.922733 2.371691 1.517921 0.456555 2.322861 2.080215 0.930621 0.450044 0.894289 1.806806 2.491701 0.273411 2.217555 0.690516 1.497707
+1 -0.017895 1 1 -0.739082 0.107814 -2.243261 1.340494 -0.240030 -0.375966 0.452373 1.948467 1.486556 -0.543925 0.284014 -0.220011 48.024120 -8.608011 -74.842985 13.956624 -31.022250 1.510593 1.028282 1.590002 1.409136 1.344932 2.264825 0.918952 2.319888 1.614690 2.346286 2.027202 0.934281 1.206672 0.540029 1.267687
+1 0.028555 1 1 -2.066399 0.342480 2.234188 1.686452 -0.817187 2.148289 -0.028634 -0.580995 -0.719763 -0.351930 -0.844194 0.637323 7.267906 51.694123 23.130634 -43.438547 -21.660940 1.293734 1.278394 2.216027 2.023296 0.535392 2.088686 1.539171 2.095867 0.729703 0.872391 0.531635 1.945922 0.609783 1.381058 1.939201
+1 -0.066942 1 1 -1.160229 -0.094941 1.827991 -1.737226 0.406022 0.473999 -2.142073 0.824829 -0.947615 1.306168 -2.256914 -1.930653 32.704564 65.602082 74.196642 72.956363 -72.413023 2.189725 0.953812 0.970907 0.289028 1.447838 1.558150 1.568151 0.911276 1.566502 2.443996 1.734232 2.244210 0.940435 1.136926 0.562814
+1 -0.065395 1 1 1.344997 0.037362 1.203573 -1.829510 -0.235760 0.696326 2.296482 -2.205760 0.164635 0.852592 -0.856472 1.629693 58.733913 -9.127471 44.591663 52.073701 -47.301120 1.526120 1.000009 1.154357 1.036911 0.364868 0.341889 1.135032 2.477292 1.099204 1.079095 0.593188 1.464313 1.715599 1.819252 2.421780
+1 -0.006651 1 1 0.599235 0.973947 -1.709087 2.105572 -1.689283 0.369774 -0.857225 -1.609876 1.358006 1.911290 -1.311330 0.326753 57.669289 -52.256150 -19.119662 -44.157229 49.449844 0.677891 0.812314 1.055438 1.252902 1.271217 0.852096 1.422873 0.470551 1.303321 0.420359 1.473767 0.849467 2.235321 2.289068 1.121696
+1 0.019323 1 1 1.858683 0.453706 0.793400 -1.394726 -1.737650 -2.017047 0.424588 1.493530 -1.140113 -1.304455 -1.948474 -1.611471 -60.459590 -44.324400 -60.196372 29.580912 66.393397 1.732386 0.457360 2.342249 1.678521 1.898261 0.567681 0.261703 1.189657 0.317419 1.618300 2.268443 0.969357 1.238894 2.084816 1.759479
+1 -0.016908 1 1 1.331465 -1.209983 -2.219728 1.014793 1.488913 1.366824 -0.680899 -2.187878 -0.895609 -1.135730 1.665396 -1.278986 63.886991 48.653014 61.197945 3.865196 12.341131 0.885780 0.553191 1.988305 1.936130 0.290796 1.909340 2.271140 1.298874 2.177889 2.278017 2.123966 0.501479 1.351677 0.882870 1.138978
+1 -0.016733 1 1 0.184261 0.837847 1.073946 1.363126 -1.570422 0.005997 1.833790 1.489949 -0.056840 1.303288 1.178131 -0.615304 72.564393 -60.252695 -17.047407 -15.772335 -35.633464 2.250435 2.063192 0.572490 2.342317 0.578111 2.306463 0.977741 0.388968 0.387667 1.020682 2.099081 0.750393 2.110697 2.490626 2.458597
+1 -0.028559 1 1 0.992089 1.613041 0.012051 -0.098537 -2.058591 -0.379675 -0.617830 2.240308 0.867928 -2.286612 -1.564024 -0.847127 -49.098030 -40.583950 -44.440366 -59.235849 -26.912432 0.366412 1.542320 1.022401 1.741960 1.623820 0.535930 2.120740 0.282613 1.629268 2.113713 1.416988 0.561194 1.485204 1.821460 1.285223
+1 0.049839 1 1 1.709748 -0.420865 -0.187326 -0.516878 -2.231092 -1.482127 -0.416184 -1.621177 -0.087292 -1.556006 1.968887 0.684089 -23.466457 -50.740564 -46.664982 51.645628 -41.921940 0.894390 1.258237 0.945115 1.042542 0.494947 1.822819 1.622676 1.572653 2.328694 1.108437 1.001092 1.345941 1.228404 1.292258 1.238594
+1 -0.013998 1 1 -2.265686 1.433822 -0.917391 0.340175 1.196373 -0.327300 -1.571332 -1.149499 1.155896 -2.029490 -1.363124 1.609627 -26.490576 -27.102735 34.336975 51.545282 71.557313 0.831445 0.843473 0.493713 1.330524 0.871805 1.925693 0.370869 2.187410 0.303673 2.337947 1.379222 0.334026 1.727919 1.892181 1.883111
+1 0.008125 1 1 1.514148 1.385848 -1.392644 0.269069 -1.645902 -0.948503 0.523353 -2.042521 1.108520 -1.883017 0.543283 -1.646456 -26.683611 28.554152 59.640107 71.282553 -4.130234 1.872492 1.726966 1.615630 2.384565 1.890672 1.279443 1.852829 1.994255 0.685012 1.247476 2.336352 1.561849 0.742789 0.300501 0.775152
+1 -0.075562 1 1 1.430982 -1.524020 2.344547 -0.197921 0.484491 -0.173233 0.736577 0.206762 2.026574 -0.526702 2.306736 0.493624 -69.163171 74.592220 -28.555082 74.731025 54.331414 0.596231 0.856794 1.630013 1.126164 1.929239 1.475882 0.406192 1.872493 1.738641 2.087125 2.308805 2.082007 1.784970 2.235195 2.423061
+1 0.022594 1 1 1.242584 -1.194143 0.109173 1.757443 0.095774 -1.965391 1.525887 0.756398 -1.236571 -1.407683 1.971385 0.259829 -45.576378 47.821368 33.725854 -19.564161 -14.851268 1.296133 1.103533 1.821955 0.594450 2.424612 2.196010 0.842170 1.104857 1.576574 0.734045 1.838203 1.432753 2.273935 1.021165 1.227460
+1 -0.018117 1 1 -2.168305 -1.795238 0.859950 0.274946 -1.832355 -0.925002 -0.337122 -1.717531 1.545169 -0.315679 0.530550 1.116357 -67.561625 -8.234292 56.249188 -69.903248 -63.887749 0.453967 1.581177 1.600974 1.323910 2.196774 2.429091 0.976498 2.004513 2.101527 1.369748 0.855597 1.762074 2.183879 1.702463 1.540981
+1 0.035974 1 1 -1.399857 1.565484 1.821121 0.609440 -1.878910 -1.117852 0.559714 1.187996 0.260658 -1.648629 0.344493 -1.634004 35.102337 14.977145 20.879214 66.950463 -63.563089 1.302560 1.122619 0.863177 0.920672 1.985061 1.423506 2.113278 0.872217 2.095772 1.398914 0.541098 1.229645 1.895651 1.701253 1.457205
+1 -0.031789 1 1 -1.785662 1.591234 1.056450 -0.530432 0.861602 -0.219000 -0.358472 2.310157 1.440725 2.007668 2.163740 0.480644 36.766265 -69.388636 35.202752 52.644847 -48.061608 1.053421 1.100608 2.170157 0.572793 0.676131 0.486844 0.633628 1.637185 2.417210 1.551126 0.527259 0.397541 0.463215 1.748578 0.352612
+1 0.004739 1 1 -1.031073 -1.797429 1.735662 1.590968 1.308463 -1.379125 1.296715 -0.911508 0.255587 -2.044064 -1.273069 -2.228101 52.775717 51.474123 -74.421479 48.205680 42.858927 1.824817 1.441256 1.185312 1.535960 2.128216 2.172988 0.900669 1.040904 2.227004 2.008014 2.440447 0.597715 1.052947 2.121292 0.554789
+1 0.020403 1 1 -1.947351 -1.589847 -1.315532 0.377742 1.128821 0.021102 1.225805 -0.466441 1.939724 0.638672 -0.654079 0.905100 13.655226 3.380204 -38.914804 -41.111679 -63.996167 2.371257 0.969858 0.646609 1.565632 1.322810 1.713228 2.470411 2.442563 2.414637 1.050972 0.435698 0.526677 1.861666 2.013094 2.321753
+1 -0.038808 1 1 -2.199607 -0.095770 2.028457 -1.857555 -0.355370 -2.101094 1.558367 0.008802 1.843280 0.765803 1.310256 0.471300 -12.152963 45.150703 -2.130907 35.844179 33.112402 1.677044 1.822644 0.922761 1.099546 2.320652 0.950712 0.623966 1.249430 1.421661 0.353176 1.837306 2.107457 2.035849 2.259756 1.222984
+1 0.003414 1 1 0.981926 0.443662 1.619756 -0.237856 -1.543333 -1.810032 1.979615 1.915970 1.953526 1.696370 0.933737 1.059131 67.406372 -51.098741 -66.545037 -22.431212 -51.383392 0.615086 0.495929 0.332747 0.473862 0.706660 0.592227 1.064514 0.792850 2.425244 1.579405 1.052253 1.720924 1.311439 1.850745 0.723698
+1 0.013672 1 1 1.578658 1.745812 -2.175834 -1.106467 -1.301514 0.362052 1.312431 -0.665861 0.793244 0.699193 -1.360106 0.496234 -22.794889 -13.707737 14.062440 -52.571405 -67.597086 1.311581 1.984098 0.979014 1.543990 2.094016 1.131819 2.476765 1.235125 1.748315 0.427915 2.473423 1.321027 1.005970 2.339335 2.199118
+1 -0.021730 1 1 2.215631 0.817027 -0.128353 1.043279 -0.413043 -0.666768 -0.304977 1.332215 1.977289 0.526643 1.416359 -2.235461 15.588787 -49.263027 36.298631 21.086866 -43.049215 2.452647 0.887929 0.664946 1.489452 1.215041 1.691618 1.528649 0.753986 1.735891 0.862948 1.574865 1.249808 1.018627 1.316302 0.346657
+1 -0.030892 1 1 -0.378688 1.836096 -2.174150 -1.074418 0.134361 0.972906 -0.358336 -0.115210 0.450089 1.261388 -0.883617 -2.209380 18.481773 -26.834224 47.196410 30.058197 -11.886080 1.834907 2.290067 2.152332 2.487871 1.147395 1.023894 2.083654 2.474692 2.390028 1.447605 2.153474 1.438539 0.532065 2.417896 1.826468
+1 0.013917 1 1 -0.008076 0.925614 1.204585 1.038588 0.860265 0.864039 -1.686768 0.218432 0.237146 -0.966805 -0.777106 1.924602 30.026579 56.707752 -12.808639 -24.789664 60.122080 2.451896 1.772533 2.470397 2.220158 1.689542 0.386728 0.995574 0.863708 0.838988 1.622713 2.183661 0.299583 1.093743 1.546216 1.250549
+1 -0.006971 1 1 -0.443205 1.334029 -0.519628 -1.335525 -1.053348 0.830243 0.503124 1.981602 2.340462 1.840948 -0.731955 2.087388 -32.099185 59.005880 61.822798 5.760180 61.354035 0.284021 0.545434 2.112817 2.106378 1.903767 0.867182 0.723957 1.047239 0.694409 1.689861 1.249774 0.442397 0.616459 1.082502 1.603643
+1 -0.029749 1 1 1.401275 -1.288908 0.169549 -1.391317 -0.983769 1.567460 2.053169 -1.219289 1.589985 -1.078155 -1.410978 -1.568928 49.397419 -27.586157 9.453948 42.509870 13.382851 0.258628 1.263174 0.665298 0.665749 1.489170 0.976000 0.384182 0.943841 2.144140 2.069567 1.953785 2.263004 1.809004 1.180548 2.470893
+1 -0.004564 1 1 0.802999 -0.275049 0.101534 0.602686 -2.291310 -0.406301 -0.444599 1.472032 0.393837 -1.687322 0.330267 -0.389767 -19.123678 38.352076 33.333791 -8.969889 -6.925065 1.531361 1.334752 2.182499 1.003807 1.984537 1.607729 2.350843 2.114091 1.028834 1.860540 1.089174 1.244810 0.270992 2.063614 0.919033
+1 -0.032294 1 1 -2.083935 -2.223676 0.638806 1.582748 -0.193589 -2.102546 0.721164 0.346441 -1.882256 -0.804253 -1.942168 0.692489 -29.938546 72.858747 -63.034463 29.784780 42.802903 1.200936 0.877270 1.523797 2.449434 0.884918 1.820503 0.942883 1.793014 2.430322 1.419276 0.765799 2.283614 1.698189 1.708312 0.854721
+1 0.010393 1 1 -0.622263 -1.588278 1.490298 1.095940 -1.267563 0.774697 -0.000432 2.156051 -1.518722 1.845688 -1.174447 1.271703 -59.951438 -53.813033 64.346840 -22.663338 -52.715376 2.315061 1.476670 2.383705 0.933412 2.350296 1.921404 0.288059 0.905702 2.390532 0.919049 1.713614 2.207107 0.598475 0.312509 2.340551
+1 -0.006386 1 1 0.087231 0.543588 -1.232917 -1.257585 -1.170220 1.625002 -1.590544 1.102398 -1.111479 -0.716434 -0.955635 -1.529024 -52.660545 -65.787214 -35.705528 47.186697 16.822048 1.047386 0.915016 1.427094 1.659969 0.604755 2.362856 1.516304 0.268717 2.074653 1.947069 1.880273 1.997220 1.027184 1.131848 0.724809
+1 -0.026538 1 1 0.122584 0.951924 0.426034 2.242660 -2.006662 0.604410 -1.587217 0.471512 -1.529352 2.264449 1.343157 2.089533 65.457470 43.691058 65.620023 -74.278786 46.435707 1.299008 2.174276 2.306272 2.258385 0.681544 1.466297 1.300203 2.011081 2.241235 0.437190 0.856221 1.000121 0.789929 0.594288 1.954921
+1 0.011623 1 1 -2.355515 -0.366409 0.859326 -0.772791 -0.949405 -0.497418 -0.328688 -1.344778 -1.073759 1.786060 0.385982 -1.762533 -25.751657 -58.096337 74.859604 -34.631548 -52.434473 1.132165 1.539781 1.098424 1.462362 0.416776 2.007093 0.459275 0.777052 2.410627 1.156312 2.386959 1.624736 2.430130 0.444849 1.321889
+1 0.022478 1 1 -0.459799 0.478649 0.603057 -0.776765 -1.779433 -2.108100 1.611631 -0.135848 2.318493 0.169844 -1.144073 -1.892619 -19.569261 49.422988 -47.843352 46.785774 28.509470 2.255001 2.297119 1.433238 1.431175 0.516609 1.398059 1.921584 1.069294 2.372197 1.015674 1.180970 0.558720 0.399043 0.972303 1.245432
+1 -0.007949 1 1 -1.683966 0.200630 -2.079615 -0.296853 1.213167 -0.802847 -1.875740 0.316046 0.920633 2.308100 -0.153335 0.582416 32.773346 21.629998 -64.616294 -6.045668 -59.549196 0.724816 1.990148 1.416138 2.030027 1.156290 2.009785 0.706996 1.731739 0.833703 0.553608 2.234668 0.312996 1.529559 0.298147 1.711106
+1 -0.067825 1 1 -1.767037 -1.109824 -1.173352 0.819555 -0.048083 -2.304674 1.179213 -1.280587 -1.336633 -0.825399 0.794019 -0.413153 69.764907 -11.207206 40.496104 68.011850 -74.844894 1.103069 0.776269 0.500205 2.453082 1.451929 0.568712 1.848019 2.148778 1.256299 2.113926 0.500310 1.966340 1.770984 1.180987 0.846791
+1 -0.006770 1 1 -0.291037 0.008470 0.979351 -0.414612 1.246614 0.553076 -1.987601 0.518128 -0.311434 1.185167 -0.175397 2.062901 67.776067 12.357165 -63.123821 27.948347 -72.130157 1.501844 2.499139 1.533354 1.074160 0.908893 2.007634 0.549581 2.056251 0.914442 0.773253 1.568104 2.367518 1.122490 0.946613 1.479203
+1 -0.023345 1 1 -1.085718 -1.289251 -0.872294 -0.395974 -1.236257 -0.840019 0.121487 1.371727 1.613024 -0.281079 -2.277263 0.056797 -64.772700 65.233425 28.169277 41.035563 -15.300587 0.520608 1.107468 0.470878 2.293259 1.805110 0.983410 1.166894 2.487855 0.877885 0.605737 0.869878 1.034086 2.384248 1.064325 2.113309
+1 -0.030291 1 1 2.014339 1.192517 0.845120 0.796219 -1.136696 -0.420606 -0.535599 -1.146118 1.434088 -1.151739 1.219971 0.454716 -34.363077 -40.237150 -65.772992 53.331746 -53.342051 1.827332 0.966188 1.964821 1.005539 1.848114 1.498128 0.779457 2.333938 1.489370 2.082374 1.206547 0.686489 1.317141 0.946783 2.086158
+1 0.007917 1 1 2.077928 0.216453 -0.038569 2.083652 2.178392 1.688133 -0.838984 -1.341087 -0.283777 -0.504373 0.584085 0.810938 38.252757 14.080754 -44.767345 -4.773425 23.049177 0.437649 1.818368 1.060015 1.680250 1.706862 1.220887 0.940731 1.621652 2.354496 0.511330 0.420909 1.725833 0.567440 0.717738 2.266261
+1 0.023525 1 1 -2.248163 -0.938123 0.624914 -0.991381 0.861138 1.400084 2.248849 -1.667199 -0.754405 1.749762 -1.775579 1.400298 36.486318 25.544910 33.304608 -49.459016 42.315988 2.197224 0.990573 2.302433 0.736776 0.490411 2.083626 2.008784 1.879731 1.884972 2.231796 1.538513 2.282223 0.828370 0.920441 0.349756
+1 -0.003283 1 1 1.189944 0.015209 1.141994 -0.060698 -2.269394 0.369446 -1.648277 1.538838 1.653056 -1.340192 0.608021 -2.159985 43.911176 15.126771 -14.360425 -5.654941 57.398765 2.140677 2.362839 1.236615 2.035667 1.446155 0.281966 2.010701 0.357518 0.555496 2.463178 2.378978 2.486116 0.897434 0.678664 0.298086
+1 0.054904 1 1 -0.171298 0.266081 -0.035429 -1.694612 0.331241 1.829374 -2.044364 -1.602114 -0.144991 -0.554551 0.769899 -0.535616 -45.690588 -71.713089 -31.883079 -58.912326 10.542527 1.948874 0.731011 0.355017 1.272710 1.179949 1.399166 0.286637 1.757428 0.592361 1.053717 1.569415 1.913977 1.468649 0.336549 1.383724
+1 -0.017471 1 1 2.296349 0.262980 -0.312926 -0.324448 -0.765879 2.125022 0.044575 -0.094612 -2.062956 1.650792 -1.685458 -1.327572 20.751399 18.765890 -51.690851 31.872698 34.436728 0.296276 1.759186 0.894199 0.297176 1.134862 1.873911 0.828945 1.584899 1.155516 0.254678 2.371172 1.784327 0.439548 2.237323 2.183650
+1 0.007287 1 1 -1.815106 1.523362 0.742255 1.391584 0.771587 -0.432202 -2.235000 -1.188283 -0.372732 -1.749676 -1.491521 1.911765 62.718609 61.660562 -20.929651 -14.651910 45.347044 1.341457 2.361419 2.124281 1.291903 2.009364 0.373836 0.317918 0.993016 0.620174 0.522847 0.483660 1.125951 0.602238 0.570385 0.710611
+1 -0.053580 1 1 0.201879 0.058161 2.055135 -1.153242 -0.481830 -2.225305 1.530402 1.241873 0.984799 1.612945 -1.607500 -1.130035 -50.004020 32.428106 69.179395 48.098833 47.092239 0.314021 0.756327 0.589963 1.253390 0.471161 0.300596 2.365011 1.734559 0.986085 1.130788 0.908886 1.896149 1.076673 0.397338 1.557975
+1 0.039212 1 1 -0.808497 2.118997 -2.249950 2.016560 0.823732 -0.532643 1.402474 0.005734 2.119218 1.457613 -1.608368 -1.570964 10.114736 48.368510 -70.455011 -37.366381 33.235864 1.302504 2.441667 0.844624 1.850893 0.957881 1.861040 0.503845 0.629835 0.878553 0.581967 1.870106 2.119901 1.928631 0.250109 2.078729
+1 -0.012024 1 1 0.299799 1.170825 -0.875964 -0.821793 0.131114 -1.759347 0.900423 1.923106 -0.640322 1.208288 2.016478 -0.558232 5.176509 1.587929 -11.681485 19.283837 -46.553372 1.037229 1.210357 1.716569 2.376144 2.103897 0.700029 1.642949 0.286509 1.854582 2.203749 0.414109 2.175726 1.933379 1.301511 1.491699
+1 0.022974 1 1 -0.264507 -1.789807 -2.107206 -2.210509 0.448871 -0.351683 -1.406671 0.142510 1.274780 -2.003841 0.892019 2.054478 61.484913 26.932950 -37.913776 -16.825945 -43.665771 2.265682 1.824705 1.815968 1.218588 0.561301 1.032130 1.016080 1.261594 1.109846 2.183898 2.027267 2.023612 1.339675 1.666911 0.268262
+1 -0.010657 1 1 1.059948 1.718342 -2.051489 1.176433 -0.876273 -1.300575 2.009613 1.882738 -0.510084 -1.151737 1.243354 2.315910 -26.296936 -72.609604 50.391286 26.350366 70.600951 0.477850 2.482511 1.054238 1.321253 0.295569 1.120194 0.596573 2.096960 1.106695 0.976970 0.938010 0.878915 2.167593 2.490526 0.767432
+1 0.001966 1 1 -1.638149 2.121405 0.527206 1.455588 2.061368 -0.067605 -0.556379 -1.683345 1.212888 -0.791813 -0.217006 0.161284 34.267141 -72.154184 54.621511 23.727770 -57.364365 0.281865 0.310767 2.310707 0.295883 1.902623 1.888409 1.487090 2.024525 0.938971 1.292960 1.772001 0.275122 1.717710 1.307953 1.765382
+1 -0.021605 1 1 -1.311054 0.244798 0.401972 -1.623736 -0.682124 0.777746 -0.591554 0.889624 -0.499585 0.947293 -2.009775 0.109353 1.879141 -67.283027 24.160736 19.482638 -5.296720 0.295487 2.008165 0.476649 0.286034 0.630249 1.095068 1.306594 1.419071 1.831768 1.277546 1.461732 1.079377 0.844591 1.285686 1.029013
+1 -0.035810 1 1 -1.433337 -0.364122 1.601726 -1.669801 -2.073763 -0.910903 1.005216 0.748924 0.383074 1.208144 -0.399811 0.244156 -30.566830 13.281464 21.569571 -30.223884 -72.814758 2.160451 1.697876 0.952086 1.201399 1.917074 1.767394 1.583564 1.203425 2.219382 2.151893 1.866781 2.491233 1.402304 1.276530 2.389398
+1 0.037732 1 1 1.507821 -1.285852 -0.293523 0.637161 2.210977 -2.001643 0.123851 -1.315250 0.417125 -1.415105 -0.236586 0.950823 24.698032 49.822195 61.639229 70.527937 63.043896 1.056492 0.955826 1.072064 1.672181 1.101965 2.484929 1.200729 1.901646 1.210153 0.548492 1.759857 0.918890 1.279388 0.928832 1.879911
+1 -0.028707 1 1 -1.890457 -1.976774 -1.298351 1.688774 0.500849 1.448244 1.146036 1.886010 -2.067012 -0.543829 1.896152 -1.257701 51.000689 68.576985 -26.620721 35.549540 31.117345 0.463226 1.938389 2.255703 0.605461 0.733957 0.368546 1.405166 2.128618 2.188105 0.730509 0.909212 0.630364 0.774417 0.870589 1.737494
+1 0.005497 1 1 -0.071407 1.528290 -1.261116 0.743352 0.982255 1.265657 0.168465 -0.755022 0.800829 0.943951 -1.627910 -0.147332 -70.075642 38.690565 22.320432 -10.499290 -61.562294 1.712826 2.459150 2.177969 1.370851 1.397465 0.940352 1.988674 1.403122 1.522990 2.392204 2.018523 1.312229 1.637197 0.362815 1.825065
+1 0.003200 1 1 -0.315191 -0.688708 -1.485492 -0.419834 -1.710569 0.750894 0.501714 1.835991 0.777139 -1.361504 0.559701 0.961363 -36.659230 68.316785 -49.793551 -30.213038 -40.527661 1.399032 0.284897 1.757326 1.123901 2.156961 1.542005 2.478561 2.168029 0.811130 1.406208 1.634107 2.435170 1.895131 1.971427 1.775643
+1 -0.039194 1 1 -0.963885 1.171729 0.178110 1.133547 -0.659567 -1.809584 0.076179 -1.428117 -2.160450 -1.728105 -1.802611 -0.540146 -68.965780 -57.863853 -67.771932 57.132776 -69.432146 2.183907 2.180785 1.453095 2.165872 0.568573 1.764007 0.923446 1.364693 1.386983 0.273700 0.331956 0.687358 2.429664 1.605456 2.404866
+1 -0.059369 1 1 -0.577483 1.762689 -1.269675 -1.732755 0.153620 -0.492691 -0.986049 0.953701 2.025632 -2.209079 0.927444 -1.035457 -2.111178 67.430226 49.812894 55.305938 -23.097780 1.309180 2.134764 1.974015 0.268982 2.037914 0.974580 1.261441 0.787704 1.441172 2.021423 0.563767 1.987524 2.316105 1.019860 1.781180
+1 -0.009967 1 1 0.604906 2.026772 -1.897866 0.732406 0.795991 -0.246864 -2.143407 1.965623 -2.331630 0.524178 -2.300743 1.284568 72.607387 62.345022 -67.221052 15.778481 -11.063157 2.297777 1.240154 0.775779 1.275785 1.120150 2.104146 0.376417 0.935720 0.643493 0.939142 1.917841 1.159449 1.106038 1.181958 1.412381
+1 -0.016212 1 1 -0.323498 1.073353 0.819256 -0.361084 0.810157 2.210273 0.288753 -0.694663 2.102271 -0.616896 -0.914177 -2.182590 -49.307340 41.534288 -33.216847 24.445916 12.504178 1.490889 0.616432 0.619165 1.553509 2.331426 2.020629 0.711299 2.044280 2.209875 2.127574 0.390213 1.061708 0.874954 0.851734 2.096245
+1 -0.033534 1 1 -1.172038 -0.647856 1.813524 0.170319 2.139279 -0.663007 1.638897 1.034075 0.402193 2.094854 1.959477 -1.965708 28.697962 -73.345405 -16.220308 -64.718870 69.948015 2.369312 2.034580 1.184681 2.175141 1.088883 0.850473 1.142110 2.191300 0.429283 0.702332 2.092341 2.225203 0.987874 1.941677 1.264699
+1 0.009154 1 1 -1.836225 0.000095 1.594970 -2.125500 1.345700 -2.295262 -0.856087 -1.326766 0.070663 0.108281 0.904849 0.925156 -56.610875 -8.979805 -23.573903 -56.583311 4.289993 0.653675 1.064137 1.194122 1.116116 1.808856 0.941187 0.286236 1.776367 1.649206 1.951968 0.982105 1.734208 1.839407 1.411419 1.462846
+1 0.005533 1 1 -0.536239 2.232781 1.587643 1.961735 -1.699035 1.390338 -1.322375 -1.526490 -1.474937 -2.091956 -0.364919 2.330401 -74.351361 26.667883 7.115704 43.641809 -12.115965 2.379694 1.019910 0.374332 1.899649 1.406331 1.450333 0.746426 0.683935 1.140119 2.471650 0.770035 1.474141 0.389555 1.247572 1.686740
+1 -0.020491 1 1 -1.730311 -1.179385 -1.616592 1.567787 -1.889338 -2.024486 -2.085991 0.923716 2.284981 -2.298739 1.967079 -1.420666 17.274168 -73.050758 -14.094942 -43.693517 43.060269 0.834241 0.587282 1.206432 1.006700 1.104146 0.875562 2.065217 0.843612 0.581616 0.463021 0.738158 1.216414 2.265987 2.449249 2.280235
+1 0.040148 1 1 0.567311 1.638586 0.522506 -2.135257 2.282139 1.774345 1.415073 -0.300031 -0.360915 -1.046582 1.453454 -0.821052 -48.952098 12.081216 -51.010678 63.539177 52.950372 1.178557 0.504554 1.287053 1.494803 1.148077 1.229767 1.698546 0.970772 0.261244 2.472861 0.874079 1.898418 0.967691 2.489653 1.840654
+1 -0.010081 1 1 -1.389259 0.615491 0.857190 1.021257 1.737568 0.628960 1.046939 -0.162334 0.126878 -2.279385 2.104474 -1.301824 -4.242726 -57.499571 54.717693 -9.734485 42.507275 0.921468 1.863962 2.352745 0.337582 0.740660 0.524892 1.104890 2.142432 0.363434 0.986406 2.025266 2.144350 1.098776 0.623779 0.354685
+1 0.031148 1 1 -1.730915 -1.914409 0.722041 0.946991 2.334180 -0.080594 -2.089822 -2.199167 -2.129321 -1.623427 -0.201573 0.378060 55.597400 -74.503606 17.897108 46.700154 -60.508610 1.851853 1.339807 1.634366 2.284199 0.279971 2.226214 2.223464 1.015013 1.323374 2.191168 0.467603 1.261283 0.378625 2.043810 1.062760
+1 -0.044795 1 1 -2.094760 -0.372344 0.067440 -2.223703 0.182589 1.005766 0.570593 0.243603 -0.837349 -2.128199 -1.608478 1.285467 -46.302173 -0.625813 -18.043328 45.780375 -69.234174 0.343505 1.296086 0.320305 0.612037 1.014029 0.533334 1.248342 1.142119 2.341367 0.350601 1.306582 1.229296 0.520597 0.920792 1.748671
+1 0.001002 1 1 2.127375 1.892590 0.138470 -0.659831 -1.525780 1.044459 0.570509 -1.173398 0.042180 2.056006 -0.650537 -0.835243 9.063140 74.194250 32.763652 8.699078 -44.597416 1.393537 2.429116 1.401288 2.198156 0.902699 1.408296 0.729750 1.655091 1.862752 2.272984 0.792177 2.366937 0.359508 2.494523 0.447945
+1 -0.040233 1 1 -0.531815 1.183936 -2.011082 1.718497 0.552302 -0.860059 -2.121536 1.994864 -0.973511 -0.386019 1.138803 -1.863257 -61.485007 -28.514268 10.703681 46.770596 73.406616 1.300013 1.064741 2.353562 0.562171 2.161117 1.647375 0.434998 2.267236 0.941931 1.536678 0.693883 1.837527 1.324329 0.251811 1.444754
+1 -0.014684 1 1 1.112569 0.193733 -0.186252 -1.313936 -1.062051 0.632385 2.058876 0.452914 1.616157 0.544727 -0.950545 -0.804906 38.543245 -53.681792 20.117447 13.932693 16.763024 1.917202 1.663989 0.656367 1.303282 2.016278 1.834661 0.390269 2.009196 2.049969 1.076658 2.386491 0.502150 1.378463 1.084325 0.746274
+1 0.003223 1 1 2.105231 1.998045 0.656814 -2.050204 -0.785551 1.354130 -1.970491 0.621642 0.574582 1.321802 1.328342 -1.862116 -51.170253 -68.449955 61.598296 -17.439269 -1.800593 1.936378 2.207815 1.251378 0.418554 0.379227 0.919598 1.929211 0.991872 1.648991 0.594750 0.709207 0.646478 1.606365 1.928284 1.164852
+1 0.018668 1 1 -1.952204 1.675146 -2.341816 -1.025812 1.804653 1.866597 1.526950 -0.215770 2.093486 -2.186907 1.285250 -0.393814 65.913579 59.514092 53.346114 38.139399 58.877945 1.549321 1.680166 0.303468 1.140868 1.566777 0.314596 1.414552 2.375874 2.068508 2.170263 2.353131 2.326409 0.957734 1.636313 1.261968
+1 -0.005349 1 1 1.896464 -0.735400 0.734966 1.407052 1.550391 -2.097772 0.846159 -0.601445 -0.405342 1.539943 1.386234 0.388586 -12.681503 11.971150 49.117379 65.782506 -43.424935 2.231828 2.074998 1.000294 1.439799 1.449009 0.994730 2.423704 0.445115 1.290732 0.326833 2.339088 0.309833 2.370229 1.694382 0.729370
+1 0.003319 1 1 -0.649028 0.959093 -1.614231 -1.156735 2.072622 0.582098 0.398432 0.135195 0.852508 -2.271223 -2.090989 1.750181 18.013441 51.907593 10.915570 7.977182 -27.506189 1.427221 1.560509 0.722603 0.787795 0.722866 0.716172 0.703571 0.425518 0.425755 2.162736 1.859497 1.562079 2.354797 1.068976 1.533048
+1 -0.015289 1 1 -0.756709 0.735107 -0.934891 -1.615122 -1.999408 -0.002405 1.984009 0.366467 0.119714 -0.159678 -2.354531 2.035551 -13.674874 -33.610333 11.136108 -35.435945 -71.927783 0.771183 0.515110 0.957224 2.065781 1.334777 0.344786 0.315833 1.956206 2.452691 1.629334 0.969807 2.053933 2.444676 1.914361 1.165549
+1 -0.008239 1 1 1.444409 -2.041905 2.030199 -0.862915 1.722665 -0.081663 -1.203586 1.619252 0.721465 0.689390 -1.186253 0.763672 -48.188692 -57.342411 -3.900291 -2.196190 -11.363877 0.734889 0.272466 2.093659 1.869412 1.708122 2.153186 1.094706 1.966530 0.466726 2.256019 1.418003 1.867433 2.200153 0.729378 2.162565
+1 -0.005956 1 1 -2.135929 0.425899 -0.035325 0.052546 1.931746 -1.512047 0.937162 2.084566 -1.306435 -2.229315 0.101834 0.918786 -14.706677 24.874450 14.886017 -10.711119 -21.768670 1.134457 1.827344 1.164504 0.566604 2.416601 0.313132 1.553540 0.595759 1.920990 2.331863 0.363650 2.357184 0.687381 0.568301 1.693171
+1 -0.009667 1 1 -0.022853 2.322034 -1.586100 0.405840 2.117824 1.594620 1.418509 0.898339 -0.106075 -1.513397 1.810238 1.488444 -57.331680 26.447431 51.978666 5.438657 57.505897 2.149147 0.712250 2.279185 1.512966 0.423049 1.682959 2.243622 2.313396 0.501765 1.656295 1.845433 1.440781 2.198582 1.321422 0.891870
+1 -0.023668 1 1 2.203620 1.576967 1.614148 -0.235593 -1.198841 1.245727 -0.208901 -0.270661 -1.546182 2.137620 -0.268934 -0.797869 53.055425 -47.472003 -11.947316 51.460853 2.558694 0.684575 0.645669 1.506415 0.562872 0.434927 1.070489 2.202786 2.226749 2.220248 0.950528 2.032490 2.053696 0.713453 2.246528 1.649582
+1 0.000562 1 1 1.691920 1.541228 -0.585671 0.811011 -2.283321 1.924471 -1.246601 -0.342745 -1.970779 0.505179 -1.188508 0.565745 -35.781005 -21.347234 17.045978 -8.246792 -3.838347 1.208558 0.727985 1.237736 0.621540 0.972982 1.406296 0.862217 0.523567 1.344196 1.146630 1.661211 1.222498 1.032933 1.010973 0.929507
+1 0.006887 1 1 -1.513400 1.770591 -0.411225 1.611955 0.600473 -1.782488 -1.625150 -0.893421 -2.052271 2.176219 -1.851984 -0.958571 30.646598 -22.631454 33.155344 -8.128897 27.628126 0.563722 1.225445 1.054175 0.273920 1.777221 0.260372 1.327268 2.402482 1.519422 0.919384 0.582734 1.254589 0.379566 2.109014 1.199106
+1 0.001061 1 1 1.722195 1.442453 -1.941140 -0.867598 -1.587185 1.017534 0.435495 1.024125 -1.883873 0.293877 0.599118 -1.004602 4.440008 73.214475 65.684368 -42.827560 47.193335 1.050657 1.898602 1.805435 1.941862 2.125123 1.947287 1.045831 1.785675 0.585887 0.257636 0.338124 0.846973 0.831752 1.510490 1.563556
+1 0.007092 1 1 -1.416562 -1.162598 -2.212814 -0.582195 -2.028899 -0.861261 1.241259 0.086172 1.587711 -1.593110 0.398066 -1.302121 -13.136414 16.287321 -8.995373 14.759659 -34.415200 1.130920 0.870002 0.866477 2.386806 1.305922 1.373848 2.260169 1.403013 1.937112 1.034012 1.144464 1.248883 1.229713 0.792723 0.287172
+1 0.039689 1 1 1.734599 -2.142282 2.034086 -1.498054 0.497858 -1.704531 -1.440779 1.789374 -0.450146 -2.217120 -2.274824 -1.354691 62.590427 7.305679 -63.449586 -47.185884 -3.154859 0.269206 1.288596 0.433787 2.161431 2.421651 1.947344 2.005522 1.060986 2.238409 2.448100 0.971885 0.974539 0.571965 0.268951 1.506905
+1 0.009989 1 1 0.222580 -0.738853 -0.751665 0.684026 -1.805476 -1.556521 -1.975703 -2.152464 0.553653 -1.726792 1.417472 2.320455 4.776841 34.370155 9.203441 32.229219 26.489344 1.471036 2.196854 1.527367 1.701644 1.277986 2.115029 1.046422 0.470982 1.802766 2.084680 1.721834 0.857590 1.519444 1.289497 2.070504
+1 -0.006906 1 1 1.332534 -2.078405 1.184775 -2.036880 1.664302 -0.821933 -2.210269 -0.234796 -1.945293 0.021067 0.641132 -1.731979 -29.932573 23.248368 -14.672172 4.813108 43.910099 1.330401 1.047954 1.463746 1.183580 1.678828 0.309186 0.485356 0.379206 0.564189 2.318060 2.381882 1.793863 0.952156 2.389378 1.768128
+1 0.001852 1 1 2.059711 0.348559 0.734990 1.812557 -1.946293 2.051569 0.177944 -1.658078 1.744703 -1.968170 1.940232 -0.252382 -20.422873 -47.227550 46.569012 -14.620418 -25.371647 1.805851 2.195656 1.647119 0.633303 0.672939 0.838133 0.754855 0.593552 0.836655 0.662667 1.450251 1.619130 0.466671 1.332111 0.533459
+1 -0.000272 1 1 1.891945 -1.281801 1.810261 1.873628 1.877643 -1.327474 2.302013 1.212428 0.910031 -1.517215 -1.090695 -0.124772 -0.911472 -19.108811 -11.780912 -1.780614 73.228106 1.296726 2.081138 0.684809 2.340458 0.832959 1.547162 1.394784 0.886491 1.257884 1.762778 0.504125 0.822158 2.254047 2.019705 0.932651
+1 0.012847 1 1 -1.289062 2.308130 0.363477 1.708796 -2.281414 0.982527 1.114586 1.106344 -0.757694 -1.685588 1.196636 -0.613391 45.860217 72.662577 -60.071737 24.314123 47.466367 2.383524 2.390326 1.952705 2.120903 0.765176 0.817807 1.139648 1.307911 1.059794 2.451932 2.366884 1.713105 0.399536 2.497861 0.296272
+1 0.049963 1 1 -0.399392 -2.131502 -0.580828 2.096942 -0.655908 -1.573332 -1.782369 0.380175 -0.402603 0.436737 -1.670867 -1.130989 39.663485 24.184212 -35.943912 -59.323473 0.395752 2.145955 1.073119 1.402664 0.580248 2.230255 0.401599 1.172658 0.367596 1.185634 2.448628 0.840384 0.341284 2.215344 1.782503 1.281774
+1 -0.049470 1 1 -0.045258 -1.953999 -0.223150 0.580535 -2.298822 0.582128 0.902446 -1.771377 1.334742 2.029788 1.665099 -1.566208 4.772219 -43.309299 50.617894 -65.055429 -36.597543 2.201538 1.498454 1.763143 2.152880 0.459261 0.553008 1.161250 2.131655 1.474295 0.730222 0.590243 1.460381 0.881355 0.431609 1.552566
+1 -0.024455 1 1 -2.335124 -1.656920 -2.347780 -2.298515 1.022221 -0.896601 1.042591 2.160967 0.991507 1.250810 0.390154 -2.328158 74.241773 -68.524060 16.130241 50.953876 31.799127 1.343819 1.563311 0.567103 1.799928 1.639315 2.211785 0.470333 2.139277 1.334466 1.874693 0.472479 2.212467 0.683162 1.658379 0.874777
+1 0.053576 1 1 1.595160 1.074029 -1.963647 -2.160882 0.439324 -0.590939 1.796771 1.340998 -1.212038 0.930319 0.166798 -0.490734 -34.295001 53.917382 39.435681 -54.504587 -8.593365 1.694785 0.757800 0.589243 0.411608 0.647906 0.860877 0.503276 2.305729 2.143672 0.951753 2.357285 2.382825 1.895307 0.424230 1.286194
+1 -0.004556 1 1 1.226015 -1.648443 -1.249469 -1.416580 -1.477671 -0.927859 -1.224340 1.514454 1.822401 -1.436928 0.547249 -0.962993 64.910481 0.459321 69.815003 -69.246401 25.744545 0.453604 2.220212 0.344081 1.965246 1.397391 1.946693 2.312027 2.244892 1.150464 0.848384 2.035320 2.378684 2.040782 1.918325 0.282070
+1 -0.066276 1 1 1.553824 -0.944986 -1.635515 -0.729808 0.462440 1.491805 -1.862572 0.146507 -2.237149 0.386950 0.364739 -0.653346 -29.373934 -37.711179 -61.791819 64.897252 -71.883133 0.777648 1.178699 0.635300 0.490286 2.233590 2.454283 1.375935 1.347711 1.731323 0.603224 1.382683 2.246906 1.254631 1.090701 2.158596
+1 -0.007648 1 1 1.056545 1.073038 0.241523 1.913795 -1.622402 -1.831180 -0.026977 -1.014015 2.169844 -0.603975 -0.527103 0.269700 -14.955989 34.697786 -34.314197 31.287440 -51.996949 1.184143 2.134387 2.391189 0.711755 0.718479 1.225919 2.276588 0.622959 2.322531 1.033082 1.267714 0.476707 1.261697 0.591301 1.249151
+1 -0.051337 1 1 -0.685018 -0.729994 2.059462 0.886252 -0.624021 1.865145 0.678352 1.793935 0.808758 2.261273 -0.200388 1.437180 -32.389966 -28.157491 7.054148 59.064274 -6.752845 2.198980 1.256135 1.618244 1.321554 0.856983 0.317777 0.881305 1.849727 1.605104 0.979238 0.802896 0.266555 1.734101 2.287338 1.296472
+1 0.024778 1 1 -0.048620 -1.911696 -0.802235 -1.011781 2.011723 -0.361403 0.162092 0.514672 -1.857997 1.645395 1.847229 1.159972 15.939292 -8.314971 50.276712 50.690210 -49.634762 0.453343 2.331544 1.753228 2.008404 2.251314 1.087245 0.322457 0.788171 0.295021 0.921625 2.255150 0.304723 1.982479 0.776631 2.082803
+1 -0.053104 1 1 -1.107118 1.893865 -1.991544 0.222062 -0.017856 1.494314 -2.092618 -2.065522 0.942329 -0.614275 0.730139 0.381242 -42.048717 -62.784977 22.895159 48.943003 -14.947816 1.705723 2.341096 0.295155 0.928349 0.511939 1.654872 0.424707 0.293579 1.440482 1.674658 2.222728 2.145532 0.710551 0.735604 1.052563
+1 -0.056997 1 1 -2.293208 0.687003 1.110598 0.042934 0.595135 -1.962349 0.812615 1.124443 1.833270 2.174287 -1.338374 -1.811188 44.488865 -25.639966 19.085331 67.151112 8.735292 0.835755 1.281269 1.033531 2.050969 2.128724 1.714464 0.743821 1.904796 2.409457 1.737059 0.256069 1.001080 1.157292 0.858675 1.742671
+1 -0.006934 1 1 -0.980900 -2.047563 1.188295 0.572811 -0.170620 2.240192 -1.077834 -0.734478 2.085305 1.680315 -0.288547 -0.562244 -41.419703 9.054270 -74.879301 3.590216 40.764036 2.442246 1.585067 1.724153 1.595811 2.294440 1.409402 1.312225 1.567182 0.375762 1.179853 2.036997 1.304582 1.355898 2.084385 1.264948
+1 -0.038313 1 1 -1.765519 0.841771 1.061061 1.578244 -0.493110 1.394699 1.291539 1.634941 0.508572 -0.701828 -0.521022 -1.194608 54.270194 -30.847560 -54.939160 37.534005 -65.973026 1.245304 1.826239 0.603054 0.780781 2.087289 0.569842 0.587903 0.391968 1.309961 1.762062 1.976441 0.543388 1.471917 1.252551 2.117496
+1 -0.014008 1 1 1.643650 0.797267 2.349120 1.271130 -2.094782 -0.741854 0.646595 0.557912 -0.833740 1.972034 1.738851 -1.358656 41.506614 -48.346190 -4.418110 -5.179461 -51.196936 0.371557 0.253905 0.639432 2.437454 2.040728 1.007799 1.577144 1.304188 1.482078 1.037773 1.345127 1.044827 0.662696 1.926900 0.415041
+1 0.030025 1 1 1.029173 -1.877236 -1.252283 -1.593251 -1.982485 1.668516 -0.680035 -1.797697 1.946959 -0.283696 0.856347 0.992619 34.567308 22.745354 -68.835598 30.109591 -48.106140 1.076628 1.879659 0.680758 1.755601 1.381107 0.506362 2.431427 1.991537 2.271076 2.481678 0.566635 0.691887 2.050627 0.893752 1.795988
+1 -0.000536 1 1 -2.146056 -0.134909 -0.760054 1.060324 -1.389697 -2.036756 -0.963210 -1.617555 -0.472040 2.083500 -0.381105 -1.096697 -64.768951 -21.763911 63.940719 51.659499 41.193904 0.564101 0.843437 2.143569 1.466970 1.355587 1.351614 2.080377 1.404344 1.816652 1.464012 1.152405 1.979706 1.425738 1.376084 1.590699
+1 0.054463 1 1 0.643107 -1.527591 -1.135497 0.881781 -0.362804 0.181264 2.301091 -0.137984 -0.602947 -2.087301 -2.236509 1.713801 55.201925 28.754685 -20.012626 -52.208363 34.039570 1.420677 1.824178 1.961415 2.252181 2.156606 2.333113 1.132429 1.476381 2.042460 0.874000 0.565586 1.049486 2.464381 2.358525 0.723028
+1 0.009925 1 1 0.394665 -1.916629 1.098313 0.921268 -1.156621 -0.723620 0.797845 -2.077860 0.925011 0.484092 -2.155648 -1.134207 -31.835263 -5.271772 47.318884 -11.519033 49.618800 0.522661 1.863727 0.658819 2.013079 2.061857 0.631212 1.526476 2.477585 1.514074 1.047364 0.546065 1.472685 0.663870 1.420236 1.149750
+1 0.000900 1 1 2.330050 1.191042 -0.387445 0.732886 -0.569499 -0.715555 -0.323404 -2.067578 -0.624549 -2.306484 -0.964194 0.698627 -46.013179 56.496039 28.925534 1.447036 20.341318 1.772935 2.462834 1.103487 1.063627 1.622006 1.552523 1.500128 0.643468 0.523457 1.735531 1.566168 1.342256 2.299293 1.973638 0.691210
+1 -0.086661 1 1 -0.508130 -1.294473 0.889588 -1.101334 0.143589 0.551705 -1.471901 1.801461 0.062969 -1.973956 -1.068940 -2.052100 10.638973 9.226541 -29.519080 72.814218 -61.433371 0.464984 2.232796 0.354032 0.473654 1.705591 2.366350 1.751769 2.231547 1.864150 1.024855 2.484263 1.261602 1.239187 0.260270 1.849723
+1 -0.041277 1 1 -2.005423 -2.139707 -1.816084 -0.773635 -1.001019 -0.904176 0.972169 1.387920 0.439814 -1.791610 0.585290 2.219394 -60.845215 74.468644 -5.502869 63.281610 74.016876 2.149637 2.199542 1.708895 1.642603 1.230149 1.364172 1.632029 1.257185 1.260592 2.269920 1.041875 0.544849 1.277266 1.253032 1.211061
+1 0.005583 1 1 -1.908378 -1.589495 -0.111230 1.380249 -1.250823 -0.616418 -2.310389 -0.629560 -1.704623 1.722206 1.629070 0.797738 26.823046 64.928466 2.722311 3.884659 39.462626 0.600319 2.054896 0.639678 2.066490 1.996996 1.763683 2.213744 1.893302 0.469601 1.086395 1.792452 1.992619 2.440736 0.952943 2.104617
+1 0.008374 1 1 -1.315883 -0.795765 -0.655691 2.072971 1.735431 -2.299339 1.306075 0.900724 2.277525 -0.376671 -1.967960 0.749194 6.437536 45.660806 21.164338 59.028143 -13.997705 0.483476 0.285531 1.164105 0.618895 1.521730 1.473464 0.253767 0.553572 1.636320 1.387364 2.174763 1.484274 1.940696 0.534162 1.654660
+1 -0.007706 1 1 -1.009951 -0.220057 0.722422 -2.087730 -0.020840 -1.544572 0.922136 -0.704922 -0.684778 -1.414694 1.959407 1.574385 19.677875 -23.961099 35.815694 4.369872 -55.556479 1.558928 1.148327 0.924680 1.841262 1.095554 0.470667 0.997004 2.395813 1.933337 0.589055 1.745116 0.662473 0.425655 0.485113 0.794035
+1 0.031646 1 1 -0.495849 -2.234804 2.099317 1.559219 0.201375 1.012688 -0.895357 -1.607148 0.071649 -2.166778 0.297980 -1.122723 -38.432797 -40.015336 62.239742 -36.664138 -14.167668 0.384938 2.404221 1.497054 0.742853 1.386610 0.747471 2.490244 0.527810 0.659432 1.076881 1.643477 2.415045 1.168540 0.910954 0.646455
+1 -0.009404 1 1 1.325670 0.351353 0.571029 -1.843721 1.250009 1.070810 0.482627 1.482837 -1.783928 -2.251467 0.071308 1.532204 -46.487060 41.981188 -22.177484 13.028342 -32.655752 1.446686 2.453628 1.630757 2.388949 1.314731 0.942699 0.934474 2.199325 0.302564 1.687201 1.530121 0.736889 2.401287 1.685557 0.909744
+1 0.025564 1 1 0.943680 -1.478573 -1.944167 0.093992 1.079208 0.259753 1.996335 0.195508 1.375616 1.005287 1.946300 -1.945647 -39.185009 67.551076 -19.058798 -71.225331 65.857967 1.747814 1.005143 1.946788 1.661958 0.284731 1.224171 2.142215 1.209322 2.321966 0.539346 1.044381 2.157546 2.377080 2.090986 1.957712
+1 -0.002429 1 1 -0.322462 -0.363146 -0.849366 -1.474918 -1.785254 -0.985795 0.510756 -1.702014 -1.554465 -0.414542 -2.290344 1.688036 71.316252 -37.754282 -36.219732 -45.040860 48.261455 0.329093 2.067079 0.654252 1.766244 0.262412 1.860276 1.159247 2.219623 1.701793 1.528705 1.693901 1.648095 1.289723 1.371108 1.213952
+1 0.029631 1 1 -0.251962 1.712645 1.159825 -1.981890 2.254209 -1.117239 1.434000 2.085304 1.662281 -1.805835 1.836350 2.092085 -69.422594 64.464382 2.867617 46.037054 44.758391 1.439208 0.525993 1.607948 1.524818 1.621437 0.991061 1.514544 2.193652 1.709923 0.933927 2.011410 1.016955 2.462709 1.243397 1.265952
+1 0.018656 1 1 0.492878 -0.586559 0.019492 -2.271174 -1.270167 -0.582390 -0.602524 0.298703 1.604127 0.984098 -0.746424 -0.771191 -74.511497 35.270672 -5.811499 -23.859059 -49.210402 1.686578 2.320354 0.442636 2.389293 0.353869 2.234206 1.546683 2.346633 1.113392 1.030970 1.768078 1.841930 1.075147 1.749259 0.554206
+1 -0.035654 1 1 0.007722 -2.170117 0.732548 -1.532564 0.113513 -0.703276 -1.286269 2.112895 -1.144160 1.355193 1.755051 2.292751 33.848326 -61.178957 15.272229 30.353541 1.958883 2.469201 2.354596 2.201861 2.425069 0.875651 1.309861 2.338471 1.185824 1.151290 1.227706 0.806502 2.385091 1.727985 0.750988 0.847900
+1 0.062637 1 1 -1.003866 -1.615362 -1.309987 -0.671238 -0.035462 -2.255460 -1.059594 -0.480331 -0.595569 -0.619013 1.210544 2.237640 -49.855781 -26.115721 -26.920874 -59.126947 3.401415 1.638774 2.122447 1.968935 0.391621 2.225479 1.123495 2.075896 0.341878 0.940906 2.313995 1.564793 0.721222 2.334631 1.900656 0.320938
+1 0.003263 1 1 -0.265288 -0.780174 2.197736 1.649864 1.567794 -1.772720 2.322627 -1.030280 2.109905 0.447171 -0.654364 0.812904 40.314010 7.559457 1.789786 -69.059589 15.491755 0.923859 1.547521 0.690085 1.008458 1.398993 1.872891 1.686209 0.614315 1.047577 1.876078 1.237346 0.828599 0.270756 0.350775 1.983464
+1 -0.036338 1 1 -1.683523 -1.783759 0.582498 -2.307606 -0.972135 -0.825265 -1.662698 -0.494863 0.198911 2.007496 -0.721083 1.018853 -30.479050 -11.386493 27.206195 54.511659 -22.543652 1.507576 2.079663 0.643936 1.624665 1.241729 2.490755 2.365036 2.156725 2.081684 0.865275 2.434977 0.910086 1.813623 2.304503 1.789100
+1 0.026926 1 1 0.742836 1.719738 -2.155524 0.952404 -0.936801 -0.720201 1.715183 1.391085 1.812747 1.246117 1.631892 1.104820 60.534619 -44.653809 -46.573508 -60.943568 71.450236 0.836658 0.705000 1.938147 0.438318 1.805234 0.820098 1.383698 1.306773 2.187346 1.471686 1.870274 0.449034 1.911938 0.940114 0.253630
+1 0.017476 1 1 -1.048776 2.266543 -1.159852 1.518887 0.924805 1.733550 -0.933338 0.931104 -0.784010 -1.012702 0.672264 -1.559956 49.230248 12.773497 34.162142 -36.880318 -47.499725 0.956717 0.297496 2.020975 2.028365 2.478384 1.449677 0.967878 1.130928 1.011334 2.491625 1.235517 1.589329 1.351005 0.834635 0.458215
+1 0.011966 1 1 -0.025778 0.283984 -0.734536 1.114378 2.322092 -0.598208 2.155046 0.440969 -1.221345 0.019972 1.090440 0.539946 -37.627021 2.650679 -0.034767 15.665466 39.488763 0.439642 1.565823 2.290140 1.135249 1.628904 0.487321 1.899114 1.404441 1.186411 2.004837 0.802196 2.013647 0.365535 0.302465 2.276799
+1 0.049289 1 1 -1.920877 0.406078 1.418777 0.701942 -2.278097 0.185382 0.827016 -1.891816 -1.261807 -1.435005 -0.125465 -2.249885 -51.135779 60.967466 30.205687 66.984118 52.066227 1.031197 1.073824 2.018131 1.475283 1.580873 0.977469 0.321284 1.317218 2.225502 1.519212 1.889541 0.258179 0.458877 0.841053 0.329172
+1 -0.012945 1 1 2.298659 1.404984 -0.211219 -1.525779 1.055154 1.258322 -0.581789 0.082415 -0.288413 1.697006 2.194535 -0.324265 73.587904 41.904625 41.039449 50.014769 -1.771633 2.487418 0.285005 1.327532 2.327672 1.931362 1.158462 0.269651 2.022350 0.392179 0.349436 1.976750 1.233404 2.065550 1.955036 0.794567
+1 0.058841 1 1 2.017206 2.256727 -1.209497 1.225568 0.276641 -1.615533 0.531224 -1.692916 0.556730 -1.844399 -0.727053 -0.351473 67.536596 37.564988 4.753670 -55.066066 4.634331 1.962992 1.753748 1.750786 1.452373 1.278659 2.168459 1.285393 0.597696 0.722050 0.486494 1.500668 0.720673 2.108399 2.106036 0.652789
+1 -0.019530 1 1 -2.123264 1.219849 -1.602353 0.561912 0.420824 -0.510091 -1.271822 -0.109282 1.133435 2.167028 -0.820847 1.907722 -0.240193 13.073233 -28.174581 19.823657 26.201194 0.826911 1.143443 2.094912 0.436634 0.513344 0.516307 0.830058 2.284952 1.692683 1.415344 2.193635 1.424547 1.605789 1.246744 1.277870
+1 -0.019859 1 1 2.329217 1.331540 0.055622 1.789280 -2.037721 1.667640 -1.269668 -1.607175 -0.382797 -1.264947 2.330056 1.295083 -2.117706 -42.279427 -40.324408 -32.320326 -57.714576 1.991745 1.250874 0.937847 0.394115 1.392131 1.300370 0.317234 0.746712 0.981069 2.319672 2.475863 1.825147 2.488477 2.328019 1.009857
+1 0.014309 1 1 1.759305 -1.597029 0.500276 1.237261 -1.131438 -1.580960 1.966711 1.822653 -1.919631 -2.227249 1.847363 -1.304784 62.052714 -30.042392 -22.474817 -34.247348 -45.180903 0.543446 2.449534 0.315165 1.984008 1.727308 0.619161 1.494905 0.626468 0.547976 2.089111 1.933206 0.643488 0.857488 2.051213 1.740221
+1 -0.027383 1 1 -1.836948 1.993010 0.852801 -2.065692 -1.912400 1.501807 1.322207 -1.290768 1.905834 1.246780 -1.361122 2.270157 -53.797423 26.710608 -24.814525 -57.719166 -36.024304 0.467741 1.329974 0.618736 1.087998 1.732069 1.888338 0.295484 1.955707 0.811739 0.402461 2.163077 0.839467 0.677907 1.090770 1.071287
+1 0.061618 1 1 -1.688246 -1.063812 -0.681017 0.541130 -0.137719 -0.867204 0.313908 -2.016444 1.125276 1.691666 1.985059 -0.831007 25.157445 -28.823159 69.164201 -57.270508 4.564690 2.406225 1.421096 2.110092 1.314493 1.442440 0.833856 0.862314 2.159897 1.383403 0.851789 0.772143 0.913729 2.300652 2.302287 0.535645
+1 -0.001287 1 1 -1.724496 2.299834 2.299505 1.486509 -1.325874 0.924031 -1.841266 0.094548 0.997357 0.604968 -1.634769 -2.339899 -57.319982 73.068524 12.676408 52.387630 -21.094803 2.269579 2.058383 0.737015 2.268897 1.858162 1.625291 0.508761 2.247004 0.641172 2.431428 2.015099 2.265588 2.481501 2.082858 0.337656
+1 -0.001956 1 1 0.334603 1.787366 -1.218811 0.201518 -1.302000 1.624276 0.340042 -1.048125 -0.924411 0.178387 1.066602 0.455944 22.675101 -49.577623 -1.104872 30.409464 41.858090 1.508833 0.704644 0.448034 0.855064 1.815055 1.631389 1.759788 2.005318 2.128927 0.629864 1.374185 1.172783 2.471753 2.494781 0.278625
+1 0.007382 1 1 -0.960566 0.409548 -1.533435 -0.385651 -2.104626 -1.260513 1.455731 -0.245206 2.161337 -2.222786 1.452306 -1.273223 -3.357812 -34.746795 -39.384558 13.738972 60.894017 1.311240 0.760678 1.710314 0.749672 1.231866 0.967483 1.233283 2.280810 1.820301 2.055975 0.775968 2.193510 1.572785 2.297205 0.631975
+1 -0.022738 1 1 1.932677 0.004218 0.213797 -2.259739 -2.282877 -0.042252 1.446616 2.052347 -0.888449 1.404064 -1.534118 2.273001 -32.324238 26.531008 -43.341449 -39.730292 52.975590 0.786212 1.115414 1.264373 0.561007 0.586990 0.792531 1.566232 2.407427 1.375144 1.546890 1.338828 0.925417 0.737280 2.220131 1.244977
+1 0.007161 1 1 1.180924 -0.789223 0.907952 1.240088 -0.741300 0.529449 1.460776 -0.291050 -0.224913 -0.769526 2.080698 -0.346338 -35.056782 0.673038 61.742827 11.697482 -50.423400 1.883802 0.557383 0.441335 0.775760 0.940433 1.107465 0.421695 1.426914 0.892364 0.961318 1.124382 1.243588 2.237755 0.450140 0.251439
+1 -0.012060 1 1 0.677851 -1.910449 1.297333 0.053025 0.554269 -0.801610 0.062953 -2.237471 -0.303160 -1.109750 0.074144 2.071561 50.972972 52.746790 15.306325 3.409298 0.075182 2.328759 2.206203 1.148945 2.326459 1.789159 0.638814 1.048865 1.016889 1.348408 2.189081 1.380290 0.280452 1.313968 1.610656 2.043759
+1 0.016079 1 1 1.306094 1.220924 2.329722 0.402793 -1.965862 -1.676955 0.219468 -1.198062 0.210019 0.211664 -0.422209 0.795470 13.310056 52.110600 -27.147446 32.869348 -14.873975 2.321410 2.433791 1.219350 2.117053 1.304531 0.495823 0.804926 0.645868 0.351783 0.910222 1.857590 1.016742 1.126075 0.447766 0.859120
+1 0.004340 1 1 -0.140736 0.272594 1.051013 2.338325 -1.095871 -2.288167 0.582998 1.386415 -1.282198 -0.148993 -1.855105 -1.590530 42.807999 74.033415 29.603408 -5.523704 13.102457 1.569896 0.998633 0.516877 1.395587 0.887301 1.368365 2.362284 0.901010 2.283342 1.632529 0.673265 1.822418 1.636438 1.117251 0.644025
+1 0.045878 1 1 -0.690559 0.387954 -1.603325 -1.634622 0.133371 -1.538701 0.639166 -1.785966 1.192041 2.268366 1.209192 -1.646963 1.908469 -24.362639 37.133568 -46.114874 -2.687917 0.987688 1.070265 0.686925 1.900001 0.573735 0.764650 0.974261 0.398255 1.223201 1.587524 0.272208 2.243027 1.302210 1.993146 2.296750
+1 0.042185 1 1 1.866605 1.654374 1.966340 0.285758 0.811142 -0.077548 1.981177 -0.100973 -0.592077 1.530221 -1.799105 1.848186 -50.843807 18.135037 -4.439169 -59.116445 29.910304 2.162120 0.508327 1.703289 1.933352 0.851857 1.902504 2.133586 2.438435 0.526178 2.474553 2.305506 0.639433 2.458620 2.284676 1.542393
+1 0.070947 1 1 0.177697 -1.098036 -0.971949 2.310607 -0.420925 -1.184143 -1.475085 0.122048 1.365261 1.313768 -1.757309 2.165763 47.135669 59.183069 39.836521 -67.589016 -18.596202 2.179432 1.215927 0.833759 1.486532 1.650743 0.795317 1.136572 1.367957 2.248254 1.413720 1.886071 0.444140 0.661325 1.381340 2.185039
+1 0.045561 1 1 2.064771 0.576445 -0.362592 -0.962603 -0.840634 -0.798826 -0.275602 0.232880 -1.986985 1.445080 -0.187140 -2.104865 -17.728810 -68.106299 -12.561148 -65.210972 49.185769 1.603403 1.647621 2.318842 2.020591 2.328384 0.399122 2.285272 0.320731 1.020107 1.441789 1.150363 1.401513 1.485553 0.938555 1.041754
+1 -0.050648 1 1 -1.038313 -0.944065 -0.279939 -1.972210 0.018161 -1.080369 -0.933026 1.466903 -0.978205 0.839049 -2.285123 -0.096048 65.906299 -62.836712 53.373404 46.796726 62.568066 0.347257 1.353110 2.470339 1.231640 1.677673 1.150903 1.482011 2.165019 1.980000 1.855417 0.496733 0.337748 1.272829 0.932816 1.346259
+1 -0.020720 1 1 -1.490832 -0.636391 1.292216 -1.129781 -2.006898 1.346792 1.929795 -1.315908 -1.222108 1.338446 -1.685275 1.756519 -41.579916 16.344577 53.306425 -28.923184 38.042475 0.323145 1.093678 0.451726 2.151260 2.471870 2.223295 0.413006 1.637996 0.305707 0.523029 1.302297 1.211535 1.265215 1.221286 0.900344
+1 0.036328 1 1 0.813139 0.491517 0.116201 2.055212 0.130471 1.571791 -0.555000 -2.073907 1.379628 -2.255446 -0.828277 -0.456735 4.529561 -71.659669 -34.050215 -31.971219 -40.280847 0.622149 2.202066 1.374243 2.157339 1.142616 1.705412 1.600559 1.092215 0.604607 2.133603 0.462700 2.103541 1.468562 1.126067 0.301310
+1 -0.018280 1 1 0.765086 -1.303075 -2.317203 -2.055595 -1.862835 0.450817 -0.632649 -1.777542 1.396433 2.146991 1.716749 -0.556189 47.904751 -64.855508 23.470571 -30.119333 34.369886 1.445080 2.452748 0.340117 0.594640 1.113397 1.116833 0.369152 0.337920 1.925744 1.238621 2.005440 1.921574 0.900649 0.713054 2.293290
+1 0.030599 1 1 -1.850847 -0.700319 1.294299 0.888409 -2.068105 -0.058083 -0.735942 1.036111 1.644704 -0.335554 1.067609 -1.472140 -70.515531 -4.532984 14.139376 40.499368 -27.124519 0.898057 2.136106 2.025616 1.274370 2.089963 0.513891 0.711988 2.384037 2.008825 0.325000 0.774573 1.252902 1.275620 0.592102 1.200866
+1 0.019404 1 1 0.435574 -2.352106 0.389981 -0.529765 -2.060416 1.937079 -1.404473 -0.624404 0.130643 -0.264035 1.430442 -1.165783 25.268354 35.224296 -35.260353 29.244624 -35.601909 1.205662 1.555248 2.308512 1.669338 0.561703 1.046315 0.910039 1.023967 1.069178 0.417808 1.346526 2.053319 1.135751 1.063668 2.312732
+1 -0.047892 1 1 -1.874127 -0.836261 2.012548 -0.632829 -0.088465 2.290924 -1.369803 -2.263167 1.355689 0.660044 0.401570 1.042876 71.450399 -33.151827 67.251638 48.284844 23.370659 0.484929 2.198949 0.726799 1.559943 2.455587 0.805311 0.355675 1.076738 1.487109 2.339978 1.766829 1.098879 2.353544 0.257776 0.446154
+1 -0.014832 1 1 0.157642 1.119950 1.717269 -1.246096 -1.276545 0.622689 -0.689351 1.845905 -2.248646 0.367805 -0.949347 0.475057 47.797190 -72.635282 68.822980 57.829456 -60.340051 1.596443 1.674648 2.050720 2.458024 1.266780 0.523005 0.894219 0.633954 0.370308 1.765432 2.367435 1.975084 2.493002 1.893319 0.768520
+1 -0.041157 1 1 -1.462632 2.081219 -1.016661 0.106488 -0.964053 -1.639517 -2.026822 1.059637 1.195673 2.041984 -0.696548 -1.314411 11.774244 39.712484 -52.277865 65.928131 4.090088 2.006651 2.025390 1.977446 1.689735 1.369854 0.393736 1.772643 2.054374 0.864667 1.201508 1.498093 2.440619 1.226718 2.195040 0.278411
+1 0.023791 1 1 2.109310 -0.137600 1.142104 1.775860 -1.387064 -0.204385 0.239597 -2.183378 -0.653180 1.867784 -2.095449 2.190123 29.232050 53.069685 42.201556 -68.453888 -4.493044 0.406018 1.194026 1.744842 0.565469 1.331767 1.503495 0.996109 0.854222 1.162735 2.341966 1.417433 1.298875 2.192681 1.134436 1.468025
+1 -0.012160 1 1 -2.163315 1.963115 -2.082517 -1.952448 2.285568 -1.851128 -0.720191 1.875467 -0.195919 1.156454 -2.083311 -1.165317 -25.338911 -21.080070 7.255117 -13.246543 -34.644704 1.771818 1.699652 1.549637 0.251530 1.212916 1.978575 0.404350 2.410411 2.036714 1.054165 2.358287 1.227242 2.007136 1.185202 1.933053
+1 -0.046343 1 1 -0.990415 -1.751566 -0.283333 2.242731 -0.822601 0.701902 1.753249 0.294729 0.789884 0.778525 -1.637884 1.862090 37.123877 -58.995314 -34.250306 55.115000 67.801248 1.158627 0.792310 2.361862 0.573081 1.019648 0.475099 1.232783 0.632304 1.876578 0.651208 2.349463 1.423166 0.898839 1.793128 2.108561
+1 0.034416 1 1 -0.959027 -2.002943 1.845482 0.074568 -0.231884 -0.135093 0.863818 -0.678512 0.229025 -0.802099 1.266868 1.685167 36.380146 41.122153 -59.968048 -32.986669 -6.940236 2.206738 1.139407 1.762326 1.908076 1.276697 0.701978 0.637851 0.619077 2.324220 2.413706 1.164062 2.144588 0.594051 2.467710 2.060007
+1 0.000330 1 1 2.246255 1.865573 -1.545763 -0.235715 1.462416 -0.988358 -0.161748 0.544173 -0.838894 0.181283 -2.089475 -1.086403 42.613835 -39.283165 67.846744 0.230969 -18.099912 1.296739 2.290795 0.884847 0.623632 2.382018 1.832301 1.232947 1.141193 0.275352 1.094545 1.524768 0.767561 0.389530 0.834879 2.317634
+1 0.017314 1 1 -2.006224 -1.458019 -0.498853 -0.883567 -1.375798 0.661146 0.059364 -1.296263 -0.916616 -0.771471 -2.324061 0.504353 -29.573183 63.516506 -28.080328 -46.080856 -30.943468 1.122086 0.904747 2.086087 0.619827 1.425950 0.443276 1.896464 1.866956 0.937344 0.948046 0.810385 2.393158 2.309214 2.216674 1.637408
+1 -0.012315 1 1 -1.830264 1.223045 0.282857 -0.830586 -1.558280 1.439954 -1.525694 -2.234812 1.962415 0.295029 1.111073 -1.387283 26.702110 -17.632068 57.838350 -60.845050 -72.753778 1.783872 1.789157 0.609230 1.086025 2.328771 2.400909 2.078923 1.714565 2.451803 2.455338 1.120242 1.404612 1.814550 2.144889 1.153828
+1 -0.036747 1 1 1.112831 -0.130309 1.165251 -0.322110 0.838206 -2.311548 -1.255330 -0.971408 1.974610 -2.087419 0.480181 -1.927895 7.922732 -42.636111 -35.125253 49.868049 -67.701320 2.033669 1.628175 1.731948 2.107242 0.674474 1.890293 1.658828 1.665391 1.734521 0.344190 1.546018 2.427176 0.288279 2.356162 1.521753
+1 0.032677 1 1 -1.739649 2.099870 1.436357 -0.725851 0.995429 1.192340 -2.131242 -0.912393 -0.480316 -0.340243 -2.333817 1.472768 -43.544221 2.281909 -47.948678 -73.439166 57.938285 0.906311 1.366341 2.088433 1.787909 2.131076 0.746602 1.382018 2.333383 1.168046 1.603628 0.933733 0.999616 1.295875 1.271479 0.742577
+1 0.025604 1 1 1.854601 -2.180830 -0.256029 -0.666454 0.255164 0.265946 -2.299363 0.910749 1.119609 0.706185 -1.652616 -0.705124 20.319852 -34.248645 -66.974211 -35.561786 63.055405 1.707805 1.329269 2.271054 2.112587 0.494547 1.844893 1.360406 1.340836 0.930761 0.551947 1.315003 1.012179 0.942846 1.155926 0.392638
+1 -0.016187 1 1 1.695767 0.222206 -2.306248 -1.704805 -1.339572 1.609768 1.539289 -0.178278 0.765014 2.188519 2.242856 1.281860 -25.998388 -4.898872 14.658169 59.842881 29.300874 1.521871 1.588203 0.429338 1.640575 0.888344 0.891340 1.747651 0.526824 2.084614 0.613009 1.596842 1.618606 0.656106 1.423842 1.008478
+1 -0.021108 1 1 2.205602 1.897529 -1.672162 0.654557 -2.288626 2.297419 -0.599984 0.582667 0.533219 -1.154942 -0.772709 0.428244 53.547434 -28.281683 19.748553 -36.070859 57.068958 2.244629 1.236879 1.974098 1.670034 1.005250 1.483642 0.317445 2.047052 1.553091 2.045723 1.719071 1.672384 2.250584 2.315390 0.262004
+1 -0.004426 1 1 1.442784 -1.086689 1.230735 2.290816 1.533836 -2.299659 0.640271 -2.065695 -1.971704 -0.914533 1.259259 1.021073 -42.793078 26.730500 9.512709 -19.908377 49.909489 1.806762 1.742266 2.260778 0.402013 1.385846 1.405778 1.163436 0.619526 0.880032 0.690513 1.460269 1.241451 2.318066 2.484967 1.843839
+1 0.002198 1 1 -0.112611 1.726591 -0.068915 0.984905 -1.329235 0.987873 1.434705 -0.208891 -0.103443 0.302636 1.734856 2.180086 59.601190 17.198047 -2.428515 -16.053374 40.946463 1.182958 2.481018 0.721789 0.599393 2.250257 1.323797 0.307011 2.183228 2.009796 0.885009 1.091614 1.765658 1.665521 1.658675 1.344429
+1 0.049840 1 1 1.514199 2.235916 -2.266891 0.019649 0.365773 -2.116916 -0.464903 -0.481028 1.828852 -1.398309 -0.698155 -0.047146 -22.489642 16.593534 37.526439 -43.133526 4.833194 0.347338 0.456827 2.397131 1.589714 1.067679 2.233999 0.328772 1.163480 1.361495 1.655614 1.658578 1.962713 1.573435 1.970027 0.741002
+1 0.007057 1 1 -0.223560 -1.603398 1.850592 1.130688 -1.592850 0.052522 1.526572 -1.861426 0.559843 -1.357124 -1.216288 0.194639 28.418402 28.078940 22.746145 -55.548771 -8.187478 0.520740 1.081562 1.563743 1.085918 0.520275 2.260554 1.128985 2.103369 0.813692 1.718699 2.179700 1.212716 0.869155 2.380901 1.048393
+1 0.051128 1 1 -0.152723 1.440511 -1.584237 -1.268117 0.888081 1.844712 1.275281 1.704048 -1.971177 -1.474582 -0.841073 1.260689 47.860809 -53.376756 46.860459 -66.258687 -9.758833 0.374419 1.110378 2.132185 1.388878 0.624349 0.926660 1.370573 1.222909 1.188521 1.463919 1.841039 1.842318 0.847256 1.080777 1.877260
+1 0.001718 1 1 -0.678768 0.641950 -2.125000 0.316636 1.419250 -0.771425 -1.559409 1.319415 -1.093319 -1.806595 -1.527139 1.760569 25.460729 -31.534688 -53.492856 45.577553 -28.059003 1.560145 1.353449 1.409491 0.562135 1.554088 0.813451 2.174998 0.945704 1.949463 1.624268 1.319360 2.232358 1.986500 0.851416 1.256620
+1 0.041586 1 1 -0.388558 0.878738 0.322069 -1.525556 0.097868 0.235618 1.619321 1.875395 -1.410849 0.601254 1.919751 -0.470927 61.910864 -14.107473 45.693016 -37.472004 58.025135 0.301718 0.967419 2.417848 1.015559 1.495370 1.678916 1.790870 2.403638 0.701001 2.227839 0.295063 1.625558 0.507082 1.030921 0.945282
+1 -0.013631 1 1 0.705238 1.271732 -1.404716 0.008183 0.876792 0.601411 -0.154068 -2.318291 -1.487678 0.529382 0.334986 -1.191037 14.971810 -68.786325 -41.757625 29.601321 -40.593274 0.607760 1.124869 0.424003 1.966589 1.468098 2.318706 1.985569 0.963838 0.719029 1.478830 0.450643 1.960751 2.333938 1.502735 1.716031
+1 -0.003240 1 1 1.478943 -1.253493 1.632162 0.923655 1.261757 0.602235 -0.455367 -0.427577 0.098613 -1.369753 -1.412767 1.347767 -16.862260 -54.006352 -34.760184 35.588152 -69.937725 0.724718 0.336456 2.060348 2.264460 1.530039 1.624438 1.928323 1.821944 0.416191 1.171295 2.212488 1.032778 0.648682 0.397927 2.460582
+1 0.037120 1 1 0.819519 -0.649979 -0.875418 -1.077354 -2.082414 -0.211854 1.936434 1.886649 -0.753290 1.638762 -1.238305 -2.280469 -63.266973 21.987823 -50.655322 36.002000 -14.392921 2.097699 2.274531 2.046017 2.151057 1.313796 0.962301 1.891600 1.122224 0.968120 0.696271 1.480198 0.942495 2.012681 2.135473 0.393929
+1 -0.010528 1 1 -0.390725 2.158444 1.001595 1.147319 -0.103930 1.550514 -0.030155 2.125473 -1.800404 -1.141907 1.525164 -1.960015 74.660224 64.382057 -30.763248 12.087214 49.802741 1.895090 1.285103 2.483734 1.374208 1.557336 1.396742 2.290089 0.282183 1.141534 1.512807 2.243384 0.558330 0.604060 1.938715 0.976922
+1 0.007635 1 1 1.717126 1.071838 -1.085021 0.999971 2.132593 0.054623 -0.864208 -1.162133 0.874923 2.172212 1.494166 0.126697 -19.458041 -31.290194 5.704366 23.283850 -18.326313 0.469844 0.664681 1.541934 1.275791 1.210556 0.562905 1.001296 0.282719 1.154236 1.246183 0.853726 1.815226 2.248470 0.536945 1.186630
+1 -0.058649 1 1 0.378597 1.354182 -1.105929 -1.692943 0.103169 -0.203162 1.938970 2.102162 2.256095 2.310766 2.247814 -0.213920 6.554484 61.214314 -21.032447 57.670815 -26.615791 0.901074 1.108286 0.716193 1.058664 1.459388 2.183730 1.442534 2.425017 2.264061 1.577840 1.759761 1.560101 0.621658 0.698802 1.258792
+1 -0.032918 1 1 2.083836 0.553119 -1.278049 -1.105261 0.116421 1.043267 -0.604787 -0.030409 -2.152564 -1.127821 -2.060603 -1.211332 -42.659833 16.193627 66.286695 30.482073 62.203500 0.688437 0.304384 0.786741 1.007087 0.864509 0.801744 1.163583 0.841190 0.374865 1.857428 0.540395 0.661424 0.811358 0.751064 2.137519
+1 -0.000999 1 1 -2.174587 1.013459 -2.079916 -0.651788 1.696293 -0.352595 2.119537 2.106194 -0.659544 -1.410607 -0.037898 -0.776038 32.799809 16.388867 47.692753 -27.894639 74.810282 1.921209 1.500855 1.614309 0.437722 0.795914 2.183241 2.236023 0.583428 1.680157 2.391709 0.452094 1.588175 2.204344 1.414906 1.567932
+1 -0.047784 1 1 -1.077889 -1.651411 0.706984 2.342310 -0.098072 1.044414 -0.185771 2.059849 -2.044169 1.680875 -0.296968 -0.727210 54.528126 -45.788365 -65.051061 36.820454 -58.637567 1.051254 0.684494 1.545967 1.558507 0.830329 2.332439 1.046985 0.932089 0.362176 2.346351 0.879388 1.118100 1.415296 1.373445 2.244540
+1 0.029506 1 1 0.508951 0.945967 -0.734772 1.863841 2.329578 -2.026441 -1.963466 0.887730 0.651880 -0.159577 -0.660481 1.683172 19.214783 -7.133887 -49.236484 32.409896 63.125704 1.430522 0.789181 1.517000 0.717863 2.127268 1.990083 0.317527 1.176092 1.820397 1.414816 2.321579 0.773876 0.789792 0.526707 2.360291
+1 0.015210 1 1 -2.150342 -1.480637 1.066028 0.229508 -2.103896 1.579303 -1.535241 2.240460 -1.293926 0.669360 1.459736 1.077993 -41.437458 10.639506 18.181473 26.018113 36.423874 1.765714 0.349080 0.479311 2.280781 1.328790 0.969804 2.000523 0.297925 2.474741 0.972386 0.385988 2.046305 0.256020 2.426066 1.884240
+1 -0.015342 1 1 0.365109 0.854707 1.706523 1.927600 -0.493598 -2.105439 -0.782149 1.982100 1.284107 -0.749542 -1.344436 -0.035383 -29.513519 16.288068 3.562427 23.717624 72.104528 1.536957 0.895063 1.330914 0.668391 0.891643 2.349568 0.932461 2.126889 2.380209 0.665704 0.734663 0.976881 1.686392 1.433886 1.069042
+1 -0.002575 1 1 -1.288717 -1.332248 2.185722 -2.349829 0.954540 1.988696 -0.964597 -1.355374 -0.087622 2.311891 2.298390 1.581797 -64.570513 13.395216 -16.599468 12.740181 74.214770 0.289671 1.003258 1.751700 1.078101 1.890703 1.790272 1.357145 0.542535 0.643785 1.348254 1.857183 0.925710 1.162575 1.896734 1.914143
+1 0.067166 1 1 -0.075802 -1.651229 -0.951962 -1.066840 0.259293 -1.020922 -0.821379 -2.327600 2.281171 -0.356578 1.154598 -0.283111 40.128057 32.253072 -22.610761 -69.053328 -29.284276 0.912669 2.484059 2.329490 0.992761 0.836018 1.204733 1.691389 2.179073 1.933287 2.007049 1.975934 1.021881 1.997431 2.315638 2.180855
+1 -0.059429 1 1 -0.476820 1.861693 -0.784233 -0.047633 0.537952 -1.721907 -1.305815 -1.238264 -1.599095 -1.230611 -0.212467 1.053149 17.208678 26.252191 70.572608 63.815369 44.899115 0.916375 1.765779 1.451617 2.082331 0.491643 0.301462 1.171183 0.321158 1.446473 1.122014 1.933734 0.514030 0.805596 0.657581 1.461458
+1 -0.006503 1 1 -2.283159 -0.062899 -1.564440 1.591413 -0.640483 -1.507621 -0.069786 0.497690 0.182818 0.147136 -1.094960 -1.116738 13.784101 69.383072 21.295224 8.823317 -56.502923 1.455700 0.947036 1.834638 2.261475 0.863134 2.441276 1.024935 1.585392 0.432271 1.430800 0.951745 2.220055 2.216364 0.922686 2.088154
+1 -0.003651 1 1 -0.784617 -1.800391 -0.928477 -2.201487 1.282107 -1.385215 -2.105417 -0.415996 1.544606 -0.366931 1.505381 0.131168 -27.106008 -20.671052 -18.375571 11.769999 -31.621741 1.125975 1.009877 0.498965 1.852719 2.394394 0.584562 0.484509 1.894545 1.115696 1.502110 2.467401 1.363511 1.787129 0.276811 0.859886
+1 0.006979 1 1 0.060741 -1.710393 -0.997967 -1.442484 1.412157 -2.178940 -1.462373 1.721108 2.012656 1.183113 -1.701927 -0.089519 -41.322845 -13.053489 60.015376 -71.568161 3.921739 2.314906 1.116579 0.597128 2.436262 2.260624 2.314111 1.258898 0.799717 0.846889 1.657351 1.600164 1.206015 0.748098 1.785063 1.558976
+1 0.010781 1 1 -0.003704 -0.990153 -2.051304 -0.423762 -1.742163 2.257813 -1.800907 -0.175025 -1.118273 -1.811758 1.239268 -0.383315 -17.293341 50.811744 42.974830 27.960120 -24.267020 1.288015 1.921843 0.920982 0.447001 1.487369 2.205173 1.842971 0.556458 0.643212 0.715087 0.472385 0.619932 0.946533 2.381701 1.005320
+1 -0.031185 1 1 1.663009 1.019488 0.285715 0.087354 -2.099598 -1.574076 -0.142626 1.495350 1.181355 1.732392 -1.545057 2.210472 -34.077389 -38.679780 8.938280 -74.327315 -19.175669 2.343005 0.879127 1.243362 0.678822 0.705175 0.381036 2.073375 0.718598 0.974666 0.469036 0.582674 0.259785 0.459968 1.183214 2.274824
+1 -0.079347 1 1 -1.641466 -1.794281 -1.911121 -0.575614 0.191372 -2.171132 -2.191350 2.005228 -1.142066 -1.138595 0.639874 0.696180 -5.282188 22.263352 -69.841546 73.135135 -67.783383 1.595136 2.193254 1.776848 0.731836 0.714793 2.278266 1.812064 0.857665 0.533124 2.222690 1.506049 1.172304 1.169234 1.323596 1.423941
+1 -0.046756 1 1 1.444113 -2.310023 0.816644 -1.850279 -0.585299 2.340308 -0.757791 1.401976 1.060946 -0.368699 0.073149 -0.513623 20.041332 -65.327669 37.871415 54.866612 -56.845161 0.675772 1.203605 0.744278 0.572779 0.451612 2.496546 0.705948 2.111525 0.657087 2.159468 0.934832 1.465975 0.397572 0.996126 1.136764
+1 -0.009891 1 1 -2.304453 0.191942 -2.021593 -0.582825 1.521016 -0.987040 -1.574023 0.751699 -0.107688 -0.357439 0.823132 -1.202277 1.557902 -66.342601 -70.101879 47.720050 -19.122264 2.306588 0.830119 1.056153 2.006355 1.558995 2.280149 1.959219 1.338340 1.722357 0.653856 1.858174 1.823554 0.472664 0.807730 0.510302
+1 0.009017 1 1 -1.249699 -0.573071 0.515425 1.383526 1.998279 -0.128939 0.613371 -1.787200 -0.708739 1.150207 1.312714 -0.621426 -52.624398 -58.257083 73.213763 53.707675 -35.104756 0.540532 0.716204 1.243051 2.206792 2.056219 0.374980 1.537939 1.637751 0.687237 0.392775 1.363599 1.002613 2.161872 0.828664 1.361954
+1 -0.059461 1 1 0.768228 -0.331738 -0.763762 -0.002207 0.597944 -1.873565 -0.824583 0.377762 1.462077 -1.979526 -0.424986 1.242234 74.456929 -52.389275 -6.547150 62.047480 32.003697 1.166970 1.522015 1.762585 1.771509 1.006836 1.148360 1.481240 0.453759 0.334634 0.686823 2.439942 1.099910 1.690652 1.035098 1.390072
+1 0.002621 1 1 -1.108787 2.111279 -0.026964 -0.792176 -1.601030 -0.764135 -1.561267 -1.639133 -0.283690 0.964556 0.671566 0.831567 -25.331587 -47.974413 -55.952506 -43.770544 -51.529601 2.004882 1.555911 2.194565 1.308287 0.624095 1.159215 1.668521 0.336903 0.574337 1.886212 0.560306 2.309658 0.677413 1.776049 0.805355
+1 -0.003969 1 1 1.162208 0.381720 2.007938 1.993677 -2.077885 0.507998 -0.919118 -0.409134 -0.931770 -0.996145 0.911070 1.800056 -0.022077 -71.050319 7.291241 -6.116730 -53.883277 0.381449 2.271436 1.777120 0.806282 0.933892 1.416443 0.415647 1.029411 0.316380 2.150988 2.412709 2.397496 0.972022 1.028121 1.128376
+1 0.001819 1 1 -2.166707 1.492220 0.409358 -0.001323 1.334327 -0.231632 -0.598545 1.212340 -0.573171 -1.157603 1.625349 -0.472101 34.005563 31.495584 -3.723764 -35.298650 -14.410463 2.175344 2.262154 1.024966 2.110150 2.290966 1.517653 0.443090 1.013324 2.179807 0.764203 2.467420 1.686273 1.688397 1.379199 2.205989
+1 0.010805 1 1 -0.501599 0.088233 -1.471941 1.135687 2.324201 1.855914 1.041355 0.237321 1.977766 -0.885466 -0.295291 -0.816610 -72.857000 -57.593173 -18.465879 -6.028705 -74.450608 1.504360 2.033598 0.427236 2.304318 0.920664 1.843694 1.456439 2.114344 0.774884 1.971163 1.839131 1.274195 1.396264 1.014672 2.343473
+1 -0.013053 1 1 1.328602 -2.192575 0.273732 1.313875 0.041373 -2.085153 0.875568 -1.123963 1.525614 0.890282 1.140201 -1.933177 32.252026 -40.202482 66.883373 8.852760 -11.656073 1.320691 2.096824 1.074720 1.313508 0.627289 0.852036 0.427153 0.911032 1.971698 1.834012 0.746028 0.743287 1.925217 1.376884 1.537343
+1 0.015982 1 1 -0.645811 -1.511781 0.699901 1.119532 -0.600542 0.631141 -0.008495 -1.401269 1.393392 -1.835125 -0.352843 -2.051840 -0.456277 -18.648157 -69.579166 -17.049365 -48.673609 2.014884 0.912225 1.773848 2.069650 1.104466 1.765179 0.365715 1.065333 1.056990 0.321914 0.653384 0.670803 0.934962 1.400184 1.640985
+1 0.027107 1 1 -0.497078 0.676236 -0.781857 2.190287 -1.031473 0.903925 -0.480651 -1.263992 -0.471405 -1.379819 -0.958761 -2.233713 50.623123 22.823349 42.033512 -42.756936 34.169063 0.316598 1.315455 1.851642 2.299257 1.366116 0.570406 1.058078 0.620791 1.879299 1.380456 0.830988 2.158197 2.068814 0.561078 1.784460
+1 -0.039046 1 1 0.351908 0.470701 -1.029302 -0.299475 -0.445384 -2.299728 -0.518785 -1.302609 0.815859 -0.903675 -0.041220 -0.064420 36.533856 74.511947 -27.709226 41.045513 1.941098 2.485530 2.309418 1.140914 2.339703 1.637900 0.929468 1.318915 1.511300 1.665285 2.194145 0.996698 1.761302 0.455696 1.389514 2.314780
+1 0.074445 1 1 -1.496967 -0.071460 0.623012 0.027497 0.327538 0.859082 -0.169782 2.184483 0.389383 -1.146991 0.898817 -1.495132 -70.988827 -9.215959 57.382714 -68.733319 -50.893360 0.404438 1.639067 0.299872 1.456701 2.024336 2.273324 2.013607 1.942155 0.291173 1.494878 2.406211 1.185554 1.098820 1.366717 1.658069
+1 -0.007332 1 1 0.641273 0.638615 -1.626443 0.934391 -2.088931 -1.358080 1.566179 -0.626867 1.140645 0.822410 0.802034 2.347097 7.867830 -65.376787 -37.654015 -1.026729 -6.230293 1.187043 1.380572 0.519669 1.081005 1.196583 1.973232 0.605990 0.624521 1.573201 0.288849 0.691555 0.967008 2.251677 0.440639 0.316541
+1 0.002369 1 1 -1.039873 1.098990 -1.839986 -1.954180 1.451765 -0.930698 -1.821601 0.741335 0.068796 1.717549 -1.245512 -0.888201 27.098490 44.313538 27.632221 14.742630 -20.623176 1.919154 0.720735 0.900536 1.066177 1.729578 0.511324 0.324622 1.166425 1.355161 0.945165 1.880939 1.947617 2.104058 1.153396 0.629769
+1 0.015095 1 1 -0.716935 0.053697 -2.287534 1.800682 1.097828 2.198319 2.009367 -2.268244 0.858425 -1.786112 -1.258916 0.028809 -37.603998 -60.399537 64.979049 -47.115632 -22.418704 1.507622 0.610302 1.097729 1.038626 2.184475 0.475659 1.644336 1.110208 1.523152 0.615452 2.144210 0.978930 2.369800 1.235210 0.925622
+1 -0.017068 1 1 2.225782 1.768588 -1.086582 -1.668552 0.072237 -1.702424 0.994939 -2.327788 -0.875539 1.611491 2.234973 0.743758 -51.879630 9.051643 30.970585 22.619743 70.020469 0.385383 0.886972 0.335725 1.024476 0.619828 1.456133 1.468756 2.138389 2.151190 1.304196 1.614148 2.237948 1.434939 0.765804 2.359827
+1 -0.019507 1 1 -0.594556 2.275013 -0.185977 -1.409131 1.194114 -0.585785 -1.111074 1.376477 1.326132 -1.295022 1.083484 1.436492 49.497539 5.130974 -13.714763 45.974267 39.512197 1.847485 2.173848 1.857172 0.743771 1.053614 2.089809 2.424527 0.770359 2.418682 1.539366 0.868543 1.104078 1.982822 2.035463 0.277110
+1 -0.019671 1 1 -1.780946 0.731655 2.310229 -2.067945 -2.090559 -0.444539 -2.238377 -1.403335 -0.342438 -1.522719 0.648400 -2.093795 54.572073 -57.172027 9.743176 -46.435527 8.090255 2.468744 1.432176 1.577779 0.737364 1.371147 1.870393 2.438818 2.460733 1.792835 1.671820 1.787171 0.985217 2.285664 2.408716 0.538072
+1 -0.045583 1 1 1.460955 -1.991819 0.306193 0.264371 -0.499464 -1.726726 -2.188785 -2.008619 0.691161 0.301079 -0.865474 1.125214 20.808770 -67.009373 -26.539147 56.558037 20.922467 2.033606 0.568516 0.791585 1.419039 1.281212 2.337417 1.460835 1.762534 0.917316 1.828025 1.366679 1.029892 1.639166 1.972160 0.596276
+1 -0.041874 1 1 -2.108660 1.632038 -1.150010 1.998416 2.181612 -0.749031 -2.174416 -0.840144 -1.985149 -0.694461 0.783626 -0.731279 -22.177694 9.499432 56.955574 -47.660703 -33.435931 0.509547 1.958492 0.378470 1.691186 1.013233 0.653923 0.736263 0.864568 1.796002 0.908420 0.813519 1.058300 2.090885 0.255946 1.185946
+1 0.025372 1 1 1.653097 -0.637205 1.747382 0.634680 -1.777015 0.834835 2.286990 -1.509237 1.050988 1.927804 -1.789157 -0.605097 -16.635371 9.313023 73.980914 47.213927 24.475643 2.306918 1.867214 0.771846 0.415867 2.472792 1.971672 1.386612 0.789716 1.498340 2.096438 1.338182 1.321237 2.280425 2.100123 0.260566
+1 -0.002358 1 1 -1.345158 1.975861 0.094393 -1.615765 1.326419 -1.181878 -1.104297 2.171443 -2.017399 -0.790189 -1.190036 -1.549786 -59.724838 4.654384 -73.763822 1.442943 -48.451294 1.811528 0.851215 2.365556 1.902100 2.095947 2.075725 1.964654 0.440776 0.368186 2.099493 0.936198 1.931043 0.294308 2.427347 0.912544
+1 -0.061221 1 1 -1.161229 1.935894 2.231129 2.108696 -1.018820 1.521363 0.120708 -2.295918 2.261032 0.451525 1.833675 -0.448105 -28.693647 -4.126457 -53.366301 72.580450 59.622039 2.389250 1.879774 0.358047 0.442273 0.786428 2.488587 1.927051 0.700186 2.028326 1.821679 0.462527 1.441997 2.392346 2.162018 1.040519
+1 -0.004459 1 1 -1.293063 1.024652 2.253604 -1.852300 -1.559612 -2.096198 -0.987929 2.339840 0.800698 -1.252491 -0.369574 -0.500588 -56.366647 45.766952 5.169167 28.182912 -29.794258 0.593564 1.029460 1.128963 1.726265 1.079792 1.070756 2.196406 0.739340 0.844460 1.344874 1.300591 1.785955 0.788477 0.927824 0.691143
+1 0.002151 1 1 -0.286364 -1.570249 -1.797522 0.177039 1.975194 -1.691073 -1.441447 -0.004942 1.754887 -0.463174 0.303650 -0.073328 70.606032 25.581197 43.179128 11.604713 40.411230 1.248027 0.340108 0.441985 0.435955 0.346123 0.283666 1.329763 1.572075 1.621621 1.829421 2.325354 1.232041 1.659157 0.447099 0.886447
+1 0.049345 1 1 0.103727 -0.250234 -2.239076 0.996044 2.110219 1.017012 1.080591 -0.051037 -0.116610 0.495779 1.048198 2.156933 -26.476933 52.188362 -70.199347 59.570961 -40.865193 1.805639 0.873797 1.661949 2.370418 0.371193 0.897377 1.964465 1.757009 0.295969 1.104424 1.062532 1.218864 0.697309 0.927470 1.495722
+1 0.032074 1 1 2.187966 -2.339515 -0.060726 1.968706 -2.344680 -2.046207 0.404582 -0.169099 -0.469042 0.637405 1.608706 -2.163165 -7.469499 10.132098 40.163339 25.246114 -38.556056 1.200429 1.361521 2.078238 1.449137 0.900112 0.680559 0.650847 0.787063 1.924017 1.449003 0.897139 2.463255 1.424549 1.652912 1.235766
+1 -0.037684 1 1 1.697611 -1.770734 -1.982456 2.171793 -0.846585 -1.843753 0.720326 0.384152 0.465486 0.855172 0.086591 -0.799270 54.053104 70.512005 -54.734154 33.075462 -0.703020 1.890070 2.405487 0.266220 0.617623 0.383860 2.282177 2.301693 1.807652 0.960989 2.348803 1.585750 1.951475 1.690012 1.526906 0.711304
+1 0.010325 1 1 -1.376179 -1.031276 -0.484279 -0.973290 -1.384133 1.942943 -1.806716 1.153998 -0.950090 2.125349 0.825153 -0.211995 -13.844377 -32.451397 -10.628950 9.236057 -19.591138 1.101190 0.707845 0.256796 1.964490 2.176428 2.471805 1.121444 1.352426 2.231501 1.079584 2.071976 1.945332 1.941152 1.438321 1.368197
+1 -0.007011 1 1 0.316870 0.636263 1.257551 0.598123 1.135658 1.827305 0.872817 -0.233374 -1.615719 2.105049 -1.060377 0.495852 72.356939 53.071625 74.798775 -6.989382 -20.545836 1.166997 1.976759 1.384228 1.213150 1.414102 1.555922 2.385803 2.434140 0.340143 1.025188 1.335967 2.354621 0.359534 0.695568 0.917982
+1 0.004961 1 1 -1.461858 0.954968 -0.243939 -0.097207 1.443225 1.619330 2.024283 -1.325787 -2.326620 -0.103831 -1.501350 1.653927 -26.240125 -17.777684 10.466550 -38.691728 -41.869137 0.706181 1.533828 2.292682 1.100766 0.328197 0.508513 0.328188 0.361211 1.872593 1.174541 0.503798 2.079174 1.418212 0.890691 2.085660
+1 0.048867 1 1 -0.137815 2.231793 -0.873991 -0.651853 0.613175 -0.360899 -0.788489 -0.895948 -2.112035 1.448003 1.817422 -0.300110 -53.727183 7.243669 -55.659005 -60.896872 -43.732412 1.215289 1.362934 1.084934 1.978721 0.615166 1.843871 2.184652 1.195208 1.362869 2.243102 0.319395 1.072384 0.304579 1.808854 0.910741
+1 0.045842 1 1 -0.501927 -0.712224 -0.877983 -1.770658 -0.718916 -0.256870 -0.665919 -0.177830 -1.138459 -1.775425 -0.719437 0.408437 -43.014140 61.350701 21.229324 -48.751938 -73.820482 0.612272 0.454592 0.829473 1.455758 1.930905 2.463061 0.417739 2.438518 1.926225 0.322167 0.408185 1.623558 0.640570 1.315079 2.283221
+1 0.049575 1 1 1.084887 1.460028 1.280131 -1.601404 -2.344254 0.404743 -2.172844 2.027462 0.268321 -0.080031 -2.049044 -0.142668 24.794394 19.373483 -39.863807 58.997431 69.823502 2.478902 1.151046 1.628043 1.761553 2.415982 1.155330 1.637316 2.364203 1.661516 1.847589 1.671961 1.900608 1.759747 1.314381 1.795492
+1 -0.005794 1 1 -1.627666 -0.759745 1.534643 1.839692 1.727885 -1.893186 -0.733199 0.028463 -2.286974 1.789384 -0.292111 0.796086 42.910945 4.251129 48.732274 43.322692 24.477486 0.521663 0.844150 0.627089 1.978001 2.006884 1.456074 0.490012 2.134333 1.477511 0.779985 2.208547 2.304243 1.914608 0.811190 2.419378
+1 0.017979 1 1 0.205983 -1.653390 0.434109 1.285494 -0.999147 2.297344 -1.859319 -1.723171 1.007607 -1.472579 -0.160516 -2.306715 -4.272355 44.524989 -18.512502 -39.614579 47.778263 2.263888 0.915785 0.850705 0.542806 0.683946 1.333187 0.627346 1.797728 0.664246 0.974535 0.501739 1.230378 0.710349 1.832443 1.364415
+1 0.070254 1 1 0.573486 1.736479 1.178179 0.189216 -0.711226 1.756843 -0.563939 -1.510943 0.650942 -1.789104 0.286499 -0.871199 -26.887367 54.021801 -5.591407 -74.774935 -42.332600 0.864908 0.750721 0.867575 0.588920 1.725960 0.457907 0.296453 2.477151 0.976330 1.419992 1.554453 2.445478 1.900080 1.888289 1.726351
+1 -0.013422 1 1 -1.569454 2.131609 -2.342174 -2.330652 -1.893389 0.570068 0.843778 1.796017 -1.903218 0.309390 2.156329 -1.555425 73.405863 -17.653213 2.443314 -35.227742 -22.654388 0.590500 1.284969 2.473682 1.180974 0.636024 1.413546 1.213873 2.312110 1.379531 1.033058 0.853085 2.301998 2.425135 1.995287 2.290064
+1 0.006371 1 1 2.227716 1.291453 0.194262 -0.719562 -1.694733 -1.699606 1.224755 0.749768 0.426501 0.665879 -0.496094 -1.641864 30.105660 35.821303 -51.360336 36.832374 -8.291514 1.292875 0.344025 1.034910 0.487439 1.630833 1.403545 1.887846 1.034067 2.060765 0.278697 1.056329 0.476855 1.509369 0.719089 2.481453
+1 -0.030442 1 1 -0.963877 1.317482 -0.588413 1.850930 2.098695 0.528337 1.615737 -1.803584 1.955167 1.002234 -2.244045 2.288279 41.059582 -61.606677 26.575188 -50.809970 -13.157537 0.794231 0.883057 2.035061 0.277048 0.353858 2.046966 2.353755 1.556004 1.502973 1.224391 1.333765 1.334771 2.495945 1.842222 1.477691
+1 0.025039 1 1 1.957601 -0.492863 0.832776 0.669807 -0.456682 1.026446 -0.576495 -0.474125 0.030495 -1.128883 -1.065126 0.792480 63.528177 18.066486 43.426925 -23.677019 10.340393 0.489760 2.398320 1.314101 1.593854 0.897956 0.452953 0.278707 1.221470 1.739954 1.659470 1.216198 0.886546 2.174802 2.151192 1.334660
+1 0.000939 1 1 2.105700 0.455600 -0.369388 -2.088465 1.762886 2.037656 1.955583 -1.435053 -0.920433 1.062814 -1.949162 0.955937 60.535324 -32.805078 45.060852 -12.266031 -55.182539 1.331044 0.603902 1.536098 2.196889 2.117138 0.494745 0.678251 2.363021 2.037132 1.328387 0.943910 1.043149 1.711088 0.260150 2.085497
+1 -0.005748 1 1 0.193144 -0.661044 1.640292 0.914402 1.252484 0.259374 0.336074 -1.757368 1.170052 0.268764 -2.063719 -1.746811 -15.070364 62.386925 37.046525 -9.048774 17.262546 1.849222 2.125295 0.338087 2.481140 0.517817 1.444503 1.760625 0.331160 0.813970 1.885912 2.266201 1.540778 2.102751 1.692712 1.904884
+1 0.049485 1 1 0.759693 2.298100 1.422294 -1.457109 0.647718 0.585326 -1.892463 1.998852 0.084441 0.770062 2.218612 -0.914784 55.765342 48.097207 19.766080 -41.496103 74.992431 0.591941 0.751673 1.116955 2.421150 0.263478 1.774072 1.331373 1.630608 2.135378 1.040336 1.672886 1.687760 1.937324 2.362668 0.620203
+1 -0.003968 1 1 -0.529858 1.096448 -2.159356 -2.185195 1.794870 -2.337576 -0.460079 0.484298 1.298026 2.280545 -1.448793 -0.952804 -34.404082 20.587644 -33.475081 34.309364 37.476021 1.517300 1.267304 0.322035 0.448672 0.335592 1.040627 2.065110 1.301440 0.296202 0.516883 1.506473 1.547568 1.473471 0.382015 0.530422
+1 -0.017627 1 1 -0.854944 -0.971923 -1.965960 1.379408 -1.240257 -2.094251 -1.242450 -1.270356 0.966134 -1.077032 -1.389133 -1.978312 35.790523 31.326830 10.035235 62.198313 17.050007 2.267092 0.771370 1.417832 1.251920 0.513438 2.108033 0.452526 2.106479 1.341851 2.232897 2.058211 2.346831 2.192190 1.879939 0.885373
+1 -0.034955 1 1 -1.682440 2.276330 -1.613963 -1.366999 -2.258656 1.773818 1.995480 -0.042908 -0.156917 1.641900 -0.329886 2.084070 -7.307565 31.748094 40.221231 -51.763224 15.495257 1.806826 0.575011 1.954732 2.437016 1.432334 1.988813 1.486288 2.042240 1.678435 0.461251 2.499978 2.123988 0.865622 1.508999 1.248399
+1 0.022883 1 1 -0.889067 0.443145 -2.347848 1.262969 2.114474 1.838072 -1.954568 -0.357384 1.743753 0.900709 2.028394 1.801589 70.265163 -3.398582 30.034228 35.265259 53.206959 0.615307 1.958786 0.819824 1.283330 1.934520 2.484341 0.318866 1.173438 2.222953 1.421871 1.633513 1.448742 1.006305 1.219320 1.603934
+1 -0.001417 1 1 -2.290894 1.870683 -0.494991 -1.940587 -1.001967 2.010473 2.183742 2.057414 -0.552613 0.358817 -1.214285 0.876080 -61.599564 -3.875065 -28.211636 -2.959677 56.709701 1.674206 1.379726 2.051156 0.777853 2.383315 1.118635 1.407641 0.977035 2.025439 0.548235 1.932382 0.289118 0.711659 1.353474 1.844300
+1 0.007217 1 1 0.086300 -0.976181 1.865069 -0.600751 1.824244 1.262163 -1.998139 -2.242398 1.708141 0.860894 2.008293 -1.465174 56.211721 50.389429 -4.860412 61.055615 11.725648 0.969594 0.717246 0.761165 0.907193 0.451128 1.104520 0.419964 1.587673 0.518718 0.837453 0.577121 1.422777 1.119511 0.368001 1.239598
+1 -0.034336 1 1 0.187053 0.627932 -2.092640 2.277542 -0.091618 1.121315 1.095721 -0.236625 0.293975 2.246145 0.006407 -0.697063 -17.146809 -36.422379 -0.926104 34.963971 -60.543955 1.941109 0.714965 0.672359 2.341897 0.260747 0.868783 0.637495 1.376164 0.683323 2.105723 2.143269 0.923199 1.709947 1.329080 1.354333
+1 0.026047 1 1 1.547837 2.100812 -1.586574 1.856304 -1.828692 -0.627528 -0.533477 1.527260 0.283407 -1.008364 -1.824672 0.968775 28.382140 18.618826 26.608298 55.657798 40.616793 1.321583 1.350344 0.979751 0.418507 1.851405 0.569408 2.283165 0.913174 1.960293 1.390756 0.691786 0.346308 1.152895 1.208494 1.906756
+1 0.015594 1 1 -0.516098 1.441016 2.186755 0.869264 1.320757 -2.104292 -0.361253 -2.014035 -0.794652 -0.809952 1.225626 1.235323 -22.434246 47.621160 -31.157824 -19.543342 35.054354 0.752804 2.128447 1.557289 0.604533 0.890560 2.144654 1.699230 1.214734 1.037667 1.811143 1.130825 1.518627 1.057917 2.403917 0.891141
+1 0.002520 1 1 -0.455155 -1.587082 -1.968792 0.906842 1.423189 -0.541670 0.479913 -1.715234 -2.252992 -1.992331 1.127138 0.000559 -0.718270 -71.962292 -20.248331 36.308526 37.392908 0.814046 0.915353 0.333616 1.576541 2.423681 2.298341 1.719486 1.903814 1.653350 1.859198 1.046360 1.673474 0.324818 2.223739 1.132902
+1 -0.061254 1 1 0.308771 1.167712 -1.355421 -0.869718 0.472479 0.571476 0.947050 -1.378405 -0.750230 1.230902 0.375807 1.579513 63.012046 43.458891 63.575447 62.537273 13.953803 2.448549 1.756971 1.906398 2.336377 1.995602 0.830083 0.458668 1.832764 2.259685 2.282452 2.426397 0.696657 1.218744 0.924208 0.672311
+1 0.030416 1 1 0.088612 0.187030 0.243117 0.427162 2.343837 2.003149 1.623867 -1.826668 0.406495 -0.999368 -1.423385 1.958862 58.710316 44.289267 69.714420 40.263709 62.158963 0.710252 2.452593 2.238497 1.664834 1.370108 2.401267 1.349201 2.027339 0.983795 0.896318 2.162276 0.879511 0.944681 0.501046 0.828090
+1 -0.036298 1 1 0.855111 -0.937813 1.115829 -1.569580 0.018924 2.320000 1.932756 1.338569 0.388981 1.512798 2.249372 -2.310562 37.551405 -73.539565 20.538245 36.287232 -20.486218 0.446896 1.979905 0.256965 0.317536 1.323446 1.163872 1.201823 2.286263 1.215422 1.353352 2.032741 1.775181 1.959844 0.590280 2.090866
+1 0.022924 1 1 0.377401 0.105051 -1.558800 2.135429 0.606484 0.271684 -0.116101 -0.386646 0.023205 -1.119465 1.729650 -0.492672 -21.188750 -19.327900 55.992963 -26.262755 51.870162 1.102122 0.615640 0.806493 2.229918 1.478260 2.114264 1.691734 1.225677 0.461844 1.216736 0.925468 1.592654 0.978264 2.434160 0.672836
+1 -0.022845 1 1 -1.407834 -0.561890 -0.058690 -1.518395 -2.080296 -2.314557 0.004626 -2.354343 0.496100 1.733328 0.061309 -1.590948 -30.790588 2.579943 11.108828 -43.927744 6.406315 0.939034 2.348921 1.310760 1.689811 0.398785 1.128310 2.005158 1.698382 0.457234 2.479024 0.949962 1.510596 1.090285 1.915244 0.253400
+1 -0.047971 1 1 -0.044796 1.101909 0.094428 -1.020619 -0.439373 -0.224866 0.013381 -1.292587 -0.394501 -0.041052 -1.944319 2.248876 -38.835568 -59.391948 49.535587 44.611476 -64.929157 1.159939 0.338259 0.875181 2.409770 2.497248 1.250396 1.899786 1.456109 1.079379 0.870353 2.275200 2.042832 0.378552 0.830509 0.871193
+1 -0.030498 1 1 1.450278 2.353178 -1.226464 -1.194109 0.677914 -0.861557 0.989590 2.010378 0.600223 -1.271756 1.001940 2.234045 -22.767707 -6.857128 -47.745832 35.802417 -68.783786 1.388700 2.123947 2.436166 0.641499 1.177846 2.063138 1.916437 2.311237 2.466664 2.474678 2.164241 2.398186 1.317731 1.861558 2.463649
+1 -0.008133 1 1 0.901678 -0.537545 -0.871829 -2.004251 -1.296192 0.273899 -0.583912 2.104645 1.570571 -2.218267 2.007374 1.946260 66.878221 72.253593 -33.858767 35.709019 11.479375 1.882915 1.398338 2.111830 1.271506 1.196722 2.056609 2.426760 2.312096 1.149483 2.361313 0.340245 0.490020 2.264959 0.908964 0.960615
+1 0.003650 1 1 -2.331489 -1.816953 -1.254174 -0.392145 1.858007 -1.483635 -2.201889 -0.759687 -2.199665 -1.071897 0.093367 -0.001169 -25.268010 -29.450783 20.686666 -19.198441 -18.195771 1.880204 0.837628 1.263688 0.308187 1.692675 1.297925 1.982200 0.577898 0.977860 2.389881 1.233197 0.844170 0.967759 1.370612 1.873152
+1 0.013477 1 1 -0.877266 0.852372 0.158423 0.117250 0.848149 -0.140551 -1.329407 -1.913547 1.068113 2.285390 -0.131145 1.251866 -22.656072 69.400637 16.509785 -20.039028 -45.947065 0.890218 0.895718 1.084456 0.708164 1.111423 1.692421 1.525655 2.187101 1.861210 1.105870 0.611172 2.214126 1.558504 0.777818 1.779649
+1 -0.055818 1 1 -1.379805 -0.719625 1.965112 -1.496671 0.186663 -1.211127 2.103224 1.249185 1.359163 -2.208080 -1.128248 0.180256 -16.228758 -56.743993 3.706581 46.505624 -29.972020 0.778821 0.639826 2.309126 0.730217 0.513959 1.861560 2.496279 0.718773 1.670303 1.023857 1.463506 1.650550 2.046606 0.813789 1.109924
+1 0.047312 1 1 -2.234961 -0.531287 0.636463 -0.085215 0.362569 0.571408 -0.202306 2.185906 0.737655 -0.525459 -0.369631 -1.455656 48.249090 22.453418 -25.403277 -52.874092 -54.857631 2.241956 1.297867 0.994580 2.159990 0.697745 1.506421 0.669549 2.360748 2.098833 1.083409 1.110578 0.993437 0.942170 1.048013 2.453355
+1 -0.032836 1 1 1.151109 2.336657 -0.863816 0.715504 -0.547575 0.199564 -1.143958 0.037396 1.760217 -0.416564 1.418891 -2.100754 -68.513569 42.438383 11.899382 42.914609 65.835655 0.622848 0.448934 2.478521 1.503805 1.699050 0.432513 0.997411 2.479730 1.578988 0.794849 2.277123 0.602468 2.171264 1.182351 1.274738
+1 -0.047745 1 1 0.636841 1.545726 -0.382594 2.161325 2.292622 -1.108060 0.196920 1.542176 1.218339 1.302609 -0.818552 -1.934401 -22.566203 -70.168402 -20.335105 -72.115037 -37.429322 1.755788 2.271449 1.991161 0.450366 1.794947 1.174239 2.183631 2.039458 2.177828 1.252414 2.070288 0.579834 2.024464 2.166627 1.991886
+1 0.070222 1 1 0.120157 -2.131232 -0.751998 -0.207748 0.260805 0.820769 1.494989 -0.173385 -1.827235 0.296861 -1.081613 1.723131 -53.665693 -9.306967 27.805714 -69.356453 -23.897303 2.245418 0.996529 1.162060 2.236043 0.921633 2.388364 0.492300 2.329569 2.325189 0.697143 0.377428 2.188374 0.752092 1.406321 1.282393
+1 -0.052171 1 1 -1.172445 1.926590 1.380713 1.849084 -0.654243 -1.851525 2.029145 0.274886 1.861900 -2.019122 -1.470567 0.659672 -36.669134 51.856955 59.836653 74.628664 -16.048554 0.954294 2.312448 0.307625 1.250658 1.809180 1.891909 1.818016 1.886642 1.035485 1.141067 0.421178 1.739439 1.994658 0.719042 1.688381
+1 -0.006548 1 1 -0.703035 -1.942534 -0.740918 2.238061 0.803178 -1.977146 1.879725 0.685663 2.143368 2.079258 -0.978482 0.886115 56.924256 25.976441 -63.954389 18.578648 -48.655538 2.070612 1.525819 0.442997 1.696780 0.530172 2.102801 0.275052 0.547306 2.075003 1.072968 1.116815 2.311130 0.655192 1.817079 1.895379
+1 -0.007899 1 1 -1.153736 0.640100 -0.227693 -0.372294 0.913893 2.129487 -0.299254 -1.448551 -1.593026 1.809461 -2.152168 0.812882 28.572108 61.415906 67.124897 18.147486 54.805465 0.856850 0.331956 0.679064 0.282493 1.852716 2.350389 1.230464 2.154684 1.519516 2.498712 1.099345 1.197286 0.276925 0.523263 0.732330
+1 -0.002948 1 1 -2.055620 -2.279220 0.160402 0.384815 2.180915 1.669231 1.915077 1.086622 2.352988 0.296612 -0.542703 1.969852 -61.745430 -55.443755 -43.197205 -15.429063 33.730380 2.222411 1.310222 1.650765 1.159213 1.650454 0.431919 2.259451 0.592382 1.417138 0.842377 2.324916 0.616850 0.899602 1.113021 1.536860
+1 0.000227 1 1 0.388717 1.800290 -0.770072 2.329509 1.530654 0.764001 -0.699015 -0.363086 0.152798 -0.172804 -1.486394 -1.456870 -1.120812 62.518714 2.023291 -44.552551 5.281445 0.853616 2.224135 1.036112 0.429741 1.662296 1.453192 1.551638 2.387060 1.065584 0.761569 0.946682 0.389640 0.427802 0.559835 1.141253
+1 0.000001 1 1 0.690844 -0.313535 -1.124862 0.552530 -1.739011 -1.324023 -0.960774 1.634147 1.307726 0.369676 2.210386 2.203683 -66.356408 -2.151771 -14.813948 21.975984 50.356892 2.099157 2.029130 1.839711 2.021911 2.001014 1.798847 1.477509 0.738691 1.182293 0.291662 0.711849 2.298053 1.385971 1.270852 1.467797
+1 0.005058 1 1 0.498783 -0.297470 0.270320 0.520568 -1.723660 2.214031 2.188849 -1.630646 0.981839 -1.017080 -2.231091 -1.463059 -12.492081 45.589072 15.539155 16.570058 -57.043489 2.426279 0.962385 1.055436 1.206536 0.508476 1.957266 2.264829 0.974245 2.384362 0.716291 0.459468 1.777734 2.130932 0.576886 1.969254
+1 0.028741 1 1 -1.179598 -0.478921 -0.466333 -0.953736 2.109755 -2.073048 1.686680 -1.703921 -0.609570 -0.311041 -1.626277 -0.976415 -65.742617 -36.165535 -34.151265 69.694521 5.808515 0.980580 0.859040 1.129628 1.665040 0.323051 1.768400 0.505919 1.734318 1.425954 0.516091 1.691160 0.579973 2.103509 0.931231 1.701915
+1 -0.062824 1 1 0.109232 -1.961891 -0.910399 0.055779 -0.295677 2.125982 2.038780 2.000958 -2.216202 -0.988843 1.117183 2.336156 4.511000 66.372252 -31.554058 70.939966 -61.986967 0.400665 1.227515 2.086689 1.732707 1.353704 1.199476 1.093017 0.583423 1.590014 1.622350 0.578894 1.970618 1.674496 1.747737 1.969803
+1 0.000052 1 1 -1.557331 -1.454263 1.371628 -0.051669 -1.323193 -1.134169 -0.372053 0.251580 1.291648 -1.249004 1.681593 2.337938 58.053916 -37.826191 -44.792718 18.793150 -43.528933 0.763312 0.992234 0.980919 2.063565 2.333224 0.739209 0.889121 0.449433 1.877186 1.861168 0.404825 1.396683 1.306291 0.837600 0.785718
+1 0.030077 1 1 0.047497 1.890035 -0.401484 0.393229 2.231771 -1.240993 -0.333907 0.478584 -0.490314 1.253015 -0.249706 1.936020 -11.328252 -43.929845 -28.903915 61.896852 50.395902 0.683757 0.400635 0.726371 1.110385 2.246012 1.974469 1.148155 0.284178 0.937274 2.015315 1.405419 1.872361 1.777966 1.515797 0.751471
+1 -0.008156 1 1 1.315737 -1.652389 -1.598607 2.256360 2.054474 1.878903 0.999280 -0.060149 2.246813 1.811973 -2.341202 -0.126705 14.745784 32.387953 -5.668860 -26.528282 -60.827333 0.250265 2.451868 1.291376 2.158720 1.860554 1.338082 1.889740 1.353758 2.107748 2.415060 1.408978 0.949112 0.725361 2.144605 0.877702
+1 0.031041 1 1 1.618552 -1.613710 -1.825804 0.793652 -1.861202 -0.381142 -1.721496 0.879040 0.683975 2.046998 -1.250538 -0.532262 -51.486435 17.487188 57.176253 61.278777 12.401590 0.377906 1.216538 2.110564 0.256143 2.249318 1.283545 1.046018 0.425524 0.533806 2.423439 0.496575 2.185800 2.489276 2.269503 0.781019
+1 -0.041920 1 1 -1.770450 -1.920834 1.123043 1.864576 0.548617 -1.530879 0.162269 -1.215417 0.687459 -0.648744 1.025472 1.900378 -29.558100 17.005171 55.916730 42.479985 -38.888092 0.742450 1.355256 0.292489 1.118695 2.404752 1.417396 0.665908 1.909642 0.609497 1.065293 0.383943 1.433862 0.673590 0.520745 1.167654
+1 -0.004290 1 1 -1.409006 -1.411085 1.353483 1.292638 1.260021 -0.294413 -0.196513 0.584665 1.133006 -0.329250 -1.353322 1.412612 24.136983 70.269717 73.129222 -17.165751 -54.773254 1.013904 0.684320 0.859523 2.494818 0.907948 1.876254 1.945467 1.969077 0.530978 2.153163 0.717038 1.761910 1.665199 0.749916 0.835386
+1 0.016672 1 1 -0.009349 -1.624822 -0.093296 1.199835 1.310543 0.588649 2.120700 -1.903934 -2.291069 -1.071897 0.098936 -0.650508 -10.807463 8.974705 -62.135406 -9.772870 -2.635213 0.774491 2.128582 1.575600 2.353017 0.414388 2.368402 2.478074 0.741488 0.943500 0.912884 1.598656 0.609638 1.177409 1.461472 1.204181
+1 -0.011072 1 1 1.768610 -0.719137 0.739400 0.523802 0.801101 0.806379 -0.016958 -2.263284 -0.607223 1.434298 -2.341338 2.287082 0.848880 17.132082 -61.089679 15.760961 -5.520518 2.374927 1.904040 0.957265 0.505556 2.384850 2.180956 2.080548 2.013483 2.115838 1.144823 0.541912 1.422837 2.119386 2.274085 1.297647
+1 -0.002339 1 1 -0.107989 -0.696737 0.231937 1.022927 1.535608 -0.796837 0.169765 2.242706 -1.245698 0.694807 0.319476 2.017986 39.280646 39.813381 -6.511045 68.867369 53.868714 0.947040 1.905621 0.526329 0.514505 2.033310 2.340587 0.740472 1.865179 0.314066 1.500321 1.650948 1.984331 0.399327 1.236102 2.422661
+1 0.010001 1 1 -1.950471 -2.182639 2.332832 0.836185 1.424573 -0.845158 -1.423415 1.458905 1.249471 1.458551 0.016844 0.356984 30.549483 -4.839155 -31.675715 -23.745178 64.787681 1.923242 1.932503 2.325180 0.543396 1.600465 1.760721 1.934913 2.327134 1.883917 2.495959 2.088383 0.952857 0.660810 1.736638 2.174230
+1 0.038184 1 1 1.145680 0.620596 1.840249 1.656655 -2.099872 -1.469328 -2.076996 1.308185 -1.348876 0.746222 2.092788 0.207530 25.071734 30.639662 10.802994 65.915629 -56.017404 2.357436 0.434787 0.967847 0.601750 1.366673 0.926666 1.471510 1.165763 1.480361 1.424671 1.440100 2.008945 2.331671 1.649031 1.263006
+1 -0.000288 1 1 -0.586262 0.300555 -0.257627 0.741991 1.660526 1.694022 -0.831923 -0.475131 1.971229 2.352310 -1.666767 1.807373 14.312638 -47.500768 -45.409146 8.481881 54.968345 1.419697 1.091140 0.541185 0.439159 2.450264 1.332072 2.129695 2.280618 0.850911 1.756631 0.704374 0.409106 1.337333 0.552731 0.996767
+1 0.009852 1 1 0.837208 -0.236014 1.144915 1.902115 0.002942 2.324080 -0.185628 -0.251078 -2.272545 -0.746243 2.269823 2.128011 -49.203089 -6.317336 24.525064 -7.254100 30.346377 1.848370 1.309209 0.370447 1.847418 1.057363 2.103813 1.544224 1.516407 1.997214 0.918623 1.288304 2.284484 0.571822 2.367760 0.694085
+1 0.061714 1 1 -1.636598 -0.092629 -1.725945 1.502242 -0.795433 0.211962 -0.114481 -1.423553 -0.855888 2.014127 2.342396 1.351016 70.929815 67.393879 38.917032 -71.439144 72.312432 2.200743 1.643361 0.471856 0.729967 0.804519 0.551825 1.529118 1.890043 1.946975 0.309133 1.852019 1.886556 1.847190 1.718283 1.925289
+1 0.049041 1 1 -0.975924 1.465384 1.768611 -0.701803 -0.095822 1.157625 -1.246140 -2.018219 -0.437220 -1.740352 -0.294241 -2.008994 -28.677950 -40.303463 19.703111 -49.811017 -23.755887 1.897093 1.200147 1.115401 1.044872 1.419316 1.441223 0.626268 1.693099 1.673347 0.450077 1.437325 0.372005 1.044784 2.192140 1.038706
+1 -0.035189 1 1 -2.236861 0.509904 -1.874635 0.039267 0.221576 1.238357 -1.554634 1.466243 2.060320 1.170511 -1.440752 2.253078 -40.637039 -36.715725 18.806405 29.250233 58.667882 0.341494 1.246948 2.453061 1.088684 2.005351 0.438200 2.070205 1.430509 0.561211 1.768538 0.568236 0.586900 1.529608 1.114868 1.086988
+1 -0.008525 1 1 0.916412 2.048220 0.426596 2.258101 -1.677067 -1.674993 0.208287 -0.631544 -2.056534 1.205054 -0.507619 -2.130317 15.523894 60.080762 -22.628521 -67.556139 -66.023618 1.990690 1.521747 1.748486 1.057411 0.652397 2.081281 0.844470 1.510050 0.905610 0.836279 1.099511 1.730370 0.324771 1.420454 0.324518
+1 -0.032290 1 1 1.447358 0.390291 -0.026126 -0.845377 -0.395022 0.619535 -1.860841 0.973044 1.965050 2.175197 -0.169673 -0.706690 -67.478107 45.452427 -31.065077 39.251059 -7.451817 1.484695 2.277554 1.099588 0.768862 2.015637 2.313772 2.324324 1.918828 1.999587 0.305130 2.076011 2.266454 1.299735 0.902072 2.124746
+1 0.002316 1 1 -1.423726 0.944976 1.452659 -0.044690 -1.834628 -1.432212 -0.304953 1.740118 1.072213 0.502437 -0.136566 -0.323900 -31.121095 -2.244728 72.863915 23.824149 62.465151 1.401845 0.314347 1.737583 2.316422 1.857829 0.530929 1.331072 1.073349 0.784360 1.482029 2.463339 0.588755 1.202385 0.478474 1.709728
+1 -0.048055 1 1 -0.589485 -2.038695 -0.569647 1.509438 2.341058 -2.281285 -1.564659 -2.087641 1.470402 1.277799 1.608249 -0.424845 -35.225541 14.329903 -57.328345 -67.491503 -29.691086 1.853831 0.838988 1.624121 1.110463 1.308541 0.400767 0.694319 2.413203 1.699591 0.534618 0.319826 1.558569 1.861003 2.122604 2.350878
+1 -0.033525 1 1 -1.800530 1.454772 -2.229453 -2.218786 -2.006220 -1.395469 -0.083745 1.503854 -1.985469 -1.349939 1.731225 -2.296849 24.007167 -11.551027 -38.104422 -71.017436 -40.048129 0.791508 2.380969 2.193386 1.746786 1.728136 1.031026 0.450211 1.439805 1.552429 2.167947 1.681333 1.912620 1.160199 2.458261 0.748408
+1 0.011811 1 1 -1.902598 1.303097 -2.038769 -1.802982 -2.049232 1.409987 -0.957394 1.879220 1.615590 0.438338 1.678367 -0.046307 -23.293221 10.828458 43.895154 45.850754 63.616275 1.355924 0.269459 1.049244 0.645270 1.554215 0.698195 2.316706 2.120202 2.485397 2.314246 1.283900 0.263010 0.663267 0.276962 1.144996
+1 0.030992 1 1 0.672693 0.926068 -0.595215 0.621765 -2.071112 1.241853 0.647118 -0.083460 1.585944 1.694534 -1.650212 2.006900 -41.896514 -54.703314 -48.591537 72.044803 57.001917 1.093282 0.536294 1.501112 1.437452 0.261328 1.636098 2.145751 2.134967 0.891951 0.767589 0.872026 1.139518 1.385747 2.003037 2.039487
+1 0.061520 1 1 1.306309 0.119470 0.453068 -0.511950 0.470992 -0.853792 -0.459045 -0.989377 1.561057 -1.897118 -0.836636 0.425090 16.033520 -74.623325 -44.217818 -68.866061 -31.894617 2.082676 1.790326 2.253302 0.744082 1.792302 1.716948 1.986511 1.042601 1.494593 2.131423 2.079270 0.786703 0.372394 0.827388 2.415831
+1 0.000150 1 1 1.633230 0.032772 -0.548059 1.491810 -1.778189 -0.049249 1.650464 2.231858 0.230149 -0.754105 2.084081 -0.042108 -27.265336 1.499139 -3.970139 23.875422 24.220018 0.862525 1.210783 2.130186 1.531312 0.506198 1.921481 1.585162 1.071020 2.138606 1.298664 0.891706 1.157853 1.287943 0.706359 2.280372
+1 0.022493 1 1 -0.703801 -0.686905 0.534180 0.855897 -1.864870 -0.771151 -1.658551 -1.488085 -1.603544 -0.620244 -0.632295 -0.549341 -38.166393 -62.568266 65.145755 54.710867 25.545420 2.003170 2.029165 2.427493 1.121529 0.538626 2.435043 2.012148 2.175722 1.862343 2.148777 1.239993 0.304944 1.196622 0.368790 1.000445
+1 -0.038165 1 1 -0.238779 1.795962 1.880694 -1.876294 0.441085 0.720323 0.349521 -1.956602 -1.564157 1.630021 -2.064244 -1.141915 44.277811 27.170475 54.176700 47.802586 18.070382 0.758547 1.894186 1.825396 2.182790 1.408094 1.830832 1.293309 0.899573 0.627866 1.542258 2.222427 1.579610 2.247202 1.722206 0.367320
+1 0.008298 1 1 -2.065043 -0.429505 0.686538 -1.993145 1.589053 2.101557 1.506872 1.623818 2.060327 1.274995 1.606061 0.508918 12.736522 12.721813 65.512635 70.859893 -57.770684 1.346609 1.213140 1.241178 2.228493 2.286209 0.309475 0.848032 0.621966 1.385172 1.338701 1.055448 1.406033 0.939580 0.275830 2.371354
+1 -0.045336 1 1 1.394883 -0.340262 2.051365 1.457423 -0.097609 -0.606756 -0.144143 -0.450012 0.030254 -0.452740 1.312112 -1.311418 -37.037479 11.097128 59.424163 41.903204 17.148283 2.292787 0.619624 0.262540 1.756396 1.241130 1.416457 0.635693 0.345863 0.415619 0.558098 1.196356 0.403979 0.678452 1.238500 2.226123
+1 0.048861 1 1 -0.218133 0.083085 1.534266 0.210891 0.725654 0.405129 -0.392646 -1.858844 1.550703 -1.557252 -0.116924 -0.081032 -0.956462 -25.253477 64.817636 -59.984487 -9.267678 0.447088 0.704332 1.950876 0.621155 1.249211 2.235042 2.096534 0.694681 1.754165 1.995899 1.316077 1.059471 1.537908 1.115793 0.886186
+1 -0.002988 1 1 -2.173013 -0.817530 1.093096 -1.939323 1.385455 1.437424 -1.632076 0.506402 0.518278 2.208084 1.204002 0.661456 18.228527 66.849639 41.879266 64.819683 -25.581724 0.594468 0.478513 2.374093 1.374634 1.968804 0.444787 0.278729 1.604173 1.089141 0.693022 0.863661 2.304880 1.364794 0.847641 0.810166
+1 -0.003616 1 1 1.441446 -0.003540 1.762010 1.456432 2.101882 2.257687 0.794887 0.043340 -2.010992 -1.486938 -1.172321 -0.702360 -0.872024 43.896583 69.865185 24.165413 -51.901091 0.600431 1.694113 0.710780 2.329721 0.375654 1.613081 2.295431 2.302015 0.472187 1.794920 0.728969 2.038482 1.508060 1.216547 2.259592
+1 0.034157 1 1 1.202485 -1.276862 0.004571 1.425882 2.298139 2.089027 -1.739221 -0.139182 -1.878853 -0.167173 -1.091672 2.311384 -48.035421 -31.315666 27.607446 48.348871 49.473344 2.102427 0.740440 1.328623 0.412155 0.838445 1.494529 1.044452 1.104910 2.474826 2.404834 0.550045 0.855019 1.051691 1.264378 0.655674
+1 -0.019350 1 1 1.157434 0.257943 -0.150833 0.210342 0.928622 -0.081004 0.448150 1.652185 -1.834415 2.156926 -0.950886 -1.826501 -47.637152 62.379563 63.323367 25.827365 -19.473374 1.540064 1.362206 2.343631 2.408908 1.524668 1.336028 1.120943 1.942281 2.408202 0.900801 1.018062 0.816914 1.870156 0.717139 1.203233
+1 -0.000309 1 1 0.290673 -1.405401 -2.084906 0.312722 1.607430 -0.048273 -0.789011 -0.238570 0.592532 1.408406 0.749306 2.088072 33.918975 -73.794692 -67.392511 -15.925116 -53.423739 1.483343 2.040633 1.660914 0.738389 0.599852 0.967811 2.243418 1.131708 0.608380 0.284731 1.217550 1.111246 0.967219 1.303955 2.068264
+1 -0.002877 1 1 1.860270 -1.145044 0.636883 2.250262 -1.483564 -1.003186 0.376895 1.024467 -0.852357 0.096903 -1.832054 -0.585925 39.703365 -55.545958 39.077139 69.482616 44.319006 0.917907 0.504845 1.680827 2.402964 0.616808 2.446708 2.322730 2.117268 0.430450 2.328266 0.661574 1.073400 1.632231 2.411192 1.654820
+1 0.051999 1 1 -0.416422 -0.902325 -0.910903 1.009900 -0.639821 0.203419 -2.332901 -1.995241 -0.661487 -1.079668 1.434273 1.953006 -74.324216 32.899818 47.245280 -48.585089 30.404407 0.728061 0.278905 2.298330 1.533320 0.514448 1.069551 2.198510 2.362084 2.041309 1.774533 2.318719 2.209296 1.385934 0.641671 1.816164
+1 0.010572 1 1 -2.310690 -0.971846 -0.667974 -1.726452 -2.306626 1.358719 -0.252126 -1.036604 -0.503080 -1.242694 -0.645956 0.763260 31.607800 -67.703386 9.193897 21.826999 -53.632429 0.621452 1.742072 1.260254 1.095348 1.516280 2.111149 1.079913 0.855409 0.851340 2.227373 1.453857 1.474653 2.246098 1.163010 2.464380
+1 -0.055255 1 1 1.798461 1.466576 -1.756164 -2.157595 -0.859622 0.520384 -0.098755 -1.018359 -0.165213 -1.139587 -1.889325 -1.810097 27.975216 -70.536520 -57.284273 73.221519 34.076595 1.754979 2.175461 1.966755 1.995635 1.389144 0.597488 1.737744 0.514559 0.694522 1.337954 1.984727 0.312064 1.604367 2.089947 2.485047
+1 0.006026 1 1 2.032532 0.664753 -0.575880 0.436341 1.109560 1.445281 -1.524964 0.609836 0.062126 -2.005692 -1.952272 0.527081 -20.513379 -68.363810 9.450391 -17.284374 51.527658 0.255297 1.520080 0.740740 1.864557 1.105585 0.311150 1.997128 1.735927 1.480807 2.174203 1.078672 2.497279 1.775435 1.743842 1.744754
+1 -0.029838 1 1 1.637170 0.276283 1.790947 -2.293122 2.135021 -1.544183 -1.954365 -1.659839 0.428130 -0.244969 1.434150 -0.115238 -0.467408 -55.729688 -48.866941 -56.671115 28.572893 2.494238 2.406376 1.706258 2.336769 1.835190 0.280411 0.610810 0.630965 1.872487 1.645963 1.449522 0.619481 2.361807 1.888536 1.375250
+1 0.051697 1 1 -0.417447 0.717841 1.031910 1.720846 2.321540 -0.460704 -0.591026 0.341893 1.799670 -1.771634 1.729521 2.042417 59.082127 -6.698065 -74.385271 56.743065 -19.308448 0.368706 1.836433 0.935609 1.037857 0.513805 1.518146 1.983845 1.227664 2.349400 0.360355 0.981632 0.534881 2.493959 2.212908 1.343362
+1 0.031930 1 1 1.646955 -0.197338 0.867818 0.577822 -0.774288 2.167511 -2.124488 -0.498370 -2.192483 1.826307 -1.766767 -1.291063 52.818066 13.229187 42.953183 -35.856873 53.536468 0.436198 2.177367 0.254432 0.481746 0.461645 2.367599 2.492672 0.846028 0.691973 1.233446 0.522970 0.307053 0.642937 0.586616 1.247935
+1 -0.039524 1 1 -1.342137 0.907722 2.080683 -0.593034 -0.424006 -1.128680 -2.352017 1.875211 0.216047 -2.145568 -1.364125 -1.077349 -64.066507 -65.780583 -74.252552 37.366308 -34.466169 1.781391 0.590983 0.408365 2.383961 0.736357 2.457755 1.233152 2.339240 0.615599 2.370134 2.346089 0.963813 0.300332 2.437356 0.388215
+1 0.010248 1 1 0.183652 0.025299 1.092055 -0.588388 2.263959 -2.181618 0.641450 -1.104125 0.365490 -2.173227 0.307896 0.611494 -11.094489 -15.079172 64.358194 18.167807 -53.673303 1.567035 2.407145 1.136103 2.489454 0.754020 2.315572 1.070956 1.060968 1.933116 1.389176 1.130576 1.835530 1.504376 2.304271 2.378754
+1 -0.007350 1 1 0.529069 -0.216819 -1.408705 -1.064300 0.541192 0.895278 0.272761 -0.866689 -0.454075 -2.279177 0.880427 0.442484 21.826448 -62.887893 -56.824798 -4.382537 -7.295721 0.337324 0.899273 2.336702 0.698701 1.816465 0.584059 1.034020 1.276833 0.730379 0.971429 2.307066 2.112650 1.562711 1.733947 1.952694
+1 -0.028176 1 1 -1.024361 -2.085913 2.229890 0.128143 0.142706 -0.139018 0.862393 -1.066394 -1.672319 -1.984640 -1.554056 1.746746 -19.614148 45.020472 59.066837 36.326622 41.533052 0.565168 0.775036 2.281278 0.691162 1.103560 2.275518 0.636771 0.458750 0.961768 1.935072 0.501322 0.964979 1.900697 1.022635 1.173824
+1 -0.032781 1 1 -1.684871 -0.875425 -1.191131 -1.112022 -0.411749 2.239643 -0.879181 1.654317 1.013706 2.071434 -0.534115 0.238617 6.401465 39.418503 -43.211914 37.362933 58.808306 1.993064 0.930354 0.466022 1.679910 0.493620 2.017080 1.811134 0.983998 2.053952 0.524270 1.898117 0.411383 1.370476 1.838394 2.383196
+1 -0.026770 1 1 -1.595865 1.211057 1.421084 1.774721 -1.688320 -2.293900 -1.528530 1.934531 -1.824048 2.027760 0.569595 2.323268 9.583382 -32.106184 -58.637364 -18.170345 11.018808 0.521478 2.224358 0.277637 1.239737 0.504059 1.966485 1.970143 0.438911 0.520601 0.990736 0.551883 0.250977 0.923730 1.626872 2.335890
+1 0.009633 1 1 1.130538 0.594931 -0.683608 -0.599282 -1.755306 -1.870348 1.408192 1.869791 -1.343786 1.473033 -1.628662 1.337991 3.113654 -18.813093 8.347060 39.041916 -72.517260 0.661144 0.601408 2.369586 2.137694 1.726697 1.595614 1.227899 1.798609 1.972865 1.194027 1.767400 1.690259 1.175207 0.447838 2.064479
+1 0.080583 1 1 -1.495371 -1.528293 1.208266 1.642764 0.043035 2.289185 -2.314728 1.845875 1.956225 -0.063391 -0.406662 -1.807932 -13.695915 62.760259 11.678421 -70.775868 -30.016159 0.901326 0.837449 0.501154 0.401237 1.836451 1.230495 0.434408 1.338937 0.517142 1.354200 0.531366 1.919972 0.964589 2.101259 1.361161
+1 -0.001751 1 1 -1.186082 -1.074257 -1.873589 -1.220868 -1.382473 1.560156 1.810802 1.535528 -2.133991 0.009323 1.175060 -0.393618 20.772448 72.530302 -33.206319 51.404429 -45.760121 0.769655 1.842537 2.273063 2.117966 0.901133 2.089989 0.941533 1.601155 2.103348 0.475346 0.892811 1.728213 2.329538 1.792330 2.196837
+1 -0.040754 1 1 1.242614 -0.687547 -0.818894 1.732494 0.181596 -1.537632 -0.248877 1.721723 -1.774957 -2.277446 1.696269 -0.755519 59.916631 68.820498 16.102385 32.788685 -20.572920 1.088997 0.523676 0.916057 0.920643 1.496138 1.093458 1.254294 2.175163 1.460492 0.494845 2.355117 1.952201 0.400058 2.267677 1.603047
+1 -0.071762 1 1 0.070834 -1.728799 0.664702 -1.421005 -0.451545 -2.170066 1.597147 1.485096 -1.509583 -0.066902 1.834966 -2.315785 -56.379070 -13.029231 17.711300 73.814466 -50.271284 1.982839 2.325454 0.646774 2.081882 1.932873 1.803371 1.006164 1.104545 0.836442 1.588185 2.367037 2.039561 1.652468 0.531138 0.337002
+1 0.056041 1 1 1.526383 -0.322380 1.003254 0.769400 0.511740 0.706363 1.339199 1.542271 -1.909425 -0.334450 0.775524 -0.230551 -40.997805 49.891564 27.511935 -56.901293 59.976654 1.789463 1.259537 0.289807 1.028753 0.501874 1.247614 2.405272 1.149440 1.638432 0.885327 1.943337 2.160186 1.746272 2.100110 2.294359
+1 0.032469 1 1 -1.779458 2.186760 0.955197 -1.115330 0.536534 -1.987934 -0.375711 0.029564 2.083246 0.070102 0.107298 -1.484940 -18.402757 4.864214 2.845124 -31.993017 43.361721 0.331710 1.057935 0.462274 1.697109 1.565084 1.119452 1.620679 1.747717 1.624467 2.410748 0.942743 1.683856 1.574077 1.517769 2.395982
+1 -0.018452 1 1 0.691157 0.241222 1.557494 -0.512049 -1.180166 -0.602976 2.131474 0.111408 1.611862 -0.967702 -1.720058 1.493039 1.020125 45.233985 47.580799 40.487316 70.323566 0.297553 0.716174 0.728577 2.188751 0.334759 0.549908 0.800820 1.386679 1.912346 1.041747 0.635065 1.030405 1.269306 2.474030 0.273962
+1 -0.027301 1 1 0.946722 -2.187676 -2.218091 0.258181 -0.864264 -2.094815 -1.288650 -0.198086 -2.290760 -0.583305 -1.831156 0.377459 34.230634 64.262770 64.376870 32.050607 24.550410 0.905998 0.614058 1.230157 1.489480 1.683555 1.003999 0.707854 0.406158 1.297407 2.276199 0.830247 0.967786 1.829018 2.304479 1.373273
+1 -0.027265 1 1 -1.905767 -0.124642 2.156300 -2.046162 1.166615 -0.952398 1.025573 -1.110769 1.781460 -1.528369 -0.065674 -1.082307 -16.486051 -31.061496 -50.567292 15.523889 59.998585 0.568371 0.603820 2.397250 1.329850 0.785675 1.088959 2.136218 1.663213 1.117150 1.192893 0.701971 0.528568 2.141172 1.679303 1.552589
+1 0.007984 1 1 -0.101679 1.681428 -0.439562 1.301567 0.523126 -1.131224 2.001060 -0.501941 -0.951470 -2.223991 0.059044 -1.960187 -17.336790 70.566881 -32.424320 -5.551013 4.118771 2.487658 2.069567 1.958275 1.232810 1.087558 1.081061 2.146096 1.183649 0.593791 0.340489 2.343170 1.409993 2.250245 1.111904 0.770050
+1 0.053570 1 1 1.769263 0.827303 -1.774172 1.487159 0.166315 0.803946 1.499825 0.994380 -2.306606 1.702522 0.668021 -2.201443 64.465929 28.871903 0.068827 -43.217817 -61.858603 1.261913 1.979054 1.716729 0.569210 1.204104 2.374805 2.091319 0.792053 0.289036 1.576756 1.531480 1.087919 0.410912 2.441628 2.444453
+1 0.004350 1 1 1.235383 0.300396 1.790191 -0.870201 1.786262 -0.920088 2.149282 -2.187113 -2.172998 -0.560249 -0.755998 -1.455231 -24.401536 -16.608143 16.941965 43.605672 -19.462959 1.915668 0.639563 2.389431 0.407804 1.959817 2.397036 2.231119 1.415509 0.455201 2.059244 1.716147 2.030394 0.578659 0.279280 1.856116
+1 -0.001448 1 1 -1.509449 2.186373 -0.838352 -0.135057 1.473091 -0.658437 -1.656295 -1.272493 -1.962239 -2.057610 1.977291 0.562048 -63.474385 -13.990527 61.207784 19.219160 66.421462 2.057674 2.327050 0.482884 1.574584 1.029433 0.678815 0.600188 2.117377 2.255781 1.906403 2.418560 1.741031 1.752670 1.629041 0.538332
+1 -0.013878 1 1 -0.670542 2.229123 1.375031 0.595700 -1.890923 -0.392321 -1.113118 0.004477 -0.150850 -0.074637 -0.920939 1.981493 15.829638 -51.275840 -43.036140 -8.405332 31.582279 0.675422 2.073427 1.589450 1.131660 2.056644 0.770829 1.319443 1.377070 2.408227 1.320168 2.306017 2.483597 1.314163 0.383597 2.357533
+1 0.004710 1 1 0.947302 -1.865534 2.203017 0.871522 1.565043 -0.877743 2.258469 -0.206485 -2.072865 0.045474 0.870137 1.850274 15.964607 -32.841842 27.168216 16.206287 -20.930369 0.974338 1.703846 2.291250 1.789570 0.807890 0.957188 1.464194 1.952500 0.919386 0.620805 2.120160 1.771655 1.212581 0.845332 2.496929
+1 -0.007493 1 1 0.535555 0.406767 -1.142103 -1.769443 0.857275 -2.268083 -1.157934 0.776726 1.119228 -0.992395 -2.039858 -1.259074 66.252534 56.334537 14.565755 6.649421 6.825129 0.774212 1.933600 0.510142 0.698371 0.775461 0.415241 0.949650 0.767295 0.421620 2.423922 1.856904 0.743741 0.561574 1.124838 2.145723
+1 -0.015147 1 1 2.023834 0.552090 0.283808 1.020190 -2.056683 -1.300855 2.006190 0.889278 -1.594536 -0.010248 2.112418 0.264518 62.668531 -29.992666 63.256981 -39.924490 -60.895096 1.166731 1.998882 1.959897 1.489043 1.094496 0.699119 2.089947 2.489361 1.445224 0.388348 1.208823 0.682230 1.733715 0.295377 2.398514
+1 -0.020249 1 1 -2.323084 -1.936487 1.940119 -2.153814 1.421455 -1.427107 0.679803 -2.097774 0.806032 -1.134479 -0.869939 1.486488 -53.487938 -21.770117 -40.362870 71.249357 37.943946 2.483528 2.410540 1.950549 1.871831 1.867767 1.065716 0.742936 0.521038 1.578544 2.343602 1.910934 2.071168 1.869489 0.745012 1.661690
+1 -0.007875 1 1 0.582592 -0.722613 -1.123011 -1.323239 -1.907414 0.470211 0.151747 1.015191 -1.239106 -1.609071 0.747867 1.457882 -57.092907 -10.481162 -56.890348 -56.077450 -43.696159 1.354778 1.258479 0.501494 1.617754 2.088822 1.580920 1.767142 1.852570 2.138622 1.565163 2.450699 1.902482 1.762910 0.479944 1.669106
+1 -0.038745 1 1 2.109278 -0.667505 1.448692 -0.755962 -0.845590 0.739662 0.213259 -1.886713 -0.315075 1.251596 -0.528715 1.446275 33.066969 6.555744 -67.611053 61.030264 35.650280 2.488729 2.077062 1.933685 1.939614 0.345184 0.265250 2.309199 1.953221 1.779499 0.288444 0.626445 2.406662 2.015472 1.794899 0.366217
+1 -0.006832 1 1 1.776387 -1.964337 0.390078 1.102731 -0.228925 -2.238184 1.844434 1.302948 0.175050 1.540301 -2.019840 0.606584 62.220243 -64.382003 31.683629 6.756672 9.383149 2.163742 0.766303 1.760270 1.112495 1.710025 0.382118 2.258179 1.715482 2.108946 2.310064 0.741819 1.997994 0.537081 1.218799 1.852678
+1 -0.029773 1 1 0.551536 0.391992 0.288468 -0.771406 -1.233825 2.335377 1.186461 -1.979236 -0.258696 1.627194 2.260109 -0.907185 70.807753 -34.089642 55.392009 73.502878 -37.125442 1.865322 0.470592 1.989029 0.603667 2.084071 0.480775 2.136827 0.648178 0.935746 1.075415 1.746595 0.764363 0.642929 0.464336 0.351533
+1 0.008778 1 1 -0.894760 -0.990402 -1.520950 2.100142 1.300628 -1.108761 -2.155995 -2.243836 1.095765 0.512204 -0.915929 1.352967 65.045737 23.710058 -55.048928 -7.339236 -50.544410 0.626464 0.477099 1.100017 1.232507 0.493231 2.234194 1.352082 0.942415 0.675957 2.060103 0.393912 2.476502 1.322526 1.447791 0.768899
+1 0.006373 1 1 0.496331 0.907374 0.952134 -0.753828 2.018463 -0.173681 -2.096091 0.823329 2.115122 -1.400090 -2.352226 -1.633453 29.755748 4.855390 4.533470 -5.962777 -16.395205 1.311773 0.722823 2.242464 0.838533 0.723572 1.318731 0.659909 2.344057 0.572895 2.394996 1.690680 1.513614 2.307746 2.288535 1.157684
+1 0.045328 1 1 -1.864397 -2.241789 -2.194319 -0.755577 0.906284 1.466684 0.058892 0.201925 0.838377 0.556163 -1.951563 -1.690365 32.802460 60.952214 73.858441 -61.190060 -21.338546 1.570956 0.804959 1.194980 2.023190 1.001937 2.053484 1.648461 0.685767 0.430368 0.945669 1.360343 0.281688 1.823238 1.916990 0.348663
+1 -0.021959 1 1 -0.717034 -1.616085 0.665446 1.654775 -0.715135 2.025497 0.232037 -2.009058 -1.969273 2.244045 -2.299712 -0.237716 25.959195 -53.806323 27.133430 31.555372 -48.856691 0.858803 1.655695 0.774657 0.403443 0.660115 1.297916 1.829949 2.207536 1.059724 1.289540 0.545744 0.571639 1.535317 0.325842 1.430521
+1 -0.006144 1 1 -1.147933 -0.796837 0.171646 0.868701 1.279536 -2.174299 1.125903 -1.907818 -1.596810 -0.530035 -1.881611 0.605323 -12.340394 45.004597 -57.740352 57.898591 51.615166 2.066407 0.604979 1.623839 0.862125 1.234212 2.156837 1.708117 2.069401 1.416915 1.583753 2.137738 2.466359 1.850433 2.231294 2.113927
+1 0.000422 1 1 1.376697 0.325105 -2.335713 -2.124815 -1.289975 1.083150 0.547042 0.260796 0.668303 -2.167556 1.370384 -2.108307 -59.514549 -61.020260 -17.517563 32.323377 -41.008226 1.746114 1.690079 0.415156 1.771251 1.174043 1.138661 0.479695 1.975637 0.533685 0.401624 1.596497 0.329397 0.430759 0.761185 1.233318
+1 0.031819 1 1 -0.714005 2.177274 1.743553 2.264313 -0.945893 1.974744 0.171794 -1.356293 -1.384926 -1.960592 2.066012 -2.126661 21.676367 -35.307140 -7.098870 -60.712691 51.810681 1.856826 1.673940 1.403786 1.432428 1.316064 0.829617 1.621723 1.304184 1.425799 2.399538 1.537255 1.391729 1.283492 2.391392 1.867206
+1 -0.054201 1 1 -1.121970 2.037441 -1.665752 0.000257 -0.385983 1.739261 0.807390 -1.883303 0.436851 0.258004 0.877996 1.992276 -65.530848 73.033587 25.493271 65.409954 -4.899139 1.527675 2.389194 0.937217 1.051838 1.498703 1.445765 0.465500 1.905885 0.452399 2.224447 1.777987 1.875644 0.694548 1.760701 1.597007
+1 -0.001658 1 1 0.322045 -1.933016 -0.983548 0.576796 0.833966 1.816778 -1.698732 1.784441 1.460802 0.157274 -0.350485 -0.117819 -31.118775 36.756418 65.123569 -18.173757 -46.332435 0.486458 0.904046 1.549123 0.614576 0.924517 1.357555 0.669613 1.187453 1.528499 0.480005 0.443828 2.163356 1.033270 2.164044 1.337914
+1 -0.016814 1 1 -0.114974 -0.290043 -2.143445 1.336988 2.090481 -0.855217 -0.846964 1.201810 1.530199 -2.166992 1.426726 2.346545 12.875146 -57.418147 73.201012 -10.596707 -48.857918 0.549619 0.439606 0.958601 0.450656 2.174017 2.455781 1.808863 1.067464 0.865564 0.529339 1.604422 0.768152 1.333836 0.287330 2.151897
+1 -0.034450 1 1 1.341160 1.527032 1.158634 1.561990 -0.358797 1.548278 0.095659 0.812706 -2.066720 -0.338446 -0.404688 -1.611732 -50.115671 -44.077363 41.752783 39.031831 57.978843 2.131257 1.533683 2.107241 0.645701 2.041615 2.425861 0.688181 0.515773 0.840741 1.836487 1.831044 0.355043 1.707731 2.326365 2.465395
+1 -0.006167 1 1 1.957711 1.342441 -0.510484 1.554079 -1.368459 1.479002 -0.265528 -0.091306 1.655823 -1.943921 -0.487478 1.800375 21.066659 67.344274 -44.782649 38.024689 -69.051466 1.405060 0.339211 1.118415 2.201951 1.695687 2.411545 0.829233 1.921866 1.296642 0.662178 2.226130 0.817518 0.770791 0.683183 1.999507
+1 -0.025158 1 1 0.402747 1.983720 0.226510 -0.651753 2.285908 -0.849191 1.470574 -0.534350 0.988966 0.948000 0.444083 -0.727836 19.545825 6.687978 54.849678 -41.463601 21.258527 1.255953 0.805963 2.327538 1.934429 0.955446 1.431761 1.351438 1.367044 0.409700 2.323285 2.450636 0.845852 2.227671 1.961000 2.023445
+1 0.054511 1 1 -2.346393 2.148706 2.265647 -2.086466 -2.346876 -1.243925 2.230785 1.038714 -1.735640 -1.213898 -2.051390 -1.878012 -5.433400 30.849508 -62.327442 62.688014 -2.547159 0.473360 1.258743 0.434679 1.395545 2.428737 1.778947 2.256636 0.531992 1.185120 0.553116 0.715414 1.465844 0.446688 0.728571 2.091688
+1 0.028999 1 1 2.074132 -2.320909 1.644605 -2.000100 -2.207465 -0.223388 1.288802 -1.950675 -0.898624 0.025127 -1.800588 0.486981 -23.430506 -46.515117 20.423265 53.819309 41.133052 0.973046 2.476679 2.042234 1.579964 1.452801 1.723814 0.388028 0.338241 0.564517 1.083038 1.621786 2.362734 1.720681 1.730688 1.166861
+1 -0.011939 1 1 -1.443740 -0.840503 1.405693 2.267903 -1.875778 -0.323580 -0.303927 0.125779 -1.893327 1.608781 -0.898556 1.175369 2.766009 -11.680632 33.616658 -54.825056 5.288745 0.444143 0.715773 0.739732 0.681266 1.283518 0.585041 1.784034 2.252526 1.201344 0.989908 2.380246 1.287859 1.548247 1.633067 0.713966
+1 0.007511 1 1 1.777705 1.347395 -2.067708 1.907810 1.469755 -0.165891 1.597289 -0.839550 -1.417786 1.816967 1.490212 -0.353147 71.967118 -48.647787 26.636223 -74.999533 -67.150934 1.288716 2.448664 1.453260 0.433936 2.412520 1.465684 2.251368 1.995481 1.052580 0.463503 2.090193 2.127184 0.585545 1.250107 1.544858
+1 0.011311 1 1 1.696725 2.195647 -0.473510 0.942067 -0.303658 -0.054722 -0.800669 1.733122 1.314196 0.729416 -2.335946 -1.331132 66.248268 -15.367136 24.542792 -9.290135 10.709006 1.168953 1.100597 1.986086 0.652669 2.155657 2.129729 0.597780 2.131342 0.713120 1.162134 1.235266 1.871648 1.031979 0.715069 2.420895
+1 -0.017163 1 1 1.523130 1.540180 0.648168 -1.290965 -1.410975 -1.523638 -0.670479 -1.416413 1.344861 -2.254564 -0.136189 1.294132 -60.574220 -20.915503 73.148015 -1.306010 -50.104256 1.341433 1.966583 1.358638 0.881201 2.339533 1.033092 1.436447 1.365650 1.734641 2.358820 1.194406 1.387892 2.055976 0.784156 0.314921
+1 -0.003472 1 1 -0.454095 2.088523 -0.779125 0.973376 -1.878468 1.593478 1.077311 1.375075 1.327565 -0.779422 0.701017 1.022621 35.101393 -0.887688 -69.371131 29.401842 56.754489 1.715555 1.090120 1.401054 0.520659 1.958897 0.433965 0.657359 2.238299 0.597976 0.932035 1.709892 0.400716 2.091904 1.626354 0.379221
+1 0.010179 1 1 1.658575 1.887210 -0.743492 1.377981 -1.668634 -1.302424 -0.797539 -2.196169 1.129375 -0.089701 0.359164 -0.092853 -25.014227 35.880157 37.805083 -9.969557 -8.345670 1.139779 1.271263 1.617045 1.426286 1.584742 0.767215 1.340144 0.544639 2.240255 1.972748 1.469775 1.255345 1.836300 0.948203 1.199214
+1 -0.028079 1 1 0.526035 0.626752 1.630334 -1.525347 -1.104382 0.749205 0.377794 1.999358 -0.836783 -2.035050 -0.571462 -0.709242 67.224689 45.348202 17.226781 30.509731 -72.952428 1.203111 1.442429 0.653624 2.461475 0.763833 0.744177 1.138271 0.665781 2.035024 1.894803 0.955181 1.476618 1.511497 0.487497 0.354065
+1 -0.024757 1 1 -0.926449 -1.089055 -0.836242 2.341194 -0.004996 0.849424 -2.273847 0.933860 -1.578413 -2.345539 -2.339429 1.392455 40.455138 -20.497725 44.741898 27.081519 59.096380 0.367977 0.841380 1.326312 2.073508 0.697886 1.625739 1.294727 2.226865 1.911183 1.756219 0.524591 0.557088 2.221947 0.265258 2.440881
+1 0.032588 1 1 -0.144885 1.228862 -0.920513 -0.295472 0.853769 0.068071 -1.046809 2.340704 1.190031 1.470529 -1.303169 0.815872 -22.106203 11.038077 -33.042419 -43.933904 52.877537 0.816498 1.624075 0.325633 2.416262 1.360156 1.644427 0.381443 2.167647 1.138743 1.846302 0.295167 1.123725 1.438397 0.397233 2.051937
+1 0.009968 1 1 -1.106939 0.196600 0.877331 0.231041 0.096350 -1.710298 0.595140 -1.884051 2.012975 1.831768 0.486611 -2.232527 -65.048866 73.706132 -71.042048 -3.699528 72.038043 0.525815 0.878185 1.149472 2.173598 2.156396 1.046367 1.791544 2.486775 0.724531 1.693454 0.885585 1.778613 1.150248 1.713607 2.084986
+1 -0.007087 1 1 2.153963 1.076784 1.929887 0.231172 2.298693 1.960743 0.462321 -0.505075 -1.777755 -2.184075 1.755456 -0.316622 -37.317686 -48.351702 52.941548 -11.400822 -63.615492 1.591371 1.916642 1.255323 1.465906 1.475073 0.293933 0.631025 0.630446 2.147698 1.108968 0.919971 1.454313 2.392143 1.001373 1.569362
+1 -0.041014 1 1 1.221197 2.196244 0.132062 0.028289 -0.506026 1.084633 1.906551 -0.839517 -0.871912 1.302385 0.144230 1.911639 -4.850741 73.589739 72.740912 56.501622 -27.235516 2.165210 0.680725 1.187136 0.699634 1.741587 2.108420 2.459632 1.280057 0.919502 0.317358 0.587098 0.349477 0.412105 2.247511 2.423615
+1 -0.001449 1 1 -1.363376 2.080086 -1.217600 1.705754 -1.570688 0.255835 2.112634 -0.811489 -1.033778 -0.124376 1.919924 -2.271790 -70.217060 61.875831 -2.904799 -70.953464 -14.874042 2.304628 1.633888 1.012638 1.906507 1.918382 1.242588 1.179508 0.740199 1.770464 1.444980 0.783260 1.008186 1.328632 0.566518 0.974009
+1 0.044778 1 1 0.296409 0.744557 -2.339085 -2.252090 -0.977240 -1.796927 0.742226 0.901769 0.991352 -1.347745 0.910981 0.311764 -11.407487 -25.626098 -47.822305 -49.481510 -35.734040 1.644953 2.481171 1.041008 1.712756 1.287513 2.477817 0.920599 0.752778 1.687034 0.977384 1.147657 0.929132 2.422889 2.486902 0.613096
+1 0.014290 1 1 -1.896728 1.010980 -1.335567 -1.764559 -1.877998 0.064715 -0.888921 -1.822491 -0.086179 -1.713918 1.016733 1.103242 -33.664919 -6.286549 -58.037663 10.993870 -26.018827 0.648551 0.451128 1.105753 0.887166 1.345511 0.756113 1.498293 1.313193 2.082304 2.290704 1.607185 2.203729 2.317856 1.213788 0.881616
+1 -0.033236 1 1 2.025996 -0.803370 -1.237430 -1.715510 -2.172364 0.664516 0.158278 -2.327916 1.678396 0.437866 -1.541919 -1.607587 67.734938 71.094666 -11.954008 -61.013465 -53.302269 0.606480 2.104030 0.688580 0.468993 2.121099 1.811203 2.135173 2.098557 0.944407 0.402035 1.744759 1.412974 0.595709 1.085251 0.569156
+1 -0.012254 1 1 0.136585 0.654205 1.224771 1.018962 0.870953 1.435161 -1.969598 1.506323 1.808640 -1.802666 -1.455345 2.026400 40.225607 21.774516 -35.716681 9.736545 -7.895548 2.117900 2.037396 1.256394 1.459454 1.050143 2.262053 1.574116 2.173417 1.375531 1.295033 0.618754 1.396073 2.302677 0.347339 0.484615
+1 -0.040210 1 1 1.302239 -2.323175 1.246710 2.169566 -0.567973 1.372352 -2.030127 2.071170 -0.264288 1.900459 0.435334 -1.678322 25.320542 12.356804 -69.191996 40.124310 -30.716721 2.036148 0.532976 1.983277 0.683512 0.792519 1.370610 1.837528 1.331214 1.222181 2.438537 2.235815 1.595337 1.076817 0.561489 1.947372
+1 0.048440 1 1 -0.630486 1.585546 -0.281207 0.288215 -0.309466 1.277842 2.325140 -1.218761 1.043398 1.587119 -2.132960 -1.513994 38.296411 -2.222955 -11.203624 -49.315204 59.371565 2.243282 1.085662 0.722859 0.584542 2.402397 2.338505 1.753849 1.183762 2.489682 2.330440 1.198840 1.652551 1.916904 1.161037 0.796061
+1 0.010510 1 1 1.211447 -1.439374 1.851525 -2.044192 1.292372 1.498168 1.410028 -0.268459 -2.239962 0.236833 -1.519828 2.111883 22.166105 -54.278588 39.765123 -67.575692 55.345180 1.921561 0.676042 1.242956 0.615050 2.137791 1.103341 0.856808 1.871472 0.330003 1.614640 1.499753 1.091001 0.451310 1.909140 1.171370
+1 -0.039893 1 1 1.896643 2.282601 0.116425 1.120164 0.602943 2.029361 -0.807059 -1.977512 0.436508 -0.796525 0.699958 2.077992 41.489900 -29.243192 59.673865 38.641105 -58.946813 1.838637 1.963119 1.644057 0.915860 2.112255 1.664836 1.405943 1.679915 0.577070 0.571630 1.391784 2.205692 1.567813 1.981334 1.773099
+1 0.006864 1 1 -0.405885 1.834118 2.280596 -0.599205 -0.460418 -0.495548 -1.876992 -1.871225 0.813101 -0.143166 1.841896 1.056234 17.634993 -8.676621 -27.961839 -4.634588 -43.521959 0.271446 0.686923 1.860609 2.261163 2.364162 0.973484 0.847557 1.646876 1.050210 1.126371 0.924392 1.509192 2.231314 2.444296 2.277703
+1 -0.008150 1 1 2.182416 -1.376873 1.433604 0.135786 1.354629 1.699410 0.190408 0.469159 1.331149 -1.792584 -1.655390 -0.192085 -12.522481 -15.333922 -17.230855 51.025191 30.381752 1.766510 2.487260 2.129483 0.964095 0.541627 1.127675 0.337355 1.432413 1.072368 2.288854 2.022102 0.721039 1.502752 2.003134 1.423756
+1 -0.022367 1 1 0.411592 -0.161952 1.838108 -1.338620 -1.240487 -1.251037 0.504177 0.829713 1.035217 0.756667 -1.427952 0.610264 -68.826475 33.436382 65.278262 31.755894 21.310960 0.974556 0.861110 2.182534 1.595533 2.129200 0.720423 2.396705 1.163418 0.321295 1.501077 0.844106 2.138342 1.363102 1.659312 0.802822
+1 -0.026304 1 1 0.155717 1.760615 1.560578 -0.526906 -1.136833 1.986137 -1.555188 1.576123 1.567697 1.314659 -0.912349 0.260437 -20.359038 -24.353242 45.064613 50.950293 -28.429481 0.410782 0.268549 1.497775 1.596645 0.554600 0.913557 1.650606 0.737966 2.494716 1.445880 2.412986 0.308704 1.386156 2.117999 1.462659
+1 -0.029124 1 1 -0.668854 2.326045 -0.134481 1.723794 0.046031 0.806616 -0.753143 -0.604451 0.905437 1.377857 0.963931 -0.409364 -3.026622 -18.439666 -15.473771 32.335537 13.376233 0.840214 1.984804 1.606121 2.318601 2.468649 2.085097 1.983464 1.581797 0.755289 1.140049 1.306159 0.859931 0.362968 2.149884 1.849727
+1 -0.050370 1 1 -0.634420 1.431766 2.240327 1.187981 -0.001455 -0.890218 -0.065602 0.126132 -0.672650 -0.203055 -0.974959 -1.155508 -27.496531 15.808936 50.784914 42.055043 19.104247 0.401085 1.531865 0.809912 1.190203 0.496001 1.545096 0.433588 1.065799 2.134901 2.023001 2.329827 2.156802 1.127520 2.221472 1.274989
+1 0.032405 1 1 -0.501496 1.813152 -1.366612 -0.462194 -2.074013 -0.388626 -0.272720 1.541241 -0.365197 -2.332636 -2.242718 1.031420 -57.298757 -20.207522 -27.824474 54.071950 -62.744266 0.731920 2.132978 1.214704 0.530078 0.513471 0.403147 2.441008 1.022775 1.282189 0.753750 2.284498 0.801395 2.048584 0.303902 1.680268
+1 0.073596 1 1 -1.473700 -0.153484 -1.925190 -1.408073 0.127863 0.138803 0.234156 0.612651 0.252037 -0.454417 1.399852 -1.641127 -25.568595 18.623555 -43.905531 -70.258262 -30.609930 1.958631 0.459593 1.629073 1.086475 0.888967 2.371762 0.453012 1.270165 1.158663 1.394479 0.260820 2.102176 1.019448 1.619112 2.421538
+1 -0.009717 1 1 -0.202385 0.858931 2.011803 0.984897 -1.461711 -1.291675 0.801749 2.282672 1.310666 -2.060143 1.809023 -0.091583 54.697725 -45.334286 66.652133 22.405356 66.817977 0.771161 2.404084 1.434826 1.120071 0.783516 0.808508 2.338047 0.811582 2.262734 1.775781 0.803864 0.794849 2.277140 0.898428 1.621376
+1 0.014384 1 1 -1.098422 1.959247 -1.114454 1.117795 -1.514376 -0.507744 0.475582 0.900938 1.163752 -1.940523 0.075840 2.294727 41.001024 4.207822 70.871715 -9.089300 -63.872240 2.113891 2.156876 2.363554 1.997429 2.284734 0.271014 2.428762 2.196077 1.957669 2.284454 2.319851 0.981335 2.302127 2.349799 0.328367
+1 0.011253 1 1 -0.053213 1.004841 -0.844656 2.295869 1.636032 -0.008007 2.092415 -1.335376 1.441866 2.341009 1.604308 -0.688789 59.531386 44.005729 -45.715646 -42.863715 39.545808 1.320866 0.539590 0.638057 1.826088 0.308118 0.546291 0.754447 0.492519 1.517861 1.698034 1.350406 2.017187 1.357321 1.248297 0.375620
+1 -0.025671 1 1 -0.560605 -2.030374 -2.089216 -1.450534 -1.935311 -1.858571 1.427220 1.219711 0.788863 -2.236175 -2.086935 -0.808635 -6.226490 51.374964 59.026755 -37.324199 -7.812477 0.560589 0.313332 0.427629 2.153908 1.976284 2.409437 1.409508 0.853675 0.968234 0.367308 0.851063 2.058065 2.148113 1.333266 1.958928
+1 -0.003263 1 1 -1.008913 -1.616651 0.580079 -0.539258 -1.393656 2.111885 0.738118 -2.172793 -1.836298 -1.218413 2.174676 0.493457 -8.421347 62.426005 -56.133652 61.706464 0.542176 0.810308 1.090209 0.635169 0.531424 0.646145 0.508482 2.058590 1.968803 0.418549 0.298295 1.937331 2.464574 1.090858 0.302989 2.087804
+1 0.012376 1 1 1.638859 0.385082 1.955124 0.271845 -2.123203 2.251518 0.784697 -1.569607 -0.426745 -0.048597 -1.529499 -0.208009 18.487103 62.732702 -1.471633 16.266727 -55.113815 0.656759 1.145089 0.507568 2.450911 0.965783 1.911509 0.488409 2.186932 1.267462 0.725744 1.828227 0.260103 1.302146 0.917409 1.144886
+1 -0.030527 1 1 -1.575694 0.941526 0.017809 -2.280136 -1.091317 -1.151155 1.610085 2.162165 2.269848 -2.170242 -1.367524 -1.649113 51.874769 59.242235 -15.748131 71.157339 -8.600230 2.213964 1.097107 1.833227 1.038308 1.341435 1.989422 0.468788 0.926432 2.045281 1.031083 1.414093 1.403602 0.581601 2.465557 1.861950
+1 -0.022914 1 1 1.171112 -0.765881 2.090944 2.207956 -0.939626 -1.086181 0.345803 1.527033 1.173644 -0.625125 2.145206 -0.003966 -21.515242 43.327559 -43.711911 33.917901 58.163961 1.550474 0.815292 1.619382 2.457807 2.119888 1.702175 1.204209 1.888731 2.406855 0.758583 0.252394 2.238642 1.850293 2.121133 2.387961
+1 0.000514 1 1 -0.081012 0.309920 1.635079 -1.875636 2.059406 -0.063099 -0.219719 1.692678 0.145636 1.975559 -0.267624 -2.335502 45.119916 -69.570528 -21.865128 12.796009 -37.470862 0.283272 1.452139 1.848098 1.227613 1.491579 0.963779 1.976885 1.249196 1.991751 1.362852 1.947635 2.406164 0.393556 1.000811 1.130532
+1 -0.000890 1 1 1.025370 0.190432 0.871493 1.075412 -2.271081 0.296902 -0.390982 -2.156953 0.506545 -1.789181 -1.014770 -1.096352 -30.274818 -28.868897 50.442951 -5.320617 -23.611684 2.251346 1.616775 1.386319 0.355370 0.448285 0.569717 0.728957 1.831695 2.299506 1.051626 2.420469 2.323065 1.012080 1.533606 0.822728
+1 -0.010600 1 1 -1.886171 -0.635989 -1.362299 1.336247 -0.948492 0.702926 0.113352 1.307919 -1.093728 0.749116 -1.117357 -0.554433 -62.599883 -16.229890 74.239103 36.612061 38.913489 1.660074 2.361743 0.820143 2.138715 0.888733 0.688383 1.658562 1.708435 0.660698 2.103109 0.948215 1.407198 0.270329 2.161643 1.482223
+1 -0.023764 1 1 1.608063 1.165539 -0.189160 1.646525 2.005091 1.275373 -1.470371 -0.758663 0.870024 -0.043966 0.914646 0.641361 67.754358 -52.505822 -15.345718 -65.490789 -3.685388 1.520175 2.325456 0.694936 1.532545 0.989125 0.471620 1.272552 0.774638 2.337249 0.901936 2.087294 0.655969 1.378377 1.889638 1.890000
+1 0.007651 1 1 1.445003 -1.482914 0.493317 2.094270 1.565564 -1.545005 -1.634220 2.178816 -0.619443 -1.313615 -0.380388 1.531239 37.336495 64.470887 -37.794874 31.552529 53.351585 1.076254 2.347196 1.569198 0.506414 1.046045 0.878683 0.519046 1.855003 0.277189 0.457997 1.804604 1.473348 0.566423 1.623726 1.217062
+1 -0.068514 1 1 1.665999 -0.573835 1.809705 1.959315 0.024133 0.338345 -1.290506 1.598094 -1.455774 -0.475078 -1.845618 2.355004 38.210204 48.905957 -37.578536 67.543595 5.196492 1.936602 1.469010 1.898720 1.535393 1.594964 1.565362 1.280236 1.681772 0.284908 1.941643 0.687465 1.979003 0.846599 1.296577 1.821086
+1 0.024591 1 1 -0.632543 -0.000916 -1.250373 2.239263 2.160444 1.627346 0.100321 -0.938320 2.015071 -0.633032 1.203148 0.439305 -29.328827 -29.594268 9.132245 35.642318 -59.554105 1.737444 2.221229 1.697883 1.068219 2.307753 2.405549 1.312039 0.683408 1.284051 0.552681 2.405711 1.776323 0.915443 1.843757 0.266221
+1 -0.047230 1 1 -1.698766 1.211607 1.249096 -0.134255 0.809474 0.161477 -0.384251 -2.129699 1.448469 0.221794 0.193478 0.239507 32.339415 -71.455155 -46.798057 65.050475 -46.673461 2.262088 2.158940 1.051752 2.294330 1.811478 2.267378 1.066532 0.949863 2.093591 0.738717 1.615024 1.213275 1.263521 2.001823 1.885679
+1 -0.020199 1 1 1.242514 2.336398 -0.495997 0.001844 -1.994064 0.267703 -1.052383 -1.810565 -2.272599 -1.658972 0.869391 -1.267329 -0.222815 5.143942 54.233577 -46.278411 -51.255582 1.336604 1.804684 0.574266 0.685572 1.663996 0.774983 1.389999 1.470541 0.636060 2.010520 1.804624 1.808172 0.700307 1.802818 0.707680
+1 -0.029486 1 1 -1.016436 -0.838554 1.173115 -0.093585 1.047191 -0.634305 -1.339950 -0.029103 0.962040 0.799377 0.108962 -1.797949 -72.829309 -42.200865 -69.932171 49.993760 -54.883327 0.263923 0.254287 0.301800 2.346107 1.265954 2.382413 1.708622 1.555883 1.726914 0.747947 1.500376 0.323219 2.344592 0.563902 2.005623
+1 0.001871 1 1 1.668276 -0.006030 2.326934 0.667217 -1.566151 1.106282 -1.801755 -0.287161 -0.834715 -0.267429 0.933104 -0.146973 -27.977800 27.123649 17.173443 34.056265 -16.358374 1.597033 0.325441 1.435953 2.065598 0.503408 2.280105 1.221898 2.196203 1.833854 0.339590 0.739929 1.733350 0.911131 1.382470 0.915732
+1 -0.047396 1 1 0.514857 1.257074 2.004478 0.397362 1.000188 1.062340 -0.497997 -0.638070 1.359598 0.383719 -2.090206 0.759173 -55.029682 16.131258 68.046667 60.328431 -60.055070 1.441633 0.771801 1.902872 1.570942 0.569910 1.720588 2.428548 0.862525 1.205042 2.397218 0.794808 1.586326 0.386713 0.728599 0.313794
+1 -0.023577 1 1 -1.829106 1.835428 0.736140 2.287632 -0.150852 -0.101560 -1.027370 -0.807700 1.370997 -1.234279 -0.599009 -1.878384 -54.104218 -29.594949 -2.310298 20.819164 -42.315420 0.696063 2.486137 1.258707 2.094502 0.295364 2.175897 0.295811 0.695222 1.843450 1.859417 2.463398 1.572571 0.942928 0.284402 2.439224
+1 -0.000629 1 1 -0.411378 -0.962184 1.488941 1.850443 -1.364120 -0.997576 0.419995 -0.302655 -2.048860 -1.768827 1.785739 -0.291588 5.389616 -16.723486 28.374170 34.672864 -3.174436 2.083750 1.843059 2.050011 1.788550 1.662354 2.428961 1.038451 1.491815 0.438081 2.332428 0.871156 2.271256 0.994106 0.947825 1.597440
+1 0.061583 1 1 0.697625 0.553865 1.847225 1.099082 -0.295119 2.074299 0.489194 -1.228870 0.789254 -0.378343 -1.793144 -1.650583 15.531275 34.131454 47.351774 -58.737485 -50.905086 1.948412 1.967832 2.102975 0.957886 1.939191 2.224429 1.476779 1.979445 1.529216 1.287061 1.633916 1.482261 1.864369 2.454641 0.658417
+1 0.013750 1 1 -1.643075 -0.563861 -0.189574 -0.593725 2.110321 -1.989931 -0.943854 -1.458585 -0.590674 1.544721 1.569832 -0.495468 -17.141319 55.848167 -59.865233 45.031054 -63.083618 0.679593 2.411751 2.051036 1.012184 1.023285 0.851312 1.754140 1.574190 1.165439 0.527896 2.092849 1.768740 1.708349 1.468670 0.686799
+1 -0.051729 1 1 -1.915143 -2.190762 -2.250736 -1.767518 0.223912 -1.901775 0.996745 -0.245493 2.055015 1.541246 -0.286456 1.593622 -38.783511 65.535872 11.409024 51.471899 38.213869 0.782463 1.103946 2.012919 1.631083 1.111101 0.779859 2.339247 0.719476 2.238312 0.806629 2.262351 2.086683 1.627896 1.549645 0.383001
+1 -0.010726 1 1 2.046273 0.696239 0.828364 1.918841 -1.631071 -1.436693 -0.222277 1.119199 -1.477231 1.750020 -2.142956 0.127467 -57.380916 -51.053765 -60.629292 -46.510063 -44.635193 0.869777 1.593943 2.391210 1.066971 1.574069 1.384678 2.030126 0.579563 1.973121 0.997079 1.400619 2.202679 0.418165 0.600092 0.500030
+1 0.005860 1 1 1.540198 0.947087 -0.754823 -0.557390 0.169614 -0.300748 1.713581 -1.969766 -1.319012 -1.562302 -0.185927 -0.563084 -40.461161 69.267551 29.737364 -4.121451 30.772256 1.214538 2.244686 2.194862 1.791287 0.411694 2.095323 0.590954 2.157168 0.519777 0.649327 2.232631 2.085652 2.302428 0.651899 0.463098
+1 0.019204 1 1 -1.142273 0.094265 0.957384 -2.056433 -1.799713 1.052789 -0.801315 0.298062 0.265769 -0.572888 -1.119658 -1.531063 56.478976 42.149364 -45.647442 53.443851 30.799999 1.458683 1.580590 0.719516 0.652782 1.812149 2.287613 1.420858 0.365503 2.013003 0.791485 1.983209 1.798380 0.367496 1.752481 0.701719
+1 0.007282 1 1 1.453350 2.135917 -0.614729 -2.195875 1.364706 1.420292 -2.108272 -1.271902 -1.464581 2.308523 2.240635 1.652932 41.158620 -47.067071 43.739735 -16.266902 52.175404 1.555303 0.974638 2.239551 1.387199 1.660820 1.394973 1.815222 2.185534 0.275822 2.236431 0.698620 0.450809 2.496371 2.250028 1.966050
+1 -0.046021 1 1 0.483253 -2.133612 1.667998 0.036020 2.210416 -2.013027 2.005105 1.513549 0.749333 -2.176288 0.693555 -1.877937 34.877880 -7.465103 -65.994412 -68.077488 21.662579 1.869575 2.199314 2.362136 0.675508 1.269224 1.091205 1.625250 2.080115 1.493665 2.275770 0.367201 1.302833 1.212403 2.363456 0.356380
+1 -0.007417 1 1 0.878952 -0.792884 0.637106 1.296405 -1.408214 -2.236018 0.541566 -2.231018 -0.236548 1.589969 -1.345283 -0.130149 -27.342836 48.961590 -2.551244 21.245962 -69.113416 1.537168 2.184926 1.306722 1.327817 0.366987 2.204665 2.312958 2.133281 1.802216 1.840416 0.364150 1.774779 1.951770 2.144450 0.517348
+1 0.007067 1 1 -0.293392 -1.883175 -2.124533 -1.257416 1.675363 1.293165 0.691379 -0.737419 -0.220980 -0.645841 -2.018709 0.761643 66.362764 -41.025332 37.238093 60.627189 11.158745 2.050346 0.658322 0.410357 2.114194 0.517579 1.953242 2.145579 1.501369 1.254292 2.131245 1.336194 1.665579 0.389902 0.328849 2.460583
+1 0.017233 1 1 1.920811 -1.504281 -0.479681 0.901783 1.217912 -1.175118 -0.580517 -2.102108 -1.352034 -0.492723 -1.525579 -0.301221 -48.060881 -9.234144 51.734036 -56.050126 -34.464768 2.134581 1.161171 0.804246 0.461777 2.339439 1.702655 0.274354 2.315899 2.073626 0.424815 2.123717 0.815705 1.812213 1.116203 1.018247
+1 0.010499 1 1 -0.746121 -0.386456 -1.492569 -1.561253 -1.400809 -0.296946 -0.347411 -0.284331 -0.384756 -1.199846 -1.496275 2.124268 48.235634 -53.705566 70.555861 -67.649828 9.347671 2.219488 1.679537 0.985176 1.594991 2.014681 1.996191 1.738924 2.347631 2.141510 0.603312 0.607464 0.648860 1.132533 0.974935 0.484896
+1 -0.020552 1 1 -0.968582 2.341808 0.887693 0.037813 -0.650479 0.147154 -0.789402 -2.103631 1.328839 1.785509 0.558560 0.639381 58.193878 64.506877 -32.922578 20.238966 -43.694855 1.683580 1.424034 1.992290 1.427096 1.706000 2.494256 0.455558 1.317055 1.739224 0.633108 1.889979 0.873105 1.279031 1.673452 2.199317
+1 0.006785 1 1 1.266547 0.995648 0.161365 -2.270377 -2.007288 -0.492009 1.039880 -0.981266 1.220872 1.446130 -1.398887 -0.987142 45.641778 1.364803 -11.763405 -7.552174 -29.395545 2.111005 0.916907 1.703413 1.757415 0.365323 1.241136 1.525723 1.067638 1.540667 2.494773 2.404691 0.390296 2.455627 1.478480 1.315446
+1 0.005343 1 1 0.956687 0.368394 -0.472969 0.612745 1.839059 0.500132 -1.179618 -0.821987 1.585887 0.739392 0.396674 -1.134540 -60.063997 4.409511 10.657335 17.824194 21.236299 2.402065 1.263902 1.643306 1.785744 1.745127 0.851931 0.909546 1.739851 2.181766 2.190430 1.550349 0.958917 1.269273 1.913701 1.326019
+1 0.001437 1 1 2.230498 0.929516 0.803418 2.055596 1.877107 -0.897910 -2.104026 -0.589957 -0.543863 1.327006 -0.744741 -0.760238 -64.748392 23.778118 38.825028 32.239732 53.168456 2.158586 1.848970 2.396326 1.558686 1.589798 2.492345 2.083726 1.437992 0.331595 1.362791 0.922138 1.878246 1.672584 1.115375 0.606647
+1 0.016950 1 1 -0.322864 2.305273 -0.536280 1.534441 -1.560320 0.139098 0.467495 1.637077 -1.285586 -0.535984 1.807648 0.370529 -73.113441 -17.596638 53.297873 -22.656412 63.678779 1.363493 1.478649 1.899122 1.548309 0.429801 0.419673 1.188246 1.357389 2.382778 1.100122 0.757457 1.579742 2.220820 1.574151 0.506955
+1 -0.029228 1 1 0.973439 -0.828174 1.278364 1.682219 -1.271135 2.012685 1.669646 -0.540318 -0.346767 1.117094 0.840561 -0.425583 20.318404 -58.576522 -45.611764 53.074436 -27.947173 0.503018 2.474028 2.483495 1.857150 0.360856 0.402907 0.654914 1.643510 0.717309 1.816792 1.572712 1.063689 0.428302 2.214522 1.466944
+1 -0.040577 1 1 -0.249239 0.351088 0.825514 1.138909 -0.079402 -0.896123 -0.338685 0.287167 0.930900 0.505648 1.982358 0.898806 -53.478925 -20.289958 -63.319580 37.820974 -42.887662 0.430881 0.564750 0.499318 1.039053 0.365736 1.432770 0.308836 1.358383 1.089102 2.293449 0.490321 0.574348 2.071145 1.482471 0.885619
+1 -0.046180 1 1 1.250584 1.302815 -2.062846 -1.199702 0.923776 -1.426129 -1.736031 1.631992 -1.927570 1.003219 0.169385 0.566991 31.036222 -74.221422 -39.435820 52.170764 -65.975060 0.732608 2.450160 1.842904 1.683951 0.921525 0.577245 1.253901 2.312947 1.951535 0.448815 0.484722 0.976124 2.470800 2.226805 0.912611
+1 -0.004651 1 1 -1.033048 -1.990199 -0.734512 1.513430 -1.264659 -2.249494 0.243830 -1.719620 -0.569169 0.127167 -2.131720 0.479209 18.943091 -73.477555 12.737099 22.422206 50.024149 1.463147 2.367030 1.921895 1.797592 0.632922 1.011593 2.345162 1.136123 0.572781 0.481302 1.985146 0.594737 0.500801 1.209602 0.281142
+1 -0.018928 1 1 -2.266709 -1.624102 -2.131206 -0.301572 2.011818 1.240039 -1.563412 0.016574 0.526606 0.792372 0.178048 0.082368 -34.500329 52.965164 -64.484157 -35.228475 -34.978572 0.852175 0.509456 0.428241 1.202443 1.460564 1.696189 1.839828 1.741356 0.465983 1.022236 1.228669 1.235040 0.314598 1.454737 0.506647
+1 0.009235 1 1 -1.755819 -1.066516 0.986357 -0.484841 -0.999721 2.064379 -1.292968 -2.083603 -1.346212 -1.600239 -1.618574 1.254269 63.024651 -44.683250 58.616035 -40.292238 58.362438 2.087423 0.563482 1.696395 0.808919 0.253830 1.625382 2.039100 0.652831 0.372354 2.408287 2.322825 1.473785 1.159338 1.493851 0.909491
+1 -0.042870 1 1 -0.868217 2.148389 1.651512 0.999901 0.958121 0.898784 -2.049305 0.188196 1.003687 -1.387001 0.854208 -1.979311 -48.564621 74.419120 62.155717 51.128575 -32.043355 0.584909 1.821703 0.860956 1.833485 0.875891 0.852259 1.921425 0.640791 0.530930 1.333502 1.415833 1.399812 2.142895 1.387566 1.075582
+1 0.005656 1 1 -2.063177 -2.057619 1.819920 -0.718506 1.927026 -0.722801 0.425292 -0.804501 -1.397542 -1.943089 -0.634430 1.267241 -47.199113 74.513251 -5.782087 20.466554 31.372292 1.736649 2.368954 0.510199 1.663222 1.267058 0.700572 1.755214 1.627857 0.898029 1.678298 0.406929 0.763246 2.121171 0.777955 1.834904
+1 0.016366 1 1 1.701654 0.203008 0.185929 0.592662 -1.116614 -2.197459 -1.700434 1.445764 1.885517 -0.937301 0.296766 2.032616 65.802911 -0.479695 37.768037 -32.599103 56.880374 1.951743 1.694672 1.106432 1.055725 1.571114 1.214919 1.890343 2.487452 0.860249 1.203614 0.885557 1.310046 0.949987 1.934065 1.586926
+1 -0.010696 1 1 -1.169514 -0.653997 2.268292 -0.043542 -1.383304 1.728241 -0.619437 -1.212008 1.441452 0.082946 -0.800996 0.959183 -2.911124 -27.259821 -55.804169 49.323297 -73.347702 0.552701 0.488650 1.742484 1.432553 1.164356 0.334076 0.314433 0.927129 0.252369 1.811668 0.957607 1.756077 0.386027 0.447604 0.383442
+1 -0.006352 1 1 0.931518 1.464022 -2.274948 1.264338 1.566466 -0.515456 -1.906092 -0.862217 -0.680697 1.206935 -1.883689 -1.330364 27.112696 -16.910980 27.164460 -46.921990 -67.883311 1.152998 0.686409 2.234045 1.089178 1.309207 0.346797 0.373107 1.556981 2.177777 0.404824 1.376485 1.590145 1.559164 0.624390 1.626226
+1 0.008245 1 1 2.077824 -1.520748 0.788762 0.776005 -1.578155 1.993572 0.883141 -1.070395 1.767249 -0.026557 1.340529 0.347446 27.846729 19.976064 37.714328 -35.282750 -47.181823 2.351413 0.451121 0.998371 0.622944 2.062688 1.096978 1.915412 0.833677 2.356648 0.677356 0.820848 0.499850 0.977602 0.311455 0.371584
+1 0.059052 1 1 -1.041514 1.795191 -1.649311 -1.704118 0.792279 -1.378289 1.198630 -0.089505 -1.054708 1.533666 -0.440893 -2.209875 53.316948 -2.057413 71.055386 -72.128995 27.981521 1.906247 2.045721 1.679397 0.874451 1.398305 1.553209 1.781686 1.044541 0.350805 2.482847 2.216993 0.257673 0.954133 1.870509 2.148860
+1 0.001743 1 1 -0.870744 2.092017 1.401494 -2.325341 -2.173065 -1.683162 -0.431011 -1.055832 1.492679 -1.294957 2.179953 -0.361560 71.431867 -44.605713 11.780476 -5.534302 -15.021794 1.055558 1.008675 0.551714 1.906489 1.613282 1.189224 2.039430 1.702781 2.388865 2.149540 0.569464 0.985496 2.477195 1.716009 1.970772
+1 0.032995 1 1 0.395465 2.116800 -1.473373 0.629676 -1.064069 -0.287233 -2.045219 -1.837986 -1.318876 0.726563 1.541964 -2.344835 2.414434 -70.604293 3.646770 -58.732418 34.251290 0.796584 2.190270 1.120332 0.665088 1.627471 1.149764 0.326652 1.535490 0.974109 2.352879 0.339710 0.501883 1.395814 2.454828 1.541821
+1 -0.023888 1 1 1.828769 1.928612 -2.340656 -0.374816 0.938770 0.832127 -0.804015 2.047017 -0.941218 0.445225 -0.383615 -0.870672 -45.000721 -27.116863 -53.118981 29.284124 28.279255 0.466530 1.227972 0.775821 1.972851 0.947673 1.286674 1.873729 2.265679 1.767122 1.526691 1.602430 1.042955 0.697181 1.023867 1.630830
+1 -0.023639 1 1 0.072997 1.641223 -2.289503 1.686136 -1.411701 0.419081 -1.520701 1.570527 1.749091 1.089126 2.025835 1.199491 7.609149 -63.037219 -16.534804 49.557557 -36.143162 2.003158 1.829528 1.878708 0.452069 1.176398 2.475159 1.246484 1.399891 1.211429 1.736233 2.109930 0.838076 2.043949 1.147000 1.126407
+1 -0.000731 1 1 -0.817721 -2.110526 -1.460683 1.853362 0.565352 1.698119 2.057903 -1.760364 -2.055526 -0.695075 -0.110023 -1.898789 -20.711858 45.805560 54.048355 -9.301700 -33.674527 1.108292 0.809787 1.336188 1.554535 1.565995 0.672735 1.903187 2.358865 1.951273 0.545655 1.318771 1.327127 2.269341 0.315625 0.715367
+1 -0.003331 1 1 -2.158807 2.330607 1.131356 0.213232 -2.338393 -0.047842 1.730465 -0.944186 -2.325317 -1.756347 -0.526420 2.323548 9.567922 8.065791 -38.242818 2.957836 62.356574 1.029179 0.919735 1.979148 1.034558 1.323926 2.473681 1.150457 0.737304 0.369493 1.572346 1.669459 0.352924 2.094338 2.039838 1.805487
+1 -0.008143 1 1 -0.398130 0.227559 -1.872794 -2.003942 -0.802400 0.920674 -1.721993 1.962908 -0.838555 1.158916 1.593222 1.480500 42.764327 -59.959887 -45.819373 13.796097 -28.992438 2.486514 0.838822 1.073886 0.797555 0.502286 1.426816 1.490609 0.411131 1.621133 0.383246 0.962299 1.863865 0.735187 0.791760 2.104866
+1 0.004056 1 1 0.856041 0.561082 0.607829 -0.683636 -1.071616 0.108667 -2.046409 1.727506 1.162888 -2.334798 -0.885046 2.044980 -69.770850 61.325907 54.520945 -16.474501 13.063767 0.815947 1.374034 0.893062 1.446722 0.808685 0.817159 1.486408 1.806431 0.677823 1.919169 0.968604 2.083825 0.842336 1.637906 1.032500
+1 -0.020582 1 1 -2.026387 -1.051696 0.309041 1.004250 -1.344453 -0.322870 2.196843 0.778018 -0.725844 1.119201 -1.442748 1.692679 5.434030 -20.261604 -36.775869 57.972117 -62.621868 2.338997 1.025286 0.729957 0.636438 1.613403 0.960317 2.305147 1.354593 0.386908 1.760080 2.418180 2.107754 0.269976 0.738797 0.716259
+1 -0.013247 1 1 1.073115 1.538108 -1.184696 -1.336327 -0.398435 -0.191918 -2.290344 1.701092 0.187641 1.096049 0.568700 1.410558 -25.005751 28.341992 -56.144905 22.589295 8.275706 1.971817 1.575416 1.523146 0.506309 1.533985 0.434909 0.764386 1.029701 0.680289 0.610950 0.741531 1.655534 0.306427 1.376362 1.775327
+1 -0.030837 1 1 -2.086171 -2.111102 -1.720422 0.080322 2.233774 -0.561432 -1.787900 1.661874 0.777906 2.098723 1.002514 -2.242097 65.234244 41.946817 0.157810 -47.691394 50.732767 2.359139 2.057152 0.303395 2.156824 1.484302 2.417504 1.993713 0.586605 1.076666 0.281028 1.992021 1.397554 2.434961 0.641614 0.857107
+1 0.031319 1 1 -1.761073 0.162104 0.729245 -0.506242 2.172073 -0.855479 -0.537490 0.050932 -1.648658 -0.140897 2.282794 -1.355424 -29.180791 58.437477 -41.327226 63.307812 64.389848 0.627626 2.003470 0.311278 1.897597 0.669935 2.105299 1.752914 1.231222 1.405565 2.080483 0.929541 0.296603 0.502206 2.321954 0.326414
+1 -0.069755 1 1 0.769600 -0.833829 0.485549 -1.232551 0.184599 1.805522 2.328807 -0.845681 -0.790674 0.076688 -2.297818 -1.392205 -56.722836 59.298842 35.640577 61.182709 47.796176 2.280030 2.211246 0.418133 2.317569 0.872965 1.175245 1.085014 1.081963 1.551038 1.298921 0.711663 1.412695 0.407859 0.633603 1.209859
+1 0.003522 1 1 0.715354 1.648357 -0.207400 1.389686 1.847889 -1.887847 -0.525899 1.662740 1.210353 -0.985456 1.494990 -0.162210 70.229768 1.711264 -38.780322 -30.880108 -1.970675 1.808063 1.108106 2.194978 1.493422 0.447960 1.858641 0.672684 1.055579 1.369103 1.261471 1.298392 0.827808 0.468809 1.266838 1.498491
+1 0.044279 1 1 2.069610 1.793888 0.012868 -0.497680 -0.025337 -1.719399 -1.568832 -1.540751 -0.828392 2.324017 -1.232087 -1.444258 -4.149139 15.419861 -38.388437 -44.456226 -25.794160 1.038418 0.941383 1.319672 0.732316 2.028053 1.735065 0.485052 2.026445 1.702470 1.670410 0.580469 1.436139 0.688507 1.487784 2.438188
+1 0.007189 1 1 0.240947 1.655272 -1.789710 -0.469178 -1.648215 -2.120417 1.943058 0.120532 -0.548790 -1.366116 -1.544218 2.167045 -17.061898 40.675358 -69.254696 36.318560 56.031600 1.721396 0.250553 0.539380 1.607263 1.269692 2.206359 1.531787 1.743386 0.830980 2.024419 1.410517 2.060404 0.963092 1.692456 2.106640
+1 -0.042750 1 1 1.165412 -2.317004 1.303996 -1.053551 2.126612 -1.497526 -0.053008 -0.256861 -0.514449 0.885737 0.138873 1.410583 -11.643791 52.807689 -11.178321 -74.040472 1.780140 2.407099 0.364515 1.159112 2.197614 0.801704 0.481362 0.757966 1.136732 1.804753 1.736693 0.848632 1.705685 1.703127 1.459471 1.321609
+1 -0.031710 1 1 -1.840572 2.331399 0.309336 1.246146 2.115179 -0.444727 -0.679969 -0.689721 0.336413 -0.778076 -0.240399 -1.866169 30.348658 69.899401 -0.761974 -56.496788 -41.509162 1.457804 0.319621 0.367846 0.890126 1.593597 1.076081 1.688469 0.346585 1.310281 0.399302 0.822336 0.749993 2.132313 1.283395 0.773869
+1 0.008317 1 1 0.711918 0.456699 -0.745561 -0.404651 -0.986085 0.343691 -0.966810 -0.852048 0.582582 -0.894588 1.889591 1.562546 -13.549657 -29.076943 3.827391 -23.042266 28.631815 1.598659 0.667889 1.463166 0.431885 1.687113 2.299704 2.127729 0.737554 2.323228 1.491033 0.800341 2.325708 0.430349 0.633315 0.871449
+1 0.005522 1 1 -1.373941 -1.116705 0.988135 1.120621 -1.141941 0.951703 1.427873 -1.929346 -0.573439 -0.955969 2.281707 -0.776221 -65.449692 -62.965256 -7.060220 -11.123259 -48.619657 2.116367 1.026159 1.913515 0.447845 2.183817 0.670415 1.165935 2.111670 0.837527 1.811887 2.389613 1.221194 1.599314 0.426644 1.357106
+1 0.033899 1 1 1.226187 1.240142 0.176703 1.034074 0.386703 0.936214 0.290182 -0.236523 2.021992 -2.129188 0.627341 2.098708 24.274447 -19.364947 33.341113 -35.919407 52.525905 2.168238 2.079227 2.325427 2.455132 2.154497 0.624542 1.926427 1.450957 2.237660 1.108750 1.752212 0.670856 1.819443 1.130235 0.615262
+1 -0.011124 1 1 -1.690656 0.852686 0.722547 0.022116 -0.575741 -1.951408 0.913168 -0.632584 -0.693391 -0.088817 1.082233 -0.737095 16.152588 -23.459054 73.675228 9.553130 59.452563 2.413379 2.405987 1.921013 0.469074 1.228602 2.369401 1.267321 0.610564 1.003654 1.670301 1.001053 0.695276 0.505543 2.154784 0.963251
+1 0.015898 1 1 0.481356 -1.014417 0.110790 0.656511 2.281617 -2.275798 1.117792 -1.565309 1.124224 -1.837965 -0.964377 2.334522 30.835790 7.121807 -3.782665 24.750555 32.574428 1.051245 0.532138 1.399845 0.439700 0.288210 1.202628 2.318505 0.864545 1.402733 1.733219 0.962782 0.983158 1.436781 2.471052 1.979265
+1 0.004196 1 1 1.568417 -0.724430 1.312758 0.116450 1.534816 0.034403 -1.407679 2.036554 2.273300 -0.703268 -1.161169 -1.769278 -34.431825 4.324260 -72.164609 29.414539 -29.850944 2.052835 1.994253 0.656485 1.042239 2.154952 1.532118 0.556208 0.944267 0.297526 0.271961 0.341028 2.414071 0.541247 1.480663 2.005843
+1 -0.072349 1 1 0.113904 1.151827 0.261977 1.672471 -0.178394 -1.188235 0.431751 -0.648047 -1.402490 -0.277952 -1.555683 -2.036686 6.702371 -3.241553 -30.777879 66.184648 -34.616270 2.190260 0.947866 2.282619 0.730788 1.106132 0.501424 0.441380 1.525424 0.550546 0.274463 1.891881 1.352284 2.085945 0.473971 0.289017
+1 0.034789 1 1 -1.380883 0.024177 1.076147 0.657840 1.053674 -0.061430 -0.434625 -0.533112 -1.756332 -0.266742 -1.646327 1.323520 61.402622 -6.125025 -43.297523 -51.472011 -40.083980 0.753220 2.367678 1.570346 1.797946 2.084435 2.100475 1.689892 1.762381 0.588676 2.126050 1.769517 1.275775 0.957017 0.830490 0.539081
+1 -0.003790 1 1 -0.364669 1.831322 -2.295972 1.344910 -1.427104 0.720593 0.167913 -0.610105 0.123945 0.263695 2.282223 -1.532661 -48.113589 4.910859 36.800794 60.938602 -4.921986 0.267804 2.483246 2.161110 1.526698 1.720959 1.899872 0.650884 1.415452 1.757449 0.944829 0.739544 2.010706 0.431319 1.173953 1.882465
+1 0.034565 1 1 0.498812 0.189874 0.931621 -1.511756 1.117172 2.149354 -0.984058 1.420902 -1.287795 0.032401 -2.080639 1.347654 72.698995 -47.998398 -9.080569 -67.123121 11.709721 1.454191 0.341008 2.077856 1.776521 1.992726 1.990163 1.673886 0.496888 0.695267 0.349242 0.963618 1.519362 2.165810 1.775044 1.923025
+1 -0.080332 1 1 -1.689456 2.161749 -0.007836 0.240029 0.365123 1.092774 2.066655 -0.747365 2.270696 -2.046452 1.015852 0.441138 51.636514 -45.113726 23.601759 74.760242 -54.611264 1.352267 1.795127 1.944186 0.689751 2.142825 2.451595 1.213971 1.718338 0.603565 0.364749 0.581978 2.053930 2.396585 1.397537 2.159745
+1 0.037398 1 1 -2.064102 1.252577 1.819362 -0.675380 1.041406 1.091262 0.215081 0.460535 -2.250205 -2.265128 1.391507 -0.532079 46.582276 58.318406 57.446284 -50.310650 -21.091655 0.813390 1.140274 0.584734 1.119816 0.990326 0.412902 2.138333 1.217790 0.647199 2.478804 1.767939 1.749520 0.426885 0.904241 0.331009
+1 0.034004 1 1 -2.015625 0.747892 1.874342 -0.263496 1.062285 -1.423044 -1.725699 0.922800 1.031160 -1.467458 1.068723 -1.601875 -26.593016 51.178988 65.246033 -59.921210 4.225553 2.407975 1.593101 1.740299 0.704349 2.240673 2.235259 1.241982 2.246789 1.534993 1.620172 2.233975 2.168351 1.723217 1.601696 2.198709
+1 0.038773 1 1 -1.670706 1.568287 1.807671 0.749997 -0.448246 1.441280 1.915711 2.314080 1.392951 0.174085 -0.541275 -2.291810 19.834885 64.918044 -22.430659 -42.083317 -44.307301 0.282995 1.292023 1.783486 2.044677 2.138989 0.988660 1.661636 1.608768 1.812185 0.639377 1.512735 1.042023 0.777659 1.364794 0.840827
+1 0.004851 1 1 1.377099 -2.353530 0.009143 -1.848104 -1.732087 1.953838 2.231653 1.486319 0.184884 1.888239 -2.303174 -1.875005 -46.835116 42.211965 -43.506360 38.607993 -15.468583 0.917860 1.980616 0.956481 0.829762 1.808520 2.048172 2.371003 1.193326 1.229186 0.921846 1.465823 2.342758 1.228062 2.291104 1.582857
+1 -0.013251 1 1 0.637081 0.876332 2.289094 0.852388 0.423744 1.450140 0.022010 2.352534 2.098884 -1.006947 -1.575683 1.120361 -25.422922 66.952129 -35.564253 21.607736 11.214775 0.425882 2.042550 2.382398 1.455224 1.941148 1.365595 0.803301 0.329147 0.722164 2.407531 0.871532 1.836243 2.243830 1.303830 2.217787
+1 -0.008742 1 1 0.472276 1.878652 1.493785 -1.564065 -1.535694 -0.649484 -1.988275 -1.386536 -0.750345 -0.694724 1.077978 -1.554615 56.908848 67.008926 19.019963 18.512005 31.264234 1.494680 1.339634 0.982841 0.609236 1.179637 0.652255 1.946168 2.493151 2.143492 2.422631 0.405993 0.771120 1.718922 1.426279 1.463238
+1 0.008965 1 1 -0.238939 -0.898151 -1.436291 1.831503 0.754520 0.183461 1.529493 0.106624 1.316515 1.992168 0.851049 1.481667 67.293332 -0.964749 -14.538588 -0.044169 7.656941 1.227992 1.118375 1.533184 0.475921 1.558960 1.696135 0.945045 2.124691 1.426200 2.396641 2.349991 1.295486 1.488910 1.110805 0.308040
+1 0.003134 1 1 0.819943 1.748454 -0.200402 1.204130 -1.900112 0.670349 -0.768854 -0.765346 1.658208 0.430163 0.947310 -1.724170 -52.224489 63.021402 50.710215 -13.416286 -37.526523 2.000942 0.584314 0.818740 1.065668 2.176233 1.441116 1.085259 0.691047 1.434600 1.827937 2.134414 0.594929 1.463676 2.253737 1.311305
+1 0.058456 1 1 1.166274 -1.973329 0.050788 0.654671 -0.368606 1.624729 -1.480854 2.118283 -0.115302 -1.083124 -0.100156 -0.998855 -70.819388 -11.457281 37.471671 -63.621381 65.456749 1.848796 1.715500 2.406245 1.753138 0.482292 0.625893 2.132937 0.516670 2.424753 2.324784 0.647881 0.431103 2.052947 1.622869 0.309653
+1 -0.009968 1 1 -0.193222 -0.651731 -2.052951 0.162645 0.390039 0.448353 0.360241 -0.849121 -2.063507 1.825583 0.208777 -1.817867 71.205800 55.888845 23.812341 14.013862 30.980189 1.885544 0.586594 0.881713 1.957610 1.302347 2.037430 1.836269 0.423022 1.237478 0.796952 1.630654 0.656930 1.778758 1.329068 1.137703
+1 -0.011330 1 1 -1.190820 -0.589315 0.827024 -1.751447 1.720295 -2.217939 -1.904853 1.105834 0.083682 2.159495 -0.186216 -0.713072 -31.759480 68.415822 -35.271554 -9.008514 -56.096569 0.399584 1.065075 1.209034 1.990635 0.605428 2.422713 1.780683 2.186301 1.910358 1.383976 1.479339 2.245694 1.133788 1.820561 1.923635
+1 0.005393 1 1 0.043995 -0.426380 1.379204 0.033763 1.975129 1.921528 1.118123 -0.715137 2.004955 -1.024041 -1.406647 0.537136 -41.272520 -67.242110 -38.144415 6.812101 40.978970 0.378130 0.474352 2.183581 1.201483 1.078198 1.273862 0.306675 1.042149 0.650164 0.564285 1.687502 2.095427 2.341638 0.410766 2.252102
+1 -0.061470 1 1 -1.101805 1.645354 1.171792 1.239838 -0.233776 1.065239 1.112087 1.505120 0.442966 -0.650546 -0.986049 0.953812 -26.330118 -30.294763 -64.085989 56.785650 -53.579544 0.454005 2.204530 2.289840 0.587710 1.647819 1.140824 0.833031 0.502344 2.398780 2.300056 1.291699 0.839667 1.779227 2.472609 1.131798
+1 0.010091 1 1 -0.083064 -1.181389 -2.314704 2.251269 1.312358 -1.883779 1.865888 -0.971607 -1.375688 -2.201519 0.748440 1.669382 -8.369331 36.647104 27.877516 -62.593706 -62.421711 1.049609 2.275677 1.050975 0.480479 1.653016 0.746418 0.544486 1.932694 1.034920 0.656647 1.510697 0.529513 2.268361 1.844931 2.013113
+1 0.033685 1 1 -1.340394 1.925081 -0.425128 -1.151853 -0.695549 1.351764 0.667692 1.702117 -1.429095 0.251290 1.136201 1.533278 -71.763112 27.377029 -74.265817 -35.588952 56.486545 1.665335 0.780535 2.459926 1.729776 1.592657 1.041834 2.099844 2.327065 0.733605 1.203396 1.723732 1.265117 1.815023 1.084391 1.853583
+1 -0.003579 1 1 -2.352828 -2.329604 1.580883 1.454441 1.619744 -0.426834 -1.541573 -0.498437 1.398690 -2.321997 2.203892 1.429585 -45.699619 -73.504347 12.446552 -60.795500 10.031392 1.339057 0.272387 0.755895 2.332400 0.401498 1.721474 1.557623 1.718071 0.618715 0.740249 0.363529 0.327057 1.594173 1.759047 0.798213
+1 -0.007233 1 1 1.016532 -2.266233 1.657369 0.472410 -0.573123 -0.350059 2.338848 -1.724961 -0.801142 -1.501363 1.439723 -0.689930 48.865620 34.471618 64.491039 0.887734 70.142420 1.879708 1.497250 1.784002 1.723048 1.025363 2.023045 0.822871 0.735946 2.302414 0.423647 0.479276 1.692488 0.396331 0.378946 0.687407
+1 0.001466 1 1 1.438137 0.931170 0.334035 1.664159 1.498546 -1.660098 0.786987 -0.787486 1.815628 -2.177015 -2.102300 0.137776 57.988288 59.162892 0.727768 -68.411472 -41.601591 0.655940 0.891479 1.844993 0.793893 1.960986 1.785789 0.259249 0.445223 0.868475 2.201494 0.761415 0.606367 2.466169 0.906400 0.614384
+1 -0.027557 1 1 -0.614649 -0.846882 -2.133409 0.364104 -1.892089 -1.143523 -2.076445 1.134795 1.461908 -0.115928 -2.184448 0.196544 -2.364095 16.652811 -16.211581 -68.046058 -50.095062 1.409349 0.434453 2.097899 1.144147 0.430319 2.377909 0.272820 1.281683 1.252916 1.517079 2.045941 0.886267 1.985121 2.419701 0.663718
+1 -0.019917 1 1 0.110997 -0.576718 0.477925 -2.143525 -0.012262 1.249596 -1.162027 -2.055344 2.348742 -0.368294 2.167277 -1.338513 17.736190 42.139381 -63.418580 23.917652 -16.030033 1.123425 0.908592 1.447892 2.468200 1.282156 2.448141 1.653842 1.118362 1.308419 0.592184 0.329712 1.222997 0.402754 0.335819 0.351867
+1 0.004090 1 1 2.285317 -1.361270 -0.215505 1.833322 -1.667381 0.903028 -1.405679 -2.037840 -0.326215 -2.192837 0.584422 1.768728 40.377131 18.438289 -7.682499 30.233794 -60.623278 2.193618 1.139240 1.211491 0.532526 1.166635 0.391291 1.177448 2.116627 0.896848 2.079184 1.590361 0.695879 1.630327 1.901514 1.245146
+1 0.008456 1 1 -2.042030 -0.066296 -2.114370 -0.089438 0.075028 -1.927459 -1.844103 -0.462328 0.383884 0.678959 -2.147028 -2.341364 59.107059 -37.665255 -39.939630 -15.360493 -13.797615 1.427306 0.736019 1.278411 0.252390 2.175195 2.006329 1.117688 1.226004 1.453015 0.818688 2.442949 2.147477 1.891638 1.759048 0.816404
+1 -0.006123 1 1 -1.792270 -1.098089 -1.863471 -0.813484 -1.587021 -0.946822 0.492667 0.591349 0.377979 0.386366 -0.023236 0.604201 -12.222206 -68.611231 51.039785 -24.333183 -67.811792 1.183192 1.904289 0.635185 0.796850 2.151577 1.046280 0.333826 0.620084 1.255134 0.531170 0.875055 0.292705 2.499404 1.488321 2.454500
+1 0.083625 1 1 1.532474 -1.634629 0.022175 0.410196 -0.067911 -0.985556 -0.189729 1.505210 1.965446 -0.596672 -0.310737 -1.232284 -1.680976 -52.169142 -56.765696 -61.057794 -48.340143 0.583239 0.740367 2.351164 0.768729 2.033232 1.027776 2.078813 2.117223 1.923636 1.808383 1.999115 1.376318 1.023990 1.448395 1.916910
+1 0.006757 1 1 -2.261511 0.920051 1.951289 1.808390 -1.298571 -2.017609 0.399263 -0.024186 -1.227396 1.997736 0.183675 0.418671 32.068437 24.226002 66.410118 4.860071 -66.779822 0.348042 1.034416 1.182156 2.499473 0.391573 1.422388 1.320671 1.769167 2.146566 2.329990 0.395529 0.402067 2.286598 2.352891 0.541178
+1 0.025442 1 1 1.633640 2.206858 -0.553348 2.137270 -1.448637 1.666551 -0.718974 -1.232554 0.124889 1.995530 0.797202 1.253389 42.308455 -71.797342 52.073147 -56.611760 -23.854993 1.661936 2.157416 2.438751 1.342928 2.342474 0.963875 1.352754 0.988150 2.080397 1.737883 0.595453 1.284930 1.809740 2.304255 2.114121
+1 0.018391 1 1 -0.285783 -1.229408 1.161137 1.223441 2.216147 0.058448 2.163670 -0.712563 -1.870589 2.066006 -2.229116 -1.260406 -46.044898 -26.608843 -64.820520 11.517738 -71.369846 1.930027 1.211601 2.384482 0.486328 0.967583 0.672827 1.211207 0.263849 1.258480 0.518030 0.524216 0.993966 0.843986 2.371123 0.958591
+1 0.031868 1 1 -2.147627 1.734768 0.699871 0.604195 -0.494578 0.286349 1.319016 1.630643 -1.041549 1.207088 0.699486 -1.150260 -70.031524 30.172528 -40.324202 -28.866549 -60.088669 1.971175 2.035422 1.840575 0.794449 2.303968 1.795363 1.419792 0.446336 1.573071 0.346347 1.800971 1.175232 0.877770 0.928448 2.183205
+1 -0.017366 1 1 0.969463 -1.681990 0.412836 1.900477 0.742036 -2.299198 -1.024177 1.022003 0.146397 0.622454 0.086003 -1.259014 -51.798270 26.470185 -15.607714 31.150466 45.880055 0.716288 0.401868 1.192498 0.814662 2.276577 0.435578 0.761923 2.391557 2.401593 2.330317 1.386118 1.487339 1.700384 0.352942 2.396585
+1 0.007393 1 1 -1.439050 -2.130408 -1.029915 -1.168229 2.100501 -2.095377 -1.315745 1.517774 1.066452 -2.065160 2.313997 0.004090 -61.962576 44.987211 -49.950762 27.540915 -19.837767 1.924686 1.446858 0.836276 1.036575 1.469246 1.374572 0.935418 2.326778 0.407592 0.649404 1.285880 2.041018 1.389581 1.186529 1.746664
+1 -0.015967 1 1 0.265310 1.150937 -0.551302 -1.177192 2.248187 1.344071 -1.395700 0.745307 0.844757 -0.603774 -1.854121 0.819397 63.604250 -53.365787 -68.775717 -13.467846 -4.085215 1.971847 2.079677 0.884373 1.662823 1.320635 1.160783 1.023720 1.411368 0.612861 1.357675 0.439509 1.577889 0.322696 0.304578 1.790981
+1 0.005831 1 1 1.310254 0.448582 -0.510339 -0.715688 2.155035 0.256085 1.611121 0.729280 0.086176 1.660736 0.503058 0.862415 -22.358616 -31.266903 -52.834340 13.255642 37.580569 0.874260 0.437771 1.621757 1.866415 0.837423 2.324674 1.045432 1.824530 1.123519 2.482531 1.400736 1.926632 0.398899 0.802147 1.183666
+1 -0.007457 1 1 2.316759 -0.709950 -0.353808 0.588156 -1.450692 0.117412 -1.140365 -0.824407 -1.392195 -1.611279 1.337126 -0.308000 74.901810 74.727473 -5.353651 21.179028 5.925049 1.109459 2.433150 1.695257 1.936383 2.293784 1.628212 2.365215 0.671601 0.851317 1.836393 0.253459 2.138474 1.326120 1.093323 1.225048
+1 -0.003077 1 1 0.238730 2.097819 -0.055801 -0.082795 -1.375684 -2.141587 -0.434814 1.003279 1.181249 -0.042059 -0.025787 0.142361 -39.146974 -43.193822 41.438510 7.029696 -51.894072 2.370063 1.150697 0.263590 1.399026 2.424856 1.803140 1.624170 1.921444 0.951455 1.857661 2.208964 0.303494 1.578918 1.868317 1.300085
+1 -0.009879 1 1 -2.192197 1.911385 0.285392 -0.629862 -2.067414 2.122635 2.343528 1.529789 0.373598 2.164051 0.982587 2.130987 42.701550 -65.056989 -62.806097 -32.065514 24.907553 0.943704 2.088586 2.115633 2.193130 1.937941 1.474069 1.431766 1.441492 0.656603 0.782340 1.281028 1.486854 0.299729 1.296547 1.317864
+1 0.081986 1 1 1.837240 -1.791462 -1.645346 -1.035444 0.151273 -2.250237 1.901387 1.906089 0.813903 -0.801361 -0.466958 -2.035477 53.584662 -2.592810 72.643894 -74.081325 65.178243 1.385939 0.724629 1.083834 1.495598 1.009526 1.362623 0.361883 1.914084 1.002615 2.204592 1.077681 1.583605 1.897286 2.182181 2.414042
+1 -0.014608 1 1 -0.116833 1.450557 2.332112 -1.840359 1.200698 1.686746 -0.587610 1.208335 -1.904336 0.363261 -1.924821 0.086556 -44.198998 -52.563739 61.236300 48.494665 -50.162443 2.422227 0.362595 0.379483 0.720782 1.690667 1.292423 1.753893 1.932018 0.922993 0.488479 1.112003 2.429818 1.947832 1.205659 1.515046
+1 0.033203 1 1 2.205649 -2.013475 -0.802262 -1.475226 -2.247550 -0.062066 -1.711355 1.678136 0.775590 0.878937 -1.046329 0.977906 -36.700267 -21.380832 52.357001 64.109323 35.394105 0.905804 1.853127 0.261118 0.353736 2.248913 1.223242 2.282758 0.819888 2.363909 1.225391 2.405571 1.683930 0.563140 0.448850 1.074987
+1 -0.014456 1 1 0.757110 1.293705 0.329492 0.708491 -0.606245 -0.968555 -1.904112 -0.573409 -0.451733 -0.618111 2.220693 1.075708 -63.914771 -65.560899 17.975673 17.141697 -49.506460 1.299025 2.454423 1.484283 2.089795 2.177679 1.002752 2.249017 0.734880 2.373492 0.271861 0.922104 1.302861 1.678822 2.456594 1.972260
+1 0.056546 1 1 2.105555 -1.983887 1.671092 0.201584 -0.183218 -2.151274 1.694612 -0.333011 1.404202 0.776470 1.530456 2.157994 -58.854241 -63.227868 -70.776774 -45.243534 -58.075762 0.935022 2.411717 1.472605 1.567338 0.745132 1.437362 0.993157 0.738647 0.441943 1.994401 0.904087 2.236187 1.086806 1.943443 1.699998
+1 -0.012377 1 1 0.021876 0.097267 -0.425755 -2.257862 0.989896 -2.256385 2.244369 -1.564202 0.874000 0.795615 -1.865265 2.008096 -2.169482 -12.477381 -7.335581 10.895719 -25.650374 1.287419 0.904952 1.021316 1.501176 0.270021 1.495682 2.419981 0.872611 1.980740 0.788221 1.131799 2.145974 1.376087 1.644866 1.006777
+1 0.000140 1 1 -1.361320 -1.060594 1.565293 -1.386300 -1.496157 -0.597401 1.586951 -0.233551 0.134507 -1.290370 -0.837306 -1.401572 32.425854 31.326378 2.432700 -63.609089 -27.959973 1.776020 0.319954 1.463528 2.014817 2.025649 1.830103 0.292339 0.847708 1.925893 1.486839 2.307988 1.857347 1.430673 1.062264 1.215102
+1 0.007006 1 1 1.220832 0.772685 -0.833455 2.060910 1.662859 -1.511058 -1.287260 -0.400741 -1.252083 1.765934 1.433147 1.875655 -55.948795 18.605228 -51.934990 -21.370222 -69.320350 1.118222 1.214793 2.022680 1.426968 1.794367 0.421593 1.960075 2.223930 2.094209 2.129543 1.975786 0.786887 1.210859 1.163959 0.404892
+1 -0.056565 1 1 -1.750255 -1.808500 -0.552333 0.342657 0.502218 0.893524 -0.924172 -0.516751 -0.094655 1.915466 -1.805848 1.606065 18.300746 -69.367362 -57.249178 63.073057 18.863139 0.366563 1.818801 1.590787 1.107452 2.454132 1.090826 2.008914 1.810963 0.361141 0.701907 1.706230 1.859592 0.910478 1.646114 1.732941
+1 0.002090 1 1 -1.086037 -1.946905 1.202842 0.014295 -0.069746 1.169328 2.231105 1.695261 1.155453 -0.060406 -2.084590 0.905060 -7.900943 -41.149679 47.346274 -1.170036 -14.798172 1.181954 1.345061 2.190264 1.024273 1.703160 2.016647 1.292707 2.024771 0.585176 1.810251 1.887061 1.325449 1.064951 1.387191 1.518131
+1 -0.071533 1 1 -0.866236 -2.267079 1.589785 0.273647 -0.106851 -0.423622 0.609290 0.308281 -2.346920 -1.988771 -0.300566 0.072264 -39.956786 -3.708589 69.743158 73.260653 -58.206681 1.679765 0.310204 1.847417 1.037430 2.327067 0.767468 1.084521 1.789060 1.229575 0.715667 1.216050 0.653877 2.204954 0.414293 0.777786
+1 0.018995 1 1 2.097401 2.343867 -2.200652 1.181366 1.930958 -0.605164 -1.658141 0.683898 0.758417 -0.302310 -0.976886 -0.566439 -35.689003 24.924585 -42.498111 34.250191 -57.041461 0.687583 1.707622 0.506740 2.028305 1.474863 1.279868 2.236651 2.135063 2.497851 2.387876 1.283692 1.268738 1.927959 2.457439 0.421333
+1 -0.041922 1 1 -2.111360 -1.339658 0.166655 1.812079 -0.558342 -1.690198 -0.870918 -0.839055 2.182926 -2.218729 -1.044846 2.353347 51.924366 -7.182523 33.337205 48.396615 -48.091755 2.453128 2.228782 0.391101 2.487905 1.719523 0.265052 1.221720 1.445960 1.507001 1.411524 0.982531 2.146504 1.297573 0.555321 1.787088
+1 0.006047 1 1 2.351248 -0.662364 -1.692204 -1.603034 -1.464866 2.236242 -1.490960 1.910868 1.021768 0.915185 0.280285 -1.638221 28.728383 -12.072572 46.288831 -73.616101 -65.816328 2.499513 1.071839 2.404049 0.846375 2.023972 0.641650 1.457726 1.251809 0.903541 2.060369 0.375733 0.695878 1.621716 1.177063 2.390390
+1 0.021842 1 1 0.489914 1.441369 -1.309898 0.819562 0.061011 -1.886321 1.558763 1.957250 -1.687761 -2.327364 1.538457 -0.027527 -26.419823 -37.969277 -49.632114 -16.943864 74.479176 1.697750 1.090181 2.419842 0.787808 0.937207 0.891576 1.216530 1.976681 2.322086 0.297972 1.020401 1.880079 0.995463 1.253317 1.504444
+1 -0.003900 1 1 1.566124 -1.562241 0.851385 -2.298047 -0.539328 2.145994 -0.897387 1.972598 1.800246 -1.518754 1.306453 -2.182900 -65.332807 -48.488266 7.720236 4.007344 1.436612 1.301962 2.331374 1.150799 1.969987 2.313166 1.125563 0.844041 1.047285 1.476017 0.421457 1.919893 1.893097 1.531309 0.458001 1.878897
+1 -0.016042 1 1 0.325435 -1.501252 -1.409480 0.052362 -1.173183 -1.056398 1.404325 -1.861147 0.539958 -0.985144 2.023782 -0.319553 44.421137 36.045930 -26.048940 45.459133 -68.352446 2.131565 2.214049 0.264782 1.186824 2.203074 0.320319 0.846382 2.150019 1.873497 0.609243 1.291509 2.136283 0.507545 2.052799 1.401576
+1 -0.007672 1 1 0.856415 2.130616 -0.186424 0.515806 -1.651378 1.256361 -0.546893 2.243417 1.291179 0.289089 0.250478 1.615487 -41.172700 -39.563595 4.658867 1.570069 -11.846616 0.533774 1.896163 1.315597 1.982934 1.677251 0.808376 2.367458 2.364761 2.042359 1.421213 1.823251 2.121734 1.225854 1.174297 0.913379
+1 0.022495 1 1 -0.943606 -1.993733 1.126985 2.136633 1.993438 -1.364381 -0.659519 -1.005212 -0.681764 2.115963 -1.409402 1.351196 17.599171 -10.731424 -63.044545 10.327842 30.037138 0.387689 1.393436 0.730854 2.220679 1.449181 1.628610 2.296724 1.533250 1.587968 0.980393 2.217465 1.427628 1.638263 0.282246 2.204398
+1 0.029285 1 1 -1.543700 1.454530 -1.586502 -1.651149 0.391203 1.170161 2.098204 1.708280 -1.528146 -1.033546 -0.933254 2.348916 -68.877368 -71.925123 4.452072 -24.018776 -33.569751 0.523010 0.979131 1.253187 1.560251 0.890038 2.375577 1.572776 2.153566 0.736065 2.044875 0.958365 0.999016 2.469024 1.627933 2.165478
+1 -0.004105 1 1 1.334767 -2.261015 -0.180008 -0.037330 -0.652794 -1.067063 1.224804 1.570663 -0.666356 1.906469 -2.217830 -0.071836 -30.858947 53.681458 -25.730128 3.742541 50.880164 1.268666 0.725647 2.444926 1.626020 1.516246 1.554078 0.634576 1.813081 2.208263 2.021373 1.962673 0.897677 0.254132 2.193963 2.442413
+1 0.007184 1 1 0.668326 -1.778241 -0.925060 -1.308233 0.537349 2.281533 1.019700 -0.855497 -0.836152 -0.858599 -1.139244 -0.841951 20.300299 -62.868107 -24.276107 -8.534103 -32.671396 2.002707 0.991245 2.351618 1.649381 0.390138 2.049876 1.767563 2.177946 0.988112 1.456358 0.756576 0.277286 2.087336 1.347682 1.234054
+1 0.021711 1 1 -0.120006 -0.040579 1.280135 -1.544202 -2.273053 0.140165 -0.446438 -1.167607 -1.589783 -0.239311 2.282470 -2.080754 -18.903366 -8.868189 52.355155 33.085204 13.025016 2.296643 2.422296 1.521606 1.626298 1.690749 0.418029 0.558995 0.529276 0.542755 2.088346 0.332867 0.250309 0.944224 1.828079 2.279248
+1 -0.004382 1 1 -0.412741 -0.294093 0.482716 -1.727946 0.859931 -0.033378 -0.210864 -0.267593 -1.822009 -1.407007 -0.805360 -1.696369 -29.467017 47.841825 -72.453135 -19.839465 8.118614 0.618291 0.365285 0.590612 0.920541 2.031060 0.521027 1.398383 0.626603 0.565319 1.059794 2.450875 0.359282 0.956386 1.481768 0.324284
+1 0.000601 1 1 -1.541349 -1.443110 0.309652 1.844274 -1.383051 1.279763 1.634501 -2.163369 1.053632 -0.771793 1.689073 0.814109 -64.934429 47.045378 41.662592 23.176022 -30.594118 1.444961 0.455833 1.427512 1.946570 0.250274 0.357481 2.190102 0.548243 2.065790 1.482255 1.759981 0.753623 2.394629 2.285321 1.141502
+1 -0.003124 1 1 0.839692 -0.896054 0.822215 2.242608 1.820254 0.176735 1.578657 1.739063 2.200019 2.306368 -0.985662 -1.977199 31.346310 37.430262 -9.586745 -24.430333 -50.613514 1.204954 0.913385 1.019403 0.850870 1.073601 0.506989 1.715822 1.064369 0.607620 1.021699 1.194166 1.853154 0.715632 0.627898 2.089098
+1 -0.018422 1 1 1.423792 0.167979 0.506907 -0.418029 0.350372 -1.786711 -1.903434 1.395428 -0.598330 0.099047 1.208732 0.051488 -54.699921 8.432173 -30.477007 22.939962 51.944990 1.966822 0.879024 1.764125 0.654531 1.959236 1.634388 0.402269 1.186379 1.466714 1.559844 0.791805 0.614427 0.675947 1.885805 0.481601
+1 0.034044 1 1 -0.803924 -1.139609 -2.268719 2.293326 1.293796 1.865396 0.195722 0.259152 1.315748 -1.472447 2.043449 0.363709 28.495003 -34.489969 -72.911425 -72.312212 -51.338683 0.636273 1.082097 1.554434 2.119265 2.490648 0.563953 0.615540 1.378887 1.460416 1.460631 0.582536 2.436093 1.667210 0.807225 1.028081
+1 0.060619 1 1 -1.090165 -0.627250 -0.571581 1.995056 2.255706 0.488856 -2.203220 0.437572 -1.772455 2.065635 0.960688 1.643132 48.611953 -28.911730 -69.448799 74.043278 45.377648 2.307038 1.633518 1.536436 1.137221 1.026955 1.778663 1.982306 2.370668 2.325914 1.639826 1.801617 0.769710 0.510653 0.286759 1.556115
+1 0.034155 1 1 -0.994890 -1.568427 0.551570 0.960437 2.135388 -0.088906 -0.411591 0.174417 0.328518 -1.514266 1.352380 1.606003 -14.817710 -41.248558 35.489156 66.242303 34.382943 2.486950 1.423548 0.572600 1.937916 1.056235 1.142333 1.434551 0.993360 1.905069 2.487988 0.868883 2.320225 0.520032 0.433536 2.438626
+1 0.062410 1 1 -1.731255 1.794347 -1.707823 -0.214452 0.687924 -2.262701 -0.244696 1.302663 0.099598 1.049652 -1.677353 -1.756567 15.721201 -73.773491 -11.071223 -74.045197 72.366753 2.395361 1.089859 1.503758 0.909395 1.447187 1.876118 1.922032 1.846226 1.274566 0.878242 2.108846 0.621628 2.456903 0.411501 1.098233
+1 -0.000935 1 1 -1.502462 1.813167 -1.119289 -0.026735 -1.653240 -1.765659 -1.511635 -1.567505 1.902387 -0.132933 -0.538259 1.269679 57.440990 10.721141 40.217181 30.157929 14.314426 1.113287 1.520460 0.368787 0.947124 1.062572 1.890273 1.311079 0.296851 2.423240 1.642878 1.349358 2.413649 2.454847 1.860198 2.094552
+1 -0.010154 1 1 -0.866507 -2.109591 0.122116 -2.196149 1.461230 -2.082958 0.060819 -0.404403 -1.541702 2.044987 -2.075852 1.688254 38.013287 39.320274 -44.161813 -27.586283 7.346698 1.764406 0.874748 1.885408 0.549494 0.593884 1.914305 2.474295 2.467641 0.893248 2.324826 1.351268 0.758275 1.825673 2.344825 2.232348
+1 -0.020358 1 1 -0.780086 -1.045244 0.370711 0.753714 0.765165 0.024268 -2.105168 -0.945612 1.993068 1.830956 0.974822 -1.137894 -54.376154 49.987758 -5.755444 18.261271 17.189360 1.398482 2.290139 1.112762 1.687954 0.694329 0.332622 0.630976 2.061929 1.833894 1.004149 0.975249 1.259172 0.905121 1.613708 1.592381
+1 0.004423 1 1 1.179858 0.145327 1.496040 -1.361491 0.778294 -0.808279 1.076073 -0.590099 1.788159 -2.027849 -2.058108 -1.687705 -44.203950 14.207520 -14.217930 -10.743686 30.874630 2.273584 1.869028 2.010483 1.186606 0.795194 1.320434 2.286500 0.710011 0.654842 0.433696 0.625827 1.023778 2.382681 1.721788 2.334100
+1 0.021437 1 1 -0.619528 1.970783 -0.435142 0.200130 -1.062870 1.013826 -0.625340 -1.461524 1.850578 0.893876 0.272607 1.269385 49.717736 -44.015751 27.280049 -54.220698 -37.267694 2.002934 0.309335 0.745795 1.328011 1.377672 1.280264 2.147133 0.620444 0.550804 2.368297 0.718515 1.824038 1.854741 0.376300 1.220888
+1 -0.006046 1 1 -0.534161 -0.549343 -1.235434 -1.154152 -1.640609 -1.521824 1.550562 0.784470 -0.670555 2.018312 1.987656 0.407103 -6.813061 -57.117334 28.961985 14.088570 -63.409955 1.658288 1.599949 2.100875 1.648483 1.060546 1.597544 2.178832 2.374548 2.273194 2.067054 2.480765 0.973643 1.269527 1.686975 2.240839
+1 0.004447 1 1 0.861870 -0.436124 -2.173469 0.944983 1.582000 1.383272 -2.268804 0.858069 1.649283 1.221126 1.003737 -0.541064 39.527274 -15.112147 -39.853232 -63.262201 -47.815762 2.282243 1.164374 0.633646 1.936350 1.732046 1.503468 0.543215 0.808382 2.482852 2.290794 0.876130 0.373420 2.326591 1.760717 1.863436
+1 -0.031981 1 1 0.935966 0.831120 1.115623 -0.313337 2.197627 -0.179207 -0.718022 0.628954 0.934157 -1.305353 1.818271 -0.168722 36.655678 21.982888 16.391816 -52.745198 11.456336 0.574512 0.326565 2.327120 1.656898 0.729339 1.494802 1.138480 1.931555 2.137520 1.051047 1.705419 1.724159 1.685618 1.940559 0.480474
+1 -0.045710 1 1 -0.483612 0.804873 -1.768068 0.400437 0.851415 -1.786362 -0.750101 -1.302343 0.572550 0.147263 1.045091 1.765806 -23.052046 14.266321 74.052935 57.685199 65.132147 1.014837 0.616837 0.687093 2.467459 2.335546 1.530416 1.207828 1.956271 1.294963 1.687661 0.265389 2.392294 1.288631 1.015283 1.353321
+1 -0.038179 1 1 -0.120520 0.754180 -0.830130 1.384182 -1.118139 0.445279 0.530330 2.135493 1.675181 -1.752349 0.710552 1.050033 0.174416 -68.582327 -63.166909 53.752877 -25.395961 2.426184 1.629218 1.269539 1.889430 0.643227 0.970687 1.082123 1.995248 1.636529 0.393716 1.438646 2.330612 1.840838 0.713141 1.506660
+1 0.038495 1 1 -0.728799 -1.422236 -2.284206 1.189933 -0.170007 -1.604254 1.588977 0.836247 -2.255667 0.175258 0.322746 0.434394 43.357839 15.195403 -60.869426 -32.441903 -1.068456 2.012031 2.450431 1.888647 0.988212 0.877184 2.331469 0.501804 2.313387 0.343703 2.369125 1.140346 1.792716 1.931455 0.471695 0.278801
+1 0.010208 1 1 0.742510 0.951552 -1.111229 -1.225139 2.235089 -2.025598 -1.927526 1.748950 -1.272247 2.167388 0.530500 0.276763 13.776313 -61.508258 30.711202 13.172799 -4.769263 0.519919 0.781799 1.189947 0.685413 1.240987 1.273243 1.142764 1.927797 1.979753 2.213720 1.495207 1.201354 1.154978 2.459504 1.387512
+1 -0.040764 1 1 -0.900190 1.992465 1.129899 -0.709497 -2.171016 -0.233159 1.999863 -1.780208 -1.003093 1.942710 -1.009714 -0.948682 70.584671 -33.441362 1.031632 -61.362735 -73.483054 2.429621 0.890817 1.959239 1.686265 1.550498 1.216257 1.879113 0.507477 0.912771 1.949666 0.530722 2.352031 1.843462 2.061695 2.406185
+1 0.035685 1 1 -1.341164 -1.591131 0.666589 2.009766 -0.272329 -1.310107 2.019894 0.301571 -2.018346 2.142568 -1.933850 -0.869862 -61.732527 11.411632 -54.701998 -26.480087 -0.819246 1.839077 0.362560 2.045857 1.717729 1.629482 1.199448 0.618657 2.012315 0.473634 1.358529 1.290251 1.244855 1.026784 1.167815 2.224997
+1 0.045594 1 1 -1.015769 0.958750 2.052628 -0.886058 -0.821311 -1.189271 1.875109 -1.495706 2.268239 -0.939157 2.086676 1.164431 1.312161 3.481594 15.150706 -62.078783 41.885848 1.756658 1.146192 1.046091 1.646784 1.749303 1.289237 2.212423 2.199787 1.311288 1.561356 1.466615 2.141060 2.048275 1.852898 0.907580
+1 -0.004305 1 1 0.481383 -0.571662 0.634556 0.853927 -1.983878 1.827209 -0.743452 2.066141 0.044739 -2.057788 -1.019909 2.063279 -30.132209 -32.031181 1.945367 -4.210139 40.197577 1.385046 1.469771 1.185841 1.432088 2.356238 0.542055 1.563849 0.617313 1.928154 1.238163 1.049438 1.651728 1.599408 2.005497 0.632797
+1 -0.022455 1 1 1.347966 -1.903784 0.216426 -0.493790 -0.606741 0.121473 1.129346 -0.584569 0.481492 1.263310 -1.575030 -2.033822 38.650760 -46.668612 -9.361311 14.442595 36.692539 1.997575 2.486305 1.825461 1.017913 0.556651 1.630952 1.154775 1.310657 2.209571 1.504773 2.225988 0.686631 1.449878 2.093499 1.437599
+1 -0.001366 1 1 -0.286785 0.780699 1.921300 2.005410 1.915803 -0.850713 -0.545415 -1.190010 -1.121672 2.320753 0.459973 -2.266788 55.756725 53.283940 43.187620 4.325991 -43.061081 1.711156 1.403207 0.692531 1.617564 1.145158 1.679170 1.559143 0.265811 0.492271 1.844274 2.212906 1.311225 0.514711 0.990708 2.335606
+1 0.025760 1 1 -2.113527 -0.064783 -0.244503 -0.153438 -1.152056 0.602481 -1.029645 -1.356365 2.117217 0.807852 1.177030 -0.260927 58.142015 -57.162043 27.538968 -52.565296 35.077052 1.975220 0.277426 2.195225 1.144804 2.477498 2.306621 1.370074 1.828348 2.289843 0.634234 0.574200 1.836662 0.278740 1.787187 1.251663
+1 0.055715 1 1 1.268753 0.373344 -2.115313 -1.810134 0.261371 0.907463 -2.270451 1.456056 0.496315 0.637222 -1.471439 0.146308 -27.582765 66.469440 -48.126618 -64.064692 -35.281222 1.052618 1.094604 0.251469 2.440254 1.850220 0.901405 2.170986 1.007761 0.930987 2.097092 1.073270 1.694906 0.532855 2.195965 2.338614
+1 -0.084673 1 1 0.375115 -0.625953 -2.333855 0.818980 -0.285878 1.883382 0.892779 0.686067 -0.486511 -0.792708 -1.124774 2.024890 -17.617707 -0.794074 4.002622 72.064314 -65.078298 1.810636 1.614142 2.137187 2.201685 1.725083 1.468704 1.251372 0.302895 0.513794 1.334146 0.997561 0.507638 1.370136 0.619411 1.196421
+1 -0.010984 1 1 2.173953 -2.239331 1.419480 -1.624154 1.704414 -0.527001 1.986727 -1.067082 0.908071 -1.476012 -1.319055 -2.274989 18.649044 -65.510426 -33.733554 40.153189 4.639874 1.110310 0.977559 1.836109 2.232264 0.408035 1.336846 1.369411 1.934529 0.382524 2.322462 2.115707 1.189888 1.953552 0.602007 1.179744
+1 -0.006974 1 1 -2.314367 -1.516754 1.945739 -1.936968 -1.439456 0.470888 2.116380 0.890705 -1.177002 0.743071 0.970238 1.929522 -37.562773 32.479499 32.939378 -37.874520 42.938157 1.549081 2.145710 1.448485 1.186402 1.852358 0.834354 2.494056 1.599678 2.031570 2.349712 1.105065 0.577098 1.035161 2.447477 1.753208
+1 -0.021853 1 1 -0.465768 -0.884338 -0.200606 -2.229113 -1.205969 -0.740744 0.452688 -2.189103 2.079235 -1.376206 -1.486607 -0.321854 13.523042 31.762373 -19.801156 51.973274 64.808127 0.327828 1.054570 2.402372 1.911320 1.809643 0.667362 1.604194 1.429512 1.804312 1.078025 0.613780 1.045141 1.437395 1.542286 0.456014
+1 -0.027623 1 1 0.464470 -2.082779 -1.634159 -1.515882 -2.251221 -0.497143 -0.419311 -2.336930 0.983464 -1.984171 1.607073 -1.341274 40.717173 33.532523 31.118677 -38.389390 -60.483065 1.541849 2.109736 2.085280 0.558441 2.462989 1.458577 2.047557 1.037354 1.064760 0.419156 1.507709 2.067932 1.484620 1.007463 0.436945
+1 -0.029925 1 1 -2.090847 -0.579407 -2.292549 2.331252 -2.165372 0.371600 1.563268 2.270306 0.820313 -1.450313 1.779591 0.058364 24.023121 -43.399659 31.938723 -55.885463 33.029405 1.003161 2.382012 1.721116 2.291360 1.384183 0.462253 1.336787 0.381087 0.678220 1.847930 0.660490 0.853008 1.000140 1.100611 2.216980
+1 -0.064026 1 1 -2.024913 0.166743 -1.413493 -1.433003 0.538569 -0.769986 -0.940800 -1.960971 0.404460 -2.212595 -1.627184 -2.094330 68.230266 -3.919263 -21.058909 62.917816 -40.271497 0.729369 2.002708 1.013433 1.761248 1.790469 2.413262 0.444994 1.516856 0.549433 1.819585 1.261668 2.360936 0.755675 0.882750 1.384438
+1 0.004901 1 1 -0.057835 -1.277176 -0.562503 -0.943672 1.608873 0.638861 -2.197587 0.857189 0.996804 0.750070 0.787633 0.646209 -38.869010 -21.452439 48.857850 53.891387 52.534096 1.983232 2.173282 1.356392 1.386428 2.189663 2.170074 1.433698 2.415651 2.353813 0.280363 2.062984 1.570188 1.399239 1.507527 1.257765
+1 0.007532 1 1 1.631883 0.950806 0.479537 1.387716 1.727369 -1.141689 0.484305 1.425118 -1.116060 -2.316154 1.442760 -1.477148 -49.408943 -16.112960 -60.518487 15.788198 2.244603 0.250661 2.366876 1.588483 0.640451 1.555414 0.595559 0.808189 1.484089 1.080131 2.267762 0.775071 0.615697 1.762416 1.169784 1.556820
+1 -0.004914 1 1 0.954106 -0.603177 -1.242353 0.369074 1.521058 -0.286377 -1.786555 0.704156 1.943173 2.055193 -0.182389 2.349068 12.341562 -25.374889 -25.756316 13.590273 -38.286782 1.585791 0.382269 0.300473 0.305969 0.424992 0.592967 2.252918 1.043203 0.369078 1.346832 0.459261 0.546739 1.549482 2.141792 0.845540
+1 -0.069205 1 1 0.803921 1.078203 2.219629 2.028588 0.343902 -2.136125 1.844529 -1.810875 1.936962 1.338070 1.426416 1.846594 -2.733927 -49.105222 -11.473180 70.268859 58.715398 1.070347 2.078573 0.324685 2.223003 2.252521 1.113773 0.680712 0.973394 1.586871 0.532436 1.893992 0.819994 1.895199 0.857511 2.432508
+1 0.006118 1 1 0.724962 -1.803913 1.141212 0.923119 1.675278 -0.123135 -0.788972 0.414369 -0.609121 -2.188918 0.475684 -2.100435 -48.065813 57.888127 25.749605 23.610224 67.030722 0.405097 1.472398 0.334511 0.883840 1.690623 0.545312 2.307984 1.781257 0.587412 1.128420 1.603857 0.265471 1.512811 2.311286 1.030180
+1 0.038618 1 1 0.277565 -0.223076 1.823090 0.715318 1.048231 -2.011721 0.401014 1.117720 1.936317 -0.072944 -0.740555 -1.083039 41.964608 -0.833405 -57.034048 -71.251175 -68.505527 1.789184 1.074416 0.711961 1.936813 0.512113 2.331173 2.265422 1.951463 1.486096 1.059836 0.914634 1.756908 0.845066 0.279812 1.796760
+1 0.004161 1 1 1.348800 -2.023260 -0.337198 1.725085 -1.821870 0.930098 1.164875 -1.914731 0.017733 1.159309 -1.217410 0.179174 4.855099 -0.356054 15.804080 -30.820247 -45.885037 0.777850 2.321189 0.971673 1.912594 0.712288 0.669108 1.700214 1.992218 2.460996 1.706789 2.261266 1.854809 1.529869 1.016056 0.855417
+1 0.008353 1 1 1.615464 -1.683125 0.186191 0.286655 1.752176 1.108162 1.518890 0.967255 -1.093911 -2.338922 0.489562 0.229579 -28.931775 43.651832 6.338416 29.754715 -12.498019 0.561937 0.480345 1.655009 0.489841 1.499766 1.312051 0.887482 2.164762 2.150358 0.822563 2.315231 2.080966 2.293886 1.083430 1.450034
+1 -0.038821 1 1 -0.484150 1.193831 -0.628118 -1.031836 -0.478992 -1.659909 -0.753166 -0.977059 1.252865 1.940657 2.178394 1.723465 -24.725543 -62.203309 48.991051 42.597312 -16.972921 1.916864 0.491689 1.059614 1.684027 2.192127 0.822728 0.583453 2.088552 1.546570 0.449016 1.619359 2.064327 1.643166 1.700095 2.245514
+1 0.004069 1 1 -1.789088 0.549202 -1.136671 -0.011965 1.531691 -0.642035 0.696419 -0.864328 1.539398 1.653301 -1.922769 1.583028 -6.179938 -66.215466 -33.331674 44.560695 -18.406464 0.513383 1.181359 0.352259 2.163910 1.331630 1.460919 0.914713 0.826093 0.894253 1.218302 0.257722 1.781208 2.020885 0.508099 2.361690
+1 -0.027882 1 1 2.171917 1.236559 1.214059 0.038978 0.079738 1.840894 -1.634283 1.128300 0.688916 0.279185 -1.277427 -0.080353 62.316990 61.643649 -5.184166 19.728951 -65.515612 1.811610 2.221326 1.081131 1.064422 1.493317 0.922992 0.476170 1.235946 2.051547 0.605837 0.295987 1.396986 1.892359 0.379216 0.727216
+1 -0.011264 1 1 -1.568154 0.430115 0.130435 0.959679 -1.180192 -1.044403 0.360623 0.864912 -1.137483 0.488121 -0.412375 1.130131 -48.749305 -29.568234 -3.309928 20.032495 -63.860026 0.693040 1.180594 0.993380 2.230119 0.364059 2.485829 0.571492 1.308512 2.160682 1.080910 1.846828 2.392993 1.783403 0.650318 0.886462
+1 -0.002393 1 1 2.108660 -1.625990 -0.865963 2.333555 -1.151382 -2.201740 1.747034 -0.501393 -1.154180 -2.111246 0.581247 0.233371 49.820447 32.248082 43.518345 12.816925 14.060687 2.394576 1.382138 2.101905 0.973600 0.539092 1.265208 1.096119 0.966498 0.439580 0.528299 2.121526 2.237798 1.162878 2.483383 2.222440
+1 -0.006318 1 1 -1.650030 0.350167 -0.520657 0.223677 -1.146116 1.467686 -1.948486 -1.812693 -0.345117 0.574280 0.959306 1.975239 -29.804694 72.511807 -44.060314 28.304728 67.568679 1.026757 0.712297 0.831114 2.032428 1.022388 1.518727 0.488604 0.966423 1.428365 0.529509 2.201657 1.248363 1.488952 1.819986 1.256060
+1 -0.003590 1 1 -1.066647 -1.206729 0.631834 2.228835 1.256466 1.199860 1.737882 1.193490 -1.654544 -0.117568 -1.471208 -0.694472 19.044453 -19.885148 -9.689298 51.962495 33.650375 2.302789 2.225269 2.095342 0.913504 0.756915 1.470822 0.861876 1.551979 1.355338 1.663957 2.373191 1.975696 1.525901 1.815098 2.355837
+1 0.016103 1 1 -1.624011 -0.597255 -0.680050 -2.057043 2.070772 -2.246998 -0.216794 -0.982878 -2.311660 1.573441 -1.110206 1.830314 -12.172778 12.117169 -46.745316 51.470144 8.711196 1.511117 0.839903 1.255872 1.690835 1.868650 2.403796 1.103548 2.074032 0.512184 1.277533 1.243447 2.108928 2.006549 0.324857 0.617994
+1 -0.041796 1 1 -0.768983 1.784274 -1.352878 -0.546735 0.188444 0.460794 2.107532 -1.744721 1.665083 -1.834406 2.304450 -0.238596 5.053992 42.442002 72.722011 38.835164 52.597094 2.115351 1.957717 0.848269 2.362329 1.656257 1.212783 1.985023 0.775659 1.494020 1.502659 0.434477 0.258919 1.647051 1.743926 0.921550
+1 0.002875 1 1 0.966559 1.346737 1.012788 0.778446 1.743252 1.918635 -0.387441 0.808344 0.025744 -0.864047 1.552928 -1.870752 -21.305731 -35.424949 -37.109639 -1.695053 11.236585 1.424254 1.192152 1.745676 1.082831 0.383572 1.937674 1.489677 0.502227 0.425954 1.010763 1.896811 0.951650 0.627432 0.999934 2.145449
+1 0.032947 1 1 -2.002960 1.563675 -0.303550 1.746061 2.005943 1.455407 -0.994915 -1.975961 -1.769560 -1.107407 1.739746 -0.456347 62.047308 29.100505 -57.811150 68.006757 -10.427416 0.571409 2.163184 0.380354 1.858239 0.678733 1.469687 2.035389 1.277393 1.150983 0.572786 0.561195 1.505772 1.002768 0.266010 1.580753
+1 0.043731 1 1 1.597573 -0.789804 0.572164 -1.621133 0.652982 -0.488727 -0.340056 0.804010 -2.132138 -1.835393 -0.148738 -2.276550 -66.303247 -8.669586 -59.729270 -69.845999 -1.699825 0.340603 2.007181 1.942808 2.271137 1.244180 0.926056 2.480222 0.847519 1.007640 1.155403 0.611569 2.142905 1.546350 1.247113 0.719416
+1 0.001294 1 1 -0.195703 0.069900 1.418125 -0.833397 -1.683060 1.282291 1.714809 -0.179076 1.494205 0.775727 -1.544366 -0.311684 54.457605 -31.039553 18.237837 73.329674 51.838511 2.122771 0.658352 0.917065 2.113866 1.739658 1.182721 0.744407 0.490189 0.599163 0.628758 0.782870 1.188761 1.002531 0.792588 0.273211
+1 0.003661 1 1 1.523562 -0.620943 1.759523 2.067088 1.816220 -1.643139 -1.646942 0.421979 0.058956 1.269517 -0.931816 -1.765812 19.685142 -51.822780 64.537456 31.028048 -61.597681 1.791533 2.304254 2.098889 2.032834 1.091196 1.480678 2.248324 0.324351 1.111208 0.324408 2.079263 0.680730 1.284974 0.303523 2.063720
+1 -0.018255 1 1 -0.139644 -0.227720 -0.828658 -2.142517 -1.924377 -1.886068 1.087677 1.229829 1.196468 1.278421 -2.079232 1.416480 -6.790123 28.396702 -36.631433 -64.488885 35.315876 1.434023 1.123487 1.953441 0.985876 2.112233 1.294706 1.872213 1.526314 2.001044 2.293863 0.709724 0.336419 1.438474 1.686236 1.075645
+1 -0.021647 1 1 -0.059803 -1.369261 2.142287 -1.951768 -0.422984 1.910546 0.324246 2.083897 1.588955 0.467032 -1.430043 -1.544201 -71.697275 -66.094883 43.295689 20.647464 71.928489 2.156654 0.885165 1.473611 0.476504 2.351967 0.760065 0.417220 0.467039 0.779715 2.163667 1.752024 2.014436 2.373143 1.159064 1.379819
+1 0.004801 1 1 -0.040582 1.237168 2.030036 1.118923 -1.402689 1.090594 -1.579716 -0.680188 0.338451 0.490288 -1.690680 0.443235 -26.879207 41.160922 -8.391111 -29.395708 46.334055 0.421973 1.592735 2.348024 1.980534 1.832918 0.356023 2.424251 0.636093 0.323384 0.620809 2.187339 1.359144 0.389765 0.283402 1.387703
+1 0.007026 1 1 -0.949823 1.900627 -1.445930 0.050036 2.147702 -0.466029 -0.551666 2.122812 0.603850 -1.578796 0.636478 0.168747 -23.077710 32.925762 33.281660 14.859072 -13.576149 1.009873 0.439005 2.108839 0.513120 1.251239 0.321511 0.643479 0.695130 0.299798 2.457812 2.197562 2.181838 1.148130 2.126628 2.488494
+1 0.002384 1 1 1.758735 -1.750773 -1.086138 1.066418 2.077640 0.101059 2.037034 0.915517 1.143698 0.288970 -1.759826 2.266946 28.591969 -54.772228 -6.827663 -2.529186 -58.037709 1.528304 1.697062 0.774760 2.137645 0.895132 2.475432 1.340107 2.169455 2.271547 1.397301 0.444599 1.626078 2.493318 0.441932 1.797617
+1 -0.002834 1 1 1.275614 -2.127042 -1.006127 -1.928800 -0.808752 -2.159887 -1.696916 -0.687766 0.212744 -1.108108 -0.604243 -0.320970 36.618846 2.940950 -71.460054 20.865408 -15.095907 0.371424 0.269369 1.792273 1.228394 1.121624 2.135968 1.968758 1.919395 0.271022 0.323581 1.671308 2.178550 2.146495 1.144812 0.352119
+1 0.010472 1 1 -0.189150 1.819497 1.591468 0.280875 -1.144657 -2.274434 0.486360 -1.743960 0.328058 0.170798 0.760474 1.294515 -5.927969 -31.369799 17.794368 -30.061436 -42.550232 2.248811 1.767655 1.482779 1.574332 1.293297 0.693685 0.763273 0.333047 1.013406 1.321895 2.087887 1.619487 1.973213 0.296066 0.478110
+1 0.032077 1 1 1.362050 -0.815113 -0.695462 -1.907555 -1.889650 2.145502 0.251096 -2.121931 0.066405 -0.771862 0.530422 -1.029152 70.545259 54.163702 -20.666990 49.906370 -23.643567 0.963584 0.960090 0.725470 1.718720 0.284598 1.241026 1.925898 1.559108 1.927924 1.866892 2.105991 2.134934 0.334228 0.621731 1.925556
+1 0.065018 1 1 1.615165 -1.987829 1.397228 1.370482 -0.465927 1.149907 0.986804 2.313270 1.913728 1.965525 0.734138 1.619209 0.142085 -11.976927 3.780075 -68.273777 22.631929 0.997396 2.229132 1.771896 0.751334 2.164561 1.028717 2.152858 2.325501 1.446220 1.370980 1.316424 2.382384 1.230740 2.292770 0.338138
+1 0.012090 1 1 0.779947 -1.302889 0.817304 -0.186594 -2.351352 -1.082065 -1.162756 -0.169458 -1.798887 0.791174 -1.103465 2.031977 24.139630 -35.236200 -14.814516 12.431726 -9.975749 1.938801 2.421592 0.945021 1.710995 0.937372 1.416014 2.198005 0.618892 1.470540 0.617676 1.278255 2.137722 2.189012 2.480066 0.467689
+1 -0.005879 1 1 -2.193889 1.749847 -0.345486 -0.912198 -1.907502 -0.999899 -0.921608 0.149299 2.281479 0.111656 1.067715 0.301241 58.935230 74.413880 -25.919113 -22.524073 37.902791 1.108040 1.080959 0.424467 0.764089 0.546225 1.901768 1.021819 0.956103 1.219659 0.559217 2.005287 1.611970 1.631459 0.686936 2.090957
+1 0.002642 1 1 0.876872 1.945572 -0.030478 1.411907 -1.663412 1.635544 1.213870 1.580237 0.015471 0.839897 -2.172877 1.479965 56.771185 3.301338 -14.404355 6.012818 -42.573762 0.816615 1.346919 1.910886 1.261262 2.280136 1.744948 2.346776 1.259846 0.980544 0.256748 1.158951 1.735161 2.099511 1.233303 0.368557
+1 -0.024607 1 1 -0.957514 -0.123929 -0.002763 0.685881 1.097493 1.274421 1.392349 -0.514100 2.047073 0.003228 -2.289475 2.166215 -10.827601 -29.488373 -11.090340 54.660822 -65.565441 0.499500 1.851809 0.600673 1.258347 0.534163 1.673537 1.389162 0.889469 1.800891 2.071216 0.419657 0.918471 0.999831 0.417322 2.180075
+1 -0.039809 1 1 0.223252 1.133099 1.223399 1.518139 -2.223189 -0.599335 2.056452 2.122052 1.964405 0.756623 -2.172872 1.551588 -26.271129 61.131694 -59.620925 -48.890924 -9.762785 1.628065 2.146299 2.346531 1.651871 1.742463 1.084786 1.749856 1.572683 0.581159 1.781743 1.996185 1.622386 1.184197 0.800460 2.073522
+1 -0.009638 1 1 0.518517 1.509148 2.170896 -1.777808 1.631333 1.140275 -0.679669 -0.370597 1.157712 0.219470 -1.169221 -0.437697 -10.758242 -63.778847 -31.082452 47.222612 20.444082 0.680258 2.340066 0.994041 2.093315 0.596897 0.802877 2.196681 0.870277 1.003314 0.442268 0.690827 2.221620 1.519139 0.674162 1.143329
+1 0.007446 1 1 -0.391418 -0.071989 1.159825 -1.966326 -0.059826 -1.751310 -0.684899 1.273709 -1.161493 2.213023 -0.609802 0.504402 -3.362281 40.145887 31.923969 -3.856538 -16.827012 0.451031 1.726326 2.114288 2.084246 1.174597 1.457766 1.917477 1.784342 0.693246 2.383379 2.196873 1.835829 2.033372 1.139451 0.257341
+1 -0.008775 1 1 -0.453957 -0.290412 1.086302 1.674275 1.862447 -2.256020 -1.054013 -0.920481 0.246714 -0.385479 0.793032 1.854088 -43.819496 25.729591 -12.756170 -42.950768 -73.560663 0.863999 1.234664 0.744557 0.764486 0.468506 0.680365 1.899795 1.601598 0.551092 0.445490 0.851828 1.419392 0.470347 2.366402 0.376847
+1 -0.000409 1 1 0.801763 -2.208800 0.892917 -1.702567 -1.422309 1.207868 -0.329030 2.332739 -0.735125 0.635419 1.205900 -0.428491 -35.784117 -73.648120 -3.953957 -4.153159 -52.142445 0.503871 1.063887 1.497167 0.392037 2.471085 0.274080 2.209844 1.606285 0.585643 0.646914 2.180280 1.957544 2.436461 1.096712 1.940529
+1 -0.039883 1 1 -0.259522 1.889178 -0.663947 -0.020761 -0.216676 1.007252 1.979375 -2.107920 -0.074570 0.194635 0.827032 -1.624282 -13.897277 -21.526554 3.214876 32.414967 -1.645135 0.628216 0.668562 1.516050 0.496095 0.860355 0.728141 1.619027 0.993985 1.154949 1.979175 1.485956 0.963164 0.644046 1.234791 0.636873
+1 0.061831 1 1 0.425179 1.998749 -1.650141 -1.516633 -0.747900 -2.012792 1.239636 1.094201 -2.217725 1.687014 -0.794555 0.827928 -22.011413 -45.824631 -74.580438 -73.426818 -34.538099 1.647514 0.510487 1.997916 1.479342 2.293627 1.236971 1.275357 0.676368 2.219458 1.182303 0.461997 1.533155 2.231187 0.312105 2.300199
+1 -0.026193 1 1 -2.222238 1.235729 1.392655 -0.090344 -1.030163 -0.637728 -2.320944 1.053072 -0.749357 1.780334 -1.587464 1.035649 -45.050330 39.105975 -45.879251 57.427536 -65.402624 1.046445 0.859092 2.011680 1.052608 0.931876 1.284893 1.205494 0.982015 2.471813 1.266844 1.594339 2.306078 1.246398 2.204904 1.823835
+1 0.006396 1 1 -1.624771 0.762009 -1.190078 -2.256608 -1.507377 -0.683158 2.254703 -2.235960 1.527688 -1.960624 1.531092 -1.297654 -23.262601 -74.534152 -45.500584 -28.318466 1.543645 1.285656 0.515032 1.885820 0.725631 2.182177 2.356512 0.645468 0.387186 1.939689 1.610538 2.314646 1.255382 2.453912 1.904101 1.976511
+1 0.005815 1 1 1.105865 0.610415 0.381465 -2.282232 1.365959 -1.084062 -1.737907 -1.620755 2.289418 1.589447 -0.704871 0.183435 34.629506 18.103322 62.527560 0.708263 53.769704 0.736184 1.787723 1.254205 0.671220 1.198740 2.231513 1.290491 0.785175 1.686456 0.259569 1.333027 2.435090 0.561682 0.694621 0.746453
+1 -0.023096 1 1 1.547075 -1.280269 -0.709479 -1.872059 0.922840 1.701765 2.074382 1.877244 1.392135 0.609741 -1.526445 -0.719911 59.650813 -48.792348 -2.995937 47.281284 -43.462740 1.700848 1.396216 2.444306 2.453867 1.142603 1.481262 0.825422 0.866886 0.250166 0.796732 2.416864 2.483972 0.863355 1.657179 0.963097
+1 0.015851 1 1 1.906745 -2.293737 1.214818 -1.331941 -2.077168 -1.594121 2.257515 -2.105832 2.029257 2.163261 1.851667 0.354541 73.798608 -16.788507 -14.430379 18.622867 -55.478383 0.997216 1.462002 1.119380 0.415884 0.504841 1.613365 0.330115 1.237832 2.247233 2.252335 2.493822 2.167620 0.684122 2.046380 1.504310
+1 0.037424 1 1 0.612837 -1.333036 -1.647850 -0.705193 -0.519878 -0.813174 -1.091570 -0.680807 -0.634860 -1.250354 -2.151192 -1.640792 3.628651 -63.256446 48.914640 -41.647664 -72.281798 1.522216 0.635987 0.787217 2.257763 1.479385 0.776774 2.236582 0.987322 1.665451 0.489574 1.512521 1.936988 1.203804 1.840949 0.321172
+1 -0.008654 1 1 0.633512 2.156991 0.138465 -0.734883 -0.014982 -2.050783 -1.093052 -2.027887 2.012221 -1.411341 1.754201 2.142111 -5.943346 10.185096 30.916078 6.527177 52.265846 1.856076 0.314356 1.876046 0.700086 0.338288 1.354401 1.665844 0.344534 0.585949 1.286884 0.905527 1.691797 2.275264 0.863074 1.440890
+1 0.000071 1 1 -0.565708 1.749704 1.968908 1.034089 0.646382 1.678728 1.313117 1.439103 -1.681387 1.130046 1.763699 1.563718 13.173472 6.537101 69.060254 -4.318047 26.576201 0.868256 0.781815 1.468315 1.471462 0.361087 2.041135 1.107864 0.368136 1.262663 1.073970 2.209770 0.358277 2.056870 2.311026 1.162943
+1 -0.054605 1 1 0.282489 -2.288887 -2.093068 -0.204094 0.414996 0.509870 2.257875 -0.755445 -1.580823 -0.439368 -0.137495 -1.810218 -36.793076 68.767033 17.531104 45.257267 -11.111695 1.311124 1.053788 0.514842 0.956121 1.520180 2.412975 2.366252 2.339061 2.094225 2.391253 1.783653 0.351059 2.241946 1.133994 0.790603
+1 0.010885 1 1 -1.374953 0.725336 -0.220069 0.519724 -1.765796 0.889354 -0.324653 0.503974 2.123981 1.401817 -1.605470 0.012971 39.290805 60.565192 19.181769 37.984359 3.121953 0.935074 1.036337 1.965043 2.478909 1.273325 0.274445 1.589107 2.115643 2.360648 0.405643 1.639287 1.743852 1.924633 0.563767 1.987066
+1 -0.007474 1 1 -0.000337 -0.950691 1.446052 2.002644 -2.153948 -0.827911 0.977631 -1.057187 2.277462 -1.426744 2.066297 -2.053422 53.454117 53.343266 -9.728632 -9.118786 40.569493 0.647126 1.239231 1.004017 1.017268 0.969728 0.714919 2.144502 1.399787 1.714478 0.976159 0.801344 1.186854 0.454201 1.000662 0.882965
+1 -0.011005 1 1 2.109101 1.075825 -0.050304 -1.938102 -1.647734 1.240680 -0.212440 1.507227 -1.847388 0.884711 1.747864 -0.680173 18.724426 1.422230 53.411061 -70.289879 37.995641 2.016194 0.423801 0.823201 1.787764 1.940687 0.376769 2.363971 2.269185 2.185954 0.571245 1.657922 2.199345 0.637969 0.337765 1.562907
+1 -0.005211 1 1 -1.461374 -0.337609 -0.476034 0.929805 0.950493 -0.062606 -1.360974 0.044720 2.344322 0.735872 -2.213571 0.827301 -57.646433 -13.599819 27.836429 -3.131875 12.570394 2.434270 0.279141 1.769727 0.305460 0.867932 2.075194 2.039928 1.073676 1.767271 1.778731 0.878304 0.903026 2.413131 0.496681 1.709465
+1 -0.059219 1 1 1.980089 0.458793 1.470974 1.467280 0.650523 0.601565 -2.280073 -0.046887 -1.063399 1.549386 -0.132364 -0.390785 36.698694 -5.056643 62.994652 51.112302 -5.539742 2.028276 0.984901 1.488179 2.321060 1.052204 0.887720 1.666975 1.352539 1.872003 0.255768 0.443381 1.407274 1.547568 1.484055 0.503989
+1 0.029299 1 1 -0.869495 -0.480678 -1.713054 1.394190 2.152573 1.284307 -2.110638 1.368642 1.587644 1.995371 -1.875925 1.918379 1.245551 -66.031614 56.668002 69.114481 7.077523 1.403909 1.249552 1.221281 0.824131 1.670517 2.385231 1.832969 1.214706 0.572868 1.946327 0.675246 1.360604 2.427646 1.441540 1.470190
+1 0.040859 1 1 0.278423 0.054434 0.669822 -0.196303 -0.590920 2.126412 -0.144581 1.617138 -1.826998 -0.428998 -0.221150 1.207061 7.843287 -27.873014 -11.738999 -47.358074 -47.150943 1.136393 0.601672 2.301820 1.683644 0.260565 2.317650 2.236174 0.874490 2.053442 0.949917 0.747602 2.438434 0.513482 0.587376 0.524772
+1 -0.055953 1 1 0.163221 0.650000 1.228147 1.206500 0.241290 -2.003620 -0.118118 -1.294500 0.445616 1.481556 0.252593 -0.533502 35.347340 -67.260455 -46.459145 61.147763 60.454556 0.770762 2.439065 2.111252 0.570332 2.064314 1.418383 1.520397 1.566154 1.094810 1.469046 0.250167 0.799989 0.919468 2.004687 0.526472
+1 -0.033230 1 1 -0.447376 1.922520 -1.053043 1.231869 -2.209717 -0.370862 1.413266 2.328404 1.801679 -0.986889 0.962461 -1.550871 -40.022726 -61.954173 36.214044 -50.563719 -74.420075 2.451892 1.696673 0.974617 1.887770 1.993813 2.273896 0.374181 1.610243 1.853287 0.702651 0.705421 2.263946 1.890849 1.999116 1.393082
+1 -0.017571 1 1 0.986632 -0.570116 -1.647966 2.061212 2.025502 0.321473 -2.107376 -0.353365 -1.400659 2.226777 -0.350687 1.207576 -16.765562 71.201053 -23.903729 -49.976005 53.292221 1.860365 0.408735 1.853489 1.836795 0.256743 1.083178 1.719181 1.267683 2.197388 1.499356 1.175447 2.229442 2.473939 0.985663 0.793526
+1 -0.069797 1 1 -1.666515 1.320170 2.163178 0.451705 0.152379 2.212775 -0.057873 -1.921559 -1.638033 -0.642971 -0.912750 -1.760556 -18.186901 32.754988 13.079304 73.855056 31.929453 0.449872 2.495546 1.893527 2.009059 1.999574 2.339011 1.258645 1.042186 1.270330 1.684386 1.481035 1.511206 2.333914 1.096171 1.841013
+1 -0.037638 1 1 -2.272789 -0.140468 0.056724 1.461605 -0.484952 1.845056 2.337445 -1.754361 -0.123392 -0.404372 -1.007593 1.716287 35.364992 -70.579623 -31.716882 34.360734 0.857990 1.678573 0.518936 2.265074 0.598192 2.308184 0.639814 2.108820 2.434952 0.490244 1.534747 1.984797 1.482098 1.372156 0.830010 1.471119
+1 -0.007519 1 1 2.210836 0.336944 -1.281365 -0.283037 -2.208105 -1.558685 -0.656313 1.046588 -1.338238 0.463146 -0.766358 -1.213578 -44.261871 -59.264464 -57.843214 -20.897464 -73.674484 1.419313 1.391300 0.829602 1.375651 1.058818 1.811061 2.001415 1.786160 1.986472 0.380191 1.366396 0.769262 1.984741 0.550071 1.300042
+1 -0.000037 1 1 -0.043559 -1.668652 -1.607503 -1.177279 0.785712 1.346658 -0.328091 -0.726520 -0.814157 1.245487 0.468091 2.226126 -59.347306 49.819868 22.517166 -3.990543 -19.060426 2.146287 2.152406 1.488574 2.208052 0.726914 1.241299 2.009025 1.436498 2.221305 0.728134 1.499795 1.798667 0.696767 0.809077 0.660286
+1 0.023763 1 1 -0.135959 0.447857 1.450895 -1.415257 1.908671 1.802439 -2.353382 -2.209803 -1.816151 -1.898797 -0.788211 -0.937961 -43.788615 -55.252992 12.971226 57.398579 47.913038 2.491497 1.337866 0.508925 0.494429 2.119971 0.851870 2.132623 1.989171 0.751723 1.966007 0.679634 0.862462 2.392284 1.117891 2.386896
+1 -0.011199 1 1 0.972734 1.466021 -1.668301 -0.426251 -1.169641 1.924684 2.328633 0.944598 -0.180384 -1.644667 0.960317 0.111106 39.983370 0.500749 16.083248 11.153083 -50.129567 1.710551 2.484452 2.183623 1.906068 1.280651 1.904204 1.452102 1.228232 0.638832 1.349949 1.091368 2.112955 2.188981 1.952297 1.999830
+1 0.024375 1 1 -1.379404 1.318923 0.068405 -0.142274 -2.024870 0.883561 1.265266 -1.691986 2.065214 -1.410747 2.314261 -0.268466 -74.930070 50.312481 51.873939 45.292124 -25.278607 0.511762 0.932082 2.499529 1.340082 1.763084 1.152089 1.163256 2.089137 2.369618 0.420746 1.232563 1.435207 0.773722 0.441957 2.228306
+1 0.008370 1 1 2.002461 -0.514180 0.697933 1.021915 -1.338944 -1.982930 -1.086186 0.270565 -0.061456 -0.875573 1.041792 -1.837537 48.362756 -17.167804 60.724198 -8.412097 67.891743 1.472924 2.429326 0.434354 0.433395 2.318903 0.796000 1.376502 1.869534 1.510894 1.600985 1.497960 2.465644 1.085851 1.646782 1.715106
+1 0.000956 1 1 -0.608782 -1.206897 -2.189222 0.075496 1.224892 -1.661695 2.214979 -0.725025 0.750005 -0.311049 -1.760449 1.217328 -49.566939 28.457474 -65.232721 -16.333459 -16.438554 1.633440 2.478310 2.450929 1.258784 1.140338 1.651560 1.015909 0.624104 1.315022 1.322808 1.677657 0.881164 1.716374 1.349787 0.623878
+1 -0.046063 1 1 -0.974864 0.437341 -0.932007 -0.265528 -0.098424 -0.166896 -1.151425 1.776941 -2.082995 -0.559260 1.740525 -1.505332 22.393740 21.589196 -0.381160 43.843425 -73.552432 0.689012 0.979972 1.889236 1.882613 0.828928 1.298396 0.885936 0.932846 1.836467 1.507684 1.641135 1.301535 1.893527 2.004639 1.963608
+1 0.019786 1 1 -0.779083 1.683075 -1.022428 2.126991 0.155986 1.563333 -1.350851 0.537926 -2.155884 -0.387621 -2.217623 -1.297984 -49.983975 69.325128 -52.577079 -12.959830 -15.868931 1.238149 0.827102 2.110474 0.985613 2.193224 1.264733 2.122438 1.808338 1.236208 1.954267 1.372788 2.442185 0.549374 0.835382 1.760005
+1 -0.026358 1 1 1.532469 -1.712005 0.181079 -0.814865 -1.236474 0.212974 -1.963345 -1.791600 0.748820 -1.368842 -0.243330 0.712243 37.986734 43.036437 13.391121 64.565658 55.009014 0.422571 0.401079 1.437585 2.489947 2.290689 1.367187 0.564571 1.991750 1.342830 0.691089 2.128848 1.551856 1.549026 1.228193 2.247430
+1 -0.006584 1 1 1.680326 -0.105913 1.205499 2.268658 1.393996 -1.111349 1.460018 1.115421 1.000957 -0.145307 -1.157363 0.944485 -66.222803 -6.647470 25.978706 -25.885364 -55.312266 2.376290 2.310188 0.571762 1.362109 0.713113 1.036509 0.356460 0.772818 1.009386 1.251758 2.297516 1.351716 1.532407 0.920399 1.889589
+1 0.010291 1 1 2.224695 2.353102 2.210436 -1.678849 1.363742 -0.654977 -0.057214 -0.272774 0.642601 -0.599619 2.006152 0.259021 -28.144894 68.771133 -63.575324 -60.478156 -56.361743 1.047855 2.055775 1.909504 0.536051 1.915976 1.309522 1.134598 1.932750 1.981263 0.594260 1.478342 1.242177 1.017599 2.037605 0.268733
+1 -0.003991 1 1 0.660361 1.014118 -0.423018 1.338154 -1.873951 2.109342 0.410635 -2.113117 2.120404 -2.168327 -2.160101 -0.569498 -21.766061 27.811068 20.614315 -35.215477 33.471047 2.093315 0.595753 1.815475 1.939403 1.292696 1.836105 2.169487 0.560551 1.937655 1.172040 1.225326 1.306150 0.715834 1.772097 1.883593
+1 0.008441 1 1 -1.443495 -1.441299 -2.235874 -1.746420 1.388292 1.985154 0.765641 -1.405986 2.231100 1.614492 0.836160 0.996792 17.077097 64.771465 64.006348 -45.306105 -59.713217 2.124410 1.203783 1.475467 2.420888 0.358521 1.670198 1.520954 1.918945 1.704117 2.341959 1.304557 0.945126 1.224921 1.252908 1.382544
+1 0.073948 1 1 2.147746 0.274319 1.755327 2.222892 0.334057 2.047499 -2.253600 1.929418 1.774097 1.958261 1.164294 -2.263059 -48.938216 -54.588107 -62.317650 -72.748093 -27.206541 0.469895 1.521639 2.186468 2.475051 1.680063 0.827525 2.461102 1.241777 1.044990 1.155261 0.470733 2.104578 0.893400 0.376224 2.203087
+1 0.033164 1 1 -1.774047 -1.129658 0.058506 -1.578604 -0.854032 0.214148 -1.076827 2.056391 1.107274 0.728624 -1.507398 -1.034264 35.807963 24.427098 -3.760577 -54.023620 -24.981913 1.059737 1.493826 0.477975 2.320660 1.085723 1.749465 1.757942 2.480424 1.987597 1.297490 1.412370 1.711363 0.382229 1.876459 0.890117
+1 -0.061026 1 1 1.052273 -0.047458 -1.225072 -1.359440 2.264366 -0.055219 0.266898 -0.447739 0.531895 0.164430 2.112561 -2.045634 19.743137 22.906510 -60.291594 -70.823163 -74.904874 1.731655 1.668882 1.895534 1.988041 2.012085 1.116257 1.927540 2.161805 1.948321 0.438057 1.917869 1.630287 1.235142 2.025944 2.283643
+1 -0.025002 1 1 0.082639 -1.233344 0.981356 0.285418 -0.191016 -1.275068 1.876313 -0.116717 -1.310094 2.236680 1.145649 0.093199 60.021379 29.316870 -21.373981 17.505589 66.432495 0.339085 1.258694 1.869437 2.130305 1.294745 0.279305 2.274584 0.679389 1.235627 1.181018 1.376004 2.495646 1.319284 0.952758 1.255445
+1 0.007195 1 1 1.544112 0.763223 0.359485 0.584606 0.135120 -0.413761 1.411895 -1.870130 0.366485 0.422985 -1.878607 -0.740235 -13.201162 -21.925888 41.598044 -11.682022 10.249076 2.218360 0.725470 1.724672 1.319086 2.128874 1.979323 1.728592 1.946385 1.644323 0.882608 1.239850 2.418175 2.025060 0.941707 2.262963
+1 -0.016594 1 1 1.814063 -0.206173 -1.546434 -2.083620 -1.631190 1.262589 0.443923 1.303422 -1.283085 -0.921371 -0.579510 0.677254 69.863253 -8.306193 47.815903 -58.119719 -18.123136 2.191760 1.404760 2.053964 0.717426 1.533613 0.939636 1.220394 1.667005 1.850654 1.443183 2.073203 2.325015 2.277674 0.869202 0.923937
+1 -0.036228 1 1 1.367564 2.330635 1.606714 2.053662 -2.352541 -2.208235 0.961982 -0.166866 -0.638006 -2.287265 1.600634 -1.179002 3.309437 -28.291271 8.609088 -57.052275 72.408688 1.717211 1.919660 2.478472 0.684284 0.265525 2.421311 0.730809 1.457191 1.260449 2.123712 0.735742 1.107747 0.657724 1.625186 1.008024
+1 -0.030639 1 1 0.813528 2.331020 -1.353765 -1.311847 1.053799 2.041740 -0.086348 0.169522 -1.839161 -2.224830 0.081044 0.222161 52.304242 -72.599139 -73.734935 36.948630 -4.378948 2.170332 1.263322 0.902546 1.085203 2.005182 2.093201 0.926917 1.189614 1.837830 1.902614 1.729097 1.436759 2.111488 2.271549 1.416267
+1 -0.050554 1 1 0.698364 -1.154366 -0.519903 -1.234538 -0.239709 0.304997 -1.001283 -0.617421 -0.307252 0.787313 -0.024501 -1.805535 68.964221 31.667038 27.910570 42.952507 -47.221935 1.239061 0.402168 1.745531 0.885274 1.058010 1.724053 2.166620 1.888536 1.381695 1.403845 2.426175 1.478060 0.998699 1.628237 0.524579
+1 -0.065903 1 1 1.819173 0.855184 0.289325 -0.501346 -0.363749 -1.555771 1.209245 -0.757986 -1.886989 -0.243778 -2.118987 -2.289947 -33.853829 -31.306423 32.954615 68.213282 10.634658 0.425406 0.792173 2.298842 1.132097 0.411516 1.347810 1.137904 1.246458 0.966613 2.365055 2.481089 1.915314 1.427854 0.939695 2.198240
+1 -0.007480 1 1 0.174240 2.055325 2.034042 -2.238659 -1.435747 1.544779 -2.163184 -0.561610 -0.070425 -0.817249 1.106883 -1.124376 -22.616081 -8.477032 26.525290 10.546823 -39.537585 1.252246 1.492036 1.894529 0.840057 1.589865 1.364658 0.799853 0.874603 1.698488 2.233786 1.247896 0.396778 1.141280 1.738916 2.219964
+1 0.052664 1 1 0.608696 -0.239461 -0.249145 1.932357 -0.669884 -0.848828 -1.849346 0.966704 -0.927197 0.465862 -2.251208 -0.279435 56.787431 -23.654247 -56.936063 -74.407773 -21.433750 2.319420 0.497211 1.623026 0.699151 0.377877 0.726154 1.965835 2.287865 1.149352 2.403983 2.001321 2.453961 0.478376 2.319243 2.009101
+1 0.000194 1 1 2.301421 0.689101 -1.336942 -1.315466 1.491767 2.214691 -0.853696 1.159289 -1.563611 1.379809 0.778524 -1.654812 2.895442 63.697444 12.943103 34.725399 -20.224979 1.056691 2.061091 1.248947 2.307774 0.511310 2.342390 1.795637 1.528436 1.669800 1.578704 0.521681 1.149161 1.450653 1.617519 0.384488
+1 0.004816 1 1 0.214334 2.051448 -1.870310 2.045199 1.495989 -2.214989 0.554487 -1.837305 0.692706 -2.001027 1.064854 -0.644802 41.396720 54.665101 6.346370 13.445929 -64.270289 0.763755 1.685610 1.802978 1.144812 0.347629 0.845900 0.783967 1.628548 1.250553 2.298265 0.435537 2.320634 0.638922 0.605793 1.816802
+1 -0.018406 1 1 -0.176824 1.638470 -1.440037 0.125179 2.159570 1.069984 0.741180 2.173115 -2.175951 1.648063 -0.429823 0.059827 56.640481 56.570188 -74.855079 -39.318448 74.852528 1.321684 0.792160 2.088991 2.176499 1.427111 1.947160 1.166775 0.489055 1.797557 2.295685 2.086735 0.261022 0.990775 1.198656 0.816674
+1 0.066715 1 1 0.703453 -0.451417 -0.023524 0.477227 0.264410 0.163212 0.492703 1.187308 -1.888122 -0.431699 1.519986 0.537235 12.001576 -39.518220 17.283766 -61.739896 37.564034 1.205850 2.464891 1.915497 2.261001 1.896338 2.003485 0.565345 1.508814 0.385510 0.764531 1.225742 1.553288 0.864941 1.315787 0.678764
+1 0.008195 1 1 1.581750 1.887035 1.014995 0.171299 -0.241113 0.276150 -0.450452 2.053885 1.391165 -1.558874 0.891510 -1.780429 0.201913 -56.443048 -38.314844 -7.576829 6.243987 0.515214 0.444120 0.332682 1.629425 2.495251 1.432873 2.044729 0.755562 1.227368 1.872034 0.779963 1.831355 1.090544 1.766104 2.418082
+1 0.045356 1 1 -1.430488 0.393571 -1.445119 -0.466832 0.087683 -1.297703 -1.555547 0.259592 -0.704748 2.247622 1.269178 -1.908674 -59.087396 68.134871 42.774643 -36.569024 -65.584398 2.470416 0.281279 1.711234 0.465102 1.964268 0.709697 2.123522 2.037341 0.342751 2.119604 1.440436 0.904302 1.359588 1.096965 1.684079
+1 -0.000472 1 1 1.309000 -1.781028 -0.643227 -0.504030 1.651043 -2.176644 -0.585174 -0.256851 -0.348928 -2.216932 0.877239 -1.314158 -2.739565 6.131925 9.257315 37.686923 -45.879451 2.185962 0.718494 1.475637 0.785679 1.160876 0.336953 1.420518 1.403212 0.791038 1.217934 0.821546 0.979055 2.233977 2.195610 0.869333
+1 0.010829 1 1 1.538656 -1.399982 -0.537391 1.719313 0.118122 1.357455 2.075533 -2.337868 -0.649493 -2.135245 -2.225745 -1.161307 19.769899 22.696951 17.661450 -14.010494 25.624418 1.668901 2.212502 1.268461 1.777634 0.446600 1.500655 0.508851 1.505278 1.709090 0.422306 0.442573 1.319280 0.889012 0.880161 0.609296
+1 0.021877 1 1 1.642750 -0.182455 1.242862 -1.235308 0.965098 0.359246 1.272736 1.333229 0.176554 -1.458632 -1.385273 1.631214 -27.530692 41.664922 62.339174 -15.502249 3.696316 1.734735 1.686352 0.773096 1.169167 2.443129 0.678324 1.347012 1.231726 0.875142 1.768860 1.486239 1.224956 1.831833 2.364270 0.542651
+1 0.010699 1 1 -1.518404 -2.238773 1.371117 0.777131 -1.504307 -0.921477 -2.355252 -0.648923 -1.975895 -0.668813 -1.687856 0.780522 -33.750360 57.692478 37.481777 -43.768819 -22.542295 1.849778 2.470796 2.169945 1.507696 1.839609 0.316958 0.605596 0.757322 1.557557 0.611131 1.525689 0.501392 2.150157 1.944107 1.608996
+1 -0.056206 1 1 0.024880 -1.246040 -0.340618 0.785029 -0.706969 -2.091778 -2.087559 -1.859875 -1.650429 -1.645895 -0.831554 1.024403 -61.343951 -57.779449 0.798193 65.230223 -25.636621 0.254785 1.913344 2.069741 0.385686 1.469007 1.852495 0.890331 0.551030 1.663020 2.373740 2.204077 1.427643 1.896909 0.343068 0.699086
+1 0.002132 1 1 1.882393 -1.596663 1.939030 -1.597441 -1.706081 0.792212 2.206688 1.299260 -0.556475 1.415137 0.771765 -2.153219 63.626524 20.987456 -63.831916 -23.015016 36.619987 1.706798 2.402000 2.417316 1.074773 2.212728 0.575880 0.820037 0.357373 0.368734 2.311110 0.333998 1.256253 1.352956 2.133863 0.327455
+1 -0.028876 1 1 -2.026503 1.705599 0.546134 -0.851182 1.001641 1.920121 1.040299 1.333373 -2.127807 0.262631 -1.466813 -2.212147 38.239076 -65.856018 7.901455 49.761816 -53.164201 1.663999 0.826050 2.424067 2.045269 0.828171 2.066744 1.763314 0.524293 2.292584 1.711866 2.078826 2.337006 1.300688 1.155943 0.676782
+1 0.080248 1 1 2.174808 -2.001062 0.472584 2.345963 0.047638 -0.461977 1.570373 -0.829068 0.386603 -0.754701 1.494146 -0.202650 35.674742 35.380725 43.852655 -68.430663 -64.156400 2.475893 2.325357 1.278899 1.708779 1.945064 1.939450 2.080079 0.892588 2.476334 0.745049 2.284726 2.389419 2.469507 0.759288 0.849688
+1 -0.012473 1 1 0.421285 -2.182505 -0.126392 1.015685 2.347961 0.627509 0.220432 0.863119 1.705340 0.903185 1.220020 1.266907 74.412496 -49.176343 -6.792209 -6.652910 -65.461853 1.864543 0.873476 0.762083 0.571187 0.684302 0.569655 1.946874 0.864728 2.236655 2.212104 1.322953 1.877766 0.370929 0.946231 1.807449
+1 -0.027854 1 1 1.245934 -1.443790 -1.693595 -1.424462 -2.004857 -2.046374 2.320219 0.898020 -0.764946 -1.043994 -2.185462 2.016641 69.429985 59.750664 -20.593771 -69.506633 2.012912 0.340194 1.892236 0.565596 1.218043 0.393725 1.580349 1.170919 0.391900 2.417767 1.907069 2.363411 1.840497 1.738946 0.465719 1.093877
+1 -0.013921 1 1 1.139191 -0.055620 -1.745871 1.189381 -0.030253 0.474241 1.923086 -0.960411 -1.696727 -2.218034 1.211294 0.695815 -50.428792 -56.715104 39.252182 11.420690 -52.464637 0.277663 1.683509 2.492607 1.988366 0.714586 1.039998 0.499124 2.276326 0.708775 2.385605 1.363989 0.807545 1.912873 0.910440 1.007370
+1 -0.001329 1 1 -0.928160 -1.582079 2.012321 0.265154 -1.482100 0.026866 -0.850942 0.321440 2.044423 -2.117588 -2.347365 -0.044619 -20.464003 11.493515 -28.490531 -40.353407 -69.709037 2.128319 1.653333 1.570440 1.143898 0.737309 0.448876 1.510131 2.274242 1.691212 1.452427 2.192865 1.979029 1.298684 1.228256 1.045819
+1 0.007012 1 1 1.753731 -1.044318 1.794258 1.510042 -1.655448 -1.170978 -1.693897 -1.784524 1.853506 -1.733440 -1.942346 -2.281734 10.053401 67.518283 29.779712 -42.379300 -68.890433 1.502368 2.303259 1.120254 1.608158 0.566460 2.239208 2.361797 1.718131 1.620105 1.098895 0.381208 0.455424 1.311775 0.751157 1.442141
+1 0.022788 1 1 0.938146 -0.226416 2.243939 0.625650 1.967745 0.342966 0.979230 2.248601 -1.121762 0.822098 0.280802 2.340668 18.540119 53.780104 -17.792846 55.629010 6.773427 1.239891 0.850097 1.576964 0.527936 0.522270 2.044320 0.628678 1.689260 2.393021 2.258731 1.999227 1.009002 1.543923 0.970083 2.187370
+1 -0.032857 1 1 -1.913328 0.031422 0.316165 -1.785988 0.812426 -2.059743 -0.890561 -1.108846 1.128845 0.427308 0.081630 0.650483 -2.373708 5.082504 71.651765 51.220685 16.053964 0.909584 2.383279 0.515058 2.331882 0.688982 0.468615 0.256118 1.830973 1.411271 1.235829 2.335360 0.643473 0.593313 1.308943 0.410373
+1 -0.000896 1 1 0.467427 0.487499 -1.440418 -1.562779 1.220428 -1.301380 -2.098242 -2.346762 0.669604 0.848170 0.221288 1.108026 -24.337689 6.465738 69.651164 27.112100 -26.942428 1.804068 1.464344 2.234651 2.286900 0.672353 2.242492 1.316415 2.236685 0.457507 0.316290 0.627957 0.830292 1.712784 1.759725 0.941802
+1 0.043531 1 1 1.617426 -1.692905 0.745339 1.380046 0.053402 2.178018 0.103183 0.036343 -1.800800 1.635458 -0.222825 1.323237 59.693541 69.351382 -61.324814 -36.156761 -36.682511 1.030668 1.178084 1.551229 2.258679 1.120874 0.773039 2.458613 2.165777 1.220315 0.340371 0.360377 1.357327 1.341978 2.132944 0.639178
+1 -0.036582 1 1 -0.293298 -0.307624 -0.737632 0.907287 -0.522327 0.427887 0.391860 -1.934344 0.253579 1.910429 -1.639293 1.745356 -13.525025 -65.087444 25.322353 42.784554 -20.002364 0.929143 0.357980 1.572707 0.990065 0.519444 1.796355 2.330491 2.057242 1.815807 0.775347 0.751494 0.356235 1.498082 2.268787 2.248810
+1 0.038882 1 1 -2.200192 -0.512180 1.327373 0.699582 0.468111 -2.154482 -0.385033 -1.142232 0.785561 -1.190047 -1.744665 -2.091538 61.876012 0.141615 -19.869430 -45.502378 -58.460944 0.578596 1.460587 2.088260 1.139747 0.734478 2.367654 1.162954 1.512807 2.243895 2.391171 0.407307 0.365636 1.989985 0.921794 0.594232
+1 0.005513 1 1 -1.488436 1.934157 1.321757 0.574312 1.483310 1.451664 2.081555 -0.073106 1.240177 0.757835 -0.658014 0.730999 22.319941 -18.759240 13.456100 -43.335341 62.927411 0.939833 2.277973 1.384146 2.083019 0.797274 0.279886 0.801601 1.011618 0.506128 0.751147 1.286052 0.429054 1.359166 0.751091 0.337121
+1 0.031875 1 1 -2.052530 -2.183877 0.368249 1.789717 0.598777 -2.009600 -1.663149 1.339420 0.558393 -2.172234 -1.862901 -0.667706 -61.843655 -56.312651 53.269687 -46.375587 -34.484624 1.628918 0.723022 1.074026 0.903225 1.258446 2.206151 0.281792 1.321070 1.725065 1.162847 1.971726 2.308003 2.101976 2.157316 0.767819
+1 0.030832 1 1 1.188510 -0.535503 0.469007 -1.231446 -0.096753 -0.357608 -2.016329 -1.646699 -0.204375 0.396120 -1.022373 -1.647554 -13.872617 -57.076865 -40.868220 -22.165268 68.348444 1.859403 2.230655 0.368942 1.312955 0.332116 1.123926 0.320622 1.438913 2.308964 0.256089 1.340271 0.439261 1.915536 0.660063 0.436838
+1 -0.010251 1 1 -0.739557 1.548689 2.293348 1.675366 1.346827 -2.195045 1.174603 1.362109 0.185097 0.740942 -1.830564 0.898094 15.415241 33.962632 59.955601 -26.218051 53.209828 1.338768 2.180384 1.470203 1.692875 2.405180 1.852566 2.076144 2.249001 0.453412 1.248479 1.182054 0.778760 1.861934 2.030645 0.294016
+1 -0.001143 1 1 -1.662089 0.318459 -0.939363 -1.376772 -1.578871 -0.619464 -1.658894 2.179511 1.639499 1.726501 -1.588408 -0.696813 -33.202021 -26.370314 44.140869 -24.420719 -39.020903 1.010244 2.176512 1.634460 1.626435 1.735280 1.850988 0.299553 0.595628 1.975036 1.683114 0.349927 1.218568 2.474839 0.373965 2.476575
+1 -0.026734 1 1 -0.215319 0.254187 -2.023970 1.872614 -1.025824 1.606824 -0.813318 1.211464 -1.154985 -1.504241 0.183069 -0.351463 72.913311 -45.974558 -44.389982 37.574566 15.726433 1.587407 0.548519 2.201693 1.851835 1.038952 0.907367 1.121107 2.445587 1.487648 2.408643 1.561160 0.415076 0.438208 2.204317 0.962046
+1 0.064319 1 1 2.318445 -0.644634 -0.581006 -0.893287 0.188613 -1.424011 0.878264 1.784114 0.667537 -0.898724 -1.640303 -1.102679 35.070921 -63.031596 -72.036091 -60.573287 -5.240850 0.880452 1.000499 0.390699 2.484780 0.938459 1.672999 1.335025 2.262157 1.077072 0.355859 1.922300 1.845569 1.474165 0.788846 0.391100
+1 0.029163 1 1 -1.315829 0.110731 -0.338572 2.182366 -2.215471 1.875500 0.353422 -2.352606 1.409860 1.632499 1.880597 1.208947 -33.311106 -59.752880 -16.649964 64.057307 61.160092 0.890077 0.766398 1.103985 0.428446 2.394204 1.893082 1.281802 1.000431 1.492325 2.247819 0.836125 0.751166 1.599128 1.802309 1.149968
+1 0.059922 1 1 0.404207 -1.754602 0.533204 -1.396622 -0.617792 -1.841602 -0.835655 -1.942689 1.376531 2.243840 -1.036867 -0.201905 -15.590137 26.572818 59.345985 -72.036973 74.586743 1.815732 1.764976 1.458784 1.041741 0.542862 1.633723 0.483005 1.366826 1.243138 1.415109 0.485551 1.398184 1.786958 1.904975 0.923522
+1 -0.002515 1 1 1.918692 0.579908 1.301473 -1.048700 -1.173602 1.326121 -1.491413 -0.983945 -1.383122 0.084970 0.229339 -0.231373 -30.912934 46.319599 -6.505188 17.305876 9.860421 0.986363 1.300061 1.872710 0.887312 1.549917 0.460124 1.555472 1.569778 1.250519 1.728990 1.889903 1.850708 2.345626 2.182478 0.663507
+1 -0.050330 1 1 1.535321 -0.901904 1.446997 -0.954159 -0.291591 0.119494 0.852746 1.726482 -1.909346 0.991012 -2.350825 -1.645802 23.065875 68.153367 53.641552 53.568027 17.835584 2.314904 1.097508 1.822423 1.714994 0.644915 2.343545 0.960101 0.913749 0.373290 2.381834 0.987250 0.457328 1.810253 1.930256 0.565386
+1 -0.003228 1 1 -0.861094 -0.663720 -0.912990 -1.085482 -2.032813 -0.662792 0.546184 -0.020476 -0.142810 -1.594015 -0.677031 1.565484 57.776718 -46.699849 65.642317 0.421947 41.657301 0.388945 2.245842 1.364203 2.157526 2.046201 0.752148 2.353703 0.681648 0.949935 1.064499 0.535014 2.478583 0.289867 2.052982 2.220671
+1 0.035316 1 1 -1.399326 1.054487 -0.537175 0.637368 0.991099 -0.899304 -1.962814 -2.297581 -2.131895 2.251453 -0.311882 -1.631126 74.459558 -8.202768 -13.925962 -53.644205 51.851017 0.775581 2.432847 1.115282 1.296935 1.091030 0.936658 0.659303 1.157623 1.920124 1.271077 0.735525 1.967458 0.321903 0.477167 2.248850
+1 -0.066478 1 1 -0.331358 0.915566 1.974403 -0.855480 -0.561573 0.549617 1.130354 2.222196 -1.944247 -1.262819 0.402094 0.428465 21.589822 10.138654 0.361358 73.341396 -51.157687 1.266204 2.099090 0.907926 1.519066 1.692354 0.397778 2.197608 0.689215 2.138733 1.192670 1.458386 1.091250 2.386308 1.926363 0.383110
+1 -0.000069 1 1 1.476851 1.275037 2.316609 1.484507 -1.993116 2.065222 -1.270710 -0.282352 -0.111033 -0.023481 1.190430 -1.254171 -10.446711 72.120885 -14.281263 -25.188994 -51.423141 1.844003 2.157777 1.760272 1.149369 0.450313 0.916594 0.938276 0.848321 0.985153 1.210773 1.962932 0.753010 1.092660 1.338837 1.082915
+1 -0.006160 1 1 1.083298 -1.676219 -1.544711 -1.410802 1.395263 1.340320 1.541176 -1.454105 -0.698355 1.305061 -2.008754 -1.577125 14.296027 -26.668534 -18.042881 53.298386 -14.034884 2.360593 1.735837 2.213429 1.094953 1.629904 1.545040 1.730254 0.632056 2.222801 1.121107 2.436254 2.128836 1.349296 1.370878 1.840146
+1 -0.013055 1 1 -0.355183 1.038282 0.425519 -1.705396 -1.848737 1.768519 -2.252977 -1.734939 1.137615 1.741993 -0.402993 -1.400516 -2.824123 -65.034990 6.921761 -65.954506 2.614965 1.370863 1.591977 0.864769 0.675550 1.964176 1.403525 1.544341 1.241892 0.726470 0.530419 1.752704 2.193948 2.185880 1.587517 2.402728
+1 0.017805 1 1 0.295957 -2.135798 -2.091782 -2.152616 -2.013774 -1.121644 -1.923137 0.104295 -0.125442 -1.864516 0.459190 -1.289020 -54.510043 49.713676 37.746918 62.459007 48.535616 1.946456 0.588940 2.060590 1.836230 2.024312 1.866179 1.371908 1.153182 1.529348 1.244461 1.156680 1.818768 1.028803 1.339268 1.580564
+1 0.012489 1 1 -2.147472 -0.370584 1.374535 1.683404 -0.209358 1.466700 0.315104 -0.773472 1.734547 1.698759 -1.320111 -1.174512 5.644787 71.930426 -65.321857 -14.457845 7.001303 2.438414 2.416543 1.582996 0.668642 0.613234 0.871719 0.476885 2.009950 1.224672 1.564564 1.382917 1.678348 1.243478 0.390114 1.640653
+1 -0.069348 1 1 -1.762181 0.388320 -0.165935 0.870293 -0.240510 0.975584 2.234483 1.924770 -0.935037 0.642327 -0.497711 -0.533334 -24.954251 -6.093656 33.918798 73.242244 -67.599102 0.803499 1.399545 2.148201 0.571413 2.244539 1.965662 1.625564 0.596855 2.335120 1.116131 2.056179 1.949715 1.358925 1.193848 1.009867
+1 -0.011693 1 1 -1.768899 0.569223 0.773686 1.858463 1.479259 -0.651087 -0.648465 0.999833 -0.177590 -1.809181 2.143347 1.733094 26.802015 11.472803 73.403521 -57.017111 63.407179 0.391952 1.040644 2.349465 1.463896 1.454373 1.152126 1.788510 0.991685 0.745512 1.073773 1.156735 0.498822 1.703395 1.453337 1.727641
+1 0.013442 1 1 -0.530793 -0.492658 -0.432872 0.648736 -1.158870 -0.826800 0.813375 -0.239837 -1.846672 -1.218515 0.465947 -0.813111 -0.948739 -45.463317 -1.965134 -28.002801 56.925101 1.977614 2.256206 2.307905 0.453232 0.466293 1.733718 0.347571 2.124023 1.454319 2.498539 0.441834 2.395915 1.388519 1.331953 2.388097
+1 0.038030 1 1 -0.777715 1.115300 -1.039811 2.154484 0.421767 1.197070 1.961295 0.320759 0.030149 -2.228075 2.091976 0.698913 -43.247538 38.621031 53.671321 -46.100404 -59.483101 1.637839 2.167777 1.073656 1.428116 0.838682 0.971667 1.799559 2.194898 2.400341 1.531021 2.368200 1.338207 1.753159 0.837877 0.946644
+1 -0.020507 1 1 2.327242 1.120735 0.780549 -0.602054 -1.217520 -1.668154 2.055059 2.274401 -1.041897 0.077175 1.165919 1.492971 -35.141223 -68.539241 60.969863 70.485271 -54.058535 1.197966 0.456719 0.571361 1.362576 1.807894 0.517299 1.740176 0.879177 2.081724 1.539572 2.086190 2.347830 0.983039 1.681377 0.405716
+1 0.039042 1 1 0.852648 0.086757 2.001650 -0.010958 -0.394549 -0.851177 1.076066 -0.703471 0.152203 -0.759087 -1.542128 -0.398809 -56.284766 71.934983 11.261122 -34.316417 -6.019688 0.281465 0.325691 1.138667 0.568604 2.277795 0.649047 2.031785 1.465506 1.510494 1.619360 2.084085 0.710313 1.225731 1.357772 2.070802
+1 0.018391 1 1 1.962257 2.352804 1.926717 -1.198226 2.162131 1.707008 0.665745 1.964974 0.897164 -1.013062 -0.665363 -0.249170 47.990720 30.032349 3.688207 37.693137 58.560316 2.473477 2.230232 2.263894 1.020825 2.252244 0.960736 0.342029 1.235472 0.833325 0.945283 1.627327 0.981421 1.498769 0.307635 1.427332
+1 -0.068613 1 1 2.296781 -1.886451 -0.627168 0.804113 -0.403383 1.474030 1.000484 1.334478 2.306549 2.050373 -1.078452 -1.700708 49.259253 50.260820 -66.397554 56.307502 10.187496 2.443675 0.837589 0.605663 1.874035 0.658396 1.662133 0.978412 0.427430 1.060618 0.552216 1.349987 1.734865 1.630087 2.380881 0.718781
+1 -0.039563 1 1 -1.840640 1.204651 2.142618 -1.101559 1.077604 1.572787 2.043314 -1.915272 0.355427 -1.647487 0.689526 1.093355 -73.088799 -53.443961 -32.644283 47.541376 -22.100149 0.816930 2.148225 0.971867 0.671429 2.462084 1.991526 2.081283 0.874547 0.759770 2.196863 1.678737 1.024004 1.690523 1.117231 0.297561
+1 -0.025423 1 1 0.472177 0.220487 1.781453 -1.636098 -1.111255 -1.662620 0.815515 -1.980038 0.391606 -1.478895 2.055321 1.963636 62.895622 36.714744 -35.293435 73.245264 -16.839618 1.772987 1.091117 2.405611 2.348489 0.798460 2.224672 1.068976 1.537345 0.650848 0.807490 0.987644 0.328894 0.973983 2.485745 1.408026
+1 0.041598 1 1 0.455278 -1.066099 -1.420060 1.296480 -0.143937 -1.692314 1.250521 0.250160 0.992907 1.217254 1.903644 2.143552 14.775976 -60.167482 65.131209 -39.768864 4.696293 1.834053 1.430837 1.582634 1.329811 2.378090 1.053808 0.854738 0.826491 0.831520 2.108879 1.180989 0.877043 2.218385 1.146474 1.286910
+1 -0.013010 1 1 1.998107 1.700986 -1.589059 -2.209249 -1.932596 1.356576 1.434451 0.231399 1.405984 -2.253818 -1.743035 1.742090 38.998943 -44.769834 -46.600281 -60.928886 18.206267 1.265880 1.141236 1.012338 1.363441 0.611143 1.724533 1.231976 0.564578 2.118009 1.626197 2.243949 1.052102 1.419314 1.408099 1.925464
+1 -0.016312 1 1 -1.217202 -1.026949 1.554552 1.864256 -0.125338 -0.114075 0.678320 1.254737 0.420162 -2.214603 2.321076 1.168522 -59.885583 2.999151 6.730056 12.046274 -38.273643 0.398141 1.554576 2.263183 0.321978 1.736498 2.079917 0.422316 0.617891 0.397272 0.453835 1.601766 1.128182 2.097434 2.328844 1.386609
+1 -0.013643 1 1 1.643178 2.285977 0.309643 1.700733 -1.124206 2.147248 1.322007 0.051039 0.162268 -1.231940 1.022373 1.654745 -38.647080 -41.467461 -43.615422 5.606962 36.207756 1.281423 1.371239 1.172356 2.033553 1.929420 2.270008 0.265424 0.729601 1.397328 0.899871 1.126521 1.188318 0.308081 2.166968 0.985134
+1 -0.011370 1 1 0.082541 1.816970 1.537604 -0.230353 2.038673 0.193684 -1.020350 -0.647682 0.021955 1.426971 1.758031 0.542647 57.287837 -13.326315 -25.383935 -27.801149 -3.904432 0.298264 1.424159 1.847574 1.427685 0.343164 2.306430 0.426463 0.564478 0.432180 2.143364 0.274028 1.343747 0.358498 1.278267 2.338715
+1 0.074165 1 1 -1.033681 1.493073 0.606284 1.625403 0.433879 2.132212 -1.627139 -1.339894 0.904132 -1.713696 0.031601 -1.385157 -35.904167 8.658318 20.344439 -71.012826 37.431753 1.607088 0.571203 0.956014 1.982815 1.924648 0.800683 1.333220 1.177655 1.094417 1.613574 1.593898 1.646846 0.540825 1.140777 2.285293
+1 0.032759 1 1 -1.192060 2.120208 -0.746340 0.635077 0.184342 2.196318 1.370301 1.204968 -1.952318 -0.237055 -2.206286 0.742534 43.637892 72.056835 -40.779571 -32.257395 -50.038295 2.220717 2.084807 1.601612 0.788571 0.262365 1.061922 2.219670 2.493015 2.104473 1.375159 1.800482 1.959124 1.987968 0.783517 0.827350
+1 0.070218 1 1 1.880477 -0.818875 2.053284 0.726732 -0.335538 1.347904 1.766166 0.614237 -1.362904 0.590306 1.695574 1.688228 23.980999 -1.356978 -6.724242 -64.340315 -17.671620 1.271309 2.395078 0.827996 1.382131 1.979468 1.913558 1.160530 1.277881 0.352265 2.264248 2.461843 2.448952 1.788729 2.418460 2.310502
+1 0.009051 1 1 0.672317 -0.679609 0.637137 1.810488 0.972621 -0.433124 1.126793 -1.088158 0.103207 0.434988 1.931186 -1.484485 -74.701358 -5.719690 19.170295 -4.860119 65.983880 1.991063 1.039665 1.647067 2.014106 1.336188 1.561050 0.821203 1.964166 1.229421 0.387591 1.984796 1.460298 1.723647 2.091385 1.901177
+1 -0.001076 1 1 1.683050 -1.450837 -2.316542 -0.369081 -1.640774 0.419924 -1.487970 0.340448 1.061198 -0.837129 1.563948 -0.439942 -11.761563 23.403855 48.594787 -17.421833 -8.740240 0.666800 1.160679 1.534165 1.204504 2.351305 0.880827 0.564800 1.347982 1.786417 1.812257 1.847800 0.723376 0.276191 1.692629 0.507319
+1 0.000635 1 1 -1.952017 0.102133 1.237726 1.972379 -1.887364 -1.843075 -2.036282 2.290379 -1.099491 -1.863366 0.949201 1.791981 29.977054 -25.657141 30.424962 2.334138 -70.143494 0.599531 2.321431 0.544271 0.566988 2.109292 1.364945 1.121587 1.510309 0.759130 0.440925 0.632851 2.078704 0.276555 1.064319 2.003867
+1 -0.000289 1 1 -0.520226 -1.961676 -2.015504 -1.925685 -0.291160 -2.064495 -0.643869 -1.867651 -0.393133 -0.616130 -2.171318 -0.597499 -2.284419 5.762592 -48.123373 -9.526247 -57.627657 1.404637 2.240256 1.978453 0.610822 0.841625 0.942246 2.335519 1.070461 1.732018 1.031486 1.426710 1.957118 2.034009 0.580199 1.409220
+1 0.075674 1 1 -1.199731 0.425035 -0.415364 -1.975289 0.097007 -0.096107 1.073543 -0.699321 -0.788132 0.384588 -1.634451 -1.703526 42.030842 62.368619 29.376297 -72.576258 10.836415 1.789429 0.690738 0.735093 1.461850 0.821574 1.439909 1.053747 2.076106 1.617689 0.990616 0.784065 1.033825 2.492745 2.073909 0.688439
+1 0.040388 1 1 -0.016270 -0.124684 1.453645 -2.319197 2.143972 -1.905778 -0.300527 0.725093 0.395885 -0.258784 0.145799 0.006003 61.276898 -19.169592 16.666588 65.346423 -22.662045 0.910183 1.193172 0.899102 1.701149 1.959479 1.217692 1.250357 1.251463 1.845931 0.806798 0.596062 0.269596 1.097015 0.284873 1.365377
+1 0.011693 1 1 -1.356419 1.201390 -0.824308 0.275264 -1.203763 -1.359176 1.999961 -0.133439 0.381305 -0.256838 -0.128306 1.831239 32.578981 54.932427 -0.697435 -21.790183 72.391444 1.869960 1.926783 0.684995 0.964706 1.810297 0.413755 0.734197 2.153830 0.670271 0.988347 0.904775 0.300886 0.484642 1.881529 0.601299
+1 0.014508 1 1 -0.487178 2.135248 2.268380 1.433133 1.639690 0.227323 -1.125396 0.990651 1.002546 -1.710643 -0.497524 -2.109556 22.417962 -21.307728 -68.985985 52.547246 -38.437690 1.791113 1.987242 2.080410 1.944828 2.467647 1.000859 1.936529 2.485547 0.332926 1.241996 2.478898 1.084060 0.796114 1.035600 0.829503
+1 0.004080 1 1 1.177205 -2.039884 -1.695486 -0.211886 1.403284 -0.517920 -0.897196 0.478067 0.254655 1.140737 -2.350313 2.253646 -36.981738 47.926441 -0.297750 -54.281269 -5.287763 0.303550 0.257915 0.535307 0.657434 1.250395 1.894767 0.357503 0.297466 1.510956 0.388209 1.135254 1.711192 2.008510 1.772373 2.016590
+1 0.002051 1 1 1.771241 1.095273 1.664634 0.053208 -1.088818 -1.565937 -0.002438 1.444220 -0.515067 -0.066405 0.767104 -0.381392 -38.204047 54.574689 -13.209746 -16.193266 -60.219694 0.439169 0.370634 0.495297 0.963052 1.020678 2.027710 0.474419 1.056863 0.445411 1.770967 0.898709 1.857617 1.464107 0.490468 0.792490
+1 0.006649 1 1 -0.844114 1.985394 0.083338 1.085567 -1.254314 1.972001 1.186449 -2.173856 -0.847311 0.075474 0.861726 1.860345 3.663815 -72.255606 0.025372 -23.567162 56.712776 2.449281 0.560152 1.979733 1.870356 1.820713 2.217955 0.662402 1.495689 0.295870 1.690818 1.581248 0.540256 0.576005 0.659225 2.100500
+1 -0.008008 1 1 -1.087731 -2.135292 1.705248 -0.648210 0.574148 -1.267784 1.782621 -0.856166 2.057173 0.112467 0.562059 -1.817742 -11.935092 -43.094606 58.958789 20.360858 54.935954 2.253598 1.227805 2.464262 0.357647 0.469418 0.260644 1.389018 0.734404 1.126866 2.477790 0.472829 1.331305 0.489735 1.977386 0.685703
+1 -0.059899 1 1 0.327031 1.759947 -0.233850 -0.181446 -0.640227 -1.919402 1.619134 -1.267521 1.476762 -0.220336 0.756063 -2.160025 22.319788 -21.323158 -28.323296 70.361108 -40.855808 1.921629 1.812531 1.956901 0.641800 1.734735 1.698996 1.772392 2.349565 0.892418 1.863796 1.825578 0.732304 1.831093 1.172204 1.732613
+1 0.022195 1 1 2.254920 1.408279 -1.392183 -1.406959 0.014577 -0.055958 1.984275 0.135144 -0.008476 -1.091543 -0.235470 0.867411 -49.660167 -38.423131 -27.569260 -6.545112 -53.695327 0.514496 1.884511 1.228390 1.044284 0.529546 0.576964 1.038791 0.465182 1.068901 0.276411 0.887418 1.089413 0.759614 1.834589 1.443117
+1 0.035380 1 1 0.506782 2.200852 2.183462 2.075049 -1.036771 1.397952 -0.594809 -1.977207 0.846876 2.025127 -1.282766 -0.262537 -53.118617 35.403954 -15.747307 -64.982943 -18.331207 1.485940 0.699887 1.495737 1.110654 2.261097 1.262329 2.208865 0.891173 1.202716 1.547883 2.262064 1.759860 0.959743 1.656642 0.938614
+1 -0.029926 1 1 1.159539 -2.070103 -0.649535 1.866818 0.517809 -0.965769 -2.213605 0.255979 -0.170521 -0.813884 1.113927 -0.556787 28.057083 -44.604454 32.943370 29.221726 29.549687 1.248896 1.447400 0.950531 2.071406 1.375347 0.460917 1.384309 0.334670 1.306478 1.727202 1.090196 0.429509 2.264312 1.288390 1.464978
+1 0.005142 1 1 0.017662 -0.028883 -0.053076 -1.407324 -1.408688 -0.775006 -0.484176 0.745175 -1.368872 -0.743176 1.976847 -2.194497 30.250743 74.235824 -18.512188 -34.343519 -11.521423 1.516655 1.678743 1.131721 0.827985 1.202182 1.563989 0.719286 1.282709 0.493983 1.378433 0.579148 1.745124 0.806517 0.378646 2.401068
+1 0.003209 1 1 -2.206808 1.385344 -0.436273 0.037104 1.577109 -0.713080 -1.122300 1.192211 0.403773 0.369676 2.219828 0.665906 -1.112036 60.013295 43.447969 30.008739 56.870154 1.625234 1.803860 2.472819 2.419107 1.934845 1.184887 1.141044 2.282593 0.289604 2.123707 0.646004 0.395468 1.637100 0.992774 1.048880
+1 0.008946 1 1 0.810363 0.960594 0.059688 -0.562266 -1.657102 -0.696284 -1.578411 -2.314670 -1.881721 -1.238685 0.753329 -0.991834 -64.932258 -66.466915 -59.438417 18.528894 15.118429 1.306599 1.514391 1.863374 1.483666 0.726351 0.784754 1.353261 0.503828 0.342116 0.437731 0.952409 2.129968 2.381144 0.636804 1.010644
+1 0.009658 1 1 -2.179711 -0.297619 -2.230353 1.518712 -2.021794 0.736485 -1.344337 1.627171 1.862312 0.192767 -2.294714 -1.072479 -8.721400 -30.564682 49.389984 -2.537273 -43.948873 0.644483 1.833500 1.127845 0.948273 2.373562 1.464488 2.406604 1.036587 1.673163 1.841642 0.732088 0.455965 1.407963 1.881004 0.783356
+1 -0.008470 1 1 0.589219 2.277099 1.900700 -0.218386 0.538902 0.109801 -1.827952 -2.320085 1.357321 -0.183090 -0.008457 -0.769831 53.123662 49.394366 71.104948 10.868661 -30.421909 2.109745 2.227652 1.645229 0.368307 1.877789 0.749564 1.678653 1.865135 1.816937 1.758452 2.050075 0.616787 2.090542 1.235298 2.402463
+1 -0.040679 1 1 -1.944986 0.463742 -0.179411 0.574807 0.383067 1.076148 0.666396 -1.223509 1.354336 1.482519 2.303742 2.006658 -21.338009 22.087918 -18.356119 38.715401 -10.252728 1.860883 2.366830 0.820382 1.660193 2.121179 0.910324 1.316400 1.977405 0.992123 1.367571 0.257737 2.034483 1.813900 2.468634 1.832597
+1 -0.083281 1 1 -1.520817 -0.370331 0.919234 -2.351297 -0.156908 1.784445 1.524680 -0.674703 -1.724533 1.682448 -2.142268 2.273037 -12.685138 -49.120315 34.873801 73.978250 2.442791 0.714725 1.136529 0.652032 0.447546 1.661266 2.156603 2.278331 0.650796 2.178027 2.356199 2.136530 2.406021 2.498934 0.331080 1.703508
+1 0.031128 1 1 -1.767047 -1.289987 0.890226 0.197525 2.280335 -0.268709 -1.721853 -0.399135 2.178141 2.176664 0.912787 -2.334152 17.418274 -51.064569 57.782115 43.998771 -12.661560 2.082401 1.663580 0.532934 1.273339 0.509212 0.828138 1.508493 1.738655 2.324463 2.007999 2.191205 1.079545 1.418053 0.469866 1.032962
+1 0.002085 1 1 1.219254 -2.184063 1.970250 0.041888 1.868990 -0.678473 0.892217 0.670553 -2.055820 -0.922329 2.181824 -1.893267 -66.524733 18.814140 9.255227 2.597397 4.447409 2.089031 0.600497 0.547003 1.483001 0.792824 1.987582 1.038985 1.469228 1.067571 0.418372 1.824607 2.418192 2.305366 0.533358 1.645380
+1 0.065399 1 1 -1.649430 1.012757 0.249869 0.802755 0.337733 -2.148417 -2.113556 -0.554156 -2.011229 -0.752006 -0.344355 -0.756917 61.808864 71.573690 -60.996126 -61.886627 -28.539398 1.950017 1.941488 0.339420 2.379082 1.976041 0.569459 0.892571 2.196152 0.975118 1.303093 1.079359 0.535600 1.075157 1.914189 0.515785
+1 0.010916 1 1 0.496970 2.216302 -2.048490 -0.253582 -1.947273 -0.275117 -1.037163 -0.477436 0.939868 0.428626 -1.332673 -0.247415 -62.842621 -45.929135 -30.966792 41.118991 36.879948 1.994184 1.751119 0.309148 2.108164 0.421055 1.925977 0.649125 1.097819 0.287849 1.878941 2.108981 0.642933 0.518591 0.954365 1.255656
+1 -0.005410 1 1 -1.013063 -0.685315 -1.012311 -2.179674 0.332197 -0.954199 -0.969019 -0.286208 1.048036 -0.561963 -1.290217 1.733994 57.844323 39.544571 -24.391486 2.286471 28.717652 0.738696 1.256710 2.268721 1.135055 0.622833 2.453248 1.994276 1.041531 1.504109 2.303396 1.180633 1.655138 0.407796 1.822077 0.397733
+1 0.012872 1 1 -1.857202 0.872242 -0.477108 1.735493 -1.256016 1.647671 -2.308603 1.116307 1.755116 -1.325087 0.019472 2.105931 -11.935487 -49.735672 42.568660 -48.535291 -32.633490 0.309009 2.010541 2.168626 1.847814 0.964941 1.255791 0.328701 2.222966 1.642199 1.185325 1.749772 2.424819 1.182587 0.742948 0.725447
+1 -0.020169 1 1 0.083255 -0.312699 -1.217378 0.725195 2.117374 -1.251510 1.981860 1.948486 1.813579 1.084523 0.059667 -0.923477 55.088240 68.057765 -53.151189 -62.026705 17.162333 1.334886 2.182355 0.836187 1.791015 0.334466 2.364541 0.585084 0.253463 2.199279 1.776080 1.329972 0.592586 0.337363 1.565786 1.673585
+1 -0.003377 1 1 0.274574 1.340005 0.954186 0.745447 -1.514262 1.404936 -1.026582 -1.702118 1.420538 2.025892 2.160422 1.261967 -18.536750 2.843286 -62.886827 -38.903195 3.998532 1.424974 2.031380 1.404728 1.506314 1.110701 0.801193 0.896655 1.082956 2.497942 1.653634 2.134620 1.807205 2.439622 2.469802 1.208566
+1 0.003026 1 1 -2.189955 1.889059 2.045994 0.713395 1.710839 -0.919704 -0.834653 0.771247 -1.429087 0.384062 -1.050172 -2.334840 -50.691873 21.685232 -36.305200 18.503804 43.433654 0.466222 0.542993 1.576754 1.502390 0.411961 2.075929 0.889088 2.148631 1.043616 0.558704 2.390503 0.437241 1.701416 1.943361 0.314391
+1 -0.006228 1 1 1.328465 0.218557 2.331317 -1.067243 -1.807211 2.262908 -0.992184 1.501225 0.951935 0.617741 0.986445 0.992608 28.746837 -1.907688 37.486286 32.006479 32.899397 1.977424 1.323443 1.105409 1.864545 0.914506 1.848937 1.832088 2.157619 1.351897 2.340409 2.246129 1.684933 1.673511 0.950460 0.887408
+1 -0.012972 1 1 1.733281 -0.731446 1.214073 0.274868 1.567406 1.141768 0.845583 -0.854435 -1.841845 -0.204470 -1.189169 -1.117966 -43.318645 43.536793 22.883196 -2.117989 -47.032772 1.678000 2.136809 0.341917 1.599020 2.227947 2.099632 1.016828 0.332050 2.264415 0.767432 0.483708 1.929024 2.359102 1.427002 2.373960
+1 0.005535 1 1 2.336849 -2.339685 1.799995 -1.015730 1.617885 1.314431 -0.045753 -0.844130 1.713876 -1.713007 2.186465 0.714186 27.910462 41.136398 29.434326 2.722400 5.381452 1.315969 1.493087 1.557462 1.265690 2.455656 1.956239 0.756839 2.445308 1.293547 0.391186 1.662113 0.624289 2.171361 0.558802 1.780372
+1 0.024486 1 1 1.598097 -1.395622 2.060812 0.002960 -2.082345 0.933519 2.113377 2.258391 -1.514355 -0.155126 -1.254843 -2.197526 60.130087 56.364772 72.731129 42.079778 -15.165279 0.882224 1.535326 0.481227 0.731766 1.798157 1.130761 0.443612 0.790413 1.968071 1.626320 2.062095 2.373001 1.020323 0.560736 0.532636
+1 -0.014709 1 1 1.772445 -2.247126 2.349975 1.496306 -1.608710 2.097812 -0.165706 -0.000840 0.019842 -1.092577 1.231640 -1.345259 8.656877 -3.867217 -46.314226 -53.192990 -14.575612 1.040318 1.373932 1.424444 2.136326 1.230267 1.094077 0.397251 2.347087 1.997653 1.559681 0.313133 1.583053 1.624758 0.558660 1.651510
+1 0.064804 1 1 0.873808 2.292653 -0.580884 1.144788 -0.236866 0.959091 -1.643146 -1.748733 0.213243 -2.159115 1.861562 1.718548 44.689309 43.214029 -1.815563 -64.174560 68.169128 1.653134 0.465863 1.259455 1.156083 0.786080 1.152995 0.643002 1.692587 2.063159 2.270913 1.986507 0.970720 1.635778 1.274342 1.607133
+1 -0.052447 1 1 -0.725471 -2.033464 -2.185407 -1.777930 -0.413454 1.849075 -0.801619 -0.084386 0.149526 1.377928 2.154631 -1.834908 -45.352562 59.486706 43.065207 46.935128 -11.308594 1.171829 2.174845 0.616448 0.888887 1.023187 1.446546 2.344788 1.601793 1.589458 1.270245 0.262028 2.152072 0.366654 1.102926 0.628019
+1 -0.008475 1 1 1.633749 -0.670891 1.083129 0.189887 1.147006 -0.660309 -0.131227 -0.127812 0.715543 0.109200 2.202006 -1.994179 -52.577267 -16.125988 20.518876 10.743533 -33.437375 2.395685 2.036530 2.464732 1.493915 1.982023 2.108172 0.549727 2.255868 1.117326 1.899975 2.380807 1.732184 1.557755 1.688027 1.910975
+1 -0.025084 1 1 -0.919709 -0.917414 -0.033613 0.557925 -0.609763 1.166156 0.754536 0.442660 -1.073748 1.964268 -1.543306 -1.362371 3.863961 -8.402661 -73.522145 13.306284 -11.287687 1.942689 0.270946 1.283011 1.057159 0.922019 2.125078 1.194171 1.927554 2.396731 1.600993 1.631914 1.583542 0.837644 1.537778 1.175950
+1 -0.020465 1 1 1.585356 1.224868 -2.071221 -0.591718 -1.863055 1.451845 0.408042 1.430757 -0.589489 -2.093537 1.330902 -1.247847 72.606274 43.652130 11.348857 -59.753315 -23.970750 1.729154 2.394126 0.570076 2.259290 2.387642 1.845436 1.493362 1.685212 1.855779 2.082782 1.311208 2.473047 1.754842 2.130965 1.125716
+1 0.005288 1 1 0.501411 1.470028 -0.293874 -0.562495 -0.800131 1.350028 -0.228624 -1.885092 -1.357219 1.888168 1.210217 1.454333 -6.188800 -65.156360 67.060400 -15.864136 71.460447 1.160983 2.146770 1.257875 1.611549 1.299444 0.510517 0.257548 1.108377 2.234294 0.772274 0.862747 0.446444 1.135493 1.235787 1.625880
+1 0.008373 1 1 0.203956 1.988390 -1.387799 1.594942 2.127648 1.776704 -1.340871 -1.381248 -1.409894 -2.190286 1.052828 -0.148155 -60.378176 -26.001913 -64.160140 10.526349 66.343220 0.332529 1.319046 1.453820 0.851829 1.436033 1.152569 2.472219 1.331690 2.465285 1.790603 2.412696 2.174333 1.020647 1.509062 2.313852
+1 -0.025087 1 1 -0.489863 -0.591780 1.802285 -0.234273 2.127606 1.066747 -1.823522 1.434629 -1.480766 -1.103233 1.220886 1.695039 67.751867 55.626233 -39.897169 -51.722403 -48.431126 2.395976 2.414509 1.146752 1.462205 2.278335 0.724878 0.781845 1.977278 1.104016 0.947499 0.611852 2.393655 1.667202 0.656383 1.584521
+1 -0.033672 1 1 2.160462 1.927557 -1.230479 2.017868 -0.755465 -1.927466 -1.964630 0.171528 -1.115565 1.298020 2.172669 -0.261414 -52.163810 32.850536 -31.037771 48.181917 -56.516000 0.408722 1.647830 1.319682 0.898988 2.039674 1.294908 0.762924 1.220724 0.462042 2.294318 1.603195 0.402222 0.392092 1.143902 0.809102
+1 0.004594 1 1 -1.001939 -2.221321 -2.203882 -1.274464 -2.108318 -2.045110 -0.002461 1.057007 -0.586873 -0.538953 -0.965807 1.865355 -16.078636 66.360843 -73.309106 -6.137998 38.673134 1.815468 1.827531 2.058667 1.024728 0.359838 1.302468 1.830306 1.454535 1.613347 2.273501 0.481906 0.897526 2.216117 1.271762 1.003577
+1 -0.046505 1 1 0.869591 2.090639 1.802900 0.675160 -0.012164 -1.811082 -1.539763 1.640839 0.681302 -0.459113 -2.134381 -1.842092 11.187932 -64.430310 -30.216874 44.998709 -6.696574 0.635233 1.610524 2.076374 1.620306 2.238779 1.915497 2.261160 2.309978 1.554492 0.853010 1.047351 0.319433 1.717185 1.472753 1.809040
+1 0.003471 1 1 -0.408354 -1.975002 0.208049 0.083362 1.480967 -0.233485 1.239975 2.072682 1.584521 1.327157 1.797053 1.373631 19.731662 -19.955577 6.610309 -50.535887 -56.645811 1.432785 0.564207 0.370641 0.612963 0.817928 0.918894 1.353118 0.363450 1.248750 1.237693 2.162553 1.030523 0.997961 0.476091 2.155914
+1 -0.018007 1 1 1.708618 -0.560877 -1.884725 0.101672 -1.796496 -1.435493 1.108324 -0.468517 0.029559 1.991929 1.542425 0.678545 10.073889 -38.154732 -16.577588 -69.525338 -12.348862 2.165149 1.907587 2.067861 0.293666 0.639166 2.463856 0.284683 0.410902 2.274498 1.487871 1.652158 2.064638 2.369493 0.563297 0.828892
+1 0.062791 1 1 2.336361 -1.114120 2.012482 -1.735826 0.379806 -1.895425 -0.660567 0.235486 -0.587632 0.832814 1.310649 -2.338778 -57.615437 57.353450 39.435723 -53.806084 31.154227 0.761410 0.525664 0.581382 1.043219 0.628886 0.691016 0.911339 0.375844 0.307079 1.070421 1.062142 1.416238 1.467071 0.810364 2.037432
+1 0.052768 1 1 -0.870972 -1.741088 1.470308 -0.310071 0.534151 0.368995 0.199726 1.578147 -2.125274 0.429535 -0.185954 -1.011482 74.074602 -28.158536 -10.508225 -61.732320 14.904149 1.285539 0.810924 2.452032 1.799772 1.270614 1.950757 0.868428 1.419798 0.550020 0.435688 0.355655 0.747919 1.025593 1.399070 0.925524
+1 -0.023716 1 1 1.788269 -0.177608 -2.115809 -0.708452 1.249374 -0.181506 -1.650875 0.295380 2.313532 1.609085 -0.505301 -0.873392 -0.476482 -58.231189 58.408417 70.262722 -44.437714 1.155018 0.889559 1.067653 1.791864 1.114506 1.752013 1.839593 2.286071 2.497264 1.521210 1.718985 2.478172 2.385231 1.831878 0.865185
+1 -0.041713 1 1 -0.996223 -0.397280 0.372040 -0.466301 -0.410443 0.616668 1.800542 -1.258123 -0.788896 1.689010 -0.243930 0.052013 -73.777092 -71.585101 19.199990 44.235275 62.271558 2.096088 2.203108 0.889523 0.458176 0.319497 0.538941 0.987652 0.474171 1.394176 1.909538 1.101100 1.431204 1.002574 1.506822 0.661757
+1 0.011744 1 1 1.809938 1.160173 -0.838183 -2.005072 -0.950046 -1.852668 1.675445 -2.034862 -2.124670 1.154011 -0.732972 -0.876637 63.545204 4.250983 46.264619 -30.541910 -17.880602 0.335864 1.121501 2.309617 2.230488 2.066206 1.723723 1.109961 1.861257 1.897779 1.479381 0.699751 1.457440 0.947543 1.360178 2.010807
+1 0.004624 1 1 -0.755756 -2.106148 1.435887 0.800072 -2.355844 -1.178299 -2.206896 -0.086646 -0.135624 1.358367 -1.457977 0.201220 -50.580637 -58.759114 35.565541 0.044697 1.229902 0.939384 1.479275 1.175188 2.382050 2.363381 1.341290 1.818245 1.241342 0.480550 0.602494 0.359366 2.371771 0.610563 0.974493 2.060503
+1 0.010512 1 1 1.575572 1.723752 -0.660902 -0.684022 1.872525 2.195987 0.517105 1.332224 2.136356 2.046295 1.066486 -1.490814 -10.646970 6.382568 21.813091 12.615444 -72.239459 0.946182 0.987964 1.211274 1.384912 1.461444 0.746690 0.621750 2.255396 2.191014 2.374277 2.228648 0.388075 1.132721 1.892889 0.285011
+1 -0.027451 1 1 0.033654 0.128871 -1.762026 -1.720757 -0.835793 0.459739 -1.480518 -1.658702 0.689221 0.691655 -0.823026 -1.735550 9.274243 22.195012 -18.435977 46.539249 -64.846331 1.790608 2.492994 1.752040 2.281252 0.259416 1.005708 2.430117 2.472918 1.837715 2.218775 0.945296 1.839783 0.989103 2.349747 1.688779
+1 -0.003725 1 1 -0.017172 -1.152278 1.591227 0.943705 -1.053594 1.401313 -0.659388 1.199233 0.622026 2.310671 0.643716 -0.706635 -38.128049 -18.111368 -47.766047 -3.956708 -50.396436 1.931585 0.393066 1.767357 0.970107 0.344093 2.168511 2.163940 1.839219 0.508591 1.642390 2.153712 0.929395 2.340031 0.395112 2.401002
+1 0.015725 1 1 1.362373 -0.097860 -0.107788 -2.043560 -2.214466 -0.090720 2.090674 -2.331898 0.737836 -2.203657 -2.189411 1.606723 70.202091 -13.453297 -59.564395 1.212303 -24.819117 1.601399 1.713102 0.355389 0.776082 1.865551 2.063371 1.319158 1.089286 0.883446 1.825413 2.473151 1.242918 2.227187 0.577866 0.447273
+1 -0.033174 1 1 -2.181261 1.932643 -0.558584 -1.042747 -0.078924 -2.287651 -0.174401 -0.048076 -2.192778 1.582825 1.106463 1.229264 36.096484 73.600098 -53.146243 21.097554 -13.412909 1.663496 1.372110 2.298191 1.438004 0.532781 0.956057 0.451452 2.053199 1.370381 2.484958 1.697312 0.474303 1.367847 0.399363 1.841071
+1 -0.016473 1 1 -0.531777 1.819062 -1.010879 -1.677941 -2.209526 -1.875129 1.158983 -1.985522 -2.249206 0.384009 -1.941398 -0.500074 68.916500 -20.380457 65.650990 -3.806839 68.461030 0.992985 2.348287 1.905636 0.765059 1.094541 1.451354 2.160223 2.372707 0.581979 2.077755 2.330496 2.149039 1.155409 0.709072 0.623554
+1 0.033947 1 1 1.379758 -0.079326 0.376453 -1.698775 1.048889 -0.375365 1.134878 -1.850114 2.192275 -0.610116 -0.060238 0.736282 -1.301458 26.400068 5.948866 -67.415620 45.678787 1.725688 0.387106 0.591079 2.012152 2.239045 1.884587 0.251439 1.928210 2.174662 2.045398 0.756780 1.444869 1.166742 2.179554 1.009736
+1 0.029607 1 1 -1.111514 -1.301660 -2.094253 -1.271033 -0.996028 -1.833613 1.496629 -0.892489 -0.533350 -1.041316 0.417942 -1.827525 4.149160 -15.066501 -22.680429 -39.963477 33.847616 0.278194 1.598726 1.791294 0.528814 1.775438 1.785699 0.991730 1.498293 1.318810 1.993552 2.376424 2.303317 2.097413 1.975812 1.230061
+1 -0.008673 1 1 -1.202980 -2.329899 1.334709 1.489594 -1.322476 1.491406 0.863934 1.270201 1.141579 -2.338271 2.000449 -1.352956 -58.796773 2.636884 68.118435 66.537071 38.545122 1.042971 0.964508 0.742981 1.280722 0.839910 1.374312 1.067952 2.321794 2.135568 1.986535 1.442879 1.461883 1.376726 1.125604 1.533869
+1 -0.025153 1 1 -2.290879 2.130177 1.860626 0.128373 -0.708253 -0.108772 0.283871 2.085310 1.766580 -1.858308 1.138215 -2.325436 30.439516 -53.048778 9.193815 20.449949 52.293747 2.140105 1.749712 1.404323 1.457316 1.103776 1.417445 1.496874 2.217183 1.193482 1.607713 2.078567 2.480211 0.647477 0.401775 1.883368
+1 -0.017953 1 1 1.544047 -0.327604 -1.964476 -1.953556 -2.197286 1.204564 0.677450 0.775341 1.395054 -2.167864 0.893299 0.009290 20.093340 58.767817 -39.298917 -46.898979 18.856335 0.901361 1.424649 1.084092 1.335153 2.167874 0.457167 1.363719 0.775925 1.468552 0.944585 1.137309 0.255593 1.995861 0.684730 1.004755
+1 0.008987 1 1 0.467622 -0.948428 1.790211 -0.520312 1.310293 1.095362 -1.555591 -0.477546 -0.920442 0.911307 1.079802 0.830288 40.324033 26.023229 -27.589764 -51.158542 -21.621073 2.344365 1.237465 0.576396 0.481362 0.754444 0.444727 1.532358 2.344134 1.853375 2.174052 0.783050 1.970348 1.638226 1.919969 0.924387
+1 -0.022853 1 1 -0.451771 -1.256372 0.368906 -1.307375 0.823341 2.323758 -0.885179 -0.187790 1.117622 0.295154 -1.486823 0.761602 44.692721 -49.430033 -70.558267 27.209412 -41.406564 0.323200 2.016037 2.291787 1.816395 1.651205 1.807334 2.355252 1.975390 0.879468 2.472522 1.930489 2.235998 2.413058 1.522480 0.568643
+1 0.048421 1 1 0.313314 2.127070 1.474035 1.080184 -2.184922 1.661428 -1.988450 0.382388 -0.895824 -0.038591 1.704590 -2.276637 37.009721 -27.614086 -9.938026 71.589532 55.260478 0.817870 2.193161 2.458226 2.408918 1.690178 2.064287 0.973396 1.610608 1.236547 0.894934 1.405844 2.278230 1.210723 1.118829 2.409292
+1 0.002640 1 1 2.216232 1.490828 0.583209 0.227574 -1.616951 0.246867 2.185820 -0.700552 2.077729 1.585331 0.803725 -2.212606 -57.411090 41.818638 -54.148941 -31.253932 15.171524 1.192086 0.632679 1.429556 0.306196 1.979101 2.494886 2.042640 1.652276 1.810796 2.055816 0.356552 2.317615 1.648392 1.774871 1.265831
+1 0.066848 1 1 0.216265 1.508370 -1.482771 -1.823362 -0.584053 -0.269821 -1.567297 0.694679 -1.822825 -0.976736 1.958095 -1.624787 15.911021 -33.471067 -48.224594 -60.751959 -8.174125 1.637274 1.672861 1.271000 1.701453 0.312558 0.906691 1.000023 1.378207 1.280728 0.938294 1.152963 2.343556 1.147939 1.169317 0.467726
+1 0.022250 1 1 -0.863224 1.244400 1.050059 0.452107 2.193141 -0.191610 -1.830998 -1.687324 0.296595 -0.832735 0.022853 -2.317977 -29.139372 4.569543 0.314744 39.901093 -32.325957 1.339617 0.694664 1.473454 2.347167 1.081085 0.290527 1.892212 2.401917 1.025175 1.113209 2.460326 1.693051 0.866189 2.030488 2.154730
+1 -0.056621 1 1 -1.467723 1.339140 0.552904 -0.178587 0.285826 1.960978 -0.296104 -0.341418 1.478445 -0.195478 -0.870496 1.546690 53.621275 12.762908 6.197549 62.201316 67.518349 1.838495 1.835173 2.248468 0.494876 0.638134 0.866147 1.339427 1.999575 2.348943 1.680098 1.405340 0.547347 0.516011 0.340243 0.460824
+1 -0.000227 1 1 0.835051 1.208439 -0.158063 1.224360 -1.187800 -1.680136 -1.407759 0.697851 -0.359201 -0.524127 -1.549887 1.127976 -1.513625 60.502357 13.111458 14.273680 47.738527 1.246415 2.499438 2.051185 1.270686 0.916487 1.402478 1.950436 2.229550 2.049621 1.983001 0.552751 1.343266 1.274336 1.516920 1.632812
+1 -0.035919 1 1 -1.838269 -1.359070 -0.941592 -1.137660 2.216993 0.148825 -0.981699 -1.348061 0.303670 0.261993 1.942808 0.632076 50.229045 -0.436904 6.949544 -49.017272 -33.291948 0.808559 0.948527 2.148122 1.484390 1.637848 2.313741 1.786289 1.906276 0.278305 1.213836 1.693124 2.088751 0.397027 0.828814 1.624383
+1 -0.030509 1 1 -0.852170 -1.473344 1.112889 0.859058 -0.565588 -0.942386 -0.347247 -2.245995 -2.201896 -0.882464 -1.677988 1.707859 26.028598 62.642795 -12.537703 28.820110 29.590298 2.487120 2.018600 0.353768 0.529147 0.625505 2.354436 1.751664 0.461052 1.405525 1.416559 2.348782 1.224812 1.658877 2.494861 1.635460
+1 0.033552 1 1 -0.326799 2.139286 -0.554762 1.937701 -0.372005 1.053149 0.548445 0.287577 -1.607809 -1.605682 1.159162 1.015587 22.070745 -6.994182 48.781124 -35.656346 -26.203138 1.432792 0.691628 2.187370 1.873214 0.350726 1.152286 2.227631 1.296846 1.845205 2.112477 0.897592 1.077846 2.115914 2.422891 0.274445
+1 -0.014960 1 1 -0.146136 -0.953614 -0.557219 -1.669053 1.079578 1.765889 0.667425 1.934289 -1.181355 -1.743603 1.604020 -0.815690 -30.368627 44.493754 56.522823 29.092815 -37.055420 1.518254 1.540932 2.441217 2.290380 0.664528 1.221640 2.358866 1.966470 1.709155 1.515405 0.911020 1.770124 2.479625 2.064251 0.365152
+1 -0.014890 1 1 -2.330481 0.979190 1.584376 -1.100860 -1.307208 -1.080494 1.690614 -1.561426 0.400534 -2.225048 1.143183 1.065473 10.130403 11.677312 60.581720 -3.027516 -33.455730 2.268235 1.977762 2.489509 1.682314 0.394162 2.173827 1.511765 0.487913 0.607226 1.139549 1.908463 1.030369 0.663351 1.693668 2.220792
+1 0.038044 1 1 -0.754937 2.229226 -1.607644 1.171855 2.301270 -1.847567 -2.133659 0.880222 1.698765 -1.228130 -0.914182 -2.274644 52.944779 42.901658 -1.826240 56.392229 -65.815183 0.538324 1.862182 1.690550 1.568206 1.833759 0.978283 0.509915 1.387307 1.219333 1.831289 2.215272 0.578694 0.862659 1.215728 1.995012
+1 0.007375 1 1 0.383990 -2.254185 1.516917 0.804432 0.246747 0.182524 -0.085945 2.219614 1.783883 1.506805 0.496627 1.167711 -44.234990 -57.474776 21.437811 5.294760 39.031009 2.037421 1.681782 0.465738 1.405122 1.387336 1.704963 0.816812 2.403317 2.048705 2.336124 2.242720 0.636971 1.565265 1.901813 1.778615
+1 -0.074951 1 1 1.370888 1.639597 -1.347048 -1.526422 -0.328789 1.677212 -0.616571 -0.166460 1.469141 -1.072448 0.249644 1.742413 62.044663 -15.351316 -9.563356 68.678020 21.485792 2.300658 2.411606 1.855470 1.380105 1.672317 1.140052 1.346519 1.950305 2.269614 0.408614 2.080370 1.285675 0.842054 1.409413 1.505118
+1 0.022870 1 1 -1.623315 1.678911 -0.334728 0.823808 0.736244 -0.682282 -1.873990 1.449063 0.782814 -0.237978 1.115196 1.922727 -72.705069 -54.092284 20.980025 -38.721986 49.576910 1.211958 1.626620 0.354984 0.720639 1.537258 1.438640 2.220994 2.239693 1.516097 1.288250 1.372004 0.515334 2.465443 2.195879 0.882692
+1 0.060533 1 1 -2.017529 1.750063 -1.423631 -2.167373 -0.265474 0.809657 -1.470250 1.271888 1.228174 1.662975 0.444883 -1.404804 -46.857392 -32.190584 22.861774 -62.158367 54.330384 0.336405 1.216649 1.727823 0.265096 1.972916 2.054595 2.333740 0.412474 1.697088 1.201346 1.019210 2.107724 2.024185 1.984341 0.563604
+1 -0.016291 1 1 0.646153 -2.170457 -0.269647 1.362448 1.160332 1.832031 0.197496 1.787532 1.578900 1.113520 2.036874 -1.760598 -40.611797 -62.469379 -72.850382 53.632056 43.964096 1.443523 1.041464 0.377428 2.189184 0.866253 0.861472 1.502681 0.817093 0.378305 1.180043 0.731576 0.846253 2.219720 1.083209 2.245066
+1 -0.011245 1 1 0.081960 1.480408 -0.203451 1.787322 -1.956097 2.218784 1.968417 2.214327 -2.251033 -2.052306 1.578232 -0.691308 61.783641 -52.339253 -65.829564 2.518276 24.660008 1.536253 0.311892 0.976562 0.823135 0.685543 1.164947 1.267922 1.716630 1.144879 1.483166 1.328003 1.254671 1.749501 2.364988 1.360308
+1 -0.017361 1 1 -0.960104 -1.252244 -0.939906 -1.078098 -0.460152 -0.740886 -1.931478 1.296583 1.579470 1.273202 -0.252256 1.484875 -16.359236 0.319080 -37.224452 18.634559 -8.961773 1.067240 1.606271 0.345680 1.849676 0.754397 1.900511 2.393386 1.643840 1.767313 2.471182 1.914301 2.406217 1.286191 0.510353 2.006654
+1 -0.010387 1 1 -0.593128 -1.994689 -0.805039 -1.030012 1.913766 -2.098240 -2.304976 0.821880 1.323321 -1.425223 -0.657800 -0.384027 51.698263 -57.290204 -26.463728 -25.884763 -45.217423 0.336531 1.073060 0.419852 1.959426 0.330710 2.243982 1.611286 1.379854 1.963863 0.654078 1.085629 2.411491 2.174959 0.282748 1.646505
+1 -0.022481 1 1 -2.226247 -0.162782 2.027584 2.319157 1.907585 -2.307512 0.601351 -1.163646 -0.977205 -1.205358 0.111340 0.474676 -6.226865 45.073172 44.799742 -50.729630 -12.898701 0.797895 1.724280 1.472754 1.825857 0.934295 1.438640 2.221416 0.342733 1.818784 1.305357 0.891434 1.089130 0.505852 0.604573 1.564698
+1 -0.007071 1 1 -1.265156 -1.185099 1.303915 2.295019 1.486351 0.721022 -2.047424 -1.197794 -0.004339 -2.237932 1.371799 -1.896532 -12.933640 -25.690836 64.118274 35.829444 -64.531140 0.252044 0.851754 2.434696 0.687351 2.315168 1.023385 0.276805 0.758439 2.328382 0.361631 2.186383 1.032336 2.221313 0.853530 0.781121
+1 -0.006748 1 1 1.936978 1.603723 -1.086758 0.080088 -1.702708 0.919118 0.407769 1.558998 1.196907 -0.769957 -0.444715 -0.477566 -40.047301 -24.990419 -13.978322 -33.662295 37.800171 2.237151 1.545015 1.315590 1.865427 2.236015 0.461167 1.079715 2.014267 1.784395 1.581584 1.678675 2.245672 0.763041 0.928230 0.766115
+1 0.011658 1 1 2.050992 -0.102338 0.025193 -0.696853 -1.721312 -0.733842 -1.355296 1.231202 0.708577 0.840925 0.969505 -0.974651 -22.373198 23.665214 -58.748245 68.241217 30.134636 2.467533 1.324310 2.180177 2.484929 1.193139 0.342876 1.961892 1.272527 0.358829 2.333219 0.657872 1.849773 2.382221 0.741027 2.194462
+1 -0.006610 1 1 0.946434 -2.314245 0.536332 -0.666854 -1.762252 -0.800720 0.878850 2.210555 0.323783 -0.983517 1.083872 -1.460736 30.466057 -56.972731 59.312606 -33.023296 -22.529571 0.557388 0.522884 1.116628 1.408989 1.127178 0.973117 1.426896 0.585504 0.561952 0.723107 0.259891 2.233527 1.388883 0.702604 2.173003
+1 -0.022684 1 1 -1.932029 1.466174 0.896839 -1.763434 -1.822923 2.084790 -2.257009 1.177048 0.041791 0.234576 -1.755816 -1.018461 -59.542594 67.627259 61.346169 -54.932206 4.416526 1.053207 1.993865 0.888180 0.388086 1.306085 1.869319 2.387405 2.361026 2.256765 0.448978 0.979629 0.632640 0.775229 1.023649 2.468336
+1 -0.009472 1 1 -2.205305 -1.626535 -0.601699 0.036940 -1.177451 -2.100034 0.525603 -1.922929 -1.101495 2.142908 -0.929442 0.439837 -44.605905 8.561491 42.973434 4.509187 35.904588 1.351204 1.933014 1.914729 0.607412 2.020048 2.201609 0.436714 1.849557 1.008837 1.026828 1.903938 1.491852 1.059884 1.726812 1.275103
+1 -0.002848 1 1 1.718633 -1.875868 -1.835954 -0.162925 -0.380554 -1.261678 0.731784 -0.235776 0.428092 -0.881238 0.067929 1.284254 54.721200 49.213337 28.550680 1.271045 62.458581 1.995653 1.682234 1.306117 2.401455 2.253350 1.544796 2.140522 2.008560 0.366846 2.075469 2.154207 0.254347 1.308736 1.432160 1.318905
+1 -0.006094 1 1 -1.041401 -1.006730 2.068592 -1.179652 -1.396702 -1.964203 -2.077371 -0.286650 -1.661671 -2.080177 -0.315060 1.518171 -53.559628 -26.673318 51.540001 -17.205454 27.938764 2.377048 1.536645 2.386178 1.987629 1.827971 0.458073 0.834608 2.261484 1.005769 1.217465 1.931932 1.734046 1.365173 0.461971 1.089875
+1 0.027289 1 1 -1.962813 -2.266822 1.178631 -1.637028 2.111275 -0.086047 0.510627 0.850703 0.378566 0.827375 -0.567614 -2.005951 -50.488698 -13.549725 -30.233289 69.119193 -63.728621 2.321122 2.103269 1.399593 0.700535 1.147956 1.446453 0.786574 0.441250 1.581020 1.196280 1.370594 1.565992 0.627655 2.495527 1.572210
+1 -0.015765 1 1 0.563141 2.237958 -0.936199 -0.022279 -2.164472 1.357076 0.407084 -0.527379 0.349517 -2.025090 1.896279 0.880359 -22.701176 61.337728 -46.803541 -27.107371 -43.590183 1.071831 2.265463 0.390991 0.642729 1.594439 1.731870 0.782017 0.360999 0.563395 2.484627 0.621423 1.258679 1.611654 0.821524 0.605544
+1 -0.004135 1 1 -0.458356 1.173232 1.883526 -1.413869 1.675294 0.150448 -1.979734 0.792680 0.647572 -1.871458 1.603096 -2.208994 74.704647 60.998901 -41.465082 -3.628153 71.627922 0.632207 2.498208 1.635931 1.594916 0.759418 0.781889 0.456903 1.411622 0.387068 2.208376 1.668514 2.465786 1.211297 1.766048 1.470189
+1 0.042166 1 1 1.994579 -1.049701 0.863354 0.953001 -0.329274 -1.768269 1.734683 -0.728379 0.922830 1.523704 1.770710 1.582740 -10.112490 -10.624670 -68.831001 -42.626535 -24.177143 1.446258 2.011132 0.851151 1.303009 1.924293 1.589379 2.190565 1.570667 0.446844 1.105865 0.531208 1.509660 1.100026 1.384757 1.113593
+1 -0.000844 1 1 0.367654 1.210515 1.745907 -0.592353 1.602845 -1.704384 1.037875 -1.697191 -0.606179 0.136323 0.966003 1.425786 21.718716 -73.540335 7.582473 -61.367260 0.463420 1.205470 0.586632 1.531410 2.152671 1.433662 1.804819 0.592524 1.546176 0.587488 2.402842 0.822664 1.769321 2.474343 1.029924 2.187204
+1 0.022914 1 1 0.983199 -1.728359 -1.369771 -1.719764 1.722174 1.078586 -0.771609 0.064942 -1.786055 -0.309306 -0.748881 0.354101 -11.860022 18.603383 67.053805 23.298040 70.150985 1.788982 2.161270 1.964481 2.033158 2.041055 2.010416 2.303111 0.894452 2.312719 0.373231 1.397825 2.491147 2.200168 0.979167 1.855496
+1 -0.038270 1 1 1.662478 1.507656 0.655897 1.380335 0.193138 -0.769659 -0.144695 -0.299858 -2.162294 0.261663 1.114543 0.380196 -1.244757 -70.632253 -16.277006 32.354540 32.747275 1.876679 2.347250 2.489109 1.708032 0.645616 0.615189 2.230131 0.567764 1.651378 2.466818 0.554146 2.276337 0.900611 2.324099 0.383844
+1 0.010265 1 1 0.671261 0.419208 0.609355 1.405377 1.680212 -2.028735 1.892930 1.142030 0.530319 1.939028 -1.631961 -2.268597 -11.770348 25.762530 -59.163419 -9.582913 39.981077 0.804397 0.748683 0.366159 1.784437 2.276642 1.516756 1.115435 1.616594 0.603393 1.976713 0.612393 2.489368 1.556128 1.344575 0.764041
+1 -0.011742 1 1 -1.531752 -0.377022 1.562587 0.248618 -1.359362 -1.142181 1.634006 -1.063679 1.556068 -0.930948 -1.306258 0.739966 19.339973 -3.080644 -26.388504 38.417058 -74.500292 2.478949 1.944769 1.480134 2.108711 0.607086 1.043863 2.461636 1.214523 1.995074 0.961531 2.454042 1.839049 2.150245 1.161405 2.477939
+1 0.011113 1 1 -2.195852 1.751956 2.111956 1.924982 -2.090043 -1.200721 -2.067136 2.092055 2.027695 -0.534139 -0.180829 0.298821 -35.480895 72.595531 13.094269 25.384390 35.441250 1.541398 1.280469 1.089722 1.463083 1.291681 0.531151 0.559619 2.010808 2.143597 1.938741 1.420572 2.301535 1.395667 2.230224 2.121664
+1 0.007299 1 1 -0.184189 0.378264 0.467129 0.191463 -0.646992 2.194153 -2.021296 -0.315740 -0.484265 -0.739281 1.477540 -1.281418 -37.246507 -52.048898 14.163287 -7.634571 -64.240280 1.579094 0.326790 1.609763 0.533547 0.332563 1.891226 1.582858 0.590230 1.253190 1.615720 1.664112 0.478298 1.005586 0.391361 2.359298
+1 -0.014602 1 1 -0.720808 0.926645 -0.329206 -0.614414 -1.605270 -1.349895 -2.243767 2.257846 -1.258869 0.818687 -0.498970 1.868565 51.460360 -5.727083 44.915334 -57.976684 -14.133683 2.202758 1.753569 0.978461 1.241650 1.160176 2.079714 1.495787 1.940793 2.158517 0.691051 1.499033 2.495662 1.594130 1.046802 2.353150
+1 0.024166 1 1 0.261814 -1.070509 -0.138128 1.685224 2.105065 -0.791847 -0.792348 0.210787 -1.011178 -1.993745 0.920046 1.860821 -41.766306 33.686884 -74.538525 31.003939 -16.802471 2.137964 1.754760 0.756011 2.021135 2.462185 1.449579 1.565665 1.885780 2.305173 1.800250 0.293178 1.443942 1.332642 0.472554 1.212923
+1 -0.050872 1 1 1.818582 0.347457 1.060563 -2.085351 2.261152 -2.229685 -1.407769 0.529784 -2.327569 -1.906993 -1.873398 1.974788 28.934560 3.154943 -74.865757 -68.784530 -11.590493 2.103739 0.293521 0.455750 2.294193 1.760978 1.753971 0.988014 2.048122 1.543100 0.632829 1.714684 2.190953 1.349573 1.518931 1.672142
+1 0.017746 1 1 0.338805 1.733058 0.225620 -1.482366 0.271466 0.943567 1.337732 0.462798 -1.909807 -2.040075 -0.194722 -2.295371 64.608597 26.693394 -14.128787 -12.518339 54.272241 1.428240 0.679596 2.468876 1.395352 1.425431 0.710598 1.519378 2.437241 0.702844 1.699007 1.962362 2.416297 1.950403 1.678449 0.684731
+1 0.016999 1 1 -0.100819 1.995893 2.181151 0.939094 1.557937 2.218865 -1.385612 0.651110 1.045857 0.506563 -1.484250 1.597931 16.822611 -12.381207 -40.941059 -46.374165 -10.587588 0.691153 0.952383 1.708718 0.925466 1.558139 1.396618 2.464689 0.775754 0.844392 2.441498 0.260984 0.351820 1.539210 0.503663 2.066374
+1 -0.025323 1 1 0.249005 0.419397 -0.928585 0.708127 -2.010073 -0.177685 1.301176 -1.336476 1.808561 1.575114 -1.257140 1.603254 14.377020 -15.428520 42.871970 -50.792498 -19.521945 0.545064 0.390788 1.729618 1.188878 0.728439 2.124885 2.437695 1.586401 1.639317 2.252938 1.378908 1.800963 1.031522 2.048020 2.064621
+1 -0.014392 1 1 -0.734510 1.545922 -1.807567 0.993990 0.577308 0.014238 -1.026067 2.230338 -1.755598 -2.064852 -1.928646 1.769407 -46.389332 34.492695 -31.271445 20.831559 16.015877 0.307762 1.307322 2.408595 0.759618 1.906735 1.241332 0.321731 2.089043 0.799464 1.099307 0.548206 1.440465 1.395867 1.083639 0.472745
+1 0.006967 1 1 0.090357 1.240384 -0.467834 2.086910 0.387750 -0.319162 -1.462898 2.314644 1.456668 1.365880 2.303417 1.261522 43.570582 -9.226450 31.058136 -5.908180 1.219981 0.688243 1.547362 0.270827 1.546202 1.025608 1.638223 1.858601 2.253706 0.784293 0.365175 0.994820 1.686856 2.493959 2.212626 1.108002
+1 0.004950 1 1 -1.786796 1.375616 0.996768 0.130950 0.199293 -0.986840 1.795932 1.382470 -1.612306 -1.784565 1.169734 -0.369638 -50.227801 21.353267 -65.633842 -7.978896 -1.297980 0.397646 2.242074 1.038214 2.014096 1.166293 1.388745 0.640869 1.837102 0.918232 1.471574 2.240267 2.165024 2.057269 2.277999 1.838079
+1 -0.029426 1 1 0.931066 -1.414415 1.930597 -1.975025 -0.177836 -1.235529 1.959339 0.443543 -0.379226 2.214211 0.510947 1.508431 -14.542158 -60.041507 -67.603854 32.019281 -51.952147 1.228979 1.944866 0.863258 2.283194 1.391866 1.337567 2.234683 0.568455 2.021617 1.572568 0.895400 2.488299 1.587003 0.516056 1.101230
+1 0.002229 1 1 -0.798061 -1.544840 1.137527 0.251119 -1.739181 0.533710 -2.317366 -0.077150 -0.753997 -0.807056 -1.931521 0.566673 10.621336 12.787544 -29.743690 47.805703 70.452271 1.244787 2.140507 1.755391 2.349590 1.315605 2.125077 1.166559 1.362237 0.621154 1.233327 0.779101 0.845532 1.364238 0.503056 0.868230
+1 -0.017520 1 1 -1.896660 2.147022 2.238724 -2.185189 1.891977 -0.740095 1.937647 -1.279091 0.243093 0.016419 -2.068592 1.171539 53.711403 27.546895 -69.329577 -22.194488 27.239468 1.581126 0.737395 1.898406 0.755411 0.941571 2.240796 2.055236 1.842724 0.909443 2.261760 1.144877 1.451769 2.381282 0.705019 2.259834
+1 -0.037265 1 1 -1.481116 -2.282936 -1.027082 -0.690720 -2.325079 2.247775 -0.874567 -0.908089 1.177904 0.282605 -0.353673 -1.853587 11.873426 56.668091 70.601882 -44.165840 54.718754 1.496416 1.257483 1.772031 0.782957 0.408823 1.087198 1.790480 0.341416 2.172550 0.299706 0.917048 1.833402 1.734367 2.249296 0.922941
+1 0.022381 1 1 0.658523 -1.607412 0.350364 -1.915794 1.007604 -1.519786 -1.896413 1.581890 -0.474308 1.671811 -1.843370 -2.267630 55.752624 -15.650720 58.349655 -17.351902 -33.423063 1.503749 0.765509 1.907837 1.761171 0.504019 1.303758 1.014665 2.224734 2.100742 1.677031 1.611684 1.321682 0.758086 0.906346 1.959828
+1 -0.053288 1 1 2.164192 -1.357069 -0.302490 0.721374 -0.836336 0.761105 -2.236112 -1.029966 -2.026927 -0.700172 -0.958356 -0.142462 -14.626052 29.935937 33.294019 72.576391 -8.602378 1.672495 1.872350 1.590109 0.964268 1.206922 2.493376 1.425254 2.251279 0.503619 1.319404 0.726986 2.452046 2.036389 2.335447 2.105364
+1 -0.032702 1 1 0.458762 0.936533 0.929653 -1.595985 -0.807730 0.877051 0.247312 0.239419 -0.470401 1.355729 1.330391 -0.395591 15.546211 -14.829925 53.444254 37.577243 60.726491 1.827021 2.490742 2.149621 1.927760 1.361895 1.614382 1.666343 1.972702 0.695845 1.062320 2.165002 1.683283 0.929024 0.609955 2.014621
+1 0.019038 1 1 0.022257 1.791422 0.976843 -0.161258 -0.632267 -0.069631 -1.613674 -1.219076 0.455080 0.321367 0.812601 0.888331 42.616851 11.418794 65.676562 -24.029989 -72.017766 0.586226 1.454466 0.457189 1.722210 0.430080 0.598137 1.393203 1.307003 1.540602 1.398029 1.422518 1.266273 0.998715 1.908049 0.829350
+1 0.026264 1 1 1.151602 1.191750 2.095807 -0.878939 1.010186 -0.539806 -1.171252 -1.576720 -2.172125 -0.034863 -1.600726 -0.371766 11.553186 74.403122 -56.721156 -62.467531 -41.788696 0.735738 1.047206 2.397164 2.140217 1.369928 1.634560 1.049726 1.994576 1.591182 1.000396 0.913330 2.332252 2.404389 2.064406 0.728905
+1 0.042988 1 1 -1.828072 0.372559 -1.165833 -0.041081 2.273165 1.751346 1.287791 -0.103986 0.596958 0.396258 1.297952 1.030984 9.113470 20.083110 36.827963 67.572029 33.096121 2.072696 0.552328 0.973867 0.524787 1.595789 1.919943 0.477586 0.280854 1.314382 1.813876 2.068568 0.916827 0.368731 2.263407 1.828295
+1 0.013279 1 1 -1.973007 0.747905 2.092308 1.566456 -0.693296 1.509380 1.357961 1.152723 1.189882 -1.041097 -0.619450 -1.436871 47.998679 13.792826 66.025362 -11.745227 -2.034980 1.346296 0.452035 0.606930 0.673965 2.325326 0.755004 0.852125 1.913698 1.264281 1.274399 0.319395 1.071486 0.960618 0.603143 2.280638
+1 -0.013273 1 1 0.618259 0.255859 -2.195024 1.524382 -0.973432 0.943205 -0.023166 1.771961 -0.944812 1.290763 -1.982067 -0.721858 67.895714 73.265265 19.315463 34.993671 -11.368732 1.760706 1.677605 2.259273 2.097739 0.705572 0.299919 2.231688 1.974963 0.451341 2.446295 2.135921 1.177201 2.470387 2.037637 0.813901
+1 -0.065152 1 1 1.244156 1.667157 0.039617 1.389293 -0.046935 -1.863087 0.918584 0.856290 0.029511 1.190581 1.292382 1.656645 -72.436076 -33.134906 51.642331 52.661496 -68.234079 0.472460 1.891290 0.418297 0.566068 2.405325 2.052517 1.152269 1.927850 0.623409 0.888944 1.977824 1.281330 2.065173 2.368935 2.438776
+1 -0.021300 1 1 0.180539 -0.457403 -1.667027 2.140893 -1.819777 -1.586077 0.787483 -1.873420 1.612876 1.944247 1.253525 -1.097278 74.480361 41.435191 -48.740228 -27.018601 -51.627889 1.976071 1.072733 1.680038 0.396396 1.471851 2.400295 0.749836 1.739645 0.970775 0.319566 1.692458 2.144940 2.009202 2.149145 0.673509
+1 -0.026999 1 1 -1.197973 1.699860 -1.670984 1.616349 -0.944678 -1.158983 1.991903 1.099559 -1.704793 -1.138276 1.295205 1.981540 41.188248 0.888412 -68.451430 36.819620 -72.653420 2.334536 0.297626 1.942135 2.215400 0.484446 0.834674 1.123812 0.662563 1.940586 0.925919 2.427239 1.353749 1.963334 0.746908 2.040672
+1 -0.035920 1 1 -0.187753 1.729108 -0.192449 -1.787276 -1.975413 -1.985104 0.064917 -2.217894 -1.138505 2.159994 -1.221697 -1.181159 49.636475 -59.757883 49.252568 -62.091406 -20.269022 1.203163 2.310305 0.293374 2.480160 2.050275 1.719093 2.046142 2.002079 1.692058 2.172367 1.718778 1.251368 2.492266 0.773434 2.348617
+1 -0.006408 1 1 -1.574741 -1.896742 0.760743 1.096532 -0.737782 -1.600651 0.886057 0.816590 1.958159 -0.543771 -1.836975 1.528974 25.877927 -69.677591 -21.267555 6.196847 50.414804 0.949141 1.214267 2.178693 2.286574 1.956857 2.150254 1.312193 1.033619 1.287055 1.537012 1.814253 1.648171 0.313370 1.067675 2.162875
+1 -0.041544 1 1 -1.352011 -0.103002 -1.714983 1.967510 1.109947 -1.461610 0.408166 -1.193214 1.572515 2.180480 -0.919875 1.002723 40.039026 35.917794 70.367465 65.988220 -35.981918 2.153594 1.204966 1.118376 1.540034 0.854370 1.402519 0.379663 1.499570 0.268719 2.102000 0.322985 0.654170 0.385444 1.899103 1.229985
+1 0.006543 1 1 -0.995361 -0.054601 1.232242 -0.649366 -0.000727 1.925994 0.787866 -0.156289 -1.941761 -1.886789 -1.598420 0.684158 13.411004 -51.259723 -72.167065 -11.865255 -69.337615 1.265460 0.836428 1.344154 0.453034 1.637812 1.712030 0.332292 1.830092 2.359537 1.986706 2.063481 0.931045 0.830432 1.822892 0.597810
+1 0.026459 1 1 1.552894 2.281601 2.151907 -0.485300 0.708504 -0.385476 0.846657 -1.652194 1.687075 0.230070 -2.080416 0.378492 -13.129867 -23.671971 -54.809633 -35.508949 51.102176 0.989167 1.183495 0.252454 1.001337 0.965274 2.360700 1.286444 0.263693 0.894727 2.421768 1.653776 2.256033 1.651625 2.119063 1.335725
+1 0.011708 1 1 -0.266389 -0.435202 -0.810112 -1.454435 -1.535508 -2.248351 0.611139 -1.589616 -2.150928 -1.906045 -0.083772 1.053907 -27.351741 49.290496 -24.634804 -37.155430 -21.303814 1.327020 0.466956 1.623398 2.454284 1.409481 0.401556 0.444636 2.242352 1.206254 0.260719 0.399618 1.624594 2.292815 1.098527 0.941334
+1 -0.040877 1 1 -0.912665 -0.336916 1.738467 1.599425 2.077870 -0.751634 1.208325 -2.082582 1.672692 -1.173299 1.707205 -0.747943 62.974132 6.241775 55.518171 -56.091855 14.200195 1.565129 1.865999 0.595867 1.494894 0.437238 1.661566 0.435828 0.460991 0.380839 1.002801 0.832960 1.559664 2.276401 1.965993 0.451470
+1 -0.009345 1 1 -1.916985 -0.156111 1.050423 1.846789 -1.525873 -0.522906 0.132631 0.169714 1.393191 -0.498370 -2.193847 -2.258855 -49.847480 -36.604036 -54.040102 -1.994297 -68.144437 0.571659 1.876621 1.373014 1.750819 2.013019 1.053881 2.083517 2.416918 1.145131 1.222842 2.301099 0.814093 1.708354 1.551346 1.969108
+1 0.015287 1 1 -0.187530 0.775214 -0.736956 -1.868425 0.740309 1.673582 -0.351095 -0.946520 0.861581 -0.585338 1.692126 0.294832 -69.904364 67.360661 -69.365671 -28.826544 12.281367 1.568972 1.217837 1.430867 2.087722 1.101160 2.439867 2.092710 1.670747 1.740759 1.688156 1.831395 1.763308 0.418796 2.196084 2.091024
+1 -0.012982 1 1 1.757855 2.300618 1.339846 -1.717134 -1.203281 2.024309 -0.893322 -0.384627 0.970632 -0.881921 -1.981087 1.604496 -71.002224 65.617050 25.756498 -10.534467 -52.783837 0.805680 2.066891 1.984044 2.333245 1.103564 2.347963 0.966307 1.719415 0.706714 1.495005 2.297030 2.183469 1.561949 2.429816 1.908616
+1 0.007376 1 1 -2.333994 -1.508979 0.672031 -0.772248 -1.251251 1.624809 -0.122715 1.548312 0.666907 -2.067504 0.623279 -0.188152 -8.120573 17.522520 50.993411 -53.737427 -14.942716 0.741574 2.387959 0.421677 1.133736 0.953936 0.797047 0.975778 1.149683 1.221896 2.147055 1.559429 0.577068 0.531763 1.838291 0.652181
+1 0.039958 1 1 0.478691 1.308477 -1.138329 0.402392 0.724391 -1.974733 0.016631 1.481452 -1.500983 -1.604217 2.211970 0.536149 30.965269 -66.717088 -64.100517 -37.386505 -4.993597 2.464225 1.980455 0.511267 1.622432 1.970084 1.700340 1.870852 1.154575 2.442432 2.456110 0.586767 1.542025 0.566625 0.508557 1.060825
+1 0.060125 1 1 0.848087 -1.174839 -0.602430 1.876836 -0.742857 -2.070771 2.265476 -0.252410 -1.098742 1.292446 -1.967463 -0.310333 27.142194 28.856251 37.007730 -61.083554 -31.289021 1.756438 1.944570 0.381508 1.008756 1.913708 1.434493 2.273984 1.851745 1.773880 0.348881 1.637007 1.680474 0.975610 0.585078 2.405608
+1 -0.012846 1 1 -0.808332 0.173302 0.437305 -1.543861 -1.264108 2.294078 -0.193703 0.693623 -0.734297 0.413709 -2.282358 -0.744661 18.812249 -22.526093 3.947305 42.355039 -38.853622 0.432531 1.305046 2.401338 0.285190 2.184910 1.025307 1.090684 1.877516 0.657209 1.968211 1.713078 2.207189 1.982075 0.733462 1.038646
+1 -0.038812 1 1 1.559620 2.228085 -1.937850 -2.129516 -0.174555 2.080179 0.360386 1.591730 -0.018825 -0.665228 2.013768 1.015723 -55.263765 -18.092609 -32.483892 43.223524 7.766062 1.738152 0.618850 0.765920 2.073303 1.747690 1.178370 1.855477 1.506082 1.720324 2.491120 1.758368 0.638142 0.996157 1.662279 1.176286
+1 -0.055683 1 1 -0.846318 -2.082452 -0.857196 -1.118216 -0.855621 1.791360 -0.062977 1.834915 1.552142 -0.926435 -0.857296 1.913252 -41.900788 23.455312 13.435982 68.550246 -26.019061 0.589595 1.826970 1.630861 1.875722 2.009912 0.586563 0.361199 1.675281 1.442479 1.499119 1.686035 2.190198 2.155904 1.782079 0.905119
+1 -0.062823 1 1 -1.408983 -1.025126 -0.800300 -1.489100 0.193281 1.633611 1.725599 2.101624 -2.074896 -1.097901 1.291063 -1.654018 -22.012964 -71.878223 42.699722 54.235860 -7.894766 2.315089 1.947737 1.860289 1.378853 0.887074 2.048232 1.136744 2.009391 0.838124 0.599893 1.645347 2.351276 0.390055 0.658950 1.977241
+1 0.050242 1 1 1.271473 -1.036417 -2.072110 -1.404407 0.492608 -0.411332 -0.177359 2.073898 -1.536556 -1.011599 0.353994 -2.164821 6.781160 -29.041005 7.823917 -53.434322 -20.650179 1.861739 0.994920 1.113265 1.138179 1.372640 2.216260 1.432215 2.241369 0.444883 1.890811 1.356428 1.990111 0.791183 1.408799 2.432299
+1 0.011350 1 1 -0.826612 -0.748094 -0.565322 -1.183631 -2.283416 0.319525 -1.858866 1.180271 -2.337360 -1.529963 1.417861 -0.567885 -59.163599 -12.601152 12.433080 12.767289 -70.177839 0.940882 1.910284 2.385298 0.704085 2.305551 1.401865 0.639750 1.032855 1.935607 0.498352 0.543935 1.661381 1.832641 2.451841 0.848167
+1 0.005175 1 1 1.485815 1.138416 1.051158 0.064021 1.583408 1.486618 0.508877 -0.292309 2.181081 -0.250573 1.489928 -0.424211 4.298793 -50.191092 38.319652 -61.603387 -68.120947 1.993589 0.752664 2.029626 1.179578 1.918756 0.782905 1.789239 1.989326 1.110933 2.454583 1.921185 1.103993 0.563263 0.264143 1.700362
+1 -0.017441 1 1 1.838656 -1.547305 2.127946 2.060607 1.277792 1.486726 2.322421 0.215009 -0.738205 0.705745 0.374813 -0.989371 53.035760 72.017293 44.644283 36.462428 74.027514 0.331432 0.885334 2.062006 0.884783 1.800871 1.747398 0.760788 1.309364 0.735961 0.289682 1.189001 0.538026 1.359212 1.534284 0.955118
+1 -0.004532 1 1 0.962967 2.249626 1.964966 0.768339 1.524588 -2.217578 -0.555055 1.715205 1.770811 -1.424350 -0.109179 -1.846990 -59.111019 -28.898016 11.051472 42.095224 -55.574394 1.542381 2.045785 0.504676 1.081355 0.335830 0.547472 0.354777 1.730329 1.892955 1.394311 1.938960 0.600359 0.475688 2.144846 0.431951
+1 0.031208 1 1 -0.355449 1.270785 1.539585 0.071732 -0.778434 -1.546935 -1.090921 0.798031 1.051411 -0.402713 -1.399084 0.419170 -0.918931 5.520971 -59.032288 -55.656590 -20.302669 1.720660 1.387271 0.604486 2.341114 0.605555 2.315680 0.635721 0.813091 0.622918 1.629129 2.015244 2.458477 2.127656 1.766805 0.690571
+1 0.017649 1 1 -2.216591 1.899866 -0.100275 1.719753 -1.908311 -0.471709 -1.773369 0.843532 -2.343163 -0.100735 -1.297135 -1.439016 -49.484016 72.139745 2.698431 52.537486 -52.466259 2.118774 0.991768 2.142549 2.312223 1.040267 0.517308 1.903150 1.739193 2.368052 1.105257 1.547950 1.149187 1.878366 1.440525 2.404247
+1 0.047583 1 1 2.299825 2.144016 -1.168049 0.408104 -2.228350 2.179943 -0.527155 -0.605336 0.163670 -1.227840 -0.762424 -1.069203 -55.845172 -39.808474 -61.015067 69.767194 27.236312 0.785325 1.962021 1.188034 2.292697 1.353337 1.782812 1.964570 1.270583 1.442305 0.818715 0.636634 0.406224 2.412958 2.093677 2.173860
+1 -0.071012 1 1 -0.875731 -1.615403 -2.000397 2.215600 0.286717 -1.927806 1.755189 -0.084340 0.934941 -2.256567 -0.809738 0.112296 -73.689373 52.711512 22.387243 62.386692 33.130210 1.666631 2.310390 1.721332 1.424411 1.580435 0.364251 1.209252 1.145681 1.455748 1.764567 1.324681 1.660024 1.517939 0.757745 1.923100
+1 0.000896 1 1 -0.688971 -1.196228 -1.960465 -0.514993 1.173494 1.563024 -1.817130 0.490520 2.194021 0.475104 2.285496 1.656178 -22.508531 -0.887439 -65.195372 11.388706 9.974147 0.407224 1.209513 1.036162 1.280483 1.332942 1.012925 2.238279 0.251301 1.867056 0.355441 1.649135 0.767547 2.414976 2.252662 1.239729
+1 0.014995 1 1 1.004085 0.592943 -1.106330 0.992109 1.940913 1.760048 1.462745 -0.175177 1.037532 1.960631 -1.404074 1.373723 68.972047 13.192304 23.055431 42.634123 1.705091 1.487035 1.102817 1.049431 1.531967 0.275290 2.293955 2.253816 0.387024 1.457109 2.126039 1.588599 0.332496 0.756586 0.444715 1.325237
+1 0.038082 1 1 0.473984 2.310305 -0.784011 -1.030183 -0.971943 -2.299437 -0.339108 -2.104147 2.078603 2.144058 -0.464362 -0.812415 71.501521 -73.932703 13.053604 -58.077176 -53.098606 2.451045 0.955672 0.730516 1.031509 1.822726 2.302083 1.602213 1.891537 2.314625 0.905080 0.921168 1.326584 2.140594 0.955695 1.117111
+1 -0.001033 1 1 0.299925 -1.418921 1.602087 -0.309493 0.836525 -2.298529 0.792085 0.065678 1.149984 2.270185 -1.211824 -0.187990 -71.341791 58.517451 -47.194090 8.925340 8.185710 1.783444 1.348528 1.951387 2.461955 2.076389 1.862575 1.556780 1.056048 0.255318 1.886196 0.295585 1.392628 0.644093 2.029324 0.603125
+1 -0.043245 1 1 2.223767 0.901562 2.221373 -1.635351 2.014942 1.900987 -0.113761 1.248161 -1.722697 -0.443779 1.114674 -2.133022 68.770621 -72.168678 -38.969537 -61.005513 -69.654492 2.379375 2.401705 1.961222 1.264089 0.297718 1.242601 1.403534 1.693615 1.345010 1.325681 0.479048 2.355415 2.457249 1.729606 0.993978
+1 -0.000090 1 1 0.374813 -0.981626 -0.110707 0.740943 -1.818246 0.585291 2.238130 1.958288 1.620879 -0.199894 0.318718 -1.297262 36.442224 34.460918 34.645769 -8.561123 -36.798429 1.057085 1.925419 0.273107 1.617241 2.467241 0.915621 0.343876 0.771354 1.153710 1.397530 2.033926 1.448043 0.506990 1.726599 2.191904
+1 -0.003319 1 1 -1.378303 0.966354 -2.092222 -0.123159 -1.192596 -2.175340 -2.233228 0.322579 2.338745 1.248494 -0.832767 -0.516198 -7.230216 -18.247753 60.020314 11.423441 -6.219012 1.780862 0.694538 1.603062 0.412878 1.747846 1.554273 1.664155 1.203785 1.512587 0.804617 2.194565 1.297774 1.685961 0.942365 2.086732
+1 -0.019966 1 1 1.936120 1.317030 1.230897 0.304995 -1.024333 -1.612289 -1.501025 -2.305581 0.071993 -1.096280 0.268023 -0.373855 -56.127477 15.493512 -0.541700 45.652534 32.143367 0.378500 2.204850 0.917113 0.670232 0.341046 0.460278 1.884799 1.564194 1.902049 1.229656 2.072378 1.956047 2.030986 1.528636 0.530858
+1 -0.000308 1 1 1.275553 1.557403 -2.048654 1.692482 1.564045 1.193255 -0.897890 -1.760037 -1.282914 1.957662 0.524865 -0.179145 10.650504 53.021923 -10.539748 8.461613 14.335798 2.001250 1.250716 0.529983 1.167995 0.741194 0.495631 2.065531 1.635938 1.702985 1.316081 1.119079 2.112587 0.494828 2.080253 1.562197
+1 -0.034900 1 1 1.595122 0.442554 1.853347 0.316296 0.403704 -0.782446 1.706348 -1.005390 1.041981 1.340011 1.053838 -2.010813 48.636617 -64.381039 47.884214 39.978128 62.400093 0.750338 1.189025 0.943006 1.597829 2.459483 1.035519 1.722598 2.454988 1.987299 0.784061 0.955851 1.481762 2.478084 0.907174 2.381360
+1 0.027431 1 1 -2.124503 -0.745214 0.717813 0.570825 -0.566677 -0.400987 -0.667810 1.030026 -1.673819 1.084367 2.155245 -0.926691 -14.575615 -22.363790 31.779396 -33.698836 23.664193 2.486310 1.917117 2.489834 0.389480 2.247309 1.275085 0.596428 1.910832 0.359189 1.636021 0.858808 1.738583 1.108486 1.830509 0.358999
+1 -0.013066 1 1 -1.118465 -0.314277 0.537158 -0.929650 1.662113 0.087932 -1.817914 1.447671 0.946485 -1.443672 0.298305 -0.367003 9.360392 -29.891848 -42.286334 -6.410986 -49.447406 0.436640 0.600580 1.952263 1.434782 0.378648 2.432694 0.793915 2.326450 1.640113 2.133177 2.301109 0.983776 0.579138 1.580336 0.962619
+1 -0.070081 1 1 -1.849900 1.077654 -2.293517 0.197932 -0.305065 -0.150323 -0.642836 1.361953 2.274000 1.640906 1.802740 -2.016444 35.715330 -32.451407 -10.803869 69.366492 42.629911 0.338734 2.097629 1.100728 1.942782 1.837031 1.987685 0.515650 1.033355 1.347162 1.498452 1.731676 2.022319 2.109162 1.435490 1.037380
+1 0.045855 1 1 1.086161 -0.692188 1.286705 0.498377 2.311977 -0.966609 -2.185778 1.415599 -0.877782 1.600182 0.651262 -1.127541 -65.483231 -26.665763 28.518538 61.061386 -41.291549 2.319041 0.867720 0.771737 0.832982 1.927805 2.116648 1.256941 1.665701 2.430136 0.553111 0.634112 0.768417 1.279699 1.656338 0.322434
+1 0.049704 1 1 1.369726 0.965550 -1.476034 -1.685725 -1.090717 -0.489081 -1.585001 0.015246 1.769302 1.476665 -1.840919 1.218119 73.224877 -59.497239 -70.100028 -71.164263 42.238946 0.774484 2.004049 1.046315 0.911131 1.373489 0.726120 1.399501 1.417555 1.098126 0.948475 1.265296 0.324580 0.474097 2.390884 2.342758
+1 0.009904 1 1 -1.155680 0.954295 -2.139752 2.145558 1.190416 -1.481394 -2.233472 0.925588 0.760244 2.135295 -1.651070 1.727398 -20.642952 3.911377 38.518172 -25.090688 -49.200675 1.888907 0.851082 2.386602 2.374268 2.072383 2.038828 0.589055 1.755030 0.787966 1.338697 0.980168 0.676933 0.460887 0.884873 1.066489
+1 -0.012033 1 1 2.126453 0.534064 -1.083817 -2.328709 -2.214628 1.899122 1.527446 -1.318189 -1.866884 -1.626227 -0.149582 -2.321378 -48.807792 37.444874 -64.001148 -17.291742 -72.307026 1.912236 1.458404 1.395117 1.972470 1.308603 1.433132 1.896646 0.427846 1.300518 0.561754 1.897655 1.643326 2.137508 0.842553 0.788743
+1 -0.030257 1 1 -0.055537 -0.351921 -0.685016 -0.695842 1.135795 -0.572099 -1.990509 -1.233431 -0.470498 -0.263896 -0.940821 -2.316946 72.464698 64.185431 -35.455886 42.929084 9.120300 1.148281 2.404060 1.038722 1.545306 1.714752 1.087356 2.189011 2.458723 1.764141 0.914163 0.593820 0.835346 1.161746 1.456713 2.218761
+1 -0.076080 1 1 -1.999349 0.987293 1.119496 -1.194177 -0.463255 -1.060611 1.272901 -0.592660 1.147520 -1.437365 -2.082389 0.197967 8.823883 -46.995058 54.061914 68.594738 -28.244697 1.995651 1.651647 2.473556 1.306955 0.733971 0.607241 1.393282 0.396439 2.193816 2.215291 0.890696 2.182353 0.799700 0.561846 1.202454
+1 -0.005313 1 1 1.694958 0.761165 -1.230481 1.990060 -1.601303 -0.638218 -1.126765 1.554628 -1.564309 -0.924534 -1.898819 -1.154365 -15.930341 8.765572 22.970548 -33.998728 -66.621701 1.961059 0.761451 1.214752 1.339015 1.825022 0.397052 1.247969 1.610818 0.263168 1.058805 1.581066 1.967551 1.873655 1.020382 1.566193
+1 0.023032 1 1 1.743699 -0.000734 1.808713 -0.579511 0.668735 0.379470 1.883994 1.746375 -2.152132 1.411865 2.335922 0.921164 57.643783 -30.947092 72.227239 -26.801527 -3.256289 1.698150 1.063969 0.631507 1.993311 0.573883 0.997390 2.127949 2.185602 1.407926 1.256331 0.397488 1.839017 1.609180 1.993728 0.837397
+1 -0.039126 1 1 -1.667787 -1.209761 1.501518 1.162224 0.647299 -1.744950 -2.181853 1.407398 -2.051410 -2.214550 -1.501082 1.447167 60.304488 -12.468194 -2.933446 47.572212 46.168284 1.380346 1.232025 1.401708 0.261558 0.999374 1.723348 1.550925 1.646021 2.429622 0.912459 1.194108 0.873882 0.832775 0.700860 2.106003
+1 -0.004825 1 1 0.761895 1.614610 -1.896721 1.127339 -1.327454 -2.071847 -1.684007 -0.497783 -1.754903 0.183875 -0.942978 -0.864932 25.776609 27.475465 -69.866837 -51.936502 -46.786356 0.800690 1.443965 1.720241 1.098627 0.377604 0.633499 1.724072 2.483905 1.996237 2.499260 1.309518 1.076364 1.942953 2.460962 1.143291
+1 -0.032218 1 1 -2.078020 -1.766151 -0.368205 -1.047084 -2.272137 1.391183 -1.262978 -2.276750 -0.736635 -1.171714 0.071905 2.139988 58.266555 -64.012498 -58.059493 -55.893016 56.087261 2.253919 2.123938 2.269969 1.870799 0.271027 0.398262 1.337767 1.103436 2.450716 2.192983 1.715415 0.977195 2.459365 1.295189 0.999042
+1 0.059195 1 1 0.545585 -0.656328 0.806199 1.662125 0.295903 1.676734 0.780453 -2.219797 -0.150348 -1.064274 0.974099 0.850780 52.973029 67.699698 -71.178742 -51.109093 59.480644 0.492876 0.760123 1.388410 1.754246 1.105356 0.975838 2.154049 2.097786 1.483658 0.589509 0.379412 1.783103 2.370934 2.290161 1.491098
+1 0.071569 1 1 -1.216603 -0.393974 -0.619430 -1.096017 -0.036619 1.867708 1.341562 -1.147435 -1.850869 -1.066952 -1.613961 -1.338232 18.025959 -37.714905 25.583531 -67.599022 -36.770008 1.472251 2.375069 2.035262 1.401419 2.147367 2.304051 0.942734 1.531483 1.131995 0.948850 0.821901 2.447333 1.576801 2.296940 0.674173
+1 0.010222 1 1 -2.265747 0.413880 0.602208 -0.909481 1.340580 1.190322 1.650538 -1.238382 1.138248 -1.756658 -1.042857 -1.924444 54.543994 70.900255 20.579480 -20.682291 -57.269689 1.649957 1.083458 1.934114 2.405848 1.828902 0.352132 2.285488 1.689571 0.876620 1.853423 0.728851 2.293996 0.687939 0.933930 2.057335
+1 0.014214 1 1 -1.809193 1.935708 -0.895228 0.568861 -0.583193 0.046229 -0.567056 -2.066264 -2.098267 1.944484 0.528219 -0.363734 -41.834658 -65.093031 -68.579991 -23.905145 -73.779124 2.038950 0.389961 1.331066 0.979351 0.449755 0.534307 1.845930 0.787850 1.643077 2.449111 2.205046 1.955391 2.265187 0.250686 0.533143
+1 -0.009768 1 1 0.126987 -0.437848 1.844527 -1.843994 1.367075 -1.176363 2.049307 -0.156073 1.679611 2.010147 1.427837 2.169050 5.582314 71.959988 -18.480458 48.946848 49.670210 2.233287 1.854532 1.373381 1.169209 0.895548 0.477695 2.113580 1.445729 2.117892 1.910573 0.502306 1.753011 0.604081 2.285354 1.699982
+1 0.000567 1 1 0.859096 0.072341 0.043076 -1.736186 -0.967374 -0.906435 0.705828 1.765481 -1.482393 -0.172211 -0.939463 1.658052 -69.431741 60.729054 73.210674 1.791846 -34.445514 2.488664 0.975440 2.220586 2.134574 1.034578 1.647638 0.356789 1.808893 1.559398 2.304775 1.857471 1.267114 1.635627 0.982452 0.823727
+1 -0.037206 1 1 1.422239 2.327909 -1.791805 2.018709 -0.750025 -0.037771 1.362723 1.067533 1.967415 -0.481832 -2.267128 0.758268 61.064733 14.959697 27.634550 53.874085 61.740650 1.001615 1.136642 0.293767 2.340932 2.040510 1.855941 0.295587 1.432601 1.973346 0.283507 0.908674 0.579978 2.186590 2.270621 1.580213
+1 0.005029 1 1 -0.456394 1.160022 1.344619 -1.598926 1.604829 -1.359037 -0.394612 -1.906082 -0.692749 1.280300 1.237355 0.460047 -32.528427 44.731873 8.590746 -65.329439 8.125733 2.412928 1.585102 2.302426 0.627017 0.771585 0.535687 0.284671 2.468802 2.396604 1.716337 0.720007 2.159604 0.961524 2.341431 1.424700
+1 0.014535 1 1 0.728120 -0.557223 -1.729685 -0.089678 0.752020 0.569328 -2.162371 -1.034811 1.360216 1.351462 0.299774 0.765394 -27.118555 68.445471 13.038464 -12.537876 25.911049 1.929917 1.609646 0.814789 2.160036 1.472204 1.578247 1.844207 1.084553 2.330811 0.689692 1.160576 2.051494 1.968009 0.583531 1.151433
+1 -0.002959 1 1 -0.655375 -2.029230 -1.702213 -0.184002 -1.192721 0.439706 1.108157 1.437235 -0.091445 -0.670660 0.246332 -2.086530 40.961953 -52.448820 42.679360 12.002037 -31.756027 1.021931 0.589280 1.026473 0.434041 1.920706 2.048253 1.481394 0.788968 2.429698 2.175752 2.366181 1.156964 2.093819 2.324487 2.403065
+1 -0.070235 1 1 -0.182704 1.778490 0.392788 -0.461524 -0.241303 1.792809 0.730743 1.105902 1.231268 1.828760 1.770393 0.971630 56.044417 -61.477910 -59.229835 74.170997 -58.051967 2.433922 1.179022 1.568659 0.455482 2.283458 1.325244 2.120918 1.025830 0.868073 2.197101 1.171230 1.106252 0.278153 0.914304 0.713068
+1 -0.036398 1 1 1.889636 2.327493 0.635856 -0.866413 -0.528249 -0.133568 -1.774863 -0.698428 0.088692 1.535948 0.217676 1.674340 -56.107097 58.018476 -33.474720 40.381061 -65.507937 1.496435 1.578889 1.384377 1.476724 1.043791 1.239337 0.537385 1.822670 1.359878 1.465205 0.950206 1.113218 0.356518 1.753165 0.945804
+1 -0.004719 1 1 1.082885 0.800199 -0.221878 -1.612028 -1.832037 -0.297369 1.961973 2.288970 -1.229243 -0.781866 2.036383 -0.594116 7.621387 -7.349669 74.113613 27.492027 58.501464 1.136683 0.974702 1.069074 0.920469 0.825331 1.592270 1.281347 2.351941 0.327915 0.262288 2.019062 1.380718 0.721927 0.677893 0.840101
+1 0.015266 1 1 1.337082 -1.041709 -1.476919 2.289766 -1.985874 1.271273 0.308414 -0.111274 0.639053 1.035023 2.210260 0.084912 -23.515064 32.325012 -13.528279 30.222670 52.412587 0.600304 1.806112 2.066468 1.634508 2.426602 1.908740 1.189129 0.439041 0.467981 0.862246 1.024676 1.728579 1.733101 1.226520 1.126367
+1 0.010682 1 1 1.933319 1.363857 1.286839 -1.960626 1.498231 -2.240929 -1.882251 -0.726471 0.004968 -1.326183 0.440787 0.432732 54.704132 62.349120 1.656085 -66.186296 6.915619 1.087030 1.209973 2.023227 1.623810 0.381707 2.102856 1.201937 1.949094 2.168916 2.216741 0.523509 0.366526 1.196135 1.194362 0.648019
+1 -0.025788 1 1 1.392875 -1.092773 -2.063483 2.218807 -2.355247 -0.574054 -1.873590 -1.239935 -1.406207 -1.493244 1.235333 -0.541041 51.788064 -48.013242 41.444519 -41.965530 -14.661632 1.854163 1.915810 0.775628 0.972591 1.580408 2.168787 2.308542 2.163051 0.392877 0.835756 1.300974 1.462797 0.976269 0.395094 2.089176
+1 0.062395 1 1 -0.597617 -2.046997 1.268093 -1.296205 0.053609 0.946632 1.018017 -0.866856 1.463480 -1.966206 1.958076 -1.946683 6.638784 -21.958885 -62.977308 -59.619179 -19.540866 0.275101 1.377551 1.498182 1.702362 2.098760 2.107976 1.752555 1.951101 2.151139 0.435897 1.621358 1.916575 2.381390 0.271457 0.878160
+1 0.032394 1 1 -2.285382 0.265649 2.133106 -0.736780 1.104397 -0.508704 -1.518586 -0.574774 0.165316 -1.851939 -0.216195 -0.337180 64.298116 58.431167 2.629383 -57.952634 -59.923234 0.928188 2.308220 1.248851 0.682186 1.007717 2.455535 2.182011 1.810238 1.673565 1.856126 1.157367 2.120242 0.910662 2.493260 1.727803
+1 0.001264 1 1 -0.060255 0.457979 1.918764 1.782410 0.309904 1.361829 0.181452 0.740728 -0.717308 -1.503666 0.426876 2.249428 -43.419086 5.420641 54.708757 -9.913902 27.044374 1.896962 1.241215 0.594115 1.298624 2.474119 1.767409 1.842861 0.964769 0.618213 1.304076 1.861316 0.632775 0.799245 1.913181 1.578444
+1 -0.023129 1 1 -1.869532 0.981572 -0.788855 -2.334628 1.962381 -0.280719 -0.945464 -0.231262 0.899146 -0.692205 1.007185 0.852295 -36.318032 -47.170584 -46.009323 -28.691058 39.387373 1.878730 0.814170 0.752358 1.377700 1.747475 2.058472 2.241363 0.337730 0.974069 1.675061 2.246492 1.041743 0.583839 1.832697 1.143571
+1 0.063013 1 1 0.119515 1.218678 2.282233 -1.362677 -0.297313 -1.801692 0.771874 -0.327725 0.707219 1.585950 1.790867 1.067435 10.046839 -42.774826 33.500304 -60.382333 54.125436 0.417970 1.818259 1.476444 0.842821 0.797471 1.344667 2.316391 1.339780 1.183003 0.986881 1.009830 1.955805 2.471348 2.450819 1.666267
+1 -0.043877 1 1 1.625140 0.726977 -0.916713 2.315540 -2.332832 -0.825269 -1.730005 -0.760941 0.294511 1.835537 -2.135781 -1.811007 -8.942738 -0.602736 69.815097 -67.668605 -6.237365 1.654098 0.928210 0.432207 0.347826 1.910310 0.583596 2.254359 0.506209 2.110746 1.063493 1.624527 1.174746 1.708766 1.731709 0.337807
+1 -0.017411 1 1 2.199760 -2.033112 -0.982027 -2.134688 -2.275363 -0.985612 -1.129528 2.231307 0.387643 -2.117180 -0.191720 1.039153 29.682467 -26.776428 -31.417726 -37.713948 41.669067 1.105254 1.507731 2.426493 2.322615 2.437497 0.513414 1.707156 1.672595 1.307370 0.958781 1.229038 0.694988 2.412783 1.392811 1.468912
+1 -0.010421 1 1 -2.280747 -1.935656 1.762371 -1.904942 -0.395403 -1.073993 -2.150644 -1.852611 -2.081545 0.257252 -2.332621 -1.995432 26.961549 -7.245959 17.162660 2.824554 72.273599 1.410677 0.254755 1.418381 1.475405 1.388294 2.058714 1.804100 2.004510 2.058367 0.471731 0.881146 1.421259 0.355756 2.447290 0.851684
+1 0.051155 1 1 2.339404 -1.813377 2.306823 1.946732 0.602079 1.635086 -1.767944 -2.227259 1.668896 0.997892 0.186284 1.845980 -31.574093 34.227256 7.484418 -59.391662 54.339412 0.362588 0.259264 0.701703 0.526214 0.832409 1.299551 2.304696 0.532404 1.367279 2.109737 2.095916 1.568295 1.080622 1.514106 1.578232
+1 0.036434 1 1 0.379536 -1.711900 1.951177 -0.079064 0.070925 -0.196619 -1.192589 -2.045372 0.307530 -0.840649 -1.039732 -1.240851 65.318103 -48.646953 40.659120 -42.167627 38.685109 0.334324 2.234129 0.255091 0.316803 0.250366 1.905711 2.041313 1.843191 2.016850 2.445886 2.008879 1.225453 1.190366 0.978741 1.443236
+1 -0.007997 1 1 0.740520 0.496596 0.649681 0.590593 1.811816 -0.267825 -1.005239 -1.133445 -2.329193 -0.930534 0.935725 1.493692 50.295332 63.643238 1.899719 -21.425204 56.594796 1.956064 2.323160 0.347343 0.538746 2.203160 1.760621 0.258610 0.958673 1.674575 0.829478 1.538487 1.851094 2.089119 2.078958 2.304601
+1 0.001578 1 1 -0.242735 1.286207 1.561924 -1.459877 1.262401 1.995250 0.814174 -0.963422 -0.463361 1.871315 0.715612 1.280353 67.461390 -26.425735 12.663617 -12.582385 27.863153 1.315176 1.658879 0.274762 2.425579 0.458791 1.644429 0.417296 1.742254 2.066724 1.422556 1.901882 0.675757 0.949784 0.776501 2.158772
+1 0.046458 1 1 -2.086534 1.227037 1.395097 -1.448134 0.704500 -1.697242 -1.454808 1.623058 -1.288704 -1.116716 0.804210 1.219819 -66.910391 -12.937531 58.918675 -53.832330 40.021706 2.047287 0.999289 0.299070 1.462319 1.939264 1.214689 0.283142 1.516064 0.732922 0.976708 1.034092 2.486682 1.413781 0.664667 1.311022
+1 0.073796 1 1 0.993197 1.388191 0.280002 -1.675834 0.212879 1.146311 1.800846 -0.855685 0.710344 2.273858 -0.745583 -0.775857 -20.563705 -14.195146 72.188823 -72.458207 44.912591 2.063726 0.537119 1.854830 1.882761 1.054923 1.599395 1.780397 1.875819 1.393107 1.944886 1.196427 1.596835 1.510432 0.573683 2.135980
+1 -0.055430 1 1 -0.052106 0.752182 -1.422541 2.007821 0.032977 -1.811310 -0.650042 -1.941534 1.925183 1.296140 -1.151332 -1.374170 -7.925971 -11.786112 60.807842 47.403003 52.278964 0.663249 2.224416 1.255835 1.069032 2.474267 1.999849 2.465229 0.850212 1.259570 0.844536 0.361408 0.679309 2.139640 0.680676 0.367087
+1 0.014868 1 1 2.188489 1.731097 0.252918 0.222550 -1.234126 1.977011 0.571533 1.904958 0.652500 0.838002 -1.031627 -1.681352 54.319420 46.484587 66.452574 -31.592234 29.325214 0.908089 2.001770 0.998573 1.774609 1.344233 1.777625 0.296727 0.334897 0.605832 2.469914 0.849685 1.408627 1.799933 1.729668 2.032665
+1 0.033366 1 1 0.994182 -0.911764 0.672126 0.830375 -1.990879 1.971974 0.738863 0.924083 -0.970730 -0.763336 -2.263498 0.499948 13.644458 -27.586193 8.848187 61.485068 29.530913 1.015825 1.470411 0.703683 2.296949 0.827233 2.062873 1.955730 1.197930 2.101732 0.318800 2.315565 0.944046 1.077080 0.476113 0.283299
+1 -0.017600 1 1 0.783544 -2.098196 -1.568722 0.298167 2.025688 -1.271677 2.322128 0.003504 2.338893 -0.968829 -1.801429 0.479328 -67.421484 -52.875941 64.051335 -39.220137 -72.845176 1.241869 0.343080 0.888791 1.664786 0.549936 1.267221 1.183857 1.828114 0.608383 0.349427 1.824676 1.322642 1.148535 2.174323 0.844377
+1 -0.009056 1 1 -0.202132 0.400717 0.844660 -2.227492 -2.243651 -0.499672 -0.502716 0.159438 -1.675924 -1.300898 1.294684 -2.065431 -71.437025 -42.077979 45.408718 -15.673531 -25.041870 1.694345 2.354767 0.561599 1.536896 2.110269 2.036103 2.038295 0.629851 1.148204 1.117804 0.934778 0.566209 0.274221 2.324654 0.715697
+1 -0.034257 1 1 -1.189314 1.150953 -0.291550 0.805036 0.967757 -2.082406 -0.077866 1.355794 -2.287889 0.546996 -0.513039 1.017629 64.374014 -15.939515 4.564184 60.238321 -74.540872 1.248386 1.866179 1.375606 0.304787 0.802862 1.956648 0.889200 1.776983 0.757384 0.352847 0.798115 0.922521 1.563012 2.292386 0.633033
+1 0.041721 1 1 -1.288700 -1.032553 1.601699 -2.119638 0.911997 -1.467506 0.271690 -0.014458 2.055051 2.135618 -0.932083 -1.538362 52.045401 -72.944407 -26.653946 -72.872864 -24.219573 1.999435 2.253045 0.931751 1.438151 0.745517 1.149159 1.411595 2.178187 0.536128 0.950559 0.297263 0.353057 2.086816 1.614968 0.265048
+1 -0.018200 1 1 -1.055044 0.588858 0.912218 2.238729 -2.106153 1.352314 0.495520 1.406244 2.114724 1.324757 -0.847774 1.734721 -2.879113 60.742803 4.289705 -52.936775 -58.383980 1.981666 0.609765 1.069302 0.262948 1.874140 2.425985 0.537355 1.318233 1.289050 1.307571 2.093928 1.900081 1.920602 0.312994 1.488776
+1 0.027479 1 1 -0.924526 -1.761180 -1.630196 -0.881876 -1.221783 2.075652 -0.334461 0.595472 -1.019790 -0.652674 0.955043 1.007320 -50.713441 -40.795799 -5.001277 -56.455522 52.046073 0.450183 0.972735 1.758770 0.647923 1.150110 1.646659 1.894918 0.632610 0.280970 1.017714 1.725423 0.439500 1.422028 2.030530 0.613488
+1 -0.038171 1 1 -0.942752 -1.785153 0.708256 0.158376 -0.668755 -0.722683 -2.311203 -0.158904 1.218478 -1.091005 -0.612073 0.034515 15.097941 -48.905815 39.959318 46.251558 49.942520 1.133950 2.297894 0.962047 2.129191 0.564739 0.314138 0.473448 0.488208 1.061998 1.253232 2.315075 1.716438 2.425383 1.658062 2.305737
+1 -0.007576 1 1 -1.737285 -0.590684 1.375364 1.468407 0.731452 -1.110622 -0.446890 0.661218 1.278609 1.096397 1.705105 1.654049 38.838092 -48.184826 7.621932 1.817749 -49.098246 0.711793 1.350002 1.990236 0.642346 1.904742 1.493261 2.233006 1.630125 0.758724 0.377453 0.346787 2.452913 0.853355 2.345540 0.734393
+1 0.066797 1 1 1.940907 1.665301 1.837014 -0.882378 -0.245128 -1.239236 0.923141 2.044677 2.150527 -0.115538 -0.340926 0.317570 -55.393885 44.972898 9.491691 -73.145684 40.494988 2.114062 0.546514 2.265501 1.022180 0.283805 1.408068 1.406359 1.926947 1.200417 1.164648 0.745177 2.197258 1.556043 2.170702 0.732515
+1 -0.003735 1 1 0.810608 0.371489 -0.295087 -2.093691 -1.257732 1.080959 1.423529 0.456652 -1.526662 0.354915 -0.821711 1.516398 47.627321 72.387389 -35.144871 20.148591 -62.639340 2.434164 0.743132 1.570322 1.398514 0.573226 1.210548 0.427771 2.304077 1.373423 1.871733 2.470679 2.444935 1.769360 0.880836 0.715554
+1 -0.012365 1 1 1.832128 1.818300 0.332231 -0.366871 -2.197651 -0.216672 1.063827 0.937782 -1.643447 -2.104185 1.443145 0.277529 -26.736308 42.874075 -15.423571 -23.949768 -73.757002 0.865931 2.205108 0.744201 1.538883 1.756312 2.082454 0.298431 1.978146 2.199968 2.107790 0.875191 0.338839 1.614725 0.689069 1.929467
+1 0.039243 1 1 -0.819196 1.373539 -0.926269 1.923929 -0.932363 -1.538060 1.986117 -1.886305 1.829358 -2.318057 -2.270924 -1.780642 35.953749 74.656306 -1.467448 -63.405127 -49.972671 0.764841 1.940358 1.603074 0.623856 1.644886 1.345845 1.860424 1.393396 2.300113 2.248097 1.020453 0.510810 0.686030 0.353744 2.373728
+1 -0.017925 1 1 -0.923328 -0.476016 1.237392 1.069024 -1.248304 -0.691342 1.358346 -1.804399 -2.317288 1.234666 -2.320458 -0.214684 47.499120 17.717886 34.516111 62.280664 51.123454 1.853269 0.387919 0.761924 2.412618 0.869781 1.664239 0.363623 1.913974 1.419554 0.950004 2.221538 2.384306 2.036008 0.437396 2.062210
+1 0.027227 1 1 0.702671 0.544828 0.755529 -1.716557 -0.925728 1.595492 1.949759 -0.349259 1.642998 -0.735527 -1.409584 -1.699850 58.609213 -4.954808 -25.464090 -24.959568 54.546033 0.702767 0.400213 0.384882 1.457473 1.502360 2.172633 1.688801 1.427528 2.216433 2.087632 1.823497 1.769964 2.028548 1.052234 1.389428
+1 0.016794 1 1 -2.177786 -0.928325 0.354174 0.862843 1.775863 -1.347233 0.082181 0.492878 -0.571069 1.178132 -0.601879 1.713036 -54.202103 -24.750204 -26.681172 69.538109 -73.001613 2.303395 1.166247 0.605799 1.916312 2.458472 2.038359 1.703527 1.422746 0.595140 0.520426 0.305208 1.128115 0.984419 2.379610 1.859121
+1 0.004632 1 1 0.544361 2.333343 -0.008289 2.060151 -1.681120 0.907058 0.351572 -0.467063 0.906813 0.947610 -1.388855 -2.020621 51.384736 73.256070 14.775976 -60.171004 5.939204 2.428131 0.599556 0.487874 2.202863 1.265083 1.247474 2.292839 1.494631 0.516099 1.820430 1.972504 1.875517 0.820123 1.801567 2.188127
+1 0.022456 1 1 2.047304 -0.824975 -1.510828 -2.142239 -1.961486 1.180705 0.238875 -0.177886 -2.081540 0.332047 1.242359 -0.263189 48.331680 60.547662 24.547141 63.796806 32.920470 0.540177 1.508439 0.838360 2.322311 1.833168 2.311254 0.499540 0.276493 2.263006 1.848555 2.156760 0.422389 1.844258 1.941176 1.852105
+1 -0.001134 1 1 -1.472288 0.013924 -1.592588 -0.266135 -0.870550 0.630716 2.285362 -0.606466 0.031293 -1.849297 1.789627 -0.914630 -11.938038 57.400869 -63.589443 2.236111 -67.676008 1.664921 0.575466 0.609315 0.253594 2.156608 2.365004 1.616031 2.379168 1.177085 0.517301 1.769530 1.494536 1.168386 0.571554 2.362906
+1 0.030730 1 1 -1.721365 -1.625105 -0.140387 1.428103 1.938095 1.533367 -0.763226 -0.410086 1.913689 1.323355 -0.849070 -1.207612 -2.272473 56.552399 -73.822776 60.597594 -36.235588 1.202104 0.265548 0.561006 0.576125 0.435196 1.097143 2.436381 2.011027 1.326800 1.279139 1.241474 0.454045 0.632718 2.098218 2.000201
+1 0.063246 1 1 -0.700317 1.319710 -0.857361 0.816193 -0.011238 -0.374848 0.389946 -1.117979 -1.571190 1.233596 -1.456093 -1.117647 -22.850931 -55.592103 13.526991 -51.864537 -37.281250 0.835438 0.459729 1.664483 2.212142 1.971523 1.131385 1.945078 2.168001 0.345222 0.895911 2.071474 0.263491 1.995105 1.471585 2.436118
+1 -0.020269 1 1 0.171426 1.881973 0.767710 0.378822 0.421015 -2.007462 1.289860 1.694393 0.699660 1.782435 0.730235 2.003522 -49.145659 58.911132 -30.601903 23.813810 38.711536 2.496673 0.591273 0.769913 1.685280 0.750174 0.682777 1.938235 1.921288 0.578598 1.500067 1.880632 1.290795 1.395068 1.161983 0.952569
+1 -0.003121 1 1 0.420485 -1.500227 1.683776 1.328384 -1.144524 -0.048967 1.679594 1.726017 -0.302175 1.304787 -1.900982 0.192907 2.283822 -15.811650 53.603397 12.292548 50.858267 2.498370 2.105816 1.442239 1.954731 2.409598 1.872578 0.914468 1.220213 0.875416 1.859666 2.152200 0.267158 0.628854 2.402734 1.255346
+1 0.004552 1 1 -0.685142 1.902129 0.226625 1.271733 -1.381260 -1.603297 -1.173168 -0.805313 -0.908225 -1.102294 -1.862898 -0.611205 15.540060 31.790389 1.070003 -16.464429 32.336394 1.791710 0.769701 0.358737 0.789638 2.440107 1.634386 0.369340 1.241135 1.507321 2.289414 2.423653 1.843651 0.735724 0.812509 2.091973
+1 0.008608 1 1 -1.319646 1.915954 1.677288 0.668913 -1.346415 -0.305050 0.107290 -1.625604 0.905679 0.724432 -1.284765 -0.883716 26.811223 16.222429 -49.642192 -36.322147 33.668182 2.292006 0.997855 0.941561 2.067150 1.843446 1.788539 1.474304 0.871871 0.792670 1.661108 1.740093 1.735839 2.244879 0.929555 0.529891
+1 -0.053004 1 1 -1.079031 -2.005848 0.137258 -2.172550 2.259805 -1.306231 1.203448 0.774324 -1.547801 -1.506624 -2.158339 0.770127 -44.949609 -68.080877 -35.301258 -58.242435 19.396903 2.181346 1.880021 2.266878 1.662901 0.381773 0.956239 1.261038 0.765331 1.175802 1.456982 2.241735 2.095892 1.160797 1.269722 0.472894
+1 0.004043 1 1 1.070969 -1.555492 1.183864 1.503047 -1.404576 -2.354856 1.294510 -0.272128 2.070432 1.478907 -1.868777 -0.464473 64.862328 -58.859654 -4.203541 1.089403 9.589940 0.296923 1.391630 1.866892 2.096904 2.419562 0.576449 1.378927 2.132793 0.352202 1.208075 1.621564 0.882919 1.974101 1.713388 0.658827
+1 -0.034422 1 1 0.714407 -0.133304 -2.056639 -0.561283 0.720959 1.612753 -0.128533 -1.982799 1.116046 2.082034 -1.451616 -1.268221 -27.246674 15.149496 67.581265 38.328243 -67.228005 2.108774 1.664491 2.351344 1.535507 1.266547 1.110987 1.099278 2.308050 0.643216 0.779044 2.149189 1.426625 0.535411 2.405565 1.589791
+1 0.003822 1 1 -1.487898 1.550104 -2.200184 -0.370779 -1.896468 0.656253 -2.054875 0.812383 1.921777 0.596916 -0.310897 0.800560 36.350061 -14.530955 -21.768411 -11.687835 62.551335 0.629259 2.456804 0.998758 0.368990 2.123372 1.754309 2.177236 0.312457 1.469963 2.173229 0.452576 0.692271 1.742438 0.647564 1.858437
+1 0.008525 1 1 -1.031652 -2.090952 -2.339916 -2.086698 -1.533166 -0.582233 2.048843 1.484291 -0.909402 -2.041331 2.253942 -0.884736 -68.892548 -27.054978 -63.019160 -13.015681 -54.557790 1.333301 0.292501 1.317945 0.942416 0.684392 2.074954 2.497548 1.786682 1.762416 1.181054 1.971234 0.786354 1.254261 1.609217 0.351303
+1 0.031060 1 1 1.657409 1.140877 0.003721 1.282618 -2.215011 0.189108 2.192413 1.720351 -1.279357 0.475707 -1.722332 0.965876 -22.247402 37.922477 13.067916 32.467457 -19.449357 0.844821 0.664705 1.944870 0.933044 0.672766 2.435622 0.506131 0.786947 2.222780 0.756699 2.339532 1.011627 0.661179 1.179153 1.521991
+1 -0.007147 1 1 0.677351 -0.899384 1.397779 1.215275 1.629183 -2.005179 1.961596 0.672966 0.801478 -2.276803 -1.621075 1.619446 -23.395919 -65.204106 14.598498 -43.049598 65.399291 0.863361 1.750315 0.295660 0.406467 1.990927 1.015878 2.355016 0.255454 1.922010 1.478332 1.077759 0.638861 1.842094 1.582099 1.342431
+1 -0.019905 1 1 1.330625 -1.177288 0.650433 -0.918149 1.743844 -2.275406 -1.710579 0.574935 -2.169208 1.869015 -0.258547 -0.572130 69.674131 -36.878455 -16.193857 -70.156052 37.235469 1.622878 0.462185 2.443783 0.411933 1.610039 0.674751 2.036110 2.153901 1.857404 2.383320 1.203565 2.322834 1.617090 2.182008 1.755103
+1 0.020114 1 1 -0.386580 1.128710 -1.848944 -1.712595 -0.314994 -2.089082 0.814101 -2.188163 -0.966968 1.204327 1.405596 0.646913 37.962452 -65.068023 51.735953 -23.839138 -14.390107 0.556950 2.156391 0.956031 2.266625 1.912343 1.005383 1.477616 0.299177 1.016130 2.104253 2.184842 2.142235 1.542983 0.922488 1.011048
+1 -0.060060 1 1 -0.408366 -2.175855 -1.463880 -0.041916 -2.329558 -2.355827 -0.888747 1.106737 1.126250 -0.785059 0.206569 -1.229088 58.497320 64.453183 -35.346781 -73.345554 -18.733747 1.253807 0.734482 2.436965 0.561605 1.653540 0.549463 2.327825 2.259861 0.742757 2.015917 0.270764 0.484518 2.049842 1.187142 0.789617
+1 -0.016656 1 1 1.400956 -1.941288 1.348876 -0.738072 -1.763621 -0.260421 0.916721 -2.180446 1.498352 -0.200641 1.896981 -1.470891 -2.249644 -9.762587 20.202717 -52.943657 -24.045587 0.862288 1.727658 1.998670 0.653252 0.713332 2.478358 1.013230 0.598700 1.855629 1.813415 1.060671 1.452793 1.587500 2.111488 2.271443
+1 -0.001262 1 1 0.176008 -1.208936 1.231125 -0.581886 -1.549232 -2.000354 -1.766879 1.532508 -1.056336 -2.275030 -0.101325 -1.792323 -62.828823 35.966969 -3.150332 2.376162 36.153853 1.192003 1.489921 2.359392 1.799874 0.727574 1.085617 2.222719 1.983509 2.332377 2.255323 0.962869 2.438411 2.369068 2.424773 0.416757
+1 -0.030848 1 1 0.395790 -1.855543 0.482558 0.324445 0.711811 -1.344638 1.287135 -1.701249 1.889682 -1.623305 1.839047 0.311228 1.968957 -57.733707 19.584011 48.467084 -63.716338 0.917618 2.397610 0.639714 0.416581 0.972671 0.679565 1.941934 1.087614 2.024692 1.505866 0.334050 2.134184 1.235879 0.916485 1.364653
+1 0.031078 1 1 0.882167 1.413337 -1.203502 -1.678312 0.969472 -1.518977 2.283766 0.842659 1.842770 1.617690 -1.968522 0.726082 -58.032764 -56.669594 54.127554 -28.198295 71.256411 1.472420 0.710523 0.268218 0.431624 1.796913 0.460330 0.511145 1.810714 0.674593 1.640203 1.384636 1.332497 0.281320 2.387010 2.476957
+1 -0.029297 1 1 1.695380 -1.562380 -1.497117 2.116173 2.119841 -2.204015 1.213085 -2.188757 -1.531749 -0.328597 0.191827 0.765982 -12.126367 42.150653 -23.976225 -68.420781 -48.062843 0.741912 1.317795 0.689320 1.650917 1.458164 1.863830 2.390291 1.374292 0.722017 2.187136 2.435820 1.577391 0.965026 0.442149 0.945883
+1 -0.047838 1 1 -0.206317 0.756637 -1.937941 1.060135 0.144960 0.041869 1.554285 2.092665 -1.841978 2.265340 2.171962 2.005304 4.693095 -23.158919 18.040617 58.641981 -54.228856 1.009179 2.280290 2.080438 2.427200 0.700566 1.668189 1.493422 0.444649 2.468156 0.551633 0.546573 1.008561 0.891736 1.648519 1.668033
+1 0.020006 1 1 -1.199539 -1.060312 1.587047 1.370916 2.113406 -1.978677 -0.293782 0.982409 -0.864184 -0.764225 1.634542 -1.476020 -45.998221 7.891542 33.141153 53.364456 46.418910 1.564334 2.003827 1.828650 0.626967 2.183452 1.272417 0.755112 0.417524 1.070382 0.408114 0.415012 1.608210 1.430127 0.894511 1.053720
+1 0.007045 1 1 -2.052941 0.333551 -1.748866 -2.025354 2.173151 -1.587184 1.031918 1.847974 -0.455208 2.232642 -0.746513 -2.256200 20.132565 -31.974055 62.054217 -4.781219 42.043973 1.120766 1.222749 0.735629 1.468020 1.003782 1.558708 1.952445 2.243065 1.939738 2.429830 2.150691 1.915128 0.554998 0.843199 0.390493
+1 -0.018798 1 1 2.347790 -2.247578 -0.532667 1.011573 -0.790738 -0.994776 0.360813 -0.665651 -0.385402 2.080729 0.166454 -1.565953 -8.866992 72.457967 -48.952171 10.855606 50.171699 0.411186 0.300096 0.708316 1.419425 1.029249 2.091583 0.730820 1.636155 0.852166 0.361714 1.323646 2.262973 1.292698 1.882664 1.687788
+1 -0.009454 1 1 -1.668354 -1.312093 1.628889 -2.242170 0.832362 -1.582540 -1.031896 -1.478022 -2.110438 0.015106 -0.575438 -1.569513 36.807143 17.655842 41.742019 8.118262 -56.378095 1.425247 2.124915 0.694491 0.815872 2.361956 2.142231 1.471366 1.003073 0.905645 1.432760 2.403381 0.873297 2.250588 2.375878 2.134684
+1 0.032629 1 1 0.574524 0.334279 1.065318 -2.277311 -0.740163 0.792237 -2.075891 1.023033 -1.383853 1.927078 0.156255 1.382758 -47.679872 -55.600987 14.215127 -36.363622 -63.398353 2.333198 0.309823 2.199912 1.169037 2.496348 1.869455 2.428027 1.090859 0.322465 0.919590 1.794675 1.107294 2.043503 0.398982 2.190396
+1 -0.008583 1 1 -1.247847 2.282874 -0.002632 -1.830620 -0.033923 0.053364 1.528324 -0.696396 1.245750 0.174992 0.562663 -1.094742 -68.573953 -72.434311 -3.471401 6.166951 -2.046320 0.737439 0.388209 1.127911 2.045863 1.811816 1.193886 1.647730 1.895880 1.056851 2.496232 2.167144 1.682161 2.326422 1.171106 1.283916
+1 0.017757 1 1 -1.097562 2.284886 0.827439 0.512222 -0.616272 0.149087 -1.287043 -1.459008 1.728557 -0.026103 -0.468675 2.088256 -17.365465 38.634715 -16.342600 -20.081139 -3.704812 1.123478 1.787931 0.257616 2.259780 1.626378 0.793868 1.532181 1.613261 0.832547 1.369158 2.184728 2.482415 1.698654 0.528246 1.235918
+1 0.002435 1 1 0.237781 0.271643 -0.802861 -2.107389 -0.573876 1.123131 -1.374531 -1.618973 -0.749538 -1.266433 0.918507 -0.431185 23.042421 -26.031504 38.519486 -2.990978 -19.371405 2.496835 1.050732 0.908902 2.164304 1.205908 1.202492 2.287445 0.841004 1.747835 1.368406 0.806109 0.271889 1.395267 2.248687 1.937588
+1 0.002026 1 1 -1.717095 -0.550895 0.949575 -1.352571 -0.091594 1.534528 -0.085306 -1.169538 -1.043976 -1.881305 1.037118 -0.282938 -17.103640 -60.882730 43.954814 -1.444600 20.610942 2.246519 1.493300 0.636717 1.804071 1.515570 1.432359 2.412635 1.152129 1.837253 1.209029 1.905459 2.296795 0.481090 0.676635 2.197264
+1 -0.005717 1 1 1.413825 2.294313 -0.956517 -2.219895 -1.799514 -0.327891 -2.077584 0.854083 0.628470 2.225923 -0.572949 -2.146054 -3.231864 -17.938527 7.173649 -32.480019 -41.679476 1.270744 1.897274 1.987897 1.837104 0.961445 1.007471 0.565053 1.101727 0.731571 0.761147 0.594927 1.442034 0.768869 2.123688 0.324476
+1 0.043349 1 1 1.656872 1.541858 0.584400 1.392875 -1.095244 -1.182416 -0.729059 -1.080823 0.861316 -0.319752 -1.956168 1.025687 25.539695 -54.341728 28.582237 -68.346476 0.785030 1.284922 1.686176 2.302771 1.928393 0.755309 1.475718 2.146123 1.644397 2.137801 1.270313 1.399749 1.083218 2.401243 0.937266 1.884513
+1 0.028027 1 1 -1.598286 -1.774992 1.840533 1.722039 -1.184242 1.579913 -0.710449 0.669834 0.002411 -1.883987 -1.636543 0.830463 -16.043633 54.659237 57.803381 -48.575250 45.777155 1.774627 1.652590 0.333594 1.207520 1.285432 1.251794 0.657116 0.395803 0.508756 2.158499 0.396095 0.918642 1.620082 0.717283 1.381542
+1 0.025494 1 1 0.313977 -0.856946 -1.624302 -0.778924 -0.364079 2.322416 0.120521 -0.737325 1.361543 0.084350 -0.752160 1.791350 -7.228718 6.933590 -17.146335 -28.452396 0.580451 1.459657 2.212268 1.843852 1.871276 1.540633 1.920163 1.933170 2.286442 1.977604 2.091101 1.636726 1.453355 2.033110 1.226077 0.434576
+1 -0.018689 1 1 0.636797 0.815042 -0.508220 1.913249 -1.366141 -1.977532 0.105502 1.316281 -1.928455 0.264034 -1.457808 -1.666545 25.859286 67.016021 -11.733171 50.597938 49.536125 2.179693 1.109402 1.471698 2.073944 1.272664 0.407040 0.371823 2.471833 1.596350 2.348295 2.051353 1.834252 0.271134 2.193498 1.370225
+1 -0.056883 1 1 -1.992319 1.338982 -2.105619 0.905637 0.031145 0.377099 -0.265670 2.231606 0.705071 -1.534978 1.946955 -0.351041 -0.941792 71.298286 -39.703826 47.799027 -41.756733 2.043838 1.537719 2.437344 2.443896 2.312473 0.733436 0.609982 2.466846 1.034299 1.468293 1.103832 2.353680 0.303434 0.570554 1.309501
+1 -0.045415 1 1 0.324679 -0.073758 -0.294167 -0.760539 2.330183 -1.286144 -0.485518 1.751502 -0.805612 -1.228308 0.809674 -1.191025 21.374563 -7.721845 -31.043537 -48.725752 66.283653 1.065415 2.432877 1.612376 1.702434 1.051970 1.464449 1.753579 1.155082 1.970684 0.533285 0.416566 0.720417 2.302230 1.837893 0.720549
+1 -0.015967 1 1 -2.002053 -2.040683 -0.988165 -1.633671 1.979942 -2.014993 1.955692 0.397633 0.850334 -1.106437 -0.807089 2.226216 -11.481623 -71.644738 66.887445 -72.716206 58.725225 1.297822 2.490214 2.278551 2.100851 1.252168 2.434261 2.377436 1.324126 1.340796 0.258437 0.298256 1.289800 0.422596 0.823316 1.467024
+1 -0.009589 1 1 1.004197 -2.235533 -0.721064 1.347720 -1.322941 -1.617537 -0.166814 0.230281 1.455061 -2.093406 -1.178739 -0.183155 -34.872713 -55.680981 19.752109 23.701079 -55.958546 1.445833 1.622679 1.622857 2.360720 1.627678 2.377025 1.164577 1.796845 1.571710 2.236037 0.820415 2.210151 2.248668 1.607413 1.546507
+1 -0.012082 1 1 0.447686 -1.433781 1.602380 -0.098245 -1.867185 -1.986953 1.976128 -0.127710 -2.288486 -0.070415 -0.653092 -1.368558 -5.896642 45.144497 43.569026 -35.373958 69.884839 2.192359 2.485926 2.207715 1.821959 0.665169 0.750065 1.095702 0.704762 2.439614 2.341782 0.579197 0.309785 1.555076 1.658942 1.345938
+1 -0.062697 1 1 2.144256 -1.846701 -1.707924 -1.920636 -0.259997 -1.383442 -0.585888 1.877871 -2.208897 -0.731797 0.021314 0.079725 51.308399 -9.739817 -47.101914 58.128525 16.120170 1.850501 1.111584 2.149944 0.609041 2.403808 1.301036 0.265694 0.767983 0.740299 1.208724 1.270296 1.118634 1.377406 1.313675 1.183178
+1 0.021694 1 1 0.120063 1.002986 0.975128 -0.713585 -0.200044 -2.208619 -0.778937 -0.579463 1.470968 1.368919 1.539841 -0.338058 44.437733 14.974209 -28.471523 -20.880231 65.956746 1.900507 2.317085 1.749059 1.682125 1.726384 0.833312 0.718370 1.636466 1.588512 1.126169 2.020737 0.284164 0.688014 2.201185 2.320413
+1 -0.019461 1 1 -1.822218 -0.195390 0.615952 -0.814154 1.292990 -2.261932 -1.451163 1.629173 -2.184973 0.798969 -2.041114 1.181329 41.484768 34.494566 0.172951 56.779871 -0.700874 2.431275 1.690844 2.007658 0.962220 0.537478 1.138351 2.007471 2.321121 2.076398 2.014597 0.579662 1.372728 1.440143 0.490207 0.913560
+1 0.005411 1 1 -0.258532 -0.327610 -2.073312 1.967091 -1.213838 -1.041075 -0.246732 0.075274 2.202464 0.990475 -1.951540 -1.304222 62.898739 -60.889279 -66.109374 -50.243704 54.063583 0.574502 2.410527 1.720060 0.301086 1.602127 0.454669 2.114602 0.618260 2.102836 0.857974 1.211958 1.631709 0.387431 1.553000 0.524506
+1 0.022561 1 1 -0.191768 0.232420 -0.281305 -1.363422 1.307984 -0.009319 -1.109522 -0.819117 -2.016080 -2.178306 -0.241480 -1.188569 -14.497427 -58.253389 -14.712172 -67.479446 22.947702 1.855377 2.067206 0.536408 1.151828 1.270450 1.447679 1.136462 1.763412 2.172438 0.670967 1.442160 0.636796 0.873573 2.392037 1.472865
+1 -0.007620 1 1 1.366441 2.306687 -0.329041 2.153608 -0.165101 0.752993 -1.921669 1.218620 1.303782 0.062729 -1.283134 -1.745143 -22.651783 -8.513806 8.461257 8.341581 -53.041971 0.978972 0.827942 0.471588 0.728582 2.273557 1.428232 0.539179 0.483650 0.952464 0.804089 2.317208 1.563137 2.136259 2.351526 2.352542
+1 -0.006321 1 1 2.196449 -1.128238 0.351125 1.443785 1.607700 -0.231983 -1.787652 1.122005 -1.447936 -0.690415 -1.906560 0.686203 57.366029 -49.154869 54.119244 -17.860246 -27.149894 1.251097 2.442473 0.898368 0.617204 2.343984 1.588093 0.836240 0.438774 0.468375 0.723247 0.362392 1.466883 2.148063 0.490484 1.062212
+1 -0.005025 1 1 -1.527834 -0.504532 -2.083842 -0.659594 -2.254331 -0.933154 -0.695719 -1.509862 -0.032191 0.888974 -2.005825 0.521225 -3.167550 12.983245 -40.600091 -15.736761 -37.739159 2.394353 2.141917 0.692952 1.940123 2.141046 1.802448 1.250973 0.344410 0.741389 1.525950 0.386556 0.344965 1.078666 2.394476 1.960819
+1 0.087903 1 1 -2.309608 -1.627539 1.369758 1.496413 0.196499 -0.823321 -1.986076 -2.130806 1.706734 0.770198 -0.215865 0.498682 -63.166650 58.109425 -4.886191 -72.218448 24.543812 1.492779 0.893896 1.954012 1.571356 0.787288 1.197256 2.033001 1.640569 0.791545 0.749092 0.482125 2.327330 0.686230 1.471053 2.487267
+1 0.054368 1 1 2.029790 1.692206 1.639509 1.893092 -0.852385 -0.370525 -2.350073 1.573039 1.568835 1.591499 0.809526 1.035555 54.605767 59.129965 47.325197 -55.411075 56.065998 1.393516 2.071118 1.034014 1.171705 2.349039 1.052939 1.989169 0.716734 1.143441 2.057140 2.352384 1.023157 0.956108 1.312178 0.783179
+1 0.006801 1 1 0.245654 0.655952 2.307152 -1.952809 0.935033 -0.720477 1.776780 -0.068333 1.351193 0.503511 -0.945499 -0.828548 -9.551155 -26.262496 56.226710 2.317908 -42.921420 0.920432 2.453158 0.482726 1.175049 2.292404 0.930842 1.913852 1.613207 2.172321 0.945552 1.646744 1.075447 2.287025 0.527478 1.829440
+1 0.010112 1 1 2.088868 0.309150 -1.878293 -0.178803 1.364451 1.849519 1.939548 -2.327916 1.678248 -2.041563 -1.647577 -0.828160 48.074595 -60.280846 -40.180778 -18.332295 -10.880112 1.194244 0.902512 0.513833 1.990305 1.809950 1.330048 1.867871 0.558212 0.875124 1.451294 1.143179 2.155600 1.164755 0.284462 1.195227
+1 -0.007499 1 1 -0.956589 1.281804 -1.756968 -1.533846 2.126430 0.146741 1.697194 0.653792 -1.006775 1.326438 -0.872927 -1.612994 24.986768 -47.392544 -26.480319 -4.714430 -35.418710 2.391027 2.493297 2.343919 0.489676 0.987865 1.804113 2.224997 2.023819 0.323769 0.337325 0.923064 1.678693 0.299979 0.998204 2.313269
+1 0.008679 1 1 2.340700 1.120510 1.712130 1.919952 -1.801854 -1.949125 1.581105 0.474140 0.222029 -0.571180 -0.680149 0.986227 65.063007 13.965832 -26.253842 51.684479 11.033222 1.905321 2.238810 2.434673 0.300527 1.211335 2.413631 2.150047 2.338154 0.356378 1.646191 0.788603 0.798005 1.323911 2.225724 0.737369
+1 -0.020592 1 1 0.027734 -0.402968 -0.984241 -1.657878 0.394451 -0.800239 -0.451862 1.930992 -0.043616 2.085202 -0.038814 -2.036460 -22.529316 -50.209605 27.168646 23.437852 19.985875 2.164104 2.344674 1.945161 1.313893 0.346271 0.522164 0.262379 1.296038 1.758180 1.981722 1.549857 1.691107 1.940843 0.740012 0.877393
+1 0.036295 1 1 2.011434 -0.510322 -0.438233 0.075836 2.229817 -1.098774 0.766635 1.169831 1.267948 0.970833 -2.215430 -2.141316 -18.347559 32.570721 66.100463 50.478693 -4.600601 0.290519 1.749594 1.671688 1.818290 1.996518 0.476150 0.904539 0.833908 1.748468 0.756150 2.118318 2.315614 1.774942 2.450780 1.009651
+1 -0.061915 1 1 1.628035 2.256550 0.533795 -0.893284 0.246184 0.133374 -1.478364 1.561953 -0.983412 -1.863397 0.417342 2.232859 -57.675652 -54.690012 24.975354 60.770232 15.294942 0.806347 2.021127 2.330203 1.729204 0.976413 0.574618 2.101673 1.577271 1.194531 1.239073 0.597879 1.545230 0.429764 2.042534 2.117976
+1 0.005791 1 1 0.677650 -0.587304 1.636074 0.701951 -2.137322 0.561135 1.512738 1.253956 1.436249 2.180407 -2.155090 -1.181943 -69.978617 19.385037 4.320154 8.827945 21.275144 0.945125 1.215712 1.715816 0.973981 2.444820 2.096932 0.629130 0.291138 0.901249 1.797865 0.710766 2.100976 1.104951 0.908526 0.348700
+1 -0.032285 1 1 -2.208774 1.331394 2.315985 0.423419 0.696190 -0.000645 -1.410000 0.741936 0.742007 1.936174 2.228541 1.025597 -22.460993 48.096033 0.020150 38.664412 32.764533 1.727698 0.425573 1.356549 1.767649 1.378268 2.301593 2.378726 0.494486 0.822777 1.406812 0.541363 1.182182 0.683508 0.714228 1.782346
+1 0.034653 1 1 1.882069 -2.340434 -1.361423 1.930416 -0.294799 -1.965020 -1.667016 2.333522 -1.716729 0.895457 -1.429041 1.157970 -5.086036 18.991876 -3.536631 -40.158289 59.629686 2.067067 0.445247 1.266727 1.883382 2.493841 2.476980 0.359812 0.863555 0.526725 0.413559 1.940636 1.770868 1.477038 1.826643 0.634214
+1 -0.052285 1 1 -0.603552 1.880328 1.393432 -1.168023 0.851228 -0.218401 0.285309 -2.028828 0.329402 -0.804143 -0.091854 1.874503 -72.086367 -5.573463 -73.189317 57.141492 -72.937775 0.397338 1.553802 0.494623 0.872696 1.153538 0.766185 2.029150 2.176032 0.312396 0.439624 1.256304 2.200810 0.517065 2.318824 1.725424
+1 -0.003720 1 1 0.464359 0.757794 -1.338983 2.080060 -1.639296 1.691288 0.355483 -0.713072 -1.000335 1.170842 -0.600906 -0.780211 49.847439 35.900837 -64.630163 60.856097 -41.569916 1.891297 0.521135 0.972604 1.809259 0.965250 1.963768 1.301558 2.289666 2.171323 2.182596 0.395983 1.282472 1.000064 2.073424 1.532448
+1 0.019301 1 1 -1.613512 1.500079 0.540111 1.589917 -2.217811 0.242168 -1.380721 -1.971713 -1.057041 0.024550 -2.084226 2.311912 -65.160304 0.768313 13.032065 29.919592 58.587284 0.272228 0.343717 0.346074 1.723126 2.335849 2.117981 1.156046 2.407286 1.262483 0.294601 0.615038 1.945004 0.933006 2.280906 1.192772
+1 0.006594 1 1 1.754449 1.607295 -2.315120 -0.028480 1.997348 -1.630342 1.382581 0.243062 -0.505113 2.286305 1.101507 -1.948288 48.321259 35.392344 -60.882171 53.345283 24.170504 1.879852 1.666931 0.604847 1.659413 0.251312 2.053028 0.739247 1.531703 0.326644 1.413263 0.965587 0.875661 1.485937 0.642744 1.855462
+1 -0.001235 1 1 -1.986993 1.307293 -2.190737 -1.829113 1.719622 0.601108 -0.543155 -0.911499 0.420924 1.178759 0.511321 -1.622364 -37.895485 -9.421031 60.730695 -49.215462 -64.272968 2.338385 1.980836 2.408403 2.025665 2.098452 1.427135 2.354094 0.506954 1.126684 1.675829 1.661387 1.924368 0.607603 0.731444 0.885102
+1 -0.003611 1 1 -0.354972 -0.125833 0.986574 -1.552512 -0.573837 1.783335 1.725964 -1.190746 0.645384 -0.953922 -1.021138 0.255291 -73.363080 -13.287371 29.149022 7.612394 -8.499947 0.495821 0.770271 0.946542 0.281416 1.757438 0.764263 1.215464 2.062515 0.434800 1.184635 1.415597 1.945197 1.920657 1.240794 0.280485
+1 0.054190 1 1 -1.742160 2.309446 -1.080367 -0.893895 -0.599040 2.307494 -0.914950 -1.031445 1.391638 1.666834 -0.675977 0.420860 3.171115 46.923698 -53.400567 -53.324497 25.173967 0.607929 1.704460 1.352270 1.859506 1.724032 1.799131 1.748810 1.994890 2.372238 1.707351 0.444726 1.506983 1.115740 2.242019 2.365661
+1 -0.033105 1 1 -0.288328 -1.594473 1.046426 0.647657 -0.451359 0.955295 0.538004 -0.841818 -1.841904 -1.192066 2.020482 0.770205 -3.303542 -22.625720 -20.480528 33.772063 7.058983 1.229900 1.672482 1.649997 1.752895 0.900361 0.362687 1.926586 1.880551 2.178449 0.447864 2.499042 2.150793 1.370398 0.527696 0.986740
+1 0.034687 1 1 -1.456371 -1.080318 -0.065513 1.617006 0.663538 -2.137281 1.253685 1.590897 0.107621 -0.768314 -1.103261 0.745860 22.948073 38.269386 -6.428643 -46.199849 69.129611 0.795555 0.646481 1.654667 1.496628 0.321999 2.091872 1.099148 2.382082 0.659094 2.142413 2.288348 0.268415 1.508097 1.829158 2.412844
+1 0.031837 1 1 -0.758169 -0.253749 -0.047716 -0.859576 1.287396 -2.024332 0.507916 -2.300898 -1.326968 1.382006 0.013048 -2.186463 -21.433692 63.939259 27.127353 -70.579920 -36.722628 2.166872 1.610409 2.389207 1.150061 0.820640 1.502144 0.780090 1.720097 0.915176 1.866021 0.959571 1.003216 1.049969 1.571171 2.178501
+1 0.002442 1 1 1.009693 0.597871 1.611612 -0.447122 1.475296 -1.285904 -1.177595 0.202115 -0.687982 1.286132 0.296098 0.236750 57.303209 -54.963387 -69.652421 -48.245644 35.453105 2.280159 2.141387 0.794781 1.130738 2.308989 0.681583 2.122315 1.994912 0.482596 1.233268 2.036181 1.093657 2.350419 1.748794 1.737970
+1 0.053944 1 1 -1.012734 0.129156 -1.679972 1.339388 0.015617 -1.425924 1.701895 -0.450897 -0.696133 0.953020 -0.002288 -0.759678 -65.265328 35.625425 -43.476389 -57.677099 70.998546 1.713507 0.417664 1.186865 0.633728 1.063100 1.774550 0.358005 1.990559 1.575458 2.226497 2.491560 2.406488 1.342940 0.289628 0.282296
+1 0.017764 1 1 0.713703 2.180806 -0.147633 2.169276 -0.727588 0.084213 1.651817 1.406359 -0.664037 -1.527678 2.127805 -0.302131 65.144429 32.419802 -70.382769 -23.200672 66.305261 2.012809 2.028211 2.151487 1.797744 0.931802 2.291129 2.003086 0.623113 0.407511 1.530666 0.905188 0.487430 1.485309 1.339913 1.162486
+1 -0.050615 1 1 1.198239 -1.949882 -1.707146 1.731114 0.539704 -0.541608 1.531977 -0.551535 -0.380190 0.145507 -0.200746 0.140749 -1.509950 -27.725285 71.142604 43.740967 4.432279 0.524762 1.179645 0.792672 1.681394 0.686039 0.514834 0.816021 0.362234 1.072102 2.320240 0.772744 2.005831 1.745578 1.676356 1.516098
+1 -0.021882 1 1 -1.812333 1.005677 -0.929759 -0.174666 0.198848 0.953624 0.728937 -0.970160 -0.615972 0.472563 1.991575 0.299250 43.563671 24.618882 69.552299 15.482729 -31.780455 1.613508 0.470124 0.866038 1.744920 1.870972 0.920016 2.204981 0.871977 0.324752 1.111428 1.772068 1.402841 1.293564 0.678940 0.444854
+1 -0.066951 1 1 0.201056 0.372073 0.098088 -0.774372 0.749772 0.495063 -1.554843 -2.049797 1.329746 -1.814276 1.338017 0.535041 38.258673 -36.488746 -66.360991 70.822668 66.582705 2.207740 2.237328 2.270199 1.241330 0.284153 0.510353 2.010510 1.640698 0.716315 0.857932 0.511142 1.764701 1.331052 0.747612 0.365848
+1 -0.023799 1 1 -0.176474 -1.903436 1.352462 -1.736482 -1.221366 -0.334121 1.588521 -2.130557 1.174500 -0.379702 -1.071502 2.021974 72.466765 -51.076055 14.747456 60.492445 -3.471638 1.407756 0.651946 1.257508 2.188439 1.849628 2.206694 0.411455 0.320922 1.979144 0.966639 0.556116 1.641793 1.119950 1.000026 1.436935
+1 -0.004166 1 1 1.829248 0.552131 0.968760 0.642263 -1.575813 -1.064058 -0.099620 -1.419752 1.763570 -0.596839 1.607481 0.813339 -27.243997 60.136641 16.518181 -28.938982 72.527811 2.498710 1.068194 1.894004 1.028841 1.981075 1.935534 1.511278 1.306336 1.595030 0.414201 1.481652 0.619120 0.795392 2.410502 1.299884
+1 -0.046214 1 1 -0.381445 -2.090041 -1.170479 1.990166 0.189966 -2.245932 -1.150828 -2.317743 -1.696473 2.038243 -2.323099 -2.189047 -53.860079 23.655015 69.830789 46.067517 -43.237401 2.259940 2.062295 1.234305 1.461494 1.584736 0.655220 2.284395 1.332478 2.206868 1.073580 2.413819 0.796887 0.532202 2.466636 1.993873
+1 -0.040964 1 1 -1.629409 -1.781567 -0.276435 0.380459 -0.341055 -1.851728 -1.368729 1.651094 -1.313963 -1.525755 1.458889 0.995214 73.200397 -20.927515 21.261733 45.949275 69.466263 2.417300 0.808767 2.190616 2.434387 2.240028 0.398124 1.274429 0.835172 0.490569 2.490364 0.293462 1.723502 1.894093 0.265016 0.619164
+1 0.012471 1 1 -1.520828 -0.564545 -2.275729 2.278028 -1.342520 -0.818076 1.340542 0.564896 -1.260829 0.858378 2.132859 -0.186547 -49.677435 -28.647209 26.363696 -5.367272 -57.739925 2.351248 2.174570 0.501694 0.467295 0.578698 0.930121 1.038578 1.373988 2.369625 0.540578 1.490522 1.197196 1.030554 1.524321 2.267148
+1 0.022535 1 1 -0.867715 1.152961 0.476746 1.612604 2.086982 1.599582 0.004309 1.740003 -0.861342 -0.117802 -0.703121 1.323238 60.685534 -58.233971 11.649774 47.747460 -8.435169 1.076820 0.621660 0.742772 2.270971 0.705742 0.906363 2.248991 0.288642 1.700541 0.734304 1.702870 1.630093 2.478155 2.101950 1.722982
+1 0.032932 1 1 0.673054 2.280402 0.858371 2.023581 1.008202 -0.894188 -0.807337 -1.948886 0.886632 1.045535 -0.199184 -1.884418 17.521984 41.987999 -57.693354 -52.206700 61.997317 0.458633 1.240861 1.405422 1.918639 1.060907 0.910067 1.499701 2.475168 1.392923 1.103445 0.342613 2.038851 0.967709 0.533411 0.295763
+1 0.023275 1 1 0.732957 0.624188 0.943446 -0.691639 1.090523 1.940904 1.619052 2.080237 1.336808 -0.939100 -1.663896 -1.785633 65.991789 24.000159 20.668377 -26.585746 23.367786 2.010798 1.980869 0.722166 2.435811 1.433329 0.716075 1.326082 0.458242 1.426807 1.347128 0.928861 2.358761 2.450377 0.990536 1.685102
+1 0.002693 1 1 -1.695612 -2.343233 -1.277014 2.160745 1.972066 2.275137 1.897498 -2.197383 -0.427600 -0.287714 -0.702152 -1.251368 -11.119021 22.615956 6.372130 -3.613411 19.401772 1.158769 0.931527 2.171867 2.315729 1.449959 1.208609 1.600527 0.556891 1.169898 1.229565 0.543677 1.824502 0.660217 0.774318 1.454676
+1 0.029669 1 1 1.095302 2.141873 0.519633 1.422268 -1.883047 0.035507 -1.704264 -1.658604 2.334257 1.217097 -0.729762 1.235537 -58.247128 -59.472941 38.273268 58.813928 -14.313441 1.884951 1.877989 1.859724 0.882423 0.381856 2.361939 1.861820 2.353955 0.419985 1.930069 1.915411 0.814694 0.561743 1.706647 2.114953
+1 -0.006578 1 1 0.396203 0.379433 1.273136 -1.365616 2.131658 -1.519877 1.281509 -2.005244 0.868557 -1.143317 1.390838 -2.342587 5.007291 7.537776 -62.589531 7.753820 -31.538469 1.869203 0.441081 0.991568 1.030399 1.164971 1.660892 0.360510 1.343712 2.014940 1.853761 1.914375 1.406726 1.341287 1.762142 1.062707
+1 -0.038993 1 1 0.213152 1.028396 -0.783920 0.504394 -0.237626 2.327428 -0.464744 2.193464 0.536634 -0.309042 -1.020404 -1.546839 17.007602 -53.241362 72.427410 37.485782 23.543435 1.292683 1.620197 0.403641 1.737627 0.791803 0.589070 1.993513 1.724562 1.705174 2.102325 1.277000 1.280473 1.166657 0.762425 1.830899
+1 0.022433 1 1 -0.017967 -0.386759 -1.872768 -1.565317 0.983192 -1.840330 1.699291 -1.803447 -0.454010 -1.189642 0.358942 0.878042 -61.843960 -61.428749 17.017578 -35.574706 -4.075862 2.079771 2.468720 1.028042 2.045244 0.417539 1.324960 1.852171 2.183834 0.944363 1.916017 2.003664 1.332757 2.396690 0.922752 0.935656
+1 -0.013219 1 1 -2.030559 -0.484449 0.879428 -2.218306 1.351669 -0.929878 -2.173205 0.664424 -1.387511 1.709119 -1.553686 -1.461129 -30.064058 63.372439 -49.414972 32.562950 -64.492683 0.947266 1.199675 2.185074 1.540289 0.641626 1.059597 1.391642 2.071899 0.663496 1.873174 1.937330 2.450328 2.409199 1.912401 1.979901
+1 -0.008573 1 1 -1.951451 0.186393 -1.026790 -0.497729 -0.840441 -2.269126 0.159551 0.219017 0.638508 1.301537 0.025824 0.492027 -23.628948 68.265883 -5.300627 12.357913 -50.561324 0.862435 1.941291 1.535733 0.569106 1.718423 2.029146 2.104397 2.347021 0.884110 1.731647 1.532286 1.133633 1.469452 0.326670 1.846470
+1 -0.004815 1 1 -0.258299 -1.126715 -2.315770 -1.528008 1.287959 -1.981230 -0.796081 -1.262819 0.410097 -1.721798 0.519716 -1.910074 -58.065064 0.462911 -19.855430 39.793501 -40.629314 0.521733 2.013955 1.047398 1.116608 1.077441 2.041858 2.014853 0.381357 0.717025 1.543941 1.272030 1.013890 0.449887 0.493732 1.654096
+1 -0.015940 1 1 1.896354 2.139731 2.212516 0.300910 1.008598 1.046811 -2.315035 1.403199 -1.935622 2.342213 -1.730088 -2.153711 -49.580144 -43.481140 12.478673 29.060799 24.850388 2.281964 0.966099 0.473663 1.860764 0.366076 0.388492 1.387713 1.290166 2.078642 1.487869 1.612343 1.149025 1.416317 0.545413 1.758763
+1 0.004004 1 1 2.206409 1.332901 -0.628771 2.137173 1.646451 0.747231 0.201879 0.060596 0.554211 -1.766082 0.794798 -1.458893 -33.589857 55.271738 2.107835 26.376051 52.291349 1.535507 1.258271 1.509775 0.796649 1.035535 1.991862 0.979705 1.899508 1.277187 2.179462 1.717828 1.036344 2.078042 0.404379 0.641868
+1 -0.020805 1 1 -1.271342 -1.472670 -1.702506 -0.397831 0.532484 0.635313 -0.573087 0.246564 1.805400 0.288629 1.947048 1.211087 61.241397 -15.847680 48.044337 31.165201 -6.462316 1.192808 1.524101 0.814117 2.111572 1.443960 1.633110 1.438432 0.973552 1.981581 1.426418 1.561284 2.498524 2.448367 0.952632 1.390353
+1 0.025159 1 1 -1.358963 0.865461 -1.340266 -0.638848 -2.299196 -0.998987 0.269478 0.516013 1.838440 -0.479375 1.328673 -1.007739 -23.839572 -21.690936 -59.562345 35.667894 70.293183 1.637863 0.321189 1.971830 1.793349 1.324394 1.342111 2.105558 1.621402 0.401888 1.534084 2.097195 0.548667 2.449911 2.154384 0.974724
+1 0.053658 1 1 -2.164879 -0.771093 -0.697177 2.260731 0.111452 -2.349743 -2.311896 2.321023 0.271284 -2.123153 -1.631825 0.021006 -12.156491 -14.136392 9.662572 -51.153045 70.768042 2.102240 2.099781 1.266543 1.041201 0.459705 1.264293 1.474652 2.226780 0.494865 0.441543 2.018447 2.289339 1.166911 0.518706 0.644297
+1 -0.001834 1 1 -2.019577 0.311715 -1.187570 2.191584 1.916650 -0.757718 -2.092422 1.228016 -1.001264 -0.300982 -2.219435 1.228696 31.939904 -36.037399 19.437026 -21.911894 -23.198820 0.586402 2.163027 2.246667 1.735231 1.031537 2.299868 0.384875 1.336286 0.955480 2.002021 0.720833 0.293240 2.492912 0.375272 1.942789
+1 0.025004 1 1 -0.809513 -0.812942 -1.894141 2.071213 0.455664 0.718414 1.243483 -0.221133 1.498752 1.812644 -0.486916 1.817254 51.054030 65.079757 -4.526709 -30.398341 -4.920956 0.527401 0.525910 2.461845 2.472249 1.843840 1.666603 1.847282 1.018679 2.179582 1.490841 2.061703 0.292059 0.636367 0.413573 2.178168
+1 0.021349 1 1 0.142230 1.274749 2.193285 2.237698 -0.593679 -1.842986 -0.525530 -1.562396 -1.755394 1.366289 -0.255539 -1.859416 43.269153 24.652420 33.225805 -23.901398 -10.803461 0.268442 1.946745 0.943339 0.452139 2.354586 2.022439 1.888391 1.184738 0.890924 1.516362 1.241738 0.391702 1.334356 2.266574 1.066779
+1 -0.057127 1 1 -0.129228 0.474778 1.526494 1.536085 -2.197955 -0.607604 -0.247908 -0.830533 -0.676016 -0.223670 1.257054 1.669194 41.143609 0.639350 -54.437074 -73.895044 45.995174 0.488297 0.300145 1.538843 1.077965 1.860435 1.584932 1.707287 1.616049 0.429795 0.306603 2.078937 1.938398 2.399660 1.328652 0.899352
+1 0.061587 1 1 0.571619 -1.356869 -1.643633 -0.514796 -0.238350 -0.417421 1.158715 -1.782708 -0.606973 0.925151 -1.876513 1.473535 66.584138 -70.390909 -10.007563 -47.115929 -27.412710 2.493683 2.083961 0.877992 2.407013 1.166623 2.438115 1.890699 1.724660 1.110099 1.925317 0.800404 1.144119 2.212845 0.277170 2.400221
+1 0.027104 1 1 -1.229174 0.380915 -2.094570 -1.891917 1.753803 0.171829 -0.757199 1.912948 -1.711525 -1.172610 -0.849582 -0.388622 -6.395272 64.670251 12.909771 74.520931 -26.716257 0.322922 1.856221 0.508496 2.285363 1.841983 1.960562 1.415192 1.884418 1.916477 0.732135 1.247593 2.040811 2.414837 2.170887 1.601321
+1 0.062515 1 1 0.270087 1.313255 -0.951412 -1.243180 0.605388 0.716160 1.065140 -0.554377 -1.015807 0.318166 -1.151053 -1.398960 -70.264353 17.022334 44.370482 -65.300648 42.010187 1.603221 0.839268 1.823911 1.973008 1.343757 0.515538 1.399755 1.187307 1.320941 1.799150 2.066605 1.685431 1.043050 2.289945 2.357976
+1 -0.033017 1 1 -0.703368 1.880663 2.303867 -0.604221 0.058682 1.385993 1.040463 -0.621764 2.097223 -0.635114 -0.795237 -1.215777 -20.601563 -50.473097 -51.333876 31.551328 33.174813 1.661333 1.022682 1.974609 1.247768 0.480090 1.878090 1.311296 1.703517 1.251883 2.145034 1.333934 1.920190 2.386980 1.972203 1.313310
+1 0.003647 1 1 0.065468 2.333572 -0.873484 -1.555042 -0.674650 -0.837178 0.736119 1.929482 -1.863620 1.390930 -0.798494 0.593564 -3.258573 -16.828545 62.643131 -6.900370 -24.511090 0.506558 1.222470 0.552216 1.348297 0.322703 0.419338 2.312453 0.391058 1.759248 1.939717 2.081641 2.383150 0.601047 0.804616 2.178382
+1 -0.005555 1 1 -0.674799 1.367715 0.158012 -2.077231 2.076789 -0.077942 0.068023 -1.839970 -1.672705 0.963558 -1.968276 0.147267 35.530830 16.666350 61.347931 -25.318007 30.253081 0.827886 1.787378 2.207425 1.433063 0.737934 1.962351 2.232455 1.377760 0.509430 2.243132 0.826227 0.893775 2.177442 1.512072 1.150652
+1 -0.062699 1 1 -2.352421 -0.191809 -0.465735 -0.329982 0.480304 0.144036 -1.346715 -0.626018 1.279852 -1.587678 2.152556 1.000139 8.017654 52.714086 65.646325 67.779985 -71.792155 1.213731 2.175235 0.432210 0.405303 0.423826 1.249083 2.330928 0.398801 1.397011 2.309154 1.207008 1.677551 1.343394 1.170966 1.181644
+1 -0.017775 1 1 0.933323 -1.188127 2.259715 1.891608 -2.240403 2.243830 -1.200581 0.287046 -1.111933 1.080157 2.082278 -2.073803 -50.070964 -42.689565 -33.513398 -9.679126 72.924444 1.241992 2.409587 1.685408 0.655381 0.480032 0.892848 2.347991 1.438519 2.433400 1.409434 1.859365 1.591066 1.304935 0.545913 1.161372
+1 -0.050940 1 1 -1.030090 0.594500 1.491566 -1.164484 -0.939936 -1.583514 1.453791 0.129326 1.172064 1.097619 -1.326610 -2.022740 -32.341550 35.573209 -21.076132 73.448592 -49.518875 0.419036 1.744117 1.881185 1.580510 1.625572 0.733802 2.266222 1.886960 1.880850 0.444027 1.011507 0.892304 2.204399 2.334289 0.640749
+1 -0.004757 1 1 0.462586 -0.759485 1.191718 1.554359 -1.379714 0.813514 2.086942 0.921933 0.591853 -0.579388 -1.980647 -0.425146 -45.794463 -17.546758 -8.360627 32.941903 4.559271 1.040075 1.796527 0.722964 2.358753 2.308587 0.670428 1.383480 2.151798 0.270865 2.180279 1.954128 1.270216 2.024989 1.989747 1.419651
+1 -0.030638 1 1 -0.820339 1.004828 -1.048902 0.145744 -0.919376 -0.028885 -0.098661 0.568552 -1.070236 -0.264009 1.870579 -2.240379 -65.644385 -35.174548 -28.628662 38.084070 28.965576 2.491607 0.932690 1.464808 1.025372 2.170418 0.462306 2.223065 1.049061 2.063919 1.535494 1.054372 1.338665 0.450092 1.688311 2.190218
+1 -0.025930 1 1 0.890723 -0.883245 -0.677796 -1.874201 -2.084016 1.133930 1.067116 -0.330037 -0.447804 -0.555464 -0.441620 -0.298836 27.609524 -66.725956 -63.147067 -62.754572 -66.090278 0.935577 0.492690 2.137443 2.001514 1.197618 1.360632 0.645138 1.588240 1.042900 2.025667 2.139886 0.321070 2.217571 0.965415 2.479630
+1 -0.039940 1 1 2.061873 -1.009076 0.341288 1.052697 -2.346404 1.975218 -1.286342 0.894424 0.055403 -1.889921 2.306125 -0.364987 37.808640 49.816469 -34.605155 -58.844864 -55.625531 2.150519 1.278871 1.227375 1.989946 0.278279 0.781140 1.363431 0.437303 0.507183 0.476559 1.027848 1.042131 0.354750 1.288934 1.609010
+1 -0.003603 1 1 1.969382 -0.409589 0.836902 -0.663642 0.398200 0.947651 -0.711390 -0.995062 0.267326 2.038801 2.355679 -1.601488 30.322491 -69.893636 -52.344444 -3.070885 -12.359935 1.623595 1.252970 2.416810 1.577373 0.657514 0.342262 0.640465 1.790217 0.426510 1.351263 0.676022 0.896405 1.371791 1.434124 0.575500
+1 0.010712 1 1 0.564581 -1.838046 -2.325909 -2.286092 -2.243604 0.285375 -0.911005 -0.712881 2.219847 0.977144 0.188404 -0.219585 -24.282536 33.416217 26.356168 18.109686 19.492506 1.533149 2.134142 0.526417 1.983105 2.303295 1.729185 0.655765 2.438553 0.262722 0.316704 0.837623 1.176469 1.418191 0.538064 1.986193
+1 -0.031481 1 1 -2.156321 1.694208 2.296462 2.170128 -0.545894 0.178911 0.445073 1.779197 -1.847523 -1.394529 1.581483 2.105265 -67.998505 -0.868581 -48.246200 26.117812 62.070272 0.850962 0.376620 2.109326 1.941227 0.459310 1.374801 0.273619 1.207301 2.114098 1.138452 1.461685 0.286218 1.463220 1.342111 2.110718
+1 -0.003405 1 1 0.130150 0.877293 -0.394275 -0.955446 1.643802 -1.351014 -2.206898 -0.121757 -1.191078 -0.226253 0.262396 -0.714916 32.047556 -26.730310 -6.316028 46.517944 27.084361 0.727934 0.389406 0.997416 0.328589 0.348559 0.723476 1.966264 0.501827 0.454226 1.426421 1.604409 0.554621 1.272593 1.479522 0.821023
+1 -0.054719 1 1 1.737183 -1.130215 0.110299 1.830553 -1.079253 -1.019684 1.132103 -1.362597 1.046701 0.554858 -0.315975 0.275968 38.061348 -52.917416 -33.009331 62.179329 -2.009936 0.910034 0.938597 1.754984 2.274953 2.390886 2.378293 2.228946 0.900994 2.006400 2.319243 2.012236 1.393513 2.018167 2.082224 0.934997
+1 -0.012025 1 1 1.204902 1.659656 1.209720 -2.187428 1.948971 0.541249 1.862037 0.272952 2.348624 2.354076 -0.264187 -1.112200 41.163441 33.949938 -3.384964 -41.092604 -43.388951 2.303627 0.550213 1.436423 0.963841 0.768829 1.453776 2.367308 2.101540 1.581870 1.990037 1.810925 1.957729 1.059282 0.601288 0.348053
+1 0.025887 1 1 1.786727 2.178270 -0.360601 -0.481462 -0.755091 -0.353654 -1.541279 -0.277342 -0.736756 1.507947 0.841291 -2.303503 64.165891 -63.871080 68.763458 -42.553107 9.927024 2.027335 0.923219 2.043837 1.527083 1.427490 1.576263 2.256944 1.202760 2.294448 1.533213 0.957149 0.804478 2.106186 0.924357 0.916585
+1 -0.015647 1 1 -0.042451 -1.900953 0.683792 -1.021713 0.006727 -0.044240 1.007887 -1.480514 -1.587522 0.066861 2.191475 0.094734 -19.129056 -52.041315 -8.388594 12.899557 52.848738 0.306206 2.148379 1.308590 1.219055 1.660642 0.666566 1.728797 0.896317 2.152292 1.820178 2.231191 0.378140 0.650287 0.370174 1.770225
+1 -0.039287 1 1 1.163304 -0.045496 -1.248240 0.386207 2.015989 0.649335 -0.522318 0.576701 -0.762793 2.153536 -1.380289 0.571182 22.867217 29.310367 19.344860 -70.937812 -51.802379 0.736254 0.726352 0.805779 1.479529 0.937526 1.755695 0.716915 1.936263 0.265330 1.401206 0.816598 1.063109 1.923190 1.056562 2.135740
+1 0.009821 1 1 1.338522 -0.400012 1.569809 -0.882754 -1.850031 -1.127049 1.488470 -1.359774 1.362007 -1.529570 -1.402471 0.041953 -55.702787 -46.745024 56.389017 30.211044 7.019452 0.264022 1.919003 0.428564 2.131770 1.150915 1.670414 0.641309 2.478020 2.075381 0.669247 1.787500 2.016114 1.323430 0.878812 0.450965
+1 0.060682 1 1 -1.084656 -2.296124 -1.204039 -1.291161 0.010752 1.644928 -1.279638 0.471508 -1.595627 0.504818 2.178362 1.173977 8.048625 -26.757616 -15.256278 -62.263218 -57.910486 2.101956 1.829501 1.426025 1.707750 0.397858 1.307541 1.589896 1.886334 0.365544 0.441860 0.596344 0.499955 0.496160 1.964477 1.967564
+1 0.024817 1 1 -1.129521 2.348515 0.515305 -0.638838 -2.123237 1.671935 0.236455 1.551699 1.049066 -2.108552 -1.263782 -1.650678 -35.366735 41.280044 43.699411 55.994564 0.643128 1.510827 0.468476 2.420980 1.914200 0.712499 1.963268 1.890268 1.228966 1.735262 1.551101 2.350356 0.688695 2.398606 1.624495 0.631305
+1 0.031024 1 1 0.581763 -0.510271 0.430349 -0.647758 -1.252907 2.055026 1.714807 -0.207142 1.021756 0.701977 -1.698698 2.346727 -39.733515 -1.182494 -74.169593 -68.355052 6.644439 2.471339 2.287669 2.346651 1.417769 2.449973 0.953565 1.318874 0.808969 1.095715 0.928137 1.442510 2.012184 0.527275 0.652700 0.423953
+1 -0.011830 1 1 1.974794 0.998959 -0.745979 1.989928 0.891152 1.611741 1.721622 1.230695 1.613941 1.001214 -0.530055 -2.214830 -47.319358 3.546702 59.413308 9.461145 13.461320 2.040986 0.845294 1.858168 1.735631 0.994267 1.398639 0.420057 0.900325 2.011187 1.774109 1.955712 0.893235 2.105449 2.031297 2.263291
+1 -0.001524 1 1 0.998339 -1.739575 -1.380181 -2.316340 -1.686067 -2.135915 0.647922 -0.706913 -1.153638 2.279492 -0.292626 1.570044 -52.357752 73.254221 -16.306841 -19.073504 -18.378159 0.899160 0.423730 1.877527 0.852180 0.587589 1.852865 0.349276 1.529493 1.444711 0.764125 1.149521 0.742167 1.108080 1.751522 0.332155
+1 0.039366 1 1 0.863523 -0.931177 -0.445747 1.031514 -0.219231 0.476112 0.381864 -0.283995 0.549320 0.851762 -0.672417 -1.008540 -2.157196 44.008459 0.167226 -39.426947 51.307708 1.054817 2.057681 2.439944 1.132593 1.992455 1.942923 1.963023 2.281711 1.224205 0.459605 1.837233 0.879911 0.912623 1.703983 2.346417
+1 0.027499 1 1 1.671893 -0.463618 2.257170 1.519240 2.147658 -1.205823 1.726810 -1.115343 0.306987 -0.532718 0.154314 1.733465 74.818941 31.935060 32.561708 64.633217 -9.527246 0.258648 1.604584 1.238230 2.186719 2.183875 1.631198 0.790767 1.171135 1.759685 0.266678 1.561985 0.774130 0.559403 0.631841 0.860071
+1 -0.063226 1 1 -1.870974 0.310666 0.038339 -1.232804 0.644178 2.345437 0.628045 -0.204854 1.774371 1.859414 -1.396738 2.150420 -60.795311 13.216333 -23.093349 70.078324 6.397540 0.976809 0.483111 0.893572 1.017571 1.563156 2.467825 1.732805 0.760918 1.247271 1.130978 1.852232 0.970618 2.182657 1.408766 1.877253
+1 -0.008924 1 1 1.802623 0.738860 0.873556 -1.945109 -1.608227 0.796347 1.013055 0.550774 1.719870 0.067509 -1.065827 -1.566373 66.378074 66.296297 41.866894 6.894575 -72.883771 0.512027 0.887753 2.218271 1.472989 1.277602 2.415048 1.217160 1.306578 1.155618 1.973859 2.152289 1.766329 1.685440 1.185721 1.658054
+1 0.043942 1 1 -1.554195 -0.589990 -1.100248 -0.459328 -1.036394 -1.683349 1.139458 -0.281632 -2.150012 -0.651192 2.303783 -2.020521 -45.253122 -69.219922 20.764032 -68.909017 -3.844310 1.955214 1.528874 2.278211 0.893649 2.312649 1.443072 2.453022 0.436698 1.585488 2.042327 0.897652 2.089837 0.642495 2.157979 0.644416
+1 0.011597 1 1 -0.366548 -1.478185 -0.136677 -2.199699 -1.653656 0.672660 0.383587 0.397564 -0.314512 1.299234 -0.988498 2.199041 0.454413 -12.685886 -61.686333 37.801159 74.072933 0.531865 1.298579 1.723486 1.629495 1.419705 1.236628 2.262897 2.264296 1.026891 0.708632 2.221489 1.566511 0.356565 0.287168 1.677963
+1 -0.018128 1 1 1.572727 1.037793 1.636663 1.187143 0.062183 -1.035024 -2.220661 -0.526257 0.358454 2.097780 -0.707671 0.245162 57.600147 -14.331111 37.021265 16.392608 -39.438414 1.503709 2.343748 2.124867 2.139551 1.437246 1.293469 1.340825 0.744190 1.355499 2.128629 2.366347 1.687865 1.442623 1.657793 2.281865
+1 -0.002029 1 1 -1.887665 -2.189565 -0.977521 -1.813333 -1.671083 -0.055794 0.036552 1.716974 -1.487401 0.469149 1.167177 -0.930245 34.117934 -29.887249 35.006889 60.784716 -41.285408 1.617183 1.489130 0.316126 2.374228 1.397805 2.152255 1.199520 1.824209 2.481471 1.589550 0.563562 0.790392 1.615779 0.400094 0.621924
+1 0.021202 1 1 2.137688 0.862719 -0.300753 1.637127 -0.451598 1.650580 -0.533699 -2.195682 -0.103123 0.974378 0.825731 0.079167 53.122556 30.801260 26.781657 -30.695278 -45.540319 2.182856 0.257567 1.436808 0.684689 0.310719 1.500871 1.890370 0.703008 2.201345 0.514007 0.417980 1.985548 0.596665 1.406583 1.194041
+1 0.003091 1 1 -1.477630 -0.230736 0.317890 -1.068877 -0.982443 0.289322 -0.552905 0.155425 1.572123 0.300298 0.143975 2.330870 26.984270 74.619424 -21.347591 11.045892 -51.692072 1.545121 0.846703 0.787946 1.011833 1.870215 1.698454 1.667453 0.377586 0.345552 1.935771 1.002891 2.340583 0.677061 0.363135 0.460844
+1 -0.015038 1 1 0.848381 -0.941315 -1.191107 -0.706811 0.557488 1.465280 0.011458 -0.637612 -0.378427 1.502170 -2.010769 2.263111 -72.971380 -29.982689 -69.059927 9.801593 35.375061 0.604779 0.516409 0.282158 0.734847 1.816068 0.657323 1.627537 2.270527 2.248296 2.112247 1.528276 1.235962 2.311549 0.955581 1.449297
+1 -0.026508 1 1 -2.026226 1.645772 -1.228023 0.878266 1.815905 -2.227880 0.664789 0.039257 0.053547 -0.110153 0.623207 -1.408319 22.451987 -49.449405 53.848728 -64.429809 -21.800788 2.037388 1.127300 0.776523 0.279255 1.442789 2.211727 1.746379 1.636347 1.841244 0.794364 0.870428 1.281785 0.704136 0.918972 0.413728
+1 -0.005697 1 1 0.968300 2.331641 -0.330259 0.536848 -1.412820 0.463437 -0.591401 -1.246229 1.203554 -2.146796 1.556873 -1.530687 -41.963449 20.306977 49.358506 68.413861 -68.236221 2.182417 1.889295 0.634249 0.831015 0.367642 1.961783 1.682616 0.975792 1.383517 0.525045 1.433971 2.493408 1.963396 1.789592 1.175573
+1 -0.014984 1 1 -0.836743 -1.370125 1.760145 -1.612353 2.127140 -2.060046 -1.272272 1.747278 -1.104438 -0.195536 -1.846364 -0.761788 6.097483 30.389304 3.032260 -36.809220 -52.563406 2.377576 1.423651 2.306908 1.698693 1.184423 2.344267 1.838827 0.661132 0.397933 0.301517 2.093824 2.396580 1.313400 1.062753 0.447393
+1 -0.037922 1 1 0.500938 -1.778841 -1.580826 -0.502508 -1.045541 0.092118 -2.140900 1.700873 1.219317 -1.124696 -1.368823 0.076170 -50.549811 9.322660 -64.049635 67.777776 41.080332 1.182033 0.433916 2.076798 1.987839 0.866566 1.624760 0.585972 1.685506 2.302575 0.876573 1.067096 1.429969 0.493867 1.671209 0.510436
+1 -0.070768 1 1 1.652258 -0.611001 -0.804771 -1.234817 -0.214034 -1.709568 -1.272380 -0.065197 2.226936 2.311672 -1.384942 -2.237309 -73.440454 36.296417 -16.114607 61.805515 15.284877 0.518860 0.977726 2.394727 1.672144 0.467589 1.025089 1.916832 2.191890 1.345766 0.537945 2.249684 0.690683 2.060093 2.477785 0.389642
+1 -0.054641 1 1 -2.233432 1.598259 1.314977 -0.289363 -0.144255 -2.317513 2.162891 0.343208 0.331558 -2.262537 -2.187846 -0.363824 60.353661 63.982313 0.726454 59.506428 74.529163 0.799692 0.421271 1.053587 1.643730 2.165216 0.783810 1.237113 1.405135 1.601800 1.702087 1.980554 2.178220 1.086120 1.669968 2.144576
+1 0.033480 1 1 -0.000090 -1.504722 1.526874 -1.504868 -0.923899 -0.645139 0.351909 0.486228 0.749195 0.218137 -0.013232 -0.909541 10.759172 -70.595807 -3.723520 -31.196850 74.544303 2.366585 1.190166 2.124603 2.207793 0.882216 1.412625 1.481785 0.601525 2.081389 0.406012 1.101489 1.224920 1.227040 0.867269 2.196872
+1 -0.007645 1 1 -0.065134 -1.426935 -1.146951 1.576098 1.143530 2.181261 -1.934045 0.565954 -2.317197 -1.941301 1.132386 -1.335680 33.375990 -49.730611 -22.372403 37.030696 24.909456 1.423453 1.223461 1.466278 0.987567 1.286827 2.203232 0.719695 1.419771 2.346985 0.272168 1.574876 1.441045 2.144480 1.032350 2.462631
+1 0.017175 1 1 -0.678984 1.730053 1.558011 -1.262071 -1.165326 -0.943053 -2.121316 0.968647 -1.261677 0.748455 1.908739 -1.769740 18.428261 -26.219057 36.311914 -55.653820 26.241140 1.897705 2.476741 0.833492 1.492103 0.773991 0.465953 0.521938 0.958446 2.353720 0.969578 0.442277 0.845401 1.408705 0.852055 0.743593
+1 -0.052639 1 1 -1.551944 -0.451847 2.172635 -0.818389 0.794343 0.317746 1.219515 2.216677 -0.463724 0.484194 -0.441535 1.136126 8.448685 -52.944562 -39.247135 73.396413 -26.487030 1.862414 1.096599 2.282699 2.071703 1.869987 2.378092 1.094433 1.884511 1.234817 1.069692 2.320417 1.493385 2.073885 0.285414 1.454292
+1 -0.028740 1 1 1.955255 -2.226400 1.981812 1.146548 1.070598 1.639992 0.585246 1.476023 1.501873 -2.282759 1.937994 -0.162860 22.812932 16.949806 25.384513 37.506238 67.338619 1.527433 0.562282 1.772617 1.627401 2.221981 0.836452 1.746158 2.424406 0.994088 0.640718 1.554633 0.973438 2.318010 1.542604 1.293191
+1 0.001743 1 1 1.272101 0.086041 -0.619795 2.203618 1.545250 1.036891 0.609918 1.444274 0.398326 -1.645710 2.281710 -0.715183 38.806215 16.055979 2.835030 -51.656572 7.998349 1.798756 2.198649 2.443506 0.260516 1.499678 2.097131 1.723142 0.349567 1.915290 1.032982 1.832132 0.637314 0.593344 1.830426 1.220504
+1 -0.022721 1 1 -1.232819 0.384463 0.983066 0.756792 0.670571 -1.745246 2.280748 1.957600 -0.513664 -0.049913 -0.090781 1.057529 -39.435491 57.702441 54.933600 19.015624 -54.409408 0.491155 1.089245 2.438547 2.400973 0.904396 0.677030 2.090561 1.551192 1.629322 0.759640 2.271054 2.108255 1.938381 2.117347 1.747558
+1 0.052101 1 1 0.354772 1.477008 -0.795241 -1.285519 0.587630 -0.877219 1.651102 -1.189896 0.798015 0.781737 0.519469 -1.333657 65.877907 59.975075 1.085407 -57.567352 -34.478051 1.035991 0.653136 1.011092 0.666332 2.299240 1.075193 0.264860 0.258140 2.063424 2.222358 0.424842 0.326753 0.979225 0.592992 0.423077
+1 -0.022358 1 1 2.079432 1.941858 -1.202988 2.241789 2.198670 -1.499494 -0.145572 -0.897826 -0.687836 -0.969178 1.759397 -0.056477 -64.333440 -52.129756 5.184311 -17.282428 -65.771814 2.471746 2.389142 2.314446 2.385203 1.348889 1.273665 1.494677 1.289043 1.189694 0.937532 1.850521 1.461640 1.789248 2.134991 1.292246
+1 0.002618 1 1 0.273248 -2.095610 -0.524902 -0.428505 -1.355287 1.381823 1.652594 0.332627 1.568632 -1.816296 0.377756 1.357077 13.777308 -44.780567 73.002690 -43.791808 41.090203 1.420742 0.668052 1.952104 1.007952 1.903582 2.261160 2.315243 2.296539 0.686491 1.354227 0.988592 0.521977 1.622019 1.765279 2.039129
+1 0.007667 1 1 -1.573979 1.493927 0.825301 2.267876 -2.315767 -1.481944 -2.054550 1.557997 -1.484020 0.745976 -2.040233 1.853612 1.847765 5.382082 6.648990 -0.422871 -57.198123 1.692266 1.171834 2.262293 1.103924 1.644955 0.250436 0.821273 0.885256 0.754813 2.134372 2.138636 1.803101 0.962534 1.315487 2.394221
+1 -0.028512 1 1 1.140087 0.869925 -1.718801 -0.942201 -1.945229 1.092826 -1.771030 -2.247217 0.816578 1.747864 -0.677923 0.700424 15.210928 50.059769 4.530343 -58.527804 23.204510 1.347983 1.806633 1.824363 0.576347 1.916667 1.663965 0.264207 0.523563 1.272596 1.523175 1.005921 1.511767 0.511862 0.362857 0.291835
+1 -0.001023 1 1 0.131968 -1.550767 0.481694 -0.055151 1.409873 1.849986 0.364795 0.288076 2.062867 1.555307 0.430345 -0.710861 -49.054602 -60.692448 -57.972351 58.694987 -63.351678 0.600158 1.604488 1.874141 2.445021 0.970140 0.889278 0.840833 1.130684 1.407409 1.574349 1.589310 1.031677 2.395572 2.377661 0.602243
+1 0.000284 1 1 1.993101 -2.332129 1.558294 -1.205428 -1.071799 1.736448 0.658564 -0.922423 0.592294 2.125783 -1.306649 -1.114990 48.980443 14.301664 68.060275 -10.962754 -51.002830 2.056478 2.481916 2.308829 2.492815 0.986354 1.147458 2.083148 0.716937 2.310320 0.548145 0.429777 2.270328 1.156837 2.218021 1.780472
+1 -0.007952 1 1 2.073345 -1.416091 2.036408 -0.167589 1.344582 -2.231065 -1.023218 -1.713515 -1.635201 -0.164615 -0.506391 -0.344164 -71.800822 -6.415658 22.036109 10.890647 39.098159 0.966486 2.473444 1.664973 1.447146 1.176429 0.746466 1.347014 1.264797 0.938066 1.829149 2.262372 2.432917 2.293875 0.901296 0.335512
+1 0.013014 1 1 1.443536 2.121973 0.640344 -0.836787 -2.110066 1.559193 -0.243778 -2.102686 -1.631615 -1.169331 -2.287164 -1.400445 35.207336 -20.307287 -54.575564 -1.503437 -68.271554 2.274913 1.721098 1.992846 1.769868 0.414054 1.253455 1.573118 1.136935 0.722178 0.402459 2.129496 1.193703 0.814371 1.887716 1.100263
+1 0.000190 1 1 -2.202240 -1.946988 -0.191330 -1.830451 -1.918838 1.676913 -0.912571 1.246823 -0.637998 -2.152834 -0.966498 -0.324178 -29.730934 -37.804216 24.544213 14.591640 -8.307365 1.796860 1.819773 2.174885 1.297806 2.220069 2.455833 0.433043 0.910902 2.024336 2.258462 1.973347 0.297648 2.314573 2.269894 0.602716
+1 0.024938 1 1 0.723333 -0.913497 -0.185538 1.256245 2.201404 2.031795 -2.296992 -1.656070 -2.196328 -1.548731 1.717566 -0.962525 15.144942 -8.955930 -72.317125 16.084121 25.818134 1.005668 1.759342 1.263710 0.672365 2.441918 0.563679 0.504801 0.936181 1.641458 2.231724 0.335919 2.034351 1.831266 1.835157 1.985631
+1 -0.040048 1 1 1.941207 1.997776 0.851957 -2.103771 -1.026228 -0.462299 0.872150 -2.012865 0.015301 -2.015754 -1.416058 -2.122620 -66.388520 58.137500 16.969916 63.374487 -14.998122 0.273448 0.590379 1.500581 1.508148 0.444622 2.006070 1.264661 0.908239 2.272810 2.365312 2.305501 0.548041 0.926099 0.953526 0.655477
+1 -0.011637 1 1 -1.186503 1.276286 -0.260807 -0.861153 -1.654636 -1.654210 0.781582 -2.088157 2.211130 0.567775 0.004271 1.095546 48.886127 -70.859775 59.758191 -44.085990 46.762249 0.371837 0.465106 2.034072 1.645229 0.367391 2.237868 2.343742 2.016587 0.281368 0.948712 0.754232 1.372904 2.139108 0.731473 1.365555
+1 0.030266 1 1 -1.133329 -0.384058 1.116926 -1.984552 -0.077382 0.057352 -2.117114 0.908400 -0.654091 0.702329 -0.488790 -1.392637 12.321399 -64.252373 -39.637132 -31.277845 63.258505 1.160421 1.697162 2.460360 2.272997 1.013597 2.268270 0.317480 0.394730 0.482242 2.046265 1.818358 0.891195 1.561506 1.733358 1.043553
+1 -0.005400 1 1 -1.106580 1.506751 -0.412967 0.618863 0.994497 -0.336318 -2.334789 -0.730958 -0.005480 2.138940 -1.653622 1.248740 -44.752429 -54.075252 7.247872 14.993152 -10.091299 2.058002 1.082291 0.306895 2.481533 0.372531 0.874490 2.058954 1.335404 1.882650 1.442790 2.214809 1.789383 2.155943 2.434734 1.321463
+1 0.014765 1 1 0.341599 1.568359 -1.690636 1.185647 -1.524549 -1.839990 -2.020602 1.925094 -0.201151 -1.957731 -1.679864 -1.559309 -54.431781 15.050860 59.803642 -30.187349 -58.772696 0.734490 0.316816 0.470817 1.279243 0.743127 1.485445 1.371201 0.533507 1.899867 0.567082 1.441701 1.924560 1.583879 2.001157 1.950478
+1 0.031946 1 1 -0.967116 -1.292473 1.515303 1.944200 0.460881 -1.145075 0.127004 -0.152685 2.080985 -0.240127 -2.012556 0.502565 64.095756 -42.622076 50.762299 -38.043537 52.270170 0.696287 1.745360 0.258526 1.798800 0.681268 1.314317 0.719122 0.779878 0.405457 0.773615 0.899046 0.762572 2.040236 1.749428 1.133286
+1 0.016729 1 1 0.804185 0.807897 1.924422 -2.083318 -1.274853 0.772093 -1.358774 -0.671630 -1.917968 2.168886 2.138734 -0.395461 -64.906324 69.416851 -10.981124 -59.755445 -59.771693 0.882283 0.279338 0.582623 1.652528 1.534113 0.332050 2.261949 2.083029 0.968031 1.454233 1.037422 2.204858 1.054906 1.307415 1.717250
+1 0.014903 1 1 1.596048 1.866912 2.109367 0.832995 -0.366000 -1.686500 0.005549 -0.980105 1.883781 -1.838596 -2.148168 2.072831 -19.758830 13.339759 -48.668393 -19.678269 17.336468 2.485353 1.577577 1.842285 0.278651 0.281624 0.761589 1.283144 1.047805 1.217307 1.522994 2.454365 0.507405 1.957501 1.715869 1.866598
+1 0.033764 1 1 -0.137640 0.467921 -0.631074 1.132698 -0.790660 0.309812 -0.175551 -0.538124 -1.181247 0.080268 1.312969 -1.051316 63.377475 35.222516 -65.180954 -46.296337 -52.528927 2.069859 2.368444 0.929753 1.610538 2.305366 0.534450 1.994902 0.309707 2.497759 0.836811 1.032918 0.755761 2.330889 1.998876 1.854470
+1 -0.000968 1 1 1.672540 0.979445 1.155334 -2.049393 -1.297219 1.870977 -0.255824 -1.938888 -0.722300 -0.584113 -1.285705 2.163151 -0.177647 14.295108 -42.123656 27.709983 -28.311619 0.874256 0.379062 0.391039 1.443091 0.523459 1.771243 1.023096 2.169341 0.369845 0.740543 0.801978 0.585797 0.996984 2.065603 0.590979
+1 0.025761 1 1 1.674026 -2.313688 0.484871 1.502703 2.234991 1.035596 -2.296567 0.778764 -2.332800 -0.292413 0.428095 -0.828351 -54.059524 -28.416114 10.364577 47.446104 26.671659 2.433520 1.168888 2.245506 2.468863 1.175570 2.048379 1.363039 0.591711 1.384488 1.086234 1.330333 2.163667 1.744804 2.170826 0.577233
+1 0.016942 1 1 1.890246 -1.559698 1.171271 1.898580 1.843564 0.824880 -0.097142 -2.174428 -1.037678 0.293793 -0.798631 -1.714443 51.524128 16.012010 13.854765 57.042042 55.606848 0.389372 0.426011 1.971792 1.165084 1.312682 2.497069 0.486893 1.465035 0.343726 0.503995 0.892616 0.690040 0.260343 0.833362 1.565748
+1 -0.032669 1 1 2.164666 1.891320 2.351096 1.496096 -0.413984 -2.344535 0.399660 1.926844 0.932457 -1.602612 0.909078 1.303904 66.873034 -14.925508 -53.011562 34.684290 38.862360 2.270326 1.110032 0.806279 0.882842 0.678336 1.541032 1.869263 1.458882 0.434956 1.552438 2.332664 0.341391 1.760034 1.640200 1.343924
+1 0.028362 1 1 -1.349134 1.112198 -1.339399 -0.203488 1.173845 -1.954061 -1.263339 1.090525 1.977637 1.673890 0.114704 0.467520 65.532786 -40.461021 71.627202 -61.619511 -39.116809 1.581805 0.904369 2.487607 1.204139 0.706969 1.279690 1.493945 2.479099 2.217710 1.060555 1.751696 1.012876 1.404776 2.325517 1.716946
+1 0.016729 1 1 1.309920 -0.448651 -0.647537 -2.247739 1.477791 -1.768252 2.029583 -1.783228 0.075336 -1.461807 1.802897 0.629207 15.200197 19.716742 29.278160 -71.967144 48.214598 2.016208 0.658674 1.837992 2.381285 0.760471 0.487948 1.188633 1.101640 1.505539 1.596032 1.509076 0.288441 0.583003 1.273284 1.839230
+1 -0.012253 1 1 0.119132 -0.515308 0.593069 0.999827 -0.287458 -1.107369 -2.325198 0.231053 0.306682 -0.956288 1.618447 1.328396 -30.191769 16.942929 59.806257 13.758497 -60.938493 1.476160 0.562152 1.840539 2.445151 0.896495 0.634520 0.879928 1.194707 1.937597 2.440144 2.244426 2.312428 2.220283 1.544491 1.514076
+1 -0.025546 1 1 -2.050548 -1.865307 1.308760 -1.102708 0.606475 0.128623 -1.223891 -0.353870 -0.466232 0.746105 0.114791 1.929184 -68.624260 -17.941636 -45.068540 33.053457 -70.545926 0.394323 0.378902 2.206708 0.639055 0.604223 2.426420 1.085788 0.593339 1.748631 1.236195 1.734573 1.225537 0.345185 0.281521 1.276260
+1 0.004598 1 1 0.626392 0.295878 1.256882 -1.227874 -1.329099 -1.437310 -1.169034 -2.001195 -1.768889 0.740866 1.607147 -0.086955 -19.256614 54.083701 -15.233315 23.672268 59.805988 1.513494 0.285033 1.794496 0.345570 2.250714 2.247908 2.343255 0.581682 1.582728 0.652201 1.036452 1.652386 1.408755 1.692584 2.007426
+1 0.030244 1 1 2.260143 -0.338925 0.972125 0.657567 1.180513 1.732337 2.241401 0.383436 -2.141317 -0.603550 1.910054 1.485122 -34.495871 -22.103611 54.607083 -68.752715 73.114490 1.903442 2.145082 2.146710 0.251027 1.755295 0.747053 2.223683 2.434798 2.392234 0.276746 2.014462 0.568905 0.591094 2.264353 1.978499
+1 -0.004652 1 1 -1.057772 1.864888 1.076266 -2.054240 2.066911 -1.164789 -1.343149 -1.962589 1.492337 -2.345614 1.113477 1.319578 52.192194 -5.798502 44.568254 -41.350446 -26.950178 2.100295 0.903797 1.860920 0.732629 0.542398 0.575957 2.110184 0.618482 1.322578 2.315420 0.765208 1.357023 0.731522 2.186696 1.792595
+1 0.022689 1 1 -1.917061 -1.448749 -0.212199 0.852769 2.109859 -0.329245 -1.283544 0.797623 -1.101838 1.105123 2.276750 0.736745 -53.511172 37.733580 -11.725384 31.478702 12.544132 0.313444 2.295732 0.618942 2.305258 0.964701 1.736091 1.988217 0.462335 0.462604 0.487709 1.676822 0.351246 0.895073 1.485770 2.340836
+1 0.009654 1 1 -2.239182 -0.787295 0.327957 -1.526498 -1.598303 -2.063216 1.992205 1.460063 1.875131 -1.134236 -1.492900 2.301849 -49.087593 -15.180927 4.159941 16.124122 -51.885790 2.207984 1.834702 1.090346 0.695883 1.701645 1.289608 1.698645 0.370326 2.066428 0.962113 0.989072 1.833089 0.971695 2.274606 1.058447
+1 0.013185 1 1 -0.285834 -2.088623 -0.892760 -0.365535 1.405034 0.631805 1.729357 -0.705136 0.432313 -0.612359 -0.063287 1.341308 -22.527909 -26.559100 21.210636 -62.839006 14.819535 2.453825 0.436152 1.407047 2.233211 0.583403 1.249098 0.336298 1.661059 0.920871 0.833634 1.635581 2.456321 1.885699 0.937245 1.533718
+1 -0.022401 1 1 2.278096 -0.197110 -0.021276 0.560602 1.965169 -0.544111 1.873661 -2.274894 2.176771 -1.991959 -2.043820 -1.885999 71.772825 -14.126793 20.988695 -42.995382 -73.384753 2.461743 0.764479 0.344818 0.857162 1.063283 0.344913 2.447672 0.514509 2.108713 0.641407 1.869949 1.729875 1.010014 0.562602 0.402303
+1 0.024878 1 1 0.055668 -2.161113 1.271511 -0.398451 -0.466791 0.767361 -0.779822 -1.317652 -2.269635 1.026670 -1.527733 1.199587 58.925087 53.932078 -13.558235 -23.257448 12.079102 2.327052 0.511622 0.831342 1.362176 1.842100 1.671484 0.635509 1.753612 1.697644 1.544962 0.433345 1.472299 0.925959 0.843083 0.694151
+1 0.003655 1 1 2.183416 1.294871 1.082058 1.044590 -1.937325 1.989964 1.494228 1.168361 0.111062 0.509498 0.717957 -1.729074 24.162485 48.877307 -69.095122 18.281865 63.308975 0.384078 1.453934 0.518076 1.305771 1.087681 0.913770 0.725934 0.527261 0.429660 0.294297 2.252820 1.652753 0.825226 2.065471 0.619034
+1 0.043456 1 1 0.984486 1.054279 0.691113 -0.509194 -0.324518 -1.932790 -1.906978 -1.616044 1.365409 -0.910267 2.269739 0.710052 65.795800 30.009299 66.281755 -52.550618 -18.229136 2.468561 0.607727 0.575387 1.537435 2.172523 2.100986 1.263734 1.080056 1.008378 2.306123 2.007473 2.347112 2.413392 0.379872 0.506750
+1 -0.039182 1 1 -1.176574 -1.493583 0.246636 -1.685346 0.560508 0.395223 -1.960493 -0.988433 -1.421083 -1.761665 -0.364505 -0.136354 -47.023362 28.362277 -15.205954 33.523507 29.585690 1.325309 0.964141 1.315997 1.969701 2.011453 1.746404 2.060715 1.681846 1.542848 0.891869 1.636507 2.273357 0.307436 0.325555 1.099295
+1 0.008947 1 1 1.268341 -1.849499 -1.605591 -2.032591 -1.649067 -2.308233 -2.087770 -0.701330 -1.562145 -2.253071 1.398763 -1.100870 -47.423137 59.337787 -59.819422 64.980261 -26.754549 1.919364 1.999716 2.473050 1.806402 2.451913 2.053578 0.992370 1.007278 1.815780 0.308224 2.319955 0.485876 2.370971 0.656646 1.505555
+1 -0.020602 1 1 0.517136 1.856671 -0.373710 0.668777 1.089464 -1.725887 -2.221185 0.080078 -1.876971 -1.512705 -0.700337 0.984683 -10.680778 38.168202 -57.027463 39.430513 8.625062 2.296294 1.058864 0.324760 1.241667 1.442401 2.431007 1.690409 1.458538 1.394673 1.273530 1.463177 0.616501 1.781997 1.773649 0.975691
+1 0.038694 1 1 0.609763 -1.162431 0.589987 1.047103 -2.113413 1.850368 2.084655 0.191372 -2.169694 -1.578864 -0.498900 -1.672892 -69.554276 -48.720928 -2.628900 66.076406 -53.852674 1.346678 2.374334 0.937036 0.262345 0.726957 1.968106 2.213028 1.108152 0.703782 1.706787 2.223072 1.167519 1.736996 1.438750 1.818107
+1 0.013031 1 1 -0.059943 0.996360 -2.009316 -1.585411 -2.150283 -0.502592 2.246970 -0.253327 2.339172 -0.991922 1.191640 0.243243 -69.172933 60.514345 64.600943 48.052536 18.978172 2.367123 1.237770 1.200746 2.190069 2.239375 0.682530 2.278506 1.356698 2.027542 2.152312 2.161605 0.850083 1.349222 2.376955 2.224098
+1 -0.072177 1 1 2.229805 -1.296529 -0.673565 -1.449021 -0.060981 -2.318071 2.218188 1.377745 -0.918581 -0.802001 -1.803140 -0.007610 -21.188655 -17.726624 -31.375582 70.586166 -8.312847 0.414774 2.101383 1.186420 2.165734 0.488929 1.936762 1.909610 2.314523 1.444492 1.568543 0.749226 0.492547 1.985724 1.309893 0.625468
+1 0.064639 1 1 -1.391426 1.887784 -0.532472 -0.437078 0.646654 1.537579 -0.653414 -2.060954 2.320616 -1.848144 2.307078 1.526025 -51.896984 17.384775 -14.087704 -72.043564 -36.175948 0.487532 0.950141 2.268904 1.966829 0.994595 2.399758 0.739423 2.231072 0.624991 0.467834 0.632465 2.342272 2.060045 1.668126 0.443730
+1 -0.037350 1 1 1.356251 0.678546 0.343035 2.133970 -0.351946 -1.109331 -2.308669 0.008442 0.512845 0.426634 -1.824547 -1.640629 -59.185204 74.280358 -20.015841 43.754470 -68.618665 0.266471 0.326640 1.340554 0.696651 1.113317 2.011549 1.101917 1.669881 0.691049 1.468886 2.062102 0.252429 0.576494 2.133751 0.709193
+1 -0.084604 1 1 -0.041322 -1.777095 -0.510101 -1.428824 0.096347 -1.749871 -0.064814 -0.774334 1.392864 -1.274854 0.754242 0.223225 21.674954 -59.050388 -59.863650 71.641100 21.972959 1.367728 0.662467 0.329719 1.344906 1.833995 0.461021 0.880310 0.862903 0.809017 1.902433 0.948725 0.972306 1.291832 0.825805 0.558749
+1 0.031185 1 1 0.987170 -0.951772 2.134090 1.654965 -2.238986 -2.218132 -0.436508 0.804971 -0.124324 -1.919568 -1.157924 0.936125 -38.425814 -72.658538 -22.050162 52.922443 -32.506970 0.705388 1.713426 1.292640 0.898444 1.890165 1.748110 1.482650 1.644860 0.913131 1.234771 0.291835 1.378307 0.697116 2.181261 0.449263
+1 -0.022009 1 1 0.004449 -0.621782 1.781966 2.262944 -0.391358 0.945665 -1.091809 0.001828 -2.260086 1.294693 -1.906216 1.754821 -49.851592 44.301645 -22.248945 11.979237 35.030890 1.587478 1.737413 1.692667 1.161823 0.507179 0.412443 1.187403 0.684431 0.478207 1.726533 1.090616 0.736290 1.330018 1.361339 1.268142
+1 0.039019 1 1 0.085320 1.414132 -1.978499 -2.008787 -2.131924 1.754704 1.184449 1.912191 -0.293251 0.487234 -1.197514 -0.007369 -42.479708 43.545173 13.730842 74.263219 -8.071623 0.478474 1.720205 0.491088 2.210839 0.320252 1.975619 2.478375 1.296740 2.305076 2.408426 2.414444 2.303847 1.999318 0.278722 1.485856
+1 0.065844 1 1 1.684662 2.086674 1.126259 -0.626102 -0.133350 1.876088 0.810770 -1.618794 2.254633 1.288016 -1.027122 -1.349413 36.256018 54.890728 48.458242 -62.334394 -54.166331 1.022031 2.277486 2.213909 2.419078 1.444037 0.687117 0.620079 1.165520 1.890611 0.255214 2.384032 1.931344 0.850897 1.531883 1.116596
+1 0.037947 1 1 1.275328 -2.226651 -2.237805 -1.216324 -0.419096 1.268215 0.749394 -1.155498 -0.706495 1.157349 -1.173995 -0.556864 -13.140533 -52.944350 -35.692398 -32.140212 -30.549689 1.395763 1.589787 2.301635 0.836674 0.975303 2.174505 1.657133 2.434165 0.768560 1.436595 1.610206 1.227505 1.921302 0.826168 2.152035
+1 -0.025244 1 1 -1.366773 1.536978 -1.322200 1.417454 2.016298 1.129592 -1.168473 -2.008805 2.278226 1.980080 0.309758 -1.093517 -13.461062 -40.070668 32.287458 -44.687784 -17.586583 2.459543 2.032031 1.100318 1.791650 2.011972 1.454482 0.731648 2.055133 2.375321 1.770289 0.741068 0.627228 2.074726 0.915352 0.328526
+1 0.010388 1 1 -1.286198 -1.399242 -2.247909 -1.379851 -1.497000 -0.643188 0.157466 -1.827793 0.354186 1.058348 -1.608505 0.838434 48.268314 45.557638 -62.780685 -54.972326 -69.878797 2.080971 2.377812 0.878901 1.933706 2.299496 0.880181 0.953682 1.032877 2.322290 1.484504 1.302792 0.532437 1.913115 0.482580 0.966804
+1 0.009328 1 1 -0.198407 1.739413 -1.355239 2.192834 -0.628384 -0.793469 0.232203 0.782826 -0.034543 -0.946760 1.540822 2.023628 57.519951 -12.189207 35.993470 -7.756353 -11.023283 1.100152 1.249268 0.947233 0.648168 0.763104 1.983346 1.848792 1.651102 2.330439 1.193645 2.094344 2.133872 0.482012 0.421807 1.056147
+1 0.006068 1 1 -2.177333 1.972830 0.989561 1.523956 1.298185 0.242833 0.358275 -0.909562 -0.021174 2.275342 0.635907 -0.007605 -18.474470 -0.421696 -37.449845 -19.548083 -44.634912 0.940461 1.577476 2.390677 1.115637 0.511374 1.164569 1.663577 0.496254 1.288611 0.675968 2.249632 2.061643 1.531689 2.338109 1.838787
+1 0.011338 1 1 1.337535 1.850706 -1.663636 -2.131250 -1.050217 1.608619 1.087191 -2.218565 1.702892 2.164051 0.987160 -1.117330 -3.039458 65.835465 -53.335481 -9.424648 -0.062585 1.346960 0.362283 1.894951 1.190210 0.605109 1.563401 2.077385 0.607288 2.192957 1.283018 1.178822 0.459820 0.948713 0.775134 1.677451
+1 0.023005 1 1 0.783928 -0.354399 0.068849 -2.106674 2.020240 1.408472 1.852598 1.866271 0.750872 0.125971 1.331833 0.272808 -2.469630 42.923614 67.172592 69.758271 27.256467 1.366586 1.706551 0.498963 1.817535 0.566268 1.260836 1.872841 0.839429 2.284674 1.513038 1.631067 0.836519 0.625215 1.993221 1.323585
+1 -0.001512 1 1 -0.098730 -0.589951 -0.434069 -0.614520 1.314781 1.131516 -1.807626 0.000087 1.463932 0.919828 -1.791384 -0.334525 -15.549267 -36.530623 -20.178944 2.495852 -52.217239 1.898046 1.464354 2.395970 2.326673 0.898156 1.553674 0.597904 1.978173 0.402897 0.495550 0.705299 2.453936 2.303481 0.349840 2.007258
+1 -0.019244 1 1 -1.623323 1.533600 -1.554696 0.423399 0.352091 -1.167260 -0.456476 -0.227547 2.069369 -2.254122 -2.136400 1.931279 2.219039 -54.611837 -11.137297 15.451702 46.762649 0.472668 0.882199 1.125240 2.164204 1.774094 1.698545 0.943055 2.420167 1.746612 1.064637 0.603247 1.773733 2.381144 0.641259 1.638530
+1 -0.026239 1 1 0.480907 0.849888 0.808431 1.484789 -1.964687 -0.793129 1.229383 -1.589767 0.038660 -0.543506 -2.093414 -1.319366 61.132068 -53.336742 -30.623935 -46.469329 39.994459 1.928098 0.295711 1.268990 1.658830 1.700522 0.424768 1.317580 1.561798 2.136112 2.141327 2.027684 2.275751 2.291429 0.292401 1.890867
+1 0.007784 1 1 0.134454 -2.176397 -1.138061 0.189989 -1.859494 0.041144 -1.221802 1.772233 -1.094961 -1.124483 2.209915 -1.011108 -26.183932 26.655339 -53.717292 23.474578 37.230488 0.367086 1.619082 1.908402 2.267040 2.143809 1.000070 2.171649 0.897458 1.083660 0.832662 1.052469 0.839729 0.576032 1.112155 0.488260
+1 -0.064876 1 1 -1.229859 -1.698380 -1.739098 1.924526 -0.330959 -1.809870 -0.022987 0.066103 -1.131001 1.035660 -1.233955 0.150847 0.826134 -65.167664 27.073329 71.444241 13.362832 1.961759 1.278570 0.673057 0.564252 1.138672 0.659380 2.451715 0.976278 0.550003 2.399501 0.913356 0.528102 1.066219 2.449500 1.994958
+1 -0.044364 1 1 -1.410346 -0.371934 2.240161 -1.601764 1.028811 1.476431 -1.070655 2.108293 1.632782 1.922894 0.509852 1.960652 -33.501744 36.187113 -53.197480 59.948448 3.566569 0.524839 2.472311 0.626064 0.501250 2.011029 1.363903 1.616908 1.377405 1.299658 1.848999 0.628981 2.276966 2.458919 0.560643 1.222449
+1 -0.062457 1 1 -0.987322 -1.593305 1.825805 -0.769385 -0.250586 1.268495 0.740315 1.763867 -0.329864 -2.257371 -0.196243 0.424042 55.675264 34.167860 59.219670 55.000884 -50.134281 0.522045 0.504598 2.026099 0.391021 1.147553 1.426387 1.041967 2.091477 1.196114 0.837791 1.753506 2.182255 1.414744 1.107521 1.356028
+1 0.003649 1 1 2.175628 -2.355949 1.777048 -0.283133 0.888089 1.980545 -1.299221 1.206427 -0.988946 -0.618174 1.169625 -2.201401 -63.326357 73.922648 -32.049178 -0.535978 -8.184084 1.376501 1.850815 1.905390 1.131955 0.271507 1.719604 1.640217 1.627821 0.290419 2.327693 2.293234 1.386941 1.820736 0.357825 1.217319
+1 0.014153 1 1 -2.030162 1.469089 -1.934318 0.689917 -1.748404 1.030591 -1.601803 0.372368 0.340315 -1.160802 -0.312452 -1.779264 23.023988 -35.839505 45.445171 -3.010867 -53.641115 0.681714 2.067212 0.636059 1.989600 1.204116 0.325146 0.978504 1.965992 0.429775 2.235691 1.753472 1.597766 1.409650 0.990849 2.446876
+1 0.000526 1 1 -0.117899 -2.330933 -1.896997 1.189711 0.805351 1.555595 0.549980 -2.188718 -0.869590 -2.074781 0.841923 -1.097916 33.320708 71.135353 71.879702 -17.851783 -34.912285 1.813483 2.209469 2.042794 1.992521 0.800427 1.526770 0.674151 0.960386 1.201796 1.837471 0.378268 0.549558 1.678901 1.537102 1.073742
+1 0.007971 1 1 -0.408843 -0.766882 -0.603814 2.184491 0.518503 1.274217 -2.050040 1.964288 -1.202416 -2.287056 0.404101 1.164675 -18.385835 -10.729832 -36.279536 -0.167377 36.898247 2.107494 0.403989 0.844455 1.253640 2.431710 2.255812 2.439226 0.326946 1.979168 1.382977 0.438947 1.139217 0.816355 1.485563 1.104030
+1 -0.014055 1 1 -0.700352 0.738503 -0.404988 -1.937126 0.613489 0.195849 -2.332955 1.822048 2.061717 1.082519 -0.633061 0.723770 54.757956 66.974489 40.243521 22.849463 30.916735 1.638365 1.999367 1.108192 1.386795 1.608212 1.466244 0.408519 0.483380 0.921160 1.187047 1.453369 2.268406 0.343909 1.330785 0.757691
+1 -0.044724 1 1 -1.649571 -1.358316 2.302586 1.433443 2.142666 -0.290290 -1.576764 1.809690 1.699083 -0.591461 -2.258904 2.312913 20.024826 -42.741545 -7.143997 -69.164179 57.646174 1.513737 2.129607 0.806999 1.732319 1.586121 1.429684 2.448740 0.481098 0.818988 0.738093 2.377999 1.772906 1.978190 0.691726 1.581852
+1 0.027756 1 1 0.477289 1.305632 -1.840332 1.668237 -0.648053 -1.489234 -2.053946 2.290956 -0.835547 -0.112437 -0.064167 0.687428 -37.287463 9.611751 -5.303029 -28.008543 -39.588119 2.012176 0.400523 1.082452 0.767957 0.302883 0.311744 0.738839 1.412761 1.516507 1.434751 2.109577 1.669087 0.843230 0.909088 0.785435
+1 0.018607 1 1 -0.011730 0.771496 -1.957191 -2.027664 1.052611 0.926450 1.113102 -0.282301 0.743866 0.192955 0.867011 1.149421 71.237771 -6.788252 59.849315 -12.568443 -37.820047 2.251991 1.208629 1.921158 0.646996 1.308738 1.458169 1.951859 1.394448 1.984055 0.254038 0.619830 1.484008 1.973473 2.415645 2.248298
+1 -0.009149 1 1 -2.110429 0.174321 -1.288746 -1.813728 1.121551 0.348102 -2.237972 0.686736 1.334213 -2.144533 1.896865 1.300715 10.796538 -42.593067 -61.681115 -24.493808 -67.434908 1.697400 1.957168 0.615451 2.128661 0.646229 1.920926 1.262061 2.200313 1.154482 0.883548 1.299085 1.224074 0.503473 1.123591 1.451467
+1 0.026799 1 1 -1.525367 -1.442986 -2.306464 -0.623414 -2.085629 2.292212 1.431903 -0.178550 0.907270 -0.811178 -0.533236 0.858935 66.252938 63.121173 -72.441256 29.804563 -74.712973 0.610861 1.490476 0.431226 1.861460 0.803635 1.449411 1.007047 2.445900 2.245619 2.112007 1.995757 1.186581 0.369400 2.257070 1.078946
+1 0.022102 1 1 -0.617242 -2.017057 0.249846 0.428340 -1.413509 -1.701828 1.580300 1.081071 -1.415863 1.147351 0.435048 -1.780034 61.466925 24.610088 71.752489 -55.915687 -24.949309 0.279350 0.779672 1.445189 2.037112 0.995746 1.509069 2.427943 1.933856 0.320642 1.772680 0.435246 1.928462 1.913122 0.597252 2.258475
+1 0.008680 1 1 0.154832 1.015897 1.202581 0.345971 -0.345306 2.111003 0.050824 1.259555 1.286683 0.130380 0.030944 1.719901 18.772079 52.335684 5.845139 -10.741720 63.908561 0.792680 1.819891 1.911623 2.395517 1.453418 0.844459 1.328603 2.333530 1.382490 1.254852 0.304738 2.224995 1.988072 0.274922 0.610016
+1 0.014650 1 1 -0.427538 0.767264 2.306377 -0.826115 -1.824181 -0.199809 1.743611 -1.474236 0.257161 0.836856 -1.445812 2.031462 48.513688 -30.443911 -20.809452 55.545699 -43.436036 1.683194 1.694452 1.904229 1.874462 1.079391 1.074551 0.727631 2.041294 1.519144 0.760501 0.985323 1.829492 1.264372 0.544736 1.619929
+1 0.013256 1 1 -0.984238 -1.608679 -2.096474 -0.906268 -1.209256 0.571443 0.387825 0.942533 -1.897699 -1.181608 -1.271743 1.211276 12.384697 -50.396390 37.865192 -49.719899 7.653656 0.400037 1.919999 1.418346 0.899140 2.346531 1.644334 1.071574 2.436861 1.069778 1.517833 1.223462 1.477777 0.749462 2.209947 1.074938
+1 -0.027374 1 1 -1.765154 2.251501 0.487179 -2.113119 2.079614 0.278376 -0.743964 -1.827922 -1.817435 0.077976 0.499905 -0.278722 -11.802681 -67.663768 -74.944476 -41.811122 30.475933 0.759999 1.546826 0.260555 2.155309 0.780719 1.042193 1.388418 1.892303 1.681939 0.853721 1.742376 1.861854 0.673705 2.456539 1.053018
+1 0.064749 1 1 -1.278989 1.954071 1.435167 -1.870167 -0.256691 2.336186 0.651337 0.149092 -1.206458 0.473388 1.717384 0.683291 -0.456337 -19.655411 -48.492500 -63.454331 23.054413 1.757733 1.211516 0.954217 1.021314 1.472755 1.840544 0.264954 1.832027 1.128389 1.080454 0.945697 1.834580 1.281076 2.288835 1.707071
+1 0.047986 1 1 -0.611592 -1.303831 -0.881190 0.875067 -0.108287 -1.002399 -0.536147 -0.936217 -0.328612 -0.057414 1.084671 -2.175285 -41.488078 59.875210 -27.347962 -37.190300 -7.369345 2.026297 1.466491 2.310077 0.972519 0.370260 0.954065 0.713400 1.365727 0.775176 2.381050 1.300714 1.595383 1.859164 0.473405 2.022195
+1 0.027717 1 1 -2.126532 -1.859084 2.223675 -0.651456 -2.136271 -0.619890 0.608741 0.508004 -0.831821 1.239941 1.508293 1.948449 38.007899 -51.243341 53.168910 59.867405 -8.519867 2.223940 2.252940 1.413193 2.035128 1.399538 2.029585 0.484696 0.540276 0.914262 2.255313 0.801427 0.326917 1.492482 0.389852 1.744184
+1 0.047935 1 1 1.390335 -1.375262 0.239769 0.702036 -0.698451 -0.309400 -2.322957 0.199544 -1.480718 -0.299745 -0.276464 -0.107217 -59.482021 35.681373 -3.172168 -64.621076 63.577128 0.486845 0.658228 1.093338 1.473639 0.953153 1.147878 2.391003 2.086205 0.340099 0.301040 0.821928 0.649875 2.453441 0.724584 0.336089
+1 0.013863 1 1 -2.171405 -2.059975 -0.069180 1.248646 1.728722 -1.958189 0.038835 -2.328105 -1.493472 2.113621 1.641183 1.750953 -19.372936 49.059399 -8.673252 28.649811 17.379056 1.971938 1.363397 2.114525 1.565505 1.434350 2.123956 0.322286 2.412479 0.793413 0.635558 0.320614 1.308886 1.690152 1.629266 2.076980
+1 -0.004412 1 1 1.078896 -0.268154 -1.819305 1.640257 0.332790 -0.401183 0.749787 0.748029 -0.529008 1.234290 0.770173 -0.633910 18.749264 -31.115712 -61.777377 7.618399 -57.575002 1.179026 1.646757 1.288185 0.280067 1.580248 1.721989 1.214810 2.314537 1.668394 0.450239 1.922987 2.149509 2.290427 1.458515 1.013132
+1 0.013293 1 1 2.348506 0.367634 0.881833 0.498217 -0.378558 -0.706111 -1.806265 -0.678700 1.782344 -0.805780 0.656718 1.045696 -70.193020 15.912536 -8.015018 -8.414880 21.119013 2.083674 0.568021 1.472603 1.530781 0.582124 2.254902 0.638391 0.682881 1.433584 0.498999 2.426994 1.742675 2.386289 1.605239 1.006125
+1 -0.020206 1 1 -1.436001 1.984811 -0.280369 0.231326 0.171876 0.020066 -2.050712 0.089387 -0.929779 -0.521937 2.273180 1.991699 -74.243549 38.672722 22.438224 19.226207 34.867691 0.944227 1.874762 1.619269 0.563026 0.775418 1.953559 0.725307 1.241828 1.895187 0.651147 1.326995 2.300372 2.097126 1.655293 0.765597
+1 0.009879 1 1 -1.702178 0.411366 0.760630 -0.800990 1.056696 -1.100322 -1.702399 1.408632 -0.163060 2.069229 0.096599 -2.241315 33.453504 53.039381 -17.118990 -18.861775 -59.848192 1.846614 1.045636 0.748118 2.125293 0.302587 2.075733 2.092075 2.257505 1.628437 1.632291 1.169590 0.555556 1.227704 0.773802 1.787328
+1 -0.010612 1 1 1.062344 -0.419257 -1.424201 -2.328493 1.411169 0.068312 -1.701340 0.345847 2.279440 -1.171166 -0.134198 1.774536 -2.464661 -23.561200 6.909868 34.151414 -67.185778 1.504442 1.158710 2.195457 0.548441 0.895468 1.379225 0.382874 1.471024 2.002799 0.297910 2.217680 0.547965 1.901378 1.203397 1.749723
+1 0.013998 1 1 1.609662 -0.236563 1.348362 0.049348 0.009029 0.945777 0.792804 -1.972785 -0.224503 1.397147 0.006221 0.880302 -52.868307 42.356441 -15.298207 -16.973377 28.454850 1.984856 2.478082 0.871075 0.913312 2.036908 2.062878 2.036363 1.898876 1.914466 0.676446 1.283220 2.325803 2.015999 1.649575 1.404345
+1 -0.066234 1 1 0.398400 -0.394120 1.652033 0.331976 0.045169 0.452430 -1.800852 0.762081 0.029942 -0.984113 0.490950 0.006566 62.801470 -45.690247 -65.986534 64.316505 67.501924 2.197661 1.585689 0.917561 1.443202 2.402410 0.297651 2.371046 1.913688 1.111820 1.602517 2.499916 1.087591 1.638449 1.168714 1.577992
+1 0.066779 1 1 -1.056708 0.908062 -1.626855 -1.269827 0.431017 1.155890 -2.142898 1.093451 -0.682318 2.234806 -2.073168 -0.332623 -47.783947 -4.793342 -11.704203 -62.533414 50.914276 0.868500 0.380317 1.229903 1.733181 0.324198 0.788872 0.826121 1.372188 1.369295 2.246834 2.283477 1.650964 2.243470 1.997030 2.333926
+1 0.017029 1 1 -1.076766 -1.630672 0.551439 -1.233792 -1.826344 1.142705 -2.247532 0.236669 0.437890 -1.134643 1.086931 -1.879587 52.105690 40.336403 -66.069272 23.752260 54.225569 0.912002 0.269293 0.499237 1.929842 0.349416 1.639760 0.696437 2.022686 1.532993 1.769667 1.545794 0.908074 1.754887 0.639047 0.454720
+1 0.008753 1 1 0.759489 -1.128209 0.839870 2.097716 -1.777069 -0.083315 -0.697063 -0.540822 0.603150 0.795061 -1.737055 -1.433161 -67.204337 -3.290472 47.034247 4.581061 43.888248 0.321762 0.353658 0.935186 0.671662 1.878980 0.517394 1.088205 0.705334 0.793338 1.631421 2.297753 0.834030 1.549762 2.343307 1.462166
+1 -0.005297 1 1 -1.506457 0.644831 -0.826781 1.123691 -1.375761 1.278495 -0.831109 -0.931108 0.707076 -0.814886 -1.580352 -1.946887 47.901166 24.897101 -54.422555 20.110410 45.654339 2.312176 2.485503 1.848283 2.085783 2.257415 2.378139 1.884264 1.579438 1.607229 0.697019 0.540441 1.440250 2.281270 0.553492 0.288097
+1 0.006331 1 1 0.244856 1.375480 -1.287008 -0.879646 -1.442344 -0.949702 -0.775346 -1.490650 -2.289805 1.326259 0.833559 -0.314010 9.900539 48.352133 -45.702939 20.701076 72.977990 1.241235 0.929626 1.724948 1.457577 1.004577 1.424753 0.580867 1.385627 2.225340 1.038762 2.216204 0.495681 0.653489 2.439607 2.231424
+1 -0.021236 1 1 2.093729 1.889538 0.680761 -0.128685 0.181452 0.751682 -0.402883 0.450942 1.459310 -1.370302 -1.218540 0.039530 -1.868106 -47.259022 -32.387112 19.815022 31.080350 2.386708 1.901437 2.199857 2.489563 0.338437 1.609082 0.335722 0.971402 1.846318 0.568640 0.632887 0.427368 2.279468 1.771131 1.393071
+1 -0.046207 1 1 0.703045 2.110453 0.229856 -0.960853 0.299759 0.512686 -2.251178 0.229189 1.961386 1.862823 -0.639021 -0.485756 -71.512953 31.806686 -25.022726 43.045005 7.402576 2.351466 1.336325 1.612783 1.801812 1.800522 0.368558 1.598922 0.576755 2.020165 1.917162 0.994517 1.098200 2.196219 2.104668 2.408789
+1 -0.069110 1 1 -0.974785 1.765422 2.252394 1.372745 -0.139655 -0.410907 2.242907 2.138050 2.245119 1.625282 -1.599697 -1.930340 49.927465 30.906222 -9.126146 66.865118 2.041867 0.889984 1.456264 1.433799 1.857803 2.336294 0.590483 0.995982 0.973740 0.643354 0.844566 0.866496 0.450658 2.201417 1.719577 1.183096
+1 -0.050484 1 1 -1.722702 -0.536572 1.354653 2.094035 2.331402 0.360527 -0.759212 1.079336 -2.299603 1.586340 -1.088622 1.740362 14.867130 -28.140438 -6.341079 -74.518808 62.388066 2.218346 0.496249 1.213049 1.961508 1.569147 1.909282 1.297203 1.091904 2.134779 2.229650 1.470641 2.313454 1.478501 1.670908 2.206347
+1 0.013569 1 1 1.000965 -0.007041 -0.520400 -0.165976 0.178407 1.413983 0.241184 0.931626 -1.436925 0.599620 -1.982475 1.848642 42.937421 -0.763428 69.060287 -3.752201 -63.241716 1.322228 0.937883 1.004384 0.432700 1.880973 0.269921 2.054816 1.542582 0.920666 1.881025 1.141688 1.851731 1.536013 0.770886 2.274450
+1 -0.001223 1 1 -0.168154 1.265485 1.990461 0.432525 -1.766037 1.558970 0.722803 -0.384797 -1.888670 -0.229911 0.047977 0.532768 22.240462 -4.552597 -15.494383 -14.099872 23.453408 1.096298 1.731498 1.280934 2.150200 0.413748 0.607269 1.873982 2.013155 1.100508 0.485718 1.970802 0.265056 1.303550 2.022189 2.177348
+1 -0.043846 1 1 -1.593482 -1.143586 1.577683 -0.492360 -0.136135 2.207820 1.476558 1.068842 0.405368 -1.098774 0.758005 2.207299 68.613214 -17.717061 -20.649350 46.372368 -19.613588 2.191287 2.466949 0.516371 1.892147 1.317799 0.746339 1.469472 0.670739 2.109366 0.365999 1.351444 1.465568 0.306030 1.449785 0.532485
+1 0.040798 1 1 -1.908457 1.789834 -2.153355 -0.289684 -0.822082 -0.012272 1.083521 2.067561 0.344365 0.927750 -0.608013 2.293494 -18.892214 28.563181 61.382059 -51.735144 37.439411 1.287722 1.490280 1.632611 2.037971 1.928266 0.864384 0.952043 0.482322 1.139522 1.444897 1.632755 2.215611 1.773041 2.001361 0.875176
+1 0.005070 1 1 1.674220 0.941531 0.106913 1.467609 1.464958 -0.685954 -2.321718 2.187584 0.666659 -1.523910 -0.518745 -0.621640 -16.972349 45.735473 -73.906700 0.090194 15.896310 1.664215 2.215159 0.930567 1.785785 2.445838 1.193179 1.015253 0.853463 1.898066 1.794300 1.548928 1.824748 0.285080 0.338061 2.034021
+1 0.022739 1 1 -0.960084 -0.912239 2.108392 -1.429335 0.932671 1.997775 0.824038 -0.096791 -0.994319 -1.396058 -0.564180 -0.844683 58.570878 -49.252049 70.818591 -1.943419 36.950581 1.801127 1.537823 1.940670 2.341498 0.311594 0.455191 1.888645 0.955441 1.345581 1.923084 1.519039 1.233772 1.506850 1.131556 0.314060
+1 -0.008805 1 1 -2.056751 2.276007 -2.314878 -0.676484 1.332273 -1.756060 -0.405826 -1.887577 -0.697327 -0.268561 0.764067 0.416447 42.502964 47.309186 -24.514521 34.450926 16.714972 1.053127 0.655344 2.124887 2.476647 1.499972 0.287006 1.204645 2.461448 0.310833 1.172577 1.257715 1.172833 1.051363 0.263399 0.453989
+1 -0.000912 1 1 0.934964 -1.882963 1.441813 1.440783 -1.722030 1.336080 0.969837 -0.104269 0.567607 1.895345 -0.684405 0.141231 -43.528557 -34.460943 -35.061349 73.904573 -35.844180 0.878085 1.725476 1.325901 1.911722 1.817012 0.774792 0.423233 0.269241 1.881150 0.988572 2.429388 1.469765 1.086806 1.952917 1.176491
+1 -0.031546 1 1 -1.021576 2.321077 1.177595 -0.192932 -0.476406 -0.599418 0.664677 -1.843476 0.654155 0.379498 -2.348353 2.198059 -74.673442 13.458625 -0.890984 25.236958 -42.447520 1.142892 1.832950 0.889128 0.567997 1.076023 0.715096 0.610336 1.670755 1.873745 0.278252 0.327030 1.146350 1.449694 1.250579 0.473143
+1 -0.006182 1 1 -2.016281 -0.847453 -2.299471 -0.909508 0.895612 1.174234 -0.131745 0.581346 1.907690 -0.543610 0.873697 0.418514 -52.126469 60.431826 27.694743 15.538359 3.195184 1.396802 1.050548 2.310241 1.466880 2.102014 0.555023 1.269397 1.760937 1.072877 1.846232 1.367156 2.286044 2.047610 1.932014 0.859705
+1 0.001188 1 1 -1.463883 -0.104613 -0.511706 -0.136517 0.500351 -2.212216 0.039494 -0.671243 -0.123386 -0.304941 1.941782 2.243833 -36.521658 -19.508813 15.378069 9.203531 33.749492 0.290570 0.366043 2.088676 1.377905 0.693973 1.104237 2.407098 0.346325 1.432408 0.981944 1.284134 1.947111 0.342077 2.043283 1.203435
+1 -0.020783 1 1 -1.329542 0.537674 -1.673513 1.520552 0.624778 1.443539 2.173569 0.741027 -0.403974 0.960218 -1.544551 1.282573 55.382152 57.824902 13.129797 22.501537 33.333417 1.145995 2.241559 1.380728 0.886310 0.464710 2.135387 1.203064 0.639461 0.672521 0.555530 0.792261 1.524345 0.418412 2.494008 0.792519
+1 -0.001846 1 1 -0.246222 -0.768537 -0.141696 -1.726221 1.583903 0.367861 -0.017293 1.525835 -0.111446 -2.252999 -2.109059 -0.367158 -73.608905 55.131599 46.791746 -21.122040 51.876978 0.570529 0.874516 2.483567 0.819446 1.682701 2.411710 1.351699 1.255818 0.776312 1.230799 1.038490 2.147657 0.423190 1.802823 0.793561
+1 -0.005289 1 1 -1.762830 -1.087309 0.239094 -1.213582 -1.451787 0.568491 -2.102016 0.201758 -1.967632 1.547954 -0.630815 0.769563 -46.656144 50.186204 29.528124 -70.828084 -7.605336 1.031852 0.830695 1.744349 1.266226 2.464695 0.879931 1.243890 0.553942 1.102890 2.266517 2.354939 1.214550 2.434621 1.669673 1.699049
+1 -0.024739 1 1 -1.955269 1.996374 0.840039 0.218186 0.810245 -1.023893 1.071417 1.270021 -1.875279 -1.353712 -0.428107 0.622519 37.200180 23.420639 30.677483 46.461096 -28.354493 1.315473 2.157146 2.409702 1.358770 0.842968 1.010382 2.247369 2.277654 0.534396 1.086013 2.129063 0.668285 1.359016 0.474487 2.197014
+1 -0.005185 1 1 1.322656 1.535446 1.199200 0.069993 -1.730735 1.112775 -1.060887 1.346817 2.347508 -2.272577 -1.288651 -0.210073 -35.384324 45.673381 -67.481430 -10.387935 9.970300 1.687566 0.920829 2.370262 2.249076 1.720104 1.040836 1.086747 0.958624 0.839734 0.660732 0.429867 1.526859 2.174713 0.647813 1.543629
+1 0.005815 1 1 -1.193783 1.448940 -1.300736 -0.689441 0.327887 2.014370 1.710546 -1.135156 1.891169 -0.195382 0.750973 1.824041 -68.180180 -54.279590 22.936473 -6.704647 -34.998870 2.484869 2.434759 1.738100 1.999759 0.954929 1.746892 1.255815 0.741340 0.704193 1.866108 2.419543 0.252790 2.133699 2.074694 0.375996
+1 -0.014113 1 1 -0.284698 -1.844865 0.879086 1.455855 1.831963 -0.949943 -0.114693 -0.272051 -1.350609 -0.103919 1.735029 0.363584 -38.330060 36.682860 28.825279 -33.531133 -7.756965 1.055305 1.260547 1.517808 0.793319 1.312287 0.364250 1.204709 1.287995 1.576859 1.018165 0.303299 0.554216 1.208540 0.426777 1.341537
+1 -0.016731 1 1 1.892264 -0.635248 1.653661 -0.596907 0.458125 -0.334739 0.631990 0.132888 -0.226503 0.768076 1.814736 1.693586 40.567572 69.188916 58.111301 26.632163 6.761962 0.599460 1.129949 0.297173 1.090539 1.692533 1.147104 0.634540 1.211459 2.234066 1.445749 2.453720 0.914178 0.837780 1.565509 1.513046
+1 -0.018987 1 1 -1.680459 -2.119444 -0.539162 0.231095 1.007861 -1.915598 -0.415488 0.651264 -1.086492 -0.164918 -0.890868 -1.565831 56.551672 63.944608 -32.965274 52.645821 -31.682582 1.537667 1.562882 2.365098 0.951909 0.492908 1.311436 1.804820 0.609957 2.046600 0.698343 0.296011 1.811686 1.250908 1.516225 1.201081
+1 0.000296 1 1 0.990149 1.992663 -0.259927 -0.201520 1.258997 1.330104 -0.508772 2.056322 -0.049163 -1.622316 -0.378699 1.635132 -31.616482 71.790123 -23.408481 23.667062 -27.697125 0.541235 1.288757 0.883509 0.634527 0.988753 0.977651 1.129602 1.220228 1.122862 0.439913 1.625671 2.408379 1.630599 1.985328 1.414977
+1 -0.001701 1 1 1.468564 -1.343547 0.768528 -0.012429 -1.555565 -0.050687 1.051033 -2.029228 -1.669279 1.998988 -2.344652 -1.565096 -0.554809 -24.668369 -1.284430 12.581043 -50.405444 1.910456 0.790979 2.475613 2.132312 1.269044 0.316450 1.072044 1.346180 0.744054 1.311937 1.223471 1.631947 2.129466 0.690287 2.159225
+1 0.008206 1 1 0.027354 -2.068098 0.064730 -0.637762 1.817062 -1.630693 0.205902 1.699496 1.631307 0.704048 0.126346 -1.783140 49.787074 71.353329 -14.605848 69.509577 47.461090 1.053069 1.926724 1.942551 2.453751 1.449501 0.272489 2.469547 1.432070 2.048339 0.681047 2.105968 1.747810 0.949075 2.360073 2.005430
+1 -0.010520 1 1 0.151535 2.154928 -1.547944 0.805741 -1.317476 0.693118 0.202638 -1.328173 -0.020697 0.863861 0.037051 0.682194 12.637580 -0.195387 16.131570 73.300117 5.068722 1.225262 2.475149 1.071922 1.548179 0.501421 0.389028 1.386275 1.867644 1.249068 2.078639 1.429547 2.392746 2.128164 1.305534 1.613960
+1 0.015564 1 1 1.446610 1.963538 0.322664 -0.940895 1.154217 -1.984679 -2.211126 -0.502164 0.022708 -0.050017 -1.825216 1.250262 19.500681 -2.058173 58.287447 -12.876572 33.458892 1.278869 1.198654 0.779148 1.645648 0.649818 1.490862 2.411829 1.115203 2.212764 1.179863 2.202877 1.498001 0.910702 0.923931 0.516545
+1 -0.002597 1 1 -1.590282 0.796538 -0.475649 -2.017544 1.484262 -1.389886 -0.506524 2.130772 -2.269795 -1.653354 1.033681 -1.495655 -50.445385 -35.594076 -29.637171 38.073584 2.722002 1.355225 2.022116 0.954046 0.395781 2.384786 1.105484 0.868083 2.374726 0.769985 0.635743 1.186884 0.966333 2.156021 1.489532 0.321312
+1 -0.018381 1 1 1.479572 -0.116799 2.017527 -1.765700 -2.214438 0.392420 -1.938303 -0.306886 2.230382 -1.021742 -0.467783 -1.765121 -60.629263 -46.015828 11.976129 -17.205429 28.351996 0.804976 1.476060 1.137082 0.939281 1.993647 1.717409 0.745464 0.264237 1.032543 1.201110 1.559699 0.608600 1.746285 2.303586 2.112428
+1 0.022748 1 1 -1.955579 1.499889 2.067577 0.606109 -1.316844 1.894132 -2.230465 -0.362214 0.677484 1.342348 -2.082901 1.018763 71.503827 -35.178088 61.872931 -51.642731 -59.375347 1.803138 1.587155 0.813475 0.316084 1.671862 2.486314 1.986023 1.831405 1.927638 1.567733 0.641035 2.367844 2.103395 1.253872 1.831402
+1 -0.036872 1 1 -0.374580 0.187094 1.332321 -0.960650 -0.992627 -1.227919 -2.076195 0.631549 2.143721 -1.415551 1.690342 -1.409102 53.738493 32.846710 54.649431 42.984740 44.529128 2.140824 0.325803 0.777197 0.347265 1.486659 1.531155 2.380858 0.333524 2.291043 0.551567 1.684350 0.877528 1.369286 2.096309 1.417198
+1 -0.019735 1 1 -0.722196 1.160722 -1.037094 0.691910 -1.241446 1.476404 -1.516066 -0.633692 -0.466475 1.368513 -0.573650 0.216629 -57.176247 -61.190730 -32.601474 17.032806 70.378092 0.543907 1.193220 1.689461 1.274876 1.585250 0.303902 1.682170 2.478073 0.728827 1.898244 0.282374 2.117405 0.475439 2.456185 1.855044
+1 0.011810 1 1 1.041888 -0.229751 -1.975647 -1.206542 -0.948703 1.879617 -1.133893 -0.440510 -0.485110 -0.803693 -1.962170 -0.899697 26.998607 15.594898 53.456895 -49.962658 -22.400123 1.692021 1.553786 2.485079 1.467912 1.453140 0.666523 1.002448 1.637275 1.683550 0.918734 0.919421 1.213975 1.783545 0.793531 0.379392
+1 0.014541 1 1 0.723608 -0.998108 0.898869 -0.627657 2.012454 -2.208491 1.377452 -1.131119 -0.943738 0.495070 -1.440254 1.191892 -7.812450 -53.856205 -61.238593 62.959684 63.402059 1.351188 1.670934 0.391702 1.340889 1.817743 1.808321 0.955181 1.478255 2.035780 1.097910 1.826605 2.253659 2.243687 1.148008 2.317481
+1 0.009130 1 1 -1.932349 0.789637 1.335138 -0.740201 0.150030 0.433433 -0.652105 1.091342 1.569384 1.398858 0.497289 -1.833971 6.151788 43.105574 -24.614922 -2.991376 -26.055907 0.300462 2.363147 1.912737 0.866842 1.760293 1.490392 1.262125 1.035100 1.429799 2.131541 1.803258 1.359358 1.724673 1.324950 1.683561
+1 -0.017614 1 1 0.179051 -1.912250 -0.685383 -2.161114 1.257718 -1.317993 1.435174 -1.754471 -1.981231 -0.802757 -0.359640 1.519566 -57.157618 -48.087436 -5.541461 14.673605 19.285848 1.183707 1.568221 2.084339 0.489415 1.103318 0.467906 1.844357 1.357037 0.966272 1.129766 1.735333 0.495524 0.272778 0.583843 1.903152
+1 -0.002101 1 1 2.327037 -2.322133 -0.086818 1.695555 1.381526 1.374261 1.777014 -0.845051 0.370951 0.082918 -1.268166 0.067776 -40.803561 14.557018 9.806385 -34.078686 -60.470740 2.399121 1.281611 2.293930 1.835718 2.408190 0.698488 0.483354 0.480434 0.899584 0.800860 2.053527 2.372469 1.082126 2.034218 1.846061
+1 -0.004749 1 1 -1.664475 -2.091769 -1.936052 -0.176451 -1.524780 -1.010938 2.032690 -1.405599 -0.705333 1.842829 -2.097218 0.722337 38.343529 39.687436 -23.264137 49.650569 27.105226 1.487894 2.036252 2.294667 0.711890 0.735821 2.446602 0.544258 0.338753 2.421429 0.463637 2.101777 1.068939 0.916598 1.014066 1.160262
+1 -0.037921 1 1 -2.067365 -1.763917 -0.511463 -0.758667 0.815404 0.863338 0.672042 -0.587843 1.995306 1.750211 1.058490 0.776362 -9.381945 -32.348523 68.377243 66.315318 61.551382 0.536210 2.324087 2.429082 0.837103 1.434969 1.265134 2.102248 2.238331 1.130007 1.272220 1.942991 0.842697 0.959128 0.307621 1.186948
+1 -0.055044 1 1 1.901949 1.915481 -1.552919 2.012043 0.298316 -0.187762 1.583612 0.200686 -1.141660 0.970912 -0.885947 1.035716 -9.249386 -54.435943 -54.893402 56.591007 -24.951806 1.899975 2.372478 1.243092 0.654791 1.819624 1.913443 1.479280 1.250204 0.921749 2.090394 1.002805 0.892215 0.715143 1.403196 0.520805
+1 0.000053 1 1 -1.035743 -0.163020 -1.980853 0.829844 -1.485561 -1.592352 -1.000698 -0.212333 -1.406776 -1.632383 0.068152 0.323464 -52.245975 1.900985 -0.141393 23.609651 57.411331 0.808666 0.504875 2.181354 2.020667 1.349584 1.707245 0.918631 1.433071 0.871836 2.442368 1.383913 0.422867 0.874095 2.165851 2.462566
+1 -0.042772 1 1 -2.114036 0.816572 1.654187 -1.177351 -0.418855 0.612946 0.494559 -0.594378 0.548944 -0.761918 -2.002191 0.338731 15.666039 49.118719 -61.685768 47.290240 -42.935832 1.786958 1.903866 0.278041 1.285477 2.008379 1.829518 1.706806 0.290321 0.683299 1.704336 1.530498 0.320842 0.649956 1.562159 1.454024
+1 0.013340 1 1 0.302773 -0.680554 -1.095103 1.189468 1.430304 1.225801 -0.518074 1.219184 1.357542 -1.173312 1.498238 -2.129180 24.010799 49.494654 -43.356905 0.495685 -69.019126 0.558286 2.105769 0.663484 1.668659 0.407619 1.099851 0.693277 0.655337 1.997924 1.604879 1.692633 0.585241 0.638136 0.896048 2.129547
+1 -0.026736 1 1 -0.403315 -2.100694 -1.138230 2.076084 2.215220 -1.385088 0.024344 -0.827614 1.264411 -1.925939 0.137181 1.243918 -74.288127 39.449697 31.056606 -31.630716 -17.451420 0.534760 0.460521 1.479215 2.413056 1.487790 0.277397 1.715617 2.127609 0.977748 0.517886 0.360998 0.540450 1.598716 1.625520 2.111154
+1 -0.000959 1 1 -1.371003 1.133927 1.002759 1.868574 1.760953 -2.178789 1.071861 -0.693641 0.429809 -0.300512 0.974481 -2.155763 52.240939 63.469745 -64.000025 1.579591 -1.815366 0.462234 1.010363 1.920135 1.452541 1.853565 0.871360 1.198524 0.851526 0.841284 1.952661 1.375517 1.073349 0.778020 0.686421 2.423028
+1 0.037674 1 1 1.110409 1.586479 1.262904 1.030544 2.330075 1.624872 0.927321 1.606586 -0.091183 -0.993522 -2.128679 -0.249441 52.969663 11.125614 -61.811003 42.478622 -61.795484 1.424515 1.070289 1.102435 1.372712 1.165896 1.458804 1.369662 1.660416 1.368920 0.444208 1.797690 2.273565 1.561006 2.327755 1.077941
+1 0.026311 1 1 -0.565412 2.012327 0.359126 -0.736204 1.357461 2.167514 -2.077539 1.610915 1.980692 1.174197 -0.764474 2.172751 35.987532 42.446873 4.601877 -56.248393 -66.741836 0.924542 1.769859 0.277599 0.609235 1.155424 0.957223 2.042202 1.044306 0.894851 2.267648 1.111711 2.033402 1.645667 0.970132 0.753686
+1 0.020467 1 1 1.591341 -1.851541 1.761131 0.816309 1.937881 -2.068643 0.322430 -0.171627 -0.554587 0.168777 -0.226525 0.397017 -2.488122 32.136534 -31.279020 43.512575 65.855254 1.063744 1.346118 1.946897 1.253190 1.614770 1.432271 0.922251 1.529595 0.910142 0.505757 1.257671 0.429983 1.227780 2.039737 2.353404
+1 -0.007936 1 1 1.101727 1.743637 -1.032550 1.654623 1.446350 2.295730 -0.699673 -1.985612 0.958332 -0.258618 -1.771571 -1.920071 -6.321719 -49.132419 -18.570320 38.636805 18.773927 0.375961 2.268934 2.476619 1.037270 1.891433 0.562391 1.356999 0.328990 0.336522 0.932960 1.511907 0.618554 0.284699 0.677665 1.522891
+1 0.031490 1 1 1.666229 -1.413103 0.414355 -0.848699 0.311137 -1.466635 0.768199 -0.831327 0.127453 -2.027095 1.188468 -1.237383 -29.417977 -27.931141 61.321153 -25.377285 -66.022986 2.150054 2.459958 2.261859 0.570722 1.875269 1.137713 0.290468 0.892847 2.328674 0.770373 0.410564 1.096246 0.856631 1.145055 2.187061
+1 -0.030709 1 1 1.250179 -0.785486 -2.260683 0.690006 -0.253031 -2.121253 2.042729 -2.321945 -1.636965 -1.541710 1.907126 -0.606774 -14.165355 -27.115682 -33.269743 35.422413 -5.502594 2.393499 1.291985 1.140146 0.691185 1.498097 0.259841 1.395569 0.585213 2.424165 1.441354 0.579231 0.883937 1.081636 0.559885 1.992928
+1 0.004088 1 1 -0.269967 0.700811 2.264333 -0.610461 -1.153419 1.257553 0.636812 1.056206 0.083641 1.457098 -0.832639 1.627283 -30.523853 -14.389655 -46.927097 -3.715885 -52.876482 2.199474 0.556117 1.665636 1.349822 1.201640 1.464561 1.382794 1.870891 1.820313 2.257074 1.139434 2.222264 1.087925 0.501371 1.788268
+1 -0.048395 1 1 -1.568382 1.307886 -1.652953 -1.642335 -2.264826 1.745446 1.098206 -0.878114 0.741785 -1.798349 0.414792 1.782783 59.482742 -23.557935 61.782891 -64.954578 8.409728 2.009491 0.272685 1.273604 0.457206 2.008309 0.642579 1.317394 0.692763 1.012941 0.257878 2.149258 0.331392 2.455861 0.898546 1.364118
+1 0.005866 1 1 1.489814 -2.336374 0.890438 -0.960136 -1.780932 0.972414 0.796049 0.719637 -1.769828 -0.894451 -0.515677 -0.897909 -66.569372 18.570948 -28.077076 8.586725 17.083602 1.736423 0.816307 0.672963 1.232794 0.810897 2.003135 1.436858 1.516148 2.155140 2.437992 2.077748 2.211968 1.292122 1.201706 0.317487
+1 0.054004 1 1 -2.194063 -1.172522 0.638193 0.715838 0.358435 1.778723 -0.393850 1.462644 -1.876899 -0.305889 0.145554 0.595218 -18.238258 69.599592 60.346791 -51.479722 -19.685133 2.154525 1.105981 2.473464 2.012352 1.100526 0.785359 0.276559 1.120422 2.182501 1.048640 1.748756 1.092817 1.728123 0.821211 2.086533
+1 0.036134 1 1 -0.694046 -1.673650 -0.790664 0.254528 -1.000900 1.100006 1.096968 1.879981 0.277090 1.211198 -0.922187 -0.143707 69.121394 -26.738460 6.699814 -46.234147 -57.309486 0.617024 1.564210 2.186281 1.570392 0.329765 2.117551 0.671939 2.024145 1.311946 1.376074 1.421509 2.299841 2.179885 2.071203 2.462271
+1 0.021274 1 1 -0.764559 0.733769 0.141546 -0.800526 -0.572640 -1.669559 2.000322 1.225247 -0.420180 1.905689 -1.192522 -0.933745 -38.140165 -71.756236 -7.051758 -18.902086 12.643370 0.581795 1.223107 2.256664 1.007074 0.640589 1.624088 0.539710 0.402265 1.121436 1.216148 2.296880 1.913010 0.961891 1.752619 0.759580
+1 0.017866 1 1 0.690167 -2.258694 1.129399 0.300093 1.409475 -0.127488 1.444266 0.264522 2.034217 0.697834 -0.633558 1.786800 -41.533221 51.154886 -39.835492 -65.105707 18.376455 1.421190 1.447661 0.840396 0.537540 2.189804 2.280464 0.507144 2.074996 0.961025 0.698947 1.449305 1.467693 2.264090 2.067397 1.494370
+1 0.060962 1 1 -1.200386 -1.156921 -1.063287 -1.279533 2.239394 -0.352147 0.227350 -0.676999 2.104793 -0.649112 -0.446291 1.312375 -51.281152 17.684553 74.276425 63.869339 51.981573 2.189515 1.935679 1.709768 0.567779 1.914585 0.431286 0.627835 1.024261 1.512381 1.835755 0.779570 1.989831 0.584614 1.351645 0.353973
+1 -0.021022 1 1 2.292037 -1.518569 -0.287177 -1.099151 -0.860912 -2.319199 2.108160 -0.601352 1.147271 -0.920842 -1.097884 1.582016 52.592583 -26.454944 -28.244612 42.810114 -40.410998 1.560277 1.333529 1.878764 1.392865 2.386604 2.407532 0.890867 0.550349 1.466779 0.398981 2.169247 1.040077 1.824931 1.106482 1.889368
+1 0.013513 1 1 -1.465475 1.418495 0.662670 2.125401 1.700411 -1.838767 -0.314738 2.208170 -2.067709 1.889591 1.565571 -1.433661 -35.131480 -54.775987 -70.005246 21.829807 -6.440596 2.168429 0.793353 1.882724 0.443246 1.382025 2.440835 0.366109 0.936900 2.470719 0.877402 1.496024 1.420537 1.715708 1.397611 1.155042
+1 0.011133 1 1 -1.229277 -1.339468 -1.355684 -0.579349 -1.321991 0.203291 0.236339 -0.397124 -1.723059 -1.829720 0.943402 -1.431986 -38.721450 58.595236 60.123805 -49.212558 -15.454033 2.335955 1.637314 2.331309 2.308192 0.788419 2.215457 1.429909 1.724287 1.585859 1.527087 1.503510 1.235684 2.140340 1.186154 2.195816
+1 0.016182 1 1 1.943004 -0.790131 -0.223941 1.430142 -1.492652 1.749403 1.630605 -1.670516 0.050484 0.260458 -0.298966 -1.316376 10.677982 64.843060 67.301230 -18.224439 1.847883 1.485456 1.555254 2.407671 0.970229 2.392234 0.278824 0.937745 0.932118 0.862704 1.964054 1.612163 0.378638 2.261197 0.689248 0.435926
+1 0.024854 1 1 -0.731859 -1.018986 -1.269857 -0.081370 -0.985847 -0.374533 0.969596 0.565384 2.234920 -0.145109 2.176670 1.020110 41.946162 -10.858588 49.718015 -39.318755 69.683603 0.959701 0.949135 1.106797 0.434670 1.253191 1.637908 1.073741 0.619386 0.778710 1.036479 2.108591 0.845079 0.493519 0.317603 2.459284
+1 0.009346 1 1 -2.254712 2.093194 2.323381 2.204715 1.133007 -0.313870 -2.054254 1.824566 1.969864 -1.732261 -0.973067 -2.341272 -41.785213 15.917118 68.995281 -46.310219 14.148613 2.061184 0.563536 0.355846 1.710284 2.486888 0.375987 0.456773 1.476639 1.871415 1.614413 2.192721 1.809719 1.943000 0.994243 0.991088
+1 -0.021799 1 1 1.107112 -1.986953 1.985054 -0.918710 1.747618 -0.101837 -0.984508 -1.424527 1.628065 -1.949870 -1.507067 -0.189182 41.010252 9.304939 -61.896205 -39.518031 20.454620 1.086925 1.690905 0.787364 2.474584 0.585212 2.412895 1.026939 1.507567 1.927747 1.146814 0.258657 1.748681 2.079101 2.453010 2.485441
+1 -0.005096 1 1 -1.041152 -1.544165 -1.658174 0.130758 1.683239 1.730509 -0.197828 2.058235 -0.885002 -1.927320 0.488466 0.663692 14.350541 -10.451528 -8.837426 -30.623152 -33.323376 1.885258 0.281994 2.465110 1.105920 1.445009 1.263150 0.260741 0.780173 0.866658 0.912706 0.846529 2.365061 0.337361 1.534055 1.603623
+1 0.035814 1 1 2.045640 -0.523400 1.251241 -1.783545 -0.530611 -2.138806 -0.809069 1.925237 2.202562 -2.073928 1.038590 0.902199 -38.727031 -35.203800 -70.267091 -28.999065 -37.285136 2.105849 1.999592 0.385429 1.653717 1.277060 2.300089 1.843928 0.895998 1.290761 0.825917 2.438070 1.133427 0.259817 0.994728 2.397202
+1 0.045084 1 1 0.488305 -2.037243 0.269989 -0.329125 0.741365 0.565397 -2.258212 -0.182098 -2.188696 -0.511255 -1.975115 -1.696591 1.754525 -61.707488 -17.746492 -65.296627 -40.413419 0.950044 0.634881 2.448385 1.254104 1.225952 0.581335 0.251574 1.950078 0.707071 0.741845 2.437012 1.366422 1.210446 0.967166 0.405492
+1 0.009493 1 1 -1.299466 1.804236 -0.431925 -2.277714 1.907972 -0.524143 -1.813512 0.034185 -0.362542 -0.130976 -0.625821 -0.118309 6.501022 62.678251 -16.643818 17.355990 -47.881764 1.392975 1.986817 1.677183 1.906074 1.381412 1.137457 0.492823 2.119355 1.750630 1.089993 1.517279 0.906753 2.040558 0.405985 0.647327
+1 -0.020288 1 1 2.309401 -1.841847 -0.237515 -0.519341 -1.223376 -1.127718 -0.326095 -0.164351 -0.782709 1.996460 2.285918 -0.689202 -11.551415 -44.625744 -24.879406 51.817152 -9.121868 1.206460 1.477256 0.997889 1.517756 2.175073 2.207378 0.643214 0.747048 2.139827 1.573166 1.959009 2.319907 1.929897 1.280703 0.531553
+1 -0.041080 1 1 -2.084682 -0.643016 -1.655605 0.906049 2.244767 0.411907 0.421756 1.019931 -1.695502 -0.491480 0.517487 -1.667496 -32.556140 28.953333 18.667194 -60.474554 4.174441 0.772418 1.029875 1.353085 2.055621 1.577131 1.090551 1.895075 1.029293 0.572476 2.097548 1.983786 0.250012 0.444865 1.593618 1.439115
+1 -0.052599 1 1 -1.992805 -2.118485 1.424764 -2.350494 -0.804002 2.269445 0.493235 0.707696 0.176903 -0.308913 1.144394 -2.142717 -18.152866 4.777665 48.207568 74.589767 -69.780874 2.017826 0.857747 1.908695 0.435872 1.203084 0.978141 0.371649 1.809144 1.282732 0.876969 0.962981 2.064491 2.153993 1.154471 0.701169
+1 -0.028463 1 1 0.383106 1.735615 0.794525 -1.323571 1.934002 -1.293209 -1.422764 -1.740716 -1.707068 -1.666840 0.571604 -1.608102 -57.630386 -43.904700 -56.291715 -44.850099 -45.613550 1.720987 2.375676 0.990715 2.441015 1.142219 1.779027 1.363277 2.338148 0.261781 2.498946 0.537073 1.093861 1.266313 1.666038 1.359093
+1 0.027871 1 1 -0.695680 -0.850874 1.462572 1.623621 -1.249218 -1.905664 1.609867 -1.509107 -1.488673 -2.058052 -0.748939 -0.621251 40.888192 57.850767 -2.154522 -61.056051 -19.045260 1.469661 1.584590 0.450796 2.284425 1.825187 0.918320 0.706639 2.482874 0.408318 1.607777 0.910449 1.172123 0.376994 1.632087 2.228815
+1 -0.021257 1 1 0.660603 0.367369 1.137497 -0.245666 -0.862706 0.516322 2.313607 -1.842825 2.166554 0.649165 1.330695 -0.011003 -36.374913 46.839976 39.476547 32.323883 -32.497050 0.956283 2.001898 0.895433 0.786812 2.195770 1.303963 2.210388 1.748257 1.711550 1.279263 1.076067 1.451606 1.888312 2.104106 1.967722
+1 0.042574 1 1 -0.065930 -0.679635 0.197258 -2.200694 0.479339 -1.941670 -0.356859 1.144499 -0.373393 1.285678 2.080888 -1.871701 70.906909 -17.580138 30.617832 -56.094458 -29.554296 0.339099 1.492581 2.060467 2.017557 0.824612 0.761811 0.510388 0.334222 0.518258 2.114459 0.455853 1.763481 1.067855 0.686644 1.675682
+1 0.028721 1 1 -0.883994 0.872843 0.205619 1.656056 1.964384 0.412340 -1.726384 -1.161253 1.535662 0.119616 -1.797669 -2.296969 -40.082580 -17.921242 -2.307611 65.984749 55.683065 1.604075 1.690820 1.605039 2.132247 2.427283 2.090964 1.579710 1.684739 0.663161 0.748102 1.855360 1.781389 0.559269 0.634363 0.482294
+1 0.057565 1 1 1.986754 -0.615143 0.267450 -0.591882 0.088614 0.221292 1.179022 0.226152 -1.963416 1.724004 -1.141909 1.492967 -37.262561 -21.856718 4.147282 -46.632987 -10.618236 1.964654 0.435070 1.227138 0.263214 1.830252 0.543727 0.423061 1.881821 1.020166 2.427929 1.707629 0.622222 1.184138 2.059195 0.891889
+1 -0.007059 1 1 -1.705298 -0.200714 0.666118 -1.198239 1.946120 -0.257234 -2.069194 0.486120 -1.071246 1.607242 1.500842 -0.770581 -47.866628 -44.411380 -22.061972 4.439457 63.955489 1.373562 1.949440 1.242321 1.196454 2.053621 1.713437 1.478313 0.750929 2.120829 1.763840 0.352590 0.982597 0.999606 1.121314 1.419768
+1 -0.010428 1 1 0.683002 -0.158092 0.739192 1.735752 -1.623651 0.748227 -1.908139 -2.282309 0.079406 0.969589 0.448361 0.494156 65.027950 24.755275 -38.095536 -71.678571 -51.743675 2.035840 2.118353 0.663997 1.292495 0.705800 1.887450 1.115730 2.077213 2.225803 2.070501 1.910111 1.728526 0.833035 0.571848 0.552992
+1 0.000860 1 1 1.296528 0.662722 -1.718222 -0.636286 -1.655127 -0.491417 1.572207 1.714422 -1.960527 -1.557468 0.951448 1.845593 61.464616 -14.196181 54.783760 50.654741 -45.763439 2.183300 0.971230 1.204813 0.794930 1.396266 1.040241 2.327427 2.321767 1.692059 2.187388 2.172678 2.446883 0.756532 1.786954 1.836035
+1 -0.048965 1 1 1.482290 -1.557983 1.729942 -0.303147 -0.898938 -0.538480 2.260159 -0.075521 -1.653227 -1.542123 -0.331022 1.843594 42.322312 11.102494 -0.389062 61.027982 -2.701669 2.020728 2.368953 0.491075 2.000636 2.195454 0.488974 0.438469 2.101085 0.694510 1.122362 1.046162 0.591155 1.033845 0.584050 0.871081
+1 0.043176 1 1 0.034165 -0.698786 -1.214894 0.063496 2.175433 -0.921571 0.786749 -0.078814 -0.442574 -2.189111 1.945542 -0.549097 -57.714122 48.745840 -28.662301 72.704807 49.688778 2.414252 1.335812 1.988895 0.615750 0.412587 1.350216 1.080866 1.120901 1.236992 1.617348 2.015981 1.344123 2.181780 2.425162 2.447459
+1 -0.002008 1 1 -1.209055 -0.761365 -2.132283 0.441603 0.010059 -0.588788 0.259968 0.897463 -0.702641 -0.046309 -0.773048 -0.558867 -34.458177 11.426110 38.635475 -3.571140 -20.141558 1.837603 0.346744 1.731177 0.385840 1.806135 2.457202 0.941466 0.461214 1.881239 2.476649 1.531159 2.432207 1.602952 0.817561 1.505082
+1 -0.049795 1 1 0.817336 0.346003 0.180136 2.199915 0.564594 -1.622403 -1.847850 -2.171492 1.183817 0.709665 0.287650 -0.383621 -31.040161 8.016208 28.401470 43.507458 -20.153414 1.098595 2.092386 0.724551 2.020706 2.006658 2.159555 2.396864 1.592872 2.394404 0.739295 2.335234 0.778469 1.472792 2.459969 2.454734
+1 -0.015294 1 1 1.251199 2.229066 0.421328 -1.457316 1.888287 -1.493896 -0.302551 -0.304652 2.079379 1.043550 -0.571084 0.927821 18.796366 10.529365 -32.968908 -8.436252 -38.080814 1.761499 1.506601 1.437806 1.704706 0.991449 1.288748 0.744413 0.596302 2.054263 1.253519 0.390683 2.213349 2.010659 1.897017 2.160474
+1 -0.035057 1 1 1.701546 -1.602681 -0.238693 -1.464648 1.190294 1.176877 1.872675 0.011267 0.865106 2.116187 2.350494 0.799318 -28.033556 -9.981544 -59.811676 45.153130 38.660521 0.885593 1.912479 1.038345 1.964840 1.316168 0.332925 1.223366 2.103193 2.365591 2.479475 1.783191 1.597160 2.460836 1.278181 0.894239
+1 0.015533 1 1 0.536192 1.698988 -2.194711 2.080318 -2.017590 0.723889 -0.987345 -1.990586 2.178981 2.149796 1.732287 1.416080 -70.688317 -58.545256 29.890582 21.013088 66.972145 1.387613 1.865519 1.530424 1.339052 2.450365 0.779400 1.374423 0.673659 1.680971 0.335711 0.789990 1.616158 2.265074 0.602154 1.399189
+1 -0.036962 1 1 -2.093860 0.608780 1.166328 -1.069710 -0.857066 1.059932 1.454533 -1.532177 1.907467 0.422492 -0.754170 0.996168 -16.591547 -4.134452 -37.739583 60.834483 45.163676 2.363600 0.521834 1.468679 0.845336 0.306678 1.081876 2.335977 2.016900 1.045572 1.921924 2.278468 0.709238 1.169405 1.935218 0.703492
+1 -0.028735 1 1 -0.973431 0.958327 -0.350710 0.820917 -0.725431 -1.373776 1.661865 0.636689 -1.002928 -0.000181 1.662800 2.210784 -17.261850 -19.917513 46.358472 46.842074 74.744515 1.090879 0.651495 0.432626 0.636927 0.832153 1.494123 0.966874 2.254868 2.309343 2.129434 2.401512 0.966351 2.460592 1.664096 2.458030
+1 0.061844 1 1 0.561003 -0.709520 2.152022 1.442428 2.351471 -1.636211 1.712537 -0.659141 0.639559 0.112472 0.652233 1.056306 56.316823 16.841277 1.343110 73.642444 58.548950 1.858122 0.957157 0.943556 1.848451 0.408735 1.858754 0.328842 2.340224 1.390054 2.388339 2.322476 2.346653 1.455594 1.422103 1.044087
+1 0.001432 1 1 -1.402741 0.214193 -0.318961 1.915060 0.795153 -0.206498 -2.289836 0.814500 -0.195383 0.725304 -0.769189 -1.676851 62.646638 52.036887 -66.043699 3.543197 0.514792 0.656587 0.509025 2.185506 2.048891 0.955160 1.115890 0.270420 1.443690 1.596172 1.614183 0.573880 0.958755 0.791658 0.389929 0.781549
+1 0.012875 1 1 -1.072086 1.624300 0.732934 0.233914 1.259769 0.177705 -0.962646 -1.559959 1.496013 -1.812803 -2.180679 2.290929 -40.997185 60.313940 -3.615594 -17.293725 44.357337 1.581414 1.078764 1.779538 0.940905 2.287229 1.705557 1.801020 2.001180 2.336704 0.730521 1.116227 1.436398 0.540794 0.625228 2.213690
+1 0.050648 1 1 -1.368147 2.016277 0.772621 -1.895366 0.328947 0.984077 -1.102251 -1.132066 1.993850 0.841939 -0.834328 1.520735 -32.178988 67.753630 -64.734915 -49.716582 63.413015 1.863265 1.888472 0.305307 0.551460 2.131595 0.470141 1.155852 1.404984 1.313855 1.963726 0.592166 2.290127 0.910413 0.561326 1.457625
+1 0.016117 1 1 -1.342514 -0.716396 -0.310293 1.525626 1.087890 0.100972 0.580017 -1.590807 1.408257 -1.747309 0.584676 1.316857 -53.099256 60.802083 -49.399010 0.838758 -2.998706 1.386115 1.433894 1.211713 2.013098 2.389496 1.513406 1.059881 1.677382 0.765318 0.945261 1.248356 1.375759 0.638956 1.186285 2.138971
+1 0.060508 1 1 -1.555001 0.012920 0.383257 -0.441876 0.112429 -0.074764 1.655346 -0.549774 0.946600 0.476753 1.731656 0.220783 65.013300 -71.468954 21.282360 -57.379351 -24.746599 1.883723 1.486595 0.459786 0.377079 0.820857 0.642521 0.345711 2.368676 0.334164 1.800749 1.932897 2.203613 0.381534 1.449623 2.318852
+1 -0.006376 1 1 2.331800 2.332874 1.536554 0.965572 -1.104016 2.186299 -2.076148 1.414162 -1.476033 -1.675029 -0.402904 0.102528 -49.171425 -74.139880 -18.956777 -6.555482 72.016908 1.947514 0.360488 0.967647 1.742682 0.262424 2.066886 1.908201 1.133425 2.471288 1.434197 1.802201 1.590680 1.559100 1.786750 0.655385
+1 0.027738 1 1 0.484052 1.871678 2.096538 1.974044 -2.174040 0.772946 -1.148313 2.248025 -1.370990 1.349975 -1.125530 -1.260559 21.923795 73.218513 -16.444575 66.024996 -17.892058 1.947793 0.559996 1.594831 1.576106 1.865791 1.592702 1.799775 1.311168 1.796690 1.226306 2.030119 0.466652 1.027452 1.129095 1.705166
+1 0.075536 1 1 -1.833358 1.056449 -0.542345 -1.431944 -0.504189 -1.037021 1.915176 -1.970183 1.086815 0.875828 -1.464343 1.598928 -50.064290 69.479525 -7.626172 -73.080363 -61.654803 0.890993 0.412342 1.728136 1.028807 1.409248 0.975696 2.025116 1.878435 0.356404 2.075472 2.202051 1.127730 1.262972 1.775079 0.258219
+1 0.000530 1 1 -0.816939 1.607793 1.345118 2.071307 2.039920 2.307561 0.217220 -1.281105 -0.624413 -0.021381 -1.200683 -1.421204 29.515397 15.285462 -47.240611 -22.946559 -12.809816 0.706455 1.646398 2.015231 2.231370 1.131235 1.672664 2.466380 2.205596 2.199005 1.672350 1.679355 2.418194 2.329649 1.412230 1.599794
+1 0.027960 1 1 0.369357 1.570251 1.830493 -2.086581 0.433581 1.847609 -1.885923 -1.175452 -1.482101 0.015765 1.067593 -1.738826 57.022559 28.154297 -60.726214 -25.484691 -71.205970 0.493912 2.426878 2.042917 1.804626 1.857038 0.739371 1.363548 2.404442 0.701388 1.985280 0.591882 2.005337 2.448836 2.085608 1.558433
+1 0.000789 1 1 1.713703 0.091766 1.356418 -1.229161 0.598328 -0.137698 -0.509423 0.540493 -1.416884 -1.867422 -1.253718 -2.147393 30.521518 -24.849804 -50.658206 -12.468271 -4.222449 1.124478 0.594576 2.285195 1.280565 0.463038 1.037833 2.364091 2.021577 0.892126 1.454139 1.711475 2.262571 1.283709 1.546912 1.708447
+1 0.012455 1 1 1.120197 1.160767 -0.284207 1.692855 -1.585228 0.928792 -1.938369 -1.421464 1.271432 -1.721258 0.165388 -0.627936 64.535234 -6.317821 16.384857 -19.707547 -24.749238 1.218337 0.841154 2.028701 1.380838 0.499483 1.560938 1.183008 1.058745 0.572685 1.112775 1.911522 0.702785 0.704256 0.680644 2.090832
+1 0.045309 1 1 0.533764 -1.411498 -0.872826 0.084449 0.910800 1.974509 0.922621 -1.976035 1.698468 -1.507828 1.157432 0.224824 -22.941235 -73.341501 49.386189 -66.325313 70.462645 1.610213 1.352971 2.386468 2.373989 1.886963 1.929663 1.845212 2.221901 1.743177 1.823659 2.232734 1.558021 1.652309 2.354168 1.744256
+1 -0.005587 1 1 -2.007320 -1.033605 -1.940323 -1.283596 -0.085343 -1.790722 1.354792 -0.281174 0.828963 -2.161201 -0.205458 1.044474 26.190882 -59.849126 15.743992 9.277586 -71.606570 0.750737 1.133441 0.493352 2.016557 2.032214 1.915891 2.130190 1.605465 0.293856 1.593008 2.430500 2.157403 2.222157 1.534641 2.465183
+1 -0.008783 1 1 1.066259 -0.605445 -1.661787 0.683684 1.871673 2.008318 -1.034294 0.616021 0.343574 1.776988 -1.288027 0.840430 66.310622 -17.377160 -7.935897 -28.621609 6.624216 1.872839 0.798276 1.376099 1.851353 1.934010 0.663193 1.283074 2.120868 2.433188 2.339037 1.688876 0.437476 1.156102 1.099438 0.511610
+1 -0.060620 1 1 -0.000923 -1.374071 1.401677 0.745546 0.154524 0.565367 1.940427 -1.696608 -0.219569 -0.493997 0.627927 -2.174736 -47.971056 0.466616 42.413512 43.897304 -68.004334 2.142402 2.103521 1.122011 1.882808 1.847643 0.331765 1.971172 1.995044 0.454242 1.687690 0.763275 0.365994 1.254610 0.731400 2.390280
+1 0.004245 1 1 1.185419 -0.641430 1.432918 -1.970617 -1.495616 -0.939705 2.309818 0.448192 -2.340731 -1.649825 -0.912604 0.683246 -24.649210 20.733881 24.335530 -42.742133 -17.029876 1.058181 2.346752 0.855025 1.155568 1.132556 1.366215 2.216614 0.630858 2.338768 1.671361 0.807133 1.729939 2.081577 1.321941 0.616202
+1 0.022508 1 1 -1.655612 0.785781 -2.207155 0.275457 2.033015 -0.648072 -1.817584 2.277080 1.564383 2.170371 -1.180805 -1.919132 46.148797 -27.173605 43.226576 59.069087 74.142073 2.212267 1.822105 0.860647 1.152344 0.946109 2.006209 1.353603 1.752377 1.195769 1.791838 0.675470 0.626712 2.397834 2.139621 0.353547
+1 -0.045865 1 1 -0.956980 -0.587461 -0.998550 -1.811797 0.587398 -0.055359 -2.070429 -1.424729 -1.764424 0.390103 1.529775 0.129447 -48.139752 15.191780 28.250422 54.834799 8.470988 1.703350 0.704060 1.878648 1.693019 0.325142 0.908771 2.214300 2.236355 1.663015 2.297386 1.421416 0.742120 0.306222 2.415900 2.033264
+1 -0.016016 1 1 -2.005555 0.357800 0.531313 -0.196954 -2.102176 2.222764 -1.826684 0.141838 -0.599605 2.234408 0.670746 1.195563 6.621104 -19.110473 -39.717528 -32.492280 52.250265 2.428050 1.491753 1.648356 1.168811 0.959708 1.059880 1.649383 0.438881 2.267221 0.677509 1.150968 0.312467 1.634170 1.250446 0.496742
+1 -0.005535 1 1 0.485052 -0.164947 -1.376405 -0.128462 -0.787231 1.401043 -0.473355 -1.162621 2.103659 -0.856247 0.689519 0.980500 1.066443 73.713152 46.945164 7.379403 -24.366674 0.914748 1.414650 1.766113 0.310841 1.300280 1.059805 0.384875 1.345566 1.676412 2.461032 2.315227 2.021992 1.123767 2.158425 1.406627
+1 -0.017079 1 1 1.361864 0.781246 1.678722 1.211731 -1.375982 2.281588 1.934863 -0.955989 1.946349 -1.120732 -0.732899 0.351460 -74.933689 -10.505452 -15.123943 61.893878 0.411229 1.547884 2.282966 2.064407 0.742658 0.346482 1.826713 1.818846 2.348851 2.390496 0.324541 2.057266 2.226721 1.752491 0.864429 1.708099
+1 0.014394 1 1 1.180013 -1.968987 2.341847 1.545685 -1.066402 -1.807119 -0.903692 -0.316831 0.020918 -1.861458 0.020313 2.100343 -1.254401 67.278552 50.630986 4.988421 -9.607446 0.289897 0.291166 1.370397 0.514806 0.344003 0.653809 1.070614 2.057471 1.164697 1.553604 1.675968 1.746701 0.300741 0.307495 1.323634
+1 -0.005764 1 1 -0.379226 2.203589 1.062848 -1.386544 -0.886804 0.766983 2.304650 -1.580477 0.662627 1.403051 0.290847 1.526630 -28.241005 -46.578569 3.989276 -2.230429 13.181975 1.366817 1.084143 2.192058 1.924529 1.056092 0.987338 1.944365 1.450383 1.586092 0.945727 2.329420 2.053691 0.635443 0.643625 0.903533
+1 0.010253 1 1 1.342511 0.663250 -2.262449 -0.711652 -0.686584 1.229858 1.681046 -2.138069 2.154040 -2.334189 -0.077920 0.443250 -18.749566 26.038355 -73.362681 -6.571173 -41.698083 1.079794 1.106661 0.408893 2.267657 1.266603 2.047768 2.330598 1.614893 1.250082 1.119910 0.328477 0.705485 1.087129 0.628510 1.123317
+1 -0.004075 1 1 -1.299126 -1.910347 -1.691722 1.778827 1.354857 0.822818 -1.752719 -0.795953 0.892759 0.358749 2.350961 -0.779676 36.209203 18.069433 -57.034506 71.060591 15.348291 0.755861 1.750060 0.503526 2.018462 0.297932 0.339853 0.663058 1.267968 2.487108 1.829740 0.932518 0.828216 0.574509 0.265038 0.992799
+1 0.007929 1 1 2.244696 -0.785984 -1.215134 0.733112 -1.489500 -1.810342 1.486486 -1.710542 1.210873 -1.669314 1.409889 2.117557 57.609726 -3.338391 -8.330847 -66.546913 -53.967176 1.730143 1.007103 1.129318 0.948575 0.697462 1.247728 2.070727 1.200977 1.568507 2.388552 1.394898 0.552545 2.372062 0.996659 1.094085
+1 0.045232 1 1 -0.969616 -0.898824 1.378810 -1.870465 -0.554867 0.164615 0.520037 -1.215724 0.248067 -1.209577 -0.108524 -0.271930 21.878040 54.226080 -22.279043 -43.875792 -20.444407 1.987701 0.782185 0.934268 0.992014 1.787345 1.652713 2.396368 2.260612 2.102288 0.655778 0.402771 0.616406 2.428879 1.915046 1.431716
+1 -0.007341 1 1 -2.063992 -1.610493 0.402398 0.821609 1.482320 -1.040691 1.489688 0.263514 -0.772880 2.257248 -1.879451 -0.792808 60.853967 72.620923 -10.152990 58.704256 -57.572494 1.811413 1.163114 1.959429 0.378026 0.988565 2.312162 2.263889 0.941389 1.426578 2.005617 0.407853 0.531204 1.452324 0.454190 0.820167
+1 0.004644 1 1 1.348487 2.147686 -0.733378 1.722409 0.318058 1.759298 -1.718773 -0.471601 0.044232 -1.150690 -0.000664 -1.729093 13.875113 -50.968317 25.489119 -4.384042 -32.586242 0.970541 0.886997 0.762170 2.038361 1.731526 1.749183 1.523180 1.091273 0.530000 1.454604 0.536533 1.018135 2.042013 2.354939 1.207347
+1 0.043888 1 1 0.136334 1.152030 -1.040663 1.969951 -0.278047 1.547998 0.099058 1.395497 0.557406 0.097478 -1.599938 -1.271826 -5.662103 -62.964533 5.093740 -39.515162 68.665446 0.777202 0.439380 1.653541 0.566896 0.578248 2.370717 0.885926 0.754939 2.002352 1.776401 2.220998 2.319886 1.568043 1.348184 0.680580
+1 -0.007738 1 1 1.014076 -1.129582 1.333700 -1.340333 -1.751176 1.566422 -1.265319 0.797366 -0.708644 -1.974164 0.153852 -1.309609 30.982656 -74.500809 64.910500 0.770420 48.442082 0.865977 0.731309 0.866069 2.274626 1.394433 1.738334 1.427873 1.257332 1.475141 1.446904 1.613552 1.212005 2.411820 0.962424 1.713602
+1 0.013020 1 1 -1.214584 0.557620 -1.023855 1.712370 1.247497 1.257962 -1.916170 -0.608031 1.997119 -0.771011 0.688254 -1.429015 50.636880 -45.963789 -13.398932 -45.844393 43.286451 1.605719 2.327203 0.796961 1.767620 0.883992 1.999699 2.185701 0.830742 0.274706 1.484660 1.676864 1.061272 0.299173 0.950712 0.612767
+1 0.040477 1 1 -0.120451 1.900106 -0.780106 -1.382151 2.266530 -1.388624 1.853939 0.831435 1.701655 0.220379 -0.029436 0.074802 -31.911105 70.058032 -34.659980 69.722247 21.810106 0.811838 2.057492 1.511829 1.563544 2.233330 0.329315 1.291981 1.077986 2.202303 0.852825 2.431168 2.141786 0.751876 2.272301 0.558340
+1 0.010783 1 1 1.069783 2.084499 2.281751 -0.037386 -1.601371 -1.782927 0.428944 -0.697848 0.401725 -1.063619 -2.159062 -1.959232 43.607336 8.488919 23.254916 -54.620898 -13.425138 0.830630 0.650827 0.444738 1.711163 1.522210 0.540369 2.474290 2.399739 0.421398 0.943051 2.352723 2.219723 1.135773 1.435735 0.652065
+1 -0.066521 1 1 -1.736675 0.234071 -0.815119 -0.795963 0.729156 -2.005118 -1.726241 1.237296 -0.537544 -0.859953 -0.330563 0.140680 -38.480153 64.071085 -7.278381 72.247787 18.556192 1.733697 2.239274 1.225429 0.775965 2.151512 2.208129 2.030145 0.900705 1.646067 0.939166 2.306145 2.373923 0.775197 0.493591 1.525674
+1 -0.001893 1 1 -1.300065 1.159201 1.681471 0.291712 1.920130 1.193834 -0.590168 0.628734 1.961444 -1.890883 0.271719 0.479083 -48.783570 -5.457920 68.740686 24.708087 68.820117 1.520706 2.252383 1.057039 1.147457 2.055237 1.870300 0.882840 0.637112 1.698617 2.157130 2.133975 2.216725 2.489664 2.036910 2.091211
+1 -0.014982 1 1 -0.409597 0.697751 -2.040011 0.874713 -1.347037 -1.327708 -1.621857 -2.085744 0.358473 -2.287623 0.300920 1.172497 -33.589408 62.817924 -69.156838 31.027712 -67.251451 0.698061 2.314983 2.416060 2.467049 2.199453 2.455216 1.320252 1.468497 2.278988 0.445897 0.933456 0.840240 2.411584 1.493246 1.982425
+1 0.066920 1 1 -1.387619 -0.097233 1.001429 -1.637705 0.157448 -2.126565 2.297473 0.310421 0.631206 1.086351 -2.198705 0.920243 14.758612 -51.999878 -61.951299 -65.484736 -51.950414 1.665796 1.779205 2.090909 0.652332 0.996071 2.466113 2.209370 0.384330 1.181564 1.554515 1.238602 1.683981 1.421349 1.856547 1.482198
+1 -0.025396 1 1 -2.023583 -1.043313 -0.161266 -0.777282 -1.043130 -1.802767 1.550307 1.205398 0.568670 0.909531 -0.506850 1.369630 -20.451232 -73.848742 74.193766 24.621097 -43.215706 0.979381 0.949578 1.813609 2.074226 1.519875 1.789927 2.308586 0.662416 1.721670 0.350850 0.977793 1.259820 0.544660 0.358290 2.287235
+1 -0.021320 1 1 0.037461 -1.854560 -1.848598 -0.607465 2.077138 1.079116 -1.285225 0.820674 -0.099261 -0.097836 0.287390 -0.029485 -23.834561 62.536841 6.690541 -52.074377 35.945450 0.402574 1.816857 0.419509 0.683742 2.402661 2.267322 2.383554 0.645907 1.010935 0.285815 1.449036 1.448152 2.348345 0.628357 0.800787
+1 -0.005155 1 1 -0.994193 0.734367 0.756854 1.706777 1.486019 -0.136084 -1.651588 -2.265248 -0.628128 -1.195661 -1.849614 1.172985 -72.556906 36.088973 -52.625933 65.945248 -8.220404 1.219966 1.215968 1.530437 1.552935 1.680808 2.089447 0.844553 0.653106 0.507095 1.244505 1.894405 1.017985 1.769881 0.638679 1.019513
+1 -0.002298 1 1 -0.376840 -0.096839 -1.793897 -0.167288 1.681814 1.347237 -0.015243 -1.712984 -2.144870 0.942394 0.472458 0.223394 -37.901132 45.669372 15.127661 0.602811 -68.557791 2.113214 2.038486 1.578057 0.907640 1.204693 1.017938 0.983941 1.100918 0.621847 1.637922 1.302856 1.605250 1.185616 2.154429 1.736275
+1 -0.026050 1 1 -1.155078 1.649598 1.807009 -0.941976 1.838604 2.275222 -1.376905 0.905064 -0.184854 -1.377955 2.099772 -0.220887 29.318910 12.912560 -28.598335 -52.211501 -18.698028 1.258550 1.693928 2.096693 1.121317 1.473670 1.466201 1.943158 1.403393 1.572290 0.730389 1.146800 2.272938 2.277809 0.880205 1.349011
+1 0.082519 1 1 -0.345770 -0.984220 -1.300097 0.621035 -0.200678 1.267829 -1.014392 0.536322 -0.837318 -1.609838 1.989960 1.440050 2.838454 5.902461 52.661248 -72.407491 -2.694837 1.493219 1.540554 0.594128 1.505534 1.504393 0.333115 2.155724 0.998608 2.351701 0.796118 1.097268 2.281504 2.242682 2.249354 1.898780
+1 -0.029749 1 1 1.172285 0.101386 -1.896474 0.559035 -0.799540 1.869705 1.913541 -1.167581 -1.142233 0.755282 -1.154818 1.309107 0.660534 1.590725 35.317819 36.586084 52.307740 1.167800 1.967144 1.786374 1.096367 0.639012 2.121147 0.360649 1.424272 1.482107 1.523420 0.626610 0.682984 0.914669 2.349092 1.934691
+1 -0.015868 1 1 1.329431 2.313963 -0.569703 0.574950 -1.921184 -0.055406 1.842197 1.417144 1.527595 1.200112 1.258608 -0.482954 -72.515143 -12.016013 -53.133664 -67.482472 -27.911567 0.479286 1.866116 0.312161 0.983018 1.340584 1.191385 2.360172 1.407485 0.596694 1.884835 2.172314 0.835494 1.396598 2.125604 1.019545
+1 -0.025912 1 1 -1.408763 -2.040021 0.712142 -0.492069 0.047084 -0.348482 0.562701 -0.452498 0.668608 -1.752136 -0.422915 -1.650348 -8.755713 -7.262049 46.740862 23.669069 6.037657 2.498465 1.456468 0.366439 1.983029 1.013905 0.694357 0.806736 1.808644 1.876742 1.150236 1.510624 1.553797 0.424978 0.350804 2.460677
+1 -0.019958 1 1 0.130670 0.199631 -0.015919 1.049561 1.498136 0.869612 -2.262788 -1.697029 2.119983 0.184503 0.184717 -0.928281 35.016971 -69.770085 74.173675 -13.046039 35.222414 0.371805 2.176401 2.025038 0.569692 0.311510 1.303382 1.445028 1.591564 0.665176 0.868506 0.472818 1.157906 2.171385 0.974769 2.198043
+1 0.012427 1 1 -0.413203 1.362905 -0.581639 -2.113184 0.984878 -1.777006 0.986526 -2.355077 2.282777 -1.644533 -1.504477 0.939945 54.915152 8.951700 1.230604 -17.236936 -51.179365 0.301096 1.767972 2.306168 0.519182 1.893881 1.206980 1.212611 1.360898 0.614492 1.767919 1.412812 2.375279 1.063168 0.670371 0.430763
+1 0.068963 1 1 -0.361419 -0.106106 -2.043191 -0.735991 0.213962 0.511971 -0.118042 -0.010307 1.132603 2.317152 1.183731 -0.744585 59.177531 -53.229966 -36.042942 -73.724552 61.450055 1.991022 0.364734 0.341294 2.372331 1.016111 1.780030 2.468893 1.680552 2.293968 2.474144 2.188836 1.758139 1.294553 1.551867 1.721509
+1 -0.023541 1 1 -1.579560 1.934336 -0.390371 -1.315048 -0.906057 2.338686 0.266171 1.481076 1.614949 -0.916396 -1.776666 1.989606 6.420511 59.520919 18.092036 22.843371 -71.470959 1.188971 2.283361 1.940904 1.775194 2.183324 1.368936 0.711940 1.573884 0.526032 2.273369 0.512180 1.202746 2.051228 1.983371 2.260551
+1 0.013164 1 1 1.301398 -2.319874 0.179118 -0.788046 1.835076 -0.457909 -0.752958 -2.208960 -1.797913 -1.688538 -1.254111 0.672422 34.880402 34.918208 70.320388 24.764593 -31.480496 0.734613 2.387198 1.128640 0.794473 0.455038 1.580854 0.670133 0.930997 2.262919 0.378809 0.649374 0.776513 2.351383 2.200594 1.380668
+1 -0.060678 1 1 -0.660498 1.394284 -0.977330 1.394641 0.307594 0.237011 1.477483 -2.242165 0.906234 0.633176 1.218083 1.708563 -47.260857 -63.231616 16.238171 64.945047 -18.587723 2.067046 2.349118 2.376509 1.482402 1.983106 2.313139 0.670838 1.518359 1.055757 2.100715 1.212620 1.507989 2.268567 0.803246 1.648054
+1 -0.030173 1 1 1.237174 2.121685 0.512927 1.798087 -0.108342 -1.925676 -0.144964 -0.105120 0.390487 -1.447669 -0.914657 -0.831888 3.613610 -16.058347 -42.641509 24.158518 -17.788097 1.156729 0.390507 1.503291 2.064579 1.374477 1.592179 2.001748 0.626436 2.251436 0.877867 0.307840 0.364163 1.989806 2.419615 1.461776
+1 -0.002943 1 1 0.220362 -0.312902 0.077443 0.964875 1.329551 -0.377242 -2.146451 -2.071187 -0.021244 1.089289 0.052848 2.294131 22.086651 -39.659887 36.279186 -5.720009 13.800623 2.080951 2.052585 2.293230 1.315641 0.478601 1.604439 1.049954 1.332090 2.429265 1.652535 1.655828 0.757731 1.685920 0.259881 2.064108
+1 -0.012498 1 1 0.160311 -1.134420 0.125809 -1.393997 1.090954 -0.236667 -0.407353 0.726025 1.934685 0.759496 -1.018341 0.138059 59.010605 -8.754425 14.388036 19.724203 4.671857 2.423464 0.908598 1.558426 1.709266 1.135023 2.328617 2.058727 2.033690 1.981295 1.118296 2.452676 1.374439 0.948470 1.183095 0.283192
+1 0.000272 1 1 -1.011890 0.177009 1.474794 -0.299549 -1.691258 0.160039 -1.005995 0.299102 -1.116442 0.697249 -1.050521 1.212635 -10.248979 -54.595720 -40.261178 -19.624211 25.887545 0.504483 2.337558 1.585894 2.120680 1.519936 0.560247 1.324258 1.300468 1.960043 1.699207 0.827435 0.942914 2.298366 2.141071 2.232732
+1 -0.048333 1 1 -0.895608 -1.120499 -1.514965 -0.972689 -0.714314 1.683371 -0.762793 2.145053 2.136608 1.564440 -1.588463 -1.607217 -34.747068 -43.977071 -72.635111 71.690953 -40.148079 0.343454 0.431556 0.662960 1.864628 2.300519 2.316413 1.695524 1.917394 0.398999 2.472251 1.874198 1.151683 1.090327 0.372540 1.033696
+1 -0.001124 1 1 1.311990 1.346447 0.836540 -2.034351 1.758956 1.954983 -2.097347 -1.444489 0.695052 -0.279476 1.094947 0.896633 -16.412047 12.732499 -54.893321 57.945751 -55.760678 1.829194 0.757546 0.823224 2.182318 2.470970 0.585680 1.272397 0.430308 2.184893 0.755004 0.854326 0.658700 2.278278 2.019748 1.660181
+1 0.005120 1 1 -0.843893 0.987058 1.880724 -1.372574 -1.711957 0.991241 1.496996 0.564189 1.002054 -0.559504 2.338555 -1.941556 49.613725 7.876629 -67.501844 -53.492833 45.953219 1.161322 1.095977 0.831544 0.251902 0.712749 1.676212 1.346047 0.768410 1.174589 1.320959 2.104056 1.114409 2.374277 2.228877 1.985556
+1 0.029996 1 1 -1.490573 -1.003510 -0.354004 1.996681 1.291270 1.832850 -0.179593 2.216677 -0.458339 1.447958 1.058782 0.961387 -23.948815 -57.738381 -58.970040 -59.466288 0.104258 0.659031 1.077031 1.910977 0.543820 1.976926 1.940239 1.850947 1.857084 1.513671 1.021734 1.778092 1.387528 0.428721 0.264241 1.102681
+1 -0.040044 1 1 -0.638872 2.012888 0.362175 -1.333521 -0.372422 -1.250978 1.485651 -1.603679 1.830830 -1.140961 -1.419837 0.336317 73.872530 25.613177 -19.328919 38.857911 -15.096116 0.318666 2.323140 2.256796 0.967855 0.737677 2.132093 2.091000 2.192338 2.133951 1.808769 1.733804 1.792786 0.859097 2.094215 2.217237
+1 -0.023370 1 1 -0.177449 0.548725 0.283882 2.275320 0.271266 2.282091 0.975541 1.523677 1.322570 0.095210 -2.015426 -0.605938 -17.036270 21.412504 29.953113 21.974345 22.814724 2.081050 1.452086 0.960535 1.454557 1.997706 2.442930 1.825983 0.799492 1.564721 1.771622 0.649963 1.672587 1.169330 0.678158 0.801267
+1 -0.028273 1 1 -1.263329 1.256416 0.361152 0.320206 0.153786 2.291374 1.485841 1.587809 0.051889 0.303651 -0.057174 0.397057 18.850865 26.492795 64.412211 26.029771 -67.633580 1.111286 1.638593 1.325804 0.287420 1.418501 1.246111 1.892890 0.308062 1.848961 2.243072 2.068603 1.515281 1.070124 0.568875 2.333945
+1 -0.030159 1 1 2.279555 0.750513 -1.187647 0.904219 -0.241780 -1.508762 -0.403053 2.296837 -0.951114 -0.957765 0.363864 -1.223359 -26.593953 35.435072 57.254515 26.632396 10.687669 0.289778 0.554393 1.930766 2.381234 2.141451 1.860797 0.912670 2.487616 1.363415 2.415380 2.292503 0.347442 2.208339 1.060851 2.227301
+1 -0.003127 1 1 0.045504 1.386138 -1.235427 -1.034400 -1.154299 0.601018 -2.045093 0.290706 -0.856798 0.858446 -1.434784 -1.122399 -14.638093 -22.430493 -39.293999 35.760394 -25.063523 0.735628 1.457137 0.350487 1.639507 0.949437 1.680221 1.226990 2.264291 0.939302 2.353476 1.364526 0.833560 0.392027 2.305434 1.678140
+1 0.005966 1 1 -1.037463 -0.800543 -0.852566 1.290707 1.791113 0.497176 0.977835 -2.336518 -1.515967 1.030374 -0.537156 0.954470 25.833019 -74.441685 8.596821 36.771810 23.802291 1.301613 0.953467 1.924814 1.343312 2.041399 1.035536 2.010440 0.467529 2.267641 0.997938 2.335692 1.722197 2.458501 0.283164 1.884222
+1 0.027071 1 1 -0.383774 1.177035 -0.173114 -1.983506 -1.342127 1.081763 0.793364 -1.999610 1.319449 -0.522698 -1.087211 1.891911 -58.733167 21.665315 -71.055057 -72.347545 -45.187539 1.120595 0.589238 0.327770 2.332235 2.127764 1.328400 1.169890 1.098129 0.998063 2.188721 2.089902 1.731332 0.754101 1.418162 2.306308
+1 0.004289 1 1 0.292520 1.354986 -1.728387 -1.833548 -2.132974 -1.750511 -1.397346 1.358342 -1.875469 0.164644 0.992186 -1.466594 46.796415 57.346312 69.471570 8.669700 61.654557 1.797128 1.834136 0.578384 2.403925 1.016590 0.823497 2.266626 1.927681 2.286564 1.775147 1.388773 1.106724 1.459519 2.130529 0.547364
+1 -0.042294 1 1 2.201336 0.888414 -1.988368 1.754763 2.179644 -0.841374 0.903762 1.501150 -0.296815 1.852535 0.795102 -1.056418 33.863106 37.228829 54.937225 -70.060787 -11.651387 0.252206 1.330549 1.287790 0.389324 1.866052 1.494560 1.564685 1.151879 2.132902 2.181741 1.770658 2.455313 0.689658 0.590122 1.676539
+1 -0.051844 1 1 -1.280055 -1.820412 1.881594 -0.889933 0.024307 -1.443414 -0.085447 1.174508 -0.245713 -1.652142 -2.152564 -1.135492 30.429973 -63.443955 47.456051 43.855820 -15.239918 2.315351 1.849365 2.277719 1.618109 1.307769 0.920225 1.222727 0.371996 0.893538 0.441499 1.276953 0.504677 1.101870 0.879257 1.177922
+1 -0.067150 1 1 -0.936678 1.348117 0.634617 1.872098 -0.269901 1.808971 -0.959317 -2.150866 -0.868254 1.527020 0.950994 -1.066332 -20.115473 19.246809 -68.887081 64.836380 -44.964124 1.194603 2.444555 2.133195 0.360698 2.256946 1.247770 0.518267 2.269421 1.654058 2.498860 1.340467 1.477945 1.317571 1.422279 1.744848
+1 0.005351 1 1 -1.092596 0.925086 1.755045 2.197267 -1.534721 1.554905 -1.618124 -0.622133 0.601894 -1.471208 -0.685067 -1.559334 -67.981574 -16.321752 30.309326 8.839252 61.309172 2.473900 0.341655 1.693553 0.291232 2.485966 0.628243 1.137727 0.528951 1.829443 0.445150 1.892530 1.010630 1.915832 1.138415 0.840991
+1 -0.001131 1 1 2.228505 0.406773 -1.047504 0.089248 1.458818 -0.205996 1.424286 -0.965383 -0.438497 0.364767 -0.177140 1.037170 18.676848 -48.216310 -71.517328 -41.731053 26.189213 2.306453 0.804483 2.188299 1.735946 1.788724 2.331171 2.236666 2.398745 1.703241 1.114589 0.894612 0.496117 1.241385 1.211126 1.141941
+1 -0.047577 1 1 2.277511 -0.614036 0.024417 0.391742 0.804253 1.953122 -0.378064 -1.817234 -1.256492 -1.639444 -0.790206 -1.475457 -44.972581 -4.163108 -69.351259 63.388628 72.671494 0.472090 2.409929 0.682724 1.041832 2.076300 0.378514 2.433895 0.719136 1.026690 1.831144 2.043056 1.889606 1.360171 1.887136 0.348445
+1 -0.017699 1 1 -1.841619 -1.121077 -1.805758 -1.590334 -0.081116 -1.440484 2.035806 -0.858687 2.088099 1.511523 -0.323120 -2.004333 64.886647 49.876394 72.551130 16.843699 42.054708 1.577285 1.436413 0.795953 0.585966 1.586207 0.634003 1.195147 0.328885 0.812453 1.144451 1.030880 2.494625 2.156473 2.337747 0.269855
+1 0.039060 1 1 1.536949 -1.808917 1.868947 -1.392819 2.044780 -0.834988 -0.144499 -1.716938 2.085314 1.842849 -1.763372 -0.785353 -0.749995 -5.163438 68.090821 52.433765 4.285122 1.675583 2.016150 1.934878 1.748702 2.439071 2.217807 0.424433 2.441874 2.075267 1.013143 1.390736 0.345498 1.042450 1.200908 0.410094
+1 -0.005326 1 1 -2.287133 -0.895250 0.185374 0.689524 1.063445 -0.774740 -0.717270 -0.861828 1.143758 1.304227 -1.890680 -1.016131 -13.283292 -52.295505 69.444523 4.100086 60.151183 0.789088 2.205651 0.876435 0.998898 0.476739 1.802814 0.646858 1.240029 0.922098 1.207559 1.943175 1.700585 1.489604 1.520190 0.332922
+1 0.039453 1 1 -0.401667 2.032997 -0.954774 -1.196709 -0.615665 0.930581 -0.149757 -0.542717 1.742260 -0.618863 -0.989924 1.800390 28.577626 4.159555 9.645062 -45.443704 27.666278 1.182027 0.319984 1.965447 0.263362 2.067270 1.615701 1.337617 0.833506 1.729459 0.769145 2.275263 0.848476 1.340030 0.893183 1.226937
+1 0.044908 1 1 -1.303925 2.258745 -0.280105 -0.054175 -1.035502 -0.837430 1.213253 0.640930 -0.415878 -1.184624 -0.131575 -1.277826 -65.590714 -33.122489 -39.665967 -65.910109 -1.196684 1.184927 1.815376 0.275726 0.627572 1.107049 2.420331 2.247401 0.571800 1.995076 0.996151 1.561448 0.759192 1.489103 2.107279 1.293900
+1 -0.021657 1 1 -0.129599 -1.053191 -1.246121 -1.702888 -2.095563 0.264792 1.866993 -1.255578 -0.424790 -0.175400 2.001273 -1.638986 69.883157 26.220613 -10.159710 -54.250210 66.723240 1.637520 1.298692 1.362545 1.286957 2.131929 1.577621 0.323759 2.412059 0.482951 0.464207 0.424262 1.825497 1.636511 2.336310 0.864519
+1 0.004810 1 1 0.228349 1.976858 -1.997000 -1.948445 -1.124348 -0.244847 -1.227108 2.118847 -0.061837 2.146755 -2.242489 0.175962 -63.477492 -66.199845 -70.800030 13.895063 -15.676093 0.353638 0.590290 2.248646 1.235839 2.494055 1.585203 1.752431 2.107668 1.081646 0.724092 1.070146 0.938460 1.692915 0.815811 1.338801
+1 -0.010314 1 1 2.348140 -1.071821 1.364025 -0.607112 -1.405648 -1.523720 -2.037912 -1.541625 -1.381402 0.709805 -2.072328 -0.354033 48.440472 -60.981602 32.222135 57.418571 -66.083320 0.439572 0.386773 1.740819 0.437855 0.777879 0.570237 0.478734 1.585964 1.037950 2.072002 2.382730 0.292171 0.269667 2.292108 0.453776
+1 0.085791 1 1 0.936343 -2.258774 -0.205173 1.118156 -0.165353 1.221792 -1.926284 -0.947111 0.354333 -1.180734 -0.726588 -1.969598 47.540372 -38.971062 63.362345 -69.064439 -66.032403 2.025999 0.971534 1.815622 2.160379 0.495088 1.948652 1.503063 0.480200 1.467279 2.059972 0.448627 1.824235 0.663058 1.273761 0.857956
+1 -0.028806 1 1 1.735367 1.337750 0.760611 -1.119825 0.377271 -2.080548 -1.845611 -2.232949 0.297973 -1.232776 1.107513 0.032750 -29.559307 -3.279604 -70.299469 26.825654 -41.232518 1.450986 0.464750 0.553661 0.885949 1.138910 2.410660 1.718014 1.919783 2.296512 2.479423 0.915861 2.132171 1.145623 0.482586 1.079838
+1 -0.004107 1 1 2.127147 -1.937491 -0.800703 1.165231 -0.659644 1.621231 0.987554 0.789812 -0.433050 -2.334744 0.022187 0.622076 -49.472749 -38.484815 -14.288090 10.079172 50.640906 1.700580 1.401680 2.041793 0.923832 1.086192 0.629394 2.474938 2.037642 0.891699 1.027491 1.795890 1.277409 1.409787 1.047249 0.856891
+1 0.023598 1 1 2.233102 2.275908 0.717696 -1.391054 -1.285977 2.308099 -0.167202 -1.576840 0.522547 -1.452592 1.172176 -1.738676 -12.865551 68.684399 -21.307428 -63.936803 14.151266 0.480039 1.013102 0.708990 1.503195 0.457340 2.011229 2.472002 2.193356 1.231026 0.355013 1.201392 1.791854 0.945668 1.337310 2.415977
+1 -0.011598 1 1 -1.430175 0.938111 -0.817211 1.754659 0.429350 1.418925 -1.534337 -1.410921 -0.615151 0.132207 -2.236832 1.008866 26.538877 -61.089504 18.698198 10.611373 -4.660757 0.874958 0.920428 2.386296 1.722517 1.099880 1.179664 1.117141 1.040784 2.449290 0.711328 0.296533 1.581661 0.721323 1.783104 2.382785
+1 -0.004825 1 1 0.779377 -1.456781 1.463850 -0.463095 1.637153 -0.017694 -0.507329 -1.963364 -2.107079 -0.072265 1.232745 -1.625136 -20.970937 41.454756 -19.910628 12.072907 -40.652671 1.383314 1.599837 2.453874 1.263051 0.847822 1.591330 1.242416 0.537950 2.328609 1.933508 1.211964 1.735041 2.330848 1.310069 1.332198
+1 0.047223 1 1 -0.991827 -1.919233 -0.242546 -0.262206 -0.816386 1.485299 1.904075 -0.038002 2.179050 -1.384802 0.126609 -2.090106 -71.893871 -70.286242 -50.867110 -73.514090 -1.317876 2.131734 0.555191 1.842825 0.353197 2.176603 0.915187 2.043382 0.618926 2.031027 2.229258 1.642306 0.731582 0.947911 0.796935 1.329640
+1 -0.021142 1 1 1.363844 1.071344 0.040744 1.489289 -1.735388 -1.688893 2.202158 0.562479 0.527950 -0.166637 -1.502132 -2.063765 69.869821 -47.921516 -66.912568 -49.534416 -24.932461 2.276808 2.067097 0.954104 1.373521 1.269121 1.622780 1.070414 0.952929 1.872174 0.872602 1.827098 1.537018 1.904818 0.520571 0.489258
+1 -0.003333 1 1 -0.173824 0.224130 1.746889 1.773907 -1.234482 0.717645 -2.249568 -0.987364 -2.313294 -2.324396 -0.425851 0.843275 -61.923878 -54.620373 -4.604037 19.949692 44.480428 1.113193 2.190463 2.105694 1.650173 2.450626 0.674425 1.056844 2.370924 2.115618 1.935347 0.629160 0.784868 1.028383 1.037418 2.133664
+1 -0.005501 1 1 -1.856167 -0.574584 -1.347361 -2.062000 -1.127840 2.340142 1.171677 -0.703896 -2.288606 -2.079317 -0.009004 -0.529281 43.200478 70.431221 -62.462867 36.589261 -44.284334 1.573101 0.861332 1.401853 0.449939 1.379763 0.428629 0.971365 1.223318 1.298975 1.621325 1.365579 0.542260 0.517761 0.512247 2.341031
+1 0.046022 1 1 1.502847 -0.056278 1.323892 -1.247654 0.803317 0.357194 -0.227831 2.020508 1.207723 1.935647 -1.908051 -0.801209 66.432676 -66.016906 3.868962 -74.347455 -57.677488 2.342000 1.991938 2.244636 1.345863 2.170683 0.413047 2.322999 2.150615 0.628854 2.405094 0.413989 2.417998 1.301320 0.534688 1.503419
+1 -0.000032 1 1 2.117476 0.466513 -0.728777 -1.054607 -1.489356 0.595473 -0.996961 1.335440 -0.365866 0.556964 2.096214 1.242960 13.091339 -23.866561 -25.282645 24.580910 31.350235 0.675922 1.474909 2.050417 1.855351 1.634862 1.625915 2.002619 1.769862 0.319950 1.393091 1.674724 1.077749 0.478916 2.387203 1.215031
+1 0.050568 1 1 1.915947 1.569301 -0.003280 1.422663 0.036192 0.378388 -2.155736 2.099627 2.063264 -1.189934 0.149243 1.341422 38.551816 -59.622205 -70.393091 -46.681930 66.808832 0.715712 1.975910 0.624843 2.486785 0.890939 1.765675 1.943748 2.327043 0.363633 2.083306 1.121139 0.726755 0.825792 0.336255 0.936963
+1 -0.003698 1 1 -1.656412 1.482849 -1.590856 0.577478 -1.842573 1.689789 -1.288489 -2.209097 0.615985 -0.265551 -0.476048 0.702951 16.914902 38.756657 -66.865370 -6.268107 -48.071178 0.890626 1.000133 0.977574 2.094297 1.348126 1.949811 0.725373 2.344189 0.538607 2.110890 1.230039 1.764487 2.241179 1.745338 2.138413
+1 -0.040146 1 1 -1.371276 1.263975 0.175436 -1.404024 2.218332 -0.910905 0.968077 -1.411954 0.879951 1.864661 1.972368 -2.073871 63.343890 70.765981 13.847469 -65.585816 49.196437 2.042806 2.188143 1.370326 1.570700 0.998861 2.110677 2.141398 0.979415 1.521582 1.233046 0.561508 2.267404 1.515816 1.073898 1.000520
+1 0.036752 1 1 -0.754334 -1.768203 -1.856600 1.560353 0.407219 1.743821 2.046304 1.212092 -0.024377 0.277240 -0.974186 -2.306837 -69.754413 37.582263 -4.902509 -46.470862 14.217921 1.533866 0.687078 2.211860 1.725808 2.405100 0.517832 1.694256 0.861636 2.019301 0.892317 2.420800 1.137015 2.066809 0.613880 0.479791
+1 -0.019670 1 1 -1.006137 -2.096755 -0.917548 -2.285413 -0.248802 -1.733912 -0.447624 -2.244652 1.516706 1.960618 -1.636719 -2.115177 15.216186 -11.562522 68.695392 13.452019 38.089229 0.860109 1.098929 0.953159 1.236981 1.448721 0.652798 2.071851 2.106037 0.672265 0.752831 0.328242 1.264165 1.564709 1.566280 0.960131
+1 0.000825 1 1 2.226275 0.629657 -1.382646 -1.340047 -1.662447 -0.989000 -1.523379 -1.014436 -0.208193 2.210046 1.195734 -1.639584 50.004967 -16.525706 52.452333 16.355335 -65.889184 2.132224 2.041233 0.509373 1.274883 1.714344 0.986833 2.453058 1.047337 2.341216 2.325282 2.271558 1.571193 0.299829 0.731831 0.625936
+1 0.006013 1 1 1.045473 -1.240995 -0.373812 -1.047697 1.559770 0.030420 2.322548 2.342041 0.104632 0.827075 -0.901970 0.353110 58.008725 -47.360066 69.366675 45.704500 5.535653 1.940891 1.561293 0.406920 0.608777 2.459847 0.395711 1.207251 1.258724 2.380319 0.272502 0.443362 1.083966 1.471540 1.678195 0.917040
+1 0.022827 1 1 -1.800677 -1.016100 0.100095 -0.023594 -0.706724 2.026491 -1.919914 -2.271278 1.687502 -2.019124 -1.497970 1.919875 51.117707 -64.700248 -67.071956 -28.372653 -9.171031 2.312203 0.698681 1.484776 1.381060 1.974860 0.975592 0.272090 0.262153 2.009187 1.897085 1.051735 2.014324 0.501148 0.286864 1.076099
+1 0.021887 1 1 2.017622 -0.169975 -1.057643 -0.665627 0.018554 0.824375 0.850193 1.237424 1.604277 -1.210985 -0.219910 -1.519206 -49.798332 39.439107 3.077925 -19.317101 -62.522925 0.282984 1.113482 0.294809 1.859363 1.568192 1.602865 1.600458 1.641699 1.791115 2.020295 1.847373 0.305005 2.211817 1.010094 1.905912
+1 -0.001475 1 1 -0.445475 0.892246 1.152623 -0.498710 1.514761 2.256630 1.879284 -2.016779 0.214914 -2.344811 0.474239 1.887275 10.950323 -7.923662 27.006069 -8.991447 -69.257005 1.337843 2.374583 0.620960 2.476006 1.981867 1.732744 1.981969 1.211188 2.188059 2.202088 1.746381 1.680512 1.608983 0.925197 1.533122
+1 -0.024030 1 1 -1.997710 0.254802 -1.112508 0.838268 -1.272761 -1.757950 0.816967 -1.137378 2.257446 1.443591 -1.651465 -0.205302 -33.251092 48.890807 7.795236 64.529030 39.402070 1.083821 1.282877 1.062445 2.009966 1.501297 2.300571 0.941931 1.531923 1.784676 1.807294 1.694374 0.595715 1.177049 2.158757 2.483044
+1 0.017179 1 1 1.471447 -0.016155 1.794192 0.414937 -0.484624 -2.060828 -0.272486 0.771567 -0.762434 -1.242359 0.272298 0.789902 34.629526 18.440247 25.229340 -20.482617 -1.342117 0.520627 1.430617 2.383266 0.298111 1.104395 0.559451 1.436958 0.948297 0.532328 2.334510 2.105878 2.488990 1.956397 1.165725 0.837110
+1 0.002920 1 1 1.225230 -0.703020 -1.691265 0.045818 1.950889 -0.217766 1.525048 0.790864 -1.599986 -2.072731 2.297975 -0.683015 -1.845988 24.485691 -68.988099 17.013964 53.696582 0.301856 1.037308 0.283240 0.917361 0.338149 1.277046 2.063402 1.845254 0.690943 1.928809 0.995931 2.369617 0.398382 1.113333 2.292999
+1 -0.019228 1 1 1.960013 2.344298 0.328265 -1.062026 1.062822 -1.816944 -1.103516 1.171730 0.198026 1.276830 -0.532927 1.352764 -43.428914 -9.764274 -8.155350 33.034785 65.629972 0.518968 0.545537 1.597934 1.981316 1.487106 2.289404 2.269642 0.877287 1.806391 2.265888 0.781892 0.509466 0.602292 1.471314 2.367324
+1 0.017875 1 1 -1.094304 0.495535 1.665591 1.990911 -1.424330 0.225368 -1.002171 -1.405215 1.049417 -0.917563 2.164938 1.749322 8.435733 29.373586 31.867229 -57.474587 24.608665 2.092444 1.712909 1.618935 1.691476 1.385453 1.557016 0.517937 1.209046 2.179213 2.041317 1.921852 1.070274 0.846078 1.536692 0.935765
+1 -0.019143 1 1 0.446880 -0.840717 -2.194768 1.113227 1.828282 -1.551057 0.314408 1.673299 -0.402390 -0.696140 0.834079 -0.988906 1.744079 62.733354 9.474327 -64.982776 -15.510193 1.677876 2.318963 1.802338 1.649915 0.368678 1.370807 0.660673 1.677016 1.353531 0.547740 0.366534 1.331745 1.132502 0.460338 0.645134
+1 0.044788 1 1 0.101938 -2.044047 -0.982300 -2.021125 -2.147915 1.605986 -0.750417 -1.905708 0.874056 1.740503 -1.874067 0.162510 -59.712500 62.015994 -47.182522 53.355831 51.456551 0.328734 0.526938 1.748573 0.257944 1.017398 0.904993 1.715933 0.690256 1.636985 1.300165 1.376987 1.016755 1.355085 1.907870 2.315354
+1 -0.002673 1 1 -0.996448 0.535223 -0.459079 -1.568370 1.505752 1.646819 2.233857 0.835727 -1.570998 -0.239949 0.980292 1.256406 6.539377 -42.688758 -19.955387 9.808163 -4.195651 1.130333 2.249443 1.144605 1.371494 0.949416 1.329778 1.826566 1.585878 1.847683 1.001694 2.474300 0.305019 2.446884 0.780446 0.950666
+1 0.001239 1 1 -1.050752 2.053968 -1.913738 -2.140341 1.673347 0.410760 -0.012123 -1.116173 0.510146 2.185030 0.143080 1.427196 26.408851 3.563190 36.537217 -18.998494 42.314924 1.928805 0.921937 0.745599 0.277864 0.555661 0.745153 1.781343 2.026253 0.725966 1.053217 2.163636 1.238765 2.167636 0.959409 0.539424
+1 -0.005415 1 1 -0.619966 -0.679583 1.082842 0.086553 -1.429195 -1.437596 -1.266799 -0.514346 -2.091886 0.812466 -1.381319 2.114119 18.689612 16.308776 51.601460 -34.266760 -71.437193 0.701445 0.680355 1.720373 1.064920 0.860179 2.276553 2.279718 1.475306 1.960759 2.473052 1.836919 2.350633 0.847631 0.633897 1.649928
+1 0.044194 1 1 0.989682 -1.142428 2.195118 0.058362 0.710378 -1.874364 -0.116266 1.554955 -0.782367 -1.669145 -0.471559 0.746629 -16.051319 -74.516944 -56.274369 -53.319409 -39.312775 1.677947 1.260938 1.336317 1.479498 0.430395 1.402983 1.442149 0.439677 2.147072 1.838590 1.181318 1.906902 1.794509 0.559964 1.063998
+1 0.003439 1 1 2.086133 1.468600 -0.729112 -1.966776 1.800275 -1.031558 -0.511675 0.391507 1.567768 -2.205628 -2.345264 2.290673 -28.126914 70.958989 -42.268435 -5.580222 -36.792980 2.430665 0.445119 1.357489 1.811282 1.213585 1.980796 1.741573 1.861502 1.508185 1.059945 0.487165 1.527401 2.284248 1.115358 0.319720
+1 -0.013264 1 1 0.906948 -1.504644 -1.866064 -1.995387 1.601974 -2.213801 1.674609 -1.946071 1.070531 0.520251 -2.330713 1.790871 36.307814 25.423259 -61.290142 -53.422915 21.062606 1.363347 1.280987 0.797801 2.384016 1.664968 1.363625 1.438039 1.115368 0.497469 1.456031 2.010369 1.530766 0.337830 0.401498 1.734962
+1 0.046860 1 1 -0.968025 2.283560 2.100857 -0.825205 -0.659648 1.546657 1.131717 1.572250 -2.273552 1.174317 1.268733 0.036732 0.858625 30.915295 -6.643428 -56.100931 11.655258 1.223738 1.615863 1.818085 0.802802 0.942069 1.606496 1.875435 1.688882 0.539258 1.805036 1.996654 0.506576 1.523519 2.284775 0.962620
+1 0.035040 1 1 -0.271575 1.938571 0.102965 1.093614 2.044360 1.536208 -0.128457 -0.702294 1.078368 0.276184 0.115632 1.929054 12.195723 73.510741 -54.973284 64.009840 13.374055 0.291067 1.971477 0.364182 2.308781 1.689477 1.540090 1.789162 0.690357 1.073853 2.494639 2.403514 0.860915 1.140751 1.854534 1.397277
+1 -0.006172 1 1 -1.661511 0.608293 -2.300839 -0.340552 1.898869 1.992004 -1.920550 1.176403 -1.372911 2.055329 2.097883 1.021896 -52.779337 37.678596 -35.843108 -15.123883 62.892914 1.243148 1.593174 0.733306 0.680475 1.494760 0.425161 1.182930 2.001639 1.052074 0.951099 0.377039 2.398163 0.923670 0.618157 0.357874
+1 0.007296 1 1 0.640224 1.858696 0.684285 -2.155371 -1.185145 0.527240 2.039229 0.108071 2.072874 0.095522 -1.487629 1.350130 46.953544 -1.785864 -15.022816 -38.471119 65.902257 1.663521 1.790772 0.747745 0.350208 1.448276 2.173463 2.149426 0.896138 1.389828 0.847068 2.425414 2.188561 1.647400 0.851846 1.732908
+1 -0.017539 1 1 1.413877 -1.550194 0.679769 2.042187 -2.012022 0.042648 0.502792 1.108122 0.838253 -1.529747 0.337613 0.544190 -17.321739 23.540180 -60.190611 -23.600639 -55.937041 2.367183 2.243139 0.946358 1.683054 1.591335 1.312272 2.361363 1.172814 0.729923 2.309134 0.859998 1.489331 1.436816 0.812092 1.831487
+1 -0.045901 1 1 1.741717 -0.327602 -1.940393 2.260148 -0.263909 -1.158529 0.192103 0.682736 0.076219 -0.760462 -1.083298 1.679649 -65.878170 -64.398539 53.756735 39.439247 5.423488 0.663370 2.010882 1.144652 2.168598 1.375831 1.848435 2.404527 2.129857 0.512371 2.175289 1.327416 0.375008 2.016296 2.141785 0.729036
+1 -0.048949 1 1 0.753546 -2.059211 -1.367554 -2.157848 -0.407235 -2.002134 1.296344 2.276599 -1.792362 2.070798 -1.806788 -0.051675 -45.517129 -6.386235 66.546034 39.188251 -13.058415 1.033244 1.741033 1.786234 0.978845 0.951756 2.416452 2.308504 1.521543 0.569227 1.506509 2.146285 2.114264 1.689163 0.765514 1.995496
+1 0.054433 1 1 -0.475421 1.817147 -0.205025 -1.091238 0.188396 -0.350254 -0.943736 0.533057 0.840174 -2.231745 1.684928 1.843549 17.955694 -18.647111 -51.999184 -50.292748 -20.218628 0.407767 1.338331 1.579933 0.929187 1.102520 0.558453 0.424477 0.938457 1.642376 1.910544 2.267433 1.993769 1.520851 2.439744 2.271747
+1 0.028408 1 1 1.331025 0.829027 -1.076755 -1.444239 0.191031 1.522502 0.418718 1.794830 1.704687 -0.656164 -1.158932 -1.872926 15.486441 30.621144 -0.430189 -30.189907 48.233536 2.290555 1.365957 2.397309 2.326538 0.872995 1.676741 1.230518 0.820897 1.319529 0.574768 2.373664 0.925851 1.281470 2.168872 1.477572
+1 0.011961 1 1 1.010160 -0.984331 1.538558 1.670359 2.021712 -2.124866 -2.142994 -0.507290 -1.316694 -0.299513 -1.091464 1.098033 29.381424 13.585024 23.499862 12.181207 -20.450102 0.551994 2.115524 0.354839 0.533226 1.684670 1.739517 1.058508 1.092342 0.492943 1.901155 1.960041 1.659886 1.448703 0.342874 1.925441
+1 0.040010 1 1 -0.356420 -0.897018 -1.255157 1.948526 -2.220534 1.609774 1.650006 -0.760541 2.306800 1.565051 -0.738924 -1.943877 8.192294 -12.116866 51.829717 52.053923 70.286368 2.169756 0.593633 2.196659 0.497189 1.248299 0.419855 1.995050 0.557837 1.320508 1.272024 0.903127 1.861340 1.039410 1.858104 0.648906
+1 -0.023067 1 1 -1.967784 -0.995094 -0.277884 -0.426353 1.820926 2.051083 1.432940 -1.600370 0.897595 1.519359 -0.570986 -2.142225 -54.817063 -10.380235 -10.615206 -59.758871 32.648143 1.635059 0.437191 0.871365 1.275741 0.386228 1.582294 2.359525 1.790274 1.379421 1.431965 0.285434 1.781192 1.745933 0.888294 2.313314
+1 -0.026545 1 1 -1.282878 -2.155708 -2.129364 -2.339101 2.198075 -2.078401 1.248026 0.730737 1.019306 1.934703 1.068668 2.192106 40.306933 38.618993 19.408259 -55.383116 -74.023139 1.271651 1.392447 2.102328 1.328736 2.311022 1.095640 1.919122 2.438722 0.856312 0.283190 2.319560 0.592827 2.136013 0.464549 1.668303
+1 -0.053458 1 1 -1.680190 -2.311894 2.352482 1.221930 0.380726 -0.554749 2.143718 -1.455456 0.164062 0.640982 0.465649 -1.108226 67.573490 57.643529 -35.214420 51.248253 29.396547 0.891389 0.328107 1.251524 0.615352 0.478508 2.278404 1.877867 2.060332 2.008949 2.400101 1.999682 1.898141 0.803561 2.446155 2.032188
+1 0.015660 1 1 1.785451 -0.418341 -0.175544 -0.404394 -1.388499 -0.744880 1.621057 -1.927807 1.736638 -0.854850 0.607538 -0.847639 -23.062825 -16.896127 -23.205666 -17.631375 69.473422 1.972115 2.093477 1.067152 2.365359 0.844346 1.669206 0.592241 1.290935 1.496830 1.465018 2.307046 1.774815 0.319664 1.085708 1.496436
+1 0.011621 1 1 -0.671651 -2.274311 -2.157601 -0.964954 2.066411 -0.140225 -0.569630 1.798769 1.935548 1.129319 -1.044953 0.546479 7.026859 50.425730 5.247725 -1.477680 64.639757 0.630994 2.363312 2.439693 1.420600 0.518517 1.959526 1.999687 1.993073 1.074046 1.249812 1.093625 1.810042 0.623559 1.151795 0.723152
+1 -0.000717 1 1 2.024096 0.246120 -0.939934 -1.538261 -1.388411 0.731241 0.058583 -0.290650 1.797335 1.387824 -1.171513 -1.254227 -40.848634 7.005954 -0.935596 25.441043 -62.395231 0.975394 1.450318 0.501234 1.736570 1.030979 1.921667 2.455254 1.951793 0.278773 2.344857 0.509642 1.302912 0.282821 0.629845 1.052709
+1 -0.013346 1 1 -2.134644 -1.538446 0.223328 -2.307895 -1.122566 1.434598 -2.006429 -0.198899 -1.807565 1.033748 -0.375840 -2.141504 31.065595 -30.543832 -50.181984 41.388174 61.034007 0.603262 2.026779 0.576679 0.750339 1.193920 2.219892 1.728958 1.345141 1.281426 1.431569 0.381396 1.367179 0.433962 0.606257 0.612312
+1 -0.045495 1 1 -1.343298 0.237142 -1.042780 -0.625572 -0.652904 1.794974 -0.577067 -0.665930 -0.363673 -0.285113 0.603302 -1.369816 70.884553 56.684874 52.677535 51.333079 -44.940290 0.453312 1.811593 1.941620 0.302120 0.985812 1.046252 2.104694 0.593810 0.658408 1.855431 0.731588 1.056579 2.416238 0.970638 0.258711
+1 0.063233 1 1 1.283629 0.631328 -1.576677 -1.443433 -0.394804 -0.422836 -0.327910 2.318957 -1.453186 0.609718 -1.919706 1.224256 56.718228 13.254147 12.446184 -66.989289 11.025855 2.298277 0.636671 1.026020 1.817899 2.184859 2.418420 1.629989 0.728703 2.065553 1.998496 2.223905 1.671533 1.451103 2.438052 0.833875
+1 0.039244 1 1 -0.884144 -1.639484 -1.463171 -2.276658 0.800487 -0.078750 0.630881 0.350215 0.289174 1.669212 1.594914 1.654282 13.427630 -71.827818 -10.132980 -55.002136 29.107566 2.287978 0.789819 0.988247 1.472503 2.101978 2.187340 1.379659 0.933192 0.913853 2.124362 0.396553 1.872038 0.837844 0.401952 0.358605
+1 0.075028 1 1 0.106537 -0.138806 -0.275057 -0.025520 -0.093240 2.136757 -0.640528 -2.250070 -0.009529 0.070082 -0.221532 -0.499670 -14.960661 -43.822220 -20.058191 -68.008812 -24.108004 0.876625 1.942737 1.088089 1.011933 1.303244 1.373643 1.069570 0.253856 2.058888 2.482954 1.759430 0.482487 1.651951 0.831636 1.798600
+1 -0.044100 1 1 -0.044428 -2.151994 -0.983887 -0.422596 -0.998152 0.158706 0.164636 0.866349 -0.556787 0.879411 2.205674 -1.595946 -4.641862 -15.780021 -14.820211 66.708578 71.068140 1.258476 0.457101 0.252535 2.356533 1.002709 1.528179 1.861325 0.789797 0.624773 1.311661 1.090703 2.193251 1.720428 1.975921 0.806025
+1 0.069015 1 1 -1.034774 1.975906 0.841747 0.654376 -0.623336 -0.775325 -1.126451 2.119379 -0.546649 1.634913 0.046344 1.357020 -16.810099 72.658922 28.502221 -63.169897 3.534587 1.462143 1.236232 2.356658 0.855281 0.950924 1.931245 1.429701 0.491830 1.189726 1.482699 2.476883 0.978272 0.325475 2.002023 0.746508
+1 -0.068580 1 1 -1.395141 0.715310 0.917266 2.273322 -0.327046 -2.023646 -2.099656 2.169821 -1.001773 0.572849 0.462883 -0.471378 -29.415623 11.618243 -32.197133 62.777630 3.621169 0.789842 1.371021 2.005530 1.185977 1.462655 0.842898 2.093817 2.283704 0.959650 2.344994 0.565866 1.253326 1.647731 1.919494 1.939242
+1 0.002110 1 1 -1.340742 0.796569 0.033935 0.138933 -2.291602 -0.594092 0.647631 -0.889504 -2.196931 -2.248091 0.272345 1.575613 -73.214684 -69.192147 37.590915 -9.498743 -45.366287 1.057261 0.381956 1.777183 1.867385 1.392977 2.013829 1.179858 2.127843 0.412342 1.733577 2.480454 2.493848 0.352200 1.181538 1.109809
+1 -0.028661 1 1 -1.210731 -0.655037 -1.071623 -0.022371 0.998919 -1.409577 -1.588764 -1.967206 -0.705923 1.340377 -2.221788 -0.618692 59.942054 46.093301 -59.891727 49.748601 24.729309 1.007386 1.390952 1.722721 2.275934 0.865842 0.702873 2.190572 1.686413 1.792077 2.441877 2.122671 1.237526 1.592172 1.889347 1.513607
+1 -0.003721 1 1 -1.115981 -0.992130 -2.296076 -0.388271 0.991218 1.114025 1.090129 0.032877 1.217208 1.136928 -0.396792 -0.850759 -41.806365 -39.583575 -31.147551 3.117321 42.813695 1.671630 0.838753 2.174261 2.047432 1.192003 1.485625 2.145146 0.972552 0.928652 1.096404 1.264125 0.906014 0.885647 0.571596 0.816469
+1 0.000284 1 1 -1.376682 -0.067750 1.726333 0.305542 -1.251790 1.978878 -1.031465 1.046101 -0.112268 -1.930715 -0.017797 -2.238887 -17.368808 -17.551964 54.145652 -24.029976 -71.799410 1.634791 0.425293 1.152269 1.935299 2.064499 2.286309 1.998087 2.092548 1.209579 2.143648 0.548270 0.275270 1.967144 1.781743 2.008881
+1 -0.019553 1 1 -2.147745 -0.246326 2.189797 0.154223 0.209989 -0.302345 -1.563330 1.401599 -0.556792 0.803067 0.871025 -2.081402 -65.507825 9.992762 -51.647566 9.355243 33.573553 0.935466 0.874939 0.591609 1.924780 0.781609 0.258575 0.363760 1.961147 2.246517 1.457359 1.832310 1.375530 1.279502 0.582013 0.397311
+1 0.038264 1 1 1.509618 0.648883 1.304884 -0.266679 -0.589321 0.725085 0.272776 -0.603434 -0.846467 0.127863 0.148319 -0.063906 11.427250 57.782687 53.627553 -31.720808 -31.612037 1.322439 2.235917 1.055643 2.444082 0.937055 0.584014 0.278703 1.163552 0.327437 1.241185 2.340559 0.275797 1.822084 0.509271 1.816039
+1 -0.032626 1 1 -0.121906 1.020196 -1.954007 -0.352713 0.145819 0.333062 -0.539013 -1.978261 1.981468 0.073062 -1.983991 -0.070350 13.724541 -31.647514 0.233440 23.428760 17.170928 1.251908 0.318785 2.065935 1.664755 2.289723 0.871505 1.389495 1.988039 1.963026 2.321632 1.665578 0.363453 1.296894 0.392397 1.768693
+1 0.022480 1 1 -0.895305 -0.741074 -0.390735 1.979092 -2.147524 -1.249788 -2.062359 2.271153 0.919283 -1.540618 1.408176 1.598717 -13.185457 -57.979628 -63.612381 66.710336 -49.389272 1.592463 2.274951 2.346317 0.303474 1.245538 1.253155 1.030175 1.901416 1.854907 0.928666 1.344960 0.489855 1.736541 0.540524 0.593097
+1 -0.040123 1 1 -1.867636 -0.134635 -0.859491 -1.993645 -2.111238 0.708449 -1.303662 1.955135 0.467904 -0.922101 1.299111 1.652254 -21.367021 -15.528540 11.830073 -71.960235 14.332873 1.264035 1.634339 1.842152 0.295506 2.315307 1.111376 0.889101 2.375351 2.278916 1.500382 0.411512 1.288149 1.925345 1.267087 1.176657
+1 -0.033859 1 1 -0.916457 1.913053 0.051272 -0.646425 2.296338 0.084292 -1.729393 0.110100 -1.519339 0.912688 0.717232 0.229763 69.401076 23.883399 8.288071 -52.392759 -65.097001 1.595509 1.720417 1.804441 0.997318 0.929053 1.089334 1.684336 0.633234 1.765883 0.942881 1.747317 1.664061 1.878701 0.322341 1.088906
+1 0.030734 1 1 -0.558642 -2.021935 -1.625884 0.910627 -0.933108 0.092573 0.793006 1.419963 1.774525 -0.276697 0.679790 -2.306667 21.151997 1.606661 3.156915 -41.728519 68.787358 2.261859 0.567605 1.240344 1.717893 2.133053 2.468295 0.628178 2.284855 2.302690 0.566452 2.115185 1.415353 2.329491 1.006127 0.469676
+1 -0.032739 1 1 -1.047609 -1.676941 0.454436 -1.069658 0.028628 0.494362 0.803340 0.743521 -0.895431 1.859109 -1.807585 0.695403 28.886378 -56.650049 -67.380945 28.460765 -9.918290 0.674377 0.254457 0.906501 2.313368 2.268547 0.467295 0.572729 1.849673 0.700618 0.288600 1.001415 2.279458 1.607241 0.893134 0.397221
+1 -0.005553 1 1 0.527342 -0.965464 -1.804196 1.098510 -0.483826 1.911859 -1.160610 -1.791235 2.172785 1.702715 -0.807295 -1.243871 -50.323914 55.981261 -72.951937 -3.206337 -38.907139 0.440808 0.909937 1.559611 1.381107 0.516488 1.608440 0.805923 1.649685 0.999292 0.345083 0.805860 0.581855 2.233477 0.554922 1.831860
+1 0.051855 1 1 -1.772407 -1.840722 -0.178014 0.485377 0.578271 2.050967 -0.518244 -1.631857 -0.514099 2.060203 -0.809882 -2.310706 -39.130187 -61.057123 -37.067823 -48.907834 6.036703 2.257939 2.188510 0.786973 0.403187 0.861589 1.226423 1.746307 0.429016 0.730125 1.217138 0.937152 2.210289 2.324737 2.104774 1.937613
+1 0.009589 1 1 -0.505934 -2.074849 -0.307765 1.600069 -1.237335 -0.124062 -2.233172 1.254781 1.156562 -0.258887 -1.583288 0.542642 54.628828 -3.289837 57.707849 -4.183470 38.426658 0.427511 2.423034 0.433261 2.313376 2.414493 0.883968 1.600777 0.257333 1.994061 1.939507 0.789418 0.998699 1.626617 0.296257 1.443962
+1 -0.024589 1 1 -1.594673 -2.308113 -0.064189 0.313530 1.042949 -1.237841 0.799264 -1.795309 -0.340007 1.625163 1.114005 0.768196 -27.956392 -63.083677 -47.360708 58.587416 -71.291109 1.529881 1.208491 1.856552 1.569610 0.690528 1.704229 1.971614 0.419367 0.547554 1.747780 0.443934 1.700845 1.343317 2.130396 0.567494
+1 -0.000923 1 1 1.707728 -1.371648 -0.283209 -0.387953 1.622724 -2.187707 1.979662 -1.995735 0.470917 -2.113385 2.320895 -1.877987 7.996650 -0.306039 -43.594555 56.314395 -23.967760 2.482816 1.687164 0.912491 1.735032 2.173878 2.372421 0.284053 1.080001 2.321245 1.905602 2.448391 1.350990 0.598001 1.347421 1.360882
+1 -0.033096 1 1 1.656490 -0.168450 1.002899 -0.492289 1.051135 -0.315778 -1.131598 0.432891 -0.334917 -2.351674 -1.785341 2.268398 55.097718 -72.661142 -65.817567 54.149810 45.849719 2.068397 0.300099 0.760774 1.084335 0.912823 0.558754 0.986420 2.264841 1.180468 1.122195 0.477630 1.025782 2.311248 0.400752 0.440762
+1 0.010704 1 1 -1.764098 1.152683 0.514961 -1.708009 1.372023 1.873987 -1.510101 0.654279 -2.244547 -1.426064 -0.649336 0.505390 -74.733691 50.854013 3.389237 -37.088328 56.478736 1.946664 1.837808 1.541464 2.384979 2.090265 1.086487 1.094186 2.239874 2.307968 1.514599 0.864779 0.832783 0.841224 0.953349 2.190154
+1 -0.010728 1 1 -1.754432 -1.322316 -0.547708 -2.034017 -2.046501 0.181016 -1.864975 2.177926 -1.437959 2.064776 0.651534 -1.253532 31.224787 -55.007932 -68.313122 -38.637185 -25.161419 0.805553 2.171810 1.363803 2.193018 2.305468 2.255656 2.061421 2.304586 0.919372 0.388732 0.913012 1.495938 2.224881 2.331633 1.004917
+1 -0.048209 1 1 -0.109845 1.099480 1.686780 -0.020529 -1.029906 -1.021074 1.326608 1.981950 -1.249647 0.298572 -0.596298 1.271300 24.189863 59.029079 1.735645 70.980588 20.747921 0.779508 0.948556 0.376515 0.330343 0.579871 0.397042 1.083251 0.700760 0.415754 0.578803 0.445403 1.643036 1.749140 0.794119 1.254388
+1 0.037454 1 1 -2.052521 -2.031412 -0.681595 0.245948 0.879850 0.156965 -0.827755 -1.099507 -2.143034 -1.176310 -1.766619 1.205885 -21.751336 -24.701527 41.435425 -44.815696 -67.394737 0.574914 0.327701 1.164701 1.636298 1.004238 2.472535 2.148035 2.276126 1.846397 1.890872 2.383158 0.735231 1.519994 1.531631 1.367024
+1 0.075091 1 1 1.849417 0.230266 1.204824 0.338693 -0.151962 0.094192 -0.274217 -0.043758 -0.311208 0.287000 -1.881047 0.660595 7.272595 -19.488860 50.733687 -68.920318 -43.777378 1.129001 2.362560 1.049275 1.166859 1.890106 0.764893 0.554748 1.142739 1.520370 1.102694 1.222956 1.971977 2.021317 1.022916 1.399112
+1 -0.016152 1 1 -2.010804 1.672464 -0.302314 -1.032577 1.214560 -0.951729 -1.863916 1.122259 -1.885129 -1.968115 -1.843680 1.933301 34.175066 30.333126 -41.150711 30.006953 26.860333 0.499158 0.591445 1.407844 2.129105 1.364065 2.081457 1.548840 0.361043 1.291981 1.080592 1.004386 0.469397 2.161662 1.803276 1.665285
+1 0.014513 1 1 -1.355468 -1.655798 -2.338068 0.704190 -2.205122 1.444796 -0.260601 -2.109946 -1.144294 -0.887866 1.770427 1.538342 -62.507691 33.229218 33.459236 -0.623492 20.976601 2.180961 2.158310 1.722946 1.560320 2.042534 2.117183 1.251312 1.554693 1.973912 0.786735 0.904460 1.759493 1.549154 1.134403 0.914405
+1 -0.003804 1 1 -0.397717 -2.262836 2.210323 1.145275 -1.478843 -1.771300 -2.074609 -0.978635 -1.672977 1.109538 1.088938 -1.139062 70.618215 -69.658678 -3.400351 0.308503 -64.984777 0.637787 1.785328 1.510545 2.472321 0.795694 0.734155 1.439684 1.761525 1.947204 1.903550 1.706431 0.732589 2.119105 2.044465 0.828823
+1 0.041297 1 1 -0.438218 0.335109 0.866290 -1.544495 2.229490 -1.875885 -2.110459 -0.331426 -0.241129 -0.003149 -1.089781 1.115625 -9.335192 3.436169 1.689950 52.995408 -6.173213 2.077071 2.084350 0.673574 0.253242 0.738940 0.861286 0.636517 0.685406 1.113108 0.761553 0.679602 0.313966 2.079478 2.030095 2.309701
+1 -0.011637 1 1 -0.087233 -0.575675 -0.830524 -0.517243 1.049513 0.695865 -0.739695 -0.766952 -1.773934 0.773581 0.094118 -1.518984 68.823991 74.809546 24.045104 26.069929 7.302722 1.927695 0.265784 2.286770 0.746351 1.666450 1.529560 0.311918 1.401845 0.303659 2.089849 0.848453 0.956411 1.904075 1.537563 2.072165
+1 0.028075 1 1 -1.257288 -0.884621 -0.229625 0.136301 0.583695 -1.028011 -2.167597 0.671344 1.815998 -0.659926 1.595605 -0.881225 9.460727 6.443414 -5.535587 -36.606138 60.637928 1.999904 1.133731 0.875028 2.100183 1.274018 0.674390 0.479416 1.795799 1.993847 0.593276 0.695575 1.030841 1.838360 1.818324 0.314665
+1 0.017068 1 1 2.323602 1.215121 -0.959892 2.310118 0.787158 2.096526 1.777727 1.710635 0.362356 1.704321 -2.087395 0.892140 -19.802782 24.640070 -24.340074 -33.618969 15.984742 1.458297 1.851166 1.045094 0.651156 1.473205 0.406445 1.626854 2.042395 2.039934 1.174630 2.006085 1.520683 1.871018 1.700813 0.822415
+1 0.001017 1 1 1.879328 -1.273887 -1.831834 -1.600230 -1.459691 -0.325365 -2.036259 -2.041030 -2.110998 0.035625 0.269971 -0.632249 7.236269 -30.024317 -18.696251 22.114982 -13.501233 1.896567 1.356459 0.256328 0.859266 0.441344 0.921688 1.061146 0.435402 2.297392 1.521631 2.050613 0.643471 0.566177 1.984547 1.787820
+1 -0.022556 1 1 0.729045 0.841503 1.265351 -0.259568 1.104611 -1.622292 0.016848 0.423001 -1.619629 -2.350230 -1.071764 2.332886 55.329210 68.028937 62.343335 54.430273 -40.397731 0.405082 1.210159 0.647844 2.066309 1.200652 0.613488 0.642527 0.457302 1.367344 0.943750 0.598992 2.261360 1.178432 0.655434 1.372473
+1 0.044552 1 1 -0.865345 -1.414189 1.006871 0.298055 0.142291 2.308669 -0.019875 0.539364 -1.546532 0.969055 0.896808 -2.275046 -11.855012 -47.193493 18.962658 -44.600996 -58.944664 2.380440 2.311117 0.439302 0.347193 0.272566 1.521388 2.460634 2.376534 1.908654 1.991431 0.473604 0.862298 1.886794 1.339401 1.565170
+1 -0.025709 1 1 -0.280994 -0.853624 -2.345767 -1.464497 -0.996049 -2.186895 1.494402 -0.625680 2.248780 1.892772 -1.514354 -0.132850 27.380728 -12.107227 63.832039 25.076482 -39.566590 0.689830 1.224671 1.546039 0.532972 1.910550 2.368616 1.580063 0.864259 1.097974 0.652976 0.560084 0.838155 1.123964 0.961601 1.383762
+1 0.030861 1 1 0.689693 -0.805870 -0.845367 -0.231529 1.123830 0.959021 1.896837 0.820710 0.507356 -2.295980 1.212618 -0.607366 -30.506417 -21.358650 -24.832334 -57.044920 46.037930 2.267267 1.461741 1.230606 2.299271 1.597327 0.775512 1.278309 0.792313 2.405410 1.232219 2.396562 1.019095 2.432884 1.725956 0.394584
+1 0.036342 1 1 -0.888164 1.479590 0.196246 -0.372852 0.957942 -2.109258 0.997072 0.538404 1.176114 -1.522014 -1.644283 -2.007317 -31.340495 60.295654 -10.937158 -70.812748 -49.851690 2.014572 2.415913 2.246020 2.109180 1.742333 1.140787 2.452670 1.271389 1.490413 1.627818 2.486905 0.655183 1.652942 1.752002 1.641558
+1 0.009437 1 1 0.753433 0.756505 0.546473 0.128110 -0.408810 -0.214812 -0.654940 0.563749 -1.678296 1.240178 0.777677 -1.754446 -49.382080 -14.614413 -74.443181 -16.537564 3.165188 0.584651 1.978133 1.973723 2.113410 0.836537 0.930825 1.629426 0.266910 0.963702 0.682458 1.069802 1.910697 0.341582 0.475938 1.839459
+1 0.023450 1 1 -1.996949 -1.096238 0.966400 -1.318424 -1.092342 0.481550 2.246850 -2.283141 0.241000 -2.170574 -2.235731 0.665259 -47.683624 31.332956 -37.012399 -17.390668 65.041088 0.558486 0.970314 1.561300 0.513263 1.411358 0.436063 2.169041 2.065281 1.921408 0.360803 1.766559 1.053100 2.457363 1.401894 1.128004
+1 -0.042022 1 1 0.346066 1.240720 0.466574 0.292455 0.271241 1.862903 0.699867 0.533642 1.240577 -1.942523 -0.555112 0.764858 -13.492059 38.970193 72.034824 39.282432 69.841986 0.388771 1.572218 1.759411 2.416663 1.358932 1.323365 2.045839 1.409531 1.237154 2.089662 2.205787 0.904889 2.220356 0.515064 2.437133
+1 0.023174 1 1 1.870130 -0.352655 1.116413 -1.175041 0.711015 -0.585647 1.205747 1.717245 -1.639209 -1.565338 0.636217 0.480471 -56.140565 -54.471683 -55.577026 -33.071217 72.063073 2.335908 0.851022 1.374348 1.658287 1.585616 1.939416 1.507336 0.292829 2.334349 1.655082 1.712333 0.932465 2.185687 0.590726 0.589588
+1 0.000447 1 1 -1.849971 -0.118357 -0.592023 -2.276041 1.744220 -0.662758 1.112748 -1.511941 -1.985544 2.097325 1.067972 -0.079044 12.685861 61.267231 -31.649714 -36.737937 -54.505539 1.006137 0.647548 1.581917 0.532211 0.368534 1.195034 0.687660 0.751908 0.568454 2.008463 0.990430 2.161755 1.112089 1.638469 1.500404
+1 0.027332 1 1 -2.217587 -0.697342 -0.512749 1.180193 1.062807 -2.069542 -0.643167 0.507982 -1.190967 1.640584 1.109496 0.369871 24.904211 65.073190 35.098005 -57.824524 -6.779872 2.135243 1.030671 1.240773 2.168912 2.157310 0.658430 2.238610 1.321696 0.993153 0.676697 1.004582 1.500474 1.958967 1.617119 0.415366
+1 -0.024617 1 1 2.059132 0.048619 1.901590 0.607359 0.842803 -0.457276 0.464025 -0.137668 0.002631 1.815904 -2.244882 -2.346052 -48.858449 -63.952184 55.639246 28.809546 2.036589 1.809352 0.283062 2.422525 0.871023 2.283356 1.868583 1.267378 1.573443 2.097730 0.543091 0.976783 2.298495 2.054237 0.803917 1.689368
+1 -0.021509 1 1 0.950926 -2.202411 -0.113706 2.176969 1.329313 0.331099 -0.558590 -1.142916 -1.288276 1.368903 1.268729 -0.028363 -23.770786 -65.593757 65.734145 43.772964 -57.789323 1.147806 1.174357 1.912233 1.403639 1.209444 2.124228 0.404304 1.644388 1.979740 1.983144 0.694662 1.435154 2.134116 2.337539 1.271444
+1 -0.012007 1 1 0.836564 -1.645479 1.450003 -2.274305 -2.064403 0.901108 -0.691990 -0.098363 0.857323 -1.453421 1.378285 -1.268630 54.040741 12.737162 23.489332 -14.798437 -17.337831 2.171212 0.314088 1.873868 2.350923 1.209655 1.176136 0.316769 1.930405 0.817637 0.517020 1.553346 1.843210 2.328922 0.449419 1.643299
+1 0.016618 1 1 -0.745360 -1.740298 0.601080 -1.013055 -0.548450 -0.367977 -1.937690 0.570830 -0.486645 1.658329 -2.253297 2.306076 -37.543539 55.731637 -68.373834 -9.032165 -3.595515 1.677608 2.300584 1.169954 2.168265 0.284640 1.943550 1.251028 1.276348 1.583703 1.301999 0.703652 1.786103 1.026957 1.814480 0.964994
+1 -0.007021 1 1 0.632403 -2.349836 0.840025 -0.013279 -1.692780 -1.867421 -1.229303 -1.779752 1.951872 2.171101 1.669080 -0.622697 17.307941 44.564890 52.104818 25.684266 -24.539344 2.383725 1.260716 2.109249 0.652682 2.380564 2.131146 1.927923 1.860183 1.845222 2.392272 0.906403 0.657016 0.972793 0.484820 0.370096
+1 0.024371 1 1 0.892934 -1.413384 0.405141 -0.199575 0.970102 -0.363179 -1.399666 0.055021 1.103382 1.282663 -1.468209 -2.126220 -42.387949 -64.261329 -40.154648 -29.173193 36.141518 0.332389 1.205363 1.035849 0.521545 1.101777 1.572170 0.958820 1.890163 1.718104 1.166770 0.404055 1.948525 1.605182 2.302315 1.009248
+1 -0.037816 1 1 0.175904 1.754856 -0.981867 0.551274 0.712456 0.071871 1.565052 -0.726347 2.082321 -1.338176 1.502856 0.090287 1.816304 -73.381513 -23.085981 43.920052 14.318892 2.239158 1.520511 1.228016 1.520502 1.076277 0.482981 0.961389 2.309561 1.286998 0.574116 0.424218 1.075270 1.555677 0.515730 2.371523
+1 -0.005576 1 1 -0.346539 0.228000 0.823341 2.313874 -2.073300 2.157913 1.502929 1.324248 0.016137 -2.103328 1.706862 -1.795280 4.787316 60.425897 -71.944721 -24.926939 2.936988 1.554421 1.907178 1.948127 1.665327 0.655615 2.169521 1.135426 2.348577 2.277574 1.432791 0.674423 1.034427 1.363814 2.373073 2.246707
+1 -0.017131 1 1 -0.548558 -2.181522 2.267381 -1.222273 -1.442964 -1.938946 -1.688137 0.774959 -0.306366 1.552167 -0.516467 -0.037090 -42.785070 11.329181 59.546973 5.983265 60.743322 1.570148 0.722002 1.930990 1.651321 1.498604 2.034183 1.269619 0.990153 2.006816 0.309724 0.538454 1.794876 2.231400 1.647611 2.154388
+1 0.006158 1 1 2.141861 0.311293 1.153826 0.876221 0.437968 0.170682 -1.189455 -1.223771 1.656360 2.354984 0.857749 0.982298 63.064187 19.787240 14.136072 -15.029896 -7.462063 1.151530 0.763853 1.073648 1.300307 1.510832 0.558952 2.063580 0.339527 1.937349 0.518916 1.917941 0.588252 1.750822 2.057200 1.117580
+1 -0.019724 1 1 0.870549 -0.658746 -2.137954 -0.618967 1.975712 2.305925 0.995481 2.074310 0.671054 1.659039 0.270155 -2.245389 -45.790407 50.622484 12.081658 -43.580714 -11.061649 0.427945 0.721098 2.493206 0.820606 0.921899 2.351361 1.830410 0.959058 1.386231 1.130236 0.627131 0.439576 0.455467 2.030870 1.824669
+1 -0.082512 1 1 -1.514889 0.294538 2.294078 -0.206906 0.267019 1.590299 -0.513441 -1.013175 2.142202 1.335691 -0.865867 -0.762455 -50.653473 67.084816 -55.490421 72.497287 11.900188 2.221843 0.761404 0.414478 1.639795 1.286209 0.815787 0.933258 2.017659 0.286504 1.765478 0.896031 1.847516 0.443974 2.378381 1.451174
+1 -0.002049 1 1 1.374896 -1.679077 2.259585 -0.301220 -1.497116 2.122996 -1.016297 1.504563 0.507520 0.459318 0.859550 -1.726979 -55.398057 -25.142762 -24.398505 34.333303 -10.171901 1.988014 1.544698 0.495318 1.305501 1.055251 0.355287 1.304929 0.436911 0.668828 1.493433 0.633544 2.481326 1.402788 0.411495 0.995412
+1 0.005701 1 1 1.428634 1.430675 -1.959835 0.648808 0.052188 0.616837 -0.072719 -1.680028 0.404789 -1.393809 -0.457386 -1.375262 7.463029 31.130285 6.692646 -16.691362 -31.714355 0.277499 1.175554 1.779714 1.650963 2.233309 2.228097 2.369316 2.094645 0.454320 0.757087 2.113983 1.455828 0.849125 0.996968 1.796268
+1 -0.075404 1 1 -1.939481 -1.261634 1.469439 -0.766859 -0.221986 1.292533 -0.509266 -1.530523 1.433400 1.419800 -0.953076 -0.937363 -23.783637 18.405496 41.165403 66.925171 -38.645291 1.203875 0.777166 2.076223 1.325529 2.417929 2.383663 2.471502 0.528473 0.544481 1.846109 1.549486 2.206066 1.099625 1.392373 0.868143
+1 0.010475 1 1 -0.982238 -0.969835 0.135949 -0.610207 -1.589173 0.592341 -1.804436 1.772478 -1.691442 1.783800 0.107987 0.660483 -52.629652 3.434471 -26.841861 68.834954 -40.935807 2.003257 1.240740 1.609428 1.665449 0.450763 1.716629 1.140195 1.507800 1.348218 1.252567 2.388310 1.817915 2.454105 0.647176 2.092086
+1 -0.005253 1 1 1.974310 2.290171 0.113344 1.163678 1.524997 -0.063371 -0.083770 1.082342 1.099352 -0.469794 2.144230 -2.281563 -48.673915 37.511166 0.168215 -22.810782 19.185715 0.689710 1.459107 1.961770 1.466320 1.698825 1.158129 1.426012 1.479022 1.423116 2.303098 0.675128 1.630629 2.478583 0.301190 1.105277
+1 -0.014898 1 1 1.511221 -0.687349 -2.216391 0.544671 -1.882599 -1.855684 -1.888478 -1.715369 0.190816 -2.090756 0.943479 -0.132635 -7.549339 18.261174 15.543474 -60.831367 7.209995 1.050921 1.823704 0.737575 0.430380 1.152227 1.221416 0.845154 1.746845 0.476303 1.228988 2.097398 1.718980 2.403121 1.003612 0.954640
+1 -0.027193 1 1 1.452484 1.728328 0.850599 -1.378367 -0.101680 1.664463 1.881843 -1.424306 0.621801 -1.474895 -1.397636 1.192052 -71.951701 7.756177 8.069612 25.961976 -7.066463 1.884370 1.106501 2.208943 2.197081 0.848046 0.851944 1.123077 1.801094 0.989574 1.271304 2.305270 1.181877 2.311059 1.719204 1.659508
+1 -0.010736 1 1 1.348388 0.486497 0.562276 1.840585 -2.128812 2.221548 1.298708 -0.394334 -1.956541 -0.532008 -2.061952 -0.318083 -68.959489 47.863744 -4.061238 -7.228893 3.997528 1.171787 1.468165 1.194752 0.445221 0.824187 0.362035 2.229798 1.719933 0.419565 1.621104 2.150662 1.427860 1.045192 2.294740 1.947942
+1 0.007392 1 1 -0.547683 -1.609222 -1.800308 0.473660 1.585528 -0.588056 -1.570339 1.404521 1.423466 -0.612636 0.004433 -0.894369 27.352900 -29.808706 5.073940 -72.296297 66.144704 2.035666 1.445363 0.463765 2.005663 1.169192 0.612813 0.543560 2.115711 1.251063 1.868673 0.541008 1.968500 2.086249 1.092124 1.319796
+1 0.023692 1 1 0.562368 -1.328818 -1.438718 -1.266258 -0.842746 1.410094 0.849585 0.436899 1.063114 -1.619970 1.352256 -0.492409 -30.647507 7.348903 63.005749 -62.383753 16.259267 0.917511 0.600508 0.735493 1.439090 0.791403 0.617359 0.455131 0.882272 2.340108 1.696213 2.249245 2.311898 2.319400 2.407263 0.864776
+1 -0.005147 1 1 0.792551 -1.523127 -1.492566 -1.518619 -1.128984 1.963834 0.592958 -0.854876 0.165742 0.607715 2.121014 -1.331585 -26.016210 -4.445329 -12.645223 21.741188 4.151636 1.773200 2.429740 0.644724 1.367973 0.278789 0.352851 0.869944 2.143456 1.819758 1.918634 0.987546 0.940610 1.833213 0.818156 2.499223
+1 0.061011 1 1 0.825083 -1.385398 -0.464469 2.095724 -2.278237 -2.171713 2.186172 0.503271 -0.265520 0.040396 0.343147 -0.687572 -39.573744 -15.921547 6.554816 66.792950 -10.897058 1.422167 2.112974 2.498377 2.219906 1.967230 0.980216 1.496559 1.420173 2.346747 0.774867 1.695542 2.222846 1.871563 1.864568 1.300872
+1 -0.011798 1 1 1.913111 1.031676 -2.206122 -1.208360 1.481313 0.869358 -1.812318 1.246989 2.141530 -0.525159 -0.047077 0.463698 -29.303799 -58.942573 -47.830636 -39.500343 17.736517 2.089590 0.996431 1.758367 0.630253 1.156067 0.512114 2.356952 1.300896 2.415394 0.279630 0.995116 2.166194 1.471873 0.525444 1.382173
+1 0.005540 1 1 -0.664353 -2.136428 1.465547 -0.209207 -0.697846 0.433000 1.500129 1.390843 -2.264067 0.364423 -1.253577 0.230282 46.971088 -6.922315 56.645040 -16.813962 7.745059 0.943044 2.235797 1.295168 0.642259 0.452764 1.609538 1.250112 1.637712 2.282962 1.998108 2.453170 0.674897 2.236783 2.114386 1.490844
+1 -0.040061 1 1 -0.717383 1.940094 2.138244 0.779762 0.298301 -0.430217 -1.853695 -1.445767 -1.923762 -0.969738 1.763872 -0.242788 12.253310 -8.621738 -5.558089 35.192394 28.563698 2.426058 1.749105 2.465318 2.344381 1.513509 0.545721 2.436681 0.303247 1.927958 2.441819 1.154792 1.590804 1.387582 1.336183 1.472123
+1 0.006875 1 1 0.346606 0.890118 -1.619154 0.921431 1.583445 2.103673 -0.628065 -0.138470 0.651238 -1.529284 -1.308541 0.063398 17.135481 -3.966184 -59.654050 -5.614614 -14.822787 1.726302 1.711122 0.829512 2.110931 1.919532 0.329201 1.625558 0.498647 1.016070 1.091646 2.299661 1.403228 1.054315 0.366243 0.945684
+1 0.024694 1 1 2.041676 -1.170535 1.034914 0.377280 -1.932324 1.219188 1.432300 1.781811 -0.330226 1.093234 0.373514 0.755090 10.558655 9.312849 71.053069 38.927383 -47.475390 0.341703 2.493862 0.582372 1.925003 2.273434 1.599890 1.107427 2.017808 0.543368 1.134399 0.836784 0.571272 2.117790 2.445354 2.062194
+1 -0.045949 1 1 0.829585 -1.116045 -2.066913 1.124072 0.317177 1.075360 1.571915 1.520804 0.154430 -1.023905 0.873699 0.449678 -29.711822 -16.593586 -38.401036 43.785701 6.272051 0.840379 2.492091 2.322532 1.051748 2.235339 0.345400 1.642262 2.241162 1.466811 0.938724 1.639922 1.172221 2.016616 0.765818 0.354914
+1 -0.031714 1 1 -1.268261 -1.535879 0.951300 -0.629447 0.190096 -0.057531 -0.878758 -0.654255 -2.059903 1.140845 -0.526552 0.103023 65.495643 -64.720016 50.685755 25.483320 48.153008 2.239110 0.724270 1.803642 1.057331 1.564493 2.426589 1.686950 1.822635 0.778717 1.146555 0.404697 1.495034 0.542962 1.055606 1.815499
+1 -0.013053 1 1 -0.959815 -1.103030 -0.093112 -0.427947 -1.394430 -1.473811 -2.021095 -1.652125 -1.869466 2.088073 1.080643 0.826803 -24.346792 3.462958 1.931191 57.525049 73.506014 1.608724 1.082489 1.397931 2.022718 2.067648 1.207895 0.845577 2.112512 1.482327 0.726381 1.284154 2.279522 0.429438 1.057034 1.065151
+1 -0.019695 1 1 0.754064 1.943172 2.033138 1.421721 -1.665806 -0.897719 1.112247 -0.515074 -0.198291 -1.019506 -0.591716 -1.826359 28.228541 -12.917292 -50.925403 -3.253822 63.019205 1.581593 1.837582 2.238923 2.073503 0.610509 2.322103 0.589107 0.377467 0.581361 0.686383 1.794974 1.621956 0.717224 0.386421 0.331937
+1 0.007511 1 1 1.898548 1.309455 1.153579 1.428371 1.731150 1.152960 0.449602 -2.212970 1.495497 -1.069972 -0.545564 1.014478 28.856999 49.585488 -16.704229 52.024279 22.056179 2.097978 2.471133 1.089797 0.466005 1.393300 0.698280 1.494576 1.834653 0.264997 0.299590 1.203379 1.443321 2.147705 1.231934 2.108814
+1 -0.006918 1 1 -1.292679 -1.951501 -0.657442 0.930770 -1.674751 -0.439975 -0.923230 1.167139 -1.575551 -1.362947 -0.120499 1.093373 -63.468235 -60.617886 -4.801974 -6.783957 -17.973560 1.650627 1.092143 1.638665 0.298032 2.030719 1.540458 1.219914 0.336823 1.476273 2.462586 1.438176 1.179710 1.885454 1.322561 2.034868
+1 0.001780 1 1 1.264000 0.593887 0.611674 -2.032310 -1.644168 -0.082429 0.053260 -0.212307 -0.967119 -1.340345 -1.953246 -1.711239 -34.510396 33.770018 -27.310909 -14.446881 41.279428 1.875195 2.143473 2.097140 1.880922 1.651376 2.418586 2.169642 0.919638 0.354511 1.762807 0.993118 2.336045 0.913479 0.344610 1.862836
+1 0.003284 1 1 0.990287 -0.398516 -1.554372 1.154556 -0.993511 -1.947889 -1.200225 1.557070 1.777124 1.003383 -1.785420 0.945959 -27.472700 -33.666834 -38.484624 -11.074974 12.918094 2.341089 2.432755 1.815520 0.447203 0.386339 1.204835 1.156485 0.797465 1.239310 2.337572 1.819834 0.949590 2.007523 0.936003 0.902943
+1 0.012209 1 1 2.342416 1.688918 -1.780904 1.438478 1.941295 -1.238566 -1.950231 1.836752 -0.575818 1.471551 1.741846 1.849551 -70.958175 55.949711 -3.212325 10.456710 -54.082085 2.010997 0.830816 1.519122 0.387588 1.939909 0.808198 1.638223 1.868216 1.847879 2.045431 1.316862 0.749371 0.678217 1.788270 1.447931
+1 0.000140 1 1 1.350965 1.380065 0.377770 1.588247 -2.023006 -0.774611 1.440632 0.438717 -1.366053 -0.490162 -0.896078 0.406973 73.790914 3.892090 14.350348 -13.698689 16.134273 0.905930 1.716053 0.458356 1.089497 2.182941 1.691354 1.593827 0.451912 0.785562 1.442381 2.103826 1.753176 1.128043 2.025908 1.689170
+1 0.034362 1 1 2.312139 1.767262 0.178059 0.264449 0.810804 -1.052857 -0.349627 0.174333 -1.091802 0.126781 0.803090 1.251488 -74.679707 58.167740 -74.793100 -47.624395 -23.199833 0.331190 1.314409 2.273814 1.248417 2.391501 1.455021 0.795223 1.817017 0.859158 0.867704 0.505713 0.514910 2.086200 0.254677 2.348966
+1 -0.022702 1 1 1.439300 1.621593 -2.351323 -0.585685 0.567117 -1.620726 -1.930242 -1.497877 -1.236878 -1.862861 0.005444 1.957612 -10.061546 -54.399133 -36.233000 31.975705 -34.321868 2.160349 2.239524 0.936383 0.538263 0.828303 2.035660 1.343933 1.234031 1.360687 1.563482 1.199416 2.332505 2.167485 0.664333 2.437254
+1 -0.051762 1 1 0.654810 1.967393 -0.863586 -0.135456 -0.517328 -0.378958 2.007746 -1.236094 1.886549 2.275707 2.059098 -0.528272 -16.582819 -7.434639 -3.977291 53.675304 20.831489 1.597523 1.821979 0.994675 1.504022 0.840977 1.292617 0.505843 0.461445 1.251629 2.372095 1.542354 1.599247 1.550404 1.891895 1.573228
+1 0.026572 1 1 -1.645457 1.814903 -0.225001 -2.257338 0.356381 0.245997 1.702662 -1.690039 1.786387 1.183377 -1.968361 -1.273164 28.574949 -40.840503 -6.329204 -24.925261 31.137745 1.106101 2.247040 1.258432 1.968126 0.290156 2.407505 0.433940 2.479664 0.461253 0.278329 1.619625 2.045902 2.469102 0.697717 1.027306
+1 -0.015692 1 1 -2.006423 -0.091133 -0.142126 0.462378 0.452058 1.373315 0.027551 1.228723 1.452152 0.848320 -1.981393 1.178454 3.647819 -41.110174 -38.688037 20.162666 23.920888 1.950584 2.456866 2.047622 2.135860 2.392935 0.804377 0.410901 2.260992 1.736533 0.416273 0.299173 0.946433 0.694481 0.641645 1.383485
+1 0.053338 1 1 -0.620328 -2.050403 0.584027 -0.163456 0.125612 0.005934 0.777853 1.214688 1.187326 -1.580350 -1.926270 -0.711737 -67.596633 3.391006 -7.356733 -44.617887 -42.830556 1.327601 1.233337 0.945773 0.857153 0.924081 0.780928 2.312510 1.348600 0.927437 0.928579 2.122644 0.772305 1.374316 1.131082 1.338477
+1 0.015939 1 1 -0.236359 0.058963 1.393289 1.145485 2.058109 1.701535 -1.784282 1.212399 0.417450 -0.662851 -0.453030 1.142097 53.205097 68.057300 -60.965036 10.645612 -29.191347 1.840510 1.960207 2.203412 1.500842 1.406466 1.471567 2.124274 1.176350 1.669690 1.989057 1.078045 0.951139 1.047268 1.182611 1.135548
+1 -0.006854 1 1 0.042283 -0.919551 1.748338 -2.147934 1.277451 0.481322 -1.586256 -2.214327 2.256270 0.536641 -0.183573 1.295996 36.158515 66.169922 17.879889 57.300194 44.353437 0.598127 1.217021 1.226969 1.920293 1.860247 0.666045 1.971290 1.715599 1.814691 2.268134 0.278091 2.132098 2.174380 1.813049 1.664152
+1 -0.057391 1 1 1.888809 -2.148987 -2.275082 -0.983553 0.491159 -1.195868 -0.612733 -1.630903 1.381413 -0.533625 -0.962384 -1.876699 -52.688443 65.345569 -37.017171 52.401178 56.596192 2.308022 2.426146 0.985386 0.629166 0.895402 0.269450 0.890285 2.014140 1.893418 2.420028 1.664538 0.894908 0.973958 2.062698 1.264425
+1 -0.010284 1 1 -2.227497 -2.324199 -1.812210 -1.643226 1.611381 0.380344 -2.275717 -2.218128 -0.371524 -0.280845 1.650257 -1.252612 73.522979 0.710744 -54.533749 -48.713870 -34.010100 2.008823 0.281382 1.181596 2.075540 1.103772 1.347096 0.386581 0.769843 0.502109 0.696207 0.409181 0.357916 0.502254 0.876207 1.662600
+1 -0.008949 1 1 -0.117186 0.231392 1.283761 -1.859061 -2.101354 1.899779 -1.558066 0.333594 -1.020358 -0.772192 -0.315324 1.787150 -4.466952 73.943973 26.355880 13.280034 -2.476558 0.272484 2.389196 0.966483 2.437397 1.084805 2.067933 1.498584 1.703762 0.875742 0.589056 1.756897 0.659728 1.550566 2.368224 1.741919
+1 -0.014817 1 1 -1.135141 2.151326 -0.819502 0.939199 -1.389664 -1.481772 0.830495 0.026543 -1.569154 -2.245354 -0.862542 -1.438888 18.669964 -13.916657 -47.254564 42.548809 67.828936 1.388789 1.385955 0.997609 1.306115 2.381433 0.996803 1.267481 1.048822 0.306775 0.464507 0.973579 2.448545 1.694317 1.880635 1.337971
+1 -0.060643 1 1 1.542390 0.105305 -2.001266 1.753538 0.426388 -1.247244 -1.719828 0.644219 -1.685098 0.018390 -1.942799 -0.470427 29.289769 -26.844019 32.579689 66.837509 -11.991001 2.383685 0.595594 1.403208 0.723277 0.863765 1.790667 1.236213 2.035235 0.946975 0.807046 0.264314 2.328836 1.252267 1.852622 0.767926
+1 0.064867 1 1 1.004321 -0.160171 -1.218624 -1.372787 -0.567905 -2.192525 1.111813 1.618756 1.810128 -0.362314 -0.996650 1.838010 54.840639 -43.387516 -63.977350 -67.329837 -12.566642 1.261650 2.055432 0.645231 0.890097 1.111876 0.293683 0.925282 0.722315 0.454051 0.742425 0.929163 0.697805 0.259237 0.250957 0.587497
+1 0.033967 1 1 -2.107720 -1.417742 -2.146961 -1.205875 0.845725 1.534156 -1.630499 -1.247359 1.052958 2.039952 -1.871235 0.635298 -26.108607 -57.359387 10.778069 -52.992742 50.987786 1.400859 1.740181 0.974232 2.173930 0.994013 1.621367 2.072312 0.851836 1.561763 1.557135 0.271720 0.796059 2.370954 0.369931 2.184455
+1 -0.053297 1 1 0.004550 1.077579 1.153636 -2.324893 0.655399 -2.277617 -1.174613 -1.530729 -2.026544 1.014267 2.073708 -0.011267 -27.625225 -47.160432 -25.378429 64.742929 34.402135 0.575360 1.083396 0.889282 0.913824 1.634981 1.371545 1.810142 2.309758 2.349788 2.395424 2.139727 2.140348 1.335341 0.819134 0.937181
+1 -0.002606 1 1 -0.035187 -2.333654 -0.504976 -0.124311 -1.702856 -1.553562 0.638647 -1.074410 0.263407 2.154399 -1.003828 -0.978465 37.211333 60.880183 63.240425 -18.180092 -2.799623 2.075983 1.798927 0.561116 2.429137 1.762491 2.430154 0.849529 1.029184 1.003291 2.309458 1.815880 1.987397 2.429899 1.063470 1.247388
+1 0.053818 1 1 1.065417 -0.620916 2.205745 -0.403623 2.140401 -0.663216 -1.878766 1.304117 0.967559 -0.689850 -1.840298 2.236646 18.430474 10.980068 41.995848 74.222839 63.250679 1.437472 0.586149 2.414688 1.911241 0.470717 1.846989 0.590179 0.388255 1.901295 2.064127 0.529643 2.217960 0.757405 0.700015 1.399975
+1 0.048050 1 1 -0.335627 -0.153997 -1.124162 -1.815168 0.478121 1.154807 -1.485029 -2.071816 -1.168633 0.016110 2.150594 1.017701 -46.609578 -67.181175 -64.003343 -54.191508 3.329437 1.492640 0.803774 1.530552 1.240895 1.969255 1.262625 0.446232 2.076859 0.766594 2.147089 2.116448 2.384526 1.223754 1.885480 1.762002
+1 0.018362 1 1 0.854917 0.507850 1.306281 -0.351020 0.323178 -1.723483 0.472250 1.447514 -1.695293 -1.687607 0.254815 -0.880416 -8.221983 -36.869350 -13.165250 -18.361378 -49.679918 0.319333 2.279506 2.414118 1.327362 1.728024 1.404628 2.088005 1.358091 0.692687 1.991284 0.254793 2.062988 1.638019 0.687249 0.588855
+1 -0.015966 1 1 1.761581 -1.053897 1.023253 2.301544 -1.953311 1.914122 -0.823900 -2.290847 -2.054889 0.575533 -1.545012 -1.746928 72.431773 -39.197182 12.965871 -32.609755 27.849830 2.456266 0.968270 0.965990 0.899935 2.214989 0.319279 1.379476 2.351366 1.904211 1.577516 0.805518 1.586318 2.488988 1.919963 0.824437
+1 0.012223 1 1 1.408625 -0.283918 1.836758 -0.462483 -2.224739 1.624767 -0.827768 -1.316330 1.105421 -2.136172 1.041374 0.552800 -60.909799 39.003664 34.584854 17.648817 73.674978 1.455308 1.117785 0.612844 1.075063 0.327095 2.230803 0.601770 1.696443 1.620022 1.968465 1.483059 1.777485 2.434206 1.450288 2.232938
+1 0.012389 1 1 0.202371 -1.092129 -0.661395 0.464388 1.250671 -1.946878 1.653711 0.247370 1.226462 1.159256 -2.106756 0.639935 54.844187 16.251766 -6.570363 -28.093114 39.033654 0.454339 1.075746 0.556565 2.432126 2.497897 0.897807 2.438499 1.601016 2.032456 1.490232 0.834626 0.313554 1.904009 0.438283 1.221749
+1 -0.028079 1 1 -0.816856 -1.707842 -0.544019 -1.299172 2.029535 2.122907 2.207284 1.893656 -0.791433 1.455868 2.047827 -1.465129 -69.958159 63.223657 0.004874 -68.090198 -41.951517 2.437771 0.624242 1.379663 0.992113 1.196091 0.449030 1.844072 1.060185 2.272079 1.327345 1.441626 0.660809 1.716845 0.265164 0.858401
+1 0.035931 1 1 0.364806 0.481073 -1.060291 1.944791 0.977643 -0.847740 2.292065 -1.037384 0.530526 0.703992 -0.821935 -2.252535 31.180432 -50.475474 58.712901 -62.280253 -44.214726 1.121468 1.771053 2.339135 1.091564 0.923545 0.765286 0.403809 2.319559 0.582754 1.596879 2.250499 0.885583 1.741950 1.461479 1.330475
+1 -0.054773 1 1 0.666715 -0.586066 -1.110551 0.734294 -0.466264 0.202554 1.981267 1.404985 -0.203289 -0.203367 -1.512418 -0.580554 63.224493 14.057120 8.008413 47.404484 -72.836704 1.127863 1.247948 1.271239 1.220078 0.849480 2.460491 2.229887 0.953519 0.551529 1.054993 0.516295 0.617302 1.745950 1.189801 0.490833
+1 -0.075706 1 1 1.940808 0.001346 -0.945123 0.789005 0.141278 -0.576911 1.952282 -0.367829 0.550996 0.751814 1.829665 -1.865351 18.337326 -54.555185 41.005091 72.566071 -32.048417 1.558849 2.078613 0.996692 1.649412 0.925708 1.128025 1.723169 0.794449 2.299319 2.411917 0.340231 0.258158 2.359332 0.784590 0.856469
+1 -0.005360 1 1 0.853922 -2.066786 -1.457080 1.137902 1.851744 1.643418 1.616693 0.128513 1.649137 -1.221459 -1.899900 -0.469830 48.589200 38.682867 42.954070 -20.945292 22.484217 2.008504 1.668812 0.725693 0.975812 1.723254 2.231775 1.194303 1.901647 1.239596 0.393651 0.347079 0.610686 0.799735 1.153291 1.111757
+1 -0.022139 1 1 -0.398976 0.139248 -1.714533 0.110766 0.248535 1.946979 0.051772 -1.651959 0.926696 0.528017 0.953916 0.913519 17.783954 -55.086445 -37.875372 28.631163 3.951751 0.881071 2.417880 1.559176 0.827250 2.335694 1.764371 0.282757 1.801344 0.685120 0.818581 0.634084 0.291961 1.239348 0.726632 1.005040
+1 0.000330 1 1 1.648283 -1.439480 0.056605 -0.541286 2.235695 -1.256791 -1.963620 -1.708943 -0.201297 0.293190 -1.507949 -0.875111 -19.699987 -47.677959 -23.454566 -0.896965 74.717028 0.911290 1.805038 2.018471 0.451045 1.962256 0.636680 1.184486 1.162149 1.492521 1.051628 2.467821 1.659568 0.613181 2.231567 2.197706
+1 -0.000198 1 1 0.559577 -1.110089 -0.922703 0.598091 0.587792 1.856320 -1.563777 -1.400679 1.884117 -0.904815 -0.343028 -2.027016 -69.859367 73.626245 -63.705392 3.479557 -19.078311 2.137418 1.588434 2.067391 1.383924 0.611850 2.367065 0.267566 0.737301 0.320698 0.467121 2.159177 0.534014 1.423805 0.384051 0.994066
diff --git a/library/cpp/linear_regression/benchmark/ya.make b/library/cpp/linear_regression/benchmark/ya.make
new file mode 100644
index 0000000000..bbc4f2683a
--- /dev/null
+++ b/library/cpp/linear_regression/benchmark/ya.make
@@ -0,0 +1,15 @@
+PROGRAM(linear_regression_benchmark)
+
+OWNER(alex-sh)
+
+SRCS(
+ pool.h
+ pool.cpp
+ main.cpp
+)
+
+PEERDIR(
+ library/cpp/linear_regression
+)
+
+END()
diff --git a/library/cpp/linear_regression/linear_model.h b/library/cpp/linear_regression/linear_model.h
new file mode 100644
index 0000000000..8bb050cff7
--- /dev/null
+++ b/library/cpp/linear_regression/linear_model.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <util/generic/algorithm.h>
+#include <util/generic/vector.h>
+
+#include <util/ysaveload.h>
+
+#include <utility>
+
+class TLinearModel {
+private:
+ TVector<double> Coefficients;
+ double Intercept;
+
+public:
+ Y_SAVELOAD_DEFINE(Coefficients, Intercept);
+
+ TLinearModel(TVector<double>&& coefficients, const double intercept)
+ : Coefficients(std::move(coefficients))
+ , Intercept(intercept)
+ {
+ }
+
+ explicit TLinearModel(size_t featuresCount = 0)
+ : Coefficients(featuresCount)
+ , Intercept(0.)
+ {
+ }
+
+ const TVector<double>& GetCoefficients() const {
+ return Coefficients;
+ }
+
+ double GetIntercept() const {
+ return Intercept;
+ }
+
+ template <typename T>
+ double Prediction(const TVector<T>& features) const {
+ return InnerProduct(Coefficients, features, Intercept);
+ }
+};
diff --git a/library/cpp/linear_regression/linear_regression.cpp b/library/cpp/linear_regression/linear_regression.cpp
new file mode 100644
index 0000000000..150f9d214e
--- /dev/null
+++ b/library/cpp/linear_regression/linear_regression.cpp
@@ -0,0 +1,440 @@
+#include "linear_model.h"
+#include "linear_regression.h"
+
+#include <util/generic/ymath.h>
+
+#ifdef _sse2_
+#include <emmintrin.h>
+#include <xmmintrin.h>
+#endif
+
+#include <algorithm>
+#include <functional>
+
+namespace {
+ inline void AddFeaturesProduct(const double weight, const TVector<double>& features, TVector<double>& linearizedOLSTriangleMatrix);
+
+ TVector<double> Solve(const TVector<double>& olsMatrix, const TVector<double>& olsVector);
+
+ double SumSquaredErrors(const TVector<double>& olsMatrix,
+ const TVector<double>& olsVector,
+ const TVector<double>& solution,
+ const double goalsDeviation);
+}
+
+bool TFastLinearRegressionSolver::Add(const TVector<double>& features, const double goal, const double weight) {
+ const size_t featuresCount = features.size();
+
+ if (LinearizedOLSMatrix.empty()) {
+ LinearizedOLSMatrix.resize((featuresCount + 1) * (featuresCount + 2) / 2);
+ OLSVector.resize(featuresCount + 1);
+ }
+
+ AddFeaturesProduct(weight, features, LinearizedOLSMatrix);
+
+ const double weightedGoal = goal * weight;
+ double* olsVectorElement = OLSVector.data();
+ for (const double feature : features) {
+ *olsVectorElement += feature * weightedGoal;
+ ++olsVectorElement;
+ }
+ *olsVectorElement += weightedGoal;
+
+ SumSquaredGoals += goal * goal * weight;
+
+ return true;
+}
+
+bool TLinearRegressionSolver::Add(const TVector<double>& features, const double goal, const double weight) {
+ const size_t featuresCount = features.size();
+
+ if (FeatureMeans.empty()) {
+ FeatureMeans.resize(featuresCount);
+ LastMeans.resize(featuresCount);
+ NewMeans.resize(featuresCount);
+
+ LinearizedOLSMatrix.resize(featuresCount * (featuresCount + 1) / 2);
+ OLSVector.resize(featuresCount);
+ }
+
+ SumWeights += weight;
+ if (!SumWeights.Get()) {
+ return false;
+ }
+
+ for (size_t featureNumber = 0; featureNumber < featuresCount; ++featureNumber) {
+ const double feature = features[featureNumber];
+ double& featureMean = FeatureMeans[featureNumber];
+
+ LastMeans[featureNumber] = weight * (feature - featureMean);
+ featureMean += weight * (feature - featureMean) / SumWeights.Get();
+ NewMeans[featureNumber] = feature - featureMean;
+ ;
+ }
+
+ double* olsMatrixElement = LinearizedOLSMatrix.data();
+
+ const double* lastMean = LastMeans.data();
+ const double* newMean = NewMeans.data();
+ const double* lastMeansEnd = lastMean + LastMeans.size();
+ const double* newMeansEnd = newMean + NewMeans.size();
+
+#ifdef _sse2_
+ for (; lastMean != lastMeansEnd; ++lastMean, ++newMean) {
+ __m128d factor = _mm_set_pd(*lastMean, *lastMean);
+ const double* secondFeatureMean = newMean;
+ for (; secondFeatureMean + 1 < newMeansEnd; secondFeatureMean += 2, olsMatrixElement += 2) {
+ __m128d matrixElem = _mm_loadu_pd(olsMatrixElement);
+ __m128d secondFeatureMeanElem = _mm_loadu_pd(secondFeatureMean);
+ __m128d product = _mm_mul_pd(factor, secondFeatureMeanElem);
+ __m128d addition = _mm_add_pd(matrixElem, product);
+ _mm_storeu_pd(olsMatrixElement, addition);
+ }
+ for (; secondFeatureMean < newMeansEnd; ++secondFeatureMean) {
+ *olsMatrixElement++ += *lastMean * *secondFeatureMean;
+ }
+ }
+#else
+ for (; lastMean != lastMeansEnd; ++lastMean, ++newMean) {
+ for (const double* secondFeatureMean = newMean; secondFeatureMean < newMeansEnd; ++secondFeatureMean) {
+ *olsMatrixElement++ += *lastMean * *secondFeatureMean;
+ }
+ }
+#endif
+
+ for (size_t firstFeatureNumber = 0; firstFeatureNumber < features.size(); ++firstFeatureNumber) {
+ OLSVector[firstFeatureNumber] += weight * (features[firstFeatureNumber] - FeatureMeans[firstFeatureNumber]) * (goal - GoalsMean);
+ }
+
+ const double oldGoalsMean = GoalsMean;
+ GoalsMean += weight * (goal - GoalsMean) / SumWeights.Get();
+ GoalsDeviation += weight * (goal - oldGoalsMean) * (goal - GoalsMean);
+
+ return true;
+}
+
+TLinearModel TFastLinearRegressionSolver::Solve() const {
+ TVector<double> coefficients = ::Solve(LinearizedOLSMatrix, OLSVector);
+ double intercept = 0.;
+
+ if (!coefficients.empty()) {
+ intercept = coefficients.back();
+ coefficients.pop_back();
+ }
+
+ return TLinearModel(std::move(coefficients), intercept);
+}
+
+TLinearModel TLinearRegressionSolver::Solve() const {
+ TVector<double> coefficients = ::Solve(LinearizedOLSMatrix, OLSVector);
+ double intercept = GoalsMean;
+
+ const size_t featuresCount = OLSVector.size();
+ for (size_t featureNumber = 0; featureNumber < featuresCount; ++featureNumber) {
+ intercept -= FeatureMeans[featureNumber] * coefficients[featureNumber];
+ }
+
+ return TLinearModel(std::move(coefficients), intercept);
+}
+
+double TFastLinearRegressionSolver::SumSquaredErrors() const {
+ const TVector<double> coefficients = ::Solve(LinearizedOLSMatrix, OLSVector);
+ return ::SumSquaredErrors(LinearizedOLSMatrix, OLSVector, coefficients, SumSquaredGoals.Get());
+}
+
+double TLinearRegressionSolver::SumSquaredErrors() const {
+ const TVector<double> coefficients = ::Solve(LinearizedOLSMatrix, OLSVector);
+ return ::SumSquaredErrors(LinearizedOLSMatrix, OLSVector, coefficients, GoalsDeviation);
+}
+
+bool TSLRSolver::Add(const double feature, const double goal, const double weight) {
+ SumWeights += weight;
+ if (!SumWeights.Get()) {
+ return false;
+ }
+
+ const double weightedFeatureDiff = weight * (feature - FeaturesMean);
+ const double weightedGoalDiff = weight * (goal - GoalsMean);
+
+ FeaturesMean += weightedFeatureDiff / SumWeights.Get();
+ FeaturesDeviation += weightedFeatureDiff * (feature - FeaturesMean);
+
+ GoalsMean += weightedGoalDiff / SumWeights.Get();
+ GoalsDeviation += weightedGoalDiff * (goal - GoalsMean);
+
+ Covariation += weightedFeatureDiff * (goal - GoalsMean);
+
+ return true;
+}
+
+bool TSLRSolver::Add(const double* featuresBegin,
+ const double* featuresEnd,
+ const double* goalsBegin) {
+ for (; featuresBegin != featuresEnd; ++featuresBegin, ++goalsBegin) {
+ Add(*featuresBegin, *goalsBegin);
+ }
+ return true;
+}
+bool TSLRSolver::Add(const double* featuresBegin,
+ const double* featuresEnd,
+ const double* goalsBegin,
+ const double* weightsBegin) {
+ for (; featuresBegin != featuresEnd; ++featuresBegin, ++goalsBegin, ++weightsBegin) {
+ Add(*featuresBegin, *goalsBegin, *weightsBegin);
+ }
+ return true;
+}
+
+double TSLRSolver::SumSquaredErrors(const double regularizationParameter) const {
+ double factor, offset;
+ Solve(factor, offset, regularizationParameter);
+
+ return factor * factor * FeaturesDeviation - 2 * factor * Covariation + GoalsDeviation;
+}
+
+namespace {
+ // LDL matrix decomposition, see http://en.wikipedia.org/wiki/Cholesky_decomposition#LDL_decomposition_2
+ bool LDLDecomposition(const TVector<double>& linearizedOLSMatrix,
+ const double regularizationThreshold,
+ const double regularizationParameter,
+ TVector<double>& decompositionTrace,
+ TVector<TVector<double>>& decompositionMatrix) {
+ const size_t featuresCount = decompositionTrace.size();
+
+ size_t olsMatrixElementIdx = 0;
+ for (size_t rowNumber = 0; rowNumber < featuresCount; ++rowNumber) {
+ double& decompositionTraceElement = decompositionTrace[rowNumber];
+ decompositionTraceElement = linearizedOLSMatrix[olsMatrixElementIdx] + regularizationParameter;
+
+ TVector<double>& decompositionRow = decompositionMatrix[rowNumber];
+ for (size_t i = 0; i < rowNumber; ++i) {
+ decompositionTraceElement -= decompositionRow[i] * decompositionRow[i] * decompositionTrace[i];
+ }
+
+ if (fabs(decompositionTraceElement) < regularizationThreshold) {
+ return false;
+ }
+
+ ++olsMatrixElementIdx;
+ decompositionRow[rowNumber] = 1.;
+ for (size_t columnNumber = rowNumber + 1; columnNumber < featuresCount; ++columnNumber) {
+ TVector<double>& secondDecompositionRow = decompositionMatrix[columnNumber];
+ double& decompositionMatrixElement = secondDecompositionRow[rowNumber];
+
+ decompositionMatrixElement = linearizedOLSMatrix[olsMatrixElementIdx];
+
+ for (size_t j = 0; j < rowNumber; ++j) {
+ decompositionMatrixElement -= decompositionRow[j] * secondDecompositionRow[j] * decompositionTrace[j];
+ }
+
+ decompositionMatrixElement /= decompositionTraceElement;
+
+ decompositionRow[columnNumber] = decompositionMatrixElement;
+ ++olsMatrixElementIdx;
+ }
+ }
+
+ return true;
+ }
+
+ void LDLDecomposition(const TVector<double>& linearizedOLSMatrix,
+ TVector<double>& decompositionTrace,
+ TVector<TVector<double>>& decompositionMatrix) {
+ const double regularizationThreshold = 1e-5;
+ double regularizationParameter = 0.;
+
+ while (!LDLDecomposition(linearizedOLSMatrix,
+ regularizationThreshold,
+ regularizationParameter,
+ decompositionTrace,
+ decompositionMatrix)) {
+ regularizationParameter = regularizationParameter ? 2 * regularizationParameter : 1e-5;
+ }
+ }
+
+ TVector<double> SolveLower(const TVector<TVector<double>>& decompositionMatrix,
+ const TVector<double>& decompositionTrace,
+ const TVector<double>& olsVector) {
+ const size_t featuresCount = olsVector.size();
+
+ TVector<double> solution(featuresCount);
+ for (size_t featureNumber = 0; featureNumber < featuresCount; ++featureNumber) {
+ double& solutionElement = solution[featureNumber];
+ solutionElement = olsVector[featureNumber];
+
+ const TVector<double>& decompositionRow = decompositionMatrix[featureNumber];
+ for (size_t i = 0; i < featureNumber; ++i) {
+ solutionElement -= solution[i] * decompositionRow[i];
+ }
+ }
+
+ for (size_t featureNumber = 0; featureNumber < featuresCount; ++featureNumber) {
+ solution[featureNumber] /= decompositionTrace[featureNumber];
+ }
+
+ return solution;
+ }
+
+ TVector<double> SolveUpper(const TVector<TVector<double>>& decompositionMatrix,
+ const TVector<double>& lowerSolution) {
+ const size_t featuresCount = lowerSolution.size();
+
+ TVector<double> solution(featuresCount);
+ for (size_t featureNumber = featuresCount; featureNumber > 0; --featureNumber) {
+ double& solutionElement = solution[featureNumber - 1];
+ solutionElement = lowerSolution[featureNumber - 1];
+
+ const TVector<double>& decompositionRow = decompositionMatrix[featureNumber - 1];
+ for (size_t i = featureNumber; i < featuresCount; ++i) {
+ solutionElement -= solution[i] * decompositionRow[i];
+ }
+ }
+
+ return solution;
+ }
+
+ TVector<double> Solve(const TVector<double>& olsMatrix, const TVector<double>& olsVector) {
+ const size_t featuresCount = olsVector.size();
+
+ TVector<double> decompositionTrace(featuresCount);
+ TVector<TVector<double>> decompositionMatrix(featuresCount, TVector<double>(featuresCount));
+
+ LDLDecomposition(olsMatrix, decompositionTrace, decompositionMatrix);
+
+ return SolveUpper(decompositionMatrix, SolveLower(decompositionMatrix, decompositionTrace, olsVector));
+ }
+
+ double SumSquaredErrors(const TVector<double>& olsMatrix,
+ const TVector<double>& olsVector,
+ const TVector<double>& solution,
+ const double goalsDeviation) {
+ const size_t featuresCount = olsVector.size();
+
+ double sumSquaredErrors = goalsDeviation;
+ size_t olsMatrixElementIdx = 0;
+ for (size_t i = 0; i < featuresCount; ++i) {
+ sumSquaredErrors += olsMatrix[olsMatrixElementIdx] * solution[i] * solution[i];
+ ++olsMatrixElementIdx;
+ for (size_t j = i + 1; j < featuresCount; ++j) {
+ sumSquaredErrors += 2 * olsMatrix[olsMatrixElementIdx] * solution[i] * solution[j];
+ ++olsMatrixElementIdx;
+ }
+ sumSquaredErrors -= 2 * solution[i] * olsVector[i];
+ }
+ return sumSquaredErrors;
+ }
+
+#ifdef _sse2_
+ inline void AddFeaturesProduct(const double weight, const TVector<double>& features, TVector<double>& linearizedOLSTriangleMatrix) {
+ const double* leftFeature = features.data();
+ const double* featuresEnd = features.data() + features.size();
+ double* matrixElement = linearizedOLSTriangleMatrix.data();
+
+ size_t unaligned = features.size() & 0x1;
+
+ for (; leftFeature != featuresEnd; ++leftFeature, ++matrixElement) {
+ const double weightedFeature = weight * *leftFeature;
+ const double* rightFeature = leftFeature;
+ __m128d wf = {weightedFeature, weightedFeature};
+ for (size_t i = 0; i < unaligned; ++i, ++rightFeature, ++matrixElement) {
+ *matrixElement += weightedFeature * *rightFeature;
+ }
+ unaligned = (unaligned + 1) & 0x1;
+ for (; rightFeature != featuresEnd; rightFeature += 2, matrixElement += 2) {
+ __m128d rf = _mm_loadu_pd(rightFeature);
+ __m128d matrixRow = _mm_loadu_pd(matrixElement);
+ __m128d rowAdd = _mm_mul_pd(rf, wf);
+ _mm_storeu_pd(matrixElement, _mm_add_pd(rowAdd, matrixRow));
+ }
+ *matrixElement += weightedFeature;
+ }
+ linearizedOLSTriangleMatrix.back() += weight;
+ }
+#else
+ inline void AddFeaturesProduct(const double weight, const TVector<double>& features, TVector<double>& linearizedTriangleMatrix) {
+ const double* leftFeature = features.data();
+ const double* featuresEnd = features.data() + features.size();
+ double* matrixElement = linearizedTriangleMatrix.data();
+ for (; leftFeature != featuresEnd; ++leftFeature, ++matrixElement) {
+ const double weightedFeature = weight * *leftFeature;
+ const double* rightFeature = leftFeature;
+ for (; rightFeature != featuresEnd; ++rightFeature, ++matrixElement) {
+ *matrixElement += weightedFeature * *rightFeature;
+ }
+ *matrixElement += weightedFeature;
+ }
+ linearizedTriangleMatrix.back() += weight;
+ }
+#endif
+}
+
+namespace {
+ inline double ArgMinPrecise(std::function<double(double)> func, double left, double right) {
+ const size_t intervalsCount = 20;
+ double points[intervalsCount + 1];
+ double values[intervalsCount + 1];
+ while (right > left + 1e-5) {
+ for (size_t pointNumber = 0; pointNumber <= intervalsCount; ++pointNumber) {
+ points[pointNumber] = left + pointNumber * (right - left) / intervalsCount;
+ values[pointNumber] = func(points[pointNumber]);
+ }
+ size_t bestPointNumber = MinElement(values, values + intervalsCount + 1) - values;
+ if (bestPointNumber == 0) {
+ right = points[bestPointNumber + 1];
+ continue;
+ }
+ if (bestPointNumber == intervalsCount) {
+ left = points[bestPointNumber - 1];
+ continue;
+ }
+ right = points[bestPointNumber + 1];
+ left = points[bestPointNumber - 1];
+ }
+ return func(left) < func(right) ? left : right;
+ }
+}
+
+TFeaturesTransformer TFeaturesTransformerLearner::Solve(const size_t iterationsCount /* = 100 */) {
+ TTransformationParameters transformationParameters;
+
+ auto updateParameter = [this, &transformationParameters](double TTransformationParameters::*parameter,
+ const double left,
+ const double right) {
+ auto evalParameter = [this, &transformationParameters, parameter](double parameterValue) {
+ transformationParameters.*parameter = parameterValue;
+ TFeaturesTransformer transformer(TransformationType, transformationParameters);
+
+ double sse = 0.;
+ for (const TPoint& point : Points) {
+ const double error = transformer.Transformation(point.Argument) - point.Target;
+ sse += error * error;
+ }
+ return sse;
+ };
+ transformationParameters.*parameter = ArgMinPrecise(evalParameter, left, right);
+ };
+
+ auto updateRegressionParameters = [this, &transformationParameters]() {
+ TFeaturesTransformer transformer(TransformationType, transformationParameters);
+
+ TSLRSolver slrSolver;
+ for (const TPoint& point : Points) {
+ slrSolver.Add(transformer.Transformation(point.Argument), point.Target);
+ }
+
+ double factor, intercept;
+ slrSolver.Solve(factor, intercept);
+
+ transformationParameters.RegressionFactor *= factor;
+ transformationParameters.RegressionIntercept *= factor;
+ transformationParameters.RegressionIntercept += intercept;
+ };
+
+ for (size_t iterationNumber = 0; iterationNumber < iterationsCount; ++iterationNumber) {
+ updateParameter(&TTransformationParameters::FeatureOffset, MinimalArgument, MaximalArgument);
+ updateParameter(&TTransformationParameters::FeatureNormalizer, 0., MaximalArgument - MinimalArgument);
+ updateRegressionParameters();
+ }
+
+ return TFeaturesTransformer(TransformationType, transformationParameters);
+}
diff --git a/library/cpp/linear_regression/linear_regression.h b/library/cpp/linear_regression/linear_regression.h
new file mode 100644
index 0000000000..e57de5ff6c
--- /dev/null
+++ b/library/cpp/linear_regression/linear_regression.h
@@ -0,0 +1,342 @@
+#pragma once
+
+#include "linear_model.h"
+#include "welford.h"
+
+#include <library/cpp/accurate_accumulate/accurate_accumulate.h>
+
+#include <util/generic/vector.h>
+#include <util/generic/hash.h>
+#include <util/generic/ymath.h>
+
+class TFastLinearRegressionSolver {
+private:
+ TKahanAccumulator<double> SumSquaredGoals;
+
+ TVector<double> LinearizedOLSMatrix;
+ TVector<double> OLSVector;
+
+public:
+ bool Add(const TVector<double>& features, const double goal, const double weight = 1.);
+ TLinearModel Solve() const;
+ double SumSquaredErrors() const;
+};
+
+class TLinearRegressionSolver {
+private:
+ double GoalsMean = 0.;
+ double GoalsDeviation = 0.;
+
+ TVector<double> FeatureMeans;
+ TVector<double> LastMeans;
+ TVector<double> NewMeans;
+ TVector<double> LinearizedOLSMatrix;
+
+ TVector<double> OLSVector;
+
+ TKahanAccumulator<double> SumWeights;
+
+public:
+ bool Add(const TVector<double>& features, const double goal, const double weight = 1.);
+ TLinearModel Solve() const;
+ double SumSquaredErrors() const;
+};
+
+template <typename TStoreType>
+class TTypedFastSLRSolver {
+private:
+ TStoreType SumFeatures = TStoreType();
+ TStoreType SumSquaredFeatures = TStoreType();
+
+ TStoreType SumGoals = TStoreType();
+ TStoreType SumSquaredGoals = TStoreType();
+
+ TStoreType SumProducts = TStoreType();
+
+ TStoreType SumWeights = TStoreType();
+
+public:
+ bool Add(const double feature, const double goal, const double weight = 1.) {
+ SumFeatures += feature * weight;
+ SumSquaredFeatures += feature * feature * weight;
+
+ SumGoals += goal * weight;
+ SumSquaredGoals += goal * goal * weight;
+
+ SumProducts += goal * feature * weight;
+
+ SumWeights += weight;
+
+ return true;
+ }
+
+ template <typename TFloatType>
+ void Solve(TFloatType& factor, TFloatType& intercept, const double regularizationParameter = 0.1) const {
+ if (!(double)SumGoals) {
+ factor = intercept = TFloatType();
+ return;
+ }
+
+ double productsDeviation, featuresDeviation;
+ SetupSolutionFactors(productsDeviation, featuresDeviation);
+
+ if (!featuresDeviation) {
+ factor = TFloatType();
+ intercept = (double)SumGoals / (double)SumWeights;
+ return;
+ }
+
+ factor = productsDeviation / (featuresDeviation + regularizationParameter);
+ intercept = (double)SumGoals / (double)SumWeights - factor * (double)SumFeatures / (double)SumWeights;
+ }
+
+ double SumSquaredErrors(const double regularizationParameter = 0.1) const {
+ if (!(double)SumWeights) {
+ return 0.;
+ }
+
+ const double sumGoalSquaredDeviations = (double)SumSquaredGoals - (double)SumGoals / (double)SumWeights * (double)SumGoals;
+
+ double productsDeviation, featuresDeviation;
+ SetupSolutionFactors(productsDeviation, featuresDeviation);
+ if (!featuresDeviation) {
+ return sumGoalSquaredDeviations;
+ }
+
+ const double factor = productsDeviation / (featuresDeviation + regularizationParameter);
+
+ const double sumSquaredErrors = factor * factor * featuresDeviation - 2 * factor * productsDeviation + sumGoalSquaredDeviations;
+ return Max(0., sumSquaredErrors);
+ }
+
+private:
+ void SetupSolutionFactors(double& productsDeviation, double& featuresDeviation) const {
+ if (!(double)SumWeights) {
+ productsDeviation = featuresDeviation = 0.;
+ return;
+ }
+
+ featuresDeviation = (double)SumSquaredFeatures - (double)SumFeatures / (double)SumWeights * (double)SumFeatures;
+ if (!featuresDeviation) {
+ return;
+ }
+ productsDeviation = (double)SumProducts - (double)SumFeatures / (double)SumWeights * (double)SumGoals;
+ }
+};
+
+using TFastSLRSolver = TTypedFastSLRSolver<double>;
+using TKahanSLRSolver = TTypedFastSLRSolver<TKahanAccumulator<double>>;
+
+class TSLRSolver {
+private:
+ double FeaturesMean = 0.;
+ double FeaturesDeviation = 0.;
+
+ double GoalsMean = 0.;
+ double GoalsDeviation = 0.;
+
+ TKahanAccumulator<double> SumWeights;
+
+ double Covariation = 0.;
+
+public:
+ bool Add(const double feature, const double goal, const double weight = 1.);
+
+ bool Add(const double* featuresBegin, const double* featuresEnd, const double* goalsBegin);
+ bool Add(const double* featuresBegin, const double* featuresEnd, const double* goalsBegin, const double* weightsBegin);
+
+ bool Add(const TVector<double>& features, const TVector<double>& goals) {
+ Y_ASSERT(features.size() == goals.size());
+ return Add(features.data(), features.data() + features.size(), goals.data());
+ }
+
+ bool Add(const TVector<double>& features, const TVector<double>& goals, const TVector<double>& weights) {
+ Y_ASSERT(features.size() == goals.size() && features.size() == weights.size());
+ return Add(features.data(), features.data() + features.size(), goals.data(), weights.data());
+ }
+
+ template <typename TFloatType>
+ void Solve(TFloatType& factor, TFloatType& intercept, const double regularizationParameter = 0.1) const {
+ if (!FeaturesDeviation) {
+ factor = 0.;
+ intercept = GoalsMean;
+ return;
+ }
+
+ factor = Covariation / (FeaturesDeviation + regularizationParameter);
+ intercept = GoalsMean - factor * FeaturesMean;
+ }
+
+ double SumSquaredErrors(const double regularizationParameter = 0.1) const;
+
+ double GetSumWeights() const {
+ return SumWeights.Get();
+ }
+};
+
+template <typename TSLRSolverType>
+class TTypedBestSLRSolver {
+private:
+ TVector<TSLRSolverType> SLRSolvers;
+
+public:
+ bool Add(const TVector<double>& features, const double goal, const double weight = 1.) {
+ if (SLRSolvers.empty()) {
+ SLRSolvers.resize(features.size());
+ }
+
+ for (size_t featureNumber = 0; featureNumber < features.size(); ++featureNumber) {
+ SLRSolvers[featureNumber].Add(features[featureNumber], goal, weight);
+ }
+
+ return true;
+ }
+
+ TLinearModel Solve(const double regularizationParameter = 0.1) const {
+ const TSLRSolverType* bestSolver = nullptr;
+ for (const TSLRSolverType& solver : SLRSolvers) {
+ if (!bestSolver || solver.SumSquaredErrors(regularizationParameter) < bestSolver->SumSquaredErrors(regularizationParameter)) {
+ bestSolver = &solver;
+ }
+ }
+
+ TVector<double> coefficients(SLRSolvers.size());
+ double intercept = 0.0;
+ if (bestSolver) {
+ bestSolver->Solve(coefficients[bestSolver - SLRSolvers.begin()], intercept, regularizationParameter);
+ }
+
+ TLinearModel model(std::move(coefficients), intercept);
+ return model;
+ }
+
+ double SumSquaredErrors(const double regularizationParameter = 0.1) const {
+ if (SLRSolvers.empty()) {
+ return 0.;
+ }
+
+ double sse = SLRSolvers.begin()->SumSquaredErrors(regularizationParameter);
+ for (const TSLRSolver& solver : SLRSolvers) {
+ sse = Min(solver.SumSquaredErrors(regularizationParameter), sse);
+ }
+ return sse;
+ }
+};
+
+using TFastBestSLRSolver = TTypedBestSLRSolver<TFastSLRSolver>;
+using TKahanBestSLRSolver = TTypedBestSLRSolver<TKahanSLRSolver>;
+using TBestSLRSolver = TTypedBestSLRSolver<TSLRSolver>;
+
+enum ETransformationType {
+ TT_IDENTITY,
+ TT_SIGMA,
+};
+
+struct TTransformationParameters {
+ double RegressionFactor = 1.;
+ double RegressionIntercept = 0.;
+
+ double FeatureOffset = 0.;
+ double FeatureNormalizer = 1.;
+
+ Y_SAVELOAD_DEFINE(RegressionFactor,
+ RegressionIntercept,
+ FeatureOffset,
+ FeatureNormalizer);
+};
+
+class TFeaturesTransformer {
+private:
+ ETransformationType TransformationType;
+ TTransformationParameters TransformationParameters;
+
+public:
+ Y_SAVELOAD_DEFINE(TransformationType, TransformationParameters);
+
+ TFeaturesTransformer() = default;
+
+ TFeaturesTransformer(const ETransformationType transformationType,
+ const TTransformationParameters transformationParameters)
+ : TransformationType(transformationType)
+ , TransformationParameters(transformationParameters)
+ {
+ }
+
+ double Transformation(const double value) const {
+ switch (TransformationType) {
+ case ETransformationType::TT_IDENTITY: {
+ return value;
+ }
+ case ETransformationType::TT_SIGMA: {
+ const double valueWithoutOffset = value - TransformationParameters.FeatureOffset;
+ const double transformedValue = valueWithoutOffset / (fabs(valueWithoutOffset) + TransformationParameters.FeatureNormalizer);
+ return TransformationParameters.RegressionIntercept + TransformationParameters.RegressionFactor * transformedValue;
+ }
+ }
+ Y_ASSERT(0);
+ return 0.;
+ }
+};
+
+class TFeaturesTransformerLearner {
+private:
+ struct TPoint {
+ float Argument;
+ float Target;
+ };
+
+ float MinimalArgument = Max<float>();
+ float MaximalArgument = Min<float>();
+
+ ETransformationType TransformationType;
+ TVector<TPoint> Points;
+
+public:
+ TFeaturesTransformerLearner(const ETransformationType transformationType)
+ : TransformationType(transformationType)
+ {
+ }
+
+ void Add(const float argument, const float target) {
+ Points.push_back(TPoint{argument, target});
+ MinimalArgument = Min(MinimalArgument, argument);
+ MaximalArgument = Max(MaximalArgument, argument);
+ }
+
+ TFeaturesTransformer Solve(const size_t iterationsCount = 100);
+};
+
+class TFastFeaturesTransformerLearner {
+private:
+ ETransformationType TransformationType;
+
+ struct TBucket {
+ TMeanCalculator ArgumentsMean;
+ TMeanCalculator TargetsMean;
+ };
+
+ THashMap<double, TBucket> Buckets;
+ double Step;
+
+public:
+ TFastFeaturesTransformerLearner(const ETransformationType transformationType, const double step = 0.1)
+ : TransformationType(transformationType)
+ , Step(step)
+ {
+ }
+
+ void Add(const float argument, const float target) {
+ TBucket& bucket = Buckets[round(argument / Step)];
+ bucket.ArgumentsMean.Add(argument);
+ bucket.TargetsMean.Add(target);
+ }
+
+ TFeaturesTransformer Solve(const size_t iterationsCount = 100) {
+ TFeaturesTransformerLearner learner(TransformationType);
+ for (auto&& argumentWithBucket : Buckets) {
+ const TBucket& bucket = argumentWithBucket.second;
+ learner.Add(bucket.ArgumentsMean.GetMean(), bucket.TargetsMean.GetMean());
+ }
+ return learner.Solve(iterationsCount);
+ }
+};
diff --git a/library/cpp/linear_regression/linear_regression_ut.cpp b/library/cpp/linear_regression/linear_regression_ut.cpp
new file mode 100644
index 0000000000..e71a16b67a
--- /dev/null
+++ b/library/cpp/linear_regression/linear_regression_ut.cpp
@@ -0,0 +1,374 @@
+#include <library/cpp/linear_regression/linear_regression.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/vector.h>
+#include <util/generic/ymath.h>
+#include <util/random/random.h>
+
+#include <util/system/defaults.h>
+
+namespace {
+ void ValueIsCorrect(const double value, const double expectedValue, double possibleRelativeError) {
+ UNIT_ASSERT_DOUBLES_EQUAL(value, expectedValue, possibleRelativeError * expectedValue);
+ }
+}
+
+Y_UNIT_TEST_SUITE(TLinearRegressionTest) {
+ Y_UNIT_TEST(MeanAndDeviationTest) {
+ TVector<double> arguments;
+ TVector<double> weights;
+
+ const size_t argumentsCount = 100;
+ for (size_t i = 0; i < argumentsCount; ++i) {
+ arguments.push_back(i);
+ weights.push_back(i);
+ }
+
+ TDeviationCalculator deviationCalculator;
+ TMeanCalculator meanCalculator;
+ for (size_t i = 0; i < arguments.size(); ++i) {
+ meanCalculator.Add(arguments[i], weights[i]);
+ deviationCalculator.Add(arguments[i], weights[i]);
+ }
+
+ double actualMean = InnerProduct(arguments, weights) / Accumulate(weights, 0.0);
+ double actualDeviation = 0.;
+ for (size_t i = 0; i < arguments.size(); ++i) {
+ double deviation = arguments[i] - actualMean;
+ actualDeviation += deviation * deviation * weights[i];
+ }
+
+ UNIT_ASSERT(IsValidFloat(meanCalculator.GetMean()));
+ UNIT_ASSERT_DOUBLES_EQUAL(meanCalculator.GetMean(), actualMean, 1e-10);
+
+ UNIT_ASSERT(IsValidFloat(deviationCalculator.GetDeviation()));
+ UNIT_ASSERT_DOUBLES_EQUAL(meanCalculator.GetMean(), deviationCalculator.GetMean(), 0);
+
+ UNIT_ASSERT(IsValidFloat(meanCalculator.GetSumWeights()));
+ UNIT_ASSERT(IsValidFloat(deviationCalculator.GetSumWeights()));
+ UNIT_ASSERT_DOUBLES_EQUAL(meanCalculator.GetSumWeights(), deviationCalculator.GetSumWeights(), 0);
+ UNIT_ASSERT_DOUBLES_EQUAL(meanCalculator.GetSumWeights(), Accumulate(weights, 0.0), 0);
+
+ ValueIsCorrect(deviationCalculator.GetDeviation(), actualDeviation, 1e-5);
+
+ TMeanCalculator checkRemovingMeanCalculator;
+ TDeviationCalculator checkRemovingDeviationCalculator;
+
+ const size_t argumentsToRemoveCount = argumentsCount / 3;
+ for (size_t i = 0; i < argumentsCount; ++i) {
+ if (i < argumentsToRemoveCount) {
+ meanCalculator.Remove(arguments[i], weights[i]);
+ deviationCalculator.Remove(arguments[i], weights[i]);
+ } else {
+ checkRemovingMeanCalculator.Add(arguments[i], weights[i]);
+ checkRemovingDeviationCalculator.Add(arguments[i], weights[i]);
+ }
+ }
+
+ UNIT_ASSERT(IsValidFloat(meanCalculator.GetMean()));
+ UNIT_ASSERT(IsValidFloat(checkRemovingMeanCalculator.GetMean()));
+
+ UNIT_ASSERT(IsValidFloat(deviationCalculator.GetDeviation()));
+ UNIT_ASSERT(IsValidFloat(checkRemovingDeviationCalculator.GetDeviation()));
+
+ UNIT_ASSERT_DOUBLES_EQUAL(meanCalculator.GetMean(), deviationCalculator.GetMean(), 0);
+ UNIT_ASSERT_DOUBLES_EQUAL(meanCalculator.GetMean(), checkRemovingMeanCalculator.GetMean(), 1e-10);
+
+ ValueIsCorrect(deviationCalculator.GetDeviation(), checkRemovingDeviationCalculator.GetDeviation(), 1e-5);
+ }
+
+ Y_UNIT_TEST(CovariationTest) {
+ TVector<double> firstValues;
+ TVector<double> secondValues;
+ TVector<double> weights;
+
+ const size_t argumentsCount = 100;
+ for (size_t i = 0; i < argumentsCount; ++i) {
+ firstValues.push_back(i);
+ secondValues.push_back(i * i);
+ weights.push_back(i);
+ }
+
+ TCovariationCalculator covariationCalculator;
+ for (size_t i = 0; i < argumentsCount; ++i) {
+ covariationCalculator.Add(firstValues[i], secondValues[i], weights[i]);
+ }
+
+ const double firstValuesMean = InnerProduct(firstValues, weights) / Accumulate(weights, 0.0);
+ const double secondValuesMean = InnerProduct(secondValues, weights) / Accumulate(weights, 0.0);
+
+ double actualCovariation = 0.;
+ for (size_t i = 0; i < argumentsCount; ++i) {
+ actualCovariation += (firstValues[i] - firstValuesMean) * (secondValues[i] - secondValuesMean) * weights[i];
+ }
+
+ UNIT_ASSERT(IsValidFloat(covariationCalculator.GetCovariation()));
+ UNIT_ASSERT(IsValidFloat(covariationCalculator.GetFirstValueMean()));
+ UNIT_ASSERT(IsValidFloat(covariationCalculator.GetSecondValueMean()));
+
+ UNIT_ASSERT_DOUBLES_EQUAL(covariationCalculator.GetFirstValueMean(), firstValuesMean, 1e-10);
+ UNIT_ASSERT_DOUBLES_EQUAL(covariationCalculator.GetSecondValueMean(), secondValuesMean, 1e-10);
+
+ UNIT_ASSERT(IsValidFloat(covariationCalculator.GetSumWeights()));
+ UNIT_ASSERT_DOUBLES_EQUAL(covariationCalculator.GetSumWeights(), Accumulate(weights, 0.0), 0);
+
+ ValueIsCorrect(covariationCalculator.GetCovariation(), actualCovariation, 1e-5);
+
+ TCovariationCalculator checkRemovingCovariationCalculator;
+
+ const size_t argumentsToRemoveCount = argumentsCount / 3;
+ for (size_t i = 0; i < argumentsCount; ++i) {
+ if (i < argumentsToRemoveCount) {
+ covariationCalculator.Remove(firstValues[i], secondValues[i], weights[i]);
+ } else {
+ checkRemovingCovariationCalculator.Add(firstValues[i], secondValues[i], weights[i]);
+ }
+ }
+
+ ValueIsCorrect(covariationCalculator.GetCovariation(), checkRemovingCovariationCalculator.GetCovariation(), 1e-5);
+ }
+
+ template <typename TSLRSolverType>
+ void SLRTest() {
+ TVector<double> arguments;
+ TVector<double> weights;
+ TVector<double> goals;
+
+ const double factor = 2.;
+ const double intercept = 105.;
+ const double randomError = 0.01;
+
+ const size_t argumentsCount = 10;
+ for (size_t i = 0; i < argumentsCount; ++i) {
+ arguments.push_back(i);
+ weights.push_back(i);
+ goals.push_back(arguments.back() * factor + intercept + 2 * (i % 2 - 0.5) * randomError);
+ }
+
+ TSLRSolverType slrSolver;
+ for (size_t i = 0; i < argumentsCount; ++i) {
+ slrSolver.Add(arguments[i], goals[i], weights[i]);
+ }
+
+ for (double regularizationThreshold = 0.; regularizationThreshold < 0.05; regularizationThreshold += 0.01) {
+ double solutionFactor, solutionIntercept;
+ slrSolver.Solve(solutionFactor, solutionIntercept, regularizationThreshold);
+
+ double predictedSumSquaredErrors = slrSolver.SumSquaredErrors(regularizationThreshold);
+
+ UNIT_ASSERT(IsValidFloat(solutionFactor));
+ UNIT_ASSERT(IsValidFloat(solutionIntercept));
+ UNIT_ASSERT(IsValidFloat(predictedSumSquaredErrors));
+
+ UNIT_ASSERT_DOUBLES_EQUAL(solutionFactor, factor, 1e-2);
+ UNIT_ASSERT_DOUBLES_EQUAL(solutionIntercept, intercept, 1e-2);
+
+ double sumSquaredErrors = 0.;
+ for (size_t i = 0; i < argumentsCount; ++i) {
+ double error = goals[i] - arguments[i] * solutionFactor - solutionIntercept;
+ sumSquaredErrors += error * error * weights[i];
+ }
+
+ if (!regularizationThreshold) {
+ UNIT_ASSERT(predictedSumSquaredErrors < Accumulate(weights, 0.0) * randomError * randomError);
+ }
+ UNIT_ASSERT_DOUBLES_EQUAL(predictedSumSquaredErrors, sumSquaredErrors, 1e-8);
+ }
+ }
+
+ Y_UNIT_TEST(FastSLRTest) {
+ SLRTest<TFastSLRSolver>();
+ }
+
+ Y_UNIT_TEST(KahanSLRTest) {
+ SLRTest<TKahanSLRSolver>();
+ }
+
+ Y_UNIT_TEST(SLRTest) {
+ SLRTest<TSLRSolver>();
+ }
+
+ template <typename TLinearRegressionSolverType>
+ void LinearRegressionTest() {
+ const size_t featuresCount = 10;
+ const size_t instancesCount = 10000;
+ const double randomError = 0.01;
+
+ TVector<double> coefficients;
+ for (size_t featureNumber = 0; featureNumber < featuresCount; ++featureNumber) {
+ coefficients.push_back(featureNumber);
+ }
+ const double intercept = 10;
+
+ TVector<TVector<double>> featuresMatrix;
+ TVector<double> goals;
+ TVector<double> weights;
+
+ for (size_t instanceNumber = 0; instanceNumber < instancesCount; ++instanceNumber) {
+ TVector<double> features;
+ for (size_t featureNumber = 0; featureNumber < featuresCount; ++featureNumber) {
+ features.push_back(RandomNumber<double>());
+ }
+ featuresMatrix.push_back(features);
+
+ const double goal = InnerProduct(coefficients, features) + intercept + 2 * (instanceNumber % 2 - 0.5) * randomError;
+ goals.push_back(goal);
+ weights.push_back(instanceNumber);
+ }
+
+ TLinearRegressionSolverType lrSolver;
+ for (size_t instanceNumber = 0; instanceNumber < instancesCount; ++instanceNumber) {
+ lrSolver.Add(featuresMatrix[instanceNumber], goals[instanceNumber], weights[instanceNumber]);
+ }
+ const TLinearModel model = lrSolver.Solve();
+
+ for (size_t featureNumber = 0; featureNumber < featuresCount; ++featureNumber) {
+ UNIT_ASSERT_DOUBLES_EQUAL(model.GetCoefficients()[featureNumber], coefficients[featureNumber], 1e-2);
+ }
+ UNIT_ASSERT_DOUBLES_EQUAL(model.GetIntercept(), intercept, 1e-2);
+
+ const double expectedSumSquaredErrors = randomError * randomError * Accumulate(weights, 0.0);
+ UNIT_ASSERT_DOUBLES_EQUAL(lrSolver.SumSquaredErrors(), expectedSumSquaredErrors, expectedSumSquaredErrors * 0.01);
+ }
+
+ Y_UNIT_TEST(FastLRTest) {
+ LinearRegressionTest<TFastLinearRegressionSolver>();
+ }
+
+ Y_UNIT_TEST(LRTest) {
+ LinearRegressionTest<TLinearRegressionSolver>();
+ }
+
+ void TransformationTest(const ETransformationType transformationType, const size_t pointsCount) {
+ TVector<float> arguments;
+ TVector<float> goals;
+
+ const double regressionFactor = 10.;
+ const double regressionIntercept = 100;
+
+ const double featureOffset = -1.5;
+ const double featureNormalizer = 15;
+
+ const double left = -100.;
+ const double right = +100.;
+ const double step = (right - left) / pointsCount;
+
+ for (double argument = left; argument <= right; argument += step) {
+ const double goal = regressionIntercept + regressionFactor * (argument - featureOffset) / (fabs(argument - featureOffset) + featureNormalizer);
+
+ arguments.push_back(argument);
+ goals.push_back(goal);
+ }
+
+ TFastFeaturesTransformerLearner learner(transformationType);
+ for (size_t instanceNumber = 0; instanceNumber < arguments.size(); ++instanceNumber) {
+ learner.Add(arguments[instanceNumber], goals[instanceNumber]);
+ }
+ TFeaturesTransformer transformer = learner.Solve();
+
+ double sse = 0.;
+ for (size_t instanceNumber = 0; instanceNumber < arguments.size(); ++instanceNumber) {
+ const double error = transformer.Transformation(arguments[instanceNumber]) - goals[instanceNumber];
+ sse += error * error;
+ }
+ const double rmse = sqrt(sse / arguments.size());
+ UNIT_ASSERT_DOUBLES_EQUAL(rmse, 0., 1e-3);
+ }
+
+ Y_UNIT_TEST(SigmaTest100) {
+ TransformationTest(ETransformationType::TT_SIGMA, 100);
+ }
+
+ Y_UNIT_TEST(SigmaTest1000) {
+ TransformationTest(ETransformationType::TT_SIGMA, 1000);
+ }
+
+ Y_UNIT_TEST(SigmaTest10000) {
+ TransformationTest(ETransformationType::TT_SIGMA, 10000);
+ }
+
+ Y_UNIT_TEST(SigmaTest100000) {
+ TransformationTest(ETransformationType::TT_SIGMA, 100000);
+ }
+
+ Y_UNIT_TEST(SigmaTest1000000) {
+ TransformationTest(ETransformationType::TT_SIGMA, 1000000);
+ }
+
+ Y_UNIT_TEST(SigmaTest10000000) {
+ TransformationTest(ETransformationType::TT_SIGMA, 10000000);
+ }
+
+ Y_UNIT_TEST(ResetCalculatorTest) {
+ TVector<double> arguments;
+ TVector<double> weights;
+ const double eps = 1e-10;
+
+ const size_t argumentsCount = 100;
+ for (size_t i = 0; i < argumentsCount; ++i) {
+ arguments.push_back(i);
+ weights.push_back(i);
+ }
+
+ TDeviationCalculator deviationCalculator1, deviationCalculator2;
+ TMeanCalculator meanCalculator1, meanCalculator2;
+ TCovariationCalculator covariationCalculator1, covariationCalculator2;
+ for (size_t i = 0; i < arguments.size(); ++i) {
+ meanCalculator1.Add(arguments[i], weights[i]);
+ meanCalculator2.Add(arguments[i], weights[i]);
+ deviationCalculator1.Add(arguments[i], weights[i]);
+ deviationCalculator2.Add(arguments[i], weights[i]);
+ covariationCalculator1.Add(arguments[i], arguments[arguments.size() - i - 1], weights[i]);
+ covariationCalculator2.Add(arguments[i], arguments[arguments.size() - i - 1], weights[i]);
+ }
+
+ UNIT_ASSERT_DOUBLES_EQUAL(meanCalculator1.GetMean(), meanCalculator2.GetMean(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(meanCalculator1.GetSumWeights(), meanCalculator2.GetSumWeights(), eps);
+
+ UNIT_ASSERT_DOUBLES_EQUAL(deviationCalculator1.GetMean(), deviationCalculator2.GetMean(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(deviationCalculator1.GetDeviation(), deviationCalculator2.GetDeviation(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(deviationCalculator1.GetStdDev(), deviationCalculator2.GetStdDev(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(deviationCalculator1.GetSumWeights(), deviationCalculator2.GetSumWeights(), eps);
+
+ UNIT_ASSERT_DOUBLES_EQUAL(covariationCalculator1.GetFirstValueMean(), covariationCalculator2.GetFirstValueMean(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(covariationCalculator1.GetSecondValueMean(), covariationCalculator2.GetSecondValueMean(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(covariationCalculator1.GetCovariation(), covariationCalculator2.GetCovariation(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(covariationCalculator1.GetSumWeights(), covariationCalculator2.GetSumWeights(), eps);
+
+ meanCalculator2.Reset();
+ deviationCalculator2.Reset();
+ covariationCalculator2.Reset();
+
+ UNIT_ASSERT_DOUBLES_EQUAL(0.0, meanCalculator2.GetMean(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(0.0, meanCalculator2.GetSumWeights(), eps);
+
+ UNIT_ASSERT_DOUBLES_EQUAL(0.0, deviationCalculator2.GetMean(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(0.0, deviationCalculator2.GetDeviation(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(0.0, deviationCalculator2.GetStdDev(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(0.0, deviationCalculator2.GetSumWeights(), eps);
+
+ UNIT_ASSERT_DOUBLES_EQUAL(0.0, covariationCalculator2.GetFirstValueMean(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(0.0, covariationCalculator2.GetSecondValueMean(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(0.0, covariationCalculator2.GetCovariation(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(0.0, covariationCalculator2.GetSumWeights(), eps);
+
+ for (size_t i = 0; i < arguments.size(); ++i) {
+ meanCalculator2.Add(arguments[i], weights[i]);
+ deviationCalculator2.Add(arguments[i], weights[i]);
+ covariationCalculator2.Add(arguments[i], arguments[arguments.size() - i - 1], weights[i]);
+ }
+
+ UNIT_ASSERT_DOUBLES_EQUAL(meanCalculator1.GetMean(), meanCalculator2.GetMean(), 1e-10);
+ UNIT_ASSERT_DOUBLES_EQUAL(meanCalculator1.GetSumWeights(), meanCalculator2.GetSumWeights(), 1e-10);
+
+ UNIT_ASSERT_DOUBLES_EQUAL(deviationCalculator1.GetMean(), deviationCalculator2.GetMean(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(deviationCalculator1.GetDeviation(), deviationCalculator2.GetDeviation(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(deviationCalculator1.GetStdDev(), deviationCalculator2.GetStdDev(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(deviationCalculator1.GetSumWeights(), deviationCalculator2.GetSumWeights(), eps);
+
+ UNIT_ASSERT_DOUBLES_EQUAL(covariationCalculator1.GetFirstValueMean(), covariationCalculator2.GetFirstValueMean(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(covariationCalculator1.GetSecondValueMean(), covariationCalculator2.GetSecondValueMean(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(covariationCalculator1.GetCovariation(), covariationCalculator2.GetCovariation(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(covariationCalculator1.GetSumWeights(), covariationCalculator2.GetSumWeights(), eps);
+ }
+}
diff --git a/library/cpp/linear_regression/unimodal.cpp b/library/cpp/linear_regression/unimodal.cpp
new file mode 100644
index 0000000000..729011012a
--- /dev/null
+++ b/library/cpp/linear_regression/unimodal.cpp
@@ -0,0 +1,118 @@
+#include "unimodal.h"
+
+#include "linear_regression.h"
+
+#include <util/generic/map.h>
+#include <util/generic/ymath.h>
+
+namespace {
+ double SimpleUnimodal(const double value) {
+ if (value > 5) {
+ return 0.;
+ }
+ return 1. / (value * value + 1.);
+ }
+
+ struct TOptimizationState {
+ double Mode = 0.;
+ double Normalizer = 1.;
+
+ double RegressionFactor = 0.;
+ double RegressionIntercept = 0.;
+
+ double SSE = 0.;
+
+ TOptimizationState(const TVector<double>& values) {
+ SSE = InnerProduct(values, values);
+ }
+
+ double NoRegressionTransform(const double value) const {
+ const double arg = (value - Mode) / Normalizer;
+ return SimpleUnimodal(arg);
+ }
+
+ double RegressionTransform(const double value) const {
+ return NoRegressionTransform(value) * RegressionFactor + RegressionIntercept;
+ }
+ };
+}
+
+double TGreedyParams::Point(const size_t step) const {
+ Y_ASSERT(step <= StepsCount);
+
+ const double alpha = (double)step / StepsCount;
+ return LowerBound * (1 - alpha) + UpperBound * alpha;
+}
+
+double MakeUnimodal(TVector<double>& values, const TOptimizationParams& optimizationParams) {
+ TOptimizationState state(values);
+ TOptimizationState bestState = state;
+
+ for (size_t modeStep = 0; modeStep <= optimizationParams.ModeParams.StepsCount; ++modeStep) {
+ state.Mode = optimizationParams.ModeParams.Point(modeStep);
+ for (size_t normalizerStep = 0; normalizerStep <= optimizationParams.NormalizerParams.StepsCount; ++normalizerStep) {
+ state.Normalizer = optimizationParams.NormalizerParams.Point(normalizerStep);
+
+ TSLRSolver solver;
+ for (size_t i = 0; i < values.size(); ++i) {
+ solver.Add(state.NoRegressionTransform(i), values[i]);
+ }
+
+ state.SSE = solver.SumSquaredErrors(optimizationParams.RegressionShrinkage);
+ if (state.SSE >= bestState.SSE) {
+ continue;
+ }
+
+ bestState = state;
+ solver.Solve(bestState.RegressionFactor, bestState.RegressionIntercept, optimizationParams.RegressionShrinkage);
+ }
+ }
+
+ for (size_t i = 0; i < values.size(); ++i) {
+ values[i] = bestState.RegressionTransform(i);
+ }
+
+ const double residualSSE = bestState.SSE;
+ const double totalSSE = InnerProduct(values, values);
+
+ const double determination = 1. - residualSSE / totalSSE;
+
+ return determination;
+}
+
+double MakeUnimodal(TVector<double>& values) {
+ return MakeUnimodal(values, TOptimizationParams::Default(values));
+}
+
+double MakeUnimodal(TVector<double>& values, const TVector<double>& arguments, const TOptimizationParams& optimizationParams) {
+ Y_ASSERT(values.size() == arguments.size());
+
+ TMap<double, double> mapping;
+ for (size_t i = 0; i < values.size(); ++i) {
+ mapping[arguments[i]] = values[i];
+ }
+
+ TVector<double> preparedValues;
+ preparedValues.reserve(mapping.size());
+
+ for (auto&& argWithValue : mapping) {
+ preparedValues.push_back(argWithValue.second);
+ }
+
+ const double result = MakeUnimodal(preparedValues, optimizationParams);
+
+ size_t pos = 0;
+ for (auto&& argWithValue : mapping) {
+ argWithValue.second = preparedValues[pos++];
+ }
+
+ for (size_t i = 0; i < values.size(); ++i) {
+ values[i] = mapping[arguments[i]];
+ }
+
+ return result;
+}
+
+double MakeUnimodal(TVector<double>& values, const TVector<double>& arguments) {
+ return MakeUnimodal(values, arguments, TOptimizationParams::Default(values, arguments));
+}
diff --git a/library/cpp/linear_regression/unimodal.h b/library/cpp/linear_regression/unimodal.h
new file mode 100644
index 0000000000..e11b1118f6
--- /dev/null
+++ b/library/cpp/linear_regression/unimodal.h
@@ -0,0 +1,59 @@
+#pragma once
+
+#include "linear_regression.h"
+
+struct TGreedyParams {
+ double LowerBound = 0;
+ double UpperBound = 0;
+ size_t StepsCount = 0;
+
+ double Point(const size_t step) const;
+};
+
+struct TOptimizationParams {
+ TGreedyParams ModeParams;
+ TGreedyParams NormalizerParams;
+
+ double OptimizationShrinkage = 1e-2;
+ double RegressionShrinkage = 1e-5;
+
+ size_t IterationsCount = 1000;
+
+ TOptimizationParams() = default;
+
+ static TOptimizationParams Default(const TVector<double>& values) {
+ TOptimizationParams optimizationParams;
+
+ optimizationParams.ModeParams.LowerBound = 0;
+ optimizationParams.ModeParams.UpperBound = values.size();
+ optimizationParams.ModeParams.StepsCount = values.size() + 1;
+
+ optimizationParams.NormalizerParams.LowerBound = 0.5;
+ optimizationParams.NormalizerParams.UpperBound = values.size() * 2;
+ optimizationParams.NormalizerParams.StepsCount = values.size() * 2 + 1;
+
+ return optimizationParams;
+ }
+
+ static TOptimizationParams Default(const TVector<double>& values, const TVector<double>& arguments) {
+ Y_ASSERT(values.size() == arguments.size());
+
+ TOptimizationParams optimizationParams;
+
+ optimizationParams.ModeParams.LowerBound = *MinElement(arguments.begin(), arguments.end());
+ optimizationParams.ModeParams.UpperBound = *MaxElement(arguments.begin(), arguments.end());
+ optimizationParams.ModeParams.StepsCount = arguments.size() + 1;
+
+ optimizationParams.NormalizerParams.UpperBound = optimizationParams.ModeParams.UpperBound - optimizationParams.ModeParams.LowerBound;
+ optimizationParams.NormalizerParams.StepsCount = arguments.size() * 2 + 1;
+ optimizationParams.NormalizerParams.LowerBound = optimizationParams.NormalizerParams.UpperBound / optimizationParams.NormalizerParams.StepsCount;
+
+ return optimizationParams;
+ }
+};
+
+double MakeUnimodal(TVector<double>& values, const TOptimizationParams& optimizationParams);
+double MakeUnimodal(TVector<double>& values);
+
+double MakeUnimodal(TVector<double>& values, const TVector<double>& arguments, const TOptimizationParams& optimizationParams);
+double MakeUnimodal(TVector<double>& values, const TVector<double>& arguments);
diff --git a/library/cpp/linear_regression/ut/ya.make b/library/cpp/linear_regression/ut/ya.make
new file mode 100644
index 0000000000..f410410673
--- /dev/null
+++ b/library/cpp/linear_regression/ut/ya.make
@@ -0,0 +1,15 @@
+UNITTEST()
+
+OWNER(alex-sh)
+
+PEERDIR(
+ ADDINCL library/cpp/linear_regression
+)
+
+SRCDIR(library/cpp/linear_regression)
+
+SRCS(
+ linear_regression_ut.cpp
+)
+
+END()
diff --git a/library/cpp/linear_regression/welford.cpp b/library/cpp/linear_regression/welford.cpp
new file mode 100644
index 0000000000..e27b1994f6
--- /dev/null
+++ b/library/cpp/linear_regression/welford.cpp
@@ -0,0 +1,107 @@
+#include "welford.h"
+
+#include <util/generic/ymath.h>
+
+void TMeanCalculator::Multiply(const double value) {
+ SumWeights *= value;
+}
+
+void TMeanCalculator::Add(const double value, const double weight /*= 1.*/) {
+ SumWeights += weight;
+ if (SumWeights.Get()) {
+ Mean += weight * (value - Mean) / SumWeights.Get();
+ }
+}
+
+void TMeanCalculator::Remove(const double value, const double weight /*= 1.*/) {
+ SumWeights -= weight;
+ if (SumWeights.Get()) {
+ Mean -= weight * (value - Mean) / SumWeights.Get();
+ }
+}
+
+double TMeanCalculator::GetMean() const {
+ return Mean;
+}
+
+double TMeanCalculator::GetSumWeights() const {
+ return SumWeights.Get();
+}
+
+void TMeanCalculator::Reset() {
+ *this = TMeanCalculator();
+}
+
+void TCovariationCalculator::Add(const double firstValue, const double secondValue, const double weight /*= 1.*/) {
+ SumWeights += weight;
+ if (SumWeights.Get()) {
+ FirstValueMean += weight * (firstValue - FirstValueMean) / SumWeights.Get();
+ Covariation += weight * (firstValue - FirstValueMean) * (secondValue - SecondValueMean);
+ SecondValueMean += weight * (secondValue - SecondValueMean) / SumWeights.Get();
+ }
+}
+
+void TCovariationCalculator::Remove(const double firstValue, const double secondValue, const double weight /*= 1.*/) {
+ SumWeights -= weight;
+ if (SumWeights.Get()) {
+ FirstValueMean -= weight * (firstValue - FirstValueMean) / SumWeights.Get();
+ Covariation -= weight * (firstValue - FirstValueMean) * (secondValue - SecondValueMean);
+ SecondValueMean -= weight * (secondValue - SecondValueMean) / SumWeights.Get();
+ }
+}
+
+double TCovariationCalculator::GetFirstValueMean() const {
+ return FirstValueMean;
+}
+
+double TCovariationCalculator::GetSecondValueMean() const {
+ return SecondValueMean;
+}
+
+double TCovariationCalculator::GetCovariation() const {
+ return Covariation;
+}
+
+double TCovariationCalculator::GetSumWeights() const {
+ return SumWeights.Get();
+}
+
+void TCovariationCalculator::Reset() {
+ *this = TCovariationCalculator();
+}
+
+void TDeviationCalculator::Add(const double value, const double weight /*= 1.*/) {
+ const double lastMean = MeanCalculator.GetMean();
+ MeanCalculator.Add(value, weight);
+ Deviation += weight * (value - lastMean) * (value - MeanCalculator.GetMean());
+}
+
+void TDeviationCalculator::Remove(const double value, const double weight /*= 1.*/) {
+ const double lastMean = MeanCalculator.GetMean();
+ MeanCalculator.Remove(value, weight);
+ Deviation -= weight * (value - lastMean) * (value - MeanCalculator.GetMean());
+}
+
+double TDeviationCalculator::GetMean() const {
+ return MeanCalculator.GetMean();
+}
+
+double TDeviationCalculator::GetDeviation() const {
+ return Deviation;
+}
+
+double TDeviationCalculator::GetStdDev() const {
+ const double sumWeights = GetSumWeights();
+ if (!sumWeights) {
+ return 0.;
+ }
+ return sqrt(GetDeviation() / sumWeights);
+}
+
+double TDeviationCalculator::GetSumWeights() const {
+ return MeanCalculator.GetSumWeights();
+}
+
+void TDeviationCalculator::Reset() {
+ *this = TDeviationCalculator();
+}
diff --git a/library/cpp/linear_regression/welford.h b/library/cpp/linear_regression/welford.h
new file mode 100644
index 0000000000..ee865d6693
--- /dev/null
+++ b/library/cpp/linear_regression/welford.h
@@ -0,0 +1,77 @@
+#pragma once
+
+#include <library/cpp/accurate_accumulate/accurate_accumulate.h>
+
+#include <util/ysaveload.h>
+
+// accurately computes (w_1 * x_1 + w_2 * x_2 + ... + w_n * x_n) / (w_1 + w_2 + ... + w_n)
+class TMeanCalculator {
+private:
+ double Mean = 0.;
+ TKahanAccumulator<double> SumWeights;
+
+public:
+ Y_SAVELOAD_DEFINE(Mean, SumWeights);
+
+ void Multiply(const double value);
+ void Add(const double value, const double weight = 1.);
+ void Remove(const double value, const double weight = 1.);
+ double GetMean() const;
+ double GetSumWeights() const;
+ void Reset();
+
+ bool operator<(const TMeanCalculator& other) const {
+ return Mean < other.Mean;
+ }
+
+ bool operator>(const TMeanCalculator& other) const {
+ return Mean > other.Mean;
+ }
+};
+
+// accurately computes (w_1 * x_1 * y_1 + w_2 * x_2 * y_2 + ... + w_n * x_n * y_n) / (w_1 + w_2 + ... + w_n)
+class TCovariationCalculator {
+private:
+ double Covariation = 0.;
+
+ double FirstValueMean = 0.;
+ double SecondValueMean = 0.;
+
+ TKahanAccumulator<double> SumWeights;
+
+public:
+ Y_SAVELOAD_DEFINE(Covariation, FirstValueMean, SecondValueMean, SumWeights);
+
+ void Add(const double firstValue, const double secondValue, const double weight = 1.);
+ void Remove(const double firstValue, const double secondValue, const double weight = 1.);
+
+ double GetFirstValueMean() const;
+ double GetSecondValueMean() const;
+
+ double GetCovariation() const;
+
+ double GetSumWeights() const;
+
+ void Reset();
+};
+
+// accurately computes (w_1 * x_1 * x_1 + w_2 * x_2 * x_2 + ... + w_n * x_n * x_n) / (w_1 + w_2 + ... + w_n)
+class TDeviationCalculator {
+private:
+ double Deviation = 0.;
+ TMeanCalculator MeanCalculator;
+
+public:
+ Y_SAVELOAD_DEFINE(Deviation, MeanCalculator);
+
+ void Add(const double value, const double weight = 1.);
+ void Remove(const double value, const double weight = 1.);
+
+ double GetMean() const;
+ double GetDeviation() const;
+ double GetStdDev() const;
+
+ double GetSumWeights() const;
+
+ void Reset();
+};
diff --git a/library/cpp/linear_regression/ya.make b/library/cpp/linear_regression/ya.make
new file mode 100644
index 0000000000..4cfcc3d673
--- /dev/null
+++ b/library/cpp/linear_regression/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(alex-sh)
+
+SRCS(
+ linear_regression.cpp
+ unimodal.cpp
+ welford.cpp
+)
+
+PEERDIR(
+ library/cpp/accurate_accumulate
+)
+
+END()
diff --git a/library/cpp/logger/all.h b/library/cpp/logger/all.h
new file mode 100644
index 0000000000..ee1666844e
--- /dev/null
+++ b/library/cpp/logger/all.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "log.h"
+#include "null.h"
+#include "file.h"
+#include "stream.h"
+#include "thread.h"
+#include "system.h"
+#include "sync_page_cache_file.h"
diff --git a/library/cpp/logger/backend.cpp b/library/cpp/logger/backend.cpp
new file mode 100644
index 0000000000..b26bf5e88c
--- /dev/null
+++ b/library/cpp/logger/backend.cpp
@@ -0,0 +1,71 @@
+#include "backend.h"
+#include <util/generic/vector.h>
+#include <util/system/mutex.h>
+#include <util/generic/singleton.h>
+#include <util/generic/yexception.h>
+
+namespace {
+ class TGlobalLogsStorage {
+ private:
+ TVector<TLogBackend*> Backends;
+ TMutex Mutex;
+
+ public:
+ void Register(TLogBackend* backend) {
+ TGuard<TMutex> g(Mutex);
+ Backends.push_back(backend);
+ }
+
+ void UnRegister(TLogBackend* backend) {
+ TGuard<TMutex> g(Mutex);
+ for (ui32 i = 0; i < Backends.size(); ++i) {
+ if (Backends[i] == backend) {
+ Backends.erase(Backends.begin() + i);
+ return;
+ }
+ }
+ Y_FAIL("Incorrect pointer for log backend");
+ }
+
+ void Reopen(bool flush) {
+ TGuard<TMutex> g(Mutex);
+ for (auto& b : Backends) {
+ if (flush) {
+ b->ReopenLog();
+ } else {
+ b->ReopenLogNoFlush();
+ }
+ }
+ }
+ };
+}
+
+template <>
+class TSingletonTraits<TGlobalLogsStorage> {
+public:
+ static const size_t Priority = 50;
+};
+
+ELogPriority TLogBackend::FiltrationLevel() const {
+ return LOG_MAX_PRIORITY;
+}
+
+TLogBackend::TLogBackend() noexcept {
+ Singleton<TGlobalLogsStorage>()->Register(this);
+}
+
+TLogBackend::~TLogBackend() {
+ Singleton<TGlobalLogsStorage>()->UnRegister(this);
+}
+
+void TLogBackend::ReopenLogNoFlush() {
+ ReopenLog();
+}
+
+void TLogBackend::ReopenAllBackends(bool flush) {
+ Singleton<TGlobalLogsStorage>()->Reopen(flush);
+}
+
+size_t TLogBackend::QueueSize() const {
+ ythrow yexception() << "Not implemented.";
+}
diff --git a/library/cpp/logger/backend.h b/library/cpp/logger/backend.h
new file mode 100644
index 0000000000..d088726d6d
--- /dev/null
+++ b/library/cpp/logger/backend.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "priority.h"
+
+#include <util/generic/noncopyable.h>
+
+#include <cstddef>
+
+struct TLogRecord;
+
+// NOTE: be aware that all `TLogBackend`s are registred in singleton.
+class TLogBackend: public TNonCopyable {
+public:
+ TLogBackend() noexcept;
+ virtual ~TLogBackend();
+
+ virtual void WriteData(const TLogRecord& rec) = 0;
+ virtual void ReopenLog() = 0;
+
+ // Does not guarantee consistency with previous WriteData() calls:
+ // log entries could be written to the new (reopened) log file due to
+ // buffering effects.
+ virtual void ReopenLogNoFlush();
+
+ virtual ELogPriority FiltrationLevel() const;
+
+ static void ReopenAllBackends(bool flush = true);
+
+ virtual size_t QueueSize() const;
+};
diff --git a/library/cpp/logger/backend_creator.cpp b/library/cpp/logger/backend_creator.cpp
new file mode 100644
index 0000000000..ea430edb83
--- /dev/null
+++ b/library/cpp/logger/backend_creator.cpp
@@ -0,0 +1,45 @@
+#include "backend_creator.h"
+#include "stream.h"
+#include "uninitialized_creator.h"
+#include <util/system/yassert.h>
+#include <util/stream/debug.h>
+#include <util/stream/output.h>
+
+
+THolder<TLogBackend> ILogBackendCreator::CreateLogBackend() const {
+ try {
+ return DoCreateLogBackend();
+ } catch(...) {
+ Cdbg << "Warning: " << CurrentExceptionMessage() << ". Use stderr instead." << Endl;
+ }
+ return MakeHolder<TStreamLogBackend>(&Cerr);
+}
+
+bool ILogBackendCreator::Init(const IInitContext& /*ctx*/) {
+ return true;
+}
+
+
+NJson::TJsonValue ILogBackendCreator::AsJson() const {
+ NJson::TJsonValue json;
+ ToJson(json);
+ return json;
+}
+
+THolder<ILogBackendCreator> ILogBackendCreator::Create(const IInitContext& ctx) {
+ auto res = MakeHolder<TLogBackendCreatorUninitialized>();
+ if(!res->Init(ctx)) {
+ Cdbg << "Cannot init log backend creator";
+ return nullptr;
+ }
+ return res;
+}
+
+TLogBackendCreatorBase::TLogBackendCreatorBase(const TString& type)
+ : Type(type)
+{}
+
+void TLogBackendCreatorBase::ToJson(NJson::TJsonValue& value) const {
+ value["LoggerType"] = Type;
+ DoToJson(value);
+}
diff --git a/library/cpp/logger/backend_creator.h b/library/cpp/logger/backend_creator.h
new file mode 100644
index 0000000000..4f0ca24a4e
--- /dev/null
+++ b/library/cpp/logger/backend_creator.h
@@ -0,0 +1,59 @@
+#pragma once
+
+#include "backend.h"
+#include <library/cpp/object_factory/object_factory.h>
+#include <library/cpp/json/json_value.h>
+#include <util/generic/vector.h>
+#include <util/generic/ptr.h>
+#include <util/string/cast.h>
+
+class ILogBackendCreator {
+public:
+ using TFactory = NObjectFactory::TObjectFactory<ILogBackendCreator, TString>;
+
+ class IInitContext {
+ public:
+ template<class T>
+ bool GetValue(TStringBuf name, T& var) const {
+ TString tmp;
+ if (!GetValue(name, tmp)) {
+ return false;
+ }
+ var = FromString<T>(tmp);
+ return true;
+ }
+
+ template<class T>
+ T GetOrElse(TStringBuf name, const T& def) const {
+ T res;
+ return GetValue(name, res) ? res : def;
+ }
+
+ virtual ~IInitContext() = default;
+ virtual bool GetValue(TStringBuf name, TString& var) const = 0;
+ virtual TVector<THolder<IInitContext>> GetChildren(TStringBuf name) const = 0;
+ };
+
+public:
+ virtual ~ILogBackendCreator() = default;
+ THolder<TLogBackend> CreateLogBackend() const;
+ virtual bool Init(const IInitContext& ctx);
+
+ NJson::TJsonValue AsJson() const;
+ virtual void ToJson(NJson::TJsonValue& value) const = 0;
+
+ static THolder<ILogBackendCreator> Create(const IInitContext& ctx);
+
+private:
+ virtual THolder<TLogBackend> DoCreateLogBackend() const = 0;
+};
+
+class TLogBackendCreatorBase: public ILogBackendCreator {
+public:
+ TLogBackendCreatorBase(const TString& type);
+ virtual void ToJson(NJson::TJsonValue& value) const override final;
+
+protected:
+ virtual void DoToJson(NJson::TJsonValue& value) const = 0;
+ TString Type;
+};
diff --git a/library/cpp/logger/composite.cpp b/library/cpp/logger/composite.cpp
new file mode 100644
index 0000000000..3ce0154ced
--- /dev/null
+++ b/library/cpp/logger/composite.cpp
@@ -0,0 +1,18 @@
+#include "composite.h"
+#include "uninitialized_creator.h"
+
+void TCompositeLogBackend::WriteData(const TLogRecord& rec) {
+ for (auto& slave: Slaves) {
+ slave->WriteData(rec);
+ }
+}
+
+void TCompositeLogBackend::ReopenLog() {
+ for (auto& slave : Slaves) {
+ slave->ReopenLog();
+ }
+}
+
+void TCompositeLogBackend::AddLogBackend(THolder<TLogBackend>&& backend) {
+ Slaves.emplace_back(std::move(backend));
+}
diff --git a/library/cpp/logger/composite.h b/library/cpp/logger/composite.h
new file mode 100644
index 0000000000..142c61b8d5
--- /dev/null
+++ b/library/cpp/logger/composite.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "backend.h"
+#include <util/generic/vector.h>
+
+class TCompositeLogBackend: public TLogBackend {
+public:
+ virtual void WriteData(const TLogRecord& rec) override;
+ virtual void ReopenLog() override;
+ virtual void AddLogBackend(THolder<TLogBackend>&& backend);
+
+private:
+ TVector<THolder<TLogBackend>> Slaves;
+};
diff --git a/library/cpp/logger/composite_creator.cpp b/library/cpp/logger/composite_creator.cpp
new file mode 100644
index 0000000000..2064265766
--- /dev/null
+++ b/library/cpp/logger/composite_creator.cpp
@@ -0,0 +1,34 @@
+#include "composite_creator.h"
+#include "composite.h"
+#include "uninitialized_creator.h"
+
+THolder<TLogBackend> TCompositeBackendCreator::DoCreateLogBackend() const {
+ auto res = MakeHolder<TCompositeLogBackend>();
+ for (const auto& child : Children) {
+ res->AddLogBackend(child->CreateLogBackend());
+ }
+ return std::move(res);
+}
+
+
+TCompositeBackendCreator::TCompositeBackendCreator()
+ : TLogBackendCreatorBase("composite")
+{}
+
+bool TCompositeBackendCreator::Init(const IInitContext& ctx) {
+ for (const auto& child : ctx.GetChildren("SubLogger")) {
+ Children.emplace_back(MakeHolder<TLogBackendCreatorUninitialized>());
+ if (!Children.back()->Init(*child)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+ILogBackendCreator::TFactory::TRegistrator<TCompositeBackendCreator> TCompositeBackendCreator::Registrar("composite");
+
+void TCompositeBackendCreator::DoToJson(NJson::TJsonValue& value) const {
+ for (const auto& child: Children) {
+ child->ToJson(value["SubLogger"].AppendValue(NJson::JSON_MAP));
+ }
+}
diff --git a/library/cpp/logger/composite_creator.h b/library/cpp/logger/composite_creator.h
new file mode 100644
index 0000000000..877d3a2b33
--- /dev/null
+++ b/library/cpp/logger/composite_creator.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "backend_creator.h"
+#include <util/generic/vector.h>
+
+class TCompositeBackendCreator : public TLogBackendCreatorBase {
+public:
+ TCompositeBackendCreator();
+ virtual bool Init(const IInitContext& ctx) override;
+ static TFactory::TRegistrator<TCompositeBackendCreator> Registrar;
+
+protected:
+ virtual void DoToJson(NJson::TJsonValue& value) const override;
+
+private:
+ virtual THolder<TLogBackend> DoCreateLogBackend() const override;
+ TVector<THolder<ILogBackendCreator>> Children;
+};
diff --git a/library/cpp/logger/composite_ut.cpp b/library/cpp/logger/composite_ut.cpp
new file mode 100644
index 0000000000..f330419271
--- /dev/null
+++ b/library/cpp/logger/composite_ut.cpp
@@ -0,0 +1,98 @@
+#include "log.h"
+#include <library/cpp/logger/init_context/config.h>
+#include <library/cpp/logger/init_context/yconf.h>
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/yconf/patcher/unstrict_config.h>
+#include <util/stream/file.h>
+#include <util/system/fs.h>
+
+Y_UNIT_TEST_SUITE(TCompositeLogTest)
+{
+ TVector<TString> ReadLines(const TString & filename) {
+ TVector<TString> lines;
+ TIFStream fin(filename);
+ TString line;
+ while (fin.ReadLine(line)) {
+ lines.push_back(std::move(line));
+ }
+ return lines;
+ }
+
+ void Clear(const TString & filename) {
+ NFs::Remove(filename + "1");
+ NFs::Remove(filename + "2");
+ }
+
+ void DoTestComposite(const ILogBackendCreator::IInitContext& ctx, const TString & filename) {
+ Clear(filename);
+ {
+ TLog log;
+ {
+ auto creator = ILogBackendCreator::Create(ctx);
+ log.ResetBackend(creator->CreateLogBackend());
+ log.ReopenLog();
+ }
+ log.Write(TLOG_ERR, "first\n");
+ log.Write(TLOG_DEBUG, "second\n");
+ }
+ auto data1 = ReadLines(filename + "1");
+ auto data2 = ReadLines(filename + "2");
+ UNIT_ASSERT_VALUES_EQUAL(data1.size(), 2);
+ UNIT_ASSERT(data1[0] == "first");
+ UNIT_ASSERT(data1[1] == "second");
+
+ UNIT_ASSERT_VALUES_EQUAL(data2.size(), 1);
+ UNIT_ASSERT(data2[0] == "first");
+ Clear(filename);
+ }
+
+ Y_UNIT_TEST(TestCompositeConfig) {
+ TString s(R"(
+{
+ "LoggerType": "composite",
+ "SubLogger":[
+ {
+ "LoggerType": "file",
+ "Path": "config_log_1"
+ }, {
+ "LoggerType": "config_log_2",
+ "LogLevel": "INFO"
+ }
+ ]
+})");
+ TStringInput si(s);
+ NConfig::TConfig cfg = NConfig::TConfig::FromJson(si);
+ //Прогоняем конфигурацию через серализацию и десериализацию
+ TLogBackendCreatorInitContextConfig ctx(cfg);
+ TString newCfg = ILogBackendCreator::Create(ctx)->AsJson().GetStringRobust();
+ TStringInput si2(newCfg);
+ DoTestComposite(TLogBackendCreatorInitContextConfig(NConfig::TConfig::FromJson(si2)), "config_log_");
+
+ }
+ Y_UNIT_TEST(TestCompositeYConf) {
+ constexpr const char* CONFIG = R"(
+<Logger>
+ LoggerType: composite
+ <SubLogger>
+ LoggerType: file
+ Path: yconf_log_1
+ </SubLogger>
+ <SubLogger>
+ LoggerType: yconf_log_2
+ LogLevel: INFO
+ </SubLogger>
+</Logger>
+)";
+ TUnstrictConfig cfg;
+ if (!cfg.ParseMemory(CONFIG)) {
+ TString errors;
+ cfg.PrintErrors(errors);
+ UNIT_ASSERT_C(false, errors);
+ }
+ TLogBackendCreatorInitContextYConf ctx(*cfg.GetFirstChild("Logger"));
+ //Прогоняем конфигурацию через серализацию и десериализацию
+ TUnstrictConfig newCfg;
+ UNIT_ASSERT(newCfg.ParseJson(ILogBackendCreator::Create(ctx)->AsJson()));
+ DoTestComposite(TLogBackendCreatorInitContextYConf(*newCfg.GetRootSection()), "yconf_log_");
+ }
+};
diff --git a/library/cpp/logger/element.cpp b/library/cpp/logger/element.cpp
new file mode 100644
index 0000000000..b510fe16e1
--- /dev/null
+++ b/library/cpp/logger/element.cpp
@@ -0,0 +1,38 @@
+#include "log.h"
+#include "element.h"
+
+#include <utility>
+
+TLogElement::TLogElement(const TLog* parent)
+ : Parent_(parent)
+ , Priority_(Parent_->DefaultPriority())
+{
+ Reset();
+}
+
+TLogElement::TLogElement(const TLog* parent, ELogPriority priority)
+ : Parent_(parent)
+ , Priority_(priority)
+{
+ Reset();
+}
+
+TLogElement::~TLogElement() {
+ try {
+ Finish();
+ } catch (...) {
+ }
+}
+
+void TLogElement::DoFlush() {
+ if (IsNull()) {
+ return;
+ }
+
+ const size_t filled = Filled();
+
+ if (filled) {
+ Parent_->Write(Priority_, Data(), filled);
+ Reset();
+ }
+}
diff --git a/library/cpp/logger/element.h b/library/cpp/logger/element.h
new file mode 100644
index 0000000000..fc9bff851f
--- /dev/null
+++ b/library/cpp/logger/element.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include "priority.h"
+
+#include <util/stream/tempbuf.h>
+
+class TLog;
+
+/*
+ * better do not use directly
+ */
+class TLogElement: public TTempBufOutput {
+public:
+ TLogElement(const TLog* parent);
+ TLogElement(const TLog* parent, ELogPriority priority);
+
+ TLogElement(TLogElement&&) noexcept = default;
+ TLogElement& operator=(TLogElement&&) noexcept = default;
+
+ ~TLogElement() override;
+
+ template <class T>
+ inline TLogElement& operator<<(const T& t) {
+ static_cast<IOutputStream&>(*this) << t;
+
+ return *this;
+ }
+
+ /*
+ * for pretty usage: logger << TLOG_ERROR << "Error description";
+ */
+ inline TLogElement& operator<<(ELogPriority priority) {
+ Flush();
+ Priority_ = priority;
+ return *this;
+ }
+
+ ELogPriority Priority() const noexcept {
+ return Priority_;
+ }
+
+protected:
+ void DoFlush() override;
+
+protected:
+ const TLog* Parent_;
+ ELogPriority Priority_;
+};
diff --git a/library/cpp/logger/element_ut.cpp b/library/cpp/logger/element_ut.cpp
new file mode 100644
index 0000000000..32edc52dfb
--- /dev/null
+++ b/library/cpp/logger/element_ut.cpp
@@ -0,0 +1,39 @@
+#include "log.h"
+#include "element.h"
+#include "stream.h"
+
+#include <util/generic/string.h>
+#include <util/stream/str.h>
+#include <util/generic/ptr.h>
+#include <utility>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+class TLogElementTest: public TTestBase {
+ UNIT_TEST_SUITE(TLogElementTest);
+ UNIT_TEST(TestMoveCtor);
+ UNIT_TEST_SUITE_END();
+
+public:
+ void TestMoveCtor();
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TLogElementTest);
+
+void TLogElementTest::TestMoveCtor() {
+ TStringStream output;
+ TLog log(MakeHolder<TStreamLogBackend>(&output));
+
+ THolder<TLogElement> src = MakeHolder<TLogElement>(&log);
+
+ TString message = "Hello, World!";
+ (*src) << message;
+
+ THolder<TLogElement> dst = MakeHolder<TLogElement>(std::move(*src));
+
+ src.Destroy();
+ UNIT_ASSERT(output.Str() == "");
+
+ dst.Destroy();
+ UNIT_ASSERT(output.Str() == message);
+}
diff --git a/library/cpp/logger/file.cpp b/library/cpp/logger/file.cpp
new file mode 100644
index 0000000000..15a4946eda
--- /dev/null
+++ b/library/cpp/logger/file.cpp
@@ -0,0 +1,59 @@
+#include "file.h"
+#include "record.h"
+
+#include <util/system/file.h>
+#include <util/system/rwlock.h>
+#include <util/generic/string.h>
+
+/*
+ * file log
+ */
+class TFileLogBackend::TImpl {
+public:
+ inline TImpl(const TString& path)
+ : File_(OpenFile(path))
+ {
+ }
+
+ inline void WriteData(const TLogRecord& rec) {
+ //many writes are thread-safe
+ TReadGuard guard(Lock_);
+
+ File_.Write(rec.Data, rec.Len);
+ }
+
+ inline void ReopenLog() {
+ //but log rotate not thread-safe
+ TWriteGuard guard(Lock_);
+
+ File_.LinkTo(OpenFile(File_.GetName()));
+ }
+
+private:
+ static inline TFile OpenFile(const TString& path) {
+ return TFile(path, OpenAlways | WrOnly | ForAppend | Seq | NoReuse);
+ }
+
+private:
+ TRWMutex Lock_;
+ TFile File_;
+};
+
+TFileLogBackend::TFileLogBackend(const TString& path)
+ : Impl_(new TImpl(path))
+{
+}
+
+TFileLogBackend::~TFileLogBackend() {
+}
+
+void TFileLogBackend::WriteData(const TLogRecord& rec) {
+ Impl_->WriteData(rec);
+}
+
+void TFileLogBackend::ReopenLog() {
+ TAtomicSharedPtr<TImpl> copy = Impl_;
+ if (copy) {
+ copy->ReopenLog();
+ }
+}
diff --git a/library/cpp/logger/file.h b/library/cpp/logger/file.h
new file mode 100644
index 0000000000..10b4cd0c20
--- /dev/null
+++ b/library/cpp/logger/file.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "backend.h"
+
+#include <util/generic/fwd.h>
+#include <util/generic/ptr.h>
+
+class TFileLogBackend: public TLogBackend {
+public:
+ TFileLogBackend(const TString& path);
+ ~TFileLogBackend() override;
+
+ void WriteData(const TLogRecord& rec) override;
+ void ReopenLog() override;
+
+private:
+ class TImpl;
+ TAtomicSharedPtr<TImpl> Impl_;
+};
diff --git a/library/cpp/logger/file_creator.cpp b/library/cpp/logger/file_creator.cpp
new file mode 100644
index 0000000000..0a84469e43
--- /dev/null
+++ b/library/cpp/logger/file_creator.cpp
@@ -0,0 +1,22 @@
+#include "file_creator.h"
+#include "file.h"
+
+TFileLogBackendCreator::TFileLogBackendCreator(const TString& path /*= TString()*/, const TString& type /*= "file"*/)
+ : TLogBackendCreatorBase(type)
+ , Path(path)
+{}
+
+THolder<TLogBackend> TFileLogBackendCreator::DoCreateLogBackend() const {
+ return MakeHolder<TFileLogBackend>(Path);
+}
+
+bool TFileLogBackendCreator::Init(const IInitContext& ctx) {
+ ctx.GetValue("Path", Path);
+ return !!Path;
+}
+
+ILogBackendCreator::TFactory::TRegistrator<TFileLogBackendCreator> TFileLogBackendCreator::Registrar("file");
+
+void TFileLogBackendCreator::DoToJson(NJson::TJsonValue& value) const {
+ value["Path"] = Path;
+}
diff --git a/library/cpp/logger/file_creator.h b/library/cpp/logger/file_creator.h
new file mode 100644
index 0000000000..73e55261ad
--- /dev/null
+++ b/library/cpp/logger/file_creator.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "backend_creator.h"
+
+class TFileLogBackendCreator : public TLogBackendCreatorBase {
+public:
+ TFileLogBackendCreator(const TString& path = TString(), const TString& type = "file");
+ virtual bool Init(const IInitContext& ctx) override;
+ static TFactory::TRegistrator<TFileLogBackendCreator> Registrar;
+
+protected:
+ virtual void DoToJson(NJson::TJsonValue& value) const override;
+ TString Path;
+
+private:
+ virtual THolder<TLogBackend> DoCreateLogBackend() const override;
+};
diff --git a/library/cpp/logger/filter.cpp b/library/cpp/logger/filter.cpp
new file mode 100644
index 0000000000..300ac6b595
--- /dev/null
+++ b/library/cpp/logger/filter.cpp
@@ -0,0 +1 @@
+#include "filter.h"
diff --git a/library/cpp/logger/filter.h b/library/cpp/logger/filter.h
new file mode 100644
index 0000000000..9ef83fb58c
--- /dev/null
+++ b/library/cpp/logger/filter.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "priority.h"
+#include "record.h"
+#include "backend.h"
+#include <util/generic/ptr.h>
+
+class TFilteredLogBackend: public TLogBackend {
+ THolder<TLogBackend> Backend;
+ ELogPriority Level;
+
+public:
+ TFilteredLogBackend(THolder<TLogBackend>&& t, ELogPriority level = LOG_MAX_PRIORITY) noexcept
+ : Backend(std::move(t))
+ , Level(level)
+ {
+ }
+
+ ELogPriority FiltrationLevel() const override {
+ return Level;
+ }
+
+ void ReopenLog() override {
+ Backend->ReopenLog();
+ }
+
+ void WriteData(const TLogRecord& rec) override {
+ if (rec.Priority <= (ELogPriority)Level) {
+ Backend->WriteData(rec);
+ }
+ }
+};
diff --git a/library/cpp/logger/filter_creator.cpp b/library/cpp/logger/filter_creator.cpp
new file mode 100644
index 0000000000..fd5618087b
--- /dev/null
+++ b/library/cpp/logger/filter_creator.cpp
@@ -0,0 +1,20 @@
+#include "filter_creator.h"
+#include "filter.h"
+
+TFilteredBackendCreator::TFilteredBackendCreator(THolder<ILogBackendCreator> slave, ELogPriority priority)
+ : Slave(std::move(slave))
+ , Priority(priority)
+{}
+
+THolder<TLogBackend> TFilteredBackendCreator::DoCreateLogBackend() const {
+ return MakeHolder<TFilteredLogBackend>(Slave->CreateLogBackend(), Priority);
+}
+
+bool TFilteredBackendCreator::Init(const IInitContext& ctx) {
+ return Slave->Init(ctx);
+}
+
+void TFilteredBackendCreator::ToJson(NJson::TJsonValue& value) const {
+ value["LogLevel"] = ToString(Priority);
+ Slave->ToJson(value);
+}
diff --git a/library/cpp/logger/filter_creator.h b/library/cpp/logger/filter_creator.h
new file mode 100644
index 0000000000..0f301457a0
--- /dev/null
+++ b/library/cpp/logger/filter_creator.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "backend_creator.h"
+#include "priority.h"
+
+class TFilteredBackendCreator : public ILogBackendCreator {
+public:
+ TFilteredBackendCreator(THolder<ILogBackendCreator> slave, ELogPriority priority);
+ virtual bool Init(const IInitContext& ctx) override;
+ virtual void ToJson(NJson::TJsonValue& value) const override;
+
+private:
+ virtual THolder<TLogBackend> DoCreateLogBackend() const override;
+ THolder<ILogBackendCreator> Slave;
+ ELogPriority Priority;
+};
diff --git a/library/cpp/logger/global/common.cpp b/library/cpp/logger/global/common.cpp
new file mode 100644
index 0000000000..4fb05c19b4
--- /dev/null
+++ b/library/cpp/logger/global/common.cpp
@@ -0,0 +1,36 @@
+#include "common.h"
+
+#include <util/generic/yexception.h>
+
+namespace NLoggingImpl {
+ TString GetLocalTimeSSimple() {
+ struct tm tm;
+ return Strftime("%b%d_%H%M%S", Now().LocalTime(&tm));
+ }
+
+ TString PrepareToOpenLog(TString logType, const int logLevel, const bool rotation, const bool startAsDaemon) {
+ Y_ENSURE(logLevel >= 0 && logLevel <= (int)LOG_MAX_PRIORITY, "Incorrect log level");
+
+ if (rotation && TFsPath(logType).Exists()) {
+ TString newPath = Sprintf("%s_%s_%" PRIu64, logType.data(), NLoggingImpl::GetLocalTimeSSimple().data(), static_cast<ui64>(Now().MicroSeconds()));
+ TFsPath(logType).RenameTo(newPath);
+ }
+ if (startAsDaemon && (logType == "console"sv || logType == "cout"sv || logType == "cerr"sv)) {
+ logType = "null";
+ }
+
+ return logType;
+ }
+}
+
+bool TLogFilter::CheckLoggingContext(TLog& log, const TLogRecordContext& context) {
+ return context.Priority <= log.FiltrationLevel();
+}
+
+TSimpleSharedPtr<TLogElement> TLogFilter::StartRecord(TLog& logger, const TLogRecordContext& context, TSimpleSharedPtr<TLogElement> earlier) {
+ if (earlier)
+ return earlier;
+ TSimpleSharedPtr<TLogElement> result(new TLogElement(&logger));
+ *result << context.Priority;
+ return result;
+}
diff --git a/library/cpp/logger/global/common.h b/library/cpp/logger/global/common.h
new file mode 100644
index 0000000000..7dcf650dec
--- /dev/null
+++ b/library/cpp/logger/global/common.h
@@ -0,0 +1,149 @@
+#pragma once
+
+#include <util/datetime/base.h>
+
+#include <util/folder/path.h>
+#include <util/generic/singleton.h>
+#include <util/generic/string.h>
+#include <util/generic/ptr.h>
+#include <util/generic/yexception.h>
+#include <util/string/printf.h>
+#include <util/system/src_location.h>
+
+#include <library/cpp/logger/log.h>
+
+namespace NLoggingImpl {
+ const size_t SingletonPriority = 500;
+}
+
+template <class T>
+T* CreateDefaultLogger() {
+ return nullptr;
+}
+
+namespace NLoggingImpl {
+ template<class T, class TTraits>
+ class TOperatorBase {
+ struct TPtr {
+ TPtr()
+ : Instance(TTraits::CreateDefault())
+ {
+ }
+
+ THolder<T> Instance;
+ };
+
+ public:
+ inline static bool Usage() {
+ return SingletonWithPriority<TPtr, SingletonPriority>()->Instance.Get();
+ }
+
+ inline static T* Get() {
+ return SingletonWithPriority<TPtr, SingletonPriority>()->Instance.Get();
+ }
+
+ inline static void Set(T* v) {
+ SingletonWithPriority<TPtr, SingletonPriority>()->Instance.Reset(v);
+ }
+ };
+
+ template<class T>
+ struct TLoggerTraits {
+ static T* CreateDefault() {
+ return CreateDefaultLogger<T>();
+ }
+ };
+}
+
+template <class T>
+class TLoggerOperator : public NLoggingImpl::TOperatorBase<T, NLoggingImpl::TLoggerTraits<T>> {
+public:
+ inline static TLog& Log() {
+ Y_ASSERT(TLoggerOperator::Usage());
+ return *TLoggerOperator::Get();
+ }
+};
+
+namespace NLoggingImpl {
+
+ TString GetLocalTimeSSimple();
+
+ // Returns correct log type to use
+ TString PrepareToOpenLog(TString logType, int logLevel, bool rotation, bool startAsDaemon);
+
+ template <class TLoggerType>
+ void InitLogImpl(TString logType, const int logLevel, const bool rotation, const bool startAsDaemon) {
+ TLoggerOperator<TLoggerType>::Set(new TLoggerType(PrepareToOpenLog(logType, logLevel, rotation, startAsDaemon), (ELogPriority)logLevel));
+ }
+}
+
+struct TLogRecordContext {
+ constexpr TLogRecordContext(const TSourceLocation& sourceLocation, TStringBuf customMessage, ELogPriority priority)
+ : SourceLocation(sourceLocation)
+ , CustomMessage(customMessage)
+ , Priority(priority)
+ {}
+
+ TSourceLocation SourceLocation;
+ TStringBuf CustomMessage;
+ ELogPriority Priority;
+};
+
+template <class... R>
+struct TLogRecordPreprocessor;
+
+template <>
+struct TLogRecordPreprocessor<> {
+ inline static bool CheckLoggingContext(TLog& /*log*/, const TLogRecordContext& /*context*/) {
+ return true;
+ }
+
+ inline static TSimpleSharedPtr<TLogElement> StartRecord(TLog& log, const TLogRecordContext& context, TSimpleSharedPtr<TLogElement> earlier) {
+ if (earlier)
+ return earlier;
+ TSimpleSharedPtr<TLogElement> result(new TLogElement(&log));
+ *result << context.Priority;
+ return result;
+ }
+};
+
+template <class H, class... R>
+struct TLogRecordPreprocessor<H, R...> {
+ inline static bool CheckLoggingContext(TLog& log, const TLogRecordContext& context) {
+ return H::CheckLoggingContext(log, context) && TLogRecordPreprocessor<R...>::CheckLoggingContext(log, context);
+ }
+
+ inline static TSimpleSharedPtr<TLogElement> StartRecord(TLog& log, const TLogRecordContext& context, TSimpleSharedPtr<TLogElement> earlier) {
+ TSimpleSharedPtr<TLogElement> first = H::StartRecord(log, context, earlier);
+ return TLogRecordPreprocessor<R...>::StartRecord(log, context, first);
+ }
+};
+
+struct TLogFilter {
+ static bool CheckLoggingContext(TLog& log, const TLogRecordContext& context);
+ static TSimpleSharedPtr<TLogElement> StartRecord(TLog& log, const TLogRecordContext& context, TSimpleSharedPtr<TLogElement> earlier);
+};
+
+class TNullLog;
+
+template <class TPreprocessor>
+TSimpleSharedPtr<TLogElement> GetLoggerForce(TLog& log, const TLogRecordContext& context) {
+ if (TSimpleSharedPtr<TLogElement> result = TPreprocessor::StartRecord(log, context, nullptr))
+ return result;
+ return new TLogElement(&TLoggerOperator<TNullLog>::Log());
+}
+
+namespace NPrivateGlobalLogger {
+ struct TEatStream {
+ Y_FORCE_INLINE bool operator|(const IOutputStream&) const {
+ return true;
+ }
+ };
+}
+
+#define LOGGER_GENERIC_LOG_CHECKED(logger, preprocessor, level, message) (*GetLoggerForce<preprocessor>(logger, TLogRecordContext(__LOCATION__, message, level)))
+#define LOGGER_CHECKED_GENERIC_LOG(logger, preprocessor, level, message) \
+ (preprocessor::CheckLoggingContext(logger, TLogRecordContext(__LOCATION__, message, level))) && NPrivateGlobalLogger::TEatStream() | (*(preprocessor::StartRecord(logger, TLogRecordContext(__LOCATION__, message, level), nullptr)))
+
+#define SINGLETON_GENERIC_LOG_CHECKED(type, preprocessor, level, message) LOGGER_GENERIC_LOG_CHECKED(TLoggerOperator<type>::Log(), preprocessor, level, message)
+#define SINGLETON_CHECKED_GENERIC_LOG(type, preprocessor, level, message) LOGGER_CHECKED_GENERIC_LOG(TLoggerOperator<type>::Log(), preprocessor, level, message)
diff --git a/library/cpp/logger/global/global.cpp b/library/cpp/logger/global/global.cpp
new file mode 100644
index 0000000000..9fbd10f666
--- /dev/null
+++ b/library/cpp/logger/global/global.cpp
@@ -0,0 +1,43 @@
+#include "global.h"
+
+static void DoInitGlobalLog(THolder<TGlobalLog> logger, THolder<ILoggerFormatter> formatter) {
+ TLoggerOperator<TGlobalLog>::Set(logger.Release());
+ if (!formatter) {
+ formatter.Reset(CreateRtyLoggerFormatter());
+ }
+ TLoggerFormatterOperator::Set(formatter.Release());
+}
+
+void DoInitGlobalLog(const TString& logType, const int logLevel, const bool rotation, const bool startAsDaemon, THolder<ILoggerFormatter> formatter, bool threaded) {
+ DoInitGlobalLog(
+ MakeHolder<TGlobalLog>(
+ CreateLogBackend(
+ NLoggingImpl::PrepareToOpenLog(logType, logLevel, rotation, startAsDaemon),
+ (ELogPriority)logLevel,
+ threaded)),
+ std::move(formatter));
+}
+
+void DoInitGlobalLog(THolder<TLogBackend> backend, THolder<ILoggerFormatter> formatter) {
+ DoInitGlobalLog(THolder(new TGlobalLog(std::move(backend))), std::move(formatter));
+}
+
+bool GlobalLogInitialized() {
+ return TLoggerOperator<TGlobalLog>::Usage();
+}
+
+template <>
+TGlobalLog* CreateDefaultLogger<TGlobalLog>() {
+ return new TGlobalLog("console", TLOG_INFO);
+}
+
+template <>
+TNullLog* CreateDefaultLogger<TNullLog>() {
+ return new TNullLog("null");
+}
+
+NPrivateGlobalLogger::TVerifyEvent::~TVerifyEvent() {
+ const TString info = Str();
+ FATAL_LOG << info << Endl;
+ Y_FAIL("%s", info.data());
+}
diff --git a/library/cpp/logger/global/global.h b/library/cpp/logger/global/global.h
new file mode 100644
index 0000000000..cbe71b16ea
--- /dev/null
+++ b/library/cpp/logger/global/global.h
@@ -0,0 +1,125 @@
+#pragma once
+
+#include "common.h"
+#include "rty_formater.h"
+
+// ATTENTION! MUST CALL DoInitGlobalLog BEFORE USAGE
+
+bool GlobalLogInitialized();
+void DoInitGlobalLog(const TString& logType, const int logLevel, const bool rotation, const bool startAsDaemon, THolder<ILoggerFormatter> formatter = {}, bool threaded = false);
+void DoInitGlobalLog(THolder<TLogBackend> backend, THolder<ILoggerFormatter> formatter = {});
+
+inline void InitGlobalLog2Null() {
+ DoInitGlobalLog("null", TLOG_EMERG, false, false);
+}
+
+inline void InitGlobalLog2Console(int loglevel = TLOG_INFO) {
+ DoInitGlobalLog("console", loglevel, false, false);
+}
+
+class TGlobalLog: public TLog {
+public:
+ TGlobalLog(const TString& logType, ELogPriority priority = LOG_MAX_PRIORITY)
+ : TLog(logType, priority)
+ {
+ }
+
+ TGlobalLog(THolder<TLogBackend> backend)
+ : TLog(std::move(backend))
+ {
+ }
+};
+
+template <>
+TGlobalLog* CreateDefaultLogger<TGlobalLog>();
+
+class TNullLog: public TLog {
+public:
+ TNullLog(const TString& logType, ELogPriority priority = LOG_MAX_PRIORITY)
+ : TLog(logType, priority)
+ {
+ }
+
+ TNullLog(THolder<TLogBackend> backend)
+ : TLog(std::move(backend))
+ {
+ }
+};
+
+template <>
+TNullLog* CreateDefaultLogger<TNullLog>();
+
+template <>
+class TSingletonTraits<TLoggerOperator<TGlobalLog>::TPtr> {
+public:
+ static const size_t Priority = NLoggingImpl::SingletonPriority;
+};
+
+template <>
+class TSingletonTraits<TLoggerOperator<TNullLog>::TPtr> {
+public:
+ static const size_t Priority = NLoggingImpl::SingletonPriority;
+};
+
+#define FATAL_LOG SINGLETON_CHECKED_GENERIC_LOG(TGlobalLog, TRTYLogPreprocessor, TLOG_CRIT, "CRITICAL_INFO")
+#define ALERT_LOG SINGLETON_CHECKED_GENERIC_LOG(TGlobalLog, TRTYLogPreprocessor, TLOG_ALERT, "ALERT")
+#define ERROR_LOG SINGLETON_CHECKED_GENERIC_LOG(TGlobalLog, TRTYLogPreprocessor, TLOG_ERR, "ERROR")
+#define WARNING_LOG SINGLETON_CHECKED_GENERIC_LOG(TGlobalLog, TRTYLogPreprocessor, TLOG_WARNING, "WARNING")
+#define NOTICE_LOG SINGLETON_CHECKED_GENERIC_LOG(TGlobalLog, TRTYLogPreprocessor, TLOG_NOTICE, "NOTICE")
+#define INFO_LOG SINGLETON_CHECKED_GENERIC_LOG(TGlobalLog, TRTYLogPreprocessor, TLOG_INFO, "INFO")
+#define DEBUG_LOG SINGLETON_CHECKED_GENERIC_LOG(TGlobalLog, TRTYLogPreprocessor, TLOG_DEBUG, "DEBUG")
+#define RESOURCES_LOG SINGLETON_CHECKED_GENERIC_LOG(TGlobalLog, TRTYLogPreprocessor, TLOG_RESOURCES, "RESOURCES")
+
+#define TEMPLATE_LOG(logLevel) SINGLETON_CHECKED_GENERIC_LOG(TGlobalLog, TRTYLogPreprocessor, logLevel, ToString(logLevel).data())
+
+#define IS_LOG_ACTIVE(logLevel) (TLoggerOperator<TGlobalLog>::Log().FiltrationLevel() >= logLevel)
+
+#define RTY_MEM_LOG(Action) \
+ { NOTICE_LOG << "RESOURCES On " << Action << ": " << NLoggingImpl::GetSystemResources() << Endl; };
+
+#define VERIFY_WITH_LOG(expr, msg, ...) \
+ do { \
+ if (Y_UNLIKELY(!(expr))) { \
+ FATAL_LOG << Sprintf(msg, ##__VA_ARGS__) << Endl; \
+ Y_VERIFY(false, msg, ##__VA_ARGS__); \
+ }; \
+ } while (0);
+
+namespace NPrivateGlobalLogger {
+ class TVerifyEvent: public TStringStream {
+ public:
+ ~TVerifyEvent();
+ template <class T>
+ inline TVerifyEvent& operator<<(const T& t) {
+ static_cast<IOutputStream&>(*this) << t;
+
+ return *this;
+ }
+ };
+ class TNullStream: public TStringStream {
+ public:
+ ~TNullStream() = default;
+
+ template <class T>
+ inline TNullStream& operator<<(const T& /*t*/) {
+ return *this;
+ }
+ };
+}
+
+#define CHECK_WITH_LOG(expr) \
+ Y_UNLIKELY(!(expr)) && NPrivateGlobalLogger::TEatStream() | NPrivateGlobalLogger::TVerifyEvent() << __LOCATION__ << ": " << #expr << "(verification failed!): "
+
+#if !defined(NDEBUG) && !defined(__GCCXML__)
+#define ASSERT_WITH_LOG(expr) \
+ Y_UNLIKELY(!(expr)) && NPrivateGlobalLogger::TEatStream() | NPrivateGlobalLogger::TVerifyEvent() << __LOCATION__ << ": " << #expr << "(verification failed!): "
+#else
+#define ASSERT_WITH_LOG(expr) \
+ Y_UNLIKELY(false && !(expr)) && NPrivateGlobalLogger::TEatStream() | NPrivateGlobalLogger::TNullStream()
+#endif
+
+#define CHECK_EQ_WITH_LOG(a, b) CHECK_WITH_LOG((a) == (b)) << a << " != " << b;
+#define CHECK_LEQ_WITH_LOG(a, b) CHECK_WITH_LOG((a) <= (b)) << a << " > " << b;
+
+#define FAIL_LOG(msg, ...) VERIFY_WITH_LOG(false, msg, ##__VA_ARGS__)
+#define S_FAIL_LOG CHECK_WITH_LOG(false)
diff --git a/library/cpp/logger/global/rty_formater.cpp b/library/cpp/logger/global/rty_formater.cpp
new file mode 100644
index 0000000000..305f8470c5
--- /dev/null
+++ b/library/cpp/logger/global/rty_formater.cpp
@@ -0,0 +1,94 @@
+#include "rty_formater.h"
+#include <util/datetime/base.h>
+#include <util/datetime/systime.h>
+#include <util/stream/str.h>
+#include <util/stream/printf.h>
+#include <util/system/mem_info.h>
+#include <util/system/yassert.h>
+#include <inttypes.h>
+#include <cstdio>
+
+namespace {
+ constexpr size_t LocalTimeSBufferSize = sizeof("2017-07-24 12:20:34.313 +0300");
+
+ size_t PrintLocalTimeS(const TInstant instant, char* const begin, const char* const end) {
+ Y_VERIFY(static_cast<size_t>(end - begin) >= LocalTimeSBufferSize);
+
+ struct tm tm;
+ instant.LocalTime(&tm);
+
+ // both stftime and sprintf exclude the terminating null byte from the return value
+ char* pos = begin;
+ pos += strftime(pos, end - pos, "%Y-%m-%d %H:%M:%S.", &tm);
+ pos += sprintf(pos, "%03" PRIu32, instant.MilliSecondsOfSecond());
+ pos += strftime(pos, end - pos, " %z", &tm);
+ Y_VERIFY(LocalTimeSBufferSize - 1 == pos - begin); // together with Y_VERIFY above this also implies pos<=end
+ return (pos - begin);
+ }
+}
+
+namespace NLoggingImpl {
+ IOutputStream& operator<<(IOutputStream& out, TLocalTimeS localTimeS) {
+ char buffer[LocalTimeSBufferSize];
+ size_t len = PrintLocalTimeS(localTimeS.GetInstant(), buffer, buffer + sizeof(buffer));
+ out.Write(buffer, len);
+ return out;
+ }
+
+ TLocalTimeS::operator TString() const {
+ TString res;
+ res.reserve(LocalTimeSBufferSize);
+ res.ReserveAndResize(PrintLocalTimeS(Instant, res.begin(), res.begin() + res.capacity()));
+ return res;
+ }
+
+ TString TLocalTimeS::operator+(const TStringBuf right) const {
+ TString res(*this);
+ res += right;
+ return res;
+ }
+
+ TStringBuf StripFileName(TStringBuf string) {
+ return string.RNextTok(LOCSLASH_C);
+ }
+
+ TString GetSystemResources() {
+ NMemInfo::TMemInfo mi = NMemInfo::GetMemInfo();
+ return PrintSystemResources(mi);
+ }
+
+ TString PrintSystemResources(const NMemInfo::TMemInfo& mi) {
+ return Sprintf(" rss=%0.3fMb, vms=%0.3fMb", mi.RSS * 1.0 / (1024 * 1024), mi.VMS * 1.0 / (1024 * 1024));
+ }
+}
+
+namespace {
+ class TRtyLoggerFormatter : public ILoggerFormatter {
+ public:
+ void Format(const TLogRecordContext& context, TLogElement& elem) const override {
+ elem << context.CustomMessage << ": " << NLoggingImpl::GetLocalTimeS() << " "
+ << NLoggingImpl::StripFileName(context.SourceLocation.File) << ":" << context.SourceLocation.Line;
+ if (context.Priority > TLOG_RESOURCES && !ExitStarted()) {
+ elem << NLoggingImpl::GetSystemResources();
+ }
+ elem << " ";
+ }
+ };
+}
+
+ILoggerFormatter* CreateRtyLoggerFormatter() {
+ return new TRtyLoggerFormatter();
+}
+
+bool TRTYMessageFormater::CheckLoggingContext(TLog& /*logger*/, const TLogRecordContext& /*context*/) {
+ return true;
+}
+
+TSimpleSharedPtr<TLogElement> TRTYMessageFormater::StartRecord(TLog& logger, const TLogRecordContext& context, TSimpleSharedPtr<TLogElement> earlier) {
+ if (!earlier) {
+ earlier.Reset(new TLogElement(&logger));
+ }
+
+ TLoggerFormatterOperator::Get()->Format(context, *earlier);
+ return earlier;
+}
diff --git a/library/cpp/logger/global/rty_formater.h b/library/cpp/logger/global/rty_formater.h
new file mode 100644
index 0000000000..6532e1d769
--- /dev/null
+++ b/library/cpp/logger/global/rty_formater.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#include "common.h"
+
+namespace NMemInfo {
+ struct TMemInfo;
+}
+
+class ILoggerFormatter {
+public:
+ virtual ~ILoggerFormatter() = default;
+
+ virtual void Format(const TLogRecordContext&, TLogElement&) const = 0;
+};
+
+ILoggerFormatter* CreateRtyLoggerFormatter();
+
+namespace NLoggingImpl {
+ class TLocalTimeS {
+ public:
+ TLocalTimeS(TInstant instant = TInstant::Now())
+ : Instant(instant)
+ {
+ }
+
+ TInstant GetInstant() const {
+ return Instant;
+ }
+
+ operator TString() const;
+ TString operator+(TStringBuf right) const;
+
+ private:
+ TInstant Instant;
+ };
+
+ IOutputStream& operator<<(IOutputStream& out, TLocalTimeS localTimeS);
+
+ inline TLocalTimeS GetLocalTimeS() {
+ return TLocalTimeS();
+ }
+
+ TString GetSystemResources();
+ TString PrintSystemResources(const NMemInfo::TMemInfo& info);
+
+ struct TLoggerFormatterTraits {
+ static ILoggerFormatter* CreateDefault() {
+ return CreateRtyLoggerFormatter();
+ }
+ };
+}
+
+class TLoggerFormatterOperator : public NLoggingImpl::TOperatorBase<ILoggerFormatter, NLoggingImpl::TLoggerFormatterTraits> {
+};
+
+struct TRTYMessageFormater {
+ static bool CheckLoggingContext(TLog& logger, const TLogRecordContext& context);
+ static TSimpleSharedPtr<TLogElement> StartRecord(TLog& logger, const TLogRecordContext& context, TSimpleSharedPtr<TLogElement> earlier);
+};
+
+using TRTYLogPreprocessor = TLogRecordPreprocessor<TLogFilter, TRTYMessageFormater>;
diff --git a/library/cpp/logger/global/rty_formater_ut.cpp b/library/cpp/logger/global/rty_formater_ut.cpp
new file mode 100644
index 0000000000..551a97c5bf
--- /dev/null
+++ b/library/cpp/logger/global/rty_formater_ut.cpp
@@ -0,0 +1,31 @@
+#include "rty_formater.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+namespace {
+ const TStringBuf SampleISO8601("2017-07-25T19:26:09.894000+03:00");
+ const TStringBuf SampleRtyLog("2017-07-25 19:26:09.894 +0300");
+}
+
+Y_UNIT_TEST_SUITE(NLoggingImplTest) {
+ Y_UNIT_TEST(TestTLocalTimeSToStream) {
+ NLoggingImpl::TLocalTimeS lt(TInstant::ParseIso8601Deprecated(SampleISO8601));
+ TStringStream ss;
+ ss << lt;
+ UNIT_ASSERT_EQUAL(ss.Str(), SampleRtyLog);
+ }
+ Y_UNIT_TEST(TestTLocalTimeSToString) {
+ NLoggingImpl::TLocalTimeS lt(TInstant::ParseIso8601Deprecated(SampleISO8601));
+ UNIT_ASSERT_EQUAL(TString(lt), SampleRtyLog);
+ }
+ Y_UNIT_TEST(TestTLocalTimeSAddLeft) {
+ NLoggingImpl::TLocalTimeS lt(TInstant::ParseIso8601Deprecated(SampleISO8601));
+ TStringBuf suffix("suffix");
+ UNIT_ASSERT_EQUAL(lt + suffix, TString(SampleRtyLog) + suffix);
+ }
+ Y_UNIT_TEST(TestTLocalTimeSAddRight) {
+ NLoggingImpl::TLocalTimeS lt(TInstant::ParseIso8601Deprecated(SampleISO8601));
+ TString prefix("prefix");
+ UNIT_ASSERT_EQUAL(prefix + lt, prefix + SampleRtyLog);
+ }
+}
diff --git a/library/cpp/logger/global/ut/ya.make b/library/cpp/logger/global/ut/ya.make
new file mode 100644
index 0000000000..8aea38906f
--- /dev/null
+++ b/library/cpp/logger/global/ut/ya.make
@@ -0,0 +1,15 @@
+UNITTEST()
+
+OWNER(salmin)
+
+PEERDIR(
+ library/cpp/logger/global
+)
+
+SRCDIR(library/cpp/logger/global)
+
+SRCS(
+ rty_formater_ut.cpp
+)
+
+END()
diff --git a/library/cpp/logger/global/ya.make b/library/cpp/logger/global/ya.make
new file mode 100644
index 0000000000..20eb361e72
--- /dev/null
+++ b/library/cpp/logger/global/ya.make
@@ -0,0 +1,19 @@
+LIBRARY()
+
+OWNER(g:geosaas)
+
+PEERDIR(
+ library/cpp/logger
+)
+
+IF (OS_WINDOWS)
+ NO_WERROR()
+ENDIF()
+
+SRCS(
+ common.cpp
+ global.cpp
+ rty_formater.cpp
+)
+
+END()
diff --git a/library/cpp/logger/init_context/README.md b/library/cpp/logger/init_context/README.md
new file mode 100644
index 0000000000..93564e4890
--- /dev/null
+++ b/library/cpp/logger/init_context/README.md
@@ -0,0 +1,5 @@
+Эта библиотека содержит две раплизации InitContext для TLogBackendCreator.
+
+TLogBackendCreatorInitContextYConf работает с YandexConfig (library/cpp/yconf).
+
+TLogBackendCreatorInitContextConfig работает с NConfig::TConfig (library/cpp/config).
diff --git a/library/cpp/logger/init_context/config.cpp b/library/cpp/logger/init_context/config.cpp
new file mode 100644
index 0000000000..30efa13333
--- /dev/null
+++ b/library/cpp/logger/init_context/config.cpp
@@ -0,0 +1,26 @@
+#include "config.h"
+
+TLogBackendCreatorInitContextConfig::TLogBackendCreatorInitContextConfig(const NConfig::TConfig& config)
+ : Config(config)
+{}
+
+bool TLogBackendCreatorInitContextConfig::GetValue(TStringBuf name, TString& var) const {
+ if (Config.Has(name)) {
+ var = Config[name].Get<TString>();
+ return true;
+ }
+ return false;
+}
+
+TVector<THolder<ILogBackendCreator::IInitContext>> TLogBackendCreatorInitContextConfig::GetChildren(TStringBuf name) const {
+ TVector<THolder<IInitContext>> result;
+ const NConfig::TConfig& child = Config[name];
+ if (child.IsA<NConfig::TArray>()) {
+ for (const auto& i: child.Get<NConfig::TArray>()) {
+ result.emplace_back(MakeHolder<TLogBackendCreatorInitContextConfig>(i));
+ }
+ } else if (!child.IsNull()) {
+ result.emplace_back(MakeHolder<TLogBackendCreatorInitContextConfig>(child));
+ }
+ return result;
+}
diff --git a/library/cpp/logger/init_context/config.h b/library/cpp/logger/init_context/config.h
new file mode 100644
index 0000000000..8227d13176
--- /dev/null
+++ b/library/cpp/logger/init_context/config.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <library/cpp/logger/backend_creator.h>
+#include <library/cpp/config/config.h>
+
+class TLogBackendCreatorInitContextConfig : public ILogBackendCreator::IInitContext {
+public:
+ TLogBackendCreatorInitContextConfig(const NConfig::TConfig& config);
+ virtual bool GetValue(TStringBuf name, TString& var) const override;
+ virtual TVector<THolder<IInitContext>> GetChildren(TStringBuf name) const override;
+
+private:
+ const NConfig::TConfig& Config;
+};
diff --git a/library/cpp/logger/init_context/ya.make b/library/cpp/logger/init_context/ya.make
new file mode 100644
index 0000000000..9572a34c60
--- /dev/null
+++ b/library/cpp/logger/init_context/ya.make
@@ -0,0 +1,20 @@
+OWNER(
+ pg
+ mvel
+ g:util
+ g:base
+)
+
+LIBRARY()
+
+PEERDIR(
+ library/cpp/logger
+ library/cpp/config
+ library/cpp/yconf
+)
+SRCS(
+ config.cpp
+ yconf.cpp
+)
+
+END()
diff --git a/library/cpp/logger/init_context/yconf.cpp b/library/cpp/logger/init_context/yconf.cpp
new file mode 100644
index 0000000000..c7da1d607c
--- /dev/null
+++ b/library/cpp/logger/init_context/yconf.cpp
@@ -0,0 +1,18 @@
+#include "yconf.h"
+
+TLogBackendCreatorInitContextYConf::TLogBackendCreatorInitContextYConf(const TYandexConfig::Section& section)
+ : Section(section)
+{}
+
+bool TLogBackendCreatorInitContextYConf::GetValue(TStringBuf name, TString& var) const {
+ return Section.GetDirectives().GetValue(name, var);
+}
+
+TVector<THolder<ILogBackendCreator::IInitContext>> TLogBackendCreatorInitContextYConf::GetChildren(TStringBuf name) const {
+ TVector<THolder<IInitContext>> result;
+ auto children = Section.GetAllChildren();
+ for (auto range = children.equal_range(TCiString(name)); range.first != range.second; ++range.first) {
+ result.emplace_back(MakeHolder<TLogBackendCreatorInitContextYConf>(*range.first->second));
+ }
+ return result;
+}
diff --git a/library/cpp/logger/init_context/yconf.h b/library/cpp/logger/init_context/yconf.h
new file mode 100644
index 0000000000..b1867d271d
--- /dev/null
+++ b/library/cpp/logger/init_context/yconf.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <library/cpp/logger/backend_creator.h>
+#include <library/cpp/yconf/conf.h>
+
+class TLogBackendCreatorInitContextYConf: public ILogBackendCreator::IInitContext {
+public:
+ TLogBackendCreatorInitContextYConf(const TYandexConfig::Section& section);
+ virtual bool GetValue(TStringBuf name, TString& var) const override;
+ virtual TVector<THolder<IInitContext>> GetChildren(TStringBuf name) const override;
+private:
+ const TYandexConfig::Section& Section;
+};
diff --git a/library/cpp/logger/log.cpp b/library/cpp/logger/log.cpp
new file mode 100644
index 0000000000..e1d70cc3d2
--- /dev/null
+++ b/library/cpp/logger/log.cpp
@@ -0,0 +1,252 @@
+#include "log.h"
+#include "uninitialized_creator.h"
+#include "filter.h"
+#include "null.h"
+#include "stream.h"
+#include "thread.h"
+
+#include <util/string/cast.h>
+#include <util/stream/printf.h>
+#include <util/system/yassert.h>
+#include <util/generic/string.h>
+#include <util/generic/scope.h>
+#include <util/generic/yexception.h>
+
+THolder<TLogBackend> CreateLogBackend(const TString& fname, ELogPriority priority, bool threaded) {
+ TLogBackendCreatorUninitialized creator;
+ creator.InitCustom(fname, priority, threaded);
+ return creator.CreateLogBackend();
+}
+
+THolder<TLogBackend> CreateFilteredOwningThreadedLogBackend(const TString& fname, ELogPriority priority, size_t queueLen) {
+ return MakeHolder<TFilteredLogBackend>(CreateOwningThreadedLogBackend(fname, queueLen), priority);
+}
+
+THolder<TOwningThreadedLogBackend> CreateOwningThreadedLogBackend(const TString& fname, size_t queueLen) {
+ return MakeHolder<TOwningThreadedLogBackend>(CreateLogBackend(fname, LOG_MAX_PRIORITY, false).Release(), queueLen);
+}
+
+class TLog::TImpl: public TAtomicRefCount<TImpl> {
+ class TPriorityLogStream final: public IOutputStream {
+ public:
+ inline TPriorityLogStream(ELogPriority p, const TImpl* parent)
+ : Priority_(p)
+ , Parent_(parent)
+ {
+ }
+
+ void DoWrite(const void* buf, size_t len) override {
+ Parent_->WriteData(Priority_, (const char*)buf, len);
+ }
+
+ private:
+ ELogPriority Priority_ = LOG_DEF_PRIORITY;
+ const TImpl* Parent_ = nullptr;
+ };
+
+public:
+ inline TImpl(THolder<TLogBackend> backend)
+ : Backend_(std::move(backend))
+ {
+ }
+
+ inline void ReopenLog() {
+ if (!IsOpen()) {
+ return;
+ }
+
+ Backend_->ReopenLog();
+ }
+
+ inline void ReopenLogNoFlush() {
+ if (!IsOpen()) {
+ return;
+ }
+
+ Backend_->ReopenLogNoFlush();
+ }
+
+ inline void AddLog(ELogPriority priority, const char* format, va_list args) const {
+ if (!IsOpen()) {
+ return;
+ }
+
+ TPriorityLogStream ls(priority, this);
+
+ Printf(ls, format, args);
+ }
+
+ inline void ResetBackend(THolder<TLogBackend> backend) noexcept {
+ Backend_ = std::move(backend);
+ }
+
+ inline THolder<TLogBackend> ReleaseBackend() noexcept {
+ return std::move(Backend_);
+ }
+
+ inline bool IsNullLog() const noexcept {
+ return !IsOpen() || (dynamic_cast<TNullLogBackend*>(Backend_.Get()) != nullptr);
+ }
+
+ inline bool IsOpen() const noexcept {
+ return nullptr != Backend_.Get();
+ }
+
+ inline void CloseLog() noexcept {
+ Backend_.Destroy();
+
+ Y_ASSERT(!IsOpen());
+ }
+
+ inline void WriteData(ELogPriority priority, const char* data, size_t len) const {
+ if (IsOpen()) {
+ Backend_->WriteData(TLogRecord(priority, data, len));
+ }
+ }
+
+ inline ELogPriority DefaultPriority() noexcept {
+ return DefaultPriority_;
+ }
+
+ inline void SetDefaultPriority(ELogPriority priority) noexcept {
+ DefaultPriority_ = priority;
+ }
+
+ inline ELogPriority FiltrationLevel() const noexcept {
+ return Backend_->FiltrationLevel();
+ }
+
+ inline size_t BackEndQueueSize() const {
+ return Backend_->QueueSize();
+ }
+
+private:
+ THolder<TLogBackend> Backend_;
+ ELogPriority DefaultPriority_ = LOG_DEF_PRIORITY;
+};
+
+TLog::TLog()
+ : Impl_(MakeIntrusive<TImpl>(nullptr))
+{
+}
+
+TLog::TLog(const TString& fname, ELogPriority priority)
+ : TLog(CreateLogBackend(fname, priority, false))
+{
+}
+
+TLog::TLog(THolder<TLogBackend> backend)
+ : Impl_(MakeIntrusive<TImpl>(std::move(backend)))
+{
+}
+
+TLog::TLog(const TLog&) = default;
+TLog::TLog(TLog&&) = default;
+TLog::~TLog() = default;
+TLog& TLog::operator=(const TLog&) = default;
+TLog& TLog::operator=(TLog&&) = default;
+
+bool TLog::IsOpen() const noexcept {
+ return Impl_->IsOpen();
+}
+
+void TLog::AddLog(const char* format, ...) const {
+ va_list args;
+ va_start(args, format);
+
+ Y_DEFER {
+ va_end(args);
+ };
+
+ Impl_->AddLog(Impl_->DefaultPriority(), format, args);
+}
+
+void TLog::AddLog(ELogPriority priority, const char* format, ...) const {
+ va_list args;
+ va_start(args, format);
+
+ Y_DEFER {
+ va_end(args);
+ };
+
+ Impl_->AddLog(priority, format, args);
+}
+
+void TLog::AddLogVAList(const char* format, va_list lst) {
+ Impl_->AddLog(Impl_->DefaultPriority(), format, lst);
+}
+
+void TLog::ReopenLog() {
+ if (const auto copy = Impl_) {
+ copy->ReopenLog();
+ }
+}
+
+void TLog::ReopenLogNoFlush() {
+ if (const auto copy = Impl_) {
+ copy->ReopenLogNoFlush();
+ }
+}
+
+void TLog::CloseLog() {
+ Impl_->CloseLog();
+}
+
+void TLog::SetDefaultPriority(ELogPriority priority) noexcept {
+ Impl_->SetDefaultPriority(priority);
+}
+
+ELogPriority TLog::FiltrationLevel() const noexcept {
+ return Impl_->FiltrationLevel();
+}
+
+ELogPriority TLog::DefaultPriority() const noexcept {
+ return Impl_->DefaultPriority();
+}
+
+bool TLog::OpenLog(const char* path, ELogPriority lp) {
+ if (path) {
+ ResetBackend(CreateLogBackend(path, lp));
+ } else {
+ ResetBackend(MakeHolder<TStreamLogBackend>(&Cerr));
+ }
+
+ return true;
+}
+
+void TLog::ResetBackend(THolder<TLogBackend> backend) noexcept {
+ Impl_->ResetBackend(std::move(backend));
+}
+
+bool TLog::IsNullLog() const noexcept {
+ return Impl_->IsNullLog();
+}
+
+THolder<TLogBackend> TLog::ReleaseBackend() noexcept {
+ return Impl_->ReleaseBackend();
+}
+
+void TLog::Write(ELogPriority priority, const char* data, size_t len) const {
+ if (Formatter_) {
+ const auto formated = Formatter_(priority, TStringBuf{data, len});
+ Impl_->WriteData(priority, formated.data(), formated.size());
+ } else {
+ Impl_->WriteData(priority, data, len);
+ }
+}
+
+void TLog::Write(ELogPriority priority, const TStringBuf data) const {
+ Write(priority, data.data(), data.size());
+}
+
+void TLog::Write(const char* data, size_t len) const {
+ Write(Impl_->DefaultPriority(), data, len);
+}
+
+void TLog::SetFormatter(TLogFormatter formatter) noexcept {
+ Formatter_ = std::move(formatter);
+}
+
+size_t TLog::BackEndQueueSize() const {
+ return Impl_->BackEndQueueSize();
+}
diff --git a/library/cpp/logger/log.h b/library/cpp/logger/log.h
new file mode 100644
index 0000000000..8be984ccc8
--- /dev/null
+++ b/library/cpp/logger/log.h
@@ -0,0 +1,115 @@
+#pragma once
+
+#include "backend.h"
+#include "element.h"
+#include "priority.h"
+#include "record.h"
+#include "thread.h"
+
+#include <util/generic/fwd.h>
+#include <util/generic/ptr.h>
+
+#include <functional>
+#include <cstdarg>
+
+using TLogFormatter = std::function<TString(ELogPriority priority, TStringBuf)>;
+
+// Logging facilities interface.
+//
+// ```cpp
+// TLog base;
+// ...
+// auto log = base;
+// log.SetFormatter([reqId](ELogPriority p, TStringBuf msg) {
+// return TStringBuilder() << "reqid=" << reqId << "; " << msg;
+// });
+//
+// log.Write(TLOG_INFO, "begin");
+// HandleRequest(...);
+// log.Write(TLOG_INFO, "end");
+// ```
+//
+// Users are encouraged to copy `TLog` instance.
+class TLog {
+public:
+ // Construct empty logger all writes will be spilled.
+ TLog();
+ // Construct file logger.
+ TLog(const TString& fname, ELogPriority priority = LOG_MAX_PRIORITY);
+ // Construct any type of logger
+ TLog(THolder<TLogBackend> backend);
+
+ TLog(const TLog&);
+ TLog(TLog&&);
+ ~TLog();
+ TLog& operator=(const TLog&);
+ TLog& operator=(TLog&&);
+
+ // Change underlying backend.
+ // NOTE: not thread safe.
+ void ResetBackend(THolder<TLogBackend> backend) noexcept;
+ // Reset underlying backend, `IsNullLog()` will return `true` after this call.
+ // NOTE: not thread safe.
+ THolder<TLogBackend> ReleaseBackend() noexcept;
+ // Check if underlying backend is defined and is not null.
+ // NOTE: not thread safe with respect to `ResetBackend` and `ReleaseBackend`.
+ bool IsNullLog() const noexcept;
+
+ // Write message to the log.
+ //
+ // @param[in] priority Message priority to use.
+ // @param[in] message Message to write.
+ void Write(ELogPriority priority, TStringBuf message) const;
+ // Write message to the log using `DefaultPriority()`.
+ void Write(const char* data, size_t len) const;
+ // Write message to the log, but pass the message in a c-style.
+ void Write(ELogPriority priority, const char* data, size_t len) const;
+
+ // Write message to the log in a c-like printf style.
+ void Y_PRINTF_FORMAT(3, 4) AddLog(ELogPriority priority, const char* format, ...) const;
+ // Write message to the log in a c-like printf style with `DefaultPriority()` priority.
+ void Y_PRINTF_FORMAT(2, 3) AddLog(const char* format, ...) const;
+
+ // Call `ReopenLog()` of the underlying backend.
+ void ReopenLog();
+ // Call `ReopenLogNoFlush()` of the underlying backend.
+ void ReopenLogNoFlush();
+ // Call `QueueSize()` of the underlying backend.
+ size_t BackEndQueueSize() const;
+
+ // Set log default priority.
+ // NOTE: not thread safe.
+ void SetDefaultPriority(ELogPriority priority) noexcept;
+ // Get default priority
+ ELogPriority DefaultPriority() const noexcept;
+
+ // Call `FiltrationLevel()` of the underlying backend.
+ ELogPriority FiltrationLevel() const noexcept;
+
+ // Set current log formatter.
+ void SetFormatter(TLogFormatter formatter) noexcept;
+
+ template <class T>
+ inline TLogElement operator<<(const T& t) const {
+ TLogElement ret(this);
+ ret << t;
+ return ret;
+ }
+
+public:
+ // These methods are deprecated and present here only for compatibility reasons (for 13 years
+ // already ...). Do not use them.
+ bool OpenLog(const char* path, ELogPriority lp = LOG_MAX_PRIORITY);
+ bool IsOpen() const noexcept;
+ void AddLogVAList(const char* format, va_list lst);
+ void CloseLog();
+
+private:
+ class TImpl;
+ TIntrusivePtr<TImpl> Impl_;
+ TLogFormatter Formatter_;
+};
+
+THolder<TLogBackend> CreateLogBackend(const TString& fname, ELogPriority priority = LOG_MAX_PRIORITY, bool threaded = false);
+THolder<TLogBackend> CreateFilteredOwningThreadedLogBackend(const TString& fname, ELogPriority priority = LOG_MAX_PRIORITY, size_t queueLen = 0);
+THolder<TOwningThreadedLogBackend> CreateOwningThreadedLogBackend(const TString& fname, size_t queueLen = 0);
diff --git a/library/cpp/logger/log_ut.cpp b/library/cpp/logger/log_ut.cpp
new file mode 100644
index 0000000000..8de46f17f5
--- /dev/null
+++ b/library/cpp/logger/log_ut.cpp
@@ -0,0 +1,191 @@
+#include "all.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/system/fs.h>
+#include <util/system/rwlock.h>
+#include <util/system/yield.h>
+#include <util/memory/blob.h>
+#include <util/stream/file.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+
+class TLogTest: public TTestBase {
+ UNIT_TEST_SUITE(TLogTest);
+ UNIT_TEST(TestFile)
+ UNIT_TEST(TestFormat)
+ UNIT_TEST(TestWrite)
+ UNIT_TEST(TestThreaded)
+ UNIT_TEST(TestThreadedWithOverflow)
+ UNIT_TEST(TestNoFlush)
+ UNIT_TEST_SUITE_END();
+
+private:
+ void TestFile();
+ void TestFormat();
+ void TestWrite();
+ void TestThreaded();
+ void TestThreadedWithOverflow();
+ void TestNoFlush();
+ void SetUp() override;
+ void TearDown() override;
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TLogTest);
+
+#define LOGFILE "tmplogfile"
+
+void TLogTest::TestFile() {
+ {
+ TLog log;
+
+ {
+ TLog filelog(LOGFILE);
+
+ log = filelog;
+ }
+
+ int v1 = 12;
+ unsigned v2 = 34;
+ double v3 = 3.0;
+ const char* v4 = "qwqwqw";
+
+ log.ReopenLog();
+ log.AddLog("some useful data %d, %u, %lf, %s\n", v1, v2, v3, v4);
+ }
+
+ TBlob data = TBlob::FromFileSingleThreaded(LOGFILE);
+
+ UNIT_ASSERT_EQUAL(TString((const char*)data.Begin(), data.Size()), "some useful data 12, 34, 3.000000, qwqwqw\n");
+}
+
+void TLogTest::TestThreaded() {
+ {
+ TFileLogBackend fb(LOGFILE);
+ TLog log(THolder(new TThreadedLogBackend(&fb)));
+
+ int v1 = 12;
+ unsigned v2 = 34;
+ double v3 = 3.0;
+ const char* v4 = "qwqwqw";
+
+ log.ReopenLog();
+ log.AddLog("some useful data %d, %u, %lf, %s\n", v1, v2, v3, v4);
+ }
+
+ TBlob data = TBlob::FromFileSingleThreaded(LOGFILE);
+
+ UNIT_ASSERT_EQUAL(TString((const char*)data.Begin(), data.Size()), "some useful data 12, 34, 3.000000, qwqwqw\n");
+}
+
+void TLogTest::TestThreadedWithOverflow() {
+ class TFakeLogBackend: public TLogBackend {
+ public:
+ TWriteGuard Guard() {
+ return TWriteGuard(Lock_);
+ }
+
+ void WriteData(const TLogRecord&) override {
+ TReadGuard guard(Lock_);
+ }
+
+ void ReopenLog() override {
+ TWriteGuard guard(Lock_);
+ }
+
+ private:
+ TRWMutex Lock_;
+ };
+
+ auto waitForFreeQueue = [](const TLog& log) {
+ ThreadYield();
+ while (log.BackEndQueueSize() > 0) {
+ Sleep(TDuration::MilliSeconds(1));
+ }
+ };
+
+ TFakeLogBackend fb;
+ {
+ TLog log(THolder(new TThreadedLogBackend(&fb, 2)));
+
+ auto guard = fb.Guard();
+ log.AddLog("first write");
+ waitForFreeQueue(log);
+ log.AddLog("second write (first in queue)");
+ log.AddLog("third write (second in queue)");
+ UNIT_ASSERT_EXCEPTION(log.AddLog("fourth write (queue overflow)"), yexception);
+ }
+
+ {
+ ui32 overflows = 0;
+ TLog log(THolder(new TThreadedLogBackend(&fb, 2, [&overflows] { ++overflows; })));
+
+ auto guard = fb.Guard();
+ log.AddLog("first write");
+ waitForFreeQueue(log);
+ log.AddLog("second write (first in queue)");
+ log.AddLog("third write (second in queue)");
+ UNIT_ASSERT_EQUAL(overflows, 0);
+ log.AddLog("fourth write (queue overflow)");
+ UNIT_ASSERT_EQUAL(overflows, 1);
+ }
+}
+
+void TLogTest::TestNoFlush() {
+ {
+ TFileLogBackend fb(LOGFILE);
+ TLog log(THolder(new TThreadedLogBackend(&fb)));
+
+ int v1 = 12;
+ unsigned v2 = 34;
+ double v3 = 3.0;
+ const char* v4 = "qwqwqw";
+
+ log.ReopenLogNoFlush();
+ log.AddLog("some useful data %d, %u, %lf, %s\n", v1, v2, v3, v4);
+ }
+
+ TBlob data = TBlob::FromFileSingleThreaded(LOGFILE);
+
+ UNIT_ASSERT_EQUAL(TString((const char*)data.Begin(), data.Size()), "some useful data 12, 34, 3.000000, qwqwqw\n");
+}
+
+void TLogTest::TestFormat() {
+ TStringStream data;
+
+ {
+ TLog log(THolder(new TStreamLogBackend(&data)));
+
+ log << "qw"
+ << " "
+ << "1234" << 1234 << " " << 12.3 << 'q' << Endl;
+ }
+
+ UNIT_ASSERT_EQUAL(data.Str(), "qw 12341234 12.3q\n");
+}
+
+void TLogTest::TestWrite() {
+ TStringStream data;
+ TString test;
+
+ {
+ TLog log(THolder(new TStreamLogBackend(&data)));
+
+ for (size_t i = 0; i < 1000; ++i) {
+ TVector<char> buf(i, (char)i);
+
+ test.append(buf.data(), buf.size());
+ log.Write(buf.data(), buf.size());
+ }
+ }
+
+ UNIT_ASSERT_EQUAL(data.Str(), test);
+}
+
+void TLogTest::SetUp() {
+ TearDown();
+}
+
+void TLogTest::TearDown() {
+ NFs::Remove(LOGFILE);
+}
diff --git a/library/cpp/logger/null.cpp b/library/cpp/logger/null.cpp
new file mode 100644
index 0000000000..debb22f794
--- /dev/null
+++ b/library/cpp/logger/null.cpp
@@ -0,0 +1,13 @@
+#include "null.h"
+
+TNullLogBackend::TNullLogBackend() {
+}
+
+TNullLogBackend::~TNullLogBackend() {
+}
+
+void TNullLogBackend::WriteData(const TLogRecord&) {
+}
+
+void TNullLogBackend::ReopenLog() {
+}
diff --git a/library/cpp/logger/null.h b/library/cpp/logger/null.h
new file mode 100644
index 0000000000..a02f250b00
--- /dev/null
+++ b/library/cpp/logger/null.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "backend.h"
+
+class TNullLogBackend: public TLogBackend {
+public:
+ TNullLogBackend();
+ ~TNullLogBackend() override;
+
+ void WriteData(const TLogRecord& rec) override;
+ void ReopenLog() override;
+};
diff --git a/library/cpp/logger/null_creator.cpp b/library/cpp/logger/null_creator.cpp
new file mode 100644
index 0000000000..9f63d5c739
--- /dev/null
+++ b/library/cpp/logger/null_creator.cpp
@@ -0,0 +1,17 @@
+#include "null_creator.h"
+#include "null.h"
+
+THolder<TLogBackend> TNullLogBackendCreator::DoCreateLogBackend() const {
+ return MakeHolder<TNullLogBackend>();
+}
+
+ILogBackendCreator::TFactory::TRegistrator<TNullLogBackendCreator> TNullLogBackendCreator::RegistrarDevNull("/dev/null");
+ILogBackendCreator::TFactory::TRegistrator<TNullLogBackendCreator> TNullLogBackendCreator::RegistrarNull("null");
+
+
+void TNullLogBackendCreator::DoToJson(NJson::TJsonValue& /*value*/) const {
+}
+
+TNullLogBackendCreator::TNullLogBackendCreator()
+ : TLogBackendCreatorBase("null")
+{}
diff --git a/library/cpp/logger/null_creator.h b/library/cpp/logger/null_creator.h
new file mode 100644
index 0000000000..a5bcab63f9
--- /dev/null
+++ b/library/cpp/logger/null_creator.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "backend_creator.h"
+
+class TNullLogBackendCreator : public TLogBackendCreatorBase {
+public:
+ TNullLogBackendCreator();
+ static TFactory::TRegistrator<TNullLogBackendCreator> RegistrarNull;
+ static TFactory::TRegistrator<TNullLogBackendCreator> RegistrarDevNull;
+protected:
+ virtual void DoToJson(NJson::TJsonValue& value) const override;
+
+private:
+ virtual THolder<TLogBackend> DoCreateLogBackend() const override;
+};
diff --git a/library/cpp/logger/priority.h b/library/cpp/logger/priority.h
new file mode 100644
index 0000000000..d2a9fa0a07
--- /dev/null
+++ b/library/cpp/logger/priority.h
@@ -0,0 +1,15 @@
+#pragma once
+
+enum ELogPriority {
+ TLOG_EMERG = 0 /* "EMERG" */,
+ TLOG_ALERT = 1 /* "ALERT" */,
+ TLOG_CRIT = 2 /* "CRITICAL_INFO" */,
+ TLOG_ERR = 3 /* "ERROR" */,
+ TLOG_WARNING = 4 /* "WARNING" */,
+ TLOG_NOTICE = 5 /* "NOTICE" */,
+ TLOG_INFO = 6 /* "INFO" */,
+ TLOG_DEBUG = 7 /* "DEBUG" */,
+ TLOG_RESOURCES = 8 /* "RESOURCES" */
+};
+#define LOG_MAX_PRIORITY TLOG_RESOURCES
+#define LOG_DEF_PRIORITY TLOG_INFO
diff --git a/library/cpp/logger/record.h b/library/cpp/logger/record.h
new file mode 100644
index 0000000000..c28a7785fd
--- /dev/null
+++ b/library/cpp/logger/record.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "priority.h"
+
+#include <util/system/defaults.h>
+
+struct TLogRecord {
+ const char* Data;
+ size_t Len;
+ ELogPriority Priority;
+
+ inline TLogRecord(ELogPriority priority, const char* data, size_t len) noexcept
+ : Data(data)
+ , Len(len)
+ , Priority(priority)
+ {
+ }
+};
diff --git a/library/cpp/logger/rotating_file.cpp b/library/cpp/logger/rotating_file.cpp
new file mode 100644
index 0000000000..a62f48f25d
--- /dev/null
+++ b/library/cpp/logger/rotating_file.cpp
@@ -0,0 +1,86 @@
+#include "rotating_file.h"
+#include "file.h"
+#include "record.h"
+
+#include <util/string/builder.h>
+#include <util/system/fstat.h>
+#include <util/system/rwlock.h>
+#include <util/system/fs.h>
+#include <util/system/atomic.h>
+#include <util/generic/string.h>
+
+/*
+ * rotating file log
+ * if Size_ > MaxSizeBytes
+ * Path.(N-1) -> Path.N
+ * Path.(N-2) -> Path.(N-1)
+ * ...
+ * Path.1 -> Path.2
+ * Path -> Path.1
+ */
+class TRotatingFileLogBackend::TImpl {
+public:
+ inline TImpl(const TString& path, const ui64 maxSizeBytes, const ui32 rotatedFilesCount)
+ : Log_(path)
+ , Path_(path)
+ , MaxSizeBytes_(maxSizeBytes)
+ , Size_(TFileStat(Path_).Size)
+ , RotatedFilesCount_(rotatedFilesCount)
+ {
+ Y_ENSURE(RotatedFilesCount_ != 0);
+ }
+
+ inline void WriteData(const TLogRecord& rec) {
+ if (static_cast<ui64>(AtomicGet(Size_)) > MaxSizeBytes_) {
+ TWriteGuard guard(Lock_);
+ if (static_cast<ui64>(AtomicGet(Size_)) > MaxSizeBytes_) {
+ TString newLogPath(TStringBuilder{} << Path_ << "." << RotatedFilesCount_);
+ for (size_t fileId = RotatedFilesCount_ - 1; fileId; --fileId) {
+ TString oldLogPath(TStringBuilder{} << Path_ << "." << fileId);
+ NFs::Rename(oldLogPath, newLogPath);
+ newLogPath = oldLogPath;
+ }
+ NFs::Rename(Path_, newLogPath);
+ Log_.ReopenLog();
+ AtomicSet(Size_, 0);
+ }
+ }
+ TReadGuard guard(Lock_);
+ Log_.WriteData(rec);
+ AtomicAdd(Size_, rec.Len);
+ }
+
+ inline void ReopenLog() {
+ TWriteGuard guard(Lock_);
+
+ Log_.ReopenLog();
+ AtomicSet(Size_, TFileStat(Path_).Size);
+ }
+
+private:
+ TRWMutex Lock_;
+ TFileLogBackend Log_;
+ const TString Path_;
+ const ui64 MaxSizeBytes_;
+ TAtomic Size_;
+ const ui32 RotatedFilesCount_;
+};
+
+TRotatingFileLogBackend::TRotatingFileLogBackend(const TString& path, const ui64 maxSizeByte, const ui32 rotatedFilesCount)
+ : Impl_(new TImpl(path, maxSizeByte, rotatedFilesCount))
+{
+}
+
+TRotatingFileLogBackend::~TRotatingFileLogBackend() {
+}
+
+void TRotatingFileLogBackend::WriteData(const TLogRecord& rec) {
+ Impl_->WriteData(rec);
+}
+
+void TRotatingFileLogBackend::ReopenLog() {
+ TAtomicSharedPtr<TImpl> copy = Impl_;
+ if (copy) {
+ copy->ReopenLog();
+ }
+}
diff --git a/library/cpp/logger/rotating_file.h b/library/cpp/logger/rotating_file.h
new file mode 100644
index 0000000000..cb047f25fb
--- /dev/null
+++ b/library/cpp/logger/rotating_file.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "backend.h"
+
+#include <util/generic/fwd.h>
+#include <util/generic/ptr.h>
+
+class TRotatingFileLogBackend: public TLogBackend {
+public:
+ TRotatingFileLogBackend(const TString& preRotatePath, const TString& postRotatePath, const ui64 maxSizeBytes);
+ TRotatingFileLogBackend(const TString& path, const ui64 maxSizeBytes, const ui32 rotatedFilesCount);
+ ~TRotatingFileLogBackend() override;
+
+ void WriteData(const TLogRecord& rec) override;
+ void ReopenLog() override;
+
+private:
+ class TImpl;
+ TAtomicSharedPtr<TImpl> Impl_;
+};
diff --git a/library/cpp/logger/rotating_file_creator.cpp b/library/cpp/logger/rotating_file_creator.cpp
new file mode 100644
index 0000000000..6f71b68573
--- /dev/null
+++ b/library/cpp/logger/rotating_file_creator.cpp
@@ -0,0 +1,28 @@
+#include "rotating_file_creator.h"
+#include "rotating_file.h"
+
+THolder<TLogBackend> TRotatingFileLogBackendCreator::DoCreateLogBackend() const {
+ return MakeHolder<TRotatingFileLogBackend>(Path, MaxSizeBytes, RotatedFilesCount);
+}
+
+
+TRotatingFileLogBackendCreator::TRotatingFileLogBackendCreator()
+ : TFileLogBackendCreator("", "rotating")
+{}
+
+bool TRotatingFileLogBackendCreator::Init(const IInitContext& ctx) {
+ if (!TFileLogBackendCreator::Init(ctx)) {
+ return false;
+ }
+ ctx.GetValue("MaxSizeBytes", MaxSizeBytes);
+ ctx.GetValue("RotatedFilesCount", RotatedFilesCount);
+ return true;
+}
+
+ILogBackendCreator::TFactory::TRegistrator<TRotatingFileLogBackendCreator> TRotatingFileLogBackendCreator::Registrar("rotating");
+
+void TRotatingFileLogBackendCreator::DoToJson(NJson::TJsonValue& value) const {
+ TFileLogBackendCreator::DoToJson(value);
+ value["MaxSizeBytes"] = MaxSizeBytes;
+ value["RotatedFilesCount"] = RotatedFilesCount;
+}
diff --git a/library/cpp/logger/rotating_file_creator.h b/library/cpp/logger/rotating_file_creator.h
new file mode 100644
index 0000000000..b2e94584da
--- /dev/null
+++ b/library/cpp/logger/rotating_file_creator.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "file_creator.h"
+
+class TRotatingFileLogBackendCreator : public TFileLogBackendCreator {
+public:
+ TRotatingFileLogBackendCreator();
+ virtual bool Init(const IInitContext& ctx) override;
+ static TFactory::TRegistrator<TRotatingFileLogBackendCreator> Registrar;
+
+protected:
+ virtual void DoToJson(NJson::TJsonValue& value) const override;
+
+private:
+ virtual THolder<TLogBackend> DoCreateLogBackend() const override;
+ ui64 MaxSizeBytes = Max<ui64>();
+ ui64 RotatedFilesCount = Max<ui64>();
+};
diff --git a/library/cpp/logger/rotating_file_ut.cpp b/library/cpp/logger/rotating_file_ut.cpp
new file mode 100644
index 0000000000..84966933d9
--- /dev/null
+++ b/library/cpp/logger/rotating_file_ut.cpp
@@ -0,0 +1,57 @@
+#include "rotating_file.h"
+#include "record.h"
+
+#include <util/generic/string.h>
+#include <util/system/fstat.h>
+#include <util/system/fs.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/testing/unittest/tests_data.h>
+
+Y_UNIT_TEST_SUITE(NewRotatingFileSuite) {
+ const TString PATH = GetWorkPath() + "/my.log";
+
+ Y_UNIT_TEST(TestFileWrite) {
+ TRotatingFileLogBackend log(PATH, 4000, 2);
+ TString data = "my data";
+ log.WriteData(TLogRecord(ELogPriority::TLOG_INFO, data.data(), data.size()));
+ UNIT_ASSERT_C(TFileStat(PATH).Size > 0, "file " << PATH << " has zero size");
+ }
+
+ Y_UNIT_TEST(TestFileRotate) {
+ const ui64 maxSize = 40;
+ TRotatingFileLogBackend log(PATH, maxSize, 2);
+ TStringBuilder data;
+ for (size_t i = 0; i < 10; ++i)
+ data << "data\n";
+ log.WriteData(TLogRecord(ELogPriority::TLOG_INFO, data.data(), data.size()));
+ UNIT_ASSERT_C(TFileStat(PATH).Size > 0, "file " << PATH << " has zero size");
+ data.clear();
+ data << "more data";
+ log.WriteData(TLogRecord(ELogPriority::TLOG_INFO, data.data(), data.size()));
+ UNIT_ASSERT_C(TFileStat(PATH).Size > 0, "file " << PATH << " has zero size");
+ UNIT_ASSERT_C(TFileStat(TStringBuilder{} << PATH << ".1").Size > 0, "file " << PATH << ".1 has zero size");
+ UNIT_ASSERT_C(TFileStat(PATH).Size < maxSize, "size of file " << PATH << " is greater than the size limit of " << maxSize << " bytes");
+ }
+
+ Y_UNIT_TEST(TestDoubleFileRotate) {
+ const ui64 maxSize = 40;
+ TRotatingFileLogBackend log(PATH, maxSize, 2);
+ TStringBuilder data;
+ for (size_t i = 0; i < 10; ++i)
+ data << "data\n";
+ log.WriteData(TLogRecord(ELogPriority::TLOG_INFO, data.data(), data.size()));
+ UNIT_ASSERT_C(TFileStat(PATH).Size > 0, "file " << PATH << " has zero size");
+ log.WriteData(TLogRecord(ELogPriority::TLOG_INFO, data.data(), data.size()));
+ UNIT_ASSERT_C(TFileStat(PATH).Size > 0, "file " << PATH << " has zero size");
+ UNIT_ASSERT_C(TFileStat(TStringBuilder{} << PATH << ".1").Size > 0, "file " << PATH << ".1 has zero size");
+ UNIT_ASSERT_C(TFileStat(PATH).Size > maxSize, "size of file " << PATH << " is lesser than was written");
+ data.clear();
+ data << "more data";
+ log.WriteData(TLogRecord(ELogPriority::TLOG_INFO, data.data(), data.size()));
+ UNIT_ASSERT_C(TFileStat(PATH).Size > 0, "file " << PATH << " has zero size");
+ UNIT_ASSERT_C(TFileStat(TStringBuilder{} << PATH << ".1").Size > 0, "file " << PATH << ".1 has zero size");
+ UNIT_ASSERT_C(TFileStat(TStringBuilder{} << PATH << ".2").Size > 0, "file " << PATH << ".2 has zero size");
+ UNIT_ASSERT_C(TFileStat(PATH).Size < maxSize, "size of file " << PATH << " is greater than the size limit of " << maxSize << " bytes");
+ }
+}
diff --git a/library/cpp/logger/stream.cpp b/library/cpp/logger/stream.cpp
new file mode 100644
index 0000000000..96787ad94b
--- /dev/null
+++ b/library/cpp/logger/stream.cpp
@@ -0,0 +1,19 @@
+#include "stream.h"
+#include "record.h"
+
+#include <util/stream/output.h>
+
+TStreamLogBackend::TStreamLogBackend(IOutputStream* slave)
+ : Slave_(slave)
+{
+}
+
+TStreamLogBackend::~TStreamLogBackend() {
+}
+
+void TStreamLogBackend::WriteData(const TLogRecord& rec) {
+ Slave_->Write(rec.Data, rec.Len);
+}
+
+void TStreamLogBackend::ReopenLog() {
+}
diff --git a/library/cpp/logger/stream.h b/library/cpp/logger/stream.h
new file mode 100644
index 0000000000..feb240afcb
--- /dev/null
+++ b/library/cpp/logger/stream.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "backend.h"
+
+class IOutputStream;
+
+class TStreamLogBackend: public TLogBackend {
+public:
+ TStreamLogBackend(IOutputStream* slave);
+ ~TStreamLogBackend() override;
+
+ void WriteData(const TLogRecord& rec) override;
+ void ReopenLog() override;
+
+private:
+ IOutputStream* Slave_;
+};
diff --git a/library/cpp/logger/stream_creator.cpp b/library/cpp/logger/stream_creator.cpp
new file mode 100644
index 0000000000..6246f9bf9c
--- /dev/null
+++ b/library/cpp/logger/stream_creator.cpp
@@ -0,0 +1,32 @@
+#include "stream_creator.h"
+#include "stream.h"
+
+THolder<TLogBackend> TCerrLogBackendCreator::DoCreateLogBackend() const {
+ return MakeHolder<TStreamLogBackend>(&Cerr);
+}
+
+
+TCerrLogBackendCreator::TCerrLogBackendCreator()
+ : TLogBackendCreatorBase("cerr")
+{}
+
+void TCerrLogBackendCreator::DoToJson(NJson::TJsonValue& /*value*/) const {
+}
+
+ILogBackendCreator::TFactory::TRegistrator<TCerrLogBackendCreator> TCerrLogBackendCreator::RegistrarCerr("cerr");
+ILogBackendCreator::TFactory::TRegistrator<TCerrLogBackendCreator> TCerrLogBackendCreator::RegistrarConsole("console");
+
+
+THolder<TLogBackend> TCoutLogBackendCreator::DoCreateLogBackend() const {
+ return MakeHolder<TStreamLogBackend>(&Cout);
+}
+
+
+TCoutLogBackendCreator::TCoutLogBackendCreator()
+ : TLogBackendCreatorBase("cout")
+{}
+
+ILogBackendCreator::TFactory::TRegistrator<TCoutLogBackendCreator> TCoutLogBackendCreator::Registrar("cout");
+
+void TCoutLogBackendCreator::DoToJson(NJson::TJsonValue& /*value*/) const {
+}
diff --git a/library/cpp/logger/stream_creator.h b/library/cpp/logger/stream_creator.h
new file mode 100644
index 0000000000..cd66e986c0
--- /dev/null
+++ b/library/cpp/logger/stream_creator.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "backend_creator.h"
+
+class TCerrLogBackendCreator : public TLogBackendCreatorBase {
+public:
+ TCerrLogBackendCreator();
+ static TFactory::TRegistrator<TCerrLogBackendCreator> RegistrarCerr;
+ static TFactory::TRegistrator<TCerrLogBackendCreator> RegistrarConsole;
+
+protected:
+ virtual void DoToJson(NJson::TJsonValue& value) const override;
+
+private:
+ virtual THolder<TLogBackend> DoCreateLogBackend() const override;
+};
+
+class TCoutLogBackendCreator : public TLogBackendCreatorBase {
+public:
+ TCoutLogBackendCreator();
+ static TFactory::TRegistrator<TCoutLogBackendCreator> Registrar;
+
+protected:
+ virtual void DoToJson(NJson::TJsonValue& value) const override;
+
+private:
+ virtual THolder<TLogBackend> DoCreateLogBackend() const override;
+};
diff --git a/library/cpp/logger/sync_page_cache_file.cpp b/library/cpp/logger/sync_page_cache_file.cpp
new file mode 100644
index 0000000000..a0e93a78d7
--- /dev/null
+++ b/library/cpp/logger/sync_page_cache_file.cpp
@@ -0,0 +1,125 @@
+#include "sync_page_cache_file.h"
+#include "record.h"
+
+#include <util/generic/buffer.h>
+#include <util/system/file.h>
+#include <util/system/info.h>
+#include <util/system/mutex.h>
+#include <util/system/rwlock.h>
+#include <util/system/align.h>
+
+class TSyncPageCacheFileLogBackend::TImpl: public TNonCopyable {
+public:
+ TImpl(const TString& path, size_t maxBufferSize, size_t maxPendingCacheSize)
+ : File_{OpenFile(path)}
+ , MaxBufferSize_{maxBufferSize}
+ , MaxPendingCacheSize_{maxPendingCacheSize}
+ , Buffer_{maxBufferSize}
+ {
+ ResetPtrs();
+ }
+
+ ~TImpl() noexcept {
+ try {
+ Write();
+ FlushSync(GuaranteedWrittenPtr_, WrittenPtr_);
+ } catch (...) {
+ }
+ }
+
+ void WriteData(const TLogRecord& rec) {
+ TGuard guard{Lock_};
+
+ Buffer_.Append(rec.Data, rec.Len);
+ if (Buffer_.size() >= MaxBufferSize_) {
+ const i64 prevAlignedEndPtr = PageAlignedWrittenPtr_;
+ Write();
+
+ if (prevAlignedEndPtr < PageAlignedWrittenPtr_) {
+ FlushAsync(prevAlignedEndPtr, PageAlignedWrittenPtr_);
+ }
+
+ const i64 minPendingCacheOffset = PageAlignedWrittenPtr_ - MaxPendingCacheSize_;
+ if (minPendingCacheOffset > GuaranteedWrittenPtr_) {
+ FlushSync(GuaranteedWrittenPtr_, minPendingCacheOffset);
+ }
+ }
+ }
+
+ void ReopenLog() {
+ TGuard guard{Lock_};
+
+ Write();
+ FlushSync(GuaranteedWrittenPtr_, WrittenPtr_);
+
+ File_.LinkTo(OpenFile(File_.GetName()));
+
+ ResetPtrs();
+ }
+
+private:
+ void ResetPtrs() {
+ WrittenPtr_ = File_.GetLength();
+ PageAlignedWrittenPtr_ = AlignDown(WrittenPtr_, GetPageSize());
+ GuaranteedWrittenPtr_ = WrittenPtr_;
+ }
+
+ static TFile OpenFile(const TString& path) {
+ return TFile{path, OpenAlways | WrOnly | ForAppend | Seq | NoReuse};
+ }
+
+ static i64 GetPageSize() {
+ static const i64 pageSize = NSystemInfo::GetPageSize();
+ Y_ASSUME(IsPowerOf2(pageSize));
+ return pageSize;
+ }
+
+ void Write() {
+ File_.Write(Buffer_.Data(), Buffer_.Size());
+ WrittenPtr_ += Buffer_.Size();
+ PageAlignedWrittenPtr_ = AlignDown(WrittenPtr_, GetPageSize());
+ Buffer_.Clear();
+ }
+
+ void FlushAsync(const i64 from, const i64 to) {
+ File_.FlushCache(from, to - from, /* wait = */ false);
+ }
+
+ void FlushSync(const i64 from, const i64 to) {
+ const i64 begin = AlignDown(from, GetPageSize());
+ const i64 end = AlignUp(to, GetPageSize());
+ const i64 length = end - begin;
+
+ File_.FlushCache(begin, length, /* wait = */ true);
+ File_.EvictCache(begin, length);
+
+ GuaranteedWrittenPtr_ = to;
+ }
+
+private:
+ TMutex Lock_;
+ TFile File_;
+
+ const size_t MaxBufferSize_ = 0;
+ const size_t MaxPendingCacheSize_ = 0;
+
+ TBuffer Buffer_;
+ i64 WrittenPtr_ = 0;
+ i64 PageAlignedWrittenPtr_ = 0;
+ i64 GuaranteedWrittenPtr_ = 0;
+};
+
+TSyncPageCacheFileLogBackend::TSyncPageCacheFileLogBackend(const TString& path, size_t maxBufferSize, size_t maxPengingCacheSize)
+ : Impl_(MakeHolder<TImpl>(path, maxBufferSize, maxPengingCacheSize))
+{}
+
+TSyncPageCacheFileLogBackend::~TSyncPageCacheFileLogBackend() {
+}
+
+void TSyncPageCacheFileLogBackend::WriteData(const TLogRecord& rec) {
+ Impl_->WriteData(rec);
+}
+
+void TSyncPageCacheFileLogBackend::ReopenLog() {
+ Impl_->ReopenLog();
+}
diff --git a/library/cpp/logger/sync_page_cache_file.h b/library/cpp/logger/sync_page_cache_file.h
new file mode 100644
index 0000000000..a36340651c
--- /dev/null
+++ b/library/cpp/logger/sync_page_cache_file.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "backend.h"
+
+#include <util/generic/fwd.h>
+#include <util/generic/ptr.h>
+
+class TSyncPageCacheFileLogBackend final: public TLogBackend {
+public:
+ TSyncPageCacheFileLogBackend(const TString& path, size_t maxBufferSize, size_t maxPendingCacheSize);
+ ~TSyncPageCacheFileLogBackend();
+
+ void WriteData(const TLogRecord& rec) override;
+ void ReopenLog() override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
diff --git a/library/cpp/logger/sync_page_cache_file_creator.cpp b/library/cpp/logger/sync_page_cache_file_creator.cpp
new file mode 100644
index 0000000000..bf91d20c23
--- /dev/null
+++ b/library/cpp/logger/sync_page_cache_file_creator.cpp
@@ -0,0 +1,28 @@
+#include "sync_page_cache_file_creator.h"
+#include "sync_page_cache_file.h"
+
+THolder<TLogBackend> TSyncPageCacheFileLogBackendCreator::DoCreateLogBackend() const {
+ return MakeHolder<TSyncPageCacheFileLogBackend>(Path, MaxBufferSize, MaxPendingCacheSize);
+}
+
+
+TSyncPageCacheFileLogBackendCreator::TSyncPageCacheFileLogBackendCreator()
+ : TFileLogBackendCreator("", "sync_page")
+{}
+
+bool TSyncPageCacheFileLogBackendCreator::Init(const IInitContext& ctx) {
+ if (!TFileLogBackendCreator::Init(ctx)) {
+ return false;
+ }
+ ctx.GetValue("MaxBufferSize", MaxBufferSize);
+ ctx.GetValue("MaxPendingCacheSize", MaxPendingCacheSize);
+ return true;
+}
+
+ILogBackendCreator::TFactory::TRegistrator<TSyncPageCacheFileLogBackendCreator> TSyncPageCacheFileLogBackendCreator::Registrar("sync_page");
+
+void TSyncPageCacheFileLogBackendCreator::DoToJson(NJson::TJsonValue& value) const {
+ TFileLogBackendCreator::DoToJson(value);
+ value["MaxBufferSize"] = MaxBufferSize;
+ value["MaxPendingCacheSize"] = MaxPendingCacheSize;
+}
diff --git a/library/cpp/logger/sync_page_cache_file_creator.h b/library/cpp/logger/sync_page_cache_file_creator.h
new file mode 100644
index 0000000000..7148150222
--- /dev/null
+++ b/library/cpp/logger/sync_page_cache_file_creator.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "file_creator.h"
+
+class TSyncPageCacheFileLogBackendCreator : public TFileLogBackendCreator {
+public:
+ TSyncPageCacheFileLogBackendCreator();
+ virtual bool Init(const IInitContext& ctx) override;
+ static TFactory::TRegistrator<TSyncPageCacheFileLogBackendCreator> Registrar;
+
+protected:
+ virtual void DoToJson(NJson::TJsonValue& value) const override;
+
+private:
+ virtual THolder<TLogBackend> DoCreateLogBackend() const override;
+ size_t MaxBufferSize = Max<size_t>();
+ size_t MaxPendingCacheSize = Max<size_t>();
+};
diff --git a/library/cpp/logger/system.cpp b/library/cpp/logger/system.cpp
new file mode 100644
index 0000000000..42233f63d2
--- /dev/null
+++ b/library/cpp/logger/system.cpp
@@ -0,0 +1,87 @@
+#include <util/stream/output.h>
+#include <util/stream/null.h>
+#include <util/system/compat.h>
+#include <util/system/yassert.h>
+#include <util/system/defaults.h>
+#include <util/generic/singleton.h>
+#include <util/generic/utility.h>
+
+#if defined(_unix_)
+#include <syslog.h>
+#endif
+
+#include "system.h"
+#include "record.h"
+#include "stream.h"
+
+TSysLogBackend::TSysLogBackend(const char* ident, EFacility facility, int flags)
+ : Ident(ident)
+ , Facility(facility)
+ , Flags(flags)
+{
+#if defined(_unix_)
+ Y_ASSERT(TSYSLOG_LOCAL0 <= facility && facility <= TSYSLOG_LOCAL7);
+
+ static const int f2sf[] = {
+ LOG_LOCAL0,
+ LOG_LOCAL1,
+ LOG_LOCAL2,
+ LOG_LOCAL3,
+ LOG_LOCAL4,
+ LOG_LOCAL5,
+ LOG_LOCAL6,
+ LOG_LOCAL7};
+
+ int sysflags = LOG_NDELAY | LOG_PID;
+
+ if (flags & LogPerror) {
+ sysflags |= LOG_PERROR;
+ }
+
+ if (flags & LogCons) {
+ sysflags |= LOG_CONS;
+ }
+
+ openlog(Ident.data(), sysflags, f2sf[(size_t)facility]);
+#endif
+}
+
+TSysLogBackend::~TSysLogBackend() {
+#if defined(_unix_)
+ closelog();
+#endif
+}
+
+void TSysLogBackend::WriteData(const TLogRecord& rec) {
+#if defined(_unix_)
+ syslog(ELogPriority2SyslogPriority(rec.Priority), "%.*s", (int)rec.Len, rec.Data);
+#else
+ Y_UNUSED(rec);
+#endif
+}
+
+void TSysLogBackend::ReopenLog() {
+}
+
+int TSysLogBackend::ELogPriority2SyslogPriority(ELogPriority priority) {
+#if defined(_unix_)
+ return Min(int(priority), (int)LOG_PRIMASK);
+#else
+ // trivial conversion
+ return int(priority);
+#endif
+}
+
+namespace {
+ class TSysLogInstance: public TLog {
+ public:
+ inline TSysLogInstance()
+ : TLog(MakeHolder<TStreamLogBackend>(&Cnull))
+ {
+ }
+ };
+}
+
+TLog& SysLogInstance() {
+ return *Singleton<TSysLogInstance>();
+}
diff --git a/library/cpp/logger/system.h b/library/cpp/logger/system.h
new file mode 100644
index 0000000000..b8c60b3023
--- /dev/null
+++ b/library/cpp/logger/system.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include "log.h"
+#include "backend.h"
+#include "priority.h"
+
+#define YSYSLOG(priority, ...) SysLogInstance().AddLog((priority), __VA_ARGS__)
+#define YSYSLOGINIT_FLAGS(ident, facility, flags) \
+ struct TLogIniter { \
+ TLogIniter() { \
+ SysLogInstance().ResetBackend(THolder<TLogBackend>( \
+ (ident) ? (TLogBackend*)(new TSysLogBackend((ident), (facility), (flags))) : (TLogBackend*)(new TNullLogBackend())));\
+ } \
+ } Y_CAT(loginit, __LINE__);
+
+#define YSYSLOGINIT(ident, facility) YSYSLOGINIT_FLAGS((ident), (facility), 0)
+
+class TSysLogBackend: public TLogBackend {
+public:
+ enum EFacility {
+ TSYSLOG_LOCAL0 = 0,
+ TSYSLOG_LOCAL1 = 1,
+ TSYSLOG_LOCAL2 = 2,
+ TSYSLOG_LOCAL3 = 3,
+ TSYSLOG_LOCAL4 = 4,
+ TSYSLOG_LOCAL5 = 5,
+ TSYSLOG_LOCAL6 = 6,
+ TSYSLOG_LOCAL7 = 7
+ };
+
+ enum EFlags {
+ LogPerror = 1,
+ LogCons = 2
+ };
+
+ TSysLogBackend(const char* ident, EFacility facility, int flags = 0);
+ ~TSysLogBackend() override;
+
+ void WriteData(const TLogRecord& rec) override;
+ void ReopenLog() override;
+
+ virtual TString GetIdent() const {
+ return Ident;
+ }
+
+ virtual EFacility GetFacility() const {
+ return Facility;
+ }
+
+ virtual int GetFlags() const {
+ return Flags;
+ }
+
+protected:
+ int ELogPriority2SyslogPriority(ELogPriority priority);
+
+ TString Ident;
+ EFacility Facility;
+ int Flags;
+};
+
+/*
+ * return system-wide logger instance
+ * better do not use in real programs(instead of robot, of course)
+ */
+TLog& SysLogInstance();
diff --git a/library/cpp/logger/system_creator.cpp b/library/cpp/logger/system_creator.cpp
new file mode 100644
index 0000000000..e1cd02d422
--- /dev/null
+++ b/library/cpp/logger/system_creator.cpp
@@ -0,0 +1,25 @@
+#include "system_creator.h"
+
+THolder<TLogBackend> TSysLogBackendCreator::DoCreateLogBackend() const {
+ return MakeHolder<TSysLogBackend>(Ident.c_str(), Facility, Flags);
+}
+
+
+TSysLogBackendCreator::TSysLogBackendCreator()
+ : TLogBackendCreatorBase("system")
+{}
+
+bool TSysLogBackendCreator::Init(const IInitContext& ctx) {
+ ctx.GetValue("Ident", Ident);
+ ctx.GetValue("Facility", (int&)Facility);
+ ctx.GetValue("Flags", Flags);
+ return true;
+}
+
+ILogBackendCreator::TFactory::TRegistrator<TSysLogBackendCreator> TSysLogBackendCreator::Registrar("system");
+
+void TSysLogBackendCreator::DoToJson(NJson::TJsonValue& value) const {
+ value["Ident"] = Ident;
+ value["Facility"] = (int&)Facility;
+ value["Flags"] = Flags;
+}
diff --git a/library/cpp/logger/system_creator.h b/library/cpp/logger/system_creator.h
new file mode 100644
index 0000000000..e5321267e9
--- /dev/null
+++ b/library/cpp/logger/system_creator.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "backend_creator.h"
+#include "system.h"
+
+class TSysLogBackendCreator : public TLogBackendCreatorBase {
+public:
+ TSysLogBackendCreator();
+ virtual bool Init(const IInitContext& ctx) override;
+ static TFactory::TRegistrator<TSysLogBackendCreator> Registrar;
+
+protected:
+ virtual void DoToJson(NJson::TJsonValue& value) const override;
+
+private:
+ virtual THolder<TLogBackend> DoCreateLogBackend() const override;
+ TString Ident;
+ TSysLogBackend::EFacility Facility = TSysLogBackend::TSYSLOG_LOCAL0;
+ int Flags = 0;
+};
diff --git a/library/cpp/logger/thread.cpp b/library/cpp/logger/thread.cpp
new file mode 100644
index 0000000000..0ccf9e374b
--- /dev/null
+++ b/library/cpp/logger/thread.cpp
@@ -0,0 +1,165 @@
+#include "thread.h"
+#include "record.h"
+
+#include <util/thread/pool.h>
+#include <util/system/event.h>
+#include <util/memory/addstorage.h>
+#include <util/generic/ptr.h>
+#include <util/generic/yexception.h>
+
+class TThreadedLogBackend::TImpl {
+ class TRec: public IObjectInQueue, public TAdditionalStorage<TRec>, public TLogRecord {
+ public:
+ inline TRec(TImpl* parent, const TLogRecord& rec)
+ : TLogRecord(rec.Priority, (const char*)AdditionalData(), rec.Len)
+ , Parent_(parent)
+ {
+ memcpy(AdditionalData(), rec.Data, rec.Len);
+ }
+
+ inline ~TRec() override {
+ }
+
+ private:
+ void Process(void* /*tsr*/) override {
+ THolder<TRec> This(this);
+
+ Parent_->Slave_->WriteData(*this);
+ }
+
+ private:
+ TImpl* Parent_;
+ };
+
+ class TReopener: public IObjectInQueue, public TSystemEvent, public TAtomicRefCount<TReopener> {
+ public:
+ inline TReopener(TImpl* parent)
+ : Parent_(parent)
+ {
+ Ref();
+ }
+
+ inline ~TReopener() override {
+ }
+
+ private:
+ void Process(void* /*tsr*/) override {
+ try {
+ Parent_->Slave_->ReopenLog();
+ } catch (...) {
+ }
+
+ Signal();
+ UnRef();
+ }
+
+ private:
+ TImpl* Parent_;
+ };
+
+public:
+ inline TImpl(TLogBackend* slave, size_t queuelen, std::function<void()> queueOverflowCallback = {})
+ : Slave_(slave)
+ , QueueOverflowCallback_(std::move(queueOverflowCallback))
+ {
+ Queue_.Start(1, queuelen);
+ }
+
+ inline ~TImpl() {
+ Queue_.Stop();
+ }
+
+ inline void WriteData(const TLogRecord& rec) {
+ THolder<TRec> obj(new (rec.Len) TRec(this, rec));
+
+ if (Queue_.Add(obj.Get())) {
+ Y_UNUSED(obj.Release());
+ return;
+ }
+
+ if (QueueOverflowCallback_) {
+ QueueOverflowCallback_();
+ } else {
+ ythrow yexception() << "log queue exhausted";
+ }
+ }
+
+ // Write an emergency message when the memory allocator is corrupted.
+ // The TThreadedLogBackend object can't be used after this method is called.
+ inline void WriteEmergencyData(const TLogRecord& rec) noexcept {
+ Queue_.Stop();
+ Slave_->WriteData(rec);
+ }
+
+ inline void ReopenLog() {
+ TIntrusivePtr<TReopener> reopener(new TReopener(this));
+
+ if (!Queue_.Add(reopener.Get())) {
+ reopener->UnRef(); // Ref() was called in constructor
+ ythrow yexception() << "log queue exhausted";
+ }
+
+ reopener->Wait();
+ }
+
+ inline void ReopenLogNoFlush() {
+ Slave_->ReopenLogNoFlush();
+ }
+
+ inline size_t QueueSize() const {
+ return Queue_.Size();
+ }
+
+private:
+ TLogBackend* Slave_;
+ TThreadPool Queue_{"ThreadedLogBack"};
+ const std::function<void()> QueueOverflowCallback_;
+};
+
+TThreadedLogBackend::TThreadedLogBackend(TLogBackend* slave)
+ : Impl_(new TImpl(slave, 0))
+{
+}
+
+TThreadedLogBackend::TThreadedLogBackend(TLogBackend* slave, size_t queuelen, std::function<void()> queueOverflowCallback)
+ : Impl_(new TImpl(slave, queuelen, std::move(queueOverflowCallback)))
+{
+}
+
+TThreadedLogBackend::~TThreadedLogBackend() {
+}
+
+void TThreadedLogBackend::WriteData(const TLogRecord& rec) {
+ Impl_->WriteData(rec);
+}
+
+void TThreadedLogBackend::ReopenLog() {
+ Impl_->ReopenLog();
+}
+
+void TThreadedLogBackend::ReopenLogNoFlush() {
+ Impl_->ReopenLogNoFlush();
+}
+
+void TThreadedLogBackend::WriteEmergencyData(const TLogRecord& rec) {
+ Impl_->WriteEmergencyData(rec);
+}
+
+size_t TThreadedLogBackend::QueueSize() const {
+ return Impl_->QueueSize();
+}
+
+TOwningThreadedLogBackend::TOwningThreadedLogBackend(TLogBackend* slave)
+ : THolder<TLogBackend>(slave)
+ , TThreadedLogBackend(Get())
+{
+}
+
+TOwningThreadedLogBackend::TOwningThreadedLogBackend(TLogBackend* slave, size_t queuelen, std::function<void()> queueOverflowCallback)
+ : THolder<TLogBackend>(slave)
+ , TThreadedLogBackend(Get(), queuelen, std::move(queueOverflowCallback))
+{
+}
+
+TOwningThreadedLogBackend::~TOwningThreadedLogBackend() {
+}
diff --git a/library/cpp/logger/thread.h b/library/cpp/logger/thread.h
new file mode 100644
index 0000000000..65f7a88e87
--- /dev/null
+++ b/library/cpp/logger/thread.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "backend.h"
+
+#include <util/generic/ptr.h>
+
+#include <functional>
+
+class TThreadedLogBackend: public TLogBackend {
+public:
+ TThreadedLogBackend(TLogBackend* slave);
+ TThreadedLogBackend(TLogBackend* slave, size_t queuelen, std::function<void()> queueOverflowCallback = {});
+ ~TThreadedLogBackend() override;
+
+ void WriteData(const TLogRecord& rec) override;
+ void ReopenLog() override;
+ void ReopenLogNoFlush() override;
+ size_t QueueSize() const override;
+
+ // Write an emergency message when the memory allocator is corrupted.
+ // The TThreadedLogBackend object can't be used after this method is called.
+ void WriteEmergencyData(const TLogRecord& rec);
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+class TOwningThreadedLogBackend: private THolder<TLogBackend>, public TThreadedLogBackend {
+public:
+ TOwningThreadedLogBackend(TLogBackend* slave);
+ TOwningThreadedLogBackend(TLogBackend* slave, size_t queuelen, std::function<void()> queueOverflowCallback = {});
+ ~TOwningThreadedLogBackend() override;
+};
diff --git a/library/cpp/logger/thread_creator.cpp b/library/cpp/logger/thread_creator.cpp
new file mode 100644
index 0000000000..8f5cfe2782
--- /dev/null
+++ b/library/cpp/logger/thread_creator.cpp
@@ -0,0 +1,30 @@
+#include "thread_creator.h"
+#include "thread.h"
+
+TOwningThreadedLogBackendCreator::TOwningThreadedLogBackendCreator(THolder<ILogBackendCreator>&& slave)
+ : Slave(std::move(slave))
+{}
+
+THolder<TLogBackend> TOwningThreadedLogBackendCreator::DoCreateLogBackend() const {
+ return MakeHolder<TOwningThreadedLogBackend>(Slave->CreateLogBackend().Release(), QueueLen, QueueOverflowCallback);
+}
+
+bool TOwningThreadedLogBackendCreator::Init(const IInitContext& ctx) {
+ ctx.GetValue("QueueLen", QueueLen);
+ return Slave->Init(ctx);
+}
+
+
+void TOwningThreadedLogBackendCreator::ToJson(NJson::TJsonValue& value) const {
+ value["QueueLen"] = QueueLen;
+ value["Threaded"] = true;
+ Slave->ToJson(value);
+}
+
+void TOwningThreadedLogBackendCreator::SetQueueOverflowCallback(std::function<void()> callback) {
+ QueueOverflowCallback = std::move(callback);
+}
+
+void TOwningThreadedLogBackendCreator::SetQueueLen(size_t len) {
+ QueueLen = len;
+}
diff --git a/library/cpp/logger/thread_creator.h b/library/cpp/logger/thread_creator.h
new file mode 100644
index 0000000000..9e5ee9571d
--- /dev/null
+++ b/library/cpp/logger/thread_creator.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "backend_creator.h"
+
+#include <functional>
+
+class TOwningThreadedLogBackendCreator: public ILogBackendCreator {
+public:
+ TOwningThreadedLogBackendCreator(THolder<ILogBackendCreator>&& slave);
+ virtual bool Init(const IInitContext& ctx) override;
+ virtual void ToJson(NJson::TJsonValue& value) const override;
+ void SetQueueOverflowCallback(std::function<void()> callback);
+ void SetQueueLen(size_t len);
+
+private:
+ virtual THolder<TLogBackend> DoCreateLogBackend() const override;
+ THolder<ILogBackendCreator> Slave;
+ std::function<void()> QueueOverflowCallback = {};
+ size_t QueueLen = 0;
+};
diff --git a/library/cpp/logger/uninitialized_creator.cpp b/library/cpp/logger/uninitialized_creator.cpp
new file mode 100644
index 0000000000..26dd168529
--- /dev/null
+++ b/library/cpp/logger/uninitialized_creator.cpp
@@ -0,0 +1,50 @@
+#include "uninitialized_creator.h"
+#include "filter_creator.h"
+#include "thread_creator.h"
+#include "file_creator.h"
+#include "null_creator.h"
+#include <util/string/cast.h>
+
+THolder<TLogBackend> TLogBackendCreatorUninitialized::DoCreateLogBackend() const {
+ return Slave->CreateLogBackend();
+}
+
+void TLogBackendCreatorUninitialized::InitCustom(const TString& type, ELogPriority priority, bool threaded) {
+ if (!type) {
+ Slave = MakeHolder<TNullLogBackendCreator>();
+ } else if (TFactory::Has(type)) {
+ Slave = TFactory::MakeHolder(type);
+ } else {
+ Slave = MakeHolder<TFileLogBackendCreator>(type);
+ }
+
+ if (threaded) {
+ Slave = MakeHolder<TOwningThreadedLogBackendCreator>(std::move(Slave));
+ }
+
+ if (priority != LOG_MAX_PRIORITY) {
+ Slave = MakeHolder<TFilteredBackendCreator>(std::move(Slave), priority);
+ }
+}
+
+bool TLogBackendCreatorUninitialized::Init(const IInitContext& ctx) {
+ auto type = ctx.GetOrElse("LoggerType", TString());
+ bool threaded = ctx.GetOrElse("Threaded", false);
+ ELogPriority priority = LOG_MAX_PRIORITY;
+ TString prStr;
+ if (ctx.GetValue("LogLevel", prStr)) {
+ if (!TryFromString(prStr, priority)) {
+ priority = (ELogPriority)FromString<int>(prStr);
+ }
+ }
+ InitCustom(type, priority, threaded);
+ return Slave->Init(ctx);
+}
+
+
+void TLogBackendCreatorUninitialized::ToJson(NJson::TJsonValue& value) const {
+ Y_VERIFY(Slave, "Serialization off uninitialized LogBackendCreator");
+ Slave->ToJson(value);
+}
+
+ILogBackendCreator::TFactory::TRegistrator<TLogBackendCreatorUninitialized> TLogBackendCreatorUninitialized::Registrar("");
diff --git a/library/cpp/logger/uninitialized_creator.h b/library/cpp/logger/uninitialized_creator.h
new file mode 100644
index 0000000000..16ee0b92f6
--- /dev/null
+++ b/library/cpp/logger/uninitialized_creator.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "backend_creator.h"
+
+class TLogBackendCreatorUninitialized : public ILogBackendCreator {
+public:
+ void InitCustom(const TString& type, ELogPriority priority, bool threaded);
+ virtual bool Init(const IInitContext& ctx) override;
+ virtual void ToJson(NJson::TJsonValue& value) const override;
+
+ static TFactory::TRegistrator<TLogBackendCreatorUninitialized> Registrar;
+
+private:
+ virtual THolder<TLogBackend> DoCreateLogBackend() const override;
+ THolder<ILogBackendCreator> Slave;
+};
diff --git a/library/cpp/logger/ut/ya.make b/library/cpp/logger/ut/ya.make
new file mode 100644
index 0000000000..2a461c1353
--- /dev/null
+++ b/library/cpp/logger/ut/ya.make
@@ -0,0 +1,20 @@
+UNITTEST()
+
+OWNER(pg)
+
+PEERDIR(
+ ADDINCL library/cpp/logger
+ library/cpp/logger/init_context
+ library/cpp/yconf/patcher
+)
+
+SRCDIR(library/cpp/logger)
+
+SRCS(
+ log_ut.cpp
+ element_ut.cpp
+ rotating_file_ut.cpp
+ composite_ut.cpp
+)
+
+END()
diff --git a/library/cpp/logger/ya.make b/library/cpp/logger/ya.make
new file mode 100644
index 0000000000..00a5263cba
--- /dev/null
+++ b/library/cpp/logger/ya.make
@@ -0,0 +1,47 @@
+OWNER(
+ pg
+ mvel
+ g:util
+ g:base
+)
+
+LIBRARY()
+
+GENERATE_ENUM_SERIALIZATION(priority.h)
+
+PEERDIR (
+ library/cpp/json
+)
+
+SRCS(
+ all.h
+ backend.cpp
+ backend_creator.cpp
+ composite.cpp
+ GLOBAL composite_creator.cpp
+ element.cpp
+ file.cpp
+ GLOBAL file_creator.cpp
+ filter.cpp
+ filter_creator.cpp
+ log.cpp
+ null.cpp
+ GLOBAL null_creator.cpp
+ priority.h
+ record.h
+ rotating_file.cpp
+ GLOBAL rotating_file_creator.cpp
+ stream.cpp
+ GLOBAL stream_creator.cpp
+ sync_page_cache_file.cpp
+ GLOBAL sync_page_cache_file_creator.cpp
+ system.cpp
+ GLOBAL system_creator.cpp
+ thread.cpp
+ thread_creator.cpp
+ GLOBAL uninitialized_creator.cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/lwtrace/all.h b/library/cpp/lwtrace/all.h
new file mode 100644
index 0000000000..d7aa57c49d
--- /dev/null
+++ b/library/cpp/lwtrace/all.h
@@ -0,0 +1,195 @@
+#pragma once
+
+#include "control.h"
+#include "event.h"
+#include "preprocessor.h"
+#include "probe.h"
+#include "start.h"
+
+//
+// Full documentation: https://wiki.yandex-team.ru/development/poisk/arcadia/library/lwtrace/
+//
+// Short usage instruction:
+//
+// 1. Declare probes provider in header file 'probes.h':
+// #include <yweb/robot/kiwi/lwtrace/all.h>
+// #define MY_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ // name of your provider
+// PROBE(MyProbe, GROUPS("MyGroup1", "MyGroup2"), TYPES(), NAMES()) \ // probe specification w/o argiments
+// PROBE(MyAnotherProbe, GROUPS("MyGroup2"), TYPES(int, TString), NAMES("arg1", "arg2")) \ // another probe with arguments
+// PROBE(MyScopedProbe, GROUPS(), TYPES(ui64, int), NAMES("duration", "stage")) \ // scoped probe with argument
+// /**/
+// LWTRACE_DECLARE_PROVIDER(MY_PROVIDER)
+//
+// 2. Define provider in source file 'provider.cpp':
+// #include "probes.h"
+// LWTRACE_DEFINE_PROVIDER(MY_PROVIDER)
+//
+// 3. Call probes from provider in your code:
+// #include "probes.h"
+// int main() {
+// GLOBAL_LWPROBE(MY_PROVIDER, MyProbe);
+// GLOBAL_LWPROBE(MY_PROVIDER, MyAnotherProbe, 123, stroka);
+// ... or ...
+// LWTRACE_USING(MY_PROVIDER); // expands into using namespace
+// LWPROBE(MyProbe);
+// LWPROBE(MyAnotherProbe, 123, stroka);
+// }
+//
+// 4. Attach provider to your monitoring service:
+// #include <yweb/robot/kiwi/util/monservice.h>
+// #include "probes.h"
+// class TMyMonSrvc: public NKiwi::TMonService {
+// TMyMonSrvc(TProbeRegistry& probes)
+// {
+// THolder<NKiwi::TTraceMonPage> tr(new NKiwi::TTraceMonPage());
+// tr->GetProbes().AddProbesList(LWTRACE_GET_PROBES(MY_PROVIDER));
+// Register(tr.Release());
+// }
+// };
+//
+// 5. Compile and run application
+//
+// 6. Create file 'mysuper.tr' with trace query:
+// Blocks { # Log all calls to probes from MyGroup1
+// ProbeDesc { Group: "MyGroup1" }
+// Action {
+// LogAction { LogTimestamp: true }
+// }
+// }
+// Blocks { # Log first 10 calls to MyAnother with arg1 > 1000
+// ProbeDesc { Name: "MyAnotherProbe"; Provider: "MY_PROVIDER" }
+// Predicate {
+// Operators { Type: OT_GT; Param: "arg1"; Value: "1000" }
+// }
+// Action {
+// LogAction { MaxRecords: 10 }
+// }
+// }
+// Blocks { # Start following executon of all 4 blocks each time MyAnotherProbe was called with arg2 == "start"
+// ProbeDesc { Name: "MyAnotherProbe"; Provider: "MY_PROVIDER" }
+// Predicate {
+// Operators { Type: OT_EQ; Param: "arg2"; Value: "start" }
+// }
+// Action { StartAction {} }
+// }
+// Blocks { # Stop following executon of all 4 blocks each time MyAnotherProbe was called with arg2 == "stop"
+// ProbeDesc { Name: "MyAnotherProbe"; Provider: "MY_PROVIDER" }
+// Predicate {
+// Operators { Type: OT_EQ; Param: "arg2"; Value: "stop" }
+// }
+// Action { StopAction {} }
+// }
+//
+// 7. Send trace query to the server with HTTP POST:
+// yweb/robot/kiwi/scripts/trace.sh new uniq-id-for-my-trace hostname:monport < mysuper.tr
+//
+// 8. With browser go to: http://hostname:monport/trace
+//
+// 9. Delete query from server:
+// yweb/robot/kiwi/scripts/trace.sh delete uniq-id-for-my-trace hostname:monport
+//
+//
+// CONFIGURATION AND SUPPORT:
+// 1. Turning off all calls to probes.
+// Add to project's CMakeLists.txt: add_definitions(-DLWTRACE_DISABLE_PROBES)
+//
+// 2. Turning off all calls to events.
+// Add to project's CMakeLists.txt: add_definitions(-DLWTRACE_DISABLE_EVENTS)
+//
+// 3. Increasing maximum number of probe parameters:
+// Add more lines in FOREACH_PARAMNUM macro definition in preprocessor.h
+//
+//
+// ISSUES
+// 1. Note that executors for different blocks are attached in order of their declaration in trace script.
+// Executor can be called by a program as soon as it is attached, therefore there is no guarantee that
+// all blocks are started simultaneously
+//
+
+#ifndef LWTRACE_DISABLE
+
+// Declare user provider (see USAGE INSTRUCTION)
+#define LWTRACE_DECLARE_PROVIDER(provider) LWTRACE_DECLARE_PROVIDER_I(provider)
+
+// Define user provider (see USAGE INSTRUCTION)
+#define LWTRACE_DEFINE_PROVIDER(provider) LWTRACE_DEFINE_PROVIDER_I(provider)
+
+// Import names from provider
+#define LWTRACE_USING(provider) using namespace LWTRACE_GET_NAMESPACE(provider);
+
+// Probes and events list accessor
+#define LWTRACE_GET_PROBES(provider) LWTRACE_GET_PROBES_I(provider)
+#define LWTRACE_GET_EVENTS(provider) LWTRACE_GET_EVENTS_I(provider)
+
+#ifndef LWTRACE_DISABLE_PROBES
+
+// Call a probe
+// NOTE: LWPROBE() should be used in source files only with previous call to LWTRACE_USING(MY_PROVIDER)
+// NOTE: in header files GLOBAL_LWPROBE() should be used instead
+// NOTE: if lots of calls needed in header file, it's convenient to define/undef the following macro:
+// NOTE: #define MY_PROBE(name, ...) GLOBAL_LWPROBE(MY_PROVIDER, name, ## __VA_ARGS__)
+#define GLOBAL_LWPROBE(provider, probe, ...) LWPROBE_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(probe), ##__VA_ARGS__)
+#define LWPROBE(probe, ...) LWPROBE_I(LWTRACE_GET_NAME(probe), ##__VA_ARGS__)
+#define GLOBAL_LWPROBE_ENABLED(provider, probe) LWPROBE_ENABLED_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(probe))
+#define LWPROBE_ENABLED(probe) LWPROBE_ENABLED_I(LWTRACE_GET_NAME(probe))
+#define LWPROBE_OBJ(probe, ...) LWPROBE_I(probe, ##__VA_ARGS__)
+
+// Calls a probe when scope is beeing left
+// NOTE: arguments are passed by value and stored until scope exit
+// NOTE: probe should be declared with first params of type ui64, argument for which is automaticaly generated (duration in microseconds)
+// NOTE: *_DURATION() macros take through "..." all arguments except the first one
+#define GLOBAL_LWPROBE_DURATION(provider, probe, ...) LWPROBE_DURATION_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_TYPE(probe), lwtrace_scoped_##provider##probe, LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(probe), ##__VA_ARGS__)
+#define LWPROBE_DURATION(probe, ...) LWPROBE_DURATION_I(LWTRACE_GET_TYPE(probe), lwtrace_scoped_##probe, LWTRACE_GET_NAME(probe), ##__VA_ARGS__)
+
+// Probe with orbit support
+#define GLOBAL_LWTRACK(provider, probe, orbit, ...) LWTRACK_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(probe), orbit, ##__VA_ARGS__)
+#define LWTRACK(probe, orbit, ...) LWTRACK_I(LWTRACE_GET_NAME(probe), orbit, ##__VA_ARGS__)
+#define LWTRACK_OBJ(probe, orbit, ...) LWTRACK_I(probe, orbit, ##__VA_ARGS__)
+
+#else
+#define GLOBAL_LWPROBE(provider, probe, ...)
+#define LWPROBE(probe, ...)
+#define GLOBAL_LWPROBE_ENABLED(provider, probe) false
+#define LWPROBE_ENABLED(probe) false
+#define LWPROBE_OBJ(probe, ...) Y_UNUSED(probe)
+#define GLOBAL_LWPROBE_DURATION(provider, probe, ...)
+#define LWPROBE_DURATION(probe, ...)
+#define GLOBAL_LWTRACK(provider, probe, orbit, ...)
+#define LWTRACK(probe, orbit, ...)
+#define LWTRACK_OBJ(probe, orbit, ...) Y_UNUSED(probe)
+#endif
+
+#ifndef LWTRACE_DISABLE_EVENTS
+
+// Call an event
+// NOTE: LWEVENT() should be used in source files only with previous call to LWTRACE_USING(MY_PROVIDER)
+// NOTE: in header files GLOBAL_LWEVENT() should be used instead
+// NOTE: if lots of calls needed in header file, it's convenient to define/undef the following macro:
+// NOTE: #define MY_EVENT(name, ...) GLOBAL_LWEVENT(MY_PROVIDER, name, ## __VA_ARGS__)
+#define GLOBAL_LWEVENT(provider, event, ...) LWEVENT_I(LWTRACE_GET_NAMESPACE(provider)::LWTRACE_GET_NAME(event), ##__VA_ARGS__)
+#define LWEVENT(event, ...) LWEVENT_I(LWTRACE_GET_NAME(event), ##__VA_ARGS__)
+
+#else
+#define GLOBAL_LWEVENT(provider, event, ...)
+#define LWEVENT(event, ...)
+#endif
+
+#else
+
+#define LWTRACE_DECLARE_PROVIDER(provider)
+#define LWTRACE_DEFINE_PROVIDER(provider)
+#define LWTRACE_USING(provider)
+#define LWTRACE_GET_PROBES(provider) NULL
+#define LWTRACE_GET_EVENTS(provider) NULL
+#define GLOBAL_LWPROBE(provider, probe, ...)
+#define LWPROBE(probe, ...)
+#define GLOBAL_LWPROBE_ENABLED(provider, probe) false
+#define LWPROBE_ENABLED(probe) false
+#define GLOBAL_LWPROBE_DURATION(provider, probe, ...)
+#define LWPROBE_DURATION(probe, ...)
+#define GLOBAL_LWTRACK(provider, probe, orbit, ...)
+#define LWTRACK(probe, orbit, ...)
+#define GLOBAL_LWEVENT(provider, event, ...)
+#define LWEVENT(event, ...)
+
+#endif
diff --git a/library/cpp/lwtrace/check.cpp b/library/cpp/lwtrace/check.cpp
new file mode 100644
index 0000000000..4e34fc5d49
--- /dev/null
+++ b/library/cpp/lwtrace/check.cpp
@@ -0,0 +1,18 @@
+#include "check.h"
+
+#include <util/stream/output.h>
+#include <util/string/cast.h>
+
+namespace NLWTrace {
+ int TCheck::ObjCount = 0;
+}
+
+template <>
+NLWTrace::TCheck FromStringImpl(const char* data, size_t len) {
+ return NLWTrace::TCheck(FromString<int, char>(data, len));
+}
+
+template <>
+void Out<NLWTrace::TCheck>(IOutputStream& o, TTypeTraits<NLWTrace::TCheck>::TFuncParam t) {
+ Out<int>(o, t.Value);
+}
diff --git a/library/cpp/lwtrace/check.h b/library/cpp/lwtrace/check.h
new file mode 100644
index 0000000000..71503cbc7b
--- /dev/null
+++ b/library/cpp/lwtrace/check.h
@@ -0,0 +1,78 @@
+#pragma once
+
+namespace NLWTrace {
+ struct TCheck {
+ int Value;
+ static int ObjCount;
+
+ TCheck()
+ : Value(0)
+ {
+ ObjCount++;
+ }
+
+ explicit TCheck(int value)
+ : Value(value)
+ {
+ ObjCount++;
+ }
+
+ TCheck(const TCheck& o)
+ : Value(o.Value)
+ {
+ ObjCount++;
+ }
+
+ ~TCheck() {
+ ObjCount--;
+ }
+
+ bool operator<(const TCheck& rhs) const {
+ return Value < rhs.Value;
+ }
+ bool operator>(const TCheck& rhs) const {
+ return Value > rhs.Value;
+ }
+ bool operator<=(const TCheck& rhs) const {
+ return Value <= rhs.Value;
+ }
+ bool operator>=(const TCheck& rhs) const {
+ return Value >= rhs.Value;
+ }
+ bool operator==(const TCheck& rhs) const {
+ return Value == rhs.Value;
+ }
+ bool operator!=(const TCheck& rhs) const {
+ return Value != rhs.Value;
+ }
+ TCheck operator+(const TCheck& rhs) const {
+ return TCheck(Value + rhs.Value);
+ }
+ TCheck operator-(const TCheck& rhs) const {
+ return TCheck(Value - rhs.Value);
+ }
+ TCheck operator*(const TCheck& rhs) const {
+ return TCheck(Value * rhs.Value);
+ }
+ TCheck operator/(const TCheck& rhs) const {
+ return TCheck(Value / rhs.Value);
+ }
+ TCheck operator%(const TCheck& rhs) const {
+ return TCheck(Value % rhs.Value);
+ }
+
+ void Add(const TCheck rhs) {
+ Value += rhs.Value;
+ }
+ void Sub(const TCheck rhs) {
+ Value -= rhs.Value;
+ }
+ void Inc() {
+ ++Value;
+ }
+ void Dec() {
+ --Value;
+ }
+ };
+
+}
diff --git a/library/cpp/lwtrace/control.cpp b/library/cpp/lwtrace/control.cpp
new file mode 100644
index 0000000000..d9404ff269
--- /dev/null
+++ b/library/cpp/lwtrace/control.cpp
@@ -0,0 +1,97 @@
+#include "probes.h"
+
+#include <library/cpp/lwtrace/protos/lwtrace.pb.h>
+
+#include <util/generic/string.h>
+
+namespace NLWTrace {
+
+LWTRACE_USING(LWTRACE_INTERNAL_PROVIDER);
+
+TProbeMap TManager::GetProbesMap() {
+ class TProbeReader
+ {
+ private:
+ TProbeMap& Result;
+
+ public:
+ TProbeReader(TProbeMap& result)
+ : Result(result)
+ {}
+
+ void Push(NLWTrace::TProbe* probe)
+ {
+ Result[std::make_pair(probe->Event.Name, probe->Event.GetProvider())] = probe;
+ }
+ };
+
+ TProbeMap result;
+
+ auto reader = TProbeReader(result);
+ ReadProbes(reader);
+ return result;
+}
+
+void TManager::CreateTraceRequest(TTraceRequest& msg, TOrbit& orbit)
+{
+ msg.SetIsTraced(orbit.HasShuttles());
+}
+
+bool TManager::HandleTraceRequest(
+ const TTraceRequest& msg,
+ TOrbit& orbit)
+{
+ if (!msg.GetIsTraced()) {
+ return false;
+ }
+ TParams params;
+ SerializingExecutor->Execute(orbit, params);
+ return true;
+}
+
+TTraceDeserializeStatus TManager::HandleTraceResponse(
+ const TTraceResponse& msg,
+ const TProbeMap& probesMap,
+ TOrbit& orbit,
+ i64 timeOffset,
+ double timeScale)
+{
+ TTraceDeserializeStatus result;
+ if (!msg.GetTrace().GetEvents().size()) {
+ return result;
+ }
+
+ ui64 prev = EpochNanosecondsToCycles(
+ msg.GetTrace().GetEvents()[0].GetTimestampNanosec());
+
+ for (auto& v : msg.GetTrace().GetEvents()) {
+ auto it = probesMap.find(std::make_pair(v.GetName(), v.GetProvider()));
+ if (it != probesMap.end()) {
+ TProbe* probe = it->second;
+ TParams params;
+ if(!probe->Event.Signature.DeserializeFromPb(params, v.GetParams())) {
+ LWTRACK(DeserializationError, orbit, probe->Event.Name, probe->Event.GetProvider());
+ result.AddFailedEventName(v.GetName());
+ } else {
+ ui64 timestamp = EpochNanosecondsToCycles(v.GetTimestampNanosec());
+ orbit.AddProbe(
+ probe,
+ params,
+ prev + (timestamp-prev)*timeScale + timeOffset);
+ probe->Event.Signature.DestroyParams(params);
+ prev = timestamp;
+ }
+ } else {
+ result.AddFailedEventName(v.GetName());
+ }
+ }
+ return result;
+}
+
+void TManager::CreateTraceResponse(TTraceResponse& msg, TOrbit& orbit)
+{
+ orbit.Serialize(0, *msg.MutableTrace());
+}
+
+}
+
diff --git a/library/cpp/lwtrace/control.h b/library/cpp/lwtrace/control.h
new file mode 100644
index 0000000000..16b24eafd2
--- /dev/null
+++ b/library/cpp/lwtrace/control.h
@@ -0,0 +1,351 @@
+#pragma once
+
+#include "custom_action.h"
+#include "event.h"
+#include "log.h"
+#include "log_shuttle.h"
+#include "probe.h"
+
+#include <library/cpp/lwtrace/protos/lwtrace.pb.h>
+
+#include <google/protobuf/repeated_field.h>
+
+#include <util/generic/deque.h>
+#include <util/generic/hash.h>
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/generic/set.h>
+#include <util/generic/vector.h>
+
+namespace NLWTrace {
+
+ using TProbeMap = THashMap<std::pair<TString, TString>, TProbe*>;
+
+ // Interface for probe ownership management
+ class IBox: public virtual TThrRefBase {
+ private:
+ bool Owns;
+
+ public:
+ explicit IBox(bool ownsProbe = false)
+ : Owns(ownsProbe)
+ {
+ }
+
+ bool OwnsProbe() {
+ return Owns;
+ }
+
+ virtual TProbe* GetProbe() = 0;
+ };
+
+ using TBoxPtr = TIntrusivePtr<IBox>;
+
+ // Simple not-owning box, that just holds pointer to static/global probe (e.g. created by LWTRACE_DEFINE_PROVIDER)
+ class TStaticBox: public IBox {
+ private:
+ TProbe* Probe;
+
+ public:
+ explicit TStaticBox(TProbe* probe)
+ : IBox(false)
+ , Probe(probe)
+ {
+ }
+
+ TProbe* GetProbe() override {
+ return Probe;
+ }
+ };
+
+ // Just a set of unique probes
+ // TODO[serxa]: get rid of different ProbeRegistries, use unique one (singleton) with auto registration
+ class TProbeRegistry: public TNonCopyable {
+ private:
+ TMutex Mutex;
+
+ // Probe* pointer uniquely identifies a probe and boxptr actually owns TProbe object (if required)
+ using TProbes = THashMap<TProbe*, TBoxPtr>;
+ TProbes Probes;
+
+ // Probe provider-name pairs must be unique, keep track of them
+ using TIds = TSet<std::pair<TString, TString>>;
+ TIds Ids;
+
+ public:
+ // Add probes from null-terminated array of probe pointers. Probe can be added multiple times. Thread-safe.
+ // Implies probes you pass will live forever (e.g. created by LWTRACE_DEFINE_PROVIDER)
+ void AddProbesList(TProbe** reg);
+
+ // Manage probes that are created/destructed dynamically
+ void AddProbe(const TBoxPtr& box);
+ void RemoveProbe(TProbe* probe);
+
+ // Helper class to make thread-safe iteration over probes
+ class TProbesAccessor {
+ private:
+ TGuard<TMutex> Guard;
+ TProbes& Probes;
+ public:
+ explicit TProbesAccessor(TProbeRegistry* registry)
+ : Guard(registry->Mutex)
+ , Probes(registry->Probes)
+ {}
+
+ explicit TProbesAccessor(TProbeRegistry& registry)
+ : TProbesAccessor(&registry)
+ {}
+
+ auto begin() { return Probes.begin(); }
+ auto end() { return Probes.end(); }
+ };
+
+ friend class TProbesAccessor;
+
+ private:
+ void AddProbeNoLock(const TBoxPtr& box);
+ void RemoveProbeNoLock(TProbe* probe);
+ };
+
+ // Represents a compiled trace query, holds executors attached to probes
+ class TSession: public TNonCopyable {
+ public:
+ typedef THashMap<TString, TAtomicBase> TTraceVariables;
+
+ private:
+ const TInstant StartTime;
+ const ui64 TraceIdx;
+ TProbeRegistry& Registry;
+ TDuration StoreDuration;
+ TDuration ReadDuration;
+ TCyclicLog CyclicLog;
+ TDurationLog DurationLog;
+ TCyclicDepot CyclicDepot;
+ TDurationDepot DurationDepot;
+ TAtomic LastTrackId;
+ TAtomic LastSpanId;
+ typedef TVector<std::pair<TProbe*, IExecutor*>> TProbes;
+ TProbes Probes;
+ bool Attached;
+ NLWTrace::TQuery Query;
+ TTraceVariables TraceVariables;
+ TTraceResources TraceResources;
+ void InsertExecutor(TTraceVariables& traceVariables,
+ size_t bi, const NLWTrace::TPredicate* pred,
+ const google::protobuf::RepeatedPtrField<NLWTrace::TAction>& actions,
+ TProbe* probe, const bool destructiveActionsAllowed,
+ const TCustomActionFactory& customActionFactory);
+
+ private:
+ void Destroy();
+
+ public:
+ TSession(ui64 traceIdx,
+ TProbeRegistry& registry,
+ const NLWTrace::TQuery& query,
+ const bool destructiveActionsAllowed,
+ const TCustomActionFactory& customActionFactory);
+ ~TSession();
+ void Detach();
+ size_t GetEventsCount() const;
+ size_t GetThreadsCount() const;
+ const NLWTrace::TQuery& GetQuery() const {
+ return Query;
+ }
+ TInstant GetStartTime() const {
+ return StartTime;
+ }
+ ui64 GetTraceIdx() const {
+ return TraceIdx;
+ }
+ TTraceResources& Resources() {
+ return TraceResources;
+ }
+ const TTraceResources& Resources() const {
+ return TraceResources;
+ }
+
+ template <class TReader>
+ void ReadThreads(TReader& r) const {
+ CyclicLog.ReadThreads(r);
+ DurationLog.ReadThreads(r);
+ }
+
+ template <class TReader>
+ void ReadItems(TReader& r) const {
+ CyclicLog.ReadItems(r);
+ DurationLog.ReadItems(GetCycleCount(), DurationToCycles(ReadDuration), r);
+ }
+
+ template <class TReader>
+ void ReadItems(ui64 now, ui64 duration, TReader& r) const {
+ CyclicLog.ReadItems(r);
+ DurationLog.ReadItems(now, duration, r);
+ }
+
+ template <class TReader>
+ void ReadDepotThreads(TReader& r) const {
+ CyclicDepot.ReadThreads(r);
+ DurationDepot.ReadThreads(r);
+ }
+
+ template <class TReader>
+ void ReadDepotItems(TReader& r) const {
+ CyclicDepot.ReadItems(r);
+ DurationDepot.ReadItems(GetCycleCount(), DurationToCycles(ReadDuration), r);
+ }
+
+ template <class TReader>
+ void ReadDepotItems(ui64 now, ui64 duration, TReader& r) const {
+ CyclicDepot.ReadItems(r);
+ DurationDepot.ReadItems(now, duration, r);
+ }
+ void ToProtobuf(TLogPb& pb) const;
+ };
+
+ // Deserialization result.
+ // Either IsSuccess is true or FailedEventNames contains event names
+ // we were not able to deserialize.
+ struct TTraceDeserializeStatus
+ {
+ bool IsSuccess = true;
+ TVector<TString> FailedEventNames;
+
+ void AddFailedEventName(const TString& name)
+ {
+ IsSuccess = false;
+ FailedEventNames.emplace_back(name);
+ }
+ };
+
+ // Just a registry of all active trace queries
+ // Facade for all interactions with probes/traces
+ class TManager: public TNonCopyable {
+ private:
+ TProbeRegistry& Registry;
+ TMutex Mtx;
+ ui64 LastTraceIdx = 1;
+ typedef THashMap<TString, TSession*> TTraces; // traceId -> TSession
+ TTraces Traces;
+ bool DestructiveActionsAllowed;
+ TCustomActionFactory CustomActionFactory;
+ THolder<TRunLogShuttleActionExecutor<TCyclicDepot>> SerializingExecutor;
+
+ public:
+ static constexpr ui64 RemoteTraceIdx = 0;
+
+ public:
+ TManager(TProbeRegistry& registry, bool allowDestructiveActions);
+ ~TManager();
+ bool HasTrace(const TString& id) const;
+ const TSession* GetTrace(const TString& id) const;
+ void New(const TString& id, const NLWTrace::TQuery& query);
+ void Delete(const TString& id);
+ void Stop(const TString& id);
+
+ template <class TReader>
+ void ReadProbes(TReader& reader) const {
+ TProbeRegistry::TProbesAccessor probes(Registry);
+ for (auto& kv : probes) {
+ TProbe* probe = kv.first;
+ reader.Push(probe);
+ }
+ }
+
+ template <class TReader>
+ void ReadTraces(TReader& reader) const {
+ TGuard<TMutex> g(Mtx);
+ for (const auto& Trace : Traces) {
+ const TString& id = Trace.first;
+ const TSession* trace = Trace.second;
+ reader.Push(id, trace);
+ }
+ }
+
+ template <class TReader>
+ void ReadLog(const TString& id, TReader& reader) {
+ TGuard<TMutex> g(Mtx);
+ TTraces::iterator it = Traces.find(id);
+ if (it == Traces.end()) {
+ ythrow yexception() << "trace id '" << id << "' is not used";
+ } else {
+ TSession* trace = it->second;
+ trace->ReadItems(reader);
+ }
+ }
+
+ template <class TReader>
+ void ReadLog(const TString& id, ui64 now, TReader& reader) {
+ TGuard<TMutex> g(Mtx);
+ TTraces::iterator it = Traces.find(id);
+ if (it == Traces.end()) {
+ ythrow yexception() << "trace id '" << id << "' is not used";
+ } else {
+ TSession* trace = it->second;
+ trace->ReadItems(now, reader);
+ }
+ }
+
+ template <class TReader>
+ void ReadDepot(const TString& id, TReader& reader) {
+ TGuard<TMutex> g(Mtx);
+ TTraces::iterator it = Traces.find(id);
+ if (it == Traces.end()) {
+ ythrow yexception() << "trace id '" << id << "' is not used";
+ } else {
+ TSession* trace = it->second;
+ trace->ReadDepotItems(reader);
+ }
+ }
+
+ template <class TReader>
+ void ReadDepot(const TString& id, ui64 now, TReader& reader) {
+ TGuard<TMutex> g(Mtx);
+ TTraces::iterator it = Traces.find(id);
+ if (it == Traces.end()) {
+ ythrow yexception() << "trace id '" << id << "' is not used";
+ } else {
+ TSession* trace = it->second;
+ trace->ReadDepotItems(now, reader);
+ }
+ }
+
+ bool GetDestructiveActionsAllowed() {
+ return DestructiveActionsAllowed;
+ }
+
+ void RegisterCustomAction(const TString& name, const TCustomActionFactory::TCallback& callback) {
+ CustomActionFactory.Register(name, callback);
+ }
+
+ template <class T>
+ void RegisterCustomAction() {
+ CustomActionFactory.Register(T::GetActionName(), [=](TProbe* probe, const TCustomAction& action, TSession* trace) {
+ return new T(probe, action, trace);
+ });
+ }
+
+ TProbeMap GetProbesMap();
+
+ void CreateTraceRequest(TTraceRequest& msg, TOrbit& orbit);
+
+ bool HandleTraceRequest(
+ const TTraceRequest& msg,
+ TOrbit& orbit);
+
+ TTraceDeserializeStatus HandleTraceResponse(
+ const TTraceResponse& msg,
+ const TProbeMap& probesMap,
+ TOrbit& orbit,
+ i64 timeOffset = 0,
+ double timeScale = 1);
+
+ void CreateTraceResponse(
+ TTraceResponse& msg,
+ TOrbit& orbit);
+
+ bool IsTraced(TOrbit& orbit) {
+ return orbit.HasShuttle(TManager::RemoteTraceIdx);
+ }
+ };
+}
diff --git a/library/cpp/lwtrace/custom_action.cpp b/library/cpp/lwtrace/custom_action.cpp
new file mode 100644
index 0000000000..a379b34ec0
--- /dev/null
+++ b/library/cpp/lwtrace/custom_action.cpp
@@ -0,0 +1,21 @@
+#include "custom_action.h"
+
+#include "control.h"
+
+using namespace NLWTrace;
+
+TCustomActionExecutor* TCustomActionFactory::Create(TProbe* probe, const TCustomAction& action, TSession* trace) const {
+ auto iter = Callbacks.find(action.GetName());
+ if (iter != Callbacks.end()) {
+ return iter->second(probe, action, trace);
+ } else {
+ return nullptr;
+ }
+}
+
+void TCustomActionFactory::Register(const TString& name, const TCustomActionFactory::TCallback& callback) {
+ if (Callbacks.contains(name)) {
+ ythrow yexception() << "duplicate custom action '" << name << "'";
+ }
+ Callbacks[name] = callback;
+}
diff --git a/library/cpp/lwtrace/custom_action.h b/library/cpp/lwtrace/custom_action.h
new file mode 100644
index 0000000000..92a3c66b84
--- /dev/null
+++ b/library/cpp/lwtrace/custom_action.h
@@ -0,0 +1,75 @@
+#pragma once
+
+#include "probe.h"
+
+#include <library/cpp/lwtrace/protos/lwtrace.pb.h>
+
+#include <util/generic/hash.h>
+
+#include <functional>
+
+namespace NLWTrace {
+ class TSession;
+
+ // Custom action can save any stuff (derived from IResource) in TSession object
+ // IMPORTANT: Derived class will be used from multiple threads! (see example3)
+ class IResource: public TAtomicRefCount<IResource> {
+ public:
+ virtual ~IResource() {
+ }
+ };
+ using TResourcePtr = TIntrusivePtr<IResource>;
+
+ // Trace resources that is used to hold/get/create any stuff
+ class TTraceResources: public THashMap<TString, TResourcePtr> {
+ public:
+ template <class T>
+ T& Get(const TString& name) {
+ auto iter = find(name);
+ if (iter == end()) {
+ iter = insert(value_type(name, TResourcePtr(new T()))).first;
+ }
+ return *static_cast<T*>(iter->second.Get());
+ }
+
+ template <class T>
+ const T* GetOrNull(const TString& name) const {
+ auto iter = find(name);
+ if (iter == end()) {
+ return nullptr;
+ }
+ return *iter->second;
+ }
+ };
+
+ // Base class of all custom actions
+ class TCustomActionExecutor: public IExecutor {
+ protected:
+ TProbe* const Probe;
+ bool Destructive;
+
+ public:
+ TCustomActionExecutor(TProbe* probe, bool destructive)
+ : IExecutor()
+ , Probe(probe)
+ , Destructive(destructive)
+ {
+ }
+
+ bool IsDestructive() {
+ return Destructive;
+ }
+ };
+
+ // Factory to produce custom action executors
+ class TCustomActionFactory {
+ public:
+ using TCallback = std::function<TCustomActionExecutor*(TProbe* probe, const TCustomAction& action, TSession* trace)>;
+ TCustomActionExecutor* Create(TProbe* probe, const TCustomAction& action, TSession* trace) const;
+ void Register(const TString& name, const TCallback& callback);
+
+ private:
+ THashMap<TString, TCallback> Callbacks;
+ };
+
+}
diff --git a/library/cpp/lwtrace/event.h b/library/cpp/lwtrace/event.h
new file mode 100644
index 0000000000..e53a620c45
--- /dev/null
+++ b/library/cpp/lwtrace/event.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "preprocessor.h"
+#include "signature.h"
+#include "param_traits.h"
+
+#include <library/cpp/lwtrace/protos/lwtrace.pb.h>
+
+namespace NLWTrace {
+ // Common class for all events
+ struct TEvent {
+ const char* Name;
+ const char* Groups[LWTRACE_MAX_GROUPS + 1];
+ TSignature Signature;
+
+ const char* GetProvider() const {
+ return Groups[0];
+ }
+
+ void ToProtobuf(TEventPb& pb) const {
+ pb.SetName(Name);
+ for (const char* const* gi = Groups; *gi != nullptr; gi++) {
+ pb.AddGroups(*gi);
+ }
+ Signature.ToProtobuf(pb);
+ }
+ };
+
+}
diff --git a/library/cpp/lwtrace/example1/example_query.tr b/library/cpp/lwtrace/example1/example_query.tr
new file mode 100644
index 0000000000..a06e2a922d
--- /dev/null
+++ b/library/cpp/lwtrace/example1/example_query.tr
@@ -0,0 +1,10 @@
+Blocks {
+ ProbeDesc {
+ Name: "IterationProbe"
+ Provider: "LWTRACE_EXAMPLE_PROVIDER"
+ }
+ Action {
+ PrintToStderrAction { }
+ }
+}
+
diff --git a/library/cpp/lwtrace/example1/lwtrace_example1.cpp b/library/cpp/lwtrace/example1/lwtrace_example1.cpp
new file mode 100644
index 0000000000..6b32c405ee
--- /dev/null
+++ b/library/cpp/lwtrace/example1/lwtrace_example1.cpp
@@ -0,0 +1,39 @@
+#include <library/cpp/lwtrace/all.h>
+
+#define LWTRACE_EXAMPLE_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \
+ PROBE(IterationProbe, GROUPS(), TYPES(i32, double), NAMES("n", "result")) \
+ /**/
+
+LWTRACE_DECLARE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER)
+LWTRACE_DEFINE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER)
+
+void InitLWTrace() {
+ NLWTrace::StartLwtraceFromEnv();
+}
+
+long double Fact(int n) {
+ if (n < 0) {
+ ythrow yexception() << "N! is undefined for negative N (" << n << ")";
+ }
+ double result = 1;
+ for (; n > 1; --n) {
+ GLOBAL_LWPROBE(LWTRACE_EXAMPLE_PROVIDER, IterationProbe, n, result);
+ result *= n;
+ }
+ return result;
+}
+
+void FactorialCalculator() {
+ i32 n;
+ Cout << "Enter a number: ";
+ TString str;
+ Cin >> n;
+ double factN = Fact(n);
+ Cout << n << "! = " << factN << Endl << Endl;
+}
+
+int main() {
+ InitLWTrace();
+ FactorialCalculator();
+ return 0;
+}
diff --git a/library/cpp/lwtrace/example1/start_with_query.sh b/library/cpp/lwtrace/example1/start_with_query.sh
new file mode 100755
index 0000000000..2b456d7be7
--- /dev/null
+++ b/library/cpp/lwtrace/example1/start_with_query.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+export LWTRACE="example_query.tr"
+./lwtrace-example1
diff --git a/library/cpp/lwtrace/example1/ya.make b/library/cpp/lwtrace/example1/ya.make
new file mode 100644
index 0000000000..5ae8c4a48e
--- /dev/null
+++ b/library/cpp/lwtrace/example1/ya.make
@@ -0,0 +1,13 @@
+PROGRAM(lwtrace-example1)
+
+OWNER(cthulhu)
+
+SRCS(
+ lwtrace_example1.cpp
+)
+
+PEERDIR(
+ library/cpp/lwtrace
+)
+
+END()
diff --git a/library/cpp/lwtrace/example2/destructive.tr b/library/cpp/lwtrace/example2/destructive.tr
new file mode 100644
index 0000000000..ad955db018
--- /dev/null
+++ b/library/cpp/lwtrace/example2/destructive.tr
@@ -0,0 +1,36 @@
+Blocks {
+ ProbeDesc { Name: "IterationProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Action {
+ SleepAction {
+ NanoSeconds: 100000000
+ }
+ }
+}
+
+Blocks {
+ ProbeDesc { Name: "AfterInputProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Action {
+ StatementAction {
+ Type: ST_MOD
+ Argument { Variable: "nMod2" }
+ Argument { Param: "n" }
+ Argument { Value: "2" }
+ }
+ }
+}
+Blocks {
+ ProbeDesc { Name: "AfterInputProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Predicate {
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "nMod2" }
+ Argument { Value: "0" }
+ }
+ }
+ Action {
+ PrintToStderrAction { }
+ }
+ Action {
+ KillAction { }
+ }
+}
diff --git a/library/cpp/lwtrace/example2/empty.tr b/library/cpp/lwtrace/example2/empty.tr
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/library/cpp/lwtrace/example2/empty.tr
diff --git a/library/cpp/lwtrace/example2/example_query.tr b/library/cpp/lwtrace/example2/example_query.tr
new file mode 100644
index 0000000000..31b5465860
--- /dev/null
+++ b/library/cpp/lwtrace/example2/example_query.tr
@@ -0,0 +1,79 @@
+Blocks {
+ ProbeDesc {
+ Name: "StartupProbe"
+ Provider: "LWTRACE_EXAMPLE_PROVIDER"
+ }
+ Action {
+ PrintToStderrAction { }
+ }
+}
+
+Blocks {
+ ProbeDesc { Name: "IterationProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Action {
+ LogAction {
+ LogTimestamp: true
+ MaxRecords: 2
+ }
+ }
+}
+
+Blocks {
+ ProbeDesc { Name: "ByrefDurationProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Action {
+ LogAction {
+ LogTimestamp: true
+ MaxRecords: 1
+ }
+ }
+ Action {
+ PrintToStderrAction { }
+ }
+}
+
+Blocks {
+ ProbeDesc { Name: "DurationProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Action {
+ LogAction {
+ LogTimestamp: true
+ MaxRecords: 1
+ }
+ }
+ Action {
+ PrintToStderrAction { }
+ }
+}
+
+Blocks {
+ ProbeDesc { Name: "ResultProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Action {
+ PrintToStderrAction { }
+ }
+ Action {
+ LogAction { LogTimestamp: true }
+ }
+}
+
+
+Blocks {
+ ProbeDesc { Name: "AfterInputProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Action {
+ StatementAction {
+ Type: ST_MOD
+ Argument { Variable: "nMod2" }
+ Argument { Param: "n" }
+ Argument { Value: "2" }
+ }
+ }
+}
+Blocks {
+ ProbeDesc { Name: "AfterInputProbe" Provider: "LWTRACE_EXAMPLE_PROVIDER" }
+ Predicate {
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "nMod2" }
+ Argument { Value: "0" }
+ }
+ }
+ Action { LogAction { } }
+}
diff --git a/library/cpp/lwtrace/example2/lwtrace_example2.cpp b/library/cpp/lwtrace/example2/lwtrace_example2.cpp
new file mode 100644
index 0000000000..7a4f7a1daf
--- /dev/null
+++ b/library/cpp/lwtrace/example2/lwtrace_example2.cpp
@@ -0,0 +1,117 @@
+#include <library/cpp/lwtrace/control.h>
+#include <library/cpp/lwtrace/all.h>
+
+#include <library/cpp/getopt/last_getopt.h>
+#include <google/protobuf/text_format.h>
+#include <util/stream/file.h>
+
+#define LWTRACE_EXAMPLE_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \
+ PROBE(StartupProbe, GROUPS(), TYPES(), NAMES()) \
+ PROBE(IterationProbe, GROUPS(), TYPES(i64, double), NAMES("n", "result")) \
+ PROBE(DurationProbe, GROUPS(), TYPES(ui64, i64, double), NAMES("duration", "n", "result")) \
+ PROBE(ResultProbe, GROUPS(), TYPES(double), NAMES("factN")) \
+ PROBE(AfterInputProbe, GROUPS(), TYPES(i32), NAMES("n")) \
+ /**/
+
+LWTRACE_DECLARE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER)
+LWTRACE_DEFINE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER)
+
+THolder<NLWTrace::TManager> traceManager;
+
+struct TConfig {
+ bool UnsafeLWTrace;
+ TString TraceRequestPath;
+};
+
+void InitLWTrace(TConfig& cfg) {
+ traceManager.Reset(new NLWTrace::TManager(*Singleton<NLWTrace::TProbeRegistry>(), cfg.UnsafeLWTrace));
+}
+
+void AddLWTraceRequest(TConfig& cfg) {
+ TString queryStr = TUnbufferedFileInput(cfg.TraceRequestPath).ReadAll();
+ NLWTrace::TQuery query;
+ google::protobuf::TextFormat::ParseFromString(queryStr, &query);
+ traceManager->New("TraceRequest1", query);
+}
+
+class TLogReader {
+public:
+ void Push(TThread::TId tid, const NLWTrace::TCyclicLog::TItem& item) {
+ Cout << "tid=" << tid << " probe=" << item.Probe->Event.Name;
+ if (item.Timestamp != TInstant::Zero()) {
+ Cout << " time=" << item.Timestamp;
+ }
+ if (item.SavedParamsCount > 0) {
+ TString paramValues[LWTRACE_MAX_PARAMS];
+ item.Probe->Event.Signature.SerializeParams(item.Params, paramValues);
+ Cout << " params: ";
+ for (size_t i = 0; i < item.SavedParamsCount; ++i) {
+ Cout << " " << item.Probe->Event.Signature.ParamNames[i] << "=" << paramValues[i];
+ }
+ }
+ Cout << Endl;
+ }
+};
+
+void DisplayLWTraceLog() {
+ Cout << "LWTrace log:" << Endl;
+ TLogReader reader;
+ traceManager->ReadLog("TraceRequest1", reader);
+}
+
+long double Fact(i64 n) {
+ if (n < 0) {
+ ythrow yexception() << "N! is undefined for negative N (" << n << ")";
+ }
+ double result = 1;
+ for (; n > 1; --n) {
+ GLOBAL_LWPROBE(LWTRACE_EXAMPLE_PROVIDER, IterationProbe, n, result);
+ GLOBAL_LWPROBE_DURATION(LWTRACE_EXAMPLE_PROVIDER, DurationProbe, n, result);
+
+ result *= n;
+ }
+ return result;
+}
+
+void FactorialCalculator() {
+ GLOBAL_LWPROBE(LWTRACE_EXAMPLE_PROVIDER, StartupProbe);
+
+ i32 n;
+ Cout << "Enter a number: ";
+ TString str;
+ Cin >> n;
+
+ GLOBAL_LWPROBE(LWTRACE_EXAMPLE_PROVIDER, AfterInputProbe, n);
+
+ double factN = Fact(n);
+ Cout << n << "! = " << factN << Endl << Endl;
+
+ GLOBAL_LWPROBE(LWTRACE_EXAMPLE_PROVIDER, ResultProbe, factN);
+}
+
+int main(int argc, char** argv) {
+ TConfig cfg;
+ using namespace NLastGetopt;
+ TOpts opts = NLastGetopt::TOpts::Default();
+ opts.AddLongOption('u', "unsafe-lwtrace",
+ "allow destructive LWTrace actions")
+ .OptionalValue(ToString(true))
+ .DefaultValue(ToString(false))
+ .StoreResult(&cfg.UnsafeLWTrace);
+ opts.AddLongOption('f', "trace-request",
+ "specify a file containing LWTrace request")
+ .DefaultValue("example_query.tr")
+ .StoreResult(&cfg.TraceRequestPath);
+ opts.AddHelpOption('h');
+ TOptsParseResult res(&opts, argc, argv);
+
+ InitLWTrace(cfg);
+
+ AddLWTraceRequest(cfg);
+
+ FactorialCalculator();
+
+ DisplayLWTraceLog();
+
+ return 0;
+}
diff --git a/library/cpp/lwtrace/example2/ya.make b/library/cpp/lwtrace/example2/ya.make
new file mode 100644
index 0000000000..22e34239c8
--- /dev/null
+++ b/library/cpp/lwtrace/example2/ya.make
@@ -0,0 +1,14 @@
+PROGRAM(lwtrace-example2)
+
+OWNER(cthulhu)
+
+SRCS(
+ lwtrace_example2.cpp
+)
+
+PEERDIR(
+ library/cpp/lwtrace
+ library/cpp/getopt
+)
+
+END()
diff --git a/library/cpp/lwtrace/example3/example_query.tr b/library/cpp/lwtrace/example3/example_query.tr
new file mode 100644
index 0000000000..1f841b0932
--- /dev/null
+++ b/library/cpp/lwtrace/example3/example_query.tr
@@ -0,0 +1,13 @@
+Blocks {
+ ProbeDesc {
+ Name: "IterationProbe"
+ Provider: "LWTRACE_EXAMPLE_PROVIDER"
+ }
+ Action {
+ CustomAction {
+ Name: "MyAction"
+ Opts: "/dev/stdout"
+ }
+ }
+}
+
diff --git a/library/cpp/lwtrace/example3/lwtrace_example3.cpp b/library/cpp/lwtrace/example3/lwtrace_example3.cpp
new file mode 100644
index 0000000000..4493dc0077
--- /dev/null
+++ b/library/cpp/lwtrace/example3/lwtrace_example3.cpp
@@ -0,0 +1,43 @@
+#include <library/cpp/lwtrace/all.h>
+#include <google/protobuf/text_format.h>
+#include "my_action.h"
+
+#define LWTRACE_EXAMPLE_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \
+ PROBE(IterationProbe, GROUPS(), TYPES(i32, double), NAMES("n", "result")) \
+ /**/
+
+LWTRACE_DECLARE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER)
+LWTRACE_DEFINE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER)
+
+void InitLWTrace() {
+ NLWTrace::StartLwtraceFromEnv([=](NLWTrace::TManager& mngr) {
+ mngr.RegisterCustomAction<TMyActionExecutor>();
+ });
+}
+
+long double Fact(int n) {
+ if (n < 0) {
+ ythrow yexception() << "N! is undefined for negative N (" << n << ")";
+ }
+ double result = 1;
+ for (; n > 1; --n) {
+ GLOBAL_LWPROBE(LWTRACE_EXAMPLE_PROVIDER, IterationProbe, n, result);
+ result *= n;
+ }
+ return result;
+}
+
+void FactorialCalculator() {
+ i32 n;
+ Cout << "Enter a number: ";
+ TString str;
+ Cin >> n;
+ double factN = Fact(n);
+ Cout << n << "! = " << factN << Endl << Endl;
+}
+
+int main() {
+ InitLWTrace();
+ FactorialCalculator();
+ return 0;
+}
diff --git a/library/cpp/lwtrace/example3/my_action.h b/library/cpp/lwtrace/example3/my_action.h
new file mode 100644
index 0000000000..9a04293ba2
--- /dev/null
+++ b/library/cpp/lwtrace/example3/my_action.h
@@ -0,0 +1,85 @@
+#pragma once
+
+#include <library/cpp/lwtrace/all.h>
+#include <util/stream/file.h>
+
+// Example of custom state for custom executors
+// Holds file for output from TMyActionExecutor
+class TMyFile: public NLWTrace::IResource {
+private:
+ TMutex Mutex;
+ THolder<TUnbufferedFileOutput> File;
+
+public:
+ // Note that this class must have default ctor (it's declared here just for clearness)
+ TMyFile() {
+ }
+
+ // Note that dtor will be called by TManager::Delete() after detachment and destruction of all executors
+ ~TMyFile() {
+ }
+
+ // Some kind of state initialization
+ // Can be called only from executor constructor, and should not be thread-safe
+ void Open(const TString& path) {
+ if (File) {
+ // We must avoid double open because each executor will call Open() on the same object
+ // if the same file was specified in Opts
+ return;
+ }
+ File.Reset(new TUnbufferedFileOutput(path));
+ }
+
+ // Outputs a line to opened file
+ // Can be called from DoExecute() and must be thread-safe
+ void Output(const TString& line) {
+ Y_VERIFY(File);
+ TGuard<TMutex> g(Mutex); // Because DoExecute() call can come from any thread
+ *File << line << Endl;
+ }
+};
+
+// Action that prints events to specified file
+class TMyActionExecutor: public NLWTrace::TCustomActionExecutor {
+private:
+ TMyFile& File;
+
+public:
+ TMyActionExecutor(NLWTrace::TProbe* probe, const NLWTrace::TCustomAction& action, NLWTrace::TSession* session)
+ : NLWTrace::TCustomActionExecutor(probe, false /* not destructive */)
+ , File(session->Resources().Get<TMyFile>("FileHolder/" + action.GetOpts(0))) // unique state id must include your d
+ {
+ if (action.GetOpts().size() != 1) {
+ yexception() << "wrong number of Opts in MyAction";
+ }
+ File.Open(action.GetOpts(0));
+ }
+
+ static const char* GetActionName() {
+ static const char name[] = "MyAction";
+ return name;
+ }
+
+private:
+ virtual bool DoExecute(NLWTrace::TOrbit&, const NLWTrace::TParams& params) {
+ // Serialize param values to strings
+ TString paramValues[LWTRACE_MAX_PARAMS];
+ Probe->Event.Signature.SerializeParams(params, paramValues);
+
+ // Generate output line
+ TStringStream ss;
+ ss << "TMyActionExecutor>>> ";
+ ss << Probe->Event.Name;
+ for (ui32 i = 0; i < Probe->Event.Signature.ParamCount; ++i) {
+ ss << " " << Probe->Event.Signature.ParamNames[i] << "=" << paramValues[i];
+ }
+
+ // Write line to file
+ File.Output(ss.Str());
+
+ // Executors can chain if you specify multiple actions in one block (in trace query).
+ // So return true to continue execution of actions for given trace query block (on current triggered event)
+ // or return false if this action is the last for this block
+ return true;
+ }
+};
diff --git a/library/cpp/lwtrace/example3/start_with_query.sh b/library/cpp/lwtrace/example3/start_with_query.sh
new file mode 100755
index 0000000000..5cd221856f
--- /dev/null
+++ b/library/cpp/lwtrace/example3/start_with_query.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+echo "Executing program with following trace query:"
+cat example_query.tr
+echo -n "Press any key to start program"
+read
+LWTRACE="example_query.tr" ./lwtrace-example3
diff --git a/library/cpp/lwtrace/example3/ya.make b/library/cpp/lwtrace/example3/ya.make
new file mode 100644
index 0000000000..c5b31586e9
--- /dev/null
+++ b/library/cpp/lwtrace/example3/ya.make
@@ -0,0 +1,13 @@
+PROGRAM(lwtrace-example3)
+
+OWNER(serxa)
+
+SRCS(
+ lwtrace_example3.cpp
+)
+
+PEERDIR(
+ library/cpp/lwtrace
+)
+
+END()
diff --git a/library/cpp/lwtrace/example4/example_query.tr b/library/cpp/lwtrace/example4/example_query.tr
new file mode 100644
index 0000000000..46cd25ce91
--- /dev/null
+++ b/library/cpp/lwtrace/example4/example_query.tr
@@ -0,0 +1,10 @@
+Blocks {
+ ProbeDesc {
+ Name: "BackTrack"
+ Provider: "LWTRACE_EXAMPLE_PROVIDER"
+ }
+ Action {
+ PrintToStderrAction { }
+ }
+}
+
diff --git a/library/cpp/lwtrace/example4/lwtrace_example4.cpp b/library/cpp/lwtrace/example4/lwtrace_example4.cpp
new file mode 100644
index 0000000000..7b55a07c75
--- /dev/null
+++ b/library/cpp/lwtrace/example4/lwtrace_example4.cpp
@@ -0,0 +1,49 @@
+#include <library/cpp/lwtrace/all.h>
+
+#define LWTRACE_EXAMPLE_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \
+ PROBE(BackTrack, GROUPS(), TYPES(NLWTrace::TSymbol), NAMES("frame")) \
+ /**/
+
+LWTRACE_DECLARE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER)
+LWTRACE_DEFINE_PROVIDER(LWTRACE_EXAMPLE_PROVIDER)
+
+LWTRACE_USING(LWTRACE_EXAMPLE_PROVIDER);
+
+#define MY_BACKTRACK() LWPROBE(BackTrack, LWTRACE_LOCATION_SYMBOL)
+
+void InitLWTrace() {
+ NLWTrace::StartLwtraceFromEnv();
+}
+
+long double Fact(int n) {
+ MY_BACKTRACK();
+ if (n < 0) {
+ MY_BACKTRACK();
+ ythrow yexception() << "N! is undefined for negative N (" << n << ")";
+ }
+ double result = 1;
+ for (; n > 1; --n) {
+ MY_BACKTRACK();
+ result *= n;
+ }
+ MY_BACKTRACK();
+ return result;
+}
+
+void FactorialCalculator() {
+ MY_BACKTRACK();
+ i32 n;
+ Cout << "Enter a number: ";
+ TString str;
+ Cin >> n;
+ double factN = Fact(n);
+ Cout << n << "! = " << factN << Endl << Endl;
+}
+
+int main() {
+ InitLWTrace();
+ MY_BACKTRACK();
+ FactorialCalculator();
+ MY_BACKTRACK();
+ return 0;
+}
diff --git a/library/cpp/lwtrace/example4/start_with_query.sh b/library/cpp/lwtrace/example4/start_with_query.sh
new file mode 100755
index 0000000000..5bc195c1ae
--- /dev/null
+++ b/library/cpp/lwtrace/example4/start_with_query.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+export LWTRACE="example_query.tr"
+./lwtrace-example4
diff --git a/library/cpp/lwtrace/example4/ya.make b/library/cpp/lwtrace/example4/ya.make
new file mode 100644
index 0000000000..a3004340a8
--- /dev/null
+++ b/library/cpp/lwtrace/example4/ya.make
@@ -0,0 +1,13 @@
+PROGRAM(lwtrace-example4)
+
+OWNER(serxa)
+
+SRCS(
+ lwtrace_example4.cpp
+)
+
+PEERDIR(
+ library/cpp/lwtrace
+)
+
+END()
diff --git a/library/cpp/lwtrace/example5/example_query.tr b/library/cpp/lwtrace/example5/example_query.tr
new file mode 100644
index 0000000000..90887d4ddf
--- /dev/null
+++ b/library/cpp/lwtrace/example5/example_query.tr
@@ -0,0 +1,9 @@
+Blocks {
+ ProbeDesc {
+ Group: "LWTRACE_EXAMPLE_PROVIDER"
+ }
+ Action {
+ PrintToStderrAction { }
+ }
+}
+
diff --git a/library/cpp/lwtrace/example5/lwtrace_example5.cpp b/library/cpp/lwtrace/example5/lwtrace_example5.cpp
new file mode 100644
index 0000000000..1c324473c2
--- /dev/null
+++ b/library/cpp/lwtrace/example5/lwtrace_example5.cpp
@@ -0,0 +1,30 @@
+#include <library/cpp/lwtrace/all.h>
+#include <library/cpp/lwtrace/lwprobe.h>
+
+template <ui64 N>
+ui64 Fact() {
+ ui64 result = N * Fact<N - 1>();
+
+#ifndef LWTRACE_DISABLE
+ // Note that probe is create on the first pass
+ // LWTRACE_DECLARE_PROVIDER and LWTRACE_DEFINE_PROVIDER are not needed
+ // (Provider is created implicitly)
+ static NLWTrace::TLWProbe<ui64> factProbe(
+ "LWTRACE_EXAMPLE_PROVIDER", "FactProbe_" + ToString(N), {}, {"result"});
+
+ LWPROBE_OBJ(factProbe, result);
+#endif // LWTRACE_DISABLE
+ return result;
+}
+
+template <>
+ui64 Fact<0>() {
+ return 1;
+}
+
+int main() {
+ Fact<6>(); // First run is required to create probes we can use later in trace query
+ NLWTrace::StartLwtraceFromEnv(); // parse trace query and create trace session
+ Cout << Fact<6>() << Endl; // actually trigger probes
+ return 0;
+}
diff --git a/library/cpp/lwtrace/example5/start_with_query.sh b/library/cpp/lwtrace/example5/start_with_query.sh
new file mode 100755
index 0000000000..4df5e4e47c
--- /dev/null
+++ b/library/cpp/lwtrace/example5/start_with_query.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+export LWTRACE="example_query.tr"
+./lwtrace-example5
diff --git a/library/cpp/lwtrace/example5/ya.make b/library/cpp/lwtrace/example5/ya.make
new file mode 100644
index 0000000000..06dd4dc569
--- /dev/null
+++ b/library/cpp/lwtrace/example5/ya.make
@@ -0,0 +1,13 @@
+PROGRAM(lwtrace-example5)
+
+OWNER(serxa)
+
+SRCS(
+ lwtrace_example5.cpp
+)
+
+PEERDIR(
+ library/cpp/lwtrace
+)
+
+END()
diff --git a/library/cpp/lwtrace/kill_action.cpp b/library/cpp/lwtrace/kill_action.cpp
new file mode 100644
index 0000000000..2b74dc4587
--- /dev/null
+++ b/library/cpp/lwtrace/kill_action.cpp
@@ -0,0 +1,21 @@
+#include "kill_action.h"
+
+#ifndef _win_
+#include <sys/types.h>
+#include <signal.h>
+#endif
+
+#include <stdlib.h>
+
+using namespace NLWTrace;
+using namespace NLWTrace::NPrivate;
+
+bool TKillActionExecutor::DoExecute(TOrbit&, const TParams&) {
+#ifdef _win_
+ abort();
+#else
+ int r = kill(getpid(), SIGABRT);
+ Y_VERIFY(r == 0, "kill failed");
+ return true;
+#endif
+}
diff --git a/library/cpp/lwtrace/kill_action.h b/library/cpp/lwtrace/kill_action.h
new file mode 100644
index 0000000000..14da9ffd50
--- /dev/null
+++ b/library/cpp/lwtrace/kill_action.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "probe.h"
+
+namespace NLWTrace {
+ namespace NPrivate {
+ class TKillActionExecutor: public IExecutor {
+ public:
+ explicit TKillActionExecutor(const TProbe*) {
+ }
+ bool DoExecute(TOrbit& orbit, const TParams& params) override;
+ };
+
+ }
+}
diff --git a/library/cpp/lwtrace/log.h b/library/cpp/lwtrace/log.h
new file mode 100644
index 0000000000..56981a97f8
--- /dev/null
+++ b/library/cpp/lwtrace/log.h
@@ -0,0 +1,906 @@
+#pragma once
+
+#include "probe.h"
+
+#include <util/datetime/base.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/deque.h>
+#include <util/generic/noncopyable.h>
+#include <util/generic/vector.h>
+#include <util/string/printf.h>
+#include <util/system/atomic.h>
+#include <util/system/hp_timer.h>
+#include <util/system/mutex.h>
+#include <util/system/spinlock.h>
+#include <util/system/thread.h>
+#include <util/system/tls.h>
+
+namespace NLWTrace {
+ // Cyclic buffer that pushes items to its back and pop item from front on overflow
+ template <class TItem>
+ class TCyclicBuffer: public TNonCopyable {
+ private:
+ TVector<TItem> Data;
+ TItem* Front; // Points to the first item (valid iff Size > 0)
+ TItem* Back; // Points to the last item (valid iff Size > 0)
+ size_t Size; // Number of items in the buffer
+
+ TItem* First() {
+ return &*Data.begin();
+ }
+
+ TItem* Last() {
+ return &*Data.end();
+ }
+
+ const TItem* First() const {
+ return &*Data.begin();
+ }
+
+ const TItem* Last() const {
+ return &*Data.end();
+ }
+
+ public:
+ explicit TCyclicBuffer(size_t capacity)
+ : Data(capacity)
+ , Size(0)
+ {
+ }
+
+ TItem* Add() {
+ if (Size != 0) {
+ Inc(Back);
+ if (Back == Front) {
+ Inc(Front); // Forget (pop_front) old items
+ } else {
+ Size++;
+ }
+ } else {
+ Front = Back = First();
+ Size = 1;
+ }
+ Back->Clear();
+ return Back;
+ }
+
+ TItem* GetFront() {
+ return Front;
+ }
+
+ TItem* GetBack() {
+ return Back;
+ }
+
+ const TItem* GetFront() const {
+ return Front;
+ }
+
+ const TItem* GetBack() const {
+ return Back;
+ }
+
+ size_t GetSize() const {
+ return Size;
+ }
+
+ bool IsFull() const {
+ return Size == Data.size();
+ }
+
+ void Inc(TItem*& it) {
+ it++;
+ if (it == Last()) {
+ it = First();
+ }
+ }
+
+ void Inc(const TItem*& it) const {
+ it++;
+ if (it == Last()) {
+ it = First();
+ }
+ }
+
+ void Destroy() {
+ Data.clear();
+ Size = 0;
+ }
+
+ void Clear() {
+ Size = 0;
+ }
+
+ void Swap(TCyclicBuffer& other) {
+ Data.swap(other.Data);
+ std::swap(Front, other.Front);
+ std::swap(Back, other.Back);
+ std::swap(Size, other.Size);
+ }
+ };
+
+ // Buffer that pushes items to its back and pop item from front on expire
+ template <class TItem>
+ class TDurationBuffer: public TNonCopyable {
+ protected:
+ TDeque<TItem> Data;
+ ui64 StoreDuration;
+ ui8 CleanupCounter = 0;
+
+ public:
+ explicit TDurationBuffer(TDuration duration)
+ : StoreDuration(DurationToCycles(duration))
+ {
+ }
+
+ TItem* Add() {
+ if (!CleanupCounter) {
+ Cleanup();
+ CleanupCounter = 128; // Make cleanup after every 128 additions
+ }
+ CleanupCounter--;
+ Data.emplace_back();
+ return &Data.back();
+ }
+
+ TItem* GetFront() {
+ return &Data.front();
+ }
+
+ TItem* GetBack() {
+ return &Data.back();
+ }
+
+ const TItem* GetFront() const {
+ return &Data.front();
+ }
+
+ const TItem* GetBack() const {
+ return &Data.back();
+ }
+
+ size_t GetSize() const {
+ return Data.size();
+ }
+
+ bool Empty() const {
+ return Data.empty();
+ }
+
+ void Destroy() {
+ Data.clear();
+ }
+
+ void Swap(TDurationBuffer& other) {
+ Data.swap(other.Data);
+ std::swap(StoreDuration, other.StoreDuration);
+ }
+
+ private:
+ void Cleanup() {
+ ui64 cutoff = GetCycleCount();
+ if (cutoff > StoreDuration) {
+ cutoff -= StoreDuration;
+ while (!Data.empty() && Data.front().GetTimestampCycles() < cutoff) {
+ Data.pop_front();
+ }
+ }
+ }
+ };
+
+ struct TLogItem {
+ TProbe* Probe = nullptr;
+ TParams Params;
+ size_t SavedParamsCount;
+ TInstant Timestamp;
+ ui64 TimestampCycles;
+
+ TLogItem() {
+ }
+
+ TLogItem(const TLogItem& other)
+ : Probe(other.Probe)
+ , SavedParamsCount(other.SavedParamsCount)
+ , Timestamp(other.Timestamp)
+ , TimestampCycles(other.TimestampCycles)
+ {
+ Clone(other);
+ }
+
+ ~TLogItem() {
+ Destroy();
+ }
+
+ TLogItem& operator=(const TLogItem& other) {
+ Destroy();
+ Probe = other.Probe;
+ SavedParamsCount = other.SavedParamsCount;
+ Timestamp = other.Timestamp;
+ TimestampCycles = other.TimestampCycles;
+ Clone(other);
+ return *this;
+ }
+
+ void Clear() {
+ Destroy();
+ Probe = nullptr;
+ }
+
+ void ToProtobuf(TLogItemPb& pb) const {
+ pb.SetName(Probe->Event.Name);
+ pb.SetProvider(Probe->Event.GetProvider());
+ if (SavedParamsCount > 0) {
+ TString paramValues[LWTRACE_MAX_PARAMS];
+ Probe->Event.Signature.SerializeParams(Params, paramValues);
+ for (size_t pi = 0; pi < SavedParamsCount; pi++) {
+ pb.AddParams(paramValues[pi]);
+ }
+ }
+ pb.SetTimestamp(Timestamp.GetValue());
+ pb.SetTimestampCycles(TimestampCycles);
+ }
+
+ TTypedParam GetParam(const TString& param) const {
+ if (SavedParamsCount == 0) {
+ return TTypedParam();
+ } else {
+ size_t idx = Probe->Event.Signature.FindParamIndex(param);
+ if (idx >= SavedParamsCount) { // Also covers idx=-1 case (not found)
+ return TTypedParam();
+ } else {
+ EParamTypePb type = ParamTypeToProtobuf(Probe->Event.Signature.ParamTypes[idx]);
+ return TTypedParam(type, Params.Param[idx]);
+ }
+ }
+ }
+
+ ui64 GetTimestampCycles() const {
+ return TimestampCycles;
+ }
+
+ private:
+ void Clone(const TLogItem& other) {
+ if (Probe && SavedParamsCount > 0) {
+ Probe->Event.Signature.CloneParams(Params, other.Params);
+ }
+ }
+
+ void Destroy() {
+ if (Probe && SavedParamsCount > 0) {
+ Probe->Event.Signature.DestroyParams(Params);
+ }
+ }
+ };
+
+ struct TTrackLog {
+ struct TItem : TLogItem {
+ TThread::TId ThreadId;
+
+ TItem() = default;
+
+ TItem(TThread::TId tid, const TLogItem& item)
+ : TLogItem(item)
+ , ThreadId(tid)
+ {
+ }
+ };
+
+ using TItems = TVector<TItem>;
+ TItems Items;
+ bool Truncated = false;
+ ui64 Id = 0;
+
+ void Clear() {
+ Items.clear();
+ Truncated = false;
+ }
+
+ ui64 GetTimestampCycles() const {
+ return Items.empty() ? 0 : Items.front().GetTimestampCycles();
+ }
+ };
+
+ // Log that uses per-thread cyclic buffers to store items
+ template <class T>
+ class TCyclicLogImpl: public TNonCopyable {
+ public:
+ using TLog = TCyclicLogImpl;
+ using TItem = T;
+
+ private:
+ using TBuffer = TCyclicBuffer<TItem>;
+
+ class TStorage {
+ private:
+ // Data that can be accessed in lock-free way from reader/writer
+ TAtomic Writers = 0;
+ mutable TBuffer* volatile CurBuffer = nullptr;
+
+ // Data that can be accessed only from reader
+ // NOTE: multiple readers are serialized by TCyclicLogImpl::Lock
+ mutable TBuffer* OldBuffer = nullptr;
+ mutable TBuffer* NewBuffer = nullptr;
+
+ TLog* volatile Log = nullptr;
+
+ TThread::TId ThreadId = 0;
+ TAtomic EventsCount = 0;
+
+ public:
+ TStorage() {
+ }
+
+ explicit TStorage(TLog* log)
+ : CurBuffer(new TBuffer(log->GetCapacity()))
+ , OldBuffer(new TBuffer(log->GetCapacity()))
+ , NewBuffer(new TBuffer(log->GetCapacity()))
+ , Log(log)
+ , ThreadId(TThread::CurrentThreadId())
+ {
+ Log->RegisterThread(this);
+ }
+
+ ~TStorage() {
+ if (TLog* log = AtomicSwap(&Log, nullptr)) {
+ AtomicBarrier(); // Serialize `Log' and TCyclicLogImpl::Lock memory order
+ // NOTE: the following function swaps `this' with `new TStorage()'
+ log->UnregisterThreadAndMakeOrphan(this);
+ } else {
+ // NOTE: `Log' can be nullptr if either it is orphan storage or TryDismiss() succeeded
+ // NOTE: in both cases it is ok to call these deletes
+ delete CurBuffer;
+ delete OldBuffer;
+ delete NewBuffer;
+ }
+ }
+
+ bool TryDismiss() {
+ // TCyclicLogImpl::Lock implied (no readers)
+ if (TLog* log = AtomicSwap(&Log, nullptr)) {
+ TBuffer* curBuffer = AtomicSwap(&CurBuffer, nullptr);
+ WaitForWriters();
+ // At this point we guarantee that there is no and wont be active writer
+ delete curBuffer;
+ delete OldBuffer;
+ delete NewBuffer;
+ OldBuffer = nullptr;
+ NewBuffer = nullptr;
+ return true;
+ } else {
+ // ~TStorage() is in progress
+ return false;
+ }
+ }
+
+ void WaitForWriters() const {
+ while (AtomicGet(Writers) > 0) {
+ SpinLockPause();
+ }
+ }
+
+ TThread::TId GetThreadId() const {
+ // TCyclicLogImpl::Lock implied (no readers)
+ return ThreadId;
+ }
+
+ size_t GetEventsCount() const {
+ // TCyclicLogImpl::Lock implied (no readers)
+ return AtomicGet(EventsCount);
+ }
+
+ void Swap(TStorage& other) {
+ // TCyclicLogImpl::Lock implied (no readers)
+ std::swap(CurBuffer, other.CurBuffer);
+ std::swap(OldBuffer, other.OldBuffer);
+ std::swap(NewBuffer, other.NewBuffer);
+ std::swap(Log, other.Log);
+ std::swap(ThreadId, other.ThreadId);
+ std::swap(EventsCount, other.EventsCount);
+ }
+
+ TBuffer* StartWriter() {
+ AtomicIncrement(Writers);
+ return const_cast<TBuffer*>(AtomicGet(CurBuffer));
+ }
+
+ void StopWriter() {
+ AtomicDecrement(Writers);
+ }
+
+ void IncEventsCount() {
+ AtomicIncrement(EventsCount);
+ }
+
+ template <class TReader>
+ void ReadItems(TReader& r) const {
+ // TCyclicLogImpl::Lock implied
+ NewBuffer = AtomicSwap(&CurBuffer, NewBuffer);
+ WaitForWriters();
+
+ // Merge new buffer into old buffer
+ if (NewBuffer->IsFull()) {
+ std::swap(NewBuffer, OldBuffer);
+ } else {
+ if (NewBuffer->GetSize() > 0) {
+ for (const TItem *i = NewBuffer->GetFront(), *e = NewBuffer->GetBack();; NewBuffer->Inc(i)) {
+ TItem* oldSlot = OldBuffer->Add();
+ *oldSlot = *i;
+ if (i == e) {
+ break;
+ }
+ }
+ }
+ }
+
+ NewBuffer->Clear();
+
+ // Iterate over old buffer
+ if (OldBuffer->GetSize() > 0) {
+ for (const TItem *i = OldBuffer->GetFront(), *e = OldBuffer->GetBack();; OldBuffer->Inc(i)) {
+ r.Push(ThreadId, *i);
+ if (i == e) {
+ break;
+ }
+ }
+ }
+ }
+ };
+
+ size_t Capacity;
+ Y_THREAD(TStorage)
+ PerThreadStorage;
+ TSpinLock Lock;
+ // If thread exits its storage is destroyed, so we move it into OrphanStorages before destruction
+ TVector<TAtomicSharedPtr<TStorage>> OrphanStorages;
+ typedef TVector<TStorage*> TStoragesVec;
+ TStoragesVec StoragesVec;
+ TAtomic ThreadsCount;
+
+ public:
+ explicit TCyclicLogImpl(size_t capacity)
+ : Capacity(capacity)
+ , PerThreadStorage(this)
+ , ThreadsCount(0)
+ {
+ }
+
+ ~TCyclicLogImpl() {
+ for (bool again = true; again;) {
+ TGuard<TSpinLock> g(Lock);
+ AtomicBarrier(); // Serialize `storage->Log' and Lock memory order
+ again = false;
+ while (!StoragesVec.empty()) {
+ TStorage* storage = StoragesVec.back();
+ // TStorage destructor can be called when TCyclicLogImpl is already destructed
+ // So we ensure this does not lead to problems
+ // NOTE: Y_THREAD(TStorage) destructs TStorage object for a specific thread only on that thread exit
+ // NOTE: this issue can lead to memleaks if threads never exit and many TCyclicLogImpl are created
+ if (storage->TryDismiss()) {
+ StoragesVec.pop_back();
+ } else {
+ // Rare case when another thread is running ~TStorage() -- let it finish
+ again = true;
+ SpinLockPause();
+ break;
+ }
+ }
+ }
+ }
+
+ size_t GetCapacity() const {
+ return Capacity;
+ }
+
+ size_t GetEventsCount() const {
+ size_t events = 0;
+ TGuard<TSpinLock> g(Lock);
+ for (auto i : StoragesVec) {
+ events += i->GetEventsCount();
+ }
+ for (const auto& orphanStorage : OrphanStorages) {
+ events += orphanStorage->GetEventsCount();
+ }
+ return events;
+ }
+
+ size_t GetThreadsCount() const {
+ return AtomicGet(ThreadsCount);
+ }
+
+ void RegisterThread(TStorage* storage) {
+ TGuard<TSpinLock> g(Lock);
+ StoragesVec.push_back(storage);
+ AtomicIncrement(ThreadsCount);
+ }
+
+ void UnregisterThreadAndMakeOrphan(TStorage* storage) {
+ TGuard<TSpinLock> g(Lock);
+ // `storage' writers are not possible at this scope because
+ // UnregisterThreadAndMakeOrphan is only called from exiting threads.
+ // `storage' readers are not possible at this scope due to Lock guard.
+
+ Erase(StoragesVec, storage);
+ TAtomicSharedPtr<TStorage> orphan(new TStorage());
+ orphan->Swap(*storage); // Swap is required because we cannot take ownership from Y_THREAD(TStorage) object
+ OrphanStorages.push_back(orphan);
+ }
+
+ template <class TReader>
+ void ReadThreads(TReader& r) const {
+ TGuard<TSpinLock> g(Lock);
+ for (auto i : StoragesVec) {
+ r.PushThread(i->GetThreadId());
+ }
+ for (const auto& orphanStorage : OrphanStorages) {
+ r.PushThread(orphanStorage->GetThreadId());
+ }
+ }
+
+ template <class TReader>
+ void ReadItems(TReader& r) const {
+ TGuard<TSpinLock> g(Lock);
+ for (auto i : StoragesVec) {
+ i->ReadItems(r);
+ }
+ for (const auto& orphanStorage : OrphanStorages) {
+ orphanStorage->ReadItems(r);
+ }
+ }
+
+ class TAccessor {
+ private:
+ TStorage& Storage;
+ TBuffer* Buffer;
+
+ public:
+ explicit TAccessor(TLog& log)
+ : Storage(log.PerThreadStorage.Get())
+ , Buffer(Storage.StartWriter())
+ {
+ }
+
+ ~TAccessor() {
+ Storage.StopWriter();
+ }
+
+ TItem* Add() {
+ if (Buffer) {
+ Storage.IncEventsCount();
+ return Buffer->Add();
+ } else {
+ // TStorage detached from trace due to trace destruction
+ // so we should not try log anything
+ return nullptr;
+ }
+ }
+ };
+
+ friend class TAccessor;
+ };
+
+ using TCyclicLog = TCyclicLogImpl<TLogItem>;
+ using TCyclicDepot = TCyclicLogImpl<TTrackLog>;
+
+ // Log that uses per-thread buffers to store items up to given duration
+ template <class T>
+ class TDurationLogImpl: public TNonCopyable {
+ public:
+ using TLog = TDurationLogImpl;
+ using TItem = T;
+
+ class TAccessor;
+ friend class TAccessor;
+ class TAccessor: public TGuard<TSpinLock> {
+ private:
+ TLog& Log;
+
+ public:
+ explicit TAccessor(TLog& log)
+ : TGuard<TSpinLock>(log.PerThreadStorage.Get().Lock)
+ , Log(log)
+ {
+ }
+
+ TItem* Add() {
+ return Log.PerThreadStorage.Get().Add();
+ }
+ };
+
+ private:
+ class TStorage: public TDurationBuffer<TItem> {
+ private:
+ TLog* Log;
+ TThread::TId ThreadId;
+ ui64 EventsCount;
+
+ public:
+ TSpinLock Lock;
+
+ TStorage()
+ : TDurationBuffer<TItem>(TDuration::Zero())
+ , Log(nullptr)
+ , ThreadId(0)
+ , EventsCount(0)
+ {
+ }
+
+ explicit TStorage(TLog* log)
+ : TDurationBuffer<TItem>(log->GetDuration())
+ , Log(log)
+ , ThreadId(TThread::CurrentThreadId())
+ , EventsCount(0)
+ {
+ Log->RegisterThread(this);
+ }
+
+ ~TStorage() {
+ if (Log) {
+ Log->UnregisterThread(this);
+ }
+ }
+
+ void DetachFromTraceLog() {
+ Log = nullptr;
+ }
+
+ TItem* Add() {
+ EventsCount++;
+ return TDurationBuffer<TItem>::Add();
+ }
+
+ bool Expired(ui64 now) const {
+ return this->Empty() ? true : this->GetBack()->GetTimestampCycles() + this->StoreDuration < now;
+ }
+
+ TThread::TId GetThreadId() const {
+ return ThreadId;
+ }
+
+ size_t GetEventsCount() const {
+ return EventsCount;
+ }
+
+ void Swap(TStorage& other) {
+ TDurationBuffer<TItem>::Swap(other);
+ std::swap(Log, other.Log);
+ std::swap(ThreadId, other.ThreadId);
+ std::swap(EventsCount, other.EventsCount);
+ }
+
+ template <class TReader>
+ void ReadItems(ui64 now, ui64 duration, TReader& r) const {
+ TGuard<TSpinLock> g(Lock);
+ if (now > duration) {
+ ui64 cutoff = now - duration;
+ for (const TItem& item : this->Data) {
+ if (item.GetTimestampCycles() >= cutoff) {
+ r.Push(ThreadId, item);
+ }
+ }
+ } else {
+ for (const TItem& item : this->Data) {
+ r.Push(ThreadId, item);
+ }
+ }
+ }
+ };
+
+ TDuration Duration;
+ Y_THREAD(TStorage)
+ PerThreadStorage;
+ TSpinLock Lock;
+ typedef TVector<TAtomicSharedPtr<TStorage>> TOrphanStorages;
+ TOrphanStorages OrphanStorages; // if thread exits its storage is destroyed, so we move it into OrphanStorages before destruction
+ TAtomic OrphanStoragesEventsCount = 0;
+ typedef TVector<TStorage*> TStoragesVec;
+ TStoragesVec StoragesVec;
+ TAtomic ThreadsCount;
+
+ public:
+ explicit TDurationLogImpl(TDuration duration)
+ : Duration(duration)
+ , PerThreadStorage(this)
+ , ThreadsCount(0)
+ {
+ }
+
+ ~TDurationLogImpl() {
+ for (auto storage : StoragesVec) {
+ // NOTE: Y_THREAD(TStorage) destructs TStorage object for a specific thread only on that thread exit
+ // NOTE: this issue can lead to memleaks if threads never exit and many TTraceLogs are created
+ storage->Destroy();
+
+ // TraceLogStorage destructor can be called when TTraceLog is already destructed
+ // So we ensure this does not lead to problems
+ storage->DetachFromTraceLog();
+ }
+ }
+
+ TDuration GetDuration() const {
+ return Duration;
+ }
+
+ size_t GetEventsCount() const {
+ size_t events = AtomicGet(OrphanStoragesEventsCount);
+ TGuard<TSpinLock> g(Lock);
+ for (auto i : StoragesVec) {
+ events += i->GetEventsCount();
+ }
+ return events;
+ }
+
+ size_t GetThreadsCount() const {
+ return AtomicGet(ThreadsCount);
+ }
+
+ void RegisterThread(TStorage* storage) {
+ TGuard<TSpinLock> g(Lock);
+ StoragesVec.push_back(storage);
+ AtomicIncrement(ThreadsCount);
+ }
+
+ void UnregisterThread(TStorage* storage) {
+ TGuard<TSpinLock> g(Lock);
+ for (auto i = StoragesVec.begin(), e = StoragesVec.end(); i != e; ++i) {
+ if (*i == storage) {
+ StoragesVec.erase(i);
+ break;
+ }
+ }
+ TAtomicSharedPtr<TStorage> orphan(new TStorage());
+ orphan->Swap(*storage);
+ orphan->DetachFromTraceLog();
+ AtomicAdd(OrphanStoragesEventsCount, orphan->GetEventsCount());
+ OrphanStorages.push_back(orphan);
+ CleanOrphanStorages(GetCycleCount());
+ }
+
+ void CleanOrphanStorages(ui64 now) {
+ EraseIf(OrphanStorages, [=](const TAtomicSharedPtr<TStorage>& ptr) {
+ const TStorage& storage = *ptr;
+ return storage.Expired(now);
+ });
+ }
+
+ template <class TReader>
+ void ReadThreads(TReader& r) const {
+ TGuard<TSpinLock> g(Lock);
+ for (TStorage* i : StoragesVec) {
+ r.PushThread(i->GetThreadId());
+ }
+ for (const auto& orphanStorage : OrphanStorages) {
+ r.PushThread(orphanStorage->GetThreadId());
+ }
+ }
+
+ template <class TReader>
+ void ReadItems(ui64 now, ui64 duration, TReader& r) const {
+ TGuard<TSpinLock> g(Lock);
+ for (TStorage* storage : StoragesVec) {
+ storage->ReadItems(now, duration, r);
+ }
+ for (const auto& orphanStorage : OrphanStorages) {
+ orphanStorage->ReadItems(now, duration, r);
+ }
+ }
+ };
+
+ using TDurationLog = TDurationLogImpl<TLogItem>;
+ using TDurationDepot = TDurationLogImpl<TTrackLog>;
+
+ // Log that uses one cyclic buffer to store items
+ // Each item is a result of execution of some event
+ class TInMemoryLog: public TNonCopyable {
+ public:
+ struct TItem {
+ const TEvent* Event;
+ TParams Params;
+ TInstant Timestamp;
+
+ TItem()
+ : Event(nullptr)
+ {
+ }
+
+ TItem(const TItem& other)
+ : Event(other.Event)
+ , Timestamp(other.Timestamp)
+ {
+ Clone(other);
+ }
+
+ ~TItem() {
+ Destroy();
+ }
+
+ TItem& operator=(const TItem& other) {
+ Destroy();
+ Event = other.Event;
+ Timestamp = other.Timestamp;
+ Clone(other);
+ return *this;
+ }
+
+ void Clear() {
+ Destroy();
+ Event = nullptr;
+ }
+
+ private:
+ void Clone(const TItem& other) {
+ if (Event && Event->Signature.ParamCount > 0) {
+ Event->Signature.CloneParams(Params, other.Params);
+ }
+ }
+
+ void Destroy() {
+ if (Event && Event->Signature.ParamCount > 0) {
+ Event->Signature.DestroyParams(Params);
+ }
+ }
+ };
+
+ class TAccessor;
+ friend class TAccessor;
+ class TAccessor: public TGuard<TMutex> {
+ private:
+ TInMemoryLog& Log;
+
+ public:
+ explicit TAccessor(TInMemoryLog& log)
+ : TGuard<TMutex>(log.Lock)
+ , Log(log)
+ {
+ }
+
+ TItem* Add() {
+ return Log.Storage.Add();
+ }
+ };
+
+ private:
+ TMutex Lock;
+ TCyclicBuffer<TItem> Storage;
+
+ public:
+ explicit TInMemoryLog(size_t capacity)
+ : Storage(capacity)
+ {
+ }
+
+ template <class TReader>
+ void ReadItems(TReader& r) const {
+ TGuard<TMutex> g(Lock);
+ if (Storage.GetSize() > 0) {
+ for (const TItem *i = Storage.GetFront(), *e = Storage.GetBack();; Storage.Inc(i)) {
+ r.Push(*i);
+ if (i == e) {
+ break;
+ }
+ }
+ }
+ }
+ };
+
+#ifndef LWTRACE_DISABLE
+
+ // Class representing a specific event
+ template <LWTRACE_TEMPLATE_PARAMS>
+ struct TUserEvent {
+ TEvent Event;
+
+ inline void operator()(TInMemoryLog& log, bool logTimestamp, LWTRACE_FUNCTION_PARAMS) const {
+ TInMemoryLog::TAccessor la(log);
+ if (TInMemoryLog::TItem* item = la.Add()) {
+ item->Event = &Event;
+ LWTRACE_PREPARE_PARAMS(item->Params);
+ if (logTimestamp) {
+ item->Timestamp = TInstant::Now();
+ }
+ }
+ }
+ };
+
+#endif
+
+}
diff --git a/library/cpp/lwtrace/log_shuttle.cpp b/library/cpp/lwtrace/log_shuttle.cpp
new file mode 100644
index 0000000000..695aa90b31
--- /dev/null
+++ b/library/cpp/lwtrace/log_shuttle.cpp
@@ -0,0 +1,67 @@
+#include "log_shuttle.h"
+#include "probes.h"
+
+namespace NLWTrace {
+ LWTRACE_USING(LWTRACE_INTERNAL_PROVIDER);
+
+#ifdef LWTRACE_DISABLE
+
+ template <class TDepot>
+ bool TLogShuttle<TDepot>::DoFork(TShuttlePtr& child) {
+ Y_UNUSED(child);
+ return false;
+ }
+
+ template <class TDepot>
+ bool TLogShuttle<TDepot>::DoJoin(const TShuttlePtr& child) {
+ Y_UNUSED(child);
+ return false;
+ }
+
+#else
+
+ template <class TDepot>
+ bool TLogShuttle<TDepot>::DoFork(TShuttlePtr& child) {
+ if (child = Executor->RentShuttle()) {
+ child->SetParentSpanId(GetSpanId());
+ Executor->Cast(child)->SetIgnore(true);
+ TParams params;
+ params.Param[0].CopyConstruct<ui64>(child->GetSpanId());
+ bool result = DoAddProbe(&LWTRACE_GET_NAME(Fork).Probe, params, 0);
+ TUserSignature<ui64>::DestroyParams(params);
+ return result;
+ }
+ AtomicIncrement(ForkFailed);
+ return false;
+ }
+
+ template <class TDepot>
+ bool TLogShuttle<TDepot>::DoJoin(const TShuttlePtr& shuttle) {
+ auto* child = Executor->Cast(shuttle);
+ TParams params;
+ params.Param[0].CopyConstruct<ui64>(child->GetSpanId());
+ params.Param[1].CopyConstruct<ui64>(child->TrackLog.Items.size());
+ bool result = DoAddProbe(&LWTRACE_GET_NAME(Join).Probe, params, 0);
+ TUserSignature<ui64, ui64>::DestroyParams(params);
+ if (result) {
+ with_lock (Lock) {
+ ssize_t n = MaxTrackLength - TrackLog.Items.size();
+ for (auto& item: child->TrackLog.Items) {
+ if (n-- <= 0) {
+ TrackLog.Truncated = true;
+ break;
+ }
+ TrackLog.Items.emplace_back(item);
+ }
+ }
+ }
+ AtomicAdd(ForkFailed, AtomicGet(child->ForkFailed));
+ Executor->ParkShuttle(child);
+ return result;
+ }
+
+#endif
+
+ template class TLogShuttle<TDurationDepot>;
+ template class TLogShuttle<TCyclicDepot>;
+}
diff --git a/library/cpp/lwtrace/log_shuttle.h b/library/cpp/lwtrace/log_shuttle.h
new file mode 100644
index 0000000000..729a38615f
--- /dev/null
+++ b/library/cpp/lwtrace/log_shuttle.h
@@ -0,0 +1,359 @@
+#pragma once
+
+#include "log.h"
+#include "probe.h"
+
+#include <library/cpp/lwtrace/protos/lwtrace.pb.h>
+
+#include <util/system/spinlock.h>
+
+namespace NLWTrace {
+ template <class TDepot>
+ class TRunLogShuttleActionExecutor;
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct THostTimeCalculator {
+ double K = 0;
+ ui64 B = 0;
+
+ THostTimeCalculator() {
+ TInstant now = TInstant::Now();
+ ui64 tsNow = GetCycleCount();
+ K = 1000000000 / NHPTimer::GetClockRate();
+ B = now.NanoSeconds() - K * tsNow;
+ }
+
+ ui64 CyclesToEpochNanoseconds(ui64 cycles) const {
+ return K*cycles + B;
+ }
+
+ ui64 EpochNanosecondsToCycles(ui64 ns) const {
+ return (ns - B) / K;
+ }
+ };
+
+ inline ui64 CyclesToEpochNanoseconds(ui64 cycles) {
+ return Singleton<THostTimeCalculator>()->CyclesToEpochNanoseconds(cycles);
+ }
+
+ inline ui64 EpochNanosecondsToCycles(ui64 ns) {
+ return Singleton<THostTimeCalculator>()->EpochNanosecondsToCycles(ns);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <class TDepot>
+ class TLogShuttle: public IShuttle {
+ private:
+ using TExecutor = TRunLogShuttleActionExecutor<TDepot>;
+ TTrackLog TrackLog;
+ TExecutor* Executor;
+ bool Ignore = false;
+ size_t MaxTrackLength;
+ TAdaptiveLock Lock;
+ TAtomic ForkFailed = 0;
+
+ public:
+ explicit TLogShuttle(TExecutor* executor)
+ : IShuttle(executor->GetTraceIdx(), executor->NewSpanId())
+ , Executor(executor)
+ , MaxTrackLength(Executor->GetAction().GetMaxTrackLength() ? Executor->GetAction().GetMaxTrackLength() : 100)
+ {
+ }
+
+ bool DoAddProbe(TProbe* probe, const TParams& params, ui64 timestamp) override;
+ void DoEndOfTrack() override;
+ void DoDrop() override;
+ void DoSerialize(TShuttleTrace& msg) override;
+ bool DoFork(TShuttlePtr& child) override;
+ bool DoJoin(const TShuttlePtr& child) override;
+
+ void SetIgnore(bool ignore);
+ void Clear();
+
+ const TTrackLog& GetTrackLog() const {
+ return TrackLog;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <class TDepot>
+ class TLogShuttleActionBase: public IExecutor {
+ private:
+ const ui64 TraceIdx;
+
+ public:
+ explicit TLogShuttleActionBase(ui64 traceIdx)
+ : TraceIdx(traceIdx)
+ {
+ }
+ ui64 GetTraceIdx() const {
+ return TraceIdx;
+ }
+
+ static TLogShuttle<TDepot>* Cast(const TShuttlePtr& shuttle);
+ static TLogShuttle<TDepot>* Cast(IShuttle* shuttle);
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <class TDepot>
+ class TRunLogShuttleActionExecutor: public TLogShuttleActionBase<TDepot> {
+ private:
+ TSpinLock Lock;
+ TVector<TShuttlePtr> AllShuttles;
+ TVector<TShuttlePtr> Parking;
+ TRunLogShuttleAction Action;
+ TDepot* Depot;
+
+ TAtomic MissedTracks = 0;
+ TAtomic* LastTrackId;
+ TAtomic* LastSpanId;
+
+ static constexpr int MaxShuttles = 100000;
+
+ public:
+ TRunLogShuttleActionExecutor(ui64 traceIdx, const TRunLogShuttleAction& action, TDepot* depot, TAtomic* lastTrackId, TAtomic* lastSpanId);
+ ~TRunLogShuttleActionExecutor();
+ bool DoExecute(TOrbit& orbit, const TParams& params) override;
+ void RecordShuttle(TLogShuttle<TDepot>* shuttle);
+ void ParkShuttle(TLogShuttle<TDepot>* shuttle);
+ void DiscardShuttle();
+ TShuttlePtr RentShuttle();
+ ui64 NewSpanId();
+ const TRunLogShuttleAction& GetAction() const {
+ return Action;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <class TDepot>
+ class TEditLogShuttleActionExecutor: public TLogShuttleActionBase<TDepot> {
+ private:
+ TEditLogShuttleAction Action;
+
+ public:
+ TEditLogShuttleActionExecutor(ui64 traceIdx, const TEditLogShuttleAction& action);
+ bool DoExecute(TOrbit& orbit, const TParams& params) override;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <class TDepot>
+ class TDropLogShuttleActionExecutor: public TLogShuttleActionBase<TDepot> {
+ private:
+ TDropLogShuttleAction Action;
+
+ public:
+ TDropLogShuttleActionExecutor(ui64 traceIdx, const TDropLogShuttleAction& action);
+ bool DoExecute(TOrbit& orbit, const TParams& params) override;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <class TDepot>
+ bool TLogShuttle<TDepot>::DoAddProbe(TProbe* probe, const TParams& params, ui64 timestamp) {
+ with_lock (Lock) {
+ if (TrackLog.Items.size() >= MaxTrackLength) {
+ TrackLog.Truncated = true;
+ return true;
+ }
+ TrackLog.Items.emplace_back();
+ TTrackLog::TItem* item = &TrackLog.Items.back();
+ item->ThreadId = 0; // TODO[serxa]: check if it is fast to run TThread::CurrentThreadId();
+ item->Probe = probe;
+ if ((item->SavedParamsCount = probe->Event.Signature.ParamCount) > 0) {
+ probe->Event.Signature.CloneParams(item->Params, params);
+ }
+ item->TimestampCycles = timestamp ? timestamp : GetCycleCount();
+ }
+
+ return true;
+ }
+
+ template <class TDepot>
+ void TLogShuttle<TDepot>::DoEndOfTrack() {
+ // Record track log if not ignored
+ if (!Ignore) {
+ if (AtomicGet(ForkFailed)) {
+ Executor->DiscardShuttle();
+ } else {
+ Executor->RecordShuttle(this);
+ }
+ }
+ Executor->ParkShuttle(this);
+ }
+
+ template <class TDepot>
+ void TLogShuttle<TDepot>::DoDrop() {
+ // Do not track log results of dropped shuttles
+ Executor->ParkShuttle(this);
+ }
+
+ template <class TDepot>
+ void TLogShuttle<TDepot>::SetIgnore(bool ignore) {
+ Ignore = ignore;
+ }
+
+ template <class TDepot>
+ void TLogShuttle<TDepot>::Clear() {
+ TrackLog.Clear();
+ }
+
+ template <class TDepot>
+ void TLogShuttle<TDepot>::DoSerialize(TShuttleTrace& msg)
+ {
+ with_lock (Lock)
+ {
+ if (!GetTrackLog().Items.size()) {
+ return ;
+ }
+ for (auto& record : GetTrackLog().Items) {
+ auto *rec = msg.AddEvents();
+ rec->SetName(record.Probe->Event.Name);
+ rec->SetProvider(record.Probe->Event.GetProvider());
+ rec->SetTimestampNanosec(
+ CyclesToEpochNanoseconds(record.TimestampCycles));
+ record.Probe->Event.Signature.SerializeToPb(record.Params, *rec->MutableParams());
+ }
+ }
+ }
+
+ template <class TDepot>
+ TLogShuttle<TDepot>* TLogShuttleActionBase<TDepot>::Cast(const TShuttlePtr& shuttle) {
+ return static_cast<TLogShuttle<TDepot>*>(shuttle.Get());
+ }
+
+ template <class TDepot>
+ TLogShuttle<TDepot>* TLogShuttleActionBase<TDepot>::Cast(IShuttle* shuttle) {
+ return static_cast<TLogShuttle<TDepot>*>(shuttle);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <class TDepot>
+ TRunLogShuttleActionExecutor<TDepot>::TRunLogShuttleActionExecutor(
+ ui64 traceIdx,
+ const TRunLogShuttleAction& action,
+ TDepot* depot,
+ TAtomic* lastTrackId,
+ TAtomic* lastSpanId)
+ : TLogShuttleActionBase<TDepot>(traceIdx)
+ , Action(action)
+ , Depot(depot)
+ , LastTrackId(lastTrackId)
+ , LastSpanId(lastSpanId)
+ {
+ ui64 size = Min<ui64>(Action.GetShuttlesCount() ? Action.GetShuttlesCount() : 1000, MaxShuttles); // Do not allow to allocate too much memory
+ AllShuttles.reserve(size);
+ Parking.reserve(size);
+ for (ui64 i = 0; i < size; i++) {
+ TShuttlePtr shuttle(new TLogShuttle<TDepot>(this));
+ AllShuttles.emplace_back(shuttle);
+ Parking.emplace_back(shuttle);
+ }
+ }
+
+ template <class TDepot>
+ TRunLogShuttleActionExecutor<TDepot>::~TRunLogShuttleActionExecutor() {
+ for (TShuttlePtr& shuttle : AllShuttles) {
+ shuttle->Kill();
+ }
+ }
+
+ template <class TDepot>
+ bool TRunLogShuttleActionExecutor<TDepot>::DoExecute(TOrbit& orbit, const TParams& params) {
+ Y_UNUSED(params);
+ if (TShuttlePtr shuttle = RentShuttle()) {
+ this->Cast(shuttle)->SetIgnore(Action.GetIgnore());
+ orbit.AddShuttle(shuttle);
+ } else {
+ AtomicIncrement(MissedTracks);
+ }
+ return true;
+ }
+
+ template <class TDepot>
+ void TRunLogShuttleActionExecutor<TDepot>::DiscardShuttle() {
+ AtomicIncrement(MissedTracks);
+ }
+
+ template <class TDepot>
+ void TRunLogShuttleActionExecutor<TDepot>::RecordShuttle(TLogShuttle<TDepot>* shuttle) {
+ if (Depot == nullptr) {
+ return;
+ }
+ typename TDepot::TAccessor a(*Depot);
+ if (TTrackLog* trackLog = a.Add()) {
+ *trackLog = shuttle->GetTrackLog();
+ trackLog->Id = AtomicIncrement(*LastTrackId); // Track id is assigned at reporting time
+ }
+ }
+
+ template <class TDepot>
+ TShuttlePtr TRunLogShuttleActionExecutor<TDepot>::RentShuttle() {
+ TGuard<TSpinLock> g(Lock);
+ if (Parking.empty()) {
+ return TShuttlePtr();
+ } else {
+ TShuttlePtr shuttle = Parking.back();
+ Parking.pop_back();
+ return shuttle;
+ }
+ }
+
+ template <class TDepot>
+ void TRunLogShuttleActionExecutor<TDepot>::ParkShuttle(TLogShuttle<TDepot>* shuttle) {
+ shuttle->Clear();
+ TGuard<TSpinLock> g(Lock);
+ Parking.emplace_back(shuttle);
+ }
+
+ template <class TDepot>
+ ui64 TRunLogShuttleActionExecutor<TDepot>::NewSpanId()
+ {
+ return LastSpanId ? AtomicIncrement(*LastSpanId) : 0;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <class TDepot>
+ TEditLogShuttleActionExecutor<TDepot>::TEditLogShuttleActionExecutor(ui64 traceIdx, const TEditLogShuttleAction& action)
+ : TLogShuttleActionBase<TDepot>(traceIdx)
+ , Action(action)
+ {
+ }
+
+ template <class TDepot>
+ bool TEditLogShuttleActionExecutor<TDepot>::DoExecute(TOrbit& orbit, const TParams& params) {
+ Y_UNUSED(params);
+ bool ignore = Action.GetIgnore();
+ orbit.ForEachShuttle(this->GetTraceIdx(), [=](IShuttle* shuttle) {
+ this->Cast(shuttle)->SetIgnore(ignore);
+ return true;
+ });
+ return true;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <class TDepot>
+ TDropLogShuttleActionExecutor<TDepot>::TDropLogShuttleActionExecutor(ui64 traceIdx, const TDropLogShuttleAction& action)
+ : TLogShuttleActionBase<TDepot>(traceIdx)
+ , Action(action)
+ {
+ }
+
+ template <class TDepot>
+ bool TDropLogShuttleActionExecutor<TDepot>::DoExecute(TOrbit& orbit, const TParams& params) {
+ Y_UNUSED(params);
+ orbit.ForEachShuttle(this->GetTraceIdx(), [](IShuttle*) {
+ return false; // Erase shuttle from orbit
+ });
+ return true;
+ }
+
+}
diff --git a/library/cpp/lwtrace/lwprobe.h b/library/cpp/lwtrace/lwprobe.h
new file mode 100644
index 0000000000..801fc3861b
--- /dev/null
+++ b/library/cpp/lwtrace/lwprobe.h
@@ -0,0 +1,110 @@
+#pragma once
+
+#include "control.h"
+#include "probe.h"
+
+#include <ctype.h>
+
+namespace NLWTrace {
+#ifndef LWTRACE_DISABLE
+
+ // Box that holds dynamically created probe
+ // NOTE: must be allocated on heap
+ template <LWTRACE_TEMPLATE_PARAMS>
+ class TLWProbe: public IBox, public TUserProbe<LWTRACE_TEMPLATE_ARGS> {
+ private:
+ // Storage for strings referenced by TEvent
+ TString Name;
+ TString Provider;
+ TVector<TString> Groups;
+ TVector<TString> Params;
+ TVector<TProbeRegistry*> Registries; // Note that we assume that registry lives longer than probe
+
+ public:
+ TLWProbe(const TString& provider, const TString& name, const TVector<TString>& groups, const TVector<TString>& params)
+ : IBox(true)
+ , Name(name)
+ , Provider(provider)
+ , Groups(groups)
+ , Params(params)
+ {
+ // initialize TProbe
+ TProbe& probe = this->Probe;
+ probe.Init();
+
+ // initialize TEvent
+ Y_VERIFY(IsCppIdentifier(Name), "probe '%s' is not C++ identifier", Name.data());
+ Y_VERIFY(IsCppIdentifier(Provider), "provider '%s' is not C++ identifier in probe %s", Provider.data(), Name.data());
+ probe.Event.Name = Name.c_str();
+ Zero(probe.Event.Groups);
+ probe.Event.Groups[0] = Provider.c_str();
+ auto i = Groups.begin(), ie = Groups.end();
+ Y_VERIFY(Groups.size() < LWTRACE_MAX_GROUPS, "too many groups in probe %s", Name.data());
+ for (size_t n = 1; n < LWTRACE_MAX_GROUPS && i != ie; n++, ++i) {
+ Y_VERIFY(IsCppIdentifier(*i), "group '%s' is not C++ identifier in probe %s", i->data(), Name.data());
+ probe.Event.Groups[n] = i->c_str();
+ }
+
+ // initialize TSignature
+ using TUsrSign = TUserSignature<LWTRACE_TEMPLATE_ARGS>;
+ Y_VERIFY(TUsrSign::ParamCount == (int)Params.size(), "param count mismatch in probe %s: %d != %d",
+ Name.data(), int(Params.size()), TUsrSign::ParamCount);
+ TSignature& signature = probe.Event.Signature;
+ signature.ParamTypes = TUsrSign::ParamTypes;
+ Zero(signature.ParamNames);
+ auto j = Params.begin(), je = Params.end();
+ for (size_t n = 0; n < LWTRACE_MAX_PARAMS && j != je; n++, ++j) {
+ Y_VERIFY(IsCppIdentifier(*j), "param '%s' is not C++ identifier in probe %s", j->data(), Name.data());
+ signature.ParamNames[n] = j->c_str();
+ }
+ signature.ParamCount = TUsrSign::ParamCount;
+ signature.SerializeParamsFunc = &TUsrSign::SerializeParams;
+ signature.CloneParamsFunc = &TUsrSign::CloneParams;
+ signature.DestroyParamsFunc = &TUsrSign::DestroyParams;
+ signature.SerializeToPbFunc = &TUsrSign::SerializeToPb;
+ signature.DeserializeFromPbFunc = &TUsrSign::DeserializeFromPb;
+
+ // register probe in global registry
+ Register(*Singleton<NLWTrace::TProbeRegistry>());
+ }
+
+ ~TLWProbe() {
+ Unregister();
+ }
+
+ void Register(TProbeRegistry& reg) {
+ Registries.push_back(&reg);
+ reg.AddProbe(TBoxPtr(this)); // NOTE: implied `this' object is created with new operator
+ }
+
+ void Unregister() {
+ // TODO[serxa]: make sure registry never dies before probe it contain
+ // TODO[serxa]: make sure probe never dies before TSession that uses it
+ for (TProbeRegistry* reg : Registries) {
+ reg->RemoveProbe(&this->Probe);
+ }
+ }
+
+ TProbe* GetProbe() override {
+ return &this->Probe;
+ }
+
+ private:
+ static bool IsCppIdentifier(const TString& str) {
+ bool first = true;
+ for (char c : str) {
+ if (first) {
+ first = false;
+ if (!(isalpha(c) || c == '_')) {
+ return false;
+ }
+ } else if (!(isalnum(c) || c == '_')) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
+#endif
+}
diff --git a/library/cpp/lwtrace/mon/analytics/all.h b/library/cpp/lwtrace/mon/analytics/all.h
new file mode 100644
index 0000000000..02ddfb83f2
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/all.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "csv_output.h"
+#include "data.h"
+#include "html_output.h"
+#include "json_output.h"
+#include "transform.h"
+#include "util.h"
diff --git a/library/cpp/lwtrace/mon/analytics/analytics.cpp b/library/cpp/lwtrace/mon/analytics/analytics.cpp
new file mode 100644
index 0000000000..1b25263386
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/analytics.cpp
@@ -0,0 +1,5 @@
+#include "all.h"
+
+namespace NAnalytics {
+
+}
diff --git a/library/cpp/lwtrace/mon/analytics/csv_output.h b/library/cpp/lwtrace/mon/analytics/csv_output.h
new file mode 100644
index 0000000000..90ded32f5d
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/csv_output.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <util/string/printf.h>
+#include <util/stream/str.h>
+#include <util/generic/set.h>
+#include "data.h"
+
+namespace NAnalytics {
+
+inline TString ToCsv(const TTable& in, TString sep = TString("\t"), bool head = true)
+{
+ TSet<TString> cols;
+ bool hasName = false;
+ for (const TRow& row : in) {
+ hasName = hasName || !row.Name.empty();
+ for (const auto& kv : row) {
+ cols.insert(kv.first);
+ }
+ }
+
+ TStringStream ss;
+ if (head) {
+ bool first = true;
+ if (hasName) {
+ ss << (first? TString(): sep) << "Name";
+ first = false;
+ }
+ for (const TString& c : cols) {
+ ss << (first? TString(): sep) << c;
+ first = false;
+ }
+ ss << Endl;
+ }
+
+ for (const TRow& row : in) {
+ bool first = true;
+ if (hasName) {
+ ss << (first? TString(): sep) << row.Name;
+ first = false;
+ }
+ for (const TString& c : cols) {
+ ss << (first? TString(): sep);
+ first = false;
+ TString value;
+ ss << (row.GetAsString(c, value) ? value : TString("-"));
+ }
+ ss << Endl;
+ }
+ return ss.Str();
+}
+
+}
diff --git a/library/cpp/lwtrace/mon/analytics/data.h b/library/cpp/lwtrace/mon/analytics/data.h
new file mode 100644
index 0000000000..4b643fe20b
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/data.h
@@ -0,0 +1,108 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/generic/hash.h>
+#include <util/generic/vector.h>
+#include <util/string/builder.h>
+#include <util/string/cast.h>
+
+#include <variant>
+
+namespace NAnalytics {
+
+using TRowValue = std::variant<i64, ui64, double, TString>;
+
+TString ToString(const TRowValue& val) {
+ TStringBuilder builder;
+ std::visit([&builder] (auto&& arg) {
+ builder << arg;
+ }, val);
+ return builder;
+}
+
+struct TRow : public THashMap<TString, TRowValue> {
+ TString Name;
+
+ template<typename T>
+ bool Get(const TString& name, T& value) const {
+ if constexpr (std::is_same_v<double, T>) {
+ if (name == "_count") { // Special values
+ value = 1.0;
+ return true;
+ }
+ }
+ auto iter = find(name);
+ if (iter != end()) {
+ try {
+ value = std::get<T>(iter->second);
+ return true;
+ } catch (...) {}
+ }
+ return false;
+ }
+
+ template<typename T = double>
+ T GetOrDefault(const TString& name, T dflt = T()) {
+ Get(name, dflt);
+ return dflt;
+ }
+
+ bool GetAsString(const TString& name, TString& value) const {
+ auto iter = find(name);
+ if (iter != end()) {
+ value = ToString(iter->second);
+ return true;
+ }
+ return false;
+ }
+};
+
+using TAttributes = THashMap<TString, TString>;
+
+struct TTable : public TVector<TRow> {
+ TAttributes Attributes;
+};
+
+struct TMatrix : public TVector<double> {
+ size_t Rows;
+ size_t Cols;
+
+ explicit TMatrix(size_t rows = 0, size_t cols = 0)
+ : TVector<double>(rows * cols)
+ , Rows(rows)
+ , Cols(cols)
+ {}
+
+ void Reset(size_t rows, size_t cols)
+ {
+ Rows = rows;
+ Cols = cols;
+ clear();
+ resize(rows * cols);
+ }
+
+ double& Cell(size_t row, size_t col)
+ {
+ Y_VERIFY(row < Rows);
+ Y_VERIFY(col < Cols);
+ return operator[](row * Cols + col);
+ }
+
+ double Cell(size_t row, size_t col) const
+ {
+ Y_VERIFY(row < Rows);
+ Y_VERIFY(col < Cols);
+ return operator[](row * Cols + col);
+ }
+
+ double CellSum() const
+ {
+ double sum = 0.0;
+ for (double x : *this) {
+ sum += x;
+ }
+ return sum;
+ }
+};
+
+}
diff --git a/library/cpp/lwtrace/mon/analytics/html_output.h b/library/cpp/lwtrace/mon/analytics/html_output.h
new file mode 100644
index 0000000000..f775f216b9
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/html_output.h
@@ -0,0 +1,86 @@
+#pragma once
+
+#include <util/string/printf.h>
+#include <util/stream/str.h>
+#include <util/generic/set.h>
+#include "data.h"
+
+namespace NAnalytics {
+
+inline TString ToHtml(const TTable& in)
+{
+ TSet<TString> cols;
+ bool hasName = false;
+ for (const TRow& row : in) {
+ hasName = hasName || !row.Name.empty();
+ for (const auto& kv : row) {
+ cols.insert(kv.first);
+ }
+ }
+
+ TStringStream ss;
+ ss << "<table>";
+ ss << "<thead><tr>";
+ if (hasName) {
+ ss << "<th>Name</th>";
+ }
+ for (const TString& c : cols) {
+ ss << "<th>" << c << "</th>";
+ }
+ ss << "</tr></thead><tbody>";
+
+ for (const TRow& row : in) {
+ ss << "<tr>";
+ if (hasName) {
+ ss << "<th>" << row.Name << "</th>";
+ }
+ for (const TString& c : cols) {
+ TString value;
+ ss << "<td>" << (row.GetAsString(c, value) ? value : TString("-")) << "</td>";
+ }
+ ss << "</tr>";
+ }
+ ss << "</tbody></table>";
+
+ return ss.Str();
+}
+
+inline TString ToTransposedHtml(const TTable& in)
+{
+ TSet<TString> cols;
+ bool hasName = false;
+ for (const TRow& row : in) {
+ hasName = hasName || !row.Name.empty();
+ for (const auto& kv : row) {
+ cols.insert(kv.first);
+ }
+ }
+
+ TStringStream ss;
+ ss << "<table><thead>";
+ if (hasName) {
+ ss << "<tr>";
+ ss << "<th>Name</th>";
+ for (const TRow& row : in) {
+ ss << "<th>" << row.Name << "</th>";
+ }
+ ss << "</tr>";
+ }
+
+ ss << "</thead><tbody>";
+
+ for (const TString& c : cols) {
+ ss << "<tr>";
+ ss << "<th>" << c << "</th>";
+ for (const TRow& row : in) {
+ TString value;
+ ss << "<td>" << (row.GetAsString(c, value) ? value : TString("-")) << "</td>";
+ }
+ ss << "</tr>";
+ }
+ ss << "</tbody></table>";
+
+ return ss.Str();
+}
+
+}
diff --git a/library/cpp/lwtrace/mon/analytics/json_output.h b/library/cpp/lwtrace/mon/analytics/json_output.h
new file mode 100644
index 0000000000..189f9802d3
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/json_output.h
@@ -0,0 +1,98 @@
+#pragma once
+
+#include <util/string/printf.h>
+#include <util/stream/str.h>
+#include <util/string/vector.h>
+#include <util/generic/set.h>
+#include <util/generic/hash_set.h>
+#include "data.h"
+#include "util.h"
+
+namespace NAnalytics {
+
+inline TString ToJsonFlot(const TTable& in, const TString& xno, const TVector<TString>& ynos, const TString& opts = TString())
+{
+ TStringStream ss;
+ ss << "[ ";
+ bool first = true;
+
+ TString xn;
+ THashSet<TString> xopts;
+ ParseNameAndOpts(xno, xn, xopts);
+ bool xstack = xopts.contains("stack");
+
+ for (const TString& yno : ynos) {
+ TString yn;
+ THashSet<TString> yopts;
+ ParseNameAndOpts(yno, yn, yopts);
+ bool ystackOpt = yopts.contains("stack");
+
+ ss << (first? "": ",\n ") << "{ " << opts << (opts? ", ": "") << "\"label\": \"" << yn << "\", \"data\": [ ";
+ bool first2 = true;
+ using TPt = std::tuple<double, double, TString>;
+ std::vector<TPt> pts;
+ for (const TRow& row : in) {
+ double x, y;
+ if (row.Get(xn, x) && row.Get(yn, y)) {
+ pts.emplace_back(x, y, row.Name);
+ }
+ }
+
+ if (xstack) {
+ std::sort(pts.begin(), pts.end(), [] (const TPt& a, const TPt& b) {
+ // At first sort by Name, then by x, then by y
+ return std::make_tuple(std::get<2>(a), std::get<0>(a), std::get<1>(a)) <
+ std::make_tuple(std::get<2>(b), std::get<0>(b), std::get<1>(b));
+ });
+ } else {
+ std::sort(pts.begin(), pts.end());
+ }
+
+ double x = 0.0, xsum = 0.0;
+ double y = 0.0, ysum = 0.0;
+ for (auto& pt : pts) {
+ if (xstack) {
+ x = xsum;
+ xsum += std::get<0>(pt);
+ } else {
+ x = std::get<0>(pt);
+ }
+
+ if (ystackOpt) {
+ y = ysum;
+ ysum += std::get<1>(pt);
+ } else {
+ y = std::get<1>(pt);
+ }
+
+ ss << (first2? "": ", ") << "["
+ << Sprintf("%.6lf", Finitize(x)) << ", " // x coordinate
+ << Sprintf("%.6lf", Finitize(y)) << ", " // y coordinate
+ << "\"" << std::get<2>(pt) << "\", " // label
+ << Sprintf("%.6lf", std::get<0>(pt)) << ", " // x label (real value)
+ << Sprintf("%.6lf", std::get<1>(pt)) // y label (real value)
+ << "]";
+ first2 = false;
+ }
+ // Add final point
+ if (!first2 && (xstack || ystackOpt)) {
+ if (xstack)
+ x = xsum;
+ if (ystackOpt)
+ y = ysum;
+ ss << (first2? "": ", ") << "["
+ << Sprintf("%.6lf", Finitize(x)) << ", " // x coordinate
+ << Sprintf("%.6lf", Finitize(y)) << ", " // y coordinate
+ << "\"\", "
+ << Sprintf("%.6lf", x) << ", " // x label (real value)
+ << Sprintf("%.6lf", y) // y label (real value)
+ << "]";
+ }
+ ss << " ] }";
+ first = false;
+ }
+ ss << "\n]";
+ return ss.Str();
+}
+
+}
diff --git a/library/cpp/lwtrace/mon/analytics/transform.h b/library/cpp/lwtrace/mon/analytics/transform.h
new file mode 100644
index 0000000000..f7dc9adb5b
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/transform.h
@@ -0,0 +1,204 @@
+#pragma once
+
+#include "data.h"
+
+namespace NAnalytics {
+
+template <class TSkip, class TX, class TY>
+inline TTable Histogram(const TTable& in, TSkip skip,
+ const TString& xn_out, TX x_in,
+ const TString& yn_out, TY y_in,
+ double x1, double x2, double dx)
+{
+ long buckets = (x2 - x1) / dx;
+ TTable out;
+ TString yn_sum = yn_out + "_sum";
+ TString yn_share = yn_out + "_share";
+ double ysum = 0.0;
+ out.resize(buckets);
+ for (size_t i = 0; i < out.size(); i++) {
+ double lb = x1 + dx*i;
+ double ub = lb + dx;
+ out[i].Name = "[" + ToString(lb) + ";" + ToString(ub) + (ub==x2? "]": ")");
+ out[i][xn_out] = (lb + ub) / 2;
+ out[i][yn_sum] = 0.0;
+ }
+ for (const auto& row : in) {
+ if (skip(row)) {
+ continue;
+ }
+ double x = x_in(row);
+ long i = (x - x1) / dx;
+ if (x == x2) { // Special hack to include right edge
+ i--;
+ }
+ double y = y_in(row);
+ ysum += y;
+ if (i >= 0 && i < buckets) {
+ out[i][yn_sum] = y + out[i].GetOrDefault(yn_sum, 0.0);
+ }
+ }
+ for (TRow& row : out) {
+ if (ysum != 0.0) {
+ row[yn_share] = row.GetOrDefault(yn_sum, 0.0) / ysum;
+ }
+ }
+ return out;
+}
+
+inline TTable HistogramAll(const TTable& in, const TString& xn, double x1, double x2, double dx)
+{
+ long buckets = (dx == 0.0? 1: (x2 - x1) / dx);
+ TTable out;
+ THashMap<TString, double> colSum;
+ out.resize(buckets);
+
+ TSet<TString> cols;
+ for (auto& row : in) {
+ for (auto& kv : row) {
+ cols.insert(kv.first);
+ }
+ }
+ cols.insert("_count");
+ cols.erase(xn);
+
+ for (const TString& col : cols) {
+ colSum[col] = 0.0;
+ }
+
+ for (size_t i = 0; i < out.size(); i++) {
+ double lb = x1 + dx*i;
+ double ub = lb + dx;
+ TRow& row = out[i];
+ row.Name = "[" + ToString(lb) + ";" + ToString(ub) + (ub==x2? "]": ")");
+ row[xn] = (lb + ub) / 2;
+ for (const TString& col : cols) {
+ row[col + "_sum"] = 0.0;
+ }
+ }
+ for (const TRow& row_in : in) {
+ double x;
+ if (!row_in.Get(xn, x)) {
+ continue;
+ }
+ long i = (dx == 0.0? 0: (x - x1) / dx);
+ if (x == x2 && dx > 0.0) { // Special hack to include right edge
+ i--;
+ }
+ for (const auto& kv : row_in) {
+ const TString& yn = kv.first;
+ if (yn == xn) {
+ continue;
+ }
+ double y;
+ if (!row_in.Get(yn, y)) {
+ continue;
+ }
+ colSum[yn] += y;
+ if (i >= 0 && i < buckets) {
+ out[i][yn + "_cnt"] = out[i].GetOrDefault(yn + "_cnt") + 1;
+ out[i][yn + "_sum"] = out[i].GetOrDefault(yn + "_sum") + y;
+ if (out[i].contains(yn + "_min")) {
+ out[i][yn + "_min"] = Min(y, out[i].GetOrDefault(yn + "_min"));
+ } else {
+ out[i][yn + "_min"] = y;
+ }
+ if (out[i].contains(yn + "_max")) {
+ out[i][yn + "_max"] = Max(y, out[i].GetOrDefault(yn + "_max"));
+ } else {
+ out[i][yn + "_max"] = y;
+ }
+ }
+ }
+ colSum["_count"]++;
+ if (i >= 0 && i < buckets) {
+ out[i]["_count_sum"] = out[i].GetOrDefault("_count_sum") + 1;
+ }
+ }
+ for (TRow& row : out) {
+ for (const TString& col : cols) {
+ double ysum = colSum[col];
+ if (col != "_count") {
+ if (row.GetOrDefault(col + "_cnt") != 0.0) {
+ row[col + "_avg"] = row.GetOrDefault(col + "_sum") / row.GetOrDefault(col + "_cnt");
+ }
+ }
+ if (ysum != 0.0) {
+ row[col + "_share"] = row.GetOrDefault(col + "_sum") / ysum;
+ }
+ }
+ }
+ return out;
+}
+
+inline TMatrix CovarianceMatrix(const TTable& in)
+{
+ TSet<TString> cols;
+ for (auto& row : in) {
+ for (auto& kv : row) {
+ cols.insert(kv.first);
+ }
+ }
+
+ struct TAggregate {
+ size_t Idx = 0;
+ double Sum = 0;
+ size_t Count = 0;
+ double Mean = 0;
+ };
+
+ THashMap<TString, TAggregate> colAggr;
+
+ size_t colCount = 0;
+ for (const TString& col : cols) {
+ TAggregate& aggr = colAggr[col];
+ aggr.Idx = colCount++;
+ }
+
+ for (const TRow& row : in) {
+ for (const auto& kv : row) {
+ const TString& xn = kv.first;
+ double x;
+ if (!row.Get(xn, x)) {
+ continue;
+ }
+ TAggregate& aggr = colAggr[xn];
+ aggr.Sum += x;
+ aggr.Count++;
+ }
+ }
+
+ for (auto& kv : colAggr) {
+ TAggregate& aggr = kv.second;
+ aggr.Mean = aggr.Sum / aggr.Count;
+ }
+
+ TMatrix covCount(cols.size(), cols.size());
+ TMatrix cov(cols.size(), cols.size());
+ for (const TRow& row : in) {
+ for (const auto& kv1 : row) {
+ double x;
+ if (!row.Get(kv1.first, x)) {
+ continue;
+ }
+ TAggregate& xaggr = colAggr[kv1.first];
+ for (const auto& kv2 : row) {
+ double y;
+ if (!row.Get(kv2.first, y)) {
+ continue;
+ }
+ TAggregate& yaggr = colAggr[kv2.first];
+ covCount.Cell(xaggr.Idx, yaggr.Idx)++;
+ cov.Cell(xaggr.Idx, yaggr.Idx) += (x - xaggr.Mean) * (y - yaggr.Mean);
+ }
+ }
+ }
+
+ for (size_t idx = 0; idx < cov.size(); idx++) {
+ cov[idx] /= covCount[idx];
+ }
+
+ return cov;
+}
+
+}
diff --git a/library/cpp/lwtrace/mon/analytics/util.h b/library/cpp/lwtrace/mon/analytics/util.h
new file mode 100644
index 0000000000..e07d06cc43
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/util.h
@@ -0,0 +1,122 @@
+#pragma once
+
+#include "data.h"
+#include <util/generic/algorithm.h>
+#include <util/generic/hash_set.h>
+#include <util/string/vector.h>
+
+namespace NAnalytics {
+
+// Get rid of NaNs and INFs
+inline double Finitize(double x, double notFiniteValue = 0.0)
+{
+ return isfinite(x)? x: notFiniteValue;
+}
+
+inline void ParseNameAndOpts(const TString& nameAndOpts, TString& name, THashSet<TString>& opts)
+{
+ name.clear();
+ opts.clear();
+ bool first = true;
+ auto vs = SplitString(nameAndOpts, "-");
+ for (const auto& s : vs) {
+ if (first) {
+ name = s;
+ first = false;
+ } else {
+ opts.insert(s);
+ }
+ }
+}
+
+inline TString ParseName(const TString& nameAndOpts)
+{
+ auto vs = SplitString(nameAndOpts, "-");
+ if (vs.empty()) {
+ return TString();
+ } else {
+ return vs[0];
+ }
+}
+
+template <class R, class T>
+inline R AccumulateIfExist(const TString& name, const TTable& table, R r, T t)
+{
+ ForEach(table.begin(), table.end(), [=,&r] (const TRow& row) {
+ double value;
+ if (row.Get(name, value)) {
+ r = t(r, value);
+ }
+ });
+ return r;
+}
+
+inline double MinValue(const TString& nameAndOpts, const TTable& table)
+{
+ TString name;
+ THashSet<TString> opts;
+ ParseNameAndOpts(nameAndOpts, name, opts);
+ bool stack = opts.contains("stack");
+ if (stack) {
+ return 0.0;
+ } else {
+ auto zero = 0.0;
+
+ return AccumulateIfExist(name, table, 1.0 / zero /*+inf*/, [] (double x, double y) {
+ return Min(x, y);
+ });
+ }
+}
+
+inline double MaxValue(const TString& nameAndOpts, const TTable& table)
+{
+ TString name;
+ THashSet<TString> opts;
+ ParseNameAndOpts(nameAndOpts, name, opts);
+ bool stack = opts.contains("stack");
+ if (stack) {
+ return AccumulateIfExist(name, table, 0.0, [] (double x, double y) {
+ return x + y;
+ });
+ } else {
+ auto zero = 0.0;
+
+ return AccumulateIfExist(name, table, -1.0 / zero /*-inf*/, [] (double x, double y) {
+ return Max(x, y);
+ });
+ }
+}
+
+template <class T>
+inline void Map(TTable& table, const TString& rname, T t)
+{
+ ForEach(table.begin(), table.end(), [=] (TRow& row) {
+ row[rname] = t(row);
+ });
+}
+
+inline std::function<bool(const TRow&)> HasNoValueFor(TString name)
+{
+ return [=] (const TRow& row) -> bool {
+ double value;
+ return !row.Get(name, value);
+ };
+}
+
+
+inline std::function<double(const TRow&)> GetValueFor(TString name, double defVal = 0.0)
+{
+ return [=] (const TRow& row) -> double {
+ double value;
+ return row.Get(name, value)? value: defVal;
+ };
+}
+
+inline std::function<double(const TRow&)> Const(double defVal = 0.0)
+{
+ return [=] (const TRow&) {
+ return defVal;
+ };
+}
+
+}
diff --git a/library/cpp/lwtrace/mon/analytics/ya.make b/library/cpp/lwtrace/mon/analytics/ya.make
new file mode 100644
index 0000000000..c18e23c8e1
--- /dev/null
+++ b/library/cpp/lwtrace/mon/analytics/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(serxa g:kikimr)
+
+PEERDIR(
+)
+
+SRCS(
+ analytics.cpp
+)
+
+END()
+
+RECURSE(
+)
diff --git a/library/cpp/lwtrace/mon/mon_lwtrace.cpp b/library/cpp/lwtrace/mon/mon_lwtrace.cpp
new file mode 100644
index 0000000000..a61ee9ce22
--- /dev/null
+++ b/library/cpp/lwtrace/mon/mon_lwtrace.cpp
@@ -0,0 +1,4723 @@
+#include "mon_lwtrace.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include <google/protobuf/text_format.h>
+#include <library/cpp/lwtrace/mon/analytics/all.h>
+#include <library/cpp/lwtrace/all.h>
+#include <library/cpp/monlib/service/pages/mon_page.h>
+#include <library/cpp/monlib/service/pages/resource_mon_page.h>
+#include <library/cpp/monlib/service/pages/templates.h>
+#include <library/cpp/resource/resource.h>
+#include <library/cpp/string_utils/base64/base64.h>
+#include <library/cpp/html/pcdata/pcdata.h>
+#include <util/string/escape.h>
+#include <util/system/condvar.h>
+#include <util/system/execpath.h>
+#include <util/system/hostname.h>
+
+using namespace NMonitoring;
+
+#define WWW_CHECK(cond, ...) \
+ do { \
+ if (!(cond)) { \
+ ythrow yexception() << Sprintf(__VA_ARGS__); \
+ } \
+ } while (false) \
+ /**/
+
+#define WWW_HTML_INNER(out) HTML(out) WITH_SCOPED(tmp, TScopedHtmlInner(out))
+#define WWW_HTML(out) out << NMonitoring::HTTPOKHTML; WWW_HTML_INNER(out)
+
+namespace NLwTraceMonPage {
+
+struct TTrackLogRefs {
+ struct TItem {
+ const TThread::TId ThreadId;
+ const NLWTrace::TLogItem* Ptr;
+
+ TItem()
+ : ThreadId(0)
+ , Ptr(nullptr)
+ {}
+
+ TItem(TThread::TId tid, const NLWTrace::TLogItem& ref)
+ : ThreadId(tid)
+ , Ptr(&ref)
+ {}
+
+ TItem(const TItem& o)
+ : ThreadId(o.ThreadId)
+ , Ptr(o.Ptr)
+ {}
+
+ operator const NLWTrace::TLogItem&() const { return *Ptr; }
+ };
+
+ using TItems = TVector<TItem>;
+ TItems Items;
+
+ TTrackLogRefs() {}
+
+ TTrackLogRefs(const TTrackLogRefs& other)
+ : Items(other.Items)
+ {}
+
+ void Clear()
+ {
+ Items.clear();
+ }
+
+ ui64 GetTimestampCycles() const
+ {
+ return Items.empty()? 0: Items.front().Ptr->GetTimestampCycles();
+ }
+};
+
+//
+// Templates to treat both NLWTrace::TLogItem and NLWTrace::TTrackLog in the same way (e.g. in TLogQuery)
+//
+
+template <class TLog>
+struct TLogTraits {};
+
+template <>
+struct TLogTraits<NLWTrace::TLogItem> {
+ using TLog = NLWTrace::TLogItem;
+ using const_iterator = const NLWTrace::TLogItem*;
+ using const_reverse_iterator = const NLWTrace::TLogItem*;
+
+ static const_iterator begin(const TLog& log) { return &log; }
+ static const_iterator end(const TLog& log) { return &log + 1; }
+ static const_reverse_iterator rbegin(const TLog& log) { return &log; }
+ static const_reverse_iterator rend(const TLog& log) { return &log + 1; }
+ static bool empty(const TLog&) { return false; }
+ static const NLWTrace::TLogItem& front(const TLog& log) { return log; }
+ static const NLWTrace::TLogItem& back(const TLog& log) { return log; }
+};
+
+template <>
+struct TLogTraits<NLWTrace::TTrackLog> {
+ using TLog = NLWTrace::TTrackLog;
+ using const_iterator = NLWTrace::TTrackLog::TItems::const_iterator;
+ using const_reverse_iterator = NLWTrace::TTrackLog::TItems::const_reverse_iterator;
+
+ static const_iterator begin(const TLog& log) { return log.Items.begin(); }
+ static const_iterator end(const TLog& log) { return log.Items.end(); }
+ static const_reverse_iterator rbegin(const TLog& log) { return log.Items.rbegin(); }
+ static const_reverse_iterator rend(const TLog& log) { return log.Items.rend(); }
+ static bool empty(const TLog& log) { return log.Items.empty(); }
+ static const NLWTrace::TLogItem& front(const TLog& log) { return log.Items.front(); }
+ static const NLWTrace::TLogItem& back(const TLog& log) { return log.Items.back(); }
+};
+
+template <>
+struct TLogTraits<TTrackLogRefs> {
+ using TLog = TTrackLogRefs;
+ using const_iterator = TTrackLogRefs::TItems::const_iterator;
+ using const_reverse_iterator = TTrackLogRefs::TItems::const_reverse_iterator;
+
+ static const_iterator begin(const TLog& log) { return log.Items.begin(); }
+ static const_iterator end(const TLog& log) { return log.Items.end(); }
+ static const_reverse_iterator rbegin(const TLog& log) { return log.Items.rbegin(); }
+ static const_reverse_iterator rend(const TLog& log) { return log.Items.rend(); }
+ static bool empty(const TLog& log) { return log.Items.empty(); }
+ static const NLWTrace::TLogItem& front(const TLog& log) { return log.Items.front(); }
+ static const NLWTrace::TLogItem& back(const TLog& log) { return log.Items.back(); }
+};
+
+/*
+ * Log Query Language:
+ * Data expressions:
+ * 1) myparam[0], myparam[-1] // the first and the last myparam in any probe/provider
+ * 2) myparam // the first (the same as [0])
+ * 3) PROVIDER..myparam // any probe with myparam in PROVIDER
+ * 4) MyProbe._elapsedMs // Ms since track begin for the first MyProbe event
+ * 5) PROVIDER.MyProbe._sliceUs // Us since previous event in track for the first PROVIDER.MyProbe event
+ */
+
+struct TLogQuery {
+private:
+ enum ESpecialParam {
+ NotSpecial = 0,
+ // The last '*' can be one of: Ms, Us, Ns, Min, Hours, (blank means seconds)
+ // '*Time' can be one of: RTime (since cut ts for given dataset), NTime (negative time since now), Time (since machine start)
+ TrackDuration = 1, // _track*
+ TrackBeginTime = 2, // _begin*Time*
+ TrackEndTime = 3, // _end*Time*
+ ElapsedDuration = 4, // _elapsed*
+ SliceDuration = 5, // _slice*
+ ThreadTime = 6, // _thr*Time*
+ };
+
+ template <class TLog, class TTr = TLogTraits<TLog>>
+ struct TExecuteQuery;
+
+ template <class TLog, class TTr>
+ friend struct TExecuteQuery;
+
+ template <class TLog, class TTr>
+ struct TExecuteQuery {
+ const TLogQuery& Query;
+ const TLog* Log = nullptr;
+ bool Reversed;
+
+ i64 Skip;
+ const NLWTrace::TLogItem* Item = nullptr;
+ typename TTr::const_iterator FwdIter;
+ typename TTr::const_reverse_iterator RevIter;
+
+ NLWTrace::TTypedParam Result;
+
+ explicit TExecuteQuery(const TLogQuery& query, const TLog& log)
+ : Query(query)
+ , Log(&log)
+ , Reversed(Query.Index < 0)
+ , Skip(Reversed? -Query.Index - 1: Query.Index)
+ , FwdIter()
+ , RevIter()
+ {}
+
+ void ExecuteQuery()
+ {
+ if (!Reversed) {
+ for (auto i = TTr::begin(*Log), e = TTr::end(*Log); i != e; ++i) {
+ if (FwdIteration(i)) {
+ return;
+ }
+ }
+ } else {
+ for (auto i = TTr::rbegin(*Log), e = TTr::rend(*Log); i != e; ++i) {
+ if (RevIteration(i)) {
+ return;
+ }
+ }
+ }
+ }
+
+ bool FwdIteration(typename TTr::const_iterator it)
+ {
+ FwdIter = it;
+ Item = &*it;
+ return ProcessItem();
+ }
+
+ bool RevIteration(typename TTr::const_reverse_iterator it)
+ {
+ RevIter = it;
+ Item = &*it;
+ return ProcessItem();
+ }
+
+ bool ProcessItem()
+ {
+ if (Query.Provider && Query.Provider != Item->Probe->Event.GetProvider()) {
+ return false;
+ }
+ if (Query.Probe && Query.Probe != Item->Probe->Event.Name) {
+ return false;
+ }
+ switch (Query.SpecialParam) {
+ case NotSpecial:
+ if (Item->Probe->Event.Signature.FindParamIndex(Query.ParamName) != size_t(-1)) {
+ break; // param found
+ } else {
+ return false; // param not found
+ }
+ case TrackDuration: Y_FAIL();
+ case TrackBeginTime: Y_FAIL();
+ case TrackEndTime: Y_FAIL();
+ case ElapsedDuration: break;
+ case SliceDuration: break;
+ case ThreadTime: break;
+ }
+ if (Skip > 0) {
+ Skip--;
+ return false;
+ }
+ switch (Query.SpecialParam) {
+ case NotSpecial:
+ Result = NLWTrace::TTypedParam(Item->GetParam(Query.ParamName));
+ return true;
+ case TrackDuration: Y_FAIL();
+ case TrackBeginTime: Y_FAIL();
+ case TrackEndTime: Y_FAIL();
+ case ElapsedDuration:
+ Result = NLWTrace::TTypedParam(Query.Duration(
+ Log->GetTimestampCycles(),
+ Item->GetTimestampCycles()));
+ return true;
+ case SliceDuration:
+ Result = NLWTrace::TTypedParam(Query.Duration(
+ PrevOrSame().GetTimestampCycles(),
+ Item->GetTimestampCycles()));
+ return true;
+ case ThreadTime:
+ Result = NLWTrace::TTypedParam(Query.Instant(Item->GetTimestampCycles()));
+ return true;
+ }
+ return true;
+ }
+
+ const NLWTrace::TLogItem& PrevOrSame() const
+ {
+ if (!Reversed) {
+ auto i = FwdIter;
+ if (i != TTr::begin(*Log)) {
+ i--;
+ }
+ return *i;
+ } else {
+ auto j = RevIter + 1;
+ if (j == TTr::rend(*Log)) {
+ return *RevIter;
+ }
+ return *j;
+ }
+ }
+ };
+
+ TString Text;
+ TString Provider;
+ TString Probe;
+ TString ParamName;
+ ESpecialParam SpecialParam = NotSpecial;
+ i64 Index = 0;
+ double TimeUnitSec = 1.0;
+ i64 ZeroTs = 0;
+ i64 RTimeZeroTs = 0;
+ i64 NTimeZeroTs = 0;
+
+public:
+ TLogQuery() {}
+
+ explicit TLogQuery(const TString& text)
+ : Text(text)
+ {
+ try {
+ if (!Text.empty()) {
+ ParseQuery(Text);
+ }
+ } catch (...) {
+ ythrow yexception()
+ << CurrentExceptionMessage()
+ << " while parsing track log query: "
+ << Text;
+ }
+ }
+
+ operator bool() const
+ {
+ return !Text.empty();
+ }
+
+ template <class TLog>
+ NLWTrace::TTypedParam ExecuteQuery(const TLog& log) const
+ {
+ using TTr = TLogTraits<TLog>;
+
+ WWW_CHECK(Text, "execute of empty log query");
+ if (TTr::empty(log)) {
+ return NLWTrace::TTypedParam();
+ }
+
+ if (SpecialParam == TrackDuration) {
+ return Duration(
+ log.GetTimestampCycles(),
+ TTr::back(log).GetTimestampCycles());
+ } else if (SpecialParam == TrackBeginTime) {
+ return Instant(log.GetTimestampCycles());
+ } else if (SpecialParam == TrackEndTime) {
+ return Instant(TTr::back(log).GetTimestampCycles());
+ }
+
+ TExecuteQuery<TLog, TTr> exec(*this, log);
+ exec.ExecuteQuery();
+ return exec.Result;
+ }
+
+private:
+ NLWTrace::TTypedParam Duration(ui64 ts1, ui64 ts2) const
+ {
+ double sec = NHPTimer::GetSeconds(ts1 < ts2? ts2 - ts1: 0);
+ return NLWTrace::TTypedParam(sec / TimeUnitSec);
+ }
+
+ NLWTrace::TTypedParam Instant(ui64 ts) const
+ {
+ double sec = NHPTimer::GetSeconds(i64(ts) - ZeroTs);
+ return NLWTrace::TTypedParam(sec / TimeUnitSec);
+ }
+
+ void ParseQuery(const TString& s)
+ {
+ auto parts = SplitString(s, ".");
+ WWW_CHECK(parts.size() <= 3, "too many name specifiers");
+ ParseParamSelector(parts.back());
+ if (parts.size() >= 2) {
+ ParseProbeSelector(parts[parts.size() - 2]);
+ }
+ if (parts.size() >= 3) {
+ ParseProviderSelector(parts[parts.size() - 3]);
+ }
+ }
+
+ void ParseParamSelector(const TString& s)
+ {
+ size_t bracket = s.find('[');
+ if (bracket == TString::npos) {
+ ParseParamName(s);
+ Index = 0;
+ } else {
+ ParseParamName(s.substr(0, bracket));
+ size_t bracket2 = s.find(']', bracket);
+ WWW_CHECK(bracket2 != TString::npos, "closing braket ']' is missing");
+ Index = FromString<i64>(s.substr(bracket + 1, bracket2 - bracket - 1));
+ }
+ }
+
+ void ParseParamName(const TString& s)
+ {
+ ParamName = s;
+ TString paramName = s;
+
+ const static TVector<std::pair<TString, ESpecialParam>> specials = {
+ { "_track", TrackDuration },
+ { "_begin", TrackBeginTime },
+ { "_end", TrackEndTime },
+ { "_elapsed", ElapsedDuration },
+ { "_slice", SliceDuration },
+ { "_thr", ThreadTime }
+ };
+
+ // Check for special params
+ SpecialParam = NotSpecial;
+ for (const auto& p : specials) {
+ if (paramName.StartsWith(p.first)) {
+ SpecialParam = p.second;
+ paramName.erase(0, p.first.size());
+ break;
+ }
+ }
+
+ if (SpecialParam == NotSpecial) {
+ return;
+ }
+
+ const static TVector<std::pair<TString, double>> timeUnits = {
+ { "Ms", 1e-3 },
+ { "Us", 1e-6 },
+ { "Ns", 1e-9 },
+ { "Min", 60.0 },
+ { "Hours", 3600.0 }
+ };
+
+ // Parse units for special params
+ TimeUnitSec = 1.0;
+ for (const auto& p : timeUnits) {
+ if (paramName.EndsWith(p.first)) {
+ TimeUnitSec = p.second;
+ paramName.erase(paramName.size() - p.first.size());
+ break;
+ }
+ }
+
+ if (SpecialParam == ThreadTime ||
+ SpecialParam == TrackBeginTime ||
+ SpecialParam == TrackEndTime)
+ {
+ // Parse time zero for special instant params
+ const TVector<std::pair<TString, i64>> timeZeros = {
+ { "RTime", RTimeZeroTs },
+ { "NTime", NTimeZeroTs },
+ { "Time", 0ll }
+ };
+ ZeroTs = -1;
+ for (const auto& p : timeZeros) {
+ if (paramName.EndsWith(p.first)) {
+ ZeroTs = p.second;
+ paramName.erase(paramName.size() - p.first.size());
+ break;
+ }
+ }
+ WWW_CHECK(ZeroTs != -1, "wrong special param name (postfix '*Time' required): %s", s.data());
+ }
+
+ WWW_CHECK(paramName.empty(), "wrong special param name: %s", s.data());
+ }
+
+ void ParseProbeSelector(const TString& s)
+ {
+ Probe = s;
+ }
+
+ void ParseProviderSelector(const TString& s)
+ {
+ Provider = s;
+ }
+};
+
+using TVariants = TVector<std::pair<TString, TString>>;
+using TTags = TSet<TString>;
+
+TString GetProbeName(const NLWTrace::TProbe* probe, const char* sep = ".")
+{
+ return TString(probe->Event.GetProvider()) + sep + probe->Event.Name;
+}
+
+struct TAdHocTraceConfig {
+ NLWTrace::TQuery Cfg;
+
+ TAdHocTraceConfig() {} // Invalid config
+
+ TAdHocTraceConfig(ui16 logSize, ui64 logDurationUs, bool logShuttle)
+ {
+ auto block = Cfg.AddBlocks(); // Create one block to distinguish valid config
+ if (logSize) {
+ Cfg.SetPerThreadLogSize(logSize);
+ }
+ if (logDurationUs) {
+ Cfg.SetLogDurationUs(logDurationUs);
+ }
+ if (logShuttle) {
+ block->AddAction()->MutableRunLogShuttleAction();
+ }
+ }
+
+ TAdHocTraceConfig(const TString& provider, const TString& probe, ui16 logSize = 0, ui64 logDurationUs = 0, bool logShuttle = false)
+ : TAdHocTraceConfig(logSize, logDurationUs, logShuttle)
+ {
+ auto block = Cfg.MutableBlocks(0);
+ auto pdesc = block->MutableProbeDesc();
+ pdesc->SetProvider(provider);
+ pdesc->SetName(probe);
+ }
+
+ explicit TAdHocTraceConfig(const TString& group, ui16 logSize = 0, ui64 logDurationUs = 0, bool logShuttle = false)
+ : TAdHocTraceConfig(logSize, logDurationUs, logShuttle)
+ {
+ auto block = Cfg.MutableBlocks(0);
+ auto pdesc = block->MutableProbeDesc();
+ pdesc->SetGroup(group);
+ }
+
+ TString Id() const
+ {
+ TStringStream ss;
+ for (size_t blockIdx = 0; blockIdx < Cfg.BlocksSize(); blockIdx++) {
+ if (!ss.Str().empty()) {
+ ss << "/";
+ }
+ auto block = Cfg.GetBlocks(blockIdx);
+ auto pdesc = block.GetProbeDesc();
+ if (pdesc.GetProvider()) {
+ ss << "." << pdesc.GetProvider() << "." << pdesc.GetName();
+ } else if (pdesc.GetGroup()) {
+ ss << ".Group." << pdesc.GetGroup();
+ }
+ // TODO[serxa]: handle predicate
+ for (size_t actionIdx = 0; actionIdx < block.ActionSize(); actionIdx++) {
+ const NLWTrace::TAction& action = block.GetAction(actionIdx);
+ if (action.HasRunLogShuttleAction()) {
+ auto ls = action.GetRunLogShuttleAction();
+ ss << ".alsr";
+ if (ls.GetIgnore()) {
+ ss << "-i";
+ }
+ if (ls.GetShuttlesCount()) {
+ ss << "-s" << ls.GetShuttlesCount();
+ }
+ if (ls.GetMaxTrackLength()) {
+ ss << "-t" << ls.GetMaxTrackLength();
+ }
+ } else if (action.HasEditLogShuttleAction()) {
+ auto ls = action.GetEditLogShuttleAction();
+ ss << ".alse";
+ if (ls.GetIgnore()) {
+ ss << "-i";
+ }
+ } else if (action.HasDropLogShuttleAction()) {
+ ss << ".alsd";
+ }
+ }
+ }
+ if (Cfg.GetPerThreadLogSize()) {
+ ss << ".l" << Cfg.GetPerThreadLogSize();
+ }
+ if (Cfg.GetLogDurationUs()) {
+ ui64 logDurationUs = Cfg.GetLogDurationUs();
+ if (logDurationUs % (60 * 1000 * 1000) == 0)
+ ss << ".d" << logDurationUs / (60 * 1000 * 1000) << "m";
+ if (logDurationUs % (1000 * 1000) == 0)
+ ss << ".d" << logDurationUs / (1000 * 1000) << "s";
+ else if (logDurationUs % 1000 == 0)
+ ss << ".d" << logDurationUs / 1000 << "ms";
+ else
+ ss << ".d" << logDurationUs << "us";
+ }
+ return ss.Str();
+ }
+
+ bool IsValid() const
+ {
+ return Cfg.BlocksSize() > 0;
+ }
+
+ NLWTrace::TQuery Query() const
+ {
+ if (!IsValid()) {
+ ythrow yexception() << "invalid adhoc trace config";
+ }
+ return Cfg;
+ }
+
+ bool ParseId(const TString& id)
+ {
+ if (IsAdHocId(id)) {
+ for (const TString& block : SplitString(id, "/")) {
+ if (block.empty()) {
+ continue;
+ }
+ size_t cutPos = (block[0] == '.'? 1: 0);
+ TVector<TString> parts = SplitString(block.substr(cutPos), ".");
+ WWW_CHECK(parts.size() >= 2, "too few parts in adhoc trace id '%s' block '%s'", id.data(), block.data());
+ auto blockPb = Cfg.AddBlocks();
+ auto pdescPb = blockPb->MutableProbeDesc();
+ if (parts[0] == "Group") {
+ pdescPb->SetGroup(parts[1]);
+ } else {
+ pdescPb->SetProvider(parts[0]);
+ pdescPb->SetName(parts[1]);
+ }
+ bool defaultAction = true;
+ for (auto i = parts.begin() + 2, e = parts.end(); i != e; ++i) {
+ const TString& part = *i;
+ if (part.empty()) {
+ continue;
+ }
+ switch (part[0]) {
+ case 'l': Cfg.SetPerThreadLogSize(FromString<ui16>(part.substr(1))); break;
+ case 'd': Cfg.SetLogDurationUs(ParseDuration(part.substr(1))); break;
+ case 's': blockPb->MutablePredicate()->SetSampleRate(1.0 / Max<ui64>(1, FromString<ui64>(part.substr(1)))); break;
+ case 'p': ParsePredicate(blockPb->MutablePredicate()->AddOperators(), part.substr(1)); break;
+ case 'a': ParseAction(blockPb->AddAction(), part.substr(1)); defaultAction = false; break;
+ default: WWW_CHECK(false, "unknown adhoc trace part type '%s' in '%s'", part.data(), id.data());
+ }
+ }
+ if (defaultAction) {
+ blockPb->AddAction()->MutableLogAction();
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+private:
+ static bool IsAdHocId(const TString& id)
+ {
+ return !id.empty() && id[0] == '.';
+ }
+
+ void ParsePredicate(NLWTrace::TOperator* op, const TString& p)
+ {
+ size_t sign = p.find_first_of("=!><");
+ WWW_CHECK(sign != TString::npos, "wrong predicate format in adhoc trace: %s", p.data());
+ op->AddArgument()->SetParam(p.substr(0, sign));
+ size_t value = sign + 1;
+ switch (p[sign]) {
+ case '=':
+ op->SetType(NLWTrace::OT_EQ);
+ break;
+ case '!': {
+ WWW_CHECK(p.size() > sign + 1, "wrong predicate operator format in adhoc trace: %s", p.data());
+ WWW_CHECK(p[sign + 1] == '=', "wrong predicate operator format in adhoc trace: %s", p.data());
+ value++;
+ op->SetType(NLWTrace::OT_NE);
+ break;
+ }
+ case '<': {
+ WWW_CHECK(p.size() > sign + 1, "wrong predicate operator format in adhoc trace: %s", p.data());
+ if (p[sign + 1] == '=') {
+ value++;
+ op->SetType(NLWTrace::OT_LE);
+ } else {
+ op->SetType(NLWTrace::OT_LT);
+ }
+ break;
+ }
+ case '>': {
+ WWW_CHECK(p.size() > sign + 1, "wrong predicate operator format in adhoc trace: %s", p.data());
+ if (p[sign + 1] == '=') {
+ value++;
+ op->SetType(NLWTrace::OT_GE);
+ } else {
+ op->SetType(NLWTrace::OT_GT);
+ }
+ break;
+ }
+ default: WWW_CHECK(false, "wrong predicate operator format in adhoc trace: %s", p.data());
+ }
+ op->AddArgument()->SetValue(p.substr(value));
+ }
+
+ void ParseAction(NLWTrace::TAction* action, const TString& a)
+ {
+ // NOTE: checks for longer action names should go first, your captain.
+ if (a.substr(0, 3) == "lsr") {
+ auto pb = action->MutableRunLogShuttleAction();
+ for (const TString& opt : SplitString(a.substr(3), "-")) {
+ if (!opt.empty()) {
+ switch (opt[0]) {
+ case 'i': pb->SetIgnore(true); break;
+ case 's': pb->SetShuttlesCount(FromString<ui64>(opt.substr(1))); break;
+ case 't': pb->SetMaxTrackLength(FromString<ui64>(opt.substr(1))); break;
+ default: WWW_CHECK(false, "unknown adhoc trace log shuttle opt '%s' in '%s'", opt.data(), a.data());
+ }
+ }
+ }
+ } else if (a.substr(0, 3) == "lse") {
+ auto pb = action->MutableEditLogShuttleAction();
+ for (const TString& opt : SplitString(a.substr(3), "-")) {
+ if (!opt.empty()) {
+ switch (opt[0]) {
+ case 'i': pb->SetIgnore(true); break;
+ default: WWW_CHECK(false, "unknown adhoc trace log shuttle opt '%s' in '%s'", opt.data(), a.data());
+ }
+ }
+ }
+ } else if (a.substr(0, 3) == "lsd") {
+ action->MutableDropLogShuttleAction();
+ } else if (a.substr(0, 1) == "l") {
+ auto pb = action->MutableLogAction();
+ for (const TString& opt : SplitString(a.substr(1), "-")) {
+ if (!opt.empty()) {
+ switch (opt[0]) {
+ case 't': pb->SetLogTimestamp(true); break;
+ case 'r': pb->SetMaxRecords(FromString<ui32>(opt.substr(1))); break;
+ default: WWW_CHECK(false, "unknown adhoc trace log opt '%s' in '%s'", opt.data(), a.data());
+ }
+ }
+ }
+ } else {
+ WWW_CHECK(false, "wrong action format in adhoc trace: %s", a.data());
+ }
+ }
+
+ static ui64 ParseDuration(const TString& s)
+ {
+ if (s.substr(s.length() - 2) == "us")
+ return FromString<ui64>(s.substr(0, s.length() - 2));
+ if (s.substr(s.length() - 2) == "ms")
+ return FromString<ui64>(s.substr(0, s.length() - 2)) * 1000;
+ if (s.substr(s.length() - 1) == "s")
+ return FromString<ui64>(s.substr(0, s.length() - 1)) * 1000 * 1000;
+ if (s.substr(s.length() - 1) == "m")
+ return FromString<ui64>(s.substr(0, s.length() - 1)) * 60 * 1000 * 1000;
+ else
+ return FromString<ui64>(s);
+ }
+};
+
+// Class that maintains one thread iff there are adhoc traces and cleans'em by deadlines
+class TTraceCleaner {
+private:
+ NLWTrace::TManager* TraceMngr;
+ TAtomic Quit = 0;
+
+ TMutex Mtx;
+ TCondVar WakeCondVar;
+ THashMap<TString, TInstant> Deadlines;
+ volatile bool ThreadIsRunning = false;
+ THolder<TThread> Thread;
+public:
+ TTraceCleaner(NLWTrace::TManager* traceMngr)
+ : TraceMngr(traceMngr)
+ {}
+
+ ~TTraceCleaner()
+ {
+ AtomicSet(Quit, 1);
+ WakeCondVar.Signal();
+ // TThread dtor joins thread
+ }
+
+ // Returns deadline for specified trace id or zero
+ TInstant GetDeadline(const TString& id) const
+ {
+ TGuard<TMutex> g(Mtx);
+ auto iter = Deadlines.find(id);
+ return iter != Deadlines.end()? iter->second: TInstant::Zero();
+ }
+
+ // Postpone deletion of specified trace for specified timeout
+ void Postpone(const TString& id, TDuration timeout, bool allowLowering)
+ {
+ TGuard<TMutex> g(Mtx);
+ TInstant newDeadline = TInstant::Now() + timeout;
+ if (Deadlines[id] < newDeadline) {
+ Deadlines[id] = newDeadline;
+ } else if (allowLowering) { // Deadline lowering requires wake
+ Deadlines[id] = newDeadline;
+ WakeCondVar.Signal();
+ }
+ if (newDeadline != TInstant::Max() && !ThreadIsRunning) {
+ // Note that dtor joins previous thread if any
+ Thread.Reset(new TThread(ThreadProc, this));
+ Thread->Start();
+ ThreadIsRunning = true;
+ }
+ }
+
+ // Forget about specified trace deletion
+ void Forget(const TString& id)
+ {
+ TGuard<TMutex> g(Mtx);
+ Deadlines.erase(id);
+ WakeCondVar.Signal(); // in case thread is not required any more
+ }
+private:
+ void Exec()
+ {
+ while (!AtomicGet(Quit)) {
+ TGuard<TMutex> g(Mtx);
+
+ // Delete all timed out traces
+ TInstant now = TInstant::Now();
+ TInstant nextDeadline = TInstant::Max();
+ for (auto i = Deadlines.begin(), e = Deadlines.end(); i != e;) {
+ const TString& id = i->first;
+ TInstant deadline = i->second;
+ if (deadline < now) {
+ try {
+ TraceMngr->Delete(id);
+ } catch (...) {
+ // already deleted
+ }
+ Deadlines.erase(i++);
+ } else {
+ nextDeadline = Min(nextDeadline, deadline);
+ ++i;
+ }
+ }
+
+ // Stop thread if there is no more work
+ if (Deadlines.empty() || nextDeadline == TInstant::Max()) {
+ ThreadIsRunning = false;
+ break;
+ }
+
+ // Wait until next deadline or quit
+ WakeCondVar.WaitD(Mtx, nextDeadline);
+ }
+ }
+
+ static void* ThreadProc(void* _this)
+ {
+ TString name = "LWTraceCleaner";
+ // Copy-pasted from kikimr/core/util/thread.h
+#if defined(_linux_)
+ TStringStream linuxName;
+ linuxName << TStringBuf(GetExecPath()).RNextTok('/') << "." << name;
+ TThread::SetCurrentThreadName(linuxName.Str().data());
+#else
+ TThread::SetCurrentThreadName(name.data());
+#endif
+ static_cast<TTraceCleaner*>(_this)->Exec();
+ return nullptr;
+ }
+};
+
+class TChromeTrace {
+private:
+ TMultiMap<double, TString> TraceEvents;
+ THashMap<TThread::TId, TString> Tids;
+public:
+ void Add(TThread::TId tid, ui64 tsCycles, const TString& ph, const TString& cat,
+ const NLWTrace::TLogItem* argsItem = nullptr,
+ const TString& name = TString(), const TString& id = TString())
+ {
+ auto tidIter = Tids.find(tid);
+ if (tidIter == Tids.end()) {
+ tidIter = Tids.emplace(tid, ToString(Tids.size() + 1)).first;
+ }
+ const TString& shortId = tidIter->second;
+ double ts = Timestamp(tsCycles);
+ TraceEvents.emplace(ts, Event(shortId, ts, ph, cat, argsItem, name, id));
+ }
+
+ void Output(IOutputStream& os)
+ {
+ os << "{\"traceEvents\":[";
+ bool first = true;
+ for (auto kv : TraceEvents) {
+ if (!first) {
+ os << ",\n";
+ }
+ os << kv.second;
+ first = false;
+ }
+ os << "]}";
+ }
+
+private:
+ static TString Event(const TString& tid, double ts, const TString& ph, const TString& cat,
+ const NLWTrace::TLogItem* argsItem,
+ const TString& name, const TString& id)
+ {
+ TStringStream ss;
+ pid_t pid = 1;
+ ss << "{\"pid\":" << pid
+ << ",\"tid\":" << tid
+ << ",\"ts\":" << Sprintf("%lf", ts)
+ << ",\"ph\":\"" << ph << "\""
+ << ",\"cat\":\"" << cat << "\"";
+ if (name) {
+ ss << ",\"name\":\"" << name << "\"";
+ }
+ if (id) {
+ ss << ",\"id\":\"" << id << "\"";
+ }
+ if (argsItem && argsItem->SavedParamsCount > 0) {
+ ss << ",\"args\":{";
+ TString paramValues[LWTRACE_MAX_PARAMS];
+ argsItem->Probe->Event.Signature.SerializeParams(argsItem->Params, paramValues);
+ bool first = true;
+ for (size_t pi = 0; pi < argsItem->SavedParamsCount; pi++, first = false) {
+ if (!first) {
+ ss << ",";
+ }
+ ss << "\"" << TString(argsItem->Probe->Event.Signature.ParamNames[pi]) << "\":"
+ "\"" << paramValues[pi] << "\"";
+ }
+ ss << "}";
+ }
+ ss << "}";
+ return ss.Str();
+ }
+
+ static double Timestamp(ui64 cycles)
+ {
+ return double(cycles) * 1000000.0 / NHPTimer::GetClockRate();
+ }
+};
+
+TString MakeUrl(const TCgiParameters& e, const THashMap<TString, TString>& values)
+{
+ TStringStream ss;
+ bool first = true;
+ for (const auto& [k, v] : e) {
+ if (values.find(k) == values.end()) {
+ ss << (first? "?": "&") << k << "=" << v;
+ first = false;
+ }
+ }
+ for (const auto& [k, v] : values) {
+ ss << (first? "?": "&") << k << "=" << v;
+ first = false;
+ }
+ return ss.Str();
+}
+
+TString MakeUrl(const TCgiParameters& e, const TString& key, const TString& value, bool keep = false)
+{
+ TStringStream ss;
+ bool first = true;
+ for (const auto& kv : e) {
+ if (keep || kv.first != key) {
+ ss << (first? "?": "&") << kv.first << "=" << kv.second;
+ first = false;
+ }
+ }
+ ss << (first? "?": "&") << key << "=" << value;
+ return ss.Str();
+}
+
+TString MakeUrlAdd(const TCgiParameters& e, const TString& key, const TString& value)
+{
+ TStringStream ss;
+ bool first = true;
+ for (const auto& kv : e) {
+ ss << (first? "?": "&") << kv.first << "=" << kv.second;
+ first = false;
+ }
+ ss << (first? "?": "&") << key << "=" << value;
+ return ss.Str();
+}
+
+TString MakeUrlReplace(const TCgiParameters& e, const TString& key, const TString& oldValue, const TString& newValue)
+{
+ TStringStream ss;
+ bool first = true;
+ bool inserted = false;
+ for (const auto& kv : e) {
+ if (kv.first == key && (kv.second == oldValue || kv.second == newValue)) {
+ if (!inserted) {
+ inserted = true;
+ ss << (first? "?": "&") << key << "=" << newValue;
+ first = false;
+ }
+ } else {
+ ss << (first? "?": "&") << kv.first << "=" << kv.second;
+ first = false;
+ }
+ }
+ if (!inserted) {
+ ss << (first? "?": "&") << key << "=" << newValue;
+ }
+ return ss.Str();
+}
+
+TString MakeUrlErase(const TCgiParameters& e, const TString& key, const TString& value)
+{
+ TStringStream ss;
+ bool first = true;
+ for (const auto& kv : e) {
+ if (kv.first != key || kv.second != value) {
+ ss << (first? "?": "&") << kv.first << "=" << kv.second;
+ first = false;
+ }
+ }
+ return ss.Str();
+}
+
+TString EscapeSubvalue(const TString& s)
+{
+ TString ret;
+ ret.reserve(s.size());
+ for (size_t i = 0; i < s.size(); i++) {
+ char c = s[i];
+ if (c == ':') {
+ ret.append("^c");
+ } else if (c == '^') {
+ ret.append("^^");
+ } else {
+ ret.append(c);
+ }
+ }
+ return ret;
+}
+
+TString UnescapeSubvalue(const TString& s)
+{
+ TString ret;
+ ret.reserve(s.size());
+ for (size_t i = 0; i < s.size(); i++) {
+ char c = s[i];
+ if (c == '^' && i + 1 < s.size()) {
+ char c2 = s[++i];
+ if (c2 == 'c') {
+ ret.append(':');
+ } else if (c2 == '^') {
+ ret.append('^');
+ } else {
+ ret.append(c);
+ ret.append(c2);
+ }
+ } else {
+ ret.append(c);
+ }
+ }
+ return ret;
+}
+
+TVector<TString> Subvalues(const TCgiParameters& e, const TString& key)
+{
+ if (!e.Has(key)) {
+ return TVector<TString>();
+ } else {
+ TVector<TString> ret;
+ for (const TString& s : SplitString(e.Get(key), ":", 0, KEEP_EMPTY_TOKENS)) {
+ ret.push_back(UnescapeSubvalue(s));
+ }
+ if (ret.empty()) {
+ ret.push_back("");
+ }
+ return ret;
+ }
+}
+
+TString ParseTagsOut(const TString& taggedStr, TTags& tags)
+{
+ auto vec = SplitString(taggedStr, "-");
+ if (vec.empty()) {
+ return "";
+ }
+ auto iter = vec.begin();
+ TString value = *iter++;
+ for (;iter != vec.end(); ++iter) {
+ tags.insert(*iter);
+ }
+ return value;
+}
+
+TString JoinTags(TTags tags) {
+ return JoinStrings(TVector<TString>(tags.begin(), tags.end()), "-");
+}
+
+TString MakeValue(const TVector<TString>& subvalues)
+{
+ TVector<TString> subvaluesEsc;
+ for (const TString& s : subvalues) {
+ subvaluesEsc.push_back(EscapeSubvalue(s));
+ }
+ return JoinStrings(subvaluesEsc, ":");
+}
+
+TString MakeUrlAddSub(const TCgiParameters& e, const TString& key, const TString& subvalue)
+{
+ const TString& value = e.Get(key);
+ auto subvalues = Subvalues(e, key);
+ subvalues.push_back(subvalue);
+ return MakeUrlReplace(e, key, value, MakeValue(subvalues));
+}
+
+TString MakeUrlReplaceSub(const TCgiParameters& e, const TString& key, const TString& oldSubvalue, const TString& newSubvalue)
+{
+ const TString& value = e.Get(key);
+ auto subvalues = Subvalues(e, key);
+ auto iter = std::find(subvalues.begin(), subvalues.end(), oldSubvalue);
+ if (iter != subvalues.end()) {
+ *iter = newSubvalue;
+ } else {
+ subvalues.push_back(newSubvalue);
+ }
+ return MakeUrlReplace(e, key, value, MakeValue(subvalues));
+}
+
+TString MakeUrlEraseSub(const TCgiParameters& e, const TString& key, const TString& subvalue)
+{
+ const TString& value = e.Get(key);
+ auto subvalues = Subvalues(e, key);
+ auto iter = std::find(subvalues.begin(), subvalues.end(), subvalue);
+ if (iter != subvalues.end()) {
+ subvalues.erase(iter);
+ }
+ if (subvalues.empty()) {
+ return MakeUrlErase(e, key, value);
+ } else {
+ return MakeUrlReplace(e, key, value, MakeValue(subvalues));
+ }
+}
+
+template <bool sub> TString UrlAdd(const TCgiParameters& e, const TString& key, const TString& value);
+template <> TString UrlAdd<false>(const TCgiParameters& e, const TString& key, const TString& value) {
+ return MakeUrlAdd(e, key, value);
+}
+template <> TString UrlAdd<true>(const TCgiParameters& e, const TString& key, const TString& value) {
+ return MakeUrlAddSub(e, key, value);
+}
+
+template <bool sub> TString UrlReplace(const TCgiParameters& e, const TString& key, const TString& oldValue, const TString& newValue);
+template <> TString UrlReplace<false>(const TCgiParameters& e, const TString& key, const TString& oldValue, const TString& newValue) {
+ return MakeUrlReplace(e, key, oldValue, newValue);
+}
+template <> TString UrlReplace<true>(const TCgiParameters& e, const TString& key, const TString& oldValue, const TString& newValue) {
+ return MakeUrlReplaceSub(e, key, oldValue, newValue);
+}
+
+template <bool sub> TString UrlErase(const TCgiParameters& e, const TString& key, const TString& value);
+template <> TString UrlErase<false>(const TCgiParameters& e, const TString& key, const TString& value) {
+ return MakeUrlErase(e, key, value);
+}
+template <> TString UrlErase<true>(const TCgiParameters& e, const TString& key, const TString& value) {
+ return MakeUrlEraseSub(e, key, value);
+}
+
+void OutputCommonHeader(IOutputStream& out)
+{
+ out << NResource::Find("lwtrace/mon/static/header.html") << Endl;
+}
+
+void OutputCommonFooter(IOutputStream& out)
+{
+ out << NResource::Find("lwtrace/mon/static/footer.html") << Endl;
+}
+
+struct TScopedHtmlInner {
+ explicit TScopedHtmlInner(IOutputStream& str)
+ : Str(str)
+ {
+ Str << "<!DOCTYPE html>\n"
+ "<html>";
+ HTML(str) {
+ HEAD() { OutputCommonHeader(Str); }
+ }
+ Str << "<body>";
+ }
+
+ ~TScopedHtmlInner()
+ {
+ OutputCommonFooter(Str);
+ Str << "</body></html>";
+ }
+
+ inline operator bool () const noexcept { return true; }
+
+ IOutputStream &Str;
+};
+
+TString NavbarHeader()
+{
+ return "<div class=\"navbar-header\">"
+ "<a class=\"navbar-brand\" href=\"?mode=\">LWTrace</a>"
+ "</div>";
+}
+
+struct TSelectorsContainer {
+ TSelectorsContainer(IOutputStream& str)
+ : Str(str)
+ {
+ Str << "<nav id=\"selectors-container\" class=\"navbar navbar-default\">"
+ "<div class=\"container-fluid\">"
+ << NavbarHeader() <<
+ "<div class=\"navbar-text\" style=\"margin-top:12px;margin-bottom:10px\">";
+ }
+
+ ~TSelectorsContainer() {
+ try {
+ Str <<
+ "</div>"
+ "<div class=\"container-fluid\">"
+ "<div class=\"pull-right\">"
+ "<button id=\"download-btn\""
+ " type=\"button\" style=\"display: inline-block;margin:7px\""
+ " title=\"Chromium trace (load it in chrome://tracing/)\""
+ " class=\"btn btn-default hidden\">"
+ "<span class=\"glyphicon glyphicon-download-alt\"></span>"
+ "</button>"
+ "</div>"
+ "</div>"
+ "</div></nav>";
+ } catch(...) {}
+ }
+
+ IOutputStream& Str;
+};
+
+struct TNullContainer {
+ TNullContainer(IOutputStream&) {}
+};
+
+class TPageGenBase: public std::exception {};
+template <class TContainer = TNullContainer>
+class TPageGen: public TPageGenBase {
+private:
+ TString Content;
+ TString HttpResponse;
+public:
+ void BuildResponse()
+ {
+ TStringStream ss;
+ WWW_HTML(ss) {
+ TContainer container(ss);
+ ss << Content;
+ }
+ HttpResponse = ss.Str();
+ }
+
+ explicit TPageGen(const TString& content = TString())
+ : Content(content)
+ {
+ BuildResponse();
+ }
+
+ void Append(const TString& moreContent)
+ {
+ Content.append(moreContent);
+ BuildResponse();
+ }
+
+ void Prepend(const TString& moreContent)
+ {
+ Content.prepend(moreContent);
+ BuildResponse();
+ }
+
+ virtual const char* what() const noexcept { return HttpResponse.data(); }
+ operator bool() const { return !Content.empty(); }
+};
+
+enum EStyleFlags {
+ // bit 1
+ Link = 0x0,
+ Button = 0x1,
+
+ // bit 2
+ NonErasable = 0x0,
+ Erasable = 0x2,
+
+ // bit 3-4
+ Medium = 0x0,
+ Large = 0x4,
+ Small = 0x8,
+ ExtraSmall = 0xC,
+ SizeMask = 0xC,
+
+ // bit 5
+ NoCaret = 0x0,
+ Caret = 0x10,
+
+ // bit 6
+ SimpleValue = 0x0,
+ CompositeValue = 0x20
+};
+
+template <ui64 flags>
+TString BtnClass() {
+ if ((flags & SizeMask) == Large) {
+ return "btn btn-lg";
+ } else if ((flags & SizeMask) == Small) {
+ return "btn btn-sm";
+ } else if ((flags & SizeMask) == ExtraSmall) {
+ return "btn btn-xs";
+ }
+ return "btn";
+}
+
+void SelectorTitle(IOutputStream& os, const TString& text)
+{
+ if (!text.empty()) {
+ os << text;
+ }
+}
+
+template <ui64 flags>
+void BtnHref(IOutputStream& os, const TString& text, const TString& href, bool push = false)
+{
+ if (flags & Button) {
+ os << "<button type=\"button\" style=\"display: inline-block;margin:3px\" class=\""
+ << BtnClass<flags>() << " "
+ << (push? "btn-primary": "btn-default")
+ << "\" onClick=\"window.location.href='" << href << "';\">"
+ << text
+ << "</button>";
+ } else {
+ os << "<a href=\"" << href << "\">"
+ << text
+ << "</a>";
+ }
+}
+
+void DropdownBeginSublist(IOutputStream& os, const TString& text)
+{
+ os << "<li>" << text << "<ul class=\"dropdown-menu\">";
+}
+
+void DropdownEndSublist(IOutputStream& os)
+{
+ os << "</ul></li>";
+}
+
+void DropdownItem(IOutputStream& os, const TString& text, const TString& href, bool separated = false)
+{
+ if (separated) {
+ os << "<li role=\"separator\" class=\"divider\"></li>";
+ }
+ os << "<li><a href=\"" << href << "\">" << text << "</a></li>";
+}
+
+TString SuggestSelection()
+{
+ return "--- ";
+}
+
+TString RemoveSelection()
+{
+ return "Remove";
+}
+
+TString GetDescription(const TString& value, const TVariants& variants)
+{
+ for (const auto& var : variants) {
+ if (value == var.first) {
+ return var.second;
+ }
+ }
+ if (!value) {
+ return SuggestSelection();
+ }
+ return value;
+}
+
+template <ui64 flags, bool sub = false>
+void DropdownSelector(IOutputStream& os, const TCgiParameters& e, const TString& param, const TString& value,
+ const TString& text, const TVariants& variants, const TString& realValue = TString())
+{
+ HTML(os) {
+ SelectorTitle(os, text);
+ os << "<div class=\"dropdown\" style=\"display:inline-block;margin:3px\">";
+ if (flags & Button) {
+ os << "<button class=\"" << BtnClass<flags>() << " btn-primary dropdown-toggle\" type=\"button\" data-toggle=\"dropdown\">";
+ } else {
+ os << "<a href=\"#\" data-toggle=\"dropdown\">";
+ }
+ os << GetDescription(flags & CompositeValue? realValue: value, variants);
+ if (flags & Caret) {
+ os << "<span class=\"caret\"></span>";
+ }
+ if (flags & Button) {
+ os <<"</button>";
+ } else {
+ os <<"</a>";
+ }
+ UL_CLASS ("dropdown-menu") {
+ for (const auto& var : variants) {
+ DropdownItem(os, var.second, UrlReplace<sub>(e, param, value, var.first));
+ }
+ if (flags & Erasable) {
+ DropdownItem(os, RemoveSelection(), UrlErase<sub>(e, param, value), true);
+ }
+ }
+ os << "</div>";
+ }
+}
+
+void RequireSelection(TStringStream& ss, const TCgiParameters& e, const TString& param,
+ const TString& text, const TVariants& variants)
+{
+ const TString& value = e.Get(param);
+ DropdownSelector<Link>(ss, e, param, value, text, variants);
+ if (!value) {
+ throw TPageGen<TSelectorsContainer>(ss.Str());
+ }
+}
+
+void RequireMultipleSelection(TStringStream& ss, const TCgiParameters& e, const TString& param,
+ const TString& text, const TVariants& variants)
+{
+ SelectorTitle(ss, text);
+ TSet<TString> selectedValues;
+ for (const TString& subvalue : Subvalues(e, param)) {
+ selectedValues.insert(subvalue);
+ }
+ for (const TString& subvalue : Subvalues(e, param)) {
+ DropdownSelector<Erasable, true>(ss, e, param, subvalue, "", variants);
+ }
+ if (selectedValues.contains("")) {
+ throw TPageGen<TSelectorsContainer>(ss.Str());
+ } else {
+ BtnHref<Button|ExtraSmall>(ss, "+", MakeUrlAddSub(e, param, ""));
+ if (selectedValues.empty()) {
+ throw TPageGen<TSelectorsContainer>(ss.Str());
+ }
+ }
+}
+
+void OptionalSelection(TStringStream& ss, const TCgiParameters& e, const TString& param,
+ const TString& text, const TVariants& variants)
+{
+ TSet<TString> selectedValues;
+ for (const TString& subvalue : Subvalues(e, param)) {
+ selectedValues.insert(subvalue);
+ }
+ if (!selectedValues.empty()) {
+ SelectorTitle(ss, text);
+ }
+ for (const TString& subvalue : Subvalues(e, param)) {
+ DropdownSelector<Erasable, true>(ss, e, param, subvalue, "", variants);
+ }
+ if (selectedValues.empty()) {
+ BtnHref<Button|ExtraSmall>(ss, text, MakeUrlAddSub(e, param, ""));
+ }
+}
+
+void OptionalMultipleSelection(TStringStream& ss, const TCgiParameters& e, const TString& param,
+ const TString& text, const TVariants& variants)
+{
+ TSet<TString> selectedValues;
+ for (const TString& subvalue : Subvalues(e, param)) {
+ selectedValues.insert(subvalue);
+ }
+ if (!selectedValues.empty()) {
+ SelectorTitle(ss, text);
+ }
+ for (const TString& subvalue : Subvalues(e, param)) {
+ DropdownSelector<Erasable, true>(ss, e, param, subvalue, "", variants);
+ }
+ if (selectedValues.contains("")) {
+ throw TPageGen<TSelectorsContainer>(ss.Str());
+ } else {
+ BtnHref<Button|ExtraSmall>(ss, selectedValues.empty()? text: "+", MakeUrlAddSub(e, param, ""));
+ }
+}
+
+TVariants ListColumns(const NAnalytics::TTable& table)
+{
+ TSet<TString> cols;
+// bool addSpecialCols = false;
+// if (addSpecialCols) {
+// cols.insert("_count");
+// }
+ for (auto& row : table) {
+ for (auto& kv : row) {
+ cols.insert(kv.first);
+ }
+ }
+ TVariants result;
+ for (const auto& s : cols) {
+ result.emplace_back(s, s);
+ }
+ return result;
+}
+
+TString TaggedValue(const TString& value, const TString& tag)
+{
+ if (!tag) {
+ return value;
+ }
+ return value + "-" + tag;
+}
+
+TVariants ValueVars(const TVariants& values, const TString& tag)
+{
+ TVariants ret;
+ for (auto& p : values) {
+ ret.emplace_back(TaggedValue(p.first, tag), p.second);
+ }
+ return ret;
+}
+
+TVariants TagVars(const TString& value, const TVariants& tags)
+{
+ TVariants ret;
+ for (auto& p : tags) {
+ ret.emplace_back(TaggedValue(value, p.first), p.second);
+ }
+ return ret;
+}
+
+TVariants SeriesTags()
+{
+ TVariants ret; // MSVS2013 doesn't understand complex initializer lists
+ ret.emplace_back("", "as is");
+ ret.emplace_back("stack", "cumulative");
+ return ret;
+}
+
+void SeriesSelectors(TStringStream& ss, const TCgiParameters& e,
+ const TString& xparam, const TString& yparam, const NAnalytics::TTable& data)
+{
+ TTags xtags;
+ TString xn = ParseTagsOut(e.Get(xparam), xtags);
+ DropdownSelector<Erasable, true>(ss, e, xparam, e.Get(xparam), "with Ox:",
+ ValueVars(ListColumns(data), JoinTags(xtags)));
+ if (xn) {
+ DropdownSelector<Link, true>(ss, e, xparam, e.Get(xparam), "",
+ TagVars(xn, SeriesTags()));
+ }
+
+ TString yns = e.Get(yparam);
+ SelectorTitle(ss, "and Oy:");
+ bool first = true;
+ bool hasEmpty = false;
+ for (auto& subvalue : Subvalues(e, yparam)) {
+ TTags ytags;
+ TString yn = ParseTagsOut(subvalue, ytags);
+ DropdownSelector<Erasable, true>(ss, e, yparam, subvalue, first? "": ", ",
+ ValueVars(ListColumns(data), JoinTags(ytags)));
+ if (yn) {
+ DropdownSelector<Link, true>(ss, e, yparam, subvalue, "",
+ TagVars(yn, SeriesTags()));
+ }
+ first = false;
+ if (yn.empty()) {
+ hasEmpty = true;
+ }
+ }
+
+ if (hasEmpty) {
+ throw TPageGen<TSelectorsContainer>(ss.Str());
+ } else {
+ BtnHref<Button|ExtraSmall>(ss, "+", MakeUrlAddSub(e, yparam, ""));
+ }
+
+ if (!xn || !yns) {
+ throw TPageGen<TSelectorsContainer>(ss.Str());
+ }
+}
+
+class TProbesHtmlPrinter {
+private:
+ TVector<TVector<TString>> TableData;
+ static constexpr int TimeoutSec = 15 * 60; // default timeout
+public:
+ void Push(const NLWTrace::TProbe* probe)
+ {
+ TableData.emplace_back();
+ auto& row = TableData.back();
+
+ row.emplace_back();
+ TString& groups = row.back();
+ bool first = true;
+ for (const char* const* i = probe->Event.Groups; *i != nullptr; ++i, first = false) {
+ groups.append(TString(first? "": ", ") + GroupHtml(*i));
+ }
+
+ row.push_back(ProbeHtml(probe->Event.GetProvider(), probe->Event.Name));
+
+ row.emplace_back();
+ TString& params = row.back();
+ first = true;
+ for (size_t i = 0; i < probe->Event.Signature.ParamCount; i++, first = false) {
+ params.append(TString(first? "": ", ") + probe->Event.Signature.ParamTypes[i]
+ + " " + probe->Event.Signature.ParamNames[i]);
+ }
+
+ row.emplace_back(ToString(probe->GetExecutorsCount()));
+ }
+
+ void Output(IOutputStream& os)
+ {
+ HTML(os) {
+ TABLE() {
+ TABLEHEAD() {
+ TABLEH() { os << "Groups"; }
+ TABLEH() { os << "Name"; }
+ TABLEH() { os << "Params"; }
+ TABLEH() { os << "ExecCount"; }
+ }
+ TABLEBODY() {
+ for (auto& row : TableData) {
+ TABLER() {
+ for (TString& cell : row) {
+ TABLED() { os << cell; }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+private:
+ TString GroupHtml(const TString& group)
+ {
+ TStringStream ss;
+ ss << "<div class=\"dropdown\" style=\"display:inline-block\">"
+ "<a href=\"#\" data-toggle=\"dropdown\">" << group << "</a>"
+ "<ul class=\"dropdown-menu\">"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "',"
+ "{id:'" << TAdHocTraceConfig(group).Id() << "'});\">"
+ "Trace 1000 items</a></li>"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "',"
+ "{id:'" << TAdHocTraceConfig(group, 10000).Id() << "'});\">"
+ "Trace 10000 items</a></li>"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "',"
+ "{id:'" << TAdHocTraceConfig(group, 0, 1000000).Id() << "'});\">"
+ "Trace 1 second</a></li>"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "',"
+ "{id:'" << TAdHocTraceConfig(group, 0, 10000000).Id() << "'});\">"
+ "Trace 10 seconds</a></li>"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "',"
+ "{id:'" << TAdHocTraceConfig(group, 0, 0, true).Id() << "'});\">"
+ "Trace 1000 tracks</a></li>"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "',"
+ "{id:'" << TAdHocTraceConfig(group, 10000, 0, true).Id() << "'});\">"
+ "Trace 10000 tracks</a></li>"
+ "</ul>"
+ "</div>";
+ return ss.Str();
+ }
+
+ TString ProbeHtml(const TString& provider, const TString& probe)
+ {
+ TStringStream ss;
+ ss << "<div class=\"dropdown\">"
+ "<a href=\"#\" data-toggle=\"dropdown\">" << probe << "</a>"
+ "<ul class=\"dropdown-menu\">"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "',"
+ "{id:'" << TAdHocTraceConfig(provider, probe).Id() << "'});\">"
+ "Trace 1000 items</a></li>"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "',"
+ "{id:'" << TAdHocTraceConfig(provider, probe, 10000).Id() << "'});\">"
+ "Trace 10000 items</a></li>"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "',"
+ "{id:'" << TAdHocTraceConfig(provider, probe, 0, 1000000).Id() << "'});\">"
+ "Trace 1 second</a></li>"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "',"
+ "{id:'" << TAdHocTraceConfig(provider, probe, 0, 10000000).Id() << "'});\">"
+ "Trace 10 seconds</a></li>"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "',"
+ "{id:'" << TAdHocTraceConfig(provider, probe, 0, 0, true).Id() << "'});\">"
+ "Trace 1000 tracks</a></li>"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=new&ui=y&timeout=" << TimeoutSec << "',"
+ "{id:'" << TAdHocTraceConfig(provider, probe, 10000, 0, true).Id() << "'});\">"
+ "Trace 10000 tracks</a></li>"
+ "</ul>"
+ "</div>";
+ return ss.Str();
+ }
+};
+
+void TDashboardRegistry::Register(const NLWTrace::TDashboard& dashboard) {
+ TGuard<TMutex> g(Mutex);
+ Dashboards[dashboard.GetName()] = dashboard;
+}
+
+void TDashboardRegistry::Register(const TVector<NLWTrace::TDashboard>& dashboards) {
+ for (const auto& dashboard : dashboards) {
+ Register(dashboard);
+ }
+}
+
+void TDashboardRegistry::Register(const TString& dashText) {
+ NLWTrace::TDashboard dash;
+ if (!google::protobuf::TextFormat::ParseFromString(dashText, &dash)) {
+ ythrow yexception() << "Couldn't parse into dashboard";
+ }
+ Register(dash);
+}
+
+bool TDashboardRegistry::Get(const TString& name, NLWTrace::TDashboard& dash) {
+ TGuard<TMutex> g(Mutex);
+ if (!Dashboards.contains(name)) {
+ return false;
+ }
+ dash = Dashboards[name];
+ return true;
+}
+
+void TDashboardRegistry::Output(TStringStream& ss) {
+ HTML(ss) {
+ TABLE() {
+ TABLEHEAD() {
+ TABLEH() { ss << "Name"; }
+ }
+ TABLEBODY() {
+ TGuard<TMutex> g(Mutex);
+ for (auto& kv : Dashboards) {
+ const auto& dash = kv.second;
+ TABLER() {
+ TABLED() {
+ ss << "<a href='?mode=dashboard&name=" << dash.GetName() << "'>" << dash.GetName() << "</a>";
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+class ILogSource {
+public:
+ virtual ~ILogSource() {}
+ virtual TString GetId() = 0;
+ virtual TInstant GetStartTime() = 0;
+ virtual TDuration GetTimeout(TInstant now) = 0;
+ virtual ui64 GetEventsCount() = 0;
+ virtual ui64 GetThreadsCount() = 0;
+};
+
+class TTraceLogSource : public ILogSource {
+private:
+ TString Id;
+ const TTraceCleaner& Cleaner;
+ const NLWTrace::TSession* Trace;
+public:
+ TTraceLogSource(const TString& id, const NLWTrace::TSession* trace, const TTraceCleaner& cleaner)
+ : Id(id)
+ , Cleaner(cleaner)
+ , Trace(trace)
+ {}
+
+ TString GetId() override
+ {
+ return Id;
+ }
+
+ TInstant GetStartTime() override
+ {
+ return Trace->GetStartTime();
+ }
+
+ TDuration GetTimeout(TInstant now) override
+ {
+ TInstant deadline = Cleaner.GetDeadline(Id);
+ if (deadline < now) {
+ return TDuration::Zero();
+ } else if (deadline == TInstant::Max()) {
+ return TDuration::Max();
+ } else {
+ return deadline - now;
+ }
+ }
+
+ ui64 GetEventsCount() override
+ {
+ return Trace->GetEventsCount();
+ }
+
+ ui64 GetThreadsCount() override
+ {
+ return Trace->GetThreadsCount();
+ }
+};
+
+class TSnapshotLogSource : public ILogSource {
+private:
+ TString Sid;
+ // Log should be used for read-only purpose, because it can be accessed from multiple threads
+ // Atomic pointer is used to avoid thread-safety issues with snapshot deletion
+ // (I hope protobuf const-implementation doesn't use any mutable non-thread-safe stuff inside)
+ TAtomicSharedPtr<NLWTrace::TLogPb> Log;
+public:
+ // Constructor should be called under SnapshotsMtx lock
+ TSnapshotLogSource(const TString& sid, const TAtomicSharedPtr<NLWTrace::TLogPb>& log)
+ : Sid(sid)
+ , Log(log)
+ {}
+
+ TString GetId() override
+ {
+ return Sid + "~";
+ }
+
+ TInstant GetStartTime() override
+ {
+ return TInstant::MicroSeconds(Log->GetCrtTime());
+ }
+
+ TDuration GetTimeout(TInstant now) override
+ {
+ Y_UNUSED(now);
+ return TDuration::Max();
+ }
+
+ ui64 GetEventsCount() override
+ {
+ return Log->GetEventsCount();
+ }
+
+ ui64 GetThreadsCount() override
+ {
+ return Log->ThreadLogsSize();
+ }
+};
+
+class TLogSources {
+private:
+ TTraceCleaner& Cleaner;
+ TInstant Now;
+ using TLogSourcePtr = std::unique_ptr<ILogSource>;
+ TMap<TString, TLogSourcePtr> LogSources;
+public:
+ explicit TLogSources(TTraceCleaner& cleaner, TInstant now = TInstant::Now())
+ : Cleaner(cleaner)
+ , Now(now)
+ {}
+
+ void Push(const TString& sid, const TAtomicSharedPtr<NLWTrace::TLogPb>& log)
+ {
+ TLogSourcePtr ls(new TSnapshotLogSource(sid, log));
+ LogSources.emplace(ls->GetId(), std::move(ls));
+ }
+
+ void Push(const TString& id, const NLWTrace::TSession* trace)
+ {
+ TLogSourcePtr ls(new TTraceLogSource(id, trace, Cleaner));
+ LogSources.emplace(ls->GetId(), std::move(ls));
+ }
+
+ template <class TFunc>
+ void ForEach(TFunc& func)
+ {
+ for (auto& kv : LogSources) {
+ func.Push(kv.second.get());
+ }
+ }
+
+ template <class TFunc>
+ void ForEach(TFunc& func) const
+ {
+ for (const auto& kv : LogSources) {
+ func.Push(kv.second.get());
+ }
+ }
+};
+
+class TTracesHtmlPrinter {
+private:
+ IOutputStream& Os;
+ TInstant Now;
+public:
+ explicit TTracesHtmlPrinter(IOutputStream& os)
+ : Os(os)
+ , Now(TInstant::Now())
+ {}
+
+ void Push(ILogSource* src)
+ {
+ TString id = src->GetId();
+ Os << "<tr>";
+ Os << "<td>";
+ try {
+ Os << src->GetStartTime().ToStringUpToSeconds();
+ } catch (...) {
+ Os << "error: " << CurrentExceptionMessage();
+ }
+ Os << "</td>"
+ << "<td><div class=\"dropdown\">"
+ "<a href=\"#\" data-toggle=\"dropdown\">" << TimeoutToString(src->GetTimeout(Now)) << "</a>"
+ "<ul class=\"dropdown-menu\">"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y&timeout=60', {id:'" << id << "'});\">1 min</a></li>"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y&timeout=600', {id:'" << id << "'});\">10 min</a></li>"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y&timeout=3600', {id:'" << id << "'});\">1 hour</a></li>"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y&timeout=86400', {id:'" << id << "'});\">1 day</a></li>"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y&timeout=604800', {id:'" << id << "'});\">1 week</a></li>"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=settimeout&ui=y', {id:'" << id << "'});\">no timeout</a></li>"
+ "</ul>"
+ "</div></td>"
+ << "<td>" << EncodeHtmlPcdata(id) << "</td>"
+ << "<td>" << src->GetEventsCount() << "</td>"
+ << "<td>" << src->GetThreadsCount() << "</td>"
+ << "<td><a href=\"?mode=log&id=" << id << "\">Text</a></td>"
+ << "<td><a href=\"?mode=log&format=json&id=" << id << "\">Json</a></td>"
+ << "<td><a href=\"?mode=query&id=" << id << "\">Query</a></td>"
+ << "<td><a href=\"?mode=analytics&id=" << id << "\">Analytics</a></td>"
+ << "<td><div class=\"dropdown navbar-right\">" // navbar-right is hack to drop left
+ "<a href=\"#\" data-toggle=\"dropdown\">Modify</a>"
+ "<ul class=\"dropdown-menu\">"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=make_snapshot&ui=y', {id:'" << id << "'});\">Snapshot</a></li>"
+ "<li><a href=\"#\" onClick=\"$.redirectPost('?mode=delete&ui=y', {id:'" << id << "'});\">Delete</a></li>"
+ "</ul>"
+ "</div></td>"
+ << "</tr>\n";
+ }
+private:
+ static TString TimeoutToString(TDuration d)
+ {
+ TStringStream ss;
+ if (d == TDuration::Zero()) {
+ ss << "0";
+ } else if (d == TDuration::Max()) {
+ ss << "-";
+ } else {
+ ui64 us = d.GetValue();
+ ui64 ms = us / 1000;
+ ui64 sec = ms / 1000;
+ ui64 min = sec / 60;
+ ui64 hours = min / 60;
+ ui64 days = hours / 24;
+ ui64 weeks = days / 7;
+ us -= ms * 1000;
+ ms -= sec * 1000;
+ sec -= min * 60;
+ min -= hours * 60;
+ hours -= days * 24;
+ days -= weeks * 7;
+ int terms = 0;
+ if ((terms > 0 && terms < 2) || ( terms == 0 && weeks)) { ss << (ss.Str()? " ": "") << weeks << "w"; terms++; }
+ if ((terms > 0 && terms < 2) || ( terms == 0 && days)) { ss << (ss.Str()? " ": "") << days << "d"; terms++; }
+ if ((terms > 0 && terms < 2) || ( terms == 0 && hours)) { ss << (ss.Str()? " ": "") << hours << "h"; terms++; }
+ if ((terms > 0 && terms < 2) || ( terms == 0 && min)) { ss << (ss.Str()? " ": "") << min << "m"; terms++; }
+ if ((terms > 0 && terms < 2) || ( terms == 0 && sec)) { ss << (ss.Str()? " ": "") << sec << "s"; terms++; }
+ if ((terms > 0 && terms < 2) || ( terms == 0 && ms)) { ss << (ss.Str()? " ": "") << ms << "ms"; terms++; }
+ if ((terms > 0 && terms < 2) || ( terms == 0 && us)) { ss << (ss.Str()? " ": "") << us << "us"; terms++; }
+ }
+ return ss.Str();
+ }
+};
+
+class TTracesLister {
+private:
+ TVariants& Variants;
+public:
+ TTracesLister(TVariants& variants)
+ : Variants(variants)
+ {}
+ void Push(ILogSource* src)
+ {
+ Variants.emplace_back(src->GetId(), src->GetId());
+ }
+};
+
+TVariants ListTraces(const TLogSources& srcs)
+{
+ TVariants variants;
+ TTracesLister lister(variants);
+ srcs.ForEach(lister);
+ return variants;
+}
+
+class TTimestampCutter {
+private:
+ THashMap<TThread::TId, std::pair<ui64, TInstant>> CutTsForThread; // tid -> time of first item
+ mutable ui64 CutTsMax = 0;
+ mutable TInstant CutInstantMax;
+ bool Enabled;
+ ui64 NowTs;
+public:
+ explicit TTimestampCutter(bool enabled)
+ : Enabled(enabled)
+ , NowTs(GetCycleCount())
+ {}
+
+ void Push(TThread::TId tid, const NLWTrace::TLogItem& item)
+ {
+ auto it = CutTsForThread.find(tid);
+ if (it != CutTsForThread.end()) {
+ ui64& ts = it->second.first;
+ TInstant& inst = it->second.second;
+ ts = Min(ts, item.TimestampCycles);
+ inst = Min(inst, item.Timestamp);
+ } else {
+ CutTsForThread[tid] = std::make_pair(item.TimestampCycles, item.Timestamp);
+ }
+ }
+
+ // Timestamp from which we are ensured that cyclic log for every thread is not truncated
+ // NOTE: should NOT be called from Push(tid, item) functions
+ ui64 StartTimestamp() const
+ {
+ if (CutTsMax == 0) {
+ FindStartTime();
+ }
+ return CutTsMax;
+ }
+
+ ui64 NowTimestamp() const
+ {
+ return NowTs;
+ }
+
+ TInstant StartInstant() const
+ {
+ if (CutInstantMax == TInstant::Zero()) {
+ FindStartTime();
+ }
+ return CutInstantMax;
+ }
+
+ // Returns true iff item should be skipped to avoid surprizes
+ bool Skip(const NLWTrace::TLogItem& item) const
+ {
+ return Enabled && item.TimestampCycles < StartTimestamp();
+ }
+
+private:
+ void FindStartTime() const
+ {
+ for (auto& kv : CutTsForThread) {
+ CutTsMax = Max(CutTsMax, kv.second.first);
+ CutInstantMax = Max(CutInstantMax, kv.second.second);
+ }
+ }
+};
+
+class TLogFilter {
+private:
+ struct TFilter {
+ TString ParamName;
+ TString ParamValue;
+ bool Parsed;
+
+ TLogQuery Query;
+ NLWTrace::TLiteral Value;
+
+ explicit TFilter(const TString& text)
+ {
+ if (!text) { // Neither ParamName nor ParamValue is selected
+ ParamName.clear();
+ ParamValue.clear();
+ Parsed = false;
+ return;
+ }
+ size_t pos = text.find('=');
+ if (pos == TString::npos) { // Only ParamName has been selected
+ ParamName = text;
+ ParamValue.clear();
+ Parsed = false;
+ return;
+ }
+ // Both ParamName and ParamValue have been selected
+ ParamValue = text.substr(pos + 1);
+ ParamName = text.substr(0, pos);
+ Parsed = true;
+
+ Query = TLogQuery(ParamName);
+ Value = NLWTrace::TLiteral(ParamValue);
+ }
+ };
+ TVector<TFilter> Filters;
+ THashSet<const NLWTrace::TSignature*> Signatures; // Just to list param names
+ TVariants ParamNames;
+ THashMap<TString, THashSet<TString>> FilteredParamValues; // paramName -> { paramValue }
+public:
+ explicit TLogFilter(const TVector<TString>& filters)
+ {
+ for (const TString& subvalue : filters) {
+ TFilter filter(subvalue);
+ FilteredParamValues[filter.ParamName]; // just create empty set to gather values later
+ if (filter.Parsed) {
+ Filters.push_back(filter);
+ }
+ }
+ }
+
+ virtual ~TLogFilter() {}
+
+ template <class TLog>
+ bool Filter(const TLog& log)
+ {
+ Gather(log);
+ for (const TFilter& filter : Filters) {
+ if (filter.Query.ExecuteQuery(log) != filter.Value) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void FilterSelectors(TStringStream& ss, const TCgiParameters& e, const TString& fparam)
+ {
+ bool first = true;
+ bool allParsed = true;
+ for (const TString& subvalue : Subvalues(e, fparam)) {
+ TFilter filter(subvalue);
+ allParsed = allParsed && filter.Parsed;
+ if (first) {
+ SelectorTitle(ss, "where");
+ }
+ DropdownSelector<Erasable | CompositeValue, true>(
+ ss, e, fparam, subvalue, first? "": ", ", ListParamNames(),
+ filter.ParamName
+ );
+ if (filter.ParamName) {
+ DropdownSelector<Link | CompositeValue, true>(
+ ss, e, fparam, subvalue, "=", ListParamValues(filter.ParamName),
+ filter.ParamValue? (filter.ParamName + "=" + filter.ParamValue): ""
+ );
+ }
+ first = false;
+ }
+
+ if (!allParsed) {
+ throw TPageGen<TSelectorsContainer>(ss.Str());
+ } else {
+ BtnHref<Button|ExtraSmall>(ss, first? "where": "+", MakeUrlAddSub(e, fparam, ""));
+ }
+ }
+
+ const TVariants& ListParamNames()
+ {
+ if (ParamNames.empty()) {
+ THashSet<TString> paramNames;
+ for (const NLWTrace::TSignature* sgn: Signatures) {
+ for (size_t pi = 0; pi < sgn->ParamCount; pi++) {
+ paramNames.insert(sgn->ParamNames[pi]);
+ }
+ }
+ for (auto& pn : paramNames) {
+ ParamNames.emplace_back(pn, pn);
+ }
+ }
+ return ParamNames;
+ }
+
+ bool IsFiltered(const TString& paramName) const
+ {
+ return FilteredParamValues.contains(paramName);
+ }
+
+private:
+ // Gather param names and values for selectors
+ void Gather(const NLWTrace::TLogItem& item)
+ {
+ Signatures.insert(&item.Probe->Event.Signature);
+ if (!FilteredParamValues.empty() && item.SavedParamsCount > 0) {
+ TString paramValues[LWTRACE_MAX_PARAMS];
+ item.Probe->Event.Signature.SerializeParams(item.Params, paramValues);
+ for (size_t pi = 0; pi < item.SavedParamsCount; pi++) {
+ auto iter = FilteredParamValues.find(item.Probe->Event.Signature.ParamNames[pi]);
+ if (iter != FilteredParamValues.end()) {
+ iter->second.insert(paramValues[pi]);
+ }
+ }
+ }
+ }
+
+ void Gather(const NLWTrace::TTrackLog& tl)
+ {
+ for (const NLWTrace::TLogItem& item : tl.Items) {
+ Gather(item);
+ }
+ }
+
+ TVariants ListParamValues(const TString& paramName) const
+ {
+ TVariants result;
+ auto iter = FilteredParamValues.find(paramName);
+ if (iter != FilteredParamValues.end()) {
+ for (const TString& paramValue : iter->second) {
+ result.emplace_back(paramName + "=" + paramValue, paramValue);
+ }
+ }
+ Sort(result.begin(), result.end());
+ return result;
+ }
+};
+
+static void EscapeJSONString(IOutputStream& os, const TString& s)
+{
+ for (TString::const_iterator i = s.begin(), e = s.end(); i != e; ++i) {
+ char c = *i;
+ if (c < ' ') {
+ os << Sprintf("\\u%04x", int(c));
+ } else if (c == '"') {
+ os << "\\\"";
+ } else if (c == '\\') {
+ os << "\\\\";
+ } else {
+ os << c;
+ }
+ }
+}
+
+static TString EscapeJSONString(const TString& s)
+{
+ TStringStream ss;
+ EscapeJSONString(ss, s);
+ return ss.Str();
+}
+
+class TLogJsonPrinter {
+private:
+ IOutputStream& Os;
+ bool FirstThread;
+ bool FirstItem;
+public:
+ explicit TLogJsonPrinter(IOutputStream& os)
+ : Os(os)
+ , FirstThread(true)
+ , FirstItem(true)
+ {}
+
+ void OutputHeader()
+ {
+ Os << "{\n\t\"source\": \"" << HostName() << "\""
+ "\n\t, \"items\": ["
+ ;
+ }
+
+ void OutputFooter(const NLWTrace::TSession* trace)
+ {
+ Os << "\n\t\t]"
+ "\n\t, \"threads\": ["
+ ;
+ trace->ReadThreads(*this);
+ Os << "]"
+ "\n\t, \"events_count\": " << trace->GetEventsCount() <<
+ "\n\t, \"threads_count\": " << trace->GetThreadsCount() <<
+ "\n\t, \"timestamp\": " << Now().GetValue() <<
+ "\n}"
+ ;
+ }
+
+ void PushThread(TThread::TId tid)
+ {
+ Os << (FirstThread? "": ", ") << tid;
+ FirstThread = false;
+ }
+
+ void Push(TThread::TId tid, const NLWTrace::TLogItem& item)
+ {
+ Os << "\n\t\t" << (FirstItem? "": ", ");
+ FirstItem = false;
+
+ Os << "[" << tid <<
+ ", " << item.Timestamp.GetValue() <<
+ ", \"" << item.Probe->Event.GetProvider() << "\""
+ ", \"" << item.Probe->Event.Name << "\""
+ ", {"
+ ;
+ if (item.SavedParamsCount > 0) {
+ TString ParamValues[LWTRACE_MAX_PARAMS];
+ item.Probe->Event.Signature.SerializeParams(item.Params, ParamValues);
+ bool first = true;
+ for (size_t i = 0; i < item.SavedParamsCount; i++, first = false) {
+ Os << (first? "": ", ") << "\"" << item.Probe->Event.Signature.ParamNames[i] << "\": \"";
+ EscapeJSONString(Os, ParamValues[i]);
+ Os << "\"";
+ }
+ }
+ Os << "}]";
+ }
+};
+
+class TLogTextPrinter : public TLogFilter {
+private:
+ TMultiMap<NLWTrace::TTypedParam, std::pair<TThread::TId, NLWTrace::TLogItem> > Items;
+ TMultiMap<NLWTrace::TTypedParam, NLWTrace::TTrackLog> Depot;
+ THashMap<NLWTrace::TProbe*, size_t> ProbeId;
+ TVector<NLWTrace::TProbe*> Probes;
+ TTimestampCutter CutTs;
+ TLogQuery Order;
+ bool ReverseOrder = false;
+ ui64 Head = 0;
+ ui64 Tail = 0;
+ bool ShowTs = false;
+public:
+ TLogTextPrinter(const TVector<TString>& filters, ui64 head, ui64 tail, const TString& order, bool reverseOrder, bool cutTs, bool showTs)
+ : TLogFilter(filters)
+ , CutTs(cutTs)
+ , Order(order)
+ , ReverseOrder(reverseOrder)
+ , Head(head)
+ , Tail(tail)
+ , ShowTs(showTs)
+ {}
+
+ TLogTextPrinter(const TCgiParameters& e)
+ : TLogTextPrinter(
+ Subvalues(e, "f"),
+ e.Has("head")? FromString<ui64>(e.Get("head")): 0,
+ e.Has("tail")? FromString<ui64>(e.Get("tail")): 0,
+ e.Get("s"),
+ e.Get("reverse") == "y",
+ e.Get("cutts") == "y",
+ e.Get("showts") == "y")
+ {}
+
+ enum EFormat {
+ Text,
+ Json
+ };
+
+ void Output(IOutputStream& os) const
+ {
+ OutputItems<Text>(os);
+ OutputDepot<Text>(os);
+ }
+
+ void OutputJson(IOutputStream& os) const
+ {
+ os << "{\"depot\":[\n";
+ OutputItems<Json>(os);
+ OutputDepot<Json>(os);
+ os << "],\"probes\":[";
+ bool first = true;
+ for (const NLWTrace::TProbe* probe : Probes) {
+ os << (first? "": ",") << "{\"provider\":\"" << probe->Event.GetProvider()
+ << "\",\"name\":\"" << probe->Event.Name << "\"}";
+ first = false;
+ }
+ os << "]}";
+ }
+
+ NLWTrace::TTypedParam GetKey(const NLWTrace::TLogItem& item)
+ {
+ return Order? Order.ExecuteQuery(item): NLWTrace::TTypedParam(item.GetTimestampCycles());
+ }
+
+ NLWTrace::TTypedParam GetKey(const NLWTrace::TTrackLog& tl)
+ {
+ return Order? Order.ExecuteQuery(tl): NLWTrace::TTypedParam(tl.GetTimestampCycles());
+ }
+
+ void Push(TThread::TId tid, const NLWTrace::TLogItem& item)
+ {
+ CutTs.Push(tid, item);
+ if (Filter(item)) {
+ AddId(item);
+ Items.emplace(GetKey(item), std::make_pair(tid, item));
+ }
+ }
+
+ void Push(TThread::TId tid, const NLWTrace::TTrackLog& tl)
+ {
+ Y_UNUSED(tid);
+ if (Filter(tl)) {
+ AddId(tl);
+ Depot.emplace(GetKey(tl), tl);
+ }
+ }
+
+private:
+ void AddId(const NLWTrace::TLogItem& item)
+ {
+ if (ProbeId.find(item.Probe) == ProbeId.end()) {
+ size_t id = Probes.size();
+ ProbeId[item.Probe] = id;
+ Probes.emplace_back(item.Probe);
+ }
+ }
+
+ void AddId(const NLWTrace::TTrackLog& tl)
+ {
+ for (const auto& item : tl.Items) {
+ AddId(item);
+ }
+ }
+
+ bool HeadTailFilter(ui64 idx, ui64 size) const
+ {
+ bool headOk = idx < Head;
+ bool tailOk = size < Tail + idx + 1ull;
+ if (Head && Tail) {
+ return headOk || tailOk;
+ } else if (Head) {
+ return headOk;
+ } else if (Tail) {
+ return tailOk;
+ } else {
+ return true;
+ }
+ }
+
+ template <EFormat Format>
+ void OutputItems(IOutputStream& os) const
+ {
+ ui64 idx = 0;
+ ui64 size = Items.size();
+ ui64 startTs = ShowTs? CutTs.StartTimestamp(): 0;
+ ui64 prevTs = 0;
+ bool first = true;
+ if (!ReverseOrder) {
+ for (auto i = Items.begin(), e = Items.end(); i != e; ++i, idx++) {
+ if (HeadTailFilter(idx, size)) {
+ OutputItem<Format, true>(os, i->second.first, i->second.second, startTs, prevTs, first);
+ prevTs = startTs? i->second.second.GetTimestampCycles(): 0;
+ }
+ }
+ } else {
+ for (auto i = Items.rbegin(), e = Items.rend(); i != e; ++i, idx++) {
+ if (HeadTailFilter(idx, size)) {
+ OutputItem<Format, true>(os, i->second.first, i->second.second, startTs, prevTs, first);
+ prevTs = startTs? i->second.second.GetTimestampCycles(): 0;
+ }
+ }
+ }
+ }
+
+ template <EFormat Format>
+ void OutputDepot(IOutputStream& os) const
+ {
+ ui64 idx = 0;
+ ui64 size = Depot.size();
+ bool first = true;
+ if (!ReverseOrder) {
+ for (auto i = Depot.begin(), e = Depot.end(); i != e; ++i, idx++) {
+ if (HeadTailFilter(idx, size)) {
+ OutputTrackLog<Format>(os, i->second, first);
+ }
+ }
+ } else {
+ for (auto i = Depot.rbegin(), e = Depot.rend(); i != e; ++i, idx++) {
+ if (HeadTailFilter(idx, size)) {
+ OutputTrackLog<Format>(os, i->second, first);
+ }
+ }
+ }
+ }
+
+ template <EFormat Format, bool AsTrack = false>
+ void OutputItem(IOutputStream& os, TThread::TId tid, const NLWTrace::TLogItem& item, ui64 startTs, ui64 prevTs, bool& first) const
+ {
+ if (CutTs.Skip(item)) {
+ return;
+ }
+ if constexpr (Format == Text) {
+ if (startTs) {
+ if (!prevTs) {
+ prevTs = item.GetTimestampCycles();
+ }
+ os << Sprintf("%10.3lf %+10.3lf ms ",
+ NHPTimer::GetSeconds(item.GetTimestampCycles() - startTs) * 1000.0,
+ NHPTimer::GetSeconds(item.GetTimestampCycles() - prevTs) * 1000.0);
+ }
+ if (tid) {
+ os << "<" << tid << "> ";
+ }
+ if (item.Timestamp != TInstant::Zero()) {
+ os << "[" << item.Timestamp << "] ";
+ } else {
+ os << "[" << item.TimestampCycles << "] ";
+ }
+ os << GetProbeName(item.Probe) << "(";
+ if (item.SavedParamsCount > 0) {
+ TString ParamValues[LWTRACE_MAX_PARAMS];
+ item.Probe->Event.Signature.SerializeParams(item.Params, ParamValues);
+ bool first = true;
+ for (size_t i = 0; i < item.SavedParamsCount; i++, first = false) {
+ os << (first? "": ", ") << item.Probe->Event.Signature.ParamNames[i] << "='" << EscapeC(ParamValues[i]) << "'";
+ }
+ }
+ os << ")\n";
+ } else if constexpr (Format == Json) {
+ if (auto probeId = ProbeId.find(item.Probe); probeId != ProbeId.end()) {
+ os << (first? "": ",") << (AsTrack? "[":"") << "[\"" << tid << "\",\"";
+ if (item.Timestamp != TInstant::Zero()) {
+ os << item.Timestamp.MicroSeconds();
+ } else {
+ os << Sprintf("%.3lf", NHPTimer::GetSeconds(item.TimestampCycles) * 1e9);
+ }
+ os << "\"," << probeId->second << ",{";
+ if (item.SavedParamsCount > 0) {
+ TString ParamValues[LWTRACE_MAX_PARAMS];
+ item.Probe->Event.Signature.SerializeParams(item.Params, ParamValues);
+ bool first = true;
+ for (size_t i = 0; i < item.SavedParamsCount; i++, first = false) {
+ os << (first? "": ",") << "\"" << item.Probe->Event.Signature.ParamNames[i] << "\":\"";
+ EscapeJSONString(os, ParamValues[i]);
+ os << "\"";
+ }
+ }
+ os << "}]" << (AsTrack? "]":"");
+ }
+ }
+ first = false;
+ }
+
+ template <EFormat Format>
+ void OutputTrackLog(IOutputStream& os, const NLWTrace::TTrackLog& tl, bool& first) const
+ {
+ if constexpr (Format == Json) {
+ os << (first? "": ",") << "[";
+ }
+ first = false;
+ ui64 prevTs = tl.GetTimestampCycles();
+ bool firstItem = true;
+ for (const NLWTrace::TTrackLog::TItem& item: tl.Items) {
+ OutputItem<Format>(os, item.ThreadId, item, tl.GetTimestampCycles(), prevTs, firstItem);
+ prevTs = item.GetTimestampCycles();
+ }
+ if constexpr (Format == Json) {
+ os << "]";
+ }
+ os << "\n";
+ }
+};
+
+class TLogAnalyzer: public TLogFilter {
+private:
+ TMultiMap<ui64, std::pair<TThread::TId, NLWTrace::TLogItem>> Items;
+ TVector<NLWTrace::TTrackLog> Depot;
+ THashMap<TString, TTrackLogRefs> Groups;
+ NAnalytics::TTable Table;
+ bool TableCreated = false;
+ TVector<TString> GroupBy;
+ TTimestampCutter CutTs;
+public:
+ TLogAnalyzer(const TVector<TString>& filters, const TVector<TString>& groupBy, bool cutTs)
+ : TLogFilter(filters)
+ , CutTs(cutTs)
+ {
+ for (const TString& groupParam : groupBy) {
+ GroupBy.push_back(groupParam);
+ }
+ }
+
+ const NAnalytics::TTable& GetTable()
+ {
+ if (!TableCreated) {
+ TableCreated = true;
+ if (GroupBy.empty()) {
+ for (auto i = Items.begin(), e = Items.end(); i != e; ++i) {
+ ParseItems(i->second.first, i->second.second);
+ }
+ ParseDepot();
+ } else {
+ for (auto i = Items.begin(), e = Items.end(); i != e; ++i) {
+ Map(i->second.first, i->second.second);
+ }
+ Reduce();
+ }
+ }
+ return Table;
+ }
+
+ void Push(TThread::TId tid, const NLWTrace::TLogItem& item)
+ {
+ CutTs.Push(tid, item);
+ if (Filter(item)) {
+ Items.emplace(item.TimestampCycles, std::make_pair(tid, item));
+ }
+ }
+
+ void Push(TThread::TId, const NLWTrace::TTrackLog& tl)
+ {
+ if (Filter(tl)) {
+ Depot.emplace_back(tl);
+ }
+ }
+private:
+ void FillRow(NAnalytics::TRow& row, const NLWTrace::TLogItem& item)
+ {
+ if (item.SavedParamsCount > 0) {
+ TString paramValues[LWTRACE_MAX_PARAMS];
+ item.Probe->Event.Signature.SerializeParams(item.Params, paramValues);
+ for (size_t i = 0; i < item.SavedParamsCount; i++) {
+ double value = FromString<double>(paramValues[i].data(), paramValues[i].size(), NAN);
+ // If value cannot be cast to double or is inf/nan -- assume it's a string
+ if (isfinite(value)) {
+ row[item.Probe->Event.Signature.ParamNames[i]] = value;
+ } else {
+ row[item.Probe->Event.Signature.ParamNames[i]] = paramValues[i];
+ }
+ }
+ }
+ }
+
+ TString GetParam(const NLWTrace::TLogItem& item, TString* paramValues, const TString& paramName)
+ {
+ for (size_t pi = 0; pi < item.SavedParamsCount; pi++) {
+ if (paramName == item.Probe->Event.Signature.ParamNames[pi]) {
+ return paramValues[pi];
+ }
+ }
+ return TString();
+ }
+
+ TString GetGroup(const NLWTrace::TLogItem& item, TString* paramValues)
+ {
+ TStringStream ss;
+ bool first = true;
+ for (const TString& groupParam : GroupBy) {
+ ss << (first? "": "|") << GetParam(item, paramValues, groupParam);
+ first = false;
+ }
+ return ss.Str();
+ }
+
+ void ParseItems(TThread::TId tid, const NLWTrace::TLogItem& item)
+ {
+ if (CutTs.Skip(item)) {
+ return;
+ }
+ Table.emplace_back();
+ NAnalytics::TRow& row = Table.back();
+ row["_thread"] = tid;
+ if (item.Timestamp != TInstant::Zero()) {
+ row["_wallTime"] = item.Timestamp.SecondsFloat();
+ row["_wallRTime"] = item.Timestamp.SecondsFloat() - CutTs.StartInstant().SecondsFloat();
+ }
+ row["_cycles"] = item.TimestampCycles;
+ row["_thrTime"] = CyclesToDuration((ui64)item.TimestampCycles).SecondsFloat();
+ row["_thrRTime"] = double(i64(item.TimestampCycles) - i64(CutTs.StartTimestamp())) / NHPTimer::GetCyclesPerSecond();
+ row["_thrNTime"] = double(i64(item.TimestampCycles) - i64(CutTs.NowTimestamp())) / NHPTimer::GetCyclesPerSecond();
+ row.Name = GetProbeName(item.Probe);
+ FillRow(row, item);
+ }
+
+ void Map(TThread::TId tid, const NLWTrace::TLogItem& item)
+ {
+ if (item.SavedParamsCount > 0 && !CutTs.Skip(item)) {
+ TString paramValues[LWTRACE_MAX_PARAMS];
+ item.Probe->Event.Signature.SerializeParams(item.Params, paramValues);
+ TTrackLogRefs& tl = Groups[GetGroup(item, paramValues)];
+ tl.Items.emplace_back(tid, item);
+ }
+ }
+
+ void Reduce()
+ {
+ for (auto& v : Groups) {
+ const TString& group = v.first;
+ const TTrackLogRefs& tl = v.second;
+ Table.emplace_back();
+ NAnalytics::TRow& row = Table.back();
+ row.Name = group;
+ for (const NLWTrace::TLogItem& item : tl.Items) {
+ FillRow(row, item);
+ }
+ }
+ }
+
+ void ParseDepot()
+ {
+ for (NLWTrace::TTrackLog& tl : Depot) {
+ Table.emplace_back();
+ NAnalytics::TRow& row = Table.back();
+ for (const NLWTrace::TLogItem& item : tl.Items) {
+ FillRow(row, item);
+ }
+ }
+ }
+};
+
+struct TSampleOpts {
+ bool ShowProvider = false;
+ size_t SizeLimit = 50;
+};
+
+enum ENodeType {
+ NT_ROOT,
+ NT_PROBE,
+ NT_PARAM
+};
+
+class TPatternTree;
+struct TPatternNode;
+
+struct TTrack : public TTrackLogRefs {
+ TString TrackId;
+ TPatternNode* LastNode = nullptr;
+};
+
+using TTrackTr = TLogTraits<TTrackLogRefs>;
+using TTrackIter = TTrackTr::const_iterator;
+
+// Visitor for tree traversing
+class IVisitor {
+public:
+ virtual ~IVisitor() {}
+ virtual void Visit(TPatternNode* node) = 0;
+};
+
+// Per-node classifier
+class TClassifier {
+public:
+ explicit TClassifier(TPatternNode* node, ENodeType childType, bool keepHead = false)
+ : Node(node)
+ , KeepHead(keepHead)
+ , ChildType(childType)
+ {}
+ virtual ~TClassifier() {}
+ virtual TPatternNode* Classify(TTrackIter cur, const TTrack& track) = 0;
+ virtual void Accept(IVisitor* visitor) = 0;
+ virtual bool IsLeaf() = 0;
+ ENodeType GetChildType() const { return ChildType; }
+public:
+ TPatternNode* Node;
+ const bool KeepHead;
+ ENodeType ChildType;
+};
+
+// Track classification tree node
+struct TPatternNode {
+ TString Name;
+ TPatternNode* Parent = nullptr;
+ THolder<TClassifier> Classifier;
+ struct TDesc {
+ ENodeType Type = NT_ROOT;
+ // NT_PROBE
+ const NLWTrace::TProbe* Probe = nullptr;
+ // NT_PARAM
+ size_t Rollbacks = 0;
+ TString ParamName;
+ TString ParamValue;
+ } Desc;
+
+ ui64 TrackCount = 0;
+ struct TTrackEntry {
+ TTrack* Track;
+ ui64 ResTotal;
+ ui64 ResLast;
+
+ TTrackEntry(TTrack* track, ui64 resTotal, ui64 resLast)
+ : Track(track)
+ , ResTotal(resTotal)
+ , ResLast(resLast)
+ {}
+ };
+
+ TVector<TTrackEntry> Tracks;
+
+ ui64 ResTotalSum = 0;
+ ui64 ResTotalMax = 0;
+ TVector<ui64> ResTotalAll;
+
+ ui64 ResLastSum = 0;
+ ui64 ResLastMax = 0;
+ TVector<ui64> ResLastAll;
+
+ TVector<ui64> TimelineSum;
+ NAnalytics::TTable Slices;
+
+ TString GetPath() const
+ {
+ if (Parent) {
+ return Parent->GetPath() + Name;
+ }
+ return "/";
+ }
+
+ NAnalytics::TTable GetTable() const
+ {
+ using namespace NAnalytics;
+ NAnalytics::TTable ret;
+ for (ui64 x : ResTotalAll) {
+ ret.emplace_back();
+ TRow& row = ret.back();
+ row["resTotal"] = double(x) * 1000.0 / NHPTimer::GetClockRate();
+ }
+ for (ui64 x : ResLastAll) {
+ ret.emplace_back();
+ TRow& row = ret.back();
+ row["resLast"] = double(x) * 1000.0 / NHPTimer::GetClockRate();
+ }
+ return ret;
+ }
+
+ template <typename TReader>
+ void OutputSample(const TString& bn, double b1, double b2, const TSampleOpts& opts, TReader& reader) const
+ {
+ bool filterTotal = false;
+ if (bn == "resTotal") {
+ filterTotal = true;
+ } else {
+ WWW_CHECK(bn == "resLast", "wrong sample filter param: %s", bn.data());
+ }
+
+ size_t spaceLeft = opts.SizeLimit;
+ for (const TTrackEntry& entry : Tracks) {
+ const TTrack* track = entry.Track;
+ // Filter out tracks that are not in sample
+ if (filterTotal) {
+ double resTotalMs = double(entry.ResTotal) * 1000.0 / NHPTimer::GetClockRate();
+ if (resTotalMs < b1 || resTotalMs > b2) {
+ continue;
+ }
+ } else {
+ double resLastMs = double(entry.ResLast) * 1000.0 / NHPTimer::GetClockRate();
+ if (resLastMs < b1 || resLastMs > b2) {
+ continue;
+ }
+ }
+
+ NLWTrace::TTrackLog tl;
+ for (TTrackIter i = TTrackTr::begin(*track), e = TTrackTr::end(*track); i != e; ++i) {
+ const NLWTrace::TLogItem& item = *i;
+ const auto threadId = i->ThreadId;
+ tl.Items.push_back(NLWTrace::TTrackLog::TItem(threadId, item));
+ }
+ reader.Push(0, tl);
+ if (spaceLeft) {
+ spaceLeft--;
+ if (!spaceLeft) {
+ break;
+ }
+ }
+ }
+ }
+};
+
+// Track classification tree
+class TPatternTree {
+public:
+ // Per-node classifier by probe name
+ class TClassifyByProbe : public TClassifier {
+ private:
+ using TChildren = THashMap<NLWTrace::TProbe*, TPatternNode>;
+ TChildren Children;
+ TVector<TChildren::value_type*> SortedChildren;
+ public:
+ explicit TClassifyByProbe(TPatternNode* node)
+ : TClassifier(node, NT_PROBE)
+ {}
+
+ TPatternNode* Classify(TTrackIter cur, const TTrack& track) override
+ {
+ Y_UNUSED(track);
+ const NLWTrace::TLogItem& item = *cur;
+ TPatternNode* node = &Children[item.Probe];
+ node->Name = "/" + GetProbeName(item.Probe);
+ node->Desc.Type = NT_PROBE;
+ node->Desc.Probe = item.Probe;
+ return node;
+ }
+
+ void Accept(IVisitor* visitor) override
+ {
+ if (SortedChildren.size() != Children.size()) {
+ SortedChildren.clear();
+ SortedChildren.reserve(Children.size());
+ for (auto i = Children.begin(), e = Children.end(); i != e; ++i) {
+ SortedChildren.push_back(&*i);
+ }
+ Sort(SortedChildren, [] (TChildren::value_type* lhs, TChildren::value_type* rhs) {
+ NLWTrace::TProbe* lp = lhs->first;
+ NLWTrace::TProbe* rp = rhs->first;
+ if (int cmp = strcmp(lp->Event.GetProvider(), rp->Event.GetProvider())) {
+ return cmp < 0;
+ }
+ return strcmp(lp->Event.Name, rp->Event.Name) < 0;
+ });
+ }
+ for (auto* kv : SortedChildren) {
+ visitor->Visit(&kv->second);
+ }
+ }
+
+ bool IsLeaf() override { return Children.empty(); }
+ };
+
+ // Per-node classifier by probe param value
+ class TClassifyByParam : public TClassifier {
+ private:
+ size_t Rollbacks; // How many items should we look back in track to locate probe
+ TString ParamName;
+ using TChildren = THashMap<TString, TPatternNode>;
+ TChildren Children;
+ TVector<TChildren::value_type*> SortedChildren;
+ public:
+ TClassifyByParam(TPatternNode* node, size_t rollbacks, const TString& paramName)
+ : TClassifier(node, NT_PARAM, true)
+ , Rollbacks(rollbacks)
+ , ParamName(paramName)
+ {}
+
+ TPatternNode* Classify(TTrackIter cur, const TTrack& track) override
+ {
+ WWW_CHECK((i64)Rollbacks >= 0 && std::distance(TTrackTr::begin(track), cur) >= (i64)Rollbacks, "wrong rollbacks in node '%s'",
+ Node->GetPath().data());
+ const NLWTrace::TLogItem& item = *(cur - Rollbacks);
+ WWW_CHECK(item.SavedParamsCount > 0, "classify by params on probe w/o param loggging in node '%s'",
+ Node->GetPath().data());
+ TString paramValues[LWTRACE_MAX_PARAMS];
+ TString* paramValue = nullptr;
+ item.Probe->Event.Signature.SerializeParams(item.Params, paramValues);
+ for (size_t pi = 0; pi < item.SavedParamsCount; pi++) {
+ if (item.Probe->Event.Signature.ParamNames[pi] == ParamName) {
+ paramValue = &paramValues[pi];
+ }
+ }
+ WWW_CHECK(paramValue, "param '%s' not found in probe '%s' at path '%s'",
+ ParamName.data(), GetProbeName(item.Probe).data(), Node->GetPath().data());
+
+ TPatternNode* node = &Children[*paramValue];
+ // Path example: "//Provider1.Probe1/Provider2.Probe2@1.xxx=123@2.type=harakiri"
+ node->Name = "@" + ToString(Rollbacks) + "." + ParamName + "=" + *paramValue;
+ node->Desc.Type = NT_PARAM;
+ node->Desc.Rollbacks = Rollbacks;
+ node->Desc.ParamName = ParamName;
+ node->Desc.ParamValue = *paramValue;
+ return node;
+ }
+
+ void Accept(IVisitor* visitor) override
+ {
+ if (SortedChildren.size() != Children.size()) {
+ SortedChildren.clear();
+ SortedChildren.reserve(Children.size());
+ for (auto i = Children.begin(), e = Children.end(); i != e; ++i) {
+ SortedChildren.push_back(&*i);
+ }
+ Sort(SortedChildren, [] (TChildren::value_type* lhs, TChildren::value_type* rhs) {
+ return lhs->first < rhs->first;
+ });
+ }
+ for (auto* kv : SortedChildren) {
+ visitor->Visit(&kv->second);
+ }
+ }
+
+ bool IsLeaf() override { return Children.empty(); }
+ };
+private:
+ TPatternNode Root;
+ THashMap<TString, std::pair<size_t, TString>> ParamClassifiers; // path -> (rollbacks, param)
+ TString SelectedPattern;
+ TPatternNode* SelectedNode = nullptr;
+ TVector<ui64> Timeline; // Just to avoid reallocations
+public:
+ TPatternTree(const TCgiParameters& e)
+ {
+ for (const TString& cl : Subvalues(e, "classify")) {
+ size_t at = cl.find_last_of('@');
+ if (at != TString::npos) {
+ size_t dot = cl.find('.', at + 1);
+ if (dot != TString::npos) {
+ size_t rollbacks = FromString<size_t>(cl.substr(at + 1, dot - at - 1));
+ ParamClassifiers[cl.substr(0, at)] = std::make_pair(rollbacks, cl.substr(dot + 1));
+ }
+ }
+ }
+ SelectedPattern = e.Get("pattern");
+ InitNode(&Root, nullptr);
+ }
+
+ TPatternNode* GetSelectedNode()
+ {
+ return SelectedNode;
+ }
+
+ NAnalytics::TTable GetSelectedTable()
+ {
+ if (SelectedNode) {
+ return SelectedNode->GetTable();
+ } else {
+ return NAnalytics::TTable();
+ }
+ }
+
+ template <typename TReader>
+ void OutputSelectedSample(const TString& bn, double b1, double b2, const TSampleOpts& opts, TReader& reader)
+ {
+ if (SelectedNode) {
+ SelectedNode->OutputSample(bn, b1, b2, opts, reader);
+ }
+ }
+
+ // Register track in given node
+ void AddTrackToNode(TPatternNode* node, TTrack& track, ui64 resTotal, TVector<ui64>& timeline)
+ {
+ if (!SelectedNode) {
+ if (node->GetPath() == SelectedPattern) {
+ SelectedNode = node;
+ }
+ }
+
+ // Counting
+ node->TrackCount++;
+
+ // Resource total
+ node->ResTotalSum += resTotal;
+ node->ResTotalMax = Max(node->ResTotalMax, resTotal);
+ node->ResTotalAll.push_back(resTotal);
+
+ // Resource last
+ ui64 resLast = 0;
+ resLast = resTotal - (timeline.size() < 2? 0: timeline[timeline.size() - 2]);
+ node->ResLastSum += resLast;
+ node->ResLastMax = Max(node->ResLastMax, resLast);
+ node->ResLastAll.push_back(resLast);
+
+ // Timeline
+ if (node->TimelineSum.size() < timeline.size()) {
+ node->TimelineSum.resize(timeline.size());
+ }
+ for (size_t i = 0; i < timeline.size(); i++) {
+ node->TimelineSum[i] += timeline[i];
+ }
+
+ if (node == SelectedNode && !timeline.empty()) {
+ node->Slices.emplace_back();
+ NAnalytics::TRow& row = node->Slices.back();
+ ui64 prev = 0;
+ for (size_t i = 0; i < timeline.size(); i++) {
+ // Note that col names should go in lexicographical order
+ // in the same way as slices go in pattern timeline
+ double sliceMs = double(timeline[i] - prev) * 1000.0 / NHPTimer::GetClockRate();
+ row[Sprintf("%09lu", i)] = sliceMs;
+ prev = timeline[i];
+ }
+ }
+
+ // Interlink node and track
+ node->Tracks.emplace_back(&track, resTotal, resLast);
+ track.LastNode = node;
+ }
+
+ bool CheckPattern(const char*& pi, const char* pe, TStringBuf str)
+ {
+ auto si = str.begin(), se = str.end();
+ for (;pi != pe && si != se; ++pi, ++si) {
+ if (*pi != *si) {
+ return false;
+ }
+ }
+ return si == se;
+ }
+
+#define WWW_CHECK_PATTERN(str) if (!CheckPattern(pi, pe, (str))) { return false; }
+
+ bool MatchTrack(const TTrack& track, const TString& patternStr)
+ {
+ const char* pi = patternStr.data();
+ const char* pe = pi + patternStr.size();
+ WWW_CHECK_PATTERN("/");
+ for (TTrackIter i = TTrackTr::begin(track), e = TTrackTr::end(track); i != e; ++i) {
+ if (pi == pe) {
+ return true;
+ }
+ const NLWTrace::TLogItem& item = *i;
+ WWW_CHECK_PATTERN("/");
+ WWW_CHECK_PATTERN(item.Probe->Event.GetProvider());
+ WWW_CHECK_PATTERN(".");
+ WWW_CHECK_PATTERN(item.Probe->Event.Name);
+ while (true) {
+ if (pi == pe) {
+ return true;
+ }
+ char c = *pi;
+ if (c == '/') {
+ break;
+ } else if (c == '@') {
+ pi++;
+ // Parse rollbacks
+ TStringBuf p(pi, pe);
+ size_t dot = p.find('.');
+ if (dot == TStringBuf::npos) {
+ return false;
+ }
+ size_t rollbacks = 0;
+ try {
+ rollbacks = FromString<size_t>(p.substr(0, dot));
+ } catch (...) {
+ return false;
+ }
+
+ // Parse param name
+ size_t equals = p.find('=', dot + 1);
+ if (equals == TStringBuf::npos) {
+ return false;
+ }
+ TStringBuf paramName = p.substr(dot + 1, equals - dot - 1);
+
+ pi += equals + 1; // Advance to value
+
+ // Check param value
+ if ((i64)rollbacks < 0 || std::distance(TTrackTr::begin(track), i) < (i64)rollbacks) {
+ return false;
+ }
+ const NLWTrace::TLogItem& mitem = *(i - rollbacks);
+ if (mitem.SavedParamsCount == 0) {
+ return false;
+ }
+ TString paramValues[LWTRACE_MAX_PARAMS];
+ TString* paramValue = nullptr;
+ mitem.Probe->Event.Signature.SerializeParams(mitem.Params, paramValues);
+ for (size_t pi = 0; pi < mitem.SavedParamsCount; pi++) {
+ if (mitem.Probe->Event.Signature.ParamNames[pi] == paramName) {
+ paramValue = &paramValues[pi];
+ }
+ }
+ if (!paramValue) {
+ return false;
+ }
+ WWW_CHECK_PATTERN(*paramValue);
+ } else {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+#undef WWW_CHECK_PATTERN
+
+ // Push new track through pattern tree
+ void AddTrack(TTrack& track)
+ {
+ // Truncate long tracks
+ if (track.Items.size() > 50) {
+ track.Items.resize(50);
+ }
+
+ if (SelectedPattern) {
+ if (!MatchTrack(track, SelectedPattern)) {
+ return;
+ }
+ }
+
+ Timeline.clear();
+ TPatternNode* node = &Root;
+ AddTrackToNode(node, track, 0, Timeline);
+ ui64 trackStart = TTrackTr::front(track).TimestampCycles;
+ for (TTrackIter i = TTrackTr::begin(track), e = TTrackTr::end(track); i != e;) {
+ // Get or create child by classification
+ TPatternNode* parent = node;
+ node = node->Classifier->Classify(i, track);
+ if (!node->Classifier) {
+ InitNode(node, parent);
+ }
+
+ const NLWTrace::TLogItem& item = *i;
+ ui64 resTotal = item.TimestampCycles - trackStart;
+ if (i != TTrackTr::begin(track)) {
+ Timeline.push_back(resTotal);
+ }
+ AddTrackToNode(node, track, resTotal, Timeline);
+
+ // Move through track
+ if (!node->Classifier->KeepHead) {
+ ++i;
+ }
+ }
+ }
+
+ // Traverse pattern tree (the only way to extract data from it)
+ template <class TOnNode, class TOnDescend, class TOnAscend>
+ void Traverse(TOnNode&& onNode, TOnDescend&& onDescend, TOnAscend&& onAscend)
+ {
+ struct TVisitor : public IVisitor {
+ TOnNode OnNode;
+ TOnDescend OnDescend;
+ TOnAscend OnAscend;
+ TVisitor(TOnNode&& onNode, TOnDescend&& onDescend, TOnAscend&& onAscend)
+ : OnNode(onNode)
+ , OnDescend(onDescend)
+ , OnAscend(onAscend)
+ {}
+ virtual void Visit(TPatternNode* node) override
+ {
+ OnNode(node);
+ if (!node->Classifier->IsLeaf()) {
+ OnDescend();
+ node->Classifier->Accept(this);
+ OnAscend();
+ }
+ }
+ };
+ TVisitor visitor(std::move(onNode), std::move(onDescend), std::move(onAscend));
+ visitor.Visit(&Root);
+ }
+
+ TPatternNode* GetRoot()
+ {
+ return &Root;
+ }
+
+private:
+ void InitNode(TPatternNode* node, TPatternNode* parent)
+ {
+ node->Parent = parent;
+ auto iter = ParamClassifiers.find(node->GetPath());
+ if (iter != ParamClassifiers.end()) {
+ node->Classifier.Reset(new TClassifyByParam(node, iter->second.first, iter->second.second));
+ } else {
+ node->Classifier.Reset(new TClassifyByProbe(node));
+ }
+ }
+};
+
+class TLogTrackExtractor: public TLogFilter {
+private:
+ // Data storage
+ TMultiMap<ui64, std::pair<TThread::TId, NLWTrace::TLogItem>> Items;
+ TVector<NLWTrace::TTrackLog> Depot;
+
+ // Data refs organized in tracks
+ THashMap<TString, TTrack> Tracks;
+ TVector<TTrack> TracksFromDepot;
+
+ // Analysis
+ TVector<TString> GroupBy;
+ THashSet<TString> TrackIds; // The same content as in GroupBy
+ TTimestampCutter CutTs;
+ TPatternTree Tree;
+public:
+ TLogTrackExtractor(const TCgiParameters& e, const TVector<TString>& filters, const TVector<TString>& groupBy)
+ : TLogFilter(filters)
+ , CutTs(true) // Always cut input data for tracks
+ , Tree(e)
+ {
+ for (const TString& groupParam : groupBy) {
+ GroupBy.push_back(groupParam);
+ TrackIds.insert(groupParam);
+ }
+ }
+
+ // For reading lwtrace log (input point for all data)
+ void Push(TThread::TId tid, const NLWTrace::TLogItem& item)
+ {
+ CutTs.Push(tid, item);
+ if (Filter(item)) {
+ Items.emplace(item.TimestampCycles, std::make_pair(tid, item));
+ }
+ }
+
+ // For reading lwtrace depot (input point for all data)
+ void Push(TThread::TId, const NLWTrace::TTrackLog& tl)
+ {
+ if (Filter(tl)) {
+ Depot.emplace_back(tl);
+ }
+ }
+
+ // Analyze logs that have been read
+ void Run()
+ {
+ RunImplLog();
+ RunImplDepot();
+ }
+
+ void RunImplLog()
+ {
+ // Create tracks by filling them with lwtrace items in order of occurance time
+ for (auto& kv : Items) {
+ AddItemToTrack(kv.second.first, kv.second.second);
+ }
+ // Push tracks throught pattern tree
+ for (auto& kv : Tracks) {
+ TTrack& track = kv.second;
+ track.TrackId = kv.first;
+ Tree.AddTrack(track);
+ }
+ }
+
+ void RunImplDepot()
+ {
+ // Create tracks from depot
+ // OPTIMIZE[serxa]: this convertion is not necessary, done just to keep things simple
+ for (NLWTrace::TTrackLog& tl : Depot) {
+ TTrack& track = TracksFromDepot.emplace_back();
+ track.TrackId = ToString(tl.Id);
+ for (const NLWTrace::TTrackLog::TItem& i : tl.Items) {
+ track.Items.emplace_back(i.ThreadId, i);
+ }
+ }
+ for (TTrack& t : TracksFromDepot) {
+ Tree.AddTrack(t);
+ }
+ }
+
+ // Selected node distribution
+ NAnalytics::TTable Distribution(const TString& bn, const TString& b1Str, const TString& b2Str, const TString& widthStr)
+ {
+ using namespace NAnalytics;
+
+ const NAnalytics::TTable& inputTable = Tree.GetSelectedTable();
+ double b1 = b1Str? FromString<double>(b1Str): MinValue(bn, inputTable);
+ double b2 = b2Str? FromString<double>(b2Str): MaxValue(bn, inputTable);
+ if (isfinite(b1) && isfinite(b2)) {
+ WWW_CHECK(b1 <= b2, "invalid xrange [%le; %le]", b1, b2);
+ double width = widthStr? FromString<double>(widthStr): 99;
+ double dx = (b2 - b1) / width;
+ if (!(dx > 0)) {
+ dx = 1.0;
+ }
+ return HistogramAll(inputTable, bn, b1, b2, dx);
+ } else {
+ // Empty table -- it's ok -- leave data table empty
+ return NAnalytics::TTable();
+ }
+ }
+
+ // Selected sample
+ template <typename TReader>
+ void OutputSample(const TString& bn, double b1, double b2, const TSampleOpts& opts, TReader& reader)
+ {
+ Tree.OutputSelectedSample(bn, b1, b2, opts, reader);
+ }
+
+ // Tabular representation of tracks data
+ void OutputTable(IOutputStream& os, const TCgiParameters& e)
+ {
+ ui64 tracksTotal = Tree.GetRoot()->TrackCount;
+
+ double maxAvgResTotal = 0;
+ double maxMaxResTotal = 0;
+ Tree.Traverse([&] (TPatternNode* node) {
+ if (node->TrackCount > 0) {
+ maxAvgResTotal = Max(maxAvgResTotal, double(node->ResTotalSum) / node->TrackCount);
+ maxMaxResTotal = Max(maxMaxResTotal, double(node->ResTotalMax));
+ Sort(node->ResTotalAll);
+ Sort(node->ResLastAll);
+ }
+ }, [&] () { // On descend
+ }, [&] () { // On ascend
+ });
+ double maxTime = Min(maxMaxResTotal, 1.25 * maxAvgResTotal);
+
+ double percentile = e.Get("ile")? FromString<double>(e.Get("ile")): 90;
+ WWW_CHECK(percentile >= 0.0 && percentile <= 100.0, "wrong percentile: %lf", percentile);
+
+ ui64 row = 0;
+ TVector<ui64> chain;
+ HTML(os) {
+ TABLE_CLASS("tracks-tree") {
+ TABLEHEAD() {
+ os << "<tr>";
+ os << "<td rowspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">#</td>";
+ os << "<td rowspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">Pattern</td>";
+ os << "<td rowspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">";
+ DIV_CLASS("rotate") { os << "Track Count"; }
+ os << "</td>";
+ os << "<td colspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">Share</td>";
+ os << "<td colspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">Total, ms</td>";
+ os << "<td colspan=\"2\" style=\"vertical-align:bottom\" align=\"center\">Last, ms</td>";
+ os << "<td rowspan=\"2\" style=\"vertical-align:bottom\" class=\"timelinehead\" align=\"center\">Global Timeline</td>";
+ os << "</tr><tr>";
+ TABLEH() DIV_CLASS("rotate") { os << "Absolute"; }
+ TABLEH() DIV_CLASS("rotate") { os << "Relative"; }
+ TABLEH() DIV_CLASS("rotate") { os << "Average"; }
+ TABLEH() DIV_CLASS("rotate") { os << percentile << "%-ile"; }
+ TABLEH() DIV_CLASS("rotate") { os << "Average"; }
+ TABLEH() DIV_CLASS("rotate") { os << percentile << "%-ile"; }
+ os << "</tr>";
+ }
+ TABLEBODY() {
+ if (tracksTotal == 0) {
+ return;
+ }
+ Tree.Traverse([&] (TPatternNode* node) {
+ TString parentClass;
+ if (!chain.empty()) {
+ parentClass = " treegrid-parent-" + ToString(chain.back());
+ }
+ TString selectedClass;
+ if (e.Get("pattern") == node->GetPath()) {
+ selectedClass = " danger";
+ }
+ TABLER_CLASS("treegrid-" + ToString(++row) + parentClass + selectedClass) {
+ // Counting
+ ui64 tracksParent = node->Parent? node->Parent->TrackCount: tracksTotal;
+ double absShare = double(node->TrackCount) * 100 / tracksTotal;
+ double relShare = double(node->TrackCount) * 100 / tracksParent;
+
+ // Resource total
+ double avgResTotal = double(node->ResTotalSum) / node->TrackCount;
+ size_t ileResTotalIdx = node->ResTotalAll.size() * percentile / 100;
+ if (ileResTotalIdx > 0) {
+ ileResTotalIdx--;
+ }
+ double ileResTotal = double(ileResTotalIdx >= node->ResTotalAll.size()? 0: node->ResTotalAll[ileResTotalIdx]);
+ double avgResTotalMs = avgResTotal * 1000.0 / NHPTimer::GetClockRate();
+ double ileResTotalMs = ileResTotal * 1000.0 / NHPTimer::GetClockRate();
+
+ // Resource last
+ double avgResLast = double(node->ResLastSum) / node->TrackCount;
+ size_t ileResLastIdx = node->ResLastAll.size() * percentile / 100;
+ if (ileResLastIdx > 0) {
+ ileResLastIdx--;
+ }
+ double ileResLast = double(ileResLastIdx >= node->ResLastAll.size()? 0: node->ResLastAll[ileResLastIdx]);
+ double avgResLastMs = avgResLast * 1000.0 / NHPTimer::GetClockRate();
+ double ileResLastMs = ileResLast * 1000.0 / NHPTimer::GetClockRate();
+
+ // Output
+ TABLED() { os << row; }
+ TABLED_CLASS("treegrid-element") { OutputPattern(os, e, node); }
+ TABLED() { os << node->TrackCount; }
+ TABLED() { OutputShare(os, absShare); }
+ TABLED() { OutputShare(os, relShare); }
+ TABLED() { os << FormatFloat(avgResTotalMs); }
+ TABLED() { os << FormatFloat(ileResTotalMs); }
+ TABLED() { os << FormatFloat(avgResLastMs); }
+ TABLED() { os << FormatFloat(ileResLastMs); }
+ TABLED() { OutputTimeline(os, MakeTimeline(node), maxTime); }
+ }
+ }, [&] () { // On descend
+ chain.push_back(row);
+ }, [&] () { // On ascend
+ chain.pop_back();
+ });
+ }
+ }
+ }
+ }
+
+ // Chromium-compatible trace representation of tracks data
+ void OutputChromeTrace(IOutputStream& os, const TCgiParameters& e)
+ {
+ Y_UNUSED(e);
+ TChromeTrace tr;
+ for (TPatternNode::TTrackEntry& entry: Tree.GetRoot()->Tracks) {
+ TTrack* track = entry.Track;
+ auto first = TTrackTr::begin(*track);
+ auto last = TTrackTr::rbegin(*track);
+
+ TString name = track->LastNode->GetPath();
+
+ const NLWTrace::TLogItem& firstItem = *first;
+ TThread::TId firstTid = first->ThreadId;
+ tr.Add(firstTid, firstItem.TimestampCycles, "b", "track", nullptr, name, track->TrackId);
+
+ for (auto cur = TTrackTr::begin(*track), end = TTrackTr::end(*track); cur != end; ++cur) {
+ const NLWTrace::TLogItem& item = *cur;
+
+ tr.Add(cur->ThreadId, item.TimestampCycles, "i", "event", &item, GetProbeName(item.Probe));
+
+ TString sliceName = GetProbeName(item.Probe);
+
+ auto next = cur + 1;
+ if (next != end) {
+ const NLWTrace::TLogItem& nextItem = *next;
+ tr.Add(cur->ThreadId, item.TimestampCycles, "b", "track", &item, sliceName, track->TrackId);
+ tr.Add(next->ThreadId, nextItem.TimestampCycles, "e", "track", &nextItem, sliceName, track->TrackId);
+ } else {
+ tr.Add(cur->ThreadId, item.TimestampCycles, "n", "track", &item, sliceName, track->TrackId);
+ }
+ }
+
+ const NLWTrace::TLogItem& lastItem = *last;
+ tr.Add(last->ThreadId, lastItem.TimestampCycles, "e", "track", nullptr, name, track->TrackId);
+ }
+ tr.Output(os);
+ }
+
+ void OutputSliceCovarianceMatrix(IOutputStream& os, const TCgiParameters& e)
+ {
+ Y_UNUSED(e);
+ TPatternNode* node = Tree.GetSelectedNode();
+ if (!node) {
+ return;
+ }
+
+ NAnalytics::TMatrix covMatrix = NAnalytics::CovarianceMatrix(node->Slices);
+ double var = covMatrix.CellSum();
+
+ double covMax = 0.0;
+ for (double x : covMatrix) {
+ if (covMax < x) {
+ covMax = x;
+ }
+ }
+ double dangerCov = covMax * 0.9 * 0.9;
+ double warnCov = covMax * 0.5 * 0.5;
+
+ HTML(os) {
+ TABLE() {
+ TTimeline timeline = MakeTimeline(node);
+ TABLEHEAD() TABLER() {
+ TABLED();
+ for (auto& e : timeline) TABLED() {
+ TPatternNode* subnode = e.first;
+ os << subnode->Name;
+ }
+ }
+
+ auto tl = timeline.begin();
+ TABLEBODY() for (size_t row = 0; row < covMatrix.Rows; row++) TABLER() {
+ TABLEH() {
+ if (tl != timeline.end()) {
+ TPatternNode* subnode = tl->first;
+ os << subnode->Name;
+ ++tl;
+ }
+ }
+
+ for (size_t col = 0; col < covMatrix.Cols; col++) {
+ double cov = covMatrix.Cell(row, col);
+ TString tdClass = (cov >= dangerCov? "danger": (cov >= warnCov? "warning": ""));
+ TABLED_CLASS(tdClass) {
+ double sigmaX = (covMatrix.Cell(row, row) > 0? sqrt(covMatrix.Cell(row, row)): 0);
+ double sigmaY = (covMatrix.Cell(col, col) > 0? sqrt(covMatrix.Cell(col, col)): 0);
+ os << Sprintf("cov=%.3lf&nbsp;ms<sup>2</sup>&nbsp;(%.3lf&nbsp;ms) corr=%.1lf%% var_share=%.1lf%%",
+ cov, sqrt(abs(cov)), cov * 100.0 / sigmaX / sigmaY, cov * 100.0 / var);
+ }
+ }
+ }
+ }
+ }
+ }
+
+private:
+ TPatternNode* RollbackFind(TPatternNode* node)
+ {
+ for (;node != nullptr; node = node->Parent) {
+ if (node->Desc.Type == NT_PROBE) {
+ return node;
+ }
+ }
+ return nullptr;
+ }
+
+ void OutputPattern(IOutputStream& os, const TCgiParameters& e, TPatternNode* node)
+ {
+ // Fill pattern name
+ TString patternName;
+ TString patternTitle;
+ switch (node->Desc.Type) {
+ case NT_ROOT:
+ patternName = "All Tracks";
+ break;
+ case NT_PROBE:
+ patternTitle = GetProbeName(node->Desc.Probe);
+ patternName = node->Desc.Probe->Event.Name;
+ break;
+ case NT_PARAM:
+ patternName.append(node->Desc.ParamName + " = " + node->Desc.ParamValue);
+ break;
+ }
+
+ os << "<a href=\"" << MakeUrl(e, {
+ {"pattern", node->GetPath()},
+ {"ptrn_anlz", e.Get("ptrn_anlz") ? e.Get("ptrn_anlz") : "resTotal"},
+ {"linesfill", "y"},
+ {"linessteps", "y"},
+ {"pointsshow", "n"},
+ {"sel_x1", e.Get("sel_x1") ? e.Get("sel_x1") : "0"},
+ {"sel_x2", e.Get("sel_x2") ? e.Get("sel_x2") : "inf"}}) << "\""
+ " title=\"" + patternTitle + "\">" << patternName << "</a>";
+
+ // Add/remove node menu
+ if (node->Desc.Type != NT_ROOT) {
+ os << "<div class=\"dropdown pull-right\" style=\"display:inline-block\">";
+ if (node->Desc.Type == NT_PARAM) {
+ os<< "<button class=\"btn btn-xs btn-default\" type=\"button\""
+ << "\" onClick=\"window.location.href='"
+ << MakeUrlEraseSub(e, "classify", node->Parent->GetPath() + "@"
+ + ToString(node->Desc.Rollbacks) + "." + node->Desc.ParamName)
+ << "';\">"
+ "<span class=\"glyphicon glyphicon-minus\"></span>"
+ "</button>";
+ }
+ if (node->Classifier->GetChildType() != NT_PARAM) {
+ os << "<button class=\"btn btn-xs btn-default dropdown-toggle\" type=\"button\""
+ " data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"true\">"
+ "<span class=\"glyphicon glyphicon-plus\"></span>"
+ "</button>"
+ "<ul class=\"dropdown-menu\">"
+ "<li class=\"dropdown-header\">Classify by param:</li>";
+ int rollbacks = 0;
+ TPatternNode* probeNode = node;
+ while (probeNode = RollbackFind(probeNode)) {
+ const NLWTrace::TProbe* probe = probeNode->Desc.Probe;
+ os << "<li class=\"dropdown-header\">" << GetProbeName(probe) << "</li>";
+ const NLWTrace::TSignature* sgn = &probe->Event.Signature;
+ for (size_t pi = 0; pi < sgn->ParamCount; pi++) {
+ TString param = sgn->ParamNames[pi];
+ if (TrackIds.contains(param) || IsFiltered(param)) {
+ continue;
+ }
+ os << "<li><a href=\""
+ << MakeUrlAddSub(e, "classify", node->GetPath() + "@" + ToString(rollbacks) + "." + param)
+ << "\">" << param << "</a></li>";
+ }
+ rollbacks++;
+ probeNode = probeNode->Parent;
+ }
+ os << "</ul>";
+ }
+ os << "</div>";
+ }
+ }
+
+ void OutputShare(IOutputStream& os, double share)
+ {
+ double lshare = share;
+ double rshare = 100 - lshare;
+ os << "<div class=\"progress\" style=\"margin-bottom:0px;position:relative\">"
+ "<div class=\"progress-bar progress-bar-success\" role=\"progressbar\""
+ " aria-valuenow=\"" << lshare << "\""
+ " aria-valuemin=\"0\""
+ " aria-valuemax=\"100\""
+ " style=\"width: " << lshare << "%;\">"
+ "</div>"
+ "<div class=\"progress-bar progress-bar-danger\" role=\"progressbar\""
+ " aria-valuenow=\"" << rshare << "\""
+ " aria-valuemin=\"0\""
+ " aria-valuemax=\"100\""
+ " style=\"width: " << rshare << "%;\">"
+ "</div>"
+ "<span style=\"position:absolute;left:0;width:100%;text-align:center;z-index:2;color:white\">"
+ << (share == 100? "100%": Sprintf("%2.1lf%%", share)) <<
+ "</span>"
+ "</div>";
+ }
+
+ using TTimeline = TVector<std::pair<TPatternNode*, double>>;
+
+ TTimeline MakeTimeline(TPatternNode* node)
+ {
+ TTimeline ret;
+ if (node->TrackCount == 0) {
+ return ret;
+ }
+ ret.reserve(node->TimelineSum.size());
+ for (double time : node->TimelineSum) {
+ ret.emplace_back(nullptr, double(time) / node->TrackCount);
+ }
+ TPatternNode* n = node;
+ for (auto i = ret.rbegin(), e = ret.rend(); i != e; ++i) {
+ WWW_CHECK(n, "internal bug: wrong timeline length at pattern node '%s'", node->GetPath().data());
+ i->first = n;
+ n = n->Parent;
+ }
+ return ret;
+ }
+
+ void OutputTimeline(IOutputStream& os, const TTimeline& timeline, double maxTime)
+ {
+ static const char *barClass[] = {
+ "progress-bar-info",
+ "progress-bar-warning"
+ };
+ if (timeline.empty()) {
+ return;
+ }
+ os << "<div class=\"progress\" style=\"margin-bottom:0px;color:black\">";
+ double prevPos = 0.0;
+ double prevTime = 0.0;
+ size_t i = 0;
+ for (auto& e : timeline) {
+ TPatternNode* node = e.first;
+ double time = e.second;
+ double pos = time * 100 / maxTime;
+ if (pos > 100) {
+ pos = 100;
+ }
+ double width = pos - prevPos;
+ os << "<div class=\"progress-bar " << barClass[i % 2] << "\" role=\"progressbar\""
+ " aria-valuenow=\"" << width << "\""
+ " aria-valuemin=\"0\""
+ " aria-valuemax=\"100\""
+ " style=\"width:" << width << "%;color:black\""
+ " title=\"" << FormatTimelineTooltip(time, prevTime, node) << "\">";
+ if (width > 20) { // To ensure text will fit the bar
+ os << FormatCycles(time - prevTime);
+ }
+ os << "</div>";
+ prevPos = pos;
+ prevTime = time;
+ i++;
+ }
+ os << "</div>";
+ }
+
+ TString FormatTimelineTooltip(double time, double prevTime, TPatternNode* node)
+ {
+ return FormatCycles(time - prevTime) + ": "
+ + FormatCycles(prevTime) + " -> " + FormatCycles(time)
+ + "(" + node->Name + ")";
+ }
+
+ TString FormatFloat(double value)
+ {
+ if (value == 0.0) {
+ return "0";
+ }
+ if (value > 1.0) {
+ if (value > 100.0) {
+ return Sprintf("%.0lf", value);
+ }
+ if (value > 10.0) {
+ return Sprintf("%.1lf", value);
+ }
+ return Sprintf("%.2lf", value);
+ } else if (value > 1e-3) {
+ if (value > 1e-1) {
+ return Sprintf("%.3lf", value);
+ }
+ if (value > 1e-2) {
+ return Sprintf("%.4lf", value);
+ }
+ return Sprintf("%.5lf", value);
+ } else if (value > 1e-6) {
+ if (value > 1e-4) {
+ return Sprintf("%.6lf", value);
+ }
+ if (value > 1e-5) {
+ return Sprintf("%.7lf", value);
+ }
+ return Sprintf("%.8lfus", value);
+ } else {
+ if (value > 1e-7) {
+ return Sprintf("%.9lfns", value);
+ }
+ if (value > 1e-8) {
+ return Sprintf("%.10lfns", value);
+ }
+ return Sprintf("%.2le", value);
+ }
+ }
+
+ TString FormatCycles(double timeCycles)
+ {
+ double timeSec = timeCycles / NHPTimer::GetClockRate();
+ if (timeSec > 1.0) {
+ if (timeSec > 100.0) {
+ return Sprintf("%.0lfs", timeSec);
+ }
+ if (timeSec > 10.0) {
+ return Sprintf("%.1lfs", timeSec);
+ }
+ return Sprintf("%.2lfs", timeSec);
+ } else if (timeSec > 1e-3) {
+ if (timeSec > 1e-1) {
+ return Sprintf("%.0lfms", timeSec * 1e3);
+ }
+ if (timeSec > 1e-2) {
+ return Sprintf("%.1lfms", timeSec * 1e3);
+ }
+ return Sprintf("%.2lfms", timeSec * 1e3);
+ } else if (timeSec > 1e-6) {
+ if (timeSec > 1e-4) {
+ return Sprintf("%.0lfus", timeSec * 1e6);
+ }
+ if (timeSec > 1e-5) {
+ return Sprintf("%.1lfus", timeSec * 1e6);
+ }
+ return Sprintf("%.2lfus", timeSec * 1e6);
+ } else {
+ if (timeSec > 1e-7) {
+ return Sprintf("%.0lfns", timeSec * 1e9);
+ }
+ if (timeSec > 1e-8) {
+ return Sprintf("%.1lfns", timeSec * 1e9);
+ }
+ return Sprintf("%.2lfns", timeSec * 1e9);
+ }
+ }
+
+ TString GetParam(const NLWTrace::TLogItem& item, TString* paramValues, const TString& paramName)
+ {
+ for (size_t pi = 0; pi < item.SavedParamsCount; pi++) {
+ if (paramName == item.Probe->Event.Signature.ParamNames[pi]) {
+ return paramValues[pi];
+ }
+ }
+ return TString();
+ }
+
+ TString GetGroup(const NLWTrace::TLogItem& item, TString* paramValues)
+ {
+ TStringStream ss;
+ bool first = true;
+ for (const TString& groupParam : GroupBy) {
+ ss << (first? "": "|") << GetParam(item, paramValues, groupParam);
+ first = false;
+ }
+ return ss.Str();
+ }
+
+ void AddItemToTrack(TThread::TId tid, const NLWTrace::TLogItem& item)
+ {
+ // Ensure cyclic per thread lwtrace logs wont drop *inner* items of a track
+ // (note that some *starting* items can be dropped)
+ if (item.SavedParamsCount > 0 && !CutTs.Skip(item)) {
+ TString paramValues[LWTRACE_MAX_PARAMS];
+ item.Probe->Event.Signature.SerializeParams(item.Params, paramValues);
+ Tracks[GetGroup(item, paramValues)].Items.emplace_back(tid, item);
+ }
+ }
+};
+
+NLWTrace::TProbeRegistry g_Probes;
+TString g_sanitizerTest("TString g_sanitizerTest");
+NLWTrace::TManager g_SafeManager(g_Probes, false);
+NLWTrace::TManager g_UnsafeManager(g_Probes, true);
+TDashboardRegistry g_DashboardRegistry;
+
+class TLWTraceMonPage : public NMonitoring::IMonPage {
+private:
+ NLWTrace::TManager* TraceMngr;
+ TString StartTime;
+ TTraceCleaner Cleaner;
+ TMutex SnapshotsMtx;
+ THashMap<TString, TAtomicSharedPtr<NLWTrace::TLogPb>> Snapshots;
+public:
+ explicit TLWTraceMonPage(bool allowUnsafe = false)
+ : NMonitoring::IMonPage("trace", "Tracing")
+ , TraceMngr(&TraceManager(allowUnsafe))
+ , Cleaner(TraceMngr)
+ {
+ time_t stime = TInstant::Now().TimeT();
+ StartTime = CTimeR(&stime);
+ }
+
+ virtual void Output(NMonitoring::IMonHttpRequest& request) {
+ TStringStream out;
+ try {
+ if (request.GetParams().Get("mode") == "") {
+ OutputTracesAndSnapshots(request, out);
+ } else if (request.GetParams().Get("mode") == "probes") {
+ OutputProbes(request, out);
+ } else if (request.GetParams().Get("mode") == "dashboards") {
+ OutputDashboards(request, out);
+ } else if (request.GetParams().Get("mode") == "dashboard") {
+ OutputDashboard(request, out);
+ } else if (request.GetParams().Get("mode") == "log") {
+ OutputLog(request, out);
+ } else if (request.GetParams().Get("mode") == "query") {
+ OutputQuery(request, out);
+ } else if (request.GetParams().Get("mode") == "builder") {
+ OutputBuilder(request, out);
+ } else if (request.GetParams().Get("mode") == "analytics") {
+ OutputAnalytics(request, out);
+ } else if (request.GetParams().Get("mode") == "new") {
+ PostNew(request, out);
+ } else if (request.GetParams().Get("mode") == "delete") {
+ PostDelete(request, out);
+ } else if (request.GetParams().Get("mode") == "make_snapshot") {
+ PostSnapshot(request, out);
+ } else if (request.GetParams().Get("mode") == "settimeout") {
+ PostSetTimeout(request, out);
+ } else {
+ ythrow yexception() << "Bad request";
+ }
+ } catch (TPageGenBase& gen) {
+ out.Clear();
+ out << gen.what();
+ } catch (...) {
+ out.Clear();
+ if (request.GetParams().Get("error") == "text") {
+ // Text error reply is helpful for ajax requests
+ out << NMonitoring::HTTPOKTEXT;
+ out << CurrentExceptionMessage();
+ } else {
+ WWW_HTML(out) {
+ out << "<h2>Error</h2><pre>"
+ << CurrentExceptionMessage()
+ << Endl;
+ }
+ }
+ }
+ request.Output() << out.Str();
+ }
+
+private:
+ void OutputNavbar(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ TString active = " class=\"active\"";
+ out <<
+ "<nav class=\"navbar navbar-default\"><div class=\"container-fluid\">"
+ << NavbarHeader() <<
+ "<ul class=\"nav navbar-nav\">"
+ "<li" << (request.GetParams().Get("mode") == ""? active: "") << "><a href=\"?mode=\">Traces</a></li>"
+ "<li" << (request.GetParams().Get("mode") == "probes"? active: "") << "><a href=\"?mode=probes\">Probes</a></li>"
+ "<li" << (request.GetParams().Get("mode") == "dashboards"? active: "") << "><a href=\"?mode=dashboards\">Dashboard</a></li>"
+ "<li" << (request.GetParams().Get("mode") == "builder"? active: "") << "><a href=\"?mode=builder\">Builder</a></li>"
+ "<li" << (request.GetParams().Get("mode") == "analytics"? active: "") << "><a href=\"?mode=analytics&id=\">Analytics</a></li>"
+ "<li><a href=\"https://wiki.yandex-team.ru/development/poisk/arcadia/library/cpp/lwtrace/\" target=\"_blank\">Documentation</a></li>"
+ "</ul>"
+ "</div></nav>"
+ ;
+ }
+
+ template <class TReader>
+ void ReadSnapshots(TReader& reader) const
+ {
+ TGuard<TMutex> g(SnapshotsMtx);
+ for (const auto& kv : Snapshots) {
+ reader.Push(kv.first, kv.second);
+ }
+ }
+
+ void OutputTracesAndSnapshots(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ TLogSources logSources(Cleaner);
+ TraceMngr->ReadTraces(logSources);
+ ReadSnapshots(logSources);
+
+ TStringStream ss;
+ TTracesHtmlPrinter printer(ss);
+ logSources.ForEach(printer);
+ WWW_HTML(out) {
+ OutputNavbar(request, out);
+ out <<
+ "<table class=\"table table-striped\">"
+ "<tr><th>Start Time</th><th>Timeout</th><th>Name</th><th>Events</th><th>Threads</th><th></th><th></th><th></th><th></th><th></th></tr>"
+ << ss.Str() <<
+ "</table>"
+ ;
+ out << "<hr/><p><strong>Start time:</strong> " << StartTime;
+ out << "<br/><strong>Build date:</strong> ";
+ out << __DATE__ << " " << __TIME__ << "</p>" << Endl;
+ }
+ }
+
+ void OutputProbes(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ TStringStream ss;
+ TProbesHtmlPrinter printer;
+ TraceMngr->ReadProbes(printer);
+ printer.Output(ss);
+ WWW_HTML(out) {
+ OutputNavbar(request, out);
+ out << ss.Str();
+ }
+ }
+
+ void OutputDashboards(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ TStringStream ss;
+ g_DashboardRegistry.Output(ss);
+
+ WWW_HTML(out) {
+ OutputNavbar(request, out);
+ out << ss.Str();
+ }
+ }
+
+ void OutputDashboard(const NMonitoring::IMonHttpRequest& request, IOutputStream& out) {
+ if (!request.GetParams().Has("name")) {
+ ythrow yexception() << "Cgi-parameter 'name' is not specified";
+ } else {
+ auto name = request.GetParams().Get("name");
+ NLWTrace::TDashboard dash;
+ if (!g_DashboardRegistry.Get(name, dash)) {
+ ythrow yexception() << "Dashboard doesn't exist";
+ }
+ WWW_HTML(out) {
+ OutputNavbar(request, out);
+ out << "<style type='text/css'>html, body { height: 100%; }</style>";
+ out << "<h2>" << dash.GetName() << "</h2>";
+ if (dash.GetDescription()) {
+ out << "<h3>" << dash.GetDescription() << "</h3>";
+ }
+ int height = 85; // %
+ int minHeight = 100; // px
+ out << "<table height='" << height << "%' width='100%' cellpadding='4'><tbody height='100%' width='100%'>";
+ ui32 rows = 0;
+ auto maxRowSpan = [](const auto& row) {
+ ui32 rowSpan = 1;
+ for (const auto& cell : row.GetCells()) {
+ rowSpan = Max(rowSpan, cell.GetRowSpan());
+ }
+ return rowSpan;
+ };
+ for (const auto& row : dash.GetRows()) {
+ rows += maxRowSpan(row);
+ }
+ for (const auto& row : dash.GetRows()) {
+ int rowSpan = maxRowSpan(row);
+ out << "<tr align='left' valign='top' style='height:" << (height * rowSpan / rows) << "%; min-height:" << (minHeight * rowSpan)<< "px'>";
+ for (const auto& cell : row.GetCells()) {
+ TString url = cell.GetUrl();
+ TString title = cell.GetTitle();
+ TString text = cell.GetText();
+ auto rowSpan = Max<ui64>(1, cell.GetRowSpan());
+ auto colSpan = Max<ui64>(1, cell.GetColSpan());
+ if (url) {
+ if (title) {
+ out << "<td rowspan='" << rowSpan << "' colSpan='1'><a href=" << url << ">" << title << "</a><br>";
+ }
+ out << "<iframe scrolling='no' width='" << 100 * colSpan << "%' height='" << height << "%' style='border: 0' src=" << url << "></iframe></td>";
+ // Add fake cells to fix html table
+ for (ui32 left = 1; left < colSpan; ++left) {
+ out << "<td height='100%' rowspan='" << rowSpan << "' colSpan='1'>"
+ << "<iframe scrolling='no' width='100%' height='100%' style='border: 0' src=" << "" << "></iframe></td>";
+ }
+ } else {
+ out << "<td style='font-size: 25px' align='left' rowspan='" << rowSpan << "' colSpan='" << colSpan << "'>" << text << "</td>";
+ }
+ }
+ }
+ out << "</tbody></table>";
+ }
+ }
+ }
+
+ static double ParseDouble(const TString& s)
+ {
+ if (s == "inf") {
+ return std::numeric_limits<double>::infinity();
+ } else if (s == "-inf") {
+ return -std::numeric_limits<double>::infinity();
+ } else {
+ return FromString<double>(s);
+ }
+ }
+
+ void OutputLog(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ if (request.GetParams().NumOfValues("id") == 0) {
+ ythrow yexception() << "Cgi-parameter 'id' is not specified";
+ } else {
+ const TCgiParameters& e = request.GetParams();
+ TStringStream ss;
+ if (e.Get("format") == "json") {
+ TLogJsonPrinter printer(ss);
+ printer.OutputHeader();
+ TString id = e.Get("id");
+ CheckAdHocTrace(id, TDuration::Minutes(1));
+ TraceMngr->ReadLog(id, printer);
+ printer.OutputFooter(TraceMngr->GetTrace(id));
+ out << HTTPOKJSON;
+ out << ss.Str();
+ } if (e.Get("format") == "json2") {
+ TLogTextPrinter printer(e);
+ for (const TString& id : Subvalues(e, "id")) {
+ CheckAdHocTrace(id, TDuration::Minutes(1));
+ TraceMngr->ReadLog(id, printer);
+ TraceMngr->ReadDepot(id, printer);
+ }
+ printer.OutputJson(ss);
+ out << HTTPOKJSON;
+ out << ss.Str();
+ } else if (e.Get("format") == "analytics" && e.Get("aggr") == "tracks") {
+ TLogTrackExtractor logTrackExtractor(e,
+ Subvalues(e, "f"),
+ Subvalues(e, "g")
+ );
+ for (const TString& id : Subvalues(e, "id")) {
+ CheckAdHocTrace(id, TDuration::Minutes(1));
+ TraceMngr->ReadLog(id, logTrackExtractor);
+ TraceMngr->ReadDepot(id, logTrackExtractor);
+ }
+ TString patternAnalyzer;
+ if (e.Get("pattern")) {
+ patternAnalyzer = e.Get("ptrn_anlz");
+ }
+ logTrackExtractor.Run();
+
+ TLogTextPrinter printer(e);
+ const TString& distBy = patternAnalyzer;
+ double sel_x1 = e.Get("sel_x1")? ParseDouble(e.Get("sel_x1")): NAN;
+ double sel_x2 = e.Get("sel_x2")? ParseDouble(e.Get("sel_x2")): NAN;
+ TSampleOpts opts;
+ opts.ShowProvider = (e.Get("show_provider") == "y");
+ if (e.Get("size_limit")) {
+ opts.SizeLimit = FromString<size_t>(e.Get("size_limit"));
+ }
+ logTrackExtractor.OutputSample(distBy, sel_x1, sel_x2, opts, printer);
+ printer.Output(ss);
+ out << HTTPOKTEXT;
+ out << ss.Str();
+ } else {
+ TLogTextPrinter printer(e);
+ for (const TString& id : Subvalues(e, "id")) {
+ CheckAdHocTrace(id, TDuration::Minutes(1));
+ TraceMngr->ReadLog(id, printer);
+ TraceMngr->ReadDepot(id, printer);
+ }
+ printer.Output(ss);
+ out << HTTPOKTEXT;
+ out << ss.Str();
+ }
+ }
+ }
+
+ void OutputQuery(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ if (request.GetParams().NumOfValues("id") == 0) {
+ ythrow yexception() << "Cgi-parameter 'id' is not specified";
+ } else {
+ TString id = request.GetParams().Get("id");
+ const NLWTrace::TQuery& query = TraceMngr->GetTrace(id)->GetQuery();
+ TString queryStr = query.DebugString();
+ WWW_HTML(out) {
+ out << "<h2>Trace Query: " << id << "</h2><pre>" << queryStr;
+ }
+ }
+ }
+
+ void OutputBuilder(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ Y_UNUSED(request);
+ WWW_HTML(out) {
+ OutputNavbar(request, out);
+ out << "<form class=\"form-horizontal\" action=\"?mode=new&ui=y\" method=\"POST\">";
+ DIV_CLASS("form-group") {
+ LABEL_CLASS_FOR("col-sm-1 control-label", "inputId") { out << "Name"; }
+ DIV_CLASS("col-sm-11") {
+ out << "<input class=\"form-control\" id=\"inputId\" name=\"id\" placeholder=\"mytrace\">";
+ }
+ }
+ DIV_CLASS("form-group") {
+ LABEL_CLASS_FOR("col-sm-1 control-label", "textareaQuery") { out << "Query"; }
+ DIV_CLASS("col-sm-11") {
+ out << "<textarea class=\"form-control\" id=\"textareaQuery\" name=\"query\" rows=\"10\"></textarea>";
+ }
+ }
+ DIV_CLASS("form-group") {
+ DIV_CLASS("col-sm-offset-1 col-sm-11") {
+ out << "<button type=\"submit\" class=\"btn btn-default\">Trace</button>";
+ }
+ }
+ out << "</form>";
+ }
+ }
+
+ void OutputAnalytics(const NMonitoring::IMonHttpRequest& request, TStringStream& out)
+ {
+ using namespace NAnalytics;
+ const TCgiParameters& e = request.GetParams();
+
+ TLogSources logSources(Cleaner);
+ TraceMngr->ReadTraces(logSources);
+ ReadSnapshots(logSources);
+
+ RequireMultipleSelection(out, e, "id", "Analyze ", ListTraces(logSources));
+
+ THolder<TLogFilter> logFilter;
+ TLogAnalyzer* logAnalyzer = nullptr;
+ TLogTrackExtractor* logTracks = nullptr;
+ if (request.GetParams().Get("aggr") == "tracks") {
+ logFilter.Reset(logTracks = new TLogTrackExtractor(e,
+ Subvalues(request.GetParams(), "f"),
+ Subvalues(request.GetParams(), "g")
+ ));
+ for (const TString& id : Subvalues(request.GetParams(), "id")) {
+ CheckAdHocTrace(id, TDuration::Minutes(1));
+ TraceMngr->ReadLog(id, *logTracks);
+ TraceMngr->ReadDepot(id, *logTracks);
+ }
+ } else {
+ logFilter.Reset(logAnalyzer = new TLogAnalyzer(
+ Subvalues(request.GetParams(), "f"),
+ Subvalues(request.GetParams(), "g"),
+ request.GetParams().Get("cutts") == "y"
+ ));
+ for (const TString& id : Subvalues(request.GetParams(), "id")) {
+ CheckAdHocTrace(id, TDuration::Minutes(1));
+ TraceMngr->ReadLog(id, *logAnalyzer);
+ TraceMngr->ReadDepot(id, *logAnalyzer);
+ }
+ }
+
+ logFilter->FilterSelectors(out, e, "f");
+
+ OptionalMultipleSelection(out, e, "g", "group by", logFilter->ListParamNames());
+ {
+ auto paramNamesList = logFilter->ListParamNames();
+ if (e.Get("aggr") == "tracks") {
+ paramNamesList.emplace_back("_trackMs", "_trackMs");
+ }
+ OptionalSelection(out, e, "s", "order by", paramNamesList);
+ }
+
+ if (e.Get("s")) {
+ TVariants variants;
+ variants.emplace_back("", "asc");
+ variants.emplace_back("y", "desc");
+ DropdownSelector<Link>(out, e, "reverse", e.Get("reverse"), "", variants);
+ }
+
+ TString aggr = e.Get("aggr");
+ TVariants variants1; // MSVS2013 doesn't understand complex initializer lists
+ variants1.emplace_back("", "without aggregation");
+ variants1.emplace_back("hist", "as histogram");
+ variants1.emplace_back("tracks", "tracks");
+ DropdownSelector<Link>(out, e, "aggr", e.Get("aggr"), "", variants1);
+
+ unsigned refresh = e.Get("refresh")?
+ FromString<unsigned>(e.Get("refresh")):
+ 1000;
+
+ if (aggr == "tracks") {
+ TVariants ileVars;
+ ileVars.emplace_back("0", "0");
+ ileVars.emplace_back("25", "25");
+ ileVars.emplace_back("50", "50");
+ ileVars.emplace_back("75", "75");
+ ileVars.emplace_back("", "90");
+ ileVars.emplace_back("95", "95");
+ ileVars.emplace_back("99", "99");
+ ileVars.emplace_back("99.9", "99.9");
+ ileVars.emplace_back("100", "100");
+ DropdownSelector<Link>(out, e, "ile", e.Get("ile"), "and show", ileVars);
+ out << "%-ile. ";
+ TString patternAnalyzer;
+ TString distBy;
+ TString distType;
+ if (e.Get("pattern")) {
+ TVariants analyzePatternVars;
+ analyzePatternVars.emplace_back("resTotal", "distribution by total");
+ analyzePatternVars.emplace_back("resLast", "distribution by last");
+ analyzePatternVars.emplace_back("covMatrix", "covariance matrix");
+ DropdownSelector<Link>(
+ out, e, "ptrn_anlz", e.Get("ptrn_anlz"),
+ "Pattern", analyzePatternVars
+ );
+ patternAnalyzer = e.Get("ptrn_anlz");
+
+ TVariants distTypeVars;
+ distTypeVars.emplace_back("", "as is");
+ distTypeVars.emplace_back("-stack", "cumulative");
+ DropdownSelector<Link>(out, e, "dist_type", e.Get("dist_type"), "", distTypeVars);
+ distType = e.Get("dist_type");
+ } else {
+ out << "<i>Select pattern for more options</i>";
+ }
+ logTracks->Run();
+
+ if (e.Get("download") == "y") {
+ out.Clear();
+ out <<
+ "HTTP/1.1 200 Ok\r\n"
+ "Content-Type: application/force-download\r\n"
+ "Content-Transfer-Encoding: binary\r\n"
+ "Content-Disposition: attachment; filename=\"trace_chrome.json\"\r\n"
+ "\r\n"
+ ;
+ logTracks->OutputChromeTrace(out, e);
+ return;
+ }
+
+ NAnalytics::TTable distData;
+ bool showSample = false;
+ TLogTextPrinter printer(e);
+
+ if (patternAnalyzer == "resTotal" || patternAnalyzer == "resLast") {
+ distBy = patternAnalyzer;
+ distData = logTracks->Distribution(distBy, "", "", e.Get("width"));
+ double sel_x1 = e.Get("sel_x1")? ParseDouble(e.Get("sel_x1")): NAN;
+ double sel_x2 = e.Get("sel_x2")? ParseDouble(e.Get("sel_x2")): NAN;
+ if (!isnan(sel_x1) && !isnan(sel_x2)) {
+ showSample = true;
+ TSampleOpts opts;
+ opts.ShowProvider = (e.Get("show_provider") == "y");
+ if (e.Get("size_limit")) {
+ opts.SizeLimit = FromString<size_t>(e.Get("size_limit"));
+ }
+ logTracks->OutputSample(distBy, sel_x1, sel_x2, opts, printer);
+ }
+ }
+
+ TString selectors = out.Str();
+ out.Clear();
+ out << NMonitoring::HTTPOKHTML;
+ out << "<!DOCTYPE html>" << Endl;
+ HTML(out) {
+ HTML_TAG() {
+ HEAD() {
+ out << NResource::Find("lwtrace/mon/static/analytics.header.html") << Endl;
+ if (distBy) {
+ out <<
+ "<script type=\"text/javascript\">\n"
+ "$(function() {\n"
+ " var dataurl = null;\n"
+ " var datajson = " << ToJsonFlot(distData, distBy, {"_count_sum" + distType}) << ";\n"
+ " var refreshPeriod = 0;\n"
+ " var xn = \"" << distBy << "\";\n"
+ " var navigate = false;\n"
+ << NResource::Find("lwtrace/mon/static/analytics.js") <<
+ " embededMode();"
+ " enableSelection();"
+ "});\n"
+ "</script>\n";
+ }
+ // Show download button
+ out <<
+ "<script type=\"text/javascript\">"
+ "$(function() {"
+ " $(\"#download-btn\").click(function(){window.location.href='"
+ << MakeUrlAdd(e, "download", "y") <<
+ "';});"
+ " $(\"#download-btn\").removeClass(\"hidden\");"
+ "});"
+ "</script>\n";
+ }
+ BODY() {
+ // Wrap selectors with navbar
+ { TSelectorsContainer sc(out);
+ out << selectors;
+ }
+
+ logTracks->OutputTable(out, e);
+ if (distBy) {
+ out << NResource::Find("lwtrace/mon/static/analytics.flot.html") << Endl;
+ if (showSample) {
+ static const THashSet<TString> keepParams = {
+ "f",
+ "g",
+ "head",
+ "tail",
+ "s",
+ "reverse",
+ "cutts",
+ "showts",
+ "show_provider",
+ "size_limit",
+ "aggr",
+ "id",
+ "pattern",
+ "ptrn_anlz",
+ "sel_x1",
+ "sel_x2"
+ };
+ TCgiParameters cgiParams;
+ for (const auto& kv : request.GetParams()) {
+ if (keepParams.count(kv.first)) {
+ cgiParams.insert(kv);
+ }
+ }
+ cgiParams.insert(std::pair<TString, TString>("mode", "log"));
+ BtnHref<Button|Medium>(out, "Open logs", MakeUrlAdd(cgiParams, "format", "analytics"));
+ out << "<pre>\n";
+ printer.Output(out);
+ out << "</pre>\n";
+ }
+ }
+
+ if (patternAnalyzer == "covMatrix") {
+ logTracks->OutputSliceCovarianceMatrix(out, e);
+ }
+ }
+ }
+ }
+ } else {
+ double width = e.Get("width")? FromString<double>(e.Get("width")): 99;
+
+ NAnalytics::TTable data;
+ if (aggr == "") {
+ data = logAnalyzer->GetTable();
+ } else if (aggr == "hist") {
+ RequireSelection(out, e, "bn", "by", logFilter->ListParamNames());
+ const NAnalytics::TTable& inputTable = logAnalyzer->GetTable();
+ TString bn = e.Get("bn");
+ double b1 = e.Get("b1")? FromString<double>(e.Get("b1")): MinValue(bn, inputTable);
+ double b2 = e.Get("b2")? FromString<double>(e.Get("b2")): MaxValue(bn, inputTable);
+ if (isfinite(b1) && isfinite(b2)) {
+ WWW_CHECK(b1 <= b2, "invalid xrange [%le; %le]", b1, b2);
+ double dx = e.Get("dx")? FromString<double>(e.Get("dx")): (b2-b1)/width;
+ data = HistogramAll(inputTable, e.Get("bn"), b1, b2, dx);
+ } else {
+ // Empty table -- it's ok -- leave data table empty
+ }
+ }
+
+ TString xn = e.Get("xn");
+
+ TString outFormat = e.Get("out");
+ TVariants variants2;
+ variants2.emplace_back("html", "table");
+ variants2.emplace_back("flot", "chart");
+ variants2.emplace_back("gantt", "gantt");
+ variants2.emplace_back("text", "text");
+ variants2.emplace_back("csv", "CSV");
+ variants2.emplace_back("json_flot", "JSON");
+
+ RequireSelection(out, e, "out", "and show", variants2);
+ if (outFormat == "csv") {
+ TString sep = e.Get("sep")? e.Get("sep"): TString("\t");
+ out.Clear();
+ out << NMonitoring::HTTPOKTEXT;
+ out << ToCsv(data, sep, e.Get("head") != "n");
+ } else if (outFormat == "html") {
+ TString selectors = out.Str();
+ out.Clear();
+ WWW_HTML(out) {
+ // Wrap selectors with navbar
+ { TSelectorsContainer sc(out);
+ out << selectors;
+ }
+ out << ToHtml(data);
+ }
+ } else if (outFormat == "json_flot") {
+ SeriesSelectors(out, e, "xn", "yns", data);
+ out.Clear();
+ out << NMonitoring::HTTPOKJSON;
+ out << ToJsonFlot(data, xn, SplitString(e.Get("yns"), ":"));
+ } else if (outFormat == "flot") {
+ SeriesSelectors(out, e, "xn", "yns", data);
+ TString selectors = out.Str();
+
+ TVector<TString> ynos = SplitString(e.Get("yns"), ":");
+ out.Clear();
+ out << NMonitoring::HTTPOKHTML;
+ out << "<!DOCTYPE html>" << Endl;
+ HTML(out) {
+ HTML_TAG() {
+ HEAD() {
+ out << NResource::Find("lwtrace/mon/static/analytics.header.html") << Endl;
+ out <<
+ "<script type=\"text/javascript\">\n"
+ "$(function() {\n"
+ " var dataurl = \"" << EscapeJSONString(MakeUrl(e, "out", "json_flot")) << "\";\n"
+ " var refreshPeriod = " << refresh << ";\n"
+ " var xn = \"" << ParseName(xn) << "\";\n"
+ " var navigate = true;\n"
+ << NResource::Find("lwtrace/mon/static/analytics.js") <<
+ "});\n"
+ "</script>\n"
+ ;
+ }
+ BODY() {
+ // Wrap selectors with navbar
+ { TSelectorsContainer sc(out);
+ out << selectors;
+ }
+ out << NResource::Find("lwtrace/mon/static/analytics.flot.html") << Endl;
+ }
+ }
+ }
+ } else if (outFormat == "gantt") {
+ TString selectors = out.Str();
+ out.Clear();
+ out << NMonitoring::HTTPOKHTML;
+ out << "<!DOCTYPE html>" << Endl;
+ HTML(out) {
+ HTML_TAG() {
+ HEAD() {
+ out << NResource::Find("lwtrace/mon/static/analytics.header.html") << Endl;
+ out <<
+ "<script type=\"text/javascript\">\n"
+ "$(function() {\n"
+ " var dataurl = \"" << EscapeJSONString(MakeUrl(e, {{"mode", "log"}, {"format", "json2"}, {"gantt",""}})) << "\";\n"
+ " var refreshPeriod = " << refresh << ";\n"
+ " var xn = \"" << ParseName(xn) << "\";\n"
+ " var navigate = true;\n"
+ << NResource::Find("lwtrace/mon/static/analytics.js") <<
+ "});\n"
+ "</script>\n"
+ ;
+ }
+ BODY() {
+ // Wrap selectors with navbar
+ { TSelectorsContainer sc(out);
+ out << selectors;
+ }
+ out << NResource::Find("lwtrace/mon/static/analytics.gantt.html") << Endl;
+ }
+ }
+ }
+ } else if (outFormat = "text") {
+ out << " <input type='text' id='logsLimit' size='2' placeholder='Limit'>" << Endl;
+ out <<
+ R"END(<script>
+ {
+ var url = new URL(window.location.href);
+ if (url.searchParams.has('head')) {
+ document.getElementById('logsLimit').value = url.searchParams.get('head');
+ }
+ }
+
+ $('#logsLimit').on('keypress', function(ev) {
+ if (ev.keyCode == 13) {
+ var url = new URL(window.location.href);
+ var limit_value = document.getElementById('logsLimit').value;
+ if (limit_value && !isNaN(limit_value)) {
+ url.searchParams.set('head', limit_value);
+ window.location.href = url.toString();
+ } else if (!limit_value) {
+ url.searchParams.delete('head');
+ window.location.href = url.toString();
+ }
+ }
+ });
+ </script>)END";
+ TString selectors = out.Str();
+ TLogTextPrinter printer(e);
+ TStringStream ss;
+ for (const TString& id : Subvalues(e, "id")) {
+ CheckAdHocTrace(id, TDuration::Minutes(1));
+ TraceMngr->ReadLog(id, printer);
+ TraceMngr->ReadDepot(id, printer);
+ }
+ printer.Output(ss);
+
+ out.Clear();
+ out << NMonitoring::HTTPOKHTML;
+ out << "<!DOCTYPE html>" << Endl;
+ HTML(out) {
+ HTML_TAG() {
+ HEAD() {
+ out << NResource::Find("lwtrace/mon/static/analytics.header.html") << Endl;
+ }
+ BODY() {
+ // Wrap selectors with navbar
+ { TSelectorsContainer sc(out);
+ out << selectors;
+ }
+ static const THashSet<TString> keepParams = {
+ "s",
+ "head",
+ "reverse",
+ "cutts",
+ "showts",
+ "id",
+ "out"
+ };
+ TCgiParameters cgiParams;
+ for (const auto& kv : request.GetParams()) {
+ if (keepParams.count(kv.first)) {
+ cgiParams.insert(kv);
+ }
+ }
+ cgiParams.insert(std::pair<TString, TString>("mode", "analytics"));
+
+ auto toggledButton = [&out, &e, &cgiParams] (const TString& label, const TString& cgiKey) {
+ if (e.Get(cgiKey) == "y") {
+ BtnHref<Button|Medium>(out, label, MakeUrlErase(cgiParams, cgiKey, "y"), true);
+ } else {
+ BtnHref<Button|Medium>(out, label, MakeUrlAdd(cgiParams, cgiKey, "y"));
+ }
+ };
+ toggledButton("Cut Tails", "cutts");
+ toggledButton("Relative Time", "showts");
+
+ cgiParams.erase("mode");
+ cgiParams.insert(std::pair<TString, TString>("mode", "log"));
+ BtnHref<Button|Medium>(out, "Fullscreen", MakeUrlAdd(cgiParams, "format", "text"));
+ out << "<pre>\n";
+ out << ss.Str() << Endl;
+ out << "</pre>\n";
+ }
+ }
+ }
+ }
+ }
+ }
+
+ TDuration GetGetTimeout(const NMonitoring::IMonHttpRequest& request)
+ {
+ return (request.GetParams().Has("timeout")?
+ TDuration::Seconds(FromString<double>(request.GetParams().Get("timeout"))):
+ TDuration::Max());
+ }
+
+ void PostNew(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ WWW_CHECK(request.GetPostParams().Has("id"), "POST parameter 'id' is not specified");
+ const TString& id = request.GetPostParams().Get("id");
+ bool ui = (request.GetParams().Get("ui") == "y");
+ TDuration timeout = GetGetTimeout(request);
+ if (!CheckAdHocTrace(id, timeout)) {
+ NLWTrace::TQuery query;
+ TString queryStr = request.GetPostParams().Get("query");
+ if (!ui) {
+ queryStr = Base64Decode(queryStr); // Needed for trace.sh (historically)
+ }
+ WWW_CHECK(queryStr, "Empty trace query");
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(queryStr, &query);
+ WWW_CHECK(parsed, "Trace query text protobuf parse failed"); // TODO[serxa]: report error line/col and message
+ TraceMngr->New(id, query);
+ Cleaner.Postpone(id, timeout, false);
+ } else {
+ WWW_CHECK(!request.GetPostParams().Has("query"), "trace id '%s' is reserved for ad-hoc traces", id.data());
+ }
+ if (ui) {
+ WWW_HTML(out) {
+ out <<
+ "<div class=\"jumbotron alert-success\">"
+ "<h2>Trace created successfully</h2>"
+ "</div>"
+ "<script type=\"text/javascript\">\n"
+ "$(function() {\n"
+ " setTimeout(function() {"
+ " window.location.replace('?');"
+ " }, 1000);"
+ "});\n"
+ "</script>\n";
+ }
+ } else {
+ out << HTTPOKTEXT;
+ out << "OK\n";
+ }
+ }
+
+ void PostDelete(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ WWW_CHECK(request.GetPostParams().Has("id"), "POST parameter 'id' is not specified");
+ const TString& id = request.GetPostParams().Get("id");
+ bool ui = (request.GetParams().Get("ui") == "y");
+ TraceMngr->Delete(id);
+ Cleaner.Forget(id);
+ if (ui) {
+ WWW_HTML(out) {
+ out <<
+ "<div class=\"jumbotron alert-success\">"
+ "<h2>Trace deleted successfully</h2>"
+ "</div>"
+ "<script type=\"text/javascript\">\n"
+ "$(function() {\n"
+ " setTimeout(function() {"
+ " window.location.replace('?');"
+ " }, 1000);"
+ "});\n"
+ "</script>\n";
+ }
+ } else {
+ out << HTTPOKTEXT;
+ out << "OK\n";
+ }
+ }
+
+ void PostSnapshot(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ WWW_CHECK(request.GetPostParams().Has("id"), "POST parameter 'id' is not specified");
+ const TString& id = request.GetPostParams().Get("id");
+ bool ui = (request.GetParams().Get("ui") == "y");
+ TInstant now = TInstant::Now();
+
+ TGuard<TMutex> g(SnapshotsMtx);
+ const NLWTrace::TSession* trace = TraceMngr->GetTrace(id);
+ struct tm tm0;
+ TString sid = id + Strftime("_%Y%m%d-%H%M%S", now.GmTime(&tm0));
+ TAtomicSharedPtr<NLWTrace::TLogPb>& pbPtr = Snapshots[sid];
+ pbPtr.Reset(new NLWTrace::TLogPb());
+ trace->ToProtobuf(*pbPtr);
+ pbPtr->SetName(sid);
+ if (ui) {
+ WWW_HTML(out) {
+ out <<
+ "<div class=\"jumbotron alert-success\">"
+ "<h2>Snapshot created successfully</h2>"
+ "</div>"
+ "<script type=\"text/javascript\">\n"
+ "$(function() {\n"
+ " setTimeout(function() {"
+ " window.location.replace('?');"
+ " }, 1000);"
+ "});\n"
+ "</script>\n";
+ }
+ } else {
+ out << HTTPOKTEXT;
+ out << "OK\n";
+ }
+ }
+
+ void PostSetTimeout(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+ {
+ WWW_CHECK(request.GetPostParams().Has("id"), "POST parameter 'id' is not specified");
+ const TString& id = request.GetPostParams().Get("id");
+ TDuration timeout = GetGetTimeout(request);
+ bool ui = (request.GetParams().Get("ui") == "y");
+ Cleaner.Postpone(id, timeout, true);
+ if (ui) {
+ WWW_HTML(out) {
+ out <<
+ "<div class=\"jumbotron alert-success\">"
+ "<h2>Timeout changed successfully</h2>"
+ "</div>"
+ "<script type=\"text/javascript\">\n"
+ "$(function() {\n"
+ " setTimeout(function() {"
+ " window.location.replace('?');"
+ " }, 1000);"
+ "});\n"
+ "</script>\n";
+ }
+ } else {
+ out << HTTPOKTEXT;
+ out << "OK\n";
+ }
+ }
+
+ void RegisterDashboard(const TString& dashConfig) {
+ g_DashboardRegistry.Register(dashConfig);
+ }
+
+private:
+ // Returns true iff trace is ad-hoc and ensures trace is created
+ bool CheckAdHocTrace(const TString& id, TDuration timeout)
+ {
+ TAdHocTraceConfig cfg;
+ if (cfg.ParseId(id)) {
+ if (!TraceMngr->HasTrace(id)) {
+ TraceMngr->New(id, cfg.Query());
+ }
+ Cleaner.Postpone(id, timeout, false);
+ return true;
+ }
+ return false;
+ }
+};
+
+void RegisterPages(NMonitoring::TMonService2* mon, bool allowUnsafe) {
+ THolder<NLwTraceMonPage::TLWTraceMonPage> p = MakeHolder<NLwTraceMonPage::TLWTraceMonPage>(allowUnsafe);
+ mon->Register(p.Release());
+
+#define WWW_STATIC_FILE(file, type) \
+ mon->Register(new TResourceMonPage(file, file, NMonitoring::TResourceMonPage::type));
+ WWW_STATIC_FILE("lwtrace/mon/static/common.css", CSS);
+ WWW_STATIC_FILE("lwtrace/mon/static/common.js", JAVASCRIPT);
+ WWW_STATIC_FILE("lwtrace/mon/static/css/bootstrap.min.css", CSS);
+ WWW_STATIC_FILE("lwtrace/mon/static/css/d3-gantt.css", CSS);
+ WWW_STATIC_FILE("lwtrace/mon/static/css/jquery.treegrid.css", CSS);
+ WWW_STATIC_FILE("lwtrace/mon/static/analytics.css", CSS);
+ WWW_STATIC_FILE("lwtrace/mon/static/fonts/glyphicons-halflings-regular.eot", FONT_EOT);
+ WWW_STATIC_FILE("lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg", SVG);
+ WWW_STATIC_FILE("lwtrace/mon/static/fonts/glyphicons-halflings-regular.ttf", FONT_TTF);
+ WWW_STATIC_FILE("lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff2", FONT_WOFF2);
+ WWW_STATIC_FILE("lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff", FONT_WOFF);
+ WWW_STATIC_FILE("lwtrace/mon/static/img/collapse.png", PNG);
+ WWW_STATIC_FILE("lwtrace/mon/static/img/expand.png", PNG);
+ WWW_STATIC_FILE("lwtrace/mon/static/img/file.png", PNG);
+ WWW_STATIC_FILE("lwtrace/mon/static/img/folder.png", PNG);
+ WWW_STATIC_FILE("lwtrace/mon/static/js/bootstrap.min.js", JAVASCRIPT);
+ WWW_STATIC_FILE("lwtrace/mon/static/js/d3.v4.min.js", JAVASCRIPT);
+ WWW_STATIC_FILE("lwtrace/mon/static/js/d3-gantt.js", JAVASCRIPT);
+ WWW_STATIC_FILE("lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js", JAVASCRIPT);
+ WWW_STATIC_FILE("lwtrace/mon/static/js/filesaver.min.js", JAVASCRIPT);
+ WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.flot.extents.js", JAVASCRIPT);
+ WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.flot.min.js", JAVASCRIPT);
+ WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.flot.navigate.min.js", JAVASCRIPT);
+ WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.flot.selection.min.js", JAVASCRIPT);
+ WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.min.js", JAVASCRIPT);
+ WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js", JAVASCRIPT);
+ WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.treegrid.min.js", JAVASCRIPT);
+ WWW_STATIC_FILE("lwtrace/mon/static/js/jquery.url.min.js", JAVASCRIPT);
+#undef WWW_STATIC_FILE
+}
+
+NLWTrace::TProbeRegistry& ProbeRegistry() {
+ return g_Probes;
+}
+
+NLWTrace::TManager& TraceManager(bool allowUnsafe) {
+ return allowUnsafe? g_UnsafeManager: g_SafeManager;
+}
+
+TDashboardRegistry& DashboardRegistry() {
+ return g_DashboardRegistry;
+}
+
+} // namespace NLwTraceMonPage
diff --git a/library/cpp/lwtrace/mon/mon_lwtrace.h b/library/cpp/lwtrace/mon/mon_lwtrace.h
new file mode 100644
index 0000000000..8030f6ea61
--- /dev/null
+++ b/library/cpp/lwtrace/mon/mon_lwtrace.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <library/cpp/lwtrace/protos/lwtrace.pb.h>
+#include <library/cpp/monlib/service/monservice.h>
+#include <library/cpp/lwtrace/control.h>
+
+#include <util/generic/vector.h>
+
+namespace NLwTraceMonPage {
+
+class TDashboardRegistry {
+ THashMap<TString, NLWTrace::TDashboard> Dashboards;
+ TMutex Mutex;
+public:
+ void Register(const NLWTrace::TDashboard& dashboard);
+ void Register(const TVector<NLWTrace::TDashboard>& dashboards);
+ void Register(const TString& dashText);
+ bool Get(const TString& name, NLWTrace::TDashboard& dash);
+ void Output(TStringStream& ss);
+};
+
+void RegisterPages(NMonitoring::TMonService2* mon, bool allowUnsafe = false);
+NLWTrace::TProbeRegistry& ProbeRegistry(); // This is not safe to use this function before main()
+NLWTrace::TManager& TraceManager(bool allowUnsafe = false);
+TDashboardRegistry& DashboardRegistry();
+
+} // namespace NLwTraceMonPage
diff --git a/library/cpp/lwtrace/mon/static/analytics.css b/library/cpp/lwtrace/mon/static/analytics.css
new file mode 100644
index 0000000000..1b0c268e43
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/analytics.css
@@ -0,0 +1,68 @@
+#header {
+ position: relative;
+ width: 900px;
+ margin: auto;
+}
+
+#header h2 {
+ margin-left: 10px;
+ vertical-align: middle;
+ font-size: 42px;
+ font-weight: bold;
+ text-decoration: none;
+ color: #000;
+}
+
+#errmsg {
+ width: 95vw;
+ margin: 0 auto;
+ padding: 10px;
+}
+
+#footer {
+ margin-top: 25px;
+ margin-bottom: 10px;
+ text-align: center;
+ font-size: 12px;
+ color: #999;
+}
+
+.chart-container {
+ box-sizing: border-box;
+ width: 90vw;
+ height: 70vh;
+ padding: 10px 0px 0px 0px;
+ margin: 15px auto 30px auto;
+}
+
+#playback div { display: inline-block; }
+#playback input { display: inline-block; }
+
+.chart-placeholder {
+ width: 100%;
+ height: 100%;
+ font-size: 14px;
+ line-height: 1.2em;
+}
+
+.legend table {
+ border-spacing: 5px;
+}
+
+.body-fullscreen {
+ width: 100%;
+ height: 100%;
+ padding: 0;
+ margin: 0;
+}
+
+.container-fullscreen {
+ width: 100vw;
+ height: 100vh;
+ margin: 0;
+}
+
+.toolbar-fullscreen {
+ display:none;
+ margin: 0;
+}
diff --git a/library/cpp/lwtrace/mon/static/analytics.flot.html b/library/cpp/lwtrace/mon/static/analytics.flot.html
new file mode 100644
index 0000000000..ea0a2880a5
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/analytics.flot.html
@@ -0,0 +1,49 @@
+<div class="container-fluid" id="toolbar" style="margin:10px;width:92vw">
+ <div class="pull-right" id="playback">
+ <div class="btn-group" style="margin-right:40px">
+ <button type="button" class="btn btn-default" id="pb-linesfill">linesfill</button>
+ <button type="button" class="btn btn-default" id="pb-linessteps">linessteps</button>
+ <button type="button" class="btn btn-default" id="pb-linesshow">linesshow</button>
+ <button type="button" class="btn btn-default" id="pb-pointsshow">pointsshow</button>
+ </div>
+ <div class="btn-group" style="margin-right:40px">
+ <button type="button" class="btn btn-default" id="pb-export">Export</button>
+ <button type="button" class="btn btn-default" id="pb-import" data-toggle="modal" data-target="#importModal">Import</button>
+ </div>
+ <button type="button" class="btn btn-default hidden" id="pb-unselect">unselect</button>
+ <button type="button" class="btn" id="pb-fullscreen">Fullscreen</button>
+ <button type="button" class="btn" id="pb-autoscale" title="Enforce axis min/max value to be equal to min/max value of data points">Autoscale</button>
+ <button type="button" class="btn" id="pb-legendshow">Legend</button>
+ <button type="button" class="btn" id="pb-cutts" title="Cuts old items in every trace log to make them start from the same instant">Cut Tails</button>
+ <button type="button" class="btn btn-default" id="pb-pause"><strong>||</strong></button>
+ </div>
+
+ <div style="display:inline-block">
+ <div style="display: inline-block">
+ <span id="errmsg2" style="display:none"></span>
+ </div>
+ </div>
+</div>
+
+<div class="chart-container" id="container">
+ <div id="placeholder" class="chart-placeholder"></div>
+</div>
+
+<div class="modal fade" id="importModal" tabindex="-1" role="dialog" aria-labelledby="importModalLabel">
+ <div class="modal-dialog" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
+ aria-hidden="true">&times;</span></button>
+ <h4 class="modal-title" id="importModalLabel">Import chart Data</h4>
+ </div>
+ <div class="modal-body">
+ <input type="file" id="importFiles" value="Import" /><br />
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
+ <button type="button" class="btn btn-primary" id="btnDoImport">Import</button>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/library/cpp/lwtrace/mon/static/analytics.gantt.html b/library/cpp/lwtrace/mon/static/analytics.gantt.html
new file mode 100644
index 0000000000..cf41008900
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/analytics.gantt.html
@@ -0,0 +1,26 @@
+<div id="placeholder" class="chart-placeholder"></div>
+
+<div class="form-group"><label class="col-sm-1 control-label" for="textareaGantt">Config</label>
+ <div class="col-sm-11">
+ <textarea class="form-control" id="textareaGantt" name="gantt" rows="5">
+{
+ "bands": [
+ {
+ "t1": "_thrRTime[0]",
+ "t2": "_thrRTime[-1]",
+ "band": "_thread",
+ "color": "1",
+ "colorScale": "colors1"
+ }
+ ],
+ "scales": {
+ "colors1": "linear().domain([-1,0,1]).range(['red','black','green'])",
+ "colors2": "ordinal().domain(['VALUE1','VALUE2']).range(['blue','yellow'])"
+ }
+}
+ </textarea>
+ </div>
+</div>
+<div class="form-group">
+ <div class="col-sm-offset-1 col-sm-11"><button class="btn btn-default" id="gantt-apply">Apply</button></div>
+</div>
diff --git a/library/cpp/lwtrace/mon/static/analytics.header.html b/library/cpp/lwtrace/mon/static/analytics.header.html
new file mode 100644
index 0000000000..0a6790e232
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/analytics.header.html
@@ -0,0 +1,21 @@
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link rel="stylesheet" href="lwtrace/mon/static/analytics.css" type="text/css">
+<link rel="stylesheet" href="lwtrace/mon/static/css/d3-gantt.css" type="text/css">
+<link rel="stylesheet" href="lwtrace/mon/static/css/bootstrap.min.css">
+<link rel="stylesheet" href="lwtrace/mon/static/css/jquery.treegrid.css">
+<link rel="stylesheet" href="lwtrace/mon/static/common.css">
+
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.min.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.url.min.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.flot.min.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.flot.navigate.min.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.flot.extents.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.flot.selection.min.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.treegrid.min.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/bootstrap.min.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/filesaver.min.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/d3.v4.min.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/d3-gantt.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/common.js"></script>
diff --git a/library/cpp/lwtrace/mon/static/analytics.js b/library/cpp/lwtrace/mon/static/analytics.js
new file mode 100644
index 0000000000..7b66cca4c0
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/analytics.js
@@ -0,0 +1,561 @@
+/*
+ * This code is executed from document ready function
+ * Also note that some variable are set from C++ code
+ */
+
+var x1 = $.url("?x1");
+var x2 = $.url("?x2");
+var y1 = $.url("?y1");
+var y2 = $.url("?y2");
+
+var gantt = $.url("?gantt");
+var out = $.url("?out");
+
+var linesfill = $.url("?linesfill") == "y";
+var linessteps = $.url("?linessteps") == "y";
+var linesshow = $.url("?linesshow") != "n";
+var pointsshow = $.url("?pointsshow") != "n";
+var autoscale = $.url("?autoscale") == "y";
+var legendshow = $.url("?legendshow") != "n";
+var cutts = $.url("?cutts") == "y";
+var fullscreen = $.url("?fullscreen") == "y";
+var realnames = $.url("?realnames") == "y";
+var xzoomoff = $.url("?xzoomoff") == "y";
+var yzoomoff = $.url("?yzoomoff") == "y";
+
+function inIframe() { try { return window.self !== window.top; } catch (e) { return true; } }
+function inDashboard() { return fullscreen && inIframe(); }
+
+// URL management
+function makeUrl(url, queryFunc, hashFunc) {
+ var query = $.url("?", url);
+ var hash = $.url("#", url);
+ if (paused) {
+ query.paused = "y";
+ }
+
+ if (queryFunc) { queryFunc(query); }
+ if (hashFunc) { hashFunc(hash); }
+ var queryStr = "";
+ var first = true;
+ for (var k in query) {
+ queryStr += (first? "?": "&") + k + "=" + encodeURIComponent(query[k]);
+ first = false;
+ }
+ var hashStr = "";
+ first = true;
+ for (k in hash) {
+ hashStr += (first? "#": "&") + k + "=" + encodeURIComponent(hash[k]);
+ first = false;
+ }
+ return queryStr + hashStr;
+}
+
+function dataUrl() {
+ return makeUrl(dataurl, function(query) {
+ query.error = "text";
+ });
+}
+
+// Error message popup
+$("<div id='errmsg'></div>").css({
+ position: "absolute",
+ display: "none",
+ border: "1px solid #faa",
+ padding: "2px",
+ "background-color": "#fcc",
+ opacity: 0.80
+}).appendTo("body");
+
+if (out == "gantt") {
+ $("#gantt-apply").click(function() {
+ try {
+ let val = $("#textareaGantt").val().replace(/\s/g, "");
+ JSON.parse(val);
+ window.location.replace(makeUrl($.url(), function(query) {
+ query.gantt = val;
+ }));
+ } catch(e) {
+ $("#errmsg").text("Not valid JSON: " + e)
+ .css({bottom: "5px", left: "25%", width: "50%"})
+ .fadeIn(200);
+ }
+ });
+
+ if (gantt) {
+ // Data fetching and auto-refreshing
+ var fetchCounter = 0;
+ function fetchData() {
+ function onDataReceived(json, textStatus, xhr) {
+ $("#errmsg").hide();
+ logs = json;
+ chart(config, logs, true);
+ }
+
+ function onDataError(xhr, error) {
+ console.log(arguments);
+ $("#errmsg").text("Fetch data error: " + error + (xhr.status == 200? xhr.responseText: ""))
+ .css({bottom: "5px", left: "25%", width: "50%"})
+ .fadeIn(200);
+ }
+
+ if (dataurl) {
+ $.ajax({
+ url: dataUrl(),
+ type: "GET",
+ dataType: "json",
+ success: function (json, textStatus, xhr) { onDataReceived(json, textStatus, xhr); },
+ error: onDataError
+ });
+ } else {
+ onDataReceived(datajson, "textStatus", "xhr");
+ }
+
+ // if (fetchPeriod > 0) {
+ // if (fetchCounter == 0) {
+ // fetchCounter++;
+ // setTimeout(function() {
+ // fetchCounter--;
+ // if (!paused) {
+ // fetchData();
+ // }
+ // }, $("#errmsg").is(":visible")? errorPeriod: fetchPeriod);
+ // }
+ // }
+ }
+
+ try {
+ var config = JSON.parse(gantt);
+ $("#textareaGantt").val(JSON.stringify(config, "\n", " "));
+ let formHeight = 220;
+ var chart = d3.gantt()
+ .height(window.innerHeight - $("#placeholder")[0].getBoundingClientRect().y - window.scrollY - formHeight)
+ .selector("#placeholder");
+ var logs = null;
+ fetchData();
+ } catch(e) {
+ $("#textareaGantt").val(gantt);
+ alert("Not valid JSON: " + e);
+ }
+ }
+} else { // flot
+ // Special options adjustment for fullscreen charts in iframe (solomon dashboards)
+ if (fullscreen) {
+ navigate = false; // Disable navigation to avoid scrolling problems
+ legendshow = false; // Show legend only on hover
+ }
+
+ // Adjust zooming options
+ var xZoomRange = null;
+ var yZoomRange = null;
+ if (xzoomoff) {
+ xZoomRange = false;
+ }
+ if (yzoomoff) {
+ yZoomRange = false;
+ }
+
+ var placeholder = $("#placeholder");
+ var playback = $("#playback");
+
+ var data = null;
+ var loaded_data = [];
+ var imported_data = [];
+ var fetchPeriod = refreshPeriod;
+ var errorPeriod = 5000;
+ var playbackPeriod = 500;
+ var abstimestep = 1.0;
+
+ var paused = $.url("?paused") == "y";
+ var timestep = abstimestep;
+
+ var seriesDescription = {
+ _time: "time",
+ _thread: "thread"
+ }
+
+ function seriesDesc(name) {
+ if (seriesDescription.hasOwnProperty(name)) {
+ return (realnames? "[" + name + "] ": "") + seriesDescription[name];
+ } else {
+ return name;
+ }
+ }
+
+ playback.show();
+
+ var options = {
+ series: {
+ lines: { show: linesshow, fill: linesfill, steps: linessteps},
+ points: { show: pointsshow },
+ shadowSize: 0
+ },
+ xaxis: { zoomRange: xZoomRange },
+ yaxis: { zoomRange: yZoomRange },
+ grid: { clickable: true, hoverable: true },
+ zoom: { interactive: navigate },
+ pan: { interactive: navigate },
+ legend: {
+ show: legendshow,
+ labelFormatter: function(label, series) { return seriesDesc(label) + '(' + seriesDesc(xn) + ')'; }
+ }
+ };
+
+ if (fullscreen) {
+ $("body").attr("class","body-fullscreen");
+ $("#container").attr("class","container-fullscreen");
+ $("#toolbar").attr("class","toolbar-fullscreen");
+ $("#selectors-container").attr("class","toolbar-fullscreen");
+ options.grid.margin = 0;
+ }
+
+ if (x1) { options.xaxis.min = x1; }
+ if (x2) { options.xaxis.max = x2; }
+ if (y1) { options.yaxis.min = y1; }
+ if (y2) { options.yaxis.max = y2; }
+
+ $("<div id='tooltip'></div>").css({
+ position: "absolute",
+ display: "none",
+ border: "1px solid #fdd",
+ padding: "2px",
+ "background-color": "#fee",
+ opacity: 0.80
+ }).appendTo("body");
+
+ // Helper to hide tooltip
+ var lastShow = new Date();
+ var hideCounter = 0;
+ function hideTooltip() {
+ if (hideCounter == 0) {
+ hideCounter++;
+ setTimeout(function() {
+ hideCounter--;
+ if (new Date().getTime() - lastShow.getTime() > 1000) {
+ $("#tooltip").fadeOut(200);
+ } else if ($("#tooltip").is(":visible")) {
+ hideTooltip();
+ }
+ }, 200);
+ }
+ }
+
+ // Helper to hide legend
+ var legendLastShow = new Date();
+ var legendHideCounter = 0;
+ function hideLegend() {
+ if (legendHideCounter == 0) {
+ legendHideCounter++;
+ setTimeout(function() {
+ legendHideCounter--;
+ if (new Date().getTime() - legendLastShow.getTime() > 1000) {
+ options.legend.show = false;
+ $.plot(placeholder, data, options);
+ } else {
+ hideLegend();
+ }
+ }, 200);
+ }
+ }
+
+ function onPlotClick(event, pos, item) {
+ // Leave fullscreen on click
+ var nonFullscreenUrl = makeUrl($.url(), function(query) {
+ delete query.fullscreen;
+ });
+ if (inDashboard()) {
+ window.open(nonFullscreenUrl, "_blank");
+ } else if (fullscreen) {
+ window.location.href = nonFullscreenUrl;
+ }
+ }
+
+ function onPlotHover(event, pos, item) {
+ var redraw = false;
+ // Show legend on hover
+ if (fullscreen) {
+ legendLastShow = new Date();
+ if (!options.legend.show) {
+ redraw = true;
+ }
+ options.legend.show = true;
+ hideLegend();
+ }
+
+ // Show names on hover
+ var left = placeholder.position().left;
+ var top = placeholder.position().top;
+ var ttmargin = 10;
+ var ttwidth = $("#tooltip").width();
+ var ttheight = $("#tooltip").height();
+ if (linessteps) {
+ var pts = data[0].data;
+ var idx = 0;
+ for (var i = 0; i < pts.length - 1; i++) {
+ var x1 = pts[i][0];
+ var x2 = pts[i+1][0];
+ if (pos.x >= x1 && (x2 == null || pos.x < x2)) {
+ idx = i;
+ }
+ }
+ var n = pts[idx][2];
+ var html = (n? "<u><b><center>" + n + "</center></b></u>": "") + "<table><tr><td align=\"right\">" + seriesDesc(xn) + "</td><td>: </td><td>" + pts[idx][3] + "</td></tr>";
+ for (var sid = 0; sid < data.length; sid++) {
+ var series = data[sid];
+ var y = series.data[idx][4];
+ html += "<tr><td align=\"right\">" + seriesDesc(series.label) + "</td><td>: </td><td>" + y + "</td></tr>";
+ }
+ html += "</table>";
+
+ lastShow = new Date();
+ if (pos.pageX < left + placeholder.width() && pos.pageX > left &&
+ pos.pageY < top + placeholder.height() && pos.pageY > top) {
+ $("#tooltip").html(html)
+ .css({top: Math.max(top + ttmargin + 10, pos.pageY - ttheight - 20),
+ left: Math.max(left + ttmargin + 10, pos.pageX - ttwidth - 20)})
+ .fadeIn(200, "swing", hideTooltip());
+ }
+ } else {
+ if (item) {
+ var idx = item.dataIndex;
+ var n = item.series.data[idx][2];
+ var x = item.series.data[idx][3]; //item.datapoint[0];
+ var y = item.series.data[idx][4]; //item.datapoint[1];
+ $("#tooltip").html((n? n + ": ": "") + seriesDesc(item.series.label) + " = " + y + ", " + seriesDesc(xn) + " = " + x)
+ .css({top: Math.max(top + ttmargin + 10, item.pageY - ttheight - 20),
+ left: Math.max(left + ttmargin + 10, item.pageX - ttwidth - 20)})
+ .fadeIn(200);
+ } else {
+ $("#tooltip").hide();
+ }
+ }
+
+ // Redraw if required
+ if (redraw) {
+ $.plot(placeholder, data, options);
+ }
+ }
+
+ // Add some more interactivity
+ function onZoomOrPan(event, plot) {
+ var axes = plot.getAxes();
+ options.xaxis.min = axes.xaxis.min;
+ options.xaxis.max = axes.xaxis.max;
+ options.yaxis.min = axes.yaxis.min;
+ options.yaxis.max = axes.yaxis.max;
+ }
+
+ // Bind to events
+ placeholder.bind("plotclick", onPlotClick);
+ placeholder.bind("plothover", onPlotHover);
+ placeholder.bind("plotpan", onZoomOrPan);
+ placeholder.bind("plotzoom", onZoomOrPan);
+
+ // Data fetching and auto-refreshing
+ var fetchCounter = 0;
+ function fetchData() {
+ function onDataReceived(json, textStatus, xhr) {
+ $("#errmsg").hide();
+ if (paused && logs) {
+ return;
+ }
+
+ // Plot fetched data
+ loaded_data = json;
+ data = loaded_data.concat(imported_data);
+
+ if (autoscale) {
+ var xmin = null;
+ var xmax = null;
+ var ymin = null;
+ var ymax = null;
+ for (var sid = 0; sid < data.length; sid++) {
+ var pts = data[sid].data;
+ for (var i = 0; i < pts.length; i++) {
+ var x = pts[i][0];
+ var y = pts[i][1];
+ if (x != null && y != null) {
+ if (xmin == null || x < xmin) { xmin = x; }
+ if (xmax == null || x > xmax) { xmax = x; }
+ if (ymin == null || y < ymin) { ymin = y; }
+ if (ymax == null || y > ymax) { ymax = y; }
+ }
+ }
+ }
+ if (xmin != null) { options.xaxis.min = xmin; }
+ if (xmax != null) { options.xaxis.max = xmax; }
+ if (ymin != null) { options.yaxis.min = ymin; }
+ if (ymax != null) { options.yaxis.max = ymax; }
+ }
+ $.plot(placeholder, data, options);
+ }
+
+ function onDataError(xhr, error) {
+ console.log(arguments);
+ $("#errmsg").text("Fetch data error: " + error + (xhr.status == 200? xhr.responseText: ""))
+ .css({bottom: "5px", left: "25%", width: "50%"})
+ .fadeIn(200);
+ }
+
+ if (dataurl) {
+ $.ajax({
+ url: dataUrl(),
+ type: "GET",
+ dataType: "json",
+ success: function (json, textStatus, xhr) { onDataReceived(json, textStatus, xhr); },
+ error: onDataError
+ });
+ } else {
+ onDataReceived(datajson, "textStatus", "xhr");
+ }
+
+ if (fetchPeriod > 0) {
+ if (fetchCounter == 0) {
+ fetchCounter++;
+ setTimeout(function() {
+ fetchCounter--;
+ if (!paused) {
+ fetchData();
+ }
+ }, $("#errmsg").is(":visible")? errorPeriod: fetchPeriod);
+ }
+ }
+ }
+
+ // Playback control
+ var pb_pause = $("#pb-pause");
+
+ function setActive(btn, active) {
+ if (active) {
+ btn.addClass("btn-primary");
+ btn.removeClass("btn-default");
+ } else {
+ btn.addClass("btn-default");
+ btn.removeClass("btn-primary");
+ }
+ }
+
+ function onPlaybackControl() {
+ setActive(pb_pause, paused);
+ fetchPeriod = refreshPeriod;
+ fetchData();
+ }
+
+ function clickPause(val) {
+ paused = val;
+ onPlaybackControl();
+ }
+
+ pb_pause.click(function() { clickPause(!paused); });
+
+ function addOptionButton(opt, btn, defOn) {
+ setActive(btn, defOn ? $.url("?" + opt) != "n" : $.url("?" + opt) == "y");
+ btn.click(function() {
+ window.location.replace(makeUrl($.url(), function(query) {
+ if (defOn) {
+ if ($.url("?" + opt) != "n") {
+ query[opt] = "n";
+ } else {
+ delete query[opt];
+ }
+ } else {
+ if ($.url("?" + opt) == "y") {
+ delete query[opt];
+ } else {
+ query[opt] = "y";
+ }
+ }
+ }));
+ });
+ }
+
+ // Options
+ addOptionButton("linesfill", $("#pb-linesfill"), false);
+ addOptionButton("linessteps", $("#pb-linessteps"), false);
+ addOptionButton("linesshow", $("#pb-linesshow"), true);
+ addOptionButton("pointsshow", $("#pb-pointsshow"), true);
+ addOptionButton("legendshow", $("#pb-legendshow"), true);
+ addOptionButton("cutts", $("#pb-cutts"), false);
+ addOptionButton("autoscale", $("#pb-autoscale"), false);
+
+ var pb_fullscreen = $("#pb-fullscreen");
+ setActive(pb_fullscreen, fullscreen);
+ pb_fullscreen.click(function(){
+ window.location.href = makeUrl($.url(), function(query) {
+ if (fullscreen) {
+ delete query.fullscreen;
+ } else {
+ query.fullscreen = "y";
+ }
+ });
+ });
+
+ // Embeded mode (in case there is other stuff on page)
+ function embededMode() {
+ $("#pb-fullscreen").hide();
+ $("#pb-autoscale").hide();
+ $("#pb-legendshow").hide();
+ $("#pb-pause").hide();
+ }
+
+ function enableSelection() {
+ // Redraw chart with selection enabled
+ options.selection = {mode: "x"};
+ var plot = $.plot(placeholder, data, options);
+ if ($.url("?sel_x1") && $.url("?sel_x2")) {
+ plot.setSelection({
+ xaxis: {
+ from: $.url("?sel_x1") ,
+ to: $.url("?sel_x2")
+ }
+ });
+ }
+
+ // Create selection hooks
+ placeholder.bind("plotselected", function (event, ranges) {
+ window.location.replace(makeUrl($.url(), function(query) {
+ query.sel_x1 = ranges.xaxis.from;
+ query.sel_x2 = ranges.xaxis.to;
+ }));
+ });
+ placeholder.bind("plotunselected", function (event) {
+ window.location.replace(makeUrl($.url(), function(query) {
+ delete query.sel_x1;
+ delete query.sel_x2;
+ }));
+ });
+
+ // Init and show unselect button
+ $("#pb-unselect").click(function () {
+ plot.clearSelection();
+ });
+ $("#pb-unselect").removeClass("hidden");
+ }
+
+ // Export data
+ var pb_export = $("#pb-export");
+ pb_export.click(function(){
+ var blob = new Blob([JSON.stringify(data)], {type: "application/json;charset=utf-8"});
+ saveAs(blob, "exported.json");
+ });
+
+ // Import data
+ $("#btnDoImport").click(function(){
+ var files = document.getElementById('importFiles').files;
+ if (files.length <= 0) {
+ return false;
+ }
+
+ var fr = new FileReader();
+ fr.onload = function(e) {
+ imported_data = imported_data.concat(JSON.parse(e.target.result));
+ data = loaded_data.concat(imported_data);
+ $.plot(placeholder, data, options);
+ $('#importModal').modal('hide');
+ }
+ fr.readAsText(files.item(0));
+ });
+
+ // Initialize stuff and fetch data
+ onPlaybackControl();
+}
diff --git a/library/cpp/lwtrace/mon/static/common.css b/library/cpp/lwtrace/mon/static/common.css
new file mode 100644
index 0000000000..e0f68e1213
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/common.css
@@ -0,0 +1,3 @@
+/* theme.bootstrap.css 2.18.4 */ .tablesorter-bootstrap{width:100%}.tablesorter-bootstrap tfoot td,.tablesorter-bootstrap tfoot th,.tablesorter-bootstrap thead td,.tablesorter-bootstrap thead th{font:700 14px/20px Arial,Sans-serif;padding:4px;margin:0 0 18px;background-color:#eee}.tablesorter-bootstrap .tablesorter-header{cursor:pointer}.tablesorter-bootstrap .tablesorter-header-inner{position:relative;padding:4px 18px 4px 4px}.tablesorter-bootstrap .tablesorter-header i.tablesorter-icon{font-size:11px;position:absolute;right:2px;top:50%;margin-top:-7px;width:14px;height:14px;background-repeat:no-repeat;line-height:14px;display:inline-block}.tablesorter-bootstrap>tbody>tr.odd>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.odd:hover~tr.tablesorter-hasChildRow.odd~.tablesorter-childRow.odd>td{background-color:#f9f9f9}.tablesorter-bootstrap>tbody>tr.even:hover>td,.tablesorter-bootstrap>tbody>tr.odd:hover>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.even:hover~.tablesorter-childRow.even>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.odd:hover~.tablesorter-childRow.odd>td{background-color:#f5f5f5}.tablesorter-bootstrap>tbody>tr.even>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.even:hover~tr.tablesorter-hasChildRow.even~.tablesorter-childRow.even>td{background-color:#fff}.tablesorter-bootstrap .tablesorter-processing{background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=);background-position:center center!important;background-repeat:no-repeat!important}.caption{background:#fff}.tablesorter-bootstrap .tablesorter-filter-row input.tablesorter-filter,.tablesorter-bootstrap .tablesorter-filter-row select.tablesorter-filter{width:98%;margin:0 auto;padding:4px 6px;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row .tablesorter-filter.disabled{background-color:#eee;color:#555;cursor:not-allowed;border:1px solid #ccc;border-radius:4px;box-shadow:0 1px 1px rgba(0,0,0,.075) inset;box-sizing:border-box;transition:height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row td{background:#efefef;line-height:normal;text-align:center;padding:4px 6px;vertical-align:middle;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0}.tablesorter-bootstrap .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter .filtered{display:none}.tablesorter-bootstrap .tablesorter-pager select{padding:4px 6px}.tablesorter-bootstrap .tablesorter-pager .pagedisplay{border:0}.tablesorter-bootstrap tfoot i{font-size:11px}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
+/* colored table cells */ .table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5!important}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8!important;color:#468847!important}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6!important;color:#356635!important}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede!important;color:#b94a48!important}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc!important;color:#953b39!important}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3!important;color:#c09853!important}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc!important;color:#a47e3c!important}
+/* custom */ body{padding:4px;}tbody td{padding:2px 8px;}.counter-header{border-bottom: 1px solid #ccc;}.tablesorter-icon{top:2px!important;right:-6px!important;}.tablesorter-headerAsc,.tablesorter-headerDesc{background-color:#fafafa!important;}.gray-right-border{border-right:1px gray solid;}.rotate{-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg);-webkit-transform-origin:50% 50%;-moz-transform-origin:50% 50%;-ms-transform-origin:50% 50%;-o-transform-origin:50% 50%;transform-origin:50% 50%;filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);white-space:nowrap;height:140px;width: 20px;margin: 65px 0 -60px 0;padding-top:73px;}
diff --git a/library/cpp/lwtrace/mon/static/common.js b/library/cpp/lwtrace/mon/static/common.js
new file mode 100644
index 0000000000..42b93a6836
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/common.js
@@ -0,0 +1,17 @@
+/* jquery.tablesorter.min.js 2.18.4 */ !function(h){h.extend({tablesorter:new function(){function d(){var b=arguments[0],a=1<arguments.length?Array.prototype.slice.call(arguments):b;if("undefined"!==typeof console&&"undefined"!==typeof console.log)console[/error/i.test(b)?"error":/warn/i.test(b)?"warn":"log"](a);else alert(a)}function r(b,a){d(b+" ("+((new Date).getTime()-a.getTime())+"ms)")}function k(b){for(var a in b)return!1;return!0}function v(b,a,c){if(!a)return"";var f,e=b.config,m=e.textExtraction||"",d="",d="basic"===m?h(a).attr(e.textAttribute)|| a.textContent||a.innerText||h(a).text()||"":"function"===typeof m?m(a,b,c):"function"===typeof(f=g.getColumnData(b,m,c))?f(a,b,c):a.textContent||a.innerText||h(a).text()||"";return h.trim(d)}function p(b){var a,c,f=b.config,e=f.$tbodies=f.$table.children("tbody:not(."+f.cssInfoBlock+")"),m,x,l,n,w,u,k,q,t,D=0,A="",y=e.length;if(0===y)return f.debug?d("Warning: *Empty table!* Not building a parser cache"):"";f.debug&&(t=new Date,d("Detecting parsers for each column"));a=[];for(c=[];D<y;){m=e[D].rows; if(m[D])for(x=f.columns,l=0;l<x;l++){n=f.$headers.filter('[data-column="'+l+'"]:last');w=g.getColumnData(b,f.headers,l);q=g.getParserById(g.getData(n,w,"extractor"));k=g.getParserById(g.getData(n,w,"sorter"));u="false"===g.getData(n,w,"parser");f.empties[l]=(g.getData(n,w,"empty")||f.emptyTo||(f.emptyToBottom?"bottom":"top")).toLowerCase();f.strings[l]=(g.getData(n,w,"string")||f.stringTo||"max").toLowerCase();u&&(k=g.getParserById("no-parser"));q||(q=!1);if(!k)a:{n=b;w=m;u=-1;k=l;for(var C=void 0, L=void 0,M=g.parsers.length,z=!1,B="",C=!0;""===B&&C;)u++,w[u]?(z=w[u].cells[k],B=v(n,z,k),L=h(z),n.config.debug&&d("Checking if value was empty on row "+u+", column: "+k+': "'+B+'"')):C=!1;for(;0<=--M;)if((C=g.parsers[M])&&"text"!==C.id&&C.is&&C.is(B,n,z,L)){k=C;break a}k=g.getParserById("text")}f.debug&&(A+="column:"+l+"; extractor:"+q.id+"; parser:"+k.id+"; string:"+f.strings[l]+"; empty: "+f.empties[l]+"\n");c[l]=k;a[l]=q}D+=c.length?y:1}f.debug&&(d(A?A:"No parsers detected"),r("Completed detecting parsers", t));f.parsers=c;f.extractors=a}function y(b){var a,c,f,e,m,x,l,n,w,u,k,q=b.config,t=q.$table.children("tbody"),p=q.extractors,A=q.parsers;q.cache={};q.totalRows=0;if(!A)return q.debug?d("Warning: *Empty table!* Not building a cache"):"";q.debug&&(n=new Date);q.showProcessing&&g.isProcessing(b,!0);for(m=0;m<t.length;m++)if(k=[],a=q.cache[m]={normalized:[]},!t.eq(m).hasClass(q.cssInfoBlock)){w=t[m]&&t[m].rows.length||0;for(f=0;f<w;++f)if(u={child:[]},x=h(t[m].rows[f]),l=[],x.hasClass(q.cssChildRow)&& 0!==f)c=a.normalized.length-1,a.normalized[c][q.columns].$row=a.normalized[c][q.columns].$row.add(x),x.prev().hasClass(q.cssChildRow)||x.prev().addClass(g.css.cssHasChild),u.child[c]=h.trim(x[0].textContent||x[0].innerText||x.text()||"");else{u.$row=x;u.order=f;for(e=0;e<q.columns;++e)"undefined"===typeof A[e]?q.debug&&d("No parser found for cell:",x[0].cells[e],"does it have a header?"):(c=v(b,x[0].cells[e],e),c="undefined"===typeof p[e].id?c:p[e].format(c,b,x[0].cells[e],e),c="no-parser"===A[e].id? "":A[e].format(c,b,x[0].cells[e],e),l.push(q.ignoreCase&&"string"===typeof c?c.toLowerCase():c),"numeric"===(A[e].type||"").toLowerCase()&&(k[e]=Math.max(Math.abs(c)||0,k[e]||0)));l[q.columns]=u;a.normalized.push(l)}a.colMax=k;q.totalRows+=a.normalized.length}q.showProcessing&&g.isProcessing(b);q.debug&&r("Building cache for "+w+" rows",n)}function B(b,a){var c=b.config,f=c.widgetOptions,e=b.tBodies,m=[],d=c.cache,l,n,w,u,p,q;if(k(d))return c.appender?c.appender(b,m):b.isUpdating?c.$table.trigger("updateComplete", b):"";c.debug&&(q=new Date);for(p=0;p<e.length;p++)if(l=h(e[p]),l.length&&!l.hasClass(c.cssInfoBlock)){w=g.processTbody(b,l,!0);l=d[p].normalized;n=l.length;for(u=0;u<n;u++)m.push(l[u][c.columns].$row),c.appender&&(!c.pager||c.pager.removeRows&&f.pager_removeRows||c.pager.ajax)||w.append(l[u][c.columns].$row);g.processTbody(b,w,!1)}c.appender&&c.appender(b,m);c.debug&&r("Rebuilt table",q);a||c.appender||g.applyWidget(b);b.isUpdating&&c.$table.trigger("updateComplete",b)}function F(b){return/^d/i.test(b)|| 1===b}function E(b){var a,c,f,e,m,x,l,n=b.config;n.headerList=[];n.headerContent=[];n.debug&&(l=new Date);n.columns=g.computeColumnIndex(n.$table.children("thead, tfoot").children("tr"));e=n.cssIcon?'<i class="'+(n.cssIcon===g.css.icon?g.css.icon:n.cssIcon+" "+g.css.icon)+'"></i>':"";n.$headers=h(h.map(h(b).find(n.selectorHeaders),function(l,d){c=h(l);if(!c.parent().hasClass(n.cssIgnoreRow))return a=g.getColumnData(b,n.headers,d,!0),n.headerContent[d]=c.html(),""!==n.headerTemplate&&(m=n.headerTemplate.replace(/\{content\}/g, c.html()).replace(/\{icon\}/g,e),n.onRenderTemplate&&(f=n.onRenderTemplate.apply(c,[d,m]))&&"string"===typeof f&&(m=f),c.html('<div class="'+g.css.headerIn+'">'+m+"</div>")),n.onRenderHeader&&n.onRenderHeader.apply(c,[d,n,n.$table]),l.column=parseInt(c.attr("data-column"),10),l.order=F(g.getData(c,a,"sortInitialOrder")||n.sortInitialOrder)?[1,0,2]:[0,1,2],l.count=-1,l.lockedOrder=!1,x=g.getData(c,a,"lockedOrder")||!1,"undefined"!==typeof x&&!1!==x&&(l.order=l.lockedOrder=F(x)?[1,1,1]:[0,0,0]),c.addClass(g.css.header+ " "+n.cssHeader),n.headerList[d]=l,c.parent().addClass(g.css.headerRow+" "+n.cssHeaderRow).attr("role","row"),n.tabIndex&&c.attr("tabindex",0),l}));h(b).find(n.selectorHeaders).attr({scope:"col",role:"columnheader"});H(b);n.debug&&(r("Built headers:",l),d(n.$headers))}function I(b,a,c){var f=b.config;f.$table.find(f.selectorRemove).remove();p(b);y(b);J(f.$table,a,c)}function H(b){var a,c,f,e=b.config;e.$headers.each(function(m,d){c=h(d);f=g.getColumnData(b,e.headers,m,!0);a="false"===g.getData(d, f,"sorter")||"false"===g.getData(d,f,"parser");d.sortDisabled=a;c[a?"addClass":"removeClass"]("sorter-false").attr("aria-disabled",""+a);b.id&&(a?c.removeAttr("aria-controls"):c.attr("aria-controls",b.id))})}function G(b){var a,c,f=b.config,e=f.sortList,m=e.length,d=g.css.sortNone+" "+f.cssNone,l=[g.css.sortAsc+" "+f.cssAsc,g.css.sortDesc+" "+f.cssDesc],n=[f.cssIconAsc,f.cssIconDesc,f.cssIconNone],w=["ascending","descending"],k=h(b).find("tfoot tr").children().add(f.$extraHeaders).removeClass(l.join(" ")); f.$headers.removeClass(l.join(" ")).addClass(d).attr("aria-sort","none").find("."+f.cssIcon).removeClass(n.join(" ")).addClass(n[2]);for(a=0;a<m;a++)if(2!==e[a][1]&&(b=f.$headers.not(".sorter-false").filter('[data-column="'+e[a][0]+'"]'+(1===m?":last":"")),b.length)){for(c=0;c<b.length;c++)b[c].sortDisabled||b.eq(c).removeClass(d).addClass(l[e[a][1]]).attr("aria-sort",w[e[a][1]]).find("."+f.cssIcon).removeClass(n[2]).addClass(n[e[a][1]]);k.length&&k.filter('[data-column="'+e[a][0]+'"]').removeClass(d).addClass(l[e[a][1]])}f.$headers.not(".sorter-false").each(function(){var b= h(this),a=this.order[(this.count+1)%(f.sortReset?3:2)],a=b.text()+": "+g.language[b.hasClass(g.css.sortAsc)?"sortAsc":b.hasClass(g.css.sortDesc)?"sortDesc":"sortNone"]+g.language[0===a?"nextAsc":1===a?"nextDesc":"nextNone"];b.attr("aria-label",a)})}function Q(b){var a,c,f=b.config;f.widthFixed&&0===f.$table.children("colgroup").length&&(a=h("<colgroup>"),c=h(b).width(),h(b.tBodies).not("."+f.cssInfoBlock).find("tr:first").children(":visible").each(function(){a.append(h("<col>").css("width",parseInt(h(this).width()/ c*1E3,10)/10+"%"))}),f.$table.prepend(a))}function R(b,a){var c,f,e,m,g,l=b.config,d=a||l.sortList;l.sortList=[];h.each(d,function(b,a){m=parseInt(a[0],10);if(e=l.$headers.filter('[data-column="'+m+'"]:last')[0]){f=(f=(""+a[1]).match(/^(1|d|s|o|n)/))?f[0]:"";switch(f){case "1":case "d":f=1;break;case "s":f=g||0;break;case "o":c=e.order[(g||0)%(l.sortReset?3:2)];f=0===c?1:1===c?0:2;break;case "n":e.count+=1;f=e.order[e.count%(l.sortReset?3:2)];break;default:f=0}g=0===b?f:g;c=[m,parseInt(f,10)||0]; l.sortList.push(c);f=h.inArray(c[1],e.order);e.count=0<=f?f:c[1]%(l.sortReset?3:2)}})}function S(b,a){return b&&b[a]?b[a].type||"":""}function N(b,a,c){if(b.isUpdating)return setTimeout(function(){N(b,a,c)},50);var f,e,m,d,l=b.config,n=!c[l.sortMultiSortKey],w=l.$table;w.trigger("sortStart",b);a.count=c[l.sortResetKey]?2:(a.count+1)%(l.sortReset?3:2);l.sortRestart&&(e=a,l.$headers.each(function(){this===e||!n&&h(this).is("."+g.css.sortDesc+",."+g.css.sortAsc)||(this.count=-1)}));e=parseInt(h(a).attr("data-column"), 10);if(n){l.sortList=[];if(null!==l.sortForce)for(f=l.sortForce,m=0;m<f.length;m++)f[m][0]!==e&&l.sortList.push(f[m]);f=a.order[a.count];if(2>f&&(l.sortList.push([e,f]),1<a.colSpan))for(m=1;m<a.colSpan;m++)l.sortList.push([e+m,f])}else{if(l.sortAppend&&1<l.sortList.length)for(m=0;m<l.sortAppend.length;m++)d=g.isValueInArray(l.sortAppend[m][0],l.sortList),0<=d&&l.sortList.splice(d,1);if(0<=g.isValueInArray(e,l.sortList))for(m=0;m<l.sortList.length;m++)d=l.sortList[m],f=l.$headers.filter('[data-column="'+ d[0]+'"]:last')[0],d[0]===e&&(d[1]=f.order[a.count],2===d[1]&&(l.sortList.splice(m,1),f.count=-1));else if(f=a.order[a.count],2>f&&(l.sortList.push([e,f]),1<a.colSpan))for(m=1;m<a.colSpan;m++)l.sortList.push([e+m,f])}if(null!==l.sortAppend)for(f=l.sortAppend,m=0;m<f.length;m++)f[m][0]!==e&&l.sortList.push(f[m]);w.trigger("sortBegin",b);setTimeout(function(){G(b);K(b);B(b);w.trigger("sortEnd",b)},1)}function K(b){var a,c,f,e,m,d,l,n,h,u,p,q=0,t=b.config,v=t.textSorter||"",A=t.sortList,z=A.length,y= b.tBodies.length;if(!t.serverSideSorting&&!k(t.cache)){t.debug&&(m=new Date);for(c=0;c<y;c++)d=t.cache[c].colMax,l=t.cache[c].normalized,l.sort(function(c,m){for(a=0;a<z;a++){e=A[a][0];n=A[a][1];q=0===n;if(t.sortStable&&c[e]===m[e]&&1===z)break;(f=/n/i.test(S(t.parsers,e)))&&t.strings[e]?(f="boolean"===typeof t.string[t.strings[e]]?(q?1:-1)*(t.string[t.strings[e]]?-1:1):t.strings[e]?t.string[t.strings[e]]||0:0,h=t.numberSorter?t.numberSorter(c[e],m[e],q,d[e],b):g["sortNumeric"+(q?"Asc":"Desc")](c[e], m[e],f,d[e],e,b)):(u=q?c:m,p=q?m:c,h="function"===typeof v?v(u[e],p[e],q,e,b):"object"===typeof v&&v.hasOwnProperty(e)?v[e](u[e],p[e],q,e,b):g["sortNatural"+(q?"Asc":"Desc")](c[e],m[e],e,b,t));if(h)return h}return c[t.columns].order-m[t.columns].order});t.debug&&r("Sorting on "+A.toString()+" and dir "+n+" time",m)}}function O(b,a){var c=b[0];c.isUpdating&&b.trigger("updateComplete",c);h.isFunction(a)&&a(b[0])}function J(b,a,c){var f=b[0].config.sortList;!1!==a&&!b[0].isProcessing&&f.length?b.trigger("sorton", [f,function(){O(b,c)},!0]):(O(b,c),g.applyWidget(b[0],!1))}function P(b){var a=b.config,c=a.$table;c.unbind("sortReset update updateRows updateCell updateAll addRows updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ".split(" ").join(a.namespace+" ")).bind("sortReset"+a.namespace,function(c,e){c.stopPropagation();a.sortList=[];G(b);K(b);B(b);h.isFunction(e)&&e(b)}).bind("updateAll"+a.namespace,function(c,e,m){c.stopPropagation();b.isUpdating= !0;g.refreshWidgets(b,!0,!0);g.restoreHeaders(b);E(b);g.bindEvents(b,a.$headers,!0);P(b);I(b,e,m)}).bind("update"+a.namespace+" updateRows"+a.namespace,function(a,c,m){a.stopPropagation();b.isUpdating=!0;H(b);I(b,c,m)}).bind("updateCell"+a.namespace,function(f,e,m,g){f.stopPropagation();b.isUpdating=!0;c.find(a.selectorRemove).remove();var l,d,k;d=c.find("tbody");k=h(e);f=d.index(h.fn.closest?k.closest("tbody"):k.parents("tbody").filter(":first"));l=h.fn.closest?k.closest("tr"):k.parents("tr").filter(":first"); e=k[0];d.length&&0<=f&&(d=d.eq(f).find("tr").index(l),k=k.index(),a.cache[f].normalized[d][a.columns].$row=l,l="undefined"===typeof a.extractors[k].id?v(b,e,k):a.extractors[k].format(v(b,e,k),b,e,k),e="no-parser"===a.parsers[k].id?"":a.parsers[k].format(l,b,e,k),a.cache[f].normalized[d][k]=a.ignoreCase&&"string"===typeof e?e.toLowerCase():e,"numeric"===(a.parsers[k].type||"").toLowerCase()&&(a.cache[f].colMax[k]=Math.max(Math.abs(e)||0,a.cache[f].colMax[k]||0)),J(c,m,g))}).bind("addRows"+a.namespace, function(f,e,m,g){f.stopPropagation();b.isUpdating=!0;if(k(a.cache))H(b),I(b,m,g);else{e=h(e).attr("role","row");var d,n,r,u,y,q=e.filter("tr").length,t=c.find("tbody").index(e.parents("tbody").filter(":first"));a.parsers&&a.parsers.length||p(b);for(f=0;f<q;f++){n=e[f].cells.length;y=[];u={child:[],$row:e.eq(f),order:a.cache[t].normalized.length};for(d=0;d<n;d++)r="undefined"===typeof a.extractors[d].id?v(b,e[f].cells[d],d):a.extractors[d].format(v(b,e[f].cells[d],d),b,e[f].cells[d],d),r="no-parser"=== a.parsers[d].id?"":a.parsers[d].format(r,b,e[f].cells[d],d),y[d]=a.ignoreCase&&"string"===typeof r?r.toLowerCase():r,"numeric"===(a.parsers[d].type||"").toLowerCase()&&(a.cache[t].colMax[d]=Math.max(Math.abs(y[d])||0,a.cache[t].colMax[d]||0));y.push(u);a.cache[t].normalized.push(y)}J(c,m,g)}}).bind("updateComplete"+a.namespace,function(){b.isUpdating=!1}).bind("sorton"+a.namespace,function(a,e,m,d){var l=b.config;a.stopPropagation();c.trigger("sortStart",this);R(b,e);G(b);l.delayInit&&k(l.cache)&& y(b);c.trigger("sortBegin",this);K(b);B(b,d);c.trigger("sortEnd",this);g.applyWidget(b);h.isFunction(m)&&m(b)}).bind("appendCache"+a.namespace,function(a,c,d){a.stopPropagation();B(b,d);h.isFunction(c)&&c(b)}).bind("updateCache"+a.namespace,function(c,e){a.parsers&&a.parsers.length||p(b);y(b);h.isFunction(e)&&e(b)}).bind("applyWidgetId"+a.namespace,function(c,e){c.stopPropagation();g.getWidgetById(e).format(b,a,a.widgetOptions)}).bind("applyWidgets"+a.namespace,function(a,c){a.stopPropagation();g.applyWidget(b, c)}).bind("refreshWidgets"+a.namespace,function(a,c,d){a.stopPropagation();g.refreshWidgets(b,c,d)}).bind("destroy"+a.namespace,function(a,c,d){a.stopPropagation();g.destroy(b,c,d)}).bind("resetToLoadState"+a.namespace,function(){g.refreshWidgets(b,!0,!0);a=h.extend(!0,g.defaults,a.originalSettings);b.hasInitialized=!1;g.setup(b,a)})}var g=this;g.version="2.18.4";g.parsers=[];g.widgets=[];g.defaults={theme:"default",widthFixed:!1,showProcessing:!1,headerTemplate:"{content}",onRenderTemplate:null, onRenderHeader:null,cancelSelection:!0,tabIndex:!0,dateFormat:"mmddyyyy",sortMultiSortKey:"shiftKey",sortResetKey:"ctrlKey",usNumberFormat:!0,delayInit:!1,serverSideSorting:!1,headers:{},ignoreCase:!0,sortForce:null,sortList:[],sortAppend:null,sortStable:!1,sortInitialOrder:"asc",sortLocaleCompare:!1,sortReset:!1,sortRestart:!1,emptyTo:"bottom",stringTo:"max",textExtraction:"basic",textAttribute:"data-text",textSorter:null,numberSorter:null,widgets:[],widgetOptions:{zebra:["even","odd"]},initWidgets:!0, widgetClass:"widget-{name}",initialized:null,tableClass:"",cssAsc:"",cssDesc:"",cssNone:"",cssHeader:"",cssHeaderRow:"",cssProcessing:"",cssChildRow:"tablesorter-childRow",cssIcon:"tablesorter-icon",cssIconNone:"",cssIconAsc:"",cssIconDesc:"",cssInfoBlock:"tablesorter-infoOnly",cssAllowClicks:"tablesorter-allowClicks",cssIgnoreRow:"tablesorter-ignoreRow",selectorHeaders:"> thead th, > thead td",selectorSort:"th, td",selectorRemove:".remove-me",debug:!1,headerList:[],empties:{},strings:{},parsers:[]}; g.css={table:"tablesorter",cssHasChild:"tablesorter-hasChildRow",childRow:"tablesorter-childRow",header:"tablesorter-header",headerRow:"tablesorter-headerRow",headerIn:"tablesorter-header-inner",icon:"tablesorter-icon",info:"tablesorter-infoOnly",processing:"tablesorter-processing",sortAsc:"tablesorter-headerAsc",sortDesc:"tablesorter-headerDesc",sortNone:"tablesorter-headerUnSorted"};g.language={sortAsc:"Ascending sort applied, ",sortDesc:"Descending sort applied, ",sortNone:"No sort applied, ", nextAsc:"activate to apply an ascending sort",nextDesc:"activate to apply a descending sort",nextNone:"activate to remove the sort"};g.log=d;g.benchmark=r;g.construct=function(b){return this.each(function(){var a=h.extend(!0,{},g.defaults,b);a.originalSettings=b;!this.hasInitialized&&g.buildTable&&"TABLE"!==this.tagName?g.buildTable(this,a):g.setup(this,a)})};g.setup=function(b,a){if(!b||!b.tHead||0===b.tBodies.length||!0===b.hasInitialized)return a.debug?d("ERROR: stopping initialization! No table, thead, tbody or tablesorter has already been initialized"): "";var c="",f=h(b),e=h.metadata;b.hasInitialized=!1;b.isProcessing=!0;b.config=a;h.data(b,"tablesorter",a);a.debug&&h.data(b,"startoveralltimer",new Date);a.supportsDataObject=function(a){a[0]=parseInt(a[0],10);return 1<a[0]||1===a[0]&&4<=parseInt(a[1],10)}(h.fn.jquery.split("."));a.string={max:1,min:-1,emptymin:1,emptymax:-1,zero:0,none:0,"null":0,top:!0,bottom:!1};a.emptyTo=a.emptyTo.toLowerCase();a.stringTo=a.stringTo.toLowerCase();/tablesorter\-/.test(f.attr("class"))||(c=""!==a.theme?" tablesorter-"+ a.theme:"");a.table=b;a.$table=f.addClass(g.css.table+" "+a.tableClass+c).attr("role","grid");a.$headers=f.find(a.selectorHeaders);a.namespace=a.namespace?"."+a.namespace.replace(/\W/g,""):".tablesorter"+Math.random().toString(16).slice(2);a.$table.children().children("tr").attr("role","row");a.$tbodies=f.children("tbody:not(."+a.cssInfoBlock+")").attr({"aria-live":"polite","aria-relevant":"all"});a.$table.children("caption").length&&(c=a.$table.children("caption")[0],c.id||(c.id=a.namespace.slice(1)+ "caption"),a.$table.attr("aria-labelledby",c.id));a.widgetInit={};a.textExtraction=a.$table.attr("data-text-extraction")||a.textExtraction||"basic";E(b);Q(b);p(b);a.totalRows=0;a.delayInit||y(b);g.bindEvents(b,a.$headers,!0);P(b);a.supportsDataObject&&"undefined"!==typeof f.data().sortlist?a.sortList=f.data().sortlist:e&&f.metadata()&&f.metadata().sortlist&&(a.sortList=f.metadata().sortlist);g.applyWidget(b,!0);0<a.sortList.length?f.trigger("sorton",[a.sortList,{},!a.initWidgets,!0]):(G(b),a.initWidgets&& g.applyWidget(b,!1));a.showProcessing&&f.unbind("sortBegin"+a.namespace+" sortEnd"+a.namespace).bind("sortBegin"+a.namespace+" sortEnd"+a.namespace,function(c){clearTimeout(a.processTimer);g.isProcessing(b);"sortBegin"===c.type&&(a.processTimer=setTimeout(function(){g.isProcessing(b,!0)},500))});b.hasInitialized=!0;b.isProcessing=!1;a.debug&&g.benchmark("Overall initialization time",h.data(b,"startoveralltimer"));f.trigger("tablesorter-initialized",b);"function"===typeof a.initialized&&a.initialized(b)}; g.getColumnData=function(b,a,c,f,e){if("undefined"!==typeof a&&null!==a){b=h(b)[0];var d;b=b.config;e=e||b.$headers;if(a[c])return f?a[c]:a[e.index(e.filter('[data-column="'+c+'"]:last'))];for(d in a)if("string"===typeof d&&(f=e.filter('[data-column="'+c+'"]:last').filter(d).add(e.filter('[data-column="'+c+'"]:last').find(d)),f.length))return a[d]}};g.computeColumnIndex=function(b){var a=[],c=0,f,e,d,g,l,k,r,u,p,q;for(f=0;f<b.length;f++)for(l=b[f].cells,e=0;e<l.length;e++){d=l[e];g=h(d);k=d.parentNode.rowIndex; g.index();r=d.rowSpan||1;u=d.colSpan||1;"undefined"===typeof a[k]&&(a[k]=[]);for(d=0;d<a[k].length+1;d++)if("undefined"===typeof a[k][d]){p=d;break}c=Math.max(p,c);g.attr({"data-column":p});for(d=k;d<k+r;d++)for("undefined"===typeof a[d]&&(a[d]=[]),q=a[d],g=p;g<p+u;g++)q[g]="x"}return c+1};g.isProcessing=function(b,a,c){b=h(b);var f=b[0].config,e=c||b.find("."+g.css.header);a?("undefined"!==typeof c&&0<f.sortList.length&&(e=e.filter(function(){return this.sortDisabled?!1:0<=g.isValueInArray(parseFloat(h(this).attr("data-column")), f.sortList)})),b.add(e).addClass(g.css.processing+" "+f.cssProcessing)):b.add(e).removeClass(g.css.processing+" "+f.cssProcessing)};g.processTbody=function(b,a,c){b=h(b)[0];if(c)return b.isProcessing=!0,a.before('<span class="tablesorter-savemyplace"/>'),c=h.fn.detach?a.detach():a.remove();c=h(b).find("span.tablesorter-savemyplace");a.insertAfter(c);c.remove();b.isProcessing=!1};g.clearTableBody=function(b){h(b)[0].config.$tbodies.children().detach()};g.bindEvents=function(b,a,c){b=h(b)[0];var f, e=b.config;!0!==c&&(e.$extraHeaders=e.$extraHeaders?e.$extraHeaders.add(a):a);a.find(e.selectorSort).add(a.filter(e.selectorSort)).unbind(["mousedown","mouseup","sort","keyup",""].join(e.namespace+" ")).bind(["mousedown","mouseup","sort","keyup",""].join(e.namespace+" "),function(c,d){var g;g=c.type;if(!(1!==(c.which||c.button)&&!/sort|keyup/.test(g)||"keyup"===g&&13!==c.which||"mouseup"===g&&!0!==d&&250<(new Date).getTime()-f)){if("mousedown"===g)return f=(new Date).getTime(),/(input|select|button|textarea)/i.test(c.target.tagName)|| h(c.target).closest("td,th").hasClass(e.cssAllowClicks)?"":!e.cancelSelection;e.delayInit&&k(e.cache)&&y(b);g=h.fn.closest?h(this).closest("th, td")[0]:/TH|TD/.test(this.tagName)?this:h(this).parents("th, td")[0];g=e.$headers[a.index(g)];g.sortDisabled||N(b,g,c)}});e.cancelSelection&&a.attr("unselectable","on").bind("selectstart",!1).css({"user-select":"none",MozUserSelect:"none"})};g.restoreHeaders=function(b){var a=h(b)[0].config;a.$table.find(a.selectorHeaders).each(function(b){h(this).find("."+ g.css.headerIn).length&&h(this).html(a.headerContent[b])})};g.destroy=function(b,a,c){b=h(b)[0];if(b.hasInitialized){g.refreshWidgets(b,!0,!0);var f=h(b),e=b.config,d=f.find("thead:first"),k=d.find("tr."+g.css.headerRow).removeClass(g.css.headerRow+" "+e.cssHeaderRow),l=f.find("tfoot:first > tr").children("th, td");!1===a&&0<=h.inArray("uitheme",e.widgets)&&(f.trigger("applyWidgetId",["uitheme"]),f.trigger("applyWidgetId",["zebra"]));d.find("tr").not(k).remove();f.removeData("tablesorter").unbind("sortReset update updateAll updateRows updateCell addRows updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd resetToLoadState ".split(" ").join(e.namespace+ " "));e.$headers.add(l).removeClass([g.css.header,e.cssHeader,e.cssAsc,e.cssDesc,g.css.sortAsc,g.css.sortDesc,g.css.sortNone].join(" ")).removeAttr("data-column").removeAttr("aria-label").attr("aria-disabled","true");k.find(e.selectorSort).unbind(["mousedown","mouseup","keypress",""].join(e.namespace+" "));g.restoreHeaders(b);f.toggleClass(g.css.table+" "+e.tableClass+" tablesorter-"+e.theme,!1===a);b.hasInitialized=!1;delete b.config.cache;"function"===typeof c&&c(b)}};g.regex={chunk:/(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, chunks:/(^\\0|\\0$)/,hex:/^0x[0-9a-f]+$/i};g.sortNatural=function(b,a){if(b===a)return 0;var c,f,e,d,k,l;f=g.regex;if(f.hex.test(a)){c=parseInt(b.match(f.hex),16);e=parseInt(a.match(f.hex),16);if(c<e)return-1;if(c>e)return 1}c=b.replace(f.chunk,"\\0$1\\0").replace(f.chunks,"").split("\\0");f=a.replace(f.chunk,"\\0$1\\0").replace(f.chunks,"").split("\\0");l=Math.max(c.length,f.length);for(k=0;k<l;k++){e=isNaN(c[k])?c[k]||0:parseFloat(c[k])||0;d=isNaN(f[k])?f[k]||0:parseFloat(f[k])||0;if(isNaN(e)!== isNaN(d))return isNaN(e)?1:-1;typeof e!==typeof d&&(e+="",d+="");if(e<d)return-1;if(e>d)return 1}return 0};g.sortNaturalAsc=function(b,a,c,f,e){if(b===a)return 0;c=e.string[e.empties[c]||e.emptyTo];return""===b&&0!==c?"boolean"===typeof c?c?-1:1:-c||-1:""===a&&0!==c?"boolean"===typeof c?c?1:-1:c||1:g.sortNatural(b,a)};g.sortNaturalDesc=function(b,a,c,f,e){if(b===a)return 0;c=e.string[e.empties[c]||e.emptyTo];return""===b&&0!==c?"boolean"===typeof c?c?-1:1:c||1:""===a&&0!==c?"boolean"===typeof c?c? 1:-1:-c||-1:g.sortNatural(a,b)};g.sortText=function(b,a){return b>a?1:b<a?-1:0};g.getTextValue=function(b,a,c){if(c){var f=b?b.length:0,e=c+a;for(c=0;c<f;c++)e+=b.charCodeAt(c);return a*e}return 0};g.sortNumericAsc=function(b,a,c,f,e,d){if(b===a)return 0;d=d.config;e=d.string[d.empties[e]||d.emptyTo];if(""===b&&0!==e)return"boolean"===typeof e?e?-1:1:-e||-1;if(""===a&&0!==e)return"boolean"===typeof e?e?1:-1:e||1;isNaN(b)&&(b=g.getTextValue(b,c,f));isNaN(a)&&(a=g.getTextValue(a,c,f));return b-a};g.sortNumericDesc= function(b,a,c,f,e,d){if(b===a)return 0;d=d.config;e=d.string[d.empties[e]||d.emptyTo];if(""===b&&0!==e)return"boolean"===typeof e?e?-1:1:e||1;if(""===a&&0!==e)return"boolean"===typeof e?e?1:-1:-e||-1;isNaN(b)&&(b=g.getTextValue(b,c,f));isNaN(a)&&(a=g.getTextValue(a,c,f));return a-b};g.sortNumeric=function(b,a){return b-a};g.characterEquivalents={a:"\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5",A:"\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5",c:"\u00e7\u0107\u010d",C:"\u00c7\u0106\u010c",e:"\u00e9\u00e8\u00ea\u00eb\u011b\u0119", E:"\u00c9\u00c8\u00ca\u00cb\u011a\u0118",i:"\u00ed\u00ec\u0130\u00ee\u00ef\u0131",I:"\u00cd\u00cc\u0130\u00ce\u00cf",o:"\u00f3\u00f2\u00f4\u00f5\u00f6",O:"\u00d3\u00d2\u00d4\u00d5\u00d6",ss:"\u00df",SS:"\u1e9e",u:"\u00fa\u00f9\u00fb\u00fc\u016f",U:"\u00da\u00d9\u00db\u00dc\u016e"};g.replaceAccents=function(b){var a,c="[",f=g.characterEquivalents;if(!g.characterRegex){g.characterRegexArray={};for(a in f)"string"===typeof a&&(c+=f[a],g.characterRegexArray[a]=new RegExp("["+f[a]+"]","g"));g.characterRegex= new RegExp(c+"]")}if(g.characterRegex.test(b))for(a in f)"string"===typeof a&&(b=b.replace(g.characterRegexArray[a],a));return b};g.isValueInArray=function(b,a){var c,f=a.length;for(c=0;c<f;c++)if(a[c][0]===b)return c;return-1};g.addParser=function(b){var a,c=g.parsers.length,f=!0;for(a=0;a<c;a++)g.parsers[a].id.toLowerCase()===b.id.toLowerCase()&&(f=!1);f&&g.parsers.push(b)};g.getParserById=function(b){if("false"==b)return!1;var a,c=g.parsers.length;for(a=0;a<c;a++)if(g.parsers[a].id.toLowerCase()=== b.toString().toLowerCase())return g.parsers[a];return!1};g.addWidget=function(b){g.widgets.push(b)};g.hasWidget=function(b,a){b=h(b);return b.length&&b[0].config&&b[0].config.widgetInit[a]||!1};g.getWidgetById=function(b){var a,c,f=g.widgets.length;for(a=0;a<f;a++)if((c=g.widgets[a])&&c.hasOwnProperty("id")&&c.id.toLowerCase()===b.toLowerCase())return c};g.applyWidget=function(b,a){b=h(b)[0];var c=b.config,f=c.widgetOptions,e=" "+c.table.className+" ",d=[],k,l,n;!1!==a&&b.hasInitialized&&(b.isApplyingWidgets|| b.isUpdating)||(c.debug&&(k=new Date),n=new RegExp("\\s"+c.widgetClass.replace(/\{name\}/i,"([\\w-]+)")+"\\s","g"),e.match(n)&&(e=e.match(n))&&h.each(e,function(a,b){c.widgets.push(b.replace(n,"$1"))}),c.widgets.length&&(b.isApplyingWidgets=!0,c.widgets=h.grep(c.widgets,function(a,b){return h.inArray(a,c.widgets)===b}),h.each(c.widgets||[],function(a,b){(n=g.getWidgetById(b))&&n.id&&(n.priority||(n.priority=10),d[a]=n)}),d.sort(function(a,b){return a.priority<b.priority?-1:a.priority===b.priority? 0:1}),h.each(d,function(e,d){if(d){if(a||!c.widgetInit[d.id])c.widgetInit[d.id]=!0,d.hasOwnProperty("options")&&(f=b.config.widgetOptions=h.extend(!0,{},d.options,f)),d.hasOwnProperty("init")&&(c.debug&&(l=new Date),d.init(b,d,c,f),c.debug&&g.benchmark("Initializing "+d.id+" widget",l));!a&&d.hasOwnProperty("format")&&(c.debug&&(l=new Date),d.format(b,c,f,!1),c.debug&&g.benchmark((a?"Initializing ":"Applying ")+d.id+" widget",l))}})),setTimeout(function(){b.isApplyingWidgets=!1;h.data(b,"lastWidgetApplication", new Date)},0),c.debug&&(e=c.widgets.length,r("Completed "+(!0===a?"initializing ":"applying ")+e+" widget"+(1!==e?"s":""),k)))};g.refreshWidgets=function(b,a,c){b=h(b)[0];var f,e=b.config,k=e.widgets,r=g.widgets,l=r.length;for(f=0;f<l;f++)r[f]&&r[f].id&&(a||0>h.inArray(r[f].id,k))&&(e.debug&&d('Refeshing widgets: Removing "'+r[f].id+'"'),r[f].hasOwnProperty("remove")&&e.widgetInit[r[f].id]&&(r[f].remove(b,e,e.widgetOptions),e.widgetInit[r[f].id]=!1));!0!==c&&g.applyWidget(b,a)};g.getData=function(b, a,c){var d="";b=h(b);var e,g;if(!b.length)return"";e=h.metadata?b.metadata():!1;g=" "+(b.attr("class")||"");"undefined"!==typeof b.data(c)||"undefined"!==typeof b.data(c.toLowerCase())?d+=b.data(c)||b.data(c.toLowerCase()):e&&"undefined"!==typeof e[c]?d+=e[c]:a&&"undefined"!==typeof a[c]?d+=a[c]:" "!==g&&g.match(" "+c+"-")&&(d=g.match(new RegExp("\\s"+c+"-([\\w-]+)"))[1]||"");return h.trim(d)};g.formatFloat=function(b,a){if("string"!==typeof b||""===b)return b;var c;b=(a&&a.config?!1!==a.config.usNumberFormat: "undefined"!==typeof a?a:1)?b.replace(/,/g,""):b.replace(/[\s|\.]/g,"").replace(/,/g,".");/^\s*\([.\d]+\)/.test(b)&&(b=b.replace(/^\s*\(([.\d]+)\)/,"-$1"));c=parseFloat(b);return isNaN(c)?h.trim(b):c};g.isDigit=function(b){return isNaN(b)?/^[\-+(]?\d+[)]?$/.test(b.toString().replace(/[,.'"\s]/g,"")):!0}}});var p=h.tablesorter;h.fn.extend({tablesorter:p.construct});p.addParser({id:"no-parser",is:function(){return!1},format:function(){return""},type:"text"});p.addParser({id:"text",is:function(){return!0}, format:function(d,r){var k=r.config;d&&(d=h.trim(k.ignoreCase?d.toLocaleLowerCase():d),d=k.sortLocaleCompare?p.replaceAccents(d):d);return d},type:"text"});p.addParser({id:"digit",is:function(d){return p.isDigit(d)},format:function(d,r){var k=p.formatFloat((d||"").replace(/[^\w,. \-()]/g,""),r);return d&&"number"===typeof k?k:d?h.trim(d&&r.config.ignoreCase?d.toLocaleLowerCase():d):d},type:"numeric"});p.addParser({id:"currency",is:function(d){return/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/.test((d|| "").replace(/[+\-,. ]/g,""))},format:function(d,r){var k=p.formatFloat((d||"").replace(/[^\w,. \-()]/g,""),r);return d&&"number"===typeof k?k:d?h.trim(d&&r.config.ignoreCase?d.toLocaleLowerCase():d):d},type:"numeric"});p.addParser({id:"url",is:function(d){return/^(https?|ftp|file):\/\//.test(d)},format:function(d){return d?h.trim(d.replace(/(https?|ftp|file):\/\//,"")):d},parsed:!0,type:"text"});p.addParser({id:"isoDate",is:function(d){return/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/.test(d)},format:function(d, h){var k=d?new Date(d.replace(/-/g,"/")):d;return k instanceof Date&&isFinite(k)?k.getTime():d},type:"numeric"});p.addParser({id:"percent",is:function(d){return/(\d\s*?%|%\s*?\d)/.test(d)&&15>d.length},format:function(d,h){return d?p.formatFloat(d.replace(/%/g,""),h):d},type:"numeric"});p.addParser({id:"image",is:function(d,h,k,p){return 0<p.find("img").length},format:function(d,r,k){return h(k).find("img").attr(r.config.imgAttr||"alt")||d},parsed:!0,type:"text"});p.addParser({id:"usLongDate",is:function(d){return/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i.test(d)|| /^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i.test(d)},format:function(d,h){var k=d?new Date(d.replace(/(\S)([AP]M)$/i,"$1 $2")):d;return k instanceof Date&&isFinite(k)?k.getTime():d},type:"numeric"});p.addParser({id:"shortDate",is:function(d){return/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/.test((d||"").replace(/\s+/g," ").replace(/[\-.,]/g,"/"))},format:function(d,h,k,v){if(d){k=h.config;var z=k.$headers.filter("[data-column="+v+"]:last");v=z.length&&z[0].dateFormat||p.getData(z, p.getColumnData(h,k.headers,v),"dateFormat")||k.dateFormat;h=d.replace(/\s+/g," ").replace(/[\-.,]/g,"/");"mmddyyyy"===v?h=h.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,"$3/$1/$2"):"ddmmyyyy"===v?h=h.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,"$3/$2/$1"):"yyyymmdd"===v&&(h=h.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/,"$1/$2/$3"));h=new Date(h);return h instanceof Date&&isFinite(h)?h.getTime():d}return d},type:"numeric"});p.addParser({id:"time",is:function(d){return/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i.test(d)}, format:function(d,h){var k=d?new Date("2000/01/01 "+d.replace(/(\S)([AP]M)$/i,"$1 $2")):d;return k instanceof Date&&isFinite(k)?k.getTime():d},type:"numeric"});p.addParser({id:"metadata",is:function(){return!1},format:function(d,p,k){d=p.config;d=d.parserMetadataName?d.parserMetadataName:"sortValue";return h(k).metadata()[d]},type:"numeric"});p.addWidget({id:"zebra",priority:90,format:function(d,p,k){var v,z,y,B,F=new RegExp(p.cssChildRow,"i"),E=p.$tbodies;for(d=0;d<E.length;d++)y=0,v=E.eq(d),v=v.children("tr:visible").not(p.selectorRemove), v.each(function(){z=h(this);F.test(this.className)||y++;B=0===y%2;z.removeClass(k.zebra[B?1:0]).addClass(k.zebra[B?0:1])})},remove:function(d,h,k){var v;h=h.$tbodies;var z=(k.zebra||["even","odd"]).join(" ");for(k=0;k<h.length;k++)v=p.processTbody(d,h.eq(k),!0),v.children().removeClass(z),p.processTbody(d,v,!1)}})}(jQuery);
+/* jquery.tablesorter.widgets.min.js 2.18.4 */ ;(function(k,A){ var e=k.tablesorter=k.tablesorter||{}; e.themes={bootstrap:{table:"table table-bordered table-striped",caption:"caption",header:"bootstrap-header",footerRow:"",footerCells:"",icons:"",sortNone:"bootstrap-icon-unsorted",sortAsc:"icon-chevron-up glyphicon glyphicon-chevron-up",sortDesc:"icon-chevron-down glyphicon glyphicon-chevron-down",active:"",hover:"",filterRow:"",even:"",odd:""},jui:{table:"ui-widget ui-widget-content ui-corner-all",caption:"ui-widget-content",header:"ui-widget-header ui-corner-all ui-state-default", footerRow:"",footerCells:"",icons:"ui-icon",sortNone:"ui-icon-carat-2-n-s",sortAsc:"ui-icon-carat-1-n",sortDesc:"ui-icon-carat-1-s",active:"ui-state-active",hover:"ui-state-hover",filterRow:"",even:"ui-widget-content",odd:"ui-state-default"}};k.extend(e.css,{filterRow:"tablesorter-filter-row",filter:"tablesorter-filter",wrapper:"tablesorter-wrapper",resizer:"tablesorter-resizer",sticky:"tablesorter-stickyHeader",stickyVis:"tablesorter-sticky-visible",stickyWrap:"tablesorter-sticky-wrapper"}); e.storage= function(c,a,b,d){c=k(c)[0];var e,h,g=!1;e={};h=c.config;var m=k(c);c=d&&d.id||m.attr(d&&d.group||"data-table-group")||c.id||k(".tablesorter").index(m);d=d&&d.url||m.attr(d&&d.page||"data-table-page")||h&&h.fixedUrl||A.location.pathname;if("localStorage"in A)try{A.localStorage.setItem("_tmptest","temp"),g=!0,A.localStorage.removeItem("_tmptest")}catch(n){}k.parseJSON&&(g?e=k.parseJSON(localStorage[a]||"{}"):(h=document.cookie.split(/[;\s|=]/),e=k.inArray(a,h)+1,e=0!==e?k.parseJSON(h[e]||"{}"):{})); if((b||""===b)&&A.JSON&&JSON.hasOwnProperty("stringify"))e[d]||(e[d]={}),e[d][c]=b,g?localStorage[a]=JSON.stringify(e):(b=new Date,b.setTime(b.getTime()+31536E6),document.cookie=a+"="+JSON.stringify(e).replace(/\"/g,'"')+"; expires="+b.toGMTString()+"; path=/");else return e&&e[d]?e[d][c]:""}; e.addHeaderResizeEvent=function(c,a,b){c=k(c)[0];var d;b=k.extend({},{timer:250},b);var e=c.config,h=e.widgetOptions,g=function(a){h.resize_flag=!0;d=[];e.$headers.each(function(){var a=k(this),b=a.data("savedSizes")|| [0,0],c=this.offsetWidth,e=this.offsetHeight;if(c!==b[0]||e!==b[1])a.data("savedSizes",[c,e]),d.push(this)});d.length&&!1!==a&&e.$table.trigger("resize",[d]);h.resize_flag=!1};g(!1);clearInterval(h.resize_timer);if(a)return h.resize_flag=!1;h.resize_timer=setInterval(function(){h.resize_flag||g()},b.timer)}; e.addWidget({id:"uitheme",priority:10,format:function(c,a,b){var d,f,h,g=e.themes;d=a.$table;var m=a.$headers,n=a.theme||"jui",p=g[n]||g.jui,g=[p.sortNone,p.sortDesc,p.sortAsc,p.active].join(" "); a.debug&&(f=new Date);d.hasClass("tablesorter-"+n)&&a.theme===a.appliedTheme&&c.hasInitialized||(h=(c=p[a.appliedTheme]||{},[c.sortNone,c.sortDesc,c.sortAsc,c.active].join(" ")),c&&(b.zebra[0]=b.zebra[0].replace(" "+c.even,""),b.zebra[1]=b.zebra[1].replace(" "+c.odd,"")),""!==p.even&&(b.zebra[0]+=" "+p.even),""!==p.odd&&(b.zebra[1]+=" "+p.odd),d.children("caption").removeClass(c.caption).addClass(p.caption),b=d.removeClass(a.appliedTheme?"tablesorter-"+(a.appliedTheme||""):"").addClass("tablesorter-"+ n+" "+p.table).children("tfoot"),b.length&&b.children("tr").removeClass(c.footerRow||"").addClass(p.footerRow).children("th, td").removeClass(c.footerCells||"").addClass(p.footerCells),m.add(a.$extraHeaders).removeClass(c.header+" "+c.hover+" "+h).addClass(p.header).not(".sorter-false").bind("mouseenter.tsuitheme mouseleave.tsuitheme",function(a){k(this)["mouseenter"===a.type?"addClass":"removeClass"](p.hover)}),m.find("."+e.css.wrapper).length||m.wrapInner('<div class="'+e.css.wrapper+'" style="position:relative;height:100%;width:100%"></div>'), a.cssIcon&&m.find("."+e.css.icon).removeClass(c.icons+" "+h).addClass(p.icons),d.hasClass("hasFilters")&&d.children("thead").children("."+e.css.filterRow).removeClass(c.filterRow).addClass(p.filterRow),a.appliedTheme=a.theme);for(d=0;d<a.columns;d++)b=a.$headers.add(a.$extraHeaders).not(".sorter-false").filter('[data-column="'+d+'"]'),c=e.css.icon?b.find("."+e.css.icon):b,h=m.not(".sorter-false").filter('[data-column="'+d+'"]:last'),h.length&&(h[0].sortDisabled?(b.removeClass(g),c.removeClass(g+" "+ p.icons)):(h=b.hasClass(e.css.sortAsc)?p.sortAsc:b.hasClass(e.css.sortDesc)?p.sortDesc:b.hasClass(e.css.header)?p.sortNone:"",b[h===p.sortNone?"removeClass":"addClass"](p.active),c.removeClass(g).addClass(h)));a.debug&&e.benchmark("Applying "+n+" theme",f)},remove:function(c,a){var b=a.$table,d=a.theme||"jui",f=e.themes[d]||e.themes.jui,h=b.children("thead").children(),g=f.sortNone+" "+f.sortDesc+" "+f.sortAsc;b.removeClass("tablesorter-"+d+" "+f.table).find(e.css.header).removeClass(f.header);h.unbind("mouseenter.tsuitheme mouseleave.tsuitheme").removeClass(f.hover+ " "+g+" "+f.active).find("."+e.css.filterRow).removeClass(f.filterRow);h.find("."+e.css.icon).removeClass(f.icons)}}); e.addWidget({id:"columns",priority:30,options:{columns:["primary","secondary","tertiary"]},format:function(c,a,b){var d,f,h,g,m,n,p=a.$table,r=a.$tbodies,w=a.sortList,x=w.length,t=b&&b.columns||["primary","secondary","tertiary"],u=t.length-1;m=t.join(" ");for(d=0;d<r.length;d++)a=e.processTbody(c,r.eq(d),!0),f=a.children("tr"),f.each(function(){h=k(this);if("none"!==this.style.display&& (g=h.children().removeClass(m),w&&w[0]&&(g.eq(w[0][0]).addClass(t[0]),1<x)))for(n=1;n<x;n++)g.eq(w[n][0]).addClass(t[n]||t[u])}),e.processTbody(c,a,!1);c=!1!==b.columns_thead?["thead tr"]:[];!1!==b.columns_tfoot&&c.push("tfoot tr");if(c.length&&(f=p.find(c.join(",")).children().removeClass(m),x))for(n=0;n<x;n++)f.filter('[data-column="'+w[n][0]+'"]').addClass(t[n]||t[u])},remove:function(c,a,b){var d=a.$tbodies,f=(b.columns||["primary","secondary","tertiary"]).join(" ");a.$headers.removeClass(f); a.$table.children("tfoot").children("tr").children("th, td").removeClass(f);for(a=0;a<d.length;a++)b=e.processTbody(c,d.eq(a),!0),b.children("tr").each(function(){k(this).children().removeClass(f)}),e.processTbody(c,b,!1)}}); e.addWidget({id:"filter",priority:50,options:{filter_childRows:!1,filter_columnFilters:!0,filter_cellFilter:"",filter_cssFilter:"",filter_defaultFilter:{},filter_excludeFilter:{},filter_external:"",filter_filteredRow:"filtered",filter_formatter:null,filter_functions:null,filter_hideEmpty:!0, filter_hideFilters:!1,filter_ignoreCase:!0,filter_liveSearch:!0,filter_onlyAvail:"filter-onlyAvail",filter_placeholder:{search:"",select:""},filter_reset:null,filter_saveFilters:!1,filter_searchDelay:300,filter_searchFiltered:!0,filter_selectSource:null,filter_startsWith:!1,filter_useParsedData:!1,filter_serversideFiltering:!1,filter_defaultAttrib:"data-value",filter_selectSourceSeparator:"|"},format:function(c,a,b){a.$table.hasClass("hasFilters")||e.filter.init(c,a,b)},remove:function(c,a,b){var d, f=a.$tbodies;a.$table.removeClass("hasFilters").unbind("addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(a.namespace+"filter ")).find("."+e.css.filterRow).remove();for(a=0;a<f.length;a++)d=e.processTbody(c,f.eq(a),!0),d.children().removeClass(b.filter_filteredRow).show(),e.processTbody(c,d,!1);b.filter_reset&&k(document).undelegate(b.filter_reset,"click.tsfilter")}}); e.filter={regex:{regex:/^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/,child:/tablesorter-childRow/, filtered:/filtered/,type:/undefined|number/,exact:/(^[\"\'=]+)|([\"\'=]+$)/g,nondigit:/[^\w,. \-()]/g,operators:/[<>=]/g,query:"(q|query)"},types:{regex:function(c,a){if(e.filter.regex.regex.test(a.iFilter)){var b,d=e.filter.regex.regex.exec(a.iFilter);try{b=(new RegExp(d[1],d[2])).test(a.iExact)}catch(f){b=!1}return b}return null},operators:function(c,a){if(/^[<>]=?/.test(a.iFilter)){var b,d;b=c.table;var f=a.index,h=a.parsed[f],g=e.formatFloat(a.iFilter.replace(e.filter.regex.operators,""),b),m= c.parsers[f],n=g;if(h||"numeric"===m.type)d=e.filter.parseFilter(c,k.trim(""+a.iFilter.replace(e.filter.regex.operators,"")),f,h,!0),g="number"!==typeof d||""===d||isNaN(d)?g:d;b=!h&&"numeric"!==m.type||isNaN(g)||"undefined"===typeof a.cache?isNaN(a.iExact)?e.formatFloat(a.iExact.replace(e.filter.regex.nondigit,""),b):e.formatFloat(a.iExact,b):a.cache;/>/.test(a.iFilter)&&(d=/>=/.test(a.iFilter)?b>=g:b>g);/</.test(a.iFilter)&&(d=/<=/.test(a.iFilter)?b<=g:b<g);d||""!==n||(d=!0);return d}return null}, notMatch:function(c,a){if(/^\!/.test(a.iFilter)){var b,d=e.filter.parseFilter(c,a.iFilter.replace("!",""),a.index,a.parsed[a.index]);if(e.filter.regex.exact.test(d))return d=d.replace(e.filter.regex.exact,""),""===d?!0:k.trim(d)!==a.iExact;b=a.iExact.search(k.trim(d));return""===d?!0:!(c.widgetOptions.filter_startsWith?0===b:0<=b)}return null},exact:function(c,a){if(e.filter.regex.exact.test(a.iFilter)){var b=e.filter.parseFilter(c,a.iFilter.replace(e.filter.regex.exact,""),a.index,a.parsed[a.index]); return a.anyMatch?0<=k.inArray(b,a.rowArray):b==a.iExact}return null},and:function(c,a){if(e.filter.regex.andTest.test(a.filter)){for(var b=a.index,d=a.parsed[b],f=a.iFilter.split(e.filter.regex.andSplit),h=0<=a.iExact.search(k.trim(e.filter.parseFilter(c,f[0],b,d))),g=f.length-1;h&&g;)h=h&&0<=a.iExact.search(k.trim(e.filter.parseFilter(c,f[g],b,d))),g--;return h}return null},range:function(c,a){if(e.filter.regex.toTest.test(a.iFilter)){var b,d;d=c.table;var f=a.index,h=a.parsed[f],g=a.iFilter.split(e.filter.regex.toSplit), k=e.formatFloat(e.filter.parseFilter(c,g[0].replace(e.filter.regex.nondigit,""),f,h),d),n=e.formatFloat(e.filter.parseFilter(c,g[1].replace(e.filter.regex.nondigit,""),f,h),d);if(h||"numeric"===c.parsers[f].type)b=c.parsers[f].format(""+g[0],d,c.$headers.eq(f),f),k=""===b||isNaN(b)?k:b,b=c.parsers[f].format(""+g[1],d,c.$headers.eq(f),f),n=""===b||isNaN(b)?n:b;b=!h&&"numeric"!==c.parsers[f].type||isNaN(k)||isNaN(n)?isNaN(a.iExact)?e.formatFloat(a.iExact.replace(e.filter.regex.nondigit,""),d):e.formatFloat(a.iExact, d):a.cache;k>n&&(d=k,k=n,n=d);return b>=k&&b<=n||""===k||""===n}return null},wild:function(c,a){if(/[\?\*\|]/.test(a.iFilter)||e.filter.regex.orReplace.test(a.filter)){var b=a.index,d=a.parsed[b],d=e.filter.parseFilter(c,a.iFilter.replace(e.filter.regex.orReplace,"|"),b,d);!c.$headers.filter('[data-column="'+b+'"]:last').hasClass("filter-match")&&/\|/.test(d)&&("|"===d[d.length-1]&&(d+="*"),d=a.anyMatch&&k.isArray(a.rowArray)?"("+d+")":"^("+d+")$");return(new RegExp(d.replace(/\?/g,"\\S{1}").replace(/\*/g, "\\S*"))).test(a.iExact)}return null},fuzzy:function(c,a){if(/^~/.test(a.iFilter)){var b,d=0,f=a.iExact.length,h=e.filter.parseFilter(c,a.iFilter.slice(1),a.index,a.parsed[a.index]);for(b=0;b<f;b++)a.iExact[b]===h[d]&&(d+=1);return d===h.length?!0:!1}return null}},init:function(c,a,b){e.language=k.extend(!0,{},{to:"to",or:"or",and:"and"},e.language);var d,f,h,g,m,n,p;d=e.filter.regex;a.$table.addClass("hasFilters");b.searchTimer=null;b.filter_initTimer=null;b.filter_formatterCount=0;b.filter_formatterInit= [];b.filter_anyColumnSelector='[data-column="all"],[data-column="any"]';b.filter_multipleColumnSelector='[data-column*="-"],[data-column*=","]';h="\\{"+e.filter.regex.query+"\\}";k.extend(d,{child:new RegExp(a.cssChildRow),filtered:new RegExp(b.filter_filteredRow),alreadyFiltered:new RegExp("(\\s+("+e.language.or+"|-|"+e.language.to+")\\s+)","i"),toTest:new RegExp("\\s+(-|"+e.language.to+")\\s+","i"),toSplit:new RegExp("(?:\\s+(?:-|"+e.language.to+")\\s+)","gi"),andTest:new RegExp("\\s+("+e.language.and+ "|&&)\\s+","i"),andSplit:new RegExp("(?:\\s+(?:"+e.language.and+"|&&)\\s+)","gi"),orReplace:new RegExp("\\s+("+e.language.or+")\\s+","gi"),iQuery:new RegExp(h,"i"),igQuery:new RegExp(h,"ig")});!1!==b.filter_columnFilters&&a.$headers.filter(".filter-false, .parser-false").length!==a.$headers.length&&e.filter.buildRow(c,a,b);a.$table.bind("addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(a.namespace+"filter "),function(d,f){a.$table.find("."+ e.css.filterRow).toggle(!(b.filter_hideEmpty&&k.isEmptyObject(a.cache)&&(!a.delayInit||"appendCache"!==d.type)));/(search|filter)/.test(d.type)||(d.stopPropagation(),e.filter.buildDefault(c,!0));"filterReset"===d.type?(a.$table.find("."+e.css.filter).add(b.filter_$externalFilters).val(""),e.filter.searching(c,[])):"filterEnd"===d.type?e.filter.buildDefault(c,!0):(f="search"===d.type?f:"updateComplete"===d.type?a.$table.data("lastSearch"):"",/(update|add)/.test(d.type)&&"updateComplete"!==d.type&& (a.lastCombinedFilter=null,a.lastSearch=[]),e.filter.searching(c,f,!0));return!1});b.filter_reset&&(b.filter_reset instanceof k?b.filter_reset.click(function(){a.$table.trigger("filterReset")}):k(b.filter_reset).length&&k(document).undelegate(b.filter_reset,"click.tsfilter").delegate(b.filter_reset,"click.tsfilter",function(){a.$table.trigger("filterReset")}));if(b.filter_functions)for(m=0;m<a.columns;m++)if(h=e.getColumnData(c,b.filter_functions,m))if(g=a.$headers.filter('[data-column="'+m+'"]:last').removeClass("filter-select"), p=!(g.hasClass("filter-false")||g.hasClass("parser-false")),d="",!0===h&&p)e.filter.buildSelect(c,m);else if("object"===typeof h&&p){for(f in h)"string"===typeof f&&(d+=""===d?'<option value="">'+(g.data("placeholder")||g.attr("data-placeholder")||b.filter_placeholder.select||"")+"</option>":"",h=p=f,0<=f.indexOf(b.filter_selectSourceSeparator)&&(p=f.split(b.filter_selectSourceSeparator),h=p[1],p=p[0]),d+="<option "+(h===p?"":'data-function-name="'+f+'" ')+'value="'+p+'">'+h+"</option>");a.$table.find("thead").find("select."+ e.css.filter+'[data-column="'+m+'"]').append(d)}e.filter.buildDefault(c,!0);e.filter.bindSearch(c,a.$table.find("."+e.css.filter),!0);b.filter_external&&e.filter.bindSearch(c,b.filter_external);b.filter_hideFilters&&e.filter.hideFilters(c,a);a.showProcessing&&a.$table.bind("filterStart"+a.namespace+"filter filterEnd"+a.namespace+"filter",function(b,d){g=d?a.$table.find("."+e.css.header).filter("[data-column]").filter(function(){return""!==d[k(this).data("column")]}):"";e.isProcessing(c,"filterStart"=== b.type,d?g:"")});a.filteredRows=a.totalRows;a.$table.bind("tablesorter-initialized pagerBeforeInitialized",function(){var b=this.config.widgetOptions;n=e.filter.setDefaults(c,a,b)||[];n.length&&(a.delayInit&&""===n.join("")||e.setFilters(c,n,!0));a.$table.trigger("filterFomatterUpdate");setTimeout(function(){b.filter_initialized||e.filter.filterInitComplete(a)},100)});a.pager&&a.pager.initialized&&!b.filter_initialized&&(a.$table.trigger("filterFomatterUpdate"),setTimeout(function(){e.filter.filterInitComplete(a)}, 100))},formatterUpdated:function(c,a){var b=c.closest("table")[0].config.widgetOptions;b.filter_initialized||(b.filter_formatterInit[a]=1)},filterInitComplete:function(c){var a=c.widgetOptions,b=0,d=function(){a.filter_initialized=!0;c.$table.trigger("filterInit",c);e.filter.findRows(c.table,c.$table.data("lastSearch")||[])};k.isEmptyObject(a.filter_formatter)?d():(k.each(a.filter_formatterInit,function(a,c){1===c&&b++}),clearTimeout(a.filter_initTimer),a.filter_initialized||b!==a.filter_formatterCount)? a.filter_initialized||(a.filter_initTimer=setTimeout(function(){d()},500)):d()},setDefaults:function(c,a,b){var d,f=e.getFilters(c)||[];b.filter_saveFilters&&e.storage&&(d=e.storage(c,"tablesorter-filters")||[],(c=k.isArray(d))&&""===d.join("")||!c||(f=d));if(""===f.join(""))for(c=0;c<a.columns;c++)f[c]=a.$headers.filter('[data-column="'+c+'"]:last').attr(b.filter_defaultAttrib)||f[c];a.$table.data("lastSearch",f);return f},parseFilter:function(c,a,b,d,e){return e||d?c.parsers[b].format(a,c.table, [],b):a},buildRow:function(c,a,b){var d,f,h,g,m=a.columns;h=k.isArray(b.filter_cellFilter);g='<tr role="row" class="'+e.css.filterRow+'">';for(f=0;f<m;f++)g=h?g+("<td"+(b.filter_cellFilter[f]?' class="'+b.filter_cellFilter[f]+'"':"")+"></td>"):g+("<td"+(""!==b.filter_cellFilter?' class="'+b.filter_cellFilter+'"':"")+"></td>");a.$filters=k(g+"</tr>").appendTo(a.$table.children("thead").eq(0)).find("td");for(f=0;f<m;f++)h=a.$headers.filter('[data-column="'+f+'"]:last'),g=e.getColumnData(c,b.filter_functions, f),g=b.filter_functions&&g&&"function"!==typeof g||h.hasClass("filter-select"),d=e.getColumnData(c,a.headers,f),d="false"===e.getData(h[0],d,"filter")||"false"===e.getData(h[0],d,"parser"),g?g=k("<select>").appendTo(a.$filters.eq(f)):((g=e.getColumnData(c,b.filter_formatter,f))?(b.filter_formatterCount++,(g=g(a.$filters.eq(f),f))&&0===g.length&&(g=a.$filters.eq(f).children("input")),g&&(0===g.parent().length||g.parent().length&&g.parent()[0]!==a.$filters[f])&&a.$filters.eq(f).append(g)):g=k('<input type="search">').appendTo(a.$filters.eq(f)), g&&g.attr("placeholder",h.data("placeholder")||h.attr("data-placeholder")||b.filter_placeholder.search||"")),g&&(h=(k.isArray(b.filter_cssFilter)?"undefined"!==typeof b.filter_cssFilter[f]?b.filter_cssFilter[f]||"":"":b.filter_cssFilter)||"",g.addClass(e.css.filter+" "+h).attr("data-column",f),d&&(g.attr("placeholder","").addClass("disabled")[0].disabled=!0))},bindSearch:function(c,a,b){c=k(c)[0];a=k(a);if(a.length){var d=c.config,f=d.widgetOptions,h=f.filter_$externalFilters;!0!==b&&(f.filter_$anyMatch= a.filter(f.filter_anyColumnSelector+","+f.filter_multipleColumnSelector),f.filter_$externalFilters=h&&h.length?f.filter_$externalFilters.add(a):a,e.setFilters(c,d.$table.data("lastSearch")||[],!1===b));a.attr("data-lastSearchTime",(new Date).getTime()).unbind(["keypress","keyup","search","change",""].join(d.namespace+"filter ")).bind("keyup"+d.namespace+"filter",function(a){k(this).attr("data-lastSearchTime",(new Date).getTime());if(27===a.which)this.value="";else if(!1===f.filter_liveSearch||""!== this.value&&("number"===typeof f.filter_liveSearch&&this.value.length<f.filter_liveSearch||13!==a.which&&8!==a.which&&(32>a.which||37<=a.which&&40>=a.which)))return;e.filter.searching(c,!0,!0)}).bind(["search","change","keypress",""].join(d.namespace+"filter "),function(a){var b=k(this).data("column");if(13===a.which||"search"===a.type||"change"===a.type&&this.value!==d.lastSearch[b])a.preventDefault(),k(this).attr("data-lastSearchTime",(new Date).getTime()),e.filter.searching(c,!1,!0)})}},searching:function(c, a,b){var d=c.config.widgetOptions;clearTimeout(d.searchTimer);"undefined"===typeof a||!0===a?d.searchTimer=setTimeout(function(){e.filter.checkFilters(c,a,b)},d.filter_liveSearch?d.filter_searchDelay:10):e.filter.checkFilters(c,a,b)},checkFilters:function(c,a,b){var d=c.config,f=d.widgetOptions,h=k.isArray(a),g=h?a:e.getFilters(c,!0),m=(g||[]).join("");if(k.isEmptyObject(d.cache))d.delayInit&&d.pager&&d.pager.initialized&&d.$table.trigger("updateCache",[function(){e.filter.checkFilters(c,!1,b)}]); else if(h&&(e.setFilters(c,g,!1,!0!==b),f.filter_initialized||(d.lastCombinedFilter="")),f.filter_hideFilters&&d.$table.find("."+e.css.filterRow).trigger(""===m?"mouseleave":"mouseenter"),d.lastCombinedFilter!==m||!1===a)if(!1===a&&(d.lastCombinedFilter=null,d.lastSearch=[]),f.filter_initialized&&d.$table.trigger("filterStart",[g]),d.showProcessing)setTimeout(function(){e.filter.findRows(c,g,m);return!1},30);else return e.filter.findRows(c,g,m),!1},hideFilters:function(c,a){var b,d,f;k(c).find("."+ e.css.filterRow).addClass("hideme").bind("mouseenter mouseleave",function(c){b=k(this);clearTimeout(f);f=setTimeout(function(){/enter|over/.test(c.type)?b.removeClass("hideme"):k(document.activeElement).closest("tr")[0]!==b[0]&&""===a.lastCombinedFilter&&b.addClass("hideme")},200)}).find("input, select").bind("focus blur",function(b){d=k(this).closest("tr");clearTimeout(f);f=setTimeout(function(){if(""===e.getFilters(a.$table).join(""))d["focus"===b.type?"removeClass":"addClass"]("hideme")},200)})}, defaultFilter:function(c,a){if(""===c)return c;var b=e.filter.regex.iQuery,d=a.match(e.filter.regex.igQuery).length,f=1<d?k.trim(c).split(/\s/):[k.trim(c)],h=f.length-1,g=0,m=a;for(1>h&&1<d&&(f[1]=f[0]);b.test(m);)m=m.replace(b,f[g++]||""),b.test(m)&&g<h&&""!==(f[g]||"")&&(m=a.replace(b,m));return m},getLatestSearch:function(c){return c.sort(function(a,b){return k(b).attr("data-lastSearchTime")-k(a).attr("data-lastSearchTime")})},multipleColumns:function(c,a){var b,d;b=c.widgetOptions;var f=b.filter_initialized|| !a.filter(b.filter_anyColumnSelector).length,h=[],g=k.trim(e.filter.getLatestSearch(a).attr("data-column"));f&&/-/.test(g)&&(b=g.match(/(\d+)\s*-\s*(\d+)/g),k.each(b,function(a,b){var d;d=b.split(/\s*-\s*/);var e=parseInt(d[0],10)||0,f=parseInt(d[1],10)||c.columns-1;e>f&&(d=e,e=f,f=d);for(f>=c.columns&&(f=c.columns-1);e<=f;e++)h.push(e);g=g.replace(b,"")}));f&&/,/.test(g)&&(b=g.split(/\s*,\s*/),k.each(b,function(a,b){""!==b&&(d=parseInt(b,10),d<c.columns&&h.push(d))}));if(!h.length)for(d=0;d<c.columns;d++)h.push(d); return h},findRows:function(c,a,b){if(c.config.lastCombinedFilter!==b&&c.config.widgetOptions.filter_initialized){var d,f,h,g,m,n,p,r,w,x,t,u,y,A,z,B,C,G,D,H,F=e.filter.regex,q=c.config,v=q.widgetOptions,I=q.$table.children("tbody"),l={anyMatch:!1},J=["range","notMatch","operators"];l.parsed=q.$headers.map(function(a){return q.parsers&&q.parsers[a]&&q.parsers[a].parsed||e.getData&&"parsed"===e.getData(q.$headers.filter('[data-column="'+a+'"]:last'),e.getColumnData(c,q.headers,a),"filter")||k(this).hasClass("filter-parsed")}).get(); q.debug&&(e.log("Starting filter widget search",a),A=new Date);q.filteredRows=0;q.totalRows=0;b=(a||[]).join("");for(g=0;g<I.length;g++)if(!I.eq(g).hasClass(q.cssInfoBlock||e.css.info)){m=e.processTbody(c,I.eq(g),!0);r=q.columns;f=k(k.map(q.cache[g].normalized,function(a){return a[r].$row.get()}));if(""===b||v.filter_serversideFiltering)f.removeClass(v.filter_filteredRow).not("."+q.cssChildRow).show();else{f=f.not("."+q.cssChildRow);d=f.length;B=v.filter_searchFiltered;h=q.lastSearch||q.$table.data("lastSearch")|| [];if(B)for(n=0;n<r+1;n++)z=a[n]||"",B||(n=r),B=B&&h.length&&0===z.indexOf(h[n]||"")&&!F.alreadyFiltered.test(z)&&!/[=\"\|!]/.test(z)&&!(/(>=?\s*-\d)/.test(z)||/(<=?\s*\d)/.test(z))&&!(""!==z&&q.$filters&&q.$filters.eq(n).find("select").length&&!q.$headers.filter('[data-column="'+n+'"]:last').hasClass("filter-match"));z=f.not("."+v.filter_filteredRow).length;B&&0===z&&(B=!1);q.debug&&e.log("Searching through "+(B&&z<d?z:"all")+" rows");if(v.filter_$anyMatch&&v.filter_$anyMatch.length||a[q.columns])l.anyMatchFlag= !0,l.anyMatchFilter=v.filter_$anyMatch&&e.filter.getLatestSearch(v.filter_$anyMatch).val()||a[q.columns]||"",q.sortLocaleCompare&&(l.anyMatchFilter=e.replaceAccents(l.anyMatchFilter)),v.filter_defaultFilter&&F.iQuery.test(e.getColumnData(c,v.filter_defaultFilter,q.columns,!0)||"")&&(l.anyMatchFilter=e.filter.defaultFilter(l.anyMatchFilter,e.getColumnData(c,v.filter_defaultFilter,q.columns,!0)),B=!1),l.iAnyMatchFilter=v.filter_ignoreCase&&q.ignoreCase?l.anyMatchFilter.toLocaleLowerCase():l.anyMatchFilter; for(h=0;h<d;h++)if(l.cacheArray=q.cache[g].normalized[h],w=f[h].className,!(F.child.test(w)||B&&F.filtered.test(w))){y=!0;w=f.eq(h).nextUntil("tr:not(."+q.cssChildRow+")");l.childRowText=w.length&&v.filter_childRows?w.text():"";l.childRowText=v.filter_ignoreCase?l.childRowText.toLocaleLowerCase():l.childRowText;n=f.eq(h).children();if(l.anyMatchFlag){r=e.filter.multipleColumns(q,v.filter_$anyMatch);l.anyMatch=!0;l.rowArray=n.map(function(a){if(-1<k.inArray(a,r))return l.parsed[a]?a=l.cacheArray[a]: (a=v.filter_ignoreCase?k(this).text().toLowerCase():k(this).text(),q.sortLocaleCompare&&(a=e.replaceAccents(a))),a}).get();l.filter=l.anyMatchFilter;l.iFilter=l.iAnyMatchFilter;l.exact=l.rowArray.join(" ");l.iExact=v.filter_ignoreCase?l.exact.toLowerCase():l.exact;l.cache=l.cacheArray.slice(0,-1).join(" ");C=null;k.each(e.filter.types,function(a,b){if(0>k.inArray(a,J)&&(t=b(q,l),null!==t))return C=t,!1});if(null!==C)y=C;else if(v.filter_startsWith)for(y=!1,r=q.columns;!y&&0<r;)r--,y=y||0===l.rowArray[r].indexOf(l.iFilter); else y=0<=(l.iExact+l.childRowText).indexOf(l.iFilter);l.anyMatch=!1}for(r=0;r<q.columns;r++)l.filter=a[r],l.index=r,G=(e.getColumnData(c,v.filter_excludeFilter,r,!0)||"").split(/\s+/),l.filter&&(l.cache=l.cacheArray[r],v.filter_useParsedData||l.parsed[r]?l.exact=l.cache:(l.exact=k.trim(n.eq(r).text()),l.exact=q.sortLocaleCompare?e.replaceAccents(l.exact):l.exact),l.iExact=!F.type.test(typeof l.exact)&&v.filter_ignoreCase?l.exact.toLocaleLowerCase():l.exact,u=y,H=v.filter_columnFilters?q.$filters.add(q.$externalFilters).filter('[data-column="'+ r+'"]').find("select option:selected").attr("data-function-name")||"":"",l.filter=q.sortLocaleCompare?e.replaceAccents(l.filter):l.filter,z=!0,v.filter_defaultFilter&&F.iQuery.test(e.getColumnData(c,v.filter_defaultFilter,r)||"")&&(l.filter=e.filter.defaultFilter(l.filter,e.getColumnData(c,v.filter_defaultFilter,r)),z=!1),l.iFilter=v.filter_ignoreCase?(l.filter||"").toLocaleLowerCase():l.filter,D=e.getColumnData(c,v.filter_functions,r),p=q.$headers.filter('[data-column="'+r+'"]:last'),x=p.hasClass("filter-select"), D||x&&z?!0===D||x?u=p.hasClass("filter-match")?0<=l.iExact.search(l.iFilter):l.filter===l.exact:"function"===typeof D?u=D(l.exact,l.cache,l.filter,r,f.eq(h)):"function"===typeof D[H||l.filter]&&(u=D[H||l.filter](l.exact,l.cache,l.filter,r,f.eq(h))):(C=null,k.each(e.filter.types,function(a,b){if(0>k.inArray(a,G)&&(t=b(q,l),null!==t))return C=t,!1}),null!==C?u=C:(l.exact=(l.iExact+l.childRowText).indexOf(e.filter.parseFilter(q,l.iFilter,r,l.parsed[r])),u=!v.filter_startsWith&&0<=l.exact||v.filter_startsWith&& 0===l.exact)),y=u?y:!1);f.eq(h).toggle(y).toggleClass(v.filter_filteredRow,!y);w.length&&w.toggleClass(v.filter_filteredRow,!y)}}q.filteredRows+=f.not("."+v.filter_filteredRow).length;q.totalRows+=f.length;e.processTbody(c,m,!1)}q.lastCombinedFilter=b;q.lastSearch=a;q.$table.data("lastSearch",a);v.filter_saveFilters&&e.storage&&e.storage(c,"tablesorter-filters",a);q.debug&&e.benchmark("Completed filter widget search",A);v.filter_initialized&&q.$table.trigger("filterEnd",q);setTimeout(function(){q.$table.trigger("applyWidgets")}, 0)}},getOptionSource:function(c,a,b){var d,f=c.config,h=[],g=!1,m=f.widgetOptions.filter_selectSource,n=f.$table.data("lastSearch")||[],p=k.isFunction(m)?!0:e.getColumnData(c,m,a);b&&""!==n[a]&&(b=!1);if(!0===p)g=m(c,a,b);else{if(p instanceof k||"string"===k.type(p)&&0<=p.indexOf("</option>"))return p;k.isArray(p)?g=p:"object"===k.type(m)&&p&&(g=p(c,a,b))}!1===g&&(g=e.filter.getOptions(c,a,b));g=k.grep(g,function(a,b){return k.inArray(a,g)===b});f.$headers.filter('[data-column="'+a+'"]:last').hasClass("filter-select-nosort")|| (k.each(g,function(b,d){h.push({t:d,p:f.parsers&&f.parsers[a].format(d,c,[],a)})}),d=f.textSorter||"",h.sort(function(b,f){var g=b.p.toString(),h=f.p.toString();return k.isFunction(d)?d(g,h,!0,a,c):"object"===typeof d&&d.hasOwnProperty(a)?d[a](g,h,!0,a,c):e.sortNatural?e.sortNatural(g,h):!0}),g=[],k.each(h,function(a,b){g.push(b.t)}));return g},getOptions:function(c,a,b){var d,e,h,g,m=c.config,n=m.widgetOptions,p=m.$table.children("tbody"),r=[];for(d=0;d<p.length;d++)if(!p.eq(d).hasClass(m.cssInfoBlock))for(g= m.cache[d],e=m.cache[d].normalized.length,c=0;c<e;c++)h=g.row?g.row[c]:g.normalized[c][m.columns].$row[0],b&&h.className.match(n.filter_filteredRow)||(n.filter_useParsedData||m.parsers[a].parsed||m.$headers.filter('[data-column="'+a+'"]:last').hasClass("filter-parsed")?r.push(""+g.normalized[c][a]):(h=h.cells[a])&&r.push(k.trim(h.textContent||h.innerText||k(h).text())));return r},buildSelect:function(c,a,b,d,f){c=k(c)[0];a=parseInt(a,10);if(c.config.cache&&!k.isEmptyObject(c.config.cache)){var h, g;g=c.config;var m=g.widgetOptions,n=g.$headers.filter('[data-column="'+a+'"]:last'),n='<option value="">'+(n.data("placeholder")||n.attr("data-placeholder")||m.filter_placeholder.select||"")+"</option>",p=g.$table.find("thead").find("select."+e.css.filter+'[data-column="'+a+'"]').val();if("undefined"===typeof b||""===b)b=e.filter.getOptionSource(c,a,f);if(k.isArray(b)){for(c=0;c<b.length;c++)f=h=b[c]=(""+b[c]).replace(/\"/g,"&quot;"),0<=h.indexOf(m.filter_selectSourceSeparator)&&(h=h.split(m.filter_selectSourceSeparator), f=h[0],h=h[1]),n+=""!==b[c]?"<option "+(f===h?"":'data-function-name="'+b[c]+'" ')+'value="'+f+'">'+h+"</option>":"";b=[]}g=(g.$filters?g.$filters:g.$table.children("thead")).find("."+e.css.filter);m.filter_$externalFilters&&(g=g&&g.length?g.add(m.filter_$externalFilters):m.filter_$externalFilters);a=g.filter('select[data-column="'+a+'"]');a.length&&(a[d?"html":"append"](n),k.isArray(b)||a.append(b).val(p),a.val(p))}},buildDefault:function(c,a){var b,d,f,h=c.config,g=h.widgetOptions,k=h.columns;for(b= 0;b<k;b++)d=h.$headers.filter('[data-column="'+b+'"]:last'),f=!(d.hasClass("filter-false")||d.hasClass("parser-false")),(d.hasClass("filter-select")||!0===e.getColumnData(c,g.filter_functions,b))&&f&&e.filter.buildSelect(c,b,"",a,d.hasClass(g.filter_onlyAvail))}}; e.getFilters=function(c,a,b,d){var f,h,g=!1,m=c?k(c)[0].config:"",n=m?m.widgetOptions:"";if(!0!==a&&n&&!n.filter_columnFilters)return k(c).data("lastSearch");if(m&&(m.$filters&&(f=m.$filters.find("."+e.css.filter)),n.filter_$externalFilters&& (f=f&&f.length?f.add(n.filter_$externalFilters):n.filter_$externalFilters),f&&f.length))for(g=b||[],c=0;c<m.columns+1;c++)h=c===m.columns?n.filter_anyColumnSelector+","+n.filter_multipleColumnSelector:'[data-column="'+c+'"]',a=f.filter(h),a.length&&(a=e.filter.getLatestSearch(a),k.isArray(b)?(d&&a.slice(1),c===m.columns&&(h=a.filter(n.filter_anyColumnSelector),a=h.length?h:a),a.val(b[c]).trigger("change.tsfilter")):(g[c]=a.val()||"",c===m.columns?a.slice(1).filter('[data-column*="'+a.attr("data-column")+ '"]').val(g[c]):a.slice(1).val(g[c])),c===m.columns&&a.length&&(n.filter_$anyMatch=a));0===g.length&&(g=!1);return g}; e.setFilters=function(c,a,b,d){var f=c?k(c)[0].config:"";c=e.getFilters(c,!0,a,d);f&&b&&(f.lastCombinedFilter=null,f.lastSearch=[],e.filter.searching(f.$table[0],a,d),f.$table.trigger("filterFomatterUpdate"));return!!c}; e.addWidget({id:"stickyHeaders",priority:60,options:{stickyHeaders:"",stickyHeaders_attachTo:null,stickyHeaders_xScroll:null,stickyHeaders_yScroll:null,stickyHeaders_offset:0, stickyHeaders_filteredToTop:!0,stickyHeaders_cloneId:"-sticky",stickyHeaders_addResizeEvent:!0,stickyHeaders_includeCaption:!0,stickyHeaders_zIndex:2},format:function(c,a,b){if(!(a.$table.hasClass("hasStickyHeaders")||0<=k.inArray("filter",a.widgets)&&!a.$table.hasClass("hasFilters"))){var d=a.$table,f=k(b.stickyHeaders_attachTo),h=a.namespace+"stickyheaders ",g=k(b.stickyHeaders_yScroll||b.stickyHeaders_attachTo||A),m=k(b.stickyHeaders_xScroll||b.stickyHeaders_attachTo||A),n=d.children("thead:first").children("tr").not(".sticky-false").children(), p=d.children("tfoot"),r=isNaN(b.stickyHeaders_offset)?k(b.stickyHeaders_offset):"",w=f.length?0:r.length?r.height()||0:parseInt(b.stickyHeaders_offset,10)||0,x=d.parent().closest("."+e.css.table).hasClass("hasStickyHeaders")?d.parent().closest("table.tablesorter")[0].config.widgetOptions.$sticky.parent():[],t=x.length?x.height():0,u=b.$sticky=d.clone().addClass("containsStickyHeaders "+e.css.sticky+" "+b.stickyHeaders).wrap('<div class="'+e.css.stickyWrap+'">'),y=u.parent().css({position:f.length? "absolute":"fixed",padding:parseInt(u.parent().parent().css("padding-left"),10),top:w+t,left:0,visibility:"hidden",zIndex:b.stickyHeaders_zIndex||2}),E=u.children("thead:first"),z,B="",C=0,G=function(a,b){a.filter(":visible").each(function(a){var d;a=b.filter(":visible").eq(a);var c=k(this);"border-box"===c.css("box-sizing")?d=c.outerWidth():"collapse"===a.css("border-collapse")?A.getComputedStyle?d=parseFloat(A.getComputedStyle(this,null).width):(d=parseFloat(c.css("border-width")),d=c.outerWidth()- parseFloat(c.css("padding-left"))-parseFloat(c.css("padding-right"))-d):d=c.width();a.css({"min-width":d,"max-width":d})})},D=function(){w=r.length?r.height()||0:parseInt(b.stickyHeaders_offset,10)||0;C=0;y.css({left:f.length?parseInt(f.css("padding-left"),10)||0:d.offset().left-parseInt(d.css("margin-left"),10)-m.scrollLeft()-C,width:d.outerWidth()});G(d,u);G(n,z)};u.attr("id")&&(u[0].id+=b.stickyHeaders_cloneId);u.find("thead:gt(0), tr.sticky-false").hide();u.find("tbody, tfoot").remove();u.find("caption").toggle(b.stickyHeaders_includeCaption); z=E.children().children();u.css({height:0,width:0,margin:0});z.find("."+e.css.resizer).remove();d.addClass("hasStickyHeaders").bind("pagerComplete"+h,function(){D()});e.bindEvents(c,E.children().children(".tablesorter-header"));d.after(y);a.onRenderHeader&&E.children("tr").children().each(function(b){a.onRenderHeader.apply(k(this),[b,a,u])});m.add(g).unbind(["scroll","resize",""].join(h)).bind(["scroll","resize",""].join(h),function(a){if(d.is(":visible")){t=x.length?x.offset().top-g.scrollTop()+ x.height():0;var b=d.offset(),c=k.isWindow(g[0]),e=k.isWindow(m[0]),h=(f.length?c?g.scrollTop():g.offset().top:g.scrollTop())+w+t,l=d.height()-(y.height()+(p.height()||0)),b=h>b.top&&h<b.top+l?"visible":"hidden",l={visibility:b};f.length&&(l.top=c?h:f.scrollTop());e&&(l.left=d.offset().left-parseInt(d.css("margin-left"),10)-m.scrollLeft()-C);x.length&&(l.top=(l.top||0)+w+t);y.removeClass("tablesorter-sticky-visible tablesorter-sticky-hidden").addClass("tablesorter-sticky-"+b).css(l);if(b!==B||"resize"=== a.type)D(),B=b}});b.stickyHeaders_addResizeEvent&&e.addHeaderResizeEvent(c);d.hasClass("hasFilters")&&b.filter_columnFilters&&(d.bind("filterEnd"+h,function(){var c=k(document.activeElement).closest("td"),c=c.parent().children().index(c);y.hasClass(e.css.stickyVis)&&b.stickyHeaders_filteredToTop&&(A.scrollTo(0,d.position().top),0<=c&&a.$filters&&a.$filters.eq(c).find("a, select, input").filter(":visible").focus())}),e.filter.bindSearch(d,z.find("."+e.css.filter)),b.filter_hideFilters&&e.filter.hideFilters(u, a));d.trigger("stickyHeadersInit")}},remove:function(c,a,b){var d=a.namespace+"stickyheaders ";a.$table.removeClass("hasStickyHeaders").unbind(["pagerComplete","filterEnd",""].join(d)).next("."+e.css.stickyWrap).remove();b.$sticky&&b.$sticky.length&&b.$sticky.remove();k(".hasStickyHeaders").length||k(A).add(b.stickyHeaders_xScroll).add(b.stickyHeaders_yScroll).add(b.stickyHeaders_attachTo).unbind(["scroll","resize",""].join(d));e.addHeaderResizeEvent(c,!1)}}); e.addWidget({id:"resizable",priority:40, options:{resizable:!0,resizable_addLastColumn:!1,resizable_widths:[],resizable_throttle:!1},format:function(c,a,b){if(!a.$table.hasClass("hasResizable")){a.$table.addClass("hasResizable");e.resizableReset(c,!0);var d,f,h,g,m,n={},p=a.$table,r=p.parent(),w="auto"===p.parent().css("overflow"),x=0,t=null,u=null,y=20>Math.abs(p.parent().width()-p.width()),E=function(a){if(0!==x&&t){var b=a.pageX-x,c=t.width();t.width(c+b);t.width()!==c&&y?u.width(u.width()-b):w&&(p.width(function(a,c){return c+b}),u.length|| (r[0].scrollLeft=p.width()));x=a.pageX}},z=function(){e.storage&&t&&u&&(n={},n[t.index()]=t.width(),n[u.index()]=u.width(),t.width(n[t.index()]),u.width(n[u.index()]),!1!==b.resizable&&e.storage(c,"tablesorter-resizable",a.$headers.map(function(){return k(this).width()}).get()));x=0;t=u=null;k(A).trigger("resize")};if(n=e.storage&&!1!==b.resizable?e.storage(c,"tablesorter-resizable"):{})for(g in n)!isNaN(g)&&g<a.$headers.length&&a.$headers.eq(g).width(n[g]);d=p.children("thead:first").children("tr"); d.children().each(function(){var b;b=k(this);g=b.attr("data-column");b="false"===e.getData(b,e.getColumnData(c,a.headers,g),"resizable");d.children().filter('[data-column="'+g+'"]')[b?"addClass":"removeClass"]("resizable-false")});d.each(function(){h=k(this).children().not(".resizable-false");k(this).find("."+e.css.wrapper).length||h.wrapInner('<div class="'+e.css.wrapper+'" style="position:relative;height:100%;width:100%"></div>');b.resizable_addLastColumn||(h=h.slice(0,-1));f=f?f.add(h):h});f.each(function(){var a= k(this),b=parseInt(a.css("padding-right"),10)+10;a.find("."+e.css.wrapper).append('<div class="'+e.css.resizer+'" style="cursor:w-resize;position:absolute;z-index:1;right:-'+b+'px;top:0;height:100%;width:20px;"></div>')}).find("."+e.css.resizer).bind("mousedown",function(b){t=k(b.target).closest("th");var c=a.$headers.filter('[data-column="'+t.attr("data-column")+'"]');1<c.length&&(t=t.add(c));u=b.shiftKey?t.parent().find("th").not(".resizable-false").filter(":last"):t.nextAll(":not(.resizable-false)").eq(0); x=b.pageX});k(document).bind("mousemove.tsresize",function(a){0!==x&&t&&(b.resizable_throttle?(clearTimeout(m),m=setTimeout(function(){E(a)},isNaN(b.resizable_throttle)?5:b.resizable_throttle)):E(a))}).bind("mouseup.tsresize",function(){z()});p.find("thead:first").bind("contextmenu.tsresize",function(){e.resizableReset(c);var a=k.isEmptyObject?k.isEmptyObject(n):!0;n={};return a})}},remove:function(c,a){a.$table.removeClass("hasResizable").children("thead").unbind("mouseup.tsresize mouseleave.tsresize contextmenu.tsresize").children("tr").children().unbind("mousemove.tsresize mouseup.tsresize").find("."+ e.css.resizer).remove();e.resizableReset(c)}}); e.resizableReset=function(c,a){k(c).each(function(){var b,d=this.config,f=d&&d.widgetOptions;c&&d&&(d.$headers.each(function(a){b=k(this);f.resizable_widths[a]?b.css("width",f.resizable_widths[a]):b.hasClass("resizable-false")||b.css("width","")}),e.storage&&!a&&e.storage(this,"tablesorter-resizable",{}))})}; e.addWidget({id:"saveSort",priority:20,options:{saveSort:!0},init:function(c,a,b,d){a.format(c,b,d,!0)},format:function(c,a,b,d){var f,h=a.$table; b=!1!==b.saveSort;var g={sortList:a.sortList};a.debug&&(f=new Date);h.hasClass("hasSaveSort")?b&&c.hasInitialized&&e.storage&&(e.storage(c,"tablesorter-savesort",g),a.debug&&e.benchmark("saveSort widget: Saving last sort: "+a.sortList,f)):(h.addClass("hasSaveSort"),g="",e.storage&&(g=(b=e.storage(c,"tablesorter-savesort"))&&b.hasOwnProperty("sortList")&&k.isArray(b.sortList)?b.sortList:"",a.debug&&e.benchmark('saveSort: Last sort loaded: "'+g+'"',f),h.bind("saveSortReset",function(a){a.stopPropagation(); e.storage(c,"tablesorter-savesort","")})),d&&g&&0<g.length?a.sortList=g:c.hasInitialized&&g&&0<g.length&&h.trigger("sorton",[g]))},remove:function(c){e.storage&&e.storage(c,"tablesorter-savesort","")}}) })(jQuery,window);
+/* tablesorter */ $(document).ready(function(){$('table').tablesorter({theme:'bootstrap',widgets:['uitheme','zebra','filter'],headerTemplate:'{content} {icon}',widthFixed:true,ignoreCase:true,widgetOptions:{filter_columnFilters:true,zebra:['even','odd'],filter_reset:'.reset'}});});
+/* treegrid */ $(document).ready(function(){$('.tracks-tree').treegrid({'treeColumn':1});});
+
+/* redirectPost */
+$.extend(
+{
+ redirectPost: function(location, args)
+ {
+ var form = '';
+ $.each(args, function(key, value) {
+ form += '<input type="hidden" name="' + key + '" value="' + value + '">';
+ });
+ $('<form action="' + location + '" method="POST">' + form + '</form>').appendTo('body').submit();
+ }
+});
diff --git a/library/cpp/lwtrace/mon/static/css/bootstrap.min.css b/library/cpp/lwtrace/mon/static/css/bootstrap.min.css
new file mode 100644
index 0000000000..f602cacbf8
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/css/bootstrap.min.css
@@ -0,0 +1,9 @@
+/*!
+ * Bootstrap v3.0.2 by @fat and @mdo
+ * Copyright 2013 Twitter, Inc.
+ * Licensed under http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world by @mdo and @fat.
+ */
+
+/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a{background:transparent}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-primary:hover{color:#3071a9}.text-warning{color:#c09853}.text-warning:hover{color:#a47e3c}.text-danger{color:#b94a48}.text-danger:hover{color:#953b39}.text-success{color:#468847}.text-success:hover{color:#356635}.text-info{color:#3a87ad}.text-info:hover{color:#2d6987}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h1 small,h2 small,h3 small,h1 .small,h2 .small,h3 .small{font-size:65%}h4,h5,h6{margin-top:10px;margin-bottom:10px}h4 small,h5 small,h6 small,h4 .small,h5 .small,h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}.list-inline>li:first-child{padding-left:0}dl{margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small{display:block;line-height:1.428571429;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small,blockquote.pull-right .small{text-align:right}blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}.col-xs-offset-0{margin-left:0}@media(min-width:768px){.container{width:750px}.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-0{margin-left:0}}@media(min-width:992px){.container{width:970px}.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-0{margin-left:0}}@media(min-width:1200px){.container{width:1170px}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}@media(max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}output{display:block;padding-top:7px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:45px;line-height:45px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#c09853}.has-warning .form-control{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.has-warning .input-group-addon{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#b94a48}.has-error .form-control{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.has-error .input-group-addon{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#468847}.has-success .form-control{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.has-success .input-group-addon{color:#468847;background-color:#dff0d8;border-color:#468847}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-control-static{padding-top:7px}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-link{font-weight:normal;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1;-moz-osx-font-smoothing:grayscale}.glyphicon:empty{width:1em}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid #000;border-right:4px solid transparent;border-bottom:0 dotted;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0 dotted;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-default .caret{border-top-color:#333}.btn-primary .caret,.btn-success .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret{border-top-color:#fff}.dropup .btn-default .caret{border-bottom-color:#333}.dropup .btn-primary .caret,.dropup .btn-success .caret,.dropup .btn-warning .caret,.dropup .btn-danger .caret,.dropup .btn-info .caret{border-bottom-color:#fff}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:5px 10px;padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified .btn{display:table-cell;float:none;width:1%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group.col{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:45px;line-height:45px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn:first-child>.btn{margin-right:-1px}.input-group-btn:last-child>.btn{margin-left:-1px}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .open>a .caret,.nav .open>a:hover .caret,.nav .open>a:focus .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-pills>li.active>a .caret,.nav-pills>li.active>a:hover .caret,.nav-pills>li.active>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav .caret{border-top-color:#428bca;border-bottom-color:#428bca}.nav a:hover .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:auto}.navbar-collapse .navbar-nav.navbar-left:first-child{margin-left:-15px}.navbar-collapse .navbar-nav.navbar-right:last-child{margin-right:-15px}.navbar-collapse .navbar-text:last-child{margin-right:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-text{float:left;margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{margin-right:15px;margin-left:15px}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.dropdown>a:hover .caret,.navbar-default .navbar-nav>.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.open>a .caret,.navbar-default .navbar-nav>.open>a:hover .caret,.navbar-default .navbar-nav>.open>a:focus .caret{border-top-color:#555;border-bottom-color:#555}.navbar-default .navbar-nav>.dropdown>a .caret{border-top-color:#777;border-bottom-color:#777}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-nav>.dropdown>a .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .navbar-nav>.open>a .caret,.navbar-inverse .navbar-nav>.open>a:hover .caret,.navbar-inverse .navbar-nav>.open>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.btn .badge{position:relative;top:-1px}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1{font-size:63px}}.thumbnail{display:inline-block;display:block;height:auto;max-width:100%;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img{display:block;height:auto;max-width:100%;margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#356635}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#2d6987}.alert-warning{color:#c09853;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#a47e3c}.alert-danger{color:#b94a48;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#953b39}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive{margin-bottom:0}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:last-child>th,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:last-child>td,.panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-heading>.dropdown .caret{border-color:#333 transparent}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-heading>.dropdown .caret{border-color:#fff transparent}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading>.dropdown .caret{border-color:#468847 transparent}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#c09853;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading>.dropdown .caret{border-color:#c09853 transparent}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#b94a48;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading>.dropdown .caret{border-color:#b94a48 transparent}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading>.dropdown .caret{border-color:#3a87ad transparent}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;z-index:1050;width:auto;padding:10px;margin-right:auto;margin-left:auto}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{width:600px;padding-top:30px;padding-bottom:30px}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.5)),to(rgba(0,0,0,0.0001)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.0001)),to(rgba(0,0,0,0.5)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm,tr.hidden-xs.hidden-sm,th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md,tr.hidden-xs.hidden-md,th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg,tr.hidden-xs.hidden-lg,th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs,tr.hidden-sm.hidden-xs,th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md,tr.hidden-sm.hidden-md,th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg,tr.hidden-sm.hidden-lg,th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs,tr.hidden-md.hidden-xs,th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm,tr.hidden-md.hidden-sm,th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg,tr.hidden-md.hidden-lg,th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs,tr.hidden-lg.hidden-xs,th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm,tr.hidden-lg.hidden-sm,th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md,tr.hidden-lg.hidden-md,th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none!important}}
diff --git a/library/cpp/lwtrace/mon/static/css/d3-gantt.css b/library/cpp/lwtrace/mon/static/css/d3-gantt.css
new file mode 100644
index 0000000000..25ba8fae6e
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/css/d3-gantt.css
@@ -0,0 +1,68 @@
+.chart {
+ font-family: Arial, sans-serif;
+ font-size: 12px;
+}
+
+rect.zoom-panel {
+ /*cursor: ew-resize;*/
+ fill: none;
+ pointer-events: all;
+}
+
+.axis path,.axis line {
+ fill: none;
+ stroke: #000;
+ shape-rendering: crispEdges;
+}
+
+.axis.y {
+ font-size: 16px;
+ cursor: ns-resize;
+}
+
+.axis.x {
+ font-size: 16px;
+}
+
+#ruler {
+ text-anchor: middle;
+ alignment-baseline: before-edge;
+ font-size: 16px;
+ font-family: sans-serif;
+ pointer-events: none;
+}
+
+.d3-tip {
+ line-height: 1;
+ font-weight: bold;
+ padding: 12px;
+ background: rgba(0, 0, 0, 0.8);
+ color: #fff;
+ border-radius: 2px;
+}
+
+.d3-tip pre {
+ font-weight: bold;
+ padding: 12px;
+ background: rgba(0, 0, 0, 0);
+ color: #fff;
+ border: 0px;
+}
+
+/* Style northward tooltips differently */
+.d3-tip.n:after {
+ margin: -1px 0 0 0;
+ top: 100%;
+ left: 0;
+}
+
+/* for arrowhead marker */
+#arrow {
+ stroke-width:1;
+ stroke-dasharray:0;
+}
+
+.bar:hover {
+ stroke-width: 1px;
+ stroke: black;
+} \ No newline at end of file
diff --git a/library/cpp/lwtrace/mon/static/css/jquery.treegrid.css b/library/cpp/lwtrace/mon/static/css/jquery.treegrid.css
new file mode 100644
index 0000000000..3980272607
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/css/jquery.treegrid.css
@@ -0,0 +1,8 @@
+.treegrid-indent {width:16px; height: 16px; display: inline-block; position: relative;}
+.treegrid-expander {width:16px; height: 16px; display: inline-block; position: relative; cursor: pointer;}
+.treegrid-expander-expanded{background-image: url(../img/collapse.png); }
+.treegrid-expander-collapsed{background-image: url(../img/expand.png);}
+
+.treegrid-element {white-space: unset;}
+
+.timelinehead {width:30vw;}
diff --git a/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.eot b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 0000000000..b93a4953ff
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.eot
Binary files differ
diff --git a/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 0000000000..94fb5490a2
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,288 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
+<font-face units-per-em="1200" ascent="960" descent="-240" />
+<missing-glyph horiz-adv-x="500" />
+<glyph horiz-adv-x="0" />
+<glyph horiz-adv-x="400" />
+<glyph unicode=" " />
+<glyph unicode="*" d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 158h-224q-10 0 -18.5 7.5 t-10.5 17.5q-6 41 -6 75q0 15 1.5 34t3.5 30l1 11q2 10 10.5 17.5t18.5 7.5h224l-158 158q-7 7 -8 18t6 19l106 106q8 7 19 6t18 -8l158 -158v224q0 10 7.5 18.5t17.5 10.5q41 6 75 6z" />
+<glyph unicode="+" d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xa0;" />
+<glyph unicode="&#xa5;" d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z" />
+<glyph unicode="&#x2000;" horiz-adv-x="650" />
+<glyph unicode="&#x2001;" horiz-adv-x="1300" />
+<glyph unicode="&#x2002;" horiz-adv-x="650" />
+<glyph unicode="&#x2003;" horiz-adv-x="1300" />
+<glyph unicode="&#x2004;" horiz-adv-x="433" />
+<glyph unicode="&#x2005;" horiz-adv-x="325" />
+<glyph unicode="&#x2006;" horiz-adv-x="216" />
+<glyph unicode="&#x2007;" horiz-adv-x="216" />
+<glyph unicode="&#x2008;" horiz-adv-x="162" />
+<glyph unicode="&#x2009;" horiz-adv-x="260" />
+<glyph unicode="&#x200a;" horiz-adv-x="72" />
+<glyph unicode="&#x202f;" horiz-adv-x="260" />
+<glyph unicode="&#x205f;" horiz-adv-x="325" />
+<glyph unicode="&#x20ac;" d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 141 297 141z" />
+<glyph unicode="&#x20bd;" d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 119q0 84 -22.5 116t-86.5 32h-203z" />
+<glyph unicode="&#x2212;" d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#x231b;" d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-28 12 -44 37t-16 55t16 55t44 37 q55 24 87.5 73.5t32.5 109.5v100h-400z" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#x2601;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z" />
+<glyph unicode="&#x26fa;" d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z " />
+<glyph unicode="&#x2709;" d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z" />
+<glyph unicode="&#x270f;" d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z" />
+<glyph unicode="&#xe001;" d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z" />
+<glyph unicode="&#xe002;" d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z" />
+<glyph unicode="&#xe003;" d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z" />
+<glyph unicode="&#xe005;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z" />
+<glyph unicode="&#xe006;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z" />
+<glyph unicode="&#xe007;" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z" />
+<glyph unicode="&#xe008;" d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z" />
+<glyph unicode="&#xe009;" d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5 t17.5 -7.5h550q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM100 400v-100h100v100h-100zM1000 400v-100h100v100h-100zM100 200v-100h100v100h-100zM1000 200v-100h100v100h-100z" />
+<glyph unicode="&#xe010;" d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe011;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 700h200q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5 t35.5 14.5z" />
+<glyph unicode="&#xe012;" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h700q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe013;" d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z" />
+<glyph unicode="&#xe014;" d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z" />
+<glyph unicode="&#xe015;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5 t-17.5 -7.5h-75v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-75q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v75q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe016;" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-350q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe017;" d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z" />
+<glyph unicode="&#xe018;" d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5 v250q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe019;" d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 94 39l5 1l38 152q43 5 74 5zM600 815 q-89 0 -152 -63t-63 -151.5t63 -151.5t152 -63t152 63t63 151.5t-63 151.5t-152 63z" />
+<glyph unicode="&#xe020;" d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z" />
+<glyph unicode="&#xe021;" d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z" />
+<glyph unicode="&#xe022;" d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z" />
+<glyph unicode="&#xe023;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe024;" d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z" />
+<glyph unicode="&#xe025;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe026;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z " />
+<glyph unicode="&#xe027;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5l223 275q13 16 32 16 t32 -16z" />
+<glyph unicode="&#xe028;" d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z" />
+<glyph unicode="&#xe029;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
+<glyph unicode="&#xe030;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z" />
+<glyph unicode="&#xe031;" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 214.5z" />
+<glyph unicode="&#xe032;" d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 700h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 700h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 500h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 500h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 300h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 300h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe033;" d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z" />
+<glyph unicode="&#xe034;" d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z" />
+<glyph unicode="&#xe035;" d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460 q0 8 6 14t14 6z" />
+<glyph unicode="&#xe036;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z" />
+<glyph unicode="&#xe037;" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z" />
+<glyph unicode="&#xe038;" d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238 q-6 8 -4.5 18.5t9.5 16.5l29 22q7 5 15 5z" />
+<glyph unicode="&#xe039;" d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0h-300v100h300v-100z" />
+<glyph unicode="&#xe040;" d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z" />
+<glyph unicode="&#xe041;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
+<glyph unicode="&#xe042;" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
+<glyph unicode="&#xe043;" d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z" />
+<glyph unicode="&#xe044;" d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe045;" d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5 t7.5 17.5v650q0 10 -7.5 17.5t-17.5 7.5zM850 200h-500q-10 0 -19.5 -7t-11.5 -17l-38 -152q-2 -10 3.5 -17t15.5 -7h600q10 0 15.5 7t3.5 17l-38 152q-2 10 -11.5 17t-19.5 7z" />
+<glyph unicode="&#xe046;" d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z" />
+<glyph unicode="&#xe047;" d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z" />
+<glyph unicode="&#xe048;" d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 0 121 50.5t41 130.5q0 90 -62.5 154.5 t-156.5 64.5h-159v-400z" />
+<glyph unicode="&#xe049;" d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z" />
+<glyph unicode="&#xe050;" d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z" />
+<glyph unicode="&#xe051;" d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z" />
+<glyph unicode="&#xe052;" d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe053;" d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe054;" d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe055;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe056;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 500h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 500h800q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 200h800 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe057;" d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe058;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe059;" d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z" />
+<glyph unicode="&#xe060;" d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z" />
+<glyph unicode="&#xe062;" d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z" />
+<glyph unicode="&#xe063;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z" />
+<glyph unicode="&#xe064;" d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 11q-8 1 -15 -10z" />
+<glyph unicode="&#xe065;" d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z" />
+<glyph unicode="&#xe066;" d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 -4.5z" />
+<glyph unicode="&#xe067;" d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z" />
+<glyph unicode="&#xe068;" d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z" />
+<glyph unicode="&#xe069;" d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe070;" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe071;" d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z" />
+<glyph unicode="&#xe072;" d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z" />
+<glyph unicode="&#xe073;" d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe074;" d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z" />
+<glyph unicode="&#xe075;" d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z" />
+<glyph unicode="&#xe076;" d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe077;" d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe078;" d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe079;" d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z" />
+<glyph unicode="&#xe080;" d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z" />
+<glyph unicode="&#xe081;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5 14.5z" />
+<glyph unicode="&#xe082;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z" />
+<glyph unicode="&#xe083;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141 141q-9 9 -21.5 9z" />
+<glyph unicode="&#xe084;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z" />
+<glyph unicode="&#xe085;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t37.5 48t29.5 74t12 100q0 47 -17 83 t-42.5 57t-59.5 34.5t-64 18t-59 4.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe086;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5 t-17.5 7.5h-75v275q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe087;" d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v168q-68 -23 -119 -74 t-74 -119h168q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-168q23 -68 74 -119t119 -74v168q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-168q68 23 119 74t74 119h-168q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h168 q-23 68 -74 119t-119 74z" />
+<glyph unicode="&#xe088;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q-7 -7 -17.5 -7t-17.5 7l-64 64 q-7 7 -7 17.5t7 17.5l124 124l-124 124q-7 7 -7 17.5t7 17.5l64 64q7 7 17.5 7t17.5 -7l124 -124l124 124q7 7 17.5 7t17.5 -7z" />
+<glyph unicode="&#xe089;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l197 197q7 7 17.5 7t17.5 -7z" />
+<glyph unicode="&#xe090;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z" />
+<glyph unicode="&#xe091;" d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z" />
+<glyph unicode="&#xe092;" d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z" />
+<glyph unicode="&#xe093;" d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z" />
+<glyph unicode="&#xe094;" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe095;" d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z" />
+<glyph unicode="&#xe096;" d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z" />
+<glyph unicode="&#xe097;" d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z" />
+<glyph unicode="&#xe101;" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe102;" d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 7t13.5 15t21.5 19.5t26.5 15.5 t29.5 7zM915 1079l-166 -162q-7 -7 -5 -12t12 -5h219q10 0 15 7t2 17l-51 149q-3 10 -11 12t-15 -6zM463 917l-177 157q-8 7 -16 5t-11 -12l-51 -143q-3 -10 2 -17t15 -7h231q11 0 12.5 5t-5.5 12zM500 0h-375q-10 0 -17.5 7.5t-7.5 17.5v375h400v-400zM1100 400v-375 q0 -10 -7.5 -17.5t-17.5 -7.5h-375v400h400z" />
+<glyph unicode="&#xe103;" d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 -102 -57t-104 -68t-102.5 -80.5t-85.5 -91 t-64 -104.5q-24 -56 -31 -86t2 -32t31.5 17.5t55.5 59.5q25 30 94 75.5t125.5 77.5t147.5 81q70 37 118.5 69t102 79.5t99 111t86.5 148.5q22 50 24 60t-6 19z" />
+<glyph unicode="&#xe104;" d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80 36 -131.5 114t-53.5 171q-2 23 0 49.5 t4.5 52.5t13.5 56t27.5 60t46 64.5t69.5 68.5q-8 -53 -5 -102.5t17.5 -90t34 -68.5t44.5 -39t49 -2q31 13 38.5 36t-4.5 55t-29 64.5t-36 75t-26 75.5q-15 85 2 161.5t53.5 128.5t85.5 92.5t93.5 61t81.5 25.5z" />
+<glyph unicode="&#xe105;" d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -71t70 -82t92.5 -81t113 -58.5t133.5 -24.5 t133.5 24t113 58.5t92.5 81.5t70 81.5t47 70.5q11 18 9 42.5t-14 41.5q-90 117 -163 189zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l35 34q14 15 12.5 33.5t-16.5 33.5q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
+<glyph unicode="&#xe106;" d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 101.5t-71.5 193.5q0 59 23 114q8 19 4.5 22 t-17.5 -12zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l12 11l22 86l-3 4q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
+<glyph unicode="&#xe107;" d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z" />
+<glyph unicode="&#xe108;" d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z" />
+<glyph unicode="&#xe109;" d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400 v-100h100v100h-100zM700 400v-100h100v100h-100zM900 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100zM500 200v-100h100v100h-100zM700 200v-100h100v100h-100zM900 200v-100h100v100h-100z" />
+<glyph unicode="&#xe110;" d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z" />
+<glyph unicode="&#xe111;" d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z" />
+<glyph unicode="&#xe112;" d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z" />
+<glyph unicode="&#xe113;" d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z" />
+<glyph unicode="&#xe114;" d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z" />
+<glyph unicode="&#xe115;" d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe116;" d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z" />
+<glyph unicode="&#xe117;" d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z" />
+<glyph unicode="&#xe118;" d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z" />
+<glyph unicode="&#xe119;" d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe120;" d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z" />
+<glyph unicode="&#xe121;" d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z" />
+<glyph unicode="&#xe122;" d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z" />
+<glyph unicode="&#xe123;" d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z" />
+<glyph unicode="&#xe124;" d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z" />
+<glyph unicode="&#xe125;" d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe126;" d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375h-214z" />
+<glyph unicode="&#xe127;" d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500 q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe128;" d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5 v500q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe129;" d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe130;" d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-456q0 -22 25 -31t50 0.5t25 30.5 v203q0 15 20 28.5t41 19.5l339 131v293l-89 100h-503z" />
+<glyph unicode="&#xe131;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z" />
+<glyph unicode="&#xe132;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z" />
+<glyph unicode="&#xe133;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z" />
+<glyph unicode="&#xe134;" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe135;" d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5 -32t60 -38t57.5 -11 q7 -15 -3 -34t-22.5 -40t-9.5 -38q13 -21 23 -34.5t27.5 -27.5t36.5 -18q0 -7 -3.5 -16t-3.5 -14t5 -17q104 -2 221 112q30 29 46.5 47t34.5 49t21 63q-13 8 -37 8.5t-36 7.5q-15 7 -49.5 15t-51.5 19q-18 0 -41 -0.5t-43 -1.5t-42 -6.5t-38 -16.5q-51 -35 -66 -12 q-4 1 -3.5 25.5t0.5 25.5q-6 13 -26.5 17.5t-24.5 6.5q1 15 -0.5 30.5t-7 28t-18.5 11.5t-31 -21q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q7 -12 18 -24t21.5 -20.5t20 -15t15.5 -10.5l5 -3q2 12 7.5 30.5t8 34.5t-0.5 32q-3 18 3.5 29 t18 22.5t15.5 24.5q6 14 10.5 35t8 31t15.5 22.5t34 22.5q-6 18 10 36q8 0 24 -1.5t24.5 -1.5t20 4.5t20.5 15.5q-10 23 -31 42.5t-37.5 29.5t-49 27t-43.5 23q0 1 2 8t3 11.5t1.5 10.5t-1 9.5t-4.5 4.5q31 -13 58.5 -14.5t38.5 2.5l12 5q5 28 -9.5 46t-36.5 24t-50 15 t-41 20q-18 -4 -37 0zM613 994q0 -17 8 -42t17 -45t9 -23q-8 1 -39.5 5.5t-52.5 10t-37 16.5q3 11 16 29.5t16 25.5q10 -10 19 -10t14 6t13.5 14.5t16.5 12.5z" />
+<glyph unicode="&#xe136;" d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z" />
+<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z " />
+<glyph unicode="&#xe138;" d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z" />
+<glyph unicode="&#xe139;" d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z" />
+<glyph unicode="&#xe140;" d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l199 199 q8 7 18 7t18 -7zM1071 271l94 94q14 14 24.5 10t10.5 -25v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -25 10.5t10 24.5l94 94l-199 199q-7 8 -7 18t7 18l106 106q8 7 18 7t18 -7z" />
+<glyph unicode="&#xe141;" d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38 -16.5q-14 0 -29 10l-55 -145 q17 -23 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 23 16 39t38.5 16zM345.5 709q22.5 0 38.5 -16t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16zM854.5 709q22.5 0 38.5 -16 t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16z" />
+<glyph unicode="&#xe142;" d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2 -96.5t-47 -84.5q-12 -11 -32 -32 t-79.5 -81t-114.5 -115t-124.5 -123.5t-123 -119.5t-96.5 -89t-57 -45q-56 -27 -120 -27q-70 0 -129 32t-93 89q-48 78 -35 173t81 163l511 511q71 72 111 96q91 55 198 55q80 0 152 -33q78 -36 129.5 -103t66.5 -154q17 -93 -11 -183.5t-94 -156.5l-482 -476 q-15 -15 -36 -16t-37 14t-17.5 34t14.5 35z" />
+<glyph unicode="&#xe143;" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 -44t50.5 -51t46 -44t41 -35t23 -12 t23.5 12t42.5 36t46 44t52.5 52t44 43q4 4 12 13q43 41 63.5 62t52 55t46 55t26 46t11.5 44q0 79 -53 133.5t-120 54.5z" />
+<glyph unicode="&#xe144;" d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z" />
+<glyph unicode="&#xe145;" d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z" />
+<glyph unicode="&#xe146;" d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z" />
+<glyph unicode="&#xe148;" d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5t16.5 -34t28.5 -22.5t31.5 -14t37.5 -10 q9 -3 13 -4zM700 547v-310q22 2 42.5 6.5t45 15.5t41.5 27t29 42t12 59.5t-12.5 59.5t-38 44.5t-53 31t-66.5 24.5z" />
+<glyph unicode="&#xe149;" d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221v100h166q-23 47 -44 104q-7 20 -12 41.5t-6 55.5t6 66.5t29.5 70.5t58.5 71q97 88 263 88z" />
+<glyph unicode="&#xe150;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe151;" d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z " />
+<glyph unicode="&#xe152;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z " />
+<glyph unicode="&#xe153;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z" />
+<glyph unicode="&#xe154;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z" />
+<glyph unicode="&#xe155;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z" />
+<glyph unicode="&#xe156;" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z" />
+<glyph unicode="&#xe157;" d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z" />
+<glyph unicode="&#xe158;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
+<glyph unicode="&#xe159;" d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z" />
+<glyph unicode="&#xe160;" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z" />
+<glyph unicode="&#xe161;" d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
+<glyph unicode="&#xe162;" d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z" />
+<glyph unicode="&#xe163;" d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
+<glyph unicode="&#xe164;" d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z" />
+<glyph unicode="&#xe165;" d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z" />
+<glyph unicode="&#xe166;" d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe167;" d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe168;" d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z" />
+<glyph unicode="&#xe169;" d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe170;" d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
+<glyph unicode="&#xe171;" d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z" />
+<glyph unicode="&#xe172;" d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z" />
+<glyph unicode="&#xe173;" d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z" />
+<glyph unicode="&#xe174;" d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15l131 -131l131 131q15 15 35.5 15 t35.5 -15z" />
+<glyph unicode="&#xe175;" d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe176;" d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z" />
+<glyph unicode="&#xe177;" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z" />
+<glyph unicode="&#xe178;" d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z" />
+<glyph unicode="&#xe179;" d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14.5 -24.5l3 -13v-350h100v350v5.5t2.5 12 t7 15t15 12t25.5 5.5q23 0 35.5 -12.5t13.5 -24.5l1 -13v-350h100v350q0 2 0.5 5.5t3 12t7 15t15 12t24.5 5.5z" />
+<glyph unicode="&#xe180;" d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z" />
+<glyph unicode="&#xe181;" d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z" />
+<glyph unicode="&#xe182;" d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z" />
+<glyph unicode="&#xe183;" d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45t24.5 40l365 303v50 q0 4 1 10.5t12 23t30 29t60 22.5t97 10z" />
+<glyph unicode="&#xe184;" d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe185;" d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z " />
+<glyph unicode="&#xe186;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
+<glyph unicode="&#xe187;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
+<glyph unicode="&#xe188;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-300h200v-100h-300v500h300v-100zM900 700h-200v-300h200v-100h-300v500h300v-100z" />
+<glyph unicode="&#xe189;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 400l-300 150l300 150v-300zM900 550l-300 -150v300z" />
+<glyph unicode="&#xe190;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM900 300h-700v500h700v-500zM800 700h-130q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300zM300 700v-300 h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130z" />
+<glyph unicode="&#xe191;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 300h-100v400h-100v100h200v-500z M700 300h-100v100h100v-100z" />
+<glyph unicode="&#xe192;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM300 700h200v-400h-300v500h100v-100zM900 300h-100v400h-100v100h200v-500zM300 600v-200h100v200h-100z M700 300h-100v100h100v-100z" />
+<glyph unicode="&#xe193;" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 500l-199 -200h-100v50l199 200v150h-200v100h300v-300zM900 300h-100v400h-100v100h200v-500zM701 300h-100 v100h100v-100z" />
+<glyph unicode="&#xe194;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700h-300v-200h300v-100h-300l-100 100v200l100 100h300v-100z" />
+<glyph unicode="&#xe195;" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700v-100l-50 -50l100 -100v-50h-100l-100 100h-150v-100h-100v400h300zM500 700v-100h200v100h-200z" />
+<glyph unicode="&#xe197;" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -207t-85 -207t-205 -86.5h-128v250q0 21 -14.5 35.5t-35.5 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-250h-222q-80 0 -136 57.5t-56 136.5q0 69 43 122.5t108 67.5q-2 19 -2 37q0 100 49 185 t134 134t185 49zM525 500h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -244q-13 -16 -32 -16t-32 16l-223 244q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe198;" d="M502 1089q110 0 201 -59.5t135 -156.5q43 15 89 15q121 0 206 -86.5t86 -206.5q0 -99 -60 -181t-150 -110l-378 360q-13 16 -31.5 16t-31.5 -16l-381 -365h-9q-79 0 -135.5 57.5t-56.5 136.5q0 69 43 122.5t108 67.5q-2 19 -2 38q0 100 49 184.5t133.5 134t184.5 49.5z M632 467l223 -228q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5q199 204 223 228q19 19 31.5 19t32.5 -19z" />
+<glyph unicode="&#xe199;" d="M700 100v100h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-100h-50q-21 0 -35.5 -14.5t-14.5 -35.5v-50h400v50q0 21 -14.5 35.5t-35.5 14.5h-50z" />
+<glyph unicode="&#xe200;" d="M600 1179q94 0 167.5 -56.5t99.5 -145.5q89 -6 150.5 -71.5t61.5 -155.5q0 -61 -29.5 -112.5t-79.5 -82.5q9 -29 9 -55q0 -74 -52.5 -126.5t-126.5 -52.5q-55 0 -100 30v-251q21 0 35.5 -14.5t14.5 -35.5v-50h-300v50q0 21 14.5 35.5t35.5 14.5v251q-45 -30 -100 -30 q-74 0 -126.5 52.5t-52.5 126.5q0 18 4 38q-47 21 -75.5 65t-28.5 97q0 74 52.5 126.5t126.5 52.5q5 0 23 -2q0 2 -1 10t-1 13q0 116 81.5 197.5t197.5 81.5z" />
+<glyph unicode="&#xe201;" d="M1010 1010q111 -111 150.5 -260.5t0 -299t-150.5 -260.5q-83 -83 -191.5 -126.5t-218.5 -43.5t-218.5 43.5t-191.5 126.5q-111 111 -150.5 260.5t0 299t150.5 260.5q83 83 191.5 126.5t218.5 43.5t218.5 -43.5t191.5 -126.5zM476 1065q-4 0 -8 -1q-121 -34 -209.5 -122.5 t-122.5 -209.5q-4 -12 2.5 -23t18.5 -14l36 -9q3 -1 7 -1q23 0 29 22q27 96 98 166q70 71 166 98q11 3 17.5 13.5t3.5 22.5l-9 35q-3 13 -14 19q-7 4 -15 4zM512 920q-4 0 -9 -2q-80 -24 -138.5 -82.5t-82.5 -138.5q-4 -13 2 -24t19 -14l34 -9q4 -1 8 -1q22 0 28 21 q18 58 58.5 98.5t97.5 58.5q12 3 18 13.5t3 21.5l-9 35q-3 12 -14 19q-7 4 -15 4zM719.5 719.5q-49.5 49.5 -119.5 49.5t-119.5 -49.5t-49.5 -119.5t49.5 -119.5t119.5 -49.5t119.5 49.5t49.5 119.5t-49.5 119.5zM855 551q-22 0 -28 -21q-18 -58 -58.5 -98.5t-98.5 -57.5 q-11 -4 -17 -14.5t-3 -21.5l9 -35q3 -12 14 -19q7 -4 15 -4q4 0 9 2q80 24 138.5 82.5t82.5 138.5q4 13 -2.5 24t-18.5 14l-34 9q-4 1 -8 1zM1000 515q-23 0 -29 -22q-27 -96 -98 -166q-70 -71 -166 -98q-11 -3 -17.5 -13.5t-3.5 -22.5l9 -35q3 -13 14 -19q7 -4 15 -4 q4 0 8 1q121 34 209.5 122.5t122.5 209.5q4 12 -2.5 23t-18.5 14l-36 9q-3 1 -7 1z" />
+<glyph unicode="&#xe202;" d="M700 800h300v-380h-180v200h-340v-200h-380v755q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM700 300h162l-212 -212l-212 212h162v200h100v-200zM520 0h-395q-10 0 -17.5 7.5t-7.5 17.5v395zM1000 220v-195q0 -10 -7.5 -17.5t-17.5 -7.5h-195z" />
+<glyph unicode="&#xe203;" d="M700 800h300v-520l-350 350l-550 -550v1095q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM862 200h-162v-200h-100v200h-162l212 212zM480 0h-355q-10 0 -17.5 7.5t-7.5 17.5v55h380v-80zM1000 80v-55q0 -10 -7.5 -17.5t-17.5 -7.5h-155v80h180z" />
+<glyph unicode="&#xe204;" d="M1162 800h-162v-200h100l100 -100h-300v300h-162l212 212zM200 800h200q27 0 40 -2t29.5 -10.5t23.5 -30t7 -57.5h300v-100h-600l-200 -350v450h100q0 36 7 57.5t23.5 30t29.5 10.5t40 2zM800 400h240l-240 -400h-800l300 500h500v-100z" />
+<glyph unicode="&#xe205;" d="M650 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM1000 850v150q41 0 70.5 -29.5t29.5 -70.5v-800 q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-1 0 -20 4l246 246l-326 326v324q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM412 250l-212 -212v162h-200v100h200v162z" />
+<glyph unicode="&#xe206;" d="M450 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM800 850v150q41 0 70.5 -29.5t29.5 -70.5v-500 h-200v-300h200q0 -36 -7 -57.5t-23.5 -30t-29.5 -10.5t-40 -2h-600q-41 0 -70.5 29.5t-29.5 70.5v800q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM1212 250l-212 -212v162h-200v100h200v162z" />
+<glyph unicode="&#xe209;" d="M658 1197l637 -1104q23 -38 7 -65.5t-60 -27.5h-1276q-44 0 -60 27.5t7 65.5l637 1104q22 39 54 39t54 -39zM704 800h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM500 300v-100h200 v100h-200z" />
+<glyph unicode="&#xe210;" d="M425 1100h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM825 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM25 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5zM425 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5 v150q0 10 7.5 17.5t17.5 7.5zM25 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe211;" d="M700 1200h100v-200h-100v-100h350q62 0 86.5 -39.5t-3.5 -94.5l-66 -132q-41 -83 -81 -134h-772q-40 51 -81 134l-66 132q-28 55 -3.5 94.5t86.5 39.5h350v100h-100v200h100v100h200v-100zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100 h-950l138 100h-13q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe212;" d="M600 1300q40 0 68.5 -29.5t28.5 -70.5h-194q0 41 28.5 70.5t68.5 29.5zM443 1100h314q18 -37 18 -75q0 -8 -3 -25h328q41 0 44.5 -16.5t-30.5 -38.5l-175 -145h-678l-178 145q-34 22 -29 38.5t46 16.5h328q-3 17 -3 25q0 38 18 75zM250 700h700q21 0 35.5 -14.5 t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-150v-200l275 -200h-950l275 200v200h-150q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe213;" d="M600 1181q75 0 128 -53t53 -128t-53 -128t-128 -53t-128 53t-53 128t53 128t128 53zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13 l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe214;" d="M600 1300q47 0 92.5 -53.5t71 -123t25.5 -123.5q0 -78 -55.5 -133.5t-133.5 -55.5t-133.5 55.5t-55.5 133.5q0 62 34 143l144 -143l111 111l-163 163q34 26 63 26zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45 zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe215;" d="M600 1200l300 -161v-139h-300q0 -57 18.5 -108t50 -91.5t63 -72t70 -67.5t57.5 -61h-530q-60 83 -90.5 177.5t-30.5 178.5t33 164.5t87.5 139.5t126 96.5t145.5 41.5v-98zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100 h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe216;" d="M600 1300q41 0 70.5 -29.5t29.5 -70.5v-78q46 -26 73 -72t27 -100v-50h-400v50q0 54 27 100t73 72v78q0 41 29.5 70.5t70.5 29.5zM400 800h400q54 0 100 -27t72 -73h-172v-100h200v-100h-200v-100h200v-100h-200v-100h200q0 -83 -58.5 -141.5t-141.5 -58.5h-400 q-83 0 -141.5 58.5t-58.5 141.5v400q0 83 58.5 141.5t141.5 58.5z" />
+<glyph unicode="&#xe218;" d="M150 1100h900q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM125 400h950q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-283l224 -224q13 -13 13 -31.5t-13 -32 t-31.5 -13.5t-31.5 13l-88 88h-524l-87 -88q-13 -13 -32 -13t-32 13.5t-13 32t13 31.5l224 224h-289q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM541 300l-100 -100h324l-100 100h-124z" />
+<glyph unicode="&#xe219;" d="M200 1100h800q83 0 141.5 -58.5t58.5 -141.5v-200h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100v200q0 83 58.5 141.5t141.5 58.5zM100 600h1000q41 0 70.5 -29.5 t29.5 -70.5v-300h-1200v300q0 41 29.5 70.5t70.5 29.5zM300 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200zM1100 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200z" />
+<glyph unicode="&#xe221;" d="M480 1165l682 -683q31 -31 31 -75.5t-31 -75.5l-131 -131h-481l-517 518q-32 31 -32 75.5t32 75.5l295 296q31 31 75.5 31t76.5 -31zM108 794l342 -342l303 304l-341 341zM250 100h800q21 0 35.5 -14.5t14.5 -35.5v-50h-900v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe223;" d="M1057 647l-189 506q-8 19 -27.5 33t-40.5 14h-400q-21 0 -40.5 -14t-27.5 -33l-189 -506q-8 -19 1.5 -33t30.5 -14h625v-150q0 -21 14.5 -35.5t35.5 -14.5t35.5 14.5t14.5 35.5v150h125q21 0 30.5 14t1.5 33zM897 0h-595v50q0 21 14.5 35.5t35.5 14.5h50v50 q0 21 14.5 35.5t35.5 14.5h48v300h200v-300h47q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-50z" />
+<glyph unicode="&#xe224;" d="M900 800h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-375v591l-300 300v84q0 10 7.5 17.5t17.5 7.5h375v-400zM1200 900h-200v200zM400 600h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-650q-10 0 -17.5 7.5t-7.5 17.5v950q0 10 7.5 17.5t17.5 7.5h375v-400zM700 700h-200v200z " />
+<glyph unicode="&#xe225;" d="M484 1095h195q75 0 146 -32.5t124 -86t89.5 -122.5t48.5 -142q18 -14 35 -20q31 -10 64.5 6.5t43.5 48.5q10 34 -15 71q-19 27 -9 43q5 8 12.5 11t19 -1t23.5 -16q41 -44 39 -105q-3 -63 -46 -106.5t-104 -43.5h-62q-7 -55 -35 -117t-56 -100l-39 -234q-3 -20 -20 -34.5 t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l12 70q-49 -14 -91 -14h-195q-24 0 -65 8l-11 -64q-3 -20 -20 -34.5t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l26 157q-84 74 -128 175l-159 53q-19 7 -33 26t-14 40v50q0 21 14.5 35.5t35.5 14.5h124q11 87 56 166l-111 95 q-16 14 -12.5 23.5t24.5 9.5h203q116 101 250 101zM675 1000h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h250q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="&#xe226;" d="M641 900l423 247q19 8 42 2.5t37 -21.5l32 -38q14 -15 12.5 -36t-17.5 -34l-139 -120h-390zM50 1100h106q67 0 103 -17t66 -71l102 -212h823q21 0 35.5 -14.5t14.5 -35.5v-50q0 -21 -14 -40t-33 -26l-737 -132q-23 -4 -40 6t-26 25q-42 67 -100 67h-300q-62 0 -106 44 t-44 106v200q0 62 44 106t106 44zM173 928h-80q-19 0 -28 -14t-9 -35v-56q0 -51 42 -51h134q16 0 21.5 8t5.5 24q0 11 -16 45t-27 51q-18 28 -43 28zM550 727q-32 0 -54.5 -22.5t-22.5 -54.5t22.5 -54.5t54.5 -22.5t54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5zM130 389 l152 130q18 19 34 24t31 -3.5t24.5 -17.5t25.5 -28q28 -35 50.5 -51t48.5 -13l63 5l48 -179q13 -61 -3.5 -97.5t-67.5 -79.5l-80 -69q-47 -40 -109 -35.5t-103 51.5l-130 151q-40 47 -35.5 109.5t51.5 102.5zM380 377l-102 -88q-31 -27 2 -65l37 -43q13 -15 27.5 -19.5 t31.5 6.5l61 53q19 16 14 49q-2 20 -12 56t-17 45q-11 12 -19 14t-23 -8z" />
+<glyph unicode="&#xe227;" d="M625 1200h150q10 0 17.5 -7.5t7.5 -17.5v-109q79 -33 131 -87.5t53 -128.5q1 -46 -15 -84.5t-39 -61t-46 -38t-39 -21.5l-17 -6q6 0 15 -1.5t35 -9t50 -17.5t53 -30t50 -45t35.5 -64t14.5 -84q0 -59 -11.5 -105.5t-28.5 -76.5t-44 -51t-49.5 -31.5t-54.5 -16t-49.5 -6.5 t-43.5 -1v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-100v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-175q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v600h-75q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5h175v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h100v75q0 10 7.5 17.5t17.5 7.5zM400 900v-200h263q28 0 48.5 10.5t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-263zM400 500v-200h363q28 0 48.5 10.5 t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-363z" />
+<glyph unicode="&#xe230;" d="M212 1198h780q86 0 147 -61t61 -147v-416q0 -51 -18 -142.5t-36 -157.5l-18 -66q-29 -87 -93.5 -146.5t-146.5 -59.5h-572q-82 0 -147 59t-93 147q-8 28 -20 73t-32 143.5t-20 149.5v416q0 86 61 147t147 61zM600 1045q-70 0 -132.5 -11.5t-105.5 -30.5t-78.5 -41.5 t-57 -45t-36 -41t-20.5 -30.5l-6 -12l156 -243h560l156 243q-2 5 -6 12.5t-20 29.5t-36.5 42t-57 44.5t-79 42t-105 29.5t-132.5 12zM762 703h-157l195 261z" />
+<glyph unicode="&#xe231;" d="M475 1300h150q103 0 189 -86t86 -189v-500q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
+<glyph unicode="&#xe232;" d="M475 1300h96q0 -150 89.5 -239.5t239.5 -89.5v-446q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
+<glyph unicode="&#xe233;" d="M1294 767l-638 -283l-378 170l-78 -60v-224l100 -150v-199l-150 148l-150 -149v200l100 150v250q0 4 -0.5 10.5t0 9.5t1 8t3 8t6.5 6l47 40l-147 65l642 283zM1000 380l-350 -166l-350 166v147l350 -165l350 165v-147z" />
+<glyph unicode="&#xe234;" d="M250 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM650 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM1050 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
+<glyph unicode="&#xe235;" d="M550 1100q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 700q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 300q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
+<glyph unicode="&#xe236;" d="M125 1100h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM125 700h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM125 300h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="&#xe237;" d="M350 1200h500q162 0 256 -93.5t94 -256.5v-500q0 -165 -93.5 -257.5t-256.5 -92.5h-500q-165 0 -257.5 92.5t-92.5 257.5v500q0 165 92.5 257.5t257.5 92.5zM900 1000h-600q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h600q41 0 70.5 29.5 t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5zM350 900h500q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-500q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 14.5 35.5t35.5 14.5zM400 800v-200h400v200h-400z" />
+<glyph unicode="&#xe238;" d="M150 1100h1000q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe239;" d="M650 1187q87 -67 118.5 -156t0 -178t-118.5 -155q-87 66 -118.5 155t0 178t118.5 156zM300 800q124 0 212 -88t88 -212q-124 0 -212 88t-88 212zM1000 800q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM300 500q124 0 212 -88t88 -212q-124 0 -212 88t-88 212z M1000 500q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM700 199v-144q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v142q40 -4 43 -4q17 0 57 6z" />
+<glyph unicode="&#xe240;" d="M745 878l69 19q25 6 45 -12l298 -295q11 -11 15 -26.5t-2 -30.5q-5 -14 -18 -23.5t-28 -9.5h-8q1 0 1 -13q0 -29 -2 -56t-8.5 -62t-20 -63t-33 -53t-51 -39t-72.5 -14h-146q-184 0 -184 288q0 24 10 47q-20 4 -62 4t-63 -4q11 -24 11 -47q0 -288 -184 -288h-142 q-48 0 -84.5 21t-56 51t-32 71.5t-16 75t-3.5 68.5q0 13 2 13h-7q-15 0 -27.5 9.5t-18.5 23.5q-6 15 -2 30.5t15 25.5l298 296q20 18 46 11l76 -19q20 -5 30.5 -22.5t5.5 -37.5t-22.5 -31t-37.5 -5l-51 12l-182 -193h891l-182 193l-44 -12q-20 -5 -37.5 6t-22.5 31t6 37.5 t31 22.5z" />
+<glyph unicode="&#xe241;" d="M1200 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM500 450h-25q0 15 -4 24.5t-9 14.5t-17 7.5t-20 3t-25 0.5h-100v-425q0 -11 12.5 -17.5t25.5 -7.5h12v-50h-200v50q50 0 50 25v425h-100q-17 0 -25 -0.5t-20 -3t-17 -7.5t-9 -14.5t-4 -24.5h-25v150h500v-150z" />
+<glyph unicode="&#xe242;" d="M1000 300v50q-25 0 -55 32q-14 14 -25 31t-16 27l-4 11l-289 747h-69l-300 -754q-18 -35 -39 -56q-9 -9 -24.5 -18.5t-26.5 -14.5l-11 -5v-50h273v50q-49 0 -78.5 21.5t-11.5 67.5l69 176h293l61 -166q13 -34 -3.5 -66.5t-55.5 -32.5v-50h312zM412 691l134 342l121 -342 h-255zM1100 150v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z" />
+<glyph unicode="&#xe243;" d="M50 1200h1100q21 0 35.5 -14.5t14.5 -35.5v-1100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5zM611 1118h-70q-13 0 -18 -12l-299 -753q-17 -32 -35 -51q-18 -18 -56 -34q-12 -5 -12 -18v-50q0 -8 5.5 -14t14.5 -6 h273q8 0 14 6t6 14v50q0 8 -6 14t-14 6q-55 0 -71 23q-10 14 0 39l63 163h266l57 -153q11 -31 -6 -55q-12 -17 -36 -17q-8 0 -14 -6t-6 -14v-50q0 -8 6 -14t14 -6h313q8 0 14 6t6 14v50q0 7 -5.5 13t-13.5 7q-17 0 -42 25q-25 27 -40 63h-1l-288 748q-5 12 -19 12zM639 611 h-197l103 264z" />
+<glyph unicode="&#xe244;" d="M1200 1100h-1200v100h1200v-100zM50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 1000h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM700 900v-300h300v300h-300z" />
+<glyph unicode="&#xe245;" d="M50 1200h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 700h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM700 600v-300h300v300h-300zM1200 0h-1200v100h1200v-100z" />
+<glyph unicode="&#xe246;" d="M50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-350h100v150q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-150h100v-100h-100v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v150h-100v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM700 700v-300h300v300h-300z" />
+<glyph unicode="&#xe247;" d="M100 0h-100v1200h100v-1200zM250 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM300 1000v-300h300v300h-300zM250 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe248;" d="M600 1100h150q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-100h450q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h350v100h-150q-21 0 -35.5 14.5 t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h150v100h100v-100zM400 1000v-300h300v300h-300z" />
+<glyph unicode="&#xe249;" d="M1200 0h-100v1200h100v-1200zM550 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM600 1000v-300h300v300h-300zM50 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="&#xe250;" d="M865 565l-494 -494q-23 -23 -41 -23q-14 0 -22 13.5t-8 38.5v1000q0 25 8 38.5t22 13.5q18 0 41 -23l494 -494q14 -14 14 -35t-14 -35z" />
+<glyph unicode="&#xe251;" d="M335 635l494 494q29 29 50 20.5t21 -49.5v-1000q0 -41 -21 -49.5t-50 20.5l-494 494q-14 14 -14 35t14 35z" />
+<glyph unicode="&#xe252;" d="M100 900h1000q41 0 49.5 -21t-20.5 -50l-494 -494q-14 -14 -35 -14t-35 14l-494 494q-29 29 -20.5 50t49.5 21z" />
+<glyph unicode="&#xe253;" d="M635 865l494 -494q29 -29 20.5 -50t-49.5 -21h-1000q-41 0 -49.5 21t20.5 50l494 494q14 14 35 14t35 -14z" />
+<glyph unicode="&#xe254;" d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z" />
+<glyph unicode="&#xe255;" d="M1200 900h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300zM0 700h50q0 21 4 37t9.5 26.5t18 17.5t22 11t28.5 5.5t31 2t37 0.5h100v-550q0 -22 -25 -34.5t-50 -13.5l-25 -2v-100h400v100q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v550h100q25 0 37 -0.5t31 -2 t28.5 -5.5t22 -11t18 -17.5t9.5 -26.5t4 -37h50v300h-800v-300z" />
+<glyph unicode="&#xe256;" d="M800 700h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-100v-550q0 -22 25 -34.5t50 -14.5l25 -1v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v550h-100q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h800v-300zM1100 200h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300z" />
+<glyph unicode="&#xe257;" d="M701 1098h160q16 0 21 -11t-7 -23l-464 -464l464 -464q12 -12 7 -23t-21 -11h-160q-13 0 -23 9l-471 471q-7 8 -7 18t7 18l471 471q10 9 23 9z" />
+<glyph unicode="&#xe258;" d="M339 1098h160q13 0 23 -9l471 -471q7 -8 7 -18t-7 -18l-471 -471q-10 -9 -23 -9h-160q-16 0 -21 11t7 23l464 464l-464 464q-12 12 -7 23t21 11z" />
+<glyph unicode="&#xe259;" d="M1087 882q11 -5 11 -21v-160q0 -13 -9 -23l-471 -471q-8 -7 -18 -7t-18 7l-471 471q-9 10 -9 23v160q0 16 11 21t23 -7l464 -464l464 464q12 12 23 7z" />
+<glyph unicode="&#xe260;" d="M618 993l471 -471q9 -10 9 -23v-160q0 -16 -11 -21t-23 7l-464 464l-464 -464q-12 -12 -23 -7t-11 21v160q0 13 9 23l471 471q8 7 18 7t18 -7z" />
+<glyph unicode="&#xf8ff;" d="M1000 1200q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM450 1000h100q21 0 40 -14t26 -33l79 -194q5 1 16 3q34 6 54 9.5t60 7t65.5 1t61 -10t56.5 -23t42.5 -42t29 -64t5 -92t-19.5 -121.5q-1 -7 -3 -19.5t-11 -50t-20.5 -73t-32.5 -81.5t-46.5 -83t-64 -70 t-82.5 -50q-13 -5 -42 -5t-65.5 2.5t-47.5 2.5q-14 0 -49.5 -3.5t-63 -3.5t-43.5 7q-57 25 -104.5 78.5t-75 111.5t-46.5 112t-26 90l-7 35q-15 63 -18 115t4.5 88.5t26 64t39.5 43.5t52 25.5t58.5 13t62.5 2t59.5 -4.5t55.5 -8l-147 192q-12 18 -5.5 30t27.5 12z" />
+<glyph unicode="&#x1f511;" d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z" />
+<glyph unicode="&#x1f6aa;" d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z" />
+</font>
+</defs></svg> \ No newline at end of file
diff --git a/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.ttf b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 0000000000..1413fc609a
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.ttf
Binary files differ
diff --git a/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 0000000000..9e612858f8
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff
Binary files differ
diff --git a/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff2 b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff2
new file mode 100644
index 0000000000..64539b54c3
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff2
Binary files differ
diff --git a/library/cpp/lwtrace/mon/static/footer.html b/library/cpp/lwtrace/mon/static/footer.html
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/footer.html
diff --git a/library/cpp/lwtrace/mon/static/header.html b/library/cpp/lwtrace/mon/static/header.html
new file mode 100644
index 0000000000..9a263673d3
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/header.html
@@ -0,0 +1,11 @@
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+
+<link rel="stylesheet" href="lwtrace/mon/static/css/bootstrap.min.css">
+<link rel="stylesheet" href="lwtrace/mon/static/css/jquery.treegrid.css">
+<link rel="stylesheet" href="lwtrace/mon/static/common.css">
+
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.min.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.treegrid.min.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/js/bootstrap.min.js"></script>
+<script language="javascript" type="text/javascript" src="lwtrace/mon/static/common.js"></script>
diff --git a/library/cpp/lwtrace/mon/static/img/collapse.png b/library/cpp/lwtrace/mon/static/img/collapse.png
new file mode 100644
index 0000000000..76577a57a2
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/img/collapse.png
Binary files differ
diff --git a/library/cpp/lwtrace/mon/static/img/expand.png b/library/cpp/lwtrace/mon/static/img/expand.png
new file mode 100644
index 0000000000..cfb42a4512
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/img/expand.png
Binary files differ
diff --git a/library/cpp/lwtrace/mon/static/img/file.png b/library/cpp/lwtrace/mon/static/img/file.png
new file mode 100644
index 0000000000..813f712f72
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/img/file.png
Binary files differ
diff --git a/library/cpp/lwtrace/mon/static/img/folder.png b/library/cpp/lwtrace/mon/static/img/folder.png
new file mode 100644
index 0000000000..784e8fa482
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/img/folder.png
Binary files differ
diff --git a/library/cpp/lwtrace/mon/static/js/bootstrap.min.js b/library/cpp/lwtrace/mon/static/js/bootstrap.min.js
new file mode 100644
index 0000000000..80e40418f2
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/bootstrap.min.js
@@ -0,0 +1,9 @@
+/*!
+ * Bootstrap v3.0.2 by @fat and @mdo
+ * Copyright 2013 Twitter, Inc.
+ * Licensed under http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world by @mdo and @fat.
+ */
+
+if("undefined"==typeof jQuery)throw new Error("Bootstrap requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]}}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()})}(jQuery),+function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function c(){f.trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one(a.support.transition.end,c).emulateTransitionEnd(150):c())};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("bs.alert");e||d.data("bs.alert",e=new c(this)),"string"==typeof b&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.bs.alert.data-api",b,c.prototype.close)}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d)};b.DEFAULTS={loadingText:"loading..."},b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.is("input")?"val":"html",e=c.data();a+="Text",e.resetText||c.data("resetText",c[d]()),c[d](e[a]||this.options[a]),setTimeout(function(){"loadingText"==a?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.closest('[data-toggle="buttons"]');if(a.length){var b=this.$element.find("input").prop("checked",!this.$element.hasClass("active")).trigger("change");"radio"===b.prop("type")&&a.find(".active").removeClass("active")}this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof c&&c;e||d.data("bs.button",e=new b(this,f)),"toggle"==c?e.toggle():c&&e.setState(c)})},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.bs.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle"),b.preventDefault()})}(jQuery),+function(a){"use strict";var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},b.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},b.prototype.getActiveIndex=function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},b.prototype.to=function(b){var c=this,d=this.getActiveIndex();return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},b.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition.end&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},b.prototype.next=function(){return this.sliding?void 0:this.slide("next")},b.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},b.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}this.sliding=!0,f&&this.pause();var j=a.Event("slide.bs.carousel",{relatedTarget:e[0],direction:g});if(!e.hasClass("active")){if(this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")})),a.support.transition&&this.$element.hasClass("slide")){if(this.$element.trigger(j),j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)}).emulateTransitionEnd(600)}else{if(this.$element.trigger(j),j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c),g="string"==typeof c?c:f.slide;e||d.data("bs.carousel",e=new b(this,f)),"number"==typeof c?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c,d=a(this),e=a(d.attr("data-target")||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),d.data()),g=d.attr("data-slide-to");g&&(f.interval=!1),e.carousel(f),(g=d.attr("data-slide-to"))&&e.data("bs.carousel").to(g),b.preventDefault()}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var b=a(this);b.carousel(b.data())})})}(jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.DEFAULTS={toggle:!0},b.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},b.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b=a.Event("show.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.$parent&&this.$parent.find("> .panel > .in");if(c&&c.length){var d=c.data("bs.collapse");if(d&&d.transitioning)return;c.collapse("hide"),d||c.data("bs.collapse",null)}var e=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[e](0),this.transitioning=1;var f=function(){this.$element.removeClass("collapsing").addClass("in")[e]("auto"),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return f.call(this);var g=a.camelCase(["scroll",e].join("-"));this.$element.one(a.support.transition.end,a.proxy(f,this)).emulateTransitionEnd(350)[e](this.$element[0][g])}}},b.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?(this.$element[c](0).one(a.support.transition.end,a.proxy(d,this)).emulateTransitionEnd(350),void 0):d.call(this)}}},b.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c);e||d.data("bs.collapse",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.bs.collapse.data-api","[data-toggle=collapse]",function(b){var c,d=a(this),e=d.attr("data-target")||b.preventDefault()||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.collapse"),h=g?"toggle":d.data(),i=d.attr("data-parent"),j=i&&a(i);g&&g.transitioning||(j&&j.find('[data-toggle=collapse][data-parent="'+i+'"]').not(d).addClass("collapsed"),d[f.hasClass("in")?"addClass":"removeClass"]("collapsed")),f.collapse(h)})}(jQuery),+function(a){"use strict";function b(){a(d).remove(),a(e).each(function(b){var d=c(a(this));d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown")),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown"))})}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}var d=".dropdown-backdrop",e="[data-toggle=dropdown]",f=function(b){a(b).on("click.bs.dropdown",this.toggle)};f.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){if("ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b),f.trigger(d=a.Event("show.bs.dropdown")),d.isDefaultPrevented())return;f.toggleClass("open").trigger("shown.bs.dropdown"),e.focus()}return!1}},f.prototype.keydown=function(b){if(/(38|40|27)/.test(b.keyCode)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var f=c(d),g=f.hasClass("open");if(!g||g&&27==b.keyCode)return 27==b.which&&f.find(e).focus(),d.click();var h=a("[role=menu] li:not(.divider):visible a",f);if(h.length){var i=h.index(h.filter(":focus"));38==b.keyCode&&i>0&&i--,40==b.keyCode&&i<h.length-1&&i++,~i||(i=0),h.eq(i).focus()}}}};var g=a.fn.dropdown;a.fn.dropdown=function(b){return this.each(function(){var c=a(this),d=c.data("dropdown");d||c.data("dropdown",d=new f(this)),"string"==typeof b&&d[b].call(c)})},a.fn.dropdown.Constructor=f,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=g,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",e,f.prototype.toggle).on("keydown.bs.dropdown.data-api",e+", [role=menu]",f.prototype.keydown)}(jQuery),+function(a){"use strict";var b=function(b,c){this.options=c,this.$element=a(b),this.$backdrop=this.isShown=null,this.options.remote&&this.$element.load(this.options.remote)};b.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},b.prototype.toggle=function(a){return this[this.isShown?"hide":"show"](a)},b.prototype.show=function(b){var c=this,d=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(d),this.isShown||d.isDefaultPrevented()||(this.isShown=!0,this.escape(),this.$element.on("click.dismiss.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.backdrop(function(){var d=a.support.transition&&c.$element.hasClass("fade");c.$element.parent().length||c.$element.appendTo(document.body),c.$element.show(),d&&c.$element[0].offsetWidth,c.$element.addClass("in").attr("aria-hidden",!1),c.enforceFocus();var e=a.Event("shown.bs.modal",{relatedTarget:b});d?c.$element.find(".modal-dialog").one(a.support.transition.end,function(){c.$element.focus().trigger(e)}).emulateTransitionEnd(300):c.$element.focus().trigger(e)}))},b.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one(a.support.transition.end,a.proxy(this.hideModal,this)).emulateTransitionEnd(300):this.hideModal())},b.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.focus()},this))},b.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keyup.dismiss.bs.modal")},b.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden.bs.modal")})},b.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},b.prototype.backdrop=function(b){var c=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var d=a.support.transition&&c;if(this.$backdrop=a('<div class="modal-backdrop '+c+'" />').appendTo(document.body),this.$element.on("click.dismiss.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),d&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;d?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,b).emulateTransitionEnd(150):b()):b&&b()};var c=a.fn.modal;a.fn.modal=function(c,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},b.DEFAULTS,e.data(),"object"==typeof c&&c);f||e.data("bs.modal",f=new b(this,g)),"string"==typeof c?f[c](d):g.show&&f.show(d)})},a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=c,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({remote:!/#/.test(d)&&d},e.data(),c.data());b.preventDefault(),e.modal(f,this).one("hide",function(){c.is(":visible")&&c.focus()})}),a(document).on("show.bs.modal",".modal",function(){a(document.body).addClass("modal-open")}).on("hidden.bs.modal",".modal",function(){a(document.body).removeClass("modal-open")})}(jQuery),+function(a){"use strict";var b=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};b.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},b.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focus",i="hover"==g?"mouseleave":"blur";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},b.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},b.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show),void 0):c.show()},b.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide),void 0):c.hide()},b.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){if(this.$element.trigger(b),b.isDefaultPrevented())return;var c=this.tip();this.setContent(),this.options.animation&&c.addClass("fade");var d="function"==typeof this.options.placement?this.options.placement.call(this,c[0],this.$element[0]):this.options.placement,e=/\s?auto?\s?/i,f=e.test(d);f&&(d=d.replace(e,"")||"top"),c.detach().css({top:0,left:0,display:"block"}).addClass(d),this.options.container?c.appendTo(this.options.container):c.insertAfter(this.$element);var g=this.getPosition(),h=c[0].offsetWidth,i=c[0].offsetHeight;if(f){var j=this.$element.parent(),k=d,l=document.documentElement.scrollTop||document.body.scrollTop,m="body"==this.options.container?window.innerWidth:j.outerWidth(),n="body"==this.options.container?window.innerHeight:j.outerHeight(),o="body"==this.options.container?0:j.offset().left;d="bottom"==d&&g.top+g.height+i-l>n?"top":"top"==d&&g.top-l-i<0?"bottom":"right"==d&&g.right+h>m?"left":"left"==d&&g.left-h<o?"right":d,c.removeClass(k).addClass(d)}var p=this.getCalculatedOffset(d,g,h,i);this.applyPlacement(p,d),this.$element.trigger("shown.bs."+this.type)}},b.prototype.applyPlacement=function(a,b){var c,d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),a.top=a.top+g,a.left=a.left+h,d.offset(a).addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;if("top"==b&&j!=f&&(c=!0,a.top=a.top+f-j),/bottom|top/.test(b)){var k=0;a.left<0&&(k=-2*a.left,a.left=0,d.offset(a),i=d[0].offsetWidth,j=d[0].offsetHeight),this.replaceArrow(k-e+i,i,"left")}else this.replaceArrow(j-f,j,"top");c&&d.offset(a)},b.prototype.replaceArrow=function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},b.prototype.hide=function(){function b(){"in"!=c.hoverState&&d.detach()}var c=this,d=this.tip(),e=a.Event("hide.bs."+this.type);return this.$element.trigger(e),e.isDefaultPrevented()?void 0:(d.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d.one(a.support.transition.end,b).emulateTransitionEnd(150):b(),this.$element.trigger("hidden.bs."+this.type),this)},b.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},b.prototype.hasContent=function(){return this.getTitle()},b.prototype.getPosition=function(){var b=this.$element[0];return a.extend({},"function"==typeof b.getBoundingClientRect?b.getBoundingClientRect():{width:b.offsetWidth,height:b.offsetHeight},this.$element.offset())},b.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},b.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},b.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},b.prototype.validate=function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},b.prototype.enable=function(){this.enabled=!0},b.prototype.disable=function(){this.enabled=!1},b.prototype.toggleEnabled=function(){this.enabled=!this.enabled},b.prototype.toggle=function(b){var c=b?a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type):this;c.tip().hasClass("in")?c.leave(c):c.enter(c)},b.prototype.destroy=function(){this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var c=a.fn.tooltip;a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof c&&c;e||d.data("bs.tooltip",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=c,this}}(jQuery),+function(a){"use strict";var b=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");b.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),b.prototype.constructor=b,b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"html":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},b.prototype.hasContent=function(){return this.getTitle()||this.getContent()},b.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},b.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof c&&c;e||d.data("bs.popover",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(jQuery),+function(a){"use strict";function b(c,d){var e,f=a.proxy(this.process,this);this.$element=a(c).is("body")?a(window):a(c),this.$body=a("body"),this.$scrollElement=this.$element.on("scroll.bs.scroll-spy.data-api",f),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||(e=a(c).attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.offsets=a([]),this.targets=a([]),this.activeTarget=null,this.refresh(),this.process()}b.DEFAULTS={offset:10},b.prototype.refresh=function(){var b=this.$element[0]==window?"offset":"position";this.offsets=a([]),this.targets=a([]);var c=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#\w/.test(e)&&a(e);return f&&f.length&&[[f[b]().top+(!a.isWindow(c.$scrollElement.get(0))&&c.$scrollElement.scrollTop()),e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){c.offsets.push(this[0]),c.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,d=c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(b>=d)return g!=(a=f.last()[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parents(".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate")};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(jQuery),+function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.parent("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},b.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one(a.support.transition.end,e).emulateTransitionEnd(150):e(),f.removeClass("in")};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new b(this)),"string"==typeof c&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(jQuery),+function(a){"use strict";var b=function(c,d){this.options=a.extend({},b.DEFAULTS,d),this.$window=a(window).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(c),this.affixed=this.unpin=null,this.checkPosition()};b.RESET="affix affix-top affix-bottom",b.DEFAULTS={offset:0},b.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},b.prototype.checkPosition=function(){if(this.$element.is(":visible")){var c=a(document).height(),d=this.$window.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top()),"function"==typeof h&&(h=f.bottom());var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=c-h?"bottom":null!=g&&g>=d?"top":!1;this.affixed!==i&&(this.unpin&&this.$element.css("top",""),this.affixed=i,this.unpin="bottom"==i?e.top-d:null,this.$element.removeClass(b.RESET).addClass("affix"+(i?"-"+i:"")),"bottom"==i&&this.$element.offset({top:document.body.offsetHeight-h-this.$element.height()}))}};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof c&&c;e||d.data("bs.affix",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(jQuery);
diff --git a/library/cpp/lwtrace/mon/static/js/d3-gantt.js b/library/cpp/lwtrace/mon/static/js/d3-gantt.js
new file mode 100644
index 0000000000..54ec38ae57
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/d3-gantt.js
@@ -0,0 +1,759 @@
+d3.gantt = function() {
+ function gantt(config, logs, autoscale) {
+ parseLogs(config, logs);
+
+ if (autoscale) {
+ gantt.timeDomain([minT, maxT]);
+ }
+
+ initAxis();
+
+ // create svg element
+ svg = d3.select(selector)
+ .append("svg")
+ .attr("class", "chart")
+ .attr("width", width + margin.left + margin.right)
+ .attr("height", height + margin.top + margin.bottom)
+ ;
+
+ // create arrowhead marker
+ defs = svg.append("defs");
+ defs.append("marker")
+ .attr("id", "arrow")
+ .attr("viewBox", "0 -5 10 10")
+ .attr("refX", 5)
+ .attr("refY", 0)
+ .attr("markerWidth", 4)
+ .attr("markerHeight", 4)
+ .attr("orient", "auto")
+ .append("path")
+ .attr("d", "M0,-5L10,0L0,5")
+ .attr("class","arrowHead")
+ ;
+
+ zoom = d3.zoom()
+ .scaleExtent([0.1, 1000])
+ //.translateExtent([0, 0], [1000,0])
+ .on("zoom", function() {
+ if (tipShown != null) {
+ tip.hide(tipShown);
+ }
+ var tr = d3.event.transform;
+ xZoomed = tr.rescaleX(x);
+ svg.select("g.x.axis").call(xAxis.scale(xZoomed));
+
+ var dy = d3.event.sourceEvent.screenY - zoom.startScreenY;
+ var newScrollTop = documentBodyScrollTop() - dy;
+ window.scrollTo(documentBodyScrollLeft(), newScrollTop);
+ documentBodyScrollTop(newScrollTop);
+ zoom.startScreenY = d3.event.sourceEvent.screenY;
+
+ zoomContainer1.attr("transform", "translate(" + tr.x + ",0) scale(" + tr.k + ",1)");
+ zoomContainer2.attr("transform", "translate(" + tr.x + ",0) scale(" + tr.k + ",1)");
+
+ render();
+ })
+ .on("start", function() {
+ zoom.startScreenY = d3.event.sourceEvent.screenY;
+ })
+ .on("end", function() {
+ })
+ ;
+
+ svgChartContainer = svg.append('g')
+ .attr("transform", "translate(" + margin.left + ", " + margin.top + ")")
+ ;
+ svgChart = svgChartContainer.append("svg")
+ .attr("top", 0)
+ .attr("left", 0)
+ .attr("width", width)
+ .attr("height", height)
+ .attr("viewBox", "0 0 " + width + " " + height)
+ ;
+
+ zoomContainer1 = svgChart.append("g");
+
+ zoomPanel = svgChart.append("rect")
+ .attr("class", "zoom-panel")
+ .attr("width", width)
+ .attr("height", height)
+ .call(zoom)
+ ;
+
+ zoomContainer2 = svgChart.append("g");
+ bandsSvg = zoomContainer2.append("g");
+
+ // tooltips for bands
+ var maxTipHeight = 130;
+ const tipDirection = d => y(d.band) - maxTipHeight < documentBodyScrollTop()? 's': 'n';
+ tip = d3.tip()
+ .attr("class", "d3-tip")
+ .offset(function(d) {
+ // compute x to return tip in chart region
+ var t0 = (d.t1 + d.t2) / 2;
+ var t1 = Math.min(Math.max(t0, xZoomed.invert(0)), xZoomed.invert(width));
+ var dir = tipDirection(d);
+ return [dir === 'n'? -10 : 10, xZoomed(t1) - xZoomed(t0)];
+ })
+ .direction(tipDirection)
+ .html(function(d) {
+ let text = '';
+ for (let item of d.record) {
+ text += probes[item[PROBEID]].provider + "." + probes[item[PROBEID]].name + "(";
+ let first = true;
+ for (let [param, value] of Object.entries(item[PARAMS])) {
+ text += (first? "": ", ") + param + "='" + value + "'";
+ first = false;
+ }
+ text += ")\n";
+ }
+ return "<pre>" + text + "</pre>";
+ })
+ ;
+
+ bandsSvg.call(tip);
+
+ render();
+
+ // container for non-zoomable elements
+ fixedContainer = svg.append("g")
+ .attr("transform", "translate(" + margin.left + ", " + margin.top + ")")
+ ;
+
+ // create x axis
+ fixedContainer.append("g")
+ .attr("class", "x axis")
+ .attr("transform", "translate(0, " + (height - margin.top - margin.bottom) + ")")
+ .transition()
+ .call(xAxis)
+ ;
+
+ // create y axis
+ fixedContainer.append("g")
+ .attr("class", "y axis")
+ .transition()
+ .call(yAxis)
+ ;
+
+ // make y axis ticks draggable
+ var ytickdrag = d3.drag()
+ .on("drag", function(d) {
+ var ypos = d3.event.y - margin.top;
+ var index = Math.floor((ypos / y.step()));
+ index = Math.min(Math.max(index, 0), this.initDomain.length - 1);
+ if (index != this.curIndex) {
+ var newDomain = [];
+ for (var i = 0; i < this.initDomain.length; ++i) {
+ newDomain.push(this.initDomain[i]);
+ }
+ newDomain.splice(this.initIndex, 1);
+ newDomain.splice(index, 0, this.initDomain[this.initIndex]);
+
+ this.curIndex = index;
+ this.curDomain = newDomain;
+ y.domain(newDomain);
+
+ // rearange y scale and axis
+ svg.select("g.y.axis").transition().call(yAxis);
+
+ // rearange other stuff
+ render(-1, true);
+ }
+ })
+ .on("start", function(d) {
+ var ypos = d3.event.y - margin.top;
+ this.initIndex = Math.floor((ypos / y.step()));
+ this.initDomain = y.domain();
+ })
+ .on("end", function(d) {
+ svg.select("g.y.axis").call(yAxis);
+ })
+ ;
+ svg.selectAll("g.y.axis .tick")
+ .call(ytickdrag)
+ ;
+
+ // right margin
+ var rmargin = fixedContainer.append("g")
+ .attr("id", "right-margin")
+ .attr("transform", "translate(" + width + ", 0)")
+ ;
+ rmargin.append("rect")
+ .attr("x", 0)
+ .attr("y", 0)
+ .attr("width", 1)
+ .attr("height", height - margin.top - margin.bottom)
+ ;
+
+ // top margin
+ var tmargin = fixedContainer.append("g")
+ .attr("id", "top-margin")
+ .attr("transform", "translate(0, 0)")
+ ;
+ tmargin.append("rect")
+ .attr("x", 0)
+ .attr("y", 0)
+ .attr("width", width)
+ .attr("height", 1)
+ ;
+
+ // ruler
+ ruler = fixedContainer.append("g")
+ .attr("id", "ruler")
+ .attr("transform", "translate(0, 0)")
+ ;
+ ruler.append("rect")
+ .attr("id", "ruler-line")
+ .attr("x", 0)
+ .attr("y", 0)
+ .attr("width", "1")
+ .attr("height", height - margin.top - margin.bottom + 8)
+ ;
+ ruler.append("rect")
+ .attr("id", "bgrect")
+ .attr("x", 0)
+ .attr("y", 0)
+ .attr("width", 0)
+ .attr("height", 0)
+ .style("fill", "white")
+ ;
+ ruler.append("text")
+ .attr("x", 0)
+ .attr("y", height - margin.top - margin.bottom + 16)
+ .attr("dy", "0.71em")
+ .text("0")
+ ;
+
+ svg.on('mousemove', function() {
+ positionRuler(d3.event.pageX);
+ });
+
+ // scroll handling
+ window.onscroll = function myFunction() {
+ documentBodyScrollLeft(document.body.scrollLeft);
+ documentBodyScrollTop(document.body.scrollTop);
+ var scroll = scrollParams();
+
+ svgChartContainer
+ .attr("transform", "translate(" + margin.left
+ + ", " + (margin.top + scroll.y1) + ")");
+ svgChart
+ .attr("viewBox", "0 " + scroll.y1 + " " + width + " " + scroll.h)
+ .attr("height", scroll.h);
+ tmargin
+ .attr("transform", "translate(0," + scroll.y1 + ")");
+ fixedContainer.select(".x.axis")
+ .attr("transform", "translate(0," + scroll.y2 + ")");
+ rmargin.select("rect")
+ .attr("y", scroll.y1)
+ .attr("height", scroll.h);
+ ruler.select("#ruler-line")
+ .attr("y", scroll.y1)
+ .attr("height", scroll.h);
+
+ positionRuler();
+ }
+
+ // render axis
+ svg.select("g.x.axis").call(xAxis);
+ svg.select("g.y.axis").call(yAxis);
+
+ // update to initiale state
+ window.onscroll(0);
+
+ return gantt;
+ }
+
+// private:
+
+ var keyFunction = function(d) {
+ return d.t1.toString() + d.t2.toString() + d.band.toString();
+ }
+
+ var bandTransform = function(d) {
+ return "translate(" + x(d.t1) + "," + y(d.band) + ")";
+ }
+
+ var xPixel = function(d) {
+ return xZoomed.invert(1) - xZoomed.invert(0);
+ }
+
+ var render = function(t0, smooth) {
+ // Save/restore last t0 value
+ if (!arguments.length || t0 == -1) {
+ t0 = render.t0;
+ }
+ render.t0 = t0;
+ smooth = smooth || false;
+
+ // Create rectangles for bands
+ bands = bandsSvg.selectAll("rect.bar")
+ .data(data, keyFunction);
+ bands.exit().remove();
+ bands.enter().append("rect")
+ .attr("class", "bar")
+ .attr("vector-effect", "non-scaling-stroke")
+ .style("fill", d => d.color)
+ .on('click', function(d) {
+ if (tipShown != d) {
+ tipShown = d;
+ tip.show(d);
+ } else {
+ tipShown = null;
+ tip.hide(d);
+ }
+ })
+ .merge(bands)
+ .transition().duration(smooth? 250: 0)
+ .attr("y", 0)
+ .attr("transform", bandTransform)
+ .attr("height", y.bandwidth())
+ .attr("width", d => Math.max(1*xPixel(), x(d.t2) - x(d.t1)))
+ ;
+
+ var emptyMarker = bandsSvg.selectAll("text")
+ .data(data.length == 0? ["no data to show"]: []);
+ emptyMarker.exit().remove();
+ emptyMarker.enter().append("text")
+ .text(d => d)
+ ;
+ }
+
+ function initAxis() {
+ x = d3.scaleLinear()
+ .domain([timeDomainStart, timeDomainEnd])
+ .range([0, width])
+ //.clamp(true); // dosn't work with zoom/pan
+ xZoomed = x;
+ y = d3.scaleBand()
+ .domain(Object.values(data).map(d => d.band).sort())
+ .rangeRound([0, height - margin.top - margin.bottom])
+ .padding(0.5);
+ xAxis = d3.axisBottom()
+ .scale(x)
+ //.tickSubdivide(true)
+ .tickSize(8)
+ .tickPadding(8);
+ yAxis = d3.axisLeft()
+ .scale(y)
+ .tickSize(0);
+ }
+
+ // slow function wrapper
+ var documentBodyScrollLeft = function(value) {
+ if (!arguments.length) {
+ if (documentBodyScrollLeft.value === undefined) {
+ documentBodyScrollLeft.value = document.body.scrollLeft;
+ }
+ return documentBodyScrollLeft.value;
+ } else {
+ documentBodyScrollLeft.value = value;
+ }
+ }
+
+ // slow function wrapper
+ var documentBodyScrollTop = function(value) {
+ if (!arguments.length) {
+ if (!documentBodyScrollTop.value === undefined) {
+ documentBodyScrollTop.value = document.body.scrollTop;
+ }
+ return documentBodyScrollTop.value;
+ } else {
+ documentBodyScrollTop.value = value;
+ }
+ }
+
+ var scrollParams = function() {
+ var y1 = documentBodyScrollTop();
+ var y2 = y1 + window.innerHeight - margin.footer;
+ y2 = Math.min(y2, height - margin.top - margin.bottom);
+ var h = y2 - y1;
+ return {
+ y1: y1,
+ y2: y2,
+ h: h
+ };
+ }
+
+ var posTextFormat = d3.format(".1f");
+
+ var positionRuler = function(pageX) {
+ if (!arguments.length) {
+ pageX = positionRuler.pageX || 0;
+ } else {
+ positionRuler.pageX = pageX;
+ }
+
+ // x-coordinate
+ if (!positionRuler.svgLeft) {
+ positionRuler.svgLeft = svg.node().getBoundingClientRect().x;
+ }
+
+ var xpos = pageX - margin.left + 1 - positionRuler.svgLeft;
+ var tpos = xZoomed.invert(xpos);
+ tpos = Math.min(Math.max(tpos, xZoomed.invert(0)), xZoomed.invert(width));
+ ruler.attr("transform", "translate(" + xZoomed(tpos) + ", 0)");
+ var posText = posTextFormat(tpos);
+
+ // scroll-related
+ var scroll = scrollParams();
+
+ var text = ruler.select("text")
+ .attr("y", scroll.y2 + 16)
+ ;
+
+ // getBBox() is very slow, so compute symbol width once
+ var xpadding = 5;
+ var ypadding = 5;
+ if (!positionRuler.bbox) {
+ positionRuler.bbox = text.node().getBBox();
+ }
+
+ text.text(posText);
+ var textWidth = 10 * posText.length;
+ ruler.select("#bgrect")
+ .attr("x", -textWidth/2 - xpadding)
+ .attr("y", positionRuler.bbox.y - ypadding)
+ .attr("width", textWidth + (xpadding*2))
+ .attr("height", positionRuler.bbox.height + (ypadding*2))
+ ;
+
+ render(tpos);
+ }
+
+ /*
+ * Log Query Language:
+ * Data expressions:
+ * 1) myparam[0], myparam[-1] // the first and the last myparam in any probe/provider
+ * 2) myparam // the first (the same as [0])
+ * 3) PROVIDER..myparam // any probe with myparam in PROVIDER
+ * 4) MyProbe._elapsedMs // Ms since track begin for the first MyProbe event
+ * 5) PROVIDER.MyProbe._sliceUs // Us since previous event in track for the first PROVIDER.MyProbe event
+ */
+ function compile(query) {
+ query = query.replace(/\s/g, "");
+ let [compiled, rest] = sum(query);
+ if (rest.length != 0) {
+ throw "parse error: unexpected expression starting at: '" + query + "'";
+ }
+ return record => {
+ try {
+ return compiled(record);
+ } catch (e) {
+ return null;
+ }
+ };
+
+ function sum(query) {
+ let term0;
+ if (query[0] == '-') {
+ let [term, rest] = product(query.substr(1));
+ query = rest;
+ term0 = x => -term(x);
+ } else {
+ let [term, rest] = product(query);
+ query = rest;
+ term0 = term;
+ }
+ let terms = [];
+ while (query.length > 0) {
+ let negate;
+ if (query[0] == '+') {
+ negate = false;
+ } else if (query[0] == '-') {
+ negate = true;
+ } else {
+ break;
+ }
+ let [term, rest] = product(query.substr(1));
+ query = rest;
+ terms.push(negate? x => -term(x): term);
+ }
+ const cast = x => (isNaN(+x)? x: +x);
+ return [terms.reduce((a, f) => x => cast(a(x)) + cast(f(x)), term0), query];
+ }
+
+ function product(query) {
+ let [factor0, rest] = parentheses(query);
+ query = rest;
+ let factors = [];
+ while (query.length > 0) {
+ let invert;
+ if (query[0] == '*') {
+ invert = false;
+ } else if (query[0] == '/') {
+ invert = true;
+ } else {
+ break;
+ }
+ let [factor, rest] = parentheses(query.substr(1));
+ query = rest;
+ factors.push(invert? x => 1 / factor(x): factor);
+ }
+ return [factors.reduce((a, f) => x => a(x) * f(x), factor0), query];
+ }
+
+ function parentheses(query) {
+ if (query[0] == "(") {
+ let [expr, rest] = sum(query.substr(1));
+ if (rest[0] != ")") {
+ throw "parse error: missing ')' before '" + rest + "'";
+ }
+ return [expr, rest.substr(1)];
+ } else {
+ return atom(query);
+ }
+ }
+
+ function atom(query) {
+ specialParam = {
+ _thrNTime: item => (item[US] - thrNTimeZero) * 1e-6,
+ _thrRTime: item => (item[US] - thrRTimeZero) * 1e-6,
+ _thrTime: item => item[US] * 1e-6,
+ _thrNTimeMs: item => (item[US] - thrNTimeZero) * 1e-3,
+ _thrRTimeMs: item => (item[US] - thrRTimeZero) * 1e-3,
+ _thrTimeMs: item => item[US] * 1e-3,
+ _thrNTimeUs: item => item[US] - thrNTimeZero,
+ _thrRTimeUs: item => item[US] - thrRTimeZero,
+ _thrTimeUs: item => item[US],
+ _thrNTimeNs: item => (item[US] - thrNTimeZero) * 1e+3,
+ _thrRTimeNs: item => (item[US] - thrRTimeZero) * 1e+3,
+ _thrTimeNs: item => item[US] * 1e+3,
+ _thread: item => item[THREAD],
+ };
+ var match;
+ if (match = query.match(/^\d+(\.\d+)?/)) { // number literals
+ let literal = match[0];
+ return [record => literal, query.substr(match[0].length)];
+ } else if (match = query.match(/^#[0-9a-fA-F]+/)) { // color literals
+ let literal = match[0];
+ return [record => literal, query.substr(match[0].length)];
+ } else if (match = query.match(/^'(.*)'/)) { // string literal
+ let literal = match[1].replace(/\\'/, "'").replace(/\\\\/, "\\");
+ return [record => literal, query.substr(match[0].length)];
+ } else if (match = query.match(/^(?:(?:(\w+)\.)?(\w*)\.)?(\w+)(?:\[(-?\d+)\])?/)) {
+ let provider = match[1] || "";
+ let probe = match[2] || "";
+ let param = match[3];
+ let index = +(match[4] || 0);
+ let probeId = new Set();
+ for (let id = 0; id < probes.length; id++) {
+ if ((!probe || probes[id].name == probe) &&
+ (!provider || probes[id].provider == provider))
+ {
+ probeId.add(id);
+ }
+ }
+ let isSpecial = specialParam.hasOwnProperty(param);
+ return [record => {
+ let end = index >= 0? record.length: -1;
+ let step = index >= 0? 1: -1;
+ let skip = index >= 0? index: -index - 1;
+ for (let i = index >= 0? 0: record.length - 1; i != end; i += step) {
+ let item = record[i];
+ if (probeId.has(item[PROBEID]) && (isSpecial || item[PARAMS].hasOwnProperty(param))) {
+ if (skip == 0) {
+ return isSpecial? specialParam[param](item): item[PARAMS][param];
+ } else {
+ skip--;
+ }
+ }
+ }
+ throw "no data";
+ }, query.substr(match[0].length)];
+ } else {
+ throw "parse error: invalid expression starting at '" + query + "'";
+ }
+ }
+ }
+
+ // ex1: "linear().domain([-1, 0, 1]).range(['red', 'white', 'green'])",
+ // ex2: "ordinal().domain(['a1', 'a2']).range(['blue', 'yellow'])"
+ function parseScale(query) {
+ query = query.replaceAll("'","\"");
+ var match, scale;
+ if (match = query.match(/^linear\(\)/)) {
+ scale = d3.scaleLinear();
+ } else if (match = query.match(/^pow\(\)/)) {
+ scale = d3.scalePow();
+ } else if (match = query.match(/^log\(\)/)) {
+ scale = d3.scaleLog();
+ } else if (match = query.match(/^identity\(\)/)) {
+ scale = d3.scaleIdentity();
+ } else if (match = query.match(/^time\(\)/)) {
+ scale = d3.scaleTime();
+ } else if (match = query.match(/^threshold\(\)/)) {
+ scale = d3.scaleThreshold();
+ } else if (match = query.match(/^ordinal\(\)/)) {
+ scale = d3.scaleOrdinal();
+ } else {
+ throw "Unable to parse scale: " + query;
+ }
+ if (match = query.match(/\.domain\(([^\)]+)\)/)) {
+ scale.domain(JSON.parse(match[1]));
+ }
+ if (match = query.match(/\.range\(([^\)]+)\)/)) {
+ scale.range(JSON.parse(match[1]));
+ }
+ if (match = query.match(/\.unknown\(([^\)]+)\)/)) {
+ scale.unknown(JSON.parse(match[1]));
+ }
+ return scale;
+ }
+
+ function parseLogs(config, logs) {
+ data = [];
+ probes = logs.probes;
+ if (config.hasOwnProperty('scales'))
+ for (let [name, text] of Object.entries(config.scales)) {
+ scales[name] = parseScale(text);
+ }
+ // Compute aggregates
+ let minUs = new Map();
+ for (record of logs.depot) {
+ if (record.length > 0) {
+ let item = record[0];
+ let us = item[US];
+ let thread = item[US];
+ if (!minUs.has(thread)) {
+ minUs.set(thread, us);
+ } else {
+ minUs.set(thread, Math.min(us, minUs.get(thread)));
+ }
+ }
+ }
+ thrNTimeZero = Number.MAX_VALUE;
+ thrRTimeZero = 0;
+ for (let [thread, us] of minUs) {
+ thrNTimeZero = Math.min(thrNTimeZero, us);
+ thrRTimeZero = Math.max(thrRTimeZero, us);
+ }
+ // Comple data for bands
+ for (let bandCfg of config.bands) {
+ function applyScale(func, scaleName) {
+ if (scaleName) {
+ let scale = scales[scaleName];
+ return (record) => {
+ let value = func(record);
+ if (value != null) {
+ value = scale(value);
+ }
+ return value;
+ };
+ } else {
+ return func;
+ }
+ }
+ let t1f = applyScale(compile(bandCfg.t1), bandCfg.t1Scale);
+ let t2f = applyScale(compile(bandCfg.t2), bandCfg.t2Scale);
+ let bandf = applyScale(compile(bandCfg.band), bandCfg.bandScale);
+ let colorf = applyScale(compile(bandCfg.color), bandCfg.colorScale);
+ let minTime = Number.MAX_VALUE;
+ let maxTime = -Number.MAX_VALUE;
+ for (record of logs.depot) {
+ let t1 = t1f(record),
+ t2 = t2f(record),
+ band = bandf(record),
+ color = colorf(record)
+ ;
+ if (t1 != null && t2 != null && band != null && color != null) {
+ data.push({t1, t2, band, color, record});
+ minTime = Math.min(minTime, t1);
+ maxTime = Math.max(maxTime, t2);
+ }
+ }
+ if (minTime != Number.MAX_VALUE) {
+ minT = minTime;
+ maxT = maxTime;
+ }
+ }
+ }
+
+// public:
+
+ gantt.width = function(value) {
+ if (!arguments.length)
+ return width;
+ width = +value;
+ return gantt;
+ }
+
+ gantt.height = function(value) {
+ if (!arguments.length)
+ return height;
+ height = +value;
+ return gantt;
+ }
+
+ gantt.selector = function(value) {
+ if (!arguments.length)
+ return selector;
+ selector = value;
+ return gantt;
+ }
+
+ gantt.timeDomain = function(value) {
+ if (!arguments.length)
+ return [timeDomainStart, timeDomainEnd];
+ timeDomainStart = value[0];
+ timeDomainEnd = value[1];
+ return gantt;
+ }
+
+ gantt.data = function() {
+ return data;
+ }
+
+ // constructor
+
+ // Log Format
+ const
+ THREAD = 0,
+ US = 1,
+ PROBEID = 2,
+ PARAMS = 3
+ ;
+
+ // Config
+ var margin = { top: 20, right: 40, bottom: 20, left: 100, footer: 100 },
+ height = document.body.clientHeight - margin.top - margin.bottom - 5,
+ width = document.body.clientWidth - margin.right - margin.left - 5,
+ selector = 'body',
+ timeDomainStart = 0,
+ timeDomainEnd = 1000,
+ scales = {};
+ ;
+
+ // View
+ var x = null,
+ xZoomed = null,
+ y = null,
+ xAxis = null,
+ yAxis = null,
+ svg = null,
+ defs = null,
+ svgChartContainer = null,
+ svgChart = null,
+ zoomPanel = null,
+ zoomContainer1 = null,
+ zoomContainer2 = null,
+ fixedContainer = null,
+ zoom = null,
+ bandsSvg = null,
+ bands = null,
+ tip = null,
+ tipShown = null,
+ ruler = null
+ ;
+
+ // Model
+ var data = null,
+ probes = null,
+ thrRTimeZero = 0,
+ thrNTimeZero = 0,
+ minT,
+ maxT
+ ;
+
+ return gantt;
+} \ No newline at end of file
diff --git a/library/cpp/lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js b/library/cpp/lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js
new file mode 100644
index 0000000000..ad3a6c0d19
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js
@@ -0,0 +1,352 @@
+/**
+ * d3.tip
+ * Copyright (c) 2013 Justin Palmer
+ *
+ * Tooltips for d3.js SVG visualizations
+ */
+// eslint-disable-next-line no-extra-semi
+;(function(root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module with d3 as a dependency.
+ define([
+ 'd3-collection',
+ 'd3-selection'
+ ], factory)
+ } else if (typeof module === 'object' && module.exports) {
+ /* eslint-disable global-require */
+ // CommonJS
+ var d3Collection = require('d3-collection'),
+ d3Selection = require('d3-selection')
+ module.exports = factory(d3Collection, d3Selection)
+ /* eslint-enable global-require */
+ } else {
+ // Browser global.
+ var d3 = root.d3
+ // eslint-disable-next-line no-param-reassign
+ root.d3.tip = factory(d3, d3)
+ }
+}(this, function(d3Collection, d3Selection) {
+ // Public - contructs a new tooltip
+ //
+ // Returns a tip
+ return function() {
+ var direction = d3TipDirection,
+ offset = d3TipOffset,
+ html = d3TipHTML,
+ rootElement = document.body,
+ node = initNode(),
+ svg = null,
+ point = null,
+ target = null
+
+ function tip(vis) {
+ svg = getSVGNode(vis)
+ if (!svg) return
+ point = svg.createSVGPoint()
+ rootElement.appendChild(node)
+ }
+
+ // Public - show the tooltip on the screen
+ //
+ // Returns a tip
+ tip.show = function() {
+ var args = Array.prototype.slice.call(arguments)
+ if (args[args.length - 1] instanceof SVGElement) target = args.pop()
+
+ var content = html.apply(this, args),
+ poffset = offset.apply(this, args),
+ dir = direction.apply(this, args),
+ nodel = getNodeEl(),
+ i = directions.length,
+ coords,
+ scrollTop = document.documentElement.scrollTop ||
+ rootElement.scrollTop,
+ scrollLeft = document.documentElement.scrollLeft ||
+ rootElement.scrollLeft
+
+ nodel.html(content)
+ .style('opacity', 1).style('pointer-events', 'all')
+
+ while (i--) nodel.classed(directions[i], false)
+ coords = directionCallbacks.get(dir).apply(this)
+ nodel.classed(dir, true)
+ .style('top', (coords.top + poffset[0]) + scrollTop + 'px')
+ .style('left', (coords.left + poffset[1]) + scrollLeft + 'px')
+
+ return tip
+ }
+
+ // Public - hide the tooltip
+ //
+ // Returns a tip
+ tip.hide = function() {
+ var nodel = getNodeEl()
+ nodel.style('opacity', 0).style('pointer-events', 'none')
+ return tip
+ }
+
+ // Public: Proxy attr calls to the d3 tip container.
+ // Sets or gets attribute value.
+ //
+ // n - name of the attribute
+ // v - value of the attribute
+ //
+ // Returns tip or attribute value
+ // eslint-disable-next-line no-unused-vars
+ tip.attr = function(n, v) {
+ if (arguments.length < 2 && typeof n === 'string') {
+ return getNodeEl().attr(n)
+ }
+
+ var args = Array.prototype.slice.call(arguments)
+ d3Selection.selection.prototype.attr.apply(getNodeEl(), args)
+ return tip
+ }
+
+ // Public: Proxy style calls to the d3 tip container.
+ // Sets or gets a style value.
+ //
+ // n - name of the property
+ // v - value of the property
+ //
+ // Returns tip or style property value
+ // eslint-disable-next-line no-unused-vars
+ tip.style = function(n, v) {
+ if (arguments.length < 2 && typeof n === 'string') {
+ return getNodeEl().style(n)
+ }
+
+ var args = Array.prototype.slice.call(arguments)
+ d3Selection.selection.prototype.style.apply(getNodeEl(), args)
+ return tip
+ }
+
+ // Public: Set or get the direction of the tooltip
+ //
+ // v - One of n(north), s(south), e(east), or w(west), nw(northwest),
+ // sw(southwest), ne(northeast) or se(southeast)
+ //
+ // Returns tip or direction
+ tip.direction = function(v) {
+ if (!arguments.length) return direction
+ direction = v == null ? v : functor(v)
+
+ return tip
+ }
+
+ // Public: Sets or gets the offset of the tip
+ //
+ // v - Array of [x, y] offset
+ //
+ // Returns offset or
+ tip.offset = function(v) {
+ if (!arguments.length) return offset
+ offset = v == null ? v : functor(v)
+
+ return tip
+ }
+
+ // Public: sets or gets the html value of the tooltip
+ //
+ // v - String value of the tip
+ //
+ // Returns html value or tip
+ tip.html = function(v) {
+ if (!arguments.length) return html
+ html = v == null ? v : functor(v)
+
+ return tip
+ }
+
+ // Public: sets or gets the root element anchor of the tooltip
+ //
+ // v - root element of the tooltip
+ //
+ // Returns root node of tip
+ tip.rootElement = function(v) {
+ if (!arguments.length) return rootElement
+ rootElement = v == null ? v : functor(v)
+
+ return tip
+ }
+
+ // Public: destroys the tooltip and removes it from the DOM
+ //
+ // Returns a tip
+ tip.destroy = function() {
+ if (node) {
+ getNodeEl().remove()
+ node = null
+ }
+ return tip
+ }
+
+ function d3TipDirection() { return 'n' }
+ function d3TipOffset() { return [0, 0] }
+ function d3TipHTML() { return ' ' }
+
+ var directionCallbacks = d3Collection.map({
+ n: directionNorth,
+ s: directionSouth,
+ e: directionEast,
+ w: directionWest,
+ nw: directionNorthWest,
+ ne: directionNorthEast,
+ sw: directionSouthWest,
+ se: directionSouthEast
+ }),
+ directions = directionCallbacks.keys()
+
+ function directionNorth() {
+ var bbox = getScreenBBox()
+ return {
+ top: bbox.n.y - node.offsetHeight,
+ left: bbox.n.x - node.offsetWidth / 2
+ }
+ }
+
+ function directionSouth() {
+ var bbox = getScreenBBox()
+ return {
+ top: bbox.s.y,
+ left: bbox.s.x - node.offsetWidth / 2
+ }
+ }
+
+ function directionEast() {
+ var bbox = getScreenBBox()
+ return {
+ top: bbox.e.y - node.offsetHeight / 2,
+ left: bbox.e.x
+ }
+ }
+
+ function directionWest() {
+ var bbox = getScreenBBox()
+ return {
+ top: bbox.w.y - node.offsetHeight / 2,
+ left: bbox.w.x - node.offsetWidth
+ }
+ }
+
+ function directionNorthWest() {
+ var bbox = getScreenBBox()
+ return {
+ top: bbox.nw.y - node.offsetHeight,
+ left: bbox.nw.x - node.offsetWidth
+ }
+ }
+
+ function directionNorthEast() {
+ var bbox = getScreenBBox()
+ return {
+ top: bbox.ne.y - node.offsetHeight,
+ left: bbox.ne.x
+ }
+ }
+
+ function directionSouthWest() {
+ var bbox = getScreenBBox()
+ return {
+ top: bbox.sw.y,
+ left: bbox.sw.x - node.offsetWidth
+ }
+ }
+
+ function directionSouthEast() {
+ var bbox = getScreenBBox()
+ return {
+ top: bbox.se.y,
+ left: bbox.se.x
+ }
+ }
+
+ function initNode() {
+ var div = d3Selection.select(document.createElement('div'))
+ div
+ .style('position', 'absolute')
+ .style('top', 0)
+ .style('opacity', 0)
+ .style('pointer-events', 'none')
+ .style('box-sizing', 'border-box')
+
+ return div.node()
+ }
+
+ function getSVGNode(element) {
+ var svgNode = element.node()
+ if (!svgNode) return null
+ if (svgNode.tagName.toLowerCase() === 'svg') return svgNode
+ return svgNode.ownerSVGElement
+ }
+
+ function getNodeEl() {
+ if (node == null) {
+ node = initNode()
+ // re-add node to DOM
+ rootElement.appendChild(node)
+ }
+ return d3Selection.select(node)
+ }
+
+ // Private - gets the screen coordinates of a shape
+ //
+ // Given a shape on the screen, will return an SVGPoint for the directions
+ // n(north), s(south), e(east), w(west), ne(northeast), se(southeast),
+ // nw(northwest), sw(southwest).
+ //
+ // +-+-+
+ // | |
+ // + +
+ // | |
+ // +-+-+
+ //
+ // Returns an Object {n, s, e, w, nw, sw, ne, se}
+ function getScreenBBox() {
+ var targetel = target || d3Selection.event.target
+
+ while (targetel.getScreenCTM == null && targetel.parentNode == null) {
+ targetel = targetel.parentNode
+ }
+
+ var bbox = {},
+ matrix = targetel.getScreenCTM(),
+ tbbox = targetel.getBBox(),
+ width = tbbox.width,
+ height = tbbox.height,
+ x = tbbox.x,
+ y = tbbox.y
+
+ point.x = x
+ point.y = y
+ bbox.nw = point.matrixTransform(matrix)
+ point.x += width
+ bbox.ne = point.matrixTransform(matrix)
+ point.y += height
+ bbox.se = point.matrixTransform(matrix)
+ point.x -= width
+ bbox.sw = point.matrixTransform(matrix)
+ point.y -= height / 2
+ bbox.w = point.matrixTransform(matrix)
+ point.x += width
+ bbox.e = point.matrixTransform(matrix)
+ point.x -= width / 2
+ point.y -= height / 2
+ bbox.n = point.matrixTransform(matrix)
+ point.y += height
+ bbox.s = point.matrixTransform(matrix)
+
+ return bbox
+ }
+
+ // Private - replace D3JS 3.X d3.functor() function
+ function functor(v) {
+ return typeof v === 'function' ? v : function() {
+ return v
+ }
+ }
+
+ return tip
+ }
+// eslint-disable-next-line semi
+}));
diff --git a/library/cpp/lwtrace/mon/static/js/d3.v4.min.js b/library/cpp/lwtrace/mon/static/js/d3.v4.min.js
new file mode 100644
index 0000000000..6a2705865c
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/d3.v4.min.js
@@ -0,0 +1,2 @@
+// https://d3js.org Version 4.10.0. Copyright 2017 Mike Bostock.
+(function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t.d3=t.d3||{})})(this,function(t){"use strict";function n(t){return function(n,e){return ss(t(n),e)}}function e(t,n){return[t,n]}function r(t,n,e){var r=(n-t)/Math.max(0,e),i=Math.floor(Math.log(r)/Math.LN10),o=r/Math.pow(10,i);return i>=0?(o>=Ts?10:o>=ks?5:o>=Ns?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=Ts?10:o>=ks?5:o>=Ns?2:1)}function i(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=Ts?i*=10:o>=ks?i*=5:o>=Ns&&(i*=2),n<t?-i:i}function o(t){return t.length}function u(t){return"translate("+(t+.5)+",0)"}function a(t){return"translate(0,"+(t+.5)+")"}function c(t){return function(n){return+t(n)}}function s(t){var n=Math.max(0,t.bandwidth()-1)/2;return t.round()&&(n=Math.round(n)),function(e){return+t(e)+n}}function f(){return!this.__axis}function l(t,n){function e(e){var u=null==i?n.ticks?n.ticks.apply(n,r):n.domain():i,a=null==o?n.tickFormat?n.tickFormat.apply(n,r):Ls:o,y=Math.max(l,0)+p,g=n.range(),m=+g[0]+.5,x=+g[g.length-1]+.5,b=(n.bandwidth?s:c)(n.copy()),w=e.selection?e.selection():e,M=w.selectAll(".domain").data([null]),T=w.selectAll(".tick").data(u,n).order(),k=T.exit(),N=T.enter().append("g").attr("class","tick"),S=T.select("line"),E=T.select("text");M=M.merge(M.enter().insert("path",".tick").attr("class","domain").attr("stroke","#000")),T=T.merge(N),S=S.merge(N.append("line").attr("stroke","#000").attr(v+"2",d*l)),E=E.merge(N.append("text").attr("fill","#000").attr(v,d*y).attr("dy",t===qs?"0em":t===Ds?"0.71em":"0.32em")),e!==w&&(M=M.transition(e),T=T.transition(e),S=S.transition(e),E=E.transition(e),k=k.transition(e).attr("opacity",Fs).attr("transform",function(t){return isFinite(t=b(t))?_(t):this.getAttribute("transform")}),N.attr("opacity",Fs).attr("transform",function(t){var n=this.parentNode.__axis;return _(n&&isFinite(n=n(t))?n:b(t))})),k.remove(),M.attr("d",t===Os||t==Us?"M"+d*h+","+m+"H0.5V"+x+"H"+d*h:"M"+m+","+d*h+"V0.5H"+x+"V"+d*h),T.attr("opacity",1).attr("transform",function(t){return _(b(t))}),S.attr(v+"2",d*l),E.attr(v,d*y).text(a),w.filter(f).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===Us?"start":t===Os?"end":"middle"),w.each(function(){this.__axis=b})}var r=[],i=null,o=null,l=6,h=6,p=3,d=t===qs||t===Os?-1:1,v=t===Os||t===Us?"x":"y",_=t===qs||t===Ds?u:a;return e.scale=function(t){return arguments.length?(n=t,e):n},e.ticks=function(){return r=Rs.call(arguments),e},e.tickArguments=function(t){return arguments.length?(r=null==t?[]:Rs.call(t),e):r.slice()},e.tickValues=function(t){return arguments.length?(i=null==t?null:Rs.call(t),e):i&&i.slice()},e.tickFormat=function(t){return arguments.length?(o=t,e):o},e.tickSize=function(t){return arguments.length?(l=h=+t,e):l},e.tickSizeInner=function(t){return arguments.length?(l=+t,e):l},e.tickSizeOuter=function(t){return arguments.length?(h=+t,e):h},e.tickPadding=function(t){return arguments.length?(p=+t,e):p},e}function h(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+"")||t in r)throw new Error("illegal type: "+t);r[t]=[]}return new p(r)}function p(t){this._=t}function d(t,n){return t.trim().split(/^|\s+/).map(function(t){var e="",r=t.indexOf(".");if(r>=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}function v(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function _(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=Is,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}function y(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===Ys&&n.documentElement.namespaceURI===Ys?n.createElement(t):n.createElementNS(e,t)}}function g(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function m(){return new x}function x(){this._="@"+(++Xs).toString(36)}function b(t,n,e){return t=w(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function w(n,e,r){return function(i){var o=t.event;t.event=i;try{n.call(this,this.__data__,e,r)}finally{t.event=o}}}function M(t){return t.trim().split(/^|\s+/).map(function(t){var n="",e=t.indexOf(".");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}function T(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.capture);++i?n.length=i:delete this.__on}}}function k(t,n,e){var r=Gs.hasOwnProperty(t.type)?b:w;return function(i,o,u){var a,c=this.__on,s=r(n,o,u);if(c)for(var f=0,l=c.length;f<l;++f)if((a=c[f]).type===t.type&&a.name===t.name)return this.removeEventListener(a.type,a.listener,a.capture),this.addEventListener(a.type,a.listener=s,a.capture=e),void(a.value=n);this.addEventListener(t.type,s,e),a={type:t.type,name:t.name,value:n,listener:s,capture:e},c?c.push(a):this.__on=[a]}}function N(n,e,r,i){var o=t.event;n.sourceEvent=t.event,t.event=n;try{return e.apply(r,i)}finally{t.event=o}}function S(){}function E(){return[]}function A(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function C(t,n,e,r,i,o){for(var u,a=0,c=n.length,s=o.length;a<s;++a)(u=n[a])?(u.__data__=o[a],r[a]=u):e[a]=new A(t,o[a]);for(;a<c;++a)(u=n[a])&&(i[a]=u)}function z(t,n,e,r,i,o,u){var a,c,s,f={},l=n.length,h=o.length,p=new Array(l);for(a=0;a<l;++a)(c=n[a])&&(p[a]=s=of+u.call(c,c.__data__,a,n),s in f?i[a]=c:f[s]=c);for(a=0;a<h;++a)(c=f[s=of+u.call(t,o[a],a,o)])?(r[a]=c,c.__data__=o[a],f[s]=null):e[a]=new A(t,o[a]);for(a=0;a<l;++a)(c=n[a])&&f[p[a]]===c&&(i[a]=c)}function P(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function R(t){return function(){this.removeAttribute(t)}}function L(t){return function(){this.removeAttributeNS(t.space,t.local)}}function q(t,n){return function(){this.setAttribute(t,n)}}function U(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function D(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function O(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function F(t){return function(){this.style.removeProperty(t)}}function I(t,n,e){return function(){this.style.setProperty(t,n,e)}}function Y(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function B(t,n){return t.style.getPropertyValue(n)||uf(t).getComputedStyle(t,null).getPropertyValue(n)}function j(t){return function(){delete this[t]}}function H(t,n){return function(){this[t]=n}}function X(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function $(t){return t.trim().split(/^|\s+/)}function V(t){return t.classList||new W(t)}function W(t){this._node=t,this._names=$(t.getAttribute("class")||"")}function Z(t,n){for(var e=V(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function G(t,n){for(var e=V(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function J(t){return function(){Z(this,t)}}function Q(t){return function(){G(this,t)}}function K(t,n){return function(){(n.apply(this,arguments)?Z:G)(this,t)}}function tt(){this.textContent=""}function nt(t){return function(){this.textContent=t}}function et(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}}function rt(){this.innerHTML=""}function it(t){return function(){this.innerHTML=t}}function ot(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}}function ut(){this.nextSibling&&this.parentNode.appendChild(this)}function at(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function ct(){return null}function st(){var t=this.parentNode;t&&t.removeChild(this)}function ft(t,n,e){var r=uf(t),i=r.CustomEvent;"function"==typeof i?i=new i(n,e):(i=r.document.createEvent("Event"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}function lt(t,n){return function(){return ft(this,t,n)}}function ht(t,n){return function(){return ft(this,t,n.apply(this,arguments))}}function pt(t,n){this._groups=t,this._parents=n}function dt(){return new pt([[document.documentElement]],af)}function vt(){t.event.stopImmediatePropagation()}function _t(t,n){var e=t.document.documentElement,r=cf(t).on("dragstart.drag",null);n&&(r.on("click.drag",ff,!0),setTimeout(function(){r.on("click.drag",null)},0)),"onselectstart"in e?r.on("selectstart.drag",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}function yt(t,n,e,r,i,o,u,a,c,s){this.target=t,this.type=n,this.subject=e,this.identifier=r,this.active=i,this.x=o,this.y=u,this.dx=a,this.dy=c,this._=s}function gt(){return!t.event.button}function mt(){return this.parentNode}function xt(n){return null==n?{x:t.event.x,y:t.event.y}:n}function bt(){return"ontouchstart"in this}function wt(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function Mt(){}function Tt(t){var n;return t=(t+"").trim().toLowerCase(),(n=yf.exec(t))?(n=parseInt(n[1],16),new At(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1)):(n=gf.exec(t))?kt(parseInt(n[1],16)):(n=mf.exec(t))?new At(n[1],n[2],n[3],1):(n=xf.exec(t))?new At(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=bf.exec(t))?Nt(n[1],n[2],n[3],n[4]):(n=wf.exec(t))?Nt(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Mf.exec(t))?Ct(n[1],n[2]/100,n[3]/100,1):(n=Tf.exec(t))?Ct(n[1],n[2]/100,n[3]/100,n[4]):kf.hasOwnProperty(t)?kt(kf[t]):"transparent"===t?new At(NaN,NaN,NaN,0):null}function kt(t){return new At(t>>16&255,t>>8&255,255&t,1)}function Nt(t,n,e,r){return r<=0&&(t=n=e=NaN),new At(t,n,e,r)}function St(t){return t instanceof Mt||(t=Tt(t)),t?(t=t.rgb(),new At(t.r,t.g,t.b,t.opacity)):new At}function Et(t,n,e,r){return 1===arguments.length?St(t):new At(t,n,e,null==r?1:r)}function At(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Ct(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new Rt(t,n,e,r)}function zt(t){if(t instanceof Rt)return new Rt(t.h,t.s,t.l,t.opacity);if(t instanceof Mt||(t=Tt(t)),!t)return new Rt;if(t instanceof Rt)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e<r):e===o?(r-n)/a+2:(n-e)/a+4,a/=c<.5?o+i:2-o-i,u*=60):a=c>0&&c<1?0:u,new Rt(u,a,c,t.opacity)}function Pt(t,n,e,r){return 1===arguments.length?zt(t):new Rt(t,n,e,null==r?1:r)}function Rt(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Lt(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}function qt(t){if(t instanceof Dt)return new Dt(t.l,t.a,t.b,t.opacity);if(t instanceof Ht){var n=t.h*Nf;return new Dt(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}t instanceof At||(t=St(t));var e=Yt(t.r),r=Yt(t.g),i=Yt(t.b),o=Ot((.4124564*e+.3575761*r+.1804375*i)/Ef),u=Ot((.2126729*e+.7151522*r+.072175*i)/Af);return new Dt(116*u-16,500*(o-u),200*(u-Ot((.0193339*e+.119192*r+.9503041*i)/Cf)),t.opacity)}function Ut(t,n,e,r){return 1===arguments.length?qt(t):new Dt(t,n,e,null==r?1:r)}function Dt(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function Ot(t){return t>Lf?Math.pow(t,1/3):t/Rf+zf}function Ft(t){return t>Pf?t*t*t:Rf*(t-zf)}function It(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function Yt(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function Bt(t){if(t instanceof Ht)return new Ht(t.h,t.c,t.l,t.opacity);t instanceof Dt||(t=qt(t));var n=Math.atan2(t.b,t.a)*Sf;return new Ht(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function jt(t,n,e,r){return 1===arguments.length?Bt(t):new Ht(t,n,e,null==r?1:r)}function Ht(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}function Xt(t){if(t instanceof Vt)return new Vt(t.h,t.s,t.l,t.opacity);t instanceof At||(t=St(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(Bf*r+If*n-Yf*e)/(Bf+If-Yf),o=r-i,u=(Ff*(e-i)-Df*o)/Of,a=Math.sqrt(u*u+o*o)/(Ff*i*(1-i)),c=a?Math.atan2(u,o)*Sf-120:NaN;return new Vt(c<0?c+360:c,a,i,t.opacity)}function $t(t,n,e,r){return 1===arguments.length?Xt(t):new Vt(t,n,e,null==r?1:r)}function Vt(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Wt(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}function Zt(t,n){return function(e){return t+e*n}}function Gt(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}function Jt(t,n){var e=n-t;return e?Zt(t,e>180||e<-180?e-360*Math.round(e/360):e):Jf(isNaN(t)?n:t)}function Qt(t){return 1==(t=+t)?Kt:function(n,e){return e-n?Gt(n,e,t):Jf(isNaN(n)?e:n)}}function Kt(t,n){var e=n-t;return e?Zt(t,e):Jf(isNaN(t)?n:t)}function tn(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e<i;++e)r=Et(n[e]),o[e]=r.r||0,u[e]=r.g||0,a[e]=r.b||0;return o=t(o),u=t(u),a=t(a),r.opacity=1,function(t){return r.r=o(t),r.g=u(t),r.b=a(t),r+""}}}function nn(t){return function(){return t}}function en(t){return function(n){return t(n)+""}}function rn(t,n,e,r){function i(t){return t.length?t.pop()+" ":""}function o(t,r,i,o,u,a){if(t!==i||r!==o){var c=u.push("translate(",null,n,null,e);a.push({i:c-4,x:rl(t,i)},{i:c-2,x:rl(r,o)})}else(i||o)&&u.push("translate("+i+n+o+e)}function u(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:rl(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}function a(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:rl(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}function c(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:rl(t,e)},{i:a-2,x:rl(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}return function(n,e){var r=[],i=[];return n=t(n),e=t(e),o(n.translateX,n.translateY,e.translateX,e.translateY,r,i),u(n.rotate,e.rotate,r,i),a(n.skewX,e.skewX,r,i),c(n.scaleX,n.scaleY,e.scaleX,e.scaleY,r,i),n=e=null,function(t){for(var n,e=-1,o=i.length;++e<o;)r[(n=i[e]).i]=n.x(t);return r.join("")}}}function on(t){return((t=Math.exp(t))+1/t)/2}function un(t){return((t=Math.exp(t))-1/t)/2}function an(t){return((t=Math.exp(2*t))-1)/(t+1)}function cn(t){return function(n,e){var r=t((n=Pt(n)).h,(e=Pt(e)).h),i=Kt(n.s,e.s),o=Kt(n.l,e.l),u=Kt(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=u(t),n+""}}}function sn(t){return function(n,e){var r=t((n=jt(n)).h,(e=jt(e)).h),i=Kt(n.c,e.c),o=Kt(n.l,e.l),u=Kt(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=u(t),n+""}}}function fn(t){return function n(e){function r(n,r){var i=t((n=$t(n)).h,(r=$t(r)).h),o=Kt(n.s,r.s),u=Kt(n.l,r.l),a=Kt(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=u(Math.pow(t,e)),n.opacity=a(t),n+""}}return e=+e,r.gamma=n,r}(1)}function ln(){return El||(zl(hn),El=Cl.now()+Al)}function hn(){El=0}function pn(){this._call=this._time=this._next=null}function dn(t,n,e){var r=new pn;return r.restart(t,n,e),r}function vn(){ln(),++Ml;for(var t,n=Vf;n;)(t=El-n._time)>=0&&n._call.call(null,t),n=n._next;--Ml}function _n(){El=(Sl=Cl.now())+Al,Ml=Tl=0;try{vn()}finally{Ml=0,gn(),El=0}}function yn(){var t=Cl.now(),n=t-Sl;n>Nl&&(Al-=n,Sl=t)}function gn(){for(var t,n,e=Vf,r=1/0;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Vf=n);Wf=t,mn(r)}function mn(t){if(!Ml){Tl&&(Tl=clearTimeout(Tl));var n=t-El;n>24?(t<1/0&&(Tl=setTimeout(_n,n)),kl&&(kl=clearInterval(kl))):(kl||(Sl=El,kl=setInterval(yn,Nl)),Ml=1,zl(_n))}}function xn(t,n){var e=t.__transition;if(!e||!(e=e[n])||e.state>ql)throw new Error("too late");return e}function bn(t,n){var e=t.__transition;if(!e||!(e=e[n])||e.state>Dl)throw new Error("too late");return e}function wn(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("too late");return e}function Mn(t,n,e){function r(c){var s,f,l,h;if(e.state!==Ul)return o();for(s in a)if((h=a[s]).name===e.name){if(h.state===Ol)return Pl(r);h.state===Fl?(h.state=Yl,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete a[s]):+s<n&&(h.state=Yl,h.timer.stop(),delete a[s])}if(Pl(function(){e.state===Ol&&(e.state=Fl,e.timer.restart(i,e.delay,e.time),i(c))}),e.state=Dl,e.on.call("start",t,t.__data__,e.index,e.group),e.state===Dl){for(e.state=Ol,u=new Array(l=e.tween.length),s=0,f=-1;s<l;++s)(h=e.tween[s].value.call(t,t.__data__,e.index,e.group))&&(u[++f]=h);u.length=f+1}}function i(n){for(var r=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(o),e.state=Il,1),i=-1,a=u.length;++i<a;)u[i].call(null,r);e.state===Il&&(e.on.call("end",t,t.__data__,e.index,e.group),o())}function o(){e.state=Yl,e.timer.stop(),delete a[n];for(var r in a)return;delete t.__transition}var u,a=t.__transition;a[n]=e,e.timer=dn(function(t){e.state=Ul,e.timer.restart(r,e.delay,e.time),e.delay<=t&&r(t-e.delay)},0,e.time)}function Tn(t,n){var e,r;return function(){var i=bn(this,t),o=i.tween;if(o!==e)for(var u=0,a=(r=e=o).length;u<a;++u)if(r[u].name===n){(r=r.slice()).splice(u,1);break}i.tween=r}}function kn(t,n,e){var r,i;if("function"!=typeof e)throw new Error;return function(){var o=bn(this,t),u=o.tween;if(u!==r){i=(r=u).slice();for(var a={name:n,value:e},c=0,s=i.length;c<s;++c)if(i[c].name===n){i[c]=a;break}c===s&&i.push(a)}o.tween=i}}function Nn(t,n,e){var r=t._id;return t.each(function(){var t=bn(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)}),function(t){return wn(t,r).value[n]}}function Sn(t){return function(){this.removeAttribute(t)}}function En(t){return function(){this.removeAttributeNS(t.space,t.local)}}function An(t,n,e){var r,i;return function(){var o=this.getAttribute(t);return o===e?null:o===r?i:i=n(r=o,e)}}function Cn(t,n,e){var r,i;return function(){var o=this.getAttributeNS(t.space,t.local);return o===e?null:o===r?i:i=n(r=o,e)}}function zn(t,n,e){var r,i,o;return function(){var u,a=e(this);{if(null!=a)return(u=this.getAttribute(t))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttribute(t)}}}function Pn(t,n,e){var r,i,o;return function(){var u,a=e(this);{if(null!=a)return(u=this.getAttributeNS(t.space,t.local))===a?null:u===r&&a===i?o:o=n(r=u,i=a);this.removeAttributeNS(t.space,t.local)}}}function Rn(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttributeNS(t.space,t.local,r(n))}}return e._value=n,e}function Ln(t,n){function e(){var e=this,r=n.apply(e,arguments);return r&&function(n){e.setAttribute(t,r(n))}}return e._value=n,e}function qn(t,n){return function(){xn(this,t).delay=+n.apply(this,arguments)}}function Un(t,n){return n=+n,function(){xn(this,t).delay=n}}function Dn(t,n){return function(){bn(this,t).duration=+n.apply(this,arguments)}}function On(t,n){return n=+n,function(){bn(this,t).duration=n}}function Fn(t,n){if("function"!=typeof n)throw new Error;return function(){bn(this,t).ease=n}}function In(t){return(t+"").trim().split(/^|\s+/).every(function(t){var n=t.indexOf(".");return n>=0&&(t=t.slice(0,n)),!t||"start"===t})}function Yn(t,n,e){var r,i,o=In(n)?xn:bn;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}function Bn(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}function jn(t,n){var e,r,i;return function(){var o=B(this,t),u=(this.style.removeProperty(t),B(this,t));return o===u?null:o===e&&u===r?i:i=n(e=o,r=u)}}function Hn(t){return function(){this.style.removeProperty(t)}}function Xn(t,n,e){var r,i;return function(){var o=B(this,t);return o===e?null:o===r?i:i=n(r=o,e)}}function $n(t,n,e){var r,i,o;return function(){var u=B(this,t),a=e(this);return null==a&&(this.style.removeProperty(t),a=B(this,t)),u===a?null:u===r&&a===i?o:o=n(r=u,i=a)}}function Vn(t,n,e){function r(){var r=this,i=n.apply(r,arguments);return i&&function(n){r.style.setProperty(t,i(n),e)}}return r._value=n,r}function Wn(t){return function(){this.textContent=t}}function Zn(t){return function(){var n=t(this);this.textContent=null==n?"":n}}function Gn(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function Jn(t){return dt().transition(t)}function Qn(){return++$l}function Kn(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function te(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}function ne(t){return(1-Math.cos(Jl*t))/2}function ee(t){return((t*=2)<=1?Math.pow(2,10*t-10):2-Math.pow(2,10-10*t))/2}function re(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}function ie(t){return(t=+t)<Kl?ch*t*t:t<nh?ch*(t-=th)*t+eh:t<ih?ch*(t-=rh)*t+oh:ch*(t-=uh)*t+ah}function oe(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))return _h.time=ln(),_h;return e}function ue(){t.event.stopImmediatePropagation()}function ae(t){return{type:t}}function ce(){return!t.event.button}function se(){var t=this.ownerSVGElement||this;return[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function fe(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function le(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function he(n){function e(t){var e=t.property("__brush",a).selectAll(".overlay").data([ae("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",Eh.overlay).merge(e).each(function(){var t=fe(this).extent;cf(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])}),t.selectAll(".selection").data([ae("selection")]).enter().append("rect").attr("class","selection").attr("cursor",Eh.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var i=t.selectAll(".handle").data(n.handles,function(t){return t.type});i.exit().remove(),i.enter().append("rect").attr("class",function(t){return"handle handle--"+t.type}).attr("cursor",function(t){return Eh[t.type]}),t.each(r).attr("fill","none").attr("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush touchstart.brush",u)}function r(){var t=cf(this),n=fe(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",function(t){return"e"===t.type[t.type.length-1]?n[1][0]-p/2:n[0][0]-p/2}).attr("y",function(t){return"s"===t.type[0]?n[1][1]-p/2:n[0][1]-p/2}).attr("width",function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+p:p}).attr("height",function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+p:p})):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function i(t,n){return t.__brush.emitter||new o(t,n)}function o(t,n){this.that=t,this.args=n,this.state=t.__brush,this.active=0}function u(){function e(){var t=Ks(w);!L||x||b||(Math.abs(t[0]-U[0])>Math.abs(t[1]-U[1])?b=!0:x=!0),U=t,m=!0,xh(),o()}function o(){var t;switch(y=U[0]-q[0],g=U[1]-q[1],T){case wh:case bh:k&&(y=Math.max(C-a,Math.min(P-p,y)),s=a+y,d=p+y),N&&(g=Math.max(z-l,Math.min(R-v,g)),h=l+g,_=v+g);break;case Mh:k<0?(y=Math.max(C-a,Math.min(P-a,y)),s=a+y,d=p):k>0&&(y=Math.max(C-p,Math.min(P-p,y)),s=a,d=p+y),N<0?(g=Math.max(z-l,Math.min(R-l,g)),h=l+g,_=v):N>0&&(g=Math.max(z-v,Math.min(R-v,g)),h=l,_=v+g);break;case Th:k&&(s=Math.max(C,Math.min(P,a-y*k)),d=Math.max(C,Math.min(P,p+y*k))),N&&(h=Math.max(z,Math.min(R,l-g*N)),_=Math.max(z,Math.min(R,v+g*N)))}d<s&&(k*=-1,t=a,a=p,p=t,t=s,s=d,d=t,M in Ah&&F.attr("cursor",Eh[M=Ah[M]])),_<h&&(N*=-1,t=l,l=v,v=t,t=h,h=_,_=t,M in Ch&&F.attr("cursor",Eh[M=Ch[M]])),S.selection&&(A=S.selection),x&&(s=A[0][0],d=A[1][0]),b&&(h=A[0][1],_=A[1][1]),A[0][0]===s&&A[0][1]===h&&A[1][0]===d&&A[1][1]===_||(S.selection=[[s,h],[d,_]],r.call(w),D.brush())}function u(){if(ue(),t.event.touches){if(t.event.touches.length)return;c&&clearTimeout(c),c=setTimeout(function(){c=null},500),O.on("touchmove.brush touchend.brush touchcancel.brush",null)}else _t(t.event.view,m),I.on("keydown.brush keyup.brush mousemove.brush mouseup.brush",null);O.attr("pointer-events","all"),F.attr("cursor",Eh.overlay),S.selection&&(A=S.selection),le(A)&&(S.selection=null,r.call(w)),D.end()}if(t.event.touches){if(t.event.changedTouches.length<t.event.touches.length)return xh()}else if(c)return;if(f.apply(this,arguments)){var a,s,l,h,p,d,v,_,y,g,m,x,b,w=this,M=t.event.target.__data__.type,T="selection"===(t.event.metaKey?M="overlay":M)?bh:t.event.altKey?Th:Mh,k=n===Nh?null:zh[M],N=n===kh?null:Ph[M],S=fe(w),E=S.extent,A=S.selection,C=E[0][0],z=E[0][1],P=E[1][0],R=E[1][1],L=k&&N&&t.event.shiftKey,q=Ks(w),U=q,D=i(w,arguments).beforestart();"overlay"===M?S.selection=A=[[a=n===Nh?C:q[0],l=n===kh?z:q[1]],[p=n===Nh?P:a,v=n===kh?R:l]]:(a=A[0][0],l=A[0][1],p=A[1][0],v=A[1][1]),s=a,h=l,d=p,_=v;var O=cf(w).attr("pointer-events","none"),F=O.selectAll(".overlay").attr("cursor",Eh[M]);if(t.event.touches)O.on("touchmove.brush",e,!0).on("touchend.brush touchcancel.brush",u,!0);else{var I=cf(t.event.view).on("keydown.brush",function(){switch(t.event.keyCode){case 16:L=k&&N;break;case 18:T===Mh&&(k&&(p=d-y*k,a=s+y*k),N&&(v=_-g*N,l=h+g*N),T=Th,o());break;case 32:T!==Mh&&T!==Th||(k<0?p=d-y:k>0&&(a=s-y),N<0?v=_-g:N>0&&(l=h-g),T=wh,F.attr("cursor",Eh.selection),o());break;default:return}xh()},!0).on("keyup.brush",function(){switch(t.event.keyCode){case 16:L&&(x=b=L=!1,o());break;case 18:T===Th&&(k<0?p=d:k>0&&(a=s),N<0?v=_:N>0&&(l=h),T=Mh,o());break;case 32:T===wh&&(t.event.altKey?(k&&(p=d-y*k,a=s+y*k),N&&(v=_-g*N,l=h+g*N),T=Th):(k<0?p=d:k>0&&(a=s),N<0?v=_:N>0&&(l=h),T=Mh),F.attr("cursor",Eh[M]),o());break;default:return}xh()},!0).on("mousemove.brush",e,!0).on("mouseup.brush",u,!0);lf(t.event.view)}ue(),jl(w),r.call(w),D.start()}}function a(){var t=this.__brush||{selection:null};return t.extent=s.apply(this,arguments),t.dim=n,t}var c,s=se,f=ce,l=h(e,"start","brush","end"),p=6;return e.move=function(t,e){t.selection?t.on("start.brush",function(){i(this,arguments).beforestart().start()}).on("interrupt.brush end.brush",function(){i(this,arguments).end()}).tween("brush",function(){function t(t){u.selection=1===t&&le(s)?null:f(t),r.call(o),a.brush()}var o=this,u=o.__brush,a=i(o,arguments),c=u.selection,s=n.input("function"==typeof e?e.apply(this,arguments):e,u.extent),f=cl(c,s);return c&&s?t:t(1)}):t.each(function(){var t=this,o=arguments,u=t.__brush,a=n.input("function"==typeof e?e.apply(t,o):e,u.extent),c=i(t,o).beforestart();jl(t),u.selection=null==a||le(a)?null:a,r.call(t),c.start().brush().end()})},o.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting&&(this.starting=!1,this.emit("start")),this},brush:function(){return this.emit("brush"),this},end:function(){return 0==--this.active&&(delete this.state.emitter,this.emit("end")),this},emit:function(t){N(new mh(e,t,n.output(this.state.selection)),l.apply,l,[t,this.that,this.args])}},e.extent=function(t){return arguments.length?(s="function"==typeof t?t:gh([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),e):s},e.filter=function(t){return arguments.length?(f="function"==typeof t?t:gh(!!t),e):f},e.handleSize=function(t){return arguments.length?(p=+t,e):p},e.on=function(){var t=l.on.apply(l,arguments);return t===l?e:t},e}function pe(t){return function(n,e){return t(n.source.value+n.target.value,e.source.value+e.target.value)}}function de(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function ve(){return new de}function _e(t){return t.source}function ye(t){return t.target}function ge(t){return t.radius}function me(t){return t.startAngle}function xe(t){return t.endAngle}function be(){}function we(t,n){var e=new be;if(t instanceof be)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(null==n)for(;++i<o;)e.set(i,t[i]);else for(;++i<o;)e.set(n(r=t[i],i,t),r)}else if(t)for(var u in t)e.set(u,t[u]);return e}function Me(){return{}}function Te(t,n,e){t[n]=e}function ke(){return we()}function Ne(t,n,e){t.set(n,e)}function Se(){}function Ee(t,n){var e=new Se;if(t instanceof Se)t.each(function(t){e.add(t)});else if(t){var r=-1,i=t.length;if(null==n)for(;++r<i;)e.add(t[r]);else for(;++r<i;)e.add(n(t[r],r,t))}return e}function Ae(t){return new Function("d","return {"+t.map(function(t,n){return JSON.stringify(t)+": d["+n+"]"}).join(",")+"}")}function Ce(t,n){var e=Ae(t);return function(r,i){return n(e(r),i,t)}}function ze(t){var n=Object.create(null),e=[];return t.forEach(function(t){for(var r in t)r in n||e.push(n[r]=r)}),e}function Pe(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,u,a,c,s,f,l,h,p=t._root,d={data:r},v=t._x0,_=t._y0,y=t._x1,g=t._y1;if(!p)return t._root=d,t;for(;p.length;)if((s=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(_+g)/2))?_=u:g=u,i=p,!(p=p[l=f<<1|s]))return i[l]=d,t;if(a=+t._x.call(null,p.data),c=+t._y.call(null,p.data),n===a&&e===c)return d.next=p,i?i[l]=d:t._root=d,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(s=n>=(o=(v+y)/2))?v=o:y=o,(f=e>=(u=(_+g)/2))?_=u:g=u}while((l=f<<1|s)==(h=(c>=u)<<1|a>=o));return i[h]=p,i[l]=d,t}function Re(t){return t[0]}function Le(t){return t[1]}function qe(t,n,e){var r=new Ue(null==n?Re:n,null==e?Le:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Ue(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function De(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}function Oe(t){return t.x+t.vx}function Fe(t){return t.y+t.vy}function Ie(t){return t.index}function Ye(t,n){var e=t.get(n);if(!e)throw new Error("missing: "+n);return e}function Be(t){return t.x}function je(t){return t.y}function He(t){return new Xe(t)}function Xe(t){if(!(n=vp.exec(t)))throw new Error("invalid format: "+t);var n,e=n[1]||" ",r=n[2]||">",i=n[3]||"-",o=n[4]||"",u=!!n[5],a=n[6]&&+n[6],c=!!n[7],s=n[8]&&+n[8].slice(1),f=n[9]||"";"n"===f?(c=!0,f="g"):dp[f]||(f=""),(u||"0"===e&&"="===r)&&(u=!0,e="0",r="="),this.fill=e,this.align=r,this.sign=i,this.symbol=o,this.zero=u,this.width=a,this.comma=c,this.precision=s,this.type=f}function $e(n){return _p=mp(n),t.format=_p.format,t.formatPrefix=_p.formatPrefix,_p}function Ve(){this.reset()}function We(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}function Ze(t){return t>1?0:t<-1?rd:Math.acos(t)}function Ge(t){return t>1?id:t<-1?-id:Math.asin(t)}function Je(t){return(t=yd(t/2))*t}function Qe(){}function Ke(t,n){t&&wd.hasOwnProperty(t.type)&&wd[t.type](t,n)}function tr(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function nr(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)tr(t[e],n,1);n.polygonEnd()}function er(){Nd.point=ir}function rr(){or(Tp,kp)}function ir(t,n){Nd.point=or,Tp=t,kp=n,Np=t*=cd,Sp=hd(n=(n*=cd)/2+od),Ep=yd(n)}function or(t,n){n=(n*=cd)/2+od;var e=(t*=cd)-Np,r=e>=0?1:-1,i=r*e,o=hd(n),u=yd(n),a=Ep*u,c=Sp*o+a*hd(i),s=a*r*yd(i);Td.add(ld(s,c)),Np=t,Sp=o,Ep=u}function ur(t){return[ld(t[1],t[0]),Ge(t[2])]}function ar(t){var n=t[0],e=t[1],r=hd(e);return[r*hd(n),r*yd(n),yd(e)]}function cr(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function sr(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function fr(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function lr(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function hr(t){var n=md(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}function pr(t,n){Dp.push(Op=[Ap=t,zp=t]),n<Cp&&(Cp=n),n>Pp&&(Pp=n)}function dr(t,n){var e=ar([t*cd,n*cd]);if(Up){var r=sr(Up,e),i=sr([r[1],-r[0],0],r);hr(i),i=ur(i);var o,u=t-Rp,a=u>0?1:-1,c=i[0]*ad*a,s=sd(u)>180;s^(a*Rp<c&&c<a*t)?(o=i[1]*ad)>Pp&&(Pp=o):(c=(c+360)%360-180,s^(a*Rp<c&&c<a*t)?(o=-i[1]*ad)<Cp&&(Cp=o):(n<Cp&&(Cp=n),n>Pp&&(Pp=n))),s?t<Rp?xr(Ap,t)>xr(Ap,zp)&&(zp=t):xr(t,zp)>xr(Ap,zp)&&(Ap=t):zp>=Ap?(t<Ap&&(Ap=t),t>zp&&(zp=t)):t>Rp?xr(Ap,t)>xr(Ap,zp)&&(zp=t):xr(t,zp)>xr(Ap,zp)&&(Ap=t)}else Dp.push(Op=[Ap=t,zp=t]);n<Cp&&(Cp=n),n>Pp&&(Pp=n),Up=e,Rp=t}function vr(){Ed.point=dr}function _r(){Op[0]=Ap,Op[1]=zp,Ed.point=pr,Up=null}function yr(t,n){if(Up){var e=t-Rp;Sd.add(sd(e)>180?e+(e>0?360:-360):e)}else Lp=t,qp=n;Nd.point(t,n),dr(t,n)}function gr(){Nd.lineStart()}function mr(){yr(Lp,qp),Nd.lineEnd(),sd(Sd)>ed&&(Ap=-(zp=180)),Op[0]=Ap,Op[1]=zp,Up=null}function xr(t,n){return(n-=t)<0?n+360:n}function br(t,n){return t[0]-n[0]}function wr(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}function Mr(t,n){t*=cd;var e=hd(n*=cd);Tr(e*hd(t),e*yd(t),yd(n))}function Tr(t,n,e){Yp+=(t-Yp)/++Fp,Bp+=(n-Bp)/Fp,jp+=(e-jp)/Fp}function kr(){Ad.point=Nr}function Nr(t,n){t*=cd;var e=hd(n*=cd);Qp=e*hd(t),Kp=e*yd(t),td=yd(n),Ad.point=Sr,Tr(Qp,Kp,td)}function Sr(t,n){t*=cd;var e=hd(n*=cd),r=e*hd(t),i=e*yd(t),o=yd(n),u=ld(md((u=Kp*o-td*i)*u+(u=td*r-Qp*o)*u+(u=Qp*i-Kp*r)*u),Qp*r+Kp*i+td*o);Ip+=u,Hp+=u*(Qp+(Qp=r)),Xp+=u*(Kp+(Kp=i)),$p+=u*(td+(td=o)),Tr(Qp,Kp,td)}function Er(){Ad.point=Mr}function Ar(){Ad.point=zr}function Cr(){Pr(Gp,Jp),Ad.point=Mr}function zr(t,n){Gp=t,Jp=n,t*=cd,n*=cd,Ad.point=Pr;var e=hd(n);Qp=e*hd(t),Kp=e*yd(t),td=yd(n),Tr(Qp,Kp,td)}function Pr(t,n){t*=cd;var e=hd(n*=cd),r=e*hd(t),i=e*yd(t),o=yd(n),u=Kp*o-td*i,a=td*r-Qp*o,c=Qp*i-Kp*r,s=md(u*u+a*a+c*c),f=Ge(s),l=s&&-f/s;Vp+=l*u,Wp+=l*a,Zp+=l*c,Ip+=f,Hp+=f*(Qp+(Qp=r)),Xp+=f*(Kp+(Kp=i)),$p+=f*(td+(td=o)),Tr(Qp,Kp,td)}function Rr(t,n){return[t>rd?t-ud:t<-rd?t+ud:t,n]}function Lr(t,n,e){return(t%=ud)?n||e?zd(Ur(t),Dr(n,e)):Ur(t):n||e?Dr(n,e):Rr}function qr(t){return function(n,e){return n+=t,[n>rd?n-ud:n<-rd?n+ud:n,e]}}function Ur(t){var n=qr(t);return n.invert=qr(-t),n}function Dr(t,n){function e(t,n){var e=hd(n),a=hd(t)*e,c=yd(t)*e,s=yd(n),f=s*r+a*i;return[ld(c*o-f*u,a*r-s*i),Ge(f*o+c*u)]}var r=hd(t),i=yd(t),o=hd(n),u=yd(n);return e.invert=function(t,n){var e=hd(n),a=hd(t)*e,c=yd(t)*e,s=yd(n),f=s*o-c*u;return[ld(c*o+s*u,a*r+f*i),Ge(f*r-a*i)]},e}function Or(t,n,e,r,i,o){if(e){var u=hd(n),a=yd(n),c=r*e;null==i?(i=n+r*ud,o=n-c/2):(i=Fr(u,i),o=Fr(u,o),(r>0?i<o:i>o)&&(i+=r*ud));for(var s,f=i;r>0?f>o:f<o;f-=c)s=ur([u,-a*hd(f),-a*yd(f)]),t.point(s[0],s[1])}}function Fr(t,n){(n=ar(n))[0]-=t,hr(n);var e=Ze(-n[1]);return((-n[2]<0?-e:e)+ud-ed)%ud}function Ir(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Yr(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}function Br(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,a,s){var f=0,l=0;if(null==i||(f=u(i,a))!==(l=u(o,a))||c(i,o)<0^a>0)do{s.point(0===f||3===f?t:e,f>1?r:n)}while((f=(f+a+4)%4)!==l);else s.point(o[0],o[1])}function u(r,i){return sd(r[0]-t)<ed?i>0?0:3:sd(r[0]-e)<ed?i>0?2:1:sd(r[1]-n)<ed?i>0?1:0:i>0?3:2}function a(t,n){return c(t.x,n.x)}function c(t,n){var e=u(t,1),r=u(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(u){function c(t,n){i(t,n)&&w.point(t,n)}function s(){for(var n=0,e=0,i=h.length;e<i;++e)for(var o,u,a=h[e],c=1,s=a.length,f=a[0],l=f[0],p=f[1];c<s;++c)o=l,u=p,l=(f=a[c])[0],p=f[1],u<=r?p>r&&(l-o)*(r-u)>(p-u)*(t-o)&&++n:p<=r&&(l-o)*(r-u)<(p-u)*(t-o)&&--n;return n}function f(o,u){var a=i(o,u);if(h&&p.push([o,u]),x)d=o,v=u,_=a,x=!1,a&&(w.lineStart(),w.point(o,u));else if(a&&m)w.point(o,u);else{var c=[y=Math.max(Zd,Math.min(Wd,y)),g=Math.max(Zd,Math.min(Wd,g))],s=[o=Math.max(Zd,Math.min(Wd,o)),u=Math.max(Zd,Math.min(Wd,u))];Xd(c,s,t,n,e,r)?(m||(w.lineStart(),w.point(c[0],c[1])),w.point(s[0],s[1]),a||w.lineEnd(),b=!1):a&&(w.lineStart(),w.point(o,u),b=!1)}y=o,g=u,m=a}var l,h,p,d,v,_,y,g,m,x,b,w=u,M=Hd(),T={point:c,lineStart:function(){T.point=f,h&&h.push(p=[]),x=!0,m=!1,y=g=NaN},lineEnd:function(){l&&(f(d,v),_&&m&&M.rejoin(),l.push(M.result())),T.point=c,m&&w.lineEnd()},polygonStart:function(){w=M,l=[],h=[],b=!0},polygonEnd:function(){var t=s(),n=b&&t,e=(l=Cs(l)).length;(n||e)&&(u.polygonStart(),n&&(u.lineStart(),o(null,null,1,u),u.lineEnd()),e&&Vd(l,a,t,o,u),u.polygonEnd()),w=u,l=h=p=null}};return T}}function jr(){Kd.point=Kd.lineEnd=Qe}function Hr(t,n){Pd=t*=cd,Rd=yd(n*=cd),Ld=hd(n),Kd.point=Xr}function Xr(t,n){t*=cd;var e=yd(n*=cd),r=hd(n),i=sd(t-Pd),o=hd(i),u=r*yd(i),a=Ld*e-Rd*r*o,c=Rd*e+Ld*r*o;Qd.add(ld(md(u*u+a*a),c)),Pd=t,Rd=e,Ld=r}function $r(t,n){return!(!t||!ov.hasOwnProperty(t.type))&&ov[t.type](t,n)}function Vr(t,n){return 0===rv(t,n)}function Wr(t,n){var e=rv(t[0],t[1]);return rv(t[0],n)+rv(n,t[1])<=e+ed}function Zr(t,n){return!!Jd(t.map(Gr),Jr(n))}function Gr(t){return(t=t.map(Jr)).pop(),t}function Jr(t){return[t[0]*cd,t[1]*cd]}function Qr(t,n,e){var r=Ms(t,n-ed,e).concat(n);return function(t){return r.map(function(n){return[t,n]})}}function Kr(t,n,e){var r=Ms(t,n-ed,e).concat(n);return function(t){return r.map(function(n){return[n,t]})}}function ti(){function t(){return{type:"MultiLineString",coordinates:n()}}function n(){return Ms(pd(o/_)*_,i,_).map(h).concat(Ms(pd(s/y)*y,c,y).map(p)).concat(Ms(pd(r/d)*d,e,d).filter(function(t){return sd(t%_)>ed}).map(f)).concat(Ms(pd(a/v)*v,u,v).filter(function(t){return sd(t%y)>ed}).map(l))}var e,r,i,o,u,a,c,s,f,l,h,p,d=10,v=d,_=90,y=360,g=2.5;return t.lines=function(){return n().map(function(t){return{type:"LineString",coordinates:t}})},t.outline=function(){return{type:"Polygon",coordinates:[h(o).concat(p(c).slice(1),h(i).reverse().slice(1),p(s).reverse().slice(1))]}},t.extent=function(n){return arguments.length?t.extentMajor(n).extentMinor(n):t.extentMinor()},t.extentMajor=function(n){return arguments.length?(o=+n[0][0],i=+n[1][0],s=+n[0][1],c=+n[1][1],o>i&&(n=o,o=i,i=n),s>c&&(n=s,s=c,c=n),t.precision(g)):[[o,s],[i,c]]},t.extentMinor=function(n){return arguments.length?(r=+n[0][0],e=+n[1][0],a=+n[0][1],u=+n[1][1],r>e&&(n=r,r=e,e=n),a>u&&(n=a,a=u,u=n),t.precision(g)):[[r,a],[e,u]]},t.step=function(n){return arguments.length?t.stepMajor(n).stepMinor(n):t.stepMinor()},t.stepMajor=function(n){return arguments.length?(_=+n[0],y=+n[1],t):[_,y]},t.stepMinor=function(n){return arguments.length?(d=+n[0],v=+n[1],t):[d,v]},t.precision=function(n){return arguments.length?(g=+n,f=Qr(a,u,90),l=Kr(r,e,g),h=Qr(s,c,90),p=Kr(o,i,g),t):g},t.extentMajor([[-180,-90+ed],[180,90-ed]]).extentMinor([[-180,-80-ed],[180,80+ed]])}function ni(){sv.point=ei}function ei(t,n){sv.point=ri,qd=Dd=t,Ud=Od=n}function ri(t,n){cv.add(Od*t-Dd*n),Dd=t,Od=n}function ii(){ri(qd,Ud)}function oi(t,n){vv+=t,_v+=n,++yv}function ui(){Tv.point=ai}function ai(t,n){Tv.point=ci,oi(Yd=t,Bd=n)}function ci(t,n){var e=t-Yd,r=n-Bd,i=md(e*e+r*r);gv+=i*(Yd+t)/2,mv+=i*(Bd+n)/2,xv+=i,oi(Yd=t,Bd=n)}function si(){Tv.point=oi}function fi(){Tv.point=hi}function li(){pi(Fd,Id)}function hi(t,n){Tv.point=pi,oi(Fd=Yd=t,Id=Bd=n)}function pi(t,n){var e=t-Yd,r=n-Bd,i=md(e*e+r*r);gv+=i*(Yd+t)/2,mv+=i*(Bd+n)/2,xv+=i,bv+=(i=Bd*t-Yd*n)*(Yd+t),wv+=i*(Bd+n),Mv+=3*i,oi(Yd=t,Bd=n)}function di(t){this._context=t}function vi(t,n){zv.point=_i,Nv=Ev=t,Sv=Av=n}function _i(t,n){Ev-=t,Av-=n,Cv.add(md(Ev*Ev+Av*Av)),Ev=t,Av=n}function yi(){this._string=[]}function gi(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function mi(t){return t.length>1}function xi(t,n){return((t=t.x)[0]<0?t[1]-id-ed:id-t[1])-((n=n.x)[0]<0?n[1]-id-ed:id-n[1])}function bi(t,n,e,r){var i,o,u=yd(t-e);return sd(u)>ed?fd((yd(n)*(o=hd(r))*yd(e)-yd(r)*(i=hd(n))*yd(t))/(i*o*u)):(n+r)/2}function wi(t){return function(n){var e=new Mi;for(var r in t)e[r]=t[r];return e.stream=n,e}}function Mi(){}function Ti(t,n,e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=t.clipExtent&&t.clipExtent();t.scale(150).translate([0,0]),null!=o&&t.clipExtent(null),Md(e,t.stream(dv));var u=dv.result(),a=Math.min(r/(u[1][0]-u[0][0]),i/(u[1][1]-u[0][1])),c=+n[0][0]+(r-a*(u[1][0]+u[0][0]))/2,s=+n[0][1]+(i-a*(u[1][1]+u[0][1]))/2;return null!=o&&t.clipExtent(o),t.scale(150*a).translate([c,s])}function ki(t,n,e){return Ti(t,[[0,0],n],e)}function Ni(t){return wi({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}function Si(t,n){function e(r,i,o,u,a,c,s,f,l,h,p,d,v,_){var y=s-r,g=f-i,m=y*y+g*g;if(m>4*n&&v--){var x=u+h,b=a+p,w=c+d,M=md(x*x+b*b+w*w),T=Ge(w/=M),k=sd(sd(w)-1)<ed||sd(o-l)<ed?(o+l)/2:ld(b,x),N=t(k,T),S=N[0],E=N[1],A=S-r,C=E-i,z=g*A-y*C;(z*z/m>n||sd((y*A+g*C)/m-.5)>.3||u*h+a*p+c*d<Uv)&&(e(r,i,o,u,a,c,S,E,k,x/=M,b/=M,w,v,_),_.point(S,E),e(S,E,k,x,b,w,s,f,l,h,p,d,v,_))}}return function(n){function r(e,r){e=t(e,r),n.point(e[0],e[1])}function i(){y=NaN,w.point=o,n.lineStart()}function o(r,i){var o=ar([r,i]),u=t(r,i);e(y,g,_,m,x,b,y=u[0],g=u[1],_=r,m=o[0],x=o[1],b=o[2],qv,n),n.point(y,g)}function u(){w.point=r,n.lineEnd()}function a(){i(),w.point=c,w.lineEnd=s}function c(t,n){o(f=t,n),l=y,h=g,p=m,d=x,v=b,w.point=o}function s(){e(y,g,_,m,x,b,l,h,f,p,d,v,qv,n),w.lineEnd=u,u()}var f,l,h,p,d,v,_,y,g,m,x,b,w={point:r,lineStart:i,lineEnd:u,polygonStart:function(){n.polygonStart(),w.lineStart=a},polygonEnd:function(){n.polygonEnd(),w.lineStart=i}};return w}}function Ei(t){return Ai(function(){return t})()}function Ai(t){function n(t){return t=f(t[0]*cd,t[1]*cd),[t[0]*_+a,c-t[1]*_]}function e(t){return(t=f.invert((t[0]-a)/_,(c-t[1])/_))&&[t[0]*ad,t[1]*ad]}function r(t,n){return t=u(t,n),[t[0]*_+a,c-t[1]*_]}function i(){f=zd(s=Lr(b,w,M),u);var t=u(m,x);return a=y-t[0]*_,c=g+t[1]*_,o()}function o(){return d=v=null,n}var u,a,c,s,f,l,h,p,d,v,_=150,y=480,g=250,m=0,x=0,b=0,w=0,M=0,T=null,k=Rv,N=null,S=uv,E=.5,A=Dv(r,E);return n.stream=function(t){return d&&v===t?d:d=Ov(k(s,A(S(v=t))))},n.clipAngle=function(t){return arguments.length?(k=+t?Lv(T=t*cd,6*cd):(T=null,Rv),o()):T*ad},n.clipExtent=function(t){return arguments.length?(S=null==t?(N=l=h=p=null,uv):Br(N=+t[0][0],l=+t[0][1],h=+t[1][0],p=+t[1][1]),o()):null==N?null:[[N,l],[h,p]]},n.scale=function(t){return arguments.length?(_=+t,i()):_},n.translate=function(t){return arguments.length?(y=+t[0],g=+t[1],i()):[y,g]},n.center=function(t){return arguments.length?(m=t[0]%360*cd,x=t[1]%360*cd,i()):[m*ad,x*ad]},n.rotate=function(t){return arguments.length?(b=t[0]%360*cd,w=t[1]%360*cd,M=t.length>2?t[2]%360*cd:0,i()):[b*ad,w*ad,M*ad]},n.precision=function(t){return arguments.length?(A=Dv(r,E=t*t),o()):md(E)},n.fitExtent=function(t,e){return Ti(n,t,e)},n.fitSize=function(t,e){return ki(n,t,e)},function(){return u=t.apply(this,arguments),n.invert=u.invert&&e,i()}}function Ci(t){var n=0,e=rd/3,r=Ai(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*cd,e=t[1]*cd):[n*ad,e*ad]},i}function zi(t){function n(t,n){return[t*e,yd(n)/e]}var e=hd(t);return n.invert=function(t,n){return[t/e,Ge(n*e)]},n}function Pi(t,n){function e(t,n){var e=md(o-2*i*yd(n))/i;return[e*yd(t*=i),u-e*hd(t)]}var r=yd(t),i=(r+yd(n))/2;if(sd(i)<ed)return zi(t);var o=1+r*(2*i-r),u=md(o)/i;return e.invert=function(t,n){var e=u-n;return[ld(t,sd(e))/i*gd(e),Ge((o-(t*t+e*e)*i*i)/(2*i))]},e}function Ri(t){var n=t.length;return{point:function(e,r){for(var i=-1;++i<n;)t[i].point(e,r)},sphere:function(){for(var e=-1;++e<n;)t[e].sphere()},lineStart:function(){for(var e=-1;++e<n;)t[e].lineStart()},lineEnd:function(){for(var e=-1;++e<n;)t[e].lineEnd()},polygonStart:function(){for(var e=-1;++e<n;)t[e].polygonStart()},polygonEnd:function(){for(var e=-1;++e<n;)t[e].polygonEnd()}}}function Li(t){return function(n,e){var r=hd(n),i=hd(e),o=t(r*i);return[o*i*yd(n),o*yd(e)]}}function qi(t){return function(n,e){var r=md(n*n+e*e),i=t(r),o=yd(i),u=hd(i);return[ld(n*o,r*u),Ge(r&&e*o/r)]}}function Ui(t,n){return[t,vd(xd((id+n)/2))]}function Di(t){function n(){var n=rd*a(),u=o(jd(o.rotate()).invert([0,0]));return s(null==f?[[u[0]-n,u[1]-n],[u[0]+n,u[1]+n]]:t===Ui?[[Math.max(u[0]-n,f),e],[Math.min(u[0]+n,r),i]]:[[f,Math.max(u[1]-n,e)],[r,Math.min(u[1]+n,i)]])}var e,r,i,o=Ei(t),u=o.center,a=o.scale,c=o.translate,s=o.clipExtent,f=null;return o.scale=function(t){return arguments.length?(a(t),n()):a()},o.translate=function(t){return arguments.length?(c(t),n()):c()},o.center=function(t){return arguments.length?(u(t),n()):u()},o.clipExtent=function(t){return arguments.length?(null==t?f=e=r=i=null:(f=+t[0][0],e=+t[0][1],r=+t[1][0],i=+t[1][1]),n()):null==f?null:[[f,e],[r,i]]},n()}function Oi(t){return xd((id+t)/2)}function Fi(t,n){function e(t,n){o>0?n<-id+ed&&(n=-id+ed):n>id-ed&&(n=id-ed);var e=o/_d(Oi(n),i);return[e*yd(i*t),o-e*hd(i*t)]}var r=hd(t),i=t===n?yd(t):vd(r/hd(n))/vd(Oi(n)/Oi(t)),o=r*_d(Oi(t),i)/i;return i?(e.invert=function(t,n){var e=o-n,r=gd(i)*md(t*t+e*e);return[ld(t,sd(e))/i*gd(e),2*fd(_d(o/r,1/i))-id]},e):Ui}function Ii(t,n){return[t,n]}function Yi(t,n){function e(t,n){var e=o-n,r=i*t;return[e*yd(r),o-e*hd(r)]}var r=hd(t),i=t===n?yd(t):(r-hd(n))/(n-t),o=r/i+t;return sd(i)<ed?Ii:(e.invert=function(t,n){var e=o-n;return[ld(t,sd(e))/i*gd(e),o-gd(i)*md(t*t+e*e)]},e)}function Bi(t,n){var e=hd(n),r=hd(t)*e;return[e*yd(t)/r,yd(n)/r]}function ji(t,n,e,r){return 1===t&&1===n&&0===e&&0===r?uv:wi({point:function(i,o){this.stream.point(i*t+e,o*n+r)}})}function Hi(t,n){return[hd(n)*yd(t),yd(n)]}function Xi(t,n){var e=hd(n),r=1+hd(t)*e;return[e*yd(t)/r,yd(n)/r]}function $i(t,n){return[vd(xd((id+n)/2)),-t]}function Vi(t,n){return t.parent===n.parent?1:2}function Wi(t){return t.reduce(Zi,0)/t.length}function Zi(t,n){return t+n.x}function Gi(t){return 1+t.reduce(Ji,0)}function Ji(t,n){return Math.max(t,n.y)}function Qi(t){for(var n;n=t.children;)t=n[0];return t}function Ki(t){for(var n;n=t.children;)t=n[n.length-1];return t}function to(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function no(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;for(t=e.pop(),n=r.pop();t===n;)i=t,t=e.pop(),n=r.pop();return i}function eo(t,n){var e,r,i,o,u,a=new uo(t),c=+t.value&&(a.value=t.value),s=[a];for(null==n&&(n=ro);e=s.pop();)if(c&&(e.value=+e.data.value),(i=n(e.data))&&(u=i.length))for(e.children=new Array(u),o=u-1;o>=0;--o)s.push(r=e.children[o]=new uo(i[o])),r.parent=e,r.depth=e.depth+1;return a.eachBefore(oo)}function ro(t){return t.children}function io(t){t.data=t.data.data}function oo(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function uo(t){this.data=t,this.depth=this.height=0,this.parent=null}function ao(t){for(var n,e,r=t.length;r;)e=Math.random()*r--|0,n=t[r],t[r]=t[e],t[e]=n;return t}function co(t,n){var e,r;if(lo(n,t))return[n];for(e=0;e<t.length;++e)if(so(n,t[e])&&lo(vo(t[e],n),t))return[t[e],n];for(e=0;e<t.length-1;++e)for(r=e+1;r<t.length;++r)if(so(vo(t[e],t[r]),n)&&so(vo(t[e],n),t[r])&&so(vo(t[r],n),t[e])&&lo(_o(t[e],t[r],n),t))return[t[e],t[r],n];throw new Error}function so(t,n){var e=t.r-n.r,r=n.x-t.x,i=n.y-t.y;return e<0||e*e<r*r+i*i}function fo(t,n){var e=t.r-n.r+1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function lo(t,n){for(var e=0;e<n.length;++e)if(!fo(t,n[e]))return!1;return!0}function ho(t){switch(t.length){case 1:return po(t[0]);case 2:return vo(t[0],t[1]);case 3:return _o(t[0],t[1],t[2])}}function po(t){return{x:t.x,y:t.y,r:t.r}}function vo(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,u=n.y,a=n.r,c=o-e,s=u-r,f=a-i,l=Math.sqrt(c*c+s*s);return{x:(e+o+c/l*f)/2,y:(r+u+s/l*f)/2,r:(l+i+a)/2}}function _o(t,n,e){var r=t.x,i=t.y,o=t.r,u=n.x,a=n.y,c=n.r,s=e.x,f=e.y,l=e.r,h=r-u,p=r-s,d=i-a,v=i-f,_=c-o,y=l-o,g=r*r+i*i-o*o,m=g-u*u-a*a+c*c,x=g-s*s-f*f+l*l,b=p*d-h*v,w=(d*x-v*m)/(2*b)-r,M=(v*_-d*y)/b,T=(p*m-h*x)/(2*b)-i,k=(h*y-p*_)/b,N=M*M+k*k-1,S=2*(o+w*M+T*k),E=w*w+T*T-o*o,A=-(N?(S+Math.sqrt(S*S-4*N*E))/(2*N):E/S);return{x:r+w+M*A,y:i+T+k*A,r:A}}function yo(t,n,e){var r=t.x,i=t.y,o=n.r+e.r,u=t.r+e.r,a=n.x-r,c=n.y-i,s=a*a+c*c;if(s){var f=.5+((u*=u)-(o*=o))/(2*s),l=Math.sqrt(Math.max(0,2*o*(u+s)-(u-=s)*u-o*o))/(2*s);e.x=r+f*a+l*c,e.y=i+f*c-l*a}else e.x=r+u,e.y=i}function go(t,n){var e=n.x-t.x,r=n.y-t.y,i=t.r+n.r;return i*i-1e-6>e*e+r*r}function mo(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function xo(t){this._=t,this.next=null,this.previous=null}function bo(t){if(!(i=t.length))return 0;var n,e,r,i,o,u,a,c,s,f,l;if(n=t[0],n.x=0,n.y=0,!(i>1))return n.r;if(e=t[1],n.x=-e.r,e.x=n.r,e.y=0,!(i>2))return n.r+e.r;yo(e,n,r=t[2]),n=new xo(n),e=new xo(e),r=new xo(r),n.next=r.previous=e,e.next=n.previous=r,r.next=e.previous=n;t:for(a=3;a<i;++a){yo(n._,e._,r=t[a]),r=new xo(r),c=e.next,s=n.previous,f=e._.r,l=n._.r;do{if(f<=l){if(go(c._,r._)){e=c,n.next=e,e.previous=n,--a;continue t}f+=c._.r,c=c.next}else{if(go(s._,r._)){(n=s).next=e,e.previous=n,--a;continue t}l+=s._.r,s=s.previous}}while(c!==s.next);for(r.previous=n,r.next=e,n.next=e.previous=e=r,o=mo(n);(r=r.next)!==e;)(u=mo(r))<o&&(n=r,o=u);e=n.next}for(n=[e._],r=e;(r=r.next)!==e;)n.push(r._);for(r=Hv(n),a=0;a<i;++a)n=t[a],n.x-=r.x,n.y-=r.y;return r.r}function wo(t){return null==t?null:Mo(t)}function Mo(t){if("function"!=typeof t)throw new Error;return t}function To(){return 0}function ko(t){return Math.sqrt(t.value)}function No(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function So(t,n){return function(e){if(r=e.children){var r,i,o,u=r.length,a=t(e)*n||0;if(a)for(i=0;i<u;++i)r[i].r+=a;if(o=bo(r),a)for(i=0;i<u;++i)r[i].r-=a;e.r=o+a}}}function Eo(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function Ao(t){return t.id}function Co(t){return t.parentId}function zo(t,n){return t.parent===n.parent?1:2}function Po(t){var n=t.children;return n?n[0]:t.t}function Ro(t){var n=t.children;return n?n[n.length-1]:t.t}function Lo(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function qo(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}function Uo(t,n,e){return t.a.parent===n.parent?t.a:e}function Do(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function Oo(t){for(var n,e,r,i,o,u=new Do(t,0),a=[u];n=a.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)a.push(e=n.children[i]=new Do(r[i],i)),e.parent=n;return(u.parent=new Do(null,0)).children=[u],u}function Fo(t,n,e,r,i,o){for(var u,a,c,s,f,l,h,p,d,v,_,y=[],g=n.children,m=0,x=0,b=g.length,w=n.value;m<b;){c=i-e,s=o-r;do{f=g[x++].value}while(!f&&x<b);for(l=h=f,_=f*f*(v=Math.max(s/c,c/s)/(w*t)),d=Math.max(h/_,_/l);x<b;++x){if(f+=a=g[x].value,a<l&&(l=a),a>h&&(h=a),_=f*f*v,(p=Math.max(h/_,_/l))>d){f-=a;break}d=p}y.push(u={value:f,dice:c<s,children:g.slice(m,x)}),u.dice?Vv(u,e,r,i,w?r+=s*f/w:o):Jv(u,e,r,w?e+=c*f/w:i,o),w-=f,m=x}return y}function Io(t,n){return t[0]-n[0]||t[1]-n[1]}function Yo(t){for(var n=t.length,e=[0,1],r=2,i=2;i<n;++i){for(;r>1&&n_(t[e[r-2]],t[e[r-1]],t[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function Bo(t){this._size=t,this._call=this._error=null,this._tasks=[],this._data=[],this._waiting=this._active=this._ended=this._start=0}function jo(t){if(!t._start)try{Ho(t)}catch(n){if(t._tasks[t._ended+t._active-1])$o(t,n);else if(!t._data)throw n}}function Ho(t){for(;t._start=t._waiting&&t._active<t._size;){var n=t._ended+t._active,e=t._tasks[n],r=e.length-1,i=e[r];e[r]=Xo(t,n),--t._waiting,++t._active,e=i.apply(null,e),t._tasks[n]&&(t._tasks[n]=e||r_)}}function Xo(t,n){return function(e,r){t._tasks[n]&&(--t._active,++t._ended,t._tasks[n]=null,null==t._error&&(null!=e?$o(t,e):(t._data[n]=r,t._waiting?jo(t):Vo(t))))}}function $o(t,n){var e,r=t._tasks.length;for(t._error=n,t._data=void 0,t._waiting=NaN;--r>=0;)if((e=t._tasks[r])&&(t._tasks[r]=null,e.abort))try{e.abort()}catch(n){}t._active=NaN,Vo(t)}function Vo(t){if(!t._active&&t._call){var n=t._data;t._data=void 0,t._call(t._error,n)}}function Wo(t){if(null==t)t=1/0;else if(!((t=+t)>=1))throw new Error("invalid concurrency");return new Bo(t)}function Zo(t){return function(n,e){t(null==n?e:null)}}function Go(t){var n=t.responseType;return n&&"text"!==n?t.response:t.responseText}function Jo(t,n){return function(e){return t(e.responseText,n)}}function Qo(t){function n(n){var o=n+"",u=e.get(o);if(!u){if(i!==M_)return i;e.set(o,u=r.push(n))}return t[(u-1)%t.length]}var e=we(),r=[],i=M_;return t=null==t?[]:w_.call(t),n.domain=function(t){if(!arguments.length)return r.slice();r=[],e=we();for(var i,o,u=-1,a=t.length;++u<a;)e.has(o=(i=t[u])+"")||e.set(o,r.push(i));return n},n.range=function(e){return arguments.length?(t=w_.call(e),n):t.slice()},n.unknown=function(t){return arguments.length?(i=t,n):i},n.copy=function(){return Qo().domain(r).range(t).unknown(i)},n}function Ko(){function t(){var t=i().length,r=u[1]<u[0],l=u[r-0],h=u[1-r];n=(h-l)/Math.max(1,t-c+2*s),a&&(n=Math.floor(n)),l+=(h-l-n*(t-c))*f,e=n*(1-c),a&&(l=Math.round(l),e=Math.round(e));var p=Ms(t).map(function(t){return l+n*t});return o(r?p.reverse():p)}var n,e,r=Qo().unknown(void 0),i=r.domain,o=r.range,u=[0,1],a=!1,c=0,s=0,f=.5;return delete r.unknown,r.domain=function(n){return arguments.length?(i(n),t()):i()},r.range=function(n){return arguments.length?(u=[+n[0],+n[1]],t()):u.slice()},r.rangeRound=function(n){return u=[+n[0],+n[1]],a=!0,t()},r.bandwidth=function(){return e},r.step=function(){return n},r.round=function(n){return arguments.length?(a=!!n,t()):a},r.padding=function(n){return arguments.length?(c=s=Math.max(0,Math.min(1,n)),t()):c},r.paddingInner=function(n){return arguments.length?(c=Math.max(0,Math.min(1,n)),t()):c},r.paddingOuter=function(n){return arguments.length?(s=Math.max(0,Math.min(1,n)),t()):s},r.align=function(n){return arguments.length?(f=Math.max(0,Math.min(1,n)),t()):f},r.copy=function(){return Ko().domain(i()).range(u).round(a).paddingInner(c).paddingOuter(s).align(f)},t()}function tu(t){var n=t.copy;return t.padding=t.paddingOuter,delete t.paddingInner,delete t.paddingOuter,t.copy=function(){return tu(n())},t}function nu(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:T_(n)}function eu(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=n?0:t>=e?1:r(t)}}}function ru(t){return function(n,e){var r=t(n=+n,e=+e);return function(t){return t<=0?n:t>=1?e:r(t)}}}function iu(t,n,e,r){var i=t[0],o=t[1],u=n[0],a=n[1];return o<i?(i=e(o,i),u=r(a,u)):(i=e(i,o),u=r(u,a)),function(t){return u(i(t))}}function ou(t,n,e,r){var i=Math.min(t.length,n.length)-1,o=new Array(i),u=new Array(i),a=-1;for(t[i]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++a<i;)o[a]=e(t[a],t[a+1]),u[a]=r(n[a],n[a+1]);return function(n){var e=hs(t,n,1,i)-1;return u[e](o[e](n))}}function uu(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp())}function au(t,n){function e(){return i=Math.min(a.length,c.length)>2?ou:iu,o=u=null,r}function r(n){return(o||(o=i(a,c,f?eu(t):t,s)))(+n)}var i,o,u,a=N_,c=N_,s=cl,f=!1;return r.invert=function(t){return(u||(u=i(c,a,nu,f?ru(n):n)))(+t)},r.domain=function(t){return arguments.length?(a=b_.call(t,k_),e()):a.slice()},r.range=function(t){return arguments.length?(c=w_.call(t),e()):c.slice()},r.rangeRound=function(t){return c=w_.call(t),s=sl,e()},r.clamp=function(t){return arguments.length?(f=!!t,e()):f},r.interpolate=function(t){return arguments.length?(s=t,e()):s},e()}function cu(t){var n=t.domain;return t.ticks=function(t){var e=n();return Ss(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){return S_(n(),t,e)},t.nice=function(e){null==e&&(e=10);var i,o=n(),u=0,a=o.length-1,c=o[u],s=o[a];return s<c&&(i=c,c=s,s=i,i=u,u=a,a=i),(i=r(c,s,e))>0?i=r(c=Math.floor(c/i)*i,s=Math.ceil(s/i)*i,e):i<0&&(i=r(c=Math.ceil(c*i)/i,s=Math.floor(s*i)/i,e)),i>0?(o[u]=Math.floor(c/i)*i,o[a]=Math.ceil(s/i)*i,n(o)):i<0&&(o[u]=Math.ceil(c*i)/i,o[a]=Math.floor(s*i)/i,n(o)),t},t}function su(){var t=au(nu,rl);return t.copy=function(){return uu(t,su())},cu(t)}function fu(){function t(t){return+t}var n=[0,1];return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=b_.call(e,k_),t):n.slice()},t.copy=function(){return fu().domain(n)},cu(t)}function lu(t,n){return(n=Math.log(n/t))?function(e){return Math.log(e/t)/n}:T_(n)}function hu(t,n){return t<0?function(e){return-Math.pow(-n,e)*Math.pow(-t,1-e)}:function(e){return Math.pow(n,e)*Math.pow(t,1-e)}}function pu(t){return isFinite(t)?+("1e"+t):t<0?0:t}function du(t){return 10===t?pu:t===Math.E?Math.exp:function(n){return Math.pow(t,n)}}function vu(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),function(n){return Math.log(n)/t})}function _u(t){return function(n){return-t(-n)}}function yu(){function n(){return o=vu(i),u=du(i),r()[0]<0&&(o=_u(o),u=_u(u)),e}var e=au(lu,hu).domain([1,10]),r=e.domain,i=10,o=vu(10),u=du(10);return e.base=function(t){return arguments.length?(i=+t,n()):i},e.domain=function(t){return arguments.length?(r(t),n()):r()},e.ticks=function(t){var n,e=r(),a=e[0],c=e[e.length-1];(n=c<a)&&(h=a,a=c,c=h);var s,f,l,h=o(a),p=o(c),d=null==t?10:+t,v=[];if(!(i%1)&&p-h<d){if(h=Math.round(h)-1,p=Math.round(p)+1,a>0){for(;h<p;++h)for(f=1,s=u(h);f<i;++f)if(!((l=s*f)<a)){if(l>c)break;v.push(l)}}else for(;h<p;++h)for(f=i-1,s=u(h);f>=1;--f)if(!((l=s*f)<a)){if(l>c)break;v.push(l)}}else v=Ss(h,p,Math.min(p-h,d)).map(u);return n?v.reverse():v},e.tickFormat=function(n,r){if(null==r&&(r=10===i?".0e":","),"function"!=typeof r&&(r=t.format(r)),n===1/0)return r;null==n&&(n=10);var a=Math.max(1,i*n/e.ticks().length);return function(t){var n=t/u(Math.round(o(t)));return n*i<i-.5&&(n*=i),n<=a?r(t):""}},e.nice=function(){return r(E_(r(),{floor:function(t){return u(Math.floor(o(t)))},ceil:function(t){return u(Math.ceil(o(t)))}}))},e.copy=function(){return uu(e,yu().base(i))},e}function gu(t,n){return t<0?-Math.pow(-t,n):Math.pow(t,n)}function mu(){var t=1,n=au(function(n,e){return(e=gu(e,t)-(n=gu(n,t)))?function(r){return(gu(r,t)-n)/e}:T_(e)},function(n,e){return e=gu(e,t)-(n=gu(n,t)),function(r){return gu(n+e*r,1/t)}}),e=n.domain;return n.exponent=function(n){return arguments.length?(t=+n,e(e())):t},n.copy=function(){return uu(n,mu().exponent(t))},cu(n)}function xu(){function t(){var t=0,o=Math.max(1,r.length);for(i=new Array(o-1);++t<o;)i[t-1]=As(e,t/o);return n}function n(t){if(!isNaN(t=+t))return r[hs(i,t)]}var e=[],r=[],i=[];return n.invertExtent=function(t){var n=r.indexOf(t);return n<0?[NaN,NaN]:[n>0?i[n-1]:e[0],n<i.length?i[n]:e[e.length-1]]},n.domain=function(n){if(!arguments.length)return e.slice();e=[];for(var r,i=0,o=n.length;i<o;++i)null==(r=n[i])||isNaN(r=+r)||e.push(r);return e.sort(ss),t()},n.range=function(n){return arguments.length?(r=w_.call(n),t()):r.slice()},n.quantiles=function(){return i.slice()},n.copy=function(){return xu().domain(e).range(r)},n}function bu(){function t(t){if(t<=t)return u[hs(o,t,0,i)]}function n(){var n=-1;for(o=new Array(i);++n<i;)o[n]=((n+1)*r-(n-i)*e)/(i+1);return t}var e=0,r=1,i=1,o=[.5],u=[0,1];return t.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],n()):[e,r]},t.range=function(t){return arguments.length?(i=(u=w_.call(t)).length-1,n()):u.slice()},t.invertExtent=function(t){var n=u.indexOf(t);return n<0?[NaN,NaN]:n<1?[e,o[0]]:n>=i?[o[i-1],r]:[o[n-1],o[n]]},t.copy=function(){return bu().domain([e,r]).range(u)},cu(t)}function wu(){function t(t){if(t<=t)return e[hs(n,t,0,r)]}var n=[.5],e=[0,1],r=1;return t.domain=function(i){return arguments.length?(n=w_.call(i),r=Math.min(n.length,e.length-1),t):n.slice()},t.range=function(i){return arguments.length?(e=w_.call(i),r=Math.min(n.length,e.length-1),t):e.slice()},t.invertExtent=function(t){var r=e.indexOf(t);return[n[r-1],n[r]]},t.copy=function(){return wu().domain(n).range(e)},t}function Mu(t,n,e,r){function i(n){return t(n=new Date(+n)),n}return i.floor=i,i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=function(t,e){return n(t=new Date(+t),null==e?1:Math.floor(e)),t},i.range=function(e,r,o){var u=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return u;do{u.push(new Date(+e))}while(n(e,o),t(e),e<r);return u},i.filter=function(e){return Mu(function(n){if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return A_.setTime(+n),C_.setTime(+r),t(A_),t(C_),Math.floor(e(A_,C_))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}function Tu(t){return Mu(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*R_)/L_})}function ku(t){return Mu(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/L_})}function Nu(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function Su(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function Eu(t){return{y:t,m:0,d:1,H:0,M:0,S:0,L:0}}function Au(t){function n(t,n){return function(e){var r,i,o,u=[],a=-1,c=0,s=t.length;for(e instanceof Date||(e=new Date(+e));++a<s;)37===t.charCodeAt(a)&&(u.push(t.slice(c,a)),null!=(i=Py[r=t.charAt(++a)])?r=t.charAt(++a):i="e"===r?" ":"0",(o=n[r])&&(r=o(e,i)),u.push(r),c=a+1);return u.push(t.slice(c,a)),u.join("")}}function e(t,n){return function(e){var i=Eu(1900);if(r(i,t,e+="",0)!=e.length)return null;if("p"in i&&(i.H=i.H%12+12*i.p),"W"in i||"U"in i){"w"in i||(i.w="W"in i?1:0);var o="Z"in i?Su(Eu(i.y)).getUTCDay():n(Eu(i.y)).getDay();i.m=0,i.d="W"in i?(i.w+6)%7+7*i.W-(o+5)%7:i.w+7*i.U-(o+6)%7}return"Z"in i?(i.H+=i.Z/100|0,i.M+=i.Z%100,Su(i)):n(i)}}function r(t,n,e,r){for(var i,o,u=0,a=n.length,c=e.length;u<a;){if(r>=c)return-1;if(37===(i=n.charCodeAt(u++))){if(i=n.charAt(u++),!(o=T[i in Py?n.charAt(u++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}var i=t.dateTime,o=t.date,u=t.time,a=t.periods,c=t.days,s=t.shortDays,f=t.months,l=t.shortMonths,h=Pu(a),p=Ru(a),d=Pu(c),v=Ru(c),_=Pu(s),y=Ru(s),g=Pu(f),m=Ru(f),x=Pu(l),b=Ru(l),w={a:function(t){return s[t.getDay()]},A:function(t){return c[t.getDay()]},b:function(t){return l[t.getMonth()]},B:function(t){return f[t.getMonth()]},c:null,d:Wu,e:Wu,H:Zu,I:Gu,j:Ju,L:Qu,m:Ku,M:ta,p:function(t){return a[+(t.getHours()>=12)]},S:na,U:ea,w:ra,W:ia,x:null,X:null,y:oa,Y:ua,Z:aa,"%":wa},M={a:function(t){return s[t.getUTCDay()]},A:function(t){return c[t.getUTCDay()]},b:function(t){return l[t.getUTCMonth()]},B:function(t){return f[t.getUTCMonth()]},c:null,d:ca,e:ca,H:sa,I:fa,j:la,L:ha,m:pa,M:da,p:function(t){return a[+(t.getUTCHours()>=12)]},S:va,U:_a,w:ya,W:ga,x:null,X:null,y:ma,Y:xa,Z:ba,"%":wa},T={a:function(t,n,e){var r=_.exec(n.slice(e));return r?(t.w=y[r[0].toLowerCase()],e+r[0].length):-1},A:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=v[r[0].toLowerCase()],e+r[0].length):-1},b:function(t,n,e){var r=x.exec(n.slice(e));return r?(t.m=b[r[0].toLowerCase()],e+r[0].length):-1},B:function(t,n,e){var r=g.exec(n.slice(e));return r?(t.m=m[r[0].toLowerCase()],e+r[0].length):-1},c:function(t,n,e){return r(t,i,n,e)},d:Yu,e:Yu,H:ju,I:ju,j:Bu,L:$u,m:Iu,M:Hu,p:function(t,n,e){var r=h.exec(n.slice(e));return r?(t.p=p[r[0].toLowerCase()],e+r[0].length):-1},S:Xu,U:qu,w:Lu,W:Uu,x:function(t,n,e){return r(t,o,n,e)},X:function(t,n,e){return r(t,u,n,e)},y:Ou,Y:Du,Z:Fu,"%":Vu};return w.x=n(o,w),w.X=n(u,w),w.c=n(i,w),M.x=n(o,M),M.X=n(u,M),M.c=n(i,M),{format:function(t){var e=n(t+="",w);return e.toString=function(){return t},e},parse:function(t){var n=e(t+="",Nu);return n.toString=function(){return t},n},utcFormat:function(t){var e=n(t+="",M);return e.toString=function(){return t},e},utcParse:function(t){var n=e(t,Su);return n.toString=function(){return t},n}}}function Cu(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function zu(t){return t.replace(qy,"\\$&")}function Pu(t){return new RegExp("^(?:"+t.map(zu).join("|")+")","i")}function Ru(t){for(var n={},e=-1,r=t.length;++e<r;)n[t[e].toLowerCase()]=e;return n}function Lu(t,n,e){var r=Ry.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function qu(t,n,e){var r=Ry.exec(n.slice(e));return r?(t.U=+r[0],e+r[0].length):-1}function Uu(t,n,e){var r=Ry.exec(n.slice(e));return r?(t.W=+r[0],e+r[0].length):-1}function Du(t,n,e){var r=Ry.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function Ou(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function Fu(t,n,e){var r=/^(Z)|([+-]\d\d)(?:\:?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function Iu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function Yu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function Bu(t,n,e){var r=Ry.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function ju(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function Hu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function Xu(t,n,e){var r=Ry.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function $u(t,n,e){var r=Ry.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function Vu(t,n,e){var r=Ly.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function Wu(t,n){return Cu(t.getDate(),n,2)}function Zu(t,n){return Cu(t.getHours(),n,2)}function Gu(t,n){return Cu(t.getHours()%12||12,n,2)}function Ju(t,n){return Cu(1+Y_.count(oy(t),t),n,3)}function Qu(t,n){return Cu(t.getMilliseconds(),n,3)}function Ku(t,n){return Cu(t.getMonth()+1,n,2)}function ta(t,n){return Cu(t.getMinutes(),n,2)}function na(t,n){return Cu(t.getSeconds(),n,2)}function ea(t,n){return Cu(j_.count(oy(t),t),n,2)}function ra(t){return t.getDay()}function ia(t,n){return Cu(H_.count(oy(t),t),n,2)}function oa(t,n){return Cu(t.getFullYear()%100,n,2)}function ua(t,n){return Cu(t.getFullYear()%1e4,n,4)}function aa(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+Cu(n/60|0,"0",2)+Cu(n%60,"0",2)}function ca(t,n){return Cu(t.getUTCDate(),n,2)}function sa(t,n){return Cu(t.getUTCHours(),n,2)}function fa(t,n){return Cu(t.getUTCHours()%12||12,n,2)}function la(t,n){return Cu(1+ly.count(Ay(t),t),n,3)}function ha(t,n){return Cu(t.getUTCMilliseconds(),n,3)}function pa(t,n){return Cu(t.getUTCMonth()+1,n,2)}function da(t,n){return Cu(t.getUTCMinutes(),n,2)}function va(t,n){return Cu(t.getUTCSeconds(),n,2)}function _a(t,n){return Cu(py.count(Ay(t),t),n,2)}function ya(t){return t.getUTCDay()}function ga(t,n){return Cu(dy.count(Ay(t),t),n,2)}function ma(t,n){return Cu(t.getUTCFullYear()%100,n,2)}function xa(t,n){return Cu(t.getUTCFullYear()%1e4,n,4)}function ba(){return"+0000"}function wa(){return"%"}function Ma(n){return Cy=Au(n),t.timeFormat=Cy.format,t.timeParse=Cy.parse,t.utcFormat=Cy.utcFormat,t.utcParse=Cy.utcParse,Cy}function Ta(t){return new Date(t)}function ka(t){return t instanceof Date?+t:+new Date(+t)}function Na(t,n,e,r,o,u,a,c,s){function f(i){return(a(i)<i?v:u(i)<i?_:o(i)<i?y:r(i)<i?g:n(i)<i?e(i)<i?m:x:t(i)<i?b:w)(i)}function l(n,e,r,o){if(null==n&&(n=10),"number"==typeof n){var u=Math.abs(r-e)/n,a=fs(function(t){return t[2]}).right(M,u);a===M.length?(o=i(e/Hy,r/Hy,n),n=t):a?(o=(a=M[u/M[a-1][2]<M[a][2]/u?a-1:a])[1],n=a[0]):(o=i(e,r,n),n=c)}return null==o?n:n.every(o)}var h=au(nu,rl),p=h.invert,d=h.domain,v=s(".%L"),_=s(":%S"),y=s("%I:%M"),g=s("%I %p"),m=s("%a %d"),x=s("%b %d"),b=s("%B"),w=s("%Y"),M=[[a,1,Oy],[a,5,5*Oy],[a,15,15*Oy],[a,30,30*Oy],[u,1,Fy],[u,5,5*Fy],[u,15,15*Fy],[u,30,30*Fy],[o,1,Iy],[o,3,3*Iy],[o,6,6*Iy],[o,12,12*Iy],[r,1,Yy],[r,2,2*Yy],[e,1,By],[n,1,jy],[n,3,3*jy],[t,1,Hy]];return h.invert=function(t){return new Date(p(t))},h.domain=function(t){return arguments.length?d(b_.call(t,ka)):d().map(Ta)},h.ticks=function(t,n){var e,r=d(),i=r[0],o=r[r.length-1],u=o<i;return u&&(e=i,i=o,o=e),e=l(t,i,o,n),e=e?e.range(i,o+1):[],u?e.reverse():e},h.tickFormat=function(t,n){return null==n?f:s(n)},h.nice=function(t,n){var e=d();return(t=l(t,e[0],e[e.length-1],n))?d(E_(e,t)):h},h.copy=function(){return uu(h,Na(t,n,e,r,o,u,a,c,s))},h}function Sa(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}function Ea(t){function n(n){var o=(n-e)/(r-e);return t(i?Math.max(0,Math.min(1,o)):o)}var e=0,r=1,i=!1;return n.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],n):[e,r]},n.clamp=function(t){return arguments.length?(i=!!t,n):i},n.interpolator=function(e){return arguments.length?(t=e,n):t},n.copy=function(){return Ea(t).domain([e,r]).clamp(i)},cu(n)}function Aa(t){return t>1?0:t<-1?pg:Math.acos(t)}function Ca(t){return t>=1?dg:t<=-1?-dg:Math.asin(t)}function za(t){return t.innerRadius}function Pa(t){return t.outerRadius}function Ra(t){return t.startAngle}function La(t){return t.endAngle}function qa(t){return t&&t.padAngle}function Ua(t,n,e,r,i,o,u,a){var c=e-t,s=r-n,f=u-i,l=a-o,h=(f*(n-o)-l*(t-i))/(l*c-f*s);return[t+h*c,n+h*s]}function Da(t,n,e,r,i,o,u){var a=t-e,c=n-r,s=(u?o:-o)/lg(a*a+c*c),f=s*c,l=-s*a,h=t+f,p=n+l,d=e+f,v=r+l,_=(h+d)/2,y=(p+v)/2,g=d-h,m=v-p,x=g*g+m*m,b=i-o,w=h*v-d*p,M=(m<0?-1:1)*lg(cg(0,b*b*x-w*w)),T=(w*m-g*M)/x,k=(-w*g-m*M)/x,N=(w*m+g*M)/x,S=(-w*g+m*M)/x,E=T-_,A=k-y,C=N-_,z=S-y;return E*E+A*A>C*C+z*z&&(T=N,k=S),{cx:T,cy:k,x01:-f,y01:-l,x11:T*(i/b-1),y11:k*(i/b-1)}}function Oa(t){this._context=t}function Fa(t){return t[0]}function Ia(t){return t[1]}function Ya(t){this._curve=t}function Ba(t){function n(n){return new Ya(t(n))}return n._curve=t,n}function ja(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(Ba(t)):n()._curve},t}function Ha(t){return t.source}function Xa(t){return t.target}function $a(t){function n(){var n,a=kg.call(arguments),c=e.apply(this,a),s=r.apply(this,a);if(u||(u=n=ve()),t(u,+i.apply(this,(a[0]=c,a)),+o.apply(this,a),+i.apply(this,(a[0]=s,a)),+o.apply(this,a)),n)return u=null,n+""||null}var e=Ha,r=Xa,i=Fa,o=Ia,u=null;return n.source=function(t){return arguments.length?(e=t,n):e},n.target=function(t){return arguments.length?(r=t,n):r},n.x=function(t){return arguments.length?(i="function"==typeof t?t:ig(+t),n):i},n.y=function(t){return arguments.length?(o="function"==typeof t?t:ig(+t),n):o},n.context=function(t){return arguments.length?(u=null==t?null:t,n):u},n}function Va(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n=(n+r)/2,e,n,i,r,i)}function Wa(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n,e=(e+i)/2,r,e,r,i)}function Za(t,n,e,r,i){var o=Tg(n,e),u=Tg(n,e=(e+i)/2),a=Tg(r,e),c=Tg(r,i);t.moveTo(o[0],o[1]),t.bezierCurveTo(u[0],u[1],a[0],a[1],c[0],c[1])}function Ga(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function Ja(t){this._context=t}function Qa(t){this._context=t}function Ka(t){this._context=t}function tc(t,n){this._basis=new Ja(t),this._beta=n}function nc(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function ec(t,n){this._context=t,this._k=(1-n)/6}function rc(t,n){this._context=t,this._k=(1-n)/6}function ic(t,n){this._context=t,this._k=(1-n)/6}function oc(t,n,e){var r=t._x1,i=t._y1,o=t._x2,u=t._y2;if(t._l01_a>hg){var a=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*a-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*a-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>hg){var s=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,f=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*s+t._x1*t._l23_2a-n*t._l12_2a)/f,u=(u*s+t._y1*t._l23_2a-e*t._l12_2a)/f}t._context.bezierCurveTo(r,i,o,u,t._x2,t._y2)}function uc(t,n){this._context=t,this._alpha=n}function ac(t,n){this._context=t,this._alpha=n}function cc(t,n){this._context=t,this._alpha=n}function sc(t){this._context=t}function fc(t){return t<0?-1:1}function lc(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),u=(e-t._y1)/(i||r<0&&-0),a=(o*i+u*r)/(r+i);return(fc(o)+fc(u))*Math.min(Math.abs(o),Math.abs(u),.5*Math.abs(a))||0}function hc(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function pc(t,n,e){var r=t._x0,i=t._y0,o=t._x1,u=t._y1,a=(o-r)/3;t._context.bezierCurveTo(r+a,i+a*n,o-a,u-a*e,o,u)}function dc(t){this._context=t}function vc(t){this._context=new _c(t)}function _c(t){this._context=t}function yc(t){this._context=t}function gc(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),u=new Array(r);for(i[0]=0,o[0]=2,u[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,u[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,u[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,u[n]-=e*u[n-1];for(i[r-1]=u[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(u[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function mc(t,n){this._context=t,this._t=n}function xc(t,n){return t[n]}function bc(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}function wc(t){return t[0]}function Mc(t){return t[1]}function Tc(){this._=null}function kc(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function Nc(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function Sc(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function Ec(t){for(;t.L;)t=t.L;return t}function Ac(t,n,e,r){var i=[null,null],o=um.push(i)-1;return i.left=t,i.right=n,e&&zc(i,t,n,e),r&&zc(i,n,t,r),im[t.index].halfedges.push(o),im[n.index].halfedges.push(o),i}function Cc(t,n,e){var r=[n,e];return r.left=t,r}function zc(t,n,e,r){t[0]||t[1]?t.left===e?t[1]=r:t[0]=r:(t[0]=r,t.left=n,t.right=e)}function Pc(t,n,e,r,i){var o,u=t[0],a=t[1],c=u[0],s=u[1],f=0,l=1,h=a[0]-c,p=a[1]-s;if(o=n-c,h||!(o>0)){if(o/=h,h<0){if(o<f)return;o<l&&(l=o)}else if(h>0){if(o>l)return;o>f&&(f=o)}if(o=r-c,h||!(o<0)){if(o/=h,h<0){if(o>l)return;o>f&&(f=o)}else if(h>0){if(o<f)return;o<l&&(l=o)}if(o=e-s,p||!(o>0)){if(o/=p,p<0){if(o<f)return;o<l&&(l=o)}else if(p>0){if(o>l)return;o>f&&(f=o)}if(o=i-s,p||!(o<0)){if(o/=p,p<0){if(o>l)return;o>f&&(f=o)}else if(p>0){if(o<f)return;o<l&&(l=o)}return!(f>0||l<1)||(f>0&&(t[0]=[c+f*h,s+f*p]),l<1&&(t[1]=[c+l*h,s+l*p]),!0)}}}}}function Rc(t,n,e,r,i){var o=t[1];if(o)return!0;var u,a,c=t[0],s=t.left,f=t.right,l=s[0],h=s[1],p=f[0],d=f[1],v=(l+p)/2,_=(h+d)/2;if(d===h){if(v<n||v>=r)return;if(l>p){if(c){if(c[1]>=i)return}else c=[v,e];o=[v,i]}else{if(c){if(c[1]<e)return}else c=[v,i];o=[v,e]}}else if(u=(l-p)/(d-h),a=_-u*v,u<-1||u>1)if(l>p){if(c){if(c[1]>=i)return}else c=[(e-a)/u,e];o=[(i-a)/u,i]}else{if(c){if(c[1]<e)return}else c=[(i-a)/u,i];o=[(e-a)/u,e]}else if(h<d){if(c){if(c[0]>=r)return}else c=[n,u*n+a];o=[r,u*r+a]}else{if(c){if(c[0]<n)return}else c=[r,u*r+a];o=[n,u*n+a]}return t[0]=c,t[1]=o,!0}function Lc(t,n,e,r){for(var i,o=um.length;o--;)Rc(i=um[o],t,n,e,r)&&Pc(i,t,n,e,r)&&(Math.abs(i[0][0]-i[1][0])>sm||Math.abs(i[0][1]-i[1][1])>sm)||delete um[o]}function qc(t){return im[t.index]={site:t,halfedges:[]}}function Uc(t,n){var e=t.site,r=n.left,i=n.right;return e===i&&(i=r,r=e),i?Math.atan2(i[1]-r[1],i[0]-r[0]):(e===r?(r=n[1],i=n[0]):(r=n[0],i=n[1]),Math.atan2(r[0]-i[0],i[1]-r[1]))}function Dc(t,n){return n[+(n.left!==t.site)]}function Oc(t,n){return n[+(n.left===t.site)]}function Fc(){for(var t,n,e,r,i=0,o=im.length;i<o;++i)if((t=im[i])&&(r=(n=t.halfedges).length)){var u=new Array(r),a=new Array(r);for(e=0;e<r;++e)u[e]=e,a[e]=Uc(t,um[n[e]]);for(u.sort(function(t,n){return a[n]-a[t]}),e=0;e<r;++e)a[e]=n[u[e]];for(e=0;e<r;++e)n[e]=a[e]}}function Ic(t,n,e,r){var i,o,u,a,c,s,f,l,h,p,d,v,_=im.length,y=!0;for(i=0;i<_;++i)if(o=im[i]){for(u=o.site,a=(c=o.halfedges).length;a--;)um[c[a]]||c.splice(a,1);for(a=0,s=c.length;a<s;)d=(p=Oc(o,um[c[a]]))[0],v=p[1],l=(f=Dc(o,um[c[++a%s]]))[0],h=f[1],(Math.abs(d-l)>sm||Math.abs(v-h)>sm)&&(c.splice(a,0,um.push(Cc(u,p,Math.abs(d-t)<sm&&r-v>sm?[t,Math.abs(l-t)<sm?h:r]:Math.abs(v-r)<sm&&e-d>sm?[Math.abs(h-r)<sm?l:e,r]:Math.abs(d-e)<sm&&v-n>sm?[e,Math.abs(l-e)<sm?h:n]:Math.abs(v-n)<sm&&d-t>sm?[Math.abs(h-n)<sm?l:t,n]:null))-1),++s);s&&(y=!1)}if(y){var g,m,x,b=1/0;for(i=0,y=null;i<_;++i)(o=im[i])&&(x=(g=(u=o.site)[0]-t)*g+(m=u[1]-n)*m)<b&&(b=x,y=o);if(y){var w=[t,n],M=[t,r],T=[e,r],k=[e,n];y.halfedges.push(um.push(Cc(u=y.site,w,M))-1,um.push(Cc(u,M,T))-1,um.push(Cc(u,T,k))-1,um.push(Cc(u,k,w))-1)}}for(i=0;i<_;++i)(o=im[i])&&(o.halfedges.length||delete im[i])}function Yc(){kc(this),this.x=this.y=this.arc=this.site=this.cy=null}function Bc(t){var n=t.P,e=t.N;if(n&&e){var r=n.site,i=t.site,o=e.site;if(r!==o){var u=i[0],a=i[1],c=r[0]-u,s=r[1]-a,f=o[0]-u,l=o[1]-a,h=2*(c*l-s*f);if(!(h>=-fm)){var p=c*c+s*s,d=f*f+l*l,v=(l*p-s*d)/h,_=(c*d-f*p)/h,y=am.pop()||new Yc;y.arc=t,y.site=i,y.x=v+u,y.y=(y.cy=_+a)+Math.sqrt(v*v+_*_),t.circle=y;for(var g=null,m=om._;m;)if(y.y<m.y||y.y===m.y&&y.x<=m.x){if(!m.L){g=m.P;break}m=m.L}else{if(!m.R){g=m;break}m=m.R}om.insert(g,y),g||(em=y)}}}}function jc(t){var n=t.circle;n&&(n.P||(em=n.N),om.remove(n),am.push(n),kc(n),t.circle=null)}function Hc(){kc(this),this.edge=this.site=this.circle=null}function Xc(t){var n=cm.pop()||new Hc;return n.site=t,n}function $c(t){jc(t),rm.remove(t),cm.push(t),kc(t)}function Vc(t){var n=t.circle,e=n.x,r=n.cy,i=[e,r],o=t.P,u=t.N,a=[t];$c(t);for(var c=o;c.circle&&Math.abs(e-c.circle.x)<sm&&Math.abs(r-c.circle.cy)<sm;)o=c.P,a.unshift(c),$c(c),c=o;a.unshift(c),jc(c);for(var s=u;s.circle&&Math.abs(e-s.circle.x)<sm&&Math.abs(r-s.circle.cy)<sm;)u=s.N,a.push(s),$c(s),s=u;a.push(s),jc(s);var f,l=a.length;for(f=1;f<l;++f)s=a[f],c=a[f-1],zc(s.edge,c.site,s.site,i);c=a[0],(s=a[l-1]).edge=Ac(c.site,s.site,null,i),Bc(c),Bc(s)}function Wc(t){for(var n,e,r,i,o=t[0],u=t[1],a=rm._;a;)if((r=Zc(a,u)-o)>sm)a=a.L;else{if(!((i=o-Gc(a,u))>sm)){r>-sm?(n=a.P,e=a):i>-sm?(n=a,e=a.N):n=e=a;break}if(!a.R){n=a;break}a=a.R}qc(t);var c=Xc(t);if(rm.insert(n,c),n||e){if(n===e)return jc(n),e=Xc(n.site),rm.insert(c,e),c.edge=e.edge=Ac(n.site,c.site),Bc(n),void Bc(e);if(e){jc(n),jc(e);var s=n.site,f=s[0],l=s[1],h=t[0]-f,p=t[1]-l,d=e.site,v=d[0]-f,_=d[1]-l,y=2*(h*_-p*v),g=h*h+p*p,m=v*v+_*_,x=[(_*g-p*m)/y+f,(h*m-v*g)/y+l];zc(e.edge,s,d,x),c.edge=Ac(s,t,null,x),e.edge=Ac(t,d,null,x),Bc(n),Bc(e)}else c.edge=Ac(n.site,c.site)}}function Zc(t,n){var e=t.site,r=e[0],i=e[1],o=i-n;if(!o)return r;var u=t.P;if(!u)return-1/0;var a=(e=u.site)[0],c=e[1],s=c-n;if(!s)return a;var f=a-r,l=1/o-1/s,h=f/s;return l?(-h+Math.sqrt(h*h-2*l*(f*f/(-2*s)-c+s/2+i-o/2)))/l+r:(r+a)/2}function Gc(t,n){var e=t.N;if(e)return Zc(e,n);var r=t.site;return r[1]===n?r[0]:1/0}function Jc(t,n,e){return(t[0]-e[0])*(n[1]-t[1])-(t[0]-n[0])*(e[1]-t[1])}function Qc(t,n){return n[1]-t[1]||n[0]-t[0]}function Kc(t,n){var e,r,i,o=t.sort(Qc).pop();for(um=[],im=new Array(t.length),rm=new Tc,om=new Tc;;)if(i=em,o&&(!i||o[1]<i.y||o[1]===i.y&&o[0]<i.x))o[0]===e&&o[1]===r||(Wc(o),e=o[0],r=o[1]),o=t.pop();else{if(!i)break;Vc(i.arc)}if(Fc(),n){var u=+n[0][0],a=+n[0][1],c=+n[1][0],s=+n[1][1];Lc(u,a,c,s),Ic(u,a,c,s)}this.edges=um,this.cells=im,rm=om=um=im=null}function ts(t,n,e){this.target=t,this.type=n,this.transform=e}function ns(t,n,e){this.k=t,this.x=n,this.y=e}function es(t){return t.__zoom||hm}function rs(){t.event.stopImmediatePropagation()}function is(){return!t.event.button}function os(){var t,n,e=this;return e instanceof SVGElement?(t=(e=e.ownerSVGElement||e).width.baseVal.value,n=e.height.baseVal.value):(t=e.clientWidth,n=e.clientHeight),[[0,0],[t,n]]}function us(){return this.__zoom||hm}function as(){return-t.event.deltaY*(t.event.deltaMode?120:1)/500}function cs(){return"ontouchstart"in this}var ss=function(t,n){return t<n?-1:t>n?1:t>=n?0:NaN},fs=function(t){return 1===t.length&&(t=n(t)),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)>0?i=o:r=o+1}return r}}},ls=fs(ss),hs=ls.right,ps=ls.left,ds=function(t){return null===t?NaN:+t},vs=function(t,n){var e,r,i=t.length,o=0,u=-1,a=0,c=0;if(null==n)for(;++u<i;)isNaN(e=ds(t[u]))||(c+=(r=e-a)*(e-(a+=r/++o)));else for(;++u<i;)isNaN(e=ds(n(t[u],u,t)))||(c+=(r=e-a)*(e-(a+=r/++o)));if(o>1)return c/(o-1)},_s=function(t,n){var e=vs(t,n);return e?Math.sqrt(e):e},ys=function(t,n){var e,r,i,o=t.length,u=-1;if(null==n){for(;++u<o;)if(null!=(e=t[u])&&e>=e)for(r=i=e;++u<o;)null!=(e=t[u])&&(r>e&&(r=e),i<e&&(i=e))}else for(;++u<o;)if(null!=(e=n(t[u],u,t))&&e>=e)for(r=i=e;++u<o;)null!=(e=n(t[u],u,t))&&(r>e&&(r=e),i<e&&(i=e));return[r,i]},gs=Array.prototype,ms=gs.slice,xs=gs.map,bs=function(t){return function(){return t}},ws=function(t){return t},Ms=function(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o},Ts=Math.sqrt(50),ks=Math.sqrt(10),Ns=Math.sqrt(2),Ss=function(t,n,e){var i,o,u,a=n<t,c=-1;if(a&&(i=t,t=n,n=i),0===(u=r(t,n,e))||!isFinite(u))return[];if(u>0)for(t=Math.ceil(t/u),n=Math.floor(n/u),o=new Array(i=Math.ceil(n-t+1));++c<i;)o[c]=(t+c)*u;else for(t=Math.floor(t*u),n=Math.ceil(n*u),o=new Array(i=Math.ceil(t-n+1));++c<i;)o[c]=(t-c)/u;return a&&o.reverse(),o},Es=function(t){return Math.ceil(Math.log(t.length)/Math.LN2)+1},As=function(t,n,e){if(null==e&&(e=ds),r=t.length){if((n=+n)<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),u=+e(t[o],o,t);return u+(+e(t[o+1],o+1,t)-u)*(i-o)}},Cs=function(t){for(var n,e,r,i=t.length,o=-1,u=0;++o<i;)u+=t[o].length;for(e=new Array(u);--i>=0;)for(n=(r=t[i]).length;--n>=0;)e[--u]=r[n];return e},zs=function(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&r>e&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&r>e&&(r=e);return r},Ps=function(t){if(!(i=t.length))return[];for(var n=-1,e=zs(t,o),r=new Array(e);++n<e;)for(var i,u=-1,a=r[n]=new Array(i);++u<i;)a[u]=t[u][n];return r},Rs=Array.prototype.slice,Ls=function(t){return t},qs=1,Us=2,Ds=3,Os=4,Fs=1e-6,Is={value:function(){}};p.prototype=h.prototype={constructor:p,on:function(t,n){var e,r=this._,i=d(t+"",r),o=-1,u=i.length;{if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o<u;)if(e=(t=i[o]).type)r[e]=_(r[e],t.name,n);else if(null==n)for(e in r)r[e]=_(r[e],t.name,null);return this}for(;++o<u;)if((e=(t=i[o]).type)&&(e=v(r[e],t.name)))return e}},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new p(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(o=0,e=(r=this._[t]).length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var Ys="http://www.w3.org/1999/xhtml",Bs={svg:"http://www.w3.org/2000/svg",xhtml:Ys,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},js=function(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),Bs.hasOwnProperty(n)?{space:Bs[n],local:t}:t},Hs=function(t){var n=js(t);return(n.local?g:y)(n)},Xs=0;x.prototype=m.prototype={constructor:x,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}};var $s=function(t){return function(){return this.matches(t)}};if("undefined"!=typeof document){var Vs=document.documentElement;if(!Vs.matches){var Ws=Vs.webkitMatchesSelector||Vs.msMatchesSelector||Vs.mozMatchesSelector||Vs.oMatchesSelector;$s=function(t){return function(){return Ws.call(this,t)}}}}var Zs=$s,Gs={};t.event=null,"undefined"!=typeof document&&("onmouseenter"in document.documentElement||(Gs={mouseenter:"mouseover",mouseleave:"mouseout"}));var Js=function(){for(var n,e=t.event;n=e.sourceEvent;)e=n;return e},Qs=function(t,n){var e=t.ownerSVGElement||t;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=n.clientX,r.y=n.clientY,r=r.matrixTransform(t.getScreenCTM().inverse()),[r.x,r.y]}var i=t.getBoundingClientRect();return[n.clientX-i.left-t.clientLeft,n.clientY-i.top-t.clientTop]},Ks=function(t){var n=Js();return n.changedTouches&&(n=n.changedTouches[0]),Qs(t,n)},tf=function(t){return null==t?S:function(){return this.querySelector(t)}},nf=function(t){return null==t?E:function(){return this.querySelectorAll(t)}},ef=function(t){return new Array(t.length)};A.prototype={constructor:A,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var rf=function(t){return function(){return t}},of="$",uf=function(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView};W.prototype={add:function(t){this._names.indexOf(t)<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var af=[null];pt.prototype=dt.prototype={constructor:pt,select:function(t){"function"!=typeof t&&(t=tf(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u,a=n[i],c=a.length,s=r[i]=new Array(c),f=0;f<c;++f)(o=a[f])&&(u=t.call(o,o.__data__,f,a))&&("__data__"in o&&(u.__data__=o.__data__),s[f]=u);return new pt(r,this._parents)},selectAll:function(t){"function"!=typeof t&&(t=nf(t));for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var u,a=n[o],c=a.length,s=0;s<c;++s)(u=a[s])&&(r.push(t.call(u,u.__data__,s,a)),i.push(u));return new pt(r,i)},filter:function(t){"function"!=typeof t&&(t=Zs(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u=n[i],a=u.length,c=r[i]=[],s=0;s<a;++s)(o=u[s])&&t.call(o,o.__data__,s,u)&&c.push(o);return new pt(r,this._parents)},data:function(t,n){if(!t)return p=new Array(this.size()),s=-1,this.each(function(t){p[++s]=t}),p;var e=n?z:C,r=this._parents,i=this._groups;"function"!=typeof t&&(t=rf(t));for(var o=i.length,u=new Array(o),a=new Array(o),c=new Array(o),s=0;s<o;++s){var f=r[s],l=i[s],h=l.length,p=t.call(f,f&&f.__data__,s,r),d=p.length,v=a[s]=new Array(d),_=u[s]=new Array(d);e(f,l,v,_,c[s]=new Array(h),p,n);for(var y,g,m=0,x=0;m<d;++m)if(y=v[m]){for(m>=x&&(x=m+1);!(g=_[x])&&++x<d;);y._next=g||null}}return u=new pt(u,r),u._enter=a,u._exit=c,u},enter:function(){return new pt(this._enter||this._groups.map(ef),this._parents)},exit:function(){return new pt(this._exit||this._groups.map(ef),this._parents)},merge:function(t){for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),a=0;a<o;++a)for(var c,s=n[a],f=e[a],l=s.length,h=u[a]=new Array(l),p=0;p<l;++p)(c=s[p]||f[p])&&(h[p]=c);for(;a<r;++a)u[a]=n[a];return new pt(u,this._parents)},order:function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,u=i[o];--o>=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){t||(t=P);for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i){for(var o,u=n[i],a=u.length,c=r[i]=new Array(a),s=0;s<a;++s)(o=u[s])&&(c[s]=o);c.sort(function(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e})}return new pt(r,this._parents).order()},call:function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},nodes:function(){var t=new Array(this.size()),n=-1;return this.each(function(){t[++n]=this}),t},node:function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var u=r[i];if(u)return u}return null},size:function(){var t=0;return this.each(function(){++t}),t},empty:function(){return!this.node()},each:function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],u=0,a=o.length;u<a;++u)(i=o[u])&&t.call(i,i.__data__,u,o);return this},attr:function(t,n){var e=js(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?L:R:"function"==typeof n?e.local?O:D:e.local?U:q)(e,n))},style:function(t,n,e){return arguments.length>1?this.each((null==n?F:"function"==typeof n?Y:I)(t,n,null==e?"":e)):B(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?j:"function"==typeof n?X:H)(t,n)):this.node()[t]},classed:function(t,n){var e=$(t+"");if(arguments.length<2){for(var r=V(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each(("function"==typeof n?K:n?J:Q)(e,n))},text:function(t){return arguments.length?this.each(null==t?tt:("function"==typeof t?et:nt)(t)):this.node().textContent},html:function(t){return arguments.length?this.each(null==t?rt:("function"==typeof t?ot:it)(t)):this.node().innerHTML},raise:function(){return this.each(ut)},lower:function(){return this.each(at)},append:function(t){var n="function"==typeof t?t:Hs(t);return this.select(function(){return this.appendChild(n.apply(this,arguments))})},insert:function(t,n){var e="function"==typeof t?t:Hs(t),r=null==n?ct:"function"==typeof n?n:tf(n);return this.select(function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)})},remove:function(){return this.each(st)},datum:function(t){return arguments.length?this.property("__data__",t):this.node().__data__},on:function(t,n,e){var r,i,o=M(t+""),u=o.length;{if(!(arguments.length<2)){for(a=n?k:T,null==e&&(e=!1),r=0;r<u;++r)this.each(a(o[r],n,e));return this}var a=this.node().__on;if(a)for(var c,s=0,f=a.length;s<f;++s)for(r=0,c=a[s];r<u;++r)if((i=o[r]).type===c.type&&i.name===c.name)return c.value}},dispatch:function(t,n){return this.each(("function"==typeof n?ht:lt)(t,n))}};var cf=function(t){return"string"==typeof t?new pt([[document.querySelector(t)]],[document.documentElement]):new pt([[t]],af)},sf=function(t,n,e){arguments.length<3&&(e=n,n=Js().changedTouches);for(var r,i=0,o=n?n.length:0;i<o;++i)if((r=n[i]).identifier===e)return Qs(t,r);return null},ff=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},lf=function(t){var n=t.document.documentElement,e=cf(t).on("dragstart.drag",ff,!0);"onselectstart"in n?e.on("selectstart.drag",ff,!0):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect="none")},hf=function(t){return function(){return t}};yt.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var pf=function(t,n,e){t.prototype=n.prototype=e,e.constructor=t},df="\\s*([+-]?\\d+)\\s*",vf="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",_f="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",yf=/^#([0-9a-f]{3})$/,gf=/^#([0-9a-f]{6})$/,mf=new RegExp("^rgb\\("+[df,df,df]+"\\)$"),xf=new RegExp("^rgb\\("+[_f,_f,_f]+"\\)$"),bf=new RegExp("^rgba\\("+[df,df,df,vf]+"\\)$"),wf=new RegExp("^rgba\\("+[_f,_f,_f,vf]+"\\)$"),Mf=new RegExp("^hsl\\("+[vf,_f,_f]+"\\)$"),Tf=new RegExp("^hsla\\("+[vf,_f,_f,vf]+"\\)$"),kf={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};pf(Mt,Tt,{displayable:function(){return this.rgb().displayable()},toString:function(){return this.rgb()+""}}),pf(At,Et,wt(Mt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new At(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new At(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return 0<=this.r&&this.r<=255&&0<=this.g&&this.g<=255&&0<=this.b&&this.b<=255&&0<=this.opacity&&this.opacity<=1},toString:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}})),pf(Rt,Pt,wt(Mt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Rt(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Rt(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new At(Lt(t>=240?t-240:t+120,i,r),Lt(t,i,r),Lt(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1}}));var Nf=Math.PI/180,Sf=180/Math.PI,Ef=.95047,Af=1,Cf=1.08883,zf=4/29,Pf=6/29,Rf=3*Pf*Pf,Lf=Pf*Pf*Pf;pf(Dt,Ut,wt(Mt,{brighter:function(t){return new Dt(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new Dt(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return t=Af*Ft(t),n=Ef*Ft(n),e=Cf*Ft(e),new At(It(3.2404542*n-1.5371385*t-.4985314*e),It(-.969266*n+1.8760108*t+.041556*e),It(.0556434*n-.2040259*t+1.0572252*e),this.opacity)}})),pf(Ht,jt,wt(Mt,{brighter:function(t){return new Ht(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new Ht(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return qt(this).rgb()}}));var qf=-.14861,Uf=1.78277,Df=-.29227,Of=-.90649,Ff=1.97294,If=Ff*Of,Yf=Ff*Uf,Bf=Uf*Df-Of*qf;pf(Vt,$t,wt(Mt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Vt(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Vt(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*Nf,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new At(255*(n+e*(qf*r+Uf*i)),255*(n+e*(Df*r+Of*i)),255*(n+e*(Ff*r)),this.opacity)}}));var jf,Hf,Xf,$f,Vf,Wf,Zf=function(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=r<n-1?t[r+2]:2*o-i;return Wt((e-r/n)*n,u,i,o,a)}},Gf=function(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],u=t[(r+1)%n],a=t[(r+2)%n];return Wt((e-r/n)*n,i,o,u,a)}},Jf=function(t){return function(){return t}},Qf=function t(n){function e(t,n){var e=r((t=Et(t)).r,(n=Et(n)).r),i=r(t.g,n.g),o=r(t.b,n.b),u=Kt(t.opacity,n.opacity);return function(n){return t.r=e(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}var r=Qt(n);return e.gamma=t,e}(1),Kf=tn(Zf),tl=tn(Gf),nl=function(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(r),u=new Array(r);for(e=0;e<i;++e)o[e]=cl(t[e],n[e]);for(;e<r;++e)u[e]=n[e];return function(t){for(e=0;e<i;++e)u[e]=o[e](t);return u}},el=function(t,n){var e=new Date;return t=+t,n-=t,function(r){return e.setTime(t+n*r),e}},rl=function(t,n){return t=+t,n-=t,function(e){return t+n*e}},il=function(t,n){var e,r={},i={};null!==t&&"object"==typeof t||(t={}),null!==n&&"object"==typeof n||(n={});for(e in n)e in t?r[e]=cl(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}},ol=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,ul=new RegExp(ol.source,"g"),al=function(t,n){var e,r,i,o=ol.lastIndex=ul.lastIndex=0,u=-1,a=[],c=[];for(t+="",n+="";(e=ol.exec(t))&&(r=ul.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,c.push({i:u,x:rl(e,r)})),o=ul.lastIndex;return o<n.length&&(i=n.slice(o),a[u]?a[u]+=i:a[++u]=i),a.length<2?c[0]?en(c[0].x):nn(n):(n=c.length,function(t){for(var e,r=0;r<n;++r)a[(e=c[r]).i]=e.x(t);return a.join("")})},cl=function(t,n){var e,r=typeof n;return null==n||"boolean"===r?Jf(n):("number"===r?rl:"string"===r?(e=Tt(n))?(n=e,Qf):al:n instanceof Tt?Qf:n instanceof Date?el:Array.isArray(n)?nl:"function"!=typeof n.valueOf&&"function"!=typeof n.toString||isNaN(n)?il:rl)(t,n)},sl=function(t,n){return t=+t,n-=t,function(e){return Math.round(t+n*e)}},fl=180/Math.PI,ll={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1},hl=function(t,n,e,r,i,o){var u,a,c;return(u=Math.sqrt(t*t+n*n))&&(t/=u,n/=u),(c=t*e+n*r)&&(e-=t*c,r-=n*c),(a=Math.sqrt(e*e+r*r))&&(e/=a,r/=a,c/=a),t*r<n*e&&(t=-t,n=-n,c=-c,u=-u),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*fl,skewX:Math.atan(c)*fl,scaleX:u,scaleY:a}},pl=rn(function(t){return"none"===t?ll:(jf||(jf=document.createElement("DIV"),Hf=document.documentElement,Xf=document.defaultView),jf.style.transform=t,t=Xf.getComputedStyle(Hf.appendChild(jf),null).getPropertyValue("transform"),Hf.removeChild(jf),t=t.slice(7,-1).split(","),hl(+t[0],+t[1],+t[2],+t[3],+t[4],+t[5]))},"px, ","px)","deg)"),dl=rn(function(t){return null==t?ll:($f||($f=document.createElementNS("http://www.w3.org/2000/svg","g")),$f.setAttribute("transform",t),(t=$f.transform.baseVal.consolidate())?(t=t.matrix,hl(t.a,t.b,t.c,t.d,t.e,t.f)):ll)},", ",")",")"),vl=Math.SQRT2,_l=function(t,n){var e,r,i=t[0],o=t[1],u=t[2],a=n[0],c=n[1],s=n[2],f=a-i,l=c-o,h=f*f+l*l;if(h<1e-12)r=Math.log(s/u)/vl,e=function(t){return[i+t*f,o+t*l,u*Math.exp(vl*t*r)]};else{var p=Math.sqrt(h),d=(s*s-u*u+4*h)/(2*u*2*p),v=(s*s-u*u-4*h)/(2*s*2*p),_=Math.log(Math.sqrt(d*d+1)-d),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-_)/vl,e=function(t){var n=t*r,e=on(_),a=u/(2*p)*(e*an(vl*n+_)-un(_));return[i+a*f,o+a*l,u*e/on(vl*n+_)]}}return e.duration=1e3*r,e},yl=cn(Jt),gl=cn(Kt),ml=sn(Jt),xl=sn(Kt),bl=fn(Jt),wl=fn(Kt),Ml=0,Tl=0,kl=0,Nl=1e3,Sl=0,El=0,Al=0,Cl="object"==typeof performance&&performance.now?performance:Date,zl="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};pn.prototype=dn.prototype={constructor:pn,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?ln():+e)+(null==n?0:+n),this._next||Wf===this||(Wf?Wf._next=this:Vf=this,Wf=this),this._call=t,this._time=e,mn()},stop:function(){this._call&&(this._call=null,this._time=1/0,mn())}};var Pl=function(t,n,e){var r=new pn;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r},Rl=h("start","end","interrupt"),Ll=[],ql=0,Ul=1,Dl=2,Ol=3,Fl=4,Il=5,Yl=6,Bl=function(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};Mn(t,e,{name:n,index:r,group:i,on:Rl,tween:Ll,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:ql})},jl=function(t,n){var e,r,i,o=t.__transition,u=!0;if(o){n=null==n?null:n+"";for(i in o)(e=o[i]).name===n?(r=e.state>Dl&&e.state<Il,e.state=Yl,e.timer.stop(),r&&e.on.call("interrupt",t,t.__data__,e.index,e.group),delete o[i]):u=!1;u&&delete t.__transition}},Hl=function(t,n){var e;return("number"==typeof n?rl:n instanceof Tt?Qf:(e=Tt(n))?(n=e,Qf):al)(t,n)},Xl=dt.prototype.constructor,$l=0,Vl=dt.prototype;Gn.prototype=Jn.prototype={constructor:Gn,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=tf(t));for(var r=this._groups,i=r.length,o=new Array(i),u=0;u<i;++u)for(var a,c,s=r[u],f=s.length,l=o[u]=new Array(f),h=0;h<f;++h)(a=s[h])&&(c=t.call(a,a.__data__,h,s))&&("__data__"in a&&(c.__data__=a.__data__),l[h]=c,Bl(l[h],n,e,h,l,wn(a,e)));return new Gn(o,this._parents,n,e)},selectAll:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=nf(t));for(var r=this._groups,i=r.length,o=[],u=[],a=0;a<i;++a)for(var c,s=r[a],f=s.length,l=0;l<f;++l)if(c=s[l]){for(var h,p=t.call(c,c.__data__,l,s),d=wn(c,e),v=0,_=p.length;v<_;++v)(h=p[v])&&Bl(h,n,e,v,p,d);o.push(p),u.push(c)}return new Gn(o,u,n,e)},filter:function(t){"function"!=typeof t&&(t=Zs(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,u=n[i],a=u.length,c=r[i]=[],s=0;s<a;++s)(o=u[s])&&t.call(o,o.__data__,s,u)&&c.push(o);return new Gn(r,this._parents,this._name,this._id)},merge:function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),a=0;a<o;++a)for(var c,s=n[a],f=e[a],l=s.length,h=u[a]=new Array(l),p=0;p<l;++p)(c=s[p]||f[p])&&(h[p]=c);for(;a<r;++a)u[a]=n[a];return new Gn(u,this._parents,this._name,this._id)},selection:function(){return new Xl(this._groups,this._parents)},transition:function(){for(var t=this._name,n=this._id,e=Qn(),r=this._groups,i=r.length,o=0;o<i;++o)for(var u,a=r[o],c=a.length,s=0;s<c;++s)if(u=a[s]){var f=wn(u,n);Bl(u,t,e,s,a,{time:f.time+f.delay+f.duration,delay:0,duration:f.duration,ease:f.ease})}return new Gn(r,this._parents,t,e)},call:Vl.call,nodes:Vl.nodes,node:Vl.node,size:Vl.size,empty:Vl.empty,each:Vl.each,on:function(t,n){var e=this._id;return arguments.length<2?wn(this.node(),e).on.on(t):this.each(Yn(e,t,n))},attr:function(t,n){var e=js(t),r="transform"===e?dl:Hl;return this.attrTween(t,"function"==typeof n?(e.local?Pn:zn)(e,r,Nn(this,"attr."+t,n)):null==n?(e.local?En:Sn)(e):(e.local?Cn:An)(e,r,n+""))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=js(t);return this.tween(e,(r.local?Rn:Ln)(r,n))},style:function(t,n,e){var r="transform"==(t+="")?pl:Hl;return null==n?this.styleTween(t,jn(t,r)).on("end.style."+t,Hn(t)):this.styleTween(t,"function"==typeof n?$n(t,r,Nn(this,"style."+t,n)):Xn(t,r,n+""),e)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,Vn(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?Zn(Nn(this,"text",t)):Wn(null==t?"":t+""))},remove:function(){return this.on("end.remove",Bn(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=wn(this.node(),e).tween,o=0,u=i.length;o<u;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?Tn:kn)(e,t,n))},delay:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?qn:Un)(n,t)):wn(this.node(),n).delay},duration:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?Dn:On)(n,t)):wn(this.node(),n).duration},ease:function(t){var n=this._id;return arguments.length?this.each(Fn(n,t)):wn(this.node(),n).ease}};var Wl=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(3),Zl=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(3),Gl=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(3),Jl=Math.PI,Ql=Jl/2,Kl=4/11,th=6/11,nh=8/11,eh=.75,rh=9/11,ih=10/11,oh=.9375,uh=21/22,ah=63/64,ch=1/Kl/Kl,sh=function t(n){function e(t){return t*t*((n+1)*t-n)}return n=+n,e.overshoot=t,e}(1.70158),fh=function t(n){function e(t){return--t*t*((n+1)*t+n)+1}return n=+n,e.overshoot=t,e}(1.70158),lh=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(1.70158),hh=2*Math.PI,ph=function t(n,e){function r(t){return n*Math.pow(2,10*--t)*Math.sin((i-t)/e)}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=hh);return r.amplitude=function(n){return t(n,e*hh)},r.period=function(e){return t(n,e)},r}(1,.3),dh=function t(n,e){function r(t){return 1-n*Math.pow(2,-10*(t=+t))*Math.sin((t+i)/e)}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=hh);return r.amplitude=function(n){return t(n,e*hh)},r.period=function(e){return t(n,e)},r}(1,.3),vh=function t(n,e){function r(t){return((t=2*t-1)<0?n*Math.pow(2,10*t)*Math.sin((i-t)/e):2-n*Math.pow(2,-10*t)*Math.sin((i+t)/e))/2}var i=Math.asin(1/(n=Math.max(1,n)))*(e/=hh);return r.amplitude=function(n){return t(n,e*hh)},r.period=function(e){return t(n,e)},r}(1,.3),_h={time:null,delay:0,duration:250,ease:te};dt.prototype.interrupt=function(t){return this.each(function(){jl(this,t)})},dt.prototype.transition=function(t){var n,e;t instanceof Gn?(n=t._id,t=t._name):(n=Qn(),(e=_h).time=ln(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var u,a=r[o],c=a.length,s=0;s<c;++s)(u=a[s])&&Bl(u,t,n,s,a,e||oe(u,n));return new Gn(r,this._parents,t,n)};var yh=[null],gh=function(t){return function(){return t}},mh=function(t,n,e){this.target=t,this.type=n,this.selection=e},xh=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()},bh={name:"drag"},wh={name:"space"},Mh={name:"handle"},Th={name:"center"},kh={name:"x",handles:["e","w"].map(ae),input:function(t,n){return t&&[[t[0],n[0][1]],[t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},Nh={name:"y",handles:["n","s"].map(ae),input:function(t,n){return t&&[[n[0][0],t[0]],[n[1][0],t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},Sh={name:"xy",handles:["n","e","s","w","nw","ne","se","sw"].map(ae),input:function(t){return t},output:function(t){return t}},Eh={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Ah={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},Ch={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},zh={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},Ph={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1},Rh=Math.cos,Lh=Math.sin,qh=Math.PI,Uh=qh/2,Dh=2*qh,Oh=Math.max,Fh=Array.prototype.slice,Ih=function(t){return function(){return t}},Yh=Math.PI,Bh=2*Yh,jh=Bh-1e-6;de.prototype=ve.prototype={constructor:de,moveTo:function(t,n){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,n){this._+="L"+(this._x1=+t)+","+(this._y1=+n)},quadraticCurveTo:function(t,n,e,r){this._+="Q"+ +t+","+ +n+","+(this._x1=+e)+","+(this._y1=+r)},bezierCurveTo:function(t,n,e,r,i,o){this._+="C"+ +t+","+ +n+","+ +e+","+ +r+","+(this._x1=+i)+","+(this._y1=+o)},arcTo:function(t,n,e,r,i){t=+t,n=+n,e=+e,r=+r,i=+i;var o=this._x1,u=this._y1,a=e-t,c=r-n,s=o-t,f=u-n,l=s*s+f*f;if(i<0)throw new Error("negative radius: "+i);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=n);else if(l>1e-6)if(Math.abs(f*a-c*s)>1e-6&&i){var h=e-o,p=r-u,d=a*a+c*c,v=h*h+p*p,_=Math.sqrt(d),y=Math.sqrt(l),g=i*Math.tan((Yh-Math.acos((d+l-v)/(2*_*y)))/2),m=g/y,x=g/_;Math.abs(m-1)>1e-6&&(this._+="L"+(t+m*s)+","+(n+m*f)),this._+="A"+i+","+i+",0,0,"+ +(f*h>s*p)+","+(this._x1=t+x*a)+","+(this._y1=n+x*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n;var u=(e=+e)*Math.cos(r),a=e*Math.sin(r),c=t+u,s=n+a,f=1^o,l=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+s:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-s)>1e-6)&&(this._+="L"+c+","+s),e&&(l<0&&(l=l%Bh+Bh),l>jh?this._+="A"+e+","+e+",0,1,"+f+","+(t-u)+","+(n-a)+"A"+e+","+e+",0,1,"+f+","+(this._x1=c)+","+(this._y1=s):l>1e-6&&(this._+="A"+e+","+e+",0,"+ +(l>=Yh)+","+f+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};be.prototype=we.prototype={constructor:be,has:function(t){return"$"+t in this},get:function(t){return this["$"+t]},set:function(t,n){return this["$"+t]=n,this},remove:function(t){var n="$"+t;return n in this&&delete this[n]},clear:function(){for(var t in this)"$"===t[0]&&delete this[t]},keys:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(n.slice(1));return t},values:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(this[n]);return t},entries:function(){var t=[];for(var n in this)"$"===n[0]&&t.push({key:n.slice(1),value:this[n]});return t},size:function(){var t=0;for(var n in this)"$"===n[0]&&++t;return t},empty:function(){for(var t in this)if("$"===t[0])return!1;return!0},each:function(t){for(var n in this)"$"===n[0]&&t(this[n],n.slice(1),this)}};var Hh=we.prototype;Se.prototype=Ee.prototype={constructor:Se,has:Hh.has,add:function(t){return t+="",this["$"+t]=t,this},remove:Hh.remove,clear:Hh.clear,values:Hh.keys,size:Hh.size,empty:Hh.empty,each:Hh.each};var Xh=function(t){function n(t,n){function e(){if(f>=s)return a;if(i)return i=!1,u;var n,e=f;if(34===t.charCodeAt(e)){for(var r=e;r++<s;)if(34===t.charCodeAt(r)){if(34!==t.charCodeAt(r+1))break;++r}return f=r+2,13===(n=t.charCodeAt(r+1))?(i=!0,10===t.charCodeAt(r+2)&&++f):10===n&&(i=!0),t.slice(e+1,r).replace(/""/g,'"')}for(;f<s;){var c=1;if(10===(n=t.charCodeAt(f++)))i=!0;else if(13===n)i=!0,10===t.charCodeAt(f)&&(++f,++c);else if(n!==o)continue;return t.slice(e,f-c)}return t.slice(e)}for(var r,i,u={},a={},c=[],s=t.length,f=0,l=0;(r=e())!==a;){for(var h=[];r!==u&&r!==a;)h.push(r),r=e();n&&null==(h=n(h,l++))||c.push(h)}return c}function e(n){return n.map(r).join(t)}function r(t){return null==t?"":i.test(t+="")?'"'+t.replace(/\"/g,'""')+'"':t}var i=new RegExp('["'+t+"\n\r]"),o=t.charCodeAt(0);return{parse:function(t,e){var r,i,o=n(t,function(t,n){if(r)return r(t,n-1);i=t,r=e?Ce(t,e):Ae(t)});return o.columns=i,o},parseRows:n,format:function(n,e){return null==e&&(e=ze(n)),[e.map(r).join(t)].concat(n.map(function(n){return e.map(function(t){return r(n[t])}).join(t)})).join("\n")},formatRows:function(t){return t.map(e).join("\n")}}},$h=Xh(","),Vh=$h.parse,Wh=$h.parseRows,Zh=$h.format,Gh=$h.formatRows,Jh=Xh("\t"),Qh=Jh.parse,Kh=Jh.parseRows,tp=Jh.format,np=Jh.formatRows,ep=function(t){return function(){return t}},rp=function(){return 1e-6*(Math.random()-.5)},ip=function(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i},op=qe.prototype=Ue.prototype;op.copy=function(){var t,n,e=new Ue(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=De(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=De(n));return e},op.add=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return Pe(this.cover(n,e),n,e,t)},op.addAll=function(t){var n,e,r,i,o=t.length,u=new Array(o),a=new Array(o),c=1/0,s=1/0,f=-1/0,l=-1/0;for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(u[e]=r,a[e]=i,r<c&&(c=r),r>f&&(f=r),i<s&&(s=i),i>l&&(l=i));for(f<c&&(c=this._x0,f=this._x1),l<s&&(s=this._y0,l=this._y1),this.cover(c,s).cover(f,l),e=0;e<o;++e)Pe(this,u[e],a[e],t[e]);return this},op.cover=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{if(!(e>t||t>i||r>n||n>o))return this;var u,a,c=i-e,s=this._root;switch(a=(n<(r+o)/2)<<1|t<(e+i)/2){case 0:do{u=new Array(4),u[a]=s,s=u}while(c*=2,i=e+c,o=r+c,t>i||n>o);break;case 1:do{u=new Array(4),u[a]=s,s=u}while(c*=2,e=i-c,o=r+c,e>t||n>o);break;case 2:do{u=new Array(4),u[a]=s,s=u}while(c*=2,i=e+c,r=o-c,t>i||r>n);break;case 3:do{u=new Array(4),u[a]=s,s=u}while(c*=2,e=i-c,r=o-c,e>t||r>n)}this._root&&this._root.length&&(this._root=s)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},op.data=function(){var t=[];return this.visit(function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)}),t},op.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},op.find=function(t,n,e){var r,i,o,u,a,c,s,f=this._x0,l=this._y0,h=this._x1,p=this._y1,d=[],v=this._root;for(v&&d.push(new ip(v,f,l,h,p)),null==e?e=1/0:(f=t-e,l=n-e,h=t+e,p=n+e,e*=e);c=d.pop();)if(!(!(v=c.node)||(i=c.x0)>h||(o=c.y0)>p||(u=c.x1)<f||(a=c.y1)<l))if(v.length){var _=(i+u)/2,y=(o+a)/2;d.push(new ip(v[3],_,y,u,a),new ip(v[2],i,y,_,a),new ip(v[1],_,o,u,y),new ip(v[0],i,o,_,y)),(s=(n>=y)<<1|t>=_)&&(c=d[d.length-1],d[d.length-1]=d[d.length-1-s],d[d.length-1-s]=c)}else{var g=t-+this._x.call(null,v.data),m=n-+this._y.call(null,v.data),x=g*g+m*m;if(x<e){var b=Math.sqrt(e=x);f=t-b,l=n-b,h=t+b,p=n+b,r=v.data}}return r},op.remove=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(u=+this._y.call(null,t)))return this;var n,e,r,i,o,u,a,c,s,f,l,h,p=this._root,d=this._x0,v=this._y0,_=this._x1,y=this._y1;if(!p)return this;if(p.length)for(;;){if((s=o>=(a=(d+_)/2))?d=a:_=a,(f=u>=(c=(v+y)/2))?v=c:y=c,n=p,!(p=p[l=f<<1|s]))return this;if(!p.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;p.data!==t;)if(r=p,!(p=p.next))return this;return(i=p.next)&&delete p.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(p=n[0]||n[1]||n[2]||n[3])&&p===(n[3]||n[2]||n[1]||n[0])&&!p.length&&(e?e[h]=p:this._root=p),this):(this._root=i,this)},op.removeAll=function(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this},op.root=function(){return this._root},op.size=function(){var t=0;return this.visit(function(n){if(!n.length)do{++t}while(n=n.next)}),t},op.visit=function(t){var n,e,r,i,o,u,a=[],c=this._root;for(c&&a.push(new ip(c,this._x0,this._y0,this._x1,this._y1));n=a.pop();)if(!t(c=n.node,r=n.x0,i=n.y0,o=n.x1,u=n.y1)&&c.length){var s=(r+o)/2,f=(i+u)/2;(e=c[3])&&a.push(new ip(e,s,f,o,u)),(e=c[2])&&a.push(new ip(e,r,f,s,u)),(e=c[1])&&a.push(new ip(e,s,i,o,f)),(e=c[0])&&a.push(new ip(e,r,i,s,f))}return this},op.visitAfter=function(t){var n,e=[],r=[];for(this._root&&e.push(new ip(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,u=n.x0,a=n.y0,c=n.x1,s=n.y1,f=(u+c)/2,l=(a+s)/2;(o=i[0])&&e.push(new ip(o,u,a,f,l)),(o=i[1])&&e.push(new ip(o,f,a,c,l)),(o=i[2])&&e.push(new ip(o,u,l,f,s)),(o=i[3])&&e.push(new ip(o,f,l,c,s))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},op.x=function(t){return arguments.length?(this._x=t,this):this._x},op.y=function(t){return arguments.length?(this._y=t,this):this._y};var up,ap=10,cp=Math.PI*(3-Math.sqrt(5)),sp=function(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]},fp=function(t){return(t=sp(Math.abs(t)))?t[1]:NaN},lp=function(t,n){return function(e,r){for(var i=e.length,o=[],u=0,a=t[0],c=0;i>0&&a>0&&(c+a+1>r&&(a=Math.max(1,r-c)),o.push(e.substring(i-=a,i+a)),!((c+=a+1)>r));)a=t[u=(u+1)%t.length];return o.reverse().join(n)}},hp=function(t){return function(n){return n.replace(/[0-9]/g,function(n){return t[+n]})}},pp=function(t,n){var e=sp(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")},dp={"":function(t,n){t:for(var e,r=(t=t.toPrecision(n)).length,i=1,o=-1;i<r;++i)switch(t[i]){case".":o=e=i;break;case"0":0===o&&(o=i),e=i;break;case"e":break t;default:o>0&&(o=0)}return o>0?t.slice(0,o)+t.slice(e+1):t},"%":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return pp(100*t,n)},r:pp,s:function(t,n){var e=sp(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(up=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,u=r.length;return o===u?r:o>u?r+new Array(o-u+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+sp(t,Math.max(0,n+o-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}},vp=/^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;He.prototype=Xe.prototype,Xe.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(null==this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(null==this.precision?"":"."+Math.max(0,0|this.precision))+this.type};var _p,yp=function(t){return t},gp=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"],mp=function(t){function n(t){function n(t){var n,r,u,f=_,x=y;if("c"===v)x=g(t)+x,t="";else{var b=(t=+t)<0;if(t=g(Math.abs(t),d),b&&0==+t&&(b=!1),f=(b?"("===s?s:"-":"-"===s||"("===s?"":s)+f,x=x+("s"===v?gp[8+up/3]:"")+(b&&"("===s?")":""),m)for(n=-1,r=t.length;++n<r;)if(48>(u=t.charCodeAt(n))||u>57){x=(46===u?i+t.slice(n+1):t.slice(n))+x,t=t.slice(0,n);break}}p&&!l&&(t=e(t,1/0));var w=f.length+t.length+x.length,M=w<h?new Array(h-w+1).join(a):"";switch(p&&l&&(t=e(M+t,M.length?h-x.length:1/0),M=""),c){case"<":t=f+t+x+M;break;case"=":t=f+M+t+x;break;case"^":t=M.slice(0,w=M.length>>1)+f+t+x+M.slice(w);break;default:t=M+f+t+x}return o(t)}var a=(t=He(t)).fill,c=t.align,s=t.sign,f=t.symbol,l=t.zero,h=t.width,p=t.comma,d=t.precision,v=t.type,_="$"===f?r[0]:"#"===f&&/[boxX]/.test(v)?"0"+v.toLowerCase():"",y="$"===f?r[1]:/[%p]/.test(v)?u:"",g=dp[v],m=!v||/[defgprs%]/.test(v);return d=null==d?v?6:12:/[gprs]/.test(v)?Math.max(1,Math.min(21,d)):Math.max(0,Math.min(20,d)),n.toString=function(){return t+""},n}var e=t.grouping&&t.thousands?lp(t.grouping,t.thousands):yp,r=t.currency,i=t.decimal,o=t.numerals?hp(t.numerals):yp,u=t.percent||"%";return{format:n,formatPrefix:function(t,e){var r=n((t=He(t),t.type="f",t)),i=3*Math.max(-8,Math.min(8,Math.floor(fp(e)/3))),o=Math.pow(10,-i),u=gp[8+i/3];return function(t){return r(o*t)+u}}}};$e({decimal:".",thousands:",",grouping:[3],currency:["$",""]});var xp=function(t){return Math.max(0,-fp(Math.abs(t)))},bp=function(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(fp(n)/3)))-fp(Math.abs(t)))},wp=function(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,fp(n)-fp(t))+1},Mp=function(){return new Ve};Ve.prototype={constructor:Ve,reset:function(){this.s=this.t=0},add:function(t){We(nd,t,this.t),We(this,nd.s,this.s),this.s?this.t+=nd.t:this.s=nd.t},valueOf:function(){return this.s}};var Tp,kp,Np,Sp,Ep,Ap,Cp,zp,Pp,Rp,Lp,qp,Up,Dp,Op,Fp,Ip,Yp,Bp,jp,Hp,Xp,$p,Vp,Wp,Zp,Gp,Jp,Qp,Kp,td,nd=new Ve,ed=1e-6,rd=Math.PI,id=rd/2,od=rd/4,ud=2*rd,ad=180/rd,cd=rd/180,sd=Math.abs,fd=Math.atan,ld=Math.atan2,hd=Math.cos,pd=Math.ceil,dd=Math.exp,vd=Math.log,_d=Math.pow,yd=Math.sin,gd=Math.sign||function(t){return t>0?1:t<0?-1:0},md=Math.sqrt,xd=Math.tan,bd={Feature:function(t,n){Ke(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)Ke(e[r].geometry,n)}},wd={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){tr(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)tr(e[r],n,0)},Polygon:function(t,n){nr(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)nr(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)Ke(e[r],n)}},Md=function(t,n){t&&bd.hasOwnProperty(t.type)?bd[t.type](t,n):Ke(t,n)},Td=Mp(),kd=Mp(),Nd={point:Qe,lineStart:Qe,lineEnd:Qe,polygonStart:function(){Td.reset(),Nd.lineStart=er,Nd.lineEnd=rr},polygonEnd:function(){var t=+Td;kd.add(t<0?ud+t:t),this.lineStart=this.lineEnd=this.point=Qe},sphere:function(){kd.add(ud)}},Sd=Mp(),Ed={point:pr,lineStart:vr,lineEnd:_r,polygonStart:function(){Ed.point=yr,Ed.lineStart=gr,Ed.lineEnd=mr,Sd.reset(),Nd.polygonStart()},polygonEnd:function(){Nd.polygonEnd(),Ed.point=pr,Ed.lineStart=vr,Ed.lineEnd=_r,Td<0?(Ap=-(zp=180),Cp=-(Pp=90)):Sd>ed?Pp=90:Sd<-ed&&(Cp=-90),Op[0]=Ap,Op[1]=zp}},Ad={sphere:Qe,point:Mr,lineStart:kr,lineEnd:Er,polygonStart:function(){Ad.lineStart=Ar,Ad.lineEnd=Cr},polygonEnd:function(){Ad.lineStart=kr,Ad.lineEnd=Er}},Cd=function(t){return function(){return t}},zd=function(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return(e=n.invert(e,r))&&t.invert(e[0],e[1])}),e};Rr.invert=Rr;var Pd,Rd,Ld,qd,Ud,Dd,Od,Fd,Id,Yd,Bd,jd=function(t){function n(n){return n=t(n[0]*cd,n[1]*cd),n[0]*=ad,n[1]*=ad,n}return t=Lr(t[0]*cd,t[1]*cd,t.length>2?t[2]*cd:0),n.invert=function(n){return n=t.invert(n[0]*cd,n[1]*cd),n[0]*=ad,n[1]*=ad,n},n},Hd=function(){var t,n=[];return{point:function(n,e){t.push([n,e])},lineStart:function(){n.push(t=[])},lineEnd:Qe,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}},Xd=function(t,n,e,r,i,o){var u,a=t[0],c=t[1],s=0,f=1,l=n[0]-a,h=n[1]-c;if(u=e-a,l||!(u>0)){if(u/=l,l<0){if(u<s)return;u<f&&(f=u)}else if(l>0){if(u>f)return;u>s&&(s=u)}if(u=i-a,l||!(u<0)){if(u/=l,l<0){if(u>f)return;u>s&&(s=u)}else if(l>0){if(u<s)return;u<f&&(f=u)}if(u=r-c,h||!(u>0)){if(u/=h,h<0){if(u<s)return;u<f&&(f=u)}else if(h>0){if(u>f)return;u>s&&(s=u)}if(u=o-c,h||!(u<0)){if(u/=h,h<0){if(u>f)return;u>s&&(s=u)}else if(h>0){if(u<s)return;u<f&&(f=u)}return s>0&&(t[0]=a+s*l,t[1]=c+s*h),f<1&&(n[0]=a+f*l,n[1]=c+f*h),!0}}}}},$d=function(t,n){return sd(t[0]-n[0])<ed&&sd(t[1]-n[1])<ed},Vd=function(t,n,e,r,i){var o,u,a=[],c=[];if(t.forEach(function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],u=t[n];if($d(r,u)){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);i.lineEnd()}else a.push(e=new Ir(r,t,null,!0)),c.push(e.o=new Ir(r,null,e,!1)),a.push(e=new Ir(u,t,null,!1)),c.push(e.o=new Ir(u,null,e,!0))}}),a.length){for(c.sort(n),Yr(a),Yr(c),o=0,u=c.length;o<u;++o)c[o].e=e=!e;for(var s,f,l=a[0];;){for(var h=l,p=!0;h.v;)if((h=h.n)===l)return;s=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(p)for(o=0,u=s.length;o<u;++o)i.point((f=s[o])[0],f[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(p)for(s=h.p.z,o=s.length-1;o>=0;--o)i.point((f=s[o])[0],f[1]);else r(h.x,h.p.x,-1,i);h=h.p}s=(h=h.o).z,p=!p}while(!h.v);i.lineEnd()}}},Wd=1e9,Zd=-Wd,Gd=Mp(),Jd=function(t,n){var e=n[0],r=n[1],i=[yd(e),-hd(e),0],o=0,u=0;Gd.reset();for(var a=0,c=t.length;a<c;++a)if(f=(s=t[a]).length)for(var s,f,l=s[f-1],h=l[0],p=l[1]/2+od,d=yd(p),v=hd(p),_=0;_<f;++_,h=g,d=x,v=b,l=y){var y=s[_],g=y[0],m=y[1]/2+od,x=yd(m),b=hd(m),w=g-h,M=w>=0?1:-1,T=M*w,k=T>rd,N=d*x;if(Gd.add(ld(N*M*yd(T),v*b+N*hd(T))),o+=k?w+M*ud:w,k^h>=e^g>=e){var S=sr(ar(l),ar(y));hr(S);var E=sr(i,S);hr(E);var A=(k^w>=0?-1:1)*Ge(E[2]);(r>A||r===A&&(S[0]||S[1]))&&(u+=k^w>=0?1:-1)}}return(o<-ed||o<ed&&Gd<-ed)^1&u},Qd=Mp(),Kd={sphere:Qe,point:Qe,lineStart:function(){Kd.point=Hr,Kd.lineEnd=jr},lineEnd:Qe,polygonStart:Qe,polygonEnd:Qe},tv=function(t){return Qd.reset(),Md(t,Kd),+Qd},nv=[null,null],ev={type:"LineString",coordinates:nv},rv=function(t,n){return nv[0]=t,nv[1]=n,tv(ev)},iv={Feature:function(t,n){return $r(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)if($r(e[r].geometry,n))return!0;return!1}},ov={Sphere:function(){return!0},Point:function(t,n){return Vr(t.coordinates,n)},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Vr(e[r],n))return!0;return!1},LineString:function(t,n){return Wr(t.coordinates,n)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Wr(e[r],n))return!0;return!1},Polygon:function(t,n){return Zr(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Zr(e[r],n))return!0;return!1},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)if($r(e[r],n))return!0;return!1}},uv=function(t){return t},av=Mp(),cv=Mp(),sv={point:Qe,lineStart:Qe,lineEnd:Qe,polygonStart:function(){sv.lineStart=ni,sv.lineEnd=ii},polygonEnd:function(){sv.lineStart=sv.lineEnd=sv.point=Qe,av.add(sd(cv)),cv.reset()},result:function(){var t=av/2;return av.reset(),t}},fv=1/0,lv=fv,hv=-fv,pv=hv,dv={point:function(t,n){t<fv&&(fv=t),t>hv&&(hv=t),n<lv&&(lv=n),n>pv&&(pv=n)},lineStart:Qe,lineEnd:Qe,polygonStart:Qe,polygonEnd:Qe,result:function(){var t=[[fv,lv],[hv,pv]];return hv=pv=-(lv=fv=1/0),t}},vv=0,_v=0,yv=0,gv=0,mv=0,xv=0,bv=0,wv=0,Mv=0,Tv={point:oi,lineStart:ui,lineEnd:si,polygonStart:function(){Tv.lineStart=fi,Tv.lineEnd=li},polygonEnd:function(){Tv.point=oi,Tv.lineStart=ui,Tv.lineEnd=si},result:function(){var t=Mv?[bv/Mv,wv/Mv]:xv?[gv/xv,mv/xv]:yv?[vv/yv,_v/yv]:[NaN,NaN];return vv=_v=yv=gv=mv=xv=bv=wv=Mv=0,t}};di.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,ud)}},result:Qe};var kv,Nv,Sv,Ev,Av,Cv=Mp(),zv={point:Qe,lineStart:function(){zv.point=vi},lineEnd:function(){kv&&_i(Nv,Sv),zv.point=Qe},polygonStart:function(){kv=!0},polygonEnd:function(){kv=null},result:function(){var t=+Cv;return Cv.reset(),t}};yi.prototype={_radius:4.5,_circle:gi(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push("M",t,",",n),this._point=1;break;case 1:this._string.push("L",t,",",n);break;default:null==this._circle&&(this._circle=gi(this._radius)),this._string.push("M",t,",",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}};var Pv=function(t,n,e,r){return function(i,o){function u(n,e){var r=i(n,e);t(n=r[0],e=r[1])&&o.point(n,e)}function a(t,n){var e=i(t,n);_.point(e[0],e[1])}function c(){b.point=a,_.lineStart()}function s(){b.point=u,_.lineEnd()}function f(t,n){v.push([t,n]);var e=i(t,n);m.point(e[0],e[1])}function l(){m.lineStart(),v=[]}function h(){f(v[0][0],v[0][1]),m.lineEnd();var t,n,e,r,i=m.clean(),u=g.result(),a=u.length;if(v.pop(),p.push(v),v=null,a)if(1&i){if(e=u[0],(n=e.length-1)>0){for(x||(o.polygonStart(),x=!0),o.lineStart(),t=0;t<n;++t)o.point((r=e[t])[0],r[1]);o.lineEnd()}}else a>1&&2&i&&u.push(u.pop().concat(u.shift())),d.push(u.filter(mi))}var p,d,v,_=n(o),y=i.invert(r[0],r[1]),g=Hd(),m=n(g),x=!1,b={point:u,lineStart:c,lineEnd:s,polygonStart:function(){b.point=f,b.lineStart=l,b.lineEnd=h,d=[],p=[]},polygonEnd:function(){b.point=u,b.lineStart=c,b.lineEnd=s,d=Cs(d);var t=Jd(p,y);d.length?(x||(o.polygonStart(),x=!0),Vd(d,xi,t,e,o)):t&&(x||(o.polygonStart(),x=!0),o.lineStart(),e(null,null,1,o),o.lineEnd()),x&&(o.polygonEnd(),x=!1),d=p=null},sphere:function(){o.polygonStart(),o.lineStart(),e(null,null,1,o),o.lineEnd(),o.polygonEnd()}};return b}},Rv=Pv(function(){return!0},function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,u){var a=o>0?rd:-rd,c=sd(o-e);sd(c-rd)<ed?(t.point(e,r=(r+u)/2>0?id:-id),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),t.point(o,r),n=0):i!==a&&c>=rd&&(sd(e-i)<ed&&(e-=i*ed),sd(o-a)<ed&&(o-=a*ed),r=bi(e,r,o,u),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(a,r),n=0),t.point(e=o,r=u),i=a},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}},function(t,n,e,r){var i;if(null==t)i=e*id,r.point(-rd,i),r.point(0,i),r.point(rd,i),r.point(rd,0),r.point(rd,-i),r.point(0,-i),r.point(-rd,-i),r.point(-rd,0),r.point(-rd,i);else if(sd(t[0]-n[0])>ed){var o=t[0]<n[0]?rd:-rd;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])},[-rd,-id]),Lv=function(t,n){function e(t,n){return hd(t)*hd(n)>o}function r(t,n,e){var r=[1,0,0],i=sr(ar(t),ar(n)),u=cr(i,i),a=i[0],c=u-a*a;if(!c)return!e&&t;var s=o*u/c,f=-o*a/c,l=sr(r,i),h=lr(r,s);fr(h,lr(i,f));var p=l,d=cr(h,p),v=cr(p,p),_=d*d-v*(cr(h,h)-1);if(!(_<0)){var y=md(_),g=lr(p,(-d-y)/v);if(fr(g,h),g=ur(g),!e)return g;var m,x=t[0],b=n[0],w=t[1],M=n[1];b<x&&(m=x,x=b,b=m);var T=b-x,k=sd(T-rd)<ed,N=k||T<ed;if(!k&&M<w&&(m=w,w=M,M=m),N?k?w+M>0^g[1]<(sd(g[0]-x)<ed?w:M):w<=g[1]&&g[1]<=M:T>rd^(x<=g[0]&&g[0]<=b)){var S=lr(p,(-d+y)/v);return fr(S,h),[g,ur(S)]}}}function i(n,e){var r=u?t:rd-t,i=0;return n<-r?i|=1:n>r&&(i|=2),e<-r?i|=4:e>r&&(i|=8),i}var o=hd(t),u=o>0,a=sd(o)>ed;return Pv(e,function(t){var n,o,c,s,f;return{lineStart:function(){s=c=!1,f=1},point:function(l,h){var p,d=[l,h],v=e(l,h),_=u?v?0:i(l,h):v?i(l+(l<0?rd:-rd),h):0;if(!n&&(s=c=v)&&t.lineStart(),v!==c&&(!(p=r(n,d))||$d(n,p)||$d(d,p))&&(d[0]+=ed,d[1]+=ed,v=e(d[0],d[1])),v!==c)f=0,v?(t.lineStart(),p=r(d,n),t.point(p[0],p[1])):(p=r(n,d),t.point(p[0],p[1]),t.lineEnd()),n=p;else if(a&&n&&u^v){var y;_&o||!(y=r(d,n,!0))||(f=0,u?(t.lineStart(),t.point(y[0][0],y[0][1]),t.point(y[1][0],y[1][1]),t.lineEnd()):(t.point(y[1][0],y[1][1]),t.lineEnd(),t.lineStart(),t.point(y[0][0],y[0][1])))}!v||n&&$d(n,d)||t.point(d[0],d[1]),n=d,c=v,o=_},lineEnd:function(){c&&t.lineEnd(),n=null},clean:function(){return f|(s&&c)<<1}}},function(e,r,i,o){Or(o,t,n,i,e,r)},u?[0,-t]:[-rd,t-rd])};Mi.prototype={constructor:Mi,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var qv=16,Uv=hd(30*cd),Dv=function(t,n){return+n?Si(t,n):Ni(t)},Ov=wi({point:function(t,n){this.stream.point(t*cd,n*cd)}}),Fv=function(){return Ci(Pi).scale(155.424).center([0,33.6442])},Iv=function(){return Fv().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])},Yv=Li(function(t){return md(2/(1+t))});Yv.invert=qi(function(t){return 2*Ge(t/2)});var Bv=Li(function(t){return(t=Ze(t))&&t/yd(t)});Bv.invert=qi(function(t){return t});Ui.invert=function(t,n){return[t,2*fd(dd(n))-id]};Ii.invert=Ii;Bi.invert=qi(fd);Hi.invert=qi(Ge);Xi.invert=qi(function(t){return 2*fd(t)});$i.invert=function(t,n){return[-n,2*fd(dd(t))-id]};uo.prototype=eo.prototype={constructor:uo,count:function(){return this.eachAfter(to)},each:function(t){var n,e,r,i,o=this,u=[o];do{for(n=u.reverse(),u=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r<i;++r)u.push(e[r])}while(u.length);return this},eachAfter:function(t){for(var n,e,r,i=this,o=[i],u=[];i=o.pop();)if(u.push(i),n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e]);for(;i=u.pop();)t(i);return this},eachBefore:function(t){for(var n,e,r=this,i=[r];r=i.pop();)if(t(r),n=r.children)for(e=n.length-1;e>=0;--e)i.push(n[e]);return this},sum:function(t){return this.eachAfter(function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e})},sort:function(t){return this.eachBefore(function(n){n.children&&n.children.sort(t)})},path:function(t){for(var n=this,e=no(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){var t=[];return this.each(function(n){t.push(n)}),t},leaves:function(){var t=[];return this.eachBefore(function(n){n.children||t.push(n)}),t},links:function(){var t=this,n=[];return t.each(function(e){e!==t&&n.push({source:e.parent,target:e})}),n},copy:function(){return eo(this).eachBefore(io)}};var jv=Array.prototype.slice,Hv=function(t){for(var n,e,r=0,i=(t=ao(jv.call(t))).length,o=[];r<i;)n=t[r],e&&fo(e,n)?++r:(e=ho(o=co(o,n)),r=0);return e},Xv=function(t){return function(){return t}},$v=function(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)},Vv=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,s=t.value&&(r-n)/t.value;++a<c;)(o=u[a]).y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*s},Wv="$",Zv={depth:-1},Gv={};Do.prototype=Object.create(uo.prototype);var Jv=function(t,n,e,r,i){for(var o,u=t.children,a=-1,c=u.length,s=t.value&&(i-e)/t.value;++a<c;)(o=u[a]).x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*s},Qv=(1+Math.sqrt(5))/2,Kv=function t(n){function e(t,e,r,i,o){Fo(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Qv),t_=function t(n){function e(t,e,r,i,o){if((u=t._squarify)&&u.ratio===n)for(var u,a,c,s,f,l=-1,h=u.length,p=t.value;++l<h;){for(c=(a=u[l]).children,s=a.value=0,f=c.length;s<f;++s)a.value+=c[s].value;a.dice?Vv(a,e,r,i,r+=(o-r)*a.value/p):Jv(a,e,r,e+=(i-e)*a.value/p,o),p-=a.value}else t._squarify=u=Fo(n,t,e,r,i,o),u.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(Qv),n_=function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])},e_=[].slice,r_={};Bo.prototype=Wo.prototype={constructor:Bo,defer:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("defer after await");if(null!=this._error)return this;var n=e_.call(arguments,1);return n.push(t),++this._waiting,this._tasks.push(n),jo(this),this},abort:function(){return null==this._error&&$o(this,new Error("abort")),this},await:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("multiple await");return this._call=function(n,e){t.apply(null,[n].concat(e))},Vo(this),this},awaitAll:function(t){if("function"!=typeof t)throw new Error("invalid callback");if(this._call)throw new Error("multiple await");return this._call=t,Vo(this),this}};var i_=function(){return Math.random()},o_=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(i_),u_=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(i_),a_=function t(n){function e(){var t=u_.source(n).apply(this,arguments);return function(){return Math.exp(t())}}return e.source=t,e}(i_),c_=function t(n){function e(t){return function(){for(var e=0,r=0;r<t;++r)e+=n();return e}}return e.source=t,e}(i_),s_=function t(n){function e(t){var e=c_.source(n)(t);return function(){return e()/t}}return e.source=t,e}(i_),f_=function t(n){function e(t){return function(){return-Math.log(1-n())/t}}return e.source=t,e}(i_),l_=function(t,n){function e(t){var n,e=s.status;if(!e&&Go(s)||e>=200&&e<300||304===e){if(o)try{n=o.call(r,s)}catch(t){return void a.call("error",r,t)}else n=s;a.call("load",r,n)}else a.call("error",r,t)}var r,i,o,u,a=h("beforesend","progress","load","error"),c=we(),s=new XMLHttpRequest,f=null,l=null,p=0;if("undefined"==typeof XDomainRequest||"withCredentials"in s||!/^(http(s)?:)?\/\//.test(t)||(s=new XDomainRequest),"onload"in s?s.onload=s.onerror=s.ontimeout=e:s.onreadystatechange=function(t){s.readyState>3&&e(t)},s.onprogress=function(t){a.call("progress",r,t)},r={header:function(t,n){return t=(t+"").toLowerCase(),arguments.length<2?c.get(t):(null==n?c.remove(t):c.set(t,n+""),r)},mimeType:function(t){return arguments.length?(i=null==t?null:t+"",r):i},responseType:function(t){return arguments.length?(u=t,r):u},timeout:function(t){return arguments.length?(p=+t,r):p},user:function(t){return arguments.length<1?f:(f=null==t?null:t+"",r)},password:function(t){return arguments.length<1?l:(l=null==t?null:t+"",r)},response:function(t){return o=t,r},get:function(t,n){return r.send("GET",t,n)},post:function(t,n){return r.send("POST",t,n)},send:function(n,e,o){return s.open(n,t,!0,f,l),null==i||c.has("accept")||c.set("accept",i+",*/*"),s.setRequestHeader&&c.each(function(t,n){s.setRequestHeader(n,t)}),null!=i&&s.overrideMimeType&&s.overrideMimeType(i),null!=u&&(s.responseType=u),p>0&&(s.timeout=p),null==o&&"function"==typeof e&&(o=e,e=null),null!=o&&1===o.length&&(o=Zo(o)),null!=o&&r.on("error",o).on("load",function(t){o(null,t)}),a.call("beforesend",r,s),s.send(null==e?null:e),r},abort:function(){return s.abort(),r},on:function(){var t=a.on.apply(a,arguments);return t===a?r:t}},null!=n){if("function"!=typeof n)throw new Error("invalid callback: "+n);return r.get(n)}return r},h_=function(t,n){return function(e,r){var i=l_(e).mimeType(t).response(n);if(null!=r){if("function"!=typeof r)throw new Error("invalid callback: "+r);return i.get(r)}return i}},p_=h_("text/html",function(t){return document.createRange().createContextualFragment(t.responseText)}),d_=h_("application/json",function(t){return JSON.parse(t.responseText)}),v_=h_("text/plain",function(t){return t.responseText}),__=h_("application/xml",function(t){var n=t.responseXML;if(!n)throw new Error("parse error");return n}),y_=function(t,n){return function(e,r,i){arguments.length<3&&(i=r,r=null);var o=l_(e).mimeType(t);return o.row=function(t){return arguments.length?o.response(Jo(n,r=t)):r},o.row(r),i?o.get(i):o}},g_=y_("text/csv",Vh),m_=y_("text/tab-separated-values",Qh),x_=Array.prototype,b_=x_.map,w_=x_.slice,M_={name:"implicit"},T_=function(t){return function(){return t}},k_=function(t){return+t},N_=[0,1],S_=function(n,e,r){var o,u=n[0],a=n[n.length-1],c=i(u,a,null==e?10:e);switch((r=He(null==r?",f":r)).type){case"s":var s=Math.max(Math.abs(u),Math.abs(a));return null!=r.precision||isNaN(o=bp(c,s))||(r.precision=o),t.formatPrefix(r,s);case"":case"e":case"g":case"p":case"r":null!=r.precision||isNaN(o=wp(c,Math.max(Math.abs(u),Math.abs(a))))||(r.precision=o-("e"===r.type));break;case"f":case"%":null!=r.precision||isNaN(o=xp(c))||(r.precision=o-2*("%"===r.type))}return t.format(r)},E_=function(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],u=t[i];return u<o&&(e=r,r=i,i=e,e=o,o=u,u=e),t[r]=n.floor(o),t[i]=n.ceil(u),t},A_=new Date,C_=new Date,z_=Mu(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});z_.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Mu(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):z_:null};var P_=z_.range,R_=6e4,L_=6048e5,q_=Mu(function(t){t.setTime(1e3*Math.floor(t/1e3))},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),U_=q_.range,D_=Mu(function(t){t.setTime(Math.floor(t/R_)*R_)},function(t,n){t.setTime(+t+n*R_)},function(t,n){return(n-t)/R_},function(t){return t.getMinutes()}),O_=D_.range,F_=Mu(function(t){var n=t.getTimezoneOffset()*R_%36e5;n<0&&(n+=36e5),t.setTime(36e5*Math.floor((+t-n)/36e5)+n)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()}),I_=F_.range,Y_=Mu(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*R_)/864e5},function(t){return t.getDate()-1}),B_=Y_.range,j_=Tu(0),H_=Tu(1),X_=Tu(2),$_=Tu(3),V_=Tu(4),W_=Tu(5),Z_=Tu(6),G_=j_.range,J_=H_.range,Q_=X_.range,K_=$_.range,ty=V_.range,ny=W_.range,ey=Z_.range,ry=Mu(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()}),iy=ry.range,oy=Mu(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()});oy.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Mu(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var uy=oy.range,ay=Mu(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*R_)},function(t,n){return(n-t)/R_},function(t){return t.getUTCMinutes()}),cy=ay.range,sy=Mu(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()}),fy=sy.range,ly=Mu(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1}),hy=ly.range,py=ku(0),dy=ku(1),vy=ku(2),_y=ku(3),yy=ku(4),gy=ku(5),my=ku(6),xy=py.range,by=dy.range,wy=vy.range,My=_y.range,Ty=yy.range,ky=gy.range,Ny=my.range,Sy=Mu(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()}),Ey=Sy.range,Ay=Mu(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()});Ay.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Mu(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var Cy,zy=Ay.range,Py={"-":"",_:" ",0:"0"},Ry=/^\s*\d+/,Ly=/^%/,qy=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;Ma({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var Uy=Date.prototype.toISOString?function(t){return t.toISOString()}:t.utcFormat("%Y-%m-%dT%H:%M:%S.%LZ"),Dy=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:t.utcParse("%Y-%m-%dT%H:%M:%S.%LZ"),Oy=1e3,Fy=60*Oy,Iy=60*Fy,Yy=24*Iy,By=7*Yy,jy=30*Yy,Hy=365*Yy,Xy=function(t){return t.match(/.{6}/g).map(function(t){return"#"+t})},$y=Xy("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"),Vy=Xy("393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6"),Wy=Xy("3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9"),Zy=Xy("1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5"),Gy=wl($t(300,.5,0),$t(-240,.5,1)),Jy=wl($t(-100,.75,.35),$t(80,1.5,.8)),Qy=wl($t(260,.75,.35),$t(80,1.5,.8)),Ky=$t(),tg=Sa(Xy("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),ng=Sa(Xy("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),eg=Sa(Xy("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),rg=Sa(Xy("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921")),ig=function(t){return function(){return t}},og=Math.abs,ug=Math.atan2,ag=Math.cos,cg=Math.max,sg=Math.min,fg=Math.sin,lg=Math.sqrt,hg=1e-12,pg=Math.PI,dg=pg/2,vg=2*pg;Oa.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var _g=function(t){return new Oa(t)},yg=function(){function t(t){var a,c,s,f=t.length,l=!1;for(null==i&&(u=o(s=ve())),a=0;a<=f;++a)!(a<f&&r(c=t[a],a,t))===l&&((l=!l)?u.lineStart():u.lineEnd()),l&&u.point(+n(c,a,t),+e(c,a,t));if(s)return u=null,s+""||null}var n=Fa,e=Ia,r=ig(!0),i=null,o=_g,u=null;return t.x=function(e){return arguments.length?(n="function"==typeof e?e:ig(+e),t):n},t.y=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.defined=function(n){return arguments.length?(r="function"==typeof n?n:ig(!!n),t):r},t.curve=function(n){return arguments.length?(o=n,null!=i&&(u=o(i)),t):o},t.context=function(n){return arguments.length?(null==n?i=u=null:u=o(i=n),t):i},t},gg=function(){function t(t){var n,f,l,h,p,d=t.length,v=!1,_=new Array(d),y=new Array(d);for(null==a&&(s=c(p=ve())),n=0;n<=d;++n){if(!(n<d&&u(h=t[n],n,t))===v)if(v=!v)f=n,s.areaStart(),s.lineStart();else{for(s.lineEnd(),s.lineStart(),l=n-1;l>=f;--l)s.point(_[l],y[l]);s.lineEnd(),s.areaEnd()}v&&(_[n]=+e(h,n,t),y[n]=+i(h,n,t),s.point(r?+r(h,n,t):_[n],o?+o(h,n,t):y[n]))}if(p)return s=null,p+""||null}function n(){return yg().defined(u).curve(c).context(a)}var e=Fa,r=null,i=ig(0),o=Ia,u=ig(!0),a=null,c=_g,s=null;return t.x=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),r=null,t):e},t.x0=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.x1=function(n){return arguments.length?(r=null==n?null:"function"==typeof n?n:ig(+n),t):r},t.y=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),o=null,t):i},t.y0=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),t):i},t.y1=function(n){return arguments.length?(o=null==n?null:"function"==typeof n?n:ig(+n),t):o},t.lineX0=t.lineY0=function(){return n().x(e).y(i)},t.lineY1=function(){return n().x(e).y(o)},t.lineX1=function(){return n().x(r).y(i)},t.defined=function(n){return arguments.length?(u="function"==typeof n?n:ig(!!n),t):u},t.curve=function(n){return arguments.length?(c=n,null!=a&&(s=c(a)),t):c},t.context=function(n){return arguments.length?(null==n?a=s=null:s=c(a=n),t):a},t},mg=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},xg=function(t){return t},bg=Ba(_g);Ya.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};var wg=function(){return ja(yg().curve(bg))},Mg=function(){var t=gg().curve(bg),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return ja(e())},delete t.lineX0,t.lineEndAngle=function(){return ja(r())},delete t.lineX1,t.lineInnerRadius=function(){return ja(i())},delete t.lineY0,t.lineOuterRadius=function(){return ja(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(Ba(t)):n()._curve},t},Tg=function(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]},kg=Array.prototype.slice,Ng={draw:function(t,n){var e=Math.sqrt(n/pg);t.moveTo(e,0),t.arc(0,0,e,0,vg)}},Sg={draw:function(t,n){var e=Math.sqrt(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}},Eg=Math.sqrt(1/3),Ag=2*Eg,Cg={draw:function(t,n){var e=Math.sqrt(n/Ag),r=e*Eg;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},zg=Math.sin(pg/10)/Math.sin(7*pg/10),Pg=Math.sin(vg/10)*zg,Rg=-Math.cos(vg/10)*zg,Lg={draw:function(t,n){var e=Math.sqrt(.8908130915292852*n),r=Pg*e,i=Rg*e;t.moveTo(0,-e),t.lineTo(r,i);for(var o=1;o<5;++o){var u=vg*o/5,a=Math.cos(u),c=Math.sin(u);t.lineTo(c*e,-a*e),t.lineTo(a*r-c*i,c*r+a*i)}t.closePath()}},qg={draw:function(t,n){var e=Math.sqrt(n),r=-e/2;t.rect(r,r,e,e)}},Ug=Math.sqrt(3),Dg={draw:function(t,n){var e=-Math.sqrt(n/(3*Ug));t.moveTo(0,2*e),t.lineTo(-Ug*e,-e),t.lineTo(Ug*e,-e),t.closePath()}},Og=-.5,Fg=Math.sqrt(3)/2,Ig=1/Math.sqrt(12),Yg=3*(Ig/2+1),Bg={draw:function(t,n){var e=Math.sqrt(n/Yg),r=e/2,i=e*Ig,o=r,u=e*Ig+e,a=-o,c=u;t.moveTo(r,i),t.lineTo(o,u),t.lineTo(a,c),t.lineTo(Og*r-Fg*i,Fg*r+Og*i),t.lineTo(Og*o-Fg*u,Fg*o+Og*u),t.lineTo(Og*a-Fg*c,Fg*a+Og*c),t.lineTo(Og*r+Fg*i,Og*i-Fg*r),t.lineTo(Og*o+Fg*u,Og*u-Fg*o),t.lineTo(Og*a+Fg*c,Og*c-Fg*a),t.closePath()}},jg=[Ng,Sg,Cg,qg,Lg,Dg,Bg],Hg=function(){};Ja.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:Ga(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:Ga(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};Qa.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:Ga(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};Ka.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:Ga(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}};tc.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],u=t[e]-i,a=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*u),this._beta*n[c]+(1-this._beta)*(o+r*a));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var Xg=function t(n){function e(t){return 1===n?new Ja(t):new tc(t,n)}return e.beta=function(n){return t(+n)},e}(.85);ec.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:nc(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:nc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var $g=function t(n){function e(t){return new ec(t,n)}return e.tension=function(n){return t(+n)},e}(0);rc.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:nc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Vg=function t(n){function e(t){return new rc(t,n)}return e.tension=function(n){return t(+n)},e}(0);ic.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:nc(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Wg=function t(n){function e(t){return new ic(t,n)}return e.tension=function(n){return t(+n)},e}(0);uc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:oc(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Zg=function t(n){function e(t){return n?new uc(t,n):new ec(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);ac.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:oc(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Gg=function t(n){function e(t){return n?new ac(t,n):new rc(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);cc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:oc(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Jg=function t(n){function e(t){return n?new cc(t,n):new ic(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);sc.prototype={areaStart:Hg,areaEnd:Hg,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}};dc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:pc(this,this._t0,hc(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(t=+t,n=+n,t!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,pc(this,hc(this,e=lc(this,t,n)),e);break;default:pc(this,this._t0,e=lc(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(vc.prototype=Object.create(dc.prototype)).point=function(t,n){dc.prototype.point.call(this,n,t)},_c.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},yc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=gc(t),i=gc(n),o=0,u=1;u<e;++o,++u)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[u],n[u]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}};mc.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}};var Qg=function(t,n){if((i=t.length)>1)for(var e,r,i,o=1,u=t[n[0]],a=u.length;o<i;++o)for(r=u,u=t[n[o]],e=0;e<a;++e)u[e][1]+=u[e][0]=isNaN(r[e][1])?r[e][0]:r[e][1]},Kg=function(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e},tm=function(t){var n=t.map(bc);return Kg(t).sort(function(t,e){return n[t]-n[e]})},nm=function(t){return function(){return t}};Tc.prototype={constructor:Tc,insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=Ec(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)e===(r=e.U).L?(i=r.R)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(Nc(this,e),e=(t=e).U),e.C=!1,r.C=!0,Sc(this,r)):(i=r.L)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(Sc(this,e),e=(t=e).U),e.C=!1,r.C=!0,Nc(this,r)),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,u=t.R;if(e=o?u?Ec(u):o:u,i?i.L===t?i.L=e:i.R=e:this._=e,o&&u?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==u?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=u,u.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r)if(t&&t.C)t.C=!1;else{do{if(t===this._)break;if(t===i.L){if((n=i.R).C&&(n.C=!1,i.C=!0,Nc(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,Sc(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,Nc(this,i),t=this._;break}}else if((n=i.L).C&&(n.C=!1,i.C=!0,Sc(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,Nc(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,Sc(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};var em,rm,im,om,um,am=[],cm=[],sm=1e-6,fm=1e-12;Kc.prototype={constructor:Kc,polygons:function(){var t=this.edges;return this.cells.map(function(n){var e=n.halfedges.map(function(e){return Dc(n,t[e])});return e.data=n.site.data,e})},triangles:function(){var t=[],n=this.edges;return this.cells.forEach(function(e,r){if(o=(i=e.halfedges).length)for(var i,o,u,a=e.site,c=-1,s=n[i[o-1]],f=s.left===a?s.right:s.left;++c<o;)u=f,f=(s=n[i[c]]).left===a?s.right:s.left,u&&f&&r<u.index&&r<f.index&&Jc(a,u,f)<0&&t.push([a.data,u.data,f.data])}),t},links:function(){return this.edges.filter(function(t){return t.right}).map(function(t){return{source:t.left.data,target:t.right.data}})},find:function(t,n,e){for(var r,i,o=this,u=o._found||0,a=o.cells.length;!(i=o.cells[u]);)if(++u>=a)return null;var c=t-i.site[0],s=n-i.site[1],f=c*c+s*s;do{i=o.cells[r=u],u=null,i.halfedges.forEach(function(e){var r=o.edges[e],a=r.left;if(a!==i.site&&a||(a=r.right)){var c=t-a[0],s=n-a[1],l=c*c+s*s;l<f&&(f=l,u=a.index)}})}while(null!==u);return o._found=r,null==e||f<=e*e?i.site:null}};var lm=function(t){return function(){return t}};ns.prototype={constructor:ns,scale:function(t){return 1===t?this:new ns(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new ns(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var hm=new ns(1,0,0);es.prototype=ns.prototype;var pm=function(){t.event.preventDefault(),t.event.stopImmediatePropagation()};t.version="4.10.0",t.bisect=hs,t.bisectRight=hs,t.bisectLeft=ps,t.ascending=ss,t.bisector=fs,t.cross=function(t,n,r){var i,o,u,a,c=t.length,s=n.length,f=new Array(c*s);for(null==r&&(r=e),i=u=0;i<c;++i)for(a=t[i],o=0;o<s;++o,++u)f[u]=r(a,n[o]);return f},t.descending=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},t.deviation=_s,t.extent=ys,t.histogram=function(){function t(t){var o,u,a=t.length,c=new Array(a);for(o=0;o<a;++o)c[o]=n(t[o],o,t);var s=e(c),f=s[0],l=s[1],h=r(c,f,l);Array.isArray(h)||(h=i(f,l,h),h=Ms(Math.ceil(f/h)*h,Math.floor(l/h)*h,h));for(var p=h.length;h[0]<=f;)h.shift(),--p;for(;h[p-1]>l;)h.pop(),--p;var d,v=new Array(p+1);for(o=0;o<=p;++o)(d=v[o]=[]).x0=o>0?h[o-1]:f,d.x1=o<p?h[o]:l;for(o=0;o<a;++o)f<=(u=c[o])&&u<=l&&v[hs(h,u,0,p)].push(t[o]);return v}var n=ws,e=ys,r=Es;return t.value=function(e){return arguments.length?(n="function"==typeof e?e:bs(e),t):n},t.domain=function(n){return arguments.length?(e="function"==typeof n?n:bs([n[0],n[1]]),t):e},t.thresholds=function(n){return arguments.length?(r="function"==typeof n?n:bs(Array.isArray(n)?ms.call(n):n),t):r},t},t.thresholdFreedmanDiaconis=function(t,n,e){return t=xs.call(t,ds).sort(ss),Math.ceil((e-n)/(2*(As(t,.75)-As(t,.25))*Math.pow(t.length,-1/3)))},t.thresholdScott=function(t,n,e){return Math.ceil((e-n)/(3.5*_s(t)*Math.pow(t.length,-1/3)))},t.thresholdSturges=Es,t.max=function(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&e>r&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&e>r&&(r=e);return r},t.mean=function(t,n){var e,r=t.length,i=r,o=-1,u=0;if(null==n)for(;++o<r;)isNaN(e=ds(t[o]))?--i:u+=e;else for(;++o<r;)isNaN(e=ds(n(t[o],o,t)))?--i:u+=e;if(i)return u/i},t.median=function(t,n){var e,r=t.length,i=-1,o=[];if(null==n)for(;++i<r;)isNaN(e=ds(t[i]))||o.push(e);else for(;++i<r;)isNaN(e=ds(n(t[i],i,t)))||o.push(e);return As(o.sort(ss),.5)},t.merge=Cs,t.min=zs,t.pairs=function(t,n){null==n&&(n=e);for(var r=0,i=t.length-1,o=t[0],u=new Array(i<0?0:i);r<i;)u[r]=n(o,o=t[++r]);return u},t.permute=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},t.quantile=As,t.range=Ms,t.scan=function(t,n){if(e=t.length){var e,r,i=0,o=0,u=t[o];for(null==n&&(n=ss);++i<e;)(n(r=t[i],u)<0||0!==n(u,u))&&(u=r,o=i);return 0===n(u,u)?o:void 0}},t.shuffle=function(t,n,e){for(var r,i,o=(null==e?t.length:e)-(n=null==n?0:+n);o;)i=Math.random()*o--|0,r=t[o+n],t[o+n]=t[i+n],t[i+n]=r;return t},t.sum=function(t,n){var e,r=t.length,i=-1,o=0;if(null==n)for(;++i<r;)(e=+t[i])&&(o+=e);else for(;++i<r;)(e=+n(t[i],i,t))&&(o+=e);return o},t.ticks=Ss,t.tickIncrement=r,t.tickStep=i,t.transpose=Ps,t.variance=vs,t.zip=function(){return Ps(arguments)},t.axisTop=function(t){return l(qs,t)},t.axisRight=function(t){return l(Us,t)},t.axisBottom=function(t){return l(Ds,t)},t.axisLeft=function(t){return l(Os,t)},t.brush=function(){return he(Sh)},t.brushX=function(){return he(kh)},t.brushY=function(){return he(Nh)},t.brushSelection=function(t){var n=t.__brush;return n?n.dim.output(n.selection):null},t.chord=function(){function t(t){var o,u,a,c,s,f,l=t.length,h=[],p=Ms(l),d=[],v=[],_=v.groups=new Array(l),y=new Array(l*l);for(o=0,s=-1;++s<l;){for(u=0,f=-1;++f<l;)u+=t[s][f];h.push(u),d.push(Ms(l)),o+=u}for(e&&p.sort(function(t,n){return e(h[t],h[n])}),r&&d.forEach(function(n,e){n.sort(function(n,i){return r(t[e][n],t[e][i])})}),c=(o=Oh(0,Dh-n*l)/o)?n:Dh/l,u=0,s=-1;++s<l;){for(a=u,f=-1;++f<l;){var g=p[s],m=d[g][f],x=t[g][m],b=u,w=u+=x*o;y[m*l+g]={index:g,subindex:m,startAngle:b,endAngle:w,value:x}}_[g]={index:g,startAngle:a,endAngle:u,value:h[g]},u+=c}for(s=-1;++s<l;)for(f=s-1;++f<l;){var M=y[f*l+s],T=y[s*l+f];(M.value||T.value)&&v.push(M.value<T.value?{source:T,target:M}:{source:M,target:T})}return i?v.sort(i):v}var n=0,e=null,r=null,i=null;return t.padAngle=function(e){return arguments.length?(n=Oh(0,e),t):n},t.sortGroups=function(n){return arguments.length?(e=n,t):e},t.sortSubgroups=function(n){return arguments.length?(r=n,t):r},t.sortChords=function(n){return arguments.length?(null==n?i=null:(i=pe(n))._=n,t):i&&i._},t},t.ribbon=function(){function t(){var t,a=Fh.call(arguments),c=n.apply(this,a),s=e.apply(this,a),f=+r.apply(this,(a[0]=c,a)),l=i.apply(this,a)-Uh,h=o.apply(this,a)-Uh,p=f*Rh(l),d=f*Lh(l),v=+r.apply(this,(a[0]=s,a)),_=i.apply(this,a)-Uh,y=o.apply(this,a)-Uh;if(u||(u=t=ve()),u.moveTo(p,d),u.arc(0,0,f,l,h),l===_&&h===y||(u.quadraticCurveTo(0,0,v*Rh(_),v*Lh(_)),u.arc(0,0,v,_,y)),u.quadraticCurveTo(0,0,p,d),u.closePath(),t)return u=null,t+""||null}var n=_e,e=ye,r=ge,i=me,o=xe,u=null;return t.radius=function(n){return arguments.length?(r="function"==typeof n?n:Ih(+n),t):r},t.startAngle=function(n){return arguments.length?(i="function"==typeof n?n:Ih(+n),t):i},t.endAngle=function(n){return arguments.length?(o="function"==typeof n?n:Ih(+n),t):o},t.source=function(e){return arguments.length?(n=e,t):n},t.target=function(n){return arguments.length?(e=n,t):e},t.context=function(n){return arguments.length?(u=null==n?null:n,t):u},t},t.nest=function(){function t(n,i,u,a){if(i>=o.length)return null!=e&&n.sort(e),null!=r?r(n):n;for(var c,s,f,l=-1,h=n.length,p=o[i++],d=we(),v=u();++l<h;)(f=d.get(c=p(s=n[l])+""))?f.push(s):d.set(c,[s]);return d.each(function(n,e){a(v,e,t(n,i,u,a))}),v}function n(t,e){if(++e>o.length)return t;var i,a=u[e-1];return null!=r&&e>=o.length?i=t.entries():(i=[],t.each(function(t,r){i.push({key:r,values:n(t,e)})})),null!=a?i.sort(function(t,n){return a(t.key,n.key)}):i}var e,r,i,o=[],u=[];return i={object:function(n){return t(n,0,Me,Te)},map:function(n){return t(n,0,ke,Ne)},entries:function(e){return n(t(e,0,ke,Ne),0)},key:function(t){return o.push(t),i},sortKeys:function(t){return u[o.length-1]=t,i},sortValues:function(t){return e=t,i},rollup:function(t){return r=t,i}}},t.set=Ee,t.map=we,t.keys=function(t){var n=[];for(var e in t)n.push(e);return n},t.values=function(t){var n=[];for(var e in t)n.push(t[e]);return n},t.entries=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},t.color=Tt,t.rgb=Et,t.hsl=Pt,t.lab=Ut,t.hcl=jt,t.cubehelix=$t,t.dispatch=h,t.drag=function(){function n(t){t.on("mousedown.drag",e).filter(bt).on("touchstart.drag",o).on("touchmove.drag",u).on("touchend.drag touchcancel.drag",a).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function e(){if(!p&&d.apply(this,arguments)){var n=c("mouse",v.apply(this,arguments),Ks,this,arguments);n&&(cf(t.event.view).on("mousemove.drag",r,!0).on("mouseup.drag",i,!0),lf(t.event.view),vt(),l=!1,s=t.event.clientX,f=t.event.clientY,n("start"))}}function r(){if(ff(),!l){var n=t.event.clientX-s,e=t.event.clientY-f;l=n*n+e*e>x}y.mouse("drag")}function i(){cf(t.event.view).on("mousemove.drag mouseup.drag",null),_t(t.event.view,l),ff(),y.mouse("end")}function o(){if(d.apply(this,arguments)){var n,e,r=t.event.changedTouches,i=v.apply(this,arguments),o=r.length;for(n=0;n<o;++n)(e=c(r[n].identifier,i,sf,this,arguments))&&(vt(),e("start"))}}function u(){var n,e,r=t.event.changedTouches,i=r.length;for(n=0;n<i;++n)(e=y[r[n].identifier])&&(ff(),e("drag"))}function a(){var n,e,r=t.event.changedTouches,i=r.length;for(p&&clearTimeout(p),p=setTimeout(function(){p=null},500),n=0;n<i;++n)(e=y[r[n].identifier])&&(vt(),e("end"))}function c(e,r,i,o,u){var a,c,s,f=i(r,e),l=g.copy();if(N(new yt(n,"beforestart",a,e,m,f[0],f[1],0,0,l),function(){return null!=(t.event.subject=a=_.apply(o,u))&&(c=a.x-f[0]||0,s=a.y-f[1]||0,!0)}))return function t(h){var p,d=f;switch(h){case"start":y[e]=t,p=m++;break;case"end":delete y[e],--m;case"drag":f=i(r,e),p=m}N(new yt(n,h,a,e,p,f[0]+c,f[1]+s,f[0]-d[0],f[1]-d[1],l),l.apply,l,[h,o,u])}}var s,f,l,p,d=gt,v=mt,_=xt,y={},g=h("start","drag","end"),m=0,x=0;return n.filter=function(t){return arguments.length?(d="function"==typeof t?t:hf(!!t),n):d},n.container=function(t){return arguments.length?(v="function"==typeof t?t:hf(t),n):v},n.subject=function(t){return arguments.length?(_="function"==typeof t?t:hf(t),n):_},n.on=function(){var t=g.on.apply(g,arguments);return t===g?n:t},n.clickDistance=function(t){return arguments.length?(x=(t=+t)*t,n):Math.sqrt(x)},n},t.dragDisable=lf,t.dragEnable=_t,t.dsvFormat=Xh,t.csvParse=Vh,t.csvParseRows=Wh,t.csvFormat=Zh,t.csvFormatRows=Gh,t.tsvParse=Qh,t.tsvParseRows=Kh,t.tsvFormat=tp,t.tsvFormatRows=np,t.easeLinear=function(t){return+t},t.easeQuad=Kn,t.easeQuadIn=function(t){return t*t},t.easeQuadOut=function(t){return t*(2-t)},t.easeQuadInOut=Kn,t.easeCubic=te,t.easeCubicIn=function(t){return t*t*t},t.easeCubicOut=function(t){return--t*t*t+1},t.easeCubicInOut=te,t.easePoly=Gl,t.easePolyIn=Wl,t.easePolyOut=Zl,t.easePolyInOut=Gl,t.easeSin=ne,t.easeSinIn=function(t){return 1-Math.cos(t*Ql)},t.easeSinOut=function(t){return Math.sin(t*Ql)},t.easeSinInOut=ne,t.easeExp=ee,t.easeExpIn=function(t){return Math.pow(2,10*t-10)},t.easeExpOut=function(t){return 1-Math.pow(2,-10*t)},t.easeExpInOut=ee,t.easeCircle=re,t.easeCircleIn=function(t){return 1-Math.sqrt(1-t*t)},t.easeCircleOut=function(t){return Math.sqrt(1- --t*t)},t.easeCircleInOut=re,t.easeBounce=ie,t.easeBounceIn=function(t){return 1-ie(1-t)},t.easeBounceOut=ie,t.easeBounceInOut=function(t){return((t*=2)<=1?1-ie(1-t):ie(t-1)+1)/2},t.easeBack=lh,t.easeBackIn=sh,t.easeBackOut=fh,t.easeBackInOut=lh,t.easeElastic=dh,t.easeElasticIn=ph,t.easeElasticOut=dh,t.easeElasticInOut=vh,t.forceCenter=function(t,n){function e(){var e,i,o=r.length,u=0,a=0;for(e=0;e<o;++e)u+=(i=r[e]).x,a+=i.y;for(u=u/o-t,a=a/o-n,e=0;e<o;++e)(i=r[e]).x-=u,i.y-=a}var r;return null==t&&(t=0),null==n&&(n=0),e.initialize=function(t){r=t},e.x=function(n){return arguments.length?(t=+n,e):t},e.y=function(t){return arguments.length?(n=+t,e):n},e},t.forceCollide=function(t){function n(){for(var t,n,r,c,s,f,l,h=i.length,p=0;p<a;++p)for(n=qe(i,Oe,Fe).visitAfter(e),t=0;t<h;++t)r=i[t],f=o[r.index],l=f*f,c=r.x+r.vx,s=r.y+r.vy,n.visit(function(t,n,e,i,o){var a=t.data,h=t.r,p=f+h;if(!a)return n>c+p||i<c-p||e>s+p||o<s-p;if(a.index>r.index){var d=c-a.x-a.vx,v=s-a.y-a.vy,_=d*d+v*v;_<p*p&&(0===d&&(d=rp(),_+=d*d),0===v&&(v=rp(),_+=v*v),_=(p-(_=Math.sqrt(_)))/_*u,r.vx+=(d*=_)*(p=(h*=h)/(l+h)),r.vy+=(v*=_)*p,a.vx-=d*(p=1-p),a.vy-=v*p)}})}function e(t){if(t.data)return t.r=o[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function r(){if(i){var n,e,r=i.length;for(o=new Array(r),n=0;n<r;++n)e=i[n],o[e.index]=+t(e,n,i)}}var i,o,u=1,a=1;return"function"!=typeof t&&(t=ep(null==t?1:+t)),n.initialize=function(t){i=t,r()},n.iterations=function(t){return arguments.length?(a=+t,n):a},n.strength=function(t){return arguments.length?(u=+t,n):u},n.radius=function(e){return arguments.length?(t="function"==typeof e?e:ep(+e),r(),n):t},n},t.forceLink=function(t){function n(n){for(var e=0,r=t.length;e<p;++e)for(var i,a,c,f,l,h,d,v=0;v<r;++v)a=(i=t[v]).source,f=(c=i.target).x+c.vx-a.x-a.vx||rp(),l=c.y+c.vy-a.y-a.vy||rp(),f*=h=((h=Math.sqrt(f*f+l*l))-u[v])/h*n*o[v],l*=h,c.vx-=f*(d=s[v]),c.vy-=l*d,a.vx+=f*(d=1-d),a.vy+=l*d}function e(){if(a){var n,e,l=a.length,h=t.length,p=we(a,f);for(n=0,c=new Array(l);n<h;++n)(e=t[n]).index=n,"object"!=typeof e.source&&(e.source=Ye(p,e.source)),"object"!=typeof e.target&&(e.target=Ye(p,e.target)),c[e.source.index]=(c[e.source.index]||0)+1,c[e.target.index]=(c[e.target.index]||0)+1;for(n=0,s=new Array(h);n<h;++n)e=t[n],s[n]=c[e.source.index]/(c[e.source.index]+c[e.target.index]);o=new Array(h),r(),u=new Array(h),i()}}function r(){if(a)for(var n=0,e=t.length;n<e;++n)o[n]=+l(t[n],n,t)}function i(){if(a)for(var n=0,e=t.length;n<e;++n)u[n]=+h(t[n],n,t)}var o,u,a,c,s,f=Ie,l=function(t){return 1/Math.min(c[t.source.index],c[t.target.index])},h=ep(30),p=1;return null==t&&(t=[]),n.initialize=function(t){a=t,e()},n.links=function(r){return arguments.length?(t=r,e(),n):t},n.id=function(t){return arguments.length?(f=t,n):f},n.iterations=function(t){return arguments.length?(p=+t,n):p},n.strength=function(t){return arguments.length?(l="function"==typeof t?t:ep(+t),r(),n):l},n.distance=function(t){return arguments.length?(h="function"==typeof t?t:ep(+t),i(),n):h},n},t.forceManyBody=function(){function t(t){var n,a=i.length,c=qe(i,Be,je).visitAfter(e);for(u=t,n=0;n<a;++n)o=i[n],c.visit(r)}function n(){if(i){var t,n,e=i.length;for(a=new Array(e),t=0;t<e;++t)n=i[t],a[n.index]=+c(n,t,i)}}function e(t){var n,e,r,i,o,u=0;if(t.length){for(r=i=o=0;o<4;++o)(n=t[o])&&(e=n.value)&&(u+=e,r+=e*n.x,i+=e*n.y);t.x=r/u,t.y=i/u}else{(n=t).x=n.data.x,n.y=n.data.y;do{u+=a[n.data.index]}while(n=n.next)}t.value=u}function r(t,n,e,r){if(!t.value)return!0;var i=t.x-o.x,c=t.y-o.y,h=r-n,p=i*i+c*c;if(h*h/l<p)return p<f&&(0===i&&(i=rp(),p+=i*i),0===c&&(c=rp(),p+=c*c),p<s&&(p=Math.sqrt(s*p)),o.vx+=i*t.value*u/p,o.vy+=c*t.value*u/p),!0;if(!(t.length||p>=f)){(t.data!==o||t.next)&&(0===i&&(i=rp(),p+=i*i),0===c&&(c=rp(),p+=c*c),p<s&&(p=Math.sqrt(s*p)));do{t.data!==o&&(h=a[t.data.index]*u/p,o.vx+=i*h,o.vy+=c*h)}while(t=t.next)}}var i,o,u,a,c=ep(-30),s=1,f=1/0,l=.81;return t.initialize=function(t){i=t,n()},t.strength=function(e){return arguments.length?(c="function"==typeof e?e:ep(+e),n(),t):c},t.distanceMin=function(n){return arguments.length?(s=n*n,t):Math.sqrt(s)},t.distanceMax=function(n){return arguments.length?(f=n*n,t):Math.sqrt(f)},t.theta=function(n){return arguments.length?(l=n*n,t):Math.sqrt(l)},t},t.forceSimulation=function(t){function n(){e(),d.call("tick",o),u<a&&(p.stop(),d.call("end",o))}function e(){var n,e,r=t.length;for(u+=(s-u)*c,l.each(function(t){t(u)}),n=0;n<r;++n)null==(e=t[n]).fx?e.x+=e.vx*=f:(e.x=e.fx,e.vx=0),null==e.fy?e.y+=e.vy*=f:(e.y=e.fy,e.vy=0)}function r(){for(var n,e=0,r=t.length;e<r;++e){if(n=t[e],n.index=e,isNaN(n.x)||isNaN(n.y)){var i=ap*Math.sqrt(e),o=e*cp;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function i(n){return n.initialize&&n.initialize(t),n}var o,u=1,a=.001,c=1-Math.pow(a,1/300),s=0,f=.6,l=we(),p=dn(n),d=h("tick","end");return null==t&&(t=[]),r(),o={tick:e,restart:function(){return p.restart(n),o},stop:function(){return p.stop(),o},nodes:function(n){return arguments.length?(t=n,r(),l.each(i),o):t},alpha:function(t){return arguments.length?(u=+t,o):u},alphaMin:function(t){return arguments.length?(a=+t,o):a},alphaDecay:function(t){return arguments.length?(c=+t,o):+c},alphaTarget:function(t){return arguments.length?(s=+t,o):s},velocityDecay:function(t){return arguments.length?(f=1-t,o):1-f},force:function(t,n){return arguments.length>1?(null==n?l.remove(t):l.set(t,i(n)),o):l.get(t)},find:function(n,e,r){var i,o,u,a,c,s=0,f=t.length;for(null==r?r=1/0:r*=r,s=0;s<f;++s)(u=(i=n-(a=t[s]).x)*i+(o=e-a.y)*o)<r&&(c=a,r=u);return c},on:function(t,n){return arguments.length>1?(d.on(t,n),o):d.on(t)}}},t.forceX=function(t){function n(t){for(var n,e=0,u=r.length;e<u;++e)(n=r[e]).vx+=(o[e]-n.x)*i[e]*t}function e(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)i[n]=isNaN(o[n]=+t(r[n],n,r))?0:+u(r[n],n,r)}}var r,i,o,u=ep(.1);return"function"!=typeof t&&(t=ep(null==t?0:+t)),n.initialize=function(t){r=t,e()},n.strength=function(t){return arguments.length?(u="function"==typeof t?t:ep(+t),e(),n):u},n.x=function(r){return arguments.length?(t="function"==typeof r?r:ep(+r),e(),n):t},n},t.forceY=function(t){function n(t){for(var n,e=0,u=r.length;e<u;++e)(n=r[e]).vy+=(o[e]-n.y)*i[e]*t}function e(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)i[n]=isNaN(o[n]=+t(r[n],n,r))?0:+u(r[n],n,r)}}var r,i,o,u=ep(.1);return"function"!=typeof t&&(t=ep(null==t?0:+t)),n.initialize=function(t){r=t,e()},n.strength=function(t){return arguments.length?(u="function"==typeof t?t:ep(+t),e(),n):u},n.y=function(r){return arguments.length?(t="function"==typeof r?r:ep(+r),e(),n):t},n},t.formatDefaultLocale=$e,t.formatLocale=mp,t.formatSpecifier=He,t.precisionFixed=xp,t.precisionPrefix=bp,t.precisionRound=wp,t.geoArea=function(t){return kd.reset(),Md(t,Nd),2*kd},t.geoBounds=function(t){var n,e,r,i,o,u,a;if(Pp=zp=-(Ap=Cp=1/0),Dp=[],Md(t,Ed),e=Dp.length){for(Dp.sort(br),n=1,o=[r=Dp[0]];n<e;++n)wr(r,(i=Dp[n])[0])||wr(r,i[1])?(xr(r[0],i[1])>xr(r[0],r[1])&&(r[1]=i[1]),xr(i[0],r[1])>xr(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(u=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(a=xr(r[1],i[0]))>u&&(u=a,Ap=i[0],zp=r[1])}return Dp=Op=null,Ap===1/0||Cp===1/0?[[NaN,NaN],[NaN,NaN]]:[[Ap,Cp],[zp,Pp]]},t.geoCentroid=function(t){Fp=Ip=Yp=Bp=jp=Hp=Xp=$p=Vp=Wp=Zp=0,Md(t,Ad);var n=Vp,e=Wp,r=Zp,i=n*n+e*e+r*r;return i<1e-12&&(n=Hp,e=Xp,r=$p,Ip<ed&&(n=Yp,e=Bp,r=jp),(i=n*n+e*e+r*r)<1e-12)?[NaN,NaN]:[ld(e,n)*ad,Ge(r/md(i))*ad]},t.geoCircle=function(){function t(){var t=r.apply(this,arguments),a=i.apply(this,arguments)*cd,c=o.apply(this,arguments)*cd;return n=[],e=Lr(-t[0]*cd,-t[1]*cd,0).invert,Or(u,a,c,1),t={type:"Polygon",coordinates:[n]},n=e=null,t}var n,e,r=Cd([0,0]),i=Cd(90),o=Cd(6),u={point:function(t,r){n.push(t=e(t,r)),t[0]*=ad,t[1]*=ad}};return t.center=function(n){return arguments.length?(r="function"==typeof n?n:Cd([+n[0],+n[1]]),t):r},t.radius=function(n){return arguments.length?(i="function"==typeof n?n:Cd(+n),t):i},t.precision=function(n){return arguments.length?(o="function"==typeof n?n:Cd(+n),t):o},t},t.geoClipExtent=function(){var t,n,e,r=0,i=0,o=960,u=500;return e={stream:function(e){return t&&n===e?t:t=Br(r,i,o,u)(n=e)},extent:function(a){return arguments.length?(r=+a[0][0],i=+a[0][1],o=+a[1][0],u=+a[1][1],t=n=null,e):[[r,i],[o,u]]}}},t.geoContains=function(t,n){return(t&&iv.hasOwnProperty(t.type)?iv[t.type]:$r)(t,n)},t.geoDistance=rv,t.geoGraticule=ti,t.geoGraticule10=function(){return ti()()},t.geoInterpolate=function(t,n){var e=t[0]*cd,r=t[1]*cd,i=n[0]*cd,o=n[1]*cd,u=hd(r),a=yd(r),c=hd(o),s=yd(o),f=u*hd(e),l=u*yd(e),h=c*hd(i),p=c*yd(i),d=2*Ge(md(Je(o-r)+u*c*Je(i-e))),v=yd(d),_=d?function(t){var n=yd(t*=d)/v,e=yd(d-t)/v,r=e*f+n*h,i=e*l+n*p,o=e*a+n*s;return[ld(i,r)*ad,ld(o,md(r*r+i*i))*ad]}:function(){return[e*ad,r*ad]};return _.distance=d,_},t.geoLength=tv,t.geoPath=function(t,n){function e(t){return t&&("function"==typeof o&&i.pointRadius(+o.apply(this,arguments)),Md(t,r(i))),i.result()}var r,i,o=4.5;return e.area=function(t){return Md(t,r(sv)),sv.result()},e.measure=function(t){return Md(t,r(zv)),zv.result()},e.bounds=function(t){return Md(t,r(dv)),dv.result()},e.centroid=function(t){return Md(t,r(Tv)),Tv.result()},e.projection=function(n){return arguments.length?(r=null==n?(t=null,uv):(t=n).stream,e):t},e.context=function(t){return arguments.length?(i=null==t?(n=null,new yi):new di(n=t),"function"!=typeof o&&i.pointRadius(o),e):n},e.pointRadius=function(t){return arguments.length?(o="function"==typeof t?t:(i.pointRadius(+t),+t),e):o},e.projection(t).context(n)},t.geoAlbers=Iv,t.geoAlbersUsa=function(){function t(t){var n=t[0],e=t[1];return a=null,i.point(n,e),a||(o.point(n,e),a)||(u.point(n,e),a)}function n(){return e=r=null,t}var e,r,i,o,u,a,c=Iv(),s=Fv().rotate([154,0]).center([-2,58.5]).parallels([55,65]),f=Fv().rotate([157,0]).center([-3,19.9]).parallels([8,18]),l={point:function(t,n){a=[t,n]}};return t.invert=function(t){var n=c.scale(),e=c.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?s:i>=.166&&i<.234&&r>=-.214&&r<-.115?f:c).invert(t)},t.stream=function(t){return e&&r===t?e:e=Ri([c.stream(r=t),s.stream(t),f.stream(t)])},t.precision=function(t){return arguments.length?(c.precision(t),s.precision(t),f.precision(t),n()):c.precision()},t.scale=function(n){return arguments.length?(c.scale(n),s.scale(.35*n),f.scale(n),t.translate(c.translate())):c.scale()},t.translate=function(t){if(!arguments.length)return c.translate();var e=c.scale(),r=+t[0],a=+t[1];return i=c.translate(t).clipExtent([[r-.455*e,a-.238*e],[r+.455*e,a+.238*e]]).stream(l),o=s.translate([r-.307*e,a+.201*e]).clipExtent([[r-.425*e+ed,a+.12*e+ed],[r-.214*e-ed,a+.234*e-ed]]).stream(l),u=f.translate([r-.205*e,a+.212*e]).clipExtent([[r-.214*e+ed,a+.166*e+ed],[r-.115*e-ed,a+.234*e-ed]]).stream(l),n()},t.fitExtent=function(n,e){return Ti(t,n,e)},t.fitSize=function(n,e){return ki(t,n,e)},t.scale(1070)},t.geoAzimuthalEqualArea=function(){return Ei(Yv).scale(124.75).clipAngle(179.999)},t.geoAzimuthalEqualAreaRaw=Yv,t.geoAzimuthalEquidistant=function(){return Ei(Bv).scale(79.4188).clipAngle(179.999)},t.geoAzimuthalEquidistantRaw=Bv,t.geoConicConformal=function(){return Ci(Fi).scale(109.5).parallels([30,30])},t.geoConicConformalRaw=Fi,t.geoConicEqualArea=Fv,t.geoConicEqualAreaRaw=Pi,t.geoConicEquidistant=function(){return Ci(Yi).scale(131.154).center([0,13.9389])},t.geoConicEquidistantRaw=Yi,t.geoEquirectangular=function(){return Ei(Ii).scale(152.63)},t.geoEquirectangularRaw=Ii,t.geoGnomonic=function(){return Ei(Bi).scale(144.049).clipAngle(60)},t.geoGnomonicRaw=Bi,t.geoIdentity=function(){function t(){return i=o=null,u}var n,e,r,i,o,u,a=1,c=0,s=0,f=1,l=1,h=uv,p=null,d=uv;return u={stream:function(t){return i&&o===t?i:i=h(d(o=t))},clipExtent:function(i){return arguments.length?(d=null==i?(p=n=e=r=null,uv):Br(p=+i[0][0],n=+i[0][1],e=+i[1][0],r=+i[1][1]),t()):null==p?null:[[p,n],[e,r]]},scale:function(n){return arguments.length?(h=ji((a=+n)*f,a*l,c,s),t()):a},translate:function(n){return arguments.length?(h=ji(a*f,a*l,c=+n[0],s=+n[1]),t()):[c,s]},reflectX:function(n){return arguments.length?(h=ji(a*(f=n?-1:1),a*l,c,s),t()):f<0},reflectY:function(n){return arguments.length?(h=ji(a*f,a*(l=n?-1:1),c,s),t()):l<0},fitExtent:function(t,n){return Ti(u,t,n)},fitSize:function(t,n){return ki(u,t,n)}}},t.geoProjection=Ei,t.geoProjectionMutator=Ai,t.geoMercator=function(){return Di(Ui).scale(961/ud)},t.geoMercatorRaw=Ui,t.geoOrthographic=function(){return Ei(Hi).scale(249.5).clipAngle(90+ed)},t.geoOrthographicRaw=Hi,t.geoStereographic=function(){return Ei(Xi).scale(250).clipAngle(142)},t.geoStereographicRaw=Xi,t.geoTransverseMercator=function(){var t=Di($i),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):(t=n(),[t[1],-t[0]])},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):(t=e(),[t[0],t[1],t[2]-90])},e([0,0,90]).scale(159.155)},t.geoTransverseMercatorRaw=$i,t.geoRotation=jd,t.geoStream=Md,t.geoTransform=function(t){return{stream:wi(t)}},t.cluster=function(){function t(t){var o,u=0;t.eachAfter(function(t){var e=t.children;e?(t.x=Wi(e),t.y=Gi(e)):(t.x=o?u+=n(t,o):0,t.y=0,o=t)});var a=Qi(t),c=Ki(t),s=a.x-n(a,c)/2,f=c.x+n(c,a)/2;return t.eachAfter(i?function(n){n.x=(n.x-t.x)*e,n.y=(t.y-n.y)*r}:function(n){n.x=(n.x-s)/(f-s)*e,n.y=(1-(t.y?n.y/t.y:1))*r})}var n=Vi,e=1,r=1,i=!1;return t.separation=function(e){return arguments.length?(n=e,t):n},t.size=function(n){return arguments.length?(i=!1,e=+n[0],r=+n[1],t):i?null:[e,r]},t.nodeSize=function(n){return arguments.length?(i=!0,e=+n[0],r=+n[1],t):i?[e,r]:null},t},t.hierarchy=eo,t.pack=function(){function t(t){return t.x=e/2,t.y=r/2,n?t.eachBefore(No(n)).eachAfter(So(i,.5)).eachBefore(Eo(1)):t.eachBefore(No(ko)).eachAfter(So(To,1)).eachAfter(So(i,t.r/Math.min(e,r))).eachBefore(Eo(Math.min(e,r)/(2*t.r))),t}var n=null,e=1,r=1,i=To;return t.radius=function(e){return arguments.length?(n=wo(e),t):n},t.size=function(n){return arguments.length?(e=+n[0],r=+n[1],t):[e,r]},t.padding=function(n){return arguments.length?(i="function"==typeof n?n:Xv(+n),t):i},t},t.packSiblings=function(t){return bo(t),t},t.packEnclose=Hv,t.partition=function(){function t(t){var u=t.height+1;return t.x0=t.y0=i,t.x1=e,t.y1=r/u,t.eachBefore(n(r,u)),o&&t.eachBefore($v),t}function n(t,n){return function(e){e.children&&Vv(e,e.x0,t*(e.depth+1)/n,e.x1,t*(e.depth+2)/n);var r=e.x0,o=e.y0,u=e.x1-i,a=e.y1-i;u<r&&(r=u=(r+u)/2),a<o&&(o=a=(o+a)/2),e.x0=r,e.y0=o,e.x1=u,e.y1=a}}var e=1,r=1,i=0,o=!1;return t.round=function(n){return arguments.length?(o=!!n,t):o},t.size=function(n){return arguments.length?(e=+n[0],r=+n[1],t):[e,r]},t.padding=function(n){return arguments.length?(i=+n,t):i},t},t.stratify=function(){function t(t){var r,i,o,u,a,c,s,f=t.length,l=new Array(f),h={};for(i=0;i<f;++i)r=t[i],a=l[i]=new uo(r),null!=(c=n(r,i,t))&&(c+="")&&(h[s=Wv+(a.id=c)]=s in h?Gv:a);for(i=0;i<f;++i)if(a=l[i],null!=(c=e(t[i],i,t))&&(c+="")){if(!(u=h[Wv+c]))throw new Error("missing: "+c);if(u===Gv)throw new Error("ambiguous: "+c);u.children?u.children.push(a):u.children=[a],a.parent=u}else{if(o)throw new Error("multiple roots");o=a}if(!o)throw new Error("no root");if(o.parent=Zv,o.eachBefore(function(t){t.depth=t.parent.depth+1,--f}).eachBefore(oo),o.parent=null,f>0)throw new Error("cycle");return o}var n=Ao,e=Co;return t.id=function(e){return arguments.length?(n=Mo(e),t):n},t.parentId=function(n){return arguments.length?(e=Mo(n),t):e},t},t.tree=function(){function t(t){var r=Oo(t);if(r.eachAfter(n),r.parent.m=-r.z,r.eachBefore(e),c)t.eachBefore(i);else{var s=t,f=t,l=t;t.eachBefore(function(t){t.x<s.x&&(s=t),t.x>f.x&&(f=t),t.depth>l.depth&&(l=t)});var h=s===f?1:o(s,f)/2,p=h-s.x,d=u/(f.x+h+p),v=a/(l.depth||1);t.eachBefore(function(t){t.x=(t.x+p)*d,t.y=t.depth*v})}return t}function n(t){var n=t.children,e=t.parent.children,i=t.i?e[t.i-1]:null;if(n){qo(t);var u=(n[0].z+n[n.length-1].z)/2;i?(t.z=i.z+o(t._,i._),t.m=t.z-u):t.z=u}else i&&(t.z=i.z+o(t._,i._));t.parent.A=r(t,i,t.parent.A||e[0])}function e(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function r(t,n,e){if(n){for(var r,i=t,u=t,a=n,c=i.parent.children[0],s=i.m,f=u.m,l=a.m,h=c.m;a=Ro(a),i=Po(i),a&&i;)c=Po(c),(u=Ro(u)).a=t,(r=a.z+l-i.z-s+o(a._,i._))>0&&(Lo(Uo(a,t,e),t,r),s+=r,f+=r),l+=a.m,s+=i.m,h+=c.m,f+=u.m;a&&!Ro(u)&&(u.t=a,u.m+=l-f),i&&!Po(c)&&(c.t=i,c.m+=s-h,e=t)}return e}function i(t){t.x*=u,t.y=t.depth*a}var o=zo,u=1,a=1,c=null;return t.separation=function(n){return arguments.length?(o=n,t):o},t.size=function(n){return arguments.length?(c=!1,u=+n[0],a=+n[1],t):c?null:[u,a]},t.nodeSize=function(n){return arguments.length?(c=!0,u=+n[0],a=+n[1],t):c?[u,a]:null},t},t.treemap=function(){function t(t){return t.x0=t.y0=0,t.x1=i,t.y1=o,t.eachBefore(n),u=[0],r&&t.eachBefore($v),t}function n(t){var n=u[t.depth],r=t.x0+n,i=t.y0+n,o=t.x1-n,h=t.y1-n;o<r&&(r=o=(r+o)/2),h<i&&(i=h=(i+h)/2),t.x0=r,t.y0=i,t.x1=o,t.y1=h,t.children&&(n=u[t.depth+1]=a(t)/2,r+=l(t)-n,i+=c(t)-n,o-=s(t)-n,h-=f(t)-n,o<r&&(r=o=(r+o)/2),h<i&&(i=h=(i+h)/2),e(t,r,i,o,h))}var e=Kv,r=!1,i=1,o=1,u=[0],a=To,c=To,s=To,f=To,l=To;return t.round=function(n){return arguments.length?(r=!!n,t):r},t.size=function(n){return arguments.length?(i=+n[0],o=+n[1],t):[i,o]},t.tile=function(n){return arguments.length?(e=Mo(n),t):e},t.padding=function(n){return arguments.length?t.paddingInner(n).paddingOuter(n):t.paddingInner()},t.paddingInner=function(n){return arguments.length?(a="function"==typeof n?n:Xv(+n),t):a},t.paddingOuter=function(n){return arguments.length?t.paddingTop(n).paddingRight(n).paddingBottom(n).paddingLeft(n):t.paddingTop()},t.paddingTop=function(n){return arguments.length?(c="function"==typeof n?n:Xv(+n),t):c},t.paddingRight=function(n){return arguments.length?(s="function"==typeof n?n:Xv(+n),t):s},t.paddingBottom=function(n){return arguments.length?(f="function"==typeof n?n:Xv(+n),t):f},t.paddingLeft=function(n){return arguments.length?(l="function"==typeof n?n:Xv(+n),t):l},t},t.treemapBinary=function(t,n,e,r,i){function o(t,n,e,r,i,u,a){if(t>=n-1){var s=c[t];return s.x0=r,s.y0=i,s.x1=u,void(s.y1=a)}for(var l=f[t],h=e/2+l,p=t+1,d=n-1;p<d;){var v=p+d>>>1;f[v]<h?p=v+1:d=v}h-f[p-1]<f[p]-h&&t+1<p&&--p;var _=f[p]-l,y=e-_;if(u-r>a-i){var g=(r*y+u*_)/e;o(t,p,_,r,i,g,a),o(p,n,y,g,i,u,a)}else{var m=(i*y+a*_)/e;o(t,p,_,r,i,u,m),o(p,n,y,r,m,u,a)}}var u,a,c=t.children,s=c.length,f=new Array(s+1);for(f[0]=a=u=0;u<s;++u)f[u+1]=a+=c[u].value;o(0,s,t.value,n,e,r,i)},t.treemapDice=Vv,t.treemapSlice=Jv,t.treemapSliceDice=function(t,n,e,r,i){(1&t.depth?Jv:Vv)(t,n,e,r,i)},t.treemapSquarify=Kv,t.treemapResquarify=t_,t.interpolate=cl,t.interpolateArray=nl,t.interpolateBasis=Zf,t.interpolateBasisClosed=Gf,t.interpolateDate=el,t.interpolateNumber=rl,t.interpolateObject=il,t.interpolateRound=sl,t.interpolateString=al,t.interpolateTransformCss=pl,t.interpolateTransformSvg=dl,t.interpolateZoom=_l,t.interpolateRgb=Qf,t.interpolateRgbBasis=Kf,t.interpolateRgbBasisClosed=tl,t.interpolateHsl=yl,t.interpolateHslLong=gl,t.interpolateLab=function(t,n){var e=Kt((t=Ut(t)).l,(n=Ut(n)).l),r=Kt(t.a,n.a),i=Kt(t.b,n.b),o=Kt(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}},t.interpolateHcl=ml,t.interpolateHclLong=xl,t.interpolateCubehelix=bl,t.interpolateCubehelixLong=wl,t.quantize=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));return e},t.path=ve,t.polygonArea=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},t.polygonCentroid=function(t){for(var n,e,r=-1,i=t.length,o=0,u=0,a=t[i-1],c=0;++r<i;)n=a,a=t[r],c+=e=n[0]*a[1]-a[0]*n[1],o+=(n[0]+a[0])*e,u+=(n[1]+a[1])*e;return c*=3,[o/c,u/c]},t.polygonHull=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(Io),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=Yo(r),u=Yo(i),a=u[0]===o[0],c=u[u.length-1]===o[o.length-1],s=[];for(n=o.length-1;n>=0;--n)s.push(t[r[o[n]][2]]);for(n=+a;n<u.length-c;++n)s.push(t[r[u[n]][2]]);return s},t.polygonContains=function(t,n){for(var e,r,i=t.length,o=t[i-1],u=n[0],a=n[1],c=o[0],s=o[1],f=!1,l=0;l<i;++l)e=(o=t[l])[0],(r=o[1])>a!=s>a&&u<(c-e)*(a-r)/(s-r)+e&&(f=!f),c=e,s=r;return f},t.polygonLength=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],u=o[0],a=o[1],c=0;++r<i;)n=u,e=a,n-=u=(o=t[r])[0],e-=a=o[1],c+=Math.sqrt(n*n+e*e);return c},t.quadtree=qe,t.queue=Wo,t.randomUniform=o_,t.randomNormal=u_,t.randomLogNormal=a_,t.randomBates=s_,t.randomIrwinHall=c_,t.randomExponential=f_,t.request=l_,t.html=p_,t.json=d_,t.text=v_,t.xml=__,t.csv=g_,t.tsv=m_,t.scaleBand=Ko,t.scalePoint=function(){return tu(Ko().paddingInner(1))},t.scaleIdentity=fu,t.scaleLinear=su,t.scaleLog=yu,t.scaleOrdinal=Qo,t.scaleImplicit=M_,t.scalePow=mu,t.scaleSqrt=function(){return mu().exponent(.5)},t.scaleQuantile=xu,t.scaleQuantize=bu,t.scaleThreshold=wu,t.scaleTime=function(){return Na(oy,ry,j_,Y_,F_,D_,q_,z_,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)])},t.scaleUtc=function(){return Na(Ay,Sy,py,ly,sy,ay,q_,z_,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)])},t.schemeCategory10=$y,t.schemeCategory20b=Vy,t.schemeCategory20c=Wy,t.schemeCategory20=Zy,t.interpolateCubehelixDefault=Gy,t.interpolateRainbow=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return Ky.h=360*t-100,Ky.s=1.5-1.5*n,Ky.l=.8-.9*n,Ky+""},t.interpolateWarm=Jy,t.interpolateCool=Qy,t.interpolateViridis=tg,t.interpolateMagma=ng,t.interpolateInferno=eg,t.interpolatePlasma=rg,t.scaleSequential=Ea,t.creator=Hs,t.local=m,t.matcher=Zs,t.mouse=Ks,t.namespace=js,t.namespaces=Bs,t.select=cf,t.selectAll=function(t){return"string"==typeof t?new pt([document.querySelectorAll(t)],[document.documentElement]):new pt([null==t?[]:t],af)},t.selection=dt,t.selector=tf,t.selectorAll=nf,t.style=B,t.touch=sf,t.touches=function(t,n){null==n&&(n=Js().touches);for(var e=0,r=n?n.length:0,i=new Array(r);e<r;++e)i[e]=Qs(t,n[e]);return i},t.window=uf,t.customEvent=N,t.arc=function(){function t(){var t,s,f=+n.apply(this,arguments),l=+e.apply(this,arguments),h=o.apply(this,arguments)-dg,p=u.apply(this,arguments)-dg,d=og(p-h),v=p>h;if(c||(c=t=ve()),l<f&&(s=l,l=f,f=s),l>hg)if(d>vg-hg)c.moveTo(l*ag(h),l*fg(h)),c.arc(0,0,l,h,p,!v),f>hg&&(c.moveTo(f*ag(p),f*fg(p)),c.arc(0,0,f,p,h,v));else{var _,y,g=h,m=p,x=h,b=p,w=d,M=d,T=a.apply(this,arguments)/2,k=T>hg&&(i?+i.apply(this,arguments):lg(f*f+l*l)),N=sg(og(l-f)/2,+r.apply(this,arguments)),S=N,E=N;if(k>hg){var A=Ca(k/f*fg(T)),C=Ca(k/l*fg(T));(w-=2*A)>hg?(A*=v?1:-1,x+=A,b-=A):(w=0,x=b=(h+p)/2),(M-=2*C)>hg?(C*=v?1:-1,g+=C,m-=C):(M=0,g=m=(h+p)/2)}var z=l*ag(g),P=l*fg(g),R=f*ag(b),L=f*fg(b);if(N>hg){var q=l*ag(m),U=l*fg(m),D=f*ag(x),O=f*fg(x);if(d<pg){var F=w>hg?Ua(z,P,D,O,q,U,R,L):[R,L],I=z-F[0],Y=P-F[1],B=q-F[0],j=U-F[1],H=1/fg(Aa((I*B+Y*j)/(lg(I*I+Y*Y)*lg(B*B+j*j)))/2),X=lg(F[0]*F[0]+F[1]*F[1]);S=sg(N,(f-X)/(H-1)),E=sg(N,(l-X)/(H+1))}}M>hg?E>hg?(_=Da(D,O,z,P,l,E,v),y=Da(q,U,R,L,l,E,v),c.moveTo(_.cx+_.x01,_.cy+_.y01),E<N?c.arc(_.cx,_.cy,E,ug(_.y01,_.x01),ug(y.y01,y.x01),!v):(c.arc(_.cx,_.cy,E,ug(_.y01,_.x01),ug(_.y11,_.x11),!v),c.arc(0,0,l,ug(_.cy+_.y11,_.cx+_.x11),ug(y.cy+y.y11,y.cx+y.x11),!v),c.arc(y.cx,y.cy,E,ug(y.y11,y.x11),ug(y.y01,y.x01),!v))):(c.moveTo(z,P),c.arc(0,0,l,g,m,!v)):c.moveTo(z,P),f>hg&&w>hg?S>hg?(_=Da(R,L,q,U,f,-S,v),y=Da(z,P,D,O,f,-S,v),c.lineTo(_.cx+_.x01,_.cy+_.y01),S<N?c.arc(_.cx,_.cy,S,ug(_.y01,_.x01),ug(y.y01,y.x01),!v):(c.arc(_.cx,_.cy,S,ug(_.y01,_.x01),ug(_.y11,_.x11),!v),c.arc(0,0,f,ug(_.cy+_.y11,_.cx+_.x11),ug(y.cy+y.y11,y.cx+y.x11),v),c.arc(y.cx,y.cy,S,ug(y.y11,y.x11),ug(y.y01,y.x01),!v))):c.arc(0,0,f,b,x,v):c.lineTo(R,L)}else c.moveTo(0,0);if(c.closePath(),t)return c=null,t+""||null}var n=za,e=Pa,r=ig(0),i=null,o=Ra,u=La,a=qa,c=null;return t.centroid=function(){var t=(+n.apply(this,arguments)+ +e.apply(this,arguments))/2,r=(+o.apply(this,arguments)+ +u.apply(this,arguments))/2-pg/2;return[ag(r)*t,fg(r)*t]},t.innerRadius=function(e){return arguments.length?(n="function"==typeof e?e:ig(+e),t):n},t.outerRadius=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.cornerRadius=function(n){return arguments.length?(r="function"==typeof n?n:ig(+n),t):r},t.padRadius=function(n){return arguments.length?(i=null==n?null:"function"==typeof n?n:ig(+n),t):i},t.startAngle=function(n){return arguments.length?(o="function"==typeof n?n:ig(+n),t):o},t.endAngle=function(n){return arguments.length?(u="function"==typeof n?n:ig(+n),t):u},t.padAngle=function(n){return arguments.length?(a="function"==typeof n?n:ig(+n),t):a},t.context=function(n){return arguments.length?(c=null==n?null:n,t):c},t},t.area=gg,t.line=yg,t.pie=function(){function t(t){var a,c,s,f,l,h=t.length,p=0,d=new Array(h),v=new Array(h),_=+i.apply(this,arguments),y=Math.min(vg,Math.max(-vg,o.apply(this,arguments)-_)),g=Math.min(Math.abs(y)/h,u.apply(this,arguments)),m=g*(y<0?-1:1);for(a=0;a<h;++a)(l=v[d[a]=a]=+n(t[a],a,t))>0&&(p+=l);for(null!=e?d.sort(function(t,n){return e(v[t],v[n])}):null!=r&&d.sort(function(n,e){return r(t[n],t[e])}),a=0,s=p?(y-h*m)/p:0;a<h;++a,_=f)c=d[a],f=_+((l=v[c])>0?l*s:0)+m,v[c]={data:t[c],index:a,value:l,startAngle:_,endAngle:f,padAngle:g};return v}var n=xg,e=mg,r=null,i=ig(0),o=ig(vg),u=ig(0);return t.value=function(e){return arguments.length?(n="function"==typeof e?e:ig(+e),t):n},t.sortValues=function(n){return arguments.length?(e=n,r=null,t):e},t.sort=function(n){return arguments.length?(r=n,e=null,t):r},t.startAngle=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),t):i},t.endAngle=function(n){return arguments.length?(o="function"==typeof n?n:ig(+n),t):o},t.padAngle=function(n){return arguments.length?(u="function"==typeof n?n:ig(+n),t):u},t},t.areaRadial=Mg,t.radialArea=Mg,t.lineRadial=wg,t.radialLine=wg,t.pointRadial=Tg,t.linkHorizontal=function(){return $a(Va)},t.linkVertical=function(){return $a(Wa)},t.linkRadial=function(){var t=$a(Za);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t},t.symbol=function(){function t(){var t;if(r||(r=t=ve()),n.apply(this,arguments).draw(r,+e.apply(this,arguments)),t)return r=null,t+""||null}var n=ig(Ng),e=ig(64),r=null;return t.type=function(e){return arguments.length?(n="function"==typeof e?e:ig(e),t):n},t.size=function(n){return arguments.length?(e="function"==typeof n?n:ig(+n),t):e},t.context=function(n){return arguments.length?(r=null==n?null:n,t):r},t},t.symbols=jg,t.symbolCircle=Ng,t.symbolCross=Sg,t.symbolDiamond=Cg,t.symbolSquare=qg,t.symbolStar=Lg,t.symbolTriangle=Dg,t.symbolWye=Bg,t.curveBasisClosed=function(t){return new Qa(t)},t.curveBasisOpen=function(t){return new Ka(t)},t.curveBasis=function(t){return new Ja(t)},t.curveBundle=Xg,t.curveCardinalClosed=Vg,t.curveCardinalOpen=Wg,t.curveCardinal=$g,t.curveCatmullRomClosed=Gg,t.curveCatmullRomOpen=Jg,t.curveCatmullRom=Zg,t.curveLinearClosed=function(t){return new sc(t)},t.curveLinear=_g,t.curveMonotoneX=function(t){return new dc(t)},t.curveMonotoneY=function(t){return new vc(t)},t.curveNatural=function(t){return new yc(t)},t.curveStep=function(t){return new mc(t,.5)},t.curveStepAfter=function(t){return new mc(t,1)},t.curveStepBefore=function(t){return new mc(t,0)},t.stack=function(){function t(t){var o,u,a=n.apply(this,arguments),c=t.length,s=a.length,f=new Array(s);for(o=0;o<s;++o){for(var l,h=a[o],p=f[o]=new Array(c),d=0;d<c;++d)p[d]=l=[0,+i(t[d],h,d,t)],l.data=t[d];p.key=h}for(o=0,u=e(f);o<s;++o)f[u[o]].index=o;return r(f,u),f}var n=ig([]),e=Kg,r=Qg,i=xc;return t.keys=function(e){return arguments.length?(n="function"==typeof e?e:ig(kg.call(e)),t):n},t.value=function(n){return arguments.length?(i="function"==typeof n?n:ig(+n),t):i},t.order=function(n){return arguments.length?(e=null==n?Kg:"function"==typeof n?n:ig(kg.call(n)),t):e},t.offset=function(n){return arguments.length?(r=null==n?Qg:n,t):r},t},t.stackOffsetExpand=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,u=t[0].length;o<u;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}Qg(t,n)}},t.stackOffsetDiverging=function(t,n){if((a=t.length)>1)for(var e,r,i,o,u,a,c=0,s=t[n[0]].length;c<s;++c)for(o=u=0,e=0;e<a;++e)(i=(r=t[n[e]][c])[1]-r[0])>=0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=u,r[0]=u+=i):r[0]=o},t.stackOffsetNone=Qg,t.stackOffsetSilhouette=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var u=0,a=0;u<e;++u)a+=t[u][r][1]||0;i[r][1]+=i[r][0]=-a/2}Qg(t,n)}},t.stackOffsetWiggle=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,u=1;u<r;++u){for(var a=0,c=0,s=0;a<i;++a){for(var f=t[n[a]],l=f[u][1]||0,h=(l-(f[u-1][1]||0))/2,p=0;p<a;++p){var d=t[n[p]];h+=(d[u][1]||0)-(d[u-1][1]||0)}c+=l,s+=h*l}e[u-1][1]+=e[u-1][0]=o,c&&(o-=s/c)}e[u-1][1]+=e[u-1][0]=o,Qg(t,n)}},t.stackOrderAscending=tm,t.stackOrderDescending=function(t){return tm(t).reverse()},t.stackOrderInsideOut=function(t){var n,e,r=t.length,i=t.map(bc),o=Kg(t).sort(function(t,n){return i[n]-i[t]}),u=0,a=0,c=[],s=[];for(n=0;n<r;++n)e=o[n],u<a?(u+=i[e],c.push(e)):(a+=i[e],s.push(e));return s.reverse().concat(c)},t.stackOrderNone=Kg,t.stackOrderReverse=function(t){return Kg(t).reverse()},t.timeInterval=Mu,t.timeMillisecond=z_,t.timeMilliseconds=P_,t.utcMillisecond=z_,t.utcMilliseconds=P_,t.timeSecond=q_,t.timeSeconds=U_,t.utcSecond=q_,t.utcSeconds=U_,t.timeMinute=D_,t.timeMinutes=O_,t.timeHour=F_,t.timeHours=I_,t.timeDay=Y_,t.timeDays=B_,t.timeWeek=j_,t.timeWeeks=G_,t.timeSunday=j_,t.timeSundays=G_,t.timeMonday=H_,t.timeMondays=J_,t.timeTuesday=X_,t.timeTuesdays=Q_,t.timeWednesday=$_,t.timeWednesdays=K_,t.timeThursday=V_,t.timeThursdays=ty,t.timeFriday=W_,t.timeFridays=ny,t.timeSaturday=Z_,t.timeSaturdays=ey,t.timeMonth=ry,t.timeMonths=iy,t.timeYear=oy,t.timeYears=uy,t.utcMinute=ay,t.utcMinutes=cy,t.utcHour=sy,t.utcHours=fy,t.utcDay=ly,t.utcDays=hy,t.utcWeek=py,t.utcWeeks=xy,t.utcSunday=py,t.utcSundays=xy,t.utcMonday=dy,t.utcMondays=by,t.utcTuesday=vy,t.utcTuesdays=wy,t.utcWednesday=_y,t.utcWednesdays=My,t.utcThursday=yy,t.utcThursdays=Ty,t.utcFriday=gy,t.utcFridays=ky,t.utcSaturday=my,t.utcSaturdays=Ny,t.utcMonth=Sy,t.utcMonths=Ey,t.utcYear=Ay,t.utcYears=zy,t.timeFormatDefaultLocale=Ma,t.timeFormatLocale=Au,t.isoFormat=Uy,t.isoParse=Dy,t.now=ln,t.timer=dn,t.timerFlush=vn,t.timeout=Pl,t.interval=function(t,n,e){var r=new pn,i=n;return null==n?(r.restart(t,n,e),r):(n=+n,e=null==e?ln():+e,r.restart(function o(u){u+=i,r.restart(o,i+=n,e),t(u)},n,e),r)},t.transition=Jn,t.active=function(t,n){var e,r,i=t.__transition;if(i){n=null==n?null:n+"";for(r in i)if((e=i[r]).state>Ul&&e.name===n)return new Gn([[t]],yh,n,+r)}return null},t.interrupt=jl,t.voronoi=function(){function t(t){return new Kc(t.map(function(r,i){var o=[Math.round(n(r,i,t)/sm)*sm,Math.round(e(r,i,t)/sm)*sm];return o.index=i,o.data=r,o}),r)}var n=wc,e=Mc,r=null;return t.polygons=function(n){return t(n).polygons()},t.links=function(n){return t(n).links()},t.triangles=function(n){return t(n).triangles()},t.x=function(e){return arguments.length?(n="function"==typeof e?e:nm(+e),t):n},t.y=function(n){return arguments.length?(e="function"==typeof n?n:nm(+n),t):e},t.extent=function(n){return arguments.length?(r=null==n?null:[[+n[0][0],+n[0][1]],[+n[1][0],+n[1][1]]],t):r&&[[r[0][0],r[0][1]],[r[1][0],r[1][1]]]},t.size=function(n){return arguments.length?(r=null==n?null:[[0,0],[+n[0],+n[1]]],t):r&&[r[1][0]-r[0][0],r[1][1]-r[0][1]]},t},t.zoom=function(){function n(t){t.property("__zoom",us).on("wheel.zoom",s).on("mousedown.zoom",f).on("dblclick.zoom",l).filter(cs).on("touchstart.zoom",p).on("touchmove.zoom",d).on("touchend.zoom touchcancel.zoom",v).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function e(t,n){return(n=Math.max(b,Math.min(w,n)))===t.k?t:new ns(n,t.x,t.y)}function r(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new ns(t.k,r,i)}function i(t,n){var e=t.invertX(n[0][0])-M,r=t.invertX(n[1][0])-T,i=t.invertY(n[0][1])-k,o=t.invertY(n[1][1])-S;return t.translate(r>e?(e+r)/2:Math.min(0,e)||Math.max(0,r),o>i?(i+o)/2:Math.min(0,i)||Math.max(0,o))}function o(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function u(t,n,e){t.on("start.zoom",function(){a(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){a(this,arguments).end()}).tween("zoom",function(){var t=this,r=arguments,i=a(t,r),u=m.apply(t,r),c=e||o(u),s=Math.max(u[1][0]-u[0][0],u[1][1]-u[0][1]),f=t.__zoom,l="function"==typeof n?n.apply(t,r):n,h=A(f.invert(c).concat(s/f.k),l.invert(c).concat(s/l.k));return function(t){if(1===t)t=l;else{var n=h(t),e=s/n[2];t=new ns(e,c[0]-n[0]*e,c[1]-n[1]*e)}i.zoom(null,t)}})}function a(t,n){for(var e,r=0,i=C.length;r<i;++r)if((e=C[r]).that===t)return e;return new c(t,n)}function c(t,n){this.that=t,this.args=n,this.index=-1,this.active=0,this.extent=m.apply(t,n)}function s(){if(g.apply(this,arguments)){var t=a(this,arguments),n=this.__zoom,o=Math.max(b,Math.min(w,n.k*Math.pow(2,x.apply(this,arguments)))),u=Ks(this);if(t.wheel)t.mouse[0][0]===u[0]&&t.mouse[0][1]===u[1]||(t.mouse[1]=n.invert(t.mouse[0]=u)),clearTimeout(t.wheel);else{if(n.k===o)return;t.mouse=[u,n.invert(u)],jl(this),t.start()}pm(),t.wheel=setTimeout(function(){t.wheel=null,t.end()},R),t.zoom("mouse",i(r(e(n,o),t.mouse[0],t.mouse[1]),t.extent))}}function f(){if(!y&&g.apply(this,arguments)){var n=a(this,arguments),e=cf(t.event.view).on("mousemove.zoom",function(){if(pm(),!n.moved){var e=t.event.clientX-u,o=t.event.clientY-c;n.moved=e*e+o*o>L}n.zoom("mouse",i(r(n.that.__zoom,n.mouse[0]=Ks(n.that),n.mouse[1]),n.extent))},!0).on("mouseup.zoom",function(){e.on("mousemove.zoom mouseup.zoom",null),_t(t.event.view,n.moved),pm(),n.end()},!0),o=Ks(this),u=t.event.clientX,c=t.event.clientY;lf(t.event.view),rs(),n.mouse=[o,this.__zoom.invert(o)],jl(this),n.start()}}function l(){if(g.apply(this,arguments)){var o=this.__zoom,a=Ks(this),c=o.invert(a),s=i(r(e(o,o.k*(t.event.shiftKey?.5:2)),a,c),m.apply(this,arguments));pm(),E>0?cf(this).transition().duration(E).call(u,s,a):cf(this).call(n.transform,s)}}function p(){if(g.apply(this,arguments)){var n,e,r,i,o=a(this,arguments),u=t.event.changedTouches,c=u.length;for(rs(),e=0;e<c;++e)r=u[e],i=[i=sf(this,u,r.identifier),this.__zoom.invert(i),r.identifier],o.touch0?o.touch1||(o.touch1=i):(o.touch0=i,n=!0);if(_&&(_=clearTimeout(_),!o.touch1))return o.end(),void((i=cf(this).on("dblclick.zoom"))&&i.apply(this,arguments));n&&(_=setTimeout(function(){_=null},P),jl(this),o.start())}}function d(){var n,o,u,c,s=a(this,arguments),f=t.event.changedTouches,l=f.length;for(pm(),_&&(_=clearTimeout(_)),n=0;n<l;++n)o=f[n],u=sf(this,f,o.identifier),s.touch0&&s.touch0[2]===o.identifier?s.touch0[0]=u:s.touch1&&s.touch1[2]===o.identifier&&(s.touch1[0]=u);if(o=s.that.__zoom,s.touch1){var h=s.touch0[0],p=s.touch0[1],d=s.touch1[0],v=s.touch1[1],y=(y=d[0]-h[0])*y+(y=d[1]-h[1])*y,g=(g=v[0]-p[0])*g+(g=v[1]-p[1])*g;o=e(o,Math.sqrt(y/g)),u=[(h[0]+d[0])/2,(h[1]+d[1])/2],c=[(p[0]+v[0])/2,(p[1]+v[1])/2]}else{if(!s.touch0)return;u=s.touch0[0],c=s.touch0[1]}s.zoom("touch",i(r(o,u,c),s.extent))}function v(){var n,e,r=a(this,arguments),i=t.event.changedTouches,o=i.length;for(rs(),y&&clearTimeout(y),y=setTimeout(function(){y=null},P),n=0;n<o;++n)e=i[n],r.touch0&&r.touch0[2]===e.identifier?delete r.touch0:r.touch1&&r.touch1[2]===e.identifier&&delete r.touch1;r.touch1&&!r.touch0&&(r.touch0=r.touch1,delete r.touch1),r.touch0?r.touch0[1]=this.__zoom.invert(r.touch0[0]):r.end()}var _,y,g=is,m=os,x=as,b=0,w=1/0,M=-w,T=w,k=M,S=T,E=250,A=_l,C=[],z=h("start","zoom","end"),P=500,R=150,L=0;return n.transform=function(t,n){var e=t.selection?t.selection():t;e.property("__zoom",us),t!==e?u(t,n):e.interrupt().each(function(){a(this,arguments).start().zoom(null,"function"==typeof n?n.apply(this,arguments):n).end()})},n.scaleBy=function(t,e){n.scaleTo(t,function(){return this.__zoom.k*("function"==typeof e?e.apply(this,arguments):e)})},n.scaleTo=function(t,u){n.transform(t,function(){var t=m.apply(this,arguments),n=this.__zoom,a=o(t),c=n.invert(a);return i(r(e(n,"function"==typeof u?u.apply(this,arguments):u),a,c),t)})},n.translateBy=function(t,e,r){n.transform(t,function(){return i(this.__zoom.translate("function"==typeof e?e.apply(this,arguments):e,"function"==typeof r?r.apply(this,arguments):r),m.apply(this,arguments))})},n.translateTo=function(t,e,r){n.transform(t,function(){var t=m.apply(this,arguments),n=this.__zoom,u=o(t);return i(hm.translate(u[0],u[1]).scale(n.k).translate("function"==typeof e?-e.apply(this,arguments):-e,"function"==typeof r?-r.apply(this,arguments):-r),t)})},c.prototype={start:function(){return 1==++this.active&&(this.index=C.push(this)-1,this.emit("start")),this},zoom:function(t,n){return this.mouse&&"mouse"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&"touch"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&"touch"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit("zoom"),this},end:function(){return 0==--this.active&&(C.splice(this.index,1),this.index=-1,this.emit("end")),this},emit:function(t){N(new ts(n,t,this.that.__zoom),z.apply,z,[t,this.that,this.args])}},n.wheelDelta=function(t){return arguments.length?(x="function"==typeof t?t:lm(+t),n):x},n.filter=function(t){return arguments.length?(g="function"==typeof t?t:lm(!!t),n):g},n.extent=function(t){return arguments.length?(m="function"==typeof t?t:lm([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),n):m},n.scaleExtent=function(t){return arguments.length?(b=+t[0],w=+t[1],n):[b,w]},n.translateExtent=function(t){return arguments.length?(M=+t[0][0],T=+t[1][0],k=+t[0][1],S=+t[1][1],n):[[M,k],[T,S]]},n.duration=function(t){return arguments.length?(E=+t,n):E},n.interpolate=function(t){return arguments.length?(A=t,n):A},n.on=function(){var t=z.on.apply(z,arguments);return t===z?n:t},n.clickDistance=function(t){return arguments.length?(L=(t=+t)*t,n):Math.sqrt(L)},n},t.zoomTransform=es,t.zoomIdentity=hm,Object.defineProperty(t,"__esModule",{value:!0})}); \ No newline at end of file
diff --git a/library/cpp/lwtrace/mon/static/js/filesaver.min.js b/library/cpp/lwtrace/mon/static/js/filesaver.min.js
new file mode 100644
index 0000000000..b431d9bc5b
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/filesaver.min.js
@@ -0,0 +1 @@
+(function(a,b){if("function"==typeof define&&define.amd)define([],b);else if("undefined"!=typeof exports)b();else{b(),a.FileSaver={exports:{}}.exports}})(this,function(){"use strict";function b(a,b){return"undefined"==typeof b?b={autoBom:!1}:"object"!=typeof b&&(console.warn("Deprecated: Expected third argument to be a object"),b={autoBom:!b}),b.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a.type)?new Blob(["\uFEFF",a],{type:a.type}):a}function c(b,c,d){var e=new XMLHttpRequest;e.open("GET",b),e.responseType="blob",e.onload=function(){a(e.response,c,d)},e.onerror=function(){console.error("could not download file")},e.send()}function d(a){var b=new XMLHttpRequest;b.open("HEAD",a,!1);try{b.send()}catch(a){}return 200<=b.status&&299>=b.status}function e(a){try{a.dispatchEvent(new MouseEvent("click"))}catch(c){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),a.dispatchEvent(b)}}var f="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,a=f.saveAs||("object"!=typeof window||window!==f?function(){}:"download"in HTMLAnchorElement.prototype?function(b,g,h){var i=f.URL||f.webkitURL,j=document.createElement("a");g=g||b.name||"download",j.download=g,j.rel="noopener","string"==typeof b?(j.href=b,j.origin===location.origin?e(j):d(j.href)?c(b,g,h):e(j,j.target="_blank")):(j.href=i.createObjectURL(b),setTimeout(function(){i.revokeObjectURL(j.href)},4E4),setTimeout(function(){e(j)},0))}:"msSaveOrOpenBlob"in navigator?function(f,g,h){if(g=g||f.name||"download","string"!=typeof f)navigator.msSaveOrOpenBlob(b(f,h),g);else if(d(f))c(f,g,h);else{var i=document.createElement("a");i.href=f,i.target="_blank",setTimeout(function(){e(i)})}}:function(a,b,d,e){if(e=e||open("","_blank"),e&&(e.document.title=e.document.body.innerText="downloading..."),"string"==typeof a)return c(a,b,d);var g="application/octet-stream"===a.type,h=/constructor/i.test(f.HTMLElement)||f.safari,i=/CriOS\/[\d]+/.test(navigator.userAgent);if((i||g&&h)&&"undefined"!=typeof FileReader){var j=new FileReader;j.onloadend=function(){var a=j.result;a=i?a:a.replace(/^data:[^;]*;/,"data:attachment/file;"),e?e.location.href=a:location=a,e=null},j.readAsDataURL(a)}else{var k=f.URL||f.webkitURL,l=k.createObjectURL(a);e?e.location=l:location.href=l,e=null,setTimeout(function(){k.revokeObjectURL(l)},4E4)}});f.saveAs=a.saveAs=a,"undefined"!=typeof module&&(module.exports=a)});
diff --git a/library/cpp/lwtrace/mon/static/js/jquery.flot.extents.js b/library/cpp/lwtrace/mon/static/js/jquery.flot.extents.js
new file mode 100644
index 0000000000..c17018b4f6
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/jquery.flot.extents.js
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2012, Serge V. Izmaylov
+ * Released under GPL Version 2 license.
+ */
+
+(function ($) {
+ var options = {
+ series: {
+ extents: {
+ show: false,
+ lineWidth: 1,
+ barHeight: 17,
+ color: "rgba(192, 192, 192, 1.0)",
+ showConnections: true,
+ connectionColor: "rgba(0, 192, 128, 0.8)",
+ fill: true,
+ fillColor: "rgba(64, 192, 255, 0.5)",
+ showLabels: true,
+ rowHeight: 20,
+ rows: 7,
+ barVAlign: "top",
+ labelHAlign: "left"
+ }
+ }
+ };
+
+ function processRawData(plot, series, data, datapoints) {
+ if (!series.extents || !series.extents.show)
+ return;
+
+ // Fool Flot with fake datapoints
+ datapoints.format = [ // Fake format
+ { x: true, number: true, required: true },
+ { y: true, number: true, required: true },
+ ];
+ datapoints.points = []; // Empty data
+ datapoints.pointsize = 2; // Fake size
+
+ // Check if we have extents data
+ if (series.extentdata == null)
+ return;
+
+ // Process our real data
+ var row = 0;
+ for (i = 0; i < series.extentdata.length; i++) {
+ // Skip bad extents
+ if ((series.extentdata[i].start == null) || (series.extentdata[i].end == null))
+ continue;
+
+ if (series.extentdata[i].end < series.extentdata[i].start) {
+ var t = series.extentdata[i].end;
+ series.extentdata[i].end = series.extentdata[i].start;
+ series.extentdata[i].start = t;
+ }
+ if ((series.extentdata[i].labelHAlign != "left") && (series.extentdata[i].labelHAlign != "right"))
+ series.extentdata[i].labelHAlign = series.extents.labelHAlign;
+ if (series.extentdata[i].row == null) {
+ series.extentdata[i].row = row;
+ row = (row+1) % series.extents.rows;
+ } else {
+ row = (series.extentdata[i].row+1) % series.extents.rows;
+ }
+ if (series.extentdata[i].color == null)
+ series.extentdata[i].color = series.extents.color;
+ if (series.extentdata[i].fillColor == null)
+ series.extentdata[i].fillColor = series.extents.fillColor;
+ }
+
+ };
+
+ function drawSingleExtent(ctx, width, height, xfrom, xto, series, extent) {
+ if (xfrom < 0) xfrom = 0;
+ if (xto > width) xto = width;
+ var bw = xto-xfrom;
+
+ var yfrom;
+ if (series.extents.barVAlign == "top")
+ yfrom = 4 + series.extents.rowHeight*extent.row;
+ else
+ yfrom = height - 4 - series.extents.rowHeight*(extent.row) - series.extents.barHeight;
+
+ if (series.extents.fill) {
+ ctx.fillStyle = extent.fillColor;
+ ctx.fillRect(xfrom, yfrom, bw, series.extents.barHeight);
+ }
+
+ ctx.strokeStyle = extent.color;
+ ctx.strokeRect(xfrom, yfrom, bw, series.extents.barHeight);
+ }
+
+ function drawSingleConnection(ctx, width, height, xfrom, xto, rfrom, rto, series) {
+ if (xfrom < 0) xfrom = 0;
+ if (xto > width) xto = width;
+
+ var yfrom, yto;
+ if (series.extents.barVAlign == "top") {
+ yfrom = 4 + Math.round(series.extents.rowHeight*rfrom) + Math.round(series.extents.barHeight*0.5);
+ yto = 4 + Math.round(series.extents.rowHeight*rto) + Math.round(series.extents.barHeight*0.5);
+ } else {
+ yfrom = height - 4 - Math.round(series.extents.rowHeight*rfrom) - Math.round(series.extents.barHeight*0.5);
+ yto = height - 4 - Math.round(series.extents.rowHeight*rto) - Math.round(series.extents.barHeight*0.5);
+ }
+
+ ctx.beginPath();
+ ctx.moveTo(xfrom, yfrom);
+ ctx.lineTo(xfrom+10, yfrom);
+ ctx.lineTo(xto-10, yto);
+ ctx.lineTo(xto, yto);
+ ctx.lineTo(xto-6, yto-3);
+ ctx.lineTo(xto-6, yto+3);
+ ctx.lineTo(xto, yto);
+ ctx.stroke();
+ }
+
+ function addExtentLabel(placeholder, plotOffset, width, xfrom, xto, series, extent) {
+ var styles = [];
+ if (series.extents.barVAlign == "top")
+ styles.push("top:"+Math.round((plotOffset.top+series.extents.rowHeight*extent.row+4))+"px");
+ else
+ styles.push("bottom:"+Math.round((plotOffset.bottom+series.extents.rowHeight*extent.row+4))+"px");
+ if (extent.labelHAlign == "left")
+ styles.push("left:"+Math.round((plotOffset.left+xfrom+3))+"px");
+ else
+ styles.push("right:"+Math.round((plotOffset.right+(width-xto)+3))+"px");
+ styles.push("");
+
+ placeholder.append('<div '+((extent.id !=null)?('id="'+extent.id+'" '):'')+'class="extentLabel" style="font-size:smaller;position:absolute;'+(styles.join(';'))+'">'+extent.label+'</div>');
+ }
+
+ function drawSeries(plot, ctx, series) {
+ if (!series.extents || !series.extents.show || !series.extentdata)
+ return;
+
+ var placeholder = plot.getPlaceholder();
+ placeholder.find(".extentLabel").remove();
+
+ ctx.save();
+
+ var plotOffset = plot.getPlotOffset();
+ var axes = plot.getAxes();
+ var yf = axes.yaxis.p2c(axes.yaxis.min);
+ var yt = axes.yaxis.p2c(axes.yaxis.max);
+ var ytop = (yf>yt)?yt:yf;
+ var ybot = (yf>yt)?yf:yt;
+ var width = plot.width();
+ var height = plot.height();
+
+ ctx.translate(plotOffset.left, plotOffset.top);
+ ctx.lineJoin = "round";
+
+ for (var i = 0; i < series.extentdata.length; i++) {
+ var xfrom, xto;
+ if ((series.extentdata[i].start == null) || (series.extentdata[i].end == null))
+ continue;
+ if ((series.extentdata[i].start < axes.xaxis.max) && (series.extentdata[i].end > axes.xaxis.min)) {
+ xfrom = axes.xaxis.p2c((series.extentdata[i].start<axes.xaxis.min)?axes.xaxis.min:series.extentdata[i].start);
+ xto = axes.xaxis.p2c((series.extentdata[i].end>axes.xaxis.max)?axes.xaxis.max:series.extentdata[i].end);
+ drawSingleExtent(ctx, width, height, xfrom, xto, series, series.extentdata[i]);
+
+ if (series.extents.showConnections && (series.extentdata[i].start > axes.xaxis.min) && (series.extentdata[i].start < axes.xaxis.max))
+ if ((series.extentdata[i].depends != null) && (series.extentdata[i].depends.length != null) && (series.extentdata[i].depends.length > 0))
+ for (var j=0; j<series.extentdata[i].depends.length; j++) {
+ var k = series.extentdata[i].depends[j];
+ if ((k < 0) || (k >= series.extentdata.length))
+ continue;
+ if ((series.extentdata[k].start == null) || (series.extentdata[k].end == null))
+ continue;
+ var cxto = xfrom;
+ var cxfrom = series.extentdata[k].end;
+ if (cxfrom < axes.xaxis.min) cxfrom = axes.xaxis.min;
+ if (cxfrom > axes.xaxis.max) cxfrom = axes.xaxis.max;
+ cxfrom = axes.xaxis.p2c(cxfrom);
+ ctx.strokeStyle = series.extents.connectionColor;
+ drawSingleConnection(ctx, width, height, cxfrom, cxto, series.extentdata[k].row, series.extentdata[i].row, series);
+ }
+
+ if (series.extents.showLabels && (series.extentdata[i].label != null))
+ addExtentLabel(placeholder, plotOffset, width, xfrom, xto, series, series.extentdata[i]);
+ }
+ }
+
+ ctx.restore();
+ };
+
+ function init(plot) {
+ plot.hooks.processRawData.push(processRawData);
+ plot.hooks.drawSeries.push(drawSeries);
+ };
+
+ $.plot.plugins.push({
+ init: init,
+ name: "extents",
+ options: options,
+ version: "0.3"
+ });
+})(jQuery);
diff --git a/library/cpp/lwtrace/mon/static/js/jquery.flot.min.js b/library/cpp/lwtrace/mon/static/js/jquery.flot.min.js
new file mode 100644
index 0000000000..81083f1819
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/jquery.flot.min.js
@@ -0,0 +1,8 @@
+/* Javascript plotting library for jQuery, version 0.8.3.
+
+Copyright (c) 2007-2014 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+*/
+(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i<c.length;++i)o[c.charAt(i)]+=d;return o.normalize()};o.scale=function(c,f){for(var i=0;i<c.length;++i)o[c.charAt(i)]*=f;return o.normalize()};o.toString=function(){if(o.a>=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return value<min?min:value>max?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);(function($){var hasOwnProperty=Object.prototype.hasOwnProperty;if(!$.fn.detach){$.fn.detach=function(){return this.each(function(){if(this.parentNode){this.parentNode.removeChild(this)}})}}function Canvas(cls,container){var element=container.children("."+cls)[0];if(element==null){element=document.createElement("canvas");element.className=cls;$(element).css({direction:"ltr",position:"absolute",left:0,top:0}).appendTo(container);if(!element.getContext){if(window.G_vmlCanvasManager){element=window.G_vmlCanvasManager.initElement(element)}else{throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode.")}}}this.element=element;var context=this.context=element.getContext("2d");var devicePixelRatio=window.devicePixelRatio||1,backingStoreRatio=context.webkitBackingStorePixelRatio||context.mozBackingStorePixelRatio||context.msBackingStorePixelRatio||context.oBackingStorePixelRatio||context.backingStorePixelRatio||1;this.pixelRatio=devicePixelRatio/backingStoreRatio;this.resize(container.width(),container.height());this.textContainer=null;this.text={};this._textCache={}}Canvas.prototype.resize=function(width,height){if(width<=0||height<=0){throw new Error("Invalid dimensions for plot, width = "+width+", height = "+height)}var element=this.element,context=this.context,pixelRatio=this.pixelRatio;if(this.width!=width){element.width=width*pixelRatio;element.style.width=width+"px";this.width=width}if(this.height!=height){element.height=height*pixelRatio;element.style.height=height+"px";this.height=height}context.restore();context.save();context.scale(pixelRatio,pixelRatio)};Canvas.prototype.clear=function(){this.context.clearRect(0,0,this.width,this.height)};Canvas.prototype.render=function(){var cache=this._textCache;for(var layerKey in cache){if(hasOwnProperty.call(cache,layerKey)){var layer=this.getTextLayer(layerKey),layerCache=cache[layerKey];layer.hide();for(var styleKey in layerCache){if(hasOwnProperty.call(layerCache,styleKey)){var styleCache=layerCache[styleKey];for(var key in styleCache){if(hasOwnProperty.call(styleCache,key)){var positions=styleCache[key].positions;for(var i=0,position;position=positions[i];i++){if(position.active){if(!position.rendered){layer.append(position.element);position.rendered=true}}else{positions.splice(i--,1);if(position.rendered){position.element.detach()}}}if(positions.length==0){delete styleCache[key]}}}}}layer.show()}}};Canvas.prototype.getTextLayer=function(classes){var layer=this.text[classes];if(layer==null){if(this.textContainer==null){this.textContainer=$("<div class='flot-text'></div>").css({position:"absolute",top:0,left:0,bottom:0,right:0,"font-size":"smaller",color:"#545454"}).insertAfter(this.element)}layer=this.text[classes]=$("<div></div>").addClass(classes).css({position:"absolute",top:0,left:0,bottom:0,right:0}).appendTo(this.textContainer)}return layer};Canvas.prototype.getTextInfo=function(layer,text,font,angle,width){var textStyle,layerCache,styleCache,info;text=""+text;if(typeof font==="object"){textStyle=font.style+" "+font.variant+" "+font.weight+" "+font.size+"px/"+font.lineHeight+"px "+font.family}else{textStyle=font}layerCache=this._textCache[layer];if(layerCache==null){layerCache=this._textCache[layer]={}}styleCache=layerCache[textStyle];if(styleCache==null){styleCache=layerCache[textStyle]={}}info=styleCache[text];if(info==null){var element=$("<div></div>").html(text).css({position:"absolute","max-width":width,top:-9999}).appendTo(this.getTextLayer(layer));if(typeof font==="object"){element.css({font:textStyle,color:font.color})}else if(typeof font==="string"){element.addClass(font)}info=styleCache[text]={width:element.outerWidth(true),height:element.outerHeight(true),element:element,positions:[]};element.detach()}return info};Canvas.prototype.addText=function(layer,x,y,text,font,angle,width,halign,valign){var info=this.getTextInfo(layer,text,font,angle,width),positions=info.positions;if(halign=="center"){x-=info.width/2}else if(halign=="right"){x-=info.width}if(valign=="middle"){y-=info.height/2}else if(valign=="bottom"){y-=info.height}for(var i=0,position;position=positions[i];i++){if(position.x==x&&position.y==y){position.active=true;return}}position={active:true,rendered:false,element:positions.length?info.element.clone():info.element,x:x,y:y};positions.push(position);position.element.css({top:Math.round(y),left:Math.round(x),"text-align":halign})};Canvas.prototype.removeText=function(layer,x,y,text,font,angle){if(text==null){var layerCache=this._textCache[layer];if(layerCache!=null){for(var styleKey in layerCache){if(hasOwnProperty.call(layerCache,styleKey)){var styleCache=layerCache[styleKey];for(var key in styleCache){if(hasOwnProperty.call(styleCache,key)){var positions=styleCache[key].positions;for(var i=0,position;position=positions[i];i++){position.active=false}}}}}}}else{var positions=this.getTextInfo(layer,text,font,angle).positions;for(var i=0,position;position=positions[i];i++){if(position.x==x&&position.y==y){position.active=false}}}};function Plot(placeholder,data_,options_,plugins){var series=[],options={colors:["#edc240","#afd8f8","#cb4b4b","#4da74d","#9440ed"],legend:{show:true,noColumns:1,labelFormatter:null,labelBoxBorderColor:"#ccc",container:null,position:"ne",margin:5,backgroundColor:null,backgroundOpacity:.85,sorted:null},xaxis:{show:null,position:"bottom",mode:null,font:null,color:null,tickColor:null,transform:null,inverseTransform:null,min:null,max:null,autoscaleMargin:null,ticks:null,tickFormatter:null,labelWidth:null,labelHeight:null,reserveSpace:null,tickLength:null,alignTicksWithAxis:null,tickDecimals:null,tickSize:null,minTickSize:null},yaxis:{autoscaleMargin:.02,position:"left"},xaxes:[],yaxes:[],series:{points:{show:false,radius:3,lineWidth:2,fill:true,fillColor:"#ffffff",symbol:"circle"},lines:{lineWidth:2,fill:false,fillColor:null,steps:false},bars:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,align:"left",horizontal:false,zero:true},shadowSize:3,highlightColor:null},grid:{show:true,aboveData:false,color:"#545454",backgroundColor:null,borderColor:null,tickColor:null,margin:0,labelMargin:5,axisMargin:8,borderWidth:2,minBorderMargin:null,markings:null,markingsColor:"#f4f4f4",markingsLineWidth:2,clickable:false,hoverable:false,autoHighlight:true,mouseActiveRadius:10},interaction:{redrawOverlayInterval:1e3/60},hooks:{}},surface=null,overlay=null,eventHolder=null,ctx=null,octx=null,xaxes=[],yaxes=[],plotOffset={left:0,right:0,top:0,bottom:0},plotWidth=0,plotHeight=0,hooks={processOptions:[],processRawData:[],processDatapoints:[],processOffset:[],drawBackground:[],drawSeries:[],draw:[],bindEvents:[],drawOverlay:[],shutdown:[]},plot=this;plot.setData=setData;plot.setupGrid=setupGrid;plot.draw=draw;plot.getPlaceholder=function(){return placeholder};plot.getCanvas=function(){return surface.element};plot.getPlotOffset=function(){return plotOffset};plot.width=function(){return plotWidth};plot.height=function(){return plotHeight};plot.offset=function(){var o=eventHolder.offset();o.left+=plotOffset.left;o.top+=plotOffset.top;return o};plot.getData=function(){return series};plot.getAxes=function(){var res={},i;$.each(xaxes.concat(yaxes),function(_,axis){if(axis)res[axis.direction+(axis.n!=1?axis.n:"")+"axis"]=axis});return res};plot.getXAxes=function(){return xaxes};plot.getYAxes=function(){return yaxes};plot.c2p=canvasToAxisCoords;plot.p2c=axisToCanvasCoords;plot.getOptions=function(){return options};plot.highlight=highlight;plot.unhighlight=unhighlight;plot.triggerRedrawOverlay=triggerRedrawOverlay;plot.pointOffset=function(point){return{left:parseInt(xaxes[axisNumber(point,"x")-1].p2c(+point.x)+plotOffset.left,10),top:parseInt(yaxes[axisNumber(point,"y")-1].p2c(+point.y)+plotOffset.top,10)}};plot.shutdown=shutdown;plot.destroy=function(){shutdown();placeholder.removeData("plot").empty();series=[];options=null;surface=null;overlay=null;eventHolder=null;ctx=null;octx=null;xaxes=[];yaxes=[];hooks=null;highlights=[];plot=null};plot.resize=function(){var width=placeholder.width(),height=placeholder.height();surface.resize(width,height);overlay.resize(width,height)};plot.hooks=hooks;initPlugins(plot);parseOptions(options_);setupCanvases();setData(data_);setupGrid();draw();bindEvents();function executeHooks(hook,args){args=[plot].concat(args);for(var i=0;i<hook.length;++i)hook[i].apply(this,args)}function initPlugins(){var classes={Canvas:Canvas};for(var i=0;i<plugins.length;++i){var p=plugins[i];p.init(plot,classes);if(p.options)$.extend(true,options,p.options)}}function parseOptions(opts){$.extend(true,options,opts);if(opts&&opts.colors){options.colors=opts.colors}if(options.xaxis.color==null)options.xaxis.color=$.color.parse(options.grid.color).scale("a",.22).toString();if(options.yaxis.color==null)options.yaxis.color=$.color.parse(options.grid.color).scale("a",.22).toString();if(options.xaxis.tickColor==null)options.xaxis.tickColor=options.grid.tickColor||options.xaxis.color;if(options.yaxis.tickColor==null)options.yaxis.tickColor=options.grid.tickColor||options.yaxis.color;if(options.grid.borderColor==null)options.grid.borderColor=options.grid.color;if(options.grid.tickColor==null)options.grid.tickColor=$.color.parse(options.grid.color).scale("a",.22).toString();var i,axisOptions,axisCount,fontSize=placeholder.css("font-size"),fontSizeDefault=fontSize?+fontSize.replace("px",""):13,fontDefaults={style:placeholder.css("font-style"),size:Math.round(.8*fontSizeDefault),variant:placeholder.css("font-variant"),weight:placeholder.css("font-weight"),family:placeholder.css("font-family")};axisCount=options.xaxes.length||1;for(i=0;i<axisCount;++i){axisOptions=options.xaxes[i];if(axisOptions&&!axisOptions.tickColor){axisOptions.tickColor=axisOptions.color}axisOptions=$.extend(true,{},options.xaxis,axisOptions);options.xaxes[i]=axisOptions;if(axisOptions.font){axisOptions.font=$.extend({},fontDefaults,axisOptions.font);if(!axisOptions.font.color){axisOptions.font.color=axisOptions.color}if(!axisOptions.font.lineHeight){axisOptions.font.lineHeight=Math.round(axisOptions.font.size*1.15)}}}axisCount=options.yaxes.length||1;for(i=0;i<axisCount;++i){axisOptions=options.yaxes[i];if(axisOptions&&!axisOptions.tickColor){axisOptions.tickColor=axisOptions.color}axisOptions=$.extend(true,{},options.yaxis,axisOptions);options.yaxes[i]=axisOptions;if(axisOptions.font){axisOptions.font=$.extend({},fontDefaults,axisOptions.font);if(!axisOptions.font.color){axisOptions.font.color=axisOptions.color}if(!axisOptions.font.lineHeight){axisOptions.font.lineHeight=Math.round(axisOptions.font.size*1.15)}}}if(options.xaxis.noTicks&&options.xaxis.ticks==null)options.xaxis.ticks=options.xaxis.noTicks;if(options.yaxis.noTicks&&options.yaxis.ticks==null)options.yaxis.ticks=options.yaxis.noTicks;if(options.x2axis){options.xaxes[1]=$.extend(true,{},options.xaxis,options.x2axis);options.xaxes[1].position="top";if(options.x2axis.min==null){options.xaxes[1].min=null}if(options.x2axis.max==null){options.xaxes[1].max=null}}if(options.y2axis){options.yaxes[1]=$.extend(true,{},options.yaxis,options.y2axis);options.yaxes[1].position="right";if(options.y2axis.min==null){options.yaxes[1].min=null}if(options.y2axis.max==null){options.yaxes[1].max=null}}if(options.grid.coloredAreas)options.grid.markings=options.grid.coloredAreas;if(options.grid.coloredAreasColor)options.grid.markingsColor=options.grid.coloredAreasColor;if(options.lines)$.extend(true,options.series.lines,options.lines);if(options.points)$.extend(true,options.series.points,options.points);if(options.bars)$.extend(true,options.series.bars,options.bars);if(options.shadowSize!=null)options.series.shadowSize=options.shadowSize;if(options.highlightColor!=null)options.series.highlightColor=options.highlightColor;for(i=0;i<options.xaxes.length;++i)getOrCreateAxis(xaxes,i+1).options=options.xaxes[i];for(i=0;i<options.yaxes.length;++i)getOrCreateAxis(yaxes,i+1).options=options.yaxes[i];for(var n in hooks)if(options.hooks[n]&&options.hooks[n].length)hooks[n]=hooks[n].concat(options.hooks[n]);executeHooks(hooks.processOptions,[options])}function setData(d){series=parseData(d);fillInSeriesOptions();processData()}function parseData(d){var res=[];for(var i=0;i<d.length;++i){var s=$.extend(true,{},options.series);if(d[i].data!=null){s.data=d[i].data;delete d[i].data;$.extend(true,s,d[i]);d[i].data=s.data}else s.data=d[i];res.push(s)}return res}function axisNumber(obj,coord){var a=obj[coord+"axis"];if(typeof a=="object")a=a.n;if(typeof a!="number")a=1;return a}function allAxes(){return $.grep(xaxes.concat(yaxes),function(a){return a})}function canvasToAxisCoords(pos){var res={},i,axis;for(i=0;i<xaxes.length;++i){axis=xaxes[i];if(axis&&axis.used)res["x"+axis.n]=axis.c2p(pos.left)}for(i=0;i<yaxes.length;++i){axis=yaxes[i];if(axis&&axis.used)res["y"+axis.n]=axis.c2p(pos.top)}if(res.x1!==undefined)res.x=res.x1;if(res.y1!==undefined)res.y=res.y1;return res}function axisToCanvasCoords(pos){var res={},i,axis,key;for(i=0;i<xaxes.length;++i){axis=xaxes[i];if(axis&&axis.used){key="x"+axis.n;if(pos[key]==null&&axis.n==1)key="x";if(pos[key]!=null){res.left=axis.p2c(pos[key]);break}}}for(i=0;i<yaxes.length;++i){axis=yaxes[i];if(axis&&axis.used){key="y"+axis.n;if(pos[key]==null&&axis.n==1)key="y";if(pos[key]!=null){res.top=axis.p2c(pos[key]);break}}}return res}function getOrCreateAxis(axes,number){if(!axes[number-1])axes[number-1]={n:number,direction:axes==xaxes?"x":"y",options:$.extend(true,{},axes==xaxes?options.xaxis:options.yaxis)};return axes[number-1]}function fillInSeriesOptions(){var neededColors=series.length,maxIndex=-1,i;for(i=0;i<series.length;++i){var sc=series[i].color;if(sc!=null){neededColors--;if(typeof sc=="number"&&sc>maxIndex){maxIndex=sc}}}if(neededColors<=maxIndex){neededColors=maxIndex+1}var c,colors=[],colorPool=options.colors,colorPoolSize=colorPool.length,variation=0;for(i=0;i<neededColors;i++){c=$.color.parse(colorPool[i%colorPoolSize]||"#666");if(i%colorPoolSize==0&&i){if(variation>=0){if(variation<.5){variation=-variation-.2}else variation=0}else variation=-variation}colors[i]=c.scale("rgb",1+variation)}var colori=0,s;for(i=0;i<series.length;++i){s=series[i];if(s.color==null){s.color=colors[colori].toString();++colori}else if(typeof s.color=="number")s.color=colors[s.color].toString();if(s.lines.show==null){var v,show=true;for(v in s)if(s[v]&&s[v].show){show=false;break}if(show)s.lines.show=true}if(s.lines.zero==null){s.lines.zero=!!s.lines.fill}s.xaxis=getOrCreateAxis(xaxes,axisNumber(s,"x"));s.yaxis=getOrCreateAxis(yaxes,axisNumber(s,"y"))}}function processData(){var topSentry=Number.POSITIVE_INFINITY,bottomSentry=Number.NEGATIVE_INFINITY,fakeInfinity=Number.MAX_VALUE,i,j,k,m,length,s,points,ps,x,y,axis,val,f,p,data,format;function updateAxis(axis,min,max){if(min<axis.datamin&&min!=-fakeInfinity)axis.datamin=min;if(max>axis.datamax&&max!=fakeInfinity)axis.datamax=max}$.each(allAxes(),function(_,axis){axis.datamin=topSentry;axis.datamax=bottomSentry;axis.used=false});for(i=0;i<series.length;++i){s=series[i];s.datapoints={points:[]};executeHooks(hooks.processRawData,[s,s.data,s.datapoints])}for(i=0;i<series.length;++i){s=series[i];data=s.data;format=s.datapoints.format;if(!format){format=[];format.push({x:true,number:true,required:true});format.push({y:true,number:true,required:true});if(s.bars.show||s.lines.show&&s.lines.fill){var autoscale=!!(s.bars.show&&s.bars.zero||s.lines.show&&s.lines.zero);format.push({y:true,number:true,required:false,defaultValue:0,autoscale:autoscale});if(s.bars.horizontal){delete format[format.length-1].y;format[format.length-1].x=true}}s.datapoints.format=format}if(s.datapoints.pointsize!=null)continue;s.datapoints.pointsize=format.length;ps=s.datapoints.pointsize;points=s.datapoints.points;var insertSteps=s.lines.show&&s.lines.steps;s.xaxis.used=s.yaxis.used=true;for(j=k=0;j<data.length;++j,k+=ps){p=data[j];var nullify=p==null;if(!nullify){for(m=0;m<ps;++m){val=p[m];f=format[m];if(f){if(f.number&&val!=null){val=+val;if(isNaN(val))val=null;else if(val==Infinity)val=fakeInfinity;else if(val==-Infinity)val=-fakeInfinity}if(val==null){if(f.required)nullify=true;if(f.defaultValue!=null)val=f.defaultValue}}points[k+m]=val}}if(nullify){for(m=0;m<ps;++m){val=points[k+m];if(val!=null){f=format[m];if(f.autoscale!==false){if(f.x){updateAxis(s.xaxis,val,val)}if(f.y){updateAxis(s.yaxis,val,val)}}}points[k+m]=null}}else{if(insertSteps&&k>0&&points[k-ps]!=null&&points[k-ps]!=points[k]&&points[k-ps+1]!=points[k+1]){for(m=0;m<ps;++m)points[k+ps+m]=points[k+m];points[k+1]=points[k-ps+1];k+=ps}}}}for(i=0;i<series.length;++i){s=series[i];executeHooks(hooks.processDatapoints,[s,s.datapoints])}for(i=0;i<series.length;++i){s=series[i];points=s.datapoints.points;ps=s.datapoints.pointsize;format=s.datapoints.format;var xmin=topSentry,ymin=topSentry,xmax=bottomSentry,ymax=bottomSentry;for(j=0;j<points.length;j+=ps){if(points[j]==null)continue;for(m=0;m<ps;++m){val=points[j+m];f=format[m];if(!f||f.autoscale===false||val==fakeInfinity||val==-fakeInfinity)continue;if(f.x){if(val<xmin)xmin=val;if(val>xmax)xmax=val}if(f.y){if(val<ymin)ymin=val;if(val>ymax)ymax=val}}}if(s.bars.show){var delta;switch(s.bars.align){case"left":delta=0;break;case"right":delta=-s.bars.barWidth;break;default:delta=-s.bars.barWidth/2}if(s.bars.horizontal){ymin+=delta;ymax+=delta+s.bars.barWidth}else{xmin+=delta;xmax+=delta+s.bars.barWidth}}updateAxis(s.xaxis,xmin,xmax);updateAxis(s.yaxis,ymin,ymax)}$.each(allAxes(),function(_,axis){if(axis.datamin==topSentry)axis.datamin=null;if(axis.datamax==bottomSentry)axis.datamax=null})}function setupCanvases(){placeholder.css("padding",0).children().filter(function(){return!$(this).hasClass("flot-overlay")&&!$(this).hasClass("flot-base")}).remove();if(placeholder.css("position")=="static")placeholder.css("position","relative");surface=new Canvas("flot-base",placeholder);overlay=new Canvas("flot-overlay",placeholder);ctx=surface.context;octx=overlay.context;eventHolder=$(overlay.element).unbind();var existing=placeholder.data("plot");if(existing){existing.shutdown();overlay.clear()}placeholder.data("plot",plot)}function bindEvents(){if(options.grid.hoverable){eventHolder.mousemove(onMouseMove);eventHolder.bind("mouseleave",onMouseLeave)}if(options.grid.clickable)eventHolder.click(onClick);executeHooks(hooks.bindEvents,[eventHolder])}function shutdown(){if(redrawTimeout)clearTimeout(redrawTimeout);eventHolder.unbind("mousemove",onMouseMove);eventHolder.unbind("mouseleave",onMouseLeave);eventHolder.unbind("click",onClick);executeHooks(hooks.shutdown,[eventHolder])}function setTransformationHelpers(axis){function identity(x){return x}var s,m,t=axis.options.transform||identity,it=axis.options.inverseTransform;if(axis.direction=="x"){s=axis.scale=plotWidth/Math.abs(t(axis.max)-t(axis.min));m=Math.min(t(axis.max),t(axis.min))}else{s=axis.scale=plotHeight/Math.abs(t(axis.max)-t(axis.min));s=-s;m=Math.max(t(axis.max),t(axis.min))}if(t==identity)axis.p2c=function(p){return(p-m)*s};else axis.p2c=function(p){return(t(p)-m)*s};if(!it)axis.c2p=function(c){return m+c/s};else axis.c2p=function(c){return it(m+c/s)}}function measureTickLabels(axis){var opts=axis.options,ticks=axis.ticks||[],labelWidth=opts.labelWidth||0,labelHeight=opts.labelHeight||0,maxWidth=labelWidth||(axis.direction=="x"?Math.floor(surface.width/(ticks.length||1)):null),legacyStyles=axis.direction+"Axis "+axis.direction+axis.n+"Axis",layer="flot-"+axis.direction+"-axis flot-"+axis.direction+axis.n+"-axis "+legacyStyles,font=opts.font||"flot-tick-label tickLabel";for(var i=0;i<ticks.length;++i){var t=ticks[i];if(!t.label)continue;var info=surface.getTextInfo(layer,t.label,font,null,maxWidth);labelWidth=Math.max(labelWidth,info.width);labelHeight=Math.max(labelHeight,info.height)}axis.labelWidth=opts.labelWidth||labelWidth;axis.labelHeight=opts.labelHeight||labelHeight}function allocateAxisBoxFirstPhase(axis){var lw=axis.labelWidth,lh=axis.labelHeight,pos=axis.options.position,isXAxis=axis.direction==="x",tickLength=axis.options.tickLength,axisMargin=options.grid.axisMargin,padding=options.grid.labelMargin,innermost=true,outermost=true,first=true,found=false;$.each(isXAxis?xaxes:yaxes,function(i,a){if(a&&(a.show||a.reserveSpace)){if(a===axis){found=true}else if(a.options.position===pos){if(found){outermost=false}else{innermost=false}}if(!found){first=false}}});if(outermost){axisMargin=0}if(tickLength==null){tickLength=first?"full":5}if(!isNaN(+tickLength))padding+=+tickLength;if(isXAxis){lh+=padding;if(pos=="bottom"){plotOffset.bottom+=lh+axisMargin;axis.box={top:surface.height-plotOffset.bottom,height:lh}}else{axis.box={top:plotOffset.top+axisMargin,height:lh};plotOffset.top+=lh+axisMargin}}else{lw+=padding;if(pos=="left"){axis.box={left:plotOffset.left+axisMargin,width:lw};plotOffset.left+=lw+axisMargin}else{plotOffset.right+=lw+axisMargin;axis.box={left:surface.width-plotOffset.right,width:lw}}}axis.position=pos;axis.tickLength=tickLength;axis.box.padding=padding;axis.innermost=innermost}function allocateAxisBoxSecondPhase(axis){if(axis.direction=="x"){axis.box.left=plotOffset.left-axis.labelWidth/2;axis.box.width=surface.width-plotOffset.left-plotOffset.right+axis.labelWidth}else{axis.box.top=plotOffset.top-axis.labelHeight/2;axis.box.height=surface.height-plotOffset.bottom-plotOffset.top+axis.labelHeight}}function adjustLayoutForThingsStickingOut(){var minMargin=options.grid.minBorderMargin,axis,i;if(minMargin==null){minMargin=0;for(i=0;i<series.length;++i)minMargin=Math.max(minMargin,2*(series[i].points.radius+series[i].points.lineWidth/2))}var margins={left:minMargin,right:minMargin,top:minMargin,bottom:minMargin};$.each(allAxes(),function(_,axis){if(axis.reserveSpace&&axis.ticks&&axis.ticks.length){if(axis.direction==="x"){margins.left=Math.max(margins.left,axis.labelWidth/2);margins.right=Math.max(margins.right,axis.labelWidth/2)}else{margins.bottom=Math.max(margins.bottom,axis.labelHeight/2);margins.top=Math.max(margins.top,axis.labelHeight/2)}}});plotOffset.left=Math.ceil(Math.max(margins.left,plotOffset.left));plotOffset.right=Math.ceil(Math.max(margins.right,plotOffset.right));plotOffset.top=Math.ceil(Math.max(margins.top,plotOffset.top));plotOffset.bottom=Math.ceil(Math.max(margins.bottom,plotOffset.bottom))}function setupGrid(){var i,axes=allAxes(),showGrid=options.grid.show;for(var a in plotOffset){var margin=options.grid.margin||0;plotOffset[a]=typeof margin=="number"?margin:margin[a]||0}executeHooks(hooks.processOffset,[plotOffset]);for(var a in plotOffset){if(typeof options.grid.borderWidth=="object"){plotOffset[a]+=showGrid?options.grid.borderWidth[a]:0}else{plotOffset[a]+=showGrid?options.grid.borderWidth:0}}$.each(axes,function(_,axis){var axisOpts=axis.options;axis.show=axisOpts.show==null?axis.used:axisOpts.show;axis.reserveSpace=axisOpts.reserveSpace==null?axis.show:axisOpts.reserveSpace;setRange(axis)});if(showGrid){var allocatedAxes=$.grep(axes,function(axis){return axis.show||axis.reserveSpace});$.each(allocatedAxes,function(_,axis){setupTickGeneration(axis);setTicks(axis);snapRangeToTicks(axis,axis.ticks);measureTickLabels(axis)});for(i=allocatedAxes.length-1;i>=0;--i)allocateAxisBoxFirstPhase(allocatedAxes[i]);adjustLayoutForThingsStickingOut();$.each(allocatedAxes,function(_,axis){allocateAxisBoxSecondPhase(axis)})}plotWidth=surface.width-plotOffset.left-plotOffset.right;plotHeight=surface.height-plotOffset.bottom-plotOffset.top;$.each(axes,function(_,axis){setTransformationHelpers(axis)});if(showGrid){drawAxisLabels()}insertLegend()}function setRange(axis){var opts=axis.options,min=+(opts.min!=null?opts.min:axis.datamin),max=+(opts.max!=null?opts.max:axis.datamax),delta=max-min;if(delta==0){var widen=max==0?1:.01;if(opts.min==null)min-=widen;if(opts.max==null||opts.min!=null)max+=widen}else{var margin=opts.autoscaleMargin;if(margin!=null){if(opts.min==null){min-=delta*margin;if(min<0&&axis.datamin!=null&&axis.datamin>=0)min=0}if(opts.max==null){max+=delta*margin;if(max>0&&axis.datamax!=null&&axis.datamax<=0)max=0}}}axis.min=min;axis.max=max}function setupTickGeneration(axis){var opts=axis.options;var noTicks;if(typeof opts.ticks=="number"&&opts.ticks>0)noTicks=opts.ticks;else noTicks=.3*Math.sqrt(axis.direction=="x"?surface.width:surface.height);var delta=(axis.max-axis.min)/noTicks,dec=-Math.floor(Math.log(delta)/Math.LN10),maxDec=opts.tickDecimals;if(maxDec!=null&&dec>maxDec){dec=maxDec}var magn=Math.pow(10,-dec),norm=delta/magn,size;if(norm<1.5){size=1}else if(norm<3){size=2;if(norm>2.25&&(maxDec==null||dec+1<=maxDec)){size=2.5;++dec}}else if(norm<7.5){size=5}else{size=10}size*=magn;if(opts.minTickSize!=null&&size<opts.minTickSize){size=opts.minTickSize}axis.delta=delta;axis.tickDecimals=Math.max(0,maxDec!=null?maxDec:dec);axis.tickSize=opts.tickSize||size;if(opts.mode=="time"&&!axis.tickGenerator){throw new Error("Time mode requires the flot.time plugin.")}if(!axis.tickGenerator){axis.tickGenerator=function(axis){var ticks=[],start=floorInBase(axis.min,axis.tickSize),i=0,v=Number.NaN,prev;do{prev=v;v=start+i*axis.tickSize;ticks.push(v);++i}while(v<axis.max&&v!=prev);return ticks};axis.tickFormatter=function(value,axis){var factor=axis.tickDecimals?Math.pow(10,axis.tickDecimals):1;var formatted=""+Math.round(value*factor)/factor;if(axis.tickDecimals!=null){var decimal=formatted.indexOf(".");var precision=decimal==-1?0:formatted.length-decimal-1;if(precision<axis.tickDecimals){return(precision?formatted:formatted+".")+(""+factor).substr(1,axis.tickDecimals-precision)}}return formatted}}if($.isFunction(opts.tickFormatter))axis.tickFormatter=function(v,axis){return""+opts.tickFormatter(v,axis)};if(opts.alignTicksWithAxis!=null){var otherAxis=(axis.direction=="x"?xaxes:yaxes)[opts.alignTicksWithAxis-1];if(otherAxis&&otherAxis.used&&otherAxis!=axis){var niceTicks=axis.tickGenerator(axis);if(niceTicks.length>0){if(opts.min==null)axis.min=Math.min(axis.min,niceTicks[0]);if(opts.max==null&&niceTicks.length>1)axis.max=Math.max(axis.max,niceTicks[niceTicks.length-1])}axis.tickGenerator=function(axis){var ticks=[],v,i;for(i=0;i<otherAxis.ticks.length;++i){v=(otherAxis.ticks[i].v-otherAxis.min)/(otherAxis.max-otherAxis.min);v=axis.min+v*(axis.max-axis.min);ticks.push(v)}return ticks};if(!axis.mode&&opts.tickDecimals==null){var extraDec=Math.max(0,-Math.floor(Math.log(axis.delta)/Math.LN10)+1),ts=axis.tickGenerator(axis);if(!(ts.length>1&&/\..*0$/.test((ts[1]-ts[0]).toFixed(extraDec))))axis.tickDecimals=extraDec}}}}function setTicks(axis){var oticks=axis.options.ticks,ticks=[];if(oticks==null||typeof oticks=="number"&&oticks>0)ticks=axis.tickGenerator(axis);else if(oticks){if($.isFunction(oticks))ticks=oticks(axis);else ticks=oticks}var i,v;axis.ticks=[];for(i=0;i<ticks.length;++i){var label=null;var t=ticks[i];if(typeof t=="object"){v=+t[0];if(t.length>1)label=t[1]}else v=+t;if(label==null)label=axis.tickFormatter(v,axis);if(!isNaN(v))axis.ticks.push({v:v,label:label})}}function snapRangeToTicks(axis,ticks){if(axis.options.autoscaleMargin&&ticks.length>0){if(axis.options.min==null)axis.min=Math.min(axis.min,ticks[0].v);if(axis.options.max==null&&ticks.length>1)axis.max=Math.max(axis.max,ticks[ticks.length-1].v)}}function draw(){surface.clear();executeHooks(hooks.drawBackground,[ctx]);var grid=options.grid;if(grid.show&&grid.backgroundColor)drawBackground();if(grid.show&&!grid.aboveData){drawGrid()}for(var i=0;i<series.length;++i){executeHooks(hooks.drawSeries,[ctx,series[i]]);drawSeries(series[i])}executeHooks(hooks.draw,[ctx]);if(grid.show&&grid.aboveData){drawGrid()}surface.render();triggerRedrawOverlay()}function extractRange(ranges,coord){var axis,from,to,key,axes=allAxes();for(var i=0;i<axes.length;++i){axis=axes[i];if(axis.direction==coord){key=coord+axis.n+"axis";if(!ranges[key]&&axis.n==1)key=coord+"axis";if(ranges[key]){from=ranges[key].from;to=ranges[key].to;break}}}if(!ranges[key]){axis=coord=="x"?xaxes[0]:yaxes[0];from=ranges[coord+"1"];to=ranges[coord+"2"]}if(from!=null&&to!=null&&from>to){var tmp=from;from=to;to=tmp}return{from:from,to:to,axis:axis}}function drawBackground(){ctx.save();ctx.translate(plotOffset.left,plotOffset.top);ctx.fillStyle=getColorOrGradient(options.grid.backgroundColor,plotHeight,0,"rgba(255, 255, 255, 0)");ctx.fillRect(0,0,plotWidth,plotHeight);ctx.restore()}function drawGrid(){var i,axes,bw,bc;ctx.save();ctx.translate(plotOffset.left,plotOffset.top);var markings=options.grid.markings;if(markings){if($.isFunction(markings)){axes=plot.getAxes();axes.xmin=axes.xaxis.min;axes.xmax=axes.xaxis.max;axes.ymin=axes.yaxis.min;axes.ymax=axes.yaxis.max;markings=markings(axes)}for(i=0;i<markings.length;++i){var m=markings[i],xrange=extractRange(m,"x"),yrange=extractRange(m,"y");if(xrange.from==null)xrange.from=xrange.axis.min;if(xrange.to==null)xrange.to=xrange.axis.max;
+if(yrange.from==null)yrange.from=yrange.axis.min;if(yrange.to==null)yrange.to=yrange.axis.max;if(xrange.to<xrange.axis.min||xrange.from>xrange.axis.max||yrange.to<yrange.axis.min||yrange.from>yrange.axis.max)continue;xrange.from=Math.max(xrange.from,xrange.axis.min);xrange.to=Math.min(xrange.to,xrange.axis.max);yrange.from=Math.max(yrange.from,yrange.axis.min);yrange.to=Math.min(yrange.to,yrange.axis.max);var xequal=xrange.from===xrange.to,yequal=yrange.from===yrange.to;if(xequal&&yequal){continue}xrange.from=Math.floor(xrange.axis.p2c(xrange.from));xrange.to=Math.floor(xrange.axis.p2c(xrange.to));yrange.from=Math.floor(yrange.axis.p2c(yrange.from));yrange.to=Math.floor(yrange.axis.p2c(yrange.to));if(xequal||yequal){var lineWidth=m.lineWidth||options.grid.markingsLineWidth,subPixel=lineWidth%2?.5:0;ctx.beginPath();ctx.strokeStyle=m.color||options.grid.markingsColor;ctx.lineWidth=lineWidth;if(xequal){ctx.moveTo(xrange.to+subPixel,yrange.from);ctx.lineTo(xrange.to+subPixel,yrange.to)}else{ctx.moveTo(xrange.from,yrange.to+subPixel);ctx.lineTo(xrange.to,yrange.to+subPixel)}ctx.stroke()}else{ctx.fillStyle=m.color||options.grid.markingsColor;ctx.fillRect(xrange.from,yrange.to,xrange.to-xrange.from,yrange.from-yrange.to)}}}axes=allAxes();bw=options.grid.borderWidth;for(var j=0;j<axes.length;++j){var axis=axes[j],box=axis.box,t=axis.tickLength,x,y,xoff,yoff;if(!axis.show||axis.ticks.length==0)continue;ctx.lineWidth=1;if(axis.direction=="x"){x=0;if(t=="full")y=axis.position=="top"?0:plotHeight;else y=box.top-plotOffset.top+(axis.position=="top"?box.height:0)}else{y=0;if(t=="full")x=axis.position=="left"?0:plotWidth;else x=box.left-plotOffset.left+(axis.position=="left"?box.width:0)}if(!axis.innermost){ctx.strokeStyle=axis.options.color;ctx.beginPath();xoff=yoff=0;if(axis.direction=="x")xoff=plotWidth+1;else yoff=plotHeight+1;if(ctx.lineWidth==1){if(axis.direction=="x"){y=Math.floor(y)+.5}else{x=Math.floor(x)+.5}}ctx.moveTo(x,y);ctx.lineTo(x+xoff,y+yoff);ctx.stroke()}ctx.strokeStyle=axis.options.tickColor;ctx.beginPath();for(i=0;i<axis.ticks.length;++i){var v=axis.ticks[i].v;xoff=yoff=0;if(isNaN(v)||v<axis.min||v>axis.max||t=="full"&&(typeof bw=="object"&&bw[axis.position]>0||bw>0)&&(v==axis.min||v==axis.max))continue;if(axis.direction=="x"){x=axis.p2c(v);yoff=t=="full"?-plotHeight:t;if(axis.position=="top")yoff=-yoff}else{y=axis.p2c(v);xoff=t=="full"?-plotWidth:t;if(axis.position=="left")xoff=-xoff}if(ctx.lineWidth==1){if(axis.direction=="x")x=Math.floor(x)+.5;else y=Math.floor(y)+.5}ctx.moveTo(x,y);ctx.lineTo(x+xoff,y+yoff)}ctx.stroke()}if(bw){bc=options.grid.borderColor;if(typeof bw=="object"||typeof bc=="object"){if(typeof bw!=="object"){bw={top:bw,right:bw,bottom:bw,left:bw}}if(typeof bc!=="object"){bc={top:bc,right:bc,bottom:bc,left:bc}}if(bw.top>0){ctx.strokeStyle=bc.top;ctx.lineWidth=bw.top;ctx.beginPath();ctx.moveTo(0-bw.left,0-bw.top/2);ctx.lineTo(plotWidth,0-bw.top/2);ctx.stroke()}if(bw.right>0){ctx.strokeStyle=bc.right;ctx.lineWidth=bw.right;ctx.beginPath();ctx.moveTo(plotWidth+bw.right/2,0-bw.top);ctx.lineTo(plotWidth+bw.right/2,plotHeight);ctx.stroke()}if(bw.bottom>0){ctx.strokeStyle=bc.bottom;ctx.lineWidth=bw.bottom;ctx.beginPath();ctx.moveTo(plotWidth+bw.right,plotHeight+bw.bottom/2);ctx.lineTo(0,plotHeight+bw.bottom/2);ctx.stroke()}if(bw.left>0){ctx.strokeStyle=bc.left;ctx.lineWidth=bw.left;ctx.beginPath();ctx.moveTo(0-bw.left/2,plotHeight+bw.bottom);ctx.lineTo(0-bw.left/2,0);ctx.stroke()}}else{ctx.lineWidth=bw;ctx.strokeStyle=options.grid.borderColor;ctx.strokeRect(-bw/2,-bw/2,plotWidth+bw,plotHeight+bw)}}ctx.restore()}function drawAxisLabels(){$.each(allAxes(),function(_,axis){var box=axis.box,legacyStyles=axis.direction+"Axis "+axis.direction+axis.n+"Axis",layer="flot-"+axis.direction+"-axis flot-"+axis.direction+axis.n+"-axis "+legacyStyles,font=axis.options.font||"flot-tick-label tickLabel",tick,x,y,halign,valign;surface.removeText(layer);if(!axis.show||axis.ticks.length==0)return;for(var i=0;i<axis.ticks.length;++i){tick=axis.ticks[i];if(!tick.label||tick.v<axis.min||tick.v>axis.max)continue;if(axis.direction=="x"){halign="center";x=plotOffset.left+axis.p2c(tick.v);if(axis.position=="bottom"){y=box.top+box.padding}else{y=box.top+box.height-box.padding;valign="bottom"}}else{valign="middle";y=plotOffset.top+axis.p2c(tick.v);if(axis.position=="left"){x=box.left+box.width-box.padding;halign="right"}else{x=box.left+box.padding}}surface.addText(layer,x,y,tick.label,font,null,null,halign,valign)}})}function drawSeries(series){if(series.lines.show)drawSeriesLines(series);if(series.bars.show)drawSeriesBars(series);if(series.points.show)drawSeriesPoints(series)}function drawSeriesLines(series){function plotLine(datapoints,xoffset,yoffset,axisx,axisy){var points=datapoints.points,ps=datapoints.pointsize,prevx=null,prevy=null;ctx.beginPath();for(var i=ps;i<points.length;i+=ps){var x1=points[i-ps],y1=points[i-ps+1],x2=points[i],y2=points[i+1];if(x1==null||x2==null)continue;if(y1<=y2&&y1<axisy.min){if(y2<axisy.min)continue;x1=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.min}else if(y2<=y1&&y2<axisy.min){if(y1<axisy.min)continue;x2=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.min}if(y1>=y2&&y1>axisy.max){if(y2>axisy.max)continue;x1=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.max}else if(y2>=y1&&y2>axisy.max){if(y1>axisy.max)continue;x2=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.max}if(x1<=x2&&x1<axisx.min){if(x2<axisx.min)continue;y1=(axisx.min-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.min}else if(x2<=x1&&x2<axisx.min){if(x1<axisx.min)continue;y2=(axisx.min-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.min}if(x1>=x2&&x1>axisx.max){if(x2>axisx.max)continue;y1=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.max}else if(x2>=x1&&x2>axisx.max){if(x1>axisx.max)continue;y2=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.max}if(x1!=prevx||y1!=prevy)ctx.moveTo(axisx.p2c(x1)+xoffset,axisy.p2c(y1)+yoffset);prevx=x2;prevy=y2;ctx.lineTo(axisx.p2c(x2)+xoffset,axisy.p2c(y2)+yoffset)}ctx.stroke()}function plotLineArea(datapoints,axisx,axisy){var points=datapoints.points,ps=datapoints.pointsize,bottom=Math.min(Math.max(0,axisy.min),axisy.max),i=0,top,areaOpen=false,ypos=1,segmentStart=0,segmentEnd=0;while(true){if(ps>0&&i>points.length+ps)break;i+=ps;var x1=points[i-ps],y1=points[i-ps+ypos],x2=points[i],y2=points[i+ypos];if(areaOpen){if(ps>0&&x1!=null&&x2==null){segmentEnd=i;ps=-ps;ypos=2;continue}if(ps<0&&i==segmentStart+ps){ctx.fill();areaOpen=false;ps=-ps;ypos=1;i=segmentStart=segmentEnd+ps;continue}}if(x1==null||x2==null)continue;if(x1<=x2&&x1<axisx.min){if(x2<axisx.min)continue;y1=(axisx.min-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.min}else if(x2<=x1&&x2<axisx.min){if(x1<axisx.min)continue;y2=(axisx.min-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.min}if(x1>=x2&&x1>axisx.max){if(x2>axisx.max)continue;y1=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x1=axisx.max}else if(x2>=x1&&x2>axisx.max){if(x1>axisx.max)continue;y2=(axisx.max-x1)/(x2-x1)*(y2-y1)+y1;x2=axisx.max}if(!areaOpen){ctx.beginPath();ctx.moveTo(axisx.p2c(x1),axisy.p2c(bottom));areaOpen=true}if(y1>=axisy.max&&y2>=axisy.max){ctx.lineTo(axisx.p2c(x1),axisy.p2c(axisy.max));ctx.lineTo(axisx.p2c(x2),axisy.p2c(axisy.max));continue}else if(y1<=axisy.min&&y2<=axisy.min){ctx.lineTo(axisx.p2c(x1),axisy.p2c(axisy.min));ctx.lineTo(axisx.p2c(x2),axisy.p2c(axisy.min));continue}var x1old=x1,x2old=x2;if(y1<=y2&&y1<axisy.min&&y2>=axisy.min){x1=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.min}else if(y2<=y1&&y2<axisy.min&&y1>=axisy.min){x2=(axisy.min-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.min}if(y1>=y2&&y1>axisy.max&&y2<=axisy.max){x1=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y1=axisy.max}else if(y2>=y1&&y2>axisy.max&&y1<=axisy.max){x2=(axisy.max-y1)/(y2-y1)*(x2-x1)+x1;y2=axisy.max}if(x1!=x1old){ctx.lineTo(axisx.p2c(x1old),axisy.p2c(y1))}ctx.lineTo(axisx.p2c(x1),axisy.p2c(y1));ctx.lineTo(axisx.p2c(x2),axisy.p2c(y2));if(x2!=x2old){ctx.lineTo(axisx.p2c(x2),axisy.p2c(y2));ctx.lineTo(axisx.p2c(x2old),axisy.p2c(y2))}}}ctx.save();ctx.translate(plotOffset.left,plotOffset.top);ctx.lineJoin="round";var lw=series.lines.lineWidth,sw=series.shadowSize;if(lw>0&&sw>0){ctx.lineWidth=sw;ctx.strokeStyle="rgba(0,0,0,0.1)";var angle=Math.PI/18;plotLine(series.datapoints,Math.sin(angle)*(lw/2+sw/2),Math.cos(angle)*(lw/2+sw/2),series.xaxis,series.yaxis);ctx.lineWidth=sw/2;plotLine(series.datapoints,Math.sin(angle)*(lw/2+sw/4),Math.cos(angle)*(lw/2+sw/4),series.xaxis,series.yaxis)}ctx.lineWidth=lw;ctx.strokeStyle=series.color;var fillStyle=getFillStyle(series.lines,series.color,0,plotHeight);if(fillStyle){ctx.fillStyle=fillStyle;plotLineArea(series.datapoints,series.xaxis,series.yaxis)}if(lw>0)plotLine(series.datapoints,0,0,series.xaxis,series.yaxis);ctx.restore()}function drawSeriesPoints(series){function plotPoints(datapoints,radius,fillStyle,offset,shadow,axisx,axisy,symbol){var points=datapoints.points,ps=datapoints.pointsize;for(var i=0;i<points.length;i+=ps){var x=points[i],y=points[i+1];if(x==null||x<axisx.min||x>axisx.max||y<axisy.min||y>axisy.max)continue;ctx.beginPath();x=axisx.p2c(x);y=axisy.p2c(y)+offset;if(symbol=="circle")ctx.arc(x,y,radius,0,shadow?Math.PI:Math.PI*2,false);else symbol(ctx,x,y,radius,shadow);ctx.closePath();if(fillStyle){ctx.fillStyle=fillStyle;ctx.fill()}ctx.stroke()}}ctx.save();ctx.translate(plotOffset.left,plotOffset.top);var lw=series.points.lineWidth,sw=series.shadowSize,radius=series.points.radius,symbol=series.points.symbol;if(lw==0)lw=1e-4;if(lw>0&&sw>0){var w=sw/2;ctx.lineWidth=w;ctx.strokeStyle="rgba(0,0,0,0.1)";plotPoints(series.datapoints,radius,null,w+w/2,true,series.xaxis,series.yaxis,symbol);ctx.strokeStyle="rgba(0,0,0,0.2)";plotPoints(series.datapoints,radius,null,w/2,true,series.xaxis,series.yaxis,symbol)}ctx.lineWidth=lw;ctx.strokeStyle=series.color;plotPoints(series.datapoints,radius,getFillStyle(series.points,series.color),0,false,series.xaxis,series.yaxis,symbol);ctx.restore()}function drawBar(x,y,b,barLeft,barRight,fillStyleCallback,axisx,axisy,c,horizontal,lineWidth){var left,right,bottom,top,drawLeft,drawRight,drawTop,drawBottom,tmp;if(horizontal){drawBottom=drawRight=drawTop=true;drawLeft=false;left=b;right=x;top=y+barLeft;bottom=y+barRight;if(right<left){tmp=right;right=left;left=tmp;drawLeft=true;drawRight=false}}else{drawLeft=drawRight=drawTop=true;drawBottom=false;left=x+barLeft;right=x+barRight;bottom=b;top=y;if(top<bottom){tmp=top;top=bottom;bottom=tmp;drawBottom=true;drawTop=false}}if(right<axisx.min||left>axisx.max||top<axisy.min||bottom>axisy.max)return;if(left<axisx.min){left=axisx.min;drawLeft=false}if(right>axisx.max){right=axisx.max;drawRight=false}if(bottom<axisy.min){bottom=axisy.min;drawBottom=false}if(top>axisy.max){top=axisy.max;drawTop=false}left=axisx.p2c(left);bottom=axisy.p2c(bottom);right=axisx.p2c(right);top=axisy.p2c(top);if(fillStyleCallback){c.fillStyle=fillStyleCallback(bottom,top);c.fillRect(left,top,right-left,bottom-top)}if(lineWidth>0&&(drawLeft||drawRight||drawTop||drawBottom)){c.beginPath();c.moveTo(left,bottom);if(drawLeft)c.lineTo(left,top);else c.moveTo(left,top);if(drawTop)c.lineTo(right,top);else c.moveTo(right,top);if(drawRight)c.lineTo(right,bottom);else c.moveTo(right,bottom);if(drawBottom)c.lineTo(left,bottom);else c.moveTo(left,bottom);c.stroke()}}function drawSeriesBars(series){function plotBars(datapoints,barLeft,barRight,fillStyleCallback,axisx,axisy){var points=datapoints.points,ps=datapoints.pointsize;for(var i=0;i<points.length;i+=ps){if(points[i]==null)continue;drawBar(points[i],points[i+1],points[i+2],barLeft,barRight,fillStyleCallback,axisx,axisy,ctx,series.bars.horizontal,series.bars.lineWidth)}}ctx.save();ctx.translate(plotOffset.left,plotOffset.top);ctx.lineWidth=series.bars.lineWidth;ctx.strokeStyle=series.color;var barLeft;switch(series.bars.align){case"left":barLeft=0;break;case"right":barLeft=-series.bars.barWidth;break;default:barLeft=-series.bars.barWidth/2}var fillStyleCallback=series.bars.fill?function(bottom,top){return getFillStyle(series.bars,series.color,bottom,top)}:null;plotBars(series.datapoints,barLeft,barLeft+series.bars.barWidth,fillStyleCallback,series.xaxis,series.yaxis);ctx.restore()}function getFillStyle(filloptions,seriesColor,bottom,top){var fill=filloptions.fill;if(!fill)return null;if(filloptions.fillColor)return getColorOrGradient(filloptions.fillColor,bottom,top,seriesColor);var c=$.color.parse(seriesColor);c.a=typeof fill=="number"?fill:.4;c.normalize();return c.toString()}function insertLegend(){if(options.legend.container!=null){$(options.legend.container).html("")}else{placeholder.find(".legend").remove()}if(!options.legend.show){return}var fragments=[],entries=[],rowStarted=false,lf=options.legend.labelFormatter,s,label;for(var i=0;i<series.length;++i){s=series[i];if(s.label){label=lf?lf(s.label,s):s.label;if(label){entries.push({label:label,color:s.color})}}}if(options.legend.sorted){if($.isFunction(options.legend.sorted)){entries.sort(options.legend.sorted)}else if(options.legend.sorted=="reverse"){entries.reverse()}else{var ascending=options.legend.sorted!="descending";entries.sort(function(a,b){return a.label==b.label?0:a.label<b.label!=ascending?1:-1})}}for(var i=0;i<entries.length;++i){var entry=entries[i];if(i%options.legend.noColumns==0){if(rowStarted)fragments.push("</tr>");fragments.push("<tr>");rowStarted=true}fragments.push('<td class="legendColorBox"><div style="border:1px solid '+options.legend.labelBoxBorderColor+';padding:1px"><div style="width:4px;height:0;border:5px solid '+entry.color+';overflow:hidden"></div></div></td>'+'<td class="legendLabel">'+entry.label+"</td>")}if(rowStarted)fragments.push("</tr>");if(fragments.length==0)return;var table='<table style="font-size:smaller;color:'+options.grid.color+'">'+fragments.join("")+"</table>";if(options.legend.container!=null)$(options.legend.container).html(table);else{var pos="",p=options.legend.position,m=options.legend.margin;if(m[0]==null)m=[m,m];if(p.charAt(0)=="n")pos+="top:"+(m[1]+plotOffset.top)+"px;";else if(p.charAt(0)=="s")pos+="bottom:"+(m[1]+plotOffset.bottom)+"px;";if(p.charAt(1)=="e")pos+="right:"+(m[0]+plotOffset.right)+"px;";else if(p.charAt(1)=="w")pos+="left:"+(m[0]+plotOffset.left)+"px;";var legend=$('<div class="legend">'+table.replace('style="','style="position:absolute;'+pos+";")+"</div>").appendTo(placeholder);if(options.legend.backgroundOpacity!=0){var c=options.legend.backgroundColor;if(c==null){c=options.grid.backgroundColor;if(c&&typeof c=="string")c=$.color.parse(c);else c=$.color.extract(legend,"background-color");c.a=1;c=c.toString()}var div=legend.children();$('<div style="position:absolute;width:'+div.width()+"px;height:"+div.height()+"px;"+pos+"background-color:"+c+';"> </div>').prependTo(legend).css("opacity",options.legend.backgroundOpacity)}}}var highlights=[],redrawTimeout=null;function findNearbyItem(mouseX,mouseY,seriesFilter){var maxDistance=options.grid.mouseActiveRadius,smallestDistance=maxDistance*maxDistance+1,item=null,foundPoint=false,i,j,ps;for(i=series.length-1;i>=0;--i){if(!seriesFilter(series[i]))continue;var s=series[i],axisx=s.xaxis,axisy=s.yaxis,points=s.datapoints.points,mx=axisx.c2p(mouseX),my=axisy.c2p(mouseY),maxx=maxDistance/axisx.scale,maxy=maxDistance/axisy.scale;ps=s.datapoints.pointsize;if(axisx.options.inverseTransform)maxx=Number.MAX_VALUE;if(axisy.options.inverseTransform)maxy=Number.MAX_VALUE;if(s.lines.show||s.points.show){for(j=0;j<points.length;j+=ps){var x=points[j],y=points[j+1];if(x==null)continue;if(x-mx>maxx||x-mx<-maxx||y-my>maxy||y-my<-maxy)continue;var dx=Math.abs(axisx.p2c(x)-mouseX),dy=Math.abs(axisy.p2c(y)-mouseY),dist=dx*dx+dy*dy;if(dist<smallestDistance){smallestDistance=dist;item=[i,j/ps]}}}if(s.bars.show&&!item){var barLeft,barRight;switch(s.bars.align){case"left":barLeft=0;break;case"right":barLeft=-s.bars.barWidth;break;default:barLeft=-s.bars.barWidth/2}barRight=barLeft+s.bars.barWidth;for(j=0;j<points.length;j+=ps){var x=points[j],y=points[j+1],b=points[j+2];if(x==null)continue;if(series[i].bars.horizontal?mx<=Math.max(b,x)&&mx>=Math.min(b,x)&&my>=y+barLeft&&my<=y+barRight:mx>=x+barLeft&&mx<=x+barRight&&my>=Math.min(b,y)&&my<=Math.max(b,y))item=[i,j/ps]}}}if(item){i=item[0];j=item[1];ps=series[i].datapoints.pointsize;return{datapoint:series[i].datapoints.points.slice(j*ps,(j+1)*ps),dataIndex:j,series:series[i],seriesIndex:i}}return null}function onMouseMove(e){if(options.grid.hoverable)triggerClickHoverEvent("plothover",e,function(s){return s["hoverable"]!=false})}function onMouseLeave(e){if(options.grid.hoverable)triggerClickHoverEvent("plothover",e,function(s){return false})}function onClick(e){triggerClickHoverEvent("plotclick",e,function(s){return s["clickable"]!=false})}function triggerClickHoverEvent(eventname,event,seriesFilter){var offset=eventHolder.offset(),canvasX=event.pageX-offset.left-plotOffset.left,canvasY=event.pageY-offset.top-plotOffset.top,pos=canvasToAxisCoords({left:canvasX,top:canvasY});pos.pageX=event.pageX;pos.pageY=event.pageY;var item=findNearbyItem(canvasX,canvasY,seriesFilter);if(item){item.pageX=parseInt(item.series.xaxis.p2c(item.datapoint[0])+offset.left+plotOffset.left,10);item.pageY=parseInt(item.series.yaxis.p2c(item.datapoint[1])+offset.top+plotOffset.top,10)}if(options.grid.autoHighlight){for(var i=0;i<highlights.length;++i){var h=highlights[i];if(h.auto==eventname&&!(item&&h.series==item.series&&h.point[0]==item.datapoint[0]&&h.point[1]==item.datapoint[1]))unhighlight(h.series,h.point)}if(item)highlight(item.series,item.datapoint,eventname)}placeholder.trigger(eventname,[pos,item])}function triggerRedrawOverlay(){var t=options.interaction.redrawOverlayInterval;if(t==-1){drawOverlay();return}if(!redrawTimeout)redrawTimeout=setTimeout(drawOverlay,t)}function drawOverlay(){redrawTimeout=null;octx.save();overlay.clear();octx.translate(plotOffset.left,plotOffset.top);var i,hi;for(i=0;i<highlights.length;++i){hi=highlights[i];if(hi.series.bars.show)drawBarHighlight(hi.series,hi.point);else drawPointHighlight(hi.series,hi.point)}octx.restore();executeHooks(hooks.drawOverlay,[octx])}function highlight(s,point,auto){if(typeof s=="number")s=series[s];if(typeof point=="number"){var ps=s.datapoints.pointsize;point=s.datapoints.points.slice(ps*point,ps*(point+1))}var i=indexOfHighlight(s,point);if(i==-1){highlights.push({series:s,point:point,auto:auto});triggerRedrawOverlay()}else if(!auto)highlights[i].auto=false}function unhighlight(s,point){if(s==null&&point==null){highlights=[];triggerRedrawOverlay();return}if(typeof s=="number")s=series[s];if(typeof point=="number"){var ps=s.datapoints.pointsize;point=s.datapoints.points.slice(ps*point,ps*(point+1))}var i=indexOfHighlight(s,point);if(i!=-1){highlights.splice(i,1);triggerRedrawOverlay()}}function indexOfHighlight(s,p){for(var i=0;i<highlights.length;++i){var h=highlights[i];if(h.series==s&&h.point[0]==p[0]&&h.point[1]==p[1])return i}return-1}function drawPointHighlight(series,point){var x=point[0],y=point[1],axisx=series.xaxis,axisy=series.yaxis,highlightColor=typeof series.highlightColor==="string"?series.highlightColor:$.color.parse(series.color).scale("a",.5).toString();if(x<axisx.min||x>axisx.max||y<axisy.min||y>axisy.max)return;var pointRadius=series.points.radius+series.points.lineWidth/2;octx.lineWidth=pointRadius;octx.strokeStyle=highlightColor;var radius=1.5*pointRadius;x=axisx.p2c(x);y=axisy.p2c(y);octx.beginPath();if(series.points.symbol=="circle")octx.arc(x,y,radius,0,2*Math.PI,false);else series.points.symbol(octx,x,y,radius,false);octx.closePath();octx.stroke()}function drawBarHighlight(series,point){var highlightColor=typeof series.highlightColor==="string"?series.highlightColor:$.color.parse(series.color).scale("a",.5).toString(),fillStyle=highlightColor,barLeft;switch(series.bars.align){case"left":barLeft=0;break;case"right":barLeft=-series.bars.barWidth;break;default:barLeft=-series.bars.barWidth/2}octx.lineWidth=series.bars.lineWidth;octx.strokeStyle=highlightColor;drawBar(point[0],point[1],point[2]||0,barLeft,barLeft+series.bars.barWidth,function(){return fillStyle},series.xaxis,series.yaxis,octx,series.bars.horizontal,series.bars.lineWidth)}function getColorOrGradient(spec,bottom,top,defaultColor){if(typeof spec=="string")return spec;else{var gradient=ctx.createLinearGradient(0,top,0,bottom);for(var i=0,l=spec.colors.length;i<l;++i){var c=spec.colors[i];if(typeof c!="string"){var co=$.color.parse(defaultColor);if(c.brightness!=null)co=co.scale("rgb",c.brightness);if(c.opacity!=null)co.a*=c.opacity;c=co.toString()}gradient.addColorStop(i/(l-1),c)}return gradient}}}$.plot=function(placeholder,data,options){var plot=new Plot($(placeholder),data,options,$.plot.plugins);return plot};$.plot.version="0.8.3";$.plot.plugins=[];$.fn.plot=function(data,options){return this.each(function(){$.plot(this,data,options)})};function floorInBase(n,base){return base*Math.floor(n/base)}})(jQuery);
diff --git a/library/cpp/lwtrace/mon/static/js/jquery.flot.navigate.min.js b/library/cpp/lwtrace/mon/static/js/jquery.flot.navigate.min.js
new file mode 100644
index 0000000000..af5ecd21e1
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/jquery.flot.navigate.min.js
@@ -0,0 +1,7 @@
+/* Javascript plotting library for jQuery, version 0.8.3.
+
+Copyright (c) 2007-2014 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+*/
+(function(a){function e(h){var k,j=this,l=h.data||{};if(l.elem)j=h.dragTarget=l.elem,h.dragProxy=d.proxy||j,h.cursorOffsetX=l.pageX-l.left,h.cursorOffsetY=l.pageY-l.top,h.offsetX=h.pageX-h.cursorOffsetX,h.offsetY=h.pageY-h.cursorOffsetY;else if(d.dragging||l.which>0&&h.which!=l.which||a(h.target).is(l.not))return;switch(h.type){case"mousedown":return a.extend(l,a(j).offset(),{elem:j,target:h.target,pageX:h.pageX,pageY:h.pageY}),b.add(document,"mousemove mouseup",e,l),i(j,!1),d.dragging=null,!1;case!d.dragging&&"mousemove":if(g(h.pageX-l.pageX)+g(h.pageY-l.pageY)<l.distance)break;h.target=l.target,k=f(h,"dragstart",j),k!==!1&&(d.dragging=j,d.proxy=h.dragProxy=a(k||j)[0]);case"mousemove":if(d.dragging){if(k=f(h,"drag",j),c.drop&&(c.drop.allowed=k!==!1,c.drop.handler(h)),k!==!1)break;h.type="mouseup"}case"mouseup":b.remove(document,"mousemove mouseup",e),d.dragging&&(c.drop&&c.drop.handler(h),f(h,"dragend",j)),i(j,!0),d.dragging=d.proxy=l.elem=!1}return!0}function f(b,c,d){b.type=c;var e=a.event.dispatch.call(d,b);return e===!1?!1:e||b.result}function g(a){return Math.pow(a,2)}function h(){return d.dragging===!1}function i(a,b){a&&(a.unselectable=b?"off":"on",a.onselectstart=function(){return b},a.style&&(a.style.MozUserSelect=b?"":"none"))}a.fn.drag=function(a,b,c){return b&&this.bind("dragstart",a),c&&this.bind("dragend",c),a?this.bind("drag",b?b:a):this.trigger("drag")};var b=a.event,c=b.special,d=c.drag={not:":input",distance:0,which:1,dragging:!1,setup:function(c){c=a.extend({distance:d.distance,which:d.which,not:d.not},c||{}),c.distance=g(c.distance),b.add(this,"mousedown",e,c),this.attachEvent&&this.attachEvent("ondragstart",h)},teardown:function(){b.remove(this,"mousedown",e),this===d.dragging&&(d.dragging=d.proxy=!1),i(this,!0),this.detachEvent&&this.detachEvent("ondragstart",h)}};c.dragstart=c.dragend={setup:function(){},teardown:function(){}}})(jQuery);(function(d){function e(a){var b=a||window.event,c=[].slice.call(arguments,1),f=0,e=0,g=0,a=d.event.fix(b);a.type="mousewheel";b.wheelDelta&&(f=b.wheelDelta/120);b.detail&&(f=-b.detail/3);g=f;void 0!==b.axis&&b.axis===b.HORIZONTAL_AXIS&&(g=0,e=-1*f);void 0!==b.wheelDeltaY&&(g=b.wheelDeltaY/120);void 0!==b.wheelDeltaX&&(e=-1*b.wheelDeltaX/120);c.unshift(a,f,e,g);return(d.event.dispatch||d.event.handle).apply(this,c)}var c=["DOMMouseScroll","mousewheel"];if(d.event.fixHooks)for(var h=c.length;h;)d.event.fixHooks[c[--h]]=d.event.mouseHooks;d.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=c.length;a;)this.addEventListener(c[--a],e,!1);else this.onmousewheel=e},teardown:function(){if(this.removeEventListener)for(var a=c.length;a;)this.removeEventListener(c[--a],e,!1);else this.onmousewheel=null}};d.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery);(function($){var options={xaxis:{zoomRange:null,panRange:null},zoom:{interactive:false,trigger:"dblclick",amount:1.5},pan:{interactive:false,cursor:"move",frameRate:20}};function init(plot){function onZoomClick(e,zoomOut){var c=plot.offset();c.left=e.pageX-c.left;c.top=e.pageY-c.top;if(zoomOut)plot.zoomOut({center:c});else plot.zoom({center:c})}function onMouseWheel(e,delta){e.preventDefault();onZoomClick(e,delta<0);return false}var prevCursor="default",prevPageX=0,prevPageY=0,panTimeout=null;function onDragStart(e){if(e.which!=1)return false;var c=plot.getPlaceholder().css("cursor");if(c)prevCursor=c;plot.getPlaceholder().css("cursor",plot.getOptions().pan.cursor);prevPageX=e.pageX;prevPageY=e.pageY}function onDrag(e){var frameRate=plot.getOptions().pan.frameRate;if(panTimeout||!frameRate)return;panTimeout=setTimeout(function(){plot.pan({left:prevPageX-e.pageX,top:prevPageY-e.pageY});prevPageX=e.pageX;prevPageY=e.pageY;panTimeout=null},1/frameRate*1e3)}function onDragEnd(e){if(panTimeout){clearTimeout(panTimeout);panTimeout=null}plot.getPlaceholder().css("cursor",prevCursor);plot.pan({left:prevPageX-e.pageX,top:prevPageY-e.pageY})}function bindEvents(plot,eventHolder){var o=plot.getOptions();if(o.zoom.interactive){eventHolder[o.zoom.trigger](onZoomClick);eventHolder.mousewheel(onMouseWheel)}if(o.pan.interactive){eventHolder.bind("dragstart",{distance:10},onDragStart);eventHolder.bind("drag",onDrag);eventHolder.bind("dragend",onDragEnd)}}plot.zoomOut=function(args){if(!args)args={};if(!args.amount)args.amount=plot.getOptions().zoom.amount;args.amount=1/args.amount;plot.zoom(args)};plot.zoom=function(args){if(!args)args={};var c=args.center,amount=args.amount||plot.getOptions().zoom.amount,w=plot.width(),h=plot.height();if(!c)c={left:w/2,top:h/2};var xf=c.left/w,yf=c.top/h,minmax={x:{min:c.left-xf*w/amount,max:c.left+(1-xf)*w/amount},y:{min:c.top-yf*h/amount,max:c.top+(1-yf)*h/amount}};$.each(plot.getAxes(),function(_,axis){var opts=axis.options,min=minmax[axis.direction].min,max=minmax[axis.direction].max,zr=opts.zoomRange,pr=opts.panRange;if(zr===false)return;min=axis.c2p(min);max=axis.c2p(max);if(min>max){var tmp=min;min=max;max=tmp}if(pr){if(pr[0]!=null&&min<pr[0]){min=pr[0]}if(pr[1]!=null&&max>pr[1]){max=pr[1]}}var range=max-min;if(zr&&(zr[0]!=null&&range<zr[0]&&amount>1||zr[1]!=null&&range>zr[1]&&amount<1))return;opts.min=min;opts.max=max});plot.setupGrid();plot.draw();if(!args.preventEvent)plot.getPlaceholder().trigger("plotzoom",[plot,args])};plot.pan=function(args){var delta={x:+args.left,y:+args.top};if(isNaN(delta.x))delta.x=0;if(isNaN(delta.y))delta.y=0;$.each(plot.getAxes(),function(_,axis){var opts=axis.options,min,max,d=delta[axis.direction];min=axis.c2p(axis.p2c(axis.min)+d),max=axis.c2p(axis.p2c(axis.max)+d);var pr=opts.panRange;if(pr===false)return;if(pr){if(pr[0]!=null&&pr[0]>min){d=pr[0]-min;min+=d;max+=d}if(pr[1]!=null&&pr[1]<max){d=pr[1]-max;min+=d;max+=d}}opts.min=min;opts.max=max});plot.setupGrid();plot.draw();if(!args.preventEvent)plot.getPlaceholder().trigger("plotpan",[plot,args])};function shutdown(plot,eventHolder){eventHolder.unbind(plot.getOptions().zoom.trigger,onZoomClick);eventHolder.unbind("mousewheel",onMouseWheel);eventHolder.unbind("dragstart",onDragStart);eventHolder.unbind("drag",onDrag);eventHolder.unbind("dragend",onDragEnd);if(panTimeout)clearTimeout(panTimeout)}plot.hooks.bindEvents.push(bindEvents);plot.hooks.shutdown.push(shutdown)}$.plot.plugins.push({init:init,options:options,name:"navigate",version:"1.3"})})(jQuery);
diff --git a/library/cpp/lwtrace/mon/static/js/jquery.flot.selection.min.js b/library/cpp/lwtrace/mon/static/js/jquery.flot.selection.min.js
new file mode 100644
index 0000000000..a0154fbc5b
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/jquery.flot.selection.min.js
@@ -0,0 +1,7 @@
+/* Javascript plotting library for jQuery, version 0.8.3.
+
+Copyright (c) 2007-2014 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+*/
+(function($){function init(plot){var selection={first:{x:-1,y:-1},second:{x:-1,y:-1},show:false,active:false};var savedhandlers={};var mouseUpHandler=null;function onMouseMove(e){if(selection.active){updateSelection(e);plot.getPlaceholder().trigger("plotselecting",[getSelection()])}}function onMouseDown(e){if(e.which!=1)return;document.body.focus();if(document.onselectstart!==undefined&&savedhandlers.onselectstart==null){savedhandlers.onselectstart=document.onselectstart;document.onselectstart=function(){return false}}if(document.ondrag!==undefined&&savedhandlers.ondrag==null){savedhandlers.ondrag=document.ondrag;document.ondrag=function(){return false}}setSelectionPos(selection.first,e);selection.active=true;mouseUpHandler=function(e){onMouseUp(e)};$(document).one("mouseup",mouseUpHandler)}function onMouseUp(e){mouseUpHandler=null;if(document.onselectstart!==undefined)document.onselectstart=savedhandlers.onselectstart;if(document.ondrag!==undefined)document.ondrag=savedhandlers.ondrag;selection.active=false;updateSelection(e);if(selectionIsSane())triggerSelectedEvent();else{plot.getPlaceholder().trigger("plotunselected",[]);plot.getPlaceholder().trigger("plotselecting",[null])}return false}function getSelection(){if(!selectionIsSane())return null;if(!selection.show)return null;var r={},c1=selection.first,c2=selection.second;$.each(plot.getAxes(),function(name,axis){if(axis.used){var p1=axis.c2p(c1[axis.direction]),p2=axis.c2p(c2[axis.direction]);r[name]={from:Math.min(p1,p2),to:Math.max(p1,p2)}}});return r}function triggerSelectedEvent(){var r=getSelection();plot.getPlaceholder().trigger("plotselected",[r]);if(r.xaxis&&r.yaxis)plot.getPlaceholder().trigger("selected",[{x1:r.xaxis.from,y1:r.yaxis.from,x2:r.xaxis.to,y2:r.yaxis.to}])}function clamp(min,value,max){return value<min?min:value>max?max:value}function setSelectionPos(pos,e){var o=plot.getOptions();var offset=plot.getPlaceholder().offset();var plotOffset=plot.getPlotOffset();pos.x=clamp(0,e.pageX-offset.left-plotOffset.left,plot.width());pos.y=clamp(0,e.pageY-offset.top-plotOffset.top,plot.height());if(o.selection.mode=="y")pos.x=pos==selection.first?0:plot.width();if(o.selection.mode=="x")pos.y=pos==selection.first?0:plot.height()}function updateSelection(pos){if(pos.pageX==null)return;setSelectionPos(selection.second,pos);if(selectionIsSane()){selection.show=true;plot.triggerRedrawOverlay()}else clearSelection(true)}function clearSelection(preventEvent){if(selection.show){selection.show=false;plot.triggerRedrawOverlay();if(!preventEvent)plot.getPlaceholder().trigger("plotunselected",[])}}function extractRange(ranges,coord){var axis,from,to,key,axes=plot.getAxes();for(var k in axes){axis=axes[k];if(axis.direction==coord){key=coord+axis.n+"axis";if(!ranges[key]&&axis.n==1)key=coord+"axis";if(ranges[key]){from=ranges[key].from;to=ranges[key].to;break}}}if(!ranges[key]){axis=coord=="x"?plot.getXAxes()[0]:plot.getYAxes()[0];from=ranges[coord+"1"];to=ranges[coord+"2"]}if(from!=null&&to!=null&&from>to){var tmp=from;from=to;to=tmp}return{from:from,to:to,axis:axis}}function setSelection(ranges,preventEvent){var axis,range,o=plot.getOptions();if(o.selection.mode=="y"){selection.first.x=0;selection.second.x=plot.width()}else{range=extractRange(ranges,"x");selection.first.x=range.axis.p2c(range.from);selection.second.x=range.axis.p2c(range.to)}if(o.selection.mode=="x"){selection.first.y=0;selection.second.y=plot.height()}else{range=extractRange(ranges,"y");selection.first.y=range.axis.p2c(range.from);selection.second.y=range.axis.p2c(range.to)}selection.show=true;plot.triggerRedrawOverlay();if(!preventEvent&&selectionIsSane())triggerSelectedEvent()}function selectionIsSane(){var minSize=plot.getOptions().selection.minSize;return Math.abs(selection.second.x-selection.first.x)>=minSize&&Math.abs(selection.second.y-selection.first.y)>=minSize}plot.clearSelection=clearSelection;plot.setSelection=setSelection;plot.getSelection=getSelection;plot.hooks.bindEvents.push(function(plot,eventHolder){var o=plot.getOptions();if(o.selection.mode!=null){eventHolder.mousemove(onMouseMove);eventHolder.mousedown(onMouseDown)}});plot.hooks.drawOverlay.push(function(plot,ctx){if(selection.show&&selectionIsSane()){var plotOffset=plot.getPlotOffset();var o=plot.getOptions();ctx.save();ctx.translate(plotOffset.left,plotOffset.top);var c=$.color.parse(o.selection.color);ctx.strokeStyle=c.scale("a",.8).toString();ctx.lineWidth=1;ctx.lineJoin=o.selection.shape;ctx.fillStyle=c.scale("a",.4).toString();var x=Math.min(selection.first.x,selection.second.x)+.5,y=Math.min(selection.first.y,selection.second.y)+.5,w=Math.abs(selection.second.x-selection.first.x)-1,h=Math.abs(selection.second.y-selection.first.y)-1;ctx.fillRect(x,y,w,h);ctx.strokeRect(x,y,w,h);ctx.restore()}});plot.hooks.shutdown.push(function(plot,eventHolder){eventHolder.unbind("mousemove",onMouseMove);eventHolder.unbind("mousedown",onMouseDown);if(mouseUpHandler)$(document).unbind("mouseup",mouseUpHandler)})}$.plot.plugins.push({init:init,options:{selection:{mode:null,color:"#e8cfac",shape:"round",minSize:5}},name:"selection",version:"1.1"})})(jQuery); \ No newline at end of file
diff --git a/library/cpp/lwtrace/mon/static/js/jquery.min.js b/library/cpp/lwtrace/mon/static/js/jquery.min.js
new file mode 100644
index 0000000000..ee48790811
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/jquery.min.js
@@ -0,0 +1,5 @@
+(function(window,undefined){var rootjQuery,readyList,document=window.document,location=window.location,navigator=window.navigator,_jQuery=window.jQuery,_$=window.$,core_push=Array.prototype.push,core_slice=Array.prototype.slice,core_indexOf=Array.prototype.indexOf,core_toString=Object.prototype.toString,core_hasOwn=Object.prototype.hasOwnProperty,core_trim=String.prototype.trim,jQuery=function(selector,context){return new jQuery.fn.init(selector,context,rootjQuery)},core_pnum=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,core_rnotwhite=/\S/,core_rspace=/\s+/,rtrim=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,rquickExpr=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,rsingleTag=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,rvalidchars=/^[\],:{}\s]*$/,rvalidbraces=/(?:^|:|,)(?:\s*\[)+/g,rvalidescape=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,rvalidtokens=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,rmsPrefix=/^-ms-/,rdashAlpha=/-([\da-z])/gi,fcamelCase=function(all,letter){return(letter+"").toUpperCase()},DOMContentLoaded=function(){if(document.addEventListener){document.removeEventListener("DOMContentLoaded",DOMContentLoaded,false);jQuery.ready()}else if(document.readyState==="complete"){document.detachEvent("onreadystatechange",DOMContentLoaded);jQuery.ready()}},class2type={};jQuery.fn=jQuery.prototype={constructor:jQuery,init:function(selector,context,rootjQuery){var match,elem,ret,doc;if(!selector){return this}if(selector.nodeType){this.context=this[0]=selector;this.length=1;return this}if(typeof selector==="string"){if(selector.charAt(0)==="<"&&selector.charAt(selector.length-1)===">"&&selector.length>=3){match=[null,selector,null]}else{match=rquickExpr.exec(selector)}if(match&&(match[1]||!context)){if(match[1]){context=context instanceof jQuery?context[0]:context;doc=context&&context.nodeType?context.ownerDocument||context:document;selector=jQuery.parseHTML(match[1],doc,true);if(rsingleTag.test(match[1])&&jQuery.isPlainObject(context)){this.attr.call(selector,context,true)}return jQuery.merge(this,selector)}else{elem=document.getElementById(match[2]);if(elem&&elem.parentNode){if(elem.id!==match[2]){return rootjQuery.find(selector)}this.length=1;this[0]=elem}this.context=document;this.selector=selector;return this}}else if(!context||context.jquery){return(context||rootjQuery).find(selector)}else{return this.constructor(context).find(selector)}}else if(jQuery.isFunction(selector)){return rootjQuery.ready(selector)}if(selector.selector!==undefined){this.selector=selector.selector;this.context=selector.context}return jQuery.makeArray(selector,this)},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return core_slice.call(this)},get:function(num){return num==null?this.toArray():num<0?this[this.length+num]:this[num]},pushStack:function(elems,name,selector){var ret=jQuery.merge(this.constructor(),elems);ret.prevObject=this;ret.context=this.context;if(name==="find"){ret.selector=this.selector+(this.selector?" ":"")+selector}else if(name){ret.selector=this.selector+"."+name+"("+selector+")"}return ret},each:function(callback,args){return jQuery.each(this,callback,args)},ready:function(fn){jQuery.ready.promise().done(fn);return this},eq:function(i){i=+i;return i===-1?this.slice(i):this.slice(i,i+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(core_slice.apply(this,arguments),"slice",core_slice.call(arguments).join(","))},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem)}))},end:function(){return this.prevObject||this.constructor(null)},push:core_push,sort:[].sort,splice:[].splice};jQuery.fn.init.prototype=jQuery.fn;jQuery.extend=jQuery.fn.extend=function(){var options,name,src,copy,copyIsArray,clone,target=arguments[0]||{},i=1,length=arguments.length,deep=false;if(typeof target==="boolean"){deep=target;target=arguments[1]||{};i=2}if(typeof target!=="object"&&!jQuery.isFunction(target)){target={}}if(length===i){target=this;--i}for(;i<length;i++){if((options=arguments[i])!=null){for(name in options){src=target[name];copy=options[name];if(target===copy){continue}if(deep&&copy&&(jQuery.isPlainObject(copy)||(copyIsArray=jQuery.isArray(copy)))){if(copyIsArray){copyIsArray=false;clone=src&&jQuery.isArray(src)?src:[]}else{clone=src&&jQuery.isPlainObject(src)?src:{}}target[name]=jQuery.extend(deep,clone,copy)}else if(copy!==undefined){target[name]=copy}}}}return target};jQuery.extend({noConflict:function(deep){if(window.$===jQuery){window.$=_$}if(deep&&window.jQuery===jQuery){window.jQuery=_jQuery}return jQuery},isReady:false,readyWait:1,holdReady:function(hold){if(hold){jQuery.readyWait++}else{jQuery.ready(true)}},ready:function(wait){if(wait===true?--jQuery.readyWait:jQuery.isReady){return}if(!document.body){return setTimeout(jQuery.ready,1)}jQuery.isReady=true;if(wait!==true&&--jQuery.readyWait>0){return}readyList.resolveWith(document,[jQuery]);if(jQuery.fn.trigger){jQuery(document).trigger("ready").off("ready")}},isFunction:function(obj){return jQuery.type(obj)==="function"},isArray:Array.isArray||function(obj){return jQuery.type(obj)==="array"},isWindow:function(obj){return obj!=null&&obj==obj.window},isNumeric:function(obj){return!isNaN(parseFloat(obj))&&isFinite(obj)},type:function(obj){return obj==null?String(obj):class2type[core_toString.call(obj)]||"object"},isPlainObject:function(obj){if(!obj||jQuery.type(obj)!=="object"||obj.nodeType||jQuery.isWindow(obj)){return false}try{if(obj.constructor&&!core_hasOwn.call(obj,"constructor")&&!core_hasOwn.call(obj.constructor.prototype,"isPrototypeOf")){return false}}catch(e){return false}var key;for(key in obj){}return key===undefined||core_hasOwn.call(obj,key)},isEmptyObject:function(obj){var name;for(name in obj){return false}return true},error:function(msg){throw new Error(msg)},parseHTML:function(data,context,scripts){var parsed;if(!data||typeof data!=="string"){return null}if(typeof context==="boolean"){scripts=context;context=0}context=context||document;if(parsed=rsingleTag.exec(data)){return[context.createElement(parsed[1])]}parsed=jQuery.buildFragment([data],context,scripts?null:[]);return jQuery.merge([],(parsed.cacheable?jQuery.clone(parsed.fragment):parsed.fragment).childNodes)},parseJSON:function(data){if(!data||typeof data!=="string"){return null}data=jQuery.trim(data);if(window.JSON&&window.JSON.parse){return window.JSON.parse(data)}if(rvalidchars.test(data.replace(rvalidescape,"@").replace(rvalidtokens,"]").replace(rvalidbraces,""))){return new Function("return "+data)()}jQuery.error("Invalid JSON: "+data)},parseXML:function(data){var xml,tmp;if(!data||typeof data!=="string"){return null}try{if(window.DOMParser){tmp=new DOMParser;xml=tmp.parseFromString(data,"text/xml")}else{xml=new ActiveXObject("Microsoft.XMLDOM");xml.async="false";xml.loadXML(data)}}catch(e){xml=undefined}if(!xml||!xml.documentElement||xml.getElementsByTagName("parsererror").length){jQuery.error("Invalid XML: "+data)}return xml},noop:function(){},globalEval:function(data){if(data&&core_rnotwhite.test(data)){(window.execScript||function(data){window["eval"].call(window,data)})(data)}},camelCase:function(string){return string.replace(rmsPrefix,"ms-").replace(rdashAlpha,fcamelCase)},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toLowerCase()===name.toLowerCase()},each:function(obj,callback,args){var name,i=0,length=obj.length,isObj=length===undefined||jQuery.isFunction(obj);if(args){if(isObj){for(name in obj){if(callback.apply(obj[name],args)===false){break}}}else{for(;i<length;){if(callback.apply(obj[i++],args)===false){break}}}}else{if(isObj){for(name in obj){if(callback.call(obj[name],name,obj[name])===false){break}}}else{for(;i<length;){if(callback.call(obj[i],i,obj[i++])===false){break}}}}return obj},trim:core_trim&&!core_trim.call(" ")?function(text){return text==null?"":core_trim.call(text)}:function(text){return text==null?"":(text+"").replace(rtrim,"")},makeArray:function(arr,results){var type,ret=results||[];if(arr!=null){type=jQuery.type(arr);if(arr.length==null||type==="string"||type==="function"||type==="regexp"||jQuery.isWindow(arr)){core_push.call(ret,arr)}else{jQuery.merge(ret,arr)}}return ret},inArray:function(elem,arr,i){var len;if(arr){if(core_indexOf){return core_indexOf.call(arr,elem,i)}len=arr.length;i=i?i<0?Math.max(0,len+i):i:0;for(;i<len;i++){if(i in arr&&arr[i]===elem){return i}}}return-1},merge:function(first,second){var l=second.length,i=first.length,j=0;if(typeof l==="number"){for(;j<l;j++){first[i++]=second[j]}}else{while(second[j]!==undefined){first[i++]=second[j++]}}first.length=i;return first},grep:function(elems,callback,inv){var retVal,ret=[],i=0,length=elems.length;inv=!!inv;for(;i<length;i++){retVal=!!callback(elems[i],i);if(inv!==retVal){ret.push(elems[i])}}return ret},map:function(elems,callback,arg){var value,key,ret=[],i=0,length=elems.length,isArray=elems instanceof jQuery||length!==undefined&&typeof length==="number"&&(length>0&&elems[0]&&elems[length-1]||length===0||jQuery.isArray(elems));if(isArray){for(;i<length;i++){value=callback(elems[i],i,arg);if(value!=null){ret[ret.length]=value}}}else{for(key in elems){value=callback(elems[key],key,arg);if(value!=null){ret[ret.length]=value}}}return ret.concat.apply([],ret)},guid:1,proxy:function(fn,context){var tmp,args,proxy;if(typeof context==="string"){tmp=fn[context];context=fn;fn=tmp}if(!jQuery.isFunction(fn)){return undefined}args=core_slice.call(arguments,2);proxy=function(){return fn.apply(context,args.concat(core_slice.call(arguments)))};proxy.guid=fn.guid=fn.guid||jQuery.guid++;return proxy},access:function(elems,fn,key,value,chainable,emptyGet,pass){var exec,bulk=key==null,i=0,length=elems.length;if(key&&typeof key==="object"){for(i in key){jQuery.access(elems,fn,i,key[i],1,emptyGet,value)}chainable=1}else if(value!==undefined){exec=pass===undefined&&jQuery.isFunction(value);if(bulk){if(exec){exec=fn;fn=function(elem,key,value){return exec.call(jQuery(elem),value)}}else{fn.call(elems,value);fn=null}}if(fn){for(;i<length;i++){fn(elems[i],key,exec?value.call(elems[i],i,fn(elems[i],key)):value,pass)}}chainable=1}return chainable?elems:bulk?fn.call(elems):length?fn(elems[0],key):emptyGet},now:function(){return(new Date).getTime()}});jQuery.ready.promise=function(obj){if(!readyList){readyList=jQuery.Deferred();if(document.readyState==="complete"){setTimeout(jQuery.ready,1)}else if(document.addEventListener){document.addEventListener("DOMContentLoaded",DOMContentLoaded,false);window.addEventListener("load",jQuery.ready,false)}else{document.attachEvent("onreadystatechange",DOMContentLoaded);window.attachEvent("onload",jQuery.ready);var top=false;try{top=window.frameElement==null&&document.documentElement}catch(e){}if(top&&top.doScroll){(function doScrollCheck(){if(!jQuery.isReady){try{top.doScroll("left")}catch(e){return setTimeout(doScrollCheck,50)}jQuery.ready()}})()}}}return readyList.promise(obj)};jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(i,name){class2type["[object "+name+"]"]=name.toLowerCase()});rootjQuery=jQuery(document);var optionsCache={};function createOptions(options){var object=optionsCache[options]={};jQuery.each(options.split(core_rspace),function(_,flag){object[flag]=true});return object}jQuery.Callbacks=function(options){options=typeof options==="string"?optionsCache[options]||createOptions(options):jQuery.extend({},options);var memory,fired,firing,firingStart,firingLength,firingIndex,list=[],stack=!options.once&&[],fire=function(data){memory=options.memory&&data;fired=true;firingIndex=firingStart||0;firingStart=0;firingLength=list.length;firing=true;for(;list&&firingIndex<firingLength;firingIndex++){if(list[firingIndex].apply(data[0],data[1])===false&&options.stopOnFalse){memory=false;break}}firing=false;if(list){if(stack){if(stack.length){fire(stack.shift())}}else if(memory){list=[]}else{self.disable()}}},self={add:function(){if(list){var start=list.length;(function add(args){jQuery.each(args,function(_,arg){var type=jQuery.type(arg);if(type==="function"){if(!options.unique||!self.has(arg)){list.push(arg)}}else if(arg&&arg.length&&type!=="string"){add(arg)}})})(arguments);if(firing){firingLength=list.length}else if(memory){firingStart=start;fire(memory)}}return this},remove:function(){if(list){jQuery.each(arguments,function(_,arg){var index;while((index=jQuery.inArray(arg,list,index))>-1){list.splice(index,1);if(firing){if(index<=firingLength){firingLength--}if(index<=firingIndex){firingIndex--}}}})}return this},has:function(fn){return jQuery.inArray(fn,list)>-1},empty:function(){list=[];return this},disable:function(){list=stack=memory=undefined;return this},disabled:function(){return!list},lock:function(){stack=undefined;if(!memory){self.disable()}return this},locked:function(){return!stack},fireWith:function(context,args){args=args||[];args=[context,args.slice?args.slice():args];if(list&&(!fired||stack)){if(firing){stack.push(args)}else{fire(args)}}return this},fire:function(){self.fireWith(this,arguments);return this},fired:function(){return!!fired}};return self};jQuery.extend({Deferred:function(func){var tuples=[["resolve","done",jQuery.Callbacks("once memory"),"resolved"],["reject","fail",jQuery.Callbacks("once memory"),"rejected"],["notify","progress",jQuery.Callbacks("memory")]],state="pending",promise={state:function(){return state},always:function(){deferred.done(arguments).fail(arguments);return this},then:function(){var fns=arguments;return jQuery.Deferred(function(newDefer){jQuery.each(tuples,function(i,tuple){var action=tuple[0],fn=fns[i];deferred[tuple[1]](jQuery.isFunction(fn)?function(){var returned=fn.apply(this,arguments);if(returned&&jQuery.isFunction(returned.promise)){returned.promise().done(newDefer.resolve).fail(newDefer.reject).progress(newDefer.notify)}else{newDefer[action+"With"](this===deferred?newDefer:this,[returned])}}:newDefer[action])});fns=null}).promise()},promise:function(obj){return obj!=null?jQuery.extend(obj,promise):promise}},deferred={};promise.pipe=promise.then;jQuery.each(tuples,function(i,tuple){var list=tuple[2],stateString=tuple[3];promise[tuple[1]]=list.add;if(stateString){list.add(function(){state=stateString},tuples[i^1][2].disable,tuples[2][2].lock)}deferred[tuple[0]]=list.fire;deferred[tuple[0]+"With"]=list.fireWith});promise.promise(deferred);if(func){func.call(deferred,deferred)}return deferred},when:function(subordinate){var i=0,resolveValues=core_slice.call(arguments),length=resolveValues.length,remaining=length!==1||subordinate&&jQuery.isFunction(subordinate.promise)?length:0,deferred=remaining===1?subordinate:jQuery.Deferred(),updateFunc=function(i,contexts,values){return function(value){contexts[i]=this;values[i]=arguments.length>1?core_slice.call(arguments):value;if(values===progressValues){deferred.notifyWith(contexts,values)}else if(!--remaining){deferred.resolveWith(contexts,values)}}},progressValues,progressContexts,resolveContexts;if(length>1){progressValues=new Array(length);progressContexts=new Array(length);resolveContexts=new Array(length);for(;i<length;i++){if(resolveValues[i]&&jQuery.isFunction(resolveValues[i].promise)){resolveValues[i].promise().done(updateFunc(i,resolveContexts,resolveValues)).fail(deferred.reject).progress(updateFunc(i,progressContexts,progressValues))}else{--remaining}}}if(!remaining){deferred.resolveWith(resolveContexts,resolveValues)}return deferred.promise()}});jQuery.support=function(){var support,all,a,select,opt,input,fragment,eventName,i,isSupported,clickFn,div=document.createElement("div");div.setAttribute("className","t");div.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";all=div.getElementsByTagName("*");a=div.getElementsByTagName("a")[0];if(!all||!a||!all.length){return{}}select=document.createElement("select");opt=select.appendChild(document.createElement("option"));input=div.getElementsByTagName("input")[0];a.style.cssText="top:1px;float:left;opacity:.5";support={leadingWhitespace:div.firstChild.nodeType===3,tbody:!div.getElementsByTagName("tbody").length,htmlSerialize:!!div.getElementsByTagName("link").length,style:/top/.test(a.getAttribute("style")),hrefNormalized:a.getAttribute("href")==="/a",opacity:/^0.5/.test(a.style.opacity),cssFloat:!!a.style.cssFloat,checkOn:input.value==="on",optSelected:opt.selected,getSetAttribute:div.className!=="t",enctype:!!document.createElement("form").enctype,html5Clone:document.createElement("nav").cloneNode(true).outerHTML!=="<:nav></:nav>",boxModel:document.compatMode==="CSS1Compat",submitBubbles:true,changeBubbles:true,focusinBubbles:false,deleteExpando:true,noCloneEvent:true,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableMarginRight:true,boxSizingReliable:true,pixelPosition:false};input.checked=true;support.noCloneChecked=input.cloneNode(true).checked;select.disabled=true;support.optDisabled=!opt.disabled;try{delete div.test}catch(e){support.deleteExpando=false}if(!div.addEventListener&&div.attachEvent&&div.fireEvent){div.attachEvent("onclick",clickFn=function(){support.noCloneEvent=false});div.cloneNode(true).fireEvent("onclick");div.detachEvent("onclick",clickFn)}input=document.createElement("input");input.value="t";input.setAttribute("type","radio");support.radioValue=input.value==="t";input.setAttribute("checked","checked");input.setAttribute("name","t");div.appendChild(input);fragment=document.createDocumentFragment();fragment.appendChild(div.lastChild);support.checkClone=fragment.cloneNode(true).cloneNode(true).lastChild.checked;support.appendChecked=input.checked;fragment.removeChild(input);fragment.appendChild(div);if(div.attachEvent){for(i in{submit:true,change:true,focusin:true}){eventName="on"+i;isSupported=eventName in div;if(!isSupported){div.setAttribute(eventName,"return;");isSupported=typeof div[eventName]==="function"}support[i+"Bubbles"]=isSupported}}jQuery(function(){var container,div,tds,marginDiv,divReset="padding:0;margin:0;border:0;display:block;overflow:hidden;",body=document.getElementsByTagName("body")[0];if(!body){return}container=document.createElement("div");container.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px";body.insertBefore(container,body.firstChild);div=document.createElement("div");container.appendChild(div);div.innerHTML="<table><tr><td></td><td>t</td></tr></table>";tds=div.getElementsByTagName("td");tds[0].style.cssText="padding:0;margin:0;border:0;display:none";isSupported=tds[0].offsetHeight===0;tds[0].style.display="";tds[1].style.display="none";support.reliableHiddenOffsets=isSupported&&tds[0].offsetHeight===0;div.innerHTML="";div.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";support.boxSizing=div.offsetWidth===4;support.doesNotIncludeMarginInBodyOffset=body.offsetTop!==1;if(window.getComputedStyle){support.pixelPosition=(window.getComputedStyle(div,null)||{}).top!=="1%";support.boxSizingReliable=(window.getComputedStyle(div,null)||{width:"4px"}).width==="4px";marginDiv=document.createElement("div");marginDiv.style.cssText=div.style.cssText=divReset;marginDiv.style.marginRight=marginDiv.style.width="0";div.style.width="1px";div.appendChild(marginDiv);support.reliableMarginRight=!parseFloat((window.getComputedStyle(marginDiv,null)||{}).marginRight)}if(typeof div.style.zoom!=="undefined"){div.innerHTML="";div.style.cssText=divReset+"width:1px;padding:1px;display:inline;zoom:1";support.inlineBlockNeedsLayout=div.offsetWidth===3;div.style.display="block";div.style.overflow="visible";div.innerHTML="<div></div>";div.firstChild.style.width="5px";support.shrinkWrapBlocks=div.offsetWidth!==3;container.style.zoom=1}body.removeChild(container);container=div=tds=marginDiv=null});fragment.removeChild(div);all=a=select=opt=input=fragment=div=null;return support}();var rbrace=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,rmultiDash=/([A-Z])/g;jQuery.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(jQuery.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},hasData:function(elem){elem=elem.nodeType?jQuery.cache[elem[jQuery.expando]]:elem[jQuery.expando];return!!elem&&!isEmptyDataObject(elem)},data:function(elem,name,data,pvt){if(!jQuery.acceptData(elem)){return}var thisCache,ret,internalKey=jQuery.expando,getByName=typeof name==="string",isNode=elem.nodeType,cache=isNode?jQuery.cache:elem,id=isNode?elem[internalKey]:elem[internalKey]&&internalKey;if((!id||!cache[id]||!pvt&&!cache[id].data)&&getByName&&data===undefined){return}if(!id){if(isNode){elem[internalKey]=id=jQuery.deletedIds.pop()||jQuery.guid++}else{id=internalKey}}if(!cache[id]){cache[id]={};if(!isNode){cache[id].toJSON=jQuery.noop}}if(typeof name==="object"||typeof name==="function"){if(pvt){cache[id]=jQuery.extend(cache[id],name)}else{cache[id].data=jQuery.extend(cache[id].data,name)}}thisCache=cache[id];if(!pvt){if(!thisCache.data){thisCache.data={}}thisCache=thisCache.data}if(data!==undefined){thisCache[jQuery.camelCase(name)]=data}if(getByName){ret=thisCache[name];if(ret==null){ret=thisCache[jQuery.camelCase(name)]}}else{ret=thisCache}return ret},removeData:function(elem,name,pvt){if(!jQuery.acceptData(elem)){return}var thisCache,i,l,isNode=elem.nodeType,cache=isNode?jQuery.cache:elem,id=isNode?elem[jQuery.expando]:jQuery.expando;if(!cache[id]){return}if(name){thisCache=pvt?cache[id]:cache[id].data;if(thisCache){if(!jQuery.isArray(name)){if(name in thisCache){name=[name]}else{name=jQuery.camelCase(name);if(name in thisCache){name=[name]}else{name=name.split(" ")}}}for(i=0,l=name.length;i<l;i++){delete thisCache[name[i]]}if(!(pvt?isEmptyDataObject:jQuery.isEmptyObject)(thisCache)){return}}}if(!pvt){delete cache[id].data;if(!isEmptyDataObject(cache[id])){return}}if(isNode){jQuery.cleanData([elem],true)}else if(jQuery.support.deleteExpando||cache!=cache.window){delete cache[id]}else{cache[id]=null}},_data:function(elem,name,data){return jQuery.data(elem,name,data,true)},acceptData:function(elem){var noData=elem.nodeName&&jQuery.noData[elem.nodeName.toLowerCase()];return!noData||noData!==true&&elem.getAttribute("classid")===noData}});jQuery.fn.extend({data:function(key,value){var parts,part,attr,name,l,elem=this[0],i=0,data=null;if(key===undefined){if(this.length){data=jQuery.data(elem);if(elem.nodeType===1&&!jQuery._data(elem,"parsedAttrs")){attr=elem.attributes;for(l=attr.length;i<l;i++){name=attr[i].name;if(!name.indexOf("data-")){name=jQuery.camelCase(name.substring(5));dataAttr(elem,name,data[name])}}jQuery._data(elem,"parsedAttrs",true)}}return data}if(typeof key==="object"){return this.each(function(){jQuery.data(this,key)})}parts=key.split(".",2);parts[1]=parts[1]?"."+parts[1]:"";part=parts[1]+"!";return jQuery.access(this,function(value){if(value===undefined){data=this.triggerHandler("getData"+part,[parts[0]]);if(data===undefined&&elem){data=jQuery.data(elem,key);data=dataAttr(elem,key,data)}return data===undefined&&parts[1]?this.data(parts[0]):data}parts[1]=value;this.each(function(){var self=jQuery(this);self.triggerHandler("setData"+part,parts);jQuery.data(this,key,value);self.triggerHandler("changeData"+part,parts)})},null,value,arguments.length>1,null,false)},removeData:function(key){return this.each(function(){jQuery.removeData(this,key)})}});function dataAttr(elem,key,data){if(data===undefined&&elem.nodeType===1){var name="data-"+key.replace(rmultiDash,"-$1").toLowerCase();data=elem.getAttribute(name);if(typeof data==="string"){try{data=data==="true"?true:data==="false"?false:data==="null"?null:+data+""===data?+data:rbrace.test(data)?jQuery.parseJSON(data):data}catch(e){}jQuery.data(elem,key,data)}else{data=undefined}}return data}function isEmptyDataObject(obj){var name;for(name in obj){if(name==="data"&&jQuery.isEmptyObject(obj[name])){continue}if(name!=="toJSON"){return false}}return true}jQuery.extend({queue:function(elem,type,data){var queue;if(elem){type=(type||"fx")+"queue";queue=jQuery._data(elem,type);if(data){if(!queue||jQuery.isArray(data)){queue=jQuery._data(elem,type,jQuery.makeArray(data))}else{queue.push(data)}}return queue||[]}},dequeue:function(elem,type){type=type||"fx";var queue=jQuery.queue(elem,type),startLength=queue.length,fn=queue.shift(),hooks=jQuery._queueHooks(elem,type),next=function(){jQuery.dequeue(elem,type)};if(fn==="inprogress"){fn=queue.shift();startLength--}if(fn){if(type==="fx"){queue.unshift("inprogress")}delete hooks.stop;fn.call(elem,next,hooks)}if(!startLength&&hooks){hooks.empty.fire()}},_queueHooks:function(elem,type){var key=type+"queueHooks";return jQuery._data(elem,key)||jQuery._data(elem,key,{empty:jQuery.Callbacks("once memory").add(function(){jQuery.removeData(elem,type+"queue",true);jQuery.removeData(elem,key,true)})})}});jQuery.fn.extend({queue:function(type,data){var setter=2;if(typeof type!=="string"){data=type;type="fx";setter--}if(arguments.length<setter){return jQuery.queue(this[0],type)}return data===undefined?this:this.each(function(){var queue=jQuery.queue(this,type,data);jQuery._queueHooks(this,type);if(type==="fx"&&queue[0]!=="inprogress"){jQuery.dequeue(this,type)}})},dequeue:function(type){return this.each(function(){jQuery.dequeue(this,type)})},delay:function(time,type){time=jQuery.fx?jQuery.fx.speeds[time]||time:time;type=type||"fx";return this.queue(type,function(next,hooks){var timeout=setTimeout(next,time);hooks.stop=function(){clearTimeout(timeout)}})},clearQueue:function(type){return this.queue(type||"fx",[])},promise:function(type,obj){var tmp,count=1,defer=jQuery.Deferred(),elements=this,i=this.length,resolve=function(){if(!--count){defer.resolveWith(elements,[elements])}};if(typeof type!=="string"){obj=type;type=undefined}type=type||"fx";while(i--){tmp=jQuery._data(elements[i],type+"queueHooks");if(tmp&&tmp.empty){count++;tmp.empty.add(resolve)}}resolve();return defer.promise(obj)}});var nodeHook,boolHook,fixSpecified,rclass=/[\t\r\n]/g,rreturn=/\r/g,rtype=/^(?:button|input)$/i,rfocusable=/^(?:button|input|object|select|textarea)$/i,rclickable=/^a(?:rea|)$/i,rboolean=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,getSetAttribute=jQuery.support.getSetAttribute;jQuery.fn.extend({attr:function(name,value){return jQuery.access(this,jQuery.attr,name,value,arguments.length>1)},removeAttr:function(name){return this.each(function(){jQuery.removeAttr(this,name)})},prop:function(name,value){return jQuery.access(this,jQuery.prop,name,value,arguments.length>1)},removeProp:function(name){name=jQuery.propFix[name]||name;return this.each(function(){try{this[name]=undefined;delete this[name]}catch(e){}})},addClass:function(value){var classNames,i,l,elem,setClass,c,cl;if(jQuery.isFunction(value)){return this.each(function(j){jQuery(this).addClass(value.call(this,j,this.className))})}if(value&&typeof value==="string"){classNames=value.split(core_rspace);for(i=0,l=this.length;i<l;i++){elem=this[i];if(elem.nodeType===1){if(!elem.className&&classNames.length===1){elem.className=value}else{setClass=" "+elem.className+" ";for(c=0,cl=classNames.length;c<cl;c++){if(setClass.indexOf(" "+classNames[c]+" ")<0){setClass+=classNames[c]+" "}}elem.className=jQuery.trim(setClass)}}}}return this},removeClass:function(value){var removes,className,elem,c,cl,i,l;if(jQuery.isFunction(value)){return this.each(function(j){jQuery(this).removeClass(value.call(this,j,this.className))})}if(value&&typeof value==="string"||value===undefined){removes=(value||"").split(core_rspace);for(i=0,l=this.length;i<l;i++){elem=this[i];if(elem.nodeType===1&&elem.className){className=(" "+elem.className+" ").replace(rclass," ");for(c=0,cl=removes.length;c<cl;c++){while(className.indexOf(" "+removes[c]+" ")>=0){className=className.replace(" "+removes[c]+" "," ")}}elem.className=value?jQuery.trim(className):""}}}return this},toggleClass:function(value,stateVal){var type=typeof value,isBool=typeof stateVal==="boolean";if(jQuery.isFunction(value)){return this.each(function(i){jQuery(this).toggleClass(value.call(this,i,this.className,stateVal),stateVal)})}return this.each(function(){if(type==="string"){var className,i=0,self=jQuery(this),state=stateVal,classNames=value.split(core_rspace);while(className=classNames[i++]){state=isBool?state:!self.hasClass(className);self[state?"addClass":"removeClass"](className)}}else if(type==="undefined"||type==="boolean"){if(this.className){jQuery._data(this,"__className__",this.className)}this.className=this.className||value===false?"":jQuery._data(this,"__className__")||""}})},hasClass:function(selector){var className=" "+selector+" ",i=0,l=this.length;for(;i<l;i++){if(this[i].nodeType===1&&(" "+this[i].className+" ").replace(rclass," ").indexOf(className)>=0){return true}}return false},val:function(value){var hooks,ret,isFunction,elem=this[0];if(!arguments.length){if(elem){hooks=jQuery.valHooks[elem.type]||jQuery.valHooks[elem.nodeName.toLowerCase()];if(hooks&&"get"in hooks&&(ret=hooks.get(elem,"value"))!==undefined){return ret}ret=elem.value;return typeof ret==="string"?ret.replace(rreturn,""):ret==null?"":ret}return}isFunction=jQuery.isFunction(value);return this.each(function(i){var val,self=jQuery(this);if(this.nodeType!==1){return}if(isFunction){val=value.call(this,i,self.val())}else{val=value}if(val==null){val=""}else if(typeof val==="number"){val+=""}else if(jQuery.isArray(val)){val=jQuery.map(val,function(value){return value==null?"":value+""})}hooks=jQuery.valHooks[this.type]||jQuery.valHooks[this.nodeName.toLowerCase()];if(!hooks||!("set"in hooks)||hooks.set(this,val,"value")===undefined){this.value=val}})}});jQuery.extend({valHooks:{option:{get:function(elem){var val=elem.attributes.value;return!val||val.specified?elem.value:elem.text}},select:{get:function(elem){var value,option,options=elem.options,index=elem.selectedIndex,one=elem.type==="select-one"||index<0,values=one?null:[],max=one?index+1:options.length,i=index<0?max:one?index:0;for(;i<max;i++){option=options[i];if((option.selected||i===index)&&(jQuery.support.optDisabled?!option.disabled:option.getAttribute("disabled")===null)&&(!option.parentNode.disabled||!jQuery.nodeName(option.parentNode,"optgroup"))){value=jQuery(option).val();if(one){return value}values.push(value)}}return values},set:function(elem,value){var values=jQuery.makeArray(value);jQuery(elem).find("option").each(function(){this.selected=jQuery.inArray(jQuery(this).val(),values)>=0});if(!values.length){elem.selectedIndex=-1}return values}}},attrFn:{},attr:function(elem,name,value,pass){var ret,hooks,notxml,nType=elem.nodeType;if(!elem||nType===3||nType===8||nType===2){return}if(pass&&jQuery.isFunction(jQuery.fn[name])){return jQuery(elem)[name](value)}if(typeof elem.getAttribute==="undefined"){return jQuery.prop(elem,name,value)}notxml=nType!==1||!jQuery.isXMLDoc(elem);if(notxml){name=name.toLowerCase();hooks=jQuery.attrHooks[name]||(rboolean.test(name)?boolHook:nodeHook)}if(value!==undefined){if(value===null){jQuery.removeAttr(elem,name);return}else if(hooks&&"set"in hooks&&notxml&&(ret=hooks.set(elem,value,name))!==undefined){return ret}else{elem.setAttribute(name,value+"");return value}}else if(hooks&&"get"in hooks&&notxml&&(ret=hooks.get(elem,name))!==null){return ret}else{ret=elem.getAttribute(name);return ret===null?undefined:ret}},removeAttr:function(elem,value){var propName,attrNames,name,isBool,i=0;if(value&&elem.nodeType===1){attrNames=value.split(core_rspace);for(;i<attrNames.length;i++){name=attrNames[i];if(name){propName=jQuery.propFix[name]||name;isBool=rboolean.test(name);if(!isBool){jQuery.attr(elem,name,"")}elem.removeAttribute(getSetAttribute?name:propName);if(isBool&&propName in elem){elem[propName]=false}}}}},attrHooks:{type:{set:function(elem,value){if(rtype.test(elem.nodeName)&&elem.parentNode){jQuery.error("type property can't be changed")
+}else if(!jQuery.support.radioValue&&value==="radio"&&jQuery.nodeName(elem,"input")){var val=elem.value;elem.setAttribute("type",value);if(val){elem.value=val}return value}}},value:{get:function(elem,name){if(nodeHook&&jQuery.nodeName(elem,"button")){return nodeHook.get(elem,name)}return name in elem?elem.value:null},set:function(elem,value,name){if(nodeHook&&jQuery.nodeName(elem,"button")){return nodeHook.set(elem,value,name)}elem.value=value}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(elem,name,value){var ret,hooks,notxml,nType=elem.nodeType;if(!elem||nType===3||nType===8||nType===2){return}notxml=nType!==1||!jQuery.isXMLDoc(elem);if(notxml){name=jQuery.propFix[name]||name;hooks=jQuery.propHooks[name]}if(value!==undefined){if(hooks&&"set"in hooks&&(ret=hooks.set(elem,value,name))!==undefined){return ret}else{return elem[name]=value}}else{if(hooks&&"get"in hooks&&(ret=hooks.get(elem,name))!==null){return ret}else{return elem[name]}}},propHooks:{tabIndex:{get:function(elem){var attributeNode=elem.getAttributeNode("tabindex");return attributeNode&&attributeNode.specified?parseInt(attributeNode.value,10):rfocusable.test(elem.nodeName)||rclickable.test(elem.nodeName)&&elem.href?0:undefined}}}});boolHook={get:function(elem,name){var attrNode,property=jQuery.prop(elem,name);return property===true||typeof property!=="boolean"&&(attrNode=elem.getAttributeNode(name))&&attrNode.nodeValue!==false?name.toLowerCase():undefined},set:function(elem,value,name){var propName;if(value===false){jQuery.removeAttr(elem,name)}else{propName=jQuery.propFix[name]||name;if(propName in elem){elem[propName]=true}elem.setAttribute(name,name.toLowerCase())}return name}};if(!getSetAttribute){fixSpecified={name:true,id:true,coords:true};nodeHook=jQuery.valHooks.button={get:function(elem,name){var ret;ret=elem.getAttributeNode(name);return ret&&(fixSpecified[name]?ret.value!=="":ret.specified)?ret.value:undefined},set:function(elem,value,name){var ret=elem.getAttributeNode(name);if(!ret){ret=document.createAttribute(name);elem.setAttributeNode(ret)}return ret.value=value+""}};jQuery.each(["width","height"],function(i,name){jQuery.attrHooks[name]=jQuery.extend(jQuery.attrHooks[name],{set:function(elem,value){if(value===""){elem.setAttribute(name,"auto");return value}}})});jQuery.attrHooks.contenteditable={get:nodeHook.get,set:function(elem,value,name){if(value===""){value="false"}nodeHook.set(elem,value,name)}}}if(!jQuery.support.hrefNormalized){jQuery.each(["href","src","width","height"],function(i,name){jQuery.attrHooks[name]=jQuery.extend(jQuery.attrHooks[name],{get:function(elem){var ret=elem.getAttribute(name,2);return ret===null?undefined:ret}})})}if(!jQuery.support.style){jQuery.attrHooks.style={get:function(elem){return elem.style.cssText.toLowerCase()||undefined},set:function(elem,value){return elem.style.cssText=value+""}}}if(!jQuery.support.optSelected){jQuery.propHooks.selected=jQuery.extend(jQuery.propHooks.selected,{get:function(elem){var parent=elem.parentNode;if(parent){parent.selectedIndex;if(parent.parentNode){parent.parentNode.selectedIndex}}return null}})}if(!jQuery.support.enctype){jQuery.propFix.enctype="encoding"}if(!jQuery.support.checkOn){jQuery.each(["radio","checkbox"],function(){jQuery.valHooks[this]={get:function(elem){return elem.getAttribute("value")===null?"on":elem.value}}})}jQuery.each(["radio","checkbox"],function(){jQuery.valHooks[this]=jQuery.extend(jQuery.valHooks[this],{set:function(elem,value){if(jQuery.isArray(value)){return elem.checked=jQuery.inArray(jQuery(elem).val(),value)>=0}}})});var rformElems=/^(?:textarea|input|select)$/i,rtypenamespace=/^([^\.]*|)(?:\.(.+)|)$/,rhoverHack=/(?:^|\s)hover(\.\S+|)\b/,rkeyEvent=/^key/,rmouseEvent=/^(?:mouse|contextmenu)|click/,rfocusMorph=/^(?:focusinfocus|focusoutblur)$/,hoverHack=function(events){return jQuery.event.special.hover?events:events.replace(rhoverHack,"mouseenter$1 mouseleave$1")};jQuery.event={add:function(elem,types,handler,data,selector){var elemData,eventHandle,events,t,tns,type,namespaces,handleObj,handleObjIn,handlers,special;if(elem.nodeType===3||elem.nodeType===8||!types||!handler||!(elemData=jQuery._data(elem))){return}if(handler.handler){handleObjIn=handler;handler=handleObjIn.handler;selector=handleObjIn.selector}if(!handler.guid){handler.guid=jQuery.guid++}events=elemData.events;if(!events){elemData.events=events={}}eventHandle=elemData.handle;if(!eventHandle){elemData.handle=eventHandle=function(e){return typeof jQuery!=="undefined"&&(!e||jQuery.event.triggered!==e.type)?jQuery.event.dispatch.apply(eventHandle.elem,arguments):undefined};eventHandle.elem=elem}types=jQuery.trim(hoverHack(types)).split(" ");for(t=0;t<types.length;t++){tns=rtypenamespace.exec(types[t])||[];type=tns[1];namespaces=(tns[2]||"").split(".").sort();special=jQuery.event.special[type]||{};type=(selector?special.delegateType:special.bindType)||type;special=jQuery.event.special[type]||{};handleObj=jQuery.extend({type:type,origType:tns[1],data:data,handler:handler,guid:handler.guid,selector:selector,needsContext:selector&&jQuery.expr.match.needsContext.test(selector),namespace:namespaces.join(".")},handleObjIn);handlers=events[type];if(!handlers){handlers=events[type]=[];handlers.delegateCount=0;if(!special.setup||special.setup.call(elem,data,namespaces,eventHandle)===false){if(elem.addEventListener){elem.addEventListener(type,eventHandle,false)}else if(elem.attachEvent){elem.attachEvent("on"+type,eventHandle)}}}if(special.add){special.add.call(elem,handleObj);if(!handleObj.handler.guid){handleObj.handler.guid=handler.guid}}if(selector){handlers.splice(handlers.delegateCount++,0,handleObj)}else{handlers.push(handleObj)}jQuery.event.global[type]=true}elem=null},global:{},remove:function(elem,types,handler,selector,mappedTypes){var t,tns,type,origType,namespaces,origCount,j,events,special,eventType,handleObj,elemData=jQuery.hasData(elem)&&jQuery._data(elem);if(!elemData||!(events=elemData.events)){return}types=jQuery.trim(hoverHack(types||"")).split(" ");for(t=0;t<types.length;t++){tns=rtypenamespace.exec(types[t])||[];type=origType=tns[1];namespaces=tns[2];if(!type){for(type in events){jQuery.event.remove(elem,type+types[t],handler,selector,true)}continue}special=jQuery.event.special[type]||{};type=(selector?special.delegateType:special.bindType)||type;eventType=events[type]||[];origCount=eventType.length;namespaces=namespaces?new RegExp("(^|\\.)"+namespaces.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(j=0;j<eventType.length;j++){handleObj=eventType[j];if((mappedTypes||origType===handleObj.origType)&&(!handler||handler.guid===handleObj.guid)&&(!namespaces||namespaces.test(handleObj.namespace))&&(!selector||selector===handleObj.selector||selector==="**"&&handleObj.selector)){eventType.splice(j--,1);if(handleObj.selector){eventType.delegateCount--}if(special.remove){special.remove.call(elem,handleObj)}}}if(eventType.length===0&&origCount!==eventType.length){if(!special.teardown||special.teardown.call(elem,namespaces,elemData.handle)===false){jQuery.removeEvent(elem,type,elemData.handle)}delete events[type]}}if(jQuery.isEmptyObject(events)){delete elemData.handle;jQuery.removeData(elem,"events",true)}},customEvent:{getData:true,setData:true,changeData:true},trigger:function(event,data,elem,onlyHandlers){if(elem&&(elem.nodeType===3||elem.nodeType===8)){return}var cache,exclusive,i,cur,old,ontype,special,handle,eventPath,bubbleType,type=event.type||event,namespaces=[];if(rfocusMorph.test(type+jQuery.event.triggered)){return}if(type.indexOf("!")>=0){type=type.slice(0,-1);exclusive=true}if(type.indexOf(".")>=0){namespaces=type.split(".");type=namespaces.shift();namespaces.sort()}if((!elem||jQuery.event.customEvent[type])&&!jQuery.event.global[type]){return}event=typeof event==="object"?event[jQuery.expando]?event:new jQuery.Event(type,event):new jQuery.Event(type);event.type=type;event.isTrigger=true;event.exclusive=exclusive;event.namespace=namespaces.join(".");event.namespace_re=event.namespace?new RegExp("(^|\\.)"+namespaces.join("\\.(?:.*\\.|)")+"(\\.|$)"):null;ontype=type.indexOf(":")<0?"on"+type:"";if(!elem){cache=jQuery.cache;for(i in cache){if(cache[i].events&&cache[i].events[type]){jQuery.event.trigger(event,data,cache[i].handle.elem,true)}}return}event.result=undefined;if(!event.target){event.target=elem}data=data!=null?jQuery.makeArray(data):[];data.unshift(event);special=jQuery.event.special[type]||{};if(special.trigger&&special.trigger.apply(elem,data)===false){return}eventPath=[[elem,special.bindType||type]];if(!onlyHandlers&&!special.noBubble&&!jQuery.isWindow(elem)){bubbleType=special.delegateType||type;cur=rfocusMorph.test(bubbleType+type)?elem:elem.parentNode;for(old=elem;cur;cur=cur.parentNode){eventPath.push([cur,bubbleType]);old=cur}if(old===(elem.ownerDocument||document)){eventPath.push([old.defaultView||old.parentWindow||window,bubbleType])}}for(i=0;i<eventPath.length&&!event.isPropagationStopped();i++){cur=eventPath[i][0];event.type=eventPath[i][1];handle=(jQuery._data(cur,"events")||{})[event.type]&&jQuery._data(cur,"handle");if(handle){handle.apply(cur,data)}handle=ontype&&cur[ontype];if(handle&&jQuery.acceptData(cur)&&handle.apply&&handle.apply(cur,data)===false){event.preventDefault()}}event.type=type;if(!onlyHandlers&&!event.isDefaultPrevented()){if((!special._default||special._default.apply(elem.ownerDocument,data)===false)&&!(type==="click"&&jQuery.nodeName(elem,"a"))&&jQuery.acceptData(elem)){if(ontype&&elem[type]&&(type!=="focus"&&type!=="blur"||event.target.offsetWidth!==0)&&!jQuery.isWindow(elem)){old=elem[ontype];if(old){elem[ontype]=null}jQuery.event.triggered=type;elem[type]();jQuery.event.triggered=undefined;if(old){elem[ontype]=old}}}}return event.result},dispatch:function(event){event=jQuery.event.fix(event||window.event);var i,j,cur,ret,selMatch,matched,matches,handleObj,sel,related,handlers=(jQuery._data(this,"events")||{})[event.type]||[],delegateCount=handlers.delegateCount,args=core_slice.call(arguments),run_all=!event.exclusive&&!event.namespace,special=jQuery.event.special[event.type]||{},handlerQueue=[];args[0]=event;event.delegateTarget=this;if(special.preDispatch&&special.preDispatch.call(this,event)===false){return}if(delegateCount&&!(event.button&&event.type==="click")){for(cur=event.target;cur!=this;cur=cur.parentNode||this){if(cur.disabled!==true||event.type!=="click"){selMatch={};matches=[];for(i=0;i<delegateCount;i++){handleObj=handlers[i];sel=handleObj.selector;if(selMatch[sel]===undefined){selMatch[sel]=handleObj.needsContext?jQuery(sel,this).index(cur)>=0:jQuery.find(sel,this,null,[cur]).length}if(selMatch[sel]){matches.push(handleObj)}}if(matches.length){handlerQueue.push({elem:cur,matches:matches})}}}}if(handlers.length>delegateCount){handlerQueue.push({elem:this,matches:handlers.slice(delegateCount)})}for(i=0;i<handlerQueue.length&&!event.isPropagationStopped();i++){matched=handlerQueue[i];event.currentTarget=matched.elem;for(j=0;j<matched.matches.length&&!event.isImmediatePropagationStopped();j++){handleObj=matched.matches[j];if(run_all||!event.namespace&&!handleObj.namespace||event.namespace_re&&event.namespace_re.test(handleObj.namespace)){event.data=handleObj.data;event.handleObj=handleObj;ret=((jQuery.event.special[handleObj.origType]||{}).handle||handleObj.handler).apply(matched.elem,args);if(ret!==undefined){event.result=ret;if(ret===false){event.preventDefault();event.stopPropagation()}}}}}if(special.postDispatch){special.postDispatch.call(this,event)}return event.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(event,original){if(event.which==null){event.which=original.charCode!=null?original.charCode:original.keyCode}return event}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(event,original){var eventDoc,doc,body,button=original.button,fromElement=original.fromElement;if(event.pageX==null&&original.clientX!=null){eventDoc=event.target.ownerDocument||document;doc=eventDoc.documentElement;body=eventDoc.body;event.pageX=original.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc&&doc.clientLeft||body&&body.clientLeft||0);event.pageY=original.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc&&doc.clientTop||body&&body.clientTop||0)}if(!event.relatedTarget&&fromElement){event.relatedTarget=fromElement===event.target?original.toElement:fromElement}if(!event.which&&button!==undefined){event.which=button&1?1:button&2?3:button&4?2:0}return event}},fix:function(event){if(event[jQuery.expando]){return event}var i,prop,originalEvent=event,fixHook=jQuery.event.fixHooks[event.type]||{},copy=fixHook.props?this.props.concat(fixHook.props):this.props;event=jQuery.Event(originalEvent);for(i=copy.length;i;){prop=copy[--i];event[prop]=originalEvent[prop]}if(!event.target){event.target=originalEvent.srcElement||document}if(event.target.nodeType===3){event.target=event.target.parentNode}event.metaKey=!!event.metaKey;return fixHook.filter?fixHook.filter(event,originalEvent):event},special:{load:{noBubble:true},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(data,namespaces,eventHandle){if(jQuery.isWindow(this)){this.onbeforeunload=eventHandle}},teardown:function(namespaces,eventHandle){if(this.onbeforeunload===eventHandle){this.onbeforeunload=null}}}},simulate:function(type,elem,event,bubble){var e=jQuery.extend(new jQuery.Event,event,{type:type,isSimulated:true,originalEvent:{}});if(bubble){jQuery.event.trigger(e,null,elem)}else{jQuery.event.dispatch.call(elem,e)}if(e.isDefaultPrevented()){event.preventDefault()}}};jQuery.event.handle=jQuery.event.dispatch;jQuery.removeEvent=document.removeEventListener?function(elem,type,handle){if(elem.removeEventListener){elem.removeEventListener(type,handle,false)}}:function(elem,type,handle){var name="on"+type;if(elem.detachEvent){if(typeof elem[name]==="undefined"){elem[name]=null}elem.detachEvent(name,handle)}};jQuery.Event=function(src,props){if(!(this instanceof jQuery.Event)){return new jQuery.Event(src,props)}if(src&&src.type){this.originalEvent=src;this.type=src.type;this.isDefaultPrevented=src.defaultPrevented||src.returnValue===false||src.getPreventDefault&&src.getPreventDefault()?returnTrue:returnFalse}else{this.type=src}if(props){jQuery.extend(this,props)}this.timeStamp=src&&src.timeStamp||jQuery.now();this[jQuery.expando]=true};function returnFalse(){return false}function returnTrue(){return true}jQuery.Event.prototype={preventDefault:function(){this.isDefaultPrevented=returnTrue;var e=this.originalEvent;if(!e){return}if(e.preventDefault){e.preventDefault()}else{e.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=returnTrue;var e=this.originalEvent;if(!e){return}if(e.stopPropagation){e.stopPropagation()}e.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=returnTrue;this.stopPropagation()},isDefaultPrevented:returnFalse,isPropagationStopped:returnFalse,isImmediatePropagationStopped:returnFalse};jQuery.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(orig,fix){jQuery.event.special[orig]={delegateType:fix,bindType:fix,handle:function(event){var ret,target=this,related=event.relatedTarget,handleObj=event.handleObj,selector=handleObj.selector;if(!related||related!==target&&!jQuery.contains(target,related)){event.type=handleObj.origType;ret=handleObj.handler.apply(this,arguments);event.type=fix}return ret}}});if(!jQuery.support.submitBubbles){jQuery.event.special.submit={setup:function(){if(jQuery.nodeName(this,"form")){return false}jQuery.event.add(this,"click._submit keypress._submit",function(e){var elem=e.target,form=jQuery.nodeName(elem,"input")||jQuery.nodeName(elem,"button")?elem.form:undefined;if(form&&!jQuery._data(form,"_submit_attached")){jQuery.event.add(form,"submit._submit",function(event){event._submit_bubble=true});jQuery._data(form,"_submit_attached",true)}})},postDispatch:function(event){if(event._submit_bubble){delete event._submit_bubble;if(this.parentNode&&!event.isTrigger){jQuery.event.simulate("submit",this.parentNode,event,true)}}},teardown:function(){if(jQuery.nodeName(this,"form")){return false}jQuery.event.remove(this,"._submit")}}}if(!jQuery.support.changeBubbles){jQuery.event.special.change={setup:function(){if(rformElems.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio"){jQuery.event.add(this,"propertychange._change",function(event){if(event.originalEvent.propertyName==="checked"){this._just_changed=true}});jQuery.event.add(this,"click._change",function(event){if(this._just_changed&&!event.isTrigger){this._just_changed=false}jQuery.event.simulate("change",this,event,true)})}return false}jQuery.event.add(this,"beforeactivate._change",function(e){var elem=e.target;if(rformElems.test(elem.nodeName)&&!jQuery._data(elem,"_change_attached")){jQuery.event.add(elem,"change._change",function(event){if(this.parentNode&&!event.isSimulated&&!event.isTrigger){jQuery.event.simulate("change",this.parentNode,event,true)}});jQuery._data(elem,"_change_attached",true)}})},handle:function(event){var elem=event.target;if(this!==elem||event.isSimulated||event.isTrigger||elem.type!=="radio"&&elem.type!=="checkbox"){return event.handleObj.handler.apply(this,arguments)}},teardown:function(){jQuery.event.remove(this,"._change");return!rformElems.test(this.nodeName)}}}if(!jQuery.support.focusinBubbles){jQuery.each({focus:"focusin",blur:"focusout"},function(orig,fix){var attaches=0,handler=function(event){jQuery.event.simulate(fix,event.target,jQuery.event.fix(event),true)};jQuery.event.special[fix]={setup:function(){if(attaches++===0){document.addEventListener(orig,handler,true)}},teardown:function(){if(--attaches===0){document.removeEventListener(orig,handler,true)}}}})}jQuery.fn.extend({on:function(types,selector,data,fn,one){var origFn,type;if(typeof types==="object"){if(typeof selector!=="string"){data=data||selector;selector=undefined}for(type in types){this.on(type,selector,data,types[type],one)}return this}if(data==null&&fn==null){fn=selector;data=selector=undefined}else if(fn==null){if(typeof selector==="string"){fn=data;data=undefined}else{fn=data;data=selector;selector=undefined}}if(fn===false){fn=returnFalse}else if(!fn){return this}if(one===1){origFn=fn;fn=function(event){jQuery().off(event);return origFn.apply(this,arguments)};fn.guid=origFn.guid||(origFn.guid=jQuery.guid++)}return this.each(function(){jQuery.event.add(this,types,fn,data,selector)})},one:function(types,selector,data,fn){return this.on(types,selector,data,fn,1)},off:function(types,selector,fn){var handleObj,type;if(types&&types.preventDefault&&types.handleObj){handleObj=types.handleObj;jQuery(types.delegateTarget).off(handleObj.namespace?handleObj.origType+"."+handleObj.namespace:handleObj.origType,handleObj.selector,handleObj.handler);return this}if(typeof types==="object"){for(type in types){this.off(type,selector,types[type])}return this}if(selector===false||typeof selector==="function"){fn=selector;selector=undefined}if(fn===false){fn=returnFalse}return this.each(function(){jQuery.event.remove(this,types,fn,selector)})},bind:function(types,data,fn){return this.on(types,null,data,fn)},unbind:function(types,fn){return this.off(types,null,fn)},live:function(types,data,fn){jQuery(this.context).on(types,this.selector,data,fn);return this},die:function(types,fn){jQuery(this.context).off(types,this.selector||"**",fn);return this},delegate:function(selector,types,data,fn){return this.on(types,selector,data,fn)},undelegate:function(selector,types,fn){return arguments.length===1?this.off(selector,"**"):this.off(types,selector||"**",fn)},trigger:function(type,data){return this.each(function(){jQuery.event.trigger(type,data,this)})},triggerHandler:function(type,data){if(this[0]){return jQuery.event.trigger(type,data,this[0],true)}},toggle:function(fn){var args=arguments,guid=fn.guid||jQuery.guid++,i=0,toggler=function(event){var lastToggle=(jQuery._data(this,"lastToggle"+fn.guid)||0)%i;jQuery._data(this,"lastToggle"+fn.guid,lastToggle+1);event.preventDefault();return args[lastToggle].apply(this,arguments)||false};toggler.guid=guid;while(i<args.length){args[i++].guid=guid}return this.click(toggler)},hover:function(fnOver,fnOut){return this.mouseenter(fnOver).mouseleave(fnOut||fnOver)}});jQuery.each(("blur focus focusin focusout load resize scroll unload click dblclick "+"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave "+"change select submit keydown keypress keyup error contextmenu").split(" "),function(i,name){jQuery.fn[name]=function(data,fn){if(fn==null){fn=data;data=null}return arguments.length>0?this.on(name,null,data,fn):this.trigger(name)};if(rkeyEvent.test(name)){jQuery.event.fixHooks[name]=jQuery.event.keyHooks}if(rmouseEvent.test(name)){jQuery.event.fixHooks[name]=jQuery.event.mouseHooks}});(function(window,undefined){var cachedruns,assertGetIdNotName,Expr,getText,isXML,contains,compile,sortOrder,hasDuplicate,outermostContext,baseHasDuplicate=true,strundefined="undefined",expando=("sizcache"+Math.random()).replace(".",""),Token=String,document=window.document,docElem=document.documentElement,dirruns=0,done=0,pop=[].pop,push=[].push,slice=[].slice,indexOf=[].indexOf||function(elem){var i=0,len=this.length;for(;i<len;i++){if(this[i]===elem){return i}}return-1},markFunction=function(fn,value){fn[expando]=value==null||value;return fn},createCache=function(){var cache={},keys=[];return markFunction(function(key,value){if(keys.push(key)>Expr.cacheLength){delete cache[keys.shift()]}return cache[key+" "]=value},cache)},classCache=createCache(),tokenCache=createCache(),compilerCache=createCache(),whitespace="[\\x20\\t\\r\\n\\f]",characterEncoding="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",identifier=characterEncoding.replace("w","w#"),operators="([*^$|!~]?=)",attributes="\\["+whitespace+"*("+characterEncoding+")"+whitespace+"*(?:"+operators+whitespace+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+identifier+")|)|)"+whitespace+"*\\]",pseudos=":("+characterEncoding+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+attributes+")|[^:]|\\\\.)*|.*))\\)|)",pos=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+whitespace+"*((?:-\\d)?\\d*)"+whitespace+"*\\)|)(?=[^-]|$)",rtrim=new RegExp("^"+whitespace+"+|((?:^|[^\\\\])(?:\\\\.)*)"+whitespace+"+$","g"),rcomma=new RegExp("^"+whitespace+"*,"+whitespace+"*"),rcombinators=new RegExp("^"+whitespace+"*([\\x20\\t\\r\\n\\f>+~])"+whitespace+"*"),rpseudo=new RegExp(pseudos),rquickExpr=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,rnot=/^:not/,rsibling=/[\x20\t\r\n\f]*[+~]/,rendsWithNot=/:not\($/,rheader=/h\d/i,rinputs=/input|select|textarea|button/i,rbackslash=/\\(?!\\)/g,matchExpr={ID:new RegExp("^#("+characterEncoding+")"),CLASS:new RegExp("^\\.("+characterEncoding+")"),NAME:new RegExp("^\\[name=['\"]?("+characterEncoding+")['\"]?\\]"),TAG:new RegExp("^("+characterEncoding.replace("w","w*")+")"),ATTR:new RegExp("^"+attributes),PSEUDO:new RegExp("^"+pseudos),POS:new RegExp(pos,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+whitespace+"*(even|odd|(([+-]|)(\\d*)n|)"+whitespace+"*(?:([+-]|)"+whitespace+"*(\\d+)|))"+whitespace+"*\\)|)","i"),needsContext:new RegExp("^"+whitespace+"*[>+~]|"+pos,"i")},assert=function(fn){var div=document.createElement("div");try{return fn(div)}catch(e){return false}finally{div=null}},assertTagNameNoComments=assert(function(div){div.appendChild(document.createComment(""));return!div.getElementsByTagName("*").length}),assertHrefNotNormalized=assert(function(div){div.innerHTML="<a href='#'></a>";return div.firstChild&&typeof div.firstChild.getAttribute!==strundefined&&div.firstChild.getAttribute("href")==="#"}),assertAttributes=assert(function(div){div.innerHTML="<select></select>";var type=typeof div.lastChild.getAttribute("multiple");return type!=="boolean"&&type!=="string"}),assertUsableClassName=assert(function(div){div.innerHTML="<div class='hidden e'></div><div class='hidden'></div>";if(!div.getElementsByClassName||!div.getElementsByClassName("e").length){return false}div.lastChild.className="e";return div.getElementsByClassName("e").length===2}),assertUsableName=assert(function(div){div.id=expando+0;div.innerHTML="<a name='"+expando+"'></a><div name='"+expando+"'></div>";docElem.insertBefore(div,docElem.firstChild);var pass=document.getElementsByName&&document.getElementsByName(expando).length===2+document.getElementsByName(expando+0).length;assertGetIdNotName=!document.getElementById(expando);docElem.removeChild(div);return pass});try{slice.call(docElem.childNodes,0)[0].nodeType}catch(e){slice=function(i){var elem,results=[];for(;elem=this[i];i++){results.push(elem)}return results}}function Sizzle(selector,context,results,seed){results=results||[];context=context||document;var match,elem,xml,m,nodeType=context.nodeType;if(!selector||typeof selector!=="string"){return results}if(nodeType!==1&&nodeType!==9){return[]}xml=isXML(context);if(!xml&&!seed){if(match=rquickExpr.exec(selector)){if(m=match[1]){if(nodeType===9){elem=context.getElementById(m);if(elem&&elem.parentNode){if(elem.id===m){results.push(elem);return results}}else{return results}}else{if(context.ownerDocument&&(elem=context.ownerDocument.getElementById(m))&&contains(context,elem)&&elem.id===m){results.push(elem);return results}}}else if(match[2]){push.apply(results,slice.call(context.getElementsByTagName(selector),0));return results}else if((m=match[3])&&assertUsableClassName&&context.getElementsByClassName){push.apply(results,slice.call(context.getElementsByClassName(m),0));return results}}}return select(selector.replace(rtrim,"$1"),context,results,seed,xml)}Sizzle.matches=function(expr,elements){return Sizzle(expr,null,null,elements)};Sizzle.matchesSelector=function(elem,expr){return Sizzle(expr,null,null,[elem]).length>0};function createInputPseudo(type){return function(elem){var name=elem.nodeName.toLowerCase();return name==="input"&&elem.type===type}}function createButtonPseudo(type){return function(elem){var name=elem.nodeName.toLowerCase();return(name==="input"||name==="button")&&elem.type===type}}function createPositionalPseudo(fn){return markFunction(function(argument){argument=+argument;return markFunction(function(seed,matches){var j,matchIndexes=fn([],seed.length,argument),i=matchIndexes.length;while(i--){if(seed[j=matchIndexes[i]]){seed[j]=!(matches[j]=seed[j])}}})})}getText=Sizzle.getText=function(elem){var node,ret="",i=0,nodeType=elem.nodeType;if(nodeType){if(nodeType===1||nodeType===9||nodeType===11){if(typeof elem.textContent==="string"){return elem.textContent}else{for(elem=elem.firstChild;elem;elem=elem.nextSibling){ret+=getText(elem)}}}else if(nodeType===3||nodeType===4){return elem.nodeValue}}else{for(;node=elem[i];i++){ret+=getText(node)}}return ret};isXML=Sizzle.isXML=function(elem){var documentElement=elem&&(elem.ownerDocument||elem).documentElement;return documentElement?documentElement.nodeName!=="HTML":false};contains=Sizzle.contains=docElem.contains?function(a,b){var adown=a.nodeType===9?a.documentElement:a,bup=b&&b.parentNode;return a===bup||!!(bup&&bup.nodeType===1&&adown.contains&&adown.contains(bup))}:docElem.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode){if(b===a){return true}}return false};Sizzle.attr=function(elem,name){var val,xml=isXML(elem);if(!xml){name=name.toLowerCase()}if(val=Expr.attrHandle[name]){return val(elem)}if(xml||assertAttributes){return elem.getAttribute(name)}val=elem.getAttributeNode(name);return val?typeof elem[name]==="boolean"?elem[name]?name:null:val.specified?val.value:null:null};Expr=Sizzle.selectors={cacheLength:50,createPseudo:markFunction,match:matchExpr,attrHandle:assertHrefNotNormalized?{}:{href:function(elem){return elem.getAttribute("href",2)},type:function(elem){return elem.getAttribute("type")}},find:{ID:assertGetIdNotName?function(id,context,xml){if(typeof context.getElementById!==strundefined&&!xml){var m=context.getElementById(id);return m&&m.parentNode?[m]:[]}}:function(id,context,xml){if(typeof context.getElementById!==strundefined&&!xml){var m=context.getElementById(id);return m?m.id===id||typeof m.getAttributeNode!==strundefined&&m.getAttributeNode("id").value===id?[m]:undefined:[]}},TAG:assertTagNameNoComments?function(tag,context){if(typeof context.getElementsByTagName!==strundefined){return context.getElementsByTagName(tag)}}:function(tag,context){var results=context.getElementsByTagName(tag);if(tag==="*"){var elem,tmp=[],i=0;for(;elem=results[i];i++){if(elem.nodeType===1){tmp.push(elem)}}return tmp}return results},NAME:assertUsableName&&function(tag,context){if(typeof context.getElementsByName!==strundefined){return context.getElementsByName(name)}},CLASS:assertUsableClassName&&function(className,context,xml){if(typeof context.getElementsByClassName!==strundefined&&!xml){return context.getElementsByClassName(className)}}},relative:{">":{dir:"parentNode",first:true}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:true},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(match){match[1]=match[1].replace(rbackslash,"");match[3]=(match[4]||match[5]||"").replace(rbackslash,"");if(match[2]==="~="){match[3]=" "+match[3]+" "}return match.slice(0,4)},CHILD:function(match){match[1]=match[1].toLowerCase();if(match[1]==="nth"){if(!match[2]){Sizzle.error(match[0])}match[3]=+(match[3]?match[4]+(match[5]||1):2*(match[2]==="even"||match[2]==="odd"));match[4]=+(match[6]+match[7]||match[2]==="odd")}else if(match[2]){Sizzle.error(match[0])}return match},PSEUDO:function(match){var unquoted,excess;if(matchExpr["CHILD"].test(match[0])){return null}if(match[3]){match[2]=match[3]}else if(unquoted=match[4]){if(rpseudo.test(unquoted)&&(excess=tokenize(unquoted,true))&&(excess=unquoted.indexOf(")",unquoted.length-excess)-unquoted.length)){unquoted=unquoted.slice(0,excess);match[0]=match[0].slice(0,excess)}match[2]=unquoted}return match.slice(0,3)}},filter:{ID:assertGetIdNotName?function(id){id=id.replace(rbackslash,"");return function(elem){return elem.getAttribute("id")===id}}:function(id){id=id.replace(rbackslash,"");return function(elem){var node=typeof elem.getAttributeNode!==strundefined&&elem.getAttributeNode("id");return node&&node.value===id}},TAG:function(nodeName){if(nodeName==="*"){return function(){return true}}nodeName=nodeName.replace(rbackslash,"").toLowerCase();return function(elem){return elem.nodeName&&elem.nodeName.toLowerCase()===nodeName}},CLASS:function(className){var pattern=classCache[expando][className+" "];return pattern||(pattern=new RegExp("(^|"+whitespace+")"+className+"("+whitespace+"|$)"))&&classCache(className,function(elem){return pattern.test(elem.className||typeof elem.getAttribute!==strundefined&&elem.getAttribute("class")||"")})},ATTR:function(name,operator,check){return function(elem,context){var result=Sizzle.attr(elem,name);if(result==null){return operator==="!="}if(!operator){return true}result+="";return operator==="="?result===check:operator==="!="?result!==check:operator==="^="?check&&result.indexOf(check)===0:operator==="*="?check&&result.indexOf(check)>-1:operator==="$="?check&&result.substr(result.length-check.length)===check:operator==="~="?(" "+result+" ").indexOf(check)>-1:operator==="|="?result===check||result.substr(0,check.length+1)===check+"-":false}},CHILD:function(type,argument,first,last){if(type==="nth"){return function(elem){var node,diff,parent=elem.parentNode;if(first===1&&last===0){return true}if(parent){diff=0;for(node=parent.firstChild;node;node=node.nextSibling){if(node.nodeType===1){diff++;
+if(elem===node){break}}}}diff-=last;return diff===first||diff%first===0&&diff/first>=0}}return function(elem){var node=elem;switch(type){case"only":case"first":while(node=node.previousSibling){if(node.nodeType===1){return false}}if(type==="first"){return true}node=elem;case"last":while(node=node.nextSibling){if(node.nodeType===1){return false}}return true}}},PSEUDO:function(pseudo,argument){var args,fn=Expr.pseudos[pseudo]||Expr.setFilters[pseudo.toLowerCase()]||Sizzle.error("unsupported pseudo: "+pseudo);if(fn[expando]){return fn(argument)}if(fn.length>1){args=[pseudo,pseudo,"",argument];return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase())?markFunction(function(seed,matches){var idx,matched=fn(seed,argument),i=matched.length;while(i--){idx=indexOf.call(seed,matched[i]);seed[idx]=!(matches[idx]=matched[i])}}):function(elem){return fn(elem,0,args)}}return fn}},pseudos:{not:markFunction(function(selector){var input=[],results=[],matcher=compile(selector.replace(rtrim,"$1"));return matcher[expando]?markFunction(function(seed,matches,context,xml){var elem,unmatched=matcher(seed,null,xml,[]),i=seed.length;while(i--){if(elem=unmatched[i]){seed[i]=!(matches[i]=elem)}}}):function(elem,context,xml){input[0]=elem;matcher(input,null,xml,results);return!results.pop()}}),has:markFunction(function(selector){return function(elem){return Sizzle(selector,elem).length>0}}),contains:markFunction(function(text){return function(elem){return(elem.textContent||elem.innerText||getText(elem)).indexOf(text)>-1}}),enabled:function(elem){return elem.disabled===false},disabled:function(elem){return elem.disabled===true},checked:function(elem){var nodeName=elem.nodeName.toLowerCase();return nodeName==="input"&&!!elem.checked||nodeName==="option"&&!!elem.selected},selected:function(elem){if(elem.parentNode){elem.parentNode.selectedIndex}return elem.selected===true},parent:function(elem){return!Expr.pseudos["empty"](elem)},empty:function(elem){var nodeType;elem=elem.firstChild;while(elem){if(elem.nodeName>"@"||(nodeType=elem.nodeType)===3||nodeType===4){return false}elem=elem.nextSibling}return true},header:function(elem){return rheader.test(elem.nodeName)},text:function(elem){var type,attr;return elem.nodeName.toLowerCase()==="input"&&(type=elem.type)==="text"&&((attr=elem.getAttribute("type"))==null||attr.toLowerCase()===type)},radio:createInputPseudo("radio"),checkbox:createInputPseudo("checkbox"),file:createInputPseudo("file"),password:createInputPseudo("password"),image:createInputPseudo("image"),submit:createButtonPseudo("submit"),reset:createButtonPseudo("reset"),button:function(elem){var name=elem.nodeName.toLowerCase();return name==="input"&&elem.type==="button"||name==="button"},input:function(elem){return rinputs.test(elem.nodeName)},focus:function(elem){var doc=elem.ownerDocument;return elem===doc.activeElement&&(!doc.hasFocus||doc.hasFocus())&&!!(elem.type||elem.href||~elem.tabIndex)},active:function(elem){return elem===elem.ownerDocument.activeElement},first:createPositionalPseudo(function(){return[0]}),last:createPositionalPseudo(function(matchIndexes,length){return[length-1]}),eq:createPositionalPseudo(function(matchIndexes,length,argument){return[argument<0?argument+length:argument]}),even:createPositionalPseudo(function(matchIndexes,length){for(var i=0;i<length;i+=2){matchIndexes.push(i)}return matchIndexes}),odd:createPositionalPseudo(function(matchIndexes,length){for(var i=1;i<length;i+=2){matchIndexes.push(i)}return matchIndexes}),lt:createPositionalPseudo(function(matchIndexes,length,argument){for(var i=argument<0?argument+length:argument;--i>=0;){matchIndexes.push(i)}return matchIndexes}),gt:createPositionalPseudo(function(matchIndexes,length,argument){for(var i=argument<0?argument+length:argument;++i<length;){matchIndexes.push(i)}return matchIndexes})}};function siblingCheck(a,b,ret){if(a===b){return ret}var cur=a.nextSibling;while(cur){if(cur===b){return-1}cur=cur.nextSibling}return 1}sortOrder=docElem.compareDocumentPosition?function(a,b){if(a===b){hasDuplicate=true;return 0}return(!a.compareDocumentPosition||!b.compareDocumentPosition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:function(a,b){if(a===b){hasDuplicate=true;return 0}else if(a.sourceIndex&&b.sourceIndex){return a.sourceIndex-b.sourceIndex}var al,bl,ap=[],bp=[],aup=a.parentNode,bup=b.parentNode,cur=aup;if(aup===bup){return siblingCheck(a,b)}else if(!aup){return-1}else if(!bup){return 1}while(cur){ap.unshift(cur);cur=cur.parentNode}cur=bup;while(cur){bp.unshift(cur);cur=cur.parentNode}al=ap.length;bl=bp.length;for(var i=0;i<al&&i<bl;i++){if(ap[i]!==bp[i]){return siblingCheck(ap[i],bp[i])}}return i===al?siblingCheck(a,bp[i],-1):siblingCheck(ap[i],b,1)};[0,0].sort(sortOrder);baseHasDuplicate=!hasDuplicate;Sizzle.uniqueSort=function(results){var elem,duplicates=[],i=1,j=0;hasDuplicate=baseHasDuplicate;results.sort(sortOrder);if(hasDuplicate){for(;elem=results[i];i++){if(elem===results[i-1]){j=duplicates.push(i)}}while(j--){results.splice(duplicates[j],1)}}return results};Sizzle.error=function(msg){throw new Error("Syntax error, unrecognized expression: "+msg)};function tokenize(selector,parseOnly){var matched,match,tokens,type,soFar,groups,preFilters,cached=tokenCache[expando][selector+" "];if(cached){return parseOnly?0:cached.slice(0)}soFar=selector;groups=[];preFilters=Expr.preFilter;while(soFar){if(!matched||(match=rcomma.exec(soFar))){if(match){soFar=soFar.slice(match[0].length)||soFar}groups.push(tokens=[])}matched=false;if(match=rcombinators.exec(soFar)){tokens.push(matched=new Token(match.shift()));soFar=soFar.slice(matched.length);matched.type=match[0].replace(rtrim," ")}for(type in Expr.filter){if((match=matchExpr[type].exec(soFar))&&(!preFilters[type]||(match=preFilters[type](match)))){tokens.push(matched=new Token(match.shift()));soFar=soFar.slice(matched.length);matched.type=type;matched.matches=match}}if(!matched){break}}return parseOnly?soFar.length:soFar?Sizzle.error(selector):tokenCache(selector,groups).slice(0)}function addCombinator(matcher,combinator,base){var dir=combinator.dir,checkNonElements=base&&combinator.dir==="parentNode",doneName=done++;return combinator.first?function(elem,context,xml){while(elem=elem[dir]){if(checkNonElements||elem.nodeType===1){return matcher(elem,context,xml)}}}:function(elem,context,xml){if(!xml){var cache,dirkey=dirruns+" "+doneName+" ",cachedkey=dirkey+cachedruns;while(elem=elem[dir]){if(checkNonElements||elem.nodeType===1){if((cache=elem[expando])===cachedkey){return elem.sizset}else if(typeof cache==="string"&&cache.indexOf(dirkey)===0){if(elem.sizset){return elem}}else{elem[expando]=cachedkey;if(matcher(elem,context,xml)){elem.sizset=true;return elem}elem.sizset=false}}}}else{while(elem=elem[dir]){if(checkNonElements||elem.nodeType===1){if(matcher(elem,context,xml)){return elem}}}}}}function elementMatcher(matchers){return matchers.length>1?function(elem,context,xml){var i=matchers.length;while(i--){if(!matchers[i](elem,context,xml)){return false}}return true}:matchers[0]}function condense(unmatched,map,filter,context,xml){var elem,newUnmatched=[],i=0,len=unmatched.length,mapped=map!=null;for(;i<len;i++){if(elem=unmatched[i]){if(!filter||filter(elem,context,xml)){newUnmatched.push(elem);if(mapped){map.push(i)}}}}return newUnmatched}function setMatcher(preFilter,selector,matcher,postFilter,postFinder,postSelector){if(postFilter&&!postFilter[expando]){postFilter=setMatcher(postFilter)}if(postFinder&&!postFinder[expando]){postFinder=setMatcher(postFinder,postSelector)}return markFunction(function(seed,results,context,xml){var temp,i,elem,preMap=[],postMap=[],preexisting=results.length,elems=seed||multipleContexts(selector||"*",context.nodeType?[context]:context,[]),matcherIn=preFilter&&(seed||!selector)?condense(elems,preMap,preFilter,context,xml):elems,matcherOut=matcher?postFinder||(seed?preFilter:preexisting||postFilter)?[]:results:matcherIn;if(matcher){matcher(matcherIn,matcherOut,context,xml)}if(postFilter){temp=condense(matcherOut,postMap);postFilter(temp,[],context,xml);i=temp.length;while(i--){if(elem=temp[i]){matcherOut[postMap[i]]=!(matcherIn[postMap[i]]=elem)}}}if(seed){if(postFinder||preFilter){if(postFinder){temp=[];i=matcherOut.length;while(i--){if(elem=matcherOut[i]){temp.push(matcherIn[i]=elem)}}postFinder(null,matcherOut=[],temp,xml)}i=matcherOut.length;while(i--){if((elem=matcherOut[i])&&(temp=postFinder?indexOf.call(seed,elem):preMap[i])>-1){seed[temp]=!(results[temp]=elem)}}}}else{matcherOut=condense(matcherOut===results?matcherOut.splice(preexisting,matcherOut.length):matcherOut);if(postFinder){postFinder(null,results,matcherOut,xml)}else{push.apply(results,matcherOut)}}})}function matcherFromTokens(tokens){var checkContext,matcher,j,len=tokens.length,leadingRelative=Expr.relative[tokens[0].type],implicitRelative=leadingRelative||Expr.relative[" "],i=leadingRelative?1:0,matchContext=addCombinator(function(elem){return elem===checkContext},implicitRelative,true),matchAnyContext=addCombinator(function(elem){return indexOf.call(checkContext,elem)>-1},implicitRelative,true),matchers=[function(elem,context,xml){return!leadingRelative&&(xml||context!==outermostContext)||((checkContext=context).nodeType?matchContext(elem,context,xml):matchAnyContext(elem,context,xml))}];for(;i<len;i++){if(matcher=Expr.relative[tokens[i].type]){matchers=[addCombinator(elementMatcher(matchers),matcher)]}else{matcher=Expr.filter[tokens[i].type].apply(null,tokens[i].matches);if(matcher[expando]){j=++i;for(;j<len;j++){if(Expr.relative[tokens[j].type]){break}}return setMatcher(i>1&&elementMatcher(matchers),i>1&&tokens.slice(0,i-1).join("").replace(rtrim,"$1"),matcher,i<j&&matcherFromTokens(tokens.slice(i,j)),j<len&&matcherFromTokens(tokens=tokens.slice(j)),j<len&&tokens.join(""))}matchers.push(matcher)}}return elementMatcher(matchers)}function matcherFromGroupMatchers(elementMatchers,setMatchers){var bySet=setMatchers.length>0,byElement=elementMatchers.length>0,superMatcher=function(seed,context,xml,results,expandContext){var elem,j,matcher,setMatched=[],matchedCount=0,i="0",unmatched=seed&&[],outermost=expandContext!=null,contextBackup=outermostContext,elems=seed||byElement&&Expr.find["TAG"]("*",expandContext&&context.parentNode||context),dirrunsUnique=dirruns+=contextBackup==null?1:Math.E;if(outermost){outermostContext=context!==document&&context;cachedruns=superMatcher.el}for(;(elem=elems[i])!=null;i++){if(byElement&&elem){for(j=0;matcher=elementMatchers[j];j++){if(matcher(elem,context,xml)){results.push(elem);break}}if(outermost){dirruns=dirrunsUnique;cachedruns=++superMatcher.el}}if(bySet){if(elem=!matcher&&elem){matchedCount--}if(seed){unmatched.push(elem)}}}matchedCount+=i;if(bySet&&i!==matchedCount){for(j=0;matcher=setMatchers[j];j++){matcher(unmatched,setMatched,context,xml)}if(seed){if(matchedCount>0){while(i--){if(!(unmatched[i]||setMatched[i])){setMatched[i]=pop.call(results)}}}setMatched=condense(setMatched)}push.apply(results,setMatched);if(outermost&&!seed&&setMatched.length>0&&matchedCount+setMatchers.length>1){Sizzle.uniqueSort(results)}}if(outermost){dirruns=dirrunsUnique;outermostContext=contextBackup}return unmatched};superMatcher.el=0;return bySet?markFunction(superMatcher):superMatcher}compile=Sizzle.compile=function(selector,group){var i,setMatchers=[],elementMatchers=[],cached=compilerCache[expando][selector+" "];if(!cached){if(!group){group=tokenize(selector)}i=group.length;while(i--){cached=matcherFromTokens(group[i]);if(cached[expando]){setMatchers.push(cached)}else{elementMatchers.push(cached)}}cached=compilerCache(selector,matcherFromGroupMatchers(elementMatchers,setMatchers))}return cached};function multipleContexts(selector,contexts,results){var i=0,len=contexts.length;for(;i<len;i++){Sizzle(selector,contexts[i],results)}return results}function select(selector,context,results,seed,xml){var i,tokens,token,type,find,match=tokenize(selector),j=match.length;if(!seed){if(match.length===1){tokens=match[0]=match[0].slice(0);if(tokens.length>2&&(token=tokens[0]).type==="ID"&&context.nodeType===9&&!xml&&Expr.relative[tokens[1].type]){context=Expr.find["ID"](token.matches[0].replace(rbackslash,""),context,xml)[0];if(!context){return results}selector=selector.slice(tokens.shift().length)}for(i=matchExpr["POS"].test(selector)?-1:tokens.length-1;i>=0;i--){token=tokens[i];if(Expr.relative[type=token.type]){break}if(find=Expr.find[type]){if(seed=find(token.matches[0].replace(rbackslash,""),rsibling.test(tokens[0].type)&&context.parentNode||context,xml)){tokens.splice(i,1);selector=seed.length&&tokens.join("");if(!selector){push.apply(results,slice.call(seed,0));return results}break}}}}}compile(selector,match)(seed,context,xml,results,rsibling.test(selector));return results}if(document.querySelectorAll){(function(){var disconnectedMatch,oldSelect=select,rescape=/'|\\/g,rattributeQuotes=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,rbuggyQSA=[":focus"],rbuggyMatches=[":active"],matches=docElem.matchesSelector||docElem.mozMatchesSelector||docElem.webkitMatchesSelector||docElem.oMatchesSelector||docElem.msMatchesSelector;assert(function(div){div.innerHTML="<select><option selected=''></option></select>";if(!div.querySelectorAll("[selected]").length){rbuggyQSA.push("\\["+whitespace+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)")}if(!div.querySelectorAll(":checked").length){rbuggyQSA.push(":checked")}});assert(function(div){div.innerHTML="<p test=''></p>";if(div.querySelectorAll("[test^='']").length){rbuggyQSA.push("[*^$]="+whitespace+"*(?:\"\"|'')")}div.innerHTML="<input type='hidden'/>";if(!div.querySelectorAll(":enabled").length){rbuggyQSA.push(":enabled",":disabled")}});rbuggyQSA=new RegExp(rbuggyQSA.join("|"));select=function(selector,context,results,seed,xml){if(!seed&&!xml&&!rbuggyQSA.test(selector)){var groups,i,old=true,nid=expando,newContext=context,newSelector=context.nodeType===9&&selector;if(context.nodeType===1&&context.nodeName.toLowerCase()!=="object"){groups=tokenize(selector);if(old=context.getAttribute("id")){nid=old.replace(rescape,"\\$&")}else{context.setAttribute("id",nid)}nid="[id='"+nid+"'] ";i=groups.length;while(i--){groups[i]=nid+groups[i].join("")}newContext=rsibling.test(selector)&&context.parentNode||context;newSelector=groups.join(",")}if(newSelector){try{push.apply(results,slice.call(newContext.querySelectorAll(newSelector),0));return results}catch(qsaError){}finally{if(!old){context.removeAttribute("id")}}}}return oldSelect(selector,context,results,seed,xml)};if(matches){assert(function(div){disconnectedMatch=matches.call(div,"div");try{matches.call(div,"[test!='']:sizzle");rbuggyMatches.push("!=",pseudos)}catch(e){}});rbuggyMatches=new RegExp(rbuggyMatches.join("|"));Sizzle.matchesSelector=function(elem,expr){expr=expr.replace(rattributeQuotes,"='$1']");if(!isXML(elem)&&!rbuggyMatches.test(expr)&&!rbuggyQSA.test(expr)){try{var ret=matches.call(elem,expr);if(ret||disconnectedMatch||elem.document&&elem.document.nodeType!==11){return ret}}catch(e){}}return Sizzle(expr,null,null,[elem]).length>0}}})()}Expr.pseudos["nth"]=Expr.pseudos["eq"];function setFilters(){}Expr.filters=setFilters.prototype=Expr.pseudos;Expr.setFilters=new setFilters;Sizzle.attr=jQuery.attr;jQuery.find=Sizzle;jQuery.expr=Sizzle.selectors;jQuery.expr[":"]=jQuery.expr.pseudos;jQuery.unique=Sizzle.uniqueSort;jQuery.text=Sizzle.getText;jQuery.isXMLDoc=Sizzle.isXML;jQuery.contains=Sizzle.contains})(window);var runtil=/Until$/,rparentsprev=/^(?:parents|prev(?:Until|All))/,isSimple=/^.[^:#\[\.,]*$/,rneedsContext=jQuery.expr.match.needsContext,guaranteedUnique={children:true,contents:true,next:true,prev:true};jQuery.fn.extend({find:function(selector){var i,l,length,n,r,ret,self=this;if(typeof selector!=="string"){return jQuery(selector).filter(function(){for(i=0,l=self.length;i<l;i++){if(jQuery.contains(self[i],this)){return true}}})}ret=this.pushStack("","find",selector);for(i=0,l=this.length;i<l;i++){length=ret.length;jQuery.find(selector,this[i],ret);if(i>0){for(n=length;n<ret.length;n++){for(r=0;r<length;r++){if(ret[r]===ret[n]){ret.splice(n--,1);break}}}}}return ret},has:function(target){var i,targets=jQuery(target,this),len=targets.length;return this.filter(function(){for(i=0;i<len;i++){if(jQuery.contains(this,targets[i])){return true}}})},not:function(selector){return this.pushStack(winnow(this,selector,false),"not",selector)},filter:function(selector){return this.pushStack(winnow(this,selector,true),"filter",selector)},is:function(selector){return!!selector&&(typeof selector==="string"?rneedsContext.test(selector)?jQuery(selector,this.context).index(this[0])>=0:jQuery.filter(selector,this).length>0:this.filter(selector).length>0)},closest:function(selectors,context){var cur,i=0,l=this.length,ret=[],pos=rneedsContext.test(selectors)||typeof selectors!=="string"?jQuery(selectors,context||this.context):0;for(;i<l;i++){cur=this[i];while(cur&&cur.ownerDocument&&cur!==context&&cur.nodeType!==11){if(pos?pos.index(cur)>-1:jQuery.find.matchesSelector(cur,selectors)){ret.push(cur);break}cur=cur.parentNode}}ret=ret.length>1?jQuery.unique(ret):ret;return this.pushStack(ret,"closest",selectors)},index:function(elem){if(!elem){return this[0]&&this[0].parentNode?this.prevAll().length:-1}if(typeof elem==="string"){return jQuery.inArray(this[0],jQuery(elem))}return jQuery.inArray(elem.jquery?elem[0]:elem,this)},add:function(selector,context){var set=typeof selector==="string"?jQuery(selector,context):jQuery.makeArray(selector&&selector.nodeType?[selector]:selector),all=jQuery.merge(this.get(),set);return this.pushStack(isDisconnected(set[0])||isDisconnected(all[0])?all:jQuery.unique(all))},addBack:function(selector){return this.add(selector==null?this.prevObject:this.prevObject.filter(selector))}});jQuery.fn.andSelf=jQuery.fn.addBack;function isDisconnected(node){return!node||!node.parentNode||node.parentNode.nodeType===11}function sibling(cur,dir){do{cur=cur[dir]}while(cur&&cur.nodeType!==1);return cur}jQuery.each({parent:function(elem){var parent=elem.parentNode;return parent&&parent.nodeType!==11?parent:null},parents:function(elem){return jQuery.dir(elem,"parentNode")},parentsUntil:function(elem,i,until){return jQuery.dir(elem,"parentNode",until)},next:function(elem){return sibling(elem,"nextSibling")},prev:function(elem){return sibling(elem,"previousSibling")},nextAll:function(elem){return jQuery.dir(elem,"nextSibling")},prevAll:function(elem){return jQuery.dir(elem,"previousSibling")},nextUntil:function(elem,i,until){return jQuery.dir(elem,"nextSibling",until)},prevUntil:function(elem,i,until){return jQuery.dir(elem,"previousSibling",until)},siblings:function(elem){return jQuery.sibling((elem.parentNode||{}).firstChild,elem)},children:function(elem){return jQuery.sibling(elem.firstChild)},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.merge([],elem.childNodes)}},function(name,fn){jQuery.fn[name]=function(until,selector){var ret=jQuery.map(this,fn,until);if(!runtil.test(name)){selector=until}if(selector&&typeof selector==="string"){ret=jQuery.filter(selector,ret)}ret=this.length>1&&!guaranteedUnique[name]?jQuery.unique(ret):ret;if(this.length>1&&rparentsprev.test(name)){ret=ret.reverse()}return this.pushStack(ret,name,core_slice.call(arguments).join(","))}});jQuery.extend({filter:function(expr,elems,not){if(not){expr=":not("+expr+")"}return elems.length===1?jQuery.find.matchesSelector(elems[0],expr)?[elems[0]]:[]:jQuery.find.matches(expr,elems)},dir:function(elem,dir,until){var matched=[],cur=elem[dir];while(cur&&cur.nodeType!==9&&(until===undefined||cur.nodeType!==1||!jQuery(cur).is(until))){if(cur.nodeType===1){matched.push(cur)}cur=cur[dir]}return matched},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType===1&&n!==elem){r.push(n)}}return r}});function winnow(elements,qualifier,keep){qualifier=qualifier||0;if(jQuery.isFunction(qualifier)){return jQuery.grep(elements,function(elem,i){var retVal=!!qualifier.call(elem,i,elem);return retVal===keep})}else if(qualifier.nodeType){return jQuery.grep(elements,function(elem,i){return elem===qualifier===keep})}else if(typeof qualifier==="string"){var filtered=jQuery.grep(elements,function(elem){return elem.nodeType===1});if(isSimple.test(qualifier)){return jQuery.filter(qualifier,filtered,!keep)}else{qualifier=jQuery.filter(qualifier,filtered)}}return jQuery.grep(elements,function(elem,i){return jQuery.inArray(elem,qualifier)>=0===keep})}function createSafeFragment(document){var list=nodeNames.split("|"),safeFrag=document.createDocumentFragment();if(safeFrag.createElement){while(list.length){safeFrag.createElement(list.pop())}}return safeFrag}var nodeNames="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|"+"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",rinlinejQuery=/ jQuery\d+="(?:null|\d+)"/g,rleadingWhitespace=/^\s+/,rxhtmlTag=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,rtagName=/<([\w:]+)/,rtbody=/<tbody/i,rhtml=/<|&#?\w+;/,rnoInnerhtml=/<(?:script|style|link)/i,rnocache=/<(?:script|object|embed|option|style)/i,rnoshimcache=new RegExp("<(?:"+nodeNames+")[\\s/>]","i"),rcheckableType=/^(?:checkbox|radio)$/,rchecked=/checked\s*(?:[^=]|=\s*.checked.)/i,rscriptType=/\/(java|ecma)script/i,rcleanScript=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,wrapMap={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},safeFragment=createSafeFragment(document),fragmentDiv=safeFragment.appendChild(document.createElement("div"));wrapMap.optgroup=wrapMap.option;wrapMap.tbody=wrapMap.tfoot=wrapMap.colgroup=wrapMap.caption=wrapMap.thead;wrapMap.th=wrapMap.td;if(!jQuery.support.htmlSerialize){wrapMap._default=[1,"X<div>","</div>"]}jQuery.fn.extend({text:function(value){return jQuery.access(this,function(value){return value===undefined?jQuery.text(this):this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(value))},null,value,arguments.length)},wrapAll:function(html){if(jQuery.isFunction(html)){return this.each(function(i){jQuery(this).wrapAll(html.call(this,i))})}if(this[0]){var wrap=jQuery(html,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){wrap.insertBefore(this[0])}wrap.map(function(){var elem=this;while(elem.firstChild&&elem.firstChild.nodeType===1){elem=elem.firstChild}return elem}).append(this)}return this},wrapInner:function(html){if(jQuery.isFunction(html)){return this.each(function(i){jQuery(this).wrapInner(html.call(this,i))})}return this.each(function(){var self=jQuery(this),contents=self.contents();if(contents.length){contents.wrapAll(html)}else{self.append(html)}})},wrap:function(html){var isFunction=jQuery.isFunction(html);return this.each(function(i){jQuery(this).wrapAll(isFunction?html.call(this,i):html)})},unwrap:function(){return this.parent().each(function(){if(!jQuery.nodeName(this,"body")){jQuery(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(elem){if(this.nodeType===1||this.nodeType===11){this.appendChild(elem)}})},prepend:function(){return this.domManip(arguments,true,function(elem){if(this.nodeType===1||this.nodeType===11){this.insertBefore(elem,this.firstChild)}})},before:function(){if(!isDisconnected(this[0])){return this.domManip(arguments,false,function(elem){this.parentNode.insertBefore(elem,this)})}if(arguments.length){var set=jQuery.clean(arguments);return this.pushStack(jQuery.merge(set,this),"before",this.selector)}},after:function(){if(!isDisconnected(this[0])){return this.domManip(arguments,false,function(elem){this.parentNode.insertBefore(elem,this.nextSibling)})}if(arguments.length){var set=jQuery.clean(arguments);return this.pushStack(jQuery.merge(this,set),"after",this.selector)}},remove:function(selector,keepData){var elem,i=0;for(;(elem=this[i])!=null;i++){if(!selector||jQuery.filter(selector,[elem]).length){if(!keepData&&elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"));jQuery.cleanData([elem])}if(elem.parentNode){elem.parentNode.removeChild(elem)}}}return this},empty:function(){var elem,i=0;for(;(elem=this[i])!=null;i++){if(elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"))}while(elem.firstChild){elem.removeChild(elem.firstChild)}}return this},clone:function(dataAndEvents,deepDataAndEvents){dataAndEvents=dataAndEvents==null?false:dataAndEvents;deepDataAndEvents=deepDataAndEvents==null?dataAndEvents:deepDataAndEvents;return this.map(function(){return jQuery.clone(this,dataAndEvents,deepDataAndEvents)})},html:function(value){return jQuery.access(this,function(value){var elem=this[0]||{},i=0,l=this.length;if(value===undefined){return elem.nodeType===1?elem.innerHTML.replace(rinlinejQuery,""):undefined}if(typeof value==="string"&&!rnoInnerhtml.test(value)&&(jQuery.support.htmlSerialize||!rnoshimcache.test(value))&&(jQuery.support.leadingWhitespace||!rleadingWhitespace.test(value))&&!wrapMap[(rtagName.exec(value)||["",""])[1].toLowerCase()]){value=value.replace(rxhtmlTag,"<$1></$2>");try{for(;i<l;i++){elem=this[i]||{};if(elem.nodeType===1){jQuery.cleanData(elem.getElementsByTagName("*"));elem.innerHTML=value}}elem=0}catch(e){}}if(elem){this.empty().append(value)}},null,value,arguments.length)},replaceWith:function(value){if(!isDisconnected(this[0])){if(jQuery.isFunction(value)){return this.each(function(i){var self=jQuery(this),old=self.html();self.replaceWith(value.call(this,i,old))})}if(typeof value!=="string"){value=jQuery(value).detach()}return this.each(function(){var next=this.nextSibling,parent=this.parentNode;jQuery(this).remove();if(next){jQuery(next).before(value)}else{jQuery(parent).append(value)}})}return this.length?this.pushStack(jQuery(jQuery.isFunction(value)?value():value),"replaceWith",value):this},detach:function(selector){return this.remove(selector,true)},domManip:function(args,table,callback){args=[].concat.apply([],args);var results,first,fragment,iNoClone,i=0,value=args[0],scripts=[],l=this.length;if(!jQuery.support.checkClone&&l>1&&typeof value==="string"&&rchecked.test(value)){return this.each(function(){jQuery(this).domManip(args,table,callback)})}if(jQuery.isFunction(value)){return this.each(function(i){var self=jQuery(this);args[0]=value.call(this,i,table?self.html():undefined);self.domManip(args,table,callback)})}if(this[0]){results=jQuery.buildFragment(args,this,scripts);fragment=results.fragment;first=fragment.firstChild;if(fragment.childNodes.length===1){fragment=first}if(first){table=table&&jQuery.nodeName(first,"tr");for(iNoClone=results.cacheable||l-1;i<l;i++){callback.call(table&&jQuery.nodeName(this[i],"table")?findOrAppend(this[i],"tbody"):this[i],i===iNoClone?fragment:jQuery.clone(fragment,true,true))}}fragment=first=null;if(scripts.length){jQuery.each(scripts,function(i,elem){if(elem.src){if(jQuery.ajax){jQuery.ajax({url:elem.src,type:"GET",dataType:"script",async:false,global:false,"throws":true})}else{jQuery.error("no ajax")}}else{jQuery.globalEval((elem.text||elem.textContent||elem.innerHTML||"").replace(rcleanScript,""))}if(elem.parentNode){elem.parentNode.removeChild(elem)}})}}return this}});function findOrAppend(elem,tag){return elem.getElementsByTagName(tag)[0]||elem.appendChild(elem.ownerDocument.createElement(tag))}function cloneCopyEvent(src,dest){if(dest.nodeType!==1||!jQuery.hasData(src)){return}var type,i,l,oldData=jQuery._data(src),curData=jQuery._data(dest,oldData),events=oldData.events;if(events){delete curData.handle;curData.events={};for(type in events){for(i=0,l=events[type].length;i<l;i++){jQuery.event.add(dest,type,events[type][i])}}}if(curData.data){curData.data=jQuery.extend({},curData.data)}}function cloneFixAttributes(src,dest){var nodeName;if(dest.nodeType!==1){return}if(dest.clearAttributes){dest.clearAttributes()}if(dest.mergeAttributes){dest.mergeAttributes(src)}nodeName=dest.nodeName.toLowerCase();if(nodeName==="object"){if(dest.parentNode){dest.outerHTML=src.outerHTML}if(jQuery.support.html5Clone&&(src.innerHTML&&!jQuery.trim(dest.innerHTML))){dest.innerHTML=src.innerHTML}}else if(nodeName==="input"&&rcheckableType.test(src.type)){dest.defaultChecked=dest.checked=src.checked;if(dest.value!==src.value){dest.value=src.value}}else if(nodeName==="option"){dest.selected=src.defaultSelected}else if(nodeName==="input"||nodeName==="textarea"){dest.defaultValue=src.defaultValue}else if(nodeName==="script"&&dest.text!==src.text){dest.text=src.text}dest.removeAttribute(jQuery.expando)}jQuery.buildFragment=function(args,context,scripts){var fragment,cacheable,cachehit,first=args[0];context=context||document;context=!context.nodeType&&context[0]||context;context=context.ownerDocument||context;if(args.length===1&&typeof first==="string"&&first.length<512&&context===document&&first.charAt(0)==="<"&&!rnocache.test(first)&&(jQuery.support.checkClone||!rchecked.test(first))&&(jQuery.support.html5Clone||!rnoshimcache.test(first))){cacheable=true;fragment=jQuery.fragments[first];cachehit=fragment!==undefined}if(!fragment){fragment=context.createDocumentFragment();jQuery.clean(args,context,fragment,scripts);if(cacheable){jQuery.fragments[first]=cachehit&&fragment}}return{fragment:fragment,cacheable:cacheable}};jQuery.fragments={};jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(selector){var elems,i=0,ret=[],insert=jQuery(selector),l=insert.length,parent=this.length===1&&this[0].parentNode;if((parent==null||parent&&parent.nodeType===11&&parent.childNodes.length===1)&&l===1){insert[original](this[0]);return this}else{for(;i<l;i++){elems=(i>0?this.clone(true):this).get();jQuery(insert[i])[original](elems);ret=ret.concat(elems)}return this.pushStack(ret,name,insert.selector)}}});function getAll(elem){if(typeof elem.getElementsByTagName!=="undefined"){return elem.getElementsByTagName("*")}else if(typeof elem.querySelectorAll!=="undefined"){return elem.querySelectorAll("*")}else{return[]}}function fixDefaultChecked(elem){if(rcheckableType.test(elem.type)){elem.defaultChecked=elem.checked}}jQuery.extend({clone:function(elem,dataAndEvents,deepDataAndEvents){var srcElements,destElements,i,clone;if(jQuery.support.html5Clone||jQuery.isXMLDoc(elem)||!rnoshimcache.test("<"+elem.nodeName+">")){clone=elem.cloneNode(true)}else{fragmentDiv.innerHTML=elem.outerHTML;fragmentDiv.removeChild(clone=fragmentDiv.firstChild)}if((!jQuery.support.noCloneEvent||!jQuery.support.noCloneChecked)&&(elem.nodeType===1||elem.nodeType===11)&&!jQuery.isXMLDoc(elem)){cloneFixAttributes(elem,clone);srcElements=getAll(elem);destElements=getAll(clone);for(i=0;srcElements[i];++i){if(destElements[i]){cloneFixAttributes(srcElements[i],destElements[i])}}}if(dataAndEvents){cloneCopyEvent(elem,clone);if(deepDataAndEvents){srcElements=getAll(elem);destElements=getAll(clone);for(i=0;srcElements[i];++i){cloneCopyEvent(srcElements[i],destElements[i])}}}srcElements=destElements=null;return clone},clean:function(elems,context,fragment,scripts){var i,j,elem,tag,wrap,depth,div,hasBody,tbody,len,handleScript,jsTags,safe=context===document&&safeFragment,ret=[];if(!context||typeof context.createDocumentFragment==="undefined"){context=document}for(i=0;(elem=elems[i])!=null;i++){if(typeof elem==="number"){elem+=""}if(!elem){continue}if(typeof elem==="string"){if(!rhtml.test(elem)){elem=context.createTextNode(elem)}else{safe=safe||createSafeFragment(context);div=context.createElement("div");safe.appendChild(div);elem=elem.replace(rxhtmlTag,"<$1></$2>");tag=(rtagName.exec(elem)||["",""])[1].toLowerCase();wrap=wrapMap[tag]||wrapMap._default;depth=wrap[0];div.innerHTML=wrap[1]+elem+wrap[2];while(depth--){div=div.lastChild
+}if(!jQuery.support.tbody){hasBody=rtbody.test(elem);tbody=tag==="table"&&!hasBody?div.firstChild&&div.firstChild.childNodes:wrap[1]==="<table>"&&!hasBody?div.childNodes:[];for(j=tbody.length-1;j>=0;--j){if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length){tbody[j].parentNode.removeChild(tbody[j])}}}if(!jQuery.support.leadingWhitespace&&rleadingWhitespace.test(elem)){div.insertBefore(context.createTextNode(rleadingWhitespace.exec(elem)[0]),div.firstChild)}elem=div.childNodes;div.parentNode.removeChild(div)}}if(elem.nodeType){ret.push(elem)}else{jQuery.merge(ret,elem)}}if(div){elem=div=safe=null}if(!jQuery.support.appendChecked){for(i=0;(elem=ret[i])!=null;i++){if(jQuery.nodeName(elem,"input")){fixDefaultChecked(elem)}else if(typeof elem.getElementsByTagName!=="undefined"){jQuery.grep(elem.getElementsByTagName("input"),fixDefaultChecked)}}}if(fragment){handleScript=function(elem){if(!elem.type||rscriptType.test(elem.type)){return scripts?scripts.push(elem.parentNode?elem.parentNode.removeChild(elem):elem):fragment.appendChild(elem)}};for(i=0;(elem=ret[i])!=null;i++){if(!(jQuery.nodeName(elem,"script")&&handleScript(elem))){fragment.appendChild(elem);if(typeof elem.getElementsByTagName!=="undefined"){jsTags=jQuery.grep(jQuery.merge([],elem.getElementsByTagName("script")),handleScript);ret.splice.apply(ret,[i+1,0].concat(jsTags));i+=jsTags.length}}}}return ret},cleanData:function(elems,acceptData){var data,id,elem,type,i=0,internalKey=jQuery.expando,cache=jQuery.cache,deleteExpando=jQuery.support.deleteExpando,special=jQuery.event.special;for(;(elem=elems[i])!=null;i++){if(acceptData||jQuery.acceptData(elem)){id=elem[internalKey];data=id&&cache[id];if(data){if(data.events){for(type in data.events){if(special[type]){jQuery.event.remove(elem,type)}else{jQuery.removeEvent(elem,type,data.handle)}}}if(cache[id]){delete cache[id];if(deleteExpando){delete elem[internalKey]}else if(elem.removeAttribute){elem.removeAttribute(internalKey)}else{elem[internalKey]=null}jQuery.deletedIds.push(id)}}}}}});(function(){var matched,browser;jQuery.uaMatch=function(ua){ua=ua.toLowerCase();var match=/(chrome)[ \/]([\w.]+)/.exec(ua)||/(webkit)[ \/]([\w.]+)/.exec(ua)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua)||/(msie) ([\w.]+)/.exec(ua)||ua.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua)||[];return{browser:match[1]||"",version:match[2]||"0"}};matched=jQuery.uaMatch(navigator.userAgent);browser={};if(matched.browser){browser[matched.browser]=true;browser.version=matched.version}if(browser.chrome){browser.webkit=true}else if(browser.webkit){browser.safari=true}jQuery.browser=browser;jQuery.sub=function(){function jQuerySub(selector,context){return new jQuerySub.fn.init(selector,context)}jQuery.extend(true,jQuerySub,this);jQuerySub.superclass=this;jQuerySub.fn=jQuerySub.prototype=this();jQuerySub.fn.constructor=jQuerySub;jQuerySub.sub=this.sub;jQuerySub.fn.init=function init(selector,context){if(context&&context instanceof jQuery&&!(context instanceof jQuerySub)){context=jQuerySub(context)}return jQuery.fn.init.call(this,selector,context,rootjQuerySub)};jQuerySub.fn.init.prototype=jQuerySub.fn;var rootjQuerySub=jQuerySub(document);return jQuerySub}})();var curCSS,iframe,iframeDoc,ralpha=/alpha\([^)]*\)/i,ropacity=/opacity=([^)]*)/,rposition=/^(top|right|bottom|left)$/,rdisplayswap=/^(none|table(?!-c[ea]).+)/,rmargin=/^margin/,rnumsplit=new RegExp("^("+core_pnum+")(.*)$","i"),rnumnonpx=new RegExp("^("+core_pnum+")(?!px)[a-z%]+$","i"),rrelNum=new RegExp("^([-+])=("+core_pnum+")","i"),elemdisplay={BODY:"block"},cssShow={position:"absolute",visibility:"hidden",display:"block"},cssNormalTransform={letterSpacing:0,fontWeight:400},cssExpand=["Top","Right","Bottom","Left"],cssPrefixes=["Webkit","O","Moz","ms"],eventsToggle=jQuery.fn.toggle;function vendorPropName(style,name){if(name in style){return name}var capName=name.charAt(0).toUpperCase()+name.slice(1),origName=name,i=cssPrefixes.length;while(i--){name=cssPrefixes[i]+capName;if(name in style){return name}}return origName}function isHidden(elem,el){elem=el||elem;return jQuery.css(elem,"display")==="none"||!jQuery.contains(elem.ownerDocument,elem)}function showHide(elements,show){var elem,display,values=[],index=0,length=elements.length;for(;index<length;index++){elem=elements[index];if(!elem.style){continue}values[index]=jQuery._data(elem,"olddisplay");if(show){if(!values[index]&&elem.style.display==="none"){elem.style.display=""}if(elem.style.display===""&&isHidden(elem)){values[index]=jQuery._data(elem,"olddisplay",css_defaultDisplay(elem.nodeName))}}else{display=curCSS(elem,"display");if(!values[index]&&display!=="none"){jQuery._data(elem,"olddisplay",display)}}}for(index=0;index<length;index++){elem=elements[index];if(!elem.style){continue}if(!show||elem.style.display==="none"||elem.style.display===""){elem.style.display=show?values[index]||"":"none"}}return elements}jQuery.fn.extend({css:function(name,value){return jQuery.access(this,function(elem,name,value){return value!==undefined?jQuery.style(elem,name,value):jQuery.css(elem,name)},name,value,arguments.length>1)},show:function(){return showHide(this,true)},hide:function(){return showHide(this)},toggle:function(state,fn2){var bool=typeof state==="boolean";if(jQuery.isFunction(state)&&jQuery.isFunction(fn2)){return eventsToggle.apply(this,arguments)}return this.each(function(){if(bool?state:isHidden(this)){jQuery(this).show()}else{jQuery(this).hide()}})}});jQuery.extend({cssHooks:{opacity:{get:function(elem,computed){if(computed){var ret=curCSS(elem,"opacity");return ret===""?"1":ret}}}},cssNumber:{fillOpacity:true,fontWeight:true,lineHeight:true,opacity:true,orphans:true,widows:true,zIndex:true,zoom:true},cssProps:{"float":jQuery.support.cssFloat?"cssFloat":"styleFloat"},style:function(elem,name,value,extra){if(!elem||elem.nodeType===3||elem.nodeType===8||!elem.style){return}var ret,type,hooks,origName=jQuery.camelCase(name),style=elem.style;name=jQuery.cssProps[origName]||(jQuery.cssProps[origName]=vendorPropName(style,origName));hooks=jQuery.cssHooks[name]||jQuery.cssHooks[origName];if(value!==undefined){type=typeof value;if(type==="string"&&(ret=rrelNum.exec(value))){value=(ret[1]+1)*ret[2]+parseFloat(jQuery.css(elem,name));type="number"}if(value==null||type==="number"&&isNaN(value)){return}if(type==="number"&&!jQuery.cssNumber[origName]){value+="px"}if(!hooks||!("set"in hooks)||(value=hooks.set(elem,value,extra))!==undefined){try{style[name]=value}catch(e){}}}else{if(hooks&&"get"in hooks&&(ret=hooks.get(elem,false,extra))!==undefined){return ret}return style[name]}},css:function(elem,name,numeric,extra){var val,num,hooks,origName=jQuery.camelCase(name);name=jQuery.cssProps[origName]||(jQuery.cssProps[origName]=vendorPropName(elem.style,origName));hooks=jQuery.cssHooks[name]||jQuery.cssHooks[origName];if(hooks&&"get"in hooks){val=hooks.get(elem,true,extra)}if(val===undefined){val=curCSS(elem,name)}if(val==="normal"&&name in cssNormalTransform){val=cssNormalTransform[name]}if(numeric||extra!==undefined){num=parseFloat(val);return numeric||jQuery.isNumeric(num)?num||0:val}return val},swap:function(elem,options,callback){var ret,name,old={};for(name in options){old[name]=elem.style[name];elem.style[name]=options[name]}ret=callback.call(elem);for(name in options){elem.style[name]=old[name]}return ret}});if(window.getComputedStyle){curCSS=function(elem,name){var ret,width,minWidth,maxWidth,computed=window.getComputedStyle(elem,null),style=elem.style;if(computed){ret=computed.getPropertyValue(name)||computed[name];if(ret===""&&!jQuery.contains(elem.ownerDocument,elem)){ret=jQuery.style(elem,name)}if(rnumnonpx.test(ret)&&rmargin.test(name)){width=style.width;minWidth=style.minWidth;maxWidth=style.maxWidth;style.minWidth=style.maxWidth=style.width=ret;ret=computed.width;style.width=width;style.minWidth=minWidth;style.maxWidth=maxWidth}}return ret}}else if(document.documentElement.currentStyle){curCSS=function(elem,name){var left,rsLeft,ret=elem.currentStyle&&elem.currentStyle[name],style=elem.style;if(ret==null&&style&&style[name]){ret=style[name]}if(rnumnonpx.test(ret)&&!rposition.test(name)){left=style.left;rsLeft=elem.runtimeStyle&&elem.runtimeStyle.left;if(rsLeft){elem.runtimeStyle.left=elem.currentStyle.left}style.left=name==="fontSize"?"1em":ret;ret=style.pixelLeft+"px";style.left=left;if(rsLeft){elem.runtimeStyle.left=rsLeft}}return ret===""?"auto":ret}}function setPositiveNumber(elem,value,subtract){var matches=rnumsplit.exec(value);return matches?Math.max(0,matches[1]-(subtract||0))+(matches[2]||"px"):value}function augmentWidthOrHeight(elem,name,extra,isBorderBox){var i=extra===(isBorderBox?"border":"content")?4:name==="width"?1:0,val=0;for(;i<4;i+=2){if(extra==="margin"){val+=jQuery.css(elem,extra+cssExpand[i],true)}if(isBorderBox){if(extra==="content"){val-=parseFloat(curCSS(elem,"padding"+cssExpand[i]))||0}if(extra!=="margin"){val-=parseFloat(curCSS(elem,"border"+cssExpand[i]+"Width"))||0}}else{val+=parseFloat(curCSS(elem,"padding"+cssExpand[i]))||0;if(extra!=="padding"){val+=parseFloat(curCSS(elem,"border"+cssExpand[i]+"Width"))||0}}}return val}function getWidthOrHeight(elem,name,extra){var val=name==="width"?elem.offsetWidth:elem.offsetHeight,valueIsBorderBox=true,isBorderBox=jQuery.support.boxSizing&&jQuery.css(elem,"boxSizing")==="border-box";if(val<=0||val==null){val=curCSS(elem,name);if(val<0||val==null){val=elem.style[name]}if(rnumnonpx.test(val)){return val}valueIsBorderBox=isBorderBox&&(jQuery.support.boxSizingReliable||val===elem.style[name]);val=parseFloat(val)||0}return val+augmentWidthOrHeight(elem,name,extra||(isBorderBox?"border":"content"),valueIsBorderBox)+"px"}function css_defaultDisplay(nodeName){if(elemdisplay[nodeName]){return elemdisplay[nodeName]}var elem=jQuery("<"+nodeName+">").appendTo(document.body),display=elem.css("display");elem.remove();if(display==="none"||display===""){iframe=document.body.appendChild(iframe||jQuery.extend(document.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!iframeDoc||!iframe.createElement){iframeDoc=(iframe.contentWindow||iframe.contentDocument).document;iframeDoc.write("<!doctype html><html><body>");iframeDoc.close()}elem=iframeDoc.body.appendChild(iframeDoc.createElement(nodeName));display=curCSS(elem,"display");document.body.removeChild(iframe)}elemdisplay[nodeName]=display;return display}jQuery.each(["height","width"],function(i,name){jQuery.cssHooks[name]={get:function(elem,computed,extra){if(computed){if(elem.offsetWidth===0&&rdisplayswap.test(curCSS(elem,"display"))){return jQuery.swap(elem,cssShow,function(){return getWidthOrHeight(elem,name,extra)})}else{return getWidthOrHeight(elem,name,extra)}}},set:function(elem,value,extra){return setPositiveNumber(elem,value,extra?augmentWidthOrHeight(elem,name,extra,jQuery.support.boxSizing&&jQuery.css(elem,"boxSizing")==="border-box"):0)}}});if(!jQuery.support.opacity){jQuery.cssHooks.opacity={get:function(elem,computed){return ropacity.test((computed&&elem.currentStyle?elem.currentStyle.filter:elem.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":computed?"1":""},set:function(elem,value){var style=elem.style,currentStyle=elem.currentStyle,opacity=jQuery.isNumeric(value)?"alpha(opacity="+value*100+")":"",filter=currentStyle&&currentStyle.filter||style.filter||"";style.zoom=1;if(value>=1&&jQuery.trim(filter.replace(ralpha,""))===""&&style.removeAttribute){style.removeAttribute("filter");if(currentStyle&&!currentStyle.filter){return}}style.filter=ralpha.test(filter)?filter.replace(ralpha,opacity):filter+" "+opacity}}}jQuery(function(){if(!jQuery.support.reliableMarginRight){jQuery.cssHooks.marginRight={get:function(elem,computed){return jQuery.swap(elem,{display:"inline-block"},function(){if(computed){return curCSS(elem,"marginRight")}})}}}if(!jQuery.support.pixelPosition&&jQuery.fn.position){jQuery.each(["top","left"],function(i,prop){jQuery.cssHooks[prop]={get:function(elem,computed){if(computed){var ret=curCSS(elem,prop);return rnumnonpx.test(ret)?jQuery(elem).position()[prop]+"px":ret}}}})}});if(jQuery.expr&&jQuery.expr.filters){jQuery.expr.filters.hidden=function(elem){return elem.offsetWidth===0&&elem.offsetHeight===0||!jQuery.support.reliableHiddenOffsets&&(elem.style&&elem.style.display||curCSS(elem,"display"))==="none"};jQuery.expr.filters.visible=function(elem){return!jQuery.expr.filters.hidden(elem)}}jQuery.each({margin:"",padding:"",border:"Width"},function(prefix,suffix){jQuery.cssHooks[prefix+suffix]={expand:function(value){var i,parts=typeof value==="string"?value.split(" "):[value],expanded={};for(i=0;i<4;i++){expanded[prefix+cssExpand[i]+suffix]=parts[i]||parts[i-2]||parts[0]}return expanded}};if(!rmargin.test(prefix)){jQuery.cssHooks[prefix+suffix].set=setPositiveNumber}});var r20=/%20/g,rbracket=/\[\]$/,rCRLF=/\r?\n/g,rinput=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,rselectTextarea=/^(?:select|textarea)/i;jQuery.fn.extend({serialize:function(){return jQuery.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?jQuery.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||rselectTextarea.test(this.nodeName)||rinput.test(this.type))}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:jQuery.isArray(val)?jQuery.map(val,function(val,i){return{name:elem.name,value:val.replace(rCRLF,"\r\n")}}):{name:elem.name,value:val.replace(rCRLF,"\r\n")}}).get()}});jQuery.param=function(a,traditional){var prefix,s=[],add=function(key,value){value=jQuery.isFunction(value)?value():value==null?"":value;s[s.length]=encodeURIComponent(key)+"="+encodeURIComponent(value)};if(traditional===undefined){traditional=jQuery.ajaxSettings&&jQuery.ajaxSettings.traditional}if(jQuery.isArray(a)||a.jquery&&!jQuery.isPlainObject(a)){jQuery.each(a,function(){add(this.name,this.value)})}else{for(prefix in a){buildParams(prefix,a[prefix],traditional,add)}}return s.join("&").replace(r20,"+")};function buildParams(prefix,obj,traditional,add){var name;if(jQuery.isArray(obj)){jQuery.each(obj,function(i,v){if(traditional||rbracket.test(prefix)){add(prefix,v)}else{buildParams(prefix+"["+(typeof v==="object"?i:"")+"]",v,traditional,add)}})}else if(!traditional&&jQuery.type(obj)==="object"){for(name in obj){buildParams(prefix+"["+name+"]",obj[name],traditional,add)}}else{add(prefix,obj)}}var ajaxLocParts,ajaxLocation,rhash=/#.*$/,rheaders=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,rlocalProtocol=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,rnoContent=/^(?:GET|HEAD)$/,rprotocol=/^\/\//,rquery=/\?/,rscript=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,rts=/([?&])_=[^&]*/,rurl=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,_load=jQuery.fn.load,prefilters={},transports={},allTypes=["*/"]+["*"];try{ajaxLocation=location.href}catch(e){ajaxLocation=document.createElement("a");ajaxLocation.href="";ajaxLocation=ajaxLocation.href}ajaxLocParts=rurl.exec(ajaxLocation.toLowerCase())||[];function addToPrefiltersOrTransports(structure){return function(dataTypeExpression,func){if(typeof dataTypeExpression!=="string"){func=dataTypeExpression;dataTypeExpression="*"}var dataType,list,placeBefore,dataTypes=dataTypeExpression.toLowerCase().split(core_rspace),i=0,length=dataTypes.length;if(jQuery.isFunction(func)){for(;i<length;i++){dataType=dataTypes[i];placeBefore=/^\+/.test(dataType);if(placeBefore){dataType=dataType.substr(1)||"*"}list=structure[dataType]=structure[dataType]||[];list[placeBefore?"unshift":"push"](func)}}}}function inspectPrefiltersOrTransports(structure,options,originalOptions,jqXHR,dataType,inspected){dataType=dataType||options.dataTypes[0];inspected=inspected||{};inspected[dataType]=true;var selection,list=structure[dataType],i=0,length=list?list.length:0,executeOnly=structure===prefilters;for(;i<length&&(executeOnly||!selection);i++){selection=list[i](options,originalOptions,jqXHR);if(typeof selection==="string"){if(!executeOnly||inspected[selection]){selection=undefined}else{options.dataTypes.unshift(selection);selection=inspectPrefiltersOrTransports(structure,options,originalOptions,jqXHR,selection,inspected)}}}if((executeOnly||!selection)&&!inspected["*"]){selection=inspectPrefiltersOrTransports(structure,options,originalOptions,jqXHR,"*",inspected)}return selection}function ajaxExtend(target,src){var key,deep,flatOptions=jQuery.ajaxSettings.flatOptions||{};for(key in src){if(src[key]!==undefined){(flatOptions[key]?target:deep||(deep={}))[key]=src[key]}}if(deep){jQuery.extend(true,target,deep)}}jQuery.fn.load=function(url,params,callback){if(typeof url!=="string"&&_load){return _load.apply(this,arguments)}if(!this.length){return this}var selector,type,response,self=this,off=url.indexOf(" ");if(off>=0){selector=url.slice(off,url.length);url=url.slice(0,off)}if(jQuery.isFunction(params)){callback=params;params=undefined}else if(params&&typeof params==="object"){type="POST"}jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(jqXHR,status){if(callback){self.each(callback,response||[jqXHR.responseText,status,jqXHR])}}}).done(function(responseText){response=arguments;self.html(selector?jQuery("<div>").append(responseText.replace(rscript,"")).find(selector):responseText)});return this};jQuery.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(i,o){jQuery.fn[o]=function(f){return this.on(o,f)}});jQuery.each(["get","post"],function(i,method){jQuery[method]=function(url,data,callback,type){if(jQuery.isFunction(data)){type=type||callback;callback=data;data=undefined}return jQuery.ajax({type:method,url:url,data:data,success:callback,dataType:type})}});jQuery.extend({getScript:function(url,callback){return jQuery.get(url,undefined,callback,"script")},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json")},ajaxSetup:function(target,settings){if(settings){ajaxExtend(target,jQuery.ajaxSettings)}else{settings=target;target=jQuery.ajaxSettings}ajaxExtend(target,settings);return target},ajaxSettings:{url:ajaxLocation,isLocal:rlocalProtocol.test(ajaxLocParts[1]),global:true,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:true,async:true,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":allTypes},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":window.String,"text html":true,"text json":jQuery.parseJSON,"text xml":jQuery.parseXML},flatOptions:{context:true,url:true}},ajaxPrefilter:addToPrefiltersOrTransports(prefilters),ajaxTransport:addToPrefiltersOrTransports(transports),ajax:function(url,options){if(typeof url==="object"){options=url;url=undefined}options=options||{};var ifModifiedKey,responseHeadersString,responseHeaders,transport,timeoutTimer,parts,fireGlobals,i,s=jQuery.ajaxSetup({},options),callbackContext=s.context||s,globalEventContext=callbackContext!==s&&(callbackContext.nodeType||callbackContext instanceof jQuery)?jQuery(callbackContext):jQuery.event,deferred=jQuery.Deferred(),completeDeferred=jQuery.Callbacks("once memory"),statusCode=s.statusCode||{},requestHeaders={},requestHeadersNames={},state=0,strAbort="canceled",jqXHR={readyState:0,setRequestHeader:function(name,value){if(!state){var lname=name.toLowerCase();name=requestHeadersNames[lname]=requestHeadersNames[lname]||name;requestHeaders[name]=value}return this},getAllResponseHeaders:function(){return state===2?responseHeadersString:null},getResponseHeader:function(key){var match;if(state===2){if(!responseHeaders){responseHeaders={};while(match=rheaders.exec(responseHeadersString)){responseHeaders[match[1].toLowerCase()]=match[2]}}match=responseHeaders[key.toLowerCase()]}return match===undefined?null:match},overrideMimeType:function(type){if(!state){s.mimeType=type}return this},abort:function(statusText){statusText=statusText||strAbort;if(transport){transport.abort(statusText)}done(0,statusText);return this}};function done(status,nativeStatusText,responses,headers){var isSuccess,success,error,response,modified,statusText=nativeStatusText;if(state===2){return}state=2;if(timeoutTimer){clearTimeout(timeoutTimer)}transport=undefined;responseHeadersString=headers||"";jqXHR.readyState=status>0?4:0;if(responses){response=ajaxHandleResponses(s,jqXHR,responses)}if(status>=200&&status<300||status===304){if(s.ifModified){modified=jqXHR.getResponseHeader("Last-Modified");if(modified){jQuery.lastModified[ifModifiedKey]=modified}modified=jqXHR.getResponseHeader("Etag");if(modified){jQuery.etag[ifModifiedKey]=modified}}if(status===304){statusText="notmodified";isSuccess=true}else{isSuccess=ajaxConvert(s,response);statusText=isSuccess.state;success=isSuccess.data;error=isSuccess.error;isSuccess=!error}}else{error=statusText;if(!statusText||status){statusText="error";if(status<0){status=0}}}jqXHR.status=status;jqXHR.statusText=(nativeStatusText||statusText)+"";if(isSuccess){deferred.resolveWith(callbackContext,[success,statusText,jqXHR])}else{deferred.rejectWith(callbackContext,[jqXHR,statusText,error])}jqXHR.statusCode(statusCode);statusCode=undefined;if(fireGlobals){globalEventContext.trigger("ajax"+(isSuccess?"Success":"Error"),[jqXHR,s,isSuccess?success:error])}completeDeferred.fireWith(callbackContext,[jqXHR,statusText]);if(fireGlobals){globalEventContext.trigger("ajaxComplete",[jqXHR,s]);if(!--jQuery.active){jQuery.event.trigger("ajaxStop")}}}deferred.promise(jqXHR);jqXHR.success=jqXHR.done;jqXHR.error=jqXHR.fail;jqXHR.complete=completeDeferred.add;jqXHR.statusCode=function(map){if(map){var tmp;if(state<2){for(tmp in map){statusCode[tmp]=[statusCode[tmp],map[tmp]]}}else{tmp=map[jqXHR.status];jqXHR.always(tmp)}}return this};s.url=((url||s.url)+"").replace(rhash,"").replace(rprotocol,ajaxLocParts[1]+"//");s.dataTypes=jQuery.trim(s.dataType||"*").toLowerCase().split(core_rspace);if(s.crossDomain==null){parts=rurl.exec(s.url.toLowerCase());s.crossDomain=!!(parts&&(parts[1]!==ajaxLocParts[1]||parts[2]!==ajaxLocParts[2]||(parts[3]||(parts[1]==="http:"?80:443))!=(ajaxLocParts[3]||(ajaxLocParts[1]==="http:"?80:443))))}if(s.data&&s.processData&&typeof s.data!=="string"){s.data=jQuery.param(s.data,s.traditional)}inspectPrefiltersOrTransports(prefilters,s,options,jqXHR);if(state===2){return jqXHR}fireGlobals=s.global;s.type=s.type.toUpperCase();s.hasContent=!rnoContent.test(s.type);if(fireGlobals&&jQuery.active++===0){jQuery.event.trigger("ajaxStart")}if(!s.hasContent){if(s.data){s.url+=(rquery.test(s.url)?"&":"?")+s.data;delete s.data}ifModifiedKey=s.url;if(s.cache===false){var ts=jQuery.now(),ret=s.url.replace(rts,"$1_="+ts);s.url=ret+(ret===s.url?(rquery.test(s.url)?"&":"?")+"_="+ts:"")}}if(s.data&&s.hasContent&&s.contentType!==false||options.contentType){jqXHR.setRequestHeader("Content-Type",s.contentType)}if(s.ifModified){ifModifiedKey=ifModifiedKey||s.url;if(jQuery.lastModified[ifModifiedKey]){jqXHR.setRequestHeader("If-Modified-Since",jQuery.lastModified[ifModifiedKey])}if(jQuery.etag[ifModifiedKey]){jqXHR.setRequestHeader("If-None-Match",jQuery.etag[ifModifiedKey])}}jqXHR.setRequestHeader("Accept",s.dataTypes[0]&&s.accepts[s.dataTypes[0]]?s.accepts[s.dataTypes[0]]+(s.dataTypes[0]!=="*"?", "+allTypes+"; q=0.01":""):s.accepts["*"]);for(i in s.headers){jqXHR.setRequestHeader(i,s.headers[i])}if(s.beforeSend&&(s.beforeSend.call(callbackContext,jqXHR,s)===false||state===2)){return jqXHR.abort()}strAbort="abort";for(i in{success:1,error:1,complete:1}){jqXHR[i](s[i])}transport=inspectPrefiltersOrTransports(transports,s,options,jqXHR);if(!transport){done(-1,"No Transport")}else{jqXHR.readyState=1;if(fireGlobals){globalEventContext.trigger("ajaxSend",[jqXHR,s])}if(s.async&&s.timeout>0){timeoutTimer=setTimeout(function(){jqXHR.abort("timeout")},s.timeout)}try{state=1;transport.send(requestHeaders,done)}catch(e){if(state<2){done(-1,e)}else{throw e}}}return jqXHR},active:0,lastModified:{},etag:{}});function ajaxHandleResponses(s,jqXHR,responses){var ct,type,finalDataType,firstDataType,contents=s.contents,dataTypes=s.dataTypes,responseFields=s.responseFields;for(type in responseFields){if(type in responses){jqXHR[responseFields[type]]=responses[type]}}while(dataTypes[0]==="*"){dataTypes.shift();if(ct===undefined){ct=s.mimeType||jqXHR.getResponseHeader("content-type")}}if(ct){for(type in contents){if(contents[type]&&contents[type].test(ct)){dataTypes.unshift(type);break}}}if(dataTypes[0]in responses){finalDataType=dataTypes[0]}else{for(type in responses){if(!dataTypes[0]||s.converters[type+" "+dataTypes[0]]){finalDataType=type;break}if(!firstDataType){firstDataType=type}}finalDataType=finalDataType||firstDataType}if(finalDataType){if(finalDataType!==dataTypes[0]){dataTypes.unshift(finalDataType)}return responses[finalDataType]}}function ajaxConvert(s,response){var conv,conv2,current,tmp,dataTypes=s.dataTypes.slice(),prev=dataTypes[0],converters={},i=0;if(s.dataFilter){response=s.dataFilter(response,s.dataType)}if(dataTypes[1]){for(conv in s.converters){converters[conv.toLowerCase()]=s.converters[conv]}}for(;current=dataTypes[++i];){if(current!=="*"){if(prev!=="*"&&prev!==current){conv=converters[prev+" "+current]||converters["* "+current];if(!conv){for(conv2 in converters){tmp=conv2.split(" ");if(tmp[1]===current){conv=converters[prev+" "+tmp[0]]||converters["* "+tmp[0]];if(conv){if(conv===true){conv=converters[conv2]}else if(converters[conv2]!==true){current=tmp[0];dataTypes.splice(i--,0,current)}break}}}}if(conv!==true){if(conv&&s["throws"]){response=conv(response)}else{try{response=conv(response)}catch(e){return{state:"parsererror",error:conv?e:"No conversion from "+prev+" to "+current}}}}}prev=current}}return{state:"success",data:response}}var oldCallbacks=[],rquestion=/\?/,rjsonp=/(=)\?(?=&|$)|\?\?/,nonce=jQuery.now();jQuery.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var callback=oldCallbacks.pop()||jQuery.expando+"_"+nonce++;this[callback]=true;return callback}});jQuery.ajaxPrefilter("json jsonp",function(s,originalSettings,jqXHR){var callbackName,overwritten,responseContainer,data=s.data,url=s.url,hasCallback=s.jsonp!==false,replaceInUrl=hasCallback&&rjsonp.test(url),replaceInData=hasCallback&&!replaceInUrl&&typeof data==="string"&&!(s.contentType||"").indexOf("application/x-www-form-urlencoded")&&rjsonp.test(data);if(s.dataTypes[0]==="jsonp"||replaceInUrl||replaceInData){callbackName=s.jsonpCallback=jQuery.isFunction(s.jsonpCallback)?s.jsonpCallback():s.jsonpCallback;overwritten=window[callbackName];if(replaceInUrl){s.url=url.replace(rjsonp,"$1"+callbackName)}else if(replaceInData){s.data=data.replace(rjsonp,"$1"+callbackName)}else if(hasCallback){s.url+=(rquestion.test(url)?"&":"?")+s.jsonp+"="+callbackName}s.converters["script json"]=function(){if(!responseContainer){jQuery.error(callbackName+" was not called")}return responseContainer[0]};s.dataTypes[0]="json";window[callbackName]=function(){responseContainer=arguments};jqXHR.always(function(){window[callbackName]=overwritten;if(s[callbackName]){s.jsonpCallback=originalSettings.jsonpCallback;oldCallbacks.push(callbackName)}if(responseContainer&&jQuery.isFunction(overwritten)){overwritten(responseContainer[0])}responseContainer=overwritten=undefined});return"script"}});jQuery.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(text){jQuery.globalEval(text);return text}}});jQuery.ajaxPrefilter("script",function(s){if(s.cache===undefined){s.cache=false}if(s.crossDomain){s.type="GET";s.global=false}});jQuery.ajaxTransport("script",function(s){if(s.crossDomain){var script,head=document.head||document.getElementsByTagName("head")[0]||document.documentElement;return{send:function(_,callback){script=document.createElement("script");script.async="async";if(s.scriptCharset){script.charset=s.scriptCharset}script.src=s.url;script.onload=script.onreadystatechange=function(_,isAbort){if(isAbort||!script.readyState||/loaded|complete/.test(script.readyState)){script.onload=script.onreadystatechange=null;if(head&&script.parentNode){head.removeChild(script)}script=undefined;if(!isAbort){callback(200,"success")}}};head.insertBefore(script,head.firstChild)},abort:function(){if(script){script.onload(0,1)}}}}});var xhrCallbacks,xhrOnUnloadAbort=window.ActiveXObject?function(){for(var key in xhrCallbacks){xhrCallbacks[key](0,1)}}:false,xhrId=0;function createStandardXHR(){try{return new window.XMLHttpRequest}catch(e){}}function createActiveXHR(){try{return new window.ActiveXObject("Microsoft.XMLHTTP")}catch(e){}}jQuery.ajaxSettings.xhr=window.ActiveXObject?function(){return!this.isLocal&&createStandardXHR()||createActiveXHR()}:createStandardXHR;(function(xhr){jQuery.extend(jQuery.support,{ajax:!!xhr,cors:!!xhr&&"withCredentials"in xhr})})(jQuery.ajaxSettings.xhr());if(jQuery.support.ajax){jQuery.ajaxTransport(function(s){if(!s.crossDomain||jQuery.support.cors){var callback;return{send:function(headers,complete){var handle,i,xhr=s.xhr();if(s.username){xhr.open(s.type,s.url,s.async,s.username,s.password)}else{xhr.open(s.type,s.url,s.async)}if(s.xhrFields){for(i in s.xhrFields){xhr[i]=s.xhrFields[i]}}if(s.mimeType&&xhr.overrideMimeType){xhr.overrideMimeType(s.mimeType)}if(!s.crossDomain&&!headers["X-Requested-With"]){headers["X-Requested-With"]="XMLHttpRequest"}try{for(i in headers){xhr.setRequestHeader(i,headers[i])}}catch(_){}xhr.send(s.hasContent&&s.data||null);callback=function(_,isAbort){var status,statusText,responseHeaders,responses,xml;try{if(callback&&(isAbort||xhr.readyState===4)){callback=undefined;if(handle){xhr.onreadystatechange=jQuery.noop;if(xhrOnUnloadAbort){delete xhrCallbacks[handle]}}if(isAbort){if(xhr.readyState!==4){xhr.abort()}}else{status=xhr.status;responseHeaders=xhr.getAllResponseHeaders();responses={};xml=xhr.responseXML;if(xml&&xml.documentElement){responses.xml=xml}try{responses.text=xhr.responseText}catch(e){}try{statusText=xhr.statusText}catch(e){statusText=""}if(!status&&s.isLocal&&!s.crossDomain){status=responses.text?200:404}else if(status===1223){status=204}}}}catch(firefoxAccessException){if(!isAbort){complete(-1,firefoxAccessException)}}if(responses){complete(status,statusText,responses,responseHeaders)}};if(!s.async){callback()}else if(xhr.readyState===4){setTimeout(callback,0)}else{handle=++xhrId;if(xhrOnUnloadAbort){if(!xhrCallbacks){xhrCallbacks={};jQuery(window).unload(xhrOnUnloadAbort)}xhrCallbacks[handle]=callback}xhr.onreadystatechange=callback}},abort:function(){if(callback){callback(0,1)}}}}})}var fxNow,timerId,rfxtypes=/^(?:toggle|show|hide)$/,rfxnum=new RegExp("^(?:([-+])=|)("+core_pnum+")([a-z%]*)$","i"),rrun=/queueHooks$/,animationPrefilters=[defaultPrefilter],tweeners={"*":[function(prop,value){var end,unit,tween=this.createTween(prop,value),parts=rfxnum.exec(value),target=tween.cur(),start=+target||0,scale=1,maxIterations=20;if(parts){end=+parts[2];unit=parts[3]||(jQuery.cssNumber[prop]?"":"px");if(unit!=="px"&&start){start=jQuery.css(tween.elem,prop,true)||end||1;do{scale=scale||".5";start=start/scale;jQuery.style(tween.elem,prop,start+unit)}while(scale!==(scale=tween.cur()/target)&&scale!==1&&--maxIterations)}tween.unit=unit;tween.start=start;tween.end=parts[1]?start+(parts[1]+1)*end:end}return tween}]};function createFxNow(){setTimeout(function(){fxNow=undefined},0);return fxNow=jQuery.now()}function createTweens(animation,props){jQuery.each(props,function(prop,value){var collection=(tweeners[prop]||[]).concat(tweeners["*"]),index=0,length=collection.length;for(;index<length;index++){if(collection[index].call(animation,prop,value)){return}}})}function Animation(elem,properties,options){var result,index=0,tweenerIndex=0,length=animationPrefilters.length,deferred=jQuery.Deferred().always(function(){delete tick.elem}),tick=function(){var currentTime=fxNow||createFxNow(),remaining=Math.max(0,animation.startTime+animation.duration-currentTime),temp=remaining/animation.duration||0,percent=1-temp,index=0,length=animation.tweens.length;
+for(;index<length;index++){animation.tweens[index].run(percent)}deferred.notifyWith(elem,[animation,percent,remaining]);if(percent<1&&length){return remaining}else{deferred.resolveWith(elem,[animation]);return false}},animation=deferred.promise({elem:elem,props:jQuery.extend({},properties),opts:jQuery.extend(true,{specialEasing:{}},options),originalProperties:properties,originalOptions:options,startTime:fxNow||createFxNow(),duration:options.duration,tweens:[],createTween:function(prop,end,easing){var tween=jQuery.Tween(elem,animation.opts,prop,end,animation.opts.specialEasing[prop]||animation.opts.easing);animation.tweens.push(tween);return tween},stop:function(gotoEnd){var index=0,length=gotoEnd?animation.tweens.length:0;for(;index<length;index++){animation.tweens[index].run(1)}if(gotoEnd){deferred.resolveWith(elem,[animation,gotoEnd])}else{deferred.rejectWith(elem,[animation,gotoEnd])}return this}}),props=animation.props;propFilter(props,animation.opts.specialEasing);for(;index<length;index++){result=animationPrefilters[index].call(animation,elem,props,animation.opts);if(result){return result}}createTweens(animation,props);if(jQuery.isFunction(animation.opts.start)){animation.opts.start.call(elem,animation)}jQuery.fx.timer(jQuery.extend(tick,{anim:animation,queue:animation.opts.queue,elem:elem}));return animation.progress(animation.opts.progress).done(animation.opts.done,animation.opts.complete).fail(animation.opts.fail).always(animation.opts.always)}function propFilter(props,specialEasing){var index,name,easing,value,hooks;for(index in props){name=jQuery.camelCase(index);easing=specialEasing[name];value=props[index];if(jQuery.isArray(value)){easing=value[1];value=props[index]=value[0]}if(index!==name){props[name]=value;delete props[index]}hooks=jQuery.cssHooks[name];if(hooks&&"expand"in hooks){value=hooks.expand(value);delete props[name];for(index in value){if(!(index in props)){props[index]=value[index];specialEasing[index]=easing}}}else{specialEasing[name]=easing}}}jQuery.Animation=jQuery.extend(Animation,{tweener:function(props,callback){if(jQuery.isFunction(props)){callback=props;props=["*"]}else{props=props.split(" ")}var prop,index=0,length=props.length;for(;index<length;index++){prop=props[index];tweeners[prop]=tweeners[prop]||[];tweeners[prop].unshift(callback)}},prefilter:function(callback,prepend){if(prepend){animationPrefilters.unshift(callback)}else{animationPrefilters.push(callback)}}});function defaultPrefilter(elem,props,opts){var index,prop,value,length,dataShow,toggle,tween,hooks,oldfire,anim=this,style=elem.style,orig={},handled=[],hidden=elem.nodeType&&isHidden(elem);if(!opts.queue){hooks=jQuery._queueHooks(elem,"fx");if(hooks.unqueued==null){hooks.unqueued=0;oldfire=hooks.empty.fire;hooks.empty.fire=function(){if(!hooks.unqueued){oldfire()}}}hooks.unqueued++;anim.always(function(){anim.always(function(){hooks.unqueued--;if(!jQuery.queue(elem,"fx").length){hooks.empty.fire()}})})}if(elem.nodeType===1&&("height"in props||"width"in props)){opts.overflow=[style.overflow,style.overflowX,style.overflowY];if(jQuery.css(elem,"display")==="inline"&&jQuery.css(elem,"float")==="none"){if(!jQuery.support.inlineBlockNeedsLayout||css_defaultDisplay(elem.nodeName)==="inline"){style.display="inline-block"}else{style.zoom=1}}}if(opts.overflow){style.overflow="hidden";if(!jQuery.support.shrinkWrapBlocks){anim.done(function(){style.overflow=opts.overflow[0];style.overflowX=opts.overflow[1];style.overflowY=opts.overflow[2]})}}for(index in props){value=props[index];if(rfxtypes.exec(value)){delete props[index];toggle=toggle||value==="toggle";if(value===(hidden?"hide":"show")){continue}handled.push(index)}}length=handled.length;if(length){dataShow=jQuery._data(elem,"fxshow")||jQuery._data(elem,"fxshow",{});if("hidden"in dataShow){hidden=dataShow.hidden}if(toggle){dataShow.hidden=!hidden}if(hidden){jQuery(elem).show()}else{anim.done(function(){jQuery(elem).hide()})}anim.done(function(){var prop;jQuery.removeData(elem,"fxshow",true);for(prop in orig){jQuery.style(elem,prop,orig[prop])}});for(index=0;index<length;index++){prop=handled[index];tween=anim.createTween(prop,hidden?dataShow[prop]:0);orig[prop]=dataShow[prop]||jQuery.style(elem,prop);if(!(prop in dataShow)){dataShow[prop]=tween.start;if(hidden){tween.end=tween.start;tween.start=prop==="width"||prop==="height"?1:0}}}}}function Tween(elem,options,prop,end,easing){return new Tween.prototype.init(elem,options,prop,end,easing)}jQuery.Tween=Tween;Tween.prototype={constructor:Tween,init:function(elem,options,prop,end,easing,unit){this.elem=elem;this.prop=prop;this.easing=easing||"swing";this.options=options;this.start=this.now=this.cur();this.end=end;this.unit=unit||(jQuery.cssNumber[prop]?"":"px")},cur:function(){var hooks=Tween.propHooks[this.prop];return hooks&&hooks.get?hooks.get(this):Tween.propHooks._default.get(this)},run:function(percent){var eased,hooks=Tween.propHooks[this.prop];if(this.options.duration){this.pos=eased=jQuery.easing[this.easing](percent,this.options.duration*percent,0,1,this.options.duration)}else{this.pos=eased=percent}this.now=(this.end-this.start)*eased+this.start;if(this.options.step){this.options.step.call(this.elem,this.now,this)}if(hooks&&hooks.set){hooks.set(this)}else{Tween.propHooks._default.set(this)}return this}};Tween.prototype.init.prototype=Tween.prototype;Tween.propHooks={_default:{get:function(tween){var result;if(tween.elem[tween.prop]!=null&&(!tween.elem.style||tween.elem.style[tween.prop]==null)){return tween.elem[tween.prop]}result=jQuery.css(tween.elem,tween.prop,false,"");return!result||result==="auto"?0:result},set:function(tween){if(jQuery.fx.step[tween.prop]){jQuery.fx.step[tween.prop](tween)}else if(tween.elem.style&&(tween.elem.style[jQuery.cssProps[tween.prop]]!=null||jQuery.cssHooks[tween.prop])){jQuery.style(tween.elem,tween.prop,tween.now+tween.unit)}else{tween.elem[tween.prop]=tween.now}}}};Tween.propHooks.scrollTop=Tween.propHooks.scrollLeft={set:function(tween){if(tween.elem.nodeType&&tween.elem.parentNode){tween.elem[tween.prop]=tween.now}}};jQuery.each(["toggle","show","hide"],function(i,name){var cssFn=jQuery.fn[name];jQuery.fn[name]=function(speed,easing,callback){return speed==null||typeof speed==="boolean"||!i&&jQuery.isFunction(speed)&&jQuery.isFunction(easing)?cssFn.apply(this,arguments):this.animate(genFx(name,true),speed,easing,callback)}});jQuery.fn.extend({fadeTo:function(speed,to,easing,callback){return this.filter(isHidden).css("opacity",0).show().end().animate({opacity:to},speed,easing,callback)},animate:function(prop,speed,easing,callback){var empty=jQuery.isEmptyObject(prop),optall=jQuery.speed(speed,easing,callback),doAnimation=function(){var anim=Animation(this,jQuery.extend({},prop),optall);if(empty){anim.stop(true)}};return empty||optall.queue===false?this.each(doAnimation):this.queue(optall.queue,doAnimation)},stop:function(type,clearQueue,gotoEnd){var stopQueue=function(hooks){var stop=hooks.stop;delete hooks.stop;stop(gotoEnd)};if(typeof type!=="string"){gotoEnd=clearQueue;clearQueue=type;type=undefined}if(clearQueue&&type!==false){this.queue(type||"fx",[])}return this.each(function(){var dequeue=true,index=type!=null&&type+"queueHooks",timers=jQuery.timers,data=jQuery._data(this);if(index){if(data[index]&&data[index].stop){stopQueue(data[index])}}else{for(index in data){if(data[index]&&data[index].stop&&rrun.test(index)){stopQueue(data[index])}}}for(index=timers.length;index--;){if(timers[index].elem===this&&(type==null||timers[index].queue===type)){timers[index].anim.stop(gotoEnd);dequeue=false;timers.splice(index,1)}}if(dequeue||!gotoEnd){jQuery.dequeue(this,type)}})}});function genFx(type,includeWidth){var which,attrs={height:type},i=0;includeWidth=includeWidth?1:0;for(;i<4;i+=2-includeWidth){which=cssExpand[i];attrs["margin"+which]=attrs["padding"+which]=type}if(includeWidth){attrs.opacity=attrs.width=type}return attrs}jQuery.each({slideDown:genFx("show"),slideUp:genFx("hide"),slideToggle:genFx("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(name,props){jQuery.fn[name]=function(speed,easing,callback){return this.animate(props,speed,easing,callback)}});jQuery.speed=function(speed,easing,fn){var opt=speed&&typeof speed==="object"?jQuery.extend({},speed):{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&!jQuery.isFunction(easing)&&easing};opt.duration=jQuery.fx.off?0:typeof opt.duration==="number"?opt.duration:opt.duration in jQuery.fx.speeds?jQuery.fx.speeds[opt.duration]:jQuery.fx.speeds._default;if(opt.queue==null||opt.queue===true){opt.queue="fx"}opt.old=opt.complete;opt.complete=function(){if(jQuery.isFunction(opt.old)){opt.old.call(this)}if(opt.queue){jQuery.dequeue(this,opt.queue)}};return opt};jQuery.easing={linear:function(p){return p},swing:function(p){return.5-Math.cos(p*Math.PI)/2}};jQuery.timers=[];jQuery.fx=Tween.prototype.init;jQuery.fx.tick=function(){var timer,timers=jQuery.timers,i=0;fxNow=jQuery.now();for(;i<timers.length;i++){timer=timers[i];if(!timer()&&timers[i]===timer){timers.splice(i--,1)}}if(!timers.length){jQuery.fx.stop()}fxNow=undefined};jQuery.fx.timer=function(timer){if(timer()&&jQuery.timers.push(timer)&&!timerId){timerId=setInterval(jQuery.fx.tick,jQuery.fx.interval)}};jQuery.fx.interval=13;jQuery.fx.stop=function(){clearInterval(timerId);timerId=null};jQuery.fx.speeds={slow:600,fast:200,_default:400};jQuery.fx.step={};if(jQuery.expr&&jQuery.expr.filters){jQuery.expr.filters.animated=function(elem){return jQuery.grep(jQuery.timers,function(fn){return elem===fn.elem}).length}}var rroot=/^(?:body|html)$/i;jQuery.fn.offset=function(options){if(arguments.length){return options===undefined?this:this.each(function(i){jQuery.offset.setOffset(this,options,i)})}var docElem,body,win,clientTop,clientLeft,scrollTop,scrollLeft,box={top:0,left:0},elem=this[0],doc=elem&&elem.ownerDocument;if(!doc){return}if((body=doc.body)===elem){return jQuery.offset.bodyOffset(elem)}docElem=doc.documentElement;if(!jQuery.contains(docElem,elem)){return box}if(typeof elem.getBoundingClientRect!=="undefined"){box=elem.getBoundingClientRect()}win=getWindow(doc);clientTop=docElem.clientTop||body.clientTop||0;clientLeft=docElem.clientLeft||body.clientLeft||0;scrollTop=win.pageYOffset||docElem.scrollTop;scrollLeft=win.pageXOffset||docElem.scrollLeft;return{top:box.top+scrollTop-clientTop,left:box.left+scrollLeft-clientLeft}};jQuery.offset={bodyOffset:function(body){var top=body.offsetTop,left=body.offsetLeft;if(jQuery.support.doesNotIncludeMarginInBodyOffset){top+=parseFloat(jQuery.css(body,"marginTop"))||0;left+=parseFloat(jQuery.css(body,"marginLeft"))||0}return{top:top,left:left}},setOffset:function(elem,options,i){var position=jQuery.css(elem,"position");if(position==="static"){elem.style.position="relative"}var curElem=jQuery(elem),curOffset=curElem.offset(),curCSSTop=jQuery.css(elem,"top"),curCSSLeft=jQuery.css(elem,"left"),calculatePosition=(position==="absolute"||position==="fixed")&&jQuery.inArray("auto",[curCSSTop,curCSSLeft])>-1,props={},curPosition={},curTop,curLeft;if(calculatePosition){curPosition=curElem.position();curTop=curPosition.top;curLeft=curPosition.left}else{curTop=parseFloat(curCSSTop)||0;curLeft=parseFloat(curCSSLeft)||0}if(jQuery.isFunction(options)){options=options.call(elem,i,curOffset)}if(options.top!=null){props.top=options.top-curOffset.top+curTop}if(options.left!=null){props.left=options.left-curOffset.left+curLeft}if("using"in options){options.using.call(elem,props)}else{curElem.css(props)}}};jQuery.fn.extend({position:function(){if(!this[0]){return}var elem=this[0],offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=rroot.test(offsetParent[0].nodeName)?{top:0,left:0}:offsetParent.offset();offset.top-=parseFloat(jQuery.css(elem,"marginTop"))||0;offset.left-=parseFloat(jQuery.css(elem,"marginLeft"))||0;parentOffset.top+=parseFloat(jQuery.css(offsetParent[0],"borderTopWidth"))||0;parentOffset.left+=parseFloat(jQuery.css(offsetParent[0],"borderLeftWidth"))||0;return{top:offset.top-parentOffset.top,left:offset.left-parentOffset.left}},offsetParent:function(){return this.map(function(){var offsetParent=this.offsetParent||document.body;while(offsetParent&&(!rroot.test(offsetParent.nodeName)&&jQuery.css(offsetParent,"position")==="static")){offsetParent=offsetParent.offsetParent}return offsetParent||document.body})}});jQuery.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(method,prop){var top=/Y/.test(prop);jQuery.fn[method]=function(val){return jQuery.access(this,function(elem,method,val){var win=getWindow(elem);if(val===undefined){return win?prop in win?win[prop]:win.document.documentElement[method]:elem[method]}if(win){win.scrollTo(!top?val:jQuery(win).scrollLeft(),top?val:jQuery(win).scrollTop())}else{elem[method]=val}},method,val,arguments.length,null)}});function getWindow(elem){return jQuery.isWindow(elem)?elem:elem.nodeType===9?elem.defaultView||elem.parentWindow:false}jQuery.each({Height:"height",Width:"width"},function(name,type){jQuery.each({padding:"inner"+name,content:type,"":"outer"+name},function(defaultExtra,funcName){jQuery.fn[funcName]=function(margin,value){var chainable=arguments.length&&(defaultExtra||typeof margin!=="boolean"),extra=defaultExtra||(margin===true||value===true?"margin":"border");return jQuery.access(this,function(elem,type,value){var doc;if(jQuery.isWindow(elem)){return elem.document.documentElement["client"+name]}if(elem.nodeType===9){doc=elem.documentElement;return Math.max(elem.body["scroll"+name],doc["scroll"+name],elem.body["offset"+name],doc["offset"+name],doc["client"+name])}return value===undefined?jQuery.css(elem,type,value,extra):jQuery.style(elem,type,value,extra)},type,chainable?margin:undefined,chainable,null)}})});window.jQuery=window.$=jQuery;if(typeof define==="function"&&define.amd&&define.amd.jQuery){define("jquery",[],function(){return jQuery})}})(window); \ No newline at end of file
diff --git a/library/cpp/lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js b/library/cpp/lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js
new file mode 100644
index 0000000000..ac4a835205
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js
@@ -0,0 +1,4 @@
+$.extend($.fn.treegrid.defaults, {
+ expanderExpandedClass: 'glyphicon glyphicon-chevron-down',
+ expanderCollapsedClass: 'glyphicon glyphicon-chevron-right'
+});
diff --git a/library/cpp/lwtrace/mon/static/js/jquery.treegrid.min.js b/library/cpp/lwtrace/mon/static/js/jquery.treegrid.min.js
new file mode 100644
index 0000000000..7b7566f323
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/jquery.treegrid.min.js
@@ -0,0 +1,2 @@
+/*! jquery-treegrid 0.3.0 */
+!function(a){var b={initTree:function(b){var c=a.extend({},this.treegrid.defaults,b);return this.each(function(){var b=a(this);b.treegrid("setTreeContainer",a(this)),b.treegrid("setSettings",c),c.getRootNodes.apply(this,[a(this)]).treegrid("initNode",c),b.treegrid("getRootNodes").treegrid("render")})},initNode:function(b){return this.each(function(){var c=a(this);c.treegrid("setTreeContainer",b.getTreeGridContainer.apply(this)),c.treegrid("getChildNodes").treegrid("initNode",b),c.treegrid("initExpander").treegrid("initIndent").treegrid("initEvents").treegrid("initState").treegrid("initChangeEvent").treegrid("initSettingsEvents")})},initChangeEvent:function(){var b=a(this);return b.on("change",function(){var b=a(this);b.treegrid("render"),b.treegrid("getSetting","saveState")&&b.treegrid("saveState")}),b},initEvents:function(){var b=a(this);return b.on("collapse",function(){var b=a(this);b.removeClass("treegrid-expanded"),b.addClass("treegrid-collapsed")}),b.on("expand",function(){var b=a(this);b.removeClass("treegrid-collapsed"),b.addClass("treegrid-expanded")}),b},initSettingsEvents:function(){var b=a(this);return b.on("change",function(){var b=a(this);"function"==typeof b.treegrid("getSetting","onChange")&&b.treegrid("getSetting","onChange").apply(b)}),b.on("collapse",function(){var b=a(this);"function"==typeof b.treegrid("getSetting","onCollapse")&&b.treegrid("getSetting","onCollapse").apply(b)}),b.on("expand",function(){var b=a(this);"function"==typeof b.treegrid("getSetting","onExpand")&&b.treegrid("getSetting","onExpand").apply(b)}),b},initExpander:function(){var b=a(this),c=b.find("td").get(b.treegrid("getSetting","treeColumn")),d=b.treegrid("getSetting","expanderTemplate"),e=b.treegrid("getSetting","getExpander").apply(this);return e&&e.remove(),a(d).prependTo(c).click(function(){a(a(this).closest("tr")).treegrid("toggle")}),b},initIndent:function(){var b=a(this);b.find(".treegrid-indent").remove();for(var c=b.treegrid("getSetting","indentTemplate"),d=b.find(".treegrid-expander"),e=b.treegrid("getDepth"),f=0;e>f;f++)a(c).insertBefore(d);return b},initState:function(){var b=a(this);return b.treegrid(b.treegrid("getSetting","saveState")&&!b.treegrid("isFirstInit")?"restoreState":"expanded"===b.treegrid("getSetting","initialState")?"expand":"collapse"),b},isFirstInit:function(){var b=a(this).treegrid("getTreeContainer");return void 0===b.data("first_init")&&b.data("first_init",void 0===a.cookie(b.treegrid("getSetting","saveStateName"))),b.data("first_init")},saveState:function(){var b=a(this);if("cookie"===b.treegrid("getSetting","saveStateMethod")){var c=a.cookie(b.treegrid("getSetting","saveStateName"))||"",d=""===c?[]:c.split(","),e=b.treegrid("getNodeId");b.treegrid("isExpanded")?-1===a.inArray(e,d)&&d.push(e):b.treegrid("isCollapsed")&&-1!==a.inArray(e,d)&&d.splice(a.inArray(e,d),1),a.cookie(b.treegrid("getSetting","saveStateName"),d.join(","))}return b},restoreState:function(){var b=a(this);if("cookie"===b.treegrid("getSetting","saveStateMethod")){var c=a.cookie(b.treegrid("getSetting","saveStateName")).split(",");b.treegrid(-1!==a.inArray(b.treegrid("getNodeId"),c)?"expand":"collapse")}return b},getSetting:function(b){return a(this).treegrid("getTreeContainer")?a(this).treegrid("getTreeContainer").data("settings")[b]:null},setSettings:function(b){a(this).treegrid("getTreeContainer").data("settings",b)},getTreeContainer:function(){return a(this).data("treegrid")},setTreeContainer:function(b){return a(this).data("treegrid",b)},getRootNodes:function(){return a(this).treegrid("getSetting","getRootNodes").apply(this,[a(this).treegrid("getTreeContainer")])},getAllNodes:function(){return a(this).treegrid("getSetting","getAllNodes").apply(this,[a(this).treegrid("getTreeContainer")])},isNode:function(){return null!==a(this).treegrid("getNodeId")},getNodeId:function(){return null===a(this).treegrid("getSetting","getNodeId")?null:a(this).treegrid("getSetting","getNodeId").apply(this)},getParentNodeId:function(){return a(this).treegrid("getSetting","getParentNodeId").apply(this)},getParentNode:function(){return null===a(this).treegrid("getParentNodeId")?null:a(this).treegrid("getSetting","getNodeById").apply(this,[a(this).treegrid("getParentNodeId"),a(this).treegrid("getTreeContainer")])},getChildNodes:function(){return a(this).treegrid("getSetting","getChildNodes").apply(this,[a(this).treegrid("getNodeId"),a(this).treegrid("getTreeContainer")])},getDepth:function(){return null===a(this).treegrid("getParentNode")?0:a(this).treegrid("getParentNode").treegrid("getDepth")+1},isRoot:function(){return 0===a(this).treegrid("getDepth")},isLeaf:function(){return 0===a(this).treegrid("getChildNodes").length},isLast:function(){if(a(this).treegrid("isNode")){var b=a(this).treegrid("getParentNode");if(null===b){if(a(this).treegrid("getNodeId")===a(this).treegrid("getRootNodes").last().treegrid("getNodeId"))return!0}else if(a(this).treegrid("getNodeId")===b.treegrid("getChildNodes").last().treegrid("getNodeId"))return!0}return!1},isFirst:function(){if(a(this).treegrid("isNode")){var b=a(this).treegrid("getParentNode");if(null===b){if(a(this).treegrid("getNodeId")===a(this).treegrid("getRootNodes").first().treegrid("getNodeId"))return!0}else if(a(this).treegrid("getNodeId")===b.treegrid("getChildNodes").first().treegrid("getNodeId"))return!0}return!1},isExpanded:function(){return a(this).hasClass("treegrid-expanded")},isCollapsed:function(){return a(this).hasClass("treegrid-collapsed")},isOneOfParentsCollapsed:function(){var b=a(this);return b.treegrid("isRoot")?!1:b.treegrid("getParentNode").treegrid("isCollapsed")?!0:b.treegrid("getParentNode").treegrid("isOneOfParentsCollapsed")},expand:function(){return this.treegrid("isLeaf")||this.treegrid("isExpanded")?this:(this.trigger("expand"),this.trigger("change"),this)},expandAll:function(){var b=a(this);return b.treegrid("getRootNodes").treegrid("expandRecursive"),b},expandRecursive:function(){return a(this).each(function(){var b=a(this);b.treegrid("expand"),b.treegrid("isLeaf")||b.treegrid("getChildNodes").treegrid("expandRecursive")})},collapse:function(){return a(this).each(function(){var b=a(this);b.treegrid("isLeaf")||b.treegrid("isCollapsed")||(b.trigger("collapse"),b.trigger("change"))})},collapseAll:function(){var b=a(this);return b.treegrid("getRootNodes").treegrid("collapseRecursive"),b},collapseRecursive:function(){return a(this).each(function(){var b=a(this);b.treegrid("collapse"),b.treegrid("isLeaf")||b.treegrid("getChildNodes").treegrid("collapseRecursive")})},toggle:function(){var b=a(this);return b.treegrid(b.treegrid("isExpanded")?"collapse":"expand"),b},render:function(){return a(this).each(function(){var b=a(this);b.treegrid("isOneOfParentsCollapsed")?b.hide():b.show(),b.treegrid("isLeaf")||(b.treegrid("renderExpander"),b.treegrid("getChildNodes").treegrid("render"))})},renderExpander:function(){return a(this).each(function(){var b=a(this),c=b.treegrid("getSetting","getExpander").apply(this);c?b.treegrid("isCollapsed")?(c.removeClass(b.treegrid("getSetting","expanderExpandedClass")),c.addClass(b.treegrid("getSetting","expanderCollapsedClass"))):(c.removeClass(b.treegrid("getSetting","expanderCollapsedClass")),c.addClass(b.treegrid("getSetting","expanderExpandedClass"))):(b.treegrid("initExpander"),b.treegrid("renderExpander"))})}};a.fn.treegrid=function(c){return b[c]?b[c].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof c&&c?void a.error("Method with name "+c+" does not exists for jQuery.treegrid"):b.initTree.apply(this,arguments)},a.fn.treegrid.defaults={initialState:"expanded",saveState:!1,saveStateMethod:"cookie",saveStateName:"tree-grid-state",expanderTemplate:'<span class="treegrid-expander"></span>',indentTemplate:'<span class="treegrid-indent"></span>',expanderExpandedClass:"treegrid-expander-expanded",expanderCollapsedClass:"treegrid-expander-collapsed",treeColumn:0,getExpander:function(){return a(this).find(".treegrid-expander")},getNodeId:function(){var b=/treegrid-([A-Za-z0-9_-]+)/;return b.test(a(this).attr("class"))?b.exec(a(this).attr("class"))[1]:null},getParentNodeId:function(){var b=/treegrid-parent-([A-Za-z0-9_-]+)/;return b.test(a(this).attr("class"))?b.exec(a(this).attr("class"))[1]:null},getNodeById:function(a,b){var c="treegrid-"+a;return b.find("tr."+c)},getChildNodes:function(a,b){var c="treegrid-parent-"+a;return b.find("tr."+c)},getTreeGridContainer:function(){return a(this).closest("table")},getRootNodes:function(b){var c=a.grep(b.find("tr"),function(b){var c=a(b).attr("class"),d=/treegrid-([A-Za-z0-9_-]+)/,e=/treegrid-parent-([A-Za-z0-9_-]+)/;return d.test(c)&&!e.test(c)});return a(c)},getAllNodes:function(b){var c=a.grep(b.find("tr"),function(b){var c=a(b).attr("class"),d=/treegrid-([A-Za-z0-9_-]+)/;return d.test(c)});return a(c)},onCollapse:null,onExpand:null,onChange:null}}(jQuery); \ No newline at end of file
diff --git a/library/cpp/lwtrace/mon/static/js/jquery.url.min.js b/library/cpp/lwtrace/mon/static/js/jquery.url.min.js
new file mode 100644
index 0000000000..8ac9051a2a
--- /dev/null
+++ b/library/cpp/lwtrace/mon/static/js/jquery.url.min.js
@@ -0,0 +1 @@
+/*! js-url - v2.0.2 - 2015-09-17 */window.url=function(){function a(){}function b(a){return decodeURIComponent(a.replace(/\+/g," "))}function c(a,b){var c=a.charAt(0),d=b.split(c);return c===a?d:(a=parseInt(a.substring(1),10),d[0>a?d.length+a:a-1])}function d(a,c){var d=a.charAt(0),e=c.split("&"),f=[],g={},h=[],i=a.substring(1);for(var j in e)if(f=e[j].match(/(.*?)=(.*)/),f||(f=[e[j],e[j],""]),""!==f[1].replace(/\s/g,"")){if(f[2]=b(f[2]||""),i===f[1])return f[2];h=f[1].match(/(.*)\[([0-9]+)\]/),h?(g[h[1]]=g[h[1]]||[],g[h[1]][h[2]]=f[2]):g[f[1]]=f[2]}return d===a?g:g[i]}return function(b,e){var f,g={};if("tld?"===b)return a();if(e=e||window.location.toString(),!b)return e;if(b=b.toString(),f=e.match(/^mailto:([^\/].+)/))g.protocol="mailto",g.email=f[1];else{if((f=e.match(/(.*?)#(.*)/))&&(g.hash=f[2],e=f[1]),g.hash&&b.match(/^#/))return d(b,g.hash);if((f=e.match(/(.*?)\?(.*)/))&&(g.query=f[2],e=f[1]),g.query&&b.match(/^\?/))return d(b,g.query);if((f=e.match(/(.*?)\:?\/\/(.*)/))&&(g.protocol=f[1].toLowerCase(),e=f[2]),(f=e.match(/(.*?)(\/.*)/))&&(g.path=f[2],e=f[1]),g.path=(g.path||"").replace(/^([^\/])/,"/$1").replace(/\/$/,""),b.match(/^[\-0-9]+$/)&&(b=b.replace(/^([^\/])/,"/$1")),b.match(/^\//))return c(b,g.path.substring(1));if(f=c("/-1",g.path.substring(1)),f&&(f=f.match(/(.*?)\.(.*)/))&&(g.file=f[0],g.filename=f[1],g.fileext=f[2]),(f=e.match(/(.*)\:([0-9]+)$/))&&(g.port=f[2],e=f[1]),(f=e.match(/(.*?)@(.*)/))&&(g.auth=f[1],e=f[2]),g.auth&&(f=g.auth.match(/(.*)\:(.*)/),g.user=f?f[1]:g.auth,g.pass=f?f[2]:void 0),g.hostname=e.toLowerCase(),"."===b.charAt(0))return c(b,g.hostname);a()&&(f=g.hostname.match(a()),f&&(g.tld=f[3],g.domain=f[2]?f[2]+"."+f[3]:void 0,g.sub=f[1]||void 0)),g.port=g.port||("https"===g.protocol?"443":"80"),g.protocol=g.protocol||("443"===g.port?"https":"http")}return b in g?g[b]:"[]"===b?g:void 0}}(),"undefined"!=typeof jQuery&&jQuery.extend({url:function(a,b){return window.url(a,b)}});
diff --git a/library/cpp/lwtrace/mon/trace.sh b/library/cpp/lwtrace/mon/trace.sh
new file mode 100755
index 0000000000..8414a9b0ca
--- /dev/null
+++ b/library/cpp/lwtrace/mon/trace.sh
@@ -0,0 +1,81 @@
+#!/bin/sh -e
+# $Id: trace.sh 2313967 2016-05-24 12:52:38Z serxa $
+# $HeadURL: svn+ssh://arcadia.yandex.ru/arc/trunk/arcadia/library/cpp/lwtrace/mon/trace.sh $
+
+usage() {
+ if [ -n "$*" ]; then
+ echo "ERROR: $*" >&2
+ else
+ echo "Script for LWTrace tracing management" >&2
+ fi
+ echo "USAGE: `basename $0` COMMAND TRACEID HOST:PORT PARAM1=VALUE1 ..." >&2
+ echo "COMMANDS:" >&2
+ echo " new Start new tracing described by query from STDIN," >&2
+ echo " uniquely named with TRACEID string," >&2
+ echo " using HOST:PORT monitoring service." >&2
+ echo " query can contain \$params that are substituted with corresponding values from cmdline" >&2
+ echo " (alse \$\$ is replaced by \$, each param must be defined from cmdline)" >&2
+ echo " delete Stop existing tracing with specified name TRACEID," >&2
+ echo " on HOST:PORT monitoring service." >&2
+ exit 1
+}
+
+COMMAND=$1
+ID="$2"
+IDENC="$(perl -MURI::Escape -e '$id = $ARGV[0]; $id=uri_escape($id); $id =~ s{[+%]}{-}g; print $id;' "$ID")"
+ADDRESS="$3"
+if [ "$COMMAND" = "--help" ] || [ -z "$*" ]; then usage; fi
+if [ -z "$ID" ]; then usage "TRACEID is not specified"; fi
+if [ -z "$ADDRESS" ]; then usage "HOST:PORT is not specified"; fi
+
+shift 3
+
+STATUS=0
+ERRFILE=/var/tmp/lwtrace.sh.$$
+
+error() {
+ echo "ERROR: $*" >&2
+ [ ! -e $ERRFILE ] || cat $ERRFILE >&2
+ exit 1
+}
+
+stop() { rm -f $ERRFILE; }
+trap stop INT ABRT EXIT
+
+case "$COMMAND" in
+
+ new)
+ QUERY="$(perl -e 'use MIME::Base64;
+ local $/;
+ $a = <STDIN>;
+ for $arg (@ARGV) {
+ ($k,$v) = split "=",$arg,2;
+ $a =~ s{\$$k}{$v}g;
+ }
+ if ($a =~ /\$([A-Za-z_][\w_]*)/) {
+ print STDERR "undefined param in lwtrace query: $1\n";
+ exit 0
+ }
+ $a =~ s{\$\$}{\$}g;
+ print encode_base64($a, "");
+ ' "$@" 2>$ERRFILE)"
+ if [ -z "$QUERY" ]; then error "lwtrace query errors"; fi
+ wget --post-data="id=$IDENC&query=$QUERY" \
+ -O - http://$ADDRESS/trace?mode=new </dev/null 2>$ERRFILE || STATUS=$?
+ if [ $STATUS -ne 0 ]; then error "wget failure"; fi
+ ;;
+
+ delete)
+ wget --post-data="id=$IDENC" \
+ -O - http://$ADDRESS/trace?mode=delete </dev/null 2>$ERRFILE || STATUS=$?
+ if [ $STATUS -ne 0 ]; then error "wget failure"; fi
+ ;;
+
+ *)
+ echo "usage: `basename $0` new TRACEID ADDRESS < query.txt" >&2
+ echo " `basename $0` delete TRACEID ADDRESS" >&2
+ exit 1
+ ;;
+
+esac
+echo "Done"
diff --git a/library/cpp/lwtrace/mon/ya.make b/library/cpp/lwtrace/mon/ya.make
new file mode 100644
index 0000000000..bdcb315754
--- /dev/null
+++ b/library/cpp/lwtrace/mon/ya.make
@@ -0,0 +1,55 @@
+LIBRARY()
+
+OWNER(serxa g:kikimr)
+
+RESOURCE(
+ static/common.css lwtrace/mon/static/common.css
+ static/common.js lwtrace/mon/static/common.js
+ static/css/bootstrap.min.css lwtrace/mon/static/css/bootstrap.min.css
+ static/css/d3-gantt.css lwtrace/mon/static/css/d3-gantt.css
+ static/css/jquery.treegrid.css lwtrace/mon/static/css/jquery.treegrid.css
+ static/analytics.css lwtrace/mon/static/analytics.css
+ static/analytics.flot.html lwtrace/mon/static/analytics.flot.html
+ static/analytics.gantt.html lwtrace/mon/static/analytics.gantt.html
+ static/analytics.header.html lwtrace/mon/static/analytics.header.html
+ static/analytics.js lwtrace/mon/static/analytics.js
+ static/fonts/glyphicons-halflings-regular.eot lwtrace/mon/static/fonts/glyphicons-halflings-regular.eot
+ static/fonts/glyphicons-halflings-regular.svg lwtrace/mon/static/fonts/glyphicons-halflings-regular.svg
+ static/fonts/glyphicons-halflings-regular.ttf lwtrace/mon/static/fonts/glyphicons-halflings-regular.ttf
+ static/fonts/glyphicons-halflings-regular.woff2 lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff2
+ static/fonts/glyphicons-halflings-regular.woff lwtrace/mon/static/fonts/glyphicons-halflings-regular.woff
+ static/footer.html lwtrace/mon/static/footer.html
+ static/header.html lwtrace/mon/static/header.html
+ static/img/collapse.png lwtrace/mon/static/img/collapse.png
+ static/img/expand.png lwtrace/mon/static/img/expand.png
+ static/img/file.png lwtrace/mon/static/img/file.png
+ static/img/folder.png lwtrace/mon/static/img/folder.png
+ static/js/bootstrap.min.js lwtrace/mon/static/js/bootstrap.min.js
+ static/js/d3.v4.min.js lwtrace/mon/static/js/d3.v4.min.js
+ static/js/d3-gantt.js lwtrace/mon/static/js/d3-gantt.js
+ static/js/d3-tip-0.8.0-alpha.1.js lwtrace/mon/static/js/d3-tip-0.8.0-alpha.1.js
+ static/js/filesaver.min.js lwtrace/mon/static/js/filesaver.min.js
+ static/js/jquery.flot.extents.js lwtrace/mon/static/js/jquery.flot.extents.js
+ static/js/jquery.flot.min.js lwtrace/mon/static/js/jquery.flot.min.js
+ static/js/jquery.flot.navigate.min.js lwtrace/mon/static/js/jquery.flot.navigate.min.js
+ static/js/jquery.flot.selection.min.js lwtrace/mon/static/js/jquery.flot.selection.min.js
+ static/js/jquery.min.js lwtrace/mon/static/js/jquery.min.js
+ static/js/jquery.treegrid.bootstrap3.js lwtrace/mon/static/js/jquery.treegrid.bootstrap3.js
+ static/js/jquery.treegrid.min.js lwtrace/mon/static/js/jquery.treegrid.min.js
+ static/js/jquery.url.min.js lwtrace/mon/static/js/jquery.url.min.js
+)
+
+SRCS(
+ mon_lwtrace.cpp
+)
+
+PEERDIR(
+ library/cpp/html/pcdata
+ library/cpp/lwtrace
+ library/cpp/lwtrace/mon/analytics
+ library/cpp/monlib/dynamic_counters
+ library/cpp/resource
+ library/cpp/string_utils/base64
+)
+
+END()
diff --git a/library/cpp/lwtrace/param_traits.h b/library/cpp/lwtrace/param_traits.h
new file mode 100644
index 0000000000..a0faeb50db
--- /dev/null
+++ b/library/cpp/lwtrace/param_traits.h
@@ -0,0 +1,66 @@
+#pragma once
+#include "signature.h"
+
+#include <util/datetime/base.h>
+#include <util/string/builder.h>
+
+#include <limits>
+
+#ifndef LWTRACE_DISABLE
+
+namespace NLWTrace {
+
+ template <>
+ struct TParamTraits<TInstant> {
+ using TStoreType = double;
+ using TFuncParam = TInstant;
+
+ inline static void ToString(TStoreType value, TString* out) {
+ *out = TParamConv<TStoreType>::ToString(value);
+ }
+
+ inline static TStoreType ToStoreType(TInstant value) {
+ if (value == TInstant::Max()) {
+ return std::numeric_limits<TStoreType>::infinity();
+ } else {
+ return static_cast<TStoreType>(value.MicroSeconds()) / 1000000.0; // seconds count
+ }
+ }
+ };
+
+ template <>
+ struct TParamTraits<TDuration> {
+ using TStoreType = double;
+ using TFuncParam = TDuration;
+
+ inline static void ToString(TStoreType value, TString* out) {
+ *out = TParamConv<TStoreType>::ToString(value);
+ }
+
+ inline static TStoreType ToStoreType(TDuration value) {
+ if (value == TDuration::Max()) {
+ return std::numeric_limits<TStoreType>::infinity();
+ } else {
+ return static_cast<TStoreType>(value.MicroSeconds()) / 1000.0; // milliseconds count
+ }
+ }
+ };
+
+ // Param for enum with GENERATE_ENUM_SERIALIZATION enabled or operator<< implemented
+ template <class TEnum>
+ struct TEnumParamWithSerialization {
+ using TStoreType = typename TParamTraits<std::underlying_type_t<TEnum>>::TStoreType;
+ using TFuncParam = TEnum;
+
+ inline static void ToString(TStoreType stored, TString* out) {
+ *out = TStringBuilder() << static_cast<TEnum>(stored) << " (" << stored << ")";
+ }
+
+ inline static TStoreType ToStoreType(TFuncParam v) {
+ return static_cast<TStoreType>(v);
+ }
+ };
+
+} // namespace NLWTrace
+
+#endif // LWTRACE_DISABLE
diff --git a/library/cpp/lwtrace/perf.cpp b/library/cpp/lwtrace/perf.cpp
new file mode 100644
index 0000000000..03b68586ea
--- /dev/null
+++ b/library/cpp/lwtrace/perf.cpp
@@ -0,0 +1,84 @@
+#include "perf.h"
+
+#include "probes.h"
+
+#include <util/system/datetime.h>
+#include <util/system/hp_timer.h>
+
+namespace NLWTrace {
+ LWTRACE_USING(LWTRACE_INTERNAL_PROVIDER);
+
+ TCpuTracker::TCpuTracker()
+ : MinReportPeriod(NHPTimer::GetCyclesPerSecond())
+ {
+ ResetStats();
+ }
+
+ void TCpuTracker::Enter() {
+ LastTs = GetCycleCount();
+ }
+
+ void TCpuTracker::Exit(const TProbe* probe) {
+ ui64 exitTs = GetCycleCount();
+ if (exitTs < LastTs) {
+ return; // probably TSC was reset
+ }
+ ui64 cycles = exitTs - LastTs;
+ LastTs = exitTs;
+
+ AddStats(probe, cycles);
+ }
+
+ void TCpuTracker::AddStats(const TProbe* probe, ui64 cycles) {
+ if (MaxCycles < cycles) {
+ MaxProbe = probe;
+ MaxCycles = cycles;
+ }
+ if (MinCycles > cycles) {
+ MinCycles = cycles;
+ }
+ ProbeCycles += cycles;
+ Count++;
+
+ if (LastTs - LastReportTs > MinReportPeriod) {
+ Report();
+ }
+ }
+
+ void TCpuTracker::ResetStats() {
+ MaxCycles = 0;
+ MaxProbe = nullptr;
+ MinCycles = ui64(-1);
+ ProbeCycles = 0;
+ Count = 0;
+ }
+
+ void TCpuTracker::Report() {
+ if (!Reporting) {
+ Reporting = true;
+ ReportNotReentrant();
+ Reporting = false;
+ }
+ }
+
+ void TCpuTracker::ReportNotReentrant() {
+ if (LastReportTs && Count > 0 && LastTs > LastReportTs) {
+ ui64 reportPeriod = LastTs - LastReportTs;
+ double share = double(ProbeCycles) / reportPeriod;
+ double minMs = MilliSeconds(MinCycles);
+ double maxMs = MilliSeconds(MaxCycles);
+ double avgMs = MilliSeconds(ProbeCycles) / Count;
+ LastReportTs = LastTs;
+ ResetStats();
+ LWPROBE(PerfReport, share, minMs, maxMs, avgMs);
+ } else {
+ LastReportTs = LastTs;
+ ResetStats();
+ }
+ }
+
+ double TCpuTracker::MilliSeconds(ui64 cycles) {
+ return NHPTimer::GetSeconds(cycles) * 1000.0;
+ }
+
+}
diff --git a/library/cpp/lwtrace/perf.h b/library/cpp/lwtrace/perf.h
new file mode 100644
index 0000000000..d535247196
--- /dev/null
+++ b/library/cpp/lwtrace/perf.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include <util/system/types.h>
+#include <util/thread/singleton.h>
+
+namespace NLWTrace {
+ struct TProbe;
+
+ class TCpuTracker {
+ private:
+ const ui64 MinReportPeriod;
+
+ // State
+ bool Reporting = false;
+ ui64 LastTs = 0;
+ ui64 LastReportTs = 0;
+
+ // Statistics
+ ui64 MaxCycles;
+ const TProbe* MaxProbe;
+ ui64 MinCycles;
+ ui64 ProbeCycles;
+ ui64 Count;
+
+ public:
+ TCpuTracker();
+ void Enter();
+ void Exit(const TProbe* Probe);
+ static TCpuTracker* TlsInstance() {
+ struct TCpuTrackerkHolder {
+ TCpuTracker Tracker;
+ };
+ return &FastTlsSingletonWithPriority<TCpuTrackerkHolder, 4>()->Tracker;
+ }
+
+ private:
+ void AddStats(const TProbe* probe, ui64 cycles);
+ void ResetStats();
+ void Report();
+ void ReportNotReentrant();
+ static double MilliSeconds(ui64 cycles);
+ };
+
+ class TScopedThreadCpuTracker {
+ private:
+ const TProbe* Probe;
+ TCpuTracker* Tracker;
+
+ public:
+ template <class T>
+ explicit TScopedThreadCpuTracker(const T& probe)
+ : Probe(&probe.Probe)
+ , Tracker(TCpuTracker::TlsInstance())
+ {
+ Tracker->Enter();
+ }
+
+ ~TScopedThreadCpuTracker() {
+ Tracker->Exit(Probe);
+ }
+ };
+
+}
diff --git a/library/cpp/lwtrace/preprocessor.h b/library/cpp/lwtrace/preprocessor.h
new file mode 100644
index 0000000000..40865467b2
--- /dev/null
+++ b/library/cpp/lwtrace/preprocessor.h
@@ -0,0 +1,295 @@
+#pragma once
+
+#include "check.h"
+#include "perf.h"
+#include "symbol.h"
+
+#include <util/generic/hide_ptr.h>
+#include <util/system/platform.h>
+
+#include <stddef.h> //size_t
+
+#ifdef _win_
+#ifndef LWTRACE_DISABLE
+#define LWTRACE_DISABLE
+#endif // LWTRACE_DISABLE
+#endif // _win_
+
+// Maximum number of executors that can be attached to a probe
+#define LWTRACE_MAX_ACTIONS 100
+
+// Maximum number of groups that can be assigned to a probe
+#define LWTRACE_MAX_GROUPS 100
+
+#ifndef LWTRACE_DISABLE
+
+/*
+ * WARNING: All macros define in this header must be considered as implementation details and should NOT be used directly
+ * WARNING: See lwtrace/all.h for macros that represent a user interface of lwtrace library
+ *
+ */
+
+// Use for code generation to handle parameter types. USAGE:
+// 1. #define FOREACH_PARAMTYPE_MACRO(n, t, v, your_p1, your_p2) your code snippet
+// 2. FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, your_p1_value, your_p1_value)
+// FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, your_p1_another_value, your_p1_another_value)
+// 3. #undef FOREACH_PARAMTYPE_MACRO
+// Type order matters!
+#define FOREACH_PARAMTYPE(MACRO, ...) \
+ MACRO("i64", i64, I64, ##__VA_ARGS__) \
+ MACRO("ui64", ui64, Ui64, ##__VA_ARGS__) \
+ MACRO("double", double, Double, ##__VA_ARGS__) \
+ MACRO("string", TString, Str, ##__VA_ARGS__) \
+ MACRO("symbol", NLWTrace::TSymbol, Symbol, ##__VA_ARGS__) \
+ MACRO("check", NLWTrace::TCheck, Check, ##__VA_ARGS__) \
+ /**/
+
+// Used with FOREACH_PARAMTYPE to handle TNil parameter type also
+#define FOR_NIL_PARAMTYPE(MACRO, ...) \
+ MACRO(NULL, TNil, Nil, ##__VA_ARGS__) \
+ /**/
+
+// Used for math statements
+#define FOR_MATH_PARAMTYPE(MACRO, ...) \
+ MACRO("i64", i64, I64, ##__VA_ARGS__) \
+ MACRO("ui64", ui64, Ui64, ##__VA_ARGS__) \
+ MACRO("check", NLWTrace::TCheck, Check, ##__VA_ARGS__) \
+ /**/
+
+// Use for code generation to handle parameter lists
+// NOTE: this is the only place to change if more parameters needed
+#define FOREACH_PARAMNUM(MACRO, ...) \
+ MACRO(0, ##__VA_ARGS__) \
+ MACRO(1, ##__VA_ARGS__) \
+ MACRO(2, ##__VA_ARGS__) \
+ MACRO(3, ##__VA_ARGS__) \
+ MACRO(4, ##__VA_ARGS__) \
+ MACRO(5, ##__VA_ARGS__) \
+ MACRO(6, ##__VA_ARGS__) \
+ MACRO(7, ##__VA_ARGS__) \
+ MACRO(8, ##__VA_ARGS__) \
+ MACRO(9, ##__VA_ARGS__) \
+ MACRO(10, ##__VA_ARGS__) \
+ MACRO(11, ##__VA_ARGS__) \
+ MACRO(12, ##__VA_ARGS__) \
+ MACRO(13, ##__VA_ARGS__) \
+ MACRO(14, ##__VA_ARGS__) \
+ MACRO(15, ##__VA_ARGS__) \
+ MACRO(16, ##__VA_ARGS__) \
+ /**/
+
+#define FOREACH_LEFT_TYPE(MACRO, ...) \
+ MACRO(__VA_ARGS__, OT_VARIABLE) \
+ MACRO(__VA_ARGS__, OT_LITERAL) \
+ MACRO(__VA_ARGS__, OT_PARAMETER) \
+ /**/
+
+#define FOREACH_RIGHT_TYPE(MACRO, ...) \
+ MACRO(__VA_ARGS__, OT_VARIABLE) \
+ MACRO(__VA_ARGS__, OT_LITERAL) \
+ MACRO(__VA_ARGS__, OT_PARAMETER) \
+ /**/
+
+#define FOREACH_DESTINATION_TYPE(MACRO, ...) \
+ MACRO(__VA_ARGS__, OT_VARIABLE) \
+ /**/
+
+// Auxilary macros
+#define LWTRACE_EXPAND(x) x
+#define LWTRACE_EAT(...)
+
+// Eat last/first comma trick
+#define LWTRACE_COMMA(bit) LWTRACE_COMMA_##bit()
+#define LWTRACE_COMMA_0()
+#define LWTRACE_COMMA_1() ,
+
+// Macros to pack/unpack tuples, e.g. (x,y,z)
+#define LWTRACE_UNROLL(...) __VA_ARGS__
+#define LWTRACE_ENROLL(...) (__VA_ARGS__)
+
+// Param types list handling macros
+#define LWTRACE_TEMPLATE_PARAMS_I(i) (1) class TP##i = TNil LWTRACE_COMMA
+#define LWTRACE_TEMPLATE_PARAMS LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_TEMPLATE_PARAMS_I)(0))
+#define LWTRACE_TEMPLATE_PARAMS_NODEF_I(i) (1) class TP##i LWTRACE_COMMA
+#define LWTRACE_TEMPLATE_PARAMS_NODEF LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_TEMPLATE_PARAMS_NODEF_I)(0))
+#define LWTRACE_TEMPLATE_ARGS_I(i) (1) TP##i LWTRACE_COMMA
+#define LWTRACE_TEMPLATE_ARGS LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_TEMPLATE_ARGS_I)(0))
+#define LWTRACE_FUNCTION_PARAMS_I(i) (1) typename ::NLWTrace::TParamTraits<TP##i>::TFuncParam p##i = ERROR_not_enough_parameters() LWTRACE_COMMA
+#define LWTRACE_FUNCTION_PARAMS LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_FUNCTION_PARAMS_I)(0))
+#define LWTRACE_PREPARE_PARAMS_I(i, params) params.Param[i].template CopyConstruct<typename ::NLWTrace::TParamTraits<TP##i>::TStoreType>(::NLWTrace::TParamTraits<TP##i>::ToStoreType(p##i));
+#define LWTRACE_PREPARE_PARAMS(params) \
+ do { \
+ FOREACH_PARAMNUM(LWTRACE_PREPARE_PARAMS_I, params) \
+ } while (false)
+#define LWTRACE_COUNT_PARAMS_I(i) +(std::is_same<TP##i, ::NLWTrace::TNil>::value ? 0 : 1)
+#define LWTRACE_COUNT_PARAMS (0 FOREACH_PARAMNUM(LWTRACE_COUNT_PARAMS_I))
+#define LWTRACE_MAX_PARAMS_I(i) +1
+#define LWTRACE_MAX_PARAMS (0 FOREACH_PARAMNUM(LWTRACE_MAX_PARAMS_I))
+
+// Determine maximum sizeof(t) over all supported types
+#define LWTRACE_MAX_PARAM_SIZE_TA_TAIL_I(n, t, v) v,
+#define LWTRACE_MAX_PARAM_SIZE_TA_TAIL \
+ FOREACH_PARAMTYPE(LWTRACE_MAX_PARAM_SIZE_TA_TAIL_I) \
+ 0
+#define LWTRACE_MAX_PARAM_SIZE_TP_I(n, t, v) , size_t v = 0
+#define LWTRACE_MAX_PARAM_SIZE_TP size_t Head = 0 FOREACH_PARAMTYPE(LWTRACE_MAX_PARAM_SIZE_TP_I)
+#define LWTRACE_MAX_PARAM_SIZE_TA_I(n, t, v) , sizeof(t)
+#define LWTRACE_MAX_PARAM_SIZE_TA 0 FOREACH_PARAMTYPE(LWTRACE_MAX_PARAM_SIZE_TA_I)
+#define LWTRACE_MAX_PARAM_SIZE ::NLWTrace::TMaxParamSize<LWTRACE_MAX_PARAM_SIZE_TA>::Result
+
+namespace NLWTrace {
+ template <LWTRACE_MAX_PARAM_SIZE_TP>
+ struct TMaxParamSize {
+ static const size_t Tail = TMaxParamSize<LWTRACE_MAX_PARAM_SIZE_TA_TAIL>::Result;
+ static const size_t Result = (Head > Tail ? Head : Tail);
+ };
+
+ template <>
+ struct TMaxParamSize<> {
+ static const size_t Result = 0;
+ };
+
+}
+
+// Define stuff that is needed to register probes before main()
+#define LWTRACE_REGISTER_PROBES(provider) \
+ namespace LWTRACE_GET_NAMESPACE(provider) { \
+ struct TInitLWTrace##provider { \
+ TInitLWTrace##provider() { \
+ Singleton<NLWTrace::TProbeRegistry>()->AddProbesList(LWTRACE_GET_PROBES(provider)); \
+ } \
+ /* This may not be in anonymous namespace because otherwise */ \
+ /* it is called twice when .so loaded twice */ \
+ }* InitLWTrace##provider = Singleton<TInitLWTrace##provider>(); \
+ } \
+ /**/
+
+// Macro for TSignature POD structure static initialization
+#define LWTRACE_SIGNATURE_CTOR(types, names) \
+ { \
+ /* ParamTypes */ ::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::ParamTypes, \
+ /* ParamNames */ {LWTRACE_EXPAND(LWTRACE_UNROLL names)}, \
+ /* ParamCount */ ::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::ParamCount, \
+ /* SerializeParams */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::SerializeParams, \
+ /* CloneParams */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::CloneParams, \
+ /* DestroyParams */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::DestroyParams, \
+ /* SerializeToPb */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::SerializeToPb, \
+ /* DeserializeFromPb */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::DeserializeFromPb\
+ }
+
+// Macro for TEvent POD structure static initialization
+#define LWTRACE_EVENT_CTOR(name, groups, types, names) \
+ { \
+ /* Name */ #name, \
+ /* Groups */ {LWTRACE_EXPAND(LWTRACE_UNROLL_GROUPS groups)}, \
+ /* Signature */ LWTRACE_SIGNATURE_CTOR(types, names) \
+ }
+
+// Macro for TProbe POD structure static initialization
+#define LWTRACE_PROBE_CTOR(name, groups, types, names) \
+ { \
+ /* Event */ LWTRACE_EVENT_CTOR(name, groups, types, names), \
+ /* ExecutorsCount */ 0, \
+ /* Lock */ {0}, \
+ /* Executors */ {0}, \
+ /* Front */ 0, \
+ /* Back */ 0 \
+ }
+
+// Provider static data accessors
+#define LWTRACE_GET_NAMESPACE(provider) NLWTrace_##provider
+#define LWTRACE_GET_NAME(name) lwtrace_##name
+#define LWTRACE_GET_TYPE(name) TLWTrace_##name
+#define LWTRACE_GET_PROBES_I(provider) gProbes##provider
+#define LWTRACE_GET_EVENTS_I(provider) gEvents##provider
+
+// Declaration of provider static data
+#define LWTRACE_DECLARE_PROBE(name, groups, types, names) \
+ typedef ::NLWTrace::TUserProbe<LWTRACE_EXPAND(LWTRACE_UNROLL types)> LWTRACE_GET_TYPE(name); \
+ extern LWTRACE_GET_TYPE(name) LWTRACE_GET_NAME(name); \
+ /**/
+#define LWTRACE_DECLARE_EVENT(name, groups, types, names) \
+ typedef ::NLWTrace::TUserEvent<LWTRACE_EXPAND(LWTRACE_UNROLL types)> LWTRACE_GET_TYPE(name); \
+ extern LWTRACE_GET_TYPE(name) LWTRACE_GET_NAME(name); \
+ /**/
+#define LWTRACE_DECLARE_PROVIDER_I(provider) \
+ namespace LWTRACE_GET_NAMESPACE(provider) { \
+ provider(LWTRACE_DECLARE_PROBE, LWTRACE_DECLARE_EVENT, LWTRACE_ENROLL, LWTRACE_ENROLL, LWTRACE_ENROLL) \
+ } \
+ extern ::NLWTrace::TProbe* LWTRACE_GET_PROBES_I(provider)[]; \
+ extern ::NLWTrace::TEvent* LWTRACE_GET_EVENTS_I(provider)[]; \
+ /**/
+
+// Initialization of provider static data
+#define LWTRACE_UNROLL_GROUPS(x) #x, LWTRACE_UNROLL
+#define LWTRACE_DEFINE_PROBE(name, groups, types, names) \
+ LWTRACE_GET_TYPE(name) \
+ LWTRACE_GET_NAME(name) = \
+ {LWTRACE_PROBE_CTOR(name, groups, types, names)}; \
+ /**/
+#define LWTRACE_DEFINE_EVENT(name, groups, types, names) \
+ LWTRACE_GET_TYPE(name) \
+ LWTRACE_GET_NAME(name) = \
+ {LWTRACE_EVENT_CTOR(name, groups, types, names)}; \
+ /**/
+#define LWTRACE_PROBE_ADDRESS_I(name, groups, types, names) \
+ LWTRACE_GET_NAME(name).Probe, /**/
+#define LWTRACE_PROBE_ADDRESS(provider) \
+ &LWTRACE_GET_NAMESPACE(provider)::LWTRACE_PROBE_ADDRESS_I /**/
+#define LWTRACE_EVENT_ADDRESS_I(name, groups, types, names) \
+ LWTRACE_GET_NAME(name).Event, /**/
+#define LWTRACE_EVENT_ADDRESS(provider) \
+ &LWTRACE_GET_NAMESPACE(provider)::LWTRACE_EVENT_ADDRESS_I /**/
+#define LWTRACE_DEFINE_PROVIDER_I(provider) \
+ namespace LWTRACE_GET_NAMESPACE(provider) { \
+ provider(LWTRACE_DEFINE_PROBE, LWTRACE_DEFINE_EVENT, (provider)LWTRACE_ENROLL, LWTRACE_ENROLL, LWTRACE_ENROLL) \
+ } \
+ ::NLWTrace::TProbe* LWTRACE_GET_PROBES_I(provider)[] = { \
+ provider(LWTRACE_PROBE_ADDRESS(provider), LWTRACE_EAT, LWTRACE_ENROLL, LWTRACE_ENROLL, LWTRACE_ENROLL) \
+ NULL}; \
+ ::NLWTrace::TEvent* LWTRACE_GET_EVENTS_I(provider)[] = { \
+ provider(LWTRACE_EAT, LWTRACE_EVENT_ADDRESS(provider), LWTRACE_ENROLL, LWTRACE_ENROLL, LWTRACE_ENROLL) \
+ NULL}; \
+ LWTRACE_REGISTER_PROBES(provider)
+ /**/
+
+#define LWPROBE_I(probe, ...) \
+ do { \
+ if ((probe).Probe.GetExecutorsCount() > 0) { \
+ ::NLWTrace::TScopedThreadCpuTracker _cpuTracker(probe); \
+ TReadSpinLockGuard g((probe).Probe.Lock); \
+ if ((probe).Probe.GetExecutorsCount() > 0) { \
+ (probe)(__VA_ARGS__); \
+ } \
+ } \
+ } while (false) /**/
+
+#define LWPROBE_ENABLED_I(probe) ((probe).Probe.GetExecutorsCount() > 0)
+
+#define LWPROBE_DURATION_I(probetype, uniqid, probe, ...) probetype ::TScopedDuration uniqid(probe, 0 /* fake P0 - used for duration */, ##__VA_ARGS__);
+
+#define LWTRACK_I(probe, orbit, ...) \
+ do { \
+ if ((probe).Probe.GetExecutorsCount() > 0) { \
+ ::NLWTrace::TScopedThreadCpuTracker _cpuTracker(probe); \
+ TReadSpinLockGuard g((probe).Probe.Lock); \
+ if ((probe).Probe.GetExecutorsCount() > 0) { \
+ (probe).Run(orbit, ##__VA_ARGS__); \
+ } \
+ } else { \
+ auto& _orbit = (orbit); \
+ if (HasShuttles(_orbit)) { \
+ ::NLWTrace::TScopedThreadCpuTracker _cpuTracker(probe); \
+ (probe).RunShuttles(_orbit, ##__VA_ARGS__); \
+ } \
+ } \
+ } while (false) /**/
+
+#define LWEVENT_I(event, ...) (event)(__VA_ARGS__)
+
+#else
+#define LWTRACE_MAX_PARAM_SIZE sizeof(void*)
+#define LWTRACE_MAX_PARAMS 1
+#define FOREACH_PARAMTYPE(MACRO, ...)
+
+#endif
diff --git a/library/cpp/lwtrace/probe.h b/library/cpp/lwtrace/probe.h
new file mode 100644
index 0000000000..31fa282da3
--- /dev/null
+++ b/library/cpp/lwtrace/probe.h
@@ -0,0 +1,266 @@
+#pragma once
+
+#include "event.h"
+#include "preprocessor.h"
+#include "rwspinlock.h"
+#include "shuttle.h"
+
+#include <util/datetime/cputimer.h>
+#include <util/generic/hide_ptr.h>
+#include <util/generic/scope.h>
+#include <util/system/atomic.h>
+
+namespace NLWTrace {
+ // Represents a chain (linked list) of steps for execution of a trace query block
+ // NOTE: different executor objects are used on different probes (even for the same query block)
+ class IExecutor {
+ private:
+ IExecutor* Next;
+
+ public:
+ IExecutor()
+ : Next(nullptr)
+ {
+ }
+
+ virtual ~IExecutor() {
+ if (Next != nullptr) {
+ delete Next;
+ }
+ }
+
+ void Execute(TOrbit& orbit, const TParams& params) {
+ if (DoExecute(orbit, params) && Next != nullptr) {
+ Next->Execute(orbit, params);
+ }
+ }
+
+ void SetNext(IExecutor* next) {
+ Next = next;
+ }
+
+ IExecutor* GetNext() {
+ return Next;
+ }
+
+ const IExecutor* GetNext() const {
+ return Next;
+ }
+
+ protected:
+ virtual bool DoExecute(TOrbit& orbit, const TParams& params) = 0;
+ };
+
+ // Common class for all probes
+ struct TProbe {
+ // Const configuration
+ TEvent Event;
+
+ // State that don't need any locking
+ TAtomic ExecutorsCount;
+
+ // State that must be accessed under lock
+ TRWSpinLock Lock;
+ IExecutor* Executors[LWTRACE_MAX_ACTIONS];
+ IExecutor** Front; // Invalid if ExecutorsCount == 0
+ IExecutor** Back; // Invalid if ExecutorsCount == 0
+
+ void Init() {
+ ExecutorsCount = 0;
+ Lock.Init();
+ Zero(Executors);
+ Front = nullptr;
+ Back = nullptr;
+ }
+
+ IExecutor** First() {
+ return Executors;
+ }
+
+ IExecutor** Last() {
+ return Executors + LWTRACE_MAX_ACTIONS;
+ }
+
+ void Inc(IExecutor**& it) {
+ it++;
+ if (it == Last()) {
+ it = First();
+ }
+ }
+
+ intptr_t GetExecutorsCount() const {
+ return AtomicGet(ExecutorsCount);
+ }
+
+ bool Attach(IExecutor* exec) {
+ TWriteSpinLockGuard g(Lock);
+ if (ExecutorsCount > 0) {
+ for (IExecutor** it = Front;; Inc(it)) {
+ if (*it == nullptr) {
+ *it = exec;
+ AtomicIncrement(ExecutorsCount);
+ return true; // Inserted into free slot in [First; Last]
+ }
+ if (it == Back) {
+ break;
+ }
+ }
+ IExecutor** newBack = Back;
+ Inc(newBack);
+ if (newBack == Front) {
+ return false; // Buffer is full
+ } else {
+ Back = newBack;
+ *Back = exec;
+ AtomicIncrement(ExecutorsCount);
+ return true; // Inserted after Last
+ }
+ } else {
+ Front = Back = First();
+ *Front = exec;
+ AtomicIncrement(ExecutorsCount);
+ return true; // Inserted as a first element
+ }
+ }
+
+ bool Detach(IExecutor* exec) {
+ TWriteSpinLockGuard g(Lock);
+ for (IExecutor** it = First(); it != Last(); it++) {
+ if ((*it) == exec) {
+ *it = nullptr;
+ AtomicDecrement(ExecutorsCount);
+ if (ExecutorsCount > 0) {
+ for (;; Inc(Front)) {
+ if (*Front != nullptr) {
+ break;
+ }
+ if (Front == Back) {
+ break;
+ }
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void RunExecutors(TOrbit& orbit, const TParams& params) {
+ // Read lock is implied
+ if (ExecutorsCount > 0) {
+ for (IExecutor** it = Front;; Inc(it)) {
+ IExecutor* exec = *it;
+ if (exec) {
+ exec->Execute(orbit, params);
+ }
+ if (it == Back) {
+ break;
+ }
+ }
+ }
+ }
+
+ void RunShuttles(TOrbit& orbit, const TParams& params) {
+ orbit.AddProbe(this, params);
+ }
+ };
+
+#ifndef LWTRACE_DISABLE
+
+ template <class T>
+ inline void PreparePtr(const T& ref, const T*& ptr) {
+ ptr = &ref;
+ }
+
+ template <>
+ inline void PreparePtr<TNil>(const TNil&, const TNil*&) {
+ }
+
+#define LWTRACE_SCOPED_FUNCTION_PARAMS_I(i) (1) typename ::NLWTrace::TParamTraits<TP##i>::TFuncParam p##i = ERROR_not_enough_parameters() LWTRACE_COMMA
+#define LWTRACE_SCOPED_FUNCTION_PARAMS LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_SCOPED_FUNCTION_PARAMS_I)(0))
+#define LWTRACE_SCOPED_FUNCTION_PARAMS_BY_REF_I(i) (1) typename ::NLWTrace::TParamTraits<TP##i>::TStoreType& p##i = *(ERROR_not_enough_parameters*)(HidePointerOrigin(nullptr))LWTRACE_COMMA
+#define LWTRACE_SCOPED_FUNCTION_PARAMS_BY_REF LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_SCOPED_FUNCTION_PARAMS_BY_REF_I)(0))
+#define LWTRACE_SCOPED_PREPARE_PTRS_I(i) PreparePtr(p##i, P##i);
+#define LWTRACE_SCOPED_PREPARE_PTRS() \
+ do { \
+ FOREACH_PARAMNUM(LWTRACE_SCOPED_PREPARE_PTRS_I) \
+ } while (false)
+#define LWTRACE_SCOPED_PREPARE_PARAMS_I(i, params) params.Param[i].CopyConstruct<typename ::NLWTrace::TParamTraits<TP##i>::TStoreType>(*P##i);
+#define LWTRACE_SCOPED_PREPARE_PARAMS(params) \
+ do { \
+ FOREACH_PARAMNUM(LWTRACE_SCOPED_PREPARE_PARAMS_I, params) \
+ } while (false)
+
+ template <LWTRACE_TEMPLATE_PARAMS>
+ struct TUserProbe;
+
+ template <LWTRACE_TEMPLATE_PARAMS>
+ class TScopedDurationImpl {
+ private:
+ TUserProbe<LWTRACE_TEMPLATE_ARGS>* Probe;
+ ui64 Started;
+ TParams Params;
+
+ public:
+ explicit TScopedDurationImpl(TUserProbe<LWTRACE_TEMPLATE_ARGS>& probe, LWTRACE_SCOPED_FUNCTION_PARAMS) {
+ if (probe.Probe.GetExecutorsCount() > 0) {
+ Probe = &probe;
+ LWTRACE_PREPARE_PARAMS(Params);
+ Started = GetCycleCount();
+ } else {
+ Probe = nullptr;
+ }
+ }
+ ~TScopedDurationImpl() {
+ if (Probe) {
+ if (Probe->Probe.GetExecutorsCount() > 0) {
+ TReadSpinLockGuard g(Probe->Probe.Lock);
+ if (Probe->Probe.GetExecutorsCount() > 0) {
+ ui64 duration = CyclesToDuration(GetCycleCount() - Started).MicroSeconds();
+ Params.Param[0].template CopyConstruct<typename TParamTraits<TP0>::TStoreType>(duration);
+ TOrbit orbit;
+ Probe->Probe.RunExecutors(orbit, Params);
+ }
+ }
+ TUserSignature<LWTRACE_TEMPLATE_ARGS>::DestroyParams(Params);
+ }
+ }
+ };
+
+ // Class representing a specific probe
+ template <LWTRACE_TEMPLATE_PARAMS_NODEF>
+ struct TUserProbe {
+ TProbe Probe;
+
+ inline void operator()(LWTRACE_FUNCTION_PARAMS) {
+ TParams params;
+ LWTRACE_PREPARE_PARAMS(params);
+ Y_DEFER { TUserSignature<LWTRACE_TEMPLATE_ARGS>::DestroyParams(params); };
+
+ TOrbit orbit;
+ Probe.RunExecutors(orbit, params);
+ }
+
+ inline void Run(TOrbit& orbit, LWTRACE_FUNCTION_PARAMS) {
+ TParams params;
+ LWTRACE_PREPARE_PARAMS(params);
+ Y_DEFER { TUserSignature<LWTRACE_TEMPLATE_ARGS>::DestroyParams(params); };
+
+ Probe.RunExecutors(orbit, params);
+ Probe.RunShuttles(orbit, params); // Executors can create shuttles
+ }
+
+ // Required to avoid running executors w/o lock
+ inline void RunShuttles(TOrbit& orbit, LWTRACE_FUNCTION_PARAMS) {
+ TParams params;
+ LWTRACE_PREPARE_PARAMS(params);
+ Probe.RunShuttles(orbit, params);
+ TUserSignature<LWTRACE_TEMPLATE_ARGS>::DestroyParams(params);
+ }
+
+ typedef TScopedDurationImpl<LWTRACE_TEMPLATE_ARGS> TScopedDuration;
+ };
+
+#endif
+
+}
diff --git a/library/cpp/lwtrace/probes.cpp b/library/cpp/lwtrace/probes.cpp
new file mode 100644
index 0000000000..6f19da0cc8
--- /dev/null
+++ b/library/cpp/lwtrace/probes.cpp
@@ -0,0 +1,3 @@
+#include "probes.h"
+
+LWTRACE_DEFINE_PROVIDER(LWTRACE_INTERNAL_PROVIDER)
diff --git a/library/cpp/lwtrace/probes.h b/library/cpp/lwtrace/probes.h
new file mode 100644
index 0000000000..68810bd118
--- /dev/null
+++ b/library/cpp/lwtrace/probes.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "all.h"
+
+#define LWTRACE_INTERNAL_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \
+ PROBE(PerfReport, GROUPS(), \
+ TYPES(double, double, double, double), \
+ NAMES("probeShare", "probeMinMs", "probeMaxMs", "probeAvgMs")) \
+ PROBE(DeserializationError, GROUPS("LWTraceError"), \
+ TYPES(TString, TString), \
+ NAMES("probeName", "providerName")) \
+ PROBE(Fork, GROUPS(), \
+ TYPES(ui64), \
+ NAMES("spanId")) \
+ PROBE(Join, GROUPS(), \
+ TYPES(ui64, ui64), \
+ NAMES("spanId", "trackLength")) \
+ PROBE(OrbitIsUsedConcurrentlyError, GROUPS("LWTraceError"), \
+ TYPES(TString), \
+ NAMES("backtrace")) \
+ /**/
+
+LWTRACE_DECLARE_PROVIDER(LWTRACE_INTERNAL_PROVIDER)
diff --git a/library/cpp/lwtrace/protos/lwtrace.proto b/library/cpp/lwtrace/protos/lwtrace.proto
new file mode 100644
index 0000000000..0051095719
--- /dev/null
+++ b/library/cpp/lwtrace/protos/lwtrace.proto
@@ -0,0 +1,266 @@
+/*
+ * This file defines language for trace queries and serialization format for trace logs
+ */
+syntax = "proto3";
+
+package NLWTrace;
+
+option go_package = "a.yandex-team.ru/library/cpp/lwtrace/protos";
+
+message TProbeDesc {
+ string Name = 1; // Use either name+provider
+ string Provider = 3;
+ string Group = 2; // or group
+}
+
+enum EOperatorType {
+ OT_EQ = 0;
+ OT_NE = 1;
+ OT_LT = 2;
+ OT_LE = 3;
+ OT_GT = 4;
+ OT_GE = 5;
+}
+
+message TArgument {
+ string Param = 1;
+ bytes Value = 2;
+ string Variable = 3;
+}
+
+message TOperator {
+ EOperatorType Type = 1;
+ repeated TArgument Argument = 8;
+}
+
+message TPredicate {
+ repeated TOperator Operators = 1; // All operators are combined using logical AND
+ double SampleRate = 2; // value 1.0 means trigger actions on 100% events (do not sample if value is not set)
+}
+
+message TLogAction {
+ bool DoNotLogParams = 2;
+ bool LogTimestamp = 3;
+ uint32 MaxRecords = 4; // Do not write more than MaxRecords records to the log (count from the trace beginning, not start)
+}
+
+message TPrintToStderrAction {
+}
+
+message TKillAction {
+}
+
+message TSleepAction {
+ uint64 NanoSeconds = 1;
+}
+
+message TCustomAction {
+ string Name = 1;
+ repeated string Opts = 2;
+}
+
+enum EStatementType {
+ ST_MOV = 0;
+ ST_ADD = 1;
+ ST_SUB = 2;
+ ST_MUL = 3;
+ ST_DIV = 4;
+ ST_MOD = 5;
+ ST_ADD_EQ = 6;
+ ST_SUB_EQ = 7;
+ ST_INC = 8;
+ ST_DEC = 9;
+}
+
+message TStatementAction {
+ EStatementType Type = 1;
+ repeated TArgument Argument = 2;
+}
+
+message TRunLogShuttleAction {
+ bool Ignore = 1;
+ uint64 ShuttlesCount = 2;
+ uint64 MaxTrackLength = 3;
+}
+
+message TEditLogShuttleAction {
+ bool Ignore = 1;
+}
+
+message TDropLogShuttleAction {
+}
+
+message TAction {
+ TLogAction LogAction = 2;
+ TPrintToStderrAction PrintToStderrAction = 3;
+ TCustomAction CustomAction = 4;
+ TKillAction KillAction = 6;
+ TSleepAction SleepAction = 7;
+ TStatementAction StatementAction = 8;
+
+ TRunLogShuttleAction RunLogShuttleAction = 100;
+ TEditLogShuttleAction EditLogShuttleAction = 101;
+ TDropLogShuttleAction DropLogShuttleAction = 102;
+}
+
+message TBlock {
+ TProbeDesc ProbeDesc = 1;
+ TPredicate Predicate = 2;
+ repeated TAction Action = 3;
+}
+
+message TQuery {
+ // Number of events to hold for every thread in cyclic buffer
+ // (Won't be used if LogDurationUs is set to non-zero value)
+ uint32 PerThreadLogSize = 1;
+
+ // Hold events for last Duration microseconds
+ // (If zero, than per-thread cyclic buffer will be used to store events)
+ uint64 LogDurationUs = 2;
+
+ repeated TBlock Blocks = 3;
+}
+
+message TDashboard {
+ message TCell {
+ optional string Url = 1;
+ optional string Title = 2;
+ optional string Text = 3;
+ optional uint32 RowSpan = 4;
+ optional uint32 ColSpan = 5;
+ }
+
+ message TRow {
+ repeated TCell Cells = 1;
+ }
+
+ optional string Name = 1;
+ optional string Description = 2;
+ repeated TRow Rows = 3;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+// Serialization format for trace logs //
+//////////////////////////////////////////////////////////////////////////////////////////////
+enum EParamTypePb {
+ PT_UNKNOWN = 0;
+ PT_I64 = 1;
+ PT_Ui64 = 2;
+ PT_Double = 3;
+ PT_Str = 4;
+ PT_Symbol = 5;
+ PT_Check = 6;
+}
+
+message TEventPb {
+ string Name = 1;
+ repeated string Groups = 2; // First group is provider
+ repeated EParamTypePb ParamTypes = 3;
+ repeated string ParamNames = 4;
+}
+
+message TLogItemPb {
+ uint64 Thread = 1;
+ string Name = 2;
+ string Provider = 3;
+ repeated bytes Params = 4;
+ uint64 Timestamp = 5; // microseconds since epoch
+ uint64 TimestampCycles = 6; // cycles since machine boot
+}
+
+message TThreadLogPb {
+ uint64 ThreadId = 1;
+ repeated TLogItemPb LogItems = 2;
+}
+
+message TLogPb {
+ // Trace info
+ string Name = 1;
+ string Description = 2;
+ uint64 EventsCount = 3;
+ uint64 CrtTime = 4; // Log creation time (seconds since epoch)
+
+ // Traced host info
+ string Hostname = 101;
+
+ // Traced process info
+ string ProcessName = 201;
+ bytes CommandLine = 202;
+ uint64 ProcessStartTime = 203;
+ uint64 Pid = 204;
+ string VersionInfo = 205; // Svn info
+
+ // Trace query and results
+ TQuery Query = 301;
+ repeated TEventPb Events = 302;
+ repeated TThreadLogPb ThreadLogs = 303;
+}
+
+message TShuttlePb {
+ repeated TLogPb Parts = 1;
+ TQuery Query = 2;
+}
+
+message TOrbitPb {
+ repeated TShuttlePb Shuttles = 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Trace parameter.
+
+message TTraceParam
+{
+ // Value.
+ oneof Value
+ {
+ int64 IntValue = 2;
+ uint64 UintValue = 3;
+ double DoubleValue = 4;
+ bytes StrValue = 5;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Trace Event .
+
+message TTraceEvent
+{
+ // Probe name.
+ string Name = 1;
+
+ // Provider name.
+ string Provider = 2;
+
+ // Probe parameters.
+ repeated TTraceParam Params = 3;
+
+ // Event timestamp in nanosec since epoch.
+ uint64 TimestampNanosec = 4;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Shuttle trace .
+
+message TShuttleTrace
+{
+ // Request events.
+ repeated TTraceEvent Events = 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Trace request.
+
+message TTraceRequest
+{
+ // trace id of remote trace session
+ bool IsTraced = 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Trace response.
+
+message TTraceResponse
+{
+ // traced events
+ TShuttleTrace Trace = 1;
+}
diff --git a/library/cpp/lwtrace/protos/ya.make b/library/cpp/lwtrace/protos/ya.make
new file mode 100644
index 0000000000..503d5e515f
--- /dev/null
+++ b/library/cpp/lwtrace/protos/ya.make
@@ -0,0 +1,11 @@
+PROTO_LIBRARY()
+
+OWNER(serxa)
+
+INCLUDE_TAGS(GO_PROTO)
+
+SRCS(
+ lwtrace.proto
+)
+
+END()
diff --git a/library/cpp/lwtrace/rwspinlock.h b/library/cpp/lwtrace/rwspinlock.h
new file mode 100644
index 0000000000..7c518ec49e
--- /dev/null
+++ b/library/cpp/lwtrace/rwspinlock.h
@@ -0,0 +1,88 @@
+#pragma once
+
+#include <util/system/spinlock.h>
+
+// State can be one of:
+// 0) [NOT_USED] State = 0:
+// * any reader can acquire lock (State += 2: -> READING)
+// * one writer can acquire lock (State = -1: -> WRITING)
+// 1) [READING] even number:
+// * State/2 = number of active readers
+// * no writers are waiting
+// * any reader can aqcuire lock (State += 2: -> READING)
+// * active readers can release lock (State -= 2)
+// * one writer can acquire lock (State += 1: -> WAITING)
+// 2) [WAITING] odd number > 0:
+// * (State-1)/2 = number of active readers
+// * no more readers/writers can acquire lock
+// * active readers can release lock (State -= 2: -> WAITING)
+// * exactly one writer is waiting for active readers to release lock
+// * if no more active readers left (State == 1) waiting writer acquires lock (State = -1: -> WRITING)
+// 3) [WRITING] State = -1
+// * exactly one active writer
+// * no active readers
+// * no more readers/writers can acquire lock
+// * writer can release lock (State = 0: -> READING)
+
+struct TRWSpinLock {
+ TAtomic State; // must be initialized by 'TRWSpinLock myLock = {0};' construction
+
+ void Init() noexcept {
+ State = 0;
+ }
+
+ void AcquireRead() noexcept {
+ while (true) {
+ TAtomic a = AtomicGet(State);
+ if ((a & 1) == 0 && AtomicCas(&State, a + 2, a)) {
+ break;
+ }
+ SpinLockPause();
+ }
+ }
+
+ void ReleaseRead() noexcept {
+ AtomicAdd(State, -2);
+ }
+
+ void AcquireWrite() noexcept {
+ while (true) {
+ TAtomic a = AtomicGet(State);
+ if ((a & 1) == 0 && AtomicCas(&State, a + 1, a)) {
+ break;
+ }
+ SpinLockPause();
+ }
+
+ while (!AtomicCas(&State, TAtomicBase(-1), 1)) {
+ SpinLockPause();
+ }
+ }
+
+ void ReleaseWrite() noexcept {
+ AtomicSet(State, 0);
+ }
+};
+
+struct TRWSpinLockReadOps {
+ static inline void Acquire(TRWSpinLock* t) noexcept {
+ t->AcquireRead();
+ }
+
+ static inline void Release(TRWSpinLock* t) noexcept {
+ t->ReleaseRead();
+ }
+};
+
+struct TRWSpinLockWriteOps {
+ static inline void Acquire(TRWSpinLock* t) noexcept {
+ t->AcquireWrite();
+ }
+
+ static inline void Release(TRWSpinLock* t) noexcept {
+ t->ReleaseWrite();
+ }
+};
+
+using TReadSpinLockGuard = TGuard<TRWSpinLock, TRWSpinLockReadOps>;
+using TWriteSpinLockGuard = TGuard<TRWSpinLock, TRWSpinLockWriteOps>;
diff --git a/library/cpp/lwtrace/shuttle.cpp b/library/cpp/lwtrace/shuttle.cpp
new file mode 100644
index 0000000000..6ef6982aea
--- /dev/null
+++ b/library/cpp/lwtrace/shuttle.cpp
@@ -0,0 +1,20 @@
+#include "shuttle.h"
+
+#include "probes.h"
+
+#include <util/system/backtrace.h>
+#include <util/stream/str.h>
+
+namespace NLWTrace {
+ LWTRACE_USING(LWTRACE_INTERNAL_PROVIDER);
+
+ inline TString CurrentBackTrace() {
+ TStringStream ss;
+ FormatBackTrace(&ss);
+ return ss.Str();
+ }
+
+ void TOrbit::LockFailed() {
+ LWPROBE(OrbitIsUsedConcurrentlyError, CurrentBackTrace());
+ }
+} // namespace NLWTrace
diff --git a/library/cpp/lwtrace/shuttle.h b/library/cpp/lwtrace/shuttle.h
new file mode 100644
index 0000000000..85c6e4da61
--- /dev/null
+++ b/library/cpp/lwtrace/shuttle.h
@@ -0,0 +1,358 @@
+#pragma once
+
+#include "event.h"
+
+#include <library/cpp/containers/stack_vector/stack_vec.h>
+
+#include <util/generic/ptr.h>
+#include <util/system/spinlock.h>
+
+#include <algorithm>
+#include <type_traits>
+
+namespace NLWTrace {
+ struct TProbe;
+
+ class IShuttle;
+ using TShuttlePtr = TIntrusivePtr<IShuttle>;
+
+ // Represents interface of tracing context passing by application between probes
+ class alignas(8) IShuttle: public TThrRefBase {
+ private:
+ ui64 TraceIdx;
+ ui64 SpanId;
+ ui64 ParentSpanId = 0;
+ TAtomic Status = 0;
+ static constexpr ui64 DeadFlag = 0x1ull;
+ TShuttlePtr Next;
+
+ public:
+ explicit IShuttle(ui64 traceIdx, ui64 spanId)
+ : TraceIdx(traceIdx)
+ , SpanId(spanId)
+ {
+ }
+
+ virtual ~IShuttle() {
+ }
+
+ ui64 GetTraceIdx() const {
+ return TraceIdx;
+ }
+
+ ui64 GetSpanId() const {
+ return SpanId;
+ }
+
+ ui64 GetParentSpanId() const {
+ return ParentSpanId;
+ }
+
+ void SetParentSpanId(ui64 parentSpanId) {
+ ParentSpanId = parentSpanId;
+ }
+
+ template <class F, class R>
+ R UnlessDead(F func, R dead) {
+ while (true) {
+ ui64 status = AtomicGet(Status);
+ if (status & DeadFlag) {
+ return dead;
+ }
+ if (AtomicCas(&Status, status + 2, status)) {
+ R result = func();
+ ATOMIC_COMPILER_BARRIER();
+ AtomicSub(Status, 2);
+ return result;
+ }
+ }
+ }
+
+ template <class F>
+ void UnlessDead(F func) {
+ while (true) {
+ ui64 status = AtomicGet(Status);
+ if (status & DeadFlag) {
+ return;
+ }
+ if (AtomicCas(&Status, status + 2, status)) {
+ func();
+ ATOMIC_COMPILER_BARRIER();
+ AtomicSub(Status, 2);
+ return;
+ }
+ }
+ }
+
+ void Serialize(TShuttleTrace& msg) {
+ UnlessDead([&] {
+ DoSerialize(msg);
+ });
+ }
+
+ // Returns false iff shuttle should be destroyed
+ bool AddProbe(TProbe* probe, const TParams& params, ui64 timestamp = 0) {
+ return UnlessDead([&] {
+ return DoAddProbe(probe, params, timestamp);
+ }, false);
+ }
+
+ // Track object was destroyed
+ void EndOfTrack() {
+ if (Next) {
+ Next->EndOfTrack();
+ Next.Reset();
+ }
+ UnlessDead([&] {
+ DoEndOfTrack();
+ });
+ }
+
+ // Shuttle was dropped from orbit
+ TShuttlePtr Drop() {
+ UnlessDead([&] {
+ DoDrop();
+ });
+ return Detach(); // Detached from orbit on Drop
+ }
+
+ TShuttlePtr Detach() {
+ TShuttlePtr result;
+ result.Swap(Next);
+ return result;
+ }
+
+ // Trace session was destroyed
+ void Kill() {
+ AtomicAdd(Status, 1); // Sets DeadFlag
+ while (AtomicGet(Status) != 1) { // Wait until any vcall is over
+ SpinLockPause();
+ }
+ // After this point all virtual calls on shuttle are disallowed
+ ATOMIC_COMPILER_BARRIER();
+ }
+
+ const TShuttlePtr& GetNext() const {
+ return Next;
+ }
+
+ TShuttlePtr& GetNext() {
+ return Next;
+ }
+
+ void SetNext(const TShuttlePtr& next) {
+ Next = next;
+ }
+
+ bool Fork(TShuttlePtr& child) {
+ return UnlessDead([&] {
+ return DoFork(child);
+ }, true);
+ }
+
+ bool Join(TShuttlePtr& child) {
+ return UnlessDead([&] {
+ return DoJoin(child);
+ }, false);
+ }
+
+ bool IsDead() {
+ return AtomicGet(Status) & DeadFlag;
+ }
+
+ protected:
+ virtual bool DoAddProbe(TProbe* probe, const TParams& params, ui64 timestamp) = 0;
+ virtual void DoEndOfTrack() = 0;
+ virtual void DoDrop() = 0;
+ virtual void DoSerialize(TShuttleTrace& msg) = 0;
+ virtual bool DoFork(TShuttlePtr& child) = 0;
+ virtual bool DoJoin(const TShuttlePtr& child) = 0;
+ };
+
+ // Not thread-safe orbit
+ // Orbit should not be used concurrenty, lock is used
+ // to ensure this is the case and avoid race condition if not.
+ class TOrbit {
+ private:
+ TShuttlePtr HeadNoLock;
+ public:
+ TOrbit() = default;
+ TOrbit(const TOrbit&) = delete;
+ TOrbit(TOrbit&&) = default;
+
+ TOrbit& operator=(const TOrbit&) = delete;
+ TOrbit& operator=(TOrbit&&) = default;
+
+ ~TOrbit() {
+ Reset();
+ }
+
+ void Reset() {
+ NotConcurrent([] (TShuttlePtr& head) {
+ if (head) {
+ head->EndOfTrack();
+ head.Reset();
+ }
+ });
+ }
+
+ // Checks if there is at least one shuttle in orbit
+ // NOTE: used by every LWTRACK macro check, so keep it optimized - do not lock
+ bool HasShuttles() const {
+ return HeadNoLock.Get();
+ }
+
+ void AddShuttle(const TShuttlePtr& shuttle) {
+ NotConcurrent([&] (TShuttlePtr& head) {
+ Y_VERIFY(!shuttle->GetNext());
+ shuttle->SetNext(head);
+ head = shuttle;
+ });
+ }
+
+ // Moves every shuttle from `orbit' into this
+ void Take(TOrbit& orbit) {
+ NotConcurrent([&] (TShuttlePtr& head) {
+ orbit.NotConcurrent([&] (TShuttlePtr& oHead) {
+ TShuttlePtr* ref = &oHead;
+ if (ref->Get()) {
+ while (TShuttlePtr& next = (*ref)->GetNext()) {
+ ref = &next;
+ }
+ (*ref)->SetNext(head);
+ head.Swap(oHead);
+ oHead.Reset();
+ }
+ });
+ });
+ }
+
+ void AddProbe(TProbe* probe, const TParams& params, ui64 timestamp = 0) {
+ NotConcurrent([&] (TShuttlePtr& head) {
+ TShuttlePtr* ref = &head;
+ while (IShuttle* s = ref->Get()) {
+ if (!s->AddProbe(probe, params, timestamp)) { // Shuttle self-destructed
+ *ref = s->Drop(); // May destroy shuttle
+ } else {
+ ref = &s->GetNext(); // Keep shuttle
+ }
+ }
+ });
+ }
+
+ template <class TFunc>
+ void ForEachShuttle(ui64 traceIdx, TFunc&& func) {
+ NotConcurrent([&] (TShuttlePtr& head) {
+ TShuttlePtr* ref = &head;
+ while (IShuttle* s = ref->Get()) {
+ if (s->GetTraceIdx() == traceIdx && !func(s)) { // Shuttle self-destructed
+ *ref = s->Drop(); // May destroy shuttle
+ } else {
+ ref = &s->GetNext(); // Keep shuttle
+ }
+ }
+ });
+ }
+
+ void Serialize(ui64 traceIdx, TShuttleTrace& msg) {
+ ForEachShuttle(traceIdx, [&] (NLWTrace::IShuttle* shuttle) {
+ shuttle->Serialize(msg);
+ return false;
+ });
+ }
+
+ bool HasShuttle(ui64 traceIdx) {
+ return NotConcurrent([=] (TShuttlePtr& head) {
+ TShuttlePtr ref = head;
+ while (IShuttle* s = ref.Get()) {
+ if (s->GetTraceIdx() == traceIdx) {
+ return true;
+ } else {
+ ref = s->GetNext();
+ }
+ }
+ return false;
+ });
+ }
+
+ bool Fork(TOrbit& child) {
+ return NotConcurrent([&] (TShuttlePtr& head) {
+ return child.NotConcurrent([&] (TShuttlePtr& cHead) {
+ bool result = true;
+ TShuttlePtr* ref = &head;
+ while (IShuttle* shuttle = ref->Get()) {
+ if (shuttle->IsDead()) {
+ *ref = shuttle->Drop();
+ } else {
+ result = result && shuttle->Fork(cHead);
+ ref = &shuttle->GetNext();
+ }
+ }
+ return result;
+ });
+ });
+ }
+
+ void Join(TOrbit& child) {
+ NotConcurrent([&] (TShuttlePtr& head) {
+ child.NotConcurrent([&] (TShuttlePtr& cHead) {
+ TShuttlePtr* ref = &head;
+ while (IShuttle* shuttle = ref->Get()) {
+ if (shuttle->IsDead()) {
+ *ref = shuttle->Drop();
+ } else {
+ child.Join(cHead, shuttle);
+ ref = &shuttle->GetNext();
+ }
+ }
+ });
+ });
+ }
+
+ private:
+ static void Join(TShuttlePtr& head, IShuttle* parent) {
+ TShuttlePtr* ref = &head;
+ while (IShuttle* child = ref->Get()) {
+ if (parent->GetTraceIdx() == child->GetTraceIdx() && parent->GetSpanId() == child->GetParentSpanId()) {
+ TShuttlePtr next = child->Detach();
+ parent->Join(*ref);
+ *ref = next;
+ } else {
+ ref = &child->GetNext();
+ }
+ }
+ }
+
+ template <class TFunc>
+ typename std::invoke_result<TFunc, TShuttlePtr&>::type NotConcurrent(TFunc func) {
+ // `HeadNoLock` is binary-copied into local `headCopy` and written with special `locked` value
+ // during not concurrent operations. Not concurrent operations should not work
+ // with `HeadNoLock` directly. Instead `headCopy` is passed into `func` by reference and
+ // after `func()` it is binary-copied back into `HeadNoLock`.
+ static_assert(sizeof(HeadNoLock) == sizeof(TAtomic));
+ TAtomic* headPtr = reinterpret_cast<TAtomic*>(&HeadNoLock);
+ TAtomicBase headCopy = AtomicGet(*headPtr);
+ static constexpr TAtomicBase locked = 0x1ull;
+ if (headCopy != locked && AtomicCas(headPtr, locked, headCopy)) {
+ struct TUnlocker { // to avoid specialization for R=void
+ TAtomic* HeadPtr;
+ TAtomicBase* HeadCopy;
+ ~TUnlocker() {
+ ATOMIC_COMPILER_BARRIER();
+ AtomicSet(*HeadPtr, *HeadCopy);
+ }
+ } scoped{headPtr, &headCopy};
+ return func(*reinterpret_cast<TShuttlePtr*>(&headCopy));
+ } else {
+ LockFailed();
+ return typename std::invoke_result<TFunc, TShuttlePtr&>::type();
+ }
+ }
+
+ void LockFailed();
+ };
+
+ inline size_t HasShuttles(const TOrbit& orbit) {
+ return orbit.HasShuttles();
+ }
+}
diff --git a/library/cpp/lwtrace/signature.h b/library/cpp/lwtrace/signature.h
new file mode 100644
index 0000000000..868bd9bcf2
--- /dev/null
+++ b/library/cpp/lwtrace/signature.h
@@ -0,0 +1,772 @@
+#pragma once
+
+#include "preprocessor.h"
+
+#include <library/cpp/lwtrace/protos/lwtrace.pb.h>
+
+#include <util/generic/cast.h>
+#include <util/generic/string.h>
+#include <util/generic/typetraits.h>
+#include <util/string/builder.h>
+#include <util/string/cast.h>
+#include <util/string/printf.h>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_enum_reflection.h>
+
+#include <library/cpp/lwtrace/protos/lwtrace.pb.h>
+
+#include <type_traits>
+
+namespace NLWTrace {
+ // Class to hold parameter values parsed from trace query predicate operators
+ template <class T>
+ struct TParamConv {
+ static T FromString(const TString& text) {
+ return ::FromString<T>(text);
+ }
+ static TString ToString(const T& param) {
+ return ::ToString(param);
+ }
+ };
+
+ template <>
+ struct TParamConv<TString const*> {
+ static TString FromString(const TString& text) {
+ return text;
+ }
+ static TString ToString(TString const* param) {
+ return TString(*param);
+ }
+ };
+
+ template <>
+ struct TParamConv<ui8> {
+ static ui8 FromString(const TString& text) {
+ return (ui8)::FromString<ui16>(text);
+ }
+ static TString ToString(ui8 param) {
+ return ::ToString((ui16)param);
+ }
+ };
+
+ template <>
+ struct TParamConv<i8> {
+ static i8 FromString(const TString& text) {
+ return (i8)::FromString<i16>(text);
+ }
+ static TString ToString(i8 param) {
+ return ::ToString((i16)param);
+ }
+ };
+
+ template <>
+ struct TParamConv<double> {
+ static double FromString(const TString& text) {
+ return ::FromString<double>(text);
+ }
+ static TString ToString(double param) {
+ return Sprintf("%.6lf", param);
+ }
+ };
+
+ // Fake parameter type used as a placeholder for not used parameters (above the number of defined params for a specific probe)
+ class TNil {
+ };
+
+ // Struct that holds and handles a value of parameter of any supported type.
+ struct TParam {
+ char Data[LWTRACE_MAX_PARAM_SIZE];
+
+ template <class T>
+ const T& Get() const {
+ return *reinterpret_cast<const T*>(Data);
+ }
+
+ template <class T>
+ T& Get() {
+ return *reinterpret_cast<T*>(Data);
+ }
+
+ template <class T>
+ void DefaultConstruct() {
+ new (&Data) T();
+ }
+
+ template <class T>
+ void CopyConstruct(const T& other) {
+ new (&Data) T(other);
+ }
+
+ template <class T>
+ void Destruct() {
+ Get<T>().~T();
+ }
+ };
+
+ template <>
+ inline void TParam::DefaultConstruct<TNil>() {
+ }
+
+ template <>
+ inline void TParam::CopyConstruct<TNil>(const TNil&) {
+ }
+
+ template <>
+ inline void TParam::Destruct<TNil>() {
+ }
+
+ class TTypedParam {
+ private:
+ EParamTypePb Type;
+ TParam Param; // Contains garbage if PT_UNKNOWN
+ public:
+ TTypedParam()
+ : Type(PT_UNKNOWN)
+ {
+ }
+
+ explicit TTypedParam(EParamTypePb type)
+ : Type(type)
+ {
+ switch (Type) {
+#define FOREACH_PARAMTYPE_MACRO(n, t, v) \
+ case PT_##v: \
+ Param.DefaultConstruct<t>(); \
+ return;
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+#undef FOREACH_PARAMTYPE_MACRO
+ case PT_UNKNOWN:
+ return;
+ default:
+ Y_FAIL("unknown param type");
+ }
+ }
+
+ template <class T>
+ explicit TTypedParam(const T& x, EParamTypePb type = PT_UNKNOWN)
+ : Type(type)
+ {
+ Param.CopyConstruct<T>(x);
+ }
+
+#define FOREACH_PARAMTYPE_MACRO(n, t, v) \
+ explicit TTypedParam(const t& x) \
+ : Type(PT_##v) { \
+ Param.CopyConstruct<t>(x); \
+ }
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+#undef FOREACH_PARAMTYPE_MACRO
+
+ TTypedParam(const TTypedParam& o) {
+ Assign(o);
+ }
+
+ TTypedParam& operator=(const TTypedParam& o) {
+ Reset();
+ Assign(o);
+ return *this;
+ }
+
+ void Assign(const TTypedParam& o) {
+ Type = o.Type;
+ switch (Type) {
+#define FOREACH_PARAMTYPE_MACRO(n, t, v) \
+ case PT_##v: \
+ Param.CopyConstruct<t>(o.Param.Get<t>()); \
+ return;
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+#undef FOREACH_PARAMTYPE_MACRO
+ case PT_UNKNOWN:
+ return;
+ default:
+ Y_FAIL("unknown param type");
+ }
+ }
+
+ TTypedParam(TTypedParam&& o)
+ : Type(o.Type)
+ , Param(o.Param)
+ {
+ o.Type = PT_UNKNOWN; // To avoid Param destroy by source object dtor
+ }
+
+ TTypedParam(EParamTypePb type, const TParam& param)
+ : Type(type)
+ {
+ Y_UNUSED(param); // for disabled lwtrace
+ switch (Type) {
+#define FOREACH_PARAMTYPE_MACRO(n, t, v) \
+ case PT_##v: \
+ Param.CopyConstruct<t>(param.Get<t>()); \
+ return;
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+#undef FOREACH_PARAMTYPE_MACRO
+ case PT_UNKNOWN:
+ return;
+ default:
+ Y_FAIL("unknown param type");
+ }
+ }
+
+ ~TTypedParam() {
+ Reset();
+ }
+
+ void Reset() {
+ switch (Type) {
+#define FOREACH_PARAMTYPE_MACRO(n, t, v) \
+ case PT_##v: \
+ Param.Destruct<t>(); \
+ return;
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+#undef FOREACH_PARAMTYPE_MACRO
+ case PT_UNKNOWN:
+ return;
+ default:
+ Y_FAIL("unknown param type");
+ }
+ Type = PT_UNKNOWN;
+ }
+
+ bool operator==(const TTypedParam& rhs) const {
+ if (Y_LIKELY(Type == rhs.Type)) {
+ switch (Type) {
+#define FOREACH_PARAMTYPE_MACRO(n, t, v) \
+ case PT_##v: \
+ return Param.Get<t>() == rhs.Param.Get<t>();
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+#undef FOREACH_PARAMTYPE_MACRO
+ case PT_UNKNOWN:
+ return false; // All unknowns are equal
+ default:
+ Y_FAIL("unknown param type");
+ }
+ } else {
+ return false;
+ }
+ }
+ bool operator!=(const TTypedParam& rhs) const {
+ return !operator==(rhs);
+ }
+
+ bool operator<(const TTypedParam& rhs) const {
+ if (Y_LIKELY(Type == rhs.Type)) {
+ switch (Type) {
+#define FOREACH_PARAMTYPE_MACRO(n, t, v) \
+ case PT_##v: \
+ return Param.Get<t>() < rhs.Param.Get<t>();
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+#undef FOREACH_PARAMTYPE_MACRO
+ case PT_UNKNOWN:
+ return false; // All unknowns are equal
+ default:
+ Y_FAIL("unknown param type");
+ }
+ } else {
+ return Type < rhs.Type;
+ }
+ }
+
+ bool operator<=(const TTypedParam& rhs) const {
+ if (Y_LIKELY(Type == rhs.Type)) {
+ switch (Type) {
+#define FOREACH_PARAMTYPE_MACRO(n, t, v) \
+ case PT_##v: \
+ return Param.Get<t>() <= rhs.Param.Get<t>();
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+#undef FOREACH_PARAMTYPE_MACRO
+ case PT_UNKNOWN:
+ return true; // All unknowns are equal
+ default:
+ Y_FAIL("unknown param type");
+ }
+ } else {
+ return Type < rhs.Type;
+ }
+ }
+
+ bool operator>(const TTypedParam& rhs) const {
+ return !operator<=(rhs);
+ }
+ bool operator>=(const TTypedParam& rhs) const {
+ return !operator<(rhs);
+ }
+
+ EParamTypePb GetType() const {
+ return Type;
+ }
+ const TParam& GetParam() const {
+ return Param;
+ }
+ };
+
+ class TLiteral {
+ private:
+ TTypedParam Values[EParamTypePb_ARRAYSIZE];
+
+ public:
+ explicit TLiteral(const TString& text) {
+ Y_UNUSED(text); /* That's for windows, where we have lwtrace disabled. */
+
+#define FOREACH_PARAMTYPE_MACRO(n, t, v) \
+ try { \
+ Values[PT_##v] = TTypedParam(TParamConv<t>::FromString(text)); \
+ } catch (...) { \
+ Values[PT_##v] = TTypedParam(); \
+ } \
+ /**/
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+#undef FOREACH_PARAMTYPE_MACRO
+ }
+
+ TLiteral() {
+ }
+
+ TLiteral(const TLiteral& o) {
+ for (size_t i = 0; i < EParamTypePb_ARRAYSIZE; i++) {
+ Values[i] = o.Values[i];
+ }
+ }
+
+ TLiteral& operator=(const TLiteral& o) {
+ for (size_t i = 0; i < EParamTypePb_ARRAYSIZE; i++) {
+ Values[i] = o.Values[i];
+ }
+ return *this;
+ }
+
+ const TTypedParam& GetValue(EParamTypePb type) const {
+ return Values[type];
+ }
+
+ bool operator==(const TTypedParam& rhs) const {
+ return Values[rhs.GetType()] == rhs;
+ }
+ bool operator!=(const TTypedParam& rhs) const {
+ return !operator==(rhs);
+ }
+
+ bool operator<(const TTypedParam& rhs) const {
+ return Values[rhs.GetType()] < rhs;
+ }
+
+ bool operator<=(const TTypedParam& rhs) const {
+ return Values[rhs.GetType()] <= rhs;
+ }
+
+ bool operator>(const TTypedParam& rhs) const {
+ return !operator<=(rhs);
+ }
+ bool operator>=(const TTypedParam& rhs) const {
+ return !operator<(rhs);
+ }
+ };
+
+ inline bool operator==(const TTypedParam& lhs, const TLiteral& rhs) {
+ return lhs == rhs.GetValue(lhs.GetType());
+ }
+ inline bool operator!=(const TTypedParam& lhs, const TLiteral& rhs) {
+ return !operator==(lhs, rhs);
+ }
+
+ inline bool operator<(const TTypedParam& lhs, const TLiteral& rhs) {
+ return lhs < rhs.GetValue(lhs.GetType());
+ }
+
+ inline bool operator<=(const TTypedParam& lhs, const TLiteral& rhs) {
+ return lhs <= rhs.GetValue(lhs.GetType());
+ }
+
+ inline bool operator>(const TTypedParam& lhs, const TLiteral& rhs) {
+ return !operator<=(lhs, rhs);
+ }
+ inline bool operator>=(const TTypedParam& lhs, const TLiteral& rhs) {
+ return !operator<(lhs, rhs);
+ }
+
+ // Struct that holds and handles all parameter values of different supported types
+ struct TParams {
+ TParam Param[LWTRACE_MAX_PARAMS];
+ };
+
+ using TSerializedParams = google::protobuf::RepeatedPtrField<NLWTrace::TTraceParam>;
+
+ // Represents a common class for all function "signatures" (parameter types and names).
+ // Provides non-virtual interface to handle the signature and (emulated) virtual interface to handle TParams corresponding to the signature
+ struct TSignature {
+ const char** ParamTypes;
+ const char* ParamNames[LWTRACE_MAX_PARAMS + 1];
+ size_t ParamCount;
+
+ // Virtual table
+ void (*SerializeParamsFunc)(const TParams& params, TString* values);
+ void (*CloneParamsFunc)(TParams& newParams, const TParams& oldParams);
+ void (*DestroyParamsFunc)(TParams& params);
+ void (*SerializeToPbFunc)(const TParams& params, TSerializedParams& arr);
+ bool (*DeserializeFromPbFunc)(TParams& params, const TSerializedParams& arr);
+
+ // Virtual calls emulation
+ void SerializeParams(const TParams& params, TString* values) const {
+ (*SerializeParamsFunc)(params, values);
+ }
+
+ void CloneParams(TParams& newParams, const TParams& oldParams) const {
+ (*CloneParamsFunc)(newParams, oldParams);
+ }
+
+ void DestroyParams(TParams& params) const {
+ (*DestroyParamsFunc)(params);
+ }
+
+ void SerializeToPb(const TParams& params, TSerializedParams& arr) const
+ {
+ (*SerializeToPbFunc)(params, arr);
+ }
+
+ bool DeserializeFromPb(TParams& params, const TSerializedParams& arr) const
+ {
+ return (*DeserializeFromPbFunc)(params, arr);
+ }
+
+ void ToProtobuf(TEventPb& pb) const;
+
+ size_t FindParamIndex(const TString& param) const {
+ for (size_t i = 0; i < ParamCount; i++) {
+ if (ParamNames[i] == param) {
+ return i;
+ }
+ }
+ return size_t(-1);
+ }
+ };
+
+#ifndef LWTRACE_DISABLE
+
+ // Implementation. Used for compilation error if not all expected parameters passed to a function call
+ struct ERROR_not_enough_parameters : TNil {};
+
+ // Struct that holds static string with a name of parameter type
+ template <class T>
+ struct TParamType {
+ enum { Supported = 0 };
+ static const char* NameString;
+ };
+
+#define FOREACH_PARAMTYPE_MACRO(n, t, v) \
+ template <> \
+ struct TParamType<t> { \
+ enum { Supported = 1 }; \
+ static const char* NameString; \
+ }; \
+ /**/
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+ FOR_NIL_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+#undef FOREACH_PARAMTYPE_MACRO
+
+ template <class T>
+ struct TParamTraits;
+
+ // Enum types traits impl.
+ template <class TEnum, class = std::enable_if_t<std::is_enum_v<TEnum>>>
+ struct TEnumParamTraitsImpl {
+ using TStoreType = typename TParamTraits<std::underlying_type_t<TEnum>>::TStoreType;
+ using TFuncParam = TEnum;
+
+ inline static void ToString(typename TTypeTraits<TStoreType>::TFuncParam stored, TString* out) {
+ if constexpr (google::protobuf::is_proto_enum<TEnum>::value) {
+ const google::protobuf::EnumValueDescriptor* valueDescriptor = google::protobuf::GetEnumDescriptor<TEnum>()->FindValueByNumber(stored);
+ if (valueDescriptor) {
+ *out = TStringBuilder() << valueDescriptor->name() << " (" << stored << ")";
+ } else {
+ *out = TParamConv<TStoreType>::ToString(stored);
+ }
+ } else {
+ *out = TParamConv<TStoreType>::ToString(stored);
+ }
+ }
+
+ inline static TStoreType ToStoreType(TFuncParam v) {
+ return static_cast<TStoreType>(v);
+ }
+ };
+
+ template <class TCustomType>
+ struct TCustomTraitsImpl {
+ using TStoreType = typename TParamTraits<typename TCustomType::TStoreType>::TStoreType; //see STORE_TYPE_AS
+ using TFuncParam = typename TCustomType::TFuncParam;
+
+ inline static void ToString(typename TTypeTraits<TStoreType>::TFuncParam stored, TString* out) {
+ TCustomType::ToString(stored, out);
+ }
+
+ inline static TStoreType ToStoreType(TFuncParam v) {
+ return TCustomType::ToStoreType(v);
+ }
+ };
+
+ template <class T, bool isEnum>
+ struct TParamTraitsImpl;
+
+ template <class TEnum>
+ struct TParamTraitsImpl<TEnum, true> : TEnumParamTraitsImpl<TEnum> {
+ };
+
+ template <class TCustomType>
+ struct TParamTraitsImpl<TCustomType, false> : TCustomTraitsImpl<TCustomType> {
+ };
+
+ template <class T>
+ struct TParamTraits : TParamTraitsImpl<T, std::is_enum_v<T>> {
+ };
+
+ // Standard stored types traits.
+
+#define STORE_TYPE_AS(input_t, store_as_t) \
+ template <> \
+ struct TParamTraits<input_t> { \
+ using TStoreType = store_as_t; \
+ using TFuncParam = typename TTypeTraits<input_t>::TFuncParam; \
+ \
+ inline static void ToString(typename TTypeTraits<TStoreType>::TFuncParam stored, TString* out) { \
+ *out = TParamConv<TStoreType>::ToString(stored); \
+ } \
+ \
+ inline static TStoreType ToStoreType(TFuncParam v) { \
+ return v; \
+ } \
+ }; \
+ /**/
+ STORE_TYPE_AS(ui8, ui64);
+ STORE_TYPE_AS(i8, i64);
+ STORE_TYPE_AS(ui16, ui64);
+ STORE_TYPE_AS(i16, i64);
+ STORE_TYPE_AS(ui32, ui64);
+ STORE_TYPE_AS(i32, i64);
+ STORE_TYPE_AS(bool, ui64);
+ STORE_TYPE_AS(float, double);
+#define FOREACH_PARAMTYPE_MACRO(n, t, v) STORE_TYPE_AS(t, t)
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+#undef STORE_TYPE_AS
+#undef FOREACH_PARAMTYPE_MACRO
+
+ // Nil type staits.
+ template <>
+ struct TParamTraits<TNil> {
+ using TStoreType = TNil;
+ using TFuncParam = TTypeTraits<TNil>::TFuncParam;
+
+ inline static void ToString(typename TTypeTraits<TNil>::TFuncParam, TString*) {
+ }
+
+ inline static TNil ToStoreType(TFuncParam v) {
+ return v;
+ }
+ };
+
+ inline EParamTypePb ParamTypeToProtobuf(const char* paramType) {
+#define FOREACH_PARAMTYPE_MACRO(n, t, v) \
+ if (strcmp(paramType, n) == 0) { \
+ return PT_##v; \
+ } \
+ /**/
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+#undef FOREACH_PARAMTYPE_MACRO
+ return PT_UNKNOWN;
+ }
+
+ template <typename T>
+ inline void SaveParamToPb(TSerializedParams& msg, const TParam& param);
+
+ template <>
+ inline void SaveParamToPb<TNil>(TSerializedParams& msg, const TParam& param)
+ {
+ Y_UNUSED(msg);
+ Y_UNUSED(param);
+ }
+
+ template <>
+ inline void SaveParamToPb<i64>(TSerializedParams& msg, const TParam& param)
+ {
+ msg.Add()->SetIntValue(param.Get<typename TParamTraits<i64>::TStoreType>());
+ }
+
+ template <>
+ inline void SaveParamToPb<ui64>(TSerializedParams& msg, const TParam& param)
+ {
+ msg.Add()->SetUintValue(param.Get<typename TParamTraits<ui64>::TStoreType>());
+ }
+
+ template <>
+ inline void SaveParamToPb<double>(TSerializedParams& msg, const TParam& param)
+ {
+ msg.Add()->SetDoubleValue(param.Get<typename TParamTraits<double>::TStoreType>());
+ }
+
+ template <>
+ inline void SaveParamToPb<TString>(TSerializedParams& msg, const TParam& param)
+ {
+ msg.Add()->SetStrValue(param.Get<typename TParamTraits<TString>::TStoreType>());
+ }
+
+ template <>
+ inline void SaveParamToPb<TSymbol>(TSerializedParams& msg, const TParam& param)
+ {
+ msg.Add()->SetStrValue(*param.Get<typename TParamTraits<TSymbol>::TStoreType>().Str);
+ }
+
+ template <>
+ inline void SaveParamToPb<TCheck>(TSerializedParams& msg, const TParam& param)
+ {
+ msg.Add()->SetIntValue(param.Get<typename TParamTraits<TCheck>::TStoreType>().Value);
+ }
+
+ template <typename T>
+ inline void LoadParamFromPb(const TTraceParam& msg, TParam& param);
+
+ template <>
+ inline void LoadParamFromPb<i64>(const TTraceParam& msg, TParam& param)
+ {
+ param.DefaultConstruct<i64>();
+ param.Get<i64>() = msg.GetIntValue();
+ }
+
+ template <>
+ inline void LoadParamFromPb<ui64>(const TTraceParam& msg, TParam& param)
+ {
+ param.DefaultConstruct<ui64>();
+ param.Get<ui64>() = msg.GetUintValue();
+ }
+
+ template <>
+ inline void LoadParamFromPb<double>(const TTraceParam& msg, TParam& param)
+ {
+ param.DefaultConstruct<double>();
+ param.Get<double>() = msg.GetDoubleValue();
+ }
+
+ template <>
+ inline void LoadParamFromPb<TCheck>(const TTraceParam& msg, TParam& param)
+ {
+ param.CopyConstruct<TCheck>(TCheck(msg.GetIntValue()));
+ }
+
+ template <>
+ inline void LoadParamFromPb<TSymbol>(const TTraceParam& msg, TParam& param)
+ {
+ Y_UNUSED(msg);
+ Y_UNUSED(param);
+ static TString unsupported("unsupported");
+ // so far TSymbol deserialization is not supported
+ // since it is not used for probes, it is ok
+ param.CopyConstruct<TSymbol>(TSymbol(&unsupported));
+ }
+
+ template <>
+ inline void LoadParamFromPb<TString>(const TTraceParam& msg, TParam& param)
+ {
+ param.DefaultConstruct<TString>();
+ param.Get<TString>() = msg.GetStrValue();
+ }
+
+ template <>
+ inline void LoadParamFromPb<TNil>(const TTraceParam& msg, TParam& param)
+ {
+ Y_UNUSED(msg);
+ Y_UNUSED(param);
+ }
+
+ // Class representing a specific signature
+ template <LWTRACE_TEMPLATE_PARAMS>
+ struct TUserSignature {
+#define FOREACH_PARAMNUM_MACRO(i) static_assert(TParamType<typename TParamTraits<TP##i>::TStoreType>::Supported == 1, "expect TParamType< typename TParamTraits<TP ## i>::TStoreType >::Supported == 1");
+ FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO) // ERROR: unsupported type used as probe/event parameter type
+#undef FOREACH_PARAMNUM_MACRO
+ static const char* ParamTypes[];
+ static const int ParamCount = LWTRACE_COUNT_PARAMS;
+
+ // Implementation of virtual function (TSignature derived classes vtable emulation)
+ inline static void SerializeParams(const TParams& params, TString* values) {
+#define FOREACH_PARAMNUM_MACRO(i) TParamTraits<TP##i>::ToString(params.Param[i].Get<typename TParamTraits<TP##i>::TStoreType>(), values + i);
+ FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO);
+#undef FOREACH_PARAMNUM_MACRO
+ }
+
+ // Implementation of virtual function (TSignature derived classes vtable emulation)
+ inline static void CloneParams(TParams& newParams, const TParams& oldParams) {
+#define FOREACH_PARAMNUM_MACRO(i) newParams.Param[i].CopyConstruct<typename TParamTraits<TP##i>::TStoreType>(oldParams.Param[i].Get<typename TParamTraits<TP##i>::TStoreType>());
+ FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO);
+#undef FOREACH_PARAMNUM_MACRO
+ }
+
+ // Implementation of virtual function (TSignature derived classes vtable emulation)
+ inline static void DestroyParams(TParams& params) {
+#define FOREACH_PARAMNUM_MACRO(i) params.Param[i].Destruct<typename TParamTraits<TP##i>::TStoreType>();
+ FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO);
+#undef FOREACH_PARAMNUM_MACRO
+ }
+
+ // Implementation of virtual function (TSignature derived classes vtable emulation)
+ inline static void SerializeToPb(const TParams& params, TSerializedParams& arr)
+ {
+#define FOREACH_PARAMNUM_MACRO(i) \
+ SaveParamToPb<typename TParamTraits<TP##i>::TStoreType>( \
+ arr, \
+ params.Param[i]); \
+// FOREACH_PARAMNUM_MACRO
+ FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO);
+#undef FOREACH_PARAMNUM_MACRO
+ }
+
+ // Implementation of virtual function (TSignature derived classes vtable emulation)
+ inline static bool DeserializeFromPb(TParams& params, const TSerializedParams& arr) {
+ if (arr.size() != ParamCount) {
+ return false;
+ }
+ if (!ParamCount) {
+ return true;
+ }
+
+ int paramIdx = 0;
+#define FOREACH_PARAMNUM_MACRO(i) \
+ if (paramIdx >= arr.size()) { \
+ return true; \
+ }; \
+ LoadParamFromPb<typename TParamTraits<TP##i>::TStoreType>( \
+ arr.Get(paramIdx), \
+ params.Param[paramIdx]); \
+ ++paramIdx; \
+// FOREACH_PARAMNUM_MACRO
+ FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO);
+#undef FOREACH_PARAMNUM_MACRO
+ return true;
+ }
+ };
+
+ // Array of static strings pointers for names of parameter types in a specific signature
+ template <LWTRACE_TEMPLATE_PARAMS_NODEF>
+ const char* TUserSignature<LWTRACE_TEMPLATE_ARGS>::ParamTypes[] = {
+#define FOREACH_PARAMNUM_MACRO(i) TParamType<typename TParamTraits<TP##i>::TStoreType>::NameString,
+ FOREACH_PARAMNUM(FOREACH_PARAMNUM_MACRO) nullptr
+#undef FOREACH_PARAMNUM_MACRO
+ };
+
+ inline void TSignature::ToProtobuf(TEventPb& pb) const {
+ for (size_t i = 0; i < ParamCount; i++) {
+ pb.AddParamTypes(ParamTypeToProtobuf(ParamTypes[i]));
+ pb.AddParamNames(ParamNames[i]);
+ }
+ }
+
+#else
+
+ inline void TSignature::ToProtobuf(TEventPb&) const {
+ }
+
+ inline EParamTypePb ParamTypeToProtobuf(const char*) {
+ return PT_UNKNOWN;
+ }
+
+#endif
+
+}
diff --git a/library/cpp/lwtrace/sleep_action.cpp b/library/cpp/lwtrace/sleep_action.cpp
new file mode 100644
index 0000000000..74977528db
--- /dev/null
+++ b/library/cpp/lwtrace/sleep_action.cpp
@@ -0,0 +1,15 @@
+#include "sleep_action.h"
+
+#include "control.h"
+
+#include <util/system/datetime.h>
+
+#include <stdlib.h>
+
+using namespace NLWTrace;
+using namespace NLWTrace::NPrivate;
+
+bool TSleepActionExecutor::DoExecute(TOrbit&, const TParams&) {
+ NanoSleep(NanoSeconds);
+ return true;
+}
diff --git a/library/cpp/lwtrace/sleep_action.h b/library/cpp/lwtrace/sleep_action.h
new file mode 100644
index 0000000000..26f89bd88c
--- /dev/null
+++ b/library/cpp/lwtrace/sleep_action.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "probe.h"
+
+namespace NLWTrace {
+ namespace NPrivate {
+ class TSleepActionExecutor: public IExecutor {
+ private:
+ ui64 NanoSeconds;
+
+ public:
+ TSleepActionExecutor(const TProbe*, ui64 nanoSeconds)
+ : IExecutor()
+ , NanoSeconds(nanoSeconds)
+ {
+ }
+ bool DoExecute(TOrbit& orbit, const TParams& params) override;
+ };
+
+ }
+}
diff --git a/library/cpp/lwtrace/start.cpp b/library/cpp/lwtrace/start.cpp
new file mode 100644
index 0000000000..121d5472b6
--- /dev/null
+++ b/library/cpp/lwtrace/start.cpp
@@ -0,0 +1,69 @@
+#include "start.h"
+
+#include "all.h"
+
+#include <google/protobuf/text_format.h>
+
+#include <util/generic/singleton.h>
+#include <util/stream/file.h>
+#include <util/stream/output.h>
+#include <util/system/env.h>
+
+#include <stdlib.h>
+
+using namespace NLWTrace;
+
+namespace {
+ struct TTraceManagerHolder {
+ TManager TraceManager;
+ TTraceManagerHolder()
+ : TraceManager(*Singleton<TProbeRegistry>(), true)
+ {
+ }
+ };
+
+ void TraceFromEnv(TString path) {
+ TString script = TUnbufferedFileInput(path).ReadAll();
+ TQuery query;
+ bool ok = google::protobuf::TextFormat::ParseFromString(script, &query);
+ Y_VERIFY(ok, "failed to parse protobuf");
+ Singleton<TTraceManagerHolder>()->TraceManager.New("env", query);
+ }
+
+} // anonymous namespace
+
+void NLWTrace::StartLwtraceFromEnv() {
+ static bool started = false;
+ if (started) {
+ return;
+ } else {
+ started = true;
+ }
+
+ TString path = GetEnv("LWTRACE");
+ if (!path) {
+ return;
+ }
+
+ try {
+ TraceFromEnv(path);
+ } catch (...) {
+ Cerr << "failed to load lwtrace script: " << CurrentExceptionMessage() << "\n";
+ abort();
+ }
+}
+
+void NLWTrace::StartLwtraceFromEnv(std::function<void(TManager&)> prepare) {
+ TString path = GetEnv("LWTRACE");
+ if (Y_LIKELY(!path)) {
+ return;
+ }
+
+ try {
+ prepare(Singleton<TTraceManagerHolder>()->TraceManager);
+ TraceFromEnv(path);
+ } catch (...) {
+ Cerr << "failed to load lwtrace script: " << CurrentExceptionMessage() << "\n";
+ abort();
+ }
+}
diff --git a/library/cpp/lwtrace/start.h b/library/cpp/lwtrace/start.h
new file mode 100644
index 0000000000..2755212bff
--- /dev/null
+++ b/library/cpp/lwtrace/start.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <functional>
+
+namespace NLWTrace {
+ class TManager;
+
+ void StartLwtraceFromEnv();
+ void StartLwtraceFromEnv(std::function<void(TManager&)> prepare);
+
+}
diff --git a/library/cpp/lwtrace/stderr_writer.cpp b/library/cpp/lwtrace/stderr_writer.cpp
new file mode 100644
index 0000000000..6e5654c338
--- /dev/null
+++ b/library/cpp/lwtrace/stderr_writer.cpp
@@ -0,0 +1,19 @@
+#include "stderr_writer.h"
+
+#include <util/stream/str.h>
+
+using namespace NLWTrace;
+
+bool TStderrActionExecutor::DoExecute(TOrbit&, const TParams& params) {
+ TString ParamValues[LWTRACE_MAX_PARAMS];
+ Probe->Event.Signature.SerializeParams(params, ParamValues);
+
+ TStringStream ss;
+ ss << Probe->Event.GetProvider() << "." << Probe->Event.Name;
+ for (ui32 i = 0; i < Probe->Event.Signature.ParamCount; ++i) {
+ ss << " " << Probe->Event.Signature.ParamNames[i] << "=" << ParamValues[i];
+ }
+ ss << "\n";
+ Cerr << ss.Str();
+ return true;
+}
diff --git a/library/cpp/lwtrace/stderr_writer.h b/library/cpp/lwtrace/stderr_writer.h
new file mode 100644
index 0000000000..b17fc3136e
--- /dev/null
+++ b/library/cpp/lwtrace/stderr_writer.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "probe.h"
+
+namespace NLWTrace {
+ class TStderrActionExecutor: public IExecutor {
+ private:
+ TProbe* const Probe;
+
+ public:
+ explicit TStderrActionExecutor(TProbe* probe)
+ : Probe(probe)
+ {
+ }
+
+ bool DoExecute(TOrbit& orbit, const TParams& params) override;
+ };
+
+}
diff --git a/library/cpp/lwtrace/symbol.cpp b/library/cpp/lwtrace/symbol.cpp
new file mode 100644
index 0000000000..456652bcd0
--- /dev/null
+++ b/library/cpp/lwtrace/symbol.cpp
@@ -0,0 +1,15 @@
+#include "symbol.h"
+
+#include <util/stream/output.h>
+#include <util/string/cast.h>
+
+template <>
+NLWTrace::TSymbol FromStringImpl(const char*, size_t) {
+ static TString err("ERROR_dynamic_symbol");
+ return NLWTrace::TSymbol(&err);
+}
+
+template <>
+void Out<NLWTrace::TSymbol>(IOutputStream& o, TTypeTraits<NLWTrace::TSymbol>::TFuncParam t) {
+ Out<TString>(o, *t.Str);
+}
diff --git a/library/cpp/lwtrace/symbol.h b/library/cpp/lwtrace/symbol.h
new file mode 100644
index 0000000000..ef9e6cdf94
--- /dev/null
+++ b/library/cpp/lwtrace/symbol.h
@@ -0,0 +1,68 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/string/builder.h>
+#include <util/system/src_location.h>
+
+#define LWTRACE_DEFINE_SYMBOL(variable, text) \
+ static TString variable##_holder(text); \
+ ::NLWTrace::TSymbol variable(&variable##_holder); \
+ /**/
+
+#define LWTRACE_INLINE_SYMBOL(text) \
+ [&] { \
+ static TString _holder(text); \
+ return ::NLWTrace::TSymbol(&_holder); \
+ }() /**/
+
+#define LWTRACE_LOCATION_SYMBOL \
+ [](const char* func) { \
+ static TString _holder(TStringBuilder() << func << " (" << __LOCATION__ << ")"); \
+ return ::NLWTrace::TSymbol(&_holder); \
+ }(Y_FUNC_SIGNATURE) /**/
+
+namespace NLWTrace {
+ struct TSymbol {
+ TString* Str;
+
+ TSymbol()
+ : Str(nullptr)
+ {
+ }
+
+ explicit TSymbol(TString* str)
+ : Str(str)
+ {
+ }
+
+ TSymbol& operator=(const TSymbol& o) {
+ Str = o.Str;
+ return *this;
+ }
+
+ TSymbol(const TSymbol& o)
+ : Str(o.Str)
+ {
+ }
+
+ bool operator<(const TSymbol& rhs) const {
+ return Str < rhs.Str;
+ }
+ bool operator>(const TSymbol& rhs) const {
+ return Str > rhs.Str;
+ }
+ bool operator<=(const TSymbol& rhs) const {
+ return Str <= rhs.Str;
+ }
+ bool operator>=(const TSymbol& rhs) const {
+ return Str >= rhs.Str;
+ }
+ bool operator==(const TSymbol& rhs) const {
+ return Str == rhs.Str;
+ }
+ bool operator!=(const TSymbol& rhs) const {
+ return Str != rhs.Str;
+ }
+ };
+
+}
diff --git a/library/cpp/lwtrace/tests/test_all_parallel.sh b/library/cpp/lwtrace/tests/test_all_parallel.sh
new file mode 100755
index 0000000000..8020783d67
--- /dev/null
+++ b/library/cpp/lwtrace/tests/test_all_parallel.sh
@@ -0,0 +1,29 @@
+
+mkdir -p out
+
+echo "
+ LogIntModFilter
+ SleepCheck
+ MultipleActionsCheck
+ KillCheck
+ InMemoryLog
+ InMemoryLogCheck
+ NoExec
+ Log
+ LogTs
+ FalseIntFilter
+ LogIntAfterFilter
+ LogInt
+ FalseStringFilter
+ FalseStringFilterPartialMatch
+ LogStringAfterFilter
+ LogString
+ LogCheck
+" | awk NF | ( while read l; do ./tests --unsafe-lwtrace 1 $l > out/out_$l.txt 2>out/err_$l.txt && echo done $l & done ; wait )
+
+
+grep . out/out_*.txt
+grep . out/err_*.txt --color=always
+
+
+
diff --git a/library/cpp/lwtrace/tests/trace_tests.cpp b/library/cpp/lwtrace/tests/trace_tests.cpp
new file mode 100644
index 0000000000..6762e344a7
--- /dev/null
+++ b/library/cpp/lwtrace/tests/trace_tests.cpp
@@ -0,0 +1,715 @@
+#include <library/cpp/lwtrace/all.h>
+
+#include <library/cpp/getopt/last_getopt.h>
+
+#include <google/protobuf/text_format.h>
+
+#include <util/system/pipe.h>
+#include <util/generic/ymath.h>
+#include <util/string/printf.h>
+#include <util/string/vector.h>
+
+#define LWTRACE_TESTS_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \
+ PROBE(Simplest, GROUPS("Group"), TYPES(), NAMES()) \
+ PROBE(IntParam, GROUPS("Group"), TYPES(ui32), NAMES("value")) \
+ PROBE(StringParam, GROUPS("Group"), TYPES(TString), NAMES("value")) \
+ PROBE(SymbolParam, GROUPS("Group"), TYPES(NLWTrace::TSymbol), NAMES("symbol")) \
+ PROBE(CheckParam, GROUPS("Group"), TYPES(NLWTrace::TCheck), NAMES("value")) \
+ EVENT(TwoParamsEvent, GROUPS("Group"), TYPES(int, TString), NAMES("param1", "param2")) \
+ EVENT(TwoParamsCheckEvent, GROUPS("Group"), TYPES(NLWTrace::TCheck, TString), NAMES("param1", "param2")) \
+ /**/
+
+LWTRACE_DECLARE_PROVIDER(LWTRACE_TESTS_PROVIDER)
+LWTRACE_DEFINE_PROVIDER(LWTRACE_TESTS_PROVIDER)
+LWTRACE_USING(LWTRACE_TESTS_PROVIDER)
+
+namespace NLWTrace {
+ namespace NTests {
+ TString gStrValue = "a long string value that can be possible passed as a trace probe string parameter";
+ //TString gStrValue = "short";
+
+ LWTRACE_DEFINE_SYMBOL(gSymbol, "a long symbol value that can be possible passed as a trace probe string parameter");
+
+ struct TConfig {
+ size_t Cycles;
+ size_t Runs;
+ bool UnsafeLWTrace;
+
+ TConfig() {
+ Cycles = 100000;
+ Runs = 10;
+ UnsafeLWTrace = false;
+ }
+ };
+
+ struct TMeasure {
+ double Average;
+ double Sigma;
+ TMeasure(double a, double s)
+ : Average(a)
+ , Sigma(s)
+ {
+ }
+ };
+
+#define DEFINE_MEASUREMENT(name, ...) \
+ double name##OneRun(const TConfig& cfg) { \
+ TInstant t0 = Now(); \
+ for (size_t i = 0; i < cfg.Cycles; i++) { \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ HOTSPOT(name, ##__VA_ARGS__); \
+ } \
+ TInstant t1 = Now(); \
+ return double(t1.MicroSeconds() - t0.MicroSeconds()) / (cfg.Cycles * 10); \
+ } \
+ TMeasure name##Time(const TConfig& cfg) { \
+ double v = 0; \
+ double vSq = 0; \
+ for (size_t i = 0; i < cfg.Runs; i++) { \
+ double value = name##OneRun(cfg); \
+ v += value; \
+ vSq += value * value; \
+ } \
+ v /= cfg.Runs; \
+ vSq /= cfg.Runs; \
+ return TMeasure(v, sqrt(vSq - v * v)); \
+ } \
+ /**/
+
+ class TProbes: public TProbeRegistry {
+ public:
+ TManager Mngr;
+
+ TProbes(bool destructiveActionsAllowed)
+ : Mngr(*this, destructiveActionsAllowed)
+ {
+ AddProbesList(LWTRACE_GET_PROBES(LWTRACE_TESTS_PROVIDER));
+ }
+
+#define HOTSPOT(name, ...) LWPROBE(name, ##__VA_ARGS__);
+ DEFINE_MEASUREMENT(Simplest);
+ DEFINE_MEASUREMENT(IntParam, 123);
+ DEFINE_MEASUREMENT(StringParam, gStrValue);
+ DEFINE_MEASUREMENT(SymbolParam, gSymbol);
+ DEFINE_MEASUREMENT(CheckParam, TCheck(13));
+#undef HOTSPOT
+ };
+
+ class TInMemoryLogTest {
+ public:
+ TInMemoryLog Log;
+
+ TInMemoryLogTest()
+ : Log(1000)
+ {
+ }
+
+#define HOTSPOT(name, ...) LWEVENT(name, Log, true, ##__VA_ARGS__);
+ DEFINE_MEASUREMENT(TwoParamsEvent, 666, TString("bla-bla-bla"));
+#undef HOTSPOT
+ };
+
+ class TInMemoryLogCheckTest {
+ public:
+ TInMemoryLog Log;
+
+ TInMemoryLogCheckTest()
+ : Log(1000)
+ {
+ }
+
+#define HOTSPOT(name, ...) LWEVENT(name, Log, true, ##__VA_ARGS__);
+ DEFINE_MEASUREMENT(TwoParamsCheckEvent, TCheck(666), TString("bla-bla-bla"));
+#undef HOTSPOT
+ };
+
+ NLWTrace::TQuery MakeQuery(const TString& queryStr) {
+ NLWTrace::TQuery query;
+ google::protobuf::TextFormat::ParseFromString(queryStr, &query);
+ return query;
+ }
+
+ void NoExec(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ Cout << "call to probe w/o executor: " << p.SimplestTime(cfg) << Endl;
+ }
+
+ void Log(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"Simplest\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to probe with logging executor: " << p.SimplestTime(cfg) << Endl;
+ }
+
+ void LogTs(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"Simplest\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: true"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to probe with logging (+timestamp) executor: " << p.SimplestTime(cfg) << Endl;
+ }
+
+ void FalseIntFilter(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"IntParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Predicate {"
+ " Operators {"
+ " Type: OT_GT"
+ " Argument {"
+ " Param: \"value\""
+ " }"
+ " Argument {"
+ " Value: \"1000\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to probe with int filter (always false) executor: " << p.IntParamTime(cfg) << Endl;
+ }
+
+ void LogIntAfterFilter(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"IntParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Predicate {"
+ " Operators {"
+ " Type: OT_GT"
+ " Argument {"
+ " Param: \"value\""
+ " }"
+ " Argument {"
+ " Value: \"0\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to probe with int filter (always true) and log executors: " << p.IntParamTime(cfg) << Endl;
+ }
+
+ void LogInt(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"IntParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to int probe with log executor: " << p.IntParamTime(cfg) << Endl;
+ }
+
+ void FalseStringFilter(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"StringParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Predicate {"
+ " Operators {"
+ " Type: OT_EQ"
+ " Argument {"
+ " Param: \"value\""
+ " }"
+ " Argument {"
+ " Value: \"string that never can exist\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to probe with string filter (always false) executor: " << p.StringParamTime(cfg) << Endl;
+ }
+
+ void FalseStringFilterPartialMatch(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"StringParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Predicate {"
+ " Operators {"
+ " Type: OT_EQ"
+ " Argument {"
+ " Param: \"value\""
+ " }"
+ " Argument {"
+ " Value: \"" +
+ gStrValue + "-not-full-match\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to probe with string filter (always false) executor: " << p.StringParamTime(cfg) << Endl;
+ }
+
+ void LogStringAfterFilter(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"StringParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Predicate {"
+ " Operators {"
+ " Type: OT_EQ"
+ " Argument {"
+ " Param: \"value\""
+ " }"
+ " Argument {"
+ " Value: \"" +
+ gStrValue + "\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to probe with string filter (always true) and log executors: " << p.StringParamTime(cfg) << Endl;
+ }
+
+ void LogString(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"StringParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to string probe with log executor: " << p.StringParamTime(cfg) << Endl;
+ }
+
+ void LogSymbol(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"SymbolParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to symbol probe with log executor: " << p.SymbolParamTime(cfg) << Endl;
+ }
+
+ void LogCheck(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"CheckParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to check probe with log executor: " << p.CheckParamTime(cfg) << Endl;
+ }
+
+ void InMemoryLog(const TConfig& cfg) {
+ TInMemoryLogTest test;
+ Cout << "log to in-memory log with (int, string) writer: " << test.TwoParamsEventTime(cfg) << Endl;
+ }
+
+ void InMemoryLogCheck(const TConfig& cfg) {
+ TInMemoryLogCheckTest test;
+ Cout << "log to in-memory log with (leak-check, string) writer: " << test.TwoParamsCheckEventTime(cfg) << Endl;
+ }
+
+ void MultipleActionsCheck(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-multipleActions", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"Simplest\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Predicate {"
+ " Operators {"
+ " Type: OT_LT"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " Argument {"
+ " Value: \"2\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " StatementAction {"
+ " Type: ST_INC"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " StatementAction {"
+ " Type: ST_DEC"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " StatementAction {"
+ " Type: ST_SUB_EQ"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " Argument {"
+ " Value: \"-1\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " SleepAction {"
+ " NanoSeconds: 25000000" // 25 ms
+ " }"
+ " }"
+ " Action {"
+ " SleepAction {"
+ " NanoSeconds: 25000000" // 25 ms
+ " }"
+ " }"
+ "}"));
+ TInstant t0 = Now();
+ for (size_t i = 0; i < 10; i++) {
+ LWPROBE(Simplest);
+ }
+ TInstant t1 = Now();
+ ui64 duration = (t1.NanoSeconds() - t0.NanoSeconds());
+ Cout << "multiple sleep tested, expected 100000000 ns, measured " << duration << " ns" << Endl;
+ }
+
+ void SleepCheck(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-sleep", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"Simplest\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Action {"
+ " SleepAction {"
+ " NanoSeconds: 100000000" // 100 ms
+ " }"
+ " }"
+ "}"));
+ TInstant t0 = Now();
+ for (size_t i = 0; i < 10; i++) {
+ LWPROBE(Simplest);
+ }
+ TInstant t1 = Now();
+ ui64 duration = (t1.NanoSeconds() - t0.NanoSeconds()) / (ui64)10;
+ Cout << "sleep tested, expected 100000000 ns, measured " << duration << " ns" << Endl;
+ }
+
+ void KillCheckChild(const TConfig& cfg, TPipeHandle& writer) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-kill", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"Simplest\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Action {"
+ " KillAction {"
+ " }"
+ " }"
+ "}"));
+ // Send "i'm alive and ok" to the parent (0)
+ char buffer = 0;
+ writer.Write(&buffer, 1);
+ LWPROBE(Simplest);
+ // Send "i'm alive and that's not OK" to the parent (1)
+ buffer = 1;
+ writer.Write(&buffer, 1);
+ }
+
+ void KillCheckParent(TPipeHandle& reader) {
+ char buffer = -1;
+ reader.Read(&buffer, 1);
+ reader.Read(&buffer, 1);
+ if (buffer == -1)
+ Cerr << "\t\terror: process died before transfering OK message during the KillAction test!" << Endl;
+ else if (buffer != 0)
+ Cerr << "\t\terror: process failed to die on time during the KillAction test!" << Endl;
+ else
+ Cout << "\t\tkill executor tested OK." << Endl;
+ }
+
+ void KillCheck(const TConfig& cfg) {
+#ifdef _unix_
+ TPipeHandle reader;
+ TPipeHandle writer;
+ TPipeHandle::Pipe(reader, writer);
+ Cout << "forking the process..." << Endl;
+ pid_t cpid = fork();
+ if (cpid == -1) {
+ Cerr << "\t\terror forking for the KillAction test!" << Endl;
+ } else if (cpid == 0) {
+ reader.Close();
+ KillCheckChild(cfg, writer);
+ writer.Close();
+ exit(EXIT_SUCCESS);
+ } else {
+ writer.Close();
+ KillCheckParent(reader);
+ reader.Close();
+ }
+#else
+ Cout << "kill action test for windows is not implemented." << Endl;
+#endif
+ }
+
+ void LogIntModFilter(const TConfig& cfg) {
+ TProbes p(cfg.UnsafeLWTrace);
+ p.Mngr.New("test-trace", MakeQuery(
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"IntParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Predicate {"
+ " Operators {"
+ " Type: OT_GT"
+ " Argument {"
+ " Param: \"value\""
+ " }"
+ " Argument {"
+ " Value: \"0\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " StatementAction {"
+ " Type: ST_ADD_EQ"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " Argument {"
+ " Value: \"1\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " StatementAction {"
+ " Type: ST_ADD"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " Argument {"
+ " Value: \"1\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " StatementAction {"
+ " Type: ST_MOD"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " Argument {"
+ " Value: \"20\""
+ " }"
+ " }"
+ " }"
+ "}"
+ "Blocks {"
+ " ProbeDesc {"
+ " Name: \"IntParam\""
+ " Provider: \"LWTRACE_TESTS_PROVIDER\""
+ " }"
+ " Predicate {"
+ " Operators {"
+ " Type: OT_EQ"
+ " Argument {"
+ " Variable: \"counter\""
+ " }"
+ " Argument {"
+ " Value: \"0\""
+ " }"
+ " }"
+ " Operators {"
+ " Type: OT_GT"
+ " Argument {"
+ " Param: \"value\""
+ " }"
+ " Argument {"
+ " Value: \"0\""
+ " }"
+ " }"
+ " }"
+ " Action {"
+ " LogAction {"
+ " LogTimestamp: false"
+ " }"
+ " }"
+ "}"));
+ Cout << "call to probe with int mod filter (always true, mod 10) and log executors: " << p.IntParamTime(cfg) << Endl;
+ }
+
+#define FOR_EACH_TEST() \
+ FOR_EACH_TEST_MACRO(LogIntModFilter) \
+ FOR_EACH_TEST_MACRO(SleepCheck) \
+ FOR_EACH_TEST_MACRO(MultipleActionsCheck) \
+ FOR_EACH_TEST_MACRO(KillCheck) \
+ FOR_EACH_TEST_MACRO(InMemoryLog) \
+ FOR_EACH_TEST_MACRO(InMemoryLogCheck) \
+ FOR_EACH_TEST_MACRO(NoExec) \
+ FOR_EACH_TEST_MACRO(Log) \
+ FOR_EACH_TEST_MACRO(LogTs) \
+ FOR_EACH_TEST_MACRO(FalseIntFilter) \
+ FOR_EACH_TEST_MACRO(LogIntAfterFilter) \
+ FOR_EACH_TEST_MACRO(LogInt) \
+ FOR_EACH_TEST_MACRO(FalseStringFilter) \
+ FOR_EACH_TEST_MACRO(FalseStringFilterPartialMatch) \
+ FOR_EACH_TEST_MACRO(LogStringAfterFilter) \
+ FOR_EACH_TEST_MACRO(LogString) \
+ FOR_EACH_TEST_MACRO(LogSymbol) \
+ FOR_EACH_TEST_MACRO(LogCheck) \
+ /**/
+
+ int Main(int argc, char** argv) {
+ TConfig cfg;
+ using namespace NLastGetopt;
+ TOpts opts = NLastGetopt::TOpts::Default();
+ opts.AddLongOption('c', "cycles", "cycles count").RequiredArgument("N").DefaultValue(ToString(cfg.Cycles)).StoreResult(&cfg.Cycles);
+ opts.AddLongOption('r', "runs", "runs count").RequiredArgument("N").DefaultValue(ToString(cfg.Runs)).StoreResult(&cfg.Runs);
+ opts.AddLongOption('u', "unsafe-lwtrace", "allow destructive actions").OptionalValue(ToString(true)).DefaultValue(ToString(false)).StoreResult(&cfg.UnsafeLWTrace);
+ opts.AddHelpOption('h');
+ TOptsParseResult res(&opts, argc, argv);
+
+ TVector<TString> tests = res.GetFreeArgs();
+ if (tests.empty()) {
+#define FOR_EACH_TEST_MACRO(t) tests.push_back(#t);
+ FOR_EACH_TEST()
+#undef FOR_EACH_TEST_MACRO
+ }
+ for (size_t i = 0; i < tests.size(); i++) {
+ const TString& test = tests[i];
+#define FOR_EACH_TEST_MACRO(t) \
+ if (test == #t) { \
+ Cout << #t ": \t"; \
+ t(cfg); \
+ }
+ FOR_EACH_TEST()
+#undef FOR_EACH_TEST_MACRO
+ }
+
+ if (TCheck::ObjCount != 0) {
+ Cout << ">>>>> THERE IS AN OBJECT LEAK <<<<<" << Endl;
+ Cout << "NLWTrace::TCheck::ObjCount = " << TCheck::ObjCount << Endl;
+ }
+
+ Cout << "Done" << Endl;
+ return 0;
+ }
+
+ }
+
+}
+
+template <>
+void Out<NLWTrace::NTests::TMeasure>(IOutputStream& os, TTypeTraits<NLWTrace::NTests::TMeasure>::TFuncParam measure) {
+ os << Sprintf("\n\t\t%.6lf +- %.6lf us,\tRPS: %30.3lf (%.1fM)", measure.Average, measure.Sigma, 1000000.0 / measure.Average, 1.0 / measure.Average);
+}
+
+int main(int argc, char** argv) {
+ try {
+ return NLWTrace::NTests::Main(argc, argv);
+ } catch (std::exception& e) {
+ Cerr << e.what() << Endl;
+ return 1;
+ } catch (...) {
+ Cerr << "Unknown error" << Endl;
+ return 1;
+ }
+}
diff --git a/library/cpp/lwtrace/tests/ya.make b/library/cpp/lwtrace/tests/ya.make
new file mode 100644
index 0000000000..6225ab1fa0
--- /dev/null
+++ b/library/cpp/lwtrace/tests/ya.make
@@ -0,0 +1,15 @@
+OWNER(serxa)
+
+PROGRAM()
+
+SRCS(
+ trace_tests.cpp
+)
+
+PEERDIR(
+ contrib/libs/protobuf
+ library/cpp/getopt
+ library/cpp/lwtrace
+)
+
+END()
diff --git a/library/cpp/lwtrace/trace.cpp b/library/cpp/lwtrace/trace.cpp
new file mode 100644
index 0000000000..3c974c85a0
--- /dev/null
+++ b/library/cpp/lwtrace/trace.cpp
@@ -0,0 +1,1051 @@
+#include "all.h"
+#include "kill_action.h"
+#include "log_shuttle.h"
+#include "preprocessor.h"
+#include "sleep_action.h"
+#include "stderr_writer.h"
+#include "google/protobuf/repeated_field.h"
+
+#include <util/generic/map.h>
+#include <util/random/random.h>
+
+#include <functional>
+
+namespace NLWTrace {
+#ifndef LWTRACE_DISABLE
+
+// Define static strings for name of each parameter type
+#define FOREACH_PARAMTYPE_MACRO(n, t, v) \
+ const char* TParamType<t>::NameString = n; \
+ /**/
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+ FOR_NIL_PARAMTYPE(FOREACH_PARAMTYPE_MACRO)
+#undef FOREACH_PARAMTYPE_MACRO
+
+#endif
+
+ void TProbeRegistry::AddProbesList(TProbe** reg) {
+ TGuard<TMutex> g(Mutex);
+ if (reg == nullptr) {
+ return;
+ }
+ for (TProbe** i = reg; *i != nullptr; i++) {
+ AddProbeNoLock(new TStaticBox(*i));
+ }
+ }
+
+ void TProbeRegistry::AddProbe(const TBoxPtr& box) {
+ TGuard<TMutex> g(Mutex);
+ AddProbeNoLock(box);
+ }
+
+ void TProbeRegistry::RemoveProbe(TProbe* probe) {
+ TGuard<TMutex> g(Mutex);
+ RemoveProbeNoLock(probe);
+ }
+
+ void TProbeRegistry::AddProbeNoLock(const TBoxPtr& box) {
+ TProbe* probe = box->GetProbe();
+ if (Probes.contains(probe)) {
+ return; // silently skip probe double registration
+ }
+ TIds::key_type key(probe->Event.GetProvider(), probe->Event.Name);
+ Y_VERIFY(Ids.count(key) == 0, "duplicate provider:probe pair %s:%s", key.first.data(), key.second.data());
+ Probes.emplace(probe, box);
+ Ids.insert(key);
+ }
+
+ void TProbeRegistry::RemoveProbeNoLock(TProbe* probe) {
+ auto iter = Probes.find(probe);
+ if (iter != Probes.end()) {
+ TIds::key_type key(probe->Event.GetProvider(), probe->Event.Name);
+ Ids.erase(key);
+ Probes.erase(iter);
+ } else {
+ // silently skip probe double unregistration
+ }
+ }
+
+ TAtomic* GetVariablePtr(TSession::TTraceVariables& traceVariables, const TString& name) {
+ TSession::TTraceVariables::iterator it = traceVariables.find(name);
+ if (it == traceVariables.end()) {
+ TAtomicBase zero = 0;
+ traceVariables[name] = zero;
+ return &traceVariables[name];
+ }
+ return &((*it).second);
+ }
+
+ typedef enum {
+ OT_LITERAL = 0,
+ OT_PARAMETER = 1,
+ OT_VARIABLE = 2
+ } EOperandType;
+
+ template <class T, EOperandType>
+ class TOperand;
+
+ template <class T>
+ class TOperand<T, OT_LITERAL> {
+ private:
+ T ImmediateValue;
+
+ public:
+ TOperand(TSession::TTraceVariables&, const TString&, const TString& value, size_t) {
+ ImmediateValue = TParamConv<T>::FromString(value);
+ }
+ const T& Get(const TParams&) {
+ return ImmediateValue;
+ }
+ };
+
+ template <class T>
+ class TOperand<T, OT_PARAMETER> {
+ private:
+ size_t Idx;
+
+ public:
+ TOperand(TSession::TTraceVariables&, const TString&, const TString&, size_t idx) {
+ Idx = idx;
+ }
+
+ const T& Get(const TParams& params) {
+ return params.Param[Idx].template Get<T>();
+ }
+ };
+
+ template <class T>
+ class TOperand<T, OT_VARIABLE> {
+ private:
+ TAtomic* Variable;
+
+ public:
+ TOperand(TSession::TTraceVariables& traceVariables, const TString& name, const TString&, size_t) {
+ Variable = GetVariablePtr(traceVariables, name);
+ }
+
+ const T Get(const TParams&) {
+ return (T)AtomicGet(*Variable);
+ }
+
+ void Set(const T& value) {
+ AtomicSet(*Variable, value);
+ }
+
+ void Inc() {
+ AtomicIncrement(*Variable);
+ }
+
+ void Dec() {
+ AtomicDecrement(*Variable);
+ }
+
+ void Add(const TAtomicBase value) {
+ AtomicAdd(*Variable, value);
+ }
+
+ void Sub(const TAtomicBase value) {
+ AtomicSub(*Variable, value);
+ }
+ };
+
+ template <>
+ class TOperand<TCheck, OT_VARIABLE> {
+ private:
+ TAtomic* Variable;
+
+ public:
+ TOperand(TSession::TTraceVariables& traceVariables, const TString& name, const TString&, size_t) {
+ Variable = GetVariablePtr(traceVariables, name);
+ }
+
+ const TCheck Get(const TParams&) {
+ return TCheck(AtomicGet(*Variable));
+ }
+
+ void Set(const TCheck& value) {
+ AtomicSet(*Variable, value.Value);
+ }
+
+ void Add(const TCheck& value) {
+ AtomicAdd(*Variable, value.Value);
+ }
+
+ void Sub(const TCheck value) {
+ AtomicSub(*Variable, value.Value);
+ }
+
+ void Inc() {
+ AtomicIncrement(*Variable);
+ }
+
+ void Dec() {
+ AtomicDecrement(*Variable);
+ }
+ };
+
+ template <>
+ class TOperand<TString, OT_VARIABLE> {
+ private:
+ TString Dummy;
+
+ public:
+ TOperand(TSession::TTraceVariables&, const TString&, const TString&, size_t) {
+ }
+
+ const TString Get(const TParams&) {
+ return Dummy;
+ }
+
+ void Set(const TString&) {
+ }
+ };
+
+ template <>
+ class TOperand<TSymbol, OT_VARIABLE> {
+ private:
+ TSymbol Dummy;
+
+ public:
+ TOperand(TSession::TTraceVariables&, const TString&, const TString&, size_t) {
+ }
+
+ const TSymbol Get(const TParams&) {
+ return Dummy;
+ }
+
+ void Set(const TSymbol&) {
+ }
+ };
+
+ // IOperandGetter: hide concrete EOperandType, to save compilation time
+ template <class T>
+ struct IOperandGetter {
+ virtual const T Get(const TParams& params) = 0;
+ virtual ~IOperandGetter() {
+ }
+ };
+
+ template <class T, EOperandType TParam>
+ class TOperandGetter: public IOperandGetter<T> {
+ private:
+ TOperand<T, TParam> Op;
+
+ public:
+ TOperandGetter(const TOperand<T, TParam>& op)
+ : Op(op)
+ {
+ }
+
+ const T Get(const TParams& params) override {
+ return Op.Get(params);
+ }
+ };
+
+ template <class T>
+ class TReceiver: public TOperand<T, OT_VARIABLE> {
+ public:
+ TReceiver(TSession::TTraceVariables& traceVariables, const TString& name)
+ : TOperand<T, OT_VARIABLE>(traceVariables, name, nullptr, 0)
+ {
+ }
+ };
+
+ template <class TP, class TPredicate>
+ static bool CmpFunc(TP a, TP b) {
+ return TPredicate()(a, b);
+ }
+
+ template <class TP, class TFunc, EOperandType TLhs, EOperandType TRhs>
+ class TOperatorExecutor: public IExecutor {
+ private:
+ bool InvertCompare;
+ TOperand<TP, TLhs> Lhs;
+ TOperand<TP, TRhs> Rhs;
+
+ bool DoExecute(TOrbit&, const TParams& params) override {
+ return TFunc()(Lhs.Get(params), Rhs.Get(params)) != InvertCompare;
+ }
+
+ public:
+ TOperatorExecutor(const TOperand<TP, TLhs>& lhs, const TOperand<TP, TRhs>& rhs, bool invertCompare)
+ : InvertCompare(invertCompare)
+ , Lhs(lhs)
+ , Rhs(rhs)
+ {
+ }
+ };
+
+ template <class TR, class TP>
+ struct TAddEq {
+ void operator()(TR& x, TP y) const {
+ x.Add(y);
+ }
+ };
+ template <class TR, class TP>
+ struct TSubEq {
+ void operator()(TR& x, TP y) const {
+ x.Sub(y);
+ }
+ };
+ template <class TR>
+ struct TInc {
+ void operator()(TR& x) const {
+ x.Inc();
+ }
+ };
+ template <class TR>
+ struct TDec {
+ void operator()(TR& x) const {
+ x.Dec();
+ }
+ };
+
+ template <class TP, class TFunc>
+ class TUnaryInplaceStatementExecutor: public IExecutor {
+ private:
+ TFunc Func;
+ TReceiver<TP> Receiver;
+
+ bool DoExecute(TOrbit&, const TParams&) override {
+ Func(Receiver);
+ return true;
+ }
+
+ public:
+ TUnaryInplaceStatementExecutor(TReceiver<TP>& receiver)
+ : Receiver(receiver)
+ {
+ }
+ };
+
+ template <class TP, class TFunc, EOperandType TParam>
+ class TBinaryInplaceStatementExecutor: public IExecutor {
+ private:
+ TFunc Func;
+ TReceiver<TP> Receiver;
+ TOperand<TP, TParam> Param;
+
+ bool DoExecute(TOrbit&, const TParams& params) override {
+ Func(Receiver, Param.Get(params));
+ return true;
+ }
+
+ public:
+ TBinaryInplaceStatementExecutor(TReceiver<TP>& receiver, const TOperand<TP, TParam>& param)
+ : Receiver(receiver)
+ , Param(param)
+ {
+ }
+ };
+
+ template <class TP, class TFunc, EOperandType TFirstParam>
+ class TBinaryStatementExecutor: public IExecutor {
+ private:
+ TFunc Func;
+ TReceiver<TP> Receiver;
+ TOperand<TP, TFirstParam> FirstParam;
+
+ bool DoExecute(TOrbit&, const TParams& params) override {
+ Receiver.Set(Func(Receiver.Get(params), FirstParam.Get(params)));
+ return true;
+ }
+
+ public:
+ TBinaryStatementExecutor(TReceiver<TP>& receiver, const TOperand<TP, TFirstParam>& firstParam)
+ : Receiver(receiver)
+ , FirstParam(firstParam)
+ {
+ }
+ };
+
+ template <class TP, class TFunc>
+ class TTernaryStatementExecutor: public IExecutor {
+ private:
+ TFunc Func;
+ TReceiver<TP> Receiver;
+
+ TAutoPtr<IOperandGetter<TP>> FirstParam;
+ TAutoPtr<IOperandGetter<TP>> SecondParam;
+
+ bool DoExecute(TOrbit&, const TParams& params) override {
+ Receiver.Set(Func(FirstParam->Get(params), SecondParam->Get(params)));
+ return true;
+ }
+
+ public:
+ TTernaryStatementExecutor(const TReceiver<TP>& receiver,
+ TAutoPtr<IOperandGetter<TP>> firstParam,
+ TAutoPtr<IOperandGetter<TP>> secondParam)
+ : Receiver(receiver)
+ , FirstParam(firstParam)
+ , SecondParam(secondParam)
+ {
+ }
+ };
+
+ template <class TLog>
+ class TLogActionExecutor: public IExecutor {
+ private:
+ bool LogParams;
+ bool LogTimestamp;
+ intptr_t* MaxRecords;
+ TAtomic Records;
+ TProbe* Probe;
+ TLog* Log;
+
+ bool DoExecute(TOrbit&, const TParams& params) override {
+ if (MaxRecords != nullptr) {
+ while (true) {
+ intptr_t a = AtomicGet(Records);
+ if (a >= *MaxRecords) {
+ return true;
+ }
+ if (AtomicCas(&Records, a + 1, a)) {
+ Write(params);
+ return true;
+ }
+ }
+ } else {
+ Write(params);
+ return true;
+ }
+ }
+
+ void Write(const TParams& params) {
+ typename TLog::TAccessor la(*Log);
+ if (typename TLog::TItem* item = la.Add()) {
+ item->Probe = Probe;
+ if (LogParams) {
+ if ((item->SavedParamsCount = Probe->Event.Signature.ParamCount) > 0) {
+ Probe->Event.Signature.CloneParams(item->Params, params);
+ }
+ } else {
+ item->SavedParamsCount = 0;
+ }
+ if (LogTimestamp) {
+ item->Timestamp = TInstant::Now();
+ }
+ item->TimestampCycles = GetCycleCount();
+ }
+ }
+
+ public:
+ TLogActionExecutor(TProbe* probe, const TLogAction& action, TLog* log)
+ : LogParams(!action.GetDoNotLogParams())
+ , LogTimestamp(action.GetLogTimestamp())
+ , MaxRecords(action.GetMaxRecords() ? new intptr_t(action.GetMaxRecords()) : nullptr)
+ , Records(0)
+ , Probe(probe)
+ , Log(log)
+ {
+ }
+
+ ~TLogActionExecutor() override {
+ delete MaxRecords;
+ }
+ };
+
+ class TSamplingExecutor: public IExecutor {
+ private:
+ double SampleRate;
+
+ public:
+ explicit TSamplingExecutor(double sampleRate)
+ : SampleRate(sampleRate)
+ {}
+
+ bool DoExecute(TOrbit&, const TParams&) override {
+ return RandomNumber<double>() < SampleRate;
+ }
+ };
+
+ typedef struct {
+ EOperandType Type;
+ size_t ParamIdx;
+ } TArgumentDescription;
+
+ using TArgumentList = TVector<TArgumentDescription>;
+
+ template <class T>
+ void ParseArguments(const T& op, const TSignature& signature, const TString& exceptionPrefix, size_t expectedArgumentCount, TArgumentList& arguments) {
+ arguments.clear();
+ size_t firstParamIdx = size_t(-1);
+ for (size_t argumentIdx = 0; argumentIdx < op.ArgumentSize(); ++argumentIdx) {
+ const TArgument& arg = op.GetArgument(argumentIdx);
+ TArgumentDescription operand;
+ operand.ParamIdx = size_t(-1);
+ if (arg.GetVariable()) {
+ operand.Type = OT_VARIABLE;
+ } else if (arg.GetValue()) {
+ operand.Type = OT_LITERAL;
+ } else if (arg.GetParam()) {
+ operand.Type = OT_PARAMETER;
+ operand.ParamIdx = signature.FindParamIndex(arg.GetParam());
+ if (operand.ParamIdx == size_t(-1)) {
+ ythrow yexception() << exceptionPrefix
+ << " argument #" << argumentIdx << " param '" << arg.GetParam()
+ << "' doesn't exist";
+ }
+ if (firstParamIdx == size_t(-1)) {
+ firstParamIdx = operand.ParamIdx;
+ } else {
+ if (strcmp(signature.ParamTypes[firstParamIdx], signature.ParamTypes[operand.ParamIdx]) != 0) {
+ ythrow yexception() << exceptionPrefix
+ << " param types do not match";
+ }
+ }
+ } else {
+ ythrow yexception() << exceptionPrefix
+ << " argument #" << argumentIdx
+ << " is empty";
+ }
+ arguments.push_back(operand);
+ }
+ if (arguments.size() != expectedArgumentCount) {
+ ythrow yexception() << exceptionPrefix
+ << " incorrect number of arguments (" << arguments.size()
+ << " present, " << expectedArgumentCount << " expected)";
+ }
+ }
+
+ template <class TArg1, class TArg2>
+ struct TTraceSecondArg {
+ // implementation of deprecated std::project2nd
+ TArg1 operator()(const TArg1&, const TArg2& y) const {
+ return y;
+ }
+ };
+
+ void TSession::InsertExecutor(
+ TTraceVariables& traceVariables, size_t bi, const TPredicate* pred,
+ const NProtoBuf::RepeatedPtrField<TAction>& actions, TProbe* probe,
+ const bool destructiveActionsAllowed,
+ const TCustomActionFactory& customActionFactory) {
+#ifndef LWTRACE_DISABLE
+ THolder<IExecutor> exec;
+ IExecutor* last = nullptr;
+ TArgumentList arguments;
+ if (pred) {
+ double sampleRate = pred->GetSampleRate();
+ if (sampleRate != 0.0) {
+ if (!(0.0 < sampleRate && sampleRate <= 1.0)) {
+ ythrow yexception() << "probe '" << probe->Event.Name << "' block #" << bi + 1 << " sampling operator"
+ << " invalid sample rate " << sampleRate << ", expected [0;1]";
+ }
+ exec.Reset(new TSamplingExecutor(sampleRate));
+ last = exec.Get();
+ }
+
+ for (size_t i = 0; i < pred->OperatorsSize(); i++) {
+ const TOperator& op = pred->GetOperators(i);
+ TString exceptionPrefix;
+ TStringOutput exceptionPrefixOutput(exceptionPrefix);
+ exceptionPrefixOutput << "probe '" << probe->Event.Name << "' block #" << bi + 1 << " operator #" << i + 1;
+ ParseArguments<TOperator>(op, probe->Event.Signature, exceptionPrefix, 2, arguments);
+ THolder<IExecutor> opExec;
+
+ TArgumentDescription arg0 = arguments.at(0);
+ TArgumentDescription arg1 = arguments.at(1);
+
+ const char* tName0 = arg0.ParamIdx == size_t(-1) ? nullptr : probe->Event.Signature.ParamTypes[arg0.ParamIdx];
+ const char* tName1 = arg1.ParamIdx == size_t(-1) ? nullptr : probe->Event.Signature.ParamTypes[arg1.ParamIdx];
+
+ TString var0 = op.GetArgument(0).GetVariable();
+ TString var1 = op.GetArgument(1).GetVariable();
+
+ TString val0 = op.GetArgument(0).GetValue();
+ TString val1 = op.GetArgument(1).GetValue();
+
+#define FOREACH_OPERAND_TYPE_RT(n, t, v, fn, lt, rt) \
+ if (rt == arg1.Type) { \
+ TOperand<t, rt> rhs(traceVariables, var1, val1, arg1.ParamIdx); \
+ opExec.Reset(new TOperatorExecutor<t, fn<t>, lt, rt>(lhs, rhs, invertCompare)); \
+ break; \
+ }
+
+#define FOREACH_OPERAND_TYPE_LT(n, t, v, fn, lt) \
+ if (lt == arg0.Type) { \
+ TOperand<t, lt> lhs(traceVariables, var0, val0, arg0.ParamIdx); \
+ FOREACH_RIGHT_TYPE(FOREACH_OPERAND_TYPE_RT, n, t, v, fn, lt) \
+ }
+
+#define FOREACH_PARAMTYPE_MACRO(n, t, v, fn) \
+ if ((arg0.ParamIdx == size_t(-1) || strcmp(tName0, n) == 0) && (arg1.ParamIdx == size_t(-1) || strcmp(tName1, n) == 0)) { \
+ FOREACH_LEFT_TYPE(FOREACH_OPERAND_TYPE_LT, n, t, v, fn); \
+ }
+
+ bool invertCompare = EqualToOneOf(op.GetType(), OT_NE, OT_GE, OT_LE);
+
+ switch (op.GetType()) {
+ case OT_EQ:
+ case OT_NE:
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, std::equal_to);
+ break;
+ case OT_LT:
+ case OT_GE:
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, std::less);
+ break;
+ case OT_GT:
+ case OT_LE:
+ FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, std::greater);
+ break;
+ default:
+ ythrow yexception() << exceptionPrefix
+ << " has not supported operator type #" << int(op.GetType());
+ }
+
+#undef FOREACH_OPERAND_TYPE_RT
+#undef FOREACH_OPERAND_TYPE_LT
+#undef FOREACH_PARAMTYPE_MACRO
+
+ if (!opExec) {
+ ythrow yexception() << exceptionPrefix
+ << " has not supported left param #" << arg0.ParamIdx + 1 << " type '"
+ << (arg0.ParamIdx != size_t(-1) ? probe->Event.Signature.ParamTypes[arg0.ParamIdx] : "?")
+ << "', or right param #" << arg0.ParamIdx + 1 << " type '"
+ << (arg1.ParamIdx != size_t(-1) ? probe->Event.Signature.ParamTypes[arg1.ParamIdx] : "?")
+ << "'";
+ }
+
+ if (!exec) {
+ exec.Reset(opExec.Release());
+ last = exec.Get();
+ } else {
+ last->SetNext(opExec.Release());
+ last = last->GetNext();
+ }
+ }
+ }
+
+ for (int i = 0; i < actions.size(); ++i) {
+ const TAction& action = actions.Get(i);
+ THolder<IExecutor> actExec;
+ if (action.HasPrintToStderrAction()) {
+ actExec.Reset(new TStderrActionExecutor(probe));
+ } else if (action.HasLogAction()) {
+ if (Query.GetLogDurationUs()) {
+ actExec.Reset(new TLogActionExecutor<TDurationLog>(probe, action.GetLogAction(), &DurationLog));
+ } else {
+ actExec.Reset(new TLogActionExecutor<TCyclicLog>(probe, action.GetLogAction(), &CyclicLog));
+ }
+ } else if (action.HasRunLogShuttleAction()) {
+ if (Query.GetLogDurationUs()) {
+ actExec.Reset(new TRunLogShuttleActionExecutor<TDurationDepot>(TraceIdx, action.GetRunLogShuttleAction(), &DurationDepot, &LastTrackId, &LastSpanId));
+ } else {
+ actExec.Reset(new TRunLogShuttleActionExecutor<TCyclicDepot>(TraceIdx, action.GetRunLogShuttleAction(), &CyclicDepot, &LastTrackId, &LastSpanId));
+ }
+ } else if (action.HasEditLogShuttleAction()) {
+ if (Query.GetLogDurationUs()) {
+ actExec.Reset(new TEditLogShuttleActionExecutor<TDurationDepot>(TraceIdx, action.GetEditLogShuttleAction()));
+ } else {
+ actExec.Reset(new TEditLogShuttleActionExecutor<TCyclicDepot>(TraceIdx, action.GetEditLogShuttleAction()));
+ }
+ } else if (action.HasDropLogShuttleAction()) {
+ if (Query.GetLogDurationUs()) {
+ actExec.Reset(new TDropLogShuttleActionExecutor<TDurationDepot>(TraceIdx, action.GetDropLogShuttleAction()));
+ } else {
+ actExec.Reset(new TDropLogShuttleActionExecutor<TCyclicDepot>(TraceIdx, action.GetDropLogShuttleAction()));
+ }
+ } else if (action.HasCustomAction()) {
+ THolder<TCustomActionExecutor> customExec(customActionFactory.Create(probe, action.GetCustomAction(), this));
+ if (customExec) {
+ if (!customExec->IsDestructive() || destructiveActionsAllowed) {
+ actExec.Reset(customExec.Release());
+ } else {
+ ythrow yexception() << "probe '" << probe->Event.Name << "block #" << bi + 1 << " action #" << i + 1
+ << " contains destructive CustomAction, but destructive actions are disabled."
+ << " Please, consider using --unsafe-lwtrace command line parameter.";
+ }
+ } else {
+ ythrow yexception() << "probe '" << probe->Event.Name << "block #" << bi + 1 << " action #" << i + 1
+ << " contains unregistered CustomAction '" << action.GetCustomAction().GetName() << "'";
+ }
+ } else if (action.HasKillAction()) {
+ if (destructiveActionsAllowed) {
+ actExec.Reset(new NPrivate::TKillActionExecutor(probe));
+ } else {
+ ythrow yexception() << "probe '" << probe->Event.Name << "block #" << bi + 1 << " action #" << i + 1
+ << " contains destructive KillAction, but destructive actions are disabled."
+ << " Please, consider using --unsafe-lwtrace command line parameter.";
+ }
+ } else if (action.HasSleepAction()) {
+ if (destructiveActionsAllowed) {
+ const TSleepAction& sleepAction = action.GetSleepAction();
+ if (sleepAction.GetNanoSeconds()) {
+ ui64 nanoSeconds = sleepAction.GetNanoSeconds();
+ actExec.Reset(new NPrivate::TSleepActionExecutor(probe, nanoSeconds));
+ } else {
+ ythrow yexception() << "probe '" << probe->Event.Name << "block #" << bi + 1 << " action #" << i + 1
+ << " SleepAction missing parameter 'NanoSeconds'";
+ }
+ } else {
+ ythrow yexception() << "probe '" << probe->Event.Name << "block #" << bi + 1 << " action #" << i + 1
+ << " contains destructive SleepAction, but destructive actions are disabled."
+ << " Please, consider using --unsafe-lwtrace command line parameter.";
+ }
+ } else if (action.HasStatementAction()) {
+ const TStatementAction& statement = action.GetStatementAction();
+ TString exceptionPrefix;
+ TStringOutput exceptionPrefixOutput(exceptionPrefix);
+ exceptionPrefixOutput << "probe '" << probe->Event.Name << "' block #" << bi + 1 << " action #" << i + 1;
+ size_t expectedArgumentCount = 3;
+ if (statement.GetType() == ST_MOV || statement.GetType() == ST_ADD_EQ || statement.GetType() == ST_SUB_EQ) {
+ expectedArgumentCount = 2;
+ } else if (statement.GetType() == ST_INC || statement.GetType() == ST_DEC) {
+ expectedArgumentCount = 1;
+ }
+ ParseArguments<TStatementAction>(statement, probe->Event.Signature, exceptionPrefix, expectedArgumentCount, arguments);
+
+ TArgumentDescription arg0 = (expectedArgumentCount <= 0) ? TArgumentDescription() : arguments.at(0);
+ TArgumentDescription arg1 = (expectedArgumentCount <= 1) ? TArgumentDescription() : arguments.at(1);
+ TArgumentDescription arg2 = (expectedArgumentCount <= 2) ? TArgumentDescription() : arguments.at(2);
+
+ TString var0 = (expectedArgumentCount <= 0) ? "" : statement.GetArgument(0).GetVariable();
+ TString var1 = (expectedArgumentCount <= 1) ? "" : statement.GetArgument(1).GetVariable();
+ TString var2 = (expectedArgumentCount <= 2) ? "" : statement.GetArgument(2).GetVariable();
+
+ TString val0 = (expectedArgumentCount <= 0) ? "" : statement.GetArgument(0).GetValue();
+ TString val1 = (expectedArgumentCount <= 1) ? "" : statement.GetArgument(1).GetValue();
+ TString val2 = (expectedArgumentCount <= 2) ? "" : statement.GetArgument(2).GetValue();
+
+ const char* tName1 = (expectedArgumentCount <= 1 || arg1.ParamIdx == size_t(-1))
+ ? nullptr : probe->Event.Signature.ParamTypes[arg1.ParamIdx];
+ const char* tName2 = (expectedArgumentCount <= 2 || arg2.ParamIdx == size_t(-1))
+ ? nullptr : probe->Event.Signature.ParamTypes[arg2.ParamIdx];
+
+ if (arg0.Type == OT_VARIABLE) {
+ switch (statement.GetType()) {
+#define PARSE_UNARY_INPLACE_STATEMENT_MACRO(n, t, v, fn) \
+ { \
+ typedef TUnaryInplaceStatementExecutor<t, fn<TReceiver<t>>> TExec; \
+ TReceiver<t> receiver(traceVariables, var0); \
+ actExec.Reset(new TExec(receiver)); \
+ break; \
+ }
+
+#define PARSE_BINARY_INPLACE_STATEMENT_MACRO2(n, t, v, fn, ft) \
+ if (arg1.Type == ft) { \
+ typedef TBinaryInplaceStatementExecutor<t, fn<TReceiver<t>, t>, ft> TExec; \
+ TOperand<t, ft> firstParam(traceVariables, var1, val1, arg1.ParamIdx); \
+ actExec.Reset(new TExec(receiver, firstParam)); \
+ break; \
+ }
+
+#define PARSE_BINARY_INPLACE_STATEMENT_MACRO(n, t, v, fn) \
+ if (arg1.ParamIdx == size_t(-1) || strcmp(tName1, n) == 0) { \
+ TReceiver<t> receiver(traceVariables, var0); \
+ FOREACH_RIGHT_TYPE(PARSE_BINARY_INPLACE_STATEMENT_MACRO2, n, t, v, fn); \
+ }
+
+#define PARSE_BINARY_STATEMENT_MACRO2(n, t, v, fn, ft) \
+ if (arg1.Type == ft) { \
+ typedef TBinaryStatementExecutor<t, fn<t, t>, ft> TExec; \
+ TOperand<t, ft> firstParam(traceVariables, var1, val1, arg1.ParamIdx); \
+ actExec.Reset(new TExec(receiver, firstParam)); \
+ break; \
+ }
+
+#define PARSE_BINARY_STATEMENT_MACRO(n, t, v, fn) \
+ if (arg1.ParamIdx == size_t(-1) || strcmp(tName1, n) == 0) { \
+ TReceiver<t> receiver(traceVariables, var0); \
+ FOREACH_RIGHT_TYPE(PARSE_BINARY_STATEMENT_MACRO2, n, t, v, fn); \
+ }
+
+#define CREATE_OPERAND_GETTER_N(N, type, arg_type) \
+ if (arg##N.Type == arg_type) { \
+ operand##N.Reset(new TOperandGetter<type, arg_type>(TOperand<type, arg_type>(traceVariables, var##N, val##N, arg##N.ParamIdx))); \
+ }
+
+#define TERNARY_ON_TYPE(n, t, v, fn) \
+ if ((arg1.ParamIdx == size_t(-1) || strcmp(tName1, n) == 0) && (arg2.ParamIdx == size_t(-1) || strcmp(tName2, n) == 0)) { \
+ TAutoPtr<IOperandGetter<t>> operand1, operand2; \
+ FOREACH_LEFT_TYPE(CREATE_OPERAND_GETTER_N, 1, t); \
+ FOREACH_RIGHT_TYPE(CREATE_OPERAND_GETTER_N, 2, t); \
+ if (operand1 && operand2) { \
+ actExec.Reset(new TTernaryStatementExecutor<t, fn<t>>( \
+ TReceiver<t>(traceVariables, var0), \
+ operand1, \
+ operand2)); \
+ } \
+ break; \
+ }
+
+#define IMPLEMENT_TERNARY_STATEMENT(fn) FOR_MATH_PARAMTYPE(TERNARY_ON_TYPE, fn)
+
+ case ST_INC:
+ FOR_MATH_PARAMTYPE(PARSE_UNARY_INPLACE_STATEMENT_MACRO, TInc);
+ break;
+ case ST_DEC:
+ FOR_MATH_PARAMTYPE(PARSE_UNARY_INPLACE_STATEMENT_MACRO, TDec);
+ break;
+ case ST_MOV:
+ FOR_MATH_PARAMTYPE(PARSE_BINARY_STATEMENT_MACRO, TTraceSecondArg);
+ break;
+ case ST_ADD_EQ:
+ FOR_MATH_PARAMTYPE(PARSE_BINARY_INPLACE_STATEMENT_MACRO, TAddEq);
+ break;
+ case ST_SUB_EQ:
+ FOR_MATH_PARAMTYPE(PARSE_BINARY_INPLACE_STATEMENT_MACRO, TSubEq);
+ break;
+ case ST_ADD:
+ IMPLEMENT_TERNARY_STATEMENT(std::plus)
+ break;
+ case ST_SUB:
+ IMPLEMENT_TERNARY_STATEMENT(std::minus)
+ break;
+ case ST_MUL:
+ IMPLEMENT_TERNARY_STATEMENT(std::multiplies)
+ break;
+ case ST_DIV:
+ IMPLEMENT_TERNARY_STATEMENT(std::divides)
+ break;
+ case ST_MOD:
+ IMPLEMENT_TERNARY_STATEMENT(std::modulus)
+ break;
+ default:
+ ythrow yexception() << "block #" << bi + 1 << " action #" << i + 1
+ << " has not supported statement type #" << int(statement.GetType());
+ }
+ }
+ if (!actExec) {
+ ythrow yexception() << "block #" << bi + 1 << " action #" << i + 1
+ << " can't create action";
+ }
+#undef CREATE_OPERAND_GETTER_N
+#undef TERNARY_ON_TYPE
+#undef IMPLEMENT_TERNARY_STATEMENT
+#undef PARSE_TERNARY_STATEMENT_MACRO
+#undef PARSE_BINARY_STATEMENT_MACRO
+#undef PARSE_BINARY_INPLACE_STATEMENT_MACRO
+#undef PARSE_UNARY_INPLACE_STATEMENT_MACRO
+ } else {
+ ythrow yexception() << "block #" << bi + 1 << " action #" << i + 1
+ << " has not supported action '" << action.ShortDebugString() << "'";
+ }
+ if (!exec) {
+ exec.Reset(actExec.Release());
+ last = exec.Get();
+ } else {
+ last->SetNext(actExec.Release());
+ last = last->GetNext();
+ }
+ }
+
+ if (!probe->Attach(exec.Get())) {
+ ythrow yexception() << "block #" << bi + 1
+ << " cannot be attached to probe '" << probe->Event.Name << "': no free slots";
+ }
+ Probes.push_back(std::make_pair(probe, exec.Release()));
+#else
+ Y_UNUSED(bi);
+ Y_UNUSED(pred);
+ Y_UNUSED(actions);
+ Y_UNUSED(probe);
+ Y_UNUSED(destructiveActionsAllowed);
+ Y_UNUSED(traceVariables);
+ Y_UNUSED(customActionFactory);
+#endif
+ }
+
+ TSession::TSession(ui64 traceIdx,
+ TProbeRegistry& registry,
+ const TQuery& query,
+ const bool destructiveActionsAllowed,
+ const TCustomActionFactory& customActionFactory)
+ : StartTime(TInstant::Now())
+ , TraceIdx(traceIdx)
+ , Registry(registry)
+ , StoreDuration(TDuration::MicroSeconds(query.GetLogDurationUs() * 11 / 10)) // +10% to try avoid truncation while reading multiple threads/traces
+ , ReadDuration(TDuration::MicroSeconds(query.GetLogDurationUs()))
+ , CyclicLog(query.GetPerThreadLogSize() ? query.GetPerThreadLogSize() : 1000)
+ , DurationLog(StoreDuration)
+ , CyclicDepot(query.GetPerThreadLogSize() ? query.GetPerThreadLogSize() : 1000)
+ , DurationDepot(StoreDuration)
+ , LastTrackId(0)
+ , LastSpanId(0)
+ , Attached(true)
+ , Query(query)
+ {
+ try {
+ for (size_t bi = 0; bi < query.BlocksSize(); bi++) {
+ const TBlock& block = query.GetBlocks(bi);
+ if (!block.HasProbeDesc()) {
+ ythrow yexception() << "block #" << bi + 1 << " has no probe description";
+ }
+ const TProbeDesc& pdesc = block.GetProbeDesc();
+ const TPredicate* pred = block.HasPredicate() ? &block.GetPredicate() : nullptr;
+ if (block.ActionSize() < 1) {
+ ythrow yexception() << "block #" << bi + 1 << " has no action";
+ }
+ const NProtoBuf::RepeatedPtrField<TAction>& actions = block.action();
+ if (pdesc.GetName() && pdesc.GetProvider()) {
+ TProbeRegistry::TProbesAccessor probes(Registry);
+ bool found = false;
+ for (auto& kv : probes) {
+ TProbe* probe = kv.first;
+ if (probe->Event.Name == pdesc.GetName() && probe->Event.GetProvider() == pdesc.GetProvider()) {
+ InsertExecutor(TraceVariables, bi, pred, actions, probe, destructiveActionsAllowed, customActionFactory);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ythrow yexception() << "block #" << bi + 1 << " has no matching probe with name '"
+ << pdesc.GetName() << "' provider '" << pdesc.GetProvider() << "'";
+ }
+ } else if (pdesc.GetGroup()) {
+ bool found = false;
+ TProbeRegistry::TProbesAccessor probes(Registry);
+ for (auto& kv : probes) {
+ TProbe* probe = kv.first;
+ for (const char* const* gi = probe->Event.Groups; *gi != nullptr; gi++) {
+ if (*gi == pdesc.GetGroup()) {
+ InsertExecutor(TraceVariables, bi, pred, actions, probe, destructiveActionsAllowed, customActionFactory);
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ ythrow yexception() << "block #" << bi + 1
+ << " has no matching probes for group '" << pdesc.GetGroup() << "'";
+ }
+ } else {
+ ythrow yexception() << "block #" << bi + 1 << " has bad probe description: name '" << pdesc.GetName()
+ << "' provider '" << pdesc.GetProvider()
+ << "' group '" << pdesc.GetGroup() << "'";
+ }
+ }
+ } catch (...) {
+ Destroy();
+ throw;
+ }
+ }
+
+ void TSession::Destroy() {
+ Detach();
+ for (auto& probe : Probes) {
+ delete probe.second;
+ }
+ }
+
+ TSession::~TSession() {
+ Destroy();
+ }
+
+ void TSession::Detach() {
+ if (Attached) {
+ for (auto& p : Probes) {
+ TProbe* probe = p.first;
+ IExecutor* exec = p.second;
+ probe->Detach(exec);
+ }
+ Attached = false;
+ }
+ }
+
+ size_t TSession::GetEventsCount() const {
+ return CyclicLog.GetEventsCount() + DurationLog.GetEventsCount() + CyclicDepot.GetEventsCount() + DurationDepot.GetEventsCount();
+ }
+
+ size_t TSession::GetThreadsCount() const {
+ return CyclicLog.GetThreadsCount() + DurationLog.GetThreadsCount() + CyclicDepot.GetThreadsCount() + DurationDepot.GetThreadsCount();
+ }
+
+ class TReadToProtobuf {
+ private:
+ TMap<TThread::TId, TVector<TLogItem>> Items;
+
+ public:
+ void ToProtobuf(TLogPb& pb) const {
+ TSet<TProbe*> probes;
+ ui64 eventsCount = 0;
+ for (auto kv : Items) {
+ TThreadLogPb* tpb = pb.AddThreadLogs();
+ tpb->SetThreadId(kv.first);
+ for (TLogItem& item : kv.second) {
+ item.ToProtobuf(*tpb->AddLogItems());
+ probes.insert(item.Probe);
+ eventsCount++;
+ }
+ }
+ pb.SetEventsCount(eventsCount);
+ for (TProbe* probe : probes) {
+ probe->Event.ToProtobuf(*pb.AddEvents());
+ }
+ }
+
+ void Push(TThread::TId tid, const TLogItem& item) {
+ // Avoid any expansive operations in Push(), because it executes under lock and blocks program being traced
+ Items[tid].push_back(item);
+ }
+ };
+
+ void TSession::ToProtobuf(TLogPb& pb) const {
+ TReadToProtobuf reader;
+ ReadItems(reader);
+ reader.ToProtobuf(pb);
+ pb.MutableQuery()->CopyFrom(Query);
+ pb.SetCrtTime(TInstant::Now().GetValue());
+ }
+
+ TManager::TManager(TProbeRegistry& registry, bool allowDestructiveActions)
+ : Registry(registry)
+ , DestructiveActionsAllowed(allowDestructiveActions)
+ , SerializingExecutor(new TRunLogShuttleActionExecutor<TCyclicDepot>(0, {}, nullptr, nullptr, nullptr))
+ {
+ }
+
+ TManager::~TManager() {
+ for (auto& trace : Traces) {
+ delete trace.second;
+ }
+ }
+
+ bool TManager::HasTrace(const TString& id) const {
+ TGuard<TMutex> g(Mtx);
+ return Traces.contains(id);
+ }
+
+ const TSession* TManager::GetTrace(const TString& id) const {
+ TGuard<TMutex> g(Mtx);
+ TTraces::const_iterator it = Traces.find(id);
+ if (it == Traces.end()) {
+ ythrow yexception() << "trace id '" << id << "' is not used";
+ } else {
+ return it->second;
+ }
+ }
+
+ void TManager::New(const TString& id, const TQuery& query) {
+ TGuard<TMutex> g(Mtx);
+ if (Traces.find(id) == Traces.end()) {
+ TSession* trace = new TSession(++LastTraceIdx, Registry, query, GetDestructiveActionsAllowed(), CustomActionFactory);
+ Traces[id] = trace;
+ } else {
+ ythrow yexception() << "trace id '" << id << "' is already used";
+ }
+ }
+
+ void TManager::Delete(const TString& id) {
+ TGuard<TMutex> g(Mtx);
+ TTraces::iterator it = Traces.find(id);
+ if (it == Traces.end()) {
+ ythrow yexception() << "trace id '" << id << "' is not used";
+ } else {
+ delete it->second;
+ Traces.erase(it);
+ }
+ }
+
+ void TManager::Stop(const TString& id) {
+ TGuard<TMutex> g(Mtx);
+ TTraces::iterator it = Traces.find(id);
+ if (it == Traces.end()) {
+ ythrow yexception() << "trace id '" << id << "' is not used";
+ } else {
+ it->second->Detach();
+ }
+ }
+}
diff --git a/library/cpp/lwtrace/trace_ut.cpp b/library/cpp/lwtrace/trace_ut.cpp
new file mode 100644
index 0000000000..cb03e4fbde
--- /dev/null
+++ b/library/cpp/lwtrace/trace_ut.cpp
@@ -0,0 +1,880 @@
+#include "all.h"
+
+#include <library/cpp/lwtrace/protos/lwtrace.pb.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <google/protobuf/text_format.h>
+
+enum ESimpleEnum {
+ ValueA,
+ ValueB,
+};
+
+enum class EEnumClass {
+ ValueC,
+ ValueD,
+};
+
+#define LWTRACE_UT_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \
+ PROBE(NoParam, GROUPS("Group"), TYPES(), NAMES()) \
+ PROBE(IntParam, GROUPS("Group"), TYPES(ui32), NAMES("value")) \
+ PROBE(StringParam, GROUPS("Group"), TYPES(TString), NAMES("value")) \
+ PROBE(SymbolParam, GROUPS("Group"), TYPES(NLWTrace::TSymbol), NAMES("symbol")) \
+ PROBE(CheckParam, GROUPS("Group"), TYPES(NLWTrace::TCheck), NAMES("value")) \
+ PROBE(EnumParams, GROUPS("Group"), TYPES(ESimpleEnum, EEnumClass), NAMES("simpleEnum", "enumClass")) \
+ PROBE(InstantParam, GROUPS("Group"), TYPES(TInstant), NAMES("value")) \
+ PROBE(DurationParam, GROUPS("Group"), TYPES(TDuration), NAMES("value")) \
+ PROBE(ProtoEnum, GROUPS("Group"), TYPES(NLWTrace::EOperatorType), NAMES("value")) \
+ PROBE(IntIntParams, GROUPS("Group"), TYPES(ui32, ui64), NAMES("value1", "value2")) \
+ /**/
+
+LWTRACE_DECLARE_PROVIDER(LWTRACE_UT_PROVIDER)
+LWTRACE_DEFINE_PROVIDER(LWTRACE_UT_PROVIDER)
+LWTRACE_USING(LWTRACE_UT_PROVIDER)
+
+using namespace NLWTrace;
+
+Y_UNIT_TEST_SUITE(LWTraceTrace) {
+#ifndef LWTRACE_DISABLE
+ Y_UNIT_TEST(Smoke) {
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "NoParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ LogAction { }
+ }
+ }
+ )END",
+ &q);
+ UNIT_ASSERT(parsed);
+ mngr.New("Query1", q);
+ LWPROBE(NoParam);
+ struct {
+ void Push(TThread::TId, const TLogItem& item) {
+ UNIT_ASSERT(TString(item.Probe->Event.Name) == "NoParam");
+ }
+ } reader;
+ mngr.ReadLog("Query1", reader);
+
+ LWPROBE(EnumParams, ValueA, EEnumClass::ValueC);
+ LWPROBE(InstantParam, TInstant::Seconds(42));
+ LWPROBE(DurationParam, TDuration::MilliSeconds(146));
+ LWPROBE(ProtoEnum, OT_EQ);
+ }
+
+ Y_UNIT_TEST(Predicate) {
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "IntParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Predicate {
+ Operators {
+ Type: OT_NE
+ Argument { Param: "value" }
+ Argument { Value: "1" }
+ }
+ }
+ Action {
+ LogAction { }
+ }
+ }
+ )END", &q);
+ UNIT_ASSERT(parsed);
+ mngr.New("QueryName", q);
+ LWPROBE(IntParam, 3);
+ LWPROBE(IntParam, 1);
+ LWPROBE(IntParam, 4);
+ LWPROBE(IntParam, 1);
+ LWPROBE(IntParam, 1);
+ LWPROBE(IntParam, 5);
+ struct {
+ ui32 expected = 3;
+ ui32 logsCount = 0;
+ void Push(TThread::TId, const TLogItem& item) {
+ UNIT_ASSERT(TString(item.Probe->Event.Name) == "IntParam");
+ ui32 value = item.GetParam("value").GetParam().Get<ui32>();
+ UNIT_ASSERT(value == expected);
+ expected++;
+ logsCount++;
+ }
+ } reader;
+ mngr.ReadLog("QueryName", reader);
+ UNIT_ASSERT(reader.logsCount == 3);
+ }
+
+ Y_UNIT_TEST(StatementAction) {
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "IntParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ StatementAction {
+ Type: ST_INC
+ Argument { Variable: "varInc" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_DEC
+ Argument { Variable: "varDec" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_MOV
+ Argument { Variable: "varMov" }
+ Argument { Value: "3" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_ADD_EQ
+ Argument { Variable: "varAddEq" }
+ Argument { Value: "2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_ADD_EQ
+ Argument { Variable: "varAddEq" }
+ Argument { Value: "3" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_SUB_EQ
+ Argument { Variable: "varSubEq" }
+ Argument { Value: "5" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_ADD
+ Argument { Variable: "varAdd" }
+ Argument { Value: "3" }
+ Argument { Value: "2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_SUB
+ Argument { Variable: "varSub" }
+ Argument { Value: "3" }
+ Argument { Value: "2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_MUL
+ Argument { Variable: "varMul" }
+ Argument { Value: "6" }
+ Argument { Value: "2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_DIV
+ Argument { Variable: "varDiv" }
+ Argument { Value: "6" }
+ Argument { Value: "2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_MOD
+ Argument { Variable: "varMod" }
+ Argument { Value: "17" }
+ Argument { Value: "5" }
+ }
+ }
+ }
+ Blocks {
+ ProbeDesc {
+ Name: "IntParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Predicate {
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varInc" }
+ Argument { Value: "1" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varDec" }
+ Argument { Value: "-1" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varMov" }
+ Argument { Value: "3" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varAddEq" }
+ Argument { Value: "5" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varSubEq" }
+ Argument { Value: "-5" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varAdd" }
+ Argument { Value: "5" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varSub" }
+ Argument { Value: "1" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varMul" }
+ Argument { Value: "12" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varDiv" }
+ Argument { Value: "3" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varMod" }
+ Argument { Value: "2" }
+ }
+ }
+ Action {
+ LogAction { }
+ }
+ }
+ )END", &q);
+ UNIT_ASSERT(parsed);
+ mngr.New("QueryName", q);
+ LWPROBE(IntParam, 1);
+ LWPROBE(IntParam, 2);
+ struct {
+ int logsCount = 0;
+ void Push(TThread::TId, const TLogItem& item) {
+ UNIT_ASSERT(TString(item.Probe->Event.Name) == "IntParam");
+ ui32 value = item.GetParam("value").GetParam().Get<ui32>();
+ UNIT_ASSERT(value == 1);
+ logsCount++;
+ }
+ } reader;
+ mngr.ReadLog("QueryName", reader);
+ UNIT_ASSERT(reader.logsCount == 1);
+ }
+
+ Y_UNIT_TEST(StatementActionWithParams) {
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "IntIntParams"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ StatementAction {
+ Type: ST_MOV
+ Argument { Variable: "varMov" }
+ Argument { Param: "value1" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_ADD_EQ
+ Argument { Variable: "varAddEq" }
+ Argument { Param: "value1" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_SUB_EQ
+ Argument { Variable: "varSubEq" }
+ Argument { Param: "value1" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_ADD
+ Argument { Variable: "varAdd" }
+ Argument { Param: "value1" }
+ Argument { Param: "value2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_SUB
+ Argument { Variable: "varSub" }
+ Argument { Param: "value1" }
+ Argument { Param: "value2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_MUL
+ Argument { Variable: "varMul" }
+ Argument { Param: "value1" }
+ Argument { Param: "value2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_DIV
+ Argument { Variable: "varDiv" }
+ Argument { Param: "value1" }
+ Argument { Param: "value2" }
+ }
+ }
+ Action {
+ StatementAction {
+ Type: ST_MOD
+ Argument { Variable: "varMod" }
+ Argument { Param: "value1" }
+ Argument { Param: "value2" }
+ }
+ }
+ }
+ Blocks {
+ ProbeDesc {
+ Name: "IntIntParams"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Predicate {
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varMov" }
+ Argument { Param: "value1" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varAddEq" }
+ Argument { Param: "value1" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varSubEq" }
+ Argument { Value: "-22" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varAdd" }
+ Argument { Value: "25" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varSub" }
+ Argument { Value: "19" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varMul" }
+ Argument { Value: "66" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varDiv" }
+ Argument { Value: "7" }
+ }
+ Operators {
+ Type: OT_EQ
+ Argument { Variable: "varMod" }
+ Argument { Value: "1" }
+ }
+ }
+ Action {
+ LogAction { }
+ }
+ }
+ )END", &q);
+ UNIT_ASSERT(parsed);
+ mngr.New("QueryName", q);
+ LWPROBE(IntIntParams, 22, 3);
+ struct {
+ int logsCount = 0;
+ void Push(TThread::TId, const TLogItem& item) {
+ UNIT_ASSERT(TString(item.Probe->Event.Name) == "IntIntParams");
+ logsCount++;
+ }
+ } reader;
+ mngr.ReadLog("QueryName", reader);
+ UNIT_ASSERT(reader.logsCount == 1);
+ }
+
+ Y_UNIT_TEST(PerThreadLogSize) {
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ PerThreadLogSize: 3
+ Blocks {
+ ProbeDesc {
+ Name: "IntParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ LogAction { }
+ }
+ }
+ )END", &q);
+ UNIT_ASSERT(parsed);
+ mngr.New("QueryRandom", q);
+ LWPROBE(IntParam, 1);
+ LWPROBE(IntParam, 2);
+ LWPROBE(IntParam, 3);
+ LWPROBE(IntParam, 4);
+ struct {
+ ui32 logsCount = 0;
+ ui32 expected = 2;
+ void Push(TThread::TId, const TLogItem& item) {
+ UNIT_ASSERT(TString(item.Probe->Event.Name) == "IntParam");
+ ui32 value = item.GetParam("value").GetParam().Get<ui32>();
+ UNIT_ASSERT(value == expected);
+ logsCount++;
+ expected++;
+ }
+ } reader;
+ mngr.ReadLog("QueryRandom", reader);
+ UNIT_ASSERT(reader.logsCount == 3);
+ }
+
+ Y_UNIT_TEST(CustomAction) {
+ static ui32 nCustomActionsCalls = 0;
+ class TMyActionExecutor: public TCustomActionExecutor {
+ public:
+ TMyActionExecutor(TProbe* probe, const TCustomAction&, TSession*)
+ : TCustomActionExecutor(probe, false /* not destructive */)
+ {}
+ private:
+ bool DoExecute(TOrbit&, const TParams& params) override {
+ (void)params;
+ nCustomActionsCalls++;
+ return true;
+ }
+ };
+
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ mngr.RegisterCustomAction("MyCustomAction", [](TProbe* probe,
+ const TCustomAction& action,
+ TSession* session) {
+ return new TMyActionExecutor(probe, action, session);
+ }
+ );
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "NoParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ CustomAction {
+ Name: "MyCustomAction"
+ }
+ }
+ }
+ )END", &q);
+ UNIT_ASSERT(parsed);
+ mngr.New("Query1", q);
+ LWPROBE(NoParam);
+ UNIT_ASSERT(nCustomActionsCalls == 1);
+ }
+
+ Y_UNIT_TEST(SafeModeSleepException) {
+ TManager mngr(*Singleton<TProbeRegistry>(), false);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "NoParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ SleepAction {
+ NanoSeconds: 1000000000
+ }
+ }
+ }
+ )END", &q);
+ UNIT_ASSERT(parsed);
+ UNIT_ASSERT_EXCEPTION(mngr.New("QueryName", q), yexception);
+ }
+
+ Y_UNIT_TEST(Sleep) {
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "NoParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ SleepAction {
+ NanoSeconds: 1000
+ }
+ }
+ }
+ )END", &q);
+ UNIT_ASSERT(parsed);
+ mngr.New("QueryName", q);
+ const ui64 sleepTimeNs = 1000; // 1 us
+
+ TInstant t0 = Now();
+ LWPROBE(NoParam);
+ TInstant t1 = Now();
+ UNIT_ASSERT(t1.NanoSeconds() - t0.NanoSeconds() >= sleepTimeNs);
+ }
+
+ Y_UNIT_TEST(ProtoEnumTraits) {
+ using TPbEnumTraits = TParamTraits<EOperatorType>;
+ TString str;
+ TPbEnumTraits::ToString(TPbEnumTraits::ToStoreType(OT_EQ), &str);
+ UNIT_ASSERT_STRINGS_EQUAL(str, "OT_EQ (0)");
+ }
+
+ Y_UNIT_TEST(Track) {
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "IntParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ RunLogShuttleAction { }
+ }
+ }
+ )END", &q);
+ UNIT_ASSERT(parsed);
+ mngr.New("Query1", q);
+
+ {
+ TOrbit orbit;
+ LWTRACK(IntParam, orbit, 1);
+ LWTRACK(StringParam, orbit, "str");
+ }
+
+ struct {
+ void Push(TThread::TId, const TTrackLog& tl) {
+ UNIT_ASSERT(tl.Items.size() == 2);
+ UNIT_ASSERT(TString(tl.Items[0].Probe->Event.Name) == "IntParam");
+ UNIT_ASSERT(TString(tl.Items[1].Probe->Event.Name) == "StringParam");
+ }
+ } reader;
+ mngr.ReadDepot("Query1", reader);
+ }
+
+ Y_UNIT_TEST(ShouldSerializeTracks)
+ {
+ TManager manager(*Singleton<TProbeRegistry>(), false);
+
+ TOrbit orbit;
+ TTraceRequest req;
+ req.SetIsTraced(true);
+ manager.HandleTraceRequest(req, orbit);
+
+ LWTRACK(NoParam, orbit);
+ LWTRACK(IntParam, orbit, 1);
+ LWTRACK(StringParam, orbit, "str");
+ LWTRACK(EnumParams, orbit, ValueA, EEnumClass::ValueC);
+ LWTRACK(InstantParam, orbit, TInstant::Seconds(42));
+ LWTRACK(DurationParam, orbit, TDuration::MilliSeconds(146));
+ LWTRACK(ProtoEnum, orbit, OT_EQ);
+ LWTRACK(IntIntParams, orbit, 1, 2);
+
+ TTraceResponse resp;
+ orbit.Serialize(0, *resp.MutableTrace());
+ auto& r = resp.GetTrace();
+
+ UNIT_ASSERT_VALUES_EQUAL(8, r.EventsSize());
+
+ const auto& p0 = r.GetEvents(0);
+ UNIT_ASSERT_VALUES_EQUAL("NoParam", p0.GetName());
+ UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p0.GetProvider());
+ UNIT_ASSERT_VALUES_EQUAL(0 , p0.ParamsSize());
+
+ const auto& p1 = r.GetEvents(1);
+ UNIT_ASSERT_VALUES_EQUAL("IntParam", p1.GetName());
+ UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p1.GetProvider());
+ UNIT_ASSERT_VALUES_EQUAL(1, p1.GetParams(0).GetUintValue());
+
+ const auto& p2 = r.GetEvents(2);
+ UNIT_ASSERT_VALUES_EQUAL("StringParam", p2.GetName());
+ UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p2.GetProvider());
+ UNIT_ASSERT_VALUES_EQUAL("str", p2.GetParams(0).GetStrValue());
+
+ const auto& p3 = r.GetEvents(3);
+ UNIT_ASSERT_VALUES_EQUAL("EnumParams", p3.GetName());
+ UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p3.GetProvider());
+ UNIT_ASSERT_VALUES_EQUAL((ui32)ValueA, p3.GetParams(0).GetIntValue());
+ UNIT_ASSERT_VALUES_EQUAL((ui32)EEnumClass::ValueC, p3.GetParams(1).GetIntValue());
+
+ const auto& p4 = r.GetEvents(4);
+ UNIT_ASSERT_VALUES_EQUAL("InstantParam", p4.GetName());
+ UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p4.GetProvider());
+ UNIT_ASSERT_VALUES_EQUAL(42, p4.GetParams(0).GetDoubleValue());
+
+ const auto& p5 = r.GetEvents(5);
+ UNIT_ASSERT_VALUES_EQUAL("DurationParam", p5.GetName());
+ UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p5.GetProvider());
+ UNIT_ASSERT_VALUES_EQUAL(146, p5.GetParams(0).GetDoubleValue());
+
+ const auto& p6 = r.GetEvents(6);
+ UNIT_ASSERT_VALUES_EQUAL("ProtoEnum", p6.GetName());
+ UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p6.GetProvider());
+ UNIT_ASSERT_VALUES_EQUAL((int)OT_EQ, p6.GetParams(0).GetIntValue());
+
+ const auto& p7 = r.GetEvents(7);
+ UNIT_ASSERT_VALUES_EQUAL("IntIntParams", p7.GetName());
+ UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p7.GetProvider());
+ UNIT_ASSERT_VALUES_EQUAL(1, p7.GetParams(0).GetUintValue());
+ UNIT_ASSERT_VALUES_EQUAL(2, p7.GetParams(1).GetUintValue());
+ }
+
+ Y_UNIT_TEST(ShouldDeserializeTracks)
+ {
+ TManager manager(*Singleton<TProbeRegistry>(), false);
+
+ TTraceResponse resp;
+ auto& r = *resp.MutableTrace()->MutableEvents();
+
+ auto& p0 = *r.Add();
+ p0.SetName("NoParam");
+ p0.SetProvider("LWTRACE_UT_PROVIDER");
+
+ auto& p1 = *r.Add();
+ p1.SetName("IntParam");
+ p1.SetProvider("LWTRACE_UT_PROVIDER");
+ auto& p1param = *p1.MutableParams()->Add();
+ p1param.SetUintValue(1);
+
+ auto& p2 = *r.Add();
+ p2.SetName("StringParam");
+ p2.SetProvider("LWTRACE_UT_PROVIDER");
+ auto& p2param = *p2.MutableParams()->Add();
+ p2param.SetStrValue("str");
+
+ auto& p3 = *r.Add();
+ p3.SetName("EnumParams");
+ p3.SetProvider("LWTRACE_UT_PROVIDER");
+ auto& p3param1 = *p3.MutableParams()->Add();
+ p3param1.SetUintValue((ui64)EEnumClass::ValueC);
+ auto& p3param2 = *p3.MutableParams()->Add();
+ p3param2.SetIntValue((ui64)EEnumClass::ValueC);
+
+ auto& p4 = *r.Add();
+ p4.SetName("InstantParam");
+ p4.SetProvider("LWTRACE_UT_PROVIDER");
+ auto& p4param = *p4.MutableParams()->Add();
+ p4param.SetDoubleValue(42);
+
+ auto& p5 = *r.Add();
+ p5.SetName("DurationParam");
+ p5.SetProvider("LWTRACE_UT_PROVIDER");
+ auto& p5param = *p5.MutableParams()->Add();
+ p5param.SetDoubleValue(146);
+
+ auto& p6 = *r.Add();
+ p6.SetName("ProtoEnum");
+ p6.SetProvider("LWTRACE_UT_PROVIDER");
+ auto& p6param = *p6.MutableParams()->Add();
+ p6param.SetIntValue((i64)OT_EQ);
+
+ auto& p7 = *r.Add();
+ p7.SetName("IntIntParams");
+ p7.SetProvider("LWTRACE_UT_PROVIDER");
+ auto& p7param1 = *p7.MutableParams()->Add();
+ p7param1.SetIntValue(1);
+ auto& p7param2 = *p7.MutableParams()->Add();
+ p7param2.SetIntValue(2);
+
+ TOrbit orbit;
+ UNIT_ASSERT_VALUES_EQUAL(
+ manager.HandleTraceResponse(resp, manager.GetProbesMap(), orbit).IsSuccess,
+ true);
+ }
+
+ Y_UNIT_TEST(ShouldDeserializeWhatSerialized)
+ {
+ TManager manager(*Singleton<TProbeRegistry>(), false);
+
+ TOrbit orbit;
+ TTraceRequest req;
+ req.SetIsTraced(true);
+ manager.HandleTraceRequest(req, orbit);
+
+ LWTRACK(NoParam, orbit);
+ LWTRACK(IntParam, orbit, 1);
+ LWTRACK(StringParam, orbit, "str");
+ LWTRACK(EnumParams, orbit, ValueA, EEnumClass::ValueC);
+ LWTRACK(InstantParam, orbit, TInstant::Seconds(42));
+ LWTRACK(DurationParam, orbit, TDuration::MilliSeconds(146));
+ LWTRACK(ProtoEnum, orbit, OT_EQ);
+ LWTRACK(IntIntParams, orbit, 1, 2);
+
+ TTraceResponse resp;
+ auto& r = *resp.MutableTrace();
+ orbit.Serialize(0, r);
+
+ TOrbit orbit1;
+ UNIT_ASSERT_VALUES_EQUAL(
+ manager.HandleTraceResponse(resp, manager.GetProbesMap(), orbit1).IsSuccess,
+ true);
+ }
+
+ Y_UNIT_TEST(TrackForkJoin) {
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "NoParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ RunLogShuttleAction { }
+ }
+ }
+ )END", &q);
+
+ UNIT_ASSERT(parsed);
+ mngr.New("Query1", q);
+
+ {
+ TOrbit a, b, c, d;
+
+ // Graph:
+ // c
+ // / \
+ // b-f-b-j-b
+ // / \
+ // a-f-a-f-a-j-a-j-a
+ // \ /
+ // d
+ //
+ // Merged track:
+ // a-f(b)-a-f(d)-a-j(d,1)-d-a-j(b,6)-b-f(c)-b-j(c,1)-c-b-a
+
+ LWTRACK(NoParam, a);
+ a.Fork(b);
+ LWTRACK(IntParam, a, 1);
+ a.Fork(d);
+ LWTRACK(IntParam, a, 2);
+
+ LWTRACK(IntParam, b, 3);
+ b.Fork(c);
+ LWTRACK(IntParam, b, 4);
+
+ LWTRACK(IntParam, c, 5);
+ b.Join(c);
+ LWTRACK(IntParam, b, 6);
+
+ LWTRACK(IntParam, d, 7);
+ a.Join(d);
+ LWTRACK(IntParam, a, 8);
+
+ a.Join(b);
+ LWTRACK(IntParam, a, 9);
+ }
+
+ struct {
+ void Push(TThread::TId, const TTrackLog& tl) {
+ UNIT_ASSERT(tl.Items.size() == 16);
+ UNIT_ASSERT(TString(tl.Items[0].Probe->Event.Name) == "NoParam");
+ UNIT_ASSERT(TString(tl.Items[1].Probe->Event.Name) == "Fork");
+ UNIT_ASSERT(tl.Items[2].Params.Param[0].Get<ui64>() == 1);
+ UNIT_ASSERT(TString(tl.Items[3].Probe->Event.Name) == "Fork");
+ UNIT_ASSERT(tl.Items[4].Params.Param[0].Get<ui64>() == 2);
+ UNIT_ASSERT(TString(tl.Items[5].Probe->Event.Name) == "Join");
+ UNIT_ASSERT(tl.Items[6].Params.Param[0].Get<ui64>() == 7);
+ UNIT_ASSERT(tl.Items[7].Params.Param[0].Get<ui64>() == 8);
+ UNIT_ASSERT(TString(tl.Items[8].Probe->Event.Name) == "Join");
+ UNIT_ASSERT(tl.Items[9].Params.Param[0].Get<ui64>() == 3);
+ UNIT_ASSERT(TString(tl.Items[10].Probe->Event.Name) == "Fork");
+ UNIT_ASSERT(tl.Items[11].Params.Param[0].Get<ui64>() == 4);
+ UNIT_ASSERT(TString(tl.Items[12].Probe->Event.Name) == "Join");
+ UNIT_ASSERT(tl.Items[13].Params.Param[0].Get<ui64>() == 5);
+ UNIT_ASSERT(tl.Items[14].Params.Param[0].Get<ui64>() == 6);
+ UNIT_ASSERT(tl.Items[15].Params.Param[0].Get<ui64>() == 9);
+ }
+ } reader;
+ mngr.ReadDepot("Query1", reader);
+ }
+
+ Y_UNIT_TEST(TrackForkError) {
+ TManager mngr(*Singleton<TProbeRegistry>(), true);
+ TQuery q;
+ bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
+ Blocks {
+ ProbeDesc {
+ Name: "NoParam"
+ Provider: "LWTRACE_UT_PROVIDER"
+ }
+ Action {
+ RunLogShuttleAction {
+ MaxTrackLength: 100
+ }
+ }
+ }
+ )END", &q);
+
+ UNIT_ASSERT(parsed);
+ mngr.New("Query1", q);
+
+ constexpr size_t n = (100 + 2) / 3 + 1;
+
+ {
+ TVector<TVector<TOrbit>> span;
+
+ while (1) {
+ TVector<TOrbit> orbit(n);
+
+ LWTRACK(NoParam, orbit[0]);
+ if (!orbit[0].HasShuttles()) {
+ break;
+ }
+ for (size_t i = 1; i < n; i++) {
+ if (!orbit[i - 1].Fork(orbit[i])) {
+ break;
+ }
+ LWTRACK(IntParam, orbit[i], i);
+ }
+
+ span.emplace_back(std::move(orbit));
+ }
+
+ for (auto& orbit: span) {
+ for (auto it = orbit.rbegin(); it + 1 != orbit.rend(); it++) {
+ (it + 1)->Join(*it);
+ }
+ }
+ }
+
+ struct {
+ void Push(TThread::TId, const TTrackLog& tl) {
+ UNIT_ASSERT(tl.Items.size() == 100);
+ UNIT_ASSERT(tl.Truncated);
+ }
+ } reader;
+ mngr.ReadDepot("Query1", reader);
+ }
+#endif // LWTRACE_DISABLE
+}
diff --git a/library/cpp/lwtrace/ut/ya.make b/library/cpp/lwtrace/ut/ya.make
new file mode 100644
index 0000000000..f43118bab7
--- /dev/null
+++ b/library/cpp/lwtrace/ut/ya.make
@@ -0,0 +1,11 @@
+UNITTEST_FOR(library/cpp/lwtrace)
+
+OWNER(serxa)
+
+FORK_SUBTESTS()
+
+SRCS(
+ trace_ut.cpp
+)
+
+END()
diff --git a/library/cpp/lwtrace/ya.make b/library/cpp/lwtrace/ya.make
new file mode 100644
index 0000000000..d9accb3006
--- /dev/null
+++ b/library/cpp/lwtrace/ya.make
@@ -0,0 +1,29 @@
+LIBRARY()
+
+OWNER(serxa)
+
+PEERDIR(
+ library/cpp/lwtrace/protos
+)
+
+SRCS(
+ check.cpp
+ control.cpp
+ custom_action.cpp
+ kill_action.cpp
+ log_shuttle.cpp
+ perf.cpp
+ probes.cpp
+ shuttle.cpp
+ sleep_action.cpp
+ start.cpp
+ stderr_writer.cpp
+ symbol.cpp
+ trace.cpp
+)
+
+END()
+
+RECURSE(mon)
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/malloc/api/helpers/io.cpp b/library/cpp/malloc/api/helpers/io.cpp
new file mode 100644
index 0000000000..5177969f4d
--- /dev/null
+++ b/library/cpp/malloc/api/helpers/io.cpp
@@ -0,0 +1,10 @@
+#include <library/cpp/malloc/api/malloc.h>
+
+#include <util/stream/output.h>
+
+using namespace NMalloc;
+
+template <>
+void Out<TMallocInfo>(IOutputStream& out, const TMallocInfo& info) {
+ out << "malloc (name = " << info.Name << ")";
+}
diff --git a/library/cpp/malloc/api/helpers/ya.make b/library/cpp/malloc/api/helpers/ya.make
new file mode 100644
index 0000000000..62875bca0e
--- /dev/null
+++ b/library/cpp/malloc/api/helpers/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ library/cpp/malloc/api
+)
+
+SRCS(
+ io.cpp
+)
+
+END()
diff --git a/library/cpp/malloc/api/malloc.cpp b/library/cpp/malloc/api/malloc.cpp
new file mode 100644
index 0000000000..eed1c58a38
--- /dev/null
+++ b/library/cpp/malloc/api/malloc.cpp
@@ -0,0 +1,37 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "malloc.h"
+
+namespace {
+ bool SetEmptyParam(const char*, const char*) {
+ return false;
+ }
+
+ const char* GetEmptyParam(const char*) {
+ return nullptr;
+ }
+
+ bool CheckEmptyParam(const char*, bool defaultValue) {
+ return defaultValue;
+ }
+}
+
+namespace NMalloc {
+ volatile bool IsAllocatorCorrupted = false;
+
+ TMallocInfo::TMallocInfo()
+ : Name()
+ , SetParam(SetEmptyParam)
+ , GetParam(GetEmptyParam)
+ , CheckParam(CheckEmptyParam)
+ {
+ }
+
+ void AbortFromCorruptedAllocator(const char* errorMessage) {
+ errorMessage = errorMessage ? errorMessage : "<unspecified>";
+ fprintf(stderr, "Allocator error: %s\n", errorMessage);
+ IsAllocatorCorrupted = true;
+ abort();
+ }
+}
diff --git a/library/cpp/malloc/api/malloc.h b/library/cpp/malloc/api/malloc.h
new file mode 100644
index 0000000000..ebd545d6dd
--- /dev/null
+++ b/library/cpp/malloc/api/malloc.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <string.h>
+#include <util/system/compiler.h>
+
+namespace NMalloc {
+ struct TMallocInfo {
+ TMallocInfo();
+
+ const char* Name;
+
+ bool (*SetParam)(const char* param, const char* value);
+ const char* (*GetParam)(const char* param);
+
+ bool (*CheckParam)(const char* param, bool defaultValue);
+ };
+
+ extern volatile bool IsAllocatorCorrupted;
+ void AbortFromCorruptedAllocator(const char* errorMessage = nullptr);
+
+ // this function should be implemented by malloc implementations
+ TMallocInfo MallocInfo();
+
+ struct TAllocHeader {
+ void* Block;
+ size_t AllocSize;
+ void Y_FORCE_INLINE Encode(void* block, size_t size, size_t signature) {
+ Block = block;
+ AllocSize = size | signature;
+ }
+ };
+}
diff --git a/library/cpp/malloc/api/ut/ut.cpp b/library/cpp/malloc/api/ut/ut.cpp
new file mode 100644
index 0000000000..7eccd0bf8d
--- /dev/null
+++ b/library/cpp/malloc/api/ut/ut.cpp
@@ -0,0 +1,10 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/malloc/api/malloc.h>
+
+Y_UNIT_TEST_SUITE(MallocApi) {
+ Y_UNIT_TEST(ToStream) {
+ TStringStream ss;
+ ss << NMalloc::MallocInfo();
+ }
+}
diff --git a/library/cpp/malloc/api/ut/ya.make b/library/cpp/malloc/api/ut/ya.make
new file mode 100644
index 0000000000..e57225b45d
--- /dev/null
+++ b/library/cpp/malloc/api/ut/ya.make
@@ -0,0 +1,13 @@
+UNITTEST()
+
+OWNER(nga)
+
+PEERDIR(
+ library/cpp/malloc/api/helpers
+)
+
+SRCS(
+ ut.cpp
+)
+
+END()
diff --git a/library/cpp/malloc/api/ya.make b/library/cpp/malloc/api/ya.make
new file mode 100644
index 0000000000..0ebaa0c589
--- /dev/null
+++ b/library/cpp/malloc/api/ya.make
@@ -0,0 +1,11 @@
+LIBRARY()
+
+NO_UTIL()
+
+OWNER(nga)
+
+SRCS(
+ malloc.cpp
+)
+
+END()
diff --git a/library/cpp/malloc/jemalloc/malloc-info.cpp b/library/cpp/malloc/jemalloc/malloc-info.cpp
new file mode 100644
index 0000000000..2643ca4766
--- /dev/null
+++ b/library/cpp/malloc/jemalloc/malloc-info.cpp
@@ -0,0 +1,65 @@
+#include <library/cpp/malloc/api/malloc.h>
+
+using namespace NMalloc;
+
+#if defined(_MSC_VER)
+TMallocInfo NMalloc::MallocInfo() {
+ TMallocInfo r;
+ r.Name = "jemalloc";
+ return r;
+}
+#else
+#include <strings.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <contrib/libs/jemalloc/include/jemalloc/jemalloc.h>
+
+namespace {
+ bool JESetParam(const char* param, const char*) {
+ if (param) {
+ if (strcmp(param, "j:reset_epoch") == 0) {
+ uint64_t epoch = 1;
+ size_t sz = sizeof(epoch);
+
+ mallctl("epoch", &epoch, &sz, &epoch, sz);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ return false;
+ }
+
+ const char* JEGetParam(const char* param) {
+ if (param) {
+ if (strcmp(param, "allocated") == 0) {
+ JESetParam("j:reset_epoch", nullptr);
+
+ size_t allocated = 0;
+ size_t sz = sizeof(allocated);
+
+ mallctl("stats.allocated", &allocated, &sz, nullptr, 0);
+
+ static_assert(sizeof(size_t) == sizeof(void*), "fix me");
+
+ return (const char*)(void*)allocated;
+ }
+
+ return nullptr;
+ }
+
+ return nullptr;
+ }
+}
+
+TMallocInfo NMalloc::MallocInfo() {
+ TMallocInfo r;
+ r.Name = "jemalloc";
+ r.SetParam = JESetParam;
+ r.GetParam = JEGetParam;
+ return r;
+}
+#endif
diff --git a/library/cpp/malloc/jemalloc/ya.make b/library/cpp/malloc/jemalloc/ya.make
new file mode 100644
index 0000000000..99db474eab
--- /dev/null
+++ b/library/cpp/malloc/jemalloc/ya.make
@@ -0,0 +1,21 @@
+LIBRARY()
+
+NO_UTIL()
+
+OWNER(nga)
+
+IF (OS_ANDROID)
+ PEERDIR(
+ library/cpp/malloc/system
+ )
+ELSE()
+ PEERDIR(
+ library/cpp/malloc/api
+ contrib/libs/jemalloc
+ )
+ SRCS(
+ malloc-info.cpp
+ )
+ENDIF()
+
+END()
diff --git a/library/cpp/malloc/tcmalloc/malloc-info.cpp b/library/cpp/malloc/tcmalloc/malloc-info.cpp
new file mode 100644
index 0000000000..fbcfa7ee06
--- /dev/null
+++ b/library/cpp/malloc/tcmalloc/malloc-info.cpp
@@ -0,0 +1,9 @@
+#include <library/cpp/malloc/api/malloc.h>
+
+using namespace NMalloc;
+
+TMallocInfo NMalloc::MallocInfo() {
+ TMallocInfo r;
+ r.Name = "tcmalloc";
+ return r;
+}
diff --git a/library/cpp/malloc/tcmalloc/ya.make b/library/cpp/malloc/tcmalloc/ya.make
new file mode 100644
index 0000000000..21372ff9e2
--- /dev/null
+++ b/library/cpp/malloc/tcmalloc/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+NO_UTIL()
+
+OWNER(ayles)
+
+PEERDIR(
+ library/cpp/malloc/api
+ contrib/libs/tcmalloc/malloc_extension
+)
+SRCS(
+ malloc-info.cpp
+)
+
+END()
diff --git a/library/cpp/malloc/ya.make b/library/cpp/malloc/ya.make
new file mode 100644
index 0000000000..0ec9db71d2
--- /dev/null
+++ b/library/cpp/malloc/ya.make
@@ -0,0 +1,26 @@
+RECURSE(
+ api
+ api/helpers
+ api/ut
+ tcmalloc
+ galloc
+ jemalloc
+ lockless
+ nalf
+ sample-client
+ system
+ mimalloc
+ mimalloc/link_test
+ hu
+ hu/link_test
+)
+
+IF (NOT OS_WINDOWS)
+ RECURSE(
+ calloc
+ calloc/tests
+ calloc/calloc_profile_diff
+ calloc/calloc_profile_scan
+ calloc/calloc_profile_scan/ut
+ )
+ENDIF()
diff --git a/library/cpp/messagebus/acceptor.cpp b/library/cpp/messagebus/acceptor.cpp
new file mode 100644
index 0000000000..64a38619c2
--- /dev/null
+++ b/library/cpp/messagebus/acceptor.cpp
@@ -0,0 +1,127 @@
+#include "acceptor.h"
+
+#include "key_value_printer.h"
+#include "mb_lwtrace.h"
+#include "network.h"
+
+#include <util/network/init.h>
+#include <util/system/defaults.h>
+#include <util/system/error.h>
+#include <util/system/yassert.h>
+
+LWTRACE_USING(LWTRACE_MESSAGEBUS_PROVIDER)
+
+using namespace NActor;
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+TAcceptor::TAcceptor(TBusSessionImpl* session, ui64 acceptorId, SOCKET socket, const TNetAddr& addr)
+ : TActor<TAcceptor>(session->Queue->WorkQueue.Get())
+ , AcceptorId(acceptorId)
+ , Session(session)
+ , GranStatus(session->Config.Secret.StatusFlushPeriod)
+{
+ SetNonBlock(socket, true);
+
+ Channel = Session->ReadEventLoop.Register(socket, this);
+ Channel->EnableRead();
+
+ Stats.AcceptorId = acceptorId;
+ Stats.Fd = socket;
+ Stats.ListenAddr = addr;
+
+ SendStatus(TInstant::Now());
+}
+
+void TAcceptor::Act(TDefaultTag) {
+ EShutdownState state = ShutdownState.State.Get();
+
+ if (state == SS_SHUTDOWN_COMPLETE) {
+ return;
+ }
+
+ TInstant now = TInstant::Now();
+
+ if (state == SS_SHUTDOWN_COMMAND) {
+ if (!!Channel) {
+ Channel->Unregister();
+ Channel.Drop();
+ Stats.Fd = INVALID_SOCKET;
+ }
+
+ SendStatus(now);
+
+ Session->GetDeadAcceptorStatusQueue()->EnqueueAndSchedule(Stats);
+ Stats.ResetIncremental();
+
+ ShutdownState.CompleteShutdown();
+ return;
+ }
+
+ THolder<TOpaqueAddr> addr(new TOpaqueAddr());
+ SOCKET acceptedSocket = accept(Channel->GetSocket(), addr->MutableAddr(), addr->LenPtr());
+
+ int acceptErrno = LastSystemError();
+
+ if (acceptedSocket == INVALID_SOCKET) {
+ if (LastSystemError() != EWOULDBLOCK) {
+ Stats.LastAcceptErrorErrno = acceptErrno;
+ Stats.LastAcceptErrorInstant = now;
+ ++Stats.AcceptErrorCount;
+ }
+ } else {
+ TSocketHolder s(acceptedSocket);
+ try {
+ SetKeepAlive(s, true);
+ SetNoDelay(s, Session->Config.TcpNoDelay);
+ SetSockOptTcpCork(s, Session->Config.TcpCork);
+ SetCloseOnExec(s, true);
+ SetNonBlock(s, true);
+ if (Session->Config.SocketToS >= 0) {
+ SetSocketToS(s, addr.Get(), Session->Config.SocketToS);
+ }
+ } catch (...) {
+ // It means that connection was reset just now
+ // TODO: do something better
+ goto skipAccept;
+ }
+
+ {
+ TOnAccept onAccept;
+ onAccept.s = s.Release();
+ onAccept.addr = TNetAddr(addr.Release());
+ onAccept.now = now;
+
+ LWPROBE(Accepted, ToString(onAccept.addr));
+
+ Session->GetOnAcceptQueue()->EnqueueAndSchedule(onAccept);
+
+ Stats.LastAcceptSuccessInstant = now;
+ ++Stats.AcceptSuccessCount;
+ }
+
+ skipAccept:;
+ }
+
+ Channel->EnableRead();
+
+ SendStatus(now);
+}
+
+void TAcceptor::SendStatus(TInstant now) {
+ GranStatus.Listen.Update(Stats, now);
+}
+
+void TAcceptor::HandleEvent(SOCKET socket, void* cookie) {
+ Y_UNUSED(socket);
+ Y_UNUSED(cookie);
+
+ GetActor()->Schedule();
+}
+
+void TAcceptor::Shutdown() {
+ ShutdownState.ShutdownCommand();
+ GetActor()->Schedule();
+
+ ShutdownState.ShutdownComplete.WaitI();
+}
diff --git a/library/cpp/messagebus/acceptor.h b/library/cpp/messagebus/acceptor.h
new file mode 100644
index 0000000000..57cb010bf2
--- /dev/null
+++ b/library/cpp/messagebus/acceptor.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "acceptor_status.h"
+#include "defs.h"
+#include "event_loop.h"
+#include "netaddr.h"
+#include "session_impl.h"
+#include "shutdown_state.h"
+
+#include <library/cpp/messagebus/actor/actor.h>
+
+#include <util/system/event.h>
+
+namespace NBus {
+ namespace NPrivate {
+ class TAcceptor
+ : public NEventLoop::IEventHandler,
+ private ::NActor::TActor<TAcceptor> {
+ friend struct TBusSessionImpl;
+ friend class ::NActor::TActor<TAcceptor>;
+
+ public:
+ TAcceptor(TBusSessionImpl* session, ui64 acceptorId, SOCKET socket, const TNetAddr& addr);
+
+ void HandleEvent(SOCKET socket, void* cookie) override;
+
+ void Shutdown();
+
+ inline ::NActor::TActor<TAcceptor>* GetActor() {
+ return this;
+ }
+
+ private:
+ void SendStatus(TInstant now);
+ void Act(::NActor::TDefaultTag);
+
+ private:
+ const ui64 AcceptorId;
+
+ TBusSessionImpl* const Session;
+ NEventLoop::TChannelPtr Channel;
+
+ TAcceptorStatus Stats;
+
+ TAtomicShutdownState ShutdownState;
+
+ struct TGranStatus {
+ TGranStatus(TDuration gran)
+ : Listen(gran)
+ {
+ }
+
+ TGranUp<TAcceptorStatus> Listen;
+ };
+
+ TGranStatus GranStatus;
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/acceptor_status.cpp b/library/cpp/messagebus/acceptor_status.cpp
new file mode 100644
index 0000000000..5006ff68ae
--- /dev/null
+++ b/library/cpp/messagebus/acceptor_status.cpp
@@ -0,0 +1,68 @@
+#include "acceptor_status.h"
+
+#include "key_value_printer.h"
+
+#include <util/stream/format.h>
+#include <util/stream/output.h>
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+TAcceptorStatus::TAcceptorStatus()
+ : Summary(false)
+ , AcceptorId(0)
+ , Fd(INVALID_SOCKET)
+{
+ ResetIncremental();
+}
+
+void TAcceptorStatus::ResetIncremental() {
+ AcceptSuccessCount = 0;
+ AcceptErrorCount = 0;
+ LastAcceptErrorErrno = 0;
+ LastAcceptErrorInstant = TInstant();
+ LastAcceptSuccessInstant = TInstant();
+}
+
+TAcceptorStatus& TAcceptorStatus::operator+=(const TAcceptorStatus& that) {
+ Y_ASSERT(Summary);
+ Y_ASSERT(AcceptorId == 0);
+
+ AcceptSuccessCount += that.AcceptSuccessCount;
+ LastAcceptSuccessInstant = Max(LastAcceptSuccessInstant, that.LastAcceptSuccessInstant);
+
+ AcceptErrorCount += that.AcceptErrorCount;
+ if (that.LastAcceptErrorInstant > LastAcceptErrorInstant) {
+ LastAcceptErrorInstant = that.LastAcceptErrorInstant;
+ LastAcceptErrorErrno = that.LastAcceptErrorErrno;
+ }
+
+ return *this;
+}
+
+TString TAcceptorStatus::PrintToString() const {
+ TStringStream ss;
+
+ if (!Summary) {
+ ss << "acceptor (" << AcceptorId << "), fd=" << Fd << ", addr=" << ListenAddr << Endl;
+ }
+
+ TKeyValuePrinter p;
+
+ p.AddRow("accept error count", LeftPad(AcceptErrorCount, 4));
+
+ if (AcceptErrorCount > 0) {
+ p.AddRow("last accept error",
+ TString() + LastSystemErrorText(LastAcceptErrorErrno) + " at " + LastAcceptErrorInstant.ToString());
+ }
+
+ p.AddRow("accept success count", LeftPad(AcceptSuccessCount, 4));
+ if (AcceptSuccessCount > 0) {
+ p.AddRow("last accept success",
+ TString() + "at " + LastAcceptSuccessInstant.ToString());
+ }
+
+ ss << p.PrintToString();
+
+ return ss.Str();
+}
diff --git a/library/cpp/messagebus/acceptor_status.h b/library/cpp/messagebus/acceptor_status.h
new file mode 100644
index 0000000000..6aa1404f4d
--- /dev/null
+++ b/library/cpp/messagebus/acceptor_status.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "netaddr.h"
+
+#include <util/network/init.h>
+
+namespace NBus {
+ namespace NPrivate {
+ struct TAcceptorStatus {
+ bool Summary;
+
+ ui64 AcceptorId;
+
+ SOCKET Fd;
+
+ TNetAddr ListenAddr;
+
+ unsigned AcceptSuccessCount;
+ TInstant LastAcceptSuccessInstant;
+
+ unsigned AcceptErrorCount;
+ TInstant LastAcceptErrorInstant;
+ int LastAcceptErrorErrno;
+
+ void ResetIncremental();
+
+ TAcceptorStatus();
+
+ TAcceptorStatus& operator+=(const TAcceptorStatus& that);
+
+ TString PrintToString() const;
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/actor/actor.h b/library/cpp/messagebus/actor/actor.h
new file mode 100644
index 0000000000..9b8f20298a
--- /dev/null
+++ b/library/cpp/messagebus/actor/actor.h
@@ -0,0 +1,144 @@
+#pragma once
+
+#include "executor.h"
+#include "tasks.h"
+#include "what_thread_does.h"
+
+#include <util/system/yassert.h>
+
+namespace NActor {
+ class IActor: protected IWorkItem {
+ public:
+ // TODO: make private
+ TTasks Tasks;
+
+ public:
+ virtual void ScheduleHereV() = 0;
+ virtual void ScheduleV() = 0;
+ virtual void ScheduleHereAtMostOnceV() = 0;
+
+ // TODO: make private
+ virtual void RefV() = 0;
+ virtual void UnRefV() = 0;
+
+ // mute warnings
+ ~IActor() override {
+ }
+ };
+
+ struct TDefaultTag {};
+
+ template <typename TThis, typename TTag = TDefaultTag>
+ class TActor: public IActor {
+ private:
+ TExecutor* const Executor;
+
+ public:
+ TActor(TExecutor* executor)
+ : Executor(executor)
+ {
+ }
+
+ void AddTaskFromActorLoop() {
+ bool schedule = Tasks.AddTask();
+ // TODO: check thread id
+ Y_ASSERT(!schedule);
+ }
+
+ /**
+ * Schedule actor.
+ *
+ * If actor is sleeping, then actor will be executed right now.
+ * If actor is executing right now, it will be executed one more time.
+ * If this method is called multiple time, actor will be re-executed no more than one more time.
+ */
+ void Schedule() {
+ if (Tasks.AddTask()) {
+ EnqueueWork();
+ }
+ }
+
+ /**
+ * Schedule actor, execute it in current thread.
+ *
+ * If actor is running, continue executing where it is executing.
+ * If actor is sleeping, execute it in current thread.
+ *
+ * Operation is useful for tasks that are likely to complete quickly.
+ */
+ void ScheduleHere() {
+ if (Tasks.AddTask()) {
+ Loop();
+ }
+ }
+
+ /**
+ * Schedule actor, execute in current thread no more than once.
+ *
+ * If actor is running, continue executing where it is executing.
+ * If actor is sleeping, execute one iteration here, and if actor got new tasks,
+ * reschedule it in worker pool.
+ */
+ void ScheduleHereAtMostOnce() {
+ if (Tasks.AddTask()) {
+ bool fetched = Tasks.FetchTask();
+ Y_VERIFY(fetched, "happens");
+
+ DoAct();
+
+ // if someone added more tasks, schedule them
+ if (Tasks.FetchTask()) {
+ bool added = Tasks.AddTask();
+ Y_VERIFY(!added, "happens");
+ EnqueueWork();
+ }
+ }
+ }
+
+ void ScheduleHereV() override {
+ ScheduleHere();
+ }
+ void ScheduleV() override {
+ Schedule();
+ }
+ void ScheduleHereAtMostOnceV() override {
+ ScheduleHereAtMostOnce();
+ }
+ void RefV() override {
+ GetThis()->Ref();
+ }
+ void UnRefV() override {
+ GetThis()->UnRef();
+ }
+
+ private:
+ TThis* GetThis() {
+ return static_cast<TThis*>(this);
+ }
+
+ void EnqueueWork() {
+ GetThis()->Ref();
+ Executor->EnqueueWork({this});
+ }
+
+ void DoAct() {
+ WHAT_THREAD_DOES_PUSH_POP_CURRENT_FUNC();
+
+ GetThis()->Act(TTag());
+ }
+
+ void Loop() {
+ // TODO: limit number of iterations
+ while (Tasks.FetchTask()) {
+ DoAct();
+ }
+ }
+
+ void DoWork() override {
+ Y_ASSERT(GetThis()->RefCount() >= 1);
+ Loop();
+ GetThis()->UnRef();
+ }
+ };
+
+}
diff --git a/library/cpp/messagebus/actor/actor_ut.cpp b/library/cpp/messagebus/actor/actor_ut.cpp
new file mode 100644
index 0000000000..b76ab55bfa
--- /dev/null
+++ b/library/cpp/messagebus/actor/actor_ut.cpp
@@ -0,0 +1,157 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "actor.h"
+#include "queue_in_actor.h"
+
+#include <library/cpp/messagebus/misc/test_sync.h>
+
+#include <util/generic/object_counter.h>
+#include <util/system/event.h>
+
+using namespace NActor;
+
+template <typename TThis>
+struct TTestActorBase: public TAtomicRefCount<TThis>, public TActor<TThis> {
+ TTestSync Started;
+ TTestSync Acted;
+
+ TTestActorBase(TExecutor* executor)
+ : TActor<TThis>(executor)
+ {
+ }
+
+ void Act(TDefaultTag) {
+ Started.Inc();
+ static_cast<TThis*>(this)->Act2();
+ Acted.Inc();
+ }
+};
+
+struct TNopActor: public TTestActorBase<TNopActor> {
+ TObjectCounter<TNopActor> AllocCounter;
+
+ TNopActor(TExecutor* executor)
+ : TTestActorBase<TNopActor>(executor)
+ {
+ }
+
+ void Act2() {
+ }
+};
+
+struct TWaitForSignalActor: public TTestActorBase<TWaitForSignalActor> {
+ TWaitForSignalActor(TExecutor* executor)
+ : TTestActorBase<TWaitForSignalActor>(executor)
+ {
+ }
+
+ TSystemEvent WaitFor;
+
+ void Act2() {
+ WaitFor.Wait();
+ }
+};
+
+struct TDecrementAndSendActor: public TTestActorBase<TDecrementAndSendActor>, public TQueueInActor<TDecrementAndSendActor, int> {
+ TSystemEvent Done;
+
+ TDecrementAndSendActor* Next;
+
+ TDecrementAndSendActor(TExecutor* executor)
+ : TTestActorBase<TDecrementAndSendActor>(executor)
+ , Next(nullptr)
+ {
+ }
+
+ void ProcessItem(TDefaultTag, TDefaultTag, int n) {
+ if (n == 0) {
+ Done.Signal();
+ } else {
+ Next->EnqueueAndSchedule(n - 1);
+ }
+ }
+
+ void Act(TDefaultTag) {
+ DequeueAll();
+ }
+};
+
+struct TObjectCountChecker {
+ TObjectCountChecker() {
+ CheckCounts();
+ }
+
+ ~TObjectCountChecker() {
+ CheckCounts();
+ }
+
+ void CheckCounts() {
+ UNIT_ASSERT_VALUES_EQUAL(TAtomicBase(0), TObjectCounter<TNopActor>::ObjectCount());
+ UNIT_ASSERT_VALUES_EQUAL(TAtomicBase(0), TObjectCounter<TWaitForSignalActor>::ObjectCount());
+ UNIT_ASSERT_VALUES_EQUAL(TAtomicBase(0), TObjectCounter<TDecrementAndSendActor>::ObjectCount());
+ }
+};
+
+Y_UNIT_TEST_SUITE(TActor) {
+ Y_UNIT_TEST(Simple) {
+ TObjectCountChecker objectCountChecker;
+
+ TExecutor executor(4);
+
+ TIntrusivePtr<TNopActor> actor(new TNopActor(&executor));
+
+ actor->Schedule();
+
+ actor->Acted.WaitFor(1u);
+ }
+
+ Y_UNIT_TEST(ScheduleAfterStart) {
+ TObjectCountChecker objectCountChecker;
+
+ TExecutor executor(4);
+
+ TIntrusivePtr<TWaitForSignalActor> actor(new TWaitForSignalActor(&executor));
+
+ actor->Schedule();
+
+ actor->Started.WaitFor(1);
+
+ actor->Schedule();
+
+ actor->WaitFor.Signal();
+
+ // make sure Act is called second time
+ actor->Acted.WaitFor(2u);
+ }
+
+ void ComplexImpl(int queueSize, int actorCount) {
+ TObjectCountChecker objectCountChecker;
+
+ TExecutor executor(queueSize);
+
+ TVector<TIntrusivePtr<TDecrementAndSendActor>> actors;
+ for (int i = 0; i < actorCount; ++i) {
+ actors.push_back(new TDecrementAndSendActor(&executor));
+ }
+
+ for (int i = 0; i < actorCount; ++i) {
+ actors.at(i)->Next = &*actors.at((i + 1) % actorCount);
+ }
+
+ for (int i = 0; i < actorCount; ++i) {
+ actors.at(i)->EnqueueAndSchedule(10000);
+ }
+
+ for (int i = 0; i < actorCount; ++i) {
+ actors.at(i)->Done.WaitI();
+ }
+ }
+
+ Y_UNIT_TEST(ComplexContention) {
+ ComplexImpl(4, 6);
+ }
+
+ Y_UNIT_TEST(ComplexNoContention) {
+ ComplexImpl(6, 4);
+ }
+}
diff --git a/library/cpp/messagebus/actor/executor.cpp b/library/cpp/messagebus/actor/executor.cpp
new file mode 100644
index 0000000000..7a2227a458
--- /dev/null
+++ b/library/cpp/messagebus/actor/executor.cpp
@@ -0,0 +1,338 @@
+#include "executor.h"
+
+#include "thread_extra.h"
+#include "what_thread_does.h"
+#include "what_thread_does_guard.h"
+
+#include <util/generic/utility.h>
+#include <util/random/random.h>
+#include <util/stream/str.h>
+#include <util/system/tls.h>
+#include <util/system/yassert.h>
+
+#include <array>
+
+using namespace NActor;
+using namespace NActor::NPrivate;
+
+namespace {
+ struct THistoryInternal {
+ struct TRecord {
+ TAtomic MaxQueueSize;
+
+ TRecord()
+ : MaxQueueSize()
+ {
+ }
+
+ TExecutorHistory::THistoryRecord Capture() {
+ TExecutorHistory::THistoryRecord r;
+ r.MaxQueueSize = AtomicGet(MaxQueueSize);
+ return r;
+ }
+ };
+
+ ui64 Start;
+ ui64 LastTime;
+
+ std::array<TRecord, 3600> Records;
+
+ THistoryInternal() {
+ Start = TInstant::Now().Seconds();
+ LastTime = Start - 1;
+ }
+
+ TRecord& GetRecordForTime(ui64 time) {
+ return Records[time % Records.size()];
+ }
+
+ TRecord& GetNowRecord(ui64 now) {
+ for (ui64 t = LastTime + 1; t <= now; ++t) {
+ GetRecordForTime(t) = TRecord();
+ }
+ LastTime = now;
+ return GetRecordForTime(now);
+ }
+
+ TExecutorHistory Capture() {
+ TExecutorHistory history;
+ ui64 now = TInstant::Now().Seconds();
+ ui64 lastHistoryRecord = now - 1;
+ ui32 historySize = Min<ui32>(lastHistoryRecord - Start, Records.size() - 1);
+ history.HistoryRecords.resize(historySize);
+ for (ui32 i = 0; i < historySize; ++i) {
+ history.HistoryRecords[i] = GetRecordForTime(lastHistoryRecord - historySize + i).Capture();
+ }
+ history.LastHistoryRecordSecond = lastHistoryRecord;
+ return history;
+ }
+ };
+
+}
+
+Y_POD_STATIC_THREAD(TExecutor*)
+ThreadCurrentExecutor;
+
+static const char* NoLocation = "nowhere";
+
+struct TExecutorWorkerThreadLocalData {
+ ui32 MaxQueueSize;
+};
+
+static TExecutorWorkerThreadLocalData WorkerNoThreadLocalData;
+Y_POD_STATIC_THREAD(TExecutorWorkerThreadLocalData)
+WorkerThreadLocalData;
+
+namespace NActor {
+ struct TExecutorWorker {
+ TExecutor* const Executor;
+ TThread Thread;
+ const char** WhatThreadDoesLocation;
+ TExecutorWorkerThreadLocalData* ThreadLocalData;
+
+ TExecutorWorker(TExecutor* executor)
+ : Executor(executor)
+ , Thread(RunThreadProc, this)
+ , WhatThreadDoesLocation(&NoLocation)
+ , ThreadLocalData(&::WorkerNoThreadLocalData)
+ {
+ Thread.Start();
+ }
+
+ void Run() {
+ WhatThreadDoesLocation = ::WhatThreadDoesLocation();
+ AtomicSet(ThreadLocalData, &::WorkerThreadLocalData);
+ WHAT_THREAD_DOES_PUSH_POP_CURRENT_FUNC();
+ Executor->RunWorker();
+ }
+
+ static void* RunThreadProc(void* thiz0) {
+ TExecutorWorker* thiz = (TExecutorWorker*)thiz0;
+ thiz->Run();
+ return nullptr;
+ }
+ };
+
+ struct TExecutor::TImpl {
+ TExecutor* const Executor;
+ THistoryInternal History;
+
+ TSystemEvent HelperStopSignal;
+ TThread HelperThread;
+
+ TImpl(TExecutor* executor)
+ : Executor(executor)
+ , HelperThread(HelperThreadProc, this)
+ {
+ }
+
+ void RunHelper() {
+ ui64 nowSeconds = TInstant::Now().Seconds();
+ for (;;) {
+ TInstant nextStop = TInstant::Seconds(nowSeconds + 1) + TDuration::MilliSeconds(RandomNumber<ui32>(1000));
+
+ if (HelperStopSignal.WaitD(nextStop)) {
+ return;
+ }
+
+ nowSeconds = nextStop.Seconds();
+
+ THistoryInternal::TRecord& record = History.GetNowRecord(nowSeconds);
+
+ ui32 maxQueueSize = Executor->GetMaxQueueSizeAndClear();
+ if (maxQueueSize > record.MaxQueueSize) {
+ AtomicSet(record.MaxQueueSize, maxQueueSize);
+ }
+ }
+ }
+
+ static void* HelperThreadProc(void* impl0) {
+ TImpl* impl = (TImpl*)impl0;
+ impl->RunHelper();
+ return nullptr;
+ }
+ };
+
+}
+
+static TExecutor::TConfig MakeConfig(unsigned workerCount) {
+ TExecutor::TConfig config;
+ config.WorkerCount = workerCount;
+ return config;
+}
+
+TExecutor::TExecutor(size_t workerCount)
+ : Config(MakeConfig(workerCount))
+{
+ Init();
+}
+
+TExecutor::TExecutor(const TExecutor::TConfig& config)
+ : Config(config)
+{
+ Init();
+}
+
+void TExecutor::Init() {
+ Impl.Reset(new TImpl(this));
+
+ AtomicSet(ExitWorkers, 0);
+
+ Y_VERIFY(Config.WorkerCount > 0);
+
+ for (size_t i = 0; i < Config.WorkerCount; i++) {
+ WorkerThreads.push_back(new TExecutorWorker(this));
+ }
+
+ Impl->HelperThread.Start();
+}
+
+TExecutor::~TExecutor() {
+ Stop();
+}
+
+void TExecutor::Stop() {
+ AtomicSet(ExitWorkers, 1);
+
+ Impl->HelperStopSignal.Signal();
+ Impl->HelperThread.Join();
+
+ {
+ TWhatThreadDoesAcquireGuard<TMutex> guard(WorkMutex, "executor: acquiring lock for Stop");
+ WorkAvailable.BroadCast();
+ }
+
+ for (size_t i = 0; i < WorkerThreads.size(); i++) {
+ WorkerThreads[i]->Thread.Join();
+ }
+
+ // TODO: make queue empty at this point
+ ProcessWorkQueueHere();
+}
+
+void TExecutor::EnqueueWork(TArrayRef<IWorkItem* const> wis) {
+ if (wis.empty())
+ return;
+
+ if (Y_UNLIKELY(AtomicGet(ExitWorkers) != 0)) {
+ Y_VERIFY(WorkItems.Empty(), "executor %s: cannot add tasks after queue shutdown", Config.Name);
+ }
+
+ TWhatThreadDoesPushPop pp("executor: EnqueueWork");
+
+ WorkItems.PushAll(wis);
+
+ {
+ if (wis.size() == 1) {
+ TWhatThreadDoesAcquireGuard<TMutex> g(WorkMutex, "executor: acquiring lock for EnqueueWork");
+ WorkAvailable.Signal();
+ } else {
+ TWhatThreadDoesAcquireGuard<TMutex> g(WorkMutex, "executor: acquiring lock for EnqueueWork");
+ WorkAvailable.BroadCast();
+ }
+ }
+}
+
+size_t TExecutor::GetWorkQueueSize() const {
+ return WorkItems.Size();
+}
+
+using namespace NTSAN;
+
+ui32 TExecutor::GetMaxQueueSizeAndClear() const {
+ ui32 max = 0;
+ for (unsigned i = 0; i < WorkerThreads.size(); ++i) {
+ TExecutorWorkerThreadLocalData* wtls = RelaxedLoad(&WorkerThreads[i]->ThreadLocalData);
+ max = Max<ui32>(max, RelaxedLoad(&wtls->MaxQueueSize));
+ RelaxedStore<ui32>(&wtls->MaxQueueSize, 0);
+ }
+ return max;
+}
+
+TString TExecutor::GetStatus() const {
+ return GetStatusRecordInternal().Status;
+}
+
+TString TExecutor::GetStatusSingleLine() const {
+ TStringStream ss;
+ ss << "work items: " << GetWorkQueueSize();
+ return ss.Str();
+}
+
+TExecutorStatus TExecutor::GetStatusRecordInternal() const {
+ TExecutorStatus r;
+
+ r.WorkQueueSize = GetWorkQueueSize();
+
+ {
+ TStringStream ss;
+ ss << "work items: " << GetWorkQueueSize() << "\n";
+ ss << "workers:\n";
+ for (unsigned i = 0; i < WorkerThreads.size(); ++i) {
+ ss << "-- " << AtomicGet(*AtomicGet(WorkerThreads[i]->WhatThreadDoesLocation)) << "\n";
+ }
+ r.Status = ss.Str();
+ }
+
+ r.History = Impl->History.Capture();
+
+ return r;
+}
+
+bool TExecutor::IsInExecutorThread() const {
+ return ThreadCurrentExecutor == this;
+}
+
+TAutoPtr<IWorkItem> TExecutor::DequeueWork() {
+ IWorkItem* wi = reinterpret_cast<IWorkItem*>(1);
+ size_t queueSize = Max<size_t>();
+ if (!WorkItems.TryPop(&wi, &queueSize)) {
+ TWhatThreadDoesAcquireGuard<TMutex> g(WorkMutex, "executor: acquiring lock for DequeueWork");
+ while (!WorkItems.TryPop(&wi, &queueSize)) {
+ if (AtomicGet(ExitWorkers) != 0)
+ return nullptr;
+
+ TWhatThreadDoesPushPop pp("waiting for work on condvar");
+ WorkAvailable.Wait(WorkMutex);
+ }
+ }
+
+ auto& wtls = TlsRef(WorkerThreadLocalData);
+
+ if (queueSize > RelaxedLoad(&wtls.MaxQueueSize)) {
+ RelaxedStore<ui32>(&wtls.MaxQueueSize, queueSize);
+ }
+
+ return wi;
+}
+
+void TExecutor::RunWorkItem(TAutoPtr<IWorkItem> wi) {
+ WHAT_THREAD_DOES_PUSH_POP_CURRENT_FUNC();
+ wi.Release()->DoWork();
+}
+
+void TExecutor::ProcessWorkQueueHere() {
+ IWorkItem* wi;
+ while (WorkItems.TryPop(&wi)) {
+ RunWorkItem(wi);
+ }
+}
+
+void TExecutor::RunWorker() {
+ Y_VERIFY(!ThreadCurrentExecutor, "state check");
+ ThreadCurrentExecutor = this;
+
+ SetCurrentThreadName("wrkr");
+
+ for (;;) {
+ TAutoPtr<IWorkItem> wi = DequeueWork();
+ if (!wi) {
+ break;
+ }
+ // Note for messagebus users: make sure program crashes
+ // on uncaught exception in thread, otherewise messagebus may just hang on error.
+ RunWorkItem(wi);
+ }
+
+ ThreadCurrentExecutor = (TExecutor*)nullptr;
+}
diff --git a/library/cpp/messagebus/actor/executor.h b/library/cpp/messagebus/actor/executor.h
new file mode 100644
index 0000000000..7292d8be53
--- /dev/null
+++ b/library/cpp/messagebus/actor/executor.h
@@ -0,0 +1,105 @@
+#pragma once
+
+#include "ring_buffer_with_spin_lock.h"
+
+#include <util/generic/array_ref.h>
+#include <util/generic/vector.h>
+#include <util/system/condvar.h>
+#include <util/system/event.h>
+#include <util/system/mutex.h>
+#include <util/system/thread.h>
+#include <util/thread/lfqueue.h>
+
+namespace NActor {
+ namespace NPrivate {
+ struct TExecutorHistory {
+ struct THistoryRecord {
+ ui32 MaxQueueSize;
+ };
+ TVector<THistoryRecord> HistoryRecords;
+ ui64 LastHistoryRecordSecond;
+
+ ui64 FirstHistoryRecordSecond() const {
+ return LastHistoryRecordSecond - HistoryRecords.size() + 1;
+ }
+ };
+
+ struct TExecutorStatus {
+ size_t WorkQueueSize = 0;
+ TExecutorHistory History;
+ TString Status;
+ };
+ }
+
+ class IWorkItem {
+ public:
+ virtual ~IWorkItem() {
+ }
+ virtual void DoWork(/* must release this */) = 0;
+ };
+
+ struct TExecutorWorker;
+
+ class TExecutor: public TAtomicRefCount<TExecutor> {
+ friend struct TExecutorWorker;
+
+ public:
+ struct TConfig {
+ size_t WorkerCount;
+ const char* Name;
+
+ TConfig()
+ : WorkerCount(1)
+ , Name()
+ {
+ }
+ };
+
+ private:
+ struct TImpl;
+ THolder<TImpl> Impl;
+
+ const TConfig Config;
+
+ TAtomic ExitWorkers;
+
+ TVector<TAutoPtr<TExecutorWorker>> WorkerThreads;
+
+ TRingBufferWithSpinLock<IWorkItem*> WorkItems;
+
+ TMutex WorkMutex;
+ TCondVar WorkAvailable;
+
+ public:
+ explicit TExecutor(size_t workerCount);
+ TExecutor(const TConfig& config);
+ ~TExecutor();
+
+ void Stop();
+
+ void EnqueueWork(TArrayRef<IWorkItem* const> w);
+
+ size_t GetWorkQueueSize() const;
+ TString GetStatus() const;
+ TString GetStatusSingleLine() const;
+ NPrivate::TExecutorStatus GetStatusRecordInternal() const;
+
+ bool IsInExecutorThread() const;
+
+ private:
+ void Init();
+
+ TAutoPtr<IWorkItem> DequeueWork();
+
+ void ProcessWorkQueueHere();
+
+ inline void RunWorkItem(TAutoPtr<IWorkItem>);
+
+ void RunWorker();
+
+ ui32 GetMaxQueueSizeAndClear() const;
+ };
+
+ using TExecutorPtr = TIntrusivePtr<TExecutor>;
+
+}
diff --git a/library/cpp/messagebus/actor/queue_for_actor.h b/library/cpp/messagebus/actor/queue_for_actor.h
new file mode 100644
index 0000000000..40fa536b82
--- /dev/null
+++ b/library/cpp/messagebus/actor/queue_for_actor.h
@@ -0,0 +1,74 @@
+#pragma once
+
+#include <util/generic/vector.h>
+#include <util/system/yassert.h>
+#include <util/thread/lfstack.h>
+#include <util/thread/singleton.h>
+
+// TODO: include from correct directory
+#include "temp_tls_vector.h"
+
+namespace NActor {
+ namespace NPrivate {
+ struct TTagForTl {};
+
+ }
+
+ template <typename T>
+ class TQueueForActor {
+ private:
+ TLockFreeStack<T> Queue;
+
+ public:
+ ~TQueueForActor() {
+ Y_VERIFY(Queue.IsEmpty());
+ }
+
+ bool IsEmpty() {
+ return Queue.IsEmpty();
+ }
+
+ void Enqueue(const T& value) {
+ Queue.Enqueue(value);
+ }
+
+ template <typename TCollection>
+ void EnqueueAll(const TCollection& all) {
+ Queue.EnqueueAll(all);
+ }
+
+ void Clear() {
+ TVector<T> tmp;
+ Queue.DequeueAll(&tmp);
+ }
+
+ template <typename TFunc>
+ void DequeueAll(const TFunc& func
+ // TODO: , std::enable_if_t<TFunctionParamCount<TFunc>::Value == 1>* = 0
+ ) {
+ TTempTlsVector<T> temp;
+
+ Queue.DequeueAllSingleConsumer(temp.GetVector());
+
+ for (typename TVector<T>::reverse_iterator i = temp.GetVector()->rbegin(); i != temp.GetVector()->rend(); ++i) {
+ func(*i);
+ }
+
+ temp.Clear();
+
+ if (temp.Capacity() * sizeof(T) > 64 * 1024) {
+ temp.Shrink();
+ }
+ }
+
+ template <typename TFunc>
+ void DequeueAllLikelyEmpty(const TFunc& func) {
+ if (Y_LIKELY(IsEmpty())) {
+ return;
+ }
+
+ DequeueAll(func);
+ }
+ };
+
+}
diff --git a/library/cpp/messagebus/actor/queue_in_actor.h b/library/cpp/messagebus/actor/queue_in_actor.h
new file mode 100644
index 0000000000..9865996532
--- /dev/null
+++ b/library/cpp/messagebus/actor/queue_in_actor.h
@@ -0,0 +1,80 @@
+#pragma once
+
+#include "actor.h"
+#include "queue_for_actor.h"
+
+#include <functional>
+
+namespace NActor {
+ template <typename TItem>
+ class IQueueInActor {
+ public:
+ virtual void EnqueueAndScheduleV(const TItem& item) = 0;
+ virtual void DequeueAllV() = 0;
+ virtual void DequeueAllLikelyEmptyV() = 0;
+
+ virtual ~IQueueInActor() {
+ }
+ };
+
+ template <typename TThis, typename TItem, typename TActorTag = TDefaultTag, typename TQueueTag = TDefaultTag>
+ class TQueueInActor: public IQueueInActor<TItem> {
+ typedef TQueueInActor<TThis, TItem, TActorTag, TQueueTag> TSelf;
+
+ public:
+ // TODO: make protected
+ TQueueForActor<TItem> QueueInActor;
+
+ private:
+ TActor<TThis, TActorTag>* GetActor() {
+ return GetThis();
+ }
+
+ TThis* GetThis() {
+ return static_cast<TThis*>(this);
+ }
+
+ void ProcessItem(const TItem& item) {
+ GetThis()->ProcessItem(TActorTag(), TQueueTag(), item);
+ }
+
+ public:
+ void EnqueueAndNoSchedule(const TItem& item) {
+ QueueInActor.Enqueue(item);
+ }
+
+ void EnqueueAndSchedule(const TItem& item) {
+ EnqueueAndNoSchedule(item);
+ GetActor()->Schedule();
+ }
+
+ void EnqueueAndScheduleV(const TItem& item) override {
+ EnqueueAndSchedule(item);
+ }
+
+ void Clear() {
+ QueueInActor.Clear();
+ }
+
+ void DequeueAll() {
+ QueueInActor.DequeueAll(std::bind(&TSelf::ProcessItem, this, std::placeholders::_1));
+ }
+
+ void DequeueAllV() override {
+ return DequeueAll();
+ }
+
+ void DequeueAllLikelyEmpty() {
+ QueueInActor.DequeueAllLikelyEmpty(std::bind(&TSelf::ProcessItem, this, std::placeholders::_1));
+ }
+
+ void DequeueAllLikelyEmptyV() override {
+ return DequeueAllLikelyEmpty();
+ }
+
+ bool IsEmpty() {
+ return QueueInActor.IsEmpty();
+ }
+ };
+
+}
diff --git a/library/cpp/messagebus/actor/ring_buffer.h b/library/cpp/messagebus/actor/ring_buffer.h
new file mode 100644
index 0000000000..ec5706f7c7
--- /dev/null
+++ b/library/cpp/messagebus/actor/ring_buffer.h
@@ -0,0 +1,135 @@
+#pragma once
+
+#include <util/generic/array_ref.h>
+#include <util/generic/maybe.h>
+#include <util/generic/utility.h>
+#include <util/generic/vector.h>
+#include <util/system/yassert.h>
+
+template <typename T>
+struct TRingBuffer {
+private:
+ ui32 CapacityPow;
+ ui32 CapacityMask;
+ ui32 Capacity;
+ ui32 WritePos;
+ ui32 ReadPos;
+ TVector<T> Data;
+
+ void StateCheck() const {
+ Y_ASSERT(Capacity == Data.size());
+ Y_ASSERT(Capacity == (1u << CapacityPow));
+ Y_ASSERT((Capacity & CapacityMask) == 0u);
+ Y_ASSERT(Capacity - CapacityMask == 1u);
+ Y_ASSERT(WritePos < Capacity);
+ Y_ASSERT(ReadPos < Capacity);
+ }
+
+ size_t Writable() const {
+ return (Capacity + ReadPos - WritePos - 1) & CapacityMask;
+ }
+
+ void ReserveWritable(ui32 sz) {
+ if (sz <= Writable())
+ return;
+
+ ui32 newCapacityPow = CapacityPow;
+ while ((1u << newCapacityPow) < sz + ui32(Size()) + 1u) {
+ ++newCapacityPow;
+ }
+ ui32 newCapacity = 1u << newCapacityPow;
+ ui32 newCapacityMask = newCapacity - 1u;
+ TVector<T> newData(newCapacity);
+ ui32 oldSize = Size();
+ // Copy old elements
+ for (size_t i = 0; i < oldSize; ++i) {
+ newData[i] = Get(i);
+ }
+
+ CapacityPow = newCapacityPow;
+ Capacity = newCapacity;
+ CapacityMask = newCapacityMask;
+ Data.swap(newData);
+ ReadPos = 0;
+ WritePos = oldSize;
+
+ StateCheck();
+ }
+
+ const T& Get(ui32 i) const {
+ return Data[(ReadPos + i) & CapacityMask];
+ }
+
+public:
+ TRingBuffer()
+ : CapacityPow(0)
+ , CapacityMask(0)
+ , Capacity(1 << CapacityPow)
+ , WritePos(0)
+ , ReadPos(0)
+ , Data(Capacity)
+ {
+ StateCheck();
+ }
+
+ size_t Size() const {
+ return (Capacity + WritePos - ReadPos) & CapacityMask;
+ }
+
+ bool Empty() const {
+ return WritePos == ReadPos;
+ }
+
+ void PushAll(TArrayRef<const T> value) {
+ ReserveWritable(value.size());
+
+ ui32 secondSize;
+ ui32 firstSize;
+
+ if (WritePos + value.size() <= Capacity) {
+ firstSize = value.size();
+ secondSize = 0;
+ } else {
+ firstSize = Capacity - WritePos;
+ secondSize = value.size() - firstSize;
+ }
+
+ for (size_t i = 0; i < firstSize; ++i) {
+ Data[WritePos + i] = value[i];
+ }
+
+ for (size_t i = 0; i < secondSize; ++i) {
+ Data[i] = value[firstSize + i];
+ }
+
+ WritePos = (WritePos + value.size()) & CapacityMask;
+ StateCheck();
+ }
+
+ void Push(const T& t) {
+ PushAll(MakeArrayRef(&t, 1));
+ }
+
+ bool TryPop(T* r) {
+ StateCheck();
+ if (Empty()) {
+ return false;
+ }
+ *r = Data[ReadPos];
+ ReadPos = (ReadPos + 1) & CapacityMask;
+ return true;
+ }
+
+ TMaybe<T> TryPop() {
+ T tmp;
+ if (TryPop(&tmp)) {
+ return tmp;
+ } else {
+ return TMaybe<T>();
+ }
+ }
+
+ T Pop() {
+ return *TryPop();
+ }
+};
diff --git a/library/cpp/messagebus/actor/ring_buffer_ut.cpp b/library/cpp/messagebus/actor/ring_buffer_ut.cpp
new file mode 100644
index 0000000000..bdb379b3a9
--- /dev/null
+++ b/library/cpp/messagebus/actor/ring_buffer_ut.cpp
@@ -0,0 +1,60 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "ring_buffer.h"
+
+#include <util/random/random.h>
+
+Y_UNIT_TEST_SUITE(RingBuffer) {
+ struct TRingBufferTester {
+ TRingBuffer<unsigned> RingBuffer;
+
+ unsigned NextPush;
+ unsigned NextPop;
+
+ TRingBufferTester()
+ : NextPush()
+ , NextPop()
+ {
+ }
+
+ void Push() {
+ //Cerr << "push " << NextPush << "\n";
+ RingBuffer.Push(NextPush);
+ NextPush += 1;
+ }
+
+ void Pop() {
+ //Cerr << "pop " << NextPop << "\n";
+ unsigned popped = RingBuffer.Pop();
+ UNIT_ASSERT_VALUES_EQUAL(NextPop, popped);
+ NextPop += 1;
+ }
+
+ bool Empty() const {
+ UNIT_ASSERT_VALUES_EQUAL(RingBuffer.Size(), NextPush - NextPop);
+ UNIT_ASSERT_VALUES_EQUAL(RingBuffer.Empty(), RingBuffer.Size() == 0);
+ return RingBuffer.Empty();
+ }
+ };
+
+ void Iter() {
+ TRingBufferTester rb;
+
+ while (rb.NextPush < 1000) {
+ rb.Push();
+ while (!rb.Empty() && RandomNumber<bool>()) {
+ rb.Pop();
+ }
+ }
+
+ while (!rb.Empty()) {
+ rb.Pop();
+ }
+ }
+
+ Y_UNIT_TEST(Random) {
+ for (unsigned i = 0; i < 100; ++i) {
+ Iter();
+ }
+ }
+}
diff --git a/library/cpp/messagebus/actor/ring_buffer_with_spin_lock.h b/library/cpp/messagebus/actor/ring_buffer_with_spin_lock.h
new file mode 100644
index 0000000000..f0b7cd90e4
--- /dev/null
+++ b/library/cpp/messagebus/actor/ring_buffer_with_spin_lock.h
@@ -0,0 +1,91 @@
+#pragma once
+
+#include "ring_buffer.h"
+
+#include <util/system/spinlock.h>
+
+template <typename T>
+class TRingBufferWithSpinLock {
+private:
+ TRingBuffer<T> RingBuffer;
+ TSpinLock SpinLock;
+ TAtomic CachedSize;
+
+public:
+ TRingBufferWithSpinLock()
+ : CachedSize(0)
+ {
+ }
+
+ void Push(const T& t) {
+ PushAll(t);
+ }
+
+ void PushAll(TArrayRef<const T> collection) {
+ if (collection.empty()) {
+ return;
+ }
+
+ TGuard<TSpinLock> Guard(SpinLock);
+ RingBuffer.PushAll(collection);
+ AtomicSet(CachedSize, RingBuffer.Size());
+ }
+
+ bool TryPop(T* r, size_t* sizePtr = nullptr) {
+ if (AtomicGet(CachedSize) == 0) {
+ return false;
+ }
+
+ bool ok;
+ size_t size;
+ {
+ TGuard<TSpinLock> Guard(SpinLock);
+ ok = RingBuffer.TryPop(r);
+ size = RingBuffer.Size();
+ AtomicSet(CachedSize, size);
+ }
+ if (!!sizePtr) {
+ *sizePtr = size;
+ }
+ return ok;
+ }
+
+ TMaybe<T> TryPop() {
+ T tmp;
+ if (TryPop(&tmp)) {
+ return tmp;
+ } else {
+ return TMaybe<T>();
+ }
+ }
+
+ bool PushAllAndTryPop(TArrayRef<const T> collection, T* r) {
+ if (collection.size() == 0) {
+ return TryPop(r);
+ } else {
+ if (AtomicGet(CachedSize) == 0) {
+ *r = collection[0];
+ if (collection.size() > 1) {
+ TGuard<TSpinLock> guard(SpinLock);
+ RingBuffer.PushAll(MakeArrayRef(collection.data() + 1, collection.size() - 1));
+ AtomicSet(CachedSize, RingBuffer.Size());
+ }
+ } else {
+ TGuard<TSpinLock> guard(SpinLock);
+ RingBuffer.PushAll(collection);
+ *r = RingBuffer.Pop();
+ AtomicSet(CachedSize, RingBuffer.Size());
+ }
+ return true;
+ }
+ }
+
+ bool Empty() const {
+ return AtomicGet(CachedSize) == 0;
+ }
+
+ size_t Size() const {
+ TGuard<TSpinLock> Guard(SpinLock);
+ return RingBuffer.Size();
+ }
+};
diff --git a/library/cpp/messagebus/actor/tasks.h b/library/cpp/messagebus/actor/tasks.h
new file mode 100644
index 0000000000..31d35931d2
--- /dev/null
+++ b/library/cpp/messagebus/actor/tasks.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <util/system/atomic.h>
+#include <util/system/yassert.h>
+
+namespace NActor {
+ class TTasks {
+ enum {
+ // order of values is important
+ E_WAITING,
+ E_RUNNING_NO_TASKS,
+ E_RUNNING_GOT_TASKS,
+ };
+
+ private:
+ TAtomic State;
+
+ public:
+ TTasks()
+ : State(E_WAITING)
+ {
+ }
+
+ // @return true iff caller have to either schedule task or execute it
+ bool AddTask() {
+ // High contention case optimization: AtomicGet is cheaper than AtomicSwap.
+ if (E_RUNNING_GOT_TASKS == AtomicGet(State)) {
+ return false;
+ }
+
+ TAtomicBase oldState = AtomicSwap(&State, E_RUNNING_GOT_TASKS);
+ return oldState == E_WAITING;
+ }
+
+ // called by executor
+ // @return true iff we have to recheck queues
+ bool FetchTask() {
+ TAtomicBase newState = AtomicDecrement(State);
+ if (newState == E_RUNNING_NO_TASKS) {
+ return true;
+ } else if (newState == E_WAITING) {
+ return false;
+ }
+ Y_FAIL("unknown");
+ }
+ };
+
+}
diff --git a/library/cpp/messagebus/actor/tasks_ut.cpp b/library/cpp/messagebus/actor/tasks_ut.cpp
new file mode 100644
index 0000000000..d80e8451a5
--- /dev/null
+++ b/library/cpp/messagebus/actor/tasks_ut.cpp
@@ -0,0 +1,37 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "tasks.h"
+
+using namespace NActor;
+
+Y_UNIT_TEST_SUITE(TTasks) {
+ Y_UNIT_TEST(AddTask_FetchTask_Simple) {
+ TTasks tasks;
+
+ UNIT_ASSERT(tasks.AddTask());
+ UNIT_ASSERT(!tasks.AddTask());
+ UNIT_ASSERT(!tasks.AddTask());
+
+ UNIT_ASSERT(tasks.FetchTask());
+ UNIT_ASSERT(!tasks.FetchTask());
+
+ UNIT_ASSERT(tasks.AddTask());
+ }
+
+ Y_UNIT_TEST(AddTask_FetchTask_AddTask) {
+ TTasks tasks;
+
+ UNIT_ASSERT(tasks.AddTask());
+ UNIT_ASSERT(!tasks.AddTask());
+
+ UNIT_ASSERT(tasks.FetchTask());
+ UNIT_ASSERT(!tasks.AddTask());
+ UNIT_ASSERT(tasks.FetchTask());
+ UNIT_ASSERT(!tasks.AddTask());
+ UNIT_ASSERT(!tasks.AddTask());
+ UNIT_ASSERT(tasks.FetchTask());
+ UNIT_ASSERT(!tasks.FetchTask());
+
+ UNIT_ASSERT(tasks.AddTask());
+ }
+}
diff --git a/library/cpp/messagebus/actor/temp_tls_vector.h b/library/cpp/messagebus/actor/temp_tls_vector.h
new file mode 100644
index 0000000000..675d92f5b0
--- /dev/null
+++ b/library/cpp/messagebus/actor/temp_tls_vector.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "thread_extra.h"
+
+#include <util/generic/vector.h>
+#include <util/system/yassert.h>
+
+template <typename T, typename TTag = void, template <typename, class> class TVectorType = TVector>
+class TTempTlsVector {
+private:
+ struct TTagForTls {};
+
+ TVectorType<T, std::allocator<T>>* Vector;
+
+public:
+ TVectorType<T, std::allocator<T>>* GetVector() {
+ return Vector;
+ }
+
+ TTempTlsVector() {
+ Vector = FastTlsSingletonWithTag<TVectorType<T, std::allocator<T>>, TTagForTls>();
+ Y_ASSERT(Vector->empty());
+ }
+
+ ~TTempTlsVector() {
+ Clear();
+ }
+
+ void Clear() {
+ Vector->clear();
+ }
+
+ size_t Capacity() const noexcept {
+ return Vector->capacity();
+ }
+
+ void Shrink() {
+ Vector->shrink_to_fit();
+ }
+};
diff --git a/library/cpp/messagebus/actor/thread_extra.cpp b/library/cpp/messagebus/actor/thread_extra.cpp
new file mode 100644
index 0000000000..048480f255
--- /dev/null
+++ b/library/cpp/messagebus/actor/thread_extra.cpp
@@ -0,0 +1,30 @@
+#include "thread_extra.h"
+
+#include <util/stream/str.h>
+#include <util/system/execpath.h>
+#include <util/system/platform.h>
+#include <util/system/thread.h>
+
+namespace {
+#ifdef _linux_
+ TString GetExecName() {
+ TString execPath = GetExecPath();
+ size_t lastSlash = execPath.find_last_of('/');
+ if (lastSlash == TString::npos) {
+ return execPath;
+ } else {
+ return execPath.substr(lastSlash + 1);
+ }
+ }
+#endif
+}
+
+void SetCurrentThreadName(const char* name) {
+#ifdef _linux_
+ TStringStream linuxName;
+ linuxName << GetExecName() << "." << name;
+ TThread::SetCurrentThreadName(linuxName.Str().data());
+#else
+ TThread::SetCurrentThreadName(name);
+#endif
+}
diff --git a/library/cpp/messagebus/actor/thread_extra.h b/library/cpp/messagebus/actor/thread_extra.h
new file mode 100644
index 0000000000..b5aa151618
--- /dev/null
+++ b/library/cpp/messagebus/actor/thread_extra.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <util/thread/singleton.h>
+
+namespace NTSAN {
+ template <typename T>
+ inline void RelaxedStore(volatile T* a, T x) {
+ static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value");
+#ifdef _win_
+ *a = x;
+#else
+ __atomic_store_n(a, x, __ATOMIC_RELAXED);
+#endif
+ }
+
+ template <typename T>
+ inline T RelaxedLoad(volatile T* a) {
+#ifdef _win_
+ return *a;
+#else
+ return __atomic_load_n(a, __ATOMIC_RELAXED);
+#endif
+ }
+
+}
+
+void SetCurrentThreadName(const char* name);
+
+namespace NThreadExtra {
+ namespace NPrivate {
+ template <typename TValue, typename TTag>
+ struct TValueHolder {
+ TValue Value;
+ };
+ }
+}
+
+template <typename TValue, typename TTag>
+static inline TValue* FastTlsSingletonWithTag() {
+ return &FastTlsSingleton< ::NThreadExtra::NPrivate::TValueHolder<TValue, TTag>>()->Value;
+}
diff --git a/library/cpp/messagebus/actor/what_thread_does.cpp b/library/cpp/messagebus/actor/what_thread_does.cpp
new file mode 100644
index 0000000000..bebb6a888c
--- /dev/null
+++ b/library/cpp/messagebus/actor/what_thread_does.cpp
@@ -0,0 +1,22 @@
+#include "what_thread_does.h"
+
+#include "thread_extra.h"
+
+#include <util/system/tls.h>
+
+Y_POD_STATIC_THREAD(const char*)
+WhatThreadDoes;
+
+const char* PushWhatThreadDoes(const char* what) {
+ const char* r = NTSAN::RelaxedLoad(&WhatThreadDoes);
+ NTSAN::RelaxedStore(&WhatThreadDoes, what);
+ return r;
+}
+
+void PopWhatThreadDoes(const char* prev) {
+ NTSAN::RelaxedStore(&WhatThreadDoes, prev);
+}
+
+const char** WhatThreadDoesLocation() {
+ return &WhatThreadDoes;
+}
diff --git a/library/cpp/messagebus/actor/what_thread_does.h b/library/cpp/messagebus/actor/what_thread_does.h
new file mode 100644
index 0000000000..235d2c3700
--- /dev/null
+++ b/library/cpp/messagebus/actor/what_thread_does.h
@@ -0,0 +1,28 @@
+#pragma once
+
+const char* PushWhatThreadDoes(const char* what);
+void PopWhatThreadDoes(const char* prev);
+const char** WhatThreadDoesLocation();
+
+struct TWhatThreadDoesPushPop {
+private:
+ const char* Prev;
+
+public:
+ TWhatThreadDoesPushPop(const char* what) {
+ Prev = PushWhatThreadDoes(what);
+ }
+
+ ~TWhatThreadDoesPushPop() {
+ PopWhatThreadDoes(Prev);
+ }
+};
+
+#ifdef __GNUC__
+#define WHAT_THREAD_DOES_FUNCTION __PRETTY_FUNCTION__
+#else
+#define WHAT_THREAD_DOES_FUNCTION __FUNCTION__
+#endif
+
+#define WHAT_THREAD_DOES_PUSH_POP_CURRENT_FUNC() \
+ TWhatThreadDoesPushPop whatThreadDoesPushPopCurrentFunc(WHAT_THREAD_DOES_FUNCTION)
diff --git a/library/cpp/messagebus/actor/what_thread_does_guard.h b/library/cpp/messagebus/actor/what_thread_does_guard.h
new file mode 100644
index 0000000000..f104e9e173
--- /dev/null
+++ b/library/cpp/messagebus/actor/what_thread_does_guard.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "what_thread_does.h"
+
+template <class T>
+class TWhatThreadDoesAcquireGuard: public TNonCopyable {
+public:
+ inline TWhatThreadDoesAcquireGuard(const T& t, const char* acquire) noexcept {
+ Init(&t, acquire);
+ }
+
+ inline TWhatThreadDoesAcquireGuard(const T* t, const char* acquire) noexcept {
+ Init(t, acquire);
+ }
+
+ inline ~TWhatThreadDoesAcquireGuard() {
+ Release();
+ }
+
+ inline void Release() noexcept {
+ if (WasAcquired()) {
+ const_cast<T*>(T_)->Release();
+ T_ = nullptr;
+ }
+ }
+
+ inline bool WasAcquired() const noexcept {
+ return T_ != nullptr;
+ }
+
+private:
+ inline void Init(const T* t, const char* acquire) noexcept {
+ T_ = const_cast<T*>(t);
+ TWhatThreadDoesPushPop pp(acquire);
+ T_->Acquire();
+ }
+
+private:
+ T* T_;
+};
diff --git a/library/cpp/messagebus/actor/what_thread_does_guard_ut.cpp b/library/cpp/messagebus/actor/what_thread_does_guard_ut.cpp
new file mode 100644
index 0000000000..e4b218a7ca
--- /dev/null
+++ b/library/cpp/messagebus/actor/what_thread_does_guard_ut.cpp
@@ -0,0 +1,13 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "what_thread_does_guard.h"
+
+#include <util/system/mutex.h>
+
+Y_UNIT_TEST_SUITE(WhatThreadDoesGuard) {
+ Y_UNIT_TEST(Simple) {
+ TMutex mutex;
+
+ TWhatThreadDoesAcquireGuard<TMutex> guard(mutex, "acquiring my mutex");
+ }
+}
diff --git a/library/cpp/messagebus/actor/ya.make b/library/cpp/messagebus/actor/ya.make
new file mode 100644
index 0000000000..59bd1b0b99
--- /dev/null
+++ b/library/cpp/messagebus/actor/ya.make
@@ -0,0 +1,11 @@
+LIBRARY(messagebus_actor)
+
+OWNER(g:messagebus)
+
+SRCS(
+ executor.cpp
+ thread_extra.cpp
+ what_thread_does.cpp
+)
+
+END()
diff --git a/library/cpp/messagebus/all.lwt b/library/cpp/messagebus/all.lwt
new file mode 100644
index 0000000000..0f04be4b2c
--- /dev/null
+++ b/library/cpp/messagebus/all.lwt
@@ -0,0 +1,8 @@
+Blocks {
+ ProbeDesc {
+ Group: "MessagebusRare"
+ }
+ Action {
+ PrintToStderrAction {}
+ }
+}
diff --git a/library/cpp/messagebus/all/ya.make b/library/cpp/messagebus/all/ya.make
new file mode 100644
index 0000000000..ffa2dbfabc
--- /dev/null
+++ b/library/cpp/messagebus/all/ya.make
@@ -0,0 +1,10 @@
+OWNER(g:messagebus)
+
+RECURSE_ROOT_RELATIVE(
+ library/python/messagebus
+ library/cpp/messagebus/debug_receiver
+ library/cpp/messagebus/oldmodule
+ library/cpp/messagebus/rain_check
+ library/cpp/messagebus/test
+ library/cpp/messagebus/www
+)
diff --git a/library/cpp/messagebus/async_result.h b/library/cpp/messagebus/async_result.h
new file mode 100644
index 0000000000..d24dde284a
--- /dev/null
+++ b/library/cpp/messagebus/async_result.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <util/generic/maybe.h>
+#include <util/generic/noncopyable.h>
+#include <util/system/condvar.h>
+#include <util/system/mutex.h>
+#include <util/system/yassert.h>
+
+#include <functional>
+
+// probably this thing should have been called TFuture
+template <typename T>
+class TAsyncResult : TNonCopyable {
+private:
+ TMutex Mutex;
+ TCondVar CondVar;
+
+ TMaybe<T> Result;
+
+ typedef void TOnResult(const T&);
+
+ std::function<TOnResult> OnResult;
+
+public:
+ void SetResult(const T& result) {
+ TGuard<TMutex> guard(Mutex);
+ Y_VERIFY(!Result, "cannot set result twice");
+ Result = result;
+ CondVar.BroadCast();
+
+ if (!!OnResult) {
+ OnResult(result);
+ }
+ }
+
+ const T& GetResult() {
+ TGuard<TMutex> guard(Mutex);
+ while (!Result) {
+ CondVar.Wait(Mutex);
+ }
+ return *Result;
+ }
+
+ template <typename TFunc>
+ void AndThen(const TFunc& onResult) {
+ TGuard<TMutex> guard(Mutex);
+ if (!!Result) {
+ onResult(*Result);
+ } else {
+ Y_ASSERT(!OnResult);
+ OnResult = std::function<TOnResult>(onResult);
+ }
+ }
+};
diff --git a/library/cpp/messagebus/async_result_ut.cpp b/library/cpp/messagebus/async_result_ut.cpp
new file mode 100644
index 0000000000..2e96492afd
--- /dev/null
+++ b/library/cpp/messagebus/async_result_ut.cpp
@@ -0,0 +1,37 @@
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "async_result.h"
+
+namespace {
+ void SetValue(int* location, const int& value) {
+ *location = value;
+ }
+
+}
+
+Y_UNIT_TEST_SUITE(TAsyncResult) {
+ Y_UNIT_TEST(AndThen_Here) {
+ TAsyncResult<int> r;
+
+ int var = 1;
+
+ r.SetResult(17);
+
+ r.AndThen(std::bind(&SetValue, &var, std::placeholders::_1));
+
+ UNIT_ASSERT_VALUES_EQUAL(17, var);
+ }
+
+ Y_UNIT_TEST(AndThen_Later) {
+ TAsyncResult<int> r;
+
+ int var = 1;
+
+ r.AndThen(std::bind(&SetValue, &var, std::placeholders::_1));
+
+ r.SetResult(17);
+
+ UNIT_ASSERT_VALUES_EQUAL(17, var);
+ }
+}
diff --git a/library/cpp/messagebus/base.h b/library/cpp/messagebus/base.h
new file mode 100644
index 0000000000..79fccc312e
--- /dev/null
+++ b/library/cpp/messagebus/base.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <util/system/defaults.h>
+
+namespace NBus {
+ /// millis since epoch
+ using TBusInstant = ui64;
+ /// returns time in milliseconds
+ TBusInstant Now();
+
+}
diff --git a/library/cpp/messagebus/cc_semaphore.h b/library/cpp/messagebus/cc_semaphore.h
new file mode 100644
index 0000000000..0df8a3d664
--- /dev/null
+++ b/library/cpp/messagebus/cc_semaphore.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include "latch.h"
+
+template <typename TThis>
+class TComplexConditionSemaphore {
+private:
+ TLatch Latch;
+
+public:
+ void Updated() {
+ if (GetThis()->TryWait()) {
+ Latch.Unlock();
+ }
+ }
+
+ void Wait() {
+ while (!GetThis()->TryWait()) {
+ Latch.Lock();
+ if (GetThis()->TryWait()) {
+ Latch.Unlock();
+ return;
+ }
+ Latch.Wait();
+ }
+ }
+
+ bool IsLocked() {
+ return Latch.IsLocked();
+ }
+
+private:
+ TThis* GetThis() {
+ return static_cast<TThis*>(this);
+ }
+};
diff --git a/library/cpp/messagebus/cc_semaphore_ut.cpp b/library/cpp/messagebus/cc_semaphore_ut.cpp
new file mode 100644
index 0000000000..206bb7c96a
--- /dev/null
+++ b/library/cpp/messagebus/cc_semaphore_ut.cpp
@@ -0,0 +1,45 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "cc_semaphore.h"
+
+#include <util/system/atomic.h>
+
+namespace {
+ struct TTestSemaphore: public TComplexConditionSemaphore<TTestSemaphore> {
+ TAtomic Current;
+
+ TTestSemaphore()
+ : Current(0)
+ {
+ }
+
+ bool TryWait() {
+ return AtomicGet(Current) > 0;
+ }
+
+ void Aquire() {
+ Wait();
+ AtomicDecrement(Current);
+ }
+
+ void Release() {
+ AtomicIncrement(Current);
+ Updated();
+ }
+ };
+}
+
+Y_UNIT_TEST_SUITE(TComplexConditionSemaphore) {
+ Y_UNIT_TEST(Simple) {
+ TTestSemaphore sema;
+ UNIT_ASSERT(!sema.TryWait());
+ sema.Release();
+ UNIT_ASSERT(sema.TryWait());
+ sema.Release();
+ UNIT_ASSERT(sema.TryWait());
+ sema.Aquire();
+ UNIT_ASSERT(sema.TryWait());
+ sema.Aquire();
+ UNIT_ASSERT(!sema.TryWait());
+ }
+}
diff --git a/library/cpp/messagebus/codegen.h b/library/cpp/messagebus/codegen.h
new file mode 100644
index 0000000000..83e969e811
--- /dev/null
+++ b/library/cpp/messagebus/codegen.h
@@ -0,0 +1,4 @@
+#pragma once
+
+#include <library/cpp/messagebus/config/codegen.h>
+
diff --git a/library/cpp/messagebus/config/codegen.h b/library/cpp/messagebus/config/codegen.h
new file mode 100644
index 0000000000..97ddada005
--- /dev/null
+++ b/library/cpp/messagebus/config/codegen.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#define COMMA ,
+
+#define STRUCT_FIELD_GEN(name, type, ...) type name;
+
+#define STRUCT_FIELD_INIT(name, type, defa) name(defa)
+#define STRUCT_FIELD_INIT_DEFAULT(name, type, ...) name()
+
+#define STRUCT_FIELD_PRINT(name, ...) ss << #name << "=" << name << "\n";
diff --git a/library/cpp/messagebus/config/defs.h b/library/cpp/messagebus/config/defs.h
new file mode 100644
index 0000000000..92b1df9969
--- /dev/null
+++ b/library/cpp/messagebus/config/defs.h
@@ -0,0 +1,82 @@
+#pragma once
+
+// unique tag to fix pragma once gcc glueing: ./library/cpp/messagebus/defs.h
+
+#include "codegen.h"
+#include "netaddr.h"
+
+#include <library/cpp/deprecated/enum_codegen/enum_codegen.h>
+
+#include <util/generic/list.h>
+
+#include <utility>
+
+// For historical reasons TCrawlerModule need to access
+// APIs that should be private.
+class TCrawlerModule;
+
+struct TDebugReceiverHandler;
+
+namespace NBus {
+ namespace NPrivate {
+ class TAcceptor;
+ struct TBusSessionImpl;
+ class TRemoteServerSession;
+ class TRemoteClientSession;
+ class TRemoteConnection;
+ class TRemoteServerConnection;
+ class TRemoteClientConnection;
+ class TBusSyncSourceSessionImpl;
+
+ struct TBusMessagePtrAndHeader;
+
+ struct TSessionDumpStatus;
+
+ struct TClientRequestImpl;
+
+ }
+
+ class TBusSession;
+ struct TBusServerSession;
+ struct TBusClientSession;
+ class TBusProtocol;
+ class TBusMessage;
+ class TBusMessageConnection;
+ class TBusMessageQueue;
+ class TBusLocator;
+ struct TBusQueueConfig;
+ struct TBusSessionConfig;
+ struct TBusHeader;
+
+ class IThreadHandler;
+
+ using TBusKey = ui64;
+ using TBusMessageList = TList<TBusMessage*>;
+ using TBusKeyVec = TVector<std::pair<TBusKey, TBusKey>>;
+
+ using TBusMessageQueuePtr = TIntrusivePtr<TBusMessageQueue>;
+
+ class TBusModule;
+
+ using TBusData = TString;
+ using TBusService = const char*;
+
+#define YBUS_KEYMIN TBusKey(0L)
+#define YBUS_KEYMAX TBusKey(-1L)
+#define YBUS_KEYLOCAL TBusKey(7L)
+#define YBUS_KEYINVALID TBusKey(99999999L)
+
+ // Check that generated id is valid for remote message
+ inline bool IsBusKeyValid(TBusKey key) {
+ return key != YBUS_KEYINVALID && key != YBUS_KEYMAX && key > YBUS_KEYLOCAL;
+ }
+
+#define YBUS_VERSION 0
+
+#define YBUS_INFINITE (1u << 30u)
+
+#define YBUS_STATUS_BASIC 0x0000
+#define YBUS_STATUS_CONNS 0x0001
+#define YBUS_STATUS_INFLIGHT 0x0002
+
+}
diff --git a/library/cpp/messagebus/config/netaddr.cpp b/library/cpp/messagebus/config/netaddr.cpp
new file mode 100644
index 0000000000..962ac538e2
--- /dev/null
+++ b/library/cpp/messagebus/config/netaddr.cpp
@@ -0,0 +1,183 @@
+#include "netaddr.h"
+
+#include <util/network/address.h>
+
+#include <cstdlib>
+
+namespace NBus {
+ const char* ToCString(EIpVersion ipVersion) {
+ switch (ipVersion) {
+ case EIP_VERSION_ANY:
+ return "EIP_VERSION_ANY";
+ case EIP_VERSION_4:
+ return "EIP_VERSION_4";
+ case EIP_VERSION_6:
+ return "EIP_VERSION_6";
+ }
+ Y_FAIL();
+ }
+
+ int ToAddrFamily(EIpVersion ipVersion) {
+ switch (ipVersion) {
+ case EIP_VERSION_ANY:
+ return AF_UNSPEC;
+ case EIP_VERSION_4:
+ return AF_INET;
+ case EIP_VERSION_6:
+ return AF_INET6;
+ }
+ Y_FAIL();
+ }
+
+ class TNetworkAddressRef: private TNetworkAddress, public TAddrInfo {
+ public:
+ TNetworkAddressRef(const TNetworkAddress& na, const TAddrInfo& ai)
+ : TNetworkAddress(na)
+ , TAddrInfo(ai)
+ {
+ }
+ };
+
+ static bool Compare(const IRemoteAddr& l, const IRemoteAddr& r) noexcept {
+ if (l.Addr()->sa_family != r.Addr()->sa_family) {
+ return false;
+ }
+
+ switch (l.Addr()->sa_family) {
+ case AF_INET: {
+ return memcmp(&(((const sockaddr_in*)l.Addr())->sin_addr), &(((const sockaddr_in*)r.Addr())->sin_addr), sizeof(in_addr)) == 0 &&
+ ((const sockaddr_in*)l.Addr())->sin_port == ((const sockaddr_in*)r.Addr())->sin_port;
+ }
+
+ case AF_INET6: {
+ return memcmp(&(((const sockaddr_in6*)l.Addr())->sin6_addr), &(((const sockaddr_in6*)r.Addr())->sin6_addr), sizeof(in6_addr)) == 0 &&
+ ((const sockaddr_in6*)l.Addr())->sin6_port == ((const sockaddr_in6*)r.Addr())->sin6_port;
+ }
+ }
+
+ return memcmp(l.Addr(), r.Addr(), Min<size_t>(l.Len(), r.Len())) == 0;
+ }
+
+ TNetAddr::TNetAddr()
+ : Ptr(new TOpaqueAddr)
+ {
+ }
+
+ TNetAddr::TNetAddr(TAutoPtr<IRemoteAddr> addr)
+ : Ptr(addr)
+ {
+ Y_VERIFY(!!Ptr);
+ }
+
+ namespace {
+ using namespace NAddr;
+
+ const char* Describe(EIpVersion version) {
+ switch (version) {
+ case EIP_VERSION_4:
+ return "ipv4 address";
+ case EIP_VERSION_6:
+ return "ipv6 address";
+ case EIP_VERSION_ANY:
+ return "any address";
+ default:
+ Y_FAIL("unreachable");
+ }
+ }
+
+ TAutoPtr<IRemoteAddr> MakeAddress(const TNetworkAddress& na, EIpVersion requireVersion, EIpVersion preferVersion) {
+ TAutoPtr<IRemoteAddr> addr;
+ for (TNetworkAddress::TIterator it = na.Begin(); it != na.End(); ++it) {
+ if (IsFamilyAllowed(it->ai_family, requireVersion)) {
+ if (IsFamilyAllowed(it->ai_family, preferVersion)) {
+ return new TNetworkAddressRef(na, &*it);
+ } else if (!addr) {
+ addr.Reset(new TNetworkAddressRef(na, &*it));
+ }
+ }
+ }
+ return addr;
+ }
+ TAutoPtr<IRemoteAddr> MakeAddress(TStringBuf host, int port, EIpVersion requireVersion, EIpVersion preferVersion) {
+ TString hostString(host);
+ TNetworkAddress na(hostString, port);
+ return MakeAddress(na, requireVersion, preferVersion);
+ }
+ TAutoPtr<IRemoteAddr> MakeAddress(const char* hostPort, EIpVersion requireVersion, EIpVersion preferVersion) {
+ const char* portStr = strchr(hostPort, ':');
+ if (!portStr) {
+ ythrow TNetAddr::TError() << "port not specified in " << hostPort;
+ }
+ int port = atoi(portStr + 1);
+ TNetworkAddress na(TString(hostPort, portStr), port);
+ return MakeAddress(na, requireVersion, preferVersion);
+ }
+ }
+
+ TNetAddr::TNetAddr(const char* hostPort, EIpVersion requireVersion /*= EIP_VERSION_ANY*/, EIpVersion preferVersion /*= EIP_VERSION_ANY*/)
+ : Ptr(MakeAddress(hostPort, requireVersion, preferVersion))
+ {
+ if (!Ptr) {
+ ythrow TNetAddr::TError() << "cannot resolve " << hostPort << " into " << Describe(requireVersion);
+ }
+ }
+
+ TNetAddr::TNetAddr(TStringBuf host, int port, EIpVersion requireVersion /*= EIP_VERSION_ANY*/, EIpVersion preferVersion /*= EIP_VERSION_ANY*/)
+ : Ptr(MakeAddress(host, port, requireVersion, preferVersion))
+ {
+ if (!Ptr) {
+ ythrow TNetAddr::TError() << "cannot resolve " << host << ":" << port << " into " << Describe(requireVersion);
+ }
+ }
+
+ TNetAddr::TNetAddr(const TNetworkAddress& na, EIpVersion requireVersion /*= EIP_VERSION_ANY*/, EIpVersion preferVersion /*= EIP_VERSION_ANY*/)
+ : Ptr(MakeAddress(na, requireVersion, preferVersion))
+ {
+ if (!Ptr) {
+ ythrow TNetAddr::TError() << "cannot resolve into " << Describe(requireVersion);
+ }
+ }
+
+ TNetAddr::TNetAddr(const TNetworkAddress& na, const TAddrInfo& ai)
+ : Ptr(new TNetworkAddressRef(na, ai))
+ {
+ }
+
+ const sockaddr* TNetAddr::Addr() const {
+ return Ptr->Addr();
+ }
+
+ socklen_t TNetAddr::Len() const {
+ return Ptr->Len();
+ }
+
+ int TNetAddr::GetPort() const {
+ switch (Ptr->Addr()->sa_family) {
+ case AF_INET:
+ return InetToHost(((sockaddr_in*)Ptr->Addr())->sin_port);
+ case AF_INET6:
+ return InetToHost(((sockaddr_in6*)Ptr->Addr())->sin6_port);
+ default:
+ Y_FAIL("unknown AF: %d", (int)Ptr->Addr()->sa_family);
+ throw 1;
+ }
+ }
+
+ bool TNetAddr::IsIpv4() const {
+ return Ptr->Addr()->sa_family == AF_INET;
+ }
+
+ bool TNetAddr::IsIpv6() const {
+ return Ptr->Addr()->sa_family == AF_INET6;
+ }
+
+ bool TNetAddr::operator==(const TNetAddr& rhs) const {
+ return Ptr == rhs.Ptr || Compare(*Ptr, *rhs.Ptr);
+ }
+
+}
+
+template <>
+void Out<NBus::TNetAddr>(IOutputStream& out, const NBus::TNetAddr& addr) {
+ Out<NAddr::IRemoteAddr>(out, addr);
+}
diff --git a/library/cpp/messagebus/config/netaddr.h b/library/cpp/messagebus/config/netaddr.h
new file mode 100644
index 0000000000..b79c0cc355
--- /dev/null
+++ b/library/cpp/messagebus/config/netaddr.h
@@ -0,0 +1,86 @@
+#pragma once
+
+#include <util/digest/numeric.h>
+#include <util/generic/hash.h>
+#include <util/generic/ptr.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/vector.h>
+#include <util/network/address.h>
+
+namespace NBus {
+ using namespace NAddr;
+
+ /// IP protocol version.
+ enum EIpVersion {
+ EIP_VERSION_4 = 1,
+ EIP_VERSION_6 = 2,
+ EIP_VERSION_ANY = EIP_VERSION_4 | EIP_VERSION_6,
+ };
+
+ inline bool IsFamilyAllowed(ui16 sa_family, EIpVersion ipVersion) {
+ if (ipVersion == EIP_VERSION_4 && sa_family != AF_INET) {
+ return false;
+ }
+ if (ipVersion == EIP_VERSION_6 && sa_family != AF_INET6) {
+ return false;
+ }
+ return true;
+ }
+
+ const char* ToCString(EIpVersion);
+ int ToAddrFamily(EIpVersion);
+
+ /// Hold referenced pointer to address description structure (ex. sockaddr_storage)
+ /// It's make possible to work with IPv4 / IPv6 addresses simultaneously
+ class TNetAddr: public IRemoteAddr {
+ public:
+ class TError: public yexception {
+ };
+
+ TNetAddr();
+ TNetAddr(TAutoPtr<IRemoteAddr> addr);
+ TNetAddr(const char* hostPort, EIpVersion requireVersion = EIP_VERSION_ANY, EIpVersion preferVersion = EIP_VERSION_ANY);
+ TNetAddr(TStringBuf host, int port, EIpVersion requireVersion = EIP_VERSION_ANY, EIpVersion preferVersion = EIP_VERSION_ANY);
+ TNetAddr(const TNetworkAddress& na, EIpVersion requireVersion = EIP_VERSION_ANY, EIpVersion preferVersion = EIP_VERSION_ANY);
+ TNetAddr(const TNetworkAddress& na, const TAddrInfo& ai);
+
+ bool operator==(const TNetAddr&) const;
+ bool operator!=(const TNetAddr& other) const {
+ return !(*this == other);
+ }
+ inline explicit operator bool() const noexcept {
+ return !!Ptr;
+ }
+
+ const sockaddr* Addr() const override;
+ socklen_t Len() const override;
+
+ bool IsIpv4() const;
+ bool IsIpv6() const;
+ int GetPort() const;
+
+ private:
+ TAtomicSharedPtr<IRemoteAddr> Ptr;
+ };
+
+ using TSockAddrInVector = TVector<TNetAddr>;
+
+ struct TNetAddrHostPortHash {
+ inline size_t operator()(const TNetAddr& a) const {
+ const sockaddr* s = a.Addr();
+ const sockaddr_in* const sa = reinterpret_cast<const sockaddr_in*>(s);
+ const sockaddr_in6* const sa6 = reinterpret_cast<const sockaddr_in6*>(s);
+
+ switch (s->sa_family) {
+ case AF_INET:
+ return CombineHashes<size_t>(ComputeHash(TStringBuf(reinterpret_cast<const char*>(&sa->sin_addr), sizeof(sa->sin_addr))), IntHashImpl(sa->sin_port));
+
+ case AF_INET6:
+ return CombineHashes<size_t>(ComputeHash(TStringBuf(reinterpret_cast<const char*>(&sa6->sin6_addr), sizeof(sa6->sin6_addr))), IntHashImpl(sa6->sin6_port));
+ }
+
+ return ComputeHash(TStringBuf(reinterpret_cast<const char*>(s), a.Len()));
+ }
+ };
+
+}
diff --git a/library/cpp/messagebus/config/session_config.cpp b/library/cpp/messagebus/config/session_config.cpp
new file mode 100644
index 0000000000..fbbbb106c9
--- /dev/null
+++ b/library/cpp/messagebus/config/session_config.cpp
@@ -0,0 +1,157 @@
+#include "session_config.h"
+
+#include <util/generic/strbuf.h>
+#include <util/string/hex.h>
+
+using namespace NBus;
+
+TBusSessionConfig::TSecret::TSecret()
+ : TimeoutPeriod(TDuration::Seconds(1))
+ , StatusFlushPeriod(TDuration::MilliSeconds(400))
+{
+}
+
+TBusSessionConfig::TBusSessionConfig()
+ : BUS_SESSION_CONFIG_MAP(STRUCT_FIELD_INIT, COMMA)
+{
+}
+
+TString TBusSessionConfig::PrintToString() const {
+ TStringStream ss;
+ BUS_SESSION_CONFIG_MAP(STRUCT_FIELD_PRINT, )
+ return ss.Str();
+}
+
+static int ParseDurationForMessageBus(const char* option) {
+ return TDuration::Parse(option).MilliSeconds();
+}
+
+static int ParseToSForMessageBus(const char* option) {
+ int tos;
+ TStringBuf str(option);
+ if (str.StartsWith("0x")) {
+ str = str.Tail(2);
+ Y_VERIFY(str.length() == 2, "ToS must be a number between 0x00 and 0xFF");
+ tos = String2Byte(str.data());
+ } else {
+ tos = FromString<int>(option);
+ }
+ Y_VERIFY(tos >= 0 && tos <= 255, "ToS must be between 0x00 and 0xFF");
+ return tos;
+}
+
+template <class T>
+static T ParseWithKmgSuffixT(const char* option) {
+ TStringBuf str(option);
+ T multiplier = 1;
+ if (str.EndsWith('k')) {
+ multiplier = 1024;
+ str = str.Head(str.size() - 1);
+ } else if (str.EndsWith('m')) {
+ multiplier = 1024 * 1024;
+ str = str.Head(str.size() - 1);
+ } else if (str.EndsWith('g')) {
+ multiplier = 1024 * 1024 * 1024;
+ str = str.Head(str.size() - 1);
+ }
+ return FromString<T>(str) * multiplier;
+}
+
+static ui64 ParseWithKmgSuffix(const char* option) {
+ return ParseWithKmgSuffixT<ui64>(option);
+}
+
+static i64 ParseWithKmgSuffixS(const char* option) {
+ return ParseWithKmgSuffixT<i64>(option);
+}
+
+void TBusSessionConfig::ConfigureLastGetopt(NLastGetopt::TOpts& opts,
+ const TString& prefix) {
+ opts.AddLongOption(prefix + "total-timeout")
+ .RequiredArgument("MILLISECONDS")
+ .DefaultValue(ToString(TotalTimeout))
+ .StoreMappedResultT<const char*>(&TotalTimeout,
+ &ParseDurationForMessageBus);
+ opts.AddLongOption(prefix + "connect-timeout")
+ .RequiredArgument("MILLISECONDS")
+ .DefaultValue(ToString(ConnectTimeout))
+ .StoreMappedResultT<const char*>(&ConnectTimeout,
+ &ParseDurationForMessageBus);
+ opts.AddLongOption(prefix + "send-timeout")
+ .RequiredArgument("MILLISECONDS")
+ .DefaultValue(ToString(SendTimeout))
+ .StoreMappedResultT<const char*>(&SendTimeout,
+ &ParseDurationForMessageBus);
+ opts.AddLongOption(prefix + "send-threshold")
+ .RequiredArgument("BYTES")
+ .DefaultValue(ToString(SendThreshold))
+ .StoreMappedResultT<const char*>(&SendThreshold, &ParseWithKmgSuffix);
+
+ opts.AddLongOption(prefix + "max-in-flight")
+ .RequiredArgument("COUNT")
+ .DefaultValue(ToString(MaxInFlight))
+ .StoreMappedResultT<const char*>(&MaxInFlight, &ParseWithKmgSuffix);
+ opts.AddLongOption(prefix + "max-in-flight-by-size")
+ .RequiredArgument("BYTES")
+ .DefaultValue(
+ ToString(MaxInFlightBySize))
+ .StoreMappedResultT<const char*>(&MaxInFlightBySize, &ParseWithKmgSuffixS);
+ opts.AddLongOption(prefix + "per-con-max-in-flight")
+ .RequiredArgument("COUNT")
+ .DefaultValue(ToString(PerConnectionMaxInFlight))
+ .StoreMappedResultT<const char*>(&PerConnectionMaxInFlight,
+ &ParseWithKmgSuffix);
+ opts.AddLongOption(prefix + "per-con-max-in-flight-by-size")
+ .RequiredArgument("BYTES")
+ .DefaultValue(
+ ToString(PerConnectionMaxInFlightBySize))
+ .StoreMappedResultT<const char*>(&PerConnectionMaxInFlightBySize,
+ &ParseWithKmgSuffix);
+
+ opts.AddLongOption(prefix + "default-buffer-size")
+ .RequiredArgument("BYTES")
+ .DefaultValue(ToString(DefaultBufferSize))
+ .StoreMappedResultT<const char*>(&DefaultBufferSize,
+ &ParseWithKmgSuffix);
+ opts.AddLongOption(prefix + "max-buffer-size")
+ .RequiredArgument("BYTES")
+ .DefaultValue(ToString(MaxBufferSize))
+ .StoreMappedResultT<const char*>(&MaxBufferSize, &ParseWithKmgSuffix);
+ opts.AddLongOption(prefix + "max-message-size")
+ .RequiredArgument("BYTES")
+ .DefaultValue(ToString(MaxMessageSize))
+ .StoreMappedResultT<const char*>(&MaxMessageSize, &ParseWithKmgSuffix);
+ opts.AddLongOption(prefix + "socket-recv-buffer-size")
+ .RequiredArgument("BYTES")
+ .DefaultValue(ToString(SocketRecvBufferSize))
+ .StoreMappedResultT<const char*>(&SocketRecvBufferSize,
+ &ParseWithKmgSuffix);
+ opts.AddLongOption(prefix + "socket-send-buffer-size")
+ .RequiredArgument("BYTES")
+ .DefaultValue(ToString(SocketSendBufferSize))
+ .StoreMappedResultT<const char*>(&SocketSendBufferSize,
+ &ParseWithKmgSuffix);
+
+ opts.AddLongOption(prefix + "socket-tos")
+ .RequiredArgument("[0x00, 0xFF]")
+ .StoreMappedResultT<const char*>(&SocketToS, &ParseToSForMessageBus);
+ ;
+ opts.AddLongOption(prefix + "tcp-cork")
+ .RequiredArgument("BOOL")
+ .DefaultValue(ToString(TcpCork))
+ .StoreResult(&TcpCork);
+ opts.AddLongOption(prefix + "cork")
+ .RequiredArgument("SECONDS")
+ .DefaultValue(
+ ToString(Cork.Seconds()))
+ .StoreMappedResultT<const char*>(&Cork, &TDuration::Parse);
+
+ opts.AddLongOption(prefix + "on-message-in-pool")
+ .RequiredArgument("BOOL")
+ .DefaultValue(ToString(ExecuteOnMessageInWorkerPool))
+ .StoreResult(&ExecuteOnMessageInWorkerPool);
+ opts.AddLongOption(prefix + "on-reply-in-pool")
+ .RequiredArgument("BOOL")
+ .DefaultValue(ToString(ExecuteOnReplyInWorkerPool))
+ .StoreResult(&ExecuteOnReplyInWorkerPool);
+}
diff --git a/library/cpp/messagebus/config/session_config.h b/library/cpp/messagebus/config/session_config.h
new file mode 100644
index 0000000000..84753350a9
--- /dev/null
+++ b/library/cpp/messagebus/config/session_config.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include "codegen.h"
+#include "defs.h"
+
+#include <library/cpp/getopt/last_getopt.h>
+
+#include <util/generic/string.h>
+
+namespace NBus {
+#define BUS_SESSION_CONFIG_MAP(XX, comma) \
+ XX(Name, TString, "") \
+ comma \
+ XX(NumRetries, int, 0) comma \
+ XX(RetryInterval, int, 1000) comma \
+ XX(ReconnectWhenIdle, bool, false) comma \
+ XX(MaxInFlight, i64, 1000) comma \
+ XX(PerConnectionMaxInFlight, unsigned, 0) comma \
+ XX(PerConnectionMaxInFlightBySize, unsigned, 0) comma \
+ XX(MaxInFlightBySize, i64, -1) comma \
+ XX(TotalTimeout, i64, 0) comma \
+ XX(SendTimeout, i64, 0) comma \
+ XX(ConnectTimeout, i64, 0) comma \
+ XX(DefaultBufferSize, size_t, 10 * 1024) comma \
+ XX(MaxBufferSize, size_t, 1024 * 1024) comma \
+ XX(SocketRecvBufferSize, unsigned, 0) comma \
+ XX(SocketSendBufferSize, unsigned, 0) comma \
+ XX(SocketToS, int, -1) comma \
+ XX(SendThreshold, size_t, 10 * 1024) comma \
+ XX(Cork, TDuration, TDuration::Zero()) comma \
+ XX(MaxMessageSize, unsigned, 26 << 20) comma \
+ XX(TcpNoDelay, bool, false) comma \
+ XX(TcpCork, bool, false) comma \
+ XX(ExecuteOnMessageInWorkerPool, bool, true) comma \
+ XX(ExecuteOnReplyInWorkerPool, bool, true) comma \
+ XX(ReusePort, bool, false) comma \
+ XX(ListenPort, unsigned, 0) /* TODO: server only */
+
+ ////////////////////////////////////////////////////////////////////
+ /// \brief Configuration for client and server session
+ struct TBusSessionConfig {
+ BUS_SESSION_CONFIG_MAP(STRUCT_FIELD_GEN, )
+
+ struct TSecret {
+ TDuration TimeoutPeriod;
+ TDuration StatusFlushPeriod;
+
+ TSecret();
+ };
+
+ // secret options are available, but you shouldn't probably use them
+ TSecret Secret;
+
+ /// initialized with default settings
+ TBusSessionConfig();
+
+ TString PrintToString() const;
+
+ void ConfigureLastGetopt(NLastGetopt::TOpts&, const TString& prefix = "mb-");
+ };
+
+ using TBusClientSessionConfig = TBusSessionConfig;
+ using TBusServerSessionConfig = TBusSessionConfig;
+
+} // NBus
diff --git a/library/cpp/messagebus/config/ya.make b/library/cpp/messagebus/config/ya.make
new file mode 100644
index 0000000000..20c7dfed19
--- /dev/null
+++ b/library/cpp/messagebus/config/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(g:messagebus)
+
+PEERDIR(
+ library/cpp/getopt
+ library/cpp/deprecated/enum_codegen
+)
+
+SRCS(
+ netaddr.cpp
+ session_config.cpp
+)
+
+END()
diff --git a/library/cpp/messagebus/connection.cpp b/library/cpp/messagebus/connection.cpp
new file mode 100644
index 0000000000..07580ce18a
--- /dev/null
+++ b/library/cpp/messagebus/connection.cpp
@@ -0,0 +1,16 @@
+#include "connection.h"
+
+#include "remote_client_connection.h"
+
+#include <util/generic/cast.h>
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+void TBusClientConnectionPtrOps::Ref(TBusClientConnection* c) {
+ return CheckedCast<TRemoteClientConnection*>(c)->Ref();
+}
+
+void TBusClientConnectionPtrOps::UnRef(TBusClientConnection* c) {
+ return CheckedCast<TRemoteClientConnection*>(c)->UnRef();
+}
diff --git a/library/cpp/messagebus/connection.h b/library/cpp/messagebus/connection.h
new file mode 100644
index 0000000000..b1df64ddc1
--- /dev/null
+++ b/library/cpp/messagebus/connection.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#include "defs.h"
+#include "message.h"
+
+#include <util/generic/ptr.h>
+
+namespace NBus {
+ struct TBusClientConnection {
+ /// if you want to open connection early
+ virtual void OpenConnection() = 0;
+
+ /// Send message to the destination
+ /// If addr is set then use it as destination.
+ /// Takes ownership of addr (see ClearState method).
+ virtual EMessageStatus SendMessage(TBusMessage* pMes, bool wait = false) = 0;
+
+ virtual EMessageStatus SendMessageOneWay(TBusMessage* pMes, bool wait = false) = 0;
+
+ /// Like SendMessage but cares about message
+ template <typename T /* <: TBusMessage */>
+ EMessageStatus SendMessageAutoPtr(const TAutoPtr<T>& mes, bool wait = false) {
+ EMessageStatus status = SendMessage(mes.Get(), wait);
+ if (status == MESSAGE_OK)
+ Y_UNUSED(mes.Release());
+ return status;
+ }
+
+ /// Like SendMessageOneWay but cares about message
+ template <typename T /* <: TBusMessage */>
+ EMessageStatus SendMessageOneWayAutoPtr(const TAutoPtr<T>& mes, bool wait = false) {
+ EMessageStatus status = SendMessageOneWay(mes.Get(), wait);
+ if (status == MESSAGE_OK)
+ Y_UNUSED(mes.Release());
+ return status;
+ }
+
+ EMessageStatus SendMessageMove(TBusMessageAutoPtr message, bool wait = false) {
+ return SendMessageAutoPtr(message, wait);
+ }
+
+ EMessageStatus SendMessageOneWayMove(TBusMessageAutoPtr message, bool wait = false) {
+ return SendMessageOneWayAutoPtr(message, wait);
+ }
+
+ // TODO: implement similar one-way methods
+
+ virtual ~TBusClientConnection() {
+ }
+ };
+
+ namespace NPrivate {
+ struct TBusClientConnectionPtrOps {
+ static void Ref(TBusClientConnection*);
+ static void UnRef(TBusClientConnection*);
+ };
+ }
+
+ using TBusClientConnectionPtr = TIntrusivePtr<TBusClientConnection, NPrivate::TBusClientConnectionPtrOps>;
+
+}
diff --git a/library/cpp/messagebus/coreconn.cpp b/library/cpp/messagebus/coreconn.cpp
new file mode 100644
index 0000000000..d9411bb5db
--- /dev/null
+++ b/library/cpp/messagebus/coreconn.cpp
@@ -0,0 +1,30 @@
+#include "coreconn.h"
+
+#include "remote_connection.h"
+
+#include <util/datetime/base.h>
+#include <util/generic/yexception.h>
+#include <util/network/socket.h>
+#include <util/string/util.h>
+#include <util/system/thread.h>
+
+namespace NBus {
+ TBusInstant Now() {
+ return millisec();
+ }
+
+ EIpVersion MakeIpVersion(bool allowIpv4, bool allowIpv6) {
+ if (allowIpv4) {
+ if (allowIpv6) {
+ return EIP_VERSION_ANY;
+ } else {
+ return EIP_VERSION_4;
+ }
+ } else if (allowIpv6) {
+ return EIP_VERSION_6;
+ }
+
+ ythrow yexception() << "Neither of IPv4/IPv6 is allowed.";
+ }
+
+}
diff --git a/library/cpp/messagebus/coreconn.h b/library/cpp/messagebus/coreconn.h
new file mode 100644
index 0000000000..fca228d82e
--- /dev/null
+++ b/library/cpp/messagebus/coreconn.h
@@ -0,0 +1,67 @@
+#pragma once
+
+//////////////////////////////////////////////////////////////
+/// \file
+/// \brief Definitions for asynchonous connection queue
+
+#include "base.h"
+#include "event_loop.h"
+#include "netaddr.h"
+
+#include <util/datetime/base.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/list.h>
+#include <util/generic/map.h>
+#include <util/generic/set.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/network/address.h>
+#include <util/network/ip.h>
+#include <util/network/poller.h>
+#include <util/string/util.h>
+#include <util/system/condvar.h>
+#include <util/system/mutex.h>
+#include <util/system/thread.h>
+#include <util/thread/lfqueue.h>
+
+#include <deque>
+#include <utility>
+
+#ifdef NO_ERROR
+#undef NO_ERROR
+#endif
+
+#define BUS_WORKER_CONDVAR
+//#define BUS_WORKER_MIXED
+
+namespace NBus {
+ class TBusConnection;
+ class TBusConnectionFactory;
+ class TBusServerFactory;
+
+ using TBusConnectionList = TList<TBusConnection*>;
+
+ /// @throw yexception
+ EIpVersion MakeIpVersion(bool allowIpv4, bool allowIpv6);
+
+ inline bool WouldBlock() {
+ int syserr = LastSystemError();
+ return syserr == EAGAIN || syserr == EINPROGRESS || syserr == EWOULDBLOCK || syserr == EINTR;
+ }
+
+ class TBusSession;
+
+ struct TMaxConnectedException: public yexception {
+ TMaxConnectedException(unsigned maxConnect) {
+ yexception& exc = *this;
+ exc << TStringBuf("Exceeded maximum number of outstanding connections: ");
+ exc << maxConnect;
+ }
+ };
+
+ enum EPollType {
+ POLL_READ,
+ POLL_WRITE
+ };
+
+}
diff --git a/library/cpp/messagebus/coreconn_ut.cpp b/library/cpp/messagebus/coreconn_ut.cpp
new file mode 100644
index 0000000000..beb6850f26
--- /dev/null
+++ b/library/cpp/messagebus/coreconn_ut.cpp
@@ -0,0 +1,25 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "coreconn.h"
+
+#include <util/generic/yexception.h>
+
+Y_UNIT_TEST_SUITE(TMakeIpVersionTest) {
+ using namespace NBus;
+
+ Y_UNIT_TEST(IpV4Allowed) {
+ UNIT_ASSERT_EQUAL(MakeIpVersion(true, false), EIP_VERSION_4);
+ }
+
+ Y_UNIT_TEST(IpV6Allowed) {
+ UNIT_ASSERT_EQUAL(MakeIpVersion(false, true), EIP_VERSION_6);
+ }
+
+ Y_UNIT_TEST(AllAllowed) {
+ UNIT_ASSERT_EQUAL(MakeIpVersion(true, true), EIP_VERSION_ANY);
+ }
+
+ Y_UNIT_TEST(NothingAllowed) {
+ UNIT_ASSERT_EXCEPTION(MakeIpVersion(false, false), yexception);
+ }
+}
diff --git a/library/cpp/messagebus/debug_receiver/debug_receiver.cpp b/library/cpp/messagebus/debug_receiver/debug_receiver.cpp
new file mode 100644
index 0000000000..23b02d1003
--- /dev/null
+++ b/library/cpp/messagebus/debug_receiver/debug_receiver.cpp
@@ -0,0 +1,42 @@
+#include "debug_receiver_handler.h"
+#include "debug_receiver_proto.h"
+
+#include <library/cpp/messagebus/ybus.h>
+
+#include <library/cpp/getopt/last_getopt.h>
+#include <library/cpp/lwtrace/all.h>
+
+using namespace NBus;
+
+int main(int argc, char** argv) {
+ NLWTrace::StartLwtraceFromEnv();
+
+ TBusQueueConfig queueConfig;
+ TBusServerSessionConfig sessionConfig;
+
+ NLastGetopt::TOpts opts;
+
+ queueConfig.ConfigureLastGetopt(opts);
+ sessionConfig.ConfigureLastGetopt(opts);
+
+ opts.AddLongOption("port").Required().RequiredArgument("PORT").StoreResult(&sessionConfig.ListenPort);
+
+ opts.SetFreeArgsMax(0);
+
+ NLastGetopt::TOptsParseResult r(&opts, argc, argv);
+
+ TBusMessageQueuePtr q(CreateMessageQueue(queueConfig));
+
+ TDebugReceiverProtocol proto;
+ TDebugReceiverHandler handler;
+
+ TBusServerSessionPtr serverSession = TBusServerSession::Create(&proto, &handler, sessionConfig, q);
+ // TODO: race is here
+ handler.ServerSession = serverSession.Get();
+
+ for (;;) {
+ Sleep(TDuration::Hours(17));
+ }
+
+ return 0;
+}
diff --git a/library/cpp/messagebus/debug_receiver/debug_receiver_handler.cpp b/library/cpp/messagebus/debug_receiver/debug_receiver_handler.cpp
new file mode 100644
index 0000000000..05f99e94ca
--- /dev/null
+++ b/library/cpp/messagebus/debug_receiver/debug_receiver_handler.cpp
@@ -0,0 +1,20 @@
+#include "debug_receiver_handler.h"
+
+#include "debug_receiver_proto.h"
+
+#include <util/generic/cast.h>
+#include <util/string/printf.h>
+
+void TDebugReceiverHandler::OnError(TAutoPtr<NBus::TBusMessage>, NBus::EMessageStatus status) {
+ Cerr << "error " << status << "\n";
+}
+
+void TDebugReceiverHandler::OnMessage(NBus::TOnMessageContext& message) {
+ TDebugReceiverMessage* typedMessage = VerifyDynamicCast<TDebugReceiverMessage*>(message.GetMessage());
+ Cerr << "type=" << typedMessage->GetHeader()->Type
+ << " size=" << typedMessage->GetHeader()->Size
+ << " flags=" << Sprintf("0x%04x", (int)typedMessage->GetHeader()->FlagsInternal)
+ << "\n";
+
+ message.ForgetRequest();
+}
diff --git a/library/cpp/messagebus/debug_receiver/debug_receiver_handler.h b/library/cpp/messagebus/debug_receiver/debug_receiver_handler.h
new file mode 100644
index 0000000000..0aed6b9984
--- /dev/null
+++ b/library/cpp/messagebus/debug_receiver/debug_receiver_handler.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include <library/cpp/messagebus/ybus.h>
+
+struct TDebugReceiverHandler: public NBus::IBusServerHandler {
+ NBus::TBusServerSession* ServerSession;
+
+ void OnError(TAutoPtr<NBus::TBusMessage> pMessage, NBus::EMessageStatus status) override;
+ void OnMessage(NBus::TOnMessageContext& message) override;
+};
diff --git a/library/cpp/messagebus/debug_receiver/debug_receiver_proto.cpp b/library/cpp/messagebus/debug_receiver/debug_receiver_proto.cpp
new file mode 100644
index 0000000000..0c74f9ecc3
--- /dev/null
+++ b/library/cpp/messagebus/debug_receiver/debug_receiver_proto.cpp
@@ -0,0 +1,20 @@
+#include "debug_receiver_proto.h"
+
+using namespace NBus;
+
+TDebugReceiverProtocol::TDebugReceiverProtocol()
+ : TBusProtocol("debug receiver", 0)
+{
+}
+
+void TDebugReceiverProtocol::Serialize(const NBus::TBusMessage*, TBuffer&) {
+ Y_FAIL("it is receiver only");
+}
+
+TAutoPtr<NBus::TBusMessage> TDebugReceiverProtocol::Deserialize(ui16, TArrayRef<const char> payload) {
+ THolder<TDebugReceiverMessage> r(new TDebugReceiverMessage(ECreateUninitialized()));
+
+ r->Payload.Append(payload.data(), payload.size());
+
+ return r.Release();
+}
diff --git a/library/cpp/messagebus/debug_receiver/debug_receiver_proto.h b/library/cpp/messagebus/debug_receiver/debug_receiver_proto.h
new file mode 100644
index 0000000000..d34710dcf7
--- /dev/null
+++ b/library/cpp/messagebus/debug_receiver/debug_receiver_proto.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <library/cpp/messagebus/ybus.h>
+
+struct TDebugReceiverMessage: public NBus::TBusMessage {
+ /// constructor to create messages on sending end
+ TDebugReceiverMessage(ui16 type)
+ : NBus::TBusMessage(type)
+ {
+ }
+
+ /// constructor with serialzed data to examine the header
+ TDebugReceiverMessage(NBus::ECreateUninitialized)
+ : NBus::TBusMessage(NBus::ECreateUninitialized())
+ {
+ }
+
+ TBuffer Payload;
+};
+
+struct TDebugReceiverProtocol: public NBus::TBusProtocol {
+ TDebugReceiverProtocol();
+
+ void Serialize(const NBus::TBusMessage* mess, TBuffer& data) override;
+
+ TAutoPtr<NBus::TBusMessage> Deserialize(ui16 messageType, TArrayRef<const char> payload) override;
+};
diff --git a/library/cpp/messagebus/debug_receiver/ya.make b/library/cpp/messagebus/debug_receiver/ya.make
new file mode 100644
index 0000000000..f1b14d35bb
--- /dev/null
+++ b/library/cpp/messagebus/debug_receiver/ya.make
@@ -0,0 +1,17 @@
+PROGRAM(messagebus_debug_receiver)
+
+OWNER(g:messagebus)
+
+SRCS(
+ debug_receiver.cpp
+ debug_receiver_proto.cpp
+ debug_receiver_handler.cpp
+)
+
+PEERDIR(
+ library/cpp/getopt
+ library/cpp/lwtrace
+ library/cpp/messagebus
+)
+
+END()
diff --git a/library/cpp/messagebus/defs.h b/library/cpp/messagebus/defs.h
new file mode 100644
index 0000000000..cb553acc45
--- /dev/null
+++ b/library/cpp/messagebus/defs.h
@@ -0,0 +1,4 @@
+#pragma once
+
+#include <library/cpp/messagebus/config/defs.h>
+
diff --git a/library/cpp/messagebus/dummy_debugger.h b/library/cpp/messagebus/dummy_debugger.h
new file mode 100644
index 0000000000..89a4e18716
--- /dev/null
+++ b/library/cpp/messagebus/dummy_debugger.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <util/datetime/base.h>
+#include <util/stream/output.h>
+
+#define MB_TRACE() \
+ do { \
+ Cerr << TInstant::Now() << " " << __FILE__ << ":" << __LINE__ << " " << __FUNCTION__ << Endl; \
+ } while (false)
diff --git a/library/cpp/messagebus/duration_histogram.cpp b/library/cpp/messagebus/duration_histogram.cpp
new file mode 100644
index 0000000000..32a0001d41
--- /dev/null
+++ b/library/cpp/messagebus/duration_histogram.cpp
@@ -0,0 +1,74 @@
+#include "duration_histogram.h"
+
+#include <util/generic/singleton.h>
+#include <util/stream/str.h>
+
+namespace {
+ ui64 SecondsRound(TDuration d) {
+ if (d.MilliSeconds() % 1000 >= 500) {
+ return d.Seconds() + 1;
+ } else {
+ return d.Seconds();
+ }
+ }
+
+ ui64 MilliSecondsRound(TDuration d) {
+ if (d.MicroSeconds() % 1000 >= 500) {
+ return d.MilliSeconds() + 1;
+ } else {
+ return d.MilliSeconds();
+ }
+ }
+
+ ui64 MinutesRound(TDuration d) {
+ if (d.Seconds() % 60 >= 30) {
+ return d.Minutes() + 1;
+ } else {
+ return d.Minutes();
+ }
+ }
+
+}
+
+namespace {
+ struct TMarks {
+ std::array<TDuration, TDurationHistogram::Buckets> Marks;
+
+ TMarks() {
+ Marks[0] = TDuration::Zero();
+ for (unsigned i = 1; i < TDurationHistogram::Buckets; ++i) {
+ if (i >= TDurationHistogram::SecondBoundary) {
+ Marks[i] = TDuration::Seconds(1) * (1 << (i - TDurationHistogram::SecondBoundary));
+ } else {
+ Marks[i] = TDuration::Seconds(1) / (1 << (TDurationHistogram::SecondBoundary - i));
+ }
+ }
+ }
+ };
+}
+
+TString TDurationHistogram::LabelBefore(unsigned i) {
+ Y_VERIFY(i < Buckets);
+
+ TDuration d = Singleton<TMarks>()->Marks[i];
+
+ TStringStream ss;
+ if (d == TDuration::Zero()) {
+ ss << "0";
+ } else if (d < TDuration::Seconds(1)) {
+ ss << MilliSecondsRound(d) << "ms";
+ } else if (d < TDuration::Minutes(1)) {
+ ss << SecondsRound(d) << "s";
+ } else {
+ ss << MinutesRound(d) << "m";
+ }
+ return ss.Str();
+}
+
+TString TDurationHistogram::PrintToString() const {
+ TStringStream ss;
+ for (auto time : Times) {
+ ss << time << "\n";
+ }
+ return ss.Str();
+}
diff --git a/library/cpp/messagebus/duration_histogram.h b/library/cpp/messagebus/duration_histogram.h
new file mode 100644
index 0000000000..ed060b0101
--- /dev/null
+++ b/library/cpp/messagebus/duration_histogram.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <util/datetime/base.h>
+#include <util/generic/bitops.h>
+#include <util/generic/string.h>
+
+#include <array>
+
+struct TDurationHistogram {
+ static const unsigned Buckets = 20;
+ std::array<ui64, Buckets> Times;
+
+ static const unsigned SecondBoundary = 11;
+
+ TDurationHistogram() {
+ Times.fill(0);
+ }
+
+ static unsigned BucketFor(TDuration d) {
+ ui64 units = d.MicroSeconds() * (1 << SecondBoundary) / 1000000;
+ if (units == 0) {
+ return 0;
+ }
+ unsigned bucket = GetValueBitCount(units) - 1;
+ if (bucket >= Buckets) {
+ bucket = Buckets - 1;
+ }
+ return bucket;
+ }
+
+ void AddTime(TDuration d) {
+ Times[BucketFor(d)] += 1;
+ }
+
+ TDurationHistogram& operator+=(const TDurationHistogram& that) {
+ for (unsigned i = 0; i < Times.size(); ++i) {
+ Times[i] += that.Times[i];
+ }
+ return *this;
+ }
+
+ static TString LabelBefore(unsigned i);
+
+ TString PrintToString() const;
+};
diff --git a/library/cpp/messagebus/duration_histogram_ut.cpp b/library/cpp/messagebus/duration_histogram_ut.cpp
new file mode 100644
index 0000000000..01bcc095e9
--- /dev/null
+++ b/library/cpp/messagebus/duration_histogram_ut.cpp
@@ -0,0 +1,38 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "duration_histogram.h"
+
+Y_UNIT_TEST_SUITE(TDurationHistogramTest) {
+ Y_UNIT_TEST(BucketFor) {
+ UNIT_ASSERT_VALUES_EQUAL(0u, TDurationHistogram::BucketFor(TDuration::MicroSeconds(0)));
+ UNIT_ASSERT_VALUES_EQUAL(0u, TDurationHistogram::BucketFor(TDuration::MicroSeconds(1)));
+ UNIT_ASSERT_VALUES_EQUAL(0u, TDurationHistogram::BucketFor(TDuration::MicroSeconds(900)));
+ UNIT_ASSERT_VALUES_EQUAL(1u, TDurationHistogram::BucketFor(TDuration::MicroSeconds(1500)));
+ UNIT_ASSERT_VALUES_EQUAL(2u, TDurationHistogram::BucketFor(TDuration::MicroSeconds(2500)));
+
+ unsigned sb = TDurationHistogram::SecondBoundary;
+
+ UNIT_ASSERT_VALUES_EQUAL(sb - 1, TDurationHistogram::BucketFor(TDuration::MilliSeconds(999)));
+ UNIT_ASSERT_VALUES_EQUAL(sb, TDurationHistogram::BucketFor(TDuration::MilliSeconds(1000)));
+ UNIT_ASSERT_VALUES_EQUAL(sb, TDurationHistogram::BucketFor(TDuration::MilliSeconds(1001)));
+
+ UNIT_ASSERT_VALUES_EQUAL(TDurationHistogram::Buckets - 1, TDurationHistogram::BucketFor(TDuration::Hours(1)));
+ }
+
+ Y_UNIT_TEST(Simple) {
+ TDurationHistogram h1;
+ h1.AddTime(TDuration::MicroSeconds(1));
+ UNIT_ASSERT_VALUES_EQUAL(1u, h1.Times.front());
+
+ TDurationHistogram h2;
+ h1.AddTime(TDuration::Hours(1));
+ UNIT_ASSERT_VALUES_EQUAL(1u, h1.Times.back());
+ }
+
+ Y_UNIT_TEST(LabelFor) {
+ for (unsigned i = 0; i < TDurationHistogram::Buckets; ++i) {
+ TDurationHistogram::LabelBefore(i);
+ //Cerr << TDurationHistogram::LabelBefore(i) << "\n";
+ }
+ }
+}
diff --git a/library/cpp/messagebus/event_loop.cpp b/library/cpp/messagebus/event_loop.cpp
new file mode 100644
index 0000000000..f685135bed
--- /dev/null
+++ b/library/cpp/messagebus/event_loop.cpp
@@ -0,0 +1,370 @@
+#include "event_loop.h"
+
+#include "network.h"
+#include "thread_extra.h"
+
+#include <util/generic/hash.h>
+#include <util/network/pair.h>
+#include <util/network/poller.h>
+#include <util/system/event.h>
+#include <util/system/mutex.h>
+#include <util/system/thread.h>
+#include <util/system/yassert.h>
+#include <util/thread/lfqueue.h>
+
+#include <errno.h>
+
+using namespace NEventLoop;
+
+namespace {
+ enum ERunningState {
+ EVENT_LOOP_CREATED,
+ EVENT_LOOP_RUNNING,
+ EVENT_LOOP_STOPPED,
+ };
+
+ enum EOperation {
+ OP_READ = 1,
+ OP_WRITE = 2,
+ OP_READ_WRITE = OP_READ | OP_WRITE,
+ };
+}
+
+class TChannel::TImpl {
+public:
+ TImpl(TEventLoop::TImpl* eventLoop, TSocket socket, TEventHandlerPtr, void* cookie);
+ ~TImpl();
+
+ void EnableRead();
+ void DisableRead();
+ void EnableWrite();
+ void DisableWrite();
+
+ void Unregister();
+
+ SOCKET GetSocket() const;
+ TSocket GetSocketPtr() const;
+
+ void Update(int pollerFlags, bool enable);
+ void CallHandler();
+
+ TEventLoop::TImpl* EventLoop;
+ TSocket Socket;
+ TEventHandlerPtr EventHandler;
+ void* Cookie;
+
+ TMutex Mutex;
+
+ int CurrentFlags;
+ bool Close;
+};
+
+class TEventLoop::TImpl {
+public:
+ TImpl(const char* name);
+
+ void Run();
+ void Wakeup();
+ void Stop();
+
+ TChannelPtr Register(TSocket socket, TEventHandlerPtr eventHandler, void* cookie);
+ void Unregister(SOCKET socket);
+
+ typedef THashMap<SOCKET, TChannelPtr> TData;
+
+ void AddToPoller(SOCKET socket, void* cookie, int flags);
+
+ TMutex Mutex;
+
+ const char* Name;
+
+ TAtomic RunningState;
+ TAtomic StopSignal;
+ TSystemEvent StoppedEvent;
+ TData Data;
+
+ TLockFreeQueue<SOCKET> SocketsToRemove;
+
+ TSocketPoller Poller;
+ TSocketHolder WakeupReadSocket;
+ TSocketHolder WakeupWriteSocket;
+};
+
+TChannel::~TChannel() {
+}
+
+void TChannel::EnableRead() {
+ Impl->EnableRead();
+}
+
+void TChannel::DisableRead() {
+ Impl->DisableRead();
+}
+
+void TChannel::EnableWrite() {
+ Impl->EnableWrite();
+}
+
+void TChannel::DisableWrite() {
+ Impl->DisableWrite();
+}
+
+void TChannel::Unregister() {
+ Impl->Unregister();
+}
+
+SOCKET TChannel::GetSocket() const {
+ return Impl->GetSocket();
+}
+
+TSocket TChannel::GetSocketPtr() const {
+ return Impl->GetSocketPtr();
+}
+
+TChannel::TChannel(TImpl* impl)
+ : Impl(impl)
+{
+}
+
+TEventLoop::TEventLoop(const char* name)
+ : Impl(new TImpl(name))
+{
+}
+
+TEventLoop::~TEventLoop() {
+}
+
+void TEventLoop::Run() {
+ Impl->Run();
+}
+
+void TEventLoop::Stop() {
+ Impl->Stop();
+}
+
+bool TEventLoop::IsRunning() {
+ return AtomicGet(Impl->RunningState) == EVENT_LOOP_RUNNING;
+}
+
+TChannelPtr TEventLoop::Register(TSocket socket, TEventHandlerPtr eventHandler, void* cookie) {
+ return Impl->Register(socket, eventHandler, cookie);
+}
+
+TChannel::TImpl::TImpl(TEventLoop::TImpl* eventLoop, TSocket socket, TEventHandlerPtr eventHandler, void* cookie)
+ : EventLoop(eventLoop)
+ , Socket(socket)
+ , EventHandler(eventHandler)
+ , Cookie(cookie)
+ , CurrentFlags(0)
+ , Close(false)
+{
+}
+
+TChannel::TImpl::~TImpl() {
+ Y_ASSERT(Close);
+}
+
+void TChannel::TImpl::EnableRead() {
+ Update(OP_READ, true);
+}
+
+void TChannel::TImpl::DisableRead() {
+ Update(OP_READ, false);
+}
+
+void TChannel::TImpl::EnableWrite() {
+ Update(OP_WRITE, true);
+}
+
+void TChannel::TImpl::DisableWrite() {
+ Update(OP_WRITE, false);
+}
+
+void TChannel::TImpl::Unregister() {
+ TGuard<TMutex> guard(Mutex);
+
+ if (Close) {
+ return;
+ }
+
+ Close = true;
+ if (CurrentFlags != 0) {
+ EventLoop->Poller.Unwait(Socket);
+ CurrentFlags = 0;
+ }
+ EventHandler.Drop();
+
+ EventLoop->SocketsToRemove.Enqueue(Socket);
+ EventLoop->Wakeup();
+}
+
+void TChannel::TImpl::Update(int flags, bool enable) {
+ TGuard<TMutex> guard(Mutex);
+
+ if (Close) {
+ return;
+ }
+
+ int newFlags = enable ? (CurrentFlags | flags) : (CurrentFlags & ~flags);
+
+ if (CurrentFlags == newFlags) {
+ return;
+ }
+
+ if (!newFlags) {
+ EventLoop->Poller.Unwait(Socket);
+ } else {
+ void* cookie = reinterpret_cast<void*>(this);
+ EventLoop->AddToPoller(Socket, cookie, newFlags);
+ }
+
+ CurrentFlags = newFlags;
+}
+
+SOCKET TChannel::TImpl::GetSocket() const {
+ return Socket;
+}
+
+TSocket TChannel::TImpl::GetSocketPtr() const {
+ return Socket;
+}
+
+void TChannel::TImpl::CallHandler() {
+ TEventHandlerPtr handler;
+
+ {
+ TGuard<TMutex> guard(Mutex);
+
+ // other thread may have re-added socket to epoll
+ // so even if CurrentFlags is 0, epoll may fire again
+ // so please use non-blocking operations
+ CurrentFlags = 0;
+
+ if (Close) {
+ return;
+ }
+
+ handler = EventHandler;
+ }
+
+ if (!!handler) {
+ handler->HandleEvent(Socket, Cookie);
+ }
+}
+
+TEventLoop::TImpl::TImpl(const char* name)
+ : Name(name)
+ , RunningState(EVENT_LOOP_CREATED)
+ , StopSignal(0)
+{
+ SOCKET wakeupSockets[2];
+
+ if (SocketPair(wakeupSockets) < 0) {
+ Y_FAIL("failed to create socket pair for wakeup sockets: %s", LastSystemErrorText());
+ }
+
+ TSocketHolder wakeupReadSocket(wakeupSockets[0]);
+ TSocketHolder wakeupWriteSocket(wakeupSockets[1]);
+
+ WakeupReadSocket.Swap(wakeupReadSocket);
+ WakeupWriteSocket.Swap(wakeupWriteSocket);
+
+ SetNonBlock(WakeupWriteSocket, true);
+ SetNonBlock(WakeupReadSocket, true);
+
+ Poller.WaitRead(WakeupReadSocket,
+ reinterpret_cast<void*>(this));
+}
+
+void TEventLoop::TImpl::Run() {
+ bool res = AtomicCas(&RunningState, EVENT_LOOP_RUNNING, EVENT_LOOP_CREATED);
+ Y_VERIFY(res, "Invalid mbus event loop state");
+
+ if (!!Name) {
+ SetCurrentThreadName(Name);
+ }
+
+ while (AtomicGet(StopSignal) == 0) {
+ void* cookies[1024];
+ const size_t count = Poller.WaitI(cookies, Y_ARRAY_SIZE(cookies));
+
+ void** end = cookies + count;
+ for (void** c = cookies; c != end; ++c) {
+ TChannel::TImpl* s = reinterpret_cast<TChannel::TImpl*>(*c);
+
+ if (*c == this) {
+ char buf[0x1000];
+ if (NBus::NPrivate::SocketRecv(WakeupReadSocket, buf) < 0) {
+ Y_FAIL("failed to recv from wakeup socket: %s", LastSystemErrorText());
+ }
+ continue;
+ }
+
+ s->CallHandler();
+ }
+
+ SOCKET socket = -1;
+ while (SocketsToRemove.Dequeue(&socket)) {
+ TGuard<TMutex> guard(Mutex);
+ Y_VERIFY(Data.erase(socket) == 1, "must be removed once");
+ }
+ }
+
+ {
+ TGuard<TMutex> guard(Mutex);
+ for (auto& it : Data) {
+ it.second->Unregister();
+ }
+
+ // release file descriptors
+ Data.clear();
+ }
+
+ res = AtomicCas(&RunningState, EVENT_LOOP_STOPPED, EVENT_LOOP_RUNNING);
+
+ Y_VERIFY(res);
+
+ StoppedEvent.Signal();
+}
+
+void TEventLoop::TImpl::Stop() {
+ AtomicSet(StopSignal, 1);
+
+ if (AtomicGet(RunningState) == EVENT_LOOP_RUNNING) {
+ Wakeup();
+
+ StoppedEvent.WaitI();
+ }
+}
+
+TChannelPtr TEventLoop::TImpl::Register(TSocket socket, TEventHandlerPtr eventHandler, void* cookie) {
+ Y_VERIFY(socket != INVALID_SOCKET, "must be a valid socket");
+
+ TChannelPtr channel = new TChannel(new TChannel::TImpl(this, socket, eventHandler, cookie));
+
+ TGuard<TMutex> guard(Mutex);
+
+ Y_VERIFY(Data.insert(std::make_pair(socket, channel)).second, "must not be already inserted");
+
+ return channel;
+}
+
+void TEventLoop::TImpl::Wakeup() {
+ if (NBus::NPrivate::SocketSend(WakeupWriteSocket, TArrayRef<const char>("", 1)) < 0) {
+ if (LastSystemError() != EAGAIN) {
+ Y_FAIL("failed to send to wakeup socket: %s", LastSystemErrorText());
+ }
+ }
+}
+
+void TEventLoop::TImpl::AddToPoller(SOCKET socket, void* cookie, int flags) {
+ if (flags == OP_READ) {
+ Poller.WaitReadOneShot(socket, cookie);
+ } else if (flags == OP_WRITE) {
+ Poller.WaitWriteOneShot(socket, cookie);
+ } else if (flags == OP_READ_WRITE) {
+ Poller.WaitReadWriteOneShot(socket, cookie);
+ } else {
+ Y_FAIL("Wrong flags: %d", int(flags));
+ }
+}
diff --git a/library/cpp/messagebus/event_loop.h b/library/cpp/messagebus/event_loop.h
new file mode 100644
index 0000000000..d5b0a53b0c
--- /dev/null
+++ b/library/cpp/messagebus/event_loop.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include <util/generic/object_counter.h>
+#include <util/generic/ptr.h>
+#include <util/network/init.h>
+#include <util/network/socket.h>
+
+namespace NEventLoop {
+ struct IEventHandler
+ : public TAtomicRefCount<IEventHandler> {
+ virtual void HandleEvent(SOCKET socket, void* cookie) = 0;
+ virtual ~IEventHandler() {
+ }
+ };
+
+ typedef TIntrusivePtr<IEventHandler> TEventHandlerPtr;
+
+ class TEventLoop;
+
+ // TODO: make TChannel itself a pointer
+ // to avoid confusion with Drop and Unregister
+ class TChannel
+ : public TAtomicRefCount<TChannel> {
+ public:
+ ~TChannel();
+
+ void EnableRead();
+ void DisableRead();
+ void EnableWrite();
+ void DisableWrite();
+
+ void Unregister();
+
+ SOCKET GetSocket() const;
+ TSocket GetSocketPtr() const;
+
+ private:
+ class TImpl;
+ friend class TEventLoop;
+
+ TObjectCounter<TChannel> ObjectCounter;
+
+ TChannel(TImpl*);
+
+ private:
+ THolder<TImpl> Impl;
+ };
+
+ typedef TIntrusivePtr<TChannel> TChannelPtr;
+
+ class TEventLoop {
+ public:
+ TEventLoop(const char* name = nullptr);
+ ~TEventLoop();
+
+ void Run();
+ void Stop();
+ bool IsRunning();
+
+ TChannelPtr Register(TSocket socket, TEventHandlerPtr, void* cookie = nullptr);
+
+ private:
+ class TImpl;
+ friend class TChannel;
+
+ TObjectCounter<TEventLoop> ObjectCounter;
+
+ private:
+ THolder<TImpl> Impl;
+ };
+
+}
diff --git a/library/cpp/messagebus/extra_ref.h b/library/cpp/messagebus/extra_ref.h
new file mode 100644
index 0000000000..2927123266
--- /dev/null
+++ b/library/cpp/messagebus/extra_ref.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <util/system/yassert.h>
+
+class TExtraRef {
+ TAtomic Holds;
+
+public:
+ TExtraRef()
+ : Holds(false)
+ {
+ }
+ ~TExtraRef() {
+ Y_VERIFY(!Holds);
+ }
+
+ template <typename TThis>
+ void Retain(TThis* thiz) {
+ if (AtomicGet(Holds)) {
+ return;
+ }
+ if (AtomicCas(&Holds, 1, 0)) {
+ thiz->Ref();
+ }
+ }
+
+ template <typename TThis>
+ void Release(TThis* thiz) {
+ if (!AtomicGet(Holds)) {
+ return;
+ }
+ if (AtomicCas(&Holds, 0, 1)) {
+ thiz->UnRef();
+ }
+ }
+};
diff --git a/library/cpp/messagebus/futex_like.cpp b/library/cpp/messagebus/futex_like.cpp
new file mode 100644
index 0000000000..7f965126db
--- /dev/null
+++ b/library/cpp/messagebus/futex_like.cpp
@@ -0,0 +1,55 @@
+#include <util/system/platform.h>
+
+#ifdef _linux_
+#include <sys/syscall.h>
+#include <linux/futex.h>
+
+#if !defined(SYS_futex)
+#define SYS_futex __NR_futex
+#endif
+#endif
+
+#include <errno.h>
+
+#include <util/system/yassert.h>
+
+#include "futex_like.h"
+
+#ifdef _linux_
+namespace {
+ int futex(int* uaddr, int op, int val, const struct timespec* timeout,
+ int* uaddr2, int val3) {
+ return syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
+ }
+}
+#endif
+
+void TFutexLike::Wake(size_t count) {
+ Y_ASSERT(count > 0);
+#ifdef _linux_
+ if (count > unsigned(Max<int>())) {
+ count = Max<int>();
+ }
+ int r = futex(&Value, FUTEX_WAKE, count, nullptr, nullptr, 0);
+ Y_VERIFY(r >= 0, "futex_wake failed: %s", strerror(errno));
+#else
+ TGuard<TMutex> guard(Mutex);
+ if (count == 1) {
+ CondVar.Signal();
+ } else {
+ CondVar.BroadCast();
+ }
+#endif
+}
+
+void TFutexLike::Wait(int expected) {
+#ifdef _linux_
+ int r = futex(&Value, FUTEX_WAIT, expected, nullptr, nullptr, 0);
+ Y_VERIFY(r >= 0 || errno == EWOULDBLOCK, "futex_wait failed: %s", strerror(errno));
+#else
+ TGuard<TMutex> guard(Mutex);
+ if (expected == Get()) {
+ CondVar.WaitI(Mutex);
+ }
+#endif
+}
diff --git a/library/cpp/messagebus/futex_like.h b/library/cpp/messagebus/futex_like.h
new file mode 100644
index 0000000000..31d60c60f1
--- /dev/null
+++ b/library/cpp/messagebus/futex_like.h
@@ -0,0 +1,86 @@
+#pragma once
+
+#include <util/system/condvar.h>
+#include <util/system/mutex.h>
+#include <util/system/platform.h>
+
+class TFutexLike {
+private:
+#ifdef _linux_
+ int Value;
+#else
+ TAtomic Value;
+ TMutex Mutex;
+ TCondVar CondVar;
+#endif
+
+public:
+ TFutexLike()
+ : Value(0)
+ {
+ }
+
+ int AddAndGet(int add) {
+#ifdef _linux_
+ //return __atomic_add_fetch(&Value, add, __ATOMIC_SEQ_CST);
+ return __sync_add_and_fetch(&Value, add);
+#else
+ return AtomicAdd(Value, add);
+#endif
+ }
+
+ int GetAndAdd(int add) {
+ return AddAndGet(add) - add;
+ }
+
+// until we have modern GCC
+#if 0
+ int GetAndSet(int newValue) {
+#ifdef _linux_
+ return __atomic_exchange_n(&Value, newValue, __ATOMIC_SEQ_CST);
+#else
+ return AtomicSwap(&Value, newValue);
+#endif
+ }
+#endif
+
+ int Get() {
+#ifdef _linux_
+ //return __atomic_load_n(&Value, __ATOMIC_SEQ_CST);
+ __sync_synchronize();
+ return Value;
+#else
+ return AtomicGet(Value);
+#endif
+ }
+
+ void Set(int newValue) {
+#ifdef _linux_
+ //__atomic_store_n(&Value, newValue, __ATOMIC_SEQ_CST);
+ Value = newValue;
+ __sync_synchronize();
+#else
+ AtomicSet(Value, newValue);
+#endif
+ }
+
+ int GetAndIncrement() {
+ return AddAndGet(1) - 1;
+ }
+
+ int IncrementAndGet() {
+ return AddAndGet(1);
+ }
+
+ int GetAndDecrement() {
+ return AddAndGet(-1) + 1;
+ }
+
+ int DecrementAndGet() {
+ return AddAndGet(-1);
+ }
+
+ void Wake(size_t count = Max<size_t>());
+
+ void Wait(int expected);
+};
diff --git a/library/cpp/messagebus/handler.cpp b/library/cpp/messagebus/handler.cpp
new file mode 100644
index 0000000000..333bd52934
--- /dev/null
+++ b/library/cpp/messagebus/handler.cpp
@@ -0,0 +1,36 @@
+#include "handler.h"
+
+#include "remote_server_connection.h"
+#include "ybus.h"
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+void IBusErrorHandler::OnError(TAutoPtr<TBusMessage> pMessage, EMessageStatus status) {
+ Y_UNUSED(pMessage);
+ Y_UNUSED(status);
+}
+void IBusServerHandler::OnSent(TAutoPtr<TBusMessage> pMessage) {
+ Y_UNUSED(pMessage);
+}
+void IBusClientHandler::OnMessageSent(TBusMessage* pMessage) {
+ Y_UNUSED(pMessage);
+}
+void IBusClientHandler::OnMessageSentOneWay(TAutoPtr<TBusMessage> pMessage) {
+ Y_UNUSED(pMessage);
+}
+
+void IBusClientHandler::OnClientConnectionEvent(const TClientConnectionEvent&) {
+}
+
+void TOnMessageContext::ForgetRequest() {
+ Session->ForgetRequest(Ident);
+}
+
+TNetAddr TOnMessageContext::GetPeerAddrNetAddr() const {
+ return Ident.GetNetAddr();
+}
+
+bool TOnMessageContext::IsConnectionAlive() const {
+ return !!Ident.Connection && Ident.Connection->IsAlive();
+}
diff --git a/library/cpp/messagebus/handler.h b/library/cpp/messagebus/handler.h
new file mode 100644
index 0000000000..60002c68a6
--- /dev/null
+++ b/library/cpp/messagebus/handler.h
@@ -0,0 +1,135 @@
+#pragma once
+
+#include "defs.h"
+#include "message.h"
+#include "message_status.h"
+#include "use_after_free_checker.h"
+#include "use_count_checker.h"
+
+#include <util/generic/noncopyable.h>
+
+namespace NBus {
+ /////////////////////////////////////////////////////////////////
+ /// \brief Interface to message bus handler
+
+ struct IBusErrorHandler {
+ friend struct ::NBus::NPrivate::TBusSessionImpl;
+
+ private:
+ TUseAfterFreeChecker UseAfterFreeChecker;
+ TUseCountChecker UseCountChecker;
+
+ public:
+ /// called when message or reply can't be delivered
+ virtual void OnError(TAutoPtr<TBusMessage> pMessage, EMessageStatus status);
+
+ virtual ~IBusErrorHandler() {
+ }
+ };
+
+ class TClientConnectionEvent {
+ public:
+ enum EType {
+ CONNECTED,
+ DISCONNECTED,
+ };
+
+ private:
+ EType Type;
+ ui64 Id;
+ TNetAddr Addr;
+
+ public:
+ TClientConnectionEvent(EType type, ui64 id, TNetAddr addr)
+ : Type(type)
+ , Id(id)
+ , Addr(addr)
+ {
+ }
+
+ EType GetType() const {
+ return Type;
+ }
+ ui64 GetId() const {
+ return Id;
+ }
+ TNetAddr GetAddr() const {
+ return Addr;
+ }
+ };
+
+ class TOnMessageContext : TNonCopyable {
+ private:
+ THolder<TBusMessage> Message;
+ TBusIdentity Ident;
+ // TODO: we don't need to store session, we have connection in ident
+ TBusServerSession* Session;
+
+ public:
+ TOnMessageContext()
+ : Session()
+ {
+ }
+ TOnMessageContext(TAutoPtr<TBusMessage> message, TBusIdentity& ident, TBusServerSession* session)
+ : Message(message)
+ , Session(session)
+ {
+ Ident.Swap(ident);
+ }
+
+ bool IsInWork() const {
+ return Ident.IsInWork();
+ }
+
+ bool operator!() const {
+ return !IsInWork();
+ }
+
+ TBusMessage* GetMessage() {
+ return Message.Get();
+ }
+
+ TBusMessage* ReleaseMessage() {
+ return Message.Release();
+ }
+
+ TBusServerSession* GetSession() {
+ return Session;
+ }
+
+ template <typename U /* <: TBusMessage */>
+ EMessageStatus SendReplyAutoPtr(TAutoPtr<U>& rep);
+
+ EMessageStatus SendReplyMove(TBusMessageAutoPtr response);
+
+ void AckMessage(TBusIdentity& ident);
+
+ void ForgetRequest();
+
+ void Swap(TOnMessageContext& that) {
+ DoSwap(Message, that.Message);
+ Ident.Swap(that.Ident);
+ DoSwap(Session, that.Session);
+ }
+
+ TNetAddr GetPeerAddrNetAddr() const;
+
+ bool IsConnectionAlive() const;
+ };
+
+ struct IBusServerHandler: public IBusErrorHandler {
+ virtual void OnMessage(TOnMessageContext& onMessage) = 0;
+ /// called when reply has been sent from destination
+ virtual void OnSent(TAutoPtr<TBusMessage> pMessage);
+ };
+
+ struct IBusClientHandler: public IBusErrorHandler {
+ /// called on source when reply arrives from destination
+ virtual void OnReply(TAutoPtr<TBusMessage> pMessage, TAutoPtr<TBusMessage> pReply) = 0;
+ /// called when client side message has gone into wire, place to call AckMessage()
+ virtual void OnMessageSent(TBusMessage* pMessage);
+ virtual void OnMessageSentOneWay(TAutoPtr<TBusMessage> pMessage);
+ virtual void OnClientConnectionEvent(const TClientConnectionEvent&);
+ };
+
+}
diff --git a/library/cpp/messagebus/handler_impl.h b/library/cpp/messagebus/handler_impl.h
new file mode 100644
index 0000000000..6593f04cc3
--- /dev/null
+++ b/library/cpp/messagebus/handler_impl.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "handler.h"
+#include "local_flags.h"
+#include "session.h"
+
+namespace NBus {
+ template <typename U /* <: TBusMessage */>
+ EMessageStatus TOnMessageContext::SendReplyAutoPtr(TAutoPtr<U>& response) {
+ return Session->SendReplyAutoPtr(Ident, response);
+ }
+
+ inline EMessageStatus TOnMessageContext::SendReplyMove(TBusMessageAutoPtr response) {
+ return SendReplyAutoPtr(response);
+ }
+
+ inline void TOnMessageContext::AckMessage(TBusIdentity& ident) {
+ Y_VERIFY(Ident.LocalFlags == NPrivate::MESSAGE_IN_WORK);
+ Y_VERIFY(ident.LocalFlags == 0);
+ Ident.Swap(ident);
+ }
+
+}
diff --git a/library/cpp/messagebus/hash.h b/library/cpp/messagebus/hash.h
new file mode 100644
index 0000000000..cc1b136a86
--- /dev/null
+++ b/library/cpp/messagebus/hash.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <util/str_stl.h>
+#include <util/digest/numeric.h>
+
+namespace NBus {
+ namespace NPrivate {
+ template <typename T>
+ size_t Hash(const T& val) {
+ return THash<T>()(val);
+ }
+
+ template <typename T, typename U>
+ size_t HashValues(const T& a, const U& b) {
+ return CombineHashes(Hash(a), Hash(b));
+ }
+
+ }
+}
diff --git a/library/cpp/messagebus/key_value_printer.cpp b/library/cpp/messagebus/key_value_printer.cpp
new file mode 100644
index 0000000000..c8592145c7
--- /dev/null
+++ b/library/cpp/messagebus/key_value_printer.cpp
@@ -0,0 +1,46 @@
+#include "key_value_printer.h"
+
+#include <util/stream/format.h>
+
+TKeyValuePrinter::TKeyValuePrinter(const TString& sep)
+ : Sep(sep)
+{
+}
+
+TKeyValuePrinter::~TKeyValuePrinter() {
+}
+
+void TKeyValuePrinter::AddRowImpl(const TString& key, const TString& value, bool alignLeft) {
+ Keys.push_back(key);
+ Values.push_back(value);
+ AlignLefts.push_back(alignLeft);
+}
+
+TString TKeyValuePrinter::PrintToString() const {
+ if (Keys.empty()) {
+ return TString();
+ }
+
+ size_t keyWidth = 0;
+ size_t valueWidth = 0;
+
+ for (size_t i = 0; i < Keys.size(); ++i) {
+ keyWidth = Max(keyWidth, Keys.at(i).size());
+ valueWidth = Max(valueWidth, Values.at(i).size());
+ }
+
+ TStringStream ss;
+
+ for (size_t i = 0; i < Keys.size(); ++i) {
+ ss << RightPad(Keys.at(i), keyWidth);
+ ss << Sep;
+ if (AlignLefts.at(i)) {
+ ss << Values.at(i);
+ } else {
+ ss << LeftPad(Values.at(i), valueWidth);
+ }
+ ss << Endl;
+ }
+
+ return ss.Str();
+}
diff --git a/library/cpp/messagebus/key_value_printer.h b/library/cpp/messagebus/key_value_printer.h
new file mode 100644
index 0000000000..bca1fde50e
--- /dev/null
+++ b/library/cpp/messagebus/key_value_printer.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/generic/typetraits.h>
+#include <util/generic/vector.h>
+#include <util/string/cast.h>
+
+class TKeyValuePrinter {
+private:
+ TString Sep;
+ TVector<TString> Keys;
+ TVector<TString> Values;
+ TVector<bool> AlignLefts;
+
+public:
+ TKeyValuePrinter(const TString& sep = TString(": "));
+ ~TKeyValuePrinter();
+
+ template <typename TKey, typename TValue>
+ void AddRow(const TKey& key, const TValue& value, bool leftAlign = !std::is_integral<TValue>::value) {
+ return AddRowImpl(ToString(key), ToString(value), leftAlign);
+ }
+
+ TString PrintToString() const;
+
+private:
+ void AddRowImpl(const TString& key, const TString& value, bool leftAlign);
+};
diff --git a/library/cpp/messagebus/latch.h b/library/cpp/messagebus/latch.h
new file mode 100644
index 0000000000..373f4c0e13
--- /dev/null
+++ b/library/cpp/messagebus/latch.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <util/system/condvar.h>
+#include <util/system/mutex.h>
+
+class TLatch {
+private:
+ // 0 for unlocked, 1 for locked
+ TAtomic Locked;
+ TMutex Mutex;
+ TCondVar CondVar;
+
+public:
+ TLatch()
+ : Locked(0)
+ {
+ }
+
+ void Wait() {
+ // optimistic path
+ if (AtomicGet(Locked) == 0) {
+ return;
+ }
+
+ TGuard<TMutex> guard(Mutex);
+ while (AtomicGet(Locked) == 1) {
+ CondVar.WaitI(Mutex);
+ }
+ }
+
+ bool TryWait() {
+ return AtomicGet(Locked) == 0;
+ }
+
+ void Unlock() {
+ // optimistic path
+ if (AtomicGet(Locked) == 0) {
+ return;
+ }
+
+ TGuard<TMutex> guard(Mutex);
+ AtomicSet(Locked, 0);
+ CondVar.BroadCast();
+ }
+
+ void Lock() {
+ AtomicSet(Locked, 1);
+ }
+
+ bool IsLocked() {
+ return AtomicGet(Locked);
+ }
+};
diff --git a/library/cpp/messagebus/latch_ut.cpp b/library/cpp/messagebus/latch_ut.cpp
new file mode 100644
index 0000000000..bfab04f527
--- /dev/null
+++ b/library/cpp/messagebus/latch_ut.cpp
@@ -0,0 +1,20 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "latch.h"
+
+Y_UNIT_TEST_SUITE(TLatch) {
+ Y_UNIT_TEST(Simple) {
+ TLatch latch;
+ UNIT_ASSERT(latch.TryWait());
+ latch.Lock();
+ UNIT_ASSERT(!latch.TryWait());
+ latch.Lock();
+ latch.Lock();
+ UNIT_ASSERT(!latch.TryWait());
+ latch.Unlock();
+ UNIT_ASSERT(latch.TryWait());
+ latch.Unlock();
+ latch.Unlock();
+ UNIT_ASSERT(latch.TryWait());
+ }
+}
diff --git a/library/cpp/messagebus/left_right_buffer.h b/library/cpp/messagebus/left_right_buffer.h
new file mode 100644
index 0000000000..f937cefad0
--- /dev/null
+++ b/library/cpp/messagebus/left_right_buffer.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include <util/generic/buffer.h>
+#include <util/generic/noncopyable.h>
+#include <util/system/yassert.h>
+
+namespace NBus {
+ namespace NPrivate {
+ class TLeftRightBuffer : TNonCopyable {
+ private:
+ TBuffer Buffer;
+ size_t Left;
+
+ void CheckInvariant() {
+ Y_ASSERT(Left <= Buffer.Size());
+ }
+
+ public:
+ TLeftRightBuffer()
+ : Left(0)
+ {
+ }
+
+ TBuffer& GetBuffer() {
+ return Buffer;
+ }
+
+ size_t Capacity() {
+ return Buffer.Capacity();
+ }
+
+ void Clear() {
+ Buffer.Clear();
+ Left = 0;
+ }
+
+ void Reset() {
+ Buffer.Reset();
+ Left = 0;
+ }
+
+ void Compact() {
+ Buffer.ChopHead(Left);
+ Left = 0;
+ }
+
+ char* LeftPos() {
+ return Buffer.Data() + Left;
+ }
+
+ size_t LeftSize() {
+ return Left;
+ }
+
+ void LeftProceed(size_t count) {
+ Y_ASSERT(count <= Size());
+ Left += count;
+ }
+
+ size_t Size() {
+ return Buffer.Size() - Left;
+ }
+
+ bool Empty() {
+ return Size() == 0;
+ }
+
+ char* RightPos() {
+ return Buffer.Data() + Buffer.Size();
+ }
+
+ size_t Avail() {
+ return Buffer.Avail();
+ }
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/lfqueue_batch.h b/library/cpp/messagebus/lfqueue_batch.h
new file mode 100644
index 0000000000..8128d3154d
--- /dev/null
+++ b/library/cpp/messagebus/lfqueue_batch.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <library/cpp/messagebus/actor/temp_tls_vector.h>
+
+#include <util/generic/vector.h>
+#include <util/thread/lfstack.h>
+
+template <typename T, template <typename, class> class TVectorType = TVector>
+class TLockFreeQueueBatch {
+private:
+ TLockFreeStack<TVectorType<T, std::allocator<T>>*> Stack;
+
+public:
+ bool IsEmpty() {
+ return Stack.IsEmpty();
+ }
+
+ void EnqueueAll(TAutoPtr<TVectorType<T, std::allocator<T>>> vec) {
+ Stack.Enqueue(vec.Release());
+ }
+
+ void DequeueAllSingleConsumer(TVectorType<T, std::allocator<T>>* r) {
+ TTempTlsVector<TVectorType<T, std::allocator<T>>*> vs;
+ Stack.DequeueAllSingleConsumer(vs.GetVector());
+
+ for (typename TVector<TVectorType<T, std::allocator<T>>*>::reverse_iterator i = vs.GetVector()->rbegin();
+ i != vs.GetVector()->rend(); ++i) {
+ if (i == vs.GetVector()->rend()) {
+ r->swap(**i);
+ } else {
+ r->insert(r->end(), (*i)->begin(), (*i)->end());
+ }
+ delete *i;
+ }
+ }
+};
diff --git a/library/cpp/messagebus/lfqueue_batch_ut.cpp b/library/cpp/messagebus/lfqueue_batch_ut.cpp
new file mode 100644
index 0000000000..f80434c0d4
--- /dev/null
+++ b/library/cpp/messagebus/lfqueue_batch_ut.cpp
@@ -0,0 +1,56 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "lfqueue_batch.h"
+
+Y_UNIT_TEST_SUITE(TLockFreeQueueBatch) {
+ Y_UNIT_TEST(Order1) {
+ TLockFreeQueueBatch<unsigned> q;
+ {
+ TAutoPtr<TVector<unsigned>> v(new TVector<unsigned>);
+ v->push_back(0);
+ v->push_back(1);
+ q.EnqueueAll(v);
+ }
+
+ TVector<unsigned> r;
+ q.DequeueAllSingleConsumer(&r);
+
+ UNIT_ASSERT_VALUES_EQUAL(2u, r.size());
+ for (unsigned i = 0; i < 2; ++i) {
+ UNIT_ASSERT_VALUES_EQUAL(i, r[i]);
+ }
+
+ r.clear();
+ q.DequeueAllSingleConsumer(&r);
+ UNIT_ASSERT_VALUES_EQUAL(0u, r.size());
+ }
+
+ Y_UNIT_TEST(Order2) {
+ TLockFreeQueueBatch<unsigned> q;
+ {
+ TAutoPtr<TVector<unsigned>> v(new TVector<unsigned>);
+ v->push_back(0);
+ v->push_back(1);
+ q.EnqueueAll(v);
+ }
+ {
+ TAutoPtr<TVector<unsigned>> v(new TVector<unsigned>);
+ v->push_back(2);
+ v->push_back(3);
+ v->push_back(4);
+ q.EnqueueAll(v);
+ }
+
+ TVector<unsigned> r;
+ q.DequeueAllSingleConsumer(&r);
+
+ UNIT_ASSERT_VALUES_EQUAL(5u, r.size());
+ for (unsigned i = 0; i < 5; ++i) {
+ UNIT_ASSERT_VALUES_EQUAL(i, r[i]);
+ }
+
+ r.clear();
+ q.DequeueAllSingleConsumer(&r);
+ UNIT_ASSERT_VALUES_EQUAL(0u, r.size());
+ }
+}
diff --git a/library/cpp/messagebus/local_flags.cpp b/library/cpp/messagebus/local_flags.cpp
new file mode 100644
index 0000000000..877e533f76
--- /dev/null
+++ b/library/cpp/messagebus/local_flags.cpp
@@ -0,0 +1,32 @@
+#include "local_flags.h"
+
+#include <util/stream/str.h>
+#include <util/string/printf.h>
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+TString NBus::NPrivate::LocalFlagSetToString(ui32 flags0) {
+ if (flags0 == 0) {
+ return "0";
+ }
+
+ ui32 flags = flags0;
+
+ TStringStream ss;
+#define P(name, value, ...) \
+ do \
+ if (flags & value) { \
+ if (!ss.Str().empty()) { \
+ ss << "|"; \
+ } \
+ ss << #name; \
+ flags &= ~name; \
+ } \
+ while (false);
+ MESSAGE_LOCAL_FLAGS_MAP(P)
+ if (flags != 0) {
+ return Sprintf("0x%x", unsigned(flags0));
+ }
+ return ss.Str();
+}
diff --git a/library/cpp/messagebus/local_flags.h b/library/cpp/messagebus/local_flags.h
new file mode 100644
index 0000000000..f589283188
--- /dev/null
+++ b/library/cpp/messagebus/local_flags.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <library/cpp/deprecated/enum_codegen/enum_codegen.h>
+
+#include <util/generic/string.h>
+#include <util/stream/output.h>
+
+namespace NBus {
+ namespace NPrivate {
+#define MESSAGE_LOCAL_FLAGS_MAP(XX) \
+ XX(MESSAGE_REPLY_INTERNAL, 0x0001) \
+ XX(MESSAGE_IN_WORK, 0x0002) \
+ XX(MESSAGE_IN_FLIGHT_ON_CLIENT, 0x0004) \
+ XX(MESSAGE_REPLY_IS_BEGING_SENT, 0x0008) \
+ XX(MESSAGE_ONE_WAY_INTERNAL, 0x0010) \
+ /**/
+
+ enum EMessageLocalFlags {
+ MESSAGE_LOCAL_FLAGS_MAP(ENUM_VALUE_GEN)
+ };
+
+ ENUM_TO_STRING(EMessageLocalFlags, MESSAGE_LOCAL_FLAGS_MAP)
+
+ TString LocalFlagSetToString(ui32);
+ }
+}
diff --git a/library/cpp/messagebus/local_flags_ut.cpp b/library/cpp/messagebus/local_flags_ut.cpp
new file mode 100644
index 0000000000..189d73eb0f
--- /dev/null
+++ b/library/cpp/messagebus/local_flags_ut.cpp
@@ -0,0 +1,18 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "local_flags.h"
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+Y_UNIT_TEST_SUITE(EMessageLocalFlags) {
+ Y_UNIT_TEST(TestLocalFlagSetToString) {
+ UNIT_ASSERT_VALUES_EQUAL("0", LocalFlagSetToString(0));
+ UNIT_ASSERT_VALUES_EQUAL("MESSAGE_REPLY_INTERNAL",
+ LocalFlagSetToString(MESSAGE_REPLY_INTERNAL));
+ UNIT_ASSERT_VALUES_EQUAL("MESSAGE_IN_WORK|MESSAGE_IN_FLIGHT_ON_CLIENT",
+ LocalFlagSetToString(MESSAGE_IN_WORK | MESSAGE_IN_FLIGHT_ON_CLIENT));
+ UNIT_ASSERT_VALUES_EQUAL("0xff3456",
+ LocalFlagSetToString(0xff3456));
+ }
+}
diff --git a/library/cpp/messagebus/local_tasks.h b/library/cpp/messagebus/local_tasks.h
new file mode 100644
index 0000000000..d8e801a457
--- /dev/null
+++ b/library/cpp/messagebus/local_tasks.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <util/system/atomic.h>
+
+class TLocalTasks {
+private:
+ TAtomic GotTasks;
+
+public:
+ TLocalTasks()
+ : GotTasks(0)
+ {
+ }
+
+ void AddTask() {
+ AtomicSet(GotTasks, 1);
+ }
+
+ bool FetchTask() {
+ bool gotTasks = AtomicCas(&GotTasks, 0, 1);
+ return gotTasks;
+ }
+};
diff --git a/library/cpp/messagebus/locator.cpp b/library/cpp/messagebus/locator.cpp
new file mode 100644
index 0000000000..e38a35c426
--- /dev/null
+++ b/library/cpp/messagebus/locator.cpp
@@ -0,0 +1,427 @@
+////////////////////////////////////////////////////////////////////////////
+/// \file
+/// \brief Implementation of locator service
+
+#include "locator.h"
+
+#include "ybus.h"
+
+#include <util/generic/hash_set.h>
+#include <util/system/hostname.h>
+
+namespace NBus {
+ using namespace NAddr;
+
+ static TIpPort GetAddrPort(const IRemoteAddr& addr) {
+ switch (addr.Addr()->sa_family) {
+ case AF_INET: {
+ return ntohs(((const sockaddr_in*)addr.Addr())->sin_port);
+ }
+
+ case AF_INET6: {
+ return ntohs(((const sockaddr_in6*)addr.Addr())->sin6_port);
+ }
+
+ default: {
+ ythrow yexception() << "not implemented";
+ break;
+ }
+ }
+ }
+
+ static inline bool GetIp6AddressFromVector(const TVector<TNetAddr>& addrs, TNetAddr* addr) {
+ for (size_t i = 1; i < addrs.size(); ++i) {
+ if (addrs[i - 1].Addr()->sa_family == addrs[i].Addr()->sa_family) {
+ return false;
+ }
+
+ if (GetAddrPort(addrs[i - 1]) != GetAddrPort(addrs[i])) {
+ return false;
+ }
+ }
+
+ for (size_t i = 0; i < addrs.size(); ++i) {
+ if (addrs[i].Addr()->sa_family == AF_INET6) {
+ *addr = addrs[i];
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ EMessageStatus TBusProtocol::GetDestination(const TBusClientSession*, TBusMessage* mess, TBusLocator* locator, TNetAddr* addr) {
+ TBusService service = GetService();
+ TBusKey key = GetKey(mess);
+ TVector<TNetAddr> addrs;
+
+ /// check for special local key
+ if (key == YBUS_KEYLOCAL) {
+ locator->GetLocalAddresses(service, addrs);
+ } else {
+ /// lookup address/port in the locator table
+ locator->LocateAll(service, key, addrs);
+ }
+
+ if (addrs.size() == 0) {
+ return MESSAGE_SERVICE_UNKNOWN;
+ } else if (addrs.size() == 1) {
+ *addr = addrs[0];
+ } else {
+ if (!GetIp6AddressFromVector(addrs, addr)) {
+ /// default policy can't make choice for you here, overide GetDestination() function
+ /// to implement custom routing strategy for your service.
+ return MESSAGE_SERVICE_TOOMANY;
+ }
+ }
+
+ return MESSAGE_OK;
+ }
+
+ static const sockaddr_in* SockAddrIpV4(const IRemoteAddr& a) {
+ return (const sockaddr_in*)a.Addr();
+ }
+
+ static const sockaddr_in6* SockAddrIpV6(const IRemoteAddr& a) {
+ return (const sockaddr_in6*)a.Addr();
+ }
+
+ static bool IsAddressEqual(const IRemoteAddr& a1, const IRemoteAddr& a2) {
+ if (a1.Addr()->sa_family == a2.Addr()->sa_family) {
+ if (a1.Addr()->sa_family == AF_INET) {
+ return memcmp(&SockAddrIpV4(a1)->sin_addr, &SockAddrIpV4(a2)->sin_addr, sizeof(in_addr)) == 0;
+ } else {
+ return memcmp(&SockAddrIpV6(a1)->sin6_addr, &SockAddrIpV6(a2)->sin6_addr, sizeof(in6_addr)) == 0;
+ }
+ }
+ return false;
+ }
+
+ TBusLocator::TBusLocator()
+ : MyInterfaces(GetNetworkInterfaces())
+ {
+ }
+
+ bool TBusLocator::TItem::operator<(const TItem& y) const {
+ const TItem& x = *this;
+
+ if (x.ServiceId == y.ServiceId) {
+ return (x.End < y.End) || ((x.End == y.End) && CompareByHost(x.Addr, y.Addr) < 0);
+ }
+ return x.ServiceId < y.ServiceId;
+ }
+
+ bool TBusLocator::TItem::operator==(const TItem& y) const {
+ return ServiceId == y.ServiceId && Start == y.Start && End == y.End && Addr == y.Addr;
+ }
+
+ TBusLocator::TItem::TItem(TServiceId serviceId, TBusKey start, TBusKey end, const TNetAddr& addr)
+ : ServiceId(serviceId)
+ , Start(start)
+ , End(end)
+ , Addr(addr)
+ {
+ }
+
+ bool TBusLocator::IsLocal(const TNetAddr& addr) {
+ for (const auto& myInterface : MyInterfaces) {
+ if (IsAddressEqual(addr, *myInterface.Address)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ TBusLocator::TServiceId TBusLocator::GetServiceId(const char* name) {
+ const char* c = ServiceIdSet.insert(name).first->c_str();
+ return (ui64)c;
+ }
+
+ int TBusLocator::RegisterBreak(TBusService service, const TVector<TBusKey>& starts, const TNetAddr& addr) {
+ TGuard<TMutex> G(Lock);
+
+ TServiceId serviceId = GetServiceId(service);
+ for (size_t i = 0; i < starts.size(); ++i) {
+ RegisterBreak(serviceId, starts[i], addr);
+ }
+ return 0;
+ }
+
+ int TBusLocator::RegisterBreak(TServiceId serviceId, const TBusKey start, const TNetAddr& addr) {
+ TItems::const_iterator it = Items.lower_bound(TItem(serviceId, 0, start, addr));
+ TItems::const_iterator service_it =
+ Items.lower_bound(TItem(serviceId, 0, 0, TNetAddr()));
+
+ THolder<TItem> left;
+ THolder<TItem> right;
+ if ((it != Items.end() || Items.begin() != Items.end()) && service_it != Items.end() && service_it->ServiceId == serviceId) {
+ if (it == Items.end()) {
+ --it;
+ }
+ const TItem& item = *it;
+ left.Reset(new TItem(serviceId, item.Start,
+ Max<TBusKey>(item.Start, start - 1), item.Addr));
+ right.Reset(new TItem(serviceId, start, item.End, addr));
+ Items.erase(*it);
+ } else {
+ left.Reset(new TItem(serviceId, YBUS_KEYMIN, start, addr));
+ if (start < YBUS_KEYMAX) {
+ right.Reset(new TItem(serviceId, start + 1, YBUS_KEYMAX, addr));
+ }
+ }
+ Items.insert(*left);
+ Items.insert(*right);
+ NormalizeBreaks(serviceId);
+ return 0;
+ }
+
+ int TBusLocator::UnregisterBreak(TBusService service, const TNetAddr& addr) {
+ TGuard<TMutex> G(Lock);
+
+ TServiceId serviceId = GetServiceId(service);
+ return UnregisterBreak(serviceId, addr);
+ }
+
+ int TBusLocator::UnregisterBreak(TServiceId serviceId, const TNetAddr& addr) {
+ int deleted = 0;
+ TItems::iterator it = Items.begin();
+ while (it != Items.end()) {
+ const TItem& item = *it;
+ if (item.ServiceId != serviceId) {
+ ++it;
+ continue;
+ }
+ TItems::iterator itErase = it++;
+ if (item.ServiceId == serviceId && item.Addr == addr) {
+ Items.erase(itErase);
+ deleted += 1;
+ }
+ }
+
+ if (Items.begin() == Items.end()) {
+ return deleted;
+ }
+ TBusKey keyItem = YBUS_KEYMAX;
+ it = Items.end();
+ TItems::iterator first = it;
+ do {
+ --it;
+ // item.Start is not used in set comparison function
+ // so you can't violate set sort order by changing it
+ // hence const_cast()
+ TItem& item = const_cast<TItem&>(*it);
+ if (item.ServiceId != serviceId) {
+ continue;
+ }
+ first = it;
+ if (item.End < keyItem) {
+ item.End = keyItem;
+ }
+ keyItem = item.Start - 1;
+ } while (it != Items.begin());
+
+ if (first != Items.end() && first->Start != 0) {
+ TItem item(serviceId, YBUS_KEYMIN, first->Start - 1, first->Addr);
+ Items.insert(item);
+ }
+
+ NormalizeBreaks(serviceId);
+ return deleted;
+ }
+
+ void TBusLocator::NormalizeBreaks(TServiceId serviceId) {
+ TItems::const_iterator first = Items.lower_bound(TItem(serviceId, YBUS_KEYMIN, YBUS_KEYMIN, TNetAddr()));
+ TItems::const_iterator last = Items.end();
+
+ if ((Items.end() != first) && (first->ServiceId == serviceId)) {
+ if (serviceId != Max<TServiceId>()) {
+ last = Items.lower_bound(TItem(serviceId + 1, YBUS_KEYMIN, YBUS_KEYMIN, TNetAddr()));
+ }
+
+ --last;
+ Y_ASSERT(Items.end() != last);
+ Y_ASSERT(last->ServiceId == serviceId);
+
+ TItem& beg = const_cast<TItem&>(*first);
+ beg.Addr = last->Addr;
+ }
+ }
+
+ int TBusLocator::LocateAll(TBusService service, TBusKey key, TVector<TNetAddr>& addrs) {
+ TGuard<TMutex> G(Lock);
+ Y_VERIFY(addrs.empty(), "Non emtpy addresses");
+
+ TServiceId serviceId = GetServiceId(service);
+ TItems::const_iterator it;
+
+ for (it = Items.lower_bound(TItem(serviceId, 0, key, TNetAddr()));
+ it != Items.end() && it->ServiceId == serviceId && it->Start <= key && key <= it->End;
+ ++it) {
+ const TItem& item = *it;
+ addrs.push_back(item.Addr);
+ }
+
+ if (addrs.size() == 0) {
+ return -1;
+ }
+ return (int)addrs.size();
+ }
+
+ int TBusLocator::Locate(TBusService service, TBusKey key, TNetAddr* addr) {
+ TGuard<TMutex> G(Lock);
+
+ TServiceId serviceId = GetServiceId(service);
+ TItems::const_iterator it;
+
+ it = Items.lower_bound(TItem(serviceId, 0, key, TNetAddr()));
+
+ if (it != Items.end()) {
+ const TItem& item = *it;
+ if (item.ServiceId == serviceId && item.Start <= key && key < item.End) {
+ *addr = item.Addr;
+
+ return 0;
+ }
+ }
+
+ return -1;
+ }
+
+ int TBusLocator::GetLocalPort(TBusService service) {
+ TGuard<TMutex> G(Lock);
+ TServiceId serviceId = GetServiceId(service);
+ TItems::const_iterator it;
+ int port = 0;
+
+ for (it = Items.lower_bound(TItem(serviceId, 0, 0, TNetAddr())); it != Items.end(); ++it) {
+ const TItem& item = *it;
+ if (item.ServiceId != serviceId) {
+ break;
+ }
+
+ if (IsLocal(item.Addr)) {
+ if (port != 0 && port != GetAddrPort(item.Addr)) {
+ Y_ASSERT(0 && "Can't decide which port to use.");
+ return 0;
+ }
+ port = GetAddrPort(item.Addr);
+ }
+ }
+
+ return port;
+ }
+
+ int TBusLocator::GetLocalAddresses(TBusService service, TVector<TNetAddr>& addrs) {
+ TGuard<TMutex> G(Lock);
+ TServiceId serviceId = GetServiceId(service);
+ TItems::const_iterator it;
+
+ for (it = Items.lower_bound(TItem(serviceId, 0, 0, TNetAddr())); it != Items.end(); ++it) {
+ const TItem& item = *it;
+ if (item.ServiceId != serviceId) {
+ break;
+ }
+
+ if (IsLocal(item.Addr)) {
+ addrs.push_back(item.Addr);
+ }
+ }
+
+ if (addrs.size() == 0) {
+ return -1;
+ }
+
+ return (int)addrs.size();
+ }
+
+ int TBusLocator::LocateHost(TBusService service, TBusKey key, TString* host, int* port, bool* isLocal) {
+ int ret;
+ TNetAddr addr;
+ ret = Locate(service, key, &addr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ {
+ TGuard<TMutex> G(Lock);
+ THostAddrMap::const_iterator it = HostAddrMap.find(addr);
+ if (it == HostAddrMap.end()) {
+ return -1;
+ }
+ *host = it->second;
+ }
+
+ *port = GetAddrPort(addr);
+ if (isLocal != nullptr) {
+ *isLocal = IsLocal(addr);
+ }
+ return 0;
+ }
+
+ int TBusLocator::LocateKeys(TBusService service, TBusKeyVec& keys, bool onlyLocal) {
+ TGuard<TMutex> G(Lock);
+ Y_VERIFY(keys.empty(), "Non empty keys");
+
+ TServiceId serviceId = GetServiceId(service);
+ TItems::const_iterator it;
+ for (it = Items.begin(); it != Items.end(); ++it) {
+ const TItem& item = *it;
+ if (item.ServiceId != serviceId) {
+ continue;
+ }
+ if (onlyLocal && !IsLocal(item.Addr)) {
+ continue;
+ }
+ keys.push_back(std::make_pair(item.Start, item.End));
+ }
+ return (int)keys.size();
+ }
+
+ int TBusLocator::Register(TBusService service, const char* hostName, int port, TBusKey start /*= YBUS_KEYMIN*/, TBusKey end /*= YBUS_KEYMAX*/, EIpVersion requireVersion /*= EIP_VERSION_4*/, EIpVersion preferVersion /*= EIP_VERSION_ANY*/) {
+ TNetAddr addr(hostName, port, requireVersion, preferVersion); // throws
+ {
+ TGuard<TMutex> G(Lock);
+ HostAddrMap[addr] = hostName;
+ }
+ Register(service, start, end, addr);
+ return 0;
+ }
+
+ int TBusLocator::Register(TBusService service, TBusKey start, TBusKey end, const TNetworkAddress& na, EIpVersion requireVersion /*= EIP_VERSION_4*/, EIpVersion preferVersion /*= EIP_VERSION_ANY*/) {
+ TNetAddr addr(na, requireVersion, preferVersion); // throws
+ Register(service, start, end, addr);
+ return 0;
+ }
+
+ int TBusLocator::Register(TBusService service, TBusKey start, TBusKey end, const TNetAddr& addr) {
+ TGuard<TMutex> G(Lock);
+
+ TServiceId serviceId = GetServiceId(service);
+ TItems::const_iterator it;
+
+ TItem itemToReg(serviceId, start, end, addr);
+ for (it = Items.lower_bound(TItem(serviceId, 0, start, TNetAddr()));
+ it != Items.end() && it->ServiceId == serviceId;
+ ++it) {
+ const TItem& item = *it;
+ if (item == itemToReg) {
+ return 0;
+ }
+ if ((item.Start < start && start < item.End) || (item.Start < end && end < item.End)) {
+ Y_FAIL("Overlap in registered keys with non-identical range");
+ }
+ }
+
+ Items.insert(itemToReg);
+ return 0;
+ }
+
+ int TBusLocator::Unregister(TBusService service, TBusKey start, TBusKey end) {
+ TGuard<TMutex> G(Lock);
+ TServiceId serviceId = GetServiceId(service);
+ Items.erase(TItem(serviceId, start, end, TNetAddr()));
+ return 0;
+ }
+
+}
diff --git a/library/cpp/messagebus/locator.h b/library/cpp/messagebus/locator.h
new file mode 100644
index 0000000000..f8556a3fce
--- /dev/null
+++ b/library/cpp/messagebus/locator.h
@@ -0,0 +1,93 @@
+#pragma once
+
+#include "defs.h"
+
+#include <util/generic/hash.h>
+#include <util/generic/map.h>
+#include <util/generic/set.h>
+#include <util/generic/string.h>
+#include <util/network/interface.h>
+#include <util/system/mutex.h>
+
+namespace NBus {
+ ///////////////////////////////////////////////
+ /// \brief Client interface to locator service
+
+ /// This interface abstracts clustering/location service that
+ /// allows clients find servers (address, port) using "name" and "key".
+ /// The instance lives in TBusMessageQueue-object, but can be shared by different queues.
+ class TBusLocator: public TAtomicRefCount<TBusLocator>, public TNonCopyable {
+ private:
+ typedef ui64 TServiceId;
+ typedef TSet<TString> TServiceIdSet;
+ TServiceIdSet ServiceIdSet;
+ TServiceId GetServiceId(const char* name);
+
+ typedef TMap<TNetAddr, TString> THostAddrMap;
+ THostAddrMap HostAddrMap;
+
+ TNetworkInterfaceList MyInterfaces;
+
+ struct TItem {
+ TServiceId ServiceId;
+ TBusKey Start;
+ TBusKey End;
+ TNetAddr Addr;
+
+ bool operator<(const TItem& y) const;
+
+ bool operator==(const TItem& y) const;
+
+ TItem(TServiceId serviceId, TBusKey start, TBusKey end, const TNetAddr& addr);
+ };
+
+ typedef TMultiSet<TItem> TItems;
+ TItems Items;
+ TMutex Lock;
+
+ int RegisterBreak(TServiceId serviceId, const TBusKey start, const TNetAddr& addr);
+ int UnregisterBreak(TServiceId serviceId, const TNetAddr& addr);
+
+ void NormalizeBreaks(TServiceId serviceId);
+
+ private:
+ int Register(TBusService service, TBusKey start, TBusKey end, const TNetAddr& addr);
+
+ public:
+ /// creates instance that obtains location table from locator server (not implemented)
+ TBusLocator();
+
+ /// returns true if this address is on the same node for YBUS_KEYLOCAL
+ bool IsLocal(const TNetAddr& addr);
+
+ /// returns first address for service and key
+ int Locate(TBusService service, TBusKey key, TNetAddr* addr);
+
+ /// returns all addresses mathing service and key
+ int LocateAll(TBusService service, TBusKey key, TVector<TNetAddr>& addrs);
+
+ /// returns actual host name for service and key
+ int LocateHost(TBusService service, TBusKey key, TString* host, int* port, bool* isLocal = nullptr);
+
+ /// returns all key ranges for the given service
+ int LocateKeys(TBusService service, TBusKeyVec& keys, bool onlyLocal = false);
+
+ /// returns port on the local node for the service
+ int GetLocalPort(TBusService service);
+
+ /// returns addresses of the local node for the service
+ int GetLocalAddresses(TBusService service, TVector<TNetAddr>& addrs);
+
+ /// register service instance
+ int Register(TBusService service, TBusKey start, TBusKey end, const TNetworkAddress& addr, EIpVersion requireVersion = EIP_VERSION_4, EIpVersion preferVersion = EIP_VERSION_ANY);
+ /// @throws yexception
+ int Register(TBusService service, const char* host, int port, TBusKey start = YBUS_KEYMIN, TBusKey end = YBUS_KEYMAX, EIpVersion requireVersion = EIP_VERSION_4, EIpVersion preferVersion = EIP_VERSION_ANY);
+
+ /// unregister service instance
+ int Unregister(TBusService service, TBusKey start, TBusKey end);
+
+ int RegisterBreak(TBusService service, const TVector<TBusKey>& starts, const TNetAddr& addr);
+ int UnregisterBreak(TBusService service, const TNetAddr& addr);
+ };
+
+}
diff --git a/library/cpp/messagebus/mb_lwtrace.cpp b/library/cpp/messagebus/mb_lwtrace.cpp
new file mode 100644
index 0000000000..c54cd5ab71
--- /dev/null
+++ b/library/cpp/messagebus/mb_lwtrace.cpp
@@ -0,0 +1,12 @@
+#include "mb_lwtrace.h"
+
+#include <library/cpp/lwtrace/all.h>
+
+#include <util/generic/singleton.h>
+
+LWTRACE_DEFINE_PROVIDER(LWTRACE_MESSAGEBUS_PROVIDER)
+
+void NBus::InitBusLwtrace() {
+ // Function is nop, and needed only to make sure TBusLwtraceInit loaded.
+ // It won't be necessary when pg@ implements GLOBAL in arc.
+}
diff --git a/library/cpp/messagebus/mb_lwtrace.h b/library/cpp/messagebus/mb_lwtrace.h
new file mode 100644
index 0000000000..e62728b265
--- /dev/null
+++ b/library/cpp/messagebus/mb_lwtrace.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <library/cpp/lwtrace/all.h>
+
+#include <util/generic/string.h>
+
+#define LWTRACE_MESSAGEBUS_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \
+ PROBE(Error, GROUPS("MessagebusRare"), TYPES(TString, TString, TString), NAMES("status", "address", "misc")) \
+ PROBE(ServerUnknownVersion, GROUPS("MessagebusRare"), TYPES(TString, ui32), NAMES("address", "version")) \
+ PROBE(Accepted, GROUPS("MessagebusRare"), TYPES(TString), NAMES("address")) \
+ PROBE(Disconnected, GROUPS("MessagebusRare"), TYPES(TString), NAMES("address")) \
+ PROBE(Read, GROUPS(), TYPES(ui32), NAMES("size")) \
+ /**/
+
+LWTRACE_DECLARE_PROVIDER(LWTRACE_MESSAGEBUS_PROVIDER)
+
+namespace NBus {
+ void InitBusLwtrace();
+}
diff --git a/library/cpp/messagebus/memory.h b/library/cpp/messagebus/memory.h
new file mode 100644
index 0000000000..b2c0544491
--- /dev/null
+++ b/library/cpp/messagebus/memory.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#ifndef CACHE_LINE_SIZE
+#define CACHE_LINE_SIZE 64
+#endif
+
+#define CONCAT(a, b) a##b
+#define LABEL(a) CONCAT(UniqueName_, a)
+#define UNIQUE_NAME LABEL(__LINE__)
+
+#define CACHE_LINE_PADDING char UNIQUE_NAME[CACHE_LINE_SIZE];
+
+static inline void* MallocAligned(size_t size, size_t alignment) {
+ void** ptr = (void**)malloc(size + alignment + sizeof(size_t*));
+ if (!ptr) {
+ return nullptr;
+ }
+
+ size_t mask = ~(alignment - 1);
+ intptr_t roundedDown = intptr_t(ptr) & mask;
+ void** alignedPtr = (void**)(roundedDown + alignment);
+ alignedPtr[-1] = ptr;
+ return alignedPtr;
+}
+
+static inline void FreeAligned(void* ptr) {
+ if (!ptr) {
+ return;
+ }
+
+ void** typedPtr = (void**)ptr;
+ void* originalPtr = typedPtr[-1];
+ free(originalPtr);
+}
+
+static inline void* MallocCacheAligned(size_t size) {
+ return MallocAligned(size, CACHE_LINE_SIZE);
+}
+
+static inline void FreeCacheAligned(void* ptr) {
+ return FreeAligned(ptr);
+}
diff --git a/library/cpp/messagebus/memory_ut.cpp b/library/cpp/messagebus/memory_ut.cpp
new file mode 100644
index 0000000000..00654f28a1
--- /dev/null
+++ b/library/cpp/messagebus/memory_ut.cpp
@@ -0,0 +1,13 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "memory.h"
+
+Y_UNIT_TEST_SUITE(MallocAligned) {
+ Y_UNIT_TEST(Test) {
+ for (size_t size = 0; size < 1000; ++size) {
+ void* ptr = MallocAligned(size, 128);
+ UNIT_ASSERT(uintptr_t(ptr) % 128 == 0);
+ FreeAligned(ptr);
+ }
+ }
+}
diff --git a/library/cpp/messagebus/message.cpp b/library/cpp/messagebus/message.cpp
new file mode 100644
index 0000000000..bfa7ed8e9b
--- /dev/null
+++ b/library/cpp/messagebus/message.cpp
@@ -0,0 +1,198 @@
+#include "remote_server_connection.h"
+#include "ybus.h"
+
+#include <util/random/random.h>
+#include <util/string/printf.h>
+#include <util/system/atomic.h>
+
+#include <string.h>
+
+using namespace NBus;
+
+namespace NBus {
+ using namespace NBus::NPrivate;
+
+ TBusIdentity::TBusIdentity()
+ : MessageId(0)
+ , Size(0)
+ , Flags(0)
+ , LocalFlags(0)
+ {
+ }
+
+ TBusIdentity::~TBusIdentity() {
+ // TODO: print local flags
+#ifndef NDEBUG
+ Y_VERIFY(LocalFlags == 0, "local flags must be zero at this point; message type is %s",
+ MessageType.value_or("unknown").c_str());
+#else
+ Y_VERIFY(LocalFlags == 0, "local flags must be zero at this point");
+#endif
+ }
+
+ TNetAddr TBusIdentity::GetNetAddr() const {
+ if (!!Connection) {
+ return Connection->GetAddr();
+ } else {
+ Y_FAIL();
+ }
+ }
+
+ void TBusIdentity::Pack(char* dest) {
+ memcpy(dest, this, sizeof(TBusIdentity));
+ LocalFlags = 0;
+
+ // prevent decref
+ new (&Connection) TIntrusivePtr<TRemoteServerConnection>;
+ }
+
+ void TBusIdentity::Unpack(const char* src) {
+ Y_VERIFY(LocalFlags == 0);
+ Y_VERIFY(!Connection);
+
+ memcpy(this, src, sizeof(TBusIdentity));
+ }
+
+ void TBusHeader::GenerateId() {
+ for (;;) {
+ Id = RandomNumber<TBusKey>();
+ // Skip reserved ids
+ if (IsBusKeyValid(Id))
+ return;
+ }
+ }
+
+ TBusMessage::TBusMessage(ui16 type, int approxsize)
+ //: TCtr("BusMessage")
+ : TRefCounted<TBusMessage, TAtomicCounter, TDelete>(1)
+ , LocalFlags(0)
+ , RequestSize(0)
+ , Data(nullptr)
+ {
+ Y_UNUSED(approxsize);
+ GetHeader()->Type = type;
+ DoReset();
+ }
+
+ TBusMessage::TBusMessage(ECreateUninitialized)
+ //: TCtr("BusMessage")
+ : TRefCounted<TBusMessage, TAtomicCounter, TDelete>(1)
+ , LocalFlags(0)
+ , Data(nullptr)
+ {
+ }
+
+ TString TBusMessage::Describe() const {
+ return Sprintf("object type: %s, message type: %d", TypeName(*this).data(), int(GetHeader()->Type));
+ }
+
+ TBusMessage::~TBusMessage() {
+#ifndef NDEBUG
+ Y_VERIFY(GetHeader()->Id != YBUS_KEYINVALID, "must not be invalid key, message type: %d, ", int(Type));
+ GetHeader()->Id = YBUS_KEYINVALID;
+ Data = (void*)17;
+ CheckClean();
+#endif
+ }
+
+ void TBusMessage::DoReset() {
+ GetHeader()->SendTime = 0;
+ GetHeader()->Size = 0;
+ GetHeader()->FlagsInternal = 0;
+ GetHeader()->GenerateId();
+ GetHeader()->SetVersionInternal();
+ }
+
+ void TBusMessage::Reset() {
+ CheckClean();
+ DoReset();
+ }
+
+ void TBusMessage::CheckClean() const {
+ if (Y_UNLIKELY(LocalFlags != 0)) {
+ TString describe = Describe();
+ TString localFlags = LocalFlagSetToString(LocalFlags);
+ Y_FAIL("message local flags must be zero, got: %s, message: %s", localFlags.data(), describe.data());
+ }
+ }
+
+ ///////////////////////////////////////////////////////
+ /// \brief Unpacks header from network order
+
+ /// \todo ntoh instead of memcpy
+ int TBusHeader::ReadHeader(TArrayRef<const char> data) {
+ Y_ASSERT(data.size() >= sizeof(TBusHeader));
+ memcpy(this, data.data(), sizeof(TBusHeader));
+ return sizeof(TBusHeader);
+ }
+
+ ///////////////////////////////////////////////////////
+ /// \brief Packs header to network order
+
+ //////////////////////////////////////////////////////////
+ /// \brief serialize message identity to be used to construct reply message
+
+ /// function stores messageid, flags and connection reply address into the buffer
+ /// that can later be used to construct a reply to the message
+ void TBusMessage::GetIdentity(TBusIdentity& data) const {
+ data.MessageId = GetHeader()->Id;
+ data.Size = GetHeader()->Size;
+ data.Flags = GetHeader()->FlagsInternal;
+ //data.LocalFlags = LocalFlags;
+ }
+
+ ////////////////////////////////////////////////////////////
+ /// \brief set message identity from serialized form
+
+ /// function restores messageid, flags and connection reply address from the buffer
+ /// into the reply message
+ void TBusMessage::SetIdentity(const TBusIdentity& data) {
+ // TODO: wrong assertion: YBUS_KEYMIN is 0
+ Y_ASSERT(data.MessageId != 0);
+ bool compressed = IsCompressed();
+ GetHeader()->Id = data.MessageId;
+ GetHeader()->FlagsInternal = data.Flags;
+ LocalFlags = data.LocalFlags & ~MESSAGE_IN_WORK;
+ ReplyTo = data.Connection->PeerAddrSocketAddr;
+ SetCompressed(compressed || IsCompressedResponse());
+ }
+
+ void TBusMessage::SetCompressed(bool v) {
+ if (v) {
+ GetHeader()->FlagsInternal |= MESSAGE_COMPRESS_INTERNAL;
+ } else {
+ GetHeader()->FlagsInternal &= ~(MESSAGE_COMPRESS_INTERNAL);
+ }
+ }
+
+ void TBusMessage::SetCompressedResponse(bool v) {
+ if (v) {
+ GetHeader()->FlagsInternal |= MESSAGE_COMPRESS_RESPONSE;
+ } else {
+ GetHeader()->FlagsInternal &= ~(MESSAGE_COMPRESS_RESPONSE);
+ }
+ }
+
+ TString TBusIdentity::ToString() const {
+ TStringStream ss;
+ ss << "msg-id=" << MessageId
+ << " size=" << Size;
+ if (!!Connection) {
+ ss << " conn=" << Connection->GetAddr();
+ }
+ ss
+ << " flags=" << Flags
+ << " local-flags=" << LocalFlags
+#ifndef NDEBUG
+ << " msg-type= " << MessageType.value_or("unknown").c_str()
+#endif
+ ;
+ return ss.Str();
+ }
+
+}
+
+template <>
+void Out<TBusIdentity>(IOutputStream& os, TTypeTraits<TBusIdentity>::TFuncParam ident) {
+ os << ident.ToString();
+}
diff --git a/library/cpp/messagebus/message.h b/library/cpp/messagebus/message.h
new file mode 100644
index 0000000000..005ca10c65
--- /dev/null
+++ b/library/cpp/messagebus/message.h
@@ -0,0 +1,272 @@
+#pragma once
+
+#include "base.h"
+#include "local_flags.h"
+#include "message_status.h"
+#include "netaddr.h"
+#include "socket_addr.h"
+
+#include <util/generic/array_ref.h>
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+#include <util/system/defaults.h>
+#include <util/system/type_name.h>
+#include <util/system/yassert.h>
+
+#include <optional>
+#include <typeinfo>
+
+namespace NBus {
+ ///////////////////////////////////////////////////////////////////
+ /// \brief Structure to preserve identity from message to reply
+ struct TBusIdentity : TNonCopyable {
+ friend class TBusMessage;
+ friend class NPrivate::TRemoteServerSession;
+ friend struct NPrivate::TClientRequestImpl;
+ friend class TOnMessageContext;
+
+ // TODO: make private
+ TBusKey MessageId;
+
+ private:
+ ui32 Size;
+ TIntrusivePtr<NPrivate::TRemoteServerConnection> Connection;
+ ui16 Flags;
+ ui32 LocalFlags;
+ TInstant RecvTime;
+
+#ifndef NDEBUG
+ std::optional<TString> MessageType;
+#endif
+
+ private:
+ // TODO: drop
+ TNetAddr GetNetAddr() const;
+
+ public:
+ void Pack(char* dest);
+ void Unpack(const char* src);
+
+ bool IsInWork() const {
+ return LocalFlags & NPrivate::MESSAGE_IN_WORK;
+ }
+
+ // for internal use only
+ void BeginWork() {
+ SetInWork(true);
+ }
+
+ // for internal use only
+ void EndWork() {
+ SetInWork(false);
+ }
+
+ TBusIdentity();
+ ~TBusIdentity();
+
+ void Swap(TBusIdentity& that) {
+ DoSwap(MessageId, that.MessageId);
+ DoSwap(Size, that.Size);
+ DoSwap(Connection, that.Connection);
+ DoSwap(Flags, that.Flags);
+ DoSwap(LocalFlags, that.LocalFlags);
+ DoSwap(RecvTime, that.RecvTime);
+#ifndef NDEBUG
+ DoSwap(MessageType, that.MessageType);
+#endif
+ }
+
+ TString ToString() const;
+
+ private:
+ void SetInWork(bool inWork) {
+ if (LocalFlags == 0 && inWork) {
+ LocalFlags = NPrivate::MESSAGE_IN_WORK;
+ } else if (LocalFlags == NPrivate::MESSAGE_IN_WORK && !inWork) {
+ LocalFlags = 0;
+ } else {
+ Y_FAIL("impossible combination of flag and parameter: %s %d",
+ inWork ? "true" : "false", unsigned(LocalFlags));
+ }
+ }
+
+ void SetMessageType(const std::type_info& messageTypeInfo) {
+#ifndef NDEBUG
+ Y_VERIFY(!MessageType, "state check");
+ MessageType = TypeName(messageTypeInfo);
+#else
+ Y_UNUSED(messageTypeInfo);
+#endif
+ }
+ };
+
+ static const size_t BUS_IDENTITY_PACKED_SIZE = sizeof(TBusIdentity);
+
+ ///////////////////////////////////////////////////////////////
+ /// \brief Message flags in TBusHeader.Flags
+ enum EMessageFlags {
+ MESSAGE_COMPRESS_INTERNAL = 0x8000, ///< message is compressed
+ MESSAGE_COMPRESS_RESPONSE = 0x4000, ///< message prefers compressed response
+ MESSAGE_VERSION_INTERNAL = 0x00F0, ///< these bits are used as version
+ };
+
+//////////////////////////////////////////////////////////
+/// \brief Message header present in all message send and received
+
+/// This header is send into the wire.
+/// \todo fix for low/high end, 32/64bit some day
+#pragma pack(1)
+ struct TBusHeader {
+ friend class TBusMessage;
+
+ TBusKey Id = 0; ///< unique message ID
+ ui32 Size = 0; ///< total size of the message
+ TBusInstant SendTime = 0; ///< time the message was sent
+ ui16 FlagsInternal = 0; ///< TRACE is one of the flags
+ ui16 Type = 0; ///< to be used by TBusProtocol
+
+ int GetVersionInternal() {
+ return (FlagsInternal & MESSAGE_VERSION_INTERNAL) >> 4;
+ }
+ void SetVersionInternal(unsigned ver = YBUS_VERSION) {
+ FlagsInternal |= (ver << 4);
+ }
+
+ public:
+ TBusHeader() {
+ }
+ TBusHeader(TArrayRef<const char> data) {
+ ReadHeader(data);
+ }
+
+ private:
+ /// function for serialization/deserialization of the header
+ /// returns number of bytes written/read
+ int ReadHeader(TArrayRef<const char> data);
+
+ void GenerateId();
+ };
+#pragma pack()
+
+#define TBUSMAX_MESSAGE 26 * 1024 * 1024 + sizeof(NBus::TBusHeader) ///< is't it enough?
+#define TBUSMIN_MESSAGE sizeof(NBus::TBusHeader) ///< can't be less then header
+
+ inline bool IsVersionNegotiation(const NBus::TBusHeader& header) {
+ return header.Id == 0 && header.Size == sizeof(TBusHeader);
+ }
+
+ //////////////////////////////////////////////////////////
+ /// \brief Base class for all messages passed in the system
+
+ enum ECreateUninitialized {
+ MESSAGE_CREATE_UNINITIALIZED,
+ };
+
+ class TBusMessage
+ : protected TBusHeader,
+ public TRefCounted<TBusMessage, TAtomicCounter, TDelete>,
+ private TNonCopyable {
+ friend class TLocalSession;
+ friend struct ::NBus::NPrivate::TBusSessionImpl;
+ friend class ::NBus::NPrivate::TRemoteServerSession;
+ friend class ::NBus::NPrivate::TRemoteClientSession;
+ friend class ::NBus::NPrivate::TRemoteConnection;
+ friend class ::NBus::NPrivate::TRemoteClientConnection;
+ friend class ::NBus::NPrivate::TRemoteServerConnection;
+ friend struct ::NBus::NPrivate::TBusMessagePtrAndHeader;
+
+ private:
+ ui32 LocalFlags;
+
+ /// connection identity for reply set by PushMessage()
+ NPrivate::TBusSocketAddr ReplyTo;
+ // server-side response only, hack
+ ui32 RequestSize;
+
+ TInstant RecvTime;
+
+ public:
+ /// constructor to create messages on sending end
+ TBusMessage(ui16 type, int approxsize = sizeof(TBusHeader));
+
+ /// constructor with serialzed data to examine the header
+ TBusMessage(ECreateUninitialized);
+
+ // slow, for diagnostics only
+ virtual TString Describe() const;
+
+ // must be called if this message object needs to be reused
+ void Reset();
+
+ void CheckClean() const;
+
+ void SetCompressed(bool);
+ void SetCompressedResponse(bool);
+
+ private:
+ bool IsCompressed() const {
+ return FlagsInternal & MESSAGE_COMPRESS_INTERNAL;
+ }
+ bool IsCompressedResponse() const {
+ return FlagsInternal & MESSAGE_COMPRESS_RESPONSE;
+ }
+
+ public:
+ /// can have private data to destroy
+ virtual ~TBusMessage();
+
+ /// returns header of the message
+ TBusHeader* GetHeader() {
+ return this;
+ }
+ const TBusHeader* GetHeader() const {
+ return this;
+ }
+
+ /// helper to return type for protocol object to unpack object
+ static ui16 GetType(TArrayRef<const char> data) {
+ return TBusHeader(data).Type;
+ }
+
+ /// returns payload data
+ static TArrayRef<const char> GetPayload(TArrayRef<const char> data) {
+ return data.Slice(sizeof(TBusHeader));
+ }
+
+ private:
+ void DoReset();
+
+ /// serialize message identity to be used to construct reply message
+ void GetIdentity(TBusIdentity& ident) const;
+
+ /// set message identity from serialized form
+ void SetIdentity(const TBusIdentity& ident);
+
+ public:
+ TNetAddr GetReplyTo() const {
+ return ReplyTo.ToNetAddr();
+ }
+
+ /// store of application specific data, never serialized into wire
+ void* Data;
+ };
+
+ class TBusMessageAutoPtr: public TAutoPtr<TBusMessage> {
+ public:
+ TBusMessageAutoPtr() {
+ }
+
+ TBusMessageAutoPtr(TBusMessage* message)
+ : TAutoPtr<TBusMessage>(message)
+ {
+ }
+
+ template <typename T1>
+ TBusMessageAutoPtr(const TAutoPtr<T1>& that)
+ : TAutoPtr<TBusMessage>(that.Release())
+ {
+ }
+ };
+
+}
diff --git a/library/cpp/messagebus/message_counter.cpp b/library/cpp/messagebus/message_counter.cpp
new file mode 100644
index 0000000000..04d9343f6a
--- /dev/null
+++ b/library/cpp/messagebus/message_counter.cpp
@@ -0,0 +1,46 @@
+#include "message_counter.h"
+
+#include <util/stream/str.h>
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+TMessageCounter::TMessageCounter()
+ : BytesData(0)
+ , BytesNetwork(0)
+ , Count(0)
+ , CountCompressed(0)
+ , CountCompressionRequests(0)
+{
+}
+
+TMessageCounter& TMessageCounter::operator+=(const TMessageCounter& that) {
+ BytesData += that.BytesData;
+ BytesNetwork += that.BytesNetwork;
+ Count += that.Count;
+ CountCompressed += that.CountCompressed;
+ CountCompressionRequests += that.CountCompressionRequests;
+ return *this;
+}
+
+TString TMessageCounter::ToString(bool reader) const {
+ if (reader) {
+ Y_ASSERT(CountCompressionRequests == 0);
+ }
+
+ TStringStream readValue;
+ readValue << Count;
+ if (CountCompressionRequests != 0 || CountCompressed != 0) {
+ readValue << " (" << CountCompressed << " compr";
+ if (!reader) {
+ readValue << ", " << CountCompressionRequests << " compr reqs";
+ }
+ readValue << ")";
+ }
+ readValue << ", ";
+ readValue << BytesData << "b";
+ if (BytesNetwork != BytesData) {
+ readValue << " (" << BytesNetwork << "b network)";
+ }
+ return readValue.Str();
+}
diff --git a/library/cpp/messagebus/message_counter.h b/library/cpp/messagebus/message_counter.h
new file mode 100644
index 0000000000..e4be1180b0
--- /dev/null
+++ b/library/cpp/messagebus/message_counter.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <util/generic/string.h>
+
+#include <cstddef>
+
+namespace NBus {
+ namespace NPrivate {
+ struct TMessageCounter {
+ size_t BytesData;
+ size_t BytesNetwork;
+ size_t Count;
+ size_t CountCompressed;
+ size_t CountCompressionRequests; // reader only
+
+ void AddMessage(size_t bytesData, size_t bytesCompressed, bool Compressed, bool compressionRequested) {
+ BytesData += bytesData;
+ BytesNetwork += bytesCompressed;
+ Count += 1;
+ if (Compressed) {
+ CountCompressed += 1;
+ }
+ if (compressionRequested) {
+ CountCompressionRequests += 1;
+ }
+ }
+
+ TMessageCounter& operator+=(const TMessageCounter& that);
+
+ TString ToString(bool reader) const;
+
+ TMessageCounter();
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/message_ptr_and_header.h b/library/cpp/messagebus/message_ptr_and_header.h
new file mode 100644
index 0000000000..9b4e2fd270
--- /dev/null
+++ b/library/cpp/messagebus/message_ptr_and_header.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include "message.h"
+#include "nondestroying_holder.h"
+
+#include <util/generic/noncopyable.h>
+#include <util/generic/utility.h>
+
+namespace NBus {
+ namespace NPrivate {
+ struct TBusMessagePtrAndHeader : TNonCopyable {
+ TNonDestroyingHolder<TBusMessage> MessagePtr;
+ TBusHeader Header;
+ ui32 LocalFlags;
+
+ TBusMessagePtrAndHeader()
+ : LocalFlags()
+ {
+ }
+
+ explicit TBusMessagePtrAndHeader(TBusMessage* messagePtr)
+ : MessagePtr(messagePtr)
+ , Header(*MessagePtr->GetHeader())
+ , LocalFlags(MessagePtr->LocalFlags)
+ {
+ }
+
+ void Swap(TBusMessagePtrAndHeader& that) {
+ DoSwap(MessagePtr, that.MessagePtr);
+ DoSwap(Header, that.Header);
+ DoSwap(LocalFlags, that.LocalFlags);
+ }
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/message_status.cpp b/library/cpp/messagebus/message_status.cpp
new file mode 100644
index 0000000000..41ad62b73f
--- /dev/null
+++ b/library/cpp/messagebus/message_status.cpp
@@ -0,0 +1,13 @@
+#include "message_status.h"
+
+using namespace NBus;
+
+const char* NBus::MessageStatusDescription(EMessageStatus messageStatus) {
+#define MESSAGE_STATUS_DESCRIPTION_GEN(name, description, ...) \
+ if (messageStatus == name) \
+ return description;
+
+ MESSAGE_STATUS_MAP(MESSAGE_STATUS_DESCRIPTION_GEN)
+
+ return "Unknown";
+}
diff --git a/library/cpp/messagebus/message_status.h b/library/cpp/messagebus/message_status.h
new file mode 100644
index 0000000000..e1878960b3
--- /dev/null
+++ b/library/cpp/messagebus/message_status.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#include "codegen.h"
+#include "defs.h"
+
+#include <library/cpp/deprecated/enum_codegen/enum_codegen.h>
+
+namespace NBus {
+////////////////////////////////////////////////////////////////
+/// \brief Status of message communication
+
+#define MESSAGE_STATUS_MAP(XX) \
+ XX(MESSAGE_OK, "OK") \
+ XX(MESSAGE_CONNECT_FAILED, "Connect failed") \
+ XX(MESSAGE_TIMEOUT, "Message timed out") \
+ XX(MESSAGE_SERVICE_UNKNOWN, "Locator hasn't found address for key") \
+ XX(MESSAGE_BUSY, "Too many messages in flight") \
+ XX(MESSAGE_UNKNOWN, "Request not found by id, usually it means that message is timed out") \
+ XX(MESSAGE_DESERIALIZE_ERROR, "Deserialize by TBusProtocol failed") \
+ XX(MESSAGE_HEADER_CORRUPTED, "Header corrupted") \
+ XX(MESSAGE_DECOMPRESS_ERROR, "Failed to decompress") \
+ XX(MESSAGE_MESSAGE_TOO_LARGE, "Message too large") \
+ XX(MESSAGE_REPLY_FAILED, "Unused by messagebus, used by other code") \
+ XX(MESSAGE_DELIVERY_FAILED, "Message delivery failed because connection is closed") \
+ XX(MESSAGE_INVALID_VERSION, "Protocol error: invalid version") \
+ XX(MESSAGE_SERVICE_TOOMANY, "Locator failed to resolve address") \
+ XX(MESSAGE_SHUTDOWN, "Failure because of either session or connection shutdown") \
+ XX(MESSAGE_DONT_ASK, "Internal error code used by modules")
+
+ enum EMessageStatus {
+ MESSAGE_STATUS_MAP(ENUM_VALUE_GEN_NO_VALUE)
+ MESSAGE_STATUS_COUNT
+ };
+
+ ENUM_TO_STRING(EMessageStatus, MESSAGE_STATUS_MAP)
+
+ const char* MessageStatusDescription(EMessageStatus);
+
+ static inline const char* GetMessageStatus(EMessageStatus status) {
+ return ToCString(status);
+ }
+
+ // For lwtrace
+ struct TMessageStatusField {
+ typedef int TStoreType;
+ typedef int TFuncParam;
+
+ static void ToString(int value, TString* out) {
+ *out = GetMessageStatus((NBus::EMessageStatus)value);
+ }
+
+ static int ToStoreType(int value) {
+ return value;
+ }
+ };
+
+} // ns
diff --git a/library/cpp/messagebus/message_status_counter.cpp b/library/cpp/messagebus/message_status_counter.cpp
new file mode 100644
index 0000000000..891c8f5bb2
--- /dev/null
+++ b/library/cpp/messagebus/message_status_counter.cpp
@@ -0,0 +1,71 @@
+#include "message_status_counter.h"
+
+#include "key_value_printer.h"
+#include "text_utils.h"
+
+#include <library/cpp/messagebus/monitoring/mon_proto.pb.h>
+
+#include <util/stream/str.h>
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+TMessageStatusCounter::TMessageStatusCounter() {
+ Zero(Counts);
+}
+
+TMessageStatusCounter& TMessageStatusCounter::operator+=(const TMessageStatusCounter& that) {
+ for (size_t i = 0; i < MESSAGE_STATUS_COUNT; ++i) {
+ Counts[i] += that.Counts[i];
+ }
+ return *this;
+}
+
+TString TMessageStatusCounter::PrintToString() const {
+ TStringStream ss;
+ TKeyValuePrinter p;
+ bool hasNonZeros = false;
+ bool hasZeros = false;
+ for (size_t i = 0; i < MESSAGE_STATUS_COUNT; ++i) {
+ if (i == MESSAGE_OK) {
+ Y_VERIFY(Counts[i] == 0);
+ continue;
+ }
+ if (Counts[i] != 0) {
+ p.AddRow(EMessageStatus(i), Counts[i]);
+ const char* description = MessageStatusDescription(EMessageStatus(i));
+ // TODO: add third column
+ Y_UNUSED(description);
+
+ hasNonZeros = true;
+ } else {
+ hasZeros = true;
+ }
+ }
+ if (!hasNonZeros) {
+ ss << "message status counts are zeros\n";
+ } else {
+ if (hasZeros) {
+ ss << "message status counts are zeros, except:\n";
+ } else {
+ ss << "message status counts:\n";
+ }
+ ss << IndentText(p.PrintToString());
+ }
+ return ss.Str();
+}
+
+void TMessageStatusCounter::FillErrorsProtobuf(TConnectionStatusMonRecord* status) const {
+ status->clear_errorcountbystatus();
+ for (size_t i = 0; i < MESSAGE_STATUS_COUNT; ++i) {
+ if (i == MESSAGE_OK) {
+ Y_VERIFY(Counts[i] == 0);
+ continue;
+ }
+ if (Counts[i] != 0) {
+ TMessageStatusRecord* description = status->add_errorcountbystatus();
+ description->SetStatus(TMessageStatusCounter::MessageStatusToProtobuf((EMessageStatus)i));
+ description->SetCount(Counts[i]);
+ }
+ }
+}
diff --git a/library/cpp/messagebus/message_status_counter.h b/library/cpp/messagebus/message_status_counter.h
new file mode 100644
index 0000000000..e8ba2fdd31
--- /dev/null
+++ b/library/cpp/messagebus/message_status_counter.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include "message_status.h"
+
+#include <library/cpp/messagebus/monitoring/mon_proto.pb.h>
+
+#include <util/generic/string.h>
+
+#include <array>
+
+namespace NBus {
+ namespace NPrivate {
+ struct TMessageStatusCounter {
+ static TMessageStatusRecord::EMessageStatus MessageStatusToProtobuf(EMessageStatus status) {
+ return (TMessageStatusRecord::EMessageStatus)status;
+ }
+
+ std::array<unsigned, MESSAGE_STATUS_COUNT> Counts;
+
+ unsigned& operator[](EMessageStatus index) {
+ return Counts[index];
+ }
+ const unsigned& operator[](EMessageStatus index) const {
+ return Counts[index];
+ }
+
+ TMessageStatusCounter();
+
+ TMessageStatusCounter& operator+=(const TMessageStatusCounter&);
+
+ TString PrintToString() const;
+ void FillErrorsProtobuf(TConnectionStatusMonRecord*) const;
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/message_status_counter_ut.cpp b/library/cpp/messagebus/message_status_counter_ut.cpp
new file mode 100644
index 0000000000..9598651329
--- /dev/null
+++ b/library/cpp/messagebus/message_status_counter_ut.cpp
@@ -0,0 +1,23 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "message_status_counter.h"
+
+#include <library/cpp/messagebus/monitoring/mon_proto.pb.h>
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+Y_UNIT_TEST_SUITE(MessageStatusCounter) {
+ Y_UNIT_TEST(MessageStatusConversion) {
+ const ::google::protobuf::EnumDescriptor* descriptor =
+ TMessageStatusRecord_EMessageStatus_descriptor();
+
+ for (int i = 0; i < MESSAGE_STATUS_COUNT; i++) {
+ const ::google::protobuf::EnumValueDescriptor* valueDescriptor =
+ descriptor->FindValueByName(ToString((EMessageStatus)i));
+ UNIT_ASSERT_UNEQUAL(valueDescriptor, nullptr);
+ UNIT_ASSERT_EQUAL(valueDescriptor->number(), i);
+ }
+ UNIT_ASSERT_EQUAL(MESSAGE_STATUS_COUNT, descriptor->value_count());
+ }
+}
diff --git a/library/cpp/messagebus/messqueue.cpp b/library/cpp/messagebus/messqueue.cpp
new file mode 100644
index 0000000000..3474d62705
--- /dev/null
+++ b/library/cpp/messagebus/messqueue.cpp
@@ -0,0 +1,198 @@
+#include "key_value_printer.h"
+#include "mb_lwtrace.h"
+#include "remote_client_session.h"
+#include "remote_server_session.h"
+#include "ybus.h"
+
+#include <util/generic/singleton.h>
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+using namespace NActor;
+
+TBusMessageQueuePtr NBus::CreateMessageQueue(const TBusQueueConfig& config, TExecutorPtr executor, TBusLocator* locator, const char* name) {
+ return new TBusMessageQueue(config, executor, locator, name);
+}
+
+TBusMessageQueuePtr NBus::CreateMessageQueue(const TBusQueueConfig& config, TBusLocator* locator, const char* name) {
+ TExecutor::TConfig executorConfig;
+ executorConfig.WorkerCount = config.NumWorkers;
+ executorConfig.Name = name;
+ TExecutorPtr executor = new TExecutor(executorConfig);
+ return CreateMessageQueue(config, executor, locator, name);
+}
+
+TBusMessageQueuePtr NBus::CreateMessageQueue(const TBusQueueConfig& config, const char* name) {
+ return CreateMessageQueue(config, new TBusLocator, name);
+}
+
+TBusMessageQueuePtr NBus::CreateMessageQueue(TExecutorPtr executor, const char* name) {
+ return CreateMessageQueue(TBusQueueConfig(), executor, new TBusLocator, name);
+}
+
+TBusMessageQueuePtr NBus::CreateMessageQueue(const char* name) {
+ TBusQueueConfig config;
+ return CreateMessageQueue(config, name);
+}
+
+namespace {
+ TBusQueueConfig QueueConfigFillDefaults(const TBusQueueConfig& orig, const TString& name) {
+ TBusQueueConfig patched = orig;
+ if (!patched.Name) {
+ patched.Name = name;
+ }
+ return patched;
+ }
+}
+
+TBusMessageQueue::TBusMessageQueue(const TBusQueueConfig& config, TExecutorPtr executor, TBusLocator* locator, const char* name)
+ : Config(QueueConfigFillDefaults(config, name))
+ , Locator(locator)
+ , WorkQueue(executor)
+ , Running(1)
+{
+ InitBusLwtrace();
+ InitNetworkSubSystem();
+}
+
+TBusMessageQueue::~TBusMessageQueue() {
+ Stop();
+}
+
+void TBusMessageQueue::Stop() {
+ if (!AtomicCas(&Running, 0, 1)) {
+ ShutdownComplete.WaitI();
+ return;
+ }
+
+ Scheduler.Stop();
+
+ DestroyAllSessions();
+
+ WorkQueue->Stop();
+
+ ShutdownComplete.Signal();
+}
+
+bool TBusMessageQueue::IsRunning() {
+ return AtomicGet(Running);
+}
+
+TBusMessageQueueStatus TBusMessageQueue::GetStatusRecordInternal() const {
+ TBusMessageQueueStatus r;
+ r.ExecutorStatus = WorkQueue->GetStatusRecordInternal();
+ r.Config = Config;
+ return r;
+}
+
+TString TBusMessageQueue::GetStatusSelf() const {
+ return GetStatusRecordInternal().PrintToString();
+}
+
+TString TBusMessageQueue::GetStatusSingleLine() const {
+ return WorkQueue->GetStatusSingleLine();
+}
+
+TString TBusMessageQueue::GetStatus(ui16 flags) const {
+ TStringStream ss;
+
+ ss << GetStatusSelf();
+
+ TList<TIntrusivePtr<TBusSessionImpl>> sessions;
+ {
+ TGuard<TMutex> scope(Lock);
+ sessions = Sessions;
+ }
+
+ for (TList<TIntrusivePtr<TBusSessionImpl>>::const_iterator session = sessions.begin();
+ session != sessions.end(); ++session) {
+ ss << Endl;
+ ss << (*session)->GetStatus(flags);
+ }
+
+ ss << Endl;
+ ss << "object counts (not necessarily owned by this message queue):" << Endl;
+ TKeyValuePrinter p;
+ p.AddRow("TRemoteClientConnection", TObjectCounter<TRemoteClientConnection>::ObjectCount(), false);
+ p.AddRow("TRemoteServerConnection", TObjectCounter<TRemoteServerConnection>::ObjectCount(), false);
+ p.AddRow("TRemoteClientSession", TObjectCounter<TRemoteClientSession>::ObjectCount(), false);
+ p.AddRow("TRemoteServerSession", TObjectCounter<TRemoteServerSession>::ObjectCount(), false);
+ p.AddRow("NEventLoop::TEventLoop", TObjectCounter<NEventLoop::TEventLoop>::ObjectCount(), false);
+ p.AddRow("NEventLoop::TChannel", TObjectCounter<NEventLoop::TChannel>::ObjectCount(), false);
+ ss << p.PrintToString();
+
+ return ss.Str();
+}
+
+TBusClientSessionPtr TBusMessageQueue::CreateSource(TBusProtocol* proto, IBusClientHandler* handler, const TBusClientSessionConfig& config, const TString& name) {
+ TRemoteClientSessionPtr session(new TRemoteClientSession(this, proto, handler, config, name));
+ Add(session.Get());
+ return session.Get();
+}
+
+TBusServerSessionPtr TBusMessageQueue::CreateDestination(TBusProtocol* proto, IBusServerHandler* handler, const TBusClientSessionConfig& config, const TString& name) {
+ TRemoteServerSessionPtr session(new TRemoteServerSession(this, proto, handler, config, name));
+ try {
+ int port = config.ListenPort;
+ if (port == 0) {
+ port = Locator->GetLocalPort(proto->GetService());
+ }
+ if (port == 0) {
+ port = proto->GetPort();
+ }
+
+ session->Listen(port, this);
+
+ Add(session.Get());
+ return session.Release();
+ } catch (...) {
+ Y_FAIL("create destination failure: %s", CurrentExceptionMessage().c_str());
+ }
+}
+
+TBusServerSessionPtr TBusMessageQueue::CreateDestination(TBusProtocol* proto, IBusServerHandler* handler, const TBusServerSessionConfig& config, const TVector<TBindResult>& bindTo, const TString& name) {
+ TRemoteServerSessionPtr session(new TRemoteServerSession(this, proto, handler, config, name));
+ try {
+ session->Listen(bindTo, this);
+ Add(session.Get());
+ return session.Release();
+ } catch (...) {
+ Y_FAIL("create destination failure: %s", CurrentExceptionMessage().c_str());
+ }
+}
+
+void TBusMessageQueue::Add(TIntrusivePtr<TBusSessionImpl> session) {
+ TGuard<TMutex> scope(Lock);
+ Sessions.push_back(session);
+}
+
+void TBusMessageQueue::Remove(TBusSession* session) {
+ TGuard<TMutex> scope(Lock);
+ TList<TIntrusivePtr<TBusSessionImpl>>::iterator it = std::find(Sessions.begin(), Sessions.end(), session);
+ Y_VERIFY(it != Sessions.end(), "do not destroy session twice");
+ Sessions.erase(it);
+}
+
+void TBusMessageQueue::Destroy(TBusSession* session) {
+ session->Shutdown();
+}
+
+void TBusMessageQueue::DestroyAllSessions() {
+ TList<TIntrusivePtr<TBusSessionImpl>> sessions;
+ {
+ TGuard<TMutex> scope(Lock);
+ sessions = Sessions;
+ }
+
+ for (auto& session : sessions) {
+ Y_VERIFY(session->IsDown(), "Session must be shut down prior to queue shutdown");
+ }
+}
+
+void TBusMessageQueue::Schedule(IScheduleItemAutoPtr i) {
+ Scheduler.Schedule(i);
+}
+
+TString TBusMessageQueue::GetNameInternal() const {
+ return Config.Name;
+}
diff --git a/library/cpp/messagebus/misc/atomic_box.h b/library/cpp/messagebus/misc/atomic_box.h
new file mode 100644
index 0000000000..401621f933
--- /dev/null
+++ b/library/cpp/messagebus/misc/atomic_box.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <util/system/atomic.h>
+
+// TAtomic with human interface
+template <typename T>
+class TAtomicBox {
+private:
+ union {
+ TAtomic Value;
+ // when T is enum, it is convenient to inspect its content in gdb
+ T ValueForDebugger;
+ };
+
+ static_assert(sizeof(T) <= sizeof(TAtomic), "expect sizeof(T) <= sizeof(TAtomic)");
+
+public:
+ TAtomicBox(T value = T())
+ : Value(value)
+ {
+ }
+
+ void Set(T value) {
+ AtomicSet(Value, (TAtomic)value);
+ }
+
+ T Get() const {
+ return (T)AtomicGet(Value);
+ }
+
+ bool CompareAndSet(T expected, T set) {
+ return AtomicCas(&Value, (TAtomicBase)set, (TAtomicBase)expected);
+ }
+};
diff --git a/library/cpp/messagebus/misc/granup.h b/library/cpp/messagebus/misc/granup.h
new file mode 100644
index 0000000000..36ecfebc93
--- /dev/null
+++ b/library/cpp/messagebus/misc/granup.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <util/datetime/base.h>
+#include <util/system/guard.h>
+#include <util/system/mutex.h>
+#include <util/system/spinlock.h>
+
+namespace NBus {
+ template <typename TItem, typename TLocker = TSpinLock>
+ class TGranUp {
+ public:
+ TGranUp(TDuration gran)
+ : Gran(gran)
+ , Next(TInstant::MicroSeconds(0))
+ {
+ }
+
+ template <typename TFunctor>
+ void Update(TFunctor functor, TInstant now, bool force = false) {
+ if (force || now > Next)
+ Set(functor(), now);
+ }
+
+ void Update(const TItem& item, TInstant now, bool force = false) {
+ if (force || now > Next)
+ Set(item, now);
+ }
+
+ TItem Get() const noexcept {
+ TGuard<TLocker> guard(Lock);
+
+ return Item;
+ }
+
+ protected:
+ void Set(const TItem& item, TInstant now) {
+ TGuard<TLocker> guard(Lock);
+
+ Item = item;
+
+ Next = now + Gran;
+ }
+
+ private:
+ const TDuration Gran;
+ TLocker Lock;
+ TItem Item;
+ TInstant Next;
+ };
+}
diff --git a/library/cpp/messagebus/misc/test_sync.h b/library/cpp/messagebus/misc/test_sync.h
new file mode 100644
index 0000000000..be3f4f20b8
--- /dev/null
+++ b/library/cpp/messagebus/misc/test_sync.h
@@ -0,0 +1,75 @@
+#pragma once
+
+#include <util/system/condvar.h>
+#include <util/system/mutex.h>
+
+class TTestSync {
+private:
+ unsigned Current;
+
+ TMutex Mutex;
+ TCondVar CondVar;
+
+public:
+ TTestSync()
+ : Current(0)
+ {
+ }
+
+ void Inc() {
+ TGuard<TMutex> guard(Mutex);
+
+ DoInc();
+ CondVar.BroadCast();
+ }
+
+ unsigned Get() {
+ TGuard<TMutex> guard(Mutex);
+
+ return Current;
+ }
+
+ void WaitFor(unsigned n) {
+ TGuard<TMutex> guard(Mutex);
+
+ Y_VERIFY(Current <= n, "too late, waiting for %d, already %d", n, Current);
+
+ while (n > Current) {
+ CondVar.WaitI(Mutex);
+ }
+ }
+
+ void WaitForAndIncrement(unsigned n) {
+ TGuard<TMutex> guard(Mutex);
+
+ Y_VERIFY(Current <= n, "too late, waiting for %d, already %d", n, Current);
+
+ while (n > Current) {
+ CondVar.WaitI(Mutex);
+ }
+
+ DoInc();
+ CondVar.BroadCast();
+ }
+
+ void CheckAndIncrement(unsigned n) {
+ TGuard<TMutex> guard(Mutex);
+
+ Y_VERIFY(Current == n, "must be %d, currently %d", n, Current);
+
+ DoInc();
+ CondVar.BroadCast();
+ }
+
+ void Check(unsigned n) {
+ TGuard<TMutex> guard(Mutex);
+
+ Y_VERIFY(Current == n, "must be %d, currently %d", n, Current);
+ }
+
+private:
+ void DoInc() {
+ unsigned r = ++Current;
+ Y_UNUSED(r);
+ }
+};
diff --git a/library/cpp/messagebus/misc/tokenquota.h b/library/cpp/messagebus/misc/tokenquota.h
new file mode 100644
index 0000000000..190547fa54
--- /dev/null
+++ b/library/cpp/messagebus/misc/tokenquota.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#include <util/system/atomic.h>
+
+namespace NBus {
+ /* Consumer and feeder quota model impl.
+
+ Consumer thread only calls:
+ Acquire(), fetches tokens for usage from bucket;
+ Consume(), eats given amount of tokens, must not
+ be greater than Value() items;
+
+ Other threads (feeders) calls:
+ Return(), put used tokens back to bucket;
+ */
+
+ class TTokenQuota {
+ public:
+ TTokenQuota(bool enabled, size_t tokens, size_t wake)
+ : Enabled(tokens > 0 ? enabled : false)
+ , Acquired(0)
+ , WakeLev(wake < 1 ? Max<size_t>(1, tokens / 2) : 0)
+ , Tokens_(tokens)
+ {
+ Y_UNUSED(padd_);
+ }
+
+ bool Acquire(TAtomic level = 1, bool force = false) {
+ level = Max(TAtomicBase(level), TAtomicBase(1));
+
+ if (Enabled && (Acquired < level || force)) {
+ Acquired += AtomicSwap(&Tokens_, 0);
+ }
+
+ return !Enabled || Acquired >= level;
+ }
+
+ void Consume(size_t items) {
+ if (Enabled) {
+ Y_ASSERT(Acquired >= TAtomicBase(items));
+
+ Acquired -= items;
+ }
+ }
+
+ bool Return(size_t items_) noexcept {
+ if (!Enabled || items_ == 0)
+ return false;
+
+ const TAtomic items = items_;
+ const TAtomic value = AtomicAdd(Tokens_, items);
+
+ return (value - items < WakeLev && value >= WakeLev);
+ }
+
+ bool IsEnabled() const noexcept {
+ return Enabled;
+ }
+
+ bool IsAboveWake() const noexcept {
+ return !Enabled || (WakeLev <= AtomicGet(Tokens_));
+ }
+
+ size_t Tokens() const noexcept {
+ return Acquired + AtomicGet(Tokens_);
+ }
+
+ size_t Check(const TAtomic level) const noexcept {
+ return !Enabled || level <= Acquired;
+ }
+
+ private:
+ bool Enabled;
+ TAtomicBase Acquired;
+ const TAtomicBase WakeLev;
+ TAtomic Tokens_;
+
+ /* This padd requires for align Tokens_ member on its own
+ CPU cacheline. */
+
+ ui64 padd_;
+ };
+}
diff --git a/library/cpp/messagebus/misc/weak_ptr.h b/library/cpp/messagebus/misc/weak_ptr.h
new file mode 100644
index 0000000000..70fdeb0e2a
--- /dev/null
+++ b/library/cpp/messagebus/misc/weak_ptr.h
@@ -0,0 +1,99 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/system/mutex.h>
+
+template <typename T>
+struct TWeakPtr;
+
+template <typename TSelf>
+struct TWeakRefCounted {
+ template <typename>
+ friend struct TWeakPtr;
+
+private:
+ struct TRef: public TAtomicRefCount<TRef> {
+ TMutex Mutex;
+ TSelf* Outer;
+
+ TRef(TSelf* outer)
+ : Outer(outer)
+ {
+ }
+
+ void Release() {
+ TGuard<TMutex> g(Mutex);
+ Y_ASSERT(!!Outer);
+ Outer = nullptr;
+ }
+
+ TIntrusivePtr<TSelf> Get() {
+ TGuard<TMutex> g(Mutex);
+ Y_ASSERT(!Outer || Outer->RefCount() > 0);
+ return Outer;
+ }
+ };
+
+ TAtomicCounter Counter;
+ TIntrusivePtr<TRef> RefPtr;
+
+public:
+ TWeakRefCounted()
+ : RefPtr(new TRef(static_cast<TSelf*>(this)))
+ {
+ }
+
+ void Ref() {
+ Counter.Inc();
+ }
+
+ void UnRef() {
+ if (Counter.Dec() == 0) {
+ RefPtr->Release();
+
+ // drop is to prevent dtor from reading it
+ RefPtr.Drop();
+
+ delete static_cast<TSelf*>(this);
+ }
+ }
+
+ void DecRef() {
+ Counter.Dec();
+ }
+
+ unsigned RefCount() const {
+ return Counter.Val();
+ }
+};
+
+template <typename T>
+struct TWeakPtr {
+private:
+ typedef TIntrusivePtr<typename T::TRef> TRefPtr;
+ TRefPtr RefPtr;
+
+public:
+ TWeakPtr() {
+ }
+
+ TWeakPtr(T* t) {
+ if (!!t) {
+ RefPtr = t->RefPtr;
+ }
+ }
+
+ TWeakPtr(TIntrusivePtr<T> t) {
+ if (!!t) {
+ RefPtr = t->RefPtr;
+ }
+ }
+
+ TIntrusivePtr<T> Get() {
+ if (!RefPtr) {
+ return nullptr;
+ } else {
+ return RefPtr->Get();
+ }
+ }
+};
diff --git a/library/cpp/messagebus/misc/weak_ptr_ut.cpp b/library/cpp/messagebus/misc/weak_ptr_ut.cpp
new file mode 100644
index 0000000000..5a325278db
--- /dev/null
+++ b/library/cpp/messagebus/misc/weak_ptr_ut.cpp
@@ -0,0 +1,46 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "weak_ptr.h"
+
+Y_UNIT_TEST_SUITE(TWeakPtrTest) {
+ struct TWeakPtrTester: public TWeakRefCounted<TWeakPtrTester> {
+ int* const CounterPtr;
+
+ TWeakPtrTester(int* counterPtr)
+ : CounterPtr(counterPtr)
+ {
+ }
+ ~TWeakPtrTester() {
+ ++*CounterPtr;
+ }
+ };
+
+ Y_UNIT_TEST(Simple) {
+ int destroyCount = 0;
+
+ TIntrusivePtr<TWeakPtrTester> p(new TWeakPtrTester(&destroyCount));
+
+ UNIT_ASSERT(!!p);
+ UNIT_ASSERT_VALUES_EQUAL(1u, p->RefCount());
+
+ TWeakPtr<TWeakPtrTester> p2(p);
+
+ UNIT_ASSERT_VALUES_EQUAL(1u, p->RefCount());
+
+ {
+ TIntrusivePtr<TWeakPtrTester> p3 = p2.Get();
+ UNIT_ASSERT(!!p3);
+ UNIT_ASSERT_VALUES_EQUAL(2u, p->RefCount());
+ }
+
+ p.Drop();
+ UNIT_ASSERT_VALUES_EQUAL(1, destroyCount);
+
+ {
+ TIntrusivePtr<TWeakPtrTester> p3 = p2.Get();
+ UNIT_ASSERT(!p3);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(1, destroyCount);
+ }
+}
diff --git a/library/cpp/messagebus/monitoring/mon_proto.proto b/library/cpp/messagebus/monitoring/mon_proto.proto
new file mode 100644
index 0000000000..73b6614481
--- /dev/null
+++ b/library/cpp/messagebus/monitoring/mon_proto.proto
@@ -0,0 +1,55 @@
+import "library/cpp/monlib/encode/legacy_protobuf/protos/metric_meta.proto";
+
+package NBus;
+
+option java_package = "ru.yandex.messagebus.monitoring.proto";
+
+message TMessageStatusRecord {
+ enum EMessageStatus {
+ MESSAGE_OK = 0;
+ MESSAGE_CONNECT_FAILED = 1;
+ MESSAGE_TIMEOUT = 2;
+ MESSAGE_SERVICE_UNKNOWN = 3;
+ MESSAGE_BUSY = 4;
+ MESSAGE_UNKNOWN = 5;
+ MESSAGE_DESERIALIZE_ERROR = 6;
+ MESSAGE_HEADER_CORRUPTED = 7;
+ MESSAGE_DECOMPRESS_ERROR = 8;
+ MESSAGE_MESSAGE_TOO_LARGE = 9;
+ MESSAGE_REPLY_FAILED = 10;
+ MESSAGE_DELIVERY_FAILED = 11;
+ MESSAGE_INVALID_VERSION = 12;
+ MESSAGE_SERVICE_TOOMANY = 13;
+ MESSAGE_SHUTDOWN = 14;
+ MESSAGE_DONT_ASK = 15;
+ }
+
+ optional EMessageStatus Status = 1;
+ optional uint32 Count = 2;
+}
+
+message TConnectionStatusMonRecord {
+ optional uint32 SendQueueSize = 1 [ (NMonProto.Metric).Type = GAUGE ];
+ // client only
+ optional uint32 AckMessagesSize = 2 [ (NMonProto.Metric).Type = GAUGE ];
+ optional uint32 ErrorCount = 3 [ (NMonProto.Metric).Type = RATE ];
+
+ optional uint64 WriteBytes = 10 [ (NMonProto.Metric).Type = RATE ];
+ optional uint64 WriteBytesCompressed = 11;
+ optional uint64 WriteMessages = 12 [ (NMonProto.Metric).Type = RATE ];
+ optional uint64 WriteSyscalls = 13;
+ optional uint64 WriteActs = 14;
+ optional uint64 ReadBytes = 20 [ (NMonProto.Metric).Type = RATE ];
+ optional uint64 ReadBytesCompressed = 21;
+ optional uint64 ReadMessages = 22 [ (NMonProto.Metric).Type = RATE ];
+ optional uint64 ReadSyscalls = 23;
+ optional uint64 ReadActs = 24;
+
+ repeated TMessageStatusRecord ErrorCountByStatus = 25;
+}
+
+message TSessionStatusMonRecord {
+ optional uint32 InFlight = 1 [ (NMonProto.Metric).Type = GAUGE ];
+ optional uint32 ConnectionCount = 2 [ (NMonProto.Metric).Type = GAUGE ];
+ optional uint32 ConnectCount = 3 [ (NMonProto.Metric).Type = RATE ];
+}
diff --git a/library/cpp/messagebus/monitoring/ya.make b/library/cpp/messagebus/monitoring/ya.make
new file mode 100644
index 0000000000..25782492b1
--- /dev/null
+++ b/library/cpp/messagebus/monitoring/ya.make
@@ -0,0 +1,15 @@
+PROTO_LIBRARY()
+
+OWNER(g:messagebus)
+
+PEERDIR(
+ library/cpp/monlib/encode/legacy_protobuf/protos
+)
+
+SRCS(
+ mon_proto.proto
+)
+
+EXCLUDE_TAGS(GO_PROTO)
+
+END()
diff --git a/library/cpp/messagebus/moved.h b/library/cpp/messagebus/moved.h
new file mode 100644
index 0000000000..ede8dcd244
--- /dev/null
+++ b/library/cpp/messagebus/moved.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <util/generic/utility.h>
+
+template <typename T>
+class TMoved {
+private:
+ mutable T Value;
+
+public:
+ TMoved() {
+ }
+ TMoved(const TMoved<T>& that) {
+ DoSwap(Value, that.Value);
+ }
+ TMoved(const T& that) {
+ DoSwap(Value, const_cast<T&>(that));
+ }
+
+ void swap(TMoved& that) {
+ DoSwap(Value, that.Value);
+ }
+
+ T& operator*() {
+ return Value;
+ }
+
+ const T& operator*() const {
+ return Value;
+ }
+
+ T* operator->() {
+ return &Value;
+ }
+
+ const T* operator->() const {
+ return &Value;
+ }
+};
diff --git a/library/cpp/messagebus/moved_ut.cpp b/library/cpp/messagebus/moved_ut.cpp
new file mode 100644
index 0000000000..c1a07cce7e
--- /dev/null
+++ b/library/cpp/messagebus/moved_ut.cpp
@@ -0,0 +1,22 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "moved.h"
+
+Y_UNIT_TEST_SUITE(TMovedTest) {
+ Y_UNIT_TEST(Simple) {
+ TMoved<THolder<int>> h1(MakeHolder<int>(10));
+ TMoved<THolder<int>> h2 = h1;
+ UNIT_ASSERT(!*h1);
+ UNIT_ASSERT(!!*h2);
+ UNIT_ASSERT_VALUES_EQUAL(10, **h2);
+ }
+
+ void Foo(TMoved<THolder<int>> h) {
+ UNIT_ASSERT_VALUES_EQUAL(11, **h);
+ }
+
+ Y_UNIT_TEST(PassToFunction) {
+ THolder<int> h(new int(11));
+ Foo(h);
+ }
+}
diff --git a/library/cpp/messagebus/netaddr.h b/library/cpp/messagebus/netaddr.h
new file mode 100644
index 0000000000..f915c8c574
--- /dev/null
+++ b/library/cpp/messagebus/netaddr.h
@@ -0,0 +1,4 @@
+#pragma once
+
+#include <library/cpp/messagebus/config/netaddr.h>
+
diff --git a/library/cpp/messagebus/netaddr_ut.cpp b/library/cpp/messagebus/netaddr_ut.cpp
new file mode 100644
index 0000000000..e5c68bf402
--- /dev/null
+++ b/library/cpp/messagebus/netaddr_ut.cpp
@@ -0,0 +1,21 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "netaddr.h"
+#include "test_utils.h"
+
+using namespace NBus;
+
+Y_UNIT_TEST_SUITE(TNetAddr) {
+ Y_UNIT_TEST(ResolveIpv4) {
+ ASSUME_IP_V4_ENABLED;
+ UNIT_ASSERT(TNetAddr("ns1.yandex.ru", 80, EIP_VERSION_4).IsIpv4());
+ }
+
+ Y_UNIT_TEST(ResolveIpv6) {
+ UNIT_ASSERT(TNetAddr("ns1.yandex.ru", 80, EIP_VERSION_6).IsIpv6());
+ }
+
+ Y_UNIT_TEST(ResolveAny) {
+ TNetAddr("ns1.yandex.ru", 80, EIP_VERSION_ANY);
+ }
+}
diff --git a/library/cpp/messagebus/network.cpp b/library/cpp/messagebus/network.cpp
new file mode 100644
index 0000000000..304bedae5a
--- /dev/null
+++ b/library/cpp/messagebus/network.cpp
@@ -0,0 +1,156 @@
+#include "network.h"
+
+#include <util/generic/maybe.h>
+#include <util/generic/ptr.h>
+#include <util/network/init.h>
+#include <util/network/socket.h>
+#include <util/system/platform.h>
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+namespace {
+ TBindResult BindOnPortProto(int port, int af, bool reusePort) {
+ Y_VERIFY(af == AF_INET || af == AF_INET6, "wrong af");
+
+ SOCKET fd = ::socket(af, SOCK_STREAM, 0);
+ if (fd == INVALID_SOCKET) {
+ ythrow TSystemError() << "failed to create a socket";
+ }
+
+ int one = 1;
+ int r1 = SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, one);
+ if (r1 < 0) {
+ ythrow TSystemError() << "failed to setsockopt SO_REUSEADDR";
+ }
+
+#ifdef SO_REUSEPORT
+ if (reusePort) {
+ int r = SetSockOpt(fd, SOL_SOCKET, SO_REUSEPORT, one);
+ if (r < 0) {
+ ythrow TSystemError() << "failed to setsockopt SO_REUSEPORT";
+ }
+ }
+#else
+ Y_UNUSED(reusePort);
+#endif
+
+ THolder<TOpaqueAddr> addr(new TOpaqueAddr);
+ sockaddr* sa = addr->MutableAddr();
+ sa->sa_family = af;
+ socklen_t len;
+ if (af == AF_INET) {
+ len = sizeof(sockaddr_in);
+ ((sockaddr_in*)sa)->sin_port = HostToInet((ui16)port);
+ ((sockaddr_in*)sa)->sin_addr.s_addr = INADDR_ANY;
+ } else {
+ len = sizeof(sockaddr_in6);
+ ((sockaddr_in6*)sa)->sin6_port = HostToInet((ui16)port);
+ }
+
+ if (af == AF_INET6) {
+ FixIPv6ListenSocket(fd);
+ }
+
+ int r2 = ::bind(fd, sa, len);
+ if (r2 < 0) {
+ ythrow TSystemError() << "failed to bind on port " << port;
+ }
+
+ int rsn = ::getsockname(fd, addr->MutableAddr(), addr->LenPtr());
+ if (rsn < 0) {
+ ythrow TSystemError() << "failed to getsockname";
+ }
+
+ int r3 = ::listen(fd, 50);
+ if (r3 < 0) {
+ ythrow TSystemError() << "listen failed";
+ }
+
+ TBindResult r;
+ r.Socket.Reset(new TSocketHolder(fd));
+ r.Addr = TNetAddr(addr.Release());
+ return r;
+ }
+
+ TMaybe<TBindResult> TryBindOnPortProto(int port, int af, bool reusePort) {
+ try {
+ return {BindOnPortProto(port, af, reusePort)};
+ } catch (const TSystemError&) {
+ return {};
+ }
+ }
+
+ std::pair<unsigned, TVector<TBindResult>> AggregateBindResults(TBindResult&& r1, TBindResult&& r2) {
+ Y_VERIFY(r1.Addr.GetPort() == r2.Addr.GetPort(), "internal");
+ std::pair<unsigned, TVector<TBindResult>> r;
+ r.second.reserve(2);
+
+ r.first = r1.Addr.GetPort();
+ r.second.emplace_back(std::move(r1));
+ r.second.emplace_back(std::move(r2));
+ return r;
+ }
+}
+
+std::pair<unsigned, TVector<TBindResult>> NBus::BindOnPort(int port, bool reusePort) {
+ std::pair<unsigned, TVector<TBindResult>> r;
+ r.second.reserve(2);
+
+ if (port != 0) {
+ return AggregateBindResults(BindOnPortProto(port, AF_INET, reusePort),
+ BindOnPortProto(port, AF_INET6, reusePort));
+ }
+
+ // use nothrow versions in cycle
+ for (int i = 0; i < 1000; ++i) {
+ TMaybe<TBindResult> in4 = TryBindOnPortProto(0, AF_INET, reusePort);
+ if (!in4) {
+ continue;
+ }
+
+ TMaybe<TBindResult> in6 = TryBindOnPortProto(in4->Addr.GetPort(), AF_INET6, reusePort);
+ if (!in6) {
+ continue;
+ }
+
+ return AggregateBindResults(std::move(*in4), std::move(*in6));
+ }
+
+ TBindResult in4 = BindOnPortProto(0, AF_INET, reusePort);
+ TBindResult in6 = BindOnPortProto(in4.Addr.GetPort(), AF_INET6, reusePort);
+ return AggregateBindResults(std::move(in4), std::move(in6));
+}
+
+void NBus::NPrivate::SetSockOptTcpCork(SOCKET s, bool value) {
+#ifdef _linux_
+ CheckedSetSockOpt(s, IPPROTO_TCP, TCP_CORK, (int)value, "TCP_CORK");
+#else
+ Y_UNUSED(s);
+ Y_UNUSED(value);
+#endif
+}
+
+ssize_t NBus::NPrivate::SocketSend(SOCKET s, TArrayRef<const char> data) {
+ int flags = 0;
+#if defined(_linux_) || defined(_freebsd_)
+ flags |= MSG_NOSIGNAL;
+#endif
+ ssize_t r = ::send(s, data.data(), data.size(), flags);
+ if (r < 0) {
+ Y_VERIFY(LastSystemError() != EBADF, "bad fd");
+ }
+ return r;
+}
+
+ssize_t NBus::NPrivate::SocketRecv(SOCKET s, TArrayRef<char> buffer) {
+ int flags = 0;
+#if defined(_linux_) || defined(_freebsd_)
+ flags |= MSG_NOSIGNAL;
+#endif
+ ssize_t r = ::recv(s, buffer.data(), buffer.size(), flags);
+ if (r < 0) {
+ Y_VERIFY(LastSystemError() != EBADF, "bad fd");
+ }
+ return r;
+}
diff --git a/library/cpp/messagebus/network.h b/library/cpp/messagebus/network.h
new file mode 100644
index 0000000000..cc4bd76ea3
--- /dev/null
+++ b/library/cpp/messagebus/network.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "netaddr.h"
+
+#include <util/generic/array_ref.h>
+#include <util/generic/ptr.h>
+#include <util/network/socket.h>
+
+#include <utility>
+
+namespace NBus {
+ namespace NPrivate {
+ void SetSockOptTcpCork(SOCKET s, bool value);
+
+ [[nodiscard]] ssize_t SocketSend(SOCKET s, TArrayRef<const char> data);
+
+ [[nodiscard]] ssize_t SocketRecv(SOCKET s, TArrayRef<char> buffer);
+
+ }
+
+ struct TBindResult {
+ TSimpleSharedPtr<TSocketHolder> Socket;
+ TNetAddr Addr;
+ };
+
+ std::pair<unsigned, TVector<TBindResult>> BindOnPort(int port, bool reusePort);
+
+}
diff --git a/library/cpp/messagebus/network_ut.cpp b/library/cpp/messagebus/network_ut.cpp
new file mode 100644
index 0000000000..f1798419db
--- /dev/null
+++ b/library/cpp/messagebus/network_ut.cpp
@@ -0,0 +1,65 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "network.h"
+
+#include <library/cpp/messagebus/test/helper/fixed_port.h>
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+using namespace NBus::NTest;
+
+namespace {
+ int GetSockPort(SOCKET socket) {
+ sockaddr_storage addr;
+ Zero(addr);
+
+ socklen_t len = sizeof(addr);
+
+ int r = ::getsockname(socket, (sockaddr*)&addr, &len);
+ UNIT_ASSERT(r >= 0);
+
+ if (addr.ss_family == AF_INET) {
+ sockaddr_in* addr_in = (sockaddr_in*)&addr;
+ return InetToHost(addr_in->sin_port);
+ } else if (addr.ss_family == AF_INET6) {
+ sockaddr_in6* addr_in6 = (sockaddr_in6*)&addr;
+ return InetToHost(addr_in6->sin6_port);
+ } else {
+ UNIT_FAIL("unknown AF");
+ throw 1;
+ }
+ }
+}
+
+Y_UNIT_TEST_SUITE(Network) {
+ Y_UNIT_TEST(BindOnPortConcrete) {
+ if (!IsFixedPortTestAllowed()) {
+ return;
+ }
+
+ TVector<TBindResult> r = BindOnPort(FixedPort, false).second;
+ UNIT_ASSERT_VALUES_EQUAL(size_t(2), r.size());
+
+ for (TVector<TBindResult>::iterator i = r.begin(); i != r.end(); ++i) {
+ UNIT_ASSERT_VALUES_EQUAL(i->Addr.GetPort(), GetSockPort(i->Socket->operator SOCKET()));
+ }
+ }
+
+ Y_UNIT_TEST(BindOnPortRandom) {
+ TVector<TBindResult> r = BindOnPort(0, false).second;
+ UNIT_ASSERT_VALUES_EQUAL(size_t(2), r.size());
+
+ for (TVector<TBindResult>::iterator i = r.begin(); i != r.end(); ++i) {
+ UNIT_ASSERT_VALUES_EQUAL(i->Addr.GetPort(), GetSockPort(i->Socket->operator SOCKET()));
+ UNIT_ASSERT(i->Addr.GetPort() > 0);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(r.at(0).Addr.GetPort(), r.at(1).Addr.GetPort());
+ }
+
+ Y_UNIT_TEST(BindOnBusyPort) {
+ auto r = BindOnPort(0, false);
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(BindOnPort(r.first, false), TSystemError, "failed to bind on port " + ToString(r.first));
+ }
+}
diff --git a/library/cpp/messagebus/nondestroying_holder.h b/library/cpp/messagebus/nondestroying_holder.h
new file mode 100644
index 0000000000..f4725d696f
--- /dev/null
+++ b/library/cpp/messagebus/nondestroying_holder.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+
+template <typename T>
+class TNonDestroyingHolder: public THolder<T> {
+public:
+ TNonDestroyingHolder(T* t = nullptr) noexcept
+ : THolder<T>(t)
+ {
+ }
+
+ TNonDestroyingHolder(TAutoPtr<T> t) noexcept
+ : THolder<T>(t)
+ {
+ }
+
+ ~TNonDestroyingHolder() {
+ Y_VERIFY(!*this, "stored object must be explicitly released");
+ }
+};
+
+template <class T>
+class TNonDestroyingAutoPtr: public TAutoPtr<T> {
+public:
+ inline TNonDestroyingAutoPtr(T* t = 0) noexcept
+ : TAutoPtr<T>(t)
+ {
+ }
+
+ inline TNonDestroyingAutoPtr(const TAutoPtr<T>& t) noexcept
+ : TAutoPtr<T>(t.Release())
+ {
+ }
+
+ inline ~TNonDestroyingAutoPtr() {
+ Y_VERIFY(!*this, "stored object must be explicitly released");
+ }
+};
diff --git a/library/cpp/messagebus/nondestroying_holder_ut.cpp b/library/cpp/messagebus/nondestroying_holder_ut.cpp
new file mode 100644
index 0000000000..208042a2ba
--- /dev/null
+++ b/library/cpp/messagebus/nondestroying_holder_ut.cpp
@@ -0,0 +1,12 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "nondestroying_holder.h"
+
+Y_UNIT_TEST_SUITE(TNonDestroyingHolder) {
+ Y_UNIT_TEST(ToAutoPtr) {
+ TNonDestroyingHolder<int> h(new int(11));
+ TAutoPtr<int> i(h);
+ UNIT_ASSERT_VALUES_EQUAL(11, *i);
+ UNIT_ASSERT(!h);
+ }
+}
diff --git a/library/cpp/messagebus/oldmodule/module.cpp b/library/cpp/messagebus/oldmodule/module.cpp
new file mode 100644
index 0000000000..24bd778799
--- /dev/null
+++ b/library/cpp/messagebus/oldmodule/module.cpp
@@ -0,0 +1,881 @@
+#include "module.h"
+
+#include <library/cpp/messagebus/scheduler_actor.h>
+#include <library/cpp/messagebus/thread_extra.h>
+#include <library/cpp/messagebus/actor/actor.h>
+#include <library/cpp/messagebus/actor/queue_in_actor.h>
+#include <library/cpp/messagebus/actor/what_thread_does.h>
+#include <library/cpp/messagebus/actor/what_thread_does_guard.h>
+
+#include <util/generic/singleton.h>
+#include <util/string/printf.h>
+#include <util/system/event.h>
+
+using namespace NActor;
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+namespace {
+ Y_POD_STATIC_THREAD(TBusJob*)
+ ThreadCurrentJob;
+
+ struct TThreadCurrentJobGuard {
+ TBusJob* Prev;
+
+ TThreadCurrentJobGuard(TBusJob* job)
+ : Prev(ThreadCurrentJob)
+ {
+ Y_ASSERT(!ThreadCurrentJob || ThreadCurrentJob == job);
+ ThreadCurrentJob = job;
+ }
+ ~TThreadCurrentJobGuard() {
+ ThreadCurrentJob = Prev;
+ }
+ };
+
+ void ClearState(NBus::TJobState* state) {
+ /// skip sendbacks handlers
+ if (state->Message != state->Reply) {
+ if (state->Message) {
+ delete state->Message;
+ state->Message = nullptr;
+ }
+
+ if (state->Reply) {
+ delete state->Reply;
+ state->Reply = nullptr;
+ }
+ }
+ }
+
+ void ClearJobStateVector(NBus::TJobStateVec* vec) {
+ Y_ASSERT(vec);
+
+ for (auto& call : *vec) {
+ ClearState(&call);
+ }
+
+ vec->clear();
+ }
+
+}
+
+namespace NBus {
+ namespace NPrivate {
+ class TJobStorage {
+ };
+
+ struct TModuleClientHandler
+ : public IBusClientHandler {
+ TModuleClientHandler(TBusModuleImpl* module)
+ : Module(module)
+ {
+ }
+
+ void OnReply(TAutoPtr<TBusMessage> req, TAutoPtr<TBusMessage> reply) override;
+ void OnMessageSentOneWay(TAutoPtr<TBusMessage> pMessage) override;
+ void OnError(TAutoPtr<TBusMessage> msg, EMessageStatus status) override;
+ void OnClientConnectionEvent(const TClientConnectionEvent& event) override;
+
+ TBusModuleImpl* const Module;
+ };
+
+ struct TModuleServerHandler
+ : public IBusServerHandler {
+ TModuleServerHandler(TBusModuleImpl* module)
+ : Module(module)
+ {
+ }
+
+ void OnMessage(TOnMessageContext& msg) override;
+
+ TBusModuleImpl* const Module;
+ };
+
+ struct TBusModuleImpl: public TBusModuleInternal {
+ TBusModule* const Module;
+
+ TBusMessageQueue* Queue;
+
+ TScheduler Scheduler;
+
+ const char* const Name;
+
+ typedef TList<TJobRunner*> TBusJobList;
+ /// jobs currently in-flight on this module
+ TBusJobList Jobs;
+ /// module level mutex
+ TMutex Lock;
+ TCondVar ShutdownCondVar;
+ TAtomic JobCount;
+
+ enum EState {
+ CREATED,
+ RUNNING,
+ STOPPED,
+ };
+
+ TAtomic State;
+ TBusModuleConfig ModuleConfig;
+ TBusServerSessionPtr ExternalSession;
+ /// protocol for local proxy session
+ THolder<IBusClientHandler> ModuleClientHandler;
+ THolder<IBusServerHandler> ModuleServerHandler;
+ TVector<TSimpleSharedPtr<TBusStarter>> Starters;
+
+ // Sessions must be destroyed before
+ // ModuleClientHandler / ModuleServerHandler
+ TVector<TBusClientSessionPtr> ClientSessions;
+ TVector<TBusServerSessionPtr> ServerSessions;
+
+ TBusModuleImpl(TBusModule* module, const char* name)
+ : Module(module)
+ , Queue()
+ , Name(name)
+ , JobCount(0)
+ , State(CREATED)
+ , ExternalSession(nullptr)
+ , ModuleClientHandler(new TModuleClientHandler(this))
+ , ModuleServerHandler(new TModuleServerHandler(this))
+ {
+ }
+
+ ~TBusModuleImpl() override {
+ // Shutdown cannot be called from destructor,
+ // because module has virtual methods.
+ Y_VERIFY(State != RUNNING, "if running, must explicitly call Shutdown() before destructor");
+
+ Scheduler.Stop();
+
+ while (!Jobs.empty()) {
+ DestroyJob(Jobs.front());
+ }
+ Y_VERIFY(JobCount == 0, "state check");
+ }
+
+ void OnMessageReceived(TAutoPtr<TBusMessage> msg, TOnMessageContext&);
+
+ void AddJob(TJobRunner* jobRunner);
+
+ void DestroyJob(TJobRunner* job);
+
+ /// terminate job on this message
+ void CancelJob(TBusJob* job, EMessageStatus status);
+ /// prints statuses of jobs
+ TString GetStatus(unsigned flags);
+
+ size_t Size() const {
+ return AtomicGet(JobCount);
+ }
+
+ void Shutdown();
+
+ TVector<TBusClientSessionPtr> GetClientSessionsInternal() override {
+ return ClientSessions;
+ }
+
+ TVector<TBusServerSessionPtr> GetServerSessionsInternal() override {
+ return ServerSessions;
+ }
+
+ TBusMessageQueue* GetQueue() override {
+ return Queue;
+ }
+
+ TString GetNameInternal() override {
+ return Name;
+ }
+
+ TString GetStatusSingleLine() override {
+ TStringStream ss;
+ ss << "jobs: " << Size();
+ return ss.Str();
+ }
+
+ void OnClientConnectionEvent(const TClientConnectionEvent& event) {
+ Module->OnClientConnectionEvent(event);
+ }
+ };
+
+ struct TJobResponseMessage {
+ TBusMessage* Request;
+ TBusMessage* Response;
+ EMessageStatus Status;
+
+ TJobResponseMessage(TBusMessage* request, TBusMessage* response, EMessageStatus status)
+ : Request(request)
+ , Response(response)
+ , Status(status)
+ {
+ }
+ };
+
+ struct TJobRunner: public TAtomicRefCount<TJobRunner>,
+ public NActor::TActor<TJobRunner>,
+ public NActor::TQueueInActor<TJobRunner, TJobResponseMessage>,
+ public TScheduleActor<TJobRunner> {
+ THolder<TBusJob> Job;
+
+ TList<TJobRunner*>::iterator JobStorageIterator;
+
+ TJobRunner(TAutoPtr<TBusJob> job)
+ : NActor::TActor<TJobRunner>(job->ModuleImpl->Queue->GetExecutor())
+ , TScheduleActor<TJobRunner>(&job->ModuleImpl->Scheduler)
+ , Job(job.Release())
+ , JobStorageIterator()
+ {
+ Job->Runner = this;
+ }
+
+ ~TJobRunner() override {
+ Y_ASSERT(JobStorageIterator == TList<TJobRunner*>::iterator());
+ }
+
+ void ProcessItem(NActor::TDefaultTag, NActor::TDefaultTag, const TJobResponseMessage& message) {
+ Job->CallReplyHandler(message.Status, message.Request, message.Response);
+ }
+
+ void Destroy() {
+ if (!!Job->OnMessageContext) {
+ if (!Job->ReplySent) {
+ Job->OnMessageContext.ForgetRequest();
+ }
+ }
+ Job->ModuleImpl->DestroyJob(this);
+ }
+
+ void Act(NActor::TDefaultTag) {
+ if (JobStorageIterator == TList<TJobRunner*>::iterator()) {
+ return;
+ }
+
+ if (Job->SleepUntil != 0) {
+ if (AtomicGet(Job->ModuleImpl->State) == TBusModuleImpl::STOPPED) {
+ Destroy();
+ return;
+ }
+ }
+
+ TThreadCurrentJobGuard g(Job.Get());
+
+ NActor::TQueueInActor<TJobRunner, TJobResponseMessage>::DequeueAll();
+
+ if (Alarm.FetchTask()) {
+ if (Job->AnyPendingToSend()) {
+ Y_ASSERT(Job->SleepUntil == 0);
+ Job->SendPending();
+ if (Job->AnyPendingToSend()) {
+ }
+ } else {
+ // regular alarm
+ Y_ASSERT(Job->Pending.empty());
+ Y_ASSERT(Job->SleepUntil != 0);
+ Job->SleepUntil = 0;
+ }
+ }
+
+ for (;;) {
+ if (Job->Pending.empty() && !!Job->Handler && Job->Status == MESSAGE_OK) {
+ TWhatThreadDoesPushPop pp("do call job handler (do not confuse with reply handler)");
+
+ Job->Handler = Job->Handler(Job->Module, Job.Get(), Job->Message);
+ }
+
+ if (Job->SleepUntil != 0) {
+ ScheduleAt(TInstant::MilliSeconds(Job->SleepUntil));
+ return;
+ }
+
+ Job->SendPending();
+
+ if (Job->AnyPendingToSend()) {
+ ScheduleAt(TInstant::Now() + TDuration::Seconds(1));
+ return;
+ }
+
+ if (!Job->Pending.empty()) {
+ // waiting replies
+ return;
+ }
+
+ if (Job->IsDone()) {
+ Destroy();
+ return;
+ }
+ }
+ }
+ };
+
+ }
+
+ static inline TJobRunner* GetJob(TBusMessage* message) {
+ return (TJobRunner*)message->Data;
+ }
+
+ static inline void SetJob(TBusMessage* message, TJobRunner* job) {
+ message->Data = job;
+ }
+
+ TBusJob::TBusJob(TBusModule* module, TBusMessage* message)
+ : Status(MESSAGE_OK)
+ , Runner()
+ , Message(message)
+ , ReplySent(false)
+ , Module(module)
+ , ModuleImpl(module->Impl.Get())
+ , SleepUntil(0)
+ {
+ Handler = TJobHandler(&TBusModule::Start);
+ }
+
+ TBusJob::~TBusJob() {
+ Y_ASSERT(Pending.size() == 0);
+ //Y_ASSERT(SleepUntil == 0);
+
+ ClearAllMessageStates();
+ }
+
+ TNetAddr TBusJob::GetPeerAddrNetAddr() const {
+ Y_VERIFY(!!OnMessageContext);
+ return OnMessageContext.GetPeerAddrNetAddr();
+ }
+
+ void TBusJob::CheckThreadCurrentJob() {
+ Y_ASSERT(ThreadCurrentJob == this);
+ }
+
+ /////////////////////////////////////////////////////////
+ /// \brief Send messages in pending list
+
+ /// If at least one message is gone return true
+ /// If message has not been send, move it to Finished with appropriate error code
+ bool TBusJob::SendPending() {
+ // Iterator type must be size_t, not vector::iterator,
+ // because `DoCallReplyHandler` may call `Send` that modifies `Pending` vector,
+ // that in turn invalidates iterator.
+ // Implementation assumes that `DoCallReplyHandler` only pushes back to `Pending`
+ // (not erases, and not inserts) so iteration by index is valid.
+ size_t it = 0;
+ while (it != Pending.size()) {
+ TJobState& call = Pending[it];
+
+ if (call.Status == MESSAGE_DONT_ASK) {
+ EMessageStatus getAddressStatus = MESSAGE_OK;
+ TNetAddr addr;
+ if (call.UseAddr) {
+ addr = call.Addr;
+ } else {
+ getAddressStatus = const_cast<TBusProtocol*>(call.Session->GetProto())->GetDestination(call.Session, call.Message, call.Session->GetQueue()->GetLocator(), &addr);
+ }
+
+ if (getAddressStatus == MESSAGE_OK) {
+ // hold extra reference for each request in flight
+ Runner->Ref();
+
+ if (call.OneWay) {
+ call.Status = call.Session->SendMessageOneWay(call.Message, &addr);
+ } else {
+ call.Status = call.Session->SendMessage(call.Message, &addr);
+ }
+
+ if (call.Status != MESSAGE_OK) {
+ Runner->UnRef();
+ }
+
+ } else {
+ call.Status = getAddressStatus;
+ }
+ }
+
+ if (call.Status == MESSAGE_OK) {
+ ++it; // keep pending list until we get reply
+ } else if (call.Status == MESSAGE_BUSY) {
+ Y_FAIL("MESSAGE_BUSY is prohibited in modules. Please increase MaxInFlight");
+ } else if (call.Status == MESSAGE_CONNECT_FAILED && call.NumRetries < call.MaxRetries) {
+ ++it; // try up to call.MaxRetries times to send message
+ call.NumRetries++;
+ DoCallReplyHandler(call);
+ call.Status = MESSAGE_DONT_ASK;
+ call.Message->Reset(); // generate new Id
+ } else {
+ Finished.push_back(call);
+ DoCallReplyHandler(call);
+ Pending.erase(Pending.begin() + it);
+ }
+ }
+ return Pending.size() > 0;
+ }
+
+ bool TBusJob::AnyPendingToSend() {
+ for (unsigned i = 0; i < Pending.size(); ++i) {
+ if (Pending[i].Status == MESSAGE_DONT_ASK) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool TBusJob::IsDone() {
+ bool r = (SleepUntil == 0 && Pending.size() == 0 && (Handler == nullptr || Status != MESSAGE_OK));
+ return r;
+ }
+
+ void TBusJob::CallJobHandlerOnly() {
+ TThreadCurrentJobGuard threadCurrentJobGuard(this);
+ TWhatThreadDoesPushPop pp("do call job handler (do not confuse with reply handler)");
+
+ Handler = Handler(ModuleImpl->Module, this, Message);
+ }
+
+ bool TBusJob::CallJobHandler() {
+ /// go on as far as we can go without waiting
+ while (!IsDone()) {
+ /// call the handler
+ CallJobHandlerOnly();
+
+ /// quit if job is canceled
+ if (Status != MESSAGE_OK) {
+ break;
+ }
+
+ /// there are messages to send and wait for reply
+ SendPending();
+
+ if (!Pending.empty()) {
+ break;
+ }
+
+ /// asked to sleep
+ if (SleepUntil) {
+ break;
+ }
+ }
+
+ Y_VERIFY(!(Pending.size() == 0 && Handler == nullptr && Status == MESSAGE_OK && !ReplySent),
+ "Handler returned NULL without Cancel() or SendReply() for message=%016" PRIx64 " type=%d",
+ Message->GetHeader()->Id, Message->GetHeader()->Type);
+
+ return IsDone();
+ }
+
+ void TBusJob::DoCallReplyHandler(TJobState& call) {
+ if (call.Handler) {
+ TWhatThreadDoesPushPop pp("do call reply handler (do not confuse with job handler)");
+
+ TThreadCurrentJobGuard threadCurrentJobGuard(this);
+ (Module->*(call.Handler))(this, call.Status, call.Message, call.Reply);
+ }
+ }
+
+ int TBusJob::CallReplyHandler(EMessageStatus status, TBusMessage* mess, TBusMessage* reply) {
+ /// find handler for given message and update it's status
+ size_t i = 0;
+ for (; i < Pending.size(); ++i) {
+ TJobState& call = Pending[i];
+ if (call.Message == mess) {
+ break;
+ }
+ }
+
+ /// if not found, report error
+ if (i == Pending.size()) {
+ Y_FAIL("must not happen");
+ }
+
+ /// fill in response into job state
+ TJobState& call = Pending[i];
+ call.Status = status;
+ Y_ASSERT(call.Message == mess);
+ call.Reply = reply;
+
+ if ((status == MESSAGE_TIMEOUT || status == MESSAGE_DELIVERY_FAILED) && call.NumRetries < call.MaxRetries) {
+ call.NumRetries++;
+ call.Status = MESSAGE_DONT_ASK;
+ call.Message->Reset(); // generate new Id
+ DoCallReplyHandler(call);
+ return 0;
+ }
+
+ /// call the handler if provided
+ DoCallReplyHandler(call);
+
+ /// move job state into the finished stack
+ Finished.push_back(Pending[i]);
+ Pending.erase(Pending.begin() + i);
+
+ return 0;
+ }
+
+ ///////////////////////////////////////////////////////////////
+ /// send message to any other session or application
+ void TBusJob::Send(TBusMessageAutoPtr mess, TBusClientSession* session, TReplyHandler rhandler, size_t maxRetries) {
+ CheckThreadCurrentJob();
+
+ SetJob(mess.Get(), Runner);
+ Pending.push_back(TJobState(rhandler, MESSAGE_DONT_ASK, mess.Release(), session, nullptr, maxRetries, nullptr, false));
+ }
+
+ void TBusJob::Send(TBusMessageAutoPtr mess, TBusClientSession* session, TReplyHandler rhandler, size_t maxRetries, const TNetAddr& addr) {
+ CheckThreadCurrentJob();
+
+ SetJob(mess.Get(), Runner);
+ Pending.push_back(TJobState(rhandler, MESSAGE_DONT_ASK, mess.Release(), session, nullptr, maxRetries, &addr, false));
+ }
+
+ void TBusJob::SendOneWayTo(TBusMessageAutoPtr req, TBusClientSession* session, const TNetAddr& addr) {
+ CheckThreadCurrentJob();
+
+ SetJob(req.Get(), Runner);
+ Pending.push_back(TJobState(nullptr, MESSAGE_DONT_ASK, req.Release(), session, nullptr, 0, &addr, true));
+ }
+
+ void TBusJob::SendOneWayWithLocator(TBusMessageAutoPtr req, TBusClientSession* session) {
+ CheckThreadCurrentJob();
+
+ SetJob(req.Get(), Runner);
+ Pending.push_back(TJobState(nullptr, MESSAGE_DONT_ASK, req.Release(), session, nullptr, 0, nullptr, true));
+ }
+
+ ///////////////////////////////////////////////////////////////
+ /// send reply to the starter message
+ void TBusJob::SendReply(TBusMessageAutoPtr reply) {
+ CheckThreadCurrentJob();
+
+ Y_VERIFY(!ReplySent, "cannot call SendReply twice");
+ ReplySent = true;
+ if (!OnMessageContext)
+ return;
+
+ EMessageStatus ok = OnMessageContext.SendReplyMove(reply);
+ if (ok != MESSAGE_OK) {
+ // TODO: count errors
+ }
+ }
+
+ /// set the flag to terminate job at the earliest convenience
+ void TBusJob::Cancel(EMessageStatus status) {
+ CheckThreadCurrentJob();
+
+ Status = status;
+ }
+
+ void TBusJob::ClearState(TJobState& call) {
+ TJobStateVec::iterator it;
+ for (it = Finished.begin(); it != Finished.end(); ++it) {
+ TJobState& state = *it;
+ if (&call == &state) {
+ ::ClearState(&call);
+ Finished.erase(it);
+ return;
+ }
+ }
+ Y_ASSERT(0);
+ }
+
+ void TBusJob::ClearAllMessageStates() {
+ ClearJobStateVector(&Finished);
+ ClearJobStateVector(&Pending);
+ }
+
+ void TBusJob::Sleep(int milliSeconds) {
+ CheckThreadCurrentJob();
+
+ Y_VERIFY(Pending.empty(), "sleep is not allowed when there are pending job");
+ Y_VERIFY(SleepUntil == 0, "must not override sleep");
+
+ SleepUntil = Now() + milliSeconds;
+ }
+
+ TString TBusJob::GetStatus(unsigned flags) {
+ TString strReturn;
+ strReturn += Sprintf(" job=%016" PRIx64 " type=%d sent=%d pending=%d (%d) %s\n",
+ Message->GetHeader()->Id,
+ (int)Message->GetHeader()->Type,
+ (int)(Now() - Message->GetHeader()->SendTime) / 1000,
+ (int)Pending.size(),
+ (int)Finished.size(),
+ Status != MESSAGE_OK ? ToString(Status).data() : "");
+
+ TJobStateVec::iterator it;
+ for (it = Pending.begin(); it != Pending.end(); ++it) {
+ TJobState& call = *it;
+ strReturn += call.GetStatus(flags);
+ }
+ return strReturn;
+ }
+
+ TString TJobState::GetStatus(unsigned flags) {
+ Y_UNUSED(flags);
+ TString strReturn;
+ strReturn += Sprintf(" pending=%016" PRIx64 " type=%d (%s) sent=%d %s\n",
+ Message->GetHeader()->Id,
+ (int)Message->GetHeader()->Type,
+ Session->GetProto()->GetService(),
+ (int)(Now() - Message->GetHeader()->SendTime) / 1000,
+ ToString(Status).data());
+ return strReturn;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+
+ void TBusModuleImpl::CancelJob(TBusJob* job, EMessageStatus status) {
+ TWhatThreadDoesAcquireGuard<TMutex> G(Lock, "modules: acquiring lock for CancelJob");
+ if (job) {
+ job->Cancel(status);
+ }
+ }
+
+ TString TBusModuleImpl::GetStatus(unsigned flags) {
+ Y_UNUSED(flags);
+ TWhatThreadDoesAcquireGuard<TMutex> G(Lock, "modules: acquiring lock for GetStatus");
+ TString strReturn = Sprintf("JobsInFlight=%d\n", (int)Jobs.size());
+ for (auto job : Jobs) {
+ //strReturn += job->Job->GetStatus(flags);
+ Y_UNUSED(job);
+ strReturn += "TODO\n";
+ }
+ return strReturn;
+ }
+
+ TBusModuleConfig::TBusModuleConfig()
+ : StarterMaxInFlight(1000)
+ {
+ }
+
+ TBusModuleConfig::TSecret::TSecret()
+ : SchedulePeriod(TDuration::Seconds(1))
+ {
+ }
+
+ TBusModule::TBusModule(const char* name)
+ : Impl(new TBusModuleImpl(this, name))
+ {
+ }
+
+ TBusModule::~TBusModule() {
+ }
+
+ const char* TBusModule::GetName() const {
+ return Impl->Name;
+ }
+
+ void TBusModule::SetConfig(const TBusModuleConfig& config) {
+ Impl->ModuleConfig = config;
+ }
+
+ bool TBusModule::StartInput() {
+ Y_VERIFY(Impl->State == TBusModuleImpl::CREATED, "state check");
+ Y_VERIFY(!!Impl->Queue, "state check");
+ Impl->State = TBusModuleImpl::RUNNING;
+
+ Y_ASSERT(!Impl->ExternalSession);
+ TBusServerSessionPtr extSession = CreateExtSession(*Impl->Queue);
+ if (extSession != nullptr) {
+ Impl->ExternalSession = extSession;
+ }
+
+ return true;
+ }
+
+ bool TBusModule::Shutdown() {
+ Impl->Shutdown();
+
+ return true;
+ }
+
+ TBusJob* TBusModule::CreateJobInstance(TBusMessage* message) {
+ TBusJob* job = new TBusJob(this, message);
+ return job;
+ }
+
+ /**
+Example for external session creation:
+
+TBusSession* TMyModule::CreateExtSession(TBusMessageQueue& queue) {
+ TBusSession* session = CreateDefaultDestination(queue, &ExternalProto, ExternalConfig);
+ session->RegisterService(hostname, begin, end);
+ return session;
+*/
+
+ bool TBusModule::CreatePrivateSessions(TBusMessageQueue* queue) {
+ Impl->Queue = queue;
+ return true;
+ }
+
+ int TBusModule::GetModuleSessionInFlight() const {
+ return Impl->Size();
+ }
+
+ TIntrusivePtr<TBusModuleInternal> TBusModule::GetInternal() {
+ return Impl.Get();
+ }
+
+ TBusServerSessionPtr TBusModule::CreateDefaultDestination(
+ TBusMessageQueue& queue, TBusProtocol* proto, const TBusServerSessionConfig& config, const TString& name) {
+ TBusServerSessionConfig patchedConfig = config;
+ patchedConfig.ExecuteOnMessageInWorkerPool = false;
+ if (!patchedConfig.Name) {
+ patchedConfig.Name = name;
+ }
+ if (!patchedConfig.Name) {
+ patchedConfig.Name = Impl->Name;
+ }
+ TBusServerSessionPtr session =
+ TBusServerSession::Create(proto, Impl->ModuleServerHandler.Get(), patchedConfig, &queue);
+ Impl->ServerSessions.push_back(session);
+ return session;
+ }
+
+ TBusClientSessionPtr TBusModule::CreateDefaultSource(
+ TBusMessageQueue& queue, TBusProtocol* proto, const TBusClientSessionConfig& config, const TString& name) {
+ TBusClientSessionConfig patchedConfig = config;
+ patchedConfig.ExecuteOnReplyInWorkerPool = false;
+ if (!patchedConfig.Name) {
+ patchedConfig.Name = name;
+ }
+ if (!patchedConfig.Name) {
+ patchedConfig.Name = Impl->Name;
+ }
+ TBusClientSessionPtr session =
+ TBusClientSession::Create(proto, Impl->ModuleClientHandler.Get(), patchedConfig, &queue);
+ Impl->ClientSessions.push_back(session);
+ return session;
+ }
+
+ TBusStarter* TBusModule::CreateDefaultStarter(TBusMessageQueue&, const TBusSessionConfig& config) {
+ TBusStarter* session = new TBusStarter(this, config);
+ Impl->Starters.push_back(session);
+ return session;
+ }
+
+ void TBusModule::OnClientConnectionEvent(const TClientConnectionEvent& event) {
+ Y_UNUSED(event);
+ }
+
+ TString TBusModule::GetStatus(unsigned flags) {
+ TString strReturn = Sprintf("%s\n", Impl->Name);
+ strReturn += Impl->GetStatus(flags);
+ return strReturn;
+ }
+
+}
+
+void TBusModuleImpl::AddJob(TJobRunner* jobRunner) {
+ TWhatThreadDoesAcquireGuard<TMutex> G(Lock, "modules: acquiring lock for AddJob");
+ Jobs.push_back(jobRunner);
+ jobRunner->JobStorageIterator = Jobs.end();
+ --jobRunner->JobStorageIterator;
+}
+
+void TBusModuleImpl::DestroyJob(TJobRunner* job) {
+ Y_ASSERT(job->JobStorageIterator != TList<TJobRunner*>::iterator());
+
+ {
+ TWhatThreadDoesAcquireGuard<TMutex> G(Lock, "modules: acquiring lock for DestroyJob");
+ int jobCount = AtomicDecrement(JobCount);
+ Y_VERIFY(jobCount >= 0, "decremented too much");
+ Jobs.erase(job->JobStorageIterator);
+
+ if (AtomicGet(State) == STOPPED) {
+ if (jobCount == 0) {
+ ShutdownCondVar.BroadCast();
+ }
+ }
+ }
+
+ job->JobStorageIterator = TList<TJobRunner*>::iterator();
+}
+
+void TBusModuleImpl::OnMessageReceived(TAutoPtr<TBusMessage> msg0, TOnMessageContext& context) {
+ TBusMessage* msg = !!msg0 ? msg0.Get() : context.GetMessage();
+ Y_VERIFY(!!msg);
+
+ THolder<TJobRunner> jobRunner(new TJobRunner(Module->CreateJobInstance(msg)));
+ jobRunner->Job->MessageHolder.Reset(msg0.Release());
+ jobRunner->Job->OnMessageContext.Swap(context);
+ SetJob(jobRunner->Job->Message, jobRunner.Get());
+
+ AtomicIncrement(JobCount);
+
+ AddJob(jobRunner.Get());
+
+ jobRunner.Release()->Schedule();
+}
+
+void TBusModuleImpl::Shutdown() {
+ if (AtomicGet(State) != TBusModuleImpl::RUNNING) {
+ AtomicSet(State, TBusModuleImpl::STOPPED);
+ return;
+ }
+ AtomicSet(State, TBusModuleImpl::STOPPED);
+
+ for (auto& clientSession : ClientSessions) {
+ clientSession->Shutdown();
+ }
+ for (auto& serverSession : ServerSessions) {
+ serverSession->Shutdown();
+ }
+
+ for (size_t starter = 0; starter < Starters.size(); ++starter) {
+ Starters[starter]->Shutdown();
+ }
+
+ {
+ TWhatThreadDoesAcquireGuard<TMutex> guard(Lock, "modules: acquiring lock for Shutdown");
+ for (auto& Job : Jobs) {
+ Job->Schedule();
+ }
+
+ while (!Jobs.empty()) {
+ ShutdownCondVar.WaitI(Lock);
+ }
+ }
+}
+
+EMessageStatus TBusModule::StartJob(TAutoPtr<TBusMessage> message) {
+ Y_VERIFY(Impl->State == TBusModuleImpl::RUNNING);
+ Y_VERIFY(!!Impl->Queue);
+
+ if ((unsigned)AtomicGet(Impl->JobCount) >= Impl->ModuleConfig.StarterMaxInFlight) {
+ return MESSAGE_BUSY;
+ }
+
+ TOnMessageContext dummy;
+ Impl->OnMessageReceived(message.Release(), dummy);
+
+ return MESSAGE_OK;
+}
+
+void TModuleServerHandler::OnMessage(TOnMessageContext& msg) {
+ Module->OnMessageReceived(nullptr, msg);
+}
+
+void TModuleClientHandler::OnReply(TAutoPtr<TBusMessage> req, TAutoPtr<TBusMessage> resp) {
+ TJobRunner* job = GetJob(req.Get());
+ Y_ASSERT(job);
+ Y_ASSERT(job->Job->Message != req.Get());
+ job->EnqueueAndSchedule(TJobResponseMessage(req.Release(), resp.Release(), MESSAGE_OK));
+ job->UnRef();
+}
+
+void TModuleClientHandler::OnMessageSentOneWay(TAutoPtr<TBusMessage> req) {
+ TJobRunner* job = GetJob(req.Get());
+ Y_ASSERT(job);
+ Y_ASSERT(job->Job->Message != req.Get());
+ job->EnqueueAndSchedule(TJobResponseMessage(req.Release(), nullptr, MESSAGE_OK));
+ job->UnRef();
+}
+
+void TModuleClientHandler::OnError(TAutoPtr<TBusMessage> msg, EMessageStatus status) {
+ TJobRunner* job = GetJob(msg.Get());
+ if (job) {
+ Y_ASSERT(job->Job->Message != msg.Get());
+ job->EnqueueAndSchedule(TJobResponseMessage(msg.Release(), nullptr, status));
+ job->UnRef();
+ }
+}
+
+void TModuleClientHandler::OnClientConnectionEvent(const TClientConnectionEvent& event) {
+ Module->OnClientConnectionEvent(event);
+}
diff --git a/library/cpp/messagebus/oldmodule/module.h b/library/cpp/messagebus/oldmodule/module.h
new file mode 100644
index 0000000000..8d1c4a5d52
--- /dev/null
+++ b/library/cpp/messagebus/oldmodule/module.h
@@ -0,0 +1,410 @@
+#pragma once
+
+///////////////////////////////////////////////////////////////////////////
+/// \file
+/// \brief Application interface for modules
+
+/// NBus::TBusModule provides foundation for implementation of asynchnous
+/// modules that communicate with multiple external or local sessions
+/// NBus::TBusSession.
+
+/// To implement the module some virtual functions needs to be overridden:
+
+/// NBus::TBusModule::CreateExtSession() creates and registers an
+/// external session that receives incoming messages as input for module
+/// processing.
+
+/// When new incoming message arrives the new NBus::TBusJob is created.
+/// NBus::TBusJob is somewhat similar to a thread, it maintains all the state
+/// during processing of one incoming message. Default implementation of
+/// NBus::TBusJob will maintain all send and received messages during
+/// lifetime of this job. Each message, status and reply can be found
+/// within NBus::TJobState using NBus::TBusJob::GetState(). If your module
+/// needs to maintain an additional information during lifetime of the job
+/// you can derive your own class from NBus::TBusJob and override job
+/// factory method NBus::IJobFactory::CreateJobInstance() to create your instances.
+
+/// Processing of a given message starts with a call to NBus::TBusModule::Start()
+/// handler that should be overridden in the module implementation. Within
+/// the callback handler module can perform any computation and access any
+/// datastore tables that it needs. The handler can also access any module
+/// variables. However, same handler can be called from multiple threads so,
+/// it is recommended that handler only access read-only module level variables.
+
+/// Handler should use NBus::TBusJob::Send() to send messages to other client
+/// sessions and it can use NBus::TBusJob::Reply() to send reply to the main
+/// job message. When handler is done, it returns the pointer to the next handler to call
+/// when all pending messages have cleared. If handler
+/// returns pointer to itself the module will reschedule execution of this handler
+/// for a later time. This should be done in case NBus::TBusJob::Send() returns
+/// error (not MESSAGE_OK)
+
+#include "startsession.h"
+
+#include <library/cpp/messagebus/ybus.h>
+
+#include <util/generic/noncopyable.h>
+#include <util/generic/object_counter.h>
+
+namespace NBus {
+ class TBusJob;
+ class TBusModule;
+
+ namespace NPrivate {
+ struct TCallJobHandlerWorkItem;
+ struct TBusModuleImpl;
+ struct TModuleServerHandler;
+ struct TModuleClientHandler;
+ struct TJobRunner;
+ }
+
+ class TJobHandler {
+ protected:
+ typedef TJobHandler (TBusModule::*TBusHandlerPtr)(TBusJob* job, TBusMessage* mess);
+ TBusHandlerPtr MyPtr;
+
+ public:
+ template <class B>
+ TJobHandler(TJobHandler (B::*fptr)(TBusJob* job, TBusMessage* mess)) {
+ MyPtr = static_cast<TBusHandlerPtr>(fptr);
+ }
+ TJobHandler(TBusHandlerPtr fptr = nullptr) {
+ MyPtr = fptr;
+ }
+ TJobHandler(const TJobHandler&) = default;
+ TJobHandler& operator =(const TJobHandler&) = default;
+ bool operator==(TJobHandler h) const {
+ return MyPtr == h.MyPtr;
+ }
+ bool operator!=(TJobHandler h) const {
+ return MyPtr != h.MyPtr;
+ }
+ bool operator!() const {
+ return !MyPtr;
+ }
+ TJobHandler operator()(TBusModule* b, TBusJob* job, TBusMessage* mess) {
+ return (b->*MyPtr)(job, mess);
+ }
+ };
+
+ typedef void (TBusModule::*TReplyHandler)(TBusJob* job, EMessageStatus status, TBusMessage* mess, TBusMessage* reply);
+
+ ////////////////////////////////////////////////////
+ /// \brief Pending message state
+
+ struct TJobState {
+ friend class TBusJob;
+ friend class ::TCrawlerModule;
+
+ TReplyHandler Handler;
+ EMessageStatus Status;
+ TBusMessage* Message;
+ TBusMessage* Reply;
+ TBusClientSession* Session;
+ size_t NumRetries;
+ size_t MaxRetries;
+ // If != NULL then use it as destination.
+ TNetAddr Addr;
+ bool UseAddr;
+ bool OneWay;
+
+ private:
+ TJobState(TReplyHandler handler,
+ EMessageStatus status,
+ TBusMessage* mess, TBusClientSession* session, TBusMessage* reply, size_t maxRetries = 0,
+ const TNetAddr* addr = nullptr, bool oneWay = false)
+ : Handler(handler)
+ , Status(status)
+ , Message(mess)
+ , Reply(reply)
+ , Session(session)
+ , NumRetries(0)
+ , MaxRetries(maxRetries)
+ , OneWay(oneWay)
+ {
+ if (!!addr) {
+ Addr = *addr;
+ }
+ UseAddr = !!addr;
+ }
+
+ public:
+ TString GetStatus(unsigned flags);
+ };
+
+ using TJobStateVec = TVector<TJobState>;
+
+ /////////////////////////////////////////////////////////
+ /// \brief Execution item = thread
+
+ /// Maintains internal state of document in computation
+ class TBusJob {
+ TObjectCounter<TBusJob> ObjectCounter;
+
+ private:
+ void CheckThreadCurrentJob();
+
+ public:
+ /// given a module and starter message
+ TBusJob(TBusModule* module, TBusMessage* message);
+
+ /// destructor will free all the message that were send and received
+ virtual ~TBusJob();
+
+ TBusMessage* GetMessage() const {
+ return Message;
+ }
+
+ TNetAddr GetPeerAddrNetAddr() const;
+
+ /// send message to any other session or application
+ /// If addr is set then use it as destination.
+ void Send(TBusMessageAutoPtr mess, TBusClientSession* session, TReplyHandler rhandler, size_t maxRetries, const TNetAddr& addr);
+ void Send(TBusMessageAutoPtr mess, TBusClientSession* session, TReplyHandler rhandler = nullptr, size_t maxRetries = 0);
+
+ void SendOneWayTo(TBusMessageAutoPtr req, TBusClientSession* session, const TNetAddr& addr);
+ void SendOneWayWithLocator(TBusMessageAutoPtr req, TBusClientSession* session);
+
+ /// send reply to the starter message
+ virtual void SendReply(TBusMessageAutoPtr reply);
+
+ /// set the flag to terminate job at the earliest convenience
+ void Cancel(EMessageStatus status);
+
+ /// helper to put item on finished list of states
+ /// It should not be a part of public API,
+ /// so prohibit it for all except current users.
+ private:
+ friend class ::TCrawlerModule;
+ void PutState(const TJobState& state) {
+ Finished.push_back(state);
+ }
+
+ public:
+ /// retrieve all pending messages
+ void GetPending(TJobStateVec* stateVec) {
+ Y_ASSERT(stateVec);
+ *stateVec = Pending;
+ }
+
+ /// helper function to find state of previously sent messages
+ template <class MessageType>
+ TJobState* GetState(int* startFrom = nullptr) {
+ for (int i = startFrom ? *startFrom : 0; i < int(Finished.size()); i++) {
+ TJobState* call = &Finished[i];
+ if (call->Reply != nullptr && dynamic_cast<MessageType*>(call->Reply)) {
+ if (startFrom) {
+ *startFrom = i;
+ }
+ return call;
+ }
+ if (call->Message != nullptr && dynamic_cast<MessageType*>(call->Message)) {
+ if (startFrom) {
+ *startFrom = i;
+ }
+ return call;
+ }
+ }
+ return nullptr;
+ }
+
+ /// helper function to find response for previously sent messages
+ template <class MessageType>
+ MessageType* Get(int* startFrom = nullptr) {
+ for (int i = startFrom ? *startFrom : 0; i < int(Finished.size()); i++) {
+ TJobState& call = Finished[i];
+ if (call.Reply != nullptr && dynamic_cast<MessageType*>(call.Reply)) {
+ if (startFrom) {
+ *startFrom = i;
+ }
+ return static_cast<MessageType*>(call.Reply);
+ }
+ if (call.Message != nullptr && dynamic_cast<MessageType*>(call.Message)) {
+ if (startFrom) {
+ *startFrom = i;
+ }
+ return static_cast<MessageType*>(call.Message);
+ }
+ }
+ return nullptr;
+ }
+
+ /// helper function to find status for previously sent message
+ template <class MessageType>
+ EMessageStatus GetStatus(int* startFrom = nullptr) {
+ for (int i = startFrom ? *startFrom : 0; i < int(Finished.size()); i++) {
+ TJobState& call = Finished[i];
+ if (call.Message != nullptr && dynamic_cast<MessageType*>(call.Message)) {
+ if (startFrom) {
+ *startFrom = i;
+ }
+ return call.Status;
+ }
+ }
+ return MESSAGE_UNKNOWN;
+ }
+
+ /// helper function to clear state of previosly sent messages
+ template <class MessageType>
+ void Clear() {
+ for (size_t i = 0; i < Finished.size();) {
+ // `Finished.size() - i` decreases with each iteration
+ // we either increment i, or remove element from Finished.
+ TJobState& call = Finished[i];
+ if (call.Message != nullptr && dynamic_cast<MessageType*>(call.Message)) {
+ ClearState(call);
+ } else {
+ ++i;
+ }
+ }
+ }
+
+ /// helper function to clear state in order to try again
+ void ClearState(TJobState& state);
+
+ /// clears all message states
+ void ClearAllMessageStates();
+
+ /// returns true if job is done
+ bool IsDone();
+
+ /// return human reabable status of this job
+ virtual TString GetStatus(unsigned flags);
+
+ /// set sleep time for job
+ void Sleep(int milliSeconds);
+
+ void CallJobHandlerOnly();
+
+ private:
+ bool CallJobHandler();
+ void DoCallReplyHandler(TJobState&);
+ /// send out all Pending jobs, failed sends will be migrated to Finished
+ bool SendPending();
+ bool AnyPendingToSend();
+
+ public:
+ /// helper to call from OnReply() and OnError()
+ int CallReplyHandler(EMessageStatus status, TBusMessage* mess, TBusMessage* reply);
+
+ public:
+ TJobHandler Handler; ///< job handler to be executed within next CallJobHandler()
+ EMessageStatus Status; ///< set != MESSAGE_OK if job should terminate asap
+ private:
+ NPrivate::TJobRunner* Runner;
+ TBusMessage* Message;
+ THolder<TBusMessage> MessageHolder;
+ TOnMessageContext OnMessageContext; // starter
+ public:
+ bool ReplySent;
+
+ private:
+ friend class TBusModule;
+ friend struct NPrivate::TBusModuleImpl;
+ friend struct NPrivate::TCallJobHandlerWorkItem;
+ friend struct NPrivate::TModuleServerHandler;
+ friend struct NPrivate::TModuleClientHandler;
+ friend struct NPrivate::TJobRunner;
+
+ TJobStateVec Pending; ///< messages currently outstanding via Send()
+ TJobStateVec Finished; ///< messages that were replied to
+ TBusModule* Module;
+ NPrivate::TBusModuleImpl* ModuleImpl; ///< module which created the job
+ TBusInstant SleepUntil; ///< time to wakeup, 0 if no sleep
+ };
+
+ ////////////////////////////////////////////////////////////////////
+ /// \brief Classes to implement basic module functionality
+
+ class IJobFactory {
+ protected:
+ virtual ~IJobFactory() {
+ }
+
+ public:
+ /// job factory method, override to create custom jobs
+ virtual TBusJob* CreateJobInstance(TBusMessage* message) = 0;
+ };
+
+ struct TBusModuleConfig {
+ unsigned StarterMaxInFlight;
+
+ struct TSecret {
+ TDuration SchedulePeriod;
+
+ TSecret();
+ };
+ TSecret Secret;
+
+ TBusModuleConfig();
+ };
+
+ namespace NPrivate {
+ struct TBusModuleInternal: public TAtomicRefCount<TBusModuleInternal> {
+ virtual TVector<TBusClientSessionPtr> GetClientSessionsInternal() = 0;
+ virtual TVector<TBusServerSessionPtr> GetServerSessionsInternal() = 0;
+ virtual TBusMessageQueue* GetQueue() = 0;
+
+ virtual TString GetNameInternal() = 0;
+
+ virtual TString GetStatusSingleLine() = 0;
+
+ virtual ~TBusModuleInternal() {
+ }
+ };
+ }
+
+ class TBusModule: public IJobFactory, TNonCopyable {
+ friend class TBusJob;
+
+ TObjectCounter<TBusModule> ObjectCounter;
+
+ TIntrusivePtr<NPrivate::TBusModuleImpl> Impl;
+
+ public:
+ /// Each module should have a name which is used as protocol service
+ TBusModule(const char* name);
+ ~TBusModule() override;
+
+ const char* GetName() const;
+
+ void SetConfig(const TBusModuleConfig& config);
+
+ /// get status of all jobs in flight
+ TString GetStatus(unsigned flags = 0);
+
+ /// called when application is about to start
+ virtual bool StartInput();
+ /// called when application is about to exit
+ virtual bool Shutdown();
+
+ // this default implementation just creates TBusJob object
+ TBusJob* CreateJobInstance(TBusMessage* message) override;
+
+ EMessageStatus StartJob(TAutoPtr<TBusMessage> message);
+
+ /// creates private sessions, calls CreateExtSession(), should be called before StartInput()
+ bool CreatePrivateSessions(TBusMessageQueue* queue);
+
+ virtual void OnClientConnectionEvent(const TClientConnectionEvent& event);
+
+ public:
+ /// entry point into module, first function to call
+ virtual TJobHandler Start(TBusJob* job, TBusMessage* mess) = 0;
+
+ protected:
+ /// override this function to create destination session
+ virtual TBusServerSessionPtr CreateExtSession(TBusMessageQueue& queue) = 0;
+
+ public:
+ int GetModuleSessionInFlight() const;
+
+ TIntrusivePtr<NPrivate::TBusModuleInternal> GetInternal();
+
+ protected:
+ TBusServerSessionPtr CreateDefaultDestination(TBusMessageQueue& queue, TBusProtocol* proto, const TBusServerSessionConfig& config, const TString& name = TString());
+ TBusClientSessionPtr CreateDefaultSource(TBusMessageQueue& queue, TBusProtocol* proto, const TBusClientSessionConfig& config, const TString& name = TString());
+ TBusStarter* CreateDefaultStarter(TBusMessageQueue& unused, const TBusSessionConfig& config);
+ };
+
+}
diff --git a/library/cpp/messagebus/oldmodule/startsession.cpp b/library/cpp/messagebus/oldmodule/startsession.cpp
new file mode 100644
index 0000000000..7c38801d62
--- /dev/null
+++ b/library/cpp/messagebus/oldmodule/startsession.cpp
@@ -0,0 +1,65 @@
+///////////////////////////////////////////////////////////
+/// \file
+/// \brief Starter session implementation
+
+/// Starter session will generate emtpy message to insert
+/// into local session that are registered under same protocol
+
+/// Starter (will one day) automatically adjust number
+/// of message inflight to make sure that at least one of source
+/// sessions within message queue is at the limit (bottle neck)
+
+/// Maximum number of messages that starter will instert into
+/// the pipeline is configured by NBus::TBusSessionConfig::MaxInFlight
+
+#include "startsession.h"
+
+#include "module.h"
+
+#include <library/cpp/messagebus/ybus.h>
+
+namespace NBus {
+ void* TBusStarter::_starter(void* data) {
+ TBusStarter* pThis = static_cast<TBusStarter*>(data);
+ pThis->Starter();
+ return nullptr;
+ }
+
+ TBusStarter::TBusStarter(TBusModule* module, const TBusSessionConfig& config)
+ : Module(module)
+ , Config(config)
+ , StartThread(_starter, this)
+ , Exiting(false)
+ {
+ StartThread.Start();
+ }
+
+ TBusStarter::~TBusStarter() {
+ Shutdown();
+ }
+
+ void TBusStarter::Shutdown() {
+ {
+ TGuard<TMutex> g(ExitLock);
+ Exiting = true;
+ ExitSignal.Signal();
+ }
+ StartThread.Join();
+ }
+
+ void TBusStarter::Starter() {
+ TGuard<TMutex> g(ExitLock);
+ while (!Exiting) {
+ TAutoPtr<TBusMessage> empty(new TBusMessage(0));
+
+ EMessageStatus status = Module->StartJob(empty);
+
+ if (Config.SendTimeout > 0) {
+ ExitSignal.WaitT(ExitLock, TDuration::MilliSeconds(Config.SendTimeout));
+ } else {
+ ExitSignal.WaitT(ExitLock, (status == MESSAGE_BUSY) ? TDuration::MilliSeconds(1) : TDuration::Zero());
+ }
+ }
+ }
+
+}
diff --git a/library/cpp/messagebus/oldmodule/startsession.h b/library/cpp/messagebus/oldmodule/startsession.h
new file mode 100644
index 0000000000..5e26e7e1e5
--- /dev/null
+++ b/library/cpp/messagebus/oldmodule/startsession.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <library/cpp/messagebus/ybus.h>
+
+#include <util/system/thread.h>
+
+namespace NBus {
+ class TBusModule;
+
+ class TBusStarter {
+ private:
+ TBusModule* Module;
+ TBusSessionConfig Config;
+ TThread StartThread;
+ bool Exiting;
+ TCondVar ExitSignal;
+ TMutex ExitLock;
+
+ static void* _starter(void* data);
+
+ void Starter();
+
+ TString GetStatus(ui16 /*flags=YBUS_STATUS_CONNS*/) {
+ return "";
+ }
+
+ public:
+ TBusStarter(TBusModule* module, const TBusSessionConfig& config);
+ ~TBusStarter();
+
+ void Shutdown();
+ };
+
+}
diff --git a/library/cpp/messagebus/oldmodule/ya.make b/library/cpp/messagebus/oldmodule/ya.make
new file mode 100644
index 0000000000..ca5eae74f0
--- /dev/null
+++ b/library/cpp/messagebus/oldmodule/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(g:messagebus)
+
+PEERDIR(
+ library/cpp/messagebus
+ library/cpp/messagebus/actor
+)
+
+SRCS(
+ module.cpp
+ startsession.cpp
+)
+
+END()
diff --git a/library/cpp/messagebus/protobuf/ya.make b/library/cpp/messagebus/protobuf/ya.make
new file mode 100644
index 0000000000..64ff240b51
--- /dev/null
+++ b/library/cpp/messagebus/protobuf/ya.make
@@ -0,0 +1,15 @@
+LIBRARY(messagebus_protobuf)
+
+OWNER(g:messagebus)
+
+SRCS(
+ ybusbuf.cpp
+)
+
+PEERDIR(
+ contrib/libs/protobuf
+ library/cpp/messagebus
+ library/cpp/messagebus/actor
+)
+
+END()
diff --git a/library/cpp/messagebus/protobuf/ybusbuf.cpp b/library/cpp/messagebus/protobuf/ybusbuf.cpp
new file mode 100644
index 0000000000..63415b3737
--- /dev/null
+++ b/library/cpp/messagebus/protobuf/ybusbuf.cpp
@@ -0,0 +1,88 @@
+#include "ybusbuf.h"
+
+#include <library/cpp/messagebus/actor/what_thread_does.h>
+
+#include <google/protobuf/io/coded_stream.h>
+
+using namespace NBus;
+
+TBusBufferProtocol::TBusBufferProtocol(TBusService name, int port)
+ : TBusProtocol(name, port)
+{
+}
+
+TBusBufferProtocol::~TBusBufferProtocol() {
+ for (auto& type : Types) {
+ delete type;
+ }
+}
+
+TBusBufferBase* TBusBufferProtocol::FindType(int type) {
+ for (unsigned i = 0; i < Types.size(); i++) {
+ if (Types[i]->GetHeader()->Type == type) {
+ return Types[i];
+ }
+ }
+ return nullptr;
+}
+
+bool TBusBufferProtocol::IsRegisteredType(unsigned type) {
+ return TypeMask[type >> 5] & (1 << (type & ((1 << 5) - 1)));
+}
+
+void TBusBufferProtocol::RegisterType(TAutoPtr<TBusBufferBase> mess) {
+ ui32 type = mess->GetHeader()->Type;
+ TypeMask[type >> 5] |= 1 << (type & ((1 << 5) - 1));
+
+ Types.push_back(mess.Release());
+}
+
+TArrayRef<TBusBufferBase* const> TBusBufferProtocol::GetTypes() const {
+ return Types;
+}
+
+void TBusBufferProtocol::Serialize(const TBusMessage* mess, TBuffer& data) {
+ TWhatThreadDoesPushPop pp("serialize protobuf message");
+
+ const TBusHeader* header = mess->GetHeader();
+
+ if (!IsRegisteredType(header->Type)) {
+ Y_FAIL("unknown message type: %d", int(header->Type));
+ return;
+ }
+
+ // cast the base from real message
+ const TBusBufferBase* bmess = CheckedCast<const TBusBufferBase*>(mess);
+
+ unsigned size = bmess->GetRecord()->ByteSize();
+ data.Reserve(data.Size() + size);
+
+ char* after = (char*)bmess->GetRecord()->SerializeWithCachedSizesToArray((ui8*)data.Pos());
+ Y_VERIFY(after - data.Pos() == size);
+
+ data.Advance(size);
+}
+
+TAutoPtr<TBusMessage> TBusBufferProtocol::Deserialize(ui16 messageType, TArrayRef<const char> payload) {
+ TWhatThreadDoesPushPop pp("deserialize protobuf message");
+
+ TBusBufferBase* messageTemplate = FindType(messageType);
+ if (messageTemplate == nullptr) {
+ return nullptr;
+ //Y_FAIL("unknown message type: %d", unsigned(messageType));
+ }
+
+ // clone the base
+ TAutoPtr<TBusBufferBase> bmess = messageTemplate->New();
+
+ // Need to override protobuf message size limit
+ // NOTE: the payload size has already been checked against session MaxMessageSize
+ google::protobuf::io::CodedInputStream input(reinterpret_cast<const ui8*>(payload.data()), payload.size());
+ input.SetTotalBytesLimit(payload.size());
+
+ bool ok = bmess->GetRecord()->ParseFromCodedStream(&input) && input.ConsumedEntireMessage();
+ if (!ok) {
+ return nullptr;
+ }
+ return bmess.Release();
+}
diff --git a/library/cpp/messagebus/protobuf/ybusbuf.h b/library/cpp/messagebus/protobuf/ybusbuf.h
new file mode 100644
index 0000000000..57b4267ea5
--- /dev/null
+++ b/library/cpp/messagebus/protobuf/ybusbuf.h
@@ -0,0 +1,233 @@
+#pragma once
+
+#include <library/cpp/messagebus/ybus.h>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+
+#include <util/generic/cast.h>
+#include <util/generic/vector.h>
+#include <util/stream/mem.h>
+
+#include <array>
+
+namespace NBus {
+ using TBusBufferRecord = ::google::protobuf::Message;
+
+ template <class TBufferMessage>
+ class TBusBufferMessagePtr;
+ template <class TBufferMessage>
+ class TBusBufferMessageAutoPtr;
+
+ class TBusBufferBase: public TBusMessage {
+ public:
+ TBusBufferBase(int type)
+ : TBusMessage((ui16)type)
+ {
+ }
+ TBusBufferBase(ECreateUninitialized)
+ : TBusMessage(MESSAGE_CREATE_UNINITIALIZED)
+ {
+ }
+
+ ui16 GetType() const {
+ return GetHeader()->Type;
+ }
+
+ virtual TBusBufferRecord* GetRecord() const = 0;
+ virtual TBusBufferBase* New() = 0;
+ };
+
+ ///////////////////////////////////////////////////////////////////
+ /// \brief Template for all messages that have protobuf description
+
+ /// @param TBufferRecord is record described in .proto file with namespace
+ /// @param MessageFile is offset for .proto file message ids
+
+ /// \attention If you want one protocol NBus::TBusBufferProtocol to handle
+ /// messageges described in different .proto files, make sure that they have
+ /// unique values for MessageFile
+
+ template <class TBufferRecord, int MType>
+ class TBusBufferMessage: public TBusBufferBase {
+ public:
+ static const int MessageType = MType;
+
+ typedef TBusBufferMessagePtr<TBusBufferMessage<TBufferRecord, MType>> TPtr;
+ typedef TBusBufferMessageAutoPtr<TBusBufferMessage<TBufferRecord, MType>> TAutoPtr;
+
+ public:
+ typedef TBufferRecord RecordType;
+ TBufferRecord Record;
+
+ public:
+ TBusBufferMessage()
+ : TBusBufferBase(MessageType)
+ {
+ }
+ TBusBufferMessage(ECreateUninitialized)
+ : TBusBufferBase(MESSAGE_CREATE_UNINITIALIZED)
+ {
+ }
+ explicit TBusBufferMessage(const TBufferRecord& record)
+ : TBusBufferBase(MessageType)
+ , Record(record)
+ {
+ }
+ explicit TBusBufferMessage(TBufferRecord&& record)
+ : TBusBufferBase(MessageType)
+ , Record(std::move(record))
+ {
+ }
+
+ public:
+ TBusBufferRecord* GetRecord() const override {
+ return (TBusBufferRecord*)&Record;
+ }
+ TBusBufferBase* New() override {
+ return new TBusBufferMessage<TBufferRecord, MessageType>();
+ }
+ };
+
+ template <class TSelf, class TBufferMessage>
+ class TBusBufferMessagePtrBase {
+ public:
+ typedef typename TBufferMessage::RecordType RecordType;
+
+ private:
+ TSelf* GetSelf() {
+ return static_cast<TSelf*>(this);
+ }
+ const TSelf* GetSelf() const {
+ return static_cast<const TSelf*>(this);
+ }
+
+ public:
+ RecordType* operator->() {
+ Y_ASSERT(GetSelf()->Get());
+ return &(GetSelf()->Get()->Record);
+ }
+ const RecordType* operator->() const {
+ Y_ASSERT(GetSelf()->Get());
+ return &(GetSelf()->Get()->Record);
+ }
+ RecordType& operator*() {
+ Y_ASSERT(GetSelf()->Get());
+ return GetSelf()->Get()->Record;
+ }
+ const RecordType& operator*() const {
+ Y_ASSERT(GetSelf()->Get());
+ return GetSelf()->Get()->Record;
+ }
+
+ TBusHeader* GetHeader() {
+ return GetSelf()->Get()->GetHeader();
+ }
+ const TBusHeader* GetHeader() const {
+ return GetSelf()->Get()->GetHeader();
+ }
+ };
+
+ template <class TBufferMessage>
+ class TBusBufferMessagePtr: public TBusBufferMessagePtrBase<TBusBufferMessagePtr<TBufferMessage>, TBufferMessage> {
+ protected:
+ TBufferMessage* Holder;
+
+ public:
+ TBusBufferMessagePtr(TBufferMessage* mess)
+ : Holder(mess)
+ {
+ }
+ static TBusBufferMessagePtr<TBufferMessage> DynamicCast(TBusMessage* message) {
+ return dynamic_cast<TBufferMessage*>(message);
+ }
+ TBufferMessage* Get() {
+ return Holder;
+ }
+ const TBufferMessage* Get() const {
+ return Holder;
+ }
+
+ operator TBufferMessage*() {
+ return Holder;
+ }
+ operator const TBufferMessage*() const {
+ return Holder;
+ }
+
+ operator TAutoPtr<TBusMessage>() {
+ TAutoPtr<TBusMessage> r(Holder);
+ Holder = 0;
+ return r;
+ }
+ operator TBusMessageAutoPtr() {
+ TBusMessageAutoPtr r(Holder);
+ Holder = nullptr;
+ return r;
+ }
+ };
+
+ template <class TBufferMessage>
+ class TBusBufferMessageAutoPtr: public TBusBufferMessagePtrBase<TBusBufferMessageAutoPtr<TBufferMessage>, TBufferMessage> {
+ public:
+ TAutoPtr<TBufferMessage> AutoPtr;
+
+ public:
+ TBusBufferMessageAutoPtr() {
+ }
+ TBusBufferMessageAutoPtr(TBufferMessage* message)
+ : AutoPtr(message)
+ {
+ }
+
+ TBufferMessage* Get() {
+ return AutoPtr.Get();
+ }
+ const TBufferMessage* Get() const {
+ return AutoPtr.Get();
+ }
+
+ TBufferMessage* Release() const {
+ return AutoPtr.Release();
+ }
+
+ operator TAutoPtr<TBusMessage>() {
+ return AutoPtr.Release();
+ }
+ operator TBusMessageAutoPtr() {
+ return AutoPtr.Release();
+ }
+ };
+
+ /////////////////////////////////////////////
+ /// \brief Generic protocol object for messages descibed with protobuf
+
+ /// \attention If you mix messages in the same protocol from more than
+ /// .proto file make sure that they have different MessageFile parameter
+ /// in the NBus::TBusBufferMessage template
+
+ class TBusBufferProtocol: public TBusProtocol {
+ private:
+ TVector<TBusBufferBase*> Types;
+ std::array<ui32, ((1 << 16) >> 5)> TypeMask;
+
+ TBusBufferBase* FindType(int type);
+ bool IsRegisteredType(unsigned type);
+
+ public:
+ TBusBufferProtocol(TBusService name, int port);
+
+ ~TBusBufferProtocol() override;
+
+ /// register all the message that this protocol should handle
+ void RegisterType(TAutoPtr<TBusBufferBase> mess);
+
+ TArrayRef<TBusBufferBase* const> GetTypes() const;
+
+ /// serialized protocol specific data into TBusData
+ void Serialize(const TBusMessage* mess, TBuffer& data) override;
+
+ TAutoPtr<TBusMessage> Deserialize(ui16 messageType, TArrayRef<const char> payload) override;
+ };
+
+}
diff --git a/library/cpp/messagebus/queue_config.cpp b/library/cpp/messagebus/queue_config.cpp
new file mode 100644
index 0000000000..78fb52ee49
--- /dev/null
+++ b/library/cpp/messagebus/queue_config.cpp
@@ -0,0 +1,22 @@
+#include "queue_config.h"
+
+using namespace NBus;
+
+TBusQueueConfig::TBusQueueConfig() {
+ // workers and listeners configuratioin
+ NumWorkers = 1;
+}
+
+void TBusQueueConfig::ConfigureLastGetopt(
+ NLastGetopt::TOpts& opts, const TString& prefix) {
+ opts.AddLongOption(prefix + "worker-count")
+ .RequiredArgument("COUNT")
+ .DefaultValue(ToString(NumWorkers))
+ .StoreResult(&NumWorkers);
+}
+
+TString TBusQueueConfig::PrintToString() const {
+ TStringStream ss;
+ ss << "NumWorkers=" << NumWorkers << "\n";
+ return ss.Str();
+}
diff --git a/library/cpp/messagebus/queue_config.h b/library/cpp/messagebus/queue_config.h
new file mode 100644
index 0000000000..a9955f0c70
--- /dev/null
+++ b/library/cpp/messagebus/queue_config.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <library/cpp/getopt/last_getopt.h>
+
+namespace NBus {
+ //////////////////////////////////////////////////////////////////
+ /// \brief Configuration for message queue
+ struct TBusQueueConfig {
+ TString Name;
+ int NumWorkers; ///< number of threads calling OnMessage(), OnReply() handlers
+
+ TBusQueueConfig(); ///< initializes with default settings
+
+ void ConfigureLastGetopt(NLastGetopt::TOpts&, const TString& prefix = "mb-");
+
+ TString PrintToString() const;
+ };
+
+}
diff --git a/library/cpp/messagebus/rain_check/core/coro.cpp b/library/cpp/messagebus/rain_check/core/coro.cpp
new file mode 100644
index 0000000000..500841dd5b
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/coro.cpp
@@ -0,0 +1,60 @@
+#include "coro.h"
+
+#include "coro_stack.h"
+
+#include <util/system/tls.h>
+#include <util/system/yassert.h>
+
+using namespace NRainCheck;
+
+TContClosure TCoroTaskRunner::ContClosure(TCoroTaskRunner* runner, TArrayRef<char> memRegion) {
+ TContClosure contClosure;
+ contClosure.TrampoLine = runner;
+ contClosure.Stack = memRegion;
+ return contClosure;
+}
+
+TCoroTaskRunner::TCoroTaskRunner(IEnv* env, ISubtaskListener* parent, TAutoPtr<ICoroTask> impl)
+ : TTaskRunnerBase(env, parent, impl.Release())
+ , Stack(GetImpl()->StackSize)
+ , ContMachineContext(ContClosure(this, Stack.MemRegion()))
+ , CoroDone(false)
+{
+}
+
+TCoroTaskRunner::~TCoroTaskRunner() {
+ Y_ASSERT(CoroDone);
+}
+
+Y_POD_STATIC_THREAD(TContMachineContext*)
+CallerContext;
+Y_POD_STATIC_THREAD(TCoroTaskRunner*)
+Task;
+
+bool TCoroTaskRunner::ReplyReceived() {
+ Y_ASSERT(!CoroDone);
+
+ TContMachineContext me;
+
+ CallerContext = &me;
+ Task = this;
+
+ me.SwitchTo(&ContMachineContext);
+
+ Stack.VerifyNoStackOverflow();
+
+ Y_ASSERT(CallerContext == &me);
+ Y_ASSERT(Task == this);
+
+ return !CoroDone;
+}
+
+void NRainCheck::TCoroTaskRunner::DoRun() {
+ GetImpl()->Run();
+ CoroDone = true;
+ ContMachineContext.SwitchTo(CallerContext);
+}
+
+void NRainCheck::ICoroTask::WaitForSubtasks() {
+ Task->ContMachineContext.SwitchTo(CallerContext);
+}
diff --git a/library/cpp/messagebus/rain_check/core/coro.h b/library/cpp/messagebus/rain_check/core/coro.h
new file mode 100644
index 0000000000..95e2a30f9b
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/coro.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#include "coro_stack.h"
+#include "task.h"
+
+#include <util/generic/ptr.h>
+#include <util/memory/alloc.h>
+#include <util/system/align.h>
+#include <util/system/context.h>
+#include <util/system/valgrind.h>
+
+namespace NRainCheck {
+ class ICoroTask;
+
+ class TCoroTaskRunner: public TTaskRunnerBase, private ITrampoLine {
+ friend class ICoroTask;
+
+ private:
+ NPrivate::TCoroStack Stack;
+ TContMachineContext ContMachineContext;
+ bool CoroDone;
+
+ public:
+ TCoroTaskRunner(IEnv* env, ISubtaskListener* parent, TAutoPtr<ICoroTask> impl);
+ ~TCoroTaskRunner() override;
+
+ private:
+ static TContClosure ContClosure(TCoroTaskRunner* runner, TArrayRef<char> memRegion);
+
+ bool ReplyReceived() override /* override */;
+
+ void DoRun() override /* override */;
+
+ ICoroTask* GetImpl() {
+ return (ICoroTask*)GetImplBase();
+ }
+ };
+
+ class ICoroTask: public ITaskBase {
+ friend class TCoroTaskRunner;
+
+ private:
+ size_t StackSize;
+
+ public:
+ typedef TCoroTaskRunner TTaskRunner;
+ typedef ICoroTask ITask;
+
+ ICoroTask(size_t stackSize = 0x2000)
+ : StackSize(stackSize)
+ {
+ }
+
+ virtual void Run() = 0;
+ static void WaitForSubtasks();
+ };
+
+}
diff --git a/library/cpp/messagebus/rain_check/core/coro_stack.cpp b/library/cpp/messagebus/rain_check/core/coro_stack.cpp
new file mode 100644
index 0000000000..83b984ca6e
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/coro_stack.cpp
@@ -0,0 +1,41 @@
+#include "coro_stack.h"
+
+#include <util/generic/singleton.h>
+#include <util/system/valgrind.h>
+
+#include <cstdlib>
+#include <stdio.h>
+
+using namespace NRainCheck;
+using namespace NRainCheck::NPrivate;
+
+TCoroStack::TCoroStack(size_t size)
+ : SizeValue(size)
+{
+ Y_VERIFY(size % sizeof(ui32) == 0);
+ Y_VERIFY(size >= 0x1000);
+
+ DataHolder.Reset(malloc(size));
+
+ // register in valgrind
+
+ *MagicNumberLocation() = MAGIC_NUMBER;
+
+#if defined(WITH_VALGRIND)
+ ValgrindStackId = VALGRIND_STACK_REGISTER(Data(), (char*)Data() + Size());
+#endif
+}
+
+TCoroStack::~TCoroStack() {
+#if defined(WITH_VALGRIND)
+ VALGRIND_STACK_DEREGISTER(ValgrindStackId);
+#endif
+
+ VerifyNoStackOverflow();
+}
+
+void TCoroStack::FailStackOverflow() {
+ static const char message[] = "stack overflow\n";
+ fputs(message, stderr);
+ abort();
+}
diff --git a/library/cpp/messagebus/rain_check/core/coro_stack.h b/library/cpp/messagebus/rain_check/core/coro_stack.h
new file mode 100644
index 0000000000..2f3520e6e4
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/coro_stack.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <util/generic/array_ref.h>
+#include <util/generic/ptr.h>
+#include <util/system/valgrind.h>
+
+namespace NRainCheck {
+ namespace NPrivate {
+ struct TCoroStack {
+ THolder<void, TFree> DataHolder;
+ size_t SizeValue;
+
+#if defined(WITH_VALGRIND)
+ size_t ValgrindStackId;
+#endif
+
+ TCoroStack(size_t size);
+ ~TCoroStack();
+
+ void* Data() {
+ return DataHolder.Get();
+ }
+
+ size_t Size() {
+ return SizeValue;
+ }
+
+ TArrayRef<char> MemRegion() {
+ return TArrayRef((char*)Data(), Size());
+ }
+
+ ui32* MagicNumberLocation() {
+#if STACK_GROW_DOWN == 1
+ return (ui32*)Data();
+#elif STACK_GROW_DOWN == 0
+ return ((ui32*)(((char*)Data()) + Size())) - 1;
+#else
+#error "unknown"
+#endif
+ }
+
+ static void FailStackOverflow();
+
+ inline void VerifyNoStackOverflow() noexcept {
+ if (Y_UNLIKELY(*MagicNumberLocation() != MAGIC_NUMBER)) {
+ FailStackOverflow();
+ }
+ }
+
+ static const ui32 MAGIC_NUMBER = 0xAB4D15FE;
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/rain_check/core/coro_ut.cpp b/library/cpp/messagebus/rain_check/core/coro_ut.cpp
new file mode 100644
index 0000000000..61a33584a5
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/coro_ut.cpp
@@ -0,0 +1,106 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "coro.h"
+#include "spawn.h"
+
+#include <library/cpp/messagebus/rain_check/test/ut/test.h>
+
+using namespace NRainCheck;
+
+Y_UNIT_TEST_SUITE(RainCheckCoro) {
+ struct TSimpleCoroTask : ICoroTask {
+ TTestSync* const TestSync;
+
+ TSimpleCoroTask(TTestEnv*, TTestSync* testSync)
+ : TestSync(testSync)
+ {
+ }
+
+ void Run() override {
+ TestSync->WaitForAndIncrement(0);
+ }
+ };
+
+ Y_UNIT_TEST(Simple) {
+ TTestSync testSync;
+
+ TTestEnv env;
+
+ TIntrusivePtr<TCoroTaskRunner> task = env.SpawnTask<TSimpleCoroTask>(&testSync);
+ testSync.WaitForAndIncrement(1);
+ }
+
+ struct TSleepCoroTask : ICoroTask {
+ TTestEnv* const Env;
+ TTestSync* const TestSync;
+
+ TSleepCoroTask(TTestEnv* env, TTestSync* testSync)
+ : Env(env)
+ , TestSync(testSync)
+ {
+ }
+
+ TSubtaskCompletion SleepCompletion;
+
+ void Run() override {
+ Env->SleepService.Sleep(&SleepCompletion, TDuration::MilliSeconds(1));
+ WaitForSubtasks();
+ TestSync->WaitForAndIncrement(0);
+ }
+ };
+
+ Y_UNIT_TEST(Sleep) {
+ TTestSync testSync;
+
+ TTestEnv env;
+
+ TIntrusivePtr<TCoroTaskRunner> task = env.SpawnTask<TSleepCoroTask>(&testSync);
+
+ testSync.WaitForAndIncrement(1);
+ }
+
+ struct TSubtask : ICoroTask {
+ TTestEnv* const Env;
+ TTestSync* const TestSync;
+
+ TSubtask(TTestEnv* env, TTestSync* testSync)
+ : Env(env)
+ , TestSync(testSync)
+ {
+ }
+
+ void Run() override {
+ TestSync->CheckAndIncrement(1);
+ }
+ };
+
+ struct TSpawnCoroTask : ICoroTask {
+ TTestEnv* const Env;
+ TTestSync* const TestSync;
+
+ TSpawnCoroTask(TTestEnv* env, TTestSync* testSync)
+ : Env(env)
+ , TestSync(testSync)
+ {
+ }
+
+ TSubtaskCompletion SubtaskCompletion;
+
+ void Run() override {
+ TestSync->CheckAndIncrement(0);
+ SpawnSubtask<TSubtask>(Env, &SubtaskCompletion, TestSync);
+ WaitForSubtasks();
+ TestSync->CheckAndIncrement(2);
+ }
+ };
+
+ Y_UNIT_TEST(Spawn) {
+ TTestSync testSync;
+
+ TTestEnv env;
+
+ TIntrusivePtr<TCoroTaskRunner> task = env.SpawnTask<TSpawnCoroTask>(&testSync);
+
+ testSync.WaitForAndIncrement(3);
+ }
+}
diff --git a/library/cpp/messagebus/rain_check/core/env.cpp b/library/cpp/messagebus/rain_check/core/env.cpp
new file mode 100644
index 0000000000..fdc0000dbd
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/env.cpp
@@ -0,0 +1,3 @@
+#include "env.h"
+
+using namespace NRainCheck;
diff --git a/library/cpp/messagebus/rain_check/core/env.h b/library/cpp/messagebus/rain_check/core/env.h
new file mode 100644
index 0000000000..f6dd7fceb6
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/env.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "sleep.h"
+#include "spawn.h"
+
+#include <library/cpp/messagebus/actor/executor.h>
+
+#include <util/generic/ptr.h>
+
+namespace NRainCheck {
+ struct IEnv {
+ virtual ::NActor::TExecutor* GetExecutor() = 0;
+ virtual ~IEnv() {
+ }
+ };
+
+ template <typename TSelf>
+ struct TEnvTemplate: public IEnv {
+ template <typename TTask, typename TParam>
+ TIntrusivePtr<typename TTask::TTaskRunner> SpawnTask(TParam param) {
+ return ::NRainCheck::SpawnTask<TTask, TSelf>((TSelf*)this, param);
+ }
+ };
+
+ template <typename TSelf>
+ struct TSimpleEnvTemplate: public TEnvTemplate<TSelf> {
+ ::NActor::TExecutorPtr Executor;
+ TSleepService SleepService;
+
+ TSimpleEnvTemplate(unsigned threadCount = 0)
+ : Executor(new ::NActor::TExecutor(threadCount != 0 ? threadCount : 4))
+ {
+ }
+
+ ::NActor::TExecutor* GetExecutor() override {
+ return Executor.Get();
+ }
+ };
+
+ struct TSimpleEnv: public TSimpleEnvTemplate<TSimpleEnv> {
+ TSimpleEnv(unsigned threadCount = 0)
+ : TSimpleEnvTemplate<TSimpleEnv>(threadCount)
+ {
+ }
+ };
+
+}
diff --git a/library/cpp/messagebus/rain_check/core/fwd.h b/library/cpp/messagebus/rain_check/core/fwd.h
new file mode 100644
index 0000000000..b43ff8c17c
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/fwd.h
@@ -0,0 +1,18 @@
+#pragma once
+
+namespace NRainCheck {
+ namespace NPrivate {
+ }
+
+ class ITaskBase;
+ class ISimpleTask;
+ class ICoroTask;
+
+ struct ISubtaskListener;
+
+ class TTaskRunnerBase;
+
+ class TSubtaskCompletion;
+ struct IEnv;
+
+}
diff --git a/library/cpp/messagebus/rain_check/core/rain_check.cpp b/library/cpp/messagebus/rain_check/core/rain_check.cpp
new file mode 100644
index 0000000000..2ea1f9e21b
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/rain_check.cpp
@@ -0,0 +1 @@
+#include "rain_check.h"
diff --git a/library/cpp/messagebus/rain_check/core/rain_check.h b/library/cpp/messagebus/rain_check/core/rain_check.h
new file mode 100644
index 0000000000..0f289717a2
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/rain_check.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "coro.h"
+#include "env.h"
+#include "simple.h"
+#include "sleep.h"
+#include "spawn.h"
+#include "task.h"
diff --git a/library/cpp/messagebus/rain_check/core/simple.cpp b/library/cpp/messagebus/rain_check/core/simple.cpp
new file mode 100644
index 0000000000..70182b2f93
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/simple.cpp
@@ -0,0 +1,18 @@
+#include "simple.h"
+
+using namespace NRainCheck;
+
+TSimpleTaskRunner::TSimpleTaskRunner(IEnv* env, ISubtaskListener* parentTask, TAutoPtr<ISimpleTask> impl)
+ : TTaskRunnerBase(env, parentTask, impl.Release())
+ , ContinueFunc(&ISimpleTask::Start)
+{
+}
+
+TSimpleTaskRunner::~TSimpleTaskRunner() {
+ Y_ASSERT(!ContinueFunc);
+}
+
+bool TSimpleTaskRunner::ReplyReceived() {
+ ContinueFunc = (GetImpl()->*(ContinueFunc.Func))();
+ return !!ContinueFunc;
+}
diff --git a/library/cpp/messagebus/rain_check/core/simple.h b/library/cpp/messagebus/rain_check/core/simple.h
new file mode 100644
index 0000000000..20e1bf19f5
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/simple.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include "task.h"
+
+namespace NRainCheck {
+ class ISimpleTask;
+
+ // Function called on continue
+ class TContinueFunc {
+ friend class TSimpleTaskRunner;
+
+ typedef TContinueFunc (ISimpleTask::*TFunc)();
+ TFunc Func;
+
+ public:
+ TContinueFunc()
+ : Func(nullptr)
+ {
+ }
+
+ TContinueFunc(void*)
+ : Func(nullptr)
+ {
+ }
+
+ template <typename TTask>
+ TContinueFunc(TContinueFunc (TTask::*func)())
+ : Func((TFunc)func)
+ {
+ static_assert((std::is_base_of<ISimpleTask, TTask>::value), "expect (std::is_base_of<ISimpleTask, TTask>::value)");
+ }
+
+ bool operator!() const {
+ return !Func;
+ }
+ };
+
+ class TSimpleTaskRunner: public TTaskRunnerBase {
+ public:
+ TSimpleTaskRunner(IEnv* env, ISubtaskListener* parentTask, TAutoPtr<ISimpleTask>);
+ ~TSimpleTaskRunner() override;
+
+ private:
+ // Function to be called on completion of all pending tasks.
+ TContinueFunc ContinueFunc;
+
+ bool ReplyReceived() override /* override */;
+
+ ISimpleTask* GetImpl() {
+ return (ISimpleTask*)GetImplBase();
+ }
+ };
+
+ class ISimpleTask: public ITaskBase {
+ public:
+ typedef TSimpleTaskRunner TTaskRunner;
+ typedef ISimpleTask ITask;
+
+ virtual TContinueFunc Start() = 0;
+ };
+
+}
diff --git a/library/cpp/messagebus/rain_check/core/simple_ut.cpp b/library/cpp/messagebus/rain_check/core/simple_ut.cpp
new file mode 100644
index 0000000000..d4545e05aa
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/simple_ut.cpp
@@ -0,0 +1,59 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/messagebus/rain_check/test/ut/test.h>
+
+#include <library/cpp/messagebus/latch.h>
+
+#include <util/system/event.h>
+
+using namespace NRainCheck;
+
+Y_UNIT_TEST_SUITE(RainCheckSimple) {
+ struct TTaskWithCompletionCallback: public ISimpleTask {
+ TTestEnv* const Env;
+ TTestSync* const TestSync;
+
+ TTaskWithCompletionCallback(TTestEnv* env, TTestSync* testSync)
+ : Env(env)
+ , TestSync(testSync)
+ {
+ }
+
+ TSubtaskCompletion SleepCompletion;
+
+ TContinueFunc Start() override {
+ TestSync->CheckAndIncrement(0);
+
+ Env->SleepService.Sleep(&SleepCompletion, TDuration::MilliSeconds(1));
+ SleepCompletion.SetCompletionCallback(&TTaskWithCompletionCallback::SleepCompletionCallback);
+
+ return &TTaskWithCompletionCallback::Last;
+ }
+
+ void SleepCompletionCallback(TSubtaskCompletion* completion) {
+ Y_VERIFY(completion == &SleepCompletion);
+ TestSync->CheckAndIncrement(1);
+
+ Env->SleepService.Sleep(&SleepCompletion, TDuration::MilliSeconds(1));
+ SleepCompletion.SetCompletionCallback(&TTaskWithCompletionCallback::NextSleepCompletionCallback);
+ }
+
+ void NextSleepCompletionCallback(TSubtaskCompletion*) {
+ TestSync->CheckAndIncrement(2);
+ }
+
+ TContinueFunc Last() {
+ TestSync->CheckAndIncrement(3);
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(CompletionCallback) {
+ TTestEnv env;
+ TTestSync testSync;
+
+ env.SpawnTask<TTaskWithCompletionCallback>(&testSync);
+
+ testSync.WaitForAndIncrement(4);
+ }
+}
diff --git a/library/cpp/messagebus/rain_check/core/sleep.cpp b/library/cpp/messagebus/rain_check/core/sleep.cpp
new file mode 100644
index 0000000000..f5d0b4cac9
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/sleep.cpp
@@ -0,0 +1,47 @@
+#include "rain_check.h"
+
+#include <util/system/yassert.h>
+
+using namespace NRainCheck;
+using namespace NRainCheck::NPrivate;
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+TSleepService::TSleepService(::NBus::NPrivate::TScheduler* scheduler)
+ : Scheduler(scheduler)
+{
+}
+
+NRainCheck::TSleepService::TSleepService()
+ : SchedulerHolder(new TScheduler)
+ , Scheduler(SchedulerHolder.Get())
+{
+}
+
+NRainCheck::TSleepService::~TSleepService() {
+ if (!!SchedulerHolder) {
+ Scheduler->Stop();
+ }
+}
+
+namespace {
+ struct TSleepServiceScheduleItem: public IScheduleItem {
+ ISubtaskListener* const Parent;
+
+ TSleepServiceScheduleItem(ISubtaskListener* parent, TInstant time)
+ : IScheduleItem(time)
+ , Parent(parent)
+ {
+ }
+
+ void Do() override {
+ Parent->SetDone();
+ }
+ };
+}
+
+void TSleepService::Sleep(TSubtaskCompletion* r, TDuration duration) {
+ TTaskRunnerBase* current = TTaskRunnerBase::CurrentTask();
+ r->SetRunning(current);
+ Scheduler->Schedule(new TSleepServiceScheduleItem(r, TInstant::Now() + duration));
+}
diff --git a/library/cpp/messagebus/rain_check/core/sleep.h b/library/cpp/messagebus/rain_check/core/sleep.h
new file mode 100644
index 0000000000..1a7a1f8674
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/sleep.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "fwd.h"
+
+#include <library/cpp/messagebus/scheduler/scheduler.h>
+
+#include <util/datetime/base.h>
+
+namespace NRainCheck {
+ class TSleepService {
+ private:
+ THolder< ::NBus::NPrivate::TScheduler> SchedulerHolder;
+ ::NBus::NPrivate::TScheduler* const Scheduler;
+
+ public:
+ TSleepService(::NBus::NPrivate::TScheduler*);
+ TSleepService();
+ ~TSleepService();
+
+ // Wake up a task after given duration.
+ void Sleep(TSubtaskCompletion* r, TDuration);
+ };
+
+}
diff --git a/library/cpp/messagebus/rain_check/core/sleep_ut.cpp b/library/cpp/messagebus/rain_check/core/sleep_ut.cpp
new file mode 100644
index 0000000000..2ae85a87b1
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/sleep_ut.cpp
@@ -0,0 +1,46 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/messagebus/rain_check/test/ut/test.h>
+
+#include <util/system/event.h>
+
+using namespace NRainCheck;
+using namespace NActor;
+
+Y_UNIT_TEST_SUITE(Sleep) {
+ struct TTestTask: public ISimpleTask {
+ TSimpleEnv* const Env;
+ TTestSync* const TestSync;
+
+ TTestTask(TSimpleEnv* env, TTestSync* testSync)
+ : Env(env)
+ , TestSync(testSync)
+ {
+ }
+
+ TSubtaskCompletion Sleep;
+
+ TContinueFunc Start() override {
+ Env->SleepService.Sleep(&Sleep, TDuration::MilliSeconds(1));
+
+ TestSync->CheckAndIncrement(0);
+
+ return &TTestTask::Continue;
+ }
+
+ TContinueFunc Continue() {
+ TestSync->CheckAndIncrement(1);
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(Test) {
+ TTestSync testSync;
+
+ TSimpleEnv env;
+
+ TIntrusivePtr<TSimpleTaskRunner> task = env.SpawnTask<TTestTask>(&testSync);
+
+ testSync.WaitForAndIncrement(2);
+ }
+}
diff --git a/library/cpp/messagebus/rain_check/core/spawn.cpp b/library/cpp/messagebus/rain_check/core/spawn.cpp
new file mode 100644
index 0000000000..c570355fbe
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/spawn.cpp
@@ -0,0 +1,5 @@
+#include "spawn.h"
+
+void NRainCheck::NPrivate::SpawnTaskImpl(TTaskRunnerBase* task) {
+ task->Schedule();
+}
diff --git a/library/cpp/messagebus/rain_check/core/spawn.h b/library/cpp/messagebus/rain_check/core/spawn.h
new file mode 100644
index 0000000000..f2b146bf29
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/spawn.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include "coro.h"
+#include "simple.h"
+#include "task.h"
+
+namespace NRainCheck {
+ namespace NPrivate {
+ void SpawnTaskImpl(TTaskRunnerBase* task);
+
+ template <typename TTask, typename ITask, typename TRunner, typename TEnv, typename TParam>
+ TIntrusivePtr<TRunner> SpawnTaskWithRunner(TEnv* env, TParam param1, ISubtaskListener* subtaskListener) {
+ static_assert((std::is_base_of<ITask, TTask>::value), "expect (std::is_base_of<ITask, TTask>::value)");
+ TIntrusivePtr<TRunner> task(new TRunner(env, subtaskListener, new TTask(env, param1)));
+ NPrivate::SpawnTaskImpl(task.Get());
+ return task;
+ }
+
+ template <typename TTask, typename ITask, typename TRunner, typename TEnv>
+ void SpawnSubtaskWithRunner(TEnv* env, TSubtaskCompletion* completion) {
+ static_assert((std::is_base_of<ITask, TTask>::value), "expect (std::is_base_of<ITask, TTask>::value)");
+ TTaskRunnerBase* current = TTaskRunnerBase::CurrentTask();
+ completion->SetRunning(current);
+ NPrivate::SpawnTaskImpl(new TRunner(env, completion, new TTask(env)));
+ }
+
+ template <typename TTask, typename ITask, typename TRunner, typename TEnv, typename TParam>
+ void SpawnSubtaskWithRunner(TEnv* env, TSubtaskCompletion* completion, TParam param) {
+ static_assert((std::is_base_of<ITask, TTask>::value), "expect (std::is_base_of<ITask, TTask>::value)");
+ TTaskRunnerBase* current = TTaskRunnerBase::CurrentTask();
+ completion->SetRunning(current);
+ NPrivate::SpawnTaskImpl(new TRunner(env, completion, new TTask(env, param)));
+ }
+
+ }
+
+ // Instantiate and start a task with given parameter.
+ template <typename TTask, typename TEnv, typename TParam>
+ TIntrusivePtr<typename TTask::TTaskRunner> SpawnTask(TEnv* env, TParam param1, ISubtaskListener* subtaskListener = &TNopSubtaskListener::Instance) {
+ return NPrivate::SpawnTaskWithRunner<
+ TTask, typename TTask::ITask, typename TTask::TTaskRunner, TEnv, TParam>(env, param1, subtaskListener);
+ }
+
+ // Instantiate and start subtask of given task.
+ template <typename TTask, typename TEnv, typename TParam>
+ void SpawnSubtask(TEnv* env, TSubtaskCompletion* completion, TParam param) {
+ return NPrivate::SpawnSubtaskWithRunner<TTask, typename TTask::ITask, typename TTask::TTaskRunner>(env, completion, param);
+ }
+
+}
diff --git a/library/cpp/messagebus/rain_check/core/spawn_ut.cpp b/library/cpp/messagebus/rain_check/core/spawn_ut.cpp
new file mode 100644
index 0000000000..ba5a5e41cf
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/spawn_ut.cpp
@@ -0,0 +1,145 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/messagebus/rain_check/test/helper/misc.h>
+#include <library/cpp/messagebus/rain_check/test/ut/test.h>
+
+#include <library/cpp/messagebus/latch.h>
+
+#include <util/system/event.h>
+
+#include <array>
+
+using namespace NRainCheck;
+using namespace NActor;
+
+Y_UNIT_TEST_SUITE(Spawn) {
+ struct TTestTask: public ISimpleTask {
+ TTestSync* const TestSync;
+
+ TTestTask(TSimpleEnv*, TTestSync* testSync)
+ : TestSync(testSync)
+ , I(0)
+ {
+ }
+
+ TSystemEvent Started;
+
+ unsigned I;
+
+ TContinueFunc Start() override {
+ if (I < 4) {
+ I += 1;
+ return &TTestTask::Start;
+ }
+ TestSync->CheckAndIncrement(0);
+ return &TTestTask::Continue;
+ }
+
+ TContinueFunc Continue() {
+ TestSync->CheckAndIncrement(1);
+
+ Started.Signal();
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(Continuation) {
+ TTestSync testSync;
+
+ TSimpleEnv env;
+
+ TIntrusivePtr<TSimpleTaskRunner> task = env.SpawnTask<TTestTask>(&testSync);
+
+ testSync.WaitForAndIncrement(2);
+ }
+
+ struct TSubtask: public ISimpleTask {
+ TTestEnv* const Env;
+ TTestSync* const TestSync;
+
+ TSubtask(TTestEnv* env, TTestSync* testSync)
+ : Env(env)
+ , TestSync(testSync)
+ {
+ }
+
+ TContinueFunc Start() override {
+ Sleep(TDuration::MilliSeconds(1));
+ TestSync->CheckAndIncrement(1);
+ return nullptr;
+ }
+ };
+
+ struct TSpawnTask: public ISimpleTask {
+ TTestEnv* const Env;
+ TTestSync* const TestSync;
+
+ TSpawnTask(TTestEnv* env, TTestSync* testSync)
+ : Env(env)
+ , TestSync(testSync)
+ {
+ }
+
+ TSubtaskCompletion SubtaskCompletion;
+
+ TContinueFunc Start() override {
+ TestSync->CheckAndIncrement(0);
+ SpawnSubtask<TSubtask>(Env, &SubtaskCompletion, TestSync);
+ return &TSpawnTask::Continue;
+ }
+
+ TContinueFunc Continue() {
+ TestSync->CheckAndIncrement(2);
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(Subtask) {
+ TTestSync testSync;
+
+ TTestEnv env;
+
+ TIntrusivePtr<TSimpleTaskRunner> task = env.SpawnTask<TSpawnTask>(&testSync);
+
+ testSync.WaitForAndIncrement(3);
+ }
+
+ struct TSpawnLongTask: public ISimpleTask {
+ TTestEnv* const Env;
+ TTestSync* const TestSync;
+ unsigned I;
+
+ TSpawnLongTask(TTestEnv* env, TTestSync* testSync)
+ : Env(env)
+ , TestSync(testSync)
+ , I(0)
+ {
+ }
+
+ std::array<TSubtaskCompletion, 3> Subtasks;
+
+ TContinueFunc Start() override {
+ if (I == 1000) {
+ TestSync->CheckAndIncrement(0);
+ return nullptr;
+ }
+
+ for (auto& subtask : Subtasks) {
+ SpawnSubtask<TNopSimpleTask>(Env, &subtask, "");
+ }
+
+ ++I;
+ return &TSpawnLongTask::Start;
+ }
+ };
+
+ Y_UNIT_TEST(SubtaskLong) {
+ TTestSync testSync;
+
+ TTestEnv env;
+
+ TIntrusivePtr<TSimpleTaskRunner> task = env.SpawnTask<TSpawnLongTask>(&testSync);
+
+ testSync.WaitForAndIncrement(1);
+ }
+}
diff --git a/library/cpp/messagebus/rain_check/core/task.cpp b/library/cpp/messagebus/rain_check/core/task.cpp
new file mode 100644
index 0000000000..a098437d53
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/task.cpp
@@ -0,0 +1,216 @@
+#include "rain_check.h"
+
+#include <library/cpp/messagebus/actor/temp_tls_vector.h>
+
+#include <util/system/type_name.h>
+#include <util/system/tls.h>
+
+using namespace NRainCheck;
+using namespace NRainCheck::NPrivate;
+
+using namespace NActor;
+
+namespace {
+ Y_POD_STATIC_THREAD(TTaskRunnerBase*)
+ ThreadCurrentTask;
+}
+
+void TNopSubtaskListener::SetDone() {
+}
+
+TNopSubtaskListener TNopSubtaskListener::Instance;
+
+TTaskRunnerBase::TTaskRunnerBase(IEnv* env, ISubtaskListener* parentTask, TAutoPtr<ITaskBase> impl)
+ : TActor<TTaskRunnerBase>(env->GetExecutor())
+ , Impl(impl)
+ , ParentTask(parentTask)
+ //, HoldsSelfReference(false)
+ , Done(false)
+ , SetDoneCalled(false)
+{
+}
+
+TTaskRunnerBase::~TTaskRunnerBase() {
+ Y_ASSERT(Done);
+}
+
+namespace {
+ struct TRunningInThisThreadGuard {
+ TTaskRunnerBase* const Task;
+ TRunningInThisThreadGuard(TTaskRunnerBase* task)
+ : Task(task)
+ {
+ Y_ASSERT(!ThreadCurrentTask);
+ ThreadCurrentTask = task;
+ }
+
+ ~TRunningInThisThreadGuard() {
+ Y_ASSERT(ThreadCurrentTask == Task);
+ ThreadCurrentTask = nullptr;
+ }
+ };
+}
+
+void NRainCheck::TTaskRunnerBase::Act(NActor::TDefaultTag) {
+ Y_ASSERT(RefCount() > 0);
+
+ TRunningInThisThreadGuard g(this);
+
+ //RetainRef();
+
+ for (;;) {
+ TTempTlsVector<TSubtaskCompletion*> temp;
+
+ temp.GetVector()->swap(Pending);
+
+ for (auto& pending : *temp.GetVector()) {
+ if (pending->IsComplete()) {
+ pending->FireCompletionCallback(GetImplBase());
+ } else {
+ Pending.push_back(pending);
+ }
+ }
+
+ if (!Pending.empty()) {
+ return;
+ }
+
+ if (!Done) {
+ Done = !ReplyReceived();
+ } else {
+ if (Pending.empty()) {
+ if (!SetDoneCalled) {
+ ParentTask->SetDone();
+ SetDoneCalled = true;
+ }
+ //ReleaseRef();
+ return;
+ }
+ }
+ }
+}
+
+bool TTaskRunnerBase::IsRunningInThisThread() const {
+ return ThreadCurrentTask == this;
+}
+
+TSubtaskCompletion::~TSubtaskCompletion() {
+ ESubtaskState state = State.Get();
+ Y_ASSERT(state == CREATED || state == DONE || state == CANCELED);
+}
+
+void TSubtaskCompletion::FireCompletionCallback(ITaskBase* task) {
+ Y_ASSERT(IsComplete());
+
+ if (!!CompletionFunc) {
+ TSubtaskCompletionFunc temp = CompletionFunc;
+ // completion func must be reset before calling it,
+ // because function may set it back
+ CompletionFunc = TSubtaskCompletionFunc();
+ (task->*(temp.Func))(this);
+ }
+}
+
+void NRainCheck::TSubtaskCompletion::Cancel() {
+ for (;;) {
+ ESubtaskState state = State.Get();
+ if (state == CREATED && State.CompareAndSet(CREATED, CANCELED)) {
+ return;
+ }
+ if (state == RUNNING && State.CompareAndSet(RUNNING, CANCEL_REQUESTED)) {
+ return;
+ }
+ if (state == DONE && State.CompareAndSet(DONE, CANCELED)) {
+ return;
+ }
+ if (state == CANCEL_REQUESTED || state == CANCELED) {
+ return;
+ }
+ }
+}
+
+void TSubtaskCompletion::SetRunning(TTaskRunnerBase* parent) {
+ Y_ASSERT(!TaskRunner);
+ Y_ASSERT(!!parent);
+
+ TaskRunner = parent;
+
+ parent->Pending.push_back(this);
+
+ parent->RefV();
+
+ for (;;) {
+ ESubtaskState current = State.Get();
+ if (current != CREATED && current != DONE) {
+ Y_FAIL("current state should be CREATED or DONE: %s", ToCString(current));
+ }
+ if (State.CompareAndSet(current, RUNNING)) {
+ return;
+ }
+ }
+}
+
+void TSubtaskCompletion::SetDone() {
+ Y_ASSERT(!!TaskRunner);
+ TTaskRunnerBase* temp = TaskRunner;
+ TaskRunner = nullptr;
+
+ for (;;) {
+ ESubtaskState state = State.Get();
+ if (state == RUNNING) {
+ if (State.CompareAndSet(RUNNING, DONE)) {
+ break;
+ }
+ } else if (state == CANCEL_REQUESTED) {
+ if (State.CompareAndSet(CANCEL_REQUESTED, CANCELED)) {
+ break;
+ }
+ } else {
+ Y_FAIL("cannot SetDone: unknown state: %s", ToCString(state));
+ }
+ }
+
+ temp->ScheduleV();
+ temp->UnRefV();
+}
+
+#if 0
+void NRainCheck::TTaskRunnerBase::RetainRef()
+{
+ if (HoldsSelfReference) {
+ return;
+ }
+ HoldsSelfReference = true;
+ Ref();
+}
+
+void NRainCheck::TTaskRunnerBase::ReleaseRef()
+{
+ if (!HoldsSelfReference) {
+ return;
+ }
+ HoldsSelfReference = false;
+ DecRef();
+}
+#endif
+
+void TTaskRunnerBase::AssertInThisThread() const {
+ Y_ASSERT(IsRunningInThisThread());
+}
+
+TTaskRunnerBase* TTaskRunnerBase::CurrentTask() {
+ Y_VERIFY(!!ThreadCurrentTask);
+ return ThreadCurrentTask;
+}
+
+ITaskBase* TTaskRunnerBase::CurrentTaskImpl() {
+ return CurrentTask()->GetImplBase();
+}
+
+TString TTaskRunnerBase::GetStatusSingleLine() {
+ return TypeName(*Impl);
+}
+
+bool NRainCheck::AreWeInsideTask() {
+ return ThreadCurrentTask != nullptr;
+}
diff --git a/library/cpp/messagebus/rain_check/core/task.h b/library/cpp/messagebus/rain_check/core/task.h
new file mode 100644
index 0000000000..7d8778bcda
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/task.h
@@ -0,0 +1,184 @@
+#pragma once
+
+#include "fwd.h"
+
+#include <library/cpp/messagebus/actor/actor.h>
+#include <library/cpp/messagebus/misc/atomic_box.h>
+
+#include <library/cpp/deprecated/enum_codegen/enum_codegen.h>
+
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/thread/lfstack.h>
+
+namespace NRainCheck {
+ struct ISubtaskListener {
+ virtual void SetDone() = 0;
+ virtual ~ISubtaskListener() {
+ }
+ };
+
+ struct TNopSubtaskListener: public ISubtaskListener {
+ void SetDone() override;
+
+ static TNopSubtaskListener Instance;
+ };
+
+ class TSubtaskCompletionFunc {
+ friend class TSubtaskCompletion;
+
+ typedef void (ITaskBase::*TFunc)(TSubtaskCompletion*);
+ TFunc Func;
+
+ public:
+ TSubtaskCompletionFunc()
+ : Func(nullptr)
+ {
+ }
+
+ TSubtaskCompletionFunc(void*)
+ : Func(nullptr)
+ {
+ }
+
+ template <typename TTask>
+ TSubtaskCompletionFunc(void (TTask::*func)(TSubtaskCompletion*))
+ : Func((TFunc)func)
+ {
+ static_assert((std::is_base_of<ITaskBase, TTask>::value), "expect (std::is_base_of<ITaskBase, TTask>::value)");
+ }
+
+ bool operator!() const {
+ return !Func;
+ }
+ };
+
+ template <typename T>
+ class TTaskFuture;
+
+#define SUBTASK_STATE_MAP(XX) \
+ XX(CREATED, "Initial") \
+ XX(RUNNING, "Running") \
+ XX(DONE, "Completed") \
+ XX(CANCEL_REQUESTED, "Cancel requested, but still executing") \
+ XX(CANCELED, "Canceled") \
+ /**/
+
+ enum ESubtaskState {
+ SUBTASK_STATE_MAP(ENUM_VALUE_GEN_NO_VALUE)
+ };
+
+ ENUM_TO_STRING(ESubtaskState, SUBTASK_STATE_MAP)
+
+ class TSubtaskCompletion : TNonCopyable, public ISubtaskListener {
+ friend struct TTaskAccessor;
+
+ private:
+ TAtomicBox<ESubtaskState> State;
+ TTaskRunnerBase* volatile TaskRunner;
+ TSubtaskCompletionFunc CompletionFunc;
+
+ public:
+ TSubtaskCompletion()
+ : State(CREATED)
+ , TaskRunner()
+ {
+ }
+ ~TSubtaskCompletion() override;
+
+ // Either done or cancel requested or cancelled
+ bool IsComplete() const {
+ ESubtaskState state = State.Get();
+ switch (state) {
+ case RUNNING:
+ return false;
+ case DONE:
+ return true;
+ case CANCEL_REQUESTED:
+ return false;
+ case CANCELED:
+ return true;
+ case CREATED:
+ Y_FAIL("not started");
+ default:
+ Y_FAIL("unknown value: %u", (unsigned)state);
+ }
+ }
+
+ void FireCompletionCallback(ITaskBase*);
+
+ void SetCompletionCallback(TSubtaskCompletionFunc func) {
+ CompletionFunc = func;
+ }
+
+ // Completed, but not cancelled
+ bool IsDone() const {
+ return State.Get() == DONE;
+ }
+
+ // Request cancel by actor
+ // Does nothing but marks task cancelled,
+ // and allows proceeding to next callback
+ void Cancel();
+
+ // called by service provider implementations
+ // must not be called by actor
+ void SetRunning(TTaskRunnerBase* parent);
+ void SetDone() override;
+ };
+
+ // See ISimpleTask, ICoroTask
+ class TTaskRunnerBase: public TAtomicRefCount<TTaskRunnerBase>, public NActor::TActor<TTaskRunnerBase> {
+ friend class NActor::TActor<TTaskRunnerBase>;
+ friend class TContinueFunc;
+ friend struct TTaskAccessor;
+ friend class TSubtaskCompletion;
+
+ private:
+ THolder<ITaskBase> Impl;
+
+ ISubtaskListener* const ParentTask;
+ // While task is running, it holds extra reference to self.
+ //bool HoldsSelfReference;
+ bool Done;
+ bool SetDoneCalled;
+
+ // Subtasks currently executed.
+ TVector<TSubtaskCompletion*> Pending;
+
+ void Act(NActor::TDefaultTag);
+
+ public:
+ // Construct task. Task is not automatically started.
+ TTaskRunnerBase(IEnv*, ISubtaskListener* parent, TAutoPtr<ITaskBase> impl);
+ ~TTaskRunnerBase() override;
+
+ bool IsRunningInThisThread() const;
+ void AssertInThisThread() const;
+ static TTaskRunnerBase* CurrentTask();
+ static ITaskBase* CurrentTaskImpl();
+
+ TString GetStatusSingleLine();
+
+ protected:
+ //void RetainRef();
+ //void ReleaseRef();
+ ITaskBase* GetImplBase() {
+ return Impl.Get();
+ }
+
+ private:
+ // true if need to call again
+ virtual bool ReplyReceived() = 0;
+ };
+
+ class ITaskBase {
+ public:
+ virtual ~ITaskBase() {
+ }
+ };
+
+ // Check that current method executed inside some task.
+ bool AreWeInsideTask();
+
+}
diff --git a/library/cpp/messagebus/rain_check/core/track.cpp b/library/cpp/messagebus/rain_check/core/track.cpp
new file mode 100644
index 0000000000..092a51a214
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/track.cpp
@@ -0,0 +1,66 @@
+#include "track.h"
+
+using namespace NRainCheck;
+using namespace NRainCheck::NPrivate;
+
+void TTaskTrackerReceipt::SetDone() {
+ TaskTracker->GetQueue<TTaskTrackerReceipt*>()->EnqueueAndSchedule(this);
+}
+
+TString TTaskTrackerReceipt::GetStatusSingleLine() {
+ return Task->GetStatusSingleLine();
+}
+
+TTaskTracker::TTaskTracker(NActor::TExecutor* executor)
+ : NActor::TActor<TTaskTracker>(executor)
+{
+}
+
+TTaskTracker::~TTaskTracker() {
+ Y_ASSERT(Tasks.Empty());
+}
+
+void TTaskTracker::Shutdown() {
+ ShutdownFlag.Set(true);
+ Schedule();
+ ShutdownEvent.WaitI();
+}
+
+void TTaskTracker::ProcessItem(NActor::TDefaultTag, NActor::TDefaultTag, ITaskFactory* taskFactory) {
+ THolder<ITaskFactory> holder(taskFactory);
+
+ THolder<TTaskTrackerReceipt> receipt(new TTaskTrackerReceipt(this));
+ receipt->Task = taskFactory->NewTask(receipt.Get());
+
+ Tasks.PushBack(receipt.Release());
+}
+
+void TTaskTracker::ProcessItem(NActor::TDefaultTag, NActor::TDefaultTag, TTaskTrackerReceipt* receipt) {
+ Y_ASSERT(!receipt->Empty());
+ receipt->Unlink();
+ delete receipt;
+}
+
+void TTaskTracker::ProcessItem(NActor::TDefaultTag, NActor::TDefaultTag, TAsyncResult<TTaskTrackerStatus>* status) {
+ TTaskTrackerStatus s;
+ s.Size = Tasks.Size();
+ status->SetResult(s);
+}
+
+void TTaskTracker::Act(NActor::TDefaultTag) {
+ GetQueue<TAsyncResult<TTaskTrackerStatus>*>()->DequeueAll();
+ GetQueue<ITaskFactory*>()->DequeueAll();
+ GetQueue<TTaskTrackerReceipt*>()->DequeueAll();
+
+ if (ShutdownFlag.Get()) {
+ if (Tasks.Empty()) {
+ ShutdownEvent.Signal();
+ }
+ }
+}
+
+ui32 TTaskTracker::Size() {
+ TAsyncResult<TTaskTrackerStatus> r;
+ GetQueue<TAsyncResult<TTaskTrackerStatus>*>()->EnqueueAndSchedule(&r);
+ return r.GetResult().Size;
+}
diff --git a/library/cpp/messagebus/rain_check/core/track.h b/library/cpp/messagebus/rain_check/core/track.h
new file mode 100644
index 0000000000..d387de7574
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/track.h
@@ -0,0 +1,97 @@
+#pragma once
+
+#include "spawn.h"
+#include "task.h"
+
+#include <library/cpp/messagebus/async_result.h>
+#include <library/cpp/messagebus/actor/queue_in_actor.h>
+#include <library/cpp/messagebus/misc/atomic_box.h>
+
+#include <util/generic/intrlist.h>
+#include <util/system/event.h>
+
+namespace NRainCheck {
+ class TTaskTracker;
+
+ namespace NPrivate {
+ struct ITaskFactory {
+ virtual TIntrusivePtr<TTaskRunnerBase> NewTask(ISubtaskListener*) = 0;
+ virtual ~ITaskFactory() {
+ }
+ };
+
+ struct TTaskTrackerReceipt: public ISubtaskListener, public TIntrusiveListItem<TTaskTrackerReceipt> {
+ TTaskTracker* const TaskTracker;
+ TIntrusivePtr<TTaskRunnerBase> Task;
+
+ TTaskTrackerReceipt(TTaskTracker* taskTracker)
+ : TaskTracker(taskTracker)
+ {
+ }
+
+ void SetDone() override;
+
+ TString GetStatusSingleLine();
+ };
+
+ struct TTaskTrackerStatus {
+ ui32 Size;
+ };
+
+ }
+
+ class TTaskTracker
+ : public TAtomicRefCount<TTaskTracker>,
+ public NActor::TActor<TTaskTracker>,
+ public NActor::TQueueInActor<TTaskTracker, NPrivate::ITaskFactory*>,
+ public NActor::TQueueInActor<TTaskTracker, NPrivate::TTaskTrackerReceipt*>,
+ public NActor::TQueueInActor<TTaskTracker, TAsyncResult<NPrivate::TTaskTrackerStatus>*> {
+ friend struct NPrivate::TTaskTrackerReceipt;
+
+ private:
+ TAtomicBox<bool> ShutdownFlag;
+ TSystemEvent ShutdownEvent;
+
+ TIntrusiveList<NPrivate::TTaskTrackerReceipt> Tasks;
+
+ template <typename TItem>
+ NActor::TQueueInActor<TTaskTracker, TItem>* GetQueue() {
+ return this;
+ }
+
+ public:
+ TTaskTracker(NActor::TExecutor* executor);
+ ~TTaskTracker() override;
+
+ void Shutdown();
+
+ void ProcessItem(NActor::TDefaultTag, NActor::TDefaultTag, NPrivate::ITaskFactory*);
+ void ProcessItem(NActor::TDefaultTag, NActor::TDefaultTag, NPrivate::TTaskTrackerReceipt*);
+ void ProcessItem(NActor::TDefaultTag, NActor::TDefaultTag, TAsyncResult<NPrivate::TTaskTrackerStatus>*);
+
+ void Act(NActor::TDefaultTag);
+
+ template <typename TTask, typename TEnv, typename TParam>
+ void Spawn(TEnv* env, TParam param) {
+ struct TTaskFactory: public NPrivate::ITaskFactory {
+ TEnv* const Env;
+ TParam Param;
+
+ TTaskFactory(TEnv* env, TParam param)
+ : Env(env)
+ , Param(param)
+ {
+ }
+
+ TIntrusivePtr<TTaskRunnerBase> NewTask(ISubtaskListener* subtaskListener) override {
+ return NRainCheck::SpawnTask<TTask>(Env, Param, subtaskListener).Get();
+ }
+ };
+
+ GetQueue<NPrivate::ITaskFactory*>()->EnqueueAndSchedule(new TTaskFactory(env, param));
+ }
+
+ ui32 Size();
+ };
+
+}
diff --git a/library/cpp/messagebus/rain_check/core/track_ut.cpp b/library/cpp/messagebus/rain_check/core/track_ut.cpp
new file mode 100644
index 0000000000..05f7de1319
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/track_ut.cpp
@@ -0,0 +1,45 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "track.h"
+
+#include <library/cpp/messagebus/rain_check/test/helper/misc.h>
+#include <library/cpp/messagebus/rain_check/test/ut/test.h>
+
+using namespace NRainCheck;
+
+Y_UNIT_TEST_SUITE(TaskTracker) {
+ struct TTaskForTracker: public ISimpleTask {
+ TTestSync* const TestSync;
+
+ TTaskForTracker(TTestEnv*, TTestSync* testSync)
+ : TestSync(testSync)
+ {
+ }
+
+ TContinueFunc Start() override {
+ TestSync->WaitForAndIncrement(0);
+ TestSync->WaitForAndIncrement(2);
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(Simple) {
+ TTestEnv env;
+
+ TIntrusivePtr<TTaskTracker> tracker(new TTaskTracker(env.GetExecutor()));
+
+ TTestSync testSync;
+
+ tracker->Spawn<TTaskForTracker>(&env, &testSync);
+
+ testSync.WaitFor(1);
+
+ UNIT_ASSERT_VALUES_EQUAL(1u, tracker->Size());
+
+ testSync.CheckAndIncrement(1);
+
+ testSync.WaitForAndIncrement(3);
+
+ tracker->Shutdown();
+ }
+}
diff --git a/library/cpp/messagebus/rain_check/core/ya.make b/library/cpp/messagebus/rain_check/core/ya.make
new file mode 100644
index 0000000000..c6fb5640d4
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/core/ya.make
@@ -0,0 +1,25 @@
+LIBRARY()
+
+OWNER(g:messagebus)
+
+PEERDIR(
+ library/cpp/coroutine/engine
+ library/cpp/deprecated/enum_codegen
+ library/cpp/messagebus
+ library/cpp/messagebus/actor
+ library/cpp/messagebus/scheduler
+)
+
+SRCS(
+ coro.cpp
+ coro_stack.cpp
+ env.cpp
+ rain_check.cpp
+ simple.cpp
+ sleep.cpp
+ spawn.cpp
+ task.cpp
+ track.cpp
+)
+
+END()
diff --git a/library/cpp/messagebus/rain_check/http/client.cpp b/library/cpp/messagebus/rain_check/http/client.cpp
new file mode 100644
index 0000000000..5ef5ceeece
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/http/client.cpp
@@ -0,0 +1,154 @@
+#include "client.h"
+
+#include "http_code_extractor.h"
+
+#include <library/cpp/http/io/stream.h>
+#include <library/cpp/neh/factory.h>
+#include <library/cpp/neh/http_common.h>
+#include <library/cpp/neh/location.h>
+#include <library/cpp/neh/neh.h>
+
+#include <util/generic/ptr.h>
+#include <util/generic/strbuf.h>
+#include <util/network/socket.h>
+#include <util/stream/str.h>
+
+namespace NRainCheck {
+ class THttpCallback: public NNeh::IOnRecv {
+ public:
+ THttpCallback(NRainCheck::THttpFuture* future)
+ : Future(future)
+ {
+ Y_VERIFY(!!future, "future is NULL");
+ }
+
+ void OnRecv(NNeh::THandle& handle) override {
+ THolder<THttpCallback> self(this);
+ NNeh::TResponseRef response = handle.Get();
+ Future->SetDoneAndSchedule(response);
+ }
+
+ private:
+ NRainCheck::THttpFuture* const Future;
+ };
+
+ THttpFuture::THttpFuture()
+ : Task(nullptr)
+ , ErrorCode(THttpFuture::NoError)
+ {
+ }
+
+ THttpFuture::~THttpFuture() {
+ }
+
+ bool THttpFuture::HasError() const {
+ return (ErrorCode != THttpFuture::NoError);
+ }
+
+ THttpFuture::EError THttpFuture::GetErrorCode() const {
+ return ErrorCode;
+ }
+
+ TString THttpFuture::GetErrorDescription() const {
+ return ErrorDescription;
+ }
+
+ THttpClientService::THttpClientService()
+ : GetProtocol(NNeh::ProtocolFactory()->Protocol("http"))
+ , FullProtocol(NNeh::ProtocolFactory()->Protocol("full"))
+ {
+ Y_VERIFY(!!GetProtocol, "GET protocol is NULL.");
+ Y_VERIFY(!!FullProtocol, "POST protocol is NULL.");
+ }
+
+ THttpClientService::~THttpClientService() {
+ }
+
+ void THttpClientService::SendPost(TString addr, const TString& data, const THttpHeaders& headers, THttpFuture* future) {
+ Y_VERIFY(!!future, "future is NULL.");
+
+ TTaskRunnerBase* current = TTaskRunnerBase::CurrentTask();
+ future->SetRunning(current);
+ future->Task = current;
+
+ THolder<THttpCallback> callback(new THttpCallback(future));
+ NNeh::TServiceStatRef stat;
+ try {
+ NNeh::TMessage msg(addr.replace(0, NNeh::TParsedLocation(addr).Scheme.size(), "post"), data);
+ TStringStream headersText;
+ headers.OutTo(&headersText);
+ NNeh::NHttp::MakeFullRequest(msg, headersText.Str(), TString());
+ FullProtocol->ScheduleRequest(msg, callback.Get(), stat);
+ Y_UNUSED(callback.Release());
+ } catch (const TNetworkResolutionError& err) {
+ future->SetFail(THttpFuture::CantResolveNameError, err.AsStrBuf());
+ } catch (const yexception& err) {
+ future->SetFail(THttpFuture::OtherError, err.AsStrBuf());
+ }
+ }
+
+ void THttpClientService::Send(const TString& request, THttpFuture* future) {
+ Y_VERIFY(!!future, "future is NULL.");
+
+ TTaskRunnerBase* current = TTaskRunnerBase::CurrentTask();
+ future->SetRunning(current);
+ future->Task = current;
+
+ THolder<THttpCallback> callback(new THttpCallback(future));
+ NNeh::TServiceStatRef stat;
+ try {
+ GetProtocol->ScheduleRequest(NNeh::TMessage::FromString(request),
+ callback.Get(),
+ stat);
+ Y_UNUSED(callback.Release());
+ } catch (const TNetworkResolutionError& err) {
+ future->SetFail(THttpFuture::CantResolveNameError, err.AsStrBuf());
+ } catch (const yexception& err) {
+ future->SetFail(THttpFuture::OtherError, err.AsStrBuf());
+ }
+ }
+
+ bool THttpFuture::HasHttpCode() const {
+ return !!HttpCode;
+ }
+
+ bool THttpFuture::HasResponseBody() const {
+ return !!Response;
+ }
+
+ ui32 THttpFuture::GetHttpCode() const {
+ Y_ASSERT(IsDone());
+ Y_ASSERT(HasHttpCode());
+
+ return static_cast<ui32>(*HttpCode);
+ }
+
+ TString THttpFuture::GetResponseBody() const {
+ Y_ASSERT(IsDone());
+ Y_ASSERT(HasResponseBody());
+
+ return Response->Data;
+ }
+
+ void THttpFuture::SetDoneAndSchedule(TAutoPtr<NNeh::TResponse> response) {
+ if (!response->IsError()) {
+ ErrorCode = THttpFuture::NoError;
+ HttpCode = HttpCodes::HTTP_OK;
+ } else {
+ ErrorCode = THttpFuture::BadHttpCodeError;
+ ErrorDescription = response->GetErrorText();
+
+ HttpCode = TryGetHttpCodeFromErrorDescription(ErrorDescription);
+ }
+ Response.Reset(response);
+ SetDone();
+ }
+
+ void THttpFuture::SetFail(THttpFuture::EError errorCode, const TStringBuf& errorDescription) {
+ ErrorCode = errorCode;
+ ErrorDescription = errorDescription;
+ Response.Destroy();
+ SetDone();
+ }
+
+}
diff --git a/library/cpp/messagebus/rain_check/http/client.h b/library/cpp/messagebus/rain_check/http/client.h
new file mode 100644
index 0000000000..d4199c4c98
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/http/client.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include <library/cpp/messagebus/rain_check/core/task.h>
+
+#include <library/cpp/http/misc/httpcodes.h>
+
+#include <util/generic/maybe.h>
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+#include <util/system/defaults.h>
+#include <util/system/yassert.h>
+
+class THttpHeaders;
+
+namespace NNeh {
+ class IProtocol;
+ struct TResponse;
+}
+
+namespace NRainCheck {
+ class THttpCallback;
+ class THttpClientService;
+
+ class THttpFuture: public TSubtaskCompletion {
+ public:
+ enum EError {
+ NoError = 0,
+
+ CantResolveNameError = 1,
+ BadHttpCodeError = 2,
+
+ OtherError = 100
+ };
+
+ private:
+ friend class THttpCallback;
+ friend class THttpClientService;
+
+ public:
+ THttpFuture();
+ ~THttpFuture() override;
+
+ bool HasHttpCode() const;
+ bool HasResponseBody() const;
+
+ ui32 GetHttpCode() const;
+ TString GetResponseBody() const;
+
+ bool HasError() const;
+ EError GetErrorCode() const;
+ TString GetErrorDescription() const;
+
+ private:
+ void SetDoneAndSchedule(TAutoPtr<NNeh::TResponse> response);
+ void SetFail(EError errorCode, const TStringBuf& errorDescription);
+
+ private:
+ TTaskRunnerBase* Task;
+ TMaybe<HttpCodes> HttpCode;
+ THolder<NNeh::TResponse> Response;
+ EError ErrorCode;
+ TString ErrorDescription;
+ };
+
+ class THttpClientService {
+ public:
+ THttpClientService();
+ virtual ~THttpClientService();
+
+ void Send(const TString& request, THttpFuture* future);
+ void SendPost(TString addr, const TString& data, const THttpHeaders& headers, THttpFuture* future);
+
+ private:
+ NNeh::IProtocol* const GetProtocol;
+ NNeh::IProtocol* const FullProtocol;
+ };
+
+}
diff --git a/library/cpp/messagebus/rain_check/http/client_ut.cpp b/library/cpp/messagebus/rain_check/http/client_ut.cpp
new file mode 100644
index 0000000000..1628114391
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/http/client_ut.cpp
@@ -0,0 +1,205 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "client.h"
+#include "http_code_extractor.h"
+
+#include <library/cpp/messagebus/rain_check/test/ut/test.h>
+
+#include <library/cpp/messagebus/test/helper/fixed_port.h>
+
+#include <library/cpp/http/io/stream.h>
+#include <library/cpp/neh/rpc.h>
+
+#include <util/generic/cast.h>
+#include <util/generic/ptr.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/network/ip.h>
+#include <util/stream/str.h>
+#include <util/string/printf.h>
+#include <util/system/defaults.h>
+#include <util/system/yassert.h>
+
+#include <cstdlib>
+#include <utility>
+
+using namespace NRainCheck;
+using namespace NBus::NTest;
+
+namespace {
+ class THttpClientEnv: public TTestEnvTemplate<THttpClientEnv> {
+ public:
+ THttpClientService HttpClientService;
+ };
+
+ const TString TEST_SERVICE = "test-service";
+ const TString TEST_GET_PARAMS = "p=GET";
+ const TString TEST_POST_PARAMS = "p=POST";
+ const TString TEST_POST_HEADERS = "Content-Type: application/json\r\n";
+ const TString TEST_GET_RECV = "GET was ok.";
+ const TString TEST_POST_RECV = "POST was ok.";
+
+ TString BuildServiceLocation(ui32 port) {
+ return Sprintf("http://*:%" PRIu32 "/%s", port, TEST_SERVICE.data());
+ }
+
+ TString BuildPostServiceLocation(ui32 port) {
+ return Sprintf("post://*:%" PRIu32 "/%s", port + 1, TEST_SERVICE.data());
+ }
+
+ TString BuildGetTestRequest(ui32 port) {
+ return BuildServiceLocation(port) + "?" + TEST_GET_PARAMS;
+ }
+
+ class TSimpleServer {
+ public:
+ inline void ServeRequest(const NNeh::IRequestRef& req) {
+ NNeh::TData response;
+ if (req->Data() == TEST_GET_PARAMS) {
+ response.assign(TEST_GET_RECV.begin(), TEST_GET_RECV.end());
+ } else {
+ response.assign(TEST_POST_RECV.begin(), TEST_POST_RECV.end());
+ }
+ req->SendReply(response);
+ }
+ };
+
+ NNeh::IServicesRef RunServer(ui32 port, TSimpleServer& server) {
+ NNeh::IServicesRef runner = NNeh::CreateLoop();
+ runner->Add(BuildServiceLocation(port), server);
+ runner->Add(BuildPostServiceLocation(port), server);
+
+ try {
+ const int THR_POOL_SIZE = 2;
+ runner->ForkLoop(THR_POOL_SIZE);
+ } catch (...) {
+ Y_FAIL("Can't run server: %s", CurrentExceptionMessage().data());
+ }
+
+ return runner;
+ }
+ enum ERequestType {
+ RT_HTTP_GET = 0,
+ RT_HTTP_POST = 1
+ };
+
+ using TTaskParam = std::pair<TIpPort, ERequestType>;
+
+ class THttpClientTask: public ISimpleTask {
+ public:
+ THttpClientTask(THttpClientEnv* env, TTaskParam param)
+ : Env(env)
+ , ServerPort(param.first)
+ , ReqType(param.second)
+ {
+ }
+
+ TContinueFunc Start() override {
+ switch (ReqType) {
+ case RT_HTTP_GET: {
+ TString getRequest = BuildGetTestRequest(ServerPort);
+ for (size_t i = 0; i < 3; ++i) {
+ Requests.push_back(new THttpFuture());
+ Env->HttpClientService.Send(getRequest, Requests[i].Get());
+ }
+ break;
+ }
+ case RT_HTTP_POST: {
+ TString servicePath = BuildPostServiceLocation(ServerPort);
+ TStringInput headersText(TEST_POST_HEADERS);
+ THttpHeaders headers(&headersText);
+ for (size_t i = 0; i < 3; ++i) {
+ Requests.push_back(new THttpFuture());
+ Env->HttpClientService.SendPost(servicePath, TEST_POST_PARAMS, headers, Requests[i].Get());
+ }
+ break;
+ }
+ }
+
+ return &THttpClientTask::GotReplies;
+ }
+
+ TContinueFunc GotReplies() {
+ const TString& TEST_OK_RECV = (ReqType == RT_HTTP_GET) ? TEST_GET_RECV : TEST_POST_RECV;
+ for (size_t i = 0; i < Requests.size(); ++i) {
+ UNIT_ASSERT_EQUAL(Requests[i]->GetHttpCode(), 200);
+ UNIT_ASSERT_EQUAL(Requests[i]->GetResponseBody(), TEST_OK_RECV);
+ }
+
+ Env->TestSync.CheckAndIncrement(0);
+
+ return nullptr;
+ }
+
+ THttpClientEnv* const Env;
+ const TIpPort ServerPort;
+ const ERequestType ReqType;
+
+ TVector<TSimpleSharedPtr<THttpFuture>> Requests;
+ };
+
+} // anonymous namespace
+
+Y_UNIT_TEST_SUITE(RainCheckHttpClient) {
+ static const TIpPort SERVER_PORT = 4000;
+
+ Y_UNIT_TEST(Simple) {
+ // TODO: randomize port
+ if (!IsFixedPortTestAllowed()) {
+ return;
+ }
+
+ TSimpleServer server;
+ NNeh::IServicesRef runner = RunServer(SERVER_PORT, server);
+
+ THttpClientEnv env;
+ TIntrusivePtr<TSimpleTaskRunner> task = env.SpawnTask<THttpClientTask>(TTaskParam(SERVER_PORT, RT_HTTP_GET));
+
+ env.TestSync.WaitForAndIncrement(1);
+ }
+
+ Y_UNIT_TEST(SimplePost) {
+ // TODO: randomize port
+ if (!IsFixedPortTestAllowed()) {
+ return;
+ }
+
+ TSimpleServer server;
+ NNeh::IServicesRef runner = RunServer(SERVER_PORT, server);
+
+ THttpClientEnv env;
+ TIntrusivePtr<TSimpleTaskRunner> task = env.SpawnTask<THttpClientTask>(TTaskParam(SERVER_PORT, RT_HTTP_POST));
+
+ env.TestSync.WaitForAndIncrement(1);
+ }
+
+ Y_UNIT_TEST(HttpCodeExtraction) {
+ // Find "request failed(" string, then copy len("HTTP/1.X NNN") chars and try to convert NNN to HTTP code.
+
+#define CHECK_VALID_LINE(line, code) \
+ UNIT_ASSERT_NO_EXCEPTION(TryGetHttpCodeFromErrorDescription(line)); \
+ UNIT_ASSERT(!!TryGetHttpCodeFromErrorDescription(line)); \
+ UNIT_ASSERT_EQUAL(*TryGetHttpCodeFromErrorDescription(line), code)
+
+ CHECK_VALID_LINE(TStringBuf("library/cpp/neh/http.cpp:<LINE>: request failed(HTTP/1.0 200 Some random message"), 200);
+ CHECK_VALID_LINE(TStringBuf("library/cpp/neh/http.cpp:<LINE>: request failed(HTTP/1.0 404 Some random message"), 404);
+ CHECK_VALID_LINE(TStringBuf("request failed(HTTP/1.0 100 Some random message"), 100);
+ CHECK_VALID_LINE(TStringBuf("request failed(HTTP/1.0 105)"), 105);
+ CHECK_VALID_LINE(TStringBuf("request failed(HTTP/1.1 2004 Some random message"), 200);
+#undef CHECK_VALID_LINE
+
+#define CHECK_INVALID_LINE(line) \
+ UNIT_ASSERT_NO_EXCEPTION(TryGetHttpCodeFromErrorDescription(line)); \
+ UNIT_ASSERT(!TryGetHttpCodeFromErrorDescription(line))
+
+ CHECK_INVALID_LINE(TStringBuf("library/cpp/neh/http.cpp:<LINE>: request failed(HTTP/1.1 1 Some random message"));
+ CHECK_INVALID_LINE(TStringBuf("request failed(HTTP/1.0 asdf Some random message"));
+ CHECK_INVALID_LINE(TStringBuf("HTTP/1.0 200 Some random message"));
+ CHECK_INVALID_LINE(TStringBuf("request failed(HTTP/1.0 2x00 Some random message"));
+ CHECK_INVALID_LINE(TStringBuf("HTTP/1.0 200 Some random message"));
+ CHECK_INVALID_LINE(TStringBuf("HTTP/1.0 200"));
+ CHECK_INVALID_LINE(TStringBuf("request failed(HTTP/1.1 3334 Some random message"));
+#undef CHECK_INVALID_LINE
+ }
+}
diff --git a/library/cpp/messagebus/rain_check/http/http_code_extractor.cpp b/library/cpp/messagebus/rain_check/http/http_code_extractor.cpp
new file mode 100644
index 0000000000..51d75762f6
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/http/http_code_extractor.cpp
@@ -0,0 +1,39 @@
+#include "http_code_extractor.h"
+
+#include <library/cpp/http/io/stream.h>
+#include <library/cpp/http/misc/httpcodes.h>
+
+#include <util/generic/maybe.h>
+#include <util/generic/strbuf.h>
+#include <util/string/cast.h>
+
+namespace NRainCheck {
+ TMaybe<HttpCodes> TryGetHttpCodeFromErrorDescription(const TStringBuf& errorMessage) {
+ // Try to get HttpCode from library/cpp/neh response.
+ // If response has HttpCode and it is not 200 OK, library/cpp/neh will send a message
+ // "library/cpp/neh/http.cpp:<LINE>: request failed(<FIRST-HTTP-RESPONSE-LINE>)"
+ // (see library/cpp/neh/http.cpp:625). So, we will try to parse this message and
+ // find out HttpCode in it. It is bad temporary solution, but we have no choice.
+ const TStringBuf SUBSTR = "request failed(";
+ const size_t SUBSTR_LEN = SUBSTR.size();
+ const size_t FIRST_LINE_LEN = TStringBuf("HTTP/1.X NNN").size();
+
+ TMaybe<HttpCodes> httpCode;
+
+ const size_t substrPos = errorMessage.find(SUBSTR);
+ if (substrPos != TStringBuf::npos) {
+ const TStringBuf firstLineStart = errorMessage.SubStr(substrPos + SUBSTR_LEN, FIRST_LINE_LEN);
+ try {
+ httpCode = static_cast<HttpCodes>(ParseHttpRetCode(firstLineStart));
+ if (*httpCode < HTTP_CONTINUE || *httpCode >= HTTP_CODE_MAX) {
+ httpCode = Nothing();
+ }
+ } catch (const TFromStringException& ex) {
+ // Can't parse HttpCode: it is OK, because ErrorDescription can be random string.
+ }
+ }
+
+ return httpCode;
+ }
+
+}
diff --git a/library/cpp/messagebus/rain_check/http/http_code_extractor.h b/library/cpp/messagebus/rain_check/http/http_code_extractor.h
new file mode 100644
index 0000000000..33b565fa1c
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/http/http_code_extractor.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <library/cpp/http/misc/httpcodes.h>
+
+#include <util/generic/maybe.h>
+#include <util/generic/strbuf.h>
+
+namespace NRainCheck {
+ // Try to get HttpCode from library/cpp/neh response.
+ // If response has HttpCode and it is not 200 OK, library/cpp/neh will send a message
+ // "library/cpp/neh/http.cpp:<LINE>: request failed(<FIRST-HTTP-RESPONSE-LINE>)"
+ // (see library/cpp/neh/http.cpp:625). So, we will try to parse this message and
+ // find out HttpCode in it. It is bad temporary solution, but we have no choice.
+ TMaybe<HttpCodes> TryGetHttpCodeFromErrorDescription(const TStringBuf& errorMessage);
+
+}
diff --git a/library/cpp/messagebus/rain_check/http/ya.make b/library/cpp/messagebus/rain_check/http/ya.make
new file mode 100644
index 0000000000..ef13329df3
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/http/ya.make
@@ -0,0 +1,17 @@
+LIBRARY()
+
+OWNER(g:messagebus)
+
+SRCS(
+ client.cpp
+ http_code_extractor.cpp
+)
+
+PEERDIR(
+ library/cpp/messagebus/rain_check/core
+ library/cpp/neh
+ library/cpp/http/misc
+ library/cpp/http/io
+)
+
+END()
diff --git a/library/cpp/messagebus/rain_check/messagebus/messagebus_client.cpp b/library/cpp/messagebus/rain_check/messagebus/messagebus_client.cpp
new file mode 100644
index 0000000000..daac8d9a99
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/messagebus/messagebus_client.cpp
@@ -0,0 +1,98 @@
+#include "messagebus_client.h"
+
+using namespace NRainCheck;
+using namespace NBus;
+
+TBusClientService::TBusClientService(
+ const NBus::TBusSessionConfig& config,
+ NBus::TBusProtocol* proto,
+ NBus::TBusMessageQueue* queue) {
+ Session = queue->CreateSource(proto, this, config);
+}
+
+TBusClientService::~TBusClientService() {
+ Session->Shutdown();
+}
+
+void TBusClientService::SendCommon(NBus::TBusMessage* message, const NBus::TNetAddr&, TBusFuture* future) {
+ TTaskRunnerBase* current = TTaskRunnerBase::CurrentTask();
+
+ future->SetRunning(current);
+
+ future->Task = current;
+
+ // after this statement message is owned by both messagebus and future
+ future->Request.Reset(message);
+
+ // TODO: allow cookie in messagebus
+ message->Data = future;
+}
+
+void TBusClientService::ProcessResultCommon(NBus::TBusMessageAutoPtr message,
+ const NBus::TNetAddr&, TBusFuture* future,
+ NBus::EMessageStatus status) {
+ Y_UNUSED(message.Release());
+
+ if (status == NBus::MESSAGE_OK) {
+ return;
+ }
+
+ future->SetDoneAndSchedule(status, nullptr);
+}
+
+void TBusClientService::SendOneWay(
+ NBus::TBusMessageAutoPtr message, const NBus::TNetAddr& addr,
+ TBusFuture* future) {
+ SendCommon(message.Get(), addr, future);
+
+ EMessageStatus ok = Session->SendMessageOneWay(message.Get(), &addr, false);
+ ProcessResultCommon(message, addr, future, ok);
+}
+
+NBus::TBusClientSessionPtr TBusClientService::GetSessionForMonitoring() const {
+ return Session;
+}
+
+void TBusClientService::Send(
+ TBusMessageAutoPtr message, const TNetAddr& addr,
+ TBusFuture* future) {
+ SendCommon(message.Get(), addr, future);
+
+ EMessageStatus ok = Session->SendMessage(message.Get(), &addr, false);
+ ProcessResultCommon(message, addr, future, ok);
+}
+
+void TBusClientService::OnReply(
+ TAutoPtr<TBusMessage> request,
+ TAutoPtr<TBusMessage> response) {
+ TBusFuture* future = (TBusFuture*)request->Data;
+ Y_ASSERT(future->Request.Get() == request.Get());
+ Y_UNUSED(request.Release());
+ future->SetDoneAndSchedule(MESSAGE_OK, response);
+}
+
+void NRainCheck::TBusClientService::OnMessageSentOneWay(
+ TAutoPtr<NBus::TBusMessage> request) {
+ TBusFuture* future = (TBusFuture*)request->Data;
+ Y_ASSERT(future->Request.Get() == request.Get());
+ Y_UNUSED(request.Release());
+ future->SetDoneAndSchedule(MESSAGE_OK, nullptr);
+}
+
+void TBusClientService::OnError(
+ TAutoPtr<TBusMessage> message, NBus::EMessageStatus status) {
+ if (message->Data == nullptr) {
+ return;
+ }
+
+ TBusFuture* future = (TBusFuture*)message->Data;
+ Y_ASSERT(future->Request.Get() == message.Get());
+ Y_UNUSED(message.Release());
+ future->SetDoneAndSchedule(status, nullptr);
+}
+
+void TBusFuture::SetDoneAndSchedule(EMessageStatus status, TAutoPtr<TBusMessage> response) {
+ Status = status;
+ Response.Reset(response.Release());
+ SetDone();
+}
diff --git a/library/cpp/messagebus/rain_check/messagebus/messagebus_client.h b/library/cpp/messagebus/rain_check/messagebus/messagebus_client.h
new file mode 100644
index 0000000000..0a291cdea6
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/messagebus/messagebus_client.h
@@ -0,0 +1,67 @@
+#pragma once
+
+#include <library/cpp/messagebus/rain_check/core/task.h>
+
+#include <library/cpp/messagebus/ybus.h>
+
+namespace NRainCheck {
+ class TBusFuture: public TSubtaskCompletion {
+ friend class TBusClientService;
+
+ private:
+ THolder<NBus::TBusMessage> Request;
+ THolder<NBus::TBusMessage> Response;
+ NBus::EMessageStatus Status;
+
+ private:
+ TTaskRunnerBase* Task;
+
+ void SetDoneAndSchedule(NBus::EMessageStatus, TAutoPtr<NBus::TBusMessage>);
+
+ public:
+ // TODO: add MESSAGE_UNDEFINED
+ TBusFuture()
+ : Status(NBus::MESSAGE_DONT_ASK)
+ , Task(nullptr)
+ {
+ }
+
+ NBus::TBusMessage* GetRequest() const {
+ return Request.Get();
+ }
+
+ NBus::TBusMessage* GetResponse() const {
+ Y_ASSERT(IsDone());
+ return Response.Get();
+ }
+
+ NBus::EMessageStatus GetStatus() const {
+ Y_ASSERT(IsDone());
+ return Status;
+ }
+ };
+
+ class TBusClientService: private NBus::IBusClientHandler {
+ private:
+ NBus::TBusClientSessionPtr Session;
+
+ public:
+ TBusClientService(const NBus::TBusSessionConfig&, NBus::TBusProtocol*, NBus::TBusMessageQueue*);
+ ~TBusClientService() override;
+
+ void Send(NBus::TBusMessageAutoPtr, const NBus::TNetAddr&, TBusFuture* future);
+ void SendOneWay(NBus::TBusMessageAutoPtr, const NBus::TNetAddr&, TBusFuture* future);
+
+ // Use it only for monitoring
+ NBus::TBusClientSessionPtr GetSessionForMonitoring() const;
+
+ private:
+ void SendCommon(NBus::TBusMessage*, const NBus::TNetAddr&, TBusFuture* future);
+ void ProcessResultCommon(NBus::TBusMessageAutoPtr, const NBus::TNetAddr&, TBusFuture* future, NBus::EMessageStatus);
+
+ void OnReply(TAutoPtr<NBus::TBusMessage> pMessage, TAutoPtr<NBus::TBusMessage> pReply) override;
+ void OnError(TAutoPtr<NBus::TBusMessage> pMessage, NBus::EMessageStatus status) override;
+ void OnMessageSentOneWay(TAutoPtr<NBus::TBusMessage>) override;
+ };
+
+}
diff --git a/library/cpp/messagebus/rain_check/messagebus/messagebus_client_ut.cpp b/library/cpp/messagebus/rain_check/messagebus/messagebus_client_ut.cpp
new file mode 100644
index 0000000000..1b3618558b
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/messagebus/messagebus_client_ut.cpp
@@ -0,0 +1,146 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "messagebus_client.h"
+
+#include <library/cpp/messagebus/rain_check/test/ut/test.h>
+
+#include <library/cpp/messagebus/test/helper/example.h>
+#include <library/cpp/messagebus/test/helper/object_count_check.h>
+
+#include <util/generic/cast.h>
+
+using namespace NBus;
+using namespace NBus::NTest;
+using namespace NRainCheck;
+
+struct TMessageBusClientEnv: public TTestEnvTemplate<TMessageBusClientEnv> {
+ // TODO: use same thread pool
+ TBusMessageQueuePtr Queue;
+ TExampleProtocol Proto;
+ TBusClientService BusClientService;
+
+ static TBusQueueConfig QueueConfig() {
+ TBusQueueConfig r;
+ r.NumWorkers = 4;
+ return r;
+ }
+
+ TMessageBusClientEnv()
+ : Queue(CreateMessageQueue(GetExecutor()))
+ , BusClientService(TBusSessionConfig(), &Proto, Queue.Get())
+ {
+ }
+};
+
+Y_UNIT_TEST_SUITE(RainCheckMessageBusClient) {
+ struct TSimpleTask: public ISimpleTask {
+ TMessageBusClientEnv* const Env;
+
+ const unsigned ServerPort;
+
+ TSimpleTask(TMessageBusClientEnv* env, unsigned serverPort)
+ : Env(env)
+ , ServerPort(serverPort)
+ {
+ }
+
+ TVector<TSimpleSharedPtr<TBusFuture>> Requests;
+
+ TContinueFunc Start() override {
+ for (unsigned i = 0; i < 3; ++i) {
+ Requests.push_back(new TBusFuture);
+ TNetAddr addr("localhost", ServerPort);
+ Env->BusClientService.Send(new TExampleRequest(&Env->Proto.RequestCount), addr, Requests[i].Get());
+ }
+
+ return TContinueFunc(&TSimpleTask::GotReplies);
+ }
+
+ TContinueFunc GotReplies() {
+ for (unsigned i = 0; i < Requests.size(); ++i) {
+ Y_VERIFY(Requests[i]->GetStatus() == MESSAGE_OK);
+ VerifyDynamicCast<TExampleResponse*>(Requests[i]->GetResponse());
+ }
+ Env->TestSync.CheckAndIncrement(0);
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(Simple) {
+ TObjectCountCheck objectCountCheck;
+
+ TExampleServer server;
+
+ TMessageBusClientEnv env;
+
+ TIntrusivePtr<TSimpleTaskRunner> task = env.SpawnTask<TSimpleTask>(server.GetActualListenPort());
+
+ env.TestSync.WaitForAndIncrement(1);
+ }
+
+ struct TOneWayServer: public NBus::IBusServerHandler {
+ TTestSync* const TestSync;
+ TExampleProtocol Proto;
+ NBus::TBusMessageQueuePtr Queue;
+ NBus::TBusServerSessionPtr Session;
+
+ TOneWayServer(TTestSync* testSync)
+ : TestSync(testSync)
+ {
+ Queue = CreateMessageQueue();
+ Session = Queue->CreateDestination(&Proto, this, NBus::TBusSessionConfig());
+ }
+
+ void OnMessage(NBus::TOnMessageContext& context) override {
+ TestSync->CheckAndIncrement(1);
+ context.ForgetRequest();
+ }
+ };
+
+ struct TOneWayTask: public ISimpleTask {
+ TMessageBusClientEnv* const Env;
+
+ const unsigned ServerPort;
+
+ TOneWayTask(TMessageBusClientEnv* env, unsigned serverPort)
+ : Env(env)
+ , ServerPort(serverPort)
+ {
+ }
+
+ TVector<TSimpleSharedPtr<TBusFuture>> Requests;
+
+ TContinueFunc Start() override {
+ Env->TestSync.CheckAndIncrement(0);
+
+ for (unsigned i = 0; i < 1; ++i) {
+ Requests.push_back(new TBusFuture);
+ TNetAddr addr("localhost", ServerPort);
+ Env->BusClientService.SendOneWay(new TExampleRequest(&Env->Proto.RequestCount), addr, Requests[i].Get());
+ }
+
+ return TContinueFunc(&TOneWayTask::GotReplies);
+ }
+
+ TContinueFunc GotReplies() {
+ for (unsigned i = 0; i < Requests.size(); ++i) {
+ Y_VERIFY(Requests[i]->GetStatus() == MESSAGE_OK);
+ Y_VERIFY(!Requests[i]->GetResponse());
+ }
+ Env->TestSync.WaitForAndIncrement(2);
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(OneWay) {
+ TObjectCountCheck objectCountCheck;
+
+ TMessageBusClientEnv env;
+
+ TOneWayServer server(&env.TestSync);
+
+ TIntrusivePtr<TSimpleTaskRunner> task = env.SpawnTask<TOneWayTask>(server.Session->GetActualListenPort());
+
+ env.TestSync.WaitForAndIncrement(3);
+ }
+}
diff --git a/library/cpp/messagebus/rain_check/messagebus/messagebus_server.cpp b/library/cpp/messagebus/rain_check/messagebus/messagebus_server.cpp
new file mode 100644
index 0000000000..5d4b13d664
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/messagebus/messagebus_server.cpp
@@ -0,0 +1,17 @@
+#include "messagebus_server.h"
+
+#include <library/cpp/messagebus/rain_check/core/spawn.h>
+
+using namespace NRainCheck;
+
+TBusTaskStarter::TBusTaskStarter(TAutoPtr<ITaskFactory> taskFactory)
+ : TaskFactory(taskFactory)
+{
+}
+
+void TBusTaskStarter::OnMessage(NBus::TOnMessageContext& onMessage) {
+ TaskFactory->NewTask(onMessage);
+}
+
+TBusTaskStarter::~TBusTaskStarter() {
+}
diff --git a/library/cpp/messagebus/rain_check/messagebus/messagebus_server.h b/library/cpp/messagebus/rain_check/messagebus/messagebus_server.h
new file mode 100644
index 0000000000..1334f05fe4
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/messagebus/messagebus_server.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <library/cpp/messagebus/rain_check/core/spawn.h>
+#include <library/cpp/messagebus/rain_check/core/task.h>
+
+#include <library/cpp/messagebus/ybus.h>
+
+#include <util/system/yassert.h>
+
+namespace NRainCheck {
+ class TBusTaskStarter: public NBus::IBusServerHandler {
+ private:
+ struct ITaskFactory {
+ virtual void NewTask(NBus::TOnMessageContext&) = 0;
+ virtual ~ITaskFactory() {
+ }
+ };
+
+ THolder<ITaskFactory> TaskFactory;
+
+ void OnMessage(NBus::TOnMessageContext&) override;
+
+ public:
+ TBusTaskStarter(TAutoPtr<ITaskFactory>);
+ ~TBusTaskStarter() override;
+
+ public:
+ template <typename TTask, typename TEnv>
+ static TAutoPtr<TBusTaskStarter> NewStarter(TEnv* env) {
+ struct TTaskFactory: public ITaskFactory {
+ TEnv* const Env;
+
+ TTaskFactory(TEnv* env)
+ : Env(env)
+ {
+ }
+
+ void NewTask(NBus::TOnMessageContext& context) override {
+ SpawnTask<TTask, TEnv, NBus::TOnMessageContext&>(Env, context);
+ }
+ };
+
+ return new TBusTaskStarter(new TTaskFactory(env));
+ }
+ };
+}
diff --git a/library/cpp/messagebus/rain_check/messagebus/messagebus_server_ut.cpp b/library/cpp/messagebus/rain_check/messagebus/messagebus_server_ut.cpp
new file mode 100644
index 0000000000..7c11399f1b
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/messagebus/messagebus_server_ut.cpp
@@ -0,0 +1,51 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "messagebus_server.h"
+
+#include <library/cpp/messagebus/rain_check/test/ut/test.h>
+
+#include <library/cpp/messagebus/test/helper/example.h>
+
+using namespace NBus;
+using namespace NBus::NTest;
+using namespace NRainCheck;
+
+struct TMessageBusServerEnv: public TTestEnvTemplate<TMessageBusServerEnv> {
+ TExampleProtocol Proto;
+};
+
+Y_UNIT_TEST_SUITE(RainCheckMessageBusServer) {
+ struct TSimpleServerTask: public ISimpleTask {
+ private:
+ TMessageBusServerEnv* const Env;
+ TOnMessageContext MessageContext;
+
+ public:
+ TSimpleServerTask(TMessageBusServerEnv* env, TOnMessageContext& messageContext)
+ : Env(env)
+ {
+ MessageContext.Swap(messageContext);
+ }
+
+ TContinueFunc Start() override {
+ MessageContext.SendReplyMove(new TExampleResponse(&Env->Proto.ResponseCount));
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(Simple) {
+ TMessageBusServerEnv env;
+
+ THolder<TBusTaskStarter> starter(TBusTaskStarter::NewStarter<TSimpleServerTask>(&env));
+
+ TBusMessageQueuePtr queue(CreateMessageQueue(env.GetExecutor()));
+
+ TExampleProtocol proto;
+
+ TBusServerSessionPtr session = queue->CreateDestination(&env.Proto, starter.Get(), TBusSessionConfig());
+
+ TExampleClient client;
+
+ client.SendMessagesWaitReplies(1, TNetAddr("localhost", session->GetActualListenPort()));
+ }
+}
diff --git a/library/cpp/messagebus/rain_check/messagebus/ya.make b/library/cpp/messagebus/rain_check/messagebus/ya.make
new file mode 100644
index 0000000000..defdac9a61
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/messagebus/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(g:messagebus)
+
+PEERDIR(
+ library/cpp/messagebus
+ library/cpp/messagebus/rain_check/core
+)
+
+SRCS(
+ messagebus_client.cpp
+ messagebus_server.cpp
+)
+
+END()
diff --git a/library/cpp/messagebus/rain_check/test/TestRainCheck.py b/library/cpp/messagebus/rain_check/test/TestRainCheck.py
new file mode 100644
index 0000000000..92ed727b62
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/test/TestRainCheck.py
@@ -0,0 +1,8 @@
+from devtools.fleur.ytest import group, constraint
+from devtools.fleur.ytest.integration import UnitTestGroup
+
+@group
+@constraint('library.messagebus')
+class TestMessageBus3(UnitTestGroup):
+ def __init__(self, context):
+ UnitTestGroup.__init__(self, context, 'MessageBus', 'library-messagebus-rain_check-test-ut')
diff --git a/library/cpp/messagebus/rain_check/test/helper/misc.cpp b/library/cpp/messagebus/rain_check/test/helper/misc.cpp
new file mode 100644
index 0000000000..c0fcb27252
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/test/helper/misc.cpp
@@ -0,0 +1,27 @@
+#include "misc.h"
+
+#include <util/system/yassert.h>
+
+using namespace NRainCheck;
+
+void TSpawnNopTasksCoroTask::Run() {
+ Y_VERIFY(Count <= Completion.size());
+ for (unsigned i = 0; i < Count; ++i) {
+ SpawnSubtask<TNopCoroTask>(Env, &Completion[i], "");
+ }
+
+ WaitForSubtasks();
+}
+
+TContinueFunc TSpawnNopTasksSimpleTask::Start() {
+ Y_VERIFY(Count <= Completion.size());
+ for (unsigned i = 0; i < Count; ++i) {
+ SpawnSubtask<TNopSimpleTask>(Env, &Completion[i], "");
+ }
+
+ return &TSpawnNopTasksSimpleTask::Join;
+}
+
+TContinueFunc TSpawnNopTasksSimpleTask::Join() {
+ return nullptr;
+}
diff --git a/library/cpp/messagebus/rain_check/test/helper/misc.h b/library/cpp/messagebus/rain_check/test/helper/misc.h
new file mode 100644
index 0000000000..9150be4d2f
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/test/helper/misc.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#include <library/cpp/messagebus/rain_check/core/rain_check.h>
+
+#include <array>
+
+namespace NRainCheck {
+ struct TNopSimpleTask: public ISimpleTask {
+ TNopSimpleTask(IEnv*, const void*) {
+ }
+
+ TContinueFunc Start() override {
+ return nullptr;
+ }
+ };
+
+ struct TNopCoroTask: public ICoroTask {
+ TNopCoroTask(IEnv*, const void*) {
+ }
+
+ void Run() override {
+ }
+ };
+
+ struct TSpawnNopTasksCoroTask: public ICoroTask {
+ IEnv* const Env;
+ unsigned const Count;
+
+ TSpawnNopTasksCoroTask(IEnv* env, unsigned count)
+ : Env(env)
+ , Count(count)
+ {
+ }
+
+ std::array<TSubtaskCompletion, 2> Completion;
+
+ void Run() override;
+ };
+
+ struct TSpawnNopTasksSimpleTask: public ISimpleTask {
+ IEnv* const Env;
+ unsigned const Count;
+
+ TSpawnNopTasksSimpleTask(IEnv* env, unsigned count)
+ : Env(env)
+ , Count(count)
+ {
+ }
+
+ std::array<TSubtaskCompletion, 2> Completion;
+
+ TContinueFunc Start() override;
+
+ TContinueFunc Join();
+ };
+
+}
diff --git a/library/cpp/messagebus/rain_check/test/helper/ya.make b/library/cpp/messagebus/rain_check/test/helper/ya.make
new file mode 100644
index 0000000000..aa9e4e6d81
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/test/helper/ya.make
@@ -0,0 +1,13 @@
+LIBRARY(messagebus-rain_check-test-helper)
+
+OWNER(g:messagebus)
+
+PEERDIR(
+ library/cpp/messagebus/rain_check/core
+)
+
+SRCS(
+ misc.cpp
+)
+
+END()
diff --git a/library/cpp/messagebus/rain_check/test/perftest/perftest.cpp b/library/cpp/messagebus/rain_check/test/perftest/perftest.cpp
new file mode 100644
index 0000000000..22edbd8c6b
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/test/perftest/perftest.cpp
@@ -0,0 +1,154 @@
+#include <library/cpp/messagebus/rain_check/test/helper/misc.h>
+
+#include <library/cpp/messagebus/rain_check/core/rain_check.h>
+
+#include <util/datetime/base.h>
+
+#include <array>
+
+using namespace NRainCheck;
+
+static const unsigned SUBTASKS = 2;
+
+struct TRainCheckPerftestEnv: public TSimpleEnvTemplate<TRainCheckPerftestEnv> {
+ unsigned SubtasksPerTask;
+
+ TRainCheckPerftestEnv()
+ : TSimpleEnvTemplate<TRainCheckPerftestEnv>(4)
+ , SubtasksPerTask(1000)
+ {
+ }
+};
+
+struct TCoroOuter: public ICoroTask {
+ TRainCheckPerftestEnv* const Env;
+
+ TCoroOuter(TRainCheckPerftestEnv* env)
+ : Env(env)
+ {
+ }
+
+ void Run() override {
+ for (;;) {
+ TInstant start = TInstant::Now();
+
+ unsigned count = 0;
+
+ unsigned current = 1000;
+
+ do {
+ for (unsigned i = 0; i < current; ++i) {
+ std::array<TSubtaskCompletion, SUBTASKS> completion;
+
+ for (unsigned j = 0; j < SUBTASKS; ++j) {
+ //SpawnSubtask<TNopSimpleTask>(Env, &completion[j]);
+ //SpawnSubtask<TSpawnNopTasksCoroTask>(Env, &completion[j], SUBTASKS);
+ SpawnSubtask<TSpawnNopTasksSimpleTask>(Env, &completion[j], SUBTASKS);
+ }
+
+ WaitForSubtasks();
+ }
+
+ count += current;
+ current *= 2;
+ } while (TInstant::Now() - start < TDuration::Seconds(1));
+
+ TDuration d = TInstant::Now() - start;
+ unsigned dns = d.NanoSeconds() / count;
+ Cerr << dns << "ns per spawn/join\n";
+ }
+ }
+};
+
+struct TSimpleOuter: public ISimpleTask {
+ TRainCheckPerftestEnv* const Env;
+
+ TSimpleOuter(TRainCheckPerftestEnv* env, const void*)
+ : Env(env)
+ {
+ }
+
+ TInstant StartInstant;
+ unsigned Count;
+ unsigned Current;
+ unsigned I;
+
+ TContinueFunc Start() override {
+ StartInstant = TInstant::Now();
+ Count = 0;
+ Current = 1000;
+ I = 0;
+
+ return &TSimpleOuter::Spawn;
+ }
+
+ std::array<TSubtaskCompletion, SUBTASKS> Completion;
+
+ TContinueFunc Spawn() {
+ for (unsigned j = 0; j < SUBTASKS; ++j) {
+ //SpawnSubtask<TNopSimpleTask>(Env, &Completion[j]);
+ //SpawnSubtask<TSpawnNopTasksCoroTask>(Env, &Completion[j], SUBTASKS);
+ SpawnSubtask<TSpawnNopTasksSimpleTask>(Env, &Completion[j], SUBTASKS);
+ }
+
+ return &TSimpleOuter::Join;
+ }
+
+ TContinueFunc Join() {
+ I += 1;
+ if (I != Current) {
+ return &TSimpleOuter::Spawn;
+ }
+
+ I = 0;
+ Count += Current;
+ Current *= 2;
+
+ TDuration d = TInstant::Now() - StartInstant;
+ if (d < TDuration::Seconds(1)) {
+ return &TSimpleOuter::Spawn;
+ }
+
+ unsigned dns = d.NanoSeconds() / Count;
+ Cerr << dns << "ns per spawn/join\n";
+
+ return &TSimpleOuter::Start;
+ }
+};
+
+struct TReproduceCrashTask: public ISimpleTask {
+ TRainCheckPerftestEnv* const Env;
+
+ TReproduceCrashTask(TRainCheckPerftestEnv* env)
+ : Env(env)
+ {
+ }
+
+ std::array<TSubtaskCompletion, SUBTASKS> Completion;
+
+ TContinueFunc Start() override {
+ for (unsigned j = 0; j < 2; ++j) {
+ //SpawnSubtask<TNopSimpleTask>(Env, &Completion[j]);
+ SpawnSubtask<TSpawnNopTasksSimpleTask>(Env, &Completion[j], SUBTASKS);
+ }
+
+ return &TReproduceCrashTask::Start;
+ }
+};
+
+int main(int argc, char** argv) {
+ Y_UNUSED(argc);
+ Y_UNUSED(argv);
+
+ TRainCheckPerftestEnv env;
+
+ env.SpawnTask<TSimpleOuter>("");
+ //env.SpawnTask<TCoroOuter>();
+ //env.SpawnTask<TReproduceCrashTask>();
+
+ for (;;) {
+ Sleep(TDuration::Hours(1));
+ }
+
+ return 0;
+}
diff --git a/library/cpp/messagebus/rain_check/test/perftest/ya.make b/library/cpp/messagebus/rain_check/test/perftest/ya.make
new file mode 100644
index 0000000000..7330a71700
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/test/perftest/ya.make
@@ -0,0 +1,14 @@
+PROGRAM(messagebus_rain_check_perftest)
+
+OWNER(g:messagebus)
+
+PEERDIR(
+ library/cpp/messagebus/rain_check/core
+ library/cpp/messagebus/rain_check/test/helper
+)
+
+SRCS(
+ perftest.cpp
+)
+
+END()
diff --git a/library/cpp/messagebus/rain_check/test/ut/test.h b/library/cpp/messagebus/rain_check/test/ut/test.h
new file mode 100644
index 0000000000..724f6b7530
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/test/ut/test.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <library/cpp/messagebus/rain_check/core/rain_check.h>
+
+#include <library/cpp/messagebus/misc/test_sync.h>
+
+template <typename TSelf>
+struct TTestEnvTemplate: public NRainCheck::TSimpleEnvTemplate<TSelf> {
+ TTestSync TestSync;
+};
+
+struct TTestEnv: public TTestEnvTemplate<TTestEnv> {
+};
diff --git a/library/cpp/messagebus/rain_check/test/ut/ya.make b/library/cpp/messagebus/rain_check/test/ut/ya.make
new file mode 100644
index 0000000000..9f7a93417a
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/test/ut/ya.make
@@ -0,0 +1,24 @@
+PROGRAM(library-messagebus-rain_check-test-ut)
+
+OWNER(g:messagebus)
+
+PEERDIR(
+ library/cpp/testing/unittest_main
+ library/cpp/messagebus/rain_check/core
+ library/cpp/messagebus/rain_check/http
+ library/cpp/messagebus/rain_check/messagebus
+ library/cpp/messagebus/test/helper
+)
+
+SRCS(
+ ../../core/coro_ut.cpp
+ ../../core/simple_ut.cpp
+ ../../core/sleep_ut.cpp
+ ../../core/spawn_ut.cpp
+ ../../core/track_ut.cpp
+ ../../http/client_ut.cpp
+ ../../messagebus/messagebus_client_ut.cpp
+ ../../messagebus/messagebus_server_ut.cpp
+)
+
+END()
diff --git a/library/cpp/messagebus/rain_check/test/ya.make b/library/cpp/messagebus/rain_check/test/ya.make
new file mode 100644
index 0000000000..4c1d6f8161
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/test/ya.make
@@ -0,0 +1,6 @@
+OWNER(g:messagebus)
+
+RECURSE(
+ perftest
+ ut
+)
diff --git a/library/cpp/messagebus/rain_check/ya.make b/library/cpp/messagebus/rain_check/ya.make
new file mode 100644
index 0000000000..966d54c232
--- /dev/null
+++ b/library/cpp/messagebus/rain_check/ya.make
@@ -0,0 +1,8 @@
+OWNER(g:messagebus)
+
+RECURSE(
+ core
+ http
+ messagebus
+ test
+)
diff --git a/library/cpp/messagebus/ref_counted.h b/library/cpp/messagebus/ref_counted.h
new file mode 100644
index 0000000000..29b87764e3
--- /dev/null
+++ b/library/cpp/messagebus/ref_counted.h
@@ -0,0 +1,6 @@
+#pragma once
+
+class TAtomicRefCountedObject: public TAtomicRefCount<TAtomicRefCountedObject> {
+ virtual ~TAtomicRefCountedObject() {
+ }
+};
diff --git a/library/cpp/messagebus/remote_client_connection.cpp b/library/cpp/messagebus/remote_client_connection.cpp
new file mode 100644
index 0000000000..8c7a6db3a8
--- /dev/null
+++ b/library/cpp/messagebus/remote_client_connection.cpp
@@ -0,0 +1,343 @@
+#include "remote_client_connection.h"
+
+#include "mb_lwtrace.h"
+#include "network.h"
+#include "remote_client_session.h"
+
+#include <library/cpp/messagebus/actor/executor.h>
+#include <library/cpp/messagebus/actor/temp_tls_vector.h>
+
+#include <util/generic/cast.h>
+#include <util/thread/singleton.h>
+
+LWTRACE_USING(LWTRACE_MESSAGEBUS_PROVIDER)
+
+using namespace NActor;
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+TRemoteClientConnection::TRemoteClientConnection(TRemoteClientSessionPtr session, ui64 id, TNetAddr addr)
+ : TRemoteConnection(session.Get(), id, addr)
+ , ClientHandler(GetSession()->ClientHandler)
+{
+ Y_VERIFY(addr.GetPort() > 0, "must connect to non-zero port");
+
+ ScheduleWrite();
+}
+
+TRemoteClientSession* TRemoteClientConnection::GetSession() {
+ return CheckedCast<TRemoteClientSession*>(Session.Get());
+}
+
+TBusMessage* TRemoteClientConnection::PopAck(TBusKey id) {
+ return AckMessages.Pop(id);
+}
+
+SOCKET TRemoteClientConnection::CreateSocket(const TNetAddr& addr) {
+ SOCKET handle = socket(addr.Addr()->sa_family, SOCK_STREAM, 0);
+ Y_VERIFY(handle != INVALID_SOCKET, "failed to create socket: %s", LastSystemErrorText());
+
+ TSocketHolder s(handle);
+
+ SetNonBlock(s, true);
+ SetNoDelay(s, Config.TcpNoDelay);
+ SetSockOptTcpCork(s, Config.TcpCork);
+ SetCloseOnExec(s, true);
+ SetKeepAlive(s, true);
+ if (Config.SocketRecvBufferSize != 0) {
+ SetInputBuffer(s, Config.SocketRecvBufferSize);
+ }
+ if (Config.SocketSendBufferSize != 0) {
+ SetOutputBuffer(s, Config.SocketSendBufferSize);
+ }
+ if (Config.SocketToS >= 0) {
+ SetSocketToS(s, &addr, Config.SocketToS);
+ }
+
+ return s.Release();
+}
+
+void TRemoteClientConnection::TryConnect() {
+ if (AtomicGet(WriterData.Down)) {
+ return;
+ }
+ Y_VERIFY(!WriterData.Status.Connected);
+
+ TInstant now = TInstant::Now();
+
+ if (!WriterData.Channel) {
+ if ((now - LastConnectAttempt) < TDuration::MilliSeconds(Config.RetryInterval)) {
+ DropEnqueuedData(MESSAGE_CONNECT_FAILED, MESSAGE_CONNECT_FAILED);
+ return;
+ }
+ LastConnectAttempt = now;
+
+ TSocket connectSocket(CreateSocket(PeerAddr));
+ WriterData.SetChannel(Session->WriteEventLoop.Register(connectSocket, this, WriteCookie));
+ }
+
+ if (BeforeSendQueue.IsEmpty() && WriterData.SendQueue.Empty() && !Config.ReconnectWhenIdle) {
+ // TryConnect is called from Writer::Act, which is called in cycle
+ // from session's ScheduleTimeoutMessages via Cron. This prevent these excessive connects.
+ return;
+ }
+
+ ++WriterData.Status.ConnectSyscalls;
+
+ int ret = connect(WriterData.Channel->GetSocket(), PeerAddr.Addr(), PeerAddr.Len());
+ int err = ret ? LastSystemError() : 0;
+
+ if (!ret || (ret && err == EISCONN)) {
+ WriterData.Status.ConnectTime = now;
+ ++WriterData.SocketVersion;
+
+ WriterData.Channel->DisableWrite();
+ WriterData.Status.Connected = true;
+ AtomicSet(ReturnConnectFailedImmediately, false);
+
+ WriterData.Status.MyAddr = TNetAddr(GetSockAddr(WriterData.Channel->GetSocket()));
+
+ TSocket readSocket = WriterData.Channel->GetSocketPtr();
+
+ ReaderGetSocketQueue()->EnqueueAndSchedule(TWriterToReaderSocketMessage(readSocket, WriterData.SocketVersion));
+
+ FireClientConnectionEvent(TClientConnectionEvent::CONNECTED);
+
+ ScheduleWrite();
+ } else {
+ if (WouldBlock() || err == EALREADY) {
+ WriterData.Channel->EnableWrite();
+ } else {
+ WriterData.DropChannel();
+ WriterData.Status.MyAddr = TNetAddr();
+ WriterData.Status.Connected = false;
+ WriterData.Status.ConnectError = err;
+
+ DropEnqueuedData(MESSAGE_CONNECT_FAILED, MESSAGE_CONNECT_FAILED);
+ }
+ }
+}
+
+void TRemoteClientConnection::HandleEvent(SOCKET socket, void* cookie) {
+ Y_UNUSED(socket);
+ Y_ASSERT(cookie == WriteCookie || cookie == ReadCookie);
+ if (cookie == ReadCookie) {
+ ScheduleRead();
+ } else {
+ ScheduleWrite();
+ }
+}
+
+void TRemoteClientConnection::WriterFillStatus() {
+ TRemoteConnection::WriterFillStatus();
+ WriterData.Status.AckMessagesSize = AckMessages.Size();
+}
+
+void TRemoteClientConnection::BeforeTryWrite() {
+ ProcessReplyQueue();
+ TimeoutMessages();
+}
+
+namespace NBus {
+ namespace NPrivate {
+ class TInvokeOnReply: public IWorkItem {
+ private:
+ TRemoteClientSession* RemoteClientSession;
+ TNonDestroyingHolder<TBusMessage> Request;
+ TBusMessagePtrAndHeader Response;
+
+ public:
+ TInvokeOnReply(TRemoteClientSession* session,
+ TNonDestroyingAutoPtr<TBusMessage> request, TBusMessagePtrAndHeader& response)
+ : RemoteClientSession(session)
+ , Request(request)
+ {
+ Response.Swap(response);
+ }
+
+ void DoWork() override {
+ THolder<TInvokeOnReply> holder(this);
+ RemoteClientSession->ReleaseInFlightAndCallOnReply(Request.Release(), Response);
+ // TODO: TRemoteClientSessionSemaphore should be enough
+ RemoteClientSession->JobCount.Decrement();
+ }
+ };
+
+ }
+}
+
+void TRemoteClientConnection::ProcessReplyQueue() {
+ if (AtomicGet(WriterData.Down)) {
+ return;
+ }
+
+ bool executeInWorkerPool = Session->Config.ExecuteOnReplyInWorkerPool;
+
+ TTempTlsVector<TBusMessagePtrAndHeader, void, TVectorSwaps> replyQueueTemp;
+ TTempTlsVector< ::NActor::IWorkItem*> workQueueTemp;
+
+ ReplyQueue.DequeueAllSingleConsumer(replyQueueTemp.GetVector());
+ if (executeInWorkerPool) {
+ workQueueTemp.GetVector()->reserve(replyQueueTemp.GetVector()->size());
+ }
+
+ for (auto& resp : *replyQueueTemp.GetVector()) {
+ TBusMessage* req = PopAck(resp.Header.Id);
+
+ if (!req) {
+ WriterErrorMessage(resp.MessagePtr.Release(), MESSAGE_UNKNOWN);
+ continue;
+ }
+
+ if (executeInWorkerPool) {
+ workQueueTemp.GetVector()->push_back(new TInvokeOnReply(GetSession(), req, resp));
+ } else {
+ GetSession()->ReleaseInFlightAndCallOnReply(req, resp);
+ }
+ }
+
+ if (executeInWorkerPool) {
+ Session->JobCount.Add(workQueueTemp.GetVector()->size());
+ Session->Queue->EnqueueWork(*workQueueTemp.GetVector());
+ }
+}
+
+void TRemoteClientConnection::TimeoutMessages() {
+ if (!TimeToTimeoutMessages.FetchTask()) {
+ return;
+ }
+
+ TMessagesPtrs timedOutMessages;
+
+ TInstant sendDeadline;
+ TInstant ackDeadline;
+ if (IsReturnConnectFailedImmediately()) {
+ sendDeadline = TInstant::Max();
+ ackDeadline = TInstant::Max();
+ } else {
+ TInstant now = TInstant::Now();
+ sendDeadline = now - TDuration::MilliSeconds(Session->Config.SendTimeout);
+ ackDeadline = now - TDuration::MilliSeconds(Session->Config.TotalTimeout);
+ }
+
+ {
+ TMessagesPtrs temp;
+ WriterData.SendQueue.Timeout(sendDeadline, &temp);
+ timedOutMessages.insert(timedOutMessages.end(), temp.begin(), temp.end());
+ }
+
+ // Ignores message that is being written currently (that is stored
+ // in WriteMessage). It is not a big problem, because after written
+ // to the network, message will be placed to the AckMessages queue,
+ // and timed out on the next iteration of this procedure.
+
+ {
+ TMessagesPtrs temp;
+ AckMessages.Timeout(ackDeadline, &temp);
+ timedOutMessages.insert(timedOutMessages.end(), temp.begin(), temp.end());
+ }
+
+ ResetOneWayFlag(timedOutMessages);
+
+ GetSession()->ReleaseInFlight(timedOutMessages);
+ WriterErrorMessages(timedOutMessages, MESSAGE_TIMEOUT);
+}
+
+void TRemoteClientConnection::ScheduleTimeoutMessages() {
+ TimeToTimeoutMessages.AddTask();
+ ScheduleWrite();
+}
+
+void TRemoteClientConnection::ReaderProcessMessageUnknownVersion(TArrayRef<const char>) {
+ LWPROBE(Error, ToString(MESSAGE_INVALID_VERSION), ToString(PeerAddr), "");
+ ReaderData.Status.Incremental.StatusCounter[MESSAGE_INVALID_VERSION] += 1;
+ // TODO: close connection
+ Y_FAIL("unknown message");
+}
+
+void TRemoteClientConnection::ClearOutgoingQueue(TMessagesPtrs& result, bool reconnect) {
+ Y_ASSERT(result.empty());
+
+ TRemoteConnection::ClearOutgoingQueue(result, reconnect);
+ AckMessages.Clear(&result);
+
+ ResetOneWayFlag(result);
+ GetSession()->ReleaseInFlight(result);
+}
+
+void TRemoteClientConnection::MessageSent(TArrayRef<TBusMessagePtrAndHeader> messages) {
+ for (auto& message : messages) {
+ bool oneWay = message.LocalFlags & MESSAGE_ONE_WAY_INTERNAL;
+
+ if (oneWay) {
+ message.MessagePtr->LocalFlags &= ~MESSAGE_ONE_WAY_INTERNAL;
+
+ TBusMessage* ackMsg = this->PopAck(message.Header.Id);
+ if (!ackMsg) {
+ // TODO: expired?
+ }
+
+ if (ackMsg != message.MessagePtr.Get()) {
+ // TODO: non-unique id?
+ }
+
+ GetSession()->ReleaseInFlight({message.MessagePtr.Get()});
+ ClientHandler->OnMessageSentOneWay(message.MessagePtr.Release());
+ } else {
+ ClientHandler->OnMessageSent(message.MessagePtr.Get());
+ AckMessages.Push(message);
+ }
+ }
+}
+
+EMessageStatus TRemoteClientConnection::SendMessage(TBusMessage* req, bool wait) {
+ return SendMessageImpl(req, wait, false);
+}
+
+EMessageStatus TRemoteClientConnection::SendMessageOneWay(TBusMessage* req, bool wait) {
+ return SendMessageImpl(req, wait, true);
+}
+
+EMessageStatus TRemoteClientConnection::SendMessageImpl(TBusMessage* msg, bool wait, bool oneWay) {
+ msg->CheckClean();
+
+ if (Session->IsDown()) {
+ return MESSAGE_SHUTDOWN;
+ }
+
+ if (wait) {
+ Y_VERIFY(!Session->Queue->GetExecutor()->IsInExecutorThread());
+ GetSession()->ClientRemoteInFlight.Wait();
+ } else {
+ if (!GetSession()->ClientRemoteInFlight.TryWait()) {
+ return MESSAGE_BUSY;
+ }
+ }
+
+ GetSession()->AcquireInFlight({msg});
+
+ EMessageStatus ret = MESSAGE_OK;
+
+ if (oneWay) {
+ msg->LocalFlags |= MESSAGE_ONE_WAY_INTERNAL;
+ }
+
+ msg->GetHeader()->SendTime = Now();
+
+ if (IsReturnConnectFailedImmediately()) {
+ ret = MESSAGE_CONNECT_FAILED;
+ goto clean;
+ }
+
+ Send(msg);
+
+ return MESSAGE_OK;
+clean:
+ msg->LocalFlags &= ~MESSAGE_ONE_WAY_INTERNAL;
+ GetSession()->ReleaseInFlight({msg});
+ return ret;
+}
+
+void TRemoteClientConnection::OpenConnection() {
+ // TODO
+}
diff --git a/library/cpp/messagebus/remote_client_connection.h b/library/cpp/messagebus/remote_client_connection.h
new file mode 100644
index 0000000000..fe80b7d2f9
--- /dev/null
+++ b/library/cpp/messagebus/remote_client_connection.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include "connection.h"
+#include "local_tasks.h"
+#include "remote_client_session.h"
+#include "remote_connection.h"
+
+#include <util/generic/object_counter.h>
+
+namespace NBus {
+ namespace NPrivate {
+ class TRemoteClientConnection: public TRemoteConnection, public TBusClientConnection {
+ friend class TRemoteConnection;
+ friend struct TBusSessionImpl;
+ friend class TRemoteClientSession;
+
+ private:
+ TObjectCounter<TRemoteClientConnection> ObjectCounter;
+
+ TSyncAckMessages AckMessages;
+
+ TLocalTasks TimeToTimeoutMessages;
+
+ IBusClientHandler* const ClientHandler;
+
+ public:
+ TRemoteClientConnection(TRemoteClientSessionPtr session, ui64 id, TNetAddr addr);
+
+ inline TRemoteClientSession* GetSession();
+
+ SOCKET CreateSocket(const TNetAddr& addr);
+
+ void TryConnect() override;
+
+ void HandleEvent(SOCKET socket, void* cookie) override;
+
+ TBusMessage* PopAck(TBusKey id);
+
+ void WriterFillStatus() override;
+
+ void ClearOutgoingQueue(TMessagesPtrs& result, bool reconnect) override;
+
+ void BeforeTryWrite() override;
+
+ void ProcessReplyQueue();
+
+ void MessageSent(TArrayRef<TBusMessagePtrAndHeader> messages) override;
+
+ void TimeoutMessages();
+
+ void ScheduleTimeoutMessages();
+
+ void ReaderProcessMessageUnknownVersion(TArrayRef<const char> dataRef) override;
+
+ EMessageStatus SendMessage(TBusMessage* pMes, bool wait) override;
+
+ EMessageStatus SendMessageOneWay(TBusMessage* pMes, bool wait) override;
+
+ EMessageStatus SendMessageImpl(TBusMessage*, bool wait, bool oneWay);
+
+ void OpenConnection() override;
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/remote_client_session.cpp b/library/cpp/messagebus/remote_client_session.cpp
new file mode 100644
index 0000000000..3bc421944f
--- /dev/null
+++ b/library/cpp/messagebus/remote_client_session.cpp
@@ -0,0 +1,127 @@
+#include "remote_client_session.h"
+
+#include "mb_lwtrace.h"
+#include "remote_client_connection.h"
+
+#include <library/cpp/messagebus/scheduler/scheduler.h>
+
+#include <util/generic/cast.h>
+#include <util/system/defaults.h>
+
+LWTRACE_USING(LWTRACE_MESSAGEBUS_PROVIDER)
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+TRemoteClientSession::TRemoteClientSession(TBusMessageQueue* queue,
+ TBusProtocol* proto, IBusClientHandler* handler,
+ const TBusClientSessionConfig& config, const TString& name)
+ : TBusSessionImpl(true, queue, proto, handler, config, name)
+ , ClientRemoteInFlight(config.MaxInFlight, "ClientRemoteInFlight")
+ , ClientHandler(handler)
+{
+}
+
+TRemoteClientSession::~TRemoteClientSession() {
+ //Cerr << "~TRemoteClientSession" << Endl;
+}
+
+void TRemoteClientSession::OnMessageReceived(TRemoteConnection* c, TVectorSwaps<TBusMessagePtrAndHeader>& newMsg) {
+ TAutoPtr<TVectorSwaps<TBusMessagePtrAndHeader>> temp(new TVectorSwaps<TBusMessagePtrAndHeader>);
+ temp->swap(newMsg);
+ c->ReplyQueue.EnqueueAll(temp);
+ c->ScheduleWrite();
+}
+
+EMessageStatus TRemoteClientSession::SendMessageImpl(TBusMessage* msg, const TNetAddr* addr, bool wait, bool oneWay) {
+ if (Y_UNLIKELY(IsDown())) {
+ return MESSAGE_SHUTDOWN;
+ }
+
+ TBusSocketAddr resolvedAddr;
+ EMessageStatus ret = GetMessageDestination(msg, addr, &resolvedAddr);
+ if (ret != MESSAGE_OK) {
+ return ret;
+ }
+
+ msg->ReplyTo = resolvedAddr;
+
+ TRemoteConnectionPtr c = ((TBusSessionImpl*)this)->GetConnection(resolvedAddr, true);
+ Y_ASSERT(!!c);
+
+ return CheckedCast<TRemoteClientConnection*>(c.Get())->SendMessageImpl(msg, wait, oneWay);
+}
+
+EMessageStatus TRemoteClientSession::SendMessage(TBusMessage* msg, const TNetAddr* addr, bool wait) {
+ return SendMessageImpl(msg, addr, wait, false);
+}
+
+EMessageStatus TRemoteClientSession::SendMessageOneWay(TBusMessage* pMes, const TNetAddr* addr, bool wait) {
+ return SendMessageImpl(pMes, addr, wait, true);
+}
+
+int TRemoteClientSession::GetInFlight() const noexcept {
+ return ClientRemoteInFlight.GetCurrent();
+}
+
+void TRemoteClientSession::FillStatus() {
+ TBusSessionImpl::FillStatus();
+
+ StatusData.Status.InFlightCount = ClientRemoteInFlight.GetCurrent();
+ StatusData.Status.InputPaused = false;
+}
+
+void TRemoteClientSession::AcquireInFlight(TArrayRef<TBusMessage* const> messages) {
+ for (auto message : messages) {
+ Y_ASSERT(!(message->LocalFlags & MESSAGE_IN_FLIGHT_ON_CLIENT));
+ message->LocalFlags |= MESSAGE_IN_FLIGHT_ON_CLIENT;
+ }
+ ClientRemoteInFlight.IncrementMultiple(messages.size());
+}
+
+void TRemoteClientSession::ReleaseInFlight(TArrayRef<TBusMessage* const> messages) {
+ for (auto message : messages) {
+ Y_ASSERT(message->LocalFlags & MESSAGE_IN_FLIGHT_ON_CLIENT);
+ message->LocalFlags &= ~MESSAGE_IN_FLIGHT_ON_CLIENT;
+ }
+ ClientRemoteInFlight.ReleaseMultiple(messages.size());
+}
+
+void TRemoteClientSession::ReleaseInFlightAndCallOnReply(TNonDestroyingAutoPtr<TBusMessage> request, TBusMessagePtrAndHeader& response) {
+ ReleaseInFlight({request.Get()});
+ if (Y_UNLIKELY(AtomicGet(Down))) {
+ InvokeOnError(request, MESSAGE_SHUTDOWN);
+ InvokeOnError(response.MessagePtr.Release(), MESSAGE_SHUTDOWN);
+
+ TRemoteConnectionReaderIncrementalStatus counter;
+ LWPROBE(Error, ToString(MESSAGE_SHUTDOWN), "", "");
+ counter.StatusCounter[MESSAGE_SHUTDOWN] += 1;
+ GetDeadConnectionReaderStatusQueue()->EnqueueAndSchedule(counter);
+ } else {
+ TWhatThreadDoesPushPop pp("OnReply");
+ ClientHandler->OnReply(request, response.MessagePtr.Release());
+ }
+}
+
+EMessageStatus TRemoteClientSession::GetMessageDestination(TBusMessage* mess, const TNetAddr* addrp, TBusSocketAddr* dest) {
+ if (addrp) {
+ *dest = *addrp;
+ } else {
+ TNetAddr tmp;
+ EMessageStatus ret = const_cast<TBusProtocol*>(GetProto())->GetDestination(this, mess, GetQueue()->GetLocator(), &tmp);
+ if (ret != MESSAGE_OK) {
+ return ret;
+ }
+ *dest = tmp;
+ }
+ return MESSAGE_OK;
+}
+
+void TRemoteClientSession::OpenConnection(const TNetAddr& addr) {
+ GetConnection(addr)->OpenConnection();
+}
+
+TBusClientConnectionPtr TRemoteClientSession::GetConnection(const TNetAddr& addr) {
+ // TODO: GetConnection should not open
+ return CheckedCast<TRemoteClientConnection*>(((TBusSessionImpl*)this)->GetConnection(addr, true).Get());
+}
diff --git a/library/cpp/messagebus/remote_client_session.h b/library/cpp/messagebus/remote_client_session.h
new file mode 100644
index 0000000000..7160d0dae9
--- /dev/null
+++ b/library/cpp/messagebus/remote_client_session.h
@@ -0,0 +1,59 @@
+#pragma once
+
+#include "remote_client_session_semaphore.h"
+#include "session_impl.h"
+
+#include <util/generic/array_ref.h>
+#include <util/generic/object_counter.h>
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4250) // 'NBus::NPrivate::TRemoteClientSession' : inherits 'NBus::NPrivate::TBusSessionImpl::NBus::NPrivate::TBusSessionImpl::GetConfig' via dominance
+#endif
+
+namespace NBus {
+ namespace NPrivate {
+ using TRemoteClientSessionPtr = TIntrusivePtr<TRemoteClientSession>;
+
+ class TRemoteClientSession: public TBusClientSession, public TBusSessionImpl {
+ friend class TRemoteClientConnection;
+ friend class TInvokeOnReply;
+
+ public:
+ TObjectCounter<TRemoteClientSession> ObjectCounter;
+
+ TRemoteClientSessionSemaphore ClientRemoteInFlight;
+ IBusClientHandler* const ClientHandler;
+
+ public:
+ TRemoteClientSession(TBusMessageQueue* queue, TBusProtocol* proto,
+ IBusClientHandler* handler,
+ const TBusSessionConfig& config, const TString& name);
+
+ ~TRemoteClientSession() override;
+
+ void OnMessageReceived(TRemoteConnection* c, TVectorSwaps<TBusMessagePtrAndHeader>& newMsg) override;
+
+ EMessageStatus SendMessageImpl(TBusMessage* msg, const TNetAddr* addr, bool wait, bool oneWay);
+ EMessageStatus SendMessage(TBusMessage* msg, const TNetAddr* addr = nullptr, bool wait = false) override;
+ EMessageStatus SendMessageOneWay(TBusMessage* msg, const TNetAddr* addr = nullptr, bool wait = false) override;
+
+ int GetInFlight() const noexcept override;
+ void FillStatus() override;
+ void AcquireInFlight(TArrayRef<TBusMessage* const> messages);
+ void ReleaseInFlight(TArrayRef<TBusMessage* const> messages);
+ void ReleaseInFlightAndCallOnReply(TNonDestroyingAutoPtr<TBusMessage> request, TBusMessagePtrAndHeader& response);
+
+ EMessageStatus GetMessageDestination(TBusMessage* mess, const TNetAddr* addrp, TBusSocketAddr* dest);
+
+ void OpenConnection(const TNetAddr&) override;
+
+ TBusClientConnectionPtr GetConnection(const TNetAddr&) override;
+ };
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+ }
+}
diff --git a/library/cpp/messagebus/remote_client_session_semaphore.cpp b/library/cpp/messagebus/remote_client_session_semaphore.cpp
new file mode 100644
index 0000000000..f877ed4257
--- /dev/null
+++ b/library/cpp/messagebus/remote_client_session_semaphore.cpp
@@ -0,0 +1,67 @@
+#include "remote_client_session_semaphore.h"
+
+#include <util/stream/output.h>
+#include <util/system/yassert.h>
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+TRemoteClientSessionSemaphore::TRemoteClientSessionSemaphore(TAtomicBase limit, const char* name)
+ : Name(name)
+ , Limit(limit)
+ , Current(0)
+ , StopSignal(0)
+{
+ Y_VERIFY(limit > 0, "limit must be > 0");
+ Y_UNUSED(Name);
+}
+
+TRemoteClientSessionSemaphore::~TRemoteClientSessionSemaphore() {
+ Y_VERIFY(AtomicGet(Current) == 0);
+}
+
+bool TRemoteClientSessionSemaphore::TryAcquire() {
+ if (!TryWait()) {
+ return false;
+ }
+
+ AtomicIncrement(Current);
+ return true;
+}
+
+bool TRemoteClientSessionSemaphore::TryWait() {
+ if (AtomicGet(Current) < Limit)
+ return true;
+ if (Y_UNLIKELY(AtomicGet(StopSignal)))
+ return true;
+ return false;
+}
+
+void TRemoteClientSessionSemaphore::Acquire() {
+ Wait();
+
+ Increment();
+}
+
+void TRemoteClientSessionSemaphore::Increment() {
+ IncrementMultiple(1);
+}
+
+void TRemoteClientSessionSemaphore::IncrementMultiple(TAtomicBase count) {
+ AtomicAdd(Current, count);
+ Updated();
+}
+
+void TRemoteClientSessionSemaphore::Release() {
+ ReleaseMultiple(1);
+}
+
+void TRemoteClientSessionSemaphore::ReleaseMultiple(TAtomicBase count) {
+ AtomicSub(Current, count);
+ Updated();
+}
+
+void TRemoteClientSessionSemaphore::Stop() {
+ AtomicSet(StopSignal, 1);
+ Updated();
+}
diff --git a/library/cpp/messagebus/remote_client_session_semaphore.h b/library/cpp/messagebus/remote_client_session_semaphore.h
new file mode 100644
index 0000000000..286ca3c86f
--- /dev/null
+++ b/library/cpp/messagebus/remote_client_session_semaphore.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "cc_semaphore.h"
+
+#include <util/generic/noncopyable.h>
+#include <util/system/atomic.h>
+#include <util/system/condvar.h>
+#include <util/system/mutex.h>
+
+namespace NBus {
+ namespace NPrivate {
+ class TRemoteClientSessionSemaphore: public TComplexConditionSemaphore<TRemoteClientSessionSemaphore> {
+ private:
+ const char* const Name;
+
+ TAtomicBase const Limit;
+ TAtomic Current;
+ TAtomic StopSignal;
+
+ public:
+ TRemoteClientSessionSemaphore(TAtomicBase limit, const char* name = "unnamed");
+ ~TRemoteClientSessionSemaphore();
+
+ TAtomicBase GetCurrent() const {
+ return AtomicGet(Current);
+ }
+
+ void Acquire();
+ bool TryAcquire();
+ void Increment();
+ void IncrementMultiple(TAtomicBase count);
+ bool TryWait();
+ void Release();
+ void ReleaseMultiple(TAtomicBase count);
+ void Stop();
+
+ private:
+ void CheckNeedToUnlock();
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/remote_connection.cpp b/library/cpp/messagebus/remote_connection.cpp
new file mode 100644
index 0000000000..22932569db
--- /dev/null
+++ b/library/cpp/messagebus/remote_connection.cpp
@@ -0,0 +1,974 @@
+#include "remote_connection.h"
+
+#include "key_value_printer.h"
+#include "mb_lwtrace.h"
+#include "network.h"
+#include "remote_client_connection.h"
+#include "remote_client_session.h"
+#include "remote_server_session.h"
+#include "session_impl.h"
+
+#include <library/cpp/messagebus/actor/what_thread_does.h>
+
+#include <util/generic/cast.h>
+#include <util/network/init.h>
+#include <util/system/atomic.h>
+
+LWTRACE_USING(LWTRACE_MESSAGEBUS_PROVIDER)
+
+using namespace NActor;
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+namespace NBus {
+ namespace NPrivate {
+ TRemoteConnection::TRemoteConnection(TRemoteSessionPtr session, ui64 connectionId, TNetAddr addr)
+ : TActor<TRemoteConnection, TWriterTag>(session->Queue->WorkQueue.Get())
+ , TActor<TRemoteConnection, TReaderTag>(session->Queue->WorkQueue.Get())
+ , TScheduleActor<TRemoteConnection, TWriterTag>(&session->Queue->Scheduler)
+ , Session(session)
+ , Proto(session->Proto)
+ , Config(session->Config)
+ , RemovedFromSession(false)
+ , ConnectionId(connectionId)
+ , PeerAddr(addr)
+ , PeerAddrSocketAddr(addr)
+ , CreatedTime(TInstant::Now())
+ , ReturnConnectFailedImmediately(false)
+ , GranStatus(Config.Secret.StatusFlushPeriod)
+ , QuotaMsg(!Session->IsSource_, Config.PerConnectionMaxInFlight, 0)
+ , QuotaBytes(!Session->IsSource_, Config.PerConnectionMaxInFlightBySize, 0)
+ , MaxBufferSize(session->Config.MaxBufferSize)
+ , ShutdownReason(MESSAGE_OK)
+ {
+ WriterData.Status.ConnectionId = connectionId;
+ WriterData.Status.PeerAddr = PeerAddr;
+ ReaderData.Status.ConnectionId = connectionId;
+
+ const TInstant now = TInstant::Now();
+
+ WriterFillStatus();
+
+ GranStatus.Writer.Update(WriterData.Status, now, true);
+ GranStatus.Reader.Update(ReaderData.Status, now, true);
+ }
+
+ TRemoteConnection::~TRemoteConnection() {
+ Y_VERIFY(ReplyQueue.IsEmpty());
+ }
+
+ TRemoteConnection::TWriterData::TWriterData()
+ : Down(0)
+ , SocketVersion(0)
+ , InFlight(0)
+ , AwakeFlags(0)
+ , State(WRITER_FILLING)
+ {
+ }
+
+ TRemoteConnection::TWriterData::~TWriterData() {
+ Y_VERIFY(AtomicGet(Down));
+ Y_VERIFY(SendQueue.Empty());
+ }
+
+ bool TRemoteConnection::TReaderData::HasBytesInBuf(size_t bytes) noexcept {
+ size_t left = Buffer.Size() - Offset;
+
+ return (MoreBytes = left >= bytes ? 0 : bytes - left) == 0;
+ }
+
+ void TRemoteConnection::TWriterData::SetChannel(NEventLoop::TChannelPtr channel) {
+ Y_VERIFY(!Channel, "must not have channel");
+ Y_VERIFY(Buffer.GetBuffer().Empty() && Buffer.LeftSize() == 0, "buffer must be empty");
+ Y_VERIFY(State == WRITER_FILLING, "state must be initial");
+ Channel = channel;
+ }
+
+ void TRemoteConnection::TReaderData::SetChannel(NEventLoop::TChannelPtr channel) {
+ Y_VERIFY(!Channel, "must not have channel");
+ Y_VERIFY(Buffer.Empty(), "buffer must be empty");
+ Channel = channel;
+ }
+
+ void TRemoteConnection::TWriterData::DropChannel() {
+ if (!!Channel) {
+ Channel->Unregister();
+ Channel.Drop();
+ }
+
+ Buffer.Reset();
+ State = WRITER_FILLING;
+ }
+
+ void TRemoteConnection::TReaderData::DropChannel() {
+ // TODO: make Drop call Unregister
+ if (!!Channel) {
+ Channel->Unregister();
+ Channel.Drop();
+ }
+ Buffer.Reset();
+ Offset = 0;
+ }
+
+ TRemoteConnection::TReaderData::TReaderData()
+ : Down(0)
+ , SocketVersion(0)
+ , Offset(0)
+ , MoreBytes(0)
+ {
+ }
+
+ TRemoteConnection::TReaderData::~TReaderData() {
+ Y_VERIFY(AtomicGet(Down));
+ }
+
+ void TRemoteConnection::Send(TNonDestroyingAutoPtr<TBusMessage> msg) {
+ BeforeSendQueue.Enqueue(msg.Release());
+ AtomicIncrement(WriterData.InFlight);
+ ScheduleWrite();
+ }
+
+ void TRemoteConnection::ClearOutgoingQueue(TMessagesPtrs& result, bool reconnect) {
+ if (!reconnect) {
+ // Do not clear send queue if reconnecting
+ WriterData.SendQueue.Clear(&result);
+ }
+ }
+
+ void TRemoteConnection::Shutdown(EMessageStatus status) {
+ ScheduleShutdown(status);
+
+ ReaderData.ShutdownComplete.WaitI();
+ WriterData.ShutdownComplete.WaitI();
+ }
+
+ void TRemoteConnection::TryConnect() {
+ Y_FAIL("TryConnect is client connection only operation");
+ }
+
+ void TRemoteConnection::ScheduleRead() {
+ GetReaderActor()->Schedule();
+ }
+
+ void TRemoteConnection::ScheduleWrite() {
+ GetWriterActor()->Schedule();
+ }
+
+ void TRemoteConnection::WriterRotateCounters() {
+ if (!WriterData.TimeToRotateCounters.FetchTask()) {
+ return;
+ }
+
+ WriterData.Status.DurationCounterPrev = WriterData.Status.DurationCounter;
+ Reset(WriterData.Status.DurationCounter);
+ }
+
+ void TRemoteConnection::WriterSendStatus(TInstant now, bool force) {
+ GranStatus.Writer.Update(std::bind(&TRemoteConnection::WriterGetStatus, this), now, force);
+ }
+
+ void TRemoteConnection::ReaderSendStatus(TInstant now, bool force) {
+ GranStatus.Reader.Update(std::bind(&TRemoteConnection::ReaderFillStatus, this), now, force);
+ }
+
+ const TRemoteConnectionReaderStatus& TRemoteConnection::ReaderFillStatus() {
+ ReaderData.Status.BufferSize = ReaderData.Buffer.Capacity();
+ ReaderData.Status.QuotaMsg = QuotaMsg.Tokens();
+ ReaderData.Status.QuotaBytes = QuotaBytes.Tokens();
+
+ return ReaderData.Status;
+ }
+
+ void TRemoteConnection::ProcessItem(TReaderTag, ::NActor::TDefaultTag, TWriterToReaderSocketMessage readSocket) {
+ if (AtomicGet(ReaderData.Down)) {
+ ReaderData.Status.Fd = INVALID_SOCKET;
+ return;
+ }
+
+ ReaderData.DropChannel();
+
+ ReaderData.Status.Fd = readSocket.Socket;
+ ReaderData.SocketVersion = readSocket.SocketVersion;
+
+ if (readSocket.Socket != INVALID_SOCKET) {
+ ReaderData.SetChannel(Session->ReadEventLoop.Register(readSocket.Socket, this, ReadCookie));
+ ReaderData.Channel->EnableRead();
+ }
+ }
+
+ void TRemoteConnection::ProcessItem(TWriterTag, TReconnectTag, ui32 socketVersion) {
+ Y_VERIFY(socketVersion <= WriterData.SocketVersion, "something weird");
+
+ if (WriterData.SocketVersion != socketVersion) {
+ return;
+ }
+ Y_VERIFY(WriterData.Status.Connected, "must be connected at this point");
+ Y_VERIFY(!!WriterData.Channel, "must have channel at this point");
+
+ WriterData.Status.Connected = false;
+ WriterData.DropChannel();
+ WriterData.Status.MyAddr = TNetAddr();
+ ++WriterData.SocketVersion;
+ LastConnectAttempt = TInstant();
+
+ TMessagesPtrs cleared;
+ ClearOutgoingQueue(cleared, true);
+ WriterErrorMessages(cleared, MESSAGE_DELIVERY_FAILED);
+
+ FireClientConnectionEvent(TClientConnectionEvent::DISCONNECTED);
+
+ ReaderGetSocketQueue()->EnqueueAndSchedule(TWriterToReaderSocketMessage(INVALID_SOCKET, WriterData.SocketVersion));
+ }
+
+ void TRemoteConnection::ProcessItem(TWriterTag, TWakeReaderTag, ui32 awakeFlags) {
+ WriterData.AwakeFlags |= awakeFlags;
+
+ ReadQuotaWakeup();
+ }
+
+ void TRemoteConnection::Act(TReaderTag) {
+ TInstant now = TInstant::Now();
+
+ ReaderData.Status.Acts += 1;
+
+ ReaderGetSocketQueue()->DequeueAllLikelyEmpty();
+
+ if (AtomicGet(ReaderData.Down)) {
+ ReaderData.DropChannel();
+
+ ReaderProcessStatusDown();
+ ReaderData.ShutdownComplete.Signal();
+
+ } else if (!!ReaderData.Channel) {
+ Y_ASSERT(ReaderData.ReadMessages.empty());
+
+ for (int i = 0;; ++i) {
+ if (i == 100) {
+ // perform other tasks
+ GetReaderActor()->AddTaskFromActorLoop();
+ break;
+ }
+
+ if (NeedInterruptRead()) {
+ ReaderData.Channel->EnableRead();
+ break;
+ }
+
+ if (!ReaderFillBuffer())
+ break;
+
+ if (!ReaderProcessBuffer())
+ break;
+ }
+
+ ReaderFlushMessages();
+ }
+
+ ReaderSendStatus(now);
+ }
+
+ bool TRemoteConnection::QuotaAcquire(size_t msg, size_t bytes) {
+ ui32 wakeFlags = 0;
+
+ if (!QuotaMsg.Acquire(msg))
+ wakeFlags |= WAKE_QUOTA_MSG;
+
+ else if (!QuotaBytes.Acquire(bytes))
+ wakeFlags |= WAKE_QUOTA_BYTES;
+
+ if (wakeFlags) {
+ ReaderData.Status.QuotaExhausted++;
+
+ WriterGetWakeQueue()->EnqueueAndSchedule(wakeFlags);
+ }
+
+ return wakeFlags == 0;
+ }
+
+ void TRemoteConnection::QuotaConsume(size_t msg, size_t bytes) {
+ QuotaMsg.Consume(msg);
+ QuotaBytes.Consume(bytes);
+ }
+
+ void TRemoteConnection::QuotaReturnSelf(size_t items, size_t bytes) {
+ if (QuotaReturnValues(items, bytes))
+ ReadQuotaWakeup();
+ }
+
+ void TRemoteConnection::QuotaReturnAside(size_t items, size_t bytes) {
+ if (QuotaReturnValues(items, bytes) && !AtomicGet(WriterData.Down))
+ WriterGetWakeQueue()->EnqueueAndSchedule(0x0);
+ }
+
+ bool TRemoteConnection::QuotaReturnValues(size_t items, size_t bytes) {
+ bool rMsg = QuotaMsg.Return(items);
+ bool rBytes = QuotaBytes.Return(bytes);
+
+ return rMsg || rBytes;
+ }
+
+ void TRemoteConnection::ReadQuotaWakeup() {
+ const ui32 mask = WriterData.AwakeFlags & WriteWakeFlags();
+
+ if (mask && mask == WriterData.AwakeFlags) {
+ WriterData.Status.ReaderWakeups++;
+ WriterData.AwakeFlags = 0;
+
+ ScheduleRead();
+ }
+ }
+
+ ui32 TRemoteConnection::WriteWakeFlags() const {
+ ui32 awakeFlags = 0;
+
+ if (QuotaMsg.IsAboveWake())
+ awakeFlags |= WAKE_QUOTA_MSG;
+
+ if (QuotaBytes.IsAboveWake())
+ awakeFlags |= WAKE_QUOTA_BYTES;
+
+ return awakeFlags;
+ }
+
+ bool TRemoteConnection::ReaderProcessBuffer() {
+ TInstant now = TInstant::Now();
+
+ for (;;) {
+ if (!ReaderData.HasBytesInBuf(sizeof(TBusHeader))) {
+ break;
+ }
+
+ TBusHeader header(MakeArrayRef(ReaderData.Buffer.Data() + ReaderData.Offset, ReaderData.Buffer.Size() - ReaderData.Offset));
+
+ if (header.Size < sizeof(TBusHeader)) {
+ LWPROBE(Error, ToString(MESSAGE_HEADER_CORRUPTED), ToString(PeerAddr), ToString(header.Size));
+ ReaderData.Status.Incremental.StatusCounter[MESSAGE_HEADER_CORRUPTED] += 1;
+ ScheduleShutdownOnServerOrReconnectOnClient(MESSAGE_HEADER_CORRUPTED, false);
+ return false;
+ }
+
+ if (!IsVersionNegotiation(header) && !IsBusKeyValid(header.Id)) {
+ LWPROBE(Error, ToString(MESSAGE_HEADER_CORRUPTED), ToString(PeerAddr), ToString(header.Size));
+ ReaderData.Status.Incremental.StatusCounter[MESSAGE_HEADER_CORRUPTED] += 1;
+ ScheduleShutdownOnServerOrReconnectOnClient(MESSAGE_HEADER_CORRUPTED, false);
+ return false;
+ }
+
+ if (header.Size > Config.MaxMessageSize) {
+ LWPROBE(Error, ToString(MESSAGE_MESSAGE_TOO_LARGE), ToString(PeerAddr), ToString(header.Size));
+ ReaderData.Status.Incremental.StatusCounter[MESSAGE_MESSAGE_TOO_LARGE] += 1;
+ ScheduleShutdownOnServerOrReconnectOnClient(MESSAGE_MESSAGE_TOO_LARGE, false);
+ return false;
+ }
+
+ if (!ReaderData.HasBytesInBuf(header.Size)) {
+ if (ReaderData.Offset == 0) {
+ ReaderData.Buffer.Reserve(header.Size);
+ }
+ break;
+ }
+
+ if (!QuotaAcquire(1, header.Size))
+ return false;
+
+ if (!MessageRead(MakeArrayRef(ReaderData.Buffer.Data() + ReaderData.Offset, header.Size), now)) {
+ return false;
+ }
+
+ ReaderData.Offset += header.Size;
+ }
+
+ ReaderData.Buffer.ChopHead(ReaderData.Offset);
+ ReaderData.Offset = 0;
+
+ if (ReaderData.Buffer.Capacity() > MaxBufferSize && ReaderData.Buffer.Size() <= MaxBufferSize) {
+ ReaderData.Status.Incremental.BufferDrops += 1;
+
+ TBuffer temp;
+ // probably should use another constant
+ temp.Reserve(Config.DefaultBufferSize);
+ temp.Append(ReaderData.Buffer.Data(), ReaderData.Buffer.Size());
+
+ ReaderData.Buffer.Swap(temp);
+ }
+
+ return true;
+ }
+
+ bool TRemoteConnection::ReaderFillBuffer() {
+ if (!ReaderData.BufferMore())
+ return true;
+
+ if (ReaderData.Buffer.Avail() == 0) {
+ if (ReaderData.Buffer.Size() == 0) {
+ ReaderData.Buffer.Reserve(Config.DefaultBufferSize);
+ } else {
+ ReaderData.Buffer.Reserve(ReaderData.Buffer.Size() * 2);
+ }
+ }
+
+ Y_ASSERT(ReaderData.Buffer.Avail() > 0);
+
+ ssize_t bytes;
+ {
+ TWhatThreadDoesPushPop pp("recv syscall");
+ bytes = SocketRecv(ReaderData.Channel->GetSocket(), TArrayRef<char>(ReaderData.Buffer.Pos(), ReaderData.Buffer.Avail()));
+ }
+
+ if (bytes < 0) {
+ if (WouldBlock()) {
+ ReaderData.Channel->EnableRead();
+ return false;
+ } else {
+ ReaderData.Channel->DisableRead();
+ ScheduleShutdownOnServerOrReconnectOnClient(MESSAGE_DELIVERY_FAILED, false);
+ return false;
+ }
+ }
+
+ if (bytes == 0) {
+ ReaderData.Channel->DisableRead();
+ // TODO: incorrect: it is possible that only input is shutdown, and output is available
+ ScheduleShutdownOnServerOrReconnectOnClient(MESSAGE_DELIVERY_FAILED, false);
+ return false;
+ }
+
+ ReaderData.Status.Incremental.NetworkOps += 1;
+
+ ReaderData.Buffer.Advance(bytes);
+ ReaderData.MoreBytes = 0;
+ return true;
+ }
+
+ void TRemoteConnection::ClearBeforeSendQueue(EMessageStatus reason) {
+ BeforeSendQueue.DequeueAll(std::bind(&TRemoteConnection::WriterBeforeWriteErrorMessage, this, std::placeholders::_1, reason));
+ }
+
+ void TRemoteConnection::ClearReplyQueue(EMessageStatus reason) {
+ TVectorSwaps<TBusMessagePtrAndHeader> replyQueueTemp;
+ Y_ASSERT(replyQueueTemp.empty());
+ ReplyQueue.DequeueAllSingleConsumer(&replyQueueTemp);
+
+ TVector<TBusMessage*> messages;
+ for (TVectorSwaps<TBusMessagePtrAndHeader>::reverse_iterator message = replyQueueTemp.rbegin();
+ message != replyQueueTemp.rend(); ++message) {
+ messages.push_back(message->MessagePtr.Release());
+ }
+
+ WriterErrorMessages(messages, reason);
+
+ replyQueueTemp.clear();
+ }
+
+ void TRemoteConnection::ProcessBeforeSendQueueMessage(TBusMessage* message, TInstant now) {
+ // legacy clients expect this field to be set
+ if (!Session->IsSource_) {
+ message->SendTime = now.MilliSeconds();
+ }
+
+ WriterData.SendQueue.PushBack(message);
+ }
+
+ void TRemoteConnection::ProcessBeforeSendQueue(TInstant now) {
+ BeforeSendQueue.DequeueAll(std::bind(&TRemoteConnection::ProcessBeforeSendQueueMessage, this, std::placeholders::_1, now));
+ }
+
+ void TRemoteConnection::WriterFillInFlight() {
+ // this is hack for TLoadBalancedProtocol
+ WriterFillStatus();
+ AtomicSet(WriterData.InFlight, WriterData.Status.GetInFlight());
+ }
+
+ const TRemoteConnectionWriterStatus& TRemoteConnection::WriterGetStatus() {
+ WriterRotateCounters();
+ WriterFillStatus();
+
+ return WriterData.Status;
+ }
+
+ void TRemoteConnection::WriterFillStatus() {
+ if (!!WriterData.Channel) {
+ WriterData.Status.Fd = WriterData.Channel->GetSocket();
+ } else {
+ WriterData.Status.Fd = INVALID_SOCKET;
+ }
+ WriterData.Status.BufferSize = WriterData.Buffer.Capacity();
+ WriterData.Status.SendQueueSize = WriterData.SendQueue.Size();
+ WriterData.Status.State = WriterData.State;
+ }
+
+ void TRemoteConnection::WriterProcessStatusDown() {
+ Session->GetDeadConnectionWriterStatusQueue()->EnqueueAndSchedule(WriterData.Status.Incremental);
+ Reset(WriterData.Status.Incremental);
+ }
+
+ void TRemoteConnection::ReaderProcessStatusDown() {
+ Session->GetDeadConnectionReaderStatusQueue()->EnqueueAndSchedule(ReaderData.Status.Incremental);
+ Reset(ReaderData.Status.Incremental);
+ }
+
+ void TRemoteConnection::ProcessWriterDown() {
+ if (!RemovedFromSession) {
+ Session->GetRemoveConnectionQueue()->EnqueueAndSchedule(this);
+
+ if (Session->IsSource_) {
+ if (WriterData.Status.Connected) {
+ FireClientConnectionEvent(TClientConnectionEvent::DISCONNECTED);
+ }
+ }
+
+ LWPROBE(Disconnected, ToString(PeerAddr));
+ RemovedFromSession = true;
+ }
+
+ WriterData.DropChannel();
+
+ DropEnqueuedData(ShutdownReason, MESSAGE_SHUTDOWN);
+
+ WriterProcessStatusDown();
+
+ WriterData.ShutdownComplete.Signal();
+ }
+
+ void TRemoteConnection::DropEnqueuedData(EMessageStatus reason, EMessageStatus reasonForQueues) {
+ ClearReplyQueue(reasonForQueues);
+ ClearBeforeSendQueue(reasonForQueues);
+ WriterGetReconnectQueue()->Clear();
+ WriterGetWakeQueue()->Clear();
+
+ TMessagesPtrs cleared;
+ ClearOutgoingQueue(cleared, false);
+
+ if (!Session->IsSource_) {
+ for (auto& i : cleared) {
+ TBusMessagePtrAndHeader h(i);
+ CheckedCast<TRemoteServerSession*>(Session.Get())->ReleaseInWorkResponses(MakeArrayRef(&h, 1));
+ // assignment back is weird
+ i = h.MessagePtr.Release();
+ // and this part is not batch
+ }
+ }
+
+ WriterErrorMessages(cleared, reason);
+ }
+
+ void TRemoteConnection::BeforeTryWrite() {
+ }
+
+ void TRemoteConnection::Act(TWriterTag) {
+ TInstant now = TInstant::Now();
+
+ WriterData.Status.Acts += 1;
+
+ if (Y_UNLIKELY(AtomicGet(WriterData.Down))) {
+ // dump status must work even if WriterDown
+ WriterSendStatus(now, true);
+ ProcessWriterDown();
+ return;
+ }
+
+ ProcessBeforeSendQueue(now);
+
+ BeforeTryWrite();
+
+ WriterFillInFlight();
+
+ WriterGetReconnectQueue()->DequeueAllLikelyEmpty();
+
+ if (!WriterData.Status.Connected) {
+ TryConnect();
+ } else {
+ for (int i = 0;; ++i) {
+ if (i == 100) {
+ // perform other tasks
+ GetWriterActor()->AddTaskFromActorLoop();
+ break;
+ }
+
+ if (WriterData.State == WRITER_FILLING) {
+ WriterFillBuffer();
+
+ if (WriterData.State == WRITER_FILLING) {
+ WriterData.Channel->DisableWrite();
+ break;
+ }
+
+ Y_ASSERT(!WriterData.Buffer.Empty());
+ }
+
+ if (WriterData.State == WRITER_FLUSHING) {
+ WriterFlushBuffer();
+
+ if (WriterData.State == WRITER_FLUSHING) {
+ break;
+ }
+ }
+ }
+ }
+
+ WriterGetWakeQueue()->DequeueAllLikelyEmpty();
+
+ WriterSendStatus(now);
+ }
+
+ void TRemoteConnection::WriterFlushBuffer() {
+ Y_ASSERT(WriterData.State == WRITER_FLUSHING);
+ Y_ASSERT(!WriterData.Buffer.Empty());
+
+ WriterData.CorkUntil = TInstant::Zero();
+
+ while (!WriterData.Buffer.Empty()) {
+ ssize_t bytes;
+ {
+ TWhatThreadDoesPushPop pp("send syscall");
+ bytes = SocketSend(WriterData.Channel->GetSocket(), TArrayRef<const char>(WriterData.Buffer.LeftPos(), WriterData.Buffer.Size()));
+ }
+
+ if (bytes < 0) {
+ if (WouldBlock()) {
+ WriterData.Channel->EnableWrite();
+ return;
+ } else {
+ WriterData.Channel->DisableWrite();
+ ScheduleShutdownOnServerOrReconnectOnClient(MESSAGE_DELIVERY_FAILED, true);
+ return;
+ }
+ }
+
+ WriterData.Status.Incremental.NetworkOps += 1;
+
+ WriterData.Buffer.LeftProceed(bytes);
+ }
+
+ WriterData.Buffer.Clear();
+ if (WriterData.Buffer.Capacity() > MaxBufferSize) {
+ WriterData.Status.Incremental.BufferDrops += 1;
+ WriterData.Buffer.Reset();
+ }
+
+ WriterData.State = WRITER_FILLING;
+ }
+
+ void TRemoteConnection::ScheduleShutdownOnServerOrReconnectOnClient(EMessageStatus status, bool writer) {
+ if (Session->IsSource_) {
+ WriterGetReconnectQueue()->EnqueueAndSchedule(writer ? WriterData.SocketVersion : ReaderData.SocketVersion);
+ } else {
+ ScheduleShutdown(status);
+ }
+ }
+
+ void TRemoteConnection::ScheduleShutdown(EMessageStatus status) {
+ ShutdownReason = status;
+
+ AtomicSet(ReaderData.Down, 1);
+ ScheduleRead();
+
+ AtomicSet(WriterData.Down, 1);
+ ScheduleWrite();
+ }
+
+ void TRemoteConnection::CallSerialize(TBusMessage* msg, TBuffer& buffer) const {
+ size_t posForAssertion = buffer.Size();
+ Proto->Serialize(msg, buffer);
+ Y_VERIFY(buffer.Size() >= posForAssertion,
+ "incorrect Serialize implementation, pos before serialize: %d, pos after serialize: %d",
+ int(posForAssertion), int(buffer.Size()));
+ }
+
+ namespace {
+ inline void WriteHeader(const TBusHeader& header, TBuffer& data) {
+ data.Reserve(data.Size() + sizeof(TBusHeader));
+ /// \todo hton instead of memcpy
+ memcpy(data.Data() + data.Size(), &header, sizeof(TBusHeader));
+ data.Advance(sizeof(TBusHeader));
+ }
+
+ inline void WriteDummyHeader(TBuffer& data) {
+ data.Resize(data.Size() + sizeof(TBusHeader));
+ }
+
+ }
+
+ void TRemoteConnection::SerializeMessage(TBusMessage* msg, TBuffer* data, TMessageCounter* counter) const {
+ size_t pos = data->Size();
+
+ size_t dataSize;
+
+ bool compressionRequested = msg->IsCompressed();
+
+ if (compressionRequested) {
+ TBuffer compdata;
+ TBuffer plaindata;
+ CallSerialize(msg, plaindata);
+
+ dataSize = sizeof(TBusHeader) + plaindata.Size();
+
+ NCodecs::TCodecPtr c = Proto->GetTransportCodec();
+ c->Encode(TStringBuf{plaindata.data(), plaindata.size()}, compdata);
+
+ if (compdata.Size() < plaindata.Size()) {
+ plaindata.Clear();
+ msg->GetHeader()->Size = sizeof(TBusHeader) + compdata.Size();
+ WriteHeader(*msg->GetHeader(), *data);
+ data->Append(compdata.Data(), compdata.Size());
+ } else {
+ compdata.Clear();
+ msg->SetCompressed(false);
+ msg->GetHeader()->Size = sizeof(TBusHeader) + plaindata.Size();
+ WriteHeader(*msg->GetHeader(), *data);
+ data->Append(plaindata.Data(), plaindata.Size());
+ }
+ } else {
+ WriteDummyHeader(*data);
+ CallSerialize(msg, *data);
+
+ dataSize = msg->GetHeader()->Size = data->Size() - pos;
+
+ data->Proceed(pos);
+ WriteHeader(*msg->GetHeader(), *data);
+ data->Proceed(pos + msg->GetHeader()->Size);
+ }
+
+ Y_ASSERT(msg->GetHeader()->Size == data->Size() - pos);
+ counter->AddMessage(dataSize, data->Size() - pos, msg->IsCompressed(), compressionRequested);
+ }
+
+ TBusMessage* TRemoteConnection::DeserializeMessage(TArrayRef<const char> dataRef, const TBusHeader* header, TMessageCounter* messageCounter, EMessageStatus* status) const {
+ size_t dataSize;
+
+ TBusMessage* message;
+ if (header->FlagsInternal & MESSAGE_COMPRESS_INTERNAL) {
+ TBuffer msg;
+ {
+ TBuffer plaindata;
+ NCodecs::TCodecPtr c = Proto->GetTransportCodec();
+ try {
+ TArrayRef<const char> payload = TBusMessage::GetPayload(dataRef);
+ c->Decode(TStringBuf{payload.data(), payload.size()}, plaindata);
+ } catch (...) {
+ // catch all, because
+ // http://nga.at.yandex-team.ru/replies.xml?item_no=3884
+ *status = MESSAGE_DECOMPRESS_ERROR;
+ return nullptr;
+ }
+
+ msg.Append(dataRef.data(), sizeof(TBusHeader));
+ msg.Append(plaindata.Data(), plaindata.Size());
+ }
+ TArrayRef<const char> msgRef(msg.Data(), msg.Size());
+ dataSize = sizeof(TBusHeader) + msgRef.size();
+ // TODO: track error types
+ message = Proto->Deserialize(header->Type, msgRef.Slice(sizeof(TBusHeader))).Release();
+ if (!message) {
+ *status = MESSAGE_DESERIALIZE_ERROR;
+ return nullptr;
+ }
+ *message->GetHeader() = *header;
+ message->SetCompressed(true);
+ } else {
+ dataSize = dataRef.size();
+ message = Proto->Deserialize(header->Type, dataRef.Slice(sizeof(TBusHeader))).Release();
+ if (!message) {
+ *status = MESSAGE_DESERIALIZE_ERROR;
+ return nullptr;
+ }
+ *message->GetHeader() = *header;
+ }
+
+ messageCounter->AddMessage(dataSize, dataRef.size(), header->FlagsInternal & MESSAGE_COMPRESS_INTERNAL, false);
+
+ return message;
+ }
+
+ void TRemoteConnection::ResetOneWayFlag(TArrayRef<TBusMessage*> messages) {
+ for (auto message : messages) {
+ message->LocalFlags &= ~MESSAGE_ONE_WAY_INTERNAL;
+ }
+ }
+
+ void TRemoteConnection::ReaderFlushMessages() {
+ if (!ReaderData.ReadMessages.empty()) {
+ Session->OnMessageReceived(this, ReaderData.ReadMessages);
+ ReaderData.ReadMessages.clear();
+ }
+ }
+
+ // @return false if actor should break
+ bool TRemoteConnection::MessageRead(TArrayRef<const char> readDataRef, TInstant now) {
+ TBusHeader header(readDataRef);
+
+ Y_ASSERT(readDataRef.size() == header.Size);
+
+ if (header.GetVersionInternal() != YBUS_VERSION) {
+ ReaderProcessMessageUnknownVersion(readDataRef);
+ return true;
+ }
+
+ EMessageStatus deserializeFailureStatus = MESSAGE_OK;
+ TBusMessage* r = DeserializeMessage(readDataRef, &header, &ReaderData.Status.Incremental.MessageCounter, &deserializeFailureStatus);
+
+ if (!r) {
+ Y_VERIFY(deserializeFailureStatus != MESSAGE_OK, "state check");
+ LWPROBE(Error, ToString(deserializeFailureStatus), ToString(PeerAddr), "");
+ ReaderData.Status.Incremental.StatusCounter[deserializeFailureStatus] += 1;
+ ScheduleShutdownOnServerOrReconnectOnClient(deserializeFailureStatus, false);
+ return false;
+ }
+
+ LWPROBE(Read, r->GetHeader()->Size);
+
+ r->ReplyTo = PeerAddrSocketAddr;
+
+ TBusMessagePtrAndHeader h(r);
+ r->RecvTime = now;
+
+ QuotaConsume(1, header.Size);
+
+ ReaderData.ReadMessages.push_back(h);
+ if (ReaderData.ReadMessages.size() >= 100) {
+ ReaderFlushMessages();
+ }
+
+ return true;
+ }
+
+ void TRemoteConnection::WriterFillBuffer() {
+ Y_ASSERT(WriterData.State == WRITER_FILLING);
+
+ Y_ASSERT(WriterData.Buffer.LeftSize() == 0);
+
+ if (Y_UNLIKELY(!WrongVersionRequests.IsEmpty())) {
+ TVector<TBusHeader> headers;
+ WrongVersionRequests.DequeueAllSingleConsumer(&headers);
+ for (TVector<TBusHeader>::reverse_iterator header = headers.rbegin();
+ header != headers.rend(); ++header) {
+ TBusHeader response = *header;
+ response.SendTime = NBus::Now();
+ response.Size = sizeof(TBusHeader);
+ response.FlagsInternal = 0;
+ response.SetVersionInternal(YBUS_VERSION);
+ WriteHeader(response, WriterData.Buffer.GetBuffer());
+ }
+
+ Y_ASSERT(!WriterData.Buffer.Empty());
+ WriterData.State = WRITER_FLUSHING;
+ return;
+ }
+
+ TTempTlsVector<TBusMessagePtrAndHeader, void, TVectorSwaps> writeMessages;
+
+ for (;;) {
+ THolder<TBusMessage> writeMessage(WriterData.SendQueue.PopFront());
+ if (!writeMessage) {
+ break;
+ }
+
+ if (Config.Cork != TDuration::Zero()) {
+ if (WriterData.CorkUntil == TInstant::Zero()) {
+ WriterData.CorkUntil = TInstant::Now() + Config.Cork;
+ }
+ }
+
+ size_t sizeBeforeSerialize = WriterData.Buffer.Size();
+
+ TMessageCounter messageCounter = WriterData.Status.Incremental.MessageCounter;
+
+ SerializeMessage(writeMessage.Get(), &WriterData.Buffer.GetBuffer(), &messageCounter);
+
+ size_t written = WriterData.Buffer.Size() - sizeBeforeSerialize;
+ if (written > Config.MaxMessageSize) {
+ WriterData.Buffer.GetBuffer().EraseBack(written);
+ WriterBeforeWriteErrorMessage(writeMessage.Release(), MESSAGE_MESSAGE_TOO_LARGE);
+ continue;
+ }
+
+ WriterData.Status.Incremental.MessageCounter = messageCounter;
+
+ TBusMessagePtrAndHeader h(writeMessage.Release());
+ writeMessages.GetVector()->push_back(h);
+
+ Y_ASSERT(!WriterData.Buffer.Empty());
+ if (WriterData.Buffer.Size() >= Config.SendThreshold) {
+ break;
+ }
+ }
+
+ if (!WriterData.Buffer.Empty()) {
+ if (WriterData.Buffer.Size() >= Config.SendThreshold) {
+ WriterData.State = WRITER_FLUSHING;
+ } else if (WriterData.CorkUntil == TInstant::Zero()) {
+ WriterData.State = WRITER_FLUSHING;
+ } else if (TInstant::Now() >= WriterData.CorkUntil) {
+ WriterData.State = WRITER_FLUSHING;
+ } else {
+ // keep filling
+ Y_ASSERT(WriterData.State == WRITER_FILLING);
+ GetWriterSchedulerActor()->ScheduleAt(WriterData.CorkUntil);
+ }
+ } else {
+ // keep filling
+ Y_ASSERT(WriterData.State == WRITER_FILLING);
+ }
+
+ size_t bytes = MessageSize(*writeMessages.GetVector());
+
+ QuotaReturnSelf(writeMessages.GetVector()->size(), bytes);
+
+ // This is called before `send` syscall inducing latency
+ MessageSent(*writeMessages.GetVector());
+ }
+
+ size_t TRemoteConnection::MessageSize(TArrayRef<TBusMessagePtrAndHeader> messages) {
+ size_t size = 0;
+ for (const auto& message : messages)
+ size += message.MessagePtr->RequestSize;
+
+ return size;
+ }
+
+ size_t TRemoteConnection::GetInFlight() {
+ return AtomicGet(WriterData.InFlight);
+ }
+
+ size_t TRemoteConnection::GetConnectSyscallsNumForTest() {
+ return WriterData.Status.ConnectSyscalls;
+ }
+
+ void TRemoteConnection::WriterBeforeWriteErrorMessage(TBusMessage* message, EMessageStatus status) {
+ if (Session->IsSource_) {
+ CheckedCast<TRemoteClientSession*>(Session.Get())->ReleaseInFlight({message});
+ WriterErrorMessage(message, status);
+ } else {
+ TBusMessagePtrAndHeader h(message);
+ CheckedCast<TRemoteServerSession*>(Session.Get())->ReleaseInWorkResponses(MakeArrayRef(&h, 1));
+ WriterErrorMessage(h.MessagePtr.Release(), status);
+ }
+ }
+
+ void TRemoteConnection::WriterErrorMessage(TNonDestroyingAutoPtr<TBusMessage> m, EMessageStatus status) {
+ TBusMessage* released = m.Release();
+ WriterErrorMessages(MakeArrayRef(&released, 1), status);
+ }
+
+ void TRemoteConnection::WriterErrorMessages(const TArrayRef<TBusMessage*> ms, EMessageStatus status) {
+ ResetOneWayFlag(ms);
+
+ WriterData.Status.Incremental.StatusCounter[status] += ms.size();
+ for (auto m : ms) {
+ Session->InvokeOnError(m, status);
+ }
+ }
+
+ void TRemoteConnection::FireClientConnectionEvent(TClientConnectionEvent::EType type) {
+ Y_VERIFY(Session->IsSource_, "state check");
+ TClientConnectionEvent event(type, ConnectionId, PeerAddr);
+ TRemoteClientSession* session = CheckedCast<TRemoteClientSession*>(Session.Get());
+ session->ClientHandler->OnClientConnectionEvent(event);
+ }
+
+ bool TRemoteConnection::IsAlive() const {
+ return !AtomicGet(WriterData.Down);
+ }
+
+ }
+}
diff --git a/library/cpp/messagebus/remote_connection.h b/library/cpp/messagebus/remote_connection.h
new file mode 100644
index 0000000000..4538947368
--- /dev/null
+++ b/library/cpp/messagebus/remote_connection.h
@@ -0,0 +1,294 @@
+#pragma once
+
+#include "async_result.h"
+#include "defs.h"
+#include "event_loop.h"
+#include "left_right_buffer.h"
+#include "lfqueue_batch.h"
+#include "message_ptr_and_header.h"
+#include "nondestroying_holder.h"
+#include "remote_connection_status.h"
+#include "scheduler_actor.h"
+#include "socket_addr.h"
+#include "storage.h"
+#include "vector_swaps.h"
+#include "ybus.h"
+#include "misc/granup.h"
+#include "misc/tokenquota.h"
+
+#include <library/cpp/messagebus/actor/actor.h>
+#include <library/cpp/messagebus/actor/executor.h>
+#include <library/cpp/messagebus/actor/queue_for_actor.h>
+#include <library/cpp/messagebus/actor/queue_in_actor.h>
+#include <library/cpp/messagebus/scheduler/scheduler.h>
+
+#include <util/system/atomic.h>
+#include <util/system/event.h>
+#include <util/thread/lfstack.h>
+
+namespace NBus {
+ namespace NPrivate {
+ class TRemoteConnection;
+
+ typedef TIntrusivePtr<TRemoteConnection> TRemoteConnectionPtr;
+ typedef TIntrusivePtr<TBusSessionImpl> TRemoteSessionPtr;
+
+ static void* const WriteCookie = (void*)1;
+ static void* const ReadCookie = (void*)2;
+
+ enum {
+ WAKE_QUOTA_MSG = 0x01,
+ WAKE_QUOTA_BYTES = 0x02
+ };
+
+ struct TWriterTag {};
+ struct TReaderTag {};
+ struct TReconnectTag {};
+ struct TWakeReaderTag {};
+
+ struct TWriterToReaderSocketMessage {
+ TSocket Socket;
+ ui32 SocketVersion;
+
+ TWriterToReaderSocketMessage(TSocket socket, ui32 socketVersion)
+ : Socket(socket)
+ , SocketVersion(socketVersion)
+ {
+ }
+ };
+
+ class TRemoteConnection
+ : public NEventLoop::IEventHandler,
+ public ::NActor::TActor<TRemoteConnection, TWriterTag>,
+ public ::NActor::TActor<TRemoteConnection, TReaderTag>,
+ private ::NActor::TQueueInActor<TRemoteConnection, TWriterToReaderSocketMessage, TReaderTag>,
+ private ::NActor::TQueueInActor<TRemoteConnection, ui32, TWriterTag, TReconnectTag>,
+ private ::NActor::TQueueInActor<TRemoteConnection, ui32, TWriterTag, TWakeReaderTag>,
+ public TScheduleActor<TRemoteConnection, TWriterTag> {
+ friend struct TBusSessionImpl;
+ friend class TRemoteClientSession;
+ friend class TRemoteServerSession;
+ friend class ::NActor::TQueueInActor<TRemoteConnection, TWriterToReaderSocketMessage, TReaderTag>;
+ friend class ::NActor::TQueueInActor<TRemoteConnection, ui32, TWriterTag, TReconnectTag>;
+ friend class ::NActor::TQueueInActor<TRemoteConnection, ui32, TWriterTag, TWakeReaderTag>;
+
+ protected:
+ ::NActor::TQueueInActor<TRemoteConnection, TWriterToReaderSocketMessage, TReaderTag>* ReaderGetSocketQueue() {
+ return this;
+ }
+
+ ::NActor::TQueueInActor<TRemoteConnection, ui32, TWriterTag, TReconnectTag>* WriterGetReconnectQueue() {
+ return this;
+ }
+
+ ::NActor::TQueueInActor<TRemoteConnection, ui32, TWriterTag, TWakeReaderTag>* WriterGetWakeQueue() {
+ return this;
+ }
+
+ protected:
+ TRemoteConnection(TRemoteSessionPtr session, ui64 connectionId, TNetAddr addr);
+ ~TRemoteConnection() override;
+
+ virtual void ClearOutgoingQueue(TMessagesPtrs&, bool reconnect /* or shutdown */);
+
+ public:
+ void Send(TNonDestroyingAutoPtr<TBusMessage> msg);
+ void Shutdown(EMessageStatus status);
+
+ inline const TNetAddr& GetAddr() const noexcept;
+
+ private:
+ friend class TScheduleConnect;
+ friend class TWorkIO;
+
+ protected:
+ static size_t MessageSize(TArrayRef<TBusMessagePtrAndHeader>);
+ bool QuotaAcquire(size_t msg, size_t bytes);
+ void QuotaConsume(size_t msg, size_t bytes);
+ void QuotaReturnSelf(size_t items, size_t bytes);
+ bool QuotaReturnValues(size_t items, size_t bytes);
+
+ bool ReaderProcessBuffer();
+ bool ReaderFillBuffer();
+ void ReaderFlushMessages();
+
+ void ReadQuotaWakeup();
+ ui32 WriteWakeFlags() const;
+
+ virtual bool NeedInterruptRead() {
+ return false;
+ }
+
+ public:
+ virtual void TryConnect();
+ void ProcessItem(TReaderTag, ::NActor::TDefaultTag, TWriterToReaderSocketMessage);
+ void ProcessItem(TWriterTag, TReconnectTag, ui32 socketVersion);
+ void ProcessItem(TWriterTag, TWakeReaderTag, ui32 awakeFlags);
+ void Act(TReaderTag);
+ inline void WriterBeforeWriteErrorMessage(TBusMessage*, EMessageStatus);
+ void ClearBeforeSendQueue(EMessageStatus reasonForQueues);
+ void ClearReplyQueue(EMessageStatus reasonForQueues);
+ inline void ProcessBeforeSendQueueMessage(TBusMessage*, TInstant now);
+ void ProcessBeforeSendQueue(TInstant now);
+ void WriterProcessStatusDown();
+ void ReaderProcessStatusDown();
+ void ProcessWriterDown();
+ void DropEnqueuedData(EMessageStatus reason, EMessageStatus reasonForQueues);
+ const TRemoteConnectionWriterStatus& WriterGetStatus();
+ virtual void WriterFillStatus();
+ void WriterFillInFlight();
+ virtual void BeforeTryWrite();
+ void Act(TWriterTag);
+ void ScheduleRead();
+ void ScheduleWrite();
+ void ScheduleShutdownOnServerOrReconnectOnClient(EMessageStatus status, bool writer);
+ void ScheduleShutdown(EMessageStatus status);
+ void WriterFlushBuffer();
+ void WriterFillBuffer();
+ void ReaderSendStatus(TInstant now, bool force = false);
+ const TRemoteConnectionReaderStatus& ReaderFillStatus();
+ void WriterRotateCounters();
+ void WriterSendStatus(TInstant now, bool force = false);
+ void WriterSendStatusIfNecessary(TInstant now);
+ void QuotaReturnAside(size_t items, size_t bytes);
+ virtual void ReaderProcessMessageUnknownVersion(TArrayRef<const char> dataRef) = 0;
+ bool MessageRead(TArrayRef<const char> dataRef, TInstant now);
+ virtual void MessageSent(TArrayRef<TBusMessagePtrAndHeader> messages) = 0;
+
+ void CallSerialize(TBusMessage* msg, TBuffer& buffer) const;
+ void SerializeMessage(TBusMessage* msg, TBuffer* data, TMessageCounter* counter) const;
+ TBusMessage* DeserializeMessage(TArrayRef<const char> dataRef, const TBusHeader* header, TMessageCounter* messageCounter, EMessageStatus* status) const;
+
+ void ResetOneWayFlag(TArrayRef<TBusMessage*>);
+
+ inline ::NActor::TActor<TRemoteConnection, TWriterTag>* GetWriterActor() {
+ return this;
+ }
+ inline ::NActor::TActor<TRemoteConnection, TReaderTag>* GetReaderActor() {
+ return this;
+ }
+ inline TScheduleActor<TRemoteConnection, TWriterTag>* GetWriterSchedulerActor() {
+ return this;
+ }
+
+ void WriterErrorMessage(TNonDestroyingAutoPtr<TBusMessage> m, EMessageStatus status);
+ // takes ownership of ms
+ void WriterErrorMessages(const TArrayRef<TBusMessage*> ms, EMessageStatus status);
+
+ void FireClientConnectionEvent(TClientConnectionEvent::EType);
+
+ size_t GetInFlight();
+ size_t GetConnectSyscallsNumForTest();
+
+ bool IsReturnConnectFailedImmediately() {
+ return (bool)AtomicGet(ReturnConnectFailedImmediately);
+ }
+
+ bool IsAlive() const;
+
+ TRemoteSessionPtr Session;
+ TBusProtocol* const Proto;
+ TBusSessionConfig const Config;
+ bool RemovedFromSession;
+ const ui64 ConnectionId;
+ const TNetAddr PeerAddr;
+ const TBusSocketAddr PeerAddrSocketAddr;
+
+ const TInstant CreatedTime;
+ TInstant LastConnectAttempt;
+ TAtomic ReturnConnectFailedImmediately;
+
+ protected:
+ ::NActor::TQueueForActor<TBusMessage*> BeforeSendQueue;
+ TLockFreeStack<TBusHeader> WrongVersionRequests;
+
+ struct TWriterData {
+ TAtomic Down;
+
+ NEventLoop::TChannelPtr Channel;
+ ui32 SocketVersion;
+
+ TRemoteConnectionWriterStatus Status;
+ TInstant StatusLastSendTime;
+
+ TLocalTasks TimeToRotateCounters;
+
+ TAtomic InFlight;
+
+ TTimedMessages SendQueue;
+ ui32 AwakeFlags;
+ EWriterState State;
+ TLeftRightBuffer Buffer;
+ TInstant CorkUntil;
+
+ TSystemEvent ShutdownComplete;
+
+ void SetChannel(NEventLoop::TChannelPtr channel);
+ void DropChannel();
+
+ TWriterData();
+ ~TWriterData();
+ };
+
+ struct TReaderData {
+ TAtomic Down;
+
+ NEventLoop::TChannelPtr Channel;
+ ui32 SocketVersion;
+
+ TRemoteConnectionReaderStatus Status;
+ TInstant StatusLastSendTime;
+
+ TBuffer Buffer;
+ size_t Offset; /* offset in read buffer */
+ size_t MoreBytes; /* more bytes required from socket */
+ TVectorSwaps<TBusMessagePtrAndHeader> ReadMessages;
+
+ TSystemEvent ShutdownComplete;
+
+ bool BufferMore() const noexcept {
+ return MoreBytes > 0;
+ }
+
+ bool HasBytesInBuf(size_t bytes) noexcept;
+ void SetChannel(NEventLoop::TChannelPtr channel);
+ void DropChannel();
+
+ TReaderData();
+ ~TReaderData();
+ };
+
+ // owned by session status actor
+ struct TGranStatus {
+ TGranStatus(TDuration gran)
+ : Writer(gran)
+ , Reader(gran)
+ {
+ }
+
+ TGranUp<TRemoteConnectionWriterStatus> Writer;
+ TGranUp<TRemoteConnectionReaderStatus> Reader;
+ };
+
+ TWriterData WriterData;
+ TReaderData ReaderData;
+ TGranStatus GranStatus;
+ TTokenQuota QuotaMsg;
+ TTokenQuota QuotaBytes;
+
+ size_t MaxBufferSize;
+
+ // client connection only
+ TLockFreeQueueBatch<TBusMessagePtrAndHeader, TVectorSwaps> ReplyQueue;
+
+ EMessageStatus ShutdownReason;
+ };
+
+ inline const TNetAddr& TRemoteConnection::GetAddr() const noexcept {
+ return PeerAddr;
+ }
+
+ typedef TIntrusivePtr<TRemoteConnection> TRemoteConnectionPtr;
+
+ }
+}
diff --git a/library/cpp/messagebus/remote_connection_status.cpp b/library/cpp/messagebus/remote_connection_status.cpp
new file mode 100644
index 0000000000..2c48b2a287
--- /dev/null
+++ b/library/cpp/messagebus/remote_connection_status.cpp
@@ -0,0 +1,265 @@
+#include "remote_connection_status.h"
+
+#include "key_value_printer.h"
+
+#include <library/cpp/messagebus/monitoring/mon_proto.pb.h>
+
+#include <util/stream/format.h>
+#include <util/stream/output.h>
+#include <util/system/yassert.h>
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+template <typename T>
+static void Add(T& thiz, const T& that) {
+ thiz += that;
+}
+
+template <typename T>
+static void Max(T& thiz, const T& that) {
+ if (that > thiz) {
+ thiz = that;
+ }
+}
+
+template <typename T>
+static void AssertZero(T& thiz, const T& that) {
+ Y_ASSERT(thiz == T());
+ Y_UNUSED(that);
+}
+
+TDurationCounter::TDurationCounter()
+ : DURATION_COUNTER_MAP(STRUCT_FIELD_INIT_DEFAULT, COMMA)
+{
+}
+
+TDuration TDurationCounter::AvgDuration() const {
+ if (Count == 0) {
+ return TDuration::Zero();
+ } else {
+ return SumDuration / Count;
+ }
+}
+
+TDurationCounter& TDurationCounter::operator+=(const TDurationCounter& that) {
+ DURATION_COUNTER_MAP(STRUCT_FIELD_ADD, )
+ return *this;
+}
+
+TString TDurationCounter::ToString() const {
+ if (Count == 0) {
+ return "0";
+ } else {
+ TStringStream ss;
+ ss << "avg: " << AvgDuration() << ", max: " << MaxDuration << ", count: " << Count;
+ return ss.Str();
+ }
+}
+
+TRemoteConnectionStatusBase::TRemoteConnectionStatusBase()
+ : REMOTE_CONNECTION_STATUS_BASE_MAP(STRUCT_FIELD_INIT_DEFAULT, COMMA)
+{
+}
+
+TRemoteConnectionStatusBase& TRemoteConnectionStatusBase ::operator+=(const TRemoteConnectionStatusBase& that) {
+ REMOTE_CONNECTION_STATUS_BASE_MAP(STRUCT_FIELD_ADD, )
+ return *this;
+}
+
+TRemoteConnectionIncrementalStatusBase::TRemoteConnectionIncrementalStatusBase()
+ : REMOTE_CONNECTION_INCREMENTAL_STATUS_BASE_MAP(STRUCT_FIELD_INIT_DEFAULT, COMMA)
+{
+}
+
+TRemoteConnectionIncrementalStatusBase& TRemoteConnectionIncrementalStatusBase::operator+=(
+ const TRemoteConnectionIncrementalStatusBase& that) {
+ REMOTE_CONNECTION_INCREMENTAL_STATUS_BASE_MAP(STRUCT_FIELD_ADD, )
+ return *this;
+}
+
+TRemoteConnectionReaderIncrementalStatus::TRemoteConnectionReaderIncrementalStatus()
+ : REMOTE_CONNECTION_READER_INCREMENTAL_STATUS_MAP(STRUCT_FIELD_INIT_DEFAULT, COMMA)
+{
+}
+
+TRemoteConnectionReaderIncrementalStatus& TRemoteConnectionReaderIncrementalStatus::operator+=(
+ const TRemoteConnectionReaderIncrementalStatus& that) {
+ TRemoteConnectionIncrementalStatusBase::operator+=(that);
+ REMOTE_CONNECTION_READER_INCREMENTAL_STATUS_MAP(STRUCT_FIELD_ADD, )
+ return *this;
+}
+
+TRemoteConnectionReaderStatus::TRemoteConnectionReaderStatus()
+ : REMOTE_CONNECTION_READER_STATUS_MAP(STRUCT_FIELD_INIT_DEFAULT, COMMA)
+{
+}
+
+TRemoteConnectionReaderStatus& TRemoteConnectionReaderStatus::operator+=(const TRemoteConnectionReaderStatus& that) {
+ TRemoteConnectionStatusBase::operator+=(that);
+ REMOTE_CONNECTION_READER_STATUS_MAP(STRUCT_FIELD_ADD, )
+ return *this;
+}
+
+TRemoteConnectionWriterIncrementalStatus::TRemoteConnectionWriterIncrementalStatus()
+ : REMOTE_CONNECTION_WRITER_INCREMENTAL_STATUS(STRUCT_FIELD_INIT_DEFAULT, COMMA)
+{
+}
+
+TRemoteConnectionWriterIncrementalStatus& TRemoteConnectionWriterIncrementalStatus::operator+=(
+ const TRemoteConnectionWriterIncrementalStatus& that) {
+ TRemoteConnectionIncrementalStatusBase::operator+=(that);
+ REMOTE_CONNECTION_WRITER_INCREMENTAL_STATUS(STRUCT_FIELD_ADD, )
+ return *this;
+}
+
+TRemoteConnectionWriterStatus::TRemoteConnectionWriterStatus()
+ : REMOTE_CONNECTION_WRITER_STATUS(STRUCT_FIELD_INIT_DEFAULT, COMMA)
+{
+}
+
+TRemoteConnectionWriterStatus& TRemoteConnectionWriterStatus::operator+=(const TRemoteConnectionWriterStatus& that) {
+ TRemoteConnectionStatusBase::operator+=(that);
+ REMOTE_CONNECTION_WRITER_STATUS(STRUCT_FIELD_ADD, )
+ return *this;
+}
+
+size_t TRemoteConnectionWriterStatus::GetInFlight() const {
+ return SendQueueSize + AckMessagesSize;
+}
+
+TConnectionStatusMonRecord TRemoteConnectionStatus::GetStatusProtobuf() const {
+ TConnectionStatusMonRecord status;
+
+ // TODO: fill unfilled fields
+ status.SetSendQueueSize(WriterStatus.SendQueueSize);
+ status.SetAckMessagesSize(WriterStatus.AckMessagesSize);
+ // status.SetErrorCount();
+ // status.SetWriteBytes();
+ // status.SetWriteBytesCompressed();
+ // status.SetWriteMessages();
+ status.SetWriteSyscalls(WriterStatus.Incremental.NetworkOps);
+ status.SetWriteActs(WriterStatus.Acts);
+ // status.SetReadBytes();
+ // status.SetReadBytesCompressed();
+ // status.SetReadMessages();
+ status.SetReadSyscalls(ReaderStatus.Incremental.NetworkOps);
+ status.SetReadActs(ReaderStatus.Acts);
+
+ TMessageStatusCounter sumStatusCounter;
+ sumStatusCounter += WriterStatus.Incremental.StatusCounter;
+ sumStatusCounter += ReaderStatus.Incremental.StatusCounter;
+ sumStatusCounter.FillErrorsProtobuf(&status);
+
+ return status;
+}
+
+TString TRemoteConnectionStatus::PrintToString() const {
+ TStringStream ss;
+
+ TKeyValuePrinter p;
+
+ if (!Summary) {
+ // TODO: print MyAddr too, but only if it is set
+ ss << WriterStatus.PeerAddr << " (" << WriterStatus.ConnectionId << ")"
+ << ", writefd=" << WriterStatus.Fd
+ << ", readfd=" << ReaderStatus.Fd
+ << Endl;
+ if (WriterStatus.Connected) {
+ p.AddRow("connect time", WriterStatus.ConnectTime.ToString());
+ p.AddRow("writer state", ToCString(WriterStatus.State));
+ } else {
+ ss << "not connected";
+ if (WriterStatus.ConnectError != 0) {
+ ss << ", last connect error: " << LastSystemErrorText(WriterStatus.ConnectError);
+ }
+ ss << Endl;
+ }
+ }
+ if (!Server) {
+ p.AddRow("connect syscalls", WriterStatus.ConnectSyscalls);
+ }
+
+ p.AddRow("send queue", LeftPad(WriterStatus.SendQueueSize, 6));
+
+ if (Server) {
+ p.AddRow("quota msg", LeftPad(ReaderStatus.QuotaMsg, 6));
+ p.AddRow("quota bytes", LeftPad(ReaderStatus.QuotaBytes, 6));
+ p.AddRow("quota exhausted", LeftPad(ReaderStatus.QuotaExhausted, 6));
+ p.AddRow("reader wakeups", LeftPad(WriterStatus.ReaderWakeups, 6));
+ } else {
+ p.AddRow("ack messages", LeftPad(WriterStatus.AckMessagesSize, 6));
+ }
+
+ p.AddRow("written", WriterStatus.Incremental.MessageCounter.ToString(false));
+ p.AddRow("read", ReaderStatus.Incremental.MessageCounter.ToString(true));
+
+ p.AddRow("write syscalls", LeftPad(WriterStatus.Incremental.NetworkOps, 12));
+ p.AddRow("read syscalls", LeftPad(ReaderStatus.Incremental.NetworkOps, 12));
+
+ p.AddRow("write acts", LeftPad(WriterStatus.Acts, 12));
+ p.AddRow("read acts", LeftPad(ReaderStatus.Acts, 12));
+
+ p.AddRow("write buffer cap", LeftPad(WriterStatus.BufferSize, 12));
+ p.AddRow("read buffer cap", LeftPad(ReaderStatus.BufferSize, 12));
+
+ p.AddRow("write buffer drops", LeftPad(WriterStatus.Incremental.BufferDrops, 10));
+ p.AddRow("read buffer drops", LeftPad(ReaderStatus.Incremental.BufferDrops, 10));
+
+ if (Server) {
+ p.AddRow("process dur", WriterStatus.DurationCounterPrev.ToString());
+ }
+
+ ss << p.PrintToString();
+
+ if (false && Server) {
+ ss << "time histogram:\n";
+ ss << WriterStatus.Incremental.ProcessDurationHistogram.PrintToString();
+ }
+
+ TMessageStatusCounter sumStatusCounter;
+ sumStatusCounter += WriterStatus.Incremental.StatusCounter;
+ sumStatusCounter += ReaderStatus.Incremental.StatusCounter;
+
+ ss << sumStatusCounter.PrintToString();
+
+ return ss.Str();
+}
+
+TRemoteConnectionStatus::TRemoteConnectionStatus()
+ : REMOTE_CONNECTION_STATUS_MAP(STRUCT_FIELD_INIT_DEFAULT, COMMA)
+{
+}
+
+TString TSessionDumpStatus::PrintToString() const {
+ if (Shutdown) {
+ return "shutdown";
+ }
+
+ TStringStream ss;
+ ss << Head;
+ if (ConnectionStatusSummary.Server) {
+ ss << "\n";
+ ss << Acceptors;
+ }
+ ss << "\n";
+ ss << "connections summary:" << Endl;
+ ss << ConnectionsSummary;
+ if (!!Connections) {
+ ss << "\n";
+ ss << Connections;
+ }
+ ss << "\n";
+ ss << Config.PrintToString();
+ return ss.Str();
+}
+
+TString TBusMessageQueueStatus::PrintToString() const {
+ TStringStream ss;
+ ss << "work queue:\n";
+ ss << ExecutorStatus.Status;
+ ss << "\n";
+ ss << "queue config:\n";
+ ss << Config.PrintToString();
+ return ss.Str();
+}
diff --git a/library/cpp/messagebus/remote_connection_status.h b/library/cpp/messagebus/remote_connection_status.h
new file mode 100644
index 0000000000..5db10e51ea
--- /dev/null
+++ b/library/cpp/messagebus/remote_connection_status.h
@@ -0,0 +1,214 @@
+#pragma once
+
+#include "codegen.h"
+#include "duration_histogram.h"
+#include "message_counter.h"
+#include "message_status_counter.h"
+#include "queue_config.h"
+#include "session_config.h"
+
+#include <library/cpp/messagebus/actor/executor.h>
+
+#include <library/cpp/deprecated/enum_codegen/enum_codegen.h>
+
+namespace NBus {
+ class TConnectionStatusMonRecord;
+}
+
+namespace NBus {
+ namespace NPrivate {
+#define WRITER_STATE_MAP(XX) \
+ XX(WRITER_UNKNOWN) \
+ XX(WRITER_FILLING) \
+ XX(WRITER_FLUSHING) \
+ /**/
+
+ // TODO: move elsewhere
+ enum EWriterState {
+ WRITER_STATE_MAP(ENUM_VALUE_GEN_NO_VALUE)
+ };
+
+ ENUM_TO_STRING(EWriterState, WRITER_STATE_MAP)
+
+#define STRUCT_FIELD_ADD(name, type, func) func(name, that.name);
+
+ template <typename T>
+ void Reset(T& t) {
+ t.~T();
+ new (&t) T();
+ }
+
+#define DURATION_COUNTER_MAP(XX, comma) \
+ XX(Count, unsigned, Add) \
+ comma \
+ XX(SumDuration, TDuration, Add) comma \
+ XX(MaxDuration, TDuration, Max) /**/
+
+ struct TDurationCounter {
+ DURATION_COUNTER_MAP(STRUCT_FIELD_GEN, )
+
+ TDuration AvgDuration() const;
+
+ TDurationCounter();
+
+ void AddDuration(TDuration d) {
+ Count += 1;
+ SumDuration += d;
+ if (d > MaxDuration) {
+ MaxDuration = d;
+ }
+ }
+
+ TDurationCounter& operator+=(const TDurationCounter&);
+
+ TString ToString() const;
+ };
+
+#define REMOTE_CONNECTION_STATUS_BASE_MAP(XX, comma) \
+ XX(ConnectionId, ui64, AssertZero) \
+ comma \
+ XX(Fd, SOCKET, AssertZero) comma \
+ XX(Acts, ui64, Add) comma \
+ XX(BufferSize, ui64, Add) /**/
+
+ struct TRemoteConnectionStatusBase {
+ REMOTE_CONNECTION_STATUS_BASE_MAP(STRUCT_FIELD_GEN, )
+
+ TRemoteConnectionStatusBase& operator+=(const TRemoteConnectionStatusBase&);
+
+ TRemoteConnectionStatusBase();
+ };
+
+#define REMOTE_CONNECTION_INCREMENTAL_STATUS_BASE_MAP(XX, comma) \
+ XX(BufferDrops, unsigned, Add) \
+ comma \
+ XX(NetworkOps, unsigned, Add) /**/
+
+ struct TRemoteConnectionIncrementalStatusBase {
+ REMOTE_CONNECTION_INCREMENTAL_STATUS_BASE_MAP(STRUCT_FIELD_GEN, )
+
+ TRemoteConnectionIncrementalStatusBase& operator+=(const TRemoteConnectionIncrementalStatusBase&);
+
+ TRemoteConnectionIncrementalStatusBase();
+ };
+
+#define REMOTE_CONNECTION_READER_INCREMENTAL_STATUS_MAP(XX, comma) \
+ XX(MessageCounter, TMessageCounter, Add) \
+ comma \
+ XX(StatusCounter, TMessageStatusCounter, Add) /**/
+
+ struct TRemoteConnectionReaderIncrementalStatus: public TRemoteConnectionIncrementalStatusBase {
+ REMOTE_CONNECTION_READER_INCREMENTAL_STATUS_MAP(STRUCT_FIELD_GEN, )
+
+ TRemoteConnectionReaderIncrementalStatus& operator+=(const TRemoteConnectionReaderIncrementalStatus&);
+
+ TRemoteConnectionReaderIncrementalStatus();
+ };
+
+#define REMOTE_CONNECTION_READER_STATUS_MAP(XX, comma) \
+ XX(QuotaMsg, size_t, Add) \
+ comma \
+ XX(QuotaBytes, size_t, Add) comma \
+ XX(QuotaExhausted, size_t, Add) comma \
+ XX(Incremental, TRemoteConnectionReaderIncrementalStatus, Add) /**/
+
+ struct TRemoteConnectionReaderStatus: public TRemoteConnectionStatusBase {
+ REMOTE_CONNECTION_READER_STATUS_MAP(STRUCT_FIELD_GEN, )
+
+ TRemoteConnectionReaderStatus& operator+=(const TRemoteConnectionReaderStatus&);
+
+ TRemoteConnectionReaderStatus();
+ };
+
+#define REMOTE_CONNECTION_WRITER_INCREMENTAL_STATUS(XX, comma) \
+ XX(MessageCounter, TMessageCounter, Add) \
+ comma \
+ XX(StatusCounter, TMessageStatusCounter, Add) comma \
+ XX(ProcessDurationHistogram, TDurationHistogram, Add) /**/
+
+ struct TRemoteConnectionWriterIncrementalStatus: public TRemoteConnectionIncrementalStatusBase {
+ REMOTE_CONNECTION_WRITER_INCREMENTAL_STATUS(STRUCT_FIELD_GEN, )
+
+ TRemoteConnectionWriterIncrementalStatus& operator+=(const TRemoteConnectionWriterIncrementalStatus&);
+
+ TRemoteConnectionWriterIncrementalStatus();
+ };
+
+#define REMOTE_CONNECTION_WRITER_STATUS(XX, comma) \
+ XX(Connected, bool, AssertZero) \
+ comma \
+ XX(ConnectTime, TInstant, AssertZero) comma /* either connect time on client or accept time on server */ \
+ XX(ConnectError, int, AssertZero) comma \
+ XX(ConnectSyscalls, unsigned, Add) comma \
+ XX(PeerAddr, TNetAddr, AssertZero) comma \
+ XX(MyAddr, TNetAddr, AssertZero) comma \
+ XX(State, EWriterState, AssertZero) comma \
+ XX(SendQueueSize, size_t, Add) comma \
+ XX(AckMessagesSize, size_t, Add) comma /* client only */ \
+ XX(DurationCounter, TDurationCounter, Add) comma /* server only */ \
+ XX(DurationCounterPrev, TDurationCounter, Add) comma /* server only */ \
+ XX(Incremental, TRemoteConnectionWriterIncrementalStatus, Add) comma \
+ XX(ReaderWakeups, size_t, Add) /**/
+
+ struct TRemoteConnectionWriterStatus: public TRemoteConnectionStatusBase {
+ REMOTE_CONNECTION_WRITER_STATUS(STRUCT_FIELD_GEN, )
+
+ TRemoteConnectionWriterStatus();
+
+ TRemoteConnectionWriterStatus& operator+=(const TRemoteConnectionWriterStatus&);
+
+ size_t GetInFlight() const;
+ };
+
+#define REMOTE_CONNECTION_STATUS_MAP(XX, comma) \
+ XX(Summary, bool) \
+ comma \
+ XX(Server, bool) /**/
+
+ struct TRemoteConnectionStatus {
+ REMOTE_CONNECTION_STATUS_MAP(STRUCT_FIELD_GEN, )
+
+ TRemoteConnectionReaderStatus ReaderStatus;
+ TRemoteConnectionWriterStatus WriterStatus;
+
+ TRemoteConnectionStatus();
+
+ TString PrintToString() const;
+ TConnectionStatusMonRecord GetStatusProtobuf() const;
+ };
+
+ struct TBusSessionStatus {
+ size_t InFlightCount;
+ size_t InFlightSize;
+ bool InputPaused;
+
+ TBusSessionStatus();
+ };
+
+ struct TSessionDumpStatus {
+ bool Shutdown;
+ TString Head;
+ TString Acceptors;
+ TString ConnectionsSummary;
+ TString Connections;
+ TBusSessionStatus Status;
+ TRemoteConnectionStatus ConnectionStatusSummary;
+ TBusSessionConfig Config;
+
+ TSessionDumpStatus()
+ : Shutdown(false)
+ {
+ }
+
+ TString PrintToString() const;
+ };
+
+ // without sessions
+ struct TBusMessageQueueStatus {
+ NActor::NPrivate::TExecutorStatus ExecutorStatus;
+ TBusQueueConfig Config;
+
+ TString PrintToString() const;
+ };
+ }
+}
diff --git a/library/cpp/messagebus/remote_server_connection.cpp b/library/cpp/messagebus/remote_server_connection.cpp
new file mode 100644
index 0000000000..74be34ded9
--- /dev/null
+++ b/library/cpp/messagebus/remote_server_connection.cpp
@@ -0,0 +1,73 @@
+#include "remote_server_connection.h"
+
+#include "mb_lwtrace.h"
+#include "remote_server_session.h"
+
+#include <util/generic/cast.h>
+
+LWTRACE_USING(LWTRACE_MESSAGEBUS_PROVIDER)
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+TRemoteServerConnection::TRemoteServerConnection(TRemoteServerSessionPtr session, ui64 id, TNetAddr addr)
+ : TRemoteConnection(session.Get(), id, addr)
+{
+}
+
+void TRemoteServerConnection::Init(SOCKET socket, TInstant now) {
+ WriterData.Status.ConnectTime = now;
+ WriterData.Status.Connected = true;
+
+ Y_VERIFY(socket != INVALID_SOCKET, "must be a valid socket");
+
+ TSocket readSocket(socket);
+ TSocket writeSocket = readSocket;
+
+ // this must not be done in constructor, because if event loop is stopped,
+ // this is deleted
+ WriterData.SetChannel(Session->WriteEventLoop.Register(writeSocket, this, WriteCookie));
+ WriterData.SocketVersion = 1;
+
+ ReaderGetSocketQueue()->EnqueueAndSchedule(TWriterToReaderSocketMessage(readSocket, WriterData.SocketVersion));
+}
+
+TRemoteServerSession* TRemoteServerConnection::GetSession() {
+ return CheckedCast<TRemoteServerSession*>(Session.Get());
+}
+
+void TRemoteServerConnection::HandleEvent(SOCKET socket, void* cookie) {
+ Y_UNUSED(socket);
+ Y_ASSERT(cookie == ReadCookie || cookie == WriteCookie);
+ if (cookie == ReadCookie) {
+ GetSession()->ServerOwnedMessages.Wait();
+ ScheduleRead();
+ } else {
+ ScheduleWrite();
+ }
+}
+
+bool TRemoteServerConnection::NeedInterruptRead() {
+ return !GetSession()->ServerOwnedMessages.TryWait();
+}
+
+void TRemoteServerConnection::MessageSent(TArrayRef<TBusMessagePtrAndHeader> messages) {
+ TInstant now = TInstant::Now();
+
+ GetSession()->ReleaseInWorkResponses(messages);
+ for (auto& message : messages) {
+ TInstant recvTime = message.MessagePtr->RecvTime;
+ GetSession()->ServerHandler->OnSent(message.MessagePtr.Release());
+ TDuration d = now - recvTime;
+ WriterData.Status.DurationCounter.AddDuration(d);
+ WriterData.Status.Incremental.ProcessDurationHistogram.AddTime(d);
+ }
+}
+
+void TRemoteServerConnection::ReaderProcessMessageUnknownVersion(TArrayRef<const char> dataRef) {
+ TBusHeader header(dataRef);
+ // TODO: full version hex
+ LWPROBE(ServerUnknownVersion, ToString(PeerAddr), header.GetVersionInternal());
+ WrongVersionRequests.Enqueue(header);
+ GetWriterActor()->Schedule();
+}
diff --git a/library/cpp/messagebus/remote_server_connection.h b/library/cpp/messagebus/remote_server_connection.h
new file mode 100644
index 0000000000..63d7f20646
--- /dev/null
+++ b/library/cpp/messagebus/remote_server_connection.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "session_impl.h"
+
+#include <util/generic/object_counter.h>
+
+namespace NBus {
+ namespace NPrivate {
+ class TRemoteServerConnection: public TRemoteConnection {
+ friend struct TBusSessionImpl;
+ friend class TRemoteServerSession;
+
+ TObjectCounter<TRemoteServerConnection> ObjectCounter;
+
+ public:
+ TRemoteServerConnection(TRemoteServerSessionPtr session, ui64 id, TNetAddr addr);
+
+ void Init(SOCKET socket, TInstant now);
+
+ inline TRemoteServerSession* GetSession();
+
+ void HandleEvent(SOCKET socket, void* cookie) override;
+
+ bool NeedInterruptRead() override;
+
+ void MessageSent(TArrayRef<TBusMessagePtrAndHeader> messages) override;
+
+ void ReaderProcessMessageUnknownVersion(TArrayRef<const char> dataRef) override;
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/remote_server_session.cpp b/library/cpp/messagebus/remote_server_session.cpp
new file mode 100644
index 0000000000..6abbf88a60
--- /dev/null
+++ b/library/cpp/messagebus/remote_server_session.cpp
@@ -0,0 +1,206 @@
+#include "remote_server_session.h"
+
+#include "remote_connection.h"
+#include "remote_server_connection.h"
+
+#include <library/cpp/messagebus/actor/temp_tls_vector.h>
+
+#include <util/generic/cast.h>
+#include <util/stream/output.h>
+#include <util/system/yassert.h>
+
+#include <typeinfo>
+
+using namespace NActor;
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+TRemoteServerSession::TRemoteServerSession(TBusMessageQueue* queue,
+ TBusProtocol* proto, IBusServerHandler* handler,
+ const TBusServerSessionConfig& config, const TString& name)
+ : TBusSessionImpl(false, queue, proto, handler, config, name)
+ , ServerOwnedMessages(config.MaxInFlight, config.MaxInFlightBySize, "ServerOwnedMessages")
+ , ServerHandler(handler)
+{
+ if (config.PerConnectionMaxInFlightBySize > 0) {
+ if (config.PerConnectionMaxInFlightBySize < config.MaxMessageSize)
+ ythrow yexception()
+ << "too low PerConnectionMaxInFlightBySize value";
+ }
+}
+
+namespace NBus {
+ namespace NPrivate {
+ class TInvokeOnMessage: public IWorkItem {
+ private:
+ TRemoteServerSession* RemoteServerSession;
+ TBusMessagePtrAndHeader Request;
+ TIntrusivePtr<TRemoteServerConnection> Connection;
+
+ public:
+ TInvokeOnMessage(TRemoteServerSession* session, TBusMessagePtrAndHeader& request, TIntrusivePtr<TRemoteServerConnection>& connection)
+ : RemoteServerSession(session)
+ {
+ Y_ASSERT(!!connection);
+ Connection.Swap(connection);
+
+ Request.Swap(request);
+ }
+
+ void DoWork() override {
+ THolder<TInvokeOnMessage> holder(this);
+ RemoteServerSession->InvokeOnMessage(Request, Connection);
+ // TODO: TRemoteServerSessionSemaphore should be enough
+ RemoteServerSession->JobCount.Decrement();
+ }
+ };
+
+ }
+}
+
+void TRemoteServerSession::OnMessageReceived(TRemoteConnection* c, TVectorSwaps<TBusMessagePtrAndHeader>& messages) {
+ AcquireInWorkRequests(messages);
+
+ bool executeInPool = Config.ExecuteOnMessageInWorkerPool;
+
+ TTempTlsVector< ::IWorkItem*> workQueueTemp;
+
+ if (executeInPool) {
+ workQueueTemp.GetVector()->reserve(messages.size());
+ }
+
+ for (auto& message : messages) {
+ // TODO: incref once
+ TIntrusivePtr<TRemoteServerConnection> connection(CheckedCast<TRemoteServerConnection*>(c));
+ if (executeInPool) {
+ workQueueTemp.GetVector()->push_back(new TInvokeOnMessage(this, message, connection));
+ } else {
+ InvokeOnMessage(message, connection);
+ }
+ }
+
+ if (executeInPool) {
+ JobCount.Add(workQueueTemp.GetVector()->size());
+ Queue->EnqueueWork(*workQueueTemp.GetVector());
+ }
+}
+
+void TRemoteServerSession::InvokeOnMessage(TBusMessagePtrAndHeader& request, TIntrusivePtr<TRemoteServerConnection>& conn) {
+ if (Y_UNLIKELY(AtomicGet(Down))) {
+ ReleaseInWorkRequests(*conn.Get(), request.MessagePtr.Get());
+ InvokeOnError(request.MessagePtr.Release(), MESSAGE_SHUTDOWN);
+ } else {
+ TWhatThreadDoesPushPop pp("OnMessage");
+
+ TBusIdentity ident;
+
+ ident.Connection.Swap(conn);
+ request.MessagePtr->GetIdentity(ident);
+
+ Y_ASSERT(request.MessagePtr->LocalFlags & MESSAGE_IN_WORK);
+ DoSwap(request.MessagePtr->LocalFlags, ident.LocalFlags);
+
+ ident.RecvTime = request.MessagePtr->RecvTime;
+
+#ifndef NDEBUG
+ auto& message = *request.MessagePtr;
+ ident.SetMessageType(typeid(message));
+#endif
+
+ TOnMessageContext context(request.MessagePtr.Release(), ident, this);
+ ServerHandler->OnMessage(context);
+ }
+}
+
+EMessageStatus TRemoteServerSession::ForgetRequest(const TBusIdentity& ident) {
+ ReleaseInWork(const_cast<TBusIdentity&>(ident));
+
+ return MESSAGE_OK;
+}
+
+EMessageStatus TRemoteServerSession::SendReply(const TBusIdentity& ident, TBusMessage* reply) {
+ reply->CheckClean();
+
+ ConvertInWork(const_cast<TBusIdentity&>(ident), reply);
+
+ reply->RecvTime = ident.RecvTime;
+
+ ident.Connection->Send(reply);
+
+ return MESSAGE_OK;
+}
+
+int TRemoteServerSession::GetInFlight() const noexcept {
+ return ServerOwnedMessages.GetCurrentCount();
+}
+
+void TRemoteServerSession::FillStatus() {
+ TBusSessionImpl::FillStatus();
+
+ // TODO: weird
+ StatusData.Status.InFlightCount = ServerOwnedMessages.GetCurrentCount();
+ StatusData.Status.InFlightSize = ServerOwnedMessages.GetCurrentSize();
+ StatusData.Status.InputPaused = ServerOwnedMessages.IsLocked();
+}
+
+void TRemoteServerSession::AcquireInWorkRequests(TArrayRef<const TBusMessagePtrAndHeader> messages) {
+ TAtomicBase size = 0;
+ for (auto message = messages.begin(); message != messages.end(); ++message) {
+ Y_ASSERT(!(message->MessagePtr->LocalFlags & MESSAGE_IN_WORK));
+ message->MessagePtr->LocalFlags |= MESSAGE_IN_WORK;
+ size += message->MessagePtr->GetHeader()->Size;
+ }
+
+ ServerOwnedMessages.IncrementMultiple(messages.size(), size);
+}
+
+void TRemoteServerSession::ReleaseInWorkResponses(TArrayRef<const TBusMessagePtrAndHeader> responses) {
+ TAtomicBase size = 0;
+ for (auto response = responses.begin(); response != responses.end(); ++response) {
+ Y_ASSERT((response->MessagePtr->LocalFlags & MESSAGE_REPLY_IS_BEGING_SENT));
+ response->MessagePtr->LocalFlags &= ~MESSAGE_REPLY_IS_BEGING_SENT;
+ size += response->MessagePtr->RequestSize;
+ }
+
+ ServerOwnedMessages.ReleaseMultiple(responses.size(), size);
+}
+
+void TRemoteServerSession::ReleaseInWorkRequests(TRemoteConnection& con, TBusMessage* request) {
+ Y_ASSERT((request->LocalFlags & MESSAGE_IN_WORK));
+ request->LocalFlags &= ~MESSAGE_IN_WORK;
+
+ const size_t size = request->GetHeader()->Size;
+
+ con.QuotaReturnAside(1, size);
+ ServerOwnedMessages.ReleaseMultiple(1, size);
+}
+
+void TRemoteServerSession::ReleaseInWork(TBusIdentity& ident) {
+ ident.SetInWork(false);
+ ident.Connection->QuotaReturnAside(1, ident.Size);
+
+ ServerOwnedMessages.ReleaseMultiple(1, ident.Size);
+}
+
+void TRemoteServerSession::ConvertInWork(TBusIdentity& req, TBusMessage* reply) {
+ reply->SetIdentity(req);
+
+ req.SetInWork(false);
+ Y_ASSERT(!(reply->LocalFlags & MESSAGE_REPLY_IS_BEGING_SENT));
+ reply->LocalFlags |= MESSAGE_REPLY_IS_BEGING_SENT;
+ reply->RequestSize = req.Size;
+}
+
+void TRemoteServerSession::Shutdown() {
+ ServerOwnedMessages.Stop();
+ TBusSessionImpl::Shutdown();
+}
+
+void TRemoteServerSession::PauseInput(bool pause) {
+ ServerOwnedMessages.PauseByUsed(pause);
+}
+
+unsigned TRemoteServerSession::GetActualListenPort() {
+ Y_VERIFY(Config.ListenPort > 0, "state check");
+ return Config.ListenPort;
+}
diff --git a/library/cpp/messagebus/remote_server_session.h b/library/cpp/messagebus/remote_server_session.h
new file mode 100644
index 0000000000..f5c266a7f7
--- /dev/null
+++ b/library/cpp/messagebus/remote_server_session.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include "remote_server_session_semaphore.h"
+#include "session_impl.h"
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4250) // 'NBus::NPrivate::TRemoteClientSession' : inherits 'NBus::NPrivate::TBusSessionImpl::NBus::NPrivate::TBusSessionImpl::GetConfig' via dominance
+#endif
+
+namespace NBus {
+ namespace NPrivate {
+ class TRemoteServerSession: public TBusServerSession, public TBusSessionImpl {
+ friend class TRemoteServerConnection;
+
+ private:
+ TObjectCounter<TRemoteServerSession> ObjectCounter;
+
+ TRemoteServerSessionSemaphore ServerOwnedMessages;
+ IBusServerHandler* const ServerHandler;
+
+ public:
+ TRemoteServerSession(TBusMessageQueue* queue, TBusProtocol* proto,
+ IBusServerHandler* handler,
+ const TBusSessionConfig& config, const TString& name);
+
+ void OnMessageReceived(TRemoteConnection* c, TVectorSwaps<TBusMessagePtrAndHeader>& newMsg) override;
+ void InvokeOnMessage(TBusMessagePtrAndHeader& request, TIntrusivePtr<TRemoteServerConnection>& conn);
+
+ EMessageStatus SendReply(const TBusIdentity& ident, TBusMessage* pRep) override;
+
+ EMessageStatus ForgetRequest(const TBusIdentity& ident) override;
+
+ int GetInFlight() const noexcept override;
+ void FillStatus() override;
+
+ void Shutdown() override;
+
+ void PauseInput(bool pause) override;
+ unsigned GetActualListenPort() override;
+
+ void AcquireInWorkRequests(TArrayRef<const TBusMessagePtrAndHeader> requests);
+ void ReleaseInWorkResponses(TArrayRef<const TBusMessagePtrAndHeader> responses);
+ void ReleaseInWorkRequests(TRemoteConnection&, TBusMessage*);
+ void ReleaseInWork(TBusIdentity&);
+ void ConvertInWork(TBusIdentity& req, TBusMessage* reply);
+ };
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+ }
+}
diff --git a/library/cpp/messagebus/remote_server_session_semaphore.cpp b/library/cpp/messagebus/remote_server_session_semaphore.cpp
new file mode 100644
index 0000000000..6094a3586e
--- /dev/null
+++ b/library/cpp/messagebus/remote_server_session_semaphore.cpp
@@ -0,0 +1,59 @@
+#include "remote_server_session_semaphore.h"
+
+#include <util/stream/output.h>
+#include <util/system/yassert.h>
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+TRemoteServerSessionSemaphore::TRemoteServerSessionSemaphore(
+ TAtomicBase limitCount, TAtomicBase limitSize, const char* name)
+ : Name(name)
+ , LimitCount(limitCount)
+ , LimitSize(limitSize)
+ , CurrentCount(0)
+ , CurrentSize(0)
+ , PausedByUser(0)
+ , StopSignal(0)
+{
+ Y_VERIFY(limitCount > 0, "limit must be > 0");
+ Y_UNUSED(Name);
+}
+
+TRemoteServerSessionSemaphore::~TRemoteServerSessionSemaphore() {
+ Y_VERIFY(AtomicGet(CurrentCount) == 0);
+ // TODO: fix spider and enable
+ //Y_VERIFY(AtomicGet(CurrentSize) == 0);
+}
+
+bool TRemoteServerSessionSemaphore::TryWait() {
+ if (Y_UNLIKELY(AtomicGet(StopSignal)))
+ return true;
+ if (AtomicGet(PausedByUser))
+ return false;
+ if (AtomicGet(CurrentCount) < LimitCount && (LimitSize < 0 || AtomicGet(CurrentSize) < LimitSize))
+ return true;
+ return false;
+}
+
+void TRemoteServerSessionSemaphore::IncrementMultiple(TAtomicBase count, TAtomicBase size) {
+ AtomicAdd(CurrentCount, count);
+ AtomicAdd(CurrentSize, size);
+ Updated();
+}
+
+void TRemoteServerSessionSemaphore::ReleaseMultiple(TAtomicBase count, TAtomicBase size) {
+ AtomicSub(CurrentCount, count);
+ AtomicSub(CurrentSize, size);
+ Updated();
+}
+
+void TRemoteServerSessionSemaphore::Stop() {
+ AtomicSet(StopSignal, 1);
+ Updated();
+}
+
+void TRemoteServerSessionSemaphore::PauseByUsed(bool pause) {
+ AtomicSet(PausedByUser, pause);
+ Updated();
+}
diff --git a/library/cpp/messagebus/remote_server_session_semaphore.h b/library/cpp/messagebus/remote_server_session_semaphore.h
new file mode 100644
index 0000000000..de714fd342
--- /dev/null
+++ b/library/cpp/messagebus/remote_server_session_semaphore.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "cc_semaphore.h"
+
+#include <util/generic/noncopyable.h>
+
+namespace NBus {
+ namespace NPrivate {
+ class TRemoteServerSessionSemaphore: public TComplexConditionSemaphore<TRemoteServerSessionSemaphore> {
+ private:
+ const char* const Name;
+
+ TAtomicBase const LimitCount;
+ TAtomicBase const LimitSize;
+ TAtomic CurrentCount;
+ TAtomic CurrentSize;
+ TAtomic PausedByUser;
+ TAtomic StopSignal;
+
+ public:
+ TRemoteServerSessionSemaphore(TAtomicBase limitCount, TAtomicBase limitSize, const char* name = "unnamed");
+ ~TRemoteServerSessionSemaphore();
+
+ TAtomicBase GetCurrentCount() const {
+ return AtomicGet(CurrentCount);
+ }
+ TAtomicBase GetCurrentSize() const {
+ return AtomicGet(CurrentSize);
+ }
+
+ void IncrementMultiple(TAtomicBase count, TAtomicBase size);
+ bool TryWait();
+ void ReleaseMultiple(TAtomicBase count, TAtomicBase size);
+ void Stop();
+ void PauseByUsed(bool pause);
+
+ private:
+ void CheckNeedToUnlock();
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/scheduler/scheduler.cpp b/library/cpp/messagebus/scheduler/scheduler.cpp
new file mode 100644
index 0000000000..5a5fe52894
--- /dev/null
+++ b/library/cpp/messagebus/scheduler/scheduler.cpp
@@ -0,0 +1,119 @@
+#include "scheduler.h"
+
+#include <util/datetime/base.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/yexception.h>
+
+//#include "dummy_debugger.h"
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+class TScheduleDeadlineCompare {
+public:
+ bool operator()(const IScheduleItemAutoPtr& i1, const IScheduleItemAutoPtr& i2) const noexcept {
+ return i1->GetScheduleTime() > i2->GetScheduleTime();
+ }
+};
+
+TScheduler::TScheduler()
+ : StopThread(false)
+ , Thread([&] { this->SchedulerThread(); })
+{
+}
+
+TScheduler::~TScheduler() {
+ Y_VERIFY(StopThread, "state check");
+}
+
+size_t TScheduler::Size() const {
+ TGuard<TLock> guard(Lock);
+ return Items.size() + (!!NextItem ? 1 : 0);
+}
+
+void TScheduler::Stop() {
+ {
+ TGuard<TLock> guard(Lock);
+ Y_VERIFY(!StopThread, "Scheduler already stopped");
+ StopThread = true;
+ CondVar.Signal();
+ }
+ Thread.Get();
+
+ if (!!NextItem) {
+ NextItem.Destroy();
+ }
+
+ for (auto& item : Items) {
+ item.Destroy();
+ }
+}
+
+void TScheduler::Schedule(TAutoPtr<IScheduleItem> i) {
+ TGuard<TLock> lock(Lock);
+ if (StopThread)
+ return;
+
+ if (!!NextItem) {
+ if (i->GetScheduleTime() < NextItem->GetScheduleTime()) {
+ DoSwap(i, NextItem);
+ }
+ }
+
+ Items.push_back(i);
+ PushHeap(Items.begin(), Items.end(), TScheduleDeadlineCompare());
+
+ FillNextItem();
+
+ CondVar.Signal();
+}
+
+void TScheduler::FillNextItem() {
+ if (!NextItem && !Items.empty()) {
+ PopHeap(Items.begin(), Items.end(), TScheduleDeadlineCompare());
+ NextItem = Items.back();
+ Items.erase(Items.end() - 1);
+ }
+}
+
+void TScheduler::SchedulerThread() {
+ for (;;) {
+ IScheduleItemAutoPtr current;
+
+ {
+ TGuard<TLock> guard(Lock);
+
+ if (StopThread) {
+ break;
+ }
+
+ if (!!NextItem) {
+ CondVar.WaitD(Lock, NextItem->GetScheduleTime());
+ } else {
+ CondVar.WaitI(Lock);
+ }
+
+ if (StopThread) {
+ break;
+ }
+
+ // signal comes if either scheduler is to be stopped of there's work to do
+ Y_VERIFY(!!NextItem, "state check");
+
+ if (TInstant::Now() < NextItem->GetScheduleTime()) {
+ // NextItem is updated since WaitD
+ continue;
+ }
+
+ current = NextItem.Release();
+ }
+
+ current->Do();
+ current.Destroy();
+
+ {
+ TGuard<TLock> guard(Lock);
+ FillNextItem();
+ }
+ }
+}
diff --git a/library/cpp/messagebus/scheduler/scheduler.h b/library/cpp/messagebus/scheduler/scheduler.h
new file mode 100644
index 0000000000..afcc0de55d
--- /dev/null
+++ b/library/cpp/messagebus/scheduler/scheduler.h
@@ -0,0 +1,68 @@
+#pragma once
+
+#include <library/cpp/threading/future/legacy_future.h>
+
+#include <util/datetime/base.h>
+#include <util/generic/object_counter.h>
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+#include <util/system/atomic.h>
+#include <util/system/condvar.h>
+#include <util/system/mutex.h>
+#include <util/system/thread.h>
+
+namespace NBus {
+ namespace NPrivate {
+ class IScheduleItem {
+ public:
+ inline IScheduleItem(TInstant scheduleTime) noexcept;
+ virtual ~IScheduleItem() {
+ }
+
+ virtual void Do() = 0;
+ inline TInstant GetScheduleTime() const noexcept;
+
+ private:
+ TInstant ScheduleTime;
+ };
+
+ using IScheduleItemAutoPtr = TAutoPtr<IScheduleItem>;
+
+ class TScheduler {
+ public:
+ TScheduler();
+ ~TScheduler();
+ void Stop();
+ void Schedule(TAutoPtr<IScheduleItem> i);
+
+ size_t Size() const;
+
+ private:
+ void SchedulerThread();
+
+ void FillNextItem();
+
+ private:
+ TVector<IScheduleItemAutoPtr> Items;
+ IScheduleItemAutoPtr NextItem;
+ typedef TMutex TLock;
+ TLock Lock;
+ TCondVar CondVar;
+
+ TObjectCounter<TScheduler> ObjectCounter;
+
+ bool StopThread;
+ NThreading::TLegacyFuture<> Thread;
+ };
+
+ inline IScheduleItem::IScheduleItem(TInstant scheduleTime) noexcept
+ : ScheduleTime(scheduleTime)
+ {
+ }
+
+ inline TInstant IScheduleItem::GetScheduleTime() const noexcept {
+ return ScheduleTime;
+ }
+
+ }
+}
diff --git a/library/cpp/messagebus/scheduler/scheduler_ut.cpp b/library/cpp/messagebus/scheduler/scheduler_ut.cpp
new file mode 100644
index 0000000000..a5ea641c10
--- /dev/null
+++ b/library/cpp/messagebus/scheduler/scheduler_ut.cpp
@@ -0,0 +1,36 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "scheduler.h"
+
+#include <library/cpp/messagebus/misc/test_sync.h>
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+Y_UNIT_TEST_SUITE(TSchedulerTests) {
+ struct TSimpleScheduleItem: public IScheduleItem {
+ TTestSync* const TestSync;
+
+ TSimpleScheduleItem(TTestSync* testSync)
+ : IScheduleItem((TInstant::Now() + TDuration::MilliSeconds(1)))
+ , TestSync(testSync)
+ {
+ }
+
+ void Do() override {
+ TestSync->WaitForAndIncrement(0);
+ }
+ };
+
+ Y_UNIT_TEST(Simple) {
+ TTestSync testSync;
+
+ TScheduler scheduler;
+
+ scheduler.Schedule(new TSimpleScheduleItem(&testSync));
+
+ testSync.WaitForAndIncrement(1);
+
+ scheduler.Stop();
+ }
+}
diff --git a/library/cpp/messagebus/scheduler/ya.make b/library/cpp/messagebus/scheduler/ya.make
new file mode 100644
index 0000000000..dcb7408a20
--- /dev/null
+++ b/library/cpp/messagebus/scheduler/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(g:messagebus)
+
+PEERDIR(
+ library/cpp/threading/future
+)
+
+SRCS(
+ scheduler.cpp
+)
+
+END()
diff --git a/library/cpp/messagebus/scheduler_actor.h b/library/cpp/messagebus/scheduler_actor.h
new file mode 100644
index 0000000000..d0c23c94c4
--- /dev/null
+++ b/library/cpp/messagebus/scheduler_actor.h
@@ -0,0 +1,85 @@
+#pragma once
+
+#include "local_tasks.h"
+
+#include <library/cpp/messagebus/actor/actor.h>
+#include <library/cpp/messagebus/actor/what_thread_does_guard.h>
+#include <library/cpp/messagebus/scheduler/scheduler.h>
+
+#include <util/system/mutex.h>
+
+namespace NBus {
+ namespace NPrivate {
+ template <typename TThis, typename TTag = NActor::TDefaultTag>
+ class TScheduleActor {
+ typedef NActor::TActor<TThis, TTag> TActorForMe;
+
+ private:
+ TScheduler* const Scheduler;
+
+ TMutex Mutex;
+
+ TInstant ScheduleTime;
+
+ public:
+ TLocalTasks Alarm;
+
+ private:
+ struct TScheduleItemImpl: public IScheduleItem {
+ TIntrusivePtr<TThis> Thiz;
+
+ TScheduleItemImpl(TIntrusivePtr<TThis> thiz, TInstant when)
+ : IScheduleItem(when)
+ , Thiz(thiz)
+ {
+ }
+
+ void Do() override {
+ {
+ TWhatThreadDoesAcquireGuard<TMutex> guard(Thiz->Mutex, "scheduler actor: acquiring lock for Do");
+
+ if (Thiz->ScheduleTime == TInstant::Max()) {
+ // was already fired
+ return;
+ }
+
+ Thiz->ScheduleTime = TInstant::Max();
+ }
+
+ Thiz->Alarm.AddTask();
+ Thiz->GetActorForMe()->Schedule();
+ }
+ };
+
+ public:
+ TScheduleActor(TScheduler* scheduler)
+ : Scheduler(scheduler)
+ , ScheduleTime(TInstant::Max())
+ {
+ }
+
+ /// call Act(TTag) at specified time, unless it is already scheduled at earlier time.
+ void ScheduleAt(TInstant when) {
+ TWhatThreadDoesAcquireGuard<TMutex> guard(Mutex, "scheduler: acquiring lock for ScheduleAt");
+
+ if (when > ScheduleTime) {
+ // already scheduled
+ return;
+ }
+
+ ScheduleTime = when;
+ Scheduler->Schedule(new TScheduleItemImpl(GetThis(), when));
+ }
+
+ private:
+ TThis* GetThis() {
+ return static_cast<TThis*>(this);
+ }
+
+ TActorForMe* GetActorForMe() {
+ return static_cast<TActorForMe*>(GetThis());
+ }
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/scheduler_actor_ut.cpp b/library/cpp/messagebus/scheduler_actor_ut.cpp
new file mode 100644
index 0000000000..e81ffd3186
--- /dev/null
+++ b/library/cpp/messagebus/scheduler_actor_ut.cpp
@@ -0,0 +1,48 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "scheduler_actor.h"
+#include "misc/test_sync.h"
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+using namespace NActor;
+
+Y_UNIT_TEST_SUITE(TSchedulerActorTests) {
+ struct TMyActor: public TAtomicRefCount<TMyActor>, public TActor<TMyActor>, public TScheduleActor<TMyActor> {
+ TTestSync TestSync;
+
+ TMyActor(TExecutor* executor, TScheduler* scheduler)
+ : TActor<TMyActor>(executor)
+ , TScheduleActor<TMyActor>(scheduler)
+ , Iteration(0)
+ {
+ }
+
+ unsigned Iteration;
+
+ void Act(TDefaultTag) {
+ if (!Alarm.FetchTask()) {
+ Y_FAIL("must not have no spurious wakeups in test");
+ }
+
+ TestSync.WaitForAndIncrement(Iteration++);
+ if (Iteration <= 5) {
+ ScheduleAt(TInstant::Now() + TDuration::MilliSeconds(Iteration));
+ }
+ }
+ };
+
+ Y_UNIT_TEST(Simple) {
+ TExecutor executor(1);
+ TScheduler scheduler;
+
+ TIntrusivePtr<TMyActor> actor(new TMyActor(&executor, &scheduler));
+
+ actor->ScheduleAt(TInstant::Now() + TDuration::MilliSeconds(1));
+
+ actor->TestSync.WaitForAndIncrement(6);
+
+ // TODO: stop in destructor
+ scheduler.Stop();
+ }
+}
diff --git a/library/cpp/messagebus/session.cpp b/library/cpp/messagebus/session.cpp
new file mode 100644
index 0000000000..46a7ece6a8
--- /dev/null
+++ b/library/cpp/messagebus/session.cpp
@@ -0,0 +1,130 @@
+#include "ybus.h"
+
+#include <util/generic/cast.h>
+
+using namespace NBus;
+
+namespace NBus {
+ TBusSession::TBusSession() {
+ }
+
+ ////////////////////////////////////////////////////////////////////
+ /// \brief Adds peer of connection into connection list
+
+ int CompareByHost(const IRemoteAddr& l, const IRemoteAddr& r) noexcept {
+ if (l.Addr()->sa_family != r.Addr()->sa_family) {
+ return l.Addr()->sa_family < r.Addr()->sa_family ? -1 : +1;
+ }
+
+ switch (l.Addr()->sa_family) {
+ case AF_INET: {
+ return memcmp(&(((const sockaddr_in*)l.Addr())->sin_addr), &(((const sockaddr_in*)r.Addr())->sin_addr), sizeof(in_addr));
+ }
+
+ case AF_INET6: {
+ return memcmp(&(((const sockaddr_in6*)l.Addr())->sin6_addr), &(((const sockaddr_in6*)r.Addr())->sin6_addr), sizeof(in6_addr));
+ }
+ }
+
+ return memcmp(l.Addr(), r.Addr(), Min<size_t>(l.Len(), r.Len()));
+ }
+
+ bool operator<(const TNetAddr& a1, const TNetAddr& a2) {
+ return CompareByHost(a1, a2) < 0;
+ }
+
+ size_t TBusSession::GetInFlight(const TNetAddr& addr) const {
+ size_t r;
+ GetInFlightBulk({addr}, MakeArrayRef(&r, 1));
+ return r;
+ }
+
+ size_t TBusSession::GetConnectSyscallsNumForTest(const TNetAddr& addr) const {
+ size_t r;
+ GetConnectSyscallsNumBulkForTest({addr}, MakeArrayRef(&r, 1));
+ return r;
+ }
+
+ // Split 'host' into name and port taking into account that host can be specified
+ // as ipv6 address ('[<ipv6 address]:port' notion).
+ bool SplitHost(const TString& host, TString* hostName, TString* portNum) {
+ hostName->clear();
+ portNum->clear();
+
+ // Simple check that we have to deal with ipv6 address specification or
+ // just host name or ipv4 address.
+ if (!host.empty() && (host[0] == '[')) {
+ size_t pos = host.find(']');
+ if (pos < 2 || pos == TString::npos) {
+ // '[]' and '[<address>' are errors.
+ return false;
+ }
+
+ *hostName = host.substr(1, pos - 1);
+
+ pos++;
+ if (pos != host.length()) {
+ if (host[pos] != ':') {
+ // Do not allow '[...]a' but '[...]:' is ok (as for ipv4 before
+ return false;
+ }
+
+ *portNum = host.substr(pos + 1);
+ }
+ } else {
+ size_t pos = host.find(':');
+ if (pos != TString::npos) {
+ if (pos == 0) {
+ // Treat ':<port>' as errors but allow or '<host>:' for compatibility.
+ return false;
+ }
+
+ *portNum = host.substr(pos + 1);
+ }
+
+ *hostName = host.substr(0, pos);
+ }
+
+ return true;
+ }
+
+ /// registers external session on host:port with locator service
+ int TBusSession::RegisterService(const char* host, TBusKey start /*= YBUS_KEYMIN*/, TBusKey end /*= YBUS_KEYMAX*/, EIpVersion ipVersion) {
+ TString hostName;
+ TString port;
+ int portNum;
+
+ if (!SplitHost(host, &hostName, &port)) {
+ hostName = host;
+ }
+
+ if (port.empty()) {
+ portNum = GetProto()->GetPort();
+ } else {
+ try {
+ portNum = FromString<int>(port);
+ } catch (const TFromStringException&) {
+ return -1;
+ }
+ }
+
+ TBusService service = GetProto()->GetService();
+ return GetQueue()->GetLocator()->Register(service, hostName.data(), portNum, start, end, ipVersion);
+ }
+
+ TBusSession::~TBusSession() {
+ }
+
+}
+
+TBusClientSessionPtr TBusClientSession::Create(TBusProtocol* proto, IBusClientHandler* handler, const TBusClientSessionConfig& config, TBusMessageQueuePtr queue) {
+ return queue->CreateSource(proto, handler, config);
+}
+
+TBusServerSessionPtr TBusServerSession::Create(TBusProtocol* proto, IBusServerHandler* handler, const TBusServerSessionConfig& config, TBusMessageQueuePtr queue) {
+ return queue->CreateDestination(proto, handler, config);
+}
+
+TBusServerSessionPtr TBusServerSession::Create(TBusProtocol* proto, IBusServerHandler* handler, const TBusServerSessionConfig& config, TBusMessageQueuePtr queue, const TVector<TBindResult>& bindTo) {
+ return queue->CreateDestination(proto, handler, config, bindTo);
+}
diff --git a/library/cpp/messagebus/session.h b/library/cpp/messagebus/session.h
new file mode 100644
index 0000000000..fb12ab7c22
--- /dev/null
+++ b/library/cpp/messagebus/session.h
@@ -0,0 +1,225 @@
+#pragma once
+
+#include "connection.h"
+#include "defs.h"
+#include "handler.h"
+#include "message.h"
+#include "netaddr.h"
+#include "network.h"
+#include "session_config.h"
+#include "misc/weak_ptr.h"
+
+#include <library/cpp/messagebus/monitoring/mon_proto.pb.h>
+
+#include <util/generic/array_ref.h>
+#include <util/generic/ptr.h>
+
+namespace NBus {
+ template <typename TBusSessionSubclass>
+ class TBusSessionPtr;
+ using TBusClientSessionPtr = TBusSessionPtr<TBusClientSession>;
+ using TBusServerSessionPtr = TBusSessionPtr<TBusServerSession>;
+
+ ///////////////////////////////////////////////////////////////////
+ /// \brief Interface of session object.
+
+ /// Each client and server
+ /// should instantiate session object to be able to communicate via bus
+ /// client: sess = queue->CreateSource(protocol, handler);
+ /// server: sess = queue->CreateDestination(protocol, handler);
+
+ class TBusSession: public TWeakRefCounted<TBusSession> {
+ public:
+ size_t GetInFlight(const TNetAddr& addr) const;
+ size_t GetConnectSyscallsNumForTest(const TNetAddr& addr) const;
+
+ virtual void GetInFlightBulk(TArrayRef<const TNetAddr> addrs, TArrayRef<size_t> results) const = 0;
+ virtual void GetConnectSyscallsNumBulkForTest(TArrayRef<const TNetAddr> addrs, TArrayRef<size_t> results) const = 0;
+
+ virtual int GetInFlight() const noexcept = 0;
+ /// monitoring status of current session and it's connections
+ virtual TString GetStatus(ui16 flags = YBUS_STATUS_CONNS) = 0;
+ virtual TConnectionStatusMonRecord GetStatusProtobuf() = 0;
+ virtual NPrivate::TSessionDumpStatus GetStatusRecordInternal() = 0;
+ virtual TString GetStatusSingleLine() = 0;
+ /// return session config
+ virtual const TBusSessionConfig* GetConfig() const noexcept = 0;
+ /// return session protocol
+ virtual const TBusProtocol* GetProto() const noexcept = 0;
+ virtual TBusMessageQueue* GetQueue() const noexcept = 0;
+
+ /// registers external session on host:port with locator service
+ int RegisterService(const char* hostname, TBusKey start = YBUS_KEYMIN, TBusKey end = YBUS_KEYMAX, EIpVersion ipVersion = EIP_VERSION_4);
+
+ protected:
+ TBusSession();
+
+ public:
+ virtual TString GetNameInternal() = 0;
+
+ virtual void Shutdown() = 0;
+
+ virtual ~TBusSession();
+ };
+
+ struct TBusClientSession: public virtual TBusSession {
+ typedef ::NBus::NPrivate::TRemoteClientSession TImpl;
+
+ static TBusClientSessionPtr Create(
+ TBusProtocol* proto,
+ IBusClientHandler* handler,
+ const TBusClientSessionConfig& config,
+ TBusMessageQueuePtr queue);
+
+ virtual TBusClientConnectionPtr GetConnection(const TNetAddr&) = 0;
+
+ /// if you want to open connection early
+ virtual void OpenConnection(const TNetAddr&) = 0;
+
+ /// Send message to the destination
+ /// If addr is set then use it as destination.
+ /// Takes ownership of addr (see ClearState method).
+ virtual EMessageStatus SendMessage(TBusMessage* pMes, const TNetAddr* addr = nullptr, bool wait = false) = 0;
+
+ virtual EMessageStatus SendMessageOneWay(TBusMessage* pMes, const TNetAddr* addr = nullptr, bool wait = false) = 0;
+
+ /// Like SendMessage but cares about message
+ template <typename T /* <: TBusMessage */>
+ EMessageStatus SendMessageAutoPtr(const TAutoPtr<T>& mes, const TNetAddr* addr = nullptr, bool wait = false) {
+ EMessageStatus status = SendMessage(mes.Get(), addr, wait);
+ if (status == MESSAGE_OK)
+ Y_UNUSED(mes.Release());
+ return status;
+ }
+
+ /// Like SendMessageOneWay but cares about message
+ template <typename T /* <: TBusMessage */>
+ EMessageStatus SendMessageOneWayAutoPtr(const TAutoPtr<T>& mes, const TNetAddr* addr = nullptr, bool wait = false) {
+ EMessageStatus status = SendMessageOneWay(mes.Get(), addr, wait);
+ if (status == MESSAGE_OK)
+ Y_UNUSED(mes.Release());
+ return status;
+ }
+
+ EMessageStatus SendMessageMove(TBusMessageAutoPtr message, const TNetAddr* addr = nullptr, bool wait = false) {
+ return SendMessageAutoPtr(message, addr, wait);
+ }
+
+ EMessageStatus SendMessageOneWayMove(TBusMessageAutoPtr message, const TNetAddr* addr = nullptr, bool wait = false) {
+ return SendMessageOneWayAutoPtr(message, addr, wait);
+ }
+
+ // TODO: implement similar one-way methods
+ };
+
+ struct TBusServerSession: public virtual TBusSession {
+ typedef ::NBus::NPrivate::TRemoteServerSession TImpl;
+
+ static TBusServerSessionPtr Create(
+ TBusProtocol* proto,
+ IBusServerHandler* handler,
+ const TBusServerSessionConfig& config,
+ TBusMessageQueuePtr queue);
+
+ static TBusServerSessionPtr Create(
+ TBusProtocol* proto,
+ IBusServerHandler* handler,
+ const TBusServerSessionConfig& config,
+ TBusMessageQueuePtr queue,
+ const TVector<TBindResult>& bindTo);
+
+ // TODO: make parameter non-const
+ virtual EMessageStatus SendReply(const TBusIdentity& ident, TBusMessage* pRep) = 0;
+
+ // TODO: make parameter non-const
+ virtual EMessageStatus ForgetRequest(const TBusIdentity& ident) = 0;
+
+ template <typename U /* <: TBusMessage */>
+ EMessageStatus SendReplyAutoPtr(TBusIdentity& ident, TAutoPtr<U>& resp) {
+ EMessageStatus status = SendReply(const_cast<const TBusIdentity&>(ident), resp.Get());
+ if (status == MESSAGE_OK) {
+ Y_UNUSED(resp.Release());
+ }
+ return status;
+ }
+
+ EMessageStatus SendReplyMove(TBusIdentity& ident, TBusMessageAutoPtr resp) {
+ return SendReplyAutoPtr(ident, resp);
+ }
+
+ /// Pause input from the network.
+ /// It is valid to call this method in parallel.
+ /// TODO: pull this method up to TBusSession.
+ virtual void PauseInput(bool pause) = 0;
+ virtual unsigned GetActualListenPort() = 0;
+ };
+
+ namespace NPrivate {
+ template <typename TBusSessionSubclass>
+ class TBusOwnerSessionPtr: public TAtomicRefCount<TBusOwnerSessionPtr<TBusSessionSubclass>> {
+ private:
+ TIntrusivePtr<TBusSessionSubclass> Ptr;
+
+ public:
+ TBusOwnerSessionPtr(TBusSessionSubclass* session)
+ : Ptr(session)
+ {
+ Y_ASSERT(!!Ptr);
+ }
+
+ ~TBusOwnerSessionPtr() {
+ Ptr->Shutdown();
+ }
+
+ TBusSessionSubclass* Get() const {
+ return reinterpret_cast<TBusSessionSubclass*>(Ptr.Get());
+ }
+ };
+
+ }
+
+ template <typename TBusSessionSubclass>
+ class TBusSessionPtr {
+ private:
+ TIntrusivePtr<NPrivate::TBusOwnerSessionPtr<TBusSessionSubclass>> SmartPtr;
+ TBusSessionSubclass* Ptr;
+
+ public:
+ TBusSessionPtr()
+ : Ptr()
+ {
+ }
+ TBusSessionPtr(TBusSessionSubclass* session)
+ : SmartPtr(!!session ? new NPrivate::TBusOwnerSessionPtr<TBusSessionSubclass>(session) : nullptr)
+ , Ptr(session)
+ {
+ }
+
+ TBusSessionSubclass* Get() const {
+ return Ptr;
+ }
+ operator TBusSessionSubclass*() {
+ return Get();
+ }
+ TBusSessionSubclass& operator*() const {
+ return *Get();
+ }
+ TBusSessionSubclass* operator->() const {
+ return Get();
+ }
+
+ bool operator!() const {
+ return !Ptr;
+ }
+
+ void Swap(TBusSessionPtr& t) noexcept {
+ DoSwap(SmartPtr, t.SmartPtr);
+ DoSwap(Ptr, t.Ptr);
+ }
+
+ void Drop() {
+ TBusSessionPtr().Swap(*this);
+ }
+ };
+
+}
diff --git a/library/cpp/messagebus/session_config.h b/library/cpp/messagebus/session_config.h
new file mode 100644
index 0000000000..37df97e986
--- /dev/null
+++ b/library/cpp/messagebus/session_config.h
@@ -0,0 +1,4 @@
+#pragma once
+
+#include <library/cpp/messagebus/config/session_config.h>
+
diff --git a/library/cpp/messagebus/session_impl.cpp b/library/cpp/messagebus/session_impl.cpp
new file mode 100644
index 0000000000..ddf9f360c4
--- /dev/null
+++ b/library/cpp/messagebus/session_impl.cpp
@@ -0,0 +1,650 @@
+#include "session_impl.h"
+
+#include "acceptor.h"
+#include "network.h"
+#include "remote_client_connection.h"
+#include "remote_client_session.h"
+#include "remote_server_connection.h"
+#include "remote_server_session.h"
+#include "misc/weak_ptr.h"
+
+#include <util/generic/cast.h>
+
+using namespace NActor;
+using namespace NBus;
+using namespace NBus::NPrivate;
+using namespace NEventLoop;
+
+namespace {
+ class TScheduleSession: public IScheduleItem {
+ public:
+ TScheduleSession(TBusSessionImpl* session, TInstant deadline)
+ : IScheduleItem(deadline)
+ , Session(session)
+ , SessionImpl(session)
+ {
+ }
+
+ void Do() override {
+ TIntrusivePtr<TBusSession> session = Session.Get();
+ if (!!session) {
+ SessionImpl->Cron();
+ }
+ }
+
+ private:
+ TWeakPtr<TBusSession> Session;
+ // Work around TWeakPtr limitation
+ TBusSessionImpl* SessionImpl;
+ };
+}
+
+TConnectionsAcceptorsSnapshot::TConnectionsAcceptorsSnapshot()
+ : LastConnectionId(0)
+ , LastAcceptorId(0)
+{
+}
+
+struct TBusSessionImpl::TImpl {
+ TRemoteConnectionWriterIncrementalStatus DeadConnectionWriterStatusSummary;
+ TRemoteConnectionReaderIncrementalStatus DeadConnectionReaderStatusSummary;
+ TAcceptorStatus DeadAcceptorStatusSummary;
+};
+
+namespace {
+ TBusSessionConfig SessionConfigFillDefaults(const TBusSessionConfig& config, const TString& name) {
+ TBusSessionConfig copy = config;
+ if (copy.TotalTimeout == 0 && copy.SendTimeout == 0) {
+ copy.TotalTimeout = TDuration::Seconds(60).MilliSeconds();
+ copy.SendTimeout = TDuration::Seconds(15).MilliSeconds();
+ } else if (copy.TotalTimeout == 0) {
+ Y_ASSERT(copy.SendTimeout != 0);
+ copy.TotalTimeout = config.SendTimeout + TDuration::MilliSeconds(10).MilliSeconds();
+ } else if (copy.SendTimeout == 0) {
+ Y_ASSERT(copy.TotalTimeout != 0);
+ if ((ui64)copy.TotalTimeout > (ui64)TDuration::MilliSeconds(10).MilliSeconds()) {
+ copy.SendTimeout = copy.TotalTimeout - TDuration::MilliSeconds(10).MilliSeconds();
+ } else {
+ copy.SendTimeout = copy.TotalTimeout;
+ }
+ } else {
+ Y_ASSERT(copy.TotalTimeout != 0);
+ Y_ASSERT(copy.SendTimeout != 0);
+ }
+
+ if (copy.ConnectTimeout == 0) {
+ copy.ConnectTimeout = copy.SendTimeout;
+ }
+
+ Y_VERIFY(copy.SendTimeout > 0, "SendTimeout must be > 0");
+ Y_VERIFY(copy.TotalTimeout > 0, "TotalTimeout must be > 0");
+ Y_VERIFY(copy.ConnectTimeout > 0, "ConnectTimeout must be > 0");
+ Y_VERIFY(copy.TotalTimeout >= copy.SendTimeout, "TotalTimeout must be >= SendTimeout");
+
+ if (!copy.Name) {
+ copy.Name = name;
+ }
+
+ return copy;
+ }
+}
+
+TBusSessionImpl::TBusSessionImpl(bool isSource, TBusMessageQueue* queue, TBusProtocol* proto,
+ IBusErrorHandler* handler,
+ const TBusSessionConfig& config, const TString& name)
+ : TActor<TBusSessionImpl, TStatusTag>(queue->WorkQueue.Get())
+ , TActor<TBusSessionImpl, TConnectionTag>(queue->WorkQueue.Get())
+ , Impl(new TImpl)
+ , IsSource_(isSource)
+ , Queue(queue)
+ , Proto(proto)
+ , ProtoName(Proto->GetService())
+ , ErrorHandler(handler)
+ , HandlerUseCountHolder(&handler->UseCountChecker)
+ , Config(SessionConfigFillDefaults(config, name))
+ , WriteEventLoop("wr-el")
+ , ReadEventLoop("rd-el")
+ , LastAcceptorId(0)
+ , LastConnectionId(0)
+ , Down(0)
+{
+ Impl->DeadAcceptorStatusSummary.Summary = true;
+
+ ReadEventLoopThread.Reset(new NThreading::TLegacyFuture<void, false>(std::bind(&TEventLoop::Run, std::ref(ReadEventLoop))));
+ WriteEventLoopThread.Reset(new NThreading::TLegacyFuture<void, false>(std::bind(&TEventLoop::Run, std::ref(WriteEventLoop))));
+
+ Queue->Schedule(IScheduleItemAutoPtr(new TScheduleSession(this, TInstant::Now() + Config.Secret.TimeoutPeriod)));
+}
+
+TBusSessionImpl::~TBusSessionImpl() {
+ Y_VERIFY(Down);
+ Y_VERIFY(ShutdownCompleteEvent.WaitT(TDuration::Zero()));
+ Y_VERIFY(!WriteEventLoop.IsRunning());
+ Y_VERIFY(!ReadEventLoop.IsRunning());
+}
+
+TBusSessionStatus::TBusSessionStatus()
+ : InFlightCount(0)
+ , InFlightSize(0)
+ , InputPaused(false)
+{
+}
+
+void TBusSessionImpl::Shutdown() {
+ if (!AtomicCas(&Down, 1, 0)) {
+ ShutdownCompleteEvent.WaitI();
+ return;
+ }
+
+ Y_VERIFY(Queue->IsRunning(), "Session must be shut down prior to queue shutdown");
+
+ TUseAfterFreeCheckerGuard handlerAliveCheckedGuard(ErrorHandler->UseAfterFreeChecker);
+
+ // For legacy clients that don't use smart pointers
+ TIntrusivePtr<TBusSessionImpl> thiz(this);
+
+ Queue->Remove(this);
+
+ // shutdown event loops first, so they won't send more events
+ // to acceptors and connections
+ ReadEventLoop.Stop();
+ WriteEventLoop.Stop();
+ ReadEventLoopThread->Get();
+ WriteEventLoopThread->Get();
+
+ // shutdown acceptors before connections
+ // so they won't create more connections
+ TVector<TAcceptorPtr> acceptors;
+ GetAcceptors(&acceptors);
+ {
+ TGuard<TMutex> guard(ConnectionsLock);
+ Acceptors.clear();
+ }
+
+ for (auto& acceptor : acceptors) {
+ acceptor->Shutdown();
+ }
+
+ // shutdown connections
+ TVector<TRemoteConnectionPtr> cs;
+ GetConnections(&cs);
+
+ for (auto& c : cs) {
+ c->Shutdown(MESSAGE_SHUTDOWN);
+ }
+
+ // shutdown connections actor
+ // must shutdown after connections destroyed
+ ConnectionsData.ShutdownState.ShutdownCommand();
+ GetConnectionsActor()->Schedule();
+ ConnectionsData.ShutdownState.ShutdownComplete.WaitI();
+
+ // finally shutdown status actor
+ StatusData.ShutdownState.ShutdownCommand();
+ GetStatusActor()->Schedule();
+ StatusData.ShutdownState.ShutdownComplete.WaitI();
+
+ // Make sure no one references IMessageHandler after Shutdown()
+ JobCount.WaitForZero();
+ HandlerUseCountHolder.Reset();
+
+ ShutdownCompleteEvent.Signal();
+}
+
+bool TBusSessionImpl::IsDown() {
+ return static_cast<bool>(AtomicGet(Down));
+}
+
+size_t TBusSessionImpl::GetInFlightImpl(const TNetAddr& addr) const {
+ TRemoteConnectionPtr conn = const_cast<TBusSessionImpl*>(this)->GetConnection(addr, false);
+ if (!!conn) {
+ return conn->GetInFlight();
+ } else {
+ return 0;
+ }
+}
+
+void TBusSessionImpl::GetInFlightBulk(TArrayRef<const TNetAddr> addrs, TArrayRef<size_t> results) const {
+ Y_VERIFY(addrs.size() == results.size(), "input.size != output.size");
+ for (size_t i = 0; i < addrs.size(); ++i) {
+ results[i] = GetInFlightImpl(addrs[i]);
+ }
+}
+
+size_t TBusSessionImpl::GetConnectSyscallsNumForTestImpl(const TNetAddr& addr) const {
+ TRemoteConnectionPtr conn = const_cast<TBusSessionImpl*>(this)->GetConnection(addr, false);
+ if (!!conn) {
+ return conn->GetConnectSyscallsNumForTest();
+ } else {
+ return 0;
+ }
+}
+
+void TBusSessionImpl::GetConnectSyscallsNumBulkForTest(TArrayRef<const TNetAddr> addrs, TArrayRef<size_t> results) const {
+ Y_VERIFY(addrs.size() == results.size(), "input.size != output.size");
+ for (size_t i = 0; i < addrs.size(); ++i) {
+ results[i] = GetConnectSyscallsNumForTestImpl(addrs[i]);
+ }
+}
+
+void TBusSessionImpl::FillStatus() {
+}
+
+TSessionDumpStatus TBusSessionImpl::GetStatusRecordInternal() {
+ // Probably useless, because it returns cached info now
+ Y_VERIFY(!Queue->GetExecutor()->IsInExecutorThread(),
+ "GetStatus must not be called from executor thread");
+
+ TGuard<TMutex> guard(StatusData.StatusDumpCachedMutex);
+ // TODO: returns zeros for a second after start
+ // (until first cron)
+ return StatusData.StatusDumpCached;
+}
+
+TString TBusSessionImpl::GetStatus(ui16 flags) {
+ Y_UNUSED(flags);
+
+ return GetStatusRecordInternal().PrintToString();
+}
+
+TConnectionStatusMonRecord TBusSessionImpl::GetStatusProtobuf() {
+ Y_VERIFY(!Queue->GetExecutor()->IsInExecutorThread(),
+ "GetStatus must not be called from executor thread");
+
+ TGuard<TMutex> guard(StatusData.StatusDumpCachedMutex);
+
+ return StatusData.StatusDumpCached.ConnectionStatusSummary.GetStatusProtobuf();
+}
+
+TString TBusSessionImpl::GetStatusSingleLine() {
+ TSessionDumpStatus status = GetStatusRecordInternal();
+
+ TStringStream ss;
+ ss << "in-flight: " << status.Status.InFlightCount;
+ if (IsSource_) {
+ ss << " ack: " << status.ConnectionStatusSummary.WriterStatus.AckMessagesSize;
+ }
+ ss << " send-q: " << status.ConnectionStatusSummary.WriterStatus.SendQueueSize;
+ return ss.Str();
+}
+
+void TBusSessionImpl::ProcessItem(TStatusTag, TDeadConnectionTag, const TRemoteConnectionWriterIncrementalStatus& connectionStatus) {
+ Impl->DeadConnectionWriterStatusSummary += connectionStatus;
+}
+
+void TBusSessionImpl::ProcessItem(TStatusTag, TDeadConnectionTag, const TRemoteConnectionReaderIncrementalStatus& connectionStatus) {
+ Impl->DeadConnectionReaderStatusSummary += connectionStatus;
+}
+
+void TBusSessionImpl::ProcessItem(TStatusTag, TDeadConnectionTag, const TAcceptorStatus& acceptorStatus) {
+ Impl->DeadAcceptorStatusSummary += acceptorStatus;
+}
+
+void TBusSessionImpl::ProcessItem(TConnectionTag, ::NActor::TDefaultTag, const TOnAccept& onAccept) {
+ TSocketHolder socket(onAccept.s);
+
+ if (AtomicGet(Down)) {
+ // do not create connections after shutdown initiated
+ return;
+ }
+
+ //if (Connections.find(addr) != Connections.end()) {
+ // TODO: it is possible
+ // won't be a problem after socket address replaced with id
+ //}
+
+ TRemoteConnectionPtr c(new TRemoteServerConnection(VerifyDynamicCast<TRemoteServerSession*>(this), ++LastConnectionId, onAccept.addr));
+
+ VerifyDynamicCast<TRemoteServerConnection*>(c.Get())->Init(socket.Release(), onAccept.now);
+
+ InsertConnectionLockAcquired(c.Get());
+}
+
+void TBusSessionImpl::ProcessItem(TConnectionTag, TRemoveTag, TRemoteConnectionPtr c) {
+ TAddrRemoteConnections::iterator it1 = Connections.find(c->PeerAddrSocketAddr);
+ if (it1 != Connections.end()) {
+ if (it1->second.Get() == c.Get()) {
+ Connections.erase(it1);
+ }
+ }
+
+ THashMap<ui64, TRemoteConnectionPtr>::iterator it2 = ConnectionsById.find(c->ConnectionId);
+ if (it2 != ConnectionsById.end()) {
+ ConnectionsById.erase(it2);
+ }
+
+ SendSnapshotToStatusActor();
+}
+
+void TBusSessionImpl::ProcessConnectionsAcceptorsShapshotQueueItem(TAtomicSharedPtr<TConnectionsAcceptorsSnapshot> snapshot) {
+ for (TVector<TRemoteConnectionPtr>::const_iterator connection = snapshot->Connections.begin();
+ connection != snapshot->Connections.end(); ++connection) {
+ Y_ASSERT((*connection)->ConnectionId <= snapshot->LastConnectionId);
+ }
+
+ for (TVector<TAcceptorPtr>::const_iterator acceptor = snapshot->Acceptors.begin();
+ acceptor != snapshot->Acceptors.end(); ++acceptor) {
+ Y_ASSERT((*acceptor)->AcceptorId <= snapshot->LastAcceptorId);
+ }
+
+ StatusData.ConnectionsAcceptorsSnapshot = snapshot;
+}
+
+void TBusSessionImpl::StatusUpdateCachedDumpIfNecessary(TInstant now) {
+ if (now - StatusData.StatusDumpCachedLastUpdate > Config.Secret.StatusFlushPeriod) {
+ StatusUpdateCachedDump();
+ StatusData.StatusDumpCachedLastUpdate = now;
+ }
+}
+
+void TBusSessionImpl::StatusUpdateCachedDump() {
+ TSessionDumpStatus r;
+
+ if (AtomicGet(Down)) {
+ r.Shutdown = true;
+ TGuard<TMutex> guard(StatusData.StatusDumpCachedMutex);
+ StatusData.StatusDumpCached = r;
+ return;
+ }
+
+ // TODO: make thread-safe
+ FillStatus();
+
+ r.Status = StatusData.Status;
+
+ {
+ TStringStream ss;
+
+ TString name = Config.Name;
+ if (!name) {
+ name = "unnamed";
+ }
+
+ ss << (IsSource_ ? "client" : "server") << " session " << name << ", proto " << Proto->GetService() << Endl;
+ ss << "in flight: " << r.Status.InFlightCount;
+ if (!IsSource_) {
+ ss << ", " << r.Status.InFlightSize << "b";
+ }
+ if (r.Status.InputPaused) {
+ ss << " (input paused)";
+ }
+ ss << "\n";
+
+ r.Head = ss.Str();
+ }
+
+ TVector<TRemoteConnectionPtr>& connections = StatusData.ConnectionsAcceptorsSnapshot->Connections;
+ TVector<TAcceptorPtr>& acceptors = StatusData.ConnectionsAcceptorsSnapshot->Acceptors;
+
+ r.ConnectionStatusSummary = TRemoteConnectionStatus();
+ r.ConnectionStatusSummary.Summary = true;
+ r.ConnectionStatusSummary.Server = !IsSource_;
+ r.ConnectionStatusSummary.WriterStatus.Incremental = Impl->DeadConnectionWriterStatusSummary;
+ r.ConnectionStatusSummary.ReaderStatus.Incremental = Impl->DeadConnectionReaderStatusSummary;
+
+ TAcceptorStatus acceptorStatusSummary = Impl->DeadAcceptorStatusSummary;
+
+ {
+ TStringStream ss;
+
+ for (TVector<TAcceptorPtr>::const_iterator acceptor = acceptors.begin();
+ acceptor != acceptors.end(); ++acceptor) {
+ const TAcceptorStatus status = (*acceptor)->GranStatus.Listen.Get();
+
+ acceptorStatusSummary += status;
+
+ if (acceptor != acceptors.begin()) {
+ ss << "\n";
+ }
+ ss << status.PrintToString();
+ }
+
+ r.Acceptors = ss.Str();
+ }
+
+ {
+ TStringStream ss;
+
+ for (TVector<TRemoteConnectionPtr>::const_iterator connection = connections.begin();
+ connection != connections.end(); ++connection) {
+ if (connection != connections.begin()) {
+ ss << "\n";
+ }
+
+ TRemoteConnectionStatus status;
+ status.Server = !IsSource_;
+ status.ReaderStatus = (*connection)->GranStatus.Reader.Get();
+ status.WriterStatus = (*connection)->GranStatus.Writer.Get();
+
+ ss << status.PrintToString();
+
+ r.ConnectionStatusSummary.ReaderStatus += status.ReaderStatus;
+ r.ConnectionStatusSummary.WriterStatus += status.WriterStatus;
+ }
+
+ r.ConnectionsSummary = r.ConnectionStatusSummary.PrintToString();
+ r.Connections = ss.Str();
+ }
+
+ r.Config = Config;
+
+ TGuard<TMutex> guard(StatusData.StatusDumpCachedMutex);
+ StatusData.StatusDumpCached = r;
+}
+
+TBusSessionImpl::TStatusData::TStatusData()
+ : ConnectionsAcceptorsSnapshot(new TConnectionsAcceptorsSnapshot)
+{
+}
+
+void TBusSessionImpl::Act(TStatusTag) {
+ TInstant now = TInstant::Now();
+
+ EShutdownState shutdownState = StatusData.ShutdownState.State.Get();
+
+ StatusData.ConnectionsAcceptorsSnapshotsQueue.DequeueAllLikelyEmpty(std::bind(&TBusSessionImpl::ProcessConnectionsAcceptorsShapshotQueueItem, this, std::placeholders::_1));
+
+ GetDeadConnectionWriterStatusQueue()->DequeueAllLikelyEmpty();
+ GetDeadConnectionReaderStatusQueue()->DequeueAllLikelyEmpty();
+ GetDeadAcceptorStatusQueue()->DequeueAllLikelyEmpty();
+
+ // TODO: check queues are empty if already stopped
+
+ if (shutdownState != SS_RUNNING) {
+ // important to beak cyclic link session -> connection -> session
+ StatusData.ConnectionsAcceptorsSnapshot->Connections.clear();
+ StatusData.ConnectionsAcceptorsSnapshot->Acceptors.clear();
+ }
+
+ if (shutdownState == SS_SHUTDOWN_COMMAND) {
+ StatusData.ShutdownState.CompleteShutdown();
+ }
+
+ StatusUpdateCachedDumpIfNecessary(now);
+}
+
+TBusSessionImpl::TConnectionsData::TConnectionsData() {
+}
+
+void TBusSessionImpl::Act(TConnectionTag) {
+ TConnectionsGuard guard(ConnectionsLock);
+
+ EShutdownState shutdownState = ConnectionsData.ShutdownState.State.Get();
+ if (shutdownState == SS_SHUTDOWN_COMPLETE) {
+ Y_VERIFY(GetRemoveConnectionQueue()->IsEmpty());
+ Y_VERIFY(GetOnAcceptQueue()->IsEmpty());
+ }
+
+ GetRemoveConnectionQueue()->DequeueAllLikelyEmpty();
+ GetOnAcceptQueue()->DequeueAllLikelyEmpty();
+
+ if (shutdownState == SS_SHUTDOWN_COMMAND) {
+ ConnectionsData.ShutdownState.CompleteShutdown();
+ }
+}
+
+void TBusSessionImpl::Listen(int port, TBusMessageQueue* q) {
+ Listen(BindOnPort(port, Config.ReusePort).second, q);
+}
+
+void TBusSessionImpl::Listen(const TVector<TBindResult>& bindTo, TBusMessageQueue* q) {
+ Y_ASSERT(q == Queue);
+ int actualPort = -1;
+
+ for (const TBindResult& br : bindTo) {
+ if (actualPort == -1) {
+ actualPort = br.Addr.GetPort();
+ } else {
+ Y_VERIFY(actualPort == br.Addr.GetPort(), "state check");
+ }
+ if (Config.SocketToS >= 0) {
+ SetSocketToS(*br.Socket, &(br.Addr), Config.SocketToS);
+ }
+
+ TAcceptorPtr acceptor(new TAcceptor(this, ++LastAcceptorId, br.Socket->Release(), br.Addr));
+
+ TConnectionsGuard guard(ConnectionsLock);
+ InsertAcceptorLockAcquired(acceptor.Get());
+ }
+
+ Config.ListenPort = actualPort;
+}
+
+void TBusSessionImpl::SendSnapshotToStatusActor() {
+ //Y_ASSERT(ConnectionsLock.IsLocked());
+
+ TAtomicSharedPtr<TConnectionsAcceptorsSnapshot> snapshot(new TConnectionsAcceptorsSnapshot);
+ GetAcceptorsLockAquired(&snapshot->Acceptors);
+ GetConnectionsLockAquired(&snapshot->Connections);
+ snapshot->LastAcceptorId = LastAcceptorId;
+ snapshot->LastConnectionId = LastConnectionId;
+ StatusData.ConnectionsAcceptorsSnapshotsQueue.Enqueue(snapshot);
+ GetStatusActor()->Schedule();
+}
+
+void TBusSessionImpl::InsertConnectionLockAcquired(TRemoteConnection* connection) {
+ //Y_ASSERT(ConnectionsLock.IsLocked());
+
+ Connections.insert(std::make_pair(connection->PeerAddrSocketAddr, connection));
+ // connection for given adds may already exist at this point
+ // (so we overwrite old connection)
+ // after reconnect, if previous connections wasn't shutdown yet
+
+ bool inserted2 = ConnectionsById.insert(std::make_pair(connection->ConnectionId, connection)).second;
+ Y_VERIFY(inserted2, "state check: must be inserted (2)");
+
+ SendSnapshotToStatusActor();
+}
+
+void TBusSessionImpl::InsertAcceptorLockAcquired(TAcceptor* acceptor) {
+ //Y_ASSERT(ConnectionsLock.IsLocked());
+
+ Acceptors.push_back(acceptor);
+
+ SendSnapshotToStatusActor();
+}
+
+void TBusSessionImpl::GetConnections(TVector<TRemoteConnectionPtr>* r) {
+ TConnectionsGuard guard(ConnectionsLock);
+ GetConnectionsLockAquired(r);
+}
+
+void TBusSessionImpl::GetAcceptors(TVector<TAcceptorPtr>* r) {
+ TConnectionsGuard guard(ConnectionsLock);
+ GetAcceptorsLockAquired(r);
+}
+
+void TBusSessionImpl::GetConnectionsLockAquired(TVector<TRemoteConnectionPtr>* r) {
+ //Y_ASSERT(ConnectionsLock.IsLocked());
+
+ r->reserve(Connections.size());
+
+ for (auto& connection : Connections) {
+ r->push_back(connection.second);
+ }
+}
+
+void TBusSessionImpl::GetAcceptorsLockAquired(TVector<TAcceptorPtr>* r) {
+ //Y_ASSERT(ConnectionsLock.IsLocked());
+
+ r->reserve(Acceptors.size());
+
+ for (auto& acceptor : Acceptors) {
+ r->push_back(acceptor);
+ }
+}
+
+TRemoteConnectionPtr TBusSessionImpl::GetConnectionById(ui64 id) {
+ TConnectionsGuard guard(ConnectionsLock);
+
+ THashMap<ui64, TRemoteConnectionPtr>::const_iterator it = ConnectionsById.find(id);
+ if (it == ConnectionsById.end()) {
+ return nullptr;
+ } else {
+ return it->second;
+ }
+}
+
+TAcceptorPtr TBusSessionImpl::GetAcceptorById(ui64 id) {
+ TGuard<TMutex> guard(ConnectionsLock);
+
+ for (const auto& Acceptor : Acceptors) {
+ if (Acceptor->AcceptorId == id) {
+ return Acceptor;
+ }
+ }
+
+ return nullptr;
+}
+
+void TBusSessionImpl::InvokeOnError(TNonDestroyingAutoPtr<TBusMessage> message, EMessageStatus status) {
+ message->CheckClean();
+ ErrorHandler->OnError(message, status);
+}
+
+TRemoteConnectionPtr TBusSessionImpl::GetConnection(const TBusSocketAddr& addr, bool create) {
+ TConnectionsGuard guard(ConnectionsLock);
+
+ TAddrRemoteConnections::const_iterator it = Connections.find(addr);
+ if (it != Connections.end()) {
+ return it->second;
+ }
+
+ if (!create) {
+ return TRemoteConnectionPtr();
+ }
+
+ Y_VERIFY(IsSource_, "must be source");
+
+ TRemoteConnectionPtr c(new TRemoteClientConnection(VerifyDynamicCast<TRemoteClientSession*>(this), ++LastConnectionId, addr.ToNetAddr()));
+ InsertConnectionLockAcquired(c.Get());
+
+ return c;
+}
+
+void TBusSessionImpl::Cron() {
+ TVector<TRemoteConnectionPtr> connections;
+ GetConnections(&connections);
+
+ for (const auto& it : connections) {
+ TRemoteConnection* connection = it.Get();
+ if (IsSource_) {
+ VerifyDynamicCast<TRemoteClientConnection*>(connection)->ScheduleTimeoutMessages();
+ } else {
+ VerifyDynamicCast<TRemoteServerConnection*>(connection)->WriterData.TimeToRotateCounters.AddTask();
+ // no schedule: do not rotate if there's no traffic
+ }
+ }
+
+ // status updates are sent without scheduling
+ GetStatusActor()->Schedule();
+
+ Queue->Schedule(IScheduleItemAutoPtr(new TScheduleSession(this, TInstant::Now() + Config.Secret.TimeoutPeriod)));
+}
+
+TString TBusSessionImpl::GetNameInternal() {
+ if (!!Config.Name) {
+ return Config.Name;
+ }
+ return ProtoName;
+}
diff --git a/library/cpp/messagebus/session_impl.h b/library/cpp/messagebus/session_impl.h
new file mode 100644
index 0000000000..90ef246ff8
--- /dev/null
+++ b/library/cpp/messagebus/session_impl.h
@@ -0,0 +1,259 @@
+#pragma once
+
+#include "acceptor_status.h"
+#include "async_result.h"
+#include "event_loop.h"
+#include "netaddr.h"
+#include "remote_connection.h"
+#include "remote_connection_status.h"
+#include "session_job_count.h"
+#include "shutdown_state.h"
+#include "ybus.h"
+
+#include <library/cpp/messagebus/actor/actor.h>
+#include <library/cpp/messagebus/actor/queue_in_actor.h>
+#include <library/cpp/messagebus/monitoring/mon_proto.pb.h>
+
+#include <library/cpp/threading/future/legacy_future.h>
+
+#include <util/generic/array_ref.h>
+#include <util/generic/string.h>
+
+namespace NBus {
+ namespace NPrivate {
+ typedef TIntrusivePtr<TRemoteClientConnection> TRemoteClientConnectionPtr;
+ typedef TIntrusivePtr<TRemoteServerConnection> TRemoteServerConnectionPtr;
+
+ typedef TIntrusivePtr<TRemoteServerSession> TRemoteServerSessionPtr;
+
+ typedef TIntrusivePtr<TAcceptor> TAcceptorPtr;
+ typedef TVector<TAcceptorPtr> TAcceptorsPtrs;
+
+ struct TConnectionsAcceptorsSnapshot {
+ TVector<TRemoteConnectionPtr> Connections;
+ TVector<TAcceptorPtr> Acceptors;
+ ui64 LastConnectionId;
+ ui64 LastAcceptorId;
+
+ TConnectionsAcceptorsSnapshot();
+ };
+
+ typedef TAtomicSharedPtr<TConnectionsAcceptorsSnapshot> TConnectionsAcceptorsSnapshotPtr;
+
+ struct TOnAccept {
+ SOCKET s;
+ TNetAddr addr;
+ TInstant now;
+ };
+
+ struct TStatusTag {};
+ struct TConnectionTag {};
+
+ struct TDeadConnectionTag {};
+ struct TRemoveTag {};
+
+ struct TBusSessionImpl
+ : public virtual TBusSession,
+ private ::NActor::TActor<TBusSessionImpl, TStatusTag>,
+ private ::NActor::TActor<TBusSessionImpl, TConnectionTag>
+
+ ,
+ private ::NActor::TQueueInActor<TBusSessionImpl, TRemoteConnectionWriterIncrementalStatus, TStatusTag, TDeadConnectionTag>,
+ private ::NActor::TQueueInActor<TBusSessionImpl, TRemoteConnectionReaderIncrementalStatus, TStatusTag, TDeadConnectionTag>,
+ private ::NActor::TQueueInActor<TBusSessionImpl, TAcceptorStatus, TStatusTag, TDeadConnectionTag>
+
+ ,
+ private ::NActor::TQueueInActor<TBusSessionImpl, TOnAccept, TConnectionTag>,
+ private ::NActor::TQueueInActor<TBusSessionImpl, TRemoteConnectionPtr, TConnectionTag, TRemoveTag> {
+ friend class TAcceptor;
+ friend class TRemoteConnection;
+ friend class TRemoteServerConnection;
+ friend class ::NActor::TActor<TBusSessionImpl, TStatusTag>;
+ friend class ::NActor::TActor<TBusSessionImpl, TConnectionTag>;
+ friend class ::NActor::TQueueInActor<TBusSessionImpl, TRemoteConnectionWriterIncrementalStatus, TStatusTag, TDeadConnectionTag>;
+ friend class ::NActor::TQueueInActor<TBusSessionImpl, TRemoteConnectionReaderIncrementalStatus, TStatusTag, TDeadConnectionTag>;
+ friend class ::NActor::TQueueInActor<TBusSessionImpl, TAcceptorStatus, TStatusTag, TDeadConnectionTag>;
+ friend class ::NActor::TQueueInActor<TBusSessionImpl, TOnAccept, TConnectionTag>;
+ friend class ::NActor::TQueueInActor<TBusSessionImpl, TRemoteConnectionPtr, TConnectionTag, TRemoveTag>;
+
+ public:
+ ::NActor::TQueueInActor<TBusSessionImpl, TOnAccept, TConnectionTag>* GetOnAcceptQueue() {
+ return this;
+ }
+
+ ::NActor::TQueueInActor<TBusSessionImpl, TRemoteConnectionPtr, TConnectionTag, TRemoveTag>* GetRemoveConnectionQueue() {
+ return this;
+ }
+
+ ::NActor::TActor<TBusSessionImpl, TConnectionTag>* GetConnectionActor() {
+ return this;
+ }
+
+ typedef TGuard<TMutex> TConnectionsGuard;
+
+ TBusSessionImpl(bool isSource, TBusMessageQueue* queue, TBusProtocol* proto,
+ IBusErrorHandler* handler,
+ const TBusSessionConfig& config, const TString& name);
+
+ ~TBusSessionImpl() override;
+
+ void Shutdown() override;
+ bool IsDown();
+
+ size_t GetInFlightImpl(const TNetAddr& addr) const;
+ size_t GetConnectSyscallsNumForTestImpl(const TNetAddr& addr) const;
+
+ void GetInFlightBulk(TArrayRef<const TNetAddr> addrs, TArrayRef<size_t> results) const override;
+ void GetConnectSyscallsNumBulkForTest(TArrayRef<const TNetAddr> addrs, TArrayRef<size_t> results) const override;
+
+ virtual void FillStatus();
+ TSessionDumpStatus GetStatusRecordInternal() override;
+ TString GetStatus(ui16 flags = YBUS_STATUS_CONNS) override;
+ TConnectionStatusMonRecord GetStatusProtobuf() override;
+ TString GetStatusSingleLine() override;
+
+ void ProcessItem(TStatusTag, TDeadConnectionTag, const TRemoteConnectionWriterIncrementalStatus&);
+ void ProcessItem(TStatusTag, TDeadConnectionTag, const TRemoteConnectionReaderIncrementalStatus&);
+ void ProcessItem(TStatusTag, TDeadConnectionTag, const TAcceptorStatus&);
+ void ProcessItem(TStatusTag, ::NActor::TDefaultTag, const TAcceptorStatus&);
+ void ProcessItem(TConnectionTag, ::NActor::TDefaultTag, const TOnAccept&);
+ void ProcessItem(TConnectionTag, TRemoveTag, TRemoteConnectionPtr);
+ void ProcessConnectionsAcceptorsShapshotQueueItem(TAtomicSharedPtr<TConnectionsAcceptorsSnapshot>);
+ void StatusUpdateCachedDump();
+ void StatusUpdateCachedDumpIfNecessary(TInstant now);
+ void Act(TStatusTag);
+ void Act(TConnectionTag);
+
+ TBusProtocol* GetProto() const noexcept override;
+ const TBusSessionConfig* GetConfig() const noexcept override;
+ TBusMessageQueue* GetQueue() const noexcept override;
+ TString GetNameInternal() override;
+
+ virtual void OnMessageReceived(TRemoteConnection* c, TVectorSwaps<TBusMessagePtrAndHeader>& newMsg) = 0;
+
+ void Listen(int port, TBusMessageQueue* q);
+ void Listen(const TVector<TBindResult>& bindTo, TBusMessageQueue* q);
+ TBusConnection* Accept(SOCKET listen);
+
+ inline ::NActor::TActor<TBusSessionImpl, TStatusTag>* GetStatusActor() {
+ return this;
+ }
+ inline ::NActor::TActor<TBusSessionImpl, TConnectionTag>* GetConnectionsActor() {
+ return this;
+ }
+
+ typedef THashMap<TBusSocketAddr, TRemoteConnectionPtr> TAddrRemoteConnections;
+
+ void SendSnapshotToStatusActor();
+
+ void InsertConnectionLockAcquired(TRemoteConnection* connection);
+ void InsertAcceptorLockAcquired(TAcceptor* acceptor);
+
+ void GetConnections(TVector<TRemoteConnectionPtr>*);
+ void GetAcceptors(TVector<TAcceptorPtr>*);
+ void GetConnectionsLockAquired(TVector<TRemoteConnectionPtr>*);
+ void GetAcceptorsLockAquired(TVector<TAcceptorPtr>*);
+
+ TRemoteConnectionPtr GetConnection(const TBusSocketAddr& addr, bool create);
+ TRemoteConnectionPtr GetConnectionById(ui64 id);
+ TAcceptorPtr GetAcceptorById(ui64 id);
+
+ void InvokeOnError(TNonDestroyingAutoPtr<TBusMessage>, EMessageStatus);
+
+ void Cron();
+
+ TBusSessionJobCount JobCount;
+
+ // TODO: replace with actor
+ TMutex ConnectionsLock;
+
+ struct TImpl;
+ THolder<TImpl> Impl;
+
+ const bool IsSource_;
+
+ TBusMessageQueue* const Queue;
+ TBusProtocol* const Proto;
+ // copied to be available after Proto dies
+ const TString ProtoName;
+
+ IBusErrorHandler* const ErrorHandler;
+ TUseCountHolder HandlerUseCountHolder;
+ TBusSessionConfig Config; // TODO: make const
+
+ NEventLoop::TEventLoop WriteEventLoop;
+ NEventLoop::TEventLoop ReadEventLoop;
+ THolder<NThreading::TLegacyFuture<void, false>> ReadEventLoopThread;
+ THolder<NThreading::TLegacyFuture<void, false>> WriteEventLoopThread;
+
+ THashMap<ui64, TRemoteConnectionPtr> ConnectionsById;
+ TAddrRemoteConnections Connections;
+ TAcceptorsPtrs Acceptors;
+
+ struct TStatusData {
+ TAtomicSharedPtr<TConnectionsAcceptorsSnapshot> ConnectionsAcceptorsSnapshot;
+ ::NActor::TQueueForActor<TAtomicSharedPtr<TConnectionsAcceptorsSnapshot>> ConnectionsAcceptorsSnapshotsQueue;
+
+ TAtomicShutdownState ShutdownState;
+
+ TBusSessionStatus Status;
+
+ TSessionDumpStatus StatusDumpCached;
+ TMutex StatusDumpCachedMutex;
+ TInstant StatusDumpCachedLastUpdate;
+
+ TStatusData();
+ };
+ TStatusData StatusData;
+
+ struct TConnectionsData {
+ TAtomicShutdownState ShutdownState;
+
+ TConnectionsData();
+ };
+ TConnectionsData ConnectionsData;
+
+ ::NActor::TQueueInActor<TBusSessionImpl, TRemoteConnectionWriterIncrementalStatus,
+ TStatusTag, TDeadConnectionTag>*
+ GetDeadConnectionWriterStatusQueue() {
+ return this;
+ }
+
+ ::NActor::TQueueInActor<TBusSessionImpl, TRemoteConnectionReaderIncrementalStatus,
+ TStatusTag, TDeadConnectionTag>*
+ GetDeadConnectionReaderStatusQueue() {
+ return this;
+ }
+
+ ::NActor::TQueueInActor<TBusSessionImpl, TAcceptorStatus,
+ TStatusTag, TDeadConnectionTag>*
+ GetDeadAcceptorStatusQueue() {
+ return this;
+ }
+
+ template <typename TItem>
+ ::NActor::IQueueInActor<TItem>* GetQueue() {
+ return this;
+ }
+
+ ui64 LastAcceptorId;
+ ui64 LastConnectionId;
+
+ TAtomic Down;
+ TSystemEvent ShutdownCompleteEvent;
+ };
+
+ inline TBusProtocol* TBusSessionImpl::GetProto() const noexcept {
+ return Proto;
+ }
+
+ inline const TBusSessionConfig* TBusSessionImpl::GetConfig() const noexcept {
+ return &Config;
+ }
+
+ inline TBusMessageQueue* TBusSessionImpl::GetQueue() const noexcept {
+ return Queue;
+ }
+
+ }
+}
diff --git a/library/cpp/messagebus/session_job_count.cpp b/library/cpp/messagebus/session_job_count.cpp
new file mode 100644
index 0000000000..33322b1910
--- /dev/null
+++ b/library/cpp/messagebus/session_job_count.cpp
@@ -0,0 +1,22 @@
+#include "session_job_count.h"
+
+#include <util/system/yassert.h>
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+TBusSessionJobCount::TBusSessionJobCount()
+ : JobCount(0)
+{
+}
+
+TBusSessionJobCount::~TBusSessionJobCount() {
+ Y_VERIFY(JobCount == 0, "must be 0 job count to destroy job");
+}
+
+void TBusSessionJobCount::WaitForZero() {
+ TGuard<TMutex> guard(Mutex);
+ while (AtomicGet(JobCount) > 0) {
+ CondVar.WaitI(Mutex);
+ }
+}
diff --git a/library/cpp/messagebus/session_job_count.h b/library/cpp/messagebus/session_job_count.h
new file mode 100644
index 0000000000..23aca618b1
--- /dev/null
+++ b/library/cpp/messagebus/session_job_count.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <util/system/atomic.h>
+#include <util/system/condvar.h>
+#include <util/system/mutex.h>
+
+namespace NBus {
+ namespace NPrivate {
+ class TBusSessionJobCount {
+ private:
+ TAtomic JobCount;
+
+ TMutex Mutex;
+ TCondVar CondVar;
+
+ public:
+ TBusSessionJobCount();
+ ~TBusSessionJobCount();
+
+ void Add(unsigned delta) {
+ AtomicAdd(JobCount, delta);
+ }
+
+ void Increment() {
+ Add(1);
+ }
+
+ void Decrement() {
+ if (AtomicDecrement(JobCount) == 0) {
+ TGuard<TMutex> guard(Mutex);
+ CondVar.BroadCast();
+ }
+ }
+
+ void WaitForZero();
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/shutdown_state.cpp b/library/cpp/messagebus/shutdown_state.cpp
new file mode 100644
index 0000000000..a4e2bfa8b2
--- /dev/null
+++ b/library/cpp/messagebus/shutdown_state.cpp
@@ -0,0 +1,20 @@
+#include "shutdown_state.h"
+
+#include <util/system/yassert.h>
+
+void TAtomicShutdownState::ShutdownCommand() {
+ Y_VERIFY(State.CompareAndSet(SS_RUNNING, SS_SHUTDOWN_COMMAND));
+}
+
+void TAtomicShutdownState::CompleteShutdown() {
+ Y_VERIFY(State.CompareAndSet(SS_SHUTDOWN_COMMAND, SS_SHUTDOWN_COMPLETE));
+ ShutdownComplete.Signal();
+}
+
+bool TAtomicShutdownState::IsRunning() {
+ return State.Get() == SS_RUNNING;
+}
+
+TAtomicShutdownState::~TAtomicShutdownState() {
+ Y_VERIFY(SS_SHUTDOWN_COMPLETE == State.Get());
+}
diff --git a/library/cpp/messagebus/shutdown_state.h b/library/cpp/messagebus/shutdown_state.h
new file mode 100644
index 0000000000..86bd7110ae
--- /dev/null
+++ b/library/cpp/messagebus/shutdown_state.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "misc/atomic_box.h"
+
+#include <util/system/event.h>
+
+enum EShutdownState {
+ SS_RUNNING,
+ SS_SHUTDOWN_COMMAND,
+ SS_SHUTDOWN_COMPLETE,
+};
+
+struct TAtomicShutdownState {
+ TAtomicBox<EShutdownState> State;
+ TSystemEvent ShutdownComplete;
+
+ void ShutdownCommand();
+ void CompleteShutdown();
+ bool IsRunning();
+
+ ~TAtomicShutdownState();
+};
diff --git a/library/cpp/messagebus/socket_addr.cpp b/library/cpp/messagebus/socket_addr.cpp
new file mode 100644
index 0000000000..c1b3a28fbe
--- /dev/null
+++ b/library/cpp/messagebus/socket_addr.cpp
@@ -0,0 +1,79 @@
+#include "socket_addr.h"
+
+#include "netaddr.h"
+
+#include <util/network/address.h>
+#include <util/network/init.h>
+#include <util/system/yassert.h>
+
+using namespace NAddr;
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+static_assert(ADDR_UNSPEC == 0, "expect ADDR_UNSPEC == 0");
+
+NBus::NPrivate::TBusSocketAddr::TBusSocketAddr(const NAddr::IRemoteAddr* addr)
+ : IPv6ScopeID(0)
+{
+ const sockaddr* sa = addr->Addr();
+
+ switch ((EAddrFamily)sa->sa_family) {
+ case AF_UNSPEC: {
+ IpAddr.Clear();
+ Port = 0;
+ break;
+ }
+ case AF_INET: {
+ IpAddr.SetInAddr(((const sockaddr_in*)sa)->sin_addr);
+ Port = InetToHost(((const sockaddr_in*)sa)->sin_port);
+ break;
+ }
+ case AF_INET6: {
+ IpAddr.SetIn6Addr(((const sockaddr_in6*)sa)->sin6_addr);
+ Port = InetToHost(((const sockaddr_in*)sa)->sin_port);
+ IPv6ScopeID = InetToHost(((const sockaddr_in6*)sa)->sin6_scope_id);
+ break;
+ }
+ default:
+ Y_FAIL("unknown address family");
+ }
+}
+
+NBus::NPrivate::TBusSocketAddr::TBusSocketAddr(TStringBuf host, unsigned port) {
+ *this = TNetAddr(host, port);
+}
+
+NBus::NPrivate::TBusSocketAddr::TBusSocketAddr(const TNetAddr& addr) {
+ *this = TBusSocketAddr(&addr);
+}
+
+TNetAddr NBus::NPrivate::TBusSocketAddr::ToNetAddr() const {
+ sockaddr_storage storage;
+ Zero(storage);
+
+ storage.ss_family = (ui16)IpAddr.GetAddrFamily();
+
+ switch (IpAddr.GetAddrFamily()) {
+ case ADDR_UNSPEC:
+ return TNetAddr();
+ case ADDR_IPV4: {
+ ((sockaddr_in*)&storage)->sin_addr = IpAddr.GetInAddr();
+ ((sockaddr_in*)&storage)->sin_port = HostToInet(Port);
+ break;
+ }
+ case ADDR_IPV6: {
+ ((sockaddr_in6*)&storage)->sin6_addr = IpAddr.GetIn6Addr();
+ ((sockaddr_in6*)&storage)->sin6_port = HostToInet(Port);
+ ((sockaddr_in6*)&storage)->sin6_scope_id = HostToInet(IPv6ScopeID);
+ break;
+ }
+ }
+
+ return TNetAddr(new TOpaqueAddr((sockaddr*)&storage));
+}
+
+template <>
+void Out<TBusSocketAddr>(IOutputStream& out, const TBusSocketAddr& addr) {
+ out << addr.ToNetAddr();
+}
diff --git a/library/cpp/messagebus/socket_addr.h b/library/cpp/messagebus/socket_addr.h
new file mode 100644
index 0000000000..959eafe689
--- /dev/null
+++ b/library/cpp/messagebus/socket_addr.h
@@ -0,0 +1,113 @@
+#pragma once
+
+#include "hash.h"
+
+#include <util/generic/hash.h>
+#include <util/generic/utility.h>
+#include <util/network/address.h>
+#include <util/network/init.h>
+
+#include <string.h>
+
+namespace NBus {
+ class TNetAddr;
+}
+
+namespace NBus {
+ namespace NPrivate {
+ enum EAddrFamily {
+ ADDR_UNSPEC = AF_UNSPEC,
+ ADDR_IPV4 = AF_INET,
+ ADDR_IPV6 = AF_INET6,
+ };
+
+ class TBusIpAddr {
+ private:
+ EAddrFamily Af;
+
+ union {
+ in_addr In4;
+ in6_addr In6;
+ };
+
+ public:
+ TBusIpAddr() {
+ Clear();
+ }
+
+ EAddrFamily GetAddrFamily() const {
+ return Af;
+ }
+
+ void Clear() {
+ Zero(*this);
+ }
+
+ in_addr GetInAddr() const {
+ Y_ASSERT(Af == ADDR_IPV4);
+ return In4;
+ }
+
+ void SetInAddr(const in_addr& in4) {
+ Clear();
+ Af = ADDR_IPV4;
+ In4 = in4;
+ }
+
+ in6_addr GetIn6Addr() const {
+ Y_ASSERT(Af == ADDR_IPV6);
+ return In6;
+ }
+
+ void SetIn6Addr(const in6_addr& in6) {
+ Clear();
+ Af = ADDR_IPV6;
+ In6 = in6;
+ }
+
+ bool operator==(const TBusIpAddr& that) const {
+ return memcmp(this, &that, sizeof(that)) == 0;
+ }
+ };
+
+ class TBusSocketAddr {
+ public:
+ TBusIpAddr IpAddr;
+ ui16 Port;
+
+ //Only makes sense for IPv6 link-local addresses
+ ui32 IPv6ScopeID;
+
+ TBusSocketAddr()
+ : Port(0)
+ , IPv6ScopeID(0)
+ {
+ }
+
+ TBusSocketAddr(const NAddr::IRemoteAddr*);
+ TBusSocketAddr(const TNetAddr&);
+ TBusSocketAddr(TStringBuf host, unsigned port);
+
+ TNetAddr ToNetAddr() const;
+
+ bool operator==(const TBusSocketAddr& that) const {
+ return IpAddr == that.IpAddr && Port == that.Port;
+ }
+ };
+
+ }
+}
+
+template <>
+struct THash<NBus::NPrivate::TBusIpAddr> {
+ inline size_t operator()(const NBus::NPrivate::TBusIpAddr& a) const {
+ return ComputeHash(TStringBuf((const char*)&a, sizeof(a)));
+ }
+};
+
+template <>
+struct THash<NBus::NPrivate::TBusSocketAddr> {
+ inline size_t operator()(const NBus::NPrivate::TBusSocketAddr& a) const {
+ return HashValues(a.IpAddr, a.Port);
+ }
+};
diff --git a/library/cpp/messagebus/socket_addr_ut.cpp b/library/cpp/messagebus/socket_addr_ut.cpp
new file mode 100644
index 0000000000..783bb62a86
--- /dev/null
+++ b/library/cpp/messagebus/socket_addr_ut.cpp
@@ -0,0 +1,15 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "netaddr.h"
+#include "socket_addr.h"
+
+#include <util/string/cast.h>
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+Y_UNIT_TEST_SUITE(TBusSocketAddr) {
+ Y_UNIT_TEST(Simple) {
+ UNIT_ASSERT_VALUES_EQUAL(TString("127.0.0.1:80"), ToString(TBusSocketAddr("127.0.0.1", 80)));
+ }
+}
diff --git a/library/cpp/messagebus/storage.cpp b/library/cpp/messagebus/storage.cpp
new file mode 100644
index 0000000000..efefc87340
--- /dev/null
+++ b/library/cpp/messagebus/storage.cpp
@@ -0,0 +1,161 @@
+#include "storage.h"
+
+#include <typeinfo>
+
+namespace NBus {
+ namespace NPrivate {
+ TTimedMessages::TTimedMessages() {
+ }
+
+ TTimedMessages::~TTimedMessages() {
+ Y_VERIFY(Items.empty());
+ }
+
+ void TTimedMessages::PushBack(TNonDestroyingAutoPtr<TBusMessage> m) {
+ TItem i;
+ i.Message.Reset(m.Release());
+ Items.push_back(i);
+ }
+
+ TNonDestroyingAutoPtr<TBusMessage> TTimedMessages::PopFront() {
+ TBusMessage* r = nullptr;
+ if (!Items.empty()) {
+ r = Items.front()->Message.Release();
+ Items.pop_front();
+ }
+ return r;
+ }
+
+ bool TTimedMessages::Empty() const {
+ return Items.empty();
+ }
+
+ size_t TTimedMessages::Size() const {
+ return Items.size();
+ }
+
+ void TTimedMessages::Timeout(TInstant before, TMessagesPtrs* r) {
+ // shortcut
+ if (before == TInstant::Max()) {
+ Clear(r);
+ return;
+ }
+
+ while (!Items.empty()) {
+ TItem& i = *Items.front();
+ if (TInstant::MilliSeconds(i.Message->GetHeader()->SendTime) > before) {
+ break;
+ }
+ r->push_back(i.Message.Release());
+ Items.pop_front();
+ }
+ }
+
+ void TTimedMessages::Clear(TMessagesPtrs* r) {
+ while (!Items.empty()) {
+ r->push_back(Items.front()->Message.Release());
+ Items.pop_front();
+ }
+ }
+
+ TSyncAckMessages::TSyncAckMessages() {
+ KeyToMessage.set_empty_key(0);
+ KeyToMessage.set_deleted_key(1);
+ }
+
+ TSyncAckMessages::~TSyncAckMessages() {
+ Y_VERIFY(KeyToMessage.empty());
+ Y_VERIFY(TimedItems.empty());
+ }
+
+ void TSyncAckMessages::Push(TBusMessagePtrAndHeader& m) {
+ // Perform garbage collection if `TimedMessages` contain too many junk data
+ if (TimedItems.size() > 1000 && TimedItems.size() > KeyToMessage.size() * 4) {
+ Gc();
+ }
+
+ TValue value = {m.MessagePtr.Release()};
+
+ std::pair<TKeyToMessage::iterator, bool> p = KeyToMessage.insert(TKeyToMessage::value_type(m.Header.Id, value));
+ Y_VERIFY(p.second, "non-unique id; %s", value.Message->Describe().data());
+
+ TTimedItem item = {m.Header.Id, m.Header.SendTime};
+ TimedItems.push_back(item);
+ }
+
+ TBusMessage* TSyncAckMessages::Pop(TBusKey id) {
+ TKeyToMessage::iterator it = KeyToMessage.find(id);
+ if (it == KeyToMessage.end()) {
+ return nullptr;
+ }
+ TValue v = it->second;
+ KeyToMessage.erase(it);
+
+ // `TimedMessages` still contain record about this message
+
+ return v.Message;
+ }
+
+ void TSyncAckMessages::Timeout(TInstant before, TMessagesPtrs* r) {
+ // shortcut
+ if (before == TInstant::Max()) {
+ Clear(r);
+ return;
+ }
+
+ Y_ASSERT(r->empty());
+
+ while (!TimedItems.empty()) {
+ TTimedItem i = TimedItems.front();
+ if (TInstant::MilliSeconds(i.SendTime) > before) {
+ break;
+ }
+
+ TKeyToMessage::iterator itMessage = KeyToMessage.find(i.Key);
+
+ if (itMessage != KeyToMessage.end()) {
+ r->push_back(itMessage->second.Message);
+ KeyToMessage.erase(itMessage);
+ }
+
+ TimedItems.pop_front();
+ }
+ }
+
+ void TSyncAckMessages::Clear(TMessagesPtrs* r) {
+ for (TKeyToMessage::const_iterator i = KeyToMessage.begin(); i != KeyToMessage.end(); ++i) {
+ r->push_back(i->second.Message);
+ }
+
+ KeyToMessage.clear();
+ TimedItems.clear();
+ }
+
+ void TSyncAckMessages::Gc() {
+ TDeque<TTimedItem> tmp;
+
+ for (auto& timedItem : TimedItems) {
+ if (KeyToMessage.find(timedItem.Key) == KeyToMessage.end()) {
+ continue;
+ }
+ tmp.push_back(timedItem);
+ }
+
+ TimedItems.swap(tmp);
+ }
+
+ void TSyncAckMessages::RemoveAll(const TMessagesPtrs& messages) {
+ for (auto message : messages) {
+ TKeyToMessage::iterator it = KeyToMessage.find(message->GetHeader()->Id);
+ Y_VERIFY(it != KeyToMessage.end(), "delete non-existent message");
+ KeyToMessage.erase(it);
+ }
+ }
+
+ void TSyncAckMessages::DumpState() {
+ Cerr << TimedItems.size() << Endl;
+ Cerr << KeyToMessage.size() << Endl;
+ }
+
+ }
+}
diff --git a/library/cpp/messagebus/storage.h b/library/cpp/messagebus/storage.h
new file mode 100644
index 0000000000..7d168844ed
--- /dev/null
+++ b/library/cpp/messagebus/storage.h
@@ -0,0 +1,94 @@
+#pragma once
+
+#include "message_ptr_and_header.h"
+#include "moved.h"
+#include "ybus.h"
+
+#include <contrib/libs/sparsehash/src/sparsehash/dense_hash_map>
+
+#include <util/generic/deque.h>
+#include <util/generic/noncopyable.h>
+#include <util/generic/utility.h>
+
+namespace NBus {
+ namespace NPrivate {
+ typedef TVector<TBusMessage*> TMessagesPtrs;
+
+ class TTimedMessages {
+ public:
+ TTimedMessages();
+ ~TTimedMessages();
+
+ struct TItem {
+ THolder<TBusMessage> Message;
+
+ void Swap(TItem& that) {
+ DoSwap(Message, that.Message);
+ }
+ };
+
+ typedef TDeque<TMoved<TItem>> TItems;
+
+ void PushBack(TNonDestroyingAutoPtr<TBusMessage> m);
+ TNonDestroyingAutoPtr<TBusMessage> PopFront();
+ bool Empty() const;
+ size_t Size() const;
+
+ void Timeout(TInstant before, TMessagesPtrs* r);
+ void Clear(TMessagesPtrs* r);
+
+ private:
+ TItems Items;
+ };
+
+ class TSyncAckMessages : TNonCopyable {
+ public:
+ TSyncAckMessages();
+ ~TSyncAckMessages();
+
+ void Push(TBusMessagePtrAndHeader& m);
+ TBusMessage* Pop(TBusKey id);
+
+ void Timeout(TInstant before, TMessagesPtrs* r);
+
+ void Clear(TMessagesPtrs* r);
+
+ size_t Size() const {
+ return KeyToMessage.size();
+ }
+
+ void RemoveAll(const TMessagesPtrs&);
+
+ void Gc();
+
+ void DumpState();
+
+ private:
+ struct TTimedItem {
+ TBusKey Key;
+ TBusInstant SendTime;
+ };
+
+ typedef TDeque<TTimedItem> TTimedItems;
+ typedef TDeque<TTimedItem>::iterator TTimedIterator;
+
+ TTimedItems TimedItems;
+
+ struct TValue {
+ TBusMessage* Message;
+ };
+
+ // keys are already random, no need to hash them further
+ struct TIdHash {
+ size_t operator()(TBusKey value) const {
+ return value;
+ }
+ };
+
+ typedef google::dense_hash_map<TBusKey, TValue, TIdHash> TKeyToMessage;
+
+ TKeyToMessage KeyToMessage;
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/synchandler.cpp b/library/cpp/messagebus/synchandler.cpp
new file mode 100644
index 0000000000..8e891d66b3
--- /dev/null
+++ b/library/cpp/messagebus/synchandler.cpp
@@ -0,0 +1,198 @@
+#include "remote_client_session.h"
+#include "remote_connection.h"
+#include "ybus.h"
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+
+/////////////////////////////////////////////////////////////////
+/// Object that encapsulates all messgae data required for sending
+/// a message synchronously and receiving a reply. It includes:
+/// 1. ConditionVariable to wait on message reply
+/// 2. Lock used by condition variable
+/// 3. Message reply
+/// 4. Reply status
+struct TBusSyncMessageData {
+ TCondVar ReplyEvent;
+ TMutex ReplyLock;
+ TBusMessage* Reply;
+ EMessageStatus ReplyStatus;
+
+ TBusSyncMessageData()
+ : Reply(nullptr)
+ , ReplyStatus(MESSAGE_DONT_ASK)
+ {
+ }
+};
+
+class TSyncHandler: public IBusClientHandler {
+public:
+ TSyncHandler(bool expectReply = true)
+ : ExpectReply(expectReply)
+ , Session(nullptr)
+ {
+ }
+ ~TSyncHandler() override {
+ }
+
+ void OnReply(TAutoPtr<TBusMessage> pMessage0, TAutoPtr<TBusMessage> pReply0) override {
+ TBusMessage* pMessage = pMessage0.Release();
+ TBusMessage* pReply = pReply0.Release();
+
+ if (!ExpectReply) { // Maybe need VERIFY, but it will be better to support backward compatibility here.
+ return;
+ }
+
+ TBusSyncMessageData* data = static_cast<TBusSyncMessageData*>(pMessage->Data);
+ SignalResult(data, pReply, MESSAGE_OK);
+ }
+
+ void OnError(TAutoPtr<TBusMessage> pMessage0, EMessageStatus status) override {
+ TBusMessage* pMessage = pMessage0.Release();
+ TBusSyncMessageData* data = static_cast<TBusSyncMessageData*>(pMessage->Data);
+ if (!data) {
+ return;
+ }
+
+ SignalResult(data, /*pReply=*/nullptr, status);
+ }
+
+ void OnMessageSent(TBusMessage* pMessage) override {
+ Y_UNUSED(pMessage);
+ Y_ASSERT(ExpectReply);
+ }
+
+ void OnMessageSentOneWay(TAutoPtr<TBusMessage> pMessage) override {
+ Y_ASSERT(!ExpectReply);
+ TBusSyncMessageData* data = static_cast<TBusSyncMessageData*>(pMessage.Release()->Data);
+ SignalResult(data, /*pReply=*/nullptr, MESSAGE_OK);
+ }
+
+ void SetSession(TRemoteClientSession* session) {
+ if (!ExpectReply) {
+ Session = session;
+ }
+ }
+
+private:
+ void SignalResult(TBusSyncMessageData* data, TBusMessage* pReply, EMessageStatus status) const {
+ Y_VERIFY(data, "Message data is set to NULL.");
+ TGuard<TMutex> G(data->ReplyLock);
+ data->Reply = pReply;
+ data->ReplyStatus = status;
+ data->ReplyEvent.Signal();
+ }
+
+private:
+ // This is weird, because in regular client one-way-ness is selected per call, not per session.
+ bool ExpectReply;
+ TRemoteClientSession* Session;
+};
+
+namespace NBus {
+ namespace NPrivate {
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4250) // 'NBus::NPrivate::TRemoteClientSession' : inherits 'NBus::NPrivate::TBusSessionImpl::NBus::NPrivate::TBusSessionImpl::GetConfig' via dominance
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ class TBusSyncSourceSessionImpl
+ : private TSyncHandler
+ // TODO: do not extend TRemoteClientSession
+ ,
+ public TRemoteClientSession {
+ private:
+ bool NeedReply;
+
+ public:
+ TBusSyncSourceSessionImpl(TBusMessageQueue* queue, TBusProtocol* proto, const TBusClientSessionConfig& config, bool needReply, const TString& name)
+ : TSyncHandler(needReply)
+ , TRemoteClientSession(queue, proto, this, config, name)
+ , NeedReply(needReply)
+ {
+ SetSession(this);
+ }
+
+ TBusMessage* SendSyncMessage(TBusMessage* pMessage, EMessageStatus& status, const TNetAddr* addr = nullptr) {
+ Y_VERIFY(!Queue->GetExecutor()->IsInExecutorThread(),
+ "SendSyncMessage must not be called from executor thread");
+
+ TBusMessage* reply = nullptr;
+ THolder<TBusSyncMessageData> data(new TBusSyncMessageData());
+
+ pMessage->Data = data.Get();
+
+ {
+ TGuard<TMutex> G(data->ReplyLock);
+ if (NeedReply) {
+ status = SendMessage(pMessage, addr, false); // probably should be true
+ } else {
+ status = SendMessageOneWay(pMessage, addr);
+ }
+
+ if (status == MESSAGE_OK) {
+ data->ReplyEvent.Wait(data->ReplyLock);
+ TBusSyncMessageData* rdata = static_cast<TBusSyncMessageData*>(pMessage->Data);
+ Y_VERIFY(rdata == data.Get(), "Message data pointer should not be modified.");
+ reply = rdata->Reply;
+ status = rdata->ReplyStatus;
+ }
+ }
+
+ // deletion of message and reply is a job of application.
+ pMessage->Data = nullptr;
+
+ return reply;
+ }
+ };
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+ }
+}
+
+TBusSyncSourceSession::TBusSyncSourceSession(TIntrusivePtr< ::NBus::NPrivate::TBusSyncSourceSessionImpl> session)
+ : Session(session)
+{
+}
+
+TBusSyncSourceSession::~TBusSyncSourceSession() {
+ Shutdown();
+}
+
+void TBusSyncSourceSession::Shutdown() {
+ Session->Shutdown();
+}
+
+TBusMessage* TBusSyncSourceSession::SendSyncMessage(TBusMessage* pMessage, EMessageStatus& status, const TNetAddr* addr) {
+ return Session->SendSyncMessage(pMessage, status, addr);
+}
+
+int TBusSyncSourceSession::RegisterService(const char* hostname, TBusKey start, TBusKey end, EIpVersion ipVersion) {
+ return Session->RegisterService(hostname, start, end, ipVersion);
+}
+
+int TBusSyncSourceSession::GetInFlight() {
+ return Session->GetInFlight();
+}
+
+const TBusProtocol* TBusSyncSourceSession::GetProto() const {
+ return Session->GetProto();
+}
+
+const TBusClientSession* TBusSyncSourceSession::GetBusClientSessionWorkaroundDoNotUse() const {
+ return Session.Get();
+}
+
+TBusSyncClientSessionPtr TBusMessageQueue::CreateSyncSource(TBusProtocol* proto, const TBusClientSessionConfig& config, bool needReply, const TString& name) {
+ TIntrusivePtr<TBusSyncSourceSessionImpl> session = new TBusSyncSourceSessionImpl(this, proto, config, needReply, name);
+ Add(session.Get());
+ return new TBusSyncSourceSession(session);
+}
+
+void TBusMessageQueue::Destroy(TBusSyncClientSessionPtr session) {
+ Destroy(session->Session.Get());
+ Y_UNUSED(session->Session.Release());
+}
diff --git a/library/cpp/messagebus/test/TestMessageBus.py b/library/cpp/messagebus/test/TestMessageBus.py
new file mode 100644
index 0000000000..0bbaa0a313
--- /dev/null
+++ b/library/cpp/messagebus/test/TestMessageBus.py
@@ -0,0 +1,8 @@
+from devtools.fleur.ytest import group, constraint
+from devtools.fleur.ytest.integration import UnitTestGroup
+
+@group
+@constraint('library.messagebus')
+class TestMessageBus(UnitTestGroup):
+ def __init__(self, context):
+ UnitTestGroup.__init__(self, context, 'MessageBus', 'library-messagebus-test-ut')
diff --git a/library/cpp/messagebus/test/example/client/client.cpp b/library/cpp/messagebus/test/example/client/client.cpp
new file mode 100644
index 0000000000..89b5f2c9be
--- /dev/null
+++ b/library/cpp/messagebus/test/example/client/client.cpp
@@ -0,0 +1,81 @@
+#include <library/cpp/messagebus/test/example/common/proto.h>
+
+#include <util/random/random.h>
+
+using namespace NBus;
+using namespace NCalculator;
+
+namespace NCalculator {
+ struct TCalculatorClient: public IBusClientHandler {
+ TCalculatorProtocol Proto;
+ TBusMessageQueuePtr MessageQueue;
+ TBusClientSessionPtr ClientSession;
+
+ TCalculatorClient() {
+ MessageQueue = CreateMessageQueue();
+ TBusClientSessionConfig config;
+ config.TotalTimeout = 2 * 1000;
+ ClientSession = TBusClientSession::Create(&Proto, this, config, MessageQueue);
+ }
+
+ ~TCalculatorClient() override {
+ MessageQueue->Stop();
+ }
+
+ void OnReply(TAutoPtr<TBusMessage> request, TAutoPtr<TBusMessage> response0) override {
+ Y_VERIFY(response0->GetHeader()->Type == TResponse::MessageType, "wrong response");
+ TResponse* response = VerifyDynamicCast<TResponse*>(response0.Get());
+ if (request->GetHeader()->Type == TRequestSum::MessageType) {
+ TRequestSum* requestSum = VerifyDynamicCast<TRequestSum*>(request.Get());
+ int a = requestSum->Record.GetA();
+ int b = requestSum->Record.GetB();
+ Cerr << a << " + " << b << " = " << response->Record.GetResult() << "\n";
+ } else if (request->GetHeader()->Type == TRequestMul::MessageType) {
+ TRequestMul* requestMul = VerifyDynamicCast<TRequestMul*>(request.Get());
+ int a = requestMul->Record.GetA();
+ int b = requestMul->Record.GetB();
+ Cerr << a << " * " << b << " = " << response->Record.GetResult() << "\n";
+ } else {
+ Y_FAIL("unknown request");
+ }
+ }
+
+ void OnError(TAutoPtr<TBusMessage>, EMessageStatus status) override {
+ Cerr << "got error " << status << "\n";
+ }
+ };
+
+}
+
+int main(int, char**) {
+ TCalculatorClient client;
+
+ for (;;) {
+ TNetAddr addr(TNetAddr("127.0.0.1", TCalculatorProtocol().GetPort()));
+
+ int a = RandomNumber<unsigned>(10);
+ int b = RandomNumber<unsigned>(10);
+ EMessageStatus ok;
+ if (RandomNumber<bool>()) {
+ TAutoPtr<TRequestSum> request(new TRequestSum);
+ request->Record.SetA(a);
+ request->Record.SetB(b);
+ Cerr << "sending " << a << " + " << b << "\n";
+ ok = client.ClientSession->SendMessageAutoPtr(request, &addr);
+ } else {
+ TAutoPtr<TRequestMul> request(new TRequestMul);
+ request->Record.SetA(a);
+ request->Record.SetB(b);
+ Cerr << "sending " << a << " * " << b << "\n";
+ ok = client.ClientSession->SendMessageAutoPtr(request, &addr);
+ }
+
+ if (ok != MESSAGE_OK) {
+ Cerr << "failed to send message " << ok << "\n";
+ }
+
+ Sleep(TDuration::Seconds(1));
+ }
+
+ return 0;
+}
diff --git a/library/cpp/messagebus/test/example/client/ya.make b/library/cpp/messagebus/test/example/client/ya.make
new file mode 100644
index 0000000000..a660a01698
--- /dev/null
+++ b/library/cpp/messagebus/test/example/client/ya.make
@@ -0,0 +1,13 @@
+PROGRAM(messagebus_example_client)
+
+OWNER(g:messagebus)
+
+PEERDIR(
+ library/cpp/messagebus/test/example/common
+)
+
+SRCS(
+ client.cpp
+)
+
+END()
diff --git a/library/cpp/messagebus/test/example/common/messages.proto b/library/cpp/messagebus/test/example/common/messages.proto
new file mode 100644
index 0000000000..16b858fc77
--- /dev/null
+++ b/library/cpp/messagebus/test/example/common/messages.proto
@@ -0,0 +1,15 @@
+package NCalculator;
+
+message TRequestSumRecord {
+ required int32 A = 1;
+ required int32 B = 2;
+}
+
+message TRequestMulRecord {
+ required int32 A = 1;
+ required int32 B = 2;
+}
+
+message TResponseRecord {
+ required int32 Result = 1;
+}
diff --git a/library/cpp/messagebus/test/example/common/proto.cpp b/library/cpp/messagebus/test/example/common/proto.cpp
new file mode 100644
index 0000000000..1d18aa77ea
--- /dev/null
+++ b/library/cpp/messagebus/test/example/common/proto.cpp
@@ -0,0 +1,12 @@
+#include "proto.h"
+
+using namespace NCalculator;
+using namespace NBus;
+
+TCalculatorProtocol::TCalculatorProtocol()
+ : TBusBufferProtocol("Calculator", 34567)
+{
+ RegisterType(new TRequestSum);
+ RegisterType(new TRequestMul);
+ RegisterType(new TResponse);
+}
diff --git a/library/cpp/messagebus/test/example/common/proto.h b/library/cpp/messagebus/test/example/common/proto.h
new file mode 100644
index 0000000000..a151aac468
--- /dev/null
+++ b/library/cpp/messagebus/test/example/common/proto.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <library/cpp/messagebus/test/example/common/messages.pb.h>
+
+#include <library/cpp/messagebus/ybus.h>
+#include <library/cpp/messagebus/protobuf/ybusbuf.h>
+
+namespace NCalculator {
+ typedef ::NBus::TBusBufferMessage<TRequestSumRecord, 1> TRequestSum;
+ typedef ::NBus::TBusBufferMessage<TRequestMulRecord, 2> TRequestMul;
+ typedef ::NBus::TBusBufferMessage<TResponseRecord, 3> TResponse;
+
+ struct TCalculatorProtocol: public ::NBus::TBusBufferProtocol {
+ TCalculatorProtocol();
+ };
+
+}
diff --git a/library/cpp/messagebus/test/example/common/ya.make b/library/cpp/messagebus/test/example/common/ya.make
new file mode 100644
index 0000000000..4da16608fc
--- /dev/null
+++ b/library/cpp/messagebus/test/example/common/ya.make
@@ -0,0 +1,15 @@
+LIBRARY(messagebus_test_example_common)
+
+OWNER(g:messagebus)
+
+PEERDIR(
+ library/cpp/messagebus
+ library/cpp/messagebus/protobuf
+)
+
+SRCS(
+ proto.cpp
+ messages.proto
+)
+
+END()
diff --git a/library/cpp/messagebus/test/example/server/server.cpp b/library/cpp/messagebus/test/example/server/server.cpp
new file mode 100644
index 0000000000..13e52d75f5
--- /dev/null
+++ b/library/cpp/messagebus/test/example/server/server.cpp
@@ -0,0 +1,58 @@
+#include <library/cpp/messagebus/test/example/common/proto.h>
+
+using namespace NBus;
+using namespace NCalculator;
+
+namespace NCalculator {
+ struct TCalculatorServer: public IBusServerHandler {
+ TCalculatorProtocol Proto;
+ TBusMessageQueuePtr MessageQueue;
+ TBusServerSessionPtr ServerSession;
+
+ TCalculatorServer() {
+ MessageQueue = CreateMessageQueue();
+ TBusServerSessionConfig config;
+ ServerSession = TBusServerSession::Create(&Proto, this, config, MessageQueue);
+ }
+
+ ~TCalculatorServer() override {
+ MessageQueue->Stop();
+ }
+
+ void OnMessage(TOnMessageContext& request) override {
+ if (request.GetMessage()->GetHeader()->Type == TRequestSum::MessageType) {
+ TRequestSum* requestSum = VerifyDynamicCast<TRequestSum*>(request.GetMessage());
+ int a = requestSum->Record.GetA();
+ int b = requestSum->Record.GetB();
+ int result = a + b;
+ Cerr << "requested " << a << " + " << b << ", sending " << result << "\n";
+ TAutoPtr<TResponse> response(new TResponse);
+ response->Record.SetResult(result);
+ request.SendReplyMove(response);
+ } else if (request.GetMessage()->GetHeader()->Type == TRequestMul::MessageType) {
+ TRequestMul* requestMul = VerifyDynamicCast<TRequestMul*>(request.GetMessage());
+ int a = requestMul->Record.GetA();
+ int b = requestMul->Record.GetB();
+ int result = a * b;
+ Cerr << "requested " << a << " * " << b << ", sending " << result << "\n";
+ TAutoPtr<TResponse> response(new TResponse);
+ response->Record.SetResult(result);
+ request.SendReplyMove(response);
+ } else {
+ Y_FAIL("unknown request");
+ }
+ }
+ };
+}
+
+int main(int, char**) {
+ TCalculatorServer server;
+
+ Cerr << "listening on port " << server.ServerSession->GetActualListenPort() << "\n";
+
+ for (;;) {
+ Sleep(TDuration::Seconds(1));
+ }
+
+ return 0;
+}
diff --git a/library/cpp/messagebus/test/example/server/ya.make b/library/cpp/messagebus/test/example/server/ya.make
new file mode 100644
index 0000000000..8cdd97cb12
--- /dev/null
+++ b/library/cpp/messagebus/test/example/server/ya.make
@@ -0,0 +1,13 @@
+PROGRAM(messagebus_example_server)
+
+OWNER(g:messagebus)
+
+PEERDIR(
+ library/cpp/messagebus/test/example/common
+)
+
+SRCS(
+ server.cpp
+)
+
+END()
diff --git a/library/cpp/messagebus/test/example/ya.make b/library/cpp/messagebus/test/example/ya.make
new file mode 100644
index 0000000000..f275351c29
--- /dev/null
+++ b/library/cpp/messagebus/test/example/ya.make
@@ -0,0 +1,7 @@
+OWNER(g:messagebus)
+
+RECURSE(
+ client
+ common
+ server
+)
diff --git a/library/cpp/messagebus/test/helper/alloc_counter.h b/library/cpp/messagebus/test/helper/alloc_counter.h
new file mode 100644
index 0000000000..ec9041cb15
--- /dev/null
+++ b/library/cpp/messagebus/test/helper/alloc_counter.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <util/generic/noncopyable.h>
+#include <util/system/atomic.h>
+#include <util/system/yassert.h>
+
+class TAllocCounter : TNonCopyable {
+private:
+ TAtomic* CountPtr;
+
+public:
+ TAllocCounter(TAtomic* countPtr)
+ : CountPtr(countPtr)
+ {
+ AtomicIncrement(*CountPtr);
+ }
+
+ ~TAllocCounter() {
+ Y_VERIFY(AtomicDecrement(*CountPtr) >= 0, "released too many");
+ }
+};
diff --git a/library/cpp/messagebus/test/helper/example.cpp b/library/cpp/messagebus/test/helper/example.cpp
new file mode 100644
index 0000000000..7c6d704042
--- /dev/null
+++ b/library/cpp/messagebus/test/helper/example.cpp
@@ -0,0 +1,281 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "example.h"
+
+#include <util/generic/cast.h>
+
+using namespace NBus;
+using namespace NBus::NTest;
+
+static void FillWithJunk(TArrayRef<char> data) {
+ TStringBuf junk =
+ "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890123456789012345678901234567890123456789";
+
+ for (size_t i = 0; i < data.size(); i += junk.size()) {
+ memcpy(data.data() + i, junk.data(), Min(junk.size(), data.size() - i));
+ }
+}
+
+static TString JunkString(size_t len) {
+ TTempBuf temp(len);
+ TArrayRef<char> tempArrayRef(temp.Data(), len);
+ FillWithJunk(tempArrayRef);
+
+ return TString(tempArrayRef.data(), tempArrayRef.size());
+}
+
+TExampleRequest::TExampleRequest(TAtomic* counterPtr, size_t payloadSize)
+ : TBusMessage(77)
+ , AllocCounter(counterPtr)
+ , Data(JunkString(payloadSize))
+{
+}
+
+TExampleRequest::TExampleRequest(ECreateUninitialized, TAtomic* counterPtr)
+ : TBusMessage(MESSAGE_CREATE_UNINITIALIZED)
+ , AllocCounter(counterPtr)
+{
+}
+
+TExampleResponse::TExampleResponse(TAtomic* counterPtr, size_t payloadSize)
+ : TBusMessage(79)
+ , AllocCounter(counterPtr)
+ , Data(JunkString(payloadSize))
+{
+}
+
+TExampleResponse::TExampleResponse(ECreateUninitialized, TAtomic* counterPtr)
+ : TBusMessage(MESSAGE_CREATE_UNINITIALIZED)
+ , AllocCounter(counterPtr)
+{
+}
+
+TExampleProtocol::TExampleProtocol(int port)
+ : TBusProtocol("Example", port)
+ , RequestCount(0)
+ , ResponseCount(0)
+ , RequestCountDeserialized(0)
+ , ResponseCountDeserialized(0)
+ , StartCount(0)
+{
+}
+
+TExampleProtocol::~TExampleProtocol() {
+ if (UncaughtException()) {
+ // so it could be reported in test
+ return;
+ }
+ Y_VERIFY(0 == AtomicGet(RequestCount), "protocol %s: must be 0 requests allocated, actually %d", GetService(), int(RequestCount));
+ Y_VERIFY(0 == AtomicGet(ResponseCount), "protocol %s: must be 0 responses allocated, actually %d", GetService(), int(ResponseCount));
+ Y_VERIFY(0 == AtomicGet(RequestCountDeserialized), "protocol %s: must be 0 requests deserialized allocated, actually %d", GetService(), int(RequestCountDeserialized));
+ Y_VERIFY(0 == AtomicGet(ResponseCountDeserialized), "protocol %s: must be 0 responses deserialized allocated, actually %d", GetService(), int(ResponseCountDeserialized));
+ Y_VERIFY(0 == AtomicGet(StartCount), "protocol %s: must be 0 start objects allocated, actually %d", GetService(), int(StartCount));
+}
+
+void TExampleProtocol::Serialize(const TBusMessage* message, TBuffer& buffer) {
+ // Messages have no data, we recreate them from scratch
+ // instead of sending, so we don't need to serialize them.
+ if (const TExampleRequest* exampleMessage = dynamic_cast<const TExampleRequest*>(message)) {
+ buffer.Append(exampleMessage->Data.data(), exampleMessage->Data.size());
+ } else if (const TExampleResponse* exampleReply = dynamic_cast<const TExampleResponse*>(message)) {
+ buffer.Append(exampleReply->Data.data(), exampleReply->Data.size());
+ } else {
+ Y_FAIL("unknown message type");
+ }
+}
+
+TAutoPtr<TBusMessage> TExampleProtocol::Deserialize(ui16 messageType, TArrayRef<const char> payload) {
+ // TODO: check data
+ Y_UNUSED(payload);
+
+ if (messageType == 77) {
+ TExampleRequest* exampleMessage = new TExampleRequest(MESSAGE_CREATE_UNINITIALIZED, &RequestCountDeserialized);
+ exampleMessage->Data.append(payload.data(), payload.size());
+ return exampleMessage;
+ } else if (messageType == 79) {
+ TExampleResponse* exampleReply = new TExampleResponse(MESSAGE_CREATE_UNINITIALIZED, &ResponseCountDeserialized);
+ exampleReply->Data.append(payload.data(), payload.size());
+ return exampleReply;
+ } else {
+ return nullptr;
+ }
+}
+
+TExampleClient::TExampleClient(const TBusClientSessionConfig sessionConfig, int port)
+ : Proto(port)
+ , UseCompression(false)
+ , CrashOnError(false)
+ , DataSize(320)
+ , MessageCount(0)
+ , RepliesCount(0)
+ , Errors(0)
+ , LastError(MESSAGE_OK)
+{
+ Bus = CreateMessageQueue("TExampleClient");
+
+ Session = TBusClientSession::Create(&Proto, this, sessionConfig, Bus);
+
+ Session->RegisterService("localhost");
+}
+
+TExampleClient::~TExampleClient() {
+}
+
+EMessageStatus TExampleClient::SendMessage(const TNetAddr* addr) {
+ TAutoPtr<TExampleRequest> message(new TExampleRequest(&Proto.RequestCount, DataSize));
+ message->SetCompressed(UseCompression);
+ return Session->SendMessageAutoPtr(message, addr);
+}
+
+void TExampleClient::SendMessages(size_t count, const TNetAddr* addr) {
+ UNIT_ASSERT(MessageCount == 0);
+ UNIT_ASSERT(RepliesCount == 0);
+ UNIT_ASSERT(Errors == 0);
+
+ WorkDone.Reset();
+ MessageCount = count;
+ for (ssize_t i = 0; i < MessageCount; ++i) {
+ EMessageStatus s = SendMessage(addr);
+ UNIT_ASSERT_EQUAL_C(s, MESSAGE_OK, "expecting OK, got " << s);
+ }
+}
+
+void TExampleClient::SendMessages(size_t count, const TNetAddr& addr) {
+ SendMessages(count, &addr);
+}
+
+void TExampleClient::ResetCounters() {
+ MessageCount = 0;
+ RepliesCount = 0;
+ Errors = 0;
+ LastError = MESSAGE_OK;
+
+ WorkDone.Reset();
+}
+
+void TExampleClient::WaitReplies() {
+ WorkDone.WaitT(TDuration::Seconds(60));
+
+ UNIT_ASSERT_VALUES_EQUAL(AtomicGet(RepliesCount), MessageCount);
+ UNIT_ASSERT_VALUES_EQUAL(AtomicGet(Errors), 0);
+ UNIT_ASSERT_VALUES_EQUAL(Session->GetInFlight(), 0);
+
+ ResetCounters();
+}
+
+EMessageStatus TExampleClient::WaitForError() {
+ WorkDone.WaitT(TDuration::Seconds(60));
+
+ UNIT_ASSERT_VALUES_EQUAL(1, MessageCount);
+ UNIT_ASSERT_VALUES_EQUAL(0, AtomicGet(RepliesCount));
+ UNIT_ASSERT_VALUES_EQUAL(0, Session->GetInFlight());
+ UNIT_ASSERT_VALUES_EQUAL(1, Errors);
+ EMessageStatus result = LastError;
+
+ ResetCounters();
+ return result;
+}
+
+void TExampleClient::WaitForError(EMessageStatus status) {
+ EMessageStatus error = WaitForError();
+ UNIT_ASSERT_VALUES_EQUAL(status, error);
+}
+
+void TExampleClient::SendMessagesWaitReplies(size_t count, const TNetAddr* addr) {
+ SendMessages(count, addr);
+ WaitReplies();
+}
+
+void TExampleClient::SendMessagesWaitReplies(size_t count, const TNetAddr& addr) {
+ SendMessagesWaitReplies(count, &addr);
+}
+
+void TExampleClient::OnReply(TAutoPtr<TBusMessage> mess, TAutoPtr<TBusMessage> reply) {
+ Y_UNUSED(mess);
+ Y_UNUSED(reply);
+
+ if (AtomicIncrement(RepliesCount) == MessageCount) {
+ WorkDone.Signal();
+ }
+}
+
+void TExampleClient::OnError(TAutoPtr<TBusMessage> mess, EMessageStatus status) {
+ if (CrashOnError) {
+ Y_FAIL("client failed: %s", ToCString(status));
+ }
+
+ Y_UNUSED(mess);
+
+ AtomicIncrement(Errors);
+ LastError = status;
+ WorkDone.Signal();
+}
+
+TExampleServer::TExampleServer(
+ const char* name,
+ const TBusServerSessionConfig& sessionConfig)
+ : UseCompression(false)
+ , AckMessageBeforeSendReply(false)
+ , ForgetRequest(false)
+{
+ Bus = CreateMessageQueue(name);
+ Session = TBusServerSession::Create(&Proto, this, sessionConfig, Bus);
+}
+
+TExampleServer::TExampleServer(unsigned port, const char* name)
+ : UseCompression(false)
+ , AckMessageBeforeSendReply(false)
+ , ForgetRequest(false)
+{
+ Bus = CreateMessageQueue(name);
+ TBusServerSessionConfig sessionConfig;
+ sessionConfig.ListenPort = port;
+ Session = TBusServerSession::Create(&Proto, this, sessionConfig, Bus);
+}
+
+TExampleServer::~TExampleServer() {
+}
+
+size_t TExampleServer::GetInFlight() const {
+ return Session->GetInFlight();
+}
+
+unsigned TExampleServer::GetActualListenPort() const {
+ return Session->GetActualListenPort();
+}
+
+TNetAddr TExampleServer::GetActualListenAddr() const {
+ return TNetAddr("127.0.0.1", GetActualListenPort());
+}
+
+void TExampleServer::WaitForOnMessageCount(unsigned n) {
+ TestSync.WaitFor(n);
+}
+
+void TExampleServer::OnMessage(TOnMessageContext& mess) {
+ TestSync.Inc();
+
+ TExampleRequest* request = VerifyDynamicCast<TExampleRequest*>(mess.GetMessage());
+
+ if (ForgetRequest) {
+ mess.ForgetRequest();
+ return;
+ }
+
+ TAutoPtr<TBusMessage> reply(new TExampleResponse(&Proto.ResponseCount, DataSize.GetOrElse(request->Data.size())));
+ reply->SetCompressed(UseCompression);
+
+ EMessageStatus status;
+ if (AckMessageBeforeSendReply) {
+ TBusIdentity ident;
+ mess.AckMessage(ident);
+ status = Session->SendReply(ident, reply.Release()); // TODO: leaks on error
+ } else {
+ status = mess.SendReplyMove(reply);
+ }
+
+ Y_VERIFY(status == MESSAGE_OK, "failed to send reply: %s", ToString(status).data());
+}
diff --git a/library/cpp/messagebus/test/helper/example.h b/library/cpp/messagebus/test/helper/example.h
new file mode 100644
index 0000000000..26b7475308
--- /dev/null
+++ b/library/cpp/messagebus/test/helper/example.h
@@ -0,0 +1,132 @@
+#pragma once
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "alloc_counter.h"
+#include "message_handler_error.h"
+
+#include <library/cpp/messagebus/ybus.h>
+#include <library/cpp/messagebus/misc/test_sync.h>
+
+#include <util/system/event.h>
+
+namespace NBus {
+ namespace NTest {
+ class TExampleRequest: public TBusMessage {
+ friend class TExampleProtocol;
+
+ private:
+ TAllocCounter AllocCounter;
+
+ public:
+ TString Data;
+
+ public:
+ TExampleRequest(TAtomic* counterPtr, size_t payloadSize = 320);
+ TExampleRequest(ECreateUninitialized, TAtomic* counterPtr);
+ };
+
+ class TExampleResponse: public TBusMessage {
+ friend class TExampleProtocol;
+
+ private:
+ TAllocCounter AllocCounter;
+
+ public:
+ TString Data;
+ TExampleResponse(TAtomic* counterPtr, size_t payloadSize = 320);
+ TExampleResponse(ECreateUninitialized, TAtomic* counterPtr);
+ };
+
+ class TExampleProtocol: public TBusProtocol {
+ public:
+ TAtomic RequestCount;
+ TAtomic ResponseCount;
+ TAtomic RequestCountDeserialized;
+ TAtomic ResponseCountDeserialized;
+ TAtomic StartCount;
+
+ TExampleProtocol(int port = 0);
+
+ ~TExampleProtocol() override;
+
+ void Serialize(const TBusMessage* message, TBuffer& buffer) override;
+
+ TAutoPtr<TBusMessage> Deserialize(ui16 messageType, TArrayRef<const char> payload) override;
+ };
+
+ class TExampleClient: private TBusClientHandlerError {
+ public:
+ TExampleProtocol Proto;
+ bool UseCompression;
+ bool CrashOnError;
+ size_t DataSize;
+
+ ssize_t MessageCount;
+ TAtomic RepliesCount;
+ TAtomic Errors;
+ EMessageStatus LastError;
+
+ TSystemEvent WorkDone;
+
+ TBusMessageQueuePtr Bus;
+ TBusClientSessionPtr Session;
+
+ public:
+ TExampleClient(const TBusClientSessionConfig sessionConfig = TBusClientSessionConfig(), int port = 0);
+ ~TExampleClient() override;
+
+ EMessageStatus SendMessage(const TNetAddr* addr = nullptr);
+
+ void SendMessages(size_t count, const TNetAddr* addr = nullptr);
+ void SendMessages(size_t count, const TNetAddr& addr);
+
+ void ResetCounters();
+ void WaitReplies();
+ EMessageStatus WaitForError();
+ void WaitForError(EMessageStatus status);
+
+ void SendMessagesWaitReplies(size_t count, const TNetAddr* addr = nullptr);
+ void SendMessagesWaitReplies(size_t count, const TNetAddr& addr);
+
+ void OnReply(TAutoPtr<TBusMessage> mess, TAutoPtr<TBusMessage> reply) override;
+
+ void OnError(TAutoPtr<TBusMessage> mess, EMessageStatus) override;
+ };
+
+ class TExampleServer: private TBusServerHandlerError {
+ public:
+ TExampleProtocol Proto;
+ bool UseCompression;
+ bool AckMessageBeforeSendReply;
+ TMaybe<size_t> DataSize; // Nothing means use request size
+ bool ForgetRequest;
+
+ TTestSync TestSync;
+
+ TBusMessageQueuePtr Bus;
+ TBusServerSessionPtr Session;
+
+ public:
+ TExampleServer(
+ const char* name = "TExampleServer",
+ const TBusServerSessionConfig& sessionConfig = TBusServerSessionConfig());
+
+ TExampleServer(unsigned port, const char* name = "TExampleServer");
+
+ ~TExampleServer() override;
+
+ public:
+ size_t GetInFlight() const;
+ unsigned GetActualListenPort() const;
+ // any of
+ TNetAddr GetActualListenAddr() const;
+
+ void WaitForOnMessageCount(unsigned n);
+
+ protected:
+ void OnMessage(TOnMessageContext& mess) override;
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/test/helper/example_module.cpp b/library/cpp/messagebus/test/helper/example_module.cpp
new file mode 100644
index 0000000000..65ecfcf73f
--- /dev/null
+++ b/library/cpp/messagebus/test/helper/example_module.cpp
@@ -0,0 +1,43 @@
+#include "example_module.h"
+
+using namespace NBus;
+using namespace NBus::NTest;
+
+TExampleModule::TExampleModule()
+ : TBusModule("TExampleModule")
+{
+ TBusQueueConfig queueConfig;
+ queueConfig.NumWorkers = 5;
+ Queue = CreateMessageQueue(queueConfig);
+}
+
+void TExampleModule::StartModule() {
+ CreatePrivateSessions(Queue.Get());
+ StartInput();
+}
+
+bool TExampleModule::Shutdown() {
+ TBusModule::Shutdown();
+ return true;
+}
+
+TBusServerSessionPtr TExampleModule::CreateExtSession(TBusMessageQueue&) {
+ return nullptr;
+}
+
+TBusServerSessionPtr TExampleServerModule::CreateExtSession(TBusMessageQueue& queue) {
+ TBusServerSessionPtr r = CreateDefaultDestination(queue, &Proto, TBusServerSessionConfig());
+ ServerAddr = TNetAddr("localhost", r->GetActualListenPort());
+ return r;
+}
+
+TExampleClientModule::TExampleClientModule()
+ : Source()
+{
+}
+
+TBusServerSessionPtr TExampleClientModule::CreateExtSession(TBusMessageQueue& queue) {
+ Source = CreateDefaultSource(queue, &Proto, TBusServerSessionConfig());
+ Source->RegisterService("localhost");
+ return nullptr;
+}
diff --git a/library/cpp/messagebus/test/helper/example_module.h b/library/cpp/messagebus/test/helper/example_module.h
new file mode 100644
index 0000000000..a0b295f613
--- /dev/null
+++ b/library/cpp/messagebus/test/helper/example_module.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "example.h"
+
+#include <library/cpp/messagebus/oldmodule/module.h>
+
+namespace NBus {
+ namespace NTest {
+ struct TExampleModule: public TBusModule {
+ TExampleProtocol Proto;
+ TBusMessageQueuePtr Queue;
+
+ TExampleModule();
+
+ void StartModule();
+
+ bool Shutdown() override;
+
+ // nop by default
+ TBusServerSessionPtr CreateExtSession(TBusMessageQueue& queue) override;
+ };
+
+ struct TExampleServerModule: public TExampleModule {
+ TNetAddr ServerAddr;
+ TBusServerSessionPtr CreateExtSession(TBusMessageQueue& queue) override;
+ };
+
+ struct TExampleClientModule: public TExampleModule {
+ TBusClientSessionPtr Source;
+
+ TExampleClientModule();
+
+ TBusServerSessionPtr CreateExtSession(TBusMessageQueue& queue) override;
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/test/helper/fixed_port.cpp b/library/cpp/messagebus/test/helper/fixed_port.cpp
new file mode 100644
index 0000000000..258da0d1a5
--- /dev/null
+++ b/library/cpp/messagebus/test/helper/fixed_port.cpp
@@ -0,0 +1,10 @@
+#include "fixed_port.h"
+
+#include <util/system/env.h>
+
+#include <stdlib.h>
+
+bool NBus::NTest::IsFixedPortTestAllowed() {
+ // TODO: report skipped tests to test
+ return !GetEnv("MB_TESTS_SKIP_FIXED_PORT");
+}
diff --git a/library/cpp/messagebus/test/helper/fixed_port.h b/library/cpp/messagebus/test/helper/fixed_port.h
new file mode 100644
index 0000000000..a9c61ebc63
--- /dev/null
+++ b/library/cpp/messagebus/test/helper/fixed_port.h
@@ -0,0 +1,11 @@
+#pragma once
+
+namespace NBus {
+ namespace NTest {
+ bool IsFixedPortTestAllowed();
+
+ // Must not be in range OS uses for bind on random port.
+ const unsigned FixedPort = 4927;
+
+ }
+}
diff --git a/library/cpp/messagebus/test/helper/hanging_server.cpp b/library/cpp/messagebus/test/helper/hanging_server.cpp
new file mode 100644
index 0000000000..a35514b00d
--- /dev/null
+++ b/library/cpp/messagebus/test/helper/hanging_server.cpp
@@ -0,0 +1,13 @@
+#include "hanging_server.h"
+
+#include <util/system/yassert.h>
+
+using namespace NBus;
+
+THangingServer::THangingServer(int port) {
+ BindResult = BindOnPort(port, false);
+}
+
+int THangingServer::GetPort() const {
+ return BindResult.first;
+}
diff --git a/library/cpp/messagebus/test/helper/hanging_server.h b/library/cpp/messagebus/test/helper/hanging_server.h
new file mode 100644
index 0000000000..cc9fb274d8
--- /dev/null
+++ b/library/cpp/messagebus/test/helper/hanging_server.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <library/cpp/messagebus/network.h>
+
+#include <util/network/sock.h>
+
+class THangingServer {
+private:
+ std::pair<unsigned, TVector<NBus::TBindResult>> BindResult;
+
+public:
+ // listen on given port, and nothing else
+ THangingServer(int port = 0);
+ // actual port
+ int GetPort() const;
+};
diff --git a/library/cpp/messagebus/test/helper/message_handler_error.cpp b/library/cpp/messagebus/test/helper/message_handler_error.cpp
new file mode 100644
index 0000000000..c09811ec67
--- /dev/null
+++ b/library/cpp/messagebus/test/helper/message_handler_error.cpp
@@ -0,0 +1,26 @@
+#include "message_handler_error.h"
+
+#include <util/system/yassert.h>
+
+using namespace NBus;
+using namespace NBus::NTest;
+
+void TBusClientHandlerError::OnError(TAutoPtr<TBusMessage>, EMessageStatus status) {
+ Y_FAIL("must not be called, status: %s", ToString(status).data());
+}
+
+void TBusClientHandlerError::OnReply(TAutoPtr<TBusMessage>, TAutoPtr<TBusMessage>) {
+ Y_FAIL("must not be called");
+}
+
+void TBusClientHandlerError::OnMessageSentOneWay(TAutoPtr<TBusMessage>) {
+ Y_FAIL("must not be called");
+}
+
+void TBusServerHandlerError::OnError(TAutoPtr<TBusMessage>, EMessageStatus status) {
+ Y_FAIL("must not be called, status: %s", ToString(status).data());
+}
+
+void TBusServerHandlerError::OnMessage(TOnMessageContext&) {
+ Y_FAIL("must not be called");
+}
diff --git a/library/cpp/messagebus/test/helper/message_handler_error.h b/library/cpp/messagebus/test/helper/message_handler_error.h
new file mode 100644
index 0000000000..a314b10761
--- /dev/null
+++ b/library/cpp/messagebus/test/helper/message_handler_error.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <library/cpp/messagebus/ybus.h>
+
+namespace NBus {
+ namespace NTest {
+ struct TBusClientHandlerError: public IBusClientHandler {
+ void OnError(TAutoPtr<TBusMessage> pMessage, EMessageStatus status) override;
+ void OnMessageSentOneWay(TAutoPtr<TBusMessage> pMessage) override;
+ void OnReply(TAutoPtr<TBusMessage> pMessage, TAutoPtr<TBusMessage> pReply) override;
+ };
+
+ struct TBusServerHandlerError: public IBusServerHandler {
+ void OnError(TAutoPtr<TBusMessage> pMessage, EMessageStatus status) override;
+ void OnMessage(TOnMessageContext& pMessage) override;
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/test/helper/object_count_check.h b/library/cpp/messagebus/test/helper/object_count_check.h
new file mode 100644
index 0000000000..1c4756e58c
--- /dev/null
+++ b/library/cpp/messagebus/test/helper/object_count_check.h
@@ -0,0 +1,74 @@
+#pragma once
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/messagebus/remote_client_connection.h>
+#include <library/cpp/messagebus/remote_client_session.h>
+#include <library/cpp/messagebus/remote_server_connection.h>
+#include <library/cpp/messagebus/remote_server_session.h>
+#include <library/cpp/messagebus/ybus.h>
+#include <library/cpp/messagebus/oldmodule/module.h>
+#include <library/cpp/messagebus/scheduler/scheduler.h>
+
+#include <util/generic/object_counter.h>
+#include <util/system/type_name.h>
+#include <util/stream/output.h>
+
+#include <typeinfo>
+
+struct TObjectCountCheck {
+ bool Enabled;
+
+ template <typename T>
+ struct TReset {
+ TObjectCountCheck* const Thiz;
+
+ TReset(TObjectCountCheck* thiz)
+ : Thiz(thiz)
+ {
+ }
+
+ void operator()() {
+ long oldValue = TObjectCounter<T>::ResetObjectCount();
+ if (oldValue != 0) {
+ Cerr << "warning: previous counter: " << oldValue << " for " << TypeName<T>() << Endl;
+ Cerr << "won't check in this test" << Endl;
+ Thiz->Enabled = false;
+ }
+ }
+ };
+
+ TObjectCountCheck() {
+ Enabled = true;
+ DoForAllCounters<TReset>();
+ }
+
+ template <typename T>
+ struct TCheckZero {
+ TCheckZero(TObjectCountCheck*) {
+ }
+
+ void operator()() {
+ UNIT_ASSERT_VALUES_EQUAL_C(0L, TObjectCounter<T>::ObjectCount(), TypeName<T>());
+ }
+ };
+
+ ~TObjectCountCheck() {
+ if (Enabled) {
+ DoForAllCounters<TCheckZero>();
+ }
+ }
+
+ template <template <typename> class TOp>
+ void DoForAllCounters() {
+ TOp< ::NBus::NPrivate::TRemoteClientConnection>(this)();
+ TOp< ::NBus::NPrivate::TRemoteServerConnection>(this)();
+ TOp< ::NBus::NPrivate::TRemoteClientSession>(this)();
+ TOp< ::NBus::NPrivate::TRemoteServerSession>(this)();
+ TOp< ::NBus::NPrivate::TScheduler>(this)();
+ TOp< ::NEventLoop::TEventLoop>(this)();
+ TOp< ::NEventLoop::TChannel>(this)();
+ TOp< ::NBus::TBusModule>(this)();
+ TOp< ::NBus::TBusJob>(this)();
+ }
+};
diff --git a/library/cpp/messagebus/test/helper/wait_for.h b/library/cpp/messagebus/test/helper/wait_for.h
new file mode 100644
index 0000000000..f09958d4c0
--- /dev/null
+++ b/library/cpp/messagebus/test/helper/wait_for.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <util/datetime/base.h>
+#include <util/system/yassert.h>
+
+#define UNIT_WAIT_FOR(condition) \
+ do { \
+ TInstant start(TInstant::Now()); \
+ while (!(condition) && (TInstant::Now() - start < TDuration::Seconds(10))) { \
+ Sleep(TDuration::MilliSeconds(1)); \
+ } \
+ /* TODO: use UNIT_ASSERT if in unittest thread */ \
+ Y_VERIFY(condition, "condition failed after 10 seconds wait"); \
+ } while (0)
diff --git a/library/cpp/messagebus/test/helper/ya.make b/library/cpp/messagebus/test/helper/ya.make
new file mode 100644
index 0000000000..97bd45f573
--- /dev/null
+++ b/library/cpp/messagebus/test/helper/ya.make
@@ -0,0 +1,17 @@
+LIBRARY(messagebus_test_helper)
+
+OWNER(g:messagebus)
+
+SRCS(
+ example.cpp
+ example_module.cpp
+ fixed_port.cpp
+ message_handler_error.cpp
+ hanging_server.cpp
+)
+
+PEERDIR(
+ library/cpp/messagebus/oldmodule
+)
+
+END()
diff --git a/library/cpp/messagebus/test/perftest/messages.proto b/library/cpp/messagebus/test/perftest/messages.proto
new file mode 100644
index 0000000000..8919034e7a
--- /dev/null
+++ b/library/cpp/messagebus/test/perftest/messages.proto
@@ -0,0 +1,7 @@
+message TPerftestRequestRecord {
+ required string Data = 1;
+}
+
+message TPerftestResponseRecord {
+ required string Data = 1;
+}
diff --git a/library/cpp/messagebus/test/perftest/perftest.cpp b/library/cpp/messagebus/test/perftest/perftest.cpp
new file mode 100644
index 0000000000..8489319278
--- /dev/null
+++ b/library/cpp/messagebus/test/perftest/perftest.cpp
@@ -0,0 +1,713 @@
+#include "simple_proto.h"
+
+#include <library/cpp/messagebus/test/perftest/messages.pb.h>
+
+#include <library/cpp/messagebus/text_utils.h>
+#include <library/cpp/messagebus/thread_extra.h>
+#include <library/cpp/messagebus/ybus.h>
+#include <library/cpp/messagebus/oldmodule/module.h>
+#include <library/cpp/messagebus/protobuf/ybusbuf.h>
+#include <library/cpp/messagebus/www/www.h>
+
+#include <library/cpp/deprecated/threadable/threadable.h>
+#include <library/cpp/execprofile/profile.h>
+#include <library/cpp/getopt/opt.h>
+#include <library/cpp/lwtrace/start.h>
+#include <library/cpp/sighandler/async_signals_handler.h>
+#include <library/cpp/threading/future/legacy_future.h>
+
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+#include <util/random/random.h>
+#include <util/stream/file.h>
+#include <util/stream/output.h>
+#include <util/stream/str.h>
+#include <util/string/split.h>
+#include <util/system/event.h>
+#include <util/system/sysstat.h>
+#include <util/system/thread.h>
+#include <util/thread/lfqueue.h>
+
+#include <signal.h>
+#include <stdlib.h>
+
+using namespace NBus;
+
+///////////////////////////////////////////////////////
+/// \brief Configuration parameters of the test
+
+const int DEFAULT_PORT = 55666;
+
+struct TPerftestConfig {
+ TString Nodes; ///< node1:port1,node2:port2
+ int ClientCount;
+ int MessageSize; ///< size of message to send
+ int Delay; ///< server delay (milliseconds)
+ float Failure; ///< simulated failure rate
+ int ServerPort;
+ int Run;
+ bool ServerUseModules;
+ bool ExecuteOnMessageInWorkerPool;
+ bool ExecuteOnReplyInWorkerPool;
+ bool UseCompression;
+ bool Profile;
+ unsigned WwwPort;
+
+ TPerftestConfig();
+
+ void Print() {
+ fprintf(stderr, "ClientCount=%d\n", ClientCount);
+ fprintf(stderr, "ServerPort=%d\n", ServerPort);
+ fprintf(stderr, "Delay=%d usecs\n", Delay);
+ fprintf(stderr, "MessageSize=%d bytes\n", MessageSize);
+ fprintf(stderr, "Failure=%.3f%%\n", Failure * 100.0);
+ fprintf(stderr, "Runtime=%d seconds\n", Run);
+ fprintf(stderr, "ServerUseModules=%s\n", ServerUseModules ? "true" : "false");
+ fprintf(stderr, "ExecuteOnMessageInWorkerPool=%s\n", ExecuteOnMessageInWorkerPool ? "true" : "false");
+ fprintf(stderr, "ExecuteOnReplyInWorkerPool=%s\n", ExecuteOnReplyInWorkerPool ? "true" : "false");
+ fprintf(stderr, "UseCompression=%s\n", UseCompression ? "true" : "false");
+ fprintf(stderr, "Profile=%s\n", Profile ? "true" : "false");
+ fprintf(stderr, "WwwPort=%u\n", WwwPort);
+ }
+};
+
+extern TPerftestConfig* TheConfig;
+extern bool TheExit;
+
+TVector<TNetAddr> ServerAddresses;
+
+struct TConfig {
+ TBusQueueConfig ServerQueueConfig;
+ TBusQueueConfig ClientQueueConfig;
+ TBusServerSessionConfig ServerSessionConfig;
+ TBusClientSessionConfig ClientSessionConfig;
+ bool SimpleProtocol;
+
+private:
+ void ConfigureDefaults(TBusQueueConfig& config) {
+ config.NumWorkers = 4;
+ }
+
+ void ConfigureDefaults(TBusSessionConfig& config) {
+ config.MaxInFlight = 10000;
+ config.SendTimeout = TDuration::Seconds(20).MilliSeconds();
+ config.TotalTimeout = TDuration::Seconds(60).MilliSeconds();
+ }
+
+public:
+ TConfig()
+ : SimpleProtocol(false)
+ {
+ ConfigureDefaults(ServerQueueConfig);
+ ConfigureDefaults(ClientQueueConfig);
+ ConfigureDefaults(ServerSessionConfig);
+ ConfigureDefaults(ClientSessionConfig);
+ }
+
+ void Print() {
+ // TODO: do not print server if only client and vice verse
+ Cerr << "server queue config:\n";
+ Cerr << IndentText(ServerQueueConfig.PrintToString());
+ Cerr << "server session config:" << Endl;
+ Cerr << IndentText(ServerSessionConfig.PrintToString());
+ Cerr << "client queue config:\n";
+ Cerr << IndentText(ClientQueueConfig.PrintToString());
+ Cerr << "client session config:" << Endl;
+ Cerr << IndentText(ClientSessionConfig.PrintToString());
+ Cerr << "simple protocol: " << SimpleProtocol << "\n";
+ }
+};
+
+TConfig Config;
+
+////////////////////////////////////////////////////////////////
+/// \brief Fast message
+
+using TPerftestRequest = TBusBufferMessage<TPerftestRequestRecord, 77>;
+using TPerftestResponse = TBusBufferMessage<TPerftestResponseRecord, 79>;
+
+static size_t RequestSize() {
+ return RandomNumber<size_t>(TheConfig->MessageSize * 2 + 1);
+}
+
+TAutoPtr<TBusMessage> NewRequest() {
+ if (Config.SimpleProtocol) {
+ TAutoPtr<TSimpleMessage> r(new TSimpleMessage);
+ r->SetCompressed(TheConfig->UseCompression);
+ r->Payload = 10;
+ return r.Release();
+ } else {
+ TAutoPtr<TPerftestRequest> r(new TPerftestRequest);
+ r->SetCompressed(TheConfig->UseCompression);
+ // TODO: use random content for better compression test
+ r->Record.SetData(TString(RequestSize(), '?'));
+ return r.Release();
+ }
+}
+
+void CheckRequest(TPerftestRequest* request) {
+ const TString& data = request->Record.GetData();
+ for (size_t i = 0; i != data.size(); ++i) {
+ Y_VERIFY(data.at(i) == '?', "must be question mark");
+ }
+}
+
+TAutoPtr<TPerftestResponse> NewResponse(TPerftestRequest* request) {
+ TAutoPtr<TPerftestResponse> r(new TPerftestResponse);
+ r->SetCompressed(TheConfig->UseCompression);
+ r->Record.SetData(TString(request->Record.GetData().size(), '.'));
+ return r;
+}
+
+void CheckResponse(TPerftestResponse* response) {
+ const TString& data = response->Record.GetData();
+ for (size_t i = 0; i != data.size(); ++i) {
+ Y_VERIFY(data.at(i) == '.', "must be dot");
+ }
+}
+
+////////////////////////////////////////////////////////////////////
+/// \brief Fast protocol that common between client and server
+class TPerftestProtocol: public TBusBufferProtocol {
+public:
+ TPerftestProtocol()
+ : TBusBufferProtocol("TPerftestProtocol", TheConfig->ServerPort)
+ {
+ RegisterType(new TPerftestRequest);
+ RegisterType(new TPerftestResponse);
+ }
+};
+
+class TPerftestServer;
+class TPerftestUsingModule;
+class TPerftestClient;
+
+struct TTestStats {
+ TInstant Start;
+
+ TAtomic Messages;
+ TAtomic Errors;
+ TAtomic Replies;
+
+ void IncMessage() {
+ AtomicIncrement(Messages);
+ }
+ void IncReplies() {
+ AtomicDecrement(Messages);
+ AtomicIncrement(Replies);
+ }
+ int NumMessage() {
+ return AtomicGet(Messages);
+ }
+ void IncErrors() {
+ AtomicDecrement(Messages);
+ AtomicIncrement(Errors);
+ }
+ int NumErrors() {
+ return AtomicGet(Errors);
+ }
+ int NumReplies() {
+ return AtomicGet(Replies);
+ }
+
+ double GetThroughput() {
+ return NumReplies() * 1000000.0 / (TInstant::Now() - Start).MicroSeconds();
+ }
+
+public:
+ TTestStats()
+ : Start(TInstant::Now())
+ , Messages(0)
+ , Errors(0)
+ , Replies(0)
+ {
+ }
+
+ void PeriodicallyPrint();
+};
+
+TTestStats Stats;
+
+////////////////////////////////////////////////////////////////////
+/// \brief Fast of the client session
+class TPerftestClient : IBusClientHandler {
+public:
+ TBusClientSessionPtr Session;
+ THolder<TBusProtocol> Proto;
+ TBusMessageQueuePtr Bus;
+ TVector<TBusClientConnectionPtr> Connections;
+
+public:
+ /// constructor creates instances of protocol and session
+ TPerftestClient() {
+ /// create or get instance of message queue, need one per application
+ Bus = CreateMessageQueue(Config.ClientQueueConfig, "client");
+
+ if (Config.SimpleProtocol) {
+ Proto.Reset(new TSimpleProtocol);
+ } else {
+ Proto.Reset(new TPerftestProtocol);
+ }
+
+ Session = TBusClientSession::Create(Proto.Get(), this, Config.ClientSessionConfig, Bus);
+
+ for (unsigned i = 0; i < ServerAddresses.size(); ++i) {
+ Connections.push_back(Session->GetConnection(ServerAddresses[i]));
+ }
+ }
+
+ /// dispatch of requests is done here
+ void Work() {
+ SetCurrentThreadName("FastClient::Work");
+
+ while (!TheExit) {
+ TBusClientConnection* connection;
+ if (Connections.size() == 1) {
+ connection = Connections.front().Get();
+ } else {
+ connection = Connections.at(RandomNumber<size_t>()).Get();
+ }
+
+ TBusMessage* message = NewRequest().Release();
+ int ret = connection->SendMessage(message, true);
+
+ if (ret == MESSAGE_OK) {
+ Stats.IncMessage();
+ } else if (ret == MESSAGE_BUSY) {
+ //delete message;
+ //Sleep(TDuration::MilliSeconds(1));
+ //continue;
+ Y_FAIL("unreachable");
+ } else if (ret == MESSAGE_SHUTDOWN) {
+ delete message;
+ } else {
+ delete message;
+ Stats.IncErrors();
+ }
+ }
+ }
+
+ void Stop() {
+ Session->Shutdown();
+ }
+
+ /// actual work is being done here
+ void OnReply(TAutoPtr<TBusMessage> mess, TAutoPtr<TBusMessage> reply) override {
+ Y_UNUSED(mess);
+
+ if (Config.SimpleProtocol) {
+ VerifyDynamicCast<TSimpleMessage*>(reply.Get());
+ } else {
+ TPerftestResponse* typed = VerifyDynamicCast<TPerftestResponse*>(reply.Get());
+
+ CheckResponse(typed);
+ }
+
+ Stats.IncReplies();
+ }
+
+ /// message that could not be delivered
+ void OnError(TAutoPtr<TBusMessage> mess, EMessageStatus status) override {
+ Y_UNUSED(mess);
+ Y_UNUSED(status);
+
+ if (TheExit) {
+ return;
+ }
+
+ Stats.IncErrors();
+
+ // Y_ASSERT(TheConfig->Failure > 0.0);
+ }
+};
+
+class TPerftestServerCommon {
+public:
+ THolder<TBusProtocol> Proto;
+
+ TBusMessageQueuePtr Bus;
+
+ TBusServerSessionPtr Session;
+
+protected:
+ TPerftestServerCommon(const char* name)
+ : Session()
+ {
+ if (Config.SimpleProtocol) {
+ Proto.Reset(new TSimpleProtocol);
+ } else {
+ Proto.Reset(new TPerftestProtocol);
+ }
+
+ /// create or get instance of single message queue, need one for application
+ Bus = CreateMessageQueue(Config.ServerQueueConfig, name);
+ }
+
+public:
+ void Stop() {
+ Session->Shutdown();
+ }
+};
+
+struct TAsyncRequest {
+ TBusMessage* Request;
+ TInstant ReceivedTime;
+};
+
+/////////////////////////////////////////////////////////////////////
+/// \brief Fast of the server session
+class TPerftestServer: public TPerftestServerCommon, public IBusServerHandler {
+public:
+ TLockFreeQueue<TAsyncRequest> AsyncRequests;
+
+public:
+ TPerftestServer()
+ : TPerftestServerCommon("server")
+ {
+ /// register destination session
+ Session = TBusServerSession::Create(Proto.Get(), this, Config.ServerSessionConfig, Bus);
+ Y_ASSERT(Session && "probably somebody is listening on the same port");
+ }
+
+ /// when message comes, send reply
+ void OnMessage(TOnMessageContext& mess) override {
+ if (Config.SimpleProtocol) {
+ TSimpleMessage* typed = VerifyDynamicCast<TSimpleMessage*>(mess.GetMessage());
+ TAutoPtr<TSimpleMessage> response(new TSimpleMessage);
+ response->Payload = typed->Payload;
+ mess.SendReplyMove(response);
+ return;
+ }
+
+ TPerftestRequest* typed = VerifyDynamicCast<TPerftestRequest*>(mess.GetMessage());
+
+ CheckRequest(typed);
+
+ /// forget replies for few messages, see what happends
+ if (TheConfig->Failure > RandomNumber<double>()) {
+ return;
+ }
+
+ /// sleep requested time
+ if (TheConfig->Delay) {
+ TAsyncRequest request;
+ request.Request = mess.ReleaseMessage();
+ request.ReceivedTime = TInstant::Now();
+ AsyncRequests.Enqueue(request);
+ return;
+ }
+
+ TAutoPtr<TPerftestResponse> reply(NewResponse(typed));
+ /// sent empty reply for each message
+ mess.SendReplyMove(reply);
+ // TODO: count results
+ }
+
+ void Stop() {
+ TPerftestServerCommon::Stop();
+ }
+};
+
+class TPerftestUsingModule: public TPerftestServerCommon, public TBusModule {
+public:
+ TPerftestUsingModule()
+ : TPerftestServerCommon("server")
+ , TBusModule("fast")
+ {
+ Y_VERIFY(CreatePrivateSessions(Bus.Get()), "failed to initialize dupdetect module");
+ Y_VERIFY(StartInput(), "failed to start input");
+ }
+
+ ~TPerftestUsingModule() override {
+ Shutdown();
+ }
+
+private:
+ TJobHandler Start(TBusJob* job, TBusMessage* mess) override {
+ TPerftestRequest* typed = VerifyDynamicCast<TPerftestRequest*>(mess);
+ CheckRequest(typed);
+
+ /// sleep requested time
+ if (TheConfig->Delay) {
+ usleep(TheConfig->Delay);
+ }
+
+ /// forget replies for few messages, see what happends
+ if (TheConfig->Failure > RandomNumber<double>()) {
+ return nullptr;
+ }
+
+ job->SendReply(NewResponse(typed).Release());
+ return nullptr;
+ }
+
+ TBusServerSessionPtr CreateExtSession(TBusMessageQueue& queue) override {
+ return Session = CreateDefaultDestination(queue, Proto.Get(), Config.ServerSessionConfig);
+ }
+};
+
+// ./perftest/perftest -s 11456 -c localhost:11456 -r 60 -n 4 -i 5000
+
+using namespace std;
+using namespace NBus;
+
+static TNetworkAddress ParseNetworkAddress(const char* string) {
+ TString Name;
+ int Port;
+
+ const char* port = strchr(string, ':');
+
+ if (port != nullptr) {
+ Name.append(string, port - string);
+ Port = atoi(port + 1);
+ } else {
+ Name.append(string);
+ Port = TheConfig->ServerPort != 0 ? TheConfig->ServerPort : DEFAULT_PORT;
+ }
+
+ return TNetworkAddress(Name, Port);
+}
+
+TVector<TNetAddr> ParseNodes(const TString nodes) {
+ TVector<TNetAddr> r;
+
+ TVector<TString> hosts;
+
+ size_t numh = Split(nodes.data(), ",", hosts);
+
+ for (int i = 0; i < int(numh); i++) {
+ const TNetworkAddress& networkAddress = ParseNetworkAddress(hosts[i].data());
+ Y_VERIFY(networkAddress.Begin() != networkAddress.End(), "no addresses");
+ r.push_back(TNetAddr(networkAddress, &*networkAddress.Begin()));
+ }
+
+ return r;
+}
+
+TPerftestConfig::TPerftestConfig() {
+ TBusSessionConfig defaultConfig;
+
+ ServerPort = DEFAULT_PORT;
+ Delay = 0; // artificial delay inside server OnMessage()
+ MessageSize = 200;
+ Failure = 0.00;
+ Run = 60; // in seconds
+ Nodes = "localhost";
+ ServerUseModules = false;
+ ExecuteOnMessageInWorkerPool = defaultConfig.ExecuteOnMessageInWorkerPool;
+ ExecuteOnReplyInWorkerPool = defaultConfig.ExecuteOnReplyInWorkerPool;
+ UseCompression = false;
+ Profile = false;
+ WwwPort = 0;
+}
+
+TPerftestConfig* TheConfig = new TPerftestConfig();
+bool TheExit = false;
+
+TSystemEvent StopEvent;
+
+TSimpleSharedPtr<TPerftestServer> Server;
+TSimpleSharedPtr<TPerftestUsingModule> ServerUsingModule;
+
+TVector<TSimpleSharedPtr<TPerftestClient>> Clients;
+TMutex ClientsLock;
+
+void stopsignal(int /*sig*/) {
+ fprintf(stderr, "\n-------------------- exiting ------------------\n");
+ TheExit = true;
+ StopEvent.Signal();
+}
+
+// -s <num> - start server on port <num>
+// -c <node:port,node:port> - start client
+
+void TTestStats::PeriodicallyPrint() {
+ SetCurrentThreadName("print-stats");
+
+ for (;;) {
+ StopEvent.WaitT(TDuration::Seconds(1));
+ if (TheExit)
+ break;
+
+ TVector<TSimpleSharedPtr<TPerftestClient>> clients;
+ {
+ TGuard<TMutex> guard(ClientsLock);
+ clients = Clients;
+ }
+
+ fprintf(stderr, "replies=%d errors=%d throughput=%.3f mess/sec\n",
+ NumReplies(), NumErrors(), GetThroughput());
+ if (!!Server) {
+ fprintf(stderr, "server: q: %u %s\n",
+ (unsigned)Server->Bus->GetExecutor()->GetWorkQueueSize(),
+ Server->Session->GetStatusSingleLine().data());
+ }
+ if (!!ServerUsingModule) {
+ fprintf(stderr, "server: q: %u %s\n",
+ (unsigned)ServerUsingModule->Bus->GetExecutor()->GetWorkQueueSize(),
+ ServerUsingModule->Session->GetStatusSingleLine().data());
+ }
+ for (const auto& client : clients) {
+ fprintf(stderr, "client: q: %u %s\n",
+ (unsigned)client->Bus->GetExecutor()->GetWorkQueueSize(),
+ client->Session->GetStatusSingleLine().data());
+ }
+
+ TStringStream stats;
+
+ bool first = true;
+ if (!!Server) {
+ if (!first) {
+ stats << "\n";
+ }
+ first = false;
+ stats << "server:\n";
+ stats << IndentText(Server->Bus->GetStatus());
+ }
+ if (!!ServerUsingModule) {
+ if (!first) {
+ stats << "\n";
+ }
+ first = false;
+ stats << "server using modules:\n";
+ stats << IndentText(ServerUsingModule->Bus->GetStatus());
+ }
+ for (const auto& client : clients) {
+ if (!first) {
+ stats << "\n";
+ }
+ first = false;
+ stats << "client:\n";
+ stats << IndentText(client->Bus->GetStatus());
+ }
+
+ TUnbufferedFileOutput("stats").Write(stats.Str());
+ }
+}
+
+int main(int argc, char* argv[]) {
+ NLWTrace::StartLwtraceFromEnv();
+
+ /* unix foo */
+ setvbuf(stdout, nullptr, _IONBF, 0);
+ setvbuf(stderr, nullptr, _IONBF, 0);
+ Umask(0);
+ SetAsyncSignalHandler(SIGINT, stopsignal);
+ SetAsyncSignalHandler(SIGTERM, stopsignal);
+#ifndef _win_
+ SetAsyncSignalHandler(SIGUSR1, stopsignal);
+#endif
+ signal(SIGPIPE, SIG_IGN);
+
+ NLastGetopt::TOpts opts = NLastGetopt::TOpts::Default();
+ opts.AddLongOption('s', "server-port", "server port").RequiredArgument("port").StoreResult(&TheConfig->ServerPort);
+ opts.AddCharOption('m', "average message size").RequiredArgument("size").StoreResult(&TheConfig->MessageSize);
+ opts.AddLongOption('c', "server-host", "server hosts").RequiredArgument("host[,host]...").StoreResult(&TheConfig->Nodes);
+ opts.AddCharOption('f', "failure rate (rational number between 0 and 1)").RequiredArgument("rate").StoreResult(&TheConfig->Failure);
+ opts.AddCharOption('w', "delay before reply").RequiredArgument("microseconds").StoreResult(&TheConfig->Delay);
+ opts.AddCharOption('r', "run duration").RequiredArgument("seconds").StoreResult(&TheConfig->Run);
+ opts.AddLongOption("client-count", "amount of clients").RequiredArgument("count").StoreResult(&TheConfig->ClientCount).DefaultValue("1");
+ opts.AddLongOption("server-use-modules").StoreResult(&TheConfig->ServerUseModules, true);
+ opts.AddLongOption("on-message-in-pool", "execute OnMessage callback in worker pool")
+ .RequiredArgument("BOOL")
+ .StoreResult(&TheConfig->ExecuteOnMessageInWorkerPool);
+ opts.AddLongOption("on-reply-in-pool", "execute OnReply callback in worker pool")
+ .RequiredArgument("BOOL")
+ .StoreResult(&TheConfig->ExecuteOnReplyInWorkerPool);
+ opts.AddLongOption("compression", "use compression").RequiredArgument("BOOL").StoreResult(&TheConfig->UseCompression);
+ opts.AddLongOption("simple-proto").SetFlag(&Config.SimpleProtocol);
+ opts.AddLongOption("profile").SetFlag(&TheConfig->Profile);
+ opts.AddLongOption("www-port").RequiredArgument("PORT").StoreResult(&TheConfig->WwwPort);
+ opts.AddHelpOption();
+
+ Config.ServerQueueConfig.ConfigureLastGetopt(opts, "server-");
+ Config.ServerSessionConfig.ConfigureLastGetopt(opts, "server-");
+ Config.ClientQueueConfig.ConfigureLastGetopt(opts, "client-");
+ Config.ClientSessionConfig.ConfigureLastGetopt(opts, "client-");
+
+ opts.SetFreeArgsMax(0);
+
+ NLastGetopt::TOptsParseResult parseResult(&opts, argc, argv);
+
+ TheConfig->Print();
+ Config.Print();
+
+ if (TheConfig->Profile) {
+ BeginProfiling();
+ }
+
+ TIntrusivePtr<TBusWww> www(new TBusWww);
+
+ ServerAddresses = ParseNodes(TheConfig->Nodes);
+
+ if (TheConfig->ServerPort) {
+ if (TheConfig->ServerUseModules) {
+ ServerUsingModule = new TPerftestUsingModule();
+ www->RegisterModule(ServerUsingModule.Get());
+ } else {
+ Server = new TPerftestServer();
+ www->RegisterServerSession(Server->Session);
+ }
+ }
+
+ TVector<TSimpleSharedPtr<NThreading::TLegacyFuture<void, false>>> futures;
+
+ if (ServerAddresses.size() > 0 && TheConfig->ClientCount > 0) {
+ for (int i = 0; i < TheConfig->ClientCount; ++i) {
+ TGuard<TMutex> guard(ClientsLock);
+ Clients.push_back(new TPerftestClient);
+ futures.push_back(new NThreading::TLegacyFuture<void, false>(std::bind(&TPerftestClient::Work, Clients.back())));
+ www->RegisterClientSession(Clients.back()->Session);
+ }
+ }
+
+ futures.push_back(new NThreading::TLegacyFuture<void, false>(std::bind(&TTestStats::PeriodicallyPrint, std::ref(Stats))));
+
+ THolder<TBusWwwHttpServer> wwwServer;
+ if (TheConfig->WwwPort != 0) {
+ wwwServer.Reset(new TBusWwwHttpServer(www, TheConfig->WwwPort));
+ }
+
+ /* sit here until signal terminate our process */
+ StopEvent.WaitT(TDuration::Seconds(TheConfig->Run));
+ TheExit = true;
+ StopEvent.Signal();
+
+ if (!!Server) {
+ Cerr << "Stopping server\n";
+ Server->Stop();
+ }
+ if (!!ServerUsingModule) {
+ Cerr << "Stopping server (using modules)\n";
+ ServerUsingModule->Stop();
+ }
+
+ TVector<TSimpleSharedPtr<TPerftestClient>> clients;
+ {
+ TGuard<TMutex> guard(ClientsLock);
+ clients = Clients;
+ }
+
+ if (!clients.empty()) {
+ Cerr << "Stopping clients\n";
+
+ for (auto& client : clients) {
+ client->Stop();
+ }
+ }
+
+ wwwServer.Destroy();
+
+ for (const auto& future : futures) {
+ future->Get();
+ }
+
+ if (TheConfig->Profile) {
+ EndProfiling();
+ }
+
+ Cerr << "***SUCCESS***\n";
+ return 0;
+}
diff --git a/library/cpp/messagebus/test/perftest/simple_proto.cpp b/library/cpp/messagebus/test/perftest/simple_proto.cpp
new file mode 100644
index 0000000000..19d6c15b9d
--- /dev/null
+++ b/library/cpp/messagebus/test/perftest/simple_proto.cpp
@@ -0,0 +1,22 @@
+#include "simple_proto.h"
+
+#include <util/generic/cast.h>
+
+#include <typeinfo>
+
+using namespace NBus;
+
+void TSimpleProtocol::Serialize(const TBusMessage* mess, TBuffer& data) {
+ Y_VERIFY(typeid(TSimpleMessage) == typeid(*mess));
+ const TSimpleMessage* typed = static_cast<const TSimpleMessage*>(mess);
+ data.Append((const char*)&typed->Payload, 4);
+}
+
+TAutoPtr<TBusMessage> TSimpleProtocol::Deserialize(ui16, TArrayRef<const char> payload) {
+ if (payload.size() != 4) {
+ return nullptr;
+ }
+ TAutoPtr<TSimpleMessage> r(new TSimpleMessage);
+ memcpy(&r->Payload, payload.data(), 4);
+ return r.Release();
+}
diff --git a/library/cpp/messagebus/test/perftest/simple_proto.h b/library/cpp/messagebus/test/perftest/simple_proto.h
new file mode 100644
index 0000000000..4a0cc08db3
--- /dev/null
+++ b/library/cpp/messagebus/test/perftest/simple_proto.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <library/cpp/messagebus/ybus.h>
+
+struct TSimpleMessage: public NBus::TBusMessage {
+ ui32 Payload;
+
+ TSimpleMessage()
+ : TBusMessage(1)
+ , Payload(0)
+ {
+ }
+
+ TSimpleMessage(NBus::ECreateUninitialized)
+ : TBusMessage(NBus::ECreateUninitialized())
+ {
+ }
+};
+
+struct TSimpleProtocol: public NBus::TBusProtocol {
+ TSimpleProtocol()
+ : NBus::TBusProtocol("simple", 55666)
+ {
+ }
+
+ void Serialize(const NBus::TBusMessage* mess, TBuffer& data) override;
+
+ TAutoPtr<NBus::TBusMessage> Deserialize(ui16 ty, TArrayRef<const char> payload) override;
+};
diff --git a/library/cpp/messagebus/test/perftest/stackcollect.diff b/library/cpp/messagebus/test/perftest/stackcollect.diff
new file mode 100644
index 0000000000..658f0141b3
--- /dev/null
+++ b/library/cpp/messagebus/test/perftest/stackcollect.diff
@@ -0,0 +1,13 @@
+Index: test/perftest/CMakeLists.txt
+===================================================================
+--- test/perftest/CMakeLists.txt (revision 1088840)
++++ test/perftest/CMakeLists.txt (working copy)
+@@ -3,7 +3,7 @@ PROGRAM(messagebus_perftest)
+ OWNER(nga)
+
+ PEERDIR(
+- library/cpp/execprofile
++ junk/davenger/stackcollect
+ library/cpp/messagebus
+ library/cpp/messagebus/protobuf
+ library/cpp/sighandler
diff --git a/library/cpp/messagebus/test/perftest/ya.make b/library/cpp/messagebus/test/perftest/ya.make
new file mode 100644
index 0000000000..24c2848ed5
--- /dev/null
+++ b/library/cpp/messagebus/test/perftest/ya.make
@@ -0,0 +1,24 @@
+PROGRAM(messagebus_perftest)
+
+OWNER(g:messagebus)
+
+PEERDIR(
+ library/cpp/deprecated/threadable
+ library/cpp/execprofile
+ library/cpp/getopt
+ library/cpp/lwtrace
+ library/cpp/messagebus
+ library/cpp/messagebus/oldmodule
+ library/cpp/messagebus/protobuf
+ library/cpp/messagebus/www
+ library/cpp/sighandler
+ library/cpp/threading/future
+)
+
+SRCS(
+ messages.proto
+ perftest.cpp
+ simple_proto.cpp
+)
+
+END()
diff --git a/library/cpp/messagebus/test/ut/count_down_latch.h b/library/cpp/messagebus/test/ut/count_down_latch.h
new file mode 100644
index 0000000000..5117db5731
--- /dev/null
+++ b/library/cpp/messagebus/test/ut/count_down_latch.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <util/system/atomic.h>
+#include <util/system/event.h>
+
+class TCountDownLatch {
+private:
+ TAtomic Current;
+ TSystemEvent EventObject;
+
+public:
+ TCountDownLatch(unsigned initial)
+ : Current(initial)
+ {
+ }
+
+ void CountDown() {
+ if (AtomicDecrement(Current) == 0) {
+ EventObject.Signal();
+ }
+ }
+
+ void Await() {
+ EventObject.Wait();
+ }
+
+ bool Await(TDuration timeout) {
+ return EventObject.WaitT(timeout);
+ }
+};
diff --git a/library/cpp/messagebus/test/ut/locator_uniq_ut.cpp b/library/cpp/messagebus/test/ut/locator_uniq_ut.cpp
new file mode 100644
index 0000000000..3fdd175d73
--- /dev/null
+++ b/library/cpp/messagebus/test/ut/locator_uniq_ut.cpp
@@ -0,0 +1,40 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/messagebus/test_utils.h>
+#include <library/cpp/messagebus/ybus.h>
+
+class TLocatorRegisterUniqTest: public TTestBase {
+ UNIT_TEST_SUITE(TLocatorRegisterUniqTest);
+ UNIT_TEST(TestRegister);
+ UNIT_TEST_SUITE_END();
+
+protected:
+ void TestRegister();
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TLocatorRegisterUniqTest);
+
+void TLocatorRegisterUniqTest::TestRegister() {
+ ASSUME_IP_V4_ENABLED;
+
+ NBus::TBusLocator locator;
+ const char* serviceName = "TestService";
+ const char* hostName = "192.168.0.42";
+ int port = 31337;
+
+ NBus::TBusKeyVec keys;
+ locator.LocateKeys(serviceName, keys);
+ UNIT_ASSERT(keys.size() == 0);
+
+ locator.Register(serviceName, hostName, port);
+ locator.LocateKeys(serviceName, keys);
+ /// YBUS_KEYMIN YBUS_KEYMAX range
+ UNIT_ASSERT(keys.size() == 1);
+
+ TVector<NBus::TNetAddr> hosts;
+ UNIT_ASSERT(locator.LocateAll(serviceName, NBus::YBUS_KEYMIN, hosts) == 1);
+
+ locator.Register(serviceName, hostName, port);
+ hosts.clear();
+ UNIT_ASSERT(locator.LocateAll(serviceName, NBus::YBUS_KEYMIN, hosts) == 1);
+}
diff --git a/library/cpp/messagebus/test/ut/messagebus_ut.cpp b/library/cpp/messagebus/test/ut/messagebus_ut.cpp
new file mode 100644
index 0000000000..040f9b7702
--- /dev/null
+++ b/library/cpp/messagebus/test/ut/messagebus_ut.cpp
@@ -0,0 +1,1151 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/messagebus/test/helper/example.h>
+#include <library/cpp/messagebus/test/helper/fixed_port.h>
+#include <library/cpp/messagebus/test/helper/hanging_server.h>
+#include <library/cpp/messagebus/test/helper/object_count_check.h>
+#include <library/cpp/messagebus/test/helper/wait_for.h>
+
+#include <library/cpp/messagebus/misc/test_sync.h>
+
+#include <util/network/sock.h>
+
+#include <utility>
+
+using namespace NBus;
+using namespace NBus::NTest;
+
+namespace {
+ struct TExampleClientSlowOnMessageSent: public TExampleClient {
+ TAtomic SentCompleted;
+
+ TSystemEvent ReplyReceived;
+
+ TExampleClientSlowOnMessageSent()
+ : SentCompleted(0)
+ {
+ }
+
+ ~TExampleClientSlowOnMessageSent() override {
+ Session->Shutdown();
+ }
+
+ void OnReply(TAutoPtr<TBusMessage> mess, TAutoPtr<TBusMessage> reply) override {
+ Y_VERIFY(AtomicGet(SentCompleted), "must be completed");
+
+ TExampleClient::OnReply(mess, reply);
+
+ ReplyReceived.Signal();
+ }
+
+ void OnMessageSent(TBusMessage*) override {
+ Sleep(TDuration::MilliSeconds(100));
+ AtomicSet(SentCompleted, 1);
+ }
+ };
+
+}
+
+Y_UNIT_TEST_SUITE(TMessageBusTests) {
+ void TestDestinationTemplate(bool useCompression, bool ackMessageBeforeReply,
+ const TBusServerSessionConfig& sessionConfig) {
+ TObjectCountCheck objectCountCheck;
+
+ TExampleServer server;
+
+ TExampleClient client(sessionConfig);
+ client.CrashOnError = true;
+
+ server.UseCompression = useCompression;
+ client.UseCompression = useCompression;
+
+ server.AckMessageBeforeSendReply = ackMessageBeforeReply;
+
+ client.SendMessagesWaitReplies(100, server.GetActualListenAddr());
+ UNIT_ASSERT_EQUAL(server.Session->GetInFlight(), 0);
+ UNIT_ASSERT_EQUAL(client.Session->GetInFlight(), 0);
+ }
+
+ Y_UNIT_TEST(TestDestination) {
+ TestDestinationTemplate(false, false, TBusServerSessionConfig());
+ }
+
+ Y_UNIT_TEST(TestDestinationUsingAck) {
+ TestDestinationTemplate(false, true, TBusServerSessionConfig());
+ }
+
+ Y_UNIT_TEST(TestDestinationWithCompression) {
+ TestDestinationTemplate(true, false, TBusServerSessionConfig());
+ }
+
+ Y_UNIT_TEST(TestCork) {
+ TBusServerSessionConfig config;
+ config.SendThreshold = 1000000000000;
+ config.Cork = TDuration::MilliSeconds(10);
+ TestDestinationTemplate(false, false, config);
+ // TODO: test for cork hanging
+ }
+
+ Y_UNIT_TEST(TestReconnect) {
+ if (!IsFixedPortTestAllowed()) {
+ return;
+ }
+
+ TObjectCountCheck objectCountCheck;
+
+ unsigned port = FixedPort;
+ TNetAddr serverAddr("localhost", port);
+ THolder<TExampleServer> server;
+
+ TBusClientSessionConfig clientConfig;
+ clientConfig.RetryInterval = 0;
+ TExampleClient client(clientConfig);
+
+ server.Reset(new TExampleServer(port, "TExampleServer 1"));
+
+ client.SendMessagesWaitReplies(17, serverAddr);
+
+ server.Destroy();
+
+ // Making the client to detect disconnection.
+ client.SendMessages(1, serverAddr);
+ EMessageStatus error = client.WaitForError();
+ if (error == MESSAGE_DELIVERY_FAILED) {
+ client.SendMessages(1, serverAddr);
+ error = client.WaitForError();
+ }
+ UNIT_ASSERT_VALUES_EQUAL(MESSAGE_CONNECT_FAILED, error);
+
+ server.Reset(new TExampleServer(port, "TExampleServer 2"));
+
+ client.SendMessagesWaitReplies(19, serverAddr);
+ }
+
+ struct TestNoServerImplClient: public TExampleClient {
+ TTestSync TestSync;
+ int failures = 0;
+
+ template <typename... Args>
+ TestNoServerImplClient(Args&&... args)
+ : TExampleClient(std::forward<Args>(args)...)
+ {
+ }
+
+ ~TestNoServerImplClient() override {
+ Session->Shutdown();
+ }
+
+ void OnError(TAutoPtr<TBusMessage> message, EMessageStatus status) override {
+ Y_UNUSED(message);
+
+ Y_VERIFY(status == MESSAGE_CONNECT_FAILED, "must be MESSAGE_CONNECT_FAILED, got %s", ToString(status).data());
+
+ TestSync.CheckAndIncrement((failures++) * 2);
+ }
+ };
+
+ void TestNoServerImpl(unsigned port, bool oneWay) {
+ TNetAddr noServerAddr("localhost", port);
+
+ TestNoServerImplClient client;
+
+ int count = 0;
+ for (; count < 200; ++count) {
+ EMessageStatus status;
+ if (oneWay) {
+ status = client.Session->SendMessageOneWay(new TExampleRequest(&client.Proto.RequestCount), &noServerAddr);
+ } else {
+ TAutoPtr<TBusMessage> message(new TExampleRequest(&client.Proto.RequestCount));
+ status = client.Session->SendMessageAutoPtr(message, &noServerAddr);
+ }
+
+ Y_VERIFY(status == MESSAGE_OK, "must be MESSAGE_OK, got %s", ToString(status).data());
+
+ if (count == 0) {
+ // lame way to wait until it is connected
+ Sleep(TDuration::MilliSeconds(10));
+ }
+ client.TestSync.WaitForAndIncrement(count * 2 + 1);
+ }
+
+ client.TestSync.WaitForAndIncrement(count * 2);
+ }
+
+ void HangingServerImpl(unsigned port) {
+ TNetAddr noServerAddr("localhost", port);
+
+ TExampleClient client;
+
+ int count = 0;
+ for (;; ++count) {
+ TAutoPtr<TBusMessage> message(new TExampleRequest(&client.Proto.RequestCount));
+ EMessageStatus status = client.Session->SendMessageAutoPtr(message, &noServerAddr);
+ if (status == MESSAGE_BUSY) {
+ break;
+ }
+ UNIT_ASSERT_VALUES_EQUAL(int(MESSAGE_OK), int(status));
+
+ if (count == 0) {
+ // lame way to wait until it is connected
+ Sleep(TDuration::MilliSeconds(10));
+ }
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(client.Session->GetConfig()->MaxInFlight, count);
+ }
+
+ Y_UNIT_TEST(TestHangindServer) {
+ TObjectCountCheck objectCountCheck;
+
+ THangingServer server(0);
+
+ HangingServerImpl(server.GetPort());
+ }
+
+ Y_UNIT_TEST(TestNoServer) {
+ TObjectCountCheck objectCountCheck;
+
+ TestNoServerImpl(17, false);
+ }
+
+ Y_UNIT_TEST(PauseInput) {
+ TObjectCountCheck objectCountCheck;
+
+ TExampleServer server;
+ server.Session->PauseInput(true);
+
+ TBusClientSessionConfig clientConfig;
+ clientConfig.MaxInFlight = 1000;
+ TExampleClient client(clientConfig);
+
+ client.SendMessages(100, server.GetActualListenAddr());
+
+ server.TestSync.Check(0);
+
+ server.Session->PauseInput(false);
+
+ server.TestSync.WaitFor(100);
+
+ client.WaitReplies();
+
+ server.Session->PauseInput(true);
+
+ client.SendMessages(200, server.GetActualListenAddr());
+
+ server.TestSync.Check(100);
+
+ server.Session->PauseInput(false);
+
+ server.TestSync.WaitFor(300);
+
+ client.WaitReplies();
+ }
+
+ struct TSendTimeoutCheckerExampleClient: public TExampleClient {
+ static TBusClientSessionConfig SessionConfig(bool periodLessThanConnectTimeout) {
+ TBusClientSessionConfig sessionConfig;
+ if (periodLessThanConnectTimeout) {
+ sessionConfig.SendTimeout = 1;
+ sessionConfig.Secret.TimeoutPeriod = TDuration::MilliSeconds(50);
+ } else {
+ sessionConfig.SendTimeout = 50;
+ sessionConfig.Secret.TimeoutPeriod = TDuration::MilliSeconds(1);
+ }
+ return sessionConfig;
+ }
+
+ TSendTimeoutCheckerExampleClient(bool periodLessThanConnectTimeout)
+ : TExampleClient(SessionConfig(periodLessThanConnectTimeout))
+ {
+ }
+
+ ~TSendTimeoutCheckerExampleClient() override {
+ Session->Shutdown();
+ }
+
+ TSystemEvent ErrorHappened;
+
+ void OnError(TAutoPtr<TBusMessage>, EMessageStatus status) override {
+ Y_VERIFY(status == MESSAGE_CONNECT_FAILED || status == MESSAGE_TIMEOUT, "got status: %s", ToString(status).data());
+ ErrorHappened.Signal();
+ }
+ };
+
+ void NoServer_SendTimeout_Callback_Impl(bool periodLessThanConnectTimeout) {
+ TObjectCountCheck objectCountCheck;
+
+ TNetAddr serverAddr("localhost", 17);
+
+ TSendTimeoutCheckerExampleClient client(periodLessThanConnectTimeout);
+
+ client.SendMessages(1, serverAddr);
+
+ client.ErrorHappened.WaitI();
+ }
+
+ Y_UNIT_TEST(NoServer_SendTimeout_Callback_PeriodLess) {
+ NoServer_SendTimeout_Callback_Impl(true);
+ }
+
+ Y_UNIT_TEST(NoServer_SendTimeout_Callback_TimeoutLess) {
+ NoServer_SendTimeout_Callback_Impl(false);
+ }
+
+ Y_UNIT_TEST(TestOnReplyCalledAfterOnMessageSent) {
+ TObjectCountCheck objectCountCheck;
+
+ TExampleServer server;
+ TNetAddr serverAddr = server.GetActualListenAddr();
+ TExampleClientSlowOnMessageSent client;
+
+ TAutoPtr<TExampleRequest> message(new TExampleRequest(&client.Proto.RequestCount));
+ EMessageStatus s = client.Session->SendMessageAutoPtr(message, &serverAddr);
+ UNIT_ASSERT_EQUAL(s, MESSAGE_OK);
+
+ UNIT_ASSERT(client.ReplyReceived.WaitT(TDuration::Seconds(5)));
+ }
+
+ struct TDelayReplyServer: public TBusServerHandlerError {
+ TBusMessageQueuePtr Bus;
+ TExampleProtocol Proto;
+ TSystemEvent MessageReceivedEvent; // 1 wait for 1 message
+ TBusServerSessionPtr Session;
+ TMutex Lock_;
+ TDeque<TAutoPtr<TOnMessageContext>> DelayedMessages;
+
+ TDelayReplyServer()
+ : MessageReceivedEvent(TEventResetType::rAuto)
+ {
+ Bus = CreateMessageQueue("TDelayReplyServer");
+ TBusServerSessionConfig sessionConfig;
+ sessionConfig.SendTimeout = 1000;
+ sessionConfig.TotalTimeout = 2001;
+ Session = TBusServerSession::Create(&Proto, this, sessionConfig, Bus);
+ if (!Session) {
+ ythrow yexception() << "Failed to create destination session";
+ }
+ }
+
+ void OnMessage(TOnMessageContext& mess) override {
+ Y_VERIFY(mess.IsConnectionAlive(), "connection should be alive here");
+ TAutoPtr<TOnMessageContext> delayedMsg(new TOnMessageContext);
+ delayedMsg->Swap(mess);
+ auto g(Guard(Lock_));
+ DelayedMessages.push_back(delayedMsg);
+ MessageReceivedEvent.Signal();
+ }
+
+ bool CheckClientIsAlive() {
+ auto g(Guard(Lock_));
+ for (auto& delayedMessage : DelayedMessages) {
+ if (!delayedMessage->IsConnectionAlive()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool CheckClientIsDead() const {
+ auto g(Guard(Lock_));
+ for (const auto& delayedMessage : DelayedMessages) {
+ if (delayedMessage->IsConnectionAlive()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void ReplyToDelayedMessages() {
+ while (true) {
+ TOnMessageContext msg;
+ {
+ auto g(Guard(Lock_));
+ if (DelayedMessages.empty()) {
+ break;
+ }
+ DelayedMessages.front()->Swap(msg);
+ DelayedMessages.pop_front();
+ }
+ TAutoPtr<TBusMessage> reply(new TExampleResponse(&Proto.ResponseCount));
+ msg.SendReplyMove(reply);
+ }
+ }
+
+ size_t GetDelayedMessageCount() const {
+ auto g(Guard(Lock_));
+ return DelayedMessages.size();
+ }
+
+ void OnError(TAutoPtr<TBusMessage> mess, EMessageStatus status) override {
+ Y_UNUSED(mess);
+ Y_VERIFY(status == MESSAGE_SHUTDOWN, "only shutdown allowed, got %s", ToString(status).data());
+ }
+ };
+
+ Y_UNIT_TEST(TestReplyCalledAfterClientDisconnected) {
+ TObjectCountCheck objectCountCheck;
+
+ TDelayReplyServer server;
+
+ THolder<TExampleClient> client(new TExampleClient);
+
+ client->SendMessages(1, TNetAddr("localhost", server.Session->GetActualListenPort()));
+
+ UNIT_ASSERT(server.MessageReceivedEvent.WaitT(TDuration::Seconds(5)));
+
+ UNIT_ASSERT_VALUES_EQUAL(1, server.Session->GetInFlight());
+
+ client.Destroy();
+
+ UNIT_WAIT_FOR(server.CheckClientIsDead());
+
+ server.ReplyToDelayedMessages();
+
+ // wait until all server message are delivered
+ UNIT_WAIT_FOR(0 == server.Session->GetInFlight());
+ }
+
+ struct TPackUnpackServer: public TBusServerHandlerError {
+ TBusMessageQueuePtr Bus;
+ TExampleProtocol Proto;
+ TSystemEvent MessageReceivedEvent;
+ TSystemEvent ClientDiedEvent;
+ TBusServerSessionPtr Session;
+
+ TPackUnpackServer() {
+ Bus = CreateMessageQueue("TPackUnpackServer");
+ TBusServerSessionConfig sessionConfig;
+ Session = TBusServerSession::Create(&Proto, this, sessionConfig, Bus);
+ }
+
+ void OnMessage(TOnMessageContext& mess) override {
+ TBusIdentity ident;
+ mess.AckMessage(ident);
+
+ char packed[BUS_IDENTITY_PACKED_SIZE];
+ ident.Pack(packed);
+ TBusIdentity resurrected;
+ resurrected.Unpack(packed);
+
+ mess.GetSession()->SendReply(resurrected, new TExampleResponse(&Proto.ResponseCount));
+ }
+
+ void OnError(TAutoPtr<TBusMessage> mess, EMessageStatus status) override {
+ Y_UNUSED(mess);
+ Y_VERIFY(status == MESSAGE_SHUTDOWN, "only shutdown allowed");
+ }
+ };
+
+ Y_UNIT_TEST(PackUnpack) {
+ TObjectCountCheck objectCountCheck;
+
+ TPackUnpackServer server;
+
+ THolder<TExampleClient> client(new TExampleClient);
+
+ client->SendMessagesWaitReplies(1, TNetAddr("localhost", server.Session->GetActualListenPort()));
+ }
+
+ Y_UNIT_TEST(ClientRequestTooLarge) {
+ TObjectCountCheck objectCountCheck;
+
+ TExampleServer server;
+
+ TBusClientSessionConfig clientConfig;
+ clientConfig.MaxMessageSize = 100;
+ TExampleClient client(clientConfig);
+
+ client.DataSize = 10;
+ client.SendMessagesWaitReplies(1, server.GetActualListenAddr());
+
+ client.DataSize = 1000;
+ client.SendMessages(1, server.GetActualListenAddr());
+ client.WaitForError(MESSAGE_MESSAGE_TOO_LARGE);
+
+ client.DataSize = 20;
+ client.SendMessagesWaitReplies(10, server.GetActualListenAddr());
+
+ client.DataSize = 10000;
+ client.SendMessages(1, server.GetActualListenAddr());
+ client.WaitForError(MESSAGE_MESSAGE_TOO_LARGE);
+ }
+
+ struct TServerForResponseTooLarge: public TExampleServer {
+ TTestSync TestSync;
+
+ static TBusServerSessionConfig Config() {
+ TBusServerSessionConfig config;
+ config.MaxMessageSize = 100;
+ return config;
+ }
+
+ TServerForResponseTooLarge()
+ : TExampleServer("TServerForResponseTooLarge", Config())
+ {
+ }
+
+ ~TServerForResponseTooLarge() override {
+ Session->Shutdown();
+ }
+
+ void OnMessage(TOnMessageContext& mess) override {
+ TAutoPtr<TBusMessage> response;
+
+ if (TestSync.Get() == 0) {
+ TestSync.CheckAndIncrement(0);
+ response.Reset(new TExampleResponse(&Proto.ResponseCount, 1000));
+ } else {
+ TestSync.WaitForAndIncrement(3);
+ response.Reset(new TExampleResponse(&Proto.ResponseCount, 10));
+ }
+
+ mess.SendReplyMove(response);
+ }
+
+ void OnError(TAutoPtr<TBusMessage>, EMessageStatus status) override {
+ TestSync.WaitForAndIncrement(1);
+
+ Y_VERIFY(status == MESSAGE_MESSAGE_TOO_LARGE, "status");
+ }
+ };
+
+ Y_UNIT_TEST(ServerResponseTooLarge) {
+ TObjectCountCheck objectCountCheck;
+
+ TServerForResponseTooLarge server;
+
+ TExampleClient client;
+ client.DataSize = 10;
+
+ client.SendMessages(1, server.GetActualListenAddr());
+ server.TestSync.WaitForAndIncrement(2);
+ client.ResetCounters();
+
+ client.SendMessages(1, server.GetActualListenAddr());
+
+ client.WorkDone.WaitI();
+
+ server.TestSync.CheckAndIncrement(4);
+
+ UNIT_ASSERT_VALUES_EQUAL(1, client.Session->GetInFlight());
+ }
+
+ struct TServerForRequestTooLarge: public TExampleServer {
+ TTestSync TestSync;
+
+ static TBusServerSessionConfig Config() {
+ TBusServerSessionConfig config;
+ config.MaxMessageSize = 100;
+ return config;
+ }
+
+ TServerForRequestTooLarge()
+ : TExampleServer("TServerForRequestTooLarge", Config())
+ {
+ }
+
+ ~TServerForRequestTooLarge() override {
+ Session->Shutdown();
+ }
+
+ void OnMessage(TOnMessageContext& req) override {
+ unsigned n = TestSync.Get();
+ if (n < 2) {
+ TestSync.CheckAndIncrement(n);
+ TAutoPtr<TExampleResponse> resp(new TExampleResponse(&Proto.ResponseCount, 10));
+ req.SendReplyMove(resp);
+ } else {
+ Y_FAIL("wrong");
+ }
+ }
+ };
+
+ Y_UNIT_TEST(ServerRequestTooLarge) {
+ TObjectCountCheck objectCountCheck;
+
+ TServerForRequestTooLarge server;
+
+ TExampleClient client;
+ client.DataSize = 10;
+
+ client.SendMessagesWaitReplies(2, server.GetActualListenAddr());
+
+ server.TestSync.CheckAndIncrement(2);
+
+ client.DataSize = 200;
+ client.SendMessages(1, server.GetActualListenAddr());
+ // server closes connection, so MESSAGE_DELIVERY_FAILED is returned to client
+ client.WaitForError(MESSAGE_DELIVERY_FAILED);
+ }
+
+ Y_UNIT_TEST(ClientResponseTooLarge) {
+ TObjectCountCheck objectCountCheck;
+
+ TExampleServer server;
+
+ server.DataSize = 10;
+
+ TBusClientSessionConfig clientSessionConfig;
+ clientSessionConfig.MaxMessageSize = 100;
+ TExampleClient client(clientSessionConfig);
+ client.DataSize = 10;
+
+ client.SendMessagesWaitReplies(3, server.GetActualListenAddr());
+
+ server.DataSize = 1000;
+
+ client.SendMessages(1, server.GetActualListenAddr());
+ client.WaitForError(MESSAGE_DELIVERY_FAILED);
+ }
+
+ Y_UNIT_TEST(ServerUnknownMessage) {
+ TObjectCountCheck objectCountCheck;
+
+ TExampleServer server;
+ TNetAddr serverAddr = server.GetActualListenAddr();
+
+ TExampleClient client;
+
+ client.SendMessagesWaitReplies(2, serverAddr);
+
+ TAutoPtr<TBusMessage> req(new TExampleRequest(&client.Proto.RequestCount));
+ req->GetHeader()->Type = 11;
+ client.Session->SendMessageAutoPtr(req, &serverAddr);
+ client.MessageCount = 1;
+
+ client.WaitForError(MESSAGE_DELIVERY_FAILED);
+ }
+
+ Y_UNIT_TEST(ServerMessageReservedIds) {
+ TObjectCountCheck objectCountCheck;
+
+ TExampleServer server;
+ TNetAddr serverAddr = server.GetActualListenAddr();
+
+ TExampleClient client;
+
+ client.SendMessagesWaitReplies(2, serverAddr);
+
+ // This test doens't check 0, 1, YBUS_KEYINVALID because there are asserts() on sending side
+
+ TAutoPtr<TBusMessage> req(new TExampleRequest(&client.Proto.RequestCount));
+ req->GetHeader()->Id = 2;
+ client.Session->SendMessageAutoPtr(req, &serverAddr);
+ client.MessageCount = 1;
+ client.WaitForError(MESSAGE_DELIVERY_FAILED);
+
+ req.Reset(new TExampleRequest(&client.Proto.RequestCount));
+ req->GetHeader()->Id = YBUS_KEYLOCAL;
+ client.Session->SendMessageAutoPtr(req, &serverAddr);
+ client.MessageCount = 1;
+ client.WaitForError(MESSAGE_DELIVERY_FAILED);
+ }
+
+ Y_UNIT_TEST(TestGetInFlightForDestination) {
+ TObjectCountCheck objectCountCheck;
+
+ TDelayReplyServer server;
+
+ TExampleClient client;
+
+ TNetAddr addr("localhost", server.Session->GetActualListenPort());
+
+ UNIT_ASSERT_VALUES_EQUAL(size_t(0), client.Session->GetInFlight(addr));
+
+ client.SendMessages(2, &addr);
+
+ for (size_t i = 0; i < 5; ++i) {
+ // One MessageReceivedEvent indicates one message, we need to wait for two
+ UNIT_ASSERT(server.MessageReceivedEvent.WaitT(TDuration::Seconds(5)));
+ if (server.GetDelayedMessageCount() == 2) {
+ break;
+ }
+ }
+ UNIT_ASSERT_VALUES_EQUAL(server.GetDelayedMessageCount(), 2);
+
+ size_t inFlight = client.Session->GetInFlight(addr);
+ // 4 is for messagebus1 that adds inFlight counter twice for some reason
+ UNIT_ASSERT(inFlight == 2 || inFlight == 4);
+
+ UNIT_ASSERT(server.CheckClientIsAlive());
+
+ server.ReplyToDelayedMessages();
+
+ client.WaitReplies();
+ }
+
+ struct TResetAfterSendOneWayErrorInCallbackClient: public TExampleClient {
+ TTestSync TestSync;
+
+ static TBusClientSessionConfig SessionConfig() {
+ TBusClientSessionConfig config;
+ // 1 ms is not enough when test is running under valgrind
+ config.ConnectTimeout = 10;
+ config.SendTimeout = 10;
+ config.Secret.TimeoutPeriod = TDuration::MilliSeconds(1);
+ return config;
+ }
+
+ TResetAfterSendOneWayErrorInCallbackClient()
+ : TExampleClient(SessionConfig())
+ {
+ }
+
+ ~TResetAfterSendOneWayErrorInCallbackClient() override {
+ Session->Shutdown();
+ }
+
+ void OnError(TAutoPtr<TBusMessage> mess, EMessageStatus status) override {
+ TestSync.WaitForAndIncrement(0);
+ Y_VERIFY(status == MESSAGE_CONNECT_FAILED || status == MESSAGE_TIMEOUT, "must be connection failed, got %s", ToString(status).data());
+ mess.Destroy();
+ TestSync.CheckAndIncrement(1);
+ }
+ };
+
+ Y_UNIT_TEST(ResetAfterSendOneWayErrorInCallback) {
+ TObjectCountCheck objectCountCheck;
+
+ TNetAddr noServerAddr("localhost", 17);
+
+ TResetAfterSendOneWayErrorInCallbackClient client;
+
+ EMessageStatus ok = client.Session->SendMessageOneWayMove(new TExampleRequest(&client.Proto.RequestCount), &noServerAddr);
+ UNIT_ASSERT_VALUES_EQUAL(MESSAGE_OK, ok);
+
+ client.TestSync.WaitForAndIncrement(2);
+ }
+
+ struct TResetAfterSendMessageOneWayDuringShutdown: public TExampleClient {
+ TTestSync TestSync;
+
+ ~TResetAfterSendMessageOneWayDuringShutdown() override {
+ Session->Shutdown();
+ }
+
+ void OnError(TAutoPtr<TBusMessage> message, EMessageStatus status) override {
+ TestSync.CheckAndIncrement(0);
+
+ Y_VERIFY(status == MESSAGE_CONNECT_FAILED, "must be MESSAGE_CONNECT_FAILED, got %s", ToString(status).data());
+
+ // check reset is possible here
+ message->Reset();
+
+ // intentionally don't destroy the message
+ // we will try to resend it
+ Y_UNUSED(message.Release());
+
+ TestSync.CheckAndIncrement(1);
+ }
+ };
+
+ Y_UNIT_TEST(ResetAfterSendMessageOneWayDuringShutdown) {
+ TObjectCountCheck objectCountCheck;
+
+ TNetAddr noServerAddr("localhost", 17);
+
+ TResetAfterSendMessageOneWayDuringShutdown client;
+
+ TExampleRequest* message = new TExampleRequest(&client.Proto.RequestCount);
+ EMessageStatus ok = client.Session->SendMessageOneWay(message, &noServerAddr);
+ UNIT_ASSERT_VALUES_EQUAL(MESSAGE_OK, ok);
+
+ client.TestSync.WaitForAndIncrement(2);
+
+ client.Session->Shutdown();
+
+ ok = client.Session->SendMessageOneWay(message);
+ Y_VERIFY(ok == MESSAGE_SHUTDOWN, "must be shutdown when sending during shutdown, got %s", ToString(ok).data());
+
+ // check reset is possible here
+ message->Reset();
+ client.TestSync.CheckAndIncrement(3);
+
+ delete message;
+ }
+
+ Y_UNIT_TEST(ResetAfterSendOneWayErrorInReturn) {
+ TObjectCountCheck objectCountCheck;
+
+ TestNoServerImpl(17, true);
+ }
+
+ struct TResetAfterSendOneWaySuccessClient: public TExampleClient {
+ TTestSync TestSync;
+
+ ~TResetAfterSendOneWaySuccessClient() override {
+ Session->Shutdown();
+ }
+
+ void OnMessageSentOneWay(TAutoPtr<TBusMessage> sent) override {
+ TestSync.WaitForAndIncrement(0);
+ sent->Reset();
+ TestSync.CheckAndIncrement(1);
+ }
+ };
+
+ Y_UNIT_TEST(ResetAfterSendOneWaySuccess) {
+ TObjectCountCheck objectCountCheck;
+
+ TExampleServer server;
+ TNetAddr serverAddr = server.GetActualListenAddr();
+
+ TResetAfterSendOneWaySuccessClient client;
+
+ EMessageStatus ok = client.Session->SendMessageOneWay(new TExampleRequest(&client.Proto.RequestCount), &serverAddr);
+ UNIT_ASSERT_VALUES_EQUAL(MESSAGE_OK, ok);
+ // otherwize message might go to OnError(MESSAGE_SHUTDOWN)
+ server.WaitForOnMessageCount(1);
+
+ client.TestSync.WaitForAndIncrement(2);
+ }
+
+ Y_UNIT_TEST(GetStatus) {
+ TObjectCountCheck objectCountCheck;
+
+ TExampleServer server;
+
+ TExampleClient client;
+ // make sure connected
+ client.SendMessagesWaitReplies(3, server.GetActualListenAddr());
+
+ server.Bus->GetStatus();
+ server.Bus->GetStatus();
+ server.Bus->GetStatus();
+
+ client.Bus->GetStatus();
+ client.Bus->GetStatus();
+ client.Bus->GetStatus();
+ }
+
+ Y_UNIT_TEST(BindOnRandomPort) {
+ TObjectCountCheck objectCountCheck;
+
+ TBusServerSessionConfig serverConfig;
+ TExampleServer server;
+
+ TExampleClient client;
+ TNetAddr addr(TNetAddr("127.0.0.1", server.Session->GetActualListenPort()));
+ client.SendMessagesWaitReplies(3, &addr);
+ }
+
+ Y_UNIT_TEST(UnbindOnShutdown) {
+ TBusMessageQueuePtr queue(CreateMessageQueue());
+
+ TExampleProtocol proto;
+ TBusServerHandlerError handler;
+ TBusServerSessionPtr session = TBusServerSession::Create(
+ &proto, &handler, TBusServerSessionConfig(), queue);
+
+ unsigned port = session->GetActualListenPort();
+ UNIT_ASSERT(port > 0);
+
+ session->Shutdown();
+
+ // fails is Shutdown() didn't unbind
+ THangingServer hangingServer(port);
+ }
+
+ Y_UNIT_TEST(VersionNegotiation) {
+ TObjectCountCheck objectCountCheck;
+
+ TExampleServer server;
+
+ TSockAddrInet addr(IpFromString("127.0.0.1"), server.Session->GetActualListenPort());
+
+ TInetStreamSocket socket;
+ int r1 = socket.Connect(&addr);
+ UNIT_ASSERT(r1 >= 0);
+
+ TStreamSocketOutput output(&socket);
+
+ TBusHeader request;
+ Zero(request);
+ request.Size = sizeof(request);
+ request.SetVersionInternal(0xF); // max
+ output.Write(&request, sizeof(request));
+
+ UNIT_ASSERT_VALUES_EQUAL(IsVersionNegotiation(request), true);
+
+ TStreamSocketInput input(&socket);
+
+ TBusHeader response;
+ size_t pos = 0;
+
+ while (pos < sizeof(response)) {
+ size_t count = input.Read(((char*)&response) + pos, sizeof(response) - pos);
+ pos += count;
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(sizeof(response), pos);
+
+ UNIT_ASSERT_VALUES_EQUAL(YBUS_VERSION, response.GetVersionInternal());
+ }
+
+ struct TOnConnectionEventClient: public TExampleClient {
+ TTestSync Sync;
+
+ ~TOnConnectionEventClient() override {
+ Session->Shutdown();
+ }
+
+ void OnClientConnectionEvent(const TClientConnectionEvent& event) override {
+ if (Sync.Get() > 2) {
+ // Test OnClientConnectionEvent_Disconnect is broken.
+ // Sometimes reconnect happens during server shutdown
+ // when acceptor connections is still alive, and
+ // server connection is already closed
+ return;
+ }
+
+ if (event.GetType() == TClientConnectionEvent::CONNECTED) {
+ Sync.WaitForAndIncrement(0);
+ } else if (event.GetType() == TClientConnectionEvent::DISCONNECTED) {
+ Sync.WaitForAndIncrement(2);
+ }
+ }
+
+ void OnError(TAutoPtr<TBusMessage>, EMessageStatus) override {
+ // We do not check for message errors in this test.
+ }
+
+ void OnMessageSentOneWay(TAutoPtr<TBusMessage>) override {
+ }
+ };
+
+ struct TOnConnectionEventServer: public TExampleServer {
+ TOnConnectionEventServer()
+ : TExampleServer("TOnConnectionEventServer")
+ {
+ }
+
+ ~TOnConnectionEventServer() override {
+ Session->Shutdown();
+ }
+
+ void OnError(TAutoPtr<TBusMessage>, EMessageStatus) override {
+ // We do not check for server message errors in this test.
+ }
+ };
+
+ Y_UNIT_TEST(OnClientConnectionEvent_Shutdown) {
+ TObjectCountCheck objectCountCheck;
+
+ TOnConnectionEventServer server;
+
+ TOnConnectionEventClient client;
+
+ TNetAddr addr("127.0.0.1", server.Session->GetActualListenPort());
+
+ client.Session->SendMessageOneWay(new TExampleRequest(&client.Proto.RequestCount), &addr);
+
+ client.Sync.WaitForAndIncrement(1);
+
+ client.Session->Shutdown();
+
+ client.Sync.WaitForAndIncrement(3);
+ }
+
+ Y_UNIT_TEST(OnClientConnectionEvent_Disconnect) {
+ TObjectCountCheck objectCountCheck;
+
+ THolder<TOnConnectionEventServer> server(new TOnConnectionEventServer);
+
+ TOnConnectionEventClient client;
+ TNetAddr addr("127.0.0.1", server->Session->GetActualListenPort());
+
+ client.Session->SendMessageOneWay(new TExampleRequest(&client.Proto.RequestCount), &addr);
+
+ client.Sync.WaitForAndIncrement(1);
+
+ server.Destroy();
+
+ client.Sync.WaitForAndIncrement(3);
+ }
+
+ struct TServerForQuotaWake: public TExampleServer {
+ TSystemEvent GoOn;
+ TMutex OneLock;
+
+ TOnMessageContext OneMessage;
+
+ static TBusServerSessionConfig Config() {
+ TBusServerSessionConfig config;
+
+ config.PerConnectionMaxInFlight = 1;
+ config.PerConnectionMaxInFlightBySize = 1500;
+ config.MaxMessageSize = 1024;
+
+ return config;
+ }
+
+ TServerForQuotaWake()
+ : TExampleServer("TServerForQuotaWake", Config())
+ {
+ }
+
+ ~TServerForQuotaWake() override {
+ Session->Shutdown();
+ }
+
+ void OnMessage(TOnMessageContext& req) override {
+ if (!GoOn.Wait(0)) {
+ TGuard<TMutex> guard(OneLock);
+
+ UNIT_ASSERT(!OneMessage);
+
+ OneMessage.Swap(req);
+ } else
+ TExampleServer::OnMessage(req);
+ }
+
+ void WakeOne() {
+ TGuard<TMutex> guard(OneLock);
+
+ UNIT_ASSERT(!!OneMessage);
+
+ TExampleServer::OnMessage(OneMessage);
+
+ TOnMessageContext().Swap(OneMessage);
+ }
+ };
+
+ Y_UNIT_TEST(WakeReaderOnQuota) {
+ const size_t test_msg_count = 64;
+
+ TBusClientSessionConfig clientConfig;
+
+ clientConfig.MaxInFlight = test_msg_count;
+
+ TExampleClient client(clientConfig);
+ TServerForQuotaWake server;
+ TInstant start;
+
+ client.MessageCount = test_msg_count;
+
+ const NBus::TNetAddr addr = server.GetActualListenAddr();
+
+ for (unsigned count = 0;;) {
+ UNIT_ASSERT(count <= test_msg_count);
+
+ TAutoPtr<TBusMessage> message(new TExampleRequest(&client.Proto.RequestCount));
+ EMessageStatus status = client.Session->SendMessageAutoPtr(message, &addr);
+
+ if (status == MESSAGE_OK) {
+ count++;
+
+ } else if (status == MESSAGE_BUSY) {
+ if (count == test_msg_count) {
+ TInstant now = TInstant::Now();
+
+ if (start.GetValue() == 0) {
+ start = now;
+
+ // TODO: properly check that server is blocked
+ } else if (start + TDuration::MilliSeconds(100) < now) {
+ break;
+ }
+ }
+
+ Sleep(TDuration::MilliSeconds(10));
+
+ } else
+ UNIT_ASSERT(false);
+ }
+
+ server.GoOn.Signal();
+ server.WakeOne();
+
+ client.WaitReplies();
+
+ server.WaitForOnMessageCount(test_msg_count);
+ };
+
+ Y_UNIT_TEST(TestConnectionAttempts) {
+ TObjectCountCheck objectCountCheck;
+
+ TNetAddr noServerAddr("localhost", 17);
+ TBusClientSessionConfig clientConfig;
+ clientConfig.RetryInterval = 100;
+ TestNoServerImplClient client(clientConfig);
+
+ int count = 0;
+ for (; count < 10; ++count) {
+ EMessageStatus status = client.Session->SendMessageOneWay(new TExampleRequest(&client.Proto.RequestCount),
+ &noServerAddr);
+
+ Y_VERIFY(status == MESSAGE_OK, "must be MESSAGE_OK, got %s", ToString(status).data());
+ client.TestSync.WaitForAndIncrement(count * 2 + 1);
+
+ // First connection attempt is for connect call; second one is to get connect result.
+ UNIT_ASSERT_EQUAL(client.Session->GetConnectSyscallsNumForTest(noServerAddr), 2);
+ }
+ Sleep(TDuration::MilliSeconds(clientConfig.RetryInterval));
+ for (; count < 10; ++count) {
+ EMessageStatus status = client.Session->SendMessageOneWay(new TExampleRequest(&client.Proto.RequestCount),
+ &noServerAddr);
+
+ Y_VERIFY(status == MESSAGE_OK, "must be MESSAGE_OK, got %s", ToString(status).data());
+ client.TestSync.WaitForAndIncrement(count * 2 + 1);
+
+ // First connection attempt is for connect call; second one is to get connect result.
+ UNIT_ASSERT_EQUAL(client.Session->GetConnectSyscallsNumForTest(noServerAddr), 4);
+ }
+ };
+
+ Y_UNIT_TEST(TestConnectionAttemptsOnNoMessagesAndNotReconnectWhenIdle) {
+ TObjectCountCheck objectCountCheck;
+
+ TNetAddr noServerAddr("localhost", 17);
+ TBusClientSessionConfig clientConfig;
+ clientConfig.RetryInterval = 100;
+ clientConfig.ReconnectWhenIdle = false;
+ TestNoServerImplClient client(clientConfig);
+
+ int count = 0;
+ for (; count < 10; ++count) {
+ EMessageStatus status = client.Session->SendMessageOneWay(new TExampleRequest(&client.Proto.RequestCount),
+ &noServerAddr);
+
+ Y_VERIFY(status == MESSAGE_OK, "must be MESSAGE_OK, got %s", ToString(status).data());
+ client.TestSync.WaitForAndIncrement(count * 2 + 1);
+
+ // First connection attempt is for connect call; second one is to get connect result.
+ UNIT_ASSERT_EQUAL(client.Session->GetConnectSyscallsNumForTest(noServerAddr), 2);
+ }
+
+ Sleep(TDuration::MilliSeconds(clientConfig.RetryInterval / 2));
+ UNIT_ASSERT_EQUAL(client.Session->GetConnectSyscallsNumForTest(noServerAddr), 2);
+ Sleep(TDuration::MilliSeconds(10 * clientConfig.RetryInterval));
+ UNIT_ASSERT_EQUAL(client.Session->GetConnectSyscallsNumForTest(noServerAddr), 2);
+ };
+
+ Y_UNIT_TEST(TestConnectionAttemptsOnNoMessagesAndReconnectWhenIdle) {
+ TObjectCountCheck objectCountCheck;
+
+ TNetAddr noServerAddr("localhost", 17);
+ TBusClientSessionConfig clientConfig;
+ clientConfig.ReconnectWhenIdle = true;
+ clientConfig.RetryInterval = 100;
+ TestNoServerImplClient client(clientConfig);
+
+ int count = 0;
+ for (; count < 10; ++count) {
+ EMessageStatus status = client.Session->SendMessageOneWay(new TExampleRequest(&client.Proto.RequestCount),
+ &noServerAddr);
+
+ Y_VERIFY(status == MESSAGE_OK, "must be MESSAGE_OK, got %s", ToString(status).data());
+ client.TestSync.WaitForAndIncrement(count * 2 + 1);
+
+ // First connection attempt is for connect call; second one is to get connect result.
+ UNIT_ASSERT_VALUES_EQUAL(client.Session->GetConnectSyscallsNumForTest(noServerAddr), 2);
+ }
+
+ Sleep(TDuration::MilliSeconds(clientConfig.RetryInterval / 2));
+ UNIT_ASSERT_EQUAL(client.Session->GetConnectSyscallsNumForTest(noServerAddr), 2);
+ Sleep(TDuration::MilliSeconds(10 * clientConfig.RetryInterval));
+ // it is undeterministic how many reconnects will be during that amount of time
+ // but it should occur at least once
+ UNIT_ASSERT(client.Session->GetConnectSyscallsNumForTest(noServerAddr) > 2);
+ };
+};
diff --git a/library/cpp/messagebus/test/ut/module_client_one_way_ut.cpp b/library/cpp/messagebus/test/ut/module_client_one_way_ut.cpp
new file mode 100644
index 0000000000..4083cf3b7b
--- /dev/null
+++ b/library/cpp/messagebus/test/ut/module_client_one_way_ut.cpp
@@ -0,0 +1,143 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/messagebus/test/helper/example.h>
+#include <library/cpp/messagebus/test/helper/message_handler_error.h>
+
+#include <library/cpp/messagebus/misc/test_sync.h>
+#include <library/cpp/messagebus/oldmodule/module.h>
+
+using namespace NBus;
+using namespace NBus::NTest;
+
+Y_UNIT_TEST_SUITE(ModuleClientOneWay) {
+ struct TTestServer: public TBusServerHandlerError {
+ TExampleProtocol Proto;
+
+ TTestSync* const TestSync;
+
+ TBusMessageQueuePtr Queue;
+ TBusServerSessionPtr ServerSession;
+
+ TTestServer(TTestSync* testSync)
+ : TestSync(testSync)
+ {
+ Queue = CreateMessageQueue();
+ ServerSession = TBusServerSession::Create(&Proto, this, TBusServerSessionConfig(), Queue);
+ }
+
+ void OnMessage(TOnMessageContext& context) override {
+ TestSync->WaitForAndIncrement(1);
+ context.ForgetRequest();
+ }
+ };
+
+ struct TClientModule: public TBusModule {
+ TExampleProtocol Proto;
+
+ TTestSync* const TestSync;
+ unsigned const Port;
+
+ TBusClientSessionPtr ClientSession;
+
+ TClientModule(TTestSync* testSync, unsigned port)
+ : TBusModule("m")
+ , TestSync(testSync)
+ , Port(port)
+ {
+ }
+
+ TJobHandler Start(TBusJob* job, TBusMessage*) override {
+ TestSync->WaitForAndIncrement(0);
+
+ job->SendOneWayTo(new TExampleRequest(&Proto.RequestCount), ClientSession.Get(), TNetAddr("localhost", Port));
+
+ return &TClientModule::Sent;
+ }
+
+ TJobHandler Sent(TBusJob* job, TBusMessage*) {
+ TestSync->WaitForAndIncrement(2);
+ job->Cancel(MESSAGE_DONT_ASK);
+ return nullptr;
+ }
+
+ TBusServerSessionPtr CreateExtSession(TBusMessageQueue& queue) override {
+ ClientSession = CreateDefaultSource(queue, &Proto, TBusServerSessionConfig());
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(Simple) {
+ TTestSync testSync;
+
+ TTestServer server(&testSync);
+
+ TBusMessageQueuePtr queue = CreateMessageQueue();
+ TClientModule clientModule(&testSync, server.ServerSession->GetActualListenPort());
+
+ clientModule.CreatePrivateSessions(queue.Get());
+ clientModule.StartInput();
+
+ clientModule.StartJob(new TExampleRequest(&clientModule.Proto.StartCount));
+
+ testSync.WaitForAndIncrement(3);
+
+ clientModule.Shutdown();
+ }
+
+ struct TSendErrorModule: public TBusModule {
+ TExampleProtocol Proto;
+
+ TTestSync* const TestSync;
+
+ TBusClientSessionPtr ClientSession;
+
+ TSendErrorModule(TTestSync* testSync)
+ : TBusModule("m")
+ , TestSync(testSync)
+ {
+ }
+
+ TJobHandler Start(TBusJob* job, TBusMessage*) override {
+ TestSync->WaitForAndIncrement(0);
+
+ job->SendOneWayTo(new TExampleRequest(&Proto.RequestCount), ClientSession.Get(), TNetAddr("localhost", 1));
+
+ return &TSendErrorModule::Sent;
+ }
+
+ TJobHandler Sent(TBusJob* job, TBusMessage*) {
+ TestSync->WaitForAndIncrement(1);
+ job->Cancel(MESSAGE_DONT_ASK);
+ return nullptr;
+ }
+
+ TBusServerSessionPtr CreateExtSession(TBusMessageQueue& queue) override {
+ TBusServerSessionConfig sessionConfig;
+ sessionConfig.ConnectTimeout = 1;
+ sessionConfig.SendTimeout = 1;
+ sessionConfig.TotalTimeout = 1;
+ sessionConfig.Secret.TimeoutPeriod = TDuration::MilliSeconds(1);
+ ClientSession = CreateDefaultSource(queue, &Proto, sessionConfig);
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(SendError) {
+ TTestSync testSync;
+
+ TBusQueueConfig queueConfig;
+ queueConfig.NumWorkers = 5;
+
+ TBusMessageQueuePtr queue = CreateMessageQueue(queueConfig);
+ TSendErrorModule clientModule(&testSync);
+
+ clientModule.CreatePrivateSessions(queue.Get());
+ clientModule.StartInput();
+
+ clientModule.StartJob(new TExampleRequest(&clientModule.Proto.StartCount));
+
+ testSync.WaitForAndIncrement(2);
+
+ clientModule.Shutdown();
+ }
+}
diff --git a/library/cpp/messagebus/test/ut/module_client_ut.cpp b/library/cpp/messagebus/test/ut/module_client_ut.cpp
new file mode 100644
index 0000000000..ebfe185cc6
--- /dev/null
+++ b/library/cpp/messagebus/test/ut/module_client_ut.cpp
@@ -0,0 +1,368 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "count_down_latch.h"
+#include "moduletest.h"
+
+#include <library/cpp/messagebus/test/helper/example.h>
+#include <library/cpp/messagebus/test/helper/example_module.h>
+#include <library/cpp/messagebus/test/helper/object_count_check.h>
+#include <library/cpp/messagebus/test/helper/wait_for.h>
+
+#include <library/cpp/messagebus/misc/test_sync.h>
+#include <library/cpp/messagebus/oldmodule/module.h>
+
+#include <util/generic/cast.h>
+#include <util/system/event.h>
+
+using namespace NBus;
+using namespace NBus::NTest;
+
+// helper class that cleans TBusJob instance, so job's destructor can
+// be completed without assertion fail.
+struct TJobGuard {
+public:
+ TJobGuard(NBus::TBusJob* job)
+ : Job(job)
+ {
+ }
+
+ ~TJobGuard() {
+ Job->ClearAllMessageStates();
+ }
+
+private:
+ NBus::TBusJob* Job;
+};
+
+class TMessageOk: public NBus::TBusMessage {
+public:
+ TMessageOk()
+ : NBus::TBusMessage(1)
+ {
+ }
+};
+
+class TMessageError: public NBus::TBusMessage {
+public:
+ TMessageError()
+ : NBus::TBusMessage(2)
+ {
+ }
+};
+
+Y_UNIT_TEST_SUITE(BusJobTest) {
+#if 0
+ Y_UNIT_TEST(TestPending) {
+ TObjectCountCheck objectCountCheck;
+
+ TDupDetectModule module;
+ TBusJob job(&module, new TBusMessage(0));
+ // Guard will clear the job if unit-assertion fails.
+ TJobGuard g(&job);
+
+ NBus::TBusMessage* msg = new NBus::TBusMessage(1);
+ job.Send(msg, NULL);
+ NBus::TJobStateVec pending;
+ job.GetPending(&pending);
+
+ UNIT_ASSERT_VALUES_EQUAL(pending.size(), 1u);
+ UNIT_ASSERT_EQUAL(msg, pending[0].Message);
+ }
+
+ Y_UNIT_TEST(TestCallReplyHandler) {
+ TObjectCountCheck objectCountCheck;
+
+ TDupDetectModule module;
+ NBus::TBusJob job(&module, new NBus::TBusMessage(0));
+ // Guard will clear the job if unit-assertion fails.
+ TJobGuard g(&job);
+
+ NBus::TBusMessage* msgOk = new TMessageOk;
+ NBus::TBusMessage* msgError = new TMessageError;
+ job.Send(msgOk, NULL);
+ job.Send(msgError, NULL);
+
+ UNIT_ASSERT_EQUAL(job.GetState<TMessageOk>(), NULL);
+ UNIT_ASSERT_EQUAL(job.GetState<TMessageError>(), NULL);
+
+ NBus::TBusMessage* reply = new NBus::TBusMessage(0);
+ job.CallReplyHandler(NBus::MESSAGE_OK, msgOk, reply);
+ job.CallReplyHandler(NBus::MESSAGE_TIMEOUT, msgError, NULL);
+
+ UNIT_ASSERT_UNEQUAL(job.GetState<TMessageOk>(), NULL);
+ UNIT_ASSERT_UNEQUAL(job.GetState<TMessageError>(), NULL);
+
+ UNIT_ASSERT_VALUES_EQUAL(job.GetStatus<TMessageError>(), NBus::MESSAGE_TIMEOUT);
+ UNIT_ASSERT_EQUAL(job.GetState<TMessageError>()->Status, NBus::MESSAGE_TIMEOUT);
+
+ UNIT_ASSERT_VALUES_EQUAL(job.GetStatus<TMessageOk>(), NBus::MESSAGE_OK);
+ UNIT_ASSERT_EQUAL(job.GetState<TMessageOk>()->Reply, reply);
+ }
+#endif
+
+ struct TParallelOnReplyModule : TExampleClientModule {
+ TNetAddr ServerAddr;
+
+ TCountDownLatch RepliesLatch;
+
+ TParallelOnReplyModule(const TNetAddr& serverAddr)
+ : ServerAddr(serverAddr)
+ , RepliesLatch(2)
+ {
+ }
+
+ TJobHandler Start(TBusJob* job, TBusMessage* mess) override {
+ Y_UNUSED(mess);
+ job->Send(new TExampleRequest(&Proto.RequestCount), Source, TReplyHandler(&TParallelOnReplyModule::ReplyHandler), 0, ServerAddr);
+ return &TParallelOnReplyModule::HandleReplies;
+ }
+
+ void ReplyHandler(TBusJob*, EMessageStatus status, TBusMessage* mess, TBusMessage* reply) {
+ Y_UNUSED(mess);
+ Y_UNUSED(reply);
+ Y_VERIFY(status == MESSAGE_OK, "failed to get reply: %s", ToCString(status));
+ }
+
+ TJobHandler HandleReplies(TBusJob* job, TBusMessage* mess) {
+ Y_UNUSED(mess);
+ RepliesLatch.CountDown();
+ Y_VERIFY(RepliesLatch.Await(TDuration::Seconds(10)), "failed to get answers");
+ job->Cancel(MESSAGE_UNKNOWN);
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(TestReplyHandlerCalledInParallel) {
+ TObjectCountCheck objectCountCheck;
+
+ TExampleServer server;
+
+ TExampleProtocol proto;
+
+ TBusQueueConfig config;
+ config.NumWorkers = 5;
+
+ TParallelOnReplyModule module(server.GetActualListenAddr());
+ module.StartModule();
+
+ module.StartJob(new TExampleRequest(&proto.StartCount));
+ module.StartJob(new TExampleRequest(&proto.StartCount));
+
+ UNIT_ASSERT(module.RepliesLatch.Await(TDuration::Seconds(10)));
+
+ module.Shutdown();
+ }
+
+ struct TErrorHandlerCheckerModule : TExampleModule {
+ TNetAddr ServerAddr;
+
+ TBusClientSessionPtr Source;
+
+ TCountDownLatch GotReplyLatch;
+
+ TBusMessage* SentMessage;
+
+ TErrorHandlerCheckerModule()
+ : ServerAddr("localhost", 17)
+ , GotReplyLatch(2)
+ , SentMessage()
+ {
+ }
+
+ TJobHandler Start(TBusJob* job, TBusMessage* mess) override {
+ Y_UNUSED(mess);
+ TExampleRequest* message = new TExampleRequest(&Proto.RequestCount);
+ job->Send(message, Source, TReplyHandler(&TErrorHandlerCheckerModule::ReplyHandler), 0, ServerAddr);
+ SentMessage = message;
+ return &TErrorHandlerCheckerModule::HandleReplies;
+ }
+
+ void ReplyHandler(TBusJob*, EMessageStatus status, TBusMessage* req, TBusMessage* resp) {
+ Y_VERIFY(status == MESSAGE_CONNECT_FAILED || status == MESSAGE_TIMEOUT, "got wrong status: %s", ToString(status).data());
+ Y_VERIFY(req == SentMessage, "checking request");
+ Y_VERIFY(resp == nullptr, "checking response");
+ GotReplyLatch.CountDown();
+ }
+
+ TJobHandler HandleReplies(TBusJob* job, TBusMessage* mess) {
+ Y_UNUSED(mess);
+ job->Cancel(MESSAGE_UNKNOWN);
+ GotReplyLatch.CountDown();
+ return nullptr;
+ }
+
+ TBusServerSessionPtr CreateExtSession(TBusMessageQueue& queue) override {
+ TBusClientSessionConfig sessionConfig;
+ sessionConfig.SendTimeout = 1; // TODO: allow 0
+ sessionConfig.Secret.TimeoutPeriod = TDuration::MilliSeconds(10);
+ Source = CreateDefaultSource(queue, &Proto, sessionConfig);
+ Source->RegisterService("localhost");
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(ErrorHandler) {
+ TExampleProtocol proto;
+
+ TBusQueueConfig config;
+ config.NumWorkers = 5;
+
+ TErrorHandlerCheckerModule module;
+
+ TBusModuleConfig moduleConfig;
+ moduleConfig.Secret.SchedulePeriod = TDuration::MilliSeconds(10);
+ module.SetConfig(moduleConfig);
+
+ module.StartModule();
+
+ module.StartJob(new TExampleRequest(&proto.StartCount));
+
+ module.GotReplyLatch.Await();
+
+ module.Shutdown();
+ }
+
+ struct TSlowReplyServer: public TBusServerHandlerError {
+ TTestSync* const TestSync;
+ TBusMessageQueuePtr Bus;
+ TBusServerSessionPtr ServerSession;
+ TExampleProtocol Proto;
+
+ TAtomic OnMessageCount;
+
+ TSlowReplyServer(TTestSync* testSync)
+ : TestSync(testSync)
+ , OnMessageCount(0)
+ {
+ Bus = CreateMessageQueue("TSlowReplyServer");
+ TBusServerSessionConfig sessionConfig;
+ ServerSession = TBusServerSession::Create(&Proto, this, sessionConfig, Bus);
+ }
+
+ void OnMessage(TOnMessageContext& req) override {
+ if (AtomicIncrement(OnMessageCount) == 1) {
+ TestSync->WaitForAndIncrement(0);
+ }
+ TAutoPtr<TBusMessage> response(new TExampleResponse(&Proto.ResponseCount));
+ req.SendReplyMove(response);
+ }
+ };
+
+ struct TModuleThatSendsReplyEarly: public TExampleClientModule {
+ TTestSync* const TestSync;
+ const unsigned ServerPort;
+
+ TBusServerSessionPtr ServerSession;
+ TAtomic ReplyCount;
+
+ TModuleThatSendsReplyEarly(TTestSync* testSync, unsigned serverPort)
+ : TestSync(testSync)
+ , ServerPort(serverPort)
+ , ServerSession(nullptr)
+ , ReplyCount(0)
+ {
+ }
+
+ TJobHandler Start(TBusJob* job, TBusMessage* mess) override {
+ Y_UNUSED(mess);
+ for (unsigned i = 0; i < 2; ++i) {
+ job->Send(
+ new TExampleRequest(&Proto.RequestCount),
+ Source,
+ TReplyHandler(&TModuleThatSendsReplyEarly::ReplyHandler),
+ 0,
+ TNetAddr("127.0.0.1", ServerPort));
+ }
+ return &TModuleThatSendsReplyEarly::HandleReplies;
+ }
+
+ void ReplyHandler(TBusJob* job, EMessageStatus status, TBusMessage* mess, TBusMessage* reply) {
+ Y_UNUSED(mess);
+ Y_UNUSED(reply);
+ Y_VERIFY(status == MESSAGE_OK, "failed to get reply");
+ if (AtomicIncrement(ReplyCount) == 1) {
+ TestSync->WaitForAndIncrement(1);
+ job->SendReply(new TExampleResponse(&Proto.ResponseCount));
+ } else {
+ TestSync->WaitForAndIncrement(3);
+ }
+ }
+
+ TJobHandler HandleReplies(TBusJob* job, TBusMessage* mess) {
+ Y_UNUSED(mess);
+ job->Cancel(MESSAGE_UNKNOWN);
+ return nullptr;
+ }
+
+ TBusServerSessionPtr CreateExtSession(TBusMessageQueue& queue) override {
+ TExampleClientModule::CreateExtSession(queue);
+ TBusServerSessionConfig sessionConfig;
+ return ServerSession = CreateDefaultDestination(queue, &Proto, sessionConfig);
+ }
+ };
+
+ Y_UNIT_TEST(SendReplyCalledBeforeAllRepliesReceived) {
+ TTestSync testSync;
+
+ TSlowReplyServer slowReplyServer(&testSync);
+
+ TModuleThatSendsReplyEarly module(&testSync, slowReplyServer.ServerSession->GetActualListenPort());
+ module.StartModule();
+
+ TExampleClient client;
+ TNetAddr addr("127.0.0.1", module.ServerSession->GetActualListenPort());
+ client.SendMessagesWaitReplies(1, &addr);
+
+ testSync.WaitForAndIncrement(2);
+
+ module.Shutdown();
+ }
+
+ struct TShutdownCalledBeforeReplyReceivedModule: public TExampleClientModule {
+ unsigned ServerPort;
+
+ TTestSync TestSync;
+
+ TShutdownCalledBeforeReplyReceivedModule(unsigned serverPort)
+ : ServerPort(serverPort)
+ {
+ }
+
+ TJobHandler Start(TBusJob* job, TBusMessage*) override {
+ TestSync.CheckAndIncrement(0);
+
+ job->Send(new TExampleRequest(&Proto.RequestCount), Source,
+ TReplyHandler(&TShutdownCalledBeforeReplyReceivedModule::HandleReply),
+ 0, TNetAddr("localhost", ServerPort));
+ return &TShutdownCalledBeforeReplyReceivedModule::End;
+ }
+
+ void HandleReply(TBusJob*, EMessageStatus status, TBusMessage*, TBusMessage*) {
+ Y_VERIFY(status == MESSAGE_SHUTDOWN, "got %s", ToCString(status));
+ TestSync.CheckAndIncrement(1);
+ }
+
+ TJobHandler End(TBusJob* job, TBusMessage*) {
+ TestSync.CheckAndIncrement(2);
+ job->Cancel(MESSAGE_SHUTDOWN);
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(ShutdownCalledBeforeReplyReceived) {
+ TExampleServer server;
+ server.ForgetRequest = true;
+
+ TShutdownCalledBeforeReplyReceivedModule module(server.GetActualListenPort());
+
+ module.StartModule();
+
+ module.StartJob(new TExampleRequest(&module.Proto.RequestCount));
+
+ server.TestSync.WaitFor(1);
+
+ module.Shutdown();
+
+ module.TestSync.CheckAndIncrement(3);
+ }
+}
diff --git a/library/cpp/messagebus/test/ut/module_server_ut.cpp b/library/cpp/messagebus/test/ut/module_server_ut.cpp
new file mode 100644
index 0000000000..88fe1dd9b6
--- /dev/null
+++ b/library/cpp/messagebus/test/ut/module_server_ut.cpp
@@ -0,0 +1,119 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "count_down_latch.h"
+#include "moduletest.h"
+
+#include <library/cpp/messagebus/test/helper/example.h>
+#include <library/cpp/messagebus/test/helper/example_module.h>
+#include <library/cpp/messagebus/test/helper/object_count_check.h>
+#include <library/cpp/messagebus/test/helper/wait_for.h>
+
+#include <library/cpp/messagebus/oldmodule/module.h>
+
+#include <util/generic/cast.h>
+
+using namespace NBus;
+using namespace NBus::NTest;
+
+Y_UNIT_TEST_SUITE(ModuleServerTests) {
+ Y_UNIT_TEST(TestModule) {
+ TObjectCountCheck objectCountCheck;
+
+ /// create or get instance of message queue, need one per application
+ TBusMessageQueuePtr bus(CreateMessageQueue());
+ THostInfoHandler hostHandler(bus.Get());
+ TDupDetectModule module(hostHandler.GetActualListenAddr());
+ bool success;
+ success = module.Init(bus.Get());
+ UNIT_ASSERT_C(success, "failed to initialize dupdetect module");
+
+ success = module.StartInput();
+ UNIT_ASSERT_C(success, "failed to start dupdetect module");
+
+ TDupDetectHandler dupHandler(module.ListenAddr, bus.Get());
+ dupHandler.Work();
+
+ UNIT_WAIT_FOR(dupHandler.NumMessages == dupHandler.NumReplies);
+
+ module.Shutdown();
+ dupHandler.DupDetect->Shutdown();
+ }
+
+ struct TParallelOnMessageModule: public TExampleServerModule {
+ TCountDownLatch WaitTwoRequestsLatch;
+
+ TParallelOnMessageModule()
+ : WaitTwoRequestsLatch(2)
+ {
+ }
+
+ TJobHandler Start(TBusJob* job, TBusMessage* mess) override {
+ WaitTwoRequestsLatch.CountDown();
+ Y_VERIFY(WaitTwoRequestsLatch.Await(TDuration::Seconds(5)), "oops");
+
+ VerifyDynamicCast<TExampleRequest*>(mess);
+
+ job->SendReply(new TExampleResponse(&Proto.ResponseCount));
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(TestOnMessageHandlerCalledInParallel) {
+ TObjectCountCheck objectCountCheck;
+
+ TBusQueueConfig config;
+ config.NumWorkers = 5;
+
+ TParallelOnMessageModule module;
+ module.StartModule();
+
+ TExampleClient client;
+
+ client.SendMessagesWaitReplies(2, module.ServerAddr);
+
+ module.Shutdown();
+ }
+
+ struct TDelayReplyServer: public TExampleServerModule {
+ TSystemEvent MessageReceivedEvent;
+ TSystemEvent ClientDiedEvent;
+
+ TJobHandler Start(TBusJob* job, TBusMessage* mess) override {
+ Y_UNUSED(mess);
+
+ MessageReceivedEvent.Signal();
+
+ Y_VERIFY(ClientDiedEvent.WaitT(TDuration::Seconds(5)), "oops");
+
+ job->SendReply(new TExampleResponse(&Proto.ResponseCount));
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(TestReplyCalledAfterClientDisconnected) {
+ TObjectCountCheck objectCountCheck;
+
+ TBusQueueConfig config;
+ config.NumWorkers = 5;
+
+ TDelayReplyServer server;
+ server.StartModule();
+
+ THolder<TExampleClient> client(new TExampleClient);
+
+ client->SendMessages(1, server.ServerAddr);
+
+ UNIT_ASSERT(server.MessageReceivedEvent.WaitT(TDuration::Seconds(5)));
+
+ UNIT_ASSERT_VALUES_EQUAL(1, server.GetModuleSessionInFlight());
+
+ client.Destroy();
+
+ server.ClientDiedEvent.Signal();
+
+ // wait until all server message are delivered
+ UNIT_WAIT_FOR(0 == server.GetModuleSessionInFlight());
+
+ server.Shutdown();
+ }
+}
diff --git a/library/cpp/messagebus/test/ut/moduletest.h b/library/cpp/messagebus/test/ut/moduletest.h
new file mode 100644
index 0000000000..d5da72c0cb
--- /dev/null
+++ b/library/cpp/messagebus/test/ut/moduletest.h
@@ -0,0 +1,221 @@
+#pragma once
+
+///////////////////////////////////////////////////////////////////
+/// \file
+/// \brief Example of using local session for communication.
+
+#include <library/cpp/messagebus/test/helper/alloc_counter.h>
+#include <library/cpp/messagebus/test/helper/example.h>
+#include <library/cpp/messagebus/test/helper/message_handler_error.h>
+
+#include <library/cpp/messagebus/ybus.h>
+#include <library/cpp/messagebus/oldmodule/module.h>
+
+namespace NBus {
+ namespace NTest {
+ using namespace std;
+
+#define TYPE_HOSTINFOREQUEST 100
+#define TYPE_HOSTINFORESPONSE 101
+
+ ////////////////////////////////////////////////////////////////////
+ /// \brief DupDetect protocol that common between client and server
+ ////////////////////////////////////////////////////////////////////
+ /// \brief HostInfo request class
+ class THostInfoMessage: public TBusMessage {
+ public:
+ THostInfoMessage()
+ : TBusMessage(TYPE_HOSTINFOREQUEST)
+ {
+ }
+ THostInfoMessage(ECreateUninitialized)
+ : TBusMessage(MESSAGE_CREATE_UNINITIALIZED)
+ {
+ }
+
+ ~THostInfoMessage() override {
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////
+ /// \brief HostInfo reply class
+ class THostInfoReply: public TBusMessage {
+ public:
+ THostInfoReply()
+ : TBusMessage(TYPE_HOSTINFORESPONSE)
+ {
+ }
+ THostInfoReply(ECreateUninitialized)
+ : TBusMessage(MESSAGE_CREATE_UNINITIALIZED)
+ {
+ }
+
+ ~THostInfoReply() override {
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////
+ /// \brief HostInfo protocol that common between client and server
+ class THostInfoProtocol: public TBusProtocol {
+ public:
+ THostInfoProtocol()
+ : TBusProtocol("HOSTINFO", 0)
+ {
+ }
+ /// serialized protocol specific data into TBusData
+ void Serialize(const TBusMessage* mess, TBuffer& data) override {
+ Y_UNUSED(data);
+ Y_UNUSED(mess);
+ }
+
+ /// deserialized TBusData into new instance of the message
+ TAutoPtr<TBusMessage> Deserialize(ui16 messageType, TArrayRef<const char> payload) override {
+ Y_UNUSED(payload);
+
+ if (messageType == TYPE_HOSTINFOREQUEST) {
+ return new THostInfoMessage(MESSAGE_CREATE_UNINITIALIZED);
+ } else if (messageType == TYPE_HOSTINFORESPONSE) {
+ return new THostInfoReply(MESSAGE_CREATE_UNINITIALIZED);
+ } else {
+ Y_FAIL("unknown");
+ }
+ }
+ };
+
+ //////////////////////////////////////////////////////////////
+ /// \brief HostInfo handler (should convert it to module too)
+ struct THostInfoHandler: public TBusServerHandlerError {
+ TBusServerSessionPtr Session;
+ TBusServerSessionConfig HostInfoConfig;
+ THostInfoProtocol HostInfoProto;
+
+ THostInfoHandler(TBusMessageQueue* queue) {
+ Session = TBusServerSession::Create(&HostInfoProto, this, HostInfoConfig, queue);
+ }
+
+ void OnMessage(TOnMessageContext& mess) override {
+ usleep(10 * 1000); /// pretend we are doing something
+
+ TAutoPtr<THostInfoReply> reply(new THostInfoReply());
+
+ mess.SendReplyMove(reply);
+ }
+
+ TNetAddr GetActualListenAddr() {
+ return TNetAddr("localhost", Session->GetActualListenPort());
+ }
+ };
+
+ //////////////////////////////////////////////////////////////
+ /// \brief DupDetect handler (should convert it to module too)
+ struct TDupDetectHandler: public TBusClientHandlerError {
+ TNetAddr ServerAddr;
+
+ TBusClientSessionPtr DupDetect;
+ TBusClientSessionConfig DupDetectConfig;
+ TExampleProtocol DupDetectProto;
+
+ int NumMessages;
+ int NumReplies;
+
+ TDupDetectHandler(const TNetAddr& serverAddr, TBusMessageQueuePtr queue)
+ : ServerAddr(serverAddr)
+ {
+ DupDetect = TBusClientSession::Create(&DupDetectProto, this, DupDetectConfig, queue);
+ DupDetect->RegisterService("localhost");
+ }
+
+ void Work() {
+ NumMessages = 10;
+ NumReplies = 0;
+
+ for (int i = 0; i < NumMessages; i++) {
+ TExampleRequest* mess = new TExampleRequest(&DupDetectProto.RequestCount);
+ DupDetect->SendMessage(mess, &ServerAddr);
+ }
+ }
+
+ void OnReply(TAutoPtr<TBusMessage> mess, TAutoPtr<TBusMessage> reply) override {
+ Y_UNUSED(mess);
+ Y_UNUSED(reply);
+ NumReplies++;
+ }
+ };
+
+ /////////////////////////////////////////////////////////////////
+ /// \brief DupDetect module
+
+ struct TDupDetectModule: public TBusModule {
+ TNetAddr HostInfoAddr;
+
+ TBusClientSessionPtr HostInfoClientSession;
+ TBusClientSessionConfig HostInfoConfig;
+ THostInfoProtocol HostInfoProto;
+
+ TExampleProtocol DupDetectProto;
+ TBusServerSessionConfig DupDetectConfig;
+
+ TNetAddr ListenAddr;
+
+ TDupDetectModule(const TNetAddr& hostInfoAddr)
+ : TBusModule("DUPDETECTMODULE")
+ , HostInfoAddr(hostInfoAddr)
+ {
+ }
+
+ bool Init(TBusMessageQueue* queue) {
+ HostInfoClientSession = CreateDefaultSource(*queue, &HostInfoProto, HostInfoConfig);
+ HostInfoClientSession->RegisterService("localhost");
+
+ return TBusModule::CreatePrivateSessions(queue);
+ }
+
+ TBusServerSessionPtr CreateExtSession(TBusMessageQueue& queue) override {
+ TBusServerSessionPtr session = CreateDefaultDestination(queue, &DupDetectProto, DupDetectConfig);
+
+ ListenAddr = TNetAddr("localhost", session->GetActualListenPort());
+
+ return session;
+ }
+
+ /// entry point into module, first function to call
+ TJobHandler Start(TBusJob* job, TBusMessage* mess) override {
+ TExampleRequest* dmess = dynamic_cast<TExampleRequest*>(mess);
+ Y_UNUSED(dmess);
+
+ THostInfoMessage* hmess = new THostInfoMessage();
+
+ /// send message to imaginary hostinfo server
+ job->Send(hmess, HostInfoClientSession, TReplyHandler(), 0, HostInfoAddr);
+
+ return TJobHandler(&TDupDetectModule::ProcessHostInfo);
+ }
+
+ /// next handler is executed when all outstanding requests from previous handler is completed
+ TJobHandler ProcessHostInfo(TBusJob* job, TBusMessage* mess) {
+ TExampleRequest* dmess = dynamic_cast<TExampleRequest*>(mess);
+ Y_UNUSED(dmess);
+
+ THostInfoMessage* hmess = job->Get<THostInfoMessage>();
+ THostInfoReply* hreply = job->Get<THostInfoReply>();
+ EMessageStatus hstatus = job->GetStatus<THostInfoMessage>();
+ Y_ASSERT(hmess != nullptr);
+ Y_ASSERT(hreply != nullptr);
+ Y_ASSERT(hstatus == MESSAGE_OK);
+
+ return TJobHandler(&TDupDetectModule::Finish);
+ }
+
+ /// last handler sends reply and returns NULL
+ TJobHandler Finish(TBusJob* job, TBusMessage* mess) {
+ Y_UNUSED(mess);
+
+ TExampleResponse* reply = new TExampleResponse(&DupDetectProto.ResponseCount);
+ job->SendReply(reply);
+
+ return nullptr;
+ }
+ };
+
+ }
+}
diff --git a/library/cpp/messagebus/test/ut/one_way_ut.cpp b/library/cpp/messagebus/test/ut/one_way_ut.cpp
new file mode 100644
index 0000000000..9c21227e2b
--- /dev/null
+++ b/library/cpp/messagebus/test/ut/one_way_ut.cpp
@@ -0,0 +1,255 @@
+///////////////////////////////////////////////////////////////////
+/// \file
+/// \brief Example of reply-less communication
+
+/// This example demostrates how asynchronous message passing library
+/// can be used to send message and do not wait for reply back.
+/// The usage of reply-less communication should be restricted to
+/// low-throughput clients and high-throughput server to provide reasonable
+/// utility. Removing replies from the communication removes any restriction
+/// on how many message can be send to server and rougue clients may overwelm
+/// server without thoughtput control.
+
+/// 1) To implement reply-less client \n
+
+/// Call NBus::TBusSession::AckMessage()
+/// from within NBus::IMessageHandler::OnSent() handler when message has
+/// gone into wire on client end. See example in NBus::NullClient::OnMessageSent().
+/// Discard identity for reply message.
+
+/// 2) To implement reply-less server \n
+
+/// Call NBus::TBusSession::AckMessage() from within NBus::IMessageHandler::OnMessage()
+/// handler when message has been received on server end.
+/// See example in NBus::NullServer::OnMessage().
+/// Discard identity for reply message.
+
+#include <library/cpp/messagebus/test/helper/alloc_counter.h>
+#include <library/cpp/messagebus/test/helper/example.h>
+#include <library/cpp/messagebus/test/helper/hanging_server.h>
+#include <library/cpp/messagebus/test/helper/message_handler_error.h>
+#include <library/cpp/messagebus/test/helper/object_count_check.h>
+#include <library/cpp/messagebus/test/helper/wait_for.h>
+
+#include <library/cpp/messagebus/ybus.h>
+
+using namespace std;
+using namespace NBus;
+using namespace NBus::NPrivate;
+using namespace NBus::NTest;
+
+////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////
+/// \brief Reply-less client and handler
+struct NullClient : TBusClientHandlerError {
+ TNetAddr ServerAddr;
+
+ TBusMessageQueuePtr Queue;
+ TBusClientSessionPtr Session;
+ TExampleProtocol Proto;
+
+ /// constructor creates instances of protocol and session
+ NullClient(const TNetAddr& serverAddr, const TBusClientSessionConfig& sessionConfig = TBusClientSessionConfig())
+ : ServerAddr(serverAddr)
+ {
+ UNIT_ASSERT(serverAddr.GetPort() > 0);
+
+ /// create or get instance of message queue, need one per application
+ Queue = CreateMessageQueue();
+
+ /// register source/client session
+ Session = TBusClientSession::Create(&Proto, this, sessionConfig, Queue);
+
+ /// register service, announce to clients via LocatorService
+ Session->RegisterService("localhost");
+ }
+
+ ~NullClient() override {
+ Session->Shutdown();
+ }
+
+ /// dispatch of requests is done here
+ void Work() {
+ int batch = 10;
+
+ for (int i = 0; i < batch; i++) {
+ TExampleRequest* mess = new TExampleRequest(&Proto.RequestCount);
+ mess->Data = "TADA";
+ Session->SendMessageOneWay(mess, &ServerAddr);
+ }
+ }
+
+ void OnMessageSentOneWay(TAutoPtr<TBusMessage>) override {
+ }
+};
+
+/////////////////////////////////////////////////////////////////////
+/// \brief Reply-less server and handler
+class NullServer: public TBusServerHandlerError {
+public:
+ /// session object to maintian
+ TBusMessageQueuePtr Queue;
+ TBusServerSessionPtr Session;
+ TExampleProtocol Proto;
+
+public:
+ TAtomic NumMessages;
+
+ NullServer() {
+ NumMessages = 0;
+
+ /// create or get instance of single message queue, need one for application
+ Queue = CreateMessageQueue();
+
+ /// register destination session
+ TBusServerSessionConfig sessionConfig;
+ Session = TBusServerSession::Create(&Proto, this, sessionConfig, Queue);
+ }
+
+ ~NullServer() override {
+ Session->Shutdown();
+ }
+
+ /// when message comes do not send reply, just acknowledge
+ void OnMessage(TOnMessageContext& mess) override {
+ TExampleRequest* fmess = static_cast<TExampleRequest*>(mess.GetMessage());
+
+ Y_ASSERT(fmess->Data == "TADA");
+
+ /// tell session to forget this message and never expect any reply
+ mess.ForgetRequest();
+
+ AtomicIncrement(NumMessages);
+ }
+
+ /// this handler should not be called because this server does not send replies
+ void OnSent(TAutoPtr<TBusMessage> mess) override {
+ Y_UNUSED(mess);
+ Y_FAIL("This server does not sent replies");
+ }
+};
+
+Y_UNIT_TEST_SUITE(TMessageBusTests_OneWay) {
+ Y_UNIT_TEST(Simple) {
+ TObjectCountCheck objectCountCheck;
+
+ NullServer server;
+ NullClient client(TNetAddr("localhost", server.Session->GetActualListenPort()));
+
+ client.Work();
+
+ // wait until all client message are delivered
+ UNIT_WAIT_FOR(AtomicGet(server.NumMessages) == 10);
+
+ // assert correct number of messages
+ UNIT_ASSERT_VALUES_EQUAL(AtomicGet(server.NumMessages), 10);
+ UNIT_ASSERT_VALUES_EQUAL(server.Session->GetInFlight(), 0);
+ UNIT_ASSERT_VALUES_EQUAL(client.Session->GetInFlight(), 0);
+ }
+
+ struct TMessageTooLargeClient: public NullClient {
+ TSystemEvent GotTooLarge;
+
+ TBusClientSessionConfig Config() {
+ TBusClientSessionConfig r;
+ r.MaxMessageSize = 1;
+ return r;
+ }
+
+ TMessageTooLargeClient(unsigned port)
+ : NullClient(TNetAddr("localhost", port), Config())
+ {
+ }
+
+ ~TMessageTooLargeClient() override {
+ Session->Shutdown();
+ }
+
+ void OnError(TAutoPtr<TBusMessage> mess, EMessageStatus status) override {
+ Y_UNUSED(mess);
+
+ Y_VERIFY(status == MESSAGE_MESSAGE_TOO_LARGE, "wrong status: %s", ToCString(status));
+
+ GotTooLarge.Signal();
+ }
+ };
+
+ Y_UNIT_TEST(MessageTooLargeOnClient) {
+ TObjectCountCheck objectCountCheck;
+
+ NullServer server;
+
+ TMessageTooLargeClient client(server.Session->GetActualListenPort());
+
+ EMessageStatus ok = client.Session->SendMessageOneWayMove(new TExampleRequest(&client.Proto.RequestCount), &client.ServerAddr);
+ UNIT_ASSERT_VALUES_EQUAL(MESSAGE_OK, ok);
+
+ client.GotTooLarge.WaitI();
+ }
+
+ struct TCheckTimeoutClient: public NullClient {
+ ~TCheckTimeoutClient() override {
+ Session->Shutdown();
+ }
+
+ static TBusClientSessionConfig SessionConfig() {
+ TBusClientSessionConfig sessionConfig;
+ sessionConfig.SendTimeout = 1;
+ sessionConfig.ConnectTimeout = 1;
+ sessionConfig.Secret.TimeoutPeriod = TDuration::MilliSeconds(10);
+ return sessionConfig;
+ }
+
+ TCheckTimeoutClient(const TNetAddr& serverAddr)
+ : NullClient(serverAddr, SessionConfig())
+ {
+ }
+
+ TSystemEvent GotError;
+
+ /// message that could not be delivered
+ void OnError(TAutoPtr<TBusMessage> mess, EMessageStatus status) override {
+ Y_UNUSED(mess);
+ Y_UNUSED(status); // TODO: check status
+
+ GotError.Signal();
+ }
+ };
+
+ Y_UNIT_TEST(SendTimeout_Callback_NoServer) {
+ TObjectCountCheck objectCountCheck;
+
+ TCheckTimeoutClient client(TNetAddr("localhost", 17));
+
+ EMessageStatus ok = client.Session->SendMessageOneWay(new TExampleRequest(&client.Proto.RequestCount), &client.ServerAddr);
+ UNIT_ASSERT_EQUAL(ok, MESSAGE_OK);
+
+ client.GotError.WaitI();
+ }
+
+ Y_UNIT_TEST(SendTimeout_Callback_HangingServer) {
+ THangingServer server;
+
+ TObjectCountCheck objectCountCheck;
+
+ TCheckTimeoutClient client(TNetAddr("localhost", server.GetPort()));
+
+ bool first = true;
+ for (;;) {
+ EMessageStatus ok = client.Session->SendMessageOneWayMove(new TExampleRequest(&client.Proto.RequestCount), &client.ServerAddr);
+ if (ok == MESSAGE_BUSY) {
+ UNIT_ASSERT(!first);
+ break;
+ }
+ UNIT_ASSERT_VALUES_EQUAL(ok, MESSAGE_OK);
+ first = false;
+ }
+
+ // BUGBUG: The test is buggy: the client might not get any error when sending one-way messages.
+ // All the messages that the client has sent before he gets first MESSAGE_BUSY error might get
+ // serailized and written to the socket buffer, so the write queue gets drained and there are
+ // no messages to timeout when periodic timeout check happens.
+
+ client.GotError.WaitI();
+ }
+}
diff --git a/library/cpp/messagebus/test/ut/starter_ut.cpp b/library/cpp/messagebus/test/ut/starter_ut.cpp
new file mode 100644
index 0000000000..dd4d3aaa5e
--- /dev/null
+++ b/library/cpp/messagebus/test/ut/starter_ut.cpp
@@ -0,0 +1,140 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/messagebus/test/helper/example_module.h>
+#include <library/cpp/messagebus/test/helper/object_count_check.h>
+#include <library/cpp/messagebus/test/helper/wait_for.h>
+
+using namespace NBus;
+using namespace NBus::NTest;
+
+Y_UNIT_TEST_SUITE(TBusStarterTest) {
+ struct TStartJobTestModule: public TExampleModule {
+ using TBusModule::CreateDefaultStarter;
+
+ TAtomic StartCount;
+
+ TStartJobTestModule()
+ : StartCount(0)
+ {
+ }
+
+ TJobHandler Start(TBusJob* job, TBusMessage* mess) override {
+ Y_UNUSED(mess);
+ AtomicIncrement(StartCount);
+ job->Sleep(10);
+ return &TStartJobTestModule::End;
+ }
+
+ TJobHandler End(TBusJob* job, TBusMessage* mess) {
+ Y_UNUSED(mess);
+ AtomicIncrement(StartCount);
+ job->Cancel(MESSAGE_UNKNOWN);
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(Test) {
+ TObjectCountCheck objectCountCheck;
+
+ TBusMessageQueuePtr bus(CreateMessageQueue());
+
+ TStartJobTestModule module;
+
+ //module.StartModule();
+ module.CreatePrivateSessions(bus.Get());
+ module.StartInput();
+
+ TBusSessionConfig config;
+ config.SendTimeout = 10;
+
+ module.CreateDefaultStarter(*bus, config);
+
+ UNIT_WAIT_FOR(AtomicGet(module.StartCount) >= 3);
+
+ module.Shutdown();
+ bus->Stop();
+ }
+
+ Y_UNIT_TEST(TestModuleStartJob) {
+ TObjectCountCheck objectCountCheck;
+
+ TExampleProtocol proto;
+
+ TStartJobTestModule module;
+
+ TBusModuleConfig moduleConfig;
+ moduleConfig.Secret.SchedulePeriod = TDuration::MilliSeconds(10);
+ module.SetConfig(moduleConfig);
+
+ module.StartModule();
+
+ module.StartJob(new TExampleRequest(&proto.RequestCount));
+
+ UNIT_WAIT_FOR(AtomicGet(module.StartCount) != 2);
+
+ module.Shutdown();
+ }
+
+ struct TSleepModule: public TExampleServerModule {
+ TSystemEvent MessageReceivedEvent;
+
+ TJobHandler Start(TBusJob* job, TBusMessage* mess) override {
+ Y_UNUSED(mess);
+
+ MessageReceivedEvent.Signal();
+
+ job->Sleep(1000000000);
+
+ return TJobHandler(&TSleepModule::Never);
+ }
+
+ TJobHandler Never(TBusJob*, TBusMessage*) {
+ Y_FAIL("happens");
+ throw 1;
+ }
+ };
+
+ Y_UNIT_TEST(StartJobDestroyDuringSleep) {
+ TObjectCountCheck objectCountCheck;
+
+ TExampleProtocol proto;
+
+ TSleepModule module;
+
+ module.StartModule();
+
+ module.StartJob(new TExampleRequest(&proto.StartCount));
+
+ module.MessageReceivedEvent.WaitI();
+
+ module.Shutdown();
+ }
+
+ struct TSendReplyModule: public TExampleServerModule {
+ TSystemEvent MessageReceivedEvent;
+
+ TJobHandler Start(TBusJob* job, TBusMessage* mess) override {
+ Y_UNUSED(mess);
+
+ job->SendReply(new TExampleResponse(&Proto.ResponseCount));
+
+ MessageReceivedEvent.Signal();
+
+ return nullptr;
+ }
+ };
+
+ Y_UNIT_TEST(AllowSendReplyInStarted) {
+ TObjectCountCheck objectCountCheck;
+
+ TExampleProtocol proto;
+
+ TSendReplyModule module;
+ module.StartModule();
+ module.StartJob(new TExampleRequest(&proto.StartCount));
+
+ module.MessageReceivedEvent.WaitI();
+
+ module.Shutdown();
+ }
+}
diff --git a/library/cpp/messagebus/test/ut/sync_client_ut.cpp b/library/cpp/messagebus/test/ut/sync_client_ut.cpp
new file mode 100644
index 0000000000..400128193f
--- /dev/null
+++ b/library/cpp/messagebus/test/ut/sync_client_ut.cpp
@@ -0,0 +1,69 @@
+#include <library/cpp/messagebus/test/helper/example.h>
+#include <library/cpp/messagebus/test/helper/object_count_check.h>
+
+namespace NBus {
+ namespace NTest {
+ using namespace std;
+
+ ////////////////////////////////////////////////////////////////////
+ /// \brief Client for sending synchronous message to local server
+ struct TSyncClient {
+ TNetAddr ServerAddr;
+
+ TExampleProtocol Proto;
+ TBusMessageQueuePtr Bus;
+ TBusSyncClientSessionPtr Session;
+
+ int NumReplies;
+ int NumMessages;
+
+ /// constructor creates instances of queue, protocol and session
+ TSyncClient(const TNetAddr& serverAddr)
+ : ServerAddr(serverAddr)
+ {
+ /// create or get instance of message queue, need one per application
+ Bus = CreateMessageQueue();
+
+ NumReplies = 0;
+ NumMessages = 10;
+
+ /// register source/client session
+ TBusClientSessionConfig sessionConfig;
+ Session = Bus->CreateSyncSource(&Proto, sessionConfig);
+ Session->RegisterService("localhost");
+ }
+
+ ~TSyncClient() {
+ Session->Shutdown();
+ }
+
+ /// dispatch of requests is done here
+ void Work() {
+ for (int i = 0; i < NumMessages; i++) {
+ THolder<TExampleRequest> mess(new TExampleRequest(&Proto.RequestCount));
+ EMessageStatus status;
+ THolder<TBusMessage> reply(Session->SendSyncMessage(mess.Get(), status, &ServerAddr));
+ if (!!reply) {
+ NumReplies++;
+ }
+ }
+ }
+ };
+
+ Y_UNIT_TEST_SUITE(SyncClientTest) {
+ Y_UNIT_TEST(TestSync) {
+ TObjectCountCheck objectCountCheck;
+
+ TExampleServer server;
+ TSyncClient client(server.GetActualListenAddr());
+ client.Work();
+ // assert correct number of replies
+ UNIT_ASSERT_EQUAL(client.NumReplies, client.NumMessages);
+ // assert that there is no message left in flight
+ UNIT_ASSERT_EQUAL(server.Session->GetInFlight(), 0);
+ UNIT_ASSERT_EQUAL(client.Session->GetInFlight(), 0);
+ }
+ }
+
+ }
+}
diff --git a/library/cpp/messagebus/test/ut/ya.make b/library/cpp/messagebus/test/ut/ya.make
new file mode 100644
index 0000000000..fe1b4961d6
--- /dev/null
+++ b/library/cpp/messagebus/test/ut/ya.make
@@ -0,0 +1,56 @@
+OWNER(g:messagebus)
+
+UNITTEST_FOR(library/cpp/messagebus)
+
+TIMEOUT(1200)
+
+SIZE(LARGE)
+
+TAG(
+ ya:not_autocheck
+ ya:fat
+)
+
+FORK_SUBTESTS()
+
+PEERDIR(
+ library/cpp/testing/unittest_main
+ library/cpp/messagebus
+ library/cpp/messagebus/test/helper
+ library/cpp/messagebus/www
+)
+
+SRCS(
+ messagebus_ut.cpp
+ module_client_ut.cpp
+ module_client_one_way_ut.cpp
+ module_server_ut.cpp
+ one_way_ut.cpp
+ starter_ut.cpp
+ sync_client_ut.cpp
+ locator_uniq_ut.cpp
+ ../../actor/actor_ut.cpp
+ ../../actor/ring_buffer_ut.cpp
+ ../../actor/tasks_ut.cpp
+ ../../actor/what_thread_does_guard_ut.cpp
+ ../../async_result_ut.cpp
+ ../../cc_semaphore_ut.cpp
+ ../../coreconn_ut.cpp
+ ../../duration_histogram_ut.cpp
+ ../../message_status_counter_ut.cpp
+ ../../misc/weak_ptr_ut.cpp
+ ../../latch_ut.cpp
+ ../../lfqueue_batch_ut.cpp
+ ../../local_flags_ut.cpp
+ ../../memory_ut.cpp
+ ../../moved_ut.cpp
+ ../../netaddr_ut.cpp
+ ../../network_ut.cpp
+ ../../nondestroying_holder_ut.cpp
+ ../../scheduler_actor_ut.cpp
+ ../../scheduler/scheduler_ut.cpp
+ ../../socket_addr_ut.cpp
+ ../../vector_swaps_ut.cpp
+)
+
+END()
diff --git a/library/cpp/messagebus/test/ya.make b/library/cpp/messagebus/test/ya.make
new file mode 100644
index 0000000000..0dc4bd4720
--- /dev/null
+++ b/library/cpp/messagebus/test/ya.make
@@ -0,0 +1,7 @@
+OWNER(g:messagebus)
+
+RECURSE(
+ example
+ perftest
+ ut
+)
diff --git a/library/cpp/messagebus/test_utils.h b/library/cpp/messagebus/test_utils.h
new file mode 100644
index 0000000000..2abdf504b1
--- /dev/null
+++ b/library/cpp/messagebus/test_utils.h
@@ -0,0 +1,12 @@
+#pragma once
+
+// Do nothing if there is no support for IPv4
+#define ASSUME_IP_V4_ENABLED \
+ do { \
+ try { \
+ TNetworkAddress("192.168.0.42", 80); \
+ } catch (const TNetworkResolutionError& ex) { \
+ Y_UNUSED(ex); \
+ return; \
+ } \
+ } while (0)
diff --git a/library/cpp/messagebus/text_utils.h b/library/cpp/messagebus/text_utils.h
new file mode 100644
index 0000000000..c2dcad834c
--- /dev/null
+++ b/library/cpp/messagebus/text_utils.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include <library/cpp/string_utils/indent_text/indent_text.h>
diff --git a/library/cpp/messagebus/thread_extra.h b/library/cpp/messagebus/thread_extra.h
new file mode 100644
index 0000000000..2c79741e88
--- /dev/null
+++ b/library/cpp/messagebus/thread_extra.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include <library/cpp/messagebus/actor/thread_extra.h>
diff --git a/library/cpp/messagebus/use_after_free_checker.cpp b/library/cpp/messagebus/use_after_free_checker.cpp
new file mode 100644
index 0000000000..4904e7c614
--- /dev/null
+++ b/library/cpp/messagebus/use_after_free_checker.cpp
@@ -0,0 +1,22 @@
+#include "use_after_free_checker.h"
+
+#include <util/system/yassert.h>
+
+namespace {
+ const ui64 VALID = (ui64)0xAABBCCDDEEFF0011LL;
+ const ui64 INVALID = (ui64)0x1122334455667788LL;
+}
+
+TUseAfterFreeChecker::TUseAfterFreeChecker()
+ : Magic(VALID)
+{
+}
+
+TUseAfterFreeChecker::~TUseAfterFreeChecker() {
+ Y_VERIFY(Magic == VALID, "Corrupted");
+ Magic = INVALID;
+}
+
+void TUseAfterFreeChecker::CheckNotFreed() const {
+ Y_VERIFY(Magic == VALID, "Freed or corrupted");
+}
diff --git a/library/cpp/messagebus/use_after_free_checker.h b/library/cpp/messagebus/use_after_free_checker.h
new file mode 100644
index 0000000000..590b076156
--- /dev/null
+++ b/library/cpp/messagebus/use_after_free_checker.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <util/system/platform.h>
+#include <util/system/types.h>
+
+class TUseAfterFreeChecker {
+private:
+ ui64 Magic;
+
+public:
+ TUseAfterFreeChecker();
+ ~TUseAfterFreeChecker();
+ void CheckNotFreed() const;
+};
+
+// check twice: in constructor and in destructor
+class TUseAfterFreeCheckerGuard {
+private:
+ const TUseAfterFreeChecker& Check;
+
+public:
+ TUseAfterFreeCheckerGuard(const TUseAfterFreeChecker& check)
+ : Check(check)
+ {
+ Check.CheckNotFreed();
+ }
+
+ ~TUseAfterFreeCheckerGuard() {
+ Check.CheckNotFreed();
+ }
+};
diff --git a/library/cpp/messagebus/use_count_checker.cpp b/library/cpp/messagebus/use_count_checker.cpp
new file mode 100644
index 0000000000..c6243ea21f
--- /dev/null
+++ b/library/cpp/messagebus/use_count_checker.cpp
@@ -0,0 +1,53 @@
+#include "use_count_checker.h"
+
+#include <util/generic/utility.h>
+#include <util/system/yassert.h>
+
+TUseCountChecker::TUseCountChecker() {
+}
+
+TUseCountChecker::~TUseCountChecker() {
+ TAtomicBase count = Counter.Val();
+ Y_VERIFY(count == 0, "must not release when count is not zero: %ld", (long)count);
+}
+
+void TUseCountChecker::Inc() {
+ Counter.Inc();
+}
+
+void TUseCountChecker::Dec() {
+ Counter.Dec();
+}
+
+TUseCountHolder::TUseCountHolder()
+ : CurrentChecker(nullptr)
+{
+}
+
+TUseCountHolder::TUseCountHolder(TUseCountChecker* currentChecker)
+ : CurrentChecker(currentChecker)
+{
+ if (!!CurrentChecker) {
+ CurrentChecker->Inc();
+ }
+}
+
+TUseCountHolder::~TUseCountHolder() {
+ if (!!CurrentChecker) {
+ CurrentChecker->Dec();
+ }
+}
+
+TUseCountHolder& TUseCountHolder::operator=(TUseCountHolder that) {
+ Swap(that);
+ return *this;
+}
+
+void TUseCountHolder::Swap(TUseCountHolder& that) {
+ DoSwap(CurrentChecker, that.CurrentChecker);
+}
+
+void TUseCountHolder::Reset() {
+ TUseCountHolder tmp;
+ Swap(tmp);
+}
diff --git a/library/cpp/messagebus/use_count_checker.h b/library/cpp/messagebus/use_count_checker.h
new file mode 100644
index 0000000000..70bef6fa8a
--- /dev/null
+++ b/library/cpp/messagebus/use_count_checker.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <util/generic/refcount.h>
+
+class TUseCountChecker {
+private:
+ TAtomicCounter Counter;
+
+public:
+ TUseCountChecker();
+ ~TUseCountChecker();
+ void Inc();
+ void Dec();
+};
+
+class TUseCountHolder {
+private:
+ TUseCountChecker* CurrentChecker;
+
+public:
+ TUseCountHolder();
+ explicit TUseCountHolder(TUseCountChecker* currentChecker);
+ TUseCountHolder& operator=(TUseCountHolder that);
+ ~TUseCountHolder();
+ void Swap(TUseCountHolder&);
+ void Reset();
+};
diff --git a/library/cpp/messagebus/vector_swaps.h b/library/cpp/messagebus/vector_swaps.h
new file mode 100644
index 0000000000..b920bcf03e
--- /dev/null
+++ b/library/cpp/messagebus/vector_swaps.h
@@ -0,0 +1,171 @@
+#pragma once
+
+#include <util/generic/array_ref.h>
+#include <util/generic/noncopyable.h>
+#include <util/generic/utility.h>
+#include <util/system/yassert.h>
+
+#include <stdlib.h>
+
+template <typename T, class A = std::allocator<T>>
+class TVectorSwaps : TNonCopyable {
+private:
+ T* Start;
+ T* Finish;
+ T* EndOfStorage;
+
+ void StateCheck() {
+ Y_ASSERT(Start <= Finish);
+ Y_ASSERT(Finish <= EndOfStorage);
+ }
+
+public:
+ typedef T* iterator;
+ typedef const T* const_iterator;
+
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ TVectorSwaps()
+ : Start()
+ , Finish()
+ , EndOfStorage()
+ {
+ }
+
+ ~TVectorSwaps() {
+ for (size_t i = 0; i < size(); ++i) {
+ Start[i].~T();
+ }
+ free(Start);
+ }
+
+ operator TArrayRef<const T>() const {
+ return MakeArrayRef(data(), size());
+ }
+
+ operator TArrayRef<T>() {
+ return MakeArrayRef(data(), size());
+ }
+
+ size_t capacity() const {
+ return EndOfStorage - Start;
+ }
+
+ size_t size() const {
+ return Finish - Start;
+ }
+
+ bool empty() const {
+ return size() == 0;
+ }
+
+ T* data() {
+ return Start;
+ }
+
+ const T* data() const {
+ return Start;
+ }
+
+ T& operator[](size_t index) {
+ Y_ASSERT(index < size());
+ return Start[index];
+ }
+
+ const T& operator[](size_t index) const {
+ Y_ASSERT(index < size());
+ return Start[index];
+ }
+
+ iterator begin() {
+ return Start;
+ }
+
+ iterator end() {
+ return Finish;
+ }
+
+ const_iterator begin() const {
+ return Start;
+ }
+
+ const_iterator end() const {
+ return Finish;
+ }
+
+ reverse_iterator rbegin() {
+ return reverse_iterator(end());
+ }
+ reverse_iterator rend() {
+ return reverse_iterator(begin());
+ }
+
+ const_reverse_iterator rbegin() const {
+ return reverse_iterator(end());
+ }
+ const_reverse_iterator rend() const {
+ return reverse_iterator(begin());
+ }
+
+ void swap(TVectorSwaps<T>& that) {
+ DoSwap(Start, that.Start);
+ DoSwap(Finish, that.Finish);
+ DoSwap(EndOfStorage, that.EndOfStorage);
+ }
+
+ void reserve(size_t n) {
+ if (n <= capacity()) {
+ return;
+ }
+
+ size_t newCapacity = FastClp2(n);
+ TVectorSwaps<T> tmp;
+ tmp.Start = (T*)malloc(sizeof(T) * newCapacity);
+ Y_VERIFY(!!tmp.Start);
+
+ tmp.EndOfStorage = tmp.Start + newCapacity;
+
+ for (size_t i = 0; i < size(); ++i) {
+ // TODO: catch exceptions
+ new (tmp.Start + i) T();
+ DoSwap(Start[i], tmp.Start[i]);
+ }
+
+ tmp.Finish = tmp.Start + size();
+
+ swap(tmp);
+
+ StateCheck();
+ }
+
+ void clear() {
+ TVectorSwaps<T> tmp;
+ swap(tmp);
+ }
+
+ template <class TIterator>
+ void insert(iterator pos, TIterator b, TIterator e) {
+ Y_VERIFY(pos == end(), "TODO: only insert at the end is implemented");
+
+ size_t count = e - b;
+
+ reserve(size() + count);
+
+ TIterator next = b;
+
+ for (size_t i = 0; i < count; ++i) {
+ new (Start + size() + i) T();
+ DoSwap(Start[size() + i], *next);
+ ++next;
+ }
+
+ Finish += count;
+
+ StateCheck();
+ }
+
+ void push_back(T& elem) {
+ insert(end(), &elem, &elem + 1);
+ }
+};
diff --git a/library/cpp/messagebus/vector_swaps_ut.cpp b/library/cpp/messagebus/vector_swaps_ut.cpp
new file mode 100644
index 0000000000..693cc6857b
--- /dev/null
+++ b/library/cpp/messagebus/vector_swaps_ut.cpp
@@ -0,0 +1,17 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "vector_swaps.h"
+
+Y_UNIT_TEST_SUITE(TVectorSwapsTest) {
+ Y_UNIT_TEST(Simple) {
+ TVectorSwaps<THolder<unsigned>> v;
+ for (unsigned i = 0; i < 100; ++i) {
+ THolder<unsigned> tmp(new unsigned(i));
+ v.push_back(tmp);
+ }
+
+ for (unsigned i = 0; i < 100; ++i) {
+ UNIT_ASSERT_VALUES_EQUAL(i, *v[i]);
+ }
+ }
+}
diff --git a/library/cpp/messagebus/www/bus-ico.png b/library/cpp/messagebus/www/bus-ico.png
new file mode 100644
index 0000000000..c69a461892
--- /dev/null
+++ b/library/cpp/messagebus/www/bus-ico.png
Binary files differ
diff --git a/library/cpp/messagebus/www/concat_strings.h b/library/cpp/messagebus/www/concat_strings.h
new file mode 100644
index 0000000000..7b730564eb
--- /dev/null
+++ b/library/cpp/messagebus/www/concat_strings.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/stream/str.h>
+
+// ATTN: not equivalent to TString::Join - cat concat anything "outputable" to stream, not only TString convertable types.
+
+inline void DoConcatStrings(TStringStream&) {
+}
+
+template <class T, class... R>
+inline void DoConcatStrings(TStringStream& ss, const T& t, const R&... r) {
+ ss << t;
+ DoConcatStrings(ss, r...);
+}
+
+template <class... R>
+inline TString ConcatStrings(const R&... r) {
+ TStringStream ss;
+ DoConcatStrings(ss, r...);
+ return ss.Str();
+}
diff --git a/library/cpp/messagebus/www/html_output.cpp b/library/cpp/messagebus/www/html_output.cpp
new file mode 100644
index 0000000000..10ea2e163b
--- /dev/null
+++ b/library/cpp/messagebus/www/html_output.cpp
@@ -0,0 +1,4 @@
+#include "html_output.h"
+
+Y_POD_THREAD(IOutputStream*)
+HtmlOutputStreamPtr;
diff --git a/library/cpp/messagebus/www/html_output.h b/library/cpp/messagebus/www/html_output.h
new file mode 100644
index 0000000000..27e77adefa
--- /dev/null
+++ b/library/cpp/messagebus/www/html_output.h
@@ -0,0 +1,324 @@
+#pragma once
+
+#include "concat_strings.h"
+
+#include <util/generic/string.h>
+#include <util/stream/output.h>
+#include <library/cpp/html/pcdata/pcdata.h>
+#include <util/system/tls.h>
+
+extern Y_POD_THREAD(IOutputStream*) HtmlOutputStreamPtr;
+
+static IOutputStream& HtmlOutputStream() {
+ Y_VERIFY(!!HtmlOutputStreamPtr);
+ return *HtmlOutputStreamPtr;
+}
+
+struct THtmlOutputStreamPushPop {
+ IOutputStream* const Prev;
+
+ THtmlOutputStreamPushPop(IOutputStream* outputStream)
+ : Prev(HtmlOutputStreamPtr)
+ {
+ HtmlOutputStreamPtr = outputStream;
+ }
+
+ ~THtmlOutputStreamPushPop() {
+ HtmlOutputStreamPtr = Prev;
+ }
+};
+
+struct TChars {
+ TString Text;
+ bool NeedEscape;
+
+ TChars(TStringBuf text)
+ : Text(text)
+ , NeedEscape(true)
+ {
+ }
+ TChars(TStringBuf text, bool escape)
+ : Text(text)
+ , NeedEscape(escape)
+ {
+ }
+ TChars(const char* text)
+ : Text(text)
+ , NeedEscape(true)
+ {
+ }
+ TChars(const char* text, bool escape)
+ : Text(text)
+ , NeedEscape(escape)
+ {
+ }
+
+ TString Escape() {
+ if (NeedEscape) {
+ return EncodeHtmlPcdata(Text);
+ } else {
+ return Text;
+ }
+ }
+};
+
+struct TAttr {
+ TString Name;
+ TString Value;
+
+ TAttr(TStringBuf name, TStringBuf value)
+ : Name(name)
+ , Value(value)
+ {
+ }
+
+ TAttr() {
+ }
+
+ bool operator!() const {
+ return !Name;
+ }
+};
+
+static inline void Doctype() {
+ HtmlOutputStream() << "<!doctype html>\n";
+}
+
+static inline void Nl() {
+ HtmlOutputStream() << "\n";
+}
+
+static inline void Sp() {
+ HtmlOutputStream() << " ";
+}
+
+static inline void Text(TStringBuf text) {
+ HtmlOutputStream() << EncodeHtmlPcdata(text);
+}
+
+static inline void Line(TStringBuf text) {
+ Text(text);
+ Nl();
+}
+
+static inline void WriteAttr(TAttr a) {
+ if (!!a) {
+ HtmlOutputStream() << " " << a.Name << "='" << EncodeHtmlPcdata(a.Value) << "'";
+ }
+}
+
+static inline void Open(TStringBuf tag, TAttr a1 = TAttr(), TAttr a2 = TAttr(), TAttr a3 = TAttr(), TAttr a4 = TAttr()) {
+ HtmlOutputStream() << "<" << tag;
+ WriteAttr(a1);
+ WriteAttr(a2);
+ WriteAttr(a3);
+ WriteAttr(a4);
+ HtmlOutputStream() << ">";
+}
+
+static inline void Open(TStringBuf tag, TStringBuf cssClass, TStringBuf id = "") {
+ Open(tag, TAttr("class", cssClass), !!id ? TAttr("id", id) : TAttr());
+}
+
+static inline void OpenBlock(TStringBuf tag, TStringBuf cssClass = "") {
+ Open(tag, cssClass);
+ Nl();
+}
+
+static inline void Close(TStringBuf tag) {
+ HtmlOutputStream() << "</" << tag << ">\n";
+}
+
+static inline void CloseBlock(TStringBuf tag) {
+ Close(tag);
+ Nl();
+}
+
+static inline void TagWithContent(TStringBuf tag, TChars content) {
+ HtmlOutputStream() << "<" << tag << ">" << content.Escape() << "</" << tag << ">";
+}
+
+static inline void BlockTagWithContent(TStringBuf tag, TStringBuf content) {
+ TagWithContent(tag, content);
+ Nl();
+}
+
+static inline void TagWithClass(TStringBuf tag, TStringBuf cssClass) {
+ Open(tag, cssClass);
+ Close(tag);
+}
+
+static inline void Hn(unsigned n, TStringBuf title) {
+ BlockTagWithContent(ConcatStrings("h", n), title);
+}
+
+static inline void Small(TStringBuf text) {
+ TagWithContent("small", text);
+}
+
+static inline void HnWithSmall(unsigned n, TStringBuf title, TStringBuf small) {
+ TString tagName = ConcatStrings("h", n);
+ Open(tagName);
+ HtmlOutputStream() << title;
+ Sp();
+ Small(small);
+ Close(tagName);
+}
+
+static inline void H1(TStringBuf title) {
+ Hn(1, title);
+}
+
+static inline void H2(TStringBuf title) {
+ Hn(2, title);
+}
+
+static inline void H3(TStringBuf title) {
+ Hn(3, title);
+}
+
+static inline void H4(TStringBuf title) {
+ Hn(4, title);
+}
+
+static inline void H5(TStringBuf title) {
+ Hn(5, title);
+}
+
+static inline void H6(TStringBuf title) {
+ Hn(6, title);
+}
+
+static inline void Pre(TStringBuf content) {
+ HtmlOutputStream() << "<pre>" << EncodeHtmlPcdata(content) << "</pre>\n";
+}
+
+static inline void Li(TStringBuf content) {
+ BlockTagWithContent("li", content);
+}
+
+static inline void LiWithClass(TStringBuf cssClass, TStringBuf content) {
+ Open("li", cssClass);
+ Text(content);
+ Close("li");
+}
+
+static inline void OpenA(TStringBuf href) {
+ Open("a", TAttr("href", href));
+}
+
+static inline void A(TStringBuf href, TStringBuf text) {
+ OpenA(href);
+ Text(text);
+ Close("a");
+}
+
+static inline void Td(TStringBuf content) {
+ TagWithContent("td", content);
+}
+
+static inline void Th(TStringBuf content, TStringBuf cssClass = "") {
+ OpenBlock("th", cssClass);
+ Text(content);
+ CloseBlock("th");
+}
+
+static inline void DivWithClassAndContent(TStringBuf cssClass, TStringBuf content) {
+ Open("div", cssClass);
+ Text(content);
+ Close("div");
+}
+
+static inline void BootstrapError(TStringBuf text) {
+ DivWithClassAndContent("alert alert-danger", text);
+}
+
+static inline void BootstrapInfo(TStringBuf text) {
+ DivWithClassAndContent("alert alert-info", text);
+}
+
+static inline void ScriptHref(TStringBuf href) {
+ Open("script",
+ TAttr("language", "javascript"),
+ TAttr("type", "text/javascript"),
+ TAttr("src", href));
+ Close("script");
+ Nl();
+}
+
+static inline void LinkStylesheet(TStringBuf href) {
+ Open("link", TAttr("rel", "stylesheet"), TAttr("href", href));
+ Close("link");
+ Nl();
+}
+
+static inline void LinkFavicon(TStringBuf href) {
+ Open("link", TAttr("rel", "shortcut icon"), TAttr("href", href));
+ Close("link");
+ Nl();
+}
+
+static inline void Title(TChars title) {
+ TagWithContent("title", title);
+ Nl();
+}
+
+static inline void Code(TStringBuf content) {
+ TagWithContent("code", content);
+}
+
+struct TTagGuard {
+ const TString TagName;
+
+ TTagGuard(TStringBuf tagName, TStringBuf cssClass, TStringBuf id = "")
+ : TagName(tagName)
+ {
+ Open(TagName, cssClass, id);
+ }
+
+ TTagGuard(TStringBuf tagName, TAttr a1 = TAttr(), TAttr a2 = TAttr(), TAttr a3 = TAttr(), TAttr a4 = TAttr())
+ : TagName(tagName)
+ {
+ Open(tagName, a1, a2, a3, a4);
+ }
+
+ ~TTagGuard() {
+ Close(TagName);
+ }
+};
+
+struct TDivGuard: public TTagGuard {
+ TDivGuard(TStringBuf cssClass, TStringBuf id = "")
+ : TTagGuard("div", cssClass, id)
+ {
+ }
+
+ TDivGuard(TAttr a1 = TAttr(), TAttr a2 = TAttr(), TAttr a3 = TAttr())
+ : TTagGuard("div", a1, a2, a3)
+ {
+ }
+};
+
+struct TAGuard {
+ TAGuard(TStringBuf href) {
+ OpenA(href);
+ }
+
+ ~TAGuard() {
+ Close("a");
+ }
+};
+
+struct TScriptFunctionGuard {
+ TTagGuard Script;
+
+ TScriptFunctionGuard()
+ : Script("script")
+ {
+ Line("$(function() {");
+ }
+
+ ~TScriptFunctionGuard() {
+ Line("});");
+ }
+};
diff --git a/library/cpp/messagebus/www/messagebus.js b/library/cpp/messagebus/www/messagebus.js
new file mode 100644
index 0000000000..e30508b879
--- /dev/null
+++ b/library/cpp/messagebus/www/messagebus.js
@@ -0,0 +1,48 @@
+function logTransform(v) {
+ return Math.log(v + 1);
+}
+
+function plotHist(where, hist) {
+ var max = hist.map(function(x) {return x[1]}).reduce(function(x, y) {return Math.max(x, y)});
+
+ var ticks = [];
+ for (var t = 1; ; t *= 10) {
+ if (t > max) {
+ break;
+ }
+ ticks.push(t);
+ }
+
+ $.plot(where, [hist],
+ {
+ data: hist,
+ series: {
+ bars: {
+ show: true,
+ barWidth: 0.9
+ }
+ },
+ xaxis: {
+ mode: 'categories',
+ tickLength: 0
+ },
+ yaxis: {
+ ticks: ticks,
+ transform: logTransform
+ }
+ }
+ );
+}
+
+function plotQueueSize(where, data, ticks) {
+ $.plot(where, [data],
+ {
+ xaxis: {
+ ticks: ticks,
+ },
+ yaxis: {
+ //transform: logTransform
+ }
+ }
+ );
+}
diff --git a/library/cpp/messagebus/www/www.cpp b/library/cpp/messagebus/www/www.cpp
new file mode 100644
index 0000000000..62ec241d85
--- /dev/null
+++ b/library/cpp/messagebus/www/www.cpp
@@ -0,0 +1,930 @@
+#include "www.h"
+
+#include "concat_strings.h"
+#include "html_output.h"
+
+#include <library/cpp/messagebus/remote_connection_status.h>
+#include <library/cpp/monlib/deprecated/json/writer.h>
+
+#include <library/cpp/archive/yarchive.h>
+#include <library/cpp/http/fetch/httpfsm.h>
+#include <library/cpp/http/fetch/httpheader.h>
+#include <library/cpp/http/server/http.h>
+#include <library/cpp/json/writer/json.h>
+#include <library/cpp/uri/http_url.h>
+
+#include <util/string/cast.h>
+#include <util/string/printf.h>
+#include <util/system/mutex.h>
+
+#include <utility>
+
+using namespace NBus;
+using namespace NBus::NPrivate;
+using namespace NActor;
+using namespace NActor::NPrivate;
+
+static const char HTTP_OK_JS[] = "HTTP/1.1 200 Ok\r\nContent-Type: text/javascript\r\nConnection: Close\r\n\r\n";
+static const char HTTP_OK_JSON[] = "HTTP/1.1 200 Ok\r\nContent-Type: application/json; charset=utf-8\r\nConnection: Close\r\n\r\n";
+static const char HTTP_OK_PNG[] = "HTTP/1.1 200 Ok\r\nContent-Type: image/png\r\nConnection: Close\r\n\r\n";
+static const char HTTP_OK_BIN[] = "HTTP/1.1 200 Ok\r\nContent-Type: application/octet-stream\r\nConnection: Close\r\n\r\n";
+static const char HTTP_OK_HTML[] = "HTTP/1.1 200 Ok\r\nContent-Type: text/html; charset=utf-8\r\nConnection: Close\r\n\r\n";
+
+namespace {
+ typedef TIntrusivePtr<TBusModuleInternal> TBusModuleInternalPtr;
+
+ template <typename TValuePtr>
+ struct TNamedValues {
+ TVector<std::pair<TString, TValuePtr>> Entries;
+
+ TValuePtr FindByName(TStringBuf name) {
+ Y_VERIFY(!!name);
+
+ for (unsigned i = 0; i < Entries.size(); ++i) {
+ if (Entries[i].first == name) {
+ return Entries[i].second;
+ }
+ }
+ return TValuePtr();
+ }
+
+ TString FindNameByPtr(TValuePtr value) {
+ Y_VERIFY(!!value);
+
+ for (unsigned i = 0; i < Entries.size(); ++i) {
+ if (Entries[i].second.Get() == value.Get()) {
+ return Entries[i].first;
+ }
+ }
+
+ Y_FAIL("unregistered");
+ }
+
+ void Add(TValuePtr p) {
+ Y_VERIFY(!!p);
+
+ // Do not add twice
+ for (unsigned i = 0; i < Entries.size(); ++i) {
+ if (Entries[i].second.Get() == p.Get()) {
+ return;
+ }
+ }
+
+ if (!!p->GetNameInternal()) {
+ TValuePtr current = FindByName(p->GetNameInternal());
+
+ if (!current) {
+ Entries.emplace_back(p->GetNameInternal(), p);
+ return;
+ }
+ }
+
+ for (unsigned i = 1;; ++i) {
+ TString prefix = p->GetNameInternal();
+ if (!prefix) {
+ prefix = "unnamed";
+ }
+ TString name = ConcatStrings(prefix, "-", i);
+
+ TValuePtr current = FindByName(name);
+
+ if (!current) {
+ Entries.emplace_back(name, p);
+ return;
+ }
+ }
+ }
+
+ size_t size() const {
+ return Entries.size();
+ }
+
+ bool operator!() const {
+ return size() == 0;
+ }
+ };
+
+ template <typename TSessionPtr>
+ struct TSessionValues: public TNamedValues<TSessionPtr> {
+ typedef TNamedValues<TSessionPtr> TBase;
+
+ TVector<TString> GetNamesForQueue(TBusMessageQueue* queue) {
+ TVector<TString> r;
+ for (unsigned i = 0; i < TBase::size(); ++i) {
+ if (TBase::Entries[i].second->GetQueue() == queue) {
+ r.push_back(TBase::Entries[i].first);
+ }
+ }
+ return r;
+ }
+ };
+}
+
+namespace {
+ TString RootHref() {
+ return ConcatStrings("?");
+ }
+
+ TString QueueHref(TStringBuf name) {
+ return ConcatStrings("?q=", name);
+ }
+
+ TString ServerSessionHref(TStringBuf name) {
+ return ConcatStrings("?ss=", name);
+ }
+
+ TString ClientSessionHref(TStringBuf name) {
+ return ConcatStrings("?cs=", name);
+ }
+
+ TString OldModuleHref(TStringBuf name) {
+ return ConcatStrings("?om=", name);
+ }
+
+ /*
+ static void RootLink() {
+ A(RootHref(), "root");
+ }
+ */
+
+ void QueueLink(TStringBuf name) {
+ A(QueueHref(name), name);
+ }
+
+ void ServerSessionLink(TStringBuf name) {
+ A(ServerSessionHref(name), name);
+ }
+
+ void ClientSessionLink(TStringBuf name) {
+ A(ClientSessionHref(name), name);
+ }
+
+ void OldModuleLink(TStringBuf name) {
+ A(OldModuleHref(name), name);
+ }
+
+}
+
+const unsigned char WWW_STATIC_DATA[] = {
+#include "www_static.inc"
+};
+
+class TWwwStaticLoader: public TArchiveReader {
+public:
+ TWwwStaticLoader()
+ : TArchiveReader(TBlob::NoCopy(WWW_STATIC_DATA, sizeof(WWW_STATIC_DATA)))
+ {
+ }
+};
+
+struct TBusWww::TImpl {
+ // TODO: use weak pointers
+ TNamedValues<TBusMessageQueuePtr> Queues;
+ TSessionValues<TIntrusivePtr<TBusClientSession>> ClientSessions;
+ TSessionValues<TIntrusivePtr<TBusServerSession>> ServerSessions;
+ TSessionValues<TBusModuleInternalPtr> Modules;
+
+ TMutex Mutex;
+
+ void RegisterClientSession(TBusClientSessionPtr s) {
+ Y_VERIFY(!!s);
+ TGuard<TMutex> g(Mutex);
+ ClientSessions.Add(s.Get());
+ Queues.Add(s->GetQueue());
+ }
+
+ void RegisterServerSession(TBusServerSessionPtr s) {
+ Y_VERIFY(!!s);
+ TGuard<TMutex> g(Mutex);
+ ServerSessions.Add(s.Get());
+ Queues.Add(s->GetQueue());
+ }
+
+ void RegisterQueue(TBusMessageQueuePtr q) {
+ Y_VERIFY(!!q);
+ TGuard<TMutex> g(Mutex);
+ Queues.Add(q);
+ }
+
+ void RegisterModule(TBusModule* module) {
+ Y_VERIFY(!!module);
+ TGuard<TMutex> g(Mutex);
+
+ {
+ TVector<TBusClientSessionPtr> clientSessions = module->GetInternal()->GetClientSessionsInternal();
+ for (unsigned i = 0; i < clientSessions.size(); ++i) {
+ RegisterClientSession(clientSessions[i]);
+ }
+ }
+
+ {
+ TVector<TBusServerSessionPtr> serverSessions = module->GetInternal()->GetServerSessionsInternal();
+ for (unsigned i = 0; i < serverSessions.size(); ++i) {
+ RegisterServerSession(serverSessions[i]);
+ }
+ }
+
+ Queues.Add(module->GetInternal()->GetQueue());
+ Modules.Add(module->GetInternal());
+ }
+
+ TString FindQueueNameBySessionName(TStringBuf sessionName, bool client) {
+ TIntrusivePtr<TBusClientSession> clientSession;
+ TIntrusivePtr<TBusServerSession> serverSession;
+ TBusSession* session;
+ if (client) {
+ clientSession = ClientSessions.FindByName(sessionName);
+ session = clientSession.Get();
+ } else {
+ serverSession = ServerSessions.FindByName(sessionName);
+ session = serverSession.Get();
+ }
+ Y_VERIFY(!!session);
+ return Queues.FindNameByPtr(session->GetQueue());
+ }
+
+ struct TRequest {
+ TImpl* const Outer;
+ IOutputStream& Os;
+ const TCgiParameters& CgiParams;
+ const TOptionalParams& Params;
+
+ TRequest(TImpl* outer, IOutputStream& os, const TCgiParameters& cgiParams, const TOptionalParams& params)
+ : Outer(outer)
+ , Os(os)
+ , CgiParams(cgiParams)
+ , Params(params)
+ {
+ }
+
+ void CrumbsParentLinks() {
+ for (unsigned i = 0; i < Params.ParentLinks.size(); ++i) {
+ const TLink& link = Params.ParentLinks[i];
+ TTagGuard li("li");
+ A(link.Href, link.Title);
+ }
+ }
+
+ void Crumb(TStringBuf name, TStringBuf href = "") {
+ if (!!href) {
+ TTagGuard li("li");
+ A(href, name);
+ } else {
+ LiWithClass("active", name);
+ }
+ }
+
+ void BreadcrumbRoot() {
+ TTagGuard ol("ol", "breadcrumb");
+ CrumbsParentLinks();
+ Crumb("MessageBus");
+ }
+
+ void BreadcrumbQueue(TStringBuf queueName) {
+ TTagGuard ol("ol", "breadcrumb");
+ CrumbsParentLinks();
+ Crumb("MessageBus", RootHref());
+ Crumb(ConcatStrings("queue ", queueName));
+ }
+
+ void BreadcrumbSession(TStringBuf sessionName, bool client) {
+ TString queueName = Outer->FindQueueNameBySessionName(sessionName, client);
+ TStringBuf whatSession = client ? "client session" : "server session";
+
+ TTagGuard ol("ol", "breadcrumb");
+ CrumbsParentLinks();
+ Crumb("MessageBus", RootHref());
+ Crumb(ConcatStrings("queue ", queueName), QueueHref(queueName));
+ Crumb(ConcatStrings(whatSession, " ", sessionName));
+ }
+
+ void ServeSessionsOfQueue(TBusMessageQueuePtr queue, bool includeQueue) {
+ TVector<TString> clientNames = Outer->ClientSessions.GetNamesForQueue(queue.Get());
+ TVector<TString> serverNames = Outer->ServerSessions.GetNamesForQueue(queue.Get());
+ TVector<TString> moduleNames = Outer->Modules.GetNamesForQueue(queue.Get());
+
+ TTagGuard table("table", "table table-condensed table-bordered");
+
+ {
+ TTagGuard colgroup("colgroup");
+ TagWithClass("col", "col-md-2");
+ TagWithClass("col", "col-md-2");
+ TagWithClass("col", "col-md-8");
+ }
+
+ {
+ TTagGuard tr("tr");
+ Th("What", "span2");
+ Th("Name", "span2");
+ Th("Status", "span6");
+ }
+
+ if (includeQueue) {
+ TTagGuard tr1("tr");
+ Td("queue");
+
+ {
+ TTagGuard td("td");
+ QueueLink(Outer->Queues.FindNameByPtr(queue));
+ }
+
+ {
+ TTagGuard tr2("td");
+ Pre(queue->GetStatusSingleLine());
+ }
+ }
+
+ for (unsigned j = 0; j < clientNames.size(); ++j) {
+ TTagGuard tr("tr");
+ Td("client session");
+
+ {
+ TTagGuard td("td");
+ ClientSessionLink(clientNames[j]);
+ }
+
+ {
+ TTagGuard td("td");
+ Pre(Outer->ClientSessions.FindByName(clientNames[j])->GetStatusSingleLine());
+ }
+ }
+
+ for (unsigned j = 0; j < serverNames.size(); ++j) {
+ TTagGuard tr("tr");
+ Td("server session");
+
+ {
+ TTagGuard td("td");
+ ServerSessionLink(serverNames[j]);
+ }
+
+ {
+ TTagGuard td("td");
+ Pre(Outer->ServerSessions.FindByName(serverNames[j])->GetStatusSingleLine());
+ }
+ }
+
+ for (unsigned j = 0; j < moduleNames.size(); ++j) {
+ TTagGuard tr("tr");
+ Td("module");
+
+ {
+ TTagGuard td("td");
+ if (false) {
+ OldModuleLink(moduleNames[j]);
+ } else {
+ // TODO
+ Text(moduleNames[j]);
+ }
+ }
+
+ {
+ TTagGuard td("td");
+ Pre(Outer->Modules.FindByName(moduleNames[j])->GetStatusSingleLine());
+ }
+ }
+ }
+
+ void ServeQueue(const TString& name) {
+ TBusMessageQueuePtr queue = Outer->Queues.FindByName(name);
+
+ if (!queue) {
+ BootstrapError(ConcatStrings("queue not found by name: ", name));
+ return;
+ }
+
+ BreadcrumbQueue(name);
+
+ TDivGuard container("container");
+
+ H1(ConcatStrings("MessageBus queue ", '"', name, '"'));
+
+ TBusMessageQueueStatus status = queue->GetStatusRecordInternal();
+
+ Pre(status.PrintToString());
+
+ ServeSessionsOfQueue(queue, false);
+
+ HnWithSmall(3, "Peak queue size", "(stored for an hour)");
+
+ {
+ TDivGuard div;
+ TDivGuard div2(TAttr("id", "queue-size-graph"), TAttr("style", "height: 300px"));
+ }
+
+ {
+ TScriptFunctionGuard script;
+
+ NJsonWriter::TBuf data(NJsonWriter::HEM_ESCAPE_HTML);
+ NJsonWriter::TBuf ticks(NJsonWriter::HEM_ESCAPE_HTML);
+
+ const TExecutorHistory& history = status.ExecutorStatus.History;
+
+ data.BeginList();
+ ticks.BeginList();
+ for (unsigned i = 0; i < history.HistoryRecords.size(); ++i) {
+ ui64 secondOfMinute = (history.FirstHistoryRecordSecond() + i) % 60;
+ ui64 minuteOfHour = (history.FirstHistoryRecordSecond() + i) / 60 % 60;
+
+ unsigned printEach;
+
+ if (history.HistoryRecords.size() <= 500) {
+ printEach = 1;
+ } else if (history.HistoryRecords.size() <= 1000) {
+ printEach = 2;
+ } else if (history.HistoryRecords.size() <= 3000) {
+ printEach = 6;
+ } else {
+ printEach = 12;
+ }
+
+ if (secondOfMinute % printEach != 0) {
+ continue;
+ }
+
+ ui32 max = 0;
+ for (unsigned j = 0; j < printEach; ++j) {
+ if (i < j) {
+ continue;
+ }
+ max = Max<ui32>(max, history.HistoryRecords[i - j].MaxQueueSize);
+ }
+
+ data.BeginList();
+ data.WriteString(ToString(i));
+ data.WriteInt(max);
+ data.EndList();
+
+ // TODO: can be done with flot time plugin
+ if (history.HistoryRecords.size() <= 20) {
+ ticks.BeginList();
+ ticks.WriteInt(i);
+ ticks.WriteString(ToString(secondOfMinute));
+ ticks.EndList();
+ } else if (history.HistoryRecords.size() <= 60) {
+ if (secondOfMinute % 5 == 0) {
+ ticks.BeginList();
+ ticks.WriteInt(i);
+ ticks.WriteString(ToString(secondOfMinute));
+ ticks.EndList();
+ }
+ } else {
+ bool needTick;
+ if (history.HistoryRecords.size() <= 3 * 60) {
+ needTick = secondOfMinute % 15 == 0;
+ } else if (history.HistoryRecords.size() <= 7 * 60) {
+ needTick = secondOfMinute % 30 == 0;
+ } else if (history.HistoryRecords.size() <= 20 * 60) {
+ needTick = secondOfMinute == 0;
+ } else {
+ needTick = secondOfMinute == 0 && minuteOfHour % 5 == 0;
+ }
+ if (needTick) {
+ ticks.BeginList();
+ ticks.WriteInt(i);
+ ticks.WriteString(Sprintf(":%02u:%02u", (unsigned)minuteOfHour, (unsigned)secondOfMinute));
+ ticks.EndList();
+ }
+ }
+ }
+ ticks.EndList();
+ data.EndList();
+
+ HtmlOutputStream() << " var data = " << data.Str() << ";\n";
+ HtmlOutputStream() << " var ticks = " << ticks.Str() << ";\n";
+ HtmlOutputStream() << " plotQueueSize('#queue-size-graph', data, ticks);\n";
+ }
+ }
+
+ void ServeSession(TStringBuf name, bool client) {
+ TIntrusivePtr<TBusClientSession> clientSession;
+ TIntrusivePtr<TBusServerSession> serverSession;
+ TBusSession* session;
+ TStringBuf whatSession;
+ if (client) {
+ whatSession = "client session";
+ clientSession = Outer->ClientSessions.FindByName(name);
+ session = clientSession.Get();
+ } else {
+ whatSession = "server session";
+ serverSession = Outer->ServerSessions.FindByName(name);
+ session = serverSession.Get();
+ }
+ if (!session) {
+ BootstrapError(ConcatStrings(whatSession, " not found by name: ", name));
+ return;
+ }
+
+ TSessionDumpStatus dumpStatus = session->GetStatusRecordInternal();
+
+ TBusMessageQueuePtr queue = session->GetQueue();
+ TString queueName = Outer->Queues.FindNameByPtr(session->GetQueue());
+
+ BreadcrumbSession(name, client);
+
+ TDivGuard container("container");
+
+ H1(ConcatStrings("MessageBus ", whatSession, " ", '"', name, '"'));
+
+ TBusMessageQueueStatus queueStatus = queue->GetStatusRecordInternal();
+
+ {
+ H3(ConcatStrings("queue ", queueName));
+ Pre(queueStatus.PrintToString());
+ }
+
+ TSessionDumpStatus status = session->GetStatusRecordInternal();
+
+ if (status.Shutdown) {
+ BootstrapError("Session shut down");
+ return;
+ }
+
+ H3("Basic");
+ Pre(status.Head);
+
+ if (status.ConnectionStatusSummary.Server) {
+ H3("Acceptors");
+ Pre(status.Acceptors);
+ }
+
+ H3("Connections");
+ Pre(status.ConnectionsSummary);
+
+ {
+ TDivGuard div;
+ TTagGuard button("button",
+ TAttr("type", "button"),
+ TAttr("class", "btn"),
+ TAttr("data-toggle", "collapse"),
+ TAttr("data-target", "#connections"));
+ Text("Show connection details");
+ }
+ {
+ TDivGuard div(TAttr("id", "connections"), TAttr("class", "collapse"));
+ Pre(status.Connections);
+ }
+
+ H3("TBusSessionConfig");
+ Pre(status.Config.PrintToString());
+
+ if (!client) {
+ H3("Message process time histogram");
+
+ const TDurationHistogram& h =
+ dumpStatus.ConnectionStatusSummary.WriterStatus.Incremental.ProcessDurationHistogram;
+
+ {
+ TDivGuard div;
+ TDivGuard div2(TAttr("id", "h"), TAttr("style", "height: 300px"));
+ }
+
+ {
+ TScriptFunctionGuard script;
+
+ NJsonWriter::TBuf buf(NJsonWriter::HEM_ESCAPE_HTML);
+ buf.BeginList();
+ for (unsigned i = 0; i < h.Times.size(); ++i) {
+ TString label = TDurationHistogram::LabelBefore(i);
+ buf.BeginList();
+ buf.WriteString(label);
+ buf.WriteLongLong(h.Times[i]);
+ buf.EndList();
+ }
+ buf.EndList();
+
+ HtmlOutputStream() << " var hist = " << buf.Str() << ";\n";
+ HtmlOutputStream() << " plotHist('#h', hist);\n";
+ }
+ }
+ }
+
+ void ServeDefault() {
+ if (!Outer->Queues) {
+ BootstrapError("no queues");
+ return;
+ }
+
+ BreadcrumbRoot();
+
+ TDivGuard container("container");
+
+ H1("MessageBus queues");
+
+ for (unsigned i = 0; i < Outer->Queues.size(); ++i) {
+ TString queueName = Outer->Queues.Entries[i].first;
+ TBusMessageQueuePtr queue = Outer->Queues.Entries[i].second;
+
+ HnWithSmall(3, queueName, "(queue)");
+
+ ServeSessionsOfQueue(queue, true);
+ }
+ }
+
+ void WriteQueueSensors(NMonitoring::TDeprecatedJsonWriter& sj, TStringBuf queueName, TBusMessageQueue* queue) {
+ auto status = queue->GetStatusRecordInternal();
+ sj.OpenMetric();
+ sj.WriteLabels("mb_queue", queueName, "sensor", "WorkQueueSize");
+ sj.WriteValue(status.ExecutorStatus.WorkQueueSize);
+ sj.CloseMetric();
+ }
+
+ void WriteMessageCounterSensors(NMonitoring::TDeprecatedJsonWriter& sj,
+ TStringBuf labelName, TStringBuf sessionName, bool read, const TMessageCounter& counter) {
+ TStringBuf readOrWrite = read ? "read" : "write";
+
+ sj.OpenMetric();
+ sj.WriteLabels(labelName, sessionName, "mb_dir", readOrWrite, "sensor", "MessageBytes");
+ sj.WriteValue(counter.BytesData);
+ sj.WriteModeDeriv();
+ sj.CloseMetric();
+
+ sj.OpenMetric();
+ sj.WriteLabels(labelName, sessionName, "mb_dir", readOrWrite, "sensor", "MessageCount");
+ sj.WriteValue(counter.Count);
+ sj.WriteModeDeriv();
+ sj.CloseMetric();
+ }
+
+ void WriteSessionStatus(NMonitoring::TDeprecatedJsonWriter& sj, TStringBuf sessionName, bool client,
+ TBusSession* session) {
+ TStringBuf labelName = client ? "mb_client_session" : "mb_server_session";
+
+ auto status = session->GetStatusRecordInternal();
+
+ sj.OpenMetric();
+ sj.WriteLabels(labelName, sessionName, "sensor", "InFlightCount");
+ sj.WriteValue(status.Status.InFlightCount);
+ sj.CloseMetric();
+
+ sj.OpenMetric();
+ sj.WriteLabels(labelName, sessionName, "sensor", "InFlightSize");
+ sj.WriteValue(status.Status.InFlightSize);
+ sj.CloseMetric();
+
+ sj.OpenMetric();
+ sj.WriteLabels(labelName, sessionName, "sensor", "SendQueueSize");
+ sj.WriteValue(status.ConnectionStatusSummary.WriterStatus.SendQueueSize);
+ sj.CloseMetric();
+
+ if (client) {
+ sj.OpenMetric();
+ sj.WriteLabels(labelName, sessionName, "sensor", "AckMessagesSize");
+ sj.WriteValue(status.ConnectionStatusSummary.WriterStatus.AckMessagesSize);
+ sj.CloseMetric();
+ }
+
+ WriteMessageCounterSensors(sj, labelName, sessionName, false,
+ status.ConnectionStatusSummary.WriterStatus.Incremental.MessageCounter);
+ WriteMessageCounterSensors(sj, labelName, sessionName, true,
+ status.ConnectionStatusSummary.ReaderStatus.Incremental.MessageCounter);
+ }
+
+ void ServeSolomonJson(const TString& q, const TString& cs, const TString& ss) {
+ Y_UNUSED(q);
+ Y_UNUSED(cs);
+ Y_UNUSED(ss);
+ bool all = q == "" && cs == "" && ss == "";
+
+ NMonitoring::TDeprecatedJsonWriter sj(&Os);
+
+ sj.OpenDocument();
+ sj.OpenMetrics();
+
+ for (unsigned i = 0; i < Outer->Queues.size(); ++i) {
+ TString queueName = Outer->Queues.Entries[i].first;
+ TBusMessageQueuePtr queue = Outer->Queues.Entries[i].second;
+ if (all || q == queueName) {
+ WriteQueueSensors(sj, queueName, &*queue);
+ }
+
+ TVector<TString> clientNames = Outer->ClientSessions.GetNamesForQueue(queue.Get());
+ TVector<TString> serverNames = Outer->ServerSessions.GetNamesForQueue(queue.Get());
+ TVector<TString> moduleNames = Outer->Modules.GetNamesForQueue(queue.Get());
+ for (auto& sessionName : clientNames) {
+ if (all || cs == sessionName) {
+ auto session = Outer->ClientSessions.FindByName(sessionName);
+ WriteSessionStatus(sj, sessionName, true, &*session);
+ }
+ }
+
+ for (auto& sessionName : serverNames) {
+ if (all || ss == sessionName) {
+ auto session = Outer->ServerSessions.FindByName(sessionName);
+ WriteSessionStatus(sj, sessionName, false, &*session);
+ }
+ }
+ }
+
+ sj.CloseMetrics();
+ sj.CloseDocument();
+ }
+
+ void ServeStatic(IOutputStream& os, TStringBuf path) {
+ if (path.EndsWith(".js")) {
+ os << HTTP_OK_JS;
+ } else if (path.EndsWith(".png")) {
+ os << HTTP_OK_PNG;
+ } else {
+ os << HTTP_OK_BIN;
+ }
+ TBlob blob = Singleton<TWwwStaticLoader>()->ObjectBlobByKey(TString("/") + TString(path));
+ os.Write(blob.Data(), blob.Size());
+ }
+
+ void HeaderJsCss() {
+ LinkStylesheet("//yandex.st/bootstrap/3.0.2/css/bootstrap.css");
+ LinkFavicon("?file=bus-ico.png");
+ ScriptHref("//yandex.st/jquery/2.0.3/jquery.js");
+ ScriptHref("//yandex.st/bootstrap/3.0.2/js/bootstrap.js");
+ ScriptHref("//cdnjs.cloudflare.com/ajax/libs/flot/0.8.1/jquery.flot.min.js");
+ ScriptHref("//cdnjs.cloudflare.com/ajax/libs/flot/0.8.1/jquery.flot.categories.min.js");
+ ScriptHref("?file=messagebus.js");
+ }
+
+ void Serve() {
+ THtmlOutputStreamPushPop pp(&Os);
+
+ TCgiParameters::const_iterator file = CgiParams.Find("file");
+ if (file != CgiParams.end()) {
+ ServeStatic(Os, file->second);
+ return;
+ }
+
+ bool solomonJson = false;
+ TCgiParameters::const_iterator fmt = CgiParams.Find("fmt");
+ if (fmt != CgiParams.end()) {
+ if (fmt->second == "solomon-json") {
+ solomonJson = true;
+ }
+ }
+
+ TCgiParameters::const_iterator cs = CgiParams.Find("cs");
+ TCgiParameters::const_iterator ss = CgiParams.Find("ss");
+ TCgiParameters::const_iterator q = CgiParams.Find("q");
+
+ if (solomonJson) {
+ Os << HTTP_OK_JSON;
+
+ TString qp = q != CgiParams.end() ? q->first : "";
+ TString csp = cs != CgiParams.end() ? cs->first : "";
+ TString ssp = ss != CgiParams.end() ? ss->first : "";
+ ServeSolomonJson(qp, csp, ssp);
+ } else {
+ Os << HTTP_OK_HTML;
+
+ Doctype();
+
+ TTagGuard html("html");
+ {
+ TTagGuard head("head");
+
+ HeaderJsCss();
+ // &#x2709; &#x1f68c;
+ Title(TChars("MessageBus", false));
+ }
+
+ TTagGuard body("body");
+
+ if (cs != CgiParams.end()) {
+ ServeSession(cs->second, true);
+ } else if (ss != CgiParams.end()) {
+ ServeSession(ss->second, false);
+ } else if (q != CgiParams.end()) {
+ ServeQueue(q->second);
+ } else {
+ ServeDefault();
+ }
+ }
+ }
+ };
+
+ void ServeHttp(IOutputStream& os, const TCgiParameters& queryArgs, const TBusWww::TOptionalParams& params) {
+ TGuard<TMutex> g(Mutex);
+
+ TRequest request(this, os, queryArgs, params);
+
+ request.Serve();
+ }
+};
+
+NBus::TBusWww::TBusWww()
+ : Impl(new TImpl)
+{
+}
+
+NBus::TBusWww::~TBusWww() {
+}
+
+void NBus::TBusWww::RegisterClientSession(TBusClientSessionPtr s) {
+ Impl->RegisterClientSession(s);
+}
+
+void TBusWww::RegisterServerSession(TBusServerSessionPtr s) {
+ Impl->RegisterServerSession(s);
+}
+
+void TBusWww::RegisterQueue(TBusMessageQueuePtr q) {
+ Impl->RegisterQueue(q);
+}
+
+void TBusWww::RegisterModule(TBusModule* module) {
+ Impl->RegisterModule(module);
+}
+
+void TBusWww::ServeHttp(IOutputStream& httpOutputStream,
+ const TCgiParameters& queryArgs,
+ const TBusWww::TOptionalParams& params) {
+ Impl->ServeHttp(httpOutputStream, queryArgs, params);
+}
+
+struct TBusWwwHttpServer::TImpl: public THttpServer::ICallBack {
+ TIntrusivePtr<TBusWww> Www;
+ THttpServer HttpServer;
+
+ static THttpServer::TOptions MakeHttpServerOptions(unsigned port) {
+ Y_VERIFY(port > 0);
+ THttpServer::TOptions r;
+ r.Port = port;
+ return r;
+ }
+
+ TImpl(TIntrusivePtr<TBusWww> www, unsigned port)
+ : Www(www)
+ , HttpServer(this, MakeHttpServerOptions(port))
+ {
+ HttpServer.Start();
+ }
+
+ struct TClientRequestImpl: public TClientRequest {
+ TBusWwwHttpServer::TImpl* const Outer;
+
+ TClientRequestImpl(TBusWwwHttpServer::TImpl* outer)
+ : Outer(outer)
+ {
+ }
+
+ bool Reply(void*) override {
+ Outer->ServeRequest(Input(), Output());
+ return true;
+ }
+ };
+
+ TString MakeSimpleResponse(unsigned code, TString text, TString content = "") {
+ if (!content) {
+ TStringStream contentSs;
+ contentSs << code << " " << text;
+ content = contentSs.Str();
+ }
+ TStringStream ss;
+ ss << "HTTP/1.1 "
+ << code << " " << text << "\r\nConnection: Close\r\n\r\n"
+ << content;
+ return ss.Str();
+ }
+
+ void ServeRequest(THttpInput& input, THttpOutput& output) {
+ TCgiParameters cgiParams;
+ try {
+ THttpRequestHeader header;
+ THttpHeaderParser parser;
+ parser.Init(&header);
+ if (parser.Execute(input.FirstLine()) < 0) {
+ HtmlOutputStream() << MakeSimpleResponse(400, "Bad request");
+ return;
+ }
+ THttpURL url;
+ if (url.Parse(header.GetUrl()) != THttpURL::ParsedOK) {
+ HtmlOutputStream() << MakeSimpleResponse(400, "Invalid url");
+ return;
+ }
+ cgiParams.Scan(url.Get(THttpURL::FieldQuery));
+
+ TBusWww::TOptionalParams params;
+ //params.ParentLinks.emplace_back();
+ //params.ParentLinks.back().Title = "temp";
+ //params.ParentLinks.back().Href = "http://wiki.yandex-team.ru/";
+
+ Www->ServeHttp(output, cgiParams, params);
+ } catch (...) {
+ output << MakeSimpleResponse(500, "Exception",
+ TString() + "Exception: " + CurrentExceptionMessage());
+ }
+ }
+
+ TClientRequest* CreateClient() override {
+ return new TClientRequestImpl(this);
+ }
+
+ ~TImpl() override {
+ HttpServer.Stop();
+ }
+};
+
+NBus::TBusWwwHttpServer::TBusWwwHttpServer(TIntrusivePtr<TBusWww> www, unsigned port)
+ : Impl(new TImpl(www, port))
+{
+}
+
+NBus::TBusWwwHttpServer::~TBusWwwHttpServer() {
+}
diff --git a/library/cpp/messagebus/www/www.h b/library/cpp/messagebus/www/www.h
new file mode 100644
index 0000000000..6cd652b477
--- /dev/null
+++ b/library/cpp/messagebus/www/www.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <library/cpp/messagebus/ybus.h>
+#include <library/cpp/messagebus/oldmodule/module.h>
+
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+#include <library/cpp/cgiparam/cgiparam.h>
+
+namespace NBus {
+ class TBusWww: public TAtomicRefCount<TBusWww> {
+ public:
+ struct TLink {
+ TString Title;
+ TString Href;
+ };
+
+ struct TOptionalParams {
+ TVector<TLink> ParentLinks;
+ };
+
+ TBusWww();
+ ~TBusWww();
+
+ void RegisterClientSession(TBusClientSessionPtr);
+ void RegisterServerSession(TBusServerSessionPtr);
+ void RegisterQueue(TBusMessageQueuePtr);
+ void RegisterModule(TBusModule*);
+
+ void ServeHttp(IOutputStream& httpOutputStream, const TCgiParameters& queryArgs, const TOptionalParams& params = TOptionalParams());
+
+ struct TImpl;
+ THolder<TImpl> Impl;
+ };
+
+ class TBusWwwHttpServer {
+ public:
+ TBusWwwHttpServer(TIntrusivePtr<TBusWww> www, unsigned port);
+ ~TBusWwwHttpServer();
+
+ struct TImpl;
+ THolder<TImpl> Impl;
+ };
+
+}
diff --git a/library/cpp/messagebus/www/ya.make b/library/cpp/messagebus/www/ya.make
new file mode 100644
index 0000000000..972390cea3
--- /dev/null
+++ b/library/cpp/messagebus/www/ya.make
@@ -0,0 +1,29 @@
+LIBRARY()
+
+OWNER(g:messagebus)
+
+SRCS(
+ html_output.cpp
+ www.cpp
+)
+
+ARCHIVE(
+ NAME www_static.inc
+ messagebus.js
+ bus-ico.png
+)
+
+PEERDIR(
+ library/cpp/archive
+ library/cpp/cgiparam
+ library/cpp/html/pcdata
+ library/cpp/http/fetch
+ library/cpp/http/server
+ library/cpp/json/writer
+ library/cpp/messagebus
+ library/cpp/messagebus/oldmodule
+ library/cpp/monlib/deprecated/json
+ library/cpp/uri
+)
+
+END()
diff --git a/library/cpp/messagebus/ya.make b/library/cpp/messagebus/ya.make
new file mode 100644
index 0000000000..e13cf06dea
--- /dev/null
+++ b/library/cpp/messagebus/ya.make
@@ -0,0 +1,68 @@
+LIBRARY()
+
+OWNER(g:messagebus)
+
+IF (SANITIZER_TYPE == "undefined")
+ NO_SANITIZE()
+ENDIF()
+
+SRCS(
+ acceptor.cpp
+ acceptor_status.cpp
+ connection.cpp
+ coreconn.cpp
+ duration_histogram.cpp
+ event_loop.cpp
+ futex_like.cpp
+ handler.cpp
+ key_value_printer.cpp
+ local_flags.cpp
+ locator.cpp
+ mb_lwtrace.cpp
+ message.cpp
+ message_counter.cpp
+ message_status.cpp
+ message_status_counter.cpp
+ messqueue.cpp
+ misc/atomic_box.h
+ misc/granup.h
+ misc/test_sync.h
+ misc/tokenquota.h
+ misc/weak_ptr.h
+ network.cpp
+ queue_config.cpp
+ remote_client_connection.cpp
+ remote_client_session.cpp
+ remote_client_session_semaphore.cpp
+ remote_connection.cpp
+ remote_connection_status.cpp
+ remote_server_connection.cpp
+ remote_server_session.cpp
+ remote_server_session_semaphore.cpp
+ session.cpp
+ session_impl.cpp
+ session_job_count.cpp
+ shutdown_state.cpp
+ socket_addr.cpp
+ storage.cpp
+ synchandler.cpp
+ use_after_free_checker.cpp
+ use_count_checker.cpp
+ ybus.h
+)
+
+PEERDIR(
+ contrib/libs/sparsehash
+ library/cpp/codecs
+ library/cpp/deprecated/enum_codegen
+ library/cpp/getopt/small
+ library/cpp/lwtrace
+ library/cpp/messagebus/actor
+ library/cpp/messagebus/config
+ library/cpp/messagebus/monitoring
+ library/cpp/messagebus/scheduler
+ library/cpp/string_utils/indent_text
+ library/cpp/threading/future
+)
+
+END()
diff --git a/library/cpp/messagebus/ybus.h b/library/cpp/messagebus/ybus.h
new file mode 100644
index 0000000000..de21ad8521
--- /dev/null
+++ b/library/cpp/messagebus/ybus.h
@@ -0,0 +1,205 @@
+#pragma once
+
+/// Asynchronous Messaging Library implements framework for sending and
+/// receiving messages between loosely connected processes.
+
+#include "coreconn.h"
+#include "defs.h"
+#include "handler.h"
+#include "handler_impl.h"
+#include "local_flags.h"
+#include "locator.h"
+#include "message.h"
+#include "message_status.h"
+#include "network.h"
+#include "queue_config.h"
+#include "remote_connection_status.h"
+#include "session.h"
+#include "session_config.h"
+#include "socket_addr.h"
+
+#include <library/cpp/messagebus/actor/executor.h>
+#include <library/cpp/messagebus/scheduler/scheduler.h>
+
+#include <library/cpp/codecs/codecs.h>
+
+#include <util/generic/array_ref.h>
+#include <util/generic/buffer.h>
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/stream/input.h>
+#include <util/system/atomic.h>
+#include <util/system/condvar.h>
+#include <util/system/type_name.h>
+#include <util/system/event.h>
+#include <util/system/mutex.h>
+
+namespace NBus {
+ ////////////////////////////////////////////////////////
+ /// \brief Common structure to store address information
+
+ int CompareByHost(const IRemoteAddr& l, const IRemoteAddr& r) noexcept;
+ bool operator<(const TNetAddr& a1, const TNetAddr& a2); // compare by addresses
+
+ /////////////////////////////////////////////////////////////////////////
+ /// \brief Handles routing and data encoding to/from wire
+
+ /// Protocol is stateless threadsafe singleton object that
+ /// encapsulates relationship between a message (TBusMessage) object
+ /// and destination server. Protocol object is reponsible for serializing in-memory
+ /// message and reply into the wire, retuning name of the service and resource
+ /// distribution key for given protocol.
+
+ /// Protocol object should transparently handle messages and replies.
+ /// This is interface only class, actuall instances of the protocols
+ /// should be created using templates inhereted from this base class.
+ class TBusProtocol {
+ private:
+ TString ServiceName;
+ int ServicePort;
+
+ public:
+ TBusProtocol(TBusService name = "UNKNOWN", int port = 0)
+ : ServiceName(name)
+ , ServicePort(port)
+ {
+ }
+
+ /// returns service type for this protocol and message
+ TBusService GetService() const {
+ return ServiceName.data();
+ }
+
+ /// returns port number for destination session to open socket
+ int GetPort() const {
+ return ServicePort;
+ }
+
+ virtual ~TBusProtocol() {
+ }
+
+ /// \brief serialized protocol specific data into TBusData
+ /// \note buffer passed to the function (data) is not empty, use append functions
+ virtual void Serialize(const TBusMessage* mess, TBuffer& data) = 0;
+
+ /// deserialized TBusData into new instance of the message
+ virtual TAutoPtr<TBusMessage> Deserialize(ui16 messageType, TArrayRef<const char> payload) = 0;
+
+ /// returns key for messages of this protocol
+ virtual TBusKey GetKey(const TBusMessage*) {
+ return YBUS_KEYMIN;
+ }
+
+ /// default implementation of routing policy to allow overrides
+ virtual EMessageStatus GetDestination(const TBusClientSession* session, TBusMessage* mess, TBusLocator* locator, TNetAddr* addr);
+
+ /// codec for transport level compression
+ virtual NCodecs::TCodecPtr GetTransportCodec(void) const {
+ return NCodecs::ICodec::GetInstance("snappy");
+ }
+ };
+
+ class TBusSyncSourceSession: public TAtomicRefCount<TBusSyncSourceSession> {
+ friend class TBusMessageQueue;
+
+ public:
+ TBusSyncSourceSession(TIntrusivePtr< ::NBus::NPrivate::TBusSyncSourceSessionImpl> session);
+ ~TBusSyncSourceSession();
+
+ void Shutdown();
+
+ TBusMessage* SendSyncMessage(TBusMessage* pMessage, EMessageStatus& status, const TNetAddr* addr = nullptr);
+
+ int RegisterService(const char* hostname, TBusKey start = YBUS_KEYMIN, TBusKey end = YBUS_KEYMAX, EIpVersion ipVersion = EIP_VERSION_4);
+
+ int GetInFlight();
+
+ const TBusProtocol* GetProto() const;
+
+ const TBusClientSession* GetBusClientSessionWorkaroundDoNotUse() const; // It's for TLoadBalancedProtocol::GetDestination() function that really needs TBusClientSession* unlike all other protocols. Look at review 32425 (http://rb.yandex-team.ru/arc/r/32425/) for more information.
+ private:
+ TIntrusivePtr< ::NBus::NPrivate::TBusSyncSourceSessionImpl> Session;
+ };
+
+ using TBusSyncClientSessionPtr = TIntrusivePtr<TBusSyncSourceSession>;
+
+ ///////////////////////////////////////////////////////////////////
+ /// \brief Main message queue object, need one per application
+ class TBusMessageQueue: public TAtomicRefCount<TBusMessageQueue> {
+ /// allow mesage queue to be created only via factory
+ friend TBusMessageQueuePtr CreateMessageQueue(const TBusQueueConfig& config, NActor::TExecutorPtr executor, TBusLocator* locator, const char* name);
+ friend class ::NBus::NPrivate::TRemoteConnection;
+ friend struct ::NBus::NPrivate::TBusSessionImpl;
+ friend class ::NBus::NPrivate::TAcceptor;
+ friend struct ::NBus::TBusServerSession;
+
+ private:
+ const TBusQueueConfig Config;
+ TMutex Lock;
+ TList<TIntrusivePtr< ::NBus::NPrivate::TBusSessionImpl>> Sessions;
+ TSimpleIntrusivePtr<TBusLocator> Locator;
+ NPrivate::TScheduler Scheduler;
+
+ ::NActor::TExecutorPtr WorkQueue;
+
+ TAtomic Running;
+ TSystemEvent ShutdownComplete;
+
+ private:
+ /// constructor is protected, used NBus::CreateMessageQueue() to create a instance
+ TBusMessageQueue(const TBusQueueConfig& config, NActor::TExecutorPtr executor, TBusLocator* locator, const char* name);
+
+ public:
+ TString GetNameInternal() const;
+
+ ~TBusMessageQueue();
+
+ void Stop();
+ bool IsRunning();
+
+ public:
+ void EnqueueWork(TArrayRef< ::NActor::IWorkItem* const> w) {
+ WorkQueue->EnqueueWork(w);
+ }
+
+ ::NActor::TExecutor* GetExecutor() {
+ return WorkQueue.Get();
+ }
+
+ TString GetStatus(ui16 flags = YBUS_STATUS_CONNS) const;
+ // without sessions
+ NPrivate::TBusMessageQueueStatus GetStatusRecordInternal() const;
+ TString GetStatusSelf() const;
+ TString GetStatusSingleLine() const;
+
+ TBusLocator* GetLocator() const {
+ return Locator.Get();
+ }
+
+ TBusClientSessionPtr CreateSource(TBusProtocol* proto, IBusClientHandler* handler, const TBusClientSessionConfig& config, const TString& name = "");
+ TBusSyncClientSessionPtr CreateSyncSource(TBusProtocol* proto, const TBusClientSessionConfig& config, bool needReply = true, const TString& name = "");
+ TBusServerSessionPtr CreateDestination(TBusProtocol* proto, IBusServerHandler* hander, const TBusServerSessionConfig& config, const TString& name = "");
+ TBusServerSessionPtr CreateDestination(TBusProtocol* proto, IBusServerHandler* hander, const TBusServerSessionConfig& config, const TVector<TBindResult>& bindTo, const TString& name = "");
+
+ private:
+ void Destroy(TBusSession* session);
+ void Destroy(TBusSyncClientSessionPtr session);
+
+ public:
+ void Schedule(NPrivate::IScheduleItemAutoPtr i);
+
+ private:
+ void DestroyAllSessions();
+ void Add(TIntrusivePtr< ::NBus::NPrivate::TBusSessionImpl> session);
+ void Remove(TBusSession* session);
+ };
+
+ /////////////////////////////////////////////////////////////////
+ /// Factory methods to construct message queue
+ TBusMessageQueuePtr CreateMessageQueue(const char* name = "");
+ TBusMessageQueuePtr CreateMessageQueue(NActor::TExecutorPtr executor, const char* name = "");
+ TBusMessageQueuePtr CreateMessageQueue(const TBusQueueConfig& config, const char* name = "");
+ TBusMessageQueuePtr CreateMessageQueue(const TBusQueueConfig& config, TBusLocator* locator, const char* name = "");
+ TBusMessageQueuePtr CreateMessageQueue(const TBusQueueConfig& config, NActor::TExecutorPtr executor, TBusLocator* locator, const char* name = "");
+
+}
diff --git a/library/cpp/mime/types/mime.cpp b/library/cpp/mime/types/mime.cpp
new file mode 100644
index 0000000000..706d776b24
--- /dev/null
+++ b/library/cpp/mime/types/mime.cpp
@@ -0,0 +1,253 @@
+#include "mime.h"
+
+#include <util/system/defaults.h>
+#include <util/generic/hash.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/singleton.h>
+#include <util/generic/yexception.h>
+
+#include <cctype>
+
+/*
+ * MIME types
+ */
+
+class TMimeTypes {
+ // Constructor
+public:
+ TMimeTypes();
+
+ // Methods
+public:
+ const char* StrByExt(const char* ext) const;
+
+ MimeTypes MimeByStr(const char* str) const;
+ MimeTypes MimeByStr(const TStringBuf& str) const;
+ const char* StrByMime(MimeTypes mime) const;
+
+ // Constants
+public:
+ static const size_t MAX_EXT_LEN = 11; // max length of supported extensions
+
+ // Helper methods
+private:
+ void SetContentTypes();
+ void SetExt();
+
+ // Types
+private:
+ struct TRecord {
+ MimeTypes Mime;
+ const char* ContentType;
+ const char* Ext;
+ };
+
+ typedef THashMap<const char*, int> TRecordHash;
+
+ // Fields
+private:
+ static const TRecord Records[];
+ TRecordHash ContentTypes;
+ TRecordHash Ext;
+};
+
+const TMimeTypes::TRecord TMimeTypes::Records[] = {
+ {MIME_UNKNOWN, nullptr, nullptr},
+ {MIME_TEXT, "text/plain\0", "asc\0txt\0"},
+ {MIME_HTML, "text/html\0", "html\0htm\0shtml\0"},
+ {MIME_PDF, "application/pdf\0", "pdf\0"},
+ {MIME_RTF, "text/rtf\0application/rtf\0", "rtf\0"},
+ {MIME_DOC, "application/msword\0", "doc\0"},
+ {MIME_MPEG, "audio/mpeg\0", "mp3\0mpa\0m2a\0mp2\0mpg\0mpga\0"},
+ {MIME_XML, "text/xml\0application/xml\0", "xml\0"},
+ {MIME_WML, "text/vnd.wap.wml\0", "wml\0"},
+ {MIME_SWF, "application/x-shockwave-flash\0", "swf\0"},
+ {MIME_XLS, "application/vnd.ms-excel\0", "xls\0"},
+ {MIME_PPT, "application/vnd.ms-powerpoint\0", "ppt\0"},
+ {MIME_IMAGE_JPG, "image/jpeg\0image/jpg\0", "jpeg\0jpg\0"},
+ {MIME_IMAGE_PJPG, "image/pjpeg\0", "pjpeg\0"},
+ {MIME_IMAGE_PNG, "image/png\0", "png\0"},
+ {MIME_IMAGE_GIF, "image/gif\0", "gif\0"},
+ {MIME_DOCX, "application/vnd.openxmlformats-officedocument.wordprocessingml.document\0", "docx\0"},
+ {MIME_ODT, "application/vnd.oasis.opendocument.text\0", "odt\0"},
+ {MIME_ODP, "application/vnd.oasis.opendocument.presentation\0", "odp\0"},
+ {MIME_ODS, "application/vnd.oasis.opendocument.spreadsheet\0", "ods\0"},
+ {MIME_UNKNOWN, nullptr, nullptr},
+ {MIME_IMAGE_BMP, "image/bmp\0image/x-ms-bmp\0image/x-windows-bmp\0", "bmp\0"},
+ {MIME_WAV, "audio/x-wav\0", "wav\0"},
+ {MIME_ARCHIVE, "application/x-archive\0", nullptr},
+ {MIME_EXE, "application/exe\0application/octet-stream\0application/x-dosexec\0application/x-msdownload\0", "exe\0"},
+ {MIME_ODG, "application/vnd.oasis.opendocument.graphics\0", "odg\0"},
+ {MIME_GZIP, "application/x-gzip\0", "gz\0gzip\0"},
+ {MIME_XLSX, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\0", "xlsx\0"},
+ {MIME_PPTX, "application/vnd.openxmlformats-officedocument.presentationml.presentation\0", "pptx\0"},
+ {MIME_JAVASCRIPT, "application/javascript\0text/javascript\0", "js\0"},
+ {MIME_EPUB, "application/epub+zip\0", "epub\0"},
+ {MIME_TEX, "application/x-tex\0application/x-latex\0text/x-tex\0", "tex\0"},
+ {MIME_JSON, "application/json\0", "json\0"},
+ {MIME_APK, "application/vnd.android.package-archive\0", "apk\0"},
+ {MIME_CSS, "text/css\0", "css\0"},
+ {MIME_IMAGE_WEBP, "image/webp\0", "webp\0"},
+ {MIME_DJVU, "image/vnd.djvu\0image/x-djvu\0", "djvu\0djv\0"},
+ {MIME_CHM, "application/x-chm\0application/vnd.ms-htmlhelp\0", "chm\0"},
+ {MIME_FB2ZIP, "application/zip\0", "fb2zip\0"},
+ {MIME_IMAGE_TIFF, "image/tiff\0image/tiff-fx\0", "tif\0tiff\0"},
+ {MIME_IMAGE_PNM, "image/x-portable-anymap\0", "pnm\0pgm\0ppm\0pbm\0"},
+ {MIME_IMAGE_SVG, "image/svg+xml\0", "svg\0"},
+ {MIME_IMAGE_ICON, "image/x-icon\0image/vnd.microsoft.icon\0", "ico\0"},
+ {MIME_WOFF, "font/woff\0", "woff\0"},
+ {MIME_WOFF2, "font/woff2\0", "woff2\0"},
+ {MIME_TTF, "font/ttf\0", "ttf\0"},
+ {MIME_WEBMANIFEST, "application/manifest+json\0", "webmanifest\0"},
+ {MIME_MAX, nullptr, nullptr},
+
+ // Additional records
+ {MIME_HTML, "application/xhtml+xml\0", "xhtml\0"},
+};
+
+TMimeTypes::TMimeTypes()
+ : ContentTypes()
+ , Ext()
+{
+ SetContentTypes();
+ SetExt();
+}
+
+void TMimeTypes::SetContentTypes() {
+ for (int i = 0; i < (int)Y_ARRAY_SIZE(Records); ++i) {
+ const TRecord& record(Records[i]);
+ assert(i == record.Mime || i > MIME_MAX || record.Mime == MIME_UNKNOWN);
+ if (!record.ContentType)
+ continue;
+ for (const char* type = record.ContentType; *type; type += strlen(type) + 1) {
+ assert(ContentTypes.find(type) == ContentTypes.end());
+ ContentTypes[type] = i;
+ }
+ }
+}
+
+void TMimeTypes::SetExt() {
+ for (int i = 0; i < (int)Y_ARRAY_SIZE(Records); ++i) {
+ const TRecord& record(Records[i]);
+ if (!record.Ext)
+ continue;
+ for (const char* ext = record.Ext; *ext; ext += strlen(ext) + 1) {
+ assert(strlen(ext) <= MAX_EXT_LEN);
+ assert(Ext.find(ext) == Ext.end());
+ Ext[ext] = i;
+ }
+ }
+}
+
+const char* TMimeTypes::StrByExt(const char* ext) const {
+ TRecordHash::const_iterator it = Ext.find(ext);
+ if (it == Ext.end())
+ return nullptr;
+ return Records[it->second].ContentType;
+}
+
+MimeTypes TMimeTypes::MimeByStr(const char* str) const {
+ TRecordHash::const_iterator it = ContentTypes.find(str);
+ if (it == ContentTypes.end())
+ return MIME_UNKNOWN;
+ return Records[it->second].Mime;
+}
+
+MimeTypes TMimeTypes::MimeByStr(const TStringBuf& str) const {
+ TRecordHash::const_iterator it = ContentTypes.find(str);
+ if (it == ContentTypes.end())
+ return MIME_UNKNOWN;
+ return Records[it->second].Mime;
+}
+
+const char* TMimeTypes::StrByMime(MimeTypes mime) const {
+ return Records[mime].ContentType;
+}
+
+const char* mimetypeByExt(const char* fname, const char* check_ext) {
+ const char* ext_p;
+ if (fname == nullptr || *fname == 0 ||
+ (ext_p = strrchr(fname, '.')) == nullptr || strlen(ext_p) - 1 > TMimeTypes::MAX_EXT_LEN) {
+ return nullptr;
+ }
+
+ char ext[TMimeTypes::MAX_EXT_LEN + 1];
+ size_t i;
+ ext_p++;
+ for (i = 0; i < TMimeTypes::MAX_EXT_LEN && ext_p[i]; i++)
+ ext[i] = (char)tolower(ext_p[i]);
+ ext[i] = 0;
+
+ if (check_ext != nullptr) {
+ if (strcmp(ext, check_ext) == 0)
+ return check_ext;
+ else
+ return nullptr;
+ }
+
+ return Singleton<TMimeTypes>()->StrByExt(ext);
+}
+
+MimeTypes mimeByStr(const char* mimeStr) {
+ return Singleton<TMimeTypes>()->MimeByStr(mimeStr);
+}
+
+MimeTypes mimeByStr(const TStringBuf& mimeStr) {
+ return Singleton<TMimeTypes>()->MimeByStr(mimeStr);
+}
+
+const char* strByMime(MimeTypes mime) {
+ if (mime < 0 || mime > MIME_MAX)
+ return nullptr; // index may contain documents with invalid MIME (ex. 255)
+ return Singleton<TMimeTypes>()->StrByMime(mime);
+}
+
+const char* MimeNames[MIME_MAX] = {
+ "unknown", // MIME_UNKNOWN // 0
+ "text", // MIME_TEXT // 1
+ "html", // MIME_HTML // 2
+ "pdf", // MIME_PDF // 3
+ "rtf", // MIME_RTF // 4
+ "doc", // MIME_DOC // 5
+ "mpeg", // MIME_MPEG // 6
+ "xml", // MIME_XML // 7
+ "wap", // MIME_WML // 8
+ "swf", // MIME_SWF // 9
+ "xls", // MIME_XLS // 10
+ "ppt", // MIME_PPT // 11
+ "jpg", // MIME_IMAGE_JPG // 12
+ "pjpg", // MIME_IMAGE_PJPG // 13
+ "png", // MIME_IMAGE_PNG // 14
+ "gif", // MIME_IMAGE_GIF // 15
+ "docx", // MIME_DOCX // 16
+ "odt", // MIME_ODT // 17
+ "odp", // MIME_ODP // 18
+ "ods", // MIME_ODS // 19
+ "xmlhtml", // MIME_XHTMLXML // 20
+ "bmp", // MIME_IMAGE_BMP // 21
+ "wav", // MIME_WAV // 22
+ "archive", // MIME_ARCHIVE // 23
+ "exe", // MIME_EXE // 24
+ "odg", // MIME_ODG // 25
+ "gzip", // MIME_GZIP // 26
+ "xlsx", // MIME_XLSX // 27
+ "pptx", // MIME_PPTX // 28
+ "js", // MIME_JAVASCRIPT // 29
+ "epub", // MIME_EPUB // 30
+ "tex", // MIME_TEX // 31
+ "json", // MIME_JSON // 32
+ "apk", // MIME_APK // 33
+ "css", // MIME_CSS // 34
+ "webp", // MIME_IMAGE_WEBP // 35
+ "djvu", // MIME_DJVU // 36
+ "chm", // MIME_CHM // 37
+ "fb2zip", // MIME_FB2ZIP // 38
+ "tiff", // MIME_IMAGE_TIFF // 39
+ "pnm", // MIME_IMAGE_PNM // 40
+ "svg", // MIME_IMAGE_SVG // 41
+ "ico", // MIME_IMAGE_ICON // 42
+ "woff", // MIME_WOFF // 43
+ "woff2", // MIME_WOFF2 // 44
+ "ttf", // MIME_TTF // 45
+ "webmanifest" // MIME_WEBMANIFEST // 46
+};
diff --git a/library/cpp/mime/types/mime.h b/library/cpp/mime/types/mime.h
new file mode 100644
index 0000000000..05da389ea9
--- /dev/null
+++ b/library/cpp/mime/types/mime.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include <util/system/defaults.h>
+#include <util/generic/strbuf.h>
+
+#include <cstring>
+
+enum MimeTypes {
+ MIME_UNKNOWN = 0,
+ MIME_TEXT = 1,
+ MIME_HTML = 2,
+ MIME_XHTMLXML = MIME_HTML,
+ MIME_PDF = 3,
+ MIME_RTF = 4,
+ MIME_DOC = 5,
+ MIME_MSWORD = MIME_DOC,
+ MIME_MPEG = 6,
+ MIME_XML = 7,
+ MIME_RSS = MIME_XML,
+ MIME_WML = 8,
+ MIME_SWF = 9,
+ MIME_FLASH = MIME_SWF,
+ MIME_XLS = 10,
+ MIME_EXCEL = MIME_XLS,
+ MIME_PPT = 11,
+ MIME_IMAGE_JPG = 12,
+ MIME_IMAGE_PJPG = 13,
+ MIME_IMAGE_PNG = 14,
+ MIME_IMAGE_GIF = 15,
+ MIME_DOCX = 16,
+ MIME_ODT = 17,
+ MIME_ODP = 18,
+ MIME_ODS = 19,
+ //MIME_XHTMLXML = 20,
+ MIME_IMAGE_BMP = 21,
+ MIME_WAV = 22,
+ MIME_ARCHIVE = 23,
+ MIME_EXE = 24,
+ MIME_ODG = 25,
+ MIME_GZIP = 26,
+ MIME_XLSX = 27,
+ MIME_PPTX = 28,
+ MIME_JAVASCRIPT = 29,
+ MIME_EPUB = 30,
+ MIME_TEX = 31,
+ MIME_JSON = 32,
+ MIME_APK = 33,
+ MIME_CSS = 34,
+ MIME_IMAGE_WEBP = 35,
+ MIME_DJVU = 36,
+ MIME_CHM = 37,
+ MIME_FB2ZIP = 38,
+ MIME_IMAGE_TIFF = 39,
+ MIME_IMAGE_PNM = 40,
+ MIME_IMAGE_SVG = 41,
+ MIME_IMAGE_ICON = 42,
+ MIME_WOFF = 43,
+ MIME_WOFF2 = 44,
+ MIME_TTF = 45,
+ MIME_WEBMANIFEST = 46,
+ MIME_MAX
+};
+
+extern const char* MimeNames[MIME_MAX];
+
+const char* mimetypeByExt(const char* fname, const char* check_ext = nullptr);
+MimeTypes mimeByStr(const char* mimeStr);
+MimeTypes mimeByStr(const TStringBuf& mimeStr);
+const char* strByMime(MimeTypes mime);
+
+// autogenerated with GENERATE_ENUM_SERIALIZATION
+const TString& ToString(MimeTypes x);
diff --git a/library/cpp/mime/types/ya.make b/library/cpp/mime/types/ya.make
new file mode 100644
index 0000000000..a7f58aab3e
--- /dev/null
+++ b/library/cpp/mime/types/ya.make
@@ -0,0 +1,11 @@
+LIBRARY()
+
+OWNER(stanly)
+
+SRCS(
+ mime.cpp
+)
+
+GENERATE_ENUM_SERIALIZATION(mime.h)
+
+END()
diff --git a/library/cpp/mime/ya.make b/library/cpp/mime/ya.make
new file mode 100644
index 0000000000..8ce42f207d
--- /dev/null
+++ b/library/cpp/mime/ya.make
@@ -0,0 +1,5 @@
+RECURSE(
+ detect
+ detect_ut
+ types
+)
diff --git a/library/cpp/monlib/counters/counters.cpp b/library/cpp/monlib/counters/counters.cpp
new file mode 100644
index 0000000000..50dca4c577
--- /dev/null
+++ b/library/cpp/monlib/counters/counters.cpp
@@ -0,0 +1,49 @@
+
+#include "counters.h"
+
+namespace NMonitoring {
+ char* PrettyNumShort(i64 val, char* buf, size_t size) {
+ static const char shorts[] = {' ', 'K', 'M', 'G', 'T', 'P', 'E'};
+ unsigned i = 0;
+ i64 major = val;
+ i64 minor = 0;
+ const unsigned imax = sizeof(shorts) / sizeof(char);
+ for (i = 0; i < imax; i++) {
+ if (major >> 10 == 0)
+ break;
+ else {
+ minor = major - (major >> 10 << 10);
+ major = major >> 10;
+ }
+ }
+ minor = (minor * 10) >> 10;
+
+ if (i == 0 || i >= imax)
+ *buf = '\0';
+ else
+ snprintf(buf, size, "%" PRId64 ".%" PRId64 "%c", major, minor, shorts[i]);
+
+ return buf;
+ }
+
+ char* PrettyNum(i64 val, char* buf, size_t size) {
+ Y_ASSERT(buf);
+ if (size < 4) {
+ buf[0] = 0;
+ return buf;
+ }
+ PrettyNumShort(val, buf + 2, size - 3);
+ if (buf[2] == 0) {
+ *buf = '\0';
+ } else {
+ size_t len = 2 + strnlen(buf + 2, size - 4);
+ Y_ASSERT(len < size);
+ buf[0] = ' ';
+ buf[1] = '(';
+ buf[len] = ')';
+ buf[len + 1] = '\0';
+ }
+
+ return buf;
+ }
+}
diff --git a/library/cpp/monlib/counters/counters.h b/library/cpp/monlib/counters/counters.h
new file mode 100644
index 0000000000..038b55f0c8
--- /dev/null
+++ b/library/cpp/monlib/counters/counters.h
@@ -0,0 +1,350 @@
+#pragma once
+
+#include <util/datetime/base.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/list.h>
+#include <util/generic/map.h>
+#include <util/generic/ptr.h>
+#include <util/generic/singleton.h>
+#include <util/generic/vector.h>
+#include <util/str_stl.h>
+#include <util/stream/output.h>
+#include <util/string/util.h>
+#include <util/system/atomic.h>
+#include <util/system/defaults.h>
+#include <util/system/guard.h>
+#include <util/system/sem.h>
+#include <util/system/spinlock.h>
+
+#include <array>
+
+namespace NMonitoring {
+#define BEGIN_OUTPUT_COUNTERS \
+ void OutputImpl(IOutputStream& out) { \
+ char prettyBuf[32];
+#define END_OUTPUT_COUNTERS \
+ out.Flush(); \
+ }
+
+#define OUTPUT_NAMED_COUNTER(var, name) out << name << ": \t" << var << NMonitoring::PrettyNum(var, prettyBuf, 32) << '\n'
+#define OUTPUT_COUNTER(var) OUTPUT_NAMED_COUNTER(var, #var);
+
+ char* PrettyNumShort(i64 val, char* buf, size_t size);
+ char* PrettyNum(i64 val, char* buf, size_t size);
+
+ // This class is deprecated. Please consider to use
+ // library/cpp/monlib/metrics instead. See more info at
+ // https://wiki.yandex-team.ru/solomon/libs/monlib_cpp/
+ class TDeprecatedCounter {
+ public:
+ using TValue = TAtomic;
+ using TValueBase = TAtomicBase;
+
+ TDeprecatedCounter()
+ : Value()
+ , Derivative(false)
+ {
+ }
+
+ TDeprecatedCounter(TValue value, bool derivative = false)
+ : Value(value)
+ , Derivative(derivative)
+ {
+ }
+
+ bool ForDerivative() const {
+ return Derivative;
+ }
+
+ operator TValueBase() const {
+ return AtomicGet(Value);
+ }
+ TValueBase Val() const {
+ return AtomicGet(Value);
+ }
+
+ void Set(TValue val) {
+ AtomicSet(Value, val);
+ }
+
+ TValueBase Inc() {
+ return AtomicIncrement(Value);
+ }
+ TValueBase Dec() {
+ return AtomicDecrement(Value);
+ }
+
+ TValueBase Add(const TValue val) {
+ return AtomicAdd(Value, val);
+ }
+ TValueBase Sub(const TValue val) {
+ return AtomicAdd(Value, -val);
+ }
+
+ // operator overloads convinient
+ void operator++() {
+ Inc();
+ }
+ void operator++(int) {
+ Inc();
+ }
+
+ void operator--() {
+ Dec();
+ }
+ void operator--(int) {
+ Dec();
+ }
+
+ void operator+=(TValue rhs) {
+ Add(rhs);
+ }
+ void operator-=(TValue rhs) {
+ Sub(rhs);
+ }
+
+ TValueBase operator=(TValue rhs) {
+ AtomicSwap(&Value, rhs);
+ return rhs;
+ }
+
+ bool operator!() const {
+ return AtomicGet(Value) == 0;
+ }
+
+ TAtomic& GetAtomic() {
+ return Value;
+ }
+
+ private:
+ TAtomic Value;
+ bool Derivative;
+ };
+
+ template <typename T>
+ struct TDeprecatedCountersBase {
+ virtual ~TDeprecatedCountersBase() {
+ }
+
+ virtual void OutputImpl(IOutputStream&) = 0;
+
+ static T& Instance() {
+ return *Singleton<T>();
+ }
+
+ static void Output(IOutputStream& out) {
+ Instance().OutputImpl(out);
+ }
+ };
+
+ // This class is deprecated. Please consider to use
+ // library/cpp/monlib/metrics instead. See more info at
+ // https://wiki.yandex-team.ru/solomon/libs/monlib_cpp/
+ //
+ // Groups of G counters, defined by T type.
+ // Less(a,b) returns true, if a < b.
+ // It's threadsafe.
+ template <typename T, typename G, typename TL = TLess<T>>
+ class TDeprecatedCounterGroups {
+ public:
+ typedef TMap<T, G*> TGroups;
+ typedef TVector<T> TGroupsNames;
+ typedef THolder<TGroupsNames> TGroupsNamesPtr;
+
+ private:
+ class TCollection {
+ struct TElement {
+ T* Name;
+ G* Counters;
+
+ public:
+ static bool Compare(const TElement& a, const TElement& b) {
+ return Less(*(a.Name), *(b.Name));
+ }
+ }; // TElement
+ private:
+ TArrayHolder<TElement> Elements;
+ size_t Size;
+
+ public:
+ TCollection()
+ : Size(0)
+ {
+ }
+
+ TCollection(const TCollection& collection)
+ : Elements(new TElement[collection.Size])
+ , Size(collection.Size)
+ {
+ for (int i = 0; i < Size; ++i) {
+ Elements[i] = collection.Elements[i];
+ }
+ }
+
+ TCollection(const TCollection& collection, T* name, G* counters)
+ : Elements(new TElement[collection.Size + 1])
+ , Size(collection.Size + 1)
+ {
+ for (size_t i = 0; i < Size - 1; ++i) {
+ Elements[i] = collection.Elements[i];
+ }
+ Elements[Size - 1].Name = name;
+ Elements[Size - 1].Counters = counters;
+ for (size_t i = 1; i < Size; ++i) {
+ size_t j = i;
+ while (j > 0 &&
+ TElement::Compare(Elements[j], Elements[j - 1])) {
+ std::swap(Elements[j], Elements[j - 1]);
+ --j;
+ }
+ }
+ }
+
+ G* Find(const T& name) const {
+ G* result = nullptr;
+ if (Size == 0) {
+ return nullptr;
+ }
+ size_t l = 0;
+ size_t r = Size - 1;
+ while (l < r) {
+ size_t m = (l + r) / 2;
+ if (Less(*(Elements[m].Name), name)) {
+ l = m + 1;
+ } else {
+ r = m;
+ }
+ }
+ if (!Less(*(Elements[l].Name), name) && !Less(name, *(Elements[l].Name))) {
+ result = Elements[l].Counters;
+ }
+ return result;
+ }
+
+ void Free() {
+ for (size_t i = 0; i < Size; ++i) {
+ T* name = Elements[i].Name;
+ G* counters = Elements[i].Counters;
+ Elements[i].Name = nullptr;
+ Elements[i].Counters = nullptr;
+ delete name;
+ delete counters;
+ }
+ Size = 0;
+ }
+
+ TGroupsNamesPtr GetNames() const {
+ TGroupsNamesPtr result(new TGroupsNames());
+ for (size_t i = 0; i < Size; ++i) {
+ result->push_back(*(Elements[i].Name));
+ }
+ return result;
+ }
+ }; // TCollection
+ struct TOldGroup {
+ TCollection* Collection;
+ ui64 Time;
+ };
+
+ private:
+ TCollection* Groups;
+ TList<TOldGroup> OldGroups;
+ TSpinLock AddMutex;
+
+ ui64 Timeout;
+
+ static TL Less;
+
+ private:
+ G* Add(const T& name) {
+ TGuard<TSpinLock> guard(AddMutex);
+ G* result = Groups->Find(name);
+ if (result == nullptr) {
+ T* newName = new T(name);
+ G* newCounters = new G();
+ TCollection* newGroups =
+ new TCollection(*Groups, newName, newCounters);
+ ui64 now = ::Now().MicroSeconds();
+ TOldGroup group;
+ group.Collection = Groups;
+ group.Time = now;
+ OldGroups.push_back(group);
+ for (ui32 i = 0; i < 5; ++i) {
+ if (OldGroups.front().Time + Timeout < now) {
+ delete OldGroups.front().Collection;
+ OldGroups.front().Collection = nullptr;
+ OldGroups.pop_front();
+ } else {
+ break;
+ }
+ }
+ Groups = newGroups;
+ result = Groups->Find(name);
+ }
+ return result;
+ }
+
+ public:
+ TDeprecatedCounterGroups(ui64 timeout = 5 * 1000000L) {
+ Groups = new TCollection();
+ Timeout = timeout;
+ }
+
+ virtual ~TDeprecatedCounterGroups() {
+ TGuard<TSpinLock> guard(AddMutex);
+ Groups->Free();
+ delete Groups;
+ Groups = nullptr;
+ typename TList<TOldGroup>::iterator i;
+ for (i = OldGroups.begin(); i != OldGroups.end(); ++i) {
+ delete i->Collection;
+ i->Collection = nullptr;
+ }
+ OldGroups.clear();
+ }
+
+ bool Has(const T& name) const {
+ TCollection* groups = Groups;
+ return groups->Find(name) != nullptr;
+ }
+
+ G* Find(const T& name) const {
+ TCollection* groups = Groups;
+ return groups->Find(name);
+ }
+
+ // Get group with the name, if it exists.
+ // If there is no group with the name, add new group.
+ G& Get(const T& name) {
+ G* result = Find(name);
+ if (result == nullptr) {
+ result = Add(name);
+ Y_ASSERT(result != nullptr);
+ }
+ return *result;
+ }
+
+ // Get copy of groups names array.
+ TGroupsNamesPtr GetGroupsNames() const {
+ TCollection* groups = Groups;
+ TGroupsNamesPtr result = groups->GetNames();
+ return result;
+ }
+ }; // TDeprecatedCounterGroups
+
+ template <typename T, typename G, typename TL>
+ TL TDeprecatedCounterGroups<T, G, TL>::Less;
+}
+
+static inline IOutputStream& operator<<(IOutputStream& o, const NMonitoring::TDeprecatedCounter& rhs) {
+ return o << rhs.Val();
+}
+
+template <size_t N>
+static inline IOutputStream& operator<<(IOutputStream& o, const std::array<NMonitoring::TDeprecatedCounter, N>& rhs) {
+ for (typename std::array<NMonitoring::TDeprecatedCounter, N>::const_iterator it = rhs.begin(); it != rhs.end(); ++it) {
+ if (!!*it)
+ o << *it << Endl;
+ }
+ return o;
+}
diff --git a/library/cpp/monlib/counters/counters_ut.cpp b/library/cpp/monlib/counters/counters_ut.cpp
new file mode 100644
index 0000000000..2845efb97b
--- /dev/null
+++ b/library/cpp/monlib/counters/counters_ut.cpp
@@ -0,0 +1,49 @@
+#include "counters.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/set.h>
+#include <util/thread/pool.h>
+
+using namespace NMonitoring;
+
+Y_UNIT_TEST_SUITE(TDeprecatedCountersTest) {
+ Y_UNIT_TEST(CounterGroupsAreThreadSafe) {
+ const static ui32 GROUPS_COUNT = 1000;
+ const static ui32 THREADS_COUNT = 10;
+
+ TDeprecatedCounterGroups<ui32, ui32> groups;
+
+ auto adder = [&groups]() {
+ for (ui32 id = 0; id < GROUPS_COUNT; id++) {
+ groups.Get(id);
+
+ // adds contention
+ ::NanoSleep(42);
+ }
+ };
+
+ TThreadPool q;
+ q.Start(THREADS_COUNT);
+ for (ui32 i = 0; i < THREADS_COUNT; i++) {
+ q.SafeAddFunc(adder);
+ }
+ q.Stop();
+
+ // each group id is present
+ for (ui32 id = 0; id < GROUPS_COUNT; id++) {
+ UNIT_ASSERT(groups.Has(id));
+ }
+
+ // group names contains only appropriate ids
+ auto ids = groups.GetGroupsNames();
+ for (ui32 id : *ids) {
+ UNIT_ASSERT(id < GROUPS_COUNT);
+ }
+
+ // no duplication in group names
+ TSet<ui32> uniqueIds(ids->begin(), ids->end());
+ UNIT_ASSERT_EQUAL(ids->size(), uniqueIds.size());
+ UNIT_ASSERT_EQUAL(ids->size(), GROUPS_COUNT);
+ }
+}
diff --git a/library/cpp/monlib/counters/histogram.cpp b/library/cpp/monlib/counters/histogram.cpp
new file mode 100644
index 0000000000..46cf4e6ec8
--- /dev/null
+++ b/library/cpp/monlib/counters/histogram.cpp
@@ -0,0 +1,40 @@
+#include "histogram.h"
+
+namespace NMonitoring {
+ void THistogramSnapshot::Print(IOutputStream* out) const {
+ (*out) << "mean: " << Mean
+ << ", stddev: " << StdDeviation
+ << ", min: " << Min
+ << ", max: " << Max
+ << ", 50%: " << Percentile50
+ << ", 75%: " << Percentile75
+ << ", 90%: " << Percentile90
+ << ", 95%: " << Percentile95
+ << ", 98%: " << Percentile98
+ << ", 99%: " << Percentile99
+ << ", 99.9%: " << Percentile999
+ << ", count: " << TotalCount;
+ }
+
+ void THdrHistogram::TakeSnaphot(THistogramSnapshot* snapshot) {
+ with_lock (Lock_) {
+ // TODO: get data with single traverse
+ snapshot->Mean = Data_.GetMean();
+ snapshot->StdDeviation = Data_.GetStdDeviation();
+ snapshot->Min = Data_.GetMin();
+ snapshot->Max = Data_.GetMax();
+ snapshot->Percentile50 = Data_.GetValueAtPercentile(50.0);
+ snapshot->Percentile75 = Data_.GetValueAtPercentile(75.0);
+ snapshot->Percentile90 = Data_.GetValueAtPercentile(90.0);
+ snapshot->Percentile95 = Data_.GetValueAtPercentile(95.0);
+ snapshot->Percentile98 = Data_.GetValueAtPercentile(98.0);
+ snapshot->Percentile99 = Data_.GetValueAtPercentile(99.0);
+ snapshot->Percentile999 = Data_.GetValueAtPercentile(99.9);
+ snapshot->TotalCount = Data_.GetTotalCount();
+
+ // cleanup histogram data
+ Data_.Reset();
+ }
+ }
+
+}
diff --git a/library/cpp/monlib/counters/histogram.h b/library/cpp/monlib/counters/histogram.h
new file mode 100644
index 0000000000..96361b0023
--- /dev/null
+++ b/library/cpp/monlib/counters/histogram.h
@@ -0,0 +1,189 @@
+#pragma once
+
+#include <library/cpp/histogram/hdr/histogram.h>
+
+#include <util/system/spinlock.h>
+#include <util/stream/output.h>
+
+namespace NMonitoring {
+ /**
+ * A statistical snapshot of values recorded in histogram.
+ */
+ struct THistogramSnapshot {
+ double Mean;
+ double StdDeviation;
+ i64 Min;
+ i64 Max;
+ i64 Percentile50;
+ i64 Percentile75;
+ i64 Percentile90;
+ i64 Percentile95;
+ i64 Percentile98;
+ i64 Percentile99;
+ i64 Percentile999;
+ i64 TotalCount;
+
+ void Print(IOutputStream* out) const;
+ };
+
+ /**
+ * Special counter which calculates the distribution of a value.
+ */
+ class THdrHistogram {
+ public:
+ /**
+ * Construct a histogram given the Lowest and Highest values to be tracked
+ * and a number of significant decimal digits. Providing a
+ * lowestDiscernibleValue is useful in situations where the units used for
+ * the histogram's values are much smaller that the minimal accuracy
+ * required. E.g. when tracking time values stated in nanosecond units,
+ * where the minimal accuracy required is a microsecond, the proper value
+ * for lowestDiscernibleValue would be 1000.
+ *
+ * @param lowestDiscernibleValue The lowest value that can be discerned
+ * (distinguished from 0) by the histogram. Must be a positive
+ * integer that is >= 1. May be internally rounded down to nearest
+ * power of 2.
+ *
+ * @param highestTrackableValue The highest value to be tracked by the
+ * histogram. Must be a positive integer that is
+ * >= (2 * lowestDiscernibleValue).
+ *
+ * @param numberOfSignificantValueDigits Specifies the precision to use.
+ * This is the number of significant decimal digits to which the
+ * histogram will maintain value resolution and separation. Must be
+ * a non-negative integer between 0 and 5.
+ */
+ THdrHistogram(i64 lowestDiscernibleValue, i64 highestTrackableValue,
+ i32 numberOfSignificantValueDigits)
+ : Data_(lowestDiscernibleValue, highestTrackableValue,
+ numberOfSignificantValueDigits) {
+ }
+
+ /**
+ * Records a value in the histogram, will round this value of to a
+ * precision at or better than the NumberOfSignificantValueDigits specified
+ * at construction time.
+ *
+ * @param value Value to add to the histogram
+ * @return false if the value is larger than the HighestTrackableValue
+ * and can't be recorded, true otherwise.
+ */
+ bool RecordValue(i64 value) {
+ with_lock (Lock_) {
+ return Data_.RecordValue(value);
+ }
+ }
+
+ /**
+ * Records count values in the histogram, will round this value of to a
+ * precision at or better than the NumberOfSignificantValueDigits specified
+ * at construction time.
+ *
+ * @param value Value to add to the histogram
+ * @param count Number of values to add to the histogram
+ * @return false if the value is larger than the HighestTrackableValue
+ * and can't be recorded, true otherwise.
+ */
+ bool RecordValues(i64 value, i64 count) {
+ with_lock (Lock_) {
+ return Data_.RecordValues(value, count);
+ }
+ }
+
+ /**
+ * Records a value in the histogram and backfill based on an expected
+ * interval. Value will be rounded this to a precision at or better
+ * than the NumberOfSignificantValueDigits specified at contruction time.
+ * This is specifically used for recording latency. If the value is larger
+ * than the expectedInterval then the latency recording system has
+ * experienced co-ordinated omission. This method fills in the values that
+ * would have occured had the client providing the load not been blocked.
+ *
+ * @param value Value to add to the histogram
+ * @param expectedInterval The delay between recording values
+ * @return false if the value is larger than the HighestTrackableValue
+ * and can't be recorded, true otherwise.
+ */
+ bool RecordValueWithExpectedInterval(i64 value, i64 expectedInterval) {
+ with_lock (Lock_) {
+ return Data_.RecordValueWithExpectedInterval(value, expectedInterval);
+ }
+ }
+
+ /**
+ * Record a value in the histogram count times. Applies the same correcting
+ * logic as {@link THdrHistogram::RecordValueWithExpectedInterval}.
+ *
+ * @param value Value to add to the histogram
+ * @param count Number of values to add to the histogram
+ * @param expectedInterval The delay between recording values.
+ * @return false if the value is larger than the HighestTrackableValue
+ * and can't be recorded, true otherwise.
+ */
+ bool RecordValuesWithExpectedInterval(
+ i64 value, i64 count, i64 expectedInterval) {
+ with_lock (Lock_) {
+ return Data_.RecordValuesWithExpectedInterval(
+ value, count, expectedInterval);
+ }
+ }
+
+ /**
+ * @return The configured lowestDiscernibleValue
+ */
+ i64 GetLowestDiscernibleValue() const {
+ with_lock (Lock_) {
+ return Data_.GetLowestDiscernibleValue();
+ }
+ }
+
+ /**
+ * @return The configured highestTrackableValue
+ */
+ i64 GetHighestTrackableValue() const {
+ with_lock (Lock_) {
+ return Data_.GetHighestTrackableValue();
+ }
+ }
+
+ /**
+ * @return The configured numberOfSignificantValueDigits
+ */
+ i32 GetNumberOfSignificantValueDigits() const {
+ with_lock (Lock_) {
+ return Data_.GetNumberOfSignificantValueDigits();
+ }
+ }
+
+ /**
+ * @return The total count of all recorded values in the histogram
+ */
+ i64 GetTotalCount() const {
+ with_lock (Lock_) {
+ return Data_.GetTotalCount();
+ }
+ }
+
+ /**
+ * Place a copy of the value counts accumulated since the last snapshot
+ * was taken into {@code snapshot}. Calling this member-function will
+ * reset the value counts, and start accumulating value counts for the
+ * next interval.
+ *
+ * @param snapshot the structure into which the values should be copied.
+ */
+ void TakeSnaphot(THistogramSnapshot* snapshot);
+
+ private:
+ mutable TSpinLock Lock_;
+ NHdr::THistogram Data_;
+ };
+
+}
+
+template <>
+inline void Out<NMonitoring::THistogramSnapshot>(
+ IOutputStream& out, const NMonitoring::THistogramSnapshot& snapshot) {
+ snapshot.Print(&out);
+}
diff --git a/library/cpp/monlib/counters/histogram_ut.cpp b/library/cpp/monlib/counters/histogram_ut.cpp
new file mode 100644
index 0000000000..5a0800505a
--- /dev/null
+++ b/library/cpp/monlib/counters/histogram_ut.cpp
@@ -0,0 +1,47 @@
+#include "histogram.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NMonitoring;
+
+Y_UNIT_TEST_SUITE(THistorgamTest) {
+ Y_UNIT_TEST(TakeSnapshot) {
+ THdrHistogram h(1, 10, 3);
+ UNIT_ASSERT(h.RecordValue(1));
+ UNIT_ASSERT(h.RecordValue(2));
+ UNIT_ASSERT(h.RecordValues(3, 10));
+ UNIT_ASSERT(h.RecordValue(4));
+ UNIT_ASSERT(h.RecordValue(5));
+
+ UNIT_ASSERT_EQUAL(h.GetTotalCount(), 14);
+
+ THistogramSnapshot snapshot;
+ h.TakeSnaphot(&snapshot);
+
+ UNIT_ASSERT_EQUAL(h.GetTotalCount(), 0);
+
+ UNIT_ASSERT_EQUAL(snapshot.Min, 1);
+ UNIT_ASSERT_EQUAL(snapshot.Max, 5);
+
+ // >>> a = [1, 2] + [3 for i in range(10)] + [4, 5]
+ // >>> numpy.mean(a)
+ // 3.0
+ UNIT_ASSERT_DOUBLES_EQUAL(snapshot.Mean, 3.0, 1e-6);
+
+ // >>> numpy.std(a)
+ // 0.84515425472851657
+ UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.84515425472851657, 1e-6);
+
+ // >>> [(p, round(numpy.percentile(a, p))) for p in [50, 75, 90, 95, 98, 99, 99.9, 100]]
+ // [(50, 3.0), (75, 3.0), (90, 4.0), (95, 4.0), (98, 5.0), (99, 5.0), (99.9, 5.0), (100, 5.0)]
+ UNIT_ASSERT_EQUAL(snapshot.Percentile50, 3);
+ UNIT_ASSERT_EQUAL(snapshot.Percentile75, 3);
+ UNIT_ASSERT_EQUAL(snapshot.Percentile90, 4);
+ UNIT_ASSERT_EQUAL(snapshot.Percentile95, 4);
+ UNIT_ASSERT_EQUAL(snapshot.Percentile98, 5);
+ UNIT_ASSERT_EQUAL(snapshot.Percentile99, 5);
+ UNIT_ASSERT_EQUAL(snapshot.Percentile999, 5);
+
+ UNIT_ASSERT_EQUAL(snapshot.TotalCount, 14);
+ }
+}
diff --git a/library/cpp/monlib/counters/meter.cpp b/library/cpp/monlib/counters/meter.cpp
new file mode 100644
index 0000000000..6f15f173d1
--- /dev/null
+++ b/library/cpp/monlib/counters/meter.cpp
@@ -0,0 +1,4 @@
+#include "meter.h"
+
+namespace NMonitoring {
+}
diff --git a/library/cpp/monlib/counters/meter.h b/library/cpp/monlib/counters/meter.h
new file mode 100644
index 0000000000..1219f95c4d
--- /dev/null
+++ b/library/cpp/monlib/counters/meter.h
@@ -0,0 +1,285 @@
+#pragma once
+
+#include <util/system/types.h>
+#include <util/generic/noncopyable.h>
+#include <util/system/atomic.h>
+
+#include <chrono>
+#include <cstdlib>
+#include <cmath>
+
+namespace NMonitoring {
+ /**
+ * An exponentially-weighted moving average.
+ *
+ * @see <a href="http://www.teamquest.com/pdfs/whitepaper/ldavg1.pdf">
+ * UNIX Load Average Part 1: How It Works</a>
+ * @see <a href="http://www.teamquest.com/pdfs/whitepaper/ldavg2.pdf">
+ * UNIX Load Average Part 2: Not Your Average Average</a>
+ * @see <a href="http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average">EMA</a>
+ */
+ class TMovingAverage {
+ public:
+ enum {
+ INTERVAL = 5 // in seconds
+ };
+
+ public:
+ /**
+ * Creates a new EWMA which is equivalent to the UNIX one minute load
+ * average and which expects to be ticked every 5 seconds.
+ *
+ * @return a one-minute EWMA
+ */
+ static TMovingAverage OneMinute() {
+ static const double M1_ALPHA = 1 - std::exp(-INTERVAL / 60.0 / 1);
+ return {M1_ALPHA, std::chrono::seconds(INTERVAL)};
+ }
+
+ /**
+ * Creates a new EWMA which is equivalent to the UNIX five minute load
+ * average and which expects to be ticked every 5 seconds.
+ *
+ * @return a five-minute EWMA
+ */
+ static TMovingAverage FiveMinutes() {
+ static const double M5_ALPHA = 1 - std::exp(-INTERVAL / 60.0 / 5);
+ return {M5_ALPHA, std::chrono::seconds(INTERVAL)};
+ }
+
+ /**
+ * Creates a new EWMA which is equivalent to the UNIX fifteen minute load
+ * average and which expects to be ticked every 5 seconds.
+ *
+ * @return a fifteen-minute EWMA
+ */
+ static TMovingAverage FifteenMinutes() {
+ static const double M15_ALPHA = 1 - std::exp(-INTERVAL / 60.0 / 15);
+ return {M15_ALPHA, std::chrono::seconds(INTERVAL)};
+ }
+
+ /**
+ * Create a new EWMA with a specific smoothing constant.
+ *
+ * @param alpha the smoothing constant
+ * @param interval the expected tick interval
+ */
+ TMovingAverage(double alpha, std::chrono::seconds interval)
+ : Initialized_(0)
+ , Rate_(0)
+ , Uncounted_(0)
+ , Alpha_(alpha)
+ , Interval_(std::chrono::nanoseconds(interval).count())
+ {
+ }
+
+ TMovingAverage(const TMovingAverage& rhs)
+ : Initialized_(AtomicGet(rhs.Initialized_))
+ , Rate_(AtomicGet(rhs.Rate_))
+ , Uncounted_(AtomicGet(rhs.Uncounted_))
+ , Alpha_(rhs.Alpha_)
+ , Interval_(rhs.Interval_)
+ {
+ }
+
+ TMovingAverage& operator=(const TMovingAverage& rhs) {
+ AtomicSet(Initialized_, AtomicGet(Initialized_));
+ AtomicSet(Rate_, AtomicGet(rhs.Rate_));
+ AtomicSet(Uncounted_, AtomicGet(rhs.Uncounted_));
+ Alpha_ = rhs.Alpha_;
+ Interval_ = rhs.Interval_;
+ return *this;
+ }
+
+ /**
+ * Update the moving average with a new value.
+ *
+ * @param n the new value
+ */
+ void Update(ui64 n = 1) {
+ AtomicAdd(Uncounted_, n);
+ }
+
+ /**
+ * Mark the passage of time and decay the current rate accordingly.
+ */
+ void Tick() {
+ double instantRate = AtomicSwap(&Uncounted_, 0) / Interval_;
+ if (AtomicGet(Initialized_)) {
+ double rate = AsDouble(AtomicGet(Rate_));
+ rate += (Alpha_ * (instantRate - rate));
+ AtomicSet(Rate_, AsAtomic(rate));
+ } else {
+ AtomicSet(Rate_, AsAtomic(instantRate));
+ AtomicSet(Initialized_, 1);
+ }
+ }
+
+ /**
+ * @return the rate in the seconds
+ */
+ double GetRate() const {
+ double rate = AsDouble(AtomicGet(Rate_));
+ return rate * std::nano::den;
+ }
+
+ private:
+ static double AsDouble(TAtomicBase val) {
+ union {
+ double D;
+ TAtomicBase A;
+ } doubleAtomic;
+ doubleAtomic.A = val;
+ return doubleAtomic.D;
+ }
+
+ static TAtomicBase AsAtomic(double val) {
+ union {
+ double D;
+ TAtomicBase A;
+ } doubleAtomic;
+ doubleAtomic.D = val;
+ return doubleAtomic.A;
+ }
+
+ private:
+ TAtomic Initialized_;
+ TAtomic Rate_;
+ TAtomic Uncounted_;
+ double Alpha_;
+ double Interval_;
+ };
+
+ /**
+ * A meter metric which measures mean throughput and one-, five-, and
+ * fifteen-minute exponentially-weighted moving average throughputs.
+ */
+ template <typename TClock>
+ class TMeterImpl: private TNonCopyable {
+ public:
+ TMeterImpl()
+ : StartTime_(TClock::now())
+ , LastTick_(StartTime_.time_since_epoch().count())
+ , Count_(0)
+ , OneMinuteRate_(TMovingAverage::OneMinute())
+ , FiveMinutesRate_(TMovingAverage::FiveMinutes())
+ , FifteenMinutesRate_(TMovingAverage::FifteenMinutes())
+ {
+ }
+
+ /**
+ * Mark the occurrence of events.
+ *
+ * @param n the number of events
+ */
+ void Mark(ui64 n = 1) {
+ TickIfNecessary();
+ AtomicAdd(Count_, n);
+ OneMinuteRate_.Update(n);
+ FiveMinutesRate_.Update(n);
+ FifteenMinutesRate_.Update(n);
+ }
+
+ /**
+ * Returns the one-minute exponentially-weighted moving average rate at
+ * which events have occurred since the meter was created.
+ *
+ * This rate has the same exponential decay factor as the one-minute load
+ * average in the top Unix command.
+ *
+ * @return the one-minute exponentially-weighted moving average rate at
+ * which events have occurred since the meter was created
+ */
+ double GetOneMinuteRate() const {
+ return OneMinuteRate_.GetRate();
+ }
+
+ /**
+ * Returns the five-minute exponentially-weighted moving average rate at
+ * which events have occurred since the meter was created.
+ *
+ * This rate has the same exponential decay factor as the five-minute load
+ * average in the top Unix command.
+ *
+ * @return the five-minute exponentially-weighted moving average rate at
+ * which events have occurred since the meter was created
+ */
+ double GetFiveMinutesRate() const {
+ return FiveMinutesRate_.GetRate();
+ }
+
+ /**
+ * Returns the fifteen-minute exponentially-weighted moving average rate
+ * at which events have occurred since the meter was created.
+ *
+ * This rate has the same exponential decay factor as the fifteen-minute
+ * load average in the top Unix command.
+ *
+ * @return the fifteen-minute exponentially-weighted moving average rate
+ * at which events have occurred since the meter was created
+ */
+ double GetFifteenMinutesRate() const {
+ return FifteenMinutesRate_.GetRate();
+ }
+
+ /**
+ * @return the mean rate at which events have occurred since the meter
+ * was created
+ */
+ double GetMeanRate() const {
+ if (GetCount() == 0) {
+ return 0.0;
+ }
+
+ auto now = TClock::now();
+ std::chrono::duration<double> elapsedSeconds = now - StartTime_;
+ return GetCount() / elapsedSeconds.count();
+ }
+
+ /**
+ * @return the number of events which have been marked
+ */
+ ui64 GetCount() const {
+ return AtomicGet(Count_);
+ }
+
+ private:
+ void TickIfNecessary() {
+ static ui64 TICK_INTERVAL_NS =
+ std::chrono::nanoseconds(
+ std::chrono::seconds(TMovingAverage::INTERVAL))
+ .count();
+
+ auto oldTickNs = AtomicGet(LastTick_);
+ auto newTickNs = TClock::now().time_since_epoch().count();
+ ui64 elapsedNs = std::abs(newTickNs - oldTickNs);
+
+ if (elapsedNs > TICK_INTERVAL_NS) {
+ // adjust to interval begining
+ newTickNs -= elapsedNs % TICK_INTERVAL_NS;
+ if (AtomicCas(&LastTick_, newTickNs, oldTickNs)) {
+ ui64 requiredTicks = elapsedNs / TICK_INTERVAL_NS;
+ for (ui64 i = 0; i < requiredTicks; ++i) {
+ OneMinuteRate_.Tick();
+ FiveMinutesRate_.Tick();
+ FifteenMinutesRate_.Tick();
+ }
+ }
+ }
+ }
+
+ private:
+ const typename TClock::time_point StartTime_;
+ TAtomic LastTick_;
+ TAtomic Count_;
+ TMovingAverage OneMinuteRate_;
+ TMovingAverage FiveMinutesRate_;
+ TMovingAverage FifteenMinutesRate_;
+ };
+
+ using TSystemMeter = TMeterImpl<std::chrono::system_clock>;
+ using TSteadyMeter = TMeterImpl<std::chrono::steady_clock>;
+ using THighResMeter = TMeterImpl<std::chrono::high_resolution_clock>;
+ using TMeter = THighResMeter;
+
+}
diff --git a/library/cpp/monlib/counters/meter_ut.cpp b/library/cpp/monlib/counters/meter_ut.cpp
new file mode 100644
index 0000000000..b507d16fbd
--- /dev/null
+++ b/library/cpp/monlib/counters/meter_ut.cpp
@@ -0,0 +1,41 @@
+#include "meter.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NMonitoring;
+
+struct TMockClock {
+ using duration = std::chrono::nanoseconds;
+ using rep = duration::rep;
+ using period = duration::period;
+ using time_point = std::chrono::time_point<TMockClock, duration>;
+
+ static time_point now() noexcept {
+ static int index = 0;
+ return index++ < 2 ? time_point() : time_point(std::chrono::seconds(10));
+ }
+};
+
+using TMockMeter = TMeterImpl<TMockClock>;
+
+Y_UNIT_TEST_SUITE(TMeterTest) {
+ Y_UNIT_TEST(StartsOutWithNoRatesOrCount) {
+ TMeter meter;
+ UNIT_ASSERT_EQUAL(meter.GetCount(), 0L);
+ UNIT_ASSERT_DOUBLES_EQUAL(meter.GetMeanRate(), 0.0, 0.0001);
+ UNIT_ASSERT_DOUBLES_EQUAL(meter.GetOneMinuteRate(), 0.0, 0.0001);
+ UNIT_ASSERT_DOUBLES_EQUAL(meter.GetFiveMinutesRate(), 0.0, 0.0001);
+ UNIT_ASSERT_DOUBLES_EQUAL(meter.GetFifteenMinutesRate(), 0.0, 0.0001);
+ }
+
+ Y_UNIT_TEST(MarksEventsAndUpdatesRatesAndCount) {
+ TMockMeter meter;
+ meter.Mark();
+ meter.Mark(2);
+ UNIT_ASSERT_EQUAL(meter.GetCount(), 3L);
+ UNIT_ASSERT_DOUBLES_EQUAL(meter.GetMeanRate(), 0.3, 0.001);
+ UNIT_ASSERT_DOUBLES_EQUAL(meter.GetOneMinuteRate(), 0.1840, 0.0001);
+ UNIT_ASSERT_DOUBLES_EQUAL(meter.GetFiveMinutesRate(), 0.1966, 0.0001);
+ UNIT_ASSERT_DOUBLES_EQUAL(meter.GetFifteenMinutesRate(), 0.1988, 0.0001);
+ }
+}
diff --git a/library/cpp/monlib/counters/timer.h b/library/cpp/monlib/counters/timer.h
new file mode 100644
index 0000000000..03dfb35337
--- /dev/null
+++ b/library/cpp/monlib/counters/timer.h
@@ -0,0 +1,176 @@
+#pragma once
+
+#include "histogram.h"
+
+#include <util/generic/scope.h>
+
+#include <chrono>
+
+namespace NMonitoring {
+ /**
+ * A timer counter which aggregates timing durations and provides duration
+ * statistics in selected time resolution.
+ */
+ template <typename TResolution>
+ class TTimerImpl {
+ public:
+ /**
+ * Construct a timer given the Lowest and Highest values to be tracked
+ * and a number of significant decimal digits. Providing a
+ * lowestDiscernibleValue is useful in situations where the units used for
+ * the timer's values are much smaller that the minimal accuracy
+ * required. E.g. when tracking time values stated in nanosecond units,
+ * where the minimal accuracy required is a microsecond, the proper value
+ * for lowestDiscernibleValue would be 1000.
+ *
+ * @param min The lowest value that can be discerned (distinguished from
+ * 0) by the timer. Must be a positive integer that is >= 1.
+ * May be internally rounded down to nearest power of 2.
+ *
+ * @param max The highest value to be tracked by the timer. Must be a
+ * positive integer that is >= (2 * min).
+ *
+ * @param numberOfSignificantValueDigits Specifies the precision to use.
+ * This is the number of significant decimal digits to which the
+ * timer will maintain value resolution and separation. Must be
+ * a non-negative integer between 0 and 5.
+ */
+ TTimerImpl(ui64 min, ui64 max, i32 numberOfSignificantValueDigits = 3)
+ : TTimerImpl(TResolution(min), TResolution(max),
+ numberOfSignificantValueDigits) {
+ }
+
+ /**
+ * Construct a timer given the Lowest and Highest values to be tracked
+ * and a number of significant decimal digits.
+ *
+ * @param min The lowest value that can be discerned (distinguished from
+ * 0) by the timer.
+ *
+ * @param max The highest value to be tracked by the histogram. Must be a
+ * positive integer that is >= (2 * min).
+ *
+ * @param numberOfSignificantValueDigits Specifies the precision to use.
+ */
+ template <typename TDurationMin, typename TDurationMax>
+ TTimerImpl(TDurationMin min, TDurationMax max,
+ i32 numberOfSignificantValueDigits = 3)
+ : Histogram_(std::chrono::duration_cast<TResolution>(min).count(),
+ std::chrono::duration_cast<TResolution>(max).count(),
+ numberOfSignificantValueDigits) {
+ }
+
+ /**
+ * Records a value in the timer with timer resulution. Recorded value will
+ * be rounded to a precision at or better than the
+ * NumberOfSignificantValueDigits specified at construction time.
+ *
+ * @param duration duration to add to the timer
+ * @return false if the value is larger than the max and can't be recorded,
+ * true otherwise.
+ */
+ bool RecordValue(ui64 duration) {
+ return Histogram_.RecordValue(duration);
+ }
+
+ /**
+ * Records a duration in the timer. Recorded value will be converted to
+ * the timer resulution and rounded to a precision at or better than the
+ * NumberOfSignificantValueDigits specified at construction time.
+ *
+ * @param duration duration to add to the timer
+ * @return false if the value is larger than the max and can't be recorded,
+ * true otherwise.
+ */
+ template <typename TDuration>
+ bool RecordValue(TDuration duration) {
+ auto count = static_cast<ui64>(
+ std::chrono::duration_cast<TResolution>(duration).count());
+ return RecordValue(count);
+ }
+
+ /**
+ * Records count values in the timer with timer resulution. Recorded value will
+ * be rounded to a precision at or better than the
+ * NumberOfSignificantValueDigits specified at construction time.
+ *
+ * @param duration duration to add to the timer
+ * @param count number of values to add to the histogram
+ * @return false if the value is larger than the max and can't be recorded,
+ * true otherwise.
+ */
+ bool RecordValues(ui64 duration, ui64 count) {
+ return Histogram_.RecordValues(duration, count);
+ }
+
+ /**
+ * Measures a time of functor execution.
+ *
+ * @param fn functor whose duration should be timed
+ */
+ template <typename TFunc>
+ void Measure(TFunc&& fn) {
+ using TClock = std::chrono::high_resolution_clock;
+
+ auto start = TClock::now();
+
+ Y_SCOPE_EXIT(this, start) {
+ RecordValue(TClock::now() - start);
+ };
+
+ fn();
+ }
+
+ /**
+ * Place a copy of the value counts accumulated since the last snapshot
+ * was taken into {@code snapshot}. Calling this member-function will
+ * reset the value counts, and start accumulating value counts for the
+ * next interval.
+ *
+ * @param snapshot the structure into which the values should be copied.
+ */
+ void TakeSnapshot(THistogramSnapshot* snapshot) {
+ Histogram_.TakeSnaphot(snapshot);
+ }
+
+ private:
+ THdrHistogram Histogram_;
+ };
+
+ /**
+ * Timer template instantiations for certain time resolutions.
+ */
+ using TTimerNs = TTimerImpl<std::chrono::nanoseconds>;
+ using TTimerUs = TTimerImpl<std::chrono::microseconds>;
+ using TTimerMs = TTimerImpl<std::chrono::milliseconds>;
+ using TTimerS = TTimerImpl<std::chrono::seconds>;
+
+ /**
+ * A timing scope to record elapsed time since creation.
+ */
+ template <typename TTimer, typename TFunc = std::function<void(std::chrono::high_resolution_clock::duration)>>
+ class TTimerScope {
+ using TClock = std::chrono::high_resolution_clock;
+
+ public:
+ explicit TTimerScope(TTimer* timer, TFunc* callback = nullptr)
+ : Timer_(timer)
+ , StartTime_(TClock::now())
+ , Callback_(callback)
+ {
+ }
+
+ ~TTimerScope() {
+ TClock::duration duration = TClock::now() - StartTime_;
+ if (Callback_) {
+ (*Callback_)(duration);
+ }
+ Timer_->RecordValue(duration);
+ }
+
+ private:
+ TTimer* Timer_;
+ TClock::time_point StartTime_;
+ TFunc* Callback_;
+ };
+}
diff --git a/library/cpp/monlib/counters/timer_ut.cpp b/library/cpp/monlib/counters/timer_ut.cpp
new file mode 100644
index 0000000000..c5cd07e89d
--- /dev/null
+++ b/library/cpp/monlib/counters/timer_ut.cpp
@@ -0,0 +1,81 @@
+#include "timer.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NMonitoring;
+using namespace std::literals::chrono_literals;
+
+class TCallback {
+public:
+ explicit TCallback(int value)
+ : Value_(value){};
+ void operator()(std::chrono::high_resolution_clock::duration duration) {
+ Value_ = duration.count();
+ };
+
+ int Value_;
+};
+
+Y_UNIT_TEST_SUITE(TTimerTest) {
+ Y_UNIT_TEST(RecordValue) {
+ TTimerNs timerNs(1ns, 1s);
+ UNIT_ASSERT(timerNs.RecordValue(10us));
+
+ TTimerUs timerUs(1us, 1s);
+ UNIT_ASSERT(timerUs.RecordValue(10us));
+
+ THistogramSnapshot snapshot;
+ timerNs.TakeSnapshot(&snapshot);
+ UNIT_ASSERT_EQUAL(snapshot.Min, 10000);
+ UNIT_ASSERT_EQUAL(snapshot.Max, 10007);
+ UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.0, 1e-6);
+
+ timerUs.TakeSnapshot(&snapshot);
+ UNIT_ASSERT_EQUAL(snapshot.Min, 10);
+ UNIT_ASSERT_EQUAL(snapshot.Max, 10);
+ UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.0, 1e-6);
+ }
+
+ Y_UNIT_TEST(Measure) {
+ TTimerNs timer(1ns, 1s);
+ timer.Measure([]() {
+ Sleep(TDuration::MilliSeconds(1));
+ });
+ THistogramSnapshot snapshot;
+ timer.TakeSnapshot(&snapshot);
+
+ UNIT_ASSERT(snapshot.Min > std::chrono::nanoseconds(1ms).count());
+ UNIT_ASSERT(snapshot.Max > std::chrono::nanoseconds(1ms).count());
+ UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.0, 1e-6);
+ }
+
+ Y_UNIT_TEST(TimerScope) {
+ TTimerUs timer(1us, 1000s);
+ {
+ TTimerScope<TTimerUs> scope(&timer);
+ Sleep(TDuration::MilliSeconds(10));
+ }
+ THistogramSnapshot snapshot;
+ timer.TakeSnapshot(&snapshot);
+
+ UNIT_ASSERT(snapshot.Min > std::chrono::microseconds(10ms).count());
+ UNIT_ASSERT(snapshot.Max > std::chrono::microseconds(10ms).count());
+ UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.0, 1e-6);
+ }
+
+ Y_UNIT_TEST(TimerScopeWithCallback) {
+ TCallback callback(0);
+ TTimerUs timer(1us, 1000s);
+ {
+ TTimerScope<TTimerUs, TCallback> scope(&timer, &callback);
+ Sleep(TDuration::MilliSeconds(10));
+ }
+ THistogramSnapshot snapshot;
+ timer.TakeSnapshot(&snapshot);
+
+ UNIT_ASSERT(snapshot.Min > std::chrono::microseconds(10ms).count());
+ UNIT_ASSERT(snapshot.Max > std::chrono::microseconds(10ms).count());
+ UNIT_ASSERT_DOUBLES_EQUAL(snapshot.StdDeviation, 0.0, 1e-6);
+ UNIT_ASSERT(callback.Value_ > std::chrono::microseconds(10ms).count());
+ }
+}
diff --git a/library/cpp/monlib/counters/ut/ya.make b/library/cpp/monlib/counters/ut/ya.make
new file mode 100644
index 0000000000..999dadb199
--- /dev/null
+++ b/library/cpp/monlib/counters/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/monlib/counters)
+
+OWNER(jamel)
+
+SRCS(
+ counters_ut.cpp
+ histogram_ut.cpp
+ meter_ut.cpp
+ timer_ut.cpp
+)
+
+END()
diff --git a/library/cpp/monlib/counters/ya.make b/library/cpp/monlib/counters/ya.make
new file mode 100644
index 0000000000..aa1a671bf8
--- /dev/null
+++ b/library/cpp/monlib/counters/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(jamel)
+
+SRCS(
+ counters.cpp
+ histogram.cpp
+ meter.cpp
+)
+
+PEERDIR(
+ library/cpp/histogram/hdr
+)
+
+END()
diff --git a/library/cpp/monlib/deprecated/json/ut/ya.make b/library/cpp/monlib/deprecated/json/ut/ya.make
new file mode 100644
index 0000000000..18315993b5
--- /dev/null
+++ b/library/cpp/monlib/deprecated/json/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/monlib/deprecated/json)
+
+OWNER(
+ jamel
+ g:solomon
+)
+
+SRCS(
+ writer_ut.cpp
+)
+
+END()
diff --git a/library/cpp/monlib/deprecated/json/writer.cpp b/library/cpp/monlib/deprecated/json/writer.cpp
new file mode 100644
index 0000000000..a581f2e07a
--- /dev/null
+++ b/library/cpp/monlib/deprecated/json/writer.cpp
@@ -0,0 +1,100 @@
+#include "writer.h"
+
+namespace NMonitoring {
+ TDeprecatedJsonWriter::TDeprecatedJsonWriter(IOutputStream* out)
+ : JsonWriter(out, false)
+ , State(STATE_ROOT)
+ {
+ }
+
+ void TDeprecatedJsonWriter::TransitionState(EState current, EState next) {
+ if (State != current) {
+ ythrow yexception() << "wrong state";
+ }
+ State = next;
+ }
+
+ void TDeprecatedJsonWriter::OpenDocument() {
+ TransitionState(STATE_ROOT, STATE_DOCUMENT);
+ JsonWriter.OpenMap();
+ }
+
+ void TDeprecatedJsonWriter::CloseDocument() {
+ TransitionState(STATE_DOCUMENT, STATE_ROOT);
+ JsonWriter.CloseMap();
+ JsonWriter.Flush();
+ }
+
+ void TDeprecatedJsonWriter::OpenCommonLabels() {
+ TransitionState(STATE_DOCUMENT, STATE_COMMON_LABELS);
+ JsonWriter.Write("commonLabels");
+ JsonWriter.OpenMap();
+ }
+
+ void TDeprecatedJsonWriter::CloseCommonLabels() {
+ TransitionState(STATE_COMMON_LABELS, STATE_DOCUMENT);
+ JsonWriter.CloseMap();
+ }
+
+ void TDeprecatedJsonWriter::WriteCommonLabel(TStringBuf name, TStringBuf value) {
+ TransitionState(STATE_COMMON_LABELS, STATE_COMMON_LABELS);
+ JsonWriter.Write(name, value);
+ }
+
+ void TDeprecatedJsonWriter::OpenMetrics() {
+ TransitionState(STATE_DOCUMENT, STATE_METRICS);
+ JsonWriter.Write("sensors");
+ JsonWriter.OpenArray();
+ }
+
+ void TDeprecatedJsonWriter::CloseMetrics() {
+ TransitionState(STATE_METRICS, STATE_DOCUMENT);
+ JsonWriter.CloseArray();
+ }
+
+ void TDeprecatedJsonWriter::OpenMetric() {
+ TransitionState(STATE_METRICS, STATE_METRIC);
+ JsonWriter.OpenMap();
+ }
+
+ void TDeprecatedJsonWriter::CloseMetric() {
+ TransitionState(STATE_METRIC, STATE_METRICS);
+ JsonWriter.CloseMap();
+ }
+
+ void TDeprecatedJsonWriter::OpenLabels() {
+ TransitionState(STATE_METRIC, STATE_LABELS);
+ JsonWriter.Write("labels");
+ JsonWriter.OpenMap();
+ }
+
+ void TDeprecatedJsonWriter::CloseLabels() {
+ TransitionState(STATE_LABELS, STATE_METRIC);
+ JsonWriter.CloseMap();
+ }
+
+ void TDeprecatedJsonWriter::WriteLabel(TStringBuf name, TStringBuf value) {
+ TransitionState(STATE_LABELS, STATE_LABELS);
+ JsonWriter.Write(name, value);
+ }
+
+ void TDeprecatedJsonWriter::WriteModeDeriv() {
+ TransitionState(STATE_METRIC, STATE_METRIC);
+ JsonWriter.Write("mode", "deriv");
+ }
+
+ void TDeprecatedJsonWriter::WriteValue(long long value) {
+ TransitionState(STATE_METRIC, STATE_METRIC);
+ JsonWriter.Write("value", value);
+ }
+
+ void TDeprecatedJsonWriter::WriteDoubleValue(double value) {
+ TransitionState(STATE_METRIC, STATE_METRIC);
+ JsonWriter.Write("value", value);
+ }
+
+ void TDeprecatedJsonWriter::WriteTs(ui64 ts) {
+ TransitionState(STATE_METRIC, STATE_METRIC);
+ JsonWriter.Write("ts", ts);
+ }
+}
diff --git a/library/cpp/monlib/deprecated/json/writer.h b/library/cpp/monlib/deprecated/json/writer.h
new file mode 100644
index 0000000000..183288143c
--- /dev/null
+++ b/library/cpp/monlib/deprecated/json/writer.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#include <library/cpp/json/json_writer.h>
+
+namespace NMonitoring {
+ /**
+ * Deprecated writer of Solomon JSON format
+ * https://wiki.yandex-team.ru/solomon/api/dataformat/json
+ *
+ * This writer will be deleted soon, so please consider to use
+ * high level library library/cpp/monlib/encode which is decoupled from the
+ * particular format.
+ */
+ class TDeprecatedJsonWriter {
+ private:
+ NJson::TJsonWriter JsonWriter;
+ enum EState {
+ STATE_ROOT,
+ STATE_DOCUMENT,
+ STATE_COMMON_LABELS,
+ STATE_METRICS,
+ STATE_METRIC,
+ STATE_LABELS,
+ };
+ EState State;
+
+ public:
+ explicit TDeprecatedJsonWriter(IOutputStream* out);
+
+ void OpenDocument();
+ void CloseDocument();
+
+ void OpenCommonLabels();
+ void CloseCommonLabels();
+
+ void WriteCommonLabel(TStringBuf name, TStringBuf value);
+
+ void OpenMetrics();
+ void CloseMetrics();
+
+ void OpenMetric();
+ void CloseMetric();
+
+ void OpenLabels();
+ void CloseLabels();
+
+ void WriteLabel(TStringBuf name, TStringBuf value);
+
+ template <typename... T>
+ void WriteLabels(T... pairs) {
+ OpenLabels();
+ WriteLabelsInner(pairs...);
+ CloseLabels();
+ }
+
+ void WriteModeDeriv();
+
+ void WriteValue(long long value);
+ void WriteDoubleValue(double d);
+
+ void WriteTs(ui64 ts);
+
+ private:
+ void WriteLabelsInner(TStringBuf name, TStringBuf value) {
+ WriteLabel(name, value);
+ }
+
+ template <typename... T>
+ void WriteLabelsInner(TStringBuf name, TStringBuf value, T... pairs) {
+ WriteLabel(name, value);
+ WriteLabelsInner(pairs...);
+ }
+
+ inline void TransitionState(EState current, EState next);
+ };
+}
diff --git a/library/cpp/monlib/deprecated/json/writer_ut.cpp b/library/cpp/monlib/deprecated/json/writer_ut.cpp
new file mode 100644
index 0000000000..1f9fc8f393
--- /dev/null
+++ b/library/cpp/monlib/deprecated/json/writer_ut.cpp
@@ -0,0 +1,32 @@
+#include "writer.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NMonitoring;
+
+Y_UNIT_TEST_SUITE(JsonWriterTests) {
+ Y_UNIT_TEST(One) {
+ TStringStream ss;
+ TDeprecatedJsonWriter w(&ss);
+ w.OpenDocument();
+ w.OpenMetrics();
+
+ for (int i = 0; i < 5; ++i) {
+ w.OpenMetric();
+ w.OpenLabels();
+ w.WriteLabel("user", TString("") + (char)('a' + i));
+ w.WriteLabel("name", "NWrites");
+ w.CloseLabels();
+ if (i % 2 == 0) {
+ w.WriteModeDeriv();
+ }
+ w.WriteValue(10l);
+ w.CloseMetric();
+ }
+
+ w.CloseMetrics();
+ w.CloseDocument();
+
+ //Cout << ss.Str() << "\n";
+ }
+}
diff --git a/library/cpp/monlib/deprecated/json/ya.make b/library/cpp/monlib/deprecated/json/ya.make
new file mode 100644
index 0000000000..0ca903ee62
--- /dev/null
+++ b/library/cpp/monlib/deprecated/json/ya.make
@@ -0,0 +1,26 @@
+LIBRARY()
+
+# Deprecated writer of Solomon JSON format
+# https://wiki.yandex-team.ru/solomon/api/dataformat/json
+#
+# This writer will be deleted soon, so please consider to use
+# high level library library/cpp/monlib/encode which is decoupled from the
+# particular format.
+
+OWNER(
+ jamel
+ g:solomon
+)
+
+SRCS(
+ writer.h
+ writer.cpp
+)
+
+PEERDIR(
+ library/cpp/json
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/monlib/deprecated/ya.make b/library/cpp/monlib/deprecated/ya.make
new file mode 100644
index 0000000000..9345139aee
--- /dev/null
+++ b/library/cpp/monlib/deprecated/ya.make
@@ -0,0 +1,8 @@
+OWNER(
+ g:solomon
+ jamel
+)
+
+RECURSE(
+ json
+)
diff --git a/library/cpp/monlib/dynamic_counters/contention_ut.cpp b/library/cpp/monlib/dynamic_counters/contention_ut.cpp
new file mode 100644
index 0000000000..8798044ee3
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/contention_ut.cpp
@@ -0,0 +1,61 @@
+#include "counters.h"
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/system/event.h>
+#include <util/system/thread.h>
+
+using namespace NMonitoring;
+
+Y_UNIT_TEST_SUITE(TDynamicCountersContentionTest) {
+
+ Y_UNIT_TEST(EnsureNonlocking) {
+ TDynamicCounterPtr counters = MakeIntrusive<TDynamicCounters>();
+
+ class TConsumer : public ICountableConsumer {
+ TAutoEvent Ev;
+ TAutoEvent Response;
+ TDynamicCounterPtr Counters;
+ TThread Thread;
+
+ public:
+ TConsumer(TDynamicCounterPtr counters)
+ : Counters(counters)
+ , Thread(std::bind(&TConsumer::ThreadFunc, this))
+ {
+ Thread.Start();
+ }
+
+ ~TConsumer() override {
+ Thread.Join();
+ }
+
+ void OnCounter(const TString& /*labelName*/, const TString& /*labelValue*/, const TCounterForPtr* /*counter*/) override {
+ Ev.Signal();
+ Response.Wait();
+ }
+
+ void OnHistogram(const TString& /*labelName*/, const TString& /*labelValue*/, IHistogramSnapshotPtr /*snapshot*/, bool /*derivative*/) override {
+ }
+
+ void OnGroupBegin(const TString& /*labelName*/, const TString& /*labelValue*/, const TDynamicCounters* /*group*/) override {
+ }
+
+ void OnGroupEnd(const TString& /*labelName*/, const TString& /*labelValue*/, const TDynamicCounters* /*group*/) override {
+ }
+
+ private:
+ void ThreadFunc() {
+ // acts like a coroutine
+ Ev.Wait();
+ auto ctr = Counters->GetSubgroup("label", "value")->GetCounter("name");
+ Y_VERIFY(*ctr == 42);
+ Response.Signal();
+ }
+ };
+
+ auto ctr = counters->GetSubgroup("label", "value")->GetCounter("name");
+ *ctr = 42;
+ TConsumer consumer(counters);
+ counters->Accept({}, {}, consumer);
+ }
+
+}
diff --git a/library/cpp/monlib/dynamic_counters/counters.cpp b/library/cpp/monlib/dynamic_counters/counters.cpp
new file mode 100644
index 0000000000..3635d87d0d
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/counters.cpp
@@ -0,0 +1,308 @@
+#include "counters.h"
+
+#include <library/cpp/monlib/service/pages/templates.h>
+
+#include <util/generic/cast.h>
+
+using namespace NMonitoring;
+
+namespace {
+ TDynamicCounters* AsDynamicCounters(const TIntrusivePtr<TCountableBase>& ptr) {
+ return dynamic_cast<TDynamicCounters*>(ptr.Get());
+ }
+
+ TCounterForPtr* AsCounter(const TIntrusivePtr<TCountableBase>& ptr) {
+ return dynamic_cast<TCounterForPtr*>(ptr.Get());
+ }
+
+ TExpiringCounter* AsExpiringCounter(const TIntrusivePtr<TCountableBase>& ptr) {
+ return dynamic_cast<TExpiringCounter*>(ptr.Get());
+ }
+
+ TExpiringHistogramCounter* AsExpiringHistogramCounter(const TIntrusivePtr<TCountableBase>& ptr) {
+ return dynamic_cast<TExpiringHistogramCounter*>(ptr.Get());
+ }
+
+ THistogramCounter* AsHistogram(const TIntrusivePtr<TCountableBase>& ptr) {
+ return dynamic_cast<THistogramCounter*>(ptr.Get());
+ }
+
+ TIntrusivePtr<TCounterForPtr> AsCounterRef(const TIntrusivePtr<TCountableBase>& ptr) {
+ return VerifyDynamicCast<TCounterForPtr*>(ptr.Get());
+ }
+
+ TIntrusivePtr<TDynamicCounters> AsGroupRef(const TIntrusivePtr<TCountableBase>& ptr) {
+ return VerifyDynamicCast<TDynamicCounters*>(ptr.Get());
+ }
+
+ THistogramPtr AsHistogramRef(const TIntrusivePtr<TCountableBase>& ptr) {
+ return VerifyDynamicCast<THistogramCounter*>(ptr.Get());
+ }
+
+ bool IsExpiringCounter(const TIntrusivePtr<TCountableBase>& ptr) {
+ return AsExpiringCounter(ptr) != nullptr || AsExpiringHistogramCounter(ptr) != nullptr;
+ }
+}
+
+static constexpr TStringBuf INDENT = " ";
+
+TDynamicCounters::TDynamicCounters(EVisibility vis)
+{
+ Visibility_ = vis;
+}
+
+TDynamicCounters::~TDynamicCounters() {
+}
+
+TDynamicCounters::TCounterPtr TDynamicCounters::GetExpiringCounter(const TString& value, bool derivative, EVisibility vis) {
+ return GetExpiringNamedCounter("sensor", value, derivative, vis);
+}
+
+TDynamicCounters::TCounterPtr TDynamicCounters::GetExpiringNamedCounter(const TString& name, const TString& value, bool derivative, EVisibility vis) {
+ return AsCounterRef(GetNamedCounterImpl<true, TExpiringCounter>(name, value, derivative, vis));
+}
+
+TDynamicCounters::TCounterPtr TDynamicCounters::GetCounter(const TString& value, bool derivative, EVisibility vis) {
+ return GetNamedCounter("sensor", value, derivative, vis);
+}
+
+TDynamicCounters::TCounterPtr TDynamicCounters::GetNamedCounter(const TString& name, const TString& value, bool derivative, EVisibility vis) {
+ return AsCounterRef(GetNamedCounterImpl<false, TCounterForPtr>(name, value, derivative, vis));
+}
+
+THistogramPtr TDynamicCounters::GetHistogram(const TString& value, IHistogramCollectorPtr collector, bool derivative, EVisibility vis) {
+ return GetNamedHistogram("sensor", value, std::move(collector), derivative, vis);
+}
+
+THistogramPtr TDynamicCounters::GetNamedHistogram(const TString& name, const TString& value, IHistogramCollectorPtr collector, bool derivative, EVisibility vis) {
+ return AsHistogramRef(GetNamedCounterImpl<false, THistogramCounter>(name, value, std::move(collector), derivative, vis));
+}
+
+THistogramPtr TDynamicCounters::GetExpiringHistogram(const TString& value, IHistogramCollectorPtr collector, bool derivative, EVisibility vis) {
+ return GetExpiringNamedHistogram("sensor", value, std::move(collector), derivative, vis);
+}
+
+THistogramPtr TDynamicCounters::GetExpiringNamedHistogram(const TString& name, const TString& value, IHistogramCollectorPtr collector, bool derivative, EVisibility vis) {
+ return AsHistogramRef(GetNamedCounterImpl<true, TExpiringHistogramCounter>(name, value, std::move(collector), derivative, vis));
+}
+
+TDynamicCounters::TCounterPtr TDynamicCounters::FindCounter(const TString& value) const {
+ return FindNamedCounter("sensor", value);
+}
+
+TDynamicCounters::TCounterPtr TDynamicCounters::FindNamedCounter(const TString& name, const TString& value) const {
+ return AsCounterRef(FindNamedCounterImpl<TCounterForPtr>(name, value));
+}
+
+THistogramPtr TDynamicCounters::FindHistogram(const TString& value) const {
+ return FindNamedHistogram("sensor", value);
+}
+
+THistogramPtr TDynamicCounters::FindNamedHistogram(const TString& name,const TString& value) const {
+ return AsHistogramRef(FindNamedCounterImpl<THistogramCounter>(name, value));
+}
+
+void TDynamicCounters::RemoveCounter(const TString &value) {
+ RemoveNamedCounter("sensor", value);
+}
+
+void TDynamicCounters::RemoveNamedCounter(const TString& name, const TString &value) {
+ auto g = LockForUpdate("RemoveNamedCounter", name, value);
+ if (const auto it = Counters.find({name, value}); it != Counters.end() && AsCounter(it->second)) {
+ Counters.erase(it);
+ }
+}
+
+TIntrusivePtr<TDynamicCounters> TDynamicCounters::GetSubgroup(const TString& name, const TString& value) {
+ auto res = FindSubgroup(name, value);
+ if (!res) {
+ auto g = LockForUpdate("GetSubgroup", name, value);
+ const TChildId key(name, value);
+ if (const auto it = Counters.lower_bound(key); it != Counters.end() && it->first == key) {
+ res = AsGroupRef(it->second);
+ } else {
+ res = MakeIntrusive<TDynamicCounters>(this);
+ Counters.emplace_hint(it, key, res);
+ }
+ }
+ return res;
+}
+
+TIntrusivePtr<TDynamicCounters> TDynamicCounters::FindSubgroup(const TString& name, const TString& value) const {
+ TReadGuard g(Lock);
+ const auto it = Counters.find({name, value});
+ return it != Counters.end() ? AsDynamicCounters(it->second) : nullptr;
+}
+
+void TDynamicCounters::RemoveSubgroup(const TString& name, const TString& value) {
+ auto g = LockForUpdate("RemoveSubgroup", name, value);
+ if (const auto it = Counters.find({name, value}); it != Counters.end() && AsDynamicCounters(it->second)) {
+ Counters.erase(it);
+ }
+}
+
+void TDynamicCounters::ReplaceSubgroup(const TString& name, const TString& value, TIntrusivePtr<TDynamicCounters> subgroup) {
+ auto g = LockForUpdate("ReplaceSubgroup", name, value);
+ const auto it = Counters.find({name, value});
+ Y_VERIFY(it != Counters.end() && AsDynamicCounters(it->second));
+ it->second = std::move(subgroup);
+}
+
+void TDynamicCounters::MergeWithSubgroup(const TString& name, const TString& value) {
+ auto g = LockForUpdate("MergeWithSubgroup", name, value);
+ auto it = Counters.find({name, value});
+ Y_VERIFY(it != Counters.end());
+ TIntrusivePtr<TDynamicCounters> subgroup = AsDynamicCounters(it->second);
+ Y_VERIFY(subgroup);
+ Counters.erase(it);
+ Counters.merge(subgroup->Resign());
+ AtomicAdd(ExpiringCount, AtomicSwap(&subgroup->ExpiringCount, 0));
+}
+
+void TDynamicCounters::ResetCounters(bool derivOnly) {
+ TReadGuard g(Lock);
+ for (auto& [key, value] : Counters) {
+ if (auto counter = AsCounter(value)) {
+ if (!derivOnly || counter->ForDerivative()) {
+ *counter = 0;
+ }
+ } else if (auto subgroup = AsDynamicCounters(value)) {
+ subgroup->ResetCounters(derivOnly);
+ }
+ }
+}
+
+void TDynamicCounters::RegisterCountable(const TString& name, const TString& value, TCountablePtr countable) {
+ Y_VERIFY(countable);
+ auto g = LockForUpdate("RegisterCountable", name, value);
+ const bool inserted = Counters.emplace(TChildId(name, value), std::move(countable)).second;
+ Y_VERIFY(inserted);
+}
+
+void TDynamicCounters::RegisterSubgroup(const TString& name, const TString& value, TIntrusivePtr<TDynamicCounters> subgroup) {
+ RegisterCountable(name, value, subgroup);
+}
+
+void TDynamicCounters::OutputHtml(IOutputStream& os) const {
+ HTML(os) {
+ PRE() {
+ OutputPlainText(os);
+ }
+ }
+}
+
+void TDynamicCounters::EnumerateSubgroups(const std::function<void(const TString& name, const TString& value)>& output) const {
+ TReadGuard g(Lock);
+ for (const auto& [key, value] : Counters) {
+ if (AsDynamicCounters(value)) {
+ output(key.LabelName, key.LabelValue);
+ }
+ }
+}
+
+void TDynamicCounters::OutputPlainText(IOutputStream& os, const TString& indent) const {
+ auto snap = ReadSnapshot();
+ // mark private records in plain text output
+ auto outputVisibilityMarker = [] (EVisibility vis) {
+ return vis == EVisibility::Private ? "\t[PRIVATE]" : "";
+ };
+
+ for (const auto& [key, value] : snap) {
+ if (const auto counter = AsCounter(value)) {
+ os << indent
+ << key.LabelName << '=' << key.LabelValue
+ << ": " << counter->Val()
+ << outputVisibilityMarker(counter->Visibility())
+ << '\n';
+ } else if (const auto histogram = AsHistogram(value)) {
+ os << indent
+ << key.LabelName << '=' << key.LabelValue
+ << ":"
+ << outputVisibilityMarker(histogram->Visibility())
+ << "\n";
+
+ auto snapshot = histogram->Snapshot();
+ for (ui32 i = 0, count = snapshot->Count(); i < count; i++) {
+ os << indent << INDENT << TStringBuf("bin=");
+ TBucketBound bound = snapshot->UpperBound(i);
+ if (bound == Max<TBucketBound>()) {
+ os << TStringBuf("inf");
+ } else {
+ os << bound;
+ }
+ os << ": " << snapshot->Value(i) << '\n';
+ }
+ }
+ }
+
+ for (const auto& [key, value] : snap) {
+ if (const auto subgroup = AsDynamicCounters(value)) {
+ os << "\n";
+ os << indent << key.LabelName << "=" << key.LabelValue << ":\n";
+ subgroup->OutputPlainText(os, indent + INDENT);
+ }
+ }
+}
+
+void TDynamicCounters::Accept(const TString& labelName, const TString& labelValue, ICountableConsumer& consumer) const {
+ if (!IsVisible(Visibility(), consumer.Visibility())) {
+ return;
+ }
+
+ consumer.OnGroupBegin(labelName, labelValue, this);
+ for (auto& [key, value] : ReadSnapshot()) {
+ value->Accept(key.LabelName, key.LabelValue, consumer);
+ }
+ consumer.OnGroupEnd(labelName, labelValue, this);
+}
+
+void TDynamicCounters::RemoveExpired() const {
+ if (AtomicGet(ExpiringCount) == 0) {
+ return;
+ }
+
+ TWriteGuard g(Lock);
+ TAtomicBase count = 0;
+
+ for (auto it = Counters.begin(); it != Counters.end();) {
+ if (IsExpiringCounter(it->second) && it->second->RefCount() == 1) {
+ it = Counters.erase(it);
+ ++count;
+ } else {
+ ++it;
+ }
+ }
+
+ AtomicSub(ExpiringCount, count);
+}
+
+template <bool expiring, class TCounterType, class... TArgs>
+TDynamicCounters::TCountablePtr TDynamicCounters::GetNamedCounterImpl(const TString& name, const TString& value, TArgs&&... args) {
+ {
+ TReadGuard g(Lock);
+ auto it = Counters.find({name, value});
+ if (it != Counters.end()) {
+ return it->second;
+ }
+ }
+
+ auto g = LockForUpdate("GetNamedCounterImpl", name, value);
+ const TChildId key(name, value);
+ auto it = Counters.lower_bound(key);
+ if (it == Counters.end() || it->first != key) {
+ auto value = MakeIntrusive<TCounterType>(std::forward<TArgs>(args)...);
+ it = Counters.emplace_hint(it, key, value);
+ if constexpr (expiring) {
+ AtomicIncrement(ExpiringCount);
+ }
+ }
+ return it->second;
+}
+
+template <class TCounterType>
+TDynamicCounters::TCountablePtr TDynamicCounters::FindNamedCounterImpl(const TString& name, const TString& value) const {
+ TReadGuard g(Lock);
+ auto it = Counters.find({name, value});
+ return it != Counters.end() ? it->second : nullptr;
+}
+
diff --git a/library/cpp/monlib/dynamic_counters/counters.h b/library/cpp/monlib/dynamic_counters/counters.h
new file mode 100644
index 0000000000..dc178cfbe0
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/counters.h
@@ -0,0 +1,374 @@
+#pragma once
+
+#include <library/cpp/monlib/counters/counters.h>
+#include <library/cpp/monlib/metrics/histogram_collector.h>
+
+#include <library/cpp/threading/light_rw_lock/lightrwlock.h>
+#include <library/cpp/containers/stack_vector/stack_vec.h>
+
+#include <util/generic/cast.h>
+#include <util/generic/map.h>
+#include <util/generic/ptr.h>
+#include <util/string/cast.h>
+#include <util/system/rwlock.h>
+
+#include <functional>
+
+namespace NMonitoring {
+ struct TCounterForPtr;
+ struct TDynamicCounters;
+ struct ICountableConsumer;
+
+
+ struct TCountableBase: public TAtomicRefCount<TCountableBase> {
+ // Private means that the object must not be serialized unless the consumer
+ // has explicitly specified this by setting its Visibility to Private.
+ //
+ // Works only for the methods that accept ICountableConsumer
+ enum class EVisibility: ui8 {
+ Unspecified,
+ Public,
+ Private,
+ };
+
+ virtual ~TCountableBase() {
+ }
+
+ virtual void Accept(
+ const TString& labelName, const TString& labelValue,
+ ICountableConsumer& consumer) const = 0;
+
+ virtual EVisibility Visibility() const {
+ return Visibility_;
+ }
+
+ protected:
+ EVisibility Visibility_{EVisibility::Unspecified};
+ };
+
+ inline bool IsVisible(TCountableBase::EVisibility myLevel, TCountableBase::EVisibility consumerLevel) {
+ if (myLevel == TCountableBase::EVisibility::Private
+ && consumerLevel != TCountableBase::EVisibility::Private) {
+
+ return false;
+ }
+
+ return true;
+ }
+
+ struct ICountableConsumer {
+ virtual ~ICountableConsumer() {
+ }
+
+ virtual void OnCounter(
+ const TString& labelName, const TString& labelValue,
+ const TCounterForPtr* counter) = 0;
+
+ virtual void OnHistogram(
+ const TString& labelName, const TString& labelValue,
+ IHistogramSnapshotPtr snapshot, bool derivative) = 0;
+
+ virtual void OnGroupBegin(
+ const TString& labelName, const TString& labelValue,
+ const TDynamicCounters* group) = 0;
+
+ virtual void OnGroupEnd(
+ const TString& labelName, const TString& labelValue,
+ const TDynamicCounters* group) = 0;
+
+ virtual TCountableBase::EVisibility Visibility() const {
+ return TCountableBase::EVisibility::Unspecified;
+ }
+ };
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4522) // multiple assignment operators specified
+#endif // _MSC_VER
+
+ struct TCounterForPtr: public TDeprecatedCounter, public TCountableBase {
+ TCounterForPtr(bool derivative = false, EVisibility vis = EVisibility::Public)
+ : TDeprecatedCounter(0ULL, derivative)
+ {
+ Visibility_ = vis;
+ }
+
+ TCounterForPtr(const TCounterForPtr&) = delete;
+ TCounterForPtr& operator=(const TCounterForPtr& other) = delete;
+
+ void Accept(
+ const TString& labelName, const TString& labelValue,
+ ICountableConsumer& consumer) const override {
+ if (IsVisible(Visibility(), consumer.Visibility())) {
+ consumer.OnCounter(labelName, labelValue, this);
+ }
+ }
+
+ TCountableBase::EVisibility Visibility() const override {
+ return Visibility_;
+ }
+
+ using TDeprecatedCounter::operator++;
+ using TDeprecatedCounter::operator--;
+ using TDeprecatedCounter::operator+=;
+ using TDeprecatedCounter::operator-=;
+ using TDeprecatedCounter::operator=;
+ using TDeprecatedCounter::operator!;
+ };
+
+ struct TExpiringCounter: public TCounterForPtr {
+ explicit TExpiringCounter(bool derivative = false, EVisibility vis = EVisibility::Public)
+ : TCounterForPtr{derivative}
+ {
+ Visibility_ = vis;
+ }
+
+ void Reset() {
+ TDeprecatedCounter::operator=(0);
+ }
+ };
+
+ struct THistogramCounter: public TCountableBase {
+ explicit THistogramCounter(
+ IHistogramCollectorPtr collector, bool derivative = true, EVisibility vis = EVisibility::Public)
+ : Collector_(std::move(collector))
+ , Derivative_(derivative)
+ {
+ Visibility_ = vis;
+ }
+
+ void Collect(i64 value) {
+ Collector_->Collect(value);
+ }
+
+ void Collect(i64 value, ui32 count) {
+ Collector_->Collect(value, count);
+ }
+
+ void Collect(double value, ui32 count) {
+ Collector_->Collect(value, count);
+ }
+
+ void Collect(const IHistogramSnapshot& snapshot) {
+ Collector_->Collect(snapshot);
+ }
+
+ void Accept(
+ const TString& labelName, const TString& labelValue,
+ ICountableConsumer& consumer) const override
+ {
+ if (IsVisible(Visibility(), consumer.Visibility())) {
+ consumer.OnHistogram(labelName, labelValue, Collector_->Snapshot(), Derivative_);
+ }
+ }
+
+ void Reset() {
+ Collector_->Reset();
+ }
+
+ IHistogramSnapshotPtr Snapshot() const {
+ return Collector_->Snapshot();
+ }
+
+ private:
+ IHistogramCollectorPtr Collector_;
+ bool Derivative_;
+ };
+
+ struct TExpiringHistogramCounter: public THistogramCounter {
+ using THistogramCounter::THistogramCounter;
+ };
+
+ using THistogramPtr = TIntrusivePtr<THistogramCounter>;
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+ struct TDynamicCounters;
+
+ typedef TIntrusivePtr<TDynamicCounters> TDynamicCounterPtr;
+ struct TDynamicCounters: public TCountableBase {
+ public:
+ using TCounterPtr = TIntrusivePtr<TCounterForPtr>;
+ using TOnLookupPtr = void (*)(const char *methodName, const TString &name, const TString &value);
+
+ private:
+ TRWMutex Lock;
+ TCounterPtr LookupCounter; // Counts lookups by name
+ TOnLookupPtr OnLookup = nullptr; // Called on each lookup if not nullptr, intended for lightweight tracing.
+
+ typedef TIntrusivePtr<TCountableBase> TCountablePtr;
+
+ struct TChildId {
+ TString LabelName;
+ TString LabelValue;
+ TChildId() {
+ }
+ TChildId(const TString& labelName, const TString& labelValue)
+ : LabelName(labelName)
+ , LabelValue(labelValue)
+ {
+ }
+ auto AsTuple() const {
+ return std::make_tuple(std::cref(LabelName), std::cref(LabelValue));
+ }
+ friend bool operator <(const TChildId& x, const TChildId& y) {
+ return x.AsTuple() < y.AsTuple();
+ }
+ friend bool operator ==(const TChildId& x, const TChildId& y) {
+ return x.AsTuple() == y.AsTuple();
+ }
+ friend bool operator !=(const TChildId& x, const TChildId& y) {
+ return x.AsTuple() != y.AsTuple();
+ }
+ };
+
+ using TCounters = TMap<TChildId, TCountablePtr>;
+ using TLabels = TVector<TChildId>;
+
+ /// XXX: hack for deferred removal of expired counters. Remove once Output* functions are not used for serialization
+ mutable TCounters Counters;
+ mutable TAtomic ExpiringCount = 0;
+
+ public:
+ TDynamicCounters(TCountableBase::EVisibility visibility = TCountableBase::EVisibility::Public);
+
+ TDynamicCounters(const TDynamicCounters *origin)
+ : LookupCounter(origin->LookupCounter)
+ , OnLookup(origin->OnLookup)
+ {}
+
+ ~TDynamicCounters() override;
+
+ // This counter allows to track lookups by name within the whole subtree
+ void SetLookupCounter(TCounterPtr lookupCounter) {
+ TWriteGuard g(Lock);
+ LookupCounter = lookupCounter;
+ }
+
+ void SetOnLookup(TOnLookupPtr onLookup) {
+ TWriteGuard g(Lock);
+ OnLookup = onLookup;
+ }
+
+ TWriteGuard LockForUpdate(const char *method, const TString& name, const TString& value) {
+ auto res = TWriteGuard(Lock);
+ if (LookupCounter) {
+ ++*LookupCounter;
+ }
+ if (OnLookup) {
+ OnLookup(method, name, value);
+ }
+ return res;
+ }
+
+ TStackVec<TCounters::value_type, 256> ReadSnapshot() const {
+ RemoveExpired();
+ TReadGuard g(Lock);
+ TStackVec<TCounters::value_type, 256> items(Counters.begin(), Counters.end());
+ return items;
+ }
+
+ TCounterPtr GetCounter(
+ const TString& value,
+ bool derivative = false,
+ TCountableBase::EVisibility visibility = TCountableBase::EVisibility::Public);
+
+ TCounterPtr GetNamedCounter(
+ const TString& name,
+ const TString& value,
+ bool derivative = false,
+ TCountableBase::EVisibility visibility = TCountableBase::EVisibility::Public);
+
+ THistogramPtr GetHistogram(
+ const TString& value,
+ IHistogramCollectorPtr collector,
+ bool derivative = true,
+ TCountableBase::EVisibility visibility = TCountableBase::EVisibility::Public);
+
+ THistogramPtr GetNamedHistogram(
+ const TString& name,
+ const TString& value,
+ IHistogramCollectorPtr collector,
+ bool derivative = true,
+ TCountableBase::EVisibility visibility = TCountableBase::EVisibility::Public);
+
+ // These counters will be automatically removed from the registry
+ // when last reference to the counter expires.
+ TCounterPtr GetExpiringCounter(
+ const TString& value,
+ bool derivative = false,
+ TCountableBase::EVisibility visibility = TCountableBase::EVisibility::Public);
+
+ TCounterPtr GetExpiringNamedCounter(
+ const TString& name,
+ const TString& value,
+ bool derivative = false,
+ TCountableBase::EVisibility visibility = TCountableBase::EVisibility::Public);
+
+ THistogramPtr GetExpiringHistogram(
+ const TString& value,
+ IHistogramCollectorPtr collector,
+ bool derivative = true,
+ TCountableBase::EVisibility visibility = TCountableBase::EVisibility::Public);
+
+ THistogramPtr GetExpiringNamedHistogram(
+ const TString& name,
+ const TString& value,
+ IHistogramCollectorPtr collector,
+ bool derivative = true,
+ TCountableBase::EVisibility visibility = TCountableBase::EVisibility::Public);
+
+ TCounterPtr FindCounter(const TString& value) const;
+ TCounterPtr FindNamedCounter(const TString& name, const TString& value) const;
+
+ THistogramPtr FindHistogram(const TString& value) const;
+ THistogramPtr FindNamedHistogram(const TString& name,const TString& value) const;
+
+ void RemoveCounter(const TString &value);
+ void RemoveNamedCounter(const TString& name, const TString &value);
+
+ TIntrusivePtr<TDynamicCounters> GetSubgroup(const TString& name, const TString& value);
+ TIntrusivePtr<TDynamicCounters> FindSubgroup(const TString& name, const TString& value) const;
+ void RemoveSubgroup(const TString& name, const TString& value);
+ void ReplaceSubgroup(const TString& name, const TString& value, TIntrusivePtr<TDynamicCounters> subgroup);
+
+ // Move all counters from specified subgroup and remove the subgroup.
+ void MergeWithSubgroup(const TString& name, const TString& value);
+ // Recursively reset all/deriv counters to 0.
+ void ResetCounters(bool derivOnly = false);
+
+ void RegisterSubgroup(const TString& name,
+ const TString& value,
+ TIntrusivePtr<TDynamicCounters> subgroup);
+
+ void OutputHtml(IOutputStream& os) const;
+ void EnumerateSubgroups(const std::function<void(const TString& name, const TString& value)>& output) const;
+
+ // mostly for debugging purposes -- use accept with encoder instead
+ void OutputPlainText(IOutputStream& os, const TString& indent = "") const;
+
+ void Accept(
+ const TString& labelName, const TString& labelValue,
+ ICountableConsumer& consumer) const override;
+
+ private:
+ TCounters Resign() {
+ TCounters counters;
+ TWriteGuard g(Lock);
+ Counters.swap(counters);
+ return counters;
+ }
+
+ void RegisterCountable(const TString& name, const TString& value, TCountablePtr countable);
+ void RemoveExpired() const;
+
+ template <bool expiring, class TCounterType, class... TArgs>
+ TCountablePtr GetNamedCounterImpl(const TString& name, const TString& value, TArgs&&... args);
+
+ template <class TCounterType>
+ TCountablePtr FindNamedCounterImpl(const TString& name, const TString& value) const;
+ };
+
+}
diff --git a/library/cpp/monlib/dynamic_counters/counters_ut.cpp b/library/cpp/monlib/dynamic_counters/counters_ut.cpp
new file mode 100644
index 0000000000..3591037e0a
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/counters_ut.cpp
@@ -0,0 +1,342 @@
+#include "counters.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NMonitoring;
+
+class TCountersPrinter: public ICountableConsumer {
+public:
+ TCountersPrinter(IOutputStream* out)
+ : Out_(out)
+ , Level_(0)
+ {
+ }
+
+private:
+ void OnCounter(
+ const TString& labelName, const TString& labelValue,
+ const TCounterForPtr* counter) override {
+ Indent(Out_, Level_)
+ << labelName << ':' << labelValue
+ << " = " << counter->Val() << '\n';
+ }
+
+ void OnHistogram(
+ const TString& labelName, const TString& labelValue,
+ IHistogramSnapshotPtr snapshot, bool /*derivative*/) override {
+ Indent(Out_, Level_)
+ << labelName << ':' << labelValue
+ << " = " << *snapshot << '\n';
+ }
+
+ void OnGroupBegin(
+ const TString& labelName, const TString& labelValue,
+ const TDynamicCounters*) override {
+ Indent(Out_, Level_++) << labelName << ':' << labelValue << " {\n";
+ }
+
+ void OnGroupEnd(
+ const TString&, const TString&,
+ const TDynamicCounters*) override {
+ Indent(Out_, --Level_) << "}\n";
+ }
+
+ static IOutputStream& Indent(IOutputStream* out, int level) {
+ for (int i = 0; i < level; i++) {
+ out->Write(" ");
+ }
+ return *out;
+ }
+
+private:
+ IOutputStream* Out_;
+ int Level_ = 0;
+};
+
+Y_UNIT_TEST_SUITE(TDynamicCountersTest) {
+ Y_UNIT_TEST(CountersConsumer) {
+ TDynamicCounterPtr rootGroup(new TDynamicCounters());
+
+ auto usersCounter = rootGroup->GetNamedCounter("users", "count");
+ *usersCounter = 7;
+
+ auto hostGroup = rootGroup->GetSubgroup("counters", "resources");
+ auto cpuCounter = hostGroup->GetNamedCounter("resource", "cpu");
+ *cpuCounter = 30;
+
+ auto memGroup = hostGroup->GetSubgroup("resource", "mem");
+ auto usedCounter = memGroup->GetCounter("used");
+ auto freeCounter = memGroup->GetCounter("free");
+ *usedCounter = 100;
+ *freeCounter = 28;
+
+ auto netGroup = hostGroup->GetSubgroup("resource", "net");
+ auto rxCounter = netGroup->GetCounter("rx", true);
+ auto txCounter = netGroup->GetCounter("tx", true);
+ *rxCounter = 8;
+ *txCounter = 9;
+
+ TStringStream ss;
+ TCountersPrinter printer(&ss);
+ rootGroup->Accept("root", "counters", printer);
+
+ UNIT_ASSERT_STRINGS_EQUAL(ss.Str(),
+ "root:counters {\n"
+ " counters:resources {\n"
+ " resource:cpu = 30\n"
+ " resource:mem {\n"
+ " sensor:free = 28\n"
+ " sensor:used = 100\n"
+ " }\n"
+ " resource:net {\n"
+ " sensor:rx = 8\n"
+ " sensor:tx = 9\n"
+ " }\n"
+ " }\n"
+ " users:count = 7\n"
+ "}\n");
+ }
+
+ Y_UNIT_TEST(MergeSubgroup) {
+ TDynamicCounterPtr rootGroup(new TDynamicCounters());
+
+ auto sensor1 = rootGroup->GetNamedCounter("sensor", "1");
+ *sensor1 = 1;
+
+ auto group1 = rootGroup->GetSubgroup("group", "1");
+ auto sensor2 = group1->GetNamedCounter("sensor", "2");
+ *sensor2 = 2;
+
+ auto group2 = group1->GetSubgroup("group", "2");
+ auto sensor3 = group2->GetNamedCounter("sensor", "3");
+ *sensor3 = 3;
+
+ rootGroup->MergeWithSubgroup("group", "1");
+
+ TStringStream ss;
+ TCountersPrinter printer(&ss);
+ rootGroup->Accept("root", "counters", printer);
+
+ UNIT_ASSERT_STRINGS_EQUAL(ss.Str(),
+ "root:counters {\n"
+ " group:2 {\n"
+ " sensor:3 = 3\n"
+ " }\n"
+ " sensor:1 = 1\n"
+ " sensor:2 = 2\n"
+ "}\n");
+ }
+
+ Y_UNIT_TEST(ResetCounters) {
+ TDynamicCounterPtr rootGroup(new TDynamicCounters());
+
+ auto sensor1 = rootGroup->GetNamedCounter("sensor", "1");
+ *sensor1 = 1;
+
+ auto group1 = rootGroup->GetSubgroup("group", "1");
+ auto sensor2 = group1->GetNamedCounter("sensor", "2");
+ *sensor2 = 2;
+
+ auto group2 = group1->GetSubgroup("group", "2");
+ auto sensor3 = group2->GetNamedCounter("sensor", "3", true);
+ *sensor3 = 3;
+
+ rootGroup->ResetCounters(true);
+
+ TStringStream ss1;
+ TCountersPrinter printer1(&ss1);
+ rootGroup->Accept("root", "counters", printer1);
+
+ UNIT_ASSERT_STRINGS_EQUAL(ss1.Str(),
+ "root:counters {\n"
+ " group:1 {\n"
+ " group:2 {\n"
+ " sensor:3 = 0\n"
+ " }\n"
+ " sensor:2 = 2\n"
+ " }\n"
+ " sensor:1 = 1\n"
+ "}\n");
+
+ rootGroup->ResetCounters();
+
+ TStringStream ss2;
+ TCountersPrinter printer2(&ss2);
+ rootGroup->Accept("root", "counters", printer2);
+
+ UNIT_ASSERT_STRINGS_EQUAL(ss2.Str(),
+ "root:counters {\n"
+ " group:1 {\n"
+ " group:2 {\n"
+ " sensor:3 = 0\n"
+ " }\n"
+ " sensor:2 = 0\n"
+ " }\n"
+ " sensor:1 = 0\n"
+ "}\n");
+ }
+
+ Y_UNIT_TEST(RemoveCounter) {
+ TDynamicCounterPtr rootGroup(new TDynamicCounters());
+
+ rootGroup->GetNamedCounter("label", "1");
+ rootGroup->GetCounter("2");
+ rootGroup->GetCounter("3");
+ rootGroup->GetSubgroup("group", "1");
+
+ rootGroup->RemoveNamedCounter("label", "1");
+ rootGroup->RemoveNamedCounter("label", "5");
+ rootGroup->RemoveNamedCounter("group", "1");
+ rootGroup->RemoveCounter("2");
+ rootGroup->RemoveCounter("5");
+
+ TStringStream ss;
+ TCountersPrinter printer(&ss);
+ rootGroup->Accept("root", "counters", printer);
+
+ UNIT_ASSERT_STRINGS_EQUAL(ss.Str(),
+ "root:counters {\n"
+ " group:1 {\n"
+ " }\n"
+ " sensor:3 = 0\n"
+ "}\n");
+ }
+
+ Y_UNIT_TEST(RemoveSubgroup) {
+ TDynamicCounterPtr rootGroup(new TDynamicCounters());
+
+ rootGroup->GetSubgroup("group", "1");
+ rootGroup->GetSubgroup("group", "2");
+ rootGroup->GetCounter("2");
+
+ rootGroup->RemoveSubgroup("group", "1");
+ rootGroup->RemoveSubgroup("group", "3");
+ rootGroup->RemoveSubgroup("sensor", "2");
+
+ TStringStream ss;
+ TCountersPrinter printer(&ss);
+ rootGroup->Accept("root", "counters", printer);
+
+ UNIT_ASSERT_STRINGS_EQUAL(ss.Str(),
+ "root:counters {\n"
+ " group:2 {\n"
+ " }\n"
+ " sensor:2 = 0\n"
+ "}\n");
+ }
+
+ Y_UNIT_TEST(ExpiringCounters) {
+ TDynamicCounterPtr rootGroup{new TDynamicCounters()};
+
+ {
+ auto c = rootGroup->GetExpiringCounter("foo");
+ auto h = rootGroup->GetExpiringHistogram("bar", ExplicitHistogram({1, 42}));
+ h->Collect(15);
+
+ TStringStream ss;
+ TCountersPrinter printer(&ss);
+ rootGroup->Accept("root", "counters", printer);
+ UNIT_ASSERT_STRINGS_EQUAL(ss.Str(),
+ "root:counters {\n"
+ " sensor:bar = {1: 0, 42: 1, inf: 0}\n"
+ " sensor:foo = 0\n"
+ "}\n");
+ }
+
+ TStringStream ss;
+ TCountersPrinter printer(&ss);
+ rootGroup->Accept("root", "counters", printer);
+ UNIT_ASSERT_STRINGS_EQUAL(ss.Str(),
+ "root:counters {\n"
+ "}\n");
+ }
+
+ Y_UNIT_TEST(ExpiringCountersDiesAfterRegistry) {
+ TDynamicCounters::TCounterPtr ptr;
+
+ {
+ TDynamicCounterPtr rootGroup{new TDynamicCounters()};
+ ptr = rootGroup->GetExpiringCounter("foo");
+
+ TStringStream ss;
+ TCountersPrinter printer(&ss);
+ rootGroup->Accept("root", "counters", printer);
+ UNIT_ASSERT_STRINGS_EQUAL(ss.Str(),
+ "root:counters {\n"
+ " sensor:foo = 0\n"
+ "}\n");
+ }
+ }
+
+ Y_UNIT_TEST(HistogramCounter) {
+ TDynamicCounterPtr rootGroup(new TDynamicCounters());
+
+ auto h = rootGroup->GetHistogram("timeMillis", ExponentialHistogram(4, 2));
+ for (i64 i = 1; i < 100; i++) {
+ h->Collect(i);
+ }
+
+ TStringStream ss;
+ TCountersPrinter printer(&ss);
+ rootGroup->Accept("root", "counters", printer);
+ UNIT_ASSERT_STRINGS_EQUAL(ss.Str(),
+ "root:counters {\n"
+ " sensor:timeMillis = {1: 1, 2: 1, 4: 2, inf: 95}\n"
+ "}\n");
+ }
+
+ Y_UNIT_TEST(CounterLookupCounter) {
+ TDynamicCounterPtr rootGroup(new TDynamicCounters());
+ TDynamicCounters::TCounterPtr lookups = rootGroup->GetCounter("Lookups", true);
+ rootGroup->SetLookupCounter(lookups);
+
+ // Create subtree and check that counter is inherited
+ TDynamicCounterPtr serviceGroup = rootGroup->GetSubgroup("service", "MyService");
+ UNIT_ASSERT_VALUES_EQUAL(lookups->Val(), 1);
+
+ TDynamicCounterPtr subGroup = serviceGroup->GetSubgroup("component", "MyComponent");
+ UNIT_ASSERT_VALUES_EQUAL(lookups->Val(), 2);
+
+ auto counter = subGroup->GetNamedCounter("range", "20 msec", true);
+ UNIT_ASSERT_VALUES_EQUAL(lookups->Val(), 3);
+
+ auto hist = subGroup->GetHistogram("timeMsec", ExponentialHistogram(4, 2));
+ UNIT_ASSERT_VALUES_EQUAL(lookups->Val(), 4);
+
+ // Replace the counter for subGroup
+ auto subGroupLookups = rootGroup->GetCounter("LookupsInMyComponent", true);
+ UNIT_ASSERT_VALUES_EQUAL(lookups->Val(), 5);
+ subGroup->SetLookupCounter(subGroupLookups);
+ auto counter2 = subGroup->GetNamedCounter("range", "30 msec", true);
+ UNIT_ASSERT_VALUES_EQUAL(subGroupLookups->Val(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(lookups->Val(), 5);
+ }
+
+ Y_UNIT_TEST(FindCounters) {
+ TDynamicCounterPtr rootGroup(new TDynamicCounters());
+
+ auto counter = rootGroup->FindCounter("counter1");
+ UNIT_ASSERT(!counter);
+ rootGroup->GetCounter("counter1");
+ counter = rootGroup->FindCounter("counter1");
+ UNIT_ASSERT(counter);
+
+ counter = rootGroup->FindNamedCounter("name", "counter2");
+ UNIT_ASSERT(!counter);
+ rootGroup->GetNamedCounter("name", "counter2");
+ counter = rootGroup->FindNamedCounter("name", "counter2");
+ UNIT_ASSERT(counter);
+
+ auto histogram = rootGroup->FindHistogram("histogram1");
+ UNIT_ASSERT(!histogram);
+ rootGroup->GetHistogram("histogram1", ExponentialHistogram(4, 2));
+ histogram = rootGroup->FindHistogram("histogram1");
+ UNIT_ASSERT(histogram);
+
+ histogram = rootGroup->FindNamedHistogram("name", "histogram2");
+ UNIT_ASSERT(!histogram);
+ rootGroup->GetNamedHistogram("name", "histogram2", ExponentialHistogram(4, 2));
+ histogram = rootGroup->FindNamedHistogram("name", "histogram2");
+ UNIT_ASSERT(histogram);
+ }
+}
diff --git a/library/cpp/monlib/dynamic_counters/encode.cpp b/library/cpp/monlib/dynamic_counters/encode.cpp
new file mode 100644
index 0000000000..ffa48d276e
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/encode.cpp
@@ -0,0 +1,131 @@
+#include "encode.h"
+
+#include <library/cpp/monlib/encode/encoder.h>
+#include <library/cpp/monlib/encode/json/json.h>
+#include <library/cpp/monlib/encode/spack/spack_v1.h>
+#include <library/cpp/monlib/encode/prometheus/prometheus.h>
+
+#include <util/stream/str.h>
+
+namespace NMonitoring {
+ namespace {
+ constexpr TInstant ZERO_TIME = TInstant::Zero();
+
+ class TConsumer final: public ICountableConsumer {
+ using TLabel = std::pair<TString, TString>; // name, value
+
+ public:
+ explicit TConsumer(NMonitoring::IMetricEncoderPtr encoderImpl, TCountableBase::EVisibility vis)
+ : EncoderImpl_(std::move(encoderImpl))
+ , Visibility_{vis}
+ {
+ }
+
+ void OnCounter(
+ const TString& labelName, const TString& labelValue,
+ const TCounterForPtr* counter) override {
+ NMonitoring::EMetricType metricType = counter->ForDerivative()
+ ? NMonitoring::EMetricType::RATE
+ : NMonitoring::EMetricType::GAUGE;
+ EncoderImpl_->OnMetricBegin(metricType);
+ EncodeLabels(labelName, labelValue);
+
+ if (metricType == NMonitoring::EMetricType::GAUGE) {
+ EncoderImpl_->OnDouble(ZERO_TIME, static_cast<double>(counter->Val()));
+ } else {
+ EncoderImpl_->OnUint64(ZERO_TIME, counter->Val());
+ }
+
+ EncoderImpl_->OnMetricEnd();
+ }
+
+ void OnHistogram(
+ const TString& labelName, const TString& labelValue,
+ IHistogramSnapshotPtr snapshot, bool derivative) override {
+ NMonitoring::EMetricType metricType = derivative ? EMetricType::HIST_RATE : EMetricType::HIST;
+
+ EncoderImpl_->OnMetricBegin(metricType);
+ EncodeLabels(labelName, labelValue);
+ EncoderImpl_->OnHistogram(ZERO_TIME, snapshot);
+ EncoderImpl_->OnMetricEnd();
+ }
+
+ void OnGroupBegin(
+ const TString& labelName, const TString& labelValue,
+ const TDynamicCounters*) override {
+ if (labelName.empty() && labelValue.empty()) {
+ // root group has empty label name and value
+ EncoderImpl_->OnStreamBegin();
+ } else {
+ ParentLabels_.emplace_back(labelName, labelValue);
+ }
+ }
+
+ void OnGroupEnd(
+ const TString& labelName, const TString& labelValue,
+ const TDynamicCounters*) override {
+ if (labelName.empty() && labelValue.empty()) {
+ // root group has empty label name and value
+ EncoderImpl_->OnStreamEnd();
+ EncoderImpl_->Close();
+ } else {
+ ParentLabels_.pop_back();
+ }
+ }
+
+ TCountableBase::EVisibility Visibility() const override {
+ return Visibility_;
+ }
+
+ private:
+ void EncodeLabels(const TString& labelName, const TString& labelValue) {
+ EncoderImpl_->OnLabelsBegin();
+ for (const auto& label : ParentLabels_) {
+ EncoderImpl_->OnLabel(label.first, label.second);
+ }
+ EncoderImpl_->OnLabel(labelName, labelValue);
+ EncoderImpl_->OnLabelsEnd();
+ }
+
+ private:
+ NMonitoring::IMetricEncoderPtr EncoderImpl_;
+ TVector<TLabel> ParentLabels_;
+ TCountableBase::EVisibility Visibility_;
+ };
+
+ }
+
+ THolder<ICountableConsumer> CreateEncoder(IOutputStream* out, EFormat format, TCountableBase::EVisibility vis) {
+ switch (format) {
+ case EFormat::JSON:
+ return MakeHolder<TConsumer>(NMonitoring::EncoderJson(out), vis);
+ case EFormat::SPACK:
+ return MakeHolder<TConsumer>(NMonitoring::EncoderSpackV1(
+ out,
+ NMonitoring::ETimePrecision::SECONDS,
+ NMonitoring::ECompression::ZSTD), vis);
+ case EFormat::PROMETHEUS:
+ return MakeHolder<TConsumer>(NMonitoring::EncoderPrometheus(
+ out), vis);
+ default:
+ ythrow yexception() << "unsupported metric encoding format: " << format;
+ break;
+ }
+ }
+
+ THolder<ICountableConsumer> AsCountableConsumer(IMetricEncoderPtr encoder, TCountableBase::EVisibility visibility) {
+ return MakeHolder<TConsumer>(std::move(encoder), visibility);
+ }
+
+ void ToJson(const TDynamicCounters& counters, IOutputStream* out) {
+ TConsumer consumer{EncoderJson(out), TCountableBase::EVisibility::Public};
+ counters.Accept(TString{}, TString{}, consumer);
+ }
+
+ TString ToJson(const TDynamicCounters& counters) {
+ TStringStream ss;
+ ToJson(counters, &ss);
+ return ss.Str();
+ }
+
+}
diff --git a/library/cpp/monlib/dynamic_counters/encode.h b/library/cpp/monlib/dynamic_counters/encode.h
new file mode 100644
index 0000000000..c79964d7cb
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/encode.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "counters.h"
+
+#include <library/cpp/monlib/encode/encoder.h>
+#include <library/cpp/monlib/encode/format.h>
+
+namespace NMonitoring {
+
+ THolder<ICountableConsumer> CreateEncoder(
+ IOutputStream* out,
+ EFormat format,
+ TCountableBase::EVisibility visibility = TCountableBase::EVisibility::Public
+ );
+
+ THolder<ICountableConsumer> AsCountableConsumer(
+ NMonitoring::IMetricEncoderPtr encoder,
+ TCountableBase::EVisibility visibility = TCountableBase::EVisibility::Public);
+
+ void ToJson(const TDynamicCounters& counters, IOutputStream* out);
+
+ TString ToJson(const TDynamicCounters& counters);
+}
diff --git a/library/cpp/monlib/dynamic_counters/encode_ut.cpp b/library/cpp/monlib/dynamic_counters/encode_ut.cpp
new file mode 100644
index 0000000000..52d77b6b41
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/encode_ut.cpp
@@ -0,0 +1,226 @@
+#include "encode.h"
+
+#include <library/cpp/monlib/encode/json/json.h>
+#include <library/cpp/monlib/encode/spack/spack_v1.h>
+#include <library/cpp/monlib/encode/protobuf/protobuf.h>
+
+#include <library/cpp/monlib/encode/protobuf/protos/samples.pb.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/buffer.h>
+#include <util/stream/buffer.h>
+
+namespace NMonitoring {
+ struct TTestData: public TDynamicCounters {
+ TTestData() {
+ auto hostGroup = GetSubgroup("counters", "resources");
+ {
+ auto cpuCounter = hostGroup->GetNamedCounter("resource", "cpu");
+ *cpuCounter = 30;
+
+ auto memGroup = hostGroup->GetSubgroup("resource", "mem");
+ auto usedCounter = memGroup->GetCounter("used");
+ auto freeCounter = memGroup->GetCounter("free");
+ *usedCounter = 100;
+ *freeCounter = 28;
+
+ auto netGroup = hostGroup->GetSubgroup("resource", "net");
+ auto rxCounter = netGroup->GetCounter("rx", true);
+ auto txCounter = netGroup->GetCounter("tx", true);
+ *rxCounter = 8;
+ *txCounter = 9;
+ }
+
+ auto usersCounter = GetNamedCounter("users", "count");
+ *usersCounter = 7;
+
+ auto responseTimeMillis = GetHistogram("responseTimeMillis", ExplicitHistogram({1, 5, 10, 15, 20, 100, 200}));
+ for (i64 i = 0; i < 400; i++) {
+ responseTimeMillis->Collect(i);
+ }
+ }
+ };
+
+ void AssertLabelsEqual(const NProto::TLabel& l, TStringBuf name, TStringBuf value) {
+ UNIT_ASSERT_STRINGS_EQUAL(l.GetName(), name);
+ UNIT_ASSERT_STRINGS_EQUAL(l.GetValue(), value);
+ }
+
+ void AssertResult(const NProto::TSingleSamplesList& samples) {
+ UNIT_ASSERT_VALUES_EQUAL(samples.SamplesSize(), 7);
+
+ {
+ auto s = samples.GetSamples(0);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 2);
+ AssertLabelsEqual(s.GetLabels(0), "counters", "resources");
+ AssertLabelsEqual(s.GetLabels(1), "resource", "cpu");
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_DOUBLES_EQUAL(s.GetFloat64(), 30.0, Min<double>());
+ }
+ {
+ auto s = samples.GetSamples(1);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 3);
+ AssertLabelsEqual(s.GetLabels(0), "counters", "resources");
+ AssertLabelsEqual(s.GetLabels(1), "resource", "mem");
+ AssertLabelsEqual(s.GetLabels(2), "sensor", "free");
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_DOUBLES_EQUAL(s.GetFloat64(), 28.0, Min<double>());
+ }
+ {
+ auto s = samples.GetSamples(2);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 3);
+ AssertLabelsEqual(s.GetLabels(0), "counters", "resources");
+ AssertLabelsEqual(s.GetLabels(1), "resource", "mem");
+ AssertLabelsEqual(s.GetLabels(2), "sensor", "used");
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_DOUBLES_EQUAL(s.GetFloat64(), 100.0, Min<double>());
+ }
+ {
+ auto s = samples.GetSamples(3);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 3);
+ AssertLabelsEqual(s.GetLabels(0), "counters", "resources");
+ AssertLabelsEqual(s.GetLabels(1), "resource", "net");
+ AssertLabelsEqual(s.GetLabels(2), "sensor", "rx");
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::RATE);
+ UNIT_ASSERT_VALUES_EQUAL(s.GetUint64(), 8);
+ }
+ {
+ auto s = samples.GetSamples(4);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 3);
+ AssertLabelsEqual(s.GetLabels(0), "counters", "resources");
+ AssertLabelsEqual(s.GetLabels(1), "resource", "net");
+ AssertLabelsEqual(s.GetLabels(2), "sensor", "tx");
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::RATE);
+ UNIT_ASSERT_VALUES_EQUAL(s.GetUint64(), 9);
+ }
+ {
+ auto s = samples.GetSamples(5);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelsEqual(s.GetLabels(0), "sensor", "responseTimeMillis");
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::HIST_RATE);
+
+ const NProto::THistogram& h = s.GetHistogram();
+
+ UNIT_ASSERT_EQUAL(h.BoundsSize(), 8);
+ UNIT_ASSERT_DOUBLES_EQUAL(h.GetBounds(0), 1, Min<double>());
+ UNIT_ASSERT_DOUBLES_EQUAL(h.GetBounds(1), 5, Min<double>());
+ UNIT_ASSERT_DOUBLES_EQUAL(h.GetBounds(2), 10, Min<double>());
+ UNIT_ASSERT_DOUBLES_EQUAL(h.GetBounds(3), 15, Min<double>());
+ UNIT_ASSERT_DOUBLES_EQUAL(h.GetBounds(4), 20, Min<double>());
+ UNIT_ASSERT_DOUBLES_EQUAL(h.GetBounds(5), 100, Min<double>());
+ UNIT_ASSERT_DOUBLES_EQUAL(h.GetBounds(6), 200, Min<double>());
+ UNIT_ASSERT_DOUBLES_EQUAL(h.GetBounds(7), Max<double>(), Min<double>());
+
+ UNIT_ASSERT_EQUAL(h.ValuesSize(), 8);
+ UNIT_ASSERT_EQUAL(h.GetValues(0), 2);
+ UNIT_ASSERT_EQUAL(h.GetValues(1), 4);
+ UNIT_ASSERT_EQUAL(h.GetValues(2), 5);
+ UNIT_ASSERT_EQUAL(h.GetValues(3), 5);
+ UNIT_ASSERT_EQUAL(h.GetValues(4), 5);
+ UNIT_ASSERT_EQUAL(h.GetValues(5), 80);
+ UNIT_ASSERT_EQUAL(h.GetValues(6), 100);
+ UNIT_ASSERT_EQUAL(h.GetValues(7), 199);
+ }
+ {
+ auto s = samples.GetSamples(6);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelsEqual(s.GetLabels(0), "users", "count");
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_DOUBLES_EQUAL(s.GetFloat64(), 7, Min<double>());
+ }
+ }
+
+ Y_UNIT_TEST_SUITE(TDynamicCountersEncodeTest) {
+ TTestData Data;
+
+ Y_UNIT_TEST(Json) {
+ TString result;
+ {
+ TStringOutput out(result);
+ auto encoder = CreateEncoder(&out, EFormat::JSON);
+ Data.Accept(TString(), TString(), *encoder);
+ }
+
+ NProto::TSingleSamplesList samples;
+ {
+ auto e = EncoderProtobuf(&samples);
+ DecodeJson(result, e.Get());
+ }
+
+ AssertResult(samples);
+ }
+
+ Y_UNIT_TEST(Spack) {
+ TBuffer result;
+ {
+ TBufferOutput out(result);
+ auto encoder = CreateEncoder(&out, EFormat::SPACK);
+ Data.Accept(TString(), TString(), *encoder);
+ }
+
+ NProto::TSingleSamplesList samples;
+ {
+ auto e = EncoderProtobuf(&samples);
+ TBufferInput in(result);
+ DecodeSpackV1(&in, e.Get());
+ }
+
+ AssertResult(samples);
+ }
+
+ Y_UNIT_TEST(PrivateSubgroupIsNotSerialized) {
+ TBuffer result;
+ auto subGroup = MakeIntrusive<TDynamicCounters>(TCountableBase::EVisibility::Private);
+ subGroup->GetCounter("hello");
+ Data.RegisterSubgroup("foo", "bar", subGroup);
+
+ {
+ TBufferOutput out(result);
+ auto encoder = CreateEncoder(&out, EFormat::SPACK);
+ Data.Accept(TString(), TString(), *encoder);
+ }
+
+ NProto::TSingleSamplesList samples;
+ {
+ auto e = EncoderProtobuf(&samples);
+ TBufferInput in(result);
+ DecodeSpackV1(&in, e.Get());
+ }
+
+ AssertResult(samples);
+ }
+
+ Y_UNIT_TEST(PrivateCounterIsNotSerialized) {
+ TBuffer result;
+ Data.GetCounter("foo", false, TCountableBase::EVisibility::Private);
+
+ {
+ TBufferOutput out(result);
+ auto encoder = CreateEncoder(&out, EFormat::SPACK);
+ Data.Accept(TString(), TString(), *encoder);
+ }
+
+ NProto::TSingleSamplesList samples;
+ {
+ auto e = EncoderProtobuf(&samples);
+ TBufferInput in(result);
+ DecodeSpackV1(&in, e.Get());
+ }
+
+ AssertResult(samples);
+ }
+
+ Y_UNIT_TEST(ToJson) {
+ TString result = ToJson(Data);
+
+ NProto::TSingleSamplesList samples;
+ {
+ auto e = EncoderProtobuf(&samples);
+ DecodeJson(result, e.Get());
+ }
+
+ AssertResult(samples);
+ }
+ }
+
+}
diff --git a/library/cpp/monlib/dynamic_counters/golovan_page.cpp b/library/cpp/monlib/dynamic_counters/golovan_page.cpp
new file mode 100644
index 0000000000..49cf2d39bb
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/golovan_page.cpp
@@ -0,0 +1,79 @@
+#include "golovan_page.h"
+
+#include <library/cpp/monlib/service/pages/templates.h>
+
+#include <util/string/split.h>
+#include <util/system/tls.h>
+
+using namespace NMonitoring;
+
+class TGolovanCountableConsumer: public ICountableConsumer {
+public:
+ using TOutputCallback = std::function<void()>;
+
+ TGolovanCountableConsumer(IOutputStream& out, TOutputCallback& OutputCallback)
+ : out(out)
+ {
+ if (OutputCallback) {
+ OutputCallback();
+ }
+
+ out << HTTPOKJSON << "[";
+ FirstCounter = true;
+ }
+
+ void OnCounter(const TString&, const TString& value, const TCounterForPtr* counter) override {
+ if (FirstCounter) {
+ FirstCounter = false;
+ } else {
+ out << ",";
+ }
+
+ out << "[\"" << prefix + value;
+ if (counter->ForDerivative()) {
+ out << "_dmmm";
+ } else {
+ out << "_ahhh";
+ }
+
+ out << "\"," << counter->Val() << "]";
+ }
+
+ void OnHistogram(const TString&, const TString&, IHistogramSnapshotPtr, bool) override {
+ }
+
+ void OnGroupBegin(const TString&, const TString& value, const TDynamicCounters*) override {
+ prefix += value;
+ if (!value.empty()) {
+ prefix += "_";
+ }
+ }
+
+ void OnGroupEnd(const TString&, const TString&, const TDynamicCounters*) override {
+ prefix = "";
+ }
+
+ void Flush() {
+ out << "]";
+ out.Flush();
+ }
+
+private:
+ IOutputStream& out;
+ bool FirstCounter;
+ TString prefix;
+};
+
+TGolovanCountersPage::TGolovanCountersPage(const TString& path, TIntrusivePtr<NMonitoring::TDynamicCounters> counters,
+ TOutputCallback outputCallback)
+ : IMonPage(path)
+ , Counters(counters)
+ , OutputCallback(outputCallback)
+{
+}
+
+void TGolovanCountersPage::Output(IMonHttpRequest& request) {
+ TGolovanCountableConsumer consumer(request.Output(), OutputCallback);
+ Counters->Accept("", "", consumer);
+ consumer.Flush();
+}
diff --git a/library/cpp/monlib/dynamic_counters/golovan_page.h b/library/cpp/monlib/dynamic_counters/golovan_page.h
new file mode 100644
index 0000000000..e1772c7734
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/golovan_page.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "counters.h"
+
+#include <library/cpp/monlib/service/pages/mon_page.h>
+
+#include <util/generic/ptr.h>
+
+#include <functional>
+
+// helper class to output json for Golovan.
+class TGolovanCountersPage: public NMonitoring::IMonPage {
+public:
+ using TOutputCallback = std::function<void()>;
+
+ const TIntrusivePtr<NMonitoring::TDynamicCounters> Counters;
+
+ TGolovanCountersPage(const TString& path, TIntrusivePtr<NMonitoring::TDynamicCounters> counters,
+ TOutputCallback outputCallback = nullptr);
+
+ void Output(NMonitoring::IMonHttpRequest& request) override;
+
+private:
+ TOutputCallback OutputCallback;
+};
diff --git a/library/cpp/monlib/dynamic_counters/page.cpp b/library/cpp/monlib/dynamic_counters/page.cpp
new file mode 100644
index 0000000000..5124a47bb3
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/page.cpp
@@ -0,0 +1,141 @@
+#include "page.h"
+#include "encode.h"
+
+#include <library/cpp/monlib/service/pages/templates.h>
+#include <library/cpp/string_utils/quote/quote.h>
+
+#include <util/string/split.h>
+#include <util/system/tls.h>
+
+using namespace NMonitoring;
+
+namespace {
+ Y_POD_STATIC_THREAD(TDynamicCounters*)
+ currentCounters(nullptr);
+}
+
+TMaybe<EFormat> ParseFormat(TStringBuf str) {
+ if (str == TStringBuf("json")) {
+ return EFormat::JSON;
+ } else if (str == TStringBuf("spack")) {
+ return EFormat::SPACK;
+ } else if (str == TStringBuf("prometheus")) {
+ return EFormat::PROMETHEUS;
+ } else {
+ return Nothing();
+ }
+}
+
+void TDynamicCountersPage::Output(NMonitoring::IMonHttpRequest& request) {
+ if (OutputCallback) {
+ OutputCallback();
+ }
+
+ TCountableBase::EVisibility visibility{
+ TCountableBase::EVisibility::Public
+ };
+
+ TVector<TStringBuf> parts;
+ StringSplitter(request.GetPathInfo())
+ .Split('/')
+ .SkipEmpty()
+ .Collect(&parts);
+
+ TMaybe<EFormat> format = !parts.empty() ? ParseFormat(parts.back()) : Nothing();
+ if (format) {
+ parts.pop_back();
+ }
+
+ if (!parts.empty() && parts.back() == TStringBuf("private")) {
+ visibility = TCountableBase::EVisibility::Private;
+ parts.pop_back();
+ }
+
+ auto counters = Counters;
+
+ for (const auto& escaped : parts) {
+ const auto part = CGIUnescapeRet(escaped);
+
+ TVector<TString> labels;
+ StringSplitter(part).Split('=').SkipEmpty().Collect(&labels);
+
+ if (labels.size() != 2U)
+ return NotFound(request);
+
+ if (const auto child = counters->FindSubgroup(
+ labels.front(),
+ labels.back())) {
+
+ counters = child;
+ } else {
+ return HandleAbsentSubgroup(request);
+ }
+ }
+
+ if (!format) {
+ currentCounters = counters.Get();
+ THtmlMonPage::Output(request);
+ currentCounters = nullptr;
+ return;
+ }
+
+ IOutputStream& out = request.Output();
+ if (*format == EFormat::JSON) {
+ out << HTTPOKJSON;
+ } else if (*format == EFormat::SPACK) {
+ out << HTTPOKSPACK;
+ } else if (*format == EFormat::PROMETHEUS) {
+ out << HTTPOKPROMETHEUS;
+ } else {
+ ythrow yexception() << "unsupported metric encoding format: " << *format;
+ }
+
+ auto encoder = CreateEncoder(&out, *format, visibility);
+ counters->Accept(TString(), TString(), *encoder);
+ out.Flush();
+}
+
+void TDynamicCountersPage::HandleAbsentSubgroup(IMonHttpRequest& request) {
+ if (UnknownGroupPolicy == EUnknownGroupPolicy::Error) {
+ NotFound(request);
+ } else if (UnknownGroupPolicy == EUnknownGroupPolicy::Ignore) {
+ NoContent(request);
+ } else {
+ Y_FAIL("Unsupported policy set");
+ }
+}
+
+void TDynamicCountersPage::BeforePre(IMonHttpRequest& request) {
+ IOutputStream& out = request.Output();
+ HTML(out) {
+ DIV() {
+ out << "<a href='" << request.GetPath() << "/json'>Counters as JSON</a>";
+ out << " for <a href='https://wiki.yandex-team.ru/solomon/'>Solomon</a>";
+ }
+
+ H5() {
+ out << "Counters subgroups";
+ }
+ UL() {
+ currentCounters->EnumerateSubgroups([&](const TString& name, const TString& value) {
+ LI() {
+ TString pathPart = name + "=" + value;
+ Quote(pathPart, "");
+ out << "\n<a href='" << request.GetPath() << "/" << pathPart << "'>" << name << " " << value << "</a>";
+ }
+ });
+ }
+
+ H4() {
+ out << "Counters as text";
+ }
+ }
+}
+
+void TDynamicCountersPage::OutputText(IOutputStream& out, IMonHttpRequest&) {
+ currentCounters->OutputPlainText(out);
+}
+
+void TDynamicCountersPage::SetUnknownGroupPolicy(EUnknownGroupPolicy value) {
+ UnknownGroupPolicy = value;
+}
diff --git a/library/cpp/monlib/dynamic_counters/page.h b/library/cpp/monlib/dynamic_counters/page.h
new file mode 100644
index 0000000000..1f0ef6a5ea
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/page.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include "counters.h"
+
+#include <library/cpp/monlib/service/pages/pre_mon_page.h>
+
+#include <util/generic/ptr.h>
+
+#include <functional>
+
+namespace NMonitoring {
+ enum class EUnknownGroupPolicy {
+ Error, // send 404
+ Ignore, // send 204
+ };
+
+ struct TDynamicCountersPage: public TPreMonPage {
+ public:
+ using TOutputCallback = std::function<void()>;
+
+ private:
+ const TIntrusivePtr<TDynamicCounters> Counters;
+ TOutputCallback OutputCallback;
+ EUnknownGroupPolicy UnknownGroupPolicy {EUnknownGroupPolicy::Error};
+
+ private:
+ void HandleAbsentSubgroup(IMonHttpRequest& request);
+
+ public:
+ TDynamicCountersPage(const TString& path,
+ const TString& title,
+ TIntrusivePtr<TDynamicCounters> counters,
+ TOutputCallback outputCallback = nullptr)
+ : TPreMonPage(path, title)
+ , Counters(counters)
+ , OutputCallback(outputCallback)
+ {
+ }
+
+ void Output(NMonitoring::IMonHttpRequest& request) override;
+
+ void BeforePre(NMonitoring::IMonHttpRequest& request) override;
+
+ void OutputText(IOutputStream& out, NMonitoring::IMonHttpRequest&) override;
+
+ /// If set to Error, responds with 404 if the requested subgroup is not found. This is the default.
+ /// If set to Ignore, responds with 204 if the requested subgroup is not found
+ void SetUnknownGroupPolicy(EUnknownGroupPolicy value);
+ };
+}
diff --git a/library/cpp/monlib/dynamic_counters/percentile/percentile.h b/library/cpp/monlib/dynamic_counters/percentile/percentile.h
new file mode 100644
index 0000000000..73c482bce9
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/percentile/percentile.h
@@ -0,0 +1,59 @@
+#pragma once
+
+#include "percentile_base.h"
+
+namespace NMonitoring {
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Percentile tracker for monitoring
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+template <size_t BUCKET_SIZE, size_t BUCKET_COUNT, size_t FRAME_COUNT>
+struct TPercentileTracker : public TPercentileBase {
+ TAtomic Items[BUCKET_COUNT];
+ TAtomicBase Frame[FRAME_COUNT][BUCKET_COUNT];
+ size_t CurrentFrame;
+
+ TPercentileTracker()
+ : CurrentFrame(0)
+ {
+ for (size_t i = 0; i < BUCKET_COUNT; ++i) {
+ AtomicSet(Items[i], 0);
+ }
+ for (size_t frame = 0; frame < FRAME_COUNT; ++frame) {
+ for (size_t bucket = 0; bucket < BUCKET_COUNT; ++bucket) {
+ Frame[frame][bucket] = 0;
+ }
+ }
+ }
+
+ void Increment(size_t value) {
+ AtomicIncrement(Items[Min((value + BUCKET_SIZE - 1) / BUCKET_SIZE, BUCKET_COUNT - 1)]);
+ }
+
+ // shift frame (call periodically)
+ void Update() {
+ TVector<TAtomicBase> totals(BUCKET_COUNT);
+ totals.resize(BUCKET_COUNT);
+ TAtomicBase total = 0;
+ for (size_t i = 0; i < BUCKET_COUNT; ++i) {
+ TAtomicBase item = AtomicGet(Items[i]);
+ TAtomicBase prevItem = Frame[CurrentFrame][i];
+ Frame[CurrentFrame][i] = item;
+ total += item - prevItem;
+ totals[i] = total;
+ }
+
+ for (size_t i = 0; i < Percentiles.size(); ++i) {
+ TPercentile &percentile = Percentiles[i];
+ auto threshold = (TAtomicBase)(percentile.first * (float)total);
+ threshold = Min(threshold, total);
+ auto it = LowerBound(totals.begin(), totals.end(), threshold);
+ size_t index = it - totals.begin();
+ (*percentile.second) = index * BUCKET_SIZE;
+ }
+ CurrentFrame = (CurrentFrame + 1) % FRAME_COUNT;
+ }
+};
+
+} // NMonitoring
diff --git a/library/cpp/monlib/dynamic_counters/percentile/percentile_base.h b/library/cpp/monlib/dynamic_counters/percentile/percentile_base.h
new file mode 100644
index 0000000000..d3c825c43d
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/percentile/percentile_base.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <library/cpp/monlib/dynamic_counters/counters.h>
+
+#include <util/string/printf.h>
+
+namespace NMonitoring {
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Percentile tracker for monitoring
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+struct TPercentileBase : public TThrRefBase {
+ using TPercentile = std::pair<float, NMonitoring::TDynamicCounters::TCounterPtr>;
+ using TPercentiles = TVector<TPercentile>;
+
+ TPercentiles Percentiles;
+
+ void Initialize(const TIntrusivePtr<NMonitoring::TDynamicCounters> &counters, const TVector<float> &thresholds,
+ TCountableBase::EVisibility visibility = TCountableBase::EVisibility::Public) {
+ Percentiles.reserve(thresholds.size());
+ for (size_t i = 0; i < thresholds.size(); ++i) {
+ Percentiles.emplace_back(thresholds[i],
+ counters->GetNamedCounter("percentile", Sprintf("%.1f", thresholds[i] * 100.f), false, visibility));
+ }
+ }
+
+ void Initialize(const TIntrusivePtr<NMonitoring::TDynamicCounters> &counters, TString group, TString subgroup,
+ TString name, const TVector<float> &thresholds,
+ TCountableBase::EVisibility visibility = TCountableBase::EVisibility::Public) {
+ auto subCounters = counters->GetSubgroup(group, subgroup)->GetSubgroup("sensor", name);
+ Initialize(subCounters, thresholds, visibility);
+ }
+};
+
+} // NMonitoring
diff --git a/library/cpp/monlib/dynamic_counters/percentile/percentile_lg.h b/library/cpp/monlib/dynamic_counters/percentile/percentile_lg.h
new file mode 100644
index 0000000000..0042cd9a6a
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/percentile/percentile_lg.h
@@ -0,0 +1,182 @@
+#pragma once
+
+#include <library/cpp/containers/stack_vector/stack_vec.h>
+
+#include <util/generic/bitops.h>
+
+#include <cmath>
+
+#include "percentile_base.h"
+
+namespace NMonitoring {
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Percentile tracker for monitoring
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+template <size_t BASE_BITS, size_t EXP_BITS, size_t FRAME_COUNT>
+struct TPercentileTrackerLg : public TPercentileBase {
+ static constexpr size_t BUCKET_COUNT = size_t(1) << EXP_BITS;
+ static constexpr size_t BUCKET_SIZE = size_t(1) << BASE_BITS;
+ static constexpr size_t ITEMS_COUNT = BUCKET_COUNT * BUCKET_SIZE;
+ static constexpr size_t TRACKER_LIMIT = BUCKET_SIZE * ((size_t(1) << BUCKET_COUNT) - 1)
+ - (size_t(1) << (BUCKET_COUNT - 1));
+ static constexpr size_t MAX_GRANULARITY = size_t(1) << (BUCKET_COUNT - 1);
+
+ size_t Borders[BUCKET_COUNT];
+ TAtomic Items[ITEMS_COUNT];
+ TAtomicBase Frame[FRAME_COUNT][ITEMS_COUNT];
+ size_t CurrentFrame;
+
+ TPercentileTrackerLg()
+ : CurrentFrame(0)
+ {
+ Borders[0] = 0;
+ for (size_t i = 1; i < BUCKET_COUNT; ++i) {
+ Borders[i] = Borders[i-1] + (BUCKET_SIZE << (i - 1));
+ }
+ for (size_t i = 0; i < ITEMS_COUNT; ++i) {
+ AtomicSet(Items[i], 0);
+ }
+ for (size_t frame = 0; frame < FRAME_COUNT; ++frame) {
+ for (size_t bucket = 0; bucket < ITEMS_COUNT; ++bucket) {
+ Frame[frame][bucket] = 0;
+ }
+ }
+ }
+
+ size_t inline BucketIdxIf(size_t value) {
+ static_assert(BASE_BITS == 5, "if-based bucket calculation cannot be used if BASE_BITS != 5");
+ size_t bucket_idx;
+ if (value < 8160) {
+ if (value < 480) {
+ if (value < 96) {
+ if (value < 32) {
+ bucket_idx = 0;
+ } else {
+ bucket_idx = 1;
+ }
+ } else {
+ if (value < 224) {
+ bucket_idx = 2;
+ } else {
+ bucket_idx = 3;
+ }
+ }
+ } else {
+ if (value < 2016) {
+ if (value < 992) {
+ bucket_idx = 4;
+ } else {
+ bucket_idx = 5;
+ }
+ } else {
+ if (value < 4064) {
+ bucket_idx = 6;
+ } else {
+ bucket_idx = 7;
+ }
+ }
+ }
+ } else {
+ if (value < 131040) {
+ if (value < 32736) {
+ if (value < 16352) {
+ bucket_idx = 8;
+ } else {
+ bucket_idx = 9;
+ }
+ } else {
+ if (value < 65504) {
+ bucket_idx = 10;
+ } else {
+ bucket_idx = 11;
+ }
+ }
+ } else {
+ if (value < 524256) {
+ if (value < 262112) {
+ bucket_idx = 12;
+ } else {
+ bucket_idx = 13;
+ }
+ } else {
+ if (value < 1048544) {
+ bucket_idx = 14;
+ } else {
+ bucket_idx = 15;
+ }
+ }
+ }
+ }
+ return Min(bucket_idx, BUCKET_COUNT - 1);
+ }
+
+ size_t inline BucketIdxBinarySearch(size_t value) {
+ size_t l = 0;
+ size_t r = BUCKET_COUNT;
+ while (l < r - 1) {
+ size_t mid = (l + r) / 2;
+ if (value < Borders[mid]) {
+ r = mid;
+ } else {
+ l = mid;
+ }
+ }
+ return l;
+ }
+
+ size_t inline BucketIdxMostSignificantBit(size_t value) {
+ size_t bucket_idx = MostSignificantBit(value + BUCKET_SIZE) - BASE_BITS;
+ return Min(bucket_idx, BUCKET_COUNT - 1);
+ }
+
+ void Increment(size_t value) {
+ size_t bucket_idx = BucketIdxMostSignificantBit(value);
+ size_t inside_bucket_idx = (value - Borders[bucket_idx] + (1 << bucket_idx) - 1) >> bucket_idx;
+ size_t idx = bucket_idx * BUCKET_SIZE + inside_bucket_idx;
+ AtomicIncrement(Items[Min(idx, ITEMS_COUNT - 1)]);
+ }
+
+ // Needed only for tests
+ size_t GetPercentile(float threshold) {
+ TStackVec<TAtomicBase, ITEMS_COUNT> totals(ITEMS_COUNT);
+ TAtomicBase total = 0;
+ for (size_t i = 0; i < ITEMS_COUNT; ++i) {
+ total += AtomicGet(Items[i]);
+ totals[i] = total;
+ }
+ TAtomicBase item_threshold = std::llround(threshold * (float)total);
+ item_threshold = Min(item_threshold, total);
+ auto it = LowerBound(totals.begin(), totals.end(), item_threshold);
+ size_t index = it - totals.begin();
+ size_t bucket_idx = index / BUCKET_SIZE;
+ return Borders[bucket_idx] + ((index % BUCKET_SIZE) << bucket_idx);
+ }
+
+ // shift frame (call periodically)
+ void Update() {
+ TStackVec<TAtomicBase, ITEMS_COUNT> totals(ITEMS_COUNT);
+ TAtomicBase total = 0;
+ for (size_t i = 0; i < ITEMS_COUNT; ++i) {
+ TAtomicBase item = AtomicGet(Items[i]);
+ TAtomicBase prevItem = Frame[CurrentFrame][i];
+ Frame[CurrentFrame][i] = item;
+ total += item - prevItem;
+ totals[i] = total;
+ }
+
+ for (size_t i = 0; i < Percentiles.size(); ++i) {
+ TPercentile &percentile = Percentiles[i];
+ TAtomicBase threshold = std::llround(percentile.first * (float)total);
+ threshold = Min(threshold, total);
+ auto it = LowerBound(totals.begin(), totals.end(), threshold);
+ size_t index = it - totals.begin();
+ size_t bucket_idx = index / BUCKET_SIZE;
+ (*percentile.second) = Borders[bucket_idx] + ((index % BUCKET_SIZE) << bucket_idx);
+ }
+ CurrentFrame = (CurrentFrame + 1) % FRAME_COUNT;
+ }
+};
+
+} // NMonitoring
diff --git a/library/cpp/monlib/dynamic_counters/percentile/percentile_ut.cpp b/library/cpp/monlib/dynamic_counters/percentile/percentile_ut.cpp
new file mode 100644
index 0000000000..6c8bb54ec9
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/percentile/percentile_ut.cpp
@@ -0,0 +1,129 @@
+#include "percentile_lg.h"
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NMonitoring;
+
+Y_UNIT_TEST_SUITE(PercentileTest) {
+
+template<size_t A, size_t B, size_t B_BEGIN>
+void printSizeAndLimit() {
+ using TPerc = TPercentileTrackerLg<A, B, 15>;
+ Cout << "TPercentileTrackerLg<" << A << ", " << B << ", 15>"
+ << "; sizeof# " << LeftPad(HumanReadableSize(sizeof(TPerc), SF_BYTES), 7)
+ << "; max_granularity# " << LeftPad(HumanReadableSize(TPerc::MAX_GRANULARITY, SF_QUANTITY), 5)
+ << "; limit# " << LeftPad(HumanReadableSize(TPerc::TRACKER_LIMIT , SF_QUANTITY), 5) << Endl;
+ if constexpr (B > 1) {
+ printSizeAndLimit<A, B - 1, B_BEGIN>();
+ } else if constexpr (A > 1) {
+ Cout << Endl;
+ printSizeAndLimit<A - 1, B_BEGIN, B_BEGIN>();
+ }
+}
+
+ Y_UNIT_TEST(PrintTrackerLgSizeAndLimits) {
+ printSizeAndLimit<10, 5, 5>();
+ }
+
+ Y_UNIT_TEST(TrackerLimitTest) {
+ {
+ using TPerc = TPercentileTrackerLg<1, 0, 1>;
+ TPerc tracker;
+ tracker.Increment(Max<size_t>());
+ UNIT_ASSERT_EQUAL(TPerc::TRACKER_LIMIT, tracker.GetPercentile(1.0));
+ }
+ {
+ using TPerc = TPercentileTrackerLg<1, 1, 1>;
+ TPerc tracker;
+ tracker.Increment(Max<size_t>());
+ UNIT_ASSERT_EQUAL(TPerc::TRACKER_LIMIT, tracker.GetPercentile(1.0));
+ }
+ {
+ using TPerc = TPercentileTrackerLg<1, 5, 1>;
+ TPerc tracker;
+ tracker.Increment(Max<size_t>());
+ UNIT_ASSERT_EQUAL(TPerc::TRACKER_LIMIT, tracker.GetPercentile(1.0));
+ }
+ {
+ using TPerc = TPercentileTrackerLg<2, 1, 1>;
+ TPerc tracker;
+ tracker.Increment(Max<size_t>());
+ UNIT_ASSERT_EQUAL(TPerc::TRACKER_LIMIT, tracker.GetPercentile(1.0));
+ }
+ {
+ using TPerc = TPercentileTrackerLg<5, 4, 1>;
+ TPerc tracker;
+ tracker.Increment(Max<size_t>());
+ UNIT_ASSERT_EQUAL(TPerc::TRACKER_LIMIT, tracker.GetPercentile(1.0));
+ }
+ }
+
+ Y_UNIT_TEST(BucketIdxIfvsBucketIdxBinarySearch) {
+ for (size_t var = 0; var < 5; var++) {
+ if (var == 0) {
+ TPercentileTrackerLg<3, 2, 15> tracker;
+ for (size_t i = 0; i < 3000000; i += 1) {
+ size_t num1 = tracker.BucketIdxMostSignificantBit(i);
+ size_t num2 = tracker.BucketIdxBinarySearch(i);
+ UNIT_ASSERT_EQUAL(num1, num2);
+ }
+ } else if (var == 1) {
+ TPercentileTrackerLg<4, 4, 15> tracker;
+ for (size_t i = 0; i < 3000000; i += 1) {
+ size_t num1 = tracker.BucketIdxMostSignificantBit(i);
+ size_t num2 = tracker.BucketIdxBinarySearch(i);
+ UNIT_ASSERT_EQUAL(num1, num2);
+ }
+ } else if (var == 2) {
+ TPercentileTrackerLg<5, 3, 15> tracker;
+ for (size_t i = 0; i < 3000000; i += 1) {
+ size_t num1 = tracker.BucketIdxMostSignificantBit(i);
+ size_t num2 = tracker.BucketIdxBinarySearch(i);
+ size_t num3 = tracker.BucketIdxIf(i);
+ UNIT_ASSERT_EQUAL(num1, num2);
+ UNIT_ASSERT_EQUAL(num2, num3);
+ }
+ } else if (var == 3) {
+ TPercentileTrackerLg<5, 4, 15> tracker;
+ for (size_t i = 0; i < 3000000; i += 1) {
+ size_t num1 = tracker.BucketIdxMostSignificantBit(i);
+ size_t num2 = tracker.BucketIdxBinarySearch(i);
+ size_t num3 = tracker.BucketIdxIf(i);
+ UNIT_ASSERT_EQUAL(num1, num2);
+ UNIT_ASSERT_EQUAL(num2, num3);
+ }
+ } else if (var == 4) {
+ TPercentileTrackerLg<6, 5, 15> tracker;
+ for (size_t i = 0; i < 3000000; i += 1) {
+ size_t num1 = tracker.BucketIdxMostSignificantBit(i);
+ size_t num2 = tracker.BucketIdxBinarySearch(i);
+ UNIT_ASSERT_EQUAL(num1, num2);
+ }
+ for (size_t i = 0; i < 400000000000ul; i += 1303) {
+ size_t num1 = tracker.BucketIdxMostSignificantBit(i);
+ size_t num2 = tracker.BucketIdxBinarySearch(i);
+ UNIT_ASSERT_EQUAL(num1, num2);
+ }
+ }
+ }
+ }
+
+ Y_UNIT_TEST(DifferentPercentiles) {
+ TPercentileTrackerLg<5, 4, 15> tracker;
+ TVector<size_t> values({0, 115, 1216, 15, 3234567, 1234567, 216546, 263421, 751654, 96, 224, 223, 225});
+ TVector<size_t> percentiles50({0, 0, 116, 15, 116, 116, 1216, 1216, 217056, 1216, 1216, 224, 232});
+ TVector<size_t> percentiles75({0, 116, 116, 116, 1216, 1245152, 217056, 270304, 753632, 753632,
+ 270304, 270304, 270304});
+ TVector<size_t> percentiles90({ 0, 116, 1216, 1216, 2064352, 1245152, 1245152, 1245152, 1245152,
+ 1245152, 1245152, 1245152, 1245152});
+ TVector<size_t> percentiles100({ 0, 116, 1216, 1216, 2064352, 2064352, 2064352, 2064352, 2064352,
+ 2064352, 2064352, 2064352, 2064352 });
+
+ for (size_t i = 0; i < values.size(); ++i) {
+ tracker.Increment(values[i]);
+ UNIT_ASSERT_EQUAL(tracker.GetPercentile(0.5), percentiles50[i]);
+ UNIT_ASSERT_EQUAL(tracker.GetPercentile(0.75), percentiles75[i]);
+ UNIT_ASSERT_EQUAL(tracker.GetPercentile(0.90), percentiles90[i]);
+ UNIT_ASSERT_EQUAL(tracker.GetPercentile(1.0), percentiles100[i]);
+ }
+ }
+}
diff --git a/library/cpp/monlib/dynamic_counters/percentile/ut/ya.make b/library/cpp/monlib/dynamic_counters/percentile/ut/ya.make
new file mode 100644
index 0000000000..f9f3564101
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/percentile/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/monlib/dynamic_counters/percentile)
+
+ OWNER(alexvru g:kikimr g:solomon)
+
+ SRCS(
+ percentile_ut.cpp
+ )
+
+END()
diff --git a/library/cpp/monlib/dynamic_counters/percentile/ya.make b/library/cpp/monlib/dynamic_counters/percentile/ya.make
new file mode 100644
index 0000000000..cb52cdd9ad
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/percentile/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+ OWNER(alexvru g:kikimr g:solomon)
+
+ SRCS(
+ percentile.h
+ percentile_lg.h
+ )
+
+ PEERDIR(
+ library/cpp/containers/stack_vector
+ library/cpp/monlib/dynamic_counters
+ )
+
+END()
diff --git a/library/cpp/monlib/dynamic_counters/ut/ya.make b/library/cpp/monlib/dynamic_counters/ut/ya.make
new file mode 100644
index 0000000000..8242f2fe30
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/ut/ya.make
@@ -0,0 +1,16 @@
+UNITTEST_FOR(library/cpp/monlib/dynamic_counters)
+
+OWNER(jamel)
+
+SRCS(
+ contention_ut.cpp
+ counters_ut.cpp
+ encode_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/monlib/encode/protobuf
+ library/cpp/monlib/encode/json
+)
+
+END()
diff --git a/library/cpp/monlib/dynamic_counters/ya.make b/library/cpp/monlib/dynamic_counters/ya.make
new file mode 100644
index 0000000000..aafe1c34be
--- /dev/null
+++ b/library/cpp/monlib/dynamic_counters/ya.make
@@ -0,0 +1,27 @@
+LIBRARY()
+
+OWNER(
+ g:solomon
+ jamel
+)
+
+NO_WSHADOW()
+
+SRCS(
+ counters.cpp
+ encode.cpp
+ golovan_page.cpp
+ page.cpp
+)
+
+PEERDIR(
+ library/cpp/containers/stack_vector
+ library/cpp/monlib/encode/json
+ library/cpp/monlib/encode/spack
+ library/cpp/monlib/encode/prometheus
+ library/cpp/monlib/service/pages
+ library/cpp/string_utils/quote
+ library/cpp/threading/light_rw_lock
+)
+
+END()
diff --git a/library/cpp/monlib/encode/buffered/buffered_encoder_base.cpp b/library/cpp/monlib/encode/buffered/buffered_encoder_base.cpp
new file mode 100644
index 0000000000..87c832d642
--- /dev/null
+++ b/library/cpp/monlib/encode/buffered/buffered_encoder_base.cpp
@@ -0,0 +1,170 @@
+#include "buffered_encoder_base.h"
+
+#include <util/string/join.h>
+#include <util/string/builder.h>
+
+namespace NMonitoring {
+
+void TBufferedEncoderBase::OnStreamBegin() {
+ State_.Expect(TEncoderState::EState::ROOT);
+}
+
+void TBufferedEncoderBase::OnStreamEnd() {
+ State_.Expect(TEncoderState::EState::ROOT);
+}
+
+void TBufferedEncoderBase::OnCommonTime(TInstant time) {
+ State_.Expect(TEncoderState::EState::ROOT);
+ CommonTime_ = time;
+}
+
+void TBufferedEncoderBase::OnMetricBegin(EMetricType type) {
+ State_.Switch(TEncoderState::EState::ROOT, TEncoderState::EState::METRIC);
+ Metrics_.emplace_back();
+ Metrics_.back().MetricType = type;
+}
+
+void TBufferedEncoderBase::OnMetricEnd() {
+ State_.Switch(TEncoderState::EState::METRIC, TEncoderState::EState::ROOT);
+
+ switch (MetricsMergingMode_) {
+ case EMetricsMergingMode::MERGE_METRICS: {
+ auto& metric = Metrics_.back();
+ Sort(metric.Labels, [] (const TPooledLabel& lhs, const TPooledLabel& rhs) {
+ return std::tie(lhs.Key, lhs.Value) < std::tie(rhs.Key, rhs.Value);
+ });
+
+ auto it = MetricMap_.find(metric.Labels);
+ if (it == std::end(MetricMap_)) {
+ MetricMap_.emplace(metric.Labels, Metrics_.size() - 1);
+ } else {
+ auto& existing = Metrics_[it->second].TimeSeries;
+
+ Y_ENSURE(existing.GetValueType() == metric.TimeSeries.GetValueType(),
+ "Time series point type mismatch: expected " << existing.GetValueType()
+ << " but found " << metric.TimeSeries.GetValueType()
+ << ", labels '" << FormatLabels(metric.Labels) << "'");
+
+ existing.CopyFrom(metric.TimeSeries);
+ Metrics_.pop_back();
+ }
+
+ break;
+ }
+ case EMetricsMergingMode::DEFAULT:
+ break;
+ }
+}
+
+void TBufferedEncoderBase::OnLabelsBegin() {
+ if (State_ == TEncoderState::EState::METRIC) {
+ State_ = TEncoderState::EState::METRIC_LABELS;
+ } else if (State_ == TEncoderState::EState::ROOT) {
+ State_ = TEncoderState::EState::COMMON_LABELS;
+ } else {
+ State_.ThrowInvalid("expected METRIC or ROOT");
+ }
+}
+
+void TBufferedEncoderBase::OnLabelsEnd() {
+ if (State_ == TEncoderState::EState::METRIC_LABELS) {
+ State_ = TEncoderState::EState::METRIC;
+ } else if (State_ == TEncoderState::EState::COMMON_LABELS) {
+ State_ = TEncoderState::EState::ROOT;
+ } else {
+ State_.ThrowInvalid("expected LABELS or COMMON_LABELS");
+ }
+}
+
+void TBufferedEncoderBase::OnLabel(TStringBuf name, TStringBuf value) {
+ TPooledLabels* labels;
+ if (State_ == TEncoderState::EState::METRIC_LABELS) {
+ labels = &Metrics_.back().Labels;
+ } else if (State_ == TEncoderState::EState::COMMON_LABELS) {
+ labels = &CommonLabels_;
+ } else {
+ State_.ThrowInvalid("expected LABELS or COMMON_LABELS");
+ }
+
+ labels->emplace_back(LabelNamesPool_.PutIfAbsent(name), LabelValuesPool_.PutIfAbsent(value));
+}
+
+void TBufferedEncoderBase::OnLabel(ui32 name, ui32 value) {
+ TPooledLabels* labels;
+ if (State_ == TEncoderState::EState::METRIC_LABELS) {
+ labels = &Metrics_.back().Labels;
+ } else if (State_ == TEncoderState::EState::COMMON_LABELS) {
+ labels = &CommonLabels_;
+ } else {
+ State_.ThrowInvalid("expected LABELS or COMMON_LABELS");
+ }
+
+ labels->emplace_back(LabelNamesPool_.GetByIndex(name), LabelValuesPool_.GetByIndex(value));
+}
+
+std::pair<ui32, ui32> TBufferedEncoderBase::PrepareLabel(TStringBuf name, TStringBuf value) {
+ auto nameLabel = LabelNamesPool_.PutIfAbsent(name);
+ auto valueLabel = LabelValuesPool_.PutIfAbsent(value);
+ return std::make_pair(nameLabel->Index, valueLabel->Index);
+}
+
+void TBufferedEncoderBase::OnDouble(TInstant time, double value) {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TMetric& metric = Metrics_.back();
+ metric.TimeSeries.Add(time, value);
+}
+
+void TBufferedEncoderBase::OnInt64(TInstant time, i64 value) {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TMetric& metric = Metrics_.back();
+ metric.TimeSeries.Add(time, value);
+}
+
+void TBufferedEncoderBase::OnUint64(TInstant time, ui64 value) {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TMetric& metric = Metrics_.back();
+ metric.TimeSeries.Add(time, value);
+}
+
+void TBufferedEncoderBase::OnHistogram(TInstant time, IHistogramSnapshotPtr s) {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TMetric& metric = Metrics_.back();
+ metric.TimeSeries.Add(time, s.Get());
+}
+
+void TBufferedEncoderBase::OnSummaryDouble(TInstant time, ISummaryDoubleSnapshotPtr s) {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TMetric& metric = Metrics_.back();
+ metric.TimeSeries.Add(time, s.Get());
+}
+
+void TBufferedEncoderBase::OnLogHistogram(TInstant time, TLogHistogramSnapshotPtr s) {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TMetric& metric = Metrics_.back();
+ metric.TimeSeries.Add(time, s.Get());
+}
+
+TString TBufferedEncoderBase::FormatLabels(const TPooledLabels& labels) const {
+ auto formattedLabels = TVector<TString>(Reserve(labels.size() + CommonLabels_.size()));
+ auto addLabel = [&](const TPooledLabel& l) {
+ auto formattedLabel = TStringBuilder() << LabelNamesPool_.Get(l.Key) << '=' << LabelValuesPool_.Get(l.Value);
+ formattedLabels.push_back(std::move(formattedLabel));
+ };
+
+ for (const auto& l: labels) {
+ addLabel(l);
+ }
+ for (const auto& l: CommonLabels_) {
+ const auto it = FindIf(labels, [&](const TPooledLabel& label) {
+ return label.Key == l.Key;
+ });
+ if (it == labels.end()) {
+ addLabel(l);
+ }
+ }
+ Sort(formattedLabels);
+
+ return TStringBuilder() << "{" << JoinSeq(", ", formattedLabels) << "}";
+}
+
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/encode/buffered/buffered_encoder_base.h b/library/cpp/monlib/encode/buffered/buffered_encoder_base.h
new file mode 100644
index 0000000000..fe3714e58f
--- /dev/null
+++ b/library/cpp/monlib/encode/buffered/buffered_encoder_base.h
@@ -0,0 +1,100 @@
+#pragma once
+
+#include "string_pool.h"
+
+#include <library/cpp/monlib/encode/encoder.h>
+#include <library/cpp/monlib/encode/encoder_state.h>
+#include <library/cpp/monlib/encode/format.h>
+#include <library/cpp/monlib/metrics/metric_value.h>
+
+#include <util/datetime/base.h>
+#include <util/digest/numeric.h>
+
+
+namespace NMonitoring {
+
+class TBufferedEncoderBase : public IMetricEncoder {
+public:
+ void OnStreamBegin() override;
+ void OnStreamEnd() override;
+
+ void OnCommonTime(TInstant time) override;
+
+ void OnMetricBegin(EMetricType type) override;
+ void OnMetricEnd() override;
+
+ void OnLabelsBegin() override;
+ void OnLabelsEnd() override;
+ void OnLabel(TStringBuf name, TStringBuf value) override;
+ void OnLabel(ui32 name, ui32 value) override;
+ std::pair<ui32, ui32> PrepareLabel(TStringBuf name, TStringBuf value) override;
+
+ void OnDouble(TInstant time, double value) override;
+ void OnInt64(TInstant time, i64 value) override;
+ void OnUint64(TInstant time, ui64 value) override;
+
+ void OnHistogram(TInstant time, IHistogramSnapshotPtr snapshot) override;
+ void OnSummaryDouble(TInstant time, ISummaryDoubleSnapshotPtr snapshot) override;
+ void OnLogHistogram(TInstant, TLogHistogramSnapshotPtr) override;
+
+protected:
+ using TPooledStr = TStringPoolBuilder::TValue;
+
+ struct TPooledLabel {
+ TPooledLabel(const TPooledStr* key, const TPooledStr* value)
+ : Key{key}
+ , Value{value}
+ {
+ }
+
+ bool operator==(const TPooledLabel& other) const {
+ return std::tie(Key, Value) == std::tie(other.Key, other.Value);
+ }
+
+ bool operator!=(const TPooledLabel& other) const {
+ return !(*this == other);
+ }
+
+ const TPooledStr* Key;
+ const TPooledStr* Value;
+ };
+
+ using TPooledLabels = TVector<TPooledLabel>;
+
+ struct TPooledLabelsHash {
+ size_t operator()(const TPooledLabels& val) const {
+ size_t hash{0};
+
+ for (auto v : val) {
+ hash = CombineHashes<size_t>(hash, reinterpret_cast<size_t>(v.Key));
+ hash = CombineHashes<size_t>(hash, reinterpret_cast<size_t>(v.Value));
+ }
+
+ return hash;
+ }
+ };
+
+ using TMetricMap = THashMap<TPooledLabels, size_t, TPooledLabelsHash>;
+
+ struct TMetric {
+ EMetricType MetricType = EMetricType::UNKNOWN;
+ TPooledLabels Labels;
+ TMetricTimeSeries TimeSeries;
+ };
+
+protected:
+ TString FormatLabels(const TPooledLabels& labels) const;
+
+protected:
+ TEncoderState State_;
+
+ TStringPoolBuilder LabelNamesPool_;
+ TStringPoolBuilder LabelValuesPool_;
+ TInstant CommonTime_ = TInstant::Zero();
+ TPooledLabels CommonLabels_;
+ TVector<TMetric> Metrics_;
+ TMetricMap MetricMap_;
+ EMetricsMergingMode MetricsMergingMode_ = EMetricsMergingMode::DEFAULT;
+};
+
+}
diff --git a/library/cpp/monlib/encode/buffered/string_pool.cpp b/library/cpp/monlib/encode/buffered/string_pool.cpp
new file mode 100644
index 0000000000..b4c7988ba3
--- /dev/null
+++ b/library/cpp/monlib/encode/buffered/string_pool.cpp
@@ -0,0 +1,58 @@
+#include "string_pool.h"
+
+namespace NMonitoring {
+ ////////////////////////////////////////////////////////////////////////////////
+ // TStringPoolBuilder
+ ////////////////////////////////////////////////////////////////////////////////
+ const TStringPoolBuilder::TValue* TStringPoolBuilder::PutIfAbsent(TStringBuf str) {
+ Y_ENSURE(!IsBuilt_, "Cannot add more values after string has been built");
+
+ auto [it, isInserted] = StrMap_.try_emplace(str, Max<ui32>(), 0);
+ if (isInserted) {
+ BytesSize_ += str.size();
+ it->second.Index = StrVector_.size();
+ StrVector_.emplace_back(it->first, &it->second);
+ }
+
+ TValue* value = &it->second;
+ ++value->Frequency;
+ return value;
+ }
+
+ const TStringPoolBuilder::TValue* TStringPoolBuilder::GetByIndex(ui32 index) const {
+ return StrVector_.at(index).second;
+ }
+
+ TStringPoolBuilder& TStringPoolBuilder::Build() {
+ if (RequiresSorting_) {
+ // sort in reversed order
+ std::sort(StrVector_.begin(), StrVector_.end(), [](auto& a, auto& b) {
+ return a.second->Frequency > b.second->Frequency;
+ });
+
+ ui32 i = 0;
+ for (auto& value : StrVector_) {
+ value.second->Index = i++;
+ }
+ }
+
+ IsBuilt_ = true;
+
+ return *this;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // TStringPool
+ ////////////////////////////////////////////////////////////////////////////////
+ void TStringPool::InitIndex(const char* data, ui32 size) {
+ const char* begin = data;
+ const char* end = begin + size;
+ for (const char* p = begin; p != end; ++p) {
+ if (*p == '\0') {
+ Index_.push_back(TStringBuf(begin, p));
+ begin = p + 1;
+ }
+ }
+ }
+
+}
diff --git a/library/cpp/monlib/encode/buffered/string_pool.h b/library/cpp/monlib/encode/buffered/string_pool.h
new file mode 100644
index 0000000000..00e5644608
--- /dev/null
+++ b/library/cpp/monlib/encode/buffered/string_pool.h
@@ -0,0 +1,92 @@
+#pragma once
+
+#include <util/generic/hash.h>
+#include <util/generic/vector.h>
+
+namespace NMonitoring {
+ ////////////////////////////////////////////////////////////////////////////////
+ // TStringPoolBuilder
+ ////////////////////////////////////////////////////////////////////////////////
+ class TStringPoolBuilder {
+ public:
+ struct TValue: TNonCopyable {
+ TValue(ui32 idx, ui32 freq)
+ : Index{idx}
+ , Frequency{freq}
+ {
+ }
+
+ ui32 Index;
+ ui32 Frequency;
+ };
+
+ public:
+ const TValue* PutIfAbsent(TStringBuf str);
+ const TValue* GetByIndex(ui32 index) const;
+
+ /// Determines whether pool must be sorted by value frequencies
+ TStringPoolBuilder& SetSorted(bool sorted) {
+ RequiresSorting_ = sorted;
+ return *this;
+ }
+
+ TStringPoolBuilder& Build();
+
+ TStringBuf Get(ui32 index) const {
+ Y_ENSURE(IsBuilt_, "Pool must be sorted first");
+ return StrVector_.at(index).first;
+ }
+
+ TStringBuf Get(const TValue* value) const {
+ return StrVector_.at(value->Index).first;
+ }
+
+ template <typename TConsumer>
+ void ForEach(TConsumer&& c) {
+ Y_ENSURE(IsBuilt_, "Pool must be sorted first");
+ for (const auto& value : StrVector_) {
+ c(value.first, value.second->Index, value.second->Frequency);
+ }
+ }
+
+ size_t BytesSize() const noexcept {
+ return BytesSize_;
+ }
+
+ size_t Count() const noexcept {
+ return StrMap_.size();
+ }
+
+ private:
+ THashMap<TString, TValue> StrMap_;
+ TVector<std::pair<TStringBuf, TValue*>> StrVector_;
+ bool RequiresSorting_ = false;
+ bool IsBuilt_ = false;
+ size_t BytesSize_ = 0;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // TStringPool
+ ////////////////////////////////////////////////////////////////////////////////
+ class TStringPool {
+ public:
+ TStringPool(const char* data, ui32 size) {
+ InitIndex(data, size);
+ }
+
+ TStringBuf Get(ui32 i) const {
+ return Index_.at(i);
+ }
+
+ size_t Size() const {
+ return Index_.size();
+ }
+
+ private:
+ void InitIndex(const char* data, ui32 size);
+
+ private:
+ TVector<TStringBuf> Index_;
+ };
+
+}
diff --git a/library/cpp/monlib/encode/buffered/string_pool_ut.cpp b/library/cpp/monlib/encode/buffered/string_pool_ut.cpp
new file mode 100644
index 0000000000..9fc3421d0b
--- /dev/null
+++ b/library/cpp/monlib/encode/buffered/string_pool_ut.cpp
@@ -0,0 +1,84 @@
+#include "string_pool.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NMonitoring;
+
+Y_UNIT_TEST_SUITE(TStringPoolTest) {
+ Y_UNIT_TEST(PutIfAbsent) {
+ TStringPoolBuilder strPool;
+ strPool.SetSorted(true);
+
+ auto* h1 = strPool.PutIfAbsent("one");
+ auto* h2 = strPool.PutIfAbsent("two");
+ auto* h3 = strPool.PutIfAbsent("two");
+ UNIT_ASSERT(h1 != h2);
+ UNIT_ASSERT(h2 == h3);
+
+ UNIT_ASSERT_VALUES_EQUAL(h1->Frequency, 1);
+ UNIT_ASSERT_VALUES_EQUAL(h1->Index, 0);
+
+ UNIT_ASSERT_VALUES_EQUAL(h2->Frequency, 2);
+ UNIT_ASSERT_VALUES_EQUAL(h2->Index, 1);
+
+ UNIT_ASSERT_VALUES_EQUAL(strPool.BytesSize(), 6);
+ UNIT_ASSERT_VALUES_EQUAL(strPool.Count(), 2);
+ }
+
+ Y_UNIT_TEST(SortByFrequency) {
+ TStringPoolBuilder strPool;
+ strPool.SetSorted(true);
+
+ auto* h1 = strPool.PutIfAbsent("one");
+ auto* h2 = strPool.PutIfAbsent("two");
+ auto* h3 = strPool.PutIfAbsent("two");
+ UNIT_ASSERT(h1 != h2);
+ UNIT_ASSERT(h2 == h3);
+
+ strPool.Build();
+
+ UNIT_ASSERT_VALUES_EQUAL(h1->Frequency, 1);
+ UNIT_ASSERT_VALUES_EQUAL(h1->Index, 1);
+
+ UNIT_ASSERT_VALUES_EQUAL(h2->Frequency, 2);
+ UNIT_ASSERT_VALUES_EQUAL(h2->Index, 0);
+
+ UNIT_ASSERT_VALUES_EQUAL(strPool.BytesSize(), 6);
+ UNIT_ASSERT_VALUES_EQUAL(strPool.Count(), 2);
+ }
+
+ Y_UNIT_TEST(ForEach) {
+ TStringPoolBuilder strPool;
+ strPool.SetSorted(true);
+
+ strPool.PutIfAbsent("one");
+ strPool.PutIfAbsent("two");
+ strPool.PutIfAbsent("two");
+ strPool.PutIfAbsent("three");
+ strPool.PutIfAbsent("three");
+ strPool.PutIfAbsent("three");
+
+ UNIT_ASSERT_VALUES_EQUAL(strPool.BytesSize(), 11);
+ UNIT_ASSERT_VALUES_EQUAL(strPool.Count(), 3);
+
+ strPool.Build();
+
+ TVector<TString> strings;
+ TVector<ui32> indexes;
+ TVector<ui32> frequences;
+ strPool.ForEach([&](TStringBuf str, ui32 index, ui32 freq) {
+ strings.emplace_back(str);
+ indexes.push_back(index);
+ frequences.push_back(freq);
+ });
+
+ TVector<TString> expectedStrings = {"three", "two", "one"};
+ UNIT_ASSERT_EQUAL(strings, expectedStrings);
+
+ TVector<ui32> expectedIndexes = {0, 1, 2};
+ UNIT_ASSERT_EQUAL(indexes, expectedIndexes);
+
+ TVector<ui32> expectedFrequences = {3, 2, 1};
+ UNIT_ASSERT_EQUAL(frequences, expectedFrequences);
+ }
+}
diff --git a/library/cpp/monlib/encode/buffered/ut/ya.make b/library/cpp/monlib/encode/buffered/ut/ya.make
new file mode 100644
index 0000000000..2157ac1490
--- /dev/null
+++ b/library/cpp/monlib/encode/buffered/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/monlib/encode/buffered)
+
+OWNER(
+ g:solomon
+ jamel
+)
+
+SRCS(
+ string_pool_ut.cpp
+)
+
+END()
diff --git a/library/cpp/monlib/encode/buffered/ya.make b/library/cpp/monlib/encode/buffered/ya.make
new file mode 100644
index 0000000000..81b6a78b93
--- /dev/null
+++ b/library/cpp/monlib/encode/buffered/ya.make
@@ -0,0 +1,19 @@
+LIBRARY()
+
+OWNER(
+ g:solomon
+ jamel
+ msherbakov
+)
+
+SRCS(
+ buffered_encoder_base.cpp
+ string_pool.cpp
+)
+
+PEERDIR(
+ library/cpp/monlib/encode
+ library/cpp/monlib/metrics
+)
+
+END()
diff --git a/library/cpp/monlib/encode/encoder.cpp b/library/cpp/monlib/encode/encoder.cpp
new file mode 100644
index 0000000000..becf932689
--- /dev/null
+++ b/library/cpp/monlib/encode/encoder.cpp
@@ -0,0 +1,6 @@
+#include "encoder.h"
+
+namespace NMonitoring {
+ IMetricEncoder::~IMetricEncoder() {
+ }
+}
diff --git a/library/cpp/monlib/encode/encoder.h b/library/cpp/monlib/encode/encoder.h
new file mode 100644
index 0000000000..a26a133d16
--- /dev/null
+++ b/library/cpp/monlib/encode/encoder.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+
+#include <library/cpp/monlib/metrics/metric_consumer.h>
+
+namespace NMonitoring {
+ class IMetricEncoder: public IMetricConsumer {
+ public:
+ virtual ~IMetricEncoder();
+
+ virtual void Close() = 0;
+ };
+
+ using IMetricEncoderPtr = THolder<IMetricEncoder>;
+
+}
diff --git a/library/cpp/monlib/encode/encoder_state.cpp b/library/cpp/monlib/encode/encoder_state.cpp
new file mode 100644
index 0000000000..0ece696b1a
--- /dev/null
+++ b/library/cpp/monlib/encode/encoder_state.cpp
@@ -0,0 +1 @@
+#include "encoder_state.h"
diff --git a/library/cpp/monlib/encode/encoder_state.h b/library/cpp/monlib/encode/encoder_state.h
new file mode 100644
index 0000000000..e6a098f404
--- /dev/null
+++ b/library/cpp/monlib/encode/encoder_state.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include "encoder_state_enum.h"
+
+#include <util/generic/serialized_enum.h>
+#include <util/generic/yexception.h>
+
+
+namespace NMonitoring {
+
+ template <typename EEncoderState>
+ class TEncoderStateImpl {
+ public:
+ using EState = EEncoderState;
+
+ explicit TEncoderStateImpl(EEncoderState state = EEncoderState::ROOT)
+ : State_(state)
+ {
+ }
+
+ TEncoderStateImpl& operator=(EEncoderState rhs) noexcept {
+ State_ = rhs;
+ return *this;
+ }
+
+ inline bool operator==(EEncoderState rhs) const noexcept {
+ return State_ == rhs;
+ }
+
+ inline bool operator!=(EEncoderState rhs) const noexcept {
+ return !operator==(rhs);
+ }
+
+ [[noreturn]] inline void ThrowInvalid(TStringBuf message) const {
+ ythrow yexception() << "invalid encoder state: "
+ << ToStr() << ", " << message;
+ }
+
+ inline void Expect(EEncoderState expected) const {
+ if (Y_UNLIKELY(State_ != expected)) {
+ ythrow yexception()
+ << "invalid encoder state: " << ToStr()
+ << ", expected: " << TEncoderStateImpl(expected).ToStr();
+ }
+ }
+
+ inline void Switch(EEncoderState from, EEncoderState to) {
+ Expect(from);
+ State_ = to;
+ }
+
+ TStringBuf ToStr() const noexcept {
+ return NEnumSerializationRuntime::GetEnumNamesImpl<EEncoderState>().at(State_);
+ }
+
+ private:
+ EEncoderState State_;
+ };
+
+ using TEncoderState = TEncoderStateImpl<EEncoderState>;
+
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/encode/encoder_state_enum.h b/library/cpp/monlib/encode/encoder_state_enum.h
new file mode 100644
index 0000000000..471604f91d
--- /dev/null
+++ b/library/cpp/monlib/encode/encoder_state_enum.h
@@ -0,0 +1,12 @@
+#pragma once
+
+namespace NMonitoring {
+
+ enum class EEncoderState {
+ ROOT,
+ COMMON_LABELS,
+ METRIC,
+ METRIC_LABELS,
+ };
+
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/encode/fake/fake.cpp b/library/cpp/monlib/encode/fake/fake.cpp
new file mode 100644
index 0000000000..69d691361a
--- /dev/null
+++ b/library/cpp/monlib/encode/fake/fake.cpp
@@ -0,0 +1,51 @@
+#include "fake.h"
+
+#include <util/datetime/base.h>
+
+namespace NMonitoring {
+ class TFakeEncoder: public IMetricEncoder {
+ public:
+ void OnStreamBegin() override {
+ }
+ void OnStreamEnd() override {
+ }
+
+ void OnCommonTime(TInstant) override {
+ }
+
+ void OnMetricBegin(EMetricType) override {
+ }
+ void OnMetricEnd() override {
+ }
+
+ void OnLabelsBegin() override {
+ }
+ void OnLabelsEnd() override {
+ }
+ void OnLabel(const TStringBuf, const TStringBuf) override {
+ }
+
+ void OnDouble(TInstant, double) override {
+ }
+ void OnInt64(TInstant, i64) override {
+ }
+ void OnUint64(TInstant, ui64) override {
+ }
+
+ void OnHistogram(TInstant, IHistogramSnapshotPtr) override {
+ }
+
+ void OnSummaryDouble(TInstant, ISummaryDoubleSnapshotPtr) override {
+ }
+
+ void OnLogHistogram(TInstant, TLogHistogramSnapshotPtr) override {
+ }
+
+ void Close() override {
+ }
+ };
+
+ IMetricEncoderPtr EncoderFake() {
+ return MakeHolder<TFakeEncoder>();
+ }
+}
diff --git a/library/cpp/monlib/encode/fake/fake.h b/library/cpp/monlib/encode/fake/fake.h
new file mode 100644
index 0000000000..8109326987
--- /dev/null
+++ b/library/cpp/monlib/encode/fake/fake.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include <library/cpp/monlib/encode/encoder.h>
+
+class IOutputStream;
+
+namespace NMonitoring {
+ // Does nothing: just implements IMetricEncoder interface with stubs
+ IMetricEncoderPtr EncoderFake();
+}
diff --git a/library/cpp/monlib/encode/fake/ya.make b/library/cpp/monlib/encode/fake/ya.make
new file mode 100644
index 0000000000..ae96f45782
--- /dev/null
+++ b/library/cpp/monlib/encode/fake/ya.make
@@ -0,0 +1,12 @@
+LIBRARY()
+
+OWNER(
+ g:solomon
+ msherbakov
+)
+
+SRCS(
+ fake.cpp
+)
+
+END()
diff --git a/library/cpp/monlib/encode/format.cpp b/library/cpp/monlib/encode/format.cpp
new file mode 100644
index 0000000000..400ce5a643
--- /dev/null
+++ b/library/cpp/monlib/encode/format.cpp
@@ -0,0 +1,202 @@
+#include "format.h"
+
+#include <util/string/ascii.h>
+#include <util/string/split.h>
+#include <util/string/strip.h>
+#include <util/stream/output.h>
+#include <util/string/cast.h>
+
+namespace NMonitoring {
+ static ECompression CompressionFromHeader(TStringBuf value) {
+ if (value.empty()) {
+ return ECompression::UNKNOWN;
+ }
+
+ for (const auto& it : StringSplitter(value).Split(',').SkipEmpty()) {
+ TStringBuf token = StripString(it.Token());
+
+ if (AsciiEqualsIgnoreCase(token, NFormatContentEncoding::IDENTITY)) {
+ return ECompression::IDENTITY;
+ } else if (AsciiEqualsIgnoreCase(token, NFormatContentEncoding::ZLIB)) {
+ return ECompression::ZLIB;
+ } else if (AsciiEqualsIgnoreCase(token, NFormatContentEncoding::LZ4)) {
+ return ECompression::LZ4;
+ } else if (AsciiEqualsIgnoreCase(token, NFormatContentEncoding::ZSTD)) {
+ return ECompression::ZSTD;
+ }
+ }
+
+ return ECompression::UNKNOWN;
+ }
+
+ static EFormat FormatFromHttpMedia(TStringBuf value) {
+ if (AsciiEqualsIgnoreCase(value, NFormatContenType::SPACK)) {
+ return EFormat::SPACK;
+ } else if (AsciiEqualsIgnoreCase(value, NFormatContenType::JSON)) {
+ return EFormat::JSON;
+ } else if (AsciiEqualsIgnoreCase(value, NFormatContenType::PROTOBUF)) {
+ return EFormat::PROTOBUF;
+ } else if (AsciiEqualsIgnoreCase(value, NFormatContenType::TEXT)) {
+ return EFormat::TEXT;
+ } else if (AsciiEqualsIgnoreCase(value, NFormatContenType::PROMETHEUS)) {
+ return EFormat::PROMETHEUS;
+ }
+
+ return EFormat::UNKNOWN;
+ }
+
+ EFormat FormatFromAcceptHeader(TStringBuf value) {
+ EFormat result{EFormat::UNKNOWN};
+
+ for (const auto& it : StringSplitter(value).Split(',').SkipEmpty()) {
+ TStringBuf token = StripString(it.Token());
+
+ result = FormatFromHttpMedia(token);
+ if (result != EFormat::UNKNOWN) {
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ EFormat FormatFromContentType(TStringBuf value) {
+ value = value.NextTok(';');
+
+ return FormatFromHttpMedia(value);
+ }
+
+ TStringBuf ContentTypeByFormat(EFormat format) {
+ switch (format) {
+ case EFormat::SPACK:
+ return NFormatContenType::SPACK;
+ case EFormat::JSON:
+ return NFormatContenType::JSON;
+ case EFormat::PROTOBUF:
+ return NFormatContenType::PROTOBUF;
+ case EFormat::TEXT:
+ return NFormatContenType::TEXT;
+ case EFormat::PROMETHEUS:
+ return NFormatContenType::PROMETHEUS;
+ case EFormat::UNKNOWN:
+ return TStringBuf();
+ }
+
+ Y_FAIL(); // for GCC
+ }
+
+ ECompression CompressionFromAcceptEncodingHeader(TStringBuf value) {
+ return CompressionFromHeader(value);
+ }
+
+ ECompression CompressionFromContentEncodingHeader(TStringBuf value) {
+ return CompressionFromHeader(value);
+ }
+
+ TStringBuf ContentEncodingByCompression(ECompression compression) {
+ switch (compression) {
+ case ECompression::IDENTITY:
+ return NFormatContentEncoding::IDENTITY;
+ case ECompression::ZLIB:
+ return NFormatContentEncoding::ZLIB;
+ case ECompression::LZ4:
+ return NFormatContentEncoding::LZ4;
+ case ECompression::ZSTD:
+ return NFormatContentEncoding::ZSTD;
+ case ECompression::UNKNOWN:
+ return TStringBuf();
+ }
+
+ Y_FAIL(); // for GCC
+ }
+
+}
+
+template <>
+NMonitoring::EFormat FromStringImpl<NMonitoring::EFormat>(const char* str, size_t len) {
+ using NMonitoring::EFormat;
+ TStringBuf value(str, len);
+ if (value == TStringBuf("SPACK")) {
+ return EFormat::SPACK;
+ } else if (value == TStringBuf("JSON")) {
+ return EFormat::JSON;
+ } else if (value == TStringBuf("PROTOBUF")) {
+ return EFormat::PROTOBUF;
+ } else if (value == TStringBuf("TEXT")) {
+ return EFormat::TEXT;
+ } else if (value == TStringBuf("PROMETHEUS")) {
+ return EFormat::PROMETHEUS;
+ } else if (value == TStringBuf("UNKNOWN")) {
+ return EFormat::UNKNOWN;
+ }
+ ythrow yexception() << "unknown format: " << value;
+}
+
+template <>
+void Out<NMonitoring::EFormat>(IOutputStream& o, NMonitoring::EFormat f) {
+ using NMonitoring::EFormat;
+ switch (f) {
+ case EFormat::SPACK:
+ o << TStringBuf("SPACK");
+ return;
+ case EFormat::JSON:
+ o << TStringBuf("JSON");
+ return;
+ case EFormat::PROTOBUF:
+ o << TStringBuf("PROTOBUF");
+ return;
+ case EFormat::TEXT:
+ o << TStringBuf("TEXT");
+ return;
+ case EFormat::PROMETHEUS:
+ o << TStringBuf("PROMETHEUS");
+ return;
+ case EFormat::UNKNOWN:
+ o << TStringBuf("UNKNOWN");
+ return;
+ }
+
+ Y_FAIL(); // for GCC
+}
+
+template <>
+NMonitoring::ECompression FromStringImpl<NMonitoring::ECompression>(const char* str, size_t len) {
+ using NMonitoring::ECompression;
+ TStringBuf value(str, len);
+ if (value == TStringBuf("IDENTITY")) {
+ return ECompression::IDENTITY;
+ } else if (value == TStringBuf("ZLIB")) {
+ return ECompression::ZLIB;
+ } else if (value == TStringBuf("LZ4")) {
+ return ECompression::LZ4;
+ } else if (value == TStringBuf("ZSTD")) {
+ return ECompression::ZSTD;
+ } else if (value == TStringBuf("UNKNOWN")) {
+ return ECompression::UNKNOWN;
+ }
+ ythrow yexception() << "unknown compression: " << value;
+}
+
+template <>
+void Out<NMonitoring::ECompression>(IOutputStream& o, NMonitoring::ECompression c) {
+ using NMonitoring::ECompression;
+ switch (c) {
+ case ECompression::IDENTITY:
+ o << TStringBuf("IDENTITY");
+ return;
+ case ECompression::ZLIB:
+ o << TStringBuf("ZLIB");
+ return;
+ case ECompression::LZ4:
+ o << TStringBuf("LZ4");
+ return;
+ case ECompression::ZSTD:
+ o << TStringBuf("ZSTD");
+ return;
+ case ECompression::UNKNOWN:
+ o << TStringBuf("UNKNOWN");
+ return;
+ }
+
+ Y_FAIL(); // for GCC
+}
diff --git a/library/cpp/monlib/encode/format.h b/library/cpp/monlib/encode/format.h
new file mode 100644
index 0000000000..495d42d786
--- /dev/null
+++ b/library/cpp/monlib/encode/format.h
@@ -0,0 +1,166 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+namespace NMonitoring {
+ namespace NFormatContenType {
+ constexpr TStringBuf TEXT = "application/x-solomon-txt";
+ constexpr TStringBuf JSON = "application/json";
+ constexpr TStringBuf PROTOBUF = "application/x-solomon-pb";
+ constexpr TStringBuf SPACK = "application/x-solomon-spack";
+ constexpr TStringBuf PROMETHEUS = "text/plain";
+ }
+
+ namespace NFormatContentEncoding {
+ constexpr TStringBuf IDENTITY = "identity";
+ constexpr TStringBuf ZLIB = "zlib";
+ constexpr TStringBuf LZ4 = "lz4";
+ constexpr TStringBuf ZSTD = "zstd";
+ }
+
+ /**
+ * Defines format types for metric encoders.
+ */
+ enum class EFormat {
+ /**
+ * Special case when it was not possible to determine format.
+ */
+ UNKNOWN,
+
+ /**
+ * Read more https://wiki.yandex-team.ru/solomon/api/dataformat/spackv1
+ */
+ SPACK,
+
+ /**
+ * Read more https://wiki.yandex-team.ru/solomon/api/dataformat/json
+ */
+ JSON,
+
+ /**
+ * Simple protobuf format, only for testing purposes.
+ */
+ PROTOBUF,
+
+ /**
+ * Simple text representation, only for debug purposes.
+ */
+ TEXT,
+
+ /**
+ * Prometheus text-based format
+ */
+ PROMETHEUS,
+ };
+
+ /**
+ * Defines compression algorithms for metric encoders.
+ */
+ enum class ECompression {
+ /**
+ * Special case when it was not possible to determine compression.
+ */
+ UNKNOWN,
+
+ /**
+ * Means no compression.
+ */
+ IDENTITY,
+
+ /**
+ * Using the zlib structure (defined in RFC 1950), with the
+ * deflate compression algorithm and Adler32 checkums.
+ */
+ ZLIB,
+
+ /**
+ * Using LZ4 compression algorithm (read http://lz4.org for more info)
+ * with XxHash32 checksums.
+ */
+ LZ4,
+
+ /**
+ * Using Zstandard compression algorithm (read http://zstd.net for more
+ * info) with XxHash32 checksums.
+ */
+ ZSTD,
+ };
+
+ enum class EMetricsMergingMode {
+ /**
+ * Do not merge metric batches. If several points of the same metric were
+ * added multiple times accross different writes, paste them as
+ * separate metrics.
+ *
+ * Example:
+ * COUNTER [(ts1, val1)] | COUNTER [(ts1, val1)]
+ * COUNTER [(ts2, val2)] | --> COUNTER [(ts2, val2)]
+ * COUNTER [(ts3, val3)] | COUNTER [(ts3, val3)]
+ */
+ DEFAULT,
+
+ /**
+ * If several points of the same metric were added multiple times across
+ * different writes, merge all values to one timeseries.
+ *
+ * Example:
+ * COUNTER [(ts1, val1)] |
+ * COUNTER [(ts2, val2)] | --> COUNTER [(ts1, val1), (ts2, val2), (ts3, val3)]
+ * COUNTER [(ts3, val3)] |
+ */
+ MERGE_METRICS,
+ };
+
+ /**
+ * Matches serialization format by the given "Accept" header value.
+ *
+ * @param value value of the "Accept" header.
+ * @return most preffered serialization format type
+ */
+ EFormat FormatFromAcceptHeader(TStringBuf value);
+
+ /**
+ * Matches serialization format by the given "Content-Type" header value
+ *
+ * @param value value of the "Content-Type" header
+ * @return message format
+ */
+ EFormat FormatFromContentType(TStringBuf value);
+
+ /**
+ * Returns value for "Content-Type" header determined by the given
+ * format type.
+ *
+ * @param format serialization format type
+ * @return mime-type indentificator
+ * or empty string if format is UNKNOWN
+ */
+ TStringBuf ContentTypeByFormat(EFormat format);
+
+ /**
+ * Matches compression algorithm by the given "Accept-Encoding" header value.
+ *
+ * @param value value of the "Accept-Encoding" header.
+ * @return most preffered compression algorithm
+ */
+ ECompression CompressionFromAcceptEncodingHeader(TStringBuf value);
+
+ /**
+ * Matches compression algorithm by the given "Content-Encoding" header value.
+ *
+ * @param value value of the "Accept-Encoding" header.
+ * @return most preffered compression algorithm
+ */
+ ECompression CompressionFromContentEncodingHeader(TStringBuf value);
+
+ /**
+ * Returns value for "Content-Encoding" header determined by the given
+ * compression algorithm.
+ *
+ * @param compression encoding compression alg
+ * @return media-type compresion algorithm
+ * or empty string if compression is UNKNOWN
+ */
+ TStringBuf ContentEncodingByCompression(ECompression compression);
+
+}
diff --git a/library/cpp/monlib/encode/format_ut.cpp b/library/cpp/monlib/encode/format_ut.cpp
new file mode 100644
index 0000000000..22a0e30c03
--- /dev/null
+++ b/library/cpp/monlib/encode/format_ut.cpp
@@ -0,0 +1,136 @@
+#include "format.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/string.h>
+#include <util/string/builder.h>
+
+#include <array>
+
+using namespace NMonitoring;
+
+Y_UNIT_TEST_SUITE(TFormatTest) {
+ Y_UNIT_TEST(ContentTypeHeader) {
+ UNIT_ASSERT_EQUAL(FormatFromContentType(""), EFormat::UNKNOWN);
+ UNIT_ASSERT_EQUAL(FormatFromContentType("application/json;some=stuff"), EFormat::JSON);
+ UNIT_ASSERT_EQUAL(FormatFromContentType("application/x-solomon-spack"), EFormat::SPACK);
+ UNIT_ASSERT_EQUAL(FormatFromContentType("application/xml"), EFormat::UNKNOWN);
+ UNIT_ASSERT_EQUAL(FormatFromContentType(";application/xml"), EFormat::UNKNOWN);
+ }
+
+ Y_UNIT_TEST(AcceptHeader) {
+ UNIT_ASSERT_EQUAL(FormatFromAcceptHeader(""), EFormat::UNKNOWN);
+ UNIT_ASSERT_EQUAL(FormatFromAcceptHeader("*/*"), EFormat::UNKNOWN);
+
+ UNIT_ASSERT_EQUAL(
+ FormatFromAcceptHeader("application/xml"),
+ EFormat::UNKNOWN);
+
+ UNIT_ASSERT_EQUAL(
+ FormatFromAcceptHeader("application/json"),
+ EFormat::JSON);
+
+ UNIT_ASSERT_EQUAL(
+ FormatFromAcceptHeader("application/x-solomon-spack"),
+ EFormat::SPACK);
+
+ UNIT_ASSERT_EQUAL(
+ FormatFromAcceptHeader("application/x-solomon-pb"),
+ EFormat::PROTOBUF);
+
+ UNIT_ASSERT_EQUAL(
+ FormatFromAcceptHeader("application/x-solomon-txt"),
+ EFormat::TEXT);
+
+ UNIT_ASSERT_EQUAL(
+ FormatFromAcceptHeader("application/json, text/plain"),
+ EFormat::JSON);
+
+ UNIT_ASSERT_EQUAL(
+ FormatFromAcceptHeader("application/x-solomon-spack, application/json, text/plain"),
+ EFormat::SPACK);
+
+ UNIT_ASSERT_EQUAL(
+ FormatFromAcceptHeader(" , application/x-solomon-spack ,, application/json , text/plain"),
+ EFormat::SPACK);
+
+ UNIT_ASSERT_EQUAL(
+ FormatFromAcceptHeader("application/xml, application/x-solomon-spack, text/plain"),
+ EFormat::SPACK);
+
+ UNIT_ASSERT_EQUAL(
+ FormatFromAcceptHeader("text/plain"),
+ EFormat::PROMETHEUS);
+ }
+
+ Y_UNIT_TEST(FormatToStrFromStr) {
+ const std::array<EFormat, 6> formats = {{
+ EFormat::UNKNOWN,
+ EFormat::SPACK,
+ EFormat::JSON,
+ EFormat::PROTOBUF,
+ EFormat::TEXT,
+ EFormat::PROMETHEUS,
+ }};
+
+ for (EFormat f : formats) {
+ TString str = (TStringBuilder() << f);
+ EFormat g = FromString<EFormat>(str);
+ UNIT_ASSERT_EQUAL(f, g);
+ }
+ }
+
+ Y_UNIT_TEST(AcceptEncodingHeader) {
+ UNIT_ASSERT_EQUAL(
+ CompressionFromAcceptEncodingHeader(""),
+ ECompression::UNKNOWN);
+
+ UNIT_ASSERT_EQUAL(
+ CompressionFromAcceptEncodingHeader("br"),
+ ECompression::UNKNOWN);
+
+ UNIT_ASSERT_EQUAL(
+ CompressionFromAcceptEncodingHeader("identity"),
+ ECompression::IDENTITY);
+
+ UNIT_ASSERT_EQUAL(
+ CompressionFromAcceptEncodingHeader("zlib"),
+ ECompression::ZLIB);
+
+ UNIT_ASSERT_EQUAL(
+ CompressionFromAcceptEncodingHeader("lz4"),
+ ECompression::LZ4);
+
+ UNIT_ASSERT_EQUAL(
+ CompressionFromAcceptEncodingHeader("zstd"),
+ ECompression::ZSTD);
+
+ UNIT_ASSERT_EQUAL(
+ CompressionFromAcceptEncodingHeader("zstd, zlib"),
+ ECompression::ZSTD);
+
+ UNIT_ASSERT_EQUAL(
+ CompressionFromAcceptEncodingHeader(" ,, , zstd , zlib"),
+ ECompression::ZSTD);
+
+ UNIT_ASSERT_EQUAL(
+ CompressionFromAcceptEncodingHeader("br, deflate,lz4, zlib"),
+ ECompression::LZ4);
+ }
+
+ Y_UNIT_TEST(CompressionToStrFromStr) {
+ const std::array<ECompression, 5> algs = {{
+ ECompression::UNKNOWN,
+ ECompression::IDENTITY,
+ ECompression::ZLIB,
+ ECompression::LZ4,
+ ECompression::ZSTD,
+ }};
+
+ for (ECompression a : algs) {
+ TString str = (TStringBuilder() << a);
+ ECompression b = FromString<ECompression>(str);
+ UNIT_ASSERT_EQUAL(a, b);
+ }
+ }
+}
diff --git a/library/cpp/monlib/encode/fuzz/ya.make b/library/cpp/monlib/encode/fuzz/ya.make
new file mode 100644
index 0000000000..d9ca172bae
--- /dev/null
+++ b/library/cpp/monlib/encode/fuzz/ya.make
@@ -0,0 +1,5 @@
+RECURSE_ROOT_RELATIVE(
+ library/cpp/monlib/encode/json/fuzz
+ library/cpp/monlib/encode/prometheus/fuzz
+ library/cpp/monlib/encode/spack/fuzz
+)
diff --git a/library/cpp/monlib/encode/json/fuzz/main.cpp b/library/cpp/monlib/encode/json/fuzz/main.cpp
new file mode 100644
index 0000000000..4f40310e06
--- /dev/null
+++ b/library/cpp/monlib/encode/json/fuzz/main.cpp
@@ -0,0 +1,16 @@
+#include <library/cpp/monlib/encode/json/json.h>
+#include <library/cpp/monlib/encode/fake/fake.h>
+
+#include <util/generic/strbuf.h>
+
+
+extern "C" int LLVMFuzzerTestOneInput(const ui8* data, size_t size) {
+ auto encoder = NMonitoring::EncoderFake();
+
+ try {
+ NMonitoring::DecodeJson({reinterpret_cast<const char*>(data), size}, encoder.Get());
+ } catch (...) {
+ }
+
+ return 0;
+}
diff --git a/library/cpp/monlib/encode/json/fuzz/ya.make b/library/cpp/monlib/encode/json/fuzz/ya.make
new file mode 100644
index 0000000000..75baa77716
--- /dev/null
+++ b/library/cpp/monlib/encode/json/fuzz/ya.make
@@ -0,0 +1,19 @@
+FUZZ()
+
+OWNER(
+ g:solomon
+ msherbakov
+)
+
+PEERDIR(
+ library/cpp/monlib/encode/json
+ library/cpp/monlib/encode/fake
+)
+
+SIZE(MEDIUM)
+
+SRCS(
+ main.cpp
+)
+
+END()
diff --git a/library/cpp/monlib/encode/json/json.h b/library/cpp/monlib/encode/json/json.h
new file mode 100644
index 0000000000..21530f20c3
--- /dev/null
+++ b/library/cpp/monlib/encode/json/json.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <library/cpp/monlib/encode/encoder.h>
+#include <library/cpp/monlib/encode/format.h>
+
+
+class IOutputStream;
+
+namespace NMonitoring {
+
+ class TJsonDecodeError: public yexception {
+ };
+
+ IMetricEncoderPtr EncoderJson(IOutputStream* out, int indentation = 0);
+
+ /// Buffered encoder will merge series with same labels into one.
+ IMetricEncoderPtr BufferedEncoderJson(IOutputStream* out, int indentation = 0);
+
+ IMetricEncoderPtr EncoderCloudJson(IOutputStream* out,
+ int indentation = 0,
+ TStringBuf metricNameLabel = "name");
+
+ IMetricEncoderPtr BufferedEncoderCloudJson(IOutputStream* out,
+ int indentation = 0,
+ TStringBuf metricNameLabel = "name");
+
+ void DecodeJson(TStringBuf data, IMetricConsumer* c, TStringBuf metricNameLabel = "name");
+
+}
diff --git a/library/cpp/monlib/encode/json/json_decoder.cpp b/library/cpp/monlib/encode/json/json_decoder.cpp
new file mode 100644
index 0000000000..d44ff5fd28
--- /dev/null
+++ b/library/cpp/monlib/encode/json/json_decoder.cpp
@@ -0,0 +1,1162 @@
+#include "json.h"
+#include "typed_point.h"
+
+
+#include <library/cpp/monlib/exception/exception.h>
+#include <library/cpp/monlib/metrics/labels.h>
+#include <library/cpp/monlib/metrics/metric_value.h>
+
+#include <library/cpp/json/json_reader.h>
+
+#include <util/datetime/base.h>
+#include <util/string/cast.h>
+
+#include <limits>
+
+namespace NMonitoring {
+
+#define DECODE_ENSURE(COND, ...) MONLIB_ENSURE_EX(COND, TJsonDecodeError() << __VA_ARGS__)
+
+namespace {
+
+///////////////////////////////////////////////////////////////////////
+// THistogramBuilder
+///////////////////////////////////////////////////////////////////////
+class THistogramBuilder {
+public:
+ void AddBound(TBucketBound bound) {
+ if (!Bounds_.empty()) {
+ DECODE_ENSURE(Bounds_.back() < bound,
+ "non sorted bounds, " << Bounds_.back() <<
+ " >= " << bound);
+ }
+ Bounds_.push_back(bound);
+ }
+
+ void AddValue(TBucketValue value) {
+ Values_.push_back(value);
+ }
+
+ void AddInf(TBucketValue value) {
+ InfPresented_ = true;
+ InfValue_ = value;
+ }
+
+ IHistogramSnapshotPtr Build() {
+ if (InfPresented_) {
+ Bounds_.push_back(Max<TBucketBound>());
+ Values_.push_back(InfValue_);
+ }
+
+ auto snapshot = ExplicitHistogramSnapshot(Bounds_, Values_);
+
+ Bounds_.clear();
+ Values_.clear();
+ InfPresented_ = false;
+
+ return snapshot;
+ }
+
+ bool Empty() const noexcept {
+ return Bounds_.empty() && Values_.empty();
+ }
+
+ void Clear() {
+ Bounds_.clear();
+ Values_.clear();
+ }
+
+private:
+ TBucketBounds Bounds_;
+ TBucketValues Values_;
+
+ bool InfPresented_ = false;
+ TBucketValue InfValue_;
+};
+
+class TSummaryDoubleBuilder {
+public:
+ ISummaryDoubleSnapshotPtr Build() const {
+ return MakeIntrusive<TSummaryDoubleSnapshot>(Sum_, Min_, Max_, Last_, Count_);
+ }
+
+ void SetSum(double sum) {
+ Empty_ = false;
+ Sum_ = sum;
+ }
+
+ void SetMin(double min) {
+ Empty_ = false;
+ Min_ = min;
+ }
+
+ void SetMax(double max) {
+ Empty_ = false;
+ Max_ = max;
+ }
+
+ void SetLast(double last) {
+ Empty_ = false;
+ Last_ = last;
+ }
+
+ void SetCount(ui64 count) {
+ Empty_ = false;
+ Count_ = count;
+ }
+
+ void Clear() {
+ Empty_ = true;
+ Sum_ = 0;
+ Min_ = 0;
+ Max_ = 0;
+ Last_ = 0;
+ Count_ = 0;
+ }
+
+ bool Empty() const {
+ return Empty_;
+ }
+
+private:
+ double Sum_ = 0;
+ double Min_ = 0;
+ double Max_ = 0;
+ double Last_ = 0;
+ ui64 Count_ = 0;
+ bool Empty_ = true;
+};
+
+class TLogHistogramBuilder {
+public:
+ void SetBase(double base) {
+ DECODE_ENSURE(base > 0, "base must be positive");
+ Base_ = base;
+ }
+
+ void SetZerosCount(ui64 zerosCount) {
+ DECODE_ENSURE(zerosCount >= 0, "zeros count must be positive");
+ ZerosCount_ = zerosCount;
+ }
+
+ void SetStartPower(int startPower) {
+ StartPower_ = startPower;
+ }
+
+ void AddBucketValue(double value) {
+ DECODE_ENSURE(value > 0.0, "bucket values must be positive");
+ DECODE_ENSURE(value < std::numeric_limits<double>::max(), "bucket values must be finite");
+ Buckets_.push_back(value);
+ }
+
+ void Clear() {
+ Buckets_.clear();
+ Base_ = 1.5;
+ ZerosCount_ = 0;
+ StartPower_ = 0;
+ }
+
+ bool Empty() const {
+ return Buckets_.empty() && ZerosCount_ == 0;
+ }
+
+ TLogHistogramSnapshotPtr Build() {
+ return MakeIntrusive<TLogHistogramSnapshot>(Base_, ZerosCount_, StartPower_, std::move(Buckets_));
+ }
+
+private:
+ double Base_ = 1.5;
+ ui64 ZerosCount_ = 0;
+ int StartPower_ = 0;
+ TVector<double> Buckets_;
+};
+
+std::pair<double, bool> ParseSpecDouble(TStringBuf string) {
+ if (string == TStringBuf("nan") || string == TStringBuf("NaN")) {
+ return {std::numeric_limits<double>::quiet_NaN(), true};
+ } else if (string == TStringBuf("inf") || string == TStringBuf("Infinity")) {
+ return {std::numeric_limits<double>::infinity(), true};
+ } else if (string == TStringBuf("-inf") || string == TStringBuf("-Infinity")) {
+ return {-std::numeric_limits<double>::infinity(), true};
+ } else {
+ return {0, false};
+ }
+}
+
+///////////////////////////////////////////////////////////////////////
+// TMetricCollector
+///////////////////////////////////////////////////////////////////////
+struct TMetricCollector {
+ EMetricType Type = EMetricType::UNKNOWN;
+ TLabels Labels;
+ THistogramBuilder HistogramBuilder;
+ TSummaryDoubleBuilder SummaryBuilder;
+ TLogHistogramBuilder LogHistBuilder;
+ TTypedPoint LastPoint;
+ TVector<TTypedPoint> TimeSeries;
+
+ bool SeenTsOrValue = false;
+ bool SeenTimeseries = false;
+
+ void Clear() {
+ Type = EMetricType::UNKNOWN;
+ Labels.Clear();
+ SeenTsOrValue = false;
+ SeenTimeseries = false;
+ TimeSeries.clear();
+ LastPoint = {};
+ HistogramBuilder.Clear();
+ SummaryBuilder.Clear();
+ LogHistBuilder.Clear();
+ }
+
+ void AddLabel(const TLabel& label) {
+ Labels.Add(label.Name(), label.Value());
+ }
+
+ void SetLastTime(TInstant time) {
+ LastPoint.SetTime(time);
+ }
+
+ template <typename T>
+ void SetLastValue(T value) {
+ LastPoint.SetValue(value);
+ }
+
+ void SaveLastPoint() {
+ DECODE_ENSURE(LastPoint.GetTime() != TInstant::Zero(),
+ "cannot add point without or zero timestamp");
+ if (!HistogramBuilder.Empty()) {
+ auto histogram = HistogramBuilder.Build();
+ TimeSeries.emplace_back(LastPoint.GetTime(), histogram.Get());
+ } else if (!SummaryBuilder.Empty()) {
+ auto summary = SummaryBuilder.Build();
+ TimeSeries.emplace_back(LastPoint.GetTime(), summary.Get());
+ } else if (!LogHistBuilder.Empty()) {
+ auto logHist = LogHistBuilder.Build();
+ TimeSeries.emplace_back(LastPoint.GetTime(), logHist.Get());
+ } else {
+ TimeSeries.push_back(std::move(LastPoint));
+ }
+ }
+
+ template <typename TConsumer>
+ void Consume(TConsumer&& consumer) {
+ if (TimeSeries.empty()) {
+ const auto& p = LastPoint;
+ consumer(p.GetTime(), p.GetValueType(), p.GetValue());
+ } else {
+ for (const auto& p: TimeSeries) {
+ consumer(p.GetTime(), p.GetValueType(), p.GetValue());
+ }
+ }
+ }
+};
+
+struct TCommonParts {
+ TInstant CommonTime;
+ TLabels CommonLabels;
+};
+
+class IHaltableMetricConsumer: public IMetricConsumer {
+public:
+ virtual bool NeedToStop() const = 0;
+};
+
+// TODO(ivanzhukov@): check all states for cases when a json document is invalid
+// e.g. "metrics" or "commonLabels" keys are specified multiple times
+class TCommonPartsCollector: public IHaltableMetricConsumer {
+public:
+ TCommonParts&& CommonParts() {
+ return std::move(CommonParts_);
+ }
+
+private:
+ bool NeedToStop() const override {
+ return TInstant::Zero() != CommonParts_.CommonTime && !CommonParts_.CommonLabels.Empty();
+ }
+
+ void OnStreamBegin() override {
+ }
+
+ void OnStreamEnd() override {
+ }
+
+ void OnCommonTime(TInstant time) override {
+ CommonParts_.CommonTime = time;
+ }
+
+ void OnMetricBegin(EMetricType) override {
+ IsMetric_ = true;
+ }
+
+ void OnMetricEnd() override {
+ IsMetric_ = false;
+ }
+
+ void OnLabelsBegin() override {
+ }
+
+ void OnLabelsEnd() override {
+ }
+
+ void OnLabel(TStringBuf name, TStringBuf value) override {
+ if (!IsMetric_) {
+ CommonParts_.CommonLabels.Add(std::move(name), std::move(value));
+ }
+ }
+
+ void OnDouble(TInstant, double) override {
+ }
+
+ void OnInt64(TInstant, i64) override {
+ }
+
+ void OnUint64(TInstant, ui64) override {
+ }
+
+ void OnHistogram(TInstant, IHistogramSnapshotPtr) override {
+ }
+
+ void OnLogHistogram(TInstant, TLogHistogramSnapshotPtr) override {
+ }
+
+ void OnSummaryDouble(TInstant, ISummaryDoubleSnapshotPtr) override {
+ }
+
+private:
+ TCommonParts CommonParts_;
+ bool IsMetric_{false};
+};
+
+class TCommonPartsProxy: public IHaltableMetricConsumer {
+public:
+ TCommonPartsProxy(TCommonParts&& commonParts, IMetricConsumer* c)
+ : CommonParts_{std::move(commonParts)}
+ , Consumer_{c}
+ {}
+
+private:
+ bool NeedToStop() const override {
+ return false;
+ }
+
+ void OnStreamBegin() override {
+ Consumer_->OnStreamBegin();
+
+ if (!CommonParts_.CommonLabels.Empty()) {
+ Consumer_->OnLabelsBegin();
+
+ for (auto&& label : CommonParts_.CommonLabels) {
+ Consumer_->OnLabel(label.Name(), label.Value());
+ }
+
+ Consumer_->OnLabelsEnd();
+ }
+
+ if (TInstant::Zero() != CommonParts_.CommonTime) {
+ Consumer_->OnCommonTime(CommonParts_.CommonTime);
+ }
+ }
+
+ void OnStreamEnd() override {
+ Consumer_->OnStreamEnd();
+ }
+
+ void OnCommonTime(TInstant) override {
+ }
+
+ void OnMetricBegin(EMetricType type) override {
+ IsMetric_ = true;
+
+ Consumer_->OnMetricBegin(type);
+ }
+
+ void OnMetricEnd() override {
+ IsMetric_ = false;
+
+ Consumer_->OnMetricEnd();
+ }
+
+ void OnLabelsBegin() override {
+ if (IsMetric_) {
+ Consumer_->OnLabelsBegin();
+ }
+ }
+
+ void OnLabelsEnd() override {
+ if (IsMetric_) {
+ Consumer_->OnLabelsEnd();
+ }
+ }
+
+ void OnLabel(TStringBuf name, TStringBuf value) override {
+ if (IsMetric_) {
+ Consumer_->OnLabel(std::move(name), std::move(value));
+ }
+ }
+
+ void OnDouble(TInstant time, double value) override {
+ Consumer_->OnDouble(time, value);
+ }
+
+ void OnInt64(TInstant time, i64 value) override {
+ Consumer_->OnInt64(time, value);
+ }
+
+ void OnUint64(TInstant time, ui64 value) override {
+ Consumer_->OnUint64(time, value);
+ }
+
+ void OnHistogram(TInstant time, IHistogramSnapshotPtr snapshot) override {
+ Consumer_->OnHistogram(time, std::move(snapshot));
+ }
+
+ void OnLogHistogram(TInstant time, TLogHistogramSnapshotPtr snapshot) override {
+ Consumer_->OnLogHistogram(time, std::move(snapshot));
+ }
+
+ void OnSummaryDouble(TInstant time, ISummaryDoubleSnapshotPtr snapshot) override {
+ Consumer_->OnSummaryDouble(time, std::move(snapshot));
+ }
+
+private:
+ const TCommonParts CommonParts_;
+ IMetricConsumer* Consumer_;
+ bool IsMetric_{false};
+};
+
+///////////////////////////////////////////////////////////////////////
+// TDecoderJson
+///////////////////////////////////////////////////////////////////////
+class TDecoderJson final: public NJson::TJsonCallbacks {
+ struct TState {
+ enum EState {
+ ROOT_OBJECT = 0x01,
+
+ COMMON_LABELS,
+ COMMON_TS,
+ METRICS_ARRAY,
+
+ METRIC_OBJECT,
+ METRIC_NAME,
+ METRIC_LABELS,
+ METRIC_TYPE,
+ METRIC_MODE, // TODO: must be deleted
+ METRIC_TIMESERIES,
+ METRIC_TS,
+ METRIC_VALUE,
+ METRIC_HIST,
+ METRIC_HIST_BOUNDS,
+ METRIC_HIST_BUCKETS,
+ METRIC_HIST_INF,
+ METRIC_DSUMMARY,
+ METRIC_DSUMMARY_SUM,
+ METRIC_DSUMMARY_MIN,
+ METRIC_DSUMMARY_MAX,
+ METRIC_DSUMMARY_LAST,
+ METRIC_DSUMMARY_COUNT,
+ METRIC_LOG_HIST,
+ METRIC_LOG_HIST_BASE,
+ METRIC_LOG_HIST_ZEROS,
+ METRIC_LOG_HIST_START_POWER,
+ METRIC_LOG_HIST_BUCKETS,
+ };
+
+ constexpr EState Current() const noexcept {
+ return static_cast<EState>(State_ & 0xFF);
+ }
+
+ void ToNext(EState state) noexcept {
+ constexpr auto bitSize = 8 * sizeof(ui8);
+ State_ = (State_ << bitSize) | static_cast<ui8>(state);
+ }
+
+ void ToPrev() noexcept {
+ constexpr auto bitSize = 8 * sizeof(ui8);
+ State_ = State_ >> bitSize;
+ }
+
+ private:
+ ui64 State_ = static_cast<ui64>(ROOT_OBJECT);
+ };
+
+public:
+ TDecoderJson(TStringBuf data, IHaltableMetricConsumer* metricConsumer, TStringBuf metricNameLabel)
+ : Data_(data)
+ , MetricConsumer_(metricConsumer)
+ , MetricNameLabel_(metricNameLabel)
+ {
+ }
+
+private:
+#define PARSE_ENSURE(CONDITION, ...) \
+do { \
+if (Y_UNLIKELY(!(CONDITION))) { \
+ ErrorMsg_ = TStringBuilder() << __VA_ARGS__; \
+ return false; \
+} \
+} while (false)
+
+ bool OnInteger(long long value) override {
+ switch (State_.Current()) {
+ case TState::COMMON_TS:
+ PARSE_ENSURE(value >= 0, "unexpected negative number in a common timestamp: " << value);
+ MetricConsumer_->OnCommonTime(TInstant::Seconds(value));
+ State_.ToPrev();
+
+ if (MetricConsumer_->NeedToStop()) {
+ IsIntentionallyHalted_ = true;
+ return false;
+ }
+
+ break;
+
+ case TState::METRIC_TS:
+ PARSE_ENSURE(value >= 0, "unexpected negative number in a metric timestamp: " << value);
+ LastMetric_.SetLastTime(TInstant::Seconds(value));
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_VALUE:
+ LastMetric_.SetLastValue(static_cast<i64>(value));
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_HIST_BOUNDS:
+ LastMetric_.HistogramBuilder.AddBound(static_cast<double>(value));
+ break;
+
+ case TState::METRIC_HIST_BUCKETS:
+ PARSE_ENSURE(value >= 0 && static_cast<ui64>(value) <= Max<TBucketValues::value_type>(), "value is out of bounds " << value);
+ LastMetric_.HistogramBuilder.AddValue(value);
+ break;
+
+ case TState::METRIC_HIST_INF:
+ PARSE_ENSURE(value >= 0, "unexpected negative number in histogram inf: " << value);
+ LastMetric_.HistogramBuilder.AddInf(value);
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_DSUMMARY_COUNT:
+ LastMetric_.SummaryBuilder.SetCount(value);
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_DSUMMARY_SUM:
+ LastMetric_.SummaryBuilder.SetSum(value);
+ State_.ToPrev();
+ break;
+ case TState::METRIC_DSUMMARY_MIN:
+ LastMetric_.SummaryBuilder.SetMin(value);
+ State_.ToPrev();
+ break;
+ case TState::METRIC_DSUMMARY_MAX:
+ LastMetric_.SummaryBuilder.SetMax(value);
+ State_.ToPrev();
+ break;
+ case TState::METRIC_DSUMMARY_LAST:
+ LastMetric_.SummaryBuilder.SetLast(value);
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_LOG_HIST_BASE:
+ LastMetric_.LogHistBuilder.SetBase(value);
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_LOG_HIST_ZEROS:
+ LastMetric_.LogHistBuilder.SetZerosCount(value);
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_LOG_HIST_START_POWER:
+ LastMetric_.LogHistBuilder.SetStartPower(value);
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_LOG_HIST_BUCKETS:
+ LastMetric_.LogHistBuilder.AddBucketValue(value);
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ bool OnUInteger(unsigned long long value) override {
+ switch (State_.Current()) {
+ case TState::COMMON_TS:
+ MetricConsumer_->OnCommonTime(TInstant::Seconds(value));
+ State_.ToPrev();
+
+ if (MetricConsumer_->NeedToStop()) {
+ IsIntentionallyHalted_ = true;
+ return false;
+ }
+
+ break;
+
+ case TState::METRIC_TS:
+ LastMetric_.SetLastTime(TInstant::Seconds(value));
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_VALUE:
+ PARSE_ENSURE(value <= Max<ui64>(), "Metric value is out of bounds: " << value);
+ LastMetric_.SetLastValue(static_cast<ui64>(value));
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_HIST_BOUNDS:
+ LastMetric_.HistogramBuilder.AddBound(static_cast<double>(value));
+ break;
+
+ case TState::METRIC_HIST_BUCKETS:
+ PARSE_ENSURE(value <= Max<TBucketValues::value_type>(), "Histogram bucket value is out of bounds: " << value);
+ LastMetric_.HistogramBuilder.AddValue(value);
+ break;
+
+ case TState::METRIC_HIST_INF:
+ LastMetric_.HistogramBuilder.AddInf(value);
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_DSUMMARY_COUNT:
+ LastMetric_.SummaryBuilder.SetCount(value);
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_DSUMMARY_SUM:
+ LastMetric_.SummaryBuilder.SetSum(value);
+ State_.ToPrev();
+ break;
+ case TState::METRIC_DSUMMARY_MIN:
+ LastMetric_.SummaryBuilder.SetMin(value);
+ State_.ToPrev();
+ break;
+ case TState::METRIC_DSUMMARY_MAX:
+ LastMetric_.SummaryBuilder.SetMax(value);
+ State_.ToPrev();
+ break;
+ case TState::METRIC_DSUMMARY_LAST:
+ LastMetric_.SummaryBuilder.SetLast(value);
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_LOG_HIST_BASE:
+ LastMetric_.LogHistBuilder.SetBase(value);
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_LOG_HIST_ZEROS:
+ LastMetric_.LogHistBuilder.SetZerosCount(value);
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_LOG_HIST_START_POWER:
+ LastMetric_.LogHistBuilder.SetStartPower(value);
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_LOG_HIST_BUCKETS:
+ LastMetric_.LogHistBuilder.AddBucketValue(value);
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ bool OnDouble(double value) override {
+ switch (State_.Current()) {
+ case TState::METRIC_VALUE:
+ LastMetric_.SetLastValue(value);
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_HIST_BOUNDS:
+ LastMetric_.HistogramBuilder.AddBound(value);
+ break;
+
+ case TState::METRIC_DSUMMARY_SUM:
+ LastMetric_.SummaryBuilder.SetSum(value);
+ State_.ToPrev();
+ break;
+ case TState::METRIC_DSUMMARY_MIN:
+ LastMetric_.SummaryBuilder.SetMin(value);
+ State_.ToPrev();
+ break;
+ case TState::METRIC_DSUMMARY_MAX:
+ LastMetric_.SummaryBuilder.SetMax(value);
+ State_.ToPrev();
+ break;
+ case TState::METRIC_DSUMMARY_LAST:
+ LastMetric_.SummaryBuilder.SetLast(value);
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_LOG_HIST_BASE:
+ LastMetric_.LogHistBuilder.SetBase(value);
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_LOG_HIST_BUCKETS:
+ LastMetric_.LogHistBuilder.AddBucketValue(value);
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ bool OnString(const TStringBuf& value) override {
+ switch (State_.Current()) {
+ case TState::COMMON_LABELS:
+ PARSE_ENSURE(!LastLabelName_.empty(), "empty label name in common labels");
+ MetricConsumer_->OnLabel(LastLabelName_, TString{value});
+ break;
+
+ case TState::METRIC_LABELS:
+ PARSE_ENSURE(!LastLabelName_.empty(), "empty label name in metric labels");
+ LastMetric_.Labels.Add(LastLabelName_, TString{value});
+ break;
+
+ case TState::METRIC_NAME:
+ PARSE_ENSURE(!value.empty(), "empty metric name");
+ LastMetric_.Labels.Add(MetricNameLabel_, TString{value});
+ State_.ToPrev();
+ break;
+
+ case TState::COMMON_TS:
+ MetricConsumer_->OnCommonTime(TInstant::ParseIso8601(value));
+ State_.ToPrev();
+
+ if (MetricConsumer_->NeedToStop()) {
+ IsIntentionallyHalted_ = true;
+ return false;
+ }
+
+ break;
+
+ case TState::METRIC_TS:
+ LastMetric_.SetLastTime(TInstant::ParseIso8601(value));
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_VALUE:
+ if (auto [doubleValue, ok] = ParseSpecDouble(value); ok) {
+ LastMetric_.SetLastValue(doubleValue);
+ } else {
+ return false;
+ }
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_TYPE:
+ LastMetric_.Type = MetricTypeFromStr(value);
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_MODE:
+ if (value == TStringBuf("deriv")) {
+ LastMetric_.Type = EMetricType::RATE;
+ }
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_DSUMMARY_SUM:
+ if (auto [doubleValue, ok] = ParseSpecDouble(value); ok) {
+ LastMetric_.SummaryBuilder.SetSum(doubleValue);
+ } else {
+ return false;
+ }
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_DSUMMARY_MIN:
+ if (auto [doubleValue, ok] = ParseSpecDouble(value); ok) {
+ LastMetric_.SummaryBuilder.SetMin(doubleValue);
+ } else {
+ return false;
+ }
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_DSUMMARY_MAX:
+ if (auto [doubleValue, ok] = ParseSpecDouble(value); ok) {
+ LastMetric_.SummaryBuilder.SetMax(doubleValue);
+ } else {
+ return false;
+ }
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_DSUMMARY_LAST:
+ if (auto [doubleValue, ok] = ParseSpecDouble(value); ok) {
+ LastMetric_.SummaryBuilder.SetLast(doubleValue);
+ } else {
+ return false;
+ }
+ State_.ToPrev();
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ bool OnMapKey(const TStringBuf& key) override {
+ switch (State_.Current()) {
+ case TState::ROOT_OBJECT:
+ if (key == TStringBuf("commonLabels") || key == TStringBuf("labels")) {
+ State_.ToNext(TState::COMMON_LABELS);
+ } else if (key == TStringBuf("ts")) {
+ State_.ToNext(TState::COMMON_TS);
+ } else if (key == TStringBuf("sensors") || key == TStringBuf("metrics")) {
+ State_.ToNext(TState::METRICS_ARRAY);
+ }
+ break;
+
+ case TState::COMMON_LABELS:
+ case TState::METRIC_LABELS:
+ LastLabelName_ = key;
+ break;
+
+ case TState::METRIC_OBJECT:
+ if (key == TStringBuf("labels")) {
+ State_.ToNext(TState::METRIC_LABELS);
+ } else if (key == TStringBuf("name")) {
+ State_.ToNext(TState::METRIC_NAME);
+ } else if (key == TStringBuf("ts")) {
+ PARSE_ENSURE(!LastMetric_.SeenTimeseries,
+ "mixed timeseries and ts attributes");
+ LastMetric_.SeenTsOrValue = true;
+ State_.ToNext(TState::METRIC_TS);
+ } else if (key == TStringBuf("value")) {
+ PARSE_ENSURE(!LastMetric_.SeenTimeseries,
+ "mixed timeseries and value attributes");
+ LastMetric_.SeenTsOrValue = true;
+ State_.ToNext(TState::METRIC_VALUE);
+ } else if (key == TStringBuf("timeseries")) {
+ PARSE_ENSURE(!LastMetric_.SeenTsOrValue,
+ "mixed timeseries and ts/value attributes");
+ LastMetric_.SeenTimeseries = true;
+ State_.ToNext(TState::METRIC_TIMESERIES);
+ } else if (key == TStringBuf("mode")) {
+ State_.ToNext(TState::METRIC_MODE);
+ } else if (key == TStringBuf("kind") || key == TStringBuf("type")) {
+ State_.ToNext(TState::METRIC_TYPE);
+ } else if (key == TStringBuf("hist")) {
+ State_.ToNext(TState::METRIC_HIST);
+ } else if (key == TStringBuf("summary")) {
+ State_.ToNext(TState::METRIC_DSUMMARY);
+ } else if (key == TStringBuf("log_hist")) {
+ State_.ToNext(TState::METRIC_LOG_HIST);
+ } else if (key == TStringBuf("memOnly")) {
+ // deprecated. Skip it without errors for backward compatibility
+ } else {
+ ErrorMsg_ = TStringBuilder() << "unexpected key \"" << key << "\" in a metric schema";
+ return false;
+ }
+ break;
+
+ case TState::METRIC_TIMESERIES:
+ if (key == TStringBuf("ts")) {
+ State_.ToNext(TState::METRIC_TS);
+ } else if (key == TStringBuf("value")) {
+ State_.ToNext(TState::METRIC_VALUE);
+ } else if (key == TStringBuf("hist")) {
+ State_.ToNext(TState::METRIC_HIST);
+ } else if (key == TStringBuf("summary")) {
+ State_.ToNext(TState::METRIC_DSUMMARY);
+ } else if (key == TStringBuf("log_hist")) {
+ State_.ToNext(TState::METRIC_LOG_HIST);
+ }
+ break;
+
+ case TState::METRIC_HIST:
+ if (key == TStringBuf("bounds")) {
+ State_.ToNext(TState::METRIC_HIST_BOUNDS);
+ } else if (key == TStringBuf("buckets")) {
+ State_.ToNext(TState::METRIC_HIST_BUCKETS);
+ } else if (key == TStringBuf("inf")) {
+ State_.ToNext(TState::METRIC_HIST_INF);
+ }
+ break;
+
+ case TState::METRIC_LOG_HIST:
+ if (key == TStringBuf("base")) {
+ State_.ToNext(TState::METRIC_LOG_HIST_BASE);
+ } else if (key == TStringBuf("zeros_count")) {
+ State_.ToNext(TState::METRIC_LOG_HIST_ZEROS);
+ } else if (key == TStringBuf("start_power")) {
+ State_.ToNext(TState::METRIC_LOG_HIST_START_POWER);
+ } else if (key == TStringBuf("buckets")) {
+ State_.ToNext(TState::METRIC_LOG_HIST_BUCKETS);
+ }
+ break;
+
+ case TState::METRIC_DSUMMARY:
+ if (key == TStringBuf("sum")) {
+ State_.ToNext(TState::METRIC_DSUMMARY_SUM);
+ } else if (key == TStringBuf("min")) {
+ State_.ToNext(TState::METRIC_DSUMMARY_MIN);
+ } else if (key == TStringBuf("max")) {
+ State_.ToNext(TState::METRIC_DSUMMARY_MAX);
+ } else if (key == TStringBuf("last")) {
+ State_.ToNext(TState::METRIC_DSUMMARY_LAST);
+ } else if (key == TStringBuf("count")) {
+ State_.ToNext(TState::METRIC_DSUMMARY_COUNT);
+ }
+
+ break;
+
+
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ bool OnOpenMap() override {
+ switch (State_.Current()) {
+ case TState::ROOT_OBJECT:
+ MetricConsumer_->OnStreamBegin();
+ break;
+
+ case TState::COMMON_LABELS:
+ MetricConsumer_->OnLabelsBegin();
+ break;
+
+ case TState::METRICS_ARRAY:
+ State_.ToNext(TState::METRIC_OBJECT);
+ LastMetric_.Clear();
+ break;
+
+ default:
+ break;
+ }
+ return true;
+ }
+
+ bool OnCloseMap() override {
+ switch (State_.Current()) {
+ case TState::ROOT_OBJECT:
+ MetricConsumer_->OnStreamEnd();
+ break;
+
+ case TState::METRIC_LABELS:
+ State_.ToPrev();
+ break;
+
+ case TState::COMMON_LABELS:
+ MetricConsumer_->OnLabelsEnd();
+ State_.ToPrev();
+
+ if (MetricConsumer_->NeedToStop()) {
+ IsIntentionallyHalted_ = true;
+ return false;
+ }
+
+ break;
+
+ case TState::METRIC_OBJECT:
+ ConsumeMetric();
+ State_.ToPrev();
+ break;
+
+ case TState::METRIC_TIMESERIES:
+ LastMetric_.SaveLastPoint();
+ break;
+
+ case TState::METRIC_HIST:
+ case TState::METRIC_DSUMMARY:
+ case TState::METRIC_LOG_HIST:
+ State_.ToPrev();
+ break;
+
+ default:
+ break;
+ }
+ return true;
+ }
+
+ bool OnOpenArray() override {
+ auto currentState = State_.Current();
+ PARSE_ENSURE(
+ currentState == TState::METRICS_ARRAY ||
+ currentState == TState::METRIC_TIMESERIES ||
+ currentState == TState::METRIC_HIST_BOUNDS ||
+ currentState == TState::METRIC_HIST_BUCKETS ||
+ currentState == TState::METRIC_LOG_HIST_BUCKETS,
+ "unexpected array begin");
+ return true;
+ }
+
+ bool OnCloseArray() override {
+ switch (State_.Current()) {
+ case TState::METRICS_ARRAY:
+ case TState::METRIC_TIMESERIES:
+ case TState::METRIC_HIST_BOUNDS:
+ case TState::METRIC_HIST_BUCKETS:
+ case TState::METRIC_LOG_HIST_BUCKETS:
+ State_.ToPrev();
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ void OnError(size_t off, TStringBuf reason) override {
+ if (IsIntentionallyHalted_) {
+ return;
+ }
+
+ size_t snippetBeg = (off < 20) ? 0 : (off - 20);
+ TStringBuf snippet = Data_.SubStr(snippetBeg, 40);
+
+ throw TJsonDecodeError()
+ << "cannot parse JSON, error at: " << off
+ << ", reason: " << (ErrorMsg_.empty() ? reason : TStringBuf{ErrorMsg_})
+ << "\nsnippet: ..." << snippet << "...";
+ }
+
+ bool OnEnd() override {
+ return true;
+ }
+
+ void ConsumeMetric() {
+ // for backwad compatibility all unknown metrics treated as gauges
+ if (LastMetric_.Type == EMetricType::UNKNOWN) {
+ if (LastMetric_.HistogramBuilder.Empty()) {
+ LastMetric_.Type = EMetricType::GAUGE;
+ } else {
+ LastMetric_.Type = EMetricType::HIST;
+ }
+ }
+
+ // (1) begin metric
+ MetricConsumer_->OnMetricBegin(LastMetric_.Type);
+
+ // (2) labels
+ if (!LastMetric_.Labels.empty()) {
+ MetricConsumer_->OnLabelsBegin();
+ for (auto&& label : LastMetric_.Labels) {
+ MetricConsumer_->OnLabel(label.Name(), label.Value());
+ }
+ MetricConsumer_->OnLabelsEnd();
+ }
+
+ // (3) values
+ switch (LastMetric_.Type) {
+ case EMetricType::GAUGE:
+ LastMetric_.Consume([this](TInstant time, EMetricValueType valueType, TMetricValue value) {
+ MetricConsumer_->OnDouble(time, value.AsDouble(valueType));
+ });
+ break;
+
+ case EMetricType::IGAUGE:
+ LastMetric_.Consume([this](TInstant time, EMetricValueType valueType, TMetricValue value) {
+ MetricConsumer_->OnInt64(time, value.AsInt64(valueType));
+ });
+ break;
+
+ case EMetricType::COUNTER:
+ case EMetricType::RATE:
+ LastMetric_.Consume([this](TInstant time, EMetricValueType valueType, TMetricValue value) {
+ MetricConsumer_->OnUint64(time, value.AsUint64(valueType));
+ });
+ break;
+
+ case EMetricType::HIST:
+ case EMetricType::HIST_RATE:
+ if (LastMetric_.TimeSeries.empty()) {
+ auto time = LastMetric_.LastPoint.GetTime();
+ auto histogram = LastMetric_.HistogramBuilder.Build();
+ MetricConsumer_->OnHistogram(time, histogram);
+ } else {
+ for (const auto& p : LastMetric_.TimeSeries) {
+ DECODE_ENSURE(p.GetValueType() == EMetricValueType::HISTOGRAM, "Value is not a histogram");
+ MetricConsumer_->OnHistogram(p.GetTime(), p.GetValue().AsHistogram());
+ }
+ }
+ break;
+
+ case EMetricType::DSUMMARY:
+ if (LastMetric_.TimeSeries.empty()) {
+ auto time = LastMetric_.LastPoint.GetTime();
+ auto summary = LastMetric_.SummaryBuilder.Build();
+ MetricConsumer_->OnSummaryDouble(time, summary);
+ } else {
+ for (const auto& p : LastMetric_.TimeSeries) {
+ DECODE_ENSURE(p.GetValueType() == EMetricValueType::SUMMARY, "Value is not a summary");
+ MetricConsumer_->OnSummaryDouble(p.GetTime(), p.GetValue().AsSummaryDouble());
+ }
+ }
+ break;
+
+ case EMetricType::LOGHIST:
+ if (LastMetric_.TimeSeries.empty()) {
+ auto time = LastMetric_.LastPoint.GetTime();
+ auto logHist = LastMetric_.LogHistBuilder.Build();
+ MetricConsumer_->OnLogHistogram(time, logHist);
+ } else {
+ for (const auto& p : LastMetric_.TimeSeries) {
+ DECODE_ENSURE(p.GetValueType() == EMetricValueType::LOGHISTOGRAM, "Value is not a log_histogram");
+ MetricConsumer_->OnLogHistogram(p.GetTime(), p.GetValue().AsLogHistogram());
+ }
+ }
+ break;
+
+ case EMetricType::UNKNOWN:
+ // TODO: output metric labels
+ ythrow yexception() << "unknown metric type";
+ }
+
+ // (4) end metric
+ MetricConsumer_->OnMetricEnd();
+ }
+
+private:
+ TStringBuf Data_;
+ IHaltableMetricConsumer* MetricConsumer_;
+ TString MetricNameLabel_;
+ TState State_;
+ TString LastLabelName_;
+ TMetricCollector LastMetric_;
+ TString ErrorMsg_;
+ bool IsIntentionallyHalted_{false};
+};
+
+} // namespace
+
+void DecodeJson(TStringBuf data, IMetricConsumer* c, TStringBuf metricNameLabel) {
+ TCommonPartsCollector commonPartsCollector;
+ {
+ TMemoryInput memIn(data);
+ TDecoderJson decoder(data, &commonPartsCollector, metricNameLabel);
+ // no need to check a return value. If there is an error, a TJsonDecodeError is thrown
+ NJson::ReadJson(&memIn, &decoder);
+ }
+
+ TCommonPartsProxy commonPartsProxy(std::move(commonPartsCollector.CommonParts()), c);
+ {
+ TMemoryInput memIn(data);
+ TDecoderJson decoder(data, &commonPartsProxy, metricNameLabel);
+ // no need to check a return value. If there is an error, a TJsonDecodeError is thrown
+ NJson::ReadJson(&memIn, &decoder);
+ }
+}
+
+#undef DECODE_ENSURE
+
+}
diff --git a/library/cpp/monlib/encode/json/json_decoder_ut.cpp b/library/cpp/monlib/encode/json/json_decoder_ut.cpp
new file mode 100644
index 0000000000..4464e1d26a
--- /dev/null
+++ b/library/cpp/monlib/encode/json/json_decoder_ut.cpp
@@ -0,0 +1,179 @@
+#include "json_decoder.cpp"
+
+#include <library/cpp/monlib/consumers/collecting_consumer.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <array>
+
+
+using namespace NMonitoring;
+
+enum EJsonPart : ui8 {
+ METRICS = 0,
+ COMMON_TS = 1,
+ COMMON_LABELS = 2,
+};
+
+constexpr std::array<TStringBuf, 3> JSON_PARTS = {
+ TStringBuf(R"("metrics": [{
+ "labels": { "key": "value" },
+ "type": "GAUGE",
+ "value": 123
+ }])"),
+
+ TStringBuf(R"("ts": 1)"),
+
+ TStringBuf(R"("commonLabels": {
+ "key1": "value1",
+ "key2": "value2"
+ })"),
+};
+
+TString BuildJson(std::initializer_list<EJsonPart> parts) {
+ TString data = "{";
+
+ for (auto it = parts.begin(); it != parts.end(); ++it) {
+ data += JSON_PARTS[*it];
+
+ if (it + 1 != parts.end()) {
+ data += ",";
+ }
+ }
+
+ data += "}";
+ return data;
+}
+
+void ValidateCommonParts(TCommonParts&& commonParts, bool checkLabels, bool checkTs) {
+ if (checkTs) {
+ UNIT_ASSERT_VALUES_EQUAL(commonParts.CommonTime.MilliSeconds(), 1000);
+ }
+
+ if (checkLabels) {
+ auto& labels = commonParts.CommonLabels;
+ UNIT_ASSERT_VALUES_EQUAL(labels.Size(), 2);
+ UNIT_ASSERT(labels.Has(TStringBuf("key1")));
+ UNIT_ASSERT(labels.Has(TStringBuf("key2")));
+ UNIT_ASSERT_VALUES_EQUAL(labels.Get(TStringBuf("key1")).value()->Value(), "value1");
+ UNIT_ASSERT_VALUES_EQUAL(labels.Get(TStringBuf("key2")).value()->Value(), "value2");
+ }
+}
+
+void ValidateMetrics(const TVector<TMetricData>& metrics) {
+ UNIT_ASSERT_VALUES_EQUAL(metrics.size(), 1);
+
+ auto& m = metrics[0];
+ UNIT_ASSERT_VALUES_EQUAL(m.Kind, EMetricType::GAUGE);
+ auto& l = m.Labels;
+ UNIT_ASSERT_VALUES_EQUAL(l.Size(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(l.Get(0)->Name(), "key");
+ UNIT_ASSERT_VALUES_EQUAL(l.Get(0)->Value(), "value");
+
+ UNIT_ASSERT_VALUES_EQUAL(m.Values->Size(), 1);
+ UNIT_ASSERT_VALUES_EQUAL((*m.Values)[0].GetValue().AsDouble(), 123);
+}
+
+void CheckCommonPartsCollector(TString data, bool shouldBeStopped, bool checkLabels = true, bool checkTs = true, TStringBuf metricNameLabel = "name") {
+ TCommonPartsCollector commonPartsCollector;
+ TMemoryInput memIn(data);
+ TDecoderJson decoder(data, &commonPartsCollector, metricNameLabel);
+
+ bool isOk{false};
+ UNIT_ASSERT_NO_EXCEPTION(isOk = NJson::ReadJson(&memIn, &decoder));
+ UNIT_ASSERT_VALUES_EQUAL(isOk, !shouldBeStopped);
+
+ ValidateCommonParts(commonPartsCollector.CommonParts(), checkLabels, checkTs);
+}
+
+Y_UNIT_TEST_SUITE(TJsonDecoderTest) {
+ Y_UNIT_TEST(FullCommonParts) {
+ CheckCommonPartsCollector(BuildJson({COMMON_LABELS, COMMON_TS, METRICS}), true);
+ CheckCommonPartsCollector(BuildJson({COMMON_TS, COMMON_LABELS, METRICS}), true);
+
+ CheckCommonPartsCollector(BuildJson({METRICS, COMMON_TS, COMMON_LABELS}), true);
+ CheckCommonPartsCollector(BuildJson({METRICS, COMMON_LABELS, COMMON_TS}), true);
+
+ CheckCommonPartsCollector(BuildJson({COMMON_LABELS, METRICS, COMMON_TS}), true);
+ CheckCommonPartsCollector(BuildJson({COMMON_TS, METRICS, COMMON_LABELS}), true);
+ }
+
+ Y_UNIT_TEST(PartialCommonParts) {
+ CheckCommonPartsCollector(BuildJson({COMMON_TS, METRICS}), false, false, true);
+ CheckCommonPartsCollector(BuildJson({COMMON_LABELS, METRICS}), false, true, false);
+
+ CheckCommonPartsCollector(BuildJson({METRICS, COMMON_LABELS}), false, true, false);
+ CheckCommonPartsCollector(BuildJson({METRICS, COMMON_TS}), false, false, true);
+
+ CheckCommonPartsCollector(BuildJson({METRICS}), false, false, false);
+ }
+
+ Y_UNIT_TEST(CheckCommonPartsAndMetrics) {
+ auto data = BuildJson({COMMON_LABELS, COMMON_TS, METRICS});
+ TCollectingConsumer collector;
+
+ DecodeJson(data, &collector);
+
+ TCommonParts commonParts;
+ commonParts.CommonTime = collector.CommonTime;
+ commonParts.CommonLabels = collector.CommonLabels;
+
+ ValidateCommonParts(std::move(commonParts), true, true);
+ ValidateMetrics(collector.Metrics);
+ }
+
+ Y_UNIT_TEST(CanParseHistogramsWithInf) {
+ const char* metricsData = R"({
+"metrics":
+ [
+ {
+ "hist": {
+ "bounds": [
+ 10
+ ],
+ "buckets": [
+ 11
+ ],
+ "inf": 12
+ },
+ "name":"s1",
+ "type": "HIST_RATE"
+ },
+ {
+ "hist": {
+ "bounds": [
+ 20
+ ],
+ "buckets": [
+ 21
+ ]
+ },
+ "name":"s2",
+ "type":"HIST_RATE"
+ }
+ ]
+})";
+ TCollectingConsumer consumer(false);
+ DecodeJson(metricsData, &consumer);
+
+ UNIT_ASSERT_VALUES_EQUAL(consumer.Metrics.size(), 2);
+ {
+ const auto& m = consumer.Metrics[0];
+ UNIT_ASSERT_VALUES_EQUAL(m.Kind, EMetricType::HIST_RATE);
+ UNIT_ASSERT_VALUES_EQUAL(m.Values->Size(), 1);
+ const auto* histogram = (*m.Values)[0].GetValue().AsHistogram();
+ UNIT_ASSERT_VALUES_EQUAL(histogram->Count(), 2);
+ UNIT_ASSERT_VALUES_EQUAL(histogram->UpperBound(1), Max<TBucketBound>());
+ UNIT_ASSERT_VALUES_EQUAL(histogram->Value(0), 11);
+ UNIT_ASSERT_VALUES_EQUAL(histogram->Value(1), 12);
+ }
+ {
+ const auto& m = consumer.Metrics[1];
+ UNIT_ASSERT_VALUES_EQUAL(m.Kind, EMetricType::HIST_RATE);
+ UNIT_ASSERT_VALUES_EQUAL(m.Values->Size(), 1);
+ const auto* histogram = (*m.Values)[0].GetValue().AsHistogram();
+ UNIT_ASSERT_VALUES_EQUAL(histogram->Count(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(histogram->UpperBound(0), 20);
+ UNIT_ASSERT_VALUES_EQUAL(histogram->Value(0), 21);
+ }
+ }
+}
diff --git a/library/cpp/monlib/encode/json/json_encoder.cpp b/library/cpp/monlib/encode/json/json_encoder.cpp
new file mode 100644
index 0000000000..20d2bb6283
--- /dev/null
+++ b/library/cpp/monlib/encode/json/json_encoder.cpp
@@ -0,0 +1,556 @@
+#include "json.h"
+#include "typed_point.h"
+
+#include <library/cpp/monlib/encode/buffered/buffered_encoder_base.h>
+#include <library/cpp/monlib/encode/encoder_state.h>
+#include <library/cpp/monlib/metrics/metric.h>
+#include <library/cpp/monlib/metrics/metric_value.h>
+#include <library/cpp/monlib/metrics/labels.h>
+
+#include <library/cpp/json/writer/json.h>
+
+#include <util/charset/utf8.h>
+#include <util/generic/algorithm.h>
+
+namespace NMonitoring {
+ namespace {
+ enum class EJsonStyle {
+ Solomon,
+ Cloud
+ };
+
+ ///////////////////////////////////////////////////////////////////////
+ // TJsonWriter
+ ///////////////////////////////////////////////////////////////////////
+ class TJsonWriter {
+ public:
+ TJsonWriter(IOutputStream* out, int indentation, EJsonStyle style, TStringBuf metricNameLabel)
+ : Buf_(NJsonWriter::HEM_UNSAFE, out)
+ , Style_(style)
+ , MetricNameLabel_(metricNameLabel)
+ , CurrentMetricName_()
+ {
+ Buf_.SetIndentSpaces(indentation);
+ Buf_.SetWriteNanAsString();
+ }
+
+ void WriteTime(TInstant time) {
+ if (time != TInstant::Zero()) {
+ Buf_.WriteKey(TStringBuf("ts"));
+ if (Style_ == EJsonStyle::Solomon) {
+ Buf_.WriteULongLong(time.Seconds());
+ } else {
+ Buf_.WriteString(time.ToString());
+ }
+ }
+ }
+
+ void WriteValue(double value) {
+ Buf_.WriteKey(TStringBuf("value"));
+ Buf_.WriteDouble(value);
+ }
+
+ void WriteValue(i64 value) {
+ Buf_.WriteKey(TStringBuf("value"));
+ Buf_.WriteLongLong(value);
+ }
+
+ void WriteValue(ui64 value) {
+ Buf_.WriteKey(TStringBuf("value"));
+ Buf_.WriteULongLong(value);
+ }
+
+ void WriteValue(IHistogramSnapshot* s) {
+ Y_ENSURE(Style_ == EJsonStyle::Solomon);
+
+ Buf_.WriteKey(TStringBuf("hist"));
+ Buf_.BeginObject();
+ if (ui32 count = s->Count()) {
+ bool hasInf = (s->UpperBound(count - 1) == Max<double>());
+ if (hasInf) {
+ count--;
+ }
+
+ Buf_.WriteKey(TStringBuf("bounds"));
+ Buf_.BeginList();
+ for (ui32 i = 0; i < count; i++) {
+ Buf_.WriteDouble(s->UpperBound(i));
+ }
+ Buf_.EndList();
+
+ Buf_.WriteKey(TStringBuf("buckets"));
+ Buf_.BeginList();
+ for (ui32 i = 0; i < count; i++) {
+ Buf_.WriteULongLong(s->Value(i));
+ }
+ Buf_.EndList();
+
+ if (hasInf) {
+ Buf_.WriteKey(TStringBuf("inf"));
+ Buf_.WriteULongLong(s->Value(count));
+ }
+ }
+ Buf_.EndObject();
+ }
+
+ void WriteValue(ISummaryDoubleSnapshot* s) {
+ Y_ENSURE(Style_ == EJsonStyle::Solomon);
+
+ Buf_.WriteKey(TStringBuf("summary"));
+ Buf_.BeginObject();
+
+ Buf_.WriteKey(TStringBuf("sum"));
+ Buf_.WriteDouble(s->GetSum());
+
+ Buf_.WriteKey(TStringBuf("min"));
+ Buf_.WriteDouble(s->GetMin());
+
+ Buf_.WriteKey(TStringBuf("max"));
+ Buf_.WriteDouble(s->GetMax());
+
+ Buf_.WriteKey(TStringBuf("last"));
+ Buf_.WriteDouble(s->GetLast());
+
+ Buf_.WriteKey(TStringBuf("count"));
+ Buf_.WriteULongLong(s->GetCount());
+
+ Buf_.EndObject();
+ }
+
+ void WriteValue(TLogHistogramSnapshot* s) {
+ Y_ENSURE(Style_ == EJsonStyle::Solomon);
+
+ Buf_.WriteKey(TStringBuf("log_hist"));
+ Buf_.BeginObject();
+
+ Buf_.WriteKey(TStringBuf("base"));
+ Buf_.WriteDouble(s->Base());
+
+ Buf_.WriteKey(TStringBuf("zeros_count"));
+ Buf_.WriteULongLong(s->ZerosCount());
+
+ Buf_.WriteKey(TStringBuf("start_power"));
+ Buf_.WriteInt(s->StartPower());
+
+ Buf_.WriteKey(TStringBuf("buckets"));
+ Buf_.BeginList();
+ for (size_t i = 0; i < s->Count(); ++i) {
+ Buf_.WriteDouble(s->Bucket(i));
+ }
+ Buf_.EndList();
+
+ Buf_.EndObject();
+ }
+
+ void WriteValue(EMetricValueType type, TMetricValue value) {
+ switch (type) {
+ case EMetricValueType::DOUBLE:
+ WriteValue(value.AsDouble());
+ break;
+
+ case EMetricValueType::INT64:
+ WriteValue(value.AsInt64());
+ break;
+
+ case EMetricValueType::UINT64:
+ WriteValue(value.AsUint64());
+ break;
+
+ case EMetricValueType::HISTOGRAM:
+ WriteValue(value.AsHistogram());
+ break;
+
+ case EMetricValueType::SUMMARY:
+ WriteValue(value.AsSummaryDouble());
+ break;
+
+ case EMetricValueType::LOGHISTOGRAM:
+ WriteValue(value.AsLogHistogram());
+ break;
+
+ case EMetricValueType::UNKNOWN:
+ ythrow yexception() << "unknown metric value type";
+ }
+ }
+
+ void WriteLabel(TStringBuf name, TStringBuf value) {
+ Y_ENSURE(IsUtf(name), "label name is not valid UTF-8 string");
+ Y_ENSURE(IsUtf(value), "label value is not valid UTF-8 string");
+ if (Style_ == EJsonStyle::Cloud && name == MetricNameLabel_) {
+ CurrentMetricName_ = value;
+ } else {
+ Buf_.WriteKey(name);
+ Buf_.WriteString(value);
+ }
+ }
+
+ void WriteMetricType(EMetricType type) {
+ if (Style_ == EJsonStyle::Cloud) {
+ Buf_.WriteKey("type");
+ Buf_.WriteString(MetricTypeToCloudStr(type));
+ } else {
+ Buf_.WriteKey("kind");
+ Buf_.WriteString(MetricTypeToStr(type));
+ }
+ }
+
+ void WriteName() {
+ if (Style_ != EJsonStyle::Cloud) {
+ return;
+ }
+ if (CurrentMetricName_.Empty()) {
+ ythrow yexception() << "label '" << MetricNameLabel_ << "' is not defined";
+ }
+ Buf_.WriteKey("name");
+ Buf_.WriteString(CurrentMetricName_);
+ CurrentMetricName_.clear();
+ }
+
+ private:
+ static TStringBuf MetricTypeToCloudStr(EMetricType type) {
+ switch (type) {
+ case EMetricType::GAUGE:
+ return TStringBuf("DGAUGE");
+ case EMetricType::COUNTER:
+ return TStringBuf("COUNTER");
+ case EMetricType::RATE:
+ return TStringBuf("RATE");
+ case EMetricType::IGAUGE:
+ return TStringBuf("IGAUGE");
+ default:
+ ythrow yexception() << "metric type '" << type << "' is not supported by cloud json format";
+ }
+ }
+
+ protected:
+ NJsonWriter::TBuf Buf_;
+ EJsonStyle Style_;
+ TString MetricNameLabel_;
+ TString CurrentMetricName_;
+ };
+
+ ///////////////////////////////////////////////////////////////////////
+ // TEncoderJson
+ ///////////////////////////////////////////////////////////////////////
+ class TEncoderJson final: public IMetricEncoder, public TJsonWriter {
+ public:
+ TEncoderJson(IOutputStream* out, int indentation, EJsonStyle style, TStringBuf metricNameLabel)
+ : TJsonWriter{out, indentation, style, metricNameLabel}
+ {
+ }
+
+ ~TEncoderJson() override {
+ Close();
+ }
+
+ private:
+ void OnStreamBegin() override {
+ State_.Expect(TEncoderState::EState::ROOT);
+ Buf_.BeginObject();
+ }
+
+ void OnStreamEnd() override {
+ State_.Expect(TEncoderState::EState::ROOT);
+ if (!Buf_.KeyExpected()) {
+ // not closed metrics array
+ Buf_.EndList();
+ }
+ Buf_.EndObject();
+ }
+
+ void OnCommonTime(TInstant time) override {
+ State_.Expect(TEncoderState::EState::ROOT);
+ WriteTime(time);
+ }
+
+ void OnMetricBegin(EMetricType type) override {
+ State_.Switch(TEncoderState::EState::ROOT, TEncoderState::EState::METRIC);
+ if (Buf_.KeyExpected()) {
+ // first metric, so open metrics array
+ Buf_.WriteKey(TStringBuf(Style_ == EJsonStyle::Solomon ? "sensors" : "metrics"));
+ Buf_.BeginList();
+ }
+ Buf_.BeginObject();
+ WriteMetricType(type);
+ }
+
+ void OnMetricEnd() override {
+ State_.Switch(TEncoderState::EState::METRIC, TEncoderState::EState::ROOT);
+ if (!Buf_.KeyExpected()) {
+ // not closed timeseries array
+ Buf_.EndList();
+ }
+
+ if (!TimeSeries_ && LastPoint_.HasValue()) {
+ // we have seen only one point between OnMetricBegin() and
+ // OnMetricEnd() calls
+ WriteTime(LastPoint_.GetTime());
+ WriteValue(LastPoint_.GetValueType(), LastPoint_.GetValue());
+ }
+ Buf_.EndObject();
+
+ LastPoint_ = {};
+ TimeSeries_ = false;
+ }
+
+ void OnLabelsBegin() override {
+ if (!Buf_.KeyExpected()) {
+ // not closed metrics or timeseries array if labels go after values
+ Buf_.EndList();
+ }
+ if (State_ == TEncoderState::EState::ROOT) {
+ State_ = TEncoderState::EState::COMMON_LABELS;
+ Buf_.WriteKey(TStringBuf(Style_ == EJsonStyle::Solomon ? "commonLabels" : "labels"));
+ } else if (State_ == TEncoderState::EState::METRIC) {
+ State_ = TEncoderState::EState::METRIC_LABELS;
+ Buf_.WriteKey(TStringBuf("labels"));
+ } else {
+ State_.ThrowInvalid("expected METRIC or ROOT");
+ }
+ Buf_.BeginObject();
+
+ EmptyLabels_ = true;
+ }
+
+ void OnLabelsEnd() override {
+ if (State_ == TEncoderState::EState::METRIC_LABELS) {
+ State_ = TEncoderState::EState::METRIC;
+ } else if (State_ == TEncoderState::EState::COMMON_LABELS) {
+ State_ = TEncoderState::EState::ROOT;
+ } else {
+ State_.ThrowInvalid("expected LABELS or COMMON_LABELS");
+ }
+
+ Y_ENSURE(!EmptyLabels_, "Labels cannot be empty");
+ Buf_.EndObject();
+ if (State_ == TEncoderState::EState::METRIC) {
+ WriteName();
+ }
+ }
+
+ void OnLabel(TStringBuf name, TStringBuf value) override {
+ if (State_ == TEncoderState::EState::METRIC_LABELS || State_ == TEncoderState::EState::COMMON_LABELS) {
+ WriteLabel(name, value);
+ } else {
+ State_.ThrowInvalid("expected LABELS or COMMON_LABELS");
+ }
+
+ EmptyLabels_ = false;
+ }
+
+ void OnDouble(TInstant time, double value) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ Write<double>(time, value);
+ }
+
+ void OnInt64(TInstant time, i64 value) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ Write<i64>(time, value);
+ }
+
+ void OnUint64(TInstant time, ui64 value) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ Write<ui64>(time, value);
+ }
+
+ void OnHistogram(TInstant time, IHistogramSnapshotPtr snapshot) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ Write<IHistogramSnapshot*>(time, snapshot.Get());
+ }
+
+ void OnSummaryDouble(TInstant time, ISummaryDoubleSnapshotPtr snapshot) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ Write<ISummaryDoubleSnapshot*>(time, snapshot.Get());
+ }
+
+ void OnLogHistogram(TInstant time, TLogHistogramSnapshotPtr snapshot) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ Write<TLogHistogramSnapshot*>(time, snapshot.Get());
+ }
+
+ template <typename T>
+ void Write(TInstant time, T value) {
+ State_.Expect(TEncoderState::EState::METRIC);
+
+ if (!LastPoint_.HasValue()) {
+ LastPoint_ = {time, value};
+ } else {
+ // second point
+ // TODO: output types
+ Y_ENSURE(LastPoint_.GetValueType() == TValueType<T>::Type,
+ "mixed metric value types in one metric");
+
+ if (!TimeSeries_) {
+ Buf_.WriteKey(TStringBuf("timeseries"));
+ Buf_.BeginList();
+ Buf_.BeginObject();
+ Y_ENSURE(LastPoint_.GetTime() != TInstant::Zero(),
+ "time cannot be empty or zero in a timeseries point");
+ WriteTime(LastPoint_.GetTime());
+ WriteValue(LastPoint_.GetValueType(), LastPoint_.GetValue());
+ Buf_.EndObject();
+ TimeSeries_ = true;
+ }
+
+ if (TimeSeries_) {
+ Buf_.BeginObject();
+ Y_ENSURE(time != TInstant::Zero(),
+ "time cannot be empty or zero in a timeseries point");
+
+ WriteTime(time);
+ WriteValue(value);
+ Buf_.EndObject();
+ }
+ }
+ }
+
+ void Close() override {
+ LastPoint_ = {};
+ }
+
+ private:
+ TEncoderState State_;
+ TTypedPoint LastPoint_;
+ bool TimeSeries_ = false;
+ bool EmptyLabels_ = false;
+ };
+
+ ///////////////////////////////////////////////////////////////////////
+ // TBufferedJsonEncoder
+ ///////////////////////////////////////////////////////////////////////
+ class TBufferedJsonEncoder : public TBufferedEncoderBase, public TJsonWriter {
+ public:
+ TBufferedJsonEncoder(IOutputStream* out, int indentation, EJsonStyle style, TStringBuf metricNameLabel)
+ : TJsonWriter{out, indentation, style, metricNameLabel}
+ {
+ MetricsMergingMode_ = EMetricsMergingMode::MERGE_METRICS;
+ }
+
+ ~TBufferedJsonEncoder() override {
+ Close();
+ }
+
+ void OnLabelsBegin() override {
+ TBufferedEncoderBase::OnLabelsBegin();
+ EmptyLabels_ = true;
+ }
+
+ void OnLabel(TStringBuf name, TStringBuf value) override {
+ TBufferedEncoderBase::OnLabel(name, value);
+ EmptyLabels_ = false;
+ }
+
+ void OnLabel(ui32 name, ui32 value) override {
+ TBufferedEncoderBase::OnLabel(name, value);
+ EmptyLabels_ = false;
+ }
+
+ void OnLabelsEnd() override {
+ TBufferedEncoderBase::OnLabelsEnd();
+ Y_ENSURE(!EmptyLabels_, "Labels cannot be empty");
+ }
+
+ void Close() final {
+ if (Closed_) {
+ return;
+ }
+
+ Closed_ = true;
+
+ LabelValuesPool_.Build();
+ LabelNamesPool_.Build();
+
+ Buf_.BeginObject();
+
+ WriteTime(CommonTime_);
+ if (CommonLabels_.size() > 0) {
+ Buf_.WriteKey(TStringBuf(Style_ == EJsonStyle::Solomon ? "commonLabels": "labels"));
+ WriteLabels(CommonLabels_, true);
+ }
+
+ if (Metrics_.size() > 0) {
+ Buf_.WriteKey(TStringBuf(Style_ == EJsonStyle::Solomon ? "sensors" : "metrics"));
+ WriteMetrics();
+ }
+
+ Buf_.EndObject();
+ }
+
+ private:
+ void WriteMetrics() {
+ Buf_.BeginList();
+ for (auto&& metric : Metrics_) {
+ WriteMetric(metric);
+ }
+ Buf_.EndList();
+ }
+
+ void WriteMetric(TMetric& metric) {
+ Buf_.BeginObject();
+
+ WriteMetricType(metric.MetricType);
+
+ Buf_.WriteKey(TStringBuf("labels"));
+ WriteLabels(metric.Labels, false);
+
+ metric.TimeSeries.SortByTs();
+ if (metric.TimeSeries.Size() == 1) {
+ const auto& point = metric.TimeSeries[0];
+ WriteTime(point.GetTime());
+ WriteValue(metric.TimeSeries.GetValueType(), point.GetValue());
+ } else if (metric.TimeSeries.Size() > 1) {
+ Buf_.WriteKey(TStringBuf("timeseries"));
+ Buf_.BeginList();
+ metric.TimeSeries.ForEach([this](TInstant time, EMetricValueType type, TMetricValue value) {
+ Buf_.BeginObject();
+ // make gcc 6.1 happy https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61636
+ this->WriteTime(time);
+ this->WriteValue(type, value);
+ Buf_.EndObject();
+ });
+
+ Buf_.EndList();
+ }
+
+ Buf_.EndObject();
+ }
+
+ void WriteLabels(const TPooledLabels& labels, bool isCommon) {
+ Buf_.BeginObject();
+
+ for (auto i = 0u; i < labels.size(); ++i) {
+ TStringBuf name = LabelNamesPool_.Get(labels[i].Key->Index);
+ TStringBuf value = LabelValuesPool_.Get(labels[i].Value->Index);
+
+ WriteLabel(name, value);
+ }
+
+ Buf_.EndObject();
+
+ if (!isCommon) {
+ WriteName();
+ }
+ }
+
+ private:
+ bool Closed_{false};
+ bool EmptyLabels_ = false;
+ };
+ }
+
+ IMetricEncoderPtr EncoderJson(IOutputStream* out, int indentation) {
+ return MakeHolder<TEncoderJson>(out, indentation, EJsonStyle::Solomon, "");
+ }
+
+ IMetricEncoderPtr BufferedEncoderJson(IOutputStream* out, int indentation) {
+ return MakeHolder<TBufferedJsonEncoder>(out, indentation, EJsonStyle::Solomon, "");
+ }
+
+ IMetricEncoderPtr EncoderCloudJson(IOutputStream* out, int indentation, TStringBuf metricNameLabel) {
+ return MakeHolder<TEncoderJson>(out, indentation, EJsonStyle::Cloud, metricNameLabel);
+ }
+
+ IMetricEncoderPtr BufferedEncoderCloudJson(IOutputStream* out, int indentation, TStringBuf metricNameLabel) {
+ return MakeHolder<TBufferedJsonEncoder>(out, indentation, EJsonStyle::Cloud, metricNameLabel);
+ }
+}
diff --git a/library/cpp/monlib/encode/json/json_ut.cpp b/library/cpp/monlib/encode/json/json_ut.cpp
new file mode 100644
index 0000000000..09e7909289
--- /dev/null
+++ b/library/cpp/monlib/encode/json/json_ut.cpp
@@ -0,0 +1,1290 @@
+#include "json.h"
+
+#include <library/cpp/monlib/encode/protobuf/protobuf.h>
+#include <library/cpp/monlib/metrics/labels.h>
+
+#include <library/cpp/json/json_reader.h>
+#include <library/cpp/resource/resource.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/str.h>
+#include <util/string/builder.h>
+
+#include <limits>
+
+using namespace NMonitoring;
+
+namespace NMonitoring {
+ bool operator<(const TLabel& lhs, const TLabel& rhs) {
+ return lhs.Name() < rhs.Name() ||
+ (lhs.Name() == rhs.Name() && lhs.Value() < rhs.Value());
+ }
+}
+namespace {
+ void AssertLabels(const NProto::TMultiSample& actual, const TLabels& expected) {
+ UNIT_ASSERT_EQUAL(actual.LabelsSize(), expected.Size());
+
+ TSet<TLabel> actualSet;
+ TSet<TLabel> expectedSet;
+ Transform(expected.begin(), expected.end(), std::inserter(expectedSet, expectedSet.end()), [] (auto&& l) {
+ return TLabel{l.Name(), l.Value()};
+ });
+
+ const auto& l = actual.GetLabels();
+ Transform(std::begin(l), std::end(l), std::inserter(actualSet, std::begin(actualSet)),
+ [](auto&& elem) -> TLabel {
+ return {elem.GetName(), elem.GetValue()};
+ });
+
+ TVector<TLabel> diff;
+ SetSymmetricDifference(std::begin(expectedSet), std::end(expectedSet),
+ std::begin(actualSet), std::end(actualSet), std::back_inserter(diff));
+
+ if (diff.size() > 0) {
+ for (auto&& l : diff) {
+ Cerr << l << Endl;
+ }
+
+ UNIT_FAIL("Labels don't match");
+ }
+ }
+
+ void AssertLabelEqual(const NProto::TLabel& l, TStringBuf name, TStringBuf value) {
+ UNIT_ASSERT_STRINGS_EQUAL(l.GetName(), name);
+ UNIT_ASSERT_STRINGS_EQUAL(l.GetValue(), value);
+ }
+
+ void AssertPointEqual(const NProto::TPoint& p, TInstant time, double value) {
+ UNIT_ASSERT_VALUES_EQUAL(p.GetTime(), time.MilliSeconds());
+ UNIT_ASSERT_EQUAL(p.GetValueCase(), NProto::TPoint::kFloat64);
+ UNIT_ASSERT_DOUBLES_EQUAL(p.GetFloat64(), value, std::numeric_limits<double>::epsilon());
+ }
+
+ void AssertPointEqualNan(const NProto::TPoint& p, TInstant time) {
+ UNIT_ASSERT_VALUES_EQUAL(p.GetTime(), time.MilliSeconds());
+ UNIT_ASSERT_EQUAL(p.GetValueCase(), NProto::TPoint::kFloat64);
+ UNIT_ASSERT(std::isnan(p.GetFloat64()));
+ }
+
+ void AssertPointEqualInf(const NProto::TPoint& p, TInstant time, int sign) {
+ UNIT_ASSERT_VALUES_EQUAL(p.GetTime(), time.MilliSeconds());
+ UNIT_ASSERT_EQUAL(p.GetValueCase(), NProto::TPoint::kFloat64);
+ UNIT_ASSERT(std::isinf(p.GetFloat64()));
+ if (sign < 0) {
+ UNIT_ASSERT(p.GetFloat64() < 0);
+ }
+ }
+
+ void AssertPointEqual(const NProto::TPoint& p, TInstant time, ui64 value) {
+ UNIT_ASSERT_VALUES_EQUAL(p.GetTime(), time.MilliSeconds());
+ UNIT_ASSERT_EQUAL(p.GetValueCase(), NProto::TPoint::kUint64);
+ UNIT_ASSERT_VALUES_EQUAL(p.GetUint64(), value);
+ }
+
+ void AssertPointEqual(const NProto::TPoint& p, TInstant time, i64 value) {
+ UNIT_ASSERT_VALUES_EQUAL(p.GetTime(), time.MilliSeconds());
+ UNIT_ASSERT_EQUAL(p.GetValueCase(), NProto::TPoint::kInt64);
+ UNIT_ASSERT_VALUES_EQUAL(p.GetInt64(), value);
+ }
+
+ void AssertPointEqual(const NProto::TPoint& p, TInstant time, const IHistogramSnapshot& expected) {
+ UNIT_ASSERT_VALUES_EQUAL(p.GetTime(), time.MilliSeconds());
+ UNIT_ASSERT_EQUAL(p.GetValueCase(), NProto::TPoint::kHistogram);
+
+ const NProto::THistogram& h = p.GetHistogram();
+ UNIT_ASSERT_VALUES_EQUAL(h.BoundsSize(), expected.Count());
+ UNIT_ASSERT_VALUES_EQUAL(h.ValuesSize(), expected.Count());
+
+ for (size_t i = 0; i < h.BoundsSize(); i++) {
+ UNIT_ASSERT_DOUBLES_EQUAL(h.GetBounds(i), expected.UpperBound(i), Min<double>());
+ UNIT_ASSERT_VALUES_EQUAL(h.GetValues(i), expected.Value(i));
+ }
+ }
+
+ void AssertPointEqual(const NProto::TPoint& p, TInstant time, const TLogHistogramSnapshot& expected) {
+ UNIT_ASSERT_VALUES_EQUAL(p.GetTime(), time.MilliSeconds());
+ UNIT_ASSERT_EQUAL(p.GetValueCase(), NProto::TPoint::kLogHistogram);
+
+ const double eps = 1e-10;
+ const NProto::TLogHistogram& h = p.GetLogHistogram();
+
+ UNIT_ASSERT_DOUBLES_EQUAL(h.GetBase(), expected.Base(), eps);
+ UNIT_ASSERT_VALUES_EQUAL(h.GetZerosCount(), expected.ZerosCount());
+ UNIT_ASSERT_VALUES_EQUAL(h.GetStartPower(), expected.StartPower());
+ UNIT_ASSERT_VALUES_EQUAL(h.BucketsSize(), expected.Count());
+ for (size_t i = 0; i < expected.Count(); ++i) {
+ UNIT_ASSERT_DOUBLES_EQUAL(h.GetBuckets(i), expected.Bucket(i), eps);
+ }
+ }
+
+ void AssertPointEqual(const NProto::TPoint& p, TInstant time, const ISummaryDoubleSnapshot& expected) {
+ UNIT_ASSERT_VALUES_EQUAL(p.GetTime(), time.MilliSeconds());
+ UNIT_ASSERT_EQUAL(p.GetValueCase(), NProto::TPoint::kSummaryDouble);
+ auto actual = p.GetSummaryDouble();
+ const double eps = 1e-10;
+ UNIT_ASSERT_DOUBLES_EQUAL(actual.GetSum(), expected.GetSum(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(actual.GetMin(), expected.GetMin(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(actual.GetMax(), expected.GetMax(), eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(actual.GetLast(), expected.GetLast(), eps);
+ UNIT_ASSERT_VALUES_EQUAL(actual.GetCount(), expected.GetCount());
+ }
+
+} // namespace
+
+
+Y_UNIT_TEST_SUITE(TJsonTest) {
+ const TInstant now = TInstant::ParseIso8601Deprecated("2017-11-05T01:02:03Z");
+
+ Y_UNIT_TEST(Encode) {
+ auto check = [](bool cloud, bool buffered, TStringBuf expectedResourceKey) {
+ TString json;
+ TStringOutput out(json);
+ auto e = cloud
+ ? (buffered ? BufferedEncoderCloudJson(&out, 2, "metric") : EncoderCloudJson(&out, 2, "metric"))
+ : (buffered ? BufferedEncoderJson(&out, 2) : EncoderJson(&out, 2));
+ e->OnStreamBegin();
+ { // common time
+ e->OnCommonTime(TInstant::Seconds(1500000000));
+ }
+ { // common labels
+ e->OnLabelsBegin();
+ e->OnLabel("project", "solomon");
+ e->OnLabelsEnd();
+ }
+ { // metric #1
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("metric", "single");
+ e->OnLabel("labels", "l1");
+ e->OnLabelsEnd();
+ }
+ e->OnUint64(now, 17);
+ e->OnMetricEnd();
+ }
+ { // metric #2
+ e->OnMetricBegin(EMetricType::RATE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("metric", "single");
+ e->OnLabel("labels", "l2");
+ e->OnLabelsEnd();
+ }
+ e->OnUint64(now, 17);
+ e->OnMetricEnd();
+ }
+ { // metric #3
+ e->OnMetricBegin(EMetricType::GAUGE);
+ e->OnDouble(now, 3.14);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("metric", "single");
+ e->OnLabel("labels", "l3");
+ e->OnLabelsEnd();
+ }
+ e->OnMetricEnd();
+ }
+ { // metric #4
+ e->OnMetricBegin(EMetricType::IGAUGE);
+ e->OnInt64(now, 42);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("metric", "single_igauge");
+ e->OnLabel("labels", "l4");
+ e->OnLabelsEnd();
+ }
+ e->OnMetricEnd();
+ }
+ { // metric #5
+ e->OnMetricBegin(EMetricType::GAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("metric", "multiple");
+ e->OnLabel("labels", "l5");
+ e->OnLabelsEnd();
+ }
+ e->OnDouble(now, std::numeric_limits<double>::quiet_NaN());
+ e->OnDouble(now + TDuration::Seconds(15), std::numeric_limits<double>::infinity());
+ e->OnDouble(now + TDuration::Seconds(30), -std::numeric_limits<double>::infinity());
+ e->OnMetricEnd();
+ }
+
+ { // metric #6
+ e->OnMetricBegin(EMetricType::COUNTER);
+ e->OnUint64(now, 1337);
+ e->OnUint64(now + TDuration::Seconds(15), 1338);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("metric", "multiple");
+ e->OnLabel("labels", "l6");
+ e->OnLabelsEnd();
+ }
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ e->Close();
+ json += "\n";
+
+ auto parseJson = [] (auto buf) {
+ NJson::TJsonValue value;
+ NJson::ReadJsonTree(buf, &value, true);
+ return value;
+ };
+
+ const auto expectedJson = NResource::Find(expectedResourceKey);
+ UNIT_ASSERT_EQUAL(parseJson(json), parseJson(expectedJson));
+ };
+
+ check(false, false, "/expected.json");
+ check(false, true, "/expected_buffered.json");
+ check(true, false, "/expected_cloud.json");
+ check(true, true, "/expected_cloud_buffered.json");
+ }
+
+ TLogHistogramSnapshotPtr TestLogHistogram(ui32 v = 1) {
+ TVector<double> buckets{0.5 * v, 0.25 * v, 0.25 * v, 0.5 * v};
+ return MakeIntrusive<TLogHistogramSnapshot>(1.5, 1u, 0, std::move(buckets));
+ }
+
+ Y_UNIT_TEST(HistogramAndSummaryMetricTypesAreNotSupportedByCloudJson) {
+ const TInstant now = TInstant::ParseIso8601Deprecated("2017-11-05T01:02:03Z");
+
+ auto emit = [&](IMetricEncoder* encoder, EMetricType metricType) {
+ encoder->OnStreamBegin();
+ {
+ encoder->OnMetricBegin(metricType);
+ {
+ encoder->OnLabelsBegin();
+ encoder->OnLabel("name", "m");
+ encoder->OnLabelsEnd();
+ }
+
+ switch (metricType) {
+ case EMetricType::HIST: {
+ auto histogram = ExponentialHistogram(6, 2);
+ encoder->OnHistogram(now, histogram->Snapshot());
+ break;
+ }
+ case EMetricType::LOGHIST: {
+ auto histogram = TestLogHistogram();
+ encoder->OnLogHistogram(now, histogram);
+ break;
+ }
+ case EMetricType::DSUMMARY: {
+ auto summary = MakeIntrusive<TSummaryDoubleSnapshot>(10., -0.5, 0.5, 0.3, 30u);
+ encoder->OnSummaryDouble(now, summary);
+ break;
+ }
+ default:
+ Y_FAIL("unexpected metric type [%s]", ToString(metricType).c_str());
+ }
+
+ encoder->OnMetricEnd();
+ }
+ encoder->OnStreamEnd();
+ encoder->Close();
+ };
+
+ auto doTest = [&](bool buffered, EMetricType metricType) {
+ TString json;
+ TStringOutput out(json);
+ auto encoder = buffered ? BufferedEncoderCloudJson(&out, 2) : EncoderCloudJson(&out, 2);
+ const TString expectedMessage = TStringBuilder()
+ << "metric type '" << metricType << "' is not supported by cloud json format";
+ UNIT_ASSERT_EXCEPTION_CONTAINS_C(emit(encoder.Get(), metricType), yexception, expectedMessage,
+ TString("buffered: ") + ToString(buffered));
+ };
+
+ doTest(false, EMetricType::HIST);
+ doTest(false, EMetricType::LOGHIST);
+ doTest(false, EMetricType::DSUMMARY);
+ doTest(true, EMetricType::HIST);
+ doTest(true, EMetricType::LOGHIST);
+ doTest(true, EMetricType::DSUMMARY);
+ }
+
+ Y_UNIT_TEST(MetricsWithDifferentLabelOrderGetMerged) {
+ TString json;
+ TStringOutput out(json);
+ auto e = BufferedEncoderJson(&out, 2);
+
+ e->OnStreamBegin();
+ {
+ e->OnMetricBegin(EMetricType::RATE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("metric", "hello");
+ e->OnLabel("label", "world");
+ e->OnLabelsEnd();
+ }
+ e->OnUint64(TInstant::Zero(), 0);
+ e->OnMetricEnd();
+ }
+ {
+ e->OnMetricBegin(EMetricType::RATE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("label", "world");
+ e->OnLabel("metric", "hello");
+ e->OnLabelsEnd();
+ }
+ e->OnUint64(TInstant::Zero(), 1);
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ e->Close();
+ json += "\n";
+
+ TString expectedJson = NResource::Find("/merged.json");
+ // we cannot be sure regarding the label order in the result,
+ // so we'll have to parse the expected value and then compare it with actual
+
+ NProto::TMultiSamplesList samples;
+ IMetricEncoderPtr d = EncoderProtobuf(&samples);
+ DecodeJson(expectedJson, d.Get());
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.SamplesSize(), 1);
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::RATE);
+ AssertLabels(s, TLabels{{"metric", "hello"}, {"label", "world"}});
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+ AssertPointEqual(s.GetPoints(0), TInstant::Zero(), ui64(1));
+ }
+ }
+ Y_UNIT_TEST(Decode1) {
+ NProto::TMultiSamplesList samples;
+ {
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TString testJson = NResource::Find("/expected.json");
+ DecodeJson(testJson, e.Get());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TInstant::MilliSeconds(samples.GetCommonTime()),
+ TInstant::Seconds(1500000000));
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.CommonLabelsSize(), 1);
+ AssertLabelEqual(samples.GetCommonLabels(0), "project", "solomon");
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.SamplesSize(), 6);
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::COUNTER);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 2);
+ AssertLabelEqual(s.GetLabels(0), "metric", "single");
+ AssertLabelEqual(s.GetLabels(1), "labels", "l1");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+ AssertPointEqual(s.GetPoints(0), now, ui64(17));
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(1);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::RATE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 2);
+ AssertLabelEqual(s.GetLabels(0), "metric", "single");
+ AssertLabelEqual(s.GetLabels(1), "labels", "l2");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+ AssertPointEqual(s.GetPoints(0), now, ui64(17));
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(2);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 2);
+ AssertLabelEqual(s.GetLabels(0), "metric", "single");
+ AssertLabelEqual(s.GetLabels(1), "labels", "l3");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+ AssertPointEqual(s.GetPoints(0), now, 3.14);
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(3);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::IGAUGE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 2);
+ AssertLabelEqual(s.GetLabels(0), "metric", "single_igauge");
+ AssertLabelEqual(s.GetLabels(1), "labels", "l4");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+ AssertPointEqual(s.GetPoints(0), now, i64(42));
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(4);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 2);
+ AssertLabelEqual(s.GetLabels(0), "metric", "multiple");
+ AssertLabelEqual(s.GetLabels(1), "labels", "l5");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 3);
+ AssertPointEqualNan(s.GetPoints(0), now);
+ AssertPointEqualInf(s.GetPoints(1), now + TDuration::Seconds(15), 1);
+ AssertPointEqualInf(s.GetPoints(2), now + TDuration::Seconds(30), -11);
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(5);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::COUNTER);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 2);
+ AssertLabelEqual(s.GetLabels(0), "metric", "multiple");
+ AssertLabelEqual(s.GetLabels(1), "labels", "l6");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 2);
+ AssertPointEqual(s.GetPoints(0), now, ui64(1337));
+ AssertPointEqual(s.GetPoints(1), now + TDuration::Seconds(15), ui64(1338));
+ }
+ }
+
+ Y_UNIT_TEST(DecodeMetrics) {
+ NProto::TMultiSamplesList samples;
+ {
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TString metricsJson = NResource::Find("/metrics.json");
+ DecodeJson(metricsJson, e.Get());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TInstant::MilliSeconds(samples.GetCommonTime()),
+ TInstant::ParseIso8601Deprecated("2017-08-27T12:34:56Z"));
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.CommonLabelsSize(), 3);
+ AssertLabelEqual(samples.GetCommonLabels(0), "project", "solomon");
+ AssertLabelEqual(samples.GetCommonLabels(1), "cluster", "man");
+ AssertLabelEqual(samples.GetCommonLabels(2), "service", "stockpile");
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.SamplesSize(), 4);
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "metric", "Memory");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+ AssertPointEqual(s.GetPoints(0), TInstant::Zero(), 10.0);
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(1);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::RATE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "metric", "UserTime");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+ AssertPointEqual(s.GetPoints(0), TInstant::Zero(), ui64(1));
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(2);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 2);
+ AssertLabelEqual(s.GetLabels(0), "export", "Oxygen");
+ AssertLabelEqual(s.GetLabels(1), "metric", "QueueSize");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+ auto ts = TInstant::ParseIso8601Deprecated("2017-11-05T12:34:56.000Z");
+ AssertPointEqual(s.GetPoints(0), ts, 3.14159);
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(3);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "metric", "Writes");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 2);
+ auto ts1 = TInstant::ParseIso8601Deprecated("2017-08-28T12:32:11Z");
+ AssertPointEqual(s.GetPoints(0), ts1, -10.0);
+ auto ts2 = TInstant::Seconds(1503923187);
+ AssertPointEqual(s.GetPoints(1), ts2, 20.0);
+ }
+ }
+
+ Y_UNIT_TEST(DecodeSensors) {
+ NProto::TMultiSamplesList samples;
+ {
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TString sensorsJson = NResource::Find("/sensors.json");
+ DecodeJson(sensorsJson, e.Get());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TInstant::MilliSeconds(samples.GetCommonTime()),
+ TInstant::ParseIso8601Deprecated("2017-08-27T12:34:56Z"));
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.CommonLabelsSize(), 3);
+ AssertLabelEqual(samples.GetCommonLabels(0), "project", "solomon");
+ AssertLabelEqual(samples.GetCommonLabels(1), "cluster", "man");
+ AssertLabelEqual(samples.GetCommonLabels(2), "service", "stockpile");
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.SamplesSize(), 4);
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "metric", "Memory");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+ AssertPointEqual(s.GetPoints(0), TInstant::Zero(), 10.0);
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(1);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::RATE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "metric", "UserTime");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+ AssertPointEqual(s.GetPoints(0), TInstant::Zero(), ui64(1));
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(2);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 2);
+ AssertLabelEqual(s.GetLabels(0), "export", "Oxygen");
+ AssertLabelEqual(s.GetLabels(1), "metric", "QueueSize");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+ auto ts = TInstant::ParseIso8601Deprecated("2017-11-05T12:34:56.000Z");
+ AssertPointEqual(s.GetPoints(0), ts, 3.14159);
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(3);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "metric", "Writes");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 2);
+ auto ts1 = TInstant::ParseIso8601Deprecated("2017-08-28T12:32:11Z");
+ AssertPointEqual(s.GetPoints(0), ts1, -10.0);
+ auto ts2 = TInstant::Seconds(1503923187);
+ AssertPointEqual(s.GetPoints(1), ts2, 20.0);
+ }
+ }
+
+ Y_UNIT_TEST(DecodeToEncoder) {
+ auto testJson = NResource::Find("/test_decode_to_encode.json");
+
+ TStringStream Stream_;
+ auto encoder = BufferedEncoderJson(&Stream_, 4);
+ DecodeJson(testJson, encoder.Get());
+
+ encoder->Close();
+
+ auto val1 = NJson::ReadJsonFastTree(testJson, true);
+ auto val2 = NJson::ReadJsonFastTree(Stream_.Str(), true);
+
+ UNIT_ASSERT_VALUES_EQUAL(val1, val2);
+ }
+
+ void WriteEmptySeries(const IMetricEncoderPtr& e) {
+ e->OnStreamBegin();
+ {
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("foo", "bar");
+ e->OnLabelsEnd();
+ }
+ e->OnMetricEnd();
+ }
+
+ e->OnStreamEnd();
+ e->Close();
+ }
+
+ Y_UNIT_TEST(EncodeEmptySeries) {
+ TString json;
+ TStringOutput out(json);
+
+ auto e = EncoderJson(&out, 2);
+ WriteEmptySeries(e);
+ json += "\n";
+
+ TString expectedJson = NResource::Find("/empty_series.json");
+ UNIT_ASSERT_NO_DIFF(json, expectedJson);
+ }
+
+ void WriteEmptyLabels(IMetricEncoderPtr& e) {
+ e->OnStreamBegin();
+ e->OnMetricBegin(EMetricType::COUNTER);
+
+ e->OnLabelsBegin();
+ UNIT_ASSERT_EXCEPTION(e->OnLabelsEnd(), yexception);
+ }
+
+ Y_UNIT_TEST(LabelsCannotBeEmpty) {
+ TString json;
+ TStringOutput out(json);
+
+ auto e = EncoderJson(&out, 2);
+ WriteEmptyLabels(e);
+ }
+
+ Y_UNIT_TEST(LabelsCannotBeEmptyBuffered) {
+ TString json;
+ TStringOutput out(json);
+
+ auto e = BufferedEncoderJson(&out, 2);
+ WriteEmptyLabels(e);
+ }
+
+ Y_UNIT_TEST(EncodeEmptySeriesBuffered) {
+ TString json;
+ TStringOutput out(json);
+
+ auto e = BufferedEncoderJson(&out, 2);
+ WriteEmptySeries(e);
+ json += "\n";
+
+ TString expectedJson = NResource::Find("/empty_series.json");
+ UNIT_ASSERT_NO_DIFF(json, expectedJson);
+ }
+
+ Y_UNIT_TEST(BufferedEncoderMergesMetrics) {
+ TString json;
+ TStringOutput out(json);
+
+ auto e = BufferedEncoderJson(&out, 2);
+ auto ts = 1;
+
+ auto writeMetric = [&] (const TString& val) {
+ e->OnMetricBegin(EMetricType::COUNTER);
+
+ e->OnLabelsBegin();
+ e->OnLabel("foo", val);
+ e->OnLabelsEnd();
+ e->OnUint64(TInstant::Seconds(ts++), 42);
+
+ e->OnMetricEnd();
+ };
+
+ e->OnStreamBegin();
+ writeMetric("bar");
+ writeMetric("bar");
+ writeMetric("baz");
+ writeMetric("bar");
+ e->OnStreamEnd();
+ e->Close();
+
+ json += "\n";
+
+ TString expectedJson = NResource::Find("/buffered_test.json");
+ UNIT_ASSERT_NO_DIFF(json, expectedJson);
+ }
+
+ Y_UNIT_TEST(JsonEncoderDisallowsValuesInTimeseriesWithoutTs) {
+ TStringStream out;
+
+ auto e = EncoderJson(&out);
+ auto writePreamble = [&] {
+ e->OnStreamBegin();
+ e->OnMetricBegin(EMetricType::COUNTER);
+ e->OnLabelsBegin();
+ e->OnLabel("foo", "bar");
+ e->OnLabelsEnd();
+ };
+
+ // writing two values for a metric in a row will trigger
+ // timeseries object construction
+ writePreamble();
+ e->OnUint64(TInstant::Zero(), 42);
+ UNIT_ASSERT_EXCEPTION(e->OnUint64(TInstant::Zero(), 42), yexception);
+
+ e = EncoderJson(&out);
+ writePreamble();
+ e->OnUint64(TInstant::Zero(), 42);
+ UNIT_ASSERT_EXCEPTION(e->OnUint64(TInstant::Now(), 42), yexception);
+
+ e = EncoderJson(&out);
+ writePreamble();
+ e->OnUint64(TInstant::Now(), 42);
+ UNIT_ASSERT_EXCEPTION(e->OnUint64(TInstant::Zero(), 42), yexception);
+ }
+
+ Y_UNIT_TEST(BufferedJsonEncoderMergesTimeseriesWithoutTs) {
+ TStringStream out;
+
+ {
+ auto e = BufferedEncoderJson(&out, 2);
+ e->OnStreamBegin();
+ e->OnMetricBegin(EMetricType::COUNTER);
+ e->OnLabelsBegin();
+ e->OnLabel("foo", "bar");
+ e->OnLabelsEnd();
+ // in buffered mode we are able to find values with same (in this case zero)
+ // timestamp and discard duplicates
+ e->OnUint64(TInstant::Zero(), 42);
+ e->OnUint64(TInstant::Zero(), 43);
+ e->OnUint64(TInstant::Zero(), 44);
+ e->OnUint64(TInstant::Zero(), 45);
+ e->OnMetricEnd();
+ e->OnStreamEnd();
+ }
+
+ out << "\n";
+ UNIT_ASSERT_NO_DIFF(out.Str(), NResource::Find("/buffered_ts_merge.json"));
+ }
+
+ template <typename TFactory, typename TConsumer>
+ TString EncodeToString(TFactory factory, TConsumer consumer) {
+ TStringStream out;
+ {
+ IMetricEncoderPtr e = factory(&out, 2);
+ consumer(e.Get());
+ }
+ out << '\n';
+ return out.Str();
+ }
+
+ Y_UNIT_TEST(SummaryValueEncode) {
+ auto writeDocument = [](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ {
+ e->OnMetricBegin(EMetricType::DSUMMARY);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("metric", "temperature");
+ e->OnLabelsEnd();
+ }
+
+ e->OnSummaryDouble(now, MakeIntrusive<TSummaryDoubleSnapshot>(10., -0.5, 0.5, 0.3, 30u));
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ };
+
+ TString result1 = EncodeToString(EncoderJson, writeDocument);
+ UNIT_ASSERT_NO_DIFF(result1, NResource::Find("/summary_value.json"));
+
+ TString result2 = EncodeToString(BufferedEncoderJson, writeDocument);
+ UNIT_ASSERT_NO_DIFF(result2, NResource::Find("/summary_value.json"));
+ }
+
+ ISummaryDoubleSnapshotPtr TestInfSummary() {
+ return MakeIntrusive<TSummaryDoubleSnapshot>(
+ std::numeric_limits<double>::quiet_NaN(),
+ -std::numeric_limits<double>::infinity(),
+ std::numeric_limits<double>::infinity(),
+ 0.3,
+ 30u);
+ }
+
+ Y_UNIT_TEST(SummaryInfEncode) {
+ auto writeDocument = [](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ {
+ e->OnMetricBegin(EMetricType::DSUMMARY);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("metric", "temperature");
+ e->OnLabelsEnd();
+ }
+
+ e->OnSummaryDouble(now, TestInfSummary());
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ };
+
+ TString result1 = EncodeToString(EncoderJson, writeDocument);
+ UNIT_ASSERT_NO_DIFF(result1, NResource::Find("/summary_inf.json"));
+
+ TString result2 = EncodeToString(BufferedEncoderJson, writeDocument);
+ UNIT_ASSERT_NO_DIFF(result2, NResource::Find("/summary_inf.json"));
+ }
+
+ Y_UNIT_TEST(SummaryInfDecode) {
+ NProto::TMultiSamplesList samples;
+ {
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TString testJson = NResource::Find("/summary_inf.json");
+ DecodeJson(testJson, e.Get());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(1, samples.SamplesSize());
+ const NProto::TMultiSample& s = samples.GetSamples(0);
+
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::DSUMMARY);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "metric", "temperature");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+
+ auto actual = s.GetPoints(0).GetSummaryDouble();
+ UNIT_ASSERT(std::isnan(actual.GetSum()));
+ UNIT_ASSERT(actual.GetMin() < 0);
+ UNIT_ASSERT(std::isinf(actual.GetMin()));
+ UNIT_ASSERT(actual.GetMax() > 0);
+ UNIT_ASSERT(std::isinf(actual.GetMax()));
+ }
+
+ Y_UNIT_TEST(SummaryValueDecode) {
+ NProto::TMultiSamplesList samples;
+ {
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TString testJson = NResource::Find("/summary_value.json");
+ DecodeJson(testJson, e.Get());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(1, samples.SamplesSize());
+ const NProto::TMultiSample& s = samples.GetSamples(0);
+
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::DSUMMARY);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "metric", "temperature");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+
+ auto snapshot = TSummaryDoubleSnapshot(10., -0.5, 0.5, 0.3, 30u);
+ AssertPointEqual(s.GetPoints(0), now, snapshot);
+ }
+
+ Y_UNIT_TEST(SummaryTimeSeriesEncode) {
+ auto writeDocument = [](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ {
+ e->OnMetricBegin(EMetricType::DSUMMARY);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("metric", "temperature");
+ e->OnLabelsEnd();
+ }
+
+ TSummaryDoubleCollector summary;
+ summary.Collect(0.3);
+ summary.Collect(-0.5);
+ summary.Collect(1.);
+
+ e->OnSummaryDouble(now, summary.Snapshot());
+
+ summary.Collect(-1.5);
+ summary.Collect(0.01);
+
+ e->OnSummaryDouble(now + TDuration::Seconds(15), summary.Snapshot());
+
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ };
+
+ TString result1 = EncodeToString(EncoderJson, writeDocument);
+ UNIT_ASSERT_NO_DIFF(result1, NResource::Find("/summary_timeseries.json"));
+
+ TString result2 = EncodeToString(BufferedEncoderJson, writeDocument);
+ UNIT_ASSERT_NO_DIFF(result2, NResource::Find("/summary_timeseries.json"));
+ }
+
+ Y_UNIT_TEST(SummaryTimeSeriesDecode) {
+ NProto::TMultiSamplesList samples;
+ {
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TString testJson = NResource::Find("/summary_timeseries.json");
+ DecodeJson(testJson, e.Get());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(1, samples.SamplesSize());
+ const NProto::TMultiSample& s = samples.GetSamples(0);
+
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::DSUMMARY);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "metric", "temperature");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 2);
+
+ TSummaryDoubleCollector summary;
+ summary.Collect(0.3);
+ summary.Collect(-0.5);
+ summary.Collect(1.);
+
+ AssertPointEqual(s.GetPoints(0), now, *summary.Snapshot());
+
+ summary.Collect(-1.5);
+ summary.Collect(0.01);
+
+ AssertPointEqual(s.GetPoints(1), now + TDuration::Seconds(15), *summary.Snapshot());
+ }
+
+ Y_UNIT_TEST(LogHistogramValueEncode) {
+ auto writeDocument = [](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ {
+ e->OnMetricBegin(EMetricType::LOGHIST);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("metric", "ms");
+ e->OnLabelsEnd();
+ }
+
+ e->OnLogHistogram(now, TestLogHistogram());
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ };
+
+ TString result1 = EncodeToString(EncoderJson, writeDocument);
+ UNIT_ASSERT_NO_DIFF(result1, NResource::Find("/log_histogram_value.json"));
+
+ TString result2 = EncodeToString(BufferedEncoderJson, writeDocument);
+ UNIT_ASSERT_NO_DIFF(result2, NResource::Find("/log_histogram_value.json"));
+ }
+
+ Y_UNIT_TEST(LogHistogramValueDecode) {
+ NProto::TMultiSamplesList samples;
+ {
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TString testJson = NResource::Find("/log_histogram_value.json");
+ DecodeJson(testJson, e.Get());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(1, samples.SamplesSize());
+ const NProto::TMultiSample& s = samples.GetSamples(0);
+
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::LOGHISTOGRAM);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "metric", "ms");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+
+ auto snapshot = TestLogHistogram();
+ AssertPointEqual(s.GetPoints(0), now, *snapshot);
+ }
+
+ Y_UNIT_TEST(HistogramValueEncode) {
+ auto writeDocument = [](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ {
+ e->OnMetricBegin(EMetricType::HIST);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("metric", "responseTimeMillis");
+ e->OnLabelsEnd();
+ }
+
+ // {1: 1, 2: 1, 4: 2, 8: 4, 16: 8, inf: 83}
+ auto h = ExponentialHistogram(6, 2);
+ for (i64 i = 1; i < 100; i++) {
+ h->Collect(i);
+ }
+
+ e->OnHistogram(now, h->Snapshot());
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ };
+
+ TString result1 = EncodeToString(EncoderJson, writeDocument);
+ UNIT_ASSERT_NO_DIFF(result1, NResource::Find("/histogram_value.json"));
+
+ TString result2 = EncodeToString(BufferedEncoderJson, writeDocument);
+ UNIT_ASSERT_NO_DIFF(result2, NResource::Find("/histogram_value.json"));
+ }
+
+ Y_UNIT_TEST(LogHistogramTimeSeriesEncode) {
+ auto writeDocument = [](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ {
+ e->OnMetricBegin(EMetricType::LOGHIST);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("metric", "ms");
+ e->OnLabelsEnd();
+ }
+
+ e->OnLogHistogram(now, TestLogHistogram(1));;
+
+ e->OnLogHistogram(now + TDuration::Seconds(15), TestLogHistogram(2));
+
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ };
+
+ TString result1 = EncodeToString(EncoderJson, writeDocument);
+ UNIT_ASSERT_NO_DIFF(result1, NResource::Find("/log_histogram_timeseries.json"));
+
+ TString result2 = EncodeToString(BufferedEncoderJson, writeDocument);
+ UNIT_ASSERT_NO_DIFF(result2, NResource::Find("/log_histogram_timeseries.json"));
+ }
+
+ Y_UNIT_TEST(LogHistogramTimeSeriesDecode) {
+ NProto::TMultiSamplesList samples;
+ {
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TString testJson = NResource::Find("/log_histogram_timeseries.json");
+ DecodeJson(testJson, e.Get());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(1, samples.SamplesSize());
+ const NProto::TMultiSample& s = samples.GetSamples(0);
+
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::LOGHISTOGRAM);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "metric", "ms");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 2);
+
+ auto logHist = TestLogHistogram(1);
+ AssertPointEqual(s.GetPoints(0), now, *logHist);
+
+ logHist = TestLogHistogram(2);
+ AssertPointEqual(s.GetPoints(1), now + TDuration::Seconds(15), *logHist);
+ }
+
+ void HistogramValueDecode(const TString& filePath) {
+ NProto::TMultiSamplesList samples;
+ {
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TString testJson = NResource::Find(filePath);
+ DecodeJson(testJson, e.Get());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(1, samples.SamplesSize());
+ const NProto::TMultiSample& s = samples.GetSamples(0);
+
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::HISTOGRAM);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "metric", "responseTimeMillis");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+
+ auto h = ExponentialHistogram(6, 2);
+ for (i64 i = 1; i < 100; i++) {
+ h->Collect(i);
+ }
+
+ AssertPointEqual(s.GetPoints(0), now, *h->Snapshot());
+ }
+
+ Y_UNIT_TEST(HistogramValueDecode) {
+ HistogramValueDecode("/histogram_value.json");
+ HistogramValueDecode("/histogram_value_inf_before_bounds.json");
+ }
+
+ Y_UNIT_TEST(HistogramTimeSeriesEncode) {
+ auto writeDocument = [](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ {
+ e->OnMetricBegin(EMetricType::HIST_RATE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("metric", "responseTimeMillis");
+ e->OnLabelsEnd();
+ }
+
+ // {1: 1, 2: 1, 4: 2, 8: 4, 16: 8, inf: 83}
+ auto h = ExponentialHistogram(6, 2);
+ for (i64 i = 1; i < 100; i++) {
+ h->Collect(i);
+ }
+ e->OnHistogram(now, h->Snapshot());
+
+ // {1: 2, 2: 2, 4: 4, 8: 8, 16: 16, inf: 166}
+ for (i64 i = 1; i < 100; i++) {
+ h->Collect(i);
+ }
+ e->OnHistogram(now + TDuration::Seconds(15), h->Snapshot());
+
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ };
+
+ TString result1 = EncodeToString(EncoderJson, writeDocument);
+ UNIT_ASSERT_NO_DIFF(result1, NResource::Find("/histogram_timeseries.json"));
+
+ TString result2 = EncodeToString(BufferedEncoderJson, writeDocument);
+ UNIT_ASSERT_NO_DIFF(result2, NResource::Find("/histogram_timeseries.json"));
+ }
+
+ Y_UNIT_TEST(HistogramTimeSeriesDecode) {
+ NProto::TMultiSamplesList samples;
+ {
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TString testJson = NResource::Find("/histogram_timeseries.json");
+ DecodeJson(testJson, e.Get());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(1, samples.SamplesSize());
+ const NProto::TMultiSample& s = samples.GetSamples(0);
+
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::HIST_RATE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "metric", "responseTimeMillis");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 2);
+
+ auto h = ExponentialHistogram(6, 2);
+ for (i64 i = 1; i < 100; i++) {
+ h->Collect(i);
+ }
+
+ AssertPointEqual(s.GetPoints(0), now, *h->Snapshot());
+
+ for (i64 i = 1; i < 100; i++) {
+ h->Collect(i);
+ }
+
+ AssertPointEqual(s.GetPoints(1), now + TDuration::Seconds(15), *h->Snapshot());
+ }
+
+ Y_UNIT_TEST(IntGaugeEncode) {
+ auto writeDocument = [](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ {
+ e->OnMetricBegin(EMetricType::IGAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("metric", "a");
+ e->OnLabelsEnd();
+ }
+ e->OnInt64(now, Min<i64>());
+ e->OnInt64(now + TDuration::Seconds(1), -1);
+ e->OnInt64(now + TDuration::Seconds(2), 0);
+ e->OnInt64(now + TDuration::Seconds(3), Max<i64>());
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ };
+
+ TString result1 = EncodeToString(EncoderJson, writeDocument);
+ UNIT_ASSERT_NO_DIFF(result1, NResource::Find("/int_gauge.json"));
+
+ TString result2 = EncodeToString(BufferedEncoderJson, writeDocument);
+ UNIT_ASSERT_NO_DIFF(result2, NResource::Find("/int_gauge.json"));
+ }
+
+ Y_UNIT_TEST(InconsistentMetricTypes) {
+ auto emitMetrics = [](IMetricEncoder& encoder, const TString& expectedError) {
+ encoder.OnMetricBegin(EMetricType::GAUGE);
+ {
+ encoder.OnLabelsBegin();
+ encoder.OnLabel("name", "m");
+ encoder.OnLabel("l1", "v1");
+ encoder.OnLabel("l2", "v2");
+ encoder.OnLabelsEnd();
+ }
+ encoder.OnDouble(now, 1.0);
+ encoder.OnMetricEnd();
+
+ encoder.OnMetricBegin(EMetricType::COUNTER);
+ {
+ encoder.OnLabelsBegin();
+ encoder.OnLabel("name", "m");
+ encoder.OnLabel("l1", "v1");
+ encoder.OnLabel("l2", "v2");
+ encoder.OnLabelsEnd();
+ }
+ encoder.OnUint64(now, 1);
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(encoder.OnMetricEnd(),
+ yexception,
+ expectedError);
+ };
+
+ {
+ TStringStream out;
+ auto encoder = BufferedEncoderJson(&out);
+
+ encoder->OnStreamBegin();
+ encoder->OnLabelsBegin();
+ encoder->OnLabel("c", "cv");
+ encoder->OnLabelsEnd();
+ emitMetrics(*encoder,
+ "Time series point type mismatch: expected DOUBLE but found UINT64, "
+ "labels '{c=cv, l1=v1, l2=v2, name=m}'");
+ }
+
+ {
+ TStringStream out;
+ auto encoder = BufferedEncoderJson(&out);
+
+ encoder->OnStreamBegin();
+ encoder->OnLabelsBegin();
+ encoder->OnLabel("l1", "v100");
+ encoder->OnLabelsEnd();
+ emitMetrics(*encoder,
+ "Time series point type mismatch: expected DOUBLE but found UINT64, "
+ "labels '{l1=v1, l2=v2, name=m}'");
+ }
+ }
+
+ Y_UNIT_TEST(IntGaugeDecode) {
+ NProto::TMultiSamplesList samples;
+ {
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TString testJson = NResource::Find("/int_gauge.json");
+ DecodeJson(testJson, e.Get());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(1, samples.SamplesSize());
+ const NProto::TMultiSample& s = samples.GetSamples(0);
+
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::IGAUGE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "metric", "a");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 4);
+ AssertPointEqual(s.GetPoints(0), now, Min<i64>());
+ AssertPointEqual(s.GetPoints(1), now + TDuration::Seconds(1), i64(-1));
+ AssertPointEqual(s.GetPoints(2), now + TDuration::Seconds(2), i64(0));
+ AssertPointEqual(s.GetPoints(3), now + TDuration::Seconds(3), Max<i64>());
+ }
+
+ Y_UNIT_TEST(FuzzerRegression) {
+ NProto::TMultiSamplesList samples;
+ {
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ for (auto f : { "/hist_crash.json", "/crash.json" }) {
+ TString testJson = NResource::Find(f);
+ UNIT_ASSERT_EXCEPTION(DecodeJson(testJson, e.Get()), yexception);
+ }
+ }
+ }
+
+ Y_UNIT_TEST(LegacyNegativeRateThrows) {
+ const auto input = R"({
+ "sensors": [
+ {
+ "mode": "deriv",
+ "value": -1,
+ "labels": { "metric": "SystemTime" }
+ },
+ }
+ ]}")";
+
+ NProto::TMultiSamplesList samples;
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+ UNIT_ASSERT_EXCEPTION(DecodeJson(input, e.Get()), yexception);
+ }
+
+ Y_UNIT_TEST(DecodeNamedMetrics) {
+ NProto::TMultiSamplesList samples;
+ {
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TString metricsJson = NResource::Find("/named_metrics.json");
+ DecodeJson(metricsJson, e.Get(), "sensor");
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.SamplesSize(), 2);
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(0);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "sensor", "Memory");
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(1);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 2);
+ AssertLabelEqual(s.GetLabels(0), "sensor", "QueueSize");
+ AssertLabelEqual(s.GetLabels(1), "export", "Oxygen");
+ }
+ }
+
+}
diff --git a/library/cpp/monlib/encode/json/typed_point.h b/library/cpp/monlib/encode/json/typed_point.h
new file mode 100644
index 0000000000..fbaa840c4b
--- /dev/null
+++ b/library/cpp/monlib/encode/json/typed_point.h
@@ -0,0 +1,123 @@
+#pragma once
+
+#include <library/cpp/monlib/metrics/metric_value.h>
+
+
+namespace NMonitoring {
+
+ class TTypedPoint {
+ public:
+ TTypedPoint()
+ : Time_(TInstant::Zero())
+ , ValueType_(EMetricValueType::UNKNOWN)
+ {
+ }
+
+ template <typename T>
+ TTypedPoint(TInstant time, T value)
+ : Time_(time)
+ , ValueType_(TValueType<T>::Type)
+ , Value_(value)
+ {
+ Ref();
+ }
+
+ ~TTypedPoint() {
+ UnRef();
+ }
+
+ TTypedPoint(const TTypedPoint& rhs)
+ : Time_(rhs.Time_)
+ , ValueType_(rhs.ValueType_)
+ , Value_(rhs.Value_)
+ {
+ Ref();
+ }
+
+ TTypedPoint& operator=(const TTypedPoint& rhs) {
+ UnRef();
+
+ Time_ = rhs.Time_;
+ ValueType_ = rhs.ValueType_;
+ Value_ = rhs.Value_;
+
+ Ref();
+ return *this;
+ }
+
+ TTypedPoint(TTypedPoint&& rhs) noexcept
+ : Time_(rhs.Time_)
+ , ValueType_(rhs.ValueType_)
+ , Value_(rhs.Value_)
+ {
+ rhs.ValueType_ = EMetricValueType::UNKNOWN;
+ rhs.Value_ = {};
+ }
+
+ TTypedPoint& operator=(TTypedPoint&& rhs) noexcept {
+ UnRef();
+
+ Time_ = rhs.Time_;
+ ValueType_ = rhs.ValueType_;
+ Value_ = rhs.Value_;
+
+ rhs.ValueType_ = EMetricValueType::UNKNOWN;
+ rhs.Value_ = {};
+
+ return *this;
+ }
+
+ TInstant GetTime() const noexcept {
+ return Time_;
+ }
+
+ void SetTime(TInstant time) noexcept {
+ Time_ = time;
+ }
+
+ TMetricValue GetValue() const noexcept {
+ return Value_;
+ }
+
+ EMetricValueType GetValueType() const noexcept {
+ return ValueType_;
+ }
+
+ template <typename T>
+ void SetValue(T value) noexcept {
+ ValueType_ = TValueType<T>::Type;
+ Value_ = TMetricValue{value};
+ }
+
+ bool HasValue() {
+ return ValueType_ != EMetricValueType::UNKNOWN;
+ }
+
+ private:
+ void Ref() {
+ if (ValueType_ == EMetricValueType::HISTOGRAM) {
+ Value_.AsHistogram()->Ref();
+ } else if (ValueType_ == EMetricValueType::SUMMARY) {
+ Value_.AsSummaryDouble()->Ref();
+ } else if (ValueType_ == EMetricValueType::LOGHISTOGRAM) {
+ Value_.AsLogHistogram()->Ref();
+ }
+ }
+
+ void UnRef() {
+ if (ValueType_ == EMetricValueType::HISTOGRAM) {
+ Value_.AsHistogram()->UnRef();
+ } else if (ValueType_ == EMetricValueType::SUMMARY) {
+ Value_.AsSummaryDouble()->UnRef();
+ } else if (ValueType_ == EMetricValueType::LOGHISTOGRAM) {
+ Value_.AsLogHistogram()->UnRef();
+ }
+ }
+
+ private:
+ TInstant Time_;
+ EMetricValueType ValueType_;
+ TMetricValue Value_;
+ };
+
+}
diff --git a/library/cpp/monlib/encode/json/ut/buffered_test.json b/library/cpp/monlib/encode/json/ut/buffered_test.json
new file mode 100644
index 0000000000..53212cf8e1
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/buffered_test.json
@@ -0,0 +1,36 @@
+{
+ "sensors":
+ [
+ {
+ "kind":"COUNTER",
+ "labels":
+ {
+ "foo":"bar"
+ },
+ "timeseries":
+ [
+ {
+ "ts":1,
+ "value":42
+ },
+ {
+ "ts":2,
+ "value":42
+ },
+ {
+ "ts":4,
+ "value":42
+ }
+ ]
+ },
+ {
+ "kind":"COUNTER",
+ "labels":
+ {
+ "foo":"baz"
+ },
+ "ts":3,
+ "value":42
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/buffered_ts_merge.json b/library/cpp/monlib/encode/json/ut/buffered_ts_merge.json
new file mode 100644
index 0000000000..1d27efacb0
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/buffered_ts_merge.json
@@ -0,0 +1,13 @@
+{
+ "sensors":
+ [
+ {
+ "kind":"COUNTER",
+ "labels":
+ {
+ "foo":"bar"
+ },
+ "value":45
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/crash.json b/library/cpp/monlib/encode/json/ut/crash.json
new file mode 100644
index 0000000000..8ff4369dc4
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/crash.json
Binary files differ
diff --git a/library/cpp/monlib/encode/json/ut/empty_series.json b/library/cpp/monlib/encode/json/ut/empty_series.json
new file mode 100644
index 0000000000..641e10cdea
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/empty_series.json
@@ -0,0 +1,12 @@
+{
+ "sensors":
+ [
+ {
+ "kind":"COUNTER",
+ "labels":
+ {
+ "foo":"bar"
+ }
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/expected.json b/library/cpp/monlib/encode/json/ut/expected.json
new file mode 100644
index 0000000000..ead853455b
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/expected.json
@@ -0,0 +1,92 @@
+{
+ "ts":1500000000,
+ "commonLabels":
+ {
+ "project":"solomon"
+ },
+ "sensors":
+ [
+ {
+ "kind":"COUNTER",
+ "labels":
+ {
+ "metric":"single",
+ "labels":"l1"
+ },
+ "ts":1509843723,
+ "value":17
+ },
+ {
+ "kind":"RATE",
+ "labels":
+ {
+ "metric":"single",
+ "labels":"l2"
+ },
+ "ts":1509843723,
+ "value":17
+ },
+ {
+ "kind":"GAUGE",
+ "labels":
+ {
+ "metric":"single",
+ "labels":"l3"
+ },
+ "ts":1509843723,
+ "value":3.14
+ },
+ {
+ "kind":"IGAUGE",
+ "labels":
+ {
+ "metric":"single_igauge",
+ "labels":"l4"
+ },
+ "ts":1509843723,
+ "value":42
+ },
+ {
+ "kind":"GAUGE",
+ "labels":
+ {
+ "metric":"multiple",
+ "labels":"l5"
+ },
+ "timeseries":
+ [
+ {
+ "ts":1509843723,
+ "value":"nan"
+ },
+ {
+ "ts":1509843738,
+ "value":"inf"
+ },
+ {
+ "ts":1509843753,
+ "value":"-inf"
+ }
+ ]
+ },
+ {
+ "kind":"COUNTER",
+ "timeseries":
+ [
+ {
+ "ts":1509843723,
+ "value":1337
+ },
+ {
+ "ts":1509843738,
+ "value":1338
+ }
+ ],
+ "labels":
+ {
+ "metric":"multiple",
+ "labels":"l6"
+ }
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/expected_buffered.json b/library/cpp/monlib/encode/json/ut/expected_buffered.json
new file mode 100644
index 0000000000..9a6a1d6201
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/expected_buffered.json
@@ -0,0 +1,92 @@
+{
+ "ts":1500000000,
+ "commonLabels":
+ {
+ "project":"solomon"
+ },
+ "sensors":
+ [
+ {
+ "kind":"COUNTER",
+ "labels":
+ {
+ "labels":"l1",
+ "metric":"single"
+ },
+ "ts":1509843723,
+ "value":17
+ },
+ {
+ "kind":"RATE",
+ "labels":
+ {
+ "labels":"l2",
+ "metric":"single"
+ },
+ "ts":1509843723,
+ "value":17
+ },
+ {
+ "kind":"GAUGE",
+ "labels":
+ {
+ "labels":"l3",
+ "metric":"single"
+ },
+ "ts":1509843723,
+ "value":3.14
+ },
+ {
+ "kind":"IGAUGE",
+ "labels":
+ {
+ "labels":"l4",
+ "metric":"single_igauge"
+ },
+ "ts":1509843723,
+ "value":42
+ },
+ {
+ "kind":"GAUGE",
+ "labels":
+ {
+ "labels":"l5",
+ "metric":"multiple"
+ },
+ "timeseries":
+ [
+ {
+ "ts":1509843723,
+ "value":"nan"
+ },
+ {
+ "ts":1509843738,
+ "value":"inf"
+ },
+ {
+ "ts":1509843753,
+ "value":"-inf"
+ }
+ ]
+ },
+ {
+ "kind":"COUNTER",
+ "labels":
+ {
+ "labels":"l6",
+ "metric":"multiple"
+ },
+ "timeseries":
+ [
+ {
+ "ts":1509843723,
+ "value":1337
+ },
+ {
+ "ts":1509843738,
+ "value":1338
+ }
+ ]
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/expected_cloud.json b/library/cpp/monlib/encode/json/ut/expected_cloud.json
new file mode 100644
index 0000000000..6184811579
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/expected_cloud.json
@@ -0,0 +1,92 @@
+{
+ "ts":"2017-07-14T02:40:00.000000Z",
+ "labels":
+ {
+ "project":"solomon"
+ },
+ "metrics":
+ [
+ {
+ "type":"COUNTER",
+ "labels":
+ {
+ "labels":"l1"
+ },
+ "name":"single",
+ "ts":"2017-11-05T01:02:03.000000Z",
+ "value":17
+ },
+ {
+ "type":"RATE",
+ "labels":
+ {
+ "labels":"l2"
+ },
+ "name":"single",
+ "ts":"2017-11-05T01:02:03.000000Z",
+ "value":17
+ },
+ {
+ "type":"DGAUGE",
+ "labels":
+ {
+ "labels":"l3"
+ },
+ "name":"single",
+ "ts":"2017-11-05T01:02:03.000000Z",
+ "value":3.14
+ },
+ {
+ "type":"IGAUGE",
+ "labels":
+ {
+ "labels":"l4"
+ },
+ "name":"single_igauge",
+ "ts":"2017-11-05T01:02:03.000000Z",
+ "value":42
+ },
+ {
+ "type":"DGAUGE",
+ "labels":
+ {
+ "labels":"l5"
+ },
+ "name":"multiple",
+ "timeseries":
+ [
+ {
+ "ts":"2017-11-05T01:02:03.000000Z",
+ "value":"nan"
+ },
+ {
+ "ts":"2017-11-05T01:02:18.000000Z",
+ "value":"inf"
+ },
+ {
+ "ts":"2017-11-05T01:02:33.000000Z",
+ "value":"-inf"
+ }
+ ]
+ },
+ {
+ "type":"COUNTER",
+ "timeseries":
+ [
+ {
+ "ts":"2017-11-05T01:02:03.000000Z",
+ "value":1337
+ },
+ {
+ "ts":"2017-11-05T01:02:18.000000Z",
+ "value":1338
+ }
+ ],
+ "labels":
+ {
+ "labels":"l6"
+ },
+ "name":"multiple"
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/expected_cloud_buffered.json b/library/cpp/monlib/encode/json/ut/expected_cloud_buffered.json
new file mode 100644
index 0000000000..be237d522b
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/expected_cloud_buffered.json
@@ -0,0 +1,92 @@
+{
+ "ts":"2017-07-14T02:40:00.000000Z",
+ "labels":
+ {
+ "project":"solomon"
+ },
+ "metrics":
+ [
+ {
+ "type":"COUNTER",
+ "labels":
+ {
+ "labels":"l1"
+ },
+ "name":"single",
+ "ts":"2017-11-05T01:02:03.000000Z",
+ "value":17
+ },
+ {
+ "type":"RATE",
+ "labels":
+ {
+ "labels":"l2"
+ },
+ "name":"single",
+ "ts":"2017-11-05T01:02:03.000000Z",
+ "value":17
+ },
+ {
+ "type":"DGAUGE",
+ "labels":
+ {
+ "labels":"l3"
+ },
+ "name":"single",
+ "ts":"2017-11-05T01:02:03.000000Z",
+ "value":3.14
+ },
+ {
+ "type":"IGAUGE",
+ "labels":
+ {
+ "labels":"l4"
+ },
+ "name":"single_igauge",
+ "ts":"2017-11-05T01:02:03.000000Z",
+ "value":42
+ },
+ {
+ "type":"DGAUGE",
+ "labels":
+ {
+ "labels":"l5"
+ },
+ "name":"multiple",
+ "timeseries":
+ [
+ {
+ "ts":"2017-11-05T01:02:03.000000Z",
+ "value":"nan"
+ },
+ {
+ "ts":"2017-11-05T01:02:18.000000Z",
+ "value":"inf"
+ },
+ {
+ "ts":"2017-11-05T01:02:33.000000Z",
+ "value":"-inf"
+ }
+ ]
+ },
+ {
+ "type":"COUNTER",
+ "labels":
+ {
+ "labels":"l6"
+ },
+ "name":"multiple",
+ "timeseries":
+ [
+ {
+ "ts":"2017-11-05T01:02:03.000000Z",
+ "value":1337
+ },
+ {
+ "ts":"2017-11-05T01:02:18.000000Z",
+ "value":1338
+ }
+ ]
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/hist_crash.json b/library/cpp/monlib/encode/json/ut/hist_crash.json
new file mode 100644
index 0000000000..867d0fce7d
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/hist_crash.json
Binary files differ
diff --git a/library/cpp/monlib/encode/json/ut/histogram_timeseries.json b/library/cpp/monlib/encode/json/ut/histogram_timeseries.json
new file mode 100644
index 0000000000..f6131ffded
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/histogram_timeseries.json
@@ -0,0 +1,61 @@
+{
+ "sensors":
+ [
+ {
+ "kind":"HIST_RATE",
+ "labels":
+ {
+ "metric":"responseTimeMillis"
+ },
+ "timeseries":
+ [
+ {
+ "ts":1509843723,
+ "hist":
+ {
+ "bounds":
+ [
+ 1,
+ 2,
+ 4,
+ 8,
+ 16
+ ],
+ "buckets":
+ [
+ 1,
+ 1,
+ 2,
+ 4,
+ 8
+ ],
+ "inf":83
+ }
+ },
+ {
+ "ts":1509843738,
+ "hist":
+ {
+ "bounds":
+ [
+ 1,
+ 2,
+ 4,
+ 8,
+ 16
+ ],
+ "buckets":
+ [
+ 2,
+ 2,
+ 4,
+ 8,
+ 16
+ ],
+ "inf":166
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/histogram_value.json b/library/cpp/monlib/encode/json/ut/histogram_value.json
new file mode 100644
index 0000000000..ec1ae5cdec
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/histogram_value.json
@@ -0,0 +1,33 @@
+{
+ "sensors":
+ [
+ {
+ "kind":"HIST",
+ "labels":
+ {
+ "metric":"responseTimeMillis"
+ },
+ "ts":1509843723,
+ "hist":
+ {
+ "bounds":
+ [
+ 1,
+ 2,
+ 4,
+ 8,
+ 16
+ ],
+ "buckets":
+ [
+ 1,
+ 1,
+ 2,
+ 4,
+ 8
+ ],
+ "inf":83
+ }
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/histogram_value_inf_before_bounds.json b/library/cpp/monlib/encode/json/ut/histogram_value_inf_before_bounds.json
new file mode 100644
index 0000000000..f8a17c8831
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/histogram_value_inf_before_bounds.json
@@ -0,0 +1,33 @@
+{
+ "sensors":
+ [
+ {
+ "kind":"HIST",
+ "labels":
+ {
+ "metric":"responseTimeMillis"
+ },
+ "ts":1509843723,
+ "hist":
+ {
+ "inf":83,
+ "bounds":
+ [
+ 1,
+ 2,
+ 4,
+ 8,
+ 16
+ ],
+ "buckets":
+ [
+ 1,
+ 1,
+ 2,
+ 4,
+ 8
+ ]
+ }
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/int_gauge.json b/library/cpp/monlib/encode/json/ut/int_gauge.json
new file mode 100644
index 0000000000..fbe57f873c
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/int_gauge.json
@@ -0,0 +1,31 @@
+{
+ "sensors":
+ [
+ {
+ "kind":"IGAUGE",
+ "labels":
+ {
+ "metric":"a"
+ },
+ "timeseries":
+ [
+ {
+ "ts":1509843723,
+ "value":-9223372036854775808
+ },
+ {
+ "ts":1509843724,
+ "value":-1
+ },
+ {
+ "ts":1509843725,
+ "value":0
+ },
+ {
+ "ts":1509843726,
+ "value":9223372036854775807
+ }
+ ]
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/log_histogram_timeseries.json b/library/cpp/monlib/encode/json/ut/log_histogram_timeseries.json
new file mode 100644
index 0000000000..e811a2cc57
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/log_histogram_timeseries.json
@@ -0,0 +1,47 @@
+{
+ "sensors":
+ [
+ {
+ "kind":"LOGHIST",
+ "labels":
+ {
+ "metric":"ms"
+ },
+ "timeseries":
+ [
+ {
+ "ts":1509843723,
+ "log_hist":
+ {
+ "base":1.5,
+ "zeros_count":1,
+ "start_power":0,
+ "buckets":
+ [
+ 0.5,
+ 0.25,
+ 0.25,
+ 0.5
+ ]
+ }
+ },
+ {
+ "ts":1509843738,
+ "log_hist":
+ {
+ "base":1.5,
+ "zeros_count":1,
+ "start_power":0,
+ "buckets":
+ [
+ 1,
+ 0.5,
+ 0.5,
+ 1
+ ]
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/log_histogram_value.json b/library/cpp/monlib/encode/json/ut/log_histogram_value.json
new file mode 100644
index 0000000000..002478293b
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/log_histogram_value.json
@@ -0,0 +1,26 @@
+{
+ "sensors":
+ [
+ {
+ "kind":"LOGHIST",
+ "labels":
+ {
+ "metric":"ms"
+ },
+ "ts":1509843723,
+ "log_hist":
+ {
+ "base":1.5,
+ "zeros_count":1,
+ "start_power":0,
+ "buckets":
+ [
+ 0.5,
+ 0.25,
+ 0.25,
+ 0.5
+ ]
+ }
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/merged.json b/library/cpp/monlib/encode/json/ut/merged.json
new file mode 100644
index 0000000000..ea2c99a33c
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/merged.json
@@ -0,0 +1,14 @@
+{
+ "sensors":
+ [
+ {
+ "kind":"RATE",
+ "labels":
+ {
+ "metric":"hello",
+ "label":"world"
+ },
+ "value":1
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/metrics.json b/library/cpp/monlib/encode/json/ut/metrics.json
new file mode 100644
index 0000000000..2be4617d51
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/metrics.json
@@ -0,0 +1,43 @@
+{
+ "labels": {
+ "project": "solomon",
+ "cluster": "man",
+ "service": "stockpile"
+ },
+ "metrics": [
+ {
+ "type": "DGAUGE",
+ "labels": {
+ "metric": "Memory"
+ },
+ "value": 10
+ },
+ {
+ "type": "RATE",
+ "value": 1,
+ "labels": { "metric": "UserTime" }
+ },
+ {
+ "type": "GAUGE",
+ "value": 3.14159,
+ "labels": { "export": "Oxygen", "metric": "QueueSize" },
+ "ts": "2017-11-05T12:34:56.000Z",
+ "memOnly": true
+ },
+ {
+ "type": "GAUGE",
+ "labels": { "metric": "Writes" },
+ "timeseries": [
+ {
+ "ts": "2017-08-28T12:32:11Z",
+ "value": -10
+ },
+ {
+ "value": 20,
+ "ts": 1503923187
+ }
+ ]
+ }
+ ],
+ "ts": "2017-08-27T12:34:56Z"
+}
diff --git a/library/cpp/monlib/encode/json/ut/named_metrics.json b/library/cpp/monlib/encode/json/ut/named_metrics.json
new file mode 100644
index 0000000000..98f93e8c39
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/named_metrics.json
@@ -0,0 +1,22 @@
+{
+ "labels": {
+ "project": "solomon",
+ "cluster": "prod-sas",
+ "service": "stockpile"
+ },
+ "metrics": [
+ {
+ "type": "DGAUGE",
+ "name": "Memory",
+ "value": 1
+ },
+ {
+ "type": "DGAUGE",
+ "name": "QueueSize",
+ "labels": {
+ "export": "Oxygen"
+ },
+ "value": 10
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/sensors.json b/library/cpp/monlib/encode/json/ut/sensors.json
new file mode 100644
index 0000000000..4d979a3c1e
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/sensors.json
@@ -0,0 +1,40 @@
+{
+ "commonLabels": {
+ "project": "solomon",
+ "cluster": "man",
+ "service": "stockpile"
+ },
+ "sensors": [
+ {
+ "labels": {
+ "metric": "Memory"
+ },
+ "value": 10
+ },
+ {
+ "mode": "deriv",
+ "value": 1,
+ "labels": { "metric": "UserTime" }
+ },
+ {
+ "value": 3.14159,
+ "labels": { "export": "Oxygen", "metric": "QueueSize" },
+ "ts": "2017-11-05T12:34:56.000Z",
+ "memOnly": true
+ },
+ {
+ "labels": { "metric": "Writes" },
+ "timeseries": [
+ {
+ "ts": "2017-08-28T12:32:11Z",
+ "value": -10
+ },
+ {
+ "value": 20,
+ "ts": 1503923187
+ }
+ ]
+ }
+ ],
+ "ts": "2017-08-27T12:34:56Z"
+}
diff --git a/library/cpp/monlib/encode/json/ut/summary_inf.json b/library/cpp/monlib/encode/json/ut/summary_inf.json
new file mode 100644
index 0000000000..625a6cd8ad
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/summary_inf.json
@@ -0,0 +1,21 @@
+{
+ "sensors":
+ [
+ {
+ "kind":"DSUMMARY",
+ "labels":
+ {
+ "metric":"temperature"
+ },
+ "ts":1509843723,
+ "summary":
+ {
+ "sum":"nan",
+ "min":"-inf",
+ "max":"inf",
+ "last":0.3,
+ "count":30
+ }
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/summary_timeseries.json b/library/cpp/monlib/encode/json/ut/summary_timeseries.json
new file mode 100644
index 0000000000..92007af3e6
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/summary_timeseries.json
@@ -0,0 +1,37 @@
+{
+ "sensors":
+ [
+ {
+ "kind":"DSUMMARY",
+ "labels":
+ {
+ "metric":"temperature"
+ },
+ "timeseries":
+ [
+ {
+ "ts":1509843723,
+ "summary":
+ {
+ "sum":0.8,
+ "min":-0.5,
+ "max":1,
+ "last":1,
+ "count":3
+ }
+ },
+ {
+ "ts":1509843738,
+ "summary":
+ {
+ "sum":-0.69,
+ "min":-1.5,
+ "max":1,
+ "last":0.01,
+ "count":5
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/summary_value.json b/library/cpp/monlib/encode/json/ut/summary_value.json
new file mode 100644
index 0000000000..366394c5e1
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/summary_value.json
@@ -0,0 +1,21 @@
+{
+ "sensors":
+ [
+ {
+ "kind":"DSUMMARY",
+ "labels":
+ {
+ "metric":"temperature"
+ },
+ "ts":1509843723,
+ "summary":
+ {
+ "sum":10,
+ "min":-0.5,
+ "max":0.5,
+ "last":0.3,
+ "count":30
+ }
+ }
+ ]
+}
diff --git a/library/cpp/monlib/encode/json/ut/test_decode_to_encode.json b/library/cpp/monlib/encode/json/ut/test_decode_to_encode.json
new file mode 100644
index 0000000000..65f0c5c6e2
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/test_decode_to_encode.json
@@ -0,0 +1,16 @@
+{
+ "commonLabels": {
+ "project": "solomon",
+ "cluster": "man",
+ "service": "stockpile"
+ },
+ "sensors": [
+ {
+ "kind": "GAUGE",
+ "labels": { "export": "Oxygen", "metric": "QueueSize" },
+ "ts": 1509885296,
+ "value": 3.14159
+ }
+ ],
+ "ts": 1503837296
+}
diff --git a/library/cpp/monlib/encode/json/ut/ya.make b/library/cpp/monlib/encode/json/ut/ya.make
new file mode 100644
index 0000000000..e50c4f4903
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ut/ya.make
@@ -0,0 +1,46 @@
+UNITTEST_FOR(library/cpp/monlib/encode/json)
+
+OWNER(
+ g:solomon
+ jamel
+)
+
+SRCS(
+ json_decoder_ut.cpp
+ json_ut.cpp
+)
+
+RESOURCE(
+ buffered_test.json /buffered_test.json
+ buffered_ts_merge.json /buffered_ts_merge.json
+ empty_series.json /empty_series.json
+ expected.json /expected.json
+ expected_buffered.json /expected_buffered.json
+ expected_cloud.json /expected_cloud.json
+ expected_cloud_buffered.json /expected_cloud_buffered.json
+ merged.json /merged.json
+ histogram_timeseries.json /histogram_timeseries.json
+ histogram_value.json /histogram_value.json
+ histogram_value_inf_before_bounds.json /histogram_value_inf_before_bounds.json
+ int_gauge.json /int_gauge.json
+ sensors.json /sensors.json
+ metrics.json /metrics.json
+ named_metrics.json /named_metrics.json
+ test_decode_to_encode.json /test_decode_to_encode.json
+ crash.json /crash.json
+ hist_crash.json /hist_crash.json
+ summary_value.json /summary_value.json
+ summary_inf.json /summary_inf.json
+ summary_timeseries.json /summary_timeseries.json
+ log_histogram_value.json /log_histogram_value.json
+ log_histogram_timeseries.json /log_histogram_timeseries.json
+)
+
+PEERDIR(
+ library/cpp/json
+ library/cpp/monlib/consumers
+ library/cpp/monlib/encode/protobuf
+ library/cpp/resource
+)
+
+END()
diff --git a/library/cpp/monlib/encode/json/ya.make b/library/cpp/monlib/encode/json/ya.make
new file mode 100644
index 0000000000..a50fc412a9
--- /dev/null
+++ b/library/cpp/monlib/encode/json/ya.make
@@ -0,0 +1,21 @@
+LIBRARY()
+
+OWNER(
+ g:solomon
+ jamel
+)
+
+SRCS(
+ json_decoder.cpp
+ json_encoder.cpp
+)
+
+PEERDIR(
+ library/cpp/monlib/encode
+ library/cpp/monlib/encode/buffered
+ library/cpp/monlib/exception
+ library/cpp/json
+ library/cpp/json/writer
+)
+
+END()
diff --git a/library/cpp/monlib/encode/legacy_protobuf/legacy_proto_decoder.cpp b/library/cpp/monlib/encode/legacy_protobuf/legacy_proto_decoder.cpp
new file mode 100644
index 0000000000..f87a2d7e8f
--- /dev/null
+++ b/library/cpp/monlib/encode/legacy_protobuf/legacy_proto_decoder.cpp
@@ -0,0 +1,527 @@
+#include "legacy_protobuf.h"
+
+#include <library/cpp/monlib/encode/legacy_protobuf/protos/metric_meta.pb.h>
+#include <library/cpp/monlib/metrics/metric_consumer.h>
+#include <library/cpp/monlib/metrics/labels.h>
+
+#include <util/generic/yexception.h>
+#include <util/generic/maybe.h>
+#include <util/datetime/base.h>
+#include <util/string/split.h>
+
+#include <google/protobuf/reflection.h>
+
+#include <algorithm>
+
+#ifdef LEGACY_PB_TRACE
+#define TRACE(msg) \
+ Cerr << msg << Endl
+#else
+#define TRACE(...) ;
+#endif
+
+namespace NMonitoring {
+ namespace {
+ using TMaybeMeta = TMaybe<NMonProto::TMetricMeta>;
+
+ TString ReadLabelValue(const NProtoBuf::Message& msg, const NProtoBuf::FieldDescriptor* d, const NProtoBuf::Reflection& r) {
+ using namespace NProtoBuf;
+
+ switch (d->type()) {
+ case FieldDescriptor::TYPE_UINT32:
+ return ::ToString(r.GetUInt32(msg, d));
+ case FieldDescriptor::TYPE_UINT64:
+ return ::ToString(r.GetUInt64(msg, d));
+ case FieldDescriptor::TYPE_STRING:
+ return r.GetString(msg, d);
+ case FieldDescriptor::TYPE_ENUM: {
+ auto val = r.GetEnumValue(msg, d);
+ auto* valDesc = d->enum_type()->FindValueByNumber(val);
+ return valDesc->name();
+ }
+
+ default:
+ ythrow yexception() << "type " << d->type_name() << " cannot be used as a field value";
+ }
+
+ return {};
+ }
+
+ double ReadFieldAsDouble(const NProtoBuf::Message& msg, const NProtoBuf::FieldDescriptor* d, const NProtoBuf::Reflection& r) {
+ using namespace NProtoBuf;
+
+ switch (d->type()) {
+ case FieldDescriptor::TYPE_DOUBLE:
+ return r.GetDouble(msg, d);
+ case FieldDescriptor::TYPE_BOOL:
+ return r.GetBool(msg, d) ? 1 : 0;
+ case FieldDescriptor::TYPE_INT32:
+ return r.GetInt32(msg, d);
+ case FieldDescriptor::TYPE_INT64:
+ return r.GetInt64(msg, d);
+ case FieldDescriptor::TYPE_UINT32:
+ return r.GetUInt32(msg, d);
+ case FieldDescriptor::TYPE_UINT64:
+ return r.GetUInt64(msg, d);
+ case FieldDescriptor::TYPE_SINT32:
+ return r.GetInt32(msg, d);
+ case FieldDescriptor::TYPE_SINT64:
+ return r.GetInt64(msg, d);
+ case FieldDescriptor::TYPE_FIXED32:
+ return r.GetUInt32(msg, d);
+ case FieldDescriptor::TYPE_FIXED64:
+ return r.GetUInt64(msg, d);
+ case FieldDescriptor::TYPE_SFIXED32:
+ return r.GetInt32(msg, d);
+ case FieldDescriptor::TYPE_SFIXED64:
+ return r.GetInt64(msg, d);
+ case FieldDescriptor::TYPE_FLOAT:
+ return r.GetFloat(msg, d);
+ case FieldDescriptor::TYPE_ENUM:
+ return r.GetEnumValue(msg, d);
+ default:
+ ythrow yexception() << "type " << d->type_name() << " cannot be used as a field value";
+ }
+
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+
+ double ReadRepeatedAsDouble(const NProtoBuf::Message& msg, const NProtoBuf::FieldDescriptor* d, const NProtoBuf::Reflection& r, size_t i) {
+ using namespace NProtoBuf;
+
+ switch (d->type()) {
+ case FieldDescriptor::TYPE_DOUBLE:
+ return r.GetRepeatedDouble(msg, d, i);
+ case FieldDescriptor::TYPE_BOOL:
+ return r.GetRepeatedBool(msg, d, i) ? 1 : 0;
+ case FieldDescriptor::TYPE_INT32:
+ return r.GetRepeatedInt32(msg, d, i);
+ case FieldDescriptor::TYPE_INT64:
+ return r.GetRepeatedInt64(msg, d, i);
+ case FieldDescriptor::TYPE_UINT32:
+ return r.GetRepeatedUInt32(msg, d, i);
+ case FieldDescriptor::TYPE_UINT64:
+ return r.GetRepeatedUInt64(msg, d, i);
+ case FieldDescriptor::TYPE_SINT32:
+ return r.GetRepeatedInt32(msg, d, i);
+ case FieldDescriptor::TYPE_SINT64:
+ return r.GetRepeatedInt64(msg, d, i);
+ case FieldDescriptor::TYPE_FIXED32:
+ return r.GetRepeatedUInt32(msg, d, i);
+ case FieldDescriptor::TYPE_FIXED64:
+ return r.GetRepeatedUInt64(msg, d, i);
+ case FieldDescriptor::TYPE_SFIXED32:
+ return r.GetRepeatedInt32(msg, d, i);
+ case FieldDescriptor::TYPE_SFIXED64:
+ return r.GetRepeatedInt64(msg, d, i);
+ case FieldDescriptor::TYPE_FLOAT:
+ return r.GetRepeatedFloat(msg, d, i);
+ case FieldDescriptor::TYPE_ENUM:
+ return r.GetRepeatedEnumValue(msg, d, i);
+ default:
+ ythrow yexception() << "type " << d->type_name() << " cannot be used as a field value";
+ }
+
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+
+ TString LabelFromField(const NProtoBuf::Message& msg, const TString& name) {
+ const auto* fieldDesc = msg.GetDescriptor()->FindFieldByName(name);
+ const auto* reflection = msg.GetReflection();
+ Y_ENSURE(fieldDesc && reflection, "Unable to get meta for field " << name);
+
+ auto s = ReadLabelValue(msg, fieldDesc, *reflection);
+ std::replace(std::begin(s), s.vend(), ' ', '_');
+
+ return s;
+ }
+
+ TMaybeMeta MaybeGetMeta(const NProtoBuf::FieldOptions& opts) {
+ if (opts.HasExtension(NMonProto::Metric)) {
+ return opts.GetExtension(NMonProto::Metric);
+ }
+
+ return Nothing();
+ }
+
+ class ILabelGetter: public TThrRefBase {
+ public:
+ enum class EType {
+ Fixed = 1,
+ Lazy = 2,
+ };
+
+ virtual TLabel Get(const NProtoBuf::Message&) = 0;
+ virtual EType Type() const = 0;
+ };
+
+ class TFixedLabel: public ILabelGetter {
+ public:
+ explicit TFixedLabel(TLabel&& l)
+ : Label_{std::move(l)}
+ {
+ TRACE("found fixed label " << l);
+ }
+
+ EType Type() const override {
+ return EType::Fixed;
+ }
+ TLabel Get(const NProtoBuf::Message&) override {
+ return Label_;
+ }
+
+ private:
+ TLabel Label_;
+ };
+
+ using TFunction = std::function<TLabel(const NProtoBuf::Message&)>;
+
+ class TLazyLabel: public ILabelGetter {
+ public:
+ TLazyLabel(TFunction&& fn)
+ : Fn_{std::move(fn)}
+ {
+ TRACE("found lazy label");
+ }
+
+ EType Type() const override {
+ return EType::Lazy;
+ }
+ TLabel Get(const NProtoBuf::Message& msg) override {
+ return Fn_(msg);
+ }
+
+ private:
+ TFunction Fn_;
+ };
+
+ class TDecoderContext {
+ public:
+ void Init(const NProtoBuf::Message* msg) {
+ Message_ = msg;
+ Y_ENSURE(Message_);
+ Reflection_ = msg->GetReflection();
+ Y_ENSURE(Reflection_);
+
+ for (auto it = Labels_.begin(); it != Labels_.end(); ++it) {
+ if ((*it)->Type() == ILabelGetter::EType::Lazy) {
+ auto l = (*it)->Get(Message());
+ *it = ::MakeIntrusive<TFixedLabel>(std::move(l));
+ } else {
+ auto l = (*it)->Get(Message());
+ }
+ }
+ }
+
+ void Clear() noexcept {
+ Message_ = nullptr;
+ Reflection_ = nullptr;
+ }
+
+ TDecoderContext CreateChildFromMeta(const NMonProto::TMetricMeta& metricMeta, const TString& name, i64 repeatedIdx = -1) {
+ TDecoderContext child{*this};
+ child.Clear();
+
+ if (metricMeta.HasCustomPath()) {
+ if (const auto& nodePath = metricMeta.GetCustomPath()) {
+ child.AppendPath(nodePath);
+ }
+ } else if (metricMeta.GetPath()) {
+ child.AppendPath(name);
+ }
+
+ if (metricMeta.HasKeys()) {
+ child.ParseKeys(metricMeta.GetKeys(), repeatedIdx);
+ }
+
+ return child;
+ }
+
+ TDecoderContext CreateChildFromRepeatedScalar(const NMonProto::TMetricMeta& metricMeta, i64 repeatedIdx = -1) {
+ TDecoderContext child{*this};
+ child.Clear();
+
+ if (metricMeta.HasKeys()) {
+ child.ParseKeys(metricMeta.GetKeys(), repeatedIdx);
+ }
+
+ return child;
+ }
+
+ TDecoderContext CreateChildFromEls(const TString& name, const NMonProto::TExtraLabelMetrics& metrics, size_t idx, TMaybeMeta maybeMeta) {
+ TDecoderContext child{*this};
+ child.Clear();
+
+ auto usePath = [&maybeMeta] {
+ return !maybeMeta->HasPath() || maybeMeta->GetPath();
+ };
+
+ if (!name.empty() && (!maybeMeta || usePath())) {
+ child.AppendPath(name);
+ }
+
+ child.Labels_.push_back(::MakeIntrusive<TLazyLabel>(
+ [ labelName = metrics.GetlabelName(), idx, &metrics ](const auto&) {
+ const auto& val = metrics.Getvalues(idx);
+ TString labelVal;
+ const auto uintLabel = val.GetlabelValueUint();
+
+ if (uintLabel) {
+ labelVal = ::ToString(uintLabel);
+ } else {
+ labelVal = val.GetlabelValue();
+ }
+
+ return TLabel{labelName, labelVal};
+ }));
+
+ return child;
+ }
+
+ void ParseKeys(TStringBuf keys, i64 repeatedIdx = -1) {
+ auto parts = StringSplitter(keys)
+ .Split(' ')
+ .SkipEmpty();
+
+ for (auto part : parts) {
+ auto str = part.Token();
+
+ TStringBuf lhs, rhs;
+
+ const bool isDynamic = str.TrySplit(':', lhs, rhs);
+ const bool isIndexing = isDynamic && rhs == TStringBuf("#");
+
+ if (isIndexing) {
+ TRACE("parsed index labels");
+
+ // <label_name>:# means that we should use index of the repeated
+ // field as label value
+ Y_ENSURE(repeatedIdx != -1);
+ Labels_.push_back(::MakeIntrusive<TLazyLabel>([=](const auto&) {
+ return TLabel{lhs, ::ToString(repeatedIdx)};
+ }));
+ } else if (isDynamic) {
+ TRACE("parsed dynamic labels");
+
+ // <label_name>:<field_name> means that we need to take label value
+ // later from message's field
+ Labels_.push_back(::MakeIntrusive<TLazyLabel>([=](const auto& msg) {
+ return TLabel{lhs, LabelFromField(msg, TString{rhs})};
+ }));
+ } else if (str.TrySplit('=', lhs, rhs)) {
+ TRACE("parsed static labels");
+
+ // <label_name>=<label_value> stands for constant label
+ Labels_.push_back(::MakeIntrusive<TFixedLabel>(TLabel{lhs, rhs}));
+ } else {
+ ythrow yexception() << "Incorrect Keys format";
+ }
+ }
+ }
+
+ void AppendPath(TStringBuf fieldName) {
+ Path_ += '/';
+ Path_ += fieldName;
+ }
+
+ const TString& Path() const {
+ return Path_;
+ }
+
+ TLabels Labels() const {
+ TLabels result;
+ for (auto&& l : Labels_) {
+ result.Add(l->Get(Message()));
+ }
+
+ return result;
+ }
+
+ const NProtoBuf::Message& Message() const {
+ Y_VERIFY_DEBUG(Message_);
+ return *Message_;
+ }
+
+ const NProtoBuf::Reflection& Reflection() const {
+ return *Reflection_;
+ }
+
+ private:
+ const NProtoBuf::Message* Message_{nullptr};
+ const NProtoBuf::Reflection* Reflection_{nullptr};
+
+ TString Path_;
+ TVector<TIntrusivePtr<ILabelGetter>> Labels_;
+ };
+
+ class TDecoder {
+ public:
+ TDecoder(IMetricConsumer* consumer, const NProtoBuf::Message& message, TInstant timestamp)
+ : Consumer_{consumer}
+ , Message_{message}
+ , Timestamp_{timestamp}
+ {
+ }
+
+ void Decode() const {
+ Consumer_->OnStreamBegin();
+ DecodeToStream();
+ Consumer_->OnStreamEnd();
+ }
+
+ void DecodeToStream() const {
+ DecodeImpl(Message_, {});
+ }
+
+ private:
+ static const NMonProto::TExtraLabelMetrics& ExtractExtraMetrics(TDecoderContext& ctx, const NProtoBuf::FieldDescriptor& f) {
+ const auto& parent = ctx.Message();
+ const auto& reflection = ctx.Reflection();
+ auto& subMessage = reflection.GetMessage(parent, &f);
+
+ return dynamic_cast<const NMonProto::TExtraLabelMetrics&>(subMessage);
+ }
+
+ void DecodeImpl(const NProtoBuf::Message& msg, TDecoderContext ctx) const {
+ std::vector<const NProtoBuf::FieldDescriptor*> fields;
+
+ ctx.Init(&msg);
+
+ ctx.Reflection().ListFields(msg, &fields);
+
+ for (const auto* f : fields) {
+ Y_ENSURE(f);
+
+ const auto& opts = f->options();
+ const auto isMessage = f->type() == NProtoBuf::FieldDescriptor::TYPE_MESSAGE;
+ const auto isExtraLabelMetrics = isMessage && f->message_type()->full_name() == "NMonProto.TExtraLabelMetrics";
+ const auto maybeMeta = MaybeGetMeta(opts);
+
+ if (!(maybeMeta || isExtraLabelMetrics)) {
+ continue;
+ }
+
+ if (isExtraLabelMetrics) {
+ const auto& extra = ExtractExtraMetrics(ctx, *f);
+ RecurseExtraLabelMetrics(ctx, extra, f->name(), maybeMeta);
+ } else if (isMessage) {
+ RecurseMessage(ctx, *maybeMeta, *f);
+ } else if (f->is_repeated()) {
+ RecurseRepeatedScalar(ctx, *maybeMeta, *f);
+ } else if (maybeMeta->HasType()) {
+ const auto val = ReadFieldAsDouble(msg, f, ctx.Reflection());
+ const bool isRate = maybeMeta->GetType() == NMonProto::EMetricType::RATE;
+ WriteMetric(val, ctx, f->name(), isRate);
+ }
+ }
+ }
+
+ void RecurseRepeatedScalar(TDecoderContext ctx, const NMonProto::TMetricMeta& meta, const NProtoBuf::FieldDescriptor& f) const {
+ auto&& msg = ctx.Message();
+ auto&& reflection = ctx.Reflection();
+ const bool isRate = meta.GetType() == NMonProto::EMetricType::RATE;
+
+ // this is a repeated scalar field, which makes metric only if it's indexing
+ for (auto i = 0; i < reflection.FieldSize(msg, &f); ++i) {
+ auto subCtx = ctx.CreateChildFromRepeatedScalar(meta, i);
+ subCtx.Init(&msg);
+ auto val = ReadRepeatedAsDouble(msg, &f, reflection, i);
+ WriteMetric(val, subCtx, f.name(), isRate);
+ }
+ }
+
+ void RecurseExtraLabelMetrics(TDecoderContext ctx, const NMonProto::TExtraLabelMetrics& msg, const TString& name, const TMaybeMeta& meta) const {
+ auto i = 0;
+ for (const auto& val : msg.Getvalues()) {
+ auto subCtx = ctx.CreateChildFromEls(name, msg, i++, meta);
+ subCtx.Init(&val);
+
+ const bool isRate = val.Hastype()
+ ? val.Gettype() == NMonProto::EMetricType::RATE
+ : meta->GetType() == NMonProto::EMetricType::RATE;
+
+ double metricVal{0};
+ if (isRate) {
+ metricVal = val.GetlongValue();
+ } else {
+ metricVal = val.GetdoubleValue();
+ }
+
+ WriteMetric(metricVal, subCtx, "", isRate);
+
+ for (const auto& child : val.Getchildren()) {
+ RecurseExtraLabelMetrics(subCtx, child, "", meta);
+ }
+ }
+ }
+
+ void RecurseMessage(TDecoderContext ctx, const NMonProto::TMetricMeta& metricMeta, const NProtoBuf::FieldDescriptor& f) const {
+ const auto& msg = ctx.Message();
+ const auto& reflection = ctx.Reflection();
+
+ if (f.is_repeated()) {
+ TRACE("recurse into repeated message " << f.name());
+ for (auto i = 0; i < reflection.FieldSize(msg, &f); ++i) {
+ auto& subMessage = reflection.GetRepeatedMessage(msg, &f, i);
+ DecodeImpl(subMessage, ctx.CreateChildFromMeta(metricMeta, f.name(), i));
+ }
+ } else {
+ TRACE("recurse into message " << f.name());
+ auto& subMessage = reflection.GetMessage(msg, &f);
+ DecodeImpl(subMessage, ctx.CreateChildFromMeta(metricMeta, f.name()));
+ }
+ }
+
+ inline void WriteValue(ui64 value) const {
+ Consumer_->OnUint64(Timestamp_, value);
+ }
+
+ inline void WriteValue(double value) const {
+ Consumer_->OnDouble(Timestamp_, value);
+ }
+
+ void WriteMetric(double value, const TDecoderContext& ctx, const TString& name, bool isRate) const {
+ if (isRate) {
+ Consumer_->OnMetricBegin(EMetricType::RATE);
+ WriteValue(static_cast<ui64>(value));
+ } else {
+ Consumer_->OnMetricBegin(EMetricType::GAUGE);
+ WriteValue(static_cast<double>(value));
+ }
+
+ Consumer_->OnLabelsBegin();
+
+ for (const auto& label : ctx.Labels()) {
+ Consumer_->OnLabel(label.Name(), label.Value());
+ }
+
+ const auto fullPath = name.empty()
+ ? ctx.Path()
+ : ctx.Path() + '/' + name;
+
+ if (fullPath) {
+ Consumer_->OnLabel("path", fullPath);
+ }
+
+ Consumer_->OnLabelsEnd();
+ Consumer_->OnMetricEnd();
+ }
+
+ private:
+ IMetricConsumer* Consumer_{nullptr};
+ const NProtoBuf::Message& Message_;
+ TInstant Timestamp_;
+ };
+
+ }
+
+ void DecodeLegacyProto(const NProtoBuf::Message& data, IMetricConsumer* consumer, TInstant ts) {
+ Y_ENSURE(consumer);
+ TDecoder(consumer, data, ts).Decode();
+ }
+
+ void DecodeLegacyProtoToStream(const NProtoBuf::Message& data, IMetricConsumer* consumer, TInstant ts) {
+ Y_ENSURE(consumer);
+ TDecoder(consumer, data, ts).DecodeToStream();
+ }
+}
diff --git a/library/cpp/monlib/encode/legacy_protobuf/legacy_protobuf.h b/library/cpp/monlib/encode/legacy_protobuf/legacy_protobuf.h
new file mode 100644
index 0000000000..7cf8985d65
--- /dev/null
+++ b/library/cpp/monlib/encode/legacy_protobuf/legacy_protobuf.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <google/protobuf/message.h>
+#include <util/datetime/base.h>
+
+namespace NMonitoring {
+ // Unsupported features of the original format:
+ // - histograms;
+ // - memOnly;
+ // - dropHost/ignorePath
+
+ void DecodeLegacyProto(const NProtoBuf::Message& data, class IMetricConsumer* c, TInstant ts = TInstant::Zero());
+
+ /// Does not open/close consumer stream unlike the above function.
+ void DecodeLegacyProtoToStream(const NProtoBuf::Message& data, class IMetricConsumer* c, TInstant ts = TInstant::Zero());
+}
diff --git a/library/cpp/monlib/encode/legacy_protobuf/legacy_protobuf_ut.cpp b/library/cpp/monlib/encode/legacy_protobuf/legacy_protobuf_ut.cpp
new file mode 100644
index 0000000000..53683cb39c
--- /dev/null
+++ b/library/cpp/monlib/encode/legacy_protobuf/legacy_protobuf_ut.cpp
@@ -0,0 +1,422 @@
+#include "legacy_protobuf.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/monlib/encode/legacy_protobuf/ut/test_cases.pb.h>
+#include <library/cpp/monlib/encode/legacy_protobuf/protos/metric_meta.pb.h>
+
+#include <library/cpp/monlib/encode/protobuf/protobuf.h>
+#include <library/cpp/monlib/encode/text/text.h>
+#include <library/cpp/monlib/metrics/labels.h>
+
+#include <util/generic/algorithm.h>
+#include <util/generic/hash_set.h>
+
+using namespace NMonitoring;
+
+TSimple MakeSimpleMessage() {
+ TSimple msg;
+
+ msg.SetFoo(1);
+ msg.SetBar(2.);
+ msg.SetBaz(42.);
+
+ return msg;
+}
+
+IMetricEncoderPtr debugPrinter = EncoderText(&Cerr);
+
+namespace NMonitoring {
+ inline bool operator<(const TLabel& lhs, const TLabel& rhs) {
+ return lhs.Name() < rhs.Name() ||
+ (lhs.Name() == rhs.Name() && lhs.Value() < rhs.Value());
+ }
+
+}
+
+void SetLabelValue(NMonProto::TExtraLabelMetrics::TValue& val, TString s) {
+ val.SetlabelValue(s);
+}
+
+void SetLabelValue(NMonProto::TExtraLabelMetrics::TValue& val, ui64 u) {
+ val.SetlabelValueUint(u);
+}
+
+template <typename T, typename V>
+NMonProto::TExtraLabelMetrics MakeExtra(TString labelName, V labelValue, T value, bool isDeriv) {
+ NMonProto::TExtraLabelMetrics metric;
+ auto* val = metric.Addvalues();
+
+ metric.SetlabelName(labelName);
+ SetLabelValue(*val, labelValue);
+
+ if (isDeriv) {
+ val->SetlongValue(value);
+ } else {
+ val->SetdoubleValue(value);
+ }
+
+ return metric;
+}
+
+void AssertLabels(const TLabels& expected, const NProto::TMultiSample& actual) {
+ UNIT_ASSERT_EQUAL(actual.LabelsSize(), expected.Size());
+
+ TSet<TLabel> actualSet;
+ TSet<TLabel> expectedSet;
+ Transform(expected.begin(), expected.end(), std::inserter(expectedSet, expectedSet.end()), [] (auto&& l) {
+ return TLabel{l.Name(), l.Value()};
+ });
+
+ const auto& l = actual.GetLabels();
+ Transform(std::begin(l), std::end(l), std::inserter(actualSet, std::begin(actualSet)),
+ [](auto&& elem) -> TLabel {
+ return {elem.GetName(), elem.GetValue()};
+ });
+
+ TVector<TLabel> diff;
+ SetSymmetricDifference(std::begin(expectedSet), std::end(expectedSet),
+ std::begin(actualSet), std::end(actualSet), std::back_inserter(diff));
+
+ if (diff.size() > 0) {
+ for (auto&& l : diff) {
+ Cerr << l << Endl;
+ }
+
+ UNIT_FAIL("Labels don't match");
+ }
+}
+
+void AssertSimpleMessage(const NProto::TMultiSamplesList& samples, TString pathPrefix = "/") {
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 3);
+
+ THashSet<TString> expectedValues{pathPrefix + "Foo", pathPrefix + "Bar", pathPrefix + "Baz"};
+
+ for (const auto& s : samples.GetSamples()) {
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 1);
+ UNIT_ASSERT_EQUAL(s.PointsSize(), 1);
+
+ const auto labelVal = s.GetLabels(0).GetValue();
+ UNIT_ASSERT(expectedValues.contains(labelVal));
+
+ if (labelVal == pathPrefix + "Foo") {
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_DOUBLES_EQUAL(s.GetPoints(0).GetFloat64(), 1, 1e-6);
+ } else if (labelVal == pathPrefix + "Bar") {
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_DOUBLES_EQUAL(s.GetPoints(0).GetFloat64(), 2, 1e-6);
+ } else if (labelVal == pathPrefix + "Baz") {
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::RATE);
+ UNIT_ASSERT_EQUAL(s.GetPoints(0).GetUint64(), 42);
+ }
+ }
+}
+
+Y_UNIT_TEST_SUITE(TLegacyProtoDecoderTest) {
+ Y_UNIT_TEST(SimpleProto) {
+ NProto::TMultiSamplesList samples;
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ auto msg = MakeSimpleMessage();
+ DecodeLegacyProto(msg, e.Get());
+
+ AssertSimpleMessage(samples);
+ };
+
+ Y_UNIT_TEST(RepeatedProto) {
+ NProto::TMultiSamplesList samples;
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ auto simple = MakeSimpleMessage();
+ TRepeated msg;
+ msg.AddMessages()->CopyFrom(simple);
+
+ DecodeLegacyProto(msg, e.Get());
+
+ AssertSimpleMessage(samples);
+ }
+
+ Y_UNIT_TEST(RepeatedProtoWithPath) {
+ NProto::TMultiSamplesList samples;
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ auto simple = MakeSimpleMessage();
+ TRepeatedWithPath msg;
+ msg.AddNamespace()->CopyFrom(simple);
+
+ DecodeLegacyProto(msg, e.Get());
+
+ AssertSimpleMessage(samples, "/Namespace/");
+ }
+
+ Y_UNIT_TEST(DeepNesting) {
+ NProto::TMultiSamplesList samples;
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ auto simple = MakeSimpleMessage();
+ TRepeatedWithPath internal;
+ internal.AddNamespace()->CopyFrom(simple);
+
+ TDeepNesting msg;
+ msg.MutableNested()->CopyFrom(internal);
+
+ DecodeLegacyProto(msg, e.Get());
+
+ AssertSimpleMessage(samples, "/Namespace/");
+ }
+
+ Y_UNIT_TEST(Keys) {
+ NProto::TMultiSamplesList samples;
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ auto simple = MakeSimpleMessage();
+ simple.SetLabel("my_label_value");
+
+ TNestedWithKeys msg;
+ msg.AddNamespace()->CopyFrom(simple);
+
+ DecodeLegacyProto(msg, e.Get());
+
+ auto i = 0;
+ for (const auto& s : samples.GetSamples()) {
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 4);
+
+ bool foundLabel = false;
+ bool foundFixed = false;
+ bool foundNumbered = false;
+
+ for (const auto& label : s.GetLabels()) {
+ if (label.GetName() == "my_label") {
+ foundLabel = true;
+ UNIT_ASSERT_STRINGS_EQUAL(label.GetValue(), "my_label_value");
+ } else if (label.GetName() == "fixed_label") {
+ foundFixed = true;
+ UNIT_ASSERT_STRINGS_EQUAL(label.GetValue(), "fixed_value");
+ } else if (label.GetName() == "numbered") {
+ foundNumbered = true;
+ UNIT_ASSERT_STRINGS_EQUAL(label.GetValue(), ::ToString(i));
+ }
+ }
+
+ UNIT_ASSERT(foundLabel);
+ UNIT_ASSERT(foundFixed);
+ UNIT_ASSERT(foundNumbered);
+ }
+ }
+
+ Y_UNIT_TEST(NonStringKeys) {
+ NProto::TMultiSamplesList samples;
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TNonStringKeys msg;
+ msg.SetFoo(42);
+ msg.SetEnum(ENUM);
+ msg.SetInt(43);
+
+ TRepeatedNonStringKeys msgs;
+ msgs.AddNested()->CopyFrom(msg);
+
+ DecodeLegacyProto(msgs, e.Get());
+
+ for (const auto& s : samples.GetSamples()) {
+ bool foundEnum = false;
+ bool foundInt = false;
+
+ for (const auto& label : s.GetLabels()) {
+ if (label.GetName() == "enum") {
+ foundEnum = true;
+ UNIT_ASSERT_STRINGS_EQUAL(label.GetValue(), "ENUM");
+ } else if (label.GetName() == "int") {
+ foundInt = true;
+ UNIT_ASSERT_STRINGS_EQUAL(label.GetValue(), "43");
+ }
+ }
+
+ UNIT_ASSERT(foundEnum);
+ UNIT_ASSERT(foundInt);
+
+ UNIT_ASSERT_DOUBLES_EQUAL(s.GetPoints(0).GetFloat64(), 42, 1e-6);
+ }
+ }
+
+ Y_UNIT_TEST(KeysFromNonLeafNodes) {
+ NProto::TMultiSamplesList samples;
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ auto simple = MakeSimpleMessage();
+ simple.SetLabel("label_value");
+
+ TRepeatedWithName nested;
+ nested.SetName("my_name");
+ nested.AddNested()->CopyFrom(simple);
+
+ TKeysFromNonLeaf msg;
+ msg.AddNested()->CopyFrom(nested);
+
+ DecodeLegacyProto(msg, e.Get());
+
+ AssertLabels({{"my_label", "label_value"}, {"path", "/Nested/Nested/Foo"}, {"name", "my_name"}}, samples.GetSamples(0));
+ }
+
+ Y_UNIT_TEST(SpacesAreGetReplaced) {
+ NProto::TMultiSamplesList samples;
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ auto simple = MakeSimpleMessage();
+ simple.SetLabel("my label_value");
+
+ TNestedWithKeys msg;
+ msg.AddNamespace()->CopyFrom(simple);
+
+ DecodeLegacyProto(msg, e.Get());
+
+ for (const auto& s : samples.GetSamples()) {
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 4);
+
+ bool foundLabel = false;
+
+ for (const auto& label : s.GetLabels()) {
+ if (label.GetName() == "my_label") {
+ foundLabel = true;
+ UNIT_ASSERT_STRINGS_EQUAL(label.GetValue(), "my_label_value");
+ }
+ }
+
+ UNIT_ASSERT(foundLabel);
+ }
+ }
+
+ Y_UNIT_TEST(ExtraLabels) {
+ NProto::TMultiSamplesList samples;
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TExtraLabels msg;
+ msg.MutableExtraAsIs()->CopyFrom(MakeExtra("label", "foo", 42, false));
+ msg.MutableExtraDeriv()->CopyFrom(MakeExtra("deriv_label", "deriv_foo", 43, true));
+
+ DecodeLegacyProto(msg, e.Get());
+
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 2);
+ {
+ auto s = samples.GetSamples(0);
+ AssertLabels({{"label", "foo"}, {"path", "/ExtraAsIs"}}, s);
+
+ UNIT_ASSERT_EQUAL(s.PointsSize(), 1);
+ auto point = s.GetPoints(0);
+ UNIT_ASSERT_DOUBLES_EQUAL(point.GetFloat64(), 42, 1e-6);
+ }
+
+ {
+ auto s = samples.GetSamples(1);
+ AssertLabels({{"deriv_label", "deriv_foo"}, {"path", "/ExtraDeriv"}}, s);
+
+ UNIT_ASSERT_EQUAL(s.PointsSize(), 1);
+ auto point = s.GetPoints(0);
+ UNIT_ASSERT_EQUAL(point.GetUint64(), 43);
+ }
+ }
+
+ Y_UNIT_TEST(NestedExtraLabels) {
+ NProto::TMultiSamplesList samples;
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TExtraLabels msg;
+ auto extra = MakeExtra("label", "foo", 42, false);
+ auto* val = extra.Mutablevalues(0);
+ {
+ auto child = MakeExtra("child1", "label1", 24, true);
+ child.Mutablevalues(0)->Settype(NMonProto::EMetricType::RATE);
+ val->Addchildren()->CopyFrom(child);
+ }
+
+ {
+ auto child = MakeExtra("child2", 34, 23, false);
+ val->Addchildren()->CopyFrom(child);
+ }
+ msg.MutableExtraAsIs()->CopyFrom(extra);
+
+ DecodeLegacyProto(msg, e.Get());
+
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 3);
+ {
+ auto s = samples.GetSamples(0);
+ AssertLabels({{"label", "foo"}, {"path", "/ExtraAsIs"}}, s);
+
+ UNIT_ASSERT_EQUAL(s.PointsSize(), 1);
+ auto point = s.GetPoints(0);
+ UNIT_ASSERT_DOUBLES_EQUAL(point.GetFloat64(), 42, 1e-6);
+ }
+
+ {
+ auto s = samples.GetSamples(1);
+ AssertLabels({{"label", "foo"}, {"child1", "label1"}, {"path", "/ExtraAsIs"}}, s);
+
+ UNIT_ASSERT_EQUAL(s.PointsSize(), 1);
+ auto point = s.GetPoints(0);
+ UNIT_ASSERT_EQUAL(point.GetUint64(), 24);
+ }
+
+ {
+ auto s = samples.GetSamples(2);
+ AssertLabels({{"label", "foo"}, {"child2", "34"}, {"path", "/ExtraAsIs"}}, s);
+
+ UNIT_ASSERT_EQUAL(s.PointsSize(), 1);
+ auto point = s.GetPoints(0);
+ UNIT_ASSERT_EQUAL(point.GetFloat64(), 23);
+ }
+ }
+
+ Y_UNIT_TEST(RobotLabels) {
+ NProto::TMultiSamplesList samples;
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TNamedCounter responses;
+ responses.SetName("responses");
+ responses.SetCount(42);
+
+ TCrawlerCounters::TStatusCounters statusCounters;
+ statusCounters.AddZoraResponses()->CopyFrom(responses);
+
+ TCrawlerCounters::TPolicyCounters policyCounters;
+ policyCounters.SetSubComponent("mySubComponent");
+ policyCounters.SetName("myComponentName");
+ policyCounters.SetZone("myComponentZone");
+ policyCounters.MutableStatusCounters()->CopyFrom(statusCounters);
+
+ TCrawlerCounters counters;
+ counters.SetComponent("myComponent");
+ counters.AddPoliciesCounters()->CopyFrom(policyCounters);
+
+ DecodeLegacyProto(counters, e.Get());
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 1);
+ auto s = samples.GetSamples(0);
+ AssertLabels({
+ {"SubComponent", "mySubComponent"}, {"Policy", "myComponentName"}, {"Zone", "myComponentZone"},
+ {"ZoraResponse", "responses"}, {"path", "/PoliciesCounters/StatusCounters/ZoraResponses/Count"}}, s);
+ }
+
+ Y_UNIT_TEST(ZoraLabels) {
+ NProto::TMultiSamplesList samples;
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TTimeLogHist hist;
+ hist.AddBuckets(42);
+ hist.AddBuckets(0);
+
+ TKiwiCounters counters;
+ counters.MutableTimes()->CopyFrom(hist);
+
+ DecodeLegacyProto(counters, e.Get());
+
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 2);
+
+ auto s = samples.GetSamples(0);
+ AssertLabels({{"slot", "0"}, {"path", "/Times/Buckets"}}, s);
+ UNIT_ASSERT_EQUAL(s.PointsSize(), 1);
+ UNIT_ASSERT_EQUAL(s.GetPoints(0).GetUint64(), 42);
+
+ s = samples.GetSamples(1);
+ AssertLabels({{"slot", "1"}, {"path", "/Times/Buckets"}}, s);
+ UNIT_ASSERT_EQUAL(s.GetPoints(0).GetUint64(), 0);
+ }
+}
diff --git a/library/cpp/monlib/encode/legacy_protobuf/protos/metric_meta.proto b/library/cpp/monlib/encode/legacy_protobuf/protos/metric_meta.proto
new file mode 100644
index 0000000000..fd23eb372b
--- /dev/null
+++ b/library/cpp/monlib/encode/legacy_protobuf/protos/metric_meta.proto
@@ -0,0 +1,73 @@
+import "google/protobuf/descriptor.proto";
+
+package NMonProto;
+
+option java_package = "ru.yandex.monlib.proto";
+option java_outer_classname = "MetricMetaProto";
+
+enum EMetricType {
+ GAUGE = 1;
+ RATE = 2;
+}
+
+enum EMemOnly {
+ DEFAULT = 0;
+ STORE = 1;
+ MEM_ONLY = 2;
+}
+
+message TMetricMeta {
+ optional EMetricType Type = 1;
+ optional bool Path = 2;
+ optional string Keys = 3;
+ optional bool MemOnly = 4;
+ optional bool IgnorePath = 5;
+ optional string CustomPath = 6;
+}
+
+enum THistogramBase {
+ MICROSECOND = 3;
+ MILLISECOND = 6;
+ SECOND = 9;
+ MINUTE = 12;
+ HOUR = 15;
+}
+
+message THistogramEntry {
+ optional uint64 Multiplier = 1;
+ optional double Value = 2;
+}
+
+message THistogram {
+ optional THistogramBase Base = 1;
+ optional string BaseStr = 2;
+ repeated THistogramEntry Entries = 5;
+}
+
+// field of this type is recognized by Solomon
+message TExtraLabelMetrics {
+ optional string labelName = 1;
+
+ message TValue {
+ optional string labelValue = 1;
+ // used only if != 0
+ optional uint64 labelValueUint = 21;
+
+ optional uint64 longValue = 2;
+ optional double doubleValue = 3;
+ optional THistogram histogramValue = 4;
+
+ optional EMetricType type = 7;
+ optional EMemOnly memOnly = 8;
+ optional bool dropHost = 9;
+
+ repeated TExtraLabelMetrics children = 17;
+ }
+
+ repeated TValue values = 2;
+}
+
+extend google.protobuf.FieldOptions {
+ optional TMetricMeta Metric = 1719;
+}
+
diff --git a/library/cpp/monlib/encode/legacy_protobuf/protos/python/ya.make b/library/cpp/monlib/encode/legacy_protobuf/protos/python/ya.make
new file mode 100644
index 0000000000..095b307b01
--- /dev/null
+++ b/library/cpp/monlib/encode/legacy_protobuf/protos/python/ya.make
@@ -0,0 +1,3 @@
+OWNER(g:solomon)
+
+PY_PROTOS_FOR(library/cpp/monlib/encode/legacy_protobuf/protos)
diff --git a/library/cpp/monlib/encode/legacy_protobuf/protos/ya.make b/library/cpp/monlib/encode/legacy_protobuf/protos/ya.make
new file mode 100644
index 0000000000..489f361ab1
--- /dev/null
+++ b/library/cpp/monlib/encode/legacy_protobuf/protos/ya.make
@@ -0,0 +1,13 @@
+PROTO_LIBRARY()
+
+OWNER(g:solomon)
+
+SRCS(
+ metric_meta.proto
+)
+
+IF (NOT PY_PROTOS_FOR)
+ EXCLUDE_TAGS(GO_PROTO)
+ENDIF()
+
+END()
diff --git a/library/cpp/monlib/encode/legacy_protobuf/ut/test_cases.proto b/library/cpp/monlib/encode/legacy_protobuf/ut/test_cases.proto
new file mode 100644
index 0000000000..37e901de48
--- /dev/null
+++ b/library/cpp/monlib/encode/legacy_protobuf/ut/test_cases.proto
@@ -0,0 +1,90 @@
+import "library/cpp/monlib/encode/legacy_protobuf/protos/metric_meta.proto";
+
+message TSimple {
+ optional uint64 Foo = 1 [ (NMonProto.Metric).Type = GAUGE ];
+ optional double Bar = 2 [ (NMonProto.Metric).Type = GAUGE ];
+ optional double Baz = 3 [ (NMonProto.Metric).Type = RATE ];
+ optional string Label = 4;
+}
+
+message TRepeated {
+ repeated TSimple Messages = 1 [ (NMonProto.Metric).Path = false ];
+};
+
+message TRepeatedWithPath {
+ repeated TSimple Namespace = 1 [ (NMonProto.Metric).Path = true ];
+};
+
+message TNestedWithKeys {
+ repeated TSimple Namespace = 1 [ (NMonProto.Metric).Path = true, (NMonProto.Metric).Keys = "my_label:Label fixed_label=fixed_value numbered:#" ];
+};
+
+message TDeepNesting {
+ optional TRepeatedWithPath Nested = 1 [ (NMonProto.Metric).Path = false ];
+};
+
+enum EEnum {
+ MY = 1;
+ ENUM = 2;
+};
+
+message TNonStringKeys {
+ optional uint32 Foo = 1 [ (NMonProto.Metric).Type = GAUGE ];
+ optional EEnum Enum = 2;
+ optional uint32 Int = 3;
+};
+
+message TRepeatedNonStringKeys {
+ repeated TNonStringKeys Nested = 1 [ (NMonProto.Metric).Path = true, (NMonProto.Metric).Keys = "enum:Enum int:Int" ];
+};
+
+message TExtraLabels {
+ optional NMonProto.TExtraLabelMetrics ExtraAsIs = 1 [ (NMonProto.Metric).Type = GAUGE ];
+ optional NMonProto.TExtraLabelMetrics ExtraDeriv = 2 [ (NMonProto.Metric).Type = RATE ];
+};
+
+message TRepeatedWithName {
+ optional string Name = 1;
+ repeated TSimple Nested = 2 [ (NMonProto.Metric).Path = true, (NMonProto.Metric).Keys = "my_label:Label" ];
+};
+
+message TKeysFromNonLeaf {
+ repeated TRepeatedWithName Nested = 1 [ (NMonProto.Metric).Path = true, (NMonProto.Metric).Keys = "name:Name" ];
+};
+
+
+message TNamedCounter {
+ optional string Name = 1;
+ optional uint64 Count = 2 [ (NMonProto.Metric).Type = RATE ];
+}
+
+message TCrawlerCounters {
+ message TStatusCounters {
+ repeated TNamedCounter ZoraResponses = 3 [ (NMonProto.Metric).Path = true, (NMonProto.Metric).Keys = "ZoraResponse:Name" ];
+ repeated TNamedCounter FetcherResponses = 4 [ (NMonProto.Metric).Path = true, (NMonProto.Metric).Keys = "SpiderResponse:Name" ];
+ repeated TNamedCounter RotorResponses = 5 [ (NMonProto.Metric).Path = true, (NMonProto.Metric).Keys = "SpiderResponse:Name" ];
+ repeated TNamedCounter PDFetchResponses = 6 [ (NMonProto.Metric).Path = true, (NMonProto.Metric).Keys = "PDFetchResponse:Name" ];
+ repeated TNamedCounter CalcResponses = 7 [ (NMonProto.Metric).Path = true, (NMonProto.Metric).Keys = "CalcResponse:Name" ];
+ repeated TNamedCounter Responses = 8 [ (NMonProto.Metric).Path = true, (NMonProto.Metric).Keys = "AggregatedResponse:Name" ];
+ }
+
+ message TPolicyCounters {
+ optional string SubComponent = 1;
+ optional string Name = 2;
+ optional string Zone = 3;
+
+ optional TStatusCounters StatusCounters = 4 [ (NMonProto.Metric).Path = true ];
+ }
+
+ optional string Component = 1;
+ repeated TPolicyCounters PoliciesCounters = 3 [ (NMonProto.Metric).Path = true, (NMonProto.Metric).Keys = "SubComponent:SubComponent Policy:Name Zone:Zone" ];
+}
+
+message TTimeLogHist {
+ optional uint32 MinBucketMillisec = 1;
+ repeated uint64 Buckets = 2 [ (NMonProto.Metric).Type = RATE, (NMonProto.Metric).Keys = "slot:#" ];
+}
+
+message TKiwiCounters {
+ optional TTimeLogHist Times = 22 [ (NMonProto.Metric).Path = true ];
+}
diff --git a/library/cpp/monlib/encode/legacy_protobuf/ut/ya.make b/library/cpp/monlib/encode/legacy_protobuf/ut/ya.make
new file mode 100644
index 0000000000..479a0c46c9
--- /dev/null
+++ b/library/cpp/monlib/encode/legacy_protobuf/ut/ya.make
@@ -0,0 +1,18 @@
+UNITTEST_FOR(library/cpp/monlib/encode/legacy_protobuf)
+
+OWNER(
+ g:solomon
+ msherbakov
+)
+
+SRCS(
+ legacy_protobuf_ut.cpp
+ test_cases.proto
+)
+
+PEERDIR(
+ library/cpp/monlib/encode/protobuf
+ library/cpp/monlib/encode/text
+)
+
+END()
diff --git a/library/cpp/monlib/encode/legacy_protobuf/ya.make b/library/cpp/monlib/encode/legacy_protobuf/ya.make
new file mode 100644
index 0000000000..74c82aac93
--- /dev/null
+++ b/library/cpp/monlib/encode/legacy_protobuf/ya.make
@@ -0,0 +1,16 @@
+LIBRARY()
+
+OWNER(
+ g:solomon
+ msherbakov
+)
+
+SRCS(
+ legacy_proto_decoder.cpp
+)
+
+PEERDIR(
+ library/cpp/monlib/encode/legacy_protobuf/protos
+)
+
+END()
diff --git a/library/cpp/monlib/encode/prometheus/fuzz/main.cpp b/library/cpp/monlib/encode/prometheus/fuzz/main.cpp
new file mode 100644
index 0000000000..24bda2d32e
--- /dev/null
+++ b/library/cpp/monlib/encode/prometheus/fuzz/main.cpp
@@ -0,0 +1,18 @@
+#include <library/cpp/monlib/encode/prometheus/prometheus.h>
+#include <library/cpp/monlib/encode/fake/fake.h>
+
+#include <util/stream/mem.h>
+
+
+extern "C" int LLVMFuzzerTestOneInput(const ui8* buf, size_t size) {
+ using namespace NMonitoring;
+
+ try {
+ TStringBuf data(reinterpret_cast<const char*>(buf), size);
+ auto encoder = EncoderFake();
+ DecodePrometheus(data, encoder.Get());
+ } catch (...) {
+ }
+
+ return 0;
+}
diff --git a/library/cpp/monlib/encode/prometheus/fuzz/ya.make b/library/cpp/monlib/encode/prometheus/fuzz/ya.make
new file mode 100644
index 0000000000..4a6c796ed5
--- /dev/null
+++ b/library/cpp/monlib/encode/prometheus/fuzz/ya.make
@@ -0,0 +1,16 @@
+FUZZ()
+
+OWNER(g:solomon jamel)
+
+PEERDIR(
+ library/cpp/monlib/encode/prometheus
+ library/cpp/monlib/encode/fake
+)
+
+SIZE(MEDIUM)
+
+SRCS(
+ main.cpp
+)
+
+END()
diff --git a/library/cpp/monlib/encode/prometheus/prometheus.h b/library/cpp/monlib/encode/prometheus/prometheus.h
new file mode 100644
index 0000000000..2e7fa31c28
--- /dev/null
+++ b/library/cpp/monlib/encode/prometheus/prometheus.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <library/cpp/monlib/encode/encoder.h>
+#include <library/cpp/monlib/encode/format.h>
+
+#include <util/generic/yexception.h>
+
+
+namespace NMonitoring {
+
+ class TPrometheusDecodeException: public yexception {
+ };
+
+ IMetricEncoderPtr EncoderPrometheus(IOutputStream* out, TStringBuf metricNameLabel = "sensor");
+
+ void DecodePrometheus(TStringBuf data, IMetricConsumer* c, TStringBuf metricNameLabel = "sensor");
+
+}
diff --git a/library/cpp/monlib/encode/prometheus/prometheus_decoder.cpp b/library/cpp/monlib/encode/prometheus/prometheus_decoder.cpp
new file mode 100644
index 0000000000..7e81357dbd
--- /dev/null
+++ b/library/cpp/monlib/encode/prometheus/prometheus_decoder.cpp
@@ -0,0 +1,597 @@
+#include "prometheus.h"
+#include "prometheus_model.h"
+
+#include <library/cpp/monlib/metrics/histogram_snapshot.h>
+#include <library/cpp/monlib/metrics/metric.h>
+
+#include <util/datetime/base.h>
+#include <util/generic/hash.h>
+#include <util/string/cast.h>
+#include <util/string/builder.h>
+#include <util/generic/maybe.h>
+#include <util/string/ascii.h>
+
+#include <cmath>
+
+#define Y_PARSER_FAIL(message) \
+ ythrow ::NMonitoring::TPrometheusDecodeException() << message << " at line #" << CurrentLine_
+
+#define Y_PARSER_ENSURE(cond, message) \
+ Y_ENSURE_EX(cond, ::NMonitoring::TPrometheusDecodeException() << message << " at line #" << CurrentLine_)
+
+
+namespace NMonitoring {
+ namespace {
+ constexpr ui32 MAX_LABEL_VALUE_LEN = 256;
+
+ using TLabelsMap = THashMap<TString, TString>;
+
+ TString LabelsToStr(const TLabelsMap& labels) {
+ TStringBuilder sb;
+ auto it = labels.begin();
+ auto end = labels.end();
+
+ sb << '{';
+ while (it != end) {
+ sb << it->first;
+ sb << '=';
+ sb << '"' << it->second << '"';
+
+ ++it;
+ if (it != end) {
+ sb << ", ";
+ }
+ }
+ sb << '}';
+ return sb;
+ }
+
+ template <typename T, typename U>
+ bool TryStaticCast(U val, T& out) {
+ static_assert(std::is_arithmetic_v<U>);
+ if constexpr (std::is_floating_point_v<T> || std::is_floating_point_v<U>) {
+ if (val > MaxFloor<T>() || val < -MaxFloor<T>()) {
+ return false;
+ }
+
+ } else {
+ if (val > Max<T>() || val < Min<T>()) {
+ return false;
+ }
+ }
+
+ out = static_cast<T>(val);
+ return true;
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // THistogramBuilder
+ ///////////////////////////////////////////////////////////////////////
+ class THistogramBuilder {
+ using TBucketData = std::pair<TBucketBound, TBucketValue>;
+ constexpr static TBucketData ZERO_BUCKET = { -std::numeric_limits<TBucketBound>::max(), 0 };
+ public:
+ TStringBuf GetName() const noexcept {
+ return Name_;
+ }
+
+ void SetName(TStringBuf name) noexcept {
+ Name_ = name;
+ }
+
+ const TLabelsMap& GetLabels() const noexcept {
+ return *Labels_;
+ }
+
+ void SetLabels(TLabelsMap&& labels) {
+ if (Labels_.Defined()) {
+ Y_ENSURE(Labels_ == labels,
+ "mixed labels in one histogram, prev: " << LabelsToStr(*Labels_) <<
+ ", current: " << LabelsToStr(labels));
+ } else {
+ Labels_.ConstructInPlace(std::move(labels));
+ }
+ }
+
+ TInstant GetTime() const noexcept {
+ return Time_;
+ }
+
+ void SetTime(TInstant time) noexcept {
+ Time_ = time;
+ }
+
+ bool Empty() const noexcept {
+ return Bounds_.empty();
+ }
+
+ bool Same(TStringBuf name, const TLabelsMap& labels) const noexcept {
+ return Name_ == name && Labels_ == labels;
+ }
+
+ void AddBucket(TBucketBound bound, TBucketValue value) {
+ Y_ENSURE_EX(PrevBucket_.first < bound, TPrometheusDecodeException() <<
+ "invalid order of histogram bounds " << PrevBucket_.first <<
+ " >= " << bound);
+
+ Y_ENSURE_EX(PrevBucket_.second <= value, TPrometheusDecodeException() <<
+ "invalid order of histogram bucket values " << PrevBucket_.second <<
+ " > " << value);
+
+ // convert infinite bound value
+ if (bound == std::numeric_limits<TBucketBound>::infinity()) {
+ bound = HISTOGRAM_INF_BOUND;
+ }
+
+ Bounds_.push_back(bound);
+ Values_.push_back(value - PrevBucket_.second); // keep only delta between buckets
+
+ PrevBucket_ = { bound, value };
+ }
+
+ // will clear builder state
+ IHistogramSnapshotPtr ToSnapshot() {
+ Y_ENSURE_EX(!Empty(), TPrometheusDecodeException() << "histogram cannot be empty");
+ Time_ = TInstant::Zero();
+ PrevBucket_ = ZERO_BUCKET;
+ Labels_.Clear();
+ auto snapshot = ExplicitHistogramSnapshot(Bounds_, Values_);
+
+ Bounds_.clear();
+ Values_.clear();
+
+ return snapshot;
+ }
+
+ private:
+ TStringBuf Name_;
+ TMaybe<TLabelsMap> Labels_;
+ TInstant Time_;
+ TBucketBounds Bounds_;
+ TBucketValues Values_;
+ TBucketData PrevBucket_ = ZERO_BUCKET;
+ };
+
+ ///////////////////////////////////////////////////////////////////////
+ // EPrometheusMetricType
+ ///////////////////////////////////////////////////////////////////////
+ enum class EPrometheusMetricType {
+ GAUGE,
+ COUNTER,
+ SUMMARY,
+ UNTYPED,
+ HISTOGRAM,
+ };
+
+ ///////////////////////////////////////////////////////////////////////
+ // TPrometheusReader
+ ///////////////////////////////////////////////////////////////////////
+ class TPrometheusReader {
+ public:
+ TPrometheusReader(TStringBuf data, IMetricConsumer* c, TStringBuf metricNameLabel)
+ : Data_(data)
+ , Consumer_(c)
+ , MetricNameLabel_(metricNameLabel)
+ {
+ }
+
+ void Read() {
+ Consumer_->OnStreamBegin();
+
+ if (HasRemaining()) {
+ ReadNextByte();
+ SkipSpaces();
+
+ try {
+ while (HasRemaining()) {
+ switch (CurrentByte_) {
+ case '\n':
+ ReadNextByte(); // skip '\n'
+ CurrentLine_++;
+ SkipSpaces();
+ break;
+ case '#':
+ ParseComment();
+ break;
+ default:
+ ParseMetric();
+ break;
+ }
+ }
+
+ if (!HistogramBuilder_.Empty()) {
+ ConsumeHistogram();
+ }
+ } catch (const TPrometheusDecodeException& e) {
+ throw e;
+ } catch (...) {
+ Y_PARSER_FAIL("unexpected error " << CurrentExceptionMessage());
+ }
+ }
+
+ Consumer_->OnStreamEnd();
+ }
+
+ private:
+ bool HasRemaining() const noexcept {
+ return CurrentPos_ < Data_.Size();
+ }
+
+ // # 'TYPE' metric_name {counter|gauge|histogram|summary|untyped}
+ // # 'HELP' metric_name some help info
+ // # general comment message
+ void ParseComment() {
+ SkipExpectedChar('#');
+ SkipSpaces();
+
+ TStringBuf keyword = ReadToken();
+ if (keyword == TStringBuf("TYPE")) {
+ SkipSpaces();
+
+ TStringBuf nextName = ReadTokenAsMetricName();
+ Y_PARSER_ENSURE(!nextName.Empty(), "invalid metric name");
+
+ SkipSpaces();
+ EPrometheusMetricType nextType = ReadType();
+
+ bool inserted = SeenTypes_.emplace(nextName, nextType).second;
+ Y_PARSER_ENSURE(inserted, "second TYPE line for metric " << nextName);
+
+ if (nextType == EPrometheusMetricType::HISTOGRAM) {
+ if (!HistogramBuilder_.Empty()) {
+ ConsumeHistogram();
+ }
+ HistogramBuilder_.SetName(nextName);
+ }
+ } else {
+ // skip HELP and general comments
+ SkipUntilEol();
+ }
+
+ Y_PARSER_ENSURE(CurrentByte_ == '\n', "expected '\\n', found '" << CurrentByte_ << '\'');
+ }
+
+ // metric_name [labels] value [timestamp]
+ void ParseMetric() {
+ TStringBuf name = ReadTokenAsMetricName();
+ SkipSpaces();
+
+ TLabelsMap labels = ReadLabels();
+ SkipSpaces();
+
+ double value = ParseGoDouble(ReadToken());
+ SkipSpaces();
+
+ TInstant time = TInstant::Zero();
+ if (CurrentByte_ != '\n') {
+ time = TInstant::MilliSeconds(FromString<ui64>(ReadToken()));
+ }
+
+ TStringBuf baseName = name;
+ EPrometheusMetricType type = EPrometheusMetricType::UNTYPED;
+
+ if (auto* seenType = SeenTypes_.FindPtr(name)) {
+ type = *seenType;
+ } else {
+ baseName = NPrometheus::ToBaseName(name);
+ if (auto* baseType = SeenTypes_.FindPtr(baseName)) {
+ type = *baseType;
+ }
+ }
+
+ switch (type) {
+ case EPrometheusMetricType::HISTOGRAM:
+ if (NPrometheus::IsBucket(name)) {
+ double bound = 0.0;
+ auto it = labels.find(NPrometheus::BUCKET_LABEL);
+ if (it != labels.end()) {
+ bound = ParseGoDouble(it->second);
+ labels.erase(it);
+ } else {
+ Y_PARSER_FAIL(
+ "metric " << name << "has no " << NPrometheus::BUCKET_LABEL <<
+ " label at line #" << CurrentLine_);
+ }
+
+ if (!HistogramBuilder_.Empty() && !HistogramBuilder_.Same(baseName, labels)) {
+ ConsumeHistogram();
+ HistogramBuilder_.SetName(baseName);
+ }
+
+ TBucketValue bucketVal;
+ Y_PARSER_ENSURE(TryStaticCast(value, bucketVal), "Cannot convert " << value << " to bucket value type");
+ HistogramBuilder_.AddBucket(bound, bucketVal);
+ HistogramBuilder_.SetTime(time);
+ HistogramBuilder_.SetLabels(std::move(labels));
+ } else if (NPrometheus::IsCount(name)) {
+ // translate x_count metric as COUNTER metric
+ ConsumeCounter(name, labels, time, value);
+ } else if (NPrometheus::IsSum(name)) {
+ // translate x_sum metric as GAUGE metric
+ ConsumeGauge(name, labels, time, value);
+ } else {
+ Y_PARSER_FAIL(
+ "metric " << name <<
+ " should be part of HISTOGRAM " << baseName);
+ }
+ break;
+
+ case EPrometheusMetricType::SUMMARY:
+ if (NPrometheus::IsCount(name)) {
+ // translate x_count metric as COUNTER metric
+ ConsumeCounter(name, labels, time, value);
+ } else if (NPrometheus::IsSum(name)) {
+ // translate x_sum metric as GAUGE metric
+ ConsumeGauge(name, labels, time, value);
+ } else {
+ ConsumeGauge(name, labels, time, value);
+ }
+ break;
+
+ case EPrometheusMetricType::COUNTER:
+ ConsumeCounter(name, labels, time, value);
+ break;
+
+ case EPrometheusMetricType::GAUGE:
+ ConsumeGauge(name, labels, time, value);
+ break;
+
+ case EPrometheusMetricType::UNTYPED:
+ ConsumeGauge(name, labels, time, value);
+ break;
+ }
+
+ Y_PARSER_ENSURE(CurrentByte_ == '\n', "expected '\\n', found '" << CurrentByte_ << '\'');
+ }
+
+ // { name = "value", name2 = "value2", }
+ TLabelsMap ReadLabels() {
+ TLabelsMap labels;
+ if (CurrentByte_ != '{') {
+ return labels;
+ }
+
+ SkipExpectedChar('{');
+ SkipSpaces();
+
+ while (CurrentByte_ != '}') {
+ TStringBuf name = ReadTokenAsLabelName();
+ SkipSpaces();
+
+ SkipExpectedChar('=');
+ SkipSpaces();
+
+ TString value = ReadTokenAsLabelValue();
+ SkipSpaces();
+ labels.emplace(name, value);
+
+ if (CurrentByte_ == ',') {
+ SkipExpectedChar(',');
+ SkipSpaces();
+ }
+ }
+
+ SkipExpectedChar('}');
+ return labels;
+ }
+
+ EPrometheusMetricType ReadType() {
+ TStringBuf keyword = ReadToken();
+ if (AsciiEqualsIgnoreCase(keyword, "GAUGE")) {
+ return EPrometheusMetricType::GAUGE;
+ } else if (AsciiEqualsIgnoreCase(keyword, "COUNTER")) {
+ return EPrometheusMetricType::COUNTER;
+ } else if (AsciiEqualsIgnoreCase(keyword, "SUMMARY")) {
+ return EPrometheusMetricType::SUMMARY;
+ } else if (AsciiEqualsIgnoreCase(keyword, "HISTOGRAM")) {
+ return EPrometheusMetricType::HISTOGRAM;
+ } else if (AsciiEqualsIgnoreCase(keyword, "UNTYPED")) {
+ return EPrometheusMetricType::UNTYPED;
+ }
+
+ Y_PARSER_FAIL(
+ "unknown metric type: " << keyword <<
+ " at line #" << CurrentLine_);
+ }
+
+ Y_FORCE_INLINE void ReadNextByteUnsafe() {
+ CurrentByte_ = Data_[CurrentPos_++];
+ }
+
+ Y_FORCE_INLINE bool IsSpace(char ch) {
+ return ch == ' ' || ch == '\t';
+ }
+
+ void ReadNextByte() {
+ Y_PARSER_ENSURE(HasRemaining(), "unexpected end of file");
+ ReadNextByteUnsafe();
+ }
+
+ void SkipExpectedChar(char ch) {
+ Y_PARSER_ENSURE(CurrentByte_ == ch,
+ "expected '" << CurrentByte_ << "', found '" << ch << '\'');
+ ReadNextByte();
+ }
+
+ void SkipSpaces() {
+ while (HasRemaining() && IsSpace(CurrentByte_)) {
+ ReadNextByteUnsafe();
+ }
+ }
+
+ void SkipUntilEol() {
+ while (HasRemaining() && CurrentByte_ != '\n') {
+ ReadNextByteUnsafe();
+ }
+ }
+
+ TStringBuf ReadToken() {
+ Y_VERIFY_DEBUG(CurrentPos_ > 0);
+ size_t begin = CurrentPos_ - 1; // read first byte again
+ while (HasRemaining() && !IsSpace(CurrentByte_) && CurrentByte_ != '\n') {
+ ReadNextByteUnsafe();
+ }
+ return TokenFromPos(begin);
+ }
+
+ TStringBuf ReadTokenAsMetricName() {
+ if (!NPrometheus::IsValidMetricNameStart(CurrentByte_)) {
+ return "";
+ }
+
+ Y_VERIFY_DEBUG(CurrentPos_ > 0);
+ size_t begin = CurrentPos_ - 1; // read first byte again
+ while (HasRemaining()) {
+ ReadNextByteUnsafe();
+ if (!NPrometheus::IsValidMetricNameContinuation(CurrentByte_)) {
+ break;
+ }
+ }
+ return TokenFromPos(begin);
+ }
+
+ TStringBuf ReadTokenAsLabelName() {
+ if (!NPrometheus::IsValidLabelNameStart(CurrentByte_)) {
+ return "";
+ }
+
+ Y_VERIFY_DEBUG(CurrentPos_ > 0);
+ size_t begin = CurrentPos_ - 1; // read first byte again
+ while (HasRemaining()) {
+ ReadNextByteUnsafe();
+ if (!NPrometheus::IsValidLabelNameContinuation(CurrentByte_)) {
+ break;
+ }
+ }
+ return TokenFromPos(begin);
+ }
+
+ TString ReadTokenAsLabelValue() {
+ TString labelValue;
+
+ SkipExpectedChar('"');
+ for (ui32 i = 0; i < MAX_LABEL_VALUE_LEN; i++) {
+ switch (CurrentByte_) {
+ case '"':
+ SkipExpectedChar('"');
+ return labelValue;
+
+ case '\n':
+ Y_PARSER_FAIL("label value contains unescaped new-line");
+
+ case '\\':
+ ReadNextByte();
+ switch (CurrentByte_) {
+ case '"':
+ case '\\':
+ labelValue.append(CurrentByte_);
+ break;
+ case 'n':
+ labelValue.append('\n');
+ break;
+ default:
+ Y_PARSER_FAIL("invalid escape sequence '" << CurrentByte_ << '\'');
+ }
+ break;
+
+ default:
+ labelValue.append(CurrentByte_);
+ break;
+ }
+
+ ReadNextByte();
+ }
+
+ Y_PARSER_FAIL("trying to parse too long label value, size >= " << MAX_LABEL_VALUE_LEN);
+ }
+
+ TStringBuf TokenFromPos(size_t begin) {
+ Y_VERIFY_DEBUG(CurrentPos_ > begin);
+ size_t len = CurrentPos_ - begin - 1;
+ if (len == 0) {
+ return {};
+ }
+
+ return Data_.SubString(begin, len);
+ }
+
+ void ConsumeLabels(TStringBuf name, const TLabelsMap& labels) {
+ Y_PARSER_ENSURE(labels.count(MetricNameLabel_) == 0,
+ "label name '" << MetricNameLabel_ <<
+ "' is reserved, but is used with metric: " << name << LabelsToStr(labels));
+
+ Consumer_->OnLabelsBegin();
+ Consumer_->OnLabel(MetricNameLabel_, TString(name)); // TODO: remove this string allocation
+ for (const auto& it: labels) {
+ Consumer_->OnLabel(it.first, it.second);
+ }
+ Consumer_->OnLabelsEnd();
+ }
+
+ void ConsumeCounter(TStringBuf name, const TLabelsMap& labels, TInstant time, double value) {
+ i64 intValue{0};
+ // not nan
+ if (value == value) {
+ Y_PARSER_ENSURE(TryStaticCast(value, intValue), "value " << value << " is out of range");
+ }
+
+ // see https://st.yandex-team.ru/SOLOMON-4142 for more details
+ // why we convert Prometheus COUNTER into Solomon RATE
+ // TODO: need to fix after server-side aggregation become correct for COUNTERs
+ Consumer_->OnMetricBegin(EMetricType::RATE);
+ ConsumeLabels(name, labels);
+ Consumer_->OnUint64(time, intValue);
+ Consumer_->OnMetricEnd();
+ }
+
+ void ConsumeGauge(TStringBuf name, const TLabelsMap& labels, TInstant time, double value) {
+ Consumer_->OnMetricBegin(EMetricType::GAUGE);
+ ConsumeLabels(name, labels);
+ Consumer_->OnDouble(time, value);
+ Consumer_->OnMetricEnd();
+ }
+
+ void ConsumeHistogram() {
+ Consumer_->OnMetricBegin(EMetricType::HIST_RATE);
+ ConsumeLabels(HistogramBuilder_.GetName(), HistogramBuilder_.GetLabels());
+ auto time = HistogramBuilder_.GetTime();
+ auto hist = HistogramBuilder_.ToSnapshot();
+ Consumer_->OnHistogram(time, std::move(hist));
+ Consumer_->OnMetricEnd();
+ }
+
+ double ParseGoDouble(TStringBuf str) {
+ if (str == TStringBuf("+Inf")) {
+ return std::numeric_limits<double>::infinity();
+ } else if (str == TStringBuf("-Inf")) {
+ return -std::numeric_limits<double>::infinity();
+ } else if (str == TStringBuf("NaN")) {
+ return NAN;
+ }
+
+ double r = 0.0;
+ if (TryFromString(str, r)) {
+ return r;
+ }
+ Y_PARSER_FAIL("cannot parse double value from '" << str << "\' at line #" << CurrentLine_);
+ }
+
+ private:
+ TStringBuf Data_;
+ IMetricConsumer* Consumer_;
+ TStringBuf MetricNameLabel_;
+ THashMap<TString, EPrometheusMetricType> SeenTypes_;
+ THistogramBuilder HistogramBuilder_;
+
+ ui32 CurrentLine_ = 1;
+ ui32 CurrentPos_ = 0;
+ char CurrentByte_ = 0;
+ };
+ } // namespace
+
+void DecodePrometheus(TStringBuf data, IMetricConsumer* c, TStringBuf metricNameLabel) {
+ TPrometheusReader reader(data, c, metricNameLabel);
+ reader.Read();
+}
+
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/encode/prometheus/prometheus_decoder_ut.cpp b/library/cpp/monlib/encode/prometheus/prometheus_decoder_ut.cpp
new file mode 100644
index 0000000000..49c2244fb4
--- /dev/null
+++ b/library/cpp/monlib/encode/prometheus/prometheus_decoder_ut.cpp
@@ -0,0 +1,478 @@
+#include "prometheus.h"
+
+#include <library/cpp/monlib/encode/protobuf/protobuf.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NMonitoring;
+
+#define ASSERT_LABEL_EQUAL(label, name, value) do { \
+ UNIT_ASSERT_STRINGS_EQUAL((label).GetName(), name); \
+ UNIT_ASSERT_STRINGS_EQUAL((label).GetValue(), value); \
+ } while (false)
+
+#define ASSERT_DOUBLE_POINT(s, time, value) do { \
+ UNIT_ASSERT_VALUES_EQUAL((s).GetTime(), (time).MilliSeconds()); \
+ UNIT_ASSERT_EQUAL((s).GetValueCase(), NProto::TSingleSample::kFloat64); \
+ UNIT_ASSERT_DOUBLES_EQUAL((s).GetFloat64(), value, std::numeric_limits<double>::epsilon()); \
+ } while (false)
+
+#define ASSERT_UINT_POINT(s, time, value) do { \
+ UNIT_ASSERT_VALUES_EQUAL((s).GetTime(), (time).MilliSeconds()); \
+ UNIT_ASSERT_EQUAL((s).GetValueCase(), NProto::TSingleSample::kUint64); \
+ UNIT_ASSERT_VALUES_EQUAL((s).GetUint64(), value); \
+ } while (false)
+
+#define ASSERT_HIST_POINT(s, time, expected) do { \
+ UNIT_ASSERT_VALUES_EQUAL((s).GetTime(), time.MilliSeconds()); \
+ UNIT_ASSERT_EQUAL((s).GetValueCase(), NProto::TSingleSample::kHistogram);\
+ UNIT_ASSERT_VALUES_EQUAL((s).GetHistogram().BoundsSize(), (expected).Count()); \
+ UNIT_ASSERT_VALUES_EQUAL((s).GetHistogram().ValuesSize(), (expected).Count()); \
+ for (size_t i = 0; i < (s).GetHistogram().BoundsSize(); i++) { \
+ UNIT_ASSERT_DOUBLES_EQUAL((s).GetHistogram().GetBounds(i), (expected).UpperBound(i), Min<double>()); \
+ UNIT_ASSERT_VALUES_EQUAL((s).GetHistogram().GetValues(i), (expected).Value(i)); \
+ } \
+ } while (false)
+
+Y_UNIT_TEST_SUITE(TPrometheusDecoderTest) {
+
+ NProto::TSingleSamplesList Decode(TStringBuf data) {
+ NProto::TSingleSamplesList samples;
+ {
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+ DecodePrometheus(data, e.Get());
+ }
+ return samples;
+ }
+
+ Y_UNIT_TEST(Empty) {
+ {
+ auto samples = Decode("");
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 0);
+ }
+ {
+ auto samples = Decode("\n");
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 0);
+ }
+ {
+ auto samples = Decode("\n \n \n");
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 0);
+ }
+ {
+ auto samples = Decode("\t\n\t\n");
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 0);
+ }
+ }
+
+ Y_UNIT_TEST(Minimal) {
+ auto samples = Decode(
+ "minimal_metric 1.234\n"
+ "another_metric -3e3 103948\n"
+ "# Even that:\n"
+ "no_labels{} 3\n"
+ "# HELP line for non-existing metric will be ignored.\n");
+
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 3);
+ {
+ auto& s = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::GAUGE);
+ UNIT_ASSERT_EQUAL(1, s.LabelsSize());
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "minimal_metric");
+ ASSERT_DOUBLE_POINT(s, TInstant::Zero(), 1.234);
+ }
+ {
+ auto& s = samples.GetSamples(1);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::GAUGE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 1);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "another_metric");
+ ASSERT_DOUBLE_POINT(s, TInstant::MilliSeconds(103948), -3000.0);
+ }
+ {
+ auto& s = samples.GetSamples(2);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::GAUGE);
+ UNIT_ASSERT_EQUAL(1, s.LabelsSize());
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "no_labels");
+ ASSERT_DOUBLE_POINT(s, TInstant::Zero(), 3.0);
+ }
+ }
+
+ Y_UNIT_TEST(Counter) {
+ auto samples = Decode(
+ "# A normal comment.\n"
+ "#\n"
+ "# TYPE name counter\n"
+ "name{labelname=\"val1\",basename=\"basevalue\"} NaN\n"
+ "name {labelname=\"val2\",basename=\"basevalue\"} 2.3 1234567890\n"
+ "# HELP name two-line\\n doc str\\\\ing\n");
+
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 2);
+
+ {
+ auto& s = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 3);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "name");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "basename", "basevalue");
+ ASSERT_LABEL_EQUAL(s.GetLabels(2), "labelname", "val1");
+ ASSERT_UINT_POINT(s, TInstant::Zero(), ui64(0));
+ }
+ {
+ auto& s = samples.GetSamples(1);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 3);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "name");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "basename", "basevalue");
+ ASSERT_LABEL_EQUAL(s.GetLabels(2), "labelname", "val2");
+ ASSERT_UINT_POINT(s, TInstant::MilliSeconds(1234567890), i64(2));
+ }
+ }
+
+ Y_UNIT_TEST(Gauge) {
+ auto samples = Decode(
+ "# A normal comment.\n"
+ "#\n"
+ " # HELP name2 \tdoc str\"ing 2\n"
+ " # TYPE name2 gauge\n"
+ "name2{labelname=\"val2\"\t,basename = \"basevalue2\"\t\t} +Inf 54321\n"
+ "name2{ labelname = \"val1\" , }-Inf\n");
+
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 2);
+
+ {
+ auto& s = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::GAUGE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 3);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "name2");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "basename", "basevalue2");
+ ASSERT_LABEL_EQUAL(s.GetLabels(2), "labelname", "val2");
+ ASSERT_DOUBLE_POINT(s, TInstant::MilliSeconds(54321), INFINITY);
+ }
+ {
+ auto& s = samples.GetSamples(1);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::GAUGE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 2);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "name2");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "labelname", "val1");
+ ASSERT_DOUBLE_POINT(s, TInstant::Zero(), -INFINITY);
+ }
+ }
+
+ Y_UNIT_TEST(Summary) {
+ auto samples = Decode(
+ "# HELP \n"
+ "# TYPE my_summary summary\n"
+ "my_summary{n1=\"val1\",quantile=\"0.5\"} 110\n"
+ "my_summary{n1=\"val1\",quantile=\"0.9\"} 140 1\n"
+ "my_summary_count{n1=\"val1\"} 42\n"
+ "my_summary_sum{n1=\"val1\"} 08 15\n"
+ "# some\n"
+ "# funny comments\n"
+ "# HELP\n"
+ "# HELP my_summary\n"
+ "# HELP my_summary \n");
+
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 4);
+
+ {
+ auto& s = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::GAUGE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 3);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "my_summary");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "quantile", "0.5");
+ ASSERT_LABEL_EQUAL(s.GetLabels(2), "n1", "val1");
+ ASSERT_DOUBLE_POINT(s, TInstant::Zero(), 110.0);
+ }
+ {
+ auto& s = samples.GetSamples(1);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::GAUGE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 3);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "my_summary");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "quantile", "0.9");
+ ASSERT_LABEL_EQUAL(s.GetLabels(2), "n1", "val1");
+ ASSERT_DOUBLE_POINT(s, TInstant::MilliSeconds(1), 140.0);
+ }
+ {
+ auto& s = samples.GetSamples(2);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 2);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "my_summary_count");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "n1", "val1");
+ ASSERT_UINT_POINT(s, TInstant::Zero(), 42);
+ }
+ {
+ auto& s = samples.GetSamples(3);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::GAUGE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 2);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "my_summary_sum");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "n1", "val1");
+ ASSERT_DOUBLE_POINT(s, TInstant::MilliSeconds(15), 8.0);
+ }
+ }
+
+ Y_UNIT_TEST(Histogram) {
+ auto samples = Decode(
+ "# HELP request_duration_microseconds The response latency.\n"
+ "# TYPE request_duration_microseconds histogram\n"
+ "request_duration_microseconds_bucket{le=\"0\"} 0\n"
+ "request_duration_microseconds_bucket{le=\"100\"} 123\n"
+ "request_duration_microseconds_bucket{le=\"120\"} 412\n"
+ "request_duration_microseconds_bucket{le=\"144\"} 592\n"
+ "request_duration_microseconds_bucket{le=\"172.8\"} 1524\n"
+ "request_duration_microseconds_bucket{le=\"+Inf\"} 2693\n"
+ "request_duration_microseconds_sum 1.7560473e+06\n"
+ "request_duration_microseconds_count 2693\n");
+
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 3);
+
+ {
+ auto& s = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::GAUGE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 1);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "request_duration_microseconds_sum");
+ ASSERT_DOUBLE_POINT(s, TInstant::Zero(), 1756047.3);
+ }
+ {
+ auto& s = samples.GetSamples(1);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 1);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "request_duration_microseconds_count");
+ ASSERT_UINT_POINT(s, TInstant::Zero(), 2693);
+ }
+ {
+ auto& s = samples.GetSamples(2);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::HIST_RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 1);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "request_duration_microseconds");
+ auto hist = ExplicitHistogramSnapshot(
+ { 0, 100, 120, 144, 172.8, HISTOGRAM_INF_BOUND },
+ { 0, 123, 289, 180, 932, 1169 });
+ ASSERT_HIST_POINT(s, TInstant::Zero(), *hist);
+ }
+ }
+
+ Y_UNIT_TEST(HistogramWithLabels) {
+ auto samples = Decode(
+ "# A histogram, which has a pretty complex representation in the text format:\n"
+ "# HELP http_request_duration_seconds A histogram of the request duration.\n"
+ "# TYPE http_request_duration_seconds histogram\n"
+ "http_request_duration_seconds_bucket{le=\"0.05\", method=\"POST\"} 24054\n"
+ "http_request_duration_seconds_bucket{method=\"POST\", le=\"0.1\"} 33444\n"
+ "http_request_duration_seconds_bucket{le=\"0.2\", method=\"POST\", } 100392\n"
+ "http_request_duration_seconds_bucket{le=\"0.5\",method=\"POST\",} 129389\n"
+ "http_request_duration_seconds_bucket{ method=\"POST\", le=\"1\", } 133988\n"
+ "http_request_duration_seconds_bucket{ le=\"+Inf\", method=\"POST\", } 144320\n"
+ "http_request_duration_seconds_sum{method=\"POST\"} 53423\n"
+ "http_request_duration_seconds_count{ method=\"POST\", } 144320\n");
+
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 3);
+
+ {
+ auto& s = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::GAUGE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 2);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "http_request_duration_seconds_sum");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "method", "POST");
+ ASSERT_DOUBLE_POINT(s, TInstant::Zero(), 53423.0);
+ }
+ {
+ auto& s = samples.GetSamples(1);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 2);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "http_request_duration_seconds_count");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "method", "POST");
+ ASSERT_UINT_POINT(s, TInstant::Zero(), 144320);
+ }
+ {
+ auto& s = samples.GetSamples(2);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::HIST_RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 2);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "http_request_duration_seconds");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "method", "POST");
+ auto hist = ExplicitHistogramSnapshot(
+ { 0.05, 0.1, 0.2, 0.5, 1, HISTOGRAM_INF_BOUND },
+ { 24054, 9390, 66948, 28997, 4599, 10332 });
+ ASSERT_HIST_POINT(s, TInstant::Zero(), *hist);
+ }
+ }
+
+ Y_UNIT_TEST(MultipleHistograms) {
+ auto samples = Decode(
+ "# TYPE inboundBytesPerSec histogram\n"
+ "inboundBytesPerSec_bucket{client=\"mbus\", le=\"10.0\"} 1.0\n"
+ "inboundBytesPerSec_bucket{client=\"mbus\", le=\"20.0\"} 5.0\n"
+ "inboundBytesPerSec_bucket{client=\"mbus\", le=\"+Inf\"} 5.0\n"
+ "inboundBytesPerSec_count{client=\"mbus\"} 5.0\n"
+ "inboundBytesPerSec_bucket{client=\"grpc\", le=\"10.0\"} 1.0\n"
+ "inboundBytesPerSec_bucket{client=\"grpc\", le=\"20.0\"} 5.0\n"
+ "inboundBytesPerSec_bucket{client=\"grpc\", le=\"30.0\"} 5.0\n"
+ "inboundBytesPerSec_count{client=\"grpc\"} 5.0\n"
+ "# TYPE outboundBytesPerSec histogram\n"
+ "outboundBytesPerSec_bucket{client=\"grpc\", le=\"100.0\"} 1.0 1512216000000\n"
+ "outboundBytesPerSec_bucket{client=\"grpc\", le=\"200.0\"} 1.0 1512216000000\n"
+ "outboundBytesPerSec_bucket{client=\"grpc\", le=\"+Inf\"} 1.0 1512216000000\n"
+ "outboundBytesPerSec_count{client=\"grpc\"} 1.0 1512216000000\n");
+
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 6);
+
+ {
+ auto& s = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 2);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "inboundBytesPerSec_count");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "client", "mbus");
+ ASSERT_UINT_POINT(s, TInstant::Zero(), 5);
+ }
+ {
+ auto& s = samples.GetSamples(1);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::HIST_RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 2);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "inboundBytesPerSec");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "client", "mbus");
+ auto hist = ExplicitHistogramSnapshot(
+ { 10, 20, HISTOGRAM_INF_BOUND },
+ { 1, 4, 0 });
+ ASSERT_HIST_POINT(s, TInstant::Zero(), *hist);
+ }
+ {
+ auto& s = samples.GetSamples(2);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 2);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "inboundBytesPerSec_count");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "client", "grpc");
+ ASSERT_UINT_POINT(s, TInstant::Zero(), 5);
+ }
+ {
+ auto& s = samples.GetSamples(3);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::HIST_RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 2);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "inboundBytesPerSec");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "client", "grpc");
+ auto hist = ExplicitHistogramSnapshot(
+ { 10, 20, 30 },
+ { 1, 4, 0 });
+ ASSERT_HIST_POINT(s, TInstant::Zero(), *hist);
+ }
+ {
+ auto& s = samples.GetSamples(4);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 2);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "outboundBytesPerSec_count");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "client", "grpc");
+ ASSERT_UINT_POINT(s, TInstant::Seconds(1512216000), 1) ;
+ }
+ {
+ auto& s = samples.GetSamples(5);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::HIST_RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 2);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "outboundBytesPerSec");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "client", "grpc");
+ auto hist = ExplicitHistogramSnapshot(
+ { 100, 200, HISTOGRAM_INF_BOUND },
+ { 1, 0, 0 });
+ ASSERT_HIST_POINT(s, TInstant::Seconds(1512216000), *hist);
+ }
+ }
+
+ Y_UNIT_TEST(MixedTypes) {
+ auto samples = Decode(
+ "# HELP http_requests_total The total number of HTTP requests.\n"
+ "# TYPE http_requests_total counter\n"
+ "http_requests_total { } 1027 1395066363000\n"
+ "http_requests_total{method=\"post\",code=\"200\"} 1027 1395066363000\n"
+ "http_requests_total{method=\"post\",code=\"400\"} 3 1395066363000\n"
+ "\n"
+ "# Minimalistic line:\n"
+ "metric_without_timestamp_and_labels 12.47\n"
+ "\n"
+ "# HELP rpc_duration_seconds A summary of the RPC duration in seconds.\n"
+ "# TYPE rpc_duration_seconds summary\n"
+ "rpc_duration_seconds{quantile=\"0.01\"} 3102\n"
+ "rpc_duration_seconds{quantile=\"0.5\"} 4773\n"
+ "rpc_duration_seconds{quantile=\"0.9\"} 9001\n"
+ "rpc_duration_seconds_sum 1.7560473e+07\n"
+ "rpc_duration_seconds_count 2693\n"
+ "\n"
+ "# Another mMinimalistic line:\n"
+ "metric_with_timestamp 12.47 1234567890\n");
+
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 10);
+
+ {
+ auto& s = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 1);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "http_requests_total");
+ ASSERT_UINT_POINT(s, TInstant::Seconds(1395066363), 1027);
+ }
+ {
+ auto& s = samples.GetSamples(1);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 3);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "http_requests_total");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "method", "post");
+ ASSERT_LABEL_EQUAL(s.GetLabels(2), "code", "200");
+ ASSERT_UINT_POINT(s, TInstant::Seconds(1395066363), 1027);
+ }
+ {
+ auto& s = samples.GetSamples(2);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 3);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "http_requests_total");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "method", "post");
+ ASSERT_LABEL_EQUAL(s.GetLabels(2), "code", "400");
+ ASSERT_UINT_POINT(s, TInstant::Seconds(1395066363), 3);
+ }
+ {
+ auto& s = samples.GetSamples(3);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::GAUGE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 1);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "metric_without_timestamp_and_labels");
+ ASSERT_DOUBLE_POINT(s, TInstant::Zero(), 12.47);
+ }
+ {
+ auto& s = samples.GetSamples(4);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::GAUGE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 2);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "rpc_duration_seconds");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "quantile", "0.01");
+ ASSERT_DOUBLE_POINT(s, TInstant::Zero(), 3102);
+ }
+ {
+ auto& s = samples.GetSamples(5);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::GAUGE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 2);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "rpc_duration_seconds");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "quantile", "0.5");
+ ASSERT_DOUBLE_POINT(s, TInstant::Zero(), 4773);
+ }
+ {
+ auto& s = samples.GetSamples(6);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::GAUGE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 2);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "rpc_duration_seconds");
+ ASSERT_LABEL_EQUAL(s.GetLabels(1), "quantile", "0.9");
+ ASSERT_DOUBLE_POINT(s, TInstant::Zero(), 9001);
+ }
+ {
+ auto& s = samples.GetSamples(7);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::GAUGE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 1);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "rpc_duration_seconds_sum");
+ ASSERT_DOUBLE_POINT(s, TInstant::Zero(), 17560473);
+ }
+ {
+ auto& s = samples.GetSamples(8);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::RATE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 1);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "rpc_duration_seconds_count");
+ ASSERT_UINT_POINT(s, TInstant::Zero(), 2693);
+ }
+ {
+ auto& s = samples.GetSamples(9);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::EMetricType::GAUGE);
+ UNIT_ASSERT_EQUAL(s.LabelsSize(), 1);
+ ASSERT_LABEL_EQUAL(s.GetLabels(0), "sensor", "metric_with_timestamp");
+ ASSERT_DOUBLE_POINT(s, TInstant::MilliSeconds(1234567890), 12.47);
+ }
+ }
+}
diff --git a/library/cpp/monlib/encode/prometheus/prometheus_encoder.cpp b/library/cpp/monlib/encode/prometheus/prometheus_encoder.cpp
new file mode 100644
index 0000000000..15efeb8c03
--- /dev/null
+++ b/library/cpp/monlib/encode/prometheus/prometheus_encoder.cpp
@@ -0,0 +1,413 @@
+#include "prometheus.h"
+#include "prometheus_model.h"
+
+#include <library/cpp/monlib/encode/encoder_state.h>
+#include <library/cpp/monlib/metrics/labels.h>
+#include <library/cpp/monlib/metrics/metric_value.h>
+
+#include <util/string/cast.h>
+#include <util/generic/hash_set.h>
+
+
+namespace NMonitoring {
+ namespace {
+ ///////////////////////////////////////////////////////////////////////
+ // TPrometheusWriter
+ ///////////////////////////////////////////////////////////////////////
+ class TPrometheusWriter {
+ public:
+ explicit TPrometheusWriter(IOutputStream* out)
+ : Out_(out)
+ {
+ }
+
+ void WriteType(EMetricType type, const TString& name) {
+ auto r = WrittenTypes_.insert(name);
+ if (!r.second) {
+ // type for this metric was already written
+ return;
+ }
+
+ Out_->Write("# TYPE ");
+ WriteMetricName(name);
+ Out_->Write(' ');
+
+ switch (type) {
+ case EMetricType::GAUGE:
+ case EMetricType::IGAUGE:
+ Out_->Write("gauge");
+ break;
+ case EMetricType::RATE:
+ case EMetricType::COUNTER:
+ Out_->Write("counter");
+ break;
+ case EMetricType::HIST:
+ case EMetricType::HIST_RATE:
+ Out_->Write("histogram");
+ break;
+ case EMetricType::LOGHIST:
+ // TODO(@kbalakirev): implement this case
+ break;
+ case EMetricType::DSUMMARY:
+ ythrow yexception() << "writing summary type is forbiden";
+ case EMetricType::UNKNOWN:
+ ythrow yexception() << "unknown metric type: " << MetricTypeToStr(type)
+ << ", name: " << name;
+ }
+ Out_->Write('\n');
+ }
+
+ void WriteDouble(TStringBuf name, const TLabels& labels, TInstant time, double value) {
+ WriteValue(name, "", labels, "", "", time, value);
+ }
+
+ void WriteHistogram(TStringBuf name, const TLabels& labels, TInstant time, IHistogramSnapshot* h) {
+ Y_ENSURE(!labels.Has(NPrometheus::BUCKET_LABEL),
+ "histogram metric " << name << " has label '" <<
+ NPrometheus::BUCKET_LABEL << "' which is reserved in Prometheus");
+
+ double totalCount = 0;
+ for (ui32 i = 0, count = h->Count(); i < count; i++) {
+ TBucketBound bound = h->UpperBound(i);
+ TStringBuf boundStr;
+ if (bound == HISTOGRAM_INF_BOUND) {
+ boundStr = TStringBuf("+Inf");
+ } else {
+ size_t len = FloatToString(bound, TmpBuf_, Y_ARRAY_SIZE(TmpBuf_));
+ boundStr = TStringBuf(TmpBuf_, len);
+ }
+
+ TBucketValue value = h->Value(i);
+ totalCount += static_cast<double>(value);
+
+ WriteValue(
+ name, NPrometheus::BUCKET_SUFFIX,
+ labels, NPrometheus::BUCKET_LABEL, boundStr,
+ time,
+ totalCount);
+ }
+
+ WriteValue(name, NPrometheus::COUNT_SUFFIX, labels, "", "", time, totalCount);
+ }
+
+ void WriteSummaryDouble(TStringBuf name, const TLabels& labels, TInstant time, ISummaryDoubleSnapshot* s) {
+ WriteValue(name, NPrometheus::SUM_SUFFIX, labels, "", "", time, s->GetSum());
+ WriteValue(name, NPrometheus::MIN_SUFFIX, labels, "", "", time, s->GetMin());
+ WriteValue(name, NPrometheus::MAX_SUFFIX, labels, "", "", time, s->GetMax());
+ WriteValue(name, NPrometheus::LAST_SUFFIX, labels, "", "", time, s->GetLast());
+ WriteValue(name, NPrometheus::COUNT_SUFFIX, labels, "", "", time, s->GetCount());
+ }
+
+ void WriteLn() {
+ Out_->Write('\n');
+ }
+
+ private:
+ // will replace invalid chars with '_'
+ void WriteMetricName(TStringBuf name) {
+ Y_ENSURE(!name.Empty(), "trying to write metric with empty name");
+
+ char ch = name[0];
+ if (NPrometheus::IsValidMetricNameStart(ch)) {
+ Out_->Write(ch);
+ } else {
+ Out_->Write('_');
+ }
+
+ for (size_t i = 1, len = name.length(); i < len; i++) {
+ ch = name[i];
+ if (NPrometheus::IsValidMetricNameContinuation(ch)) {
+ Out_->Write(ch);
+ } else {
+ Out_->Write('_');
+ }
+ }
+ }
+
+ void WriteLabels(const TLabels& labels, TStringBuf addLabelKey, TStringBuf addLabelValue) {
+ Out_->Write('{');
+ for (auto&& l: labels) {
+ Out_->Write(l.Name());
+ Out_->Write('=');
+ WriteLabelValue(l.Value());
+ Out_->Write(", "); // trailign comma is supported in parsers
+ }
+ if (!addLabelKey.Empty() && !addLabelValue.Empty()) {
+ Out_->Write(addLabelKey);
+ Out_->Write('=');
+ WriteLabelValue(addLabelValue);
+ }
+ Out_->Write('}');
+ }
+
+ void WriteLabelValue(TStringBuf value) {
+ Out_->Write('"');
+ for (char ch: value) {
+ if (ch == '"') {
+ Out_->Write("\\\"");
+ } else if (ch == '\\') {
+ Out_->Write("\\\\");
+ } else if (ch == '\n') {
+ Out_->Write("\\n");
+ } else {
+ Out_->Write(ch);
+ }
+ }
+ Out_->Write('"');
+ }
+
+ void WriteValue(
+ TStringBuf name, TStringBuf suffix,
+ const TLabels& labels, TStringBuf addLabelKey, TStringBuf addLabelValue,
+ TInstant time, double value)
+ {
+ // (1) name
+ WriteMetricName(name);
+ if (!suffix.Empty()) {
+ Out_->Write(suffix);
+ }
+
+ // (2) labels
+ if (!labels.Empty() || !addLabelKey.Empty()) {
+ WriteLabels(labels, addLabelKey, addLabelValue);
+ }
+ Out_->Write(' ');
+
+ // (3) value
+ {
+ size_t len = FloatToString(value, TmpBuf_, Y_ARRAY_SIZE(TmpBuf_));
+ Out_->Write(TmpBuf_, len);
+ }
+
+ // (4) time
+ if (ui64 timeMillis = time.MilliSeconds()) {
+ Out_->Write(' ');
+ size_t len = IntToString<10>(timeMillis, TmpBuf_, Y_ARRAY_SIZE(TmpBuf_));
+ Out_->Write(TmpBuf_, len);
+ }
+ Out_->Write('\n');
+ }
+
+ private:
+ IOutputStream* Out_;
+ THashSet<TString> WrittenTypes_;
+ char TmpBuf_[512]; // used to convert doubles to strings
+ };
+
+ ///////////////////////////////////////////////////////////////////////
+ // TMetricState
+ ///////////////////////////////////////////////////////////////////////
+ struct TMetricState {
+ EMetricType Type = EMetricType::UNKNOWN;
+ TLabels Labels;
+ TInstant Time = TInstant::Zero();
+ EMetricValueType ValueType = EMetricValueType::UNKNOWN;
+ TMetricValue Value;
+
+ ~TMetricState() {
+ ClearValue();
+ }
+
+ void Clear() {
+ Type = EMetricType::UNKNOWN;
+ Labels.Clear();
+ Time = TInstant::Zero();
+ ClearValue();
+ }
+
+ void ClearValue() {
+ // TMetricValue does not keep ownership of histogram
+ if (ValueType == EMetricValueType::HISTOGRAM) {
+ Value.AsHistogram()->UnRef();
+ } else if (ValueType == EMetricValueType::SUMMARY) {
+ Value.AsSummaryDouble()->UnRef();
+ }
+ ValueType = EMetricValueType::UNKNOWN;
+ Value = {};
+ }
+
+ template <typename T>
+ void SetValue(T value) {
+ // TMetricValue does not keep ownership of histogram
+ if (ValueType == EMetricValueType::HISTOGRAM) {
+ Value.AsHistogram()->UnRef();
+ } else if (ValueType == EMetricValueType::SUMMARY) {
+ Value.AsSummaryDouble()->UnRef();
+ }
+ ValueType = TValueType<T>::Type;
+ Value = TMetricValue(value);
+ if (ValueType == EMetricValueType::HISTOGRAM) {
+ Value.AsHistogram()->Ref();
+ } else if (ValueType == EMetricValueType::SUMMARY) {
+ Value.AsSummaryDouble()->Ref();
+ }
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////
+ // TPrometheusEncoder
+ ///////////////////////////////////////////////////////////////////////
+ class TPrometheusEncoder final: public IMetricEncoder {
+ public:
+ explicit TPrometheusEncoder(IOutputStream* out, TStringBuf metricNameLabel)
+ : Writer_(out)
+ , MetricNameLabel_(metricNameLabel)
+ {
+ }
+
+ private:
+ void OnStreamBegin() override {
+ State_.Expect(TEncoderState::EState::ROOT);
+ }
+
+ void OnStreamEnd() override {
+ State_.Expect(TEncoderState::EState::ROOT);
+ Writer_.WriteLn();
+ }
+
+ void OnCommonTime(TInstant time) override {
+ State_.Expect(TEncoderState::EState::ROOT);
+ CommonTime_ = time;
+ }
+
+ void OnMetricBegin(EMetricType type) override {
+ State_.Switch(TEncoderState::EState::ROOT, TEncoderState::EState::METRIC);
+ MetricState_.Clear();
+ MetricState_.Type = type;
+ }
+
+ void OnMetricEnd() override {
+ State_.Switch(TEncoderState::EState::METRIC, TEncoderState::EState::ROOT);
+ WriteMetric();
+ }
+
+ void OnLabelsBegin() override {
+ if (State_ == TEncoderState::EState::METRIC) {
+ State_ = TEncoderState::EState::METRIC_LABELS;
+ } else if (State_ == TEncoderState::EState::ROOT) {
+ State_ = TEncoderState::EState::COMMON_LABELS;
+ } else {
+ State_.ThrowInvalid("expected METRIC or ROOT");
+ }
+ }
+
+ void OnLabelsEnd() override {
+ if (State_ == TEncoderState::EState::METRIC_LABELS) {
+ State_ = TEncoderState::EState::METRIC;
+ } else if (State_ == TEncoderState::EState::COMMON_LABELS) {
+ State_ = TEncoderState::EState::ROOT;
+ } else {
+ State_.ThrowInvalid("expected LABELS or COMMON_LABELS");
+ }
+ }
+
+ void OnLabel(TStringBuf name, TStringBuf value) override {
+ if (State_ == TEncoderState::EState::METRIC_LABELS) {
+ MetricState_.Labels.Add(name, value);
+ } else if (State_ == TEncoderState::EState::COMMON_LABELS) {
+ CommonLabels_.Add(name, value);
+ } else {
+ State_.ThrowInvalid("expected LABELS or COMMON_LABELS");
+ }
+ }
+
+ void OnDouble(TInstant time, double value) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ MetricState_.Time = time;
+ MetricState_.SetValue(value);
+ }
+
+ void OnInt64(TInstant time, i64 value) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ MetricState_.Time = time;
+ MetricState_.SetValue(value);
+ }
+
+ void OnUint64(TInstant time, ui64 value) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ MetricState_.Time = time;
+ MetricState_.SetValue(value);
+ }
+
+ void OnHistogram(TInstant time, IHistogramSnapshotPtr snapshot) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ MetricState_.Time = time;
+ MetricState_.SetValue(snapshot.Get());
+ }
+
+ void OnSummaryDouble(TInstant time, ISummaryDoubleSnapshotPtr snapshot) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ MetricState_.Time = time;
+ MetricState_.SetValue(snapshot.Get());
+ }
+
+ void OnLogHistogram(TInstant, TLogHistogramSnapshotPtr) override {
+ // TODO(@kbalakirev): implement this function
+ }
+
+ void Close() override {
+ }
+
+ void WriteMetric() {
+ if (MetricState_.ValueType == EMetricValueType::UNKNOWN) {
+ return;
+ }
+
+ // XXX: poor performace
+ for (auto&& l: CommonLabels_) {
+ MetricState_.Labels.Add(l.Name(), l.Value());
+ }
+
+ TMaybe<TLabel> nameLabel = MetricState_.Labels.Extract(MetricNameLabel_);
+ Y_ENSURE(nameLabel,
+ "labels " << MetricState_.Labels <<
+ " does not contain label '" << MetricNameLabel_ << '\'');
+
+ const TString& metricName = ToString(nameLabel->Value());
+ if (MetricState_.Type != EMetricType::DSUMMARY) {
+ Writer_.WriteType(MetricState_.Type, metricName);
+ }
+
+ if (MetricState_.Time == TInstant::Zero()) {
+ MetricState_.Time = CommonTime_;
+ }
+
+ EMetricType type = MetricState_.Type;
+ if (type == EMetricType::HIST || type == EMetricType::HIST_RATE) {
+ Y_ENSURE(MetricState_.ValueType == EMetricValueType::HISTOGRAM,
+ "invalid value type for histogram: " << int(MetricState_.ValueType)); // TODO: to string conversion
+ Writer_.WriteHistogram(
+ metricName,
+ MetricState_.Labels,
+ MetricState_.Time,
+ MetricState_.Value.AsHistogram());
+ } else if (type == EMetricType::DSUMMARY) {
+ Writer_.WriteSummaryDouble(
+ metricName,
+ MetricState_.Labels,
+ MetricState_.Time,
+ MetricState_.Value.AsSummaryDouble());
+ } else {
+ Writer_.WriteDouble(
+ metricName,
+ MetricState_.Labels,
+ MetricState_.Time,
+ MetricState_.Value.AsDouble(MetricState_.ValueType));
+ }
+ }
+
+ private:
+ TEncoderState State_;
+ TPrometheusWriter Writer_;
+ TString MetricNameLabel_;
+ TInstant CommonTime_ = TInstant::Zero();
+ TLabels CommonLabels_;
+ TMetricState MetricState_;
+ };
+ }
+
+ IMetricEncoderPtr EncoderPrometheus(IOutputStream* out, TStringBuf metricNameLabel) {
+ return MakeHolder<TPrometheusEncoder>(out, metricNameLabel);
+ }
+
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/encode/prometheus/prometheus_encoder_ut.cpp b/library/cpp/monlib/encode/prometheus/prometheus_encoder_ut.cpp
new file mode 100644
index 0000000000..fd9debb060
--- /dev/null
+++ b/library/cpp/monlib/encode/prometheus/prometheus_encoder_ut.cpp
@@ -0,0 +1,414 @@
+#include "prometheus.h"
+
+#include <library/cpp/monlib/encode/protobuf/protobuf.h>
+#include <library/cpp/monlib/metrics/metric_value.h>
+#include <library/cpp/monlib/metrics/histogram_snapshot.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/str.h>
+
+using namespace NMonitoring;
+
+Y_UNIT_TEST_SUITE(TPrometheusEncoderTest) {
+
+ template <typename TFunc>
+ TString EncodeToString(TFunc fn) {
+ TStringStream ss;
+ IMetricEncoderPtr encoder = EncoderPrometheus(&ss);
+ fn(encoder.Get());
+ return ss.Str();
+ }
+
+ ISummaryDoubleSnapshotPtr TestSummaryDouble() {
+ return MakeIntrusive<TSummaryDoubleSnapshot>(10.1, -0.45, 0.478, 0.3, 30u);
+ }
+
+ Y_UNIT_TEST(Empty) {
+ auto result = EncodeToString([](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ e->OnStreamEnd();
+ });
+ UNIT_ASSERT_STRINGS_EQUAL(result, "\n");
+ }
+
+ Y_UNIT_TEST(DoubleGauge) {
+ auto result = EncodeToString([](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ { // no values
+ e->OnMetricBegin(EMetricType::GAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "cpuUsage");
+ e->OnLabelsEnd();
+ }
+ e->OnMetricEnd();
+ }
+ { // one value no ts
+ e->OnMetricBegin(EMetricType::GAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "diskUsage");
+ e->OnLabel("disk", "sda1");
+ e->OnLabelsEnd();
+ }
+ e->OnDouble(TInstant::Zero(), 1000);
+ e->OnMetricEnd();
+ }
+ { // one value with ts
+ e->OnMetricBegin(EMetricType::GAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "memoryUsage");
+ e->OnLabel("host", "solomon-man-00");
+ e->OnLabel("dc", "man");
+ e->OnLabelsEnd();
+ }
+ e->OnDouble(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:00Z"), 1000);
+ e->OnMetricEnd();
+ }
+ { // many values
+ e->OnMetricBegin(EMetricType::GAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "bytesRx");
+ e->OnLabel("host", "solomon-sas-01");
+ e->OnLabel("dc", "sas");
+ e->OnLabelsEnd();
+ }
+ e->OnDouble(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:00Z"), 2);
+ e->OnDouble(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:05Z"), 4);
+ e->OnDouble(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:10Z"), 8);
+ e->OnMetricEnd();
+ }
+ { // already seen metric name
+ e->OnMetricBegin(EMetricType::GAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "diskUsage");
+ e->OnLabel("disk", "sdb1");
+ e->OnLabelsEnd();
+ }
+ e->OnDouble(TInstant::Zero(), 1001);
+ e->OnMetricEnd();
+ }
+ { // NaN
+ e->OnMetricBegin(EMetricType::GAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "nanValue");
+ e->OnLabelsEnd();
+ }
+ e->OnDouble(TInstant::Zero(), NAN);
+ e->OnMetricEnd();
+ }
+ { // Inf
+ e->OnMetricBegin(EMetricType::GAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "infValue");
+ e->OnLabelsEnd();
+ }
+ e->OnDouble(TInstant::Zero(), INFINITY);
+ e->OnMetricEnd();
+ }
+ {
+ e->OnMetricBegin(EMetricType::DSUMMARY);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "seconds");
+ e->OnLabel("disk", "sdb1");
+ e->OnLabelsEnd();
+ }
+ e->OnSummaryDouble(TInstant::Zero(), TestSummaryDouble());
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ });
+
+ UNIT_ASSERT_STRINGS_EQUAL(result,
+ "# TYPE diskUsage gauge\n"
+ "diskUsage{disk=\"sda1\", } 1000\n"
+ "# TYPE memoryUsage gauge\n"
+ "memoryUsage{host=\"solomon-man-00\", dc=\"man\", } 1000 1512216000000\n"
+ "# TYPE bytesRx gauge\n"
+ "bytesRx{host=\"solomon-sas-01\", dc=\"sas\", } 8 1512216010000\n"
+ "diskUsage{disk=\"sdb1\", } 1001\n"
+ "# TYPE nanValue gauge\n"
+ "nanValue nan\n"
+ "# TYPE infValue gauge\n"
+ "infValue inf\n"
+ "seconds_sum{disk=\"sdb1\", } 10.1\n"
+ "seconds_min{disk=\"sdb1\", } -0.45\n"
+ "seconds_max{disk=\"sdb1\", } 0.478\n"
+ "seconds_last{disk=\"sdb1\", } 0.3\n"
+ "seconds_count{disk=\"sdb1\", } 30\n"
+ "\n");
+ }
+
+ Y_UNIT_TEST(IntGauges) {
+ auto result = EncodeToString([](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ { // no values
+ e->OnMetricBegin(EMetricType::IGAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "cpuUsage");
+ e->OnLabelsEnd();
+ }
+ e->OnMetricEnd();
+ }
+ { // one value no ts
+ e->OnMetricBegin(EMetricType::IGAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "diskUsage");
+ e->OnLabel("disk", "sda1");
+ e->OnLabelsEnd();
+ }
+ e->OnInt64(TInstant::Zero(), 1000);
+ e->OnMetricEnd();
+ }
+ { // one value with ts
+ e->OnMetricBegin(EMetricType::IGAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "memoryUsage");
+ e->OnLabel("dc", "man");
+ e->OnLabel("host", "solomon-man-00");
+ e->OnLabelsEnd();
+ }
+ e->OnInt64(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:00Z"), 1000);
+ e->OnMetricEnd();
+ }
+ { // many values
+ e->OnMetricBegin(EMetricType::IGAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "bytesRx");
+ e->OnLabel("dc", "sas");
+ e->OnLabel("host", "solomon-sas-01");
+ e->OnLabelsEnd();
+ }
+ e->OnInt64(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:00Z"), 2);
+ e->OnInt64(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:05Z"), 4);
+ e->OnInt64(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:10Z"), 8);
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ });
+
+ UNIT_ASSERT_STRINGS_EQUAL(result,
+ "# TYPE diskUsage gauge\n"
+ "diskUsage{disk=\"sda1\", } 1000\n"
+ "# TYPE memoryUsage gauge\n"
+ "memoryUsage{dc=\"man\", host=\"solomon-man-00\", } 1000 1512216000000\n"
+ "# TYPE bytesRx gauge\n"
+ "bytesRx{dc=\"sas\", host=\"solomon-sas-01\", } 8 1512216010000\n"
+ "\n");
+ }
+
+ Y_UNIT_TEST(Counters) {
+ auto result = EncodeToString([](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ { // no values
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "cpuUsage");
+ e->OnLabelsEnd();
+ }
+ e->OnMetricEnd();
+ }
+ { // one value no ts
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "diskUsage");
+ e->OnLabel("disk", "sda1");
+ e->OnLabelsEnd();
+ }
+ e->OnInt64(TInstant::Zero(), 1000);
+ e->OnMetricEnd();
+ }
+ { // one value with ts
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "memoryUsage");
+ e->OnLabel("host", "solomon-man-00");
+ e->OnLabel("dc", "man");
+ e->OnLabelsEnd();
+ }
+ e->OnInt64(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:00Z"), 1000);
+ e->OnMetricEnd();
+ }
+ { // many values
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "bytesRx");
+ e->OnLabel("host", "solomon-sas-01");
+ e->OnLabel("dc", "sas");
+ e->OnLabelsEnd();
+ }
+ e->OnInt64(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:00Z"), 2);
+ e->OnInt64(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:05Z"), 4);
+ e->OnInt64(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:10Z"), 8);
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ });
+
+ UNIT_ASSERT_STRINGS_EQUAL(result,
+ "# TYPE diskUsage counter\n"
+ "diskUsage{disk=\"sda1\", } 1000\n"
+ "# TYPE memoryUsage counter\n"
+ "memoryUsage{host=\"solomon-man-00\", dc=\"man\", } 1000 1512216000000\n"
+ "# TYPE bytesRx counter\n"
+ "bytesRx{host=\"solomon-sas-01\", dc=\"sas\", } 8 1512216010000\n"
+ "\n");
+ }
+
+ Y_UNIT_TEST(Histograms) {
+ auto result = EncodeToString([](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ { // no values histogram
+ e->OnMetricBegin(EMetricType::HIST);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "cpuUsage");
+ e->OnLabelsEnd();
+ }
+ e->OnMetricEnd();
+ }
+ { // one value no ts
+ e->OnMetricBegin(EMetricType::HIST);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "inboundBytesPerSec");
+ e->OnLabel("client", "mbus");
+ e->OnLabelsEnd();
+ }
+ e->OnHistogram(
+ TInstant::Zero(),
+ ExplicitHistogramSnapshot({10, 20, HISTOGRAM_INF_BOUND}, {1, 4, 0}));
+ e->OnMetricEnd();
+ }
+ { // one value no ts no +inf bucket
+ e->OnMetricBegin(EMetricType::HIST);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "inboundBytesPerSec");
+ e->OnLabel("client", "grpc");
+ e->OnLabelsEnd();
+ }
+ e->OnHistogram(
+ TInstant::Zero(),
+ ExplicitHistogramSnapshot({10, 20, 30}, {1, 4, 0}));
+ e->OnMetricEnd();
+ }
+ { // one value with ts
+ e->OnMetricBegin(EMetricType::HIST_RATE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "outboundBytesPerSec");
+ e->OnLabel("client", "grps");
+ e->OnLabelsEnd();
+ }
+ e->OnHistogram(
+ TInstant::ParseIso8601Deprecated("2017-12-02T12:00:00Z"),
+ ExplicitHistogramSnapshot({100, 200, HISTOGRAM_INF_BOUND}, {1, 0, 0}));
+ e->OnMetricEnd();
+ }
+ { // many values
+ e->OnMetricBegin(EMetricType::HIST);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "bytesRx");
+ e->OnLabel("host", "solomon-sas-01");
+ e->OnLabel("dc", "sas");
+ e->OnLabelsEnd();
+ }
+ TBucketBounds bounds = {100, 200, HISTOGRAM_INF_BOUND};
+ e->OnHistogram(
+ TInstant::ParseIso8601Deprecated("2017-12-02T12:00:00Z"),
+ ExplicitHistogramSnapshot(bounds, {10, 0, 0}));
+ e->OnHistogram(
+ TInstant::ParseIso8601Deprecated("2017-12-02T12:00:05Z"),
+ ExplicitHistogramSnapshot(bounds, {10, 2, 0}));
+ e->OnHistogram(
+ TInstant::ParseIso8601Deprecated("2017-12-02T12:00:10Z"),
+ ExplicitHistogramSnapshot(bounds, {10, 2, 5}));
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ });
+
+ UNIT_ASSERT_STRINGS_EQUAL(result,
+ "# TYPE inboundBytesPerSec histogram\n"
+ "inboundBytesPerSec_bucket{client=\"mbus\", le=\"10\"} 1\n"
+ "inboundBytesPerSec_bucket{client=\"mbus\", le=\"20\"} 5\n"
+ "inboundBytesPerSec_bucket{client=\"mbus\", le=\"+Inf\"} 5\n"
+ "inboundBytesPerSec_count{client=\"mbus\", } 5\n"
+ "inboundBytesPerSec_bucket{client=\"grpc\", le=\"10\"} 1\n"
+ "inboundBytesPerSec_bucket{client=\"grpc\", le=\"20\"} 5\n"
+ "inboundBytesPerSec_bucket{client=\"grpc\", le=\"30\"} 5\n"
+ "inboundBytesPerSec_count{client=\"grpc\", } 5\n"
+ "# TYPE outboundBytesPerSec histogram\n"
+ "outboundBytesPerSec_bucket{client=\"grps\", le=\"100\"} 1 1512216000000\n"
+ "outboundBytesPerSec_bucket{client=\"grps\", le=\"200\"} 1 1512216000000\n"
+ "outboundBytesPerSec_bucket{client=\"grps\", le=\"+Inf\"} 1 1512216000000\n"
+ "outboundBytesPerSec_count{client=\"grps\", } 1 1512216000000\n"
+ "# TYPE bytesRx histogram\n"
+ "bytesRx_bucket{host=\"solomon-sas-01\", dc=\"sas\", le=\"100\"} 10 1512216010000\n"
+ "bytesRx_bucket{host=\"solomon-sas-01\", dc=\"sas\", le=\"200\"} 12 1512216010000\n"
+ "bytesRx_bucket{host=\"solomon-sas-01\", dc=\"sas\", le=\"+Inf\"} 17 1512216010000\n"
+ "bytesRx_count{host=\"solomon-sas-01\", dc=\"sas\", } 17 1512216010000\n"
+ "\n");
+ }
+
+ Y_UNIT_TEST(CommonLables) {
+ auto result = EncodeToString([](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ { // common time
+ e->OnCommonTime(TInstant::Seconds(1500000000));
+ }
+ { // common labels
+ e->OnLabelsBegin();
+ e->OnLabel("project", "solomon");
+ e->OnLabelsEnd();
+ }
+ { // metric #1
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "single");
+ e->OnLabel("labels", "l1");
+ e->OnLabelsEnd();
+ }
+ e->OnUint64(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:10Z"), 17);
+ e->OnMetricEnd();
+ }
+ { // metric #2
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "two");
+ e->OnLabel("labels", "l2");
+ e->OnLabelsEnd();
+ }
+ e->OnUint64(TInstant::Zero(), 42);
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ });
+ UNIT_ASSERT_STRINGS_EQUAL(result,
+R"(# TYPE single counter
+single{labels="l1", project="solomon", } 17 1512216010000
+# TYPE two counter
+two{labels="l2", project="solomon", } 42 1500000000000
+
+)");
+ }
+}
diff --git a/library/cpp/monlib/encode/prometheus/prometheus_model.h b/library/cpp/monlib/encode/prometheus/prometheus_model.h
new file mode 100644
index 0000000000..cb7f2cb15b
--- /dev/null
+++ b/library/cpp/monlib/encode/prometheus/prometheus_model.h
@@ -0,0 +1,70 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+
+namespace NMonitoring {
+namespace NPrometheus {
+
+ //
+ // Prometheus specific names and validation rules.
+ //
+ // See https://github.com/prometheus/docs/blob/master/content/docs/instrumenting/exposition_formats.md
+ // and https://github.com/prometheus/common/blob/master/expfmt/text_parse.go
+ //
+
+ inline constexpr TStringBuf BUCKET_SUFFIX = "_bucket";
+ inline constexpr TStringBuf COUNT_SUFFIX = "_count";
+ inline constexpr TStringBuf SUM_SUFFIX = "_sum";
+ inline constexpr TStringBuf MIN_SUFFIX = "_min";
+ inline constexpr TStringBuf MAX_SUFFIX = "_max";
+ inline constexpr TStringBuf LAST_SUFFIX = "_last";
+
+ // Used for the label that defines the upper bound of a bucket of a
+ // histogram ("le" -> "less or equal").
+ inline constexpr TStringBuf BUCKET_LABEL = "le";
+
+
+ inline bool IsValidLabelNameStart(char ch) {
+ return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_';
+ }
+
+ inline bool IsValidLabelNameContinuation(char ch) {
+ return IsValidLabelNameStart(ch) || (ch >= '0' && ch <= '9');
+ }
+
+ inline bool IsValidMetricNameStart(char ch) {
+ return IsValidLabelNameStart(ch) || ch == ':';
+ }
+
+ inline bool IsValidMetricNameContinuation(char ch) {
+ return IsValidLabelNameContinuation(ch) || ch == ':';
+ }
+
+ inline bool IsSum(TStringBuf name) {
+ return name.EndsWith(SUM_SUFFIX);
+ }
+
+ inline bool IsCount(TStringBuf name) {
+ return name.EndsWith(COUNT_SUFFIX);
+ }
+
+ inline bool IsBucket(TStringBuf name) {
+ return name.EndsWith(BUCKET_SUFFIX);
+ }
+
+ inline TStringBuf ToBaseName(TStringBuf name) {
+ if (IsBucket(name)) {
+ return name.SubString(0, name.length() - BUCKET_SUFFIX.length());
+ }
+ if (IsCount(name)) {
+ return name.SubString(0, name.length() - COUNT_SUFFIX.length());
+ }
+ if (IsSum(name)) {
+ return name.SubString(0, name.length() - SUM_SUFFIX.length());
+ }
+ return name;
+ }
+
+} // namespace NPrometheus
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/encode/prometheus/ut/ya.make b/library/cpp/monlib/encode/prometheus/ut/ya.make
new file mode 100644
index 0000000000..fc468ffb68
--- /dev/null
+++ b/library/cpp/monlib/encode/prometheus/ut/ya.make
@@ -0,0 +1,17 @@
+UNITTEST_FOR(library/cpp/monlib/encode/prometheus)
+
+OWNER(
+ g:solomon
+ jamel
+)
+
+SRCS(
+ prometheus_encoder_ut.cpp
+ prometheus_decoder_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/monlib/encode/protobuf
+)
+
+END()
diff --git a/library/cpp/monlib/encode/prometheus/ya.make b/library/cpp/monlib/encode/prometheus/ya.make
new file mode 100644
index 0000000000..7f2483b166
--- /dev/null
+++ b/library/cpp/monlib/encode/prometheus/ya.make
@@ -0,0 +1,17 @@
+LIBRARY()
+
+OWNER(
+ jamel
+ g:solomon
+)
+
+SRCS(
+ prometheus_decoder.cpp
+ prometheus_encoder.cpp
+)
+
+PEERDIR(
+ library/cpp/monlib/encode
+)
+
+END()
diff --git a/library/cpp/monlib/encode/protobuf/protobuf.h b/library/cpp/monlib/encode/protobuf/protobuf.h
new file mode 100644
index 0000000000..3f82cbdd84
--- /dev/null
+++ b/library/cpp/monlib/encode/protobuf/protobuf.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <library/cpp/monlib/encode/encoder.h>
+
+#include <library/cpp/monlib/encode/protobuf/protos/samples.pb.h>
+
+namespace NMonitoring {
+ namespace NProto {
+ class TSingleSamplesList;
+ class TMultiSamplesList;
+ }
+
+ IMetricEncoderPtr EncoderProtobuf(NProto::TSingleSamplesList* samples);
+ IMetricEncoderPtr EncoderProtobuf(NProto::TMultiSamplesList* samples);
+
+}
diff --git a/library/cpp/monlib/encode/protobuf/protobuf_encoder.cpp b/library/cpp/monlib/encode/protobuf/protobuf_encoder.cpp
new file mode 100644
index 0000000000..2d11b9d5ba
--- /dev/null
+++ b/library/cpp/monlib/encode/protobuf/protobuf_encoder.cpp
@@ -0,0 +1,248 @@
+#include "protobuf.h"
+
+#include <util/datetime/base.h>
+
+namespace NMonitoring {
+ namespace {
+ NProto::EMetricType ConvertMetricType(EMetricType type) {
+ switch (type) {
+ case EMetricType::GAUGE:
+ return NProto::GAUGE;
+ case EMetricType::COUNTER:
+ return NProto::COUNTER;
+ case EMetricType::RATE:
+ return NProto::RATE;
+ case EMetricType::IGAUGE:
+ return NProto::IGAUGE;
+ case EMetricType::HIST:
+ return NProto::HISTOGRAM;
+ case EMetricType::HIST_RATE:
+ return NProto::HIST_RATE;
+ case EMetricType::DSUMMARY:
+ return NProto::DSUMMARY;
+ case EMetricType::LOGHIST:
+ return NProto::LOGHISTOGRAM;
+ case EMetricType::UNKNOWN:
+ return NProto::UNKNOWN;
+ }
+ }
+
+ void FillHistogram(
+ const IHistogramSnapshot& snapshot,
+ NProto::THistogram* histogram)
+ {
+ for (ui32 i = 0; i < snapshot.Count(); i++) {
+ histogram->AddBounds(snapshot.UpperBound(i));
+ histogram->AddValues(snapshot.Value(i));
+ }
+ }
+
+ void FillSummaryDouble(const ISummaryDoubleSnapshot& snapshot, NProto::TSummaryDouble* summary) {
+ summary->SetSum(snapshot.GetSum());
+ summary->SetMin(snapshot.GetMin());
+ summary->SetMax(snapshot.GetMax());
+ summary->SetLast(snapshot.GetLast());
+ summary->SetCount(snapshot.GetCount());
+ }
+
+ void FillLogHistogram(const TLogHistogramSnapshot& snapshot, NProto::TLogHistogram* logHist) {
+ logHist->SetBase(snapshot.Base());
+ logHist->SetZerosCount(snapshot.ZerosCount());
+ logHist->SetStartPower(snapshot.StartPower());
+ for (ui32 i = 0; i < snapshot.Count(); ++i) {
+ logHist->AddBuckets(snapshot.Bucket(i));
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // TSingleamplesEncoder
+ ///////////////////////////////////////////////////////////////////////////////
+ class TSingleSamplesEncoder final: public IMetricEncoder {
+ public:
+ TSingleSamplesEncoder(NProto::TSingleSamplesList* samples)
+ : Samples_(samples)
+ , Sample_(nullptr)
+ {
+ }
+
+ private:
+ void OnStreamBegin() override {
+ }
+ void OnStreamEnd() override {
+ }
+
+ void OnCommonTime(TInstant time) override {
+ Samples_->SetCommonTime(time.MilliSeconds());
+ }
+
+ void OnMetricBegin(EMetricType type) override {
+ Sample_ = Samples_->AddSamples();
+ Sample_->SetMetricType(ConvertMetricType(type));
+ }
+
+ void OnMetricEnd() override {
+ Sample_ = nullptr;
+ }
+
+ void OnLabelsBegin() override {
+ }
+ void OnLabelsEnd() override {
+ }
+
+ void OnLabel(TStringBuf name, TStringBuf value) override {
+ NProto::TLabel* label = (Sample_ == nullptr)
+ ? Samples_->AddCommonLabels()
+ : Sample_->AddLabels();
+ label->SetName(TString{name});
+ label->SetValue(TString{value});
+ }
+
+ void OnDouble(TInstant time, double value) override {
+ Y_ENSURE(Sample_, "metric not started");
+ Sample_->SetTime(time.MilliSeconds());
+ Sample_->SetFloat64(value);
+ }
+
+ void OnInt64(TInstant time, i64 value) override {
+ Y_ENSURE(Sample_, "metric not started");
+ Sample_->SetTime(time.MilliSeconds());
+ Sample_->SetInt64(value);
+ }
+
+ void OnUint64(TInstant time, ui64 value) override {
+ Y_ENSURE(Sample_, "metric not started");
+ Sample_->SetTime(time.MilliSeconds());
+ Sample_->SetUint64(value);
+ }
+
+ void OnHistogram(TInstant time, IHistogramSnapshotPtr snapshot) override {
+ Y_ENSURE(Sample_, "metric not started");
+ Sample_->SetTime(time.MilliSeconds());
+ FillHistogram(*snapshot, Sample_->MutableHistogram());
+ }
+
+ void OnSummaryDouble(TInstant time, ISummaryDoubleSnapshotPtr snapshot) override {
+ Y_ENSURE(Sample_, "metric not started");
+ Sample_->SetTime(time.MilliSeconds());
+ FillSummaryDouble(*snapshot, Sample_->MutableSummaryDouble());
+ }
+
+ void OnLogHistogram(TInstant time, TLogHistogramSnapshotPtr snapshot) override {
+ Y_ENSURE(Sample_, "metric not started");
+ Sample_->SetTime(time.MilliSeconds());
+ FillLogHistogram(*snapshot, Sample_->MutableLogHistogram());
+ }
+
+ void Close() override {
+ }
+
+ private:
+ NProto::TSingleSamplesList* Samples_;
+ NProto::TSingleSample* Sample_;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // TMultiSamplesEncoder
+ ///////////////////////////////////////////////////////////////////////////////
+ class TMultiSamplesEncoder final: public IMetricEncoder {
+ public:
+ TMultiSamplesEncoder(NProto::TMultiSamplesList* samples)
+ : Samples_(samples)
+ , Sample_(nullptr)
+ {
+ }
+
+ private:
+ void OnStreamBegin() override {
+ }
+ void OnStreamEnd() override {
+ }
+
+ void OnCommonTime(TInstant time) override {
+ Samples_->SetCommonTime(time.MilliSeconds());
+ }
+
+ void OnMetricBegin(EMetricType type) override {
+ Sample_ = Samples_->AddSamples();
+ Sample_->SetMetricType(ConvertMetricType(type));
+ }
+
+ void OnMetricEnd() override {
+ Sample_ = nullptr;
+ }
+
+ void OnLabelsBegin() override {
+ }
+ void OnLabelsEnd() override {
+ }
+
+ void OnLabel(TStringBuf name, TStringBuf value) override {
+ NProto::TLabel* label = (Sample_ == nullptr)
+ ? Samples_->AddCommonLabels()
+ : Sample_->AddLabels();
+
+ label->SetName(TString{name});
+ label->SetValue(TString{value});
+ }
+
+ void OnDouble(TInstant time, double value) override {
+ Y_ENSURE(Sample_, "metric not started");
+ NProto::TPoint* point = Sample_->AddPoints();
+ point->SetTime(time.MilliSeconds());
+ point->SetFloat64(value);
+ }
+
+ void OnInt64(TInstant time, i64 value) override {
+ Y_ENSURE(Sample_, "metric not started");
+ NProto::TPoint* point = Sample_->AddPoints();
+ point->SetTime(time.MilliSeconds());
+ point->SetInt64(value);
+ }
+
+ void OnUint64(TInstant time, ui64 value) override {
+ Y_ENSURE(Sample_, "metric not started");
+ NProto::TPoint* point = Sample_->AddPoints();
+ point->SetTime(time.MilliSeconds());
+ point->SetUint64(value);
+ }
+
+ void OnHistogram(TInstant time, IHistogramSnapshotPtr snapshot) override {
+ Y_ENSURE(Sample_, "metric not started");
+ NProto::TPoint* point = Sample_->AddPoints();
+ point->SetTime(time.MilliSeconds());
+ FillHistogram(*snapshot, point->MutableHistogram());
+ }
+
+ void OnSummaryDouble(TInstant time, ISummaryDoubleSnapshotPtr snapshot) override {
+ Y_ENSURE(Sample_, "metric not started");
+ NProto::TPoint* point = Sample_->AddPoints();
+ point->SetTime(time.MilliSeconds());
+ FillSummaryDouble(*snapshot, point->MutableSummaryDouble());
+ }
+
+ void OnLogHistogram(TInstant time, TLogHistogramSnapshotPtr snapshot) override {
+ Y_ENSURE(Sample_, "metric not started");
+ NProto::TPoint* point = Sample_->AddPoints();
+ point->SetTime(time.MilliSeconds());
+ FillLogHistogram(*snapshot, point->MutableLogHistogram());
+ }
+
+ void Close() override {
+ }
+
+ private:
+ NProto::TMultiSamplesList* Samples_;
+ NProto::TMultiSample* Sample_;
+ };
+
+ }
+
+ IMetricEncoderPtr EncoderProtobuf(NProto::TSingleSamplesList* samples) {
+ return MakeHolder<TSingleSamplesEncoder>(samples);
+ }
+
+ IMetricEncoderPtr EncoderProtobuf(NProto::TMultiSamplesList* samples) {
+ return MakeHolder<TMultiSamplesEncoder>(samples);
+ }
+
+}
diff --git a/library/cpp/monlib/encode/protobuf/protos/samples.proto b/library/cpp/monlib/encode/protobuf/protos/samples.proto
new file mode 100644
index 0000000000..371f4181d2
--- /dev/null
+++ b/library/cpp/monlib/encode/protobuf/protos/samples.proto
@@ -0,0 +1,91 @@
+syntax = 'proto3';
+
+package NMonitoring.NProto;
+
+option java_package = "ru.yandex.solomon.protos";
+option java_multiple_files = true;
+option cc_enable_arenas = true;
+
+message TLabel {
+ string Name = 1;
+ string Value = 2;
+}
+
+enum EMetricType {
+ UNKNOWN = 0;
+ GAUGE = 1;
+ IGAUGE = 2;
+ COUNTER = 3;
+ RATE = 4;
+ HISTOGRAM = 5;
+ HIST_RATE = 6;
+ DSUMMARY = 7;
+ LOGHISTOGRAM = 8;
+}
+
+message THistogram {
+ repeated double Bounds = 1; // upper bounds of each bucket
+ repeated uint64 Values = 2; // values stored in each bucket
+}
+
+message TLogHistogram {
+ double Base = 1;
+ uint64 ZerosCount = 2;
+ int32 StartPower = 3;
+ repeated double Buckets = 4;
+}
+
+message TSummaryDouble {
+ double Sum = 1;
+ double Min = 2;
+ double Max = 3;
+ double Last = 4;
+ uint64 Count = 5;
+}
+
+// see TSingleSample
+message TPoint {
+ uint64 Time = 1;
+ oneof Value {
+ sfixed64 Int64 = 2;
+ fixed64 Uint64 = 3;
+ double Float64 = 4;
+ THistogram Histogram = 5;
+ TSummaryDouble SummaryDouble = 6;
+ TLogHistogram LogHistogram = 7;
+ }
+}
+
+message TSingleSample {
+ repeated TLabel Labels = 1;
+ EMetricType MetricType = 2;
+
+ // inlined TPoint
+ uint64 Time = 3;
+ oneof Value {
+ sfixed64 Int64 = 4;
+ fixed64 Uint64 = 5;
+ double Float64 = 6;
+ THistogram Histogram = 7;
+ TSummaryDouble SummaryDouble = 8;
+ TLogHistogram LogHistogram = 9;
+ }
+}
+
+message TMultiSample {
+ repeated TLabel Labels = 1;
+ EMetricType MetricType = 2;
+ repeated TPoint Points = 3;
+}
+
+message TSingleSamplesList {
+ uint64 CommonTime = 1;
+ repeated TLabel CommonLabels = 2;
+ repeated TSingleSample Samples = 3;
+}
+
+message TMultiSamplesList {
+ uint64 CommonTime = 1;
+ repeated TLabel CommonLabels = 2;
+ repeated TMultiSample Samples = 3;
+}
diff --git a/library/cpp/monlib/encode/protobuf/protos/ya.make b/library/cpp/monlib/encode/protobuf/protos/ya.make
new file mode 100644
index 0000000000..88ff3ddf88
--- /dev/null
+++ b/library/cpp/monlib/encode/protobuf/protos/ya.make
@@ -0,0 +1,14 @@
+PROTO_LIBRARY()
+
+OWNER(
+ jamel
+ g:solomon
+)
+
+SRCS(
+ samples.proto
+)
+
+EXCLUDE_TAGS(GO_PROTO)
+
+END()
diff --git a/library/cpp/monlib/encode/protobuf/ya.make b/library/cpp/monlib/encode/protobuf/ya.make
new file mode 100644
index 0000000000..9354958b6f
--- /dev/null
+++ b/library/cpp/monlib/encode/protobuf/ya.make
@@ -0,0 +1,17 @@
+LIBRARY()
+
+OWNER(
+ jamel
+ g:solomon
+)
+
+SRCS(
+ protobuf_encoder.cpp
+)
+
+PEERDIR(
+ library/cpp/monlib/encode
+ library/cpp/monlib/encode/protobuf/protos
+)
+
+END()
diff --git a/library/cpp/monlib/encode/spack/compression.cpp b/library/cpp/monlib/encode/spack/compression.cpp
new file mode 100644
index 0000000000..0d2152fc85
--- /dev/null
+++ b/library/cpp/monlib/encode/spack/compression.cpp
@@ -0,0 +1,383 @@
+#include "compression.h"
+
+#include <util/generic/buffer.h>
+#include <util/generic/cast.h>
+#include <util/generic/ptr.h>
+#include <util/generic/scope.h>
+#include <util/generic/size_literals.h>
+#include <util/stream/format.h>
+#include <util/stream/output.h>
+#include <util/stream/walk.h>
+
+#include <contrib/libs/lz4/lz4.h>
+#include <contrib/libs/xxhash/xxhash.h>
+#include <contrib/libs/zlib/zlib.h>
+#define ZSTD_STATIC_LINKING_ONLY
+#include <contrib/libs/zstd/include/zstd.h>
+
+namespace NMonitoring {
+ namespace {
+ ///////////////////////////////////////////////////////////////////////////////
+ // Frame
+ ///////////////////////////////////////////////////////////////////////////////
+ using TCompressedSize = ui32;
+ using TUncompressedSize = ui32;
+ using TCheckSum = ui32;
+
+ constexpr size_t COMPRESSED_FRAME_SIZE_LIMIT = 512_KB;
+ constexpr size_t UNCOMPRESSED_FRAME_SIZE_LIMIT = COMPRESSED_FRAME_SIZE_LIMIT;
+ constexpr size_t FRAME_SIZE_LIMIT = 2_MB;
+ constexpr size_t DEFAULT_FRAME_LEN = 64_KB;
+
+ struct Y_PACKED TFrameHeader {
+ TCompressedSize CompressedSize;
+ TUncompressedSize UncompressedSize;
+ };
+
+ struct Y_PACKED TFrameFooter {
+ TCheckSum CheckSum;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // TBlock
+ ///////////////////////////////////////////////////////////////////////////////
+ struct TBlock: public TStringBuf {
+ template <typename T>
+ TBlock(T&& t)
+ : TStringBuf(t.data(), t.size())
+ {
+ Y_ENSURE(t.data() != nullptr);
+ }
+
+ char* data() noexcept {
+ return const_cast<char*>(TStringBuf::data());
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // XXHASH
+ ///////////////////////////////////////////////////////////////////////////////
+ struct TXxHash32 {
+ static TCheckSum Calc(TBlock in) {
+ static const ui32 SEED = 0x1337c0de;
+ return XXH32(in.data(), in.size(), SEED);
+ }
+
+ static bool Check(TBlock in, TCheckSum checksum) {
+ return Calc(in) == checksum;
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // Adler32
+ ///////////////////////////////////////////////////////////////////////////////
+ struct TAdler32 {
+ static TCheckSum Calc(TBlock in) {
+ return adler32(1L, reinterpret_cast<const Bytef*>(in.data()), in.size());
+ }
+
+ static bool Check(TBlock in, TCheckSum checksum) {
+ return Calc(in) == checksum;
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // LZ4
+ ///////////////////////////////////////////////////////////////////////////////
+ struct TLz4Codec {
+ static size_t MaxCompressedLength(size_t in) {
+ int result = LZ4_compressBound(static_cast<int>(in));
+ Y_ENSURE(result != 0, "lz4 input size is too large");
+ return result;
+ }
+
+ static size_t Compress(TBlock in, TBlock out) {
+ int rc = LZ4_compress_default(
+ in.data(),
+ out.data(),
+ SafeIntegerCast<int>(in.size()),
+ SafeIntegerCast<int>(out.size()));
+ Y_ENSURE(rc != 0, "lz4 compression failed");
+ return rc;
+ }
+
+ static void Decompress(TBlock in, TBlock out) {
+ int rc = LZ4_decompress_safe(
+ in.data(),
+ out.data(),
+ SafeIntegerCast<int>(in.size()),
+ SafeIntegerCast<int>(out.size()));
+ Y_ENSURE(rc >= 0, "the lz4 stream is detected malformed");
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // ZSTD
+ ///////////////////////////////////////////////////////////////////////////////
+ struct TZstdCodec {
+ static const int LEVEL = 11;
+
+ static size_t MaxCompressedLength(size_t in) {
+ return ZSTD_compressBound(in);
+ }
+
+ static size_t Compress(TBlock in, TBlock out) {
+ size_t rc = ZSTD_compress(out.data(), out.size(), in.data(), in.size(), LEVEL);
+ if (Y_UNLIKELY(ZSTD_isError(rc))) {
+ ythrow yexception() << TStringBuf("zstd compression failed: ")
+ << ZSTD_getErrorName(rc);
+ }
+ return rc;
+ }
+
+ static void Decompress(TBlock in, TBlock out) {
+ size_t rc = ZSTD_decompress(out.data(), out.size(), in.data(), in.size());
+ if (Y_UNLIKELY(ZSTD_isError(rc))) {
+ ythrow yexception() << TStringBuf("zstd decompression failed: ")
+ << ZSTD_getErrorName(rc);
+ }
+ Y_ENSURE(rc == out.size(), "zstd decompressed wrong size");
+ }
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // ZLIB
+ ///////////////////////////////////////////////////////////////////////////////
+ struct TZlibCodec {
+ static const int LEVEL = 6;
+
+ static size_t MaxCompressedLength(size_t in) {
+ return compressBound(in);
+ }
+
+ static size_t Compress(TBlock in, TBlock out) {
+ uLong ret = out.size();
+ int rc = compress2(
+ reinterpret_cast<Bytef*>(out.data()),
+ &ret,
+ reinterpret_cast<const Bytef*>(in.data()),
+ in.size(),
+ LEVEL);
+ Y_ENSURE(rc == Z_OK, "zlib compression failed");
+ return ret;
+ }
+
+ static void Decompress(TBlock in, TBlock out) {
+ uLong ret = out.size();
+ int rc = uncompress(
+ reinterpret_cast<Bytef*>(out.data()),
+ &ret,
+ reinterpret_cast<const Bytef*>(in.data()),
+ in.size());
+ Y_ENSURE(rc == Z_OK, "zlib decompression failed");
+ Y_ENSURE(ret == out.size(), "zlib decompressed wrong size");
+ }
+ };
+
+ //
+ // Framed streams use next frame structure:
+ //
+ // +-----------------+-------------------+============+------------------+
+ // | compressed size | uncompressed size | data | check sum |
+ // +-----------------+-------------------+============+------------------+
+ // 4 bytes 4 bytes var len 4 bytes
+ //
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // TFramedInputStream
+ ///////////////////////////////////////////////////////////////////////////////
+ template <typename TCodecAlg, typename TCheckSumAlg>
+ class TFramedDecompressStream final: public IWalkInput {
+ public:
+ explicit TFramedDecompressStream(IInputStream* in)
+ : In_(in)
+ {
+ }
+
+ private:
+ size_t DoUnboundedNext(const void** ptr) override {
+ if (!In_) {
+ return 0;
+ }
+
+ TFrameHeader header;
+ In_->LoadOrFail(&header, sizeof(header));
+
+ if (header.CompressedSize == 0) {
+ In_ = nullptr;
+ return 0;
+ }
+
+ Y_ENSURE(header.CompressedSize <= COMPRESSED_FRAME_SIZE_LIMIT, "Compressed frame size is limited to "
+ << HumanReadableSize(COMPRESSED_FRAME_SIZE_LIMIT, SF_BYTES)
+ << " but is " << HumanReadableSize(header.CompressedSize, SF_BYTES));
+
+ Y_ENSURE(header.UncompressedSize <= UNCOMPRESSED_FRAME_SIZE_LIMIT, "Uncompressed frame size is limited to "
+ << HumanReadableSize(UNCOMPRESSED_FRAME_SIZE_LIMIT, SF_BYTES)
+ << " but is " << HumanReadableSize(header.UncompressedSize, SF_BYTES));
+
+ Compressed_.Resize(header.CompressedSize);
+ In_->LoadOrFail(Compressed_.Data(), header.CompressedSize);
+
+ TFrameFooter footer;
+ In_->LoadOrFail(&footer, sizeof(footer));
+ Y_ENSURE(TCheckSumAlg::Check(Compressed_, footer.CheckSum),
+ "corrupted stream: check sum mismatch");
+
+ Uncompressed_.Resize(header.UncompressedSize);
+ TCodecAlg::Decompress(Compressed_, Uncompressed_);
+
+ *ptr = Uncompressed_.Data();
+ return Uncompressed_.Size();
+ }
+
+ private:
+ IInputStream* In_;
+ TBuffer Compressed_;
+ TBuffer Uncompressed_;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // TFramedOutputStream
+ ///////////////////////////////////////////////////////////////////////////////
+ template <typename TCodecAlg, typename TCheckSumAlg>
+ class TFramedCompressStream final: public IFramedCompressStream {
+ public:
+ explicit TFramedCompressStream(IOutputStream* out)
+ : Out_(out)
+ , Uncompressed_(DEFAULT_FRAME_LEN)
+ {
+ }
+
+ ~TFramedCompressStream() override {
+ try {
+ Finish();
+ } catch (...) {
+ }
+ }
+
+ private:
+ void DoWrite(const void* buf, size_t len) override {
+ const char* in = static_cast<const char*>(buf);
+
+ while (len != 0) {
+ const size_t avail = Uncompressed_.Avail();
+ if (len < avail) {
+ Uncompressed_.Append(in, len);
+ return;
+ }
+
+ Uncompressed_.Append(in, avail);
+ Y_ASSERT(Uncompressed_.Avail() == 0);
+
+ in += avail;
+ len -= avail;
+
+ WriteCompressedFrame();
+ }
+ }
+
+ void FlushWithoutEmptyFrame() override {
+ if (Out_ && !Uncompressed_.Empty()) {
+ WriteCompressedFrame();
+ }
+ }
+
+ void FinishAndWriteEmptyFrame() override {
+ if (Out_) {
+ Y_DEFER {
+ Out_ = nullptr;
+ };
+
+ if (!Uncompressed_.Empty()) {
+ WriteCompressedFrame();
+ }
+
+ WriteEmptyFrame();
+ }
+ }
+
+ void DoFlush() override {
+ FlushWithoutEmptyFrame();
+ }
+
+ void DoFinish() override {
+ FinishAndWriteEmptyFrame();
+ }
+
+ void WriteCompressedFrame() {
+ static const auto framePayload = sizeof(TFrameHeader) + sizeof(TFrameFooter);
+ const auto maxFrameSize = ui64(TCodecAlg::MaxCompressedLength(Uncompressed_.Size())) + framePayload;
+ Y_ENSURE(maxFrameSize <= FRAME_SIZE_LIMIT, "Frame size in encoder is limited to "
+ << HumanReadableSize(FRAME_SIZE_LIMIT, SF_BYTES)
+ << " but is " << HumanReadableSize(maxFrameSize, SF_BYTES));
+
+ Frame_.Resize(maxFrameSize);
+
+ // compress
+ TBlock compressedBlock = Frame_;
+ compressedBlock.Skip(sizeof(TFrameHeader));
+ compressedBlock.Trunc(TCodecAlg::Compress(Uncompressed_, compressedBlock));
+
+ // add header
+ auto header = reinterpret_cast<TFrameHeader*>(Frame_.Data());
+ header->CompressedSize = SafeIntegerCast<TCompressedSize>(compressedBlock.size());
+ header->UncompressedSize = SafeIntegerCast<TUncompressedSize>(Uncompressed_.Size());
+
+ // add footer
+ auto footer = reinterpret_cast<TFrameFooter*>(
+ Frame_.Data() + sizeof(TFrameHeader) + header->CompressedSize);
+ footer->CheckSum = TCheckSumAlg::Calc(compressedBlock);
+
+ // write
+ Out_->Write(Frame_.Data(), header->CompressedSize + framePayload);
+ Uncompressed_.Clear();
+ }
+
+ void WriteEmptyFrame() {
+ static const auto framePayload = sizeof(TFrameHeader) + sizeof(TFrameFooter);
+ char buf[framePayload] = {0};
+ Out_->Write(buf, sizeof(buf));
+ }
+
+ private:
+ IOutputStream* Out_;
+ TBuffer Uncompressed_;
+ TBuffer Frame_;
+ };
+
+ }
+
+ THolder<IInputStream> CompressedInput(IInputStream* in, ECompression alg) {
+ switch (alg) {
+ case ECompression::IDENTITY:
+ return nullptr;
+ case ECompression::ZLIB:
+ return MakeHolder<TFramedDecompressStream<TZlibCodec, TAdler32>>(in);
+ case ECompression::ZSTD:
+ return MakeHolder<TFramedDecompressStream<TZstdCodec, TXxHash32>>(in);
+ case ECompression::LZ4:
+ return MakeHolder<TFramedDecompressStream<TLz4Codec, TXxHash32>>(in);
+ case ECompression::UNKNOWN:
+ return nullptr;
+ }
+ Y_FAIL("invalid compression algorithm");
+ }
+
+ THolder<IFramedCompressStream> CompressedOutput(IOutputStream* out, ECompression alg) {
+ switch (alg) {
+ case ECompression::IDENTITY:
+ return nullptr;
+ case ECompression::ZLIB:
+ return MakeHolder<TFramedCompressStream<TZlibCodec, TAdler32>>(out);
+ case ECompression::ZSTD:
+ return MakeHolder<TFramedCompressStream<TZstdCodec, TXxHash32>>(out);
+ case ECompression::LZ4:
+ return MakeHolder<TFramedCompressStream<TLz4Codec, TXxHash32>>(out);
+ case ECompression::UNKNOWN:
+ return nullptr;
+ }
+ Y_FAIL("invalid compression algorithm");
+ }
+
+}
diff --git a/library/cpp/monlib/encode/spack/compression.h b/library/cpp/monlib/encode/spack/compression.h
new file mode 100644
index 0000000000..f74d8b424e
--- /dev/null
+++ b/library/cpp/monlib/encode/spack/compression.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "spack_v1.h"
+
+#include <util/stream/input.h>
+#include <util/stream/output.h>
+
+namespace NMonitoring {
+
+class IFramedCompressStream: public IOutputStream {
+public:
+ virtual void FlushWithoutEmptyFrame() = 0;
+ virtual void FinishAndWriteEmptyFrame() = 0;
+};
+
+THolder<IInputStream> CompressedInput(IInputStream* in, ECompression alg);
+THolder<IFramedCompressStream> CompressedOutput(IOutputStream* out, ECompression alg);
+
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/encode/spack/fuzz/main.cpp b/library/cpp/monlib/encode/spack/fuzz/main.cpp
new file mode 100644
index 0000000000..6a14afe71c
--- /dev/null
+++ b/library/cpp/monlib/encode/spack/fuzz/main.cpp
@@ -0,0 +1,20 @@
+#include <library/cpp/monlib/encode/spack/spack_v1.h>
+#include <library/cpp/monlib/encode/fake/fake.h>
+
+#include <util/stream/mem.h>
+
+
+extern "C" int LLVMFuzzerTestOneInput(const ui8* data, size_t size) {
+ using namespace NMonitoring;
+
+ TMemoryInput min{data, size};
+
+ auto encoder = EncoderFake();
+
+ try {
+ DecodeSpackV1(&min, encoder.Get());
+ } catch (...) {
+ }
+
+ return 0;
+}
diff --git a/library/cpp/monlib/encode/spack/fuzz/ya.make b/library/cpp/monlib/encode/spack/fuzz/ya.make
new file mode 100644
index 0000000000..99b63eadd5
--- /dev/null
+++ b/library/cpp/monlib/encode/spack/fuzz/ya.make
@@ -0,0 +1,21 @@
+FUZZ()
+
+OWNER(
+ g:solomon
+ msherbakov
+)
+
+FUZZ_OPTS(-rss_limit_mb=1024)
+
+SIZE(MEDIUM)
+
+PEERDIR(
+ library/cpp/monlib/encode/spack
+ library/cpp/monlib/encode/fake
+)
+
+SRCS(
+ main.cpp
+)
+
+END()
diff --git a/library/cpp/monlib/encode/spack/spack_v1.h b/library/cpp/monlib/encode/spack/spack_v1.h
new file mode 100644
index 0000000000..cf1c9417b9
--- /dev/null
+++ b/library/cpp/monlib/encode/spack/spack_v1.h
@@ -0,0 +1,115 @@
+#pragma once
+
+#include <library/cpp/monlib/encode/encoder.h>
+#include <library/cpp/monlib/encode/format.h>
+#include <library/cpp/monlib/metrics/metric.h>
+
+#include <util/generic/yexception.h>
+
+//
+// format specification available here:
+// https://wiki.yandex-team.ru/solomon/api/dataformat/spackv1/
+//
+
+class IInputStream;
+class IOutputStream;
+
+namespace NMonitoring {
+ class TSpackDecodeError: public yexception {
+ };
+
+ constexpr auto EncodeMetricType(EMetricType mt) noexcept {
+ return static_cast<std::underlying_type_t<EMetricType>>(mt);
+ }
+
+ EMetricType DecodeMetricType(ui8 byte);
+
+ [[nodiscard]]
+ bool TryDecodeMetricType(ui8 byte, EMetricType* result);
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // EValueType
+ ///////////////////////////////////////////////////////////////////////////////
+ enum class EValueType : ui8 {
+ NONE = 0x00,
+ ONE_WITHOUT_TS = 0x01,
+ ONE_WITH_TS = 0x02,
+ MANY_WITH_TS = 0x03,
+ };
+
+ constexpr auto EncodeValueType(EValueType vt) noexcept {
+ return static_cast<std::underlying_type_t<EValueType>>(vt);
+ }
+
+ EValueType DecodeValueType(ui8 byte);
+
+ [[nodiscard]]
+ bool TryDecodeValueType(ui8 byte, EValueType* result);
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // ETimePrecision
+ ///////////////////////////////////////////////////////////////////////////////
+ enum class ETimePrecision : ui8 {
+ SECONDS = 0x00,
+ MILLIS = 0x01,
+ };
+
+ constexpr auto EncodeTimePrecision(ETimePrecision tp) noexcept {
+ return static_cast<std::underlying_type_t<ETimePrecision>>(tp);
+ }
+
+ ETimePrecision DecodeTimePrecision(ui8 byte);
+
+ [[nodiscard]]
+ bool TryDecodeTimePrecision(ui8 byte, ETimePrecision* result);
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // ECompression
+ ///////////////////////////////////////////////////////////////////////////////
+ ui8 EncodeCompression(ECompression c) noexcept;
+
+ ECompression DecodeCompression(ui8 byte);
+
+ [[nodiscard]]
+ bool TryDecodeCompression(ui8 byte, ECompression* result);
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // TSpackHeader
+ ///////////////////////////////////////////////////////////////////////////////
+ struct Y_PACKED TSpackHeader {
+ ui16 Magic = 0x5053; // "SP"
+ ui16 Version; // MSB - major version, LSB - minor version
+ ui16 HeaderSize = sizeof(TSpackHeader);
+ ui8 TimePrecision;
+ ui8 Compression;
+ ui32 LabelNamesSize;
+ ui32 LabelValuesSize;
+ ui32 MetricCount;
+ ui32 PointsCount;
+ // add new fields here
+ };
+
+ enum ESpackV1Version: ui16 {
+ SV1_00 = 0x0100,
+ SV1_01 = 0x0101,
+ SV1_02 = 0x0102
+ };
+
+ IMetricEncoderPtr EncoderSpackV1(
+ IOutputStream* out,
+ ETimePrecision timePrecision,
+ ECompression compression,
+ EMetricsMergingMode mergingMode = EMetricsMergingMode::DEFAULT
+ );
+
+ IMetricEncoderPtr EncoderSpackV12(
+ IOutputStream* out,
+ ETimePrecision timePrecision,
+ ECompression compression,
+ EMetricsMergingMode mergingMode = EMetricsMergingMode::DEFAULT,
+ TStringBuf metricNameLabel = "name"
+ );
+
+ void DecodeSpackV1(IInputStream* in, IMetricConsumer* c, TStringBuf metricNameLabel = "name");
+
+}
diff --git a/library/cpp/monlib/encode/spack/spack_v1_decoder.cpp b/library/cpp/monlib/encode/spack/spack_v1_decoder.cpp
new file mode 100644
index 0000000000..1f445fc80d
--- /dev/null
+++ b/library/cpp/monlib/encode/spack/spack_v1_decoder.cpp
@@ -0,0 +1,458 @@
+#include "spack_v1.h"
+#include "varint.h"
+#include "compression.h"
+
+#include <library/cpp/monlib/encode/buffered/string_pool.h>
+#include <library/cpp/monlib/exception/exception.h>
+#include <library/cpp/monlib/metrics/histogram_collector.h>
+#include <library/cpp/monlib/metrics/metric.h>
+
+#include <util/generic/yexception.h>
+#include <util/generic/buffer.h>
+#include <util/generic/size_literals.h>
+#include <util/stream/format.h>
+
+#ifndef _little_endian_
+#error Unsupported platform
+#endif
+
+namespace NMonitoring {
+ namespace {
+#define DECODE_ENSURE(COND, ...) MONLIB_ENSURE_EX(COND, TSpackDecodeError() << __VA_ARGS__)
+
+ constexpr ui64 LABEL_SIZE_LIMIT = 128_MB;
+
+ ///////////////////////////////////////////////////////////////////////
+ // TDecoderSpackV1
+ ///////////////////////////////////////////////////////////////////////
+ class TDecoderSpackV1 {
+ public:
+ TDecoderSpackV1(IInputStream* in, TStringBuf metricNameLabel)
+ : In_(in)
+ , MetricNameLabel_(metricNameLabel)
+ {
+ }
+
+ void Decode(IMetricConsumer* c) {
+ c->OnStreamBegin();
+
+ // (1) read header
+ size_t readBytes = In_->Read(&Header_, sizeof(Header_));
+ DECODE_ENSURE(readBytes == sizeof(Header_), "not enough data in input stream to read header");
+
+ ui8 version = ((Header_.Version >> 8) & 0xff);
+ DECODE_ENSURE(version == 1, "versions mismatch (expected: 1, got: " << +version << ')');
+
+ DECODE_ENSURE(Header_.HeaderSize >= sizeof(Header_), "invalid header size");
+ if (size_t skipBytes = Header_.HeaderSize - sizeof(Header_)) {
+ DECODE_ENSURE(In_->Skip(skipBytes) == skipBytes, "input stream unexpectedly ended");
+ }
+
+ if (Header_.MetricCount == 0) {
+ // emulate empty stream
+ c->OnStreamEnd();
+ return;
+ }
+
+ // if compression enabled all below reads must go throught decompressor
+ auto compressedIn = CompressedInput(In_, DecodeCompression(Header_.Compression));
+ if (compressedIn) {
+ In_ = compressedIn.Get();
+ }
+
+ TimePrecision_ = DecodeTimePrecision(Header_.TimePrecision);
+
+ const ui64 labelSizeTotal = ui64(Header_.LabelNamesSize) + Header_.LabelValuesSize;
+
+ DECODE_ENSURE(labelSizeTotal <= LABEL_SIZE_LIMIT, "Label names & values size of " << HumanReadableSize(labelSizeTotal, SF_BYTES)
+ << " exceeds the limit which is " << HumanReadableSize(LABEL_SIZE_LIMIT, SF_BYTES));
+
+ // (2) read string pools
+ TVector<char> namesBuf(Header_.LabelNamesSize);
+ readBytes = In_->Load(namesBuf.data(), namesBuf.size());
+ DECODE_ENSURE(readBytes == Header_.LabelNamesSize, "not enough data to read label names pool");
+ TStringPool labelNames(namesBuf.data(), namesBuf.size());
+
+ TVector<char> valuesBuf(Header_.LabelValuesSize);
+ readBytes = In_->Load(valuesBuf.data(), valuesBuf.size());
+ DECODE_ENSURE(readBytes == Header_.LabelValuesSize, "not enough data to read label values pool");
+ TStringPool labelValues(valuesBuf.data(), valuesBuf.size());
+
+ // (3) read common time
+ c->OnCommonTime(ReadTime());
+
+ // (4) read common labels
+ if (ui32 commonLabelsCount = ReadVarint()) {
+ c->OnLabelsBegin();
+ ReadLabels(labelNames, labelValues, commonLabelsCount, c);
+ c->OnLabelsEnd();
+ }
+
+ // (5) read metrics
+ ReadMetrics(labelNames, labelValues, c);
+ c->OnStreamEnd();
+ }
+
+ private:
+ void ReadMetrics(
+ const TStringPool& labelNames,
+ const TStringPool& labelValues,
+ IMetricConsumer* c)
+ {
+ for (ui32 i = 0; i < Header_.MetricCount; i++) {
+ // (5.1) types byte
+ ui8 typesByte = ReadFixed<ui8>();
+ EMetricType metricType = DecodeMetricType(typesByte >> 2);
+ EValueType valueType = DecodeValueType(typesByte & 0x03);
+
+ c->OnMetricBegin(metricType);
+
+ // TODO: use it
+ ReadFixed<ui8>(); // skip flags byte
+
+ auto metricNameValueIndex = std::numeric_limits<ui32>::max();
+ if (Header_.Version >= SV1_02) {
+ metricNameValueIndex = ReadVarint();
+ }
+
+ // (5.2) labels
+ ui32 labelsCount = ReadVarint();
+ DECODE_ENSURE(Header_.Version >= SV1_02 || labelsCount > 0, "metric #" << i << " has no labels");
+ c->OnLabelsBegin();
+ if (Header_.Version >= SV1_02) {
+ c->OnLabel(MetricNameLabel_, labelValues.Get(metricNameValueIndex));
+ }
+ ReadLabels(labelNames, labelValues, labelsCount, c);
+ c->OnLabelsEnd();
+
+ // (5.3) values
+ switch (valueType) {
+ case EValueType::NONE:
+ break;
+ case EValueType::ONE_WITHOUT_TS:
+ ReadValue(metricType, TInstant::Zero(), c);
+ break;
+ case EValueType::ONE_WITH_TS: {
+ TInstant time = ReadTime();
+ ReadValue(metricType, time, c);
+ break;
+ }
+ case EValueType::MANY_WITH_TS: {
+ ui32 pointsCount = ReadVarint();
+ for (ui32 i = 0; i < pointsCount; i++) {
+ TInstant time = ReadTime();
+ ReadValue(metricType, time, c);
+ }
+ break;
+ }
+ }
+
+ c->OnMetricEnd();
+ }
+ }
+
+ void ReadValue(EMetricType metricType, TInstant time, IMetricConsumer* c) {
+ switch (metricType) {
+ case EMetricType::GAUGE:
+ c->OnDouble(time, ReadFixed<double>());
+ break;
+
+ case EMetricType::IGAUGE:
+ c->OnInt64(time, ReadFixed<i64>());
+ break;
+
+ case EMetricType::COUNTER:
+ case EMetricType::RATE:
+ c->OnUint64(time, ReadFixed<ui64>());
+ break;
+
+ case EMetricType::DSUMMARY:
+ c->OnSummaryDouble(time, ReadSummaryDouble());
+ break;
+
+ case EMetricType::HIST:
+ case EMetricType::HIST_RATE:
+ c->OnHistogram(time, ReadHistogram());
+ break;
+
+ case EMetricType::LOGHIST:
+ c->OnLogHistogram(time, ReadLogHistogram());
+ break;
+
+ default:
+ throw TSpackDecodeError() << "Unsupported metric type: " << metricType;
+ }
+ }
+
+ ISummaryDoubleSnapshotPtr ReadSummaryDouble() {
+ ui64 count = ReadFixed<ui64>();
+ double sum = ReadFixed<double>();
+ double min = ReadFixed<double>();
+ double max = ReadFixed<double>();
+ double last = ReadFixed<double>();
+ return MakeIntrusive<TSummaryDoubleSnapshot>(sum, min, max, last, count);
+ }
+
+ TLogHistogramSnapshotPtr ReadLogHistogram() {
+ double base = ReadFixed<double>();
+ ui64 zerosCount = ReadFixed<ui64>();
+ int startPower = static_cast<int>(ReadVarint());
+ ui32 count = ReadVarint();
+ // see https://a.yandex-team.ru/arc/trunk/arcadia/infra/yasm/stockpile_client/points.cpp?rev=r8593154#L31
+ // and https://a.yandex-team.ru/arc/trunk/arcadia/infra/yasm/common/points/hgram/normal/normal.h?rev=r8268697#L9
+ // TODO: share this constant value
+ Y_ENSURE(count <= 100u, "more than 100 buckets in log histogram: " << count);
+ TVector<double> buckets;
+ buckets.reserve(count);
+ for (ui32 i = 0; i < count; ++i) {
+ buckets.emplace_back(ReadFixed<double>());
+ }
+ return MakeIntrusive<TLogHistogramSnapshot>(base, zerosCount, startPower, std::move(buckets));
+ }
+
+ IHistogramSnapshotPtr ReadHistogram() {
+ ui32 bucketsCount = ReadVarint();
+ auto s = TExplicitHistogramSnapshot::New(bucketsCount);
+
+ if (SV1_00 == Header_.Version) { // v1.0
+ for (ui32 i = 0; i < bucketsCount; i++) {
+ i64 bound = ReadFixed<i64>();
+ double doubleBound = (bound != Max<i64>())
+ ? static_cast<double>(bound)
+ : Max<double>();
+
+ (*s)[i].first = doubleBound;
+ }
+ } else {
+ for (ui32 i = 0; i < bucketsCount; i++) {
+ double doubleBound = ReadFixed<double>();
+ (*s)[i].first = doubleBound;
+ }
+ }
+
+
+ // values
+ for (ui32 i = 0; i < bucketsCount; i++) {
+ (*s)[i].second = ReadFixed<ui64>();
+ }
+ return s;
+ }
+
+ void ReadLabels(
+ const TStringPool& labelNames,
+ const TStringPool& labelValues,
+ ui32 count,
+ IMetricConsumer* c)
+ {
+ for (ui32 i = 0; i < count; i++) {
+ auto nameIdx = ReadVarint();
+ auto valueIdx = ReadVarint();
+ c->OnLabel(labelNames.Get(nameIdx), labelValues.Get(valueIdx));
+ }
+ }
+
+ TInstant ReadTime() {
+ switch (TimePrecision_) {
+ case ETimePrecision::SECONDS:
+ return TInstant::Seconds(ReadFixed<ui32>());
+ case ETimePrecision::MILLIS:
+ return TInstant::MilliSeconds(ReadFixed<ui64>());
+ }
+ Y_FAIL("invalid time precision");
+ }
+
+ template <typename T>
+ inline T ReadFixed() {
+ T value;
+ size_t readBytes = In_->Load(&value, sizeof(T));
+ DECODE_ENSURE(readBytes == sizeof(T), "no enough data to read " << TypeName<T>());
+ return value;
+ }
+
+ inline ui32 ReadVarint() {
+ return ReadVarUInt32(In_);
+ }
+
+ private:
+ IInputStream* In_;
+ TString MetricNameLabel_;
+ ETimePrecision TimePrecision_;
+ TSpackHeader Header_;
+ }; // class TDecoderSpackV1
+
+#undef DECODE_ENSURE
+ } // namespace
+
+ EValueType DecodeValueType(ui8 byte) {
+ EValueType result;
+ if (!TryDecodeValueType(byte, &result)) {
+ throw TSpackDecodeError() << "unknown value type: " << byte;
+ }
+ return result;
+ }
+
+ bool TryDecodeValueType(ui8 byte, EValueType* result) {
+ if (byte == EncodeValueType(EValueType::NONE)) {
+ if (result) {
+ *result = EValueType::NONE;
+ }
+ return true;
+ } else if (byte == EncodeValueType(EValueType::ONE_WITHOUT_TS)) {
+ if (result) {
+ *result = EValueType::ONE_WITHOUT_TS;
+ }
+ return true;
+ } else if (byte == EncodeValueType(EValueType::ONE_WITH_TS)) {
+ if (result) {
+ *result = EValueType::ONE_WITH_TS;
+ }
+ return true;
+ } else if (byte == EncodeValueType(EValueType::MANY_WITH_TS)) {
+ if (result) {
+ *result = EValueType::MANY_WITH_TS;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ ETimePrecision DecodeTimePrecision(ui8 byte) {
+ ETimePrecision result;
+ if (!TryDecodeTimePrecision(byte, &result)) {
+ throw TSpackDecodeError() << "unknown time precision: " << byte;
+ }
+ return result;
+ }
+
+ bool TryDecodeTimePrecision(ui8 byte, ETimePrecision* result) {
+ if (byte == EncodeTimePrecision(ETimePrecision::SECONDS)) {
+ if (result) {
+ *result = ETimePrecision::SECONDS;
+ }
+ return true;
+ } else if (byte == EncodeTimePrecision(ETimePrecision::MILLIS)) {
+ if (result) {
+ *result = ETimePrecision::MILLIS;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ EMetricType DecodeMetricType(ui8 byte) {
+ EMetricType result;
+ if (!TryDecodeMetricType(byte, &result)) {
+ throw TSpackDecodeError() << "unknown metric type: " << byte;
+ }
+ return result;
+ }
+
+ bool TryDecodeMetricType(ui8 byte, EMetricType* result) {
+ if (byte == EncodeMetricType(EMetricType::GAUGE)) {
+ if (result) {
+ *result = EMetricType::GAUGE;
+ }
+ return true;
+ } else if (byte == EncodeMetricType(EMetricType::COUNTER)) {
+ if (result) {
+ *result = EMetricType::COUNTER;
+ }
+ return true;
+ } else if (byte == EncodeMetricType(EMetricType::RATE)) {
+ if (result) {
+ *result = EMetricType::RATE;
+ }
+ return true;
+ } else if (byte == EncodeMetricType(EMetricType::IGAUGE)) {
+ if (result) {
+ *result = EMetricType::IGAUGE;
+ }
+ return true;
+ } else if (byte == EncodeMetricType(EMetricType::HIST)) {
+ if (result) {
+ *result = EMetricType::HIST;
+ }
+ return true;
+ } else if (byte == EncodeMetricType(EMetricType::HIST_RATE)) {
+ if (result) {
+ *result = EMetricType::HIST_RATE;
+ }
+ return true;
+ } else if (byte == EncodeMetricType(EMetricType::DSUMMARY)) {
+ if (result) {
+ *result = EMetricType::DSUMMARY;
+ }
+ return true;
+ } else if (byte == EncodeMetricType(EMetricType::LOGHIST)) {
+ if (result) {
+ *result = EMetricType::LOGHIST;
+ }
+ return true;
+ } else if (byte == EncodeMetricType(EMetricType::UNKNOWN)) {
+ if (result) {
+ *result = EMetricType::UNKNOWN;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ ui8 EncodeCompression(ECompression c) noexcept {
+ switch (c) {
+ case ECompression::IDENTITY:
+ return 0x00;
+ case ECompression::ZLIB:
+ return 0x01;
+ case ECompression::ZSTD:
+ return 0x02;
+ case ECompression::LZ4:
+ return 0x03;
+ case ECompression::UNKNOWN:
+ return Max<ui8>();
+ }
+ Y_FAIL(); // for GCC
+ }
+
+ ECompression DecodeCompression(ui8 byte) {
+ ECompression result;
+ if (!TryDecodeCompression(byte, &result)) {
+ throw TSpackDecodeError() << "unknown compression alg: " << byte;
+ }
+ return result;
+ }
+
+ bool TryDecodeCompression(ui8 byte, ECompression* result) {
+ if (byte == EncodeCompression(ECompression::IDENTITY)) {
+ if (result) {
+ *result = ECompression::IDENTITY;
+ }
+ return true;
+ } else if (byte == EncodeCompression(ECompression::ZLIB)) {
+ if (result) {
+ *result = ECompression::ZLIB;
+ }
+ return true;
+ } else if (byte == EncodeCompression(ECompression::ZSTD)) {
+ if (result) {
+ *result = ECompression::ZSTD;
+ }
+ return true;
+ } else if (byte == EncodeCompression(ECompression::LZ4)) {
+ if (result) {
+ *result = ECompression::LZ4;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ void DecodeSpackV1(IInputStream* in, IMetricConsumer* c, TStringBuf metricNameLabel) {
+ TDecoderSpackV1 decoder(in, metricNameLabel);
+ decoder.Decode(c);
+ }
+
+}
diff --git a/library/cpp/monlib/encode/spack/spack_v1_encoder.cpp b/library/cpp/monlib/encode/spack/spack_v1_encoder.cpp
new file mode 100644
index 0000000000..a2b0bb5f50
--- /dev/null
+++ b/library/cpp/monlib/encode/spack/spack_v1_encoder.cpp
@@ -0,0 +1,318 @@
+#include "spack_v1.h"
+#include "compression.h"
+#include "varint.h"
+
+#include <library/cpp/monlib/encode/buffered/buffered_encoder_base.h>
+
+#include <util/generic/cast.h>
+#include <util/datetime/base.h>
+#include <util/string/builder.h>
+
+#ifndef _little_endian_
+#error Unsupported platform
+#endif
+
+namespace NMonitoring {
+ namespace {
+ ///////////////////////////////////////////////////////////////////////
+ // TEncoderSpackV1
+ ///////////////////////////////////////////////////////////////////////
+ class TEncoderSpackV1 final: public TBufferedEncoderBase {
+ public:
+ TEncoderSpackV1(
+ IOutputStream* out,
+ ETimePrecision timePrecision,
+ ECompression compression,
+ EMetricsMergingMode mergingMode,
+ ESpackV1Version version,
+ TStringBuf metricNameLabel
+ )
+ : Out_(out)
+ , TimePrecision_(timePrecision)
+ , Compression_(compression)
+ , Version_(version)
+ , MetricName_(Version_ >= SV1_02 ? LabelNamesPool_.PutIfAbsent(metricNameLabel) : nullptr)
+ {
+ MetricsMergingMode_ = mergingMode;
+
+ LabelNamesPool_.SetSorted(true);
+ LabelValuesPool_.SetSorted(true);
+ }
+
+ ~TEncoderSpackV1() override {
+ Close();
+ }
+
+ private:
+ void OnDouble(TInstant time, double value) override {
+ TBufferedEncoderBase::OnDouble(time, value);
+ }
+
+ void OnInt64(TInstant time, i64 value) override {
+ TBufferedEncoderBase::OnInt64(time, value);
+ }
+
+ void OnUint64(TInstant time, ui64 value) override {
+ TBufferedEncoderBase::OnUint64(time, value);
+ }
+
+ void OnHistogram(TInstant time, IHistogramSnapshotPtr snapshot) override {
+ TBufferedEncoderBase::OnHistogram(time, snapshot);
+ }
+
+ void OnSummaryDouble(TInstant time, ISummaryDoubleSnapshotPtr snapshot) override {
+ TBufferedEncoderBase::OnSummaryDouble(time, snapshot);
+ }
+
+ void OnLogHistogram(TInstant time, TLogHistogramSnapshotPtr snapshot) override {
+ TBufferedEncoderBase::OnLogHistogram(time, snapshot);
+ }
+
+ void Close() override {
+ if (Closed_) {
+ return;
+ }
+ Closed_ = true;
+
+ LabelNamesPool_.Build();
+ LabelValuesPool_.Build();
+
+ // Sort all points uniquely by ts -- the size can decrease
+ ui64 pointsCount = 0;
+ for (TMetric& metric : Metrics_) {
+ if (metric.TimeSeries.Size() > 1) {
+ metric.TimeSeries.SortByTs();
+ }
+
+ pointsCount += metric.TimeSeries.Size();
+ }
+
+ // (1) write header
+ TSpackHeader header;
+ header.Version = Version_;
+ header.TimePrecision = EncodeTimePrecision(TimePrecision_);
+ header.Compression = EncodeCompression(Compression_);
+ header.LabelNamesSize = static_cast<ui32>(
+ LabelNamesPool_.BytesSize() + LabelNamesPool_.Count());
+ header.LabelValuesSize = static_cast<ui32>(
+ LabelValuesPool_.BytesSize() + LabelValuesPool_.Count());
+ header.MetricCount = Metrics_.size();
+ header.PointsCount = pointsCount;
+ Out_->Write(&header, sizeof(header));
+
+ // if compression enabled all below writes must go throught compressor
+ auto compressedOut = CompressedOutput(Out_, Compression_);
+ if (compressedOut) {
+ Out_ = compressedOut.Get();
+ }
+
+ // (2) write string pools
+ auto strPoolWrite = [this](TStringBuf str, ui32, ui32) {
+ Out_->Write(str);
+ Out_->Write('\0');
+ };
+
+ LabelNamesPool_.ForEach(strPoolWrite);
+ LabelValuesPool_.ForEach(strPoolWrite);
+
+ // (3) write common time
+ WriteTime(CommonTime_);
+
+ // (4) write common labels' indexes
+ WriteLabels(CommonLabels_, nullptr);
+
+ // (5) write metrics
+ // metrics count already written in header
+ for (TMetric& metric : Metrics_) {
+ // (5.1) types byte
+ ui8 typesByte = PackTypes(metric);
+ Out_->Write(&typesByte, sizeof(typesByte));
+
+ // TODO: implement
+ ui8 flagsByte = 0x00;
+ Out_->Write(&flagsByte, sizeof(flagsByte));
+
+ // v1.2 format addition — metric name
+ if (Version_ >= SV1_02) {
+ const auto it = FindIf(metric.Labels, [&](const auto& l) {
+ return l.Key == MetricName_;
+ });
+ Y_ENSURE(it != metric.Labels.end(),
+ "metric name label '" << LabelNamesPool_.Get(MetricName_->Index) << "' not found, "
+ << "all metric labels '" << FormatLabels(metric.Labels) << "'");
+ WriteVarUInt32(Out_, it->Value->Index);
+ }
+
+ // (5.2) labels
+ WriteLabels(metric.Labels, MetricName_);
+
+ // (5.3) values
+ switch (metric.TimeSeries.Size()) {
+ case 0:
+ break;
+ case 1: {
+ const auto& point = metric.TimeSeries[0];
+ if (point.GetTime() != TInstant::Zero()) {
+ WriteTime(point.GetTime());
+ }
+ EMetricValueType valueType = metric.TimeSeries.GetValueType();
+ WriteValue(metric.MetricType, valueType, point.GetValue());
+ break;
+ }
+ default:
+ WriteVarUInt32(Out_, static_cast<ui32>(metric.TimeSeries.Size()));
+ const TMetricTimeSeries& ts = metric.TimeSeries;
+ EMetricType metricType = metric.MetricType;
+ ts.ForEach([this, metricType](TInstant time, EMetricValueType valueType, TMetricValue value) {
+ // workaround for GCC bug
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61636
+ this->WriteTime(time);
+ this->WriteValue(metricType, valueType, value);
+ });
+ break;
+ }
+ }
+ }
+
+ // store metric type and values type in one byte
+ ui8 PackTypes(const TMetric& metric) {
+ EValueType valueType;
+ if (metric.TimeSeries.Empty()) {
+ valueType = EValueType::NONE;
+ } else if (metric.TimeSeries.Size() == 1) {
+ TInstant time = metric.TimeSeries[0].GetTime();
+ valueType = (time == TInstant::Zero())
+ ? EValueType::ONE_WITHOUT_TS
+ : EValueType::ONE_WITH_TS;
+ } else {
+ valueType = EValueType::MANY_WITH_TS;
+ }
+ return (static_cast<ui8>(metric.MetricType) << 2) | static_cast<ui8>(valueType);
+ }
+
+ void WriteLabels(const TPooledLabels& labels, const TPooledStr* skipKey) {
+ WriteVarUInt32(Out_, static_cast<ui32>(skipKey ? labels.size() - 1 : labels.size()));
+ for (auto&& label : labels) {
+ if (label.Key == skipKey) {
+ continue;
+ }
+ WriteVarUInt32(Out_, label.Key->Index);
+ WriteVarUInt32(Out_, label.Value->Index);
+ }
+ }
+
+ void WriteValue(EMetricType metricType, EMetricValueType valueType, TMetricValue value) {
+ switch (metricType) {
+ case EMetricType::GAUGE:
+ WriteFixed(value.AsDouble(valueType));
+ break;
+
+ case EMetricType::IGAUGE:
+ WriteFixed(value.AsInt64(valueType));
+ break;
+
+ case EMetricType::COUNTER:
+ case EMetricType::RATE:
+ WriteFixed(value.AsUint64(valueType));
+ break;
+
+ case EMetricType::HIST:
+ case EMetricType::HIST_RATE:
+ WriteHistogram(*value.AsHistogram());
+ break;
+
+ case EMetricType::DSUMMARY:
+ WriteSummaryDouble(*value.AsSummaryDouble());
+ break;
+
+ case EMetricType::LOGHIST:
+ WriteLogHistogram(*value.AsLogHistogram());
+ break;
+
+ default:
+ ythrow yexception() << "unsupported metric type: " << metricType;
+ }
+ }
+
+ void WriteTime(TInstant instant) {
+ switch (TimePrecision_) {
+ case ETimePrecision::SECONDS: {
+ ui32 time = static_cast<ui32>(instant.Seconds());
+ Out_->Write(&time, sizeof(time));
+ break;
+ }
+ case ETimePrecision::MILLIS: {
+ ui64 time = static_cast<ui64>(instant.MilliSeconds());
+ Out_->Write(&time, sizeof(time));
+ }
+ }
+ }
+
+ template <typename T>
+ void WriteFixed(T value) {
+ Out_->Write(&value, sizeof(value));
+ }
+
+ void WriteHistogram(const IHistogramSnapshot& histogram) {
+ ui32 count = histogram.Count();
+ WriteVarUInt32(Out_, count);
+
+ for (ui32 i = 0; i < count; i++) {
+ double bound = histogram.UpperBound(i);
+ Out_->Write(&bound, sizeof(bound));
+ }
+ for (ui32 i = 0; i < count; i++) {
+ ui64 value = histogram.Value(i);
+ Out_->Write(&value, sizeof(value));
+ }
+ }
+
+ void WriteLogHistogram(const TLogHistogramSnapshot& logHist) {
+ WriteFixed(logHist.Base());
+ WriteFixed(logHist.ZerosCount());
+ WriteVarUInt32(Out_, static_cast<ui32>(logHist.StartPower()));
+ WriteVarUInt32(Out_, logHist.Count());
+ for (ui32 i = 0; i < logHist.Count(); ++i) {
+ WriteFixed(logHist.Bucket(i));
+ }
+ }
+
+ void WriteSummaryDouble(const ISummaryDoubleSnapshot& summary) {
+ WriteFixed(summary.GetCount());
+ WriteFixed(summary.GetSum());
+ WriteFixed(summary.GetMin());
+ WriteFixed(summary.GetMax());
+ WriteFixed(summary.GetLast());
+ }
+
+ private:
+ IOutputStream* Out_;
+ ETimePrecision TimePrecision_;
+ ECompression Compression_;
+ ESpackV1Version Version_;
+ const TPooledStr* MetricName_;
+ bool Closed_ = false;
+ };
+
+ }
+
+ IMetricEncoderPtr EncoderSpackV1(
+ IOutputStream* out,
+ ETimePrecision timePrecision,
+ ECompression compression,
+ EMetricsMergingMode mergingMode
+ ) {
+ return MakeHolder<TEncoderSpackV1>(out, timePrecision, compression, mergingMode, SV1_01, "");
+ }
+
+ IMetricEncoderPtr EncoderSpackV12(
+ IOutputStream* out,
+ ETimePrecision timePrecision,
+ ECompression compression,
+ EMetricsMergingMode mergingMode,
+ TStringBuf metricNameLabel
+ ) {
+ Y_ENSURE(!metricNameLabel.Empty(), "metricNameLabel can't be empty");
+ return MakeHolder<TEncoderSpackV1>(out, timePrecision, compression, mergingMode, SV1_02, metricNameLabel);
+ }
+}
diff --git a/library/cpp/monlib/encode/spack/spack_v1_ut.cpp b/library/cpp/monlib/encode/spack/spack_v1_ut.cpp
new file mode 100644
index 0000000000..fe778eb7e0
--- /dev/null
+++ b/library/cpp/monlib/encode/spack/spack_v1_ut.cpp
@@ -0,0 +1,845 @@
+#include "spack_v1.h"
+
+#include <library/cpp/monlib/encode/protobuf/protobuf.h>
+#include <library/cpp/monlib/metrics/labels.h>
+#include <library/cpp/monlib/metrics/metric.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/buffer.h>
+#include <util/stream/buffer.h>
+#include <util/string/hex.h>
+
+#include <utility>
+
+using namespace NMonitoring;
+
+#define UNIT_ASSERT_BINARY_EQUALS(a, b) \
+ do { \
+ auto size = Y_ARRAY_SIZE(b); \
+ if (Y_UNLIKELY(::memcmp(a, b, size) != 0)) { \
+ auto as = HexEncode(a, size); \
+ auto bs = HexEncode(b, size); \
+ UNIT_FAIL_IMPL("equal assertion failed " #a " == " #b, \
+ "\n actual: " << as << "\nexpected: " << bs); \
+ } \
+ } while (0)
+
+void AssertLabelEqual(const NProto::TLabel& l, TStringBuf name, TStringBuf value) {
+ UNIT_ASSERT_STRINGS_EQUAL(l.GetName(), name);
+ UNIT_ASSERT_STRINGS_EQUAL(l.GetValue(), value);
+}
+
+void AssertPointEqual(const NProto::TPoint& p, TInstant time, double value) {
+ UNIT_ASSERT_VALUES_EQUAL(p.GetTime(), time.MilliSeconds());
+ UNIT_ASSERT_EQUAL(p.GetValueCase(), NProto::TPoint::kFloat64);
+ UNIT_ASSERT_DOUBLES_EQUAL(p.GetFloat64(), value, std::numeric_limits<double>::epsilon());
+}
+
+void AssertPointEqual(const NProto::TPoint& p, TInstant time, ui64 value) {
+ UNIT_ASSERT_VALUES_EQUAL(p.GetTime(), time.MilliSeconds());
+ UNIT_ASSERT_EQUAL(p.GetValueCase(), NProto::TPoint::kUint64);
+ UNIT_ASSERT_VALUES_EQUAL(p.GetUint64(), value);
+}
+
+void AssertPointEqual(const NProto::TPoint& p, TInstant time, i64 value) {
+ UNIT_ASSERT_VALUES_EQUAL(p.GetTime(), time.MilliSeconds());
+ UNIT_ASSERT_EQUAL(p.GetValueCase(), NProto::TPoint::kInt64);
+ UNIT_ASSERT_VALUES_EQUAL(p.GetInt64(), value);
+}
+
+Y_UNIT_TEST_SUITE(TSpackTest) {
+ ui8 expectedHeader_v1_0[] = {
+ 0x53, 0x50, // magic "SP" (fixed ui16)
+ // minor, major
+ 0x00, 0x01, // version (fixed ui16)
+ 0x18, 0x00, // header size (fixed ui16)
+ 0x00, // time precision (fixed ui8)
+ 0x00, // compression algorithm (fixed ui8)
+ 0x0d, 0x00, 0x00, 0x00, // label names size (fixed ui32)
+ 0x40, 0x00, 0x00, 0x00, // labels values size (fixed ui32)
+ 0x08, 0x00, 0x00, 0x00, // metric count (fixed ui32)
+ 0x08, 0x00, 0x00, 0x00, // points count (fixed ui32)
+ };
+
+ ui8 expectedHeader[] = {
+ 0x53, 0x50, // magic "SP" (fixed ui16)
+ // minor, major
+ 0x01, 0x01, // version (fixed ui16)
+ 0x18, 0x00, // header size (fixed ui16)
+ 0x00, // time precision (fixed ui8)
+ 0x00, // compression algorithm (fixed ui8)
+ 0x0d, 0x00, 0x00, 0x00, // label names size (fixed ui32)
+ 0x40, 0x00, 0x00, 0x00, // labels values size (fixed ui32)
+ 0x08, 0x00, 0x00, 0x00, // metric count (fixed ui32)
+ 0x08, 0x00, 0x00, 0x00, // points count (fixed ui32)
+ };
+
+ ui8 expectedStringPools[] = {
+ 0x6e, 0x61, 0x6d, 0x65, 0x00, // "name\0"
+ 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x00, // "project\0"
+ 0x73, 0x6f, 0x6c, 0x6f, 0x6d, 0x6f, 0x6e, 0x00, // "solomon\0"
+ 0x71, 0x31, 0x00, // "q1\0"
+ 0x71, 0x32, 0x00, // "q2\0"
+ 0x71, 0x33, 0x00, // "q3\0"
+ 0x61, 0x6e, 0x73, 0x77, 0x65, 0x72, 0x00, // "answer\0"
+ 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, // "responseTimeMillis\0"
+ 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x6c, 0x6c,
+ 0x69, 0x73, 0x00,
+ 0x62, 0x79, 0x74, 0x65, 0x73, 0x00, // "bytes\0"
+ 0x74, 0x65, 0x6D, 0x70, 0x65, 0x72, 0x61, 0x74, // "temperature\0"
+ 0x75, 0x72, 0x65, 0x00,
+ 0x6d, 0x73, 0x00, // "ms\0"
+ };
+
+ ui8 expectedCommonTime[] = {
+ 0x00, 0x2f, 0x68, 0x59, // common time in seconds (fixed ui32)
+ };
+
+ ui8 expectedCommonLabels[] = {
+ 0x01, // common labels count (varint)
+ 0x01, // label name index (varint)
+ 0x00, // label value index (varint)
+ };
+
+ ui8 expectedMetric1[] = {
+ 0x0C, // types (RATE | NONE) (fixed ui8)
+ 0x00, // flags (fixed ui8)
+ 0x01, // metric labels count (varint)
+ 0x00, // label name index (varint)
+ 0x01, // label value index (varint)
+ };
+
+ ui8 expectedMetric2[] = {
+ 0x09, // types (COUNTER | ONE_WITHOUT_TS) (fixed ui8)
+ 0x00, // flags (fixed ui8)
+ 0x01, // metric labels count (varint)
+ 0x00, // label name index (varint)
+ 0x02, // label value index (varint)
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // value (fixed ui64)
+ };
+
+ ui8 expectedMetric3[] = {
+ 0x0a, // types (COUNTER | ONE_WITH_TS) (fixed ui8)
+ 0x00, // flags (fixed ui8)
+ 0x01, // metric labels count (varint)
+ 0x00, // label name index (varint)
+ 0x03, // label value index (varint)
+ 0x0b, 0x63, 0xfe, 0x59, // time in seconds (fixed ui32)
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // value (fixed ui64)
+ };
+
+ ui8 expectedMetric4[] = {
+ 0x07, // types (GAUGE | MANY_WITH_TS) (fixed ui8)
+ 0x00, // flags (fixed ui8)
+ 0x01, // metric labels count (varint)
+ 0x00, // label name index (varint)
+ 0x04, // label value index (varint)
+ 0x02, // points count (varint)
+ 0x0b, 0x63, 0xfe, 0x59, // time in seconds (fixed ui32)
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x40, // value (double IEEE754)
+ 0x1a, 0x63, 0xfe, 0x59, // time in seconds (fixed ui32)
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x4d, 0x40 // value (double IEEE754)
+ };
+
+ ui8 expectedMetric5_v1_0[] = {
+ 0x16, // types (HIST | ONE_WITH_TS) (fixed ui8)
+ 0x00, // flags (fixed ui8)
+ 0x01, // metric labels count (varint)
+ 0x00, // label name index (varint)
+ 0x05, // label value index (varint)
+ 0x0b, 0x63, 0xfe, 0x59, // time in seconds (fixed ui32)
+ 0x06, // histogram buckets count (varint)
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // histogram bucket bounds (array of fixed ui64)
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // histogram bucket values
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ ui8 expectedMetric5[] = {
+ 0x16, // types (HIST | ONE_WITH_TS) (fixed ui8)
+ 0x00, // flags (fixed ui8)
+ 0x01, // metric labels count (varint)
+ 0x00, // label name index (varint)
+ 0x05, // label value index (varint)
+ 0x0b, 0x63, 0xfe, 0x59, // time in seconds (fixed ui32)
+ 0x06, // histogram buckets count (varint)
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, // histogram bucket bounds (array of doubles)
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x40,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x7f,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // histogram bucket values
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ ui8 expectedMetric6[] = {
+ 0x12, // types (IGAUGE | ONE_WITH_TS) (fixed ui8)
+ 0x00, // flags (fixed ui8)
+ 0x01, // metric labels count (varint)
+ 0x00, // label name index (varint)
+ 0x06, // label value index (varint)
+ 0x0b, 0x63, 0xfe, 0x59, // time in seconds (fixed ui32)
+ 0x39, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // value (fixed i64)
+ };
+
+ ui8 expectedMetric7[] = {
+ 0x1e, // types (DSUMMARY | ONE_WITH_TS) (fixed ui8)
+ 0x00, // flags (fixed ui8)
+ 0x01, // metric labels count (varint)
+ 0x00, // label name index (varint)
+ 0x07, // label value index (varint)
+ 0x0b, 0x63, 0xfe, 0x59, // time in seconds (fixed ui32)
+ 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // count (fixed ui64)
+ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x24, 0x40, // sum (fixed double)
+ 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xdc, 0xbf, // min (fixed double)
+ 0x64, 0x3b, 0xdf, 0x4f, 0x8d, 0x97, 0xde, 0x3f, // max (fixed double)
+ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xd3, 0x3f, // last (fixed double)
+ };
+
+ ui8 expectedMetric8[] = {
+ 0x26, // types (LOGHIST | ONE_WITH_TS) (fixed ui8)
+ 0x00, // flags (fixed ui8)
+ 0x01, // metric labels count (variant)
+ 0x00, // label name index (variant)
+ 0x08, // label value index (variant)
+ 0x0b, 0x63, 0xfe, 0x59, // time in seconds (fixed ui32)
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x3F, // base (fixed double)
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // zerosCount (fixed ui64)
+ 0x00, // startPower (variant)
+ 0x04, // buckets count (variant)
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x3F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x3F, // bucket values
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x3F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x3F,
+ };
+
+ const size_t expectedSize =
+ Y_ARRAY_SIZE(expectedHeader) +
+ Y_ARRAY_SIZE(expectedStringPools) +
+ Y_ARRAY_SIZE(expectedCommonTime) +
+ Y_ARRAY_SIZE(expectedCommonLabels) +
+ Y_ARRAY_SIZE(expectedMetric1) +
+ Y_ARRAY_SIZE(expectedMetric2) +
+ Y_ARRAY_SIZE(expectedMetric3) +
+ Y_ARRAY_SIZE(expectedMetric4) +
+ Y_ARRAY_SIZE(expectedMetric5) +
+ Y_ARRAY_SIZE(expectedMetric6) +
+ Y_ARRAY_SIZE(expectedMetric7) +
+ Y_ARRAY_SIZE(expectedMetric8);
+
+ const TInstant now = TInstant::ParseIso8601Deprecated("2017-11-05T01:02:03Z");
+
+ // {1: 1, 2: 1, 4: 2, 8: 4, 16: 8, inf: 83}
+ IHistogramSnapshotPtr TestHistogram() {
+ auto h = ExponentialHistogram(6, 2);
+ for (i64 i = 1; i < 100; i++) {
+ h->Collect(i);
+ }
+ return h->Snapshot();
+ }
+
+ TLogHistogramSnapshotPtr TestLogHistogram() {
+ TVector buckets{0.5, 0.25, 0.25, 0.5};
+ return MakeIntrusive<TLogHistogramSnapshot>(1.5, 1u, 0, std::move(buckets));
+ }
+
+ ISummaryDoubleSnapshotPtr TestSummaryDouble() {
+ return MakeIntrusive<TSummaryDoubleSnapshot>(10.1, -0.45, 0.478, 0.3, 30u);
+ }
+
+ Y_UNIT_TEST(Encode) {
+ TBuffer buffer;
+ TBufferOutput out(buffer);
+ auto e = EncoderSpackV1(
+ &out, ETimePrecision::SECONDS, ECompression::IDENTITY);
+
+ e->OnStreamBegin();
+ { // common time
+ e->OnCommonTime(TInstant::Seconds(1500000000));
+ }
+ { // common labels
+ e->OnLabelsBegin();
+ e->OnLabel("project", "solomon");
+ e->OnLabelsEnd();
+ }
+ { // metric #1
+ e->OnMetricBegin(EMetricType::RATE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("name", "q1");
+ e->OnLabelsEnd();
+ }
+ e->OnMetricEnd();
+ }
+ { // metric #2
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("name", "q2");
+ e->OnLabelsEnd();
+ }
+ // Only the last value will be encoded
+ e->OnUint64(TInstant::Zero(), 10);
+ e->OnUint64(TInstant::Zero(), 13);
+ e->OnUint64(TInstant::Zero(), 17);
+ e->OnMetricEnd();
+ }
+ { // metric #3
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("name", "q3");
+ e->OnLabelsEnd();
+ }
+ e->OnUint64(now, 10);
+ e->OnUint64(now, 13);
+ e->OnUint64(now, 17);
+ e->OnMetricEnd();
+ }
+ { // metric #4
+ e->OnMetricBegin(EMetricType::GAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("name", "answer");
+ e->OnLabelsEnd();
+ }
+ e->OnDouble(now, 42);
+ e->OnDouble(now + TDuration::Seconds(15), 59);
+ e->OnMetricEnd();
+ }
+ { // metric #5
+ e->OnMetricBegin(EMetricType::HIST);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("name", "responseTimeMillis");
+ e->OnLabelsEnd();
+ }
+
+ auto histogram = TestHistogram();
+ e->OnHistogram(now, histogram);
+ e->OnMetricEnd();
+ }
+ { // metric #6
+ e->OnMetricBegin(EMetricType::IGAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("name", "bytes");
+ e->OnLabelsEnd();
+ }
+ e->OnInt64(now, 1337);
+ e->OnMetricEnd();
+ }
+ { // metric 7
+ e->OnMetricBegin(EMetricType::DSUMMARY);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("name", "temperature");
+ e->OnLabelsEnd();
+ }
+ e->OnSummaryDouble(now, TestSummaryDouble());
+ e->OnMetricEnd();
+ }
+ { // metric 8
+ e->OnMetricBegin(EMetricType::LOGHIST);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("name", "ms");
+ e->OnLabelsEnd();
+ }
+ e->OnLogHistogram(now, TestLogHistogram());
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ e->Close();
+
+ // Cout << "encoded: " << HexEncode(buffer.Data(), buffer.Size()) << Endl;
+ // Cout << "size: " << buffer.Size() << Endl;
+
+ UNIT_ASSERT_VALUES_EQUAL(buffer.Size(), expectedSize);
+
+ ui8* p = reinterpret_cast<ui8*>(buffer.Data());
+ UNIT_ASSERT_BINARY_EQUALS(p, expectedHeader);
+ p += Y_ARRAY_SIZE(expectedHeader);
+
+ UNIT_ASSERT_BINARY_EQUALS(p, expectedStringPools);
+ p += Y_ARRAY_SIZE(expectedStringPools);
+
+ UNIT_ASSERT_BINARY_EQUALS(p, expectedCommonTime);
+ p += Y_ARRAY_SIZE(expectedCommonTime);
+
+ UNIT_ASSERT_BINARY_EQUALS(p, expectedCommonLabels);
+ p += Y_ARRAY_SIZE(expectedCommonLabels);
+
+ UNIT_ASSERT_BINARY_EQUALS(p, expectedMetric1);
+ p += Y_ARRAY_SIZE(expectedMetric1);
+
+ UNIT_ASSERT_BINARY_EQUALS(p, expectedMetric2);
+ p += Y_ARRAY_SIZE(expectedMetric2);
+
+ UNIT_ASSERT_BINARY_EQUALS(p, expectedMetric3);
+ p += Y_ARRAY_SIZE(expectedMetric3);
+
+ UNIT_ASSERT_BINARY_EQUALS(p, expectedMetric4);
+ p += Y_ARRAY_SIZE(expectedMetric4);
+
+ UNIT_ASSERT_BINARY_EQUALS(p, expectedMetric5);
+ p += Y_ARRAY_SIZE(expectedMetric5);
+
+ UNIT_ASSERT_BINARY_EQUALS(p, expectedMetric6);
+ p += Y_ARRAY_SIZE(expectedMetric6);
+
+ UNIT_ASSERT_BINARY_EQUALS(p, expectedMetric7);
+ p += Y_ARRAY_SIZE(expectedMetric7);
+
+ UNIT_ASSERT_BINARY_EQUALS(p, expectedMetric8);
+ p += Y_ARRAY_SIZE(expectedMetric8);
+ }
+
+ NProto::TMultiSamplesList GetMergingMetricSamples(EMetricsMergingMode mergingMode) {
+ TBuffer buffer;
+ TBufferOutput out(buffer);
+
+ auto e = EncoderSpackV1(
+ &out,
+ ETimePrecision::SECONDS,
+ ECompression::IDENTITY,
+ mergingMode
+ );
+
+ e->OnStreamBegin();
+ for (size_t i = 0; i != 3; ++i) {
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("name", "my_counter");
+ e->OnLabelsEnd();
+ }
+ e->OnUint64(TInstant::Zero() + TDuration::Seconds(i), i + 1);
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ e->Close();
+
+ NProto::TMultiSamplesList samples;
+ IMetricEncoderPtr eProto = EncoderProtobuf(&samples);
+ TBufferInput in(buffer);
+ DecodeSpackV1(&in, eProto.Get());
+
+ return samples;
+ }
+
+ Y_UNIT_TEST(SpackEncoderMergesMetrics) {
+ {
+ NProto::TMultiSamplesList samples = GetMergingMetricSamples(EMetricsMergingMode::DEFAULT);
+
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 3);
+ UNIT_ASSERT_EQUAL(samples.GetSamples(0).GetPoints(0).GetUint64(), 1);
+ UNIT_ASSERT_EQUAL(samples.GetSamples(1).GetPoints(0).GetUint64(), 2);
+ UNIT_ASSERT_EQUAL(samples.GetSamples(2).GetPoints(0).GetUint64(), 3);
+ }
+
+ {
+ NProto::TMultiSamplesList samples = GetMergingMetricSamples(EMetricsMergingMode::MERGE_METRICS);
+
+ UNIT_ASSERT_EQUAL(samples.SamplesSize(), 1);
+
+ auto sample0 = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(sample0.GetPoints(0).GetUint64(), 1);
+ UNIT_ASSERT_EQUAL(sample0.GetPoints(1).GetUint64(), 2);
+ UNIT_ASSERT_EQUAL(sample0.GetPoints(2).GetUint64(), 3);
+ }
+ }
+
+ void DecodeDataToSamples(NProto::TMultiSamplesList & samples, ui16 version) {
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+
+ TBuffer data(expectedSize);
+ if (SV1_00 == version) { // v1.0
+ data.Append(reinterpret_cast<char*>(expectedHeader_v1_0), Y_ARRAY_SIZE(expectedHeader_v1_0));
+ } else {
+ data.Append(reinterpret_cast<char*>(expectedHeader), Y_ARRAY_SIZE(expectedHeader));
+ }
+ data.Append(reinterpret_cast<char*>(expectedStringPools), Y_ARRAY_SIZE(expectedStringPools));
+ data.Append(reinterpret_cast<char*>(expectedCommonTime), Y_ARRAY_SIZE(expectedCommonTime));
+ data.Append(reinterpret_cast<char*>(expectedCommonLabels), Y_ARRAY_SIZE(expectedCommonLabels));
+ data.Append(reinterpret_cast<char*>(expectedMetric1), Y_ARRAY_SIZE(expectedMetric1));
+ data.Append(reinterpret_cast<char*>(expectedMetric2), Y_ARRAY_SIZE(expectedMetric2));
+ data.Append(reinterpret_cast<char*>(expectedMetric3), Y_ARRAY_SIZE(expectedMetric3));
+ data.Append(reinterpret_cast<char*>(expectedMetric4), Y_ARRAY_SIZE(expectedMetric4));
+ if (SV1_00 == version) { // v1.0
+ data.Append(reinterpret_cast<char*>(expectedMetric5_v1_0), Y_ARRAY_SIZE(expectedMetric5_v1_0));
+ } else {
+ data.Append(reinterpret_cast<char*>(expectedMetric5), Y_ARRAY_SIZE(expectedMetric5));
+ }
+ data.Append(reinterpret_cast<char*>(expectedMetric6), Y_ARRAY_SIZE(expectedMetric6));
+ data.Append(reinterpret_cast<char*>(expectedMetric7), Y_ARRAY_SIZE(expectedMetric7));
+ data.Append(reinterpret_cast<char*>(expectedMetric8), Y_ARRAY_SIZE(expectedMetric8));
+ TBufferInput in(data);
+ DecodeSpackV1(&in, e.Get());
+ }
+
+ void DecodeDataToSamples(NProto::TMultiSamplesList & samples) {
+ TSpackHeader header;
+ header.Version = SV1_01;
+ DecodeDataToSamples(samples, header.Version);
+ }
+
+ Y_UNIT_TEST(Decode) {
+ NProto::TMultiSamplesList samples;
+ DecodeDataToSamples(samples);
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TInstant::MilliSeconds(samples.GetCommonTime()),
+ TInstant::Seconds(1500000000));
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.CommonLabelsSize(), 1);
+ AssertLabelEqual(samples.GetCommonLabels(0), "project", "solomon");
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.SamplesSize(), 8);
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::RATE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "name", "q1");
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(1);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::COUNTER);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "name", "q2");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+ AssertPointEqual(s.GetPoints(0), TInstant::Zero(), ui64(17));
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(2);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::COUNTER);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "name", "q3");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+ AssertPointEqual(s.GetPoints(0), now, ui64(17));
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(3);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "name", "answer");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 2);
+ AssertPointEqual(s.GetPoints(0), now, double(42));
+ AssertPointEqual(s.GetPoints(1), now + TDuration::Seconds(15), double(59));
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(4);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::HISTOGRAM);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "name", "responseTimeMillis");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+
+ const NProto::TPoint& p = s.GetPoints(0);
+ UNIT_ASSERT_VALUES_EQUAL(p.GetTime(), now.MilliSeconds());
+ UNIT_ASSERT_EQUAL(p.GetValueCase(), NProto::TPoint::kHistogram);
+
+ auto histogram = TestHistogram();
+
+ const NProto::THistogram& pointHistogram = p.GetHistogram();
+ UNIT_ASSERT_VALUES_EQUAL(pointHistogram.BoundsSize(), histogram->Count());
+ UNIT_ASSERT_VALUES_EQUAL(pointHistogram.ValuesSize(), histogram->Count());
+
+ for (size_t i = 0; i < pointHistogram.BoundsSize(); i++) {
+ UNIT_ASSERT_DOUBLES_EQUAL(pointHistogram.GetBounds(i), histogram->UpperBound(i), Min<double>());
+ UNIT_ASSERT_VALUES_EQUAL(pointHistogram.GetValues(i), histogram->Value(i));
+ }
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(5);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::IGAUGE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "name", "bytes");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+ AssertPointEqual(s.GetPoints(0), now, i64(1337));
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(6);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::DSUMMARY);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "name", "temperature");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+
+ const NProto::TPoint& p = s.GetPoints(0);
+ UNIT_ASSERT_VALUES_EQUAL(p.GetTime(), now.MilliSeconds());
+ UNIT_ASSERT_EQUAL(p.GetValueCase(), NProto::TPoint::kSummaryDouble);
+
+ auto expected = TestSummaryDouble();
+
+ auto actual = p.GetSummaryDouble();
+
+ UNIT_ASSERT_VALUES_EQUAL(expected->GetSum(), actual.GetSum());
+ UNIT_ASSERT_VALUES_EQUAL(expected->GetMin(), actual.GetMin());
+ UNIT_ASSERT_VALUES_EQUAL(expected->GetMax(), actual.GetMax());
+ UNIT_ASSERT_VALUES_EQUAL(expected->GetLast(), actual.GetLast());
+ UNIT_ASSERT_VALUES_EQUAL(expected->GetCount(), actual.GetCount());
+ }
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(7);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::LOGHISTOGRAM);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "name", "ms");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+
+ const NProto::TPoint& p = s.GetPoints(0);
+ UNIT_ASSERT_VALUES_EQUAL(p.GetTime(), now.MilliSeconds());
+ UNIT_ASSERT_EQUAL(p.GetValueCase(), NProto::TPoint::kLogHistogram);
+
+ auto expected = TestLogHistogram();
+ auto actual = p.GetLogHistogram();
+
+ UNIT_ASSERT_VALUES_EQUAL(expected->ZerosCount(), actual.GetZerosCount());
+ UNIT_ASSERT_VALUES_EQUAL(expected->Base(), actual.GetBase());
+ UNIT_ASSERT_VALUES_EQUAL(expected->StartPower(), actual.GetStartPower());
+ UNIT_ASSERT_VALUES_EQUAL(expected->Count(), actual.BucketsSize());
+ for (size_t i = 0; i < expected->Count(); ++i) {
+ UNIT_ASSERT_VALUES_EQUAL(expected->Bucket(i), actual.GetBuckets(i));
+ }
+ }
+ }
+
+ void TestCompression(ECompression alg) {
+ TBuffer buffer;
+ {
+ TBufferOutput out(buffer);
+ auto e = EncoderSpackV1(&out, ETimePrecision::MILLIS, alg);
+ e->OnStreamBegin();
+ {
+ e->OnMetricBegin(EMetricType::GAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("name", "answer");
+ e->OnLabelsEnd();
+ }
+ e->OnDouble(now, 42);
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ e->Close();
+ }
+
+ auto* header = reinterpret_cast<const TSpackHeader*>(buffer.Data());
+ UNIT_ASSERT_EQUAL(DecodeCompression(header->Compression), alg);
+
+ NProto::TMultiSamplesList samples;
+ {
+ IMetricEncoderPtr e = EncoderProtobuf(&samples);
+ TBufferInput in(buffer);
+ DecodeSpackV1(&in, e.Get());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TInstant::MilliSeconds(samples.GetCommonTime()),
+ TInstant::Zero());
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.CommonLabelsSize(), 0);
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.SamplesSize(), 1);
+ {
+ const NProto::TMultiSample& s = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 1);
+ AssertLabelEqual(s.GetLabels(0), "name", "answer");
+ AssertPointEqual(s.GetPoints(0), now, 42.0);
+ }
+ }
+
+ Y_UNIT_TEST(CompressionIdentity) {
+ TestCompression(ECompression::IDENTITY);
+ }
+
+ Y_UNIT_TEST(CompressionZlib) {
+ TestCompression(ECompression::ZLIB);
+ }
+
+ Y_UNIT_TEST(CompressionZstd) {
+ TestCompression(ECompression::ZSTD);
+ }
+
+ Y_UNIT_TEST(CompressionLz4) {
+ TestCompression(ECompression::LZ4);
+ }
+
+ Y_UNIT_TEST(Decode_v1_0_histograms) {
+ // Check that histogram bounds decoded from different versions are the same
+ NProto::TMultiSamplesList samples, samples_v1_0;
+ DecodeDataToSamples(samples);
+ DecodeDataToSamples(samples_v1_0, /*version = */ SV1_00);
+
+ const NProto::THistogram& pointHistogram = samples.GetSamples(4).GetPoints(0).GetHistogram();
+ const NProto::THistogram& pointHistogram_v1_0 = samples_v1_0.GetSamples(4).GetPoints(0).GetHistogram();
+
+ for (size_t i = 0; i < pointHistogram.BoundsSize(); i++) {
+ UNIT_ASSERT_DOUBLES_EQUAL(pointHistogram.GetBounds(i), pointHistogram_v1_0.GetBounds(i), Min<double>());
+ }
+ }
+
+ Y_UNIT_TEST(SimpleV12) {
+ ui8 expectedSerialized[] = {
+ // header
+ 0x53, 0x50, // magic "SP" (fixed ui16)
+ // minor, major
+ 0x02, 0x01, // version (fixed ui16)
+ 0x18, 0x00, // header size (fixed ui16)
+ 0x00, // time precision (fixed ui8)
+ 0x00, // compression algorithm (fixed ui8)
+ 0x0A, 0x00, 0x00, 0x00, // label names size (fixed ui32)
+ 0x14, 0x00, 0x00, 0x00, // labels values size (fixed ui32)
+ 0x01, 0x00, 0x00, 0x00, // metric count (fixed ui32)
+ 0x01, 0x00, 0x00, 0x00, // points count (fixed ui32)
+
+ // string pools
+ 0x73, 0x00, // "s\0"
+ 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x00, // "project\0"
+ 0x73, 0x6f, 0x6c, 0x6f, 0x6d, 0x6f, 0x6e, 0x00, // "solomon\0"
+ 0x74, 0x65, 0x6D, 0x70, 0x65, 0x72, 0x61, 0x74, // temperature
+ 0x75, 0x72, 0x65, 0x00,
+
+ // common time
+ 0x00, 0x2f, 0x68, 0x59, // common time in seconds (fixed ui32)
+
+ // common labels
+ 0x00, // common labels count (varint)
+
+ // metric
+ 0x09, // types (COUNTER | ONE_WITHOUT_TS) (fixed ui8)
+ 0x00, // flags (fixed ui8)
+ 0x01, // name index (varint)
+ 0x01, // metric labels count (varint)
+ 0x01, // 'project' label name index (varint)
+ 0x00, // 'project' label value index (varint)
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // value (fixed ui64)
+ };
+
+ // encode
+ {
+ TBuffer actualSerialized;
+ {
+ TBufferOutput out(actualSerialized);
+ auto e = EncoderSpackV12(
+ &out,
+ ETimePrecision::SECONDS,
+ ECompression::IDENTITY,
+ EMetricsMergingMode::DEFAULT,
+ "s");
+
+ e->OnStreamBegin();
+ e->OnCommonTime(TInstant::Seconds(1500000000));
+
+ {
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("project", "solomon");
+ e->OnLabel("s", "temperature");
+ e->OnLabelsEnd();
+ }
+ // Only the last value will be encoded
+ e->OnUint64(TInstant::Zero(), 10);
+ e->OnUint64(TInstant::Zero(), 13);
+ e->OnUint64(TInstant::Zero(), 17);
+ e->OnMetricEnd();
+ }
+
+ e->OnStreamEnd();
+ e->Close();
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(actualSerialized.Size(), Y_ARRAY_SIZE(expectedSerialized));
+ UNIT_ASSERT_BINARY_EQUALS(actualSerialized.Data(), expectedSerialized);
+ }
+
+ // decode
+ {
+ NProto::TMultiSamplesList samples;
+ {
+ auto input = TMemoryInput(expectedSerialized, Y_ARRAY_SIZE(expectedSerialized));
+ auto encoder = EncoderProtobuf(&samples);
+ DecodeSpackV1(&input, encoder.Get(), "s");
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::MilliSeconds(samples.GetCommonTime()),
+ TInstant::Seconds(1500000000));
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.CommonLabelsSize(), 0);
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.SamplesSize(), 1);
+ {
+ const auto& s = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(s.GetMetricType(), NProto::COUNTER);
+ UNIT_ASSERT_VALUES_EQUAL(s.LabelsSize(), 2);
+ AssertLabelEqual(s.GetLabels(0), "s", "temperature");
+ AssertLabelEqual(s.GetLabels(1), "project", "solomon");
+
+ UNIT_ASSERT_VALUES_EQUAL(s.PointsSize(), 1);
+ AssertPointEqual(s.GetPoints(0), TInstant::Zero(), ui64(17));
+ }
+ }
+ }
+
+ Y_UNIT_TEST(V12MissingNameForOneMetric) {
+ TBuffer b;
+ TBufferOutput out(b);
+ auto e = EncoderSpackV12(
+ &out,
+ ETimePrecision::SECONDS,
+ ECompression::IDENTITY,
+ EMetricsMergingMode::DEFAULT,
+ "s");
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ [&]() {
+ e->OnStreamBegin();
+ {
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("s", "s1");
+ e->OnLabelsEnd();
+ }
+ e->OnUint64(TInstant::Zero(), 1);
+ e->OnMetricEnd();
+
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("project", "solomon");
+ e->OnLabel("m", "v");
+ e->OnLabelsEnd();
+ }
+ e->OnUint64(TInstant::Zero(), 2);
+ e->OnMetricEnd();
+ }
+
+ e->OnStreamEnd();
+ e->Close();
+ }(),
+ yexception,
+ "metric name label 's' not found, all metric labels '{m=v, project=solomon}'");
+ }
+}
diff --git a/library/cpp/monlib/encode/spack/ut/ya.make b/library/cpp/monlib/encode/spack/ut/ya.make
new file mode 100644
index 0000000000..980bf54667
--- /dev/null
+++ b/library/cpp/monlib/encode/spack/ut/ya.make
@@ -0,0 +1,16 @@
+UNITTEST_FOR(library/cpp/monlib/encode/spack)
+
+OWNER(
+ g:solomon
+ jamel
+)
+
+SRCS(
+ spack_v1_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/monlib/encode/protobuf
+)
+
+END()
diff --git a/library/cpp/monlib/encode/spack/varint.cpp b/library/cpp/monlib/encode/spack/varint.cpp
new file mode 100644
index 0000000000..051cf17380
--- /dev/null
+++ b/library/cpp/monlib/encode/spack/varint.cpp
@@ -0,0 +1,79 @@
+#include "varint.h"
+
+#include <util/generic/yexception.h>
+#include <util/stream/input.h>
+#include <util/stream/output.h>
+
+namespace NMonitoring {
+ ui32 WriteVarUInt32(IOutputStream* output, ui32 value) {
+ bool stop = false;
+ ui32 written = 0;
+ while (!stop) {
+ ui8 byte = static_cast<ui8>(value | 0x80);
+ value >>= 7;
+ if (value == 0) {
+ stop = true;
+ byte &= 0x7F;
+ }
+ output->Write(byte);
+ written++;
+ }
+ return written;
+ }
+
+ ui32 ReadVarUInt32(IInputStream* input) {
+ ui32 value = 0;
+ switch (TryReadVarUInt32(input, &value)) {
+ case EReadResult::OK:
+ return value;
+ case EReadResult::ERR_OVERFLOW:
+ ythrow yexception() << "the data is too long to read ui32";
+ case EReadResult::ERR_UNEXPECTED_EOF:
+ ythrow yexception() << "the data unexpectedly ended";
+ default:
+ ythrow yexception() << "unknown error while reading varint";
+ }
+ }
+
+ size_t ReadVarUInt32(const ui8* buf, size_t len, ui32* result) {
+ size_t count = 0;
+ ui32 value = 0;
+
+ ui8 byte = 0;
+ do {
+ if (7 * count > 8 * sizeof(ui32)) {
+ ythrow yexception() << "the data is too long to read ui32";
+ }
+ if (count == len) {
+ ythrow yexception() << "the data unexpectedly ended";
+ }
+ byte = buf[count];
+ value |= (static_cast<ui32>(byte & 0x7F)) << (7 * count);
+ ++count;
+ } while (byte & 0x80);
+
+ *result = value;
+ return count;
+ }
+
+EReadResult TryReadVarUInt32(IInputStream* input, ui32* value) {
+ size_t count = 0;
+ ui32 result = 0;
+
+ ui8 byte = 0;
+ do {
+ if (7 * count > 8 * sizeof(ui32)) {
+ return EReadResult::ERR_OVERFLOW;
+ }
+ if (input->Read(&byte, 1) != 1) {
+ return EReadResult::ERR_UNEXPECTED_EOF;
+ }
+ result |= (static_cast<ui32>(byte & 0x7F)) << (7 * count);
+ ++count;
+ } while (byte & 0x80);
+
+ *value = result;
+ return EReadResult::OK;
+ }
+
+}
diff --git a/library/cpp/monlib/encode/spack/varint.h b/library/cpp/monlib/encode/spack/varint.h
new file mode 100644
index 0000000000..7ac522dd6c
--- /dev/null
+++ b/library/cpp/monlib/encode/spack/varint.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <util/system/types.h>
+
+class IInputStream;
+class IOutputStream;
+
+namespace NMonitoring {
+ ui32 WriteVarUInt32(IOutputStream* output, ui32 value);
+
+ ui32 ReadVarUInt32(IInputStream* input);
+ size_t ReadVarUInt32(const ui8* buf, size_t len, ui32* result);
+
+ enum class EReadResult {
+ OK,
+ ERR_OVERFLOW,
+ ERR_UNEXPECTED_EOF,
+ };
+
+ [[nodiscard]]
+ EReadResult TryReadVarUInt32(IInputStream* input, ui32* value);
+
+}
diff --git a/library/cpp/monlib/encode/spack/ya.make b/library/cpp/monlib/encode/spack/ya.make
new file mode 100644
index 0000000000..78d3061291
--- /dev/null
+++ b/library/cpp/monlib/encode/spack/ya.make
@@ -0,0 +1,25 @@
+LIBRARY()
+
+OWNER(
+ g:solomon
+ jamel
+)
+
+SRCS(
+ spack_v1_decoder.cpp
+ spack_v1_encoder.cpp
+ varint.cpp
+ compression.cpp
+)
+
+PEERDIR(
+ library/cpp/monlib/encode/buffered
+ library/cpp/monlib/exception
+
+ contrib/libs/lz4
+ contrib/libs/xxhash
+ contrib/libs/zlib
+ contrib/libs/zstd
+)
+
+END()
diff --git a/library/cpp/monlib/encode/text/text.h b/library/cpp/monlib/encode/text/text.h
new file mode 100644
index 0000000000..6b2be3937b
--- /dev/null
+++ b/library/cpp/monlib/encode/text/text.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <library/cpp/monlib/encode/encoder.h>
+
+class IOutputStream;
+
+namespace NMonitoring {
+ IMetricEncoderPtr EncoderText(IOutputStream* out, bool humanReadableTs = true);
+}
diff --git a/library/cpp/monlib/encode/text/text_encoder.cpp b/library/cpp/monlib/encode/text/text_encoder.cpp
new file mode 100644
index 0000000000..10336261f0
--- /dev/null
+++ b/library/cpp/monlib/encode/text/text_encoder.cpp
@@ -0,0 +1,226 @@
+#include "text.h"
+
+#include <library/cpp/monlib/encode/encoder_state.h>
+#include <library/cpp/monlib/metrics/labels.h>
+#include <library/cpp/monlib/metrics/metric_value.h>
+
+#include <util/datetime/base.h>
+#include <util/stream/format.h>
+
+namespace NMonitoring {
+ namespace {
+ class TEncoderText final: public IMetricEncoder {
+ public:
+ TEncoderText(IOutputStream* out, bool humanReadableTs)
+ : Out_(out)
+ , HumanReadableTs_(humanReadableTs)
+ {
+ }
+
+ private:
+ void OnStreamBegin() override {
+ State_.Expect(TEncoderState::EState::ROOT);
+ }
+
+ void OnStreamEnd() override {
+ State_.Expect(TEncoderState::EState::ROOT);
+ }
+
+ void OnCommonTime(TInstant time) override {
+ State_.Expect(TEncoderState::EState::ROOT);
+ CommonTime_ = time;
+ if (time != TInstant::Zero()) {
+ Out_->Write(TStringBuf("common time: "));
+ WriteTime(time);
+ Out_->Write('\n');
+ }
+ }
+
+ void OnMetricBegin(EMetricType type) override {
+ State_.Switch(TEncoderState::EState::ROOT, TEncoderState::EState::METRIC);
+ ClearLastMetricState();
+ MetricType_ = type;
+ }
+
+ void OnMetricEnd() override {
+ State_.Switch(TEncoderState::EState::METRIC, TEncoderState::EState::ROOT);
+ WriteMetric();
+ }
+
+ void OnLabelsBegin() override {
+ if (State_ == TEncoderState::EState::METRIC) {
+ State_ = TEncoderState::EState::METRIC_LABELS;
+ } else if (State_ == TEncoderState::EState::ROOT) {
+ State_ = TEncoderState::EState::COMMON_LABELS;
+ } else {
+ State_.ThrowInvalid("expected METRIC or ROOT");
+ }
+ }
+
+ void OnLabelsEnd() override {
+ if (State_ == TEncoderState::EState::METRIC_LABELS) {
+ State_ = TEncoderState::EState::METRIC;
+ } else if (State_ == TEncoderState::EState::COMMON_LABELS) {
+ State_ = TEncoderState::EState::ROOT;
+ Out_->Write(TStringBuf("common labels: "));
+ WriteLabels();
+ Out_->Write('\n');
+ } else {
+ State_.ThrowInvalid("expected LABELS or COMMON_LABELS");
+ }
+ }
+
+ void OnLabel(TStringBuf name, TStringBuf value) override {
+ Labels_.Add(name, value);
+ }
+
+ void OnDouble(TInstant time, double value) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TimeSeries_.Add(time, value);
+ }
+
+ void OnInt64(TInstant time, i64 value) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TimeSeries_.Add(time, value);
+ }
+
+ void OnUint64(TInstant time, ui64 value) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TimeSeries_.Add(time, value);
+ }
+
+ void OnHistogram(TInstant time, IHistogramSnapshotPtr snapshot) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TimeSeries_.Add(time, snapshot.Get());
+ }
+
+ void OnSummaryDouble(TInstant time, ISummaryDoubleSnapshotPtr snapshot) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TimeSeries_.Add(time, snapshot.Get());
+ }
+
+ void OnLogHistogram(TInstant ts, TLogHistogramSnapshotPtr snapshot) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TimeSeries_.Add(ts, snapshot.Get());
+ }
+
+ void Close() override {
+ }
+
+ void WriteTime(TInstant time) {
+ if (HumanReadableTs_) {
+ char buf[64];
+ auto len = FormatDate8601(buf, sizeof(buf), time.TimeT());
+ Out_->Write(buf, len);
+ } else {
+ (*Out_) << time.Seconds();
+ }
+ }
+
+ void WriteValue(EMetricValueType type, TMetricValue value) {
+ switch (type) {
+ case EMetricValueType::DOUBLE:
+ (*Out_) << value.AsDouble();
+ break;
+ case EMetricValueType::INT64:
+ (*Out_) << value.AsInt64();
+ break;
+ case EMetricValueType::UINT64:
+ (*Out_) << value.AsUint64();
+ break;
+ case EMetricValueType::HISTOGRAM:
+ (*Out_) << *value.AsHistogram();
+ break;
+ case EMetricValueType::SUMMARY:
+ (*Out_) << *value.AsSummaryDouble();
+ break;
+ case EMetricValueType::LOGHISTOGRAM:
+ (*Out_) << *value.AsLogHistogram();
+ break;
+ case EMetricValueType::UNKNOWN:
+ ythrow yexception() << "unknown metric value type";
+ }
+ }
+
+ void WriteLabels() {
+ auto& out = *Out_;
+ const auto size = Labels_.Size();
+ size_t i = 0;
+
+ out << '{';
+ for (auto&& l : Labels_) {
+ out << l.Name() << TStringBuf("='") << l.Value() << '\'';
+
+ ++i;
+ if (i < size) {
+ out << TStringBuf(", ");
+ }
+ };
+
+ out << '}';
+ }
+
+ void WriteMetric() {
+ // (1) type
+ TStringBuf typeStr = MetricTypeToStr(MetricType_);
+ (*Out_) << LeftPad(typeStr, MaxMetricTypeNameLength) << ' ';
+
+ // (2) name and labels
+ auto name = Labels_.Extract(TStringBuf("sensor"));
+ if (name) {
+ if (name->Value().find(' ') != TString::npos) {
+ (*Out_) << '"' << name->Value() << '"';
+ } else {
+ (*Out_) << name->Value();
+ }
+ }
+ WriteLabels();
+
+ // (3) values
+ if (!TimeSeries_.Empty()) {
+ TimeSeries_.SortByTs();
+ Out_->Write(TStringBuf(" ["));
+ for (size_t i = 0; i < TimeSeries_.Size(); i++) {
+ if (i > 0) {
+ Out_->Write(TStringBuf(", "));
+ }
+
+ const auto& point = TimeSeries_[i];
+ if (point.GetTime() == CommonTime_ || point.GetTime() == TInstant::Zero()) {
+ WriteValue(TimeSeries_.GetValueType(), point.GetValue());
+ } else {
+ Out_->Write('(');
+ WriteTime(point.GetTime());
+ Out_->Write(TStringBuf(", "));
+ WriteValue(TimeSeries_.GetValueType(), point.GetValue());
+ Out_->Write(')');
+ }
+ }
+ Out_->Write(']');
+ }
+ Out_->Write('\n');
+ }
+
+ void ClearLastMetricState() {
+ MetricType_ = EMetricType::UNKNOWN;
+ Labels_.Clear();
+ TimeSeries_.Clear();
+ }
+
+ private:
+ TEncoderState State_;
+ IOutputStream* Out_;
+ bool HumanReadableTs_;
+ TInstant CommonTime_ = TInstant::Zero();
+ EMetricType MetricType_ = EMetricType::UNKNOWN;
+ TLabels Labels_;
+ TMetricTimeSeries TimeSeries_;
+ };
+
+ }
+
+ IMetricEncoderPtr EncoderText(IOutputStream* out, bool humanReadableTs) {
+ return MakeHolder<TEncoderText>(out, humanReadableTs);
+ }
+
+}
diff --git a/library/cpp/monlib/encode/text/text_encoder_ut.cpp b/library/cpp/monlib/encode/text/text_encoder_ut.cpp
new file mode 100644
index 0000000000..554b6f5fa9
--- /dev/null
+++ b/library/cpp/monlib/encode/text/text_encoder_ut.cpp
@@ -0,0 +1,283 @@
+#include "text.h"
+
+#include <library/cpp/monlib/metrics/histogram_collector.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NMonitoring;
+
+Y_UNIT_TEST_SUITE(TTextText) {
+ template <typename TFunc>
+ TString EncodeToString(bool humanReadableTs, TFunc fn) {
+ TStringStream ss;
+ IMetricEncoderPtr encoder = EncoderText(&ss, humanReadableTs);
+ fn(encoder.Get());
+ return ss.Str();
+ }
+
+ Y_UNIT_TEST(Empty) {
+ auto result = EncodeToString(true, [](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ e->OnStreamEnd();
+ });
+ UNIT_ASSERT_STRINGS_EQUAL(result, "");
+ }
+
+ Y_UNIT_TEST(CommonPart) {
+ auto result = EncodeToString(true, [](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ e->OnCommonTime(TInstant::ParseIso8601Deprecated("2017-01-02T03:04:05.006Z"));
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("project", "solomon");
+ e->OnLabel("cluster", "man");
+ e->OnLabel("service", "stockpile");
+ e->OnLabelsEnd();
+ }
+ e->OnStreamEnd();
+ });
+ UNIT_ASSERT_STRINGS_EQUAL(result,
+ "common time: 2017-01-02T03:04:05Z\n"
+ "common labels: {project='solomon', cluster='man', service='stockpile'}\n");
+ }
+
+ Y_UNIT_TEST(Gauges) {
+ auto result = EncodeToString(true, [](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ { // no values
+ e->OnMetricBegin(EMetricType::GAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "cpuUsage");
+ e->OnLabelsEnd();
+ }
+ e->OnMetricEnd();
+ }
+ { // one value no ts
+ e->OnMetricBegin(EMetricType::GAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "diskUsage");
+ e->OnLabel("disk", "sda1");
+ e->OnLabelsEnd();
+ }
+ e->OnDouble(TInstant::Zero(), 1000);
+ e->OnMetricEnd();
+ }
+ { // one value with ts
+ e->OnMetricBegin(EMetricType::GAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "memoryUsage");
+ e->OnLabel("host", "solomon-man-00");
+ e->OnLabel("dc", "man");
+ e->OnLabelsEnd();
+ }
+ e->OnDouble(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:00Z"), 1000);
+ e->OnMetricEnd();
+ }
+ { // many values
+ e->OnMetricBegin(EMetricType::GAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "bytesRx");
+ e->OnLabel("host", "solomon-sas-01");
+ e->OnLabel("dc", "sas");
+ e->OnLabelsEnd();
+ }
+ e->OnDouble(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:00Z"), 2);
+ e->OnDouble(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:05Z"), 4);
+ e->OnDouble(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:10Z"), 8);
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ });
+ UNIT_ASSERT_STRINGS_EQUAL(result,
+ " GAUGE cpuUsage{}\n"
+ " GAUGE diskUsage{disk='sda1'} [1000]\n"
+ " GAUGE memoryUsage{host='solomon-man-00', dc='man'} [(2017-12-02T12:00:00Z, 1000)]\n"
+ " GAUGE bytesRx{host='solomon-sas-01', dc='sas'} [(2017-12-02T12:00:00Z, 2), (2017-12-02T12:00:05Z, 4), (2017-12-02T12:00:10Z, 8)]\n");
+ }
+
+ Y_UNIT_TEST(IntGauges) {
+ auto result = EncodeToString(true, [](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ { // no values
+ e->OnMetricBegin(EMetricType::IGAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "cpuUsage");
+ e->OnLabelsEnd();
+ }
+ e->OnMetricEnd();
+ }
+ { // one value no ts
+ e->OnMetricBegin(EMetricType::IGAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "diskUsage");
+ e->OnLabel("disk", "sda1");
+ e->OnLabelsEnd();
+ }
+ e->OnDouble(TInstant::Zero(), 1000);
+ e->OnMetricEnd();
+ }
+ { // one value with ts
+ e->OnMetricBegin(EMetricType::IGAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "memoryUsage");
+ e->OnLabel("host", "solomon-man-00");
+ e->OnLabel("dc", "man");
+ e->OnLabelsEnd();
+ }
+ e->OnDouble(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:00Z"), 1000);
+ e->OnMetricEnd();
+ }
+ { // many values
+ e->OnMetricBegin(EMetricType::IGAUGE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "bytesRx");
+ e->OnLabel("host", "solomon-sas-01");
+ e->OnLabel("dc", "sas");
+ e->OnLabelsEnd();
+ }
+ e->OnDouble(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:00Z"), 2);
+ e->OnDouble(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:05Z"), 4);
+ e->OnDouble(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:10Z"), 8);
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ });
+ UNIT_ASSERT_STRINGS_EQUAL(result,
+ " IGAUGE cpuUsage{}\n"
+ " IGAUGE diskUsage{disk='sda1'} [1000]\n"
+ " IGAUGE memoryUsage{host='solomon-man-00', dc='man'} [(2017-12-02T12:00:00Z, 1000)]\n"
+ " IGAUGE bytesRx{host='solomon-sas-01', dc='sas'} [(2017-12-02T12:00:00Z, 2), (2017-12-02T12:00:05Z, 4), (2017-12-02T12:00:10Z, 8)]\n");
+ }
+
+ Y_UNIT_TEST(Counters) {
+ auto doEncode = [](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ { // no values
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "cpuUsage");
+ e->OnLabelsEnd();
+ }
+ e->OnMetricEnd();
+ }
+ { // one value no ts
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "diskUsage");
+ e->OnLabel("disk", "sda1");
+ e->OnLabelsEnd();
+ }
+ e->OnUint64(TInstant::Zero(), 1000);
+ e->OnMetricEnd();
+ }
+ { // one value with ts
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "memoryUsage");
+ e->OnLabel("host", "solomon-man-00");
+ e->OnLabel("dc", "man");
+ e->OnLabelsEnd();
+ }
+ e->OnUint64(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:00Z"), 1000);
+ e->OnMetricEnd();
+ }
+ { // many values
+ e->OnMetricBegin(EMetricType::COUNTER);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "bytesRx");
+ e->OnLabel("host", "solomon-sas-01");
+ e->OnLabel("dc", "sas");
+ e->OnLabelsEnd();
+ }
+ e->OnUint64(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:00Z"), 2);
+ e->OnUint64(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:05Z"), 4);
+ e->OnUint64(TInstant::ParseIso8601Deprecated("2017-12-02T12:00:10Z"), 8);
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ };
+
+ auto result1 = EncodeToString(false, doEncode);
+ UNIT_ASSERT_STRINGS_EQUAL(result1,
+ " COUNTER cpuUsage{}\n"
+ " COUNTER diskUsage{disk='sda1'} [1000]\n"
+ " COUNTER memoryUsage{host='solomon-man-00', dc='man'} [(1512216000, 1000)]\n"
+ " COUNTER bytesRx{host='solomon-sas-01', dc='sas'} [(1512216000, 2), (1512216005, 4), (1512216010, 8)]\n");
+
+ auto result2 = EncodeToString(true, doEncode);
+ UNIT_ASSERT_STRINGS_EQUAL(result2,
+ " COUNTER cpuUsage{}\n"
+ " COUNTER diskUsage{disk='sda1'} [1000]\n"
+ " COUNTER memoryUsage{host='solomon-man-00', dc='man'} [(2017-12-02T12:00:00Z, 1000)]\n"
+ " COUNTER bytesRx{host='solomon-sas-01', dc='sas'} [(2017-12-02T12:00:00Z, 2), (2017-12-02T12:00:05Z, 4), (2017-12-02T12:00:10Z, 8)]\n");
+ }
+
+ Y_UNIT_TEST(Histograms) {
+ auto h = ExplicitHistogram({1, 2, 3, 4, 5});
+ h->Collect(3);
+ h->Collect(5, 7);
+ h->Collect(13);
+ auto s = h->Snapshot();
+
+ TString result = EncodeToString(true, [s](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ {
+ e->OnMetricBegin(EMetricType::HIST);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "readTimeMillis");
+ e->OnLabelsEnd();
+ }
+ e->OnHistogram(TInstant::Zero(), s);
+ e->OnMetricEnd();
+ }
+ {
+ e->OnMetricBegin(EMetricType::HIST_RATE);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "writeTimeMillis");
+ e->OnLabelsEnd();
+ }
+ e->OnHistogram(TInstant::Zero(), s);
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ });
+
+ UNIT_ASSERT_STRINGS_EQUAL(result,
+ " HIST readTimeMillis{} [{1: 0, 2: 0, 3: 1, 4: 0, 5: 7, inf: 1}]\n"
+ "HIST_RATE writeTimeMillis{} [{1: 0, 2: 0, 3: 1, 4: 0, 5: 7, inf: 1}]\n");
+ }
+
+ Y_UNIT_TEST(Summary) {
+ auto s = MakeIntrusive<TSummaryDoubleSnapshot>(10.1, -0.45, 0.478, 0.3, 30u);
+ TString result = EncodeToString(true, [s](IMetricEncoder* e) {
+ e->OnStreamBegin();
+ {
+ e->OnMetricBegin(EMetricType::DSUMMARY);
+ {
+ e->OnLabelsBegin();
+ e->OnLabel("sensor", "temperature");
+ e->OnLabelsEnd();
+ }
+ e->OnSummaryDouble(TInstant::Zero(), s);
+ e->OnMetricEnd();
+ }
+ e->OnStreamEnd();
+ });
+ UNIT_ASSERT_STRINGS_EQUAL(result,
+ " DSUMMARY temperature{} [{sum: 10.1, min: -0.45, max: 0.478, last: 0.3, count: 30}]\n");
+ }
+}
diff --git a/library/cpp/monlib/encode/text/ut/ya.make b/library/cpp/monlib/encode/text/ut/ya.make
new file mode 100644
index 0000000000..df23a252d1
--- /dev/null
+++ b/library/cpp/monlib/encode/text/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/monlib/encode/text)
+
+OWNER(
+ g:solomon
+ jamel
+)
+
+SRCS(
+ text_encoder_ut.cpp
+)
+
+END()
diff --git a/library/cpp/monlib/encode/text/ya.make b/library/cpp/monlib/encode/text/ya.make
new file mode 100644
index 0000000000..d296c78c1b
--- /dev/null
+++ b/library/cpp/monlib/encode/text/ya.make
@@ -0,0 +1,16 @@
+LIBRARY()
+
+OWNER(
+ g:solomon
+ jamel
+)
+
+SRCS(
+ text_encoder.cpp
+)
+
+PEERDIR(
+ library/cpp/monlib/encode
+)
+
+END()
diff --git a/library/cpp/monlib/encode/unistat/unistat.h b/library/cpp/monlib/encode/unistat/unistat.h
new file mode 100644
index 0000000000..1c43b7fa1b
--- /dev/null
+++ b/library/cpp/monlib/encode/unistat/unistat.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <util/generic/fwd.h>
+#include <util/datetime/base.h>
+
+namespace NMonitoring {
+ /// Decodes unistat-style metrics
+ /// https://wiki.yandex-team.ru/golovan/stat-handle
+ void DecodeUnistat(TStringBuf data, class IMetricConsumer* c, TInstant ts = TInstant::Zero());
+
+ /// Assumes consumer's stream is open by the caller
+ void DecodeUnistatToStream(TStringBuf data, class IMetricConsumer* c, TInstant = TInstant::Zero());
+}
diff --git a/library/cpp/monlib/encode/unistat/unistat_decoder.cpp b/library/cpp/monlib/encode/unistat/unistat_decoder.cpp
new file mode 100644
index 0000000000..b2344b0905
--- /dev/null
+++ b/library/cpp/monlib/encode/unistat/unistat_decoder.cpp
@@ -0,0 +1,253 @@
+#include "unistat.h"
+
+#include <library/cpp/monlib/metrics/histogram_collector.h>
+#include <library/cpp/monlib/metrics/labels.h>
+#include <library/cpp/monlib/metrics/metric_type.h>
+#include <library/cpp/monlib/metrics/metric_value.h>
+#include <library/cpp/monlib/metrics/metric_consumer.h>
+
+#include <library/cpp/json/json_reader.h>
+
+#include <util/datetime/base.h>
+#include <util/string/split.h>
+
+#include <contrib/libs/re2/re2/re2.h>
+
+using namespace NJson;
+
+const re2::RE2 NAME_RE{R"((?:[a-zA-Z0-9\.\-/@_]+_)+(?:[ad][vehmntx]{3}|summ|hgram|max))"};
+
+namespace NMonitoring {
+ namespace {
+ bool IsNumber(const NJson::TJsonValue& j) {
+ switch (j.GetType()) {
+ case EJsonValueType::JSON_INTEGER:
+ case EJsonValueType::JSON_UINTEGER:
+ case EJsonValueType::JSON_DOUBLE:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ template <typename T>
+ T ExtractNumber(const TJsonValue& val) {
+ switch (val.GetType()) {
+ case EJsonValueType::JSON_INTEGER:
+ return static_cast<T>(val.GetInteger());
+ case EJsonValueType::JSON_UINTEGER:
+ return static_cast<T>(val.GetUInteger());
+ case EJsonValueType::JSON_DOUBLE:
+ return static_cast<T>(val.GetDouble());
+
+ default:
+ ythrow yexception() << "Expected number, but found " << val.GetType();
+ }
+ }
+
+ auto ExtractDouble = ExtractNumber<double>;
+ auto ExtractUi64 = ExtractNumber<ui64>;
+
+ class THistogramBuilder {
+ public:
+ void Add(TBucketBound bound, TBucketValue value) {
+ /// XXX: yasm uses left-closed intervals, while in monlib we use right-closed ones,
+ /// so (-inf; 0) [0, 100) [100; +inf)
+ /// becomes (-inf; 0] (0, 100] (100; +inf)
+ /// but since we've already lost some information these no way to avoid this kind of error here
+ Bounds_.push_back(bound);
+
+ /// this will always be 0 for the first bucket,
+ /// since there's no way to make (-inf; N) bucket in yasm
+ Values_.push_back(NextValue_);
+
+ /// we will write this value into the next bucket so that [[0, 10], [100, 20], [200, 50]]
+ /// becomes (-inf; 0] -> 0; (0; 100] -> 10; (100; 200] -> 20; (200; +inf) -> 50
+ NextValue_ = value;
+ }
+
+ IHistogramSnapshotPtr Finalize() {
+ Bounds_.push_back(std::numeric_limits<TBucketBound>::max());
+ Values_.push_back(NextValue_);
+
+ Y_ENSURE(Bounds_.size() <= HISTOGRAM_MAX_BUCKETS_COUNT,
+ "Histogram is only allowed to have " << HISTOGRAM_MAX_BUCKETS_COUNT << " buckets, but has " << Bounds_.size());
+
+ return ExplicitHistogramSnapshot(Bounds_, Values_);
+ }
+
+ public:
+ TBucketValue NextValue_ {0};
+ TBucketBounds Bounds_;
+ TBucketValues Values_;
+ };
+
+ class TDecoderUnistat {
+ private:
+ public:
+ explicit TDecoderUnistat(IMetricConsumer* consumer, IInputStream* is, TInstant ts)
+ : Consumer_{consumer}
+ , Timestamp_{ts} {
+ ReadJsonTree(is, &Json_, /* throw */ true);
+ }
+
+ void Decode() {
+ Y_ENSURE(Json_.IsArray(), "Expected array at the top level, but found " << Json_.GetType());
+
+ for (auto&& metric : Json_.GetArray()) {
+ Y_ENSURE(metric.IsArray(), "Metric must be an array");
+ auto&& arr = metric.GetArray();
+ Y_ENSURE(arr.size() == 2, "Metric must be an array of 2 elements");
+ auto&& name = arr[0];
+ auto&& value = arr[1];
+ MetricContext_ = {};
+
+ ParseName(name.GetString());
+
+ if (value.IsArray()) {
+ OnHistogram(value);
+ } else if (IsNumber(value)) {
+ OnScalar(value);
+ } else {
+ ythrow yexception() << "Expected list or number, but found " << value.GetType();
+ }
+
+ WriteValue();
+ }
+ }
+
+ private:
+ void OnScalar(const TJsonValue& jsonValue) {
+ if (MetricContext_.IsDeriv) {
+ MetricContext_.Type = EMetricType::RATE;
+ MetricContext_.Value = TMetricValue{ExtractUi64(jsonValue)};
+ } else {
+ MetricContext_.Type = EMetricType::GAUGE;
+ MetricContext_.Value = TMetricValue{ExtractDouble(jsonValue)};
+ }
+ }
+
+ void OnHistogram(const TJsonValue& jsonHist) {
+ if (MetricContext_.IsDeriv) {
+ MetricContext_.Type = EMetricType::HIST_RATE;
+ } else {
+ MetricContext_.Type = EMetricType::HIST;
+ }
+
+ auto histogramBuilder = THistogramBuilder();
+
+ for (auto&& bucket : jsonHist.GetArray()) {
+ Y_ENSURE(bucket.IsArray(), "Expected an array, but found " << bucket.GetType());
+ auto&& arr = bucket.GetArray();
+ Y_ENSURE(arr.size() == 2, "Histogram bucket must be an array of 2 elements");
+ const auto bound = ExtractDouble(arr[0]);
+ const auto weight = ExtractUi64(arr[1]);
+ histogramBuilder.Add(bound, weight);
+ }
+
+ MetricContext_.Histogram = histogramBuilder.Finalize();
+ MetricContext_.Value = TMetricValue{MetricContext_.Histogram.Get()};
+ }
+
+ bool IsDeriv(TStringBuf name) {
+ TStringBuf ignore, suffix;
+ name.RSplit('_', ignore, suffix);
+
+ Y_ENSURE(suffix.size() >= 3 && suffix.size() <= 5, "Disallowed suffix value: " << suffix);
+
+ if (suffix == TStringBuf("summ") || suffix == TStringBuf("hgram")) {
+ return true;
+ } else if (suffix == TStringBuf("max")) {
+ return false;
+ }
+
+ return suffix[0] == 'd';
+ }
+
+ void ParseName(TStringBuf value) {
+ TVector<TStringBuf> parts;
+ StringSplitter(value).Split(';').SkipEmpty().Collect(&parts);
+
+ Y_ENSURE(parts.size() >= 1 && parts.size() <= 16);
+
+ TStringBuf name = parts.back();
+ parts.pop_back();
+
+ Y_ENSURE(RE2::FullMatch(re2::StringPiece{name.data(), name.size()}, NAME_RE),
+ "Metric name " << name << " doesn't match regex " << NAME_RE.pattern());
+
+ MetricContext_.Name = name;
+ MetricContext_.IsDeriv = IsDeriv(MetricContext_.Name);
+
+ for (auto tag : parts) {
+ TStringBuf n, v;
+ tag.Split('=', n, v);
+ Y_ENSURE(n && v, "Unexpected tag format in " << tag);
+ MetricContext_.Labels.Add(n, v);
+ }
+ }
+
+ private:
+ void WriteValue() {
+ Consumer_->OnMetricBegin(MetricContext_.Type);
+
+ Consumer_->OnLabelsBegin();
+ Consumer_->OnLabel("sensor", TString{MetricContext_.Name});
+ for (auto&& l : MetricContext_.Labels) {
+ Consumer_->OnLabel(l.Name(), l.Value());
+ }
+
+ Consumer_->OnLabelsEnd();
+
+ switch (MetricContext_.Type) {
+ case EMetricType::GAUGE:
+ Consumer_->OnDouble(Timestamp_, MetricContext_.Value.AsDouble());
+ break;
+ case EMetricType::RATE:
+ Consumer_->OnUint64(Timestamp_, MetricContext_.Value.AsUint64());
+ break;
+ case EMetricType::HIST:
+ case EMetricType::HIST_RATE:
+ Consumer_->OnHistogram(Timestamp_, MetricContext_.Value.AsHistogram());
+ break;
+ case EMetricType::LOGHIST:
+ case EMetricType::DSUMMARY:
+ case EMetricType::IGAUGE:
+ case EMetricType::COUNTER:
+ case EMetricType::UNKNOWN:
+ ythrow yexception() << "Unexpected metric type: " << MetricContext_.Type;
+ }
+
+ Consumer_->OnMetricEnd();
+ }
+
+ private:
+ IMetricConsumer* Consumer_;
+ NJson::TJsonValue Json_;
+ TInstant Timestamp_;
+
+ struct {
+ TStringBuf Name;
+ EMetricType Type{EMetricType::UNKNOWN};
+ TMetricValue Value;
+ bool IsDeriv{false};
+ TLabels Labels;
+ IHistogramSnapshotPtr Histogram;
+ } MetricContext_;
+ };
+
+ }
+
+ void DecodeUnistat(TStringBuf data, IMetricConsumer* c, TInstant ts) {
+ c->OnStreamBegin();
+ DecodeUnistatToStream(data, c, ts);
+ c->OnStreamEnd();
+ }
+
+ void DecodeUnistatToStream(TStringBuf data, IMetricConsumer* c, TInstant ts) {
+ TMemoryInput in{data.data(), data.size()};
+ TDecoderUnistat decoder(c, &in, ts);
+ decoder.Decode();
+ }
+}
diff --git a/library/cpp/monlib/encode/unistat/unistat_ut.cpp b/library/cpp/monlib/encode/unistat/unistat_ut.cpp
new file mode 100644
index 0000000000..dbbc238bf3
--- /dev/null
+++ b/library/cpp/monlib/encode/unistat/unistat_ut.cpp
@@ -0,0 +1,223 @@
+#include "unistat.h"
+
+#include <library/cpp/monlib/encode/protobuf/protobuf.h>
+#include <library/cpp/monlib/metrics/labels.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NMonitoring;
+
+Y_UNIT_TEST_SUITE(TUnistatDecoderTest) {
+ Y_UNIT_TEST(ScalarMetric) {
+ constexpr auto input = TStringBuf(R"([["something_axxx", 42]])");
+
+ NProto::TMultiSamplesList samples;
+ auto encoder = EncoderProtobuf(&samples);
+
+ DecodeUnistat(input, encoder.Get());
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.SamplesSize(), 1);
+ auto sample = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(sample.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_VALUES_EQUAL(sample.PointsSize(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(sample.LabelsSize(), 1);
+
+ auto label = sample.GetLabels(0);
+ auto point = sample.GetPoints(0);
+ UNIT_ASSERT_VALUES_EQUAL(point.GetFloat64(), 42.);
+ UNIT_ASSERT_VALUES_EQUAL(label.GetName(), "sensor");
+ UNIT_ASSERT_VALUES_EQUAL(label.GetValue(), "something_axxx");
+ }
+
+ Y_UNIT_TEST(OverriddenTags) {
+ constexpr auto input = TStringBuf(R"([["ctype=foo;prj=bar;custom_tag=qwe;something_axxx", 42]])");
+
+ NProto::TMultiSamplesList samples;
+ auto encoder = EncoderProtobuf(&samples);
+
+ DecodeUnistat(input, encoder.Get());
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.SamplesSize(), 1);
+ auto sample = samples.GetSamples(0);
+ UNIT_ASSERT_VALUES_EQUAL(sample.PointsSize(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(sample.LabelsSize(), 4);
+
+ const auto& labels = sample.GetLabels();
+ TLabels actual;
+ for (auto&& l : labels) {
+ actual.Add(l.GetName(), l.GetValue());
+ }
+
+ TLabels expected{{"ctype", "foo"}, {"prj", "bar"}, {"custom_tag", "qwe"}, {"sensor", "something_axxx"}};
+
+ UNIT_ASSERT_VALUES_EQUAL(actual.size(), expected.size());
+ for (auto&& l : actual) {
+ UNIT_ASSERT(expected.Extract(l.Name())->Value() == l.Value());
+ }
+ }
+
+ Y_UNIT_TEST(ThrowsOnTopLevelObject) {
+ constexpr auto input = TStringBuf(R"({["something_axxx", 42]})");
+
+ NProto::TMultiSamplesList samples;
+ auto encoder = EncoderProtobuf(&samples);
+
+ UNIT_ASSERT_EXCEPTION(DecodeUnistat(input, encoder.Get()), yexception);
+ }
+
+ Y_UNIT_TEST(ThrowsOnUnwrappedMetric) {
+ constexpr auto input = TStringBuf(R"(["something_axxx", 42])");
+
+ NProto::TMultiSamplesList samples;
+ auto encoder = EncoderProtobuf(&samples);
+
+ UNIT_ASSERT_EXCEPTION(DecodeUnistat(input, encoder.Get()), yexception);
+ }
+
+ Y_UNIT_TEST(HistogramMetric) {
+ constexpr auto input = TStringBuf(R"([["something_hgram", [[0, 1], [200, 2], [500, 3]] ]])");
+
+ NProto::TMultiSamplesList samples;
+ auto encoder = EncoderProtobuf(&samples);
+
+ DecodeUnistat(input, encoder.Get());
+
+ auto sample = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(sample.GetMetricType(), NProto::HIST_RATE);
+ UNIT_ASSERT_VALUES_EQUAL(sample.PointsSize(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(sample.LabelsSize(), 1);
+
+ auto label = sample.GetLabels(0);
+ const auto point = sample.GetPoints(0);
+ const auto histogram = point.GetHistogram();
+ const auto size = histogram.BoundsSize();
+ UNIT_ASSERT_VALUES_EQUAL(size, 4);
+
+ const TVector<double> expectedBounds {0, 200, 500, std::numeric_limits<double>::max()};
+ const TVector<ui64> expectedValues {0, 1, 2, 3};
+
+ for (auto i = 0; i < 4; ++i) {
+ UNIT_ASSERT_VALUES_EQUAL(histogram.GetBounds(i), expectedBounds[i]);
+ UNIT_ASSERT_VALUES_EQUAL(histogram.GetValues(i), expectedValues[i]);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(label.GetName(), "sensor");
+ UNIT_ASSERT_VALUES_EQUAL(label.GetValue(), "something_hgram");
+ }
+
+ Y_UNIT_TEST(AbsoluteHistogram) {
+ constexpr auto input = TStringBuf(R"([["something_ahhh", [[0, 1], [200, 2], [500, 3]] ]])");
+
+ NProto::TMultiSamplesList samples;
+ auto encoder = EncoderProtobuf(&samples);
+
+ DecodeUnistat(input, encoder.Get());
+
+ auto sample = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(sample.GetMetricType(), NProto::HISTOGRAM);
+ UNIT_ASSERT_VALUES_EQUAL(sample.PointsSize(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(sample.LabelsSize(), 1);
+ }
+
+ Y_UNIT_TEST(AllowedMetricNames) {
+ NProto::TMultiSamplesList samples;
+ auto encoder = EncoderProtobuf(&samples);
+
+ {
+ constexpr auto input = TStringBuf(R"([["a/A-b/c_D/__G_dmmm", [[0, 1], [200, 2], [500, 3]] ]])");
+ UNIT_ASSERT_NO_EXCEPTION(DecodeUnistat(input, encoder.Get()));
+ }
+ }
+
+ Y_UNIT_TEST(DisallowedMetricNames) {
+ NProto::TMultiSamplesList samples;
+ auto encoder = EncoderProtobuf(&samples);
+
+ {
+ constexpr auto input = TStringBuf(R"([["someth!ng_ahhh", [[0, 1], [200, 2], [500, 3]] ]])");
+ UNIT_ASSERT_EXCEPTION(DecodeUnistat(input, encoder.Get()), yexception);
+ }
+
+ {
+ constexpr auto input = TStringBuf(R"([["foo_a", [[0, 1], [200, 2], [500, 3]] ]])");
+ UNIT_ASSERT_EXCEPTION(DecodeUnistat(input, encoder.Get()), yexception);
+ }
+
+ {
+ constexpr auto input = TStringBuf(R"([["foo_ahhh;tag=value", [[0, 1], [200, 2], [500, 3]] ]])");
+ UNIT_ASSERT_EXCEPTION(DecodeUnistat(input, encoder.Get()), yexception);
+ }
+ }
+
+ Y_UNIT_TEST(MultipleMetrics) {
+ constexpr auto input = TStringBuf(R"([["something_axxx", 42], ["some-other_dhhh", 53]])");
+
+ NProto::TMultiSamplesList samples;
+ auto encoder = EncoderProtobuf(&samples);
+
+ DecodeUnistat(input, encoder.Get());
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.SamplesSize(), 2);
+ auto sample = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(sample.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_VALUES_EQUAL(sample.PointsSize(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(sample.LabelsSize(), 1);
+
+ auto label = sample.GetLabels(0);
+ auto point = sample.GetPoints(0);
+ UNIT_ASSERT_VALUES_EQUAL(point.GetFloat64(), 42.);
+ UNIT_ASSERT_VALUES_EQUAL(label.GetName(), "sensor");
+ UNIT_ASSERT_VALUES_EQUAL(label.GetValue(), "something_axxx");
+
+ sample = samples.GetSamples(1);
+ UNIT_ASSERT_EQUAL(sample.GetMetricType(), NProto::RATE);
+ UNIT_ASSERT_VALUES_EQUAL(sample.PointsSize(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(sample.LabelsSize(), 1);
+
+ label = sample.GetLabels(0);
+ point = sample.GetPoints(0);
+ UNIT_ASSERT_VALUES_EQUAL(point.GetUint64(), 53);
+ UNIT_ASSERT_VALUES_EQUAL(label.GetName(), "sensor");
+ UNIT_ASSERT_VALUES_EQUAL(label.GetValue(), "some-other_dhhh");
+ }
+
+ Y_UNIT_TEST(UnderscoreName) {
+ constexpr auto input = TStringBuf(R"([["something_anything_dmmm", 42]])");
+
+ NProto::TMultiSamplesList samples;
+ auto encoder = EncoderProtobuf(&samples);
+ DecodeUnistat(input, encoder.Get());
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.SamplesSize(), 1);
+ auto sample = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(sample.GetMetricType(), NProto::RATE);
+ UNIT_ASSERT_VALUES_EQUAL(sample.PointsSize(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(sample.LabelsSize(), 1);
+
+ auto label = sample.GetLabels(0);
+ auto point = sample.GetPoints(0);
+ UNIT_ASSERT_VALUES_EQUAL(point.GetUint64(), 42);
+ UNIT_ASSERT_VALUES_EQUAL(label.GetName(), "sensor");
+ UNIT_ASSERT_VALUES_EQUAL(label.GetValue(), "something_anything_dmmm");
+ }
+
+ Y_UNIT_TEST(MaxAggr) {
+ constexpr auto input = TStringBuf(R"([["something_anything_max", 42]])");
+
+ NProto::TMultiSamplesList samples;
+ auto encoder = EncoderProtobuf(&samples);
+ DecodeUnistat(input, encoder.Get());
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.SamplesSize(), 1);
+ auto sample = samples.GetSamples(0);
+ UNIT_ASSERT_EQUAL(sample.GetMetricType(), NProto::GAUGE);
+ UNIT_ASSERT_VALUES_EQUAL(sample.PointsSize(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(sample.LabelsSize(), 1);
+
+ auto label = sample.GetLabels(0);
+ auto point = sample.GetPoints(0);
+ UNIT_ASSERT_VALUES_EQUAL(point.GetFloat64(), 42.);
+ UNIT_ASSERT_VALUES_EQUAL(label.GetName(), "sensor");
+ UNIT_ASSERT_VALUES_EQUAL(label.GetValue(), "something_anything_max");
+ }
+}
diff --git a/library/cpp/monlib/encode/unistat/ut/ya.make b/library/cpp/monlib/encode/unistat/ut/ya.make
new file mode 100644
index 0000000000..a652139f45
--- /dev/null
+++ b/library/cpp/monlib/encode/unistat/ut/ya.make
@@ -0,0 +1,16 @@
+UNITTEST_FOR(library/cpp/monlib/encode/unistat)
+
+OWNER(
+ msherbakov
+ g:solomon
+)
+
+SRCS(
+ unistat_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/monlib/encode/protobuf
+)
+
+END()
diff --git a/library/cpp/monlib/encode/unistat/ya.make b/library/cpp/monlib/encode/unistat/ya.make
new file mode 100644
index 0000000000..4ac2edadf4
--- /dev/null
+++ b/library/cpp/monlib/encode/unistat/ya.make
@@ -0,0 +1,18 @@
+LIBRARY()
+
+OWNER(
+ msherbakov
+ g:solomon
+)
+
+PEERDIR(
+ contrib/libs/re2
+ library/cpp/json
+ library/cpp/monlib/metrics
+)
+
+SRCS(
+ unistat_decoder.cpp
+)
+
+END()
diff --git a/library/cpp/monlib/encode/ut/ya.make b/library/cpp/monlib/encode/ut/ya.make
new file mode 100644
index 0000000000..1990386d76
--- /dev/null
+++ b/library/cpp/monlib/encode/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/monlib/encode)
+
+OWNER(
+ jamel
+ g:solomon
+)
+
+SRCS(
+ format_ut.cpp
+)
+
+END()
diff --git a/library/cpp/monlib/encode/ya.make b/library/cpp/monlib/encode/ya.make
new file mode 100644
index 0000000000..d1bb09f07b
--- /dev/null
+++ b/library/cpp/monlib/encode/ya.make
@@ -0,0 +1,20 @@
+LIBRARY()
+
+OWNER(
+ g:solomon
+ jamel
+)
+
+SRCS(
+ encoder.cpp
+ encoder_state.cpp
+ format.cpp
+)
+
+PEERDIR(
+ library/cpp/monlib/metrics
+)
+
+GENERATE_ENUM_SERIALIZATION_WITH_HEADER(encoder_state_enum.h)
+
+END()
diff --git a/library/cpp/monlib/exception/exception.cpp b/library/cpp/monlib/exception/exception.cpp
new file mode 100644
index 0000000000..5a8d53ceb0
--- /dev/null
+++ b/library/cpp/monlib/exception/exception.cpp
@@ -0,0 +1 @@
+#include "exception.h"
diff --git a/library/cpp/monlib/exception/exception.h b/library/cpp/monlib/exception/exception.h
new file mode 100644
index 0000000000..027c22b27d
--- /dev/null
+++ b/library/cpp/monlib/exception/exception.h
@@ -0,0 +1,13 @@
+#pragma once
+
+
+namespace NMonitoring {
+
+#define MONLIB_ENSURE_EX(CONDITION, THROW_EXPRESSION) \
+ do { \
+ if (Y_UNLIKELY(!(CONDITION))) { \
+ throw THROW_EXPRESSION; \
+ } \
+ } while (false)
+
+} // namespace NSolomon
diff --git a/library/cpp/monlib/exception/ya.make b/library/cpp/monlib/exception/ya.make
new file mode 100644
index 0000000000..78660711d3
--- /dev/null
+++ b/library/cpp/monlib/exception/ya.make
@@ -0,0 +1,12 @@
+LIBRARY()
+
+OWNER(g:solomon)
+
+SRCS(
+ exception.cpp
+)
+
+PEERDIR(
+)
+
+END()
diff --git a/library/cpp/monlib/messagebus/mon_messagebus.cpp b/library/cpp/monlib/messagebus/mon_messagebus.cpp
new file mode 100644
index 0000000000..355b4386cd
--- /dev/null
+++ b/library/cpp/monlib/messagebus/mon_messagebus.cpp
@@ -0,0 +1,11 @@
+#include <library/cpp/messagebus/www/www.h>
+
+#include "mon_messagebus.h"
+
+using namespace NMonitoring;
+
+void TBusNgMonPage::Output(NMonitoring::IMonHttpRequest& request) {
+ NBus::TBusWww::TOptionalParams params;
+ params.ParentLinks.push_back(NBus::TBusWww::TLink{"/", request.GetServiceTitle()});
+ BusWww->ServeHttp(request.Output(), request.GetParams(), params);
+}
diff --git a/library/cpp/monlib/messagebus/mon_messagebus.h b/library/cpp/monlib/messagebus/mon_messagebus.h
new file mode 100644
index 0000000000..e1fa73c69f
--- /dev/null
+++ b/library/cpp/monlib/messagebus/mon_messagebus.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <library/cpp/messagebus/ybus.h>
+#include <library/cpp/messagebus/www/www.h>
+
+#include <library/cpp/monlib/service/pages/mon_page.h>
+
+namespace NMonitoring {
+ template <class TBusSmth>
+ class TBusSmthMonPage: public NMonitoring::IMonPage {
+ private:
+ TBusSmth* Smth;
+
+ public:
+ explicit TBusSmthMonPage(const TString& name, const TString& title, TBusSmth* smth)
+ : IMonPage("msgbus/" + name, title)
+ , Smth(smth)
+ {
+ }
+ void Output(NMonitoring::IMonHttpRequest& request) override {
+ Y_UNUSED(request);
+ request.Output() << NMonitoring::HTTPOKHTML;
+ request.Output() << "<h2>" << Title << "</h2>";
+ request.Output() << "<pre>";
+ request.Output() << Smth->GetStatus();
+ request.Output() << "</pre>";
+ }
+ };
+
+ using TBusQueueMonPage = TBusSmthMonPage<NBus::TBusMessageQueue>;
+ using TBusModuleMonPage = TBusSmthMonPage<NBus::TBusModule>;
+
+ class TBusNgMonPage: public NMonitoring::IMonPage {
+ public:
+ TIntrusivePtr<NBus::TBusWww> BusWww;
+
+ public:
+ TBusNgMonPage()
+ : IMonPage("messagebus", "MessageBus")
+ , BusWww(new NBus::TBusWww)
+ {
+ }
+ void Output(NMonitoring::IMonHttpRequest& request) override;
+ };
+
+}
diff --git a/library/cpp/monlib/messagebus/mon_service_messagebus.cpp b/library/cpp/monlib/messagebus/mon_service_messagebus.cpp
new file mode 100644
index 0000000000..4dd144ebe8
--- /dev/null
+++ b/library/cpp/monlib/messagebus/mon_service_messagebus.cpp
@@ -0,0 +1,8 @@
+#include "mon_service_messagebus.h"
+
+using namespace NMonitoring;
+
+TMonServiceMessageBus::TMonServiceMessageBus(ui16 port, const TString& title)
+ : TMonService2(port, title)
+{
+}
diff --git a/library/cpp/monlib/messagebus/mon_service_messagebus.h b/library/cpp/monlib/messagebus/mon_service_messagebus.h
new file mode 100644
index 0000000000..fe791e8a9b
--- /dev/null
+++ b/library/cpp/monlib/messagebus/mon_service_messagebus.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "mon_messagebus.h"
+
+#include <library/cpp/monlib/service/monservice.h>
+
+#include <util/system/mutex.h>
+
+namespace NMonitoring {
+ class TMonServiceMessageBus: public TMonService2 {
+ private:
+ TMutex Mtx;
+ TIntrusivePtr<NMonitoring::TBusNgMonPage> BusNgMonPage;
+
+ public:
+ TMonServiceMessageBus(ui16 port, const TString& title);
+
+ private:
+ NBus::TBusWww* RegisterBusNgMonPage() {
+ TGuard<TMutex> g(Mtx);
+ if (!BusNgMonPage) {
+ BusNgMonPage = new NMonitoring::TBusNgMonPage();
+ Register(BusNgMonPage.Get());
+ }
+ return BusNgMonPage->BusWww.Get();
+ }
+
+ public:
+ void RegisterClientSession(NBus::TBusClientSessionPtr clientSession) {
+ RegisterBusNgMonPage()->RegisterClientSession(clientSession);
+ }
+
+ void RegisterServerSession(NBus::TBusServerSessionPtr serverSession) {
+ RegisterBusNgMonPage()->RegisterServerSession(serverSession);
+ }
+
+ void RegisterQueue(NBus::TBusMessageQueuePtr queue) {
+ RegisterBusNgMonPage()->RegisterQueue(queue);
+ }
+
+ void RegisterModule(NBus::TBusModule* module) {
+ RegisterBusNgMonPage()->RegisterModule(module);
+ }
+ };
+
+}
diff --git a/library/cpp/monlib/messagebus/ya.make b/library/cpp/monlib/messagebus/ya.make
new file mode 100644
index 0000000000..a0b5362296
--- /dev/null
+++ b/library/cpp/monlib/messagebus/ya.make
@@ -0,0 +1,16 @@
+LIBRARY()
+
+OWNER(g:solomon)
+
+SRCS(
+ mon_messagebus.cpp
+ mon_service_messagebus.cpp
+)
+
+PEERDIR(
+ library/cpp/messagebus
+ library/cpp/messagebus/www
+ library/cpp/monlib/dynamic_counters
+)
+
+END()
diff --git a/library/cpp/monlib/metrics/atomics_array.h b/library/cpp/monlib/metrics/atomics_array.h
new file mode 100644
index 0000000000..f19aebf291
--- /dev/null
+++ b/library/cpp/monlib/metrics/atomics_array.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+
+#include <atomic>
+
+namespace NMonitoring {
+ class TAtomicsArray {
+ public:
+ explicit TAtomicsArray(size_t size)
+ : Values_(new std::atomic<ui64>[size])
+ , Size_(size)
+ {
+ for (size_t i = 0; i < Size_; i++) {
+ Values_[i].store(0, std::memory_order_relaxed);
+ }
+ }
+
+ ui64 operator[](size_t index) const noexcept {
+ Y_VERIFY_DEBUG(index < Size_);
+ return Values_[index].load(std::memory_order_relaxed);
+ }
+
+ size_t Size() const noexcept {
+ return Size_;
+ }
+
+ void Add(size_t index, ui32 count) noexcept {
+ Y_VERIFY_DEBUG(index < Size_);
+ Values_[index].fetch_add(count, std::memory_order_relaxed);
+ }
+
+ void Reset() noexcept {
+ for (size_t i = 0; i < Size_; i++) {
+ Values_[i].store(0, std::memory_order_relaxed);
+ }
+ }
+
+ TVector<ui64> Copy() const {
+ TVector<ui64> copy(Reserve(Size_));
+ for (size_t i = 0; i < Size_; i++) {
+ copy.push_back(Values_[i].load(std::memory_order_relaxed));
+ }
+ return copy;
+ }
+
+ private:
+ TArrayHolder<std::atomic<ui64>> Values_;
+ size_t Size_;
+ };
+}
diff --git a/library/cpp/monlib/metrics/ewma.cpp b/library/cpp/monlib/metrics/ewma.cpp
new file mode 100644
index 0000000000..8a296c3225
--- /dev/null
+++ b/library/cpp/monlib/metrics/ewma.cpp
@@ -0,0 +1,150 @@
+#include "ewma.h"
+#include "metric.h"
+
+#include <atomic>
+#include <cmath>
+
+namespace NMonitoring {
+namespace {
+ constexpr auto DEFAULT_INTERVAL = TDuration::Seconds(5);
+
+ const double ALPHA1 = 1. - std::exp(-double(DEFAULT_INTERVAL.Seconds())/60./1.);
+ const double ALPHA5 = 1. - std::exp(-double(DEFAULT_INTERVAL.Seconds())/60./5.);
+ const double ALPHA15 = 1. - std::exp(-double(DEFAULT_INTERVAL.Seconds())/60./15.);
+
+ class TExpMovingAverage final: public IExpMovingAverage {
+ public:
+ explicit TExpMovingAverage(IGauge* metric, double alpha, TDuration interval)
+ : Metric_{metric}
+ , Alpha_{alpha}
+ , Interval_{interval.Seconds()}
+ {
+ Y_VERIFY(metric != nullptr, "Passing nullptr metric is not allowed");
+ }
+
+ ~TExpMovingAverage() override = default;
+
+ // This method NOT thread safe
+ void Tick() override {
+ const auto current = Uncounted_.fetch_and(0);
+ const double instantRate = double(current) / Interval_;
+
+ if (Y_UNLIKELY(!IsInitialized())) {
+ Metric_->Set(instantRate);
+ Init_ = true;
+ } else {
+ const double currentRate = Metric_->Get();
+ Metric_->Set(Alpha_ * (instantRate - currentRate) + currentRate);
+ }
+
+ }
+
+ void Update(i64 value) override {
+ Uncounted_ += value;
+ }
+
+ double Rate() const override {
+ return Metric_->Get();
+ }
+
+ void Reset() override {
+ Init_ = false;
+ Uncounted_ = 0;
+ }
+
+ private:
+ bool IsInitialized() const {
+ return Init_;
+ }
+
+ private:
+ std::atomic<i64> Uncounted_{0};
+ std::atomic<bool> Init_{false};
+
+ IGauge* Metric_{nullptr};
+ double Alpha_;
+ ui64 Interval_;
+ };
+
+ struct TFakeEwma: IExpMovingAverage {
+ void Tick() override {}
+ void Update(i64) override {}
+ double Rate() const override { return 0; }
+ void Reset() override {}
+ };
+
+} // namespace
+
+ TEwmaMeter::TEwmaMeter()
+ : Ewma_{MakeHolder<TFakeEwma>()}
+ {
+ }
+
+ TEwmaMeter::TEwmaMeter(IExpMovingAveragePtr&& ewma)
+ : Ewma_{std::move(ewma)}
+ {
+ }
+
+ TEwmaMeter::TEwmaMeter(TEwmaMeter&& other) {
+ if (&other == this) {
+ return;
+ }
+
+ *this = std::move(other);
+ }
+
+ TEwmaMeter& TEwmaMeter::operator=(TEwmaMeter&& other) {
+ Ewma_ = std::move(other.Ewma_);
+ LastTick_.store(other.LastTick_);
+ return *this;
+ }
+
+ void TEwmaMeter::TickIfNeeded() {
+ constexpr ui64 INTERVAL_SECONDS = DEFAULT_INTERVAL.Seconds();
+
+ const auto now = TInstant::Now().Seconds();
+ ui64 old = LastTick_.load();
+ const auto secondsSinceLastTick = now - old;
+
+ if (secondsSinceLastTick > INTERVAL_SECONDS) {
+ // round to the interval grid
+ const ui64 newLast = now - (secondsSinceLastTick % INTERVAL_SECONDS);
+ if (LastTick_.compare_exchange_strong(old, newLast)) {
+ for (size_t i = 0; i < secondsSinceLastTick / INTERVAL_SECONDS; ++i) {
+ Ewma_->Tick();
+ }
+ }
+ }
+ }
+
+ void TEwmaMeter::Mark() {
+ TickIfNeeded();
+ Ewma_->Update(1);
+ }
+
+ void TEwmaMeter::Mark(i64 value) {
+ TickIfNeeded();
+ Ewma_->Update(value);
+ }
+
+ double TEwmaMeter::Get() {
+ TickIfNeeded();
+ return Ewma_->Rate();
+ }
+
+ IExpMovingAveragePtr OneMinuteEwma(IGauge* metric) {
+ return MakeHolder<TExpMovingAverage>(metric, ALPHA1, DEFAULT_INTERVAL);
+ }
+
+ IExpMovingAveragePtr FiveMinuteEwma(IGauge* metric) {
+ return MakeHolder<TExpMovingAverage>(metric, ALPHA5, DEFAULT_INTERVAL);
+ }
+
+ IExpMovingAveragePtr FiveteenMinuteEwma(IGauge* metric) {
+ return MakeHolder<TExpMovingAverage>(metric, ALPHA15, DEFAULT_INTERVAL);
+ }
+
+ IExpMovingAveragePtr CreateEwma(IGauge* metric, double alpha, TDuration interval) {
+ return MakeHolder<TExpMovingAverage>(metric, alpha, interval);
+ }
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/metrics/ewma.h b/library/cpp/monlib/metrics/ewma.h
new file mode 100644
index 0000000000..9b2dad7cc5
--- /dev/null
+++ b/library/cpp/monlib/metrics/ewma.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <util/datetime/base.h>
+#include <util/generic/ptr.h>
+
+#include <atomic>
+
+namespace NMonitoring {
+ class IGauge;
+
+ class IExpMovingAverage {
+ public:
+ virtual ~IExpMovingAverage() = default;
+ virtual void Tick() = 0;
+ virtual void Update(i64 value) = 0;
+ virtual double Rate() const = 0;
+ virtual void Reset() = 0;
+ };
+
+ using IExpMovingAveragePtr = THolder<IExpMovingAverage>;
+
+ class TEwmaMeter {
+ public:
+ // Creates a fake EWMA that will always return 0. Mostly for usage convenience
+ TEwmaMeter();
+ explicit TEwmaMeter(IExpMovingAveragePtr&& ewma);
+
+ TEwmaMeter(TEwmaMeter&& other);
+ TEwmaMeter& operator=(TEwmaMeter&& other);
+
+ void Mark();
+ void Mark(i64 value);
+
+ double Get();
+
+ private:
+ void TickIfNeeded();
+
+ private:
+ IExpMovingAveragePtr Ewma_;
+ std::atomic<ui64> LastTick_{TInstant::Now().Seconds()};
+ };
+
+ IExpMovingAveragePtr OneMinuteEwma(IGauge* gauge);
+ IExpMovingAveragePtr FiveMinuteEwma(IGauge* gauge);
+ IExpMovingAveragePtr FiveteenMinuteEwma(IGauge* gauge);
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/metrics/ewma_ut.cpp b/library/cpp/monlib/metrics/ewma_ut.cpp
new file mode 100644
index 0000000000..01ef2478f7
--- /dev/null
+++ b/library/cpp/monlib/metrics/ewma_ut.cpp
@@ -0,0 +1,112 @@
+#include "ewma.h"
+#include "metric.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+
+using namespace NMonitoring;
+
+const auto EPS = 1e-6;
+void ElapseMinute(IExpMovingAverage& ewma) {
+ for (auto i = 0; i < 12; ++i) {
+ ewma.Tick();
+ }
+}
+
+Y_UNIT_TEST_SUITE(TEwmaTest) {
+ Y_UNIT_TEST(OneMinute) {
+ TGauge gauge;
+
+ auto ewma = OneMinuteEwma(&gauge);
+ ewma->Update(3);
+ ewma->Tick();
+
+ TVector<double> expectedValues {
+ 0.6,
+ 0.22072766,
+ 0.08120117,
+ 0.02987224,
+ 0.01098938,
+ 0.00404277,
+ 0.00148725,
+ 0.00054713,
+ 0.00020128,
+ 0.00007405,
+ 0.00002724,
+ 0.00001002,
+ 0.00000369,
+ 0.00000136,
+ 0.00000050,
+ 0.00000018,
+ };
+
+ for (auto expectedValue : expectedValues) {
+ UNIT_ASSERT_DOUBLES_EQUAL(ewma->Rate(), expectedValue, EPS);
+ ElapseMinute(*ewma);
+ }
+ }
+
+ Y_UNIT_TEST(FiveMinutes) {
+ TGauge gauge;
+
+ auto ewma = FiveMinuteEwma(&gauge);
+ ewma->Update(3);
+ ewma->Tick();
+
+ TVector<double> expectedValues {
+ 0.6,
+ 0.49123845,
+ 0.40219203,
+ 0.32928698,
+ 0.26959738,
+ 0.22072766,
+ 0.18071653,
+ 0.14795818,
+ 0.12113791,
+ 0.09917933,
+ 0.08120117,
+ 0.06648190,
+ 0.05443077,
+ 0.04456415,
+ 0.03648604,
+ 0.02987224,
+ };
+
+ for (auto expectedValue : expectedValues) {
+ UNIT_ASSERT_DOUBLES_EQUAL(ewma->Rate(), expectedValue, EPS);
+ ElapseMinute(*ewma);
+ }
+ }
+
+ Y_UNIT_TEST(FiveteenMinutes) {
+ TGauge gauge;
+
+ auto ewma = FiveteenMinuteEwma(&gauge);
+ ewma->Update(3);
+ ewma->Tick();
+
+ TVector<double> expectedValues {
+ 0.6,
+ 0.56130419,
+ 0.52510399,
+ 0.49123845,
+ 0.45955700,
+ 0.42991879,
+ 0.40219203,
+ 0.37625345,
+ 0.35198773,
+ 0.32928698,
+ 0.30805027,
+ 0.28818318,
+ 0.26959738,
+ 0.25221023,
+ 0.23594443,
+ 0.22072766,
+ };
+
+ for (auto expectedValue : expectedValues) {
+ UNIT_ASSERT_DOUBLES_EQUAL(ewma->Rate(), expectedValue, EPS);
+ ElapseMinute(*ewma);
+ }
+ }
+};
diff --git a/library/cpp/monlib/metrics/fake.cpp b/library/cpp/monlib/metrics/fake.cpp
new file mode 100644
index 0000000000..b6f5e37af8
--- /dev/null
+++ b/library/cpp/monlib/metrics/fake.cpp
@@ -0,0 +1,100 @@
+#include "fake.h"
+
+namespace NMonitoring {
+
+ IGauge* TFakeMetricRegistry::Gauge(ILabelsPtr labels) {
+ return Metric<TFakeGauge, EMetricType::GAUGE>(std::move(labels));
+ }
+
+ ILazyGauge* TFakeMetricRegistry::LazyGauge(ILabelsPtr labels, std::function<double()> supplier) {
+ Y_UNUSED(supplier);
+ return Metric<TFakeLazyGauge, EMetricType::GAUGE>(std::move(labels));
+ }
+
+ IIntGauge* TFakeMetricRegistry::IntGauge(ILabelsPtr labels) {
+ return Metric<TFakeIntGauge, EMetricType::IGAUGE>(std::move(labels));
+ }
+
+ ILazyIntGauge* TFakeMetricRegistry::LazyIntGauge(ILabelsPtr labels, std::function<i64()> supplier) {
+ Y_UNUSED(supplier);
+ return Metric<TFakeLazyIntGauge, EMetricType::IGAUGE>(std::move(labels));
+ }
+
+ ICounter* TFakeMetricRegistry::Counter(ILabelsPtr labels) {
+ return Metric<TFakeCounter, EMetricType::COUNTER>(std::move(labels));
+ }
+
+ ILazyCounter* TFakeMetricRegistry::LazyCounter(ILabelsPtr labels, std::function<ui64()> supplier) {
+ Y_UNUSED(supplier);
+ return Metric<TFakeLazyCounter, EMetricType::COUNTER>(std::move(labels));
+ }
+
+ IRate* TFakeMetricRegistry::Rate(ILabelsPtr labels) {
+ return Metric<TFakeRate, EMetricType::RATE>(std::move(labels));
+ }
+
+ ILazyRate* TFakeMetricRegistry::LazyRate(ILabelsPtr labels, std::function<ui64()> supplier) {
+ Y_UNUSED(supplier);
+ return Metric<TFakeLazyRate, EMetricType::RATE>(std::move(labels));
+ }
+
+ IHistogram* TFakeMetricRegistry::HistogramCounter(ILabelsPtr labels, IHistogramCollectorPtr collector) {
+ Y_UNUSED(collector);
+ return Metric<TFakeHistogram, EMetricType::HIST>(std::move(labels), false);
+ }
+
+ void TFakeMetricRegistry::RemoveMetric(const ILabels& labels) noexcept {
+ TWriteGuard g{Lock_};
+ Metrics_.erase(labels);
+ }
+
+ void TFakeMetricRegistry::Accept(TInstant time, IMetricConsumer* consumer) const {
+ Y_UNUSED(time);
+ consumer->OnStreamBegin();
+ consumer->OnStreamEnd();
+ }
+
+ IHistogram* TFakeMetricRegistry::HistogramRate(ILabelsPtr labels, IHistogramCollectorPtr collector) {
+ Y_UNUSED(collector);
+ return Metric<TFakeHistogram, EMetricType::HIST_RATE>(std::move(labels), true);
+ }
+
+ void TFakeMetricRegistry::Append(TInstant time, IMetricConsumer* consumer) const {
+ Y_UNUSED(time, consumer);
+ }
+
+ const TLabels& TFakeMetricRegistry::CommonLabels() const noexcept {
+ return CommonLabels_;
+ }
+
+ template <typename TMetric, EMetricType type, typename TLabelsType, typename... Args>
+ TMetric* TFakeMetricRegistry::Metric(TLabelsType&& labels, Args&&... args) {
+ {
+ TReadGuard g{Lock_};
+
+ auto it = Metrics_.find(labels);
+ if (it != Metrics_.end()) {
+ Y_ENSURE(it->second->Type() == type, "cannot create metric " << labels
+ << " with type " << MetricTypeToStr(type)
+ << ", because registry already has same metric with type " << MetricTypeToStr(it->second->Type()));
+ return static_cast<TMetric*>(it->second.Get());
+ }
+ }
+
+ {
+ TWriteGuard g{Lock_};
+
+ IMetricPtr metric = MakeHolder<TMetric>(std::forward<Args>(args)...);
+
+ // decltype(Metrics_)::iterator breaks build on windows
+ THashMap<ILabelsPtr, IMetricPtr>::iterator it;
+ if constexpr (!std::is_convertible_v<TLabelsType, ILabelsPtr>) {
+ it = Metrics_.emplace(new TLabels{std::forward<TLabelsType>(labels)}, std::move(metric)).first;
+ } else {
+ it = Metrics_.emplace(std::forward<TLabelsType>(labels), std::move(metric)).first;
+ }
+
+ return static_cast<TMetric*>(it->second.Get());
+ }
+ }
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/metrics/fake.h b/library/cpp/monlib/metrics/fake.h
new file mode 100644
index 0000000000..61ba4f2bd4
--- /dev/null
+++ b/library/cpp/monlib/metrics/fake.h
@@ -0,0 +1,165 @@
+#pragma once
+
+#include "metric.h"
+#include "metric_registry.h"
+
+namespace NMonitoring {
+ class TFakeMetricRegistry: public IMetricRegistry {
+ public:
+ TFakeMetricRegistry() noexcept
+ : CommonLabels_{0}
+ {
+ }
+
+ explicit TFakeMetricRegistry(TLabels commonLabels) noexcept
+ : CommonLabels_{std::move(commonLabels)}
+ {
+ }
+
+ IGauge* Gauge(ILabelsPtr labels) override;
+ ILazyGauge* LazyGauge(ILabelsPtr labels, std::function<double()> supplier) override;
+ IIntGauge* IntGauge(ILabelsPtr labels) override;
+ ILazyIntGauge* LazyIntGauge(ILabelsPtr labels, std::function<i64()> supplier) override;
+ ICounter* Counter(ILabelsPtr labels) override;
+ ILazyCounter* LazyCounter(ILabelsPtr labels, std::function<ui64()> supplier) override;
+ IRate* Rate(ILabelsPtr labels) override;
+ ILazyRate* LazyRate(ILabelsPtr labels, std::function<ui64()> supplier) override;
+
+ IHistogram* HistogramCounter(
+ ILabelsPtr labels,
+ IHistogramCollectorPtr collector) override;
+
+ IHistogram* HistogramRate(
+ ILabelsPtr labels,
+ IHistogramCollectorPtr collector) override;
+ void Accept(TInstant time, IMetricConsumer* consumer) const override;
+ void Append(TInstant time, IMetricConsumer* consumer) const override;
+
+ const TLabels& CommonLabels() const noexcept override;
+ void RemoveMetric(const ILabels& labels) noexcept override;
+
+ private:
+ TRWMutex Lock_;
+ THashMap<ILabelsPtr, IMetricPtr> Metrics_;
+
+ template <typename TMetric, EMetricType type, typename TLabelsType, typename... Args>
+ TMetric* Metric(TLabelsType&& labels, Args&&... args);
+
+ const TLabels CommonLabels_;
+ };
+
+ template <typename TBase>
+ struct TFakeAcceptor: TBase {
+ void Accept(TInstant time, IMetricConsumer* consumer) const override {
+ Y_UNUSED(time, consumer);
+ }
+ };
+
+ struct TFakeIntGauge final: public TFakeAcceptor<IIntGauge> {
+ i64 Add(i64 n) noexcept override {
+ Y_UNUSED(n);
+ return 0;
+ }
+
+ void Set(i64 n) noexcept override {
+ Y_UNUSED(n);
+ }
+
+ i64 Get() const noexcept override {
+ return 0;
+ }
+ };
+
+ struct TFakeLazyIntGauge final: public TFakeAcceptor<ILazyIntGauge> {
+ i64 Get() const noexcept override {
+ return 0;
+ }
+ };
+
+ struct TFakeRate final: public TFakeAcceptor<IRate> {
+ ui64 Add(ui64 n) noexcept override {
+ Y_UNUSED(n);
+ return 0;
+ }
+
+ ui64 Get() const noexcept override {
+ return 0;
+ }
+
+ void Reset() noexcept override {
+ }
+ };
+
+ struct TFakeLazyRate final: public TFakeAcceptor<ILazyRate> {
+ ui64 Get() const noexcept override {
+ return 0;
+ }
+ };
+
+ struct TFakeGauge final: public TFakeAcceptor<IGauge> {
+ double Add(double n) noexcept override {
+ Y_UNUSED(n);
+ return 0;
+ }
+
+ void Set(double n) noexcept override {
+ Y_UNUSED(n);
+ }
+
+ double Get() const noexcept override {
+ return 0;
+ }
+ };
+
+ struct TFakeLazyGauge final: public TFakeAcceptor<ILazyGauge> {
+ double Get() const noexcept override {
+ return 0;
+ }
+ };
+
+ struct TFakeHistogram final: public IHistogram {
+ TFakeHistogram(bool isRate = false)
+ : IHistogram{isRate}
+ {
+ }
+
+ void Record(double value) override {
+ Y_UNUSED(value);
+ }
+
+ void Record(double value, ui32 count) override {
+ Y_UNUSED(value, count);
+ }
+
+ IHistogramSnapshotPtr TakeSnapshot() const override {
+ return nullptr;
+ }
+
+ void Accept(TInstant time, IMetricConsumer* consumer) const override {
+ Y_UNUSED(time, consumer);
+ }
+
+ void Reset() override {
+ }
+ };
+
+ struct TFakeCounter final: public TFakeAcceptor<ICounter> {
+ ui64 Add(ui64 n) noexcept override {
+ Y_UNUSED(n);
+ return 0;
+ }
+
+ ui64 Get() const noexcept override {
+ return 0;
+ }
+
+ void Reset() noexcept override {
+ }
+ };
+
+ struct TFakeLazyCounter final: public TFakeAcceptor<ILazyCounter> {
+ ui64 Get() const noexcept override {
+ return 0;
+ }
+ };
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/metrics/fake_ut.cpp b/library/cpp/monlib/metrics/fake_ut.cpp
new file mode 100644
index 0000000000..c3368ca302
--- /dev/null
+++ b/library/cpp/monlib/metrics/fake_ut.cpp
@@ -0,0 +1,34 @@
+#include "fake.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/ptr.h>
+
+using namespace NMonitoring;
+
+Y_UNIT_TEST_SUITE(TFakeTest) {
+
+ Y_UNIT_TEST(CreateOnStack) {
+ TFakeMetricRegistry registry;
+ }
+
+ Y_UNIT_TEST(CreateOnHeap) {
+ auto registry = MakeAtomicShared<TFakeMetricRegistry>();
+ UNIT_ASSERT(registry);
+ }
+
+ Y_UNIT_TEST(Gauge) {
+ TFakeMetricRegistry registry(TLabels{{"common", "label"}});
+
+ IGauge* g = registry.Gauge(MakeLabels({{"my", "gauge"}}));
+ UNIT_ASSERT(g);
+
+ UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 0.0, 1E-6);
+ g->Set(12.34);
+ UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 0.0, 1E-6); // no changes
+
+ double val = g->Add(1.2);
+ UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 0.0, 1E-6);
+ UNIT_ASSERT_DOUBLES_EQUAL(val, 0.0, 1E-6);
+ }
+}
diff --git a/library/cpp/monlib/metrics/fwd.h b/library/cpp/monlib/metrics/fwd.h
new file mode 100644
index 0000000000..b4327ee5d5
--- /dev/null
+++ b/library/cpp/monlib/metrics/fwd.h
@@ -0,0 +1,40 @@
+#pragma once
+
+namespace NMonitoring {
+
+ struct ILabel;
+ struct ILabels;
+
+ class ICounter;
+ class IGauge;
+ class IHistogram;
+ class IIntGauge;
+ class ILazyCounter;
+ class ILazyGauge;
+ class ILazyIntGauge;
+ class ILazyRate;
+ class IMetric;
+ class IRate;
+ class TCounter;
+ class TGauge;
+ class THistogram;
+ class TIntGauge;
+ class TLazyCounter;
+ class TLazyGauge;
+ class TLazyIntGauge;
+ class TLazyRate;
+ class TRate;
+
+ class IMetricSupplier;
+ class IMetricFactory;
+ class IMetricConsumer;
+
+ class IMetricRegistry;
+ class TMetricRegistry;
+
+ class IHistogramCollector;
+ class IHistogramSnapshot;
+
+ class IExpMovingAverage;
+
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/metrics/histogram_collector.h b/library/cpp/monlib/metrics/histogram_collector.h
new file mode 100644
index 0000000000..9f6bbbdfb7
--- /dev/null
+++ b/library/cpp/monlib/metrics/histogram_collector.h
@@ -0,0 +1,119 @@
+#pragma once
+
+#include "histogram_snapshot.h"
+
+namespace NMonitoring {
+
+ ///////////////////////////////////////////////////////////////////////////
+ // IHistogramCollector
+ ///////////////////////////////////////////////////////////////////////////
+ class IHistogramCollector {
+ public:
+ virtual ~IHistogramCollector() = default;
+
+ /**
+ * Store {@code count} times given {@code value} in this collector.
+ */
+ virtual void Collect(double value, ui32 count) = 0;
+
+ /**
+ * Store given {@code value} in this collector.
+ */
+ void Collect(double value) {
+ Collect(value, 1);
+ }
+
+ /**
+ * Add counts from snapshot into this collector
+ */
+ void Collect(const IHistogramSnapshot& snapshot) {
+ for (ui32 i = 0; i < snapshot.Count(); i++) {
+ Collect(snapshot.UpperBound(i), snapshot.Value(i));
+ }
+ }
+
+ /**
+ * Reset collector values
+ */
+ virtual void Reset() = 0;
+
+ /**
+ * @return snapshot of the state of this collector.
+ */
+ virtual IHistogramSnapshotPtr Snapshot() const = 0;
+ };
+
+ using IHistogramCollectorPtr = THolder<IHistogramCollector>;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // free functions
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * <p>Creates histogram collector for a set of buckets with arbitrary
+ * bounds.</p>
+ *
+ * <p>Defines {@code bounds.size() + 1} buckets with these boundaries for
+ * bucket i:</p>
+ * <ul>
+ * <li>Upper bound (0 <= i < N-1): {@code bounds[i]}</li>
+ * <li>Lower bound (1 <= i < N): {@code bounds[i - 1]}</li>
+ * </ul>
+ *
+ * <p>For example, if the list of boundaries is:</p>
+ * <pre>0, 1, 2, 5, 10, 20</pre>
+ *
+ * <p>then there are five finite buckets with the following ranges:</p>
+ * <pre>(-INF, 0], (0, 1], (1, 2], (2, 5], (5, 10], (10, 20], (20, +INF)</pre>
+ *
+ * @param bounds array of upper bounds for buckets. Values must be sorted.
+ */
+ IHistogramCollectorPtr ExplicitHistogram(TBucketBounds bounds);
+
+ /**
+ * <p>Creates histogram collector for a sequence of buckets that have a
+ * width proportional to the value of the lower bound.</p>
+ *
+ * <p>Defines {@code bucketsCount} buckets with these boundaries for bucket i:</p>
+ * <ul>
+ * <li>Upper bound (0 <= i < N-1): {@code scale * (base ^ i)}</li>
+ * <li>Lower bound (1 <= i < N): {@code scale * (base ^ (i - 1))}</li>
+ * </ul>
+ *
+ * <p>For example, if {@code bucketsCount=6}, {@code base=2}, and {@code scale=3},
+ * then the bucket ranges are as follows:</p>
+ *
+ * <pre>(-INF, 3], (3, 6], (6, 12], (12, 24], (24, 48], (48, +INF)</pre>
+ *
+ * @param bucketsCount the total number of buckets. The value must be >= 2.
+ * @param base the exponential growth factor for the buckets width.
+ * The value must be >= 1.0.
+ * @param scale the linear scale for the buckets. The value must be >= 1.0.
+ */
+ IHistogramCollectorPtr ExponentialHistogram(
+ ui32 bucketsCount, double base, double scale = 1.0);
+
+ /**
+ * <p>Creates histogram collector for a sequence of buckets that all have
+ * the same width (except overflow and underflow).</p>
+ *
+ * <p>Defines {@code bucketsCount} buckets with these boundaries for bucket i:</p>
+ * <ul>
+ * <li>Upper bound (0 <= i < N-1): {@code startValue + bucketWidth * i}</li>
+ * <li>Lower bound (1 <= i < N): {@code startValue + bucketWidth * (i - 1)}</li>
+ * </ul>
+ *
+ * <p>For example, if {@code bucketsCount=6}, {@code startValue=5}, and
+ * {@code bucketWidth=15}, then the bucket ranges are as follows:</p>
+ *
+ * <pre>(-INF, 5], (5, 20], (20, 35], (35, 50], (50, 65], (65, +INF)</pre>
+ *
+ * @param bucketsCount the total number of buckets. The value must be >= 2.
+ * @param startValue the upper boundary of the first bucket.
+ * @param bucketWidth the difference between the upper and lower bounds for
+ * each bucket. The value must be >= 1.
+ */
+ IHistogramCollectorPtr LinearHistogram(
+ ui32 bucketsCount, TBucketBound startValue, TBucketBound bucketWidth);
+
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/metrics/histogram_collector_explicit.cpp b/library/cpp/monlib/metrics/histogram_collector_explicit.cpp
new file mode 100644
index 0000000000..377fc233ef
--- /dev/null
+++ b/library/cpp/monlib/metrics/histogram_collector_explicit.cpp
@@ -0,0 +1,55 @@
+#include "histogram_collector.h"
+#include "atomics_array.h"
+
+#include <util/generic/algorithm.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+#include <util/generic/ylimits.h>
+
+namespace NMonitoring {
+
+ ///////////////////////////////////////////////////////////////////////////
+ // TExplicitHistogramCollector
+ ///////////////////////////////////////////////////////////////////////////
+ class TExplicitHistogramCollector: public IHistogramCollector {
+ public:
+ TExplicitHistogramCollector(TBucketBounds bounds)
+ : Values_(bounds.size() + 1)
+ , Bounds_(std::move(bounds))
+ {
+ // add one bucket as +INF
+ Bounds_.push_back(Max<TBucketBound>());
+ }
+
+ void Collect(double value, ui32 count) override {
+ auto it = LowerBound(Bounds_.begin(), Bounds_.end(), value);
+ auto index = std::distance(Bounds_.begin(), it);
+ Values_.Add(index, count);
+ }
+
+ void Reset() override {
+ Values_.Reset();
+ }
+
+ IHistogramSnapshotPtr Snapshot() const override {
+ auto values = Values_.Copy();
+ return ExplicitHistogramSnapshot(Bounds_, values);
+ }
+
+ private:
+ TAtomicsArray Values_;
+ TBucketBounds Bounds_;
+ };
+
+ IHistogramCollectorPtr ExplicitHistogram(TBucketBounds bounds) {
+ Y_ENSURE(bounds.size() >= 1,
+ "explicit histogram must contain at least one bucket");
+ Y_ENSURE(bounds.size() <= HISTOGRAM_MAX_BUCKETS_COUNT,
+ "buckets count must be <=" << HISTOGRAM_MAX_BUCKETS_COUNT
+ << ", but got: " << bounds.size());
+ Y_ENSURE(IsSorted(bounds.begin(), bounds.end()),
+ "bounds for explicit histogram must be sorted");
+
+ return MakeHolder<TExplicitHistogramCollector>(bounds);
+ }
+}
diff --git a/library/cpp/monlib/metrics/histogram_collector_exponential.cpp b/library/cpp/monlib/metrics/histogram_collector_exponential.cpp
new file mode 100644
index 0000000000..2f8a50a5f9
--- /dev/null
+++ b/library/cpp/monlib/metrics/histogram_collector_exponential.cpp
@@ -0,0 +1,68 @@
+#include "histogram_collector.h"
+#include "atomics_array.h"
+
+#include <util/generic/algorithm.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+#include <util/generic/ylimits.h>
+
+namespace NMonitoring {
+ ///////////////////////////////////////////////////////////////////////////
+ // TExponentialHistogramCollector
+ ///////////////////////////////////////////////////////////////////////////
+ class TExponentialHistogramCollector: public IHistogramCollector {
+ public:
+ TExponentialHistogramCollector(ui32 bucketsCount, double base, double scale)
+ : Values_(bucketsCount)
+ , Base_(base)
+ , Scale_(scale)
+ , MinValue_(scale)
+ , MaxValue_(scale * std::pow(base, bucketsCount - 2))
+ , LogOfBase_(std::log(base))
+ {
+ }
+
+ void Collect(double value, ui32 count) override {
+ ui32 index = Max<ui32>();
+ if (value <= MinValue_) {
+ index = 0;
+ } else if (value > MaxValue_) {
+ index = Values_.Size() - 1;
+ } else {
+ double logBase = std::log(value / Scale_) / LogOfBase_;
+ index = static_cast<ui32>(std::ceil(logBase));
+ }
+ Values_.Add(index, count);
+ }
+
+ void Reset() override {
+ Values_.Reset();
+ }
+
+ IHistogramSnapshotPtr Snapshot() const override {
+ return new TExponentialHistogramSnapshot(Base_, Scale_, Values_.Copy());
+ }
+
+ private:
+ TAtomicsArray Values_;
+ double Base_;
+ double Scale_;
+ TBucketBound MinValue_;
+ TBucketBound MaxValue_;
+ double LogOfBase_;
+ };
+
+ IHistogramCollectorPtr ExponentialHistogram(
+ ui32 bucketsCount, double base, double scale)
+ {
+ Y_ENSURE(bucketsCount >= 2,
+ "exponential histogram must contain at least two buckets");
+ Y_ENSURE(bucketsCount <= HISTOGRAM_MAX_BUCKETS_COUNT,
+ "buckets count must be <=" << HISTOGRAM_MAX_BUCKETS_COUNT
+ << ", but got: " << bucketsCount);
+ Y_ENSURE(base > 1.0, "base must be > 1.0, got: " << base);
+ Y_ENSURE(scale >= 1.0, "scale must be >= 1.0, got: " << scale);
+
+ return MakeHolder<TExponentialHistogramCollector>(bucketsCount, base, scale);
+ }
+}
diff --git a/library/cpp/monlib/metrics/histogram_collector_linear.cpp b/library/cpp/monlib/metrics/histogram_collector_linear.cpp
new file mode 100644
index 0000000000..f8ad86f3a4
--- /dev/null
+++ b/library/cpp/monlib/metrics/histogram_collector_linear.cpp
@@ -0,0 +1,67 @@
+#include "histogram_collector.h"
+#include "atomics_array.h"
+
+#include <util/generic/algorithm.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+#include <util/generic/ylimits.h>
+
+#include <cmath>
+
+namespace NMonitoring {
+ ///////////////////////////////////////////////////////////////////////////
+ // TLinearHistogramCollector
+ ///////////////////////////////////////////////////////////////////////////
+ class TLinearHistogramCollector: public IHistogramCollector {
+ public:
+ TLinearHistogramCollector(
+ ui32 bucketsCount, TBucketBound startValue, TBucketBound bucketWidth)
+ : Values_(bucketsCount)
+ , StartValue_(startValue)
+ , BucketWidth_(bucketWidth)
+ , MaxValue_(startValue + bucketWidth * (bucketsCount - 2))
+ {
+ }
+
+ void Collect(double value, ui32 count) override {
+ ui32 index = Max<ui32>();
+ if (value <= StartValue_) {
+ index = 0;
+ } else if (value > MaxValue_) {
+ index = Values_.Size() - 1;
+ } else {
+ double buckets = (value - StartValue_) / BucketWidth_;
+ index = static_cast<ui32>(std::ceil(buckets));
+ }
+ Values_.Add(index, count);
+ }
+
+ void Reset() override {
+ Values_.Reset();
+ }
+
+ IHistogramSnapshotPtr Snapshot() const override {
+ return new TLinearHistogramSnapshot(
+ StartValue_, BucketWidth_, Values_.Copy());
+ }
+
+ private:
+ TAtomicsArray Values_;
+ TBucketBound StartValue_;
+ double BucketWidth_;
+ TBucketBound MaxValue_;
+ };
+
+ IHistogramCollectorPtr LinearHistogram(
+ ui32 bucketsCount, TBucketBound startValue, TBucketBound bucketWidth)
+ {
+ Y_ENSURE(bucketsCount >= 2,
+ "linear histogram must contain at least two buckets");
+ Y_ENSURE(bucketsCount <= HISTOGRAM_MAX_BUCKETS_COUNT,
+ "buckets count must be <=" << HISTOGRAM_MAX_BUCKETS_COUNT
+ << ", but got: " << bucketsCount);
+ Y_ENSURE(bucketWidth >= 1, "bucketWidth must be >= 1, got: " << bucketWidth);
+
+ return MakeHolder<TLinearHistogramCollector>(bucketsCount, startValue, bucketWidth);
+ }
+}
diff --git a/library/cpp/monlib/metrics/histogram_collector_ut.cpp b/library/cpp/monlib/metrics/histogram_collector_ut.cpp
new file mode 100644
index 0000000000..1cf66507fa
--- /dev/null
+++ b/library/cpp/monlib/metrics/histogram_collector_ut.cpp
@@ -0,0 +1,114 @@
+#include "histogram_collector.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NMonitoring;
+
+Y_UNIT_TEST_SUITE(THistogramCollectorTest) {
+ void CheckSnapshot(
+ const IHistogramSnapshot& s,
+ const TBucketBounds& bounds,
+ const TBucketValues& values) {
+ UNIT_ASSERT_VALUES_EQUAL(bounds.size(), values.size());
+ UNIT_ASSERT_VALUES_EQUAL(bounds.size(), s.Count());
+
+ double epsilon = std::numeric_limits<double>::epsilon();
+ for (ui32 i = 0; i < s.Count(); i++) {
+ UNIT_ASSERT_DOUBLES_EQUAL(bounds[i], s.UpperBound(i), epsilon);
+ UNIT_ASSERT_VALUES_EQUAL(values[i], s.Value(i));
+ }
+ }
+
+ Y_UNIT_TEST(Explicit) {
+ auto histogram = ExplicitHistogram({0, 1, 2, 5, 10, 20});
+ histogram->Collect(-2);
+ histogram->Collect(-1);
+ histogram->Collect(0);
+ histogram->Collect(1);
+ histogram->Collect(20);
+ histogram->Collect(21);
+ histogram->Collect(1000);
+
+ TBucketBounds expectedBounds = {0, 1, 2, 5, 10, 20, Max<TBucketBound>()};
+ TBucketValues expectedValues = {3, 1, 0, 0, 0, 1, 2};
+
+ CheckSnapshot(*histogram->Snapshot(), expectedBounds, expectedValues);
+ }
+
+ Y_UNIT_TEST(ExplicitWithFloadBounds) {
+ auto histogram = ExplicitHistogram({0.1, 0.5, 1, 1.7, 10});
+ histogram->Collect(0.3, 2);
+ histogram->Collect(0.01);
+ histogram->Collect(0.9);
+ histogram->Collect(0.6);
+ histogram->Collect(1.1);
+ histogram->Collect(0.7);
+ histogram->Collect(2.71);
+
+ TBucketBounds expectedBounds = {0.1, 0.5, 1, 1.7, 10, Max<TBucketBound>()};
+ TBucketValues expectedValues = {1, 2, 3, 1, 1, 0};
+
+ CheckSnapshot(*histogram->Snapshot(), expectedBounds, expectedValues);
+ }
+
+ Y_UNIT_TEST(Exponential) {
+ auto histogram = ExponentialHistogram(6, 2.0, 3.0);
+ histogram->Collect(-1);
+ histogram->Collect(0);
+ histogram->Collect(1);
+ histogram->Collect(3);
+ histogram->Collect(4);
+ histogram->Collect(5);
+ histogram->Collect(22);
+ histogram->Collect(23);
+ histogram->Collect(24);
+ histogram->Collect(50);
+ histogram->Collect(100);
+ histogram->Collect(1000);
+
+ TBucketBounds expectedBounds = {3, 6, 12, 24, 48, Max<TBucketBound>()};
+ TBucketValues expectedValues = {4, 2, 0, 3, 0, 3};
+
+ CheckSnapshot(*histogram->Snapshot(), expectedBounds, expectedValues);
+ }
+
+ Y_UNIT_TEST(Linear) {
+ auto histogram = LinearHistogram(6, 5, 15);
+ histogram->Collect(-1);
+ histogram->Collect(0);
+ histogram->Collect(1);
+ histogram->Collect(4);
+ histogram->Collect(5);
+ histogram->Collect(6);
+ histogram->Collect(64);
+ histogram->Collect(65);
+ histogram->Collect(66);
+ histogram->Collect(100);
+ histogram->Collect(1000);
+
+ TBucketBounds expectedBounds = {5, 20, 35, 50, 65, Max<TBucketBound>()};
+ TBucketValues expectedValues = {5, 1, 0, 0, 2, 3};
+
+ CheckSnapshot(*histogram->Snapshot(), expectedBounds, expectedValues);
+ }
+
+ Y_UNIT_TEST(SnapshotOutput) {
+ auto histogram = ExplicitHistogram({0, 1, 2, 5, 10, 20});
+ histogram->Collect(-2);
+ histogram->Collect(-1);
+ histogram->Collect(0);
+ histogram->Collect(1);
+ histogram->Collect(20);
+ histogram->Collect(21);
+ histogram->Collect(1000);
+
+ auto snapshot = histogram->Snapshot();
+
+ TStringStream ss;
+ ss << *snapshot;
+
+ UNIT_ASSERT_STRINGS_EQUAL(
+ "{0: 3, 1: 1, 2: 0, 5: 0, 10: 0, 20: 1, inf: 2}",
+ ss.Str());
+ }
+}
diff --git a/library/cpp/monlib/metrics/histogram_snapshot.cpp b/library/cpp/monlib/metrics/histogram_snapshot.cpp
new file mode 100644
index 0000000000..75b5811546
--- /dev/null
+++ b/library/cpp/monlib/metrics/histogram_snapshot.cpp
@@ -0,0 +1,63 @@
+#include "histogram_snapshot.h"
+
+#include <util/stream/output.h>
+
+#include <iostream>
+
+
+namespace NMonitoring {
+
+ IHistogramSnapshotPtr ExplicitHistogramSnapshot(TConstArrayRef<TBucketBound> bounds, TConstArrayRef<TBucketValue> values) {
+ Y_ENSURE(bounds.size() == values.size(),
+ "mismatched sizes: bounds(" << bounds.size() <<
+ ") != buckets(" << values.size() << ')');
+
+ auto snapshot = TExplicitHistogramSnapshot::New(bounds.size());
+
+ for (size_t i = 0; i != bounds.size(); ++i) {
+ (*snapshot)[i].first = bounds[i];
+ (*snapshot)[i].second = values[i];
+ }
+
+ return snapshot;
+ }
+
+} // namespace NMonitoring
+
+namespace {
+
+template <typename TStream>
+auto& Output(TStream& os, const NMonitoring::IHistogramSnapshot& hist) {
+ os << TStringBuf("{");
+
+ ui32 i = 0;
+ ui32 count = hist.Count();
+
+ if (count > 0) {
+ for (; i < count - 1; ++i) {
+ os << hist.UpperBound(i) << TStringBuf(": ") << hist.Value(i);
+ os << TStringBuf(", ");
+ }
+
+ if (hist.UpperBound(i) == Max<NMonitoring::TBucketBound>()) {
+ os << TStringBuf("inf: ") << hist.Value(i);
+ } else {
+ os << hist.UpperBound(i) << TStringBuf(": ") << hist.Value(i);
+ }
+ }
+
+ os << TStringBuf("}");
+
+ return os;
+}
+
+} // namespace
+
+std::ostream& operator<<(std::ostream& os, const NMonitoring::IHistogramSnapshot& hist) {
+ return Output(os, hist);
+}
+
+template <>
+void Out<NMonitoring::IHistogramSnapshot>(IOutputStream& os, const NMonitoring::IHistogramSnapshot& hist) {
+ Output(os, hist);
+}
diff --git a/library/cpp/monlib/metrics/histogram_snapshot.h b/library/cpp/monlib/metrics/histogram_snapshot.h
new file mode 100644
index 0000000000..e8acf6ac2b
--- /dev/null
+++ b/library/cpp/monlib/metrics/histogram_snapshot.h
@@ -0,0 +1,210 @@
+#pragma once
+
+#include <util/generic/array_ref.h>
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+#include <cmath>
+#include <limits>
+
+
+namespace NMonitoring {
+
+ using TBucketBound = double;
+ using TBucketValue = ui64;
+
+ using TBucketBounds = TVector<TBucketBound>;
+ using TBucketValues = TVector<TBucketValue>;
+
+ constexpr ui32 HISTOGRAM_MAX_BUCKETS_COUNT = 51;
+ constexpr TBucketBound HISTOGRAM_INF_BOUND = std::numeric_limits<TBucketBound>::max();
+
+ ///////////////////////////////////////////////////////////////////////////
+ // IHistogramSnapshot
+ ///////////////////////////////////////////////////////////////////////////
+ class IHistogramSnapshot: public TAtomicRefCount<IHistogramSnapshot> {
+ public:
+ virtual ~IHistogramSnapshot() = default;
+
+ /**
+ * @return buckets count.
+ */
+ virtual ui32 Count() const = 0;
+
+ /**
+ * @return upper bound for the bucket with particular index.
+ */
+ virtual TBucketBound UpperBound(ui32 index) const = 0;
+
+ /**
+ * @return value stored in the bucket with particular index.
+ */
+ virtual TBucketValue Value(ui32 index) const = 0;
+ };
+
+ using IHistogramSnapshotPtr = TIntrusivePtr<IHistogramSnapshot>;
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // TLinearHistogramSnapshot
+ ///////////////////////////////////////////////////////////////////////////////
+ class TLinearHistogramSnapshot: public IHistogramSnapshot {
+ public:
+ TLinearHistogramSnapshot(
+ TBucketBound startValue, TBucketBound bucketWidth, TBucketValues values)
+ : StartValue_(startValue)
+ , BucketWidth_(bucketWidth)
+ , Values_(std::move(values))
+ {
+ }
+
+ ui32 Count() const override {
+ return static_cast<ui32>(Values_.size());
+ }
+
+ TBucketBound UpperBound(ui32 index) const override {
+ Y_ASSERT(index < Values_.size());
+ if (index == Count() - 1) {
+ return Max<TBucketBound>();
+ }
+ return StartValue_ + BucketWidth_ * index;
+ }
+
+ TBucketValue Value(ui32 index) const override {
+ Y_ASSERT(index < Values_.size());
+ return Values_[index];
+ }
+
+ ui64 MemorySizeBytes() {
+ return sizeof(*this) + Values_.capacity() * sizeof(decltype(Values_)::value_type);
+ }
+
+ private:
+ TBucketBound StartValue_;
+ TBucketBound BucketWidth_;
+ TBucketValues Values_;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ // TExponentialHistogramSnapshot
+ ///////////////////////////////////////////////////////////////////////////
+ class TExponentialHistogramSnapshot: public IHistogramSnapshot {
+ public:
+ TExponentialHistogramSnapshot(
+ double base, double scale, TBucketValues values)
+ : Base_(base)
+ , Scale_(scale)
+ , Values_(std::move(values))
+ {
+ }
+
+ ui32 Count() const override {
+ return static_cast<ui32>(Values_.size());
+ }
+
+ TBucketBound UpperBound(ui32 index) const override {
+ Y_ASSERT(index < Values_.size());
+ if (index == Values_.size() - 1) {
+ return Max<TBucketBound>();
+ }
+ return std::round(Scale_ * std::pow(Base_, index));
+ }
+
+ TBucketValue Value(ui32 index) const override {
+ Y_ASSERT(index < Values_.size());
+ return Values_[index];
+ }
+
+ ui64 MemorySizeBytes() {
+ return sizeof(*this) + Values_.capacity() * sizeof(decltype(Values_)::value_type);
+ }
+
+ private:
+ double Base_;
+ double Scale_;
+ TBucketValues Values_;
+ };
+
+ using TBucket = std::pair<TBucketBound, TBucketValue>;
+
+ ///////////////////////////////////////////////////////////////////////
+ // TExplicitHistogramSnapshot
+ ///////////////////////////////////////////////////////////////////////
+ //
+ // Memory layout (single contiguous block):
+ //
+ // +------+-----------+--------------+--------+--------+- -+--------+--------+
+ // | vptr | RefsCount | BucketsCount | Bound1 | Value1 | ... | BoundN | ValueN |
+ // +------+-----------+--------------+--------+--------+- -+--------+--------+
+ //
+ class TExplicitHistogramSnapshot: public IHistogramSnapshot, private TNonCopyable {
+ public:
+ static TIntrusivePtr<TExplicitHistogramSnapshot> New(ui32 bucketsCount) {
+ size_t bucketsSize = bucketsCount * sizeof(TBucket);
+ Y_ENSURE(bucketsCount <= HISTOGRAM_MAX_BUCKETS_COUNT, "Cannot allocate a histogram with " << bucketsCount
+ << " buckets. Bucket count is limited to " << HISTOGRAM_MAX_BUCKETS_COUNT);
+
+ return new(bucketsSize) TExplicitHistogramSnapshot(bucketsCount);
+ }
+
+ TBucket& operator[](ui32 index) noexcept {
+ return Bucket(index);
+ }
+
+ ui32 Count() const override {
+ return BucketsCount_;
+ }
+
+ TBucketBound UpperBound(ui32 index) const override {
+ return Bucket(index).first;
+ }
+
+ TBucketValue Value(ui32 index) const override {
+ return Bucket(index).second;
+ }
+
+ ui64 MemorySizeBytes() const {
+ return sizeof(*this) + BucketsCount_ * sizeof(TBucket);
+ }
+
+ private:
+ explicit TExplicitHistogramSnapshot(ui32 bucketsCount) noexcept
+ : BucketsCount_(bucketsCount)
+ {
+ }
+
+ static void* operator new(size_t size, size_t bucketsSize) {
+ return ::operator new(size + bucketsSize);
+ }
+
+ static void operator delete(void* mem) {
+ ::operator delete(mem);
+ }
+
+ static void operator delete(void* mem, size_t, size_t) {
+ // this operator can be called as paired for custom new operator
+ ::operator delete(mem);
+ }
+
+ TBucket& Bucket(ui32 index) noexcept {
+ Y_VERIFY_DEBUG(index < BucketsCount_);
+ return *(reinterpret_cast<TBucket*>(this + 1) + index);
+ }
+
+ const TBucket& Bucket(ui32 index) const noexcept {
+ Y_VERIFY_DEBUG(index < BucketsCount_);
+ return *(reinterpret_cast<const TBucket*>(this + 1) + index);
+ }
+
+ private:
+ ui32 BucketsCount_;
+ };
+
+ static_assert(alignof(TExplicitHistogramSnapshot) == alignof(TBucket),
+ "mismatched alingments of THistogramSnapshot and TBucket");
+
+ IHistogramSnapshotPtr ExplicitHistogramSnapshot(TConstArrayRef<TBucketBound> bounds, TConstArrayRef<TBucketValue> values);
+
+} // namespace NMonitoring
+
+std::ostream& operator<<(std::ostream& os, const NMonitoring::IHistogramSnapshot& hist);
diff --git a/library/cpp/monlib/metrics/labels.cpp b/library/cpp/monlib/metrics/labels.cpp
new file mode 100644
index 0000000000..1eaadb7cba
--- /dev/null
+++ b/library/cpp/monlib/metrics/labels.cpp
@@ -0,0 +1,82 @@
+#include "labels.h"
+
+#include <util/stream/output.h>
+#include <util/string/split.h>
+
+static void OutputLabels(IOutputStream& out, const NMonitoring::ILabels& labels) {
+ size_t i = 0;
+ out << '{';
+ for (const auto& label: labels) {
+ if (i++ > 0) {
+ out << TStringBuf(", ");
+ }
+ out << label;
+ }
+ out << '}';
+}
+
+template <>
+void Out<NMonitoring::ILabelsPtr>(IOutputStream& out, const NMonitoring::ILabelsPtr& labels) {
+ OutputLabels(out, *labels);
+}
+
+template <>
+void Out<NMonitoring::ILabels>(IOutputStream& out, const NMonitoring::ILabels& labels) {
+ OutputLabels(out, labels);
+}
+
+template <>
+void Out<NMonitoring::ILabel>(IOutputStream& out, const NMonitoring::ILabel& labels) {
+ out << labels.Name() << "=" << labels.Value();
+}
+
+Y_MONLIB_DEFINE_LABELS_OUT(NMonitoring::TLabels);
+Y_MONLIB_DEFINE_LABEL_OUT(NMonitoring::TLabel);
+
+namespace NMonitoring {
+ bool TryLoadLabelsFromString(TStringBuf sb, ILabels& labels) {
+ if (sb.Empty()) {
+ return false;
+ }
+
+ if (!sb.StartsWith('{') || !sb.EndsWith('}')) {
+ return false;
+ }
+
+ sb.Skip(1);
+ sb.Chop(1);
+
+ if (sb.Empty()) {
+ return true;
+ }
+
+ bool ok = true;
+ TVector<std::pair<TStringBuf, TStringBuf>> rawLabels;
+ StringSplitter(sb).SplitBySet(" ,").SkipEmpty().Consume([&] (TStringBuf label) {
+ TStringBuf key, value;
+ ok &= label.TrySplit('=', key, value);
+
+ if (!ok) {
+ return;
+ }
+
+ rawLabels.emplace_back(key, value);
+ });
+
+ if (!ok) {
+ return false;
+ }
+
+ for (auto&& [k, v] : rawLabels) {
+ labels.Add(k, v);
+ }
+
+ return true;
+ }
+
+ bool TryLoadLabelsFromString(IInputStream& is, ILabels& labels) {
+ TString str = is.ReadAll();
+ return TryLoadLabelsFromString(str, labels);
+ }
+
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/metrics/labels.h b/library/cpp/monlib/metrics/labels.h
new file mode 100644
index 0000000000..63dc997c28
--- /dev/null
+++ b/library/cpp/monlib/metrics/labels.h
@@ -0,0 +1,483 @@
+#pragma once
+
+#include <util/digest/multi.h>
+#include <util/digest/sequence.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/maybe.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/stream/output.h>
+#include <util/string/builder.h>
+#include <util/string/strip.h>
+
+#include <optional>
+#include <type_traits>
+
+namespace NMonitoring {
+ struct ILabel {
+ virtual ~ILabel() = default;
+
+ virtual TStringBuf Name() const noexcept = 0;
+ virtual TStringBuf Value() const noexcept = 0;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ // TLabel
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename TStringBackend>
+ class TLabelImpl: public ILabel {
+ public:
+ using TStringType = TStringBackend;
+
+ TLabelImpl() = default;
+
+ inline TLabelImpl(TStringBuf name, TStringBuf value)
+ : Name_{name}
+ , Value_{value}
+ {
+ }
+
+ inline bool operator==(const TLabelImpl& rhs) const noexcept {
+ return Name_ == rhs.Name_ && Value_ == rhs.Value_;
+ }
+
+ inline bool operator!=(const TLabelImpl& rhs) const noexcept {
+ return !(*this == rhs);
+ }
+
+ inline TStringBuf Name() const noexcept {
+ return Name_;
+ }
+
+ inline TStringBuf Value() const noexcept {
+ return Value_;
+ }
+
+ inline const TStringBackend& NameStr() const {
+ return Name_;
+ }
+
+ inline const TStringBackend& ValueStr() const {
+ return Value_;
+ }
+
+ inline size_t Hash() const noexcept {
+ return MultiHash(Name_, Value_);
+ }
+
+ TStringBackend ToString() const {
+ TStringBackend buf = Name_;
+ buf += '=';
+ buf += Value_;
+
+ return buf;
+ }
+
+ static TLabelImpl FromString(TStringBuf str) {
+ TStringBuf name, value;
+ Y_ENSURE(str.TrySplit('=', name, value),
+ "invalid label string format: '" << str << '\'');
+
+ TStringBuf nameStripped = StripString(name);
+ Y_ENSURE(!nameStripped.empty(), "label name cannot be empty");
+
+ TStringBuf valueStripped = StripString(value);
+ Y_ENSURE(!valueStripped.empty(), "label value cannot be empty");
+
+ return {nameStripped, valueStripped};
+ }
+
+ static bool TryFromString(TStringBuf str, TLabelImpl& label) {
+ TStringBuf name, value;
+ if (!str.TrySplit('=', name, value)) {
+ return false;
+ }
+
+ TStringBuf nameStripped = StripString(name);
+ if (nameStripped.empty()) {
+ return false;
+ }
+
+ TStringBuf valueStripped = StripString(value);
+ if (valueStripped.empty()) {
+ return false;
+ }
+
+ label = {nameStripped, valueStripped};
+ return true;
+ }
+
+ private:
+ TStringBackend Name_;
+ TStringBackend Value_;
+ };
+
+ using TLabel = TLabelImpl<TString>;
+
+ struct ILabels {
+ struct TIterator {
+ TIterator() = default;
+ TIterator(const ILabels* labels, size_t idx = 0)
+ : Labels_{labels}
+ , Idx_{idx}
+ {
+ }
+
+ TIterator& operator++() noexcept {
+ Idx_++;
+ return *this;
+ }
+
+ void operator+=(size_t i) noexcept {
+ Idx_ += i;
+ }
+
+ bool operator==(const TIterator& other) const noexcept {
+ return Idx_ == other.Idx_;
+ }
+
+ bool operator!=(const TIterator& other) const noexcept {
+ return !(*this == other);
+ }
+
+ const ILabel* operator->() const noexcept {
+ Y_VERIFY_DEBUG(Labels_);
+ return Labels_->Get(Idx_);
+ }
+
+ const ILabel& operator*() const noexcept {
+ Y_VERIFY_DEBUG(Labels_);
+ return *Labels_->Get(Idx_);
+ }
+
+
+ private:
+ const ILabels* Labels_{nullptr};
+ size_t Idx_{0};
+ };
+
+ virtual ~ILabels() = default;
+
+ virtual bool Add(TStringBuf name, TStringBuf value) noexcept = 0;
+ virtual bool Add(const ILabel& label) noexcept {
+ return Add(label.Name(), label.Value());
+ }
+
+ virtual bool Has(TStringBuf name) const noexcept = 0;
+
+ virtual size_t Size() const noexcept = 0;
+ virtual bool Empty() const noexcept = 0;
+ virtual void Clear() noexcept = 0;
+
+ virtual size_t Hash() const noexcept = 0;
+
+ virtual std::optional<const ILabel*> Get(TStringBuf name) const = 0;
+
+ // NB: there's no guarantee that indices are preserved after any object modification
+ virtual const ILabel* Get(size_t idx) const = 0;
+
+ TIterator begin() const {
+ return TIterator{this};
+ }
+
+ TIterator end() const {
+ return TIterator{this, Size()};
+ }
+ };
+
+ bool TryLoadLabelsFromString(TStringBuf sb, ILabels& labels);
+ bool TryLoadLabelsFromString(IInputStream& is, ILabels& labels);
+
+ ///////////////////////////////////////////////////////////////////////////
+ // TLabels
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename TStringBackend>
+ class TLabelsImpl: public ILabels {
+ public:
+ using value_type = TLabelImpl<TStringBackend>;
+
+ TLabelsImpl() = default;
+
+ explicit TLabelsImpl(::NDetail::TReserveTag rt)
+ : Labels_(std::move(rt))
+ {}
+
+ explicit TLabelsImpl(size_t count)
+ : Labels_(count)
+ {}
+
+ explicit TLabelsImpl(size_t count, const value_type& label)
+ : Labels_(count, label)
+ {}
+
+ TLabelsImpl(std::initializer_list<value_type> il)
+ : Labels_(std::move(il))
+ {}
+
+ TLabelsImpl(const TLabelsImpl&) = default;
+ TLabelsImpl& operator=(const TLabelsImpl&) = default;
+
+ TLabelsImpl(TLabelsImpl&&) noexcept = default;
+ TLabelsImpl& operator=(TLabelsImpl&&) noexcept = default;
+
+ inline bool operator==(const TLabelsImpl& rhs) const {
+ return Labels_ == rhs.Labels_;
+ }
+
+ inline bool operator!=(const TLabelsImpl& rhs) const {
+ return Labels_ != rhs.Labels_;
+ }
+
+ bool Add(TStringBuf name, TStringBuf value) noexcept override {
+ if (Has(name)) {
+ return false;
+ }
+
+ Labels_.emplace_back(name, value);
+ return true;
+ }
+
+ using ILabels::Add;
+
+ bool Has(TStringBuf name) const noexcept override {
+ auto it = FindIf(Labels_, [name](const TLabelImpl<TStringBackend>& label) {
+ return name == TStringBuf{label.Name()};
+ });
+ return it != Labels_.end();
+ }
+
+ bool Has(const TString& name) const noexcept {
+ auto it = FindIf(Labels_, [name](const TLabelImpl<TStringBackend>& label) {
+ return name == TStringBuf{label.Name()};
+ });
+ return it != Labels_.end();
+ }
+
+ // XXX for backward compatibility
+ TMaybe<TLabelImpl<TStringBackend>> Find(TStringBuf name) const {
+ auto it = FindIf(Labels_, [name](const TLabelImpl<TStringBackend>& label) {
+ return name == TStringBuf{label.Name()};
+ });
+ if (it == Labels_.end()) {
+ return Nothing();
+ }
+ return *it;
+ }
+
+ std::optional<const ILabel*> Get(TStringBuf name) const override {
+ auto it = FindIf(Labels_, [name] (auto&& l) {
+ return name == l.Name();
+ });
+
+ if (it == Labels_.end()) {
+ return {};
+ }
+
+ return &*it;
+ }
+
+ const ILabel* Get(size_t idx) const noexcept override {
+ return &(*this)[idx];
+ }
+
+ TMaybe<TLabelImpl<TStringBackend>> Extract(TStringBuf name) {
+ auto it = FindIf(Labels_, [name](const TLabelImpl<TStringBackend>& label) {
+ return name == TStringBuf{label.Name()};
+ });
+ if (it == Labels_.end()) {
+ return Nothing();
+ }
+ TLabel tmp = *it;
+ Labels_.erase(it);
+ return tmp;
+ }
+
+ void SortByName() {
+ std::sort(Labels_.begin(), Labels_.end(), [](const auto& lhs, const auto& rhs) {
+ return lhs.Name() < rhs.Name();
+ });
+ }
+
+ inline size_t Hash() const noexcept override {
+ return TSimpleRangeHash()(Labels_);
+ }
+
+ inline TLabel* Data() const noexcept {
+ return const_cast<TLabel*>(Labels_.data());
+ }
+
+ inline size_t Size() const noexcept override {
+ return Labels_.size();
+ }
+
+ inline bool Empty() const noexcept override {
+ return Labels_.empty();
+ }
+
+ inline void Clear() noexcept override {
+ Labels_.clear();
+ };
+
+ TLabelImpl<TStringBackend>& front() {
+ return Labels_.front();
+ }
+
+ const TLabelImpl<TStringBackend>& front() const {
+ return Labels_.front();
+ }
+
+ TLabelImpl<TStringBackend>& back() {
+ return Labels_.back();
+ }
+
+ const TLabelImpl<TStringBackend>& back() const {
+ return Labels_.back();
+ }
+
+ TLabelImpl<TStringBackend>& operator[](size_t index) {
+ return Labels_[index];
+ }
+
+ const TLabelImpl<TStringBackend>& operator[](size_t index) const {
+ return Labels_[index];
+ }
+
+ TLabelImpl<TStringBackend>& at(size_t index) {
+ return Labels_.at(index);
+ }
+
+ const TLabelImpl<TStringBackend>& at(size_t index) const {
+ return Labels_.at(index);
+ }
+
+ size_t capacity() const {
+ return Labels_.capacity();
+ }
+
+ TLabelImpl<TStringBackend>* data() {
+ return Labels_.data();
+ }
+
+ const TLabelImpl<TStringBackend>* data() const {
+ return Labels_.data();
+ }
+
+ size_t size() const {
+ return Labels_.size();
+ }
+
+ bool empty() const {
+ return Labels_.empty();
+ }
+
+ void clear() {
+ Labels_.clear();
+ }
+
+ using ILabels::begin;
+ using ILabels::end;
+
+ using iterator = ILabels::TIterator;
+ using const_iterator = iterator;
+
+ protected:
+ TVector<TLabelImpl<TStringBackend>>& AsVector() {
+ return Labels_;
+ }
+
+ const TVector<TLabelImpl<TStringBackend>>& AsVector() const {
+ return Labels_;
+ }
+
+ private:
+ TVector<TLabelImpl<TStringBackend>> Labels_;
+ };
+
+ using TLabels = TLabelsImpl<TString>;
+ using ILabelsPtr = THolder<ILabels>;
+
+ template <typename T>
+ ILabelsPtr MakeLabels() {
+ return MakeHolder<TLabelsImpl<T>>();
+ }
+
+ template <typename T>
+ ILabelsPtr MakeLabels(std::initializer_list<TLabelImpl<T>> labels) {
+ return MakeHolder<TLabelsImpl<T>>(labels);
+ }
+
+ inline ILabelsPtr MakeLabels(TLabels&& labels) {
+ return MakeHolder<TLabels>(std::move(labels));
+ }
+}
+
+template<>
+struct THash<NMonitoring::ILabelsPtr> {
+ size_t operator()(const NMonitoring::ILabelsPtr& labels) const noexcept {
+ return labels->Hash();
+ }
+
+ size_t operator()(const NMonitoring::ILabels& labels) const noexcept {
+ return labels.Hash();
+ }
+};
+
+template<typename TStringBackend>
+struct THash<NMonitoring::TLabelsImpl<TStringBackend>> {
+ size_t operator()(const NMonitoring::TLabelsImpl<TStringBackend>& labels) const noexcept {
+ return labels.Hash();
+ }
+};
+
+template <typename TStringBackend>
+struct THash<NMonitoring::TLabelImpl<TStringBackend>> {
+ inline size_t operator()(const NMonitoring::TLabelImpl<TStringBackend>& label) const noexcept {
+ return label.Hash();
+ }
+};
+
+inline bool operator==(const NMonitoring::ILabels& lhs, const NMonitoring::ILabels& rhs) {
+ if (lhs.Size() != rhs.Size()) {
+ return false;
+ }
+
+ for (auto&& l : lhs) {
+ auto rl = rhs.Get(l.Name());
+ if (!rl || (*rl)->Value() != l.Value()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool operator==(const NMonitoring::ILabelsPtr& lhs, const NMonitoring::ILabelsPtr& rhs) = delete;
+bool operator==(const NMonitoring::ILabels& lhs, const NMonitoring::ILabelsPtr& rhs) = delete;
+bool operator==(const NMonitoring::ILabelsPtr& lhs, const NMonitoring::ILabels& rhs) = delete;
+
+template<>
+struct TEqualTo<NMonitoring::ILabelsPtr> {
+ bool operator()(const NMonitoring::ILabelsPtr& lhs, const NMonitoring::ILabelsPtr& rhs) {
+ return *lhs == *rhs;
+ }
+
+ bool operator()(const NMonitoring::ILabelsPtr& lhs, const NMonitoring::ILabels& rhs) {
+ return *lhs == rhs;
+ }
+
+ bool operator()(const NMonitoring::ILabels& lhs, const NMonitoring::ILabelsPtr& rhs) {
+ return lhs == *rhs;
+ }
+};
+
+#define Y_MONLIB_DEFINE_LABELS_OUT(T) \
+template <> \
+void Out<T>(IOutputStream& out, const T& labels) { \
+ Out<NMonitoring::ILabels>(out, labels); \
+}
+
+#define Y_MONLIB_DEFINE_LABEL_OUT(T) \
+template <> \
+void Out<T>(IOutputStream& out, const T& label) { \
+ Out<NMonitoring::ILabel>(out, label); \
+}
diff --git a/library/cpp/monlib/metrics/labels_ut.cpp b/library/cpp/monlib/metrics/labels_ut.cpp
new file mode 100644
index 0000000000..f0e4f532ab
--- /dev/null
+++ b/library/cpp/monlib/metrics/labels_ut.cpp
@@ -0,0 +1,194 @@
+#include "labels.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NMonitoring;
+
+Y_UNIT_TEST_SUITE(TLabelsTest) {
+ TLabel pSolomon("project", "solomon");
+ TLabel pKikimr("project", "kikimr");
+
+ Y_UNIT_TEST(Equals) {
+ UNIT_ASSERT(pSolomon == TLabel("project", "solomon"));
+
+ UNIT_ASSERT_STRINGS_EQUAL(pSolomon.Name(), "project");
+ UNIT_ASSERT_STRINGS_EQUAL(pSolomon.Value(), "solomon");
+
+ UNIT_ASSERT(pSolomon != pKikimr);
+ }
+
+ Y_UNIT_TEST(ToString) {
+ UNIT_ASSERT_STRINGS_EQUAL(pSolomon.ToString(), "project=solomon");
+ UNIT_ASSERT_STRINGS_EQUAL(pKikimr.ToString(), "project=kikimr");
+ }
+
+ Y_UNIT_TEST(FromString) {
+ auto pYql = TLabel::FromString("project=yql");
+ UNIT_ASSERT_EQUAL(pYql, TLabel("project", "yql"));
+
+ UNIT_ASSERT_EQUAL(TLabel::FromString("k=v"), TLabel("k", "v"));
+ UNIT_ASSERT_EQUAL(TLabel::FromString("k=v "), TLabel("k", "v"));
+ UNIT_ASSERT_EQUAL(TLabel::FromString("k= v"), TLabel("k", "v"));
+ UNIT_ASSERT_EQUAL(TLabel::FromString("k =v"), TLabel("k", "v"));
+ UNIT_ASSERT_EQUAL(TLabel::FromString(" k=v"), TLabel("k", "v"));
+ UNIT_ASSERT_EQUAL(TLabel::FromString(" k = v "), TLabel("k", "v"));
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TLabel::FromString(""),
+ yexception,
+ "invalid label string format");
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TLabel::FromString("k v"),
+ yexception,
+ "invalid label string format");
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TLabel::FromString(" =v"),
+ yexception,
+ "label name cannot be empty");
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TLabel::FromString("k= "),
+ yexception,
+ "label value cannot be empty");
+ }
+
+ Y_UNIT_TEST(TryFromString) {
+ TLabel pYql;
+ UNIT_ASSERT(TLabel::TryFromString("project=yql", pYql));
+ UNIT_ASSERT_EQUAL(pYql, TLabel("project", "yql"));
+
+ {
+ TLabel label;
+ UNIT_ASSERT(TLabel::TryFromString("k=v", label));
+ UNIT_ASSERT_EQUAL(label, TLabel("k", "v"));
+ }
+ {
+ TLabel label;
+ UNIT_ASSERT(TLabel::TryFromString("k=v ", label));
+ UNIT_ASSERT_EQUAL(label, TLabel("k", "v"));
+ }
+ {
+ TLabel label;
+ UNIT_ASSERT(TLabel::TryFromString("k= v", label));
+ UNIT_ASSERT_EQUAL(label, TLabel("k", "v"));
+ }
+ {
+ TLabel label;
+ UNIT_ASSERT(TLabel::TryFromString("k =v", label));
+ UNIT_ASSERT_EQUAL(label, TLabel("k", "v"));
+ }
+ {
+ TLabel label;
+ UNIT_ASSERT(TLabel::TryFromString(" k=v", label));
+ UNIT_ASSERT_EQUAL(label, TLabel("k", "v"));
+ }
+ {
+ TLabel label;
+ UNIT_ASSERT(TLabel::TryFromString(" k = v ", label));
+ UNIT_ASSERT_EQUAL(label, TLabel("k", "v"));
+ }
+ }
+
+ Y_UNIT_TEST(Labels) {
+ TLabels labels;
+ UNIT_ASSERT(labels.Add(TStringBuf("name1"), TStringBuf("value1")));
+ UNIT_ASSERT(labels.Size() == 1);
+ UNIT_ASSERT(labels.Has(TStringBuf("name1")));
+ {
+ auto l = labels.Find("name1");
+ UNIT_ASSERT(l.Defined());
+ UNIT_ASSERT_STRINGS_EQUAL(l->Name(), "name1");
+ UNIT_ASSERT_STRINGS_EQUAL(l->Value(), "value1");
+ }
+ {
+ auto l = labels.Find("name2");
+ UNIT_ASSERT(!l.Defined());
+ }
+
+ // duplicated name
+ UNIT_ASSERT(!labels.Add(TStringBuf("name1"), TStringBuf("value2")));
+ UNIT_ASSERT(labels.Size() == 1);
+
+ UNIT_ASSERT(labels.Add(TStringBuf("name2"), TStringBuf("value2")));
+ UNIT_ASSERT(labels.Size() == 2);
+ UNIT_ASSERT(labels.Has(TStringBuf("name2")));
+ {
+ auto l = labels.Find("name2");
+ UNIT_ASSERT(l.Defined());
+ UNIT_ASSERT_STRINGS_EQUAL(l->Name(), "name2");
+ UNIT_ASSERT_STRINGS_EQUAL(l->Value(), "value2");
+ }
+
+ UNIT_ASSERT_EQUAL(labels[0], TLabel("name1", "value1"));
+ UNIT_ASSERT_EQUAL(labels[1], TLabel("name2", "value2"));
+
+ TVector<TLabel> labelsCopy;
+ for (auto&& label : labels) {
+ labelsCopy.emplace_back(label.Name(), label.Value());
+ }
+
+ UNIT_ASSERT_EQUAL(labelsCopy, TVector<TLabel>({
+ {"name1", "value1"},
+ {"name2", "value2"},
+ }));
+ }
+
+ Y_UNIT_TEST(Hash) {
+ TLabel label("name", "value");
+ UNIT_ASSERT_EQUAL(ULL(2378153472115172159), label.Hash());
+
+ {
+ TLabels labels = {{"name", "value"}};
+ UNIT_ASSERT_EQUAL(ULL(5420514431458887014), labels.Hash());
+ }
+ {
+ TLabels labels = {{"name1", "value1"}, {"name2", "value2"}};
+ UNIT_ASSERT_EQUAL(ULL(2226975250396609813), labels.Hash());
+ }
+ }
+
+ Y_UNIT_TEST(MakeEmptyLabels) {
+ {
+ auto labels = MakeLabels<TString>();
+ UNIT_ASSERT(labels);
+ UNIT_ASSERT(labels->Empty());
+ UNIT_ASSERT_VALUES_EQUAL(labels->Size(), 0);
+ }
+ {
+ auto labels = MakeLabels<TStringBuf>();
+ UNIT_ASSERT(labels);
+ UNIT_ASSERT(labels->Empty());
+ UNIT_ASSERT_VALUES_EQUAL(labels->Size(), 0);
+ }
+ }
+
+ Y_UNIT_TEST(MakeLabelsFromInitializerList) {
+ auto labels = MakeLabels<TString>({{"my", "label"}});
+ UNIT_ASSERT(labels);
+ UNIT_ASSERT(!labels->Empty());
+ UNIT_ASSERT_VALUES_EQUAL(labels->Size(), 1);
+
+ UNIT_ASSERT(labels->Has("my"));
+
+ auto label = labels->Get("my");
+ UNIT_ASSERT(label.has_value());
+ UNIT_ASSERT_STRINGS_EQUAL((*label)->Name(), "my");
+ UNIT_ASSERT_STRINGS_EQUAL((*label)->Value(), "label");
+ }
+
+ Y_UNIT_TEST(MakeLabelsFromOtherLabel) {
+ auto labels = MakeLabels({{"my", "label"}});
+ UNIT_ASSERT(labels);
+ UNIT_ASSERT(!labels->Empty());
+ UNIT_ASSERT_VALUES_EQUAL(labels->Size(), 1);
+
+ UNIT_ASSERT(labels->Has("my"));
+
+ auto label = labels->Get("my");
+ UNIT_ASSERT(label.has_value());
+ UNIT_ASSERT_STRINGS_EQUAL((*label)->Name(), "my");
+ UNIT_ASSERT_STRINGS_EQUAL((*label)->Value(), "label");
+ }
+}
diff --git a/library/cpp/monlib/metrics/log_histogram_collector.h b/library/cpp/monlib/metrics/log_histogram_collector.h
new file mode 100644
index 0000000000..b81f84ebf3
--- /dev/null
+++ b/library/cpp/monlib/metrics/log_histogram_collector.h
@@ -0,0 +1,158 @@
+#pragma once
+
+#include "log_histogram_snapshot.h"
+
+#include <util/generic/algorithm.h>
+#include <util/generic/utility.h>
+#include <util/generic/yexception.h>
+
+#include <mutex>
+#include <cmath>
+
+namespace NMonitoring {
+
+ class TLogHistogramCollector {
+ public:
+ static constexpr int DEFAULT_START_POWER = -1;
+
+ explicit TLogHistogramCollector(int startPower = DEFAULT_START_POWER)
+ : StartPower_(startPower)
+ , CountZero_(0u)
+ {}
+
+ void Collect(TLogHistogramSnapshot* logHist) {
+ std::lock_guard guard(Mutex_);
+ Merge(logHist);
+ }
+
+ bool Collect(double value) {
+ std::lock_guard guard(Mutex_);
+ return CollectDouble(value);
+ }
+
+ TLogHistogramSnapshotPtr Snapshot() const {
+ std::lock_guard guard(Mutex_);
+ return MakeIntrusive<TLogHistogramSnapshot>(BASE, CountZero_, StartPower_, Buckets_);
+ }
+
+ void AddZeros(ui64 zerosCount) noexcept {
+ std::lock_guard guard(Mutex_);
+ CountZero_ += zerosCount;
+ }
+
+ private:
+ int StartPower_;
+ ui64 CountZero_;
+ TVector<double> Buckets_;
+ mutable std::mutex Mutex_;
+
+ static constexpr size_t MAX_BUCKETS = LOG_HIST_MAX_BUCKETS;
+ static constexpr double BASE = 1.5;
+
+ private:
+ int EstimateBucketIndex(double value) const {
+ return (int) (std::floor(std::log(value) / std::log(BASE)) - StartPower_);
+ }
+
+ void CollectPositiveDouble(double value) {
+ ssize_t idx = std::floor(std::log(value) / std::log(BASE)) - StartPower_;
+ if (idx >= Buckets_.ysize()) {
+ idx = ExtendUp(idx);
+ } else if (idx <= 0) {
+ idx = Max<ssize_t>(0, ExtendDown(idx, 1));
+ }
+ ++Buckets_[idx];
+ }
+
+ bool CollectDouble(double value) {
+ if (Y_UNLIKELY(std::isnan(value) || std::isinf(value))) {
+ return false;
+ }
+ if (value <= 0.0) {
+ ++CountZero_;
+ } else {
+ CollectPositiveDouble(value);
+ }
+ return true;
+ }
+
+ void Merge(TLogHistogramSnapshot* logHist) {
+ CountZero_ += logHist->ZerosCount();
+ const i32 firstIdxBeforeExtend = logHist->StartPower() - StartPower_;
+ const i32 lastIdxBeforeExtend = firstIdxBeforeExtend + logHist->Count() - 1;
+ if (firstIdxBeforeExtend > Max<i16>() || firstIdxBeforeExtend < Min<i16>()) {
+ ythrow yexception() << "i16 overflow on first index";
+ }
+ if (lastIdxBeforeExtend > Max<i16>() || lastIdxBeforeExtend < Min<i16>()) {
+ ythrow yexception() << "i16 overflow on last index";
+ }
+ i64 firstIdx = ExtendBounds(firstIdxBeforeExtend, lastIdxBeforeExtend, 0).first;
+ size_t toMerge = std::min<ui32>(std::max<i64>(-firstIdx, (i64) 0), logHist->Count());
+ if (toMerge) {
+ for (size_t i = 0; i < toMerge; ++i) {
+ Buckets_[0] += logHist->Bucket(i);
+ }
+ firstIdx = 0;
+ }
+ for (size_t i = toMerge; i != logHist->Count(); ++i) {
+ Buckets_[firstIdx] += logHist->Bucket(i);
+ ++firstIdx;
+ }
+ }
+
+ int ExtendUp(int expectedIndex) {
+ Y_VERIFY_DEBUG(expectedIndex >= (int) Buckets_.size());
+ const size_t toAdd = expectedIndex - Buckets_.size() + 1;
+ const size_t newSize = Buckets_.size() + toAdd;
+ if (newSize <= MAX_BUCKETS) {
+ Buckets_.resize(newSize, 0.0);
+ return expectedIndex;
+ }
+
+ const size_t toRemove = newSize - MAX_BUCKETS;
+ const size_t actualToRemove = std::min<size_t>(toRemove, Buckets_.size());
+ if (actualToRemove > 0) {
+ const double firstWeight = std::accumulate(Buckets_.cbegin(), Buckets_.cbegin() + actualToRemove, 0.0);
+ Buckets_.erase(Buckets_.cbegin(), Buckets_.cbegin() + actualToRemove);
+ if (Buckets_.empty()) {
+ Buckets_.push_back(firstWeight);
+ } else {
+ Buckets_[0] = firstWeight;
+ }
+ }
+ Buckets_.resize(MAX_BUCKETS, 0.0);
+ StartPower_ += toRemove;
+ return expectedIndex - toRemove;
+ }
+
+ int ExtendDown(int expectedIndex, int margin) {
+ Y_VERIFY_DEBUG(expectedIndex <= 0);
+ int toAdd = std::min<int>(MAX_BUCKETS - Buckets_.size(), margin - expectedIndex);
+ if (toAdd > 0) {
+ Buckets_.insert(Buckets_.begin(), toAdd, 0.0);
+ StartPower_ -= toAdd;
+ }
+ return expectedIndex + toAdd;
+ }
+
+ std::pair<ssize_t, ssize_t> ExtendBounds(ssize_t startIdx, ssize_t endIdx, ui8 margin) {
+ ssize_t realEndIdx;
+ ssize_t realStartIdx;
+ if (endIdx >= Buckets_.ysize()) {
+ Buckets_.reserve(std::max<size_t>(std::min<ui32>(endIdx - startIdx + 1ul, MAX_BUCKETS), 0ul));
+ realEndIdx = ExtendUp(endIdx);
+ startIdx += realEndIdx - endIdx;
+ } else {
+ realEndIdx = endIdx;
+ }
+ if (startIdx < 1) {
+ realStartIdx = ExtendDown(startIdx, margin);
+ realEndIdx += realStartIdx - startIdx;
+ } else {
+ realStartIdx = startIdx;
+ }
+ return std::make_pair(realStartIdx, realEndIdx);
+ }
+ };
+
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/metrics/log_histogram_collector_ut.cpp b/library/cpp/monlib/metrics/log_histogram_collector_ut.cpp
new file mode 100644
index 0000000000..ac9a3522ce
--- /dev/null
+++ b/library/cpp/monlib/metrics/log_histogram_collector_ut.cpp
@@ -0,0 +1,38 @@
+#include "log_histogram_collector.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(LogHistogramCollector) {
+
+ Y_UNIT_TEST(ExtendUpEmpty) {
+ NMonitoring::TLogHistogramCollector collector(-1);
+ collector.Collect(4.1944122207138854e+17);
+ auto s = collector.Snapshot();
+ UNIT_ASSERT_EQUAL(s->ZerosCount(), 0);
+ UNIT_ASSERT_EQUAL(s->StartPower(), 1);
+ UNIT_ASSERT_EQUAL(s->Count(), 100);
+ UNIT_ASSERT_EQUAL(s->Bucket(s->Count() - 1), 1);
+ }
+
+ Y_UNIT_TEST(ExtendUpNonEmpty) {
+ NMonitoring::TLogHistogramCollector collector(-1);
+ collector.Collect(0.0);
+ collector.Collect(1/(1.5*1.5*1.5));
+ collector.Collect(1/1.5);
+ auto s = collector.Snapshot();
+
+ UNIT_ASSERT_EQUAL(s->ZerosCount(), 1);
+ UNIT_ASSERT_EQUAL(s->StartPower(), -4);
+ UNIT_ASSERT_EQUAL(s->Count(), 3);
+ UNIT_ASSERT_EQUAL(s->Bucket(1), 1);
+ UNIT_ASSERT_EQUAL(s->Bucket(2), 1);
+
+ collector.Collect(4.1944122207138854e+17);
+ s = collector.Snapshot();
+ UNIT_ASSERT_EQUAL(s->ZerosCount(), 1);
+ UNIT_ASSERT_EQUAL(s->StartPower(), 1);
+ UNIT_ASSERT_EQUAL(s->Count(), 100);
+ UNIT_ASSERT_EQUAL(s->Bucket(0), 2);
+ UNIT_ASSERT_EQUAL(s->Bucket(99), 1);
+ }
+}
diff --git a/library/cpp/monlib/metrics/log_histogram_snapshot.cpp b/library/cpp/monlib/metrics/log_histogram_snapshot.cpp
new file mode 100644
index 0000000000..21cf2ca2bb
--- /dev/null
+++ b/library/cpp/monlib/metrics/log_histogram_snapshot.cpp
@@ -0,0 +1,35 @@
+#include "log_histogram_snapshot.h"
+
+#include <util/stream/output.h>
+
+#include <iostream>
+
+
+namespace {
+
+template <typename TStream>
+auto& Output(TStream& o, const NMonitoring::TLogHistogramSnapshot& hist) {
+ o << TStringBuf("{");
+
+ for (auto i = 0u; i < hist.Count(); ++i) {
+ o << hist.UpperBound(i) << TStringBuf(": ") << hist.Bucket(i);
+ o << TStringBuf(", ");
+ }
+
+ o << TStringBuf("zeros: ") << hist.ZerosCount();
+
+ o << TStringBuf("}");
+
+ return o;
+}
+
+} // namespace
+
+std::ostream& operator<<(std::ostream& os, const NMonitoring::TLogHistogramSnapshot& hist) {
+ return Output(os, hist);
+}
+
+template <>
+void Out<NMonitoring::TLogHistogramSnapshot>(IOutputStream& os, const NMonitoring::TLogHistogramSnapshot& hist) {
+ Output(os, hist);
+}
diff --git a/library/cpp/monlib/metrics/log_histogram_snapshot.h b/library/cpp/monlib/metrics/log_histogram_snapshot.h
new file mode 100644
index 0000000000..7673b43751
--- /dev/null
+++ b/library/cpp/monlib/metrics/log_histogram_snapshot.h
@@ -0,0 +1,71 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+
+#include <cmath>
+
+namespace NMonitoring {
+
+ constexpr ui32 LOG_HIST_MAX_BUCKETS = 100;
+
+ class TLogHistogramSnapshot: public TAtomicRefCount<TLogHistogramSnapshot> {
+ public:
+ TLogHistogramSnapshot(double base, ui64 zerosCount, int startPower, TVector<double> buckets)
+ : Base_(base)
+ , ZerosCount_(zerosCount)
+ , StartPower_(startPower)
+ , Buckets_(std::move(buckets)) {
+ }
+
+ /**
+ * @return buckets count.
+ */
+ ui32 Count() const noexcept {
+ return Buckets_.size();
+ }
+
+ /**
+ * @return upper bound for the bucket with particular index.
+ */
+ double UpperBound(int index) const noexcept {
+ return std::pow(Base_, StartPower_ + index);
+ }
+
+ /**
+ * @return value stored in the bucket with particular index.
+ */
+ double Bucket(ui32 index) const noexcept {
+ return Buckets_[index];
+ }
+
+ /**
+ * @return nonpositive values count
+ */
+ ui64 ZerosCount() const noexcept {
+ return ZerosCount_;
+ }
+
+ double Base() const noexcept {
+ return Base_;
+ }
+
+ int StartPower() const noexcept {
+ return StartPower_;
+ }
+
+ ui64 MemorySizeBytes() const noexcept {
+ return sizeof(*this) + Buckets_.capacity() * sizeof(double);
+ }
+
+ private:
+ double Base_;
+ ui64 ZerosCount_;
+ int StartPower_;
+ TVector<double> Buckets_;
+ };
+
+ using TLogHistogramSnapshotPtr = TIntrusivePtr<TLogHistogramSnapshot>;
+}
+
+std::ostream& operator<<(std::ostream& os, const NMonitoring::TLogHistogramSnapshot& hist);
diff --git a/library/cpp/monlib/metrics/metric.h b/library/cpp/monlib/metrics/metric.h
new file mode 100644
index 0000000000..b8ce12d753
--- /dev/null
+++ b/library/cpp/monlib/metrics/metric.h
@@ -0,0 +1,388 @@
+#pragma once
+
+#include "metric_consumer.h"
+
+#include <util/datetime/base.h>
+#include <util/generic/ptr.h>
+
+namespace NMonitoring {
+ ///////////////////////////////////////////////////////////////////////////////
+ // IMetric
+ ///////////////////////////////////////////////////////////////////////////////
+ class IMetric {
+ public:
+ virtual ~IMetric() = default;
+
+ virtual EMetricType Type() const noexcept = 0;
+ virtual void Accept(TInstant time, IMetricConsumer* consumer) const = 0;
+ };
+
+ using IMetricPtr = THolder<IMetric>;
+
+ class IGauge: public IMetric {
+ public:
+ EMetricType Type() const noexcept final {
+ return EMetricType::GAUGE;
+ }
+
+ virtual double Add(double n) noexcept = 0;
+ virtual void Set(double n) noexcept = 0;
+ virtual double Get() const noexcept = 0;
+ virtual void Reset() noexcept {
+ Set(0);
+ }
+ };
+
+ class ILazyGauge: public IMetric {
+ public:
+ EMetricType Type() const noexcept final {
+ return EMetricType::GAUGE;
+ }
+ virtual double Get() const noexcept = 0;
+ };
+
+ class IIntGauge: public IMetric {
+ public:
+ EMetricType Type() const noexcept final {
+ return EMetricType::IGAUGE;
+ }
+
+ virtual i64 Add(i64 n) noexcept = 0;
+ virtual i64 Inc() noexcept {
+ return Add(1);
+ }
+
+ virtual i64 Dec() noexcept {
+ return Add(-1);
+ }
+
+ virtual void Set(i64 value) noexcept = 0;
+ virtual i64 Get() const noexcept = 0;
+ virtual void Reset() noexcept {
+ Set(0);
+ }
+ };
+
+ class ILazyIntGauge: public IMetric {
+ public:
+ EMetricType Type() const noexcept final {
+ return EMetricType::IGAUGE;
+ }
+
+ virtual i64 Get() const noexcept = 0;
+ };
+
+ class ICounter: public IMetric {
+ public:
+ EMetricType Type() const noexcept final {
+ return EMetricType::COUNTER;
+ }
+
+ virtual ui64 Inc() noexcept {
+ return Add(1);
+ }
+
+ virtual ui64 Add(ui64 n) noexcept = 0;
+ virtual ui64 Get() const noexcept = 0;
+ virtual void Reset() noexcept = 0;
+ };
+
+ class ILazyCounter: public IMetric {
+ public:
+ EMetricType Type() const noexcept final {
+ return EMetricType::COUNTER;
+ }
+
+ virtual ui64 Get() const noexcept = 0;
+ };
+
+ class IRate: public IMetric {
+ public:
+ EMetricType Type() const noexcept final {
+ return EMetricType::RATE;
+ }
+
+ virtual ui64 Inc() noexcept {
+ return Add(1);
+ }
+
+ virtual ui64 Add(ui64 n) noexcept = 0;
+ virtual ui64 Get() const noexcept = 0;
+ virtual void Reset() noexcept = 0;
+ };
+
+ class ILazyRate: public IMetric {
+ public:
+ EMetricType Type() const noexcept final {
+ return EMetricType::RATE;
+ }
+
+ virtual ui64 Get() const noexcept = 0;
+ };
+
+ class IHistogram: public IMetric {
+ public:
+ explicit IHistogram(bool isRate)
+ : IsRate_{isRate}
+ {
+ }
+
+ EMetricType Type() const noexcept final {
+ return IsRate_ ? EMetricType::HIST_RATE : EMetricType::HIST;
+ }
+
+ virtual void Record(double value) = 0;
+ virtual void Record(double value, ui32 count) = 0;
+ virtual IHistogramSnapshotPtr TakeSnapshot() const = 0;
+ virtual void Reset() = 0;
+
+ protected:
+ const bool IsRate_;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // TGauge
+ ///////////////////////////////////////////////////////////////////////////////
+ class TGauge final: public IGauge {
+ public:
+ explicit TGauge(double value = 0.0) {
+ Set(value);
+ }
+
+ double Add(double n) noexcept override {
+ double newValue;
+ double oldValue = Get();
+
+ do {
+ newValue = oldValue + n;
+ } while (!Value_.compare_exchange_weak(oldValue, newValue, std::memory_order_release, std::memory_order_consume));
+
+ return newValue;
+ }
+
+ void Set(double n) noexcept override {
+ Value_.store(n, std::memory_order_relaxed);
+ }
+
+ double Get() const noexcept override {
+ return Value_.load(std::memory_order_relaxed);
+ }
+
+ void Accept(TInstant time, IMetricConsumer* consumer) const override {
+ consumer->OnDouble(time, Get());
+ }
+
+ private:
+ std::atomic<double> Value_;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // TLazyGauge
+ ///////////////////////////////////////////////////////////////////////////////
+ class TLazyGauge final: public ILazyGauge {
+ public:
+ explicit TLazyGauge(std::function<double()> supplier)
+ : Supplier_(std::move(supplier))
+ {
+ }
+
+ double Get() const noexcept override {
+ return Supplier_();
+ }
+
+ void Accept(TInstant time, IMetricConsumer* consumer) const override {
+ consumer->OnDouble(time, Get());
+ }
+
+ private:
+ std::function<double()> Supplier_;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // TIntGauge
+ ///////////////////////////////////////////////////////////////////////////////
+ class TIntGauge final: public IIntGauge {
+ public:
+ explicit TIntGauge(i64 value = 0) {
+ Set(value);
+ }
+
+ i64 Add(i64 n) noexcept override {
+ return Value_.fetch_add(n, std::memory_order_relaxed) + n;
+ }
+
+ void Set(i64 value) noexcept override {
+ Value_.store(value, std::memory_order_relaxed);
+ }
+
+ i64 Get() const noexcept override {
+ return Value_.load(std::memory_order_relaxed);
+ }
+
+ void Accept(TInstant time, IMetricConsumer* consumer) const override {
+ consumer->OnInt64(time, Get());
+ }
+
+ private:
+ std::atomic_int64_t Value_;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // TLazyIntGauge
+ ///////////////////////////////////////////////////////////////////////////////
+ class TLazyIntGauge final: public ILazyIntGauge {
+ public:
+ explicit TLazyIntGauge(std::function<i64()> supplier)
+ : Supplier_(std::move(supplier))
+ {
+ }
+
+ i64 Get() const noexcept override {
+ return Supplier_();
+ }
+
+ void Accept(TInstant time, IMetricConsumer* consumer) const override {
+ consumer->OnInt64(time, Get());
+ }
+
+ private:
+ std::function<i64()> Supplier_;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // TCounter
+ ///////////////////////////////////////////////////////////////////////////////
+ class TCounter final: public ICounter {
+ public:
+ explicit TCounter(ui64 value = 0) {
+ Value_.store(value, std::memory_order_relaxed);
+ }
+
+ ui64 Add(ui64 n) noexcept override {
+ return Value_.fetch_add(n, std::memory_order_relaxed) + n;
+ }
+
+ ui64 Get() const noexcept override {
+ return Value_.load(std::memory_order_relaxed);
+ }
+
+ void Reset() noexcept override {
+ Value_.store(0, std::memory_order_relaxed);
+ }
+
+ void Accept(TInstant time, IMetricConsumer* consumer) const override {
+ consumer->OnUint64(time, Get());
+ }
+
+ private:
+ std::atomic_uint64_t Value_;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // TLazyCounter
+ ///////////////////////////////////////////////////////////////////////////////
+ class TLazyCounter final: public ILazyCounter {
+ public:
+ explicit TLazyCounter(std::function<ui64()> supplier)
+ : Supplier_(std::move(supplier))
+ {
+ }
+
+ ui64 Get() const noexcept override {
+ return Supplier_();
+ }
+
+ void Accept(TInstant time, IMetricConsumer* consumer) const override {
+ consumer->OnUint64(time, Get());
+ }
+
+ private:
+ std::function<ui64()> Supplier_;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // TRate
+ ///////////////////////////////////////////////////////////////////////////////
+ class TRate final: public IRate {
+ public:
+ explicit TRate(ui64 value = 0) {
+ Value_.store(value, std::memory_order_relaxed);
+ }
+
+ ui64 Add(ui64 n) noexcept override {
+ return Value_.fetch_add(n, std::memory_order_relaxed) + n;
+ }
+
+ ui64 Get() const noexcept override {
+ return Value_.load(std::memory_order_relaxed);
+ }
+
+ void Reset() noexcept override {
+ Value_.store(0, std::memory_order_relaxed);
+ }
+
+ void Accept(TInstant time, IMetricConsumer* consumer) const override {
+ consumer->OnUint64(time, Get());
+ }
+
+ private:
+ std::atomic_uint64_t Value_;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // TLazyRate
+ ///////////////////////////////////////////////////////////////////////////////
+ class TLazyRate final: public ILazyRate {
+ public:
+ explicit TLazyRate(std::function<ui64()> supplier)
+ : Supplier_(std::move(supplier))
+ {
+ }
+
+ ui64 Get() const noexcept override {
+ return Supplier_();
+ }
+
+ void Accept(TInstant time, IMetricConsumer* consumer) const override {
+ consumer->OnUint64(time, Get());
+ }
+
+ private:
+ std::function<ui64()> Supplier_;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // THistogram
+ ///////////////////////////////////////////////////////////////////////////////
+ class THistogram final: public IHistogram {
+ public:
+ THistogram(IHistogramCollectorPtr collector, bool isRate)
+ : IHistogram(isRate)
+ , Collector_(std::move(collector))
+ {
+ }
+
+ void Record(double value) override {
+ Collector_->Collect(value);
+ }
+
+ void Record(double value, ui32 count) override {
+ Collector_->Collect(value, count);
+ }
+
+ void Accept(TInstant time, IMetricConsumer* consumer) const override {
+ consumer->OnHistogram(time, TakeSnapshot());
+ }
+
+ IHistogramSnapshotPtr TakeSnapshot() const override {
+ return Collector_->Snapshot();
+ }
+
+ void Reset() override {
+ Collector_->Reset();
+ }
+
+ private:
+ IHistogramCollectorPtr Collector_;
+ };
+}
diff --git a/library/cpp/monlib/metrics/metric_consumer.cpp b/library/cpp/monlib/metrics/metric_consumer.cpp
new file mode 100644
index 0000000000..121ee368f0
--- /dev/null
+++ b/library/cpp/monlib/metrics/metric_consumer.cpp
@@ -0,0 +1,15 @@
+#include "metric_consumer.h"
+
+#include <util/system/yassert.h>
+
+namespace NMonitoring {
+ void IMetricConsumer::OnLabel(ui32 name, ui32 value) {
+ Y_UNUSED(name, value);
+ Y_ENSURE(false, "Not implemented");
+ }
+
+ std::pair<ui32, ui32> IMetricConsumer::PrepareLabel(TStringBuf name, TStringBuf value) {
+ Y_UNUSED(name, value);
+ Y_ENSURE(false, "Not implemented");
+ }
+}
diff --git a/library/cpp/monlib/metrics/metric_consumer.h b/library/cpp/monlib/metrics/metric_consumer.h
new file mode 100644
index 0000000000..f7a727585a
--- /dev/null
+++ b/library/cpp/monlib/metrics/metric_consumer.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "metric_type.h"
+#include "histogram_collector.h"
+#include "summary_collector.h"
+#include "log_histogram_snapshot.h"
+
+class TInstant;
+
+namespace NMonitoring {
+ class IMetricConsumer {
+ public:
+ virtual ~IMetricConsumer() = default;
+
+ virtual void OnStreamBegin() = 0;
+ virtual void OnStreamEnd() = 0;
+
+ virtual void OnCommonTime(TInstant time) = 0;
+
+ virtual void OnMetricBegin(EMetricType type) = 0;
+ virtual void OnMetricEnd() = 0;
+
+ virtual void OnLabelsBegin() = 0;
+ virtual void OnLabelsEnd() = 0;
+ virtual void OnLabel(TStringBuf name, TStringBuf value) = 0;
+ virtual void OnLabel(ui32 name, ui32 value);
+ virtual std::pair<ui32, ui32> PrepareLabel(TStringBuf name, TStringBuf value);
+
+ virtual void OnDouble(TInstant time, double value) = 0;
+ virtual void OnInt64(TInstant time, i64 value) = 0;
+ virtual void OnUint64(TInstant time, ui64 value) = 0;
+
+ virtual void OnHistogram(TInstant time, IHistogramSnapshotPtr snapshot) = 0;
+ virtual void OnLogHistogram(TInstant time, TLogHistogramSnapshotPtr snapshot) = 0;
+ virtual void OnSummaryDouble(TInstant time, ISummaryDoubleSnapshotPtr snapshot) = 0;
+ };
+
+ using IMetricConsumerPtr = THolder<IMetricConsumer>;
+
+}
diff --git a/library/cpp/monlib/metrics/metric_registry.cpp b/library/cpp/monlib/metrics/metric_registry.cpp
new file mode 100644
index 0000000000..e46141ccde
--- /dev/null
+++ b/library/cpp/monlib/metrics/metric_registry.cpp
@@ -0,0 +1,225 @@
+#include "metric_registry.h"
+
+#include <memory>
+
+namespace NMonitoring {
+ namespace {
+ void ConsumeLabels(IMetricConsumer* consumer, const ILabels& labels) {
+ for (auto&& label: labels) {
+ consumer->OnLabel(label.Name(), label.Value());
+ }
+ }
+
+ template <typename TLabelsConsumer>
+ void ConsumeMetric(TInstant time, IMetricConsumer* consumer, IMetric* metric, TLabelsConsumer&& labelsConsumer) {
+ consumer->OnMetricBegin(metric->Type());
+
+ // (1) add labels
+ consumer->OnLabelsBegin();
+ labelsConsumer();
+ consumer->OnLabelsEnd();
+
+ // (2) add time and value
+ metric->Accept(time, consumer);
+ consumer->OnMetricEnd();
+ }
+ }
+
+ void WriteLabels(IMetricConsumer* consumer, const ILabels& labels) {
+ consumer->OnLabelsBegin();
+ ConsumeLabels(consumer, labels);
+ consumer->OnLabelsEnd();
+ }
+
+ TMetricRegistry::TMetricRegistry() = default;
+ TMetricRegistry::~TMetricRegistry() = default;
+
+ TMetricRegistry::TMetricRegistry(const TLabels& commonLabels)
+ : TMetricRegistry{}
+ {
+ CommonLabels_ = commonLabels;
+ }
+
+ TMetricRegistry* TMetricRegistry::Instance() {
+ return Singleton<TMetricRegistry>();
+ }
+
+ TGauge* TMetricRegistry::Gauge(TLabels labels) {
+ return Metric<TGauge, EMetricType::GAUGE>(std::move(labels));
+ }
+
+ TGauge* TMetricRegistry::Gauge(ILabelsPtr labels) {
+ return Metric<TGauge, EMetricType::GAUGE>(std::move(labels));
+ }
+
+ TLazyGauge* TMetricRegistry::LazyGauge(TLabels labels, std::function<double()> supplier) {
+ return Metric<TLazyGauge, EMetricType::GAUGE>(std::move(labels), std::move(supplier));
+ }
+
+ TLazyGauge* TMetricRegistry::LazyGauge(ILabelsPtr labels, std::function<double()> supplier) {
+ return Metric<TLazyGauge, EMetricType::GAUGE>(std::move(labels), std::move(supplier));
+ }
+
+ TIntGauge* TMetricRegistry::IntGauge(TLabels labels) {
+ return Metric<TIntGauge, EMetricType::IGAUGE>(std::move(labels));
+ }
+
+ TIntGauge* TMetricRegistry::IntGauge(ILabelsPtr labels) {
+ return Metric<TIntGauge, EMetricType::IGAUGE>(std::move(labels));
+ }
+
+ TLazyIntGauge* TMetricRegistry::LazyIntGauge(TLabels labels, std::function<i64()> supplier) {
+ return Metric<TLazyIntGauge, EMetricType::GAUGE>(std::move(labels), std::move(supplier));
+ }
+
+ TLazyIntGauge* TMetricRegistry::LazyIntGauge(ILabelsPtr labels, std::function<i64()> supplier) {
+ return Metric<TLazyIntGauge, EMetricType::GAUGE>(std::move(labels), std::move(supplier));
+ }
+
+ TCounter* TMetricRegistry::Counter(TLabels labels) {
+ return Metric<TCounter, EMetricType::COUNTER>(std::move(labels));
+ }
+
+ TCounter* TMetricRegistry::Counter(ILabelsPtr labels) {
+ return Metric<TCounter, EMetricType::COUNTER>(std::move(labels));
+ }
+
+ TLazyCounter* TMetricRegistry::LazyCounter(TLabels labels, std::function<ui64()> supplier) {
+ return Metric<TLazyCounter, EMetricType::COUNTER>(std::move(labels), std::move(supplier));
+ }
+
+ TLazyCounter* TMetricRegistry::LazyCounter(ILabelsPtr labels, std::function<ui64()> supplier) {
+ return Metric<TLazyCounter, EMetricType::COUNTER>(std::move(labels), std::move(supplier));
+ }
+
+ TRate* TMetricRegistry::Rate(TLabels labels) {
+ return Metric<TRate, EMetricType::RATE>(std::move(labels));
+ }
+
+ TRate* TMetricRegistry::Rate(ILabelsPtr labels) {
+ return Metric<TRate, EMetricType::RATE>(std::move(labels));
+ }
+
+ TLazyRate* TMetricRegistry::LazyRate(TLabels labels, std::function<ui64()> supplier) {
+ return Metric<TLazyRate, EMetricType::RATE>(std::move(labels), std::move(supplier));
+ }
+
+ TLazyRate* TMetricRegistry::LazyRate(ILabelsPtr labels, std::function<ui64()> supplier) {
+ return Metric<TLazyRate, EMetricType::RATE>(std::move(labels), std::move(supplier));
+ }
+
+ THistogram* TMetricRegistry::HistogramCounter(TLabels labels, IHistogramCollectorPtr collector) {
+ return Metric<THistogram, EMetricType::HIST>(std::move(labels), std::move(collector), false);
+ }
+
+ THistogram* TMetricRegistry::HistogramCounter(ILabelsPtr labels, IHistogramCollectorPtr collector) {
+ return Metric<THistogram, EMetricType::HIST>(std::move(labels), std::move(collector), false);
+ }
+
+ THistogram* TMetricRegistry::HistogramRate(TLabels labels, IHistogramCollectorPtr collector) {
+ return Metric<THistogram, EMetricType::HIST_RATE>(std::move(labels), std::move(collector), true);
+ }
+
+ THistogram* TMetricRegistry::HistogramRate(ILabelsPtr labels, IHistogramCollectorPtr collector) {
+ return Metric<THistogram, EMetricType::HIST_RATE>(std::move(labels), std::move(collector), true);
+ }
+
+ void TMetricRegistry::Reset() {
+ TWriteGuard g{Lock_};
+ for (auto& [label, metric] : Metrics_) {
+ switch (metric->Type()) {
+ case EMetricType::GAUGE:
+ static_cast<TGauge*>(metric.Get())->Set(.0);
+ break;
+ case EMetricType::IGAUGE:
+ static_cast<TIntGauge*>(metric.Get())->Set(0);
+ break;
+ case EMetricType::COUNTER:
+ static_cast<TCounter*>(metric.Get())->Reset();
+ break;
+ case EMetricType::RATE:
+ static_cast<TRate*>(metric.Get())->Reset();
+ break;
+ case EMetricType::HIST:
+ case EMetricType::HIST_RATE:
+ static_cast<THistogram*>(metric.Get())->Reset();
+ break;
+ case EMetricType::UNKNOWN:
+ case EMetricType::DSUMMARY:
+ case EMetricType::LOGHIST:
+ break;
+ }
+ }
+ }
+
+ template <typename TMetric, EMetricType type, typename TLabelsType, typename... Args>
+ TMetric* TMetricRegistry::Metric(TLabelsType&& labels, Args&&... args) {
+ {
+ TReadGuard g{Lock_};
+
+ auto it = Metrics_.find(labels);
+ if (it != Metrics_.end()) {
+ Y_ENSURE(it->second->Type() == type, "cannot create metric " << labels
+ << " with type " << MetricTypeToStr(type)
+ << ", because registry already has same metric with type " << MetricTypeToStr(it->second->Type()));
+ return static_cast<TMetric*>(it->second.Get());
+ }
+ }
+
+ {
+ IMetricPtr metric = MakeHolder<TMetric>(std::forward<Args>(args)...);
+
+ TWriteGuard g{Lock_};
+ // decltype(Metrics_)::iterator breaks build on windows
+ THashMap<ILabelsPtr, IMetricPtr>::iterator it;
+ if constexpr (!std::is_convertible_v<TLabelsType, ILabelsPtr>) {
+ it = Metrics_.emplace(new TLabels{std::forward<TLabelsType>(labels)}, std::move(metric)).first;
+ } else {
+ it = Metrics_.emplace(std::forward<TLabelsType>(labels), std::move(metric)).first;
+ }
+
+ return static_cast<TMetric*>(it->second.Get());
+ }
+ }
+
+ void TMetricRegistry::RemoveMetric(const ILabels& labels) noexcept {
+ TWriteGuard g{Lock_};
+ Metrics_.erase(labels);
+ }
+
+ void TMetricRegistry::Accept(TInstant time, IMetricConsumer* consumer) const {
+ consumer->OnStreamBegin();
+
+ if (!CommonLabels_.Empty()) {
+ consumer->OnLabelsBegin();
+ ConsumeLabels(consumer, CommonLabels_);
+ consumer->OnLabelsEnd();
+ }
+
+ {
+ TReadGuard g{Lock_};
+ for (const auto& it: Metrics_) {
+ ILabels* labels = it.first.Get();
+ IMetric* metric = it.second.Get();
+ ConsumeMetric(time, consumer, metric, [&]() {
+ ConsumeLabels(consumer, *labels);
+ });
+ }
+ }
+
+ consumer->OnStreamEnd();
+ }
+
+ void TMetricRegistry::Append(TInstant time, IMetricConsumer* consumer) const {
+ TReadGuard g{Lock_};
+
+ for (const auto& it: Metrics_) {
+ ILabels* labels = it.first.Get();
+ IMetric* metric = it.second.Get();
+ ConsumeMetric(time, consumer, metric, [&]() {
+ ConsumeLabels(consumer, CommonLabels_);
+ ConsumeLabels(consumer, *labels);
+ });
+ }
+ }
+}
diff --git a/library/cpp/monlib/metrics/metric_registry.h b/library/cpp/monlib/metrics/metric_registry.h
new file mode 100644
index 0000000000..68b2d652cb
--- /dev/null
+++ b/library/cpp/monlib/metrics/metric_registry.h
@@ -0,0 +1,122 @@
+#pragma once
+
+#include "labels.h"
+#include "metric.h"
+
+#include <util/system/rwlock.h>
+
+#include <library/cpp/threading/light_rw_lock/lightrwlock.h>
+
+
+namespace NMonitoring {
+ class IMetricFactory {
+ public:
+ virtual ~IMetricFactory() = default;
+
+ virtual IGauge* Gauge(ILabelsPtr labels) = 0;
+ virtual ILazyGauge* LazyGauge(ILabelsPtr labels, std::function<double()> supplier) = 0;
+ virtual IIntGauge* IntGauge(ILabelsPtr labels) = 0;
+ virtual ILazyIntGauge* LazyIntGauge(ILabelsPtr labels, std::function<i64()> supplier) = 0;
+ virtual ICounter* Counter(ILabelsPtr labels) = 0;
+ virtual ILazyCounter* LazyCounter(ILabelsPtr labels, std::function<ui64()> supplier) = 0;
+
+ virtual IRate* Rate(ILabelsPtr labels) = 0;
+ virtual ILazyRate* LazyRate(ILabelsPtr labels, std::function<ui64()> supplier) = 0;
+
+ virtual IHistogram* HistogramCounter(
+ ILabelsPtr labels,
+ IHistogramCollectorPtr collector) = 0;
+
+ virtual IHistogram* HistogramRate(
+ ILabelsPtr labels,
+ IHistogramCollectorPtr collector) = 0;
+ };
+
+ class IMetricSupplier {
+ public:
+ virtual ~IMetricSupplier() = default;
+
+ virtual void Accept(TInstant time, IMetricConsumer* consumer) const = 0;
+ virtual void Append(TInstant time, IMetricConsumer* consumer) const = 0;
+ };
+
+ class IMetricRegistry: public IMetricSupplier, public IMetricFactory {
+ public:
+ virtual const TLabels& CommonLabels() const noexcept = 0;
+ virtual void RemoveMetric(const ILabels& labels) noexcept = 0;
+ };
+
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // TMetricRegistry
+ ///////////////////////////////////////////////////////////////////////////////
+ class TMetricRegistry: public IMetricRegistry {
+ public:
+ TMetricRegistry();
+ ~TMetricRegistry();
+
+ explicit TMetricRegistry(const TLabels& commonLabels);
+
+ /**
+ * Get a global metrics registry instance.
+ */
+ static TMetricRegistry* Instance();
+
+ TGauge* Gauge(TLabels labels);
+ TLazyGauge* LazyGauge(TLabels labels, std::function<double()> supplier);
+ TIntGauge* IntGauge(TLabels labels);
+ TLazyIntGauge* LazyIntGauge(TLabels labels, std::function<i64()> supplier);
+ TCounter* Counter(TLabels labels);
+ TLazyCounter* LazyCounter(TLabels labels, std::function<ui64()> supplier);
+ TRate* Rate(TLabels labels);
+ TLazyRate* LazyRate(TLabels labels, std::function<ui64()> supplier);
+
+ THistogram* HistogramCounter(
+ TLabels labels,
+ IHistogramCollectorPtr collector);
+
+ THistogram* HistogramRate(
+ TLabels labels,
+ IHistogramCollectorPtr collector);
+
+ void Reset();
+
+ void Accept(TInstant time, IMetricConsumer* consumer) const override;
+ void Append(TInstant time, IMetricConsumer* consumer) const override;
+
+ const TLabels& CommonLabels() const noexcept override {
+ return CommonLabels_;
+ }
+
+ void RemoveMetric(const ILabels& labels) noexcept override;
+
+ private:
+ TGauge* Gauge(ILabelsPtr labels) override;
+ TLazyGauge* LazyGauge(ILabelsPtr labels, std::function<double()> supplier) override;
+ TIntGauge* IntGauge(ILabelsPtr labels) override;
+ TLazyIntGauge* LazyIntGauge(ILabelsPtr labels, std::function<i64()> supplier) override;
+ TCounter* Counter(ILabelsPtr labels) override;
+ TLazyCounter* LazyCounter(ILabelsPtr labels, std::function<ui64()> supplier) override;
+ TRate* Rate(ILabelsPtr labels) override;
+ TLazyRate* LazyRate(ILabelsPtr labels, std::function<ui64()> supplier) override;
+
+ THistogram* HistogramCounter(
+ ILabelsPtr labels,
+ IHistogramCollectorPtr collector) override;
+
+ THistogram* HistogramRate(
+ ILabelsPtr labels,
+ IHistogramCollectorPtr collector) override;
+
+ private:
+ TRWMutex Lock_;
+ THashMap<ILabelsPtr, IMetricPtr> Metrics_;
+
+ template <typename TMetric, EMetricType type, typename TLabelsType, typename... Args>
+ TMetric* Metric(TLabelsType&& labels, Args&&... args);
+
+ TLabels CommonLabels_;
+ };
+
+ void WriteLabels(IMetricConsumer* consumer, const ILabels& labels);
+}
diff --git a/library/cpp/monlib/metrics/metric_registry_ut.cpp b/library/cpp/monlib/metrics/metric_registry_ut.cpp
new file mode 100644
index 0000000000..afcbcd6801
--- /dev/null
+++ b/library/cpp/monlib/metrics/metric_registry_ut.cpp
@@ -0,0 +1,302 @@
+#include "metric_registry.h"
+
+#include <library/cpp/monlib/encode/protobuf/protobuf.h>
+#include <library/cpp/monlib/encode/json/json.h>
+#include <library/cpp/resource/resource.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/str.h>
+
+using namespace NMonitoring;
+
+template<>
+void Out<NMonitoring::NProto::TSingleSample::ValueCase>(IOutputStream& os, NMonitoring::NProto::TSingleSample::ValueCase val) {
+ switch (val) {
+ case NMonitoring::NProto::TSingleSample::ValueCase::kInt64:
+ os << "Int64";
+ break;
+ case NMonitoring::NProto::TSingleSample::ValueCase::kUint64:
+ os << "Uint64";
+ break;
+ case NMonitoring::NProto::TSingleSample::ValueCase::kHistogram:
+ os << "Histogram";
+ break;
+ case NMonitoring::NProto::TSingleSample::ValueCase::kFloat64:
+ os << "Float64";
+ break;
+ case NMonitoring::NProto::TSingleSample::ValueCase::kSummaryDouble:
+ os << "DSummary";
+ break;
+ case NMonitoring::NProto::TSingleSample::ValueCase::kLogHistogram:
+ os << "LogHistogram";
+ break;
+ case NMonitoring::NProto::TSingleSample::ValueCase::VALUE_NOT_SET:
+ os << "NOT SET";
+ break;
+ }
+}
+
+Y_UNIT_TEST_SUITE(TMetricRegistryTest) {
+ Y_UNIT_TEST(Gauge) {
+ TMetricRegistry registry(TLabels{{"common", "label"}});
+ TGauge* g = registry.Gauge({{"my", "gauge"}});
+
+ UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 0.0, 1E-6);
+ g->Set(12.34);
+ UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 12.34, 1E-6);
+
+ double val;
+
+ val = g->Add(1.2);
+ UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 13.54, 1E-6);
+ UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), val, 1E-6);
+
+ val = g->Add(-3.47);
+ UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 10.07, 1E-6);
+ UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), val, 1E-6);
+ }
+
+ Y_UNIT_TEST(LazyGauge) {
+ TMetricRegistry registry(TLabels{{"common", "label"}});
+ double val = 0.0;
+ TLazyGauge* g = registry.LazyGauge({{"my", "lazyGauge"}}, [&val](){return val;});
+
+ UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 0.0, 1E-6);
+ val = 12.34;
+ UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 12.34, 1E-6);
+
+ val += 1.2;
+ UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 13.54, 1E-6);
+ UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), val, 1E-6);
+
+ val += -3.47;
+ UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 10.07, 1E-6);
+ UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), val, 1E-6);
+ }
+
+ Y_UNIT_TEST(IntGauge) {
+ TMetricRegistry registry(TLabels{{"common", "label"}});
+ TIntGauge* g = registry.IntGauge({{"my", "gauge"}});
+
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), 0);
+
+ i64 val;
+
+ val = g->Inc();
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), val);
+
+ val = g->Dec();
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), 0);
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), val);
+
+ val = g->Add(1);
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), val);
+
+ val = g->Add(2);
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), 3);
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), val);
+
+ val = g->Add(-5);
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), -2);
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), val);
+ }
+
+ Y_UNIT_TEST(LazyIntGauge) {
+ TMetricRegistry registry(TLabels{{"common", "label"}});
+ i64 val = 0;
+ TLazyIntGauge* g = registry.LazyIntGauge({{"my", "gauge"}}, [&val](){return val;});
+
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), 0);
+ val += 1;
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), val);
+
+ val -= 1;
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), 0);
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), val);
+
+ val = 42;
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), val);
+ }
+
+ Y_UNIT_TEST(Counter) {
+ TMetricRegistry registry(TLabels{{"common", "label"}});
+ TCounter* c = registry.Counter({{"my", "counter"}});
+
+ UNIT_ASSERT_VALUES_EQUAL(c->Get(), 0);
+ UNIT_ASSERT_VALUES_EQUAL(c->Inc(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(c->Get(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(c->Add(10), 11);
+ UNIT_ASSERT_VALUES_EQUAL(c->Get(), 11);
+ }
+
+ Y_UNIT_TEST(LazyCounter) {
+ TMetricRegistry registry(TLabels{{"common", "label"}});
+ ui64 val = 0;
+
+ TLazyCounter* c = registry.LazyCounter({{"my", "counter"}}, [&val](){return val;});
+
+ UNIT_ASSERT_VALUES_EQUAL(c->Get(), 0);
+ val = 42;
+ UNIT_ASSERT_VALUES_EQUAL(c->Get(), 42);
+ }
+
+ Y_UNIT_TEST(LazyRate) {
+ TMetricRegistry registry(TLabels{{"common", "label"}});
+ ui64 val = 0;
+
+ TLazyRate* r = registry.LazyRate({{"my", "rate"}}, [&val](){return val;});
+
+ UNIT_ASSERT_VALUES_EQUAL(r->Get(), 0);
+ val = 42;
+ UNIT_ASSERT_VALUES_EQUAL(r->Get(), 42);
+ }
+
+ Y_UNIT_TEST(DoubleCounter) {
+ TMetricRegistry registry(TLabels{{"common", "label"}});
+
+ TCounter* c = registry.Counter({{"my", "counter"}});
+ UNIT_ASSERT_VALUES_EQUAL(c->Get(), 0);
+ c->Add(10);
+
+ c = registry.Counter({{"my", "counter"}});
+ UNIT_ASSERT_VALUES_EQUAL(c->Get(), 10);
+ }
+
+ Y_UNIT_TEST(Sample) {
+ TMetricRegistry registry(TLabels{{"common", "label"}});
+
+ TGauge* g = registry.Gauge({{"my", "gauge"}});
+ g->Set(12.34);
+
+ TCounter* c = registry.Counter({{"my", "counter"}});
+ c->Add(10);
+
+ NProto::TSingleSamplesList samples;
+ auto encoder = EncoderProtobuf(&samples);
+ auto now = TInstant::Now();
+ registry.Accept(now, encoder.Get());
+
+ UNIT_ASSERT_VALUES_EQUAL(samples.SamplesSize(), 2);
+ UNIT_ASSERT_VALUES_EQUAL(samples.CommonLabelsSize(), 1);
+ {
+ const NProto::TLabel& label = samples.GetCommonLabels(0);
+ UNIT_ASSERT_STRINGS_EQUAL(label.GetName(), "common");
+ UNIT_ASSERT_STRINGS_EQUAL(label.GetValue(), "label");
+ }
+
+
+ for (const NProto::TSingleSample& sample : samples.GetSamples()) {
+ UNIT_ASSERT_VALUES_EQUAL(sample.LabelsSize(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(sample.GetTime(), now.MilliSeconds());
+
+ if (sample.GetMetricType() == NProto::GAUGE) {
+ UNIT_ASSERT_VALUES_EQUAL(sample.GetValueCase(), NProto::TSingleSample::kFloat64);
+ UNIT_ASSERT_DOUBLES_EQUAL(sample.GetFloat64(), 12.34, 1E-6);
+
+ const NProto::TLabel& label = sample.GetLabels(0);
+ UNIT_ASSERT_STRINGS_EQUAL(label.GetName(), "my");
+ UNIT_ASSERT_STRINGS_EQUAL(label.GetValue(), "gauge");
+ } else if (sample.GetMetricType() == NProto::COUNTER) {
+ UNIT_ASSERT_VALUES_EQUAL(sample.GetValueCase(), NProto::TSingleSample::kUint64);
+ UNIT_ASSERT_VALUES_EQUAL(sample.GetUint64(), 10);
+
+ const NProto::TLabel& label = sample.GetLabels(0);
+ UNIT_ASSERT_STRINGS_EQUAL(label.GetName(), "my");
+ UNIT_ASSERT_STRINGS_EQUAL(label.GetValue(), "counter");
+ } else {
+ UNIT_FAIL("unexpected sample type");
+ }
+ }
+ }
+
+ Y_UNIT_TEST(Histograms) {
+ TMetricRegistry registry(TLabels{{"common", "label"}});
+
+ THistogram* h1 = registry.HistogramCounter(
+ {{"sensor", "readTimeMillis"}},
+ ExponentialHistogram(5, 2));
+
+ THistogram* h2 = registry.HistogramRate(
+ {{"sensor", "writeTimeMillis"}},
+ ExplicitHistogram({1, 5, 15, 20, 25}));
+
+ for (i64 i = 0; i < 100; i++) {
+ h1->Record(i);
+ h2->Record(i);
+ }
+
+ TStringStream ss;
+ {
+ auto encoder = EncoderJson(&ss, 2);
+ registry.Accept(TInstant::Zero(), encoder.Get());
+ }
+ ss << '\n';
+
+ UNIT_ASSERT_NO_DIFF(ss.Str(), NResource::Find("/histograms.json"));
+ }
+
+ Y_UNIT_TEST(StreamingEncoderTest) {
+ const TString expected {
+ "{\"commonLabels\":{\"common\":\"label\"},"
+ "\"sensors\":[{\"kind\":\"GAUGE\",\"labels\":{\"my\":\"gauge\"},\"value\":12.34}]}"
+ };
+
+ TMetricRegistry registry(TLabels{{"common", "label"}});
+
+ TGauge* g = registry.Gauge({{"my", "gauge"}});
+ g->Set(12.34);
+
+ TStringStream os;
+ auto encoder = EncoderJson(&os);
+ registry.Accept(TInstant::Zero(), encoder.Get());
+
+ UNIT_ASSERT_STRINGS_EQUAL(os.Str(), expected);
+ }
+
+ Y_UNIT_TEST(CreatingSameMetricWithDifferentTypesShouldThrow) {
+ TMetricRegistry registry;
+
+ registry.Gauge({{"foo", "bar"}});
+ UNIT_ASSERT_EXCEPTION(registry.Counter({{"foo", "bar"}}), yexception);
+
+ registry.HistogramCounter({{"bar", "baz"}}, nullptr);
+ UNIT_ASSERT_EXCEPTION(registry.HistogramRate({{"bar", "baz"}}, nullptr), yexception);
+ }
+
+ Y_UNIT_TEST(EncodeRegistryWithCommonLabels) {
+ TMetricRegistry registry(TLabels{{"common", "label"}});
+
+ TGauge* g = registry.Gauge({{"my", "gauge"}});
+ g->Set(12.34);
+
+ // Append() adds common labels to each metric, allowing to combine
+ // several metric registries in one resulting blob
+ {
+ TStringStream os;
+ auto encoder = EncoderJson(&os);
+ encoder->OnStreamBegin();
+ registry.Append(TInstant::Zero(), encoder.Get());
+ encoder->OnStreamEnd();
+
+ UNIT_ASSERT_STRINGS_EQUAL(
+ os.Str(),
+ "{\"sensors\":[{\"kind\":\"GAUGE\",\"labels\":{\"common\":\"label\",\"my\":\"gauge\"},\"value\":12.34}]}");
+ }
+
+ // Accept() adds common labels to the beginning of the blob
+ {
+ TStringStream os;
+ auto encoder = EncoderJson(&os);
+ registry.Accept(TInstant::Zero(), encoder.Get());
+
+ UNIT_ASSERT_STRINGS_EQUAL(
+ os.Str(),
+ "{\"commonLabels\":{\"common\":\"label\"},"
+ "\"sensors\":[{\"kind\":\"GAUGE\",\"labels\":{\"my\":\"gauge\"},\"value\":12.34}]}");
+ }
+ }
+}
diff --git a/library/cpp/monlib/metrics/metric_sub_registry.h b/library/cpp/monlib/metrics/metric_sub_registry.h
new file mode 100644
index 0000000000..e83eeeafb2
--- /dev/null
+++ b/library/cpp/monlib/metrics/metric_sub_registry.h
@@ -0,0 +1,116 @@
+#pragma once
+
+#include "metric_registry.h"
+
+namespace NMonitoring {
+
+/**
+ * This registry is wrapping given delegate registry to add common labels
+ * to all created metrics through this sub registry.
+ */
+class TMetricSubRegistry final: public IMetricRegistry {
+public:
+ /**
+ * Do not keep ownership of the given delegate.
+ */
+ TMetricSubRegistry(TLabels commonLabels, IMetricRegistry* delegate) noexcept
+ : CommonLabels_{std::move(commonLabels)}
+ , DelegatePtr_{delegate}
+ {
+ }
+
+ /**
+ * Keeps ownership of the given delegate.
+ */
+ TMetricSubRegistry(TLabels commonLabels, std::shared_ptr<IMetricRegistry> delegate) noexcept
+ : CommonLabels_{std::move(commonLabels)}
+ , Delegate_{std::move(delegate)}
+ , DelegatePtr_{Delegate_.get()}
+ {
+ }
+
+ IGauge* Gauge(ILabelsPtr labels) override {
+ AddCommonLabels(labels.Get());
+ return DelegatePtr_->Gauge(std::move(labels));
+ }
+
+ ILazyGauge* LazyGauge(ILabelsPtr labels, std::function<double()> supplier) override {
+ AddCommonLabels(labels.Get());
+ return DelegatePtr_->LazyGauge(std::move(labels), std::move(supplier));
+ }
+
+ IIntGauge* IntGauge(ILabelsPtr labels) override {
+ AddCommonLabels(labels.Get());
+ return DelegatePtr_->IntGauge(std::move(labels));
+ }
+
+ ILazyIntGauge* LazyIntGauge(ILabelsPtr labels, std::function<i64()> supplier) override {
+ AddCommonLabels(labels.Get());
+ return DelegatePtr_->LazyIntGauge(std::move(labels), std::move(supplier));
+ }
+
+ ICounter* Counter(ILabelsPtr labels) override {
+ AddCommonLabels(labels.Get());
+ return DelegatePtr_->Counter(std::move(labels));
+ }
+
+ ILazyCounter* LazyCounter(ILabelsPtr labels, std::function<ui64()> supplier) override {
+ AddCommonLabels(labels.Get());
+ return DelegatePtr_->LazyCounter(std::move(labels), std::move(supplier));
+ }
+
+ IRate* Rate(ILabelsPtr labels) override {
+ AddCommonLabels(labels.Get());
+ return DelegatePtr_->Rate(std::move(labels));
+ }
+
+ ILazyRate* LazyRate(ILabelsPtr labels, std::function<ui64()> supplier) override {
+ AddCommonLabels(labels.Get());
+ return DelegatePtr_->LazyRate(std::move(labels), std::move(supplier));
+ }
+
+ IHistogram* HistogramCounter(ILabelsPtr labels, IHistogramCollectorPtr collector) override {
+ AddCommonLabels(labels.Get());
+ return DelegatePtr_->HistogramCounter(std::move(labels), std::move(collector));
+ }
+
+ IHistogram* HistogramRate(ILabelsPtr labels, IHistogramCollectorPtr collector) override {
+ AddCommonLabels(labels.Get());
+ return DelegatePtr_->HistogramRate(std::move(labels), std::move(collector));
+ }
+
+ void Accept(TInstant time, IMetricConsumer* consumer) const override {
+ DelegatePtr_->Accept(time, consumer);
+ }
+
+ void Append(TInstant time, IMetricConsumer* consumer) const override {
+ DelegatePtr_->Append(time, consumer);
+ }
+
+ const TLabels& CommonLabels() const noexcept override {
+ return CommonLabels_;
+ }
+
+ void RemoveMetric(const ILabels& labels) noexcept override {
+ TLabelsImpl<TStringBuf> toRemove;
+ for (auto& l: labels) {
+ toRemove.Add(l);
+ }
+ AddCommonLabels(&toRemove);
+ DelegatePtr_->RemoveMetric(toRemove);
+ }
+
+private:
+ void AddCommonLabels(ILabels* labels) const {
+ for (auto& label: CommonLabels_) {
+ labels->Add(label);
+ }
+ }
+
+private:
+ const TLabels CommonLabels_;
+ std::shared_ptr<IMetricRegistry> Delegate_;
+ IMetricRegistry* DelegatePtr_;
+};
+
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/metrics/metric_sub_registry_ut.cpp b/library/cpp/monlib/metrics/metric_sub_registry_ut.cpp
new file mode 100644
index 0000000000..0c5d48b876
--- /dev/null
+++ b/library/cpp/monlib/metrics/metric_sub_registry_ut.cpp
@@ -0,0 +1,65 @@
+#include "metric_sub_registry.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NMonitoring;
+
+Y_UNIT_TEST_SUITE(TMetricSubRegistryTest) {
+ Y_UNIT_TEST(WrapRegistry) {
+ TMetricRegistry registry;
+
+ {
+ TMetricSubRegistry subRegistry{{{"common", "label"}}, &registry};
+ IIntGauge* g = subRegistry.IntGauge(MakeLabels({{"my", "gauge"}}));
+ UNIT_ASSERT(g);
+ g->Set(42);
+ }
+
+ TIntGauge* g = registry.IntGauge({{"my", "gauge"}, {"common", "label"}});
+ UNIT_ASSERT(g);
+ UNIT_ASSERT_VALUES_EQUAL(g->Get(), 42);
+ }
+
+ Y_UNIT_TEST(CommonLabelsDoNotOverrideGeneralLabel) {
+ TMetricRegistry registry;
+
+ {
+ TMetricSubRegistry subRegistry{{{"common", "label"}, {"my", "notOverride"}}, &registry};
+ IIntGauge* g = subRegistry.IntGauge(MakeLabels({{"my", "gauge"}}));
+ UNIT_ASSERT(g);
+ g->Set(1234);
+ }
+
+ TIntGauge* knownGauge = registry.IntGauge({{"my", "gauge"}, {"common", "label"}});
+ UNIT_ASSERT(knownGauge);
+ UNIT_ASSERT_VALUES_EQUAL(knownGauge->Get(), 1234);
+
+ TIntGauge* newGauge = registry.IntGauge({{"common", "label"}, {"my", "notOverride"}});
+ UNIT_ASSERT(newGauge);
+ UNIT_ASSERT_VALUES_EQUAL(newGauge->Get(), 0);
+ }
+
+ Y_UNIT_TEST(RemoveMetric) {
+ TMetricRegistry registry;
+
+ {
+ TMetricSubRegistry subRegistry{{{"common", "label"}}, &registry};
+ IIntGauge* g = subRegistry.IntGauge(MakeLabels({{"my", "gauge"}}));
+ UNIT_ASSERT(g);
+ g->Set(1234);
+ }
+
+ IIntGauge* g1 = registry.IntGauge({{"my", "gauge"}, {"common", "label"}});
+ UNIT_ASSERT(g1);
+ UNIT_ASSERT_VALUES_EQUAL(g1->Get(), 1234);
+
+ {
+ TMetricSubRegistry subRegistry{{{"common", "label"}}, &registry};
+ subRegistry.RemoveMetric(TLabels{{"my", "gauge"}});
+ }
+
+ IIntGauge* g2 = registry.IntGauge({{"my", "gauge"}, {"common", "label"}});
+ UNIT_ASSERT(g2);
+ UNIT_ASSERT_VALUES_EQUAL(g2->Get(), 0);
+ }
+}
diff --git a/library/cpp/monlib/metrics/metric_type.cpp b/library/cpp/monlib/metrics/metric_type.cpp
new file mode 100644
index 0000000000..a8a546e843
--- /dev/null
+++ b/library/cpp/monlib/metrics/metric_type.cpp
@@ -0,0 +1,57 @@
+#include "metric_type.h"
+
+#include <util/generic/strbuf.h>
+#include <util/generic/yexception.h>
+#include <util/stream/output.h>
+
+namespace NMonitoring {
+ TStringBuf MetricTypeToStr(EMetricType type) {
+ switch (type) {
+ case EMetricType::GAUGE:
+ return TStringBuf("GAUGE");
+ case EMetricType::COUNTER:
+ return TStringBuf("COUNTER");
+ case EMetricType::RATE:
+ return TStringBuf("RATE");
+ case EMetricType::IGAUGE:
+ return TStringBuf("IGAUGE");
+ case EMetricType::HIST:
+ return TStringBuf("HIST");
+ case EMetricType::HIST_RATE:
+ return TStringBuf("HIST_RATE");
+ case EMetricType::DSUMMARY:
+ return TStringBuf("DSUMMARY");
+ case EMetricType::LOGHIST:
+ return TStringBuf("LOGHIST");
+ default:
+ return TStringBuf("UNKNOWN");
+ }
+ }
+
+ EMetricType MetricTypeFromStr(TStringBuf str) {
+ if (str == TStringBuf("GAUGE") || str == TStringBuf("DGAUGE")) {
+ return EMetricType::GAUGE;
+ } else if (str == TStringBuf("COUNTER")) {
+ return EMetricType::COUNTER;
+ } else if (str == TStringBuf("RATE")) {
+ return EMetricType::RATE;
+ } else if (str == TStringBuf("IGAUGE")) {
+ return EMetricType::IGAUGE;
+ } else if (str == TStringBuf("HIST")) {
+ return EMetricType::HIST;
+ } else if (str == TStringBuf("HIST_RATE")) {
+ return EMetricType::HIST_RATE;
+ } else if (str == TStringBuf("DSUMMARY")) {
+ return EMetricType::DSUMMARY;
+ } else if (str == TStringBuf("LOGHIST")) {
+ return EMetricType::LOGHIST;
+ } else {
+ ythrow yexception() << "unknown metric type: " << str;
+ }
+ }
+}
+
+template <>
+void Out<NMonitoring::EMetricType>(IOutputStream& o, NMonitoring::EMetricType t) {
+ o << NMonitoring::MetricTypeToStr(t);
+}
diff --git a/library/cpp/monlib/metrics/metric_type.h b/library/cpp/monlib/metrics/metric_type.h
new file mode 100644
index 0000000000..1984c42c1e
--- /dev/null
+++ b/library/cpp/monlib/metrics/metric_type.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <util/generic/fwd.h>
+
+namespace NMonitoring {
+
+ constexpr ui32 MaxMetricTypeNameLength = 9;
+
+ enum class EMetricType {
+ UNKNOWN = 0,
+ GAUGE = 1,
+ COUNTER = 2,
+ RATE = 3,
+ IGAUGE = 4,
+ HIST = 5,
+ HIST_RATE = 6,
+ DSUMMARY = 7,
+ // ISUMMARY = 8, reserved
+ LOGHIST = 9,
+ };
+
+ TStringBuf MetricTypeToStr(EMetricType type);
+ EMetricType MetricTypeFromStr(TStringBuf str);
+
+}
diff --git a/library/cpp/monlib/metrics/metric_value.cpp b/library/cpp/monlib/metrics/metric_value.cpp
new file mode 100644
index 0000000000..b95d7011c6
--- /dev/null
+++ b/library/cpp/monlib/metrics/metric_value.cpp
@@ -0,0 +1,27 @@
+#include "metric_value.h"
+
+
+namespace NMonitoring {
+ void TMetricTimeSeries::SortByTs() {
+ SortPointsByTs(ValueType_, Points_);
+ }
+
+ void TMetricTimeSeries::Clear() noexcept {
+ if (ValueType_ == EMetricValueType::HISTOGRAM) {
+ for (TPoint& p: Points_) {
+ SnapshotUnRef<EMetricValueType::HISTOGRAM>(p);
+ }
+ } else if (ValueType_ == EMetricValueType::SUMMARY) {
+ for (TPoint& p: Points_) {
+ SnapshotUnRef<EMetricValueType::SUMMARY>(p);
+ }
+ } else if (ValueType_ == EMetricValueType::LOGHISTOGRAM) {
+ for (TPoint& p: Points_) {
+ SnapshotUnRef<EMetricValueType::LOGHISTOGRAM>(p);
+ }
+ }
+
+ Points_.clear();
+ ValueType_ = EMetricValueType::UNKNOWN;
+ }
+}
diff --git a/library/cpp/monlib/metrics/metric_value.h b/library/cpp/monlib/metrics/metric_value.h
new file mode 100644
index 0000000000..607fcc8602
--- /dev/null
+++ b/library/cpp/monlib/metrics/metric_value.h
@@ -0,0 +1,542 @@
+#pragma once
+
+#include "histogram_collector.h"
+#include "metric_value_type.h"
+#include "summary_collector.h"
+#include "log_histogram_snapshot.h"
+
+#include <util/datetime/base.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/vector.h>
+#include <util/generic/cast.h>
+#include <util/generic/ymath.h>
+
+namespace NMonitoring {
+ namespace NPrivate {
+ template <typename T>
+ T FromFloatSafe(double d) {
+ static_assert(std::is_integral<T>::value, "this function only converts floats to integers");
+ Y_ENSURE(::IsValidFloat(d) && d >= Min<T>() && d <= MaxFloor<T>(), "Cannot convert " << d << " to an integer value");
+ return static_cast<T>(d);
+ }
+
+ inline auto POINT_KEY_FN = [](auto& p) {
+ return p.GetTime();
+ };
+ } // namespace NPrivate
+
+ template <typename T, typename Enable = void>
+ struct TValueType;
+
+ template <>
+ struct TValueType<double> {
+ static constexpr auto Type = EMetricValueType::DOUBLE;
+ };
+
+ template <>
+ struct TValueType<i64> {
+ static constexpr auto Type = EMetricValueType::INT64;
+ };
+
+ template <>
+ struct TValueType<ui64> {
+ static constexpr auto Type = EMetricValueType::UINT64;
+ };
+
+ template <>
+ struct TValueType<TLogHistogramSnapshot*> {
+ static constexpr auto Type = EMetricValueType::LOGHISTOGRAM;
+ };
+
+ template <typename T>
+ struct TValueType<T*, typename std::enable_if_t<std::is_base_of<IHistogramSnapshot, T>::value>> {
+ static constexpr auto Type = EMetricValueType::HISTOGRAM;
+ };
+
+ template <typename T>
+ struct TValueType<T*, typename std::enable_if_t<std::is_base_of<ISummaryDoubleSnapshot, T>::value>> {
+ static constexpr auto Type = EMetricValueType::SUMMARY;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ // TMetricValue
+ ///////////////////////////////////////////////////////////////////////////
+ // TMetricValue represents a generic value. It does not contain type
+ // information about a value. This is done to minimize object footprint.
+ // To read an actual value from the object the type must be checked
+ // first or provided to AsXxxx(type) member-functions.
+ // This class does not hold an ownership of an IHistogramSnapshot or
+ // SummarySnapshot, so this must be done somewhere outside.
+ class TMetricValue {
+ public:
+ TMetricValue() noexcept {
+ Value_.Uint64 = 0;
+ }
+
+ explicit TMetricValue(double value) noexcept {
+ Value_.Double = value;
+ }
+
+ explicit TMetricValue(i64 value) noexcept {
+ Value_.Int64 = value;
+ }
+
+ explicit TMetricValue(ui64 value) noexcept {
+ Value_.Uint64 = value;
+ }
+
+ explicit TMetricValue(IHistogramSnapshot* histogram) noexcept {
+ Value_.Histogram = histogram;
+ }
+
+ explicit TMetricValue(ISummaryDoubleSnapshot* summary) noexcept {
+ Value_.Summary = summary;
+ }
+
+ explicit TMetricValue(TLogHistogramSnapshot* logHist) noexcept {
+ Value_.LogHistogram = logHist;
+ }
+
+ double AsDouble() const noexcept {
+ return Value_.Double;
+ }
+
+ // will cast value into double, current value type is determined by
+ // the given type argument
+ double AsDouble(EMetricValueType type) const {
+ switch (type) {
+ case EMetricValueType::DOUBLE:
+ return Value_.Double;
+ case EMetricValueType::INT64:
+ return static_cast<double>(Value_.Int64);
+ case EMetricValueType::UINT64:
+ return static_cast<double>(Value_.Uint64);
+ case EMetricValueType::HISTOGRAM:
+ ythrow yexception() << "histogram cannot be casted to Double";
+ case EMetricValueType::SUMMARY:
+ ythrow yexception() << "summary cannot be casted to Double";
+ case EMetricValueType::LOGHISTOGRAM:
+ ythrow yexception() << "loghistogram cannot be casted to Double";
+ case EMetricValueType::UNKNOWN:
+ ythrow yexception() << "unknown value type";
+ }
+ Y_FAIL(); // for GCC
+ }
+
+ ui64 AsUint64() const noexcept {
+ return Value_.Uint64;
+ }
+
+ // will cast value into uint64, current value's type is determined by
+ // the given type argument
+ ui64 AsUint64(EMetricValueType type) const {
+ switch (type) {
+ case EMetricValueType::DOUBLE:
+ return NPrivate::FromFloatSafe<ui64>(Value_.Double);
+ case EMetricValueType::INT64:
+ return SafeIntegerCast<ui64>(Value_.Int64);
+ case EMetricValueType::UINT64:
+ return Value_.Uint64;
+ case EMetricValueType::HISTOGRAM:
+ ythrow yexception() << "histogram cannot be casted to Uint64";
+ case EMetricValueType::SUMMARY:
+ ythrow yexception() << "summary cannot be casted to Uint64";
+ case EMetricValueType::LOGHISTOGRAM:
+ ythrow yexception() << "loghistogram cannot be casted to Uint64";
+ case EMetricValueType::UNKNOWN:
+ ythrow yexception() << "unknown value type";
+ }
+ Y_FAIL(); // for GCC
+ }
+
+ i64 AsInt64() const noexcept {
+ return Value_.Int64;
+ }
+
+ // will cast value into int64, current value's type is determined by
+ // the given type argument
+ i64 AsInt64(EMetricValueType type) const {
+ switch (type) {
+ case EMetricValueType::DOUBLE:
+ return NPrivate::FromFloatSafe<i64>(Value_.Double);
+ case EMetricValueType::INT64:
+ return Value_.Int64;
+ case EMetricValueType::UINT64:
+ return SafeIntegerCast<i64>(Value_.Uint64);
+ case EMetricValueType::HISTOGRAM:
+ ythrow yexception() << "histogram cannot be casted to Int64";
+ case EMetricValueType::SUMMARY:
+ ythrow yexception() << "summary cannot be casted to Int64";
+ case EMetricValueType::LOGHISTOGRAM:
+ ythrow yexception() << "loghistogram cannot be casted to Int64";
+ case EMetricValueType::UNKNOWN:
+ ythrow yexception() << "unknown value type";
+ }
+ Y_FAIL(); // for GCC
+ }
+
+ IHistogramSnapshot* AsHistogram() const noexcept {
+ return Value_.Histogram;
+ }
+
+ IHistogramSnapshot* AsHistogram(EMetricValueType type) const {
+ if (type != EMetricValueType::HISTOGRAM) {
+ ythrow yexception() << type << " cannot be casted to Histogram";
+ }
+
+ return Value_.Histogram;
+ }
+
+ ISummaryDoubleSnapshot* AsSummaryDouble() const noexcept {
+ return Value_.Summary;
+ }
+
+ ISummaryDoubleSnapshot* AsSummaryDouble(EMetricValueType type) const {
+ if (type != EMetricValueType::SUMMARY) {
+ ythrow yexception() << type << " cannot be casted to SummaryDouble";
+ }
+
+ return Value_.Summary;
+ }
+
+ TLogHistogramSnapshot* AsLogHistogram() const noexcept {
+ return Value_.LogHistogram;
+ }
+
+ TLogHistogramSnapshot* AsLogHistogram(EMetricValueType type) const {
+ if (type != EMetricValueType::LOGHISTOGRAM) {
+ ythrow yexception() << type << " cannot be casted to LogHistogram";
+ }
+
+ return Value_.LogHistogram;
+ }
+
+ protected:
+ union {
+ double Double;
+ i64 Int64;
+ ui64 Uint64;
+ IHistogramSnapshot* Histogram;
+ ISummaryDoubleSnapshot* Summary;
+ TLogHistogramSnapshot* LogHistogram;
+ } Value_;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ // TMetricValueWithType
+ ///////////////////////////////////////////////////////////////////////////
+ // Same as TMetricValue, but this type holds an ownership of
+ // snapshots and contains value type information.
+ class TMetricValueWithType: private TMetricValue, public TMoveOnly {
+ public:
+ using TBase = TMetricValue;
+
+ template <typename T>
+ explicit TMetricValueWithType(T value)
+ : TBase(value)
+ , ValueType_{TValueType<T>::Type}
+ {
+ Ref();
+ }
+
+ TMetricValueWithType(TMetricValueWithType&& other)
+ : TBase(std::move(other))
+ , ValueType_{other.ValueType_}
+ {
+ Ref();
+ other.Clear();
+ }
+
+ TMetricValueWithType& operator=(TMetricValueWithType&& other) {
+ TBase::operator=(other);
+ ValueType_ = other.ValueType_;
+
+ Ref();
+ other.Clear();
+
+ return *this;
+ }
+
+ ~TMetricValueWithType() {
+ UnRef();
+ }
+
+ void Clear() {
+ UnRef();
+ ValueType_ = EMetricValueType::UNKNOWN;
+ }
+
+ EMetricValueType GetType() const noexcept {
+ return ValueType_;
+ }
+
+ double AsDouble() const {
+ return TBase::AsDouble(ValueType_);
+ }
+
+ ui64 AsUint64() const {
+ return TBase::AsUint64(ValueType_);
+ }
+
+ i64 AsInt64() const {
+ return TBase::AsInt64(ValueType_);
+ }
+
+ IHistogramSnapshot* AsHistogram() const {
+ return TBase::AsHistogram(ValueType_);
+ }
+
+ ISummaryDoubleSnapshot* AsSummaryDouble() const {
+ return TBase::AsSummaryDouble(ValueType_);
+ }
+
+ TLogHistogramSnapshot* AsLogHistogram() const {
+ return TBase::AsLogHistogram(ValueType_);
+ }
+
+ private:
+ void Ref() {
+ if (ValueType_ == EMetricValueType::SUMMARY) {
+ TBase::AsSummaryDouble()->Ref();
+ } else if (ValueType_ == EMetricValueType::HISTOGRAM) {
+ TBase::AsHistogram()->Ref();
+ } else if (ValueType_ == EMetricValueType::LOGHISTOGRAM) {
+ TBase::AsLogHistogram()->Ref();
+ }
+ }
+
+ void UnRef() {
+ if (ValueType_ == EMetricValueType::SUMMARY) {
+ TBase::AsSummaryDouble()->UnRef();
+ } else if (ValueType_ == EMetricValueType::HISTOGRAM) {
+ TBase::AsHistogram()->UnRef();
+ } else if (ValueType_ == EMetricValueType::LOGHISTOGRAM) {
+ TBase::AsLogHistogram()->UnRef();
+ }
+ }
+
+ private:
+ EMetricValueType ValueType_ = EMetricValueType::UNKNOWN;
+ };
+
+ static_assert(sizeof(TMetricValue) == sizeof(ui64),
+ "expected size of TMetricValue is one machine word");
+
+ ///////////////////////////////////////////////////////////////////////////
+ // TMetricTimeSeries
+ ///////////////////////////////////////////////////////////////////////////
+ class TMetricTimeSeries: private TMoveOnly {
+ public:
+ class TPoint {
+ public:
+ TPoint()
+ : Time_(TInstant::Zero())
+ {
+ }
+
+ template <typename T>
+ TPoint(TInstant time, T value)
+ : Time_(time)
+ , Value_(value)
+ {
+ }
+
+ TInstant GetTime() const noexcept {
+ return Time_;
+ }
+
+ TMetricValue GetValue() const noexcept {
+ return Value_;
+ }
+
+ void ClearValue() {
+ Value_ = {};
+ }
+
+ private:
+ TInstant Time_;
+ TMetricValue Value_;
+ };
+
+ public:
+ TMetricTimeSeries() = default;
+
+ TMetricTimeSeries(TMetricTimeSeries&& rhs) noexcept
+ : ValueType_(rhs.ValueType_)
+ , Points_(std::move(rhs.Points_))
+ {
+ rhs.ValueType_ = EMetricValueType::UNKNOWN;
+ }
+
+ TMetricTimeSeries& operator=(TMetricTimeSeries&& rhs) noexcept {
+ Clear();
+
+ ValueType_ = rhs.ValueType_;
+ rhs.ValueType_ = EMetricValueType::UNKNOWN;
+
+ Points_ = std::move(rhs.Points_);
+ return *this;
+ }
+
+ ~TMetricTimeSeries() {
+ Clear();
+ }
+
+ template <typename T>
+ void Add(TInstant time, T value) {
+ Add(TPoint(time, value), TValueType<T>::Type);
+ }
+
+ void Add(TPoint point, EMetricValueType valueType) {
+ if (Empty()) {
+ ValueType_ = valueType;
+ } else {
+ CheckTypes(ValueType_, valueType);
+ }
+ Points_.push_back(point);
+
+ if (ValueType_ == EMetricValueType::SUMMARY) {
+ TPoint& p = Points_.back();
+ p.GetValue().AsSummaryDouble()->Ref();
+ } else if (ValueType_ == EMetricValueType::HISTOGRAM) {
+ TPoint& p = Points_.back();
+ p.GetValue().AsHistogram()->Ref();
+ } else if (ValueType_ == EMetricValueType::LOGHISTOGRAM) {
+ TPoint& p = Points_.back();
+ p.GetValue().AsLogHistogram()->Ref();
+ }
+ }
+
+ void CopyFrom(const TMetricTimeSeries& other) {
+ if (Empty()) {
+ ValueType_ = other.ValueType_;
+ } else {
+ CheckTypes(GetValueType(), other.GetValueType());
+ }
+
+ size_t prevSize = Points_.size();
+ Copy(std::begin(other.Points_), std::end(other.Points_),
+ std::back_inserter(Points_));
+
+ if (ValueType_ == EMetricValueType::HISTOGRAM) {
+ for (size_t i = prevSize; i < Points_.size(); i++) {
+ TPoint& point = Points_[i];
+ point.GetValue().AsHistogram()->Ref();
+ }
+ } else if (ValueType_ == EMetricValueType::SUMMARY) {
+ for (size_t i = prevSize; i < Points_.size(); ++i) {
+ TPoint& point = Points_[i];
+ point.GetValue().AsSummaryDouble()->Ref();
+ }
+ } else if (ValueType_ == EMetricValueType::LOGHISTOGRAM) {
+ for (size_t i = prevSize; i < Points_.size(); ++i) {
+ TPoint& point = Points_[i];
+ point.GetValue().AsLogHistogram()->Ref();
+ }
+ }
+ }
+
+ template <typename TConsumer>
+ void ForEach(TConsumer c) const {
+ for (const auto& point : Points_) {
+ c(point.GetTime(), ValueType_, point.GetValue());
+ }
+ }
+
+ bool Empty() const noexcept {
+ return Points_.empty();
+ }
+
+ size_t Size() const noexcept {
+ return Points_.size();
+ }
+
+ size_t Capacity() const noexcept {
+ return Points_.capacity();
+ }
+
+ const TPoint& operator[](size_t index) const noexcept {
+ return Points_[index];
+ }
+
+ void SortByTs();
+
+ void Clear() noexcept;
+
+ EMetricValueType GetValueType() const noexcept {
+ return ValueType_;
+ }
+
+ private:
+ static void CheckTypes(EMetricValueType t1, EMetricValueType t2) {
+ Y_ENSURE(t1 == t2,
+ "Series type mismatch: expected " << t1 <<
+ ", but got " << t2);
+ }
+
+ private:
+ EMetricValueType ValueType_ = EMetricValueType::UNKNOWN;
+ TVector<TPoint> Points_;
+ };
+
+ template <EMetricValueType valueType, typename TPoint>
+ static inline void SnapshotUnRef(TPoint& point) {
+ if constexpr (valueType == EMetricValueType::HISTOGRAM) {
+ if (auto* hist = point.GetValue().AsHistogram()) {
+ hist->UnRef();
+ }
+ } else if constexpr (valueType == EMetricValueType::SUMMARY) {
+ if (auto* summary = point.GetValue().AsSummaryDouble()) {
+ summary->UnRef();
+ }
+ } else if constexpr (valueType == EMetricValueType::LOGHISTOGRAM) {
+ if (auto* logHist = point.GetValue().AsLogHistogram()) {
+ logHist->UnRef();
+ }
+ }
+ }
+
+ template <EMetricValueType valueType, typename TPoint>
+ static void EraseDuplicates(TVector<TPoint>& points) {
+ // we have to manually clean reference to a snapshot from point
+ // while removing duplicates
+ auto result = points.rbegin();
+ for (auto it = result + 1; it != points.rend(); ++it) {
+ if (result->GetTime() != it->GetTime() && ++result != it) {
+ SnapshotUnRef<valueType>(*result);
+ *result = *it; // (2) copy
+ it->ClearValue(); // (3) clean pointer in the source
+ }
+ }
+
+ // erase tail points
+ for (auto it = result + 1; it != points.rend(); ++it) {
+ SnapshotUnRef<valueType>(*it);
+ }
+ points.erase(points.begin(), (result + 1).base());
+ }
+
+ template <typename TPoint>
+ void SortPointsByTs(EMetricValueType valueType, TVector<TPoint>& points) {
+ if (points.size() < 2) {
+ return;
+ }
+
+ if (valueType != EMetricValueType::HISTOGRAM && valueType != EMetricValueType::SUMMARY
+ && valueType != EMetricValueType::LOGHISTOGRAM) {
+ // Stable sort + saving only the last point inside a group of duplicates
+ StableSortBy(points, NPrivate::POINT_KEY_FN);
+ auto it = UniqueBy(points.rbegin(), points.rend(), NPrivate::POINT_KEY_FN);
+ points.erase(points.begin(), it.base());
+ } else {
+ StableSortBy(points, NPrivate::POINT_KEY_FN);
+ if (valueType == EMetricValueType::HISTOGRAM) {
+ EraseDuplicates<EMetricValueType::HISTOGRAM>(points);
+ } else if (valueType == EMetricValueType::LOGHISTOGRAM) {
+ EraseDuplicates<EMetricValueType::LOGHISTOGRAM>(points);
+ } else {
+ EraseDuplicates<EMetricValueType::SUMMARY>(points);
+ }
+ }
+ }
+}
diff --git a/library/cpp/monlib/metrics/metric_value_type.h b/library/cpp/monlib/metrics/metric_value_type.h
new file mode 100644
index 0000000000..ab30a958c2
--- /dev/null
+++ b/library/cpp/monlib/metrics/metric_value_type.h
@@ -0,0 +1,16 @@
+#pragma once
+
+
+namespace NMonitoring {
+
+enum class EMetricValueType {
+ UNKNOWN,
+ DOUBLE,
+ INT64,
+ UINT64,
+ HISTOGRAM,
+ SUMMARY,
+ LOGHISTOGRAM,
+};
+
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/metrics/metric_value_ut.cpp b/library/cpp/monlib/metrics/metric_value_ut.cpp
new file mode 100644
index 0000000000..49b47c4057
--- /dev/null
+++ b/library/cpp/monlib/metrics/metric_value_ut.cpp
@@ -0,0 +1,507 @@
+#include "metric_value.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NMonitoring;
+
+Y_UNIT_TEST_SUITE(TMetricValueTest) {
+
+ class TTestHistogram: public IHistogramSnapshot {
+ public:
+ TTestHistogram(ui32 count = 1)
+ : Count_{count}
+ {}
+
+ private:
+ ui32 Count() const override {
+ return Count_;
+ }
+
+ TBucketBound UpperBound(ui32 /*index*/) const override {
+ return 1234.56;
+ }
+
+ TBucketValue Value(ui32 /*index*/) const override {
+ return 42;
+ }
+
+ ui32 Count_{0};
+ };
+
+ IHistogramSnapshotPtr MakeHistogramSnapshot() {
+ return MakeIntrusive<TTestHistogram>();
+ }
+
+ ISummaryDoubleSnapshotPtr MakeSummarySnapshot(ui64 count = 0u) {
+ return MakeIntrusive<TSummaryDoubleSnapshot>(0.0, 0.0, 0.0, 0.0, count);
+ }
+
+ TLogHistogramSnapshotPtr MakeLogHistogram(ui64 count = 0) {
+ TVector<double> buckets;
+ for (ui64 i = 0; i < count; ++i) {
+ buckets.push_back(i);
+ }
+ return MakeIntrusive<TLogHistogramSnapshot>(1.5, 0u, 0, buckets);
+ }
+
+ Y_UNIT_TEST(Sorted) {
+ auto ts1 = TInstant::Now();
+ auto ts2 = ts1 + TDuration::Seconds(1);
+
+ TMetricTimeSeries timeSeries;
+ timeSeries.Add(ts1, 3.14159);
+ timeSeries.Add(ts1, 6.28318);
+ timeSeries.Add(ts2, 2.71828);
+
+ UNIT_ASSERT_EQUAL(timeSeries.Size(), 3);
+
+ timeSeries.SortByTs();
+ UNIT_ASSERT_EQUAL(timeSeries.Size(), 2);
+
+ UNIT_ASSERT_EQUAL(ts1, timeSeries[0].GetTime());
+ UNIT_ASSERT_DOUBLES_EQUAL(6.28318, timeSeries[0].GetValue().AsDouble(), Min<double>());
+
+ UNIT_ASSERT_EQUAL(ts2, timeSeries[1].GetTime());
+ UNIT_ASSERT_DOUBLES_EQUAL(2.71828, timeSeries[1].GetValue().AsDouble(), Min<double>());
+ }
+
+ Y_UNIT_TEST(Histograms) {
+ auto ts = TInstant::Now();
+ auto histogram = MakeIntrusive<TTestHistogram>();
+
+ UNIT_ASSERT_VALUES_EQUAL(1, histogram->RefCount());
+ {
+ TMetricTimeSeries timeSeries;
+ timeSeries.Add(ts, histogram.Get());
+ UNIT_ASSERT_VALUES_EQUAL(2, histogram->RefCount());
+ }
+ UNIT_ASSERT_VALUES_EQUAL(1, histogram->RefCount());
+ }
+
+ Y_UNIT_TEST(Summary) {
+ auto ts = TInstant::Now();
+ auto summary = MakeSummarySnapshot();
+ UNIT_ASSERT_VALUES_EQUAL(1, summary->RefCount());
+ {
+ TMetricTimeSeries timeSeries;
+ timeSeries.Add(ts, summary.Get());
+ UNIT_ASSERT_VALUES_EQUAL(2, summary->RefCount());
+ }
+ UNIT_ASSERT_VALUES_EQUAL(1, summary->RefCount());
+ }
+
+ Y_UNIT_TEST(LogHistogram) {
+ auto ts = TInstant::Now();
+ auto logHist = MakeLogHistogram();
+ UNIT_ASSERT_VALUES_EQUAL(1, logHist->RefCount());
+ {
+ TMetricTimeSeries timeSeries;
+ timeSeries.Add(ts, logHist.Get());
+ UNIT_ASSERT_VALUES_EQUAL(2, logHist->RefCount());
+ }
+ UNIT_ASSERT_VALUES_EQUAL(1, logHist->RefCount());
+ }
+
+ Y_UNIT_TEST(TimeSeriesMovable) {
+ auto ts = TInstant::Now();
+ auto histogram = MakeIntrusive<TTestHistogram>();
+
+ UNIT_ASSERT_VALUES_EQUAL(1, histogram->RefCount());
+ {
+ TMetricTimeSeries timeSeriesA;
+ timeSeriesA.Add(ts, histogram.Get());
+ UNIT_ASSERT_VALUES_EQUAL(2, histogram->RefCount());
+
+ TMetricTimeSeries timeSeriesB = std::move(timeSeriesA);
+ UNIT_ASSERT_VALUES_EQUAL(2, histogram->RefCount());
+
+ UNIT_ASSERT_VALUES_EQUAL(1, timeSeriesB.Size());
+ UNIT_ASSERT_EQUAL(EMetricValueType::HISTOGRAM, timeSeriesB.GetValueType());
+
+ UNIT_ASSERT_VALUES_EQUAL(0, timeSeriesA.Size());
+ UNIT_ASSERT_EQUAL(EMetricValueType::UNKNOWN, timeSeriesA.GetValueType());
+ }
+ UNIT_ASSERT_VALUES_EQUAL(1, histogram->RefCount());
+ }
+
+ Y_UNIT_TEST(HistogramsUnique) {
+ auto ts1 = TInstant::Now();
+ auto ts2 = ts1 + TDuration::Seconds(1);
+ auto ts3 = ts2 + TDuration::Seconds(1);
+
+ auto h1 = MakeIntrusive<TTestHistogram>();
+ auto h2 = MakeIntrusive<TTestHistogram>();
+ auto h3 = MakeIntrusive<TTestHistogram>();
+
+ UNIT_ASSERT_VALUES_EQUAL(1, h1->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(1, h2->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(1, h3->RefCount());
+
+ {
+ TMetricTimeSeries timeSeries;
+ timeSeries.Add(ts1, h1.Get()); // drop at the head
+ timeSeries.Add(ts1, h1.Get());
+ timeSeries.Add(ts1, h1.Get());
+
+ timeSeries.Add(ts2, h2.Get()); // drop in the middle
+ timeSeries.Add(ts2, h2.Get());
+ timeSeries.Add(ts2, h2.Get());
+
+ timeSeries.Add(ts3, h3.Get()); // drop at the end
+ timeSeries.Add(ts3, h3.Get());
+ timeSeries.Add(ts3, h3.Get());
+
+ UNIT_ASSERT_EQUAL(timeSeries.Size(), 9);
+
+ UNIT_ASSERT_VALUES_EQUAL(4, h1->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(4, h2->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(4, h3->RefCount());
+
+ timeSeries.SortByTs();
+ UNIT_ASSERT_EQUAL(timeSeries.Size(), 3);
+
+ UNIT_ASSERT_VALUES_EQUAL(2, h1->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(2, h2->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(2, h3->RefCount());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(1, h1->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(1, h2->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(1, h3->RefCount());
+ }
+
+ Y_UNIT_TEST(LogHistogramsUnique) {
+ auto ts1 = TInstant::Now();
+ auto ts2 = ts1 + TDuration::Seconds(1);
+ auto ts3 = ts2 + TDuration::Seconds(1);
+
+ auto h1 = MakeLogHistogram();
+ auto h2 = MakeLogHistogram();
+ auto h3 = MakeLogHistogram();
+
+ UNIT_ASSERT_VALUES_EQUAL(1, h1->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(1, h2->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(1, h3->RefCount());
+
+ {
+ TMetricTimeSeries timeSeries;
+ timeSeries.Add(ts1, h1.Get()); // drop at the head
+ timeSeries.Add(ts1, h1.Get());
+ timeSeries.Add(ts1, h1.Get());
+
+ timeSeries.Add(ts2, h2.Get()); // drop in the middle
+ timeSeries.Add(ts2, h2.Get());
+ timeSeries.Add(ts2, h2.Get());
+
+ timeSeries.Add(ts3, h3.Get()); // drop at the end
+ timeSeries.Add(ts3, h3.Get());
+ timeSeries.Add(ts3, h3.Get());
+
+ UNIT_ASSERT_EQUAL(timeSeries.Size(), 9);
+
+ UNIT_ASSERT_VALUES_EQUAL(4, h1->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(4, h2->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(4, h3->RefCount());
+
+ timeSeries.SortByTs();
+ UNIT_ASSERT_EQUAL(timeSeries.Size(), 3);
+
+ UNIT_ASSERT_VALUES_EQUAL(2, h1->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(2, h2->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(2, h3->RefCount());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(1, h1->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(1, h2->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(1, h3->RefCount());
+ }
+
+ Y_UNIT_TEST(SummaryUnique) {
+ auto ts1 = TInstant::Now();
+ auto ts2 = ts1 + TDuration::Seconds(1);
+ auto ts3 = ts2 + TDuration::Seconds(1);
+
+ auto h1 = MakeSummarySnapshot();
+ auto h2 = MakeSummarySnapshot();
+ auto h3 = MakeSummarySnapshot();
+
+ UNIT_ASSERT_VALUES_EQUAL(1, h1->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(1, h2->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(1, h3->RefCount());
+
+ {
+ TMetricTimeSeries timeSeries;
+ timeSeries.Add(ts1, h1.Get()); // drop at the head
+ timeSeries.Add(ts1, h1.Get());
+ timeSeries.Add(ts1, h1.Get());
+
+ timeSeries.Add(ts2, h2.Get()); // drop in the middle
+ timeSeries.Add(ts2, h2.Get());
+ timeSeries.Add(ts2, h2.Get());
+
+ timeSeries.Add(ts3, h3.Get()); // drop at the end
+ timeSeries.Add(ts3, h3.Get());
+ timeSeries.Add(ts3, h3.Get());
+
+ UNIT_ASSERT_EQUAL(timeSeries.Size(), 9);
+
+ UNIT_ASSERT_VALUES_EQUAL(4, h1->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(4, h2->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(4, h3->RefCount());
+
+ timeSeries.SortByTs();
+ UNIT_ASSERT_EQUAL(timeSeries.Size(), 3);
+
+ UNIT_ASSERT_VALUES_EQUAL(2, h1->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(2, h2->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(2, h3->RefCount());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(1, h1->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(1, h2->RefCount());
+ UNIT_ASSERT_VALUES_EQUAL(1, h3->RefCount());
+ }
+
+ Y_UNIT_TEST(HistogramsUnique2) {
+ auto ts1 = TInstant::Now();
+ auto ts2 = ts1 + TDuration::Seconds(1);
+ auto ts3 = ts2 + TDuration::Seconds(1);
+ auto ts4 = ts3 + TDuration::Seconds(1);
+ auto ts5 = ts4 + TDuration::Seconds(1);
+
+ auto h1 = MakeIntrusive<TTestHistogram>(1u);
+ auto h2 = MakeIntrusive<TTestHistogram>(2u);
+ auto h3 = MakeIntrusive<TTestHistogram>(3u);
+ auto h4 = MakeIntrusive<TTestHistogram>(4u);
+ auto h5 = MakeIntrusive<TTestHistogram>(5u);
+ auto h6 = MakeIntrusive<TTestHistogram>(6u);
+ auto h7 = MakeIntrusive<TTestHistogram>(7u);
+
+ {
+ TMetricTimeSeries timeSeries;
+ timeSeries.Add(ts1, h1.Get());
+ timeSeries.Add(ts1, h2.Get());
+
+ timeSeries.Add(ts2, h3.Get());
+
+ timeSeries.Add(ts3, h4.Get());
+ timeSeries.Add(ts3, h5.Get());
+
+ timeSeries.Add(ts4, h6.Get());
+ timeSeries.Add(ts5, h7.Get());
+
+ timeSeries.SortByTs();
+
+ UNIT_ASSERT_EQUAL(timeSeries.Size(), 5);
+ UNIT_ASSERT_EQUAL(timeSeries[0].GetValue().AsHistogram()->Count(), 2);
+ UNIT_ASSERT_EQUAL(timeSeries[1].GetValue().AsHistogram()->Count(), 3);
+ UNIT_ASSERT_EQUAL(timeSeries[2].GetValue().AsHistogram()->Count(), 5);
+ UNIT_ASSERT_EQUAL(timeSeries[3].GetValue().AsHistogram()->Count(), 6);
+ UNIT_ASSERT_EQUAL(timeSeries[4].GetValue().AsHistogram()->Count(), 7);
+ }
+ }
+
+ Y_UNIT_TEST(LogHistogramsUnique2) {
+ auto ts1 = TInstant::Now();
+ auto ts2 = ts1 + TDuration::Seconds(1);
+ auto ts3 = ts2 + TDuration::Seconds(1);
+ auto ts4 = ts3 + TDuration::Seconds(1);
+ auto ts5 = ts4 + TDuration::Seconds(1);
+
+ auto h1 = MakeLogHistogram(1u);
+ auto h2 = MakeLogHistogram(2u);
+ auto h3 = MakeLogHistogram(3u);
+ auto h4 = MakeLogHistogram(4u);
+ auto h5 = MakeLogHistogram(5u);
+ auto h6 = MakeLogHistogram(6u);
+ auto h7 = MakeLogHistogram(7u);
+
+ {
+ TMetricTimeSeries timeSeries;
+ timeSeries.Add(ts1, h1.Get());
+ timeSeries.Add(ts1, h2.Get());
+
+ timeSeries.Add(ts2, h3.Get());
+
+ timeSeries.Add(ts3, h4.Get());
+ timeSeries.Add(ts3, h5.Get());
+
+ timeSeries.Add(ts4, h6.Get());
+ timeSeries.Add(ts5, h7.Get());
+
+ timeSeries.SortByTs();
+
+ UNIT_ASSERT_EQUAL(timeSeries.Size(), 5);
+ UNIT_ASSERT_EQUAL(timeSeries[0].GetValue().AsLogHistogram()->Count(), 2);
+ UNIT_ASSERT_EQUAL(timeSeries[1].GetValue().AsLogHistogram()->Count(), 3);
+ UNIT_ASSERT_EQUAL(timeSeries[2].GetValue().AsLogHistogram()->Count(), 5);
+ UNIT_ASSERT_EQUAL(timeSeries[3].GetValue().AsLogHistogram()->Count(), 6);
+ UNIT_ASSERT_EQUAL(timeSeries[4].GetValue().AsLogHistogram()->Count(), 7);
+ }
+ }
+
+ Y_UNIT_TEST(SummaryUnique2) {
+ auto ts1 = TInstant::Now();
+ auto ts2 = ts1 + TDuration::Seconds(1);
+ auto ts3 = ts2 + TDuration::Seconds(1);
+ auto ts4 = ts3 + TDuration::Seconds(1);
+ auto ts5 = ts4 + TDuration::Seconds(1);
+
+ auto h1 = MakeSummarySnapshot(1u);
+ auto h2 = MakeSummarySnapshot(2u);
+ auto h3 = MakeSummarySnapshot(3u);
+ auto h4 = MakeSummarySnapshot(4u);
+ auto h5 = MakeSummarySnapshot(5u);
+ auto h6 = MakeSummarySnapshot(6u);
+ auto h7 = MakeSummarySnapshot(7u);
+
+ {
+ TMetricTimeSeries timeSeries;
+ timeSeries.Add(ts1, h1.Get());
+ timeSeries.Add(ts1, h2.Get());
+
+ timeSeries.Add(ts2, h3.Get());
+
+ timeSeries.Add(ts3, h4.Get());
+ timeSeries.Add(ts3, h5.Get());
+
+ timeSeries.Add(ts4, h6.Get());
+ timeSeries.Add(ts5, h7.Get());
+
+ timeSeries.SortByTs();
+
+ UNIT_ASSERT_EQUAL(timeSeries.Size(), 5);
+ UNIT_ASSERT_EQUAL(timeSeries[0].GetValue().AsSummaryDouble()->GetCount(), 2);
+ UNIT_ASSERT_EQUAL(timeSeries[1].GetValue().AsSummaryDouble()->GetCount(), 3);
+ UNIT_ASSERT_EQUAL(timeSeries[2].GetValue().AsSummaryDouble()->GetCount(), 5);
+ UNIT_ASSERT_EQUAL(timeSeries[3].GetValue().AsSummaryDouble()->GetCount(), 6);
+ UNIT_ASSERT_EQUAL(timeSeries[4].GetValue().AsSummaryDouble()->GetCount(), 7);
+ }
+ }
+
+ Y_UNIT_TEST(TMetricValueWithType) {
+ // correct usage
+ {
+ double value = 1.23;
+ TMetricValueWithType v{value};
+
+ UNIT_ASSERT_VALUES_EQUAL(v.GetType(), EMetricValueType::DOUBLE);
+ UNIT_ASSERT_VALUES_EQUAL(v.AsDouble(), value);
+ }
+ {
+ ui64 value = 12;
+ TMetricValueWithType v{value};
+
+ UNIT_ASSERT_VALUES_EQUAL(v.GetType(), EMetricValueType::UINT64);
+ UNIT_ASSERT_VALUES_EQUAL(v.AsUint64(), value);
+ }
+ {
+ i64 value = i64(-12);
+ TMetricValueWithType v{value};
+
+ UNIT_ASSERT_VALUES_EQUAL(v.GetType(), EMetricValueType::INT64);
+ UNIT_ASSERT_VALUES_EQUAL(v.AsInt64(), value);
+ }
+ {
+ auto h = MakeHistogramSnapshot();
+ UNIT_ASSERT_VALUES_EQUAL(h.RefCount(), 1);
+
+ {
+ auto value = h.Get();
+ TMetricValueWithType v{value};
+
+ UNIT_ASSERT_VALUES_EQUAL(h.RefCount(), 2);
+
+ UNIT_ASSERT_VALUES_EQUAL(v.GetType(), EMetricValueType::HISTOGRAM);
+ UNIT_ASSERT_VALUES_EQUAL(v.AsHistogram(), value);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(h.RefCount(), 1);
+ }
+ {
+ auto s = MakeSummarySnapshot();
+ auto value = s.Get();
+
+ UNIT_ASSERT_VALUES_EQUAL(s.RefCount(), 1);
+
+ {
+ TMetricValueWithType v{value};
+
+ UNIT_ASSERT_VALUES_EQUAL(s.RefCount(), 2);
+
+ UNIT_ASSERT_VALUES_EQUAL(v.GetType(), EMetricValueType::SUMMARY);
+ UNIT_ASSERT_VALUES_EQUAL(v.AsSummaryDouble(), value);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(s.RefCount(), 1);
+ }
+ {
+ auto s = MakeSummarySnapshot();
+ auto value = s.Get();
+
+ UNIT_ASSERT_VALUES_EQUAL(s.RefCount(), 1);
+
+ {
+ TMetricValueWithType v{value};
+
+ UNIT_ASSERT_VALUES_EQUAL(s.RefCount(), 2);
+
+ v.Clear();
+ UNIT_ASSERT_VALUES_EQUAL(s.RefCount(), 1);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(s.RefCount(), 1);
+ }
+ {
+ auto s = MakeSummarySnapshot();
+ auto value = s.Get();
+
+ {
+ TMetricValueWithType v1{ui64{1}};
+
+ UNIT_ASSERT_VALUES_EQUAL(s.RefCount(), 1);
+
+ {
+ TMetricValueWithType v2{value};
+ UNIT_ASSERT_VALUES_EQUAL(s.RefCount(), 2);
+
+ v1 = std::move(v2);
+ UNIT_ASSERT_VALUES_EQUAL(s.RefCount(), 2);
+ UNIT_ASSERT_VALUES_EQUAL(v1.AsSummaryDouble(), value);
+ UNIT_ASSERT_VALUES_EQUAL(v1.GetType(), EMetricValueType::SUMMARY);
+ UNIT_ASSERT_VALUES_EQUAL(v2.GetType(), EMetricValueType::UNKNOWN);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(s.RefCount(), 2);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(s.RefCount(), 1);
+ }
+
+ // incorrect usage
+ {
+ TMetricValueWithType v{1.23};
+
+ UNIT_ASSERT_EXCEPTION(v.AsHistogram(), yexception);
+ UNIT_ASSERT_EXCEPTION(v.AsSummaryDouble(), yexception);
+ }
+ {
+ auto h = MakeHistogramSnapshot();
+ TMetricValueWithType v{h.Get()};
+
+ UNIT_ASSERT_EXCEPTION(v.AsUint64(), yexception);
+ UNIT_ASSERT_EXCEPTION(v.AsInt64(), yexception);
+ UNIT_ASSERT_EXCEPTION(v.AsDouble(), yexception);
+ UNIT_ASSERT_EXCEPTION(v.AsSummaryDouble(), yexception);
+ }
+ {
+ auto s = MakeSummarySnapshot();
+ TMetricValueWithType v{s.Get()};
+
+ UNIT_ASSERT_EXCEPTION(v.AsUint64(), yexception);
+ UNIT_ASSERT_EXCEPTION(v.AsInt64(), yexception);
+ UNIT_ASSERT_EXCEPTION(v.AsDouble(), yexception);
+ UNIT_ASSERT_EXCEPTION(v.AsHistogram(), yexception);
+ }
+ }
+}
diff --git a/library/cpp/monlib/metrics/summary_collector.cpp b/library/cpp/monlib/metrics/summary_collector.cpp
new file mode 100644
index 0000000000..cae8560891
--- /dev/null
+++ b/library/cpp/monlib/metrics/summary_collector.cpp
@@ -0,0 +1 @@
+#include "summary_collector.h"
diff --git a/library/cpp/monlib/metrics/summary_collector.h b/library/cpp/monlib/metrics/summary_collector.h
new file mode 100644
index 0000000000..acba0fddf9
--- /dev/null
+++ b/library/cpp/monlib/metrics/summary_collector.h
@@ -0,0 +1,104 @@
+#pragma once
+
+#include "summary_snapshot.h"
+
+#include <atomic>
+#include <limits>
+#include <cmath>
+
+namespace NMonitoring {
+
+ class ISummaryDoubleCollector {
+ public:
+ virtual ~ISummaryDoubleCollector() = default;
+
+ virtual void Collect(double value) = 0;
+
+ virtual ISummaryDoubleSnapshotPtr Snapshot() const = 0;
+
+ virtual size_t SizeBytes() const = 0;
+ };
+
+ using ISummaryDoubleCollectorPtr = THolder<ISummaryDoubleCollector>;
+
+ class TSummaryDoubleCollector final: public ISummaryDoubleCollector {
+ public:
+ TSummaryDoubleCollector() {
+ Sum_.store(0, std::memory_order_relaxed);
+ Min_.store(std::numeric_limits<double>::max(), std::memory_order_relaxed);
+ Max_.store(std::numeric_limits<double>::lowest(), std::memory_order_relaxed);
+ Count_.store(0, std::memory_order_relaxed);
+ }
+
+ void Collect(double value) noexcept override {
+ if (std::isnan(value)) {
+ return;
+ }
+ UpdateSum(value);
+ UpdateMin(value);
+ UpdateMax(value);
+ Last_.store(value, std::memory_order_relaxed);
+ Count_.fetch_add(1ul, std::memory_order_relaxed);
+ }
+
+ ISummaryDoubleSnapshotPtr Snapshot() const override {
+ return new TSummaryDoubleSnapshot(
+ Sum_.load(std::memory_order_relaxed),
+ Min_.load(std::memory_order_relaxed),
+ Max_.load(std::memory_order_relaxed),
+ Last_.load(std::memory_order_relaxed),
+ Count_.load(std::memory_order_relaxed));
+ }
+
+ size_t SizeBytes() const override {
+ return sizeof(*this);
+ }
+
+ private:
+ std::atomic<double> Sum_;
+ std::atomic<double> Min_;
+ std::atomic<double> Max_;
+ std::atomic<double> Last_;
+ std::atomic_uint64_t Count_;
+
+ void UpdateSum(double add) noexcept {
+ double newValue;
+ double oldValue = Sum_.load(std::memory_order_relaxed);
+ do {
+ newValue = oldValue + add;
+ } while (!Sum_.compare_exchange_weak(
+ oldValue,
+ newValue,
+ std::memory_order_release,
+ std::memory_order_consume));
+ }
+
+ void UpdateMin(double candidate) noexcept {
+ double oldValue = Min_.load(std::memory_order_relaxed);
+ do {
+ if (oldValue <= candidate) {
+ break;
+ }
+ } while (!Min_.compare_exchange_weak(
+ oldValue,
+ candidate,
+ std::memory_order_release,
+ std::memory_order_consume));
+ }
+
+ void UpdateMax(double candidate) noexcept {
+ double oldValue = Max_.load(std::memory_order_relaxed);
+ do {
+ if (oldValue >= candidate) {
+ break;
+ }
+ } while (!Max_.compare_exchange_weak(
+ oldValue,
+ candidate,
+ std::memory_order_release,
+ std::memory_order_consume));
+ }
+
+ };
+
+}
diff --git a/library/cpp/monlib/metrics/summary_collector_ut.cpp b/library/cpp/monlib/metrics/summary_collector_ut.cpp
new file mode 100644
index 0000000000..191929550f
--- /dev/null
+++ b/library/cpp/monlib/metrics/summary_collector_ut.cpp
@@ -0,0 +1,64 @@
+#include "summary_collector.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/random/random.h>
+
+#include <numeric>
+#include <algorithm>
+
+namespace NMonitoring {
+
+Y_UNIT_TEST_SUITE(SummaryCollectorTest) {
+
+ void CheckSnapshot(ISummaryDoubleSnapshotPtr snapshot, const TVector<double> values) {
+ const double eps = 1e-9;
+
+ double sum = std::accumulate(values.begin(), values.end(), 0.0);
+ double min = *std::min_element(values.begin(), values.end());
+ double max = *std::max_element(values.begin(), values.end());
+ double last = values.back();
+ ui64 count = values.size();
+
+ UNIT_ASSERT_DOUBLES_EQUAL(snapshot->GetSum(), sum, eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(snapshot->GetMin(), min, eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(snapshot->GetMax(), max, eps);
+ UNIT_ASSERT_DOUBLES_EQUAL(snapshot->GetLast(), last, eps);
+ UNIT_ASSERT_EQUAL(snapshot->GetCount(), count);
+ }
+
+ Y_UNIT_TEST(Simple) {
+ {
+ TVector<double> test{05, -1.5, 0.0, 2.5, 0.25, -1.0};
+ TSummaryDoubleCollector summary;
+ for (auto value : test) {
+ summary.Collect(value);
+ }
+ CheckSnapshot(summary.Snapshot(), test);
+ }
+ {
+ TVector<double> test{-1.0, 1.0, 9.0, -5000.0, 5000.0, 5.0, -5.0};
+ TSummaryDoubleCollector summary;
+ for (auto value : test) {
+ summary.Collect(value);
+ }
+ CheckSnapshot(summary.Snapshot(), test);
+ }
+ }
+
+ Y_UNIT_TEST(RandomStressTest) {
+ const ui32 attemts = 100;
+ for (ui32 i = 0; i < attemts; ++i) {
+ const ui32 size = 100;
+ TVector<double> values(size);
+ TSummaryDoubleCollector summary;
+ for (auto& value : values) {
+ value = RandomNumber<double>() - 0.5;
+ summary.Collect(value);
+ }
+ CheckSnapshot(summary.Snapshot(), values);
+ }
+ }
+}
+
+}
diff --git a/library/cpp/monlib/metrics/summary_snapshot.cpp b/library/cpp/monlib/metrics/summary_snapshot.cpp
new file mode 100644
index 0000000000..0b13263337
--- /dev/null
+++ b/library/cpp/monlib/metrics/summary_snapshot.cpp
@@ -0,0 +1,34 @@
+#include "summary_snapshot.h"
+
+#include <util/stream/output.h>
+
+#include <iostream>
+
+
+namespace {
+
+template <typename TStream>
+auto& Output(TStream& o, const NMonitoring::ISummaryDoubleSnapshot& s) {
+ o << TStringBuf("{");
+
+ o << TStringBuf("sum: ") << s.GetSum() << TStringBuf(", ");
+ o << TStringBuf("min: ") << s.GetMin() << TStringBuf(", ");
+ o << TStringBuf("max: ") << s.GetMax() << TStringBuf(", ");
+ o << TStringBuf("last: ") << s.GetLast() << TStringBuf(", ");
+ o << TStringBuf("count: ") << s.GetCount();
+
+ o << TStringBuf("}");
+
+ return o;
+}
+
+} // namespace
+
+std::ostream& operator<<(std::ostream& o, const NMonitoring::ISummaryDoubleSnapshot& s) {
+ return Output(o, s);
+}
+
+template <>
+void Out<NMonitoring::ISummaryDoubleSnapshot>(IOutputStream& o, const NMonitoring::ISummaryDoubleSnapshot& s) {
+ Output(o, s);
+}
diff --git a/library/cpp/monlib/metrics/summary_snapshot.h b/library/cpp/monlib/metrics/summary_snapshot.h
new file mode 100644
index 0000000000..afcc895fd3
--- /dev/null
+++ b/library/cpp/monlib/metrics/summary_snapshot.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+
+namespace NMonitoring {
+
+ class ISummaryDoubleSnapshot: public TAtomicRefCount<ISummaryDoubleSnapshot> {
+ public:
+ virtual ~ISummaryDoubleSnapshot() = default;
+
+ // TODO: write documentation
+
+ virtual ui64 GetCount() const = 0;
+
+ virtual double GetSum() const = 0;
+
+ virtual double GetMin() const = 0;
+
+ virtual double GetMax() const = 0;
+
+ virtual double GetLast() const = 0;
+
+ virtual ui64 MemorySizeBytes() const = 0;
+ };
+
+ using ISummaryDoubleSnapshotPtr = TIntrusivePtr<ISummaryDoubleSnapshot>;
+
+ class TSummaryDoubleSnapshot final: public ISummaryDoubleSnapshot {
+ public:
+ TSummaryDoubleSnapshot(double sum, double min, double max, double last, ui64 count)
+ : Sum_(sum)
+ , Min_(min)
+ , Max_(max)
+ , Last_(last)
+ , Count_(count)
+ {}
+
+ ui64 GetCount() const noexcept override {
+ return Count_;
+ }
+
+ double GetSum() const noexcept override {
+ return Sum_;
+ }
+
+ double GetMin() const noexcept override {
+ return Min_;
+ }
+
+ double GetMax() const noexcept override {
+ return Max_;
+ }
+
+ virtual double GetLast() const noexcept override {
+ return Last_;
+ }
+
+ ui64 MemorySizeBytes() const noexcept override {
+ return sizeof(*this);
+ }
+
+ private:
+ double Sum_;
+ double Min_;
+ double Max_;
+ double Last_;
+ ui64 Count_;
+ };
+
+}
+
+std::ostream& operator<<(std::ostream& os, const NMonitoring::ISummaryDoubleSnapshot& s);
diff --git a/library/cpp/monlib/metrics/timer.h b/library/cpp/monlib/metrics/timer.h
new file mode 100644
index 0000000000..5c4e26e37b
--- /dev/null
+++ b/library/cpp/monlib/metrics/timer.h
@@ -0,0 +1,127 @@
+#pragma once
+
+#include "metric.h"
+
+#include <util/generic/typetraits.h>
+
+#include <chrono>
+
+
+namespace NMonitoring {
+
+ /**
+ * A timing scope to record elapsed time since creation.
+ */
+ template <typename TMetric,
+ typename Resolution = std::chrono::milliseconds,
+ typename Clock = std::chrono::high_resolution_clock>
+ class TMetricTimerScope {
+ public:
+ explicit TMetricTimerScope(TMetric* metric)
+ : Metric_(metric)
+ , StartTime_(Clock::now())
+ {
+ Y_ENSURE(Metric_);
+ }
+
+ TMetricTimerScope(TMetricTimerScope&) = delete;
+ TMetricTimerScope& operator=(const TMetricTimerScope&) = delete;
+
+ TMetricTimerScope(TMetricTimerScope&& other) {
+ *this = std::move(other);
+ }
+
+ TMetricTimerScope& operator=(TMetricTimerScope&& other) {
+ Metric_ = other.Metric_;
+ other.Metric_ = nullptr;
+ StartTime_ = std::move(other.StartTime_);
+
+ return *this;
+ }
+
+ void Record() {
+ Y_VERIFY_DEBUG(Metric_);
+ if (Metric_ == nullptr) {
+ return;
+ }
+
+ auto duration = std::chrono::duration_cast<Resolution>(Clock::now() - StartTime_).count();
+ if constexpr (std::is_same<TMetric, TGauge>::value) {
+ Metric_->Set(duration);
+ } else if constexpr (std::is_same<TMetric, TIntGauge>::value) {
+ Metric_->Set(duration);
+ } else if constexpr (std::is_same<TMetric, TCounter>::value) {
+ Metric_->Add(duration);
+ } else if constexpr (std::is_same<TMetric, TRate>::value) {
+ Metric_->Add(duration);
+ } else if constexpr (std::is_same<TMetric, THistogram>::value) {
+ Metric_->Record(duration);
+ } else {
+ static_assert(TDependentFalse<TMetric>, "Not supported metric type");
+ }
+
+ Metric_ = nullptr;
+ }
+
+ ~TMetricTimerScope() {
+ if (Metric_ == nullptr) {
+ return;
+ }
+
+ Record();
+ }
+
+ private:
+ TMetric* Metric_{nullptr};
+ typename Clock::time_point StartTime_;
+ };
+
+ /**
+ * @brief A class that is supposed to use to measure execution time of an asynchronuous operation.
+ *
+ * In order to be able to capture an object into a lambda which is then passed to TFuture::Subscribe/Apply,
+ * the object must be copy constructible (limitation of the std::function class). So, we cannot use the TMetricTimerScope
+ * with the abovementioned functions without storing it in a shared pointer or somewhere else. This class works around this
+ * issue with wrapping the timer with a auto_ptr-like hack Also, Record is const so that one doesn't need to make every lambda mutable
+ * just to record time measurement.
+ */
+ template <typename TMetric,
+ typename Resolution = std::chrono::milliseconds,
+ typename Clock = std::chrono::high_resolution_clock>
+ class TFutureFriendlyTimer {
+ public:
+ explicit TFutureFriendlyTimer(TMetric* metric)
+ : Impl_{metric}
+ {
+ }
+
+ TFutureFriendlyTimer(const TFutureFriendlyTimer& other)
+ : Impl_{std::move(other.Impl_)}
+ {
+ }
+
+ TFutureFriendlyTimer& operator=(const TFutureFriendlyTimer& other) {
+ Impl_ = std::move(other.Impl_);
+ }
+
+ TFutureFriendlyTimer(TFutureFriendlyTimer&&) = default;
+ TFutureFriendlyTimer& operator=(TFutureFriendlyTimer&& other) = default;
+
+ void Record() const {
+ Impl_.Record();
+ }
+
+ private:
+ mutable TMetricTimerScope<TMetric, Resolution, Clock> Impl_;
+ };
+
+ template <typename TMetric>
+ TMetricTimerScope<TMetric> ScopeTimer(TMetric* metric) {
+ return TMetricTimerScope<TMetric>{metric};
+ }
+
+ template <typename TMetric>
+ TFutureFriendlyTimer<TMetric> FutureTimer(TMetric* metric) {
+ return TFutureFriendlyTimer<TMetric>{metric};
+ }
+}
diff --git a/library/cpp/monlib/metrics/timer_ut.cpp b/library/cpp/monlib/metrics/timer_ut.cpp
new file mode 100644
index 0000000000..c244a8c9e1
--- /dev/null
+++ b/library/cpp/monlib/metrics/timer_ut.cpp
@@ -0,0 +1,157 @@
+#include "timer.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/threading/future/async.h>
+#include <library/cpp/threading/future/future.h>
+
+using namespace NMonitoring;
+using namespace NThreading;
+
+Y_UNIT_TEST_SUITE(TTimerTest) {
+
+ using namespace std::chrono;
+
+ struct TTestClock {
+ using time_point = time_point<high_resolution_clock>;
+
+ static time_point TimePoint;
+
+ static time_point now() {
+ return TimePoint;
+ }
+ };
+
+ TTestClock::time_point TTestClock::TimePoint;
+
+
+ Y_UNIT_TEST(Gauge) {
+ TTestClock::TimePoint = TTestClock::time_point::min();
+
+ TGauge gauge(0);
+ {
+ TMetricTimerScope<TGauge, milliseconds, TTestClock> t{&gauge};
+ TTestClock::TimePoint += milliseconds(10);
+ }
+ UNIT_ASSERT_EQUAL(10, gauge.Get());
+
+ {
+ TMetricTimerScope<TGauge, milliseconds, TTestClock> t{&gauge};
+ TTestClock::TimePoint += milliseconds(20);
+ }
+ UNIT_ASSERT_EQUAL(20, gauge.Get());
+ }
+
+ Y_UNIT_TEST(IntGauge) {
+ TTestClock::TimePoint = TTestClock::time_point::min();
+
+ TIntGauge gauge(0);
+ {
+ TMetricTimerScope<TIntGauge, milliseconds, TTestClock> t{&gauge};
+ TTestClock::TimePoint += milliseconds(10);
+ }
+ UNIT_ASSERT_EQUAL(10, gauge.Get());
+
+ {
+ TMetricTimerScope<TIntGauge, milliseconds, TTestClock> t{&gauge};
+ TTestClock::TimePoint += milliseconds(20);
+ }
+ UNIT_ASSERT_EQUAL(20, gauge.Get());
+ }
+
+ Y_UNIT_TEST(CounterNew) {
+ TTestClock::TimePoint = TTestClock::time_point::min();
+
+ TCounter counter(0);
+ {
+ TMetricTimerScope<TCounter, milliseconds, TTestClock> t{&counter};
+ TTestClock::TimePoint += milliseconds(10);
+ }
+ UNIT_ASSERT_EQUAL(10, counter.Get());
+
+ {
+ TMetricTimerScope<TCounter, milliseconds, TTestClock> t{&counter};
+ TTestClock::TimePoint += milliseconds(20);
+ }
+ UNIT_ASSERT_EQUAL(30, counter.Get());
+ }
+
+ Y_UNIT_TEST(Rate) {
+ TTestClock::TimePoint = TTestClock::time_point::min();
+
+ TRate rate(0);
+ {
+ TMetricTimerScope<TRate, milliseconds, TTestClock> t{&rate};
+ TTestClock::TimePoint += milliseconds(10);
+ }
+ UNIT_ASSERT_EQUAL(10, rate.Get());
+
+ {
+ TMetricTimerScope<TRate, milliseconds, TTestClock> t{&rate};
+ TTestClock::TimePoint += milliseconds(20);
+ }
+ UNIT_ASSERT_EQUAL(30, rate.Get());
+ }
+
+ Y_UNIT_TEST(Histogram) {
+ TTestClock::TimePoint = TTestClock::time_point::min();
+
+ auto assertHistogram = [](const TVector<ui64>& expected, IHistogramSnapshotPtr snapshot) {
+ UNIT_ASSERT_EQUAL(expected.size(), snapshot->Count());
+ for (size_t i = 0; i < expected.size(); ++i) {
+ UNIT_ASSERT_EQUAL(expected[i], snapshot->Value(i));
+ }
+ };
+
+ THistogram histogram(ExplicitHistogram({10, 20, 30}), true);
+ {
+ TMetricTimerScope<THistogram, milliseconds, TTestClock> t{&histogram};
+ TTestClock::TimePoint += milliseconds(5);
+ }
+ assertHistogram({1, 0, 0, 0}, histogram.TakeSnapshot());
+
+ {
+ TMetricTimerScope<THistogram, milliseconds, TTestClock> t{&histogram};
+ TTestClock::TimePoint += milliseconds(15);
+ }
+ assertHistogram({1, 1, 0, 0}, histogram.TakeSnapshot());
+ }
+
+ Y_UNIT_TEST(Moving) {
+ TTestClock::TimePoint = TTestClock::time_point::min();
+
+ TCounter counter(0);
+ {
+ TMetricTimerScope<TCounter, milliseconds, TTestClock> t{&counter};
+ [tt = std::move(t)] {
+ TTestClock::TimePoint += milliseconds(5);
+ Y_UNUSED(tt);
+ }();
+
+ TTestClock::TimePoint += milliseconds(10);
+ }
+
+ UNIT_ASSERT_EQUAL(counter.Get(), 5);
+ }
+
+ Y_UNIT_TEST(MovingIntoApply) {
+ TTestClock::TimePoint = TTestClock::time_point::min();
+ auto pool = CreateThreadPool(1);
+
+ TCounter counter(0);
+ {
+ TFutureFriendlyTimer<TCounter, milliseconds, TTestClock> t{&counter};
+
+ auto f = Async([=] {
+ return;
+ }, *pool).Apply([tt = t] (auto) {
+ TTestClock::TimePoint += milliseconds(5);
+ tt.Record();
+ });
+
+ f.Wait();
+ TTestClock::TimePoint += milliseconds(10);
+ }
+
+ UNIT_ASSERT_EQUAL(counter.Get(), 5);
+ }
+}
diff --git a/library/cpp/monlib/metrics/ut/histograms.json b/library/cpp/monlib/metrics/ut/histograms.json
new file mode 100644
index 0000000000..a6e8b78fea
--- /dev/null
+++ b/library/cpp/monlib/metrics/ut/histograms.json
@@ -0,0 +1,61 @@
+{
+ "commonLabels":
+ {
+ "common":"label"
+ },
+ "sensors":
+ [
+ {
+ "kind":"HIST",
+ "labels":
+ {
+ "sensor":"readTimeMillis"
+ },
+ "hist":
+ {
+ "bounds":
+ [
+ 1,
+ 2,
+ 4,
+ 8
+ ],
+ "buckets":
+ [
+ 2,
+ 1,
+ 2,
+ 4
+ ],
+ "inf":91
+ }
+ },
+ {
+ "kind":"HIST_RATE",
+ "labels":
+ {
+ "sensor":"writeTimeMillis"
+ },
+ "hist":
+ {
+ "bounds":
+ [
+ 1,
+ 5,
+ 15,
+ 20,
+ 25
+ ],
+ "buckets":
+ [
+ 2,
+ 4,
+ 10,
+ 5,
+ 5
+ ],
+ "inf":74
+ }
+ }
+ ]
+}
diff --git a/library/cpp/monlib/metrics/ut/ya.make b/library/cpp/monlib/metrics/ut/ya.make
new file mode 100644
index 0000000000..aec9974fbd
--- /dev/null
+++ b/library/cpp/monlib/metrics/ut/ya.make
@@ -0,0 +1,32 @@
+UNITTEST_FOR(library/cpp/monlib/metrics)
+
+OWNER(
+ jamel
+ g:solomon
+)
+
+SRCS(
+ ewma_ut.cpp
+ fake_ut.cpp
+ histogram_collector_ut.cpp
+ labels_ut.cpp
+ log_histogram_collector_ut.cpp
+ metric_registry_ut.cpp
+ metric_sub_registry_ut.cpp
+ metric_value_ut.cpp
+ summary_collector_ut.cpp
+ timer_ut.cpp
+)
+
+RESOURCE(
+ histograms.json /histograms.json
+)
+
+PEERDIR(
+ library/cpp/resource
+ library/cpp/monlib/encode/protobuf
+ library/cpp/monlib/encode/json
+ library/cpp/threading/future
+)
+
+END()
diff --git a/library/cpp/monlib/metrics/ya.make b/library/cpp/monlib/metrics/ya.make
new file mode 100644
index 0000000000..0e1fa143f9
--- /dev/null
+++ b/library/cpp/monlib/metrics/ya.make
@@ -0,0 +1,26 @@
+LIBRARY()
+
+OWNER(
+ g:solomon
+ jamel
+)
+
+GENERATE_ENUM_SERIALIZATION_WITH_HEADER(metric_value_type.h)
+
+SRCS(
+ ewma.cpp
+ fake.cpp
+ histogram_collector_explicit.cpp
+ histogram_collector_exponential.cpp
+ histogram_collector_linear.cpp
+ histogram_snapshot.cpp
+ log_histogram_snapshot.cpp
+ labels.cpp
+ metric_registry.cpp
+ metric_consumer.cpp
+ metric_type.cpp
+ metric_value.cpp
+ summary_snapshot.cpp
+)
+
+END()
diff --git a/library/cpp/monlib/service/auth.cpp b/library/cpp/monlib/service/auth.cpp
new file mode 100644
index 0000000000..ddabcfbbf7
--- /dev/null
+++ b/library/cpp/monlib/service/auth.cpp
@@ -0,0 +1,22 @@
+#include "auth.h"
+
+#include <util/generic/hash_set.h>
+
+
+namespace NMonitoring {
+namespace {
+ class TFakeAuthProvider final: public IAuthProvider {
+ public:
+ TAuthResult Check(const IHttpRequest&) override {
+ return TAuthResult::Ok();
+ }
+ };
+
+} // namespace
+
+THolder<IAuthProvider> CreateFakeAuth() {
+ return MakeHolder<TFakeAuthProvider>();
+}
+
+
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/service/auth.h b/library/cpp/monlib/service/auth.h
new file mode 100644
index 0000000000..ae53b8bd8e
--- /dev/null
+++ b/library/cpp/monlib/service/auth.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include "mon_service_http_request.h"
+
+namespace NMonitoring {
+ enum class EAuthType {
+ None = 0,
+ Tvm = 1,
+ };
+
+ struct TAuthResult {
+ enum class EStatus {
+ NoCredentials = 0,
+ Denied,
+ Ok,
+ };
+
+ TAuthResult(EStatus status)
+ : Status{status}
+ {
+ }
+
+ static TAuthResult Denied() {
+ return TAuthResult(EStatus::Denied);
+ }
+
+ static TAuthResult NoCredentials() {
+ return TAuthResult(EStatus::NoCredentials);
+ }
+
+ static TAuthResult Ok() {
+ return TAuthResult(EStatus::Ok);
+ }
+
+ explicit operator bool() const {
+ return Status == EStatus::Ok;
+ }
+
+ EStatus Status{EStatus::NoCredentials};
+ };
+
+ struct IAuthProvider {
+ virtual ~IAuthProvider() = default;
+ virtual TAuthResult Check(const IHttpRequest& req) = 0;
+ };
+
+ THolder<IAuthProvider> CreateFakeAuth();
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/service/auth/tvm/auth.cpp b/library/cpp/monlib/service/auth/tvm/auth.cpp
new file mode 100644
index 0000000000..e071c11ebc
--- /dev/null
+++ b/library/cpp/monlib/service/auth/tvm/auth.cpp
@@ -0,0 +1,93 @@
+#include "auth.h"
+
+#include <util/generic/hash_set.h>
+
+
+using namespace NTvmAuth;
+
+
+namespace NMonitoring {
+namespace {
+ template <class TTvmClientPtr = THolder<TTvmClient>>
+ class TTvmManager final: public ITvmManager {
+ public:
+ TTvmManager(NTvmApi::TClientSettings settings, TVector<TTvmId> clients, TLoggerPtr logger)
+ : AllowedClients_{clients.begin(), clients.end()}
+ , Tvm_(new TTvmClient{std::move(settings), std::move(logger)})
+ {
+ }
+
+ TTvmManager(NTvmTool::TClientSettings settings, TVector<TTvmId> clients, TLoggerPtr logger)
+ : AllowedClients_{clients.begin(), clients.end()}
+ , Tvm_(new TTvmClient{std::move(settings), std::move(logger)})
+ {
+ }
+
+ TTvmManager(TTvmClientPtr tvm, TVector<TTvmId> clients)
+ : AllowedClients_{clients.begin(), clients.end()}
+ , Tvm_(std::move(tvm))
+ {
+ }
+
+ bool IsAllowedClient(TTvmId clientId) override {
+ return AllowedClients_.contains(clientId);
+ }
+
+ TCheckedServiceTicket CheckServiceTicket(TStringBuf ticket) override {
+ return Tvm_->CheckServiceTicket(ticket);
+ }
+
+ private:
+ THashSet<TTvmId> AllowedClients_;
+ TTvmClientPtr Tvm_;
+ };
+
+ class TTvmAuthProvider final: public IAuthProvider {
+ public:
+ TTvmAuthProvider(THolder<ITvmManager> manager)
+ : TvmManager_{std::move(manager)}
+ {
+ }
+
+ TAuthResult Check(const IHttpRequest& req) override {
+ auto ticketHeader = req.GetHeaders().FindHeader("X-Ya-Service-Ticket");
+ if (!ticketHeader) {
+ return TAuthResult::NoCredentials();
+ }
+
+ const auto ticket = TvmManager_->CheckServiceTicket(ticketHeader->Value());
+ if (!ticket) {
+ return TAuthResult::Denied();
+ }
+
+ return TvmManager_->IsAllowedClient(ticket.GetSrc())
+ ? TAuthResult::Ok()
+ : TAuthResult::Denied();
+ }
+
+ private:
+ THolder<ITvmManager> TvmManager_;
+ };
+} // namespace
+
+THolder<ITvmManager> CreateDefaultTvmManager(NTvmApi::TClientSettings settings, TVector<TTvmId> allowedClients, TLoggerPtr logger) {
+ return MakeHolder<TTvmManager<>>(std::move(settings), std::move(allowedClients), std::move(logger));
+}
+
+THolder<ITvmManager> CreateDefaultTvmManager(NTvmTool::TClientSettings settings, TVector<TTvmId> allowedClients, TLoggerPtr logger) {
+ return MakeHolder<TTvmManager<>>(std::move(settings), std::move(allowedClients), std::move(logger));
+}
+
+THolder<ITvmManager> CreateDefaultTvmManager(TAtomicSharedPtr<NTvmAuth::TTvmClient> client, TVector<TTvmId> allowedClients) {
+ return MakeHolder<TTvmManager<TAtomicSharedPtr<NTvmAuth::TTvmClient>>>(std::move(client), std::move(allowedClients));
+}
+
+THolder<ITvmManager> CreateDefaultTvmManager(std::shared_ptr<NTvmAuth::TTvmClient> client, TVector<TTvmId> allowedClients) {
+ return MakeHolder<TTvmManager<std::shared_ptr<NTvmAuth::TTvmClient>>>(std::move(client), std::move(allowedClients));
+}
+
+THolder<IAuthProvider> CreateTvmAuth(THolder<ITvmManager> manager) {
+ return MakeHolder<TTvmAuthProvider>(std::move(manager));
+}
+
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/service/auth/tvm/auth.h b/library/cpp/monlib/service/auth/tvm/auth.h
new file mode 100644
index 0000000000..432beff9d6
--- /dev/null
+++ b/library/cpp/monlib/service/auth/tvm/auth.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <library/cpp/monlib/service/mon_service_http_request.h>
+#include <library/cpp/monlib/service/auth.h>
+#include <library/cpp/tvmauth/client/facade.h>
+
+namespace NMonitoring {
+ struct ITvmManager {
+ virtual ~ITvmManager() = default;
+ virtual bool IsAllowedClient(NTvmAuth::TTvmId clientId) = 0;
+ virtual NTvmAuth::TCheckedServiceTicket CheckServiceTicket(TStringBuf ticket) = 0;
+ };
+
+ THolder<ITvmManager> CreateDefaultTvmManager(
+ NTvmAuth::NTvmApi::TClientSettings settings,
+ TVector<NTvmAuth::TTvmId> allowedClients,
+ NTvmAuth::TLoggerPtr logger = NTvmAuth::TDevNullLogger::IAmBrave());
+
+ THolder<ITvmManager> CreateDefaultTvmManager(
+ NTvmAuth::NTvmTool::TClientSettings settings,
+ TVector<NTvmAuth::TTvmId> allowedClients,
+ NTvmAuth::TLoggerPtr logger = NTvmAuth::TDevNullLogger::IAmBrave());
+
+ THolder<ITvmManager> CreateDefaultTvmManager(
+ TAtomicSharedPtr<NTvmAuth::TTvmClient> client,
+ TVector<NTvmAuth::TTvmId> allowedClients);
+
+ THolder<ITvmManager> CreateDefaultTvmManager(
+ std::shared_ptr<NTvmAuth::TTvmClient> client,
+ TVector<NTvmAuth::TTvmId> allowedClients);
+
+ THolder<IAuthProvider> CreateTvmAuth(THolder<ITvmManager> tvmManager);
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/service/auth/tvm/ya.make b/library/cpp/monlib/service/auth/tvm/ya.make
new file mode 100644
index 0000000000..4437a65b62
--- /dev/null
+++ b/library/cpp/monlib/service/auth/tvm/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+OWNER(g:solomon)
+
+SRCS(
+ auth.cpp
+)
+
+PEERDIR(
+ library/cpp/tvmauth/client
+ library/cpp/monlib/service
+)
+
+END()
diff --git a/library/cpp/monlib/service/format.cpp b/library/cpp/monlib/service/format.cpp
new file mode 100644
index 0000000000..b0d6a10246
--- /dev/null
+++ b/library/cpp/monlib/service/format.cpp
@@ -0,0 +1 @@
+#include "format.h"
diff --git a/library/cpp/monlib/service/format.h b/library/cpp/monlib/service/format.h
new file mode 100644
index 0000000000..0044b586b1
--- /dev/null
+++ b/library/cpp/monlib/service/format.h
@@ -0,0 +1,86 @@
+#pragma once
+
+#include <library/cpp/monlib/encode/format.h>
+
+#include <util/string/ascii.h>
+#include <util/generic/yexception.h>
+#include <util/generic/typetraits.h>
+
+namespace NMonitoring {
+ namespace NPrivate {
+ Y_HAS_MEMBER(Name, Name);
+ Y_HAS_MEMBER(second, Second);
+ } // namespace NPrivate
+
+ template <typename TRequest>
+ ECompression ParseCompression(const TRequest& req) {
+ auto&& headers = req.GetHeaders();
+
+ constexpr auto isPlainPair = NPrivate::THasSecond<std::decay_t<decltype(*headers.begin())>>::value;
+
+ auto it = FindIf(std::begin(headers), std::end(headers),
+ [=] (const auto& h) {
+ if constexpr (NPrivate::THasName<std::decay_t<decltype(h)>>::value) {
+ return AsciiCompareIgnoreCase(h.Name(), TStringBuf("accept-encoding")) == 0;
+ } else if (isPlainPair) {
+ return AsciiCompareIgnoreCase(h.first, TStringBuf("accept-encoding")) == 0;
+ }
+ });
+
+ if (it == std::end(headers)) {
+ return NMonitoring::ECompression::IDENTITY;
+ }
+
+ NMonitoring::ECompression val{};
+ if constexpr (isPlainPair) {
+ val = CompressionFromAcceptEncodingHeader(it->second);
+ } else {
+ val = CompressionFromAcceptEncodingHeader(it->Value());
+ }
+
+ return val != NMonitoring::ECompression::UNKNOWN
+ ? val
+ : NMonitoring::ECompression::IDENTITY;
+ }
+
+ template <typename TRequest>
+ NMonitoring::EFormat ParseFormat(const TRequest& req) {
+ auto&& formatStr = req.GetParams()
+ .Get(TStringBuf("format"));
+
+ if (!formatStr.empty()) {
+ if (formatStr == TStringBuf("SPACK")) {
+ return EFormat::SPACK;
+ } else if (formatStr == TStringBuf("TEXT")) {
+ return EFormat::TEXT;
+ } else if (formatStr == TStringBuf("JSON")) {
+ return EFormat::JSON;
+ } else {
+ ythrow yexception() << "unknown format: " << formatStr << ". Only spack is supported here";
+ }
+ }
+
+ auto&& headers = req.GetHeaders();
+ constexpr auto isPlainPair = NPrivate::THasSecond<std::decay_t<decltype(*headers.begin())>>::value;
+
+ auto it = FindIf(std::begin(headers), std::end(headers),
+ [=] (const auto& h) {
+ if constexpr (NPrivate::THasName<std::decay_t<decltype(h)>>::value) {
+ return AsciiCompareIgnoreCase(h.Name(), TStringBuf("accept")) == 0;
+ } else if (isPlainPair) {
+ return AsciiCompareIgnoreCase(h.first, TStringBuf("accept")) == 0;
+ }
+ });
+
+ if (it != std::end(headers)) {
+ if constexpr (isPlainPair) {
+ return FormatFromAcceptHeader(it->second);
+ } else {
+ return FormatFromAcceptHeader(it->Value());
+ }
+ }
+
+ return EFormat::UNKNOWN;
+ }
+
+} // namespace NMonitoring
diff --git a/library/cpp/monlib/service/mon_service_http_request.cpp b/library/cpp/monlib/service/mon_service_http_request.cpp
new file mode 100644
index 0000000000..5d805631d9
--- /dev/null
+++ b/library/cpp/monlib/service/mon_service_http_request.cpp
@@ -0,0 +1,85 @@
+#include "mon_service_http_request.h"
+#include "monservice.h"
+
+using namespace NMonitoring;
+
+IMonHttpRequest::~IMonHttpRequest() {
+}
+
+TMonService2HttpRequest::~TMonService2HttpRequest() {
+}
+
+TString TMonService2HttpRequest::GetServiceTitle() const {
+ return MonService->GetTitle();
+}
+
+IOutputStream& TMonService2HttpRequest::Output() {
+ return *Out;
+}
+
+HTTP_METHOD TMonService2HttpRequest::GetMethod() const {
+ return HttpRequest->GetMethod();
+}
+
+TStringBuf TMonService2HttpRequest::GetPathInfo() const {
+ return PathInfo;
+}
+
+TStringBuf TMonService2HttpRequest::GetPath() const {
+ return HttpRequest->GetPath();
+}
+
+TStringBuf TMonService2HttpRequest::GetUri() const {
+ return HttpRequest->GetURI();
+}
+
+const TCgiParameters& TMonService2HttpRequest::GetParams() const {
+ return HttpRequest->GetParams();
+}
+
+const TCgiParameters& TMonService2HttpRequest::GetPostParams() const {
+ return HttpRequest->GetPostParams();
+}
+
+TStringBuf TMonService2HttpRequest::GetHeader(TStringBuf name) const {
+ const THttpHeaders& headers = HttpRequest->GetHeaders();
+ const THttpInputHeader* header = headers.FindHeader(name);
+ if (header != nullptr) {
+ return header->Value();
+ }
+ return TStringBuf();
+}
+
+const THttpHeaders& TMonService2HttpRequest::GetHeaders() const {
+ return HttpRequest->GetHeaders();
+}
+
+TString TMonService2HttpRequest::GetRemoteAddr() const {
+ return HttpRequest->GetRemoteAddr();
+}
+
+TStringBuf TMonService2HttpRequest::GetCookie(TStringBuf name) const {
+ TStringBuf cookie = GetHeader("Cookie");
+ size_t size = cookie.size();
+ size_t start = 0;
+ while (start < size) {
+ size_t semicolon = cookie.find(';', start);
+ auto pair = cookie.substr(start, semicolon - start);
+ if (!pair.empty()) {
+ size_t equal = pair.find('=');
+ if (equal != TStringBuf::npos) {
+ auto cookieName = pair.substr(0, equal);
+ if (cookieName == name) {
+ size_t valueStart = equal + 1;
+ auto cookieValue = pair.substr(valueStart, semicolon - valueStart);
+ return cookieValue;
+ }
+ }
+ start = semicolon;
+ while (start < size && (cookie[start] == ' ' || cookie[start] == ';')) {
+ ++start;
+ }
+ }
+ }
+ return TStringBuf();
+}
diff --git a/library/cpp/monlib/service/mon_service_http_request.h b/library/cpp/monlib/service/mon_service_http_request.h
new file mode 100644
index 0000000000..b4f2f8f0c5
--- /dev/null
+++ b/library/cpp/monlib/service/mon_service_http_request.h
@@ -0,0 +1,90 @@
+#pragma once
+
+#include "service.h"
+
+#include <util/stream/output.h>
+
+namespace NMonitoring {
+ class TMonService2;
+ class IMonPage;
+
+ // XXX: IHttpRequest is already taken
+ struct IMonHttpRequest {
+ virtual ~IMonHttpRequest();
+
+ virtual IOutputStream& Output() = 0;
+
+ virtual HTTP_METHOD GetMethod() const = 0;
+ virtual TStringBuf GetPath() const = 0;
+ virtual TStringBuf GetPathInfo() const = 0;
+ virtual TStringBuf GetUri() const = 0;
+ virtual const TCgiParameters& GetParams() const = 0;
+ virtual const TCgiParameters& GetPostParams() const = 0;
+ virtual TStringBuf GetPostContent() const = 0;
+ virtual const THttpHeaders& GetHeaders() const = 0;
+ virtual TStringBuf GetHeader(TStringBuf name) const = 0;
+ virtual TStringBuf GetCookie(TStringBuf name) const = 0;
+ virtual TString GetRemoteAddr() const = 0;
+
+ virtual TString GetServiceTitle() const = 0;
+
+ virtual IMonPage* GetPage() const = 0;
+
+ virtual IMonHttpRequest* MakeChild(IMonPage* page, const TString& pathInfo) const = 0;
+ };
+
+ struct TMonService2HttpRequest: IMonHttpRequest {
+ IOutputStream* const Out;
+ const IHttpRequest* const HttpRequest;
+ TMonService2* const MonService;
+ IMonPage* const MonPage;
+ const TString PathInfo;
+ TMonService2HttpRequest* const Parent;
+
+ TMonService2HttpRequest(
+ IOutputStream* out, const IHttpRequest* httpRequest,
+ TMonService2* monService, IMonPage* monPage,
+ const TString& pathInfo,
+ TMonService2HttpRequest* parent)
+ : Out(out)
+ , HttpRequest(httpRequest)
+ , MonService(monService)
+ , MonPage(monPage)
+ , PathInfo(pathInfo)
+ , Parent(parent)
+ {
+ }
+
+ ~TMonService2HttpRequest() override;
+
+ IOutputStream& Output() override;
+ HTTP_METHOD GetMethod() const override;
+ TStringBuf GetPath() const override;
+ TStringBuf GetPathInfo() const override;
+ TStringBuf GetUri() const override;
+ const TCgiParameters& GetParams() const override;
+ const TCgiParameters& GetPostParams() const override;
+ TStringBuf GetPostContent() const override {
+ return HttpRequest->GetPostContent();
+ }
+
+ TStringBuf GetHeader(TStringBuf name) const override;
+ TStringBuf GetCookie(TStringBuf name) const override;
+ const THttpHeaders& GetHeaders() const override;
+ TString GetRemoteAddr() const override;
+
+ IMonPage* GetPage() const override {
+ return MonPage;
+ }
+
+ TMonService2HttpRequest* MakeChild(IMonPage* page, const TString& pathInfo) const override {
+ return new TMonService2HttpRequest{
+ Out, HttpRequest, MonService, page,
+ pathInfo, const_cast<TMonService2HttpRequest*>(this)
+ };
+ }
+
+ TString GetServiceTitle() const override;
+ };
+
+}
diff --git a/library/cpp/monlib/service/monservice.cpp b/library/cpp/monlib/service/monservice.cpp
new file mode 100644
index 0000000000..d1b9cda1d2
--- /dev/null
+++ b/library/cpp/monlib/service/monservice.cpp
@@ -0,0 +1,129 @@
+#include "monservice.h"
+
+#include <library/cpp/malloc/api/malloc.h>
+#include <library/cpp/string_utils/base64/base64.h>
+#include <library/cpp/svnversion/svnversion.h>
+
+#include <util/generic/map.h>
+#include <util/generic/ptr.h>
+#include <util/system/hostname.h>
+
+#include <google/protobuf/text_format.h>
+
+using namespace NMonitoring;
+
+TMonService2::TMonService2(ui16 port, const TString& host, ui32 threads, const TString& title, THolder<IAuthProvider> auth)
+ : TMonService2(HttpServerOptions(port, host, threads), title, std::move(auth))
+{
+}
+
+TMonService2::TMonService2(const THttpServerOptions& options, const TString& title, THolder<IAuthProvider> auth)
+ : NMonitoring::TMtHttpServer(options, std::bind(&TMonService2::ServeRequest, this, std::placeholders::_1, std::placeholders::_2))
+ , Title(title)
+ , IndexMonPage(new TIndexMonPage("", Title))
+ , AuthProvider_{std::move(auth)}
+{
+ Y_VERIFY(!!title);
+ time_t t = time(nullptr);
+ ctime_r(&t, StartTime);
+}
+
+TMonService2::TMonService2(const THttpServerOptions& options, TSimpleSharedPtr<IThreadPool> pool, const TString& title, THolder<IAuthProvider> auth)
+ : NMonitoring::TMtHttpServer(options, std::bind(&TMonService2::ServeRequest, this, std::placeholders::_1, std::placeholders::_2), std::move(pool))
+ , Title(title)
+ , IndexMonPage(new TIndexMonPage("", Title))
+ , AuthProvider_{std::move(auth)}
+{
+ Y_VERIFY(!!title);
+ time_t t = time(nullptr);
+ ctime_r(&t, StartTime);
+}
+
+TMonService2::TMonService2(ui16 port, ui32 threads, const TString& title, THolder<IAuthProvider> auth)
+ : TMonService2(port, TString(), threads, title, std::move(auth))
+{
+}
+
+TMonService2::TMonService2(ui16 port, const TString& title, THolder<IAuthProvider> auth)
+ : TMonService2(port, TString(), 0, title, std::move(auth))
+{
+}
+
+void TMonService2::OutputIndex(IOutputStream& out) {
+ IndexMonPage->OutputIndex(out, true);
+}
+
+void TMonService2::OutputIndexPage(IOutputStream& out) {
+ out << HTTPOKHTML;
+ out << "<html>\n";
+ IndexMonPage->OutputHead(out);
+ OutputIndexBody(out);
+ out << "</html>\n";
+}
+
+void TMonService2::OutputIndexBody(IOutputStream& out) {
+ out << "<body>\n";
+
+ // part of common navbar
+ out << "<ol class='breadcrumb'>\n";
+ out << "<li class='active'>" << Title << "</li>\n";
+ out << "</ol>\n";
+
+ out << "<div class='container'>\n"
+ << "<h2>" << Title << "</h2>\n";
+ OutputIndex(out);
+ out
+ << "<div>\n"
+ << "</body>\n";
+}
+
+void TMonService2::ServeRequest(IOutputStream& out, const NMonitoring::IHttpRequest& request) {
+ TString path = request.GetPath();
+ Y_VERIFY(path.StartsWith('/'));
+
+ if (AuthProvider_) {
+ const auto authResult = AuthProvider_->Check(request);
+ switch (authResult.Status) {
+ case TAuthResult::EStatus::NoCredentials:
+ out << HTTPUNAUTHORIZED;
+ return;
+ case TAuthResult::EStatus::Denied:
+ out << HTTPFORBIDDEN;
+ return;
+ case TAuthResult::EStatus::Ok:
+ break;
+ }
+ }
+
+ if (path == "/") {
+ OutputIndexPage(out);
+ } else {
+ TMonService2HttpRequest monService2HttpRequest(
+ &out, &request, this, IndexMonPage.Get(), path, nullptr);
+ IndexMonPage->Output(monService2HttpRequest);
+ }
+}
+
+void TMonService2::Register(IMonPage* page) {
+ IndexMonPage->Register(page);
+}
+
+void TMonService2::Register(TMonPagePtr page) {
+ IndexMonPage->Register(std::move(page));
+}
+
+TIndexMonPage* TMonService2::RegisterIndexPage(const TString& path, const TString& title) {
+ return IndexMonPage->RegisterIndexPage(path, title);
+}
+
+IMonPage* TMonService2::FindPage(const TString& relativePath) {
+ return IndexMonPage->FindPage(relativePath);
+}
+
+TIndexMonPage* TMonService2::FindIndexPage(const TString& relativePath) {
+ return IndexMonPage->FindIndexPage(relativePath);
+}
+
+void TMonService2::SortPages() {
+ IndexMonPage->SortPages();
+}
diff --git a/library/cpp/monlib/service/monservice.h b/library/cpp/monlib/service/monservice.h
new file mode 100644
index 0000000000..8f5e52fcdb
--- /dev/null
+++ b/library/cpp/monlib/service/monservice.h
@@ -0,0 +1,73 @@
+#pragma once
+
+#include "service.h"
+#include "auth.h"
+#include "mon_service_http_request.h"
+
+#include <library/cpp/monlib/service/pages/index_mon_page.h>
+#include <library/cpp/monlib/service/pages/mon_page.h>
+
+#include <util/system/progname.h>
+
+#include <functional>
+
+namespace NMonitoring {
+ class TMonService2: public TMtHttpServer {
+ protected:
+ const TString Title;
+ char StartTime[26];
+ TIntrusivePtr<TIndexMonPage> IndexMonPage;
+ THolder<IAuthProvider> AuthProvider_;
+
+ public:
+ static THttpServerOptions HttpServerOptions(ui16 port, const TString& host, ui32 threads) {
+ THttpServerOptions opts(port);
+ if (!host.empty()) {
+ opts.SetHost(host);
+ }
+ opts.SetClientTimeout(TDuration::Minutes(1));
+ opts.EnableCompression(true);
+ opts.SetThreads(threads);
+ opts.SetMaxConnections(std::max<ui32>(100, threads));
+ opts.EnableRejectExcessConnections(true);
+ return opts;
+ }
+
+ static THttpServerOptions HttpServerOptions(ui16 port, ui32 threads) {
+ return HttpServerOptions(port, TString(), threads);
+ }
+
+ public:
+ explicit TMonService2(ui16 port, const TString& title = GetProgramName(), THolder<IAuthProvider> auth = nullptr);
+ explicit TMonService2(ui16 port, ui32 threads, const TString& title = GetProgramName(), THolder<IAuthProvider> auth = nullptr);
+ explicit TMonService2(ui16 port, const TString& host, ui32 threads, const TString& title = GetProgramName(), THolder<IAuthProvider> auth = nullptr);
+ explicit TMonService2(const THttpServerOptions& options, const TString& title = GetProgramName(), THolder<IAuthProvider> auth = nullptr);
+ explicit TMonService2(const THttpServerOptions& options, TSimpleSharedPtr<IThreadPool> pool, const TString& title = GetProgramName(), THolder<IAuthProvider> auth = nullptr);
+
+ ~TMonService2() override {
+ }
+
+ const char* GetStartTime() const {
+ return StartTime;
+ }
+
+ const TString& GetTitle() const {
+ return Title;
+ }
+
+ virtual void ServeRequest(IOutputStream& out, const NMonitoring::IHttpRequest& request);
+ virtual void OutputIndex(IOutputStream& out);
+ virtual void OutputIndexPage(IOutputStream& out);
+ virtual void OutputIndexBody(IOutputStream& out);
+
+ void Register(IMonPage* page);
+ void Register(TMonPagePtr page);
+
+ TIndexMonPage* RegisterIndexPage(const TString& path, const TString& title);
+
+ IMonPage* FindPage(const TString& relativePath);
+ TIndexMonPage* FindIndexPage(const TString& relativePath);
+ void SortPages();
+ };
+
+}
diff --git a/library/cpp/monlib/service/pages/diag_mon_page.cpp b/library/cpp/monlib/service/pages/diag_mon_page.cpp
new file mode 100644
index 0000000000..2493ff4fba
--- /dev/null
+++ b/library/cpp/monlib/service/pages/diag_mon_page.cpp
@@ -0,0 +1,9 @@
+#include "diag_mon_page.h"
+
+using namespace NMonitoring;
+
+void TDiagMonPage::OutputText(IOutputStream& out, NMonitoring::IMonHttpRequest& request) {
+ out << "uri: " << request.GetUri() << "\n";
+ out << "path: " << request.GetPath() << "\n";
+ out << "path info: " << request.GetPathInfo() << "\n";
+}
diff --git a/library/cpp/monlib/service/pages/diag_mon_page.h b/library/cpp/monlib/service/pages/diag_mon_page.h
new file mode 100644
index 0000000000..761194d4ec
--- /dev/null
+++ b/library/cpp/monlib/service/pages/diag_mon_page.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "pre_mon_page.h"
+
+namespace NMonitoring {
+ // internal diagnostics page
+ struct TDiagMonPage: public TPreMonPage {
+ TDiagMonPage()
+ : TPreMonPage("diag", "Diagnostics Page")
+ {
+ }
+
+ void OutputText(IOutputStream& out, NMonitoring::IMonHttpRequest&) override;
+ };
+
+}
diff --git a/library/cpp/monlib/service/pages/html_mon_page.cpp b/library/cpp/monlib/service/pages/html_mon_page.cpp
new file mode 100644
index 0000000000..eb4eb3b66c
--- /dev/null
+++ b/library/cpp/monlib/service/pages/html_mon_page.cpp
@@ -0,0 +1,60 @@
+#include "html_mon_page.h"
+
+#include <library/cpp/monlib/service/pages/templates.h>
+
+using namespace NMonitoring;
+
+void THtmlMonPage::Output(NMonitoring::IMonHttpRequest& request) {
+ IOutputStream& out = request.Output();
+
+ out << HTTPOKHTML;
+ HTML(out) {
+ out << "<!DOCTYPE html>\n";
+ HTML_TAG() {
+ HEAD() {
+ if (!!Title) {
+ out << "<title>" << Title << "</title>\n";
+ }
+ out << "<link rel='stylesheet' href='https://yastatic.net/bootstrap/3.3.1/css/bootstrap.min.css'>\n";
+ out << "<script language='javascript' type='text/javascript' src='https://yastatic.net/jquery/2.1.3/jquery.min.js'></script>\n";
+ out << "<script language='javascript' type='text/javascript' src='https://yastatic.net/bootstrap/3.3.1/js/bootstrap.min.js'></script>\n";
+
+ if (OutputTableSorterJsCss) {
+ out << "<link rel='stylesheet' href='/jquery.tablesorter.css'>\n";
+ out << "<script language='javascript' type='text/javascript' src='/jquery.tablesorter.js'></script>\n";
+ }
+
+ out << "<style type=\"text/css\">\n";
+ out << ".table-nonfluid { width: auto; }\n";
+ out << ".narrow-line50 {line-height: 50%}\n";
+ out << ".narrow-line60 {line-height: 60%}\n";
+ out << ".narrow-line70 {line-height: 70%}\n";
+ out << ".narrow-line80 {line-height: 80%}\n";
+ out << ".narrow-line90 {line-height: 90%}\n";
+ out << "</style>\n";
+ }
+ BODY() {
+ OutputNavBar(out);
+
+ DIV_CLASS("container") {
+ if (!!Title) {
+ out << "<h2>" << Title << "</h2>";
+ }
+ OutputContent(request);
+ }
+ }
+ }
+ }
+}
+
+void THtmlMonPage::NotFound(NMonitoring::IMonHttpRequest& request) const {
+ IOutputStream& out = request.Output();
+ out << HTTPNOTFOUND;
+ out.Flush();
+}
+
+void THtmlMonPage::NoContent(NMonitoring::IMonHttpRequest& request) const {
+ IOutputStream& out = request.Output();
+ out << HTTPNOCONTENT;
+ out.Flush();
+}
diff --git a/library/cpp/monlib/service/pages/html_mon_page.h b/library/cpp/monlib/service/pages/html_mon_page.h
new file mode 100644
index 0000000000..e87c53b62b
--- /dev/null
+++ b/library/cpp/monlib/service/pages/html_mon_page.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "mon_page.h"
+
+namespace NMonitoring {
+ struct THtmlMonPage: public IMonPage {
+ THtmlMonPage(const TString& path,
+ const TString& title = TString(),
+ bool outputTableSorterJsCss = false)
+ : IMonPage(path, title)
+ , OutputTableSorterJsCss(outputTableSorterJsCss)
+ {
+ }
+
+ void Output(NMonitoring::IMonHttpRequest& request) override;
+
+ void NotFound(NMonitoring::IMonHttpRequest& request) const;
+ void NoContent(NMonitoring::IMonHttpRequest& request) const;
+
+ virtual void OutputContent(NMonitoring::IMonHttpRequest& request) = 0;
+
+ bool OutputTableSorterJsCss;
+ };
+
+}
diff --git a/library/cpp/monlib/service/pages/index_mon_page.cpp b/library/cpp/monlib/service/pages/index_mon_page.cpp
new file mode 100644
index 0000000000..83ff8b529a
--- /dev/null
+++ b/library/cpp/monlib/service/pages/index_mon_page.cpp
@@ -0,0 +1,151 @@
+#include "index_mon_page.h"
+
+#include <util/generic/cast.h>
+#include <util/string/ascii.h>
+
+using namespace NMonitoring;
+
+void TIndexMonPage::OutputIndexPage(IMonHttpRequest& request) {
+ request.Output() << HTTPOKHTML;
+ request.Output() << "<html>\n";
+ OutputHead(request.Output());
+ OutputBody(request);
+ request.Output() << "</html>\n";
+}
+
+void TIndexMonPage::Output(IMonHttpRequest& request) {
+ TStringBuf pathInfo = request.GetPathInfo();
+ if (pathInfo.empty() || pathInfo == TStringBuf("/")) {
+ OutputIndexPage(request);
+ return;
+ }
+
+ Y_VERIFY(pathInfo.StartsWith('/'));
+
+ TMonPagePtr found;
+ // analogous to CGI PATH_INFO
+ {
+ TGuard<TMutex> g(Mtx);
+ TStringBuf pathTmp = request.GetPathInfo();
+ for (;;) {
+ TPagesByPath::iterator i = PagesByPath.find(pathTmp);
+ if (i != PagesByPath.end()) {
+ found = i->second;
+ pathInfo = request.GetPathInfo().substr(pathTmp.size());
+ Y_VERIFY(pathInfo.empty() || pathInfo.StartsWith('/'));
+ break;
+ }
+ size_t slash = pathTmp.find_last_of('/');
+ Y_VERIFY(slash != TString::npos);
+ pathTmp = pathTmp.substr(0, slash);
+ if (!pathTmp) {
+ break;
+ }
+ }
+ }
+ if (found) {
+ THolder<IMonHttpRequest> child(request.MakeChild(found.Get(), TString{pathInfo}));
+ found->Output(*child);
+ } else {
+ request.Output() << HTTPNOTFOUND;
+ }
+}
+
+void TIndexMonPage::OutputIndex(IOutputStream& out, bool pathEndsWithSlash) {
+ TGuard<TMutex> g(Mtx);
+ for (auto& Page : Pages) {
+ IMonPage* page = Page.Get();
+ if (page->IsInIndex()) {
+ TString pathToDir = "";
+ if (!pathEndsWithSlash) {
+ pathToDir = this->GetPath() + "/";
+ }
+ out << "<a href='" << pathToDir << page->GetPath() << "'>" << page->GetTitle() << "</a><br/>\n";
+ }
+ }
+}
+
+void TIndexMonPage::Register(TMonPagePtr page) {
+ TGuard<TMutex> g(Mtx);
+ auto insres = PagesByPath.insert(std::make_pair("/" + page->GetPath(), page));
+ if (insres.second) {
+ // new unique page just inserted, update Pages
+ Pages.push_back(page);
+ } else {
+ // a page with the given path is already present, replace it with the new page
+
+ // find old page, sorry for O(n)
+ auto it = std::find(Pages.begin(), Pages.end(), insres.first->second);
+ *it = page;
+ // this already present, replace it
+ insres.first->second = page;
+ }
+ page->Parent = this;
+}
+
+TIndexMonPage* TIndexMonPage::RegisterIndexPage(const TString& path, const TString& title) {
+ TGuard<TMutex> g(Mtx);
+ TIndexMonPage* page = VerifyDynamicCast<TIndexMonPage*>(FindPage(path));
+ if (page) {
+ return page;
+ }
+ page = new TIndexMonPage(path, title);
+ Register(page);
+ return VerifyDynamicCast<TIndexMonPage*>(page);
+}
+
+IMonPage* TIndexMonPage::FindPage(const TString& relativePath) {
+ TGuard<TMutex> g(Mtx);
+
+ Y_VERIFY(!relativePath.StartsWith('/'));
+ TPagesByPath::iterator i = PagesByPath.find("/" + relativePath);
+ if (i == PagesByPath.end()) {
+ return nullptr;
+ } else {
+ return i->second.Get();
+ }
+}
+
+TIndexMonPage* TIndexMonPage::FindIndexPage(const TString& relativePath) {
+ return VerifyDynamicCast<TIndexMonPage*>(FindPage(relativePath));
+}
+
+void TIndexMonPage::OutputCommonJsCss(IOutputStream& out) {
+ out << "<link rel='stylesheet' href='https://yastatic.net/bootstrap/3.3.1/css/bootstrap.min.css'>\n";
+ out << "<script language='javascript' type='text/javascript' src='https://yastatic.net/jquery/2.1.3/jquery.min.js'></script>\n";
+ out << "<script language='javascript' type='text/javascript' src='https://yastatic.net/bootstrap/3.3.1/js/bootstrap.min.js'></script>\n";
+}
+
+void TIndexMonPage::OutputHead(IOutputStream& out) {
+ out << "<head>\n";
+ OutputCommonJsCss(out);
+ out << "<title>" << Title << "</title>\n";
+ out << "</head>\n";
+}
+
+void TIndexMonPage::OutputBody(IMonHttpRequest& req) {
+ auto& out = req.Output();
+ out << "<body>\n";
+
+ // part of common navbar
+ OutputNavBar(out);
+
+ out << "<div class='container'>\n"
+ << "<h2>" << Title << "</h2>\n";
+ OutputIndex(out, req.GetPathInfo().EndsWith('/'));
+ out << "<div>\n"
+ << "</body>\n";
+}
+
+void TIndexMonPage::SortPages() {
+ TGuard<TMutex> g(Mtx);
+ std::sort(Pages.begin(), Pages.end(), [](const TMonPagePtr& a, const TMonPagePtr& b) {
+ return AsciiCompareIgnoreCase(a->GetTitle(), b->GetTitle()) < 0;
+ });
+}
+
+void TIndexMonPage::ClearPages() {
+ TGuard<TMutex> g(Mtx);
+ Pages.clear();
+ PagesByPath.clear();
+}
diff --git a/library/cpp/monlib/service/pages/index_mon_page.h b/library/cpp/monlib/service/pages/index_mon_page.h
new file mode 100644
index 0000000000..bf514a3105
--- /dev/null
+++ b/library/cpp/monlib/service/pages/index_mon_page.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "mon_page.h"
+
+namespace NMonitoring {
+ struct TIndexMonPage: public IMonPage {
+ TMutex Mtx;
+ typedef TVector<TMonPagePtr> TPages;
+ TPages Pages;
+ typedef THashMap<TString, TMonPagePtr> TPagesByPath;
+ TPagesByPath PagesByPath;
+
+ TIndexMonPage(const TString& path, const TString& title)
+ : IMonPage(path, title)
+ {
+ }
+
+ ~TIndexMonPage() override {
+ }
+
+ void Output(IMonHttpRequest& request) override;
+ void OutputIndexPage(IMonHttpRequest& request);
+ virtual void OutputIndex(IOutputStream& out, bool pathEndsWithSlash);
+ virtual void OutputCommonJsCss(IOutputStream& out);
+ void OutputHead(IOutputStream& out);
+ void OutputBody(IMonHttpRequest& out);
+
+ void Register(TMonPagePtr page);
+ TIndexMonPage* RegisterIndexPage(const TString& path, const TString& title);
+
+ IMonPage* FindPage(const TString& relativePath);
+ TIndexMonPage* FindIndexPage(const TString& relativePath);
+
+ void SortPages();
+ void ClearPages();
+ };
+
+}
diff --git a/library/cpp/monlib/service/pages/mon_page.cpp b/library/cpp/monlib/service/pages/mon_page.cpp
new file mode 100644
index 0000000000..72033b1699
--- /dev/null
+++ b/library/cpp/monlib/service/pages/mon_page.cpp
@@ -0,0 +1,36 @@
+#include "mon_page.h"
+
+using namespace NMonitoring;
+
+IMonPage::IMonPage(const TString& path, const TString& title)
+ : Path(path)
+ , Title(title)
+{
+ Y_VERIFY(!Path.StartsWith('/'));
+ Y_VERIFY(!Path.EndsWith('/'));
+}
+
+void IMonPage::OutputNavBar(IOutputStream& out) {
+ TVector<const IMonPage*> parents;
+ for (const IMonPage* p = this; p; p = p->Parent) {
+ parents.push_back(p);
+ }
+ std::reverse(parents.begin(), parents.end());
+
+ out << "<ol class='breadcrumb'>\n";
+
+ TString absolutePath;
+ for (size_t i = 0; i < parents.size(); ++i) {
+ const TString& title = parents[i]->GetTitle();
+ if (i == parents.size() - 1) {
+ out << "<li>" << title << "</li>\n";
+ } else {
+ if (!absolutePath.EndsWith('/')) {
+ absolutePath += '/';
+ }
+ absolutePath += parents[i]->GetPath();
+ out << "<li class='active'><a href='" << absolutePath << "'>" << title << "</a></li>\n";
+ }
+ }
+ out << "</ol>\n";
+}
diff --git a/library/cpp/monlib/service/pages/mon_page.h b/library/cpp/monlib/service/pages/mon_page.h
new file mode 100644
index 0000000000..e396612bb0
--- /dev/null
+++ b/library/cpp/monlib/service/pages/mon_page.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include <library/cpp/monlib/service/service.h>
+#include <library/cpp/monlib/service/mon_service_http_request.h>
+
+#include <util/generic/string.h>
+#include <util/generic/ptr.h>
+
+namespace NMonitoring {
+ static const char HTTPOKTEXT[] = "HTTP/1.1 200 Ok\r\nContent-Type: text/plain\r\nConnection: Close\r\n\r\n";
+ static const char HTTPOKBIN[] = "HTTP/1.1 200 Ok\r\nContent-Type: application/octet-stream\r\nConnection: Close\r\n\r\n";
+ static const char HTTPOKHTML[] = "HTTP/1.1 200 Ok\r\nContent-Type: text/html\r\nConnection: Close\r\n\r\n";
+ static const char HTTPOKJSON[] = "HTTP/1.1 200 Ok\r\nContent-Type: application/json\r\nConnection: Close\r\n\r\n";
+ static const char HTTPOKSPACK[] = "HTTP/1.1 200 Ok\r\nContent-Type: application/x-solomon-spack\r\nConnection: Close\r\n\r\n";
+ static const char HTTPOKPROMETHEUS[] = "HTTP/1.1 200 Ok\r\nContent-Type: text/plain\r\nConnection: Close\r\n\r\n";
+ static const char HTTPOKJAVASCRIPT[] = "HTTP/1.1 200 Ok\r\nContent-Type: text/javascript\r\nConnection: Close\r\n\r\n";
+ static const char HTTPOKCSS[] = "HTTP/1.1 200 Ok\r\nContent-Type: text/css\r\nConnection: Close\r\n\r\n";
+ static const char HTTPNOCONTENT[] = "HTTP/1.1 204 No content\r\nConnection: Close\r\n\r\n";
+ static const char HTTPNOTFOUND[] = "HTTP/1.1 404 Invalid URI\r\nConnection: Close\r\n\r\nInvalid URL\r\n";
+ static const char HTTPUNAUTHORIZED[] = "HTTP/1.1 401 Unauthorized\r\nConnection: Close\r\n\r\nUnauthorized\r\n";
+ static const char HTTPFORBIDDEN[] = "HTTP/1.1 403 Forbidden\r\nConnection: Close\r\n\r\nForbidden\r\n";
+
+ // Fonts
+ static const char HTTPOKFONTEOT[] = "HTTP/1.1 200 Ok\r\nContent-Type: application/vnd.ms-fontobject\r\nConnection: Close\r\n\r\n";
+ static const char HTTPOKFONTTTF[] = "HTTP/1.1 200 Ok\r\nContent-Type: application/x-font-ttf\r\nConnection: Close\r\n\r\n";
+ static const char HTTPOKFONTWOFF[] = "HTTP/1.1 200 Ok\r\nContent-Type: application/font-woff\r\nConnection: Close\r\n\r\n";
+ static const char HTTPOKFONTWOFF2[] = "HTTP/1.1 200 Ok\r\nContent-Type: application/font-woff2\r\nConnection: Close\r\n\r\n";
+
+ // Images
+ static const char HTTPOKPNG[] = "HTTP/1.1 200 Ok\r\nContent-Type: image/png\r\nConnection: Close\r\n\r\n";
+ static const char HTTPOKSVG[] = "HTTP/1.1 200 Ok\r\nContent-Type: image/svg+xml\r\nConnection: Close\r\n\r\n";
+
+ class IMonPage;
+
+ using TMonPagePtr = TIntrusivePtr<IMonPage>;
+
+ class IMonPage: public TAtomicRefCount<IMonPage> {
+ public:
+ const TString Path;
+ const TString Title;
+ const IMonPage* Parent = nullptr;
+
+ public:
+ IMonPage(const TString& path, const TString& title = TString());
+
+ virtual ~IMonPage() {
+ }
+
+ void OutputNavBar(IOutputStream& out);
+
+ virtual const TString& GetPath() const {
+ return Path;
+ }
+
+ virtual const TString& GetTitle() const {
+ return Title;
+ }
+
+ bool IsInIndex() const {
+ return !Title.empty();
+ }
+
+ virtual void Output(IMonHttpRequest& request) = 0;
+ };
+
+}
diff --git a/library/cpp/monlib/service/pages/pre_mon_page.cpp b/library/cpp/monlib/service/pages/pre_mon_page.cpp
new file mode 100644
index 0000000000..fc03a19b80
--- /dev/null
+++ b/library/cpp/monlib/service/pages/pre_mon_page.cpp
@@ -0,0 +1,18 @@
+#include "pre_mon_page.h"
+
+using namespace NMonitoring;
+
+void TPreMonPage::OutputContent(NMonitoring::IMonHttpRequest& request) {
+ auto& out = request.Output();
+ if (PreTag) {
+ BeforePre(request);
+ out << "<pre>\n";
+ OutputText(out, request);
+ out << "</pre>\n";
+ } else {
+ OutputText(out, request);
+ }
+}
+
+void TPreMonPage::BeforePre(NMonitoring::IMonHttpRequest&) {
+}
diff --git a/library/cpp/monlib/service/pages/pre_mon_page.h b/library/cpp/monlib/service/pages/pre_mon_page.h
new file mode 100644
index 0000000000..c9a923d39a
--- /dev/null
+++ b/library/cpp/monlib/service/pages/pre_mon_page.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "html_mon_page.h"
+
+namespace NMonitoring {
+ struct TPreMonPage: public THtmlMonPage {
+ TPreMonPage(const TString& path,
+ const TString& title = TString(),
+ bool preTag = true,
+ bool outputTableSorterJsCss = false)
+ : THtmlMonPage(path, title, outputTableSorterJsCss)
+ , PreTag(preTag)
+ {
+ }
+
+ void OutputContent(NMonitoring::IMonHttpRequest& request) override;
+
+ // hook to customize output
+ virtual void BeforePre(NMonitoring::IMonHttpRequest& request);
+
+ // put your text here
+ virtual void OutputText(IOutputStream& out, NMonitoring::IMonHttpRequest&) = 0;
+
+ const bool PreTag;
+ };
+
+}
diff --git a/library/cpp/monlib/service/pages/registry_mon_page.cpp b/library/cpp/monlib/service/pages/registry_mon_page.cpp
new file mode 100644
index 0000000000..c59e50f622
--- /dev/null
+++ b/library/cpp/monlib/service/pages/registry_mon_page.cpp
@@ -0,0 +1,46 @@
+#include "registry_mon_page.h"
+
+#include <library/cpp/monlib/encode/text/text.h>
+#include <library/cpp/monlib/encode/json/json.h>
+#include <library/cpp/monlib/encode/prometheus/prometheus.h>
+#include <library/cpp/monlib/encode/spack/spack_v1.h>
+#include <library/cpp/monlib/service/format.h>
+
+namespace NMonitoring {
+ void TMetricRegistryPage::Output(NMonitoring::IMonHttpRequest& request) {
+ const auto formatStr = TStringBuf{request.GetPathInfo()}.RNextTok('/');
+ auto& out = request.Output();
+
+ if (!formatStr.empty()) {
+ IMetricEncoderPtr encoder;
+ TString resp;
+
+ if (formatStr == TStringBuf("json")) {
+ resp = HTTPOKJSON;
+ encoder = NMonitoring::EncoderJson(&out);
+ } else if (formatStr == TStringBuf("spack")) {
+ resp = HTTPOKSPACK;
+ const auto compression = ParseCompression(request);
+ encoder = NMonitoring::EncoderSpackV1(&out, ETimePrecision::SECONDS, compression);
+ } else if (formatStr == TStringBuf("prometheus")) {
+ resp = HTTPOKPROMETHEUS;
+ encoder = NMonitoring::EncoderPrometheus(&out);
+ } else {
+ ythrow yexception() << "unsupported metric encoding format: " << formatStr;
+ }
+
+ out.Write(resp);
+ RegistryRawPtr_->Accept(TInstant::Zero(), encoder.Get());
+
+ encoder->Close();
+ } else {
+ THtmlMonPage::Output(request);
+ }
+ }
+
+ void TMetricRegistryPage::OutputText(IOutputStream& out, NMonitoring::IMonHttpRequest&) {
+ IMetricEncoderPtr encoder = NMonitoring::EncoderText(&out);
+ RegistryRawPtr_->Accept(TInstant::Zero(), encoder.Get());
+ }
+
+}
diff --git a/library/cpp/monlib/service/pages/registry_mon_page.h b/library/cpp/monlib/service/pages/registry_mon_page.h
new file mode 100644
index 0000000000..2d26d3319c
--- /dev/null
+++ b/library/cpp/monlib/service/pages/registry_mon_page.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "pre_mon_page.h"
+
+#include <library/cpp/monlib/metrics/metric_registry.h>
+
+namespace NMonitoring {
+ // For now this class can only enumerate all metrics without any grouping or serve JSON/Spack/Prometheus
+ class TMetricRegistryPage: public TPreMonPage {
+ public:
+ TMetricRegistryPage(const TString& path, const TString& title, TAtomicSharedPtr<IMetricSupplier> registry)
+ : TPreMonPage(path, title)
+ , Registry_(registry)
+ , RegistryRawPtr_(Registry_.Get())
+ {
+ }
+
+ TMetricRegistryPage(const TString& path, const TString& title, IMetricSupplier* registry)
+ : TPreMonPage(path, title)
+ , RegistryRawPtr_(registry)
+ {
+ }
+
+ void Output(NMonitoring::IMonHttpRequest& request) override;
+ void OutputText(IOutputStream& out, NMonitoring::IMonHttpRequest&) override;
+
+ private:
+ TAtomicSharedPtr<IMetricSupplier> Registry_;
+ IMetricSupplier* RegistryRawPtr_;
+ };
+
+}
diff --git a/library/cpp/monlib/service/pages/resource_mon_page.cpp b/library/cpp/monlib/service/pages/resource_mon_page.cpp
new file mode 100644
index 0000000000..ec4ac6a1a7
--- /dev/null
+++ b/library/cpp/monlib/service/pages/resource_mon_page.cpp
@@ -0,0 +1,49 @@
+#include "resource_mon_page.h"
+
+using namespace NMonitoring;
+
+void TResourceMonPage::Output(NMonitoring::IMonHttpRequest& request) {
+ IOutputStream& out = request.Output();
+ switch (ResourceType) {
+ case TEXT:
+ out << HTTPOKTEXT;
+ break;
+ case JSON:
+ out << HTTPOKJSON;
+ break;
+ case CSS:
+ out << HTTPOKCSS;
+ break;
+ case JAVASCRIPT:
+ out << HTTPOKJAVASCRIPT;
+ break;
+ case FONT_EOT:
+ out << HTTPOKFONTEOT;
+ break;
+ case FONT_TTF:
+ out << HTTPOKFONTTTF;
+ break;
+ case FONT_WOFF:
+ out << HTTPOKFONTWOFF;
+ break;
+ case FONT_WOFF2:
+ out << HTTPOKFONTWOFF2;
+ break;
+ case PNG:
+ out << HTTPOKPNG;
+ break;
+ case SVG:
+ out << HTTPOKSVG;
+ break;
+ default:
+ out << HTTPOKBIN;
+ break;
+ }
+ out << NResource::Find(ResourceName);
+}
+
+void TResourceMonPage::NotFound(NMonitoring::IMonHttpRequest& request) const {
+ IOutputStream& out = request.Output();
+ out << HTTPNOTFOUND;
+ out.Flush();
+}
diff --git a/library/cpp/monlib/service/pages/resource_mon_page.h b/library/cpp/monlib/service/pages/resource_mon_page.h
new file mode 100644
index 0000000000..f6ab67200e
--- /dev/null
+++ b/library/cpp/monlib/service/pages/resource_mon_page.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include "mon_page.h"
+
+#include <library/cpp/resource/resource.h>
+
+namespace NMonitoring {
+ struct TResourceMonPage: public IMonPage {
+ public:
+ enum EResourceType {
+ BINARY,
+ TEXT,
+ JSON,
+ CSS,
+ JAVASCRIPT,
+
+ FONT_EOT,
+ FONT_TTF,
+ FONT_WOFF,
+ FONT_WOFF2,
+
+ PNG,
+ SVG
+ };
+
+ TResourceMonPage(const TString& path, const TString& resourceName,
+ const EResourceType& resourceType = BINARY)
+ : IMonPage(path, "")
+ , ResourceName(resourceName)
+ , ResourceType(resourceType)
+ {
+ }
+
+ void Output(NMonitoring::IMonHttpRequest& request) override;
+
+ void NotFound(NMonitoring::IMonHttpRequest& request) const;
+
+ private:
+ TString ResourceName;
+ EResourceType ResourceType;
+ };
+
+}
diff --git a/library/cpp/monlib/service/pages/tablesorter/css_mon_page.h b/library/cpp/monlib/service/pages/tablesorter/css_mon_page.h
new file mode 100644
index 0000000000..c2c8330089
--- /dev/null
+++ b/library/cpp/monlib/service/pages/tablesorter/css_mon_page.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <library/cpp/monlib/service/pages/resource_mon_page.h>
+
+namespace NMonitoring {
+ struct TTablesorterCssMonPage: public TResourceMonPage {
+ TTablesorterCssMonPage()
+ : TResourceMonPage("jquery.tablesorter.css", "jquery.tablesorter.css", CSS)
+ {
+ }
+ };
+
+}
diff --git a/library/cpp/monlib/service/pages/tablesorter/js_mon_page.h b/library/cpp/monlib/service/pages/tablesorter/js_mon_page.h
new file mode 100644
index 0000000000..f8a1d8254e
--- /dev/null
+++ b/library/cpp/monlib/service/pages/tablesorter/js_mon_page.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <library/cpp/monlib/service/pages/resource_mon_page.h>
+
+namespace NMonitoring {
+ struct TTablesorterJsMonPage: public TResourceMonPage {
+ TTablesorterJsMonPage()
+ : TResourceMonPage("jquery.tablesorter.js", "jquery.tablesorter.js", JAVASCRIPT)
+ {
+ }
+ };
+
+}
diff --git a/library/cpp/monlib/service/pages/tablesorter/resources/jquery.tablesorter.css b/library/cpp/monlib/service/pages/tablesorter/resources/jquery.tablesorter.css
new file mode 100644
index 0000000000..1e57adfeb3
--- /dev/null
+++ b/library/cpp/monlib/service/pages/tablesorter/resources/jquery.tablesorter.css
@@ -0,0 +1,2 @@
+/* theme.bootstrap.css v2.22.3 */ .tablesorter-bootstrap{width:100%}.tablesorter-bootstrap tfoot td,.tablesorter-bootstrap tfoot th,.tablesorter-bootstrap thead td,.tablesorter-bootstrap thead th{font:14px/20px Arial,Sans-serif;font-weight:700;padding:4px;margin:0 0 18px;background-color:#eee}.tablesorter-bootstrap .tablesorter-header{cursor:pointer}.tablesorter-bootstrap .tablesorter-header-inner{position:relative;padding:4px 18px 4px 4px}.tablesorter-bootstrap .tablesorter-header i.tablesorter-icon{font-size:11px;position:absolute;right:2px;top:50%;margin-top:-7px;width:14px;height:14px;background-repeat:no-repeat;line-height:14px;display:inline-block}.tablesorter-bootstrap .bootstrap-icon-unsorted{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAMAAADOvxanAAAAVFBMVEUAAABCQkJZWVkZGRnJyckgICAZGRkZGRn8/PweHh4dHR0aGhoaGhpUVFQbGxvQ0NDc3NxMTExSUlIbGxvr6+s4ODhKSkogICAtLS00NDQzMzMnJydSEPrQAAAAGHRSTlMA1ssZRLgdAQbDyisqsZo8QdXUq0r9xPepSRwiAAAAX0lEQVQI13XHSQKAIAwEwQAKxn13Ev7/T2Pu9qmarJKPXIicI4PH4hxaKNrhm2S8bJK5h4YzKHrzJNtK6yYT/TdXzpS5zuYg4MSQYF6i4IHExdw1UVRi05HPrrvT53a+qyMFC9t04gcAAAAASUVORK5CYII=)}.tablesorter-bootstrap .icon-white.bootstrap-icon-unsorted{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOBAMAAAALT/umAAAAKlBMVEUAAAD///////////////////////////////////////////////////+Gu8ovAAAADXRSTlMA4EXKBtQqvR0+sxmalc142gAAAFdJREFUCNdjYGDoamAAAjZbMxCVfvd6AgMDd+3du9UMDKx3hWSvMjBwXZww8RYDGuC53NB8h4GB8a617UUGBs7Yu3cjGRhYVO9eVQFKOskKOQApFmUgBwBZ+xXRTttNdAAAAABJRU5ErkJggg==)}.tablesorter-bootstrap>tbody>tr.odd>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.odd:hover~tr.tablesorter-hasChildRow.odd~.tablesorter-childRow.odd>td{background-color:#f9f9f9}.tablesorter-bootstrap>tbody>tr.even:hover>td,.tablesorter-bootstrap>tbody>tr.hover>td,.tablesorter-bootstrap>tbody>tr.odd:hover>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.even:hover~.tablesorter-childRow.even>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.odd:hover~.tablesorter-childRow.odd>td{background-color:#f5f5f5}.caption,.tablesorter-bootstrap>tbody>tr.even>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.even:hover~tr.tablesorter-hasChildRow.even~.tablesorter-childRow.even>td{background-color:#fff}.tablesorter-bootstrap .tablesorter-processing{background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=);background-position:center center!important;background-repeat:no-repeat!important}.tablesorter-bootstrap .tablesorter-filter-row input.tablesorter-filter,.tablesorter-bootstrap .tablesorter-filter-row select.tablesorter-filter{width:98%;margin:0;padding:4px 6px;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row .tablesorter-filter.disabled{background-color:#eee;color:#555;cursor:not-allowed;border:1px solid #ccc;border-radius:4px;box-shadow:0 1px 1px rgba(0,0,0,.075) inset;box-sizing:border-box;transition:height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row{background-color:#efefef}.tablesorter-bootstrap .tablesorter-filter-row td{background-color:#efefef;line-height:normal;text-align:center;padding:4px 6px;vertical-align:middle;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0}.tablesorter-bootstrap .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter .filtered{display:none}.tablesorter-bootstrap .tablesorter-pager select{padding:4px 6px}.tablesorter-bootstrap .tablesorter-pager .pagedisplay{border:0}.tablesorter-bootstrap tfoot i{font-size:11px}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
+/* colored table cells */ .table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5!important}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8!important;color:#468847!important}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6!important;color:#356635!important}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede!important;color:#b94a48!important}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc!important;color:#953b39!important}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3!important;color:#c09853!important}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc!important;color:#a47e3c!important}
diff --git a/library/cpp/monlib/service/pages/tablesorter/resources/jquery.tablesorter.js b/library/cpp/monlib/service/pages/tablesorter/resources/jquery.tablesorter.js
new file mode 100644
index 0000000000..3001b4b833
--- /dev/null
+++ b/library/cpp/monlib/service/pages/tablesorter/resources/jquery.tablesorter.js
@@ -0,0 +1,3 @@
+/* jquery.tablesorter.js v2.22.3 */ !function(e){"use strict";e.extend({tablesorter:new function(){function t(){var e=arguments[0],t=arguments.length>1?Array.prototype.slice.call(arguments):e;"undefined"!=typeof console&&"undefined"!=typeof console.log?console[/error/i.test(e)?"error":/warn/i.test(e)?"warn":"log"](t):alert(t)}function r(e,r){t(e+" ("+((new Date).getTime()-r.getTime())+"ms)")}function s(e){for(var t in e)return!1;return!0}function a(r,s,a,n){for(var o,i,d=v.parsers.length,c=!1,l="",p=!0;""===l&&p;)a++,s[a]?(c=s[a].cells[n],l=v.getElementText(r,c,n),i=e(c),r.debug&&t("Checking if value was empty on row "+a+", column: "+n+': "'+l+'"')):p=!1;for(;--d>=0;)if(o=v.parsers[d],o&&"text"!==o.id&&o.is&&o.is(l,r.table,c,i))return o;return v.getParserById("text")}function n(e,s){var n,o,i,d,c,l,p,u,g,f,h,m,b=e.table,y=0,w="";if(e.$tbodies=e.$table.children("tbody:not(."+e.cssInfoBlock+")"),h="undefined"==typeof s?e.$tbodies:s,m=h.length,0===m)return e.debug?t("Warning: *Empty table!* Not building a parser cache"):"";for(e.debug&&(f=new Date,t("Detecting parsers for each column")),o={extractors:[],parsers:[]};m>y;){if(n=h[y].rows,n.length)for(i=e.columns,d=0;i>d;d++)c=e.$headerIndexed[d],l=v.getColumnData(b,e.headers,d),g=v.getParserById(v.getData(c,l,"extractor")),u=v.getParserById(v.getData(c,l,"sorter")),p="false"===v.getData(c,l,"parser"),e.empties[d]=(v.getData(c,l,"empty")||e.emptyTo||(e.emptyToBottom?"bottom":"top")).toLowerCase(),e.strings[d]=(v.getData(c,l,"string")||e.stringTo||"max").toLowerCase(),p&&(u=v.getParserById("no-parser")),g||(g=!1),u||(u=a(e,n,-1,d)),e.debug&&(w+="column:"+d+"; extractor:"+g.id+"; parser:"+u.id+"; string:"+e.strings[d]+"; empty: "+e.empties[d]+"\n"),o.parsers[d]=u,o.extractors[d]=g;y+=o.parsers.length?m:1}e.debug&&(t(w?w:"No parsers detected"),r("Completed detecting parsers",f)),e.parsers=o.parsers,e.extractors=o.extractors}function o(s,a){var n,o,i,d,c,l,p,u,g,f,h,m,b,y,w=s.config,x=w.parsers;if(w.$tbodies=w.$table.children("tbody:not(."+w.cssInfoBlock+")"),p="undefined"==typeof a?w.$tbodies:a,w.cache={},w.totalRows=0,!x)return w.debug?t("Warning: *Empty table!* Not building a cache"):"";for(w.debug&&(f=new Date),w.showProcessing&&v.isProcessing(s,!0),l=0;l<p.length;l++){for(y=[],n=w.cache[l]={normalized:[]},h=p[l]&&p[l].rows.length||0,d=0;h>d;++d)if(m={child:[],raw:[]},u=e(p[l].rows[d]),g=[],u.hasClass(w.cssChildRow)&&0!==d)for(o=n.normalized.length-1,b=n.normalized[o][w.columns],b.$row=b.$row.add(u),u.prev().hasClass(w.cssChildRow)||u.prev().addClass(v.css.cssHasChild),i=u.children("th, td"),o=b.child.length,b.child[o]=[],c=0;c<w.columns;c++)b.child[o][c]=v.getParsedText(w,i[c],c);else{for(m.$row=u,m.order=d,c=0;c<w.columns;++c)"undefined"!=typeof x[c]?(o=v.getElementText(w,u[0].cells[c],c),m.raw.push(o),i=v.getParsedText(w,u[0].cells[c],c,o),g.push(i),"numeric"===(x[c].type||"").toLowerCase()&&(y[c]=Math.max(Math.abs(i)||0,y[c]||0))):w.debug&&t("No parser found for cell:",u[0].cells[c],"does it have a header?");g[w.columns]=m,n.normalized.push(g)}n.colMax=y,w.totalRows+=n.normalized.length}w.showProcessing&&v.isProcessing(s),w.debug&&r("Building cache for "+h+" rows",f)}function i(e,t){var a,n,o,i,d,c,l,p=e.config,u=p.widgetOptions,g=p.$tbodies,f=[],h=p.cache;if(s(h))return p.appender?p.appender(e,f):e.isUpdating?p.$table.trigger("updateComplete",e):"";for(p.debug&&(l=new Date),c=0;c<g.length;c++)if(o=g.eq(c),o.length){for(i=v.processTbody(e,o,!0),a=h[c].normalized,n=a.length,d=0;n>d;d++)f.push(a[d][p.columns].$row),p.appender&&(!p.pager||p.pager.removeRows&&u.pager_removeRows||p.pager.ajax)||i.append(a[d][p.columns].$row);v.processTbody(e,i,!1)}p.appender&&p.appender(e,f),p.debug&&r("Rebuilt table",l),t||p.appender||v.applyWidget(e),e.isUpdating&&p.$table.trigger("updateComplete",e)}function d(e){return/^d/i.test(e)||1===e}function c(s){var a,n,o,i,c,l,u,g,f=s.config;for(f.headerList=[],f.headerContent=[],f.debug&&(u=new Date),f.columns=v.computeColumnIndex(f.$table.children("thead, tfoot").children("tr")),i=f.cssIcon?'<i class="'+(f.cssIcon===v.css.icon?v.css.icon:f.cssIcon+" "+v.css.icon)+'"></i>':"",f.$headers=e(e.map(e(s).find(f.selectorHeaders),function(t,r){return n=e(t),n.parent().hasClass(f.cssIgnoreRow)?void 0:(a=v.getColumnData(s,f.headers,r,!0),f.headerContent[r]=n.html(),""===f.headerTemplate||n.find("."+v.css.headerIn).length||(c=f.headerTemplate.replace(/\{content\}/g,n.html()).replace(/\{icon\}/g,n.find("."+v.css.icon).length?"":i),f.onRenderTemplate&&(o=f.onRenderTemplate.apply(n,[r,c]),o&&"string"==typeof o&&(c=o)),n.html('<div class="'+v.css.headerIn+'">'+c+"</div>")),f.onRenderHeader&&f.onRenderHeader.apply(n,[r,f,f.$table]),t.column=parseInt(n.attr("data-column"),10),t.order=d(v.getData(n,a,"sortInitialOrder")||f.sortInitialOrder)?[1,0,2]:[0,1,2],t.count=-1,t.lockedOrder=!1,l=v.getData(n,a,"lockedOrder")||!1,"undefined"!=typeof l&&l!==!1&&(t.order=t.lockedOrder=d(l)?[1,1,1]:[0,0,0]),n.addClass(v.css.header+" "+f.cssHeader),f.headerList[r]=t,n.parent().addClass(v.css.headerRow+" "+f.cssHeaderRow).attr("role","row"),f.tabIndex&&n.attr("tabindex",0),t)})),f.$headerIndexed=[],g=0;g<f.columns;g++)n=f.$headers.filter('[data-column="'+g+'"]'),f.$headerIndexed[g]=n.not(".sorter-false").length?n.not(".sorter-false").filter(":last"):n.filter(":last");e(s).find(f.selectorHeaders).attr({scope:"col",role:"columnheader"}),p(s),f.debug&&(r("Built headers:",u),t(f.$headers))}function l(e,t,r){var s=e.config;s.$table.find(s.selectorRemove).remove(),n(s),o(e),y(s,t,r)}function p(e){var t,r,s,a,n=e.config,o=n.$headers.length;for(t=0;o>t;t++)s=n.$headers.eq(t),a=v.getColumnData(e,n.headers,t,!0),r="false"===v.getData(s,a,"sorter")||"false"===v.getData(s,a,"parser"),s[0].sortDisabled=r,s[r?"addClass":"removeClass"]("sorter-false").attr("aria-disabled",""+r),e.id&&(r?s.removeAttr("aria-controls"):s.attr("aria-controls",e.id))}function u(t){var r,s,a,n,o,i,d,c,l=t.config,p=l.sortList,u=p.length,g=v.css.sortNone+" "+l.cssNone,f=[v.css.sortAsc+" "+l.cssAsc,v.css.sortDesc+" "+l.cssDesc],h=[l.cssIconAsc,l.cssIconDesc,l.cssIconNone],m=["ascending","descending"],b=e(t).find("tfoot tr").children().add(e(l.namespace+"_extra_headers")).removeClass(f.join(" "));for(l.$headers.removeClass(f.join(" ")).addClass(g).attr("aria-sort","none").find("."+v.css.icon).removeClass(h.join(" ")).addClass(h[2]),a=0;u>a;a++)if(2!==p[a][1]&&(r=l.$headers.not(".sorter-false").filter('[data-column="'+p[a][0]+'"]'+(1===u?":last":"")),r.length)){for(n=0;n<r.length;n++)r[n].sortDisabled||r.eq(n).removeClass(g).addClass(f[p[a][1]]).attr("aria-sort",m[p[a][1]]).find("."+v.css.icon).removeClass(h[2]).addClass(h[p[a][1]]);b.length&&b.filter('[data-column="'+p[a][0]+'"]').removeClass(g).addClass(f[p[a][1]])}for(u=l.$headers.length,o=l.$headers.not(".sorter-false"),a=0;u>a;a++)i=o.eq(a),i.length&&(s=o[a],d=s.order[(s.count+1)%(l.sortReset?3:2)],c=e.trim(i.text())+": "+v.language[i.hasClass(v.css.sortAsc)?"sortAsc":i.hasClass(v.css.sortDesc)?"sortDesc":"sortNone"]+v.language[0===d?"nextAsc":1===d?"nextDesc":"nextNone"],i.attr("aria-label",c))}function g(t,r){var s,a,n,o,i,d,c,l,p=t.config,u=r||p.sortList,g=u.length;for(p.sortList=[],i=0;g>i;i++)if(l=u[i],s=parseInt(l[0],10),s<p.columns&&p.$headerIndexed[s]){switch(o=p.$headerIndexed[s][0],a=(""+l[1]).match(/^(1|d|s|o|n)/),a=a?a[0]:""){case"1":case"d":a=1;break;case"s":a=d||0;break;case"o":c=o.order[(d||0)%(p.sortReset?3:2)],a=0===c?1:1===c?0:2;break;case"n":o.count=o.count+1,a=o.order[o.count%(p.sortReset?3:2)];break;default:a=0}d=0===i?a:d,n=[s,parseInt(a,10)||0],p.sortList.push(n),a=e.inArray(n[1],o.order),o.count=a>=0?a:n[1]%(p.sortReset?3:2)}}function f(e,t){return e&&e[t]?e[t].type||"":""}function h(t,r,s){if(t.isUpdating)return setTimeout(function(){h(t,r,s)},50);var a,n,o,d,c,l,p,g=t.config,f=!s[g.sortMultiSortKey],b=g.$table,y=g.$headers.length;if(b.trigger("sortStart",t),r.count=s[g.sortResetKey]?2:(r.count+1)%(g.sortReset?3:2),g.sortRestart)for(n=r,o=0;y>o;o++)p=g.$headers.eq(o),p[0]===n||!f&&p.is("."+v.css.sortDesc+",."+v.css.sortAsc)||(p[0].count=-1);if(n=parseInt(e(r).attr("data-column"),10),f){if(g.sortList=[],null!==g.sortForce)for(a=g.sortForce,d=0;d<a.length;d++)a[d][0]!==n&&g.sortList.push(a[d]);if(c=r.order[r.count],2>c&&(g.sortList.push([n,c]),r.colSpan>1))for(d=1;d<r.colSpan;d++)g.sortList.push([n+d,c])}else{if(g.sortAppend&&g.sortList.length>1)for(d=0;d<g.sortAppend.length;d++)l=v.isValueInArray(g.sortAppend[d][0],g.sortList),l>=0&&g.sortList.splice(l,1);if(v.isValueInArray(n,g.sortList)>=0)for(d=0;d<g.sortList.length;d++)l=g.sortList[d],c=g.$headerIndexed[l[0]][0],l[0]===n&&(l[1]=c.order[r.count],2===l[1]&&(g.sortList.splice(d,1),c.count=-1));else if(c=r.order[r.count],2>c&&(g.sortList.push([n,c]),r.colSpan>1))for(d=1;d<r.colSpan;d++)g.sortList.push([n+d,c])}if(null!==g.sortAppend)for(a=g.sortAppend,d=0;d<a.length;d++)a[d][0]!==n&&g.sortList.push(a[d]);b.trigger("sortBegin",t),setTimeout(function(){u(t),m(t),i(t),b.trigger("sortEnd",t)},1)}function m(e){var t,a,n,o,i,d,c,l,p,u,g,h=0,m=e.config,b=m.textSorter||"",y=m.sortList,w=y.length,x=m.$tbodies.length;if(!m.serverSideSorting&&!s(m.cache)){for(m.debug&&(i=new Date),a=0;x>a;a++)d=m.cache[a].colMax,c=m.cache[a].normalized,c.sort(function(r,s){for(t=0;w>t;t++){if(o=y[t][0],l=y[t][1],h=0===l,m.sortStable&&r[o]===s[o]&&1===w)return r[m.columns].order-s[m.columns].order;if(n=/n/i.test(f(m.parsers,o)),n&&m.strings[o]?(n="boolean"==typeof m.string[m.strings[o]]?(h?1:-1)*(m.string[m.strings[o]]?-1:1):m.strings[o]?m.string[m.strings[o]]||0:0,p=m.numberSorter?m.numberSorter(r[o],s[o],h,d[o],e):v["sortNumeric"+(h?"Asc":"Desc")](r[o],s[o],n,d[o],o,e)):(u=h?r:s,g=h?s:r,p="function"==typeof b?b(u[o],g[o],h,o,e):"object"==typeof b&&b.hasOwnProperty(o)?b[o](u[o],g[o],h,o,e):v["sortNatural"+(h?"Asc":"Desc")](r[o],s[o],o,e,m)),p)return p}return r[m.columns].order-s[m.columns].order});m.debug&&r("Sorting on "+y.toString()+" and dir "+l+" time",i)}}function b(t,r){t.table.isUpdating&&t.$table.trigger("updateComplete",t.table),e.isFunction(r)&&r(t.table)}function y(t,r,s){var a=e.isArray(r)?r:t.sortList,n="undefined"==typeof r?t.resort:r;n===!1||t.serverSideSorting||t.table.isProcessing?(b(t,s),v.applyWidget(t.table,!1)):a.length?t.$table.trigger("sorton",[a,function(){b(t,s)},!0]):t.$table.trigger("sortReset",[function(){b(t,s),v.applyWidget(t.table,!1)}])}function w(t){var r=t.config,a=r.$table,d="sortReset update updateRows updateCell updateAll addRows updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ".split(" ").join(r.namespace+" ");a.unbind(d.replace(/\s+/g," ")).bind("sortReset"+r.namespace,function(s,a){s.stopPropagation(),r.sortList=[],u(t),m(t),i(t),e.isFunction(a)&&a(t)}).bind("updateAll"+r.namespace,function(e,s,a){e.stopPropagation(),t.isUpdating=!0,v.refreshWidgets(t,!0,!0),c(t),v.bindEvents(t,r.$headers,!0),w(t),l(t,s,a)}).bind("update"+r.namespace+" updateRows"+r.namespace,function(e,r,s){e.stopPropagation(),t.isUpdating=!0,p(t),l(t,r,s)}).bind("updateCell"+r.namespace,function(s,n,o,i){s.stopPropagation(),t.isUpdating=!0,a.find(r.selectorRemove).remove();var d,c,l,p,u=r.$tbodies,g=e(n),f=u.index(e.fn.closest?g.closest("tbody"):g.parents("tbody").filter(":first")),h=r.cache[f],m=e.fn.closest?g.closest("tr"):g.parents("tr").filter(":first");n=g[0],u.length&&f>=0&&(c=u.eq(f).find("tr").index(m),p=h.normalized[c],l=g.index(),d=v.getParsedText(r,n,l),p[l]=d,p[r.columns].$row=m,"numeric"===(r.parsers[l].type||"").toLowerCase()&&(h.colMax[l]=Math.max(Math.abs(d)||0,h.colMax[l]||0)),d="undefined"!==o?o:r.resort,d!==!1?y(r,d,i):(e.isFunction(i)&&i(t),r.$table.trigger("updateComplete",r.table)))}).bind("addRows"+r.namespace,function(a,o,i,d){if(a.stopPropagation(),t.isUpdating=!0,s(r.cache))p(t),l(t,i,d);else{o=e(o).attr("role","row");var c,u,g,f,h,m=o.filter("tr").length,b=r.$tbodies.index(o.parents("tbody").filter(":first"));for(r.parsers&&r.parsers.length||n(r),c=0;m>c;c++){for(g=o[c].cells.length,h=[],f={child:[],$row:o.eq(c),order:r.cache[b].normalized.length},u=0;g>u;u++)h[u]=v.getParsedText(r,o[c].cells[u],u),"numeric"===(r.parsers[u].type||"").toLowerCase()&&(r.cache[b].colMax[u]=Math.max(Math.abs(h[u])||0,r.cache[b].colMax[u]||0));h.push(f),r.cache[b].normalized.push(h)}y(r,i,d)}}).bind("updateComplete"+r.namespace,function(){t.isUpdating=!1}).bind("sorton"+r.namespace,function(r,n,d,c){var l=t.config;r.stopPropagation(),a.trigger("sortStart",this),g(t,n),u(t),l.delayInit&&s(l.cache)&&o(t),a.trigger("sortBegin",this),m(t),i(t,c),a.trigger("sortEnd",this),v.applyWidget(t),e.isFunction(d)&&d(t)}).bind("appendCache"+r.namespace,function(r,s,a){r.stopPropagation(),i(t,a),e.isFunction(s)&&s(t)}).bind("updateCache"+r.namespace,function(s,a,i){r.parsers&&r.parsers.length||n(r,i),o(t,i),e.isFunction(a)&&a(t)}).bind("applyWidgetId"+r.namespace,function(e,s){e.stopPropagation(),v.getWidgetById(s).format(t,r,r.widgetOptions)}).bind("applyWidgets"+r.namespace,function(e,r){e.stopPropagation(),v.applyWidget(t,r)}).bind("refreshWidgets"+r.namespace,function(e,r,s){e.stopPropagation(),v.refreshWidgets(t,r,s)}).bind("destroy"+r.namespace,function(e,r,s){e.stopPropagation(),v.destroy(t,r,s)}).bind("resetToLoadState"+r.namespace,function(){v.removeWidget(t,!0,!1),r=e.extend(!0,v.defaults,r.originalSettings),t.hasInitialized=!1,v.setup(t,r)})}var v=this;v.version="2.22.3",v.parsers=[],v.widgets=[],v.defaults={theme:"default",widthFixed:!1,showProcessing:!1,headerTemplate:"{content}",onRenderTemplate:null,onRenderHeader:null,cancelSelection:!0,tabIndex:!0,dateFormat:"mmddyyyy",sortMultiSortKey:"shiftKey",sortResetKey:"ctrlKey",usNumberFormat:!0,delayInit:!1,serverSideSorting:!1,resort:!0,headers:{},ignoreCase:!0,sortForce:null,sortList:[],sortAppend:null,sortStable:!1,sortInitialOrder:"asc",sortLocaleCompare:!1,sortReset:!1,sortRestart:!1,emptyTo:"bottom",stringTo:"max",textExtraction:"basic",textAttribute:"data-text",textSorter:null,numberSorter:null,widgets:[],widgetOptions:{zebra:["even","odd"]},initWidgets:!0,widgetClass:"widget-{name}",initialized:null,tableClass:"",cssAsc:"",cssDesc:"",cssNone:"",cssHeader:"",cssHeaderRow:"",cssProcessing:"",cssChildRow:"tablesorter-childRow",cssIcon:"tablesorter-icon",cssIconNone:"",cssIconAsc:"",cssIconDesc:"",cssInfoBlock:"tablesorter-infoOnly",cssNoSort:"tablesorter-noSort",cssIgnoreRow:"tablesorter-ignoreRow",pointerClick:"click",pointerDown:"mousedown",pointerUp:"mouseup",selectorHeaders:"> thead th, > thead td",selectorSort:"th, td",selectorRemove:".remove-me",debug:!1,headerList:[],empties:{},strings:{},parsers:[]},v.css={table:"tablesorter",cssHasChild:"tablesorter-hasChildRow",childRow:"tablesorter-childRow",colgroup:"tablesorter-colgroup",header:"tablesorter-header",headerRow:"tablesorter-headerRow",headerIn:"tablesorter-header-inner",icon:"tablesorter-icon",processing:"tablesorter-processing",sortAsc:"tablesorter-headerAsc",sortDesc:"tablesorter-headerDesc",sortNone:"tablesorter-headerUnSorted"},v.language={sortAsc:"Ascending sort applied, ",sortDesc:"Descending sort applied, ",sortNone:"No sort applied, ",nextAsc:"activate to apply an ascending sort",nextDesc:"activate to apply a descending sort",nextNone:"activate to remove the sort"},v.instanceMethods={},v.log=t,v.benchmark=r,v.getElementText=function(t,r,s){if(!r)return"";var a,n=t.textExtraction||"",o=r.jquery?r:e(r);return e.trim("string"==typeof n?"basic"===n&&"undefined"!=typeof(a=o.attr(t.textAttribute))?a:r.textContent||o.text():"function"==typeof n?n(o[0],t.table,s):"function"==typeof(a=v.getColumnData(t.table,n,s))?a(o[0],t.table,s):o[0].textContent||o.text())},v.getParsedText=function(e,t,r,s){"undefined"==typeof s&&(s=v.getElementText(e,t,r));var a=""+s,n=e.parsers[r],o=e.extractors[r];return n&&(o&&"function"==typeof o.format&&(s=o.format(s,e.table,t,r)),a="no-parser"===n.id?"":n.format(""+s,e.table,t,r),e.ignoreCase&&"string"==typeof a&&(a=a.toLowerCase())),a},v.construct=function(t){return this.each(function(){var r=this,s=e.extend(!0,{},v.defaults,t,v.instanceMethods);s.originalSettings=t,!r.hasInitialized&&v.buildTable&&"TABLE"!==this.nodeName?v.buildTable(r,s):v.setup(r,s)})},v.setup=function(r,s){if(!r||!r.tHead||0===r.tBodies.length||r.hasInitialized===!0)return s.debug?t("ERROR: stopping initialization! No table, thead, tbody or tablesorter has already been initialized"):"";var a="",i=e(r),d=e.metadata;r.hasInitialized=!1,r.isProcessing=!0,r.config=s,e.data(r,"tablesorter",s),s.debug&&e.data(r,"startoveralltimer",new Date),s.supportsDataObject=function(e){return e[0]=parseInt(e[0],10),e[0]>1||1===e[0]&&parseInt(e[1],10)>=4}(e.fn.jquery.split(".")),s.string={max:1,min:-1,emptymin:1,emptymax:-1,zero:0,none:0,"null":0,top:!0,bottom:!1},s.emptyTo=s.emptyTo.toLowerCase(),s.stringTo=s.stringTo.toLowerCase(),/tablesorter\-/.test(i.attr("class"))||(a=""!==s.theme?" tablesorter-"+s.theme:""),s.table=r,s.$table=i.addClass(v.css.table+" "+s.tableClass+a).attr("role","grid"),s.$headers=i.find(s.selectorHeaders),s.namespace=s.namespace?"."+s.namespace.replace(/\W/g,""):".tablesorter"+Math.random().toString(16).slice(2),s.$table.children().children("tr").attr("role","row"),s.$tbodies=i.children("tbody:not(."+s.cssInfoBlock+")").attr({"aria-live":"polite","aria-relevant":"all"}),s.$table.children("caption").length&&(a=s.$table.children("caption")[0],a.id||(a.id=s.namespace.slice(1)+"caption"),s.$table.attr("aria-labelledby",a.id)),s.widgetInit={},s.textExtraction=s.$table.attr("data-text-extraction")||s.textExtraction||"basic",c(r),v.fixColumnWidth(r),v.applyWidgetOptions(r,s),n(s),s.totalRows=0,s.delayInit||o(r),v.bindEvents(r,s.$headers,!0),w(r),s.supportsDataObject&&"undefined"!=typeof i.data().sortlist?s.sortList=i.data().sortlist:d&&i.metadata()&&i.metadata().sortlist&&(s.sortList=i.metadata().sortlist),v.applyWidget(r,!0),s.sortList.length>0?i.trigger("sorton",[s.sortList,{},!s.initWidgets,!0]):(u(r),s.initWidgets&&v.applyWidget(r,!1)),s.showProcessing&&i.unbind("sortBegin"+s.namespace+" sortEnd"+s.namespace).bind("sortBegin"+s.namespace+" sortEnd"+s.namespace,function(e){clearTimeout(s.processTimer),v.isProcessing(r),"sortBegin"===e.type&&(s.processTimer=setTimeout(function(){v.isProcessing(r,!0)},500))}),r.hasInitialized=!0,r.isProcessing=!1,s.debug&&v.benchmark("Overall initialization time",e.data(r,"startoveralltimer")),i.trigger("tablesorter-initialized",r),"function"==typeof s.initialized&&s.initialized(r)},v.fixColumnWidth=function(t){t=e(t)[0];var r,s,a,n,o,i=t.config,d=i.$table.children("colgroup");if(d.length&&d.hasClass(v.css.colgroup)&&d.remove(),i.widthFixed&&0===i.$table.children("colgroup").length){for(d=e('<colgroup class="'+v.css.colgroup+'">'),r=i.$table.width(),a=i.$tbodies.find("tr:first").children(":visible"),n=a.length,o=0;n>o;o++)s=parseInt(a.eq(o).width()/r*1e3,10)/10+"%",d.append(e("<col>").css("width",s));i.$table.prepend(d)}},v.getColumnData=function(t,r,s,a,n){if("undefined"!=typeof r&&null!==r){t=e(t)[0];var o,i,d=t.config,c=n||d.$headers,l=d.$headerIndexed&&d.$headerIndexed[s]||c.filter('[data-column="'+s+'"]:last');if(r[s])return a?r[s]:r[c.index(l)];for(i in r)if("string"==typeof i&&(o=l.filter(i).add(l.find(i)),o.length))return r[i]}},v.computeColumnIndex=function(t){var r,s,a,n,o,i,d,c,l,p,u,g,f=[],h=[],m={};for(r=0;r<t.length;r++)for(d=t[r].cells,s=0;s<d.length;s++){for(i=d[s],o=e(i),c=i.parentNode.rowIndex,l=c+"-"+o.index(),p=i.rowSpan||1,u=i.colSpan||1,"undefined"==typeof f[c]&&(f[c]=[]),a=0;a<f[c].length+1;a++)if("undefined"==typeof f[c][a]){g=a;break}for(m[l]=g,o.attr({"data-column":g}),a=c;c+p>a;a++)for("undefined"==typeof f[a]&&(f[a]=[]),h=f[a],n=g;g+u>n;n++)h[n]="x"}return h.length},v.isProcessing=function(t,r,s){t=e(t);var a=t[0].config,n=s||t.find("."+v.css.header);r?("undefined"!=typeof s&&a.sortList.length>0&&(n=n.filter(function(){return this.sortDisabled?!1:v.isValueInArray(parseFloat(e(this).attr("data-column")),a.sortList)>=0})),t.add(n).addClass(v.css.processing+" "+a.cssProcessing)):t.add(n).removeClass(v.css.processing+" "+a.cssProcessing)},v.processTbody=function(t,r,s){t=e(t)[0];var a;return s?(t.isProcessing=!0,r.before('<span class="tablesorter-savemyplace"/>'),a=e.fn.detach?r.detach():r.remove()):(a=e(t).find("span.tablesorter-savemyplace"),r.insertAfter(a),a.remove(),void(t.isProcessing=!1))},v.clearTableBody=function(t){e(t)[0].config.$tbodies.children().detach()},v.bindEvents=function(t,r,a){t=e(t)[0];var n,i=null,d=t.config;a!==!0&&(r.addClass(d.namespace.slice(1)+"_extra_headers"),n=e.fn.closest?r.closest("table")[0]:r.parents("table")[0],n&&"TABLE"===n.nodeName&&n!==t&&e(n).addClass(d.namespace.slice(1)+"_extra_table")),n=(d.pointerDown+" "+d.pointerUp+" "+d.pointerClick+" sort keyup ").replace(/\s+/g," ").split(" ").join(d.namespace+" "),r.find(d.selectorSort).add(r.filter(d.selectorSort)).unbind(n).bind(n,function(a,n){var c,l,p=e(a.target),u=" "+a.type+" ";if(!(1!==(a.which||a.button)&&!u.match(" "+d.pointerClick+" | sort | keyup ")||" keyup "===u&&13!==a.which||u.match(" "+d.pointerClick+" ")&&"undefined"!=typeof a.which||u.match(" "+d.pointerUp+" ")&&i!==a.target&&n!==!0)){if(u.match(" "+d.pointerDown+" "))return i=a.target,l=p.jquery.split("."),void("1"===l[0]&&l[1]<4&&a.preventDefault());if(i=null,/(input|select|button|textarea)/i.test(a.target.nodeName)||p.hasClass(d.cssNoSort)||p.parents("."+d.cssNoSort).length>0||p.parents("button").length>0)return!d.cancelSelection;d.delayInit&&s(d.cache)&&o(t),c=e.fn.closest?e(this).closest("th, td")[0]:/TH|TD/.test(this.nodeName)?this:e(this).parents("th, td")[0],c=d.$headers[r.index(c)],c.sortDisabled||h(t,c,a)}}),d.cancelSelection&&r.attr("unselectable","on").bind("selectstart",!1).css({"user-select":"none",MozUserSelect:"none"})},v.restoreHeaders=function(t){var r,s,a=e(t)[0].config,n=a.$table.find(a.selectorHeaders),o=n.length;for(r=0;o>r;r++)s=n.eq(r),s.find("."+v.css.headerIn).length&&s.html(a.headerContent[r])},v.destroy=function(t,r,s){if(t=e(t)[0],t.hasInitialized){v.removeWidget(t,!0,!1);var a,n=e(t),o=t.config,i=n.find("thead:first"),d=i.find("tr."+v.css.headerRow).removeClass(v.css.headerRow+" "+o.cssHeaderRow),c=n.find("tfoot:first > tr").children("th, td");r===!1&&e.inArray("uitheme",o.widgets)>=0&&(n.trigger("applyWidgetId",["uitheme"]),n.trigger("applyWidgetId",["zebra"])),i.find("tr").not(d).remove(),a="sortReset update updateAll updateRows updateCell addRows updateComplete sorton appendCache updateCache "+"applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd resetToLoadState ".split(" ").join(o.namespace+" "),n.removeData("tablesorter").unbind(a.replace(/\s+/g," ")),o.$headers.add(c).removeClass([v.css.header,o.cssHeader,o.cssAsc,o.cssDesc,v.css.sortAsc,v.css.sortDesc,v.css.sortNone].join(" ")).removeAttr("data-column").removeAttr("aria-label").attr("aria-disabled","true"),d.find(o.selectorSort).unbind("mousedown mouseup keypress ".split(" ").join(o.namespace+" ").replace(/\s+/g," ")),v.restoreHeaders(t),n.toggleClass(v.css.table+" "+o.tableClass+" tablesorter-"+o.theme,r===!1),t.hasInitialized=!1,delete t.config.cache,"function"==typeof s&&s(t)}},v.regex={chunk:/(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,chunks:/(^\\0|\\0$)/,hex:/^0x[0-9a-f]+$/i},v.sortNatural=function(e,t){if(e===t)return 0;var r,s,a,n,o,i,d,c,l=v.regex;if(l.hex.test(t)){if(s=parseInt(e.match(l.hex),16),n=parseInt(t.match(l.hex),16),n>s)return-1;if(s>n)return 1}for(r=e.replace(l.chunk,"\\0$1\\0").replace(l.chunks,"").split("\\0"),a=t.replace(l.chunk,"\\0$1\\0").replace(l.chunks,"").split("\\0"),c=Math.max(r.length,a.length),d=0;c>d;d++){if(o=isNaN(r[d])?r[d]||0:parseFloat(r[d])||0,i=isNaN(a[d])?a[d]||0:parseFloat(a[d])||0,isNaN(o)!==isNaN(i))return isNaN(o)?1:-1;if(typeof o!=typeof i&&(o+="",i+=""),i>o)return-1;if(o>i)return 1}return 0},v.sortNaturalAsc=function(e,t,r,s,a){if(e===t)return 0;var n=a.string[a.empties[r]||a.emptyTo];return""===e&&0!==n?"boolean"==typeof n?n?-1:1:-n||-1:""===t&&0!==n?"boolean"==typeof n?n?1:-1:n||1:v.sortNatural(e,t)},v.sortNaturalDesc=function(e,t,r,s,a){if(e===t)return 0;var n=a.string[a.empties[r]||a.emptyTo];return""===e&&0!==n?"boolean"==typeof n?n?-1:1:n||1:""===t&&0!==n?"boolean"==typeof n?n?1:-1:-n||-1:v.sortNatural(t,e)},v.sortText=function(e,t){return e>t?1:t>e?-1:0},v.getTextValue=function(e,t,r){if(r){var s,a=e?e.length:0,n=r+t;for(s=0;a>s;s++)n+=e.charCodeAt(s);return t*n}return 0},v.sortNumericAsc=function(e,t,r,s,a,n){if(e===t)return 0;var o=n.config,i=o.string[o.empties[a]||o.emptyTo];return""===e&&0!==i?"boolean"==typeof i?i?-1:1:-i||-1:""===t&&0!==i?"boolean"==typeof i?i?1:-1:i||1:(isNaN(e)&&(e=v.getTextValue(e,r,s)),isNaN(t)&&(t=v.getTextValue(t,r,s)),e-t)},v.sortNumericDesc=function(e,t,r,s,a,n){if(e===t)return 0;var o=n.config,i=o.string[o.empties[a]||o.emptyTo];return""===e&&0!==i?"boolean"==typeof i?i?-1:1:i||1:""===t&&0!==i?"boolean"==typeof i?i?1:-1:-i||-1:(isNaN(e)&&(e=v.getTextValue(e,r,s)),isNaN(t)&&(t=v.getTextValue(t,r,s)),t-e)},v.sortNumeric=function(e,t){return e-t},v.characterEquivalents={a:"áàâãäąå",A:"ÁÀÂÃÄĄÅ",c:"çćč",C:"ÇĆČ",e:"éèêëěę",E:"ÉÈÊËĚĘ",i:"íìİîïı",I:"ÍÌİÎÏ",o:"óòôõöō",O:"ÓÒÔÕÖŌ",ss:"ß",SS:"ẞ",u:"úùûüů",U:"ÚÙÛÜŮ"},v.replaceAccents=function(e){var t,r="[",s=v.characterEquivalents;if(!v.characterRegex){v.characterRegexArray={};for(t in s)"string"==typeof t&&(r+=s[t],v.characterRegexArray[t]=new RegExp("["+s[t]+"]","g"));v.characterRegex=new RegExp(r+"]")}if(v.characterRegex.test(e))for(t in s)"string"==typeof t&&(e=e.replace(v.characterRegexArray[t],t));return e},v.isValueInArray=function(e,t){var r,s=t.length;for(r=0;s>r;r++)if(t[r][0]===e)return r;return-1},v.addParser=function(e){var t,r=v.parsers.length,s=!0;for(t=0;r>t;t++)v.parsers[t].id.toLowerCase()===e.id.toLowerCase()&&(s=!1);s&&v.parsers.push(e)},v.addInstanceMethods=function(t){e.extend(v.instanceMethods,t)},v.getParserById=function(e){if("false"==e)return!1;var t,r=v.parsers.length;for(t=0;r>t;t++)if(v.parsers[t].id.toLowerCase()===e.toString().toLowerCase())return v.parsers[t];return!1},v.addWidget=function(e){v.widgets.push(e)},v.hasWidget=function(t,r){return t=e(t),t.length&&t[0].config&&t[0].config.widgetInit[r]||!1},v.getWidgetById=function(e){var t,r,s=v.widgets.length;for(t=0;s>t;t++)if(r=v.widgets[t],r&&r.hasOwnProperty("id")&&r.id.toLowerCase()===e.toLowerCase())return r},v.applyWidgetOptions=function(t,r){var s,a,n=r.widgets.length,o=r.widgetOptions;if(n)for(s=0;n>s;s++)a=v.getWidgetById(r.widgets[s]),a&&"options"in a&&(o=t.config.widgetOptions=e.extend(!0,{},a.options,o))},v.applyWidget=function(t,s,a){t=e(t)[0];var n,o,i,d,c,l,p,u=t.config,g=u.widgetOptions,f=" "+u.table.className+" ",h=[];if(s===!1||!t.hasInitialized||!t.isApplyingWidgets&&!t.isUpdating){if(u.debug&&(d=new Date),p=new RegExp("\\s"+u.widgetClass.replace(/\{name\}/i,"([\\w-]+)")+"\\s","g"),f.match(p)&&(l=f.match(p)))for(o=l.length,n=0;o>n;n++)u.widgets.push(l[n].replace(p,"$1"));if(u.widgets.length){for(t.isApplyingWidgets=!0,u.widgets=e.grep(u.widgets,function(t,r){return e.inArray(t,u.widgets)===r}),i=u.widgets||[],o=i.length,n=0;o>n;n++)p=v.getWidgetById(i[n]),p&&p.id&&(p.priority||(p.priority=10),h[n]=p);for(h.sort(function(e,t){return e.priority<t.priority?-1:e.priority===t.priority?0:1}),o=h.length,n=0;o>n;n++)h[n]&&((s||!u.widgetInit[h[n].id])&&(u.widgetInit[h[n].id]=!0,t.hasInitialized&&v.applyWidgetOptions(t,u),"init"in h[n]&&(u.debug&&(c=new Date),h[n].init(t,h[n],u,g),u.debug&&v.benchmark("Initializing "+h[n].id+" widget",c))),!s&&"format"in h[n]&&(u.debug&&(c=new Date),h[n].format(t,u,g,!1),u.debug&&v.benchmark((s?"Initializing ":"Applying ")+h[n].id+" widget",c)));s||"function"!=typeof a||a(t)}setTimeout(function(){t.isApplyingWidgets=!1,e.data(t,"lastWidgetApplication",new Date)},0),u.debug&&(l=u.widgets.length,r("Completed "+(s===!0?"initializing ":"applying ")+l+" widget"+(1!==l?"s":""),d))}},v.removeWidget=function(r,s,a){r=e(r)[0];var n,o,i,d,c=r.config;if(s===!0)for(s=[],d=v.widgets.length,i=0;d>i;i++)o=v.widgets[i],o&&o.id&&s.push(o.id);else s=(e.isArray(s)?s.join(","):s||"").toLowerCase().split(/[\s,]+/);for(d=s.length,n=0;d>n;n++)o=v.getWidgetById(s[n]),i=e.inArray(s[n],c.widgets),o&&"remove"in o&&(c.debug&&i>=0&&t('Removing "'+s[n]+'" widget'),o.remove(r,c,c.widgetOptions,a),c.widgetInit[s[n]]=!1),i>=0&&a!==!0&&c.widgets.splice(i,1)},v.refreshWidgets=function(t,r,s){t=e(t)[0];var a,n=t.config,o=n.widgets,i=v.widgets,d=i.length,c=[],l=function(t){e(t).trigger("refreshComplete")};for(a=0;d>a;a++)i[a]&&i[a].id&&(r||e.inArray(i[a].id,o)<0)&&c.push(i[a].id);v.removeWidget(t,c.join(","),!0),s!==!0?(v.applyWidget(t,r||!1,l),r&&v.applyWidget(t,!1,l)):l(t)},v.getColumnText=function(t,r,a){t=e(t)[0];var n,o,i,d,c,l,p,u,g,f,h="function"==typeof a,m="all"===r,b={raw:[],parsed:[],$cell:[]},y=t.config;if(!s(y)){for(c=y.$tbodies.length,n=0;c>n;n++)for(i=y.cache[n].normalized,l=i.length,o=0;l>o;o++)f=!0,d=i[o],u=m?d.slice(0,y.columns):d[r],d=d[y.columns],p=m?d.raw:d.raw[r],g=m?d.$row.children():d.$row.children().eq(r),h&&(f=a({tbodyIndex:n,rowIndex:o,parsed:u,raw:p,$row:d.$row,$cell:g})),f!==!1&&(b.parsed.push(u),b.raw.push(p),b.$cell.push(g));return b}},v.getData=function(t,r,s){var a,n,o="",i=e(t);return i.length?(a=e.metadata?i.metadata():!1,n=" "+(i.attr("class")||""),"undefined"!=typeof i.data(s)||"undefined"!=typeof i.data(s.toLowerCase())?o+=i.data(s)||i.data(s.toLowerCase()):a&&"undefined"!=typeof a[s]?o+=a[s]:r&&"undefined"!=typeof r[s]?o+=r[s]:" "!==n&&n.match(" "+s+"-")&&(o=n.match(new RegExp("\\s"+s+"-([\\w-]+)"))[1]||""),e.trim(o)):""},v.formatFloat=function(t,r){if("string"!=typeof t||""===t)return t;var s,a=r&&r.config?r.config.usNumberFormat!==!1:"undefined"!=typeof r?r:!0;return t=a?t.replace(/,/g,""):t.replace(/[\s|\.]/g,"").replace(/,/g,"."),/^\s*\([.\d]+\)/.test(t)&&(t=t.replace(/^\s*\(([.\d]+)\)/,"-$1")),s=parseFloat(t),isNaN(s)?e.trim(t):s},v.isDigit=function(e){return isNaN(e)?/^[\-+(]?\d+[)]?$/.test(e.toString().replace(/[,.'"\s]/g,"")):""!==e}}});var t=e.tablesorter;e.fn.extend({tablesorter:t.construct}),t.addParser({id:"no-parser",is:function(){return!1},format:function(){return""},type:"text"}),t.addParser({id:"text",is:function(){return!0},format:function(r,s){var a=s.config;return r&&(r=e.trim(a.ignoreCase?r.toLocaleLowerCase():r),r=a.sortLocaleCompare?t.replaceAccents(r):r),r},type:"text"}),t.addParser({id:"digit",is:function(e){return t.isDigit(e)},format:function(r,s){var a=t.formatFloat((r||"").replace(/[^\w,. \-()]/g,""),s);return r&&"number"==typeof a?a:r?e.trim(r&&s.config.ignoreCase?r.toLocaleLowerCase():r):r},type:"numeric"}),t.addParser({id:"currency",is:function(e){return/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/.test((e||"").replace(/[+\-,. ]/g,""))},format:function(r,s){var a=t.formatFloat((r||"").replace(/[^\w,. \-()]/g,""),s);return r&&"number"==typeof a?a:r?e.trim(r&&s.config.ignoreCase?r.toLocaleLowerCase():r):r},type:"numeric"}),t.addParser({id:"url",is:function(e){return/^(https?|ftp|file):\/\//.test(e)},format:function(t){return t?e.trim(t.replace(/(https?|ftp|file):\/\//,"")):t},parsed:!0,type:"text"}),t.addParser({id:"isoDate",is:function(e){return/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/.test(e)},format:function(e){var t=e?new Date(e.replace(/-/g,"/")):e;return t instanceof Date&&isFinite(t)?t.getTime():e},type:"numeric"}),t.addParser({id:"percent",is:function(e){return/(\d\s*?%|%\s*?\d)/.test(e)&&e.length<15},format:function(e,r){return e?t.formatFloat(e.replace(/%/g,""),r):e},type:"numeric"}),t.addParser({id:"image",is:function(e,t,r,s){return s.find("img").length>0},format:function(t,r,s){return e(s).find("img").attr(r.config.imgAttr||"alt")||t},parsed:!0,type:"text"}),t.addParser({id:"usLongDate",is:function(e){return/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i.test(e)||/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i.test(e)},format:function(e){var t=e?new Date(e.replace(/(\S)([AP]M)$/i,"$1 $2")):e;return t instanceof Date&&isFinite(t)?t.getTime():e
+},type:"numeric"}),t.addParser({id:"shortDate",is:function(e){return/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/.test((e||"").replace(/\s+/g," ").replace(/[\-.,]/g,"/"))},format:function(e,r,s,a){if(e){var n,o,i=r.config,d=i.$headerIndexed[a],c=d.length&&d[0].dateFormat||t.getData(d,t.getColumnData(r,i.headers,a),"dateFormat")||i.dateFormat;return o=e.replace(/\s+/g," ").replace(/[\-.,]/g,"/"),"mmddyyyy"===c?o=o.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,"$3/$1/$2"):"ddmmyyyy"===c?o=o.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,"$3/$2/$1"):"yyyymmdd"===c&&(o=o.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/,"$1/$2/$3")),n=new Date(o),n instanceof Date&&isFinite(n)?n.getTime():e}return e},type:"numeric"}),t.addParser({id:"time",is:function(e){return/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i.test(e)},format:function(e){var t=e?new Date("2000/01/01 "+e.replace(/(\S)([AP]M)$/i,"$1 $2")):e;return t instanceof Date&&isFinite(t)?t.getTime():e},type:"numeric"}),t.addParser({id:"metadata",is:function(){return!1},format:function(t,r,s){var a=r.config,n=a.parserMetadataName?a.parserMetadataName:"sortValue";return e(s).metadata()[n]},type:"numeric"}),t.addWidget({id:"zebra",priority:90,format:function(t,r,s){var a,n,o,i,d,c,l,p,u=new RegExp(r.cssChildRow,"i"),g=r.$tbodies.add(e(r.namespace+"_extra_table").children("tbody:not(."+r.cssInfoBlock+")"));for(r.debug&&(d=new Date),c=0;c<g.length;c++)for(o=0,a=g.eq(c).children("tr:visible").not(r.selectorRemove),p=a.length,l=0;p>l;l++)n=a.eq(l),u.test(n[0].className)||o++,i=o%2===0,n.removeClass(s.zebra[i?1:0]).addClass(s.zebra[i?0:1])},remove:function(e,r,s,a){if(!a){var n,o,i=r.$tbodies,d=(s.zebra||["even","odd"]).join(" ");for(n=0;n<i.length;n++)o=t.processTbody(e,i.eq(n),!0),o.children().removeClass(d),t.processTbody(e,o,!1)}}})}(jQuery); /* jquery.tablesorter.widgets.js v2.22.3 */ !function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof module&&"object"==typeof module.exports?module.exports=e(require("jquery")):e(jQuery)}(function(e){return function(e,t,r){"use strict";var i=e.tablesorter||{};i.storage=function(l,a,s,n){l=e(l)[0];var o,c,d,f=!1,u={},h=l.config,p=h&&h.widgetOptions,g=n&&n.useSessionStorage||p&&p.storage_useSessionStorage?"sessionStorage":"localStorage",m=e(l),b=n&&n.id||m.attr(n&&n.group||p&&p.storage_group||"data-table-group")||p&&p.storage_tableId||l.id||e(".tablesorter").index(m),y=n&&n.url||m.attr(n&&n.page||p&&p.storage_page||"data-table-page")||p&&p.storage_fixedUrl||h&&h.fixedUrl||t.location.pathname;if(g in t)try{t[g].setItem("_tmptest","temp"),f=!0,t[g].removeItem("_tmptest")}catch(_){h&&h.debug&&i.log(g+" is not supported in this browser")}return e.parseJSON&&(f?u=e.parseJSON(t[g][a]||"null")||{}:(c=r.cookie.split(/[;\s|=]/),o=e.inArray(a,c)+1,u=0!==o?e.parseJSON(c[o]||"null")||{}:{})),(s||""===s)&&t.JSON&&JSON.hasOwnProperty("stringify")?(u[y]||(u[y]={}),u[y][b]=s,f?t[g][a]=JSON.stringify(u):(d=new Date,d.setTime(d.getTime()+31536e6),r.cookie=a+"="+JSON.stringify(u).replace(/\"/g,'"')+"; expires="+d.toGMTString()+"; path=/"),void 0):u&&u[y]?u[y][b]:""}}(jQuery,window,document),function(e){"use strict";var t=e.tablesorter||{};t.themes={bootstrap:{table:"table table-bordered table-striped",caption:"caption",header:"bootstrap-header",sortNone:"",sortAsc:"",sortDesc:"",active:"",hover:"",icons:"",iconSortNone:"bootstrap-icon-unsorted",iconSortAsc:"icon-chevron-up glyphicon glyphicon-chevron-up",iconSortDesc:"icon-chevron-down glyphicon glyphicon-chevron-down",filterRow:"",footerRow:"",footerCells:"",even:"",odd:""},jui:{table:"ui-widget ui-widget-content ui-corner-all",caption:"ui-widget-content",header:"ui-widget-header ui-corner-all ui-state-default",sortNone:"",sortAsc:"",sortDesc:"",active:"ui-state-active",hover:"ui-state-hover",icons:"ui-icon",iconSortNone:"ui-icon-carat-2-n-s",iconSortAsc:"ui-icon-carat-1-n",iconSortDesc:"ui-icon-carat-1-s",filterRow:"",footerRow:"",footerCells:"",even:"ui-widget-content",odd:"ui-state-default"}},e.extend(t.css,{wrapper:"tablesorter-wrapper"}),t.addWidget({id:"uitheme",priority:10,format:function(r,i,l){var a,s,n,o,c,d,f,u,h,p,g,m,b=t.themes,y=i.$table.add(e(i.namespace+"_extra_table")),_=i.$headers.add(e(i.namespace+"_extra_headers")),v=i.theme||"jui",w=b[v]||{},x=e.trim([w.sortNone,w.sortDesc,w.sortAsc,w.active].join(" ")),C=e.trim([w.iconSortNone,w.iconSortDesc,w.iconSortAsc].join(" "));for(i.debug&&(o=new Date),y.hasClass("tablesorter-"+v)&&i.theme===i.appliedTheme&&l.uitheme_applied||(l.uitheme_applied=!0,h=b[i.appliedTheme]||{},m=!e.isEmptyObject(h),p=m?[h.sortNone,h.sortDesc,h.sortAsc,h.active].join(" "):"",g=m?[h.iconSortNone,h.iconSortDesc,h.iconSortAsc].join(" "):"",m&&(l.zebra[0]=e.trim(" "+l.zebra[0].replace(" "+h.even,"")),l.zebra[1]=e.trim(" "+l.zebra[1].replace(" "+h.odd,"")),i.$tbodies.children().removeClass([h.even,h.odd].join(" "))),w.even&&(l.zebra[0]+=" "+w.even),w.odd&&(l.zebra[1]+=" "+w.odd),y.children("caption").removeClass(h.caption||"").addClass(w.caption),f=y.removeClass((i.appliedTheme?"tablesorter-"+(i.appliedTheme||""):"")+" "+(h.table||"")).addClass("tablesorter-"+v+" "+(w.table||"")).children("tfoot"),i.appliedTheme=i.theme,f.length&&f.children("tr").removeClass(h.footerRow||"").addClass(w.footerRow).children("th, td").removeClass(h.footerCells||"").addClass(w.footerCells),_.removeClass((m?[h.header,h.hover,p].join(" "):"")||"").addClass(w.header).not(".sorter-false").unbind("mouseenter.tsuitheme mouseleave.tsuitheme").bind("mouseenter.tsuitheme mouseleave.tsuitheme",function(t){e(this)["mouseenter"===t.type?"addClass":"removeClass"](w.hover||"")}),_.each(function(){var r=e(this);r.find("."+t.css.wrapper).length||r.wrapInner('<div class="'+t.css.wrapper+'" style="position:relative;height:100%;width:100%"></div>')}),i.cssIcon&&_.find("."+t.css.icon).removeClass(m?[h.icons,g].join(" "):"").addClass(w.icons||""),y.hasClass("hasFilters")&&y.children("thead").children("."+t.css.filterRow).removeClass(m?h.filterRow||"":"").addClass(w.filterRow||"")),a=0;a<i.columns;a++)c=i.$headers.add(e(i.namespace+"_extra_headers")).not(".sorter-false").filter('[data-column="'+a+'"]'),d=t.css.icon?c.find("."+t.css.icon):e(),u=_.not(".sorter-false").filter('[data-column="'+a+'"]:last'),u.length&&(c.removeClass(x),d.removeClass(C),u[0].sortDisabled?d.removeClass(w.icons||""):(s=w.sortNone,n=w.iconSortNone,u.hasClass(t.css.sortAsc)?(s=[w.sortAsc,w.active].join(" "),n=w.iconSortAsc):u.hasClass(t.css.sortDesc)&&(s=[w.sortDesc,w.active].join(" "),n=w.iconSortDesc),c.addClass(s),d.addClass(n||"")));i.debug&&t.benchmark("Applying "+v+" theme",o)},remove:function(e,r,i,l){if(i.uitheme_applied){var a=r.$table,s=r.appliedTheme||"jui",n=t.themes[s]||t.themes.jui,o=a.children("thead").children(),c=n.sortNone+" "+n.sortDesc+" "+n.sortAsc,d=n.iconSortNone+" "+n.iconSortDesc+" "+n.iconSortAsc;a.removeClass("tablesorter-"+s+" "+n.table),i.uitheme_applied=!1,l||(a.find(t.css.header).removeClass(n.header),o.unbind("mouseenter.tsuitheme mouseleave.tsuitheme").removeClass(n.hover+" "+c+" "+n.active).filter("."+t.css.filterRow).removeClass(n.filterRow),o.find("."+t.css.icon).removeClass(n.icons+" "+d))}}})}(jQuery),function(e){"use strict";var t=e.tablesorter||{};t.addWidget({id:"columns",priority:30,options:{columns:["primary","secondary","tertiary"]},format:function(r,i,l){var a,s,n,o,c,d,f,u,h=i.$table,p=i.$tbodies,g=i.sortList,m=g.length,b=l&&l.columns||["primary","secondary","tertiary"],y=b.length-1;for(f=b.join(" "),s=0;s<p.length;s++)a=t.processTbody(r,p.eq(s),!0),n=a.children("tr"),n.each(function(){if(c=e(this),"none"!==this.style.display&&(d=c.children().removeClass(f),g&&g[0]&&(d.eq(g[0][0]).addClass(b[0]),m>1)))for(u=1;m>u;u++)d.eq(g[u][0]).addClass(b[u]||b[y])}),t.processTbody(r,a,!1);if(o=l.columns_thead!==!1?["thead tr"]:[],l.columns_tfoot!==!1&&o.push("tfoot tr"),o.length&&(n=h.find(o.join(",")).children().removeClass(f),m))for(u=0;m>u;u++)n.filter('[data-column="'+g[u][0]+'"]').addClass(b[u]||b[y])},remove:function(r,i,l){var a,s,n=i.$tbodies,o=(l.columns||["primary","secondary","tertiary"]).join(" ");for(i.$headers.removeClass(o),i.$table.children("tfoot").children("tr").children("th, td").removeClass(o),a=0;a<n.length;a++)s=t.processTbody(r,n.eq(a),!0),s.children("tr").each(function(){e(this).children().removeClass(o)}),t.processTbody(r,s,!1)}})}(jQuery),function(e){"use strict";var t=e.tablesorter||{},r=t.css;e.extend(r,{filterRow:"tablesorter-filter-row",filter:"tablesorter-filter",filterDisabled:"disabled",filterRowHide:"hideme"}),t.addWidget({id:"filter",priority:50,options:{filter_childRows:!1,filter_childByColumn:!1,filter_columnFilters:!0,filter_columnAnyMatch:!0,filter_cellFilter:"",filter_cssFilter:"",filter_defaultFilter:{},filter_excludeFilter:{},filter_external:"",filter_filteredRow:"filtered",filter_formatter:null,filter_functions:null,filter_hideEmpty:!0,filter_hideFilters:!1,filter_ignoreCase:!0,filter_liveSearch:!0,filter_onlyAvail:"filter-onlyAvail",filter_placeholder:{search:"",select:""},filter_reset:null,filter_saveFilters:!1,filter_searchDelay:300,filter_searchFiltered:!0,filter_selectSource:null,filter_startsWith:!1,filter_useParsedData:!1,filter_serversideFiltering:!1,filter_defaultAttrib:"data-value",filter_selectSourceSeparator:"|"},format:function(e,r,i){r.$table.hasClass("hasFilters")||t.filter.init(e,r,i)},remove:function(i,l,a,s){var n,o,c=l.$table,d=l.$tbodies,f="addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(l.namespace+"filter ");if(c.removeClass("hasFilters").unbind(f.replace(/\s+/g," ")).find("."+r.filterRow).remove(),!s){for(n=0;n<d.length;n++)o=t.processTbody(i,d.eq(n),!0),o.children().removeClass(a.filter_filteredRow).show(),t.processTbody(i,o,!1);a.filter_reset&&e(document).undelegate(a.filter_reset,"click.tsfilter")}}}),t.filter={regex:{regex:/^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/,child:/tablesorter-childRow/,filtered:/filtered/,type:/undefined|number/,exact:/(^[\"\'=]+)|([\"\'=]+$)/g,nondigit:/[^\w,. \-()]/g,operators:/[<>=]/g,query:"(q|query)"},types:{or:function(r,i,l){if(/\|/.test(i.iFilter)||t.filter.regex.orSplit.test(i.filter)){var a,s,n,o,c=e.extend({},i),d=i.index,f=i.parsed[d],u=i.filter.split(t.filter.regex.orSplit),h=i.iFilter.split(t.filter.regex.orSplit),p=u.length;for(a=0;p>a;a++)if(c.nestedFilters=!0,c.filter=""+(t.filter.parseFilter(r,u[a],d,f)||""),c.iFilter=""+(t.filter.parseFilter(r,h[a],d,f)||""),n="("+(t.filter.parseFilter(r,c.filter,d,f)||"")+")",o=new RegExp(i.isMatch?n:"^"+n+"$",r.widgetOptions.filter_ignoreCase?"i":""),s=o.test(c.exact)||t.filter.processTypes(r,c,l))return s;return s||!1}return null},and:function(r,i,l){if(t.filter.regex.andTest.test(i.filter)){var a,s,n,o,c,d=e.extend({},i),f=i.index,u=i.parsed[f],h=i.filter.split(t.filter.regex.andSplit),p=i.iFilter.split(t.filter.regex.andSplit),g=h.length;for(a=0;g>a;a++)d.nestedFilters=!0,d.filter=""+(t.filter.parseFilter(r,h[a],f,u)||""),d.iFilter=""+(t.filter.parseFilter(r,p[a],f,u)||""),o=("("+(t.filter.parseFilter(r,d.filter,f,u)||"")+")").replace(/\?/g,"\\S{1}").replace(/\*/g,"\\S*"),c=new RegExp(i.isMatch?o:"^"+o+"$",r.widgetOptions.filter_ignoreCase?"i":""),n=c.test(d.exact)||t.filter.processTypes(r,d,l),s=0===a?n:s&&n;return s||!1}return null},regex:function(e,r){if(t.filter.regex.regex.test(r.filter)){var i,l=r.filter_regexCache[r.index]||t.filter.regex.regex.exec(r.filter),a=l instanceof RegExp;try{a||(r.filter_regexCache[r.index]=l=new RegExp(l[1],l[2])),i=l.test(r.exact)}catch(s){i=!1}return i}return null},operators:function(r,i){if(/^[<>]=?/.test(i.iFilter)&&""!==i.iExact){var l,a,s,n=r.table,o=i.index,c=i.parsed[o],d=t.formatFloat(i.iFilter.replace(t.filter.regex.operators,""),n),f=r.parsers[o],u=d;return(c||"numeric"===f.type)&&(s=e.trim(""+i.iFilter.replace(t.filter.regex.operators,"")),a=t.filter.parseFilter(r,s,o,!0),d="number"!=typeof a||""===a||isNaN(a)?d:a),!c&&"numeric"!==f.type||isNaN(d)||"undefined"==typeof i.cache?(s=isNaN(i.iExact)?i.iExact.replace(t.filter.regex.nondigit,""):i.iExact,l=t.formatFloat(s,n)):l=i.cache,/>/.test(i.iFilter)?a=/>=/.test(i.iFilter)?l>=d:l>d:/</.test(i.iFilter)&&(a=/<=/.test(i.iFilter)?d>=l:d>l),a||""!==u||(a=!0),a}return null},notMatch:function(r,i){if(/^\!/.test(i.iFilter)){var l,a=i.iFilter.replace("!",""),s=t.filter.parseFilter(r,a,i.index,i.parsed[i.index])||"";return t.filter.regex.exact.test(s)?(s=s.replace(t.filter.regex.exact,""),""===s?!0:e.trim(s)!==i.iExact):(l=i.iExact.search(e.trim(s)),""===s?!0:!(r.widgetOptions.filter_startsWith?0===l:l>=0))}return null},exact:function(r,i){if(t.filter.regex.exact.test(i.iFilter)){var l=i.iFilter.replace(t.filter.regex.exact,""),a=t.filter.parseFilter(r,l,i.index,i.parsed[i.index])||"";return i.anyMatch?e.inArray(a,i.rowArray)>=0:a==i.iExact}return null},range:function(e,r){if(t.filter.regex.toTest.test(r.iFilter)){var i,l,a,s,n=e.table,o=r.index,c=r.parsed[o],d=r.iFilter.split(t.filter.regex.toSplit);return l=d[0].replace(t.filter.regex.nondigit,"")||"",a=t.formatFloat(t.filter.parseFilter(e,l,o,c),n),l=d[1].replace(t.filter.regex.nondigit,"")||"",s=t.formatFloat(t.filter.parseFilter(e,l,o,c),n),(c||"numeric"===e.parsers[o].type)&&(i=e.parsers[o].format(""+d[0],n,e.$headers.eq(o),o),a=""===i||isNaN(i)?a:i,i=e.parsers[o].format(""+d[1],n,e.$headers.eq(o),o),s=""===i||isNaN(i)?s:i),!c&&"numeric"!==e.parsers[o].type||isNaN(a)||isNaN(s)?(l=isNaN(r.iExact)?r.iExact.replace(t.filter.regex.nondigit,""):r.iExact,i=t.formatFloat(l,n)):i=r.cache,a>s&&(l=a,a=s,s=l),i>=a&&s>=i||""===a||""===s}return null},wild:function(e,r){if(/[\?\*\|]/.test(r.iFilter)){var i=r.index,l=r.parsed[i],a=""+(t.filter.parseFilter(e,r.iFilter,i,l)||"");return!/\?\*/.test(a)&&r.nestedFilters&&(a=r.isMatch?a:"^("+a+")$"),new RegExp(a.replace(/\?/g,"\\S{1}").replace(/\*/g,"\\S*"),e.widgetOptions.filter_ignoreCase?"i":"").test(r.exact)}return null},fuzzy:function(e,r){if(/^~/.test(r.iFilter)){var i,l=0,a=r.iExact.length,s=r.iFilter.slice(1),n=t.filter.parseFilter(e,s,r.index,r.parsed[r.index])||"";for(i=0;a>i;i++)r.iExact[i]===n[l]&&(l+=1);return l===n.length?!0:!1}return null}},init:function(i,l,a){t.language=e.extend(!0,{},{to:"to",or:"or",and:"and"},t.language);var s,n,o,c,d,f,u,h,p,g=t.filter.regex;if(l.$table.addClass("hasFilters"),a.searchTimer=null,a.filter_initTimer=null,a.filter_formatterCount=0,a.filter_formatterInit=[],a.filter_anyColumnSelector='[data-column="all"],[data-column="any"]',a.filter_multipleColumnSelector='[data-column*="-"],[data-column*=","]',u="\\{"+t.filter.regex.query+"\\}",e.extend(g,{child:new RegExp(l.cssChildRow),filtered:new RegExp(a.filter_filteredRow),alreadyFiltered:new RegExp("(\\s+("+t.language.or+"|-|"+t.language.to+")\\s+)","i"),toTest:new RegExp("\\s+(-|"+t.language.to+")\\s+","i"),toSplit:new RegExp("(?:\\s+(?:-|"+t.language.to+")\\s+)","gi"),andTest:new RegExp("\\s+("+t.language.and+"|&&)\\s+","i"),andSplit:new RegExp("(?:\\s+(?:"+t.language.and+"|&&)\\s+)","gi"),orSplit:new RegExp("(?:\\s+(?:"+t.language.or+")\\s+|\\|)","gi"),iQuery:new RegExp(u,"i"),igQuery:new RegExp(u,"ig")}),u=l.$headers.filter(".filter-false, .parser-false").length,a.filter_columnFilters!==!1&&u!==l.$headers.length&&t.filter.buildRow(i,l,a),o="addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(l.namespace+"filter "),l.$table.bind(o,function(s,n){return u=a.filter_hideEmpty&&e.isEmptyObject(l.cache)&&!(l.delayInit&&"appendCache"===s.type),l.$table.find("."+r.filterRow).toggleClass(a.filter_filteredRow,u),/(search|filter)/.test(s.type)||(s.stopPropagation(),t.filter.buildDefault(i,!0)),"filterReset"===s.type?(l.$table.find("."+r.filter).add(a.filter_$externalFilters).val(""),t.filter.searching(i,[])):"filterEnd"===s.type?t.filter.buildDefault(i,!0):(n="search"===s.type?n:"updateComplete"===s.type?l.$table.data("lastSearch"):"",/(update|add)/.test(s.type)&&"updateComplete"!==s.type&&(l.lastCombinedFilter=null,l.lastSearch=[]),t.filter.searching(i,n,!0)),!1}),a.filter_reset&&(a.filter_reset instanceof e?a.filter_reset.click(function(){l.$table.trigger("filterReset")}):e(a.filter_reset).length&&e(document).undelegate(a.filter_reset,"click.tsfilter").delegate(a.filter_reset,"click.tsfilter",function(){l.$table.trigger("filterReset")})),a.filter_functions)for(d=0;d<l.columns;d++)if(h=t.getColumnData(i,a.filter_functions,d))if(c=l.$headerIndexed[d].removeClass("filter-select"),p=!(c.hasClass("filter-false")||c.hasClass("parser-false")),s="",h===!0&&p)t.filter.buildSelect(i,d);else if("object"==typeof h&&p){for(n in h)"string"==typeof n&&(s+=""===s?'<option value="">'+(c.data("placeholder")||c.attr("data-placeholder")||a.filter_placeholder.select||"")+"</option>":"",u=n,o=n,n.indexOf(a.filter_selectSourceSeparator)>=0&&(u=n.split(a.filter_selectSourceSeparator),o=u[1],u=u[0]),s+="<option "+(o===u?"":'data-function-name="'+n+'" ')+'value="'+u+'">'+o+"</option>");l.$table.find("thead").find("select."+r.filter+'[data-column="'+d+'"]').append(s),o=a.filter_selectSource,h=e.isFunction(o)?!0:t.getColumnData(i,o,d),h&&t.filter.buildSelect(l.table,d,"",!0,c.hasClass(a.filter_onlyAvail))}t.filter.buildDefault(i,!0),t.filter.bindSearch(i,l.$table.find("."+r.filter),!0),a.filter_external&&t.filter.bindSearch(i,a.filter_external),a.filter_hideFilters&&t.filter.hideFilters(i,l),l.showProcessing&&(o="filterStart filterEnd ".split(" ").join(l.namespace+"filter "),l.$table.unbind(o.replace(/\s+/g," ")).bind(o,function(a,s){c=s?l.$table.find("."+r.header).filter("[data-column]").filter(function(){return""!==s[e(this).data("column")]}):"",t.isProcessing(i,"filterStart"===a.type,s?c:"")})),l.filteredRows=l.totalRows,o="tablesorter-initialized pagerBeforeInitialized ".split(" ").join(l.namespace+"filter "),l.$table.unbind(o.replace(/\s+/g," ")).bind(o,function(){var e=this.config.widgetOptions;f=t.filter.setDefaults(i,l,e)||[],f.length&&(l.delayInit&&""===f.join("")||t.setFilters(i,f,!0)),l.$table.trigger("filterFomatterUpdate"),setTimeout(function(){e.filter_initialized||t.filter.filterInitComplete(l)},100)}),l.pager&&l.pager.initialized&&!a.filter_initialized&&(l.$table.trigger("filterFomatterUpdate"),setTimeout(function(){t.filter.filterInitComplete(l)},100))},formatterUpdated:function(e,t){var r=e.closest("table")[0].config.widgetOptions;r.filter_initialized||(r.filter_formatterInit[t]=1)},filterInitComplete:function(r){var i,l,a=r.widgetOptions,s=0,n=function(){a.filter_initialized=!0,r.$table.trigger("filterInit",r),t.filter.findRows(r.table,r.$table.data("lastSearch")||[])};if(e.isEmptyObject(a.filter_formatter))n();else{for(l=a.filter_formatterInit.length,i=0;l>i;i++)1===a.filter_formatterInit[i]&&s++;clearTimeout(a.filter_initTimer),a.filter_initialized||s!==a.filter_formatterCount?a.filter_initialized||(a.filter_initTimer=setTimeout(function(){n()},500)):n()}},setDefaults:function(r,i,l){var a,s,n,o,c,d=t.getFilters(r)||[];if(l.filter_saveFilters&&t.storage&&(s=t.storage(r,"tablesorter-filters")||[],a=e.isArray(s),a&&""===s.join("")||!a||(d=s)),""===d.join(""))for(c=i.$headers.add(l.filter_$externalFilters).filter("["+l.filter_defaultAttrib+"]"),n=0;n<=i.columns;n++)o=n===i.columns?"all":n,d[n]=c.filter('[data-column="'+o+'"]').attr(l.filter_defaultAttrib)||d[n]||"";return i.$table.data("lastSearch",d),d},parseFilter:function(e,t,r,i){return i?e.parsers[r].format(t,e.table,[],r):t},buildRow:function(i,l,a){var s,n,o,c,d,f,u,h,p=a.filter_cellFilter,g=l.columns,m=e.isArray(p),b='<tr role="row" class="'+r.filterRow+" "+l.cssIgnoreRow+'">';for(n=0;g>n;n++)b+="<td",b+=m?p[n]?' class="'+p[n]+'"':"":""!==p?' class="'+p+'"':"",b+="></td>";for(l.$filters=e(b+="</tr>").appendTo(l.$table.children("thead").eq(0)).find("td"),n=0;g>n;n++)d=!1,o=l.$headerIndexed[n],u=t.getColumnData(i,a.filter_functions,n),c=a.filter_functions&&u&&"function"!=typeof u||o.hasClass("filter-select"),s=t.getColumnData(i,l.headers,n),d="false"===t.getData(o[0],s,"filter")||"false"===t.getData(o[0],s,"parser"),c?b=e("<select>").appendTo(l.$filters.eq(n)):(u=t.getColumnData(i,a.filter_formatter,n),u?(a.filter_formatterCount++,b=u(l.$filters.eq(n),n),b&&0===b.length&&(b=l.$filters.eq(n).children("input")),b&&(0===b.parent().length||b.parent().length&&b.parent()[0]!==l.$filters[n])&&l.$filters.eq(n).append(b)):b=e('<input type="search">').appendTo(l.$filters.eq(n)),b&&(h=o.data("placeholder")||o.attr("data-placeholder")||a.filter_placeholder.search||"",b.attr("placeholder",h))),b&&(f=(e.isArray(a.filter_cssFilter)?"undefined"!=typeof a.filter_cssFilter[n]?a.filter_cssFilter[n]||"":"":a.filter_cssFilter)||"",b.addClass(r.filter+" "+f).attr("data-column",n),d&&(b.attr("placeholder","").addClass(r.filterDisabled)[0].disabled=!0))},bindSearch:function(r,i,l){if(r=e(r)[0],i=e(i),i.length){var a,s=r.config,n=s.widgetOptions,o=s.namespace+"filter",c=n.filter_$externalFilters;l!==!0&&(a=n.filter_anyColumnSelector+","+n.filter_multipleColumnSelector,n.filter_$anyMatch=i.filter(a),n.filter_$externalFilters=c&&c.length?n.filter_$externalFilters.add(i):i,t.setFilters(r,s.$table.data("lastSearch")||[],l===!1)),a="keypress keyup search change ".split(" ").join(o+" "),i.attr("data-lastSearchTime",(new Date).getTime()).unbind(a.replace(/\s+/g," ")).bind("keyup"+o,function(i){if(e(this).attr("data-lastSearchTime",(new Date).getTime()),27===i.which)this.value="";else{if(n.filter_liveSearch===!1)return;if(""!==this.value&&("number"==typeof n.filter_liveSearch&&this.value.length<n.filter_liveSearch||13!==i.which&&8!==i.which&&(i.which<32||i.which>=37&&i.which<=40)))return}t.filter.searching(r,!0,!0)}).bind("search change keypress ".split(" ").join(o+" "),function(i){var l=e(this).data("column");(13===i.which||"search"===i.type||"change"===i.type&&this.value!==s.lastSearch[l])&&(i.preventDefault(),e(this).attr("data-lastSearchTime",(new Date).getTime()),t.filter.searching(r,!1,!0))})}},searching:function(e,r,i){var l=e.config.widgetOptions;clearTimeout(l.searchTimer),"undefined"==typeof r||r===!0?l.searchTimer=setTimeout(function(){t.filter.checkFilters(e,r,i)},l.filter_liveSearch?l.filter_searchDelay:10):t.filter.checkFilters(e,r,i)},checkFilters:function(i,l,a){var s=i.config,n=s.widgetOptions,o=e.isArray(l),c=o?l:t.getFilters(i,!0),d=(c||[]).join("");return e.isEmptyObject(s.cache)?void(s.delayInit&&s.pager&&s.pager.initialized&&s.$table.trigger("updateCache",[function(){t.filter.checkFilters(i,!1,a)}])):(o&&(t.setFilters(i,c,!1,a!==!0),n.filter_initialized||(s.lastCombinedFilter="")),n.filter_hideFilters&&s.$table.find("."+r.filterRow).trigger(""===d?"mouseleave":"mouseenter"),s.lastCombinedFilter!==d||l===!1?(l===!1&&(s.lastCombinedFilter=null,s.lastSearch=[]),n.filter_initialized&&s.$table.trigger("filterStart",[c]),s.showProcessing?void setTimeout(function(){return t.filter.findRows(i,c,d),!1},30):(t.filter.findRows(i,c,d),!1)):void 0)},hideFilters:function(i,l){var a;l.$table.find("."+r.filterRow).bind("mouseenter mouseleave",function(t){var i=t,s=e(this);clearTimeout(a),a=setTimeout(function(){/enter|over/.test(i.type)?s.removeClass(r.filterRowHide):e(document.activeElement).closest("tr")[0]!==s[0]&&""===l.lastCombinedFilter&&s.addClass(r.filterRowHide)},200)}).find("input, select").bind("focus blur",function(i){var s=i,n=e(this).closest("tr");clearTimeout(a),a=setTimeout(function(){clearTimeout(a),""===t.getFilters(l.$table).join("")&&n.toggleClass(r.filterRowHide,"focus"!==s.type)},200)})},defaultFilter:function(r,i){if(""===r)return r;var l=t.filter.regex.iQuery,a=i.match(t.filter.regex.igQuery).length,s=a>1?e.trim(r).split(/\s/):[e.trim(r)],n=s.length-1,o=0,c=i;for(1>n&&a>1&&(s[1]=s[0]);l.test(c);)c=c.replace(l,s[o++]||""),l.test(c)&&n>o&&""!==(s[o]||"")&&(c=i.replace(l,c));return c},getLatestSearch:function(t){return t?t.sort(function(t,r){return e(r).attr("data-lastSearchTime")-e(t).attr("data-lastSearchTime")}):t||e()},multipleColumns:function(r,i){var l,a,s,n,o,c,d,f,u,h=r.widgetOptions,p=h.filter_initialized||!i.filter(h.filter_anyColumnSelector).length,g=[],m=e.trim(t.filter.getLatestSearch(i).attr("data-column")||"");if(p&&/-/.test(m))for(a=m.match(/(\d+)\s*-\s*(\d+)/g),u=a.length,f=0;u>f;f++){for(s=a[f].split(/\s*-\s*/),n=parseInt(s[0],10)||0,o=parseInt(s[1],10)||r.columns-1,n>o&&(l=n,n=o,o=l),o>=r.columns&&(o=r.columns-1);o>=n;n++)g.push(n);m=m.replace(a[f],"")}if(p&&/,/.test(m))for(c=m.split(/\s*,\s*/),u=c.length,d=0;u>d;d++)""!==c[d]&&(f=parseInt(c[d],10),f<r.columns&&g.push(f));if(!g.length)for(f=0;f<r.columns;f++)g.push(f);return g},processTypes:function(r,i,l){var a,s=null,n=null;for(a in t.filter.types)e.inArray(a,l.excludeMatch)<0&&null===n&&(n=t.filter.types[a](r,i,l),null!==n&&(s=n));return s},processRow:function(r,i,l){var a,s,n,o,c,d,f,u,h=t.filter.regex,p=r.widgetOptions,g=!0;if(i.$cells=i.$row.children(),i.anyMatchFlag){if(a=t.filter.multipleColumns(r,p.filter_$anyMatch),i.anyMatch=!0,i.isMatch=!0,i.rowArray=i.$cells.map(function(l){return e.inArray(l,a)>-1?(i.parsed[l]?u=i.cacheArray[l]:(u=i.rawArray[l],u=e.trim(p.filter_ignoreCase?u.toLowerCase():u),r.sortLocaleCompare&&(u=t.replaceAccents(u))),u):void 0}).get(),i.filter=i.anyMatchFilter,i.iFilter=i.iAnyMatchFilter,i.exact=i.rowArray.join(" "),i.iExact=p.filter_ignoreCase?i.exact.toLowerCase():i.exact,i.cache=i.cacheArray.slice(0,-1).join(" "),l.excludeMatch=l.noAnyMatch,c=t.filter.processTypes(r,i,l),null!==c)g=c;else if(p.filter_startsWith)for(g=!1,a=r.columns;!g&&a>0;)a--,g=g||0===i.rowArray[a].indexOf(i.iFilter);else g=(i.iExact+i.childRowText).indexOf(i.iFilter)>=0;if(i.anyMatch=!1,i.filters.join("")===i.filter)return g}for(a=0;a<r.columns;a++)i.filter=i.filters[a],i.index=a,l.excludeMatch=l.excludeFilter[a],i.filter&&(i.cache=i.cacheArray[a],p.filter_useParsedData||i.parsed[a]?i.exact=i.cache:(n=i.rawArray[a]||"",i.exact=r.sortLocaleCompare?t.replaceAccents(n):n),i.iExact=!h.type.test(typeof i.exact)&&p.filter_ignoreCase?i.exact.toLowerCase():i.exact,i.isMatch=r.$headerIndexed[i.index].hasClass("filter-match"),n=g,f=p.filter_columnFilters?r.$filters.add(r.$externalFilters).filter('[data-column="'+a+'"]').find("select option:selected").attr("data-function-name")||"":"",r.sortLocaleCompare&&(i.filter=t.replaceAccents(i.filter)),o=!0,p.filter_defaultFilter&&h.iQuery.test(l.defaultColFilter[a])&&(i.filter=t.filter.defaultFilter(i.filter,l.defaultColFilter[a]),o=!1),i.iFilter=p.filter_ignoreCase?(i.filter||"").toLowerCase():i.filter,d=l.functions[a],s=r.$headerIndexed[a].hasClass("filter-select"),c=null,(d||s&&o)&&(d===!0||s?c=i.isMatch?i.iExact.search(i.iFilter)>=0:i.filter===i.exact:"function"==typeof d?c=d(i.exact,i.cache,i.filter,a,i.$row,r,i):"function"==typeof d[f||i.filter]&&(u=f||i.filter,c=d[u](i.exact,i.cache,i.filter,a,i.$row,r,i))),null===c?(c=t.filter.processTypes(r,i,l),null!==c?n=c:(u=(i.iExact+i.childRowText).indexOf(t.filter.parseFilter(r,i.iFilter,a,i.parsed[a])),n=!p.filter_startsWith&&u>=0||p.filter_startsWith&&0===u)):n=c,g=n?g:!1);return g},findRows:function(r,i,l){if(r.config.lastCombinedFilter!==l&&r.config.widgetOptions.filter_initialized){var a,s,n,o,c,d,f,u,h,p,g,m,b,y,_,v,w,x,C,z,S,$,F=e.extend([],i),R=t.filter.regex,k=r.config,T=k.widgetOptions,A={anyMatch:!1,filters:i,filter_regexCache:[]},H={noAnyMatch:["range","notMatch","operators"],functions:[],excludeFilter:[],defaultColFilter:[],defaultAnyFilter:t.getColumnData(r,T.filter_defaultFilter,k.columns,!0)||""};for(A.parsed=k.$headers.map(function(i){return k.parsers&&k.parsers[i]&&k.parsers[i].parsed||t.getData&&"parsed"===t.getData(k.$headerIndexed[i],t.getColumnData(r,k.headers,i),"filter")||e(this).hasClass("filter-parsed")}).get(),u=0;u<k.columns;u++)H.functions[u]=t.getColumnData(r,T.filter_functions,u),H.defaultColFilter[u]=t.getColumnData(r,T.filter_defaultFilter,u)||"",H.excludeFilter[u]=(t.getColumnData(r,T.filter_excludeFilter,u,!0)||"").split(/\s+/);for(k.debug&&(t.log("Filter: Starting filter widget search",i),b=new Date),k.filteredRows=0,k.totalRows=0,l=(F||[]).join(""),d=0;d<k.$tbodies.length;d++){if(f=t.processTbody(r,k.$tbodies.eq(d),!0),u=k.columns,s=k.cache[d].normalized,o=e(e.map(s,function(e){return e[u].$row.get()})),""===l||T.filter_serversideFiltering)o.removeClass(T.filter_filteredRow).not("."+k.cssChildRow).css("display","");else{if(o=o.not("."+k.cssChildRow),a=o.length,(T.filter_$anyMatch&&T.filter_$anyMatch.length||"undefined"!=typeof i[k.columns])&&(A.anyMatchFlag=!0,A.anyMatchFilter=""+(i[k.columns]||T.filter_$anyMatch&&t.filter.getLatestSearch(T.filter_$anyMatch).val()||""),T.filter_columnAnyMatch)){for(x=A.anyMatchFilter.split(R.andSplit),C=!1,_=0;_<x.length;_++)z=x[_].split(":"),z.length>1&&(S=parseInt(z[0],10)-1,S>=0&&S<k.columns&&(i[S]=z[1],x.splice(_,1),_--,C=!0));C&&(A.anyMatchFilter=x.join(" && "))}if(w=T.filter_searchFiltered,g=k.lastSearch||k.$table.data("lastSearch")||[],w)for(_=0;u+1>_;_++)y=i[_]||"",w||(_=u),w=!(!w||!g.length||0!==y.indexOf(g[_]||"")||R.alreadyFiltered.test(y)||/[=\"\|!]/.test(y)||/(>=?\s*-\d)/.test(y)||/(<=?\s*\d)/.test(y)||""!==y&&k.$filters&&k.$filters.eq(_).find("select").length&&!k.$headerIndexed[_].hasClass("filter-match"));for(v=o.not("."+T.filter_filteredRow).length,w&&0===v&&(w=!1),k.debug&&t.log("Filter: Searching through "+(w&&a>v?v:"all")+" rows"),A.anyMatchFlag&&(k.sortLocaleCompare&&(A.anyMatchFilter=t.replaceAccents(A.anyMatchFilter)),T.filter_defaultFilter&&R.iQuery.test(H.defaultAnyFilter)&&(A.anyMatchFilter=t.filter.defaultFilter(A.anyMatchFilter,H.defaultAnyFilter),w=!1),A.iAnyMatchFilter=T.filter_ignoreCase&&k.ignoreCase?A.anyMatchFilter.toLowerCase():A.anyMatchFilter),c=0;a>c;c++)if($=o[c].className,h=c&&R.child.test($),!(h||w&&R.filtered.test($))){if(A.$row=o.eq(c),A.cacheArray=s[c],n=A.cacheArray[k.columns],A.rawArray=n.raw,A.childRowText="",!T.filter_childByColumn){for($="",p=n.child,_=0;_<p.length;_++)$+=" "+p[_].join("")||"";A.childRowText=T.filter_childRows?T.filter_ignoreCase?$.toLowerCase():$:""}if(m=t.filter.processRow(k,A,H),p=n.$row.filter(":gt( 0 )"),T.filter_childRows&&p.length){if(T.filter_childByColumn)for(_=0;_<p.length;_++)A.$row=p.eq(_),A.cacheArray=n.child[_],A.rawArray=A.cacheArray,m=m||t.filter.processRow(k,A,H);p.toggleClass(T.filter_filteredRow,!m)}n.$row.toggleClass(T.filter_filteredRow,!m)[0].display=m?"":"none"}}k.filteredRows+=o.not("."+T.filter_filteredRow).length,k.totalRows+=o.length,t.processTbody(r,f,!1)}k.lastCombinedFilter=l,k.lastSearch=F,k.$table.data("lastSearch",F),T.filter_saveFilters&&t.storage&&t.storage(r,"tablesorter-filters",F),k.debug&&t.benchmark("Completed filter widget search",b),T.filter_initialized&&k.$table.trigger("filterEnd",k),setTimeout(function(){k.$table.trigger("applyWidgets")},0)}},getOptionSource:function(r,i,l){r=e(r)[0];var a,s,n,o,c=r.config,d=c.widgetOptions,f=[],u=!1,h=d.filter_selectSource,p=c.$table.data("lastSearch")||[],g=e.isFunction(h)?!0:t.getColumnData(r,h,i);if(l&&""!==p[i]&&(l=!1),g===!0)u=h(r,i,l);else{if(g instanceof e||"string"===e.type(g)&&g.indexOf("</option>")>=0)return g;e.isArray(g)?u=g:"object"===e.type(h)&&g&&(u=g(r,i,l))}if(u===!1&&(u=t.filter.getOptions(r,i,l)),u=e.grep(u,function(t,r){return e.inArray(t,u)===r}),c.$headerIndexed[i].hasClass("filter-select-nosort"))return u;for(o=u.length,n=0;o>n;n++)s=u[n],f.push({t:s,p:c.parsers&&c.parsers.length&&c.parsers[i].format(s,r,[],i)||s});for(a=c.textSorter||"",f.sort(function(l,s){var n=l.p.toString(),o=s.p.toString();return e.isFunction(a)?a(n,o,!0,i,r):"object"==typeof a&&a.hasOwnProperty(i)?a[i](n,o,!0,i,r):t.sortNatural?t.sortNatural(n,o):!0}),u=[],o=f.length,n=0;o>n;n++)u.push(f[n].t);return u},getOptions:function(t,r,i){t=e(t)[0];var l,a,s,n,o,c=t.config,d=c.widgetOptions,f=[];for(a=0;a<c.$tbodies.length;a++)for(o=c.cache[a],s=c.cache[a].normalized.length,l=0;s>l;l++)n=o.row?o.row[l]:o.normalized[l][c.columns].$row[0],i&&n.className.match(d.filter_filteredRow)||f.push(d.filter_useParsedData||c.parsers[r].parsed||c.$headerIndexed[r].hasClass("filter-parsed")?""+o.normalized[l][r]:o.normalized[l][c.columns].raw[r]);return f},buildSelect:function(i,l,a,s,n){if(i=e(i)[0],l=parseInt(l,10),i.config.cache&&!e.isEmptyObject(i.config.cache)){var o,c,d,f,u,h,p=i.config,g=p.widgetOptions,m=p.$headerIndexed[l],b='<option value="">'+(m.data("placeholder")||m.attr("data-placeholder")||g.filter_placeholder.select||"")+"</option>",y=p.$table.find("thead").find("select."+r.filter+'[data-column="'+l+'"]').val();if(("undefined"==typeof a||""===a)&&(a=t.filter.getOptionSource(i,l,n)),e.isArray(a)){for(o=0;o<a.length;o++)d=a[o]=(""+a[o]).replace(/\"/g,"&quot;"),c=d,d.indexOf(g.filter_selectSourceSeparator)>=0&&(f=d.split(g.filter_selectSourceSeparator),c=f[0],d=f[1]),b+=""!==a[o]?"<option "+(c===d?"":'data-function-name="'+a[o]+'" ')+'value="'+c+'">'+d+"</option>":"";a=[]}u=(p.$filters?p.$filters:p.$table.children("thead")).find("."+r.filter),g.filter_$externalFilters&&(u=u&&u.length?u.add(g.filter_$externalFilters):g.filter_$externalFilters),h=u.filter('select[data-column="'+l+'"]'),h.length&&(h[s?"html":"append"](b),e.isArray(a)||h.append(a).val(y),h.val(y))}},buildDefault:function(e,r){var i,l,a,s=e.config,n=s.widgetOptions,o=s.columns;for(i=0;o>i;i++)l=s.$headerIndexed[i],a=!(l.hasClass("filter-false")||l.hasClass("parser-false")),(l.hasClass("filter-select")||t.getColumnData(e,n.filter_functions,i)===!0)&&a&&t.filter.buildSelect(e,i,"",r,l.hasClass(n.filter_onlyAvail))}},t.getFilters=function(i,l,a,s){var n,o,c,d,f=!1,u=i?e(i)[0].config:"",h=u?u.widgetOptions:"";if(l!==!0&&h&&!h.filter_columnFilters||e.isArray(a)&&a.join("")===u.lastCombinedFilter)return e(i).data("lastSearch");if(u&&(u.$filters&&(o=u.$filters.find("."+r.filter)),h.filter_$externalFilters&&(o=o&&o.length?o.add(h.filter_$externalFilters):h.filter_$externalFilters),o&&o.length))for(f=a||[],n=0;n<u.columns+1;n++)d=n===u.columns?h.filter_anyColumnSelector+","+h.filter_multipleColumnSelector:'[data-column="'+n+'"]',c=o.filter(d),c.length&&(c=t.filter.getLatestSearch(c),e.isArray(a)?(s&&c.length>1&&(c=c.slice(1)),n===u.columns&&(d=c.filter(h.filter_anyColumnSelector),c=d.length?d:c),c.val(a[n]).trigger("change.tsfilter")):(f[n]=c.val()||"",n===u.columns?c.slice(1).filter('[data-column*="'+c.attr("data-column")+'"]').val(f[n]):c.slice(1).val(f[n])),n===u.columns&&c.length&&(h.filter_$anyMatch=c));
+ return 0===f.length&&(f=!1),f},t.setFilters=function(r,i,l,a){var s=r?e(r)[0].config:"",n=t.getFilters(r,!0,i,a);return s&&l&&(s.lastCombinedFilter=null,s.lastSearch=[],t.filter.searching(s.table,i,a),s.$table.trigger("filterFomatterUpdate")),!!n}}(jQuery),function(e,t){"use strict";var r=e.tablesorter||{};e.extend(r.css,{sticky:"tablesorter-stickyHeader",stickyVis:"tablesorter-sticky-visible",stickyHide:"tablesorter-sticky-hidden",stickyWrap:"tablesorter-sticky-wrapper"}),r.addHeaderResizeEvent=function(t,r,i){if(t=e(t)[0],t.config){var l={timer:250},a=e.extend({},l,i),s=t.config,n=s.widgetOptions,o=function(e){var t,r,i,l,a,o,c=s.$headers.length;for(n.resize_flag=!0,r=[],t=0;c>t;t++)i=s.$headers.eq(t),l=i.data("savedSizes")||[0,0],a=i[0].offsetWidth,o=i[0].offsetHeight,(a!==l[0]||o!==l[1])&&(i.data("savedSizes",[a,o]),r.push(i[0]));r.length&&e!==!1&&s.$table.trigger("resize",[r]),n.resize_flag=!1};return o(!1),clearInterval(n.resize_timer),r?(n.resize_flag=!1,!1):void(n.resize_timer=setInterval(function(){n.resize_flag||o()},a.timer))}},r.addWidget({id:"stickyHeaders",priority:60,options:{stickyHeaders:"",stickyHeaders_attachTo:null,stickyHeaders_xScroll:null,stickyHeaders_yScroll:null,stickyHeaders_offset:0,stickyHeaders_filteredToTop:!0,stickyHeaders_cloneId:"-sticky",stickyHeaders_addResizeEvent:!0,stickyHeaders_includeCaption:!0,stickyHeaders_zIndex:2},format:function(i,l,a){if(!(l.$table.hasClass("hasStickyHeaders")||e.inArray("filter",l.widgets)>=0&&!l.$table.hasClass("hasFilters"))){var s,n,o,c,d=l.$table,f=e(a.stickyHeaders_attachTo),u=l.namespace+"stickyheaders ",h=e(a.stickyHeaders_yScroll||a.stickyHeaders_attachTo||t),p=e(a.stickyHeaders_xScroll||a.stickyHeaders_attachTo||t),g=d.children("thead:first"),m=g.children("tr").not(".sticky-false").children(),b=d.children("tfoot"),y=isNaN(a.stickyHeaders_offset)?e(a.stickyHeaders_offset):"",_=y.length?y.height()||0:parseInt(a.stickyHeaders_offset,10)||0,v=d.parent().closest("."+r.css.table).hasClass("hasStickyHeaders")?d.parent().closest("table.tablesorter")[0].config.widgetOptions.$sticky.parent():[],w=v.length?v.height():0,x=a.$sticky=d.clone().addClass("containsStickyHeaders "+r.css.sticky+" "+a.stickyHeaders+" "+l.namespace.slice(1)+"_extra_table").wrap('<div class="'+r.css.stickyWrap+'">'),C=x.parent().addClass(r.css.stickyHide).css({position:f.length?"absolute":"fixed",padding:parseInt(x.parent().parent().css("padding-left"),10),top:_+w,left:0,visibility:"hidden",zIndex:a.stickyHeaders_zIndex||2}),z=x.children("thead:first"),S="",$=0,F=function(e,r){var i,l,a,s,n,o=e.filter(":visible"),c=o.length;for(i=0;c>i;i++)s=r.filter(":visible").eq(i),n=o.eq(i),"border-box"===n.css("box-sizing")?l=n.outerWidth():"collapse"===s.css("border-collapse")?t.getComputedStyle?l=parseFloat(t.getComputedStyle(n[0],null).width):(a=parseFloat(n.css("border-width")),l=n.outerWidth()-parseFloat(n.css("padding-left"))-parseFloat(n.css("padding-right"))-a):l=n.width(),s.css({width:l,"min-width":l,"max-width":l})},R=function(){_=y.length?y.height()||0:parseInt(a.stickyHeaders_offset,10)||0,$=0,C.css({left:f.length?parseInt(f.css("padding-left"),10)||0:d.offset().left-parseInt(d.css("margin-left"),10)-p.scrollLeft()-$,width:d.outerWidth()}),F(d,x),F(m,c)},k=function(t){if(d.is(":visible")){w=v.length?v.offset().top-h.scrollTop()+v.height():0;var i=d.offset(),l=e.isWindow(h[0]),a=e.isWindow(p[0]),s=(f.length?l?h.scrollTop():h.offset().top:h.scrollTop())+_+w,n=d.height()-(C.height()+(b.height()||0)),o=s>i.top&&s<i.top+n?"visible":"hidden",c={visibility:o};f.length&&(c.top=l?s-f.offset().top:f.scrollTop()),a&&(c.left=d.offset().left-parseInt(d.css("margin-left"),10)-p.scrollLeft()-$),v.length&&(c.top=(c.top||0)+_+w),C.removeClass(r.css.stickyVis+" "+r.css.stickyHide).addClass("visible"===o?r.css.stickyVis:r.css.stickyHide).css(c),(o!==S||t)&&(R(),S=o)}};if(f.length&&!f.css("position")&&f.css("position","relative"),x.attr("id")&&(x[0].id+=a.stickyHeaders_cloneId),x.find("thead:gt(0), tr.sticky-false").hide(),x.find("tbody, tfoot").remove(),x.find("caption").toggle(a.stickyHeaders_includeCaption),c=z.children().children(),x.css({height:0,width:0,margin:0}),c.find("."+r.css.resizer).remove(),d.addClass("hasStickyHeaders").bind("pagerComplete"+u,function(){R()}),r.bindEvents(i,z.children().children("."+r.css.header)),d.after(C),l.onRenderHeader)for(o=z.children("tr").children(),n=o.length,s=0;n>s;s++)l.onRenderHeader.apply(o.eq(s),[s,l,x]);p.add(h).unbind("scroll resize ".split(" ").join(u).replace(/\s+/g," ")).bind("scroll resize ".split(" ").join(u),function(e){k("resize"===e.type)}),l.$table.unbind("stickyHeadersUpdate"+u).bind("stickyHeadersUpdate"+u,function(){k(!0)}),a.stickyHeaders_addResizeEvent&&r.addHeaderResizeEvent(i),d.hasClass("hasFilters")&&a.filter_columnFilters&&(d.bind("filterEnd"+u,function(){var i=e(document.activeElement).closest("td"),s=i.parent().children().index(i);C.hasClass(r.css.stickyVis)&&a.stickyHeaders_filteredToTop&&(t.scrollTo(0,d.position().top),s>=0&&l.$filters&&l.$filters.eq(s).find("a, select, input").filter(":visible").focus())}),r.filter.bindSearch(d,c.find("."+r.css.filter)),a.filter_hideFilters&&r.filter.hideFilters(x,l)),d.trigger("stickyHeadersInit")}},remove:function(i,l,a){var s=l.namespace+"stickyheaders ";l.$table.removeClass("hasStickyHeaders").unbind("pagerComplete filterEnd stickyHeadersUpdate ".split(" ").join(s).replace(/\s+/g," ")).next("."+r.css.stickyWrap).remove(),a.$sticky&&a.$sticky.length&&a.$sticky.remove(),e(t).add(a.stickyHeaders_xScroll).add(a.stickyHeaders_yScroll).add(a.stickyHeaders_attachTo).unbind("scroll resize ".split(" ").join(s).replace(/\s+/g," ")),r.addHeaderResizeEvent(i,!1)}})}(jQuery,window),function(e,t){"use strict";var r=e.tablesorter||{};e.extend(r.css,{resizableContainer:"tablesorter-resizable-container",resizableHandle:"tablesorter-resizable-handle",resizableNoSelect:"tablesorter-disableSelection",resizableStorage:"tablesorter-resizable"}),e(function(){var t="<style>body."+r.css.resizableNoSelect+" { -ms-user-select: none; -moz-user-select: -moz-none;-khtml-user-select: none; -webkit-user-select: none; user-select: none; }."+r.css.resizableContainer+" { position: relative; height: 1px; }."+r.css.resizableHandle+" { position: absolute; display: inline-block; width: 8px;top: 1px; cursor: ew-resize; z-index: 3; user-select: none; -moz-user-select: none; }</style>";e(t).appendTo("body")}),r.resizable={init:function(t,i){if(!t.$table.hasClass("hasResizable")){t.$table.addClass("hasResizable");var l,a,s,n,o,c=t.$table,d=c.parent(),f=parseInt(c.css("margin-top"),10),u=i.resizable_={useStorage:r.storage&&i.resizable!==!1,$wrap:d,mouseXPosition:0,$target:null,$next:null,overflow:"auto"===d.css("overflow")||"scroll"===d.css("overflow")||"auto"===d.css("overflow-x")||"scroll"===d.css("overflow-x"),storedSizes:[]};for(r.resizableReset(t.table,!0),u.tableWidth=c.width(),u.fullWidth=Math.abs(d.width()-u.tableWidth)<20,u.useStorage&&u.overflow&&(r.storage(t.table,"tablesorter-table-original-css-width",u.tableWidth),o=r.storage(t.table,"tablesorter-table-resized-width")||"auto",r.resizable.setWidth(c,o,!0)),i.resizable_.storedSizes=n=(u.useStorage?r.storage(t.table,r.css.resizableStorage):[])||[],r.resizable.setWidths(t,i,n),r.resizable.updateStoredSizes(t,i),i.$resizable_container=e('<div class="'+r.css.resizableContainer+'">').css({top:f}).insertBefore(c),s=0;s<t.columns;s++)a=t.$headerIndexed[s],o=r.getColumnData(t.table,t.headers,s),l="false"===r.getData(a,o,"resizable"),l||e('<div class="'+r.css.resizableHandle+'">').appendTo(i.$resizable_container).attr({"data-column":s,unselectable:"on"}).data("header",a).bind("selectstart",!1);c.one("tablesorter-initialized",function(){r.resizable.setHandlePosition(t,i),r.resizable.bindings(this.config,this.config.widgetOptions)})}},updateStoredSizes:function(e,t){var r,i,l=e.columns,a=t.resizable_;for(a.storedSizes=[],r=0;l>r;r++)i=e.$headerIndexed[r],a.storedSizes[r]=i.is(":visible")?i.width():0},setWidth:function(e,t,r){e.css({width:t,"min-width":r?t:"","max-width":r?t:""})},setWidths:function(t,i,l){var a,s,n=i.resizable_,o=e(t.namespace+"_extra_headers"),c=t.$table.children("colgroup").children("col");if(l=l||n.storedSizes||[],l.length){for(a=0;a<t.columns;a++)r.resizable.setWidth(t.$headerIndexed[a],l[a],n.overflow),o.length&&(s=o.eq(a).add(c.eq(a)),r.resizable.setWidth(s,l[a],n.overflow));s=e(t.namespace+"_extra_table"),s.length&&!r.hasWidget(t.table,"scroller")&&r.resizable.setWidth(s,t.$table.outerWidth(),n.overflow)}},setHandlePosition:function(t,i){var l,a=r.hasWidget(t.table,"scroller"),s=t.$table.height(),n=i.$resizable_container.children(),o=Math.floor(n.width()/2);a&&(s=0,t.$table.closest("."+r.css.scrollerWrap).children().each(function(){var t=e(this);s+=t.filter('[style*="height"]').length?t.height():t.children("table").height()})),l=t.$table.position().left,n.each(function(){var r=e(this),a=parseInt(r.attr("data-column"),10),n=t.columns-1,c=r.data("header");c&&(c.is(":visible")?(n>a||a===n&&i.resizable_addLastColumn)&&r.css({display:"inline-block",height:s,left:c.position().left-l+c.outerWidth()-o}):r.hide())})},toggleTextSelection:function(t,i){var l=t.namespace+"tsresize";t.widgetOptions.resizable_.disabled=i,e("body").toggleClass(r.css.resizableNoSelect,i),i?e("body").attr("unselectable","on").bind("selectstart"+l,!1):e("body").removeAttr("unselectable").unbind("selectstart"+l)},bindings:function(i,l){var a=i.namespace+"tsresize";l.$resizable_container.children().bind("mousedown",function(t){var a,s=l.resizable_,n=e(i.namespace+"_extra_headers"),o=e(t.target).data("header");a=parseInt(o.attr("data-column"),10),s.$target=o=o.add(n.filter('[data-column="'+a+'"]')),s.target=a,s.$next=t.shiftKey||l.resizable_targetLast?o.parent().children().not(".resizable-false").filter(":last"):o.nextAll(":not(.resizable-false)").eq(0),a=parseInt(s.$next.attr("data-column"),10),s.$next=s.$next.add(n.filter('[data-column="'+a+'"]')),s.next=a,s.mouseXPosition=t.pageX,r.resizable.updateStoredSizes(i,l),r.resizable.toggleTextSelection(i,!0)}),e(document).bind("mousemove"+a,function(e){var t=l.resizable_;t.disabled&&0!==t.mouseXPosition&&t.$target&&(l.resizable_throttle?(clearTimeout(t.timer),t.timer=setTimeout(function(){r.resizable.mouseMove(i,l,e)},isNaN(l.resizable_throttle)?5:l.resizable_throttle)):r.resizable.mouseMove(i,l,e))}).bind("mouseup"+a,function(){l.resizable_.disabled&&(r.resizable.toggleTextSelection(i,!1),r.resizable.stopResize(i,l),r.resizable.setHandlePosition(i,l))}),e(t).bind("resize"+a+" resizeEnd"+a,function(){r.resizable.setHandlePosition(i,l)}),i.$table.bind("columnUpdate"+a,function(){r.resizable.setHandlePosition(i,l)}).find("thead:first").add(e(i.namespace+"_extra_table").find("thead:first")).bind("contextmenu"+a,function(){var e=0===l.resizable_.storedSizes.length;return r.resizableReset(i.table),r.resizable.setHandlePosition(i,l),l.resizable_.storedSizes=[],e})},mouseMove:function(t,i,l){if(0!==i.resizable_.mouseXPosition&&i.resizable_.$target){var a,s=0,n=i.resizable_,o=n.$next,c=n.storedSizes[n.target],d=l.pageX-n.mouseXPosition;if(n.overflow){if(c+d>0){for(n.storedSizes[n.target]+=d,r.resizable.setWidth(n.$target,n.storedSizes[n.target],!0),a=0;a<t.columns;a++)s+=n.storedSizes[a];r.resizable.setWidth(t.$table.add(e(t.namespace+"_extra_table")),s)}o.length||(n.$wrap[0].scrollLeft=t.$table.width())}else n.fullWidth?(n.storedSizes[n.target]+=d,n.storedSizes[n.next]-=d,r.resizable.setWidths(t,i)):(n.storedSizes[n.target]+=d,r.resizable.setWidths(t,i));n.mouseXPosition=l.pageX,t.$table.trigger("stickyHeadersUpdate")}},stopResize:function(e,t){var i=t.resizable_;r.resizable.updateStoredSizes(e,t),i.useStorage&&(r.storage(e.table,r.css.resizableStorage,i.storedSizes),r.storage(e.table,"tablesorter-table-resized-width",e.$table.width())),i.mouseXPosition=0,i.$target=i.$next=null,e.$table.trigger("stickyHeadersUpdate")}},r.addWidget({id:"resizable",priority:40,options:{resizable:!0,resizable_addLastColumn:!1,resizable_widths:[],resizable_throttle:!1,resizable_targetLast:!1,resizable_fullWidth:null},init:function(e,t,i,l){r.resizable.init(i,l)},remove:function(t,i,l,a){if(l.$resizable_container){var s=i.namespace+"tsresize";i.$table.add(e(i.namespace+"_extra_table")).removeClass("hasResizable").children("thead").unbind("contextmenu"+s),l.$resizable_container.remove(),r.resizable.toggleTextSelection(i,!1),r.resizableReset(t,a),e(document).unbind("mousemove"+s+" mouseup"+s)}}}),r.resizableReset=function(t,i){e(t).each(function(){var e,l,a=this.config,s=a&&a.widgetOptions,n=s.resizable_;if(t&&a&&a.$headerIndexed.length){for(n.overflow&&n.tableWidth&&(r.resizable.setWidth(a.$table,n.tableWidth,!0),n.useStorage&&r.storage(t,"tablesorter-table-resized-width","auto")),e=0;e<a.columns;e++)l=a.$headerIndexed[e],s.resizable_widths&&s.resizable_widths[e]?r.resizable.setWidth(l,s.resizable_widths[e],n.overflow):l.hasClass("resizable-false")||r.resizable.setWidth(l,"",n.overflow);a.$table.trigger("stickyHeadersUpdate"),r.storage&&!i&&r.storage(this,r.css.resizableStorage,{})}})}}(jQuery,window),function(e){"use strict";var t=e.tablesorter||{};t.addWidget({id:"saveSort",priority:20,options:{saveSort:!0},init:function(e,t,r,i){t.format(e,r,i,!0)},format:function(r,i,l,a){var s,n,o=i.$table,c=l.saveSort!==!1,d={sortList:i.sortList};i.debug&&(n=new Date),o.hasClass("hasSaveSort")?c&&r.hasInitialized&&t.storage&&(t.storage(r,"tablesorter-savesort",d),i.debug&&t.benchmark("saveSort widget: Saving last sort: "+i.sortList,n)):(o.addClass("hasSaveSort"),d="",t.storage&&(s=t.storage(r,"tablesorter-savesort"),d=s&&s.hasOwnProperty("sortList")&&e.isArray(s.sortList)?s.sortList:"",i.debug&&t.benchmark('saveSort: Last sort loaded: "'+d+'"',n),o.bind("saveSortReset",function(e){e.stopPropagation(),t.storage(r,"tablesorter-savesort","")})),a&&d&&d.length>0?i.sortList=d:r.hasInitialized&&d&&d.length>0&&o.trigger("sorton",[d]))},remove:function(e,r){r.$table.removeClass("hasSaveSort"),t.storage&&t.storage(e,"tablesorter-savesort","")}})}(jQuery),e.tablesorter}); /* custom */ $(document).ready(function(){$('.table-sortable').tablesorter({theme:'bootstrap',widgets:['uitheme','zebra','filter'],headerTemplate:'{content} {icon}',widthFixed:true,ignoreCase:true,widgetOptions:{filter_columnFilters:true,zebra:['even','odd'],filter_reset:'.reset'}});}); /* jquery.tablesorter.widgets.js */ !function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof module&&"object"==typeof module.exports?module.exports=e(require("jquery")):e(jQuery)}(function(e){return function(e,t,r){"use strict";var i=e.tablesorter||{};i.storage=function(l,a,s,n){l=e(l)[0];var o,c,d,f=!1,u={},h=l.config,p=h&&h.widgetOptions,g=n&&n.useSessionStorage||p&&p.storage_useSessionStorage?"sessionStorage":"localStorage",m=e(l),b=n&&n.id||m.attr(n&&n.group||p&&p.storage_group||"data-table-group")||p&&p.storage_tableId||l.id||e(".tablesorter").index(m),y=n&&n.url||m.attr(n&&n.page||p&&p.storage_page||"data-table-page")||p&&p.storage_fixedUrl||h&&h.fixedUrl||t.location.pathname;if(g in t)try{t[g].setItem("_tmptest","temp"),f=!0,t[g].removeItem("_tmptest")}catch(_){h&&h.debug&&i.log(g+" is not supported in this browser")}return e.parseJSON&&(f?u=e.parseJSON(t[g][a]||"null")||{}:(c=r.cookie.split(/[;\s|=]/),o=e.inArray(a,c)+1,u=0!==o?e.parseJSON(c[o]||"null")||{}:{})),(s||""===s)&&t.JSON&&JSON.hasOwnProperty("stringify")?(u[y]||(u[y]={}),u[y][b]=s,f?t[g][a]=JSON.stringify(u):(d=new Date,d.setTime(d.getTime()+31536e6),r.cookie=a+"="+JSON.stringify(u).replace(/\"/g,'"')+"; expires="+d.toGMTString()+"; path=/"),void 0):u&&u[y]?u[y][b]:""}}(jQuery,window,document),function(e){"use strict";var t=e.tablesorter||{};t.themes={bootstrap:{table:"table table-bordered table-striped",caption:"caption",header:"bootstrap-header",sortNone:"",sortAsc:"",sortDesc:"",active:"",hover:"",icons:"",iconSortNone:"bootstrap-icon-unsorted",iconSortAsc:"icon-chevron-up glyphicon glyphicon-chevron-up",iconSortDesc:"icon-chevron-down glyphicon glyphicon-chevron-down",filterRow:"",footerRow:"",footerCells:"",even:"",odd:""},jui:{table:"ui-widget ui-widget-content ui-corner-all",caption:"ui-widget-content",header:"ui-widget-header ui-corner-all ui-state-default",sortNone:"",sortAsc:"",sortDesc:"",active:"ui-state-active",hover:"ui-state-hover",icons:"ui-icon",iconSortNone:"ui-icon-carat-2-n-s",iconSortAsc:"ui-icon-carat-1-n",iconSortDesc:"ui-icon-carat-1-s",filterRow:"",footerRow:"",footerCells:"",even:"ui-widget-content",odd:"ui-state-default"}},e.extend(t.css,{wrapper:"tablesorter-wrapper"}),t.addWidget({id:"uitheme",priority:10,format:function(r,i,l){var a,s,n,o,c,d,f,u,h,p,g,m,b=t.themes,y=i.$table.add(e(i.namespace+"_extra_table")),_=i.$headers.add(e(i.namespace+"_extra_headers")),v=i.theme||"jui",w=b[v]||{},x=e.trim([w.sortNone,w.sortDesc,w.sortAsc,w.active].join(" ")),C=e.trim([w.iconSortNone,w.iconSortDesc,w.iconSortAsc].join(" "));for(i.debug&&(o=new Date),y.hasClass("tablesorter-"+v)&&i.theme===i.appliedTheme&&l.uitheme_applied||(l.uitheme_applied=!0,h=b[i.appliedTheme]||{},m=!e.isEmptyObject(h),p=m?[h.sortNone,h.sortDesc,h.sortAsc,h.active].join(" "):"",g=m?[h.iconSortNone,h.iconSortDesc,h.iconSortAsc].join(" "):"",m&&(l.zebra[0]=e.trim(" "+l.zebra[0].replace(" "+h.even,"")),l.zebra[1]=e.trim(" "+l.zebra[1].replace(" "+h.odd,"")),i.$tbodies.children().removeClass([h.even,h.odd].join(" "))),w.even&&(l.zebra[0]+=" "+w.even),w.odd&&(l.zebra[1]+=" "+w.odd),y.children("caption").removeClass(h.caption||"").addClass(w.caption),f=y.removeClass((i.appliedTheme?"tablesorter-"+(i.appliedTheme||""):"")+" "+(h.table||"")).addClass("tablesorter-"+v+" "+(w.table||"")).children("tfoot"),i.appliedTheme=i.theme,f.length&&f.children("tr").removeClass(h.footerRow||"").addClass(w.footerRow).children("th, td").removeClass(h.footerCells||"").addClass(w.footerCells),_.removeClass((m?[h.header,h.hover,p].join(" "):"")||"").addClass(w.header).not(".sorter-false").unbind("mouseenter.tsuitheme mouseleave.tsuitheme").bind("mouseenter.tsuitheme mouseleave.tsuitheme",function(t){e(this)["mouseenter"===t.type?"addClass":"removeClass"](w.hover||"")}),_.each(function(){var r=e(this);r.find("."+t.css.wrapper).length||r.wrapInner('<div class="'+t.css.wrapper+'" style="position:relative;height:100%;width:100%"></div>')}),i.cssIcon&&_.find("."+t.css.icon).removeClass(m?[h.icons,g].join(" "):"").addClass(w.icons||""),y.hasClass("hasFilters")&&y.children("thead").children("."+t.css.filterRow).removeClass(m?h.filterRow||"":"").addClass(w.filterRow||"")),a=0;a<i.columns;a++)c=i.$headers.add(e(i.namespace+"_extra_headers")).not(".sorter-false").filter('[data-column="'+a+'"]'),d=t.css.icon?c.find("."+t.css.icon):e(),u=_.not(".sorter-false").filter('[data-column="'+a+'"]:last'),u.length&&(c.removeClass(x),d.removeClass(C),u[0].sortDisabled?d.removeClass(w.icons||""):(s=w.sortNone,n=w.iconSortNone,u.hasClass(t.css.sortAsc)?(s=[w.sortAsc,w.active].join(" "),n=w.iconSortAsc):u.hasClass(t.css.sortDesc)&&(s=[w.sortDesc,w.active].join(" "),n=w.iconSortDesc),c.addClass(s),d.addClass(n||"")));i.debug&&t.benchmark("Applying "+v+" theme",o)},remove:function(e,r,i,l){if(i.uitheme_applied){var a=r.$table,s=r.appliedTheme||"jui",n=t.themes[s]||t.themes.jui,o=a.children("thead").children(),c=n.sortNone+" "+n.sortDesc+" "+n.sortAsc,d=n.iconSortNone+" "+n.iconSortDesc+" "+n.iconSortAsc;a.removeClass("tablesorter-"+s+" "+n.table),i.uitheme_applied=!1,l||(a.find(t.css.header).removeClass(n.header),o.unbind("mouseenter.tsuitheme mouseleave.tsuitheme").removeClass(n.hover+" "+c+" "+n.active).filter("."+t.css.filterRow).removeClass(n.filterRow),o.find("."+t.css.icon).removeClass(n.icons+" "+d))}}})}(jQuery),function(e){"use strict";var t=e.tablesorter||{};t.addWidget({id:"columns",priority:30,options:{columns:["primary","secondary","tertiary"]},format:function(r,i,l){var a,s,n,o,c,d,f,u,h=i.$table,p=i.$tbodies,g=i.sortList,m=g.length,b=l&&l.columns||["primary","secondary","tertiary"],y=b.length-1;for(f=b.join(" "),s=0;s<p.length;s++)a=t.processTbody(r,p.eq(s),!0),n=a.children("tr"),n.each(function(){if(c=e(this),"none"!==this.style.display&&(d=c.children().removeClass(f),g&&g[0]&&(d.eq(g[0][0]).addClass(b[0]),m>1)))for(u=1;m>u;u++)d.eq(g[u][0]).addClass(b[u]||b[y])}),t.processTbody(r,a,!1);if(o=l.columns_thead!==!1?["thead tr"]:[],l.columns_tfoot!==!1&&o.push("tfoot tr"),o.length&&(n=h.find(o.join(",")).children().removeClass(f),m))for(u=0;m>u;u++)n.filter('[data-column="'+g[u][0]+'"]').addClass(b[u]||b[y])},remove:function(r,i,l){var a,s,n=i.$tbodies,o=(l.columns||["primary","secondary","tertiary"]).join(" ");for(i.$headers.removeClass(o),i.$table.children("tfoot").children("tr").children("th, td").removeClass(o),a=0;a<n.length;a++)s=t.processTbody(r,n.eq(a),!0),s.children("tr").each(function(){e(this).children().removeClass(o)}),t.processTbody(r,s,!1)}})}(jQuery),function(e){"use strict";var t=e.tablesorter||{},r=t.css;e.extend(r,{filterRow:"tablesorter-filter-row",filter:"tablesorter-filter",filterDisabled:"disabled",filterRowHide:"hideme"}),t.addWidget({id:"filter",priority:50,options:{filter_childRows:!1,filter_childByColumn:!1,filter_columnFilters:!0,filter_columnAnyMatch:!0,filter_cellFilter:"",filter_cssFilter:"",filter_defaultFilter:{},filter_excludeFilter:{},filter_external:"",filter_filteredRow:"filtered",filter_formatter:null,filter_functions:null,filter_hideEmpty:!0,filter_hideFilters:!1,filter_ignoreCase:!0,filter_liveSearch:!0,filter_onlyAvail:"filter-onlyAvail",filter_placeholder:{search:"",select:""},filter_reset:null,filter_saveFilters:!1,filter_searchDelay:300,filter_searchFiltered:!0,filter_selectSource:null,filter_startsWith:!1,filter_useParsedData:!1,filter_serversideFiltering:!1,filter_defaultAttrib:"data-value",filter_selectSourceSeparator:"|"},format:function(e,r,i){r.$table.hasClass("hasFilters")||t.filter.init(e,r,i)},remove:function(i,l,a,s){var n,o,c=l.$table,d=l.$tbodies,f="addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(l.namespace+"filter ");if(c.removeClass("hasFilters").unbind(f.replace(/\s+/g," ")).find("."+r.filterRow).remove(),!s){for(n=0;n<d.length;n++)o=t.processTbody(i,d.eq(n),!0),o.children().removeClass(a.filter_filteredRow).show(),t.processTbody(i,o,!1);a.filter_reset&&e(document).undelegate(a.filter_reset,"click.tsfilter")}}}),t.filter={regex:{regex:/^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/,child:/tablesorter-childRow/,filtered:/filtered/,type:/undefined|number/,exact:/(^[\"\'=]+)|([\"\'=]+$)/g,nondigit:/[^\w,. \-()]/g,operators:/[<>=]/g,query:"(q|query)"},types:{or:function(r,i,l){if(/\|/.test(i.iFilter)||t.filter.regex.orSplit.test(i.filter)){var a,s,n,o,c=e.extend({},i),d=i.index,f=i.parsed[d],u=i.filter.split(t.filter.regex.orSplit),h=i.iFilter.split(t.filter.regex.orSplit),p=u.length;for(a=0;p>a;a++)if(c.nestedFilters=!0,c.filter=""+(t.filter.parseFilter(r,u[a],d,f)||""),c.iFilter=""+(t.filter.parseFilter(r,h[a],d,f)||""),n="("+(t.filter.parseFilter(r,c.filter,d,f)||"")+")",o=new RegExp(i.isMatch?n:"^"+n+"$",r.widgetOptions.filter_ignoreCase?"i":""),s=o.test(c.exact)||t.filter.processTypes(r,c,l))return s;return s||!1}return null},and:function(r,i,l){if(t.filter.regex.andTest.test(i.filter)){var a,s,n,o,c,d=e.extend({},i),f=i.index,u=i.parsed[f],h=i.filter.split(t.filter.regex.andSplit),p=i.iFilter.split(t.filter.regex.andSplit),g=h.length;for(a=0;g>a;a++)d.nestedFilters=!0,d.filter=""+(t.filter.parseFilter(r,h[a],f,u)||""),d.iFilter=""+(t.filter.parseFilter(r,p[a],f,u)||""),o=("("+(t.filter.parseFilter(r,d.filter,f,u)||"")+")").replace(/\?/g,"\\S{1}").replace(/\*/g,"\\S*"),c=new RegExp(i.isMatch?o:"^"+o+"$",r.widgetOptions.filter_ignoreCase?"i":""),n=c.test(d.exact)||t.filter.processTypes(r,d,l),s=0===a?n:s&&n;return s||!1}return null},regex:function(e,r){if(t.filter.regex.regex.test(r.filter)){var i,l=r.filter_regexCache[r.index]||t.filter.regex.regex.exec(r.filter),a=l instanceof RegExp;try{a||(r.filter_regexCache[r.index]=l=new RegExp(l[1],l[2])),i=l.test(r.exact)}catch(s){i=!1}return i}return null},operators:function(r,i){if(/^[<>]=?/.test(i.iFilter)&&""!==i.iExact){var l,a,s,n=r.table,o=i.index,c=i.parsed[o],d=t.formatFloat(i.iFilter.replace(t.filter.regex.operators,""),n),f=r.parsers[o],u=d;return(c||"numeric"===f.type)&&(s=e.trim(""+i.iFilter.replace(t.filter.regex.operators,"")),a=t.filter.parseFilter(r,s,o,!0),d="number"!=typeof a||""===a||isNaN(a)?d:a),!c&&"numeric"!==f.type||isNaN(d)||"undefined"==typeof i.cache?(s=isNaN(i.iExact)?i.iExact.replace(t.filter.regex.nondigit,""):i.iExact,l=t.formatFloat(s,n)):l=i.cache,/>/.test(i.iFilter)?a=/>=/.test(i.iFilter)?l>=d:l>d:/</.test(i.iFilter)&&(a=/<=/.test(i.iFilter)?d>=l:d>l),a||""!==u||(a=!0),a}return null},notMatch:function(r,i){if(/^\!/.test(i.iFilter)){var l,a=i.iFilter.replace("!",""),s=t.filter.parseFilter(r,a,i.index,i.parsed[i.index])||"";return t.filter.regex.exact.test(s)?(s=s.replace(t.filter.regex.exact,""),""===s?!0:e.trim(s)!==i.iExact):(l=i.iExact.search(e.trim(s)),""===s?!0:!(r.widgetOptions.filter_startsWith?0===l:l>=0))}return null},exact:function(r,i){if(t.filter.regex.exact.test(i.iFilter)){var l=i.iFilter.replace(t.filter.regex.exact,""),a=t.filter.parseFilter(r,l,i.index,i.parsed[i.index])||"";return i.anyMatch?e.inArray(a,i.rowArray)>=0:a==i.iExact}return null},range:function(e,r){if(t.filter.regex.toTest.test(r.iFilter)){var i,l,a,s,n=e.table,o=r.index,c=r.parsed[o],d=r.iFilter.split(t.filter.regex.toSplit);return l=d[0].replace(t.filter.regex.nondigit,"")||"",a=t.formatFloat(t.filter.parseFilter(e,l,o,c),n),l=d[1].replace(t.filter.regex.nondigit,"")||"",s=t.formatFloat(t.filter.parseFilter(e,l,o,c),n),(c||"numeric"===e.parsers[o].type)&&(i=e.parsers[o].format(""+d[0],n,e.$headers.eq(o),o),a=""===i||isNaN(i)?a:i,i=e.parsers[o].format(""+d[1],n,e.$headers.eq(o),o),s=""===i||isNaN(i)?s:i),!c&&"numeric"!==e.parsers[o].type||isNaN(a)||isNaN(s)?(l=isNaN(r.iExact)?r.iExact.replace(t.filter.regex.nondigit,""):r.iExact,i=t.formatFloat(l,n)):i=r.cache,a>s&&(l=a,a=s,s=l),i>=a&&s>=i||""===a||""===s}return null},wild:function(e,r){if(/[\?\*\|]/.test(r.iFilter)){var i=r.index,l=r.parsed[i],a=""+(t.filter.parseFilter(e,r.iFilter,i,l)||"");return!/\?\*/.test(a)&&r.nestedFilters&&(a=r.isMatch?a:"^("+a+")$"),new RegExp(a.replace(/\?/g,"\\S{1}").replace(/\*/g,"\\S*"),e.widgetOptions.filter_ignoreCase?"i":"").test(r.exact)}return null},fuzzy:function(e,r){if(/^~/.test(r.iFilter)){var i,l=0,a=r.iExact.length,s=r.iFilter.slice(1),n=t.filter.parseFilter(e,s,r.index,r.parsed[r.index])||"";for(i=0;a>i;i++)r.iExact[i]===n[l]&&(l+=1);return l===n.length?!0:!1}return null}},init:function(i,l,a){t.language=e.extend(!0,{},{to:"to",or:"or",and:"and"},t.language);var s,n,o,c,d,f,u,h,p,g=t.filter.regex;if(l.$table.addClass("hasFilters"),a.searchTimer=null,a.filter_initTimer=null,a.filter_formatterCount=0,a.filter_formatterInit=[],a.filter_anyColumnSelector='[data-column="all"],[data-column="any"]',a.filter_multipleColumnSelector='[data-column*="-"],[data-column*=","]',u="\\{"+t.filter.regex.query+"\\}",e.extend(g,{child:new RegExp(l.cssChildRow),filtered:new RegExp(a.filter_filteredRow),alreadyFiltered:new RegExp("(\\s+("+t.language.or+"|-|"+t.language.to+")\\s+)","i"),toTest:new RegExp("\\s+(-|"+t.language.to+")\\s+","i"),toSplit:new RegExp("(?:\\s+(?:-|"+t.language.to+")\\s+)","gi"),andTest:new RegExp("\\s+("+t.language.and+"|&&)\\s+","i"),andSplit:new RegExp("(?:\\s+(?:"+t.language.and+"|&&)\\s+)","gi"),orSplit:new RegExp("(?:\\s+(?:"+t.language.or+")\\s+|\\|)","gi"),iQuery:new RegExp(u,"i"),igQuery:new RegExp(u,"ig")}),u=l.$headers.filter(".filter-false, .parser-false").length,a.filter_columnFilters!==!1&&u!==l.$headers.length&&t.filter.buildRow(i,l,a),o="addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(l.namespace+"filter "),l.$table.bind(o,function(s,n){return u=a.filter_hideEmpty&&e.isEmptyObject(l.cache)&&!(l.delayInit&&"appendCache"===s.type),l.$table.find("."+r.filterRow).toggleClass(a.filter_filteredRow,u),/(search|filter)/.test(s.type)||(s.stopPropagation(),t.filter.buildDefault(i,!0)),"filterReset"===s.type?(l.$table.find("."+r.filter).add(a.filter_$externalFilters).val(""),t.filter.searching(i,[])):"filterEnd"===s.type?t.filter.buildDefault(i,!0):(n="search"===s.type?n:"updateComplete"===s.type?l.$table.data("lastSearch"):"",/(update|add)/.test(s.type)&&"updateComplete"!==s.type&&(l.lastCombinedFilter=null,l.lastSearch=[]),t.filter.searching(i,n,!0)),!1}),a.filter_reset&&(a.filter_reset instanceof e?a.filter_reset.click(function(){l.$table.trigger("filterReset")}):e(a.filter_reset).length&&e(document).undelegate(a.filter_reset,"click.tsfilter").delegate(a.filter_reset,"click.tsfilter",function(){l.$table.trigger("filterReset")})),a.filter_functions)for(d=0;d<l.columns;d++)if(h=t.getColumnData(i,a.filter_functions,d))if(c=l.$headerIndexed[d].removeClass("filter-select"),p=!(c.hasClass("filter-false")||c.hasClass("parser-false")),s="",h===!0&&p)t.filter.buildSelect(i,d);else if("object"==typeof h&&p){for(n in h)"string"==typeof n&&(s+=""===s?'<option value="">'+(c.data("placeholder")||c.attr("data-placeholder")||a.filter_placeholder.select||"")+"</option>":"",u=n,o=n,n.indexOf(a.filter_selectSourceSeparator)>=0&&(u=n.split(a.filter_selectSourceSeparator),o=u[1],u=u[0]),s+="<option "+(o===u?"":'data-function-name="'+n+'" ')+'value="'+u+'">'+o+"</option>");l.$table.find("thead").find("select."+r.filter+'[data-column="'+d+'"]').append(s),o=a.filter_selectSource,h=e.isFunction(o)?!0:t.getColumnData(i,o,d),h&&t.filter.buildSelect(l.table,d,"",!0,c.hasClass(a.filter_onlyAvail))}t.filter.buildDefault(i,!0),t.filter.bindSearch(i,l.$table.find("."+r.filter),!0),a.filter_external&&t.filter.bindSearch(i,a.filter_external),a.filter_hideFilters&&t.filter.hideFilters(i,l),l.showProcessing&&(o="filterStart filterEnd ".split(" ").join(l.namespace+"filter "),l.$table.unbind(o.replace(/\s+/g," ")).bind(o,function(a,s){c=s?l.$table.find("."+r.header).filter("[data-column]").filter(function(){return""!==s[e(this).data("column")]}):"",t.isProcessing(i,"filterStart"===a.type,s?c:"")})),l.filteredRows=l.totalRows,o="tablesorter-initialized pagerBeforeInitialized ".split(" ").join(l.namespace+"filter "),l.$table.unbind(o.replace(/\s+/g," ")).bind(o,function(){var e=this.config.widgetOptions;f=t.filter.setDefaults(i,l,e)||[],f.length&&(l.delayInit&&""===f.join("")||t.setFilters(i,f,!0)),l.$table.trigger("filterFomatterUpdate"),setTimeout(function(){e.filter_initialized||t.filter.filterInitComplete(l)},100)}),l.pager&&l.pager.initialized&&!a.filter_initialized&&(l.$table.trigger("filterFomatterUpdate"),setTimeout(function(){t.filter.filterInitComplete(l)},100))},formatterUpdated:function(e,t){var r=e.closest("table")[0].config.widgetOptions;r.filter_initialized||(r.filter_formatterInit[t]=1)},filterInitComplete:function(r){var i,l,a=r.widgetOptions,s=0,n=function(){a.filter_initialized=!0,r.$table.trigger("filterInit",r),t.filter.findRows(r.table,r.$table.data("lastSearch")||[])};if(e.isEmptyObject(a.filter_formatter))n();else{for(l=a.filter_formatterInit.length,i=0;l>i;i++)1===a.filter_formatterInit[i]&&s++;clearTimeout(a.filter_initTimer),a.filter_initialized||s!==a.filter_formatterCount?a.filter_initialized||(a.filter_initTimer=setTimeout(function(){n()},500)):n()}},setDefaults:function(r,i,l){var a,s,n,o,c,d=t.getFilters(r)||[];if(l.filter_saveFilters&&t.storage&&(s=t.storage(r,"tablesorter-filters")||[],a=e.isArray(s),a&&""===s.join("")||!a||(d=s)),""===d.join(""))for(c=i.$headers.add(l.filter_$externalFilters).filter("["+l.filter_defaultAttrib+"]"),n=0;n<=i.columns;n++)o=n===i.columns?"all":n,d[n]=c.filter('[data-column="'+o+'"]').attr(l.filter_defaultAttrib)||d[n]||"";return i.$table.data("lastSearch",d),d},parseFilter:function(e,t,r,i){return i?e.parsers[r].format(t,e.table,[],r):t},buildRow:function(i,l,a){var s,n,o,c,d,f,u,h,p=a.filter_cellFilter,g=l.columns,m=e.isArray(p),b='<tr role="row" class="'+r.filterRow+" "+l.cssIgnoreRow+'">';for(n=0;g>n;n++)b+="<td",b+=m?p[n]?' class="'+p[n]+'"':"":""!==p?' class="'+p+'"':"",b+="></td>";for(l.$filters=e(b+="</tr>").appendTo(l.$table.children("thead").eq(0)).find("td"),n=0;g>n;n++)d=!1,o=l.$headerIndexed[n],u=t.getColumnData(i,a.filter_functions,n),c=a.filter_functions&&u&&"function"!=typeof u||o.hasClass("filter-select"),s=t.getColumnData(i,l.headers,n),d="false"===t.getData(o[0],s,"filter")||"false"===t.getData(o[0],s,"parser"),c?b=e("<select>").appendTo(l.$filters.eq(n)):(u=t.getColumnData(i,a.filter_formatter,n),u?(a.filter_formatterCount++,b=u(l.$filters.eq(n),n),b&&0===b.length&&(b=l.$filters.eq(n).children("input")),b&&(0===b.parent().length||b.parent().length&&b.parent()[0]!==l.$filters[n])&&l.$filters.eq(n).append(b)):b=e('<input type="search">').appendTo(l.$filters.eq(n)),b&&(h=o.data("placeholder")||o.attr("data-placeholder")||a.filter_placeholder.search||"",b.attr("placeholder",h))),b&&(f=(e.isArray(a.filter_cssFilter)?"undefined"!=typeof a.filter_cssFilter[n]?a.filter_cssFilter[n]||"":"":a.filter_cssFilter)||"",b.addClass(r.filter+" "+f).attr("data-column",n),d&&(b.attr("placeholder","").addClass(r.filterDisabled)[0].disabled=!0))},bindSearch:function(r,i,l){if(r=e(r)[0],i=e(i),i.length){var a,s=r.config,n=s.widgetOptions,o=s.namespace+"filter",c=n.filter_$externalFilters;l!==!0&&(a=n.filter_anyColumnSelector+","+n.filter_multipleColumnSelector,n.filter_$anyMatch=i.filter(a),n.filter_$externalFilters=c&&c.length?n.filter_$externalFilters.add(i):i,t.setFilters(r,s.$table.data("lastSearch")||[],l===!1)),a="keypress keyup search change ".split(" ").join(o+" "),i.attr("data-lastSearchTime",(new Date).getTime()).unbind(a.replace(/\s+/g," ")).bind("keyup"+o,function(i){if(e(this).attr("data-lastSearchTime",(new Date).getTime()),27===i.which)this.value="";else{if(n.filter_liveSearch===!1)return;if(""!==this.value&&("number"==typeof n.filter_liveSearch&&this.value.length<n.filter_liveSearch||13!==i.which&&8!==i.which&&(i.which<32||i.which>=37&&i.which<=40)))return}t.filter.searching(r,!0,!0)}).bind("search change keypress ".split(" ").join(o+" "),function(i){var l=e(this).data("column");(13===i.which||"search"===i.type||"change"===i.type&&this.value!==s.lastSearch[l])&&(i.preventDefault(),e(this).attr("data-lastSearchTime",(new Date).getTime()),t.filter.searching(r,!1,!0))})}},searching:function(e,r,i){var l=e.config.widgetOptions;clearTimeout(l.searchTimer),"undefined"==typeof r||r===!0?l.searchTimer=setTimeout(function(){t.filter.checkFilters(e,r,i)},l.filter_liveSearch?l.filter_searchDelay:10):t.filter.checkFilters(e,r,i)},checkFilters:function(i,l,a){var s=i.config,n=s.widgetOptions,o=e.isArray(l),c=o?l:t.getFilters(i,!0),d=(c||[]).join("");return e.isEmptyObject(s.cache)?void(s.delayInit&&s.pager&&s.pager.initialized&&s.$table.trigger("updateCache",[function(){t.filter.checkFilters(i,!1,a)}])):(o&&(t.setFilters(i,c,!1,a!==!0),n.filter_initialized||(s.lastCombinedFilter="")),n.filter_hideFilters&&s.$table.find("."+r.filterRow).trigger(""===d?"mouseleave":"mouseenter"),s.lastCombinedFilter!==d||l===!1?(l===!1&&(s.lastCombinedFilter=null,s.lastSearch=[]),n.filter_initialized&&s.$table.trigger("filterStart",[c]),s.showProcessing?void setTimeout(function(){return t.filter.findRows(i,c,d),!1},30):(t.filter.findRows(i,c,d),!1)):void 0)},hideFilters:function(i,l){var a;l.$table.find("."+r.filterRow).bind("mouseenter mouseleave",function(t){var i=t,s=e(this);clearTimeout(a),a=setTimeout(function(){/enter|over/.test(i.type)?s.removeClass(r.filterRowHide):e(document.activeElement).closest("tr")[0]!==s[0]&&""===l.lastCombinedFilter&&s.addClass(r.filterRowHide)},200)}).find("input, select").bind("focus blur",function(i){var s=i,n=e(this).closest("tr");clearTimeout(a),a=setTimeout(function(){clearTimeout(a),""===t.getFilters(l.$table).join("")&&n.toggleClass(r.filterRowHide,"focus"!==s.type)},200)})},defaultFilter:function(r,i){if(""===r)return r;var l=t.filter.regex.iQuery,a=i.match(t.filter.regex.igQuery).length,s=a>1?e.trim(r).split(/\s/):[e.trim(r)],n=s.length-1,o=0,c=i;for(1>n&&a>1&&(s[1]=s[0]);l.test(c);)c=c.replace(l,s[o++]||""),l.test(c)&&n>o&&""!==(s[o]||"")&&(c=i.replace(l,c));return c},getLatestSearch:function(t){return t?t.sort(function(t,r){return e(r).attr("data-lastSearchTime")-e(t).attr("data-lastSearchTime")}):t||e()},multipleColumns:function(r,i){var l,a,s,n,o,c,d,f,u,h=r.widgetOptions,p=h.filter_initialized||!i.filter(h.filter_anyColumnSelector).length,g=[],m=e.trim(t.filter.getLatestSearch(i).attr("data-column")||"");if(p&&/-/.test(m))for(a=m.match(/(\d+)\s*-\s*(\d+)/g),u=a.length,f=0;u>f;f++){for(s=a[f].split(/\s*-\s*/),n=parseInt(s[0],10)||0,o=parseInt(s[1],10)||r.columns-1,n>o&&(l=n,n=o,o=l),o>=r.columns&&(o=r.columns-1);o>=n;n++)g.push(n);m=m.replace(a[f],"")}if(p&&/,/.test(m))for(c=m.split(/\s*,\s*/),u=c.length,d=0;u>d;d++)""!==c[d]&&(f=parseInt(c[d],10),f<r.columns&&g.push(f));if(!g.length)for(f=0;f<r.columns;f++)g.push(f);return g},processTypes:function(r,i,l){var a,s=null,n=null;for(a in t.filter.types)e.inArray(a,l.excludeMatch)<0&&null===n&&(n=t.filter.types[a](r,i,l),null!==n&&(s=n));return s},processRow:function(r,i,l){var a,s,n,o,c,d,f,u,h=t.filter.regex,p=r.widgetOptions,g=!0;if(i.$cells=i.$row.children(),i.anyMatchFlag){if(a=t.filter.multipleColumns(r,p.filter_$anyMatch),i.anyMatch=!0,i.isMatch=!0,i.rowArray=i.$cells.map(function(l){return e.inArray(l,a)>-1?(i.parsed[l]?u=i.cacheArray[l]:(u=i.rawArray[l],u=e.trim(p.filter_ignoreCase?u.toLowerCase():u),r.sortLocaleCompare&&(u=t.replaceAccents(u))),u):void 0}).get(),i.filter=i.anyMatchFilter,i.iFilter=i.iAnyMatchFilter,i.exact=i.rowArray.join(" "),i.iExact=p.filter_ignoreCase?i.exact.toLowerCase():i.exact,i.cache=i.cacheArray.slice(0,-1).join(" "),l.excludeMatch=l.noAnyMatch,c=t.filter.processTypes(r,i,l),null!==c)g=c;else if(p.filter_startsWith)for(g=!1,a=r.columns;!g&&a>0;)a--,g=g||0===i.rowArray[a].indexOf(i.iFilter);else g=(i.iExact+i.childRowText).indexOf(i.iFilter)>=0;if(i.anyMatch=!1,i.filters.join("")===i.filter)return g}for(a=0;a<r.columns;a++)i.filter=i.filters[a],i.index=a,l.excludeMatch=l.excludeFilter[a],i.filter&&(i.cache=i.cacheArray[a],p.filter_useParsedData||i.parsed[a]?i.exact=i.cache:(n=i.rawArray[a]||"",i.exact=r.sortLocaleCompare?t.replaceAccents(n):n),i.iExact=!h.type.test(typeof i.exact)&&p.filter_ignoreCase?i.exact.toLowerCase():i.exact,i.isMatch=r.$headerIndexed[i.index].hasClass("filter-match"),n=g,f=p.filter_columnFilters?r.$filters.add(r.$externalFilters).filter('[data-column="'+a+'"]').find("select option:selected").attr("data-function-name")||"":"",r.sortLocaleCompare&&(i.filter=t.replaceAccents(i.filter)),o=!0,p.filter_defaultFilter&&h.iQuery.test(l.defaultColFilter[a])&&(i.filter=t.filter.defaultFilter(i.filter,l.defaultColFilter[a]),o=!1),i.iFilter=p.filter_ignoreCase?(i.filter||"").toLowerCase():i.filter,d=l.functions[a],s=r.$headerIndexed[a].hasClass("filter-select"),c=null,(d||s&&o)&&(d===!0||s?c=i.isMatch?i.iExact.search(i.iFilter)>=0:i.filter===i.exact:"function"==typeof d?c=d(i.exact,i.cache,i.filter,a,i.$row,r,i):"function"==typeof d[f||i.filter]&&(u=f||i.filter,c=d[u](i.exact,i.cache,i.filter,a,i.$row,r,i))),null===c?(c=t.filter.processTypes(r,i,l),null!==c?n=c:(u=(i.iExact+i.childRowText).indexOf(t.filter.parseFilter(r,i.iFilter,a,i.parsed[a])),n=!p.filter_startsWith&&u>=0||p.filter_startsWith&&0===u)):n=c,g=n?g:!1);return g},findRows:function(r,i,l){if(r.config.lastCombinedFilter!==l&&r.config.widgetOptions.filter_initialized){var a,s,n,o,c,d,f,u,h,p,g,m,b,y,_,v,w,x,C,z,S,$,F=e.extend([],i),R=t.filter.regex,k=r.config,T=k.widgetOptions,A={anyMatch:!1,filters:i,filter_regexCache:[]},H={noAnyMatch:["range","notMatch","operators"],functions:[],excludeFilter:[],defaultColFilter:[],defaultAnyFilter:t.getColumnData(r,T.filter_defaultFilter,k.columns,!0)||""};for(A.parsed=k.$headers.map(function(i){return k.parsers&&k.parsers[i]&&k.parsers[i].parsed||t.getData&&"parsed"===t.getData(k.$headerIndexed[i],t.getColumnData(r,k.headers,i),"filter")||e(this).hasClass("filter-parsed")}).get(),u=0;u<k.columns;u++)H.functions[u]=t.getColumnData(r,T.filter_functions,u),H.defaultColFilter[u]=t.getColumnData(r,T.filter_defaultFilter,u)||"",H.excludeFilter[u]=(t.getColumnData(r,T.filter_excludeFilter,u,!0)||"").split(/\s+/);for(k.debug&&(t.log("Filter: Starting filter widget search",i),b=new Date),k.filteredRows=0,k.totalRows=0,l=(F||[]).join(""),d=0;d<k.$tbodies.length;d++){if(f=t.processTbody(r,k.$tbodies.eq(d),!0),u=k.columns,s=k.cache[d].normalized,o=e(e.map(s,function(e){return e[u].$row.get()})),""===l||T.filter_serversideFiltering)o.removeClass(T.filter_filteredRow).not("."+k.cssChildRow).css("display","");else{if(o=o.not("."+k.cssChildRow),a=o.length,(T.filter_$anyMatch&&T.filter_$anyMatch.length||"undefined"!=typeof i[k.columns])&&(A.anyMatchFlag=!0,A.anyMatchFilter=""+(i[k.columns]||T.filter_$anyMatch&&t.filter.getLatestSearch(T.filter_$anyMatch).val()||""),T.filter_columnAnyMatch)){for(x=A.anyMatchFilter.split(R.andSplit),C=!1,_=0;_<x.length;_++)z=x[_].split(":"),z.length>1&&(S=parseInt(z[0],10)-1,S>=0&&S<k.columns&&(i[S]=z[1],x.splice(_,1),_--,C=!0));C&&(A.anyMatchFilter=x.join(" && "))}if(w=T.filter_searchFiltered,g=k.lastSearch||k.$table.data("lastSearch")||[],w)for(_=0;u+1>_;_++)y=i[_]||"",w||(_=u),w=!(!w||!g.length||0!==y.indexOf(g[_]||"")||R.alreadyFiltered.test(y)||/[=\"\|!]/.test(y)||/(>=?\s*-\d)/.test(y)||/(<=?\s*\d)/.test(y)||""!==y&&k.$filters&&k.$filters.eq(_).find("select").length&&!k.$headerIndexed[_].hasClass("filter-match"));for(v=o.not("."+T.filter_filteredRow).length,w&&0===v&&(w=!1),k.debug&&t.log("Filter: Searching through "+(w&&a>v?v:"all")+" rows"),A.anyMatchFlag&&(k.sortLocaleCompare&&(A.anyMatchFilter=t.replaceAccents(A.anyMatchFilter)),T.filter_defaultFilter&&R.iQuery.test(H.defaultAnyFilter)&&(A.anyMatchFilter=t.filter.defaultFilter(A.anyMatchFilter,H.defaultAnyFilter),w=!1),A.iAnyMatchFilter=T.filter_ignoreCase&&k.ignoreCase?A.anyMatchFilter.toLowerCase():A.anyMatchFilter),c=0;a>c;c++)if($=o[c].className,h=c&&R.child.test($),!(h||w&&R.filtered.test($))){if(A.$row=o.eq(c),A.cacheArray=s[c],n=A.cacheArray[k.columns],A.rawArray=n.raw,A.childRowText="",!T.filter_childByColumn){for($="",p=n.child,_=0;_<p.length;_++)$+=" "+p[_].join("")||"";A.childRowText=T.filter_childRows?T.filter_ignoreCase?$.toLowerCase():$:""}if(m=t.filter.processRow(k,A,H),p=n.$row.filter(":gt( 0 )"),T.filter_childRows&&p.length){if(T.filter_childByColumn)for(_=0;_<p.length;_++)A.$row=p.eq(_),A.cacheArray=n.child[_],A.rawArray=A.cacheArray,m=m||t.filter.processRow(k,A,H);p.toggleClass(T.filter_filteredRow,!m)}n.$row.toggleClass(T.filter_filteredRow,!m)[0].display=m?"":"none"}}k.filteredRows+=o.not("."+T.filter_filteredRow).length,k.totalRows+=o.length,t.processTbody(r,f,!1)}k.lastCombinedFilter=l,k.lastSearch=F,k.$table.data("lastSearch",F),T.filter_saveFilters&&t.storage&&t.storage(r,"tablesorter-filters",F),k.debug&&t.benchmark("Completed filter widget search",b),T.filter_initialized&&k.$table.trigger("filterEnd",k),setTimeout(function(){k.$table.trigger("applyWidgets")},0)}},getOptionSource:function(r,i,l){r=e(r)[0];var a,s,n,o,c=r.config,d=c.widgetOptions,f=[],u=!1,h=d.filter_selectSource,p=c.$table.data("lastSearch")||[],g=e.isFunction(h)?!0:t.getColumnData(r,h,i);if(l&&""!==p[i]&&(l=!1),g===!0)u=h(r,i,l);else{if(g instanceof e||"string"===e.type(g)&&g.indexOf("</option>")>=0)return g;e.isArray(g)?u=g:"object"===e.type(h)&&g&&(u=g(r,i,l))}if(u===!1&&(u=t.filter.getOptions(r,i,l)),u=e.grep(u,function(t,r){return e.inArray(t,u)===r}),c.$headerIndexed[i].hasClass("filter-select-nosort"))return u;for(o=u.length,n=0;o>n;n++)s=u[n],f.push({t:s,p:c.parsers&&c.parsers.length&&c.parsers[i].format(s,r,[],i)||s});for(a=c.textSorter||"",f.sort(function(l,s){var n=l.p.toString(),o=s.p.toString();return e.isFunction(a)?a(n,o,!0,i,r):"object"==typeof a&&a.hasOwnProperty(i)?a[i](n,o,!0,i,r):t.sortNatural?t.sortNatural(n,o):!0}),u=[],o=f.length,n=0;o>n;n++)u.push(f[n].t);return u},getOptions:function(t,r,i){t=e(t)[0];var l,a,s,n,o,c=t.config,d=c.widgetOptions,f=[];for(a=0;a<c.$tbodies.length;a++)for(o=c.cache[a],s=c.cache[a].normalized.length,l=0;s>l;l++)n=o.row?o.row[l]:o.normalized[l][c.columns].$row[0],i&&n.className.match(d.filter_filteredRow)||f.push(d.filter_useParsedData||c.parsers[r].parsed||c.$headerIndexed[r].hasClass("filter-parsed")?""+o.normalized[l][r]:o.normalized[l][c.columns].raw[r]);return f},buildSelect:function(i,l,a,s,n){if(i=e(i)[0],l=parseInt(l,10),i.config.cache&&!e.isEmptyObject(i.config.cache)){var o,c,d,f,u,h,p=i.config,g=p.widgetOptions,m=p.$headerIndexed[l],b='<option value="">'+(m.data("placeholder")||m.attr("data-placeholder")||g.filter_placeholder.select||"")+"</option>",y=p.$table.find("thead").find("select."+r.filter+'[data-column="'+l+'"]').val();if(("undefined"==typeof a||""===a)&&(a=t.filter.getOptionSource(i,l,n)),e.isArray(a)){for(o=0;o<a.length;o++)d=a[o]=(""+a[o]).replace(/\"/g,"&quot;"),c=d,d.indexOf(g.filter_selectSourceSeparator)>=0&&(f=d.split(g.filter_selectSourceSeparator),c=f[0],d=f[1]),b+=""!==a[o]?"<option "+(c===d?"":'data-function-name="'+a[o]+'" ')+'value="'+c+'">'+d+"</option>":"";a=[]}u=(p.$filters?p.$filters:p.$table.children("thead")).find("."+r.filter),g.filter_$externalFilters&&(u=u&&u.length?u.add(g.filter_$externalFilters):g.filter_$externalFilters),h=u.filter('select[data-column="'+l+'"]'),h.length&&(h[s?"html":"append"](b),e.isArray(a)||h.append(a).val(y),h.val(y))}},buildDefault:function(e,r){var i,l,a,s=e.config,n=s.widgetOptions,o=s.columns;for(i=0;o>i;i++)l=s.$headerIndexed[i],a=!(l.hasClass("filter-false")||l.hasClass("parser-false")),(l.hasClass("filter-select")||t.getColumnData(e,n.filter_functions,i)===!0)&&a&&t.filter.buildSelect(e,i,"",r,l.hasClass(n.filter_onlyAvail))}},t.getFilters=function(i,l,a,s){var n,o,c,d,f=!1,u=i?e(i)[0].config:"",h=u?u.widgetOptions:"";if(l!==!0&&h&&!h.filter_columnFilters||e.isArray(a)&&a.join("")===u.lastCombinedFilter)return e(i).data("lastSearch");if(u&&(u.$filters&&(o=u.$filters.find("."+r.filter)),h.filter_$externalFilters&&(o=o&&o.length?o.add(h.filter_$externalFilters):h.filter_$externalFilters),o&&o.length))for(f=a||[],n=0;n<u.columns+1;n++)d=n===u.columns?h.filter_anyColumnSelector+","+h.filter_multipleColumnSelector:'[data-column="'+n+'"]',c=o.filter(d),c.length&&(c=t.filter.getLatestSearch(c),e.isArray(a)?(s&&c.length>1&&(c=c.slice(1)),n===u.columns&&(d=c.filter(h.filter_anyColumnSelector),c=d.length?d:c),c.val(a[n]).trigger("change.tsfilter")):(f[n]=c.val()||"",n===u.columns?c.slice(1).filter('[data-column*="'+c.attr("data-column")+'"]').val(f[n]):c.slice(1).val(f[n])),n===u.columns&&c.length&&(h.filter_$anyMatch=c)); return 0===f.length&&(f=!1),f},t.setFilters=function(r,i,l,a){var s=r?e(r)[0].config:"",n=t.getFilters(r,!0,i,a);return s&&l&&(s.lastCombinedFilter=null,s.lastSearch=[],t.filter.searching(s.table,i,a),s.$table.trigger("filterFomatterUpdate")),!!n}}(jQuery),function(e,t){"use strict";var r=e.tablesorter||{};e.extend(r.css,{sticky:"tablesorter-stickyHeader",stickyVis:"tablesorter-sticky-visible",stickyHide:"tablesorter-sticky-hidden",stickyWrap:"tablesorter-sticky-wrapper"}),r.addHeaderResizeEvent=function(t,r,i){if(t=e(t)[0],t.config){var l={timer:250},a=e.extend({},l,i),s=t.config,n=s.widgetOptions,o=function(e){var t,r,i,l,a,o,c=s.$headers.length;for(n.resize_flag=!0,r=[],t=0;c>t;t++)i=s.$headers.eq(t),l=i.data("savedSizes")||[0,0],a=i[0].offsetWidth,o=i[0].offsetHeight,(a!==l[0]||o!==l[1])&&(i.data("savedSizes",[a,o]),r.push(i[0]));r.length&&e!==!1&&s.$table.trigger("resize",[r]),n.resize_flag=!1};return o(!1),clearInterval(n.resize_timer),r?(n.resize_flag=!1,!1):void(n.resize_timer=setInterval(function(){n.resize_flag||o()},a.timer))}},r.addWidget({id:"stickyHeaders",priority:60,options:{stickyHeaders:"",stickyHeaders_attachTo:null,stickyHeaders_xScroll:null,stickyHeaders_yScroll:null,stickyHeaders_offset:0,stickyHeaders_filteredToTop:!0,stickyHeaders_cloneId:"-sticky",stickyHeaders_addResizeEvent:!0,stickyHeaders_includeCaption:!0,stickyHeaders_zIndex:2},format:function(i,l,a){if(!(l.$table.hasClass("hasStickyHeaders")||e.inArray("filter",l.widgets)>=0&&!l.$table.hasClass("hasFilters"))){var s,n,o,c,d=l.$table,f=e(a.stickyHeaders_attachTo),u=l.namespace+"stickyheaders ",h=e(a.stickyHeaders_yScroll||a.stickyHeaders_attachTo||t),p=e(a.stickyHeaders_xScroll||a.stickyHeaders_attachTo||t),g=d.children("thead:first"),m=g.children("tr").not(".sticky-false").children(),b=d.children("tfoot"),y=isNaN(a.stickyHeaders_offset)?e(a.stickyHeaders_offset):"",_=y.length?y.height()||0:parseInt(a.stickyHeaders_offset,10)||0,v=d.parent().closest("."+r.css.table).hasClass("hasStickyHeaders")?d.parent().closest("table.tablesorter")[0].config.widgetOptions.$sticky.parent():[],w=v.length?v.height():0,x=a.$sticky=d.clone().addClass("containsStickyHeaders "+r.css.sticky+" "+a.stickyHeaders+" "+l.namespace.slice(1)+"_extra_table").wrap('<div class="'+r.css.stickyWrap+'">'),C=x.parent().addClass(r.css.stickyHide).css({position:f.length?"absolute":"fixed",padding:parseInt(x.parent().parent().css("padding-left"),10),top:_+w,left:0,visibility:"hidden",zIndex:a.stickyHeaders_zIndex||2}),z=x.children("thead:first"),S="",$=0,F=function(e,r){var i,l,a,s,n,o=e.filter(":visible"),c=o.length;for(i=0;c>i;i++)s=r.filter(":visible").eq(i),n=o.eq(i),"border-box"===n.css("box-sizing")?l=n.outerWidth():"collapse"===s.css("border-collapse")?t.getComputedStyle?l=parseFloat(t.getComputedStyle(n[0],null).width):(a=parseFloat(n.css("border-width")),l=n.outerWidth()-parseFloat(n.css("padding-left"))-parseFloat(n.css("padding-right"))-a):l=n.width(),s.css({width:l,"min-width":l,"max-width":l})},R=function(){_=y.length?y.height()||0:parseInt(a.stickyHeaders_offset,10)||0,$=0,C.css({left:f.length?parseInt(f.css("padding-left"),10)||0:d.offset().left-parseInt(d.css("margin-left"),10)-p.scrollLeft()-$,width:d.outerWidth()}),F(d,x),F(m,c)},k=function(t){if(d.is(":visible")){w=v.length?v.offset().top-h.scrollTop()+v.height():0;var i=d.offset(),l=e.isWindow(h[0]),a=e.isWindow(p[0]),s=(f.length?l?h.scrollTop():h.offset().top:h.scrollTop())+_+w,n=d.height()-(C.height()+(b.height()||0)),o=s>i.top&&s<i.top+n?"visible":"hidden",c={visibility:o};f.length&&(c.top=l?s-f.offset().top:f.scrollTop()),a&&(c.left=d.offset().left-parseInt(d.css("margin-left"),10)-p.scrollLeft()-$),v.length&&(c.top=(c.top||0)+_+w),C.removeClass(r.css.stickyVis+" "+r.css.stickyHide).addClass("visible"===o?r.css.stickyVis:r.css.stickyHide).css(c),(o!==S||t)&&(R(),S=o)}};if(f.length&&!f.css("position")&&f.css("position","relative"),x.attr("id")&&(x[0].id+=a.stickyHeaders_cloneId),x.find("thead:gt(0), tr.sticky-false").hide(),x.find("tbody, tfoot").remove(),x.find("caption").toggle(a.stickyHeaders_includeCaption),c=z.children().children(),x.css({height:0,width:0,margin:0}),c.find("."+r.css.resizer).remove(),d.addClass("hasStickyHeaders").bind("pagerComplete"+u,function(){R()}),r.bindEvents(i,z.children().children("."+r.css.header)),d.after(C),l.onRenderHeader)for(o=z.children("tr").children(),n=o.length,s=0;n>s;s++)l.onRenderHeader.apply(o.eq(s),[s,l,x]);p.add(h).unbind("scroll resize ".split(" ").join(u).replace(/\s+/g," ")).bind("scroll resize ".split(" ").join(u),function(e){k("resize"===e.type)}),l.$table.unbind("stickyHeadersUpdate"+u).bind("stickyHeadersUpdate"+u,function(){k(!0)}),a.stickyHeaders_addResizeEvent&&r.addHeaderResizeEvent(i),d.hasClass("hasFilters")&&a.filter_columnFilters&&(d.bind("filterEnd"+u,function(){var i=e(document.activeElement).closest("td"),s=i.parent().children().index(i);C.hasClass(r.css.stickyVis)&&a.stickyHeaders_filteredToTop&&(t.scrollTo(0,d.position().top),s>=0&&l.$filters&&l.$filters.eq(s).find("a, select, input").filter(":visible").focus())}),r.filter.bindSearch(d,c.find("."+r.css.filter)),a.filter_hideFilters&&r.filter.hideFilters(x,l)),d.trigger("stickyHeadersInit")}},remove:function(i,l,a){var s=l.namespace+"stickyheaders ";l.$table.removeClass("hasStickyHeaders").unbind("pagerComplete filterEnd stickyHeadersUpdate ".split(" ").join(s).replace(/\s+/g," ")).next("."+r.css.stickyWrap).remove(),a.$sticky&&a.$sticky.length&&a.$sticky.remove(),e(t).add(a.stickyHeaders_xScroll).add(a.stickyHeaders_yScroll).add(a.stickyHeaders_attachTo).unbind("scroll resize ".split(" ").join(s).replace(/\s+/g," ")),r.addHeaderResizeEvent(i,!1)}})}(jQuery,window),function(e,t){"use strict";var r=e.tablesorter||{};e.extend(r.css,{resizableContainer:"tablesorter-resizable-container",resizableHandle:"tablesorter-resizable-handle",resizableNoSelect:"tablesorter-disableSelection",resizableStorage:"tablesorter-resizable"}),e(function(){var t="<style>body."+r.css.resizableNoSelect+" { -ms-user-select: none; -moz-user-select: -moz-none;-khtml-user-select: none; -webkit-user-select: none; user-select: none; }."+r.css.resizableContainer+" { position: relative; height: 1px; }."+r.css.resizableHandle+" { position: absolute; display: inline-block; width: 8px;top: 1px; cursor: ew-resize; z-index: 3; user-select: none; -moz-user-select: none; }</style>";e(t).appendTo("body")}),r.resizable={init:function(t,i){if(!t.$table.hasClass("hasResizable")){t.$table.addClass("hasResizable");var l,a,s,n,o,c=t.$table,d=c.parent(),f=parseInt(c.css("margin-top"),10),u=i.resizable_={useStorage:r.storage&&i.resizable!==!1,$wrap:d,mouseXPosition:0,$target:null,$next:null,overflow:"auto"===d.css("overflow")||"scroll"===d.css("overflow")||"auto"===d.css("overflow-x")||"scroll"===d.css("overflow-x"),storedSizes:[]};for(r.resizableReset(t.table,!0),u.tableWidth=c.width(),u.fullWidth=Math.abs(d.width()-u.tableWidth)<20,u.useStorage&&u.overflow&&(r.storage(t.table,"tablesorter-table-original-css-width",u.tableWidth),o=r.storage(t.table,"tablesorter-table-resized-width")||"auto",r.resizable.setWidth(c,o,!0)),i.resizable_.storedSizes=n=(u.useStorage?r.storage(t.table,r.css.resizableStorage):[])||[],r.resizable.setWidths(t,i,n),r.resizable.updateStoredSizes(t,i),i.$resizable_container=e('<div class="'+r.css.resizableContainer+'">').css({top:f}).insertBefore(c),s=0;s<t.columns;s++)a=t.$headerIndexed[s],o=r.getColumnData(t.table,t.headers,s),l="false"===r.getData(a,o,"resizable"),l||e('<div class="'+r.css.resizableHandle+'">').appendTo(i.$resizable_container).attr({"data-column":s,unselectable:"on"}).data("header",a).bind("selectstart",!1);c.one("tablesorter-initialized",function(){r.resizable.setHandlePosition(t,i),r.resizable.bindings(this.config,this.config.widgetOptions)})}},updateStoredSizes:function(e,t){var r,i,l=e.columns,a=t.resizable_;for(a.storedSizes=[],r=0;l>r;r++)i=e.$headerIndexed[r],a.storedSizes[r]=i.is(":visible")?i.width():0},setWidth:function(e,t,r){e.css({width:t,"min-width":r?t:"","max-width":r?t:""})},setWidths:function(t,i,l){var a,s,n=i.resizable_,o=e(t.namespace+"_extra_headers"),c=t.$table.children("colgroup").children("col");if(l=l||n.storedSizes||[],l.length){for(a=0;a<t.columns;a++)r.resizable.setWidth(t.$headerIndexed[a],l[a],n.overflow),o.length&&(s=o.eq(a).add(c.eq(a)),r.resizable.setWidth(s,l[a],n.overflow));s=e(t.namespace+"_extra_table"),s.length&&!r.hasWidget(t.table,"scroller")&&r.resizable.setWidth(s,t.$table.outerWidth(),n.overflow)}},setHandlePosition:function(t,i){var l,a=r.hasWidget(t.table,"scroller"),s=t.$table.height(),n=i.$resizable_container.children(),o=Math.floor(n.width()/2);a&&(s=0,t.$table.closest("."+r.css.scrollerWrap).children().each(function(){var t=e(this);s+=t.filter('[style*="height"]').length?t.height():t.children("table").height()})),l=t.$table.position().left,n.each(function(){var r=e(this),a=parseInt(r.attr("data-column"),10),n=t.columns-1,c=r.data("header");c&&(c.is(":visible")?(n>a||a===n&&i.resizable_addLastColumn)&&r.css({display:"inline-block",height:s,left:c.position().left-l+c.outerWidth()-o}):r.hide())})},toggleTextSelection:function(t,i){var l=t.namespace+"tsresize";t.widgetOptions.resizable_.disabled=i,e("body").toggleClass(r.css.resizableNoSelect,i),i?e("body").attr("unselectable","on").bind("selectstart"+l,!1):e("body").removeAttr("unselectable").unbind("selectstart"+l)},bindings:function(i,l){var a=i.namespace+"tsresize";l.$resizable_container.children().bind("mousedown",function(t){var a,s=l.resizable_,n=e(i.namespace+"_extra_headers"),o=e(t.target).data("header");a=parseInt(o.attr("data-column"),10),s.$target=o=o.add(n.filter('[data-column="'+a+'"]')),s.target=a,s.$next=t.shiftKey||l.resizable_targetLast?o.parent().children().not(".resizable-false").filter(":last"):o.nextAll(":not(.resizable-false)").eq(0),a=parseInt(s.$next.attr("data-column"),10),s.$next=s.$next.add(n.filter('[data-column="'+a+'"]')),s.next=a,s.mouseXPosition=t.pageX,r.resizable.updateStoredSizes(i,l),r.resizable.toggleTextSelection(i,!0)}),e(document).bind("mousemove"+a,function(e){var t=l.resizable_;t.disabled&&0!==t.mouseXPosition&&t.$target&&(l.resizable_throttle?(clearTimeout(t.timer),t.timer=setTimeout(function(){r.resizable.mouseMove(i,l,e)},isNaN(l.resizable_throttle)?5:l.resizable_throttle)):r.resizable.mouseMove(i,l,e))}).bind("mouseup"+a,function(){l.resizable_.disabled&&(r.resizable.toggleTextSelection(i,!1),r.resizable.stopResize(i,l),r.resizable.setHandlePosition(i,l))}),e(t).bind("resize"+a+" resizeEnd"+a,function(){r.resizable.setHandlePosition(i,l)}),i.$table.bind("columnUpdate"+a,function(){r.resizable.setHandlePosition(i,l)}).find("thead:first").add(e(i.namespace+"_extra_table").find("thead:first")).bind("contextmenu"+a,function(){var e=0===l.resizable_.storedSizes.length;return r.resizableReset(i.table),r.resizable.setHandlePosition(i,l),l.resizable_.storedSizes=[],e})},mouseMove:function(t,i,l){if(0!==i.resizable_.mouseXPosition&&i.resizable_.$target){var a,s=0,n=i.resizable_,o=n.$next,c=n.storedSizes[n.target],d=l.pageX-n.mouseXPosition;if(n.overflow){if(c+d>0){for(n.storedSizes[n.target]+=d,r.resizable.setWidth(n.$target,n.storedSizes[n.target],!0),a=0;a<t.columns;a++)s+=n.storedSizes[a];r.resizable.setWidth(t.$table.add(e(t.namespace+"_extra_table")),s)}o.length||(n.$wrap[0].scrollLeft=t.$table.width())}else n.fullWidth?(n.storedSizes[n.target]+=d,n.storedSizes[n.next]-=d,r.resizable.setWidths(t,i)):(n.storedSizes[n.target]+=d,r.resizable.setWidths(t,i));n.mouseXPosition=l.pageX,t.$table.trigger("stickyHeadersUpdate")}},stopResize:function(e,t){var i=t.resizable_;r.resizable.updateStoredSizes(e,t),i.useStorage&&(r.storage(e.table,r.css.resizableStorage,i.storedSizes),r.storage(e.table,"tablesorter-table-resized-width",e.$table.width())),i.mouseXPosition=0,i.$target=i.$next=null,e.$table.trigger("stickyHeadersUpdate")}},r.addWidget({id:"resizable",priority:40,options:{resizable:!0,resizable_addLastColumn:!1,resizable_widths:[],resizable_throttle:!1,resizable_targetLast:!1,resizable_fullWidth:null},init:function(e,t,i,l){r.resizable.init(i,l)},remove:function(t,i,l,a){if(l.$resizable_container){var s=i.namespace+"tsresize";i.$table.add(e(i.namespace+"_extra_table")).removeClass("hasResizable").children("thead").unbind("contextmenu"+s),l.$resizable_container.remove(),r.resizable.toggleTextSelection(i,!1),r.resizableReset(t,a),e(document).unbind("mousemove"+s+" mouseup"+s)}}}),r.resizableReset=function(t,i){e(t).each(function(){var e,l,a=this.config,s=a&&a.widgetOptions,n=s.resizable_;if(t&&a&&a.$headerIndexed.length){for(n.overflow&&n.tableWidth&&(r.resizable.setWidth(a.$table,n.tableWidth,!0),n.useStorage&&r.storage(t,"tablesorter-table-resized-width","auto")),e=0;e<a.columns;e++)l=a.$headerIndexed[e],s.resizable_widths&&s.resizable_widths[e]?r.resizable.setWidth(l,s.resizable_widths[e],n.overflow):l.hasClass("resizable-false")||r.resizable.setWidth(l,"",n.overflow);a.$table.trigger("stickyHeadersUpdate"),r.storage&&!i&&r.storage(this,r.css.resizableStorage,{})}})}}(jQuery,window),function(e){"use strict";var t=e.tablesorter||{};t.addWidget({id:"saveSort",priority:20,options:{saveSort:!0},init:function(e,t,r,i){t.format(e,r,i,!0)},format:function(r,i,l,a){var s,n,o=i.$table,c=l.saveSort!==!1,d={sortList:i.sortList};i.debug&&(n=new Date),o.hasClass("hasSaveSort")?c&&r.hasInitialized&&t.storage&&(t.storage(r,"tablesorter-savesort",d),i.debug&&t.benchmark("saveSort widget: Saving last sort: "+i.sortList,n)):(o.addClass("hasSaveSort"),d="",t.storage&&(s=t.storage(r,"tablesorter-savesort"),d=s&&s.hasOwnProperty("sortList")&&e.isArray(s.sortList)?s.sortList:"",i.debug&&t.benchmark('saveSort: Last sort loaded: "'+d+'"',n),o.bind("saveSortReset",function(e){e.stopPropagation(),t.storage(r,"tablesorter-savesort","")})),a&&d&&d.length>0?i.sortList=d:r.hasInitialized&&d&&d.length>0&&o.trigger("sorton",[d]))},remove:function(e,r){r.$table.removeClass("hasSaveSort"),t.storage&&t.storage(e,"tablesorter-savesort","")}})}(jQuery),e.tablesorter}); /* custom */ $(document).ready(function(){$('.table-sortable').tablesorter({theme:'bootstrap',widgets:['uitheme','zebra','filter','stickyHeaders','saveSort'],headerTemplate:'{content} {icon}',widthFixed:true,ignoreCase:true,widgetOptions:{filter_columnFilters:true,zebra:['even','odd'],filter_reset:'.reset'}});}); \ No newline at end of file
diff --git a/library/cpp/monlib/service/pages/tablesorter/ya.make b/library/cpp/monlib/service/pages/tablesorter/ya.make
new file mode 100644
index 0000000000..b5b6a64da8
--- /dev/null
+++ b/library/cpp/monlib/service/pages/tablesorter/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+OWNER(blinkov)
+
+RESOURCE(
+ resources/jquery.tablesorter.css jquery.tablesorter.css
+ resources/jquery.tablesorter.js jquery.tablesorter.js
+)
+
+PEERDIR(
+ library/cpp/monlib/dynamic_counters
+)
+
+END()
diff --git a/library/cpp/monlib/service/pages/templates.cpp b/library/cpp/monlib/service/pages/templates.cpp
new file mode 100644
index 0000000000..ece12bea71
--- /dev/null
+++ b/library/cpp/monlib/service/pages/templates.cpp
@@ -0,0 +1,35 @@
+#include "templates.h"
+
+namespace NMonitoring {
+ extern const char HtmlTag[] = "html";
+ extern const char HeadTag[] = "head";
+ extern const char BodyTag[] = "body";
+ extern const char DivTag[] = "div";
+ extern const char TableTag[] = "table";
+ extern const char TableHeadTag[] = "thead";
+ extern const char TableBodyTag[] = "tbody";
+ extern const char TableRTag[] = "tr";
+ extern const char TableDTag[] = "td";
+ extern const char TableHTag[] = "th";
+ extern const char FormTag[] = "form";
+ extern const char LabelTag[] = "label";
+ extern const char SpanTag[] = "span";
+ extern const char CaptionTag[] = "caption";
+ extern const char PreTag[] = "pre";
+ extern const char ParaTag[] = "p";
+ extern const char H1Tag[] = "h1";
+ extern const char H2Tag[] = "h2";
+ extern const char H3Tag[] = "h3";
+ extern const char H4Tag[] = "h4";
+ extern const char H5Tag[] = "h5";
+ extern const char H6Tag[] = "h6";
+ extern const char SmallTag[] = "small";
+ extern const char StrongTag[] = "strong";
+ extern const char ListTag[] = "li";
+ extern const char UListTag[] = "ul";
+ extern const char OListTag[] = "ol";
+ extern const char DListTag[] = "dl";
+ extern const char DTermTag[] = "dt";
+ extern const char DDescTag[] = "dd";
+
+}
diff --git a/library/cpp/monlib/service/pages/templates.h b/library/cpp/monlib/service/pages/templates.h
new file mode 100644
index 0000000000..b4656f059f
--- /dev/null
+++ b/library/cpp/monlib/service/pages/templates.h
@@ -0,0 +1,268 @@
+#pragma once
+
+#include <util/stream/output.h>
+#include <util/system/defaults.h>
+
+#define WITH_SCOPED(var, value) WITH_SCOPED_I(var, value, Y_GENERATE_UNIQUE_ID(WITH_SCOPED_LABEL_))
+
+#define WITH_SCOPED_I(var, value, label) \
+ if (auto var = (value)) { \
+ Y_UNUSED(var); \
+ goto label; \
+ } else \
+ label \
+ :
+
+#define TAG(name) WITH_SCOPED(tmp, NMonitoring::name(__stream))
+#define TAG_CLASS(name, cls) WITH_SCOPED(tmp, NMonitoring::name(__stream, cls))
+#define TAG_CLASS_STYLE(name, cls, style) WITH_SCOPED(tmp, NMonitoring::name(__stream, {{"class", cls}, {"style", style}}))
+#define TAG_CLASS_ID(name, cls, id) WITH_SCOPED(tmp, NMonitoring::name(__stream, cls, "", id))
+#define TAG_CLASS_FOR(name, cls, for0) WITH_SCOPED(tmp, NMonitoring::name(__stream, cls, for0))
+#define TAG_ATTRS(name, ...) WITH_SCOPED(tmp, NMonitoring::name(__stream, ##__VA_ARGS__))
+
+#define HTML(str) WITH_SCOPED(__stream, NMonitoring::TOutputStreamRef(str))
+
+#define HEAD() TAG(THead)
+#define BODY() TAG(TBody)
+#define HTML_TAG() TAG(THtml)
+#define DIV() TAG(TDiv)
+#define DIV_CLASS(cls) TAG_CLASS(TDiv, cls)
+#define DIV_CLASS_ID(cls, id) TAG_CLASS_ID(TDiv, cls, id)
+#define PRE() TAG(TPre)
+#define TABLE() TAG(TTable)
+#define TABLE_CLASS(cls) TAG_CLASS(TTable, cls)
+#define TABLE_SORTABLE() TABLE_CLASS("table-sortable")
+#define TABLE_SORTABLE_CLASS(cls) TABLE_CLASS(cls " table-sortable")
+#define TABLEHEAD() TAG(TTableHead)
+#define TABLEHEAD_CLASS(cls) TAG_CLASS(TTableHead, cls)
+#define TABLEBODY() TAG(TTableBody)
+#define TABLEBODY_CLASS(cls) TAG_CLASS(TTableBody, cls)
+#define TABLER() TAG(TTableR)
+#define TABLER_CLASS(cls) TAG_CLASS(TTableR, cls)
+#define TABLED() TAG(TTableD)
+#define TABLED_CLASS(cls) TAG_CLASS(TTableD, cls)
+#define TABLED_ATTRS(...) TAG_ATTRS(TTableD, ##__VA_ARGS__)
+#define TABLEH() TAG(TTableH)
+#define TABLEH_CLASS(cls) TAG_CLASS(TTableH, cls)
+#define FORM() TAG(TFormC)
+#define FORM_CLASS(cls) TAG_CLASS(TFormC, cls)
+#define LABEL() TAG(TLabelC)
+#define LABEL_CLASS(cls) TAG_CLASS(TLabelC, cls)
+#define LABEL_CLASS_FOR(cls, for0) TAG_CLASS_FOR(TLabelC, cls, for0)
+#define SPAN_CLASS(cls) TAG_CLASS(TSpanC, cls)
+#define SPAN_CLASS_STYLE(cls, style) TAG_CLASS_STYLE(TSpanC, cls, style)
+
+#define PARA() TAG(TPara)
+#define PARA_CLASS(cls) TAG_CLASS(TPara, cls)
+
+#define H1() TAG(TH1)
+#define H1_CLASS(cls) TAG_CLASS(TH1, cls)
+#define H2() TAG(TH2)
+#define H2_CLASS(cls) TAG_CLASS(TH2, cls)
+#define H3() TAG(TH3)
+#define H3_CLASS(cls) TAG_CLASS(TH3, cls)
+#define H4() TAG(TH4)
+#define H4_CLASS(cls) TAG_CLASS(TH4, cls)
+#define H5() TAG(TH5)
+#define H5_CLASS(cls) TAG_CLASS(TH5, cls)
+#define H6() TAG(TH6)
+#define H6_CLASS(cls) TAG_CLASS(TH6, cls)
+
+#define SMALL() TAG(TSMALL)
+#define STRONG() TAG(TSTRONG)
+
+#define LI() TAG(TLIST)
+#define LI_CLASS(cls) TAG_CLASS(TLIST, cls)
+#define UL() TAG(TULIST)
+#define UL_CLASS(cls) TAG_CLASS(TULIST, cls)
+#define OL() TAG(TOLIST)
+#define OL_CLASS(cls) TAG_CLASS(TOLIST, cls)
+
+#define DL() TAG(DLIST)
+#define DL_CLASS(cls) TAG_CLASS(DLIST, cls)
+#define DT() TAG(DTERM)
+#define DT_CLASS(cls) TAG_CLASS(DTERM, cls)
+#define DD() TAG(DDESC)
+#define DD_CLASS(cls) TAG_CLASS(DDESC, cls)
+
+#define CAPTION() TAG(TCaption)
+#define CAPTION_CLASS(cls) CAPTION_CLASS(TCaption, cls)
+
+#define HTML_OUTPUT_PARAM(str, param) str << #param << ": " << param << "<br/>"
+#define HTML_OUTPUT_TIME_PARAM(str, param) str << #param << ": " << ToStringLocalTimeUpToSeconds(param) << "<br/>"
+
+#define COLLAPSED_BUTTON_CONTENT(targetId, buttonText) \
+ WITH_SCOPED(tmp, NMonitoring::TCollapsedButton(__stream, targetId, buttonText))
+
+#define HREF(path) \
+ WITH_SCOPED(tmp, NMonitoring::THref(__stream, path))
+
+namespace NMonitoring {
+ struct THref {
+ THref(IOutputStream& str, TStringBuf path)
+ : Str(str)
+ {
+ Str << "<a href="<< path << '>';
+ }
+
+ ~THref() {
+ Str << "</a>";
+ }
+
+ explicit inline operator bool() const noexcept {
+ return true; // just to work with WITH_SCOPED
+ }
+
+ IOutputStream& Str;
+ };
+
+ template <const char* tag>
+ struct TTag {
+ TTag(IOutputStream& str, TStringBuf cls = "", TStringBuf for0 = "", TStringBuf id = "")
+ : Str(str)
+ {
+ Str << "<" << tag;
+
+ if (!cls.empty()) {
+ Str << " class=\"" << cls << "\"";
+ }
+
+ if (!for0.empty()) {
+ Str << " for=\"" << for0 << "\"";
+ }
+
+ if (!id.empty()) {
+ Str << "id=\"" << id << "\"";
+ }
+ Str << ">";
+ }
+
+ TTag(IOutputStream& str, std::initializer_list<std::pair<TStringBuf, TStringBuf>> attributes)
+ : Str(str)
+ {
+ Str << "<" << tag;
+ for (const std::pair<TStringBuf, TStringBuf>& attr : attributes) {
+ if (!attr.second.empty()) {
+ Str << ' ' << attr.first << "=\"" << attr.second << "\"";
+ }
+ }
+ Str << ">";
+ }
+
+ ~TTag() {
+ try {
+ Str << "</" << tag << ">";
+ } catch (...) {
+ }
+ }
+
+ explicit inline operator bool() const noexcept {
+ return true; // just to work with WITH_SCOPED
+ }
+
+ IOutputStream& Str;
+ };
+
+ // a nice class for creating collapsable regions of html output
+ struct TCollapsedButton {
+ TCollapsedButton(IOutputStream& str, const TString& targetId, const TString& buttonText)
+ : Str(str)
+ {
+ Str << "<button type='button' class='btn' data-toggle='collapse' data-target='#" << targetId << "'>"
+ << buttonText << "</button>";
+ Str << "<div id='" << targetId << "' class='collapse'>";
+ }
+
+ ~TCollapsedButton() {
+ try {
+ Str << "</div>";
+ } catch (...) {
+ }
+ }
+
+ explicit inline operator bool() const noexcept {
+ return true; // just to work with WITH_SCOPED
+ }
+
+ IOutputStream& Str;
+ };
+
+ struct TOutputStreamRef {
+ TOutputStreamRef(IOutputStream& str)
+ : Str(str)
+ {
+ }
+
+ inline operator IOutputStream&() noexcept {
+ return Str;
+ }
+
+ explicit inline operator bool() const noexcept {
+ return true; // just to work with WITH_SCOPED
+ }
+
+ IOutputStream& Str;
+ };
+
+ extern const char HtmlTag[5];
+ extern const char HeadTag[5];
+ extern const char BodyTag[5];
+ extern const char DivTag[4];
+ extern const char TableTag[6];
+ extern const char TableHeadTag[6];
+ extern const char TableBodyTag[6];
+ extern const char TableRTag[3];
+ extern const char TableDTag[3];
+ extern const char TableHTag[3];
+ extern const char FormTag[5];
+ extern const char LabelTag[6];
+ extern const char SpanTag[5];
+ extern const char CaptionTag[8];
+ extern const char PreTag[4];
+ extern const char ParaTag[2];
+ extern const char H1Tag[3];
+ extern const char H2Tag[3];
+ extern const char H3Tag[3];
+ extern const char H4Tag[3];
+ extern const char H5Tag[3];
+ extern const char H6Tag[3];
+ extern const char SmallTag[6];
+ extern const char StrongTag[7];
+ extern const char ListTag[3];
+ extern const char UListTag[3];
+ extern const char OListTag[3];
+ extern const char DListTag[3];
+ extern const char DTermTag[3];
+ extern const char DDescTag[3];
+
+ typedef TTag<HtmlTag> THtml;
+ typedef TTag<HeadTag> THead;
+ typedef TTag<BodyTag> TBody;
+ typedef TTag<DivTag> TDiv;
+ typedef TTag<TableTag> TTable;
+ typedef TTag<TableHeadTag> TTableHead;
+ typedef TTag<TableBodyTag> TTableBody;
+ typedef TTag<TableRTag> TTableR;
+ typedef TTag<TableDTag> TTableD;
+ typedef TTag<TableHTag> TTableH;
+ typedef TTag<FormTag> TFormC;
+ typedef TTag<LabelTag> TLabelC;
+ typedef TTag<SpanTag> TSpanC;
+ typedef TTag<CaptionTag> TCaption;
+ typedef TTag<PreTag> TPre;
+ typedef TTag<ParaTag> TPara;
+ typedef TTag<H1Tag> TH1;
+ typedef TTag<H2Tag> TH2;
+ typedef TTag<H3Tag> TH3;
+ typedef TTag<H4Tag> TH4;
+ typedef TTag<H5Tag> TH5;
+ typedef TTag<H6Tag> TH6;
+ typedef TTag<SmallTag> TSMALL;
+ typedef TTag<StrongTag> TSTRONG;
+ typedef TTag<ListTag> TLIST;
+ typedef TTag<UListTag> TULIST;
+ typedef TTag<OListTag> TOLIST;
+ typedef TTag<DListTag> DLIST;
+ typedef TTag<DTermTag> DTERM;
+ typedef TTag<DDescTag> DDESC;
+}
diff --git a/library/cpp/monlib/service/pages/version_mon_page.cpp b/library/cpp/monlib/service/pages/version_mon_page.cpp
new file mode 100644
index 0000000000..41e29417da
--- /dev/null
+++ b/library/cpp/monlib/service/pages/version_mon_page.cpp
@@ -0,0 +1,16 @@
+#include <library/cpp/svnversion/svnversion.h>
+#include <library/cpp/build_info/build_info.h>
+#include <library/cpp/malloc/api/malloc.h>
+
+#include "version_mon_page.h"
+
+using namespace NMonitoring;
+
+void TVersionMonPage::OutputText(IOutputStream& out, NMonitoring::IMonHttpRequest&) {
+ const char* version = GetProgramSvnVersion();
+ out << version;
+ if (!TString(version).EndsWith("\n"))
+ out << "\n";
+ out << GetBuildInfo() << "\n\n";
+ out << "linked with malloc: " << NMalloc::MallocInfo().Name << "\n";
+}
diff --git a/library/cpp/monlib/service/pages/version_mon_page.h b/library/cpp/monlib/service/pages/version_mon_page.h
new file mode 100644
index 0000000000..f7649947e4
--- /dev/null
+++ b/library/cpp/monlib/service/pages/version_mon_page.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "pre_mon_page.h"
+
+namespace NMonitoring {
+ struct TVersionMonPage: public TPreMonPage {
+ TVersionMonPage(const TString& path = "ver", const TString& title = "Version")
+ : TPreMonPage(path, title)
+ {
+ }
+
+ void OutputText(IOutputStream& out, NMonitoring::IMonHttpRequest&) override;
+ };
+
+}
diff --git a/library/cpp/monlib/service/pages/ya.make b/library/cpp/monlib/service/pages/ya.make
new file mode 100644
index 0000000000..48d44a0838
--- /dev/null
+++ b/library/cpp/monlib/service/pages/ya.make
@@ -0,0 +1,31 @@
+LIBRARY()
+
+OWNER(g:solomon)
+
+NO_WSHADOW()
+
+SRCS(
+ diag_mon_page.cpp
+ html_mon_page.cpp
+ index_mon_page.cpp
+ mon_page.cpp
+ pre_mon_page.cpp
+ resource_mon_page.cpp
+ templates.cpp
+ version_mon_page.cpp
+ registry_mon_page.cpp
+)
+
+PEERDIR(
+ library/cpp/build_info
+ library/cpp/malloc/api
+ library/cpp/svnversion
+ library/cpp/resource
+ library/cpp/monlib/service
+ library/cpp/monlib/encode/json
+ library/cpp/monlib/encode/text
+ library/cpp/monlib/encode/spack
+ library/cpp/monlib/encode/prometheus
+)
+
+END()
diff --git a/library/cpp/monlib/service/service.cpp b/library/cpp/monlib/service/service.cpp
new file mode 100644
index 0000000000..929efbf816
--- /dev/null
+++ b/library/cpp/monlib/service/service.cpp
@@ -0,0 +1,268 @@
+#include "service.h"
+
+#include <library/cpp/coroutine/engine/sockpool.h>
+#include <library/cpp/http/io/stream.h>
+#include <library/cpp/http/fetch/httpheader.h>
+#include <library/cpp/http/fetch/httpfsm.h>
+#include <library/cpp/uri/http_url.h>
+
+#include <util/generic/buffer.h>
+#include <util/stream/str.h>
+#include <util/stream/buffer.h>
+#include <util/stream/zerocopy.h>
+#include <util/string/vector.h>
+
+namespace NMonitoring {
+ class THttpClient: public IHttpRequest {
+ public:
+ void ServeRequest(THttpInput& in, IOutputStream& out, const NAddr::IRemoteAddr* remoteAddr, const THandler& Handler) {
+ try {
+ try {
+ RemoteAddr = remoteAddr;
+ THttpHeaderParser parser;
+ parser.Init(&Header);
+ if (parser.Execute(in.FirstLine().data(), in.FirstLine().size()) < 0) {
+ out << "HTTP/1.1 400 Bad request\r\nConnection: Close\r\n\r\n";
+ return;
+ }
+ if (Url.Parse(Header.GetUrl().data()) != THttpURL::ParsedOK) {
+ out << "HTTP/1.1 400 Invalid url\r\nConnection: Close\r\n\r\n";
+ return;
+ }
+ TString path = GetPath();
+ if (!path.StartsWith('/')) {
+ out << "HTTP/1.1 400 Bad request\r\nConnection: Close\r\n\r\n";
+ return;
+ }
+ Headers = &in.Headers();
+ CgiParams.Scan(Url.Get(THttpURL::FieldQuery));
+ } catch (...) {
+ out << "HTTP/1.1 500 Internal server error\r\nConnection: Close\r\n\r\n";
+ YSYSLOG(TLOG_ERR, "THttpClient: internal error while serving monitoring request: %s", CurrentExceptionMessage().data());
+ }
+
+ if (Header.http_method == HTTP_METHOD_POST)
+ TransferData(&in, &PostContent);
+
+ Handler(out, *this);
+ out.Finish();
+ } catch (...) {
+ auto msg = CurrentExceptionMessage();
+ out << "HTTP/1.1 500 Internal server error\r\nConnection: Close\r\n\r\n" << msg;
+ out.Finish();
+ YSYSLOG(TLOG_ERR, "THttpClient: error while serving monitoring request: %s", msg.data());
+ }
+ }
+
+ const char* GetURI() const override {
+ return Header.request_uri.c_str();
+ }
+ const char* GetPath() const override {
+ return Url.Get(THttpURL::FieldPath);
+ }
+ const TCgiParameters& GetParams() const override {
+ return CgiParams;
+ }
+ const TCgiParameters& GetPostParams() const override {
+ if (PostParams.empty() && !PostContent.Buffer().Empty())
+ const_cast<THttpClient*>(this)->ScanPostParams();
+ return PostParams;
+ }
+ TStringBuf GetPostContent() const override {
+ return TStringBuf(PostContent.Buffer().Data(), PostContent.Buffer().Size());
+ }
+ HTTP_METHOD GetMethod() const override {
+ return (HTTP_METHOD)Header.http_method;
+ }
+ void ScanPostParams() {
+ PostParams.Scan(TStringBuf(PostContent.Buffer().data(), PostContent.Buffer().size()));
+ }
+
+ const THttpHeaders& GetHeaders() const override {
+ if (Headers != nullptr) {
+ return *Headers;
+ }
+ static THttpHeaders defaultHeaders;
+ return defaultHeaders;
+ }
+
+ TString GetRemoteAddr() const override {
+ return RemoteAddr ? NAddr::PrintHostAndPort(*RemoteAddr) : TString();
+ }
+
+ private:
+ THttpRequestHeader Header;
+ const THttpHeaders* Headers = nullptr;
+ THttpURL Url;
+ TCgiParameters CgiParams;
+ TCgiParameters PostParams;
+ TBufferOutput PostContent;
+ const NAddr::IRemoteAddr* RemoteAddr = nullptr;
+ };
+
+ /* TCoHttpServer */
+
+ class TCoHttpServer::TConnection: public THttpClient {
+ public:
+ TConnection(const TCoHttpServer::TAcceptFull& acc, const TCoHttpServer& parent)
+ : Socket(acc.S->Release())
+ , RemoteAddr(acc.Remote)
+ , Parent(parent)
+ {
+ }
+
+ void operator()(TCont* c) {
+ try {
+ THolder<TConnection> me(this);
+ TContIO io(Socket, c);
+ THttpInput in(&io);
+ THttpOutput out(&io, &in);
+ // buffer reply so there will be ne context switching
+ TStringStream s;
+ ServeRequest(in, s, RemoteAddr, Parent.Handler);
+ out << s.Str();
+ out.Finish();
+ } catch (...) {
+ YSYSLOG(TLOG_WARNING, "TCoHttpServer::TConnection: error: %s\n", CurrentExceptionMessage().data());
+ }
+ }
+
+ private:
+ TSocketHolder Socket;
+ const NAddr::IRemoteAddr* RemoteAddr;
+ const TCoHttpServer& Parent;
+ };
+
+ TCoHttpServer::TCoHttpServer(TContExecutor& executor, const TString& bindAddr, TIpPort port, THandler handler)
+ : Executor(executor)
+ , Listener(this, &executor)
+ , Handler(std::move(handler))
+ , BindAddr(bindAddr)
+ , Port(port)
+ {
+ try {
+ Listener.Bind(TIpAddress(bindAddr, port));
+ } catch (yexception e) {
+ Y_FAIL("TCoHttpServer::TCoHttpServer: couldn't bind to %s:%d\n", bindAddr.data(), port);
+ }
+ }
+
+ void TCoHttpServer::Start() {
+ Listener.Listen();
+ }
+
+ void TCoHttpServer::Stop() {
+ Listener.Stop();
+ }
+
+ void TCoHttpServer::OnAcceptFull(const TAcceptFull& acc) {
+ THolder<TConnection> conn(new TConnection(acc, *this));
+ Executor.Create(*conn, "client");
+ Y_UNUSED(conn.Release());
+ }
+
+ void TCoHttpServer::OnError() {
+ throw; // just rethrow
+ }
+
+ void TCoHttpServer::ProcessRequest(IOutputStream& out, const IHttpRequest& request) {
+ try {
+ TNetworkAddress addr(BindAddr, Port);
+ TSocket sock(addr);
+ TSocketOutput sock_out(sock);
+ TSocketInput sock_in(sock);
+ sock_out << "GET " << request.GetURI() << " HTTP/1.0\r\n\r\n";
+ THttpInput http_in(&sock_in);
+ try {
+ out << "HTTP/1.1 200 Ok\nConnection: Close\n\n";
+ TransferData(&http_in, &out);
+ } catch (...) {
+ YSYSLOG(TLOG_DEBUG, "TCoHttpServer: while getting data from backend: %s", CurrentExceptionMessage().data());
+ }
+ } catch (const yexception& /*e*/) {
+ out << "HTTP/1.1 500 Internal server error\nConnection: Close\n\n";
+ YSYSLOG(TLOG_DEBUG, "TCoHttpServer: while getting data from backend: %s", CurrentExceptionMessage().data());
+ }
+ }
+
+ /* TMtHttpServer */
+
+ class TMtHttpServer::TConnection: public TClientRequest, public THttpClient {
+ public:
+ TConnection(const TMtHttpServer& parent)
+ : Parent(parent)
+ {
+ }
+
+ bool Reply(void*) override {
+ ServeRequest(Input(), Output(), NAddr::GetPeerAddr(Socket()).Get(), Parent.Handler);
+ return true;
+ }
+
+ private:
+ const TMtHttpServer& Parent;
+ };
+
+ TMtHttpServer::TMtHttpServer(const TOptions& options, THandler handler, IThreadFactory* pool)
+ : THttpServer(this, options, pool)
+ , Handler(std::move(handler))
+ {
+ }
+
+ TMtHttpServer::TMtHttpServer(const TOptions& options, THandler handler, TSimpleSharedPtr<IThreadPool> pool)
+ : THttpServer(this, /* mainWorkers = */pool, /* failWorkers = */pool, options)
+ , Handler(std::move(handler))
+ {
+ }
+
+ bool TMtHttpServer::Start() {
+ return THttpServer::Start();
+ }
+
+ void TMtHttpServer::StartOrThrow() {
+ if (!Start()) {
+ const auto& opts = THttpServer::Options();
+ TNetworkAddress addr = opts.Host
+ ? TNetworkAddress(opts.Host, opts.Port)
+ : TNetworkAddress(opts.Port);
+ ythrow TSystemError(GetErrorCode()) << addr;
+ }
+ }
+
+ void TMtHttpServer::Stop() {
+ THttpServer::Stop();
+ }
+
+ TClientRequest* TMtHttpServer::CreateClient() {
+ return new TConnection(*this);
+ }
+
+ /* TService */
+
+ TMonService::TMonService(TContExecutor& executor, TIpPort internalPort, TIpPort externalPort,
+ THandler coHandler, THandler mtHandler)
+ : CoServer(executor, "127.0.0.1", internalPort, std::move(coHandler))
+ , MtServer(THttpServerOptions(externalPort), std::bind(&TMonService::DispatchRequest, this, std::placeholders::_1, std::placeholders::_2))
+ , MtHandler(std::move(mtHandler))
+ {
+ }
+
+ void TMonService::Start() {
+ MtServer.Start();
+ CoServer.Start();
+ }
+
+ void TMonService::Stop() {
+ MtServer.Stop();
+ CoServer.Stop();
+ }
+
+ void TMonService::DispatchRequest(IOutputStream& out, const IHttpRequest& request) {
+ if (strcmp(request.GetPath(), "/") == 0) {
+ out << "HTTP/1.1 200 Ok\nConnection: Close\n\n";
+ MtHandler(out, request);
+ } else
+ CoServer.ProcessRequest(out, request);
+ }
+
+}
diff --git a/library/cpp/monlib/service/service.h b/library/cpp/monlib/service/service.h
new file mode 100644
index 0000000000..2f66dddaf8
--- /dev/null
+++ b/library/cpp/monlib/service/service.h
@@ -0,0 +1,112 @@
+#pragma once
+
+#include <library/cpp/coroutine/engine/impl.h>
+#include <library/cpp/coroutine/listener/listen.h>
+#include <library/cpp/http/fetch/httpheader.h>
+#include <library/cpp/http/server/http.h>
+#include <library/cpp/logger/all.h>
+
+#include <util/network/ip.h>
+#include <library/cpp/cgiparam/cgiparam.h>
+
+#include <functional>
+
+struct TMonitor;
+
+namespace NMonitoring {
+ struct IHttpRequest {
+ virtual ~IHttpRequest() {
+ }
+ virtual const char* GetURI() const = 0;
+ virtual const char* GetPath() const = 0;
+ virtual const TCgiParameters& GetParams() const = 0;
+ virtual const TCgiParameters& GetPostParams() const = 0;
+ virtual TStringBuf GetPostContent() const = 0;
+ virtual HTTP_METHOD GetMethod() const = 0;
+ virtual const THttpHeaders& GetHeaders() const = 0;
+ virtual TString GetRemoteAddr() const = 0;
+ };
+ // first param - output stream to write result to
+ // second param - URL of request
+ typedef std::function<void(IOutputStream&, const IHttpRequest&)> THandler;
+
+ class TCoHttpServer: private TContListener::ICallBack {
+ public:
+ // initialize and schedule coroutines for execution
+ TCoHttpServer(TContExecutor& executor, const TString& bindAddr, TIpPort port, THandler handler);
+ void Start();
+ void Stop();
+
+ // this function implements THandler interface
+ // by forwarding it to the httpserver
+ // @note this call may be blocking; don't use inside coroutines
+ // @throws may throw in case of connection error, etc
+ void ProcessRequest(IOutputStream&, const IHttpRequest&);
+
+ private:
+ class TConnection;
+
+ // ICallBack implementation
+ void OnAcceptFull(const TAcceptFull& a) override;
+ void OnError() override;
+
+ private:
+ TContExecutor& Executor;
+ TContListener Listener;
+ THandler Handler;
+ TString BindAddr;
+ TIpPort Port;
+ };
+
+ class TMtHttpServer: public THttpServer, private THttpServer::ICallBack {
+ public:
+ TMtHttpServer(const TOptions& options, THandler handler, IThreadFactory* pool = nullptr);
+ TMtHttpServer(const TOptions& options, THandler handler, TSimpleSharedPtr<IThreadPool> pool);
+
+ /**
+ * This will cause the server start to accept incoming connections.
+ *
+ * @return true if the port binding was successfull,
+ * false otherwise.
+ */
+ bool Start();
+
+ /**
+ * Same as Start() member-function, but will throw TSystemError if
+ * there were some errors.
+ */
+ void StartOrThrow();
+
+ /**
+ * Stops the server from accepting new connections.
+ */
+ void Stop();
+
+ private:
+ class TConnection;
+ TClientRequest* CreateClient() override;
+
+ THandler Handler;
+ };
+
+ // this class implements hybrid coroutine and threaded approach
+ // requests for main page which holds counters and simple tables are served in a thread
+ // requests for other pages which include access with inter-thread synchonization
+ // will be served in a coroutine context
+ class TMonService {
+ public:
+ TMonService(TContExecutor& executor, TIpPort internalPort, TIpPort externalPort,
+ THandler coHandler, THandler mtHandler);
+ void Start();
+ void Stop();
+
+ protected:
+ void DispatchRequest(IOutputStream& out, const IHttpRequest&);
+
+ private:
+ TCoHttpServer CoServer;
+ TMtHttpServer MtServer;
+ THandler MtHandler;
+ };
+
+}
diff --git a/library/cpp/monlib/service/ya.make b/library/cpp/monlib/service/ya.make
new file mode 100644
index 0000000000..ad088fc2c6
--- /dev/null
+++ b/library/cpp/monlib/service/ya.make
@@ -0,0 +1,28 @@
+LIBRARY()
+
+OWNER(g:solomon)
+
+SRCS(
+ monservice.cpp
+ mon_service_http_request.cpp
+ service.cpp
+ format.cpp
+ auth.cpp
+)
+
+PEERDIR(
+ library/cpp/string_utils/base64
+ contrib/libs/protobuf
+ library/cpp/coroutine/engine
+ library/cpp/coroutine/listener
+ library/cpp/http/fetch
+ library/cpp/http/server
+ library/cpp/http/io
+ library/cpp/logger
+ library/cpp/malloc/api
+ library/cpp/svnversion
+ library/cpp/uri
+ library/cpp/cgiparam
+)
+
+END()
diff --git a/library/cpp/monlib/ya.make b/library/cpp/monlib/ya.make
new file mode 100644
index 0000000000..9bd236d6fd
--- /dev/null
+++ b/library/cpp/monlib/ya.make
@@ -0,0 +1,45 @@
+OWNER(
+ g:solomon
+ jamel
+)
+
+RECURSE(
+ consumers
+ counters
+ counters/ut
+ deprecated
+ dynamic_counters
+ dynamic_counters/percentile
+ dynamic_counters/percentile/ut
+ dynamic_counters/ut
+ encode
+ encode/buffered
+ encode/buffered/ut
+ encode/fake
+ encode/fuzz
+ encode/json
+ encode/json/ut
+ encode/legacy_protobuf
+ encode/legacy_protobuf/ut
+ encode/prometheus
+ encode/prometheus/ut
+ encode/protobuf
+ encode/spack
+ encode/spack/ut
+ encode/text
+ encode/text/ut
+ encode/unistat
+ encode/unistat/ut
+ encode/ut
+ example
+ exception
+ libtimestats/ut
+ metrics
+ metrics/ut
+ messagebus
+ push_client
+ service
+ service/auth/tvm
+ service/pages
+ service/pages/tablesorter
+)
diff --git a/library/cpp/object_factory/object_factory.cpp b/library/cpp/object_factory/object_factory.cpp
new file mode 100644
index 0000000000..3ef5bd9d18
--- /dev/null
+++ b/library/cpp/object_factory/object_factory.cpp
@@ -0,0 +1 @@
+#include "object_factory.h"
diff --git a/library/cpp/object_factory/object_factory.h b/library/cpp/object_factory/object_factory.h
new file mode 100644
index 0000000000..96cc11bcfd
--- /dev/null
+++ b/library/cpp/object_factory/object_factory.h
@@ -0,0 +1,243 @@
+#pragma once
+
+#include <util/system/guard.h>
+#include <util/system/rwlock.h>
+#include <util/generic/map.h>
+#include <util/generic/set.h>
+#include <util/generic/singleton.h>
+#include <util/generic/yexception.h>
+
+namespace NObjectFactory {
+ template <class TProduct, class... TArgs>
+ class IFactoryObjectCreator {
+ public:
+ virtual TProduct* Create(TArgs... args) const = 0;
+ virtual ~IFactoryObjectCreator() {
+ }
+ };
+
+ template <class TProduct>
+ class IFactoryObjectCreator<TProduct, void> {
+ public:
+ virtual TProduct* Create(void) const = 0;
+ virtual ~IFactoryObjectCreator() {
+ }
+ };
+
+#define FACTORY_OBJECT_NAME(Name) \
+ static TString GetTypeName() { \
+ return #Name; \
+ } \
+ virtual TString GetType() const override { \
+ return #Name; \
+ }
+
+ template <class TBaseProduct, class TDerivedProduct, class... TArgs>
+ class TFactoryObjectCreator: public IFactoryObjectCreator<TBaseProduct, TArgs...> {
+ TDerivedProduct* Create(TArgs... args) const override {
+ return new TDerivedProduct(std::forward<TArgs>(args)...);
+ }
+ };
+
+ template <class TBaseProduct, class TDerivedProduct>
+ class TFactoryObjectCreator<TBaseProduct, TDerivedProduct, void>: public IFactoryObjectCreator<TBaseProduct, void> {
+ TDerivedProduct* Create() const override {
+ return new TDerivedProduct();
+ }
+ };
+
+ template <class P, class K, class... TArgs>
+ class IObjectFactory {
+ public:
+ typedef P TProduct;
+ typedef K TKey;
+
+ public:
+ template <class TDerivedProduct>
+ void Register(const TKey& key, IFactoryObjectCreator<TProduct, TArgs...>* creator) {
+ if (!creator)
+ ythrow yexception() << "Please specify non-null creator for " << key;
+
+ TWriteGuard guard(CreatorsLock);
+ if (!Creators.insert(typename ICreators::value_type(key, creator)).second)
+ ythrow yexception() << "Product with key " << key << " already registered";
+ }
+
+ template <class TDerivedProduct>
+ void Register(const TKey& key) {
+ Register<TDerivedProduct>(key, new TFactoryObjectCreator<TProduct, TDerivedProduct, TArgs...>);
+ }
+
+ void GetKeys(TSet<TKey>& keys) const {
+ TReadGuard guard(CreatorsLock);
+ keys.clear();
+ for (typename ICreators::const_iterator i = Creators.begin(), e = Creators.end(); i != e; ++i) {
+ keys.insert(i->first);
+ }
+ }
+
+ protected:
+ IFactoryObjectCreator<TProduct, TArgs...>* GetCreator(const TKey& key) const {
+ TReadGuard guard(CreatorsLock);
+ typename ICreators::const_iterator i = Creators.find(key);
+ return i == Creators.end() ? nullptr : i->second.Get();
+ }
+
+ bool HasImpl(const TKey& key) const {
+ TReadGuard guard(CreatorsLock);
+ return Creators.find(key) != Creators.end();
+ }
+
+ private:
+ typedef TSimpleSharedPtr<IFactoryObjectCreator<TProduct, TArgs...>> ICreatorPtr;
+ typedef TMap<TKey, ICreatorPtr> ICreators;
+ ICreators Creators;
+ TRWMutex CreatorsLock;
+ };
+
+ template <class TProduct, class TKey>
+ class TObjectFactory: public IObjectFactory<TProduct, TKey, void> {
+ public:
+ TProduct* Create(const TKey& key) const {
+ IFactoryObjectCreator<TProduct, void>* creator = IObjectFactory<TProduct, TKey, void>::GetCreator(key);
+ return creator == nullptr ? nullptr : creator->Create();
+ }
+
+ static TString KeysDebugString() {
+ TSet<TString> keys;
+ Singleton<TObjectFactory<TProduct, TKey>>()->GetKeys(keys);
+ TString keysStr;
+ for (auto&& k : keys) {
+ keysStr += k + " ";
+ }
+ return keysStr;
+ }
+
+ static TProduct* Construct(const TKey& key, const TKey& defKey) {
+ TProduct* result = Singleton<TObjectFactory<TProduct, TKey>>()->Create(key);
+ if (!result && !!defKey) {
+ result = Singleton<TObjectFactory<TProduct, TKey>>()->Create(defKey);
+ }
+ return result;
+ }
+
+ static TProduct* Construct(const TKey& key) {
+ TProduct* result = Singleton<TObjectFactory<TProduct, TKey>>()->Create(key);
+ return result;
+ }
+
+ static THolder<TProduct> VerifiedConstruct(const TKey& key) {
+ auto result = MakeHolder(key);
+ Y_VERIFY(result, "Construct by factory failed");
+ return result;
+ }
+
+ template<class... Args>
+ static THolder<TProduct> MakeHolder(Args&&... args) {
+ return THolder<TProduct>(Construct(std::forward<Args>(args)...));
+ }
+
+ static bool Has(const TKey& key) {
+ return Singleton<TObjectFactory<TProduct, TKey>>()->HasImpl(key);
+ }
+
+ static void GetRegisteredKeys(TSet<TKey>& keys) {
+ return Singleton<TObjectFactory<TProduct, TKey>>()->GetKeys(keys);
+ }
+
+ static TSet<TKey> GetRegisteredKeys() {
+ TSet<TKey> keys;
+ Singleton<TObjectFactory<TProduct, TKey>>()->GetKeys(keys);
+ return keys;
+ }
+
+ template <class TDerivedProduct>
+ static TSet<TKey> GetRegisteredKeys() {
+ TSet<TKey> registeredKeys(GetRegisteredKeys());
+ TSet<TKey> fileredKeys;
+ std::copy_if(registeredKeys.begin(), registeredKeys.end(), std::inserter(fileredKeys, fileredKeys.end()), [](const TKey& key) {
+ THolder<TProduct> objectHolder(Construct(key));
+ return !!dynamic_cast<const TDerivedProduct*>(objectHolder.Get());
+ });
+ return fileredKeys;
+ }
+
+ template <class Product>
+ class TRegistrator {
+ public:
+ TRegistrator(const TKey& key, IFactoryObjectCreator<TProduct, void>* creator) {
+ Singleton<TObjectFactory<TProduct, TKey>>()->template Register<Product>(key, creator);
+ }
+
+ TRegistrator(const TKey& key) {
+ Singleton<TObjectFactory<TProduct, TKey>>()->template Register<Product>(key);
+ }
+
+ TRegistrator()
+ : TRegistrator(Product::GetTypeName())
+ {
+ }
+ };
+ };
+
+ template <class TProduct, class TKey, class... TArgs>
+ class TParametrizedObjectFactory: public IObjectFactory<TProduct, TKey, TArgs...> {
+ public:
+ TProduct* Create(const TKey& key, TArgs... args) const {
+ IFactoryObjectCreator<TProduct, TArgs...>* creator = IObjectFactory<TProduct, TKey, TArgs...>::GetCreator(key);
+ return creator == nullptr ? nullptr : creator->Create(std::forward<TArgs>(args)...);
+ }
+
+ static bool Has(const TKey& key) {
+ return Singleton<TParametrizedObjectFactory<TProduct, TKey, TArgs...>>()->HasImpl(key);
+ }
+
+ static TProduct* Construct(const TKey& key, TArgs... args) {
+ return Singleton<TParametrizedObjectFactory<TProduct, TKey, TArgs...>>()->Create(key, std::forward<TArgs>(args)...);
+ }
+
+ template <class... Args>
+ static THolder<TProduct> VerifiedConstruct(Args&&... args) {
+ auto result = MakeHolder(std::forward<Args>(args)...);
+ Y_VERIFY(result, "Construct by factory failed");
+ return result;
+ }
+
+ template<class... Args>
+ static THolder<TProduct> MakeHolder(Args&&... args) {
+ return THolder<TProduct>(Construct(std::forward<Args>(args)...));
+ }
+
+ static void GetRegisteredKeys(TSet<TKey>& keys) {
+ return Singleton<TParametrizedObjectFactory<TProduct, TKey, TArgs...>>()->GetKeys(keys);
+ }
+
+ static TSet<TKey> GetRegisteredKeys() {
+ TSet<TKey> keys;
+ Singleton<TParametrizedObjectFactory<TProduct, TKey, TArgs...>>()->GetKeys(keys);
+ return keys;
+ }
+
+ template <class Product>
+ class TRegistrator {
+ public:
+ TRegistrator(const TKey& key, IFactoryObjectCreator<TProduct, TArgs...>* creator) {
+ Singleton<TParametrizedObjectFactory<TProduct, TKey, TArgs...>>()->template Register<Product>(key, creator);
+ }
+
+ TRegistrator(const TKey& key) {
+ Singleton<TParametrizedObjectFactory<TProduct, TKey, TArgs...>>()->template Register<Product>(key);
+ }
+
+ TRegistrator()
+ : TRegistrator(Product::GetTypeName())
+ {
+ }
+
+ TString GetName() const {
+ return Product::GetTypeName();
+ }
+ };
+ };
+
+}
diff --git a/library/cpp/object_factory/object_factory_ut.cpp b/library/cpp/object_factory/object_factory_ut.cpp
new file mode 100644
index 0000000000..06fb0739ff
--- /dev/null
+++ b/library/cpp/object_factory/object_factory_ut.cpp
@@ -0,0 +1,189 @@
+#include <library/cpp/object_factory/object_factory.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/noncopyable.h>
+#include <util/generic/string.h>
+#include <util/generic/ptr.h>
+
+using namespace NObjectFactory;
+
+struct TArgument {
+ TString Name;
+ void* Discarded;
+};
+
+class ICommonInterface {
+public:
+ virtual ~ICommonInterface() {
+ }
+
+ virtual TString GetValue() const = 0;
+};
+
+class TDirectOrder: public ICommonInterface {
+public:
+ TDirectOrder(const TString& provider, float factor, TArgument& argument)
+ : Provider(provider)
+ , Factor(factor)
+ , Argument(argument)
+ {
+ }
+
+ TString GetValue() const override {
+ return Provider + ToString(Factor) + Argument.Name;
+ }
+
+private:
+ const TString Provider;
+ const float Factor;
+ const TArgument Argument;
+};
+
+class TInverseOrder: public ICommonInterface {
+public:
+ TInverseOrder(const TString& provider, float factor, TArgument& argument)
+ : Provider(provider)
+ , Factor(factor)
+ , Argument(argument)
+ {
+ }
+
+ TString GetValue() const override {
+ return Argument.Name + ToString(Factor) + Provider;
+ }
+
+private:
+ const TString Provider;
+ const float Factor;
+ const TArgument Argument;
+};
+
+struct TDirectOrderCreator: public IFactoryObjectCreator<ICommonInterface, const TString&, float, TArgument&> {
+ ICommonInterface* Create(const TString& provider, float factor, TArgument& argument) const override {
+ ++CallsCounter;
+ return new TDirectOrder(provider, factor, argument);
+ }
+
+ static int CallsCounter;
+};
+int TDirectOrderCreator::CallsCounter = 0;
+
+using TTestFactory = TParametrizedObjectFactory<ICommonInterface, TString, const TString&, float, TArgument&>;
+
+static TTestFactory::TRegistrator<TDirectOrder> Direct("direct", new TDirectOrderCreator);
+static TTestFactory::TRegistrator<TInverseOrder> Inverse("inverse");
+
+
+
+class IMoveableOnlyInterface {
+public:
+ virtual ~IMoveableOnlyInterface() {
+ }
+
+ virtual TString GetValue() const = 0;
+};
+
+class TMoveableOnly: public IMoveableOnlyInterface, public TMoveOnly {
+public:
+ TMoveableOnly(TString&& value)
+ : Value(value)
+ {}
+
+ TString GetValue() const override {
+ return Value;
+ }
+
+private:
+ const TString Value;
+};
+
+
+using TMoveableOnlyFactory = TParametrizedObjectFactory<IMoveableOnlyInterface, TString, TString&&>;
+
+static TMoveableOnlyFactory::TRegistrator<TMoveableOnly> MoveableOnlyReg("move");
+
+
+
+class TMoveableOnly2: public IMoveableOnlyInterface, public TMoveOnly {
+public:
+ TMoveableOnly2(THolder<TString>&& value)
+ : Value(std::move(value))
+ {}
+
+ TString GetValue() const override {
+ return *Value;
+ }
+
+private:
+ const THolder<TString> Value;
+};
+
+
+using TMoveableOnly2Factory = TParametrizedObjectFactory<IMoveableOnlyInterface, TString, THolder<TString>&&>;
+
+static TMoveableOnly2Factory::TRegistrator<TMoveableOnly2> MoveableOnly2Reg("move2");
+
+class TDirectOrderDifferentSignature : public TDirectOrder {
+public:
+ TDirectOrderDifferentSignature(const TString& provider, TArgument& argument) :
+ TDirectOrder(provider, 0.01f, argument)
+ {
+ }
+
+};
+
+struct TDirectOrderDSCreator: public IFactoryObjectCreator<ICommonInterface, const TString&, float, TArgument&> {
+ ICommonInterface* Create(const TString& provider, float factor, TArgument& argument) const override {
+ Y_UNUSED(factor);
+ return new TDirectOrderDifferentSignature(provider, argument);
+ }
+};
+
+
+static TTestFactory::TRegistrator<TDirectOrderDifferentSignature> DirectDs("direct_ds", new TDirectOrderDSCreator);
+
+Y_UNIT_TEST_SUITE(TestObjectFactory) {
+ Y_UNIT_TEST(TestParametrized) {
+ TArgument directArg{"Name", nullptr};
+ TArgument inverseArg{"Fake", nullptr};
+ THolder<ICommonInterface> direct(TTestFactory::Construct("direct", "prov", 0.42, directArg));
+ THolder<ICommonInterface> inverse(TTestFactory::Construct("inverse", "prov2", 1, inverseArg));
+
+ UNIT_ASSERT(!!direct);
+ UNIT_ASSERT(!!inverse);
+
+ UNIT_ASSERT(direct->GetValue() == "prov0.42Name");
+ UNIT_ASSERT(inverse->GetValue() == "Fake1prov2");
+
+ UNIT_ASSERT_EQUAL(TDirectOrderCreator::CallsCounter, 1);
+ }
+
+ Y_UNIT_TEST(TestMoveableOnly) {
+ TString v = "value1";
+
+ THolder<IMoveableOnlyInterface> moveableOnly(TMoveableOnlyFactory::Construct("move", std::move(v)));
+
+ UNIT_ASSERT(!!moveableOnly);
+
+ UNIT_ASSERT(moveableOnly->GetValue() == "value1");
+ }
+
+ Y_UNIT_TEST(TestMoveableOnly2) {
+ THolder<TString> v = MakeHolder<TString>("value2");
+
+ THolder<IMoveableOnlyInterface> moveableOnly2(TMoveableOnly2Factory::Construct("move2", std::move(v)));
+
+ UNIT_ASSERT(!!moveableOnly2);
+
+ UNIT_ASSERT(moveableOnly2->GetValue() == "value2");
+ }
+
+ Y_UNIT_TEST(TestDifferentSignature) {
+ TArgument directArg{"Name", nullptr};
+ THolder<ICommonInterface> directDs(TTestFactory::Construct("direct_ds", "prov", 0.42, directArg));
+
+ UNIT_ASSERT(!!directDs);
+
+ UNIT_ASSERT_EQUAL(directDs->GetValue(), "prov0.01Name");
+ }
+}
diff --git a/library/cpp/object_factory/ut/ya.make b/library/cpp/object_factory/ut/ya.make
new file mode 100644
index 0000000000..5a870072fc
--- /dev/null
+++ b/library/cpp/object_factory/ut/ya.make
@@ -0,0 +1,15 @@
+UNITTEST()
+
+OWNER(svshevtsov)
+
+PEERDIR(
+ ADDINCL library/cpp/object_factory
+)
+
+SRCDIR(library/cpp/object_factory)
+
+SRCS(
+ object_factory_ut.cpp
+)
+
+END()
diff --git a/library/cpp/object_factory/ya.make b/library/cpp/object_factory/ya.make
new file mode 100644
index 0000000000..bb93f75c23
--- /dev/null
+++ b/library/cpp/object_factory/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(ivanmorozov)
+
+SRCS(
+ object_factory.cpp
+)
+
+END()
diff --git a/library/cpp/on_disk/chunks/chunked_helpers.cpp b/library/cpp/on_disk/chunks/chunked_helpers.cpp
new file mode 100644
index 0000000000..b7adba2753
--- /dev/null
+++ b/library/cpp/on_disk/chunks/chunked_helpers.cpp
@@ -0,0 +1,67 @@
+#include <util/ysaveload.h>
+
+#include "chunked_helpers.h"
+
+TBlob GetBlock(const TBlob& blob, size_t index) {
+ TChunkedDataReader reader(blob);
+ if (index >= reader.GetBlocksCount())
+ ythrow yexception() << "index " << index << " is >= than block count " << reader.GetBlocksCount();
+ size_t begin = (const char*)reader.GetBlock(index) - (const char*)blob.Data();
+ return blob.SubBlob(begin, begin + reader.GetBlockLen(index));
+}
+
+/*************************** TNamedChunkedDataReader ***************************/
+
+static const char* NamedChunkedDataMagic = "NamedChunkedData";
+
+TNamedChunkedDataReader::TNamedChunkedDataReader(const TBlob& blob)
+ : TChunkedDataReader(blob)
+{
+ if (TChunkedDataReader::GetBlocksCount() < 1)
+ throw yexception() << "Too few blocks";
+
+ size_t block = TChunkedDataReader::GetBlocksCount() - 1;
+ size_t magicLen = strlen(NamedChunkedDataMagic);
+ if (GetBlockLen(block) < magicLen || memcmp(GetBlock(block), NamedChunkedDataMagic, magicLen) != 0)
+ throw yexception() << "Not a valid named chunked data file";
+
+ TMemoryInput input(static_cast<const char*>(GetBlock(block)) + magicLen, GetBlockLen(block) - magicLen);
+ Load(&input, Names);
+
+ size_t index = 0;
+ for (TVector<TString>::const_iterator it = Names.begin(); it != Names.end(); ++it, ++index) {
+ if (!it->empty())
+ NameToIndex[*it] = index;
+ }
+}
+
+/*************************** TNamedChunkedDataWriter ***************************/
+
+TNamedChunkedDataWriter::TNamedChunkedDataWriter(IOutputStream& slave)
+ : TChunkedDataWriter(slave)
+{
+}
+
+TNamedChunkedDataWriter::~TNamedChunkedDataWriter() {
+}
+
+void TNamedChunkedDataWriter::NewBlock() {
+ NewBlock("");
+}
+
+void TNamedChunkedDataWriter::NewBlock(const TString& name) {
+ if (!name.empty()) {
+ if (NameToIndex.count(name) != 0)
+ throw yexception() << "Block name is not unique";
+ NameToIndex[name] = Names.size();
+ }
+ Names.push_back(name);
+ TChunkedDataWriter::NewBlock();
+}
+
+void TNamedChunkedDataWriter::WriteFooter() {
+ NewBlock("");
+ Write(NamedChunkedDataMagic);
+ Save(this, Names);
+ TChunkedDataWriter::WriteFooter();
+}
diff --git a/library/cpp/on_disk/chunks/chunked_helpers.h b/library/cpp/on_disk/chunks/chunked_helpers.h
new file mode 100644
index 0000000000..5fa96afdca
--- /dev/null
+++ b/library/cpp/on_disk/chunks/chunked_helpers.h
@@ -0,0 +1,674 @@
+#pragma once
+
+#include <util/generic/vector.h>
+#include <util/generic/buffer.h>
+#include <util/generic/hash_set.h>
+#include <util/generic/cast.h>
+#include <util/generic/ymath.h>
+#include <util/memory/blob.h>
+#include <util/stream/buffer.h>
+#include <util/stream/mem.h>
+#include <util/system/unaligned_mem.h>
+#include <util/ysaveload.h>
+
+#include "reader.h"
+#include "writer.h"
+
+#include <cmath>
+#include <cstddef>
+
+template <typename T>
+class TYVector {
+private:
+ ui32 Size;
+ const T* Data;
+
+public:
+ TYVector(const TBlob& blob)
+ : Size(IntegerCast<ui32>(ReadUnaligned<ui64>(blob.Data())))
+ , Data((const T*)((const char*)blob.Data() + sizeof(ui64)))
+ {
+ }
+
+ void Get(size_t idx, T& t) const {
+ assert(idx < (size_t)Size);
+ t = ReadUnaligned<T>(Data + idx);
+ }
+
+ const T& At(size_t idx) const {
+ assert(idx < (size_t)Size);
+ return Data[idx];
+ }
+
+ size_t GetSize() const {
+ return Size;
+ }
+
+ size_t RealSize() const {
+ return sizeof(ui64) + Size * sizeof(T);
+ }
+
+ ~TYVector() = default;
+};
+
+template <typename T>
+class TYVectorWriter {
+private:
+ TVector<T> Vector;
+
+public:
+ TYVectorWriter() = default;
+
+ void PushBack(const T& value) {
+ Vector.push_back(value);
+ }
+
+ void Save(IOutputStream& out) const {
+ ui64 uSize = (ui64)Vector.size();
+ out.Write(&uSize, sizeof(uSize));
+ out.Write(Vector.data(), Vector.size() * sizeof(T));
+ }
+
+ const T& At(size_t idx) const {
+ assert(idx < Size());
+ return Vector[idx];
+ }
+
+ T& At(size_t idx) {
+ assert(idx < Size());
+ return Vector[idx];
+ }
+
+ void Clear() {
+ Vector.clear();
+ }
+
+ size_t Size() const {
+ return Vector.size();
+ }
+
+ void Resize(size_t size) {
+ Vector.resize(size);
+ }
+
+ void Resize(size_t size, const T& value) {
+ Vector.resize(size, value);
+ }
+};
+
+template <typename T, bool>
+struct TYVectorG;
+
+template <typename X>
+struct TYVectorG<X, false> {
+ typedef TYVector<X> T;
+};
+
+template <typename X>
+struct TYVectorG<X, true> {
+ typedef TYVectorWriter<X> T;
+};
+
+template <typename T>
+struct TIsMemsetThisWithZeroesSupported {
+ enum {
+ Result = TTypeTraits<T>::IsPod
+ };
+};
+
+#define MEMSET_THIS_WITH_ZEROES_SUPPORTED(type) \
+ template <> \
+ struct TIsMemsetThisWithZeroesSupported<type> { \
+ enum { \
+ Result = true \
+ }; \
+ };
+
+class TPlainHashCommon {
+protected:
+#pragma pack(push, 8)
+ template <typename TKey, typename TValue>
+ class TPackedPair {
+ private:
+ typedef TPackedPair<TKey, TValue> TThis;
+ TKey Key;
+ TValue Value;
+
+ private:
+ static_assert(TIsMemsetThisWithZeroesSupported<TKey>::Result, "expect TIsMemsetThisWithZeroesSupported<TKey>::Result");
+ static_assert(TIsMemsetThisWithZeroesSupported<TValue>::Result, "expect TIsMemsetThisWithZeroesSupported<TValue>::Result");
+
+ /// to aviod uninitialized bytes
+ void Init(const TKey& key, const TValue& value) {
+ memset(static_cast<TThis*>(this), 0, sizeof(TThis));
+ Key = key;
+ Value = value;
+ }
+
+ public:
+ TPackedPair(typename TTypeTraits<TKey>::TFuncParam key, typename TTypeTraits<TValue>::TFuncParam value) {
+ Init(key, value);
+ }
+
+ TPackedPair(const TThis& rhs) {
+ Init(rhs.Key, rhs.Value);
+ }
+
+ TPackedPair& operator=(const TThis& rhs) {
+ if (this != &rhs) {
+ Init(rhs.Key, rhs.Value);
+ }
+ return *this;
+ }
+
+ TPackedPair() {
+ Init(TKey(), TValue());
+ }
+
+ typename TTypeTraits<TKey>::TFuncParam First() const {
+ return Key;
+ }
+
+ typename TTypeTraits<TValue>::TFuncParam Second() const {
+ return Value;
+ }
+
+ static TKey GetFirst(const void* self) {
+ static constexpr size_t offset = offsetof(TThis, Key);
+ return ReadUnaligned<TKey>(reinterpret_cast<const char*>(self) + offset);
+ }
+
+ static TValue GetSecond(const void* self) {
+ static constexpr size_t offset = offsetof(TThis, Value);
+ return ReadUnaligned<TValue>(reinterpret_cast<const char*>(self) + offset);
+ }
+ };
+#pragma pack(pop)
+
+protected:
+ static const ui16 VERSION_ID = 2;
+
+#pragma pack(push, 8)
+ struct TInterval {
+ static const ui32 INVALID = (ui32)-1;
+ ui32 Offset;
+ ui32 Length;
+
+ TInterval()
+ : Offset(INVALID)
+ , Length(INVALID)
+ {
+ }
+
+ TInterval(ui32 offset, ui32 length)
+ : Offset(offset)
+ , Length(length)
+ {
+ }
+
+ static inline ui32 GetOffset(const TInterval* self) {
+ static constexpr size_t offset = offsetof(TInterval, Offset);
+ return ReadUnaligned<ui32>(reinterpret_cast<const char*>(self) + offset);
+ }
+
+ static inline ui32 GetLength(const TInterval* self) {
+ static constexpr size_t offset = offsetof(TInterval, Length);
+ return ReadUnaligned<ui32>(reinterpret_cast<const char*>(self) + offset);
+ }
+ };
+#pragma pack(pop)
+ static_assert(8 == sizeof(TInterval), "expect 8 == sizeof(TInterval)");
+
+ template <typename TKey>
+ static ui32 KeyHash(typename TTypeTraits<TKey>::TFuncParam key, ui16 bits) {
+ Y_ASSERT(bits < 32);
+ const ui32 res = ui32(key) & ((ui32(1) << bits) - 1);
+
+ Y_ASSERT(res < (ui32(1) << bits));
+ return res;
+ }
+};
+
+template <typename TKey, typename TValue>
+class TPlainHashWriter : TPlainHashCommon {
+private:
+ typedef TPackedPair<TKey, TValue> TKeyValuePair;
+ typedef TVector<TKeyValuePair> TData;
+ TData Data;
+ typedef TVector<TData> TData2;
+
+ bool IsPlainEnought(ui16 bits) const {
+ TVector<size_t> counts(1LL << bits, 0);
+ for (size_t i = 0; i < Data.size(); ++i) {
+ size_t& count = counts[KeyHash<TKey>(TKeyValuePair::GetFirst(&Data[i]), bits)];
+ ++count;
+ if (count > 2)
+ return false;
+ }
+ return true;
+ }
+
+public:
+ void Add(const TKey& key, const TValue& value) {
+ Data.push_back(TKeyValuePair(key, value));
+ }
+
+ void Save(IOutputStream& out) const {
+ Y_ASSERT(Data.size() < Max<ui32>());
+
+ WriteBin<ui16>(&out, VERSION_ID);
+ static const ui32 PAIR_SIZE = sizeof(TKeyValuePair);
+ WriteBin<ui32>(&out, PAIR_SIZE);
+
+ ui16 bits;
+ if (!Data.empty()) {
+ bits = (ui16)(log((float)Data.size()) / log(2.f));
+ while ((bits < 22) && !IsPlainEnought(bits))
+ ++bits;
+ } else {
+ bits = 0;
+ }
+ WriteBin<ui16>(&out, bits);
+ WriteBin<ui32>(&out, (ui32)Data.size());
+
+ const ui32 nBuckets = ui32(1) << bits;
+ TData2 data2(nBuckets);
+ for (size_t i = 0; i < Data.size(); ++i)
+ data2[KeyHash<TKey>(TKeyValuePair::GetFirst(&Data[i]), bits)].push_back(Data[i]);
+
+ typedef TVector<TInterval> TIntervals;
+ TIntervals intervals(nBuckets);
+ ui32 offset = 0;
+ for (ui32 i = 0; i < nBuckets; ++i) {
+ intervals[i].Offset = offset;
+ intervals[i].Length = (ui32)data2[i].size();
+ offset += (ui32)data2[i].size();
+ }
+#ifndef NDEBUG
+ for (ui32 i = 0; i < nBuckets; ++i) {
+ for (size_t j = 0; j < data2[i].size(); ++j)
+ for (size_t k = j + 1; k < data2[i].size(); ++k)
+ if (TKeyValuePair::GetFirst(&data2[i][j]) == TKeyValuePair::GetFirst(&data2[i][k]))
+ ythrow yexception() << "key clash";
+ }
+#endif
+ out.Write(intervals.data(), intervals.size() * sizeof(intervals[0]));
+ for (ui32 i = 0; i < nBuckets; ++i)
+ out.Write(data2[i].data(), data2[i].size() * sizeof(data2[i][0]));
+ }
+};
+
+template <typename TKey, typename TValue>
+class TPlainHash : TPlainHashCommon {
+private:
+ typedef TPackedPair<TKey, TValue> TKeyValuePair;
+
+ const char* P;
+
+ ui16 GetBits() const {
+ return ReadUnaligned<ui16>(P + 6);
+ }
+
+ ui32 GetSize() const {
+ return ReadUnaligned<ui32>(P + 8);
+ }
+
+ const TInterval* GetIntervals() const {
+ return (const TInterval*)(P + 12);
+ }
+
+ const TKeyValuePair* GetData() const {
+ return (const TKeyValuePair*)(GetIntervals() + (1ULL << GetBits()));
+ }
+
+ template <typename T>
+ void Init(const T* p) {
+ static_assert(sizeof(T) == 1, "expect sizeof(T) == 1");
+ P = reinterpret_cast<const char*>(p);
+#ifndef NDEBUG
+ ui16 version = ReadUnaligned<ui16>(p);
+ if (version != VERSION_ID)
+ ythrow yexception() << "bad version: " << version;
+ static const ui32 PAIR_SIZE = sizeof(TKeyValuePair);
+ const ui32 size = ReadUnaligned<ui32>(p + 2);
+ if (size != PAIR_SIZE)
+ ythrow yexception() << "bad size " << size << " instead of " << PAIR_SIZE;
+#endif
+ }
+
+public:
+ typedef const TKeyValuePair* TConstIterator;
+
+ TPlainHash(const char* p) {
+ Init(p);
+ }
+
+ TPlainHash(const TBlob& blob) {
+ Init(blob.Begin());
+ }
+
+ bool Find(typename TTypeTraits<TKey>::TFuncParam key, TValue* res) const {
+ // Cerr << GetBits() << "\t" << (1 << GetBits()) << "\t" << GetSize() << Endl;
+ const ui32 hash = KeyHash<TKey>(key, GetBits());
+ const TInterval* intervalPtr = GetIntervals();
+ const TKeyValuePair* pair = GetData() + TInterval::GetOffset(intervalPtr + hash);
+ const ui32 length = TInterval::GetLength(intervalPtr + hash);
+ for (ui32 i = 0; i < length; ++i, ++pair) {
+ if (TKeyValuePair::GetFirst(pair) == key) {
+ *res = TKeyValuePair::GetSecond(pair);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ TValue Get(typename TTypeTraits<TKey>::TFuncParam key) const {
+ TValue res;
+ if (Find(key, &res))
+ return res;
+ else
+ ythrow yexception() << "key not found";
+ }
+
+ TConstIterator Begin() const {
+ return GetData();
+ }
+
+ TConstIterator End() const {
+ return GetData() + GetSize();
+ }
+
+ const char* ByteEnd() const {
+ return (const char*)(GetData() + GetSize());
+ }
+
+ size_t ByteSize() const {
+ return 12 + sizeof(TInterval) * (size_t(1) << GetBits()) + sizeof(TKeyValuePair) * GetSize();
+ }
+};
+
+template <typename Key, typename Value, bool>
+struct TPlainHashG;
+
+template <typename Key, typename Value>
+struct TPlainHashG<Key, Value, false> {
+ typedef TPlainHash<Key, Value> T;
+};
+
+template <typename Key, typename Value>
+struct TPlainHashG<Key, Value, true> {
+ typedef TPlainHashWriter<Key, Value> T;
+};
+
+template <typename T>
+class TSingleValue {
+private:
+ const T* Value;
+
+public:
+ TSingleValue(const TBlob& blob) {
+ Y_ASSERT(blob.Length() >= sizeof(T));
+ Y_ASSERT(blob.Length() <= sizeof(T) + 16);
+ Value = reinterpret_cast<const T*>(blob.Begin());
+ }
+
+ const T& Get() const {
+ return *Value;
+ }
+};
+
+template <typename T>
+class TSingleValueWriter {
+private:
+ T Value;
+
+public:
+ TSingleValueWriter() = default;
+
+ TSingleValueWriter(const T& value)
+ : Value(value)
+ {
+ }
+
+ void Set(const T& value) {
+ Value = value;
+ }
+
+ void Save(IOutputStream& out) const {
+ out.Write(&Value, sizeof(Value));
+ }
+};
+
+TBlob GetBlock(const TBlob& data, size_t index);
+
+template <class T>
+void WriteBlock(TChunkedDataWriter& writer, const T& t) {
+ writer.NewBlock();
+ t.Save(writer);
+}
+
+template <class T>
+void WriteBlock(TChunkedDataWriter& writer, T& t) {
+ writer.NewBlock();
+ t.Save(writer);
+}
+
+// Extends TChunkedDataWriter, allowing user to name blocks with arbitrary strings.
+class TNamedChunkedDataWriter: public TChunkedDataWriter {
+public:
+ TNamedChunkedDataWriter(IOutputStream& slave);
+ ~TNamedChunkedDataWriter() override;
+
+ // Start a new unnamed block, overrides TChunkedDataReader::NewBlock().
+ void NewBlock();
+
+ // Start a new block with given name (possibly empty, in which case block is unnamed).
+ // Throws an exception if name is a duplicate.
+ void NewBlock(const TString& name);
+
+ void WriteFooter();
+
+private:
+ TVector<TString> Names;
+ THashMap<TString, size_t> NameToIndex;
+};
+
+class TNamedChunkedDataReader: public TChunkedDataReader {
+public:
+ TNamedChunkedDataReader(const TBlob& blob);
+
+ inline bool HasBlock(const char* name) const {
+ return NameToIndex.find(name) != NameToIndex.end();
+ }
+
+ inline size_t GetIndexByName(const char* name) const {
+ THashMap<TString, size_t>::const_iterator it = NameToIndex.find(name);
+ if (it == NameToIndex.end())
+ throw yexception() << "Block \"" << name << "\" is not found";
+ else
+ return it->second;
+ }
+
+ // Returns number of blocks written to the file by user of TNamedChunkedDataReader.
+ inline size_t GetBlocksCount() const {
+ // Last block is for internal usage
+ return TChunkedDataReader::GetBlocksCount() - 1;
+ }
+
+ inline const char* GetBlockName(size_t index) const {
+ Y_ASSERT(index < GetBlocksCount());
+ return Names[index].data();
+ }
+
+ inline const void* GetBlockByName(const char* name) const {
+ return GetBlock(GetIndexByName(name));
+ }
+
+ inline size_t GetBlockLenByName(const char* name) const {
+ return GetBlockLen(GetIndexByName(name));
+ }
+
+ inline TBlob GetBlobByName(const char* name) const {
+ size_t id = GetIndexByName(name);
+ return TBlob::NoCopy(GetBlock(id), GetBlockLen(id));
+ }
+
+ inline bool GetBlobByName(const char* name, TBlob& blob) const {
+ THashMap<TString, size_t>::const_iterator it = NameToIndex.find(name);
+ if (it == NameToIndex.end())
+ return false;
+ blob = TBlob::NoCopy(GetBlock(it->second), GetBlockLen(it->second));
+ return true;
+ }
+
+private:
+ TVector<TString> Names;
+ THashMap<TString, size_t> NameToIndex;
+};
+
+template <class T>
+struct TSaveLoadVectorNonPodElement {
+ static inline void Save(IOutputStream* out, const T& t) {
+ TSerializer<T>::Save(out, t);
+ }
+
+ static inline void Load(IInputStream* in, T& t, size_t elementSize) {
+ Y_ASSERT(elementSize > 0);
+ TSerializer<T>::Load(in, t);
+ }
+};
+
+template <class T, bool isPod>
+class TVectorTakingIntoAccountThePodType {
+private:
+ ui64 SizeofOffsets;
+ const ui64* Offsets;
+ const char* Data;
+
+public:
+ TVectorTakingIntoAccountThePodType(const TBlob& blob) {
+ SizeofOffsets = ReadUnaligned<ui64>(blob.Begin());
+ Y_ASSERT(SizeofOffsets > 0);
+ Offsets = reinterpret_cast<const ui64*>(blob.Begin() + sizeof(ui64));
+ Data = reinterpret_cast<const char*>(blob.Begin() + sizeof(ui64) + SizeofOffsets * sizeof(ui64));
+ }
+
+ size_t GetSize() const {
+ return (size_t)(SizeofOffsets - 1);
+ }
+
+ size_t GetLength(ui64 index) const {
+ if (index + 1 >= SizeofOffsets)
+ ythrow yexception() << "bad offset";
+ return IntegerCast<size_t>(ReadUnaligned<ui64>(Offsets + index + 1) - ReadUnaligned<ui64>(Offsets + index));
+ }
+
+ void Get(ui64 index, T& t) const {
+ const size_t len = GetLength(index);
+ TMemoryInput input(Data + ReadUnaligned<ui64>(Offsets + index), len);
+ TSaveLoadVectorNonPodElement<T>::Load(&input, t, len);
+ }
+
+ T Get(ui64 index) const {
+ T ret;
+ Get(index, ret);
+ return ret;
+ }
+
+ size_t RealSize() const {
+ return sizeof(ui64) * (SizeofOffsets + 1) + ReadUnaligned<ui64>(Offsets + SizeofOffsets - 1);
+ }
+};
+
+template <class T, bool isPod>
+class TVectorTakingIntoAccountThePodTypeWriter : TNonCopyable {
+private:
+ typedef TVector<ui64> TOffsets;
+ TOffsets Offsets;
+ TBuffer Data;
+ TBufferOutput DataStream;
+
+public:
+ TVectorTakingIntoAccountThePodTypeWriter()
+ : DataStream(Data)
+ {
+ }
+
+ void PushBack(const T& t) {
+ Offsets.push_back((ui64) Data.size());
+ TSaveLoadVectorNonPodElement<T>::Save(&DataStream, t);
+ }
+
+ size_t Size() const {
+ return Offsets.size();
+ }
+
+ void Save(IOutputStream& out) const {
+ ui64 sizeofOffsets = Offsets.size() + 1;
+ out.Write(&sizeofOffsets, sizeof(sizeofOffsets));
+ out.Write(Offsets.data(), Offsets.size() * sizeof(Offsets[0]));
+ ui64 lastOffset = (ui64) Data.size();
+ out.Write(&lastOffset, sizeof(lastOffset));
+ out.Write(Data.data(), Data.size());
+ }
+};
+
+template <class T>
+class TVectorTakingIntoAccountThePodType<T, true>: public TYVector<T> {
+public:
+ TVectorTakingIntoAccountThePodType(const TBlob& blob)
+ : TYVector<T>(blob)
+ {
+ }
+};
+
+template <class T>
+class TVectorTakingIntoAccountThePodTypeWriter<T, true>: public TYVectorWriter<T> {
+};
+
+template <typename T>
+class TGeneralVector: public TVectorTakingIntoAccountThePodType<T, TTypeTraits<T>::IsPod> {
+ typedef TVectorTakingIntoAccountThePodType<T, TTypeTraits<T>::IsPod> TBase;
+
+public:
+ TGeneralVector(const TBlob& blob)
+ : TBase(blob)
+ {
+ }
+};
+
+template <typename T>
+class TGeneralVectorWriter: public TVectorTakingIntoAccountThePodTypeWriter<T, TTypeTraits<T>::IsPod> {
+};
+
+template <typename TItem, bool>
+struct TGeneralVectorG;
+
+template <typename TItem>
+struct TGeneralVectorG<TItem, false> {
+ typedef TGeneralVector<TItem> T;
+};
+
+template <typename TItem>
+struct TGeneralVectorG<TItem, true> {
+ typedef TGeneralVectorWriter<TItem> T;
+};
+
+template <>
+struct TSaveLoadVectorNonPodElement<TString> {
+ static inline void Save(IOutputStream* out, const TString& s) {
+ out->Write(s.data(), s.size() + 1);
+ }
+
+ static inline void Load(TMemoryInput* in, TString& s, size_t elementSize) {
+ Y_ASSERT(elementSize > 0 && in->Avail() >= elementSize);
+ s.assign(in->Buf(), elementSize - 1); /// excluding 0 at the end
+ }
+};
+
+template <bool G>
+struct TStringsVectorG: public TGeneralVectorG<TString, G> {
+};
+
+using TStringsVector = TGeneralVector<TString>;
+using TStringsVectorWriter = TGeneralVectorWriter<TString>;
diff --git a/library/cpp/on_disk/chunks/chunks_ut.cpp b/library/cpp/on_disk/chunks/chunks_ut.cpp
new file mode 100644
index 0000000000..f727647f7f
--- /dev/null
+++ b/library/cpp/on_disk/chunks/chunks_ut.cpp
@@ -0,0 +1,329 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/file.h>
+#include <util/system/filemap.h>
+#include <util/system/tempfile.h>
+
+#include "chunked_helpers.h"
+
+/// Data for TChunkedHelpersTest::TestGeneralVector
+struct TPodStruct {
+ int x;
+ float y;
+ TPodStruct(int _x = 0, float _y = 0)
+ : x(_x)
+ , y(_y)
+ {
+ }
+};
+/// And its serialization
+template <>
+struct TSaveLoadVectorNonPodElement<TPodStruct> {
+ typedef TPodStruct TItem;
+ static inline void Save(IOutputStream* out, const TItem& item) {
+ TSerializer<int>::Save(out, item.x);
+ TSerializer<float>::Save(out, item.y);
+ }
+
+ static inline void Load(IInputStream* in, TItem& item, size_t elementSize) {
+ Y_ASSERT(elementSize == sizeof(TItem));
+ TSerializer<int>::Load(in, item.x);
+ TSerializer<float>::Load(in, item.y);
+ }
+};
+
+class TChunkedHelpersTest: public TTestBase {
+ UNIT_TEST_SUITE(TChunkedHelpersTest);
+ UNIT_TEST(TestHash)
+ UNIT_TEST(TestGeneralVector)
+ UNIT_TEST(TestStrings);
+ UNIT_TEST(TestNamedChunkedData);
+ UNIT_TEST_SUITE_END();
+
+public:
+ void TestHash() {
+ {
+ TBufferStream stream;
+ {
+ TPlainHashWriter<ui64, ui16> writer;
+ writer.Add(5, 7);
+ writer.Save(stream);
+ }
+
+ {
+ TBlob temp = TBlob::FromStreamSingleThreaded(stream);
+ TPlainHash<ui64, ui16> reader(temp);
+ ui16 value = 0;
+ UNIT_ASSERT(reader.Find(5, &value));
+ UNIT_ASSERT_EQUAL(7, value);
+ UNIT_ASSERT(!reader.Find(6, &value));
+ }
+ }
+
+ {
+ TBufferStream stream;
+ int v = 1;
+ wchar16 k = 'a';
+ {
+ TPlainHashWriter<wchar16, void*> writer;
+ writer.Add(k, &v);
+ writer.Save(stream);
+ }
+ {
+ TBlob temp = TBlob::FromStreamSingleThreaded(stream);
+ TPlainHash<wchar16, void*> reader(temp);
+ void* value = nullptr;
+ UNIT_ASSERT(reader.Find(k, &value));
+ UNIT_ASSERT_EQUAL((int*)value, &v);
+ }
+ }
+ }
+
+ void TestGeneralVector() {
+ { /// ui32
+ const size_t N = 3;
+ TBufferStream stream;
+ {
+ TGeneralVectorWriter<ui32> writer;
+ for (size_t i = 0; i < N; ++i)
+ writer.PushBack(i);
+ writer.Save(stream);
+ }
+ {
+ TBlob temp = TBlob::FromStreamSingleThreaded(stream);
+ TGeneralVector<ui32> reader(temp);
+ UNIT_ASSERT_EQUAL(reader.GetSize(), N);
+ for (size_t i = 0; i < N; ++i) {
+ ui32 value;
+ reader.Get(i, value);
+ UNIT_ASSERT_EQUAL(value, i);
+ UNIT_ASSERT_EQUAL(reader.At(i), i);
+ }
+ UNIT_ASSERT_EQUAL(reader.RealSize(), sizeof(ui64) + N * sizeof(ui32));
+ }
+ }
+ { /// TString
+ const size_t N = 4;
+ TBufferStream stream;
+ {
+ TGeneralVectorWriter<TString> writer;
+ for (size_t i = 0; i < N; ++i)
+ writer.PushBack(ToString(i));
+ writer.Save(stream);
+ }
+ {
+ TBlob temp = TBlob::FromStreamSingleThreaded(stream);
+ TGeneralVector<TString> reader(temp);
+ UNIT_ASSERT_EQUAL(reader.GetSize(), N);
+ for (size_t i = 0; i < N; ++i) {
+ TString value;
+ reader.Get(i, value);
+ UNIT_ASSERT_EQUAL(value, ToString(i));
+ UNIT_ASSERT_EQUAL(reader.Get(i), ToString(i));
+ }
+ UNIT_ASSERT_EQUAL(reader.RealSize(), sizeof(ui64) * (N + 2) + N * 2);
+ }
+ }
+ { /// some other struct
+ typedef TPodStruct TItem;
+ const size_t N = 2;
+ TBufferStream stream;
+ {
+ TGeneralVectorWriter<TItem> writer;
+ writer.PushBack(TItem(1, 2));
+ writer.PushBack(TItem(3, 4));
+ writer.Save(stream);
+ }
+ {
+ TBlob temp = TBlob::FromStreamSingleThreaded(stream);
+ TGeneralVector<TItem> reader(temp);
+ UNIT_ASSERT_EQUAL(reader.GetSize(), N);
+
+ TItem value;
+ reader.Get(0, value);
+ UNIT_ASSERT(value.x == 1 && value.y == 2.0);
+
+ reader.Get(1, value);
+ UNIT_ASSERT(value.x == 3 && value.y == 4.0);
+
+ UNIT_ASSERT_EQUAL(reader.RealSize(), sizeof(ui64) * (N + 2) + N * sizeof(TItem));
+ }
+ }
+ { /// pointer
+ const size_t N = 3;
+ TVector<int> data_holder(N);
+ int* a = &(data_holder[0]);
+ TBufferStream stream;
+ {
+ TGeneralVectorWriter<int*> writer;
+ for (size_t i = 0; i < N; ++i) {
+ a[i] = i;
+ writer.PushBack(a + i);
+ }
+ writer.Save(stream);
+ }
+ {
+ TBlob temp = TBlob::FromStreamSingleThreaded(stream);
+ TGeneralVector<int*> reader(temp);
+ UNIT_ASSERT_EQUAL(reader.GetSize(), N);
+ for (size_t i = 0; i < N; ++i) {
+ int* value;
+ reader.Get(i, value);
+ UNIT_ASSERT_EQUAL(value, a + i);
+ UNIT_ASSERT_EQUAL(reader.At(i), a + i);
+ }
+ UNIT_ASSERT_EQUAL(reader.RealSize(), sizeof(ui64) + N * sizeof(int*));
+ }
+ }
+ { /// std::pair<int, int>
+ typedef std::pair<int, int> TItem;
+ const size_t N = 3;
+ TBufferStream stream;
+ {
+ TGeneralVectorWriter<TItem> writer;
+ for (size_t i = 0; i < N; ++i)
+ writer.PushBack(TItem(i, i));
+ writer.Save(stream);
+ }
+ {
+ TBlob temp = TBlob::FromStreamSingleThreaded(stream);
+ TGeneralVector<TItem> reader(temp);
+ UNIT_ASSERT_EQUAL(reader.GetSize(), N);
+ for (size_t i = 0; i < N; ++i) {
+ TItem value;
+ reader.Get(i, value);
+ UNIT_ASSERT_EQUAL(value, TItem(i, i));
+ }
+ UNIT_ASSERT_EQUAL(reader.RealSize(), sizeof(ui64) + N * sizeof(TItem));
+ }
+ }
+ }
+
+ void TestStrings() {
+ const TString FILENAME = "chunked_helpers_test.bin";
+ TTempFileHandle file(FILENAME.c_str());
+
+ {
+ TFixedBufferFileOutput fOut(FILENAME);
+ TStringsVectorWriter stringsWriter;
+ stringsWriter.PushBack("");
+ stringsWriter.PushBack("test");
+ TChunkedDataWriter writer(fOut);
+ WriteBlock(writer, stringsWriter);
+ writer.WriteFooter();
+ }
+
+ {
+ TBlob fIn = TBlob::FromFileSingleThreaded(FILENAME);
+ TStringsVector vct(GetBlock(fIn, 0));
+ UNIT_ASSERT_EQUAL(vct.Get(0), "");
+ UNIT_ASSERT_EQUAL(vct.Get(1), "test");
+
+ bool wasException = false;
+ try {
+ vct.Get(2);
+ } catch (...) {
+ wasException = true;
+ }
+ UNIT_ASSERT(wasException);
+ }
+ }
+
+ void TestNamedChunkedData() {
+ const TString filename = MakeTempName(nullptr, "named_chunked_data_test");
+ TTempFile file(filename);
+
+ {
+ TFixedBufferFileOutput fOut(filename);
+ TNamedChunkedDataWriter writer(fOut);
+
+ writer.NewBlock("alpha");
+ writer.Write("123456");
+
+ writer.NewBlock();
+ writer.Write("anonymous");
+
+ writer.NewBlock("omega");
+ writer.Write("12345678901234567");
+
+ writer.WriteFooter();
+ }
+
+ {
+ TBlob mf = TBlob::FromFileSingleThreaded(filename);
+ TNamedChunkedDataReader reader(mf);
+
+ UNIT_ASSERT(reader.GetBlocksCount() == 3);
+
+ UNIT_ASSERT(reader.HasBlock("alpha"));
+ UNIT_ASSERT(reader.HasBlock("omega"));
+
+ UNIT_ASSERT_STRINGS_EQUAL(reader.GetBlockName(0), "alpha");
+ UNIT_ASSERT_STRINGS_EQUAL(reader.GetBlockName(1), "");
+ UNIT_ASSERT_STRINGS_EQUAL(reader.GetBlockName(2), "omega");
+
+ UNIT_ASSERT_EQUAL(reader.GetBlockLenByName("alpha"), 6); // padding not included
+ UNIT_ASSERT_EQUAL(reader.GetBlockLenByName("omega"), 17);
+
+ UNIT_ASSERT(memcmp(reader.GetBlockByName("alpha"), "123456", 6) == 0);
+ UNIT_ASSERT(memcmp(reader.GetBlock(1), "anonymous", 9) == 0);
+ UNIT_ASSERT(memcmp(reader.GetBlockByName("omega"), "12345678901234567", 17) == 0);
+ }
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TChunkedHelpersTest);
+
+class TChunkedDataTest: public TTestBase {
+private:
+ UNIT_TEST_SUITE(TChunkedDataTest);
+ UNIT_TEST(Test)
+ UNIT_TEST(TestEmpty)
+ UNIT_TEST_SUITE_END();
+
+ void Test() {
+ TBuffer buffer;
+ {
+ TBufferOutput out(buffer);
+ TChunkedDataWriter writer(out);
+ writer.NewBlock();
+ writer << "test";
+ writer.NewBlock();
+ writer << 4;
+ writer.NewBlock();
+ writer.NewBlock();
+ writer << 1;
+ writer << 2;
+ writer.WriteFooter();
+ }
+ {
+ TBlob blob = TBlob::FromBufferSingleThreaded(buffer);
+ TChunkedDataReader data(blob);
+ // printf("%d\n", (int)data.GetBlockLen(3));
+ UNIT_ASSERT_EQUAL(4, data.GetBlockLen(0));
+ UNIT_ASSERT_EQUAL(1, data.GetBlockLen(1));
+ UNIT_ASSERT_EQUAL(0, data.GetBlockLen(2));
+ UNIT_ASSERT_EQUAL(2, data.GetBlockLen(3));
+ }
+ }
+
+ void TestEmpty() {
+ TBuffer buffer;
+ {
+ TBufferOutput out(buffer);
+ TChunkedDataWriter writer(out);
+ writer.NewBlock();
+ writer.NewBlock();
+ writer.WriteFooter();
+ }
+ {
+ TBlob blob = TBlob::FromBufferSingleThreaded(buffer);
+ TChunkedDataReader data(blob);
+ // printf("%d\n", (int)data.GetBlockLen(1));
+ UNIT_ASSERT_EQUAL(0, data.GetBlockLen(0));
+ UNIT_ASSERT_EQUAL(0, data.GetBlockLen(1));
+ }
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TChunkedDataTest);
diff --git a/library/cpp/on_disk/chunks/reader.cpp b/library/cpp/on_disk/chunks/reader.cpp
new file mode 100644
index 0000000000..6e28cbf367
--- /dev/null
+++ b/library/cpp/on_disk/chunks/reader.cpp
@@ -0,0 +1,52 @@
+#include <util/generic/cast.h>
+#include <util/memory/blob.h>
+#include <util/system/unaligned_mem.h>
+
+#include "reader.h"
+
+template <typename T>
+static inline void ReadAux(const char* data, T* aux, T count, TVector<const char*>* result) {
+ result->resize(count);
+ for (size_t i = 0; i < count; ++i) {
+ (*result)[i] = data + ReadUnaligned<T>(aux + i);
+ }
+}
+
+TChunkedDataReader::TChunkedDataReader(const TBlob& blob) {
+ const char* cdata = blob.AsCharPtr();
+ const size_t size = blob.Size();
+ Y_ENSURE(size >= sizeof(ui32), "Empty file with chunks. ");
+
+ ui32 last = ReadUnaligned<ui32>((ui32*)(cdata + size) - 1);
+
+ if (last != 0) { // old version file
+ ui32* aux = (ui32*)(cdata + size);
+ ui32 count = last;
+ Size = size - (count + 1) * sizeof(ui32);
+
+ aux -= (count + 1);
+ ReadAux<ui32>(cdata, aux, count, &Offsets);
+ return;
+ }
+
+ Y_ENSURE(size >= 3 * sizeof(ui64), "Blob size must be >= 3 * sizeof(ui64). ");
+
+ ui64* aux = (ui64*)(cdata + size);
+ Version = ReadUnaligned<ui64>(aux - 2);
+ Y_ENSURE(Version > 0, "Invalid chunked array version. ");
+
+ ui64 count = ReadUnaligned<ui64>(aux - 3);
+
+ aux -= (count + 3);
+ ReadAux<ui64>(cdata, aux, count, &Offsets);
+
+ aux -= count;
+ Lengths.resize(count);
+ for (size_t i = 0; i < count; ++i) {
+ Lengths[i] = IntegerCast<size_t>(ReadUnaligned<ui64>(aux + i));
+ }
+}
+
+TBlob TChunkedDataReader::GetBlob(size_t index) const {
+ return TBlob::NoCopy(GetBlock(index), GetBlockLen(index));
+}
diff --git a/library/cpp/on_disk/chunks/reader.h b/library/cpp/on_disk/chunks/reader.h
new file mode 100644
index 0000000000..c5fe783319
--- /dev/null
+++ b/library/cpp/on_disk/chunks/reader.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#include <util/generic/array_ref.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+class TBlob;
+
+class TChunkedDataReader {
+public:
+ TChunkedDataReader(const TBlob& blob);
+
+ inline const void* GetBlock(size_t index) const {
+ CheckIndex(index);
+ return Offsets[index];
+ }
+
+ inline size_t GetBlockLen(size_t index) const {
+ CheckIndex(index);
+
+ if (Version == 0) {
+ if (index + 1 < Offsets.size()) {
+ return Offsets[index + 1] - Offsets[index];
+ }
+
+ return Size - (Offsets.back() - Offsets.front());
+ }
+
+ return Lengths[index];
+ }
+
+ TBlob GetBlob(size_t index) const;
+
+ template <typename T>
+ TArrayRef<const T> GetRegion(size_t index) const {
+ size_t len = GetBlockLen(index);
+ Y_ENSURE(len % sizeof(T) == 0, "wrong data padding");
+ return TArrayRef<const T>(reinterpret_cast<const T*>(GetBlock(index)), len / sizeof(T));
+ }
+
+ inline size_t GetBlocksCount() const {
+ return Offsets.size();
+ }
+
+private:
+ inline void CheckIndex(size_t index) const {
+ if (index >= GetBlocksCount()) {
+ ythrow yexception() << "requested block " << index << " of " << GetBlocksCount() << " blocks";
+ }
+ }
+
+private:
+ ui64 Version = 0;
+ TVector<const char*> Offsets;
+ TVector<size_t> Lengths;
+ size_t Size = 0;
+};
diff --git a/library/cpp/on_disk/chunks/ut/ya.make b/library/cpp/on_disk/chunks/ut/ya.make
new file mode 100644
index 0000000000..0190905cbe
--- /dev/null
+++ b/library/cpp/on_disk/chunks/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/on_disk/chunks)
+
+OWNER(g:util)
+
+SRCS(
+ chunks_ut.cpp
+)
+
+END()
diff --git a/library/cpp/on_disk/chunks/writer.cpp b/library/cpp/on_disk/chunks/writer.cpp
new file mode 100644
index 0000000000..6dc7397f09
--- /dev/null
+++ b/library/cpp/on_disk/chunks/writer.cpp
@@ -0,0 +1,46 @@
+#include <util/ysaveload.h>
+
+#include "writer.h"
+
+static inline void WriteAux(IOutputStream* out, const TVector<ui64>& data) {
+ ::SavePodArray(out, data.data(), data.size());
+}
+
+/*************************** TBuffersWriter ***************************/
+
+TChunkedDataWriter::TChunkedDataWriter(IOutputStream& slave)
+ : Slave(slave)
+ , Offset(0)
+{
+}
+
+TChunkedDataWriter::~TChunkedDataWriter() {
+}
+
+void TChunkedDataWriter::NewBlock() {
+ if (Offsets.size()) {
+ Lengths.push_back(Offset - Offsets.back());
+ }
+
+ Pad(16);
+ Offsets.push_back(Offset);
+}
+
+void TChunkedDataWriter::WriteFooter() {
+ Lengths.push_back(Offset - Offsets.back());
+ WriteAux(this, Lengths);
+ WriteAux(this, Offsets);
+ WriteBinary<ui64>(Offsets.size());
+ WriteBinary<ui64>(Version);
+ WriteBinary<ui64>(0);
+}
+
+size_t TChunkedDataWriter::GetCurrentBlockOffset() const {
+ Y_ASSERT(!Offsets.empty());
+ Y_ASSERT(Offset >= Offsets.back());
+ return Offset - Offsets.back();
+}
+
+size_t TChunkedDataWriter::GetBlockCount() const {
+ return Offsets.size();
+}
diff --git a/library/cpp/on_disk/chunks/writer.h b/library/cpp/on_disk/chunks/writer.h
new file mode 100644
index 0000000000..ab14522bdd
--- /dev/null
+++ b/library/cpp/on_disk/chunks/writer.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#include <util/generic/vector.h>
+#include <util/stream/output.h>
+
+template <typename T>
+inline void WriteBin(IOutputStream* out, typename TTypeTraits<T>::TFuncParam t) {
+ out->Write(&t, sizeof(T));
+}
+
+class TChunkedDataWriter: public IOutputStream {
+public:
+ TChunkedDataWriter(IOutputStream& slave);
+ ~TChunkedDataWriter() override;
+
+ void NewBlock();
+
+ template <typename T>
+ inline void WriteBinary(typename TTypeTraits<T>::TFuncParam t) {
+ this->Write(&t, sizeof(T));
+ }
+
+ void WriteFooter();
+
+ size_t GetCurrentBlockOffset() const;
+ size_t GetBlockCount() const;
+
+protected:
+ void DoWrite(const void* buf, size_t len) override {
+ Slave.Write(buf, len);
+ Offset += len;
+ }
+
+private:
+ static inline size_t PaddingSize(size_t size, size_t boundary) noexcept {
+ const size_t boundaryViolation = size % boundary;
+
+ return boundaryViolation == 0 ? 0 : boundary - boundaryViolation;
+ }
+
+ inline void Pad(size_t boundary) {
+ const size_t newOffset = Offset + PaddingSize(Offset, boundary);
+
+ while (Offset < newOffset) {
+ Write('\0');
+ }
+ }
+
+private:
+ static const ui64 Version = 1;
+
+ IOutputStream& Slave;
+
+ size_t Offset;
+ TVector<ui64> Offsets;
+ TVector<ui64> Lengths;
+};
diff --git a/library/cpp/on_disk/chunks/ya.make b/library/cpp/on_disk/chunks/ya.make
new file mode 100644
index 0000000000..acb52df5b0
--- /dev/null
+++ b/library/cpp/on_disk/chunks/ya.make
@@ -0,0 +1,11 @@
+LIBRARY()
+
+OWNER(g:util)
+
+SRCS(
+ chunked_helpers.cpp
+ reader.cpp
+ writer.cpp
+)
+
+END()
diff --git a/library/cpp/on_disk/ya.make b/library/cpp/on_disk/ya.make
new file mode 100644
index 0000000000..42a79d37bd
--- /dev/null
+++ b/library/cpp/on_disk/ya.make
@@ -0,0 +1,31 @@
+RECURSE(
+ 2d_array
+ 2d_array/ut
+ 4d_array
+ 4d_array/ut
+ aho_corasick
+ aho_corasick/tool
+ aho_corasick/ut
+ chunks
+ chunks/ut
+ codec_trie
+ codec_trie/ut
+ coded_blob
+ coded_blob/common
+ coded_blob/keys
+ coded_blob/ut
+ file_with_header
+ file_with_header/ut
+ fried_trie
+ head_ar
+ head_ar/ut
+ meta_trie
+ meta_trie/ut
+ mms
+ mms/ut
+ multi_blob
+ tar_archive
+ tar_archive/ut
+ st_hash
+ st_hash/ut
+)
diff --git a/library/cpp/openssl/holders/bio.cpp b/library/cpp/openssl/holders/bio.cpp
new file mode 100644
index 0000000000..42cc5fc1ef
--- /dev/null
+++ b/library/cpp/openssl/holders/bio.cpp
@@ -0,0 +1,29 @@
+#include "bio.h"
+
+namespace NOpenSSL {
+
+ TBioMethod::TBioMethod(
+ int type,
+ const char* name,
+ int (*write)(BIO*, const char*, int),
+ int (*read)(BIO*, char*, int),
+ int (*puts)(BIO*, const char*),
+ int (*gets)(BIO*, char*, int),
+ long (*ctrl)(BIO*, int, long, void*),
+ int (*create)(BIO*),
+ int (*destroy)(BIO*),
+ long (*callbackCtrl)(BIO*, int, bio_info_cb*)
+ )
+ : THolder(type, name)
+ {
+ BIO_meth_set_write(*this, write);
+ BIO_meth_set_read(*this, read);
+ BIO_meth_set_puts(*this, puts);
+ BIO_meth_set_gets(*this, gets);
+ BIO_meth_set_ctrl(*this, ctrl);
+ BIO_meth_set_create(*this, create);
+ BIO_meth_set_destroy(*this, destroy);
+ BIO_meth_set_callback_ctrl(*this, callbackCtrl);
+ }
+
+} // namespace NOpenSSL
diff --git a/library/cpp/openssl/holders/bio.h b/library/cpp/openssl/holders/bio.h
new file mode 100644
index 0000000000..bcd6a7a9d6
--- /dev/null
+++ b/library/cpp/openssl/holders/bio.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <contrib/libs/openssl/include/openssl/bio.h>
+
+#include <library/cpp/openssl/holders/holder.h>
+
+namespace NOpenSSL {
+
+class TBioMethod : public THolder<BIO_METHOD, BIO_meth_new, BIO_meth_free, int, const char*> {
+public:
+ TBioMethod(
+ int type,
+ const char* name,
+ int (*write)(BIO*, const char*, int),
+ int (*read)(BIO*, char*, int),
+ int (*puts)(BIO*, const char*),
+ int (*gets)(BIO*, char*, int),
+ long (*ctrl)(BIO*, int, long, void*),
+ int (*create)(BIO*),
+ int (*destroy)(BIO*),
+ long (*callbackCtrl)(BIO*, int, bio_info_cb*)
+ );
+};
+
+} // namespace NOpenSSL
diff --git a/library/cpp/openssl/holders/bn.h b/library/cpp/openssl/holders/bn.h
new file mode 100644
index 0000000000..9d133d4bdd
--- /dev/null
+++ b/library/cpp/openssl/holders/bn.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "holder.h"
+
+#include <contrib/libs/openssl/include/openssl/bn.h>
+
+namespace NOpenSSL {
+ class TBignum : public THolder<BIGNUM, BN_new, BN_clear_free> {
+ };
+
+ class TBnCtx : public THolder<BN_CTX, BN_CTX_new, BN_CTX_free> {
+ };
+}
diff --git a/library/cpp/openssl/holders/evp.h b/library/cpp/openssl/holders/evp.h
new file mode 100644
index 0000000000..df3cc4c2fa
--- /dev/null
+++ b/library/cpp/openssl/holders/evp.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "holder.h"
+
+#include <contrib/libs/openssl/include/openssl/evp.h>
+
+namespace NOpenSSL {
+ class TEvpCipherCtx : public THolder<EVP_CIPHER_CTX, EVP_CIPHER_CTX_new, EVP_CIPHER_CTX_free> {
+ };
+
+ class TEvpMdCtx : public THolder<EVP_MD_CTX, EVP_MD_CTX_new, EVP_MD_CTX_free> {
+ };
+}
diff --git a/library/cpp/openssl/holders/hmac.h b/library/cpp/openssl/holders/hmac.h
new file mode 100644
index 0000000000..4110e06f00
--- /dev/null
+++ b/library/cpp/openssl/holders/hmac.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "holder.h"
+
+#include <contrib/libs/openssl/include/openssl/hmac.h>
+
+namespace NOpenSSL {
+ class THmacCtx : public THolder<HMAC_CTX, HMAC_CTX_new, HMAC_CTX_free> {
+ };
+}
diff --git a/library/cpp/openssl/holders/holder.h b/library/cpp/openssl/holders/holder.h
new file mode 100644
index 0000000000..c2a26ce431
--- /dev/null
+++ b/library/cpp/openssl/holders/holder.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <util/generic/yexception.h>
+
+namespace NOpenSSL {
+
+template <typename TType, auto Create, auto Destroy, class... Args>
+class THolder {
+public:
+ inline THolder(Args... args) {
+ Ptr = Create(args...);
+ if (!Ptr) {
+ throw std::bad_alloc();
+ }
+ }
+
+ THolder(const THolder&) = delete;
+ THolder& operator=(const THolder&) = delete;
+
+ inline ~THolder() noexcept {
+ Destroy(Ptr);
+ }
+
+ inline operator TType* () noexcept {
+ return Ptr;
+ }
+
+private:
+ TType* Ptr;
+};
+
+}
diff --git a/library/cpp/openssl/holders/ut/evp_ut.cpp b/library/cpp/openssl/holders/ut/evp_ut.cpp
new file mode 100644
index 0000000000..0f8c0aed01
--- /dev/null
+++ b/library/cpp/openssl/holders/ut/evp_ut.cpp
@@ -0,0 +1,15 @@
+#include "evp.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(Evp) {
+ Y_UNIT_TEST(Cipher) {
+ NOpenSSL::TEvpCipherCtx ctx;
+ UNIT_ASSERT(ctx);
+ }
+
+ Y_UNIT_TEST(Md) {
+ NOpenSSL::TEvpMdCtx ctx;
+ UNIT_ASSERT(ctx);
+ }
+}
diff --git a/library/cpp/openssl/holders/ut/hmac_ut.cpp b/library/cpp/openssl/holders/ut/hmac_ut.cpp
new file mode 100644
index 0000000000..60f561c337
--- /dev/null
+++ b/library/cpp/openssl/holders/ut/hmac_ut.cpp
@@ -0,0 +1,10 @@
+#include "hmac.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(Hmac) {
+ Y_UNIT_TEST(Ctx) {
+ NOpenSSL::THmacCtx ctx;
+ UNIT_ASSERT(ctx);
+ }
+}
diff --git a/library/cpp/openssl/holders/ut/ya.make b/library/cpp/openssl/holders/ut/ya.make
new file mode 100644
index 0000000000..045cdc3566
--- /dev/null
+++ b/library/cpp/openssl/holders/ut/ya.make
@@ -0,0 +1,10 @@
+UNITTEST_FOR(library/cpp/openssl/holders)
+
+OWNER(somov deshevoy)
+
+SRCS(
+ evp_ut.cpp
+ hmac_ut.cpp
+)
+
+END()
diff --git a/library/cpp/openssl/holders/x509_vfy.cpp b/library/cpp/openssl/holders/x509_vfy.cpp
new file mode 100644
index 0000000000..731baa9055
--- /dev/null
+++ b/library/cpp/openssl/holders/x509_vfy.cpp
@@ -0,0 +1,30 @@
+#include "x509_vfy.h"
+
+namespace NOpenSSL {
+
+ TX509LookupMethod::TX509LookupMethod(
+ const char* name,
+ int (*newItem) (X509_LOOKUP *ctx),
+ void (*free) (X509_LOOKUP *ctx),
+ int (*init) (X509_LOOKUP *ctx),
+ int (*shutdown) (X509_LOOKUP *ctx),
+ X509_LOOKUP_ctrl_fn ctrl,
+ X509_LOOKUP_get_by_subject_fn getBySubject,
+ X509_LOOKUP_get_by_issuer_serial_fn getByIssuerSerial,
+ X509_LOOKUP_get_by_fingerprint_fn getByFingerprint,
+ X509_LOOKUP_get_by_alias_fn getByAlias
+ )
+ : THolder(name)
+ {
+ X509_LOOKUP_meth_set_new_item(*this, newItem);
+ X509_LOOKUP_meth_set_free(*this, free);
+ X509_LOOKUP_meth_set_init(*this, init);
+ X509_LOOKUP_meth_set_shutdown(*this, shutdown);
+ X509_LOOKUP_meth_set_ctrl(*this, ctrl);
+ X509_LOOKUP_meth_set_get_by_subject(*this, getBySubject);
+ X509_LOOKUP_meth_set_get_by_issuer_serial(*this, getByIssuerSerial);
+ X509_LOOKUP_meth_set_get_by_fingerprint(*this, getByFingerprint);
+ X509_LOOKUP_meth_set_get_by_alias(*this, getByAlias);
+ }
+
+} // namespace NOpenSSL
diff --git a/library/cpp/openssl/holders/x509_vfy.h b/library/cpp/openssl/holders/x509_vfy.h
new file mode 100644
index 0000000000..b735d8a042
--- /dev/null
+++ b/library/cpp/openssl/holders/x509_vfy.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <contrib/libs/openssl/include/openssl/x509_vfy.h>
+
+#include <library/cpp/openssl/holders/holder.h>
+
+namespace NOpenSSL {
+
+class TX509LookupMethod : public THolder<X509_LOOKUP_METHOD, X509_LOOKUP_meth_new, X509_LOOKUP_meth_free, const char*> {
+public:
+ TX509LookupMethod(
+ const char* name,
+ int (*newItem) (X509_LOOKUP *ctx),
+ void (*free) (X509_LOOKUP *ctx),
+ int (*init) (X509_LOOKUP *ctx),
+ int (*shutdown) (X509_LOOKUP *ctx),
+ X509_LOOKUP_ctrl_fn ctrl,
+ X509_LOOKUP_get_by_subject_fn getBySubject,
+ X509_LOOKUP_get_by_issuer_serial_fn getByIssuerSerial,
+ X509_LOOKUP_get_by_fingerprint_fn getByFingerprint,
+ X509_LOOKUP_get_by_alias_fn getByAlias
+ );
+};
+
+} // namespace NOpenSSL
diff --git a/library/cpp/openssl/holders/ya.make b/library/cpp/openssl/holders/ya.make
new file mode 100644
index 0000000000..3a2fbf3ba5
--- /dev/null
+++ b/library/cpp/openssl/holders/ya.make
@@ -0,0 +1,16 @@
+LIBRARY()
+
+OWNER(somov deshevoy)
+
+PEERDIR(
+ contrib/libs/openssl
+)
+
+SRCS(
+ bio.cpp
+ x509_vfy.cpp
+)
+
+END()
+
+NEED_CHECK()
diff --git a/library/cpp/openssl/init/init.cpp b/library/cpp/openssl/init/init.cpp
new file mode 100644
index 0000000000..ae68ef08ea
--- /dev/null
+++ b/library/cpp/openssl/init/init.cpp
@@ -0,0 +1,66 @@
+#include "init.h"
+
+#include <util/generic/singleton.h>
+#include <util/generic/vector.h>
+#include <util/generic/ptr.h>
+#include <util/generic/buffer.h>
+
+#include <util/system/yassert.h>
+#include <util/system/mutex.h>
+#include <util/system/thread.h>
+
+#include <util/random/entropy.h>
+#include <util/stream/input.h>
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/conf.h>
+#include <openssl/crypto.h>
+
+namespace {
+ struct TInitSsl {
+ struct TOpensslLocks {
+ inline TOpensslLocks()
+ : Mutexes(CRYPTO_num_locks())
+ {
+ for (auto& mpref : Mutexes) {
+ mpref.Reset(new TMutex());
+ }
+ }
+
+ inline void LockOP(int mode, int n) {
+ auto& mutex = *Mutexes.at(n);
+
+ if (mode & CRYPTO_LOCK) {
+ mutex.Acquire();
+ } else {
+ mutex.Release();
+ }
+ }
+
+ TVector<TAutoPtr<TMutex>> Mutexes;
+ };
+
+ inline TInitSsl() {
+ OPENSSL_init_crypto(OPENSSL_INIT_NO_ATEXIT, nullptr);
+ }
+
+ inline ~TInitSsl() {
+ OPENSSL_cleanup();
+ }
+
+ static void LockingFunction(int mode, int n, const char* /*file*/, int /*line*/) {
+ Singleton<TOpensslLocks>()->LockOP(mode, n);
+ }
+
+ static unsigned long ThreadIdFunction() {
+ return TThread::CurrentThreadId();
+ }
+ };
+}
+
+void InitOpenSSL() {
+ (void)SingletonWithPriority<TInitSsl, 0>();
+}
diff --git a/library/cpp/openssl/init/init.h b/library/cpp/openssl/init/init.h
new file mode 100644
index 0000000000..a626b316b3
--- /dev/null
+++ b/library/cpp/openssl/init/init.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void InitOpenSSL();
diff --git a/library/cpp/openssl/init/ya.make b/library/cpp/openssl/init/ya.make
new file mode 100644
index 0000000000..aac073497c
--- /dev/null
+++ b/library/cpp/openssl/init/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(pg g:zora)
+
+PEERDIR(
+ contrib/libs/openssl
+)
+
+SRCS(
+ init.cpp
+)
+
+END()
diff --git a/library/cpp/openssl/io/stream.cpp b/library/cpp/openssl/io/stream.cpp
new file mode 100644
index 0000000000..0b4be38c0e
--- /dev/null
+++ b/library/cpp/openssl/io/stream.cpp
@@ -0,0 +1,329 @@
+#include "stream.h"
+
+#include <util/generic/deque.h>
+#include <util/generic/singleton.h>
+#include <util/generic/yexception.h>
+
+#include <library/cpp/openssl/init/init.h>
+#include <library/cpp/openssl/method/io.h>
+#include <library/cpp/resource/resource.h>
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/tls1.h>
+#include <openssl/x509v3.h>
+
+using TOptions = TOpenSslClientIO::TOptions;
+
+namespace {
+ struct TSslIO;
+
+ struct TSslInitOnDemand {
+ inline TSslInitOnDemand() {
+ InitOpenSSL();
+ }
+ };
+
+ int GetLastSslError() noexcept {
+ return ERR_peek_last_error();
+ }
+
+ const char* SslErrorText(int error) noexcept {
+ return ERR_error_string(error, nullptr);
+ }
+
+ inline TStringBuf SslLastError() noexcept {
+ return SslErrorText(GetLastSslError());
+ }
+
+ struct TSslError: public yexception {
+ inline TSslError() {
+ *this << SslLastError();
+ }
+ };
+
+ struct TSslDestroy {
+ static inline void Destroy(ssl_ctx_st* ctx) noexcept {
+ SSL_CTX_free(ctx);
+ }
+
+ static inline void Destroy(ssl_st* ssl) noexcept {
+ SSL_free(ssl);
+ }
+
+ static inline void Destroy(bio_st* bio) noexcept {
+ BIO_free(bio);
+ }
+
+ static inline void Destroy(x509_st* x509) noexcept {
+ X509_free(x509);
+ }
+ };
+
+ template <class T>
+ using TSslHolderPtr = THolder<T, TSslDestroy>;
+
+ using TSslContextPtr = TSslHolderPtr<ssl_ctx_st>;
+ using TSslPtr = TSslHolderPtr<ssl_st>;
+ using TBioPtr = TSslHolderPtr<bio_st>;
+ using TX509Ptr = TSslHolderPtr<x509_st>;
+
+ inline TSslContextPtr CreateSslCtx(const ssl_method_st* method) {
+ TSslContextPtr ctx(SSL_CTX_new(method));
+
+ if (!ctx) {
+ ythrow TSslError() << "SSL_CTX_new";
+ }
+
+ SSL_CTX_set_options(ctx.Get(), SSL_OP_NO_SSLv2);
+ SSL_CTX_set_options(ctx.Get(), SSL_OP_NO_SSLv3);
+ SSL_CTX_set_options(ctx.Get(), SSL_OP_MICROSOFT_SESS_ID_BUG);
+ SSL_CTX_set_options(ctx.Get(), SSL_OP_NETSCAPE_CHALLENGE_BUG);
+
+ return ctx;
+ }
+
+ struct TStreamIO : public NOpenSSL::TAbstractIO {
+ inline TStreamIO(IInputStream* in, IOutputStream* out)
+ : In(in)
+ , Out(out)
+ {
+ }
+
+ int Write(const char* data, size_t dlen, size_t* written) override {
+ Out->Write(data, dlen);
+
+ *written = dlen;
+ return 1;
+ }
+
+ int Read(char* data, size_t dlen, size_t* readbytes) override {
+ *readbytes = In->Read(data, dlen);
+ return 1;
+ }
+
+ int Puts(const char* buf) override {
+ Y_UNUSED(buf);
+ return -1;
+ }
+
+ int Gets(char* buf, int size) override {
+ Y_UNUSED(buf);
+ Y_UNUSED(size);
+ return -1;
+ }
+
+ void Flush() override {
+ }
+
+ IInputStream* In;
+ IOutputStream* Out;
+ };
+
+ struct TSslIO: public TSslInitOnDemand, public TOptions {
+ inline TSslIO(IInputStream* in, IOutputStream* out, const TOptions& opts)
+ : TOptions(opts)
+ , Io(in, out)
+ , Ctx(CreateClientContext())
+ , Ssl(ConstructSsl())
+ {
+ Connect();
+ }
+
+ inline TSslContextPtr CreateClientContext() {
+ TSslContextPtr ctx = CreateSslCtx(SSLv23_client_method());
+ if (ClientCert_) {
+ if (!ClientCert_->CertificateFile_ || !ClientCert_->PrivateKeyFile_) {
+ ythrow yexception() << "both client certificate and private key are required";
+ }
+ if (ClientCert_->PrivateKeyPassword_) {
+ SSL_CTX_set_default_passwd_cb(ctx.Get(), [](char* buf, int size, int rwflag, void* userData) -> int {
+ Y_UNUSED(rwflag);
+ auto io = static_cast<TSslIO*>(userData);
+ if (!io) {
+ return -1;
+ }
+ if (size < static_cast<int>(io->ClientCert_->PrivateKeyPassword_.size())) {
+ return -1;
+ }
+ return io->ClientCert_->PrivateKeyPassword_.copy(buf, size, 0);
+ });
+ SSL_CTX_set_default_passwd_cb_userdata(ctx.Get(), this);
+ }
+ if (1 != SSL_CTX_use_certificate_chain_file(ctx.Get(), ClientCert_->CertificateFile_.c_str())) {
+ ythrow TSslError() << "SSL_CTX_use_certificate_chain_file";
+ }
+ if (1 != SSL_CTX_use_PrivateKey_file(ctx.Get(), ClientCert_->PrivateKeyFile_.c_str(), SSL_FILETYPE_PEM)) {
+ ythrow TSslError() << "SSL_CTX_use_PrivateKey_file";
+ }
+ if (1 != SSL_CTX_check_private_key(ctx.Get())) {
+ ythrow TSslError() << "SSL_CTX_check_private_key (client)";
+ }
+ }
+ return ctx;
+ }
+
+ inline TSslPtr ConstructSsl() {
+ TSslPtr ssl(SSL_new(Ctx.Get()));
+
+ if (!ssl) {
+ ythrow TSslError() << "SSL_new";
+ }
+
+ if (VerifyCert_) {
+ InitVerification(ssl.Get());
+ }
+
+ BIO_up_ref(Io); // SSL_set_bio consumes only one reference if rbio and wbio are the same
+ SSL_set_bio(ssl.Get(), Io, Io);
+
+ return ssl;
+ }
+
+ inline void InitVerification(ssl_st* ssl) {
+ X509_VERIFY_PARAM* param = SSL_get0_param(ssl);
+ X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
+ Y_ENSURE(X509_VERIFY_PARAM_set1_host(param, VerifyCert_->Hostname_.data(), VerifyCert_->Hostname_.size()));
+ SSL_set_tlsext_host_name(ssl, VerifyCert_->Hostname_.data()); // TLS extenstion: SNI
+
+ SSL_CTX_set_cert_store(Ctx.Get(), GetBuiltinOpenSslX509Store().Release());
+
+ Y_ENSURE_EX(1 == SSL_CTX_set_default_verify_paths(Ctx.Get()),
+ TSslError());
+ // it is OK to ignore result of SSL_CTX_load_verify_locations():
+ // Dir "/etc/ssl/certs/" may be missing
+ SSL_CTX_load_verify_locations(Ctx.Get(),
+ "/etc/ssl/certs/ca-certificates.crt",
+ "/etc/ssl/certs/");
+
+ SSL_set_verify(ssl, SSL_VERIFY_PEER, nullptr);
+ }
+
+ inline void Connect() {
+ if (SSL_connect(Ssl.Get()) != 1) {
+ ythrow TSslError() << "SSL_connect";
+ }
+ }
+
+ inline void Finish() const {
+ SSL_shutdown(Ssl.Get());
+ }
+
+ inline size_t Read(void* buf, size_t len) {
+ const int ret = SSL_read(Ssl.Get(), buf, len);
+
+ if (ret < 0) {
+ ythrow TSslError() << "SSL_read";
+ }
+
+ return ret;
+ }
+
+ inline void Write(const char* buf, size_t len) {
+ while (len) {
+ const int ret = SSL_write(Ssl.Get(), buf, len);
+
+ if (ret < 0) {
+ ythrow TSslError() << "SSL_write";
+ }
+
+ buf += (size_t)ret;
+ len -= (size_t)ret;
+ }
+ }
+
+ TStreamIO Io;
+ TSslContextPtr Ctx;
+ TSslPtr Ssl;
+ };
+}
+
+struct TOpenSslClientIO::TImpl: public TSslIO {
+ inline TImpl(IInputStream* in, IOutputStream* out, const TOptions& opts)
+ : TSslIO(in, out, opts)
+ {
+ }
+};
+
+TOpenSslClientIO::TOpenSslClientIO(IInputStream* in, IOutputStream* out)
+ : Impl_(new TImpl(in, out, TOptions()))
+{
+}
+
+TOpenSslClientIO::TOpenSslClientIO(IInputStream* in, IOutputStream* out, const TOptions& options)
+ : Impl_(new TImpl(in, out, options))
+{
+}
+
+TOpenSslClientIO::~TOpenSslClientIO() {
+ try {
+ Impl_->Finish();
+ } catch (...) {
+ }
+}
+
+void TOpenSslClientIO::DoWrite(const void* buf, size_t len) {
+ Impl_->Write((const char*)buf, len);
+}
+
+size_t TOpenSslClientIO::DoRead(void* buf, size_t len) {
+ return Impl_->Read(buf, len);
+}
+
+namespace NPrivate {
+ void TSslDestroy::Destroy(x509_store_st* x509) noexcept {
+ X509_STORE_free(x509);
+ }
+}
+
+class TBuiltinCerts {
+public:
+ TBuiltinCerts() {
+ TString c = NResource::Find("/builtin/cacert");
+
+ TBioPtr cbio(BIO_new_mem_buf(c.data(), c.size()));
+ Y_ENSURE_EX(cbio, TSslError() << "BIO_new_mem_buf");
+
+ while (true) {
+ TX509Ptr cert(PEM_read_bio_X509(cbio.Get(), nullptr, nullptr, nullptr));
+ if (!cert) {
+ break;
+ }
+ Certs.push_back(std::move(cert));
+ }
+
+ int err = GetLastSslError();
+ if (!Certs.empty() && ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
+ ERR_clear_error();
+ } else {
+ ythrow TSslError() << "can't load provided bundle: " << ERR_reason_error_string(err);
+ }
+
+ Y_ENSURE_EX(!Certs.empty(), TSslError());
+ }
+
+ TOpenSslX509StorePtr GetX509Store() const {
+ TOpenSslX509StorePtr store(X509_STORE_new());
+
+ for (const TX509Ptr& c : Certs) {
+ if (0 == X509_STORE_add_cert(store.Get(), c.Get())) {
+ int err = GetLastSslError();
+ if (ERR_GET_LIB(err) == ERR_LIB_X509 && ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
+ ERR_clear_error();
+ } else {
+ ythrow TSslError() << "can't load provided bundle: " << ERR_reason_error_string(err);
+ }
+ }
+ }
+
+ return store;
+ }
+
+private:
+ TDeque<TX509Ptr> Certs;
+};
+
+TOpenSslX509StorePtr GetBuiltinOpenSslX509Store() {
+ return Singleton<TBuiltinCerts>()->GetX509Store();
+}
diff --git a/library/cpp/openssl/io/stream.h b/library/cpp/openssl/io/stream.h
new file mode 100644
index 0000000000..7bca8f80ef
--- /dev/null
+++ b/library/cpp/openssl/io/stream.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <util/generic/maybe.h>
+#include <util/generic/ptr.h>
+#include <util/stream/input.h>
+#include <util/stream/output.h>
+
+class TOpenSslClientIO: public IInputStream, public IOutputStream {
+public:
+ struct TOptions {
+ struct TVerifyCert {
+ // Uses builtin certs.
+ // Also uses default CA path /etc/ssl/certs/ - can be provided with debian package: ca-certificates.deb.
+ // It can be expanded with ENV: SSL_CERT_DIR.
+ TString Hostname_;
+ };
+ struct TClientCert {
+ TString CertificateFile_;
+ TString PrivateKeyFile_;
+ TString PrivateKeyPassword_;
+ };
+
+ TMaybe<TVerifyCert> VerifyCert_;
+ TMaybe<TClientCert> ClientCert_;
+ // TODO - keys, cyphers, etc
+ };
+
+ TOpenSslClientIO(IInputStream* in, IOutputStream* out);
+ TOpenSslClientIO(IInputStream* in, IOutputStream* out, const TOptions& options);
+ ~TOpenSslClientIO() override;
+
+private:
+ void DoWrite(const void* buf, size_t len) override;
+ size_t DoRead(void* buf, size_t len) override;
+
+private:
+ struct TImpl;
+ THolder<TImpl> Impl_;
+};
+
+struct x509_store_st;
+
+namespace NPrivate {
+ struct TSslDestroy {
+ static void Destroy(x509_store_st* x509) noexcept;
+ };
+}
+
+using TOpenSslX509StorePtr = THolder<x509_store_st, NPrivate::TSslDestroy>;
+TOpenSslX509StorePtr GetBuiltinOpenSslX509Store();
diff --git a/library/cpp/openssl/io/ut/builtin_ut.cpp b/library/cpp/openssl/io/ut/builtin_ut.cpp
new file mode 100644
index 0000000000..987cd08492
--- /dev/null
+++ b/library/cpp/openssl/io/ut/builtin_ut.cpp
@@ -0,0 +1,9 @@
+#include <library/cpp/openssl/io/stream.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(Builtin) {
+ Y_UNIT_TEST(Init) {
+ UNIT_ASSERT_NO_EXCEPTION(GetBuiltinOpenSslX509Store());
+ UNIT_ASSERT_NO_EXCEPTION(GetBuiltinOpenSslX509Store());
+ }
+}
diff --git a/library/cpp/openssl/io/ut/ya.make b/library/cpp/openssl/io/ut/ya.make
new file mode 100644
index 0000000000..b978a6c046
--- /dev/null
+++ b/library/cpp/openssl/io/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/openssl/io)
+
+OWNER(
+ pg
+ cerevra
+)
+
+SRCS(
+ builtin_ut.cpp
+)
+
+END()
diff --git a/library/cpp/openssl/io/ya.make b/library/cpp/openssl/io/ya.make
new file mode 100644
index 0000000000..aaebba4011
--- /dev/null
+++ b/library/cpp/openssl/io/ya.make
@@ -0,0 +1,16 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ certs
+ contrib/libs/openssl
+ library/cpp/openssl/init
+ library/cpp/openssl/method
+)
+
+SRCS(
+ stream.cpp
+)
+
+END()
diff --git a/library/cpp/openssl/method/io.cpp b/library/cpp/openssl/method/io.cpp
new file mode 100644
index 0000000000..d184b6456c
--- /dev/null
+++ b/library/cpp/openssl/method/io.cpp
@@ -0,0 +1,122 @@
+#include "io.h"
+
+#include <util/generic/singleton.h>
+#include <util/generic/yexception.h>
+#include <util/system/compiler.h>
+#include <util/system/yassert.h>
+
+namespace {
+ using NOpenSSL::TAbstractIO;
+
+ TAbstractIO* IO(BIO* bio) noexcept {
+ void* ptr = BIO_get_data(bio);
+ Y_VERIFY(ptr);
+ return static_cast<TAbstractIO*>(ptr);
+ }
+
+ template<class T, class Callable, class... Args>
+ T ExceptionBoundary(BIO* bio, Callable&& f, T err, Args&&... args) noexcept {
+ try {
+ return (IO(bio)->*f)(args...);
+ } catch (...) {
+ return err;
+ }
+ }
+
+ int Write(BIO* bio, const char* data, int dlen) noexcept {
+ return ExceptionBoundary(bio, &TAbstractIO::WriteOld, -1, data, dlen);
+ }
+
+ int Read(BIO* bio, char* data, int dlen) noexcept {
+ return ExceptionBoundary(bio, &TAbstractIO::ReadOld, -1, data, dlen);
+ }
+
+ int Puts(BIO* bio, const char* buf) noexcept {
+ return ExceptionBoundary(bio, &TAbstractIO::Puts, -1, buf);
+ }
+
+ int Gets(BIO* bio, char* buf, int size) noexcept {
+ return ExceptionBoundary(bio, &TAbstractIO::Gets, -1, buf, size);
+ }
+
+ long Ctrl(BIO* bio, int cmd, long larg, void* parg) noexcept {
+ return ExceptionBoundary(bio, &TAbstractIO::Ctrl, -1, cmd, larg, parg);
+ }
+
+ int Create(BIO* bio) noexcept {
+ BIO_set_data(bio, nullptr);
+ BIO_set_init(bio, 1);
+ return 1;
+ }
+
+ int Destroy(BIO* bio) noexcept {
+ BIO_set_data(bio, nullptr);
+ BIO_set_init(bio, 0);
+ return 1;
+ }
+
+ NOpenSSL::TBioMethod* Method() {
+ return SingletonWithPriority<NOpenSSL::TBioMethod, 32768>(
+ BIO_get_new_index() | BIO_TYPE_SOURCE_SINK,
+ "AbstractIO",
+ Write,
+ Read,
+ Puts,
+ Gets,
+ Ctrl,
+ Create,
+ Destroy,
+ nullptr
+ );
+ }
+}
+
+namespace NOpenSSL {
+
+ TAbstractIO::TAbstractIO()
+ : Bio(BIO_new(*Method())) {
+ if (Y_UNLIKELY(!Bio)) {
+ throw std::bad_alloc();
+ }
+ BIO_set_data(Bio, this);
+ }
+
+ TAbstractIO::~TAbstractIO() {
+ BIO_free(Bio);
+ }
+
+ int TAbstractIO::WriteOld(const char* data, int dlen) {
+ size_t written = 0;
+
+ int ret = Write(data, dlen, &written);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ return written;
+ }
+
+ int TAbstractIO::ReadOld(char* data, int dlen) {
+ size_t readbytes = 0;
+
+ int ret = Read(data, dlen, &readbytes);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ return readbytes;
+ }
+
+ long TAbstractIO::Ctrl(int cmd, long larg, void* parg) {
+ Y_UNUSED(larg);
+ Y_UNUSED(parg);
+
+ if (cmd == BIO_CTRL_FLUSH) {
+ Flush();
+ return 1;
+ }
+
+ return 0;
+ }
+
+} // namespace NOpenSSL
diff --git a/library/cpp/openssl/method/io.h b/library/cpp/openssl/method/io.h
new file mode 100644
index 0000000000..f1d3df978d
--- /dev/null
+++ b/library/cpp/openssl/method/io.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <library/cpp/openssl/holders/bio.h>
+
+namespace NOpenSSL {
+
+class TAbstractIO {
+public:
+ TAbstractIO();
+ virtual ~TAbstractIO();
+
+ virtual int Write(const char* data, size_t dlen, size_t* written) = 0;
+ virtual int Read(char* data, size_t dlen, size_t* readbytes) = 0;
+ virtual int Puts(const char* buf) = 0;
+ virtual int Gets(char* buf, int size) = 0;
+
+ virtual long Ctrl(int cmd, long larg, void* parg);
+ virtual void Flush() = 0;
+
+ int WriteOld(const char* data, int dlen);
+ int ReadOld(char* data, int dlen);
+
+ inline operator BIO* () noexcept {
+ return Bio;
+ }
+
+private:
+ BIO* Bio;
+};
+
+} // namespace NOpenSSL
diff --git a/library/cpp/openssl/method/ut/io_ut.cpp b/library/cpp/openssl/method/ut/io_ut.cpp
new file mode 100644
index 0000000000..bff2b23d31
--- /dev/null
+++ b/library/cpp/openssl/method/ut/io_ut.cpp
@@ -0,0 +1,52 @@
+#include <library/cpp/openssl/method/io.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+class TTestIO : public NOpenSSL::TAbstractIO {
+public:
+ int Write(const char* data, size_t dlen, size_t* written) override {
+ Y_UNUSED(data);
+ *written = dlen;
+ return 1;
+ }
+
+ int Read(char* data, size_t dlen, size_t* readbytes) override {
+ Y_UNUSED(data);
+ Y_UNUSED(dlen);
+ *readbytes = 0;
+ return 0;
+ }
+
+ int Puts(const char* buf) override {
+ if (buf == nullptr) {
+ return 0;
+ }
+
+ return strlen(buf);
+ }
+
+ int Gets(char* buf, int size) override {
+ Y_UNUSED(buf);
+ Y_UNUSED(size);
+ return 0;
+ }
+
+ void Flush() override {
+
+ }
+};
+
+Y_UNIT_TEST_SUITE(IO) {
+ Y_UNIT_TEST(AbstractIO) {
+ static const char s[] = "12345";
+
+ TTestIO test;
+
+ UNIT_ASSERT(BIO_write(test, s, sizeof(s)) == sizeof(s));
+ UNIT_ASSERT(BIO_puts(test, s) == strlen(s));
+
+ char buf[128];
+ UNIT_ASSERT(BIO_read(test, buf, sizeof(buf)) == 0);
+ UNIT_ASSERT(BIO_gets(test, buf, sizeof(buf)) == 0);
+ }
+}
diff --git a/library/cpp/openssl/method/ut/ya.make b/library/cpp/openssl/method/ut/ya.make
new file mode 100644
index 0000000000..3645ad17e6
--- /dev/null
+++ b/library/cpp/openssl/method/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/openssl/method)
+
+OWNER(somov deshevoy)
+
+SRCS(
+ io_ut.cpp
+)
+
+END()
diff --git a/library/cpp/openssl/method/ya.make b/library/cpp/openssl/method/ya.make
new file mode 100644
index 0000000000..c8f6f18b6b
--- /dev/null
+++ b/library/cpp/openssl/method/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+OWNER(somov deshevoy)
+
+PEERDIR(
+ contrib/libs/openssl
+ library/cpp/openssl/holders
+)
+
+SRCS(
+ io.cpp
+)
+
+END()
diff --git a/library/cpp/openssl/ya.make b/library/cpp/openssl/ya.make
new file mode 100644
index 0000000000..7c10963e26
--- /dev/null
+++ b/library/cpp/openssl/ya.make
@@ -0,0 +1,13 @@
+RECURSE(
+ big_integer
+ big_integer/ut
+ crypto
+ crypto/ut
+ holders
+ holders/ut
+ io
+ io/ut
+ method
+ method/ut
+ init
+)
diff --git a/library/cpp/packedtypes/fixed_point.h b/library/cpp/packedtypes/fixed_point.h
new file mode 100644
index 0000000000..b36b80876e
--- /dev/null
+++ b/library/cpp/packedtypes/fixed_point.h
@@ -0,0 +1,71 @@
+#pragma once
+
+namespace NFixedPoint {
+ template <ui64 FracMult>
+ class TFixedPoint {
+ typedef TFixedPoint<FracMult> TSelf;
+ ui64 Rep;
+
+ public:
+ TFixedPoint()
+ : Rep()
+ {
+ }
+
+ template <typename T>
+ explicit TFixedPoint(T t)
+ : Rep(ui64(t * FracMult))
+ {
+ }
+
+ explicit TFixedPoint(ui64 i, ui64 f)
+ : Rep(i * FracMult + f % FracMult)
+ {
+ }
+
+ template <typename T>
+ TSelf& operator=(T t) {
+ Rep = t * FracMult;
+ return *this;
+ }
+
+ operator double() const {
+ return Int() + double(Frac()) / FracMult;
+ }
+
+ operator ui64() const {
+ return Int();
+ }
+
+ template <typename T>
+ TSelf& operator/=(T t) {
+ Rep = ui64(Rep / t);
+ return *this;
+ }
+
+ template <typename T>
+ TSelf operator/(T t) const {
+ TSelf r = *this;
+ return r /= t;
+ }
+
+ ui64 Frac() const {
+ return Rep % FracMult;
+ }
+
+ ui64 Int() const {
+ return Rep / FracMult;
+ }
+
+ static ui64 Mult() {
+ return FracMult;
+ }
+
+ static TSelf Make(ui64 rep) {
+ TFixedPoint<FracMult> fp;
+ fp.Rep = rep;
+ return fp;
+ }
+ };
+
+}
diff --git a/library/cpp/packedtypes/longs.cpp b/library/cpp/packedtypes/longs.cpp
new file mode 100644
index 0000000000..4cb6f4963b
--- /dev/null
+++ b/library/cpp/packedtypes/longs.cpp
@@ -0,0 +1 @@
+#include "longs.h"
diff --git a/library/cpp/packedtypes/longs.h b/library/cpp/packedtypes/longs.h
new file mode 100644
index 0000000000..084098d705
--- /dev/null
+++ b/library/cpp/packedtypes/longs.h
@@ -0,0 +1,347 @@
+#pragma once
+
+#include <util/system/defaults.h> // _BIDSCLASS _EXPCLASS
+#include <util/system/yassert.h>
+#include <util/system/unaligned_mem.h>
+
+#define PUT_8(x, buf, shift) WriteUnaligned<ui8>((buf)++, (x) >> (shift))
+#define GET_8_OR(x, buf, type, shift) (x) |= (type) * (buf)++ << (shift)
+
+#if defined(_big_endian_)
+#define LO_SHIFT 1
+#define HI_SHIFT 0
+#elif defined(_little_endian_)
+#define LO_SHIFT 0
+#define HI_SHIFT 1
+#endif
+
+#if !defined(_must_align2_)
+#define PUT_16(x, buf, shift) WriteUnaligned<ui16>(buf, (x) >> (shift)), (buf) += 2
+#define GET_16_OR(x, buf, type, shift) (x) |= (type)ReadUnaligned<ui16>(buf) << (shift), (buf) += 2
+#else
+#define PUT_16(x, buf, shift) PUT_8(x, buf, shift + 8 * LO_SHIFT), PUT_8(x, buf, shift + 8 * HI_SHIFT)
+#define GET_16_OR(x, buf, type, shift) GET_8_OR(x, buf, type, shift + 8 * LO_SHIFT), GET_8_OR(x, buf, type, shift + 8 * HI_SHIFT)
+#endif
+
+#if !defined(_must_align4_)
+#define PUT_32(x, buf, shift) WriteUnaligned<ui32>(buf, (x) >> (shift)), (buf) += 4
+#define GET_32_OR(x, buf, type, shift) (x) |= (type)ReadUnaligned<ui32>(buf) << (shift), (buf) += 4
+#else
+#define PUT_32(x, buf, shift) PUT_16(x, buf, shift + 16 * LO_SHIFT), PUT_16(x, buf, shift + 16 * HI_SHIFT)
+#define GET_32_OR(x, buf, type, shift) GET_16_OR(x, buf, type, shift + 16 * LO_SHIFT), GET_16_OR(x, buf, type, shift + 16 * HI_SHIFT)
+#endif
+
+#if !defined(_must_align8_)
+#define PUT_64(x, buf, shift) WriteUnaligned<ui64>(buf, (x) >> (shift)), (buf) += 8
+#define GET_64_OR(x, buf, type, shift) (x) |= (type)ReadUnaligned<ui64>(buf) << (shift), (buf) += 8
+#else
+#define PUT_64(x, buf, shift) PUT_32(x, buf, shift + 32 * LO_SHIFT), PUT_32(x, buf, shift + 32 * HI_SHIFT)
+#define GET_64_OR(x, buf, type, shift) GET_32_OR(x, buf, type, shift + 32 * LO_SHIFT), GET_32_OR(x, buf, type, shift + 32 * HI_SHIFT)
+#endif
+
+struct mem_traits {
+ static ui8 get_8(const char*& mem) {
+ ui8 x = 0;
+ GET_8_OR(x, mem, ui8, 0);
+ return x;
+ }
+ static ui16 get_16(const char*& mem) {
+ ui16 x = 0;
+ GET_16_OR(x, mem, ui16, 0);
+ return x;
+ }
+ static ui32 get_32(const char*& mem) {
+ ui32 x = 0;
+ GET_32_OR(x, mem, ui32, 0);
+ return x;
+ }
+ static void put_8(ui8 x, char*& mem) {
+ PUT_8(x, mem, 0);
+ }
+ static void put_16(ui16 x, char*& mem) {
+ PUT_16(x, mem, 0);
+ }
+ static void put_32(ui32 x, char*& mem) {
+ PUT_32(x, mem, 0);
+ }
+ static int is_good(char*&) {
+ return 1;
+ }
+};
+
+/*
+|____|____|____|____|____|____|____|____|____|____|____|____|____|____|8***|****
+|____|____|____|____|____|____|____|____|____|____|____|____|i4**|****|****|****
+|____|____|____|____|____|____|____|____|____|____|ii2*|****|****|****|****|****
+|____|____|____|____|____|____|____|____|iii1|****|****|****|****|****|****|****
+|____|____|____|____|____|____|iiii|8***|****|****|****|****|****|****|****|****
+|____|____|____|____|iiii|i4**|****|****|****|****|****|****|****|****|****|****
+|____|____|iiii|ii2*|****|****|****|****|****|****|****|****|****|****|****|****
+|iiii|iii1|****|****|****|****|****|****|****|****|****|****|****|****|****|****
+*/
+
+#define PACK1LIM 0x80u
+#define PACK2LIM 0x4000u
+#define PACK3LIM 0x200000u
+#define PACK4LIM 0x10000000u
+#define PACK5LIM 0x800000000ull
+#define PACK6LIM 0x40000000000ull
+#define PACK7LIM 0x2000000000000ull
+#define PACK8LIM 0x100000000000000ull
+
+#define MY_14(x) ((ui16)(x) < PACK1LIM ? 1 : 2)
+#define MY_28(x) ((ui32)(x) < PACK2LIM ? MY_14(x) : ((ui32)(x) < PACK3LIM ? 3 : 4))
+
+#define MY_32(x) ((ui32)(x) < PACK4LIM ? MY_28(x) : 5)
+#define MY_64(x) ((ui64)(x) < PACK4LIM ? MY_28(x) : ((ui64)(x) < PACK6LIM ? ((ui64)(x) < PACK5LIM ? 5 : 6) : ((ui64)(x) < PACK7LIM ? 7 : ((ui64)(x) < PACK8LIM ? 8 : 9))))
+
+#if !defined(MACRO_BEGIN)
+#define MACRO_BEGIN do {
+#define MACRO_END \
+ } \
+ while (0)
+#endif
+
+#define PACK_14(x, buf, how, ret) \
+ MACRO_BEGIN \
+ if ((ui16)(x) < PACK1LIM) { \
+ how::put_8((ui8)(x), (buf)); \
+ (ret) = 1; \
+ } else { \
+ how::put_8((ui8)(0x80 | (x) >> 8), (buf)); \
+ how::put_8((ui8)(x), (buf)); \
+ (ret) = 2; \
+ } \
+ MACRO_END
+
+#define PACK_28(x, buf, how, ret) \
+ MACRO_BEGIN \
+ if ((ui32)(x) < PACK2LIM) { \
+ PACK_14(x, buf, how, ret); \
+ } else { \
+ if ((ui32)(x) < PACK3LIM) { \
+ how::put_8((ui8)(0xC0 | (x) >> 16), buf); \
+ (ret) = 3; \
+ } else { \
+ how::put_8((ui8)(0xE0 | (x) >> 24), buf); \
+ how::put_8((ui8)((x) >> 16), buf); \
+ (ret) = 4; \
+ } \
+ how::put_16((ui16)(x), (buf)); \
+ } \
+ MACRO_END
+
+#define PACK_32(x, buf, how, ret) \
+ MACRO_BEGIN \
+ if ((ui32)(x) < PACK4LIM) { \
+ PACK_28(x, buf, how, ret); \
+ } else { \
+ how::put_8((ui8)(0xF0), buf); \
+ how::put_32((ui32)(x), buf); \
+ (ret) = 5; \
+ } \
+ MACRO_END
+
+#define PACK_64(x, buf, how, ret) \
+ MACRO_BEGIN \
+ if ((ui64)(x) < PACK4LIM) { \
+ PACK_28((ui32)(x), buf, how, ret); \
+ } else { \
+ if ((ui64)(x) < PACK6LIM) { \
+ if ((ui64)(x) < PACK5LIM) { \
+ how::put_8((ui8)(0xF0 | (x) >> 32), buf); \
+ (ret) = 5; \
+ } else { \
+ how::put_8((ui8)(0xF8 | (x) >> 40), buf); \
+ how::put_8((ui8)((x) >> 32), buf); \
+ (ret) = 6; \
+ } \
+ } else { \
+ if ((ui64)(x) < PACK7LIM) { \
+ how::put_8((ui8)(0xFC | (x) >> 48), buf); \
+ (ret) = 7; \
+ } else { \
+ if ((ui64)(x) < PACK8LIM) { \
+ how::put_8((ui8)(0xFE | (x) >> 56), buf); \
+ how::put_8((ui8)((x) >> 48), buf); \
+ (ret) = 8; \
+ } else { \
+ how::put_8((ui8)(0xFF), buf); \
+ how::put_16((ui16)((x) >> 48), buf); \
+ (ret) = 9; \
+ } \
+ } \
+ how::put_16((ui16)((x) >> 32), buf); \
+ } \
+ how::put_32((ui32)(x), buf); \
+ } \
+ MACRO_END
+
+#define DO_UNPACK_14(firstByte, x, buf, how, ret) \
+ MACRO_BEGIN \
+ if (firstByte < 0x80) { \
+ (x) = (firstByte); \
+ (ret) = 1; \
+ } else { \
+ (x) = (firstByte & 0x7F) << 8; \
+ (x) |= how::get_8(buf); \
+ (ret) = 2; \
+ } \
+ MACRO_END
+
+#define UNPACK_14(x, buf, how, ret) \
+ MACRO_BEGIN \
+ ui8 firstByte = how::get_8(buf); \
+ DO_UNPACK_14(firstByte, x, buf, how, ret); \
+ MACRO_END
+
+#define DO_UNPACK_28(firstByte, x, buf, how, ret) \
+ MACRO_BEGIN \
+ if (firstByte < 0xC0) { \
+ DO_UNPACK_14(firstByte, x, buf, how, ret); \
+ } else { \
+ if (firstByte < 0xE0) { \
+ (x) = (firstByte & 0x3F) << 16; \
+ (ret) = 3; \
+ } else { \
+ (x) = (firstByte & 0x1F) << 24; \
+ (x) |= how::get_8(buf) << 16; \
+ (ret) = 4; \
+ } \
+ (x) |= how::get_16(buf); \
+ } \
+ MACRO_END
+
+#define UNPACK_28(x, buf, how, ret) \
+ MACRO_BEGIN \
+ ui8 firstByte = how::get_8(buf); \
+ DO_UNPACK_28(firstByte, x, buf, how, ret); \
+ MACRO_END
+
+#define DO_UNPACK_32(firstByte, x, buf, how, ret) \
+ MACRO_BEGIN \
+ if (firstByte < 0xF0) { \
+ DO_UNPACK_28(firstByte, x, buf, how, ret); \
+ } else { \
+ (x) = how::get_32(buf); \
+ (ret) = 5; \
+ } \
+ MACRO_END
+
+#define UNPACK_32(x, buf, how, ret) \
+ MACRO_BEGIN \
+ ui8 firstByte = how::get_8(buf); \
+ DO_UNPACK_32(firstByte, x, buf, how, ret); \
+ MACRO_END
+
+#define DO_UNPACK_64(firstByte, x, buf, how, ret) \
+ MACRO_BEGIN \
+ if (firstByte < 0xF0) { \
+ DO_UNPACK_28(firstByte, x, buf, how, ret); \
+ } else { \
+ if (firstByte < 0xFC) { \
+ if (firstByte < 0xF8) { \
+ (x) = (ui64)(firstByte & 0x0F) << 32; \
+ (ret) = 5; \
+ } else { \
+ (x) = (ui64)(firstByte & 0x07) << 40; \
+ (x) |= (ui64)how::get_8(buf) << 32; \
+ (ret) = 6; \
+ } \
+ } else { \
+ if (firstByte < 0xFE) { \
+ (x) = (ui64)(firstByte & 0x03) << 48; \
+ (ret) = 7; \
+ } else { \
+ if (firstByte < 0xFF) { \
+ (x) = (ui64)(firstByte & 0x01) << 56; \
+ (x) |= (ui64)how::get_8(buf) << 48; \
+ (ret) = 8; \
+ } else { \
+ (x) = (ui64)how::get_16(buf) << 48; \
+ (ret) = 9; \
+ } \
+ } \
+ (x) |= (ui64)how::get_16(buf) << 32; \
+ } \
+ (x) |= how::get_32(buf); \
+ } \
+ MACRO_END
+
+#define UNPACK_64(x, buf, how, ret) \
+ MACRO_BEGIN \
+ ui8 firstByte = how::get_8(buf); \
+ DO_UNPACK_64(firstByte, x, buf, how, ret); \
+ MACRO_END
+
+inline int in_long(i64& longVal, const char* ptrBuf) {
+ int ret;
+ UNPACK_64(longVal, ptrBuf, mem_traits, ret);
+ return ret;
+}
+
+inline int out_long(const i64& longVal, char* ptrBuf) {
+ int ret;
+ PACK_64(longVal, ptrBuf, mem_traits, ret); /*7*/
+ return ret;
+}
+
+inline int len_long(const i64& longVal) {
+ return MY_64(longVal);
+}
+
+inline int in_long(i32& longVal, const char* ptrBuf) {
+ int ret;
+ UNPACK_32(longVal, ptrBuf, mem_traits, ret);
+ return ret;
+}
+
+inline int out_long(const i32& longVal, char* ptrBuf) {
+ int ret;
+ PACK_32(longVal, ptrBuf, mem_traits, ret);
+ return ret;
+}
+
+inline int len_long(const i32& longVal) {
+ return MY_32(longVal);
+}
+
+template <typename T, typename C>
+inline const C* Unpack32(T& x, const C* src) {
+ int pkLen = 0;
+ const char* c = reinterpret_cast<const char*>(src);
+ Y_UNUSED(pkLen);
+ UNPACK_32(x, c, mem_traits, pkLen);
+ Y_ASSERT(pkLen);
+ return reinterpret_cast<const C*>(c);
+}
+
+template <typename T, typename C>
+inline const C* Unpack64(T& x, const C* src) {
+ int pkLen = 0;
+ const char* c = reinterpret_cast<const char*>(src);
+ Y_UNUSED(pkLen);
+ UNPACK_64(x, c, mem_traits, pkLen);
+ Y_ASSERT(pkLen);
+ return reinterpret_cast<const C*>(c);
+}
+
+template <typename T, typename C>
+inline C* Pack32(const T& x, C* dest) {
+ int pkLen = 0;
+ Y_UNUSED(pkLen);
+ char* c = reinterpret_cast<char*>(dest);
+ PACK_32(x, c, mem_traits, pkLen);
+ Y_ASSERT(pkLen);
+ return reinterpret_cast<C*>(c);
+}
+
+template <typename T, typename C>
+inline C* Pack64(const T& x, C* dest) {
+ int pkLen = 0;
+ Y_UNUSED(pkLen);
+ char* c = reinterpret_cast<char*>(dest);
+ PACK_64(x, c, mem_traits, pkLen);
+ Y_ASSERT(pkLen);
+ return reinterpret_cast<C*>(c);
+}
diff --git a/library/cpp/packedtypes/longs_ut.cpp b/library/cpp/packedtypes/longs_ut.cpp
new file mode 100644
index 0000000000..8b06c934d2
--- /dev/null
+++ b/library/cpp/packedtypes/longs_ut.cpp
@@ -0,0 +1,68 @@
+#include "longs.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/digest/old_crc/crc.h>
+#include <util/string/util.h>
+#include <util/stream/output.h>
+#include <util/system/hi_lo.h>
+
+Y_UNIT_TEST_SUITE(TLongsTest) {
+ Y_UNIT_TEST(TestLongs) {
+ i16 x16 = 40;
+ i64 x64 = 40;
+ i64 y64;
+ TString s;
+
+ s += Sprintf("x16=0x%x\n", (int)x16);
+ s += Sprintf("LO_8(x16)=0x%x HI_8(x16)=0x%x\n\n", (int)Lo8(x16), (int)Hi8(x16));
+
+ char buf[100];
+ memset(buf, 0, 100);
+ char* p = buf;
+ int l = out_long(x64, buf);
+ s += Sprintf("x64=0x%" PRIi64 "\n", x64);
+ s += Sprintf("LO_32(x64)=0x%" PRIu32 " HI_32(x64)=0x%" PRIu32 "\n", (ui32)Lo32(x64), (ui32)Hi32(x64));
+ s += Sprintf("buf=%s, l=%d: ", buf, l);
+ for (int i = 0; i < l; i++) {
+ s += Sprintf("0x%02x ", buf[i]);
+ }
+ s += Sprintf("\n");
+
+ p = buf;
+ in_long(y64, p);
+ s += Sprintf("x=0x%" PRIi64 " y=0x%" PRIi64 "\n", x64, y64);
+ if (x64 != y64) {
+ s += Sprintf("Error: y64 != x64\n");
+ } else {
+ s += Sprintf("OK\n");
+ }
+
+ UNIT_ASSERT_EQUAL(Crc<ui64>(s.data(), s.size()), 7251624297500315779ULL); // WTF?
+ }
+
+ template <typename TSignedInt>
+ void TestOneValue(TSignedInt value) {
+ char buffer[sizeof(TSignedInt) + 1];
+ auto bytes = out_long(value, buffer);
+ TSignedInt readValue = 0;
+ auto readBytes = in_long(readValue, buffer);
+ UNIT_ASSERT_EQUAL(bytes, readBytes);
+ UNIT_ASSERT_EQUAL(bytes, len_long(value));
+ UNIT_ASSERT_EQUAL(value, readValue);
+ }
+
+ template <typename TSignedInt>
+ void TestCornerCasesImpl(int maxPow) {
+ for (int i = 0; i <= maxPow; ++i) {
+ TestOneValue<TSignedInt>((TSignedInt)(1ull << i));
+ TestOneValue<TSignedInt>((TSignedInt)((1ull << i) - 1));
+ TestOneValue<TSignedInt>((TSignedInt)((1ull << i) + 1));
+ }
+ }
+
+ Y_UNIT_TEST(TestCornerCases) {
+ TestCornerCasesImpl<i32>(31);
+ TestCornerCasesImpl<i64>(63);
+ }
+}
diff --git a/library/cpp/packedtypes/packed.h b/library/cpp/packedtypes/packed.h
new file mode 100644
index 0000000000..88cff26ae2
--- /dev/null
+++ b/library/cpp/packedtypes/packed.h
@@ -0,0 +1,98 @@
+#pragma once
+
+#include <library/cpp/streams/zc_memory_input/zc_memory_input.h>
+
+#include <util/stream/output.h>
+#include <util/ysaveload.h>
+
+#include "longs.h"
+
+struct Stream_traits {
+ template <typename T>
+ static T get(IInputStream& in) {
+ T x;
+ ::Load(&in, x);
+ return x;
+ }
+ static ui8 get_8(IInputStream& in) {
+ return get<ui8>(in);
+ }
+ static ui16 get_16(IInputStream& in) {
+ return get<ui16>(in);
+ }
+ static ui32 get_32(IInputStream& in) {
+ return get<ui32>(in);
+ }
+ static void put_8(ui8 x, IOutputStream& out) {
+ ::Save(&out, x);
+ }
+ static void put_16(ui16 x, IOutputStream& out) {
+ ::Save(&out, x);
+ }
+ static void put_32(ui32 x, IOutputStream& out) {
+ ::Save(&out, x);
+ }
+ static int is_good(IInputStream& /*in*/) {
+ return 1;
+ }
+ static int is_good(IOutputStream& /*out*/) {
+ return 1;
+ }
+};
+
+struct TZCMemoryInput_traits {
+ template <typename T>
+ static T get(TZCMemoryInput& in) {
+ T x;
+ in.ReadPOD(x);
+ return x;
+ }
+
+ static ui8 Y_FORCE_INLINE get_8(TZCMemoryInput& in) {
+ return get<ui8>(in);
+ }
+
+ static ui16 Y_FORCE_INLINE get_16(TZCMemoryInput& in) {
+ return get<ui16>(in);
+ }
+
+ static ui32 Y_FORCE_INLINE get_32(TZCMemoryInput& in) {
+ return get<ui32>(in);
+ }
+
+ static int Y_FORCE_INLINE is_good(TZCMemoryInput&) {
+ return 1;
+ }
+};
+
+void Y_FORCE_INLINE PackUI32(IOutputStream& out, ui32 v) {
+ char buf[sizeof(ui32)];
+ char* bufPtr = buf;
+ size_t size;
+ PACK_28(v, bufPtr, mem_traits, size);
+ out.Write(buf, size);
+}
+
+template <class TStream>
+struct TInputStream2Traits {
+ typedef Stream_traits TTraits;
+};
+
+template <>
+struct TInputStream2Traits<TZCMemoryInput> {
+ typedef TZCMemoryInput_traits TTraits;
+};
+
+template <class TStream>
+void Y_FORCE_INLINE UnPackUI32(TStream& in, ui32& v) {
+ size_t size;
+ UNPACK_28(v, in, TInputStream2Traits<TStream>::TTraits, size);
+ (void)size;
+}
+
+template <class TStream>
+ui32 Y_FORCE_INLINE UnPackUI32(TStream& in) {
+ ui32 res;
+ UnPackUI32(in, res);
+ return res;
+}
diff --git a/library/cpp/packedtypes/packed_ut.cpp b/library/cpp/packedtypes/packed_ut.cpp
new file mode 100644
index 0000000000..70a22cf9c3
--- /dev/null
+++ b/library/cpp/packedtypes/packed_ut.cpp
@@ -0,0 +1,130 @@
+#include "packed.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/system/defaults.h>
+#include <util/generic/ylimits.h>
+#include <util/generic/buffer.h>
+#include <util/stream/mem.h>
+#include <util/stream/buffer.h>
+
+namespace NPrivate {
+#if 0
+static ui64 gSeed = 42;
+
+template<typename T>
+static T PseudoRandom(T max = Max<T>()) {
+ Y_ASSERT(max != 0);
+ // stupid and non-threadsafe, but very predictable chaos generator
+ gSeed += 1;
+ gSeed *= 419;
+ gSeed = gSeed ^ (ui64(max) << 17u);
+ return gSeed % max;
+};
+#endif
+}
+
+Y_UNIT_TEST_SUITE(TPackedTest) {
+ void TestPackUi32Sub(ui32 v, const TVector<char>& p) {
+ TBufferOutput out;
+ PackUI32(out, v);
+ const TBuffer& buf = out.Buffer();
+ UNIT_ASSERT_VALUES_EQUAL(buf.Size(), p.size());
+ UNIT_ASSERT(!memcmp(buf.Data(), &p[0], buf.Size()));
+
+ {
+ TBufferInput in(buf);
+ ui32 v2;
+ UnPackUI32(in, v2);
+ UNIT_ASSERT_VALUES_EQUAL(v, v2);
+ }
+
+ {
+ TZCMemoryInput in(buf.Data(), buf.Size());
+ ui32 v2;
+ UnPackUI32(in, v2);
+ UNIT_ASSERT_VALUES_EQUAL(v, v2);
+ }
+ }
+
+ Y_UNIT_TEST(TestPackUi32) {
+ ui32 v;
+ TVector<char> pv;
+
+ v = 0;
+ pv.resize(1);
+ pv[0] = 0x0;
+ TestPackUi32Sub(v, pv);
+
+ v = 0x1600;
+ pv.resize(2);
+ pv[0] = 0x96;
+ pv[1] = 0x00;
+ TestPackUi32Sub(v, pv);
+
+ v = 0xEF98;
+ pv.resize(3);
+ pv[0] = 0xC0;
+#if defined(_big_endian_)
+ pv[1] = 0xEF;
+ pv[2] = 0x98;
+#elif defined(_little_endian_)
+ pv[1] = 0x98;
+ pv[2] = 0xEF;
+#endif
+ TestPackUi32Sub(v, pv);
+
+ v = 0xF567FE4;
+ pv.resize(4);
+ pv[0] = 0xEF;
+ pv[1] = 0x56;
+#if defined(_big_endian_)
+ pv[2] = 0x7F;
+ pv[3] = 0xE4;
+#elif defined(_little_endian_)
+ pv[2] = 0xE4;
+ pv[3] = 0x7F;
+#endif
+ TestPackUi32Sub(v, pv);
+ }
+
+#if 0
+ Y_UNIT_TEST(ReadWrite32) {
+ TBuffer buffer(65536);
+
+ char* writePtr = buffer.Data();
+ TVector<ui32> correctNumbers;
+ for (size_t i = 0; i < 1000; ++i) {
+ ui32 randNum = NPrivate::PseudoRandom<ui32>();
+ correctNumbers.push_back(randNum);
+ writePtr = Pack32(randNum, writePtr);
+ }
+
+ const char* readPtr = buffer.Data();
+ for (size_t i = 0; i < correctNumbers.size(); ++i) {
+ ui32 value = 0xCCCCCCCC;
+ readPtr = Unpack32(value, readPtr);
+ UNIT_ASSERT_VALUES_EQUAL(value, correctNumbers[i]);
+ }
+ }
+
+ Y_UNIT_TEST(ReadWrite64) {
+ TBuffer buffer(65536);
+
+ char* writePtr = buffer.Data();
+ TVector<ui64> correctNumbers;
+ for (size_t i = 0; i < 1000; ++i) {
+ ui64 randNum = NPrivate::PseudoRandom<ui64>();
+ correctNumbers.push_back(randNum);
+ writePtr = Pack64(randNum, writePtr);
+ }
+
+ const char* readPtr = buffer.Data();
+ for (size_t i = 0; i < correctNumbers.size(); ++i) {
+ ui64 value = 0xDEADBEEF;
+ readPtr = Unpack64(value, readPtr);
+ UNIT_ASSERT_VALUES_EQUAL(value, correctNumbers[i]);
+ }
+ }
+#endif
+};
diff --git a/library/cpp/packedtypes/packedfloat.cpp b/library/cpp/packedtypes/packedfloat.cpp
new file mode 100644
index 0000000000..6039d78969
--- /dev/null
+++ b/library/cpp/packedtypes/packedfloat.cpp
@@ -0,0 +1,18 @@
+#include "packedfloat.h"
+
+#include <util/stream/output.h>
+
+#define OUT_IMPL(T) \
+ template <> \
+ void Out<T>(IOutputStream & os, TTypeTraits<T>::TFuncParam val) { \
+ os << (float)val; \
+ }
+
+OUT_IMPL(f16)
+OUT_IMPL(uf16)
+OUT_IMPL(f8)
+OUT_IMPL(uf8)
+OUT_IMPL(f8d)
+OUT_IMPL(uf8d)
+
+#undef OUT_IMPL
diff --git a/library/cpp/packedtypes/packedfloat.h b/library/cpp/packedtypes/packedfloat.h
new file mode 100644
index 0000000000..f178912ed3
--- /dev/null
+++ b/library/cpp/packedtypes/packedfloat.h
@@ -0,0 +1,217 @@
+#pragma once
+
+#include <util/generic/cast.h>
+#include <util/generic/ylimits.h>
+#include <util/system/hi_lo.h>
+
+#include <cmath>
+#include <cfloat>
+#include <limits>
+#include <algorithm>
+#include <cassert>
+
+namespace NPackedFloat {
+ /*
+ Exponent Mantissa zero Mantissa non-zero Equation
+ 0x00 zero denormal (-1)^sign * 2^-126 * 0.mantissa
+ 0x01–0xfe normalized value (-1)^sign * 2^(exponent - 127) * 1.mantissa
+ 0xff infinity NaN
+ * */
+
+ //fast 16 bit floats by melkov
+ template <ui8 SIGNED>
+ struct float16 {
+ private:
+ typedef float16<SIGNED> self;
+
+ public:
+ ui16 val;
+
+ explicit float16(ui16 v = 0)
+ : val(v)
+ {
+ }
+
+ self& operator=(float t) {
+ assert(SIGNED == 1 || SIGNED == 0 && t >= 0.);
+ val = BitCast<ui32>(t) >> (15 + SIGNED);
+ return *this;
+ }
+
+ operator float() const {
+ return BitCast<float>((ui32)val << (15 + SIGNED));
+ }
+
+ static self New(float v) {
+ self f;
+ return f = v;
+ }
+
+ static self denorm_min() {
+ return self(0x0001);
+ }
+
+ static self min() {
+ return self(SIGNED ? 0x0080 : 0x0100);
+ }
+
+ static self max() {
+ return self(SIGNED ? 0x7f7f : 0xfeff);
+ }
+ };
+
+ //fast 8 bit floats
+ template <ui8 SIGNED, ui8 DENORM = 0>
+ struct float8 {
+ private:
+ typedef float8<SIGNED, DENORM> self;
+ enum {
+ FMinExp = SIGNED ? 0x7c : 0x78,
+ FMaxExp = SIGNED ? 0x83 : 0x87,
+ MaxExp = SIGNED ? 0x70 : 0xf0,
+ };
+
+ public:
+ ui8 val;
+
+ explicit float8(ui8 v = 0)
+ : val(v)
+ {
+ }
+
+ self& operator=(float t) {
+ assert(SIGNED == 1 || SIGNED == 0 && t >= 0.);
+ ui16 hi16 = Hi16(t);
+
+ ui8 sign = SIGNED ? Hi8(hi16) & 0x80 : 0;
+
+ hi16 <<= 1;
+
+ ui8 fexp = Hi8(hi16);
+ ui8 exp;
+ ui8 frac = (Lo8(hi16) & 0xf0) >> 4;
+
+ if (fexp <= FMinExp) {
+ exp = 0;
+ frac = DENORM ? ((ui8)(0x10 | frac) >> std::min<int>((FMinExp - fexp + 1), 8)) : 0;
+ } else if (fexp > FMaxExp) {
+ exp = MaxExp;
+ frac = 0x0f;
+ } else {
+ exp = (fexp - FMinExp) << 4;
+ }
+
+ val = sign | exp | frac;
+ return *this;
+ }
+
+ operator float() const {
+ ui32 v = 0;
+
+ v |= SIGNED ? (val & 0x80) << 24 : 0;
+ ui8 frac = val & 0x0f;
+ ui8 exp = val & MaxExp;
+
+ if (exp) {
+ v |= ((exp >> 4) + FMinExp) << 23 | frac << 19;
+ } else if (DENORM && val & 0x0f) {
+ while (!(frac & 0x10)) {
+ frac <<= 1;
+ ++exp;
+ }
+
+ v |= (FMinExp - exp + 1) << 23 | (frac & 0x0f) << 19;
+ } else
+ v |= 0;
+
+ return BitCast<float>(v);
+ }
+
+ static self New(float v) {
+ self f;
+ return f = v;
+ }
+
+ static self denorm_min() {
+ return self(0x01);
+ }
+
+ static self min() {
+ return self(0x10);
+ }
+
+ static self max() {
+ return self(SIGNED ? 0x7f : 0xff);
+ }
+ };
+}
+
+using f64 = double;
+using f32 = float;
+static_assert(sizeof(f32) == 4, "expect sizeof(f32) == 4");
+static_assert(sizeof(f64) == 8, "expect sizeof(f64) == 8");
+using f16 = NPackedFloat::float16<1>;
+using uf16 = NPackedFloat::float16<0>;
+using f8 = NPackedFloat::float8<1>;
+using uf8 = NPackedFloat::float8<0>;
+using f8d = NPackedFloat::float8<1, 1>;
+using uf8d = NPackedFloat::float8<0, 1>;
+
+// [0,1) value in 1/255s.
+using frac8 = ui8;
+
+using frac16 = ui16;
+
+template <class T>
+inline constexpr T Float2Frac(float fac) {
+ return T(fac * float(Max<T>()));
+}
+
+template <class T>
+inline constexpr T Float2FracR(float fac) {
+ float v = fac * float(Max<T>());
+ return T(v + 0.5f);
+}
+
+template <class T>
+inline constexpr float Frac2Float(T pf) {
+ constexpr float multiplier = float(1.0 / Max<T>());
+ return pf * multiplier;
+}
+
+class TUi82FloatMapping {
+private:
+ float Mapping[Max<ui8>() + 1] = {};
+
+public:
+ constexpr TUi82FloatMapping() noexcept {
+ for (ui32 i = 0; i < Y_ARRAY_SIZE(Mapping); ++i) {
+ Mapping[i] = static_cast<float>(i) / Max<ui8>();
+ }
+ }
+
+ inline float operator [] (ui8 index) const {
+ return Mapping[index];
+ }
+};
+
+constexpr TUi82FloatMapping Ui82FloatMapping{};
+
+template <>
+inline float Frac2Float(ui8 pf) {
+ return Ui82FloatMapping[pf];
+}
+
+// Probably you don't want to use it, since sizeof(float) == sizeof(ui32)
+template <>
+inline float Frac2Float(ui32 pf) = delete;
+
+template <class T>
+inline float FracOrFloatToFloat(T t) {
+ return Frac2Float(t);
+}
+
+template <>
+inline float FracOrFloatToFloat<float>(float t) {
+ return t;
+}
diff --git a/library/cpp/packedtypes/packedfloat_ut.cpp b/library/cpp/packedtypes/packedfloat_ut.cpp
new file mode 100644
index 0000000000..f61e49014c
--- /dev/null
+++ b/library/cpp/packedtypes/packedfloat_ut.cpp
@@ -0,0 +1,130 @@
+#include "packedfloat.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/ylimits.h>
+
+class TPackedFloatTest: public TTestBase {
+ UNIT_TEST_SUITE(TPackedFloatTest);
+ UNIT_TEST(F16Test);
+ UNIT_TEST(Uf16Test);
+ UNIT_TEST(F8dTest);
+ UNIT_TEST(F8Test);
+ UNIT_TEST(Uf8dTest);
+ UNIT_TEST(Uf8Test);
+ UNIT_TEST_SUITE_END();
+
+private:
+ template <typename F>
+ void TestF(float f, float rf) {
+ UNIT_ASSERT(F::New(f) == rf);
+ }
+
+ void TestF16(float f, float rf) {
+ TestF<f16>(f, rf);
+ }
+
+ void F16Test() {
+ TestF16(f16(), 0.);
+ TestF16(0, 0);
+ TestF16(1.5, 1.5);
+ TestF16(-1.5, -1.5);
+ TestF16(f16::max(), f16::max());
+ TestF16(f16::min(), f16::min());
+ TestF16(2.0f * f16::max(), std::numeric_limits<float>::infinity());
+ TestF16(0.5 * f16::min(), 0.5 * f16::min());
+ TestF16(0.5 * f16::denorm_min(), 0);
+ TestF16(-0.5 * f16::denorm_min(), 0);
+ TestF16(FLT_MIN, FLT_MIN);
+ TestF16(FLT_MAX, f16::max());
+ TestF16(f16::min(), FLT_MIN);
+ TestF16(f16::denorm_min(), (FLT_MIN / (1 << 23)) * (1 << 16));
+ }
+
+ void TestUf16(float f, float rf) {
+ TestF<uf16>(f, rf);
+ }
+
+ void Uf16Test() {
+ UNIT_ASSERT(uf16() == 0.);
+
+ TestUf16(0, 0);
+ TestUf16(1.5, 1.5);
+ TestUf16(uf16::max(), uf16::max());
+ TestUf16(uf16::min(), uf16::min());
+ TestUf16(2.0f * uf16::max(), std::numeric_limits<float>::infinity());
+ TestUf16(0.5 * uf16::min(), 0.5 * uf16::min());
+ TestUf16(0.5 * uf16::denorm_min(), 0);
+ TestUf16(FLT_MIN, FLT_MIN);
+ TestUf16(FLT_MAX, uf16::max());
+ TestUf16(uf16::min(), FLT_MIN);
+ TestUf16(uf16::denorm_min(), (FLT_MIN / (1 << 23)) * (1 << 15));
+ }
+
+ void TestF8d(float f, float rf) {
+ TestF<f8d>(f, rf);
+ }
+
+ void F8dTest() {
+ UNIT_ASSERT(f8d() == 0.);
+
+ TestF8d(0, 0);
+ TestF8d(1.5, 1.5);
+ TestF8d(-1.5, -1.5);
+ TestF8d(f8d::max(), f8d::max());
+ TestF8d(f8d::min(), f8d::min());
+ TestF8d(f8d::denorm_min(), f8d::denorm_min());
+ TestF8d(2.0 * f8d::max(), f8d::max());
+ TestF8d(0.5 * f8d::min(), 0.5 * f8d::min());
+ TestF8d(0.5 * f8d::denorm_min(), 0);
+ }
+
+ void TestF8(float f, float rf) {
+ TestF<f8>(f, rf);
+ }
+
+ void F8Test() {
+ UNIT_ASSERT(f8() == 0.);
+
+ TestF8(0, 0);
+ TestF8(1.5, 1.5);
+ TestF8(-1.5, -1.5);
+ TestF8(f8::max(), f8::max());
+ TestF8(f8::min(), f8::min());
+ TestF8(2.0 * f8::max(), f8::max());
+ TestF8(0.5 * f8::min(), 0);
+ }
+
+ void TestUf8d(float f, float rf) {
+ TestF<uf8d>(f, rf);
+ }
+
+ void Uf8dTest() {
+ UNIT_ASSERT(uf8d() == 0.);
+
+ TestUf8d(0, 0);
+ TestUf8d(1.5, 1.5);
+ TestUf8d(uf8d::max(), uf8d::max());
+ TestUf8d(uf8d::min(), uf8d::min());
+ TestUf8d(uf8d::denorm_min(), uf8d::denorm_min());
+ TestUf8d(2.0 * uf8d::max(), uf8d::max());
+ TestUf8d(0.5 * uf8d::min(), 0.5 * uf8d::min());
+ TestUf8d(0.5 * uf8d::denorm_min(), 0);
+ }
+
+ void TestUf8(float f, float rf) {
+ TestF<uf8>(f, rf);
+ }
+
+ void Uf8Test() {
+ UNIT_ASSERT(uf8() == 0.);
+
+ TestUf8(0, 0);
+ TestUf8(1.5, 1.5);
+ TestUf8(uf8::max(), uf8::max());
+ TestUf8(uf8::min(), uf8::min());
+ TestUf8(2.0 * uf8::max(), uf8::max());
+ TestUf8(0.5 * uf8::min(), 0);
+ }
+};
+UNIT_TEST_SUITE_REGISTRATION(TPackedFloatTest);
diff --git a/library/cpp/packedtypes/ut/ya.make b/library/cpp/packedtypes/ut/ya.make
new file mode 100644
index 0000000000..a203115e71
--- /dev/null
+++ b/library/cpp/packedtypes/ut/ya.make
@@ -0,0 +1,19 @@
+UNITTEST_FOR(library/cpp/packedtypes)
+
+OWNER(
+ akhropov
+ velavokr
+)
+
+PEERDIR(
+ library/cpp/digest/old_crc
+)
+
+SRCS(
+ longs_ut.cpp
+ packed_ut.cpp
+ packedfloat_ut.cpp
+ zigzag_ut.cpp
+)
+
+END()
diff --git a/library/cpp/packedtypes/ya.make b/library/cpp/packedtypes/ya.make
new file mode 100644
index 0000000000..4c2c950619
--- /dev/null
+++ b/library/cpp/packedtypes/ya.make
@@ -0,0 +1,21 @@
+LIBRARY()
+
+OWNER(
+ akhropov
+ velavokr
+)
+
+PEERDIR(
+ library/cpp/streams/zc_memory_input
+)
+
+SRCS(
+ fixed_point.h
+ longs.cpp
+ packed.h
+ packedfloat.cpp
+ packedfloat.h
+ zigzag.h
+)
+
+END()
diff --git a/library/cpp/packedtypes/zigzag.h b/library/cpp/packedtypes/zigzag.h
new file mode 100644
index 0000000000..548403f838
--- /dev/null
+++ b/library/cpp/packedtypes/zigzag.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <util/generic/typetraits.h>
+
+#include <limits.h>
+
+//! Convert signed values to unsigned. Convenient for further varint encoding.
+//! See https://developers.google.com/protocol-buffers/docs/encoding#types for details.
+
+template <typename TSignedInt>
+inline auto ZigZagEncode(TSignedInt n) -> std::make_unsigned_t<TSignedInt> {
+ static_assert(std::is_signed<TSignedInt>::value && std::is_integral<TSignedInt>::value, "Expected signed integral type.");
+ auto un = static_cast<std::make_unsigned_t<TSignedInt>>(n);
+ return (un << 1) ^ (n >> (CHAR_BIT * sizeof(TSignedInt) - 1));
+}
+
+template <typename TUnsignedInt>
+inline auto ZigZagDecode(TUnsignedInt n) -> std::make_signed_t<TUnsignedInt> {
+ static_assert(std::is_unsigned<TUnsignedInt>::value, "Expected unsigned integral type.");
+ return (n >> 1) ^ -static_cast<std::make_signed_t<TUnsignedInt>>(n & 1);
+}
diff --git a/library/cpp/packedtypes/zigzag_ut.cpp b/library/cpp/packedtypes/zigzag_ut.cpp
new file mode 100644
index 0000000000..13b78b7481
--- /dev/null
+++ b/library/cpp/packedtypes/zigzag_ut.cpp
@@ -0,0 +1,38 @@
+#include "zigzag.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TZigZagTest) {
+ template <typename T>
+ void TestEncodeDecode(T value) {
+ auto encoded = ZigZagEncode(value);
+ UNIT_ASSERT(encoded >= 0);
+ auto decoded = ZigZagDecode(encoded);
+ UNIT_ASSERT(decoded == value);
+ static_assert(sizeof(value) == sizeof(decoded), "sizeof mismatch");
+ static_assert(sizeof(value) == sizeof(encoded), "sizeof mismatch");
+ }
+
+ template <typename TSignedInt>
+ void TestImpl() {
+ static const int bits = CHAR_BIT * sizeof(TSignedInt);
+ for (int p = 0; p + 1 < bits; ++p) {
+ TSignedInt value = 1;
+ value <<= p;
+
+ TestEncodeDecode(value);
+ TestEncodeDecode(-value);
+ TestEncodeDecode(value - 1);
+ TestEncodeDecode(-value + 1);
+ }
+
+ TestEncodeDecode((TSignedInt)123);
+ TestEncodeDecode((TSignedInt)-123);
+ }
+
+ Y_UNIT_TEST(TestSigned) {
+ TestImpl<i16>();
+ TestImpl<i32>();
+ TestImpl<i64>();
+ }
+}
diff --git a/library/cpp/packers/README.md b/library/cpp/packers/README.md
new file mode 100644
index 0000000000..c635bf8c8a
--- /dev/null
+++ b/library/cpp/packers/README.md
@@ -0,0 +1,2 @@
+A library of packers used to serialize data in the library/cpp/containers/comptrie.
+It is specially excluded as separate library since many packers are of standalone interest.
diff --git a/library/cpp/packers/packers.cpp b/library/cpp/packers/packers.cpp
new file mode 100644
index 0000000000..54615a9e7f
--- /dev/null
+++ b/library/cpp/packers/packers.cpp
@@ -0,0 +1,20 @@
+#include "packers.h"
+#include "region_packer.h"
+
+namespace NPackers {
+#define _X_4(X) X, X, X, X
+#define _X_8(X) _X_4(X), _X_4(X)
+#define _X_16(X) _X_8(X), _X_8(X)
+#define _X_32(X) _X_16(X), _X_16(X)
+#define _X_64(X) _X_32(X), _X_32(X)
+#define _X_128(X) _X_64(X), _X_64(X)
+
+ const ui8 SkipTable[256] = {_X_128(1), _X_64(2), _X_32(3), _X_16(4), _X_8(5), _X_4(6), 7, 7, 8, 9};
+
+#undef _X_4
+#undef _X_8
+#undef _X_16
+#undef _X_32
+#undef _X_64
+#undef _X_128
+}
diff --git a/library/cpp/packers/packers.h b/library/cpp/packers/packers.h
new file mode 100644
index 0000000000..1bde1b59aa
--- /dev/null
+++ b/library/cpp/packers/packers.h
@@ -0,0 +1,611 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/set.h>
+#include <util/generic/list.h>
+#include <util/generic/vector.h>
+#include <util/generic/bitops.h>
+
+#include <array>
+// Data serialization strategy class.
+// Default realization can pack only limited range of types, but you can pack any data other using your own strategy class.
+
+template <class T>
+class TNullPacker { // Very effective package class - pack any data into zero bytes :)
+public:
+ void UnpackLeaf(const char*, T& t) const {
+ t = T();
+ }
+
+ void PackLeaf(char*, const T&, size_t) const {
+ }
+
+ size_t MeasureLeaf(const T&) const {
+ return 0;
+ }
+
+ size_t SkipLeaf(const char*) const {
+ return 0;
+ }
+};
+
+template <typename T>
+class TAsIsPacker { // this packer is not really a packer...
+public:
+ void UnpackLeaf(const char* p, T& t) const {
+ memcpy(&t, p, sizeof(T));
+ }
+ void PackLeaf(char* buffer, const T& data, size_t computedSize) const {
+ Y_ASSERT(computedSize == sizeof(data));
+ memcpy(buffer, &data, sizeof(T));
+ }
+ size_t MeasureLeaf(const T& data) const {
+ Y_UNUSED(data);
+ return sizeof(T);
+ }
+ size_t SkipLeaf(const char*) const {
+ return sizeof(T);
+ }
+};
+
+// Implementation
+
+namespace NPackers {
+ template <class T>
+ inline ui64 ConvertIntegral(const T& data);
+
+ template <>
+ inline ui64 ConvertIntegral(const i64& data) {
+ if (data < 0) {
+ return (static_cast<ui64>(-1 * data) << 1) | 1;
+ } else {
+ return static_cast<ui64>(data) << 1;
+ }
+ }
+
+ namespace NImpl {
+ template <class T, bool isSigned>
+ struct TConvertImpl {
+ static inline ui64 Convert(const T& data);
+ };
+
+ template <class T>
+ struct TConvertImpl<T, true> {
+ static inline ui64 Convert(const T& data) {
+ return ConvertIntegral<i64>(static_cast<i64>(data));
+ }
+ };
+
+ template <class T>
+ struct TConvertImpl<T, false> {
+ static inline ui64 Convert(const T& data) {
+ return data;
+ }
+ };
+ }
+
+ template <class T>
+ inline ui64 ConvertIntegral(const T& data) {
+ static_assert(std::is_integral<T>::value, "T must be integral type");
+ return NImpl::TConvertImpl<T, std::is_signed<T>::value>::Convert(data);
+ }
+
+ //---------------------------------
+ // TIntegralPacker --- for integral types.
+
+ template <class T>
+ class TIntegralPacker { // can pack only integral types <= ui64
+ public:
+ void UnpackLeaf(const char* p, T& t) const;
+ void PackLeaf(char* buffer, const T& data, size_t size) const;
+ size_t MeasureLeaf(const T& data) const;
+ size_t SkipLeaf(const char* p) const;
+ };
+
+ template <>
+ inline size_t TIntegralPacker<ui64>::MeasureLeaf(const ui64& val) const {
+ constexpr size_t MAX_SIZE = sizeof(ui64) + sizeof(ui64) / 8;
+
+ ui64 value = val;
+ size_t len = 1;
+
+ value >>= 7;
+ for (; value && len < MAX_SIZE; value >>= 7)
+ ++len;
+
+ return len;
+ }
+
+ template <>
+ inline void TIntegralPacker<ui64>::PackLeaf(char* buffer, const ui64& val, size_t len) const {
+ ui64 value = val;
+ int lenmask = 0;
+
+ for (size_t i = len - 1; i; --i) {
+ buffer[i] = (char)(value & 0xFF);
+ value >>= 8;
+ lenmask = ((lenmask >> 1) | (1 << 7));
+ }
+
+ buffer[0] = (char)(lenmask | value);
+ }
+
+ extern const ui8 SkipTable[];
+
+ template <>
+ inline void TIntegralPacker<ui64>::UnpackLeaf(const char* p, ui64& result) const {
+ unsigned char ch = *(p++);
+ size_t taillen = SkipTable[ch] - 1;
+
+ result = (ch & (0x7F >> taillen));
+
+ while (taillen--)
+ result = ((result << 8) | (*(p++) & 0xFF));
+ }
+
+ template <>
+ inline size_t TIntegralPacker<ui64>::SkipLeaf(const char* p) const {
+ return SkipTable[(ui8)*p];
+ }
+
+ namespace NImpl {
+ template <class T, bool isSigned>
+ struct TUnpackLeafImpl {
+ inline void UnpackLeaf(const char* p, T& t) const;
+ };
+ template <class T>
+ struct TUnpackLeafImpl<T, true> {
+ inline void UnpackLeaf(const char* p, T& t) const {
+ ui64 val;
+ TIntegralPacker<ui64>().UnpackLeaf(p, val);
+ if (val & 1) {
+ t = -1 * static_cast<i64>(val >> 1);
+ } else {
+ t = static_cast<T>(val >> 1);
+ }
+ }
+ };
+ template <class T>
+ struct TUnpackLeafImpl<T, false> {
+ inline void UnpackLeaf(const char* p, T& t) const {
+ ui64 tmp;
+ TIntegralPacker<ui64>().UnpackLeaf(p, tmp);
+ t = static_cast<T>(tmp);
+ }
+ };
+ }
+
+ template <class T>
+ inline void TIntegralPacker<T>::UnpackLeaf(const char* p, T& t) const {
+ NImpl::TUnpackLeafImpl<T, std::is_signed<T>::value>().UnpackLeaf(p, t);
+ }
+
+ template <class T>
+ inline void TIntegralPacker<T>::PackLeaf(char* buffer, const T& data, size_t size) const {
+ TIntegralPacker<ui64>().PackLeaf(buffer, ConvertIntegral<T>(data), size);
+ }
+
+ template <class T>
+ inline size_t TIntegralPacker<T>::MeasureLeaf(const T& data) const {
+ return TIntegralPacker<ui64>().MeasureLeaf(ConvertIntegral<T>(data));
+ }
+
+ template <class T>
+ inline size_t TIntegralPacker<T>::SkipLeaf(const char* p) const {
+ return TIntegralPacker<ui64>().SkipLeaf(p);
+ }
+
+ //-------------------------------------------
+ // TFPPacker --- for float/double
+ namespace NImpl {
+ template <class TFloat, class TUInt>
+ class TFPPackerBase {
+ protected:
+ typedef TIntegralPacker<TUInt> TPacker;
+
+ union THelper {
+ TFloat F;
+ TUInt U;
+ };
+
+ TFloat FromUInt(TUInt u) const {
+ THelper h;
+ h.U = ReverseBytes(u);
+ return h.F;
+ }
+
+ TUInt ToUInt(TFloat f) const {
+ THelper h;
+ h.F = f;
+ return ReverseBytes(h.U);
+ }
+
+ public:
+ void UnpackLeaf(const char* c, TFloat& t) const {
+ TUInt u = 0;
+ TPacker().UnpackLeaf(c, u);
+ t = FromUInt(u);
+ }
+
+ void PackLeaf(char* c, const TFloat& t, size_t sz) const {
+ TPacker().PackLeaf(c, ToUInt(t), sz);
+ }
+
+ size_t MeasureLeaf(const TFloat& t) const {
+ return TPacker().MeasureLeaf(ToUInt(t));
+ }
+
+ size_t SkipLeaf(const char* c) const {
+ return TPacker().SkipLeaf(c);
+ }
+ };
+ }
+
+ class TFloatPacker: public NImpl::TFPPackerBase<float, ui32> {
+ };
+
+ class TDoublePacker: public NImpl::TFPPackerBase<double, ui64> {
+ };
+
+ //-------------------------------------------
+ // TStringPacker --- for TString/TUtf16String and TStringBuf.
+
+ template <class TStringType>
+ class TStringPacker {
+ public:
+ void UnpackLeaf(const char* p, TStringType& t) const;
+ void PackLeaf(char* buffer, const TStringType& data, size_t size) const;
+ size_t MeasureLeaf(const TStringType& data) const;
+ size_t SkipLeaf(const char* p) const;
+ };
+
+ template <class TStringType>
+ inline void TStringPacker<TStringType>::UnpackLeaf(const char* buf, TStringType& t) const {
+ size_t len;
+ TIntegralPacker<size_t>().UnpackLeaf(buf, len);
+ size_t start = TIntegralPacker<size_t>().SkipLeaf(buf);
+ t = TStringType((const typename TStringType::char_type*)(buf + start), len);
+ }
+
+ template <class TStringType>
+ inline void TStringPacker<TStringType>::PackLeaf(char* buf, const TStringType& str, size_t size) const {
+ size_t len = str.size();
+ size_t lenChar = len * sizeof(typename TStringType::char_type);
+ size_t start = size - lenChar;
+ TIntegralPacker<size_t>().PackLeaf(buf, len, TIntegralPacker<size_t>().MeasureLeaf(len));
+ memcpy(buf + start, str.data(), lenChar);
+ }
+
+ template <class TStringType>
+ inline size_t TStringPacker<TStringType>::MeasureLeaf(const TStringType& str) const {
+ size_t len = str.size();
+ return TIntegralPacker<size_t>().MeasureLeaf(len) + len * sizeof(typename TStringType::char_type);
+ }
+
+ template <class TStringType>
+ inline size_t TStringPacker<TStringType>::SkipLeaf(const char* buf) const {
+ size_t result = TIntegralPacker<size_t>().SkipLeaf(buf);
+ {
+ size_t len;
+ TIntegralPacker<size_t>().UnpackLeaf(buf, len);
+ result += len * sizeof(typename TStringType::char_type);
+ }
+ return result;
+ }
+
+ template <class T>
+ class TPacker;
+
+ // TContainerPacker --- for any container
+ // Requirements to class C:
+ // - has method size() (returns size_t)
+ // - has subclass C::value_type
+ // - has subclass C::const_iterator
+ // - has methods begin() and end() (return C::const_iterator)
+ // - has method insert(C::const_iterator, const C::value_type&)
+ // Examples: TVector, TList, TSet
+ // Requirements to class EP: has methods as in any packer (UnpackLeaf, PackLeaf, MeasureLeaf, SkipLeaf) that
+ // are applicable to C::value_type
+
+ template <typename T>
+ struct TContainerInfo {
+ enum {
+ IsVector = 0
+ };
+ };
+
+ template <typename T>
+ struct TContainerInfo<std::vector<T>> {
+ enum {
+ IsVector = 1
+ };
+ };
+
+ template <typename T>
+ struct TContainerInfo<TVector<T>> {
+ enum {
+ IsVector = 1
+ };
+ };
+
+ template <bool IsVector>
+ class TContainerPackerHelper {
+ };
+
+ template <>
+ class TContainerPackerHelper<false> {
+ public:
+ template <class Packer, class Container>
+ static void UnpackLeaf(Packer& p, const char* buffer, Container& c) {
+ p.UnpackLeafSimple(buffer, c);
+ }
+ };
+
+ template <>
+ class TContainerPackerHelper<true> {
+ public:
+ template <class Packer, class Container>
+ static void UnpackLeaf(Packer& p, const char* buffer, Container& c) {
+ p.UnpackLeafVector(buffer, c);
+ }
+ };
+
+ template <class C, class EP = TPacker<typename C::value_type>>
+ class TContainerPacker {
+ private:
+ typedef C TContainer;
+ typedef EP TElementPacker;
+ typedef typename TContainer::const_iterator TElementIterator;
+
+ void UnpackLeafSimple(const char* buffer, TContainer& c) const;
+ void UnpackLeafVector(const char* buffer, TContainer& c) const;
+
+ friend class TContainerPackerHelper<TContainerInfo<C>::IsVector>;
+
+ public:
+ void UnpackLeaf(const char* buffer, TContainer& c) const {
+ TContainerPackerHelper<TContainerInfo<C>::IsVector>::UnpackLeaf(*this, buffer, c);
+ }
+ void PackLeaf(char* buffer, const TContainer& data, size_t size) const;
+ size_t MeasureLeaf(const TContainer& data) const;
+ size_t SkipLeaf(const char* buffer) const;
+ };
+
+ template <class C, class EP>
+ inline void TContainerPacker<C, EP>::UnpackLeafSimple(const char* buffer, C& result) const {
+ size_t offset = TIntegralPacker<size_t>().SkipLeaf(buffer); // first value is the total size (not needed here)
+ size_t len;
+ TIntegralPacker<size_t>().UnpackLeaf(buffer + offset, len);
+ offset += TIntegralPacker<size_t>().SkipLeaf(buffer + offset);
+
+ result.clear();
+
+ typename C::value_type value;
+ for (size_t i = 0; i < len; i++) {
+ TElementPacker().UnpackLeaf(buffer + offset, value);
+ result.insert(result.end(), value);
+ offset += TElementPacker().SkipLeaf(buffer + offset);
+ }
+ }
+
+ template <class C, class EP>
+ inline void TContainerPacker<C, EP>::UnpackLeafVector(const char* buffer, C& result) const {
+ size_t offset = TIntegralPacker<size_t>().SkipLeaf(buffer); // first value is the total size (not needed here)
+ size_t len;
+ TIntegralPacker<size_t>().UnpackLeaf(buffer + offset, len);
+ offset += TIntegralPacker<size_t>().SkipLeaf(buffer + offset);
+ result.resize(len);
+
+ for (size_t i = 0; i < len; i++) {
+ TElementPacker().UnpackLeaf(buffer + offset, result[i]);
+ offset += TElementPacker().SkipLeaf(buffer + offset);
+ }
+ }
+
+ template <class C, class EP>
+ inline void TContainerPacker<C, EP>::PackLeaf(char* buffer, const C& data, size_t size) const {
+ size_t sizeOfSize = TIntegralPacker<size_t>().MeasureLeaf(size);
+ TIntegralPacker<size_t>().PackLeaf(buffer, size, sizeOfSize);
+ size_t len = data.size();
+ size_t curSize = TIntegralPacker<size_t>().MeasureLeaf(len);
+ TIntegralPacker<size_t>().PackLeaf(buffer + sizeOfSize, len, curSize);
+ curSize += sizeOfSize;
+ for (TElementIterator p = data.begin(); p != data.end(); p++) {
+ size_t sizeChange = TElementPacker().MeasureLeaf(*p);
+ TElementPacker().PackLeaf(buffer + curSize, *p, sizeChange);
+ curSize += sizeChange;
+ }
+ Y_ASSERT(curSize == size);
+ }
+
+ template <class C, class EP>
+ inline size_t TContainerPacker<C, EP>::MeasureLeaf(const C& data) const {
+ size_t curSize = TIntegralPacker<size_t>().MeasureLeaf(data.size());
+ for (TElementIterator p = data.begin(); p != data.end(); p++)
+ curSize += TElementPacker().MeasureLeaf(*p);
+ size_t extraSize = TIntegralPacker<size_t>().MeasureLeaf(curSize);
+
+ // Double measurement protects against sudden increases in extraSize,
+ // e.g. when curSize is 127 and stays in one byte, but curSize + 1 requires two bytes.
+
+ extraSize = TIntegralPacker<size_t>().MeasureLeaf(curSize + extraSize);
+ Y_ASSERT(extraSize == TIntegralPacker<size_t>().MeasureLeaf(curSize + extraSize));
+ return curSize + extraSize;
+ }
+
+ template <class C, class EP>
+ inline size_t TContainerPacker<C, EP>::SkipLeaf(const char* buffer) const {
+ size_t value;
+ TIntegralPacker<size_t>().UnpackLeaf(buffer, value);
+ return value;
+ }
+
+ // TPairPacker --- for std::pair<T1, T2> (any two types; can be nested)
+ // TPacker<T1> and TPacker<T2> should be valid classes
+
+ template <class T1, class T2, class TPacker1 = TPacker<T1>, class TPacker2 = TPacker<T2>>
+ class TPairPacker {
+ private:
+ typedef std::pair<T1, T2> TMyPair;
+
+ public:
+ void UnpackLeaf(const char* buffer, TMyPair& pair) const;
+ void PackLeaf(char* buffer, const TMyPair& data, size_t size) const;
+ size_t MeasureLeaf(const TMyPair& data) const;
+ size_t SkipLeaf(const char* buffer) const;
+ };
+
+ template <class T1, class T2, class TPacker1, class TPacker2>
+ inline void TPairPacker<T1, T2, TPacker1, TPacker2>::UnpackLeaf(const char* buffer, std::pair<T1, T2>& pair) const {
+ TPacker1().UnpackLeaf(buffer, pair.first);
+ size_t size = TPacker1().SkipLeaf(buffer);
+ TPacker2().UnpackLeaf(buffer + size, pair.second);
+ }
+
+ template <class T1, class T2, class TPacker1, class TPacker2>
+ inline void TPairPacker<T1, T2, TPacker1, TPacker2>::PackLeaf(char* buffer, const std::pair<T1, T2>& data, size_t size) const {
+ size_t size1 = TPacker1().MeasureLeaf(data.first);
+ TPacker1().PackLeaf(buffer, data.first, size1);
+ size_t size2 = TPacker2().MeasureLeaf(data.second);
+ TPacker2().PackLeaf(buffer + size1, data.second, size2);
+ Y_ASSERT(size == size1 + size2);
+ }
+
+ template <class T1, class T2, class TPacker1, class TPacker2>
+ inline size_t TPairPacker<T1, T2, TPacker1, TPacker2>::MeasureLeaf(const std::pair<T1, T2>& data) const {
+ size_t size1 = TPacker1().MeasureLeaf(data.first);
+ size_t size2 = TPacker2().MeasureLeaf(data.second);
+ return size1 + size2;
+ }
+
+ template <class T1, class T2, class TPacker1, class TPacker2>
+ inline size_t TPairPacker<T1, T2, TPacker1, TPacker2>::SkipLeaf(const char* buffer) const {
+ size_t size1 = TPacker1().SkipLeaf(buffer);
+ size_t size2 = TPacker2().SkipLeaf(buffer + size1);
+ return size1 + size2;
+ }
+
+ //------------------------------------------------------------------------------------------
+ // Packer for fixed-size arrays, i.e. for std::array.
+ // Saves memory by not storing anything about their size.
+ // SkipLeaf skips every value, so can be slow for big arrays.
+ // Requires std::tuple_size<TValue>, TValue::operator[] and possibly TValue::value_type.
+ template <class TValue, class TElementPacker = TPacker<typename TValue::value_type>>
+ class TArrayPacker {
+ public:
+ using TElemPacker = TElementPacker;
+
+ enum {
+ Size = std::tuple_size<TValue>::value
+ };
+
+ void UnpackLeaf(const char* p, TValue& t) const {
+ const char* buf = p;
+ for (size_t i = 0; i < Size; ++i) {
+ TElemPacker().UnpackLeaf(buf, t[i]);
+ buf += TElemPacker().SkipLeaf(buf);
+ }
+ }
+
+ void PackLeaf(char* buffer, const TValue& data, size_t computedSize) const {
+ size_t remainingSize = computedSize;
+ char* pos = buffer;
+ for (size_t i = 0; i < Size; ++i) {
+ const size_t elemSize = TElemPacker().MeasureLeaf(data[i]);
+ TElemPacker().PackLeaf(pos, data[i], Min(elemSize, remainingSize));
+ pos += elemSize;
+ remainingSize -= elemSize;
+ }
+ }
+
+ size_t MeasureLeaf(const TValue& data) const {
+ size_t result = 0;
+ for (size_t i = 0; i < Size; ++i) {
+ result += TElemPacker().MeasureLeaf(data[i]);
+ }
+ return result;
+ }
+
+ size_t SkipLeaf(const char* p) const // this function better be fast because it is very frequently used
+ {
+ const char* buf = p;
+ for (size_t i = 0; i < Size; ++i) {
+ buf += TElemPacker().SkipLeaf(buf);
+ }
+ return buf - p;
+ }
+ };
+
+ //------------------------------------
+ // TPacker --- the generic packer.
+
+ template <class T, bool IsIntegral>
+ class TPackerImpl;
+
+ template <class T>
+ class TPackerImpl<T, true>: public TIntegralPacker<T> {
+ };
+ // No implementation for non-integral types.
+
+ template <class T>
+ class TPacker: public TPackerImpl<T, std::is_integral<T>::value> {
+ };
+
+ template <>
+ class TPacker<float>: public TAsIsPacker<float> {
+ };
+
+ template <>
+ class TPacker<double>: public TAsIsPacker<double> {
+ };
+
+ template <>
+ class TPacker<TString>: public TStringPacker<TString> {
+ };
+
+ template <>
+ class TPacker<TUtf16String>: public TStringPacker<TUtf16String> {
+ };
+
+ template <>
+ class TPacker<TStringBuf>: public TStringPacker<TStringBuf> {
+ };
+
+ template <>
+ class TPacker<TWtringBuf>: public TStringPacker<TWtringBuf> {
+ };
+
+ template <class T>
+ class TPacker<std::vector<T>>: public TContainerPacker<std::vector<T>> {
+ };
+
+ template <class T>
+ class TPacker<TVector<T>>: public TContainerPacker<TVector<T>> {
+ };
+
+ template <class T>
+ class TPacker<std::list<T>>: public TContainerPacker<std::list<T>> {
+ };
+
+ template <class T>
+ class TPacker<TList<T>>: public TContainerPacker<TList<T>> {
+ };
+
+ template <class T>
+ class TPacker<std::set<T>>: public TContainerPacker<std::set<T>> {
+ };
+
+ template <class T>
+ class TPacker<TSet<T>>: public TContainerPacker<TSet<T>> {
+ };
+
+ template <class T1, class T2>
+ class TPacker<std::pair<T1, T2>>: public TPairPacker<T1, T2> {
+ };
+
+ template <class T, size_t N>
+ class TPacker<std::array<T, N>>: public TArrayPacker<std::array<T, N>> {
+ };
+
+}
diff --git a/library/cpp/packers/proto_packer.cpp b/library/cpp/packers/proto_packer.cpp
new file mode 100644
index 0000000000..ddca0d5b3b
--- /dev/null
+++ b/library/cpp/packers/proto_packer.cpp
@@ -0,0 +1 @@
+#include "proto_packer.h"
diff --git a/library/cpp/packers/proto_packer.h b/library/cpp/packers/proto_packer.h
new file mode 100644
index 0000000000..5a3d008e29
--- /dev/null
+++ b/library/cpp/packers/proto_packer.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include "packers.h"
+
+#include <util/generic/yexception.h>
+
+namespace NPackers {
+ template <typename TProtoMessage>
+ class TProtoMessagePacker {
+ public:
+ void UnpackLeaf(const char* bufferPtr, TProtoMessage& protoMessage) const {
+ const size_t protoMessageByteSize = GetProtoMessageByteSize(bufferPtr);
+ const size_t skipBytesCount = ProtoMessageByteSizePacker.SkipLeaf(bufferPtr);
+
+ if (!protoMessage.ParseFromArray(static_cast<const void*>(bufferPtr + skipBytesCount), protoMessageByteSize)) {
+ ythrow yexception() << "Cannot unpack leaf with proto message";
+ }
+ }
+
+ void PackLeaf(char* bufferPtr, const TProtoMessage& protoMessage, const size_t totalByteSize) const {
+ const size_t protoMessageByteSize = protoMessage.ByteSize();
+ const size_t skipBytesCount = totalByteSize - protoMessageByteSize;
+
+ ProtoMessageByteSizePacker.PackLeaf(bufferPtr, protoMessageByteSize, skipBytesCount);
+
+ if (!protoMessage.SerializeToArray(static_cast<void*>(bufferPtr + skipBytesCount), protoMessageByteSize)) {
+ ythrow yexception() << "Cannot pack leaf with proto message";
+ }
+ }
+
+ size_t MeasureLeaf(const TProtoMessage& protoMessage) const {
+ const size_t protoMessageByteSize = protoMessage.ByteSize();
+ return ProtoMessageByteSizePacker.MeasureLeaf(protoMessageByteSize) + protoMessageByteSize;
+ }
+
+ size_t SkipLeaf(const char* bufferPtr) const {
+ const size_t protoMessageByteSize = GetProtoMessageByteSize(bufferPtr);
+ return ProtoMessageByteSizePacker.SkipLeaf(bufferPtr) + protoMessageByteSize;
+ }
+
+ private:
+ TIntegralPacker<size_t> ProtoMessageByteSizePacker;
+
+ size_t GetProtoMessageByteSize(const char* bufferPtr) const {
+ size_t result;
+ ProtoMessageByteSizePacker.UnpackLeaf(bufferPtr, result);
+ return result;
+ }
+ };
+}
diff --git a/library/cpp/packers/region_packer.cpp b/library/cpp/packers/region_packer.cpp
new file mode 100644
index 0000000000..3d8b20c371
--- /dev/null
+++ b/library/cpp/packers/region_packer.cpp
@@ -0,0 +1 @@
+#include "region_packer.h"
diff --git a/library/cpp/packers/region_packer.h b/library/cpp/packers/region_packer.h
new file mode 100644
index 0000000000..2c661cb5bc
--- /dev/null
+++ b/library/cpp/packers/region_packer.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "packers.h"
+
+#include <util/generic/array_ref.h>
+
+// Stores an array of PODs in the trie (copying them with memcpy).
+// Byte order and alignment are your problem.
+
+template <class TRecord>
+class TRegionPacker {
+public:
+ typedef TArrayRef<TRecord> TRecords;
+
+ void UnpackLeaf(const char* p, TRecords& result) const {
+ size_t len;
+ NPackers::TIntegralPacker<size_t>().UnpackLeaf(p, len);
+ size_t start = NPackers::TIntegralPacker<size_t>().SkipLeaf(p);
+ result = TRecords((TRecord*)(p + start), len);
+ }
+
+ void PackLeaf(char* buf, const TRecords& data, size_t computedSize) const {
+ size_t len = data.size();
+ size_t lenChar = len * sizeof(TRecord);
+ size_t start = computedSize - lenChar;
+ NPackers::TIntegralPacker<size_t>().PackLeaf(buf, len, NPackers::TIntegralPacker<size_t>().MeasureLeaf(len));
+ memcpy(buf + start, data.data(), lenChar);
+ }
+
+ size_t MeasureLeaf(const TRecords& data) const {
+ size_t len = data.size();
+ return NPackers::TIntegralPacker<size_t>().MeasureLeaf(len) + len * sizeof(TRecord);
+ }
+
+ size_t SkipLeaf(const char* p) const {
+ size_t result = NPackers::TIntegralPacker<size_t>().SkipLeaf(p);
+ size_t len;
+ NPackers::TIntegralPacker<size_t>().UnpackLeaf(p, len);
+ result += len * sizeof(TRecord);
+ return result;
+ }
+};
diff --git a/library/cpp/packers/ut/packers_ut.cpp b/library/cpp/packers/ut/packers_ut.cpp
new file mode 100644
index 0000000000..18ce2150d1
--- /dev/null
+++ b/library/cpp/packers/ut/packers_ut.cpp
@@ -0,0 +1,110 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/output.h>
+#include <utility>
+
+#include <util/charset/wide.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/buffer.h>
+#include <util/generic/map.h>
+#include <util/generic/vector.h>
+#include <util/generic/ptr.h>
+#include <util/generic/ylimits.h>
+
+#include <util/folder/dirut.h>
+
+#include <util/random/random.h>
+
+#include <util/string/hex.h>
+
+#include "packers.h"
+
+#include <array>
+#include <iterator>
+
+class TPackersTest: public TTestBase {
+private:
+ UNIT_TEST_SUITE(TPackersTest);
+ UNIT_TEST(TestPackers);
+ UNIT_TEST_SUITE_END();
+
+ template <class TData, class TPacker>
+ void TestPacker(const TData& data);
+
+ template <class TData, class TPacker>
+ void TestPacker(const TData* test, size_t size);
+
+public:
+ void TestPackers();
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TPackersTest);
+
+template <class TData, class TPacker>
+void TPackersTest::TestPacker(const TData& data) {
+ size_t len = TPacker().MeasureLeaf(data);
+ size_t bufLen = len * 3;
+
+ TArrayHolder<char> buf(new char[bufLen]);
+ memset(buf.Get(), -1, bufLen);
+
+ TPacker().PackLeaf(buf.Get(), data, len);
+
+ UNIT_ASSERT(TPacker().SkipLeaf(buf.Get()) == len);
+
+ TData dataTmp;
+ TPacker().UnpackLeaf(buf.Get(), dataTmp);
+ UNIT_ASSERT(data == dataTmp);
+}
+
+template <class TData, class TPacker>
+void TPackersTest::TestPacker(const TData* test, size_t size) {
+ for (size_t i = 0; i < size; ++i) {
+ TestPacker<TData, TPacker>(test[i]);
+ }
+}
+
+void TPackersTest::TestPackers() {
+ {
+ const TString test[] = {"",
+ "a", "b", "c", "d",
+ "aa", "ab", "ac", "ad",
+ "aaa", "aab", "aac", "aad",
+ "aba", "abb", "abc", "abd",
+ "asdfjjmk.gjilsjgilsjilgjildsajgfilsjdfilgjm ldsa8oq43u 583uq4905 -q435 jiores u893q 5oiju fd-KE 89536 9Q2URE 12AI894T3 89 Q*(re43"};
+
+ TestPacker<TString, NPackers::TPacker<TString>>(test, Y_ARRAY_SIZE(test));
+
+ for (size_t i = 0; i != Y_ARRAY_SIZE(test); ++i) {
+ TestPacker<TUtf16String, NPackers::TPacker<TUtf16String>>(UTF8ToWide(test[i]));
+ }
+ }
+ {
+ const ui64 test[] = {
+ 0, 1, 2, 3, 4, 5, 6, 76, 100000, Max<ui64>()};
+
+ TestPacker<ui64, NPackers::TPacker<ui64>>(test, Y_ARRAY_SIZE(test));
+ }
+ {
+ const int test[] = {
+ 0, 1, 2, 3, 4, 5, 6, 76, 100000, -1, -2, -3, -4, -5, -6, -76, -10000, Min<int>(), Max<int>()};
+
+ TestPacker<int, NPackers::TPacker<int>>(test, Y_ARRAY_SIZE(test));
+ }
+ {
+ const float test[] = {
+ 2.f, 3.f, 4.f, 0.f, -0.f, 1.f, -1.f, 1.1f, -1.1f,
+ std::numeric_limits<float>::min(), -std::numeric_limits<float>::min(),
+ std::numeric_limits<float>::max(), -std::numeric_limits<float>::max()};
+
+ TestPacker<float, NPackers::TFloatPacker>(test, Y_ARRAY_SIZE(test));
+ }
+ {
+ const double test[] = {
+ 0., -0., 1., -1., 1.1, -1.1,
+ std::numeric_limits<double>::min(), -std::numeric_limits<double>::min(),
+ std::numeric_limits<double>::max(), -std::numeric_limits<double>::max()};
+
+ TestPacker<double, NPackers::TDoublePacker>(test, Y_ARRAY_SIZE(test));
+ }
+}
diff --git a/library/cpp/packers/ut/proto_packer_ut.cpp b/library/cpp/packers/ut/proto_packer_ut.cpp
new file mode 100644
index 0000000000..e4151ba68c
--- /dev/null
+++ b/library/cpp/packers/ut/proto_packer_ut.cpp
@@ -0,0 +1,104 @@
+#include "proto_packer.h"
+
+#include <library/cpp/packers/ut/test.pb.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/string.h>
+
+using namespace NPackers;
+using namespace NProtoPackerTest;
+
+void FillRequiredFields(TTestMessage& msg) {
+ msg.SetRequiredString("required_string");
+ msg.SetRequiredInt32(42);
+}
+
+void FillOptionalFields(TTestMessage& msg) {
+ msg.SetOptionalString("optional_string");
+ msg.SetOptionalInt32(43);
+}
+
+void FillRepeatedFields(TTestMessage& msg) {
+ msg.ClearRepeatedStrings();
+ for (ui32 idx = 0; idx < 5; ++idx) {
+ msg.AddRepeatedStrings("repeated_string" + ToString(idx));
+ }
+}
+
+// do not want to use google/protobuf/util/message_differencer because of warnings
+bool operator==(const TTestMessage& lhs, const TTestMessage& rhs) {
+ if (lhs.GetRequiredString() != rhs.GetRequiredString() ||
+ lhs.GetRequiredInt32() != rhs.GetRequiredInt32() ||
+ lhs.HasOptionalString() != rhs.HasOptionalString() ||
+ (lhs.HasOptionalString() && lhs.GetOptionalString() != rhs.GetOptionalString()) ||
+ lhs.HasOptionalInt32() != rhs.HasOptionalInt32() ||
+ (lhs.HasOptionalInt32() && lhs.GetOptionalInt32() != rhs.GetOptionalInt32()) ||
+ lhs.RepeatedStringsSize() != rhs.RepeatedStringsSize())
+ {
+ return false;
+ }
+ for (ui32 idx = 0; idx < lhs.RepeatedStringsSize(); ++idx) {
+ if (lhs.GetRepeatedStrings(idx) != rhs.GetRepeatedStrings(idx)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+Y_UNIT_TEST_SUITE(ProtoPackerTestSuite) {
+ TProtoMessagePacker<TTestMessage> Packer;
+ TString Buffer;
+
+ void DoPackUnpackTest(const TTestMessage& msg) {
+ const ui32 msgByteSize = Packer.MeasureLeaf(msg);
+ Buffer.resize(msgByteSize);
+
+ Packer.PackLeaf(Buffer.begin(), msg, msgByteSize);
+
+ TTestMessage checkMsg;
+ Packer.UnpackLeaf(Buffer.begin(), checkMsg);
+
+ UNIT_ASSERT_EQUAL(msg, checkMsg);
+ }
+
+ Y_UNIT_TEST(TestPackUnpackOnlyRequired) {
+ TTestMessage msg;
+ FillRequiredFields(msg);
+ DoPackUnpackTest(msg);
+ }
+
+ Y_UNIT_TEST(TestPackUnpackRequiredAndOptional) {
+ TTestMessage msg;
+ FillRequiredFields(msg);
+ FillOptionalFields(msg);
+ DoPackUnpackTest(msg);
+ }
+
+ Y_UNIT_TEST(TestPackUnpackAll) {
+ TTestMessage msg;
+ FillRequiredFields(msg);
+ FillOptionalFields(msg);
+ FillRepeatedFields(msg);
+ DoPackUnpackTest(msg);
+ }
+
+ Y_UNIT_TEST(TestSkipLeaf) {
+ TTestMessage msgFirst;
+ FillRequiredFields(msgFirst);
+ TTestMessage msgSecond;
+ FillRequiredFields(msgSecond);
+ FillOptionalFields(msgSecond);
+
+ const ui32 msgFirstByteSize = Packer.MeasureLeaf(msgFirst);
+ const ui32 msgSecondByteSize = Packer.MeasureLeaf(msgSecond);
+
+ Buffer.resize(msgFirstByteSize + msgSecondByteSize);
+ Packer.PackLeaf(Buffer.begin(), msgFirst, msgFirstByteSize);
+ Packer.PackLeaf(Buffer.begin() + msgFirstByteSize, msgSecond, msgSecondByteSize);
+
+ TTestMessage checkMsg;
+ Packer.UnpackLeaf(Buffer.begin() + Packer.SkipLeaf(Buffer.begin()), checkMsg);
+
+ UNIT_ASSERT_EQUAL(msgSecond, checkMsg);
+ }
+}
diff --git a/library/cpp/packers/ut/region_packer_ut.cpp b/library/cpp/packers/ut/region_packer_ut.cpp
new file mode 100644
index 0000000000..0cb08ccf65
--- /dev/null
+++ b/library/cpp/packers/ut/region_packer_ut.cpp
@@ -0,0 +1,40 @@
+#include "region_packer.h"
+#include <library/cpp/testing/unittest/registar.h>
+
+template <typename TValue>
+void TestPacker() {
+ TValue values[] = {1, 2, 3, 42};
+ TString buffer;
+
+ TRegionPacker<TValue> p;
+
+ using TValues = TArrayRef<TValue>;
+ TValues valueRegion = TValues(values, Y_ARRAY_SIZE(values));
+ size_t sz = p.MeasureLeaf(valueRegion);
+ UNIT_ASSERT_VALUES_EQUAL(sz, 1 + sizeof(values));
+
+ buffer.resize(sz);
+ p.PackLeaf(buffer.begin(), valueRegion, sz);
+ UNIT_ASSERT_VALUES_EQUAL(buffer[0], 4);
+
+ p.UnpackLeaf(buffer.data(), valueRegion);
+ UNIT_ASSERT_EQUAL(valueRegion.data(), (const TValue*)(buffer.begin() + 1));
+ UNIT_ASSERT_EQUAL(valueRegion.size(), Y_ARRAY_SIZE(values));
+ UNIT_ASSERT_EQUAL(0, memcmp(values, valueRegion.data(), sizeof(values)));
+}
+
+Y_UNIT_TEST_SUITE(RegionPacker) {
+ Y_UNIT_TEST(Test0) {
+ TestPacker<char>();
+ TestPacker<signed char>();
+ TestPacker<unsigned char>();
+ TestPacker<i8>();
+ TestPacker<ui8>();
+ TestPacker<i16>();
+ TestPacker<ui16>();
+ TestPacker<i32>();
+ TestPacker<ui32>();
+ TestPacker<i64>();
+ TestPacker<ui64>();
+ }
+}
diff --git a/library/cpp/packers/ut/test.proto b/library/cpp/packers/ut/test.proto
new file mode 100644
index 0000000000..c872616bcc
--- /dev/null
+++ b/library/cpp/packers/ut/test.proto
@@ -0,0 +1,11 @@
+package NProtoPackerTest;
+
+message TTestMessage {
+ required string RequiredString = 1;
+ optional string OptionalString = 2;
+
+ required int32 RequiredInt32 = 3;
+ optional int32 OptionalInt32 = 4;
+
+ repeated string RepeatedStrings = 5;
+}
diff --git a/library/cpp/packers/ut/ya.make b/library/cpp/packers/ut/ya.make
new file mode 100644
index 0000000000..1c024ffd94
--- /dev/null
+++ b/library/cpp/packers/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/packers)
+
+OWNER(velavokr)
+
+SRCS(
+ packers_ut.cpp
+ proto_packer_ut.cpp
+ region_packer_ut.cpp
+ test.proto
+)
+
+END()
diff --git a/library/cpp/packers/ya.make b/library/cpp/packers/ya.make
new file mode 100644
index 0000000000..e1ec4972ed
--- /dev/null
+++ b/library/cpp/packers/ya.make
@@ -0,0 +1,11 @@
+LIBRARY()
+
+OWNER(velavokr)
+
+SRCS(
+ packers.cpp
+ proto_packer.cpp
+ region_packer.cpp
+)
+
+END()
diff --git a/library/cpp/pop_count/benchmark/main.cpp b/library/cpp/pop_count/benchmark/main.cpp
new file mode 100644
index 0000000000..41ea3c91cc
--- /dev/null
+++ b/library/cpp/pop_count/benchmark/main.cpp
@@ -0,0 +1,52 @@
+#include <util/stream/output.h>
+#include <util/datetime/cputimer.h>
+#include <util/system/type_name.h>
+
+#include <library/cpp/pop_count/popcount.h>
+#include <library/cpp/testing/benchmark/bench.h>
+
+template <class F, class I>
+inline void DoRun(F&& f, I&& i) {
+ const ui64 n = i.Iterations();
+
+ for (ui64 j = 0; j < n; ++j) {
+ Y_DO_NOT_OPTIMIZE_AWAY(f(j * (ui64)123456 + (ui64)1));
+ }
+}
+
+Y_CPU_BENCHMARK(PopCount_8, iface) {
+ DoRun([](ui8 x) {
+ return PopCount<ui8>(x);
+ },
+ iface);
+}
+
+Y_CPU_BENCHMARK(PopCount_16, iface) {
+ DoRun([](ui16 x) {
+ return PopCount<ui16>(x);
+ },
+ iface);
+}
+
+Y_CPU_BENCHMARK(PopCount_32, iface) {
+ DoRun([](ui32 x) {
+ return PopCount<ui32>(x);
+ },
+ iface);
+}
+
+Y_CPU_BENCHMARK(PopCount_64, iface) {
+ DoRun([](ui64 x) {
+ return PopCount<ui64>(x);
+ },
+ iface);
+}
+
+#if !defined(_MSC_VER)
+Y_CPU_BENCHMARK(BUILTIN_64, iface) {
+ DoRun([](ui64 x) {
+ return __builtin_popcountll(x);
+ },
+ iface);
+}
+#endif
diff --git a/library/cpp/pop_count/benchmark/ya.make b/library/cpp/pop_count/benchmark/ya.make
new file mode 100644
index 0000000000..7fb54a519a
--- /dev/null
+++ b/library/cpp/pop_count/benchmark/ya.make
@@ -0,0 +1,14 @@
+OWNER(g:util)
+
+Y_BENCHMARK()
+
+PEERDIR(
+ util/draft
+ library/cpp/pop_count
+)
+
+SRCS(
+ main.cpp
+)
+
+END()
diff --git a/library/cpp/pop_count/popcount.cpp b/library/cpp/pop_count/popcount.cpp
new file mode 100644
index 0000000000..49276424be
--- /dev/null
+++ b/library/cpp/pop_count/popcount.cpp
@@ -0,0 +1,30 @@
+#include "popcount.h"
+
+#include <util/system/defaults.h>
+#include <util/system/yassert.h>
+
+#include <string.h>
+
+static const ui8 PopCountLUT8Impl[1 << 8] = {
+#define B2(n) n, n + 1, n + 1, n + 2
+#define B4(n) B2(n), B2(n + 1), B2(n + 1), B2(n + 2)
+#define B6(n) B4(n), B4(n + 1), B4(n + 1), B4(n + 2)
+ B6(0), B6(1), B6(1), B6(2)};
+
+ui8 const* PopCountLUT8 = PopCountLUT8Impl;
+
+#if !defined(_MSC_VER)
+//ICE here for msvc
+
+static const ui8 PopCountLUT16Impl[1 << 16] = {
+#define B2(n) n, n + 1, n + 1, n + 2
+#define B4(n) B2(n), B2(n + 1), B2(n + 1), B2(n + 2)
+#define B6(n) B4(n), B4(n + 1), B4(n + 1), B4(n + 2)
+#define B8(n) B6(n), B6(n + 1), B6(n + 1), B6(n + 2)
+#define B10(n) B8(n), B8(n + 1), B8(n + 1), B8(n + 2)
+#define B12(n) B10(n), B10(n + 1), B10(n + 1), B10(n + 2)
+#define B14(n) B12(n), B12(n + 1), B12(n + 1), B12(n + 2)
+ B14(0), B14(1), B14(1), B14(2)};
+
+ui8 const* PopCountLUT16 = PopCountLUT16Impl;
+#endif
diff --git a/library/cpp/pop_count/popcount.h b/library/cpp/pop_count/popcount.h
new file mode 100644
index 0000000000..3d67737ed2
--- /dev/null
+++ b/library/cpp/pop_count/popcount.h
@@ -0,0 +1,105 @@
+#pragma once
+
+#include <util/generic/typelist.h>
+#include <util/system/cpu_id.h>
+#include <util/system/defaults.h>
+#include <util/system/hi_lo.h>
+#include <util/system/platform.h>
+
+#if defined(_MSC_VER)
+#include <intrin.h>
+#endif
+
+static inline ui32 PopCountImpl(ui8 n) {
+#if defined(_ppc64_)
+ ui32 r;
+ __asm__("popcntb %0, %1"
+ : "=r"(r)
+ : "r"(n)
+ :);
+ return r;
+#else
+ extern ui8 const* PopCountLUT8;
+ return PopCountLUT8[n];
+#endif
+}
+
+static inline ui32 PopCountImpl(ui16 n) {
+#if defined(_MSC_VER)
+ return __popcnt16(n);
+#else
+ extern ui8 const* PopCountLUT16;
+ return PopCountLUT16[n];
+#endif
+}
+
+static inline ui32 PopCountImpl(ui32 n) {
+#if defined(_MSC_VER)
+ return __popcnt(n);
+#else
+#if defined(_x86_64_)
+ if (NX86::CachedHavePOPCNT()) {
+ ui32 r;
+
+ __asm__("popcnt %1, %0;"
+ : "=r"(r)
+ : "r"(n)
+ :);
+
+ return r;
+ }
+#else
+#if defined(_ppc64_)
+ ui32 r;
+
+ __asm__("popcntw %0, %1"
+ : "=r"(r)
+ : "r"(n)
+ :);
+
+ return r;
+#endif
+#endif
+
+ return PopCountImpl((ui16)Lo16(n)) + PopCountImpl((ui16)Hi16(n));
+#endif
+}
+
+static inline ui32 PopCountImpl(ui64 n) {
+#if defined(_MSC_VER) && !defined(_i386_)
+ return __popcnt64(n);
+#else
+#if defined(_x86_64_)
+ if (NX86::CachedHavePOPCNT()) {
+ ui64 r;
+
+ __asm__("popcnt %1, %0;"
+ : "=r"(r)
+ : "r"(n)
+ :);
+
+ return r;
+ }
+#else
+#if defined(_ppc64_)
+ ui32 r;
+
+ __asm__("popcntd %0, %1"
+ : "=r"(r)
+ : "r"(n)
+ :);
+
+ return r;
+#endif
+#endif
+
+ return PopCountImpl((ui32)Lo32(n)) + PopCountImpl((ui32)Hi32(n));
+#endif
+}
+
+template <class T>
+static inline ui32 PopCount(T n) {
+ using TCvt = TFixedWidthUnsignedInt<T>;
+
+ return PopCountImpl((TCvt)n);
+}
diff --git a/library/cpp/pop_count/popcount_ut.cpp b/library/cpp/pop_count/popcount_ut.cpp
new file mode 100644
index 0000000000..5cd6605411
--- /dev/null
+++ b/library/cpp/pop_count/popcount_ut.cpp
@@ -0,0 +1,70 @@
+#include "popcount.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/random/random.h>
+
+Y_UNIT_TEST_SUITE(TestPopCount) {
+ template <class T>
+ static inline ui32 SlowPopCount(T t) {
+ ui32 ret = 0;
+
+ while (t) {
+ if (t & T(1)) {
+ ++ret;
+ }
+
+ t = t >> 1;
+ }
+
+ return ret;
+ }
+
+ template <class T>
+ static inline void Test() {
+ for (size_t i = 0; i < 10000; ++i) {
+ const T rndv = RandomNumber<T>();
+
+ UNIT_ASSERT_VALUES_EQUAL(SlowPopCount(rndv), PopCount(rndv));
+ }
+ }
+
+ Y_UNIT_TEST(Test8) {
+ Test<ui8>();
+ }
+
+ Y_UNIT_TEST(Test16) {
+ Test<ui16>();
+ }
+
+ Y_UNIT_TEST(Test32) {
+ Test<ui32>();
+ }
+
+ Y_UNIT_TEST(Test64) {
+ Test<ui64>();
+ }
+
+ Y_UNIT_TEST(TestPopCount) {
+ UNIT_ASSERT_VALUES_EQUAL(PopCount(0), 0);
+ UNIT_ASSERT_VALUES_EQUAL(PopCount(1), 1);
+ UNIT_ASSERT_VALUES_EQUAL(PopCount(1 << 10), 1);
+ UNIT_ASSERT_VALUES_EQUAL(PopCount((1 << 10) + 1), 2);
+ UNIT_ASSERT_VALUES_EQUAL(PopCount(0xFFFF), 16);
+ UNIT_ASSERT_VALUES_EQUAL(PopCount(0xFFFFFFFF), 32);
+ UNIT_ASSERT_VALUES_EQUAL(PopCount(0x55555555), 16);
+
+ UNIT_ASSERT_VALUES_EQUAL(0, PopCount(0ULL));
+ UNIT_ASSERT_VALUES_EQUAL(1, PopCount(1ULL));
+ UNIT_ASSERT_VALUES_EQUAL(16, PopCount(0xAAAAAAAAULL));
+ UNIT_ASSERT_VALUES_EQUAL(32, PopCount(0xFFFFFFFFULL));
+ UNIT_ASSERT_VALUES_EQUAL(32, PopCount(0xAAAAAAAAAAAAAAAAULL));
+ UNIT_ASSERT_VALUES_EQUAL(64, PopCount(0xFFFFFFFFFFFFFFFFULL));
+
+ ui64 v = 0;
+
+ for (int i = 0; i < 64; v |= 1ULL << i, ++i) {
+ UNIT_ASSERT_VALUES_EQUAL(i, PopCount(v));
+ }
+ }
+}
diff --git a/library/cpp/pop_count/ut/ya.make b/library/cpp/pop_count/ut/ya.make
new file mode 100644
index 0000000000..f0e6c014e5
--- /dev/null
+++ b/library/cpp/pop_count/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/pop_count)
+
+OWNER(g:util)
+
+SRCS(
+ popcount_ut.cpp
+)
+
+END()
diff --git a/library/cpp/pop_count/ya.make b/library/cpp/pop_count/ya.make
new file mode 100644
index 0000000000..0dec238979
--- /dev/null
+++ b/library/cpp/pop_count/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(g:util)
+
+SRCS(
+ popcount.cpp
+)
+
+END()
diff --git a/library/cpp/protobuf/interop/cast.cpp b/library/cpp/protobuf/interop/cast.cpp
new file mode 100644
index 0000000000..c4cd59b417
--- /dev/null
+++ b/library/cpp/protobuf/interop/cast.cpp
@@ -0,0 +1,23 @@
+#include <library/cpp/protobuf/interop/cast.h>
+
+#include <google/protobuf/duration.pb.h>
+#include <google/protobuf/timestamp.pb.h>
+#include <google/protobuf/util/time_util.h>
+
+namespace NProtoInterop {
+ google::protobuf::Duration CastToProto(TDuration duration) {
+ return google::protobuf::util::TimeUtil::MicrosecondsToDuration(duration.MicroSeconds());
+ }
+
+ google::protobuf::Timestamp CastToProto(TInstant instant) {
+ return google::protobuf::util::TimeUtil::MicrosecondsToTimestamp(instant.MicroSeconds());
+ }
+
+ TDuration CastFromProto(const google::protobuf::Duration& duration) {
+ return TDuration::MicroSeconds(google::protobuf::util::TimeUtil::DurationToMicroseconds(duration));
+ }
+
+ TInstant CastFromProto(const google::protobuf::Timestamp& timestamp) {
+ return TInstant::MicroSeconds(google::protobuf::util::TimeUtil::TimestampToMicroseconds(timestamp));
+ }
+}
diff --git a/library/cpp/protobuf/interop/cast.h b/library/cpp/protobuf/interop/cast.h
new file mode 100644
index 0000000000..b1c295236e
--- /dev/null
+++ b/library/cpp/protobuf/interop/cast.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <util/datetime/base.h>
+
+namespace google::protobuf {
+ class Duration;
+ class Timestamp;
+}
+
+namespace NProtoInterop {
+ google::protobuf::Duration CastToProto(TDuration duration);
+ google::protobuf::Timestamp CastToProto(TInstant instant);
+ TDuration CastFromProto(const google::protobuf::Duration& message);
+ TInstant CastFromProto(const google::protobuf::Timestamp& message);
+}
diff --git a/library/cpp/protobuf/interop/ut/cast_ut.cpp b/library/cpp/protobuf/interop/ut/cast_ut.cpp
new file mode 100644
index 0000000000..6ef055b651
--- /dev/null
+++ b/library/cpp/protobuf/interop/ut/cast_ut.cpp
@@ -0,0 +1,52 @@
+#include <library/cpp/protobuf/interop/cast.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <google/protobuf/duration.pb.h>
+#include <google/protobuf/timestamp.pb.h>
+
+static constexpr ui64 MicroSecondsInSecond = 1000 * 1000;
+static constexpr ui64 NanoSecondsInMicroSecond = 1000;
+
+Y_UNIT_TEST_SUITE(TCastTest) {
+ Y_UNIT_TEST(TimestampFromProto) {
+ const ui64 now = TInstant::Now().MicroSeconds();
+
+ google::protobuf::Timestamp timestamp;
+ timestamp.set_seconds(now / MicroSecondsInSecond);
+ timestamp.set_nanos((now % MicroSecondsInSecond) * NanoSecondsInMicroSecond);
+
+ const TInstant instant = NProtoInterop::CastFromProto(timestamp);
+ UNIT_ASSERT_EQUAL(instant.MicroSeconds(), now);
+ }
+
+ Y_UNIT_TEST(DurationFromProto) {
+ const ui64 now = TInstant::Now().MicroSeconds();
+
+ google::protobuf::Duration message;
+ message.set_seconds(now / MicroSecondsInSecond);
+ message.set_nanos((now % MicroSecondsInSecond) * NanoSecondsInMicroSecond);
+
+ const TDuration duration = NProtoInterop::CastFromProto(message);
+ UNIT_ASSERT_EQUAL(duration.MicroSeconds(), now);
+ }
+
+ Y_UNIT_TEST(TimestampToProto) {
+ const TInstant instant = TInstant::Now();
+
+ google::protobuf::Timestamp timestamp = NProtoInterop::CastToProto(instant);
+ const ui64 microSeconds = timestamp.seconds() * MicroSecondsInSecond +
+ timestamp.nanos() / NanoSecondsInMicroSecond;
+
+ UNIT_ASSERT_EQUAL(instant.MicroSeconds(), microSeconds);
+ }
+
+ Y_UNIT_TEST(DurationToProto) {
+ const TDuration duration = TDuration::Seconds(TInstant::Now().Seconds() / 2);
+
+ google::protobuf::Duration message = NProtoInterop::CastToProto(duration);
+ const ui64 microSeconds = message.seconds() * MicroSecondsInSecond +
+ message.nanos() / NanoSecondsInMicroSecond;
+
+ UNIT_ASSERT_EQUAL(duration.MicroSeconds(), microSeconds);
+ }
+}
diff --git a/library/cpp/protobuf/interop/ut/ya.make b/library/cpp/protobuf/interop/ut/ya.make
new file mode 100644
index 0000000000..b9c634cb6b
--- /dev/null
+++ b/library/cpp/protobuf/interop/ut/ya.make
@@ -0,0 +1,15 @@
+UNITTEST_FOR(library/cpp/protobuf/interop)
+
+OWNER(
+ paxakor
+)
+
+SRCS(
+ cast_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/protobuf/interop
+)
+
+END()
diff --git a/library/cpp/protobuf/interop/ya.make b/library/cpp/protobuf/interop/ya.make
new file mode 100644
index 0000000000..618b553459
--- /dev/null
+++ b/library/cpp/protobuf/interop/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(
+ paxakor
+)
+
+SRCS(
+ cast.cpp
+)
+
+PEERDIR(
+ contrib/libs/protobuf
+)
+
+END()
diff --git a/library/cpp/protobuf/json/README b/library/cpp/protobuf/json/README
new file mode 100644
index 0000000000..a0d1092ee2
--- /dev/null
+++ b/library/cpp/protobuf/json/README
@@ -0,0 +1 @@
+Protobuf to/from JSON converter.
diff --git a/library/cpp/protobuf/json/config.h b/library/cpp/protobuf/json/config.h
new file mode 100644
index 0000000000..dc84fb4d5d
--- /dev/null
+++ b/library/cpp/protobuf/json/config.h
@@ -0,0 +1,164 @@
+#pragma once
+
+#include "string_transform.h"
+#include "name_generator.h"
+
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+#include <functional>
+
+namespace NProtobufJson {
+ struct TProto2JsonConfig {
+ using TSelf = TProto2JsonConfig;
+
+ bool FormatOutput = false;
+
+ enum MissingKeyMode {
+ // Skip missing keys
+ MissingKeySkip = 0,
+ // Fill missing keys with json null value.
+ MissingKeyNull,
+ // Use default value in any case.
+ // If default value is not explicitly defined, use default type value:
+ // i.e. 0 for integers, "" for strings
+ // For repeated keys, means []
+ MissingKeyDefault,
+ // Use default value if it is explicitly specified for optional fields.
+ // Skip if no explicitly defined default value for optional fields.
+ // Throw exception if required field is empty.
+ // For repeated keys, same as MissingKeySkip
+ MissingKeyExplicitDefaultThrowRequired
+ };
+ MissingKeyMode MissingSingleKeyMode = MissingKeySkip;
+ MissingKeyMode MissingRepeatedKeyMode = MissingKeySkip;
+
+ /// Add null value for missing fields (false by default).
+ bool AddMissingFields = false;
+
+ enum EnumValueMode {
+ EnumNumber = 0, // default
+ EnumName,
+ EnumFullName,
+ EnumNameLowerCase,
+ EnumFullNameLowerCase,
+ };
+ EnumValueMode EnumMode = EnumNumber;
+
+ enum FldNameMode {
+ FieldNameOriginalCase = 0, // default
+ FieldNameLowerCase,
+ FieldNameUpperCase,
+ FieldNameCamelCase,
+ FieldNameSnakeCase, // ABC -> a_b_c, UserID -> user_i_d
+ FieldNameSnakeCaseDense // ABC -> abc, UserID -> user_id
+ };
+ FldNameMode FieldNameMode = FieldNameOriginalCase;
+
+ enum ExtFldNameMode {
+ ExtFldNameFull = 0, // default, field.full_name()
+ ExtFldNameShort // field.name()
+ };
+ ExtFldNameMode ExtensionFieldNameMode = ExtFldNameFull;
+
+ /// Use 'json_name' protobuf option for field name, mutually exclusive
+ /// with FieldNameMode.
+ bool UseJsonName = false;
+
+ /// Transforms will be applied only to string values (== protobuf fields of string / bytes type).
+ /// yajl_encode_string will be used if no transforms are specified.
+ TVector<TStringTransformPtr> StringTransforms;
+
+ /// Print map as object, otherwise print it as array of key/value objects
+ bool MapAsObject = false;
+
+ /// Stringify long integers which are not exactly representable by float or double values
+ enum EStringifyLongNumbersMode {
+ StringifyLongNumbersNever = 0, // default
+ StringifyLongNumbersForFloat,
+ StringifyLongNumbersForDouble,
+ };
+ EStringifyLongNumbersMode StringifyLongNumbers = StringifyLongNumbersNever;
+
+ /// Custom field names generator.
+ TNameGenerator NameGenerator = {};
+
+ /// Custom enum values generator.
+ TEnumValueGenerator EnumValueGenerator = {};
+
+ bool WriteNanAsString = false;
+
+ TSelf& SetFormatOutput(bool format) {
+ FormatOutput = format;
+ return *this;
+ }
+
+ TSelf& SetMissingSingleKeyMode(MissingKeyMode mode) {
+ MissingSingleKeyMode = mode;
+ return *this;
+ }
+
+ TSelf& SetMissingRepeatedKeyMode(MissingKeyMode mode) {
+ MissingRepeatedKeyMode = mode;
+ return *this;
+ }
+
+ TSelf& SetAddMissingFields(bool add) {
+ AddMissingFields = add;
+ return *this;
+ }
+
+ TSelf& SetEnumMode(EnumValueMode mode) {
+ EnumMode = mode;
+ return *this;
+ }
+
+ TSelf& SetFieldNameMode(FldNameMode mode) {
+ Y_ENSURE(mode == FieldNameOriginalCase || !UseJsonName, "FieldNameMode and UseJsonName are mutually exclusive");
+ FieldNameMode = mode;
+ return *this;
+ }
+
+ TSelf& SetUseJsonName(bool jsonName) {
+ Y_ENSURE(!jsonName || FieldNameMode == FieldNameOriginalCase, "FieldNameMode and UseJsonName are mutually exclusive");
+ UseJsonName = jsonName;
+ return *this;
+ }
+
+ TSelf& SetExtensionFieldNameMode(ExtFldNameMode mode) {
+ ExtensionFieldNameMode = mode;
+ return *this;
+ }
+
+ TSelf& AddStringTransform(TStringTransformPtr transform) {
+ StringTransforms.push_back(transform);
+ return *this;
+ }
+
+ TSelf& SetMapAsObject(bool value) {
+ MapAsObject = value;
+ return *this;
+ }
+
+ TSelf& SetStringifyLongNumbers(EStringifyLongNumbersMode stringify) {
+ StringifyLongNumbers = stringify;
+ return *this;
+ }
+
+ TSelf& SetNameGenerator(TNameGenerator callback) {
+ NameGenerator = callback;
+ return *this;
+ }
+
+ TSelf& SetEnumValueGenerator(TEnumValueGenerator callback) {
+ EnumValueGenerator = callback;
+ return *this;
+ }
+
+ TSelf& SetWriteNanAsString(bool value) {
+ WriteNanAsString = value;
+ return *this;
+ }
+ };
+
+}
diff --git a/library/cpp/protobuf/json/field_option.h b/library/cpp/protobuf/json/field_option.h
new file mode 100644
index 0000000000..c8a8bfbff5
--- /dev/null
+++ b/library/cpp/protobuf/json/field_option.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/message.h>
+
+namespace NProtobufJson {
+ // Functor that defines whether given field has some option set to true
+ //
+ // Example:
+ // message T {
+ // optional stroka some_field = 1 [(some_option) = true];
+ // }
+ //
+ template <typename TFieldOptionExtensionId>
+ class TFieldOptionFunctor {
+ public:
+ TFieldOptionFunctor(const TFieldOptionExtensionId& option, bool positive = true)
+ : Option(option)
+ , Positive(positive)
+ {
+ }
+
+ bool operator()(const NProtoBuf::Message&, const NProtoBuf::FieldDescriptor* field) const {
+ const NProtoBuf::FieldOptions& opt = field->options();
+ const bool val = opt.GetExtension(Option);
+ return Positive ? val : !val;
+ }
+
+ private:
+ const TFieldOptionExtensionId& Option;
+ bool Positive;
+ };
+
+ template <typename TFieldOptionExtensionId>
+ TFieldOptionFunctor<TFieldOptionExtensionId> MakeFieldOptionFunctor(const TFieldOptionExtensionId& option, bool positive = true) {
+ return TFieldOptionFunctor<TFieldOptionExtensionId>(option, positive);
+ }
+
+}
diff --git a/library/cpp/protobuf/json/filter.h b/library/cpp/protobuf/json/filter.h
new file mode 100644
index 0000000000..9a3ddb54fe
--- /dev/null
+++ b/library/cpp/protobuf/json/filter.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include "config.h"
+#include "proto2json_printer.h"
+#include "json_output_create.h"
+
+#include <util/generic/yexception.h>
+#include <util/generic/utility.h>
+
+#include <functional>
+
+namespace NProtobufJson {
+ template <typename TBasePrinter = TProto2JsonPrinter> // TBasePrinter is assumed to be a TProto2JsonPrinter descendant
+ class TFilteringPrinter: public TBasePrinter {
+ public:
+ using TFieldPredicate = std::function<bool(const NProtoBuf::Message&, const NProtoBuf::FieldDescriptor*)>;
+
+ template <typename... TArgs>
+ TFilteringPrinter(TFieldPredicate isPrinted, TArgs&&... args)
+ : TBasePrinter(std::forward<TArgs>(args)...)
+ , IsPrinted(std::move(isPrinted))
+ {
+ }
+
+ virtual void PrintField(const NProtoBuf::Message& proto,
+ const NProtoBuf::FieldDescriptor& field,
+ IJsonOutput& json,
+ TStringBuf key) override {
+ if (key || IsPrinted(proto, &field))
+ TBasePrinter::PrintField(proto, field, json, key);
+ }
+
+ private:
+ TFieldPredicate IsPrinted;
+ };
+
+ inline void PrintWithFilter(const NProtoBuf::Message& msg, TFilteringPrinter<>::TFieldPredicate filter, IJsonOutput& output, const TProto2JsonConfig& config = TProto2JsonConfig()) {
+ TFilteringPrinter<> printer(std::move(filter), config);
+ printer.Print(msg, output);
+ }
+
+ inline TString PrintWithFilter(const NProtoBuf::Message& msg, TFilteringPrinter<>::TFieldPredicate filter, const TProto2JsonConfig& config = TProto2JsonConfig()) {
+ TString ret;
+ PrintWithFilter(msg, std::move(filter), *CreateJsonMapOutput(ret, config), config);
+ return ret;
+ }
+
+}
diff --git a/library/cpp/protobuf/json/inline.h b/library/cpp/protobuf/json/inline.h
new file mode 100644
index 0000000000..e2d7bb6ef0
--- /dev/null
+++ b/library/cpp/protobuf/json/inline.h
@@ -0,0 +1,115 @@
+#pragma once
+
+// A printer from protobuf to json string, with ability to inline some string fields of given protobuf message
+// into output as ready json without additional escaping. These fields should be marked using special field option.
+// An example of usage:
+// 1) Define a field option in your .proto to identify fields which should be inlined, e.g.
+//
+// import "google/protobuf/descriptor.proto";
+// extend google.protobuf.FieldOptions {
+// optional bool this_is_json = 58253; // do not forget assign some more or less unique tag
+// }
+//
+// 2) Mark some fields of your protobuf message with this option, e.g.:
+//
+// message TMyObject {
+// optional string A = 1 [(this_is_json) = true];
+// }
+//
+// 3) In the C++ code you prepare somehow an object of TMyObject type
+//
+// TMyObject o;
+// o.Set("{\"inner\":\"value\"}");
+//
+// 4) And then serialize it to json string with inlining, e.g.:
+//
+// Cout << NProtobufJson::PrintInlined(o, MakeFieldOptionFunctor(this_is_json)) << Endl;
+//
+// 5) Alternatively you can specify a some more abstract functor for defining raw json fields
+//
+// which will print following json to stdout:
+// {"A":{"inner":"value"}}
+// instead of
+// {"A":"{\"inner\":\"value\"}"}
+// which would be printed with normal Proto2Json printer.
+//
+// See ut/inline_ut.cpp for additional examples of usage.
+
+#include "config.h"
+#include "proto2json_printer.h"
+#include "json_output_create.h"
+
+#include <library/cpp/protobuf/util/simple_reflection.h>
+
+#include <util/generic/maybe.h>
+#include <util/generic/yexception.h>
+#include <util/generic/utility.h>
+
+#include <functional>
+
+namespace NProtobufJson {
+ template <typename TBasePrinter = TProto2JsonPrinter> // TBasePrinter is assumed to be a TProto2JsonPrinter descendant
+ class TInliningPrinter: public TBasePrinter {
+ public:
+ using TFieldPredicate = std::function<bool(const NProtoBuf::Message&,
+ const NProtoBuf::FieldDescriptor*)>;
+
+ template <typename... TArgs>
+ TInliningPrinter(TFieldPredicate isInlined, TArgs&&... args)
+ : TBasePrinter(std::forward<TArgs>(args)...)
+ , IsInlined(std::move(isInlined))
+ {
+ }
+
+ virtual void PrintField(const NProtoBuf::Message& proto,
+ const NProtoBuf::FieldDescriptor& field,
+ IJsonOutput& json,
+ TStringBuf key) override {
+ const NProtoBuf::TConstField f(proto, &field);
+ if (!key && IsInlined(proto, &field) && ShouldPrint(f)) {
+ key = this->MakeKey(field);
+ json.WriteKey(key);
+ if (!field.is_repeated()) {
+ json.WriteRawJson(f.Get<TString>());
+ } else {
+ json.BeginList();
+ for (size_t i = 0, sz = f.Size(); i < sz; ++i)
+ json.WriteRawJson(f.Get<TString>(i));
+ json.EndList();
+ }
+
+ } else {
+ TBasePrinter::PrintField(proto, field, json, key);
+ }
+ }
+
+ private:
+ bool ShouldPrint(const NProtoBuf::TConstField& f) const {
+ if (!f.IsString())
+ ythrow yexception() << "TInliningPrinter: json field "
+ << f.Field()->name() << " should be a string";
+
+ if (f.HasValue())
+ return true;
+
+ // we may want write default value for given field in case of its absence
+ const auto& cfg = this->GetConfig();
+ return (f.Field()->is_repeated() ? cfg.MissingRepeatedKeyMode : cfg.MissingSingleKeyMode) == TProto2JsonConfig::MissingKeyDefault;
+ }
+
+ private:
+ TFieldPredicate IsInlined;
+ };
+
+ inline void PrintInlined(const NProtoBuf::Message& msg, TInliningPrinter<>::TFieldPredicate isInlined, IJsonOutput& output, const TProto2JsonConfig& config = TProto2JsonConfig()) {
+ TInliningPrinter<> printer(std::move(isInlined), config);
+ printer.Print(msg, output);
+ }
+
+ inline TString PrintInlined(const NProtoBuf::Message& msg, TInliningPrinter<>::TFieldPredicate isInlined, const TProto2JsonConfig& config = TProto2JsonConfig()) {
+ TString ret;
+ PrintInlined(msg, std::move(isInlined), *CreateJsonMapOutput(ret, config), config);
+ return ret;
+ }
+
+}
diff --git a/library/cpp/protobuf/json/json2proto.cpp b/library/cpp/protobuf/json/json2proto.cpp
new file mode 100644
index 0000000000..640c10f5a5
--- /dev/null
+++ b/library/cpp/protobuf/json/json2proto.cpp
@@ -0,0 +1,428 @@
+#include "json2proto.h"
+#include "util.h"
+
+#include <library/cpp/json/json_value.h>
+
+#include <google/protobuf/message.h>
+#include <google/protobuf/descriptor.h>
+
+#include <util/generic/hash.h>
+#include <util/generic/maybe.h>
+#include <util/string/ascii.h>
+#include <util/string/cast.h>
+
+#define JSON_TO_FIELD(EProtoCppType, name, json, JsonCheckType, ProtoSet, JsonGet) \
+ case FieldDescriptor::EProtoCppType: { \
+ if (config.CastRobust) { \
+ reflection->ProtoSet(&proto, &field, json.JsonGet##Robust()); \
+ break; \
+ } \
+ if (!json.JsonCheckType()) { \
+ if (config.CastFromString && json.IsString()) { \
+ if (config.DoNotCastEmptyStrings && json.GetString().empty()) { \
+ /* Empty string is same as "no value" for scalar types.*/ \
+ break; \
+ } \
+ reflection->ProtoSet(&proto, &field, FromString(json.GetString())); \
+ break; \
+ } \
+ ythrow yexception() << "Invalid type of JSON field " << name << ": " \
+ << #JsonCheckType << "() failed while " \
+ << #EProtoCppType << " is expected."; \
+ } \
+ reflection->ProtoSet(&proto, &field, json.JsonGet()); \
+ break; \
+ }
+
+static TString GetFieldName(const google::protobuf::FieldDescriptor& field,
+ const NProtobufJson::TJson2ProtoConfig& config) {
+ if (config.NameGenerator) {
+ return config.NameGenerator(field);
+ }
+
+ if (config.UseJsonName) {
+ Y_ASSERT(!field.json_name().empty());
+ TString name = field.json_name();
+ if (!field.has_json_name() && !name.empty()) {
+ // FIXME: https://st.yandex-team.ru/CONTRIB-139
+ name[0] = AsciiToLower(name[0]);
+ }
+ return name;
+ }
+
+ TString name = field.name();
+ switch (config.FieldNameMode) {
+ case NProtobufJson::TJson2ProtoConfig::FieldNameOriginalCase:
+ break;
+ case NProtobufJson::TJson2ProtoConfig::FieldNameLowerCase:
+ name.to_lower();
+ break;
+ case NProtobufJson::TJson2ProtoConfig::FieldNameUpperCase:
+ name.to_upper();
+ break;
+ case NProtobufJson::TJson2ProtoConfig::FieldNameCamelCase:
+ if (!name.empty()) {
+ name[0] = AsciiToLower(name[0]);
+ }
+ break;
+ case NProtobufJson::TJson2ProtoConfig::FieldNameSnakeCase:
+ NProtobufJson::ToSnakeCase(&name);
+ break;
+ case NProtobufJson::TJson2ProtoConfig::FieldNameSnakeCaseDense:
+ NProtobufJson::ToSnakeCaseDense(&name);
+ break;
+ default:
+ Y_VERIFY_DEBUG(false, "Unknown FieldNameMode.");
+ }
+ return name;
+}
+
+static void
+JsonString2Field(const NJson::TJsonValue& json,
+ google::protobuf::Message& proto,
+ const google::protobuf::FieldDescriptor& field,
+ const NProtobufJson::TJson2ProtoConfig& config) {
+ using namespace google::protobuf;
+
+ const Reflection* reflection = proto.GetReflection();
+ Y_ASSERT(!!reflection);
+
+ if (!json.IsString() && !config.CastRobust) {
+ ythrow yexception() << "Invalid type of JSON field '" << field.name() << "': "
+ << "IsString() failed while "
+ << "CPPTYPE_STRING is expected.";
+ }
+ TString value = json.GetStringRobust();
+ for (size_t i = 0, endI = config.StringTransforms.size(); i < endI; ++i) {
+ Y_ASSERT(!!config.StringTransforms[i]);
+ if (!!config.StringTransforms[i]) {
+ if (field.type() == google::protobuf::FieldDescriptor::TYPE_BYTES) {
+ config.StringTransforms[i]->TransformBytes(value);
+ } else {
+ config.StringTransforms[i]->Transform(value);
+ }
+ }
+ }
+
+ if (field.is_repeated())
+ reflection->AddString(&proto, &field, value);
+ else
+ reflection->SetString(&proto, &field, value);
+}
+
+static const NProtoBuf::EnumValueDescriptor*
+FindEnumValue(const NProtoBuf::EnumDescriptor* enumField,
+ TStringBuf target, bool (*equals)(TStringBuf, TStringBuf)) {
+ for (int i = 0; i < enumField->value_count(); i++) {
+ auto* valueDescriptor = enumField->value(i);
+ if (equals(valueDescriptor->name(), target)) {
+ return valueDescriptor;
+ }
+ }
+ return nullptr;
+}
+
+static void
+JsonEnum2Field(const NJson::TJsonValue& json,
+ google::protobuf::Message& proto,
+ const google::protobuf::FieldDescriptor& field,
+ const NProtobufJson::TJson2ProtoConfig& config) {
+ using namespace google::protobuf;
+
+ const Reflection* reflection = proto.GetReflection();
+ Y_ASSERT(!!reflection);
+
+ const EnumDescriptor* enumField = field.enum_type();
+ Y_ASSERT(!!enumField);
+
+ /// @todo configure name/numerical value
+ const EnumValueDescriptor* enumFieldValue = nullptr;
+
+ if (json.IsInteger()) {
+ const auto value = json.GetInteger();
+ enumFieldValue = enumField->FindValueByNumber(value);
+ if (!enumFieldValue) {
+ ythrow yexception() << "Invalid integer value of JSON enum field: " << value << ".";
+ }
+ } else if (json.IsString()) {
+ const auto& value = json.GetString();
+ if (config.EnumValueMode == NProtobufJson::TJson2ProtoConfig::EnumCaseInsensetive) {
+ enumFieldValue = FindEnumValue(enumField, value, AsciiEqualsIgnoreCase);
+ } else if (config.EnumValueMode == NProtobufJson::TJson2ProtoConfig::EnumSnakeCaseInsensitive) {
+ enumFieldValue = FindEnumValue(enumField, value, NProtobufJson::EqualsIgnoringCaseAndUnderscores);
+ } else {
+ enumFieldValue = enumField->FindValueByName(value);
+ }
+ if (!enumFieldValue) {
+ ythrow yexception() << "Invalid string value of JSON enum field: " << TStringBuf(value).Head(100) << ".";
+ }
+ } else {
+ ythrow yexception() << "Invalid type of JSON enum field: not an integer/string.";
+ }
+
+ if (field.is_repeated()) {
+ reflection->AddEnum(&proto, &field, enumFieldValue);
+ } else {
+ reflection->SetEnum(&proto, &field, enumFieldValue);
+ }
+}
+
+static void
+Json2SingleField(const NJson::TJsonValue& json,
+ google::protobuf::Message& proto,
+ const google::protobuf::FieldDescriptor& field,
+ const NProtobufJson::TJson2ProtoConfig& config,
+ bool isMapValue = false) {
+ using namespace google::protobuf;
+
+ const Reflection* reflection = proto.GetReflection();
+ Y_ASSERT(!!reflection);
+
+ TString name;
+ if (!isMapValue) {
+ name = GetFieldName(field, config);
+ if (!json.Has(name) || json[name].GetType() == NJson::JSON_UNDEFINED || json[name].GetType() == NJson::JSON_NULL) {
+ if (field.is_required() && !field.has_default_value() && !reflection->HasField(proto, &field) && config.CheckRequiredFields) {
+ ythrow yexception() << "JSON has no field for required field "
+ << name << ".";
+ }
+
+ return;
+ }
+ }
+
+ const NJson::TJsonValue& fieldJson = name ? json[name] : json;
+
+ switch (field.cpp_type()) {
+ JSON_TO_FIELD(CPPTYPE_INT32, field.name(), fieldJson, IsInteger, SetInt32, GetInteger);
+ JSON_TO_FIELD(CPPTYPE_INT64, field.name(), fieldJson, IsInteger, SetInt64, GetInteger);
+ JSON_TO_FIELD(CPPTYPE_UINT32, field.name(), fieldJson, IsInteger, SetUInt32, GetInteger);
+ JSON_TO_FIELD(CPPTYPE_UINT64, field.name(), fieldJson, IsUInteger, SetUInt64, GetUInteger);
+ JSON_TO_FIELD(CPPTYPE_DOUBLE, field.name(), fieldJson, IsDouble, SetDouble, GetDouble);
+ JSON_TO_FIELD(CPPTYPE_FLOAT, field.name(), fieldJson, IsDouble, SetFloat, GetDouble);
+ JSON_TO_FIELD(CPPTYPE_BOOL, field.name(), fieldJson, IsBoolean, SetBool, GetBoolean);
+
+ case FieldDescriptor::CPPTYPE_STRING: {
+ JsonString2Field(fieldJson, proto, field, config);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ JsonEnum2Field(fieldJson, proto, field, config);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_MESSAGE: {
+ Message* innerProto = reflection->MutableMessage(&proto, &field);
+ Y_ASSERT(!!innerProto);
+ NProtobufJson::MergeJson2Proto(fieldJson, *innerProto, config);
+
+ break;
+ }
+
+ default:
+ ythrow yexception() << "Unknown protobuf field type: "
+ << static_cast<int>(field.cpp_type()) << ".";
+ }
+}
+
+static void
+SetKey(NProtoBuf::Message& proto,
+ const NProtoBuf::FieldDescriptor& field,
+ const TString& key) {
+ using namespace google::protobuf;
+ using namespace NProtobufJson;
+
+ const Reflection* reflection = proto.GetReflection();
+ TString result;
+ switch (field.cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ reflection->SetInt32(&proto, &field, FromString<int32>(key));
+ break;
+ case FieldDescriptor::CPPTYPE_INT64:
+ reflection->SetInt64(&proto, &field, FromString<int64>(key));
+ break;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ reflection->SetUInt32(&proto, &field, FromString<uint32>(key));
+ break;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ reflection->SetUInt64(&proto, &field, FromString<uint64>(key));
+ break;
+ case FieldDescriptor::CPPTYPE_BOOL:
+ reflection->SetBool(&proto, &field, FromString<bool>(key));
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ reflection->SetString(&proto, &field, key);
+ break;
+ default:
+ ythrow yexception() << "Unsupported key type.";
+ }
+}
+
+static void
+Json2RepeatedFieldValue(const NJson::TJsonValue& jsonValue,
+ google::protobuf::Message& proto,
+ const google::protobuf::FieldDescriptor& field,
+ const NProtobufJson::TJson2ProtoConfig& config,
+ const google::protobuf::Reflection* reflection,
+ const TMaybe<TString>& key = {}) {
+ using namespace google::protobuf;
+
+ switch (field.cpp_type()) {
+ JSON_TO_FIELD(CPPTYPE_INT32, field.name(), jsonValue, IsInteger, AddInt32, GetInteger);
+ JSON_TO_FIELD(CPPTYPE_INT64, field.name(), jsonValue, IsInteger, AddInt64, GetInteger);
+ JSON_TO_FIELD(CPPTYPE_UINT32, field.name(), jsonValue, IsInteger, AddUInt32, GetInteger);
+ JSON_TO_FIELD(CPPTYPE_UINT64, field.name(), jsonValue, IsUInteger, AddUInt64, GetUInteger);
+ JSON_TO_FIELD(CPPTYPE_DOUBLE, field.name(), jsonValue, IsDouble, AddDouble, GetDouble);
+ JSON_TO_FIELD(CPPTYPE_FLOAT, field.name(), jsonValue, IsDouble, AddFloat, GetDouble);
+ JSON_TO_FIELD(CPPTYPE_BOOL, field.name(), jsonValue, IsBoolean, AddBool, GetBoolean);
+
+ case FieldDescriptor::CPPTYPE_STRING: {
+ JsonString2Field(jsonValue, proto, field, config);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ JsonEnum2Field(jsonValue, proto, field, config);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_MESSAGE: {
+ Message* innerProto = reflection->AddMessage(&proto, &field);
+ Y_ASSERT(!!innerProto);
+ if (key.Defined()) {
+ const FieldDescriptor* keyField = innerProto->GetDescriptor()->FindFieldByName("key");
+ Y_ENSURE(keyField, "Map entry key field not found: " << field.name());
+ SetKey(*innerProto, *keyField, *key);
+
+ const FieldDescriptor* valueField = innerProto->GetDescriptor()->FindFieldByName("value");
+ Y_ENSURE(valueField, "Map entry value field not found.");
+ Json2SingleField(jsonValue, *innerProto, *valueField, config, /*isMapValue=*/true);
+ } else {
+ NProtobufJson::MergeJson2Proto(jsonValue, *innerProto, config);
+ }
+
+ break;
+ }
+
+ default:
+ ythrow yexception() << "Unknown protobuf field type: "
+ << static_cast<int>(field.cpp_type()) << ".";
+ }
+}
+
+static void
+Json2RepeatedField(const NJson::TJsonValue& json,
+ google::protobuf::Message& proto,
+ const google::protobuf::FieldDescriptor& field,
+ const NProtobufJson::TJson2ProtoConfig& config) {
+ using namespace google::protobuf;
+
+ TString name = GetFieldName(field, config);
+ if (!json.Has(name))
+ return;
+
+ const NJson::TJsonValue& fieldJson = json[name];
+ if (fieldJson.GetType() == NJson::JSON_UNDEFINED || fieldJson.GetType() == NJson::JSON_NULL)
+ return;
+
+ bool isMap = fieldJson.GetType() == NJson::JSON_MAP;
+ if (isMap) {
+ if (!config.MapAsObject) {
+ ythrow yexception() << "Map as object representation is not allowed, field: " << field.name();
+ } else if (!field.is_map() && !fieldJson.GetMap().empty()) {
+ ythrow yexception() << "Field " << field.name() << " is not a map.";
+ }
+ }
+
+ if (fieldJson.GetType() != NJson::JSON_ARRAY && !config.MapAsObject && !config.VectorizeScalars && !config.ValueVectorizer) {
+ ythrow yexception() << "JSON field doesn't represent an array for "
+ << name
+ << "(actual type is "
+ << static_cast<int>(fieldJson.GetType()) << ").";
+ }
+
+ const Reflection* reflection = proto.GetReflection();
+ Y_ASSERT(!!reflection);
+
+ if (isMap) {
+ const THashMap<TString, NJson::TJsonValue> jsonMap = fieldJson.GetMap();
+ for (const auto& x : jsonMap) {
+ const TString& key = x.first;
+ const NJson::TJsonValue& jsonValue = x.second;
+ Json2RepeatedFieldValue(jsonValue, proto, field, config, reflection, key);
+ }
+ } else {
+ if (config.ReplaceRepeatedFields) {
+ reflection->ClearField(&proto, &field);
+ }
+ if (fieldJson.GetType() == NJson::JSON_ARRAY) {
+ const NJson::TJsonValue::TArray& jsonArray = fieldJson.GetArray();
+ for (const NJson::TJsonValue& jsonValue : jsonArray) {
+ Json2RepeatedFieldValue(jsonValue, proto, field, config, reflection);
+ }
+ } else if (config.ValueVectorizer) {
+ for (const NJson::TJsonValue& jsonValue : config.ValueVectorizer(fieldJson)) {
+ Json2RepeatedFieldValue(jsonValue, proto, field, config, reflection);
+ }
+ } else if (config.VectorizeScalars) {
+ Json2RepeatedFieldValue(fieldJson, proto, field, config, reflection);
+ }
+ }
+}
+
+namespace NProtobufJson {
+ void MergeJson2Proto(const NJson::TJsonValue& json, google::protobuf::Message& proto, const TJson2ProtoConfig& config) {
+ if (json.IsNull()) {
+ return;
+ }
+
+ Y_ENSURE(json.IsMap(), "expected json map");
+
+ const google::protobuf::Descriptor* descriptor = proto.GetDescriptor();
+ Y_ASSERT(!!descriptor);
+
+ for (int f = 0, endF = descriptor->field_count(); f < endF; ++f) {
+ const google::protobuf::FieldDescriptor* field = descriptor->field(f);
+ Y_ASSERT(!!field);
+
+ if (field->is_repeated()) {
+ Json2RepeatedField(json, proto, *field, config);
+ } else {
+ Json2SingleField(json, proto, *field, config);
+ }
+ }
+
+ if (!config.AllowUnknownFields) {
+ THashMap<TString, bool> knownFields;
+ for (int f = 0, endF = descriptor->field_count(); f < endF; ++f) {
+ const google::protobuf::FieldDescriptor* field = descriptor->field(f);
+ knownFields[GetFieldName(*field, config)] = 1;
+ }
+ for (const auto& f : json.GetMap()) {
+ Y_ENSURE(knownFields.contains(f.first), "unknown field " << f.first);
+ }
+ }
+ }
+
+ void MergeJson2Proto(const TStringBuf& json, google::protobuf::Message& proto, const TJson2ProtoConfig& config) {
+ NJson::TJsonReaderConfig jsonCfg;
+ jsonCfg.DontValidateUtf8 = true;
+ jsonCfg.AllowComments = config.AllowComments;
+
+ NJson::TJsonValue jsonValue;
+ ReadJsonTree(json, &jsonCfg, &jsonValue, /* throwOnError = */ true);
+
+ MergeJson2Proto(jsonValue, proto, config);
+ }
+
+ void Json2Proto(const NJson::TJsonValue& json, google::protobuf::Message& proto, const TJson2ProtoConfig& config) {
+ proto.Clear();
+ MergeJson2Proto(json, proto, config);
+ }
+
+ void Json2Proto(const TStringBuf& json, google::protobuf::Message& proto, const TJson2ProtoConfig& config) {
+ proto.Clear();
+ MergeJson2Proto(json, proto, config);
+ }
+}
diff --git a/library/cpp/protobuf/json/json2proto.h b/library/cpp/protobuf/json/json2proto.h
new file mode 100644
index 0000000000..4c33498dfa
--- /dev/null
+++ b/library/cpp/protobuf/json/json2proto.h
@@ -0,0 +1,222 @@
+#pragma once
+
+#include "string_transform.h"
+#include "name_generator.h"
+
+#include <library/cpp/json/json_reader.h>
+#include <library/cpp/json/json_value.h>
+
+#include <util/stream/input.h>
+#include <util/stream/str.h>
+#include <util/stream/mem.h>
+
+namespace google {
+ namespace protobuf {
+ class Message;
+ }
+}
+
+namespace NProtobufJson {
+ struct TJson2ProtoConfig {
+ using TSelf = TJson2ProtoConfig;
+ using TValueVectorizer = std::function<NJson::TJsonValue::TArray(const NJson::TJsonValue& jsonValue)>;
+
+ enum FldNameMode {
+ FieldNameOriginalCase = 0, // default
+ FieldNameLowerCase,
+ FieldNameUpperCase,
+ FieldNameCamelCase,
+ FieldNameSnakeCase, // ABC -> a_b_c, UserID -> user_i_d
+ FieldNameSnakeCaseDense // ABC -> abc, UserID -> user_id
+ };
+
+ enum EnumValueMode {
+ EnumCaseSensetive = 0, // default
+ EnumCaseInsensetive,
+ EnumSnakeCaseInsensitive
+ };
+
+ TSelf& SetFieldNameMode(FldNameMode mode) {
+ Y_ENSURE(mode == FieldNameOriginalCase || !UseJsonName, "FieldNameMode and UseJsonName are mutually exclusive");
+ FieldNameMode = mode;
+ return *this;
+ }
+
+ TSelf& SetUseJsonName(bool jsonName) {
+ Y_ENSURE(!jsonName || FieldNameMode == FieldNameOriginalCase, "FieldNameMode and UseJsonName are mutually exclusive");
+ UseJsonName = jsonName;
+ return *this;
+ }
+
+ TSelf& AddStringTransform(TStringTransformPtr transform) {
+ StringTransforms.push_back(transform);
+ return *this;
+ }
+
+ TSelf& SetCastFromString(bool cast) {
+ CastFromString = cast;
+ return *this;
+ }
+
+ TSelf& SetDoNotCastEmptyStrings(bool cast) {
+ DoNotCastEmptyStrings = cast;
+ return *this;
+ }
+
+ TSelf& SetCastRobust(bool cast) {
+ CastRobust = cast;
+ return *this;
+ }
+
+ TSelf& SetMapAsObject(bool mapAsObject) {
+ MapAsObject = mapAsObject;
+ return *this;
+ }
+
+ TSelf& SetReplaceRepeatedFields(bool replaceRepeatedFields) {
+ ReplaceRepeatedFields = replaceRepeatedFields;
+ return *this;
+ }
+
+ TSelf& SetNameGenerator(TNameGenerator callback) {
+ NameGenerator = callback;
+ return *this;
+ }
+
+ TSelf& SetEnumValueMode(EnumValueMode enumValueMode) {
+ EnumValueMode = enumValueMode;
+ return *this;
+ }
+
+ TSelf& SetVectorizeScalars(bool vectorizeScalars) {
+ VectorizeScalars = vectorizeScalars;
+ return *this;
+ }
+
+ TSelf& SetAllowComments(bool value) {
+ AllowComments = value;
+ return *this;
+ }
+
+ TSelf& SetAllowUnknownFields(bool value) {
+ AllowUnknownFields = value;
+ return *this;
+ }
+
+ FldNameMode FieldNameMode = FieldNameOriginalCase;
+ bool AllowUnknownFields = true;
+
+ /// Use 'json_name' protobuf option for field name, mutually exclusive
+ /// with FieldNameMode.
+ bool UseJsonName = false;
+
+ /// Transforms will be applied only to string values (== protobuf fields of string / bytes type).
+ TVector<TStringTransformPtr> StringTransforms;
+
+ /// Cast string json values to protobuf field type
+ bool CastFromString = false;
+ /// Skip empty strings, instead casting from string into scalar types.
+ /// I.e. empty string like default value for scalar types.
+ bool DoNotCastEmptyStrings = false;
+ /// Cast all json values to protobuf field types
+ bool CastRobust = false;
+
+ /// Consider map to be an object, otherwise consider it to be an array of key/value objects
+ bool MapAsObject = false;
+
+ /// Throw exception if there is no required fields in json object.
+ bool CheckRequiredFields = true;
+
+ /// Replace repeated fields content during merging
+ bool ReplaceRepeatedFields = false;
+
+ /// Custom field names generator.
+ TNameGenerator NameGenerator = {};
+
+ /// Enum value parsing mode.
+ EnumValueMode EnumValueMode = EnumCaseSensetive;
+
+ /// Append scalars to repeated fields
+ bool VectorizeScalars = false;
+
+ /// Custom spliter non array value to repeated fields.
+ TValueVectorizer ValueVectorizer;
+
+ /// Allow js-style comments (both // and /**/)
+ bool AllowComments = false;
+ };
+
+ /// @throw yexception
+ void MergeJson2Proto(const NJson::TJsonValue& json, google::protobuf::Message& proto,
+ const TJson2ProtoConfig& config = TJson2ProtoConfig());
+
+ /// @throw yexception
+ void MergeJson2Proto(const TStringBuf& json, google::protobuf::Message& proto,
+ const TJson2ProtoConfig& config = TJson2ProtoConfig());
+
+ /// @throw yexception
+ inline void MergeJson2Proto(const TString& json, google::protobuf::Message& proto,
+ const TJson2ProtoConfig& config = TJson2ProtoConfig()) {
+ MergeJson2Proto(TStringBuf(json), proto, config);
+ }
+
+ /// @throw yexception
+ void Json2Proto(const NJson::TJsonValue& json, google::protobuf::Message& proto,
+ const TJson2ProtoConfig& config = TJson2ProtoConfig());
+
+ /// @throw yexception
+ void Json2Proto(const TStringBuf& json, google::protobuf::Message& proto,
+ const TJson2ProtoConfig& config = TJson2ProtoConfig());
+
+ /// @throw yexception
+ inline void Json2Proto(const TString& json, google::protobuf::Message& proto,
+ const TJson2ProtoConfig& config = TJson2ProtoConfig()) {
+ Json2Proto(TStringBuf(json), proto, config);
+ }
+
+ /// @throw yexception
+ inline void Json2Proto(IInputStream& in, google::protobuf::Message& proto,
+ const TJson2ProtoConfig& config = TJson2ProtoConfig()) {
+ Json2Proto(TStringBuf(in.ReadAll()), proto, config);
+ }
+
+ /// @throw yexception
+ template <typename T>
+ T Json2Proto(IInputStream& in, const NJson::TJsonReaderConfig& readerConfig,
+ const TJson2ProtoConfig& config = TJson2ProtoConfig()) {
+ NJson::TJsonValue jsonValue;
+ NJson::ReadJsonTree(&in, &readerConfig, &jsonValue, true);
+ T protoValue;
+ Json2Proto(jsonValue, protoValue, config);
+ return protoValue;
+ }
+
+ /// @throw yexception
+ template <typename T>
+ T Json2Proto(IInputStream& in, const TJson2ProtoConfig& config = TJson2ProtoConfig()) {
+ NJson::TJsonReaderConfig readerConfig;
+ readerConfig.DontValidateUtf8 = true;
+ return Json2Proto<T>(in, readerConfig, config);
+ }
+
+ /// @throw yexception
+ template <typename T>
+ T Json2Proto(const TString& value, const TJson2ProtoConfig& config = TJson2ProtoConfig()) {
+ TStringInput in(value);
+ return Json2Proto<T>(in, config);
+ }
+
+ /// @throw yexception
+ template <typename T>
+ T Json2Proto(const TStringBuf& value, const TJson2ProtoConfig& config = TJson2ProtoConfig()) {
+ TMemoryInput in(value);
+ return Json2Proto<T>(in, config);
+ }
+
+ /// @throw yexception
+ template <typename T>
+ T Json2Proto(const char* ptr, const TJson2ProtoConfig& config = TJson2ProtoConfig()) {
+ return Json2Proto<T>(TStringBuf(ptr), config);
+ }
+
+}
diff --git a/library/cpp/protobuf/json/json_output.h b/library/cpp/protobuf/json/json_output.h
new file mode 100644
index 0000000000..df143af57a
--- /dev/null
+++ b/library/cpp/protobuf/json/json_output.h
@@ -0,0 +1,79 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/generic/strbuf.h>
+
+namespace NProtobufJson {
+ class IJsonOutput {
+ public:
+ template <typename T>
+ IJsonOutput& Write(const T& t) {
+ DoWrite(t);
+ return *this;
+ }
+ IJsonOutput& WriteNull() {
+ DoWriteNull();
+ return *this;
+ }
+
+ IJsonOutput& BeginList() {
+ DoBeginList();
+ return *this;
+ }
+ IJsonOutput& EndList() {
+ DoEndList();
+ return *this;
+ }
+
+ IJsonOutput& BeginObject() {
+ DoBeginObject();
+ return *this;
+ }
+ IJsonOutput& WriteKey(const TStringBuf& key) {
+ DoWriteKey(key);
+ return *this;
+ }
+ IJsonOutput& EndObject() {
+ DoEndObject();
+ return *this;
+ }
+
+ IJsonOutput& WriteRawJson(const TStringBuf& str) {
+ DoWriteRawJson(str);
+ return *this;
+ }
+
+ virtual ~IJsonOutput() {
+ }
+
+ protected:
+ virtual void DoWrite(const TStringBuf& s) = 0;
+ virtual void DoWrite(const TString& s) = 0;
+ virtual void DoWrite(int i) = 0;
+ void DoWrite(long i) {
+ DoWrite(static_cast<long long>(i));
+ }
+ virtual void DoWrite(long long i) = 0;
+ virtual void DoWrite(unsigned int i) = 0;
+ void DoWrite(unsigned long i) {
+ DoWrite(static_cast<unsigned long long>(i));
+ }
+ virtual void DoWrite(unsigned long long i) = 0;
+ virtual void DoWrite(float f) = 0;
+ virtual void DoWrite(double f) = 0;
+ virtual void DoWrite(bool b) = 0;
+ virtual void DoWriteNull() = 0;
+
+ virtual void DoBeginList() = 0;
+ virtual void DoEndList() = 0;
+
+ virtual void DoBeginObject() = 0;
+ virtual void DoWriteKey(const TStringBuf& key) = 0;
+ virtual void DoEndObject() = 0;
+
+ virtual void DoWriteRawJson(const TStringBuf& str) = 0;
+ };
+
+ using TJsonMapOutputPtr = THolder<IJsonOutput>;
+
+}
diff --git a/library/cpp/protobuf/json/json_output_create.cpp b/library/cpp/protobuf/json/json_output_create.cpp
new file mode 100644
index 0000000000..378e4ea65a
--- /dev/null
+++ b/library/cpp/protobuf/json/json_output_create.cpp
@@ -0,0 +1,32 @@
+#include "json_output_create.h"
+
+#include "config.h"
+#include "json_writer_output.h"
+#include "json_value_output.h"
+
+namespace NProtobufJson {
+ TJsonMapOutputPtr CreateJsonMapOutput(IOutputStream& out, const NJson::TJsonWriterConfig& config) {
+ return MakeHolder<TJsonWriterOutput>(&out, config);
+ }
+
+ TJsonMapOutputPtr CreateJsonMapOutput(NJson::TJsonWriter& writer) {
+ return MakeHolder<TBaseJsonWriterOutput>(writer);
+ }
+
+ TJsonMapOutputPtr CreateJsonMapOutput(TString& str, const TProto2JsonConfig& config) {
+ return MakeHolder<TJsonStringWriterOutput>(&str, config);
+ }
+
+ TJsonMapOutputPtr CreateJsonMapOutput(TStringStream& out, const TProto2JsonConfig& config) {
+ return MakeHolder<TJsonWriterOutput>(&out, config);
+ }
+
+ TJsonMapOutputPtr CreateJsonMapOutput(IOutputStream& out, const TProto2JsonConfig& config) {
+ return MakeHolder<TJsonWriterOutput>(&out, config);
+ }
+
+ TJsonMapOutputPtr CreateJsonMapOutput(NJson::TJsonValue& json) {
+ return MakeHolder<TJsonValueOutput>(json);
+ }
+
+}
diff --git a/library/cpp/protobuf/json/json_output_create.h b/library/cpp/protobuf/json/json_output_create.h
new file mode 100644
index 0000000000..ad3889f5e9
--- /dev/null
+++ b/library/cpp/protobuf/json/json_output_create.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "config.h"
+#include "json_output.h"
+
+namespace NJson {
+ class TJsonValue;
+ class TJsonWriter;
+ struct TJsonWriterConfig;
+}
+
+class IOutputStream;
+class TStringStream;
+
+namespace NProtobufJson {
+ TJsonMapOutputPtr CreateJsonMapOutput(IOutputStream& out, const NJson::TJsonWriterConfig& config);
+ TJsonMapOutputPtr CreateJsonMapOutput(NJson::TJsonWriter& writer);
+ TJsonMapOutputPtr CreateJsonMapOutput(IOutputStream& out, const TProto2JsonConfig& config = TProto2JsonConfig());
+ TJsonMapOutputPtr CreateJsonMapOutput(TString& str, const TProto2JsonConfig& config = TProto2JsonConfig());
+ TJsonMapOutputPtr CreateJsonMapOutput(NJson::TJsonValue& json);
+
+}
diff --git a/library/cpp/protobuf/json/json_value_output.cpp b/library/cpp/protobuf/json/json_value_output.cpp
new file mode 100644
index 0000000000..d845cc1c74
--- /dev/null
+++ b/library/cpp/protobuf/json/json_value_output.cpp
@@ -0,0 +1,106 @@
+#include "json_value_output.h"
+
+#include <library/cpp/json/json_reader.h>
+
+namespace NProtobufJson {
+ template <typename T>
+ void TJsonValueOutput::WriteImpl(const T& t) {
+ Y_ASSERT(Context.top().Type == TContext::JSON_ARRAY || Context.top().Type == TContext::JSON_AFTER_KEY);
+
+ if (Context.top().Type == TContext::JSON_AFTER_KEY) {
+ Context.top().Value = t;
+ Context.pop();
+ } else {
+ Context.top().Value.AppendValue(t);
+ }
+ }
+
+ void TJsonValueOutput::DoWrite(const TStringBuf& s) {
+ WriteImpl(s);
+ }
+
+ void TJsonValueOutput::DoWrite(const TString& s) {
+ WriteImpl(s);
+ }
+
+ void TJsonValueOutput::DoWrite(int i) {
+ WriteImpl(i);
+ }
+
+ void TJsonValueOutput::DoWrite(unsigned int i) {
+ WriteImpl(i);
+ }
+
+ void TJsonValueOutput::DoWrite(long long i) {
+ WriteImpl(i);
+ }
+
+ void TJsonValueOutput::DoWrite(unsigned long long i) {
+ WriteImpl(i);
+ }
+
+ void TJsonValueOutput::DoWrite(float f) {
+ WriteImpl(f);
+ }
+
+ void TJsonValueOutput::DoWrite(double f) {
+ WriteImpl(f);
+ }
+
+ void TJsonValueOutput::DoWrite(bool b) {
+ WriteImpl(b);
+ }
+
+ void TJsonValueOutput::DoWriteNull() {
+ WriteImpl(NJson::JSON_NULL);
+ }
+
+ void TJsonValueOutput::DoBeginList() {
+ Y_ASSERT(Context.top().Type == TContext::JSON_ARRAY || Context.top().Type == TContext::JSON_AFTER_KEY);
+
+ if (Context.top().Type == TContext::JSON_AFTER_KEY) {
+ Context.top().Type = TContext::JSON_ARRAY;
+ Context.top().Value.SetType(NJson::JSON_ARRAY);
+ } else {
+ Context.emplace(TContext::JSON_ARRAY, Context.top().Value.AppendValue(NJson::JSON_ARRAY));
+ }
+ }
+
+ void TJsonValueOutput::DoEndList() {
+ Y_ASSERT(Context.top().Type == TContext::JSON_ARRAY);
+ Context.pop();
+ }
+
+ void TJsonValueOutput::DoBeginObject() {
+ Y_ASSERT(Context.top().Type == TContext::JSON_ARRAY || Context.top().Type == TContext::JSON_AFTER_KEY);
+
+ if (Context.top().Type == TContext::JSON_AFTER_KEY) {
+ Context.top().Type = TContext::JSON_MAP;
+ Context.top().Value.SetType(NJson::JSON_MAP);
+ } else {
+ Context.emplace(TContext::JSON_MAP, Context.top().Value.AppendValue(NJson::JSON_MAP));
+ }
+ }
+
+ void TJsonValueOutput::DoWriteKey(const TStringBuf& key) {
+ Y_ASSERT(Context.top().Type == TContext::JSON_MAP);
+ Context.emplace(TContext::JSON_AFTER_KEY, Context.top().Value[key]);
+ }
+
+ void TJsonValueOutput::DoEndObject() {
+ Y_ASSERT(Context.top().Type == TContext::JSON_MAP);
+ Context.pop();
+ }
+
+ void TJsonValueOutput::DoWriteRawJson(const TStringBuf& str) {
+ Y_ASSERT(Context.top().Type == TContext::JSON_ARRAY || Context.top().Type == TContext::JSON_AFTER_KEY);
+
+ if (Context.top().Type == TContext::JSON_AFTER_KEY) {
+ NJson::ReadJsonTree(str, &Context.top().Value);
+ Context.pop();
+ } else {
+ NJson::ReadJsonTree(str, &Context.top().Value.AppendValue(NJson::JSON_UNDEFINED));
+ }
+ }
+
+}
diff --git a/library/cpp/protobuf/json/json_value_output.h b/library/cpp/protobuf/json/json_value_output.h
new file mode 100644
index 0000000000..3fc6ff2ab0
--- /dev/null
+++ b/library/cpp/protobuf/json/json_value_output.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include "json_output.h"
+
+#include <library/cpp/json/writer/json_value.h>
+
+#include <util/generic/stack.h>
+
+namespace NProtobufJson {
+ class TJsonValueOutput: public IJsonOutput {
+ public:
+ TJsonValueOutput(NJson::TJsonValue& value)
+ : Root(value)
+ {
+ Context.emplace(TContext::JSON_AFTER_KEY, Root);
+ }
+
+ void DoWrite(const TStringBuf& s) override;
+ void DoWrite(const TString& s) override;
+ void DoWrite(int i) override;
+ void DoWrite(unsigned int i) override;
+ void DoWrite(long long i) override;
+ void DoWrite(unsigned long long i) override;
+ void DoWrite(float f) override;
+ void DoWrite(double f) override;
+ void DoWrite(bool b) override;
+ void DoWriteNull() override;
+
+ void DoBeginList() override;
+ void DoEndList() override;
+
+ void DoBeginObject() override;
+ void DoWriteKey(const TStringBuf& key) override;
+ void DoEndObject() override;
+
+ void DoWriteRawJson(const TStringBuf& str) override;
+
+ private:
+ template <typename T>
+ void WriteImpl(const T& t);
+
+ struct TContext {
+ enum EType {
+ JSON_MAP,
+ JSON_ARRAY,
+ JSON_AFTER_KEY,
+ };
+
+ TContext(EType type, NJson::TJsonValue& value)
+ : Type(type)
+ , Value(value)
+ {
+ }
+
+ EType Type;
+ NJson::TJsonValue& Value;
+ };
+
+ NJson::TJsonValue& Root;
+ TStack<TContext, TVector<TContext>> Context;
+ };
+
+}
diff --git a/library/cpp/protobuf/json/json_writer_output.cpp b/library/cpp/protobuf/json/json_writer_output.cpp
new file mode 100644
index 0000000000..288f645bab
--- /dev/null
+++ b/library/cpp/protobuf/json/json_writer_output.cpp
@@ -0,0 +1,22 @@
+#include "json_writer_output.h"
+
+namespace NProtobufJson {
+ NJson::TJsonWriterConfig TJsonWriterOutput::CreateJsonWriterConfig(const TProto2JsonConfig& config) {
+ NJson::TJsonWriterConfig jsonConfig;
+ jsonConfig.FormatOutput = config.FormatOutput;
+ jsonConfig.SortKeys = false;
+ jsonConfig.ValidateUtf8 = false;
+ jsonConfig.DontEscapeStrings = false;
+ jsonConfig.WriteNanAsString = config.WriteNanAsString;
+
+ for (size_t i = 0; i < config.StringTransforms.size(); ++i) {
+ Y_ASSERT(config.StringTransforms[i]);
+ if (config.StringTransforms[i]->GetType() == IStringTransform::EscapeTransform) {
+ jsonConfig.DontEscapeStrings = true;
+ break;
+ }
+ }
+ return jsonConfig;
+ }
+
+}
diff --git a/library/cpp/protobuf/json/json_writer_output.h b/library/cpp/protobuf/json/json_writer_output.h
new file mode 100644
index 0000000000..3d8a2daa56
--- /dev/null
+++ b/library/cpp/protobuf/json/json_writer_output.h
@@ -0,0 +1,103 @@
+#pragma once
+
+#include "json_output.h"
+#include "config.h"
+
+#include <library/cpp/json/json_writer.h>
+
+#include <util/string/builder.h>
+#include <util/generic/store_policy.h>
+
+namespace NProtobufJson {
+ class TBaseJsonWriterOutput: public IJsonOutput {
+ public:
+ TBaseJsonWriterOutput(NJson::TJsonWriter& writer)
+ : Writer(writer)
+ {
+ }
+
+ private:
+ void DoWrite(int i) override {
+ Writer.Write(i);
+ }
+ void DoWrite(unsigned int i) override {
+ Writer.Write(i);
+ }
+ void DoWrite(long long i) override {
+ Writer.Write(i);
+ }
+ void DoWrite(unsigned long long i) override {
+ Writer.Write(i);
+ }
+ void DoWrite(float f) override {
+ Writer.Write(f);
+ }
+ void DoWrite(double f) override {
+ Writer.Write(f);
+ }
+ void DoWrite(bool b) override {
+ Writer.Write(b);
+ }
+ void DoWriteNull() override {
+ Writer.WriteNull();
+ }
+ void DoWrite(const TStringBuf& s) override {
+ Writer.Write(s);
+ }
+ void DoWrite(const TString& s) override {
+ Writer.Write(s);
+ }
+
+ void DoBeginList() override {
+ Writer.OpenArray();
+ }
+ void DoEndList() override {
+ Writer.CloseArray();
+ }
+
+ void DoBeginObject() override {
+ Writer.OpenMap();
+ }
+ void DoWriteKey(const TStringBuf& key) override {
+ Writer.Write(key);
+ }
+ void DoEndObject() override {
+ Writer.CloseMap();
+ }
+
+ void DoWriteRawJson(const TStringBuf& str) override {
+ Writer.UnsafeWrite(str);
+ }
+
+ NJson::TJsonWriter& Writer;
+ };
+
+ class TJsonWriterOutput: public TEmbedPolicy<NJson::TJsonWriter>, public TBaseJsonWriterOutput {
+ public:
+ TJsonWriterOutput(IOutputStream* outputStream, const NJson::TJsonWriterConfig& cfg)
+ : TEmbedPolicy<NJson::TJsonWriter>(outputStream, cfg)
+ , TBaseJsonWriterOutput(*Ptr())
+ {
+ }
+
+ TJsonWriterOutput(IOutputStream* outputStream, const TProto2JsonConfig& cfg)
+ : TEmbedPolicy<NJson::TJsonWriter>(outputStream, CreateJsonWriterConfig(cfg))
+ , TBaseJsonWriterOutput(*Ptr())
+ {
+ }
+
+ private:
+ static NJson::TJsonWriterConfig CreateJsonWriterConfig(const TProto2JsonConfig& cfg);
+ };
+
+ class TJsonStringWriterOutput: public TEmbedPolicy<TStringOutput>, public TJsonWriterOutput {
+ public:
+ template <typename TConfig>
+ TJsonStringWriterOutput(TString* str, const TConfig& cfg)
+ : TEmbedPolicy<TStringOutput>(*str)
+ , TJsonWriterOutput(TEmbedPolicy<TStringOutput>::Ptr(), cfg)
+ {
+ }
+ };
+
+}
diff --git a/library/cpp/protobuf/json/name_generator.cpp b/library/cpp/protobuf/json/name_generator.cpp
new file mode 100644
index 0000000000..c1fb421175
--- /dev/null
+++ b/library/cpp/protobuf/json/name_generator.cpp
@@ -0,0 +1 @@
+#include "name_generator.h"
diff --git a/library/cpp/protobuf/json/name_generator.h b/library/cpp/protobuf/json/name_generator.h
new file mode 100644
index 0000000000..2b5361bee2
--- /dev/null
+++ b/library/cpp/protobuf/json/name_generator.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <util/generic/string.h>
+
+#include <functional>
+
+namespace google {
+ namespace protobuf {
+ class FieldDescriptor;
+ class EnumValueDescriptor;
+ }
+}
+
+namespace NProtobufJson {
+ using TNameGenerator = std::function<TString(const google::protobuf::FieldDescriptor&)>;
+ using TEnumValueGenerator = std::function<TString(const google::protobuf::EnumValueDescriptor&)>;
+
+}
diff --git a/library/cpp/protobuf/json/proto2json.cpp b/library/cpp/protobuf/json/proto2json.cpp
new file mode 100644
index 0000000000..3d76a91686
--- /dev/null
+++ b/library/cpp/protobuf/json/proto2json.cpp
@@ -0,0 +1,56 @@
+#include "proto2json.h"
+
+#include "json_output_create.h"
+#include "proto2json_printer.h"
+
+#include <library/cpp/json/json_reader.h>
+#include <library/cpp/json/json_value.h>
+#include <library/cpp/json/json_writer.h>
+
+#include <util/generic/ptr.h>
+#include <util/generic/strbuf.h>
+#include <util/stream/output.h>
+#include <util/stream/str.h>
+#include <util/system/yassert.h>
+
+namespace NProtobufJson {
+ void Proto2Json(const NProtoBuf::Message& proto, IJsonOutput& jsonOutput,
+ const TProto2JsonConfig& config, bool closeMap) {
+ TProto2JsonPrinter printer(config);
+ printer.Print(proto, jsonOutput, closeMap);
+ }
+
+ void Proto2Json(const NProtoBuf::Message& proto, NJson::TJsonValue& json,
+ const TProto2JsonConfig& config) {
+ Proto2Json(proto, *CreateJsonMapOutput(json), config);
+ }
+
+ void Proto2Json(const NProtoBuf::Message& proto, NJson::TJsonWriter& writer,
+ const TProto2JsonConfig& config) {
+ Proto2Json(proto, *CreateJsonMapOutput(writer), config);
+ writer.Flush();
+ }
+
+ void Proto2Json(const NProtoBuf::Message& proto, IOutputStream& out,
+ const TProto2JsonConfig& config) {
+ Proto2Json(proto, *CreateJsonMapOutput(out, config), config);
+ }
+
+ void Proto2Json(const NProtoBuf::Message& proto, TStringStream& out,
+ const TProto2JsonConfig& config) {
+ Proto2Json(proto, *CreateJsonMapOutput(out, config), config);
+ }
+
+ void Proto2Json(const NProtoBuf::Message& proto, TString& str,
+ const TProto2JsonConfig& config) {
+ Proto2Json(proto, *CreateJsonMapOutput(str, config), config);
+ }
+
+ TString Proto2Json(const ::NProtoBuf::Message& proto,
+ const TProto2JsonConfig& config) {
+ TString res;
+ Proto2Json(proto, res, config);
+ return res;
+ }
+
+}
diff --git a/library/cpp/protobuf/json/proto2json.h b/library/cpp/protobuf/json/proto2json.h
new file mode 100644
index 0000000000..89a1781a40
--- /dev/null
+++ b/library/cpp/protobuf/json/proto2json.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include "config.h"
+#include "json_output.h"
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/message.h>
+
+#include <util/generic/fwd.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+#include <util/stream/str.h>
+
+#include <functional>
+
+namespace NJson {
+ class TJsonValue;
+ class TJsonWriter;
+}
+
+class IOutputStream;
+class TStringStream;
+
+namespace NProtobufJson {
+ void Proto2Json(const NProtoBuf::Message& proto, IJsonOutput& jsonOutput,
+ const TProto2JsonConfig& config = TProto2JsonConfig(), bool closeMap = true);
+
+ void Proto2Json(const NProtoBuf::Message& proto, NJson::TJsonWriter& writer,
+ const TProto2JsonConfig& config = TProto2JsonConfig());
+
+ /// @throw yexception
+ void Proto2Json(const NProtoBuf::Message& proto, NJson::TJsonValue& json,
+ const TProto2JsonConfig& config = TProto2JsonConfig());
+
+ /// @throw yexception
+ void Proto2Json(const NProtoBuf::Message& proto, IOutputStream& out,
+ const TProto2JsonConfig& config);
+ // Generated code shortcut
+ template <class T>
+ inline void Proto2Json(const T& proto, IOutputStream& out) {
+ out << proto.AsJSON();
+ }
+
+ // TStringStream deserves a special overload as its operator TString() would cause ambiguity
+ /// @throw yexception
+ void Proto2Json(const NProtoBuf::Message& proto, TStringStream& out,
+ const TProto2JsonConfig& config);
+ // Generated code shortcut
+ template <class T>
+ inline void Proto2Json(const T& proto, TStringStream& out) {
+ out << proto.AsJSON();
+ }
+
+ /// @throw yexception
+ void Proto2Json(const NProtoBuf::Message& proto, TString& str,
+ const TProto2JsonConfig& config);
+ // Generated code shortcut
+ template <class T>
+ inline void Proto2Json(const T& proto, TString& str) {
+ str.clear();
+ TStringOutput out(str);
+ out << proto.AsJSON();
+ }
+
+ /// @throw yexception
+ TString Proto2Json(const NProtoBuf::Message& proto,
+ const TProto2JsonConfig& config);
+ // Returns incorrect result if proto contains another NProtoBuf::Message
+ // Generated code shortcut
+ template <class T>
+ inline TString Proto2Json(const T& proto) {
+ TString result;
+ Proto2Json(proto, result);
+ return result;
+ }
+
+}
diff --git a/library/cpp/protobuf/json/proto2json_printer.cpp b/library/cpp/protobuf/json/proto2json_printer.cpp
new file mode 100644
index 0000000000..6123eab0f2
--- /dev/null
+++ b/library/cpp/protobuf/json/proto2json_printer.cpp
@@ -0,0 +1,517 @@
+#include "proto2json_printer.h"
+#include "config.h"
+#include "util.h"
+
+#include <util/generic/yexception.h>
+#include <util/string/ascii.h>
+#include <util/string/cast.h>
+
+namespace NProtobufJson {
+ using namespace NProtoBuf;
+
+ class TJsonKeyBuilder {
+ public:
+ TJsonKeyBuilder(const FieldDescriptor& field, const TProto2JsonConfig& config, TString& tmpBuf)
+ : NewKeyStr(tmpBuf)
+ {
+ if (config.NameGenerator) {
+ NewKeyStr = config.NameGenerator(field);
+ NewKeyBuf = NewKeyStr;
+ return;
+ }
+
+ if (config.UseJsonName) {
+ Y_ASSERT(!field.json_name().empty());
+ NewKeyStr = field.json_name();
+ if (!field.has_json_name() && !NewKeyStr.empty()) {
+ // FIXME: https://st.yandex-team.ru/CONTRIB-139
+ NewKeyStr[0] = AsciiToLower(NewKeyStr[0]);
+ }
+ NewKeyBuf = NewKeyStr;
+ return;
+ }
+
+ switch (config.FieldNameMode) {
+ case TProto2JsonConfig::FieldNameOriginalCase: {
+ NewKeyBuf = field.name();
+ break;
+ }
+
+ case TProto2JsonConfig::FieldNameLowerCase: {
+ NewKeyStr = field.name();
+ NewKeyStr.to_lower();
+ NewKeyBuf = NewKeyStr;
+ break;
+ }
+
+ case TProto2JsonConfig::FieldNameUpperCase: {
+ NewKeyStr = field.name();
+ NewKeyStr.to_upper();
+ NewKeyBuf = NewKeyStr;
+ break;
+ }
+
+ case TProto2JsonConfig::FieldNameCamelCase: {
+ NewKeyStr = field.name();
+ if (!NewKeyStr.empty()) {
+ NewKeyStr[0] = AsciiToLower(NewKeyStr[0]);
+ }
+ NewKeyBuf = NewKeyStr;
+ break;
+ }
+
+ case TProto2JsonConfig::FieldNameSnakeCase: {
+ NewKeyStr = field.name();
+ ToSnakeCase(&NewKeyStr);
+ NewKeyBuf = NewKeyStr;
+ break;
+ }
+
+ case TProto2JsonConfig::FieldNameSnakeCaseDense: {
+ NewKeyStr = field.name();
+ ToSnakeCaseDense(&NewKeyStr);
+ NewKeyBuf = NewKeyStr;
+ break;
+ }
+
+ default:
+ Y_VERIFY_DEBUG(false, "Unknown FieldNameMode.");
+ }
+ }
+
+ const TStringBuf& GetKey() const {
+ return NewKeyBuf;
+ }
+
+ private:
+ TStringBuf NewKeyBuf;
+ TString& NewKeyStr;
+ };
+
+ TProto2JsonPrinter::TProto2JsonPrinter(const TProto2JsonConfig& cfg)
+ : Config(cfg)
+ {
+ }
+
+ TProto2JsonPrinter::~TProto2JsonPrinter() {
+ }
+
+ TStringBuf TProto2JsonPrinter::MakeKey(const FieldDescriptor& field) {
+ return TJsonKeyBuilder(field, GetConfig(), TmpBuf).GetKey();
+ }
+
+ template <bool InMapContext, typename T>
+ std::enable_if_t<InMapContext, void> WriteWithMaybeEmptyKey(IJsonOutput& json, const TStringBuf& key, const T& value) {
+ json.WriteKey(key).Write(value);
+ }
+
+ template <bool InMapContext, typename T>
+ std::enable_if_t<!InMapContext, void> WriteWithMaybeEmptyKey(IJsonOutput& array, const TStringBuf& key, const T& value) {
+ Y_ASSERT(!key);
+ array.Write(value);
+ }
+
+ template <bool InMapContext>
+ void TProto2JsonPrinter::PrintStringValue(const FieldDescriptor& field,
+ const TStringBuf& key, const TString& value,
+ IJsonOutput& json) {
+ if (!GetConfig().StringTransforms.empty()) {
+ TString tmpBuf = value;
+ for (const TStringTransformPtr& stringTransform : GetConfig().StringTransforms) {
+ Y_ASSERT(stringTransform);
+ if (stringTransform) {
+ if (field.type() == FieldDescriptor::TYPE_BYTES)
+ stringTransform->TransformBytes(tmpBuf);
+ else
+ stringTransform->Transform(tmpBuf);
+ }
+ }
+ WriteWithMaybeEmptyKey<InMapContext>(json, key, tmpBuf);
+ } else {
+ WriteWithMaybeEmptyKey<InMapContext>(json, key, value);
+ }
+ }
+
+ template <bool InMapContext>
+ void TProto2JsonPrinter::PrintEnumValue(const TStringBuf& key,
+ const EnumValueDescriptor* value,
+ IJsonOutput& json) {
+ if (Config.EnumValueGenerator) {
+ WriteWithMaybeEmptyKey<InMapContext>(json, key, Config.EnumValueGenerator(*value));
+ return;
+ }
+
+ switch (GetConfig().EnumMode) {
+ case TProto2JsonConfig::EnumNumber: {
+ WriteWithMaybeEmptyKey<InMapContext>(json, key, value->number());
+ break;
+ }
+
+ case TProto2JsonConfig::EnumName: {
+ WriteWithMaybeEmptyKey<InMapContext>(json, key, value->name());
+ break;
+ }
+
+ case TProto2JsonConfig::EnumFullName: {
+ WriteWithMaybeEmptyKey<InMapContext>(json, key, value->full_name());
+ break;
+ }
+
+ case TProto2JsonConfig::EnumNameLowerCase: {
+ TString newName = value->name();
+ newName.to_lower();
+ WriteWithMaybeEmptyKey<InMapContext>(json, key, newName);
+ break;
+ }
+
+ case TProto2JsonConfig::EnumFullNameLowerCase: {
+ TString newName = value->full_name();
+ newName.to_lower();
+ WriteWithMaybeEmptyKey<InMapContext>(json, key, newName);
+ break;
+ }
+
+ default:
+ Y_VERIFY_DEBUG(false, "Unknown EnumMode.");
+ }
+ }
+
+ void TProto2JsonPrinter::PrintSingleField(const Message& proto,
+ const FieldDescriptor& field,
+ IJsonOutput& json,
+ TStringBuf key) {
+ Y_VERIFY(!field.is_repeated(), "field is repeated.");
+
+ if (!key) {
+ key = MakeKey(field);
+ }
+
+#define FIELD_TO_JSON(EProtoCppType, ProtoGet) \
+ case FieldDescriptor::EProtoCppType: { \
+ json.WriteKey(key).Write(reflection->ProtoGet(proto, &field)); \
+ break; \
+ }
+
+#define INT_FIELD_TO_JSON(EProtoCppType, ProtoGet) \
+ case FieldDescriptor::EProtoCppType: { \
+ const auto value = reflection->ProtoGet(proto, &field); \
+ if (NeedStringifyNumber(value)) { \
+ json.WriteKey(key).Write(ToString(value)); \
+ } else { \
+ json.WriteKey(key).Write(value); \
+ } \
+ break; \
+ }
+
+ const Reflection* reflection = proto.GetReflection();
+
+ bool shouldPrintField = reflection->HasField(proto, &field);
+ if (!shouldPrintField && GetConfig().MissingSingleKeyMode == TProto2JsonConfig::MissingKeyExplicitDefaultThrowRequired) {
+ if (field.has_default_value()) {
+ shouldPrintField = true;
+ } else if (field.is_required()) {
+ ythrow yexception() << "Empty required protobuf field: "
+ << field.full_name() << ".";
+ }
+ }
+ shouldPrintField = shouldPrintField || GetConfig().MissingSingleKeyMode == TProto2JsonConfig::MissingKeyDefault;
+
+ if (shouldPrintField) {
+ switch (field.cpp_type()) {
+ INT_FIELD_TO_JSON(CPPTYPE_INT32, GetInt32);
+ INT_FIELD_TO_JSON(CPPTYPE_INT64, GetInt64);
+ INT_FIELD_TO_JSON(CPPTYPE_UINT32, GetUInt32);
+ INT_FIELD_TO_JSON(CPPTYPE_UINT64, GetUInt64);
+ FIELD_TO_JSON(CPPTYPE_DOUBLE, GetDouble);
+ FIELD_TO_JSON(CPPTYPE_FLOAT, GetFloat);
+ FIELD_TO_JSON(CPPTYPE_BOOL, GetBool);
+
+ case FieldDescriptor::CPPTYPE_MESSAGE: {
+ json.WriteKey(key);
+ Print(reflection->GetMessage(proto, &field), json);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ PrintEnumValue<true>(key, reflection->GetEnum(proto, &field), json);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_STRING: {
+ TString scratch;
+ const TString& value = reflection->GetStringReference(proto, &field, &scratch);
+ PrintStringValue<true>(field, key, value, json);
+ break;
+ }
+
+ default:
+ ythrow yexception() << "Unknown protobuf field type: "
+ << static_cast<int>(field.cpp_type()) << ".";
+ }
+ } else {
+ switch (GetConfig().MissingSingleKeyMode) {
+ case TProto2JsonConfig::MissingKeyNull: {
+ json.WriteKey(key).WriteNull();
+ break;
+ }
+
+ case TProto2JsonConfig::MissingKeySkip:
+ case TProto2JsonConfig::MissingKeyExplicitDefaultThrowRequired:
+ default:
+ break;
+ }
+ }
+#undef FIELD_TO_JSON
+ }
+
+ void TProto2JsonPrinter::PrintRepeatedField(const Message& proto,
+ const FieldDescriptor& field,
+ IJsonOutput& json,
+ TStringBuf key) {
+ Y_VERIFY(field.is_repeated(), "field isn't repeated.");
+
+ const bool isMap = field.is_map() && GetConfig().MapAsObject;
+ if (!key) {
+ key = MakeKey(field);
+ }
+
+#define REPEATED_FIELD_TO_JSON(EProtoCppType, ProtoGet) \
+ case FieldDescriptor::EProtoCppType: { \
+ for (size_t i = 0, endI = reflection->FieldSize(proto, &field); i < endI; ++i) \
+ json.Write(reflection->ProtoGet(proto, &field, i)); \
+ break; \
+ }
+
+ const Reflection* reflection = proto.GetReflection();
+
+ if (reflection->FieldSize(proto, &field) > 0) {
+ json.WriteKey(key);
+ if (isMap) {
+ json.BeginObject();
+ } else {
+ json.BeginList();
+ }
+
+ switch (field.cpp_type()) {
+ REPEATED_FIELD_TO_JSON(CPPTYPE_INT32, GetRepeatedInt32);
+ REPEATED_FIELD_TO_JSON(CPPTYPE_INT64, GetRepeatedInt64);
+ REPEATED_FIELD_TO_JSON(CPPTYPE_UINT32, GetRepeatedUInt32);
+ REPEATED_FIELD_TO_JSON(CPPTYPE_UINT64, GetRepeatedUInt64);
+ REPEATED_FIELD_TO_JSON(CPPTYPE_DOUBLE, GetRepeatedDouble);
+ REPEATED_FIELD_TO_JSON(CPPTYPE_FLOAT, GetRepeatedFloat);
+ REPEATED_FIELD_TO_JSON(CPPTYPE_BOOL, GetRepeatedBool);
+
+ case FieldDescriptor::CPPTYPE_MESSAGE: {
+ if (isMap) {
+ for (size_t i = 0, endI = reflection->FieldSize(proto, &field); i < endI; ++i) {
+ PrintKeyValue(reflection->GetRepeatedMessage(proto, &field, i), json);
+ }
+ } else {
+ for (size_t i = 0, endI = reflection->FieldSize(proto, &field); i < endI; ++i) {
+ Print(reflection->GetRepeatedMessage(proto, &field, i), json);
+ }
+ }
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ for (int i = 0, endI = reflection->FieldSize(proto, &field); i < endI; ++i)
+ PrintEnumValue<false>(TStringBuf(), reflection->GetRepeatedEnum(proto, &field, i), json);
+ break;
+ }
+
+ case FieldDescriptor::CPPTYPE_STRING: {
+ TString scratch;
+ for (int i = 0, endI = reflection->FieldSize(proto, &field); i < endI; ++i) {
+ const TString& value =
+ reflection->GetRepeatedStringReference(proto, &field, i, &scratch);
+ PrintStringValue<false>(field, TStringBuf(), value, json);
+ }
+ break;
+ }
+
+ default:
+ ythrow yexception() << "Unknown protobuf field type: "
+ << static_cast<int>(field.cpp_type()) << ".";
+ }
+
+ if (isMap) {
+ json.EndObject();
+ } else {
+ json.EndList();
+ }
+ } else {
+ switch (GetConfig().MissingRepeatedKeyMode) {
+ case TProto2JsonConfig::MissingKeyNull: {
+ json.WriteKey(key).WriteNull();
+ break;
+ }
+
+ case TProto2JsonConfig::MissingKeyDefault: {
+ json.WriteKey(key);
+ if (isMap) {
+ json.BeginObject().EndObject();
+ } else {
+ json.BeginList().EndList();
+ }
+ break;
+ }
+
+ case TProto2JsonConfig::MissingKeySkip:
+ case TProto2JsonConfig::MissingKeyExplicitDefaultThrowRequired:
+ default:
+ break;
+ }
+ }
+
+#undef REPEATED_FIELD_TO_JSON
+ }
+
+ void TProto2JsonPrinter::PrintKeyValue(const NProtoBuf::Message& proto,
+ IJsonOutput& json) {
+ const FieldDescriptor* keyField = proto.GetDescriptor()->FindFieldByName("key");
+ Y_VERIFY(keyField, "Map entry key field not found.");
+ TString key = MakeKey(proto, *keyField);
+ const FieldDescriptor* valueField = proto.GetDescriptor()->FindFieldByName("value");
+ Y_VERIFY(valueField, "Map entry value field not found.");
+ PrintField(proto, *valueField, json, key);
+ }
+
+ TString TProto2JsonPrinter::MakeKey(const NProtoBuf::Message& proto,
+ const NProtoBuf::FieldDescriptor& field) {
+ const Reflection* reflection = proto.GetReflection();
+ TString result;
+ switch (field.cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ result = ToString(reflection->GetInt32(proto, &field));
+ break;
+ case FieldDescriptor::CPPTYPE_INT64:
+ result = ToString(reflection->GetInt64(proto, &field));
+ break;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ result = ToString(reflection->GetUInt32(proto, &field));
+ break;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ result = ToString(reflection->GetUInt64(proto, &field));
+ break;
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ result = ToString(reflection->GetDouble(proto, &field));
+ break;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ result = ToString(reflection->GetFloat(proto, &field));
+ break;
+ case FieldDescriptor::CPPTYPE_BOOL:
+ result = ToString(reflection->GetBool(proto, &field));
+ break;
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ const EnumValueDescriptor* value = reflection->GetEnum(proto, &field);
+ switch (GetConfig().EnumMode) {
+ case TProto2JsonConfig::EnumNumber:
+ result = ToString(value->number());
+ break;
+ case TProto2JsonConfig::EnumName:
+ result = value->name();
+ break;
+ case TProto2JsonConfig::EnumFullName:
+ result = value->full_name();
+ break;
+ case TProto2JsonConfig::EnumNameLowerCase:
+ result = value->name();
+ result.to_lower();
+ break;
+ case TProto2JsonConfig::EnumFullNameLowerCase:
+ result = value->full_name();
+ result.to_lower();
+ break;
+ default:
+ ythrow yexception() << "Unsupported enum mode.";
+ }
+ break;
+ }
+ case FieldDescriptor::CPPTYPE_STRING:
+ result = reflection->GetString(proto, &field);
+ break;
+ default:
+ ythrow yexception() << "Unsupported key type.";
+ }
+
+ return result;
+ }
+
+ void TProto2JsonPrinter::PrintField(const Message& proto,
+ const FieldDescriptor& field,
+ IJsonOutput& json,
+ const TStringBuf key) {
+
+
+ if (field.is_repeated())
+ PrintRepeatedField(proto, field, json, key);
+ else
+ PrintSingleField(proto, field, json, key);
+ }
+
+ void TProto2JsonPrinter::Print(const Message& proto, IJsonOutput& json, bool closeMap) {
+ const Descriptor* descriptor = proto.GetDescriptor();
+ Y_ASSERT(descriptor);
+
+ json.BeginObject();
+
+ // Iterate over all non-extension fields
+ for (int f = 0, endF = descriptor->field_count(); f < endF; ++f) {
+ const FieldDescriptor* field = descriptor->field(f);
+ Y_ASSERT(field);
+ PrintField(proto, *field, json);
+ }
+
+ // Check extensions via ListFields
+ std::vector<const FieldDescriptor*> fields;
+ auto* ref = proto.GetReflection();
+ ref->ListFields(proto, &fields);
+
+ for (const FieldDescriptor* field : fields) {
+ Y_ASSERT(field);
+ if (field->is_extension()) {
+ switch (GetConfig().ExtensionFieldNameMode) {
+ case TProto2JsonConfig::ExtFldNameFull:
+ PrintField(proto, *field, json, field->full_name());
+ break;
+ case TProto2JsonConfig::ExtFldNameShort:
+ PrintField(proto, *field, json);
+ break;
+ }
+ }
+ }
+
+ if (closeMap) {
+ json.EndObject();
+ }
+ }
+
+ template <class T, class U>
+ std::enable_if_t<!std::is_unsigned<T>::value, bool> ValueInRange(T value, U range) {
+ return value >= -range && value <= range;
+ }
+
+ template <class T, class U>
+ std::enable_if_t<std::is_unsigned<T>::value, bool> ValueInRange(T value, U range) {
+ return value <= (std::make_unsigned_t<U>)(range);
+ }
+
+ template <class T>
+ bool TProto2JsonPrinter::NeedStringifyNumber(T value) const {
+ constexpr long SAFE_INTEGER_RANGE_FLOAT = 16777216;
+ constexpr long long SAFE_INTEGER_RANGE_DOUBLE = 9007199254740992;
+
+ switch (GetConfig().StringifyLongNumbers) {
+ case TProto2JsonConfig::StringifyLongNumbersNever:
+ return false;
+ case TProto2JsonConfig::StringifyLongNumbersForFloat:
+ return !ValueInRange(value, SAFE_INTEGER_RANGE_FLOAT);
+ case TProto2JsonConfig::StringifyLongNumbersForDouble:
+ return !ValueInRange(value, SAFE_INTEGER_RANGE_DOUBLE);
+ }
+
+ return false;
+ }
+
+}
diff --git a/library/cpp/protobuf/json/proto2json_printer.h b/library/cpp/protobuf/json/proto2json_printer.h
new file mode 100644
index 0000000000..9dc5aa86c6
--- /dev/null
+++ b/library/cpp/protobuf/json/proto2json_printer.h
@@ -0,0 +1,68 @@
+#pragma once
+
+#include "json_output.h"
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/message.h>
+
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+
+namespace NProtobufJson {
+ struct TProto2JsonConfig;
+
+ class TProto2JsonPrinter {
+ public:
+ TProto2JsonPrinter(const TProto2JsonConfig& config);
+ virtual ~TProto2JsonPrinter();
+
+ virtual void Print(const NProtoBuf::Message& proto, IJsonOutput& json, bool closeMap = true);
+
+ virtual const TProto2JsonConfig& GetConfig() const {
+ return Config;
+ }
+
+ protected:
+ virtual TStringBuf MakeKey(const NProtoBuf::FieldDescriptor& field);
+
+ virtual void PrintField(const NProtoBuf::Message& proto,
+ const NProtoBuf::FieldDescriptor& field,
+ IJsonOutput& json,
+ TStringBuf key = {});
+
+ void PrintRepeatedField(const NProtoBuf::Message& proto,
+ const NProtoBuf::FieldDescriptor& field,
+ IJsonOutput& json,
+ TStringBuf key = {});
+
+ void PrintSingleField(const NProtoBuf::Message& proto,
+ const NProtoBuf::FieldDescriptor& field,
+ IJsonOutput& json,
+ TStringBuf key = {});
+
+ void PrintKeyValue(const NProtoBuf::Message& proto,
+ IJsonOutput& json);
+
+ TString MakeKey(const NProtoBuf::Message& proto,
+ const NProtoBuf::FieldDescriptor& field);
+
+ template <bool InMapContext>
+ void PrintEnumValue(const TStringBuf& key,
+ const NProtoBuf::EnumValueDescriptor* value,
+ IJsonOutput& json);
+
+ template <bool InMapContext>
+ void PrintStringValue(const NProtoBuf::FieldDescriptor& field,
+ const TStringBuf& key, const TString& value,
+ IJsonOutput& json);
+
+ template <class T>
+ bool NeedStringifyNumber(T value) const;
+
+ protected:
+ const TProto2JsonConfig& Config;
+ TString TmpBuf;
+ };
+
+}
diff --git a/library/cpp/protobuf/json/string_transform.cpp b/library/cpp/protobuf/json/string_transform.cpp
new file mode 100644
index 0000000000..7c42daa677
--- /dev/null
+++ b/library/cpp/protobuf/json/string_transform.cpp
@@ -0,0 +1,64 @@
+#include "string_transform.h"
+
+#include <google/protobuf/stubs/strutil.h>
+
+#include <library/cpp/string_utils/base64/base64.h>
+
+namespace NProtobufJson {
+ void TCEscapeTransform::Transform(TString& str) const {
+ str = google::protobuf::CEscape(str);
+ }
+
+ void TSafeUtf8CEscapeTransform::Transform(TString& str) const {
+ str = google::protobuf::strings::Utf8SafeCEscape(str);
+ }
+
+ void TDoubleEscapeTransform::Transform(TString& str) const {
+ TString escaped = google::protobuf::CEscape(str);
+ str = "";
+ for (char* it = escaped.begin(); *it; ++it) {
+ if (*it == '\\' || *it == '\"')
+ str += "\\";
+ str += *it;
+ }
+ }
+
+ void TDoubleUnescapeTransform::Transform(TString& str) const {
+ str = google::protobuf::UnescapeCEscapeString(Unescape(str));
+ }
+
+ TString TDoubleUnescapeTransform::Unescape(const TString& str) const {
+ if (str.empty()) {
+ return str;
+ }
+
+ TString result;
+ result.reserve(str.size());
+
+ char prev = str[0];
+ bool doneOutput = true;
+ for (const char* it = str.c_str() + 1; *it; ++it) {
+ if (doneOutput && prev == '\\' && (*it == '\\' || *it == '\"')) {
+ doneOutput = false;
+ } else {
+ result += prev;
+ doneOutput = true;
+ }
+ prev = *it;
+ }
+
+ if ((doneOutput && prev != '\\') || !doneOutput) {
+ result += prev;
+ }
+
+ return result;
+ }
+
+ void TBase64EncodeBytesTransform::TransformBytes(TString &str) const {
+ str = Base64Encode(str);
+ }
+
+ void TBase64DecodeBytesTransform::TransformBytes(TString &str) const {
+ str = Base64Decode(str);
+ }
+}
diff --git a/library/cpp/protobuf/json/string_transform.h b/library/cpp/protobuf/json/string_transform.h
new file mode 100644
index 0000000000..e4b296bc01
--- /dev/null
+++ b/library/cpp/protobuf/json/string_transform.h
@@ -0,0 +1,111 @@
+#pragma once
+
+#include <library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h>
+#include <util/generic/ptr.h>
+#include <util/generic/refcount.h>
+
+namespace NProtobufJson {
+ class IStringTransform: public TSimpleRefCount<IStringTransform> {
+ public:
+ virtual ~IStringTransform() {
+ }
+
+ /// Some transforms have special meaning.
+ /// For example, escape transforms cause generic JSON escaping to be turned off.
+ enum Type {
+ EscapeTransform = 0x1,
+ };
+
+ virtual int GetType() const = 0;
+
+ /// This method is called for each string field in proto
+ virtual void Transform(TString& str) const = 0;
+
+ /// This method is called for each bytes field in proto
+ virtual void TransformBytes(TString& str) const {
+ // Default behaviour is to apply string transform
+ return Transform(str);
+ }
+ };
+
+ using TStringTransformPtr = TIntrusivePtr<IStringTransform>;
+
+ template <bool quote, bool tounicode>
+ class TEscapeJTransform: public IStringTransform {
+ public:
+ int GetType() const override {
+ return EscapeTransform;
+ }
+
+ void Transform(TString& str) const override {
+ TString newStr;
+ NEscJ::EscapeJ<quote, tounicode>(str, newStr);
+ str = newStr;
+ }
+ };
+
+ class TCEscapeTransform: public IStringTransform {
+ public:
+ int GetType() const override {
+ return EscapeTransform;
+ }
+
+ void Transform(TString& str) const override;
+ };
+
+ class TSafeUtf8CEscapeTransform: public IStringTransform {
+ public:
+ int GetType() const override {
+ return EscapeTransform;
+ }
+
+ void Transform(TString& str) const override;
+ };
+
+ class TDoubleEscapeTransform: public IStringTransform {
+ public:
+ int GetType() const override {
+ return EscapeTransform;
+ }
+
+ void Transform(TString& str) const override;
+ };
+
+ class TDoubleUnescapeTransform: public NProtobufJson::IStringTransform {
+ public:
+ int GetType() const override {
+ return NProtobufJson::IStringTransform::EscapeTransform;
+ }
+
+ void Transform(TString& str) const override;
+
+ private:
+ TString Unescape(const TString& str) const;
+ };
+
+ class TBase64EncodeBytesTransform: public NProtobufJson::IStringTransform {
+ public:
+ int GetType() const override {
+ return 0;
+ }
+
+ void Transform(TString&) const override {
+ // Do not transform strings
+ }
+
+ void TransformBytes(TString &str) const override;
+ };
+
+ class TBase64DecodeBytesTransform: public NProtobufJson::IStringTransform {
+ public:
+ int GetType() const override {
+ return 0;
+ }
+
+ void Transform(TString&) const override {
+ // Do not transform strings
+ }
+
+ void TransformBytes(TString &str) const override;
+ };
+}
diff --git a/library/cpp/protobuf/json/ut/fields.incl b/library/cpp/protobuf/json/ut/fields.incl
new file mode 100644
index 0000000000..4b22985836
--- /dev/null
+++ b/library/cpp/protobuf/json/ut/fields.incl
@@ -0,0 +1,23 @@
+// Intentionally no #pragma once
+
+// (Field name == JSON key, Value)
+DEFINE_FIELD(I32, Min<i32>())
+DEFINE_FIELD(I64, Min<i64>())
+DEFINE_FIELD(UI32, Max<ui32>())
+DEFINE_FIELD(UI64, Max<ui64>())
+DEFINE_FIELD(SI32, Min<i32>())
+DEFINE_FIELD(SI64, Min<i64>())
+DEFINE_FIELD(FI32, Max<ui32>())
+DEFINE_FIELD(FI64, Max<ui64>())
+DEFINE_FIELD(SFI32, Min<i32>())
+DEFINE_FIELD(SFI64, Min<i64>())
+DEFINE_FIELD(Bool, true)
+DEFINE_FIELD(String, "Lorem ipsum")
+DEFINE_FIELD(Bytes, "מחשב")
+DEFINE_FIELD(Enum, E_1)
+DEFINE_FIELD(Float, 1.123f)
+DEFINE_FIELD(Double, 1.123456789012)
+DEFINE_FIELD(OneString, "Lorem ipsum dolor")
+DEFINE_FIELD(OneTwoString, "Lorem ipsum dolor sit")
+DEFINE_FIELD(ABC, "abc")
+DEFINE_FIELD(UserID, "some_id") \ No newline at end of file
diff --git a/library/cpp/protobuf/json/ut/filter_ut.cpp b/library/cpp/protobuf/json/ut/filter_ut.cpp
new file mode 100644
index 0000000000..95c227666f
--- /dev/null
+++ b/library/cpp/protobuf/json/ut/filter_ut.cpp
@@ -0,0 +1,93 @@
+#include <library/cpp/protobuf/json/ut/filter_ut.pb.h>
+
+#include <library/cpp/protobuf/json/filter.h>
+#include <library/cpp/protobuf/json/field_option.h>
+#include <library/cpp/protobuf/json/proto2json.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NProtobufJson;
+
+static NProtobufJsonUt::TFilterTest GetTestMsg() {
+ NProtobufJsonUt::TFilterTest msg;
+ msg.SetOptFiltered("1");
+ msg.SetNotFiltered("23");
+ msg.AddRepFiltered(45);
+ msg.AddRepFiltered(67);
+ msg.MutableInner()->AddNumber(100);
+ msg.MutableInner()->AddNumber(200);
+ msg.MutableInner()->SetInnerFiltered(235);
+ return msg;
+}
+
+Y_UNIT_TEST_SUITE(TProto2JsonFilterTest){
+ Y_UNIT_TEST(TestFilterPrinter){
+ NProtobufJsonUt::TFilterTest msg = GetTestMsg();
+{
+ TString expected = R"({"OptFiltered":"1","NotFiltered":"23","RepFiltered":[45,67],)"
+ R"("Inner":{"Number":[100,200],"InnerFiltered":235}})";
+ TString my = Proto2Json(msg);
+ UNIT_ASSERT_STRINGS_EQUAL(my, expected);
+}
+
+{
+ TString expected = R"({"NotFiltered":"23",)"
+ R"("Inner":{"Number":[100,200]}})";
+ TString my = PrintWithFilter(msg, MakeFieldOptionFunctor(NProtobufJsonUt::filter_test, false));
+ UNIT_ASSERT_STRINGS_EQUAL(my, expected);
+}
+
+{
+ TString expected = R"({"OptFiltered":"1","RepFiltered":[45,67]})";
+ TString my = PrintWithFilter(msg, MakeFieldOptionFunctor(NProtobufJsonUt::filter_test));
+ UNIT_ASSERT_STRINGS_EQUAL(my, expected);
+}
+
+{
+ TString expected = R"({"OptFiltered":"1","NotFiltered":"23",)"
+ R"("Inner":{"Number":[100,200]}})";
+ TString my;
+ PrintWithFilter(msg, MakeFieldOptionFunctor(NProtobufJsonUt::export_test), *CreateJsonMapOutput(my));
+ UNIT_ASSERT_STRINGS_EQUAL(my, expected);
+}
+
+{
+ TString expected = R"({"NotFiltered":"23",)"
+ R"("Inner":{"Number":[100,200]}})";
+ auto functor = [](const NProtoBuf::Message&, const NProtoBuf::FieldDescriptor* field) {
+ return field->name() == "NotFiltered" || field->name() == "Number" || field->name() == "Inner";
+ };
+ TString my = PrintWithFilter(msg, functor);
+ UNIT_ASSERT_STRINGS_EQUAL(my, expected);
+}
+}
+
+Y_UNIT_TEST(NoUnnecessaryCopyFunctor) {
+ size_t CopyCount = 0;
+ struct TFunctorMock {
+ TFunctorMock(size_t* copyCount)
+ : CopyCount(copyCount)
+ {
+ UNIT_ASSERT(*CopyCount <= 1);
+ }
+
+ TFunctorMock(const TFunctorMock& f)
+ : CopyCount(f.CopyCount)
+ {
+ ++*CopyCount;
+ }
+
+ TFunctorMock(TFunctorMock&& f) = default;
+
+ bool operator()(const NProtoBuf::Message&, const NProtoBuf::FieldDescriptor*) const {
+ return false;
+ }
+
+ size_t* CopyCount;
+ };
+
+ TProto2JsonConfig cfg;
+ TFilteringPrinter<> printer(TFunctorMock(&CopyCount), cfg);
+ UNIT_ASSERT(CopyCount <= 1);
+}
+}
+;
diff --git a/library/cpp/protobuf/json/ut/filter_ut.proto b/library/cpp/protobuf/json/ut/filter_ut.proto
new file mode 100644
index 0000000000..29d630ade4
--- /dev/null
+++ b/library/cpp/protobuf/json/ut/filter_ut.proto
@@ -0,0 +1,20 @@
+import "google/protobuf/descriptor.proto";
+
+package NProtobufJsonUt;
+
+extend google.protobuf.FieldOptions {
+ optional bool filter_test = 58255;
+ optional bool export_test = 58256;
+}
+
+message TFilterTest {
+ optional string OptFiltered = 1 [(filter_test) = true, (export_test) = true];
+ optional string NotFiltered = 2 [(export_test) = true];
+ repeated uint64 RepFiltered = 3 [(filter_test) = true];
+
+ message TInner {
+ repeated uint32 Number = 1 [(export_test) = true];
+ optional int32 InnerFiltered = 2 [(filter_test) = true];
+ }
+ optional TInner Inner = 4 [(export_test) = true];
+}
diff --git a/library/cpp/protobuf/json/ut/inline_ut.cpp b/library/cpp/protobuf/json/ut/inline_ut.cpp
new file mode 100644
index 0000000000..c29ad32e7d
--- /dev/null
+++ b/library/cpp/protobuf/json/ut/inline_ut.cpp
@@ -0,0 +1,122 @@
+#include <library/cpp/protobuf/json/ut/inline_ut.pb.h>
+
+#include <library/cpp/protobuf/json/inline.h>
+#include <library/cpp/protobuf/json/field_option.h>
+#include <library/cpp/protobuf/json/proto2json.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/string.h>
+
+using namespace NProtobufJson;
+
+static NProtobufJsonUt::TInlineTest GetTestMsg() {
+ NProtobufJsonUt::TInlineTest msg;
+ msg.SetOptJson(R"({"a":1,"b":"000"})");
+ msg.SetNotJson("12{}34");
+ msg.AddRepJson("{}");
+ msg.AddRepJson("[1,2]");
+ msg.MutableInner()->AddNumber(100);
+ msg.MutableInner()->AddNumber(200);
+ msg.MutableInner()->SetInnerJson(R"({"xxx":[]})");
+ return msg;
+}
+
+Y_UNIT_TEST_SUITE(TProto2JsonInlineTest){
+ Y_UNIT_TEST(TestNormalPrint){
+ NProtobufJsonUt::TInlineTest msg = GetTestMsg();
+// normal print should output these fields as just string values
+TString expRaw = R"({"OptJson":"{\"a\":1,\"b\":\"000\"}","NotJson":"12{}34","RepJson":["{}","[1,2]"],)"
+ R"("Inner":{"Number":[100,200],"InnerJson":"{\"xxx\":[]}"}})";
+TString myRaw;
+Proto2Json(msg, myRaw);
+UNIT_ASSERT_STRINGS_EQUAL(myRaw, expRaw);
+
+myRaw = PrintInlined(msg, [](const NProtoBuf::Message&, const NProtoBuf::FieldDescriptor*) { return false; });
+UNIT_ASSERT_STRINGS_EQUAL(myRaw, expRaw); // result is the same
+}
+
+Y_UNIT_TEST(TestInliningPrinter) {
+ NProtobufJsonUt::TInlineTest msg = GetTestMsg();
+ // inlined print should output these fields as inlined json sub-objects
+ TString expInlined = R"({"OptJson":{"a":1,"b":"000"},"NotJson":"12{}34","RepJson":[{},[1,2]],)"
+ R"("Inner":{"Number":[100,200],"InnerJson":{"xxx":[]}}})";
+
+ {
+ TString myInlined = PrintInlined(msg, MakeFieldOptionFunctor(NProtobufJsonUt::inline_test));
+ UNIT_ASSERT_STRINGS_EQUAL(myInlined, expInlined);
+ }
+ {
+ auto functor = [](const NProtoBuf::Message&, const NProtoBuf::FieldDescriptor* field) {
+ return field->name() == "OptJson" || field->name() == "RepJson" || field->name() == "InnerJson";
+ };
+ TString myInlined = PrintInlined(msg, functor);
+ UNIT_ASSERT_STRINGS_EQUAL(myInlined, expInlined);
+ }
+}
+
+Y_UNIT_TEST(TestNoValues) {
+ // no values - no printing
+ NProtobufJsonUt::TInlineTest msg;
+ msg.MutableInner()->AddNumber(100);
+ msg.MutableInner()->AddNumber(200);
+
+ TString expInlined = R"({"Inner":{"Number":[100,200]}})";
+
+ TString myInlined = PrintInlined(msg, MakeFieldOptionFunctor(NProtobufJsonUt::inline_test));
+ UNIT_ASSERT_STRINGS_EQUAL(myInlined, expInlined);
+}
+
+Y_UNIT_TEST(TestMissingKeyModeNull) {
+ NProtobufJsonUt::TInlineTest msg;
+ msg.MutableInner()->AddNumber(100);
+ msg.MutableInner()->AddNumber(200);
+
+ TString expInlined = R"({"OptJson":null,"NotJson":null,"RepJson":null,"Inner":{"Number":[100,200],"InnerJson":null}})";
+
+ TProto2JsonConfig cfg;
+ cfg.SetMissingSingleKeyMode(TProto2JsonConfig::MissingKeyNull).SetMissingRepeatedKeyMode(TProto2JsonConfig::MissingKeyNull);
+ TString myInlined = PrintInlined(msg, MakeFieldOptionFunctor(NProtobufJsonUt::inline_test), cfg);
+ UNIT_ASSERT_STRINGS_EQUAL(myInlined, expInlined);
+}
+
+Y_UNIT_TEST(TestMissingKeyModeDefault) {
+ NProtobufJsonUt::TInlineTestDefaultValues msg;
+
+ TString expInlined = R"({"OptJson":{"default":1},"Number":0,"RepJson":[],"Inner":{"OptJson":{"default":2}}})";
+
+ TProto2JsonConfig cfg;
+ cfg.SetMissingSingleKeyMode(TProto2JsonConfig::MissingKeyDefault).SetMissingRepeatedKeyMode(TProto2JsonConfig::MissingKeyDefault);
+ TString myInlined = PrintInlined(msg, MakeFieldOptionFunctor(NProtobufJsonUt::inline_test), cfg);
+ UNIT_ASSERT_STRINGS_EQUAL(myInlined, expInlined);
+}
+
+Y_UNIT_TEST(NoUnnecessaryCopyFunctor) {
+ size_t CopyCount = 0;
+ struct TFunctorMock {
+ TFunctorMock(size_t* copyCount)
+ : CopyCount(copyCount)
+ {
+ UNIT_ASSERT(*CopyCount <= 1);
+ }
+
+ TFunctorMock(const TFunctorMock& f)
+ : CopyCount(f.CopyCount)
+ {
+ ++*CopyCount;
+ }
+
+ TFunctorMock(TFunctorMock&& f) = default;
+
+ bool operator()(const NProtoBuf::Message&, const NProtoBuf::FieldDescriptor*) const {
+ return false;
+ }
+
+ size_t* CopyCount;
+ };
+
+ TProto2JsonConfig cfg;
+ TInliningPrinter<> printer(TFunctorMock(&CopyCount), cfg);
+ UNIT_ASSERT(CopyCount <= 1);
+}
+}
+;
diff --git a/library/cpp/protobuf/json/ut/inline_ut.proto b/library/cpp/protobuf/json/ut/inline_ut.proto
new file mode 100644
index 0000000000..76bd10232d
--- /dev/null
+++ b/library/cpp/protobuf/json/ut/inline_ut.proto
@@ -0,0 +1,29 @@
+import "google/protobuf/descriptor.proto";
+
+package NProtobufJsonUt;
+
+extend google.protobuf.FieldOptions {
+ optional bool inline_test = 58253;
+}
+
+message TInlineTest {
+ optional string OptJson = 1 [(inline_test) = true];
+ optional string NotJson = 2;
+ repeated string RepJson = 3 [(inline_test) = true];
+
+ message TInner {
+ repeated uint32 Number = 1;
+ optional string InnerJson = 2 [(inline_test) = true];
+ }
+ optional TInner Inner = 4;
+}
+
+message TInlineTestDefaultValues {
+ optional string OptJson = 1 [(inline_test) = true, default = "{\"default\":1}"];
+ optional uint32 Number = 2;
+ repeated string RepJson = 3 [(inline_test) = true];
+ message TInner {
+ optional string OptJson = 1 [(inline_test) = true, default = "{\"default\":2}"];
+ }
+ optional TInner Inner = 4;
+}
diff --git a/library/cpp/protobuf/json/ut/json.h b/library/cpp/protobuf/json/ut/json.h
new file mode 100644
index 0000000000..c1f108e6e4
--- /dev/null
+++ b/library/cpp/protobuf/json/ut/json.h
@@ -0,0 +1,69 @@
+#pragma once
+
+#include <library/cpp/protobuf/json/ut/test.pb.h>
+
+#include <library/cpp/json/json_value.h>
+
+#include <cstdarg>
+
+#include <util/generic/hash_set.h>
+#include <util/generic/string.h>
+
+#include <util/system/defaults.h>
+
+namespace NProtobufJsonTest {
+ inline NJson::TJsonValue
+ CreateFlatJson(const THashSet<TString>& skippedKeys = THashSet<TString>()) {
+ NJson::TJsonValue json;
+
+#define DEFINE_FIELD(name, value) \
+ if (skippedKeys.find(#name) == skippedKeys.end()) \
+ json.InsertValue(#name, value);
+#include "fields.incl"
+#undef DEFINE_FIELD
+
+ return json;
+ }
+
+ inline NJson::TJsonValue
+ CreateRepeatedFlatJson(const THashSet<TString>& skippedKeys = THashSet<TString>()) {
+ NJson::TJsonValue json;
+
+#define DEFINE_REPEATED_FIELD(name, type, ...) \
+ if (skippedKeys.find(#name) == skippedKeys.end()) { \
+ type values[] = {__VA_ARGS__}; \
+ NJson::TJsonValue array(NJson::JSON_ARRAY); \
+ for (size_t i = 0, end = Y_ARRAY_SIZE(values); i < end; ++i) { \
+ array.AppendValue(values[i]); \
+ } \
+ json.InsertValue(#name, array); \
+ }
+#include "repeated_fields.incl"
+#undef DEFINE_REPEATED_FIELD
+
+ return json;
+ }
+
+ inline NJson::TJsonValue
+ CreateCompositeJson(const THashSet<TString>& skippedKeys = THashSet<TString>()) {
+ const NJson::TJsonValue& part = CreateFlatJson(skippedKeys);
+ NJson::TJsonValue json;
+ json.InsertValue("Part", part);
+
+ return json;
+ }
+
+#define UNIT_ASSERT_JSONS_EQUAL(lhs, rhs) \
+ if (lhs != rhs) { \
+ UNIT_ASSERT_STRINGS_EQUAL(lhs.GetStringRobust(), rhs.GetStringRobust()); \
+ }
+
+#define UNIT_ASSERT_JSON_STRINGS_EQUAL(lhs, rhs) \
+ if (lhs != rhs) { \
+ NJson::TJsonValue _lhs_json, _rhs_json; \
+ UNIT_ASSERT(NJson::ReadJsonTree(lhs, &_lhs_json)); \
+ UNIT_ASSERT(NJson::ReadJsonTree(rhs, &_rhs_json)); \
+ UNIT_ASSERT_JSONS_EQUAL(_lhs_json, _rhs_json); \
+ }
+
+}
diff --git a/library/cpp/protobuf/json/ut/json2proto_ut.cpp b/library/cpp/protobuf/json/ut/json2proto_ut.cpp
new file mode 100644
index 0000000000..0dfe57bc7a
--- /dev/null
+++ b/library/cpp/protobuf/json/ut/json2proto_ut.cpp
@@ -0,0 +1,1147 @@
+#include "json.h"
+#include "proto.h"
+#include "proto2json.h"
+
+#include <library/cpp/protobuf/json/ut/test.pb.h>
+
+#include <library/cpp/json/json_value.h>
+#include <library/cpp/json/json_reader.h>
+#include <library/cpp/json/json_writer.h>
+
+#include <library/cpp/protobuf/json/json2proto.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/hash_set.h>
+#include <util/generic/string.h>
+#include <util/generic/ylimits.h>
+#include <util/stream/str.h>
+#include <util/string/cast.h>
+#include <util/system/defaults.h>
+#include <util/system/yassert.h>
+
+using namespace NProtobufJson;
+using namespace NProtobufJsonTest;
+
+namespace google {
+ namespace protobuf {
+ namespace internal {
+ void MapTestForceDeterministic() {
+ google::protobuf::io::CodedOutputStream::SetDefaultSerializationDeterministic();
+ }
+ }
+ } // namespace protobuf
+}
+
+namespace {
+ class TInit {
+ public:
+ TInit() {
+ ::google::protobuf::internal::MapTestForceDeterministic();
+ }
+ } Init;
+
+ template <typename T>
+ TString ConvertToString(T value) {
+ return ToString(value);
+ }
+
+ // default ToString<double>() implementation loses precision
+ TString ConvertToString(double value) {
+ return FloatToString(value);
+ }
+
+ TString JsonValueToString(const NJson::TJsonValue& json) {
+ NJsonWriter::TBuf buf(NJsonWriter::HEM_UNSAFE);
+ return buf.WriteJsonValue(&json).Str();
+ }
+
+ void TestComplexMapAsObject(std::function<void(TComplexMapType&)>&& init, const TString& json, const TJson2ProtoConfig& config = TJson2ProtoConfig().SetMapAsObject(true)) {
+ TComplexMapType modelProto;
+
+ init(modelProto);
+
+ TString modelStr(json);
+
+ TComplexMapType proto;
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TComplexMapType>(modelStr, config));
+
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+ }
+}
+
+Y_UNIT_TEST_SUITE(TJson2ProtoTest) {
+ Y_UNIT_TEST(TestFlatOptional){
+ {const NJson::TJsonValue& json = CreateFlatJson();
+ TFlatOptional proto;
+ Json2Proto(json, proto);
+ TFlatOptional modelProto;
+ FillFlatProto(&modelProto);
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+}
+
+ // Try to skip each field
+#define DEFINE_FIELD(name, value) \
+ { \
+ THashSet<TString> skippedField; \
+ skippedField.insert(#name); \
+ const NJson::TJsonValue& json = CreateFlatJson(skippedField); \
+ TFlatOptional proto; \
+ Json2Proto(json, proto); \
+ TFlatOptional modelProto; \
+ FillFlatProto(&modelProto, skippedField); \
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto); \
+ }
+#include <library/cpp/protobuf/json/ut/fields.incl>
+#undef DEFINE_FIELD
+} // TestFlatOptional
+
+Y_UNIT_TEST(TestFlatRequired){
+ {const NJson::TJsonValue& json = CreateFlatJson();
+TFlatRequired proto;
+Json2Proto(json, proto);
+TFlatRequired modelProto;
+FillFlatProto(&modelProto);
+UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+}
+
+// Try to skip each field
+#define DEFINE_FIELD(name, value) \
+ { \
+ THashSet<TString> skippedField; \
+ skippedField.insert(#name); \
+ const NJson::TJsonValue& json = CreateFlatJson(skippedField); \
+ TFlatRequired proto; \
+ UNIT_ASSERT_EXCEPTION(Json2Proto(json, proto), yexception); \
+ }
+#include <library/cpp/protobuf/json/ut/fields.incl>
+#undef DEFINE_FIELD
+} // TestFlatRequired
+
+Y_UNIT_TEST(TestNameGenerator) {
+ TJson2ProtoConfig cfg;
+ cfg.SetNameGenerator([](const NProtoBuf::FieldDescriptor&) { return "42"; });
+
+ TNameGeneratorType proto;
+ Json2Proto(TStringBuf(R"({"42":42})"), proto, cfg);
+
+ TNameGeneratorType expected;
+ expected.SetField(42);
+
+ UNIT_ASSERT_PROTOS_EQUAL(expected, proto);
+}
+
+Y_UNIT_TEST(TestFlatNoCheckRequired) {
+ {
+ const NJson::TJsonValue& json = CreateFlatJson();
+ TFlatRequired proto;
+ Json2Proto(json, proto);
+ TFlatRequired modelProto;
+ FillFlatProto(&modelProto);
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+ }
+
+ TJson2ProtoConfig cfg;
+ cfg.CheckRequiredFields = false;
+
+ // Try to skip each field
+#define DEFINE_FIELD(name, value) \
+ { \
+ THashSet<TString> skippedField; \
+ skippedField.insert(#name); \
+ const NJson::TJsonValue& json = CreateFlatJson(skippedField); \
+ TFlatRequired proto; \
+ UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto, cfg)); \
+ }
+#include <library/cpp/protobuf/json/ut/fields.incl>
+#undef DEFINE_FIELD
+} // TestFlatNoCheckRequired
+
+Y_UNIT_TEST(TestFlatRepeated){
+ {const NJson::TJsonValue& json = CreateRepeatedFlatJson();
+TFlatRepeated proto;
+Json2Proto(json, proto);
+TFlatRepeated modelProto;
+FillRepeatedProto(&modelProto);
+UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+}
+
+// Try to skip each field
+#define DEFINE_REPEATED_FIELD(name, ...) \
+ { \
+ THashSet<TString> skippedField; \
+ skippedField.insert(#name); \
+ const NJson::TJsonValue& json = CreateRepeatedFlatJson(skippedField); \
+ TFlatRepeated proto; \
+ Json2Proto(json, proto); \
+ TFlatRepeated modelProto; \
+ FillRepeatedProto(&modelProto, skippedField); \
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto); \
+ }
+#include <library/cpp/protobuf/json/ut/repeated_fields.incl>
+#undef DEFINE_REPEATED_FIELD
+} // TestFlatRepeated
+
+Y_UNIT_TEST(TestCompositeOptional){
+ {const NJson::TJsonValue& json = CreateCompositeJson();
+TCompositeOptional proto;
+Json2Proto(json, proto);
+TCompositeOptional modelProto;
+FillCompositeProto(&modelProto);
+UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+}
+
+// Try to skip each field
+#define DEFINE_FIELD(name, value) \
+ { \
+ THashSet<TString> skippedField; \
+ skippedField.insert(#name); \
+ const NJson::TJsonValue& json = CreateCompositeJson(skippedField); \
+ TCompositeOptional proto; \
+ Json2Proto(json, proto); \
+ TCompositeOptional modelProto; \
+ FillCompositeProto(&modelProto, skippedField); \
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto); \
+ }
+#include <library/cpp/protobuf/json/ut/fields.incl>
+#undef DEFINE_FIELD
+} // TestCompositeOptional
+
+Y_UNIT_TEST(TestCompositeOptionalStringBuf){
+ {NJson::TJsonValue json = CreateCompositeJson();
+json["Part"]["Double"] = 42.5;
+TCompositeOptional proto;
+Json2Proto(JsonValueToString(json), proto);
+TCompositeOptional modelProto;
+FillCompositeProto(&modelProto);
+modelProto.MutablePart()->SetDouble(42.5);
+UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+}
+
+// Try to skip each field
+#define DEFINE_FIELD(name, value) \
+ { \
+ THashSet<TString> skippedField; \
+ skippedField.insert(#name); \
+ NJson::TJsonValue json = CreateCompositeJson(skippedField); \
+ if (json["Part"].Has("Double")) { \
+ json["Part"]["Double"] = 42.5; \
+ } \
+ TCompositeOptional proto; \
+ Json2Proto(JsonValueToString(json), proto); \
+ TCompositeOptional modelProto; \
+ FillCompositeProto(&modelProto, skippedField); \
+ if (modelProto.GetPart().HasDouble()) { \
+ modelProto.MutablePart()->SetDouble(42.5); \
+ } \
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto); \
+ }
+#include <library/cpp/protobuf/json/ut/fields.incl>
+#undef DEFINE_FIELD
+} // TestCompositeOptionalStringBuf
+
+Y_UNIT_TEST(TestCompositeRequired) {
+ {
+ const NJson::TJsonValue& json = CreateCompositeJson();
+ TCompositeRequired proto;
+ Json2Proto(json, proto);
+ TCompositeRequired modelProto;
+ FillCompositeProto(&modelProto);
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+ }
+
+ {
+ NJson::TJsonValue json;
+ TCompositeRequired proto;
+ UNIT_ASSERT_EXCEPTION(Json2Proto(json, proto), yexception);
+ }
+} // TestCompositeRequired
+
+Y_UNIT_TEST(TestCompositeRepeated) {
+ {
+ NJson::TJsonValue json;
+ NJson::TJsonValue array;
+ array.AppendValue(CreateFlatJson());
+ json.InsertValue("Part", array);
+
+ TCompositeRepeated proto;
+ Json2Proto(json, proto);
+
+ TFlatOptional partModelProto;
+ FillFlatProto(&partModelProto);
+ TCompositeRepeated modelProto;
+ modelProto.AddPart()->CopyFrom(partModelProto);
+
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+ }
+
+ {
+ // Array of messages with each field skipped
+ TCompositeRepeated modelProto;
+ NJson::TJsonValue array;
+
+#define DEFINE_REPEATED_FIELD(name, ...) \
+ { \
+ THashSet<TString> skippedField; \
+ skippedField.insert(#name); \
+ TFlatOptional partModelProto; \
+ FillFlatProto(&partModelProto, skippedField); \
+ modelProto.AddPart()->CopyFrom(partModelProto); \
+ array.AppendValue(CreateFlatJson(skippedField)); \
+ }
+#include <library/cpp/protobuf/json/ut/repeated_fields.incl>
+#undef DEFINE_REPEATED_FIELD
+
+ NJson::TJsonValue json;
+ json.InsertValue("Part", array);
+
+ TCompositeRepeated proto;
+ Json2Proto(json, proto);
+
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+ }
+} // TestCompositeRepeated
+
+Y_UNIT_TEST(TestInvalidEnum) {
+ {
+ NJson::TJsonValue json;
+ json.InsertValue("Enum", "E_100");
+ TFlatOptional proto;
+ UNIT_ASSERT_EXCEPTION(Json2Proto(json, proto), yexception);
+ }
+
+ {
+ NJson::TJsonValue json;
+ json.InsertValue("Enum", 100);
+ TFlatOptional proto;
+ UNIT_ASSERT_EXCEPTION(Json2Proto(json, proto), yexception);
+ }
+}
+
+Y_UNIT_TEST(TestFieldNameMode) {
+ // Original case 1
+ {
+ TString modelStr(R"_({"String":"value"})_");
+
+ TFlatOptional proto;
+ TJson2ProtoConfig config;
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
+ UNIT_ASSERT(proto.GetString() == "value");
+ }
+
+ // Original case 2
+ {
+ TString modelStr(R"_({"String":"value"})_");
+
+ TFlatOptional proto;
+ TJson2ProtoConfig config;
+ config.FieldNameMode = TJson2ProtoConfig::FieldNameOriginalCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
+ UNIT_ASSERT(proto.GetString() == "value");
+ }
+
+ // Lowercase
+ {
+ TString modelStr(R"_({"string":"value"})_");
+
+ TFlatOptional proto;
+ TJson2ProtoConfig config;
+ config.FieldNameMode = TJson2ProtoConfig::FieldNameLowerCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
+ UNIT_ASSERT(proto.GetString() == "value");
+ }
+
+ // Uppercase
+ {
+ TString modelStr(R"_({"STRING":"value"})_");
+
+ TFlatOptional proto;
+ TJson2ProtoConfig config;
+ config.FieldNameMode = TJson2ProtoConfig::FieldNameUpperCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
+ UNIT_ASSERT(proto.GetString() == "value");
+ }
+
+ // Camelcase
+ {
+ TString modelStr(R"_({"string":"value"})_");
+
+ TFlatOptional proto;
+ TJson2ProtoConfig config;
+ config.FieldNameMode = TJson2ProtoConfig::FieldNameCamelCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
+ UNIT_ASSERT(proto.GetString() == "value");
+ }
+ {
+ TString modelStr(R"_({"oneString":"value"})_");
+
+ TFlatOptional proto;
+ TJson2ProtoConfig config;
+ config.FieldNameMode = TJson2ProtoConfig::FieldNameCamelCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
+ UNIT_ASSERT(proto.GetOneString() == "value");
+ }
+ {
+ TString modelStr(R"_({"oneTwoString":"value"})_");
+
+ TFlatOptional proto;
+ TJson2ProtoConfig config;
+ config.FieldNameMode = TJson2ProtoConfig::FieldNameCamelCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
+ UNIT_ASSERT(proto.GetOneTwoString() == "value");
+ }
+
+ // snake_case
+ {
+ TString modelStr(R"_({"string":"value"})_");
+
+ TFlatOptional proto;
+ TJson2ProtoConfig config;
+ config.FieldNameMode = TJson2ProtoConfig::FieldNameSnakeCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
+ UNIT_ASSERT(proto.GetString() == "value");
+ }
+ {
+ TString modelStr(R"_({"one_string":"value"})_");
+
+ TFlatOptional proto;
+ TJson2ProtoConfig config;
+ config.FieldNameMode = TJson2ProtoConfig::FieldNameSnakeCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
+ UNIT_ASSERT(proto.GetOneString() == "value");
+ }
+ {
+ TString modelStr(R"_({"one_two_string":"value"})_");
+
+ TFlatOptional proto;
+ TJson2ProtoConfig config;
+ config.FieldNameMode = TJson2ProtoConfig::FieldNameSnakeCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
+ UNIT_ASSERT(proto.GetOneTwoString() == "value");
+ }
+
+ // Original case, repeated
+ {
+ TString modelStr(R"_({"I32":[1,2]})_");
+
+ TFlatRepeated proto;
+ TJson2ProtoConfig config;
+ config.FieldNameMode = TJson2ProtoConfig::FieldNameOriginalCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatRepeated>(modelStr, config));
+ UNIT_ASSERT(proto.I32Size() == 2);
+ UNIT_ASSERT(proto.GetI32(0) == 1);
+ UNIT_ASSERT(proto.GetI32(1) == 2);
+ }
+
+ // Lower case, repeated
+ {
+ TString modelStr(R"_({"i32":[1,2]})_");
+
+ TFlatRepeated proto;
+ TJson2ProtoConfig config;
+ config.FieldNameMode = TJson2ProtoConfig::FieldNameLowerCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatRepeated>(modelStr, config));
+ UNIT_ASSERT(proto.I32Size() == 2);
+ UNIT_ASSERT(proto.GetI32(0) == 1);
+ UNIT_ASSERT(proto.GetI32(1) == 2);
+ }
+
+ // UseJsonName
+ {
+ // FIXME(CONTRIB-139): since protobuf 3.1, Def_upper json name is
+ // "DefUpper", but until kernel/ugc/schema and yweb/yasap/pdb are
+ // updated, library/cpp/protobuf/json preserves compatibility with
+ // protobuf 3.0 by lowercasing default names, making it "defUpper".
+ TString modelStr(R"_({"My-Upper":1,"my-lower":2,"defUpper":3,"defLower":4})_");
+
+ TWithJsonName proto;
+ TJson2ProtoConfig config;
+ config.SetUseJsonName(true);
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TWithJsonName>(modelStr, config));
+ UNIT_ASSERT_EQUAL(proto.Getmy_upper(), 1);
+ UNIT_ASSERT_EQUAL(proto.GetMy_lower(), 2);
+ UNIT_ASSERT_EQUAL(proto.GetDef_upper(), 3);
+ UNIT_ASSERT_EQUAL(proto.Getdef_lower(), 4);
+ }
+
+ // FieldNameMode with UseJsonName
+ {
+ TJson2ProtoConfig config;
+ config.SetFieldNameMode(TJson2ProtoConfig::FieldNameLowerCase);
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ config.SetUseJsonName(true), yexception, "mutually exclusive");
+ }
+ {
+ TJson2ProtoConfig config;
+ config.SetUseJsonName(true);
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ config.SetFieldNameMode(TJson2ProtoConfig::FieldNameLowerCase), yexception, "mutually exclusive");
+ }
+} // TestFieldNameMode
+
+class TStringTransform: public IStringTransform {
+public:
+ int GetType() const override {
+ return 0;
+ }
+ void Transform(TString& str) const override {
+ str = "transformed_any";
+ }
+};
+
+class TBytesTransform: public IStringTransform {
+public:
+ int GetType() const override {
+ return 0;
+ }
+ void Transform(TString&) const override {
+ }
+ void TransformBytes(TString& str) const override {
+ str = "transformed_bytes";
+ }
+};
+
+Y_UNIT_TEST(TestInvalidJson) {
+ NJson::TJsonValue val{"bad value"};
+ TFlatOptional proto;
+ UNIT_ASSERT_EXCEPTION(Json2Proto(val, proto), yexception);
+}
+
+Y_UNIT_TEST(TestInvalidRepeatedFieldWithMapAsObject) {
+ TCompositeRepeated proto;
+ TJson2ProtoConfig config;
+ config.MapAsObject = true;
+ UNIT_ASSERT_EXCEPTION(Json2Proto(TStringBuf(R"({"Part":{"Boo":{}}})"), proto, config), yexception);
+}
+
+Y_UNIT_TEST(TestStringTransforms) {
+ // Check that strings and bytes are transformed
+ {
+ TString modelStr(R"_({"String":"value_str", "Bytes": "value_bytes"})_");
+
+ TFlatOptional proto;
+ TJson2ProtoConfig config;
+ config.AddStringTransform(new TStringTransform);
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
+ UNIT_ASSERT(proto.GetString() == "transformed_any");
+ UNIT_ASSERT(proto.GetBytes() == "transformed_any");
+ }
+
+ // Check that bytes are transformed, strings are left intact
+ {
+ TString modelStr(R"_({"String":"value_str", "Bytes": "value_bytes"})_");
+
+ TFlatOptional proto;
+ TJson2ProtoConfig config;
+ config.AddStringTransform(new TBytesTransform);
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatOptional>(modelStr, config));
+ UNIT_ASSERT(proto.GetString() == "value_str");
+ UNIT_ASSERT(proto.GetBytes() == "transformed_bytes");
+ }
+
+ // Check that repeated bytes are transformed, repeated strings are left intact
+ {
+ TString modelStr(R"_({"String":["value_str", "str2"], "Bytes": ["value_bytes", "bytes2"]})_");
+
+ TFlatRepeated proto;
+ TJson2ProtoConfig config;
+ config.AddStringTransform(new TBytesTransform);
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TFlatRepeated>(modelStr, config));
+ UNIT_ASSERT(proto.StringSize() == 2);
+ UNIT_ASSERT(proto.GetString(0) == "value_str");
+ UNIT_ASSERT(proto.GetString(1) == "str2");
+ UNIT_ASSERT(proto.BytesSize() == 2);
+ UNIT_ASSERT(proto.GetBytes(0) == "transformed_bytes");
+ UNIT_ASSERT(proto.GetBytes(1) == "transformed_bytes");
+ }
+
+ // Check that bytes are transformed, strings are left intact in composed messages
+ {
+ TString modelStr(R"_({"Part": {"String":"value_str", "Bytes": "value_bytes"}})_");
+
+ TCompositeOptional proto;
+ TJson2ProtoConfig config;
+ config.AddStringTransform(new TBytesTransform);
+
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TCompositeOptional>(modelStr, config));
+ UNIT_ASSERT(proto.GetPart().GetString() == "value_str");
+ UNIT_ASSERT(proto.GetPart().GetBytes() == "transformed_bytes");
+ }
+} // TestStringTransforms
+
+Y_UNIT_TEST(TestCastFromString) {
+ // single fields
+ {
+ NJson::TJsonValue json;
+#define DEFINE_FIELD(name, value) \
+ json.InsertValue(#name, ConvertToString(value));
+#include <library/cpp/protobuf/json/ut/fields.incl>
+#undef DEFINE_FIELD
+
+ TFlatOptional proto;
+ UNIT_ASSERT_EXCEPTION_CONTAINS(Json2Proto(json, proto), yexception, "Invalid type");
+
+ TJson2ProtoConfig config;
+ config.SetCastFromString(true);
+ Json2Proto(json, proto, config);
+
+ TFlatOptional modelProto;
+ FillFlatProto(&modelProto);
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+ }
+
+ // repeated fields
+ {
+ NJson::TJsonValue json;
+#define DEFINE_REPEATED_FIELD(name, type, ...) \
+ { \
+ type values[] = {__VA_ARGS__}; \
+ NJson::TJsonValue array(NJson::JSON_ARRAY); \
+ for (size_t i = 0, end = Y_ARRAY_SIZE(values); i < end; ++i) { \
+ array.AppendValue(ConvertToString(values[i])); \
+ } \
+ json.InsertValue(#name, array); \
+ }
+#include <library/cpp/protobuf/json/ut/repeated_fields.incl>
+#undef DEFINE_REPEATED_FIELD
+
+ TFlatRepeated proto;
+ UNIT_ASSERT_EXCEPTION_CONTAINS(Json2Proto(json, proto), yexception, "Invalid type");
+
+ TJson2ProtoConfig config;
+ config.SetCastFromString(true);
+ Json2Proto(json, proto, config);
+
+ TFlatRepeated modelProto;
+ FillRepeatedProto(&modelProto);
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+ }
+} // TestCastFromString
+
+Y_UNIT_TEST(TestMap) {
+ TMapType modelProto;
+
+ auto& items = *modelProto.MutableItems();
+ items["key1"] = "value1";
+ items["key2"] = "value2";
+ items["key3"] = "value3";
+
+ TString modelStr(R"_({"Items":[{"key":"key3","value":"value3"},{"key":"key2","value":"value2"},{"key":"key1","value":"value1"}]})_");
+
+ TJson2ProtoConfig config;
+ TMapType proto;
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TMapType>(modelStr, config));
+
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+} // TestMap
+
+Y_UNIT_TEST(TestCastRobust) {
+ NJson::TJsonValue json;
+ json["I32"] = "5";
+ json["Bool"] = 1;
+ json["String"] = 6;
+ json["Double"] = 8;
+ TFlatOptional proto;
+ UNIT_ASSERT_EXCEPTION_CONTAINS(Json2Proto(json, proto), yexception, "Invalid type");
+
+ TJson2ProtoConfig config;
+ config.SetCastRobust(true);
+ Json2Proto(json, proto, config);
+
+ TFlatOptional expected;
+ expected.SetI32(5);
+ expected.SetBool(true);
+ expected.SetString("6");
+ expected.SetDouble(8);
+ UNIT_ASSERT_PROTOS_EQUAL(proto, expected);
+}
+
+Y_UNIT_TEST(TestVectorizeScalars) {
+ NJson::TJsonValue json;
+#define DEFINE_FIELD(name, value) \
+ json.InsertValue(#name, value);
+#include <library/cpp/protobuf/json/ut/fields.incl>
+#undef DEFINE_FIELD
+
+ TFlatRepeated proto;
+ TJson2ProtoConfig config;
+ config.SetVectorizeScalars(true);
+ Json2Proto(json, proto, config);
+
+#define DEFINE_FIELD(name, value) \
+ UNIT_ASSERT_VALUES_EQUAL(proto.Get ## name(0), value);
+#include <library/cpp/protobuf/json/ut/fields.incl>
+#undef DEFINE_FIELD
+}
+
+Y_UNIT_TEST(TestValueVectorizer) {
+ {
+ // No ValueVectorizer
+ NJson::TJsonValue json;
+ json["RepeatedString"] = "123";
+ TJson2ProtoConfig config;
+ TSingleRepeatedString expected;
+ UNIT_ASSERT_EXCEPTION(Json2Proto(json, expected, config), yexception);
+ }
+ {
+ // ValueVectorizer replace original value by array
+ NJson::TJsonValue json;
+ json["RepeatedString"] = "123";
+ TJson2ProtoConfig config;
+
+ TSingleRepeatedString expected;
+ expected.AddRepeatedString("4");
+ expected.AddRepeatedString("5");
+ expected.AddRepeatedString("6");
+
+ config.ValueVectorizer = [](const NJson::TJsonValue& val) -> NJson::TJsonValue::TArray {
+ Y_UNUSED(val);
+ return {NJson::TJsonValue("4"), NJson::TJsonValue("5"), NJson::TJsonValue("6")};
+ };
+ TSingleRepeatedString actual;
+ Json2Proto(json, actual, config);
+ UNIT_ASSERT_PROTOS_EQUAL(expected, actual);
+ }
+ {
+ // ValueVectorizer replace original value by array and cast
+ NJson::TJsonValue json;
+ json["RepeatedInt"] = 123;
+ TJson2ProtoConfig config;
+
+ TSingleRepeatedInt expected;
+ expected.AddRepeatedInt(4);
+ expected.AddRepeatedInt(5);
+ expected.AddRepeatedInt(6);
+
+ config.ValueVectorizer = [](const NJson::TJsonValue& val) -> NJson::TJsonValue::TArray {
+ Y_UNUSED(val);
+ return {NJson::TJsonValue("4"), NJson::TJsonValue(5), NJson::TJsonValue("6")};
+ };
+ config.CastFromString = true;
+
+ TSingleRepeatedInt actual;
+ Json2Proto(json, actual, config);
+ UNIT_ASSERT_PROTOS_EQUAL(expected, actual);
+ }
+}
+
+Y_UNIT_TEST(TestMapAsObject) {
+ TMapType modelProto;
+
+ auto& items = *modelProto.MutableItems();
+ items["key1"] = "value1";
+ items["key2"] = "value2";
+ items["key3"] = "value3";
+
+ TString modelStr(R"_({"Items":{"key1":"value1","key2":"value2","key3":"value3"}})_");
+
+ TJson2ProtoConfig config;
+ config.MapAsObject = true;
+ TMapType proto;
+ UNIT_ASSERT_NO_EXCEPTION(proto = Json2Proto<TMapType>(modelStr, config));
+
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+} // TestMapAsObject
+
+Y_UNIT_TEST(TestComplexMapAsObject_I32) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableI32();
+ items[1] = 1;
+ items[-2] = -2;
+ items[3] = 3;
+ },
+ R"_({"I32":{"1":1,"-2":-2,"3":3}})_");
+} // TestComplexMapAsObject_I32
+
+Y_UNIT_TEST(TestComplexMapAsObject_I64) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableI64();
+ items[2147483649L] = 2147483649L;
+ items[-2147483650L] = -2147483650L;
+ items[2147483651L] = 2147483651L;
+ },
+ R"_({"I64":{"2147483649":2147483649,"-2147483650":-2147483650,"2147483651":2147483651}})_");
+} // TestComplexMapAsObject_I64
+
+Y_UNIT_TEST(TestComplexMapAsObject_UI32) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableUI32();
+ items[1073741825U] = 1073741825U;
+ items[1073741826U] = 1073741826U;
+ items[1073741827U] = 1073741827U;
+ },
+ R"_({"UI32":{"1073741825":1073741825,"1073741826":1073741826,"1073741827":1073741827}})_");
+} // TestComplexMapAsObject_UI32
+
+Y_UNIT_TEST(TestComplexMapAsObject_UI64) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableUI64();
+ items[9223372036854775809UL] = 9223372036854775809UL;
+ items[9223372036854775810UL] = 9223372036854775810UL;
+ items[9223372036854775811UL] = 9223372036854775811UL;
+ },
+ R"_({"UI64":{"9223372036854775809":9223372036854775809,"9223372036854775810":9223372036854775810,"9223372036854775811":9223372036854775811}})_");
+} // TestComplexMapAsObject_UI64
+
+Y_UNIT_TEST(TestComplexMapAsObject_SI32) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableSI32();
+ items[1] = 1;
+ items[-2] = -2;
+ items[3] = 3;
+ },
+ R"_({"SI32":{"1":1,"-2":-2,"3":3}})_");
+} // TestComplexMapAsObject_SI32
+
+Y_UNIT_TEST(TestComplexMapAsObject_SI64) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableSI64();
+ items[2147483649L] = 2147483649L;
+ items[-2147483650L] = -2147483650L;
+ items[2147483651L] = 2147483651L;
+ },
+ R"_({"SI64":{"2147483649":2147483649,"-2147483650":-2147483650,"2147483651":2147483651}})_");
+} // TestComplexMapAsObject_SI64
+
+Y_UNIT_TEST(TestComplexMapAsObject_FI32) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableFI32();
+ items[1073741825U] = 1073741825U;
+ items[1073741826U] = 1073741826U;
+ items[1073741827U] = 1073741827U;
+ },
+ R"_({"FI32":{"1073741825":1073741825,"1073741826":1073741826,"1073741827":1073741827}})_");
+} // TestComplexMapAsObject_FI32
+
+Y_UNIT_TEST(TestComplexMapAsObject_FI64) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableFI64();
+ items[9223372036854775809UL] = 9223372036854775809UL;
+ items[9223372036854775810UL] = 9223372036854775810UL;
+ items[9223372036854775811UL] = 9223372036854775811UL;
+ },
+ R"_({"FI64":{"9223372036854775809":9223372036854775809,"9223372036854775810":9223372036854775810,"9223372036854775811":9223372036854775811}})_");
+} // TestComplexMapAsObject_FI64
+
+Y_UNIT_TEST(TestComplexMapAsObject_SFI32) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableSFI32();
+ items[1] = 1;
+ items[-2] = -2;
+ items[3] = 3;
+ },
+ R"_({"SFI32":{"1":1,"-2":-2,"3":3}})_");
+} // TestComplexMapAsObject_SFI32
+
+Y_UNIT_TEST(TestComplexMapAsObject_SFI64) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableSFI64();
+ items[2147483649L] = 2147483649L;
+ items[-2147483650L] = -2147483650L;
+ items[2147483651L] = 2147483651L;
+ },
+ R"_({"SFI64":{"2147483649":2147483649,"-2147483650":-2147483650,"2147483651":2147483651}})_");
+} // TestComplexMapAsObject_SFI64
+
+Y_UNIT_TEST(TestComplexMapAsObject_Bool) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableBool();
+ items[true] = true;
+ items[false] = false;
+ },
+ R"_({"Bool":{"true":true,"false":false}})_");
+} // TestComplexMapAsObject_Bool
+
+Y_UNIT_TEST(TestComplexMapAsObject_String) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableString();
+ items["key1"] = "value1";
+ items["key2"] = "value2";
+ items["key3"] = "value3";
+ items[""] = "value4";
+ },
+ R"_({"String":{"key1":"value1","key2":"value2","key3":"value3","":"value4"}})_");
+} // TestComplexMapAsObject_String
+
+Y_UNIT_TEST(TestComplexMapAsObject_Enum) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableEnum();
+ items["key1"] = EEnum::E_1;
+ items["key2"] = EEnum::E_2;
+ items["key3"] = EEnum::E_3;
+ },
+ R"_({"Enum":{"key1":1,"key2":2,"key3":3}})_");
+} // TestComplexMapAsObject_Enum
+
+Y_UNIT_TEST(TestComplexMapAsObject_EnumString) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableEnum();
+ items["key1"] = EEnum::E_1;
+ items["key2"] = EEnum::E_2;
+ items["key3"] = EEnum::E_3;
+ },
+ R"_({"Enum":{"key1":"E_1","key2":"E_2","key3":"E_3"}})_");
+} // TestComplexMapAsObject_EnumString
+
+Y_UNIT_TEST(TestComplexMapAsObject_EnumStringCaseInsensetive) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableEnum();
+ items["key1"] = EEnum::E_1;
+ items["key2"] = EEnum::E_2;
+ items["key3"] = EEnum::E_3;
+ },
+ R"_({"Enum":{"key1":"e_1","key2":"E_2","key3":"e_3"}})_",
+ TJson2ProtoConfig()
+ .SetMapAsObject(true)
+ .SetEnumValueMode(NProtobufJson::TJson2ProtoConfig::EnumCaseInsensetive)
+ );
+} // TestComplexMapAsObject_EnumStringCaseInsensetive
+
+Y_UNIT_TEST(TestComplexMapAsObject_EnumStringSnakeCaseInsensitive) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableEnum();
+ items["key1"] = EEnum::E_1;
+ items["key2"] = EEnum::E_2;
+ items["key3"] = EEnum::E_3;
+ },
+ R"_({"Enum":{"key1":"e1","key2":"_E_2_","key3":"e_3"}})_",
+ TJson2ProtoConfig()
+ .SetMapAsObject(true)
+ .SetEnumValueMode(NProtobufJson::TJson2ProtoConfig::EnumSnakeCaseInsensitive)
+ );
+} // TestComplexMapAsObject_EnumStringCaseInsensetive
+
+Y_UNIT_TEST(TestComplexMapAsObject_Float) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableFloat();
+ items["key1"] = 0.1f;
+ items["key2"] = 0.2f;
+ items["key3"] = 0.3f;
+ },
+ R"_({"Float":{"key1":0.1,"key2":0.2,"key3":0.3}})_");
+} // TestComplexMapAsObject_Float
+
+Y_UNIT_TEST(TestComplexMapAsObject_Double) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ auto& items = *proto.MutableDouble();
+ items["key1"] = 0.1L;
+ items["key2"] = 0.2L;
+ items["key3"] = 0.3L;
+ },
+ R"_({"Double":{"key1":0.1,"key2":0.2,"key3":0.3}})_");
+} // TestComplexMapAsObject_Double
+
+Y_UNIT_TEST(TestComplexMapAsObject_Nested) {
+ TestComplexMapAsObject(
+ [](TComplexMapType& proto) {
+ TComplexMapType inner;
+ auto& innerItems = *inner.MutableString();
+ innerItems["key"] = "value";
+ auto& items = *proto.MutableNested();
+ items["key1"] = inner;
+ items["key2"] = inner;
+ items["key3"] = inner;
+ },
+ R"_({"Nested":{"key1":{"String":{"key":"value"}},"key2":{"String":{"key":"value"}},"key3":{"String":{"key":"value"}}}})_");
+} // TestComplexMapAsObject_Nested
+
+Y_UNIT_TEST(TestMapAsObjectConfigNotSet) {
+ TString modelStr(R"_({"Items":{"key":"value"}})_");
+
+ TJson2ProtoConfig config;
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ Json2Proto<TMapType>(modelStr, config), yexception,
+ "Map as object representation is not allowed");
+} // TestMapAsObjectNotSet
+
+Y_UNIT_TEST(TestMergeFlatOptional) {
+ const NJson::TJsonValue& json = CreateFlatJson();
+
+ NJson::TJsonValue patch;
+ patch["I32"] = 5;
+ patch["Bool"] = false;
+ patch["String"] = "abacaba";
+ patch["Double"] = 0.123;
+
+ TFlatOptional proto;
+ UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto));
+ UNIT_ASSERT_NO_EXCEPTION(MergeJson2Proto(patch, proto));
+
+ TFlatRequired modelProto;
+ FillFlatProto(&modelProto);
+ modelProto.SetI32(5);
+ modelProto.SetBool(false);
+ modelProto.SetString("abacaba");
+ modelProto.SetDouble(0.123);
+
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+} // TestMergeFlatOptional
+
+Y_UNIT_TEST(TestMergeFlatRequired) {
+ const NJson::TJsonValue& json = CreateFlatJson();
+
+ NJson::TJsonValue patch;
+ patch["I32"] = 5;
+ patch["Bool"] = false;
+ patch["String"] = "abacaba";
+ patch["Double"] = 0.123;
+
+ TFlatRequired proto;
+ UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto));
+ UNIT_ASSERT_NO_EXCEPTION(MergeJson2Proto(patch, proto));
+
+ TFlatRequired modelProto;
+ FillFlatProto(&modelProto);
+ modelProto.SetI32(5);
+ modelProto.SetBool(false);
+ modelProto.SetString("abacaba");
+ modelProto.SetDouble(0.123);
+
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+} // TestMergeFlatRequired
+
+Y_UNIT_TEST(TestMergeComposite) {
+ const NJson::TJsonValue& json = CreateCompositeJson();
+
+ NJson::TJsonValue patch;
+ patch["Part"]["I32"] = 5;
+ patch["Part"]["Bool"] = false;
+ patch["Part"]["String"] = "abacaba";
+ patch["Part"]["Double"] = 0.123;
+
+ TCompositeOptional proto;
+ UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto));
+ UNIT_ASSERT_NO_EXCEPTION(MergeJson2Proto(patch, proto));
+
+ TCompositeOptional modelProto;
+ FillCompositeProto(&modelProto);
+ modelProto.MutablePart()->SetI32(5);
+ modelProto.MutablePart()->SetBool(false);
+ modelProto.MutablePart()->SetString("abacaba");
+ modelProto.MutablePart()->SetDouble(0.123);
+
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+} // TestMergeComposite
+
+Y_UNIT_TEST(TestMergeRepeatedReplace) {
+ const NJson::TJsonValue& json = CreateRepeatedFlatJson();
+
+ NJson::TJsonValue patch;
+ patch["I32"].AppendValue(5);
+ patch["I32"].AppendValue(6);
+ patch["String"].AppendValue("abacaba");
+
+ TFlatRepeated proto;
+ TJson2ProtoConfig config;
+ config.ReplaceRepeatedFields = true;
+ UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto));
+ UNIT_ASSERT_NO_EXCEPTION(MergeJson2Proto(patch, proto, config));
+
+ TFlatRepeated modelProto;
+ FillRepeatedProto(&modelProto);
+ modelProto.ClearI32();
+ modelProto.AddI32(5);
+ modelProto.AddI32(6);
+ modelProto.ClearString();
+ modelProto.AddString("abacaba");
+
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+} // TestMergeRepeatedReplace
+
+Y_UNIT_TEST(TestMergeRepeatedAppend) {
+ const NJson::TJsonValue& json = CreateRepeatedFlatJson();
+
+ NJson::TJsonValue patch;
+ patch["I32"].AppendValue(5);
+ patch["I32"].AppendValue(6);
+ patch["String"].AppendValue("abacaba");
+
+ TFlatRepeated proto;
+ UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto));
+ UNIT_ASSERT_NO_EXCEPTION(MergeJson2Proto(patch, proto));
+
+ TFlatRepeated modelProto;
+ FillRepeatedProto(&modelProto);
+ modelProto.AddI32(5);
+ modelProto.AddI32(6);
+ modelProto.AddString("abacaba");
+
+ UNIT_ASSERT_PROTOS_EQUAL(proto, modelProto);
+} // TestMergeRepeatedAppend
+
+Y_UNIT_TEST(TestEmptyStringForCastFromString) {
+ NJson::TJsonValue json;
+ json["I32"] = "";
+ json["Bool"] = "";
+ json["OneString"] = "";
+
+ TJson2ProtoConfig config;
+ config.SetCastFromString(true);
+ config.SetDoNotCastEmptyStrings(true);
+ TFlatOptional proto;
+ UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto, config));
+ UNIT_ASSERT(!proto.HasBool());
+ UNIT_ASSERT(!proto.HasI32());
+ UNIT_ASSERT(proto.HasOneString());
+ UNIT_ASSERT_EQUAL("", proto.GetOneString());
+} // TestEmptyStringForCastFromString
+
+Y_UNIT_TEST(TestAllowComments) {
+ constexpr TStringBuf json = R"(
+{
+ "I32": 4, // comment1
+/*
+ comment2
+ {}
+ qwer
+*/
+ "I64": 3423
+}
+
+)";
+
+ TJson2ProtoConfig config;
+ TFlatOptional proto;
+ UNIT_ASSERT_EXCEPTION_CONTAINS(Json2Proto(json, proto, config), yexception, "Error: Missing a name for object member");
+
+ config.SetAllowComments(true);
+ UNIT_ASSERT_NO_EXCEPTION(Json2Proto(json, proto, config));
+ UNIT_ASSERT_VALUES_EQUAL(proto.GetI32(), 4);
+ UNIT_ASSERT_VALUES_EQUAL(proto.GetI64(), 3423);
+} // TestAllowComments
+
+} // TJson2ProtoTest
diff --git a/library/cpp/protobuf/json/ut/proto.h b/library/cpp/protobuf/json/ut/proto.h
new file mode 100644
index 0000000000..8183bfc8e1
--- /dev/null
+++ b/library/cpp/protobuf/json/ut/proto.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include <util/generic/hash_set.h>
+#include <util/generic/string.h>
+
+#include <util/system/defaults.h>
+
+namespace NProtobufJsonTest {
+ template <typename TProto>
+ inline void
+ FillFlatProto(TProto* proto,
+ const THashSet<TString>& skippedFields = THashSet<TString>()) {
+#define DEFINE_FIELD(name, value) \
+ if (skippedFields.find(#name) == skippedFields.end()) \
+ proto->Set##name(value);
+#include <library/cpp/protobuf/json/ut/fields.incl>
+#undef DEFINE_FIELD
+ }
+
+ template <typename TRepeatedField, typename TValue>
+ inline void
+ AddValue(TRepeatedField* field, TValue value) {
+ field->Add(value);
+ }
+
+ inline void
+ AddValue(google::protobuf::RepeatedPtrField<TString>* field, const TString& value) {
+ *(field->Add()) = value;
+ }
+
+ inline void
+ FillRepeatedProto(TFlatRepeated* proto,
+ const THashSet<TString>& skippedFields = THashSet<TString>()) {
+#define DEFINE_REPEATED_FIELD(name, type, ...) \
+ if (skippedFields.find(#name) == skippedFields.end()) { \
+ type values[] = {__VA_ARGS__}; \
+ for (size_t i = 0, end = Y_ARRAY_SIZE(values); i < end; ++i) { \
+ AddValue(proto->Mutable##name(), values[i]); \
+ } \
+ }
+#include <library/cpp/protobuf/json/ut/repeated_fields.incl>
+#undef DEFINE_REPEATED_FIELD
+ }
+
+ template <typename TProto>
+ inline void
+ FillCompositeProto(TProto* proto, const THashSet<TString>& skippedFields = THashSet<TString>()) {
+ FillFlatProto(proto->MutablePart(), skippedFields);
+ }
+
+#define UNIT_ASSERT_PROTOS_EQUAL(lhs, rhs) \
+ do { \
+ if (lhs.SerializeAsString() != rhs.SerializeAsString()) { \
+ Cerr << ">>>>>>>>>> lhs != rhs:" << Endl; \
+ Cerr << lhs.DebugString() << Endl; \
+ Cerr << rhs.DebugString() << Endl; \
+ UNIT_ASSERT_STRINGS_EQUAL(lhs.DebugString(), rhs.DebugString()); \
+ UNIT_ASSERT_STRINGS_EQUAL(lhs.SerializeAsString(), rhs.SerializeAsString()); \
+ } \
+ } while (false);
+
+}
diff --git a/library/cpp/protobuf/json/ut/proto2json_ut.cpp b/library/cpp/protobuf/json/ut/proto2json_ut.cpp
new file mode 100644
index 0000000000..07e52d7f2f
--- /dev/null
+++ b/library/cpp/protobuf/json/ut/proto2json_ut.cpp
@@ -0,0 +1,1022 @@
+#include "json.h"
+#include "proto.h"
+
+#include <library/cpp/protobuf/json/ut/test.pb.h>
+
+#include <library/cpp/json/json_value.h>
+#include <library/cpp/json/json_reader.h>
+#include <library/cpp/json/json_writer.h>
+
+#include <library/cpp/protobuf/json/proto2json.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/hash_set.h>
+#include <util/generic/string.h>
+#include <util/generic/ylimits.h>
+
+#include <util/stream/str.h>
+
+#include <util/system/defaults.h>
+#include <util/system/yassert.h>
+
+#include <limits>
+
+using namespace NProtobufJson;
+using namespace NProtobufJsonTest;
+
+Y_UNIT_TEST_SUITE(TProto2JsonFlatTest) {
+ Y_UNIT_TEST(TestFlatDefault) {
+ using namespace ::google::protobuf;
+ TFlatDefault proto;
+ NJson::TJsonValue json;
+ TProto2JsonConfig cfg;
+ cfg.SetMissingSingleKeyMode(TProto2JsonConfig::MissingKeyDefault);
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json, cfg));
+#define DEFINE_FIELD(name, value) \
+ { \
+ auto descr = proto.GetMetadata().descriptor->FindFieldByName(#name); \
+ UNIT_ASSERT(descr); \
+ UNIT_ASSERT(json.Has(#name)); \
+ switch (descr->cpp_type()) { \
+ case FieldDescriptor::CPPTYPE_INT32: \
+ UNIT_ASSERT(descr->default_value_int32() == json[#name].GetIntegerRobust()); \
+ break; \
+ case FieldDescriptor::CPPTYPE_INT64: \
+ UNIT_ASSERT(descr->default_value_int64() == json[#name].GetIntegerRobust()); \
+ break; \
+ case FieldDescriptor::CPPTYPE_UINT32: \
+ UNIT_ASSERT(descr->default_value_uint32() == json[#name].GetUIntegerRobust()); \
+ break; \
+ case FieldDescriptor::CPPTYPE_UINT64: \
+ UNIT_ASSERT(descr->default_value_uint32() == json[#name].GetUIntegerRobust()); \
+ break; \
+ case FieldDescriptor::CPPTYPE_DOUBLE: \
+ UNIT_ASSERT(descr->default_value_double() == json[#name].GetDoubleRobust()); \
+ break; \
+ case FieldDescriptor::CPPTYPE_FLOAT: \
+ UNIT_ASSERT(descr->default_value_float() == json[#name].GetDoubleRobust()); \
+ break; \
+ case FieldDescriptor::CPPTYPE_BOOL: \
+ UNIT_ASSERT(descr->default_value_bool() == json[#name].GetBooleanRobust()); \
+ break; \
+ case FieldDescriptor::CPPTYPE_ENUM: \
+ UNIT_ASSERT(descr->default_value_enum()->number() == json[#name].GetIntegerRobust()); \
+ break; \
+ case FieldDescriptor::CPPTYPE_STRING: \
+ UNIT_ASSERT(descr->default_value_string() == json[#name].GetStringRobust()); \
+ break; \
+ default: \
+ break; \
+ } \
+ }
+#include <library/cpp/protobuf/json/ut/fields.incl>
+#undef DEFINE_FIELD
+ }
+
+ Y_UNIT_TEST(TestNameGenerator) {
+ TNameGeneratorType proto;
+ proto.SetField(42);
+
+ TProto2JsonConfig cfg;
+ cfg.SetNameGenerator([](const NProtoBuf::FieldDescriptor&) { return "42"; });
+
+ TStringStream str;
+ Proto2Json(proto, str, cfg);
+
+ UNIT_ASSERT_STRINGS_EQUAL(R"({"42":42})", str.Str());
+ }
+
+ Y_UNIT_TEST(TestEnumValueGenerator) {
+ TEnumValueGeneratorType proto;
+ proto.SetEnum(TEnumValueGeneratorType::ENUM_42);
+
+ TProto2JsonConfig cfg;
+ cfg.SetEnumValueGenerator([](const NProtoBuf::EnumValueDescriptor&) { return "42"; });
+
+ TStringStream str;
+ Proto2Json(proto, str, cfg);
+
+ UNIT_ASSERT_STRINGS_EQUAL(R"({"Enum":"42"})", str.Str());
+ }
+
+ Y_UNIT_TEST(TestFlatOptional){
+ {TFlatOptional proto;
+ FillFlatProto(&proto);
+ const NJson::TJsonValue& modelJson = CreateFlatJson();
+ {
+ NJson::TJsonValue json;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+
+ {
+ TStringStream jsonStream;
+ NJson::TJsonValue json;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStream));
+ UNIT_ASSERT(ReadJsonTree(&jsonStream, &json));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ } // streamed
+}
+
+ // Try to skip each field
+#define DEFINE_FIELD(name, value) \
+ { \
+ THashSet<TString> skippedField; \
+ skippedField.insert(#name); \
+ TFlatOptional proto; \
+ FillFlatProto(&proto, skippedField); \
+ const NJson::TJsonValue& modelJson = CreateFlatJson(skippedField); \
+ NJson::TJsonValue json; \
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json)); \
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson); \
+ { \
+ TStringStream jsonStream; \
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStream)); \
+ UNIT_ASSERT(ReadJsonTree(&jsonStream, &json)); \
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson); \
+ } \
+ }
+#include <library/cpp/protobuf/json/ut/fields.incl>
+#undef DEFINE_FIELD
+} // TestFlatOptional
+
+Y_UNIT_TEST(TestFlatRequired){
+ {TFlatRequired proto;
+FillFlatProto(&proto);
+const NJson::TJsonValue& modelJson = CreateFlatJson();
+{
+ NJson::TJsonValue json;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+}
+
+{
+ TStringStream jsonStream;
+ NJson::TJsonValue json;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStream));
+ UNIT_ASSERT(ReadJsonTree(&jsonStream, &json));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+} // streamed
+}
+
+// Try to skip each field
+#define DEFINE_FIELD(name, value) \
+ { \
+ THashSet<TString> skippedField; \
+ skippedField.insert(#name); \
+ TFlatRequired proto; \
+ FillFlatProto(&proto, skippedField); \
+ const NJson::TJsonValue& modelJson = CreateFlatJson(skippedField); \
+ NJson::TJsonValue json; \
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json)); \
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson); \
+ { \
+ TStringStream jsonStream; \
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStream)); \
+ UNIT_ASSERT(ReadJsonTree(&jsonStream, &json)); \
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson); \
+ } \
+ }
+#include <library/cpp/protobuf/json/ut/fields.incl>
+#undef DEFINE_FIELD
+} // TestFlatRequired
+
+Y_UNIT_TEST(TestFlatRepeated) {
+ {
+ TFlatRepeated proto;
+ FillRepeatedProto(&proto);
+ const NJson::TJsonValue& modelJson = CreateRepeatedFlatJson();
+ {
+ NJson::TJsonValue json;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+
+ {
+ TStringStream jsonStream;
+ NJson::TJsonValue json;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStream));
+ UNIT_ASSERT(ReadJsonTree(&jsonStream, &json));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ } // streamed
+ }
+
+ TProto2JsonConfig config;
+ config.SetMissingRepeatedKeyMode(TProto2JsonConfig::MissingKeySkip);
+
+ // Try to skip each field
+#define DEFINE_REPEATED_FIELD(name, ...) \
+ { \
+ THashSet<TString> skippedField; \
+ skippedField.insert(#name); \
+ TFlatRepeated proto; \
+ FillRepeatedProto(&proto, skippedField); \
+ const NJson::TJsonValue& modelJson = CreateRepeatedFlatJson(skippedField); \
+ NJson::TJsonValue json; \
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json, config)); \
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson); \
+ { \
+ TStringStream jsonStream; \
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStream, config)); \
+ UNIT_ASSERT(ReadJsonTree(&jsonStream, &json)); \
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson); \
+ } \
+ }
+#include <library/cpp/protobuf/json/ut/repeated_fields.incl>
+#undef DEFINE_REPEATED_FIELD
+} // TestFlatRepeated
+
+Y_UNIT_TEST(TestCompositeOptional){
+ {TCompositeOptional proto;
+FillCompositeProto(&proto);
+const NJson::TJsonValue& modelJson = CreateCompositeJson();
+{
+ NJson::TJsonValue json;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+}
+
+{
+ TStringStream jsonStream;
+ NJson::TJsonValue json;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStream));
+ UNIT_ASSERT(ReadJsonTree(&jsonStream, &json));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+} // streamed
+}
+
+// Try to skip each field
+#define DEFINE_FIELD(name, value) \
+ { \
+ THashSet<TString> skippedField; \
+ skippedField.insert(#name); \
+ TCompositeOptional proto; \
+ FillCompositeProto(&proto, skippedField); \
+ const NJson::TJsonValue& modelJson = CreateCompositeJson(skippedField); \
+ NJson::TJsonValue json; \
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json)); \
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson); \
+ { \
+ TStringStream jsonStream; \
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStream)); \
+ UNIT_ASSERT(ReadJsonTree(&jsonStream, &json)); \
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson); \
+ } \
+ }
+#include <library/cpp/protobuf/json/ut/fields.incl>
+#undef DEFINE_FIELD
+} // TestCompositeOptional
+
+Y_UNIT_TEST(TestCompositeRequired){
+ {TCompositeRequired proto;
+FillCompositeProto(&proto);
+const NJson::TJsonValue& modelJson = CreateCompositeJson();
+{
+ NJson::TJsonValue json;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+}
+
+{
+ TStringStream jsonStream;
+ NJson::TJsonValue json;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStream));
+ UNIT_ASSERT(ReadJsonTree(&jsonStream, &json));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+} // streamed
+}
+
+// Try to skip each field
+#define DEFINE_FIELD(name, value) \
+ { \
+ THashSet<TString> skippedField; \
+ skippedField.insert(#name); \
+ TCompositeRequired proto; \
+ FillCompositeProto(&proto, skippedField); \
+ const NJson::TJsonValue& modelJson = CreateCompositeJson(skippedField); \
+ NJson::TJsonValue json; \
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json)); \
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson); \
+ { \
+ TStringStream jsonStream; \
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStream)); \
+ UNIT_ASSERT(ReadJsonTree(&jsonStream, &json)); \
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson); \
+ } \
+ }
+#include <library/cpp/protobuf/json/ut/fields.incl>
+#undef DEFINE_FIELD
+} // TestCompositeRequired
+
+Y_UNIT_TEST(TestCompositeRepeated) {
+ {
+ TFlatOptional partProto;
+ FillFlatProto(&partProto);
+ TCompositeRepeated proto;
+ proto.AddPart()->CopyFrom(partProto);
+
+ NJson::TJsonValue modelJson;
+ NJson::TJsonValue modelArray;
+ modelArray.AppendValue(CreateFlatJson());
+ modelJson.InsertValue("Part", modelArray);
+ {
+ NJson::TJsonValue json;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+
+ {
+ TStringStream jsonStream;
+ NJson::TJsonValue json;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStream));
+ UNIT_ASSERT(ReadJsonTree(&jsonStream, &json));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ } // streamed
+ }
+
+ {
+ // Array of messages with each field skipped
+ TCompositeRepeated proto;
+ NJson::TJsonValue modelArray;
+
+#define DEFINE_REPEATED_FIELD(name, ...) \
+ { \
+ THashSet<TString> skippedField; \
+ skippedField.insert(#name); \
+ TFlatOptional partProto; \
+ FillFlatProto(&partProto, skippedField); \
+ proto.AddPart()->CopyFrom(partProto); \
+ modelArray.AppendValue(CreateFlatJson(skippedField)); \
+ }
+#include <library/cpp/protobuf/json/ut/repeated_fields.incl>
+#undef DEFINE_REPEATED_FIELD
+
+ NJson::TJsonValue modelJson;
+ modelJson.InsertValue("Part", modelArray);
+
+ {
+ NJson::TJsonValue json;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+
+ {
+ TStringStream jsonStream;
+ NJson::TJsonValue json;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStream));
+ UNIT_ASSERT(ReadJsonTree(&jsonStream, &json));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ } // streamed
+ }
+} // TestCompositeRepeated
+
+Y_UNIT_TEST(TestEnumConfig) {
+ {
+ TFlatOptional proto;
+ proto.SetEnum(E_1);
+ NJson::TJsonValue modelJson;
+ modelJson.InsertValue("Enum", 1);
+ NJson::TJsonValue json;
+ TProto2JsonConfig config;
+ config.EnumMode = TProto2JsonConfig::EnumNumber;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json, config));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+
+ {
+ TFlatOptional proto;
+ proto.SetEnum(E_1);
+ NJson::TJsonValue modelJson;
+ modelJson.InsertValue("Enum", "E_1");
+ NJson::TJsonValue json;
+ TProto2JsonConfig config;
+ config.EnumMode = TProto2JsonConfig::EnumName;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json, config));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+
+ {
+ TFlatOptional proto;
+ proto.SetEnum(E_1);
+ NJson::TJsonValue modelJson;
+ modelJson.InsertValue("Enum", "NProtobufJsonTest.E_1");
+ NJson::TJsonValue json;
+ TProto2JsonConfig config;
+ config.EnumMode = TProto2JsonConfig::EnumFullName;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json, config));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+
+ {
+ TFlatOptional proto;
+ proto.SetEnum(E_1);
+ NJson::TJsonValue modelJson;
+ modelJson.InsertValue("Enum", "e_1");
+ NJson::TJsonValue json;
+ TProto2JsonConfig config;
+ config.EnumMode = TProto2JsonConfig::EnumNameLowerCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json, config));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+
+ {
+ TFlatOptional proto;
+ proto.SetEnum(E_1);
+ NJson::TJsonValue modelJson;
+ modelJson.InsertValue("Enum", "nprotobufjsontest.e_1");
+ NJson::TJsonValue json;
+ TProto2JsonConfig config;
+ config.EnumMode = TProto2JsonConfig::EnumFullNameLowerCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json, config));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+} // TestEnumConfig
+
+Y_UNIT_TEST(TestMissingSingleKeyConfig) {
+ {
+ TFlatOptional proto;
+ NJson::TJsonValue modelJson(NJson::JSON_MAP);
+ NJson::TJsonValue json;
+ TProto2JsonConfig config;
+ config.MissingSingleKeyMode = TProto2JsonConfig::MissingKeySkip;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json, config));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+
+ {
+ NJson::TJsonValue modelJson;
+#define DEFINE_FIELD(name, value) \
+ modelJson.InsertValue(#name, NJson::TJsonValue(NJson::JSON_NULL));
+#include <library/cpp/protobuf/json/ut/fields.incl>
+#undef DEFINE_FIELD
+
+ TFlatOptional proto;
+ NJson::TJsonValue json;
+ TProto2JsonConfig config;
+ config.MissingSingleKeyMode = TProto2JsonConfig::MissingKeyNull;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json, config));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+ {
+ // Test MissingKeyExplicitDefaultThrowRequired for non explicit default values.
+ TFlatOptional proto;
+ NJson::TJsonValue modelJson(NJson::JSON_MAP);
+ NJson::TJsonValue json;
+ TProto2JsonConfig config;
+ config.MissingSingleKeyMode = TProto2JsonConfig::MissingKeyExplicitDefaultThrowRequired;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json, config));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+ {
+ // Test MissingKeyExplicitDefaultThrowRequired for explicit default values.
+ NJson::TJsonValue modelJson;
+ modelJson["String"] = "value";
+
+ TSingleDefaultString proto;
+ NJson::TJsonValue json;
+ TProto2JsonConfig config;
+ config.MissingSingleKeyMode = TProto2JsonConfig::MissingKeyExplicitDefaultThrowRequired;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json, config));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+ {
+ // Test MissingKeyExplicitDefaultThrowRequired for empty required values.
+ TFlatRequired proto;
+ NJson::TJsonValue json;
+ TProto2JsonConfig config;
+ config.MissingSingleKeyMode = TProto2JsonConfig::MissingKeyExplicitDefaultThrowRequired;
+ UNIT_ASSERT_EXCEPTION_CONTAINS(Proto2Json(proto, json, config), yexception, "Empty required protobuf field");
+ }
+ {
+ // Test MissingKeyExplicitDefaultThrowRequired for required value.
+ TSingleRequiredString proto;
+ NJson::TJsonValue json;
+ TProto2JsonConfig config;
+ config.MissingSingleKeyMode = TProto2JsonConfig::MissingKeyExplicitDefaultThrowRequired;
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(Proto2Json(proto, json, config), yexception, "Empty required protobuf field");
+
+ NJson::TJsonValue modelJson;
+ modelJson["String"] = "value";
+ proto.SetString("value");
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json, config));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+} // TestMissingSingleKeyConfig
+
+Y_UNIT_TEST(TestMissingRepeatedKeyNoConfig) {
+ {
+ TFlatRepeated proto;
+ NJson::TJsonValue modelJson(NJson::JSON_MAP);
+ NJson::TJsonValue json;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+} // TestMissingRepeatedKeyNoConfig
+
+Y_UNIT_TEST(TestMissingRepeatedKeyConfig) {
+ {
+ TFlatRepeated proto;
+ NJson::TJsonValue modelJson(NJson::JSON_MAP);
+ NJson::TJsonValue json;
+ TProto2JsonConfig config;
+ config.MissingRepeatedKeyMode = TProto2JsonConfig::MissingKeySkip;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json, config));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+
+ {
+ NJson::TJsonValue modelJson;
+#define DEFINE_FIELD(name, value) \
+ modelJson.InsertValue(#name, NJson::TJsonValue(NJson::JSON_NULL));
+#include <library/cpp/protobuf/json/ut/fields.incl>
+#undef DEFINE_FIELD
+
+ TFlatRepeated proto;
+ NJson::TJsonValue json;
+ TProto2JsonConfig config;
+ config.MissingRepeatedKeyMode = TProto2JsonConfig::MissingKeyNull;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json, config));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+ {
+ TFlatRepeated proto;
+ NJson::TJsonValue modelJson(NJson::JSON_MAP);
+ NJson::TJsonValue json;
+ TProto2JsonConfig config;
+ config.MissingRepeatedKeyMode = TProto2JsonConfig::MissingKeyExplicitDefaultThrowRequired;
+
+ // SHould be same as MissingKeySkip
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, json, config));
+ UNIT_ASSERT_JSONS_EQUAL(json, modelJson);
+ }
+} // TestMissingRepeatedKeyConfig
+
+Y_UNIT_TEST(TestEscaping) {
+ // No escape
+ {
+ TString modelStr(R"_({"String":"value\""})_");
+
+ TFlatOptional proto;
+ proto.SetString(R"_(value")_");
+ TStringStream jsonStr;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+
+ // TEscapeJTransform
+ {
+ TString modelStr(R"_({"String":"value\""})_");
+
+ TFlatOptional proto;
+ proto.SetString(R"_(value")_");
+ TProto2JsonConfig config;
+ config.StringTransforms.push_back(new TEscapeJTransform<false, true>());
+ TStringStream jsonStr;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(modelStr, jsonStr.Str());
+ }
+
+ // TCEscapeTransform
+ {
+ TString modelStr(R"_({"String":"value\""})_");
+
+ TFlatOptional proto;
+ proto.SetString(R"_(value")_");
+ TProto2JsonConfig config;
+ config.StringTransforms.push_back(new TCEscapeTransform());
+ TStringStream jsonStr;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+
+ // TSafeUtf8CEscapeTransform
+ {
+ TString modelStr(R"_({"String":"value\""})_");
+
+ TFlatOptional proto;
+ proto.SetString(R"_(value")_");
+ TProto2JsonConfig config;
+ config.StringTransforms.push_back(new TSafeUtf8CEscapeTransform());
+ TStringStream jsonStr;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+} // TestEscaping
+
+class TBytesTransform: public IStringTransform {
+public:
+ int GetType() const override {
+ return 0;
+ }
+ void Transform(TString&) const override {
+ }
+ void TransformBytes(TString& str) const override {
+ str = "bytes";
+ }
+};
+
+Y_UNIT_TEST(TestBytesTransform) {
+ // Test that string field is not changed
+ {
+ TString modelStr(R"_({"String":"value"})_");
+
+ TFlatOptional proto;
+ proto.SetString(R"_(value)_");
+ TProto2JsonConfig config;
+ config.StringTransforms.push_back(new TBytesTransform());
+ TStringStream jsonStr;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+
+ // Test that bytes field is changed
+ {
+ TString modelStr(R"_({"Bytes":"bytes"})_");
+
+ TFlatOptional proto;
+ proto.SetBytes(R"_(value)_");
+ TProto2JsonConfig config;
+ config.StringTransforms.push_back(new TBytesTransform());
+ TStringStream jsonStr;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+}
+
+Y_UNIT_TEST(TestFieldNameMode) {
+ // Original case 1
+ {
+ TString modelStr(R"_({"String":"value"})_");
+
+ TFlatOptional proto;
+ proto.SetString("value");
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+
+ // Original case 2
+ {
+ TString modelStr(R"_({"String":"value"})_");
+
+ TFlatOptional proto;
+ proto.SetString("value");
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+ config.FieldNameMode = TProto2JsonConfig::FieldNameOriginalCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+
+ // Lowercase
+ {
+ TString modelStr(R"_({"string":"value"})_");
+
+ TFlatOptional proto;
+ proto.SetString("value");
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+ config.FieldNameMode = TProto2JsonConfig::FieldNameLowerCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+
+ // Uppercase
+ {
+ TString modelStr(R"_({"STRING":"value"})_");
+
+ TFlatOptional proto;
+ proto.SetString("value");
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+ config.FieldNameMode = TProto2JsonConfig::FieldNameUpperCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+
+ // Camelcase
+ {
+ TString modelStr(R"_({"string":"value"})_");
+
+ TFlatOptional proto;
+ proto.SetString("value");
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+ config.FieldNameMode = TProto2JsonConfig::FieldNameCamelCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+ {
+ TString modelStr(R"_({"oneString":"value"})_");
+
+ TFlatOptional proto;
+ proto.SetOneString("value");
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+ config.FieldNameMode = TProto2JsonConfig::FieldNameCamelCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+ {
+ TString modelStr(R"_({"oneTwoString":"value"})_");
+
+ TFlatOptional proto;
+ proto.SetOneTwoString("value");
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+ config.FieldNameMode = TProto2JsonConfig::FieldNameCamelCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+
+ // snake_case
+ {
+ TString modelStr(R"_({"string":"value"})_");
+
+ TFlatOptional proto;
+ proto.SetString("value");
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+ config.FieldNameMode = TProto2JsonConfig::FieldNameSnakeCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+ {
+ TString modelStr(R"_({"one_string":"value"})_");
+
+ TFlatOptional proto;
+ proto.SetOneString("value");
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+ config.FieldNameMode = TProto2JsonConfig::FieldNameSnakeCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+ {
+ TString modelStr(R"_({"one_two_string":"value"})_");
+
+ TFlatOptional proto;
+ proto.SetOneTwoString("value");
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+ config.FieldNameMode = TProto2JsonConfig::FieldNameSnakeCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+ {
+ TString modelStr(R"_({"a_b_c":"value","user_i_d":"value"})_");
+
+ TFlatOptional proto;
+ proto.SetABC("value");
+ proto.SetUserID("value");
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+ config.FieldNameMode = TProto2JsonConfig::FieldNameSnakeCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+
+ // snake_case_dense
+ {
+ TString modelStr(R"_({"abc":"value","user_id":"value"})_");
+
+ TFlatOptional proto;
+ proto.SetABC("value");
+ proto.SetUserID("value");
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+ config.FieldNameMode = TProto2JsonConfig::FieldNameSnakeCaseDense;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+
+ // Original case, repeated
+ {
+ TString modelStr(R"_({"I32":[1,2]})_");
+
+ TFlatRepeated proto;
+ proto.AddI32(1);
+ proto.AddI32(2);
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+ config.FieldNameMode = TProto2JsonConfig::FieldNameOriginalCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+
+ // Lower case, repeated
+ {
+ TString modelStr(R"_({"i32":[1,2]})_");
+
+ TFlatRepeated proto;
+ proto.AddI32(1);
+ proto.AddI32(2);
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+ config.FieldNameMode = TProto2JsonConfig::FieldNameLowerCase;
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+
+ // UseJsonName
+ {
+ // FIXME(CONTRIB-139): see the comment about UseJsonName in json2proto_ut.cpp:
+ // Def_upper json name should be "DefUpper".
+ TString modelStr(R"_({"My-Upper":1,"my-lower":2,"defUpper":3,"defLower":4})_");
+
+ TWithJsonName proto;
+ proto.Setmy_upper(1);
+ proto.SetMy_lower(2);
+ proto.SetDef_upper(3);
+ proto.Setdef_lower(4);
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+ config.SetUseJsonName(true);
+
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+ UNIT_ASSERT_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+ }
+
+ // FieldNameMode with UseJsonName
+ {
+ TProto2JsonConfig config;
+ config.SetFieldNameMode(TProto2JsonConfig::FieldNameLowerCase);
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ config.SetUseJsonName(true), yexception, "mutually exclusive");
+ }
+ {
+ TProto2JsonConfig config;
+ config.SetUseJsonName(true);
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ config.SetFieldNameMode(TProto2JsonConfig::FieldNameLowerCase), yexception, "mutually exclusive");
+ }
+
+ /// TODO: test missing keys
+} // TestFieldNameMode
+
+Y_UNIT_TEST(TestNan) {
+ TFlatOptional proto;
+ proto.SetDouble(std::numeric_limits<double>::quiet_NaN());
+
+ UNIT_ASSERT_EXCEPTION(Proto2Json(proto, TProto2JsonConfig()), yexception);
+} // TestNan
+
+Y_UNIT_TEST(TestInf) {
+ TFlatOptional proto;
+ proto.SetFloat(std::numeric_limits<float>::infinity());
+
+ UNIT_ASSERT_EXCEPTION(Proto2Json(proto, TProto2JsonConfig()), yexception);
+} // TestInf
+
+Y_UNIT_TEST(TestMap) {
+ TMapType proto;
+
+ auto& items = *proto.MutableItems();
+ items["key1"] = "value1";
+ items["key2"] = "value2";
+ items["key3"] = "value3";
+
+ TString modelStr(R"_({"Items":[{"key":"key3","value":"value3"},{"key":"key2","value":"value2"},{"key":"key1","value":"value1"}]})_");
+
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+
+ NJson::TJsonValue jsonValue, modelValue;
+ NJson::TJsonValue::TArray jsonItems, modelItems;
+ UNIT_ASSERT(NJson::ReadJsonTree(jsonStr.Str(), &jsonValue));
+ UNIT_ASSERT(NJson::ReadJsonTree(modelStr, &modelValue));
+ UNIT_ASSERT(jsonValue.Has("Items"));
+ jsonValue["Items"].GetArray(&jsonItems);
+ modelValue["Items"].GetArray(&modelItems);
+ auto itemKey = [](const NJson::TJsonValue& v) {
+ return v["key"].GetString();
+ };
+ SortBy(jsonItems, itemKey);
+ SortBy(modelItems, itemKey);
+ UNIT_ASSERT_EQUAL(jsonItems, modelItems);
+} // TestMap
+
+Y_UNIT_TEST(TestMapAsObject) {
+ TMapType proto;
+
+ auto& items = *proto.MutableItems();
+ items["key1"] = "value1";
+ items["key2"] = "value2";
+ items["key3"] = "value3";
+
+ TString modelStr(R"_({"Items":{"key3":"value3","key2":"value2","key1":"value1"}})_");
+
+ TStringStream jsonStr;
+ TProto2JsonConfig config;
+ config.MapAsObject = true;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+} // TestMapAsObject
+
+Y_UNIT_TEST(TestMapWTF) {
+ TMapType proto;
+
+ auto& items = *proto.MutableItems();
+ items["key1"] = "value1";
+ items["key2"] = "value2";
+ items["key3"] = "value3";
+
+ TString modelStr(R"_({"Items":{"key3":"value3","key2":"value2","key1":"value1"}})_");
+
+ TStringStream jsonStr;
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr));
+
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+} // TestMapWTF
+
+Y_UNIT_TEST(TestStringifyLongNumbers) {
+#define TEST_SINGLE(flag, value, expectString) \
+ do { \
+ TFlatOptional proto; \
+ proto.SetSI64(value); \
+ \
+ TStringStream jsonStr; \
+ TProto2JsonConfig config; \
+ config.SetStringifyLongNumbers(flag); \
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config)); \
+ if (expectString) { \
+ UNIT_ASSERT_EQUAL(jsonStr.Str(), "{\"SI64\":\"" #value "\"}"); \
+ } else { \
+ UNIT_ASSERT_EQUAL(jsonStr.Str(), "{\"SI64\":" #value "}"); \
+ } \
+ } while (false)
+
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersNever, 1, false);
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersNever, 1000000000, false);
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersNever, 10000000000000000, false);
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersNever, -1, false);
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersNever, -1000000000, false);
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersNever, -10000000000000000, false);
+
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersForDouble, 1, false);
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersForDouble, 1000000000, false);
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersForDouble, 10000000000000000, true);
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersForDouble, -1, false);
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersForDouble, -1000000000, false);
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersForDouble, -10000000000000000, true);
+
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersForFloat, 1, false);
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersForFloat, 1000000000, true);
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersForFloat, 10000000000000000, true);
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersForFloat, -1, false);
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersForFloat, -1000000000, true);
+ TEST_SINGLE(TProto2JsonConfig::StringifyLongNumbersForFloat, -10000000000000000, true);
+
+#undef TEST_SINGLE
+} // TestStringifyLongNumbers
+
+Y_UNIT_TEST(TestExtension) {
+ TExtensionField proto;
+ proto.SetExtension(bar, 1);
+
+ Y_ASSERT(proto.HasExtension(bar));
+ UNIT_ASSERT_EQUAL(Proto2Json(proto, TProto2JsonConfig()), "{\"NProtobufJsonTest.bar\":1}");
+
+
+ TProto2JsonConfig cfg;
+ cfg.SetExtensionFieldNameMode(TProto2JsonConfig::ExtFldNameShort);
+ UNIT_ASSERT_EQUAL(Proto2Json(proto, cfg), "{\"bar\":1}");
+} // TestExtension
+
+} // TProto2JsonTest
diff --git a/library/cpp/protobuf/json/ut/repeated_fields.incl b/library/cpp/protobuf/json/ut/repeated_fields.incl
new file mode 100644
index 0000000000..e9548917d8
--- /dev/null
+++ b/library/cpp/protobuf/json/ut/repeated_fields.incl
@@ -0,0 +1,21 @@
+// Intentionally no #pragma once
+
+// (Field name == JSON key, Type, Values...)
+DEFINE_REPEATED_FIELD(I32, i32, Min<i32>(), -1, 0, 1, Max<i32>())
+DEFINE_REPEATED_FIELD(I64, i64, Min<i64>(), -1ll, 0ll, 1ll, Max<i64>())
+DEFINE_REPEATED_FIELD(UI32, ui32, 0ul, 1ul, Max<ui32>())
+DEFINE_REPEATED_FIELD(UI64, ui64, 0ull, 1ull, Max<ui64>())
+DEFINE_REPEATED_FIELD(SI32, i32, Min<i32>(), -1, 0, 1, Max<i32>())
+DEFINE_REPEATED_FIELD(SI64, i64, Min<i64>(), -1ll, 0ll, 1ll, Max<i64>())
+DEFINE_REPEATED_FIELD(FI32, ui32, 0, 1, Max<ui32>())
+DEFINE_REPEATED_FIELD(FI64, ui64, 0ull, 1ull, Max<ui64>())
+DEFINE_REPEATED_FIELD(SFI32, i32, Min<i32>(), -1, 0, 1, Max<i32>())
+DEFINE_REPEATED_FIELD(SFI64, i64, Min<i64>(), -1ll, 0ll, 1ll, Max<i64>())
+DEFINE_REPEATED_FIELD(Bool, bool, false, true)
+DEFINE_REPEATED_FIELD(String, TString, "", "Lorem ipsum", "123123")
+DEFINE_REPEATED_FIELD(Bytes, TString, "", "מחשב", "\x1")
+DEFINE_REPEATED_FIELD(Enum, EEnum, E_1, E_2, E_3)
+DEFINE_REPEATED_FIELD(Float, float, 0.0f, 1.0f, 1.123f)
+DEFINE_REPEATED_FIELD(Double, double, 0.0, 1.0, 1.123456789012)
+DEFINE_REPEATED_FIELD(OneString, TString, "", "Lorem ipsum dolor", "1231231")
+DEFINE_REPEATED_FIELD(OneTwoString, TString, "", "Lorem ipsum dolor sit", "12312312")
diff --git a/library/cpp/protobuf/json/ut/string_transform_ut.cpp b/library/cpp/protobuf/json/ut/string_transform_ut.cpp
new file mode 100644
index 0000000000..a31dabcb0f
--- /dev/null
+++ b/library/cpp/protobuf/json/ut/string_transform_ut.cpp
@@ -0,0 +1,106 @@
+#include "json.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/protobuf/json/proto2json.h>
+
+Y_UNIT_TEST_SUITE(TDoubleEscapeTransform) {
+ Y_UNIT_TEST(TestEmptyString) {
+ const NProtobufJson::IStringTransform& transform = NProtobufJson::TDoubleEscapeTransform();
+ TString s;
+ s = "";
+ transform.Transform(s);
+ UNIT_ASSERT_EQUAL(s, "");
+ }
+
+ Y_UNIT_TEST(TestAlphabeticString) {
+ const NProtobufJson::IStringTransform& transform = NProtobufJson::TDoubleEscapeTransform();
+ TString s;
+ s = "abacaba";
+ transform.Transform(s);
+ UNIT_ASSERT_EQUAL(s, "abacaba");
+ }
+
+ Y_UNIT_TEST(TestRussianSymbols) {
+ const NProtobufJson::IStringTransform& transform = NProtobufJson::TDoubleEscapeTransform();
+ TString s;
+ s = "тест";
+ transform.Transform(s);
+ UNIT_ASSERT_EQUAL(s, "\\\\321\\\\202\\\\320\\\\265\\\\321\\\\201\\\\321\\\\202");
+ }
+
+ Y_UNIT_TEST(TestEscapeSpecialSymbols) {
+ const NProtobufJson::IStringTransform& transform = NProtobufJson::TDoubleEscapeTransform();
+ TString s;
+ s = "aba\\ca\"ba";
+ transform.Transform(s);
+ Cerr << "###" << s << Endl;
+ UNIT_ASSERT_EQUAL(s, "aba\\\\\\\\ca\\\\\\\"ba");
+ }
+}
+
+Y_UNIT_TEST_SUITE(TDoubleUnescapeTransform) {
+ Y_UNIT_TEST(TestEmptyString) {
+ const NProtobufJson::IStringTransform& transform = NProtobufJson::TDoubleUnescapeTransform();
+ TString s;
+ s = "";
+ transform.Transform(s);
+ UNIT_ASSERT_EQUAL("", s);
+ }
+
+ Y_UNIT_TEST(TestAlphabeticString) {
+ const NProtobufJson::IStringTransform& transform = NProtobufJson::TDoubleUnescapeTransform();
+ TString s;
+ s = "abacaba";
+ transform.Transform(s);
+ Cerr << "###" << s << Endl;
+ UNIT_ASSERT_EQUAL("abacaba", s);
+ }
+
+ Y_UNIT_TEST(TestRussianSymbols) {
+ const NProtobufJson::IStringTransform& transform = NProtobufJson::TDoubleUnescapeTransform();
+ TString s;
+ s = "\\\\321\\\\202\\\\320\\\\265\\\\321\\\\201\\\\321\\\\202";
+ transform.Transform(s);
+ UNIT_ASSERT_EQUAL("тест", s);
+ }
+
+ Y_UNIT_TEST(TestEscapeSpecialSymbols) {
+ const NProtobufJson::IStringTransform& transform = NProtobufJson::TDoubleUnescapeTransform();
+ TString s;
+ s = "aba\\\\\\\\ca\\\\\\\"ba";
+ transform.Transform(s);
+ UNIT_ASSERT_EQUAL("aba\\ca\"ba", s);
+ }
+
+ Y_UNIT_TEST(TestEscapeSpecialSymbolsDifficultCases) {
+ const NProtobufJson::IStringTransform& transform = NProtobufJson::TDoubleUnescapeTransform();
+ TString s;
+ s = "\\\\\\\\\\\\\\\\";
+ transform.Transform(s);
+ UNIT_ASSERT_EQUAL("\\\\", s);
+
+ s = "\\\\\\\\\\\\\\\"";
+ transform.Transform(s);
+ UNIT_ASSERT_EQUAL("\\\"", s);
+
+ s = "\\\\\\\"\\\\\\\\";
+ transform.Transform(s);
+ UNIT_ASSERT_EQUAL("\"\\", s);
+
+ s = "\\\\\\\"\\\\\\\"";
+ transform.Transform(s);
+ UNIT_ASSERT_EQUAL("\"\"", s);
+
+ s = "\\\\\\\\\\\\\\\\\\\\\\\\";
+ transform.Transform(s);
+ UNIT_ASSERT_EQUAL("\\\\\\", s);
+
+ s = "\\\\\\\\\\\\\\\\\\\\\\\\abacaba\\\\";
+ transform.Transform(s);
+ UNIT_ASSERT_EQUAL("\\\\\\abacaba", s);
+
+ s = "\\\\\\\\\\\\\\\\\\\\\\\\abacaba\\\"";
+ transform.Transform(s);
+ UNIT_ASSERT_EQUAL("\\\\\\abacaba\"", s);
+ }
+}
diff --git a/library/cpp/protobuf/json/ut/test.proto b/library/cpp/protobuf/json/ut/test.proto
new file mode 100644
index 0000000000..0fa996fd41
--- /dev/null
+++ b/library/cpp/protobuf/json/ut/test.proto
@@ -0,0 +1,203 @@
+package NProtobufJsonTest;
+
+enum EEnum {
+ E_0 = 0;
+ E_1 = 1;
+ E_2 = 2;
+ E_3 = 3;
+};
+
+message TFlatOptional {
+ optional int32 I32 = 1;
+ optional int64 I64 = 2;
+ optional uint32 UI32 = 3;
+ optional uint64 UI64 = 4;
+ optional sint32 SI32 = 5;
+ optional sint64 SI64 = 6;
+ optional fixed32 FI32 = 7;
+ optional fixed64 FI64 = 8;
+ optional sfixed32 SFI32 = 9;
+ optional sfixed64 SFI64 = 10;
+
+ optional bool Bool = 11;
+
+ optional string String = 12;
+ optional bytes Bytes = 13;
+
+ optional EEnum Enum = 14;
+
+ optional float Float = 15;
+ optional double Double = 16;
+
+ optional string OneString = 17;
+ optional string OneTwoString = 18;
+ optional string ABC = 19;
+ optional string UserID = 20;
+};
+
+message TFlatRequired {
+ required int32 I32 = 1;
+ required int64 I64 = 2;
+ required uint32 UI32 = 3;
+ required uint64 UI64 = 4;
+ required sint32 SI32 = 5;
+ required sint64 SI64 = 6;
+ required fixed32 FI32 = 7;
+ required fixed64 FI64 = 8;
+ required sfixed32 SFI32 = 9;
+ required sfixed64 SFI64 = 10;
+
+ required bool Bool = 11;
+
+ required string String = 12;
+ required bytes Bytes = 13;
+
+ required EEnum Enum = 14;
+
+ required float Float = 15;
+ required double Double = 16;
+
+ required string OneString = 17;
+ required string OneTwoString = 18;
+ required string ABC = 19;
+ required string UserID = 20;
+};
+
+message TFlatRepeated {
+ repeated int32 I32 = 1;
+ repeated int64 I64 = 2;
+ repeated uint32 UI32 = 3;
+ repeated uint64 UI64 = 4;
+ repeated sint32 SI32 = 5;
+ repeated sint64 SI64 = 6;
+ repeated fixed32 FI32 = 7;
+ repeated fixed64 FI64 = 8;
+ repeated sfixed32 SFI32 = 9;
+ repeated sfixed64 SFI64 = 10;
+
+ repeated bool Bool = 11;
+
+ repeated string String = 12;
+ repeated bytes Bytes = 13;
+
+ repeated EEnum Enum = 14;
+
+ repeated float Float = 15;
+ repeated double Double = 16;
+
+ repeated string OneString = 17;
+ repeated string OneTwoString = 18;
+ repeated string ABC = 19;
+ repeated string UserID = 20;
+};
+
+message TFlatDefault {
+ optional int32 I32 = 1 [default = 132];
+ optional int64 I64 = 2 [default = 164];
+ optional uint32 UI32 = 3 [default = 232];
+ optional uint64 UI64 = 4 [default = 264];
+ optional sint32 SI32 = 5 [default = 332];
+ optional sint64 SI64 = 6 [default = 364];
+ optional fixed32 FI32 = 7 [default = 432];
+ optional fixed64 FI64 = 8 [default = 464];
+ optional sfixed32 SFI32 = 9 [default = 532];
+ optional sfixed64 SFI64 = 10 [default = 564];
+
+ optional bool Bool = 11 [default = true];
+
+ optional string String = 12 [default = "string"];
+ optional bytes Bytes = 13 [default = "bytes"];
+
+ optional EEnum Enum = 14 [default = E_2];
+
+ optional float Float = 15 [default = 0.123];
+ optional double Double = 16 [default = 0.456];
+
+ optional string OneString = 17 [default = "string"];
+ optional string OneTwoString = 18 [default = "string"];
+ optional string ABC = 19 [default = "abc"];
+ optional string UserID = 20 [default = "some_id"];
+};
+
+message TCompositeOptional {
+ optional TFlatOptional Part = 1;
+};
+
+message TCompositeRequired {
+ required TFlatRequired Part = 1;
+};
+
+message TCompositeRepeated {
+ repeated TFlatOptional Part = 1;
+};
+
+message TMapType {
+ map<string, string> Items = 1;
+};
+
+message TNameGeneratorType {
+ optional int32 Field = 1;
+};
+
+message TEnumValueGeneratorType {
+ enum EEnum {
+ ENUM_42 = 1;
+ };
+
+ optional EEnum Enum = 1;
+};
+
+message TComplexMapType {
+ map<int32, int32> I32 = 1;
+ map<int64, int64> I64 = 2;
+ map<uint32, uint32> UI32 = 3;
+ map<uint64, uint64> UI64 = 4;
+ map<sint32, sint32> SI32 = 5;
+ map<sint64, sint64> SI64 = 6;
+ map<fixed32, fixed32> FI32 = 7;
+ map<fixed64, fixed64> FI64 = 8;
+ map<sfixed32, sfixed32> SFI32 = 9;
+ map<sfixed64, sfixed64> SFI64 = 10;
+
+ map<bool, bool> Bool = 11;
+
+ map<string, string> String = 12;
+
+ map<string, EEnum> Enum = 13;
+
+ map<string, float> Float = 14;
+ map<string, double> Double = 15;
+
+ map<string, TComplexMapType> Nested = 16;
+};
+
+message TWithJsonName {
+ optional int32 my_upper = 1 [json_name = "My-Upper"];
+ optional int32 My_lower = 2 [json_name = "my-lower"];
+ optional int32 Def_upper = 3; // json_name = "DefUpper"
+ optional int32 def_lower = 4; // json_name = "defLower"
+}
+
+message TSingleRequiredString {
+ required string String = 1;
+}
+
+message TSingleDefaultString {
+ optional string String = 1 [default = "value"];
+}
+
+message TSingleRepeatedString {
+ repeated string RepeatedString = 1;
+}
+
+message TSingleRepeatedInt {
+ repeated int32 RepeatedInt = 1;
+}
+
+message TExtensionField {
+ extensions 100 to 199;
+}
+
+extend TExtensionField {
+ optional int32 bar = 123;
+} \ No newline at end of file
diff --git a/library/cpp/protobuf/json/ut/util_ut.cpp b/library/cpp/protobuf/json/ut/util_ut.cpp
new file mode 100644
index 0000000000..05101dca28
--- /dev/null
+++ b/library/cpp/protobuf/json/ut/util_ut.cpp
@@ -0,0 +1,42 @@
+#include <library/cpp/protobuf/json/util.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NProtobufJson;
+
+Y_UNIT_TEST_SUITE(TEqualsTest) {
+ Y_UNIT_TEST(TestEmpty) {
+ UNIT_ASSERT(EqualsIgnoringCaseAndUnderscores("", ""));
+ UNIT_ASSERT(EqualsIgnoringCaseAndUnderscores("", "_"));
+ UNIT_ASSERT(!EqualsIgnoringCaseAndUnderscores("f", ""));
+ }
+
+ Y_UNIT_TEST(TestTrivial) {
+ UNIT_ASSERT(EqualsIgnoringCaseAndUnderscores("f", "f"));
+ UNIT_ASSERT(!EqualsIgnoringCaseAndUnderscores("f", "o"));
+ UNIT_ASSERT(!EqualsIgnoringCaseAndUnderscores("fo", "f"));
+ UNIT_ASSERT(!EqualsIgnoringCaseAndUnderscores("f", "fo"));
+ UNIT_ASSERT(!EqualsIgnoringCaseAndUnderscores("bar", "baz"));
+ }
+
+ Y_UNIT_TEST(TestUnderscores) {
+ UNIT_ASSERT(EqualsIgnoringCaseAndUnderscores("foo_bar", "foobar"));
+ UNIT_ASSERT(EqualsIgnoringCaseAndUnderscores("foo_bar_", "foobar"));
+ UNIT_ASSERT(!EqualsIgnoringCaseAndUnderscores("foo_bar_z", "foobar"));
+ UNIT_ASSERT(EqualsIgnoringCaseAndUnderscores("foo__bar__", "foobar"));
+ UNIT_ASSERT(!EqualsIgnoringCaseAndUnderscores("foo__bar__z", "foobar"));
+ UNIT_ASSERT(EqualsIgnoringCaseAndUnderscores("_foo_bar", "foobar"));
+ UNIT_ASSERT(EqualsIgnoringCaseAndUnderscores("_foo_bar_", "foobar"));
+ UNIT_ASSERT(EqualsIgnoringCaseAndUnderscores("_foo_bar_", "foo___bar"));
+ }
+
+ Y_UNIT_TEST(TestCase) {
+ UNIT_ASSERT(EqualsIgnoringCaseAndUnderscores("foo_bar", "FOO_BAR"));
+ UNIT_ASSERT(EqualsIgnoringCaseAndUnderscores("foobar", "fooBar"));
+ }
+
+ Y_UNIT_TEST(TestCaseAndUnderscores) {
+ UNIT_ASSERT(EqualsIgnoringCaseAndUnderscores("fooBar", "FOO_BAR"));
+ UNIT_ASSERT(EqualsIgnoringCaseAndUnderscores("FOO_BAR_BAZ", "fooBar_BAZ"));
+ }
+}
diff --git a/library/cpp/protobuf/json/ut/ya.make b/library/cpp/protobuf/json/ut/ya.make
new file mode 100644
index 0000000000..b60a6d3c17
--- /dev/null
+++ b/library/cpp/protobuf/json/ut/ya.make
@@ -0,0 +1,23 @@
+UNITTEST_FOR(library/cpp/protobuf/json)
+
+OWNER(avitella)
+
+SRCS(
+ filter_ut.cpp
+ json2proto_ut.cpp
+ proto2json_ut.cpp
+ inline_ut.proto
+ inline_ut.cpp
+ string_transform_ut.cpp
+ filter_ut.proto
+ test.proto
+ util_ut.cpp
+)
+
+GENERATE_ENUM_SERIALIZATION(test.pb.h)
+
+PEERDIR(
+ library/cpp/protobuf/json
+)
+
+END()
diff --git a/library/cpp/protobuf/json/util.cpp b/library/cpp/protobuf/json/util.cpp
new file mode 100644
index 0000000000..53a065eee2
--- /dev/null
+++ b/library/cpp/protobuf/json/util.cpp
@@ -0,0 +1,76 @@
+#include "util.h"
+
+#include <util/string/ascii.h>
+
+namespace {
+ void ToSnakeCaseImpl(TString* const name, std::function<bool(const char)> requiresUnderscore) {
+ bool requiresChanges = false;
+ size_t size = name->size();
+ for (size_t i = 0; i < name->size(); i++) {
+ if (IsAsciiUpper(name->at(i))) {
+ requiresChanges = true;
+ if (i > 0 && requiresUnderscore(name->at(i - 1))) {
+ size++;
+ }
+ }
+ }
+
+ if (!requiresChanges) {
+ return;
+ }
+
+ if (size != name->size()) {
+ TString result;
+ result.reserve(size);
+ for (size_t i = 0; i < name->size(); i++) {
+ const char c = name->at(i);
+ if (IsAsciiUpper(c)) {
+ if (i > 0 && requiresUnderscore(name->at(i - 1))) {
+ result += '_';
+ }
+ result += AsciiToLower(c);
+ } else {
+ result += c;
+ }
+ }
+ *name = std::move(result);
+ } else {
+ name->to_lower();
+ }
+ }
+}
+
+namespace NProtobufJson {
+ void ToSnakeCase(TString* const name) {
+ ToSnakeCaseImpl(name, [](const char prev) { return prev != '_'; });
+ }
+
+ void ToSnakeCaseDense(TString* const name) {
+ ToSnakeCaseImpl(name, [](const char prev) { return prev != '_' && !IsAsciiUpper(prev); });
+ }
+
+ bool EqualsIgnoringCaseAndUnderscores(TStringBuf s1, TStringBuf s2) {
+ size_t i1 = 0, i2 = 0;
+
+ while (i1 < s1.size() && i2 < s2.size()) {
+ if (s1[i1] == '_') {
+ ++i1;
+ } else if (s2[i2] == '_') {
+ ++i2;
+ } else if (AsciiToUpper(s1[i1]) != AsciiToUpper(s2[i2])) {
+ return false;
+ } else {
+ ++i1, ++i2;
+ }
+ }
+
+ while (i1 < s1.size() && s1[i1] == '_') {
+ ++i1;
+ }
+ while (i2 < s2.size() && s2[i2] == '_') {
+ ++i2;
+ }
+
+ return (i1 == s1.size() && i2 == s2.size());
+ }
+}
diff --git a/library/cpp/protobuf/json/util.h b/library/cpp/protobuf/json/util.h
new file mode 100644
index 0000000000..d93342d3f8
--- /dev/null
+++ b/library/cpp/protobuf/json/util.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <util/generic/string.h>
+
+namespace NProtobufJson {
+ void ToSnakeCase(TString* const name);
+
+ void ToSnakeCaseDense(TString* const name);
+
+ /**
+ * "FOO_BAR" ~ "foo_bar" ~ "fooBar"
+ */
+ bool EqualsIgnoringCaseAndUnderscores(TStringBuf s1, TStringBuf s2);
+}
diff --git a/library/cpp/protobuf/json/ya.make b/library/cpp/protobuf/json/ya.make
new file mode 100644
index 0000000000..2f2c75cfdb
--- /dev/null
+++ b/library/cpp/protobuf/json/ya.make
@@ -0,0 +1,25 @@
+LIBRARY()
+
+OWNER(avitella)
+
+SRCS(
+ json2proto.cpp
+ json_output_create.cpp
+ json_value_output.cpp
+ json_writer_output.cpp
+ name_generator.cpp
+ proto2json.cpp
+ proto2json_printer.cpp
+ string_transform.cpp
+ util.h
+ util.cpp
+)
+
+PEERDIR(
+ contrib/libs/protobuf
+ library/cpp/json
+ library/cpp/protobuf/util
+ library/cpp/string_utils/relaxed_escaper
+)
+
+END()
diff --git a/library/cpp/protobuf/util/cast.h b/library/cpp/protobuf/util/cast.h
new file mode 100644
index 0000000000..83749dfcee
--- /dev/null
+++ b/library/cpp/protobuf/util/cast.h
@@ -0,0 +1,156 @@
+#pragma once
+
+#include "traits.h"
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+
+#include <util/generic/cast.h>
+
+namespace NProtoBuf {
+ // C++ compatible conversions of FieldDescriptor::CppType's
+
+ using ECppType = FieldDescriptor::CppType;
+
+ namespace NCast {
+ template <ECppType src, ECppType dst>
+ struct TIsCompatibleCppType {
+ enum {
+ Result = src == dst ||
+ (TIsNumericCppType<src>::Result && TIsNumericCppType<dst>::Result)
+ };
+ };
+
+ template <ECppType src, ECppType dst>
+ struct TIsEnumToNumericCppType {
+ enum {
+ Result = (src == FieldDescriptor::CPPTYPE_ENUM && TIsNumericCppType<dst>::Result)
+ };
+ };
+
+ template <ECppType src, ECppType dst, bool compatible> // compatible == true
+ struct TCompatCastBase {
+ static const bool IsCompatible = true;
+
+ typedef typename TCppTypeTraits<src>::T TSrc;
+ typedef typename TCppTypeTraits<dst>::T TDst;
+
+ static inline TDst Cast(TSrc value) {
+ return value;
+ }
+ };
+
+ template <ECppType src, ECppType dst> // compatible == false
+ struct TCompatCastBase<src, dst, false> {
+ static const bool IsCompatible = false;
+
+ typedef typename TCppTypeTraits<src>::T TSrc;
+ typedef typename TCppTypeTraits<dst>::T TDst;
+
+ static inline TDst Cast(TSrc) {
+ ythrow TBadCastException() << "Incompatible FieldDescriptor::CppType conversion: #"
+ << (size_t)src << " to #" << (size_t)dst;
+ }
+ };
+
+ template <ECppType src, ECppType dst, bool isEnumToNum> // enum -> numeric
+ struct TCompatCastImpl {
+ static const bool IsCompatible = true;
+
+ typedef typename TCppTypeTraits<dst>::T TDst;
+
+ static inline TDst Cast(const EnumValueDescriptor* value) {
+ Y_ASSERT(value != nullptr);
+ return value->number();
+ }
+ };
+
+ template <ECppType src, ECppType dst>
+ struct TCompatCastImpl<src, dst, false>: public TCompatCastBase<src, dst, TIsCompatibleCppType<src, dst>::Result> {
+ using TCompatCastBase<src, dst, TIsCompatibleCppType<src, dst>::Result>::IsCompatible;
+ };
+
+ template <ECppType src, ECppType dst>
+ struct TCompatCast: public TCompatCastImpl<src, dst, TIsEnumToNumericCppType<src, dst>::Result> {
+ typedef TCompatCastImpl<src, dst, TIsEnumToNumericCppType<src, dst>::Result> TBase;
+
+ typedef typename TCppTypeTraits<src>::T TSrc;
+ typedef typename TCppTypeTraits<dst>::T TDst;
+
+ using TBase::Cast;
+ using TBase::IsCompatible;
+
+ inline bool Try(TSrc value, TDst& res) {
+ if (IsCompatible) {
+ res = Cast(value);
+ return true;
+ }
+ return false;
+ }
+ };
+
+ }
+
+ template <ECppType src, ECppType dst>
+ inline typename TCppTypeTraits<dst>::T CompatCast(typename TCppTypeTraits<src>::T value) {
+ return NCast::TCompatCast<src, dst>::Cast(value);
+ }
+
+ template <ECppType src, ECppType dst>
+ inline bool TryCompatCast(typename TCppTypeTraits<src>::T value, typename TCppTypeTraits<dst>::T& res) {
+ return NCast::TCompatCast<src, dst>::Try(value, res);
+ }
+
+ // Message static/dynamic checked casts
+
+ template <typename TpMessage>
+ inline const TpMessage* TryCast(const Message* msg) {
+ if (!msg || TpMessage::descriptor() != msg->GetDescriptor())
+ return NULL;
+ return CheckedCast<const TpMessage*>(msg);
+ }
+
+ template <typename TpMessage>
+ inline const TpMessage* TryCast(const Message* msg, const TpMessage*& ret) {
+ ret = TryCast<TpMessage>(msg);
+ return ret;
+ }
+
+ template <typename TpMessage>
+ inline TpMessage* TryCast(Message* msg) {
+ if (!msg || TpMessage::descriptor() != msg->GetDescriptor())
+ return nullptr;
+ return CheckedCast<TpMessage*>(msg);
+ }
+
+ template <typename TpMessage>
+ inline TpMessage* TryCast(Message* msg, TpMessage*& ret) {
+ ret = TryCast<TpMessage>(msg);
+ return ret;
+ }
+
+ // specialize for Message itself
+
+ template <>
+ inline const Message* TryCast<Message>(const Message* msg) {
+ return msg;
+ }
+
+ template <>
+ inline Message* TryCast<Message>(Message* msg) {
+ return msg;
+ }
+
+ // Binary serialization compatible conversion
+ inline bool TryBinaryCast(const Message* from, Message* to, TString* buffer = nullptr) {
+ TString tmpbuf;
+ if (!buffer)
+ buffer = &tmpbuf;
+
+ if (!from->SerializeToString(buffer))
+ return false;
+
+ return to->ParseFromString(*buffer);
+ }
+
+}
diff --git a/library/cpp/protobuf/util/is_equal.cpp b/library/cpp/protobuf/util/is_equal.cpp
new file mode 100644
index 0000000000..227408006e
--- /dev/null
+++ b/library/cpp/protobuf/util/is_equal.cpp
@@ -0,0 +1,163 @@
+#include "is_equal.h"
+#include "traits.h"
+
+#include <google/protobuf/descriptor.h>
+
+#include <util/generic/yexception.h>
+#include <util/string/cast.h>
+#include <util/string/vector.h>
+
+namespace NProtoBuf {
+ template <bool useDefault>
+ static bool IsEqualImpl(const Message& m1, const Message& m2, TVector<TString>* differentPath);
+
+ namespace {
+ template <FieldDescriptor::CppType CppType, bool useDefault>
+ struct TCompareValue {
+ typedef typename TCppTypeTraits<CppType>::T T;
+ static inline bool IsEqual(T value1, T value2, TVector<TString>*) {
+ return value1 == value2;
+ }
+ };
+
+ template <bool useDefault>
+ struct TCompareValue<FieldDescriptor::CPPTYPE_MESSAGE, useDefault> {
+ static inline bool IsEqual(const Message* value1, const Message* value2, TVector<TString>* differentPath) {
+ return NProtoBuf::IsEqualImpl<useDefault>(*value1, *value2, differentPath);
+ }
+ };
+
+ template <FieldDescriptor::CppType CppType, bool useDefault>
+ class TCompareField {
+ typedef TCppTypeTraits<CppType> TTraits;
+ typedef TCompareValue<CppType, useDefault> TCompare;
+
+ public:
+ static inline bool IsEqual(const Message& m1, const Message& m2, const FieldDescriptor& field, TVector<TString>* differentPath) {
+ if (field.is_repeated())
+ return IsEqualRepeated(m1, m2, &field, differentPath);
+ else
+ return IsEqualSingle(m1, m2, &field, differentPath);
+ }
+
+ private:
+ static bool IsEqualSingle(const Message& m1, const Message& m2, const FieldDescriptor* field, TVector<TString>* differentPath) {
+ bool has1 = m1.GetReflection()->HasField(m1, field);
+ bool has2 = m2.GetReflection()->HasField(m2, field);
+
+ if (has1 != has2) {
+ if (!useDefault || field->is_required()) {
+ return false;
+ }
+ } else if (!has1)
+ return true;
+
+ return TCompare::IsEqual(TTraits::Get(m1, field),
+ TTraits::Get(m2, field),
+ differentPath);
+ }
+
+ static bool IsEqualRepeated(const Message& m1, const Message& m2, const FieldDescriptor* field, TVector<TString>* differentPath) {
+ int fieldSize = m1.GetReflection()->FieldSize(m1, field);
+ if (fieldSize != m2.GetReflection()->FieldSize(m2, field))
+ return false;
+ for (int i = 0; i < fieldSize; ++i)
+ if (!IsEqualRepeatedValue(m1, m2, field, i, differentPath)) {
+ if (!!differentPath) {
+ differentPath->push_back(ToString(i));
+ }
+ return false;
+ }
+ return true;
+ }
+
+ static inline bool IsEqualRepeatedValue(const Message& m1, const Message& m2, const FieldDescriptor* field, int index, TVector<TString>* differentPath) {
+ return TCompare::IsEqual(TTraits::GetRepeated(m1, field, index),
+ TTraits::GetRepeated(m2, field, index),
+ differentPath);
+ }
+ };
+
+ template <bool useDefault>
+ bool IsEqualField(const Message& m1, const Message& m2, const FieldDescriptor& field, TVector<TString>* differentPath) {
+#define CASE_CPPTYPE(cpptype) \
+ case FieldDescriptor::CPPTYPE_##cpptype: { \
+ bool r = TCompareField<FieldDescriptor::CPPTYPE_##cpptype, useDefault>::IsEqual(m1, m2, field, differentPath); \
+ if (!r && !!differentPath) { \
+ differentPath->push_back(field.name()); \
+ } \
+ return r; \
+ }
+
+ switch (field.cpp_type()) {
+ CASE_CPPTYPE(INT32)
+ CASE_CPPTYPE(INT64)
+ CASE_CPPTYPE(UINT32)
+ CASE_CPPTYPE(UINT64)
+ CASE_CPPTYPE(DOUBLE)
+ CASE_CPPTYPE(FLOAT)
+ CASE_CPPTYPE(BOOL)
+ CASE_CPPTYPE(ENUM)
+ CASE_CPPTYPE(STRING)
+ CASE_CPPTYPE(MESSAGE)
+ default:
+ ythrow yexception() << "Unsupported cpp-type field comparison";
+ }
+
+#undef CASE_CPPTYPE
+ }
+ }
+
+ template <bool useDefault>
+ bool IsEqualImpl(const Message& m1, const Message& m2, TVector<TString>* differentPath) {
+ const Descriptor* descr = m1.GetDescriptor();
+ if (descr != m2.GetDescriptor()) {
+ return false;
+ }
+ for (int i = 0; i < descr->field_count(); ++i)
+ if (!IsEqualField<useDefault>(m1, m2, *descr->field(i), differentPath)) {
+ return false;
+ }
+ return true;
+ }
+
+ bool IsEqual(const Message& m1, const Message& m2) {
+ return IsEqualImpl<false>(m1, m2, nullptr);
+ }
+
+ bool IsEqual(const Message& m1, const Message& m2, TString* differentPath) {
+ TVector<TString> differentPathVector;
+ TVector<TString>* differentPathVectorPtr = !!differentPath ? &differentPathVector : nullptr;
+ bool r = IsEqualImpl<false>(m1, m2, differentPathVectorPtr);
+ if (!r && differentPath) {
+ *differentPath = JoinStrings(differentPathVector.rbegin(), differentPathVector.rend(), "/");
+ }
+ return r;
+ }
+
+ bool IsEqualDefault(const Message& m1, const Message& m2) {
+ return IsEqualImpl<true>(m1, m2, nullptr);
+ }
+
+ template <bool useDefault>
+ static bool IsEqualFieldImpl(
+ const Message& m1,
+ const Message& m2,
+ const FieldDescriptor& field,
+ TVector<TString>* differentPath) {
+ const Descriptor* descr = m1.GetDescriptor();
+ if (descr != m2.GetDescriptor()) {
+ return false;
+ }
+ return IsEqualField<useDefault>(m1, m2, field, differentPath);
+ }
+
+ bool IsEqualField(const Message& m1, const Message& m2, const FieldDescriptor& field) {
+ return IsEqualFieldImpl<false>(m1, m2, field, nullptr);
+ }
+
+ bool IsEqualFieldDefault(const Message& m1, const Message& m2, const FieldDescriptor& field) {
+ return IsEqualFieldImpl<true>(m1, m2, field, nullptr);
+ }
+
+}
diff --git a/library/cpp/protobuf/util/is_equal.h b/library/cpp/protobuf/util/is_equal.h
new file mode 100644
index 0000000000..13c0aae63d
--- /dev/null
+++ b/library/cpp/protobuf/util/is_equal.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <util/generic/fwd.h>
+
+namespace google {
+ namespace protobuf {
+ class Message;
+ class FieldDescriptor;
+ }
+}
+
+namespace NProtoBuf {
+ using ::google::protobuf::FieldDescriptor;
+ using ::google::protobuf::Message;
+}
+
+namespace NProtoBuf {
+ // Reflection-based equality check for arbitrary protobuf messages
+
+ // Strict comparison: optional field without value is NOT equal to
+ // a field with explicitly set default value.
+ bool IsEqual(const Message& m1, const Message& m2);
+ bool IsEqual(const Message& m1, const Message& m2, TString* differentPath);
+
+ bool IsEqualField(const Message& m1, const Message& m2, const FieldDescriptor& field);
+
+ // Non-strict version: optional field without explicit value is compared
+ // using its default value.
+ bool IsEqualDefault(const Message& m1, const Message& m2);
+
+ bool IsEqualFieldDefault(const Message& m1, const Message& m2, const FieldDescriptor& field);
+
+}
diff --git a/library/cpp/protobuf/util/is_equal_ut.cpp b/library/cpp/protobuf/util/is_equal_ut.cpp
new file mode 100644
index 0000000000..3ca4c90dd5
--- /dev/null
+++ b/library/cpp/protobuf/util/is_equal_ut.cpp
@@ -0,0 +1,88 @@
+#include "is_equal.h"
+#include <library/cpp/protobuf/util/ut/sample_for_is_equal.pb.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <google/protobuf/descriptor.h>
+
+Y_UNIT_TEST_SUITE(ProtobufIsEqual) {
+ const ::google::protobuf::Descriptor* Descr = TSampleForIsEqual::descriptor();
+ const ::google::protobuf::FieldDescriptor* NameDescr = Descr->field(0);
+ const ::google::protobuf::FieldDescriptor* InnerDescr = Descr->field(1);
+
+ Y_UNIT_TEST(CheckDescriptors) {
+ UNIT_ASSERT(Descr);
+ UNIT_ASSERT(NameDescr);
+ UNIT_ASSERT_VALUES_EQUAL(NameDescr->name(), "Name");
+ UNIT_ASSERT_VALUES_EQUAL(InnerDescr->name(), "Inner");
+ }
+
+ Y_UNIT_TEST(IsEqual1) {
+ TSampleForIsEqual a;
+ TSampleForIsEqual b;
+
+ a.SetName("aaa");
+ b.SetName("bbb");
+
+ TString path;
+
+ bool equal = NProtoBuf::IsEqual(a, b, &path);
+ UNIT_ASSERT(!equal);
+ UNIT_ASSERT_VALUES_EQUAL("Name", path);
+
+ UNIT_ASSERT(!NProtoBuf::IsEqualField(a, b, *NameDescr));
+ }
+
+ Y_UNIT_TEST(IsEqual2) {
+ TSampleForIsEqual a;
+ TSampleForIsEqual b;
+
+ a.MutableInner()->SetBrbrbr("aaa");
+ b.MutableInner()->SetBrbrbr("bbb");
+
+ TString path;
+
+ bool equal = NProtoBuf::IsEqual(a, b, &path);
+ UNIT_ASSERT(!equal);
+ UNIT_ASSERT_VALUES_EQUAL("Inner/Brbrbr", path);
+
+ bool equalField = NProtoBuf::IsEqualField(a, b, *InnerDescr);
+ UNIT_ASSERT(!equalField);
+ }
+
+ Y_UNIT_TEST(IsEqual3) {
+ TSampleForIsEqual a;
+ TSampleForIsEqual b;
+
+ a.SetName("aaa");
+ a.MutableInner()->SetBrbrbr("bbb");
+
+ b.SetName("aaa");
+ b.MutableInner()->SetBrbrbr("bbb");
+
+ TString path;
+
+ UNIT_ASSERT(NProtoBuf::IsEqual(a, b));
+ UNIT_ASSERT(NProtoBuf::IsEqualField(a, b, *NameDescr));
+ UNIT_ASSERT(NProtoBuf::IsEqualField(a, b, *InnerDescr));
+
+ b.MutableInner()->SetBrbrbr("ccc");
+ UNIT_ASSERT(!NProtoBuf::IsEqual(a, b));
+ UNIT_ASSERT(!NProtoBuf::IsEqualField(a, b, *InnerDescr));
+
+ b.SetName("ccc");
+ UNIT_ASSERT(!NProtoBuf::IsEqualField(a, b, *NameDescr));
+ }
+
+ Y_UNIT_TEST(IsEqualDefault) {
+ TSampleForIsEqual a;
+ TSampleForIsEqual b;
+
+ a.SetName("");
+ UNIT_ASSERT(NProtoBuf::IsEqualDefault(a, b));
+ UNIT_ASSERT(!NProtoBuf::IsEqual(a, b));
+
+ UNIT_ASSERT(!NProtoBuf::IsEqualField(a, b, *NameDescr));
+ UNIT_ASSERT(NProtoBuf::IsEqualFieldDefault(a, b, *NameDescr));
+ }
+}
diff --git a/library/cpp/protobuf/util/iterators.h b/library/cpp/protobuf/util/iterators.h
new file mode 100644
index 0000000000..6d53ac71b1
--- /dev/null
+++ b/library/cpp/protobuf/util/iterators.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <google/protobuf/descriptor.h>
+
+namespace NProtoBuf {
+ class TFieldsIterator {
+ public:
+ explicit TFieldsIterator(const NProtoBuf::Descriptor* descriptor, int position = 0)
+ : Descriptor(descriptor)
+ , Position(position)
+ { }
+
+ TFieldsIterator& operator++() {
+ ++Position;
+ return *this;
+ }
+
+ TFieldsIterator& operator++(int) {
+ auto& ret = *this;
+ ++*this;
+ return ret;
+ }
+
+ const NProtoBuf::FieldDescriptor* operator*() const {
+ return Descriptor->field(Position);
+ }
+
+ bool operator== (const TFieldsIterator& other) const {
+ return Position == other.Position && Descriptor == other.Descriptor;
+ }
+
+ bool operator!= (const TFieldsIterator& other) const {
+ return !(*this == other);
+ }
+
+ private:
+ const NProtoBuf::Descriptor* Descriptor = nullptr;
+ int Position = 0;
+ };
+}
+
+// Namespaces required by `range-based for` ADL:
+namespace google {
+ namespace protobuf {
+ NProtoBuf::TFieldsIterator begin(const NProtoBuf::Descriptor& descriptor) {
+ return NProtoBuf::TFieldsIterator(&descriptor);
+ }
+
+ NProtoBuf::TFieldsIterator end(const NProtoBuf::Descriptor& descriptor) {
+ return NProtoBuf::TFieldsIterator(&descriptor, descriptor.field_count());
+ }
+ }
+}
diff --git a/library/cpp/protobuf/util/iterators_ut.cpp b/library/cpp/protobuf/util/iterators_ut.cpp
new file mode 100644
index 0000000000..9ebcff2963
--- /dev/null
+++ b/library/cpp/protobuf/util/iterators_ut.cpp
@@ -0,0 +1,52 @@
+#include "iterators.h"
+#include "simple_reflection.h"
+#include <library/cpp/protobuf/util/ut/common_ut.pb.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/algorithm.h>
+
+using NProtoBuf::TFieldsIterator;
+using NProtoBuf::TConstField;
+
+Y_UNIT_TEST_SUITE(Iterators) {
+ Y_UNIT_TEST(Count) {
+ const NProtobufUtilUt::TWalkTest proto;
+ const NProtoBuf::Descriptor* d = proto.GetDescriptor();
+ TFieldsIterator dbegin(d), dend(d, d->field_count());
+ size_t steps = 0;
+
+ UNIT_ASSERT_EQUAL(dbegin, begin(*d));
+ UNIT_ASSERT_EQUAL(dend, end(*d));
+
+ for (; dbegin != dend; ++dbegin)
+ ++steps;
+ UNIT_ASSERT_VALUES_EQUAL(steps, d->field_count());
+ }
+
+ Y_UNIT_TEST(RangeFor) {
+ size_t steps = 0, values = 0;
+ NProtobufUtilUt::TWalkTest proto;
+ proto.SetOptStr("yandex");
+ for (const auto& field : *proto.GetDescriptor()) {
+ values += TConstField(proto, field).HasValue();
+ ++steps;
+ }
+ UNIT_ASSERT_VALUES_EQUAL(steps, proto.GetDescriptor()->field_count());
+ UNIT_ASSERT_VALUES_EQUAL(values, 1);
+ }
+
+ Y_UNIT_TEST(AnyOf) {
+ NProtobufUtilUt::TWalkTest proto;
+ const NProtoBuf::Descriptor* d = proto.GetDescriptor();
+ TFieldsIterator begin(d), end(d, d->field_count());
+ UNIT_ASSERT(!AnyOf(begin, end, [&proto](const NProtoBuf::FieldDescriptor* f){
+ return TConstField(proto, f).HasValue();
+ }));
+
+ proto.SetOptStr("yandex");
+ UNIT_ASSERT(AnyOf(begin, end, [&proto](const NProtoBuf::FieldDescriptor* f){
+ return TConstField(proto, f).HasValue();
+ }));
+ }
+}
diff --git a/library/cpp/protobuf/util/merge.cpp b/library/cpp/protobuf/util/merge.cpp
new file mode 100644
index 0000000000..dc2b9cc806
--- /dev/null
+++ b/library/cpp/protobuf/util/merge.cpp
@@ -0,0 +1,46 @@
+#include "merge.h"
+#include "simple_reflection.h"
+
+#include <google/protobuf/message.h>
+
+#include <library/cpp/protobuf/util/proto/merge.pb.h>
+
+namespace NProtoBuf {
+ void RewriteMerge(const Message& src, Message& dst) {
+ const Descriptor* d = src.GetDescriptor();
+ Y_ASSERT(d == dst.GetDescriptor());
+
+ for (int i = 0; i < d->field_count(); ++i) {
+ if (TConstField(src, d->field(i)).Has())
+ TMutableField(dst, d->field(i)).Clear();
+ }
+
+ dst.MergeFrom(src);
+ }
+
+ static void ClearNonMergeable(const Message& src, Message& dst) {
+ const Descriptor* d = src.GetDescriptor();
+ if (d->options().GetExtension(DontMerge)) {
+ dst.Clear();
+ return;
+ }
+
+ for (int i = 0; i < d->field_count(); ++i) {
+ const FieldDescriptor* fd = d->field(i);
+ TConstField srcField(src, fd);
+ if (srcField.Has()) {
+ TMutableField dstField(dst, fd);
+ if (fd->options().GetExtension(DontMergeField))
+ dstField.Clear();
+ else if (!fd->is_repeated() && dstField.IsMessage() && dstField.Has())
+ ClearNonMergeable(*srcField.Get<const Message*>(), *dstField.MutableMessage());
+ }
+ }
+ }
+
+ void CustomMerge(const Message& src, Message& dst) {
+ ClearNonMergeable(src, dst);
+ dst.MergeFrom(src);
+ }
+
+}
diff --git a/library/cpp/protobuf/util/merge.h b/library/cpp/protobuf/util/merge.h
new file mode 100644
index 0000000000..924975f141
--- /dev/null
+++ b/library/cpp/protobuf/util/merge.h
@@ -0,0 +1,22 @@
+#pragma once
+
+namespace google {
+ namespace protobuf {
+ class Message;
+ }
+}
+
+namespace NProtoBuf {
+ using Message = ::google::protobuf::Message;
+}
+
+namespace NProtoBuf {
+ // Similiar to Message::MergeFrom, overwrites existing repeated fields
+ // and embedded messages completely instead of recursive merging.
+ void RewriteMerge(const Message& src, Message& dst);
+
+ // Does standard MergeFrom() by default, except messages/fields marked with DontMerge or DontMergeField option.
+ // Such fields are merged using RewriteMerge() (i.e. destination is cleared before merging anything from source)
+ void CustomMerge(const Message& src, Message& dst);
+
+}
diff --git a/library/cpp/protobuf/util/merge_ut.cpp b/library/cpp/protobuf/util/merge_ut.cpp
new file mode 100644
index 0000000000..22217db183
--- /dev/null
+++ b/library/cpp/protobuf/util/merge_ut.cpp
@@ -0,0 +1,83 @@
+#include "merge.h"
+#include <library/cpp/protobuf/util/ut/common_ut.pb.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NProtoBuf;
+
+Y_UNIT_TEST_SUITE(ProtobufMerge) {
+ static void InitProto(NProtobufUtilUt::TMergeTest & p, bool isSrc) {
+ size_t start = isSrc ? 0 : 100;
+
+ p.AddMergeInt(start + 1);
+ p.AddMergeInt(start + 2);
+
+ p.AddNoMergeInt(start + 3);
+ p.AddNoMergeInt(start + 4);
+
+ NProtobufUtilUt::TMergeTestMerge* m = p.MutableMergeSub();
+ m->SetA(start + 5);
+ m->AddB(start + 6);
+ m->AddB(start + 7);
+ m->AddC(start + 14);
+
+ if (!isSrc) {
+ // only for dst
+ NProtobufUtilUt::TMergeTestMerge* mm1 = p.AddNoMergeRepSub();
+ mm1->SetA(start + 8);
+ mm1->AddB(start + 9);
+ mm1->AddB(start + 10);
+ }
+
+ NProtobufUtilUt::TMergeTestNoMerge* mm3 = p.MutableNoMergeOptSub();
+ mm3->SetA(start + 11);
+ mm3->AddB(start + 12);
+ mm3->AddB(start + 13);
+ }
+
+ Y_UNIT_TEST(CustomMerge) {
+ NProtobufUtilUt::TMergeTest src, dst;
+ InitProto(src, true);
+ InitProto(dst, false);
+
+ // Cerr << "\nsrc: " << src.ShortDebugString() << Endl;
+ // Cerr << "dst: " << dst.ShortDebugString() << Endl;
+ NProtoBuf::CustomMerge(src, dst);
+ // Cerr << "dst2:" << dst.ShortDebugString() << Endl;
+
+ // repeated uint32 MergeInt = 1;
+ UNIT_ASSERT_EQUAL(dst.MergeIntSize(), 4);
+ UNIT_ASSERT_EQUAL(dst.GetMergeInt(0), 101);
+ UNIT_ASSERT_EQUAL(dst.GetMergeInt(1), 102);
+ UNIT_ASSERT_EQUAL(dst.GetMergeInt(2), 1);
+ UNIT_ASSERT_EQUAL(dst.GetMergeInt(3), 2);
+
+ // repeated uint32 NoMergeInt = 2 [(DontMergeField)=true];
+ UNIT_ASSERT_EQUAL(dst.NoMergeIntSize(), 2);
+ UNIT_ASSERT_EQUAL(dst.GetNoMergeInt(0), 3);
+ UNIT_ASSERT_EQUAL(dst.GetNoMergeInt(1), 4);
+
+ // optional TMergeTestMerge MergeSub = 3;
+ UNIT_ASSERT_EQUAL(dst.GetMergeSub().GetA(), 5);
+ UNIT_ASSERT_EQUAL(dst.GetMergeSub().BSize(), 4);
+ UNIT_ASSERT_EQUAL(dst.GetMergeSub().GetB(0), 106);
+ UNIT_ASSERT_EQUAL(dst.GetMergeSub().GetB(1), 107);
+ UNIT_ASSERT_EQUAL(dst.GetMergeSub().GetB(2), 6);
+ UNIT_ASSERT_EQUAL(dst.GetMergeSub().GetB(3), 7);
+ UNIT_ASSERT_EQUAL(dst.GetMergeSub().CSize(), 1);
+ UNIT_ASSERT_EQUAL(dst.GetMergeSub().GetC(0), 14);
+
+ // repeated TMergeTestMerge NoMergeRepSub = 4 [(DontMergeField)=true];
+ UNIT_ASSERT_EQUAL(dst.NoMergeRepSubSize(), 1);
+ UNIT_ASSERT_EQUAL(dst.GetNoMergeRepSub(0).GetA(), 108);
+ UNIT_ASSERT_EQUAL(dst.GetNoMergeRepSub(0).BSize(), 2);
+ UNIT_ASSERT_EQUAL(dst.GetNoMergeRepSub(0).GetB(0), 109);
+ UNIT_ASSERT_EQUAL(dst.GetNoMergeRepSub(0).GetB(1), 110);
+
+ // optional TMergeTestNoMerge NoMergeOptSub = 5;
+ UNIT_ASSERT_EQUAL(dst.GetNoMergeOptSub().GetA(), 11);
+ UNIT_ASSERT_EQUAL(dst.GetNoMergeOptSub().BSize(), 2);
+ UNIT_ASSERT_EQUAL(dst.GetNoMergeOptSub().GetB(0), 12);
+ UNIT_ASSERT_EQUAL(dst.GetNoMergeOptSub().GetB(1), 13);
+ }
+}
diff --git a/library/cpp/protobuf/util/path.cpp b/library/cpp/protobuf/util/path.cpp
new file mode 100644
index 0000000000..efa2a42c8a
--- /dev/null
+++ b/library/cpp/protobuf/util/path.cpp
@@ -0,0 +1,61 @@
+#include "path.h"
+
+#include <util/generic/yexception.h>
+
+namespace NProtoBuf {
+ TFieldPath::TFieldPath() {
+ }
+
+ TFieldPath::TFieldPath(const Descriptor* msgType, const TStringBuf& path) {
+ Init(msgType, path);
+ }
+
+ TFieldPath::TFieldPath(const TVector<const FieldDescriptor*>& path)
+ : Path(path)
+ {
+ }
+
+ bool TFieldPath::InitUnsafe(const Descriptor* msgType, TStringBuf path) {
+ Path.clear();
+ while (path) {
+ TStringBuf next;
+ while (!next && path)
+ next = path.NextTok('/');
+ if (!next)
+ return true;
+
+ if (!msgType) // need field but no message type
+ return false;
+
+ TString nextStr(next);
+ const FieldDescriptor* field = msgType->FindFieldByName(nextStr);
+ if (!field) {
+ // Try to find extension field by FindAllExtensions()
+ const DescriptorPool* pool = msgType->file()->pool();
+ Y_ASSERT(pool); // never NULL by protobuf docs
+ TVector<const FieldDescriptor*> extensions;
+ pool->FindAllExtensions(msgType, &extensions); // find all extensions of this extendee
+ for (const FieldDescriptor* ext : extensions) {
+ if (ext->full_name() == nextStr || ext->name() == nextStr) {
+ if (field)
+ return false; // ambiguity
+ field = ext;
+ }
+ }
+ }
+
+ if (!field)
+ return false;
+
+ Path.push_back(field);
+ msgType = field->type() == FieldDescriptor::TYPE_MESSAGE ? field->message_type() : nullptr;
+ }
+ return true;
+ }
+
+ void TFieldPath::Init(const Descriptor* msgType, const TStringBuf& path) {
+ if (!InitUnsafe(msgType, path))
+ ythrow yexception() << "Failed to resolve path \"" << path << "\" relative to " << msgType->full_name();
+ }
+
+}
diff --git a/library/cpp/protobuf/util/path.h b/library/cpp/protobuf/util/path.h
new file mode 100644
index 0000000000..487f643a2d
--- /dev/null
+++ b/library/cpp/protobuf/util/path.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+
+#include <util/generic/vector.h>
+
+namespace NProtoBuf {
+ class TFieldPath {
+ public:
+ TFieldPath();
+ TFieldPath(const Descriptor* msgType, const TStringBuf& path); // throws exception if path doesn't exist
+ TFieldPath(const TVector<const FieldDescriptor*>& path);
+ TFieldPath(const TFieldPath&) = default;
+ TFieldPath& operator=(const TFieldPath&) = default;
+
+ bool InitUnsafe(const Descriptor* msgType, const TStringBuf path); // noexcept
+ void Init(const Descriptor* msgType, const TStringBuf& path); // throws
+
+ const TVector<const FieldDescriptor*>& Fields() const {
+ return Path;
+ }
+
+ void AddField(const FieldDescriptor* field) {
+ Path.push_back(field);
+ }
+
+ const Descriptor* ParentType() const {
+ return Empty() ? nullptr : Path.front()->containing_type();
+ }
+
+ const FieldDescriptor* FieldDescr() const {
+ return Empty() ? nullptr : Path.back();
+ }
+
+ bool Empty() const {
+ return Path.empty();
+ }
+
+ explicit operator bool() const {
+ return !Empty();
+ }
+
+ bool operator!() const {
+ return Empty();
+ }
+
+ private:
+ TVector<const FieldDescriptor*> Path;
+ };
+
+}
diff --git a/library/cpp/protobuf/util/pb_io.cpp b/library/cpp/protobuf/util/pb_io.cpp
new file mode 100644
index 0000000000..6270ee0624
--- /dev/null
+++ b/library/cpp/protobuf/util/pb_io.cpp
@@ -0,0 +1,221 @@
+#include "pb_io.h"
+
+#include <library/cpp/binsaver/bin_saver.h>
+#include <library/cpp/string_utils/base64/base64.h>
+
+#include <google/protobuf/message.h>
+#include <google/protobuf/messagext.h>
+#include <google/protobuf/text_format.h>
+
+#include <util/generic/string.h>
+#include <util/stream/file.h>
+#include <util/stream/str.h>
+#include <util/string/cast.h>
+
+namespace NProtoBuf {
+
+ class TEnumIdValuePrinter : public google::protobuf::TextFormat::FastFieldValuePrinter {
+ public:
+ void PrintEnum(int32 val, const TString& /*name*/, google::protobuf::TextFormat::BaseTextGenerator* generator) const override {
+ generator->PrintString(ToString(val));
+ }
+ };
+
+ void ParseFromBase64String(const TStringBuf dataBase64, Message& m, bool allowUneven) {
+ if (!m.ParseFromString(allowUneven ? Base64DecodeUneven(dataBase64) : Base64StrictDecode(dataBase64))) {
+ ythrow yexception() << "can't parse " << m.GetTypeName() << " from base64-encoded string";
+ }
+ }
+
+ bool TryParseFromBase64String(const TStringBuf dataBase64, Message& m, bool allowUneven) {
+ try {
+ ParseFromBase64String(dataBase64, m, allowUneven);
+ return true;
+ } catch (const std::exception&) {
+ return false;
+ }
+ }
+
+ void SerializeToBase64String(const Message& m, TString& dataBase64) {
+ TString rawData;
+ if (!m.SerializeToString(&rawData)) {
+ ythrow yexception() << "can't serialize " << m.GetTypeName();
+ }
+
+ Base64EncodeUrl(rawData, dataBase64);
+ }
+
+ TString SerializeToBase64String(const Message& m) {
+ TString s;
+ SerializeToBase64String(m, s);
+ return s;
+ }
+
+ bool TrySerializeToBase64String(const Message& m, TString& dataBase64) {
+ try {
+ SerializeToBase64String(m, dataBase64);
+ return true;
+ } catch (const std::exception&) {
+ return false;
+ }
+ }
+
+ const TString ShortUtf8DebugString(const Message& message) {
+ TextFormat::Printer printer;
+ printer.SetSingleLineMode(true);
+ printer.SetUseUtf8StringEscaping(true);
+ TString result;
+ printer.PrintToString(message, &result);
+ return result;
+ }
+
+ bool MergePartialFromString(NProtoBuf::Message& m, const TStringBuf serializedProtoMessage) {
+ google::protobuf::io::CodedInputStream input(reinterpret_cast<const ui8*>(serializedProtoMessage.data()), serializedProtoMessage.size());
+ bool ok = m.MergePartialFromCodedStream(&input);
+ ok = ok && input.ConsumedEntireMessage();
+ return ok;
+ }
+
+ bool MergeFromString(NProtoBuf::Message& m, const TStringBuf serializedProtoMessage) {
+ return MergePartialFromString(m, serializedProtoMessage) && m.IsInitialized();
+ }
+}
+
+int operator&(NProtoBuf::Message& m, IBinSaver& f) {
+ TStringStream ss;
+ if (f.IsReading()) {
+ f.Add(0, &ss.Str());
+ m.ParseFromArcadiaStream(&ss);
+ } else {
+ m.SerializeToArcadiaStream(&ss);
+ f.Add(0, &ss.Str());
+ }
+ return 0;
+}
+
+void SerializeToTextFormat(const NProtoBuf::Message& m, IOutputStream& out) {
+ NProtoBuf::io::TCopyingOutputStreamAdaptor adaptor(&out);
+
+ if (!NProtoBuf::TextFormat::Print(m, &adaptor)) {
+ ythrow yexception() << "SerializeToTextFormat failed on Print";
+ }
+}
+
+void SerializeToTextFormat(const NProtoBuf::Message& m, const TString& fileName) {
+ /* TUnbufferedFileOutput is unbuffered, but TCopyingOutputStreamAdaptor adds
+ * a buffer on top of it. */
+ TUnbufferedFileOutput stream(fileName);
+ SerializeToTextFormat(m, stream);
+}
+
+void SerializeToTextFormatWithEnumId(const NProtoBuf::Message& m, IOutputStream& out) {
+ google::protobuf::TextFormat::Printer printer;
+ printer.SetDefaultFieldValuePrinter(new NProtoBuf::TEnumIdValuePrinter());
+ NProtoBuf::io::TCopyingOutputStreamAdaptor adaptor(&out);
+
+ if (!printer.Print(m, &adaptor)) {
+ ythrow yexception() << "SerializeToTextFormatWithEnumId failed on Print";
+ }
+}
+
+void SerializeToTextFormatPretty(const NProtoBuf::Message& m, IOutputStream& out) {
+ google::protobuf::TextFormat::Printer printer;
+ printer.SetUseUtf8StringEscaping(true);
+ printer.SetUseShortRepeatedPrimitives(true);
+
+ NProtoBuf::io::TCopyingOutputStreamAdaptor adaptor(&out);
+
+ if (!printer.Print(m, &adaptor)) {
+ ythrow yexception() << "SerializeToTextFormatPretty failed on Print";
+ }
+}
+
+static void ConfigureParser(const EParseFromTextFormatOptions options,
+ NProtoBuf::TextFormat::Parser& p) {
+ if (options & EParseFromTextFormatOption::AllowUnknownField) {
+ p.AllowUnknownField(true);
+ }
+}
+
+void ParseFromTextFormat(IInputStream& in, NProtoBuf::Message& m,
+ const EParseFromTextFormatOptions options) {
+ NProtoBuf::io::TCopyingInputStreamAdaptor adaptor(&in);
+ NProtoBuf::TextFormat::Parser p;
+ ConfigureParser(options, p);
+
+ if (!p.Parse(&adaptor, &m)) {
+ // remove everything that may have been read
+ m.Clear();
+ ythrow yexception() << "ParseFromTextFormat failed on Parse for " << m.GetTypeName();
+ }
+}
+
+void ParseFromTextFormat(const TString& fileName, NProtoBuf::Message& m,
+ const EParseFromTextFormatOptions options) {
+ /* TUnbufferedFileInput is unbuffered, but TCopyingInputStreamAdaptor adds
+ * a buffer on top of it. */
+ TUnbufferedFileInput stream(fileName);
+ ParseFromTextFormat(stream, m, options);
+}
+
+bool TryParseFromTextFormat(const TString& fileName, NProtoBuf::Message& m,
+ const EParseFromTextFormatOptions options) {
+ try {
+ ParseFromTextFormat(fileName, m, options);
+ } catch (std::exception&) {
+ return false;
+ }
+
+ return true;
+}
+
+bool TryParseFromTextFormat(IInputStream& in, NProtoBuf::Message& m,
+ const EParseFromTextFormatOptions options) {
+ try {
+ ParseFromTextFormat(in, m, options);
+ } catch (std::exception&) {
+ return false;
+ }
+
+ return true;
+}
+
+void MergeFromTextFormat(IInputStream& in, NProtoBuf::Message& m,
+ const EParseFromTextFormatOptions options) {
+ NProtoBuf::io::TCopyingInputStreamAdaptor adaptor(&in);
+ NProtoBuf::TextFormat::Parser p;
+ ConfigureParser(options, p);
+ if (!p.Merge(&adaptor, &m)) {
+ ythrow yexception() << "MergeFromTextFormat failed on Merge for " << m.GetTypeName();
+ }
+}
+
+void MergeFromTextFormat(const TString& fileName, NProtoBuf::Message& m,
+ const EParseFromTextFormatOptions options) {
+ /* TUnbufferedFileInput is unbuffered, but TCopyingInputStreamAdaptor adds
+ * a buffer on top of it. */
+ TUnbufferedFileInput stream(fileName);
+ MergeFromTextFormat(stream, m, options);
+}
+
+bool TryMergeFromTextFormat(const TString& fileName, NProtoBuf::Message& m,
+ const EParseFromTextFormatOptions options) {
+ try {
+ MergeFromTextFormat(fileName, m, options);
+ } catch (std::exception&) {
+ return false;
+ }
+
+ return true;
+}
+
+bool TryMergeFromTextFormat(IInputStream& in, NProtoBuf::Message& m,
+ const EParseFromTextFormatOptions options) {
+ try {
+ MergeFromTextFormat(in, m, options);
+ } catch (std::exception&) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/library/cpp/protobuf/util/pb_io.h b/library/cpp/protobuf/util/pb_io.h
new file mode 100644
index 0000000000..493c84cb5f
--- /dev/null
+++ b/library/cpp/protobuf/util/pb_io.h
@@ -0,0 +1,138 @@
+#pragma once
+
+#include <util/generic/fwd.h>
+#include <util/generic/flags.h>
+
+struct IBinSaver;
+
+namespace google {
+ namespace protobuf {
+ class Message;
+ }
+}
+
+namespace NProtoBuf {
+ using Message = ::google::protobuf::Message;
+}
+
+class IInputStream;
+class IOutputStream;
+
+namespace NProtoBuf {
+ /* Parse base64 URL encoded serialized message from string.
+ */
+ void ParseFromBase64String(const TStringBuf dataBase64, Message& m, bool allowUneven = false);
+ bool TryParseFromBase64String(const TStringBuf dataBase64, Message& m, bool allowUneven = false);
+ template <typename T>
+ static T ParseFromBase64String(const TStringBuf& dataBase64, bool allowUneven = false) {
+ T m;
+ ParseFromBase64String(dataBase64, m, allowUneven);
+ return m;
+ }
+
+ /* Serialize message into string and apply base64 URL encoding.
+ */
+ TString SerializeToBase64String(const Message& m);
+ void SerializeToBase64String(const Message& m, TString& dataBase64);
+ bool TrySerializeToBase64String(const Message& m, TString& dataBase64);
+
+ const TString ShortUtf8DebugString(const Message& message);
+
+ bool MergePartialFromString(NProtoBuf::Message& m, const TStringBuf serializedProtoMessage);
+ bool MergeFromString(NProtoBuf::Message& m, const TStringBuf serializedProtoMessage);
+}
+
+int operator&(NProtoBuf::Message& m, IBinSaver& f);
+
+// Write a textual representation of the given message to the given file.
+void SerializeToTextFormat(const NProtoBuf::Message& m, const TString& fileName);
+void SerializeToTextFormat(const NProtoBuf::Message& m, IOutputStream& out);
+
+// Write a textual representation of the given message to the given output stream
+// with flags UseShortRepeatedPrimitives and UseUtf8StringEscaping set to true.
+void SerializeToTextFormatPretty(const NProtoBuf::Message& m, IOutputStream& out);
+
+// Write a textual representation of the given message to the given output stream
+// use enum id instead of enum name for all enum fields.
+void SerializeToTextFormatWithEnumId(const NProtoBuf::Message& m, IOutputStream& out);
+
+enum class EParseFromTextFormatOption : ui64 {
+ // Unknown fields will be ignored by the parser
+ AllowUnknownField = 1
+};
+
+Y_DECLARE_FLAGS(EParseFromTextFormatOptions, EParseFromTextFormatOption);
+
+// Parse a text-format protocol message from the given file into message object.
+void ParseFromTextFormat(const TString& fileName, NProtoBuf::Message& m,
+ const EParseFromTextFormatOptions options = {});
+// NOTE: will read `in` till the end.
+void ParseFromTextFormat(IInputStream& in, NProtoBuf::Message& m,
+ const EParseFromTextFormatOptions options = {});
+
+/* @return `true` if parsing was successfull and `false` otherwise.
+ *
+ * @see `ParseFromTextFormat`
+ */
+bool TryParseFromTextFormat(const TString& fileName, NProtoBuf::Message& m,
+ const EParseFromTextFormatOptions options = {});
+// NOTE: will read `in` till the end.
+bool TryParseFromTextFormat(IInputStream& in, NProtoBuf::Message& m,
+ const EParseFromTextFormatOptions options = {});
+
+// @see `ParseFromTextFormat`
+template <typename T>
+static T ParseFromTextFormat(const TString& fileName,
+ const EParseFromTextFormatOptions options = {}) {
+ T message;
+ ParseFromTextFormat(fileName, message, options);
+ return message;
+}
+
+// @see `ParseFromTextFormat`
+// NOTE: will read `in` till the end.
+template <typename T>
+static T ParseFromTextFormat(IInputStream& in,
+ const EParseFromTextFormatOptions options = {}) {
+ T message;
+ ParseFromTextFormat(in, message, options);
+ return message;
+}
+
+// Merge a text-format protocol message from the given file into message object.
+//
+// NOTE: Even when parsing failed and exception was thrown `m` may be different from its original
+// value. User must implement transactional logic around `MergeFromTextFormat` by himself.
+void MergeFromTextFormat(const TString& fileName, NProtoBuf::Message& m,
+ const EParseFromTextFormatOptions options = {});
+// NOTE: will read `in` till the end.
+void MergeFromTextFormat(IInputStream& in, NProtoBuf::Message& m,
+ const EParseFromTextFormatOptions options = {});
+/* @return `true` if parsing was successfull and `false` otherwise.
+ *
+ * @see `MergeFromTextFormat`
+ */
+bool TryMergeFromTextFormat(const TString& fileName, NProtoBuf::Message& m,
+ const EParseFromTextFormatOptions options = {});
+// NOTE: will read `in` till the end.
+bool TryMergeFromTextFormat(IInputStream& in, NProtoBuf::Message& m,
+ const EParseFromTextFormatOptions options = {});
+
+// @see `MergeFromTextFormat`
+template <typename T>
+static T MergeFromTextFormat(const TString& fileName,
+ const EParseFromTextFormatOptions options = {}) {
+ T message;
+ MergeFromTextFormat(fileName, message, options);
+ return message;
+}
+
+// @see `MergeFromTextFormat`
+// NOTE: will read `in` till the end.
+template <typename T>
+static T MergeFromTextFormat(IInputStream& in,
+ const EParseFromTextFormatOptions options = {}) {
+ T message;
+ MergeFromTextFormat(in, message, options);
+ return message;
+}
diff --git a/library/cpp/protobuf/util/pb_io_ut.cpp b/library/cpp/protobuf/util/pb_io_ut.cpp
new file mode 100644
index 0000000000..875d6dc602
--- /dev/null
+++ b/library/cpp/protobuf/util/pb_io_ut.cpp
@@ -0,0 +1,418 @@
+#include "pb_io.h"
+
+#include "is_equal.h"
+
+#include <library/cpp/protobuf/util/ut/common_ut.pb.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/folder/path.h>
+#include <util/folder/tempdir.h>
+#include <util/stream/file.h>
+#include <util/stream/str.h>
+
+static NProtobufUtilUt::TTextTest GetCorrectMessage() {
+ NProtobufUtilUt::TTextTest m;
+ m.SetFoo(42);
+ return m;
+}
+
+static NProtobufUtilUt::TTextEnumTest GetCorrectEnumMessage() {
+ NProtobufUtilUt::TTextEnumTest m;
+ m.SetSlot(NProtobufUtilUt::TTextEnumTest::EET_SLOT_1);
+ return m;
+}
+
+static const TString CORRECT_MESSAGE =
+ R"(Foo: 42
+)";
+static const TString CORRECT_ENUM_NAME_MESSAGE =
+ R"(Slot: EET_SLOT_1
+)";
+static const TString CORRECT_ENUM_ID_MESSAGE =
+ R"(Slot: 1
+)";
+
+static const TString INCORRECT_MESSAGE =
+ R"(Bar: 1
+)";
+static const TString INCORRECT_ENUM_NAME_MESSAGE =
+ R"(Slot: EET_SLOT_3
+)";
+static const TString INCORRECT_ENUM_ID_MESSAGE =
+ R"(Slot: 3
+)";
+
+static const TString CORRECT_BASE64_MESSAGE = "CCo,";
+
+static const TString CORRECT_UNEVEN_BASE64_MESSAGE = "CCo";
+
+static const TString INCORRECT_BASE64_MESSAGE = "CC";
+
+Y_UNIT_TEST_SUITE(TTestProtoBufIO) {
+ Y_UNIT_TEST(TestBase64) {
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT(NProtoBuf::TryParseFromBase64String(CORRECT_BASE64_MESSAGE, message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT(!NProtoBuf::TryParseFromBase64String(INCORRECT_BASE64_MESSAGE, message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT(NProtoBuf::TryParseFromBase64String(CORRECT_UNEVEN_BASE64_MESSAGE , message, true));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT(!NProtoBuf::TryParseFromBase64String(CORRECT_UNEVEN_BASE64_MESSAGE , message, false));
+ }
+ {
+ UNIT_ASSERT_VALUES_EQUAL(CORRECT_BASE64_MESSAGE, NProtoBuf::SerializeToBase64String(GetCorrectMessage()));
+ }
+ {
+ const auto m = NProtoBuf::ParseFromBase64String<NProtobufUtilUt::TTextTest>(CORRECT_BASE64_MESSAGE);
+ UNIT_ASSERT(NProtoBuf::IsEqual(GetCorrectMessage(), m));
+ }
+ }
+
+ Y_UNIT_TEST(TestParseFromTextFormat) {
+ TTempDir tempDir;
+ const TFsPath correctFileName = TFsPath{tempDir()} / "correct.pb.txt";
+ const TFsPath incorrectFileName = TFsPath{tempDir()} / "incorrect.pb.txt";
+
+ TFileOutput{correctFileName}.Write(CORRECT_MESSAGE);
+ TFileOutput{incorrectFileName}.Write(INCORRECT_MESSAGE);
+
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT(TryParseFromTextFormat(correctFileName, message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT(!TryParseFromTextFormat(incorrectFileName, message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ TStringInput in{CORRECT_MESSAGE};
+ UNIT_ASSERT(TryParseFromTextFormat(in, message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ TStringInput in{INCORRECT_MESSAGE};
+ UNIT_ASSERT(!TryParseFromTextFormat(in, message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT_NO_EXCEPTION(TryParseFromTextFormat(incorrectFileName, message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT(!TryParseFromTextFormat("this_file_doesnt_exists", message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT_NO_EXCEPTION(TryParseFromTextFormat("this_file_doesnt_exists", message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT_EXCEPTION(ParseFromTextFormat("this_file_doesnt_exists", message), TFileError);
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT_NO_EXCEPTION(ParseFromTextFormat(correctFileName, message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT_EXCEPTION(ParseFromTextFormat(incorrectFileName, message), yexception);
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ TStringInput in{CORRECT_MESSAGE};
+ UNIT_ASSERT_NO_EXCEPTION(ParseFromTextFormat(in, message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ TStringInput in{INCORRECT_MESSAGE};
+ UNIT_ASSERT_EXCEPTION(ParseFromTextFormat(in, message), yexception);
+ }
+ {
+ NProtobufUtilUt::TTextTest m;
+ const auto f = [&correctFileName](NProtobufUtilUt::TTextTest& mm) {
+ mm = ParseFromTextFormat<NProtobufUtilUt::TTextTest>(correctFileName);
+ };
+ UNIT_ASSERT_NO_EXCEPTION(f(m));
+ UNIT_ASSERT(NProtoBuf::IsEqual(GetCorrectMessage(), m));
+ }
+ {
+ UNIT_ASSERT_EXCEPTION(ParseFromTextFormat<NProtobufUtilUt::TTextTest>(incorrectFileName), yexception);
+ }
+ {
+ NProtobufUtilUt::TTextTest m;
+ TStringInput in{CORRECT_MESSAGE};
+ const auto f = [&in](NProtobufUtilUt::TTextTest& mm) {
+ mm = ParseFromTextFormat<NProtobufUtilUt::TTextTest>(in);
+ };
+ UNIT_ASSERT_NO_EXCEPTION(f(m));
+ UNIT_ASSERT(NProtoBuf::IsEqual(GetCorrectMessage(), m));
+ }
+ {
+ TStringInput in{INCORRECT_MESSAGE};
+ UNIT_ASSERT_EXCEPTION(ParseFromTextFormat<NProtobufUtilUt::TTextTest>(in), yexception);
+ }
+ {
+ const TFsPath correctFileName2 = TFsPath{tempDir()} / "serialized.pb.txt";
+ const auto original = GetCorrectMessage();
+ UNIT_ASSERT_NO_EXCEPTION(SerializeToTextFormat(original, correctFileName2));
+ const auto serializedStr = TUnbufferedFileInput{correctFileName2}.ReadAll();
+ UNIT_ASSERT_VALUES_EQUAL(serializedStr, CORRECT_MESSAGE);
+ }
+ {
+ const auto original = GetCorrectMessage();
+ TStringStream out;
+ UNIT_ASSERT_NO_EXCEPTION(SerializeToTextFormat(original, out));
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), CORRECT_MESSAGE);
+ }
+ {
+ NProtobufUtilUt::TTextTest m;
+ const auto f = [&correctFileName](NProtobufUtilUt::TTextTest& mm) {
+ mm = ParseFromTextFormat<NProtobufUtilUt::TTextTest>(
+ correctFileName,
+ EParseFromTextFormatOption::AllowUnknownField);
+ };
+ UNIT_ASSERT_NO_EXCEPTION(f(m));
+ UNIT_ASSERT(NProtoBuf::IsEqual(GetCorrectMessage(), m));
+ }
+ {
+ const NProtobufUtilUt::TTextTest empty;
+ NProtobufUtilUt::TTextTest m;
+ const auto f = [&incorrectFileName](NProtobufUtilUt::TTextTest& mm) {
+ mm = ParseFromTextFormat<NProtobufUtilUt::TTextTest>(
+ incorrectFileName,
+ EParseFromTextFormatOption::AllowUnknownField);
+ };
+ UNIT_ASSERT_NO_EXCEPTION(f(m));
+ UNIT_ASSERT(NProtoBuf::IsEqual(empty, m));
+ }
+ }
+
+ Y_UNIT_TEST(TestSerializeToTextFormatWithEnumId) {
+ TTempDir tempDir;
+ const TFsPath correctNameFileName = TFsPath{tempDir()} / "correct_name.pb.txt";
+ const TFsPath incorrectNameFileName = TFsPath{tempDir()} / "incorrect_name.pb.txt";
+ const TFsPath correctIdFileName = TFsPath{tempDir()} / "correct_id.pb.txt";
+ const TFsPath incorrectIdFileName = TFsPath{tempDir()} / "incorrect_id.pb.txt";
+
+ TFileOutput{correctNameFileName}.Write(CORRECT_ENUM_NAME_MESSAGE);
+ TFileOutput{incorrectNameFileName}.Write(INCORRECT_ENUM_NAME_MESSAGE);
+ TFileOutput{correctIdFileName}.Write(CORRECT_ENUM_ID_MESSAGE);
+ TFileOutput{incorrectIdFileName}.Write(INCORRECT_ENUM_ID_MESSAGE);
+
+ {
+ NProtobufUtilUt::TTextEnumTest message;
+ for (auto correct_message: {CORRECT_ENUM_ID_MESSAGE, CORRECT_ENUM_NAME_MESSAGE}) {
+ TStringInput in{correct_message};
+ UNIT_ASSERT_NO_EXCEPTION(ParseFromTextFormat(in, message));
+ }
+ }
+ {
+ NProtobufUtilUt::TTextEnumTest message;
+ for (auto incorrect_message: {INCORRECT_ENUM_ID_MESSAGE, INCORRECT_ENUM_NAME_MESSAGE}) {
+ TStringInput in{incorrect_message};
+ UNIT_ASSERT_EXCEPTION(ParseFromTextFormat(in, message), yexception);
+ }
+ }
+ {
+ const auto f = [](NProtobufUtilUt::TTextEnumTest& mm, const TString fileName) {
+ mm = ParseFromTextFormat<NProtobufUtilUt::TTextEnumTest>(fileName);
+ };
+ for (auto fileName: {correctIdFileName, correctNameFileName}) {
+ NProtobufUtilUt::TTextEnumTest m;
+ UNIT_ASSERT_NO_EXCEPTION(f(m, fileName));
+ UNIT_ASSERT(NProtoBuf::IsEqual(GetCorrectEnumMessage(), m));
+ }
+ }
+ {
+ UNIT_ASSERT_EXCEPTION(ParseFromTextFormat<NProtobufUtilUt::TTextEnumTest>(incorrectIdFileName), yexception);
+ UNIT_ASSERT_EXCEPTION(ParseFromTextFormat<NProtobufUtilUt::TTextEnumTest>(incorrectNameFileName), yexception);
+ }
+ {
+ const auto original = GetCorrectEnumMessage();
+ TStringStream out;
+ UNIT_ASSERT_NO_EXCEPTION(SerializeToTextFormat(original, out));
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), CORRECT_ENUM_NAME_MESSAGE);
+ }
+ {
+ const auto original = GetCorrectEnumMessage();
+ TStringStream out;
+ UNIT_ASSERT_NO_EXCEPTION(SerializeToTextFormatWithEnumId(original, out));
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), CORRECT_ENUM_ID_MESSAGE);
+ }
+ }
+
+ Y_UNIT_TEST(TestMergeFromTextFormat) {
+ //
+ // Tests cases below are identical to `Parse` tests
+ //
+ TTempDir tempDir;
+ const TFsPath correctFileName = TFsPath{tempDir()} / "correct.pb.txt";
+ const TFsPath incorrectFileName = TFsPath{tempDir()} / "incorrect.pb.txt";
+
+ TFileOutput{correctFileName}.Write(CORRECT_MESSAGE);
+ TFileOutput{incorrectFileName}.Write(INCORRECT_MESSAGE);
+
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT(TryMergeFromTextFormat(correctFileName, message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT(!TryMergeFromTextFormat(incorrectFileName, message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ TStringInput in{CORRECT_MESSAGE};
+ UNIT_ASSERT(TryMergeFromTextFormat(in, message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ TStringInput in{INCORRECT_MESSAGE};
+ UNIT_ASSERT(!TryMergeFromTextFormat(in, message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT_NO_EXCEPTION(TryMergeFromTextFormat(incorrectFileName, message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT(!TryMergeFromTextFormat("this_file_doesnt_exists", message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT_NO_EXCEPTION(TryMergeFromTextFormat("this_file_doesnt_exists", message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT_EXCEPTION(MergeFromTextFormat("this_file_doesnt_exists", message), TFileError);
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT_NO_EXCEPTION(MergeFromTextFormat(correctFileName, message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ UNIT_ASSERT_EXCEPTION(MergeFromTextFormat(incorrectFileName, message), yexception);
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ TStringInput in{CORRECT_MESSAGE};
+ UNIT_ASSERT_NO_EXCEPTION(MergeFromTextFormat(in, message));
+ }
+ {
+ NProtobufUtilUt::TTextTest message;
+ TStringInput in{INCORRECT_MESSAGE};
+ UNIT_ASSERT_EXCEPTION(MergeFromTextFormat(in, message), yexception);
+ }
+ {
+ NProtobufUtilUt::TTextTest m;
+ const auto f = [&correctFileName](NProtobufUtilUt::TTextTest& mm) {
+ mm = MergeFromTextFormat<NProtobufUtilUt::TTextTest>(correctFileName);
+ };
+ UNIT_ASSERT_NO_EXCEPTION(f(m));
+ UNIT_ASSERT(NProtoBuf::IsEqual(GetCorrectMessage(), m));
+ }
+ {
+ UNIT_ASSERT_EXCEPTION(MergeFromTextFormat<NProtobufUtilUt::TTextTest>(incorrectFileName), yexception);
+ }
+ {
+ NProtobufUtilUt::TTextTest m;
+ TStringInput in{CORRECT_MESSAGE};
+ const auto f = [&in](NProtobufUtilUt::TTextTest& mm) {
+ mm = MergeFromTextFormat<NProtobufUtilUt::TTextTest>(in);
+ };
+ UNIT_ASSERT_NO_EXCEPTION(f(m));
+ UNIT_ASSERT(NProtoBuf::IsEqual(GetCorrectMessage(), m));
+ }
+ {
+ TStringInput in{INCORRECT_MESSAGE};
+ UNIT_ASSERT_EXCEPTION(MergeFromTextFormat<NProtobufUtilUt::TTextTest>(in), yexception);
+ }
+ {
+ const TFsPath correctFileName2 = TFsPath{tempDir()} / "serialized.pb.txt";
+ const auto original = GetCorrectMessage();
+ UNIT_ASSERT_NO_EXCEPTION(SerializeToTextFormat(original, correctFileName2));
+ const auto serializedStr = TUnbufferedFileInput{correctFileName2}.ReadAll();
+ UNIT_ASSERT_VALUES_EQUAL(serializedStr, CORRECT_MESSAGE);
+ }
+ {
+ const auto original = GetCorrectMessage();
+ TStringStream out;
+ UNIT_ASSERT_NO_EXCEPTION(SerializeToTextFormat(original, out));
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), CORRECT_MESSAGE);
+ }
+ {
+ NProtobufUtilUt::TTextTest m;
+ const auto f = [&correctFileName](NProtobufUtilUt::TTextTest& mm) {
+ mm = MergeFromTextFormat<NProtobufUtilUt::TTextTest>(
+ correctFileName,
+ EParseFromTextFormatOption::AllowUnknownField);
+ };
+ UNIT_ASSERT_NO_EXCEPTION(f(m));
+ UNIT_ASSERT(NProtoBuf::IsEqual(GetCorrectMessage(), m));
+ }
+ {
+ const NProtobufUtilUt::TTextTest empty;
+ NProtobufUtilUt::TTextTest m;
+ const auto f = [&incorrectFileName](NProtobufUtilUt::TTextTest& mm) {
+ mm = MergeFromTextFormat<NProtobufUtilUt::TTextTest>(
+ incorrectFileName,
+ EParseFromTextFormatOption::AllowUnknownField);
+ };
+ UNIT_ASSERT_NO_EXCEPTION(f(m));
+ UNIT_ASSERT(NProtoBuf::IsEqual(empty, m));
+ }
+
+ //
+ // Test cases for `Merge`
+ //
+ {
+ NProtobufUtilUt::TTextTest message;
+ message.SetFoo(100500);
+ TStringInput in{CORRECT_MESSAGE};
+ UNIT_ASSERT(TryMergeFromTextFormat(in, message));
+ UNIT_ASSERT(NProtoBuf::IsEqual(message, GetCorrectMessage()));
+ }
+ }
+
+ Y_UNIT_TEST(TestMergeFromString) {
+ NProtobufUtilUt::TMergeTest message;
+ NProtobufUtilUt::TMergeTest messageFirstHalf;
+ NProtobufUtilUt::TMergeTest messageSecondHalf;
+
+ for (ui32 v = ~0; v != 0; v >>= 1) {
+ message.AddMergeInt(v);
+ (v > 0xffff ? messageFirstHalf : messageSecondHalf).AddMergeInt(v);
+ }
+
+ const TString full = message.SerializeAsString();
+
+ {
+ NProtobufUtilUt::TMergeTest m1;
+ UNIT_ASSERT(NProtoBuf::MergeFromString(m1, full));
+ UNIT_ASSERT(NProtoBuf::IsEqual(message, m1));
+ }
+ {
+ NProtobufUtilUt::TMergeTest m2;
+ TStringBuf s0 = TStringBuf(full).SubStr(0, 3);
+ TStringBuf s1 = TStringBuf(full).SubStr(3);
+ // объединение результатов двух MergePartialFromString не эквивалентно вызову MergePartialFromString от объединения строк
+ UNIT_ASSERT(!(NProtoBuf::MergePartialFromString(m2, s0) && NProtoBuf::MergePartialFromString(m2, s1)));
+ }
+ {
+ NProtobufUtilUt::TMergeTest m3;
+ UNIT_ASSERT(NProtoBuf::MergePartialFromString(m3, messageFirstHalf.SerializeAsString()));
+ UNIT_ASSERT(NProtoBuf::MergeFromString(m3, messageSecondHalf.SerializeAsString()));
+ UNIT_ASSERT(NProtoBuf::IsEqual(message, m3));
+ }
+ }
+}
diff --git a/library/cpp/protobuf/util/pb_utils.h b/library/cpp/protobuf/util/pb_utils.h
new file mode 100644
index 0000000000..9e9a110b48
--- /dev/null
+++ b/library/cpp/protobuf/util/pb_utils.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#define UPDATE_PB_FIELD_MAX(PBMESS, FIELD, VAL) \
+ if ((VAL) > (PBMESS).Get##FIELD()) { \
+ (PBMESS).Set##FIELD(VAL); \
+ }
+
+#define UPDATE_OPT_PB_FIELD_MAX(PBMESS, FIELD, VAL) \
+ if (!(PBMESS).Has##FIELD() || ((VAL) > (PBMESS).Get##FIELD())) { \
+ (PBMESS).Set##FIELD(VAL); \
+ }
diff --git a/library/cpp/protobuf/util/proto/merge.proto b/library/cpp/protobuf/util/proto/merge.proto
new file mode 100644
index 0000000000..a937041c07
--- /dev/null
+++ b/library/cpp/protobuf/util/proto/merge.proto
@@ -0,0 +1,11 @@
+import "google/protobuf/descriptor.proto";
+
+// These meta-options are used for selecting proper merging method, see merge.h
+
+extend google.protobuf.MessageOptions {
+ optional bool DontMerge = 54287;
+}
+
+extend google.protobuf.FieldOptions {
+ optional bool DontMergeField = 54288;
+}
diff --git a/library/cpp/protobuf/util/proto/ya.make b/library/cpp/protobuf/util/proto/ya.make
new file mode 100644
index 0000000000..4d68047d8b
--- /dev/null
+++ b/library/cpp/protobuf/util/proto/ya.make
@@ -0,0 +1,11 @@
+PROTO_LIBRARY()
+
+OWNER(mowgli)
+
+SRCS(
+ merge.proto
+)
+
+EXCLUDE_TAGS(GO_PROTO)
+
+END()
diff --git a/library/cpp/protobuf/util/repeated_field_utils.h b/library/cpp/protobuf/util/repeated_field_utils.h
new file mode 100644
index 0000000000..c07bd84647
--- /dev/null
+++ b/library/cpp/protobuf/util/repeated_field_utils.h
@@ -0,0 +1,96 @@
+#pragma once
+
+#include <google/protobuf/repeated_field.h>
+#include <util/generic/vector.h>
+
+template <typename T>
+void RemoveRepeatedPtrFieldElement(google::protobuf::RepeatedPtrField<T>* repeated, unsigned index) {
+ google::protobuf::RepeatedPtrField<T> r;
+ Y_ASSERT(index < (unsigned)repeated->size());
+ for (unsigned i = 0; i < (unsigned)repeated->size(); ++i) {
+ if (i == index) {
+ continue;
+ }
+ r.Add()->Swap(repeated->Mutable(i));
+ }
+ r.Swap(repeated);
+}
+
+namespace NProtoBuf {
+ /// Move item to specified position
+ template <typename TRepeated>
+ static void MoveRepeatedFieldItem(TRepeated* field, size_t indexFrom, size_t indexTo) {
+ if (!field->size() || indexFrom >= static_cast<size_t>(field->size()) || indexFrom == indexTo)
+ return;
+ if (indexTo >= static_cast<size_t>(field->size()))
+ indexTo = field->size() - 1;
+ if (indexFrom > indexTo) {
+ for (size_t i = indexFrom; i > indexTo; --i)
+ field->SwapElements(i, i - 1);
+ } else {
+ for (size_t i = indexFrom; i < indexTo; ++i)
+ field->SwapElements(i, i + 1);
+ }
+ }
+
+ template <typename T>
+ static T* InsertRepeatedFieldItem(NProtoBuf::RepeatedPtrField<T>* field, size_t index) {
+ T* ret = field->Add();
+ MoveRepeatedFieldItem(field, field->size() - 1, index);
+ return ret;
+ }
+
+ template <typename TRepeated> // suitable both for RepeatedField and RepeatedPtrField
+ static void RemoveRepeatedFieldItem(TRepeated* field, size_t index) {
+ if ((int)index >= field->size())
+ return;
+
+ for (int i = index + 1; i < field->size(); ++i)
+ field->SwapElements(i - 1, i);
+
+ field->RemoveLast();
+ }
+
+ template <typename TRepeated, typename TPred> // suitable both for RepeatedField and RepeatedPtrField
+ static void RemoveRepeatedFieldItemIf(TRepeated* repeated, TPred p) {
+ auto last = std::remove_if(repeated->begin(), repeated->end(), p);
+ if (last != repeated->end()) {
+ size_t countToRemove = repeated->end() - last;
+ while (countToRemove--)
+ repeated->RemoveLast();
+ }
+ }
+
+ namespace NImpl {
+ template <typename TRepeated>
+ static void ShiftLeft(TRepeated* field, int begIndex, int endIndex, size_t shiftSize) {
+ Y_ASSERT(begIndex <= field->size());
+ Y_ASSERT(endIndex <= field->size());
+ size_t shiftIndex = (int)shiftSize < begIndex ? begIndex - shiftSize : 0;
+ for (int i = begIndex; i < endIndex; ++i, ++shiftIndex)
+ field->SwapElements(shiftIndex, i);
+ }
+ }
+
+ // Remove several items at once, could be more efficient compared to calling RemoveRepeatedFieldItem several times
+ template <typename TRepeated>
+ static void RemoveRepeatedFieldItems(TRepeated* field, const TVector<size_t>& sortedIndices) {
+ if (sortedIndices.empty())
+ return;
+
+ size_t shift = 1;
+ for (size_t i = 1; i < sortedIndices.size(); ++i, ++shift)
+ NImpl::ShiftLeft(field, sortedIndices[i - 1] + 1, sortedIndices[i], shift);
+ NImpl::ShiftLeft(field, sortedIndices.back() + 1, field->size(), shift);
+
+ for (; shift > 0; --shift)
+ field->RemoveLast();
+ }
+
+ template <typename TRepeated>
+ static void ReverseRepeatedFieldItems(TRepeated* field) {
+ for (int i1 = 0, i2 = field->size() - 1; i1 < i2; ++i1, --i2)
+ field->SwapElements(i1, i2);
+ }
+
+}
diff --git a/library/cpp/protobuf/util/repeated_field_utils_ut.cpp b/library/cpp/protobuf/util/repeated_field_utils_ut.cpp
new file mode 100644
index 0000000000..58aaaa9e12
--- /dev/null
+++ b/library/cpp/protobuf/util/repeated_field_utils_ut.cpp
@@ -0,0 +1,46 @@
+#include "repeated_field_utils.h"
+#include <library/cpp/protobuf/util/ut/common_ut.pb.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NProtoBuf;
+
+Y_UNIT_TEST_SUITE(RepeatedFieldUtils) {
+ Y_UNIT_TEST(RemoveIf) {
+ {
+ NProtobufUtilUt::TWalkTest msg;
+ msg.AddRepInt(0);
+ msg.AddRepInt(1);
+ msg.AddRepInt(2);
+ msg.AddRepInt(3);
+ msg.AddRepInt(4);
+ msg.AddRepInt(5);
+ auto cond = [](ui32 val) {
+ return val % 2 == 0;
+ };
+ RemoveRepeatedFieldItemIf(msg.MutableRepInt(), cond);
+ UNIT_ASSERT_VALUES_EQUAL(3, msg.RepIntSize());
+ UNIT_ASSERT_VALUES_EQUAL(1, msg.GetRepInt(0));
+ UNIT_ASSERT_VALUES_EQUAL(3, msg.GetRepInt(1));
+ UNIT_ASSERT_VALUES_EQUAL(5, msg.GetRepInt(2));
+ }
+
+ {
+ NProtobufUtilUt::TWalkTest msg;
+ msg.AddRepSub()->SetOptInt(0);
+ msg.AddRepSub()->SetOptInt(1);
+ msg.AddRepSub()->SetOptInt(2);
+ msg.AddRepSub()->SetOptInt(3);
+ msg.AddRepSub()->SetOptInt(4);
+ msg.AddRepSub()->SetOptInt(5);
+ auto cond = [](const NProtobufUtilUt::TWalkTest& val) {
+ return val.GetOptInt() % 2 == 0;
+ };
+ RemoveRepeatedFieldItemIf(msg.MutableRepSub(), cond);
+ UNIT_ASSERT_VALUES_EQUAL(3, msg.RepSubSize());
+ UNIT_ASSERT_VALUES_EQUAL(1, msg.GetRepSub(0).GetOptInt());
+ UNIT_ASSERT_VALUES_EQUAL(3, msg.GetRepSub(1).GetOptInt());
+ UNIT_ASSERT_VALUES_EQUAL(5, msg.GetRepSub(2).GetOptInt());
+ }
+ }
+}
diff --git a/library/cpp/protobuf/util/simple_reflection.cpp b/library/cpp/protobuf/util/simple_reflection.cpp
new file mode 100644
index 0000000000..d842e9ee44
--- /dev/null
+++ b/library/cpp/protobuf/util/simple_reflection.cpp
@@ -0,0 +1,70 @@
+#include "simple_reflection.h"
+
+namespace NProtoBuf {
+ const Message* GetMessageHelper(const TConstField& curField, bool) {
+ return curField.HasValue() && curField.IsMessage() ? curField.Get<Message>() : nullptr;
+ }
+
+ Message* GetMessageHelper(TMutableField& curField, bool createPath) {
+ if (curField.IsMessage()) {
+ if (!curField.HasValue()) {
+ if (createPath)
+ return curField.Field()->is_repeated() ? curField.AddMessage() : curField.MutableMessage();
+ } else {
+ return curField.MutableMessage();
+ }
+ }
+ return nullptr;
+ }
+
+ template <class TField, class TMsg>
+ TMaybe<TField> ByPathImpl(TMsg& msg, const TVector<const FieldDescriptor*>& fieldsPath, bool createPath) {
+ if (fieldsPath.empty())
+ return TMaybe<TField>();
+ TMsg* curParent = &msg;
+ for (size_t i = 0, size = fieldsPath.size(); i < size; ++i) {
+ const FieldDescriptor* field = fieldsPath[i];
+ if (!curParent)
+ return TMaybe<TField>();
+ TField curField(*curParent, field);
+ if (size - i == 1) // last element in path
+ return curField;
+ curParent = GetMessageHelper(curField, createPath);
+ }
+ if (curParent)
+ return TField(*curParent, fieldsPath.back());
+ else
+ return TMaybe<TField>();
+ }
+
+ TMaybe<TConstField> TConstField::ByPath(const Message& msg, const TVector<const FieldDescriptor*>& fieldsPath) {
+ return ByPathImpl<TConstField, const Message>(msg, fieldsPath, false);
+ }
+
+ TMaybe<TConstField> TConstField::ByPath(const Message& msg, const TStringBuf& path) {
+ TFieldPath fieldPath;
+ if (!fieldPath.InitUnsafe(msg.GetDescriptor(), path))
+ return TMaybe<TConstField>();
+ return ByPathImpl<TConstField, const Message>(msg, fieldPath.Fields(), false);
+ }
+
+ TMaybe<TConstField> TConstField::ByPath(const Message& msg, const TFieldPath& path) {
+ return ByPathImpl<TConstField, const Message>(msg, path.Fields(), false);
+ }
+
+ TMaybe<TMutableField> TMutableField::ByPath(Message& msg, const TVector<const FieldDescriptor*>& fieldsPath, bool createPath) {
+ return ByPathImpl<TMutableField, Message>(msg, fieldsPath, createPath);
+ }
+
+ TMaybe<TMutableField> TMutableField::ByPath(Message& msg, const TStringBuf& path, bool createPath) {
+ TFieldPath fieldPath;
+ if (!fieldPath.InitUnsafe(msg.GetDescriptor(), path))
+ return TMaybe<TMutableField>();
+ return ByPathImpl<TMutableField, Message>(msg, fieldPath.Fields(), createPath);
+ }
+
+ TMaybe<TMutableField> TMutableField::ByPath(Message& msg, const TFieldPath& path, bool createPath) {
+ return ByPathImpl<TMutableField, Message>(msg, path.Fields(), createPath);
+ }
+
+}
diff --git a/library/cpp/protobuf/util/simple_reflection.h b/library/cpp/protobuf/util/simple_reflection.h
new file mode 100644
index 0000000000..61e877a787
--- /dev/null
+++ b/library/cpp/protobuf/util/simple_reflection.h
@@ -0,0 +1,289 @@
+#pragma once
+
+#include "cast.h"
+#include "path.h"
+#include "traits.h"
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+
+#include <util/generic/maybe.h>
+#include <util/generic/typetraits.h>
+#include <util/generic/vector.h>
+#include <util/system/defaults.h>
+
+namespace NProtoBuf {
+ class TConstField {
+ public:
+ TConstField(const Message& msg, const FieldDescriptor* fd)
+ : Msg(msg)
+ , Fd(fd)
+ {
+ Y_ASSERT(Fd && Fd->containing_type() == Msg.GetDescriptor());
+ }
+
+ static TMaybe<TConstField> ByPath(const Message& msg, const TStringBuf& path);
+ static TMaybe<TConstField> ByPath(const Message& msg, const TVector<const FieldDescriptor*>& fieldsPath);
+ static TMaybe<TConstField> ByPath(const Message& msg, const TFieldPath& fieldsPath);
+
+ const Message& Parent() const {
+ return Msg;
+ }
+
+ const FieldDescriptor* Field() const {
+ return Fd;
+ }
+
+ bool HasValue() const {
+ return IsRepeated() ? Refl().FieldSize(Msg, Fd) > 0
+ : Refl().HasField(Msg, Fd);
+ }
+
+ // deprecated, use HasValue() instead
+ bool Has() const {
+ return HasValue();
+ }
+
+ size_t Size() const {
+ return IsRepeated() ? Refl().FieldSize(Msg, Fd)
+ : (Refl().HasField(Msg, Fd) ? 1 : 0);
+ }
+
+ template <typename T>
+ inline typename TSelectCppType<T>::T Get(size_t index = 0) const;
+
+ template <typename TMsg>
+ inline const TMsg* GetAs(size_t index = 0) const {
+ // casting version of Get
+ return IsMessageInstance<TMsg>() ? CheckedCast<const TMsg*>(Get<const Message*>(index)) : nullptr;
+ }
+
+ template <typename T>
+ bool IsInstance() const {
+ return CppType() == TSelectCppType<T>::Result;
+ }
+
+ template <typename TMsg>
+ bool IsMessageInstance() const {
+ return IsMessage() && Fd->message_type() == TMsg::descriptor();
+ }
+
+ template <typename TMsg>
+ bool IsInstance(std::enable_if_t<std::is_base_of<Message, TMsg>::value && !std::is_same<Message, TMsg>::value, void>* = NULL) const { // template will be selected when specifying Message children types
+ return IsMessage() && Fd->message_type() == TMsg::descriptor();
+ }
+
+ bool IsString() const {
+ return CppType() == FieldDescriptor::CPPTYPE_STRING;
+ }
+
+ bool IsMessage() const {
+ return CppType() == FieldDescriptor::CPPTYPE_MESSAGE;
+ }
+
+ bool HasSameType(const TConstField& other) const {
+ if (CppType() != other.CppType())
+ return false;
+ if (IsMessage() && Field()->message_type() != other.Field()->message_type())
+ return false;
+ if (CppType() == FieldDescriptor::CPPTYPE_ENUM && Field()->enum_type() != other.Field()->enum_type())
+ return false;
+ return true;
+ }
+
+ protected:
+ bool IsRepeated() const {
+ return Fd->is_repeated();
+ }
+
+ FieldDescriptor::CppType CppType() const {
+ return Fd->cpp_type();
+ }
+
+ const Reflection& Refl() const {
+ return *Msg.GetReflection();
+ }
+
+ [[noreturn]] void RaiseUnknown() const {
+ ythrow yexception() << "Unknown field cpp-type: " << (size_t)CppType();
+ }
+
+ bool IsSameField(const TConstField& other) const {
+ return &Parent() == &other.Parent() && Field() == other.Field();
+ }
+
+ protected:
+ const Message& Msg;
+ const FieldDescriptor* Fd;
+ };
+
+ class TMutableField: public TConstField {
+ public:
+ TMutableField(Message& msg, const FieldDescriptor* fd)
+ : TConstField(msg, fd)
+ {
+ }
+
+ static TMaybe<TMutableField> ByPath(Message& msg, const TStringBuf& path, bool createPath = false);
+ static TMaybe<TMutableField> ByPath(Message& msg, const TVector<const FieldDescriptor*>& fieldsPath, bool createPath = false);
+ static TMaybe<TMutableField> ByPath(Message& msg, const TFieldPath& fieldsPath, bool createPath = false);
+
+ Message* MutableParent() {
+ return Mut();
+ }
+
+ template <typename T>
+ inline void Set(T value, size_t index = 0);
+
+ template <typename T>
+ inline void Add(T value);
+
+ inline void MergeFrom(const TConstField& src);
+
+ inline void Clear() {
+ Refl().ClearField(Mut(), Fd);
+ }
+ /*
+ void Swap(TMutableField& f) {
+ Y_ASSERT(Field() == f.Field());
+
+ // not implemented yet, TODO: implement when Reflection::Mutable(Ptr)RepeatedField
+ // is ported into arcadia protobuf library from up-stream.
+ }
+*/
+ inline void RemoveLast() {
+ Y_ASSERT(HasValue());
+ if (IsRepeated())
+ Refl().RemoveLast(Mut(), Fd);
+ else
+ Clear();
+ }
+
+ inline void SwapElements(size_t index1, size_t index2) {
+ Y_ASSERT(IsRepeated());
+ Y_ASSERT(index1 < Size());
+ Y_ASSERT(index2 < Size());
+ if (index1 == index2)
+ return;
+ Refl().SwapElements(Mut(), Fd, index1, index2);
+ }
+
+ inline void Remove(size_t index) {
+ if (index >= Size())
+ return;
+
+ // Move to the end
+ for (size_t i = index, size = Size(); i < size - 1; ++i)
+ SwapElements(i, i + 1);
+ RemoveLast();
+ }
+
+ Message* MutableMessage(size_t index = 0) {
+ Y_ASSERT(IsMessage());
+ if (IsRepeated()) {
+ Y_ASSERT(index < Size());
+ return Refl().MutableRepeatedMessage(Mut(), Fd, index);
+ } else {
+ Y_ASSERT(index == 0);
+ return Refl().MutableMessage(Mut(), Fd);
+ }
+ }
+
+ template <typename TMsg>
+ inline TMsg* AddMessage() {
+ return CheckedCast<TMsg*>(AddMessage());
+ }
+
+ inline Message* AddMessage() {
+ Y_ASSERT(IsMessage() && IsRepeated());
+ return Refl().AddMessage(Mut(), Fd);
+ }
+
+ private:
+ Message* Mut() {
+ return const_cast<Message*>(&Msg);
+ }
+
+ template <typename T>
+ inline void MergeValue(T srcValue);
+ };
+
+ // template implementations
+
+ template <typename T>
+ inline typename TSelectCppType<T>::T TConstField::Get(size_t index) const {
+ Y_ASSERT(index < Size() || !Fd->is_repeated() && index == 0); // Get for single fields is always allowed because of default values
+#define TMP_MACRO_FOR_CPPTYPE(CPPTYPE) \
+ case CPPTYPE: \
+ return CompatCast<CPPTYPE, TSelectCppType<T>::Result>(TSimpleFieldTraits<CPPTYPE>::Get(Msg, Fd, index));
+ switch (CppType()) {
+ APPLY_TMP_MACRO_FOR_ALL_CPPTYPES()
+ default:
+ RaiseUnknown();
+ }
+#undef TMP_MACRO_FOR_CPPTYPE
+ }
+
+ template <typename T>
+ inline void TMutableField::Set(T value, size_t index) {
+ Y_ASSERT(!IsRepeated() && index == 0 || index < Size());
+#define TMP_MACRO_FOR_CPPTYPE(CPPTYPE) \
+ case CPPTYPE: \
+ TSimpleFieldTraits<CPPTYPE>::Set(*Mut(), Fd, CompatCast<TSelectCppType<T>::Result, CPPTYPE>(value), index); \
+ break;
+ switch (CppType()) {
+ APPLY_TMP_MACRO_FOR_ALL_CPPTYPES()
+ default:
+ RaiseUnknown();
+ }
+#undef TMP_MACRO_FOR_CPPTYPE
+ }
+
+ template <typename T>
+ inline void TMutableField::Add(T value) {
+#define TMP_MACRO_FOR_CPPTYPE(CPPTYPE) \
+ case CPPTYPE: \
+ TSimpleFieldTraits<CPPTYPE>::Add(*Mut(), Fd, CompatCast<TSelectCppType<T>::Result, CPPTYPE>(value)); \
+ break;
+ switch (CppType()) {
+ APPLY_TMP_MACRO_FOR_ALL_CPPTYPES()
+ default:
+ RaiseUnknown();
+ }
+#undef TMP_MACRO_FOR_CPPTYPE
+ }
+
+ template <typename T>
+ inline void TMutableField::MergeValue(T srcValue) {
+ Add(srcValue);
+ }
+
+ template <>
+ inline void TMutableField::MergeValue<const Message*>(const Message* srcValue) {
+ if (IsRepeated()) {
+ Add(srcValue);
+ } else {
+ MutableMessage()->MergeFrom(*srcValue);
+ }
+ }
+
+ inline void TMutableField::MergeFrom(const TConstField& src) {
+ Y_ASSERT(HasSameType(src));
+ if (IsSameField(src))
+ return;
+#define TMP_MACRO_FOR_CPPTYPE(CPPTYPE) \
+ case CPPTYPE: { \
+ for (size_t itemIdx = 0; itemIdx < src.Size(); ++itemIdx) { \
+ MergeValue(TSimpleFieldTraits<CPPTYPE>::Get(src.Parent(), src.Field(), itemIdx)); \
+ } \
+ break; \
+ }
+ switch (CppType()) {
+ APPLY_TMP_MACRO_FOR_ALL_CPPTYPES()
+ default:
+ RaiseUnknown();
+ }
+#undef TMP_MACRO_FOR_CPPTYPE
+ }
+
+}
diff --git a/library/cpp/protobuf/util/simple_reflection_ut.cpp b/library/cpp/protobuf/util/simple_reflection_ut.cpp
new file mode 100644
index 0000000000..169d4703c9
--- /dev/null
+++ b/library/cpp/protobuf/util/simple_reflection_ut.cpp
@@ -0,0 +1,359 @@
+#include "simple_reflection.h"
+#include <library/cpp/protobuf/util/ut/sample_for_simple_reflection.pb.h>
+#include <library/cpp/protobuf/util/ut/extensions.pb.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NProtoBuf;
+
+Y_UNIT_TEST_SUITE(ProtobufSimpleReflection) {
+ static TSample GenSampleForMergeFrom() {
+ TSample smf;
+ smf.SetOneStr("one str");
+ smf.MutableOneMsg()->AddRepInt(1);
+ smf.AddRepMsg()->AddRepInt(2);
+ smf.AddRepMsg()->AddRepInt(3);
+ smf.AddRepStr("one rep str");
+ smf.AddRepStr("two rep str");
+ smf.SetAnotherOneStr("another one str");
+ return smf;
+ }
+
+ Y_UNIT_TEST(MergeFromGeneric) {
+ const TSample src(GenSampleForMergeFrom());
+ TSample dst;
+ const Descriptor* descr = dst.GetDescriptor();
+
+ {
+ TMutableField dstOneStr(dst, descr->FindFieldByName("OneStr"));
+ TConstField srcOneStr(src, descr->FindFieldByName("OneStr"));
+ dstOneStr.MergeFrom(srcOneStr);
+ UNIT_ASSERT_VALUES_EQUAL(dst.GetOneStr(), src.GetOneStr());
+ }
+
+ { // MergeFrom for single message fields acts like a Message::MergeFrom
+ TMutableField dstOneMsg(dst, descr->FindFieldByName("OneMsg"));
+ dstOneMsg.MergeFrom(TConstField(src, descr->FindFieldByName("OneMsg")));
+ UNIT_ASSERT_VALUES_EQUAL(dst.GetOneMsg().RepIntSize(), src.GetOneMsg().RepIntSize());
+ dstOneMsg.MergeFrom(TConstField(src, descr->FindFieldByName("OneMsg")));
+ UNIT_ASSERT_VALUES_EQUAL(dst.GetOneMsg().RepIntSize(), src.GetOneMsg().RepIntSize() * 2);
+ }
+
+ { // MergeFrom for repeated fields acts like append
+ TMutableField dstRepMsg(dst, descr->FindFieldByName("RepMsg"));
+ dstRepMsg.MergeFrom(TConstField(src, descr->FindFieldByName("RepMsg")));
+ UNIT_ASSERT_VALUES_EQUAL(dst.RepMsgSize(), src.RepMsgSize());
+ dstRepMsg.MergeFrom(TConstField(src, descr->FindFieldByName("RepMsg")));
+ UNIT_ASSERT_VALUES_EQUAL(dst.RepMsgSize(), src.RepMsgSize() * 2);
+ for (size_t repMsgIndex = 0; repMsgIndex < dst.RepMsgSize(); ++repMsgIndex) {
+ UNIT_ASSERT_VALUES_EQUAL(dst.GetRepMsg(repMsgIndex).RepIntSize(), src.GetRepMsg(0).RepIntSize());
+ }
+ }
+ }
+
+ Y_UNIT_TEST(MergeFromSelf) {
+ const TSample sample(GenSampleForMergeFrom());
+ TSample msg(sample);
+ const Descriptor* descr = msg.GetDescriptor();
+
+ TMutableField oneStr(msg, descr->FindFieldByName("OneStr"));
+ oneStr.MergeFrom(oneStr);
+ UNIT_ASSERT_VALUES_EQUAL(msg.GetOneStr(), sample.GetOneStr());
+
+ TMutableField oneMsg(msg, descr->FindFieldByName("OneMsg"));
+ oneMsg.MergeFrom(oneMsg); // nothing should change
+ UNIT_ASSERT_VALUES_EQUAL(msg.GetOneMsg().RepIntSize(), sample.GetOneMsg().RepIntSize());
+ }
+
+ Y_UNIT_TEST(MergeFromAnotherFD) {
+ const TSample sample(GenSampleForMergeFrom());
+ TSample msg(GenSampleForMergeFrom());
+ const Descriptor* descr = msg.GetDescriptor();
+
+ { // string
+ TMutableField oneStr(msg, descr->FindFieldByName("OneStr"));
+ TMutableField repStr(msg, descr->FindFieldByName("RepStr"));
+ TMutableField anotherOneStr(msg, descr->FindFieldByName("AnotherOneStr"));
+ oneStr.MergeFrom(anotherOneStr);
+ UNIT_ASSERT_VALUES_EQUAL(msg.GetOneStr(), sample.GetAnotherOneStr());
+ oneStr.MergeFrom(repStr);
+ const size_t sampleRepStrSize = sample.RepStrSize();
+ UNIT_ASSERT_VALUES_EQUAL(msg.GetOneStr(), sample.GetRepStr(sampleRepStrSize - 1));
+ repStr.MergeFrom(anotherOneStr);
+ UNIT_ASSERT_VALUES_EQUAL(msg.RepStrSize(), sampleRepStrSize + 1);
+ UNIT_ASSERT_VALUES_EQUAL(msg.GetRepStr(sampleRepStrSize), msg.GetAnotherOneStr());
+ }
+
+ { // Message
+ TMutableField oneMsg(msg, descr->FindFieldByName("OneMsg"));
+ TMutableField repMsg(msg, descr->FindFieldByName("RepMsg"));
+ oneMsg.MergeFrom(repMsg);
+ const size_t oneMsgRepIntSize = sample.GetOneMsg().RepIntSize();
+ const size_t sizeOfAllRepIntsInRepMsg = sample.RepMsgSize();
+ UNIT_ASSERT_VALUES_EQUAL(msg.GetOneMsg().RepIntSize(), oneMsgRepIntSize + sizeOfAllRepIntsInRepMsg);
+ repMsg.MergeFrom(oneMsg);
+ UNIT_ASSERT_VALUES_EQUAL(msg.RepMsgSize(), sample.RepMsgSize() + 1);
+ }
+ }
+
+ Y_UNIT_TEST(RemoveByIndex) {
+ TSample msg;
+
+ const Descriptor* descr = msg.GetDescriptor();
+ {
+ TMutableField fld(msg, descr->FindFieldByName("RepMsg"));
+ msg.AddRepMsg()->AddRepInt(1);
+ msg.AddRepMsg()->AddRepInt(2);
+ msg.AddRepMsg()->AddRepInt(3);
+
+ UNIT_ASSERT_VALUES_EQUAL(3, msg.RepMsgSize()); // 1, 2, 3
+ fld.Remove(1); // from middle
+ UNIT_ASSERT_VALUES_EQUAL(2, msg.RepMsgSize());
+ UNIT_ASSERT_VALUES_EQUAL(1, msg.GetRepMsg(0).GetRepInt(0));
+ UNIT_ASSERT_VALUES_EQUAL(3, msg.GetRepMsg(1).GetRepInt(0));
+
+ msg.AddRepMsg()->AddRepInt(5);
+ UNIT_ASSERT_VALUES_EQUAL(3, msg.RepMsgSize()); // 1, 3, 5
+ fld.Remove(2); // from end
+ UNIT_ASSERT_VALUES_EQUAL(2, msg.RepMsgSize());
+ UNIT_ASSERT_VALUES_EQUAL(1, msg.GetRepMsg(0).GetRepInt(0));
+ UNIT_ASSERT_VALUES_EQUAL(3, msg.GetRepMsg(1).GetRepInt(0));
+ msg.ClearRepMsg();
+ }
+
+ {
+ TMutableField fld(msg, descr->FindFieldByName("RepStr"));
+ msg.AddRepStr("1");
+ msg.AddRepStr("2");
+ msg.AddRepStr("3");
+ UNIT_ASSERT_VALUES_EQUAL(3, msg.RepStrSize()); // "1", "2", "3"
+ fld.Remove(0); // from begin
+ UNIT_ASSERT_VALUES_EQUAL(2, msg.RepStrSize());
+ UNIT_ASSERT_VALUES_EQUAL("2", msg.GetRepStr(0));
+ UNIT_ASSERT_VALUES_EQUAL("3", msg.GetRepStr(1));
+ }
+
+ {
+ TMutableField fld(msg, descr->FindFieldByName("OneStr"));
+ msg.SetOneStr("1");
+ UNIT_ASSERT(msg.HasOneStr());
+ fld.Remove(0); // not repeated
+ UNIT_ASSERT(!msg.HasOneStr());
+ }
+ }
+
+ Y_UNIT_TEST(GetFieldByPath) {
+ // Simple get by path
+ {
+ TSample msg;
+ msg.SetOneStr("1");
+ msg.MutableOneMsg()->AddRepInt(2);
+ msg.MutableOneMsg()->AddRepInt(3);
+ msg.AddRepMsg()->AddRepInt(4);
+ msg.MutableRepMsg(0)->AddRepInt(5);
+ msg.AddRepMsg()->AddRepInt(6);
+
+ {
+ TMaybe<TConstField> field = TConstField::ByPath(msg, "OneStr");
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(field->HasValue());
+ UNIT_ASSERT_VALUES_EQUAL("1", (field->Get<TString>()));
+ }
+
+ {
+ TMaybe<TConstField> field = TConstField::ByPath(msg, "OneMsg");
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(field->HasValue());
+ UNIT_ASSERT(field->IsMessageInstance<TInnerSample>());
+ }
+
+ {
+ TMaybe<TConstField> field = TConstField::ByPath(msg, "/OneMsg/RepInt");
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(field->HasValue());
+ UNIT_ASSERT_VALUES_EQUAL(2, field->Size());
+ UNIT_ASSERT_VALUES_EQUAL(2, field->Get<int>(0));
+ UNIT_ASSERT_VALUES_EQUAL(3, field->Get<int>(1));
+ }
+
+ {
+ TMaybe<TConstField> field = TConstField::ByPath(msg, "RepMsg/RepInt");
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(field->HasValue());
+ UNIT_ASSERT_VALUES_EQUAL(2, field->Size());
+ UNIT_ASSERT_VALUES_EQUAL(4, field->Get<int>(0));
+ UNIT_ASSERT_VALUES_EQUAL(5, field->Get<int>(1));
+ }
+ }
+
+ // get of unset fields
+ {
+ TSample msg;
+ msg.MutableOneMsg();
+
+ {
+ TMaybe<TConstField> field = TConstField::ByPath(msg, "OneStr");
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(!field->HasValue());
+ }
+
+ {
+ TMaybe<TConstField> field = TConstField::ByPath(msg, "OneMsg/RepInt");
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(!field->HasValue());
+ }
+
+ {
+ TMaybe<TConstField> field = TConstField::ByPath(msg, "RepMsg/RepInt");
+ UNIT_ASSERT(!field);
+ }
+ }
+
+ // mutable
+ {
+ TSample msg;
+ msg.MutableOneMsg();
+
+ {
+ TMaybe<TMutableField> field = TMutableField::ByPath(msg, "OneStr");
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(!field->HasValue());
+ field->Set(TString("zz"));
+ UNIT_ASSERT(field->HasValue());
+ UNIT_ASSERT_VALUES_EQUAL("zz", msg.GetOneStr());
+ }
+
+ {
+ TMaybe<TMutableField> field = TMutableField::ByPath(msg, "OneStr");
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(field->HasValue());
+ field->Set(TString("dd"));
+ UNIT_ASSERT(field->HasValue());
+ UNIT_ASSERT_VALUES_EQUAL("dd", msg.GetOneStr());
+ }
+
+ {
+ TMaybe<TMutableField> field = TMutableField::ByPath(msg, "OneMsg/RepInt");
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(!field->HasValue());
+ field->Add(10);
+ UNIT_ASSERT_VALUES_EQUAL(10, msg.GetOneMsg().GetRepInt(0));
+ }
+
+ {
+ TMaybe<TMutableField> field = TMutableField::ByPath(msg, "RepMsg/RepInt");
+ UNIT_ASSERT(!field);
+ }
+ }
+
+ // mutable with path creation
+ {
+ TSample msg;
+
+ {
+ TMaybe<TMutableField> field = TMutableField::ByPath(msg, "OneStr", true);
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(!field->HasValue());
+ }
+
+ {
+ TMaybe<TMutableField> field = TMutableField::ByPath(msg, "OneMsg/RepInt", true);
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(!field->HasValue());
+ UNIT_ASSERT(msg.HasOneMsg());
+ field->Add(10);
+ UNIT_ASSERT_VALUES_EQUAL(10, msg.GetOneMsg().GetRepInt(0));
+ }
+
+ {
+ TMaybe<TMutableField> field = TMutableField::ByPath(msg, "RepMsg/RepInt", true);
+ TMaybe<TMutableField> fieldCopy = TMutableField::ByPath(msg, "RepMsg/RepInt", true);
+ Y_UNUSED(fieldCopy);
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(!field->HasValue());
+ UNIT_ASSERT_VALUES_EQUAL(1, msg.RepMsgSize());
+ field->Add(12);
+ UNIT_ASSERT_VALUES_EQUAL(12, field->Get<int>());
+ }
+ }
+
+ // error
+ {
+ {TSample msg;
+ UNIT_ASSERT(!TConstField::ByPath(msg, "SomeField"));
+ }
+
+ {
+ TSample msg;
+ UNIT_ASSERT(!TMutableField::ByPath(msg, "SomeField/FieldSome"));
+ }
+
+ {
+ TSample msg;
+ UNIT_ASSERT(!TMutableField::ByPath(msg, "SomeField/FieldSome", true));
+ }
+}
+
+// extension
+{
+ TSample msg;
+ msg.SetExtension(NExt::TTestExt::ExtField, "ext");
+ msg.SetExtension(NExt::ExtField, 2);
+ msg.AddExtension(NExt::Ext2Field, 33);
+ TInnerSample* subMsg = msg.MutableExtension(NExt::SubMsgExt);
+ subMsg->AddRepInt(20);
+ subMsg->SetExtension(NExt::Ext3Field, 54);
+
+ {
+ TMaybe<TConstField> field = TConstField::ByPath(msg, "NExt.TTestExt.ExtField");
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(field->HasValue());
+ UNIT_ASSERT_VALUES_EQUAL("ext", field->Get<TString>());
+ }
+ {
+ TMaybe<TConstField> field = TConstField::ByPath(msg, "NExt.ExtField");
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(field->HasValue());
+ UNIT_ASSERT_VALUES_EQUAL(2, field->Get<int>());
+ }
+ {
+ TMaybe<TConstField> field = TConstField::ByPath(msg, "ExtField"); // ambiguity
+ UNIT_ASSERT(!field);
+ }
+ {
+ TMaybe<TConstField> field = TConstField::ByPath(msg, "NExt.Ext2Field");
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(field->HasValue());
+ UNIT_ASSERT_VALUES_EQUAL(33, field->Get<int>());
+ }
+ {
+ TMaybe<TConstField> field = TConstField::ByPath(msg, "Ext2Field");
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(field->HasValue());
+ UNIT_ASSERT_VALUES_EQUAL(33, field->Get<int>());
+ }
+ {
+ TMaybe<TConstField> field = TConstField::ByPath(msg, "SubMsgExt");
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(field->HasValue());
+ const TInnerSample* subMsg2 = field->GetAs<TInnerSample>();
+ UNIT_ASSERT(subMsg2);
+ UNIT_ASSERT_VALUES_EQUAL(1, subMsg2->RepIntSize());
+ UNIT_ASSERT_VALUES_EQUAL(20, subMsg2->GetRepInt(0));
+ UNIT_ASSERT_VALUES_EQUAL(54, subMsg2->GetExtension(NExt::Ext3Field));
+ }
+ {
+ TMaybe<TConstField> field = TConstField::ByPath(msg, "SubMsgExt/Ext3Field");
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(field->HasValue());
+ UNIT_ASSERT_VALUES_EQUAL(54, field->Get<int>());
+ }
+ {
+ TMaybe<TConstField> field = TConstField::ByPath(msg, "SubMsgExt/RepInt");
+ UNIT_ASSERT(field);
+ UNIT_ASSERT(field->HasValue());
+ UNIT_ASSERT_VALUES_EQUAL(20, field->Get<int>());
+ }
+}
+}
+}
diff --git a/library/cpp/protobuf/util/sort.h b/library/cpp/protobuf/util/sort.h
new file mode 100644
index 0000000000..985ba6f689
--- /dev/null
+++ b/library/cpp/protobuf/util/sort.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <google/protobuf/message.h>
+
+#include <util/generic/vector.h>
+#include <util/generic/algorithm.h>
+
+namespace NProtoBuf {
+ // TComparePtr is something like:
+ // typedef bool (*TComparePtr)(const Message* msg1, const Message* msg2);
+ // typedef bool (*TComparePtr)(const TProto* msg1, const TProto* msg2);
+
+ template <typename TProto, typename TComparePtr>
+ void SortMessages(RepeatedPtrField<TProto>& msgs, TComparePtr cmp) {
+ TVector<TProto*> ptrs;
+ ptrs.reserve(msgs.size());
+ while (msgs.size()) {
+ ptrs.push_back(msgs.ReleaseLast());
+ }
+
+ ::StableSort(ptrs.begin(), ptrs.end(), cmp);
+
+ for (size_t i = 0; i < ptrs.size(); ++i) {
+ msgs.AddAllocated(ptrs[i]);
+ }
+ }
+
+}
diff --git a/library/cpp/protobuf/util/traits.h b/library/cpp/protobuf/util/traits.h
new file mode 100644
index 0000000000..50f036d0ea
--- /dev/null
+++ b/library/cpp/protobuf/util/traits.h
@@ -0,0 +1,320 @@
+#pragma once
+
+#include <util/generic/typetraits.h>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+
+namespace NProtoBuf {
+// this nasty windows.h macro interfers with protobuf::Reflection::GetMessage()
+#if defined(GetMessage)
+#undef GetMessage
+#endif
+
+ struct TCppTypeTraitsBase {
+ static inline bool Has(const Message& msg, const FieldDescriptor* field) { // non-repeated
+ return msg.GetReflection()->HasField(msg, field);
+ }
+ static inline size_t Size(const Message& msg, const FieldDescriptor* field) { // repeated
+ return msg.GetReflection()->FieldSize(msg, field);
+ }
+
+ static inline void Clear(Message& msg, const FieldDescriptor* field) {
+ msg.GetReflection()->ClearField(&msg, field);
+ }
+
+ static inline void RemoveLast(Message& msg, const FieldDescriptor* field) {
+ msg.GetReflection()->RemoveLast(&msg, field);
+ }
+
+ static inline void SwapElements(Message& msg, const FieldDescriptor* field, int index1, int index2) {
+ msg.GetReflection()->SwapElements(&msg, field, index1, index2);
+ }
+ };
+
+ // default value accessor
+ template <FieldDescriptor::CppType cpptype>
+ struct TCppTypeTraitsDefault;
+
+#define DECLARE_CPPTYPE_DEFAULT(cpptype, method) \
+ template <> \
+ struct TCppTypeTraitsDefault<cpptype> { \
+ static auto GetDefault(const FieldDescriptor* fd) \
+ -> decltype(fd->default_value_##method()) { \
+ Y_ASSERT(fd); \
+ return fd->default_value_##method(); \
+ } \
+ };
+
+ DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_INT32, int32);
+ DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_INT64, int64);
+ DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_UINT32, uint32);
+ DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_UINT64, uint64);
+ DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_FLOAT, float);
+ DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_DOUBLE, double);
+ DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_BOOL, bool);
+ DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_ENUM, enum);
+ DECLARE_CPPTYPE_DEFAULT(FieldDescriptor::CppType::CPPTYPE_STRING, string);
+
+#undef DECLARE_CPPTYPE_DEFAULT
+
+ // getters/setters of field with specified CppType
+ template <FieldDescriptor::CppType cpptype>
+ struct TCppTypeTraits : TCppTypeTraitsBase {
+ static const FieldDescriptor::CppType CppType = cpptype;
+
+ struct T {};
+ static T Get(const Message& msg, const FieldDescriptor* field);
+ static T GetRepeated(const Message& msg, const FieldDescriptor* field, int index);
+ static T GetDefault(const FieldDescriptor* field);
+
+ static void Set(Message& msg, const FieldDescriptor* field, T value);
+ static void AddRepeated(Message& msg, const FieldDescriptor* field, T value);
+ static void SetRepeated(Message& msg, const FieldDescriptor* field, int index, T value);
+ };
+
+ // any type T -> CppType
+ template <typename T>
+ struct TSelectCppType {
+ //static const FieldDescriptor::CppType Result = FieldDescriptor::MAX_CPPTYPE;
+ };
+
+#define DECLARE_CPPTYPE_TRAITS(cpptype, type, method) \
+ template <> \
+ struct TCppTypeTraits<cpptype>: public TCppTypeTraitsBase { \
+ typedef type T; \
+ static const FieldDescriptor::CppType CppType = cpptype; \
+ \
+ static inline T Get(const Message& msg, const FieldDescriptor* field) { \
+ return msg.GetReflection()->Get##method(msg, field); \
+ } \
+ static inline T GetRepeated(const Message& msg, const FieldDescriptor* field, int index) { \
+ return msg.GetReflection()->GetRepeated##method(msg, field, index); \
+ } \
+ static inline T GetDefault(const FieldDescriptor* field) { \
+ return TCppTypeTraitsDefault<cpptype>::GetDefault(field); \
+ } \
+ static inline void Set(Message& msg, const FieldDescriptor* field, T value) { \
+ msg.GetReflection()->Set##method(&msg, field, value); \
+ } \
+ static inline void AddRepeated(Message& msg, const FieldDescriptor* field, T value) { \
+ msg.GetReflection()->Add##method(&msg, field, value); \
+ } \
+ static inline void SetRepeated(Message& msg, const FieldDescriptor* field, int index, T value) { \
+ msg.GetReflection()->SetRepeated##method(&msg, field, index, value); \
+ } \
+ }; \
+ template <> \
+ struct TSelectCppType<type> { \
+ static const FieldDescriptor::CppType Result = cpptype; \
+ typedef type T; \
+ };
+
+ DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_INT32, i32, Int32);
+ DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_INT64, i64, Int64);
+ DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_UINT32, ui32, UInt32);
+ DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_UINT64, ui64, UInt64);
+ DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_DOUBLE, double, Double);
+ DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_FLOAT, float, Float);
+ DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_BOOL, bool, Bool);
+ DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_ENUM, const EnumValueDescriptor*, Enum);
+ DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_STRING, TString, String);
+ //DECLARE_CPPTYPE_TRAITS(FieldDescriptor::CPPTYPE_MESSAGE, const Message&, Message);
+
+#undef DECLARE_CPPTYPE_TRAITS
+
+ // specialization for message pointer
+ template <>
+ struct TCppTypeTraits<FieldDescriptor::CPPTYPE_MESSAGE>: public TCppTypeTraitsBase {
+ typedef const Message* T;
+ static const FieldDescriptor::CppType CppType = FieldDescriptor::CPPTYPE_MESSAGE;
+
+ static inline T Get(const Message& msg, const FieldDescriptor* field) {
+ return &(msg.GetReflection()->GetMessage(msg, field));
+ }
+ static inline T GetRepeated(const Message& msg, const FieldDescriptor* field, int index) {
+ return &(msg.GetReflection()->GetRepeatedMessage(msg, field, index));
+ }
+ static inline Message* Set(Message& msg, const FieldDescriptor* field, const Message* value) {
+ Message* ret = msg.GetReflection()->MutableMessage(&msg, field);
+ ret->CopyFrom(*value);
+ return ret;
+ }
+ static inline Message* AddRepeated(Message& msg, const FieldDescriptor* field, const Message* value) {
+ Message* ret = msg.GetReflection()->AddMessage(&msg, field);
+ ret->CopyFrom(*value);
+ return ret;
+ }
+ static inline Message* SetRepeated(Message& msg, const FieldDescriptor* field, int index, const Message* value) {
+ Message* ret = msg.GetReflection()->MutableRepeatedMessage(&msg, field, index);
+ ret->CopyFrom(*value);
+ return ret;
+ }
+ };
+
+ template <>
+ struct TSelectCppType<const Message*> {
+ static const FieldDescriptor::CppType Result = FieldDescriptor::CPPTYPE_MESSAGE;
+ typedef const Message* T;
+ };
+
+ template <>
+ struct TSelectCppType<Message> {
+ static const FieldDescriptor::CppType Result = FieldDescriptor::CPPTYPE_MESSAGE;
+ typedef const Message* T;
+ };
+
+ template <FieldDescriptor::CppType CppType, bool Repeated>
+ struct TFieldTraits {
+ typedef TCppTypeTraits<CppType> TBaseTraits;
+ typedef typename TBaseTraits::T T;
+
+ static inline T Get(const Message& msg, const FieldDescriptor* field, size_t index = 0) {
+ Y_ASSERT(index == 0);
+ return TBaseTraits::Get(msg, field);
+ }
+
+ static inline T GetDefault(const FieldDescriptor* field) {
+ return TBaseTraits::GetDefault(field);
+ }
+
+ static inline bool Has(const Message& msg, const FieldDescriptor* field) {
+ return TBaseTraits::Has(msg, field);
+ }
+
+ static inline size_t Size(const Message& msg, const FieldDescriptor* field) {
+ return Has(msg, field);
+ }
+
+ static inline void Set(Message& msg, const FieldDescriptor* field, T value, size_t index = 0) {
+ Y_ASSERT(index == 0);
+ TBaseTraits::Set(msg, field, value);
+ }
+
+ static inline void Add(Message& msg, const FieldDescriptor* field, T value) {
+ TBaseTraits::Set(msg, field, value);
+ }
+ };
+
+ template <FieldDescriptor::CppType CppType>
+ struct TFieldTraits<CppType, true> {
+ typedef TCppTypeTraits<CppType> TBaseTraits;
+ typedef typename TBaseTraits::T T;
+
+ static inline T Get(const Message& msg, const FieldDescriptor* field, size_t index = 0) {
+ return TBaseTraits::GetRepeated(msg, field, index);
+ }
+
+ static inline T GetDefault(const FieldDescriptor* field) {
+ return TBaseTraits::GetDefault(field);
+ }
+
+ static inline size_t Size(const Message& msg, const FieldDescriptor* field) {
+ return TBaseTraits::Size(msg, field);
+ }
+
+ static inline bool Has(const Message& msg, const FieldDescriptor* field) {
+ return Size(msg, field) > 0;
+ }
+
+ static inline void Set(Message& msg, const FieldDescriptor* field, T value, size_t index = 0) {
+ TBaseTraits::SetRepeated(msg, field, index, value);
+ }
+
+ static inline void Add(Message& msg, const FieldDescriptor* field, T value) {
+ TBaseTraits::AddRepeated(msg, field, value);
+ }
+ };
+
+ // Simpler interface at the cost of checking is_repeated() on each call
+ template <FieldDescriptor::CppType CppType>
+ struct TSimpleFieldTraits {
+ typedef TFieldTraits<CppType, true> TRepeated;
+ typedef TFieldTraits<CppType, false> TSingle;
+ typedef typename TRepeated::T T;
+
+ static inline size_t Size(const Message& msg, const FieldDescriptor* field) {
+ if (field->is_repeated())
+ return TRepeated::Size(msg, field);
+ else
+ return TSingle::Size(msg, field);
+ }
+
+ static inline bool Has(const Message& msg, const FieldDescriptor* field) {
+ if (field->is_repeated())
+ return TRepeated::Has(msg, field);
+ else
+ return TSingle::Has(msg, field);
+ }
+
+ static inline T Get(const Message& msg, const FieldDescriptor* field, size_t index = 0) {
+ Y_ASSERT(index < Size(msg, field) || !field->is_repeated() && index == 0); // Get for single fields is always allowed because of default values
+ if (field->is_repeated())
+ return TRepeated::Get(msg, field, index);
+ else
+ return TSingle::Get(msg, field, index);
+ }
+
+ static inline T GetDefault(const FieldDescriptor* field) {
+ return TSingle::GetDefault(field);
+ }
+
+ static inline void Set(Message& msg, const FieldDescriptor* field, T value, size_t index = 0) {
+ Y_ASSERT(!field->is_repeated() && index == 0 || index < Size(msg, field));
+ if (field->is_repeated())
+ TRepeated::Set(msg, field, value, index);
+ else
+ TSingle::Set(msg, field, value, index);
+ }
+
+ static inline void Add(Message& msg, const FieldDescriptor* field, T value) {
+ if (field->is_repeated())
+ TRepeated::Add(msg, field, value);
+ else
+ TSingle::Add(msg, field, value);
+ }
+ };
+
+ // some cpp-type groups
+
+ template <FieldDescriptor::CppType CppType>
+ struct TIsIntegerCppType {
+ enum {
+ Result = CppType == FieldDescriptor::CPPTYPE_INT32 ||
+ CppType == FieldDescriptor::CPPTYPE_INT64 ||
+ CppType == FieldDescriptor::CPPTYPE_UINT32 ||
+ CppType == FieldDescriptor::CPPTYPE_UINT64
+ };
+ };
+
+ template <FieldDescriptor::CppType CppType>
+ struct TIsFloatCppType {
+ enum {
+ Result = CppType == FieldDescriptor::CPPTYPE_FLOAT ||
+ CppType == FieldDescriptor::CPPTYPE_DOUBLE
+ };
+ };
+
+ template <FieldDescriptor::CppType CppType>
+ struct TIsNumericCppType {
+ enum {
+ Result = CppType == FieldDescriptor::CPPTYPE_BOOL ||
+ TIsIntegerCppType<CppType>::Result ||
+ TIsFloatCppType<CppType>::Result
+ };
+ };
+
+ // a helper macro for splitting flow by cpp-type (e.g. in a switch)
+
+#define APPLY_TMP_MACRO_FOR_ALL_CPPTYPES() \
+ TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_INT32) \
+ TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_INT64) \
+ TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_UINT32) \
+ TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_UINT64) \
+ TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_DOUBLE) \
+ TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_FLOAT) \
+ TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_BOOL) \
+ TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_ENUM) \
+ TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_STRING) \
+ TMP_MACRO_FOR_CPPTYPE(NProtoBuf::FieldDescriptor::CPPTYPE_MESSAGE)
+}
diff --git a/library/cpp/protobuf/util/ut/common_ut.proto b/library/cpp/protobuf/util/ut/common_ut.proto
new file mode 100644
index 0000000000..9cf803ffbf
--- /dev/null
+++ b/library/cpp/protobuf/util/ut/common_ut.proto
@@ -0,0 +1,72 @@
+import "google/protobuf/descriptor.proto";
+import "library/cpp/protobuf/util/proto/merge.proto";
+
+package NProtobufUtilUt;
+
+extend google.protobuf.FieldOptions {
+ optional bool XXX = 53772;
+}
+
+message TWalkTest {
+ optional uint32 OptInt = 1 [(XXX)=true];
+ repeated uint32 RepInt = 2;
+
+ optional string OptStr = 3;
+ repeated string RepStr = 4 [(XXX)=true];
+
+ optional TWalkTest OptSub = 5 [(XXX)=true];
+ repeated TWalkTest RepSub = 6;
+}
+
+message TWalkTestCyclic {
+ optional TNested OptNested = 1;
+ repeated uint64 OptInt64 = 2;
+ optional TWalkTestCyclic OptSub = 3;
+ optional TEnum OptEnum = 4;
+
+ message TNested {
+ optional uint32 OptInt32 = 1;
+ optional TWalkTestCyclic OptSubNested = 2;
+ repeated string RepStr = 3;
+ optional TNested OptNested = 4;
+ }
+ enum TEnum {
+ A = 0;
+ B = 1;
+ C = 2;
+ }
+}
+
+message TMergeTestNoMerge {
+ option (DontMerge) = true;
+
+ optional uint32 A = 1;
+ repeated uint32 B = 2;
+}
+
+message TMergeTestMerge {
+ optional uint32 A = 1;
+ repeated uint32 B = 2;
+ repeated uint32 C = 3 [(DontMergeField)=true];
+}
+
+message TMergeTest {
+ repeated uint32 MergeInt = 1;
+ repeated uint32 NoMergeInt = 2 [(DontMergeField)=true];
+
+ optional TMergeTestMerge MergeSub = 3;
+ repeated TMergeTestMerge NoMergeRepSub = 4 [(DontMergeField)=true];
+ optional TMergeTestNoMerge NoMergeOptSub = 5;
+}
+
+message TTextTest {
+ optional uint32 Foo = 1;
+}
+
+message TTextEnumTest {
+ enum EnumTest {
+ EET_SLOT_1 = 1;
+ EET_SLOT_2 = 2;
+ }
+ optional EnumTest Slot = 1;
+}
diff --git a/library/cpp/protobuf/util/ut/extensions.proto b/library/cpp/protobuf/util/ut/extensions.proto
new file mode 100644
index 0000000000..4944f0f5ca
--- /dev/null
+++ b/library/cpp/protobuf/util/ut/extensions.proto
@@ -0,0 +1,22 @@
+package NExt;
+
+import "library/cpp/protobuf/util/ut/sample_for_simple_reflection.proto";
+
+message TTestExt {
+ extend TSample {
+ optional string ExtField = 100;
+ }
+}
+
+extend TSample {
+ optional uint64 ExtField = 150; // the same name, but another full name
+}
+
+extend TSample {
+ repeated uint64 Ext2Field = 105;
+ optional TInnerSample SubMsgExt = 111;
+}
+
+extend TInnerSample {
+ optional uint64 Ext3Field = 100;
+}
diff --git a/library/cpp/protobuf/util/ut/sample_for_is_equal.proto b/library/cpp/protobuf/util/ut/sample_for_is_equal.proto
new file mode 100644
index 0000000000..a91c16deaa
--- /dev/null
+++ b/library/cpp/protobuf/util/ut/sample_for_is_equal.proto
@@ -0,0 +1,8 @@
+message TInner {
+ optional string Brbrbr = 3;
+}
+
+message TSampleForIsEqual {
+ optional string Name = 1;
+ optional TInner Inner = 5;
+}
diff --git a/library/cpp/protobuf/util/ut/sample_for_simple_reflection.proto b/library/cpp/protobuf/util/ut/sample_for_simple_reflection.proto
new file mode 100644
index 0000000000..cca1dd869a
--- /dev/null
+++ b/library/cpp/protobuf/util/ut/sample_for_simple_reflection.proto
@@ -0,0 +1,25 @@
+message TInnerSample {
+ repeated int32 RepInt = 1;
+
+ extensions 100 to 199;
+}
+
+message TSample {
+ optional string OneStr = 1;
+ optional TInnerSample OneMsg = 2;
+ repeated TInnerSample RepMsg = 3;
+ repeated string RepStr = 4;
+ optional string AnotherOneStr = 5;
+
+ optional int32 OneInt = 6;
+ repeated int32 RepInt = 7;
+
+ enum EEnum {
+ V1 = 1;
+ V2 = 2;
+ }
+ optional EEnum OneEnum = 8;
+ repeated EEnum RepEnum = 9;
+
+ extensions 100 to 199;
+}
diff --git a/library/cpp/protobuf/util/ut/ya.make b/library/cpp/protobuf/util/ut/ya.make
new file mode 100644
index 0000000000..701ba9a8c8
--- /dev/null
+++ b/library/cpp/protobuf/util/ut/ya.make
@@ -0,0 +1,19 @@
+OWNER(nga)
+
+UNITTEST_FOR(library/cpp/protobuf/util)
+
+SRCS(
+ extensions.proto
+ sample_for_is_equal.proto
+ sample_for_simple_reflection.proto
+ common_ut.proto
+ pb_io_ut.cpp
+ is_equal_ut.cpp
+ iterators_ut.cpp
+ simple_reflection_ut.cpp
+ repeated_field_utils_ut.cpp
+ walk_ut.cpp
+ merge_ut.cpp
+)
+
+END()
diff --git a/library/cpp/protobuf/util/walk.cpp b/library/cpp/protobuf/util/walk.cpp
new file mode 100644
index 0000000000..b65ec03e04
--- /dev/null
+++ b/library/cpp/protobuf/util/walk.cpp
@@ -0,0 +1,72 @@
+#include "walk.h"
+
+#include <util/generic/hash_set.h>
+
+namespace {
+ using namespace NProtoBuf;
+
+ template <typename TMessage, typename TOnField>
+ void DoWalkReflection(TMessage& msg, TOnField& onField) {
+ const Descriptor* descr = msg.GetDescriptor();
+ for (int i1 = 0; i1 < descr->field_count(); ++i1) {
+ const FieldDescriptor* fd = descr->field(i1);
+ if (!onField(msg, fd)) {
+ continue;
+ }
+
+ std::conditional_t<std::is_const_v<TMessage>, TConstField, TMutableField> ff(msg, fd);
+ if (ff.IsMessage()) {
+ for (size_t i2 = 0; i2 < ff.Size(); ++i2) {
+ if constexpr (std::is_const_v<TMessage>) {
+ WalkReflection(*ff.template Get<Message>(i2), onField);
+ } else {
+ WalkReflection(*ff.MutableMessage(i2), onField);
+ }
+ }
+ }
+ }
+ }
+
+ void DoWalkSchema(const Descriptor* descriptor,
+ std::function<bool(const FieldDescriptor*)>& onField,
+ THashSet<const Descriptor*>& visited)
+ {
+ if (!visited.emplace(descriptor).second) {
+ return;
+ }
+ for (int i1 = 0; i1 < descriptor->field_count(); ++i1) {
+ const FieldDescriptor* fd = descriptor->field(i1);
+ if (!onField(fd)) {
+ continue;
+ }
+
+ if (fd->type() == FieldDescriptor::Type::TYPE_MESSAGE) {
+ DoWalkSchema(fd->message_type(), onField, visited);
+ }
+ }
+ visited.erase(descriptor);
+ }
+
+}
+
+namespace NProtoBuf {
+ void WalkReflection(Message& msg,
+ std::function<bool(Message&, const FieldDescriptor*)> onField)
+ {
+ DoWalkReflection(msg, onField);
+ }
+
+ void WalkReflection(const Message& msg,
+ std::function<bool(const Message&, const FieldDescriptor*)> onField)
+ {
+ DoWalkReflection(msg, onField);
+ }
+
+ void WalkSchema(const Descriptor* descriptor,
+ std::function<bool(const FieldDescriptor*)> onField)
+ {
+ THashSet<const Descriptor*> visited;
+ DoWalkSchema(descriptor, onField, visited);
+ }
+
+} // namespace NProtoBuf
diff --git a/library/cpp/protobuf/util/walk.h b/library/cpp/protobuf/util/walk.h
new file mode 100644
index 0000000000..d15d76562d
--- /dev/null
+++ b/library/cpp/protobuf/util/walk.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "simple_reflection.h"
+
+#include <google/protobuf/message.h>
+#include <google/protobuf/descriptor.h>
+
+#include <functional>
+
+namespace NProtoBuf {
+ // Apply @onField processor to each field in @msg (even empty)
+ // Do not walk deeper the field if the field is an empty message
+ // Returned bool defines if we should walk down deeper to current node children (true), or not (false)
+ void WalkReflection(Message& msg,
+ std::function<bool(Message&, const FieldDescriptor*)> onField);
+ void WalkReflection(const Message& msg,
+ std::function<bool(const Message&, const FieldDescriptor*)> onField);
+
+ template <typename TOnField>
+ inline void WalkReflection(Message& msg, TOnField& onField) { // is used when TOnField is a callable class instance
+ WalkReflection(msg, std::function<bool(Message&, const FieldDescriptor*)>(std::ref(onField)));
+ }
+ template <typename TOnField>
+ inline void WalkReflection(const Message& msg, TOnField& onField) {
+ WalkReflection(msg, std::function<bool(const Message&, const FieldDescriptor*)>(std::ref(onField)));
+ }
+
+ // Apply @onField processor to each descriptor of a field
+ // Walk every field including nested messages. Avoid cyclic fields pointing to themselves
+ // Returned bool defines if we should walk down deeper to current node children (true), or not (false)
+ void WalkSchema(const Descriptor* descriptor,
+ std::function<bool(const FieldDescriptor*)> onField);
+}
diff --git a/library/cpp/protobuf/util/walk_ut.cpp b/library/cpp/protobuf/util/walk_ut.cpp
new file mode 100644
index 0000000000..2ea6071b17
--- /dev/null
+++ b/library/cpp/protobuf/util/walk_ut.cpp
@@ -0,0 +1,158 @@
+#include "walk.h"
+#include "simple_reflection.h"
+#include <library/cpp/protobuf/util/ut/common_ut.pb.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NProtoBuf;
+
+Y_UNIT_TEST_SUITE(ProtobufWalk) {
+ static void InitProto(NProtobufUtilUt::TWalkTest & p, int level = 0) {
+ p.SetOptInt(1);
+ p.AddRepInt(2);
+ p.AddRepInt(3);
+
+ p.SetOptStr("123");
+ p.AddRepStr("*");
+ p.AddRepStr("abcdef");
+ p.AddRepStr("1234");
+
+ if (level == 0) {
+ InitProto(*p.MutableOptSub(), 1);
+ InitProto(*p.AddRepSub(), 1);
+ InitProto(*p.AddRepSub(), 1);
+ }
+ }
+
+ static bool IncreaseInts(Message & msg, const FieldDescriptor* fd) {
+ TMutableField f(msg, fd);
+ if (f.IsInstance<ui32>()) {
+ for (size_t i = 0; i < f.Size(); ++i)
+ f.Set(f.Get<ui64>(i) + 1, i); // ui64 should be ok!
+ }
+ return true;
+ }
+
+ static bool RepeatString1(Message & msg, const FieldDescriptor* fd) {
+ TMutableField f(msg, fd);
+ if (f.IsString()) {
+ for (size_t i = 0; i < f.Size(); ++i)
+ if (f.Get<TString>(i).StartsWith('1'))
+ f.Set(f.Get<TString>(i) + f.Get<TString>(i), i);
+ }
+ return true;
+ }
+
+ static bool ClearXXX(Message & msg, const FieldDescriptor* fd) {
+ const FieldOptions& opt = fd->options();
+ if (opt.HasExtension(NProtobufUtilUt::XXX) && opt.GetExtension(NProtobufUtilUt::XXX))
+ TMutableField(msg, fd).Clear();
+
+ return true;
+ }
+
+ struct TestStruct {
+ bool Ok = false;
+
+ TestStruct() = default;
+ bool operator()(Message&, const FieldDescriptor*) {
+ Ok = true;
+ return false;
+ }
+ };
+
+ Y_UNIT_TEST(TestWalkRefl) {
+ NProtobufUtilUt::TWalkTest p;
+ InitProto(p);
+
+ {
+ UNIT_ASSERT_EQUAL(p.GetOptInt(), 1);
+ UNIT_ASSERT_EQUAL(p.RepIntSize(), 2);
+ UNIT_ASSERT_EQUAL(p.GetRepInt(0), 2);
+ UNIT_ASSERT_EQUAL(p.GetRepInt(1), 3);
+
+ WalkReflection(p, IncreaseInts);
+
+ UNIT_ASSERT_EQUAL(p.GetOptInt(), 2);
+ UNIT_ASSERT_EQUAL(p.RepIntSize(), 2);
+ UNIT_ASSERT_EQUAL(p.GetRepInt(0), 3);
+ UNIT_ASSERT_EQUAL(p.GetRepInt(1), 4);
+
+ UNIT_ASSERT_EQUAL(p.GetOptSub().GetOptInt(), 2);
+ UNIT_ASSERT_EQUAL(p.GetOptSub().RepIntSize(), 2);
+ UNIT_ASSERT_EQUAL(p.GetOptSub().GetRepInt(0), 3);
+ UNIT_ASSERT_EQUAL(p.GetOptSub().GetRepInt(1), 4);
+
+ UNIT_ASSERT_EQUAL(p.RepSubSize(), 2);
+ UNIT_ASSERT_EQUAL(p.GetRepSub(1).GetOptInt(), 2);
+ UNIT_ASSERT_EQUAL(p.GetRepSub(1).RepIntSize(), 2);
+ UNIT_ASSERT_EQUAL(p.GetRepSub(1).GetRepInt(0), 3);
+ UNIT_ASSERT_EQUAL(p.GetRepSub(1).GetRepInt(1), 4);
+ }
+ {
+ UNIT_ASSERT_EQUAL(p.GetOptStr(), "123");
+ UNIT_ASSERT_EQUAL(p.GetRepStr(2), "1234");
+
+ WalkReflection(p, RepeatString1);
+
+ UNIT_ASSERT_EQUAL(p.GetOptStr(), "123123");
+ UNIT_ASSERT_EQUAL(p.RepStrSize(), 3);
+ UNIT_ASSERT_EQUAL(p.GetRepStr(0), "*");
+ UNIT_ASSERT_EQUAL(p.GetRepStr(1), "abcdef");
+ UNIT_ASSERT_EQUAL(p.GetRepStr(2), "12341234");
+
+ UNIT_ASSERT_EQUAL(p.RepSubSize(), 2);
+ UNIT_ASSERT_EQUAL(p.GetRepSub(0).GetOptStr(), "123123");
+ UNIT_ASSERT_EQUAL(p.GetRepSub(0).RepStrSize(), 3);
+ UNIT_ASSERT_EQUAL(p.GetRepSub(0).GetRepStr(0), "*");
+ UNIT_ASSERT_EQUAL(p.GetRepSub(0).GetRepStr(1), "abcdef");
+ UNIT_ASSERT_EQUAL(p.GetRepSub(0).GetRepStr(2), "12341234");
+ }
+ {
+ UNIT_ASSERT(p.HasOptInt());
+ UNIT_ASSERT(p.RepStrSize() == 3);
+ UNIT_ASSERT(p.HasOptSub());
+
+ WalkReflection(p, ClearXXX);
+
+ UNIT_ASSERT(!p.HasOptInt());
+ UNIT_ASSERT(p.RepIntSize() == 2);
+ UNIT_ASSERT(p.HasOptStr());
+ UNIT_ASSERT(p.RepStrSize() == 0);
+ UNIT_ASSERT(!p.HasOptSub());
+ UNIT_ASSERT(p.RepSubSize() == 2);
+ }
+ }
+
+ Y_UNIT_TEST(TestMutableCallable) {
+ TestStruct testStruct;
+ NProtobufUtilUt::TWalkTest p;
+ InitProto(p);
+
+ WalkReflection(p, testStruct);
+ UNIT_ASSERT(testStruct.Ok);
+ }
+
+ Y_UNIT_TEST(TestWalkDescr) {
+ NProtobufUtilUt::TWalkTestCyclic p;
+
+ TStringBuilder printedSchema;
+ auto func = [&](const FieldDescriptor* desc) mutable {
+ printedSchema << desc->DebugString();
+ return true;
+ };
+ WalkSchema(p.GetDescriptor(), func);
+
+ TString schema =
+ "optional .NProtobufUtilUt.TWalkTestCyclic.TNested OptNested = 1;\n"
+ "optional uint32 OptInt32 = 1;\n"
+ "optional .NProtobufUtilUt.TWalkTestCyclic OptSubNested = 2;\n"
+ "repeated string RepStr = 3;\n"
+ "optional .NProtobufUtilUt.TWalkTestCyclic.TNested OptNested = 4;\n"
+ "repeated uint64 OptInt64 = 2;\n"
+ "optional .NProtobufUtilUt.TWalkTestCyclic OptSub = 3;\n"
+ "optional .NProtobufUtilUt.TWalkTestCyclic.TEnum OptEnum = 4;\n";
+
+ UNIT_ASSERT_STRINGS_EQUAL(printedSchema, schema);
+ }
+}
diff --git a/library/cpp/protobuf/util/ya.make b/library/cpp/protobuf/util/ya.make
new file mode 100644
index 0000000000..b62028af58
--- /dev/null
+++ b/library/cpp/protobuf/util/ya.make
@@ -0,0 +1,26 @@
+LIBRARY()
+
+OWNER(mowgli)
+
+PEERDIR(
+ contrib/libs/protobuf
+ library/cpp/binsaver
+ library/cpp/protobuf/util/proto
+ library/cpp/string_utils/base64
+)
+
+SRCS(
+ is_equal.cpp
+ iterators.h
+ merge.cpp
+ path.cpp
+ pb_io.cpp
+ pb_utils.h
+ repeated_field_utils.h
+ simple_reflection.cpp
+ walk.cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/protobuf/ya.make b/library/cpp/protobuf/ya.make
new file mode 100644
index 0000000000..618b542b4f
--- /dev/null
+++ b/library/cpp/protobuf/ya.make
@@ -0,0 +1,19 @@
+RECURSE(
+ dynamic_prototype
+ from_xml
+ from_xml/ut
+ interop
+ interop/ut
+ json
+ json/ut
+ parser
+ parser/ut
+ protofile
+ protofile/ut
+ util
+ util/proto
+ yql
+ yql/ut
+ yandex_patches_ut
+ yt
+)
diff --git a/library/cpp/random_provider/random_provider.cpp b/library/cpp/random_provider/random_provider.cpp
new file mode 100644
index 0000000000..64cb48b8b7
--- /dev/null
+++ b/library/cpp/random_provider/random_provider.cpp
@@ -0,0 +1,75 @@
+#include "random_provider.h"
+#include <util/random/mersenne.h>
+#include <util/random/random.h>
+#include <util/system/unaligned_mem.h>
+
+namespace {
+ void SetV4(TGUID& g) {
+ g.dw[1] &= 0x0fffffff;
+ g.dw[1] |= 0x40000000;
+
+ g.dw[2] &= 0xffffff3f;
+ g.dw[2] |= 0x00000080;
+ }
+}
+
+class TDefaultRandomProvider: public IRandomProvider {
+public:
+ ui64 GenRand() noexcept override {
+ return RandomNumber<ui64>();
+ }
+
+ TGUID GenGuid() noexcept override {
+ TGUID ret;
+ CreateGuid(&ret);
+ return ret;
+ }
+
+ TGUID GenUuid4() noexcept override {
+ TGUID ret;
+ WriteUnaligned<ui64>(ret.dw, RandomNumber<ui64>());
+ WriteUnaligned<ui64>(ret.dw + 2, RandomNumber<ui64>());
+ SetV4(ret);
+ return ret;
+ }
+};
+
+class TDeterministicRandomProvider: public IRandomProvider {
+public:
+ TDeterministicRandomProvider(ui64 seed)
+ : Gen(seed)
+ {
+ }
+
+ ui64 GenRand() noexcept override {
+ return Gen.GenRand();
+ }
+
+ TGUID GenGuid() noexcept override {
+ TGUID ret;
+ WriteUnaligned<ui64>(ret.dw, Gen.GenRand());
+ ret.dw[2] = (ui32)Gen.GenRand();
+ ret.dw[3] = ++GuidCount;
+ return ret;
+ }
+
+ TGUID GenUuid4() noexcept override {
+ TGUID ret;
+ WriteUnaligned<ui64>(ret.dw, Gen.GenRand());
+ WriteUnaligned<ui64>(ret.dw + 2, Gen.GenRand());
+ SetV4(ret);
+ return ret;
+ }
+
+private:
+ TMersenne<ui64> Gen;
+ ui32 GuidCount = 0;
+};
+
+TIntrusivePtr<IRandomProvider> CreateDefaultRandomProvider() {
+ return TIntrusivePtr<IRandomProvider>(new TDefaultRandomProvider());
+}
+
+TIntrusivePtr<IRandomProvider> CreateDeterministicRandomProvider(ui64 seed) {
+ return TIntrusivePtr<IRandomProvider>(new TDeterministicRandomProvider(seed));
+}
diff --git a/library/cpp/random_provider/random_provider.h b/library/cpp/random_provider/random_provider.h
new file mode 100644
index 0000000000..6e7226866f
--- /dev/null
+++ b/library/cpp/random_provider/random_provider.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <util/generic/guid.h>
+#include <util/random/common_ops.h>
+
+class IRandomProvider: public TThrRefBase, public TCommonRNG<ui64, IRandomProvider> {
+public:
+ virtual TGUID GenGuid() noexcept = 0;
+ virtual TGUID GenUuid4() noexcept = 0;
+ virtual ui64 GenRand() noexcept = 0; // for TCommonRNG
+};
+
+TIntrusivePtr<IRandomProvider> CreateDefaultRandomProvider();
+TIntrusivePtr<IRandomProvider> CreateDeterministicRandomProvider(ui64 seed);
diff --git a/library/cpp/random_provider/ya.make b/library/cpp/random_provider/ya.make
new file mode 100644
index 0000000000..38d1f070e8
--- /dev/null
+++ b/library/cpp/random_provider/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(
+ g:kikimr
+ g:yql
+)
+
+SRCS(
+ random_provider.cpp
+ random_provider.h
+)
+
+END()
diff --git a/library/cpp/regex/hyperscan/hyperscan.cpp b/library/cpp/regex/hyperscan/hyperscan.cpp
new file mode 100644
index 0000000000..ba321f9c29
--- /dev/null
+++ b/library/cpp/regex/hyperscan/hyperscan.cpp
@@ -0,0 +1,282 @@
+#include "hyperscan.h"
+
+#include <contrib/libs/hyperscan/runtime_core2/hs_common.h>
+#include <contrib/libs/hyperscan/runtime_core2/hs_runtime.h>
+#include <contrib/libs/hyperscan/runtime_corei7/hs_common.h>
+#include <contrib/libs/hyperscan/runtime_corei7/hs_runtime.h>
+#include <contrib/libs/hyperscan/runtime_avx2/hs_common.h>
+#include <contrib/libs/hyperscan/runtime_avx2/hs_runtime.h>
+#include <contrib/libs/hyperscan/runtime_avx512/hs_common.h>
+#include <contrib/libs/hyperscan/runtime_avx512/hs_runtime.h>
+
+#include <util/generic/singleton.h>
+
+namespace NHyperscan {
+ using TSerializedDatabase = THolder<char, TDeleter<decltype(&free), &free>>;
+
+ using TCompileError = THolder<hs_compile_error_t, TDeleter<decltype(&hs_free_compile_error), &hs_free_compile_error>>;
+
+ namespace NPrivate {
+ ERuntime DetectCurrentRuntime() {
+ if (NX86::HaveAVX512F() && NX86::HaveAVX512BW()) {
+ return ERuntime::AVX512;
+ } else if (NX86::HaveAVX() && NX86::HaveAVX2()) {
+ return ERuntime::AVX2;
+ } else if (NX86::HaveSSE42() && NX86::HavePOPCNT()) {
+ return ERuntime::Corei7;
+ } else {
+ return ERuntime::Core2;
+ }
+ }
+
+ TCPUFeatures RuntimeCpuFeatures(ERuntime runtime) {
+ switch (runtime) {
+ default:
+ Y_ASSERT(false);
+ [[fallthrough]];
+ case ERuntime::Core2:
+ case ERuntime::Corei7:
+ return 0;
+ case ERuntime::AVX2:
+ return CPU_FEATURES_AVX2;
+ case ERuntime::AVX512:
+ return CPU_FEATURES_AVX512;
+ }
+ }
+
+ hs_platform_info_t MakePlatformInfo(TCPUFeatures cpuFeatures) {
+ hs_platform_info_t platformInfo{HS_TUNE_FAMILY_GENERIC, cpuFeatures, 0, 0};
+ return platformInfo;
+ }
+
+ hs_platform_info_t MakeCurrentPlatformInfo() {
+ return MakePlatformInfo(RuntimeCpuFeatures(DetectCurrentRuntime()));
+ }
+
+ TImpl::TImpl(ERuntime runtime) {
+ switch (runtime) {
+ default:
+ Y_ASSERT(false);
+ [[fallthrough]];
+ case ERuntime::Core2:
+ AllocScratch = core2_hs_alloc_scratch;
+ Scan = core2_hs_scan;
+ SerializeDatabase = core2_hs_serialize_database;
+ DeserializeDatabase = core2_hs_deserialize_database;
+ break;
+ case ERuntime::Corei7:
+ AllocScratch = corei7_hs_alloc_scratch;
+ Scan = corei7_hs_scan;
+ SerializeDatabase = corei7_hs_serialize_database;
+ DeserializeDatabase = corei7_hs_deserialize_database;
+ break;
+ case ERuntime::AVX2:
+ AllocScratch = avx2_hs_alloc_scratch;
+ Scan = avx2_hs_scan;
+ SerializeDatabase = avx2_hs_serialize_database;
+ DeserializeDatabase = avx2_hs_deserialize_database;
+ break;
+ case ERuntime::AVX512:
+ AllocScratch = avx512_hs_alloc_scratch;
+ Scan = avx512_hs_scan;
+ SerializeDatabase = avx512_hs_serialize_database;
+ DeserializeDatabase = avx512_hs_deserialize_database;
+ }
+ }
+
+ TDatabase Compile(const TStringBuf& regex, unsigned int flags, hs_platform_info_t* platform) {
+ hs_database_t* rawDb = nullptr;
+ hs_compile_error_t* rawCompileErr = nullptr;
+ hs_error_t status = hs_compile(
+ regex.begin(),
+ flags,
+ HS_MODE_BLOCK,
+ platform,
+ &rawDb,
+ &rawCompileErr);
+ TDatabase db(rawDb);
+ NHyperscan::TCompileError compileError(rawCompileErr);
+ if (status != HS_SUCCESS) {
+ ythrow TCompileException()
+ << "Failed to compile regex: " << regex << ". "
+ << "Error message (hyperscan): " << compileError->message;
+ }
+ return db;
+ }
+
+ TDatabase CompileMulti(
+ const TVector<const char*>& regexs,
+ const TVector<unsigned int>& flags,
+ const TVector<unsigned int>& ids,
+ hs_platform_info_t* platform,
+ const TVector<const hs_expr_ext_t*>* extendedParameters) {
+ unsigned int count = regexs.size();
+ if (flags.size() != count) {
+ ythrow yexception()
+ << "Mismatch of sizes vectors passed to CompileMulti. "
+ << "size(regexs) = " << regexs.size() << ". "
+ << "size(flags) = " << flags.size() << ".";
+ }
+ if (ids.size() != count) {
+ ythrow yexception()
+ << "Mismatch of sizes vectors passed to CompileMulti. "
+ << "size(regexs) = " << regexs.size() << ". "
+ << "size(ids) = " << ids.size() << ".";
+ }
+ if (extendedParameters && extendedParameters->size() != count) {
+ ythrow yexception()
+ << "Mismatch of sizes vectors passed to CompileMulti. "
+ << "size(regexs) = " << regexs.size() << ". "
+ << "size(extendedParameters) = " << extendedParameters->size() << ".";
+ }
+ hs_database_t* rawDb = nullptr;
+ hs_compile_error_t* rawCompileErr = nullptr;
+ hs_error_t status = hs_compile_ext_multi(
+ regexs.data(),
+ flags.data(),
+ ids.data(),
+ extendedParameters ? extendedParameters->data() : nullptr,
+ count,
+ HS_MODE_BLOCK,
+ platform,
+ &rawDb,
+ &rawCompileErr);
+ TDatabase db(rawDb);
+ NHyperscan::TCompileError compileError(rawCompileErr);
+ if (status != HS_SUCCESS) {
+ if (compileError->expression >= 0) {
+ const char* regex = regexs[compileError->expression];
+ ythrow TCompileException()
+ << "Failed to compile regex: " << regex << ". "
+ << "Error message (hyperscan): " << compileError->message;
+ } else {
+ ythrow TCompileException()
+ << "Failed to compile multiple regexs. "
+ << "Error message (hyperscan): " << compileError->message;
+ }
+ }
+ return db;
+ }
+
+ bool Matches(
+ const TDatabase& db,
+ const TScratch& scratch,
+ const TStringBuf& text,
+ const TImpl& impl) {
+ bool result = false;
+ auto callback = [&](unsigned int /* id */, unsigned long long /* from */, unsigned long long /* to */) {
+ result = true;
+ return 1; // stop scan
+ };
+ Scan(
+ db,
+ scratch,
+ text,
+ callback,
+ impl);
+ return result;
+ }
+ } // namespace NPrivate
+
+ TDatabase Compile(const TStringBuf& regex, unsigned int flags) {
+ auto platformInfo = NPrivate::MakeCurrentPlatformInfo();
+ return NPrivate::Compile(regex, flags, &platformInfo);
+ }
+
+ TDatabase Compile(const TStringBuf& regex, unsigned int flags, TCPUFeatures cpuFeatures) {
+ auto platformInfo = NPrivate::MakePlatformInfo(cpuFeatures);
+ return NPrivate::Compile(regex, flags, &platformInfo);
+ }
+
+ TDatabase CompileMulti(
+ const TVector<const char*>& regexs,
+ const TVector<unsigned int>& flags,
+ const TVector<unsigned int>& ids,
+ const TVector<const hs_expr_ext_t*>* extendedParameters)
+ {
+ auto platformInfo = NPrivate::MakeCurrentPlatformInfo();
+ return NPrivate::CompileMulti(regexs, flags, ids, &platformInfo, extendedParameters);
+ }
+
+ TDatabase CompileMulti(
+ const TVector<const char*>& regexs,
+ const TVector<unsigned int>& flags,
+ const TVector<unsigned int>& ids,
+ TCPUFeatures cpuFeatures,
+ const TVector<const hs_expr_ext_t*>* extendedParameters)
+ {
+ auto platformInfo = NPrivate::MakePlatformInfo(cpuFeatures);
+ return NPrivate::CompileMulti(regexs, flags, ids, &platformInfo, extendedParameters);
+ }
+
+ TScratch MakeScratch(const TDatabase& db) {
+ hs_scratch_t* rawScratch = nullptr;
+ hs_error_t status = Singleton<NPrivate::TImpl>()->AllocScratch(db.Get(), &rawScratch);
+ NHyperscan::TScratch scratch(rawScratch);
+ if (status != HS_SUCCESS) {
+ ythrow yexception() << "Failed to make scratch for hyperscan database";
+ }
+ return scratch;
+ }
+
+ void GrowScratch(TScratch& scratch, const TDatabase& db) {
+ hs_scratch_t* rawScratch = scratch.Get();
+ hs_error_t status = Singleton<NPrivate::TImpl>()->AllocScratch(db.Get(), &rawScratch);
+ if (rawScratch != scratch.Get()) {
+ Y_UNUSED(scratch.Release()); // freed by hs_alloc_scratch
+ scratch.Reset(rawScratch);
+ }
+ if (status != HS_SUCCESS) {
+ ythrow yexception() << "Failed to make grow scratch for hyperscan database";
+ }
+ }
+
+ TScratch CloneScratch(const TScratch& scratch) {
+ hs_scratch_t* rawScratch = nullptr;
+ hs_error_t status = hs_clone_scratch(scratch.Get(), &rawScratch);
+ TScratch scratchCopy(rawScratch);
+ if (status != HS_SUCCESS) {
+ ythrow yexception() << "Failed to clone scratch for hyperscan database";
+ }
+ return scratchCopy;
+ }
+
+ bool Matches(
+ const TDatabase& db,
+ const TScratch& scratch,
+ const TStringBuf& text)
+ {
+ return NPrivate::Matches(db, scratch, text, *Singleton<NPrivate::TImpl>());
+ }
+
+ TString Serialize(const TDatabase& db) {
+ char* databaseBytes = nullptr;
+ size_t databaseLength;
+ hs_error_t status = Singleton<NPrivate::TImpl>()->SerializeDatabase(
+ db.Get(),
+ &databaseBytes,
+ &databaseLength);
+ TSerializedDatabase serialization(databaseBytes);
+ if (status != HS_SUCCESS) {
+ ythrow yexception() << "Failed to serialize hyperscan database";
+ }
+ return TString(serialization.Get(), databaseLength);
+ }
+
+ TDatabase Deserialize(const TStringBuf& serialization) {
+ hs_database_t* rawDb = nullptr;
+ hs_error_t status = Singleton<NPrivate::TImpl>()->DeserializeDatabase(
+ serialization.begin(),
+ serialization.size(),
+ &rawDb);
+ TDatabase db(rawDb);
+ if (status != HS_SUCCESS) {
+ if (status == HS_DB_PLATFORM_ERROR) {
+ ythrow yexception() << "Serialized Hyperscan database is incompatible with current CPU";
+ } else {
+ ythrow yexception() << "Failed to deserialize hyperscan database";
+ }
+ }
+ return db;
+ }
+}
diff --git a/library/cpp/regex/hyperscan/hyperscan.h b/library/cpp/regex/hyperscan/hyperscan.h
new file mode 100644
index 0000000000..1c8f404389
--- /dev/null
+++ b/library/cpp/regex/hyperscan/hyperscan.h
@@ -0,0 +1,160 @@
+#pragma once
+
+#include <contrib/libs/hyperscan/src/hs.h>
+
+#include <util/generic/ptr.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+#include <util/system/cpu_id.h>
+
+namespace NHyperscan {
+ using TCPUFeatures = decltype(hs_platform_info_t::cpu_features);
+ constexpr TCPUFeatures CPU_FEATURES_AVX2 = HS_CPU_FEATURES_AVX2;
+ constexpr TCPUFeatures CPU_FEATURES_AVX512 = HS_CPU_FEATURES_AVX512 | HS_CPU_FEATURES_AVX2;
+
+ template<typename TNativeDeleter, TNativeDeleter NativeDeleter>
+ class TDeleter {
+ public:
+ template<typename T>
+ static void Destroy(T* ptr) {
+ NativeDeleter(ptr);
+ }
+ };
+
+ using TDatabase = THolder<hs_database_t, TDeleter<decltype(&hs_free_database), &hs_free_database>>;
+
+ using TScratch = THolder<hs_scratch_t, TDeleter<decltype(&hs_free_scratch), &hs_free_scratch>>;
+
+ class TCompileException : public yexception {
+ };
+
+
+ namespace NPrivate {
+ enum class ERuntime {
+ Core2 = 0,
+ Corei7 = 1,
+ AVX2 = 2,
+ AVX512 = 3
+ };
+
+ ERuntime DetectCurrentRuntime();
+
+ TCPUFeatures RuntimeCpuFeatures(ERuntime runtime);
+
+ hs_platform_info_t MakePlatformInfo(TCPUFeatures cpuFeatures);
+
+ struct TImpl {
+ hs_error_t (*AllocScratch)(const hs_database_t* db, hs_scratch_t** scratch);
+
+ hs_error_t (*Scan)(const hs_database_t* db, const char* data,
+ unsigned length, unsigned flags, hs_scratch_t* scratch,
+ match_event_handler onEvent, void* userCtx);
+
+ hs_error_t (*SerializeDatabase)(const hs_database_t* db, char** bytes, size_t* serialized_length);
+
+ hs_error_t (*DeserializeDatabase)(const char* bytes, size_t length, hs_database_t** info);
+
+ TImpl() : TImpl(DetectCurrentRuntime()) {}
+
+ explicit TImpl(ERuntime runtime);
+ };
+
+ TDatabase Compile(const TStringBuf& regex, unsigned int flags, hs_platform_info_t* platform);
+
+ TDatabase CompileMulti(
+ const TVector<const char*>& regexs,
+ const TVector<unsigned int>& flags,
+ const TVector<unsigned int>& ids,
+ hs_platform_info_t* platform,
+ const TVector<const hs_expr_ext_t*>* extendedParameters = nullptr);
+
+ // We need to parametrize Scan and Matches functions for testing purposes
+ template<typename TCallback>
+ void Scan(
+ const TDatabase& db,
+ const TScratch& scratch,
+ const TStringBuf& text,
+ TCallback& callback, // applied to index of matched regex
+ const TImpl& impl
+ ) {
+ struct TCallbackWrapper {
+ static int EventHandler(
+ unsigned int id,
+ unsigned long long from,
+ unsigned long long to,
+ unsigned int flags,
+ void* ctx) {
+ Y_UNUSED(flags);
+ TCallback& callback2 = *reinterpret_cast<TCallback*>(ctx);
+ if constexpr (std::is_same_v<int, std::invoke_result_t<TCallback, unsigned int, unsigned long long, unsigned long long>>) {
+ return callback2(id, from, to);
+ } else {
+ callback2(id, from, to);
+ return 0;
+ }
+ }
+ };
+ unsigned int flags = 0; // unused at present
+ hs_error_t status = impl.Scan(
+ db.Get(),
+ text.begin(),
+ text.size(),
+ flags,
+ scratch.Get(),
+ &TCallbackWrapper::EventHandler,
+ &callback);
+ if (status != HS_SUCCESS && status != HS_SCAN_TERMINATED) {
+ ythrow yexception() << "Failed to scan against text: " << text;
+ }
+ }
+
+ bool Matches(
+ const TDatabase& db,
+ const TScratch& scratch,
+ const TStringBuf& text,
+ const TImpl& impl);
+ }
+
+ TDatabase Compile(const TStringBuf& regex, unsigned int flags);
+
+ TDatabase Compile(const TStringBuf& regex, unsigned int flags, TCPUFeatures cpuFeatures);
+
+ TDatabase CompileMulti(
+ const TVector<const char*>& regexs,
+ const TVector<unsigned int>& flags,
+ const TVector<unsigned int>& ids,
+ const TVector<const hs_expr_ext_t*>* extendedParameters = nullptr);
+
+ TDatabase CompileMulti(
+ const TVector<const char*>& regexs,
+ const TVector<unsigned int>& flags,
+ const TVector<unsigned int>& ids,
+ TCPUFeatures cpuFeatures,
+ const TVector<const hs_expr_ext_t*>* extendedParameters = nullptr);
+
+ TScratch MakeScratch(const TDatabase& db);
+
+ void GrowScratch(TScratch& scratch, const TDatabase& db);
+
+ TScratch CloneScratch(const TScratch& scratch);
+
+ template<typename TCallback>
+ void Scan(
+ const TDatabase& db,
+ const TScratch& scratch,
+ const TStringBuf& text,
+ TCallback& callback // applied to index of matched regex
+ ) {
+ NPrivate::Scan<TCallback>(db, scratch, text, callback, *Singleton<NPrivate::TImpl>());
+ }
+
+ bool Matches(
+ const TDatabase& db,
+ const TScratch& scratch,
+ const TStringBuf& text);
+
+ TString Serialize(const TDatabase& db);
+
+ TDatabase Deserialize(const TStringBuf& serialization);
+}
diff --git a/library/cpp/regex/hyperscan/ut/hyperscan_ut.cpp b/library/cpp/regex/hyperscan/ut/hyperscan_ut.cpp
new file mode 100644
index 0000000000..9caa53f2e7
--- /dev/null
+++ b/library/cpp/regex/hyperscan/ut/hyperscan_ut.cpp
@@ -0,0 +1,231 @@
+#include <library/cpp/regex/hyperscan/hyperscan.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/set.h>
+
+#include <array>
+#include <algorithm>
+
+Y_UNIT_TEST_SUITE(HyperscanWrappers) {
+ using namespace NHyperscan;
+ using namespace NHyperscan::NPrivate;
+
+ Y_UNIT_TEST(CompileAndScan) {
+ TDatabase db = Compile("a.c", HS_FLAG_DOTALL | HS_FLAG_SINGLEMATCH);
+ TScratch scratch = MakeScratch(db);
+
+ unsigned int foundId = 42;
+ auto callback = [&](unsigned int id, unsigned long long /* from */, unsigned long long /* to */) {
+ foundId = id;
+ };
+ NHyperscan::Scan(
+ db,
+ scratch,
+ "abc",
+ callback);
+ UNIT_ASSERT_EQUAL(foundId, 0);
+ }
+
+ Y_UNIT_TEST(Matches) {
+ NHyperscan::TDatabase db = NHyperscan::Compile(
+ "a.c",
+ HS_FLAG_DOTALL | HS_FLAG_SINGLEMATCH);
+ NHyperscan::TScratch scratch = NHyperscan::MakeScratch(db);
+ UNIT_ASSERT(NHyperscan::Matches(db, scratch, "abc"));
+ UNIT_ASSERT(!NHyperscan::Matches(db, scratch, "foo"));
+ }
+
+ Y_UNIT_TEST(Multi) {
+ NHyperscan::TDatabase db = NHyperscan::CompileMulti(
+ {
+ "foo",
+ "bar",
+ },
+ {
+ HS_FLAG_DOTALL | HS_FLAG_SINGLEMATCH,
+ HS_FLAG_DOTALL | HS_FLAG_SINGLEMATCH | HS_FLAG_CASELESS,
+ },
+ {
+ 42,
+ 241,
+ });
+ NHyperscan::TScratch scratch = NHyperscan::MakeScratch(db);
+
+ UNIT_ASSERT(NHyperscan::Matches(db, scratch, "foo"));
+ UNIT_ASSERT(NHyperscan::Matches(db, scratch, "bar"));
+ UNIT_ASSERT(NHyperscan::Matches(db, scratch, "BAR"));
+ UNIT_ASSERT(!NHyperscan::Matches(db, scratch, "FOO"));
+
+ TSet<unsigned int> foundIds;
+ auto callback = [&](unsigned int id, unsigned long long /* from */, unsigned long long /* to */) {
+ foundIds.insert(id);
+ };
+ NHyperscan::Scan(
+ db,
+ scratch,
+ "fooBaR",
+ callback);
+ UNIT_ASSERT_EQUAL(foundIds.size(), 2);
+ UNIT_ASSERT(foundIds.contains(42));
+ UNIT_ASSERT(foundIds.contains(241));
+ }
+
+ // https://ml.yandex-team.ru/thread/2370000002965712422/
+ Y_UNIT_TEST(MultiRegression) {
+ NHyperscan::CompileMulti(
+ {
+ "aa.bb/cc.dd",
+ },
+ {
+ HS_FLAG_UTF8,
+ },
+ {
+ 0,
+ });
+ }
+
+ Y_UNIT_TEST(Serialize) {
+ NHyperscan::TDatabase db = NHyperscan::Compile(
+ "foo",
+ HS_FLAG_DOTALL | HS_FLAG_SINGLEMATCH);
+ TString serialization = Serialize(db);
+ db.Reset();
+ TDatabase db2 = Deserialize(serialization);
+ NHyperscan::TScratch scratch = NHyperscan::MakeScratch(db2);
+
+ UNIT_ASSERT(NHyperscan::Matches(db2, scratch, "foo"));
+ UNIT_ASSERT(!NHyperscan::Matches(db2, scratch, "FOO"));
+ }
+
+ Y_UNIT_TEST(GrowScratch) {
+ NHyperscan::TDatabase db1 = NHyperscan::Compile(
+ "foo",
+ HS_FLAG_DOTALL | HS_FLAG_SINGLEMATCH);
+ NHyperscan::TDatabase db2 = NHyperscan::Compile(
+ "longer\\w\\w\\wpattern",
+ HS_FLAG_DOTALL | HS_FLAG_SINGLEMATCH | HS_FLAG_UTF8);
+ NHyperscan::TScratch scratch = NHyperscan::MakeScratch(db1);
+ NHyperscan::GrowScratch(scratch, db2);
+ UNIT_ASSERT(NHyperscan::Matches(db1, scratch, "foo"));
+ UNIT_ASSERT(NHyperscan::Matches(db2, scratch, "longerWWWpattern"));
+ }
+
+ Y_UNIT_TEST(CloneScratch) {
+ NHyperscan::TDatabase db = NHyperscan::Compile(
+ "foo",
+ HS_FLAG_DOTALL | HS_FLAG_SINGLEMATCH);
+ NHyperscan::TScratch scratch1 = NHyperscan::MakeScratch(db);
+ NHyperscan::TScratch scratch2 = NHyperscan::CloneScratch(scratch1);
+ scratch1.Reset();
+ UNIT_ASSERT(NHyperscan::Matches(db, scratch2, "foo"));
+ }
+
+ class TSimpleSingleRegex {
+ public:
+ static TDatabase Compile(TCPUFeatures cpuFeatures) {
+ return NHyperscan::Compile("foo", HS_FLAG_DOTALL | HS_FLAG_SINGLEMATCH, cpuFeatures);
+ }
+ static void Check(const TDatabase& db, const NHyperscan::NPrivate::TImpl& impl) {
+ NHyperscan::TScratch scratch = NHyperscan::MakeScratch(db);
+ UNIT_ASSERT(NHyperscan::NPrivate::Matches(db, scratch, "foo", impl));
+ UNIT_ASSERT(!NHyperscan::NPrivate::Matches(db, scratch, "FOO", impl));
+ }
+ };
+
+ // This regex uses AVX2 instructions on long (>70) texts.
+ // It crushes when compiled for machine with AVX2 and run on machine without it.
+ class TAvx2SingleRegex {
+ public:
+ static TDatabase Compile(TCPUFeatures cpuFeatures) {
+ auto regex = "[ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё]+"
+ "[.][\\-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]{2,5}";
+ unsigned int flags = HS_FLAG_UTF8 | HS_FLAG_DOTALL | HS_FLAG_SINGLEMATCH | HS_FLAG_ALLOWEMPTY;
+ return NHyperscan::Compile(regex, flags, cpuFeatures);
+ }
+ static void Check(const TDatabase& db, const NHyperscan::NPrivate::TImpl& impl) {
+ NHyperscan::TScratch scratch = NHyperscan::MakeScratch(db);
+ UNIT_ASSERT(NHyperscan::NPrivate::Matches(
+ db,
+ scratch,
+ "_________________________________________________________________"
+ "фу.bar"
+ "_________________________________________________________________",
+ impl));
+ UNIT_ASSERT(!NHyperscan::NPrivate::Matches(
+ db,
+ scratch,
+ "_________________________________________________________________"
+ "фу"
+ "_________________________________________________________________",
+ impl));
+ }
+ };
+
+ class TSimpleMultiRegex {
+ public:
+ static TDatabase Compile(TCPUFeatures cpuFeatures) {
+ return NHyperscan::CompileMulti(
+ {
+ "foo",
+ "bar",
+ },
+ {
+ HS_FLAG_DOTALL | HS_FLAG_SINGLEMATCH,
+ HS_FLAG_DOTALL | HS_FLAG_SINGLEMATCH | HS_FLAG_CASELESS,
+ },
+ {
+ 42,
+ 241,
+ },
+ cpuFeatures);
+ }
+ static void Check(const TDatabase& db, const NHyperscan::NPrivate::TImpl& impl) {
+ NHyperscan::TScratch scratch = NHyperscan::MakeScratch(db);
+
+ UNIT_ASSERT(NHyperscan::NPrivate::Matches(db, scratch, "foo", impl));
+ UNIT_ASSERT(NHyperscan::NPrivate::Matches(db, scratch, "bar", impl));
+ UNIT_ASSERT(NHyperscan::NPrivate::Matches(db, scratch, "BAR", impl));
+ UNIT_ASSERT(!NHyperscan::NPrivate::Matches(db, scratch, "FOO", impl));
+
+ TSet<unsigned int> foundIds;
+ auto callback = [&](unsigned int id, unsigned long long /* from */, unsigned long long /* to */) {
+ foundIds.insert(id);
+ };
+ NHyperscan::NPrivate::Scan(
+ db,
+ scratch,
+ "fooBaR",
+ callback,
+ impl);
+ UNIT_ASSERT_EQUAL(foundIds.size(), 2);
+ UNIT_ASSERT(foundIds.contains(42));
+ UNIT_ASSERT(foundIds.contains(241));
+ }
+ };
+
+ template <class Regex>
+ void TestCrossPlatformCompile() {
+ const std::array<ERuntime, 4> runtimes = {
+ ERuntime::Core2,
+ ERuntime::Corei7,
+ ERuntime::AVX2,
+ ERuntime::AVX512
+ };
+
+ // Unfortunately, we cannot emulate runtimes with more capabilities than current machine.
+ auto currentRuntimeIter = std::find(runtimes.cbegin(), runtimes.cend(), DetectCurrentRuntime());
+ Y_ASSERT(currentRuntimeIter != runtimes.cend());
+
+ for (auto targetRuntime = runtimes.cbegin(); targetRuntime <= currentRuntimeIter; ++targetRuntime) {
+ auto db = Regex::Compile(RuntimeCpuFeatures(*targetRuntime));
+ Regex::Check(db, NHyperscan::NPrivate::TImpl{*targetRuntime});
+ }
+ }
+
+ Y_UNIT_TEST(CrossPlatformCompile) {
+ TestCrossPlatformCompile<TSimpleSingleRegex>();
+ TestCrossPlatformCompile<TAvx2SingleRegex>();
+ TestCrossPlatformCompile<TSimpleMultiRegex>();
+ }
+}
diff --git a/library/cpp/regex/hyperscan/ut/ya.make b/library/cpp/regex/hyperscan/ut/ya.make
new file mode 100644
index 0000000000..da67b88672
--- /dev/null
+++ b/library/cpp/regex/hyperscan/ut/ya.make
@@ -0,0 +1,13 @@
+UNITTEST()
+
+PEERDIR(
+ library/cpp/regex/hyperscan
+)
+
+OWNER(g:antiinfra)
+
+SRCS(
+ hyperscan_ut.cpp
+)
+
+END()
diff --git a/library/cpp/regex/hyperscan/ya.make b/library/cpp/regex/hyperscan/ya.make
new file mode 100644
index 0000000000..e99130ae18
--- /dev/null
+++ b/library/cpp/regex/hyperscan/ya.make
@@ -0,0 +1,19 @@
+LIBRARY()
+
+OWNER(g:antiinfra)
+
+PEERDIR(
+ contrib/libs/hyperscan
+ contrib/libs/hyperscan/runtime_core2
+ contrib/libs/hyperscan/runtime_corei7
+ contrib/libs/hyperscan/runtime_avx2
+ contrib/libs/hyperscan/runtime_avx512
+)
+
+SRCS(
+ hyperscan.cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/regex/pcre/README.md b/library/cpp/regex/pcre/README.md
new file mode 100644
index 0000000000..b5b09a3715
--- /dev/null
+++ b/library/cpp/regex/pcre/README.md
@@ -0,0 +1,59 @@
+# About
+This is a PCRE library wrapper which provides unified interface for UTF-8, UTF-16 and UTF-32 strings matching and optimization control.
+
+# Rationale
+Many Arcadia related libraries (telfinder, lemmer etc.) provides only UTF-16 interfaces, because this is way faster for cyrillic texts. Any algorithm that is working with such libraries and regular expressions must use `WideToUTF8` and `UTF8ToWide` at the borderline between regular expression and UTF-18 interface. This leads us to great performance penalty.
+This library allows us to erase these charset conversions.
+
+# Interface
+
+Before starting with interface details, let's consider simplest library usage example:
+`UNIT_ASSERT(NPcre::TPcre<wchar16>(u"ba+d").Matches(TWtringBuf(u"baaad")));`
+
+Here we see regular expression construction for UTF-16 charset:
+
+`NPcre::TPcre<wchar16>(u"ba+d")`
+
+and matching of the subject string `baaad` against this pattern:
+
+`.Matches(TWtringBuf(u"baaad"))`;
+
+Let's consider both of them in details.
+
+## Construction
+`NPcre::TPcre` class accepts single template parameter: `TCharType`. Currently supported char types are `char`, `wchar16` and `wchar32`. Additional char types traits can be defined in `traits.h`
+
+Constructor accepts three arguments. Two of them are optional:
+1. Zero-terminated string on characters with pattern
+2. Optimization type. The default value is `NPcre::EOptimize::None` which means no pattern optimization. Another possible value is `NPcre::EOptimize::Study` which will take some time at construction stage but could give up to 4x speed boost. And the last but not the least is `NPcre::EOptimize::JIT` which performs JIT optimization which could take significant time but could give up to 10x speed boost.
+3. Regular expressions compile flags. We don't want to reimplement every constant from PCRE library, so they are passed as they are. Full list of compile flags can be found [here](https://www.pcre.org/original/doc/html/pcre_compile2.html), but for most cases `PCRE_UTF8 | PCRE_UCP` will be enough. The default value is `0`.
+
+## Matching
+{% note tip %}
+Two words on PCRE workspaces. Workspace is memory area where PCRE stores information about back references and capturing groups. If passed workspace size is not enough, PCRE will allocate bigger workspace in heap. For simple matching and string searching of string without back references, workspace is not required and this library provides separate functions that won't waste space on workspace and this could save ≈0.5% of CPU TIME on simple patterns.
+For regular expressions with capturing groups, recommended workspace size is `(capturing groups count + 1)`.
+{% endnote %}
+
+In the example above matching function `Matches` returns boolean indicating that subject string matched pattern and accepts two arguments:
+1. `TBasicStringBuf<TCharType>` with subject string
+2. Regular expression execute flags. We don't want to reimplement every constant from PCRE library, so they are passed as they are. Full list of compile flags can be found [here](https://www.pcre.org/original/doc/html/pcre_exec.html). For most cases `0` will be just fine and this is the default value.
+
+## Searching
+Function `Find` accepts the same arguments as `Match` and returns `TMaybe<NPcre::TPcreMatch>` which contains pair of ints with start and end offsets of string found. Check result for `Defined` to ensure that pattern was found in subject string.
+
+## Capturing
+The last member function of `NPcre::TPcre` is `Capture` which searches for pattern and returns capturing group.
+
+### Return value
+Return value is `NPcre::TPcreMatches` which is alias for `TVector<NPcre::TPcreMatch>`.
+Vector will be empty if pattern wasn't found in subject string.
+If pattern was found, first element will contain start and end offsets of string found.
+All other elements will contains start and end offsets of capturing groups in order they appeared in regular expression.
+{% note tip %}
+If some capturing group not matched subject string, but some of consequent capturing groups did, this capturing group will present as `-1, -1` pair.
+For example: calling `Capture` on pattern `(a)(?:(b)c|b(d))` against subject string `zabda` will return `[{1,4},{1,2},{-1,-1},{3,4}]` because capturing group `(b)` wasn't matched.
+{% endnote %}
+### Arguments
+1. `TBasicStringBuf<TCharType>` with subject string
+2. Regular expression execute flags.
+3. Initial workspace size. Default value is `16` but if pattern contains more than 16 capturing groups, this function will reallocate workspace with bigger size.
diff --git a/library/cpp/regex/pcre/benchmark/main.cpp b/library/cpp/regex/pcre/benchmark/main.cpp
new file mode 100644
index 0000000000..3c11ef4f29
--- /dev/null
+++ b/library/cpp/regex/pcre/benchmark/main.cpp
@@ -0,0 +1,80 @@
+#include <benchmark/benchmark.h>
+
+#include <library/cpp/regex/pcre/pcre.h>
+
+#include <util/charset/wide.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+
+static TStringBuf SimplePattern = "[-.\\w]+@(?:[a-z\\d]{2,}\\.)+[a-z]{2,6}";
+static TStringBuf ComplexPattern = R"((?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*:(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)(?:,\s*(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[(?:[^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*))*)?;\s*))";
+
+static constexpr size_t HaystacksCount = 32;
+static constexpr size_t MinPrefix = 1024;
+
+static TVector<TString> GenerateHaystacks() {
+ // Generate long randomized haystacks to prevent cache hit
+ TVector<TString> result(Reserve(HaystacksCount));
+ for (size_t i = 0; i < HaystacksCount; ++i) {
+ result.push_back(TString::Join(ComplexPattern.SubString(MinPrefix + i, ComplexPattern.Size() - MinPrefix - i), ComplexPattern.SubString(0, MinPrefix + i)));
+ }
+ return result;
+}
+
+static const TVector<TString> Haystacks{GenerateHaystacks()};
+
+static const NPcre::TPcre<char> Simple{SimplePattern.Data()};
+static const NPcre::TPcre<char> SimpleStudy{SimplePattern.Data(), NPcre::EOptimize::Study};
+static const NPcre::TPcre<char> SimpleJIT{SimplePattern.Data(), NPcre::EOptimize::JIT};
+static const NPcre::TPcre<char> Complex{ComplexPattern.Data()};
+static const NPcre::TPcre<char> ComplexStudy{ComplexPattern.Data(), NPcre::EOptimize::Study};
+static const NPcre::TPcre<char> ComplexJIT{ComplexPattern.Data(), NPcre::EOptimize::JIT};
+
+static void Benchmark(benchmark::State& state, const NPcre::TPcre<char>& pattern) {
+ for (auto _ : state) {
+ for (size_t i = 0; i < HaystacksCount; ++i) {
+ // Force string reallocation, so there will be no chance for cache hit of any type
+ benchmark::DoNotOptimize(pattern.Matches(TString{i, 'a'} + Haystacks[i]));
+ }
+ }
+}
+
+static void BenchmarkSimplePatternJIT(benchmark::State& state) {
+ Benchmark(state, SimpleJIT);
+}
+
+static void BenchmarkSimplePatternStudy(benchmark::State& state) {
+ Benchmark(state, SimpleStudy);
+}
+
+static void BenchmarkSimplePattern(benchmark::State& state) {
+ Benchmark(state, Simple);
+}
+
+BENCHMARK(BenchmarkSimplePatternJIT)->Iterations(1);
+BENCHMARK(BenchmarkSimplePatternStudy)->Iterations(1);
+BENCHMARK(BenchmarkSimplePattern)->Iterations(1);
+BENCHMARK(BenchmarkSimplePatternJIT);
+BENCHMARK(BenchmarkSimplePatternStudy);
+BENCHMARK(BenchmarkSimplePattern);
+
+static void BenchmarkComplexPatternJIT(benchmark::State& state) {
+ Benchmark(state, ComplexJIT);
+}
+
+static void BenchmarkComplexPatternStudy(benchmark::State& state) {
+ Benchmark(state, ComplexStudy);
+}
+
+static void BenchmarkComplexPattern(benchmark::State& state) {
+ Benchmark(state, Complex);
+}
+
+BENCHMARK(BenchmarkComplexPatternJIT)->Iterations(1);
+BENCHMARK(BenchmarkComplexPatternStudy)->Iterations(1);
+BENCHMARK(BenchmarkComplexPattern)->Iterations(1);
+BENCHMARK(BenchmarkComplexPatternJIT);
+BENCHMARK(BenchmarkComplexPatternStudy);
+BENCHMARK(BenchmarkComplexPattern);
+
diff --git a/library/cpp/regex/pcre/benchmark/ya.make b/library/cpp/regex/pcre/benchmark/ya.make
new file mode 100644
index 0000000000..7c30fae0a6
--- /dev/null
+++ b/library/cpp/regex/pcre/benchmark/ya.make
@@ -0,0 +1,14 @@
+G_BENCHMARK()
+
+OWNER(g:so)
+
+PEERDIR(
+ library/cpp/regex/pcre
+)
+
+SRCS(
+ main.cpp
+)
+
+END()
+
diff --git a/library/cpp/regex/pcre/pcre.cpp b/library/cpp/regex/pcre/pcre.cpp
new file mode 100644
index 0000000000..9e97d5f8f7
--- /dev/null
+++ b/library/cpp/regex/pcre/pcre.cpp
@@ -0,0 +1 @@
+#include "pcre.h"
diff --git a/library/cpp/regex/pcre/pcre.h b/library/cpp/regex/pcre/pcre.h
new file mode 100644
index 0000000000..82a9774f00
--- /dev/null
+++ b/library/cpp/regex/pcre/pcre.h
@@ -0,0 +1,191 @@
+#pragma once
+
+#include "traits.h"
+
+#include <library/cpp/containers/stack_array/stack_array.h>
+
+#include <util/generic/maybe.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+namespace NPcre {
+ //! Start and end offset for match group.
+ using TPcreMatch = std::pair<int, int>;
+
+ //! Full match result containing all capturing groups.
+ /*!
+ * At zero index we have whole matched string start and end offsets.
+ * All other elements will contain capturing groups positions.
+ * Non-captured capturing groups will have {-1, -1} offsets.
+ */
+ using TPcreMatches = TVector<TPcreMatch>;
+
+ //! Compiled pattern optimization strategy.
+ enum class EOptimize {
+ //! No optimization.
+ /*!
+ * Useful for non-reusable patterns where compile time matters.
+ */
+ None,
+ //! Basic optimization via |pcre_study|.
+ /*!
+ * Could give up to 4x match speed boost in exchange of increased
+ * construction time. Could not.
+ */
+ Study,
+ //! PCRE JIT optimization.
+ /*!
+ * Could give up to 10x match speed bust in exchange of significantly
+ * increased compile time. Also, for very complex patterns |pcre_exec|
+ * could return |PCRE_ERROR_JIT_STACKLIMIT|. See
+ * https://www.pcre.org/original/doc/html/pcrejit.html for details.
+ */
+ JIT
+ };
+
+ //! PCRE code container. Controls its life time and provides handy wrapper.
+ template <class TCharType>
+ class TPcre {
+ private:
+ using TCodeType = typename TPcreTraits<TCharType>::TCodeType;
+ using TExtraType = typename TPcreTraits<TCharType>::TExtraType;
+ using TStringType = typename TPcreTraits<TCharType>::TStringType;
+ using TTraits = TPcreTraits<TCharType>;
+ static constexpr size_t DefaultWorkspaceSize = 16;
+
+ public:
+ //! Compiles regexp into internal representation for future use.
+ /*!
+ * \param pattern Regular expression to be compiled.
+ * \param optimize If |EOptimize::JIT|, perform additional
+ * analysis, which will take extra time, but could
+ * speed up matching. |None| to omit optimization.
+ * \param compileFlags See https://www.pcre.org/original/doc/html/pcre_compile2.html
+ **/
+ TPcre(const TCharType* pattern, EOptimize optimize = EOptimize::None, int compileFlags = 0) {
+ int errcode;
+ const char* errptr;
+ int erroffset;
+ Code.Reset(TTraits::Compile((TStringType) pattern, compileFlags, &errcode, &errptr, &erroffset, nullptr));
+ if (!Code) {
+ ythrow yexception() << "Failed to compile pattern <" << pattern
+ << ">, because of error at pos " << erroffset
+ << ", error code " << errcode << ": " << errptr;
+ }
+ if (optimize != EOptimize::None) {
+ errptr = nullptr;
+ int options;
+ if (optimize == EOptimize::Study) {
+ options = 0;
+ } else {
+ options = PCRE_STUDY_JIT_COMPILE;
+ }
+ Extra.Reset(TTraits::Study(Code.Get(), options, &errptr));
+ if (errptr) {
+ ythrow yexception() << "Failed to study pattern <" << pattern << ">: " << errptr;
+ }
+ }
+ }
+
+ //! Check if compiled pattern matches string.
+ /*!
+ * \param string String to search in.
+ * \param executeFlags See https://www.pcre.org/original/doc/html/pcre_exec.html
+ * \param workspaceSize Amount of space which will be allocated for
+ * back references. PCRE could allocate more
+ * heap space is provided workspaceSize won't
+ * fit all of them.
+ * \returns |true| if there is a match.
+ */
+ bool Matches(TBasicStringBuf<TCharType> string, int executeFlags = 0, size_t workspaceSize = DefaultWorkspaceSize) const {
+ Y_ASSERT(workspaceSize >= 0);
+ size_t ovecsize = workspaceSize * 3;
+ NStackArray::TStackArray<int> ovector(ALLOC_ON_STACK(int, ovecsize));
+ return ConvertReturnCode(TTraits::Exec(Code.Get(), Extra.Get(), (TStringType) string.Data(), string.Size(), 0, executeFlags, ovector.data(), ovecsize));
+ }
+
+ //! Find compiled pattern in string.
+ /*!
+ * \param string String to search in.
+ * \param executeFlags See https://www.pcre.org/original/doc/html/pcre_exec.html
+ * \param workspaceSize Amount of space which will be allocated for
+ * back references. PCRE could allocate more
+ * heap space is provided workspaceSize won't
+ * fit all of them.
+ * \returns Start and end offsets pair if there is a
+ * match. |Nothing| otherwise.
+ */
+ Y_NO_SANITIZE("memory") TMaybe<TPcreMatch> Find(TBasicStringBuf<TCharType> string, int executeFlags = 0, size_t workspaceSize = DefaultWorkspaceSize) const {
+ Y_ASSERT(workspaceSize >= 0);
+ size_t ovecsize = workspaceSize * 3;
+ NStackArray::TStackArray<int> ovector(ALLOC_ON_STACK(int, ovecsize));
+ for (size_t i = 0; i < ovecsize; ++i) {
+ ovector[i] = -4;
+ }
+ int rc = TTraits::Exec(Code.Get(), Extra.Get(), (TStringType) string.Data(), string.Size(), 0, executeFlags, ovector.data(), ovecsize);
+ if (ConvertReturnCode(rc)) {
+ return MakeMaybe<TPcreMatch>(ovector[0], ovector[1]);
+ } else {
+ return Nothing();
+ }
+ }
+
+ //! Find and return all capturing groups in string.
+ /*!
+ * \param string String to search in.
+ * \param executeFlags See https://www.pcre.org/original/doc/html/pcre_exec.html
+ * \param initialWorkspaceSize Capturing groups vector initial size.
+ * Workspace will be grown and search will
+ * be repeated if there is not enough
+ * space.
+ * \returns List of capturing groups start and end
+ * offsets. First element will contain
+ * whole matched substring start and end
+ * offsets. For non-matched capturing
+ * groups, result will contain {-1, -1}
+ * pair.
+ * If pattern not found in string, result
+ * vector will be empty.
+ */
+ Y_NO_SANITIZE("memory") TPcreMatches Capture(TBasicStringBuf<TCharType> string, int executeFlags = 0, size_t initialWorkspaceSize = DefaultWorkspaceSize) const {
+ Y_ASSERT(initialWorkspaceSize > 0);
+ size_t ovecsize = (initialWorkspaceSize + 1) * 3;
+ while (true) {
+ NStackArray::TStackArray<int> ovector(ALLOC_ON_STACK(int, ovecsize));
+ int rc = TTraits::Exec(Code.Get(), Extra.Get(), (TStringType) string.Data(), string.Size(), 0, executeFlags, ovector.data(), ovecsize);
+ if (rc > 0) {
+ TPcreMatches result(Reserve(rc >> 1));
+ for (int i = 0, pos = 0; i < rc; ++i) {
+ int start = ovector[pos++];
+ int end = ovector[pos++];
+ result.emplace_back(start, end);
+ }
+ return result;
+ } else if (rc == 0) {
+ ovecsize <<= 1;
+ } else if (rc == PCRE_ERROR_NOMATCH) {
+ return TPcreMatches{};
+ } else if (rc < 0) {
+ ythrow yexception() << "Error. RC = " << rc;
+ }
+ }
+ }
+
+ private:
+ TPcreCode<TCharType> Code;
+ TPcreExtra<TCharType> Extra;
+
+ private:
+ static inline bool ConvertReturnCode(int rc) {
+ if (rc >= 0) {
+ return true;
+ } else if (rc == PCRE_ERROR_NOMATCH) {
+ return false;
+ } else {
+ ythrow yexception() << "Error. RC = " << rc;
+ }
+ }
+ };
+}
+
diff --git a/library/cpp/regex/pcre/pcre_ut.cpp b/library/cpp/regex/pcre/pcre_ut.cpp
new file mode 100644
index 0000000000..84d06499ae
--- /dev/null
+++ b/library/cpp/regex/pcre/pcre_ut.cpp
@@ -0,0 +1,89 @@
+#include <library/cpp/regex/pcre/pcre.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+template <class T>
+inline IOutputStream& operator<<(IOutputStream& out, const TVector<T>& value) {
+ size_t size = value.size();
+ out << "[";
+ for (size_t i = 0; i < size; ++i) {
+ if (i) {
+ out << ",";
+ }
+ out << value[i];
+ }
+ out << "]";
+ return out;
+}
+
+template <class T, class U>
+inline IOutputStream& operator<<(IOutputStream& out, const std::pair<T, U>& value) {
+ out << "{" << value.first << "," << value.second << "}";
+ return out;
+}
+
+// char8_t
+#define OPTIMIZE NPcre::EOptimize::None
+#define TEST_NAME(S) S
+#define STRING(S) S
+#define CHAR_TYPE char
+#include "pcre_ut_base.h"
+
+#undef OPTIMIZE
+#define OPTIMIZE NPcre::EOptimize::Study
+#undef TEST_NAME
+#define TEST_NAME(S) S ## Study
+#include "pcre_ut_base.h"
+
+#undef OPTIMIZE
+#define OPTIMIZE NPcre::EOptimize::JIT
+#undef TEST_NAME
+#define TEST_NAME(S) S ## JIT
+#include "pcre_ut_base.h"
+
+// char16_t
+#undef OPTIMIZE
+#define OPTIMIZE NPcre::EOptimize::None
+#undef TEST_NAME
+#define TEST_NAME(S) S ## 16
+#undef STRING
+#define STRING(S) u ## S
+#undef CHAR_TYPE
+#define CHAR_TYPE wchar16
+#include "pcre_ut_base.h"
+
+#undef OPTIMIZE
+#define OPTIMIZE NPcre::EOptimize::Study
+#undef TEST_NAME
+#define TEST_NAME(S) S ## Study16
+#include "pcre_ut_base.h"
+
+#undef OPTIMIZE
+#define OPTIMIZE NPcre::EOptimize::JIT
+#undef TEST_NAME
+#define TEST_NAME(S) S ## JIT16
+#include "pcre_ut_base.h"
+
+// char32_t
+#undef OPTIMIZE
+#define OPTIMIZE NPcre::EOptimize::None
+#undef TEST_NAME
+#define TEST_NAME(S) S ## 32
+#undef STRING
+#define STRING(S) U ## S
+#undef CHAR_TYPE
+#define CHAR_TYPE wchar32
+#include "pcre_ut_base.h"
+
+#undef OPTIMIZE
+#define OPTIMIZE NPcre::EOptimize::Study
+#undef TEST_NAME
+#define TEST_NAME(S) S ## Study32
+#include "pcre_ut_base.h"
+
+#undef OPTIMIZE
+#define OPTIMIZE NPcre::EOptimize::JIT
+#undef TEST_NAME
+#define TEST_NAME(S) S ## JIT32
+#include "pcre_ut_base.h"
+
diff --git a/library/cpp/regex/pcre/pcre_ut_base.h b/library/cpp/regex/pcre/pcre_ut_base.h
new file mode 100644
index 0000000000..1d61d07b14
--- /dev/null
+++ b/library/cpp/regex/pcre/pcre_ut_base.h
@@ -0,0 +1,38 @@
+#define CHECK_MATCHES(EXPECTED, PATTERN, STR) \
+ UNIT_ASSERT(EXPECTED == NPcre::TPcre<CHAR_TYPE>(STRING(PATTERN), OPTIMIZE).Matches(STRING(STR))); \
+ UNIT_ASSERT(EXPECTED == NPcre::TPcre<CHAR_TYPE>(STRING(PATTERN), OPTIMIZE).Matches(STRING(STR), 0, 10));
+
+#define CHECK(A, B) UNIT_ASSERT_STRINGS_EQUAL(ToString(STRING(A)), ToString(B))
+
+#define CHECK_GROUPS(EXPECTED, PATTERN, STR) \
+ CHECK(EXPECTED, NPcre::TPcre<CHAR_TYPE>(STRING(PATTERN), OPTIMIZE).Find(STRING(STR))); \
+ CHECK(EXPECTED, NPcre::TPcre<CHAR_TYPE>(STRING(PATTERN), OPTIMIZE).Find(STRING(STR), 0, 10));
+
+Y_UNIT_TEST_SUITE(TEST_NAME(TestRegExp)) {
+ Y_UNIT_TEST(TestMatches) {
+ CHECK_MATCHES(true, "ю", "bюd");
+ CHECK_MATCHES(false, "c", "bюd");
+ CHECK_MATCHES(true, "(ю)(?:(b)c|bd)", "zюbda");
+ CHECK_MATCHES(false, "(ю)(?:(b)c|bd)", "bюd");
+ CHECK_MATCHES(true, "(abc|def)=\\g1", "abc=abc");
+ CHECK_MATCHES(true, "(abc|def)=\\g1", "def=def");
+ CHECK_MATCHES(false, "(abc|def)=\\g1", "abc=def");
+ }
+
+ Y_UNIT_TEST(TestGroups) {
+ CHECK_GROUPS("{1,2}", "a", "bad");
+ CHECK_GROUPS("(empty maybe)", "c", "bad");
+ CHECK_GROUPS("{1,4}", "(a)(?:(b)c|bd)", "zabda");
+ CHECK_GROUPS("(empty maybe)", "(a)(?:(b)c|bd)", "bad");
+ CHECK_GROUPS("{1,8}", "(abc|def)=\\g1", "aabc=abca");
+ CHECK_GROUPS("(empty maybe)", "(abc|def)=\\g1", "abc=def");
+ }
+
+ Y_UNIT_TEST(TestCapture) {
+ CHECK("[{1,2}]",NPcre::TPcre<CHAR_TYPE>(STRING("a"), OPTIMIZE).Capture(STRING("bad"), 0, 1));
+ CHECK("[]",NPcre::TPcre<CHAR_TYPE>(STRING("c"), OPTIMIZE).Capture(STRING("bad"), 0, 1));
+ CHECK("[{1,4},{1,2},{-1,-1},{3,4}]",NPcre::TPcre<CHAR_TYPE>(STRING("(a)(?:(b)c|b(d))"), OPTIMIZE).Capture(STRING("zabda"), 0, 1));
+ CHECK("[]",NPcre::TPcre<CHAR_TYPE>(STRING("(a)(?:(b)c|bd)"), OPTIMIZE).Capture(STRING("bad"), 0, 1));
+ }
+}
+
diff --git a/library/cpp/regex/pcre/regexp.cpp b/library/cpp/regex/pcre/regexp.cpp
new file mode 100644
index 0000000000..575c09cee4
--- /dev/null
+++ b/library/cpp/regex/pcre/regexp.cpp
@@ -0,0 +1,317 @@
+#include "regexp.h"
+
+#include <util/generic/string.h>
+#include <util/string/ascii.h>
+#include <util/system/defaults.h>
+
+#include <cstdlib>
+#include <util/generic/noncopyable.h>
+
+class TGlobalImpl : TNonCopyable {
+private:
+ const char* Str;
+ regmatch_t* Pmatch;
+ int Options;
+ int StrLen;
+ int StartOffset, NotEmptyOpts, MatchPos;
+ int MatchBuf[NMATCHES * 3];
+ pcre* PregComp;
+
+ enum StateCode {
+ TGI_EXIT,
+ TGI_CONTINUE,
+ TGI_WALKTHROUGH
+ };
+
+private:
+ void CopyResults(int count) {
+ for (int i = 0; i < count; i++) {
+ Pmatch[MatchPos].rm_so = MatchBuf[2 * i];
+ Pmatch[MatchPos].rm_eo = MatchBuf[2 * i + 1];
+ MatchPos++;
+ if (MatchPos >= NMATCHES) {
+ ythrow yexception() << "TRegExBase::Exec(): Not enough space in internal buffer.";
+ }
+ }
+ }
+
+ int DoPcreExec(int opts) {
+ int rc = pcre_exec(
+ PregComp, /* the compiled pattern */
+ nullptr, /* no extra data - we didn't study the pattern */
+ Str, /* the subject string */
+ StrLen, /* the length of the subject */
+ StartOffset, /* start at offset 0 in the subject */
+ opts, /* default options */
+ MatchBuf, /* output vector for substring information */
+ NMATCHES); /* number of elements in the output vector */
+
+ if (rc == 0) {
+ ythrow yexception() << "TRegExBase::Exec(): Not enough space in internal buffer.";
+ }
+
+ return rc;
+ }
+
+ StateCode CheckEmptyCase() {
+ if (MatchBuf[0] == MatchBuf[1]) { // founded an empty string
+ if (MatchBuf[0] == StrLen) { // at the end
+ return TGI_EXIT;
+ }
+ NotEmptyOpts = PCRE_NOTEMPTY | PCRE_ANCHORED; // trying to find non empty string
+ }
+ return TGI_WALKTHROUGH;
+ }
+
+ StateCode CheckNoMatch(int rc) {
+ if (rc == PCRE_ERROR_NOMATCH) {
+ if (NotEmptyOpts == 0) {
+ return TGI_EXIT;
+ }
+
+ MatchBuf[1] = StartOffset + 1; // we have failed to find non-empty-string. trying to find again shifting "previous match offset"
+ return TGI_CONTINUE;
+ }
+ return TGI_WALKTHROUGH;
+ }
+
+public:
+ TGlobalImpl(const char* st, regmatch_t& pma, int opts, pcre* pc_re)
+ : Str(st)
+ , Pmatch(&pma)
+ , Options(opts)
+ , StartOffset(0)
+ , NotEmptyOpts(0)
+ , MatchPos(0)
+ , PregComp(pc_re)
+ {
+ memset(Pmatch, -1, sizeof(regmatch_t) * NMATCHES);
+ StrLen = strlen(Str);
+ }
+
+ int ExecGlobal() {
+ StartOffset = 0;
+ int rc = DoPcreExec(Options);
+
+ if (rc < 0) {
+ return rc;
+ }
+ CopyResults(rc);
+ do {
+ NotEmptyOpts = 0;
+ StartOffset = MatchBuf[1];
+
+ if (CheckEmptyCase() == TGI_EXIT) {
+ return 0;
+ }
+
+ rc = DoPcreExec(NotEmptyOpts | Options);
+
+ switch (CheckNoMatch(rc)) {
+ case TGI_CONTINUE:
+ continue;
+ case TGI_EXIT:
+ return 0;
+ case TGI_WALKTHROUGH:
+ default:
+ break;
+ }
+
+ if (rc < 0) {
+ return rc;
+ }
+
+ CopyResults(rc);
+ } while (true);
+
+ return 0;
+ }
+
+private:
+};
+
+class TRegExBaseImpl: public TAtomicRefCount<TRegExBaseImpl> {
+ friend class TRegExBase;
+
+protected:
+ int CompileOptions;
+ TString RegExpr;
+ regex_t Preg;
+
+public:
+ TRegExBaseImpl()
+ : CompileOptions(0)
+ {
+ memset(&Preg, 0, sizeof(Preg));
+ }
+
+ TRegExBaseImpl(const TString& re, int cflags)
+ : CompileOptions(cflags)
+ , RegExpr(re)
+ {
+ int rc = regcomp(&Preg, re.data(), cflags);
+ if (rc) {
+ const size_t ERRBUF_SIZE = 100;
+ char errbuf[ERRBUF_SIZE];
+ regerror(rc, &Preg, errbuf, ERRBUF_SIZE);
+ Error = "Error: regular expression " + re + " is wrong: " + errbuf;
+ ythrow yexception() << "RegExp " << re << ": " << Error.data();
+ }
+ }
+
+ int Exec(const char* str, regmatch_t pmatch[], int eflags, int nmatches) const {
+ if (!RegExpr) {
+ ythrow yexception() << "Regular expression is not compiled";
+ }
+ if (!str) {
+ ythrow yexception() << "Empty string is passed to TRegExBaseImpl::Exec";
+ }
+ if ((eflags & REGEXP_GLOBAL) == 0) {
+ return regexec(&Preg, str, nmatches, pmatch, eflags);
+ } else {
+ int options = 0;
+ if ((eflags & REG_NOTBOL) != 0)
+ options |= PCRE_NOTBOL;
+ if ((eflags & REG_NOTEOL) != 0)
+ options |= PCRE_NOTEOL;
+
+ return TGlobalImpl(str, pmatch[0], options, (pcre*)Preg.re_pcre).ExecGlobal();
+ }
+ }
+
+ bool IsCompiled() {
+ return Preg.re_pcre;
+ }
+
+ ~TRegExBaseImpl() {
+ regfree(&Preg);
+ }
+
+private:
+ TString Error;
+};
+
+bool TRegExBase::IsCompiled() const {
+ return Impl && Impl->IsCompiled();
+}
+
+TRegExBase::TRegExBase(const char* re, int cflags) {
+ if (re) {
+ Compile(re, cflags);
+ }
+}
+
+TRegExBase::TRegExBase(const TString& re, int cflags) {
+ Compile(re, cflags);
+}
+
+TRegExBase::~TRegExBase() {
+}
+
+void TRegExBase::Compile(const TString& re, int cflags) {
+ Impl = new TRegExBaseImpl(re, cflags);
+}
+
+int TRegExBase::Exec(const char* str, regmatch_t pmatch[], int eflags, int nmatches) const {
+ if (!Impl)
+ ythrow yexception() << "!Regular expression is not compiled";
+ return Impl->Exec(str, pmatch, eflags, nmatches);
+}
+
+int TRegExBase::GetCompileOptions() const {
+ if (!Impl)
+ ythrow yexception() << "!Regular expression is not compiled";
+ return Impl->CompileOptions;
+}
+
+TString TRegExBase::GetRegExpr() const {
+ if (!Impl)
+ ythrow yexception() << "!Regular expression is not compiled";
+ return Impl->RegExpr;
+}
+
+TRegExMatch::TRegExMatch(const char* re, int cflags)
+ : TRegExBase(re, cflags)
+{
+}
+
+TRegExMatch::TRegExMatch(const TString& re, int cflags)
+ : TRegExBase(re, cflags)
+{
+}
+
+bool TRegExMatch::Match(const char* str) const {
+ return Exec(str, nullptr, 0, 0) == 0;
+}
+
+TRegExSubst::TRegExSubst(const char* re, int cflags)
+ : TRegExBase(re, cflags)
+ , Replacement(nullptr)
+{
+ memset(Brfs, 0, sizeof(TBackReferences) * NMATCHES);
+}
+
+TString TRegExSubst::Replace(const char* str, int eflags) {
+ TString s;
+ if (BrfsCount) {
+ if (Exec(str, PMatch, eflags) == 0) {
+ int i;
+ for (i = 0; i < BrfsCount; i++) {
+ s += TString(Replacement, Brfs[i].Beg, Brfs[i].End - Brfs[i].Beg);
+ if (Brfs[i].Refer >= 0 && Brfs[i].Refer < NMATCHES)
+ s += TString(str, PMatch[Brfs[i].Refer].rm_so, int(PMatch[Brfs[i].Refer].rm_eo - PMatch[Brfs[i].Refer].rm_so));
+ }
+ s += TString(Replacement, Brfs[i].Beg, Brfs[i].End - Brfs[i].Beg);
+ }
+ } else {
+ s = Replacement;
+ }
+ return s;
+}
+
+//***
+// ��� ������������ ������ aaa.$1.$$$$.$2.bbb.$$$ccc Brfs ����� �����:
+// {beg = 0, end = 4, Refer = 1} => "aaa." + $1_match
+// {beg = 6, end = 8, Refer = -1} => ".$"
+// {beg = 9, end = 10, Refer = -1} => "$"
+// {beg = 11, end = 12, Refer = 2} => "." + $2_match
+// {beg = 14, end = 20, Refer = -1} => ".bbb.$"
+// {beg = 21, end = 22, Refer = -1} => "$"
+// {beg = 22, end = 25, Refer = -1} => "ccc"
+// {beg = 0, end = 0, Refer = 0}
+//***
+int TRegExSubst::ParseReplacement(const char* repl) {
+ Replacement = repl;
+ if (!Replacement || *Replacement == 0)
+ return 0;
+ char* pos = (char*)Replacement;
+ char* pos1 = nullptr;
+ char* pos2 = nullptr;
+ int i = 0;
+ while (pos && *pos && i < NMATCHES) {
+ pos1 = strchr(pos, '$');
+ Brfs[i].Refer = -1;
+ pos2 = pos1;
+ if (pos1) {
+ pos2 = pos1 + 1;
+ while (IsAsciiDigit(*pos2))
+ pos2++;
+ if (pos2 > pos1 + 1) {
+ Brfs[i].Refer = atol(TString(Replacement, pos1 + 1 - Replacement, pos2 - (pos1 + 1)).data());
+ } else {
+ pos1++;
+ if (*pos2 == '$')
+ pos2++;
+ Brfs[i].Refer = -1;
+ }
+ }
+ Brfs[i].Beg = int(pos - (char*)Replacement);
+ Brfs[i].End = (pos1 == nullptr ? (int)strlen(Replacement) : int(pos1 - Replacement));
+ pos = pos2;
+ i++;
+ }
+ Brfs[i].Beg = Brfs[i].End = 0;
+ Brfs[i].Refer = -1;
+ BrfsCount = i;
+ return BrfsCount;
+}
diff --git a/library/cpp/regex/pcre/regexp.h b/library/cpp/regex/pcre/regexp.h
new file mode 100644
index 0000000000..bc610bd2f3
--- /dev/null
+++ b/library/cpp/regex/pcre/regexp.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include <sys/types.h>
+
+#include <util/system/defaults.h>
+#include <util/generic/string.h>
+#include <util/generic/yexception.h>
+
+#include <contrib/libs/pcre/pcre.h>
+#include <contrib/libs/pcre/pcreposix.h>
+
+//THIS CODE LOOKS LIKE A TRASH, BUT WORKS.
+
+#define NMATCHES 100
+#define REGEXP_GLOBAL 0x0080 // use this if you want to find all occurences
+
+class TRegExBaseImpl;
+
+class TRegExBase {
+protected:
+ TSimpleIntrusivePtr<TRegExBaseImpl> Impl;
+
+public:
+ TRegExBase(const char* regExpr = nullptr, int cflags = REG_EXTENDED);
+ TRegExBase(const TString& regExpr, int cflags = REG_EXTENDED);
+
+ virtual ~TRegExBase();
+
+ int Exec(const char* str, regmatch_t pmatch[], int eflags, int nmatches = NMATCHES) const;
+ void Compile(const TString& regExpr, int cflags = REG_EXTENDED);
+ bool IsCompiled() const;
+ int GetCompileOptions() const;
+ TString GetRegExpr() const;
+};
+
+class TRegExMatch: public TRegExBase {
+public:
+ TRegExMatch(const char* regExpr = nullptr, int cflags = REG_NOSUB | REG_EXTENDED);
+ TRegExMatch(const TString& regExpr, int cflags = REG_NOSUB | REG_EXTENDED);
+
+ bool Match(const char* str) const;
+};
+
+struct TBackReferences {
+ int Beg;
+ int End;
+ int Refer;
+};
+
+class TRegExSubst: public TRegExBase {
+private:
+ const char* Replacement;
+ regmatch_t PMatch[NMATCHES];
+
+ TBackReferences Brfs[NMATCHES];
+ int BrfsCount;
+
+public:
+ TRegExSubst(const char* regExpr = nullptr, int cflags = REG_EXTENDED);
+
+ TString Replace(const char* str, int eflags = 0);
+ int ParseReplacement(const char* replacement);
+};
diff --git a/library/cpp/regex/pcre/regexp_ut.cpp b/library/cpp/regex/pcre/regexp_ut.cpp
new file mode 100644
index 0000000000..5184e801cc
--- /dev/null
+++ b/library/cpp/regex/pcre/regexp_ut.cpp
@@ -0,0 +1,103 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/string/strip.h>
+#include <library/cpp/regex/pcre/regexp.h>
+#include <util/stream/output.h>
+
+struct TRegTest {
+ const char* Regexp;
+ const char* Data;
+ const char* Result;
+ int CompileOptions;
+ int RunOptions;
+
+ TRegTest(const char* re, const char* text, const char* res, int copts = REG_EXTENDED, int ropts = 0)
+ : Regexp(re)
+ , Data(text)
+ , Result(res)
+ , CompileOptions(copts)
+ , RunOptions(ropts)
+ {
+ }
+};
+
+struct TSubstTest: public TRegTest {
+ const char* Replacement;
+ const char* Replacement2;
+
+ TSubstTest(const char* re, const char* text, const char* res, const char* repl, const char* repl2)
+ : TRegTest(re, text, res, REG_EXTENDED, REGEXP_GLOBAL)
+ , Replacement(repl)
+ , Replacement2(repl2)
+ {
+ }
+};
+
+const TRegTest REGTEST_DATA[] = {
+ TRegTest("test", "its a test and test string.", "6 10", REG_EXTENDED, 0),
+ TRegTest("test", "its a test and test string.", "6 10 15 19", REG_EXTENDED, REGEXP_GLOBAL),
+ TRegTest("test|[an]{0,0}", "test and test an test string tes", "0 4 4 4 5 5 6 6 7 7 8 8 9 13 13 13 14 14 15 15 16 16 17 21 21 21 22 22 23 23 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 31 32 32", REG_EXTENDED, REGEXP_GLOBAL),
+ TRegTest("test[an]{1,}", "test and test an test string tes", "NM", REG_EXTENDED, REGEXP_GLOBAL)};
+
+const TSubstTest SUBSTTEST_DATA[] = {
+ TSubstTest("([a-zA-Z]*[0-9]+) (_[a-z]+)", "Xxx123 534 ___124 bsd _A ZXC _L 141 _sd dsfg QWE123 _bbb", "141 XXX/_sd", "$1 XXX/$2", "$2$2$2 YY$1Y/$2")};
+
+class TRegexpTest: public TTestBase {
+private:
+ regmatch_t Matches[NMATCHES];
+
+private:
+ UNIT_TEST_SUITE(TRegexpTest);
+ UNIT_TEST(TestRe)
+ UNIT_TEST(TestSubst)
+ UNIT_TEST(TestOffEndOfBuffer);
+ UNIT_TEST_SUITE_END();
+
+ inline void TestRe() {
+ for (const auto& regTest : REGTEST_DATA) {
+ memset(Matches, 0, sizeof(Matches));
+ TString result;
+
+ TRegExBase re(regTest.Regexp, regTest.CompileOptions);
+ if (re.Exec(regTest.Data, Matches, regTest.RunOptions) == 0) {
+ for (auto& matche : Matches) {
+ if (matche.rm_so == -1) {
+ break;
+ }
+ result.append(Sprintf("%i %i ", matche.rm_so, matche.rm_eo));
+ }
+ } else {
+ result = "NM";
+ }
+ StripInPlace(result);
+ UNIT_ASSERT_VALUES_EQUAL(result, regTest.Result);
+ }
+ }
+
+ inline void TestSubst() {
+ for (const auto& substTest : SUBSTTEST_DATA) {
+ TRegExSubst subst(substTest.Regexp, substTest.CompileOptions);
+ subst.ParseReplacement(substTest.Replacement);
+ TString result = subst.Replace(substTest.Data, substTest.RunOptions);
+ UNIT_ASSERT_VALUES_EQUAL(result, substTest.Result);
+ TRegExSubst substCopy = subst;
+ subst.ParseReplacement(substTest.Replacement2);
+ TString newResult = subst.Replace(substTest.Data, substTest.RunOptions);
+ UNIT_ASSERT_VALUES_UNEQUAL(newResult.c_str(), result.c_str());
+ TString copyResult = substCopy.Replace(substTest.Data, substTest.RunOptions);
+ UNIT_ASSERT_VALUES_EQUAL(copyResult, result);
+ substCopy = subst;
+ copyResult = substCopy.Replace(substTest.Data, substTest.RunOptions);
+ UNIT_ASSERT_VALUES_EQUAL(copyResult, newResult);
+ }
+ }
+
+ void TestOffEndOfBuffer() {
+ const TString needle{".*[^./]gov[.].*"};
+ TRegExMatch re{needle, REG_UTF8};
+ const TString haystack{"fakty.ictv.ua"};
+ UNIT_ASSERT_VALUES_EQUAL(re.Match(haystack.c_str()), false);
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TRegexpTest);
diff --git a/library/cpp/regex/pcre/traits.h b/library/cpp/regex/pcre/traits.h
new file mode 100644
index 0000000000..e926bdd758
--- /dev/null
+++ b/library/cpp/regex/pcre/traits.h
@@ -0,0 +1,99 @@
+#pragma once
+
+#include <contrib/libs/pcre/pcre.h>
+
+#include <util/generic/ptr.h> // THolder
+#include <util/system/types.h> // wchar16, wchar32
+
+namespace NPcre {
+ template <class TCharType>
+ struct TPcreTraits;
+
+ template <>
+ struct TPcreTraits<char> {
+ using TCharType = char;
+ using TStringType = const char*;
+ using TCodeType = pcre;
+ using TExtraType = pcre_extra;
+ static constexpr TCodeType* (*Compile)(TStringType pattern, int options, int* errcodeptr, const char** errptr, int* erroffset, const unsigned char* tableptr) = pcre_compile2;
+ static constexpr TExtraType* (*Study)(const TCodeType* pattern, int options, const char** errptr) = pcre_study;
+ static constexpr int (*Exec)(const TCodeType* code, const TExtraType* extra, TStringType str, int length, int startoffset, int options, int* ovector, int ovecsize) = pcre_exec;
+ };
+
+ template <>
+ struct TPcreTraits<wchar16> {
+ using TCharType = wchar16;
+ using TStringType = PCRE_SPTR16;
+ using TCodeType = pcre16;
+ using TExtraType = pcre16_extra;
+ static constexpr TCodeType* (*Compile)(TStringType pattern, int options, int* errcodeptr, const char** errptr, int* erroffset, const unsigned char* tableptr) = pcre16_compile2;
+ static constexpr TExtraType* (*Study)(const TCodeType* pattern, int options, const char** errptr) = pcre16_study;
+ static constexpr int (*Exec)(const TCodeType* code, const TExtraType* extra, TStringType str, int length, int startoffset, int options, int* ovector, int ovecsize) = pcre16_exec;
+ };
+
+ template <>
+ struct TPcreTraits<wchar32> {
+ using TCharType = wchar32;
+ using TStringType = PCRE_SPTR32;
+ using TCodeType = pcre32;
+ using TExtraType = pcre32_extra;
+ static constexpr TCodeType* (*Compile)(TStringType pattern, int options, int* errcodeptr, const char** errptr, int* erroffset, const unsigned char* tableptr) = pcre32_compile2;
+ static constexpr TExtraType* (*Study)(const TCodeType* pattern, int options, const char** errptr) = pcre32_study;
+ static constexpr int (*Exec)(const TCodeType* code, const TExtraType* extra, TStringType str, int length, int startoffset, int options, int* ovector, int ovecsize) = pcre32_exec;
+ };
+
+ template <class TCharType>
+ struct TFreePcre;
+
+ template <>
+ struct TFreePcre<char> {
+ static inline void Destroy(void* ptr) noexcept {
+ pcre_free(ptr);
+ }
+ };
+
+ template <>
+ struct TFreePcre<wchar16> {
+ static inline void Destroy(void* ptr) noexcept {
+ pcre16_free(ptr);
+ }
+ };
+
+ template <>
+ struct TFreePcre<wchar32> {
+ static inline void Destroy(void* ptr) noexcept {
+ pcre32_free(ptr);
+ }
+ };
+
+ template <class TCharType>
+ struct TFreePcreExtra;
+
+ template <>
+ struct TFreePcreExtra<char> {
+ static inline void Destroy(pcre_extra* ptr) noexcept {
+ pcre_free_study(ptr);
+ }
+ };
+
+ template <>
+ struct TFreePcreExtra<wchar16> {
+ static inline void Destroy(pcre16_extra* ptr) noexcept {
+ pcre16_free_study(ptr);
+ }
+ };
+
+ template <>
+ struct TFreePcreExtra<wchar32> {
+ static inline void Destroy(pcre32_extra* ptr) noexcept {
+ pcre32_free_study(ptr);
+ }
+ };
+
+ template <typename TCharType>
+ using TPcreCode = THolder<typename TPcreTraits<TCharType>::TCodeType, TFreePcre<TCharType>>;
+
+ template <typename TCharType>
+ using TPcreExtra = THolder<typename TPcreTraits<TCharType>::TExtraType, TFreePcreExtra<TCharType>>;
+}
+
diff --git a/library/cpp/regex/pcre/ut/ya.make b/library/cpp/regex/pcre/ut/ya.make
new file mode 100644
index 0000000000..0721ef87c2
--- /dev/null
+++ b/library/cpp/regex/pcre/ut/ya.make
@@ -0,0 +1,10 @@
+UNITTEST_FOR(library/cpp/regex/pcre)
+
+OWNER(g:util)
+
+SRCS(
+ pcre_ut.cpp
+ regexp_ut.cpp
+)
+
+END()
diff --git a/library/cpp/regex/pcre/ya.make b/library/cpp/regex/pcre/ya.make
new file mode 100644
index 0000000000..d34911f103
--- /dev/null
+++ b/library/cpp/regex/pcre/ya.make
@@ -0,0 +1,23 @@
+LIBRARY()
+
+OWNER(g:util)
+
+PEERDIR(
+ contrib/libs/pcre
+ contrib/libs/pcre/pcre16
+ contrib/libs/pcre/pcre32
+ library/cpp/containers/stack_array
+)
+
+SRCS(
+ pcre.cpp
+ regexp.cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ benchmark
+ ut
+)
+
diff --git a/library/cpp/regex/pire/extraencodings.cpp b/library/cpp/regex/pire/extraencodings.cpp
new file mode 100644
index 0000000000..2e507e4b67
--- /dev/null
+++ b/library/cpp/regex/pire/extraencodings.cpp
@@ -0,0 +1,81 @@
+#include <util/system/defaults.h>
+#include <util/system/yassert.h>
+#include <library/cpp/charset/codepage.h>
+#include <util/generic/singleton.h>
+#include <util/generic/yexception.h>
+#include <library/cpp/charset/doccodes.h>
+
+#include "pire.h"
+
+namespace NPire {
+ namespace {
+ // A one-byte encoding which is capable of transforming upper half of the character
+ // table to/from Unicode chars.
+ class TOneByte: public TEncoding {
+ public:
+ TOneByte(ECharset doccode) {
+ Table_ = CodePageByCharset(doccode)->unicode;
+ for (size_t i = 0; i < 256; ++i)
+ Reverse_.insert(std::make_pair(Table_[i], static_cast<char>(i)));
+ }
+
+ wchar32 FromLocal(const char*& begin, const char* end) const override {
+ if (begin != end)
+ return Table_[static_cast<unsigned char>(*begin++)];
+ else
+ ythrow yexception() << "EOF reached in Pire::OneByte::fromLocal()";
+ }
+
+ TString ToLocal(wchar32 c) const override {
+ THashMap<wchar32, char>::const_iterator i = Reverse_.find(c);
+ if (i != Reverse_.end())
+ return TString(1, i->second);
+ else
+ return TString();
+ }
+
+ void AppendDot(TFsm& fsm) const override {
+ fsm.AppendDot();
+ }
+
+ private:
+ const wchar32* Table_;
+ THashMap<wchar32, char> Reverse_;
+ };
+
+ template <unsigned N>
+ struct TOneByteHelper: public TOneByte {
+ inline TOneByteHelper()
+ : TOneByte((ECharset)N)
+ {
+ }
+ };
+ }
+
+ namespace NEncodings {
+ const NPire::TEncoding& Koi8r() {
+ return *Singleton<TOneByteHelper<CODES_KOI8>>();
+ }
+
+ const NPire::TEncoding& Cp1251() {
+ return *Singleton<TOneByteHelper<CODES_WIN>>();
+ }
+
+ const NPire::TEncoding& Get(ECharset encoding) {
+ switch (encoding) {
+ case CODES_WIN:
+ return Cp1251();
+ case CODES_KOI8:
+ return Koi8r();
+ case CODES_ASCII:
+ return NPire::NEncodings::Latin1();
+ case CODES_UTF8:
+ return NPire::NEncodings::Utf8();
+ default:
+ ythrow yexception() << "Pire::Encodings::get(ECharset): unknown encoding " << (int)encoding;
+ }
+ }
+
+ }
+
+}
diff --git a/library/cpp/regex/pire/inline/ya.make b/library/cpp/regex/pire/inline/ya.make
new file mode 100644
index 0000000000..d4850f7b45
--- /dev/null
+++ b/library/cpp/regex/pire/inline/ya.make
@@ -0,0 +1,22 @@
+PROGRAM(pire_inline)
+
+CFLAGS(-DPIRE_NO_CONFIG)
+
+OWNER(
+ g:util
+ davenger
+)
+
+PEERDIR(
+ ADDINCL library/cpp/regex/pire
+)
+
+SRCDIR(
+ contrib/libs/pire/pire
+)
+
+SRCS(
+ inline.l
+)
+
+END()
diff --git a/library/cpp/regex/pire/pcre2pire.cpp b/library/cpp/regex/pire/pcre2pire.cpp
new file mode 100644
index 0000000000..f788beb85f
--- /dev/null
+++ b/library/cpp/regex/pire/pcre2pire.cpp
@@ -0,0 +1,110 @@
+#include "pcre2pire.h"
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+TString Pcre2Pire(const TString& src) {
+ TVector<char> result;
+ result.reserve(src.size() + 1);
+
+ enum EState {
+ S_SIMPLE,
+ S_SLASH,
+ S_BRACE,
+ S_EXPECT_Q,
+ S_QUESTION,
+ S_P,
+ S_COMMA,
+ S_IN,
+ };
+
+ EState state = S_SIMPLE;
+
+ for (ui32 i = 0; i < src.size(); ++i) {
+ const char c = src[i];
+
+ switch (state) {
+ case S_SIMPLE:
+ if (c == '\\') {
+ state = S_SLASH;
+ } else if (c == '(') {
+ state = S_BRACE;
+ } else if (c == '*' || c == '?') {
+ state = S_EXPECT_Q;
+ result.push_back(c);
+ } else {
+ if (c == ')' && result.size() > 0 && result.back() == '(') {
+ // eliminating "()"
+ result.pop_back();
+ } else {
+ result.push_back(c);
+ }
+ }
+ break;
+ case S_SLASH:
+ state = S_SIMPLE;
+ if (c == ':' || c == '=' || c == '#' || c == '&') {
+ result.push_back(c);
+ } else {
+ result.push_back('\\');
+ --i;
+ }
+ break;
+ case S_BRACE:
+ if (c == '?') {
+ state = S_QUESTION;
+ } else {
+ state = S_COMMA;
+ --i;
+ }
+ break;
+ case S_EXPECT_Q:
+ state = S_SIMPLE;
+ if (c != '?') {
+ --i;
+ }
+ break;
+ case S_QUESTION:
+ if (c == 'P') {
+ state = S_P;
+ } else if (c == ':' || c == '=') {
+ state = S_COMMA;
+ } else {
+ ythrow yexception() << "Pcre to pire convertaion failed: unexpected symbol '" << c << "' at posiotion " << i << "!";
+ }
+ break;
+ case S_P:
+ if (c == '<') {
+ state = S_IN;
+ } else {
+ ythrow yexception() << "Pcre to pire convertaion failed: unexpected symbol '" << c << "' at posiotion " << i << "!";
+ }
+ break;
+ case S_IN:
+ if (c == '>') {
+ state = S_COMMA;
+ } else {
+ // nothing to do
+ }
+ break;
+ case S_COMMA:
+ state = S_SIMPLE;
+ if (c == ')') {
+ // nothing to do
+ } else {
+ result.push_back('(');
+ --i;
+ }
+ break;
+ default:
+ ythrow yexception() << "Pcre to pire convertaion failed: unexpected automata state!";
+ }
+ }
+
+ if (state != S_SIMPLE && state != S_EXPECT_Q) {
+ ythrow yexception() << "Pcre to pire convertaion failed: unexpected end of expression!";
+ }
+
+ result.push_back('\0');
+
+ return &result[0];
+}
diff --git a/library/cpp/regex/pire/pcre2pire.h b/library/cpp/regex/pire/pcre2pire.h
new file mode 100644
index 0000000000..46e45b9193
--- /dev/null
+++ b/library/cpp/regex/pire/pcre2pire.h
@@ -0,0 +1,19 @@
+#pragma once
+
+// Author: smikler@yandex-team.ru
+
+#include <util/generic/string.h>
+
+/* Converts pcre regular expression to pire compatible format:
+ * - replaces "\\#" with "#"
+ * - replaces "\\=" with "="
+ * - replaces "\\:" with ":"
+ * - removes "?P<...>"
+ * - removes "?:"
+ * - removes "()" recursively
+ * - replaces "??" with "?"
+ * - replaces "*?" with "*"
+ * NOTE:
+ * - Not fully tested!
+ */
+TString Pcre2Pire(const TString& src);
diff --git a/library/cpp/regex/pire/pire.h b/library/cpp/regex/pire/pire.h
new file mode 100644
index 0000000000..286fecd693
--- /dev/null
+++ b/library/cpp/regex/pire/pire.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#ifndef PIRE_NO_CONFIG
+#define PIRE_NO_CONFIG
+#endif
+
+#include <contrib/libs/pire/pire/pire.h>
+#include <contrib/libs/pire/pire/extra.h>
+
+#include <library/cpp/charset/doccodes.h>
+
+namespace NPire {
+ using TChar = Pire::Char;
+ using Pire::MaxChar;
+
+ // Scanner classes
+ using TScanner = Pire::Scanner;
+ using TNonrelocScanner = Pire::NonrelocScanner;
+ using TScannerNoMask = Pire::ScannerNoMask;
+ using TNonrelocScannerNoMask = Pire::NonrelocScannerNoMask;
+ using THalfFinalScanner = Pire::HalfFinalScanner;
+ using TNonrelocHalfFinalScanner = Pire::NonrelocHalfFinalScanner;
+ using THalfFinalScannerNoMask = Pire::HalfFinalScannerNoMask;
+ using TNonrelocHalfFinalScannerNoMask = Pire::NonrelocHalfFinalScannerNoMask;
+ using TSimpleScanner = Pire::SimpleScanner;
+ using TSlowScanner = Pire::SlowScanner;
+ using TCapturingScanner = Pire::CapturingScanner;
+ using TSlowCapturingScanner = Pire::SlowCapturingScanner;
+ using TCountingScanner = Pire::CountingScanner;
+
+ template <typename T1, typename T2>
+ using TScannerPair = Pire::ScannerPair<T1, T2>;
+
+ // Helper classes
+ using TFsm = Pire::Fsm;
+ using TLexer = Pire::Lexer;
+ using TTerm = Pire::Term;
+ using TEncoding = Pire::Encoding;
+ using TFeature = Pire::Feature;
+ using TFeaturePtr = Pire::Feature::Ptr;
+ using TError = Pire::Error;
+
+ // Helper functions
+ using Pire::LongestPrefix;
+ using Pire::LongestSuffix;
+ using Pire::Matches;
+ using Pire::MmappedScanner;
+ using Pire::Run;
+ using Pire::Runner;
+ using Pire::ShortestPrefix;
+ using Pire::ShortestSuffix;
+ using Pire::Step;
+
+ using namespace Pire::SpecialChar;
+ using namespace Pire::Consts;
+
+ namespace NFeatures {
+ using Pire::Features::AndNotSupport;
+ using Pire::Features::Capture;
+ using Pire::Features::CaseInsensitive;
+ using Pire::Features::GlueSimilarGlyphs;
+ }
+
+ namespace NEncodings {
+ using Pire::Encodings::Latin1;
+ using Pire::Encodings::Utf8;
+
+ const NPire::TEncoding& Koi8r();
+ const NPire::TEncoding& Cp1251();
+ const NPire::TEncoding& Get(ECharset encoding);
+ }
+
+ namespace NTokenTypes {
+ using namespace Pire::TokenTypes;
+ }
+}
diff --git a/library/cpp/regex/pire/regexp.h b/library/cpp/regex/pire/regexp.h
new file mode 100644
index 0000000000..94bba4064b
--- /dev/null
+++ b/library/cpp/regex/pire/regexp.h
@@ -0,0 +1,337 @@
+#pragma once
+
+#include "pire.h"
+
+#include <library/cpp/charset/doccodes.h>
+#include <library/cpp/charset/recyr.hh>
+#include <util/generic/maybe.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+namespace NRegExp {
+ struct TMatcher;
+
+ struct TFsmBase {
+ struct TOptions {
+ inline TOptions& SetCaseInsensitive(bool v) noexcept {
+ CaseInsensitive = v;
+ return *this;
+ }
+
+ inline TOptions& SetSurround(bool v) noexcept {
+ Surround = v;
+ return *this;
+ }
+
+ inline TOptions& SetCapture(size_t pos) noexcept {
+ CapturePos = pos;
+ return *this;
+ }
+
+ inline TOptions& SetCharset(ECharset charset) noexcept {
+ Charset = charset;
+ return *this;
+ }
+
+ inline TOptions& SetAndNotSupport(bool andNotSupport) noexcept {
+ AndNotSupport = andNotSupport;
+ return *this;
+ }
+
+ bool CaseInsensitive = false;
+ bool Surround = false;
+ TMaybe<size_t> CapturePos;
+ ECharset Charset = CODES_UNKNOWN;
+ bool AndNotSupport = false;
+ };
+
+ static inline NPire::TFsm Parse(const TStringBuf& regexp,
+ const TOptions& opts, const bool needDetermine = true) {
+ NPire::TLexer lexer;
+ if (opts.Charset == CODES_UNKNOWN) {
+ lexer.Assign(regexp.data(), regexp.data() + regexp.size());
+ } else {
+ TVector<wchar32> ucs4(regexp.size() + 1);
+ size_t inRead = 0;
+ size_t outWritten = 0;
+ int recodeRes = RecodeToUnicode(opts.Charset, regexp.data(), ucs4.data(),
+ regexp.size(), regexp.size(), inRead, outWritten);
+ Y_ASSERT(recodeRes == RECODE_OK);
+ Y_ASSERT(outWritten < ucs4.size());
+ ucs4[outWritten] = 0;
+
+ lexer.Assign(ucs4.begin(),
+ ucs4.begin() + std::char_traits<wchar32>::length(ucs4.data()));
+ }
+
+ if (opts.CaseInsensitive) {
+ lexer.AddFeature(NPire::NFeatures::CaseInsensitive());
+ }
+
+ if (opts.CapturePos) {
+ lexer.AddFeature(NPire::NFeatures::Capture(*opts.CapturePos));
+ }
+
+ if (opts.AndNotSupport) {
+ lexer.AddFeature(NPire::NFeatures::AndNotSupport());
+ }
+
+ switch (opts.Charset) {
+ case CODES_UNKNOWN:
+ break;
+ case CODES_UTF8:
+ lexer.SetEncoding(NPire::NEncodings::Utf8());
+ break;
+ case CODES_KOI8:
+ lexer.SetEncoding(NPire::NEncodings::Koi8r());
+ break;
+ default:
+ lexer.SetEncoding(NPire::NEncodings::Get(opts.Charset));
+ break;
+ }
+
+ NPire::TFsm ret = lexer.Parse();
+
+ if (opts.Surround) {
+ ret.Surround();
+ }
+
+ if (needDetermine) {
+ ret.Determine();
+ }
+
+ return ret;
+ }
+ };
+
+ template <class TScannerType>
+ class TFsmParser: public TFsmBase {
+ public:
+ typedef TScannerType TScanner;
+
+ public:
+ inline explicit TFsmParser(const TStringBuf& regexp,
+ const TOptions& opts = TOptions(), bool needDetermine = true)
+ : Scanner(Parse(regexp, opts, needDetermine).template Compile<TScanner>())
+ {
+ }
+
+ inline const TScanner& GetScanner() const noexcept {
+ return Scanner;
+ }
+
+ static inline TFsmParser False() {
+ return TFsmParser(NPire::TFsm::MakeFalse().Compile<TScanner>());
+ }
+
+ inline explicit TFsmParser(const TScanner& compiled)
+ : Scanner(compiled)
+ {
+ if (Scanner.Empty())
+ ythrow yexception() << "Can't create fsm with empty scanner";
+ }
+
+ private:
+ TScanner Scanner;
+ };
+
+ class TFsm: public TFsmParser<NPire::TNonrelocScanner> {
+ public:
+ inline explicit TFsm(const TStringBuf& regexp,
+ const TOptions& opts = TOptions())
+ : TFsmParser<TScanner>(regexp, opts)
+ {
+ }
+
+ inline TFsm(const TFsmParser<TScanner>& fsm)
+ : TFsmParser<TScanner>(fsm)
+ {
+ }
+
+ static inline TFsm Glue(const TFsm& l, const TFsm& r) {
+ return TFsm(TScanner::Glue(l.GetScanner(), r.GetScanner()));
+ }
+
+ inline explicit TFsm(const TScanner& compiled)
+ : TFsmParser<TScanner>(compiled)
+ {
+ }
+ };
+
+ static inline TFsm operator|(const TFsm& l, const TFsm& r) {
+ return TFsm::Glue(l, r);
+ }
+
+ struct TCapturingFsm : TFsmParser<NPire::TCapturingScanner> {
+ inline explicit TCapturingFsm(const TStringBuf& regexp,
+ TOptions opts = TOptions())
+ : TFsmParser<TScanner>(regexp,
+ opts.SetSurround(true).CapturePos ? opts : opts.SetCapture(1)) {
+ }
+
+ inline TCapturingFsm(const TFsmParser<TScanner>& fsm)
+ : TFsmParser<TScanner>(fsm)
+ {
+ }
+ };
+
+ struct TSlowCapturingFsm : TFsmParser<NPire::TSlowCapturingScanner> {
+ inline explicit TSlowCapturingFsm(const TStringBuf& regexp,
+ TOptions opts = TOptions())
+ : TFsmParser<TScanner>(regexp,
+ opts.SetSurround(true).CapturePos ? opts : opts.SetCapture(1), false) {
+ }
+
+ inline TSlowCapturingFsm(const TFsmParser<TScanner>& fsm)
+ : TFsmParser<TScanner>(fsm)
+ {
+ }
+ };
+
+ template <class TFsm>
+ class TMatcherBase {
+ public:
+ typedef typename TFsm::TScanner::State TState;
+
+ public:
+ inline explicit TMatcherBase(const TFsm& fsm)
+ : Fsm(fsm)
+ {
+ Fsm.GetScanner().Initialize(State);
+ }
+
+ inline bool Final() const noexcept {
+ return GetScanner().Final(GetState());
+ }
+
+ protected:
+ inline void Run(const char* data, size_t len, bool addBegin, bool addEnd) noexcept {
+ if (addBegin) {
+ NPire::Step(GetScanner(), State, NPire::BeginMark);
+ }
+ NPire::Run(GetScanner(), State, data, data + len);
+ if (addEnd) {
+ NPire::Step(GetScanner(), State, NPire::EndMark);
+ }
+ }
+
+ inline const typename TFsm::TScanner& GetScanner() const noexcept {
+ return Fsm.GetScanner();
+ }
+
+ inline const TState& GetState() const noexcept {
+ return State;
+ }
+
+ private:
+ const TFsm& Fsm;
+ TState State;
+ };
+
+ struct TMatcher : TMatcherBase<TFsm> {
+ inline explicit TMatcher(const TFsm& fsm)
+ : TMatcherBase<TFsm>(fsm)
+ {
+ }
+
+ inline TMatcher& Match(const char* data, size_t len, bool addBegin = false, bool addEnd = false) noexcept {
+ Run(data, len, addBegin, addEnd);
+ return *this;
+ }
+
+ inline TMatcher& Match(const TStringBuf& s, bool addBegin = false, bool addEnd = false) noexcept {
+ return Match(s.data(), s.size(), addBegin, addEnd);
+ }
+
+ inline const char* Find(const char* b, const char* e) noexcept {
+ return NPire::ShortestPrefix(GetScanner(), b, e);
+ }
+
+ typedef std::pair<const size_t*, const size_t*> TMatchedRegexps;
+
+ inline TMatchedRegexps MatchedRegexps() const noexcept {
+ return GetScanner().AcceptedRegexps(GetState());
+ }
+ };
+
+ class TSearcher: public TMatcherBase<TCapturingFsm> {
+ public:
+ inline explicit TSearcher(const TCapturingFsm& fsm)
+ : TMatcherBase<TCapturingFsm>(fsm)
+ {
+ }
+
+ inline bool Captured() const noexcept {
+ return GetState().Captured();
+ }
+
+ inline TSearcher& Search(const char* data, size_t len, bool addBegin = true, bool addEnd = true) noexcept {
+ Data = TStringBuf(data, len);
+ Run(data, len, addBegin, addEnd);
+ return *this;
+ }
+
+ inline TSearcher& Search(const TStringBuf& s) noexcept {
+ return Search(s.data(), s.size());
+ }
+
+ inline TStringBuf GetCaptured() const noexcept {
+ return TStringBuf(Data.data() + GetState().Begin() - 1,
+ Data.data() + GetState().End() - 1);
+ }
+
+ private:
+ TStringBuf Data;
+ };
+
+ class TSlowSearcher : TMatcherBase<TSlowCapturingFsm>{
+ public:
+ typedef typename TSlowCapturingFsm::TScanner::State TState;
+ inline explicit TSlowSearcher(const TSlowCapturingFsm& fsm)
+ : TMatcherBase<TSlowCapturingFsm>(fsm)
+ , HasCaptured(false)
+ {
+ }
+
+ inline bool Captured() const noexcept {
+ return HasCaptured;
+ }
+
+ inline TSlowSearcher& Search(const char* data, size_t len, bool addBegin = false, bool addEnd = false) noexcept {
+ TStringBuf textData(data, len);
+ Data = textData;
+ Run(Data.begin(), Data.size(), addBegin, addEnd);
+ return GetAns();
+ }
+
+ inline TSlowSearcher& Search(const TStringBuf& s) noexcept {
+ return Search(s.data(), s.size());
+ }
+
+ inline TStringBuf GetCaptured() const noexcept {
+ return Ans;
+ }
+
+ private:
+ TStringBuf Data;
+ TStringBuf Ans;
+ bool HasCaptured;
+
+ inline TSlowSearcher& GetAns() {
+ auto state = GetState();
+ Pire::SlowCapturingScanner::SingleState final;
+ if (!GetScanner().GetCapture(state, final)) {
+ HasCaptured = false;
+ } else {
+ if (!final.HasEnd()) {
+ final.SetEnd(Data.size());
+ }
+ Ans = TStringBuf(Data, final.GetBegin(), final.GetEnd() - final.GetBegin());
+ HasCaptured = true;
+ }
+ return *this;
+ }
+ };
+}
diff --git a/library/cpp/regex/pire/ut/regexp_ut.cpp b/library/cpp/regex/pire/ut/regexp_ut.cpp
new file mode 100644
index 0000000000..e7206de9ad
--- /dev/null
+++ b/library/cpp/regex/pire/ut/regexp_ut.cpp
@@ -0,0 +1,318 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/regex/pire/regexp.h>
+#include <library/cpp/regex/pire/pcre2pire.h>
+
+Y_UNIT_TEST_SUITE(TRegExp) {
+ using namespace NRegExp;
+
+ Y_UNIT_TEST(False) {
+ UNIT_ASSERT(!TMatcher(TFsm::False()).Match("").Final());
+ UNIT_ASSERT(!TMatcher(TFsm::False()).Match(TStringBuf{}).Final());
+ }
+
+ Y_UNIT_TEST(Surround) {
+ UNIT_ASSERT(TMatcher(TFsm("qw", TFsm::TOptions().SetSurround(true))).Match("aqwb").Final());
+ UNIT_ASSERT(!TMatcher(TFsm("qw", TFsm::TOptions().SetSurround(false))).Match("aqwb").Final());
+ }
+
+ Y_UNIT_TEST(Boundaries) {
+ UNIT_ASSERT(!TMatcher(TFsm("qwb$", TFsm::TOptions().SetSurround(true))).Match("aqwb").Final());
+ UNIT_ASSERT(!TMatcher(TFsm("^aqw", TFsm::TOptions().SetSurround(true))).Match("aqwb").Final());
+ UNIT_ASSERT(TMatcher(TFsm("qwb$", TFsm::TOptions().SetSurround(true))).Match(TStringBuf("aqwb"), true, true).Final());
+ UNIT_ASSERT(TMatcher(TFsm("^aqw", TFsm::TOptions().SetSurround(true))).Match(TStringBuf("aqwb"), true, true).Final());
+ UNIT_ASSERT(!TMatcher(TFsm("qw$", TFsm::TOptions().SetSurround(true))).Match(TStringBuf("aqwb"), true, true).Final());
+ UNIT_ASSERT(!TMatcher(TFsm("^qw", TFsm::TOptions().SetSurround(true))).Match(TStringBuf("aqwb"), true, true).Final());
+
+ UNIT_ASSERT(TMatcher(TFsm("^aqwb$", TFsm::TOptions().SetSurround(true)))
+ .Match(TStringBuf("a"), true, false)
+ .Match(TStringBuf("q"), false, false)
+ .Match(TStringBuf("w"), false, false)
+ .Match(TStringBuf("b"), false, true)
+ .Final());
+ }
+
+ Y_UNIT_TEST(Case) {
+ UNIT_ASSERT(TMatcher(TFsm("qw", TFsm::TOptions().SetCaseInsensitive(true))).Match("Qw").Final());
+ UNIT_ASSERT(!TMatcher(TFsm("qw", TFsm::TOptions().SetCaseInsensitive(false))).Match("Qw").Final());
+ }
+
+ Y_UNIT_TEST(UnicodeCase) {
+ UNIT_ASSERT(TMatcher(TFsm("\\x{61}\\x{62}", TFsm::TOptions().SetCaseInsensitive(true))).Match("Ab").Final());
+ UNIT_ASSERT(!TMatcher(TFsm("\\x{61}\\x{62}", TFsm::TOptions().SetCaseInsensitive(false))).Match("Ab").Final());
+ }
+
+ Y_UNIT_TEST(Utf) {
+ NRegExp::TFsmBase::TOptions opts;
+ opts.Charset = CODES_UTF8;
+ opts.Surround = true;
+ UNIT_ASSERT(TMatcher(TFsm(".*", opts)).Match("wtf").Final());
+ UNIT_ASSERT(TMatcher(TFsm(".*", opts)).Match("чзн").Final());
+ UNIT_ASSERT(TMatcher(TFsm("ч.*", opts)).Match("чзн").Final());
+ UNIT_ASSERT(!TMatcher(TFsm("чзн", opts)).Match("чзх").Final());
+ }
+
+ Y_UNIT_TEST(AndNot) {
+ NRegExp::TFsmBase::TOptions opts;
+ opts.AndNotSupport = true;
+ {
+ NRegExp::TFsm fsm(".*&~([0-9]*)", opts);
+ UNIT_ASSERT(TMatcher(fsm).Match("a2").Final());
+ UNIT_ASSERT(TMatcher(fsm).Match("ab").Final());
+ UNIT_ASSERT(TMatcher(fsm).Match("1a").Final());
+ UNIT_ASSERT(!TMatcher(fsm).Match("12").Final());
+ }
+ {
+ NRegExp::TFsm fsm(".*&~(.*[0-9].*)", opts);
+ UNIT_ASSERT(TMatcher(fsm).Match("ab").Final());
+ UNIT_ASSERT(!TMatcher(fsm).Match("a2").Final());
+ UNIT_ASSERT(!TMatcher(fsm).Match("1a").Final());
+ UNIT_ASSERT(!TMatcher(fsm).Match("12").Final());
+ }
+ {
+ NRegExp::TFsm fsm(
+ "((([a-z0-9_\\-]+[.])*[a-z0-9_\\-]+)"
+ "&~(\\d+[.]\\d+[.]\\d+[.]\\d+))(:\\d+)?",
+ TFsm::TOptions().SetCaseInsensitive(true).SetAndNotSupport(true)
+ );
+ UNIT_ASSERT(TMatcher(fsm).Match("yandex.ru").Final());
+ UNIT_ASSERT(TMatcher(fsm).Match("yandex").Final());
+ UNIT_ASSERT(TMatcher(fsm).Match("yandex:80").Final());
+ UNIT_ASSERT(!TMatcher(fsm).Match("127.0.0.1").Final());
+ UNIT_ASSERT(!TMatcher(fsm).Match("127.0.0.1:8080").Final());
+ }
+ }
+
+ Y_UNIT_TEST(Glue) {
+ TFsm glued =
+ TFsm("qw", TFsm::TOptions().SetCaseInsensitive(true)) |
+ TFsm("qw", TFsm::TOptions().SetCaseInsensitive(false)) |
+ TFsm("abc", TFsm::TOptions().SetCaseInsensitive(false));
+ UNIT_ASSERT(TMatcher(glued).Match("Qw").Final());
+ UNIT_ASSERT(TMatcher(glued).Match("Qw").Final());
+ UNIT_ASSERT(TMatcher(glued).Match("abc").Final());
+ UNIT_ASSERT(!TMatcher(glued).Match("Abc").Final());
+ }
+
+ Y_UNIT_TEST(Capture1) {
+ TCapturingFsm fsm("here we have user_id=([a-z0-9]+);");
+
+ TSearcher searcher(fsm);
+ searcher.Search("in db and here we have user_id=0x0d0a; same as CRLF");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("0x0d0a"));
+ }
+
+ Y_UNIT_TEST(Capture2) {
+ TCapturingFsm fsm("w([abcdez]+)f");
+
+ TSearcher searcher(fsm);
+ searcher.Search("wabcdef");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("abcde"));
+ }
+
+ Y_UNIT_TEST(Capture3) {
+ TCapturingFsm fsm("http://vk(ontakte[.]ru|[.]com)/id(\\d+)([^0-9]|$)",
+ TFsm::TOptions().SetCapture(2));
+
+ TSearcher searcher(fsm);
+ searcher.Search("http://vkontakte.ru/id100500");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("100500"));
+ }
+
+ Y_UNIT_TEST(Capture4) {
+ TCapturingFsm fsm("Здравствуйте, ((\\s|\\w|[()]|-)+)!",
+ TFsm::TOptions().SetCharset(CODES_UTF8));
+
+ TSearcher searcher(fsm);
+ searcher.Search(" Здравствуйте, Уважаемый (-ая)! ");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("Уважаемый (-ая)"));
+ }
+
+ Y_UNIT_TEST(Capture5) {
+ TCapturingFsm fsm("away\\.php\\?to=http:([^\"])+\"");
+ TSearcher searcher(fsm);
+ searcher.Search("\"/away.php?to=http:some.addr\"&id=1");
+ UNIT_ASSERT(searcher.Captured());
+ //UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("some.addr"));
+ }
+
+ Y_UNIT_TEST(Capture6) {
+ TCapturingFsm fsm("(/to-match-with)");
+ TSearcher searcher(fsm);
+ searcher.Search("/some/table/path/to-match-with");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("/to-match-with"));
+ }
+
+ Y_UNIT_TEST(Capture7) {
+ TCapturingFsm fsm("(pref.*suff)");
+ TSearcher searcher(fsm);
+ searcher.Search("ala pref bla suff cla");
+ UNIT_ASSERT(searcher.Captured());
+ //UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("pref bla suff"));
+ }
+
+ Y_UNIT_TEST(CaptureXA) {
+ TCapturingFsm fsm(".*(xa).*");
+
+ TSearcher searcher(fsm);
+ searcher.Search("xa");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("xa"));
+ }
+
+ Y_UNIT_TEST(CaptureWrongXX) {
+ TCapturingFsm fsm(".*(xx).*");
+
+ TSearcher searcher(fsm);
+ searcher.Search("xx");
+ UNIT_ASSERT(searcher.Captured());
+ // Surprise!
+ // TCapturingFsm uses a fast - O(|text|) - but incorrect algorithm.
+ // It works more or less for a particular class of regexps to which ".*(xx).*" does not belong.
+ // So it returns not the expected "xx" but just the second "x" instead.
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("x"));
+ }
+
+ Y_UNIT_TEST(CaptureRight1XX) {
+ TCapturingFsm fsm("[^x]+(xx).*");
+
+ TSearcher searcher(fsm);
+
+ searcher.Search("xxx");
+ UNIT_ASSERT(!searcher.Captured());
+ }
+
+ Y_UNIT_TEST(CaptureRight2XX) {
+ TCapturingFsm fsm("[^x]+(xx).*");
+
+ TSearcher searcher(fsm);
+
+ searcher.Search("axx");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("xx"));
+ }
+
+ Y_UNIT_TEST(CaptureRight3XX) {
+ TCapturingFsm fsm("[^x]+(xx).*");
+
+ TSearcher searcher(fsm);
+
+ searcher.Search("axxb");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("xx"));
+ }
+
+ Y_UNIT_TEST(SlowCaptureXX) {
+ TSlowCapturingFsm fsm(".*(xx).*");
+
+ TSlowSearcher searcher(fsm);
+ searcher.Search("xx");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("xx"));
+ }
+
+ Y_UNIT_TEST(SlowCapture) {
+ TSlowCapturingFsm fsm("^http://vk(ontakte[.]ru|[.]com)/id(\\d+)([^0-9]|$)",
+ TFsm::TOptions().SetCapture(2));
+ TSlowSearcher searcher(fsm);
+ searcher.Search("http://vkontakte.ru/id100500");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("100500"));
+ }
+
+ Y_UNIT_TEST(SlowCaptureGreedy) {
+ TSlowCapturingFsm fsm(".*(pref.*suff)");
+ TSlowSearcher searcher(fsm);
+ searcher.Search("pref ala bla pref cla suff dla");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("pref cla suff"));
+ }
+
+ Y_UNIT_TEST(SlowCaptureNonGreedy) {
+ TSlowCapturingFsm fsm(".*?(pref.*suff)");
+ TSlowSearcher searcher(fsm);
+ searcher.Search("pref ala bla pref cla suff dla");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("pref ala bla pref cla suff"));
+ }
+
+ Y_UNIT_TEST(SlowCapture2) {
+ TSlowCapturingFsm fsm("Здравствуйте, ((\\s|\\w|[()]|-)+)!",
+ TFsm::TOptions().SetCharset(CODES_UTF8));
+
+ TSlowSearcher searcher(fsm);
+ searcher.Search(" Здравствуйте, Уважаемый (-ая)! ");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("Уважаемый (-ая)"));
+ }
+
+ Y_UNIT_TEST(SlowCapture3) {
+ TSlowCapturingFsm fsm("here we have user_id=([a-z0-9]+);");
+ TSlowSearcher searcher(fsm);
+ searcher.Search("in db and here we have user_id=0x0d0a; same as CRLF");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("0x0d0a"));
+ }
+
+ Y_UNIT_TEST(SlowCapture4) {
+ TSlowCapturingFsm fsm("away\\.php\\?to=http:([^\"]+)\"");
+ TSlowSearcher searcher(fsm);
+ searcher.Search("\"/away.php?to=http:some.addr\"&id=1");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf("some.addr"));
+ }
+
+ Y_UNIT_TEST(CapturedEmptySlow) {
+ TSlowCapturingFsm fsm("Comments=(.*)$");
+ TSlowSearcher searcher(fsm);
+ searcher.Search("And Comments=");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf(""));
+ }
+
+ Y_UNIT_TEST(CaptureInOrFirst) {
+ TSlowCapturingFsm fsm("(A)|A");
+ TSlowSearcher searcher(fsm);
+ searcher.Search("A");
+ UNIT_ASSERT(searcher.Captured());
+ }
+
+ Y_UNIT_TEST(CaptureInOrSecond) {
+ TSlowCapturingFsm fsm("A|(A)");
+ TSlowSearcher searcher(fsm);
+ searcher.Search("A");
+ UNIT_ASSERT(!searcher.Captured());
+ }
+
+ Y_UNIT_TEST(CaptureOutside) {
+ TSlowCapturingFsm fsm("((ID=([0-9]+))?)");
+ TSlowSearcher searcher(fsm);
+ searcher.Search("ID=");
+ UNIT_ASSERT(searcher.Captured());
+ UNIT_ASSERT_VALUES_EQUAL(searcher.GetCaptured(), TStringBuf(""));
+ }
+
+ Y_UNIT_TEST(CaptureInside) {
+ TSlowCapturingFsm fsm("((ID=([0-9]+))?)",
+ TFsm::TOptions().SetCapture(2));
+ TSlowSearcher searcher(fsm);
+ searcher.Search("ID=");
+ UNIT_ASSERT(!searcher.Captured());
+ }
+
+ Y_UNIT_TEST(Pcre2PireTest) {
+ UNIT_ASSERT_VALUES_EQUAL(Pcre2Pire("(?:fake)"), "(fake)");
+ UNIT_ASSERT_VALUES_EQUAL(Pcre2Pire("(?:fake)??"), "(fake)?");
+ UNIT_ASSERT_VALUES_EQUAL(Pcre2Pire("(?:fake)*?fake"), "(fake)*fake");
+ UNIT_ASSERT_VALUES_EQUAL(Pcre2Pire("(?P<field>fake)"), "(fake)");
+ UNIT_ASSERT_VALUES_EQUAL(Pcre2Pire("fake\\#"), "fake#");
+ UNIT_ASSERT_VALUES_EQUAL(Pcre2Pire("(?P<field>)fake"), "fake");
+ UNIT_ASSERT_VALUES_EQUAL(Pcre2Pire("(?:(?P<field1>)(?P<field2>))"), "");
+ UNIT_ASSERT_VALUES_EQUAL(Pcre2Pire("(?:(?:fake))"), "((fake))");
+ }
+}
diff --git a/library/cpp/regex/pire/ut/ya.make b/library/cpp/regex/pire/ut/ya.make
new file mode 100644
index 0000000000..8776695f40
--- /dev/null
+++ b/library/cpp/regex/pire/ut/ya.make
@@ -0,0 +1,44 @@
+# this test in not linked into build tree with ReCURSE and is built by unittest/library
+
+UNITTEST()
+
+OWNER(
+ g:util
+ davenger
+)
+
+SET(PIRETESTSDIR contrib/libs/pire/ut)
+
+CFLAGS(-DPIRE_NO_CONFIG)
+
+PEERDIR(
+ library/cpp/regex/pire
+)
+
+SRCDIR(
+ ${PIRETESTSDIR}
+)
+
+ADDINCL(
+ contrib/libs/pire/pire
+ contrib/libs/pire/ut
+)
+
+SRCS(
+ pire_ut.cpp
+ capture_ut.cpp
+ count_ut.cpp
+ glyph_ut.cpp
+ easy_ut.cpp
+ read_unicode_ut.cpp
+ regexp_ut.cpp
+ approx_matching_ut.cpp
+)
+
+SIZE(MEDIUM)
+
+TIMEOUT(600)
+
+PIRE_INLINE(inline_ut.cpp)
+
+END()
diff --git a/library/cpp/regex/pire/ya.make b/library/cpp/regex/pire/ya.make
new file mode 100644
index 0000000000..c857e6d18b
--- /dev/null
+++ b/library/cpp/regex/pire/ya.make
@@ -0,0 +1,40 @@
+LIBRARY()
+
+OWNER(
+ g:util
+ g:antiinfra
+ davenger
+ pg
+)
+
+CFLAGS(-DPIRE_NO_CONFIG)
+
+SRCDIR(contrib/libs/pire/pire)
+
+SRCS(
+ pcre2pire.cpp
+ classes.cpp
+ encoding.cpp
+ fsm.cpp
+ scanner_io.cpp
+ easy.cpp
+ scanners/null.cpp
+ extra/capture.cpp
+ extra/count.cpp
+ extra/glyphs.cpp
+ re_lexer.cpp
+ re_parser.y
+ read_unicode.cpp
+ extraencodings.cpp
+ approx_matching.cpp
+ half_final_fsm.cpp
+ minimize.h
+)
+
+PEERDIR(
+ library/cpp/charset
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/regex/ya.make b/library/cpp/regex/ya.make
new file mode 100644
index 0000000000..15b0d1aeda
--- /dev/null
+++ b/library/cpp/regex/ya.make
@@ -0,0 +1,14 @@
+RECURSE(
+ glob
+ hyperscan
+ hyperscan/ut
+ libregex
+ pcre
+ pire
+ pire/inline
+ pire/ut
+ pire2hyperscan
+ pire2hyperscan/ut
+ regexp_classifier
+ regexp_classifier/ut
+)
diff --git a/library/cpp/resource/README.md b/library/cpp/resource/README.md
new file mode 100644
index 0000000000..b1e4961c1f
--- /dev/null
+++ b/library/cpp/resource/README.md
@@ -0,0 +1,24 @@
+This library provides implementation to access a resource (data, file, image, etc.) by a key.
+=============================================================================================
+
+See ya make documentation, resources section for more details.
+
+### Example - adding a resource file into build:
+```
+LIBRARY()
+OWNER(user1)
+RESOURCE(
+ path/to/file1 /key/in/program/1
+ path/to/file2 /key2
+)
+END()
+```
+
+### Example - access to a file content by a key:
+```cpp
+#include <library/cpp/resource/resource.h>
+int main() {
+ Cout << NResource::Find("/key/in/program/1") << Endl;
+ Cout << NResource::Find("/key2") << Endl;
+}
+```
diff --git a/library/cpp/resource/registry.cpp b/library/cpp/resource/registry.cpp
new file mode 100644
index 0000000000..66001c4769
--- /dev/null
+++ b/library/cpp/resource/registry.cpp
@@ -0,0 +1,113 @@
+#include "registry.h"
+
+#include <library/cpp/blockcodecs/codecs.h>
+
+#include <util/system/yassert.h>
+#include <util/generic/hash.h>
+#include <util/generic/deque.h>
+#include <util/generic/singleton.h>
+#include <util/system/env.h>
+
+using namespace NResource;
+using namespace NBlockCodecs;
+
+namespace {
+ inline const ICodec* GetCodec() noexcept {
+ static const ICodec* ret = Codec("zstd08_5");
+
+ return ret;
+ }
+
+ typedef std::pair<TStringBuf, TStringBuf> TDescriptor;
+
+ struct TStore: public IStore, public THashMap<TStringBuf, TDescriptor*> {
+ void Store(const TStringBuf key, const TStringBuf data) override {
+ if (contains(key)) {
+ const TStringBuf value = (*this)[key]->second;
+ if (value != data) {
+ size_t vsize = GetCodec()->DecompressedLength(value);
+ size_t dsize = GetCodec()->DecompressedLength(data);
+ if (vsize + dsize < 1000) {
+ Y_VERIFY(false, "Redefinition of key %s:\n"
+ " old value: %s,\n"
+ " new value: %s.",
+ TString{key}.Quote().c_str(),
+ Decompress(value).Quote().c_str(),
+ Decompress(data).Quote().c_str());
+ } else {
+ Y_VERIFY(false, "Redefinition of key %s,"
+ " old size: %zu,"
+ " new size: %zu.",
+ TString{key}.Quote().c_str(), vsize, dsize);
+ }
+ }
+ } else {
+ D_.push_back(TDescriptor(key, data));
+ (*this)[key] = &D_.back();
+ }
+
+ Y_VERIFY(size() == Count(), "size mismatch");
+ }
+
+ bool FindExact(const TStringBuf key, TString* out) const override {
+ if (TDescriptor* const* res = FindPtr(key)) {
+ // temporary
+ // https://st.yandex-team.ru/DEVTOOLS-3985
+ try {
+ *out = Decompress((*res)->second);
+ } catch (const yexception& e) {
+ if (GetEnv("RESOURCE_DECOMPRESS_DIAG")) {
+ Cerr << "Can't decompress resource " << key << Endl << e.what() << Endl;
+ }
+ throw e;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ void FindMatch(const TStringBuf subkey, IMatch& cb) const override {
+ for (const auto& it : *this) {
+ if (it.first.StartsWith(subkey)) {
+ // temporary
+ // https://st.yandex-team.ru/DEVTOOLS-3985
+ try {
+ const TResource res = {
+ it.first, Decompress(it.second->second)};
+ cb.OnMatch(res);
+ } catch (const yexception& e) {
+ if (GetEnv("RESOURCE_DECOMPRESS_DIAG")) {
+ Cerr << "Can't decompress resource " << it.first << Endl << e.what() << Endl;
+ }
+ throw e;
+ }
+ }
+ }
+ }
+
+ size_t Count() const noexcept override {
+ return D_.size();
+ }
+
+ TStringBuf KeyByIndex(size_t idx) const override {
+ return D_.at(idx).first;
+ }
+
+ typedef TDeque<TDescriptor> TDescriptors;
+ TDescriptors D_;
+ };
+}
+
+TString NResource::Compress(const TStringBuf data) {
+ return GetCodec()->Encode(data);
+}
+
+TString NResource::Decompress(const TStringBuf data) {
+ return GetCodec()->Decode(data);
+}
+
+IStore* NResource::CommonStore() {
+ return SingletonWithPriority<TStore, 0>();
+}
diff --git a/library/cpp/resource/registry.h b/library/cpp/resource/registry.h
new file mode 100644
index 0000000000..fe67702cbc
--- /dev/null
+++ b/library/cpp/resource/registry.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/generic/strbuf.h>
+
+#include "resource.h"
+
+namespace NResource {
+ TString Compress(const TStringBuf data);
+ TString Decompress(const TStringBuf data);
+
+ class IMatch {
+ public:
+ virtual void OnMatch(const TResource& res) = 0;
+ };
+
+ class IStore {
+ public:
+ virtual void Store(const TStringBuf key, const TStringBuf data) = 0;
+ virtual bool FindExact(const TStringBuf key, TString* out) const = 0;
+ virtual void FindMatch(const TStringBuf subkey, IMatch& cb) const = 0;
+ virtual size_t Count() const noexcept = 0;
+ virtual TStringBuf KeyByIndex(size_t idx) const = 0;
+ virtual ~IStore() {
+ }
+ };
+
+ IStore* CommonStore();
+
+ struct TRegHelper {
+ inline TRegHelper(const TStringBuf key, const TStringBuf data) {
+ CommonStore()->Store(key, data);
+ }
+ };
+}
diff --git a/library/cpp/resource/resource.cpp b/library/cpp/resource/resource.cpp
new file mode 100644
index 0000000000..cc20f847a5
--- /dev/null
+++ b/library/cpp/resource/resource.cpp
@@ -0,0 +1,57 @@
+#include "resource.h"
+#include "resource.h"
+#include "registry.h"
+
+#include <util/generic/yexception.h>
+#include <util/generic/xrange.h>
+
+using namespace NResource;
+
+bool NResource::FindExact(const TStringBuf key, TString* out) {
+ return CommonStore()->FindExact(key, out);
+}
+
+void NResource::FindMatch(const TStringBuf subkey, TResources* out) {
+ struct TMatch: public IMatch {
+ inline TMatch(TResources* r)
+ : R(r)
+ {
+ }
+
+ void OnMatch(const TResource& res) override {
+ R->push_back(res);
+ }
+
+ TResources* R;
+ };
+
+ TMatch m(out);
+
+ CommonStore()->FindMatch(subkey, m);
+}
+
+TString NResource::Find(const TStringBuf key) {
+ TString ret;
+
+ if (FindExact(key, &ret)) {
+ return ret;
+ }
+
+ ythrow yexception() << "can not find resource with path " << key;
+}
+
+size_t NResource::Count() noexcept {
+ return CommonStore()->Count();
+}
+
+TStringBuf NResource::KeyByIndex(size_t idx) {
+ return CommonStore()->KeyByIndex(idx);
+}
+
+TVector<TStringBuf> NResource::ListAllKeys() {
+ TVector<TStringBuf> res(Reserve(NResource::Count()));
+ for (auto i : xrange(NResource::Count())) {
+ res.push_back(NResource::KeyByIndex(i));
+ }
+ return res;
+}
diff --git a/library/cpp/resource/resource.h b/library/cpp/resource/resource.h
new file mode 100644
index 0000000000..42dd0f1891
--- /dev/null
+++ b/library/cpp/resource/resource.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/vector.h>
+
+namespace NResource {
+ struct TResource {
+ TStringBuf Key;
+ TString Data;
+ };
+
+ typedef TVector<TResource> TResources;
+
+ TString Find(const TStringBuf key);
+ bool FindExact(const TStringBuf key, TString* out);
+ //perform full scan for now
+ void FindMatch(const TStringBuf subkey, TResources* out);
+ size_t Count() noexcept;
+ TStringBuf KeyByIndex(size_t idx);
+ TVector<TStringBuf> ListAllKeys();
+}
diff --git a/library/cpp/resource/ut/lib/data b/library/cpp/resource/ut/lib/data
new file mode 100644
index 0000000000..50e37d5cac
--- /dev/null
+++ b/library/cpp/resource/ut/lib/data
@@ -0,0 +1 @@
+na gorshke sidel korol
diff --git a/library/cpp/resource/ut/lib/ya.make b/library/cpp/resource/ut/lib/ya.make
new file mode 100644
index 0000000000..48b92b9c8f
--- /dev/null
+++ b/library/cpp/resource/ut/lib/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(pg)
+
+RESOURCE(
+ data /x
+)
+
+END()
diff --git a/library/cpp/resource/ut/resource_ut.cpp b/library/cpp/resource/ut/resource_ut.cpp
new file mode 100644
index 0000000000..b6fa8e4df3
--- /dev/null
+++ b/library/cpp/resource/ut/resource_ut.cpp
@@ -0,0 +1,8 @@
+#include <library/cpp/resource/resource.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TestResource) {
+ Y_UNIT_TEST(Test1) {
+ UNIT_ASSERT_VALUES_EQUAL(NResource::Find("/x"), "na gorshke sidel korol\n");
+ }
+}
diff --git a/library/cpp/resource/ut/ya.make b/library/cpp/resource/ut/ya.make
new file mode 100644
index 0000000000..d1ac9ed2ed
--- /dev/null
+++ b/library/cpp/resource/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/resource/ut/lib)
+
+OWNER(pg)
+
+SRCS(
+ resource_ut.cpp
+)
+
+END()
diff --git a/library/cpp/resource/ya.make b/library/cpp/resource/ya.make
new file mode 100644
index 0000000000..9c06df514f
--- /dev/null
+++ b/library/cpp/resource/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ library/cpp/blockcodecs/core
+ library/cpp/blockcodecs/codecs/zstd
+)
+
+SRCS(
+ registry.cpp
+ resource.cpp
+)
+
+END()
diff --git a/library/cpp/retry/protos/retry_options.proto b/library/cpp/retry/protos/retry_options.proto
new file mode 100644
index 0000000000..063fff0141
--- /dev/null
+++ b/library/cpp/retry/protos/retry_options.proto
@@ -0,0 +1,9 @@
+package NRetry;
+
+message TRetryOptionsPB {
+ optional uint32 MaxTries = 1 [default = 5];
+ optional uint32 InitialSleepMs = 2 [default = 0];
+ optional uint32 SleepIncrementMs = 3 [default = 0];
+ optional uint32 RandomDeltaMs = 4 [default = 10];
+ optional uint32 ExponentalMultiplierMs = 5 [default = 100];
+}
diff --git a/library/cpp/retry/protos/ya.make b/library/cpp/retry/protos/ya.make
new file mode 100644
index 0000000000..ad8ea2086a
--- /dev/null
+++ b/library/cpp/retry/protos/ya.make
@@ -0,0 +1,16 @@
+PROTO_LIBRARY()
+
+OWNER(
+ anskor
+)
+
+SRCS(
+ retry_options.proto
+)
+
+PEERDIR()
+
+EXCLUDE_TAGS(GO_PROTO)
+
+END()
+
diff --git a/library/cpp/retry/retry.cpp b/library/cpp/retry/retry.cpp
new file mode 100644
index 0000000000..92466cdeca
--- /dev/null
+++ b/library/cpp/retry/retry.cpp
@@ -0,0 +1,26 @@
+#include "retry.h"
+
+#include <util/stream/output.h>
+
+void DoWithRetry(std::function<void()> func, TRetryOptions retryOptions) {
+ DoWithRetry(func, retryOptions, true);
+}
+
+bool DoWithRetryOnRetCode(std::function<bool()> func, TRetryOptions retryOptions) {
+ for (ui32 attempt = 0; attempt <= retryOptions.RetryCount; ++attempt) {
+ if (func()) {
+ return true;
+ }
+ auto sleep = retryOptions.SleepFunction;
+ sleep(retryOptions.GetTimeToSleep(attempt));
+ }
+ return false;
+}
+
+TRetryOptions MakeRetryOptions(const NRetry::TRetryOptionsPB& retryOptions) {
+ return TRetryOptions(retryOptions.GetMaxTries(),
+ TDuration::MilliSeconds(retryOptions.GetInitialSleepMs()),
+ TDuration::MilliSeconds(retryOptions.GetRandomDeltaMs()),
+ TDuration::MilliSeconds(retryOptions.GetSleepIncrementMs()),
+ TDuration::MilliSeconds(retryOptions.GetExponentalMultiplierMs()));
+}
diff --git a/library/cpp/retry/retry.h b/library/cpp/retry/retry.h
new file mode 100644
index 0000000000..c47ff5070f
--- /dev/null
+++ b/library/cpp/retry/retry.h
@@ -0,0 +1,133 @@
+#pragma once
+
+#include "utils.h"
+
+#include <library/cpp/retry/protos/retry_options.pb.h>
+
+#include <util/datetime/base.h>
+#include <util/generic/maybe.h>
+#include <util/generic/typetraits.h>
+#include <util/generic/yexception.h>
+#include <functional>
+
+struct TRetryOptions {
+ ui32 RetryCount;
+
+ // TotalDuration = SleepDuration +/- SleepRandomDelta + (attempt * SleepIncrement) + (2**attempt * SleepExponentialMultiplier)
+ TDuration SleepDuration;
+ TDuration SleepRandomDelta;
+ TDuration SleepIncrement;
+ TDuration SleepExponentialMultiplier;
+
+ std::function<void(TDuration)> SleepFunction;
+
+ TRetryOptions(ui32 retryCount = 3, TDuration sleepDuration = TDuration::Seconds(1), TDuration sleepRandomDelta = TDuration::Zero(),
+ TDuration sleepIncrement = TDuration::Zero(), TDuration sleepExponentialMultiplier = TDuration::Zero(),
+ std::function<void(TDuration)> sleepFunction = [](TDuration d) { Sleep(d); }) // can't use Sleep itself due to Win compilation error
+ : RetryCount(retryCount)
+ , SleepDuration(sleepDuration)
+ , SleepRandomDelta(sleepRandomDelta)
+ , SleepIncrement(sleepIncrement)
+ , SleepExponentialMultiplier(sleepExponentialMultiplier)
+ , SleepFunction(sleepFunction)
+ {
+ }
+
+ TRetryOptions& WithCount(ui32 retryCount) {
+ RetryCount = retryCount;
+ return *this;
+ }
+
+ TRetryOptions& WithSleep(TDuration sleepDuration) {
+ SleepDuration = sleepDuration;
+ return *this;
+ }
+
+ TRetryOptions& WithRandomDelta(TDuration sleepRandomDelta) {
+ SleepRandomDelta = sleepRandomDelta;
+ return *this;
+ }
+
+ TRetryOptions& WithIncrement(TDuration sleepIncrement) {
+ SleepIncrement = sleepIncrement;
+ return *this;
+ }
+
+ TRetryOptions& WithExponentialMultiplier(TDuration sleepExponentialMultiplier) {
+ SleepExponentialMultiplier = sleepExponentialMultiplier;
+ return *this;
+ }
+
+ TRetryOptions& WithSleepFunction(std::function<void(TDuration)> sleepFunction) {
+ SleepFunction = sleepFunction;
+ return *this;
+ }
+
+ // for compatibility attempt == 0 by default
+ TDuration GetTimeToSleep(ui32 attempt = 0) const {
+ return SleepDuration + NRetryPrivate::AddRandomDelta(SleepRandomDelta) + NRetryPrivate::AddIncrement(attempt, SleepIncrement) + NRetryPrivate::AddExponentialMultiplier(attempt, SleepExponentialMultiplier);
+ }
+
+ static TRetryOptions Count(ui32 retryCount) {
+ return TRetryOptions(retryCount);
+ }
+
+ static TRetryOptions Default() {
+ return TRetryOptions();
+ }
+
+ static TRetryOptions NoRetry() {
+ return TRetryOptions(0);
+ }
+};
+
+template <typename TResult, typename TException = yexception>
+TMaybe<TResult> DoWithRetry(std::function<TResult()> func, std::function<void(const TException&)> onFail, TRetryOptions retryOptions, bool throwLast) {
+ for (ui32 attempt = 0; attempt <= retryOptions.RetryCount; ++attempt) {
+ try {
+ return func();
+ } catch (TException& ex) {
+ onFail(ex);
+ if (attempt == retryOptions.RetryCount) {
+ if (throwLast) {
+ throw;
+ }
+ } else {
+ auto sleep = retryOptions.SleepFunction;
+ sleep(retryOptions.GetTimeToSleep(attempt));
+ }
+ }
+ }
+ return Nothing();
+}
+
+template <typename TResult, typename TException = yexception>
+TMaybe<TResult> DoWithRetry(std::function<TResult()> func, TRetryOptions retryOptions, bool throwLast) {
+ return DoWithRetry<TResult, TException>(func, [](const TException&){}, retryOptions, throwLast);
+}
+
+template <typename TException = yexception>
+bool DoWithRetry(std::function<void()> func, std::function<void(const TException&)> onFail, TRetryOptions retryOptions, bool throwLast) {
+ auto f = [&]() {
+ func();
+ return nullptr;
+ };
+ return DoWithRetry<void*, TException>(f, onFail, retryOptions, throwLast).Defined();
+}
+
+template <typename TException = yexception>
+bool DoWithRetry(std::function<void()> func, TRetryOptions retryOptions, bool throwLast) {
+ auto f = [&]() {
+ func();
+ return nullptr;
+ };
+ return DoWithRetry<void*, TException>(f, [](const TException&){}, retryOptions, throwLast).Defined();
+}
+
+void DoWithRetry(std::function<void()> func, TRetryOptions retryOptions);
+
+bool DoWithRetryOnRetCode(std::function<bool()> func, TRetryOptions retryOptions);
+
+Y_DECLARE_PODTYPE(TRetryOptions);
+
+TRetryOptions MakeRetryOptions(const NRetry::TRetryOptionsPB& retryOptions);
diff --git a/library/cpp/retry/retry_ut.cpp b/library/cpp/retry/retry_ut.cpp
new file mode 100644
index 0000000000..92153e987e
--- /dev/null
+++ b/library/cpp/retry/retry_ut.cpp
@@ -0,0 +1,117 @@
+#include "retry.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+namespace {
+ class TDoOnSecondOrThrow {
+ public:
+ ui32 operator()() {
+ if (attempt++ != 1) {
+ throw yexception();
+ }
+ return 42;
+ }
+
+ private:
+ ui32 attempt = 0;
+ };
+
+ class TDoOnSecondOrFail {
+ public:
+ bool operator()() {
+ return (attempt++ == 1);
+ }
+
+ private:
+ ui32 attempt = 0;
+ };
+}
+
+Y_UNIT_TEST_SUITE(Retry) {
+ Y_UNIT_TEST(RetryOnExceptionSuccess) {
+ UNIT_ASSERT_NO_EXCEPTION(DoWithRetry(TDoOnSecondOrThrow{}, TRetryOptions(1, TDuration::Zero())));
+ }
+ Y_UNIT_TEST(RetryOnExceptionSuccessWithOnFail) {
+ ui32 value = 0;
+ std::function<void(const yexception&)> cb = [&value](const yexception&){ value += 1; };
+ UNIT_ASSERT_NO_EXCEPTION(DoWithRetry<ui32>(TDoOnSecondOrThrow{}, cb, TRetryOptions(1, TDuration::Zero()), true));
+ UNIT_ASSERT_EQUAL(value, 1);
+ }
+ Y_UNIT_TEST(RetryOnExceptionFail) {
+ UNIT_ASSERT_EXCEPTION(DoWithRetry(TDoOnSecondOrThrow{}, TRetryOptions(0, TDuration::Zero())), yexception);
+ }
+ Y_UNIT_TEST(RetryOnExceptionFailWithOnFail) {
+ ui32 value = 0;
+ std::function<void(const yexception&)> cb = [&value](const yexception&) { value += 1; };
+ UNIT_ASSERT_EXCEPTION(DoWithRetry<ui32>(TDoOnSecondOrThrow{}, cb, TRetryOptions(0, TDuration::Zero()), true), yexception);
+ UNIT_ASSERT_EQUAL(value, 1);
+ }
+
+ Y_UNIT_TEST(RetryOnExceptionSuccessWithValue) {
+ std::function<ui32()> f = TDoOnSecondOrThrow{};
+ UNIT_ASSERT(42 == *DoWithRetry<ui32>(f, TRetryOptions(1, TDuration::Zero()), false));
+ }
+ Y_UNIT_TEST(RetryOnExceptionSuccessWithValueWithOnFail) {
+ ui32 value = 0;
+ std::function<ui32()> f = TDoOnSecondOrThrow{};
+ std::function<void(const yexception&)> cb = [&value](const yexception&){ value += 1; };
+ UNIT_ASSERT(42 == *DoWithRetry<ui32>(f, cb, TRetryOptions(1, TDuration::Zero()), false));
+ UNIT_ASSERT_EQUAL(value, 1);
+ }
+ Y_UNIT_TEST(RetryOnExceptionFailWithValue) {
+ std::function<ui32()> f = TDoOnSecondOrThrow{};
+ UNIT_ASSERT(!DoWithRetry<ui32>(f, TRetryOptions(0, TDuration::Zero()), false).Defined());
+ }
+ Y_UNIT_TEST(RetryOnExceptionFailWithValueWithOnFail) {
+ ui32 value = 0;
+ std::function<ui32()> f = TDoOnSecondOrThrow{};
+ std::function<void(const yexception&)> cb = [&value](const yexception&){ value += 1; };
+ UNIT_ASSERT(!DoWithRetry<ui32>(f, cb, TRetryOptions(0, TDuration::Zero()), false).Defined());
+ UNIT_ASSERT_EQUAL(value, 1);
+ }
+
+ Y_UNIT_TEST(RetryOnExceptionSuccessWithValueAndRethrow) {
+ std::function<ui32()> f = TDoOnSecondOrThrow{};
+ UNIT_ASSERT(42 == *DoWithRetry<ui32>(f, TRetryOptions(1, TDuration::Zero()), true));
+ }
+ Y_UNIT_TEST(RetryOnExceptionSuccessWithValueAndRethrowWithOnFail) {
+ ui32 value = 0;
+ std::function<ui32()> f = TDoOnSecondOrThrow{};
+ std::function<void(const yexception&)> cb = [&value](const yexception&){ value += 1; };
+ UNIT_ASSERT(42 == *DoWithRetry<ui32>(f, cb, TRetryOptions(1, TDuration::Zero()), true));
+ UNIT_ASSERT_EQUAL(value, 1);
+ }
+ Y_UNIT_TEST(RetryOnExceptionFailWithValueAndRethrow) {
+ std::function<ui32()> f = TDoOnSecondOrThrow{};
+ UNIT_ASSERT_EXCEPTION(DoWithRetry<ui32>(f, TRetryOptions(0, TDuration::Zero()), true), yexception);
+ }
+ Y_UNIT_TEST(RetryOnExceptionFailWithValueAndRethrowWithOnFail) {
+ ui32 value = 0;
+ std::function<ui32()> f = TDoOnSecondOrThrow{};
+ std::function<void(const yexception&)> cb = [&value](const yexception&){ value += 1; };
+ UNIT_ASSERT_EXCEPTION(42 == *DoWithRetry<ui32>(f, cb, TRetryOptions(0, TDuration::Zero()), true), yexception);
+ UNIT_ASSERT_EQUAL(value, 1);
+ }
+
+ Y_UNIT_TEST(RetryOnRetCodeSuccess) {
+ UNIT_ASSERT(true == DoWithRetryOnRetCode(TDoOnSecondOrFail{}, TRetryOptions(1, TDuration::Zero())));
+ }
+ Y_UNIT_TEST(RetryOnRetCodeFail) {
+ UNIT_ASSERT(false == DoWithRetryOnRetCode(TDoOnSecondOrFail{}, TRetryOptions(0, TDuration::Zero())));
+ }
+ Y_UNIT_TEST(MakeRetryOptionsFromProto) {
+ NRetry::TRetryOptionsPB protoOptions;
+ protoOptions.SetMaxTries(1);
+ protoOptions.SetInitialSleepMs(2);
+ protoOptions.SetSleepIncrementMs(3);
+ protoOptions.SetRandomDeltaMs(4);
+ protoOptions.SetExponentalMultiplierMs(5);
+
+ const TRetryOptions options = MakeRetryOptions(protoOptions);
+ UNIT_ASSERT_EQUAL(options.RetryCount, 1);
+ UNIT_ASSERT_EQUAL(options.SleepDuration, TDuration::MilliSeconds(2));
+ UNIT_ASSERT_EQUAL(options.SleepIncrement, TDuration::MilliSeconds(3));
+ UNIT_ASSERT_EQUAL(options.SleepRandomDelta, TDuration::MilliSeconds(4));
+ UNIT_ASSERT_EQUAL(options.SleepExponentialMultiplier, TDuration::MilliSeconds(5));
+ }
+}
diff --git a/library/cpp/retry/ut/ya.make b/library/cpp/retry/ut/ya.make
new file mode 100644
index 0000000000..ff8259bfdb
--- /dev/null
+++ b/library/cpp/retry/ut/ya.make
@@ -0,0 +1,13 @@
+UNITTEST_FOR(library/cpp/retry)
+
+OWNER(
+ salmin
+ osado
+ g:yabs-small
+)
+
+SRCS(
+ retry_ut.cpp
+)
+
+END()
diff --git a/library/cpp/retry/utils.cpp b/library/cpp/retry/utils.cpp
new file mode 100644
index 0000000000..24d943f518
--- /dev/null
+++ b/library/cpp/retry/utils.cpp
@@ -0,0 +1,20 @@
+#include "utils.h"
+
+#include <util/random/random.h>
+
+TDuration NRetryPrivate::AddRandomDelta(TDuration maxDelta) {
+ if (maxDelta == TDuration::Zero()) {
+ return TDuration::Zero();
+ }
+
+ const TDuration delta = TDuration::MicroSeconds(RandomNumber(2 * maxDelta.MicroSeconds()));
+ return delta - maxDelta;
+}
+
+TDuration NRetryPrivate::AddIncrement(ui32 attempt, TDuration increment) {
+ return TDuration::MicroSeconds(attempt * increment.MicroSeconds());
+}
+
+TDuration NRetryPrivate::AddExponentialMultiplier(ui32 attempt, TDuration exponentialMultiplier) {
+ return TDuration::MicroSeconds((1ull << Min(63u, attempt)) * exponentialMultiplier.MicroSeconds());
+}
diff --git a/library/cpp/retry/utils.h b/library/cpp/retry/utils.h
new file mode 100644
index 0000000000..a8fd3d1a89
--- /dev/null
+++ b/library/cpp/retry/utils.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include <util/datetime/base.h>
+
+namespace NRetryPrivate {
+ TDuration AddRandomDelta(TDuration delta);
+ TDuration AddIncrement(ui32 attempt, TDuration increment);
+ TDuration AddExponentialMultiplier(ui32 attempt, TDuration exponentialMultiplier);
+
+}
diff --git a/library/cpp/retry/ya.make b/library/cpp/retry/ya.make
new file mode 100644
index 0000000000..31e0c6a259
--- /dev/null
+++ b/library/cpp/retry/ya.make
@@ -0,0 +1,17 @@
+LIBRARY()
+
+OWNER(
+ osado
+ g:yabs-small
+)
+
+SRCS(
+ retry.cpp
+ utils.cpp
+)
+
+PEERDIR(
+ library/cpp/retry/protos
+)
+
+END()
diff --git a/library/cpp/scheme/README b/library/cpp/scheme/README
new file mode 100644
index 0000000000..117c81979b
--- /dev/null
+++ b/library/cpp/scheme/README
@@ -0,0 +1 @@
+see http://wiki.yandex-team.ru/JandeksPoisk/KachestvoPoiska/Rearrange/RealizacijaFormata \ No newline at end of file
diff --git a/library/cpp/scheme/domscheme_traits.h b/library/cpp/scheme/domscheme_traits.h
new file mode 100644
index 0000000000..a11c4dd444
--- /dev/null
+++ b/library/cpp/scheme/domscheme_traits.h
@@ -0,0 +1,228 @@
+#pragma once
+
+#include "scheme.h"
+#include <util/string/cast.h>
+
+struct TSchemeTraits {
+ using TValue = NSc::TValue;
+ using TValueRef = TValue*;
+ using TConstValueRef = const TValue*;
+ using TStringType = TStringBuf;
+
+ // anyvalue defaults
+ template <class T>
+ static inline TValue Value(T&& t) {
+ return TValue(std::forward<T>(t));
+ }
+
+ template <class T>
+ static inline TValue Value(std::initializer_list<T> t) {
+ return TValue().SetArray().AppendAll(t);
+ }
+
+ static inline TValueRef Ref(TValue& v) {
+ return &v;
+ }
+
+ static inline TConstValueRef Ref(const TValue& v) {
+ return &v;
+ }
+
+ // common ops
+ static inline bool IsNull(TConstValueRef v) {
+ return v->IsNull();
+ }
+
+ static inline TString ToJson(TConstValueRef v) {
+ return v->ToJson();
+ }
+
+ // struct ops
+ static inline TValueRef GetField(TValueRef v, const TStringBuf& name) {
+ return &(*v)[name];
+ }
+
+ static inline TConstValueRef GetField(TConstValueRef v, const TStringBuf& name) {
+ return &(*v)[name];
+ }
+
+ // array ops
+ static bool IsArray(TConstValueRef v) {
+ return v->IsArray();
+ }
+
+ static inline void ArrayClear(TValueRef v) {
+ v->SetArray();
+ v->ClearArray();
+ }
+
+ using TArrayIterator = size_t;
+
+ static inline TValueRef ArrayElement(TValueRef v, TArrayIterator n) {
+ return &(*v)[n];
+ }
+
+ static inline TConstValueRef ArrayElement(TConstValueRef v, TArrayIterator n) {
+ return &(*v)[n];
+ }
+
+ static inline size_t ArraySize(TConstValueRef v) {
+ return v->GetArray().size();
+ }
+
+ static inline TArrayIterator ArrayBegin(TConstValueRef) {
+ return 0;
+ }
+
+ static inline TArrayIterator ArrayEnd(TConstValueRef v) {
+ return ArraySize(v);
+ }
+
+ // dict ops
+ static bool IsDict(TConstValueRef v) {
+ return v->IsDict();
+ }
+
+ static inline void DictClear(TValueRef v) {
+ v->SetDict();
+ v->ClearDict();
+ }
+
+ static inline TValueRef DictElement(TValueRef v, TStringBuf key) {
+ return &(*v)[key];
+ }
+
+ static inline TConstValueRef DictElement(TConstValueRef v, TStringBuf key) {
+ return &(*v)[key];
+ }
+
+ static inline size_t DictSize(TConstValueRef v) {
+ return v->GetDict().size();
+ }
+
+ using TDictIterator = NSc::TDict::const_iterator;
+
+ static inline TDictIterator DictBegin(TConstValueRef v) {
+ return v->GetDict().begin();
+ }
+
+ static inline TDictIterator DictEnd(TConstValueRef v) {
+ return v->GetDict().end();
+ }
+
+ static inline TStringBuf DictIteratorKey(TConstValueRef /*dict*/, const TDictIterator& it) {
+ return it->first;
+ }
+
+ static inline TConstValueRef DictIteratorValue(TConstValueRef /*dict*/, const TDictIterator& it) {
+ return &it->second;
+ }
+
+ // boolean ops
+ static inline void Get(TConstValueRef v, bool def, bool& b) {
+ b = def == true ? !v->IsExplicitFalse() : v->IsTrue();
+ }
+
+ static inline void Get(TConstValueRef v, bool& b) {
+ b = v->IsTrue();
+ }
+
+ static inline void Set(TValueRef v, bool b) {
+ v->SetIntNumber(b ? 1 : 0);
+ }
+
+ static inline bool IsValidPrimitive(const bool&, TConstValueRef v) {
+ return v->IsTrue() || v->IsExplicitFalse();
+ }
+
+#define INTEGER_OPS_EX(type, min, max, isUnsigned) \
+ static inline void Get(TConstValueRef v, type def, type& i) { \
+ if (isUnsigned) { \
+ i = v->IsNumber() && v->GetIntNumber() >= 0 ? v->GetIntNumber() : def; \
+ } else { \
+ i = v->IsNumber() ? v->GetIntNumber() : def; \
+ } \
+ } \
+ static inline void Get(TConstValueRef v, type& i) { \
+ if (isUnsigned) { \
+ i = Max<i64>(0, v->GetIntNumber()); \
+ } else { \
+ i = v->GetIntNumber(); \
+ } \
+ } \
+ static inline bool IsValidPrimitive(const type&, TConstValueRef v) { \
+ return v->IsIntNumber() && \
+ v->GetIntNumber() >= min && \
+ v->GetIntNumber() <= max; \
+ } \
+ static inline void Set(TValueRef v, type i) { \
+ v->SetIntNumber(i); \
+ }
+
+#define INTEGER_OPS(type, isUnsigned) INTEGER_OPS_EX(type, Min<type>(), Max<type>(), isUnsigned)
+
+ INTEGER_OPS(i8, false)
+ INTEGER_OPS(i16, false)
+ INTEGER_OPS(i32, false)
+ INTEGER_OPS(i64, false)
+ INTEGER_OPS(ui8, true)
+ INTEGER_OPS(ui16, true)
+ INTEGER_OPS(ui32, true)
+ INTEGER_OPS_EX(ui64, 0, (i64)(Max<i64>() >> 1), true)
+
+#undef INTEGER_OPS
+#undef INTEGER_OPS_EX
+
+ // double ops
+ static inline bool Get(TConstValueRef v, double def, double& d) {
+ if (v->IsNumber()) {
+ d = v->GetNumber(def);
+ return true;
+ }
+ d = def;
+ return false;
+ }
+
+ static inline void Get(TConstValueRef v, double& d) {
+ d = v->GetNumber();
+ }
+
+ static inline void Set(TValueRef v, double d) {
+ v->SetNumber(d);
+ }
+
+ static inline bool IsValidPrimitive(const double&, TConstValueRef v) {
+ return v->IsNumber();
+ }
+
+ // string ops
+ static inline void Get(TConstValueRef v, TStringBuf def, TStringBuf& s) {
+ s = v->GetString(def);
+ }
+
+ static inline void Get(TConstValueRef v, TStringBuf& s) {
+ s = v->GetString();
+ }
+
+ static inline void Set(TValueRef v, TStringBuf s) {
+ v->SetString(s);
+ }
+
+ static inline bool IsValidPrimitive(const TStringBuf&, TConstValueRef v) {
+ return v->IsString();
+ }
+
+ // validation ops
+ static inline TVector<TString> GetKeys(TConstValueRef v) {
+ TVector<TString> res;
+ for (const auto& key : v->DictKeys(true)) {
+ res.push_back(ToString(key));
+ }
+ return res;
+ }
+
+ template <typename T>
+ static inline bool IsValidPrimitive(const T&, TConstValueRef) {
+ return false;
+ }
+};
diff --git a/library/cpp/scheme/fwd.h b/library/cpp/scheme/fwd.h
new file mode 100644
index 0000000000..975a034eb2
--- /dev/null
+++ b/library/cpp/scheme/fwd.h
@@ -0,0 +1,7 @@
+#pragma once
+
+namespace NSc {
+ class TValue;
+ class TDict;
+ class TArray;
+}
diff --git a/library/cpp/scheme/scheme.cpp b/library/cpp/scheme/scheme.cpp
new file mode 100644
index 0000000000..3efd116d4f
--- /dev/null
+++ b/library/cpp/scheme/scheme.cpp
@@ -0,0 +1,598 @@
+#include "scheme.h"
+#include "scimpl_private.h"
+
+#include <util/generic/algorithm.h>
+#include <util/string/cast.h>
+
+namespace NSc {
+ TStringBufs& TValue::DictKeys(TStringBufs& vs, bool sorted) const {
+ if (!IsDict()) {
+ return vs;
+ }
+
+ const ::NSc::TDict& dict = GetDict();
+ vs.reserve(vs.size() + dict.size());
+ for (const auto& it : dict)
+ vs.push_back(it.first);
+
+ if (sorted) {
+ Sort(vs.begin(), vs.end());
+ }
+
+ return vs;
+ }
+
+ TStringBufs TValue::DictKeys(bool sorted) const {
+ TStringBufs bufs;
+ DictKeys(bufs, sorted);
+ return bufs;
+ }
+
+ TValue& TValue::MergeUpdate(const TValue& delta) {
+ return DoMerge(delta, false);
+ }
+
+ TValue& TValue::ReverseMerge(const TValue& delta) {
+ return DoMerge(delta, true);
+ }
+
+ TValue& TValue::MergeUpdateJson(TStringBuf data) {
+ return MergeUpdate(FromJson(data));
+ }
+
+ TValue& TValue::ReverseMergeJson(TStringBuf data) {
+ return ReverseMerge(FromJson(data));
+ }
+
+ bool TValue::MergeUpdateJson(TValue& v, TStringBuf data) {
+ NSc::TValue m;
+ if (!FromJson(m, data)) {
+ return false;
+ }
+
+ v.MergeUpdate(m);
+ return true;
+ }
+
+ bool TValue::ReverseMergeJson(TValue& v, TStringBuf data) {
+ NSc::TValue m;
+ if (!FromJson(m, data)) {
+ return false;
+ }
+
+ v.ReverseMerge(m);
+ return true;
+ }
+
+ TValue TValue::Clone() const {
+ return TValue().CopyFrom(*this);
+ }
+
+ double TValue::ForceNumber(double deflt) const {
+ const TScCore& core = Core();
+ if (core.IsNumber()) {
+ return core.GetNumber(deflt);
+ }
+
+ if (TStringBuf str = core.GetString(TStringBuf())) {
+ {
+ double result = 0;
+ if (TryFromString<double>(str, result)) {
+ return result;
+ }
+ }
+ {
+ i64 result = 0;
+ if (TryFromString<i64>(str, result)) {
+ return result;
+ }
+ }
+ {
+ ui64 result = 0;
+ if (TryFromString<ui64>(str, result)) {
+ return result;
+ }
+ }
+ }
+
+ return deflt;
+ }
+
+ i64 TValue::ForceIntNumber(i64 deflt) const {
+ const TScCore& core = Core();
+ if (core.IsNumber()) {
+ return core.GetIntNumber(deflt);
+ }
+
+ if (TStringBuf str = core.GetString(TStringBuf())) {
+ {
+ i64 result = 0;
+ if (TryFromString<i64>(str, result)) {
+ return result;
+ }
+ }
+ {
+ ui64 result = 0;
+ if (TryFromString<ui64>(str, result)) {
+ return result;
+ }
+ }
+ {
+ double result = 0;
+ if (TryFromString<double>(str, result)) {
+ return result;
+ }
+ }
+ }
+
+ return deflt;
+ }
+
+ TString TValue::ForceString(const TString& deflt) const {
+ const TScCore& core = Core();
+ if (core.IsString()) {
+ return ToString(core.GetString(TStringBuf()));
+ }
+
+ if (core.IsIntNumber()) {
+ return ToString(core.GetIntNumber(0));
+ }
+
+ if (core.IsNumber()) {
+ return ToString(core.GetNumber(0));
+ }
+
+ return deflt;
+ }
+
+ TValue& /*this*/ TValue::CopyFrom(const TValue& other) {
+ if (Same(*this, other)) {
+ return *this;
+ }
+
+ using namespace NImpl;
+ return DoCopyFromImpl(other, GetTlsInstance<TSelfLoopContext>(), GetTlsInstance<TSelfOverrideContext>());
+ }
+
+ TValue& TValue::DoCopyFromImpl(const TValue& other,
+ NImpl::TSelfLoopContext& otherLoopCtx,
+ NImpl::TSelfOverrideContext& selfOverrideCtx) {
+ if (Same(*this, other)) {
+ return *this;
+ }
+
+ CoreMutableForSet(); // trigger COW
+
+ TScCore& selfCore = *TheCore;
+ const TScCore& otherCore = other.Core();
+
+ NImpl::TSelfLoopContext::TGuard loopCheck(otherLoopCtx, otherCore);
+ NImpl::TSelfOverrideContext::TGuard overrideGuard(selfOverrideCtx, selfCore);
+
+ selfCore.SetNull();
+
+ if (!loopCheck.Ok) {
+ return *this; // a loop encountered (and asserted), skip the back reference
+ }
+
+ switch (otherCore.ValueType) {
+ default:
+ Y_ASSERT(false);
+ [[fallthrough]];
+ case EType::Null:
+ break;
+ case EType::Bool:
+ selfCore.SetBool(otherCore.IntNumber);
+ break;
+ case EType::IntNumber:
+ selfCore.SetIntNumber(otherCore.IntNumber);
+ break;
+ case EType::FloatNumber:
+ selfCore.SetNumber(otherCore.FloatNumber);
+ break;
+ case EType::String:
+ if (selfCore.Pool.Get() == otherCore.Pool.Get()) {
+ selfCore.SetOwnedString(otherCore.String);
+ } else {
+ selfCore.SetString(otherCore.String);
+ }
+ break;
+ case EType::Array:
+ selfCore.SetArray();
+ for (const TValue& e : otherCore.GetArray()) {
+ selfCore.Push().DoCopyFromImpl(e, otherLoopCtx, selfOverrideCtx);
+ }
+ break;
+ case EType::Dict: {
+ TCorePtr tmp = NewCore(selfCore.Pool);
+ auto& tmpCore = *tmp;
+ tmpCore.SetDict();
+ const TDict& d = otherCore.GetDict();
+ tmpCore.Dict.reserve(d.size());
+ for (const TDict::value_type& e : d) {
+ tmpCore.Add(e.first).DoCopyFromImpl(e.second, otherLoopCtx, selfOverrideCtx);
+ }
+ TheCore = std::move(tmp);
+ break;
+ }
+ }
+
+ return *this;
+ }
+
+ TValue& TValue::Swap(TValue& v) {
+ DoSwap(TheCore, v.TheCore);
+ DoSwap(CopyOnWrite, v.CopyOnWrite);
+ return *this;
+ }
+
+ bool TValue::Same(const TValue& a, const TValue& b) {
+ return a.TheCore.Get() == b.TheCore.Get();
+ }
+
+ bool TValue::SamePool(const TValue& a, const TValue& b) {
+ return Same(a, b) || a.TheCore->Pool.Get() == b.TheCore->Pool.Get();
+ }
+
+ bool TValue::Equal(const TValue& a, const TValue& b) {
+ if (Same(a, b)) {
+ return true;
+ }
+
+ const NSc::TValue::TScCore& coreA = a.Core();
+ const NSc::TValue::TScCore& coreB = b.Core();
+
+ if (coreA.IsNumber() && coreB.IsNumber()) {
+ return coreA.GetIntNumber(0) == coreB.GetIntNumber(0) && coreA.GetNumber(0) == coreB.GetNumber(0);
+ }
+
+ if (coreA.ValueType != coreB.ValueType) {
+ return false;
+ }
+
+ if (coreA.IsString()) {
+ std::string_view strA = coreA.String;
+ std::string_view strB = coreB.String;
+
+ if (strA != strB) {
+ return false;
+ }
+ } else if (coreA.IsArray()) {
+ const TArray& arrA = coreA.Array;
+ const TArray& arrB = coreB.Array;
+
+ if (arrA.size() != arrB.size()) {
+ return false;
+ }
+
+ for (size_t i = 0; i < arrA.size(); ++i) {
+ if (!Equal(arrA[i], arrB[i])) {
+ return false;
+ }
+ }
+ } else if (coreA.IsDict()) {
+ const ::NSc::TDict& dictA = coreA.Dict;
+ const ::NSc::TDict& dictB = coreB.Dict;
+
+ if (dictA.size() != dictB.size()) {
+ return false;
+ }
+
+ for (const auto& ita : dictA) {
+ ::NSc::TDict::const_iterator itb = dictB.find(ita.first);
+
+ if (itb == dictB.end() || !Equal(ita.second, itb->second)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ TValue& TValue::DoMerge(const TValue& delta, bool lowPriorityDelta) {
+ if (Same(*this, delta)) {
+ return *this;
+ }
+
+ using namespace NImpl;
+ return DoMergeImpl(delta, lowPriorityDelta, GetTlsInstance<TSelfLoopContext>(), GetTlsInstance<TSelfOverrideContext>());
+ }
+
+ TValue& TValue::DoMergeImpl(const TValue& delta, bool lowPriorityDelta,
+ NImpl::TSelfLoopContext& otherLoopCtx,
+ NImpl::TSelfOverrideContext& selfOverrideGuard) {
+ if (Same(*this, delta)) {
+ return *this;
+ }
+
+ if (delta.IsDict() && (!lowPriorityDelta || IsDict() || IsNull())) {
+ TScCore& core = CoreMutable();
+ const TScCore& deltaCore = delta.Core();
+
+ NImpl::TSelfLoopContext::TGuard loopCheck(otherLoopCtx, deltaCore);
+
+ if (!loopCheck.Ok) {
+ return *this; // a loop encountered (and asserted), skip the back reference
+ }
+
+ if (!lowPriorityDelta || IsNull()) {
+ SetDict();
+ }
+
+ const TDict& ddelta = deltaCore.Dict;
+
+ for (const auto& dit : ddelta) {
+ core.GetOrAdd(dit.first).DoMergeImpl(dit.second, lowPriorityDelta, otherLoopCtx, selfOverrideGuard);
+ }
+ } else if (!delta.IsNull() && (!lowPriorityDelta || IsNull())) {
+ DoCopyFromImpl(delta, otherLoopCtx, selfOverrideGuard);
+ }
+
+ return *this;
+ }
+
+ NJson::TJsonValue TValue::ToJsonValue() const {
+ using namespace NImpl;
+ return ToJsonValueImpl(GetTlsInstance<TSelfLoopContext>());
+ }
+
+ NJson::TJsonValue TValue::ToJsonValueImpl(NImpl::TSelfLoopContext& loopCtx) const {
+ const TScCore& core = Core();
+
+ switch (core.ValueType) {
+ default:
+ case EType::Null:
+ return NJson::TJsonValue(NJson::JSON_NULL);
+ case EType::Bool:
+ return NJson::TJsonValue(core.GetBool());
+ case EType::IntNumber:
+ return NJson::TJsonValue(core.GetIntNumber());
+ case EType::FloatNumber:
+ return NJson::TJsonValue(core.GetNumber());
+ case EType::String:
+ return NJson::TJsonValue(core.String);
+ case EType::Array: {
+ NImpl::TSelfLoopContext::TGuard loopGuard(loopCtx, core);
+
+ if (!loopGuard.Ok) {
+ return NJson::TJsonValue(NJson::JSON_NULL);
+ }
+
+ NJson::TJsonValue result(NJson::JSON_ARRAY);
+ const TArray& arr = core.Array;
+
+ for (const auto& item : arr) {
+ result.AppendValue(NJson::TJsonValue::UNDEFINED) = item.ToJsonValueImpl(loopCtx);
+ }
+
+ return result;
+ }
+ case EType::Dict: {
+ NImpl::TSelfLoopContext::TGuard loopGuard(loopCtx, core);
+
+ if (!loopGuard.Ok) {
+ return NJson::TJsonValue(NJson::JSON_NULL);
+ }
+
+ NJson::TJsonValue result(NJson::JSON_MAP);
+ const TDict& dict = core.Dict;
+
+ for (const auto& item : dict) {
+ result.InsertValue(item.first, NJson::TJsonValue::UNDEFINED) = item.second.ToJsonValueImpl(loopCtx);
+ }
+
+ return result;
+ }
+ }
+ }
+
+ TValue TValue::FromJsonValue(const NJson::TJsonValue& val) {
+ TValue result;
+ FromJsonValue(result, val);
+ return result;
+ }
+
+ TValue& TValue::FromJsonValue(TValue& res, const NJson::TJsonValue& val) {
+ TScCore& core = res.CoreMutableForSet();
+ core.SetNull();
+
+ switch (val.GetType()) {
+ default:
+ case NJson::JSON_UNDEFINED:
+ case NJson::JSON_NULL:
+ break;
+ case NJson::JSON_BOOLEAN:
+ core.SetBool(val.GetBoolean());
+ break;
+ case NJson::JSON_INTEGER:
+ core.SetIntNumber(val.GetInteger());
+ break;
+ case NJson::JSON_UINTEGER:
+ core.SetIntNumber(val.GetUInteger());
+ break;
+ case NJson::JSON_DOUBLE:
+ core.SetNumber(val.GetDouble());
+ break;
+ case NJson::JSON_STRING:
+ core.SetString(val.GetString());
+ break;
+ case NJson::JSON_ARRAY: {
+ core.SetArray();
+ for (const auto& item : val.GetArray()) {
+ FromJsonValue(core.Push(), item);
+ }
+ break;
+ }
+ case NJson::JSON_MAP: {
+ core.SetDict();
+ for (const auto& item : val.GetMap()) {
+ FromJsonValue(core.Add(item.first), item.second);
+ }
+ break;
+ }
+ }
+
+ return res;
+ }
+
+ struct TDefaults {
+ TValue::TPoolPtr Pool = MakeIntrusive<NDefinitions::TPool>();
+ TValue::TScCore Core{Pool};
+ };
+
+ const TValue::TScCore& TValue::DefaultCore() {
+ return Default<TDefaults>().Core;
+ }
+
+ const TArray& TValue::DefaultArray() {
+ return Default<TDefaults>().Core.Array;
+ }
+
+ const TDict& TValue::DefaultDict() {
+ return Default<TDefaults>().Core.Dict;
+ }
+
+ const TValue& TValue::DefaultValue() {
+ return *FastTlsSingleton<TValue>();
+ }
+
+ bool TValue::IsSameOrAncestorOf(const TValue& other) const {
+ using namespace NImpl;
+ return IsSameOrAncestorOfImpl(other.Core(), GetTlsInstance<TSelfLoopContext>());
+ }
+
+ bool TValue::IsSameOrAncestorOfImpl(const TScCore& other, NImpl::TSelfLoopContext& loopCtx) const {
+ const TScCore& core = Core();
+
+ if (&core == &other) {
+ return true;
+ }
+
+ switch (core.ValueType) {
+ default:
+ return false;
+ case EType::Array: {
+ NImpl::TSelfLoopContext::TGuard loopGuard(loopCtx, core);
+
+ if (!loopGuard.Ok) {
+ return false;
+ }
+
+ for (const auto& item : core.Array) {
+ if (item.IsSameOrAncestorOfImpl(other, loopCtx)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ case EType::Dict: {
+ NImpl::TSelfLoopContext::TGuard loopGuard(loopCtx, core);
+
+ if (!loopGuard.Ok) {
+ return false;
+ }
+
+ for (const auto& item : core.Dict) {
+ if (item.second.IsSameOrAncestorOfImpl(other, loopCtx)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+ }
+
+ namespace NPrivate {
+ int CompareStr(const NSc::TValue& a, TStringBuf b) {
+ return a.GetString().compare(b);
+ }
+
+ int CompareInt(const NSc::TValue& a, i64 r) {
+ i64 l = a.GetIntNumber();
+ return l < r ? -1 : l > r ? 1 : 0;
+ }
+
+ int CompareFloat(const NSc::TValue& a, double r) {
+ double l = a.GetNumber();
+ return l < r ? -1 : l > r ? 1 : 0;
+ }
+
+ }
+
+ bool operator==(const NSc::TValue& a, const NSc::TValue& b) {
+ return NSc::TValue::Equal(a, b);
+ }
+
+ bool operator!=(const NSc::TValue& a, const NSc::TValue& b) {
+ return !NSc::TValue::Equal(a, b);
+ }
+
+#define LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(T, Impl) \
+ bool operator==(const NSc::TValue& a, T b) { \
+ return NPrivate::Impl(a, b) == 0; \
+ } \
+ bool operator==(T b, const NSc::TValue& a) { \
+ return NPrivate::Impl(a, b) == 0; \
+ } \
+ bool operator!=(const NSc::TValue& a, T b) { \
+ return NPrivate::Impl(a, b) != 0; \
+ } \
+ bool operator!=(T b, const NSc::TValue& a) { \
+ return NPrivate::Impl(a, b) != 0; \
+ } \
+ bool operator<=(const NSc::TValue& a, T b) { \
+ return NPrivate::Impl(a, b) <= 0; \
+ } \
+ bool operator<=(T b, const NSc::TValue& a) { \
+ return NPrivate::Impl(a, b) >= 0; \
+ } \
+ bool operator>=(const NSc::TValue& a, T b) { \
+ return NPrivate::Impl(a, b) >= 0; \
+ } \
+ bool operator>=(T b, const NSc::TValue& a) { \
+ return NPrivate::Impl(a, b) <= 0; \
+ } \
+ bool operator<(const NSc::TValue& a, T b) { \
+ return NPrivate::Impl(a, b) < 0; \
+ } \
+ bool operator<(T b, const NSc::TValue& a) { \
+ return NPrivate::Impl(a, b) > 0; \
+ } \
+ bool operator>(const NSc::TValue& a, T b) { \
+ return NPrivate::Impl(a, b) > 0; \
+ } \
+ bool operator>(T b, const NSc::TValue& a) { \
+ return NPrivate::Impl(a, b) < 0; \
+ }
+
+#define LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS_IMPL(T) \
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(signed T, CompareInt) \
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(unsigned T, CompareInt)
+
+ //LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(bool, CompareInt)
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(char, CompareInt)
+ LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS_IMPL(char)
+ LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS_IMPL(short)
+ LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS_IMPL(int)
+ LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS_IMPL(long)
+ LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS_IMPL(long long)
+
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(float, CompareFloat)
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(double, CompareFloat)
+
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(TStringBuf, CompareStr)
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(const TString&, CompareStr)
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL(const char* const, CompareStr)
+
+#undef LIBRARY_SCHEME_DECLARE_TVALUE_OPS_IMPL
+#undef LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS_IMPL
+
+}
+
+template <>
+void Out<NSc::TValue>(IOutputStream& o, TTypeTraits<NSc::TValue>::TFuncParam v) {
+ o.Write(v.ToJson(true));
+}
diff --git a/library/cpp/scheme/scheme.h b/library/cpp/scheme/scheme.h
new file mode 100644
index 0000000000..3d7c59f3c9
--- /dev/null
+++ b/library/cpp/scheme/scheme.h
@@ -0,0 +1,538 @@
+#pragma once
+
+#include "scimpl_defs.h"
+
+#include "fwd.h"
+
+#include <iterator>
+#include <utility>
+
+namespace NSc {
+#ifdef _MSC_VER
+#pragma warning(disable : 4521 4522)
+#endif
+
+ // todo: try to remove some rarely used methods
+ class TValue {
+ public:
+ enum class EType {
+ Null = 0 /* "Null" */,
+ Bool /* "Bool" */,
+ IntNumber /* "Int" */,
+ FloatNumber /* "Float" */,
+ String /* "String" */,
+ Array /* "Array" */,
+ Dict /* "Dict" */
+ };
+
+ struct TScCore;
+ using TCorePtr = TIntrusivePtr<TScCore>;
+ using TPoolPtr = TIntrusivePtr<NDefinitions::TPool>;
+
+ using TArray = ::NSc::TArray;
+ using TDict = ::NSc::TDict;
+
+ private: // A TValue instance has only these 3 fields
+ mutable TCorePtr TheCore; // a pointer to a refcounted (kind of) variant
+ bool CopyOnWrite = false; // a flag that thevalue is a COW shallow copy and should produce a deep copy once modified
+
+ // Thus all copies of a TValue are by default shallow. Use TValue::Clone to force a deep copy.
+ // A COW copy will see changes in its parent, but no change in the COW copy will propagate to its parent.
+
+ public:
+ inline TValue();
+ inline TValue(TValue& v);
+ inline TValue(const TValue& v);
+ inline TValue(TValue&& v) noexcept;
+
+ public: // Operators
+ inline TValue(double t);
+ inline TValue(unsigned long long t);
+ inline TValue(unsigned long t);
+ inline TValue(unsigned t);
+ inline TValue(long long t);
+ inline TValue(long t);
+ inline TValue(int t);
+ // inline TValue(bool b);
+
+ inline TValue(TStringBuf t);
+ inline TValue(const char*);
+
+ inline operator double() const;
+ inline operator float() const;
+ inline operator long long() const;
+ inline operator long() const;
+ inline operator int() const;
+ inline operator short() const;
+ inline operator char() const;
+ inline operator unsigned long long() const;
+ inline operator unsigned long() const;
+ inline operator unsigned() const;
+ inline operator unsigned short() const;
+ inline operator unsigned char() const;
+ inline operator signed char() const;
+
+ inline operator TStringBuf() const;
+
+ inline operator const ::NSc::TArray&() const;
+ inline operator const ::NSc::TDict&() const;
+
+ inline TValue& operator=(double t);
+
+ inline TValue& operator=(unsigned long long t);
+ inline TValue& operator=(unsigned long t);
+ inline TValue& operator=(unsigned t);
+
+ inline TValue& operator=(long long t);
+ inline TValue& operator=(long t);
+ inline TValue& operator=(int t);
+ // inline TValue& operator=(bool t);
+
+ inline TValue& operator=(TStringBuf t);
+ inline TValue& operator=(const char* t);
+
+ inline TValue& operator=(TValue& v) &;
+ inline TValue& operator=(const TValue& v) &;
+ inline TValue& operator=(TValue&& v) & noexcept;
+
+ inline TValue& operator=(TValue& v) && = delete;
+ inline TValue& operator=(const TValue& v) && = delete;
+ inline TValue& operator=(TValue&& v) && = delete;
+
+ public:
+ template <class T> // ui16 or TStringBuf
+ inline TValue& operator[](const T& idx) {
+ return GetOrAdd(idx);
+ }
+
+ template <class T> // ui16 or TStringBuf
+ inline const TValue& operator[](const T& idx) const {
+ return Get(idx);
+ }
+
+ public: // Data methods ///////////////////////////////////////////////////////////
+ inline EType GetType() const;
+
+ inline bool IsNull() const;
+
+ inline TValue& SetNull(); // returns self, will set type to Null
+
+ TValue& Clear() {
+ return ClearArray().ClearDict().SetNull();
+ }
+
+ public: // Number methods /////////////////////////////////////////////////////////
+ // Bool, IntNumber and FloatNumber are all compatible.
+ // If a TValue node has one of the types it may as well be used as another.
+ // FloatNumber methods. Forces FloatNumber representation. Compatible with IntNumber and Bool
+
+ inline bool IsNumber() const; // true if any of FloatNumber, IntNumber, Bool
+
+ inline double GetNumber(double defaultval = 0) const; // Compatible with Bool, IntNumber and FloatNumber types
+
+ inline double& GetNumberMutable(double defaultval = 0); // Will switch the type to FloatNumber
+
+ inline TValue& SetNumber(double val = 0); // returns self, will switch the type to FloatNumber
+
+ double ForceNumber(double deflt = 0) const; // Best-effort cast to double (will do TryFromString if applicable)
+
+ // IntNumber methods. Forces integer representation. Compatible with FloatNumber and Bool types.
+ // Note: if you don't care about distinguishing bools, ints and doubles, use *Number methods above
+
+ inline bool IsIntNumber() const; // true only if IntNumber or Bool
+
+ inline i64 GetIntNumber(i64 defaultval = 0) const; // Compatible with Bool, IntNumber and FloatNumber types
+
+ inline i64& GetIntNumberMutable(i64 defaultval = 0); // Will switch the type to IntNumber
+
+ inline TValue& SetIntNumber(i64 val = 0); // returns self, will switch the type to IntNumber
+
+ i64 ForceIntNumber(i64 deflt = 0) const; // Best-effort cast to i64 (will do TryFromString for String)
+
+ // Bool methods. Forces bool representation. Compatible with Float Number and Int Number methods above.
+ // Note: if you don't care about distinguishing Bool, IntNumber and FloatNumber, use *Number methods above
+
+ inline bool IsBool() const; // true only if Bool
+
+ inline bool GetBool(bool defaultval = false) const; // Compatible with Bool, IntNumber and FloatNumber types
+
+ inline TValue& SetBool(bool val = false); // returns self, will switch the type to Bool
+
+ public: // Arcadia-specific boolean representation support
+ // Tests for explicit True, also checks for arcadia-specific boolean representation
+ bool IsTrue() const {
+ return IsNumber() ? GetNumber() : ::IsTrue(GetString());
+ }
+
+ // Tests for explicit False, also checks for arcadia-specific boolean representation
+ bool IsExplicitFalse() const {
+ return IsNumber() ? !GetNumber() : IsFalse(GetString());
+ }
+
+ public: // String methods /////////////////////////////////////////////////////////
+ inline bool IsString() const;
+
+ inline TStringBuf GetString(TStringBuf defaultval = TStringBuf()) const;
+
+ inline TValue& SetString(TStringBuf val = TStringBuf()); // returns self
+
+ TString ForceString(const TString& deflt = TString()) const; // Best-effort cast to TString (will do ToString for numeric types)
+
+ // todo: remove
+ inline bool StringEmpty() const;
+ inline size_t StringSize() const;
+
+ public: // Array methods //////////////////////////////////////////////////////////
+ inline bool IsArray() const;
+
+ inline const TArray& GetArray() const;
+ inline TArray& GetArrayMutable();
+ inline TValue& SetArray(); // turns into array if needed, returns self
+ inline TValue& ClearArray();
+
+ inline bool Has(size_t idx) const;
+
+ inline const TValue& Get(size_t idx) const; // returns child or default
+ inline TValue* GetNoAdd(size_t idx); // returns link to existing child or nullptr
+
+ inline TValue& Push(); // returns new child
+
+ template <class T>
+ TValue& Push(T&& t) {
+ return Push() = std::forward<T>(t);
+ } // returns new child
+
+ TValue& Insert(ui16 idx) {
+ return InsertUnsafe(idx);
+ } // creates missing values, returns new child
+
+ template <class T>
+ TValue& Insert(ui16 idx, T&& v) {
+ return InsertUnsafe(idx, std::forward<T>(v));
+ } // creates missing values, returns new child
+
+ template <class TIt>
+ inline TValue& AppendAll(TIt begin, TIt end); // Append(vec.begin(), vec.end())
+
+ template <class TColl>
+ inline TValue& AppendAll(TColl&& coll); // Append(vec)
+
+ inline TValue& AppendAll(std::initializer_list<TValue> coll);
+
+ TValue& GetOrAdd(ui16 idx) {
+ return GetOrAddUnsafe(idx);
+ } // creates missing values, returns new child
+
+ inline TValue& InsertUnsafe(size_t idx); // creates missing values, returns new child
+
+ template <class T>
+ TValue& InsertUnsafe(size_t idx, T&& t) {
+ return InsertUnsafe(idx) = std::forward<T>(t);
+ } // creates missing values, returns new child
+
+ inline TValue& GetOrAddUnsafe(size_t idx); // creates missing values, returns new child
+
+ inline TValue Pop(); // returns popped value
+ inline TValue Delete(size_t idx); // returns deleted value if it existed, NSc::Null() otherwise
+
+ inline TValue& Front() {
+ return GetOrAdd(0);
+ } // creates missing value, returns child
+ inline const TValue& Front() const {
+ return Get(0);
+ } // returns child or default
+
+ inline TValue& Back(); // creates missing value, returns child
+ inline const TValue& Back() const; // returns child or default
+
+ // todo: remove
+ inline bool ArrayEmpty() const;
+ inline size_t ArraySize() const;
+
+ public: // Dict methods
+ inline bool IsDict() const;
+
+ inline const TDict& GetDict() const;
+ inline TDict& GetDictMutable();
+ inline TValue& SetDict(); // turns into dict if not one, returns self
+ inline TValue& ClearDict();
+
+ inline bool Has(TStringBuf idx) const;
+
+ inline const TValue& Get(TStringBuf idx) const;
+ inline TValue* GetNoAdd(TStringBuf idx); // returns link to existing child or nullptr
+
+ TValue& Add(TStringBuf idx) {
+ return GetOrAdd(idx);
+ }
+
+ template <class T>
+ TValue& Add(TStringBuf idx, T&& t) {
+ return Add(idx) = std::forward<T>(t);
+ }
+
+ inline TValue& GetOrAdd(TStringBuf idx); // creates missing value, returns child
+
+ inline TValue Delete(TStringBuf idx); // returns deleted value
+
+ inline TValue& AddAll(std::initializer_list<std::pair<TStringBuf, TValue>> t);
+
+ TStringBufs DictKeys(bool sorted = true) const;
+ TStringBufs& DictKeys(TStringBufs&, bool sorted = true) const;
+
+ // todo: remove
+ inline bool DictEmpty() const;
+ inline size_t DictSize() const;
+
+ public: // Json methods ////////////////////////////////////////////////
+ using TJsonOpts = NSc::TJsonOpts;
+ using EJsonOpts = TJsonOpts::EJsonOpts;
+ static const EJsonOpts JO_DEFAULT = TJsonOpts::JO_DEFAULT;
+ static const EJsonOpts JO_SORT_KEYS = TJsonOpts::JO_SORT_KEYS;
+ static const EJsonOpts JO_SKIP_UNSAFE = TJsonOpts::JO_SKIP_UNSAFE; // skip non-utf8 strings
+ static const EJsonOpts JO_PRETTY = TJsonOpts::JO_PRETTY;
+ static const EJsonOpts JO_SAFE = TJsonOpts::JO_SAFE; // JO_SORT_KEYS | JO_SKIP_UNSAFE
+ static const EJsonOpts JO_PARSER_STRICT_WITH_COMMENTS = TJsonOpts::JO_PARSER_STRICT_WITH_COMMENTS; // strict json + strict utf8
+ static const EJsonOpts JO_PARSER_STRICT = TJsonOpts::JO_PARSER_STRICT; // strict json + strict utf8 + comments are disallowed
+ static const EJsonOpts JO_PARSER_DISALLOW_DUPLICATE_KEYS = TJsonOpts::JO_PARSER_DISALLOW_DUPLICATE_KEYS;
+
+ static TValue FromJson(TStringBuf, const TJsonOpts& = TJsonOpts());
+ static TValue FromJsonThrow(TStringBuf, const TJsonOpts& = TJsonOpts());
+ static bool FromJson(TValue&, TStringBuf, const TJsonOpts& = TJsonOpts());
+
+ // TODO: Переименовать ToJson в ToJsonUnsafe, а ToJsonSafe в ToJson
+ TString ToJson(const TJsonOpts& = TJsonOpts()) const;
+ const TValue& ToJson(IOutputStream&, const TJsonOpts& = TJsonOpts()) const; // returns self
+
+ // ToJson(JO_SORT_KEYS | JO_SKIP_UNSAFE)
+ TString ToJsonSafe(const TJsonOpts& = TJsonOpts()) const;
+ const TValue& ToJsonSafe(IOutputStream&, const TJsonOpts& = TJsonOpts()) const;
+
+ // ToJson(JO_SORT_KEYS | JO_PRETTY | JO_SKIP_UNSAFE)
+ TString ToJsonPretty(const TJsonOpts& = TJsonOpts()) const;
+ const TValue& ToJsonPretty(IOutputStream&, const TJsonOpts& = TJsonOpts()) const;
+
+ NJson::TJsonValue ToJsonValue() const;
+
+ static TValue FromJsonValue(const NJson::TJsonValue&);
+ static TValue& FromJsonValue(TValue&, const NJson::TJsonValue&); // returns self
+
+ static TJsonOpts MakeOptsSafeForSerializer(TJsonOpts = TJsonOpts());
+ static TJsonOpts MakeOptsPrettyForSerializer(TJsonOpts = TJsonOpts());
+
+ public: // Merge methods ////////////////////////////////////////////////
+ /*
+ * LHS.MergeUpdate(RHS):
+ * 1. Dict <- Dict:
+ * - Copy all nonconflicting key-value pairs from RHS to LHS.
+ * - For every pair of conflicting values apply LHS[key].MergeUpdate(RHS[key]).
+ * 2. Anything <- Null:
+ * - Do nothing.
+ * 3. Other conflicts:
+ * - Copy RHS over LHS.
+ *
+ * LHS.ReverseMerge(RHS):
+ * 1. Dict <- Dict:
+ * - Copy all nonconflicting key-value pairs from RHS to LHS.
+ * - For every pair of conflicting values apply LHS[key].ReverseMerge(RHS[key]).
+ * 2. Null <- Anything:
+ * - Copy RHS over LHS.
+ * 3. Other conflicts:
+ * - Do nothing.
+ */
+
+ TValue& MergeUpdateJson(TStringBuf json); // returns self
+ TValue& ReverseMergeJson(TStringBuf json); // returns self
+
+ static bool MergeUpdateJson(TValue&, TStringBuf json); // returns true unless failed to parse the json
+ static bool ReverseMergeJson(TValue&, TStringBuf json); // returns true unless failed to parse the json
+
+ TValue& MergeUpdate(const TValue& delta); // return self
+ TValue& ReverseMerge(const TValue& delta); // return self
+
+ public: // Path methods /////////////////////////////////////////////////////////
+ // TODO: add throwing variants
+ // make sure to properly escape the tokens
+
+ static TString EscapeForPath(TStringBuf rawKey); // converts a raw dict key into a valid token for a selector path
+
+ static bool PathValid(TStringBuf path); // returns true if the path is syntactically valid
+
+ bool PathExists(TStringBuf path) const; // returns true if the path is syntactically valid and the target value exists
+
+ const TValue& TrySelect(TStringBuf path) const; // returns the target value
+ // if the path is syntactically valid and the target value exists
+ // otherwise returns NSc::Null()
+
+ TValue* TrySelectOrAdd(TStringBuf path); // returns the target value if it exists or creates if not
+ // if the path is syntactically valid
+ // otherwise returns NSc::Null()
+
+ TValue TrySelectAndDelete(TStringBuf path); // deletes and returns the target value
+ // if the path is syntactically valid and the target value existed
+ // otherwise returns NSc::Null()
+
+ public: // Copy methods /////////////////////////////////////////////////////////
+ TValue Clone() const; // returns deep copy of self (on the separate pool)
+ TValue& CopyFrom(const TValue& other); // deep copy other value into self, returns self
+
+ TValue& Swap(TValue& v);
+
+ static bool Same(const TValue&, const TValue&); // point to the same core
+ static bool Equal(const TValue&, const TValue&); // recursively equal
+ static bool SamePool(const TValue&, const TValue&); // share arena
+
+ public:
+ // very specific methods useful in very specific corner cases
+
+ static TValue From(const ::google::protobuf::Message&, bool mapAsDict = false);
+
+ void To(::google::protobuf::Message&, const TProtoOpts& opts = {}) const;
+
+ public:
+ inline explicit TValue(TPoolPtr&);
+
+ static const TScCore& DefaultCore();
+ static const TArray& DefaultArray();
+ static const TDict& DefaultDict();
+ static const TValue& DefaultValue();
+ static const TValue& Null() {
+ return DefaultValue();
+ }
+
+ void DoWriteJsonImpl(IOutputStream&, const TJsonOpts&, NImpl::TKeySortContext&, NImpl::TSelfLoopContext&) const;
+
+ bool IsSameOrAncestorOf(const TValue& other) const;
+
+ private:
+ TValue& DoMerge(const TValue& delta, bool olddelta);
+ TValue& DoMergeImpl(const TValue& delta, bool olddelta, NImpl::TSelfLoopContext&, NImpl::TSelfOverrideContext&);
+ TValue& DoCopyFromImpl(const TValue& other, NImpl::TSelfLoopContext&, NImpl::TSelfOverrideContext&);
+ NJson::TJsonValue ToJsonValueImpl(NImpl::TSelfLoopContext&) const;
+
+ bool IsSameOrAncestorOfImpl(const TScCore& other, NImpl::TSelfLoopContext& loopCtx) const;
+
+ inline TScCore& CoreMutable();
+ inline TScCore& CoreMutableForSet();
+ inline const TScCore& Core() const;
+
+ static inline TScCore* NewCore(TPoolPtr&);
+
+ static TValue FromField(const ::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*);
+ static TValue FromRepeatedField(const ::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, int index);
+
+ void ValueToField(const TValue& value, ::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const;
+ void ToField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const;
+ void ToEnumField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const;
+ void ToRepeatedField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const;
+ void ToMapField(::google::protobuf::Message&, const ::google::protobuf::FieldDescriptor*, const TProtoOpts& opts) const;
+ };
+
+
+ inline const TValue& Null() {
+ return TValue::DefaultValue();
+ }
+
+
+ class TArray: public TDeque<TValue, TPoolAllocator>, TNonCopyable {
+ using TParent = TDeque<TValue, TPoolAllocator>;
+
+ public:
+ TArray(TMemoryPool* p)
+ : TParent(p)
+ {
+ }
+
+ template <class TIt>
+ void AppendAll(TIt begin, TIt end) {
+ TParent::insert(TParent::end(), begin, end);
+ }
+
+ template <class TColl>
+ void AppendAll(TColl&& coll) {
+ AppendAll(std::begin(coll), std::end(coll));
+ }
+
+ void AppendAll(std::initializer_list<TValue> coll) {
+ AppendAll(coll.begin(), coll.end());
+ }
+
+ const TValue& operator[](size_t i) const {
+ return EnsureIndex(i);
+ }
+
+ TValue& operator[](size_t i) {
+ return EnsureIndex(i);
+ }
+
+ const TValue& front() const {
+ return EnsureIndex(0);
+ }
+
+ TValue& front() {
+ return EnsureIndex(0);
+ }
+
+ const TValue& back() const {
+ return EnsureIndex(LastIndex());
+ }
+
+ TValue& back() {
+ return EnsureIndex(LastIndex());
+ }
+
+ void pop_back() {
+ if (empty())
+ return;
+ TParent::pop_back();
+ }
+
+ void pop_front() {
+ if (empty())
+ return;
+ TParent::pop_front();
+ }
+
+ private:
+ size_t LastIndex() const {
+ return ::Max<size_t>(size(), 1) - 1;
+ }
+
+ TValue& EnsureIndex(size_t i) {
+ if (i >= size())
+ resize(::Min<size_t>(i + 1, ::Max<ui16>()), TValue::DefaultValue());
+ return TParent::operator[](i);
+ }
+
+ const TValue& EnsureIndex(size_t i) const {
+ return i < size() ? TParent::operator[](i) : TValue::DefaultValue();
+ }
+ };
+
+
+ // todo: densehashtable
+ // todo: allow insertions
+ // todo: make TDict methods safe
+ class TDict: public THashMap<TStringBuf, TValue, THash<TStringBuf>, TEqualTo<TStringBuf>, TPoolAllocator>, TNonCopyable {
+ using TParent = THashMap<TStringBuf, TValue, THash<TStringBuf>, TEqualTo<TStringBuf>, TPoolAllocator>;
+
+ public:
+ TDict(TMemoryPool* p)
+ : TParent(p)
+ {
+ }
+
+ template <class TStr>
+ const TValue& Get(const TStr& key) const {
+ const_iterator it = find(key);
+ return it != end() ? it->second : TValue::DefaultValue();
+ }
+ };
+}
+
+#include "scimpl.h"
+#include "scheme_cast.h"
+
+#ifdef _MSC_VER
+#pragma warning(default : 4521 4522)
+#endif
diff --git a/library/cpp/scheme/scheme_cast.h b/library/cpp/scheme/scheme_cast.h
new file mode 100644
index 0000000000..00839e8017
--- /dev/null
+++ b/library/cpp/scheme/scheme_cast.h
@@ -0,0 +1,321 @@
+#pragma once
+
+#include <util/generic/set.h>
+#include <util/generic/vector.h>
+#include <util/generic/map.h>
+#include <util/generic/hash.h>
+#include <util/generic/hash_set.h>
+#include <util/string/cast.h>
+#include <util/generic/yexception.h>
+
+#include "scheme.h"
+
+namespace NJsonConverters {
+ class IJsonSerializable {
+ public:
+ virtual NSc::TValue ToTValue() const = 0;
+ virtual void FromTValue(const NSc::TValue&, const bool validate) = 0;
+
+ const TString ToJson(const bool sort = false) const {
+ return ToTValue().ToJson(sort);
+ };
+
+ void FromJson(const TStringBuf& json, const bool validate = false) {
+ NSc::TValue v = NSc::TValue::FromJson(json);
+ FromTValue(v, validate);
+ }
+
+ virtual ~IJsonSerializable(){};
+ };
+ //////////////////////////////////////////////////////////////////////
+ // fwd declarations
+ //////////////////////////////////////////////////////////////////////
+
+ //TVector
+ template <typename T, typename A>
+ NSc::TValue ToTValue(const TVector<T, A>& x);
+ template <typename T, typename A>
+ void FromTValue(const NSc::TValue& x, TVector<T, A>& out, const bool validate);
+
+ //THashMap
+ template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
+ NSc::TValue ToTValue(const THashMap<Key, T, HashFcn, EqualKey, Alloc>& x);
+ template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
+ void FromTValue(const NSc::TValue& x, THashMap<Key, T, HashFcn, EqualKey, Alloc>& out, const bool validate);
+
+ //TMap
+ template <class K, class V, class Less, class A>
+ NSc::TValue ToTValue(const TMap<K, V, Less, A>& x);
+ template <class K, class V, class Less, class A>
+ void FromTValue(const NSc::TValue& x, TMap<K, V, Less, A>& out, const bool validate);
+
+ //THashSet
+ template <class V, class H, class E, class A>
+ NSc::TValue ToTValue(const THashSet<V, H, E, A>& x);
+ template <class V, class H, class E, class A>
+ void FromTValue(const NSc::TValue& x, THashSet<V, H, E, A>& out, const bool validate);
+
+ //TSet
+ template <class K, class L, class A>
+ NSc::TValue ToTValue(const TSet<K, L, A>& x);
+ template <class K, class L, class A>
+ void FromTValue(const NSc::TValue& x, TSet<K, L, A>& out, const bool validate);
+
+ //std::pair
+ template <class T1, class T2>
+ NSc::TValue ToTValue(const std::pair<T1, T2>& x);
+ template <class T1, class T2>
+ void FromTValue(const NSc::TValue& x, std::pair<T1, T2>& out, const bool validate);
+
+ //////////////////////////////////////////////////////////////////////
+ // simple From, To helpers
+ //////////////////////////////////////////////////////////////////////
+ template <typename T, bool HasSerializer>
+ struct TValueAndStrokaConv {};
+
+ template <typename T>
+ struct TValueAndStrokaConv<T, 0> {
+ static NSc::TValue ToTValue(const T& x) {
+ return NSc::TValue(x);
+ }
+
+ static void FromTValue(const NSc::TValue& x, T& out, const bool) {
+ out = x;
+ }
+
+ static TString ToString(const T& x) {
+ return ::ToString(x);
+ }
+
+ static void FromString(const TStringBuf& str, T& res, const bool) {
+ res = ::FromString<T>(str);
+ }
+ };
+
+ template <typename T>
+ struct TValueAndStrokaConv<T, 1> {
+ static NSc::TValue ToTValue(const T& x) {
+ return x.ToTValue();
+ }
+
+ static void FromTValue(const NSc::TValue& x, T& out, const bool validate) {
+ out.FromTValue(x, validate);
+ }
+
+ static TString ToString(const T& x) {
+ return x.ToJson();
+ }
+
+ static void FromString(const TStringBuf& str, T& res, const bool validate) {
+ res.FromJson(str, validate);
+ }
+ };
+
+ template <typename T>
+ NSc::TValue ToTValue(const T& x) {
+ return TValueAndStrokaConv<T, std::is_base_of<IJsonSerializable, T>::value>::ToTValue(x);
+ }
+
+ template <typename T>
+ void FromTValue(const NSc::TValue& x, T& out, const bool validate) {
+ return TValueAndStrokaConv<T, std::is_base_of<IJsonSerializable, T>::value>::FromTValue(x, out, validate);
+ }
+
+ template <typename T>
+ T FromTValue(const NSc::TValue& x, const bool validate) {
+ T ret;
+ FromTValue(x, ret, validate);
+ return ret;
+ }
+
+ template <typename T>
+ TString ToString(const T& x) {
+ return TValueAndStrokaConv<T, std::is_base_of<IJsonSerializable, T>::value>::ToString(x);
+ }
+
+ template <typename T>
+ void FromString(const TStringBuf& str, T& res, const bool validate) {
+ return TValueAndStrokaConv<T, std::is_base_of<IJsonSerializable, T>::value>::FromString(str, res, validate);
+ }
+
+ template <typename T>
+ T FromString(const TStringBuf& str, bool validate) {
+ T ret;
+ FromString(str, ret, validate);
+ return ret;
+ }
+
+ namespace NPrivate {
+ template <typename T>
+ NSc::TValue ToTValueDict(const T& dict) {
+ NSc::TValue out;
+ out.SetDict();
+ for (typename T::const_iterator it = dict.begin(); it != dict.end(); ++it) {
+ out[ToString(it->first)] = NJsonConverters::ToTValue(it->second);
+ }
+ return out;
+ }
+
+ template <typename T>
+ void FromTValueDict(const NSc::TValue& x, T& out, bool validate) {
+ typedef typename T::key_type TKey;
+ typedef typename T::mapped_type TMapped;
+ if (validate)
+ Y_ENSURE(x.IsDict() || x.IsNull(), "not valid input scheme");
+ out.clear();
+ if (x.IsDict()) {
+ const NSc::TDict& dict = x.GetDict();
+ for (const auto& it : dict) {
+ TKey key = NJsonConverters::FromString<TKey>(it.first, validate);
+ TMapped val = NJsonConverters::FromTValue<TMapped>(it.second, validate);
+ out.insert(std::pair<TKey, TMapped>(key, val));
+ }
+ }
+ }
+
+ template <typename T>
+ NSc::TValue ToTValueSet(const T& set) {
+ NSc::TValue out;
+ out.SetDict();
+ for (typename T::const_iterator it = set.begin(); it != set.end(); ++it) {
+ out[ToString(*it)] = NSc::Null();
+ }
+ return out;
+ }
+
+ template <typename T>
+ void FromTValueSet(const NSc::TValue& x, T& out, const bool validate) {
+ typedef typename T::key_type TKey;
+ if (validate)
+ Y_ENSURE(x.IsDict() || x.IsNull(), "not valid input scheme");
+ out.clear();
+ if (x.IsDict()) {
+ const NSc::TDict& dict = x.GetDict();
+ for (const auto& it : dict) {
+ TKey key;
+ NJsonConverters::FromString<TKey>(it.first, key, validate);
+ out.insert(key);
+ }
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // TVector
+ //////////////////////////////////////////////////////////////////////
+ template <typename T, typename A>
+ NSc::TValue ToTValue(const TVector<T, A>& x) {
+ NSc::TValue out;
+ out.SetArray();
+ for (typename TVector<T, A>::const_iterator it = x.begin(); it != x.end(); ++it)
+ out.Push(NJsonConverters::ToTValue(*it));
+ return out;
+ }
+
+ template <typename T, typename A>
+ void FromTValue(const NSc::TValue& x, TVector<T, A>& out, const bool validate) {
+ if (validate)
+ Y_ENSURE(x.IsArray() || x.IsNull(), "not valid input scheme");
+ out.clear();
+ if (x.IsArray()) {
+ const NSc::TArray& arr = x.GetArray();
+ out.reserve(arr.size());
+ for (const auto& it : arr) {
+ T val;
+ NJsonConverters::FromTValue(it, val, validate);
+ out.push_back(val);
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // THashMap & TMap
+ //////////////////////////////////////////////////////////////////////
+ template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
+ NSc::TValue ToTValue(const THashMap<Key, T, HashFcn, EqualKey, Alloc>& x) {
+ return NPrivate::ToTValueDict(x);
+ }
+
+ template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
+ void FromTValue(const NSc::TValue& x, THashMap<Key, T, HashFcn, EqualKey, Alloc>& out, const bool validate) {
+ NPrivate::FromTValueDict(x, out, validate);
+ }
+
+ template <class K, class V, class Less, class A>
+ NSc::TValue ToTValue(const TMap<K, V, Less, A>& x) {
+ return NPrivate::ToTValueDict(x);
+ }
+
+ template <class K, class V, class Less, class A>
+ void FromTValue(const NSc::TValue& x, TMap<K, V, Less, A>& out, const bool validate) {
+ NPrivate::FromTValueDict(x, out, validate);
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // THashSet & TSet
+ //////////////////////////////////////////////////////////////////////
+ template <class V, class H, class E, class A>
+ NSc::TValue ToTValue(const THashSet<V, H, E, A>& x) {
+ return NPrivate::ToTValueSet(x);
+ }
+
+ template <class V, class H, class E, class A>
+ void FromTValue(const NSc::TValue& x, THashSet<V, H, E, A>& out, const bool validate) {
+ NPrivate::FromTValueSet(x, out, validate);
+ }
+
+ template <class K, class L, class A>
+ NSc::TValue ToTValue(const TSet<K, L, A>& x) {
+ return NPrivate::ToTValueSet(x);
+ }
+
+ template <class K, class L, class A>
+ void FromTValue(const NSc::TValue& x, TSet<K, L, A>& out, const bool validate) {
+ NPrivate::FromTValueSet(x, out, validate);
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // std::pair
+ //////////////////////////////////////////////////////////////////////
+ template <class T1, class T2>
+ NSc::TValue ToTValue(const std::pair<T1, T2>& x) {
+ NSc::TValue out;
+ out.SetArray();
+ out.Push(NJsonConverters::ToTValue(x.first));
+ out.Push(NJsonConverters::ToTValue(x.second));
+ return out;
+ }
+
+ template <class T1, class T2>
+ void FromTValue(const NSc::TValue& x, std::pair<T1, T2>& out, const bool validate) {
+ if (validate)
+ Y_ENSURE(x.IsArray() || x.IsNull(), "not valid input scheme");
+ if (x.IsArray()) {
+ const NSc::TArray& arr = x.GetArray();
+ if (arr.size() == 2) {
+ T1 val0;
+ T2 val1;
+ NJsonConverters::FromTValue(arr[0], val0, validate);
+ NJsonConverters::FromTValue(arr[1], val1, validate);
+ out.first = val0;
+ out.second = val1;
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // global user functions
+ //////////////////////////////////////////////////////////////////////
+ template <typename T>
+ TString ToJson(const T& val, const bool sort = false) {
+ return NJsonConverters::ToTValue(val).ToJson(sort);
+ }
+
+ template <typename T>
+ T FromJson(const TStringBuf& json, bool validate = false) {
+ NSc::TValue v = NSc::TValue::FromJson(json);
+ T ret;
+ NJsonConverters::FromTValue(v, ret, validate);
+ return ret;
+ }
+}
diff --git a/library/cpp/scheme/scimpl.h b/library/cpp/scheme/scimpl.h
new file mode 100644
index 0000000000..4f68f16290
--- /dev/null
+++ b/library/cpp/scheme/scimpl.h
@@ -0,0 +1,858 @@
+#pragma once
+
+#include "scheme.h"
+
+#include <util/stream/output.h>
+
+namespace NSc {
+ struct TValue::TScCore : TAtomicRefCount<TScCore, TDestructor>, TNonCopyable {
+ TPoolPtr Pool;
+ double FloatNumber = 0;
+ i64 IntNumber = 0;
+ TStringBuf String;
+ TDict Dict;
+ TArray Array;
+ TValue::EType ValueType = TValue::EType::Null;
+
+ TScCore(TPoolPtr& p)
+ : Pool(p)
+ , Dict(Pool->Get())
+ , Array(Pool->Get())
+ {
+ }
+
+ bool IsNull() const {
+ return TValue::EType::Null == ValueType;
+ }
+
+ bool IsBool() const {
+ return TValue::EType::Bool == ValueType;
+ }
+
+ bool IsIntNumber() const {
+ return TValue::EType::IntNumber == ValueType || IsBool();
+ }
+
+ bool IsNumber() const {
+ return TValue::EType::FloatNumber == ValueType || IsIntNumber();
+ }
+
+ bool IsString() const {
+ return TValue::EType::String == ValueType;
+ }
+
+ bool IsArray() const {
+ return TValue::EType::Array == ValueType;
+ }
+
+ bool IsDict() const {
+ return TValue::EType::Dict == ValueType;
+ }
+
+ bool HasChildren() const {
+ return GetDict().size() + GetArray().size();
+ }
+
+ void SetNull() {
+ ValueType = TValue::EType::Null;
+ }
+
+ void SetArray() {
+ if (Y_LIKELY(IsArray())) {
+ return;
+ }
+
+ ValueType = TValue::EType::Array;
+ Array.clear();
+ }
+
+ void SetDict() {
+ if (Y_LIKELY(IsDict())) {
+ return;
+ }
+
+ ValueType = TValue::EType::Dict;
+ Dict.clear();
+ }
+
+ void SetNumber(double n) {
+ ValueType = TValue::EType::FloatNumber;
+ FloatNumber = n;
+ }
+
+ void SetIntNumber(i64 n) {
+ ValueType = TValue::EType::IntNumber;
+ IntNumber = n;
+ }
+
+ void SetBool(bool b) {
+ ValueType = TValue::EType::Bool;
+ IntNumber = b;
+ }
+
+ void SetString(TStringBuf s) {
+ SetOwnedString(Pool->AppendBuf(s));
+ }
+
+ void SetOwnedString(TStringBuf s) {
+ ValueType = TValue::EType::String;
+ String = s;
+ }
+
+ double& GetNumberMutable(double defaultnum) {
+ switch (ValueType) {
+ case TValue::EType::Bool:
+ SetNumber(bool(IntNumber));
+ break;
+ case TValue::EType::IntNumber:
+ SetNumber(IntNumber);
+ break;
+ case TValue::EType::FloatNumber:
+ break;
+ default:
+ SetNumber(defaultnum);
+ break;
+ }
+
+ return FloatNumber;
+ }
+
+ i64& GetIntNumberMutable(i64 defaultnum) {
+ switch (ValueType) {
+ case TValue::EType::Bool:
+ SetIntNumber(bool(IntNumber));
+ break;
+ case TValue::EType::IntNumber:
+ break;
+ case TValue::EType::FloatNumber:
+ SetIntNumber(FloatNumber);
+ break;
+ default:
+ SetIntNumber(defaultnum);
+ break;
+ }
+
+ return IntNumber;
+ }
+
+ void ClearArray() {
+ if (!IsArray()) {
+ return;
+ }
+
+ Array.clear();
+ }
+
+ void ClearDict() {
+ if (!IsDict()) {
+ return;
+ }
+
+ Dict.clear();
+ }
+
+ double GetNumber(double d = 0) const {
+ switch (ValueType) {
+ case TValue::EType::Bool:
+ return (bool)IntNumber;
+ case TValue::EType::IntNumber:
+ return IntNumber;
+ case TValue::EType::FloatNumber:
+ return FloatNumber;
+ default:
+ return d;
+ }
+ }
+
+ i64 GetIntNumber(i64 n = 0) const {
+ switch (ValueType) {
+ case TValue::EType::Bool:
+ return (bool)IntNumber;
+ case TValue::EType::IntNumber:
+ return IntNumber;
+ case TValue::EType::FloatNumber:
+ return FloatNumber;
+ default:
+ return n;
+ }
+ }
+
+ bool GetBool(bool b = false) const {
+ return GetIntNumber(b);
+ }
+
+ TStringBuf GetString(TStringBuf s = TStringBuf()) const {
+ return IsString() ? String : s;
+ }
+
+ const TArray& GetArray() const {
+ return IsArray() ? Array : TValue::DefaultArray();
+ }
+
+ TArray& GetArrayMutable() {
+ SetArray();
+ return Array;
+ }
+
+ TDict& GetDictMutable() {
+ SetDict();
+ return Dict;
+ }
+
+ const TDict& GetDict() const {
+ return IsDict() ? Dict : TValue::DefaultDict();
+ }
+
+ static void DoPush(TPoolPtr& p, TArray& a) {
+ a.push_back(TValue(p));
+ a.back().CopyOnWrite = false;
+ }
+
+ TValue& Push() {
+ SetArray();
+ DoPush(Pool, Array);
+ return Array.back();
+ }
+
+ TValue Pop() {
+ if (!IsArray() || Array.empty()) {
+ return TValue::DefaultValue();
+ }
+
+ TValue v = Array.back();
+ Array.pop_back();
+ return v;
+ }
+
+ const TValue& Get(size_t key) const {
+ return IsArray() && Array.size() > key ? Array[key] : TValue::DefaultValue();
+ }
+
+ TValue* GetNoAdd(size_t key) {
+ return IsArray() && Array.size() > key ? &Array[key] : nullptr;
+ }
+
+ TValue& GetOrAdd(size_t key) {
+ SetArray();
+ for (size_t i = Array.size(); i <= key; ++i) {
+ DoPush(Pool, Array);
+ }
+
+ return Array[key];
+ }
+
+ TValue& Back() {
+ SetArray();
+
+ if (Array.empty()) {
+ DoPush(Pool, Array);
+ }
+
+ return Array.back();
+ }
+
+ TValue& Insert(size_t key) {
+ SetArray();
+
+ if (Array.size() <= key) {
+ return GetOrAdd(key);
+ } else {
+ Array.insert(Array.begin() + key, TValue(Pool));
+ Array[key].CopyOnWrite = false;
+ return Array[key];
+ }
+ }
+
+ TValue Delete(size_t key) {
+ if (!IsArray() || Array.size() <= key) {
+ return TValue::DefaultValue();
+ }
+
+ TValue v = Array[key];
+ Array.erase(Array.begin() + key);
+ return v;
+ }
+
+ const TValue& Get(TStringBuf key) const {
+ if (!IsDict()) {
+ return TValue::DefaultValue();
+ }
+
+ TDict::const_iterator it = Dict.find(key);
+ return it != Dict.end() ? it->second : TValue::DefaultValue();
+ }
+
+ TValue* GetNoAdd(TStringBuf key) {
+ if (!IsDict()) {
+ return nullptr;
+ }
+
+ return Dict.FindPtr(key);
+ }
+
+ TValue& Add(TStringBuf key) {
+ SetDict();
+ TDict::iterator it = Dict.insert(std::make_pair(Pool->AppendBuf(key), TValue(Pool))).first;
+ it->second.CopyOnWrite = false;
+ return it->second;
+ }
+
+ TValue& GetOrAdd(TStringBuf key) {
+ SetDict();
+ TDict::insert_ctx ctx;
+ TDict::iterator it = Dict.find(key, ctx);
+
+ if (it == Dict.end()) {
+ it = Dict.insert_direct(std::make_pair(Pool->AppendBuf(key), TValue(Pool)), ctx);
+ it->second.CopyOnWrite = false;
+ }
+
+ return it->second;
+ }
+
+ TValue Delete(TStringBuf key) {
+ if (!IsDict()) {
+ return TValue::DefaultValue();
+ }
+
+ TDict::iterator it = Dict.find(key);
+
+ if (it == Dict.end()) {
+ return TValue::DefaultValue();
+ }
+
+ TValue v = it->second;
+ Dict.erase(key);
+ return v;
+ }
+ };
+
+ TValue::TScCore* TValue::NewCore(TPoolPtr& p) {
+ return new (p->Pool.Allocate<TScCore>()) TScCore(p);
+ }
+
+ TValue::TValue() {
+ auto p = TPoolPtr(new NDefinitions::TPool);
+ TheCore = NewCore(p);
+ }
+
+ TValue::TValue(double t)
+ : TValue()
+ {
+ SetNumber(t);
+ }
+
+ TValue::TValue(unsigned long long t)
+ : TValue()
+ {
+ SetIntNumber(t);
+ }
+
+ TValue::TValue(unsigned long t)
+ : TValue()
+ {
+ SetIntNumber(t);
+ }
+
+ TValue::TValue(unsigned t)
+ : TValue()
+ {
+ SetIntNumber(t);
+ }
+
+ TValue::TValue(long long t)
+ : TValue()
+ {
+ SetIntNumber(t);
+ }
+
+ TValue::TValue(long t)
+ : TValue()
+ {
+ SetIntNumber(t);
+ }
+
+ TValue::TValue(int t)
+ : TValue()
+ {
+ SetIntNumber(t);
+ }
+
+ //TValue::TValue(bool t)
+ // : TValue()
+ //{
+ // SetBool(t);
+ //}
+
+ TValue::TValue(TStringBuf t)
+ : TValue()
+ {
+ SetString(t);
+ }
+
+ TValue::TValue(const char* t)
+ : TValue()
+ {
+ SetString(t);
+ }
+
+ TValue::TValue(TValue& v)
+ : TheCore(v.TheCore)
+ , CopyOnWrite(v.CopyOnWrite)
+ {
+ }
+
+ TValue::TValue(const TValue& v)
+ : TheCore(v.TheCore)
+ , CopyOnWrite(true)
+ {
+ }
+
+ TValue::TValue(TValue&& v) noexcept
+ : TheCore(std::move(v.TheCore))
+ , CopyOnWrite(v.CopyOnWrite)
+ {}
+
+ TValue::operator double() const {
+ return GetNumber();
+ }
+
+ TValue::operator float() const {
+ return GetNumber();
+ }
+
+ TValue::operator long long() const {
+ return GetIntNumber();
+ }
+
+ TValue::operator long() const {
+ return GetIntNumber();
+ }
+
+ TValue::operator int() const {
+ return GetIntNumber();
+ }
+
+ TValue::operator short() const {
+ return GetIntNumber();
+ }
+
+ TValue::operator char() const {
+ return GetIntNumber();
+ }
+
+ TValue::operator unsigned long long() const {
+ return GetIntNumber();
+ }
+
+ TValue::operator unsigned long() const {
+ return GetIntNumber();
+ }
+
+ TValue::operator unsigned() const {
+ return GetIntNumber();
+ }
+
+ TValue::operator unsigned short() const {
+ return GetIntNumber();
+ }
+
+ TValue::operator unsigned char() const {
+ return GetIntNumber();
+ }
+
+ TValue::operator signed char() const {
+ return GetIntNumber();
+ }
+
+ TValue::operator TStringBuf() const {
+ return GetString();
+ }
+
+ TValue::operator const ::NSc::TArray&() const {
+ return GetArray();
+ }
+
+ TValue::operator const ::NSc::TDict&() const {
+ return GetDict();
+ }
+
+ TValue& TValue::operator=(double t) {
+ return SetNumber(t);
+ }
+
+ TValue& TValue::operator=(unsigned long long t) {
+ return SetIntNumber(t);
+ }
+
+ TValue& TValue::operator=(unsigned long t) {
+ return SetIntNumber(t);
+ }
+
+ TValue& TValue::operator=(unsigned t) {
+ return SetIntNumber(t);
+ }
+
+ TValue& TValue::operator=(long long t) {
+ return SetIntNumber(t);
+ }
+
+ TValue& TValue::operator=(long t) {
+ return SetIntNumber(t);
+ }
+
+ TValue& TValue::operator=(int t) {
+ return SetIntNumber(t);
+ }
+
+ //TValue& TValue::operator=(bool t) {
+ // return SetBool(t);
+ //}
+
+ TValue& TValue::operator=(TStringBuf t) {
+ return SetString(t);
+ }
+
+ TValue& TValue::operator=(const char* t) {
+ return SetString(t);
+ }
+
+ TValue& TValue::operator=(TValue& v) & {
+ if (!Same(*this, v)) {
+ //Extend TheCore lifetime not to trigger possible v deletion via parent-child chain
+ auto tmpCore = TheCore;
+ TheCore = v.TheCore;
+ CopyOnWrite = v.CopyOnWrite;
+ }
+ return *this;
+ }
+
+ TValue& TValue::operator=(const TValue& v) & {
+ if (!Same(*this, v)) {
+ //Extend TheCore lifetime not to trigger possible v deletion via parent-child chain
+ auto tmpCore = TheCore;
+ TheCore = v.TheCore;
+ CopyOnWrite = true;
+ }
+ return *this;
+ }
+
+ TValue& TValue::operator=(TValue&& v) & noexcept {
+ if (!Same(*this, v)) {
+ //Extend TheCore lifetime not to trigger possible v deletion via parent-child chain
+ auto tmpCore = TheCore;
+ TheCore = std::move(v.TheCore);
+ CopyOnWrite = v.CopyOnWrite;
+ }
+ return *this;
+ }
+
+ bool TValue::Has(size_t idx) const {
+ return IsArray() && GetArray().size() > idx;
+ }
+
+ bool TValue::Has(TStringBuf s) const {
+ return GetDict().contains(s);
+ }
+
+ TValue& TValue::GetOrAddUnsafe(size_t idx) {
+ return CoreMutable().GetOrAdd(idx);
+ }
+
+ TValue& TValue::GetOrAdd(TStringBuf idx) {
+ return CoreMutable().GetOrAdd(idx);
+ }
+
+ const TValue& TValue::Get(size_t idx) const {
+ return Core().Get(idx);
+ }
+
+ TValue* TValue::GetNoAdd(size_t idx) {
+ return CoreMutable().GetNoAdd(idx);
+ }
+
+ const TValue& TValue::Get(TStringBuf idx) const {
+ return Core().Get(idx);
+ }
+
+ TValue* TValue::GetNoAdd(TStringBuf key) {
+ return CoreMutable().GetNoAdd(key);
+ }
+
+ TValue& TValue::Back() {
+ return CoreMutable().Back();
+ }
+
+ const TValue& TValue::Back() const {
+ const TArray& arr = GetArray();
+ return arr.empty() ? DefaultValue() : arr.back();
+ }
+
+ TValue TValue::Delete(size_t idx) {
+ return CoreMutable().Delete(idx);
+ }
+
+ TValue TValue::Delete(TStringBuf idx) {
+ return CoreMutable().Delete(idx);
+ }
+
+ TValue& TValue::AddAll(std::initializer_list<std::pair<TStringBuf, TValue>> t) {
+ for (const auto& el : t) {
+ Add(el.first) = el.second;
+ }
+ return *this;
+ }
+
+ TValue& TValue::InsertUnsafe(size_t idx) {
+ return CoreMutable().Insert(idx);
+ }
+
+ template <class TIt>
+ TValue& TValue::AppendAll(TIt begin, TIt end) {
+ GetArrayMutable().AppendAll(begin, end);
+ return *this;
+ }
+
+ template <class TColl>
+ TValue& TValue::AppendAll(TColl&& coll) {
+ return AppendAll(std::begin(coll), std::end(coll));
+ }
+
+ TValue& TValue::AppendAll(std::initializer_list<TValue> coll) {
+ return AppendAll(coll.begin(), coll.end());
+ }
+
+ TValue& TValue::Push() {
+ return CoreMutable().Push();
+ }
+
+ TValue TValue::Pop() {
+ return CoreMutable().Pop();
+ }
+
+ TValue::EType TValue::GetType() const {
+ return Core().ValueType;
+ }
+
+ bool TValue::IsNull() const {
+ return Core().IsNull();
+ }
+
+ bool TValue::IsNumber() const {
+ return Core().IsNumber();
+ }
+
+ bool TValue::IsIntNumber() const {
+ return Core().IsIntNumber();
+ }
+
+ bool TValue::IsBool() const {
+ return Core().IsBool();
+ }
+
+ bool TValue::IsString() const {
+ return Core().IsString();
+ }
+
+ bool TValue::IsArray() const {
+ return Core().IsArray();
+ }
+
+ bool TValue::IsDict() const {
+ return Core().IsDict();
+ }
+
+ TValue& TValue::SetNumber(double i) {
+ CoreMutableForSet().SetNumber(i);
+ return *this;
+ }
+
+ TValue& TValue::SetIntNumber(i64 n) {
+ CoreMutableForSet().SetIntNumber(n);
+ return *this;
+ }
+
+ TValue& TValue::SetBool(bool val) {
+ CoreMutableForSet().SetBool(val);
+ return *this;
+ }
+
+ TValue& TValue::SetString(TStringBuf s) {
+ CoreMutableForSet().SetString(s);
+ return *this;
+ }
+
+ double TValue::GetNumber(double d) const {
+ return Core().GetNumber(d);
+ }
+
+ i64 TValue::GetIntNumber(i64 n) const {
+ return Core().GetIntNumber(n);
+ }
+
+ bool TValue::GetBool(bool b) const {
+ return Core().GetBool(b);
+ }
+
+ double& TValue::GetNumberMutable(double defaultval) {
+ return CoreMutable().GetNumberMutable(defaultval);
+ }
+
+ i64& TValue::GetIntNumberMutable(i64 defaultval) {
+ return CoreMutable().GetIntNumberMutable(defaultval);
+ }
+
+ TStringBuf TValue::GetString(TStringBuf d) const {
+ return Core().GetString(d);
+ }
+
+ TValue& TValue::SetArray() {
+ CoreMutable().SetArray();
+ return *this;
+ }
+
+ TValue& TValue::ClearArray() {
+ CoreMutable().ClearArray();
+ return *this;
+ }
+
+ TValue& TValue::SetDict() {
+ CoreMutable().SetDict();
+ return *this;
+ }
+
+ TValue& TValue::ClearDict() {
+ CoreMutable().ClearDict();
+ return *this;
+ }
+
+ const TArray& TValue::GetArray() const {
+ return Core().GetArray();
+ }
+
+ TArray& TValue::GetArrayMutable() {
+ return CoreMutable().GetArrayMutable();
+ }
+
+ const TDict& TValue::GetDict() const {
+ return Core().GetDict();
+ }
+
+ TDict& TValue::GetDictMutable() {
+ return CoreMutable().GetDictMutable();
+ }
+
+ size_t TValue::StringSize() const {
+ return GetString().size();
+ }
+
+ size_t TValue::ArraySize() const {
+ return GetArray().size();
+ }
+
+ size_t TValue::DictSize() const {
+ return GetDict().size();
+ }
+
+ bool TValue::StringEmpty() const {
+ return GetString().empty();
+ }
+
+ bool TValue::ArrayEmpty() const {
+ return GetArray().empty();
+ }
+
+ bool TValue::DictEmpty() const {
+ return GetDict().empty();
+ }
+
+ TValue::TValue(TPoolPtr& p)
+ : TheCore(NewCore(p))
+ {
+ }
+
+ TValue::TScCore& TValue::CoreMutable() {
+ if (Y_UNLIKELY(!TheCore)) {
+ *this = TValue();
+ } else if (Y_UNLIKELY(CopyOnWrite) && Y_UNLIKELY(TheCore->RefCount() > 1)) {
+ *this = Clone();
+ }
+
+ CopyOnWrite = false;
+
+ return *TheCore;
+ }
+
+ TValue::TScCore& TValue::CoreMutableForSet() {
+ if (Y_UNLIKELY(!TheCore) || Y_UNLIKELY(CopyOnWrite) && Y_UNLIKELY(TheCore->RefCount() > 1)) {
+ *this = TValue();
+ }
+
+ CopyOnWrite = false;
+
+ return *TheCore;
+ }
+
+ const TValue::TScCore& TValue::Core() const {
+ return TheCore ? *TheCore : DefaultCore();
+ }
+
+ TValue& TValue::SetNull() {
+ CoreMutableForSet().SetNull();
+ return *this;
+ }
+
+ namespace NPrivate {
+ int CompareStr(const NSc::TValue& a, TStringBuf b);
+
+ int CompareInt(const NSc::TValue& a, i64 r);
+
+ int CompareFloat(const NSc::TValue& a, double r);
+ }
+
+ bool operator==(const TValue& a, const TValue& b);
+
+ bool operator!=(const TValue& a, const TValue& b);
+
+ bool operator<=(const TValue&, const TValue&) = delete;
+ bool operator>=(const TValue&, const TValue&) = delete;
+ bool operator<(const TValue&, const TValue&) = delete;
+ bool operator>(const TValue&, const TValue&) = delete;
+
+#define LIBRARY_SCHEME_DECLARE_TVALUE_OPS(T, Impl) \
+ bool operator==(const NSc::TValue& a, T b); \
+ bool operator==(T b, const NSc::TValue& a); \
+ bool operator!=(const NSc::TValue& a, T b); \
+ bool operator!=(T b, const NSc::TValue& a); \
+ bool operator<=(const NSc::TValue& a, T b); \
+ bool operator<=(T b, const NSc::TValue& a); \
+ bool operator>=(const NSc::TValue& a, T b); \
+ bool operator>=(T b, const NSc::TValue& a); \
+ bool operator<(const NSc::TValue& a, T b); \
+ bool operator<(T b, const NSc::TValue& a); \
+ bool operator>(const NSc::TValue& a, T b); \
+ bool operator>(T b, const NSc::TValue& a);
+
+#define LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS(T) \
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS(signed T, CompareInt) \
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS(unsigned T, CompareInt)
+
+ //LIBRARY_SCHEME_DECLARE_TVALUE_OPS(bool, CompareInt)
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS(char, CompareInt)
+ LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS(char)
+ LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS(short)
+ LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS(int)
+ LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS(long)
+ LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS(long long)
+
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS(float, CompareFloat)
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS(double, CompareFloat)
+
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS(TStringBuf, CompareStr)
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS(const TString&, CompareStr)
+ LIBRARY_SCHEME_DECLARE_TVALUE_OPS(const char* const, CompareStr)
+
+#undef LIBRARY_SCHEME_DECLARE_TVALUE_OPS
+#undef LIBRARY_SCHEME_DECLARE_TVALUE_INT_OPS
+
+}
diff --git a/library/cpp/scheme/scimpl_defs.h b/library/cpp/scheme/scimpl_defs.h
new file mode 100644
index 0000000000..f3dd66b437
--- /dev/null
+++ b/library/cpp/scheme/scimpl_defs.h
@@ -0,0 +1,140 @@
+#pragma once
+
+#include <library/cpp/json/json_reader.h>
+#include <library/cpp/json/json_value.h>
+
+#include <util/system/types.h>
+#include <util/memory/pool.h>
+
+#include <util/generic/deque.h>
+#include <util/generic/hash.h>
+#include <util/generic/ptr.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <functional>
+#include <util/string/vector.h>
+#include <util/string/type.h>
+
+namespace NSc {
+ namespace NDefinitions {
+ const size_t POOL_BLOCK_SIZE = 4000; // leave 96 bytes for overhead
+
+ struct TPool: public TAtomicRefCount<TPool> {
+ TMemoryPool Pool;
+
+ TPool(size_t blsz = POOL_BLOCK_SIZE, TMemoryPool::IGrowPolicy* grow = TMemoryPool::TExpGrow::Instance())
+ : Pool(blsz, grow)
+ {
+ }
+
+ TMemoryPool* Get() {
+ return &Pool;
+ }
+
+ TStringBuf AppendBuf(const TStringBuf& strb) {
+ return Pool.AppendCString(strb);
+ }
+
+ template <typename T>
+ T* NewWithPool() {
+ return new (Pool.Allocate<T>()) T(&Pool);
+ }
+ };
+ }
+
+ using TStringBufs = TVector<TStringBuf>;
+
+ class TSchemeException : public yexception {
+ };
+
+ class TSchemeParseException : public TSchemeException {
+ public:
+ size_t Offset = 0;
+ TString Reason;
+
+ public:
+ TSchemeParseException() = default;
+
+ TSchemeParseException(size_t off, const TString& reason)
+ : Offset(off)
+ , Reason(reason)
+ {
+ }
+ };
+
+ struct TJsonOpts: public NJson::TJsonReaderConfig {
+ enum EJsonOpts {
+ JO_DEFAULT = 0, // just dump json, used to be default, actually
+ JO_SORT_KEYS = 1, // sort dict keys to make output more predictable
+ JO_SKIP_UNSAFE = 2, // skip nonunicode data to make external json parsers happy
+ // will skip nonunicode dict keys and replace nonunicode values with nulls
+ JO_FORMAT = 8, // format json
+
+ JO_PARSER_STRICT_JSON = 16, // strict standard json
+ JO_PARSER_STRICT_UTF8 = 32, // strict utf8
+ JO_PARSER_DISALLOW_COMMENTS = 64,
+ JO_PARSER_DISALLOW_DUPLICATE_KEYS = 128,
+
+ JO_PRETTY = JO_FORMAT | JO_SORT_KEYS, // pretty print json
+ JO_SAFE = JO_SKIP_UNSAFE | JO_SORT_KEYS, // ensure standard parser-safe json
+
+ JO_PARSER_STRICT_WITH_COMMENTS = JO_PARSER_STRICT_JSON | JO_PARSER_STRICT_UTF8,
+ JO_PARSER_STRICT = JO_PARSER_STRICT_JSON | JO_PARSER_STRICT_UTF8 | JO_PARSER_DISALLOW_COMMENTS,
+ };
+
+ public:
+ TJsonOpts(int opts = JO_SORT_KEYS)
+ : Opts(opts)
+ , SortKeys(opts & JO_SORT_KEYS)
+ , FormatJson(opts & JO_FORMAT)
+ , StringPolicy((opts & JO_SKIP_UNSAFE) ? StringPolicySafe : StringPolicyUnsafe)
+ {
+ AllowComments = !(opts & JO_PARSER_DISALLOW_COMMENTS);
+ RelaxedJson = !(opts & JO_PARSER_STRICT_JSON);
+ DontValidateUtf8 = !(opts & JO_PARSER_STRICT_UTF8);
+ }
+
+ public:
+ bool RelaxedJson = false;
+ int Opts = 0;
+ bool SortKeys = true;
+ bool FormatJson = false;
+
+ // return true to proceed with output, false to skip, optionally modify value
+ std::function<bool(double&)> NumberPolicy = NumberPolicySafe;
+ std::function<bool(TStringBuf&)> StringPolicy = StringPolicyUnsafe;
+
+ public:
+ static bool NumberPolicySafe(double&); // skip if nan or inf
+ static bool NumberPolicyUnsafe(double&) {
+ return true;
+ }
+
+ static bool StringPolicySafe(TStringBuf&); // skip if not utf8
+ static bool StringPolicyUnsafe(TStringBuf&) {
+ return true;
+ }
+ };
+
+ struct TProtoOpts {
+ // Serialization throws on unknown enum value if not set, else use default value
+ bool UnknownEnumValueIsDefault = false;
+
+ // Serialization throws on type mismatch if not set, else leaves protobuf empty
+ bool SkipTypeMismatch = false;
+ };
+
+ namespace NImpl {
+ class TKeySortContext;
+ class TSelfLoopContext;
+ class TSelfOverrideContext;
+ }
+}
+
+namespace google {
+ namespace protobuf {
+ class Message;
+ class FieldDescriptor;
+ }
+}
diff --git a/library/cpp/scheme/scimpl_json_read.cpp b/library/cpp/scheme/scimpl_json_read.cpp
new file mode 100644
index 0000000000..8a29cc7739
--- /dev/null
+++ b/library/cpp/scheme/scimpl_json_read.cpp
@@ -0,0 +1,229 @@
+#include "scimpl.h"
+
+#include <library/cpp/json/json_reader.h>
+#include <util/stream/output.h>
+#include <util/generic/maybe.h>
+
+namespace NSc {
+ struct TJsonError {
+ size_t Offset = 0;
+ TMaybe<TString> Reason;
+ };
+
+ struct TJsonDeserializer : NJson::TJsonCallbacks {
+ struct TContainer {
+ TValue* Container = nullptr;
+ TValue* LastValue = nullptr;
+ bool ExpectKey = false;
+
+ TContainer(TValue& v)
+ : Container(&v)
+ , ExpectKey(v.IsDict())
+ {
+ }
+
+ bool Add(TStringBuf v, bool allowDuplicated) {
+ if (!ExpectKey || Y_UNLIKELY(!Container->IsDict()))
+ return false;
+
+ if (!allowDuplicated && Y_UNLIKELY(Container->Has(v)))
+ return false;
+
+ LastValue = &Container->GetOrAdd(v);
+ ExpectKey = false;
+ return true;
+ }
+
+ void Push() {
+ LastValue = &Container->Push();
+ }
+
+ TValue& NextValue() {
+ if (Container->IsArray()) {
+ Push();
+ } else if (Container->IsDict()) {
+ ExpectKey = true;
+ }
+
+ return *(LastValue ? LastValue : Container);
+ }
+
+ bool IsArray() const {
+ return !!Container && Container->IsArray();
+ }
+
+ bool IsDict() const {
+ return !!Container && Container->IsDict();
+ }
+ };
+
+ typedef TVector<TContainer> TStackType;
+
+ public:
+ TValue& Root;
+ TJsonError& Error;
+ const TJsonOpts& Cfg;
+
+ TStackType Stack;
+ bool Virgin = true;
+
+ public:
+ TJsonDeserializer(TValue& root, TJsonError& err, const TJsonOpts& cfg)
+ : Root(root)
+ , Error(err)
+ , Cfg(cfg)
+ {
+ Root.SetNull();
+ Stack.reserve(10);
+ }
+
+ bool HasNextValue() const {
+ return Virgin | !Stack.empty();
+ }
+
+ TValue& NextValue() {
+ Virgin = false;
+ return Stack.empty() ? Root : Stack.back().NextValue();
+ }
+
+ bool OnNull() override {
+ if (Y_UNLIKELY(!HasNextValue()))
+ return false;
+
+ NextValue().SetNull();
+ return true;
+ }
+
+ bool OnEnd() override {
+ return Stack.empty();
+ }
+
+ template <typename T>
+ bool OnValue(T v) {
+ if (Y_UNLIKELY(!HasNextValue()))
+ return false;
+
+ NextValue() = v;
+ return true;
+ }
+
+ template <typename T>
+ bool OnIntValue(T v) {
+ if (Y_UNLIKELY(!HasNextValue()))
+ return false;
+
+ NextValue().SetIntNumber(v);
+ return true;
+ }
+
+ bool OnBoolean(bool v) override {
+ if (Y_UNLIKELY(!HasNextValue()))
+ return false;
+
+ NextValue().SetBool(v);
+ return true;
+ }
+
+ bool OnInteger(long long v) override {
+ return OnIntValue(v);
+ }
+
+ bool OnUInteger(unsigned long long v) override {
+ return OnIntValue(v);
+ }
+
+ bool OnDouble(double v) override {
+ return OnValue(v);
+ }
+
+ bool OnString(const TStringBuf& v) override {
+ return OnValue(v);
+ }
+
+ bool OnMapKey(const TStringBuf& k) override {
+ if (Y_UNLIKELY(Stack.empty()))
+ return false;
+ return Stack.back().Add(k, !(Cfg.Opts & TJsonOpts::JO_PARSER_DISALLOW_DUPLICATE_KEYS));
+ }
+
+ bool OnOpenMap() override {
+ if (Y_UNLIKELY(!HasNextValue()))
+ return false;
+ Stack.push_back(TContainer(NextValue().SetDict()));
+ return true;
+ }
+
+ bool OnCloseMap() override {
+ if (Y_UNLIKELY(Stack.empty() || !Stack.back().IsDict()))
+ return false;
+ Stack.pop_back();
+ return true;
+ }
+
+ bool OnOpenArray() override {
+ if (Y_UNLIKELY(!HasNextValue()))
+ return false;
+ Stack.push_back(TContainer(NextValue().SetArray()));
+ return true;
+ }
+
+ bool OnCloseArray() override {
+ if (Y_UNLIKELY(Stack.empty() || !Stack.back().IsArray()))
+ return false;
+ Stack.pop_back();
+ return true;
+ }
+
+ void OnError(size_t off, TStringBuf reason) override {
+ Error.Offset = off;
+ Error.Reason = reason;
+ }
+ };
+
+ static bool DoParseFromJson(TValue& res, TJsonError& err, TStringBuf json, const TJsonOpts& cfg) {
+ TJsonDeserializer d(res, err, cfg);
+
+ if (cfg.RelaxedJson) {
+ return NJson::ReadJsonFast(json, &d);
+ } else {
+ TMemoryInput min(json.data(), json.size());
+ return NJson::ReadJson(&min, &cfg, &d);
+ }
+ }
+
+ static bool DoParseFromJson(TValue& res, TStringBuf json, const TJsonOpts& cfg) {
+ TJsonError err;
+ return DoParseFromJson(res, err, json, cfg);
+ }
+
+ TValue TValue::FromJson(TStringBuf v, const TJsonOpts& cfg) {
+ TValue res;
+ if (FromJson(res, v, cfg)) {
+ return res;
+ } else {
+ return DefaultValue();
+ }
+ }
+
+ TValue TValue::FromJsonThrow(TStringBuf json, const TJsonOpts& cfg) {
+ TValue res;
+ TJsonError err;
+
+ if (DoParseFromJson(res, err, json, cfg)) {
+ return res;
+ }
+
+ TString reason = err.Reason.Empty() ? "NULL" : *err.Reason;
+ ythrow TSchemeParseException(err.Offset, reason) << "JSON error at offset " << err.Offset << " (" << reason << ")";
+ }
+
+ bool TValue::FromJson(TValue& res, TStringBuf json, const TJsonOpts& cfg) {
+ if (DoParseFromJson(res, json, cfg)) {
+ return true;
+ }
+
+ res.SetNull();
+ return false;
+ }
+
+}
diff --git a/library/cpp/scheme/scimpl_json_write.cpp b/library/cpp/scheme/scimpl_json_write.cpp
new file mode 100644
index 0000000000..aadd7e6cd5
--- /dev/null
+++ b/library/cpp/scheme/scimpl_json_write.cpp
@@ -0,0 +1,193 @@
+#include "scimpl.h"
+#include "scimpl_private.h"
+
+#include <library/cpp/json/json_prettifier.h>
+#include <library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h>
+
+#include <util/charset/utf8.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/ymath.h>
+#include <util/system/tls.h>
+
+namespace NSc {
+ bool TJsonOpts::StringPolicySafe(TStringBuf& s) {
+ return IsUtf(s);
+ }
+
+ bool TJsonOpts::NumberPolicySafe(double& d) {
+ return IsFinite(d);
+ }
+
+ static inline void WriteString(IOutputStream& out, TStringBuf s) {
+ NEscJ::EscapeJ<true, true>(s, out);
+ }
+
+ static inline const NSc::TValue& GetValue(size_t, TStringBuf key, const TDict& dict) {
+ return dict.find(key)->second;
+ }
+
+ static inline const NSc::TValue& GetValue(TDict::const_iterator it, TStringBuf, const TDict&) {
+ return it->second;
+ }
+
+ static inline TStringBuf GetKey(size_t it, const NImpl::TKeySortContext::TGuard& keys) {
+ return keys.GetVector()[it];
+ }
+
+ static inline TStringBuf GetKey(TDict::const_iterator it, const TDict&) {
+ return it->first;
+ }
+
+ template <typename TDictKeys>
+ static inline void WriteDict(IOutputStream& out, const TDictKeys& keys, const TDict& dict,
+ const TJsonOpts& jopts, NImpl::TKeySortContext& sortCtx, NImpl::TSelfLoopContext& loopCtx) {
+ using const_iterator = typename TDictKeys::const_iterator;
+ const_iterator begin = keys.begin();
+ const_iterator end = keys.end();
+ for (const_iterator it = begin; it != end; ++it) {
+ TStringBuf key = GetKey(it, keys);
+
+ if (jopts.StringPolicy && !jopts.StringPolicy(key)) {
+ ++begin;
+ continue;
+ }
+
+ if (it != begin) {
+ out << ',';
+ }
+
+ NEscJ::EscapeJ<true, true>(key, out);
+ out << ':';
+
+ GetValue(it, key, dict).DoWriteJsonImpl(out, jopts, sortCtx, loopCtx);
+ }
+ }
+
+ void TValue::DoWriteJsonImpl(IOutputStream& out, const TJsonOpts& jopts,
+ NImpl::TKeySortContext& sortCtx, NImpl::TSelfLoopContext& loopCtx) const {
+ const TScCore& core = Core();
+
+ NImpl::TSelfLoopContext::TGuard loopCheck(loopCtx, core);
+
+ if (!loopCheck.Ok) {
+ out << TStringBuf("null"); // a loop encountered (and asserted), skip the back reference
+ return;
+ }
+
+ switch (core.ValueType) {
+ default: {
+ Y_ASSERT(false);
+ [[fallthrough]]; /* no break */
+ }
+ case EType::Null: {
+ out << TStringBuf("null");
+ break;
+ }
+ case EType::Bool: {
+ out << (core.IntNumber ? TStringBuf("true") : TStringBuf("false"));
+ break;
+ }
+ case EType::IntNumber: {
+ out << core.IntNumber;
+ break;
+ }
+ case EType::FloatNumber: {
+ double d = core.FloatNumber;
+ if (!jopts.NumberPolicy || jopts.NumberPolicy(d)) {
+ out << d;
+ } else {
+ out << TStringBuf("null");
+ }
+ break;
+ }
+ case EType::String: {
+ TStringBuf s = core.String;
+ if (!jopts.StringPolicy || jopts.StringPolicy(s)) {
+ WriteString(out, s);
+ } else {
+ out << TStringBuf("null");
+ }
+ break;
+ }
+ case EType::Array: {
+ out << '[';
+ const TArray& a = core.GetArray();
+ for (TArray::const_iterator it = a.begin(); it != a.end(); ++it) {
+ if (it != a.begin()) {
+ out << ',';
+ }
+
+ it->DoWriteJsonImpl(out, jopts, sortCtx, loopCtx);
+ }
+ out << ']';
+ break;
+ }
+ case EType::Dict: {
+ out << '{';
+
+ const TDict& dict = core.GetDict();
+
+ if (jopts.SortKeys) {
+ NImpl::TKeySortContext::TGuard keys(sortCtx, dict);
+ WriteDict(out, keys, dict, jopts, sortCtx, loopCtx);
+ } else {
+ WriteDict(out, dict, dict, jopts, sortCtx, loopCtx);
+ }
+
+ out << '}';
+ break;
+ }
+ }
+ }
+
+ const TValue& TValue::ToJson(IOutputStream& out, const TJsonOpts& jopts) const {
+ using namespace NImpl;
+
+ if (jopts.FormatJson) {
+ TStringStream str;
+ DoWriteJsonImpl(str, jopts, GetTlsInstance<TKeySortContext>(), GetTlsInstance<TSelfLoopContext>());
+ NJson::PrettifyJson(str.Str(), out);
+ } else {
+ DoWriteJsonImpl(out, jopts, GetTlsInstance<TKeySortContext>(), GetTlsInstance<TSelfLoopContext>());
+ }
+
+ return *this;
+ }
+
+ TString TValue::ToJson(const TJsonOpts& jopts) const {
+ TString s;
+ {
+ TStringOutput out(s);
+ ToJson(out, jopts);
+ }
+ return s;
+ }
+
+ TJsonOpts TValue::MakeOptsSafeForSerializer(TJsonOpts opts) {
+ opts.SortKeys = true;
+ opts.StringPolicy = TJsonOpts::StringPolicySafe;
+ opts.NumberPolicy = TJsonOpts::NumberPolicySafe;
+ return opts;
+ }
+
+ TJsonOpts TValue::MakeOptsPrettyForSerializer(TJsonOpts opts) {
+ opts.FormatJson = true;
+ return MakeOptsSafeForSerializer(opts);
+ }
+
+ TString TValue::ToJsonSafe(const TJsonOpts& jopts) const {
+ return ToJson(MakeOptsSafeForSerializer(jopts));
+ }
+
+ const TValue& TValue::ToJsonSafe(IOutputStream& out, const TJsonOpts& jopts) const {
+ return ToJson(out, MakeOptsSafeForSerializer(jopts));
+ }
+
+ TString TValue::ToJsonPretty(const TJsonOpts& jopts) const {
+ return ToJson(MakeOptsPrettyForSerializer(jopts));
+ }
+
+ const TValue& TValue::ToJsonPretty(IOutputStream& out, const TJsonOpts& jopts) const {
+ return ToJson(out, MakeOptsPrettyForSerializer(jopts));
+ }
+}
diff --git a/library/cpp/scheme/scimpl_private.cpp b/library/cpp/scheme/scimpl_private.cpp
new file mode 100644
index 0000000000..024bf8cc3b
--- /dev/null
+++ b/library/cpp/scheme/scimpl_private.cpp
@@ -0,0 +1,74 @@
+#include "scimpl_private.h"
+
+#include <util/generic/algorithm.h>
+#include <utility>
+
+namespace NSc {
+ namespace NImpl {
+ struct TGetKey {
+ static inline TStringBuf Do(const TDict::value_type& v) {
+ return v.first;
+ }
+ };
+
+ struct TMoveValue {
+ static inline TValue&& Do(TDict::value_type& v) {
+ return std::move(v.second);
+ }
+
+ static inline TValue&& Do(TArray::value_type& v) {
+ return std::move(v);
+ }
+ };
+
+ template <typename TAction, typename TElement, typename TColl>
+ static inline void PutToVector(TVector<TElement>& vector, TColl& coll) {
+ size_t i = vector.size();
+ vector.resize(vector.size() + coll.size());
+
+ for (auto& item : coll) {
+ vector[i++] = TAction::Do(item);
+ }
+ }
+
+ bool TKeySortContext::Process(const TDict& self) {
+ size_t oldSz = Vector.size();
+ PutToVector<TGetKey>(Vector, self);
+ Sort(Vector.begin() + oldSz, Vector.end());
+ return true;
+ }
+
+ bool TSelfOverrideContext::Process(TValue::TScCore& self) {
+ if (self.GetDict().size()) {
+ PutToVector<TMoveValue>(Vector, self.Dict);
+ } else if (self.GetArray().size()) {
+ PutToVector<TMoveValue>(Vector, self.Array);
+ }
+ return true;
+ }
+
+ bool TSelfLoopContext::Process(const TValue::TScCore& self) {
+ const bool ok = (Vector.end() == Find(Vector.begin(), Vector.end(), &self));
+
+ if (!ok) {
+ switch (ReportingMode) {
+ case EMode::Assert:
+ Y_ASSERT(false); // make sure the debug build sees this
+ break;
+ case EMode::Throw:
+ ythrow TSchemeException() << "REFERENCE LOOP DETECTED";
+ case EMode::Abort:
+ Y_FAIL("REFERENCE LOOP DETECTED");
+ break;
+ case EMode::Stderr:
+ Cerr << "REFERENCE LOOP DETECTED: " << JoinStrings(Vector.begin(), Vector.end(), ", ")
+ << " AND " << ToString((const void*)&self) << Endl;
+ break;
+ }
+ }
+
+ Vector.push_back(&self);
+ return ok;
+ }
+ }
+}
diff --git a/library/cpp/scheme/scimpl_private.h b/library/cpp/scheme/scimpl_private.h
new file mode 100644
index 0000000000..b92badabde
--- /dev/null
+++ b/library/cpp/scheme/scimpl_private.h
@@ -0,0 +1,114 @@
+#pragma once
+
+#include "scheme.h"
+
+#include <util/thread/singleton.h>
+
+namespace NSc {
+ namespace NImpl {
+ template <typename TContext>
+ static inline TContext& GetTlsInstance() {
+ return *FastTlsSingleton<TContext>();
+ }
+
+ template <typename TContext>
+ class TContextGuard : TNonCopyable {
+ using TElement = typename TContext::TElement;
+ using TTarget = typename TContext::TTarget;
+ using TVectorType = TVector<TElement>;
+
+ public:
+ TContextGuard(TContext& ctx, TTarget& target)
+ : Ctx(ctx)
+ , Active(TContext::Needed(target))
+ {
+ if (Active) {
+ Begin = Ctx.Vector.size();
+ Ok = Ctx.Process(target);
+ End = Ctx.Vector.size();
+ }
+ }
+
+ ~TContextGuard() noexcept {
+ if (Active) {
+ Ctx.Vector.resize(Begin);
+ }
+ }
+
+ const TVectorType& GetVector() const {
+ return Ctx.Vector;
+ }
+
+ using const_iterator = size_t;
+
+ size_t begin() const {
+ return Begin;
+ }
+
+ size_t end() const {
+ return End;
+ }
+
+ bool Ok = true;
+
+ private:
+ TContext& Ctx;
+ size_t Begin = 0;
+ size_t End = 0;
+ bool Active = false;
+ };
+
+ template <typename TElem, typename TTgt>
+ class TBasicContext {
+ public:
+ using TElement = TElem;
+ using TTarget = TTgt;
+
+ TBasicContext() {
+ Vector.reserve(64);
+ }
+
+ TVector<TElement> Vector;
+ };
+
+ class TKeySortContext: public TBasicContext<TStringBuf, const TDict> {
+ public:
+ using TGuard = TContextGuard<TKeySortContext>;
+
+ bool Process(const TDict& self);
+
+ static bool Needed(const TDict& self) {
+ return self.size();
+ }
+ };
+
+ class TSelfOverrideContext: public TBasicContext<TValue, TValue::TScCore> {
+ public:
+ using TGuard = TContextGuard<TSelfOverrideContext>;
+
+ bool Process(TValue::TScCore& self);
+
+ static bool Needed(const TValue::TScCore& self) {
+ return self.HasChildren();
+ }
+ };
+
+ class TSelfLoopContext: public TBasicContext<const void*, const TValue::TScCore> {
+ public:
+ enum class EMode {
+ Assert, Throw, Abort, Stderr
+ };
+
+ using TGuard = TContextGuard<TSelfLoopContext>;
+
+ bool Process(const TValue::TScCore& self);
+
+ static bool Needed(const TValue::TScCore& self) {
+ return self.HasChildren();
+ }
+
+ public:
+ EMode ReportingMode = EMode::Assert;
+ };
+ }
+}
diff --git a/library/cpp/scheme/scimpl_protobuf.cpp b/library/cpp/scheme/scimpl_protobuf.cpp
new file mode 100644
index 0000000000..0c99122c69
--- /dev/null
+++ b/library/cpp/scheme/scimpl_protobuf.cpp
@@ -0,0 +1,329 @@
+#include "scheme.h"
+
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/reflection.h>
+
+using namespace google::protobuf;
+
+namespace NSc {
+ TValue TValue::From(const Message& msg, bool mapAsDict) {
+ TValue v;
+ const Reflection* r = msg.GetReflection();
+ TVector<const FieldDescriptor*> fields;
+ TVector<const FieldDescriptor*>::iterator it;
+ int i1;
+
+ r->ListFields(msg, &fields);
+ for (it = fields.begin(), i1 = 0; it != fields.end(); ++it, ++i1) {
+ const FieldDescriptor* field = *it;
+ try {
+ if (field->is_repeated()) {
+ if (field->is_map() && mapAsDict) {
+ auto& elem = v[field->name()];
+ for (int i2 = 0; i2 < r->FieldSize(msg, field); ++i2) {
+ auto val = FromRepeatedField(msg, field, i2);
+ if (val.IsDict()) {
+ elem[TStringBuf(val["key"])] = val["value"];
+ }
+ }
+ } else {
+ for (int i2 = 0; i2 < r->FieldSize(msg, field); ++i2)
+ v[field->name()][i2] = FromRepeatedField(msg, field, i2);
+ }
+ } else {
+ v[field->name()] = FromField(msg, field);
+ }
+ } catch (...) {
+ /* conversion failed, skip this field */
+ }
+ }
+
+ return v;
+ }
+
+ TValue TValue::FromField(const Message& msg, const FieldDescriptor* field) {
+ TValue v;
+ const Reflection* r = msg.GetReflection();
+
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ v = r->GetInt32(msg, field);
+ break;
+ case FieldDescriptor::CPPTYPE_INT64:
+ v = r->GetInt64(msg, field);
+ break;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ v = r->GetUInt32(msg, field);
+ break;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ v = r->GetUInt64(msg, field);
+ break;
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ v = r->GetDouble(msg, field);
+ break;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ v = r->GetFloat(msg, field);
+ break;
+ case FieldDescriptor::CPPTYPE_BOOL:
+ v.SetBool(r->GetBool(msg, field));
+ break;
+ case FieldDescriptor::CPPTYPE_ENUM:
+ v = r->GetEnum(msg, field)->name();
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ v = r->GetString(msg, field);
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ v = From(r->GetMessage(msg, field));
+ break;
+ default:
+ ythrow TSchemeException() << "field " << field->full_name() << " unexpected type " << (int)field->cpp_type();
+ }
+
+ return v;
+ }
+
+ TValue TValue::FromRepeatedField(const Message& msg, const FieldDescriptor* field, int index) {
+ TValue v;
+ const Reflection* r = msg.GetReflection();
+
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ v = r->GetRepeatedInt32(msg, field, index);
+ break;
+ case FieldDescriptor::CPPTYPE_INT64:
+ v = r->GetRepeatedInt64(msg, field, index);
+ break;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ v = r->GetRepeatedUInt32(msg, field, index);
+ break;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ v = r->GetRepeatedUInt64(msg, field, index);
+ break;
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ v = r->GetRepeatedDouble(msg, field, index);
+ break;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ v = r->GetRepeatedFloat(msg, field, index);
+ break;
+ case FieldDescriptor::CPPTYPE_BOOL:
+ v.SetBool(r->GetRepeatedBool(msg, field, index));
+ break;
+ case FieldDescriptor::CPPTYPE_ENUM:
+ v = r->GetRepeatedEnum(msg, field, index)->name();
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ v = r->GetRepeatedString(msg, field, index);
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ v = From(r->GetRepeatedMessage(msg, field, index));
+ break;
+ default:
+ ythrow TSchemeException() << "field " << field->full_name() << " unexpected type " << (int)field->cpp_type();
+ }
+
+ return v;
+ }
+
+ void TValue::To(Message& msg, const TProtoOpts& opts) const {
+ msg.Clear();
+
+ if (IsNull()) {
+ return;
+ }
+
+ if (!IsDict()) {
+ ythrow TSchemeException() << "expected dictionary";
+ }
+
+ const Descriptor* descriptor = msg.GetDescriptor();
+ for (int i = 0, count = descriptor->field_count(); i < count; ++i) {
+ const FieldDescriptor* field = descriptor->field(i);
+ if (field->is_map()) {
+ ToMapField(msg, field, opts);
+ } else if (field->is_repeated()) {
+ ToRepeatedField(msg, field, opts);
+ } else {
+ ToField(msg, field, opts);
+ }
+ }
+ }
+
+ void TValue::ValueToField(const TValue& value, Message& msg, const FieldDescriptor* field, const TProtoOpts& opts) const {
+ const TString& name = field->name();
+ if (value.IsNull()) {
+ if (field->is_required() && !field->has_default_value()) {
+ ythrow TSchemeException() << "has no value for required field " << name;
+ }
+ return;
+ }
+
+ const Reflection* reflection = msg.GetReflection();
+
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ reflection->SetInt32(&msg, field, value.ForceIntNumber());
+ break;
+ case FieldDescriptor::CPPTYPE_INT64:
+ reflection->SetInt64(&msg, field, value.ForceIntNumber());
+ break;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ reflection->SetUInt32(&msg, field, value.ForceIntNumber());
+ break;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ reflection->SetUInt64(&msg, field, value.ForceIntNumber());
+ break;
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ reflection->SetDouble(&msg, field, value.ForceNumber());
+ break;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ reflection->SetFloat(&msg, field, value.ForceNumber());
+ break;
+ case FieldDescriptor::CPPTYPE_BOOL:
+ reflection->SetBool(&msg, field, value.IsTrue());
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ reflection->SetString(&msg, field, value.ForceString());
+ break;
+ case FieldDescriptor::CPPTYPE_ENUM:
+ value.ToEnumField(msg, field, opts);
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ value.To(*reflection->MutableMessage(&msg, field), opts);
+ break;
+ default:
+ ythrow TSchemeException()
+ << "field " << field->full_name()
+ << " unexpected type " << (int)field->cpp_type();
+ }
+ }
+
+ void TValue::ToField(Message& msg, const FieldDescriptor* field, const TProtoOpts& opts) const {
+ const TString& name = field->name();
+ const TValue& value = Get(name);
+ ValueToField(value, msg, field, opts);
+ }
+
+ void TValue::ToEnumField(Message& msg, const FieldDescriptor* field, const TProtoOpts& opts) const {
+ const EnumDescriptor* enumField = field->enum_type();
+
+ const EnumValueDescriptor* enumFieldValue = IsString()
+ ? enumField->FindValueByName(ForceString())
+ : enumField->FindValueByNumber(ForceIntNumber());
+
+ if (!enumFieldValue) {
+ if (opts.UnknownEnumValueIsDefault) {
+ enumFieldValue = field->default_value_enum();
+ } else {
+ ythrow TSchemeException() << "invalid value of enum field " << field->name();
+ }
+ }
+
+ const Reflection* reflection = msg.GetReflection();
+
+ if (field->is_repeated()) {
+ reflection->AddEnum(&msg, field, enumFieldValue);
+ } else {
+ reflection->SetEnum(&msg, field, enumFieldValue);
+ }
+ }
+
+ void TValue::ToRepeatedField(Message& msg, const FieldDescriptor* field, const TProtoOpts& opts) const {
+ const TString& name = field->name();
+
+ const TValue& fieldValue = Get(name);
+ if (fieldValue.IsNull()) {
+ return;
+ }
+
+ if (!fieldValue.IsArray()) {
+ if (opts.SkipTypeMismatch) {
+ return; // leave repeated field empty
+ } else {
+ ythrow TSchemeException() << "invalid type of repeated field " << name << ": not an array";
+ }
+ }
+
+ const Reflection* reflection = msg.GetReflection();
+
+ for (const TValue& value : fieldValue.GetArray()) {
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ reflection->AddInt32(&msg, field, value.ForceIntNumber());
+ break;
+ case FieldDescriptor::CPPTYPE_INT64:
+ reflection->AddInt64(&msg, field, value.ForceIntNumber());
+ break;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ reflection->AddUInt32(&msg, field, value.ForceIntNumber());
+ break;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ reflection->AddUInt64(&msg, field, value.ForceIntNumber());
+ break;
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ reflection->AddDouble(&msg, field, value.ForceNumber());
+ break;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ reflection->AddFloat(&msg, field, value.ForceNumber());
+ break;
+ case FieldDescriptor::CPPTYPE_BOOL:
+ reflection->AddBool(&msg, field, value.IsTrue());
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ reflection->AddString(&msg, field, value.ForceString());
+ break;
+ case FieldDescriptor::CPPTYPE_ENUM:
+ value.ToEnumField(msg, field, opts);
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ value.To(*reflection->AddMessage(&msg, field));
+ break;
+ default:
+ ythrow TSchemeException()
+ << "field " << field->full_name()
+ << " unexpected type " << (int)field->cpp_type();
+ }
+ }
+ }
+
+ void TValue::ToMapField(Message& msg, const FieldDescriptor* field, const TProtoOpts& opts) const {
+ const TString& name = field->name();
+
+ const TValue& fieldValue = Get(name);
+ if (fieldValue.IsNull()) {
+ return;
+ }
+
+ if (fieldValue.IsArray()) {
+ // read dict from key, value array
+ ToRepeatedField(msg, field, opts);
+ return;
+ }
+
+ if (!fieldValue.IsDict()) {
+ if (opts.SkipTypeMismatch) {
+ return; // leave map field empty
+ } else {
+ ythrow TSchemeException() << "invalid type of map field " << name << ": not dict or array";
+ }
+ }
+
+ const Reflection* reflection = msg.GetReflection();
+
+ auto mutableField = reflection->GetMutableRepeatedFieldRef<Message>(&msg, field);
+ for (const auto& value : fieldValue.GetDict()) {
+ THolder<Message> entry(mutableField.NewMessage());
+ auto entryDesc = entry->GetDescriptor();
+ auto keyField = entryDesc->FindFieldByNumber(1);
+ auto valueField = entryDesc->FindFieldByNumber(2);
+ auto entryReflection = entry->GetReflection();
+ entryReflection->SetString(entry.Get(), keyField, TString(value.first));
+ ValueToField(value.second, *entry, valueField, opts);
+ mutableField.Add(*entry);
+ }
+ }
+}
diff --git a/library/cpp/scheme/scimpl_select.rl6 b/library/cpp/scheme/scimpl_select.rl6
new file mode 100644
index 0000000000..11aa549b78
--- /dev/null
+++ b/library/cpp/scheme/scimpl_select.rl6
@@ -0,0 +1,270 @@
+#include <library/cpp/scheme/scimpl.h>
+
+#include <util/string/cast.h>
+#include <util/string/escape.h>
+#include <library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h>
+#include <util/generic/is_in.h>
+#include <util/string/util.h>
+
+namespace NSc {
+
+ template <typename TValue, typename TGetter>
+ struct TSelector {
+ TValue& Root;
+ TValue* Current = nullptr;
+ TValue* Parent = nullptr;
+ TStringBuf CurrentDictKey;
+ size_t CurrentArrayKey = 0;
+ size_t Depth = 0;
+ bool HasArray = false;
+ bool HasError = false;
+
+ TSelector(TValue& root)
+ : Root(root)
+ , Current(&Root)
+ {}
+
+ template <typename T>
+ bool Next(T k) {
+ Depth += 1;
+ Parent = Current;
+ Current = TGetter::Next(Current, k);
+ return Current != nullptr;
+ }
+
+ bool NextDict(TStringBuf k) {
+ return Next(CurrentDictKey = k);
+ }
+
+ bool NextArray(size_t k) {
+ HasArray = true;
+ return Next(CurrentArrayKey = k);
+ }
+
+ bool Error() {
+ Parent = nullptr;
+ Current = nullptr;
+ CurrentArrayKey = 0;
+ CurrentDictKey = TStringBuf();
+ HasError = true;
+ return false;
+ }
+ };
+
+ template <typename TSelector>
+ struct TSelectorCtx {
+ TSelector Selector;
+ TString Buffer;
+
+ const char* p0 = nullptr;
+ const char* p = nullptr;
+ const char* pe = nullptr;
+ const char* eof = nullptr;
+ const char* ts = nullptr;
+ const char* te = nullptr;
+ int cs = 0;
+ int act = 0;
+
+ TSelectorCtx(TSelector sel, TStringBuf data)
+ : Selector(sel)
+ , p0(data.data())
+ , p(data.data())
+ , pe(data.end())
+ , eof(data.end())
+ {}
+
+ bool OnString(TStringBuf s) {
+ return Selector.NextDict(s);
+ }
+
+ bool OnInt(size_t k) {
+ return Selector.NextArray(k);
+ }
+
+ bool OnStrU() {
+ return OnString(TStringBuf(ts, te));
+ }
+
+ bool OnStrQ() {
+ return OnString(TStringBuf(ts + 1, te - 1));
+ }
+
+ bool OnStrE() {
+ Buffer.clear();
+ Buffer.reserve(te - ts);
+ UnescapeC(ts + 1, te - ts - 2, Buffer);
+ return OnString(Buffer);
+ }
+
+ bool OnIntU() {
+ return OnInt(FromString<ui32>(TStringBuf(ts, te)));
+ }
+
+ bool OnIntQ() {
+ return OnInt(FromString<ui32>(TStringBuf(ts + 1, te - 1)));
+ }
+
+ bool OnError() {
+ Selector.Error();
+ return false;
+ }
+
+ bool SelectPath();
+ };
+
+#if 0
+ %%{
+ machine schemeselect;
+
+ alphtype char;
+
+ action OnIntU { if (Y_UNLIKELY(!OnIntU())) goto TOKEN_ERROR; }
+ action OnIntQ { if (Y_UNLIKELY(!OnIntQ())) goto TOKEN_ERROR; }
+ action OnStrU { if (Y_UNLIKELY(!OnStrU())) goto TOKEN_ERROR; }
+ action OnStrQ { if (Y_UNLIKELY(!OnStrQ())) goto TOKEN_ERROR; }
+ action OnStrE { if (Y_UNLIKELY(!OnStrE())) goto TOKEN_ERROR; }
+ action OnError { goto TOKEN_ERROR; }
+
+ intu = [0-9]+;
+ intq = '[' intu ']';
+
+ uchar0 = [a-zA-Z_@$] | (0x80 .. 0xFF);
+ uchar = uchar0 | digit | [.\-];
+
+ qchar = [^'\\]; #';
+ dchar = [^"\\]; #";
+ bchar = [^\]\\];
+
+ echar = "\\" any;
+
+ qechar = qchar | echar;
+ dechar = dchar | echar;
+ bechar = bchar | echar;
+
+ strq = "'" qchar* "'";
+ strd = '"' dchar* '"';
+ strb = '[' bchar* ']';
+
+ strqe = "'" qechar* "'";
+ strde = '"' dechar* '"';
+ strbe = '[' bechar* ']';
+
+ strU = uchar0 uchar*;
+ strQ = strq | strd | strb;
+ strE = strqe | strde | strbe;
+
+ main := |*
+ intu => OnIntU;
+ intq => OnIntQ;
+
+ strU => OnStrU;
+ strQ => OnStrQ;
+ strE => OnStrE;
+
+ '/';
+
+ (intu) (any - ('/' | '[' )) => OnError;
+
+ any => OnError;
+ *|;
+ }%%
+#endif
+
+ template <typename TSelector>
+ bool TSelectorCtx<TSelector>::SelectPath() {
+ try {
+ %%{
+ write data noerror nofinal;
+ write init;
+ write exec;
+ }%%
+ ;
+ Y_UNUSED(schemeselect_en_main);
+ } catch (const TFromStringException&) {
+ return OnError();
+ }
+
+ return Selector.Current;
+
+ TOKEN_ERROR:
+ return OnError();
+ }
+
+ template <bool CheckHas>
+ struct TGetNext {
+ template <typename TValue, typename TIdx>
+ static TValue* Next(TValue* val, TIdx idx) {
+ if (val) {
+ if (CheckHas && !val->Has(idx)) {
+ return nullptr;
+ } else {
+ return &(*val)[idx];
+ }
+ } else {
+ return nullptr;
+ }
+ }
+ };
+
+ const TValue& TValue::TrySelect(TStringBuf path) const {
+ TSelectorCtx<TSelector<const TValue, TGetNext<true> > > ctx(*this, path);
+
+ if (ctx.SelectPath()) {
+ return *ctx.Selector.Current;
+ }
+
+ return DefaultValue();
+ }
+
+ TValue* TValue::TrySelectOrAdd(TStringBuf path) {
+ TSelectorCtx<TSelector<TValue, TGetNext<false> > > ctx(*this, path);
+
+ if (ctx.SelectPath()) {
+ return ctx.Selector.Current;
+ } else {
+ return nullptr;
+ }
+ }
+
+ TValue TValue::TrySelectAndDelete(TStringBuf path) {
+ TSelectorCtx<TSelector<TValue, TGetNext<true> > > ctx(*this, path);
+
+ if (ctx.SelectPath() && ctx.Selector.Parent) {
+ if (ctx.Selector.Parent->IsArray()) {
+ return ctx.Selector.Parent->Delete(ctx.Selector.CurrentArrayKey);
+ } else if (ctx.Selector.Parent->IsDict()) {
+ return ctx.Selector.Parent->Delete(ctx.Selector.CurrentDictKey);
+ } else {
+ Y_ASSERT(false);
+ return DefaultValue();
+ }
+ } else {
+ return DefaultValue();
+ }
+ }
+
+ bool TValue::PathExists(TStringBuf path) const {
+ return TSelectorCtx<TSelector<const TValue, TGetNext<true>>>(*this, path).SelectPath();
+ }
+
+ bool TValue::PathValid(TStringBuf path) {
+ TSelectorCtx<TSelector<const TValue, TGetNext<false>>> ctx(DefaultValue(), path);
+ return ctx.SelectPath() || !ctx.Selector.HasError;
+ }
+
+ TString TValue::EscapeForPath(TStringBuf rawKey) {
+ static const str_spn danger{"/[]"};
+ if (!rawKey || danger.brk(rawKey.begin(), rawKey.end()) != rawKey.end()) {
+ return NEscJ::EscapeJ<true>(rawKey);
+ }
+
+ TSelectorCtx<TSelector<const TValue, TGetNext<false>>> ctx(DefaultValue(), rawKey);
+ ctx.SelectPath();
+ if (ctx.Selector.HasError || ctx.Selector.Depth > 1 || ctx.Selector.HasArray) {
+ return NEscJ::EscapeJ<true>(rawKey);
+ } else {
+ return ToString(rawKey);
+ }
+ }
+
+}
diff --git a/library/cpp/scheme/tests/fuzz_json/fuzz_json.cpp b/library/cpp/scheme/tests/fuzz_json/fuzz_json.cpp
new file mode 100644
index 0000000000..8d4c0fa8a0
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_json/fuzz_json.cpp
@@ -0,0 +1,6 @@
+#include <library/cpp/scheme/tests/fuzz_json/lib/fuzz_json.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const ui8* wireData, const size_t wireSize) {
+ NSc::NUt::FuzzJson({(const char*)wireData, wireSize});
+ return 0;
+}
diff --git a/library/cpp/scheme/tests/fuzz_json/lib/fuzz_json.cpp b/library/cpp/scheme/tests/fuzz_json/lib/fuzz_json.cpp
new file mode 100644
index 0000000000..7c16527c23
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_json/lib/fuzz_json.cpp
@@ -0,0 +1,115 @@
+#include "fuzz_json.h"
+#include "util/generic/fwd.h"
+
+#include <library/cpp/scheme/scheme.h>
+#include <util/stream/null.h>
+
+namespace {
+ static constexpr size_t MAX_DEPTH = 4;
+ static constexpr size_t MAX_PATH_LEN = 256;
+ static constexpr size_t MAX_ITERATIONS = 4;
+
+ void SplitOnDepth(const TStringBuf src, const size_t depth, const size_t maxPathLen,
+ TStringBuf& left, TStringBuf& right)
+ {
+ size_t pos = 0;
+ size_t prevPos = 0;
+ for(size_t i = 0; i < depth; ++i) {
+ if (pos > maxPathLen) {
+ break;
+ }
+ prevPos = pos;
+ pos = src.find_first_of(TStringBuf("/]"), pos + 1);
+ if (pos == TStringBuf::npos) {
+ break;
+ }
+ }
+ if (pos == TStringBuf::npos && prevPos > 0) {
+ pos = prevPos;
+ }
+ if (src.length() > maxPathLen) {
+ if (pos == TStringBuf::npos || pos > maxPathLen) {
+ pos = maxPathLen;
+ }
+ }
+ if (pos == TStringBuf::npos || pos == 0) {
+ left = src;
+ right = TStringBuf();
+ } else {
+ src.SplitAt(pos + 1, left, right);
+ }
+ }
+
+ TString tmp;
+ //Limit max array size in the path to 256
+ TStringBuf ProcessPath(TStringBuf path) {
+ size_t pos = 0;
+ while(pos != TStringBuf::npos) {
+ pos = path.find(']', pos + 1);
+ if (pos == TStringBuf::npos) {
+ continue;
+ }
+ size_t open = path.rfind('[', pos);
+ if (open == TStringBuf::npos) {
+ continue;
+ }
+ bool allDigit = true;
+ for(size_t i = open + 1; i < pos; ++i) {
+ if (path[i] < '0' || path[i] > '9') {
+ allDigit = false;
+ break;
+ }
+ }
+ if (!allDigit) {
+ continue;
+ }
+ if (pos - open > 4) {
+ TString str = TString::Join(path.Head(open + 1), "256", path.Tail(pos));
+ tmp = std::move(str);
+ path = tmp;
+ pos = (open + 1) + 3;
+ continue;
+ }
+ }
+ return path;
+ }
+}
+
+namespace NSc::NUt {
+
+
+ void FuzzJson(TStringBuf wire) {
+ if (wire.size() < 2) {
+ return;
+ }
+
+
+ ProcessPath("[123][1234][12][2134][12312312][1][12]");
+ ui8 len1 = wire[0];
+ ui8 len2 = wire[1];
+ wire.Skip(2);
+ auto json1 = wire.NextTokAt(len1);
+ auto json2 = wire.NextTokAt(len2);
+ NSc::TValue val1 = NSc::TValue::FromJson(json1);
+ NSc::TValue val2 = NSc::TValue::FromJson(json2);
+ NSc::TValue val3;
+ val3.MergeUpdate(val1);
+
+ size_t i = 0;
+ while (!wire.empty()) {
+ TStringBuf path;
+ SplitOnDepth(wire, MAX_DEPTH, MAX_PATH_LEN, path, wire);
+ path = ProcessPath(path);
+ if (auto* target = val3.TrySelectOrAdd(path)) {
+ target->MergeUpdate(val2);
+ }
+ ++i;
+ // Release memory since there are up to MAX_DICT_SIZE * MAX_DEPTH elements
+ if (i > MAX_ITERATIONS) {
+ Cnull << val3.ToJson();
+ val3 = NSc::TValue();
+ }
+ }
+ Cnull << val3.ToJson();
+ }
+}
diff --git a/library/cpp/scheme/tests/fuzz_json/lib/fuzz_json.h b/library/cpp/scheme/tests/fuzz_json/lib/fuzz_json.h
new file mode 100644
index 0000000000..f8cf7a4770
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_json/lib/fuzz_json.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+namespace NSc::NUt {
+ void FuzzJson(TStringBuf wire);
+}
diff --git a/library/cpp/scheme/tests/fuzz_json/lib/ya.make b/library/cpp/scheme/tests/fuzz_json/lib/ya.make
new file mode 100644
index 0000000000..b30a6c9350
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_json/lib/ya.make
@@ -0,0 +1,18 @@
+LIBRARY()
+
+OWNER(
+ g:blender
+ g:middle
+ g:upper
+ velavokr
+)
+
+SRCS(
+ fuzz_json.cpp
+)
+
+PEERDIR(
+ library/cpp/scheme
+)
+
+END()
diff --git a/library/cpp/scheme/tests/fuzz_json/ya.make b/library/cpp/scheme/tests/fuzz_json/ya.make
new file mode 100644
index 0000000000..0d91c70585
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_json/ya.make
@@ -0,0 +1,20 @@
+FUZZ()
+
+OWNER(
+ g:blender
+ g:middle
+ g:upper
+ velavokr
+)
+
+SIZE(MEDIUM)
+
+SRCS(
+ fuzz_json.cpp
+)
+
+PEERDIR(
+ library/cpp/scheme/tests/fuzz_json/lib
+)
+
+END()
diff --git a/library/cpp/scheme/tests/fuzz_ops/fuzz_ops.cpp b/library/cpp/scheme/tests/fuzz_ops/fuzz_ops.cpp
new file mode 100644
index 0000000000..facde50f5a
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_ops/fuzz_ops.cpp
@@ -0,0 +1,6 @@
+#include <library/cpp/scheme/tests/fuzz_ops/lib/fuzz_ops.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const ui8* wireData, const size_t wireSize) {
+ NSc::NUt::FuzzOps({(const char*)wireData, wireSize}, false);
+ return 0;
+}
diff --git a/library/cpp/scheme/tests/fuzz_ops/lib/fuzz_ops.cpp b/library/cpp/scheme/tests/fuzz_ops/lib/fuzz_ops.cpp
new file mode 100644
index 0000000000..8a7facba24
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_ops/lib/fuzz_ops.cpp
@@ -0,0 +1,37 @@
+#include "fuzz_ops.h"
+#include "vm_apply.h"
+#include "vm_defs.h"
+#include "vm_parse.h"
+
+#include <library/cpp/bit_io/bitinput.h>
+
+#include <library/cpp/scheme/scheme.h>
+#include <library/cpp/scheme/scimpl_private.h>
+
+#include <util/generic/maybe.h>
+
+namespace NSc::NUt {
+
+ void FuzzOps(TStringBuf wire, bool log) {
+ if (log) {
+ NImpl::GetTlsInstance<NImpl::TSelfLoopContext>().ReportingMode = NImpl::TSelfLoopContext::EMode::Stderr;
+ }
+
+ // We start with a single TValue node
+ TVMState st {wire, 1, 0};
+
+ while (auto act = ParseNextAction(st)) {
+ if (log) {
+ Cerr << " STATE: " << st.ToString() << Endl;
+ Cerr << "ACTION: " << (act ? act->ToString() : TString("(empty)")) << Endl;
+ }
+
+ if (!ApplyNextAction(st, *act)) {
+ break;
+ }
+ if (!NSc::TValue::DefaultValue().IsNull()) {
+ std::terminate();
+ }
+ }
+ }
+}
diff --git a/library/cpp/scheme/tests/fuzz_ops/lib/fuzz_ops.h b/library/cpp/scheme/tests/fuzz_ops/lib/fuzz_ops.h
new file mode 100644
index 0000000000..26ba42eaef
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_ops/lib/fuzz_ops.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+namespace NSc::NUt {
+ void FuzzOps(TStringBuf wire, bool log);
+}
diff --git a/library/cpp/scheme/tests/fuzz_ops/lib/vm_apply.cpp b/library/cpp/scheme/tests/fuzz_ops/lib/vm_apply.cpp
new file mode 100644
index 0000000000..ada7b8854f
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_ops/lib/vm_apply.cpp
@@ -0,0 +1,302 @@
+#include "vm_apply.h"
+
+namespace NSc::NUt {
+
+#define Y_GEN_TRY_OP(op) \
+ if (!op) { return false; }
+
+#define Y_GEN_SRC_OP(op, arg, st, act) \
+ switch (act.GetSrc(arg).Type) { \
+ case TSrc::T_LREF__POS: \
+ op(st.LRef(act.GetSrc(arg).Pos)); \
+ break; \
+ case TSrc::T_CREF__POS: \
+ op(st.CRef(act.GetSrc(arg).Pos)); \
+ break; \
+ case TSrc::T_RREF__POS: \
+ op(st.RRef(act.GetSrc(arg).Pos)); \
+ break; \
+ default: \
+ Y_FAIL(); \
+ }
+
+
+#define Y_GEN_SRC_TRY_OP(op, arg, st, act) \
+ if (st.CRef(act.GetSrc(arg).Pos).IsSameOrAncestorOf(st.Current())) { \
+ return false; \
+ } \
+ Y_GEN_SRC_OP(op, arg, st, act);
+
+
+#define Y_GEN_DST_OP(op, arg, st, act) \
+ switch (act.GetDst(arg).Type) { \
+ case TDst::T_CREATE_BACK_LREF: \
+ Y_GEN_TRY_OP(st.TryPushBack(op)) \
+ break; \
+ case TDst::T_CREATE_BACK_CREF: \
+ Y_GEN_TRY_OP(st.TryPushBack(std::as_const(op))) \
+ break; \
+ case TDst::T_CREATE_BACK_RREF: \
+ Y_GEN_TRY_OP(st.TryPushBack(std::move(op))) \
+ break; \
+ case TDst::T_CREATE_FRONT_LREF: \
+ Y_GEN_TRY_OP(st.TryPushFront(op)) \
+ break; \
+ case TDst::T_CREATE_FRONT_CREF: \
+ Y_GEN_TRY_OP(st.TryPushFront(std::as_const(op))) \
+ break; \
+ case TDst::T_CREATE_FRONT_RREF: \
+ Y_GEN_TRY_OP(st.TryPushFront(std::move(op))) \
+ break; \
+ case TDst::T_LREF__POS: \
+ st.LRef(act.GetDst(arg).Pos) = op; \
+ break; \
+ case TDst::T_CREF__POS: \
+ st.LRef(act.GetDst(arg).Pos) = std::as_const(op); \
+ break; \
+ case TDst::T_RREF__POS: \
+ st.LRef(act.GetDst(arg).Pos) = std::move(op); \
+ break; \
+ default: \
+ Y_FAIL(); \
+ }
+
+
+#define Y_GEN_REF_OP(op, arg, st, act) \
+ switch (act.GetRef(arg).Type) { \
+ case TRef::T_CREATE_BACK: \
+ Y_GEN_TRY_OP(st.TryPushBack(op)) \
+ break; \
+ case TRef::T_CREATE_FRONT: \
+ Y_GEN_TRY_OP(st.TryPushFront(op)) \
+ break; \
+ case TRef::T_REF__POS: \
+ st.LRef(act.GetRef(arg).Pos) = op; \
+ break; \
+ default: \
+ Y_FAIL(); \
+ }
+
+#define Y_GEN_PTR_OP(op, arg, st, act) \
+ if (auto* r = (op)) { \
+ switch (act.GetRef(arg).Type) { \
+ case TRef::T_CREATE_BACK: \
+ Y_GEN_TRY_OP(st.TryPushBack(*r)) \
+ break; \
+ case TRef::T_CREATE_FRONT: \
+ Y_GEN_TRY_OP(st.TryPushFront(*r)) \
+ break; \
+ case TRef::T_REF__POS: \
+ st.LRef(act.GetRef(arg).Pos) = *r; \
+ break; \
+ default: \
+ Y_FAIL(); \
+ } \
+ }
+
+ bool ApplyNextAction(TVMState& st, TVMAction act) {
+ switch (act.Type) {
+ case VMA_JMP__POS:
+ st.Pos = act.GetPos(0);
+ return true;
+
+ case VMA_CREATE_BACK:
+ Y_GEN_TRY_OP(st.TryPushBack())
+ return true;
+
+ case VMA_CREATE_BACK__SRC:
+ switch (act.GetSrc(0).Type) {
+ case TSrc::T_LREF__POS:
+ Y_GEN_TRY_OP(st.TryPushBack(st.LRef(act.GetSrc(0).Pos)))
+ break;
+ case TSrc::T_CREF__POS:
+ Y_GEN_TRY_OP(st.TryPushBack(st.CRef(act.GetSrc(0).Pos)))
+ break;
+ case TSrc::T_RREF__POS:
+ Y_GEN_TRY_OP(st.TryPushBack(st.RRef(act.GetSrc(0).Pos)))
+ break;
+ default:
+ Y_FAIL();
+ }
+
+ return true;
+
+ case VMA_CREATE_FRONT:
+ Y_GEN_TRY_OP(st.TryPushFront())
+ return true;
+
+ case VMA_CREATE_FRONT__SRC:
+ switch (act.GetSrc(0).Type) {
+ case TSrc::T_LREF__POS:
+ Y_GEN_TRY_OP(st.TryPushFront(st.LRef(act.GetSrc(0).Pos)))
+ break;
+ case TSrc::T_CREF__POS:
+ Y_GEN_TRY_OP(st.TryPushFront(st.CRef(act.GetSrc(0).Pos)))
+ break;
+ case TSrc::T_RREF__POS:
+ Y_GEN_TRY_OP(st.TryPushFront(st.RRef(act.GetSrc(0).Pos)))
+ break;
+ default:
+ Y_FAIL();
+ }
+ return true;
+
+ case VMA_DESTROY_BACK:
+ return st.TryPopBack();
+
+ case VMA_DESTROY_FRONT:
+ return st.TryPopFront();
+
+ case VMA_ASSIGN__SRC:
+ Y_GEN_SRC_OP(st.Current() = , 0, st, act);
+ return true;
+
+ case VMA_SET_STRING__IDX:
+ st.Current().SetString(act.GetString(0));
+ return true;
+
+ case VMA_SET_INT_NUMBER__IDX:
+ st.Current().SetIntNumber(act.GetIntNumber(0));
+ return true;
+
+ case VMA_SET_DICT:
+ st.Current().SetDict();
+ return true;
+
+ case VMA_SET_ARRAY:
+ st.Current().SetArray();
+ return true;
+
+ case VMA_SET_NULL:
+ st.Current().SetNull();
+ return true;
+
+ case VMA_GET_JSON:
+ st.Current().ToJson();
+ return true;
+
+ case VMA_ARRAY_CLEAR:
+ st.Current().ClearArray();
+ return true;
+
+ case VMA_ARRAY_PUSH:
+ st.Current().Push();
+ return true;
+
+ case VMA_ARRAY_PUSH__SRC:
+ Y_GEN_SRC_TRY_OP(st.Current().Push, 0, st, act);
+ return true;
+
+ case VMA_ARRAY_PUSH__DST:
+ Y_GEN_DST_OP(st.Current().Push(), 0, st, act);
+ return true;
+
+ case VMA_ARRAY_POP__REF:
+ Y_GEN_REF_OP(st.Current().Pop(), 0, st, act);
+ return true;
+
+ case VMA_ARRAY_INSERT__IDX:
+ st.Current().Insert(act.GetIdx(0));
+ return true;
+
+ case VMA_ARRAY_INSERT__IDX_SRC:
+ Y_GEN_SRC_TRY_OP(st.Current().Insert(act.GetIdx(0)) = , 1, st, act);
+ return true;
+
+ case VMA_ARRAY_INSERT__IDX_DST:
+ Y_GEN_DST_OP(st.Current().Insert(act.GetIdx(0)), 1, st, act);
+ return true;
+
+ case VMA_ARRAY_DELETE__IDX_REF:
+ Y_GEN_REF_OP(st.Current().Delete(act.GetIdx(0)), 1, st, act);
+ return true;
+
+ case VMA_ARRAY_GET__IDX_REF:
+ Y_GEN_REF_OP(st.Current().Get(act.GetIdx(0)), 1, st, act);
+ return true;
+
+ case VMA_ARRAY_GET_OR_ADD__IDX:
+ st.Current().GetOrAdd(act.GetIdx(0));
+ return true;
+
+ case VMA_ARRAY_GET_OR_ADD__IDX_SRC:
+ Y_GEN_SRC_TRY_OP(st.Current().GetOrAdd(act.GetIdx(0)) = , 1, st, act);
+ return true;
+
+ case VMA_ARRAY_GET_OR_ADD__IDX_DST:
+ Y_GEN_DST_OP(st.Current().GetOrAdd(act.GetIdx(0)), 1, st, act);
+ return true;
+
+ case VMA_ARRAY_GET_NO_ADD__IDX_REF:
+ Y_GEN_PTR_OP(st.Current().GetNoAdd(act.GetIdx(0)), 1, st, act);
+ return true;
+
+ case VMA_DICT_CLEAR:
+ st.Current().ClearDict();
+ return true;
+
+ case VMA_DICT_DELETE__IDX:
+ st.Current().Delete(act.GetKey(0));
+ return true;
+
+ case VMA_DICT_DELETE__IDX_REF:
+ Y_GEN_REF_OP(st.Current().Delete(act.GetKey(0)), 1, st, act);
+ return true;
+
+ case VMA_DICT_GET__IDX_REF:
+ Y_GEN_REF_OP(st.Current().Get(act.GetKey(0)), 1, st, act);
+ return true;
+
+ case VMA_DICT_GET_OR_ADD__IDX:
+ st.Current().GetOrAdd(act.GetKey(0));
+ return true;
+
+ case VMA_DICT_GET_OR_ADD__IDX_SRC:
+ Y_GEN_SRC_TRY_OP(st.Current().GetOrAdd(act.GetKey(0)) = , 1, st, act);
+ return true;
+
+ case VMA_DICT_GET_OR_ADD__IDX_DST:
+ Y_GEN_DST_OP(st.Current().GetOrAdd(act.GetKey(0)), 1, st, act);
+ return true;
+
+ case VMA_DICT_GET_NO_ADD__IDX_REF:
+ Y_GEN_PTR_OP(st.Current().GetNoAdd(act.GetKey(0)), 1, st, act);
+ return true;
+
+ case VMA_MERGE_UPDATE__POS:
+ st.Current().MergeUpdate(st.LRef(act.GetPos(0)));
+ return true;
+
+ case VMA_MERGE_REVERSE__POS:
+ st.Current().ReverseMerge(st.LRef(act.GetPos(0)));
+ return true;
+
+ case VMA_MERGE_COPY_FROM__POS:
+ st.Current().CopyFrom(st.LRef(act.GetPos(0)));
+ return true;
+
+ case VMA_SWAP__POS:
+ st.Current().Swap(st.LRef(act.GetPos(0)));
+ return true;
+
+ case VMA_EQUAL__POS_POS:
+ TValue::Equal(st.CRef(act.GetPos(0)), st.CRef(act.GetPos(1)));
+ return true;
+
+ case VMA_SELECT_NO_ADD__PATH_REF:
+ Y_GEN_REF_OP(st.Current().TrySelect(act.GetPath(0)), 1, st, act);
+ return true;
+
+ case VMA_SELECT_OR_ADD__PATH_REF:
+ Y_GEN_PTR_OP(st.Current().TrySelectOrAdd(act.GetPath(0)), 1, st, act);
+ return true;
+
+ case VMA_SELECT_AND_DELETE__PATH_REF:
+ Y_GEN_REF_OP(st.Current().TrySelectAndDelete(act.GetPath(0)), 1, st, act);
+ return true;
+
+ default:
+ Y_FAIL();
+ }
+ }
+}
diff --git a/library/cpp/scheme/tests/fuzz_ops/lib/vm_apply.h b/library/cpp/scheme/tests/fuzz_ops/lib/vm_apply.h
new file mode 100644
index 0000000000..82906b53fb
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_ops/lib/vm_apply.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "vm_defs.h"
+
+namespace NSc::NUt {
+
+ bool ApplyNextAction(TVMState& st, TVMAction act);
+
+}
diff --git a/library/cpp/scheme/tests/fuzz_ops/lib/vm_defs.cpp b/library/cpp/scheme/tests/fuzz_ops/lib/vm_defs.cpp
new file mode 100644
index 0000000000..55a971d9e4
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_ops/lib/vm_defs.cpp
@@ -0,0 +1,168 @@
+#include "vm_defs.h"
+
+#include <util/generic/xrange.h>
+#include <util/string/builder.h>
+
+namespace NSc::NUt {
+ namespace {
+ TStringBuf GetStringByIdx(ui32 idx) {
+ static const TStringBuf strings[TIdx::ValueCount] {{}, "a", "aa", "aaa"};
+ return strings[idx % TIdx::ValueCount];
+ }
+ }
+
+
+ TVMState::TVMState(TStringBuf wire, ui32 memSz, ui32 pos)
+ : Input(wire)
+ , Memory(memSz)
+ , Pos(pos)
+ {}
+
+ bool TVMState::TryPushBack() {
+ if (MayAddMoreMemory()) {
+ Memory.emplace_back();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ bool TVMState::TryPushFront() {
+ if (MayAddMoreMemory()) {
+ Pos += 1;
+ Memory.emplace_front();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ bool TVMState::TryPopBack() {
+ if (Memory.size() > 1 && Pos < Memory.size() - 1) {
+ Memory.pop_back();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ bool TVMState::TryPopFront() {
+ if (Memory.size() > 1 && Pos > 0) {
+ Memory.pop_front();
+ Pos -= 1;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ TString TVMState::ToString() const {
+ TStringBuilder b;
+ b << "pos=" << Pos << ";";
+ for (const auto i : xrange(Memory.size())) {
+ b << " " << i << (i == Pos ? "@" : ".") << Memory[i].ToJson().Quote();
+ }
+
+ return b;
+ }
+
+ TString TIdx::ToString() const {
+ return TStringBuilder() << "IDX:" << Idx;
+ }
+
+ TString TPos::ToString() const {
+ return TStringBuilder() << "POS:" << Pos;
+ }
+
+ template <class T>
+ TString RenderToString(TStringBuf name, T type, ui32 pos) {
+ TStringBuilder b;
+ b << name << ":" << type;
+ if ((ui32)-1 != pos) {
+ b << "," << pos;
+ }
+ return b;
+ }
+
+ TString TRef::ToString() const {
+ return RenderToString("REF", Type, Pos);
+ }
+
+ TString TSrc::ToString() const {
+ return RenderToString("SRC", Type, Pos);
+ }
+
+ TString TDst::ToString() const {
+ return RenderToString("DST", Type, Pos);
+ }
+
+ TString TPath::ToString() const {
+ return TStringBuilder() << "PATH:" << Path.Quote();
+ }
+
+
+ TRef TVMAction::GetRef(ui32 arg) const noexcept {
+ return std::get<TRef>(Arg[arg]);
+ }
+
+ TSrc TVMAction::GetSrc(ui32 arg) const noexcept {
+ return std::get<TSrc>(Arg[arg]);
+ }
+
+ TDst TVMAction::GetDst(ui32 arg) const noexcept {
+ return std::get<TDst>(Arg[arg]);
+ }
+
+ ui32 TVMAction::GetPos(ui32 arg) const noexcept {
+ return std::get<TPos>(Arg[arg]).Pos;
+ }
+
+ ui32 TVMAction::GetIdx(ui32 arg) const noexcept {
+ return std::get<TIdx>(Arg[arg]).Idx;
+ }
+
+ TStringBuf TVMAction::GetKey(ui32 arg) const noexcept {
+ return GetString(arg);
+ }
+
+ TStringBuf TVMAction::GetString(ui32 arg) const noexcept {
+ return GetStringByIdx(GetIdx(arg));
+ }
+
+ i64 TVMAction::GetIntNumber(ui32 arg) const noexcept {
+ return GetIdx(arg);
+ }
+
+ TStringBuf TVMAction::GetPath(ui32 arg) const noexcept {
+ return std::get<TPath>(Arg[arg]).Path;
+ }
+
+
+ struct TActionPrinter {
+ TActionPrinter(IOutputStream& out)
+ : Out(out)
+ {}
+
+ bool operator()(const std::monostate&) const {
+ return true;
+ }
+ //TIdx, TPos, TRef, TSrc, TDst, TPath
+ template <class T>
+ bool operator()(const T& t) const {
+ Out << "; " << t.ToString();
+ return false;
+ }
+ IOutputStream& Out;
+ };
+
+ TString TVMAction::ToString() const {
+ TStringBuilder out;
+ out << Type;
+ for (const auto& arg : Arg) {
+ if (std::visit(TActionPrinter(out.Out), arg)) {
+ break;
+ }
+ }
+ return out;
+ }
+}
diff --git a/library/cpp/scheme/tests/fuzz_ops/lib/vm_defs.h b/library/cpp/scheme/tests/fuzz_ops/lib/vm_defs.h
new file mode 100644
index 0000000000..9a0ddf7351
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_ops/lib/vm_defs.h
@@ -0,0 +1,277 @@
+#pragma once
+
+#include <library/cpp/bit_io/bitinput.h>
+#include <library/cpp/scheme/scheme.h>
+
+#include <util/generic/deque.h>
+#include <util/generic/maybe.h>
+#include <util/generic/variant.h>
+#include <util/string/builder.h>
+
+namespace NSc::NUt {
+
+ enum EVMAction {
+ VMA_JMP__POS /* "pos=POS" */,
+
+ VMA_CREATE_BACK /* "TValue()->emplace_back" */,
+ VMA_CREATE_BACK__SRC /* "TValue(SRC)->emplace_back" */,
+ VMA_CREATE_FRONT /* "TValue()->emplace_front,pos+=1" */,
+ VMA_CREATE_FRONT__SRC /* "TValue(SRC)->emplace_front,pos+=1" */,
+
+ VMA_DESTROY_BACK /* "pop_back" */,
+ VMA_DESTROY_FRONT /* "pop_front,pos-=1" */,
+
+ VMA_ASSIGN__SRC /* "operator=(SRC)" */,
+
+ VMA_SET_STRING__IDX /* "SetString(str[IDX])" */,
+ VMA_SET_INT_NUMBER__IDX /* "SetIntNumber(IDX)" */,
+ VMA_SET_DICT /* "SetDict()" */,
+ VMA_SET_ARRAY /* "SetArray()" */,
+ VMA_SET_NULL /* "SetNull()" */,
+
+ VMA_GET_JSON /* "ToJson()" */,
+
+ VMA_ARRAY_CLEAR /* "ClearArray()" */,
+ VMA_ARRAY_PUSH /* "Push()" */,
+ VMA_ARRAY_PUSH__SRC /* "Push()=SRC" */,
+ VMA_ARRAY_PUSH__DST /* "Push()->DST" */,
+ VMA_ARRAY_POP /* "Pop()" */,
+ VMA_ARRAY_POP__REF /* "Pop()->REF" */,
+ VMA_ARRAY_INSERT__IDX /* "Insert(IDX)" */,
+ VMA_ARRAY_INSERT__IDX_SRC /* "Insert(IDX)=SRC" */,
+ VMA_ARRAY_INSERT__IDX_DST /* "Insert(IDX)->DST" */,
+ VMA_ARRAY_DELETE__IDX /* "Delete(IDX)" */,
+ VMA_ARRAY_DELETE__IDX_REF /* "Delete(IDX)->REF" */,
+ VMA_ARRAY_GET__IDX_REF /* "Get(IDX)->REF" */,
+ VMA_ARRAY_GET_OR_ADD__IDX /* "GetOrAdd(IDX)" */,
+ VMA_ARRAY_GET_OR_ADD__IDX_SRC /* "GetOrAdd(IDX)=SRC" */,
+ VMA_ARRAY_GET_OR_ADD__IDX_DST /* "GetOrAdd(IDX)->DST" */,
+ VMA_ARRAY_GET_NO_ADD__IDX_REF /* "GetNoAdd(IDX)->REF" */,
+
+ VMA_DICT_CLEAR /* "ClearDict()" */,
+ VMA_DICT_DELETE__IDX /* "Delete(str[IDX])" */,
+ VMA_DICT_DELETE__IDX_REF /* "Delete(str[IDX])->REF" */,
+ VMA_DICT_GET__IDX_REF /* "Get(str[IDX])->REF" */,
+ VMA_DICT_GET_OR_ADD__IDX /* "GetOrAdd(str[IDX])" */,
+ VMA_DICT_GET_OR_ADD__IDX_SRC /* "GetOrAdd(str[IDX])=SRC" */,
+ VMA_DICT_GET_OR_ADD__IDX_DST /* "GetOrAdd(str[IDX])->DST" */,
+ VMA_DICT_GET_NO_ADD__IDX_REF /* "GetNoAdd(str[IDX])->REF" */,
+
+ VMA_MERGE_UPDATE__POS /* "MergeUpdate(POS)" */,
+ VMA_MERGE_REVERSE__POS /* "ReverseMerge(POS)" */,
+ VMA_MERGE_COPY_FROM__POS /* "CopyFrom(POS)" */,
+
+ VMA_SWAP__POS /* "Swap(POS)" */,
+ VMA_EQUAL__POS_POS /* "Equal(POS, POS)" */,
+
+ VMA_SELECT_NO_ADD__PATH_REF /* "TrySelect(PATH)->REF" */,
+ VMA_SELECT_OR_ADD__PATH_REF /* "TrySelectOrAdd(PATH)->REF" */,
+ VMA_SELECT_AND_DELETE__PATH_REF /* "TrySelectAndDelete(PATH)->REF" */,
+
+ VMA_COUNT,
+ };
+
+
+ struct TVMState {
+ NBitIO::TBitInput Input;
+ TDeque<TValue> Memory { 1 };
+ ui32 Pos = 0;
+
+ static const ui32 MaxMemory = 16;
+
+ public:
+ explicit TVMState(TStringBuf wire, ui32 memSz, ui32 pos);
+
+ TValue& Current() {
+ return Memory[Pos];
+ }
+
+ TValue& LRef(ui32 pos) {
+ return Memory[pos];
+ }
+
+ const TValue& CRef(ui32 pos) {
+ return Memory[pos];
+ }
+
+ TValue&& RRef(ui32 pos) {
+ return std::move(Memory[pos]);
+ }
+
+ [[nodiscard]]
+ bool TryPushBack();
+
+ template <class T>
+ [[nodiscard]]
+ bool TryPushBack(T&& t) {
+ if (MayAddMoreMemory()) {
+ Memory.emplace_back(std::forward<T>(t));
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ [[nodiscard]]
+ bool TryPushFront();
+
+ template <class T>
+ [[nodiscard]]
+ bool TryPushFront(T&& t) {
+ if (MayAddMoreMemory()) {
+ Pos += 1;
+ Memory.emplace_front(std::forward<T>(t));
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ [[nodiscard]]
+ bool TryPopBack();
+
+ [[nodiscard]]
+ bool TryPopFront();
+
+ TString ToString() const;
+
+ private:
+ [[nodiscard]]
+ bool MayAddMoreMemory() const noexcept {
+ return Memory.size() < MaxMemory;
+ }
+ };
+
+
+ struct TIdx {
+ ui32 Idx = -1;
+ static const ui32 ValueCount = 4;
+
+ public:
+ TString ToString() const;
+ };
+
+
+ struct TPos {
+ ui32 Pos = -1;
+ static const ui32 ValueCount = TVMState::MaxMemory;
+
+ public:
+ TString ToString() const;
+ };
+
+
+ struct TRef : public TPos {
+ enum EType {
+ T_CREATE_FRONT /* "emplace_front(RES),pos+=1" */,
+ T_CREATE_BACK /* "emplace_back(RES)" */,
+ T_REF__POS /* "pos@(RES)" */,
+ T_COUNT
+ };
+
+ EType Type = T_COUNT;
+ static const ui32 TypeCount = T_COUNT;
+
+ public:
+ TString ToString() const;
+ };
+
+
+ struct TSrc : public TPos {
+ enum EType {
+ T_LREF__POS /* "pos@(TValue&)" */,
+ T_CREF__POS /* "pos@(const TValue&)" */,
+ T_RREF__POS /* "pos@(TValue&&)" */,
+ T_COUNT
+ };
+
+ EType Type = T_COUNT;
+ static const ui32 TypeCount = T_COUNT;
+
+ public:
+ TString ToString() const;
+ };
+
+
+ struct TDst : public TPos {
+ enum EType {
+ T_CREATE_FRONT_LREF /* "emplace_front(TValue&),pos+=1" */,
+ T_CREATE_FRONT_CREF /* "emplace_front(const TValue&),pos+=1" */,
+ T_CREATE_FRONT_RREF /* "emplace_front(TValue&&),pos+=1" */,
+ T_CREATE_BACK_LREF /* "emplace_back(TValue&)" */,
+ T_CREATE_BACK_CREF /* "emplace_back(TValue&),pos+=1" */,
+ T_CREATE_BACK_RREF /* "emplace_back(TValue&),pos+=1" */,
+ T_LREF__POS /* "pos@(TValue&)" */,
+ T_CREF__POS /* "pos@(const TValue&)" */,
+ T_RREF__POS /* "pos@(TValue&&)" */,
+ T_COUNT
+ };
+
+ EType Type = T_COUNT;
+ static const ui32 TypeCount = T_COUNT;
+
+ public:
+ TString ToString() const;
+ };
+
+
+ struct TPath {
+ TString Path;
+ static const ui32 MaxLength = 32;
+
+ public:
+ TString ToString() const;
+ };
+
+ using TArg = std::variant<std::monostate, TIdx, TPos, TRef, TSrc, TDst, TPath>;
+
+ struct TVMAction {
+ using EType = EVMAction;
+ EVMAction Type = VMA_COUNT;
+ static const ui32 TypeCount = VMA_COUNT;
+
+ public:
+ template <class T>
+ bool SetArg(TMaybe<T> arg) {
+ Y_VERIFY(CurrArg < Y_ARRAY_SIZE(Arg));
+ if (arg) {
+ Arg[CurrArg++] = *arg;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public:
+ TRef GetRef(ui32 arg) const noexcept;
+
+ TSrc GetSrc(ui32 arg) const noexcept;
+
+ TDst GetDst(ui32 arg) const noexcept;
+
+
+ ui32 GetPos(ui32 arg) const noexcept;
+
+ ui32 GetIdx(ui32 arg) const noexcept;
+
+ TStringBuf GetKey(ui32 arg) const noexcept;
+
+ TStringBuf GetString(ui32 arg) const noexcept;
+
+ i64 GetIntNumber(ui32 arg) const noexcept;
+
+ TStringBuf GetPath(ui32 arg) const noexcept;
+
+ TString ToString() const;
+
+ private:
+ TArg Arg[2];
+ ui32 CurrArg = 0;
+ };
+
+ [[nodiscard]]
+ inline ui32 GetCountWidth(ui32 cnt) {
+ return MostSignificantBit(cnt - 1) + 1;
+ }
+
+}
diff --git a/library/cpp/scheme/tests/fuzz_ops/lib/vm_parse.cpp b/library/cpp/scheme/tests/fuzz_ops/lib/vm_parse.cpp
new file mode 100644
index 0000000000..a03f5aef53
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_ops/lib/vm_parse.cpp
@@ -0,0 +1,265 @@
+#include "vm_parse.h"
+
+namespace NSc::NUt {
+#define Y_TRY_READ_BITS(state, out, bits, res) do { if (!state.Input.Read(out, bits)) { return res; } } while (false)
+#define Y_TRY_READ_BITS_BOOL(state, out, bits) Y_TRY_READ_BITS(state, out, bits, false)
+#define Y_TRY_READ_BITS_MAYBE(state, out, bits) Y_TRY_READ_BITS(state, out, bits, Nothing())
+
+ TMaybe<TIdx> ParseIdx(TVMState& st) {
+ static_assert(IsPowerOf2(TIdx::ValueCount));
+ static const auto bits = GetCountWidth(TIdx::ValueCount);
+
+ TIdx idx;
+ if (!st.Input.Read(idx.Idx, bits)) {
+ return Nothing();
+ }
+ return idx;
+ }
+
+ namespace {
+ bool DoParsePos(TVMState& st, TPos& pos) {
+ static const auto bits = GetCountWidth(TPos::ValueCount);
+ const ui32 sz = st.Memory.size();
+
+ ui32 neg = -1;
+ Y_TRY_READ_BITS_BOOL(st, neg, 1);
+
+ ui32 delta = -1;
+ Y_TRY_READ_BITS_BOOL(st, delta, bits);
+
+ if (neg) {
+ if (st.Pos < delta) {
+ return false;
+ }
+ pos.Pos = st.Pos - delta;
+ } else {
+ if (st.Pos + delta >= sz) {
+ return false;
+ }
+ pos.Pos = st.Pos + delta;
+ }
+
+ return true;
+ }
+
+ template <class T>
+ bool DoParseType(TVMState& state, T& res) {
+ static const auto bits = GetCountWidth(T::TypeCount);
+
+ ui32 type = -1;
+ if (state.Input.Read(type, bits) && type < T::TypeCount) {
+ res.Type = (typename T::EType)(type);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ TMaybe<TPos> ParsePos(TVMState& state) {
+ TPos res;
+ if (DoParsePos(state, res)) {
+ return res;
+ }
+ return Nothing();
+ }
+
+ TMaybe<TRef> ParseRef(TVMState& state) {
+ TRef ref;
+ if (!DoParseType(state, ref)) {
+ return Nothing();
+ }
+
+ switch (ref.Type) {
+ case TRef::T_REF__POS:
+ if (!DoParsePos(state, ref)) {
+ return Nothing();
+ }
+ [[fallthrough]];
+ case TRef::T_CREATE_FRONT:
+ case TRef::T_CREATE_BACK:
+ return ref;
+ default:
+ Y_FAIL();
+ }
+ }
+
+ TMaybe<TSrc> ParseSrc(TVMState& state) {
+ TSrc src;
+ if (!DoParseType(state, src)) {
+ return Nothing();
+ }
+
+ switch (src.Type) {
+ case TSrc::T_LREF__POS:
+ case TSrc::T_CREF__POS:
+ case TSrc::T_RREF__POS:
+ if (!DoParsePos(state, src)) {
+ return Nothing();
+ }
+ return src;
+ default:
+ Y_FAIL();
+ }
+ }
+
+ TMaybe<TDst> ParseDst(TVMState& state) {
+ TDst dst;
+ if (!DoParseType(state, dst)) {
+ return Nothing();
+ }
+
+ switch (dst.Type) {
+ case TDst::T_LREF__POS:
+ case TDst::T_CREF__POS:
+ case TDst::T_RREF__POS:
+ if (!DoParsePos(state, dst)) {
+ return Nothing();
+ }
+ [[fallthrough]];
+ case TDst::T_CREATE_FRONT_LREF:
+ case TDst::T_CREATE_FRONT_CREF:
+ case TDst::T_CREATE_FRONT_RREF:
+ case TDst::T_CREATE_BACK_LREF:
+ case TDst::T_CREATE_BACK_CREF:
+ case TDst::T_CREATE_BACK_RREF:
+ return dst;
+ default:
+ Y_FAIL();
+ }
+ }
+
+ TMaybe<TPath> ParsePath(TVMState& state) {
+ static const ui32 bits = GetCountWidth(TPath::MaxLength);
+ TPath path;
+
+ ui32 len = -1;
+ Y_TRY_READ_BITS_MAYBE(state, len, bits);
+ while (len--) {
+ ui8 c;
+ Y_TRY_READ_BITS_MAYBE(state, c, 8);
+ path.Path.push_back(c);
+ }
+ return path;
+ }
+
+ TMaybe<TVMAction> ParseNextAction(TVMState& state) {
+ TVMAction res;
+
+ if (!DoParseType(state, res)) {
+ return Nothing();
+ }
+
+ switch (res.Type) {
+ case VMA_CREATE_BACK:
+ case VMA_CREATE_FRONT:
+ case VMA_DESTROY_BACK:
+ case VMA_DESTROY_FRONT:
+
+ case VMA_SET_DICT:
+ case VMA_SET_ARRAY:
+ case VMA_SET_NULL:
+ case VMA_GET_JSON:
+
+ case VMA_ARRAY_CLEAR:
+ case VMA_ARRAY_PUSH:
+ case VMA_DICT_CLEAR:
+ return res;
+
+ case VMA_JMP__POS:
+ case VMA_MERGE_UPDATE__POS:
+ case VMA_MERGE_REVERSE__POS:
+ case VMA_MERGE_COPY_FROM__POS:
+ case VMA_SWAP__POS:
+ if (res.SetArg(ParsePos(state))) {
+ return res;
+ } else {
+ return Nothing();
+ }
+
+ case VMA_ARRAY_POP__REF:
+ if (res.SetArg(ParseRef(state))) {
+ return res;
+ } else {
+ return Nothing();
+ }
+
+ case VMA_SET_STRING__IDX:
+ case VMA_SET_INT_NUMBER__IDX:
+ case VMA_ARRAY_INSERT__IDX:
+ case VMA_ARRAY_GET_OR_ADD__IDX:
+ case VMA_DICT_GET_OR_ADD__IDX:
+ if (res.SetArg(ParseIdx(state))) {
+ return res;
+ } else {
+ return Nothing();
+ }
+
+ case VMA_CREATE_BACK__SRC:
+ case VMA_CREATE_FRONT__SRC:
+ case VMA_ASSIGN__SRC:
+ case VMA_ARRAY_PUSH__SRC:
+ if (res.SetArg(ParseSrc(state))) {
+ return res;
+ } else {
+ return Nothing();
+ }
+
+ case VMA_ARRAY_PUSH__DST:
+ if (res.SetArg(ParseDst(state))) {
+ return res;
+ } else {
+ return Nothing();
+ }
+
+ case VMA_ARRAY_DELETE__IDX_REF:
+ case VMA_ARRAY_GET__IDX_REF:
+ case VMA_ARRAY_GET_NO_ADD__IDX_REF:
+ case VMA_DICT_DELETE__IDX_REF:
+ case VMA_DICT_GET__IDX_REF:
+ case VMA_DICT_GET_NO_ADD__IDX_REF:
+ if (res.SetArg(ParseIdx(state)) && res.SetArg(ParseRef(state))) {
+ return res;
+ } else {
+ return Nothing();
+ }
+
+ case VMA_ARRAY_INSERT__IDX_SRC:
+ case VMA_ARRAY_GET_OR_ADD__IDX_SRC:
+ case VMA_DICT_GET_OR_ADD__IDX_SRC:
+ if (res.SetArg(ParseIdx(state)) && res.SetArg(ParseSrc(state))) {
+ return res;
+ } else {
+ return Nothing();
+ }
+
+ case VMA_ARRAY_INSERT__IDX_DST:
+ case VMA_ARRAY_GET_OR_ADD__IDX_DST:
+ case VMA_DICT_GET_OR_ADD__IDX_DST:
+ if (res.SetArg(ParseIdx(state)) && res.SetArg(ParseDst(state))) {
+ return res;
+ } else {
+ return Nothing();
+ }
+
+ case VMA_EQUAL__POS_POS:
+ if (res.SetArg(ParsePos(state)) && res.SetArg(ParsePos(state))) {
+ return res;
+ } else {
+ return Nothing();
+ }
+
+ case VMA_SELECT_NO_ADD__PATH_REF:
+ case VMA_SELECT_OR_ADD__PATH_REF:
+ case VMA_SELECT_AND_DELETE__PATH_REF:
+ if (res.SetArg(ParsePath(state)) && res.SetArg(ParseRef(state))) {
+ return res;
+ } else {
+ return Nothing();
+ }
+
+ default:
+ return Nothing();
+ }
+ }
+}
diff --git a/library/cpp/scheme/tests/fuzz_ops/lib/vm_parse.h b/library/cpp/scheme/tests/fuzz_ops/lib/vm_parse.h
new file mode 100644
index 0000000000..b4aba4e4d4
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_ops/lib/vm_parse.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "vm_defs.h"
+
+namespace NSc::NUt {
+
+ TMaybe<TIdx> ParseIdx(TVMState& st);
+ TMaybe<TPos> ParsePos(TVMState& state);
+ TMaybe<TRef> ParseRef(TVMState& state);
+ TMaybe<TSrc> ParseSrc(TVMState& state);
+ TMaybe<TDst> ParseDst(TVMState& state);
+ TMaybe<TPath> ParsePath(TVMState& state);
+
+ TMaybe<TVMAction> ParseNextAction(TVMState& state);
+
+}
diff --git a/library/cpp/scheme/tests/fuzz_ops/lib/ya.make b/library/cpp/scheme/tests/fuzz_ops/lib/ya.make
new file mode 100644
index 0000000000..279a2ca2d4
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_ops/lib/ya.make
@@ -0,0 +1,23 @@
+LIBRARY()
+
+OWNER(
+ g:blender
+ g:middle
+ g:upper
+ velavokr
+)
+
+GENERATE_ENUM_SERIALIZATION(vm_defs.h)
+
+SRCS(
+ fuzz_ops.cpp
+ vm_apply.cpp
+ vm_defs.cpp
+ vm_parse.cpp
+)
+
+PEERDIR(
+ library/cpp/scheme
+)
+
+END()
diff --git a/library/cpp/scheme/tests/fuzz_ops/ut/vm_parse_ut.cpp b/library/cpp/scheme/tests/fuzz_ops/ut/vm_parse_ut.cpp
new file mode 100644
index 0000000000..ce3786a671
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_ops/ut/vm_parse_ut.cpp
@@ -0,0 +1,225 @@
+#include <library/cpp/scheme/tests/fuzz_ops/lib/vm_parse.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TestParseNextAction) {
+ using namespace NSc::NUt;
+
+ Y_UNIT_TEST(TestWidth) {
+ UNIT_ASSERT_VALUES_EQUAL(GetCountWidth(TIdx::ValueCount), 2);
+ UNIT_ASSERT_VALUES_EQUAL(GetCountWidth(TPos::ValueCount), 4);
+ UNIT_ASSERT_VALUES_EQUAL(GetCountWidth(TRef::TypeCount), 2);
+ UNIT_ASSERT_VALUES_EQUAL(GetCountWidth(TSrc::TypeCount), 2);
+ UNIT_ASSERT_VALUES_EQUAL(GetCountWidth(TDst::TypeCount), 4);
+ UNIT_ASSERT_VALUES_EQUAL(GetCountWidth(TPath::MaxLength), 5);
+ UNIT_ASSERT_VALUES_EQUAL(GetCountWidth(TVMAction::TypeCount), 6);
+ }
+
+ Y_UNIT_TEST(TestParseIdx) {
+ {
+ TVMState st{"", 1, 0};
+ UNIT_ASSERT(!ParseIdx(st));
+ }
+ {
+ TVMState st{"\x03", 1, 0};
+ auto idx = ParseIdx(st);
+ UNIT_ASSERT(idx);
+ UNIT_ASSERT_VALUES_EQUAL(idx->Idx, 3);
+ }
+ }
+
+ void DoTestParsePosFailure(const TStringBuf inp, const ui32 memSz, const ui32 curPos) {
+ TVMState st{inp, memSz, curPos};
+ UNIT_ASSERT(!ParsePos(st));
+ }
+
+ [[nodiscard]]
+ ui32 DoTestParsePosSuccess(TVMState& st) {
+ const auto pos = ParsePos(st);
+ UNIT_ASSERT(pos);
+ return pos->Pos;
+ }
+
+ [[nodiscard]]
+ ui32 DoTestParsePosSuccess(const TStringBuf inp, const ui32 memSz, const ui32 curPos) {
+ TVMState st{inp, memSz, curPos};
+ return DoTestParsePosSuccess(st);
+ }
+
+ Y_UNIT_TEST(TestParsePos) {
+ DoTestParsePosFailure("", 1, 0);
+
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParsePosSuccess(TStringBuf("\x00"sv), 1, 0), 0);
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParsePosSuccess(TStringBuf("\x01"sv), 1, 0), 0);
+
+ DoTestParsePosFailure(TStringBuf("\x02"sv), 1, 0);
+ DoTestParsePosFailure(TStringBuf("\x03"sv), 2, 0);
+
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParsePosSuccess(TStringBuf("\x02"sv), 2, 0), 1);
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParsePosSuccess(TStringBuf("\x03"sv), 2, 1), 0);
+
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParsePosSuccess(TStringBuf("\x0E"sv), 8, 0), 7);
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParsePosSuccess(TStringBuf("\x0F"sv), 8, 7), 0);
+
+ {
+ TVMState st{TStringBuf("\xDE\x7B"), 16, 0};
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParsePosSuccess(st), 15);
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParsePosSuccess(st), 15);
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParsePosSuccess(st), 15);
+ UNIT_ASSERT(!ParsePos(st));
+ }
+ {
+ TVMState st{TStringBuf("\xFF\x7F"), 16, 15};
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParsePosSuccess(st), 0);
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParsePosSuccess(st), 0);
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParsePosSuccess(st), 0);
+ UNIT_ASSERT(!ParsePos(st));
+ }
+ }
+
+ void DoTestParseRefFailure(const TStringBuf inp, const ui32 memSz, const ui32 curPos) {
+ TVMState st{inp, memSz, curPos};
+ UNIT_ASSERT(!ParseRef(st));
+ }
+
+ [[nodiscard]]
+ auto DoTestParseRefSuccess(TVMState& st) {
+ const auto ref = ParseRef(st);
+ UNIT_ASSERT(ref);
+ return std::make_pair(ref->Pos, ref->Type);
+ }
+
+ [[nodiscard]]
+ auto DoTestParseRefSuccess(const TStringBuf inp, const ui32 memSz, const ui32 curPos) {
+ TVMState st{inp, memSz, curPos};
+ return DoTestParseRefSuccess(st);
+ }
+
+ Y_UNIT_TEST(TestParseRef) {
+ DoTestParseRefFailure("", 1, 0);
+
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseRefSuccess(TStringBuf("\x00"sv), 1, 0), std::make_pair((ui32)-1, TRef::T_CREATE_FRONT));
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseRefSuccess(TStringBuf("\x01"sv), 1, 0), std::make_pair((ui32)-1, TRef::T_CREATE_BACK));
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseRefSuccess(TStringBuf("\x0A"sv), 2, 0), std::make_pair(1u, TRef::T_REF__POS));
+
+ DoTestParseRefFailure(TStringBuf("\x12"), 1, 0);
+ DoTestParseRefFailure(TStringBuf("\x03"sv), 1, 0);
+
+ {
+ TVMState st{TStringBuf("\x7A\x7D"), 16, 0};
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseRefSuccess(st), std::make_pair(15u, TRef::T_REF__POS));
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseRefSuccess(st), std::make_pair(15u, TRef::T_REF__POS));
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseRefSuccess(st), std::make_pair((ui32)-1, TRef::T_CREATE_BACK));
+ UNIT_ASSERT(!ParseRef(st));
+ }
+ }
+
+ void DoTestParseSrcFailure(const TStringBuf inp, const ui32 memSz, const ui32 curPos) {
+ TVMState st{inp, memSz, curPos};
+ UNIT_ASSERT(!ParseSrc(st));
+ }
+
+ [[nodiscard]]
+ auto DoTestParseSrcSuccess(TVMState& st) {
+ const auto src = ParseSrc(st);
+ UNIT_ASSERT(src);
+ return std::make_pair(src->Pos, src->Type);
+ }
+
+ [[nodiscard]]
+ auto DoTestParseSrcSuccess(const TStringBuf inp, const ui32 memSz, const ui32 curPos) {
+ TVMState st{inp, memSz, curPos};
+ return DoTestParseSrcSuccess(st);
+ }
+
+ Y_UNIT_TEST(TestParseSrc) {
+ DoTestParseSrcFailure("", 1, 0);
+
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseSrcSuccess(TStringBuf("\x08"sv), 2, 0), std::make_pair(1u, TSrc::T_LREF__POS));
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseSrcSuccess(TStringBuf("\x09"sv), 2, 0), std::make_pair(1u, TSrc::T_CREF__POS));
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseSrcSuccess(TStringBuf("\x0A"sv), 2, 0), std::make_pair(1u, TSrc::T_RREF__POS));
+
+ DoTestParseSrcFailure(TStringBuf("\x03"sv), 1, 0);
+
+ {
+ TVMState st{TStringBuf("\x7A\x7D"), 16, 0};
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseSrcSuccess(st), std::make_pair(15u, TSrc::T_RREF__POS));
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseSrcSuccess(st), std::make_pair(15u, TSrc::T_RREF__POS));
+ UNIT_ASSERT(!ParseSrc(st));
+ }
+ }
+
+ void DoTestParseDstFailure(const TStringBuf inp, const ui32 memSz, const ui32 curPos) {
+ TVMState st{inp, memSz, curPos};
+ UNIT_ASSERT(!ParseDst(st));
+ }
+
+ [[nodiscard]]
+ auto DoTestParseDstSuccess(TVMState& st) {
+ const auto dst = ParseDst(st);
+ UNIT_ASSERT(dst);
+ return std::make_pair(dst->Pos, dst->Type);
+ }
+
+ [[nodiscard]]
+ auto DoTestParseDstSuccess(const TStringBuf inp, const ui32 memSz, const ui32 curPos) {
+ TVMState st{inp, memSz, curPos};
+ return DoTestParseDstSuccess(st);
+ }
+
+ Y_UNIT_TEST(TestParseDst) {
+ DoTestParseDstFailure("", 1, 0);
+
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseDstSuccess(TStringBuf("\x00"sv), 1, 0), std::make_pair((ui32)-1, TDst::T_CREATE_FRONT_LREF));
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseDstSuccess(TStringBuf("\x01"sv), 1, 0), std::make_pair((ui32)-1, TDst::T_CREATE_FRONT_CREF));
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseDstSuccess(TStringBuf("\x02"sv), 1, 0), std::make_pair((ui32)-1, TDst::T_CREATE_FRONT_RREF));
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseDstSuccess(TStringBuf("\x03"sv), 1, 0), std::make_pair((ui32)-1, TDst::T_CREATE_BACK_LREF));
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseDstSuccess(TStringBuf("\x04"sv), 1, 0), std::make_pair((ui32)-1, TDst::T_CREATE_BACK_CREF));
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseDstSuccess(TStringBuf("\x05"sv), 1, 0), std::make_pair((ui32)-1, TDst::T_CREATE_BACK_RREF));
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseDstSuccess(TStringBuf("\x26\x00"sv), 2, 0), std::make_pair(1u, TDst::T_LREF__POS));
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseDstSuccess(TStringBuf("\x27\x00"sv), 2, 0), std::make_pair(1u, TDst::T_CREF__POS));
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseDstSuccess(TStringBuf("\x28\x00"sv), 2, 0), std::make_pair(1u, TDst::T_RREF__POS));
+
+ DoTestParseDstFailure(TStringBuf("\x06"sv), 1, 0);
+ DoTestParseDstFailure(TStringBuf("\x09\x00"sv), 1, 0);
+
+ {
+ TVMState st{TStringBuf("\x14\xE7\x09"sv), 16, 0};
+ // 4=4
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseDstSuccess(st), std::make_pair((ui32)-1, TDst::T_CREATE_BACK_CREF));
+ // 4=8
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseDstSuccess(st), std::make_pair((ui32)-1, TDst::T_CREATE_FRONT_CREF));
+ // 4+1+4=17
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseDstSuccess(st), std::make_pair(15u, TDst::T_CREF__POS));
+ // 4=21
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParseDstSuccess(st), std::make_pair((ui32)-1, TDst::T_CREATE_BACK_CREF));
+ UNIT_ASSERT(!ParseDst(st));
+ }
+ }
+
+ void DoTestParsePathFailure(const TStringBuf inp, const ui32 memSz, const ui32 curPos) {
+ TVMState st{inp, memSz, curPos};
+ UNIT_ASSERT(!ParsePath(st));
+ }
+
+ [[nodiscard]]
+ auto DoTestParsePathSuccess(TVMState& st) {
+ const auto path = ParsePath(st);
+ UNIT_ASSERT(path);
+ return path->Path;
+ }
+
+ [[nodiscard]]
+ auto DoTestParsePathSuccess(const TStringBuf inp, const ui32 memSz, const ui32 curPos) {
+ TVMState st{inp, memSz, curPos};
+ return DoTestParsePathSuccess(st);
+ }
+
+ Y_UNIT_TEST(TestParsePath) {
+ DoTestParsePathFailure("", 1, 0);
+
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParsePathSuccess(TStringBuf("\x00"sv), 1, 0), TStringBuf(""));
+ UNIT_ASSERT_VALUES_EQUAL(DoTestParsePathSuccess(TStringBuf("\x21\x0C"sv), 1, 0), TStringBuf("a"));
+
+ DoTestParsePathFailure("\x22\x0C", 1, 0);
+ }
+};
diff --git a/library/cpp/scheme/tests/fuzz_ops/ut/ya.make b/library/cpp/scheme/tests/fuzz_ops/ut/ya.make
new file mode 100644
index 0000000000..5c933518ea
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_ops/ut/ya.make
@@ -0,0 +1,15 @@
+UNITTEST()
+
+OWNER(velavokr)
+
+PEERDIR(
+ library/cpp/testing/unittest
+ library/cpp/scheme
+ library/cpp/scheme/tests/fuzz_ops/lib
+)
+
+SRCS(
+ vm_parse_ut.cpp
+)
+
+END()
diff --git a/library/cpp/scheme/tests/fuzz_ops/ya.make b/library/cpp/scheme/tests/fuzz_ops/ya.make
new file mode 100644
index 0000000000..025241ef20
--- /dev/null
+++ b/library/cpp/scheme/tests/fuzz_ops/ya.make
@@ -0,0 +1,18 @@
+FUZZ()
+
+OWNER(
+ g:blender
+ g:middle
+ g:upper
+ velavokr
+)
+
+SRCS(
+ fuzz_ops.cpp
+)
+
+PEERDIR(
+ library/cpp/scheme/tests/fuzz_ops/lib
+)
+
+END()
diff --git a/library/cpp/scheme/tests/ut/fuzz_ops_found_bugs_ut.cpp b/library/cpp/scheme/tests/ut/fuzz_ops_found_bugs_ut.cpp
new file mode 100644
index 0000000000..a445b0f87c
--- /dev/null
+++ b/library/cpp/scheme/tests/ut/fuzz_ops_found_bugs_ut.cpp
@@ -0,0 +1,12 @@
+#include <library/cpp/scheme/scheme.h>
+#include <library/cpp/scheme/tests/fuzz_ops/lib/fuzz_ops.h>
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/string/hex.h>
+
+Y_UNIT_TEST_SUITE(TTestSchemeFuzzOpsFoundBugs) {
+ using namespace NSc::NUt;
+
+ Y_UNIT_TEST(TestBug1) {
+ FuzzOps(HexDecode("98040129000525"), true);
+ }
+};
diff --git a/library/cpp/scheme/tests/ut/scheme_cast_ut.cpp b/library/cpp/scheme/tests/ut/scheme_cast_ut.cpp
new file mode 100644
index 0000000000..4f907157e9
--- /dev/null
+++ b/library/cpp/scheme/tests/ut/scheme_cast_ut.cpp
@@ -0,0 +1,162 @@
+#include <library/cpp/scheme/scheme.h>
+#include <library/cpp/scheme/scheme_cast.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/null.h>
+#include <util/string/subst.h>
+#include <util/string/util.h>
+
+using namespace NJsonConverters;
+
+using TVI = TVector<int>;
+using THI = THashMap<int, int>;
+using TMI = TMap<int, int>;
+using THSI = THashSet<int>;
+using TSI = TSet<int>;
+using TPI = std::pair<int, int>;
+
+Y_UNIT_TEST_SUITE(TSchemeCastTest) {
+ Y_UNIT_TEST(TestYVector) {
+ TVI v;
+ for (int i = 0; i < 3; ++i)
+ v.push_back(i);
+
+ UNIT_ASSERT_VALUES_EQUAL("[0,1,2]", ToJson(v));
+
+ TVI y(FromJson<TVI>(ToJson(v)));
+ UNIT_ASSERT_VALUES_EQUAL(v.size(), y.size());
+ UNIT_ASSERT(std::equal(v.begin(), v.end(), y.begin()));
+ }
+
+ Y_UNIT_TEST(TestYHash) {
+ THI h;
+ for (int i = 0; i < 3; ++i)
+ h[i] = i * i;
+
+ const TString etalon = "{\"0\":0,\"1\":1,\"2\":4}";
+ UNIT_ASSERT_VALUES_EQUAL(etalon, ToJson(h, true));
+
+ THI h2(FromJson<THI>(ToJson(h)));
+ UNIT_ASSERT_VALUES_EQUAL(ToJson(h2, true), ToJson(h, true));
+ }
+
+ Y_UNIT_TEST(TestYMap) {
+ TMI h;
+ for (int i = 0; i < 3; ++i)
+ h[i] = i * i;
+
+ const TString etalon = "{\"0\":0,\"1\":1,\"2\":4}";
+ UNIT_ASSERT_VALUES_EQUAL(etalon, ToJson(h, true));
+
+ TMI h2(FromJson<TMI>(ToJson(h)));
+ UNIT_ASSERT_VALUES_EQUAL(ToJson(h2, true), ToJson(h, true));
+ }
+
+ Y_UNIT_TEST(TestYHashSet) {
+ THSI h;
+ for (int i = 0; i < 3; ++i)
+ h.insert(i * i);
+
+ const TString etalon = "{\"0\":null,\"1\":null,\"4\":null}";
+ UNIT_ASSERT_VALUES_EQUAL(etalon, ToJson(h, true));
+
+ THSI h2(FromJson<THSI>(ToJson(h)));
+ UNIT_ASSERT_VALUES_EQUAL(ToJson(h2, true), ToJson(h, true));
+ }
+
+ Y_UNIT_TEST(TestYSet) {
+ TSI h;
+ for (int i = 0; i < 3; ++i)
+ h.insert(i * i);
+
+ const TString etalon = "{\"0\":null,\"1\":null,\"4\":null}";
+ UNIT_ASSERT_VALUES_EQUAL(etalon, ToJson(h, true));
+
+ TSI h2(FromJson<TSI>(ToJson(h)));
+ UNIT_ASSERT_VALUES_EQUAL(ToJson(h2, true), ToJson(h, true));
+ }
+
+ Y_UNIT_TEST(TestTPair) {
+ TPI p(1, 1);
+
+ const TString etalon = "[1,1]";
+ UNIT_ASSERT_VALUES_EQUAL(etalon, ToJson(p, true));
+
+ TPI p2(FromJson<TPI>(ToJson(p)));
+ UNIT_ASSERT_VALUES_EQUAL(ToJson(p2, true), ToJson(p, true));
+ }
+
+ struct TCustom: public IJsonSerializable {
+ int A, B;
+ TCustom()
+ : A(0)
+ , B(0){};
+ TCustom(int a, int b)
+ : A(a)
+ , B(b)
+ {
+ }
+ NSc::TValue ToTValue() const override {
+ NSc::TValue res;
+ res["a"] = A;
+ res["b"] = B;
+ return res;
+ }
+ void FromTValue(const NSc::TValue& v, const bool) override {
+ A = v["a"].GetNumber();
+ B = v["b"].GetNumber();
+ }
+
+ bool operator<(const TCustom& rhs) const {
+ return A < rhs.A;
+ }
+ };
+
+ Y_UNIT_TEST(TestTCustom) {
+ TCustom x(2, 3);
+
+ const TString etalon = "{\"a\":2,\"b\":3}";
+ UNIT_ASSERT_VALUES_EQUAL(etalon, ToJson(x, true));
+
+ TCustom x2(FromJson<TCustom>(ToJson(x)));
+ UNIT_ASSERT_VALUES_EQUAL(ToJson(x2, true), ToJson(x, true));
+ }
+
+ Y_UNIT_TEST(TestVectorOfPairs) {
+ typedef TVector<TPI> TVPI;
+ TVPI v;
+
+ for (int i = 0; i < 3; ++i)
+ v.push_back(TPI(i, i * i));
+
+ const TString etalon = "[[0,0],[1,1],[2,4]]";
+ UNIT_ASSERT_VALUES_EQUAL(etalon, ToJson(v, true));
+
+ TVPI v2(FromJson<TVPI>(ToJson(v)));
+ UNIT_ASSERT_VALUES_EQUAL(ToJson(v2, true), ToJson(v, true));
+ }
+
+ Y_UNIT_TEST(TestSetOfCustom) {
+ typedef TSet<TCustom> TSC;
+ TSC s;
+ s.insert(TCustom(2, 3));
+
+ const TString etalon = "{\"{\\\"a\\\":2,\\\"b\\\":3}\":null}";
+ UNIT_ASSERT_VALUES_EQUAL(etalon, ToJson(s, true));
+
+ TSC s2(FromJson<TSC>(ToJson(s)));
+ UNIT_ASSERT_VALUES_EQUAL(ToJson(s2, true), ToJson(s, true));
+ }
+
+ Y_UNIT_TEST(TestExceptions) {
+ NSc::TValue v = 1;
+ const TString json = v.ToJson();
+ UNIT_ASSERT_EXCEPTION(FromJson<TVI>(json, true), yexception);
+ UNIT_ASSERT_EXCEPTION(FromJson<THI>(json, true), yexception);
+ UNIT_ASSERT_EXCEPTION(FromJson<TMI>(json, true), yexception);
+ UNIT_ASSERT_EXCEPTION(FromJson<THSI>(json, true), yexception);
+ UNIT_ASSERT_EXCEPTION(FromJson<TSI>(json, true), yexception);
+ UNIT_ASSERT_EXCEPTION(FromJson<TPI>(json, true), yexception);
+ }
+};
diff --git a/library/cpp/scheme/tests/ut/scheme_json_ut.cpp b/library/cpp/scheme/tests/ut/scheme_json_ut.cpp
new file mode 100644
index 0000000000..daeb2654f9
--- /dev/null
+++ b/library/cpp/scheme/tests/ut/scheme_json_ut.cpp
@@ -0,0 +1,161 @@
+#include <library/cpp/scheme/scimpl_private.h>
+#include <library/cpp/scheme/ut_utils/scheme_ut_utils.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/null.h>
+#include <util/string/subst.h>
+#include <util/string/util.h>
+
+#include <type_traits>
+#include <library/cpp/string_utils/quote/quote.h>
+
+using namespace std::string_view_literals;
+
+Y_UNIT_TEST_SUITE(TSchemeJsonTest) {
+ Y_UNIT_TEST(TestJson) {
+ const char* json = "[\n"
+ " {\n"
+ " \"url\":\"foo\",\n"
+ " \"title\":\"bar\",\n"
+ " \"passages\":[\"foo\", \"bar\"],\n"
+ " }\n"
+ "]";
+
+ {
+ const NSc::TValue& v = NSc::TValue::FromJson(json);
+ UNIT_ASSERT_VALUES_EQUAL("bar", (TStringBuf)v.TrySelect("0/passages/1"));
+ UNIT_ASSERT(v.PathExists("0/passages/0"));
+ UNIT_ASSERT(v.PathExists("[0]/[passages]/[0]"));
+ UNIT_ASSERT(v.PathExists("[0][passages][0]"));
+ UNIT_ASSERT(v.PathExists(""));
+ UNIT_ASSERT(!v.PathExists("`"));
+ UNIT_ASSERT(v.TrySelect("").Has(0));
+ UNIT_ASSERT(!v.PathExists("1"));
+ UNIT_ASSERT(!v.PathExists("0/passages1"));
+ UNIT_ASSERT(!v.PathExists("0/passages/2"));
+ UNIT_ASSERT(!v.PathExists("0/passages/2"));
+ UNIT_ASSERT_VALUES_EQUAL(0, (double)v.TrySelect("0/passages/2"));
+ UNIT_ASSERT(!v.PathExists("0/passages/2"));
+ }
+ {
+ const NSc::TValue& vv = NSc::TValue::FromJson("[ test ]]");
+ UNIT_ASSERT(vv.IsNull());
+ }
+ {
+ const char* json = "[a,b],[a,b]";
+ const NSc::TValue& v = NSc::TValue::FromJson(json);
+ UNIT_ASSERT(v.IsNull());
+ }
+ {
+ const char* json = "[null,null]";
+ const NSc::TValue& v = NSc::TValue::FromJson(json);
+ UNIT_ASSERT(v.PathExists("1"));
+ UNIT_ASSERT(!v.PathExists("2"));
+ }
+ {
+ const char* json = "{ a : b : c }";
+ NSc::TValue v;
+ UNIT_ASSERT(!NSc::TValue::FromJson(v, json));
+ UNIT_ASSERT(v.IsNull());
+ }
+ {
+ const char* json = "[a:b]";
+ UNIT_ASSERT(NSc::TValue::FromJson(json).IsNull());
+ }
+ {
+ UNIT_ASSERT_VALUES_EQUAL("{\n \"a\" : \"b\",\n \"c\" : \"d\"\n}",
+ NSc::TValue::FromJson("{a:b,c:d}").ToJson(NSc::TValue::JO_PRETTY));
+ }
+ }
+
+ Y_UNIT_TEST(TestSafeJson) {
+ TString ss;
+ ss.reserve(256);
+
+ for (int i = 0; i < 256; ++i) {
+ ss.append((char)i);
+ }
+
+ NSc::TValue v;
+ v[ss] = "xxx";
+ v["xxx"] = ss;
+
+ UNIT_ASSERT_VALUES_EQUAL("{\"xxx\":null}", v.ToJson(NSc::TValue::JO_SKIP_UNSAFE));
+ UNIT_ASSERT_VALUES_EQUAL("{\"xxx\":null}", v.ToJson(NSc::TValue::JO_SAFE));
+
+ UNIT_ASSERT_VALUES_EQUAL("{"
+ "\"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000B\\f\\r"
+ "\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018"
+ "\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F !\\\"#$%&'()*+,-./0123456789"
+ ":;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\u007F"
+ "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93"
+ "\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7"
+ "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB"
+ "\xBC\xBD\xBE\xBF\\xC0\\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE"
+ "\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1"
+ "\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4"
+ "\\xF5\\xF6\\xF7\\xF8\\xF9\\xFA\\xFB\\xFC\\xFD\\xFE\\xFF\":"
+ "\"xxx\","
+ "\"xxx\":"
+ "\"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000B\\f\\r"
+ "\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018"
+ "\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F !\\\"#$%&'()*+,-./0123456789"
+ ":;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\u007F"
+ "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93"
+ "\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7"
+ "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB"
+ "\xBC\xBD\xBE\xBF\\xC0\\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE"
+ "\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1"
+ "\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4"
+ "\\xF5\\xF6\\xF7\\xF8\\xF9\\xFA\\xFB\\xFC\\xFD\\xFE\\xFF\""
+ "}",
+ v.ToJson(NSc::TValue::JO_SORT_KEYS));
+ UNIT_ASSERT(NSc::TValue::Equal(v, NSc::TValue::FromJson(v.ToJson())));
+
+ {
+ NSc::TValue value;
+ TString articleName{"\xC2\xC2\xCF"};
+ value["text"] = articleName;
+ UNIT_ASSERT_VALUES_EQUAL(value.ToJson(), "{\"text\":\"\xC2\xC2\xCF\"}");
+ UNIT_ASSERT_VALUES_EQUAL(value.ToJsonSafe(), "{\"text\":null}");
+ }
+ }
+
+ Y_UNIT_TEST(TestJsonEscape) {
+ NSc::TValue v("\10\7\6\5\4\3\2\1\0"sv);
+ UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), "\"\\b\\u0007\\u0006\\u0005\\u0004\\u0003\\u0002\\u0001\\u0000\"");
+ }
+
+ Y_UNIT_TEST(TestStrictJson) {
+ UNIT_ASSERT_NO_EXCEPTION(NSc::TValue::FromJsonThrow("{a:b}"));
+ UNIT_ASSERT_EXCEPTION(NSc::TValue::FromJsonThrow("{a:b}", NSc::TValue::JO_PARSER_STRICT), yexception);
+ UNIT_ASSERT_NO_EXCEPTION(NSc::TValue::FromJsonThrow("{\"a\":\"b\"}", NSc::TValue::JO_PARSER_STRICT));
+ }
+
+ Y_UNIT_TEST(TestJsonValue) {
+ NSc::TValue a = NSc::NUt::AssertFromJson("{a:[null,-1,2,3.4,str,{b:{c:d}}],e:f}");
+ NSc::TValue b = NSc::TValue::FromJsonValue(a.ToJsonValue());
+ UNIT_ASSERT_JSON_EQ_JSON(a, b);
+ }
+
+ Y_UNIT_TEST(TestJsonEmptyContainers) {
+ {
+ NSc::TValue a = NSc::NUt::AssertFromJson("{a:[]}");
+ NSc::TValue b = NSc::TValue::FromJsonValue(a.ToJsonValue());
+ UNIT_ASSERT_JSON_EQ_JSON(a, b);
+ }
+ {
+ NSc::TValue a = NSc::NUt::AssertFromJson("{a:{}}");
+ NSc::TValue b = NSc::TValue::FromJsonValue(a.ToJsonValue());
+ UNIT_ASSERT_JSON_EQ_JSON(a, b);
+ }
+ }
+
+ Y_UNIT_TEST(TestDuplicateKeys) {
+ const TStringBuf duplicatedKeys = "{\"a\":[{\"b\":1, \"b\":42}]}";
+ UNIT_ASSERT_NO_EXCEPTION(NSc::TValue::FromJsonThrow(duplicatedKeys));
+ UNIT_ASSERT_EXCEPTION(NSc::TValue::FromJsonThrow(duplicatedKeys, NSc::TValue::JO_PARSER_DISALLOW_DUPLICATE_KEYS), yexception);
+ UNIT_ASSERT(NSc::TValue::FromJson(duplicatedKeys).IsDict());
+ UNIT_ASSERT(NSc::TValue::FromJson(duplicatedKeys, NSc::TValue::JO_PARSER_DISALLOW_DUPLICATE_KEYS).IsNull());
+ }
+};
diff --git a/library/cpp/scheme/tests/ut/scheme_merge_ut.cpp b/library/cpp/scheme/tests/ut/scheme_merge_ut.cpp
new file mode 100644
index 0000000000..2a06cf110d
--- /dev/null
+++ b/library/cpp/scheme/tests/ut/scheme_merge_ut.cpp
@@ -0,0 +1,172 @@
+#include <library/cpp/scheme/scimpl_private.h>
+#include <library/cpp/scheme/ut_utils/scheme_ut_utils.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/null.h>
+#include <library/cpp/string_utils/quote/quote.h>
+#include <util/string/subst.h>
+#include <util/string/util.h>
+
+#include <type_traits>
+
+
+Y_UNIT_TEST_SUITE(TSchemeMergeTest) {
+
+ void DoTestReverseMerge(TStringBuf lhs, TStringBuf rhs, TStringBuf res) {
+ NSc::TValue v = NSc::TValue::FromJson(lhs);
+ v.ReverseMerge(NSc::TValue::FromJson(rhs));
+ UNIT_ASSERT(NSc::TValue::Equal(v, NSc::TValue::FromJson(res)));
+ }
+
+ Y_UNIT_TEST(TestReverseMerge) {
+ DoTestReverseMerge("{a:{x:y, b:c}}", "{a:{u:w, b:d}}", "{a:{u:w, x:y, b:c}}");
+ DoTestReverseMerge("null", "{x:y}", "{x:y}");
+ DoTestReverseMerge("null", "[b]", "[b]");
+ DoTestReverseMerge("[a]", "[b]", "[a]");
+ DoTestReverseMerge("{x:null}", "{x:b}", "{x:b}");
+ }
+
+ Y_UNIT_TEST(TestMerge) {
+ TStringBuf data = "{ a : [ { b : 1, d : { e : -1.e5 } }, { f : 0, g : [ h, i ] } ] }";
+ NSc::TValue v = NSc::TValue::FromJson(data);
+ UNIT_ASSERT_VALUES_EQUAL(v.ToJson(true), v.Clone().ToJson(true));
+ UNIT_ASSERT(v.Has("a"));
+ UNIT_ASSERT(v["a"].Has(1));
+ UNIT_ASSERT(v["a"][0].Has("b"));
+ UNIT_ASSERT(v["a"][0].Has("d"));
+ UNIT_ASSERT(1 == v["a"][0]["b"]);
+ UNIT_ASSERT(v["a"][0]["d"].Has("e"));
+ UNIT_ASSERT(-1.e5 == v["a"][0]["d"]["e"]);
+ UNIT_ASSERT(v["a"][1].Has("f"));
+ UNIT_ASSERT(v["a"][1].Has("g"));
+ UNIT_ASSERT(0. == v["a"][1]["f"]);
+ UNIT_ASSERT(v["a"][1]["g"].IsArray());
+ UNIT_ASSERT(v["a"][1]["g"].Has(1));
+ UNIT_ASSERT(TStringBuf("h") == v["a"][1]["g"][0]);
+ UNIT_ASSERT(TStringBuf("i") == v["a"][1]["g"][1]);
+
+ {
+ TStringBuf data = "{ a : [ { d : 42 }, { g : [ 3 ] } ], q : r }";
+
+ NSc::TValue v1 = NSc::TValue::FromJson(data);
+ UNIT_ASSERT_VALUES_EQUAL(v1.ToJson(true), v1.Clone().ToJson(true));
+ UNIT_ASSERT(NSc::TValue::Equal(v1, v1.FromJson(v1.ToJson())));
+
+ NSc::TValue v2;
+ v2.MergeUpdate(v["a"]);
+ UNIT_ASSERT_C(NSc::TValue::Equal(v["a"], v2), Sprintf("\n%s\n!=\n%s\n", v["a"].ToJson().data(), v2.ToJson().data()));
+
+ v.MergeUpdate(v1);
+ UNIT_ASSERT_C(!NSc::TValue::Equal(v["a"], v2), Sprintf("\n%s\n!=\n%s\n", v["a"].ToJson().data(), v2.ToJson().data()));
+ v2.MergeUpdate(v1["a"]);
+ UNIT_ASSERT_C(NSc::TValue::Equal(v["a"], v2), Sprintf("\n%s\n!=\n%s\n", v["a"].ToJson().data(), v2.ToJson().data()));
+ }
+
+ UNIT_ASSERT(v.Has("a"));
+ UNIT_ASSERT(v.Has("q"));
+ UNIT_ASSERT(TStringBuf("r") == v["q"]);
+ UNIT_ASSERT(v["a"].Has(1));
+ UNIT_ASSERT(!v["a"][0].Has("b"));
+ UNIT_ASSERT(v["a"][0].Has("d"));
+ UNIT_ASSERT(!v["a"][0]["d"].IsArray());
+ UNIT_ASSERT(!v["a"][0]["d"].IsDict());
+ UNIT_ASSERT(42 == v["a"][0]["d"]);
+ UNIT_ASSERT(!v["a"][1].Has("f"));
+ UNIT_ASSERT(v["a"][1].Has("g"));
+ UNIT_ASSERT(v["a"][1]["g"].IsArray());
+ UNIT_ASSERT(!v["a"][1]["g"].Has(1));
+ UNIT_ASSERT(3 == v["a"][1]["g"][0]);
+ }
+
+ Y_UNIT_TEST(TestMerge1) {
+ TStringBuf data = "[ { a : { b : d } } ]";
+
+ NSc::TValue wcopy = NSc::TValue::FromJson(data);
+
+ TStringBuf data1 = "[ { a : { b : c } } ]";
+
+ wcopy.MergeUpdateJson(data1);
+
+ {
+ TString json = wcopy.ToJson(true);
+ SubstGlobal(json, "\"", "");
+ UNIT_ASSERT_VALUES_EQUAL(json, "[{a:{b:c}}]");
+ }
+ }
+
+ Y_UNIT_TEST(TestMerge2) {
+ TStringBuf data = "{ a : { b : c }, q : { x : y } }";
+
+ NSc::TValue wcopy = NSc::TValue::FromJson(data);
+
+ TStringBuf data1 = "{ a : { e : f } }";
+
+ wcopy.MergeUpdateJson(data1);
+
+ {
+ TString json = wcopy.ToJson(true);
+ SubstGlobal(json, "\"", "");
+ UNIT_ASSERT_VALUES_EQUAL(json, "{a:{b:c,e:f},q:{x:y}}");
+ }
+ }
+
+ Y_UNIT_TEST(TestMerge3) {
+ TStringBuf data = "{ g : { x : { a : { b : c }, q : { x : y } }, y : fff } }";
+
+ NSc::TValue wcopy = NSc::TValue::FromJson(data);
+
+ TStringBuf data1 = "{ g : { x : { a : { e : f } } } }";
+
+ wcopy.MergeUpdateJson(data1);
+
+ {
+ TString json = wcopy.ToJson(true);
+ SubstGlobal(json, "\"", "");
+ UNIT_ASSERT_VALUES_EQUAL(json, "{g:{x:{a:{b:c,e:f},q:{x:y}},y:fff}}");
+ }
+ }
+
+ Y_UNIT_TEST(TestMerge4) {
+ TStringBuf data = "{ a : 1, b : { c : 2, d : { q : f } } }";
+ NSc::TValue val = NSc::TValue::FromJson(data);
+
+ TStringBuf data1 = "{ a : 2, b : { c : 3, d : { q : e }, g : h } }";
+
+ val.MergeUpdateJson(data1);
+
+ {
+ TString json = val.ToJson(true);
+ SubstGlobal(json, "\"", "");
+
+ UNIT_ASSERT_VALUES_EQUAL(json, "{a:2,b:{c:3,d:{q:e},g:h}}");
+ }
+ }
+
+ Y_UNIT_TEST(TestMerge5) {
+ NSc::TValue v0;
+ v0.GetOrAdd("x").MergeUpdate(NSc::TValue(1));
+ UNIT_ASSERT_VALUES_EQUAL(v0.ToJson(), "{\"x\":1}");
+ }
+
+ Y_UNIT_TEST(TestMerge6) {
+ NSc::TValue va = NSc::TValue::FromJson("{\"x\":\"abc\",\"y\":\"def\"}");
+ NSc::TValue vb = va.Get("y");
+ NSc::TValue diff;
+ diff["y"] = vb;
+ va.MergeUpdate(diff);
+ UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), "{\"x\":\"abc\",\"y\":\"def\"}");
+ UNIT_ASSERT_VALUES_EQUAL(vb.ToJson(), "\"def\"");
+ UNIT_ASSERT_VALUES_EQUAL(diff.ToJson(), "{\"y\":\"def\"}");
+ }
+
+ Y_UNIT_TEST(TestMerge7) {
+ NSc::TValue v;
+ v["a"] = NSc::TValue::FromJson("[0.125,0.12,0.1,0.08,0.06]");
+ UNIT_ASSERT_JSON_EQ_JSON(v, "{a:[0.125,0.12,0.1,0.08,0.06]}");
+
+ NSc::TValue a = v.TrySelectOrAdd("a")->MergeUpdateJson("[1,2,3]");
+
+ UNIT_ASSERT_JSON_EQ_JSON(a, "[1,2,3]");
+ UNIT_ASSERT_JSON_EQ_JSON(v, "{a:[1,2,3]}");
+ }
+};
diff --git a/library/cpp/scheme/tests/ut/scheme_path_ut.cpp b/library/cpp/scheme/tests/ut/scheme_path_ut.cpp
new file mode 100644
index 0000000000..0d4d79d483
--- /dev/null
+++ b/library/cpp/scheme/tests/ut/scheme_path_ut.cpp
@@ -0,0 +1,159 @@
+#include <library/cpp/scheme/scimpl_private.h>
+#include <library/cpp/scheme/ut_utils/scheme_ut_utils.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/null.h>
+#include <util/string/subst.h>
+#include <util/string/util.h>
+
+#include <type_traits>
+#include <library/cpp/string_utils/quote/quote.h>
+
+Y_UNIT_TEST_SUITE(TSchemePathTest) {
+ void DoTestSelect(TStringBuf path, TStringBuf expected, TStringBuf delexpected) {
+ NSc::TValue v;
+ UNIT_ASSERT(!v.PathExists(path));
+ UNIT_ASSERT(NSc::TValue::PathValid(path));
+ UNIT_ASSERT(NSc::TValue::Same(v.TrySelect(path), NSc::Null()));
+ *v.TrySelectOrAdd(path) = 1;
+ NSc::NUt::AssertSchemeJson(expected, v);
+ UNIT_ASSERT(v.PathExists(path));
+ UNIT_ASSERT(1 == v.TrySelectOrAdd(path)->GetNumber());
+ UNIT_ASSERT(1 == v.TrySelect(path).GetNumber());
+ UNIT_ASSERT(1 == v.TrySelectAndDelete(path).GetNumber());
+ UNIT_ASSERT(NSc::TValue::Same(v.TrySelectAndDelete(path), NSc::Null()));
+ NSc::NUt::AssertSchemeJson(delexpected, v);
+ UNIT_ASSERT(!v.PathExists(path));
+ UNIT_ASSERT(NSc::TValue::Same(v.TrySelect(path), NSc::Null()));
+ }
+
+ Y_UNIT_TEST(TestSelect) {
+ NSc::TValue v;
+ UNIT_ASSERT(!v.PathValid(" "));
+ UNIT_ASSERT(v.PathExists(""));
+ UNIT_ASSERT(v.PathExists("//"));
+
+ UNIT_ASSERT(NSc::TValue::Same(v, *v.TrySelectOrAdd("//")));
+ NSc::NUt::AssertSchemeJson("null", v);
+ UNIT_ASSERT(NSc::TValue::Same(v.TrySelectAndDelete("//"), NSc::Null()));
+ NSc::NUt::AssertSchemeJson("null", v);
+
+ v.SetDict();
+ UNIT_ASSERT(NSc::TValue::Same(v, *v.TrySelectOrAdd("//")));
+ NSc::NUt::AssertSchemeJson("{}", v);
+ UNIT_ASSERT(NSc::TValue::Same(v.TrySelectAndDelete("//"), NSc::Null()));
+ NSc::NUt::AssertSchemeJson("{}", v);
+
+ v.SetArray();
+ UNIT_ASSERT(NSc::TValue::Same(v, *v.TrySelectOrAdd("//")));
+ NSc::NUt::AssertSchemeJson("[]", v);
+ UNIT_ASSERT(NSc::TValue::Same(v.TrySelectAndDelete("//"), NSc::Null()));
+ NSc::NUt::AssertSchemeJson("[]", v);
+
+ DoTestSelect("[]", "{'':1}", "{}");
+ DoTestSelect("[ ]", "{' ':1}", "{}");
+ DoTestSelect("[0]", "[1]", "[]");
+ DoTestSelect("[1]", "[null,1]", "[null]");
+ DoTestSelect("foo/[0]/bar", "{foo:[{bar:1}]}", "{foo:[{}]}");
+ DoTestSelect("foo/1/bar", "{foo:[null,{bar:1}]}", "{foo:[null,{}]}");
+ DoTestSelect("foo[-1]bar", "{foo:{'-1':{bar:1}}}", "{foo:{'-1':{}}}");
+ DoTestSelect("'foo'/\"0\"/'bar'", "{foo:{'0':{bar:1}}}", "{foo:{'0':{}}}");
+ DoTestSelect("'\\''", "{'\\'':1}", "{}");
+ }
+
+ Y_UNIT_TEST(TestSelectAndMerge) {
+ NSc::TValue v;
+ v.TrySelectOrAdd("blender/enabled")->MergeUpdateJson("1");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::FromJson("1").ToJson(), "1");
+ UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), "{\"blender\":{\"enabled\":1}}");
+ }
+
+ Y_UNIT_TEST(TestPathEscapes) {
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("a"), "a");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath(""), R"=("")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("[]"), R"=("[]")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("[]ab"), R"=("[]ab")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("a[]b"), R"=("a[]b")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("ab[]"), R"=("ab[]")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("[ab]"), R"=("[ab]")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("[ab"), R"=("[ab")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("a[b"), R"=("a[b")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("ab["), R"=("ab[")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("]ab"), R"=("]ab")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("a]b"), R"=("a]b")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("ab]"), R"=("ab]")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath(R"=(\)="), R"=("\\")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath(R"=(\\)="), R"=("\\\\")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("/"), R"=("/")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("//"), R"=("//")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("///"), R"=("///")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("/ab"), R"=("/ab")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("a/b"), R"=("a/b")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("ab/"), R"=("ab/")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("//ab"), R"=("//ab")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("a//b"), R"=("a//b")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("ab//"), R"=("ab//")=");
+ UNIT_ASSERT_VALUES_EQUAL(NSc::TValue::EscapeForPath("6400"), R"=("6400")=");
+
+ {
+ NSc::TValue val;
+ *val.TrySelectOrAdd("") = 100;
+ const TString res = R"=(100)=";
+ UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res);
+ }
+ {
+ NSc::TValue val;
+ *val.TrySelectOrAdd("a") = 100;
+ const TString res = R"=({"a":100})=";
+ UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res);
+ }
+ {
+ NSc::TValue val;
+ *val.TrySelectOrAdd(R"=(////)=") = 100;
+ const TString res = R"=(100)=";
+ UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res);
+ }
+ {
+ NSc::TValue val;
+ *val.TrySelectOrAdd(R"=()=") = 100;
+ const TString res = R"=(100)=";
+ UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res);
+ }
+ {
+ NSc::TValue val;
+ *val.TrySelectOrAdd(R"=("")=") = 100;
+ const TString res = R"=({"":100})=";
+ UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res);
+ }
+ {
+ NSc::TValue val;
+ *val.TrySelectOrAdd(R"=("[1]")=") = 100;
+ const TString res = R"=({"[1]":100})=";
+ UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res);
+ }
+ {
+ NSc::TValue val;
+ *val.TrySelectOrAdd(R"=("\"\"")=") = 100;
+ const TString res = R"=({"\"\"":100})=";
+ UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res);
+ }
+ {
+ NSc::TValue val;
+ *val.TrySelectOrAdd(R"=("/10/")=") = 100;
+ const TString res = R"=({"/10/":100})=";
+ UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res);
+ }
+ {
+ NSc::TValue val;
+ *val.TrySelectOrAdd(R"=(/"[10]"//""/"\"/10/\""///)=") = 100;
+ const TString res = R"=({"[10]":{"":{"\"/10/\"":100}}})=";
+ UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res);
+ }
+ {
+ NSc::TValue val;
+ *val.TrySelectOrAdd(R"=(/"[10]"//""/"\"/10/\""///)=") = 100;
+ const TString res = R"=({"[10]":{"":{"\"/10/\"":100}}})=";
+ UNIT_ASSERT_VALUES_EQUAL(val.ToJson(), res);
+ }
+ }
+};
diff --git a/library/cpp/scheme/tests/ut/scheme_proto_ut.cpp b/library/cpp/scheme/tests/ut/scheme_proto_ut.cpp
new file mode 100644
index 0000000000..e711a0d092
--- /dev/null
+++ b/library/cpp/scheme/tests/ut/scheme_proto_ut.cpp
@@ -0,0 +1,220 @@
+#include <library/cpp/protobuf/util/is_equal.h>
+#include <library/cpp/scheme/scheme.h>
+#include <library/cpp/scheme/tests/ut/scheme_ut.pb.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TSchemeProtoTest) {
+ void DoTestProtobuf(bool fromProto, bool mapAsDict);
+
+ Y_UNIT_TEST(TestFromProtobuf) {
+ DoTestProtobuf(true, false);
+ }
+
+ Y_UNIT_TEST(TestToProtobuf) {
+ DoTestProtobuf(false, false);
+ }
+
+ Y_UNIT_TEST(TestFromProtobufWithDict) {
+ DoTestProtobuf(true, true);
+ }
+
+ Y_UNIT_TEST(TestToProtobufWithDict) {
+ DoTestProtobuf(false, true);
+ }
+
+ template <class T>
+ void AddMapPair(NSc::TValue& v, TStringBuf key, T value, bool mapAsDict) {
+ if (mapAsDict) {
+ v[key] = value;
+ } else {
+ auto& newElement = v.Push();
+ newElement["key"] = key;
+ newElement["value"] = value;
+ }
+ }
+
+ void DoTestProtobuf(bool fromProto, bool mapAsDict) {
+ NSc::TMessage m;
+ NSc::TValue v;
+ m.SetDouble((double)1 / 3), v["Double"] = (double)1 / 3;
+ m.SetFloat((float)1 / 3), v["Float"] = (float)1 / 3;
+ m.SetInt32(1000000), v["Int32"] = 1000000;
+ m.SetInt64(1000000000000LL), v["Int64"] = 1000000000000LL;
+ m.SetUInt32(555555), v["UInt32"] = 555555;
+ m.SetUInt64(555555555555LL), v["UInt64"] = 555555555555LL;
+ m.SetSInt32(-555555), v["SInt32"] = -555555;
+ m.SetSInt64(-555555555555LL), v["SInt64"] = -555555555555LL;
+ m.SetFixed32(123456), v["Fixed32"] = 123456;
+ m.SetFixed64(123456123456LL), v["Fixed64"] = 123456123456LL;
+ m.SetSFixed32(-123456), v["SFixed32"] = -123456;
+ m.SetSFixed64(-123456123456LL), v["SFixed64"] = -123456123456LL;
+ m.SetBool(true), v["Bool"] = true;
+ m.SetString("String"), v["String"] = "String";
+ m.SetBytes("Bytes"), v["Bytes"] = "Bytes";
+ m.SetEnum(NSc::VALUE1), v["Enum"] = "VALUE1";
+
+ auto& mapDoublesP = *m.mutable_mapdoubles();
+ auto& mapDoublesV = v["MapDoubles"];
+ mapDoublesP["pi"] = 3.14;
+ AddMapPair(mapDoublesV, "pi", 3.14, mapAsDict);
+ if (fromProto && mapAsDict) {
+ // can not add two entries in dict, as it represent over array with unstable order
+ mapDoublesP["back_e"] = 1 / 2.7;
+ AddMapPair(mapDoublesV, "back_e", 1 / 2.7, mapAsDict);
+ }
+
+ auto& mapInt32sP = *m.mutable_mapint32s();
+ auto& mapInt32sV = v["MapInt32s"];
+ mapInt32sP["pi"] = -7;
+ AddMapPair(mapInt32sV, "pi", -7, mapAsDict);
+ if (fromProto && mapAsDict) {
+ // can not add two entries in dict, as it represent over array with unstable order
+ mapInt32sP["back_e"] = 42;
+ AddMapPair(mapInt32sV, "back_e", 42, mapAsDict);
+ }
+
+ auto& mapStringP = *m.mutable_mapstring();
+ auto& mapStringV = v["MapString"];
+ mapStringP["intro"] = "body";
+ AddMapPair(mapStringV, "intro", "body", mapAsDict);
+ if (fromProto && mapAsDict) {
+ // can not add two entries in dict, as it represent over array with unstable order
+ mapStringP["deep"] = "blue";
+ AddMapPair(mapStringV, "deep", "blue", mapAsDict);
+ }
+
+ m.AddDoubles((double)1 / 3), v["Doubles"][0] = (double)1 / 3;
+ m.AddDoubles((double)1 / 4), v["Doubles"][1] = (double)1 / 4;
+
+ m.AddFloats((float)1 / 3), v["Floats"][0] = (float)1 / 3;
+ m.AddFloats((float)1 / 4), v["Floats"][1] = (float)1 / 4;
+
+ m.AddInt32s(1000000), v["Int32s"][0] = 1000000;
+ m.AddInt32s(2000000), v["Int32s"][1] = 2000000;
+
+ m.AddInt64s(1000000000000LL), v["Int64s"][0] = 1000000000000LL;
+ m.AddInt64s(2000000000000LL), v["Int64s"][1] = 2000000000000LL;
+
+ m.AddUInt32s(555555), v["UInt32s"][0] = 555555;
+ m.AddUInt32s(655555), v["UInt32s"][1] = 655555;
+
+ m.AddUInt64s(555555555555LL);
+ v["UInt64s"][0] = 555555555555LL;
+ m.AddUInt64s(655555555555LL);
+ v["UInt64s"][1] = 655555555555LL;
+
+ m.AddSInt32s(-555555), v["SInt32s"][0] = -555555;
+ m.AddSInt32s(-655555), v["SInt32s"][1] = -655555;
+
+ m.AddSInt64s(-555555555555LL), v["SInt64s"][0] = -555555555555LL;
+ m.AddSInt64s(-655555555555LL), v["SInt64s"][1] = -655555555555LL;
+
+ m.AddFixed32s(123456), v["Fixed32s"][0] = 123456;
+ m.AddFixed32s(223456), v["Fixed32s"][1] = 223456;
+
+ m.AddFixed64s(123456123456LL), v["Fixed64s"][0] = 123456123456LL;
+ m.AddFixed64s(223456123456LL), v["Fixed64s"][1] = 223456123456LL;
+
+ m.AddSFixed32s(-123456), v["SFixed32s"][0] = -123456;
+ m.AddSFixed32s(-223456), v["SFixed32s"][1] = -223456;
+
+ m.AddSFixed64s(-123456123456LL), v["SFixed64s"][0] = -123456123456LL;
+ m.AddSFixed64s(-223456123456LL), v["SFixed64s"][1] = -223456123456LL;
+
+ m.AddBools(false), v["Bools"][0] = false;
+ m.AddBools(true), v["Bools"][1] = true;
+
+ m.AddStrings("String1"), v["Strings"][0] = "String1";
+ m.AddStrings("String2"), v["Strings"][1] = "String2";
+
+ m.AddBytess("Bytes1"), v["Bytess"][0] = "Bytes1";
+ m.AddBytess("Bytes2"), v["Bytess"][1] = "Bytes2";
+
+ m.AddEnums(NSc::VALUE1), v["Enums"][0] = "VALUE1";
+ m.AddEnums(NSc::VALUE2), v["Enums"][1] = "VALUE2";
+
+ NSc::TMessage2 m2;
+ NSc::TValue v2;
+ m2.SetDouble((double)1 / 3), v2["Double"] = (double)1 / 3;
+ m2.SetFloat((float)1 / 3), v2["Float"] = (float)1 / 3;
+ m2.SetInt32(1000000), v2["Int32"] = 1000000;
+ m2.SetInt64(1000000000000LL), v2["Int64"] = 1000000000000LL;
+ m2.SetUInt32(555555), v2["UInt32"] = 555555;
+ m2.SetUInt64(555555555555LL), v2["UInt64"] = 555555555555LL;
+ m2.SetSInt32(-555555), v2["SInt32"] = -555555;
+ m2.SetSInt64(-555555555555LL), v2["SInt64"] = -555555555555LL;
+ m2.SetFixed32(123456), v2["Fixed32"] = 123456;
+ m2.SetFixed64(123456123456LL), v2["Fixed64"] = 123456123456LL;
+ m2.SetSFixed32(-123456), v2["SFixed32"] = -123456;
+ m2.SetSFixed64(-123456123456LL), v2["SFixed64"] = -123456123456LL;
+ m2.SetBool(true), v2["Bool"] = true;
+ m2.SetString("String"), v2["String"] = "String";
+ m2.SetBytes("Bytes"), v2["Bytes"] = "Bytes";
+ m2.SetEnum(NSc::VALUE1), v2["Enum"] = "VALUE1";
+
+ m2.AddDoubles((double)1 / 3), v2["Doubles"][0] = (double)1 / 3;
+ m2.AddDoubles((double)1 / 4), v2["Doubles"][1] = (double)1 / 4;
+
+ m2.AddFloats((float)1 / 3), v2["Floats"][0] = (float)1 / 3;
+ m2.AddFloats((float)1 / 4), v2["Floats"][1] = (float)1 / 4;
+
+ m2.AddInt32s(1000000), v2["Int32s"][0] = 1000000;
+ m2.AddInt32s(2000000), v2["Int32s"][1] = 2000000;
+
+ m2.AddInt64s(1000000000000LL), v2["Int64s"][0] = 1000000000000LL;
+ m2.AddInt64s(2000000000000LL), v2["Int64s"][1] = 2000000000000LL;
+
+ m2.AddUInt32s(555555), v2["UInt32s"][0] = 555555;
+ m2.AddUInt32s(655555), v2["UInt32s"][1] = 655555;
+
+ m2.AddUInt64s(555555555555LL);
+ v2["UInt64s"][0] = 555555555555LL;
+ m2.AddUInt64s(655555555555LL);
+ v2["UInt64s"][1] = 655555555555LL;
+
+ m2.AddSInt32s(-555555), v2["SInt32s"][0] = -555555;
+ m2.AddSInt32s(-655555), v2["SInt32s"][1] = -655555;
+
+ m2.AddSInt64s(-555555555555LL), v2["SInt64s"][0] = -555555555555LL;
+ m2.AddSInt64s(-655555555555LL), v2["SInt64s"][1] = -655555555555LL;
+
+ m2.AddFixed32s(123456), v2["Fixed32s"][0] = 123456;
+ m2.AddFixed32s(223456), v2["Fixed32s"][1] = 223456;
+
+ m2.AddFixed64s(123456123456LL), v2["Fixed64s"][0] = 123456123456LL;
+ m2.AddFixed64s(223456123456LL), v2["Fixed64s"][1] = 223456123456LL;
+
+ m2.AddSFixed32s(-123456), v2["SFixed32s"][0] = -123456;
+ m2.AddSFixed32s(-223456), v2["SFixed32s"][1] = -223456;
+
+ m2.AddSFixed64s(-123456123456LL), v2["SFixed64s"][0] = -123456123456LL;
+ m2.AddSFixed64s(-223456123456LL), v2["SFixed64s"][1] = -223456123456LL;
+
+ m2.AddBools(false), v2["Bools"][0] = false;
+ m2.AddBools(true), v2["Bools"][1] = true;
+
+ m2.AddStrings("String1"), v2["Strings"][0] = "String1";
+ m2.AddStrings("String2"), v2["Strings"][1] = "String2";
+
+ m2.AddBytess("Bytes1"), v2["Bytess"][0] = "Bytes1";
+ m2.AddBytess("Bytes2"), v2["Bytess"][1] = "Bytes2";
+
+ m2.AddEnums(NSc::VALUE1), v2["Enums"][0] = "VALUE1";
+ m2.AddEnums(NSc::VALUE2), v2["Enums"][1] = "VALUE2";
+
+ *(m.MutableMessage()) = m2, v["Message"] = v2;
+
+ *(m.AddMessages()) = m2, v["Messages"][0] = v2;
+ *(m.AddMessages()) = m2, v["Messages"][1] = v2;
+
+ if (fromProto) {
+ UNIT_ASSERT(NSc::TValue::Equal(v, NSc::TValue::From(m, mapAsDict)));
+ } else {
+ NSc::TMessage proto;
+ v.To(proto);
+
+ TString differentPath;
+ UNIT_ASSERT_C(NProtoBuf::IsEqual(m, proto, &differentPath), differentPath);
+ }
+ }
+};
diff --git a/library/cpp/scheme/tests/ut/scheme_ut.cpp b/library/cpp/scheme/tests/ut/scheme_ut.cpp
new file mode 100644
index 0000000000..1a5d07c31b
--- /dev/null
+++ b/library/cpp/scheme/tests/ut/scheme_ut.cpp
@@ -0,0 +1,879 @@
+#include <library/cpp/scheme/scimpl_private.h>
+#include <library/cpp/scheme/ut_utils/scheme_ut_utils.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/null.h>
+#include <library/cpp/string_utils/quote/quote.h>
+#include <util/string/subst.h>
+#include <util/string/util.h>
+
+#include <type_traits>
+
+Y_UNIT_TEST_SUITE(TSchemeTest) {
+
+ Y_UNIT_TEST(TestNaN) {
+ UNIT_ASSERT_VALUES_EQUAL("null", NSc::TValue(std::numeric_limits<double>::quiet_NaN()).ToJson());
+ UNIT_ASSERT_VALUES_EQUAL("null", NSc::TValue(-std::numeric_limits<double>::infinity()).ToJson());
+ UNIT_ASSERT_VALUES_EQUAL("null", NSc::TValue(std::numeric_limits<double>::infinity()).ToJson());
+ UNIT_ASSERT_VALUES_EQUAL("1", NSc::TValue(1.0).ToJson());
+ }
+
+ Y_UNIT_TEST(TestNumbers) {
+ {
+ NSc::TValue vd;
+ UNIT_ASSERT_VALUES_EQUAL(2.5, vd.GetNumberMutable(2.5));
+ UNIT_ASSERT_VALUES_EQUAL(2, vd.GetIntNumberMutable(-1));
+ }
+ {
+ NSc::TValue vi;
+ UNIT_ASSERT_VALUES_EQUAL(2, vi.GetIntNumberMutable(2));
+ UNIT_ASSERT_VALUES_EQUAL(2., vi.GetNumberMutable(-1));
+ }
+ {
+ NSc::TValue vb = NSc::TValue::FromJson("true");
+
+ UNIT_ASSERT_VALUES_EQUAL("true", vb.ToJson());
+
+ UNIT_ASSERT(vb.IsBool());
+ UNIT_ASSERT(vb.IsIntNumber());
+ UNIT_ASSERT(vb.IsNumber());
+ UNIT_ASSERT_VALUES_EQUAL(true, vb.GetBool());
+ UNIT_ASSERT_VALUES_EQUAL(1, vb.GetIntNumber());
+ UNIT_ASSERT_VALUES_EQUAL(1.0, vb.GetNumber());
+
+ NSc::TValue vb1 = vb.Clone();
+
+ UNIT_ASSERT(NSc::TValue::Equal(vb, vb1));
+
+ UNIT_ASSERT_VALUES_EQUAL(true, vb.GetBool());
+ UNIT_ASSERT_VALUES_EQUAL(1, vb.GetIntNumber());
+ UNIT_ASSERT_VALUES_EQUAL(1.0, vb.GetNumber());
+ UNIT_ASSERT(vb.IsBool());
+ UNIT_ASSERT_VALUES_EQUAL(1, vb.GetIntNumberMutable());
+ UNIT_ASSERT(!vb.IsBool());
+
+ UNIT_ASSERT(NSc::TValue::Equal(vb, vb1));
+
+ UNIT_ASSERT(vb1.IsBool());
+ UNIT_ASSERT_VALUES_EQUAL(1.0, vb1.GetNumberMutable());
+ UNIT_ASSERT(!vb1.IsBool());
+
+ vb.SetBool(true);
+
+ UNIT_ASSERT(vb.IsBool());
+ UNIT_ASSERT(NSc::TValue::Equal(vb, vb1));
+
+ vb = NSc::TValue::FromJson("false");
+
+ UNIT_ASSERT_VALUES_EQUAL("false", vb.ToJson());
+ UNIT_ASSERT(!NSc::TValue::Equal(vb, vb1));
+
+ UNIT_ASSERT(vb.IsBool());
+ UNIT_ASSERT(vb.IsIntNumber());
+ UNIT_ASSERT(vb.IsNumber());
+ UNIT_ASSERT_VALUES_EQUAL(false, vb.GetBool());
+ UNIT_ASSERT_VALUES_EQUAL(0.0, vb.GetNumber());
+ UNIT_ASSERT_VALUES_EQUAL(0, vb.GetIntNumber());
+
+ NSc::TValue vd = NSc::TValue::FromJson("1.0");
+
+ UNIT_ASSERT(vd.IsNumber());
+ UNIT_ASSERT(!vd.IsIntNumber());
+ UNIT_ASSERT_VALUES_EQUAL(1.0, vd.GetNumber());
+ UNIT_ASSERT_VALUES_EQUAL(1, vd.GetIntNumber());
+ UNIT_ASSERT_VALUES_EQUAL(1.0, vd.GetNumberMutable());
+
+ NSc::TValue vi = NSc::TValue::FromJson("1");
+
+ UNIT_ASSERT(vi.IsNumber());
+ UNIT_ASSERT(vi.IsIntNumber());
+ UNIT_ASSERT_VALUES_EQUAL(1.0, vi.GetNumber());
+ UNIT_ASSERT_VALUES_EQUAL(1, vi.GetIntNumber());
+ UNIT_ASSERT_VALUES_EQUAL(1, vi.GetIntNumberMutable());
+
+ UNIT_ASSERT(NSc::TValue::Equal(vd, vi));
+
+ vd.SetNumber(1.5);
+ UNIT_ASSERT(vd.IsNumber());
+ UNIT_ASSERT(!vd.IsIntNumber());
+ UNIT_ASSERT_VALUES_EQUAL(1.5, vd.GetNumber());
+ UNIT_ASSERT_VALUES_EQUAL(1, vd.GetIntNumber());
+ UNIT_ASSERT_VALUES_EQUAL(1.5, vd.GetNumberMutable());
+
+ UNIT_ASSERT(!NSc::TValue::Equal(vd, vi));
+
+ UNIT_ASSERT_VALUES_EQUAL("1", vi.ToJson());
+ UNIT_ASSERT_VALUES_EQUAL("1.5", vd.ToJson());
+
+ UNIT_ASSERT_VALUES_EQUAL(1, vd.GetIntNumberMutable());
+ UNIT_ASSERT(NSc::TValue::Equal(vd, vi));
+ vd.SetIntNumber(2);
+ UNIT_ASSERT(!NSc::TValue::Equal(vd, vi));
+ vi.SetNumber(2.);
+ UNIT_ASSERT(NSc::TValue::Equal(vd, vi));
+ vd.SetNumber(2.);
+ UNIT_ASSERT(NSc::TValue::Equal(vd, vi));
+ vi.SetIntNumber(5);
+ vd.MergeUpdate(vi);
+ UNIT_ASSERT(vd.IsNumber());
+ UNIT_ASSERT(vd.IsIntNumber());
+ UNIT_ASSERT_VALUES_EQUAL(5, vd.GetIntNumber());
+ vd.SetNumber(3.3);
+ vi.MergeUpdate(vd);
+ UNIT_ASSERT(vi.IsNumber());
+ UNIT_ASSERT(!vi.IsIntNumber());
+ UNIT_ASSERT_VALUES_EQUAL(3.3, vi.GetNumber());
+
+ vi.SetIntNumber(Max<i64>());
+ UNIT_ASSERT_VALUES_EQUAL("9223372036854775807", vi.ToJson());
+ }
+ }
+
+ template <typename T>
+ void DoTestForce(T t) {
+ UNIT_ASSERT_VALUES_EQUAL_C(i64(t), NSc::TValue(i64(t)).ForceIntNumber(), ToString(t));
+ UNIT_ASSERT_VALUES_EQUAL_C(double(t), NSc::TValue(double(t)).ForceNumber(), ToString(t));
+
+ UNIT_ASSERT_VALUES_EQUAL_C(i64(t), NSc::TValue(TStringBuf(ToString(i64(t)))).ForceIntNumber(), ToString(t));
+ UNIT_ASSERT_VALUES_EQUAL_C(ToString(double(t)), ToString(NSc::TValue(TStringBuf(ToString(double(t)))).ForceNumber()), ToString(t));
+
+ UNIT_ASSERT_VALUES_EQUAL_C(ToString(i64(t)), NSc::TValue(TStringBuf(ToString(i64(t)))).ForceString(), ToString(t));
+ UNIT_ASSERT_VALUES_EQUAL_C(ToString(double(t)), NSc::TValue(TStringBuf(ToString(double(t)))).ForceString(), ToString(t));
+ }
+
+ Y_UNIT_TEST(TestForce) {
+ DoTestForce(Max<i64>());
+ DoTestForce(Min<i64>());
+ DoTestForce(1.5);
+ DoTestForce(-1.5);
+
+ UNIT_ASSERT_VALUES_EQUAL(1, NSc::TValue("32a").ForceIntNumber(1));
+ UNIT_ASSERT_VALUES_EQUAL(1.5, NSc::TValue("32a").ForceNumber(1.5));
+ }
+
+ template <typename T>
+ void DoCheckRelations(T t, T tless, T tmore, const NSc::TValue& v, TStringBuf ss) {
+ UNIT_ASSERT_C((t == v), ss);
+ UNIT_ASSERT_C(!(t != v), ss);
+ UNIT_ASSERT_C((t <= v), ss);
+ UNIT_ASSERT_C((t >= v), ss);
+ UNIT_ASSERT_C(!(t < v), ss);
+ UNIT_ASSERT_C(!(t > v), ss);
+
+ UNIT_ASSERT_C(!(tless == v), ss);
+ UNIT_ASSERT_C((tless != v), ss);
+ UNIT_ASSERT_C((tless <= v), ss);
+ UNIT_ASSERT_C(!(tless >= v), ss);
+ UNIT_ASSERT_C((tless < v), ss);
+ UNIT_ASSERT_C(!(tless > v), ss);
+ UNIT_ASSERT_C(!(tmore == v), ss);
+ UNIT_ASSERT_C((tmore != v), ss);
+ UNIT_ASSERT_C(!(tmore <= v), ss);
+ UNIT_ASSERT_C((tmore >= v), ss);
+ UNIT_ASSERT_C(!(tmore < v), ss);
+ UNIT_ASSERT_C((tmore > v), ss);
+ }
+
+ void DoCheckRelations(const NSc::TValue& t, const NSc::TValue&, const NSc::TValue&, const NSc::TValue& v, TStringBuf ss) {
+ UNIT_ASSERT_C((t == v), ss);
+ UNIT_ASSERT_C(!(t != v), ss);
+ }
+
+ // void DoCheckRelations(bool t, bool, bool, const NSc::TValue& v, TStringBuf ss) {
+ // UNIT_ASSERT_C((t == v), ss);
+ // UNIT_ASSERT_C(!(t != v), ss);
+ // }
+
+ template <typename T>
+ void DoCheckAssignment(T t, T tless, T tmore, TStringBuf s, TStringBuf ss) {
+ bool expectint = std::is_integral<T>::value;
+ bool expectnum = std::is_arithmetic<T>::value;
+ bool expectbool = std::is_same<bool, T>::value;
+
+ {
+ NSc::TValue v(t);
+ UNIT_ASSERT_VALUES_EQUAL_C(expectnum, v.IsNumber(), ss);
+ UNIT_ASSERT_VALUES_EQUAL_C(expectint, v.IsIntNumber(), ss);
+ UNIT_ASSERT_VALUES_EQUAL_C(expectbool, v.IsBool(), ss);
+ UNIT_ASSERT_VALUES_EQUAL_C(s, v.ToJson(), ss);
+ DoCheckRelations(t, tless, tmore, v, ss);
+ }
+ {
+ NSc::TValue v;
+ UNIT_ASSERT(v.IsNull());
+ v = t;
+ UNIT_ASSERT(!v.IsNull());
+ UNIT_ASSERT_VALUES_EQUAL_C(expectnum, v.IsNumber(), ss);
+ UNIT_ASSERT_VALUES_EQUAL_C(expectint, v.IsIntNumber(), ss);
+ UNIT_ASSERT_VALUES_EQUAL_C(expectbool, v.IsBool(), ss);
+ UNIT_ASSERT_VALUES_EQUAL_C(s, v.ToJson(), ss);
+ DoCheckRelations(t, tless, tmore, v, ss);
+ }
+ }
+
+ template <size_t N>
+ void DoCheckAssignmentArr(const char (&t)[N], const char (&tless)[N], const char (&tmore)[N], TStringBuf s, TStringBuf ss) {
+ {
+ NSc::TValue v(t);
+
+ UNIT_ASSERT_C(v.IsString(), ss);
+ UNIT_ASSERT_VALUES_EQUAL_C(s, v.ToJson(), ss);
+ DoCheckRelations(t, tless, tmore, v, ss);
+ }
+ {
+ NSc::TValue v;
+ v = t;
+ UNIT_ASSERT_C(v.IsString(), ss);
+ UNIT_ASSERT_VALUES_EQUAL_C(s, v.ToJson(), ss);
+ DoCheckRelations(t, tless, tmore, v, ss);
+ }
+ }
+
+ template <typename T>
+ void DoCheckAssignmentNum(T t, T tless, T tmore, TStringBuf s, TStringBuf ss) {
+ DoCheckAssignment(t, tless, tmore, s, ss);
+ {
+ NSc::TValue v;
+ T tt = (v = t);
+ UNIT_ASSERT_VALUES_EQUAL_C(t, tt, ss);
+ }
+ }
+
+ Y_UNIT_TEST(TestAssignments) {
+ for (int i = -2; i < 3; ++i) {
+ TString ii = ToString(i);
+ int iless = i - 1;
+ int imore = i + 1;
+ DoCheckAssignmentNum<signed char>(i, iless, imore, ii, "schar");
+ DoCheckAssignmentNum<short>(i, iless, imore, ii, "short");
+ DoCheckAssignmentNum<int>(i, iless, imore, ii, "int");
+ DoCheckAssignmentNum<long>(i, iless, imore, ii, "long");
+ DoCheckAssignmentNum<long long>(i, iless, imore, ii, "longlong");
+ DoCheckAssignmentNum<i8>(i, iless, imore, ii, "i8");
+ DoCheckAssignmentNum<i16>(i, iless, imore, ii, "i16");
+ DoCheckAssignmentNum<i32>(i, iless, imore, ii, "i32");
+ DoCheckAssignmentNum<i64>(i, iless, imore, ii, "i64");
+
+ DoCheckAssignmentNum<float>(i, iless, imore, ii, "float");
+ DoCheckAssignmentNum<double>(i, iless, imore, ii, "double");
+ }
+
+ // DoCheckAssignment<bool>(true, true, true, "true", "bool");
+ // DoCheckAssignment<bool>(false, false, false, "false", "bool");
+
+ for (int i = 1; i < 3; ++i) {
+ TString ii = ToString(i);
+ int iless = i - 1;
+ int imore = i + 1;
+
+ DoCheckAssignmentNum<char>(i, iless, imore, ii, "char");
+
+ DoCheckAssignmentNum<signed char>(i, iless, imore, ii, "schar");
+ DoCheckAssignmentNum<short>(i, iless, imore, ii, "short");
+ DoCheckAssignmentNum<int>(i, iless, imore, ii, "int");
+ DoCheckAssignmentNum<long>(i, iless, imore, ii, "long");
+ DoCheckAssignmentNum<long long>(i, iless, imore, ii, "longlong");
+ DoCheckAssignmentNum<i8>(i, iless, imore, ii, "i8");
+ DoCheckAssignmentNum<i16>(i, iless, imore, ii, "i16");
+ DoCheckAssignmentNum<i32>(i, iless, imore, ii, "i32");
+ DoCheckAssignmentNum<i64>(i, iless, imore, ii, "i64");
+
+ DoCheckAssignmentNum<unsigned char>(i, iless, imore, ii, "uchar");
+ DoCheckAssignmentNum<unsigned short>(i, iless, imore, ii, "ushort");
+ DoCheckAssignmentNum<unsigned int>(i, iless, imore, ii, "uint");
+ DoCheckAssignmentNum<unsigned long>(i, iless, imore, ii, "ulong");
+ DoCheckAssignmentNum<unsigned long long>(i, iless, imore, ii, "ulonglong");
+ DoCheckAssignmentNum<ui8>(i, iless, imore, ii, "ui8");
+ DoCheckAssignmentNum<ui16>(i, iless, imore, ii, "ui16");
+ DoCheckAssignmentNum<ui32>(i, iless, imore, ii, "ui32");
+ DoCheckAssignmentNum<ui64>(i, iless, imore, ii, "ui64");
+
+ DoCheckAssignmentNum<float>(i, iless, imore, ii, "float");
+ DoCheckAssignmentNum<double>(i, iless, imore, ii, "double");
+ }
+
+ TString uuu = "uuu";
+ TString uua = "uua";
+ TString uuz = "uuz";
+ DoCheckAssignment<char*>(uuu.begin(), uua.begin(), uuz.begin(), "\"uuu\"", "char*");
+ DoCheckAssignment<const char*>("www", "wwa", "wwz", "\"www\"", "const char*");
+ DoCheckAssignmentArr("xxx", "xxa", "xxz", "\"xxx\"", "const char[]");
+ DoCheckAssignment<TStringBuf>("yyy", "yya", "yyz", "\"yyy\"", "TStringBuf");
+
+#if defined(_MSC_VER)
+ //TODO
+#else
+ DoCheckAssignment<TString>("ttt", "tta", "ttz", "\"ttt\"", "TString");
+#endif
+
+ NSc::TValue v;
+ v.SetDict();
+ DoCheckAssignment<NSc::TValue>(v, v, v, "{}", "TValue");
+ DoCheckAssignment<NSc::TValue&>(v, v, v, "{}", "TValue&");
+ DoCheckAssignment<const NSc::TValue&>(v, v, v, "{}", "const TValue&");
+
+ NSc::TValue v1{1};
+ UNIT_ASSERT_VALUES_EQUAL(v1.ToJson(), "1");
+ }
+
+ Y_UNIT_TEST(TestAssignmentDictChild) {
+ {
+ NSc::TValue v;
+ {
+ NSc::TValue b;
+ v["a"] = b;
+ }
+ v = v["a"];
+ }
+ {
+ NSc::TValue v;
+ {
+ NSc::TValue b;
+ v["a"] = b;
+ }
+ v = v.Get("a");
+ }
+ {
+ NSc::TValue v;
+ {
+ NSc::TValue b;
+ v["a"] = b;
+ }
+ v = std::move(v["a"]);
+ }
+ }
+
+ Y_UNIT_TEST(TestInsert) {
+ NSc::TValue v;
+ v.Insert(0, "b");
+ v.Insert(0, "a");
+ v.Insert(2, "d");
+ v.Insert(2, "c");
+ UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), R"(["a","b","c","d"])");
+
+ v.AppendAll({1, 2, 3});
+ UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), R"(["a","b","c","d",1,2,3])");
+
+ TVector<int> d{4, 5, 6};
+ v.AppendAll(d);
+ UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), R"(["a","b","c","d",1,2,3,4,5,6])");
+ UNIT_ASSERT_VALUES_EQUAL(d.size(), 3u);
+ TVector<TStringBuf> s{"x", "y", "z"};
+ v.AppendAll(s.begin(), s.end());
+ UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), R"(["a","b","c","d",1,2,3,4,5,6,"x","y","z"])");
+
+ UNIT_ASSERT_VALUES_EQUAL(v.Clone().Clear().AppendAll(s).ToJson(), R"(["x","y","z"])");
+ UNIT_ASSERT_VALUES_EQUAL(v.Clone().Clear().AppendAll(TVector<TStringBuf>()).ToJson(), R"([])");
+
+ v.AddAll({{"a", "b"}, {"c", "d"}});
+ UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), R"({"a":"b","c":"d"})");
+ }
+
+ Y_UNIT_TEST(TestFrontBack) {
+ NSc::TValue v;
+ const NSc::TValue& vv = v;
+ UNIT_ASSERT(NSc::TValue::Same(vv.Front(), NSc::Null()));
+ UNIT_ASSERT(NSc::TValue::Same(vv.Back(), NSc::Null()));
+ UNIT_ASSERT(!vv.IsArray());
+ v.Back() = "a";
+ UNIT_ASSERT_VALUES_EQUAL("a", vv.Front().GetString());
+ UNIT_ASSERT_VALUES_EQUAL("a", vv.Back().GetString());
+ UNIT_ASSERT(vv.IsArray());
+ v.Push("b");
+ UNIT_ASSERT_VALUES_EQUAL("a", vv.Front().GetString());
+ UNIT_ASSERT_VALUES_EQUAL("b", vv.Back().GetString());
+
+ UNIT_ASSERT_VALUES_EQUAL("b", v.Pop().GetString());
+
+ UNIT_ASSERT_VALUES_EQUAL("a", vv.Front().GetString());
+ UNIT_ASSERT_VALUES_EQUAL("a", vv.Back().GetString());
+
+ UNIT_ASSERT_VALUES_EQUAL("a", v.Pop().GetString());
+
+ UNIT_ASSERT(NSc::TValue::Same(vv.Front(), NSc::Null()));
+ UNIT_ASSERT(NSc::TValue::Same(vv.Back(), NSc::Null()));
+
+ v.Front() = "a";
+ UNIT_ASSERT_VALUES_EQUAL("a", vv.Front().GetString());
+ UNIT_ASSERT_VALUES_EQUAL("a", vv.Back().GetString());
+ }
+
+ Y_UNIT_TEST(TestAssign) {
+ NSc::TValue v;
+ v.SetArray();
+ v.Push() = "test";
+ UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), "[\"test\"]");
+ UNIT_ASSERT(NSc::TValue::SamePool(v[0], v));
+ }
+
+ NSc::TValue MutableRef(const NSc::TValue& v) {
+ return v;
+ }
+
+ NSc::TValue Clone(const NSc::TValue& v) {
+ NSc::TValue v1 = v.Clone();
+ UNIT_ASSERT_VALUES_EQUAL(v1.ToJson(true), v.ToJson(true));
+ return v1;
+ }
+
+ Y_UNIT_TEST(TestCOW) {
+ NSc::TValue vd = NSc::TValue::FromJson("{ a : 1, b : c}");
+ NSc::TValue va = NSc::TValue::FromJson("[ x, y]");
+ NSc::TValue vs = NSc::TValue::FromJson("foo");
+ NSc::TValue vn = NSc::TValue::FromJson("1");
+ TString sd = "{\"a\":1,\"b\":\"c\"}";
+ TString sa = "[\"x\",\"y\"]";
+ TString ss = "\"foo\"";
+ TString sn = "1";
+ UNIT_ASSERT_VALUES_EQUAL(sd, vd.ToJson(true));
+ UNIT_ASSERT_VALUES_EQUAL(sa, va.ToJson(true));
+ UNIT_ASSERT_VALUES_EQUAL(ss, vs.ToJson(true));
+ UNIT_ASSERT_VALUES_EQUAL(sn, vn.ToJson(true));
+
+ {
+ NSc::TValue v2 = MutableRef(vn);
+ v2 = -1;
+
+ UNIT_ASSERT_VALUES_EQUAL(sn, vn.ToJson(true));
+
+ NSc::TValue v3 = Clone(vn);
+ v3 = -1;
+
+ UNIT_ASSERT_VALUES_EQUAL(v3.ToJson(true), v2.ToJson(true));
+ }
+
+ {
+ NSc::TValue v2 = MutableRef(vs);
+ v2 = "xxx";
+
+ UNIT_ASSERT_VALUES_EQUAL(ss, vs.ToJson(true));
+
+ NSc::TValue v3 = Clone(vs);
+ v3 = "xxx";
+
+ UNIT_ASSERT_VALUES_EQUAL(v3.ToJson(true), v2.ToJson(true));
+ }
+
+ {
+ NSc::TValue v2 = MutableRef(vd);
+ v2["a"] = "zzz";
+
+ UNIT_ASSERT_VALUES_EQUAL(sd, vd.ToJson(true));
+
+ NSc::TValue v3 = Clone(vd);
+ v3["a"] = "zzz";
+
+ UNIT_ASSERT_VALUES_EQUAL(v3.ToJson(true), v2.ToJson(true));
+ }
+
+ {
+ NSc::TValue v2 = MutableRef(va);
+ v2[0] = "zzz";
+
+ UNIT_ASSERT_VALUES_EQUAL(sa, va.ToJson(true));
+
+ NSc::TValue v3 = Clone(va);
+ v3[0] = "zzz";
+
+ UNIT_ASSERT_VALUES_EQUAL(v3.ToJson(true), v2.ToJson(true));
+ }
+
+ {
+ NSc::TValue v2 = MutableRef(va);
+
+ UNIT_ASSERT_VALUES_EQUAL(sa, va.ToJson(true));
+
+ NSc::TValue v3 = Clone(va);
+
+ UNIT_ASSERT_VALUES_EQUAL(v3.ToJson(true), v2.ToJson(true));
+ }
+
+ {
+ NSc::TValue v2 = MutableRef(va);
+ v2.ClearArray();
+
+ UNIT_ASSERT_VALUES_EQUAL(sa, va.ToJson(true));
+
+ NSc::TValue v3 = Clone(va);
+ v3.ClearArray();
+
+ UNIT_ASSERT_VALUES_EQUAL(v3.ToJson(true), v2.ToJson(true));
+ }
+ }
+
+ Y_UNIT_TEST(TestOperators) {
+ UNIT_ASSERT("test" == NSc::TValue("test"));
+ UNIT_ASSERT(NSc::TValue("test") == "test");
+
+ UNIT_ASSERT("test1" != NSc::TValue("test"));
+ UNIT_ASSERT(NSc::TValue("test") != "test1");
+
+ UNIT_ASSERT("test1" > NSc::TValue("test"));
+ UNIT_ASSERT(NSc::TValue("test") < "test1");
+
+ UNIT_ASSERT("test" < NSc::TValue("test1"));
+ UNIT_ASSERT(NSc::TValue("test1") > "test");
+
+ UNIT_ASSERT(1 == NSc::TValue(1));
+ UNIT_ASSERT(NSc::TValue(1) == 1);
+
+ UNIT_ASSERT(2 != NSc::TValue(1));
+ UNIT_ASSERT(NSc::TValue(1) != 2);
+
+ UNIT_ASSERT(1 < NSc::TValue(2));
+ UNIT_ASSERT(NSc::TValue(2) > 1);
+
+ UNIT_ASSERT(2 > NSc::TValue(1));
+ UNIT_ASSERT(NSc::TValue(1) < 2);
+
+ UNIT_ASSERT(TString("test") == NSc::TValue("test"));
+ }
+
+ Y_UNIT_TEST(TestDestructor) {
+ NSc::TValue v;
+ const NSc::TValue& v1 = v;
+ v1.GetString();
+ v1.GetArray();
+ v1.GetNumber();
+ v1.GetDict();
+ v.GetString();
+ v.GetArray();
+ v.GetNumber();
+ v.GetDict();
+ }
+
+ void DoTestSamePool(TStringBuf json, TStringBuf jpath) {
+ NSc::TValue v = NSc::TValue::FromJson(json);
+ UNIT_ASSERT_C(NSc::TValue::SamePool(v, v.TrySelect(jpath)), json);
+ }
+
+ Y_UNIT_TEST(TestSamePool) {
+ DoTestSamePool("", "");
+ DoTestSamePool("a", "");
+ DoTestSamePool("[a]", "0");
+ DoTestSamePool("{a:b}", "a");
+ DoTestSamePool("{a:{b:c}}", "a/b");
+ DoTestSamePool("{a:{b:[c, {}]}}", "a/b/1");
+ DoTestSamePool("{a:{b:[c, {d:{e:[]}}]}}", "a/b/1/d/e");
+ UNIT_ASSERT(!NSc::TValue::SamePool(NSc::TValue(), NSc::TValue()));
+ UNIT_ASSERT(!NSc::TValue::SamePool(NSc::Null().Clone(), NSc::Null()));
+ UNIT_ASSERT(!NSc::TValue::SamePool(NSc::TValue() = 0, NSc::TValue()));
+ UNIT_ASSERT(!NSc::TValue::SamePool(NSc::TValue::FromJson("a"), NSc::TValue::FromJson("a")));
+ NSc::TValue v, vv;
+ v["x"] = vv;
+ UNIT_ASSERT(!NSc::TValue::SamePool(v, vv));
+ UNIT_ASSERT(!NSc::TValue::SamePool(v, v["x"]));
+ v = vv;
+ UNIT_ASSERT(NSc::TValue::SamePool(v, vv));
+ }
+
+ Y_UNIT_TEST(TestLoopDetection) {
+ NSc::NImpl::GetTlsInstance<NSc::NImpl::TSelfLoopContext>().ReportingMode
+ = NSc::NImpl::TSelfLoopContext::EMode::Stderr;
+
+ NSc::TValue x;
+
+ x["a"]["x"] = x;
+ x["b"][0] = x;
+
+ UNIT_ASSERT(x.IsSameOrAncestorOf(x));
+ UNIT_ASSERT(x.IsSameOrAncestorOf(x.Get("a")));
+ UNIT_ASSERT(x.Get("a").IsSameOrAncestorOf(x));
+
+ UNIT_ASSERT_VALUES_EQUAL(x.ToJson(), "{\"a\":{\"x\":null},\"b\":[null]}");
+
+ NSc::TValue y = x.Clone();
+
+ UNIT_ASSERT(y.Has("a"));
+ UNIT_ASSERT(y.Get("a").Has("x"));
+ UNIT_ASSERT(y.Get("a").Get("x").IsNull());
+ UNIT_ASSERT(y.Get("a").Get("x").IsNull());
+
+ UNIT_ASSERT(y.Has("b"));
+ UNIT_ASSERT(y.Get("b").Has(0));
+ UNIT_ASSERT(y.Get("b").Get(0).IsNull());
+
+ UNIT_ASSERT_VALUES_EQUAL(y.ToJson(), "{\"a\":{\"x\":null},\"b\":[null]}");
+
+ NSc::TValue z;
+ z.MergeUpdate(x);
+
+ UNIT_ASSERT(z.Has("a"));
+ UNIT_ASSERT(z.Get("a").Has("x"));
+ UNIT_ASSERT(z.Get("a").Get("x").IsNull());
+
+ UNIT_ASSERT(z.Has("b"));
+ UNIT_ASSERT(z.Get("b").Has(0));
+ UNIT_ASSERT(z.Get("b").Get(0).IsNull());
+
+ UNIT_ASSERT_VALUES_EQUAL(z.ToJson(), "{\"a\":{\"x\":null},\"b\":[null]}");
+
+ x["a"].Delete("x");
+ x["b"].Delete(0);
+
+ UNIT_ASSERT(x.IsSameOrAncestorOf(x));
+ UNIT_ASSERT(x.IsSameOrAncestorOf(x.Get("a")));
+ UNIT_ASSERT(!x.Get("a").IsSameOrAncestorOf(x));
+ }
+
+ Y_UNIT_TEST(TestLoopDetectionThrow) {
+ NSc::NImpl::GetTlsInstance<NSc::NImpl::TSelfLoopContext>().ReportingMode
+ = NSc::NImpl::TSelfLoopContext::EMode::Throw;
+
+ {
+ NSc::TValue x;
+ x["a"]["x"] = x;
+
+ UNIT_ASSERT(x.IsSameOrAncestorOf(x));
+ UNIT_ASSERT(x.IsSameOrAncestorOf(x.Get("a")));
+ UNIT_ASSERT(x.Get("a").IsSameOrAncestorOf(x));
+
+ UNIT_ASSERT_EXCEPTION(x.ToJson(), NSc::TSchemeException);
+ UNIT_ASSERT_EXCEPTION(x.Clone(), NSc::TSchemeException);
+
+ NSc::TValue z;
+ UNIT_ASSERT_EXCEPTION(z.MergeUpdate(x), NSc::TSchemeException);
+
+ UNIT_ASSERT_VALUES_EQUAL(z.ToJson(), "{\"a\":{\"x\":null}}");
+
+ x["a"].Delete("x");
+
+ UNIT_ASSERT(x.IsSameOrAncestorOf(x));
+ UNIT_ASSERT(x.IsSameOrAncestorOf(x.Get("a")));
+ UNIT_ASSERT(!x.Get("a").IsSameOrAncestorOf(x));
+
+ UNIT_ASSERT_VALUES_EQUAL(x.ToJson(), "{\"a\":{}}");
+ }
+
+ {
+ NSc::TValue x;
+ x["a"][0] = x;
+
+ UNIT_ASSERT(x.IsSameOrAncestorOf(x));
+ UNIT_ASSERT(x.IsSameOrAncestorOf(x.Get("a")));
+ UNIT_ASSERT(x.Get("a").IsSameOrAncestorOf(x));
+
+ UNIT_ASSERT_EXCEPTION(x.ToJson(), NSc::TSchemeException);
+ UNIT_ASSERT_EXCEPTION(x.Clone(), NSc::TSchemeException);
+
+ NSc::TValue z;
+ UNIT_ASSERT_EXCEPTION(z.MergeUpdate(x), NSc::TSchemeException);
+
+ UNIT_ASSERT_VALUES_EQUAL(z.ToJson(), "{\"a\":[null]}");
+
+ x["a"].Delete(0);
+
+ UNIT_ASSERT(x.IsSameOrAncestorOf(x));
+ UNIT_ASSERT(x.IsSameOrAncestorOf(x.Get("a")));
+ UNIT_ASSERT(!x.Get("a").IsSameOrAncestorOf(x));
+
+ UNIT_ASSERT_VALUES_EQUAL(x.ToJson(), "{\"a\":[]}");
+ }
+ }
+
+ Y_UNIT_TEST(TestIsSameOrAncestorOf) {
+ NSc::TValue x;
+ UNIT_ASSERT(x.IsSameOrAncestorOf(x));
+
+ x["a"] = NSc::Null();
+ UNIT_ASSERT(x.IsSameOrAncestorOf(x.Get("a")));
+
+ NSc::TValue a = 1;
+ NSc::TValue b = 2;
+ NSc::TValue c = 3;
+ NSc::TValue d = 4;
+
+ x["a"] = a;
+ x["b"] = b;
+ x["c"] = a;
+ UNIT_ASSERT(x.IsSameOrAncestorOf(a));
+ UNIT_ASSERT(x.IsSameOrAncestorOf(b));
+ UNIT_ASSERT(x.Get("a").IsSameOrAncestorOf(a));
+ UNIT_ASSERT(x.Get("b").IsSameOrAncestorOf(b));
+ UNIT_ASSERT(x.Get("c").IsSameOrAncestorOf(a));
+
+ UNIT_ASSERT(!x.Get("a").IsSameOrAncestorOf(b));
+ UNIT_ASSERT(!x.Get("b").IsSameOrAncestorOf(a));
+
+ UNIT_ASSERT(!x.Get("a").Get(0).IsSameOrAncestorOf(a));
+
+ b.Push() = c;
+ b.Push() = d;
+ b.Push() = c;
+
+ UNIT_ASSERT(x.Get("b").IsSameOrAncestorOf(b));
+ UNIT_ASSERT(x.IsSameOrAncestorOf(c));
+ UNIT_ASSERT(x.IsSameOrAncestorOf(d));
+ UNIT_ASSERT(x.Get("b").Get(0).IsSameOrAncestorOf(c));
+ UNIT_ASSERT(x.Get("b").Get(1).IsSameOrAncestorOf(d));
+ UNIT_ASSERT(x.Get("b").Get(2).IsSameOrAncestorOf(c));
+
+ UNIT_ASSERT(b.Get(0).IsSameOrAncestorOf(b.Get(2)));
+ UNIT_ASSERT(b.Get(2).IsSameOrAncestorOf(b.Get(0)));
+ UNIT_ASSERT(b.Get(0).IsSameOrAncestorOf(c));
+ UNIT_ASSERT(b.Get(1).IsSameOrAncestorOf(d));
+
+ UNIT_ASSERT(!b.Get(0).IsSameOrAncestorOf(d));
+ UNIT_ASSERT(!b.Get(1).IsSameOrAncestorOf(c));
+ }
+
+ static void ByVal(NSc::TValue v) {
+ v["VAL"] = 1;
+ }
+
+ static void ByRef(NSc::TValue& v) {
+ ByVal(v);
+ }
+
+ static void ByRefAndModify(NSc::TValue& v) {
+ v["REF"] = 1;
+ ByVal(v);
+ }
+
+ Y_UNIT_TEST(TestMove) {
+ using namespace NSc;
+ {
+ TValue v = TValue::FromJson("{}");
+ ByRef(v);
+ UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), "{\"VAL\":1}");
+ }
+ {
+ TValue v = TValue::FromJson("{}");
+ ByVal(v);
+ UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), "{\"VAL\":1}");
+ }
+ {
+ TValue v;
+ ByVal(v);
+ UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), "{\"VAL\":1}");
+ }
+ {
+ TValue v = TValue::FromJson("{}");
+ ByRefAndModify(v);
+ UNIT_ASSERT_VALUES_EQUAL(v.ToJson(), "{\"REF\":1,\"VAL\":1}");
+ }
+ {
+ TValue v = TValue::FromJson("{foo:bar}");
+ TValue w(std::move(v));
+ UNIT_ASSERT(v.IsNull());
+ v = static_cast<TValue&>(v);
+ UNIT_ASSERT(v.IsNull());
+ UNIT_ASSERT_VALUES_EQUAL(w.Get("foo").GetString(), "bar");
+ v = std::move(w);
+ UNIT_ASSERT_VALUES_EQUAL(v.Get("foo").GetString(), "bar");
+ UNIT_ASSERT(w.IsNull());
+ UNIT_ASSERT(w.Get("foo").IsNull()); // no crash here
+ w["foo"] = "baz"; // no crash here
+ UNIT_ASSERT(w.IsDict());
+ UNIT_ASSERT_VALUES_EQUAL(w.Get("foo").GetString(), "baz");
+ }
+ UNIT_ASSERT(NSc::TValue::DefaultValue().IsNull());
+ }
+
+ //SPI-25156
+ Y_UNIT_TEST(TestMoveNotCorruptingDefault) {
+ using namespace NSc;
+ TValue w = TValue::FromJson("{foo:bar}");
+ TValue v = std::move(w);
+ w["foo"] = "baz"; // no crash here
+ UNIT_ASSERT(NSc::TValue::DefaultValue().IsNull());
+ }
+
+ Y_UNIT_TEST(TestCopyFrom) {
+ {
+ TString sa = "[1,2]";
+ const NSc::TValue& va = NSc::TValue::FromJson(sa);
+ NSc::TValue vb = va;
+ vb.CopyFrom(va);
+ UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), sa);
+ UNIT_ASSERT_VALUES_EQUAL(vb.ToJson(), sa);
+ }
+ {
+ TString sa = "[1,2]";
+ NSc::TValue va = NSc::TValue::FromJson(sa);
+ NSc::TValue vb = va;
+ vb.CopyFrom(va);
+ UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), sa);
+ UNIT_ASSERT_VALUES_EQUAL(vb.ToJson(), sa);
+ }
+ {
+ TString sa = "[1,2]";
+ NSc::TValue va = NSc::TValue::FromJson(sa);
+ const NSc::TValue& vb = va;
+ va.CopyFrom(vb);
+ UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), sa);
+ UNIT_ASSERT_VALUES_EQUAL(vb.ToJson(), sa);
+ }
+ {
+ TString sa = "[1,2]";
+ NSc::TValue va = NSc::TValue::FromJson(sa);
+ NSc::TValue vb = va;
+ va.CopyFrom(vb);
+ UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), sa);
+ UNIT_ASSERT_VALUES_EQUAL(vb.ToJson(), sa);
+ }
+ {
+ NSc::TValue va = NSc::TValue::FromJson("{\"x\":\"ab\",\"y\":{\"p\":\"cd\",\"q\":\"ef\"}}");
+ NSc::TValue vb = va.Get("y");
+ va.CopyFrom(vb);
+ TString sa = "{\"p\":\"cd\",\"q\":\"ef\"}";
+ UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), sa);
+ UNIT_ASSERT_VALUES_EQUAL(vb.ToJson(), sa);
+ }
+ {
+ NSc::TValue va = NSc::TValue::FromJson("{\"x\":\"ab\",\"y\":{\"p\":\"cd\",\"q\":\"ef\"}}");
+ const NSc::TValue& vb = va.Get("y");
+ va.CopyFrom(vb);
+ TString sa = "{\"p\":\"cd\",\"q\":\"ef\"}";
+ UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), sa);
+ }
+ {
+ NSc::TValue va = NSc::TValue::FromJson("{\"x\":\"ab\",\"y\":{\"p\":\"cd\",\"q\":\"ef\"}}");
+ NSc::TValue vb = va.Get("y");
+ va = vb;
+ TString sa = "{\"p\":\"cd\",\"q\":\"ef\"}";
+ UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), sa);
+ UNIT_ASSERT_VALUES_EQUAL(vb.ToJson(), sa);
+ }
+ {
+ NSc::TValue va = NSc::TValue::FromJson("{\"x\":\"ab\",\"y\":{\"p\":\"cd\",\"q\":\"ef\"}}");
+ const NSc::TValue& vb = va.Get("y");
+ va = vb;
+ TString sa = "{\"p\":\"cd\",\"q\":\"ef\"}";
+ UNIT_ASSERT_VALUES_EQUAL(va.ToJson(), sa);
+ UNIT_ASSERT_VALUES_EQUAL(vb.ToJson(), sa);
+ }
+ }
+
+ Y_UNIT_TEST(TestCopyingDictIntoSelf) { //Found by fuzzing
+ NSc::TValue a;
+ NSc::TValue b = a.GetOrAdd("aa");
+ b.CopyFrom(a);
+ NSc::TValue target = NSc::TValue::FromJsonThrow("{\"aa\":null}");
+ UNIT_ASSERT_VALUES_EQUAL(b, target);
+ UNIT_ASSERT_VALUES_EQUAL(a, target);
+ }
+
+ Y_UNIT_TEST(TestCopyingDictIntoSelfByRef) { //Found by fuzzing
+ NSc::TValue a;
+ NSc::TValue& b = a.GetOrAdd("aa");
+ b.CopyFrom(a);
+ UNIT_ASSERT_VALUES_EQUAL(b, NSc::TValue::FromJsonThrow("{\"aa\":null}"));
+ UNIT_ASSERT_VALUES_EQUAL(a, NSc::TValue::FromJsonThrow("{\"aa\": {\"aa\": null}}"));
+ }
+
+ Y_UNIT_TEST(TestGetNoAdd) {
+ NSc::TValue v = NSc::NUt::AssertFromJson("{a:[null,-1,2,3.4],b:3,c:{d:5}}");
+ UNIT_ASSERT(v.GetNoAdd("a") != nullptr);
+ UNIT_ASSERT(v.GetNoAdd("b") != nullptr);
+ UNIT_ASSERT(v.GetNoAdd("c") != nullptr);
+ UNIT_ASSERT(v.GetNoAdd("d") == nullptr);
+ UNIT_ASSERT(v.GetNoAdd("value") == nullptr);
+
+ NSc::TValue* child = v.GetNoAdd("c");
+ UNIT_ASSERT(child != nullptr);
+ (*child)["e"]["f"] = 42;
+ const NSc::TValue expectedResult = NSc::NUt::AssertFromJson("{a:[null,-1,2,3.4],b:3,c:{d:5,e:{f:42}}}");
+ UNIT_ASSERT_VALUES_EQUAL(v, expectedResult);
+ }
+};
diff --git a/library/cpp/scheme/tests/ut/scheme_ut.proto b/library/cpp/scheme/tests/ut/scheme_ut.proto
new file mode 100644
index 0000000000..7981af7eae
--- /dev/null
+++ b/library/cpp/scheme/tests/ut/scheme_ut.proto
@@ -0,0 +1,84 @@
+package NSc;
+
+message TMessage {
+ optional double Double = 1;
+ optional float Float = 2;
+ optional int32 Int32 = 3;
+ optional int64 Int64 = 4;
+ optional uint32 UInt32 = 5;
+ optional uint64 UInt64 = 6;
+ optional sint32 SInt32 = 7;
+ optional sint64 SInt64 = 8;
+ optional fixed32 Fixed32 = 9;
+ optional fixed64 Fixed64 = 10;
+ optional sfixed32 SFixed32 = 11;
+ optional sfixed64 SFixed64 = 12;
+ optional bool Bool = 13;
+ optional string String = 14;
+ optional bytes Bytes = 15;
+ optional EEnum Enum = 16;
+ optional TMessage2 Message = 17;
+
+ repeated double Doubles = 18;
+ repeated float Floats = 19;
+ repeated int32 Int32s = 20;
+ repeated int64 Int64s = 21;
+ repeated uint32 UInt32s = 22;
+ repeated uint64 UInt64s = 23;
+ repeated sint32 SInt32s = 24;
+ repeated sint64 SInt64s = 25;
+ repeated fixed32 Fixed32s = 26;
+ repeated fixed64 Fixed64s = 27;
+ repeated sfixed32 SFixed32s = 28;
+ repeated sfixed64 SFixed64s = 29;
+ repeated bool Bools = 30;
+ repeated string Strings = 31;
+ repeated bytes Bytess = 32;
+ repeated EEnum Enums = 33;
+ repeated TMessage2 Messages = 34;
+
+ map<string, double> MapDoubles = 35;
+ map<string, int32> MapInt32s = 36;
+ map<string, string> MapString = 37;
+}
+
+enum EEnum {
+ VALUE1 = 0;
+ VALUE2 = 1;
+}
+
+message TMessage2 {
+ optional double Double = 1;
+ optional float Float = 2;
+ optional int32 Int32 = 3;
+ optional int64 Int64 = 4;
+ optional uint32 UInt32 = 5;
+ optional uint64 UInt64 = 6;
+ optional sint32 SInt32 = 7;
+ optional sint64 SInt64 = 8;
+ optional fixed32 Fixed32 = 9;
+ optional fixed64 Fixed64 = 10;
+ optional sfixed32 SFixed32 = 11;
+ optional sfixed64 SFixed64 = 12;
+ optional bool Bool = 13;
+ optional string String = 14;
+ optional bytes Bytes = 15;
+ optional EEnum Enum = 16;
+
+ repeated double Doubles = 18;
+ repeated float Floats = 19;
+ repeated int32 Int32s = 20;
+ repeated int64 Int64s = 21;
+ repeated uint32 UInt32s = 22;
+ repeated uint64 UInt64s = 23;
+ repeated sint32 SInt32s = 24;
+ repeated sint64 SInt64s = 25;
+ repeated fixed32 Fixed32s = 26;
+ repeated fixed64 Fixed64s = 27;
+ repeated sfixed32 SFixed32s = 28;
+ repeated sfixed64 SFixed64s = 29;
+ repeated bool Bools = 30;
+ repeated string Strings = 31;
+ repeated bytes Bytess = 32;
+ repeated EEnum Enums = 33;
+}
diff --git a/library/cpp/scheme/tests/ut/ya.make b/library/cpp/scheme/tests/ut/ya.make
new file mode 100644
index 0000000000..9f54791414
--- /dev/null
+++ b/library/cpp/scheme/tests/ut/ya.make
@@ -0,0 +1,24 @@
+UNITTEST()
+
+OWNER(velavokr)
+
+PEERDIR(
+ library/cpp/protobuf/util
+ library/cpp/scheme/tests/fuzz_ops/lib
+ library/cpp/scheme/ut_utils
+ library/cpp/string_utils/quote
+ library/cpp/testing/unittest
+)
+
+SRCS(
+ fuzz_ops_found_bugs_ut.cpp
+ scheme_cast_ut.cpp
+ scheme_json_ut.cpp
+ scheme_merge_ut.cpp
+ scheme_path_ut.cpp
+ scheme_proto_ut.cpp
+ scheme_ut.cpp
+ scheme_ut.proto
+)
+
+END()
diff --git a/library/cpp/scheme/tests/ya.make b/library/cpp/scheme/tests/ya.make
new file mode 100644
index 0000000000..741cc9a2da
--- /dev/null
+++ b/library/cpp/scheme/tests/ya.make
@@ -0,0 +1,13 @@
+OWNER(
+ g:blender
+ g:middle
+ g:upper
+ velavokr
+)
+
+RECURSE(
+ fuzz_json
+ fuzz_ops
+ fuzz_ops/ut
+ ut
+)
diff --git a/library/cpp/scheme/ut_utils/scheme_ut_utils.cpp b/library/cpp/scheme/ut_utils/scheme_ut_utils.cpp
new file mode 100644
index 0000000000..0bbdab10e8
--- /dev/null
+++ b/library/cpp/scheme/ut_utils/scheme_ut_utils.cpp
@@ -0,0 +1,44 @@
+#include "scheme_ut_utils.h"
+
+#include <library/cpp/colorizer/colors.h>
+
+#include <util/stream/str.h>
+
+namespace NSc {
+ namespace NUt {
+ NSc::TValue AssertFromJson(TStringBuf val) {
+ try {
+ return TValue::FromJsonThrow(val);
+ } catch (const TSchemeParseException& e) {
+ TStringStream s;
+ NColorizer::TColors colors;
+ s << "\n"
+ << colors.YellowColor() << "Reason:" << colors.OldColor() << "\n"
+ << e.Reason;
+ s << "\n"
+ << colors.YellowColor() << "Where:" << colors.OldColor() << "\n"
+ << val.SubStr(0, e.Offset) << colors.RedColor() << val.SubStr(e.Offset) << colors.OldColor() << "\n";
+ UNIT_FAIL_IMPL("could not parse json", s.Str());
+ return NSc::Null();
+ } catch (const yexception& e) {
+ TStringStream s;
+ s << '\n'
+ << val;
+ UNIT_FAIL_IMPL("could not parse json", s.Str());
+ return NSc::Null();
+ }
+ }
+
+ void AssertScheme(const TValue& expected, const TValue& actual) {
+ UNIT_ASSERT_JSON_EQ_JSON(actual, expected);
+ }
+
+ void AssertSchemeJson(TStringBuf expected, const NSc::TValue& actual) {
+ UNIT_ASSERT_JSON_EQ_JSON(actual, expected);
+ }
+
+ void AssertJsonJson(TStringBuf expected, TStringBuf actual) {
+ UNIT_ASSERT_JSON_EQ_JSON(actual, expected);
+ }
+ }
+}
diff --git a/library/cpp/scheme/ut_utils/scheme_ut_utils.h b/library/cpp/scheme/ut_utils/scheme_ut_utils.h
new file mode 100644
index 0000000000..eb3ea15b2a
--- /dev/null
+++ b/library/cpp/scheme/ut_utils/scheme_ut_utils.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include <library/cpp/json/json_prettifier.h>
+#include <library/cpp/scheme/scheme.h>
+#include <library/cpp/json/json_value.h>
+#include <library/cpp/json/json_writer.h>
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/string/cast.h>
+
+namespace NSc {
+ namespace NUt {
+ TValue AssertFromJson(TStringBuf json);
+
+ inline TString NormalizeJson(const NSc::TValue& sc) {
+ return sc.ToJson(true);
+ }
+
+ inline TString NormalizeJson(const NJson::TJsonValue& sc) {
+ return NJson::WriteJson(sc, false, true, false);
+ }
+
+ template <class TStr>
+ inline TString NormalizeJson(const TStr& val) {
+ return AssertFromJson(val).ToJson(true);
+ }
+
+#define UNIT_ASSERT_JSON_EQ_JSON_C(A, B, c) \
+ do { \
+ const TString _a = NSc::NUt::NormalizeJson(A); \
+ const TString _b = NSc::NUt::NormalizeJson(B); \
+ if (_a != _b) { \
+ UNIT_FAIL_IMPL( \
+ "json values are different (" #A " != " #B ")", \
+ Sprintf("%s\n!=\n%s\n%s\n%s", _a.data(), _b.data(), \
+ ::NUnitTest::ColoredDiff(NJson::PrettifyJson(_a), NJson::PrettifyJson(_b), " \t\n,:\"{}[]").data(), ToString(c).data())); \
+ } \
+ } while (false)
+
+#define UNIT_ASSERT_JSON_EQ_JSON(A, B) UNIT_ASSERT_JSON_EQ_JSON_C(A, B, "")
+
+ inline TString DumpJson(const TValue& json) {
+ return NJson::CompactifyJson(json.ToJson(true), true, true);
+ }
+
+ // deprecated
+ inline TString DumpJsonVS(const TValue& expected, const TValue& fact) {
+ return DumpJson(expected) + "(expected) != (fact)" + DumpJson(fact);
+ }
+
+ void AssertScheme(const TValue& expected, const TValue& real);
+ void AssertSchemeJson(TStringBuf expected, const TValue& real);
+ void AssertJsonJson(TStringBuf expected, TStringBuf real);
+
+ }
+}
diff --git a/library/cpp/scheme/ut_utils/ya.make b/library/cpp/scheme/ut_utils/ya.make
new file mode 100644
index 0000000000..7661262e1b
--- /dev/null
+++ b/library/cpp/scheme/ut_utils/ya.make
@@ -0,0 +1,16 @@
+LIBRARY()
+
+OWNER(velavokr)
+
+SRCS(
+ scheme_ut_utils.cpp
+)
+
+PEERDIR(
+ library/cpp/colorizer
+ library/cpp/json
+ library/cpp/scheme
+ library/cpp/testing/unittest
+)
+
+END()
diff --git a/library/cpp/scheme/util/scheme_holder.cpp b/library/cpp/scheme/util/scheme_holder.cpp
new file mode 100644
index 0000000000..33232acc50
--- /dev/null
+++ b/library/cpp/scheme/util/scheme_holder.cpp
@@ -0,0 +1 @@
+#include "scheme_holder.h"
diff --git a/library/cpp/scheme/util/scheme_holder.h b/library/cpp/scheme/util/scheme_holder.h
new file mode 100644
index 0000000000..f2fa16d1cd
--- /dev/null
+++ b/library/cpp/scheme/util/scheme_holder.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#include <library/cpp/scheme/scheme.h>
+
+
+// Scheme adapter that holds referenced value
+template <typename TScheme>
+class TSchemeHolder {
+public:
+ TSchemeHolder()
+ : Value_(NSc::Null())
+ , Scheme_(&Value_)
+ {
+ }
+
+ explicit TSchemeHolder(NSc::TValue&& value)
+ : Value_(std::move(value))
+ , Scheme_(&Value_)
+ {
+ }
+
+ explicit TSchemeHolder(const NSc::TValue& value)
+ : Value_(value)
+ , Scheme_(&Value_)
+ {
+ }
+
+ TSchemeHolder(TSchemeHolder<TScheme>&& rhs)
+ : Value_(std::move(rhs.Value_))
+ , Scheme_(&Value_)
+ {
+ }
+
+ TSchemeHolder(const TSchemeHolder<TScheme>& rhs)
+ : Value_(rhs.Value_)
+ , Scheme_(&Value_)
+ {
+ }
+
+ TSchemeHolder<TScheme>& operator=(TSchemeHolder<TScheme>&& rhs) {
+ Value_ = std::move(rhs.Value_);
+ return *this;
+ }
+ TSchemeHolder<TScheme>& operator=(const TSchemeHolder<TScheme>& rhs) {
+ Value_ = rhs.Value_;
+ return *this;
+ }
+
+ TScheme& Scheme() {
+ return Scheme_;
+ }
+ const TScheme& Scheme() const {
+ return Scheme_;
+ }
+ TScheme& operator->() {
+ return Scheme_;
+ }
+ const TScheme& operator->() const {
+ return Scheme_;
+ }
+
+ NSc::TValue& Value() {
+ return Value_;
+ }
+ const NSc::TValue& Value() const {
+ return Value_;
+ }
+
+ bool IsNull() const {
+ return Value_.IsNull();
+ }
+
+private:
+ NSc::TValue Value_;
+ TScheme Scheme_;
+};
diff --git a/library/cpp/scheme/util/utils.cpp b/library/cpp/scheme/util/utils.cpp
new file mode 100644
index 0000000000..40cceceacd
--- /dev/null
+++ b/library/cpp/scheme/util/utils.cpp
@@ -0,0 +1,23 @@
+#include "utils.h"
+
+#include <library/cpp/string_utils/base64/base64.h>
+
+namespace NScUtils {
+
+void CopyField(const NSc::TValue& from, NSc::TValue& to) {
+ to = from;
+}
+
+} // namespace NScUtils
+
+void TSerializer<NSc::TValue>::Save(IOutputStream* out, const NSc::TValue& v) {
+ TString json = Base64Encode(v.ToJson());
+ ::Save(out, json);
+}
+
+void TSerializer<NSc::TValue>::Load(IInputStream* in, NSc::TValue& v) {
+ TString json;
+ ::Load(in, json);
+ json = Base64Decode(json);
+ v = NSc::TValue::FromJsonThrow(json);
+}
diff --git a/library/cpp/scheme/util/utils.h b/library/cpp/scheme/util/utils.h
new file mode 100644
index 0000000000..f7d666f67a
--- /dev/null
+++ b/library/cpp/scheme/util/utils.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <library/cpp/scheme/scheme.h>
+
+#include <util/generic/strbuf.h>
+#include <util/ysaveload.h>
+
+namespace NScUtils {
+
+void CopyField(const NSc::TValue& from, NSc::TValue& to);
+
+template <typename... Args>
+void CopyField(const NSc::TValue& from, NSc::TValue& to, TStringBuf path, Args... args) {
+ CopyField(from[path], to[path], args...);
+}
+
+} // namespace NScUtils
+
+template<>
+struct TSerializer<NSc::TValue> {
+ static void Save(IOutputStream* out, const NSc::TValue& v);
+ static void Load(IInputStream* in, NSc::TValue& v);
+};
diff --git a/library/cpp/scheme/util/ya.make b/library/cpp/scheme/util/ya.make
new file mode 100644
index 0000000000..dffd1c8070
--- /dev/null
+++ b/library/cpp/scheme/util/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+OWNER(g:cards_serivce)
+
+SRCS(
+ scheme_holder.cpp
+ utils.cpp
+)
+
+PEERDIR(
+ library/cpp/string_utils/base64
+)
+
+END()
diff --git a/library/cpp/scheme/ya.make b/library/cpp/scheme/ya.make
new file mode 100644
index 0000000000..bac08ba5a4
--- /dev/null
+++ b/library/cpp/scheme/ya.make
@@ -0,0 +1,25 @@
+LIBRARY()
+
+OWNER(velavokr)
+
+SRCS(
+ scheme.cpp
+ scheme_cast.h
+ scimpl.h
+ scimpl_defs.h
+ scimpl_private.cpp
+ scimpl_protobuf.cpp
+ scimpl_select.rl6
+ scimpl_json_read.cpp
+ scimpl_json_write.cpp
+)
+
+PEERDIR(
+ contrib/libs/protobuf
+ library/cpp/json
+ library/cpp/string_utils/relaxed_escaper
+)
+
+GENERATE_ENUM_SERIALIZATION(scheme.h)
+
+END()
diff --git a/library/cpp/sighandler/async_signals_handler.cpp b/library/cpp/sighandler/async_signals_handler.cpp
new file mode 100644
index 0000000000..00ce1c18fb
--- /dev/null
+++ b/library/cpp/sighandler/async_signals_handler.cpp
@@ -0,0 +1,245 @@
+#include "async_signals_handler.h"
+
+#include <util/system/platform.h>
+
+#if !defined(_win_)
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+
+#include <unistd.h>
+
+#if defined(_linux_)
+#include <dlfcn.h>
+#endif
+
+#include <util/system/atomic.h>
+#include <util/system/defaults.h>
+#include <util/system/event.h>
+#include <util/system/rwlock.h>
+#include <util/system/spinlock.h>
+#include <util/system/thread.h>
+#include <util/system/yassert.h>
+#include <util/generic/hash.h>
+
+namespace {
+ volatile int SIGNAL_PIPE_WRITE_FD = 0; // will be initialized in ctor
+
+ void WriteAllOrDie(const int fd, const void* buf, size_t bufsize) {
+ size_t totalBytesWritten = 0;
+
+ while (totalBytesWritten != bufsize) {
+ const ssize_t result = write(fd, (const char*)buf + totalBytesWritten, bufsize - totalBytesWritten);
+
+ Y_VERIFY(result >= 0 || (result == -1 && errno == EINTR), "write failed: %s (errno = %d)", strerror(errno), errno);
+ totalBytesWritten += static_cast<size_t>(result);
+ }
+ }
+
+ void PipeWriterSignalHandler(int, siginfo_t* info, void*) {
+ const ui8 signum = static_cast<ui8>(info->si_signo);
+
+ WriteAllOrDie(SIGNAL_PIPE_WRITE_FD, &signum, 1);
+ }
+
+ // Handler for the "asynchronous" unix signals (those which can occur
+ // at arbitrary point of execution and have no need to be reacted on instantly
+ // and/or to preserve execution context at the point of interrupt).
+ //
+ // Async signals -- SIGHUP, SIGUSR1 (used to cause configuration files reread for example)
+ // Sync signals -- fatal errors like SIGSEGV, SIGBUS...
+ class TAsyncSignalsHandler {
+ private:
+ TThread Thread;
+ int SignalPipeReadFd;
+ typedef TAutoPtr<TEventHandler> TEventHandlerPtr;
+ THashMap<int, TEventHandlerPtr> Handlers;
+ TRWMutex HandlersLock;
+
+ TAtomic ShouldDie;
+ TSystemEvent DieEvent;
+
+ static void* ThreadFunc(void* data) {
+ reinterpret_cast<TAsyncSignalsHandler*>(data)->RealThreadFunc();
+
+ return nullptr;
+ }
+
+ inline void RealThreadFunc() {
+ for (;;) {
+ ui8 signum;
+ const ssize_t bytesRead = read(SignalPipeReadFd, &signum, 1);
+
+ Y_VERIFY(bytesRead >= 0 || (bytesRead == -1 && errno == EINTR), "read failed: %s (errno = %d)", strerror(errno), errno);
+
+ if (AtomicAdd(ShouldDie, 0) != 0) {
+ DieEvent.Signal();
+
+ break;
+ }
+
+ if (bytesRead == 0) {
+ break;
+ } else if (bytesRead == -1) {
+ continue;
+ }
+
+ {
+ TReadGuard dnd(HandlersLock);
+
+ const TEventHandlerPtr* handler = Handlers.FindPtr(signum);
+ Y_VERIFY(handler && handler->Get(), "Async signal handler is not set, it's a bug!");
+ handler->Get()->Handle(signum);
+ }
+ }
+ }
+
+ public:
+ TAsyncSignalsHandler()
+ : Thread(TThread::TParams(ThreadFunc, this).SetName("sighandler"))
+ , SignalPipeReadFd(0)
+ , ShouldDie(0)
+ {
+ int filedes[2] = {-1};
+
+#ifdef _linux_
+ int result;
+
+ {
+ using pipe2_t = decltype(pipe2);
+ pipe2_t* pipe2Ptr = (pipe2_t*)dlsym(RTLD_DEFAULT, "pipe2");
+
+#if defined(_musl_)
+ if (!pipe2Ptr) {
+ pipe2Ptr = pipe2;
+ }
+#endif
+
+ if (pipe2Ptr) {
+ result = pipe2Ptr(filedes, O_CLOEXEC);
+ } else {
+ result = -1;
+ errno = ENOSYS;
+ }
+ }
+
+ if (result != 0 && errno == ENOSYS) { // linux older than 2.6.27 returns "not implemented"
+#endif
+ Y_VERIFY(pipe(filedes) == 0, "pipe failed: %s (errno = %d)", strerror(errno), errno);
+
+ SignalPipeReadFd = filedes[0];
+ SIGNAL_PIPE_WRITE_FD = filedes[1];
+
+ Y_VERIFY(fcntl(SignalPipeReadFd, F_SETFD, FD_CLOEXEC) == 0, "fcntl failed: %s (errno = %d)", strerror(errno), errno);
+ Y_VERIFY(fcntl(SIGNAL_PIPE_WRITE_FD, F_SETFD, FD_CLOEXEC) == 0, "fcntl failed: %s (errno = %d)", strerror(errno), errno);
+#ifdef _linux_
+ } else {
+ Y_VERIFY(result == 0, "pipe2 failed: %s (errno = %d)", strerror(errno), errno);
+ SignalPipeReadFd = filedes[0];
+ SIGNAL_PIPE_WRITE_FD = filedes[1];
+ }
+#endif
+
+ Thread.Start();
+ Thread.Detach();
+ }
+
+ ~TAsyncSignalsHandler() {
+ AtomicSwap(&ShouldDie, TAtomic(1));
+ ui8 fakeSignal = 0;
+ WriteAllOrDie(SIGNAL_PIPE_WRITE_FD, &fakeSignal, 1);
+
+ DieEvent.WaitT(TDuration::Seconds(15));
+
+ /* may cause VERIFY failure in signal handler, propably we should leave it to process clean procedure
+ close(SIGNAL_PIPE_WRITE_FD);
+ close(SignalPipeReadFd);
+*/
+ }
+
+ bool DoInstall(int signum, TAutoPtr<TEventHandler> handler) {
+ TWriteGuard dnd(HandlersLock);
+ TEventHandlerPtr& ev = Handlers[signum];
+ const bool ret = !ev;
+
+ ev = handler;
+
+ return ret;
+ }
+
+ void Install(int signum, TAutoPtr<TEventHandler> handler) {
+ if (DoInstall(signum, handler)) {
+ struct sigaction a;
+
+ memset(&a, 0, sizeof(a));
+ a.sa_sigaction = PipeWriterSignalHandler;
+ a.sa_flags = SA_SIGINFO | SA_RESTART;
+
+ Y_VERIFY(!sigaction(signum, &a, nullptr), "sigaction failed: %s (errno = %d)", strerror(errno), errno);
+ }
+ }
+ };
+
+ // This pointer is never deleted - yeah, it's intended memory leak.
+ // It is necessary to prevent problems when user's signal handler calls exit function
+ // which destroys all global variables including this one.
+ // It such situation we have 2 options:
+ // - wait for auxiliary thread to die - which will cause dead lock
+ // - destruct variable, ignoring thread - which will cause data corruption.
+ TAsyncSignalsHandler* SIGNALS_HANDLER = nullptr;
+}
+
+void SetAsyncSignalHandler(int signum, TAutoPtr<TEventHandler> handler) {
+ static TAtomic lock;
+
+ if (Y_UNLIKELY(SIGNALS_HANDLER == nullptr)) {
+ TGuard<TAtomic> dnd(lock);
+
+ if (SIGNALS_HANDLER == nullptr) {
+ // NEVERS GETS DESTROYED
+ SIGNALS_HANDLER = new TAsyncSignalsHandler();
+ }
+ }
+
+ SIGNALS_HANDLER->Install(signum, handler);
+}
+
+#else //_win_
+
+void SetAsyncSignalHandler(int, TAutoPtr<TEventHandler>) {
+ // TODO: it's really easy to port using _pipe, _read and _write, but it must be tested properly.
+}
+
+#endif
+
+namespace {
+ template <typename TFunc>
+ class TFunctionEventHandler: public TEventHandler {
+ TFunc Func;
+
+ public:
+ TFunctionEventHandler(TFunc func) {
+ if (func)
+ Func = func;
+ }
+
+ int Handle(int signum) override {
+ if (Func) {
+ Func(signum);
+ }
+
+ return 0;
+ }
+ };
+}
+
+void SetAsyncSignalHandler(int signum, void (*handler)(int)) {
+ SetAsyncSignalHandler(signum, new TFunctionEventHandler<void (*)(int)>(handler));
+}
+
+void SetAsyncSignalFunction(int signum, std::function<void(int)> func) {
+ typedef std::function<void(int)> TFunc;
+ SetAsyncSignalHandler(signum, new TFunctionEventHandler<TFunc>(func));
+}
diff --git a/library/cpp/sighandler/async_signals_handler.h b/library/cpp/sighandler/async_signals_handler.h
new file mode 100644
index 0000000000..da36365ace
--- /dev/null
+++ b/library/cpp/sighandler/async_signals_handler.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <functional>
+
+struct TEventHandler {
+ virtual ~TEventHandler() {
+ }
+ virtual int Handle(int signum) = 0;
+};
+
+void SetAsyncSignalHandler(int signum, TAutoPtr<TEventHandler> handler);
+void SetAsyncSignalHandler(int signum, void (*handler)(int));
+void SetAsyncSignalFunction(int signum, std::function<void(int)> func);
diff --git a/library/cpp/sighandler/ya.make b/library/cpp/sighandler/ya.make
new file mode 100644
index 0000000000..c0f7ea6084
--- /dev/null
+++ b/library/cpp/sighandler/ya.make
@@ -0,0 +1,10 @@
+LIBRARY()
+
+OWNER(pg)
+
+SRCS(
+ async_signals_handler.cpp
+ async_signals_handler.h
+)
+
+END()
diff --git a/library/cpp/sliding_window/README.md b/library/cpp/sliding_window/README.md
new file mode 100644
index 0000000000..47692da7d5
--- /dev/null
+++ b/library/cpp/sliding_window/README.md
@@ -0,0 +1,30 @@
+# TSlidingWindow - скользящее окно
+
+[TSlidingWindow](/arc/trunk/arcadia/library/cpp/sliding_window/sliding_window.h) - класс скользящего окна, позволяющий поддерживать и обновлять определённое значение (максимум, сумму) в промежутке времени определённой длины. Разбивает общий временной промежуток на маленькие бакеты (число задаётся в конструкторе) и ротирует их, поддерживая значение за окно. Есть возможность также указать мьютекс или спинлок для синхронизации (по умолчанию TFakeMutex). Использование:
+
+```
+// Создаём окно, вычисляющее максимум за последние пять минут, поддерживая 50 бакетов со значениями.
+TSlidingWindow<TMaxOperation<int>> window(TDuration::Minutes(5), 50);
+
+// Загружаем значения в различные моменты времени
+window.Update(42, TInstant::Now());
+
+... // делаем какую-то работу
+int currentMaximum = window.Update(50, TInstant::Now());
+
+... // делаем ещё что-то
+int currentMaximum = window.Update(25, TInstant::Now());
+
+...
+// Просто получаем значение максимума за последние 5 минут
+int currentMaximum = window.Update(TInstant::Now());
+
+...
+int currentMaximum = window.GetValue(); // получение значения без обновления времени
+```
+
+# Поддерживаемые функции
+
+* `TMaxOperation` - максимум
+* `TMinOperation` - минимум
+* `TSumOperation` - сумма
diff --git a/library/cpp/sliding_window/sliding_window.cpp b/library/cpp/sliding_window/sliding_window.cpp
new file mode 100644
index 0000000000..086cce5d02
--- /dev/null
+++ b/library/cpp/sliding_window/sliding_window.cpp
@@ -0,0 +1 @@
+#include "sliding_window.h"
diff --git a/library/cpp/sliding_window/sliding_window.h b/library/cpp/sliding_window/sliding_window.h
new file mode 100644
index 0000000000..180bdf93d0
--- /dev/null
+++ b/library/cpp/sliding_window/sliding_window.h
@@ -0,0 +1,224 @@
+#pragma once
+
+#include <util/datetime/base.h>
+#include <util/generic/vector.h>
+#include <util/system/guard.h>
+#include <util/system/mutex.h>
+#include <util/system/types.h>
+#include <util/system/yassert.h>
+
+#include <functional>
+#include <limits>
+
+namespace NSlidingWindow {
+ namespace NPrivate {
+ template <class TValueType_, class TCmp, TValueType_ initialValue> // std::less for max, std::greater for min
+ struct TMinMaxOperationImpl {
+ using TValueType = TValueType_;
+ using TValueVector = TVector<TValueType>;
+
+ static constexpr TValueType InitialValue() {
+ return initialValue;
+ }
+
+ // Updates value in current bucket and returns window value
+ static TValueType UpdateBucket(TValueType windowValue, TValueVector& buckets, size_t index, TValueType newVal) {
+ Y_ASSERT(index < buckets.size());
+ TCmp cmp;
+ TValueType& curVal = buckets[index];
+ if (cmp(curVal, newVal)) {
+ curVal = newVal;
+ if (cmp(windowValue, newVal)) {
+ windowValue = newVal;
+ }
+ }
+ return windowValue;
+ }
+
+ static TValueType ClearBuckets(TValueType windowValue, TValueVector& buckets, const size_t firstElemIndex, const size_t bucketsToClear) {
+ Y_ASSERT(!buckets.empty());
+ Y_ASSERT(firstElemIndex < buckets.size());
+ Y_ASSERT(bucketsToClear <= buckets.size());
+ TCmp cmp;
+
+ bool needRecalc = false;
+ size_t current = firstElemIndex;
+ const size_t arraySize = buckets.size();
+ for (size_t i = 0; i < bucketsToClear; ++i) {
+ TValueType& curVal = buckets[current];
+ if (!needRecalc && windowValue == curVal) {
+ needRecalc = true;
+ }
+ curVal = InitialValue();
+ current = (current + 1) % arraySize;
+ }
+ if (needRecalc) {
+ windowValue = InitialValue();
+ for (size_t i = 0; i < firstElemIndex; ++i) {
+ const TValueType val = buckets[i];
+ if (cmp(windowValue, val)) {
+ windowValue = val;
+ }
+ }
+ for (size_t i = current, size = buckets.size(); i < size; ++i) {
+ const TValueType val = buckets[i];
+ if (cmp(windowValue, val)) {
+ windowValue = val;
+ }
+ }
+ }
+ return windowValue;
+ }
+ };
+
+ }
+
+ template <class TValueType>
+ using TMaxOperation = NPrivate::TMinMaxOperationImpl<TValueType, std::less<TValueType>, std::numeric_limits<TValueType>::min()>;
+
+ template <class TValueType>
+ using TMinOperation = NPrivate::TMinMaxOperationImpl<TValueType, std::greater<TValueType>, std::numeric_limits<TValueType>::max()>;
+
+ template <class TValueType_>
+ struct TSumOperation {
+ using TValueType = TValueType_;
+ using TValueVector = TVector<TValueType>;
+
+ static constexpr TValueType InitialValue() {
+ return TValueType(); // zero
+ }
+
+ // Updates value in current bucket and returns window value
+ static TValueType UpdateBucket(TValueType windowValue, TValueVector& buckets, size_t index, TValueType newVal) {
+ Y_ASSERT(index < buckets.size());
+ buckets[index] += newVal;
+ windowValue += newVal;
+ return windowValue;
+ }
+
+ static TValueType ClearBuckets(TValueType windowValue, TValueVector& buckets, size_t firstElemIndex, size_t bucketsToClear) {
+ Y_ASSERT(!buckets.empty());
+ Y_ASSERT(firstElemIndex < buckets.size());
+ Y_ASSERT(bucketsToClear <= buckets.size());
+
+ const size_t arraySize = buckets.size();
+ for (size_t i = 0; i < bucketsToClear; ++i) {
+ TValueType& curVal = buckets[firstElemIndex];
+ windowValue -= curVal;
+ curVal = InitialValue();
+ firstElemIndex = (firstElemIndex + 1) % arraySize;
+ }
+ return windowValue;
+ }
+ };
+
+ /////////////////////////////////////////////////////////////////////////////////////////
+ // TSlidingWindow
+ /////////////////////////////////////////////////////////////////////////////////////////
+ template <class TOperation, class TMutexImpl = TFakeMutex>
+ class TSlidingWindow {
+ public:
+ using TValueType = typename TOperation::TValueType;
+ using TValueVector = TVector<TValueType>;
+ using TSizeType = typename TValueVector::size_type;
+
+ public:
+ TSlidingWindow(const TDuration& length, TSizeType partsNum)
+ : Mutex()
+ , Buckets(partsNum, TOperation::InitialValue()) // vector of size partsNum initialized with initial value
+ , WindowValue(TOperation::InitialValue())
+ , FirstElem(0)
+ , PeriodStart()
+ , Length(length)
+ , MicroSecondsPerBucket(length.MicroSeconds() / partsNum)
+ {
+ }
+
+ TSlidingWindow(const TSlidingWindow& w)
+ : Mutex()
+ {
+ TGuard<TMutexImpl> guard(&w.Mutex);
+ Buckets = w.Buckets;
+ WindowValue = w.WindowValue;
+ FirstElem = w.FirstElem;
+ PeriodStart = w.PeriodStart;
+ Length = w.Length;
+ MicroSecondsPerBucket = w.MicroSecondsPerBucket;
+ }
+
+ TSlidingWindow(TSlidingWindow&&) = default;
+
+ TSlidingWindow& operator=(TSlidingWindow&&) = default;
+ TSlidingWindow& operator=(const TSlidingWindow&) = delete;
+
+ // Period of time
+ const TDuration& GetDuration() const {
+ return Length;
+ }
+
+ // Update window with new value and time
+ TValueType Update(TValueType val, TInstant t) {
+ TGuard<TMutexImpl> guard(&Mutex);
+ AdvanceTime(t);
+ UpdateCurrentBucket(val);
+ return WindowValue;
+ }
+
+ // Update just time, without new values
+ TValueType Update(TInstant t) {
+ TGuard<TMutexImpl> guard(&Mutex);
+ AdvanceTime(t);
+ return WindowValue;
+ }
+
+ // Get current window value (without updating current time)
+ TValueType GetValue() const {
+ TGuard<TMutexImpl> guard(&Mutex);
+ return WindowValue;
+ }
+
+ private:
+ void UpdateCurrentBucket(TValueType val) {
+ const TSizeType arraySize = Buckets.size();
+ const TSizeType pos = (FirstElem + arraySize - 1) % arraySize;
+ WindowValue = TOperation::UpdateBucket(WindowValue, Buckets, pos, val);
+ }
+
+ void AdvanceTime(const TInstant& time) {
+ if (time < PeriodStart + Length) {
+ return;
+ }
+
+ if (PeriodStart.MicroSeconds() == 0) {
+ PeriodStart = time - Length;
+ return;
+ }
+
+ const TInstant& newPeriodStart = time - Length;
+ const ui64 tmDiff = (newPeriodStart - PeriodStart).MicroSeconds();
+ const TSizeType bucketsDiff = tmDiff / MicroSecondsPerBucket;
+ const TSizeType arraySize = Buckets.size();
+ const TSizeType buckets = Min(bucketsDiff, arraySize);
+
+ WindowValue = TOperation::ClearBuckets(WindowValue, Buckets, FirstElem, buckets);
+ FirstElem = (FirstElem + buckets) % arraySize;
+ PeriodStart += TDuration::MicroSeconds(bucketsDiff * MicroSecondsPerBucket);
+
+ // Check that PeriodStart lags behind newPeriodStart
+ // (which is actual, uptodate, precise and equal to time - Length) not more
+ // then MicroSecondsPerBucket
+ Y_ASSERT(newPeriodStart >= PeriodStart);
+ Y_ASSERT((newPeriodStart - PeriodStart).MicroSeconds() <= MicroSecondsPerBucket);
+ }
+
+
+ mutable TMutexImpl Mutex;
+ TValueVector Buckets;
+ TValueType WindowValue;
+ TSizeType FirstElem;
+ TInstant PeriodStart;
+ TDuration Length;
+ ui64 MicroSecondsPerBucket;
+ };
+
+}
diff --git a/library/cpp/sliding_window/sliding_window_ut.cpp b/library/cpp/sliding_window/sliding_window_ut.cpp
new file mode 100644
index 0000000000..1e7343a8d3
--- /dev/null
+++ b/library/cpp/sliding_window/sliding_window_ut.cpp
@@ -0,0 +1,132 @@
+#include "sliding_window.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NSlidingWindow;
+
+Y_UNIT_TEST_SUITE(TSlidingWindowTest) {
+ Y_UNIT_TEST(TestSlidingWindowMax) {
+ TSlidingWindow<TMaxOperation<unsigned>> w(TDuration::Minutes(5), 5);
+ TInstant start = TInstant::MicroSeconds(TDuration::Hours(1).MicroSeconds());
+ TInstant now = start;
+ w.Update(5, start); // ~ ~ ~ ~ 5
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^
+ now += TDuration::Minutes(1) + TDuration::Seconds(1);
+ w.Update(5, now); // 5 ~ ~ ~ 5
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^
+ now += TDuration::Minutes(1);
+ w.Update(3, now); // 5 3 ~ ~ 5
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^
+ now += TDuration::Minutes(3);
+ w.Update(2, now); // 5 3 ~ ~ 2
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^
+ now += TDuration::Minutes(1);
+ w.Update(2, now); // 2 3 ~ ~ 2
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 3); // ^
+ now += TDuration::Minutes(1);
+ w.Update(2, now); // 2 2 ~ ~ 2
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 2); // ^
+ now += TDuration::Minutes(5);
+ w.Update(1, now); // ~ 1 ~ ~ ~
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 1); // ^
+
+ // update current bucket
+ w.Update(2, now); // ~ 2 ~ ~ ~
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 2); // ^
+
+ w.Update(1, now + TDuration::Seconds(30)); // ~ 2 ~ ~ ~
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 2); // ^
+
+ // test idle
+ now += TDuration::Minutes(1);
+ w.Update(now); // ~ 2 ~ ~ ~
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 2); // ^
+
+ now += TDuration::Minutes(5); // ~ ~ ~ ~ ~
+ UNIT_ASSERT_VALUES_EQUAL(w.Update(now), 0);
+ }
+
+ Y_UNIT_TEST(TestSlidingWindowMin) {
+ TSlidingWindow<TMinOperation<unsigned>> w(TDuration::Minutes(5), 5);
+ TInstant start = TInstant::MicroSeconds(TDuration::Hours(1).MicroSeconds());
+ TInstant now = start;
+ w.Update(5, start); // ~ ~ ~ ~ 5
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^
+ now += TDuration::Minutes(1) + TDuration::Seconds(1);
+ w.Update(5, now); // 5 ~ ~ ~ 5
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^
+ now += TDuration::Minutes(1);
+ w.Update(7, now); // 5 7 ~ ~ 5
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^
+ now += TDuration::Minutes(3);
+ w.Update(8, now); // 5 7 ~ ~ 8
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^
+ now += TDuration::Minutes(1);
+ w.Update(8, now); // 8 7 ~ ~ 8
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 7); // ^
+ now += TDuration::Minutes(1);
+ w.Update(8, now); // 8 8 ~ ~ 8
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 8); // ^
+ now += TDuration::Minutes(5);
+ w.Update(6, now); // ~ 6 ~ ~ ~
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 6); // ^
+
+ // update current bucket
+ w.Update(5, now); // ~ 5 ~ ~ ~
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^
+
+ w.Update(6, now + TDuration::Seconds(30)); // ~ 5 ~ ~ ~
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^
+
+ // test idle
+ now += TDuration::Minutes(1);
+ w.Update(now); // ~ 5 ~ ~ ~
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^
+
+ now += TDuration::Minutes(5); // ~ ~ ~ ~ ~
+ UNIT_ASSERT_VALUES_EQUAL(w.Update(now), std::numeric_limits<unsigned>::max());
+ }
+
+ Y_UNIT_TEST(TestSlidingWindowSum) {
+ TSlidingWindow<TSumOperation<unsigned>> w(TDuration::Minutes(5), 5);
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 0); // current sum
+
+ TInstant start = TInstant::MicroSeconds(TDuration::Hours(1).MicroSeconds());
+ TInstant now = start;
+ w.Update(5, start); // 0 0 0 0 5
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^
+ now += TDuration::Minutes(1) + TDuration::Seconds(1);
+ w.Update(5, now); // 5 0 0 0 5
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 10); // ^
+ now += TDuration::Minutes(1);
+ w.Update(3, now); // 5 3 0 0 5
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 13); // ^
+ now += TDuration::Minutes(3);
+ w.Update(2, now); // 5 3 0 0 2
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 10); // ^
+ now += TDuration::Minutes(1);
+ w.Update(2, now); // 2 3 0 0 2
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 7); // ^
+ now += TDuration::Minutes(1);
+ w.Update(2, now); // 2 2 0 0 2
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 6); // ^
+ now += TDuration::Minutes(5);
+ w.Update(1, now); // 0 1 0 0 0
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 1); // ^
+
+ // update current bucket
+ w.Update(2, now); // 0 3 0 0 0
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 3); // ^
+
+ w.Update(1, now + TDuration::Seconds(30)); // 0 4 0 0 0
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 4); // ^
+
+ // test idle
+ now += TDuration::Minutes(1);
+ w.Update(now); // 0 4 0 0 0
+ UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 4); // ^
+
+ now += TDuration::Minutes(5); // 0 0 0 0 0
+ UNIT_ASSERT_VALUES_EQUAL(w.Update(now), 0);
+ }
+}
diff --git a/library/cpp/sliding_window/ut/ya.make b/library/cpp/sliding_window/ut/ya.make
new file mode 100644
index 0000000000..3839a8dadc
--- /dev/null
+++ b/library/cpp/sliding_window/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/sliding_window)
+
+OWNER(g:kikimr)
+
+SRCS(
+ sliding_window_ut.cpp
+)
+
+END()
diff --git a/library/cpp/sliding_window/ya.make b/library/cpp/sliding_window/ya.make
new file mode 100644
index 0000000000..79aeaa06bb
--- /dev/null
+++ b/library/cpp/sliding_window/ya.make
@@ -0,0 +1,10 @@
+LIBRARY()
+
+OWNER(g:kikimr)
+
+SRCS(
+ sliding_window.cpp
+ sliding_window.h
+)
+
+END()
diff --git a/library/cpp/sse/README.md b/library/cpp/sse/README.md
new file mode 100644
index 0000000000..a82c98a1b9
--- /dev/null
+++ b/library/cpp/sse/README.md
@@ -0,0 +1,7 @@
+Overview
+===
+This library provides the implementation of Intel SSE intrinsics for other CPU architectures. Currently supports PowerPC via translation to AltiVec and ARM via NEON. In some cases, falls back to software emulation if there's no corresponding instruction in the target instruction set.
+
+Usage
+===
+Include library/cpp/sse/sse.h and use the needed intrinsics. Implementation will be selected based on the target architecture of the used toolchain.
diff --git a/library/cpp/sse/powerpc.h b/library/cpp/sse/powerpc.h
new file mode 100644
index 0000000000..82fc011fa5
--- /dev/null
+++ b/library/cpp/sse/powerpc.h
@@ -0,0 +1,1000 @@
+#pragma once
+
+/*
+ The header contains code which translates SSE intrinsics
+ to PowerPC AltiVec or software emulation.
+
+ See also: https://www.ibm.com/developerworks/community/wikis/home?lang=en#!/wiki/W51a7ffcf4dfd_4b40_9d82_446ebc23c550/page/Intel%20SSE%20to%20PowerPC%20AltiVec%20migration
+*/
+/* Author: Vadim Rumyantsev <rumvadim@yandex-team.ru> */
+
+#if !defined(_ppc64_)
+#error "This header is for PowerPC (ppc64) platform only." \
+ "Include sse.h instead of including this header directly."
+#endif
+
+#include <util/system/types.h>
+#include <util/system/compiler.h>
+
+#include <altivec.h>
+
+typedef __attribute__((__aligned__(8))) unsigned long long __m64;
+typedef __attribute__((__aligned__(16), __may_alias__)) vector float __m128;
+typedef __attribute__((__aligned__(16), __may_alias__)) vector unsigned char __m128i;
+typedef __attribute__((__aligned__(16), __may_alias__)) vector double __m128d;
+
+using __v2df = __vector double;
+using __v2di = __vector long long;
+using __v2du = __vector unsigned long long;
+using __v4si = __vector int;
+using __v4su = __vector unsigned int;
+using __v8hi = __vector short;
+using __v8hu = __vector unsigned short;
+using __v16qi = __vector signed char;
+using __v16qu = __vector unsigned char;
+using __v4sf = __vector float;
+
+enum _mm_hint
+{
+ /* _MM_HINT_ET is _MM_HINT_T with set 3rd bit. */
+ _MM_HINT_ET0 = 7,
+ _MM_HINT_ET1 = 6,
+ _MM_HINT_T0 = 3,
+ _MM_HINT_T1 = 2,
+ _MM_HINT_T2 = 1,
+ _MM_HINT_NTA = 0
+};
+
+#define _MM_SHUFFLE(a, b, c, d) ((signed char)(a * 64 + b * 16 + c * 4 + d))
+
+/// Functions that work with floats.
+
+Y_FORCE_INLINE __m128 _mm_setzero_ps() {
+ return (__m128){0.0f, 0.0f, 0.0f, 0.0f};
+};
+
+Y_FORCE_INLINE __m128d _mm_setzero_pd() {
+ return (__m128d)vec_splats((double)0);
+}
+
+// bug in clang compiler until 7.0.0 inclusive, Y_NO_INLINE is vital/essential
+static Y_NO_INLINE __m128 _mm_set1_ps(float f) {
+ return (vector float)f;
+}
+
+Y_FORCE_INLINE __m128 _mm_set_ps1(float f) {
+ return _mm_set1_ps(f);
+}
+
+Y_FORCE_INLINE __m128 _mm_set_ps(float v3, float v2, float v1, float v0) {
+ return (__m128)(__v4sf){v0, v1, v2, v3};
+}
+
+Y_FORCE_INLINE __m128d _mm_set_pd(double d1, double d0) {
+ return (__m128d){d0, d1};
+}
+
+Y_FORCE_INLINE __m128 _mm_loadu_ps(const float* p) {
+ return vec_vsx_ld(0, p);
+}
+
+Y_FORCE_INLINE __m128 _mm_load_ps(const float* p) {
+ return (__m128)vec_ld(0, (vector float*)p);
+}
+
+Y_FORCE_INLINE __m128 _mm_loadu_pd(const double* d) {
+ return vec_vsx_ld(0, d);
+}
+
+Y_FORCE_INLINE void _mm_storeu_ps(float* p, __m128 a) {
+ *(__m128*)p = a;
+}
+
+Y_FORCE_INLINE __m128 _mm_xor_ps(__m128 a, __m128 b) {
+ return (__m128)vec_xor((__v4sf)a, (__v4sf)b);
+}
+
+Y_FORCE_INLINE __m128 _mm_xor_pd(__m128d a, __m128d b) {
+ return (__m128)vec_xor((__v2df)a, (__v2df)b);
+}
+
+Y_FORCE_INLINE __m128 _mm_add_ps(__m128 a, __m128 b) {
+ return (__m128)((__v4sf)a + (__v4sf)b);
+}
+
+Y_FORCE_INLINE __m128d _mm_add_pd(__m128d a, __m128d b) {
+ return (__m128d)((__v2df)a + (__v2df)b);
+}
+
+Y_FORCE_INLINE __m128 _mm_sub_ps(__m128 a, __m128 b) {
+ return (__m128)((__v4sf)a - (__v4sf)b);
+}
+
+Y_FORCE_INLINE __m128d _mm_sub_pd(__m128d a, __m128d b) {
+ return (__m128d)((__v2df)a - (__v2df)b);
+}
+
+Y_FORCE_INLINE __m128 _mm_mul_ps(__m128 a, __m128 b) {
+ return (__m128)((__v4sf)a * (__v4sf)b);
+}
+
+Y_FORCE_INLINE __m128d _mm_mul_pd(__m128d a, __m128d b) {
+ return (__m128d)((__v2df)a * (__v2df)b);
+}
+
+Y_FORCE_INLINE __m128 _mm_div_ps(__m128 a, __m128 b) {
+ return (__m128)((__v4sf)a / (__v4sf)b);
+}
+
+Y_FORCE_INLINE __m128d _mm_div_pd(__m128d a, __m128d b) {
+ return (__m128d)((__v2df)a / (__v2df)b);
+}
+
+Y_FORCE_INLINE __m128 _mm_cmpeq_ps(__m128 a, __m128 b) {
+ return ((__m128)vec_cmpeq((__v4sf)a, (__v4sf)b));
+ ;
+}
+
+Y_FORCE_INLINE __m128 _mm_cmpgt_ps(__m128 a, __m128 b) {
+ return ((__m128)vec_cmpgt((__v4sf)a, (__v4sf)b));
+}
+
+Y_FORCE_INLINE __m128 _mm_max_ps(__m128 a, __m128 b) {
+ return (__m128)vec_max((vector float)a, (vector float)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_max_epu8(__m128i a, __m128i b) {
+ return (__m128i)vec_max((__v16qu)a, (__v16qu)b);
+}
+
+Y_FORCE_INLINE __m128 _mm_min_ps(__m128 a, __m128 b) {
+ return (__m128)vec_min((vector float)a, (vector float)b);
+}
+
+Y_FORCE_INLINE __m128 _mm_and_ps(__m128 a, __m128 b) {
+ return ((__m128)vec_and((__v4sf)a, (__v4sf)b));
+}
+
+Y_FORCE_INLINE __m128d _mm_and_pd(__m128d a, __m128d b) {
+ return vec_and((__v2df)a, (__v2df)b);
+}
+
+Y_FORCE_INLINE __m128 _mm_rsqrt_ps(__m128 a) {
+ return vec_rsqrte(a);
+}
+
+Y_FORCE_INLINE __m128 _mm_rsqrt_ss(__m128 a) {
+ __m128 a1, c;
+ const vector unsigned int mask = {0xffffffff, 0, 0, 0};
+ a1 = vec_splat(a, 0);
+ c = vec_rsqrte(a1);
+ return (vec_sel((vector float)a, c, mask));
+}
+
+Y_FORCE_INLINE int _mm_movemask_ps(__m128 a) {
+ __vector unsigned long long result;
+ const __vector unsigned int perm_mask =
+ {
+#ifdef __LITTLE_ENDIAN__
+ 0x00204060, 0x80808080, 0x80808080, 0x80808080
+#elif __BIG_ENDIAN__
+ 0x80808080, 0x80808080, 0x80808080, 0x00204060
+#endif
+ };
+
+ result = (__vector unsigned long long)vec_vbpermq((__vector unsigned char)a,
+ (__vector unsigned char)perm_mask);
+
+#ifdef __LITTLE_ENDIAN__
+ return result[1];
+#elif __BIG_ENDIAN__
+ return result[0];
+#endif
+}
+
+Y_FORCE_INLINE __m128 _mm_cvtepi32_ps(__m128i a) {
+ return ((__m128)vec_ctf((__v4si)a, 0));
+}
+
+Y_FORCE_INLINE float _mm_cvtss_f32(__m128 a) {
+ return ((__v4sf)a)[0];
+}
+
+Y_FORCE_INLINE __m128 _mm_cmpunord_ps(__m128 A, __m128 B) {
+ __vector unsigned int a, b;
+ __vector unsigned int c, d;
+ const __vector unsigned int float_exp_mask =
+ {0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000};
+
+ a = (__vector unsigned int)vec_abs((__v4sf)A);
+ b = (__vector unsigned int)vec_abs((__v4sf)B);
+ c = (__vector unsigned int)vec_cmpgt(a, float_exp_mask);
+ d = (__vector unsigned int)vec_cmpgt(b, float_exp_mask);
+ return ((__m128)vec_or(c, d));
+}
+
+Y_FORCE_INLINE __m128 _mm_andnot_ps(__m128 a, __m128 b) {
+ return ((__m128)vec_andc((__v4sf)b, (__v4sf)a));
+}
+
+Y_FORCE_INLINE __m128 _mm_or_ps(__m128 a, __m128 b) {
+ return ((__m128)vec_or((__v4sf)a, (__v4sf)b));
+}
+
+Y_FORCE_INLINE void _mm_store_ss(float* p, __m128 a) {
+ *p = ((__v4sf)a)[0];
+}
+
+Y_FORCE_INLINE void _mm_store_ps(float* p, __m128 a) {
+ vec_st(a, 0, p);
+}
+
+Y_FORCE_INLINE void _mm_storeu_pd(double* p, __m128d a) {
+ *(__m128d*)p = a;
+}
+
+Y_FORCE_INLINE void _mm_store_pd(double* p, __m128d a) {
+ vec_st((vector unsigned char)a, 0, (vector unsigned char*)p);
+}
+
+Y_FORCE_INLINE __m128 _mm_shuffle_ps(__m128 a, __m128 b, long shuff) {
+ unsigned long element_selector_10 = shuff & 0x03;
+ unsigned long element_selector_32 = (shuff >> 2) & 0x03;
+ unsigned long element_selector_54 = (shuff >> 4) & 0x03;
+ unsigned long element_selector_76 = (shuff >> 6) & 0x03;
+ const unsigned int permute_selectors[4] =
+ {
+#ifdef __LITTLE_ENDIAN__
+ 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
+#elif __BIG_ENDIAN__
+ 0x0C0D0E0F, 0x08090A0B, 0x04050607, 0x00010203
+#endif
+ };
+ __vector unsigned int t;
+
+#ifdef __LITTLE_ENDIAN__
+ t[0] = permute_selectors[element_selector_10];
+ t[1] = permute_selectors[element_selector_32];
+ t[2] = permute_selectors[element_selector_54] + 0x10101010;
+ t[3] = permute_selectors[element_selector_76] + 0x10101010;
+#elif __BIG_ENDIAN__
+ t[3] = permute_selectors[element_selector_10] + 0x10101010;
+ t[2] = permute_selectors[element_selector_32] + 0x10101010;
+ t[1] = permute_selectors[element_selector_54];
+ t[0] = permute_selectors[element_selector_76];
+#endif
+ return vec_perm((__v4sf)a, (__v4sf)b, (__vector unsigned char)t);
+}
+
+Y_FORCE_INLINE __m128d _mm_shuffle_pd(__m128d a, __m128d b, const int mask) {
+ __vector double result;
+ const int litmsk = mask & 0x3;
+
+ if (litmsk == 0)
+ result = vec_mergeh(a, b);
+ else if (litmsk == 1)
+ result = vec_xxpermdi(a, b, 2);
+ else if (litmsk == 2)
+ result = vec_xxpermdi(a, b, 1);
+ else
+ result = vec_mergel(a, b);
+ return result;
+}
+
+Y_FORCE_INLINE __m128i _mm_cvtps_epi32(__m128 a) {
+ vector float rounded;
+ __v4si result;
+
+ rounded = vec_rint((vector float)a);
+ result = vec_cts(rounded, 0);
+ return (__m128i)result;
+}
+
+/// Functions that work with integers.
+
+Y_FORCE_INLINE int _mm_movemask_epi8(__m128i a) {
+ __vector unsigned long long result;
+ const __vector unsigned char perm_mask =
+ {
+#ifdef __LITTLE_ENDIAN__
+ 0x78, 0x70, 0x68, 0x60, 0x58, 0x50, 0x48, 0x40,
+ 0x38, 0x30, 0x28, 0x20, 0x18, 0x10, 0x08, 0x00
+#elif __BIG_ENDIAN__
+ 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38,
+ 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78
+#endif
+ };
+
+ result = (__vector unsigned long long)vec_vbpermq((__vector unsigned char)a,
+ (__vector unsigned char)perm_mask);
+
+#ifdef __LITTLE_ENDIAN__
+ return result[1];
+#elif __BIG_ENDIAN__
+ return result[0];
+#endif
+}
+
+Y_FORCE_INLINE __m128i _mm_cvttps_epi32(__m128 a) {
+ __v4si result;
+
+ result = vec_cts((__v4sf)a, 0);
+ return (__m128i)result;
+}
+
+#define _MM_TRANSPOSE4_PS(row0, row1, row2, row3) \
+ do { \
+ __v4sf __r0 = (row0), __r1 = (row1), __r2 = (row2), __r3 = (row3); \
+ __v4sf __t0 = vec_vmrghw((vector unsigned int)__r0, (vector unsigned int)__r1); \
+ __v4sf __t1 = vec_vmrghw((vector unsigned int)__r2, (vector unsigned int)__r3); \
+ __v4sf __t2 = vec_vmrglw((vector unsigned int)__r0, (vector unsigned int)__r1); \
+ __v4sf __t3 = vec_vmrglw((vector unsigned int)__r2, (vector unsigned int)__r3); \
+ (row0) = (__v4sf)vec_mergeh((vector long long)__t0, \
+ (vector long long)__t1); \
+ (row1) = (__v4sf)vec_mergel((vector long long)__t0, \
+ (vector long long)__t1); \
+ (row2) = (__v4sf)vec_mergeh((vector long long)__t2, \
+ (vector long long)__t3); \
+ (row3) = (__v4sf)vec_mergel((vector long long)__t2, \
+ (vector long long)__t3); \
+ } while (0)
+
+Y_FORCE_INLINE __m128i _mm_or_si128(__m128i a, __m128i b) {
+ return (__m128i)vec_or((__v2di)a, (__v2di)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_and_si128(__m128i a, __m128i b) {
+ return (__m128i)vec_and((__v2di)a, (__v2di)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_andnot_si128(__m128i a, __m128i b) {
+ return (__m128i)vec_andc((__v2di)b, (__v2di)a);
+}
+
+Y_FORCE_INLINE __m128i _mm_xor_si128(__m128i a, __m128i b) {
+ return (__m128i)vec_xor((__v2di)a, (__v2di)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_setzero_si128() {
+ return (__m128i)(__v4si){0, 0, 0, 0};
+}
+
+Y_FORCE_INLINE __m128i _mm_shuffle_epi32(__m128i op1, long op2) {
+ unsigned long element_selector_10 = op2 & 0x03;
+ unsigned long element_selector_32 = (op2 >> 2) & 0x03;
+ unsigned long element_selector_54 = (op2 >> 4) & 0x03;
+ unsigned long element_selector_76 = (op2 >> 6) & 0x03;
+ const unsigned int permute_selectors[4] =
+ {
+#ifdef __LITTLE_ENDIAN__
+ 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
+#elif __BIG_ENDIAN__
+ 0x0C0D0E0F, 0x08090A0B, 0x04050607, 0x00010203
+#endif
+ };
+ __v4su t;
+
+#ifdef __LITTLE_ENDIAN__
+ t[0] = permute_selectors[element_selector_10];
+ t[1] = permute_selectors[element_selector_32];
+ t[2] = permute_selectors[element_selector_54] + 0x10101010;
+ t[3] = permute_selectors[element_selector_76] + 0x10101010;
+#elif __BIG_ENDIAN__
+ t[3] = permute_selectors[element_selector_10] + 0x10101010;
+ t[2] = permute_selectors[element_selector_32] + 0x10101010;
+ t[1] = permute_selectors[element_selector_54];
+ t[0] = permute_selectors[element_selector_76];
+#endif
+ return (__m128i)vec_perm((__v4si)op1, (__v4si)op1, (__vector unsigned char)t);
+}
+
+Y_FORCE_INLINE int _mm_extract_epi16(__m128i a, int imm) {
+ return (unsigned short)((__v8hi)a)[imm & 7];
+}
+
+Y_FORCE_INLINE int _mm_extract_epi8(__m128i a, int imm) {
+ return (unsigned char)((__v16qi)a)[imm & 15];
+}
+
+Y_FORCE_INLINE int _mm_extract_epi32(__m128i a, int imm) {
+ return ((__v4si)a)[imm & 3];
+}
+
+Y_FORCE_INLINE long long _mm_extract_epi64(__m128i a, int imm) {
+ return ((__v2di)a)[imm & 1];
+}
+
+Y_FORCE_INLINE int _mm_extract_ps(__m128 a, int imm) {
+ return ((__v4si)a)[imm & 3];
+}
+
+Y_FORCE_INLINE __m128i _mm_slli_epi16(__m128i a, int count) {
+ __v8hu lshift;
+ __v8hi result = {0, 0, 0, 0, 0, 0, 0, 0};
+
+ if (count >= 0 && count < 16) {
+ if (__builtin_constant_p(count)) {
+ lshift = (__v8hu)vec_splat_s16(count);
+ } else {
+ lshift = vec_splats((unsigned short)count);
+ }
+
+ result = vec_vslh((__v8hi)a, lshift);
+ }
+
+ return (__m128i)result;
+}
+
+Y_FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, int count) {
+ __v4su lshift;
+ __v4si result = {0, 0, 0, 0};
+
+ if (count >= 0 && count < 32) {
+ if (__builtin_constant_p(count) && count < 16) {
+ lshift = (__v4su)vec_splat_s32(count);
+ } else {
+ lshift = vec_splats((unsigned int)count);
+ }
+
+ result = vec_vslw((__v4si)a, lshift);
+ }
+
+ return (__m128i)result;
+}
+
+Y_FORCE_INLINE __m128i _mm_slli_epi64(__m128i a, int count) {
+ __v2du lshift;
+ __v2di result = {0, 0};
+
+ if (count >= 0 && count < 64) {
+ if (__builtin_constant_p(count) && count < 16) {
+ lshift = (__v2du)vec_splat_s32(count);
+ } else {
+ lshift = (__v2du)vec_splats((unsigned int)count);
+ }
+
+ result = vec_sl((__v2di)a, lshift);
+ }
+
+ return (__m128i)result;
+}
+
+Y_FORCE_INLINE __m128i _mm_slli_si128(__m128i a, int imm) {
+ __v16qu result;
+ const __v16qu zeros = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ if (imm < 16)
+#ifdef __LITTLE_ENDIAN__
+ result = vec_sld((__v16qu)a, zeros, imm);
+#elif __BIG_ENDIAN__
+ result = vec_sld(zeros, (__v16qu)a, (16 - imm));
+#endif
+ else
+ result = zeros;
+
+ return (__m128i)result;
+}
+
+Y_FORCE_INLINE __m128i _mm_srli_epi16(__m128i a, int count) {
+ if ((unsigned long)count >= 16) {
+ /* SSE2 shifts >= element_size or < 0 produce 0; Altivec/MMX shifts by count%element_size. */
+ return (__m128i)vec_splats(0);
+ } else if (count == 0) {
+ return a;
+ } else {
+ /* The PowerPC Architecture says all shift count fields must contain the same shift count. */
+ __v8hi replicated_count;
+ replicated_count = vec_splats((short)count);
+ return (__m128i)vec_sr((vector signed short)a, replicated_count);
+ }
+}
+
+Y_FORCE_INLINE __m128i _mm_srli_epi32(__m128i a, int count) {
+ if ((unsigned long)count >= 32) {
+ /* SSE2 shifts >= element_size or < 0 produce 0; Altivec/MMX shifts by count%element_size. */
+ return (__m128i)vec_splats(0);
+ } else if (count == 0) {
+ return a;
+ } else {
+ /* The PowerPC Architecture says all shift count fields must contain the same shift count. */
+ __v4si replicated_count;
+ replicated_count = vec_splats(count);
+ return (__m128i)vec_sr((vector signed int)a, replicated_count);
+ }
+}
+
+Y_FORCE_INLINE __m128i _mm_srli_epi64(__m128i a, int count) {
+ if ((unsigned long)count >= 64) {
+ /* SSE2 shifts >= element_size or < 0 produce 0; Altivec/MMX shifts by count%element_size. */
+ return (__m128i)vec_splats(0);
+ } else if (count == 0) {
+ return a;
+ } else {
+ /* The PowerPC Architecture says all shift count fields must contain the same shift count. */
+ /* On Power7 vec_slo (vslo) does use just the documented bits 121:124. */
+ /* On Power7 vec_sll (vsll) uses the lower 3 bits of each byte instead (legal). */
+ __v16qu replicated_count;
+ replicated_count = vec_splats((unsigned char)count);
+ long long m = 0xFFFFFFFFFFFFFFFFull >> count;
+ __v2di mask;
+ mask[0] = m;
+ mask[1] = m;
+ return vec_and(vec_srl(vec_sro(a, (__m128i)replicated_count), (__m128i)replicated_count), (__v16qu)mask);
+ }
+}
+
+Y_FORCE_INLINE __m128i _mm_bsrli_si128(__m128i a, const int __N) {
+ __v16qu result;
+ const __v16qu zeros = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ if (__N < 16)
+ if (__builtin_constant_p(__N))
+ /* Would like to use Vector Shift Left Double by Octet
+ Immediate here to use the immediate form and avoid
+ load of __N * 8 value into a separate VR. */
+ result = vec_sld(zeros, (__v16qu)a, (16 - __N));
+ else {
+ __v16qu shift = vec_splats((unsigned char)(__N * 8));
+ result = vec_sro((__v16qu)a, shift);
+ }
+ else
+ result = zeros;
+
+ return (__m128i)result;
+}
+
+Y_FORCE_INLINE __m128i _mm_srli_si128(__m128i a, int imm) {
+ return _mm_bsrli_si128(a, imm);
+}
+
+Y_FORCE_INLINE __m128i _mm_srai_epi16(__m128i a, int count) {
+ __v8hu rshift = {15, 15, 15, 15, 15, 15, 15, 15};
+ __v8hi result;
+ if (count < 16) {
+ if (__builtin_constant_p(count)) {
+ rshift = (__v8hu)vec_splat_s16(count);
+ } else {
+ rshift = vec_splats((unsigned short)count);
+ }
+ }
+ result = vec_vsrah((__v8hi)a, rshift);
+ return (__m128i)result;
+}
+
+Y_FORCE_INLINE __m128i _mm_srai_epi32(__m128i a, int count) {
+ // return vec_shiftrightarithmetic4wimmediate(a, count); //!< Failes to work with count >= 32.
+ __v4su rshift = {31, 31, 31, 31};
+ __v4si result;
+
+ if (count < 32) {
+ if (__builtin_constant_p(count)) {
+ if (count < 16) {
+ rshift = (__v4su)vec_splat_s32(count);
+ } else {
+ rshift = (__v4su)vec_splats((unsigned int)count);
+ }
+ } else {
+ rshift = vec_splats((unsigned int)count);
+ }
+ }
+ result = vec_vsraw((__v4si)a, rshift);
+ return (__m128i)result;
+}
+
+Y_FORCE_INLINE __m128i _mm_sll_epi16(__m128i a, __m128i count) {
+ __v8hu lshift, shmask;
+ const __v8hu shmax = {15, 15, 15, 15, 15, 15, 15, 15};
+ __v8hu result;
+
+#ifdef __LITTLE_ENDIAN__
+ lshift = vec_splat((__v8hu)count, 0);
+#elif __BIG_ENDIAN__
+ lshift = vec_splat((__v8hu)count, 3);
+#endif
+ shmask = vec_cmple(lshift, shmax);
+ result = vec_vslh((__v8hu)a, lshift);
+ result = vec_sel(shmask, result, shmask);
+ return (__m128i)result;
+}
+
+Y_FORCE_INLINE __m128i _mm_sll_epi32(__m128i a, __m128i count) {
+ __v4su lshift, shmask;
+ const __v4su shmax = {32, 32, 32, 32};
+ __v4su result;
+#ifdef __LITTLE_ENDIAN__
+ lshift = vec_splat((__v4su)count, 0);
+#elif __BIG_ENDIAN__
+ lshift = vec_splat((__v4su)count, 1);
+#endif
+ shmask = vec_cmplt(lshift, shmax);
+ result = vec_vslw((__v4su)a, lshift);
+ result = vec_sel(shmask, result, shmask);
+
+ return (__m128i)result;
+}
+
+Y_FORCE_INLINE __m128i _mm_sll_epi64(__m128i a, __m128i count) {
+ __v2du lshift, shmask;
+ const __v2du shmax = {64, 64};
+ __v2du result;
+
+ lshift = (__v2du)vec_splat((__v2du)count, 0);
+ shmask = vec_cmplt(lshift, shmax);
+ result = vec_sl((__v2du)a, lshift);
+ result = ((vector long long)shmask & ~(vector long long)shmask) | ((vector long long)result & (vector long long)shmask);
+
+ return (__m128i)result;
+}
+
+Y_FORCE_INLINE __m128i _mm_srl_epi16(__m128i a, __m128i count) {
+ __v8hu rshift, shmask;
+ const __v8hu shmax = {15, 15, 15, 15, 15, 15, 15, 15};
+ __v8hu result;
+
+#ifdef __LITTLE_ENDIAN__
+ rshift = vec_splat((__v8hu)count, 0);
+#elif __BIG_ENDIAN__
+ rshift = vec_splat((__v8hu)count, 3);
+#endif
+ shmask = vec_cmple(rshift, shmax);
+ result = vec_vsrh((__v8hu)a, rshift);
+ result = vec_sel(shmask, result, shmask);
+
+ return (__m128i)result;
+}
+
+Y_FORCE_INLINE __m128i _mm_srl_epi32(__m128i a, __m128i count) {
+ __v4su rshift, shmask;
+ const __v4su shmax = {32, 32, 32, 32};
+ __v4su result;
+
+#ifdef __LITTLE_ENDIAN__
+ rshift = vec_splat((__v4su)count, 0);
+#elif __BIG_ENDIAN__
+ rshift = vec_splat((__v4su)count, 1);
+#endif
+ shmask = vec_cmplt(rshift, shmax);
+ result = vec_vsrw((__v4su)a, rshift);
+ result = vec_sel(shmask, result, shmask);
+
+ return (__m128i)result;
+}
+
+Y_FORCE_INLINE __m128i _mm_srl_epi64(__m128i a, __m128i count) {
+ __v2du rshift, shmask;
+ const __v2du shmax = {64, 64};
+ __v2du result;
+
+ rshift = (__v2du)vec_splat((__v2du)count, 0);
+ shmask = vec_cmplt(rshift, shmax);
+ result = vec_sr((__v2du)a, rshift);
+ result = (__v2du)vec_sel((__v2du)shmask, (__v2du)result, (__v2du)shmask);
+
+ return (__m128i)result;
+}
+
+Y_FORCE_INLINE void _mm_storeu_si128(__m128i* p, __m128i a) {
+ vec_vsx_st(a, 0, p);
+}
+
+Y_FORCE_INLINE void _mm_store_si128(__m128i* p, __m128i a) {
+ vec_st((__v16qu)a, 0, (__v16qu*)p);
+}
+
+Y_FORCE_INLINE __m128i _mm_unpackhi_epi8(__m128i a, __m128i b) {
+ return (__m128i)vec_mergel((__v16qu)a, (__v16qu)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_unpackhi_epi16(__m128i a, __m128i b) {
+ return (__m128i)vec_mergel((__v8hu)a, (__v8hu)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_unpackhi_epi32(__m128i a, __m128i b) {
+ return (__m128i)vec_mergel((__v4su)a, (__v4su)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_unpackhi_epi64(__m128i a, __m128i b) {
+ return (__m128i)vec_mergel((vector long long)a, (vector long long)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_unpacklo_epi8(__m128i a, __m128i b) {
+ return (__m128i)vec_mergeh((__v16qu)a, (__v16qu)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_unpacklo_epi16(__m128i a, __m128i b) {
+ return (__m128i)vec_mergeh((__v8hi)a, (__v8hi)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_unpacklo_epi32(__m128i a, __m128i b) {
+ return (__m128i)vec_mergeh((__v4si)a, (__v4si)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_unpacklo_epi64(__m128i a, __m128i b) {
+ return (__m128i)vec_mergeh((vector long long)a, (vector long long)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_add_epi8(__m128i a, __m128i b) {
+ return (__m128i)((__v16qu)a + (__v16qu)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_add_epi16(__m128i a, __m128i b) {
+ return (__m128i)((__v8hu)a + (__v8hu)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_add_epi32(__m128i a, __m128i b) {
+ return (__m128i)((__v4su)a + (__v4su)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_add_epi64(__m128i a, __m128i b) {
+ return (__m128i)((__v2du)a + (__v2du)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_madd_epi16(__m128i a, __m128i b) {
+ const vector signed int zero = {0, 0, 0, 0};
+ return (__m128i)vec_vmsumshm((__v8hi)a, (__v8hi)b, zero);
+}
+
+Y_FORCE_INLINE __m128i _mm_sub_epi8(__m128i a, __m128i b) {
+ return (__m128i)((__v16qu)a - (__v16qu)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_sub_epi16(__m128i a, __m128i b) {
+ return (__m128i)((__v8hu)a - (__v8hu)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_sub_epi32(__m128i a, __m128i b) {
+ return (__m128i)((__v4su)a - (__v4su)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_sub_epi64(__m128i a, __m128i b) {
+ return (__m128i)((__v2du)a - (__v2du)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_mul_epu32(__m128i a, __m128 b) {
+#ifdef __LITTLE_ENDIAN__
+ return (__m128i)vec_mule((__v4su)a, (__v4su)b);
+#elif __BIG_ENDIAN__
+ return (__m128i)vec_mulo((__v4su)a, (__v4su)b);
+#endif
+}
+
+Y_FORCE_INLINE __m128i _mm_set_epi8(char q15, char q14, char q13, char q12, char q11, char q10, char q09, char q08, char q07, char q06, char q05, char q04, char q03, char q02, char q01, char q00) {
+ return (__m128i)(__v16qi){q00, q01, q02, q03, q04, q05, q06, q07, q08, q09, q10, q11, q12, q13, q14, q15};
+};
+
+Y_FORCE_INLINE __m128i _mm_setr_epi8(char q15, char q14, char q13, char q12, char q11, char q10, char q09, char q08, char q07, char q06, char q05, char q04, char q03, char q02, char q01, char q00) {
+ return (__m128i)(__v16qi){q15, q14, q13, q12, q11, q10, q09, q08, q07, q06, q05, q04, q03, q02, q01, q00};
+};
+
+Y_FORCE_INLINE __m128i _mm_set_epi16(short q7, short q6, short q5, short q4, short q3, short q2, short q1, short q0) {
+ return (__m128i)(__v8hi){q0, q1, q2, q3, q4, q5, q6, q7};
+}
+
+Y_FORCE_INLINE __m128i _mm_setr_epi16(short q7, short q6, short q5, short q4, short q3, short q2, short q1, short q0) {
+ return (__m128i)(__v8hi){q7, q6, q5, q4, q3, q2, q1, q0};
+}
+
+Y_FORCE_INLINE __m128i _mm_set_epi32(int q3, int q2, int q1, int q0) {
+ return (__m128i)(__v4si){q0, q1, q2, q3};
+}
+
+Y_FORCE_INLINE __m128i _mm_setr_epi32(int q3, int q2, int q1, int q0) {
+ return (__m128i)(__v4si){q3, q2, q1, q0};
+}
+
+Y_FORCE_INLINE __m128i _mm_set1_epi8(char a) {
+ return _mm_set_epi8(a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a);
+}
+
+Y_FORCE_INLINE __m128i _mm_set1_epi16(short a) {
+ return _mm_set_epi16(a, a, a, a, a, a, a, a);
+}
+
+Y_FORCE_INLINE __m128i _mm_set1_epi32(int a) {
+ return _mm_set_epi32(a, a, a, a);
+}
+
+Y_FORCE_INLINE __m128i _mm_cmpeq_epi8(__m128i a, __m128i b) {
+ return (__m128i)vec_cmpeq((__v16qi)a, (__v16qi)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_cmpeq_epi16(__m128i a, __m128i b) {
+ return (__m128i)vec_cmpeq((__v8hi)a, (__v8hi)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_cmpeq_epi32(__m128i a, __m128i b) {
+ return (__m128i)vec_cmpeq((__v4si)a, (__v4si)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_packs_epi16(__m128i a, __m128i b) {
+ return (__m128i)vec_packs((__v8hi)a, (__v8hi)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_packs_epi32(__m128i a, __m128i b) {
+ return (__m128i)vec_packs((__v4si)a, (__v4si)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_packus_epi16(__m128i a, __m128i b) {
+ return (__m128i)vec_packsu((vector signed short)a, (vector signed short)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_cvtsi64_si128(i64 a) {
+ return (__m128i)(__v2di){a, 0LL};
+}
+
+Y_FORCE_INLINE __m128i _mm_cvtsi32_si128(int a) {
+ return _mm_set_epi32(0, 0, 0, a);
+}
+
+Y_FORCE_INLINE int _mm_cvtsi128_si32(__m128i a) {
+ return ((__v4si)a)[0];
+}
+
+Y_FORCE_INLINE i64 _mm_cvtsi128_si64(__m128i a) {
+ return ((__v2di)a)[0];
+}
+
+Y_FORCE_INLINE __m128i _mm_load_si128(const __m128i* p) {
+ return *p;
+}
+
+Y_FORCE_INLINE __m128i _mm_loadu_si128(const __m128i* p) {
+ return (__m128i)(vec_vsx_ld(0, (signed int const*)p));
+}
+
+Y_FORCE_INLINE __m128i _mm_lddqu_si128(const __m128i* p) {
+ return _mm_loadu_si128(p);
+}
+
+Y_FORCE_INLINE __m128i _mm_loadl_epi64(const __m128i* a) {
+#ifdef __LITTLE_ENDIAN__
+ const vector bool long long mask = {
+ 0xFFFFFFFFFFFFFFFFull, 0x0000000000000000ull};
+#elif __BIG_ENDIAN__
+ const vector bool long long mask = {
+ 0x0000000000000000ull, 0xFFFFFFFFFFFFFFFFull};
+#endif
+ return (__m128i)vec_and(_mm_loadu_si128(a), (vector unsigned char)mask);
+}
+
+Y_FORCE_INLINE void _mm_storel_epi64(__m128i* a, __m128i b) {
+ *(long long*)a = ((__v2di)b)[0];
+}
+
+Y_FORCE_INLINE double _mm_cvtsd_f64(__m128d a) {
+ return ((__v2df)a)[0];
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wuninitialized"
+Y_FORCE_INLINE __m128d _mm_undefined_pd(void) {
+ __m128d ans = ans;
+ return ans;
+}
+#pragma GCC diagnostic pop
+
+Y_FORCE_INLINE __m128d _mm_loadh_pd(__m128d a, const double* b) {
+ __v2df result = (__v2df)a;
+ result[1] = *b;
+ return (__m128d)result;
+}
+
+Y_FORCE_INLINE __m128d _mm_loadl_pd(__m128d a, const double* b) {
+ __v2df result = (__v2df)a;
+ result[0] = *b;
+ return (__m128d)result;
+}
+
+Y_FORCE_INLINE __m128 _mm_castsi128_ps(__m128i a) {
+ return (__m128)a;
+}
+
+Y_FORCE_INLINE __m128i _mm_castps_si128(__m128 a) {
+ return (__m128i)a;
+}
+
+Y_FORCE_INLINE __m128i _mm_cmpgt_epi8(__m128i a, __m128i b) {
+ return (__m128i)vec_cmpgt((__v16qi)a, (__v16qi)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_cmpgt_epi16(__m128i a, __m128i b) {
+ return (__m128i)vec_cmpgt((__v8hi)a, (__v8hi)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_cmpgt_epi32(__m128i a, __m128i b) {
+ return (__m128i)vec_cmpgt((__v4si)a, (__v4si)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_cmpgt_epi64(__m128i a, __m128i b) {
+ return vec_cmpgt((vector signed long long)a, (vector signed long long)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_cmplt_epi8(__m128i a, __m128i b) {
+ return (__m128i)vec_cmplt((__v16qi)a, (__v16qi)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_cmplt_epi16(__m128i a, __m128i b) {
+ return (__m128i)vec_cmplt((__v8hi)a, (__v8hi)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_cmplt_epi32(__m128i a, __m128i b) {
+ return (__m128i)vec_cmplt((__v4si)a, (__v4si)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_cmplt_epi64(__m128i a, __m128i b) {
+ return vec_cmplt((vector signed long long)a, (vector signed long long)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_sad_epu8(__m128i A, __m128i B) {
+ __v16qu a, b;
+ __v16qu vmin, vmax, vabsdiff;
+ __v4si vsum;
+ const __v4su zero = {0, 0, 0, 0};
+ __v4si result;
+
+ a = (__v16qu)A;
+ b = (__v16qu)B;
+ vmin = vec_min(a, b);
+ vmax = vec_max(a, b);
+ vabsdiff = vec_sub(vmax, vmin);
+ /* Sum four groups of bytes into integers. */
+ vsum = (__vector signed int)vec_sum4s(vabsdiff, zero);
+ /* Sum across four integers with two integer results. */
+ result = vec_sum2s(vsum, (__vector signed int)zero);
+ /* Rotate the sums into the correct position. */
+#ifdef __LITTLE_ENDIAN__
+ result = vec_sld(result, result, 4);
+#elif __BIG_ENDIAN__
+ result = vec_sld(result, result, 6);
+#endif
+ /* Rotate the sums into the correct position. */
+ return (__m128i)result;
+}
+
+Y_FORCE_INLINE __m128i _mm_subs_epi8(__m128i a, __m128i b) {
+ return (__m128i)vec_subs((__v16qi)a, (__v16qi)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_subs_epi16(__m128i a, __m128i b) {
+ return (__m128i)vec_subs((__v8hi)a, (__v8hi)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_subs_epu8(__m128i a, __m128i b) {
+ return (__m128i)vec_subs((__v16qu)a, (__v16qu)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_subs_epu16(__m128i a, __m128i b) {
+ return (__m128i)vec_subs((__v8hu)a, (__v8hu)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_adds_epi8(__m128i a, __m128i b) {
+ return (__m128i)vec_adds((__v16qi)a, (__v16qi)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_adds_epi16(__m128i a, __m128i b) {
+ return (__m128i)vec_adds((__v8hi)a, (__v8hi)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_adds_epu8(__m128i a, __m128i b) {
+ return (__m128i)vec_adds((__v16qu)a, (__v16qu)b);
+}
+
+Y_FORCE_INLINE __m128i _mm_adds_epu16(__m128i a, __m128i b) {
+ return (__m128i)vec_adds((__v8hu)a, (__v8hu)b);
+}
+
+Y_FORCE_INLINE __m128d _mm_castsi128_pd(__m128i a) {
+ return (__m128d)a;
+}
+
+Y_FORCE_INLINE void _mm_prefetch(const void *p, enum _mm_hint) {
+ __builtin_prefetch(p);
+}
+
+Y_FORCE_INLINE __m128i _mm_hadd_epi16(__m128i a, __m128i b) {
+ const __v16qu p = { 0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29 };
+ const __v16qu q = { 2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31 };
+ __v8hi c = vec_perm((__v8hi)a, (__v8hi)b, p);
+ __v8hi d = vec_perm((__v8hi)a, (__v8hi)b, q);
+ return (__m128i)vec_add(c, d);
+}
diff --git a/library/cpp/sse/sse.cpp b/library/cpp/sse/sse.cpp
new file mode 100644
index 0000000000..d0d1de9930
--- /dev/null
+++ b/library/cpp/sse/sse.cpp
@@ -0,0 +1 @@
+#include "sse.h"
diff --git a/library/cpp/sse/sse.h b/library/cpp/sse/sse.h
new file mode 100644
index 0000000000..19bac17de0
--- /dev/null
+++ b/library/cpp/sse/sse.h
@@ -0,0 +1,33 @@
+#pragma once
+
+/*
+ The header chooses appropriate SSE support.
+ On Intel: SSE intrinsics
+ On ARM64: translation to NEON intrinsics or software emulation
+ On PowerPc: translation to Altivec intrinsics or software emulation
+*/
+/* Author: Vitaliy Manushkin <agri@yandex-team.ru>, Danila Kutenin <danlark@yandex-team.ru> */
+
+#include <util/system/platform.h>
+
+#if (defined(_i386_) || defined(_x86_64_)) && defined(_sse_)
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <pmmintrin.h>
+#define ARCADIA_SSE
+#if defined(_ssse3_)
+#include <tmmintrin.h>
+#endif
+#if defined(_sse4_1_)
+#include <smmintrin.h>
+#endif
+#if defined(_sse4_2_)
+#include <nmmintrin.h>
+#endif
+#elif defined(_arm64_)
+#include "sse2neon.h"
+#define ARCADIA_SSE
+#elif defined(_ppc64_)
+#include "powerpc.h"
+#define ARCADIA_SSE
+#endif
diff --git a/library/cpp/sse/sse2neon.h b/library/cpp/sse/sse2neon.h
new file mode 100644
index 0000000000..695dbd3041
--- /dev/null
+++ b/library/cpp/sse/sse2neon.h
@@ -0,0 +1,1045 @@
+#pragma once
+
+/*
+ The header contains inlining code
+ which translates SSE intrinsics to NEON intrinsics or software emulation.
+ You are encouraged for commitments.
+ Add missing intrinsics, add unittests, purify the implementation,
+ merge and simplify templates.
+ Warning: The code is made in deep nights, so it surely contains bugs,
+ imperfections, flaws and all other kinds of errors and mistakes.
+*/
+/* Author: Vitaliy Manushkin <agri@yandex-team.ru> */
+
+#include <util/system/platform.h>
+#include <util/system/compiler.h>
+#include <util/system/types.h>
+
+#if !defined(_arm64_)
+#error "This header is for ARM64 (aarch64) platform only. " \
+ "Include sse.h instead of including this header directly."
+#endif
+
+#include <arm_neon.h>
+
+union __m128i {
+ uint64x2_t AsUi64x2;
+ int64x2_t AsSi64x2;
+
+ uint32x4_t AsUi32x4;
+ int32x4_t AsSi32x4;
+
+ uint16x8_t AsUi16x8;
+ int16x8_t AsSi16x8;
+
+ uint8x16_t AsUi8x16;
+ int8x16_t AsSi8x16;
+
+ float32x4_t AsFloat32x4;
+ float64x2_t AsFloat64x2;
+};
+
+union __m128 {
+ float32x4_t AsFloat32x4;
+ float64x2_t AsFloat64x2;
+
+ uint32x4_t AsUi32x4;
+ int32x4_t AsSi32x4;
+
+ uint64x2_t AsUi64x2;
+ int64x2_t AsSi64x2;
+
+ uint8x16_t AsUi8x16;
+ int8x16_t AsSi8x16;
+
+ __m128i As128i;
+};
+
+typedef float64x2_t __m128d;
+
+enum _mm_hint
+{
+ /* _MM_HINT_ET is _MM_HINT_T with set 3rd bit. */
+ _MM_HINT_ET0 = 7,
+ _MM_HINT_ET1 = 6,
+ _MM_HINT_T0 = 3,
+ _MM_HINT_T1 = 2,
+ _MM_HINT_T2 = 1,
+ _MM_HINT_NTA = 0
+};
+
+Y_FORCE_INLINE void _mm_prefetch(const void *p, enum _mm_hint) {
+ __builtin_prefetch(p);
+}
+
+template <typename TType>
+struct TQType;
+
+template <>
+struct TQType<uint8x16_t> {
+ static inline uint8x16_t& As(__m128i& value) {
+ return value.AsUi8x16;
+ }
+ static inline const uint8x16_t& As(const __m128i& value) {
+ return value.AsUi8x16;
+ }
+};
+
+template <>
+struct TQType<int8x16_t> {
+ static inline int8x16_t& As(__m128i& value) {
+ return value.AsSi8x16;
+ }
+ static inline const int8x16_t& As(const __m128i& value) {
+ return value.AsSi8x16;
+ }
+};
+
+template <>
+struct TQType<uint16x8_t> {
+ static inline uint16x8_t& As(__m128i& value) {
+ return value.AsUi16x8;
+ }
+ static inline const uint16x8_t& As(const __m128i& value) {
+ return value.AsUi16x8;
+ }
+};
+
+template <>
+struct TQType<int16x8_t> {
+ static inline int16x8_t& As(__m128i& value) {
+ return value.AsSi16x8;
+ }
+ static inline const int16x8_t& As(const __m128i& value) {
+ return value.AsSi16x8;
+ }
+};
+
+template <>
+struct TQType<uint32x4_t> {
+ static inline uint32x4_t& As(__m128i& value) {
+ return value.AsUi32x4;
+ }
+ static inline const uint32x4_t& As(const __m128i& value) {
+ return value.AsUi32x4;
+ }
+};
+
+template <>
+struct TQType<int32x4_t> {
+ static inline int32x4_t& As(__m128i& value) {
+ return value.AsSi32x4;
+ }
+ static inline const int32x4_t& As(const __m128i& value) {
+ return value.AsSi32x4;
+ }
+};
+
+template <>
+struct TQType<uint64x2_t> {
+ static inline uint64x2_t& As(__m128i& value) {
+ return value.AsUi64x2;
+ }
+ static inline const uint64x2_t& As(const __m128i& value) {
+ return value.AsUi64x2;
+ }
+ static inline uint64x2_t& As(__m128& value) {
+ return value.AsUi64x2;
+ }
+ static inline const uint64x2_t& As(const __m128& value) {
+ return value.AsUi64x2;
+ }
+};
+
+template <>
+struct TQType<int64x2_t> {
+ static inline int64x2_t& As(__m128i& value) {
+ return value.AsSi64x2;
+ }
+ static inline const int64x2_t& As(const __m128i& value) {
+ return value.AsSi64x2;
+ }
+};
+
+template <typename TValue>
+struct TBaseWrapper {
+ TValue Value;
+
+ Y_FORCE_INLINE
+ operator TValue&() {
+ return Value;
+ }
+
+ Y_FORCE_INLINE
+ operator const TValue&() const {
+ return Value;
+ }
+};
+
+template <typename TOp, typename TFunc, TFunc* func,
+ typename TDup, TDup* dupfunc>
+struct TWrapperSingleDup: public TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ TWrapperSingleDup(const __m128i& op, const int shift) {
+ TQType<TOp>::As(Value) = func(TQType<TOp>::As(op), dupfunc(shift));
+ }
+};
+
+template <typename TOp, typename TFunc, TFunc* func,
+ typename TDup, TDup* dupfunc>
+struct TWrapperSingleNegDup: public TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ TWrapperSingleNegDup(const __m128i& op, const int shift) {
+ TQType<TOp>::As(Value) = func(TQType<TOp>::As(op), dupfunc(-shift));
+ }
+};
+
+inline __m128i _mm_srl_epi16(__m128i a, __m128i count) {
+ __m128i res;
+ res.AsUi16x8 = vshlq_u16(a.AsUi16x8, vdupq_n_s16(-count.AsUi16x8[0]));
+ return res;
+}
+
+
+inline __m128i _mm_srl_epi32(__m128i a, __m128i count) {
+ __m128i res;
+ res.AsUi32x4 = vshlq_u32(a.AsUi32x4, vdupq_n_s32(-count.AsUi32x4[0]));
+ return res;
+}
+
+inline __m128i _mm_srl_epi64(__m128i a, __m128i count) {
+ __m128i res;
+ res.AsUi64x2 = vshlq_u64(a.AsUi64x2, vdupq_n_s64(-count.AsUi64x2[0]));
+ return res;
+}
+
+inline __m128i _mm_srai_epi16(__m128i a, int count) {
+ __m128i res;
+ res.AsSi16x8 = vqshlq_s16(a.AsSi16x8, vdupq_n_s16(-count));
+ return res;
+}
+
+inline __m128i _mm_srai_epi32(__m128i a, int count) {
+ __m128i res;
+ res.AsSi32x4 = vqshlq_s32(a.AsSi32x4, vdupq_n_s32(-count));
+ return res;
+}
+
+using _mm_srli_epi16 =
+ TWrapperSingleNegDup<uint16x8_t, decltype(vshlq_u16), vshlq_u16,
+ decltype(vdupq_n_s16), vdupq_n_s16>;
+using _mm_srli_epi32 =
+ TWrapperSingleNegDup<uint32x4_t, decltype(vshlq_u32), vshlq_u32,
+ decltype(vdupq_n_s32), vdupq_n_s32>;
+using _mm_srli_epi64 =
+ TWrapperSingleNegDup<uint64x2_t, decltype(vshlq_u64), vshlq_u64,
+ decltype(vdupq_n_s64), vdupq_n_s64>;
+
+
+inline __m128i _mm_sll_epi16(__m128i a, __m128i count) {
+ __m128i res;
+ res.AsUi16x8 = vshlq_u16(a.AsUi16x8, vdupq_n_s16(count.AsUi16x8[0]));
+ return res;
+}
+
+
+inline __m128i _mm_sll_epi32(__m128i a, __m128i count) {
+ __m128i res;
+ res.AsUi32x4 = vshlq_u32(a.AsUi32x4, vdupq_n_s32(count.AsUi32x4[0]));
+ return res;
+}
+
+inline __m128i _mm_sll_epi64(__m128i a, __m128i count) {
+ __m128i res;
+ res.AsUi64x2 = vshlq_u64(a.AsUi64x2, vdupq_n_s64(count.AsUi64x2[0]));
+ return res;
+}
+
+using _mm_slli_epi16 =
+ TWrapperSingleDup<uint16x8_t, decltype(vshlq_u16), vshlq_u16,
+ decltype(vdupq_n_s16), vdupq_n_s16>;
+using _mm_slli_epi32 =
+ TWrapperSingleDup<uint32x4_t, decltype(vshlq_u32), vshlq_u32,
+ decltype(vdupq_n_s32), vdupq_n_s32>;
+using _mm_slli_epi64 =
+ TWrapperSingleDup<uint64x2_t, decltype(vshlq_u64), vshlq_u64,
+ decltype(vdupq_n_s64), vdupq_n_s64>;
+
+template <typename TOp, typename TFunc, TFunc* func, typename... TParams>
+struct TWrapperDual : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ TWrapperDual(const __m128i& op1, const __m128i& op2, TParams... params) {
+ TQType<TOp>::As(Value) = (TOp)
+ func(TQType<TOp>::As(op1),
+ TQType<TOp>::As(op2),
+ params...);
+ }
+};
+
+template <typename TOp, typename TFunc, TFunc* func, typename... TParams>
+struct TWrapperDualSwap : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ TWrapperDualSwap(const __m128i& op1, const __m128i& op2, TParams... params) {
+ TQType<TOp>::As(Value) =
+ func(TQType<TOp>::As(op2),
+ TQType<TOp>::As(op1),
+ params...);
+ }
+};
+
+template <typename TOp, typename TFunc, TFunc* func, typename TArgument = __m128>
+struct TWrapperDualF : TBaseWrapper<TArgument> {
+ Y_FORCE_INLINE
+ TWrapperDualF(const TArgument& op1, const TArgument& op2) {
+ TQType<TOp>::As(TBaseWrapper<TArgument>::Value) = (TOp) func(TQType<TOp>::As(op1), TQType<TOp>::As(op2));
+ }
+};
+
+using _mm_or_si128 = TWrapperDual<uint64x2_t, decltype(vorrq_u64), vorrq_u64>;
+using _mm_and_si128 = TWrapperDual<uint64x2_t, decltype(vandq_u64), vandq_u64>;
+using _mm_andnot_si128 =
+ TWrapperDualSwap<uint64x2_t, decltype(vbicq_u64), vbicq_u64>;
+using _mm_xor_si128 = TWrapperDual<uint64x2_t, decltype(veorq_u64), veorq_u64>;
+
+using _mm_add_epi8 = TWrapperDual<uint8x16_t, decltype(vaddq_u8), vaddq_u8>;
+using _mm_add_epi16 = TWrapperDual<uint16x8_t, decltype(vaddq_u16), vaddq_u16>;
+using _mm_add_epi32 = TWrapperDual<uint32x4_t, decltype(vaddq_u32), vaddq_u32>;
+using _mm_add_epi64 = TWrapperDual<uint64x2_t, decltype(vaddq_u64), vaddq_u64>;
+
+inline __m128i _mm_madd_epi16(__m128i a, __m128i b) {
+ int32x4_t aLow;
+ int32x4_t aHigh;
+ int32x4_t bLow;
+ int32x4_t bHigh;
+ #ifdef __LITTLE_ENDIAN__
+ aLow[0] = a.AsSi16x8[0]; //!< I couldn't find vector instructions to do that. Feel free to fix this code.
+ aLow[1] = a.AsSi16x8[2];
+ aLow[2] = a.AsSi16x8[4];
+ aLow[3] = a.AsSi16x8[6];
+
+ aHigh[0] = a.AsSi16x8[1];
+ aHigh[1] = a.AsSi16x8[3];
+ aHigh[2] = a.AsSi16x8[5];
+ aHigh[3] = a.AsSi16x8[7];
+
+ bLow[0] = b.AsSi16x8[0];
+ bLow[1] = b.AsSi16x8[2];
+ bLow[2] = b.AsSi16x8[4];
+ bLow[3] = b.AsSi16x8[6];
+
+ bHigh[0] = b.AsSi16x8[1];
+ bHigh[1] = b.AsSi16x8[3];
+ bHigh[2] = b.AsSi16x8[5];
+ bHigh[3] = b.AsSi16x8[7];
+ #else
+ #error Not implemented yet. Do it yourself.
+ #endif
+
+ const int32x4_t lowMul = vmulq_u32(aLow, bLow);
+ const int32x4_t highMul = vmulq_u32(aHigh, bHigh);
+ __m128i res;
+ res.AsSi32x4 = vaddq_u32(lowMul, highMul);
+ return res;
+}
+
+using _mm_sub_epi8 = TWrapperDual<uint8x16_t, decltype(vsubq_u8), vsubq_u8>;
+using _mm_sub_epi16 = TWrapperDual<uint16x8_t, decltype(vsubq_u16), vsubq_u16>;
+using _mm_sub_epi32 = TWrapperDual<uint32x4_t, decltype(vsubq_u32), vsubq_u32>;
+using _mm_sub_epi64 = TWrapperDual<uint64x2_t, decltype(vsubq_u64), vsubq_u64>;
+
+using _mm_unpacklo_epi8 =
+ TWrapperDual<uint8x16_t, decltype(vzip1q_u8), vzip1q_u8>;
+using _mm_unpackhi_epi8 =
+ TWrapperDual<uint8x16_t, decltype(vzip2q_u8), vzip2q_u8>;
+using _mm_unpacklo_epi16 =
+ TWrapperDual<uint16x8_t, decltype(vzip1q_u16), vzip1q_u16>;
+using _mm_unpackhi_epi16 =
+ TWrapperDual<uint16x8_t, decltype(vzip2q_u16), vzip2q_u16>;
+using _mm_unpacklo_epi32 =
+ TWrapperDual<uint32x4_t, decltype(vzip1q_u32), vzip1q_u32>;
+using _mm_unpackhi_epi32 =
+ TWrapperDual<uint32x4_t, decltype(vzip2q_u32), vzip2q_u32>;
+using _mm_unpacklo_epi64 =
+ TWrapperDual<uint64x2_t, decltype(vzip1q_u64), vzip1q_u64>;
+using _mm_unpackhi_epi64 =
+ TWrapperDual<uint64x2_t, decltype(vzip2q_u64), vzip2q_u64>;
+
+using _mm_cmpeq_epi8 =
+ TWrapperDual<uint8x16_t, decltype(vceqq_u8), vceqq_u8>;
+using _mm_cmpeq_epi16 =
+ TWrapperDual<uint16x8_t, decltype(vceqq_u16), vceqq_u16>;
+using _mm_cmpeq_epi32 =
+ TWrapperDual<uint32x4_t, decltype(vceqq_u32), vceqq_u32>;
+
+using _mm_cmpgt_epi8 =
+ TWrapperDual<int8x16_t, decltype(vcgtq_s8), vcgtq_s8>;
+using _mm_cmpgt_epi16 =
+ TWrapperDual<int16x8_t, decltype(vcgtq_s16), vcgtq_s16>;
+using _mm_cmpgt_epi32 =
+ TWrapperDual<int32x4_t, decltype(vcgtq_s32), vcgtq_s32>;
+
+using _mm_cmplt_epi8 =
+ TWrapperDual<int8x16_t, decltype(vcltq_s8), vcltq_s8>;
+using _mm_cmplt_epi16 =
+ TWrapperDual<int16x8_t, decltype(vcltq_s16), vcltq_s16>;
+using _mm_cmplt_epi32 =
+ TWrapperDual<int32x4_t, decltype(vcltq_s32), vcltq_s32>;
+
+Y_FORCE_INLINE __m128i _mm_load_si128(const __m128i* ptr) {
+ __m128i result;
+ result.AsUi64x2 = vld1q_u64((const uint64_t*)ptr);
+ return result;
+}
+
+Y_FORCE_INLINE __m128i _mm_loadu_si128(const __m128i* ptr) {
+ __m128i result;
+ result.AsUi64x2 = vld1q_u64((const uint64_t*)ptr);
+ return result;
+}
+
+Y_FORCE_INLINE __m128i _mm_lddqu_si128(const __m128i* ptr) {
+ return _mm_loadu_si128(ptr);
+}
+
+Y_FORCE_INLINE void _mm_storeu_si128(__m128i* ptr, const __m128i& op) {
+ vst1q_u64((uint64_t*)ptr, op.AsUi64x2);
+}
+
+Y_FORCE_INLINE void
+_mm_store_si128(__m128i* ptr, const __m128i& op) {
+ vst1q_u64((uint64_t*)ptr, op.AsUi64x2);
+}
+
+template <typename TOp, typename TFunc, TFunc* func, typename... TParams>
+struct TWrapperSimple : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ TWrapperSimple(TParams... params) {
+ TQType<TOp>::As(Value) = func(params...);
+ }
+};
+
+template <typename TOp, typename TFunc, TFunc* func, typename... TParams>
+struct TWrapperSimpleF : TBaseWrapper<__m128> {
+ Y_FORCE_INLINE
+ TWrapperSimpleF(TParams... params) {
+ TQType<TOp>::As(Value) = func(params...);
+ }
+};
+
+using _mm_set1_epi8 =
+ TWrapperSimple<int8x16_t, decltype(vdupq_n_s8), vdupq_n_s8, const char>;
+using _mm_set1_epi16 =
+ TWrapperSimple<int16x8_t, decltype(vdupq_n_s16), vdupq_n_s16, const ui16>;
+using _mm_set1_epi32 =
+ TWrapperSimple<int32x4_t, decltype(vdupq_n_s32), vdupq_n_s32, const ui32>;
+
+struct _mm_setzero_si128 : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ _mm_setzero_si128() {
+ TQType<uint64x2_t>::As(Value) = vdupq_n_u64(0);
+ }
+};
+
+struct _mm_loadl_epi64 : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ _mm_loadl_epi64(const __m128i* p) {
+ uint64x1_t im = vld1_u64((const uint64_t*)p);
+ TQType<uint64x2_t>::As(Value) = vcombine_u64(im, vdup_n_u64(0));
+ }
+};
+
+struct _mm_storel_epi64 : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ _mm_storel_epi64(__m128i* a, __m128i op) {
+ vst1_u64((uint64_t*)a, vget_low_u64(op.AsUi64x2));
+ }
+};
+
+struct ShuffleStruct4 {
+ ui8 x[4];
+};
+
+Y_FORCE_INLINE ShuffleStruct4
+_MM_SHUFFLE(ui8 x4, ui8 x3, ui8 x2, ui8 x1) {
+ ShuffleStruct4 result;
+ result.x[0] = x1;
+ result.x[1] = x2;
+ result.x[2] = x3;
+ result.x[3] = x4;
+ return result;
+}
+
+Y_FORCE_INLINE __m128i
+_mm_shuffle_epi32(const __m128i& op1, const ShuffleStruct4& op2) {
+ __m128i result;
+ const ui8 xi[4] = {
+ ui8(op2.x[0] * 4), ui8(op2.x[1] * 4),
+ ui8(op2.x[2] * 4), ui8(op2.x[3] * 4)
+ };
+ const uint8x16_t transform = {
+ ui8(xi[0]), ui8(xi[0] + 1), ui8(xi[0] + 2), ui8(xi[0] + 3),
+ ui8(xi[1]), ui8(xi[1] + 1), ui8(xi[1] + 2), ui8(xi[1] + 3),
+ ui8(xi[2]), ui8(xi[2] + 1), ui8(xi[2] + 2), ui8(xi[2] + 3),
+ ui8(xi[3]), ui8(xi[3] + 1), ui8(xi[3] + 2), ui8(xi[3] + 3)
+ };
+ result.AsUi8x16 = vqtbl1q_u8(op1.AsUi8x16, transform);
+ return result;
+}
+
+Y_FORCE_INLINE int
+_mm_movemask_epi8(const __m128i& op) {
+ uint8x16_t mask = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
+ uint8x16_t opmasked = vandq_u8(op.AsUi8x16, mask);
+ int8x16_t byteshifter = {
+ 0, -7, 0, -7, 0, -7, 0, -7, 0, -7, 0, -7, 0, -7, 0, -7};
+ uint8x16_t opshifted = vshlq_u8(opmasked, byteshifter);
+ int16x8_t wordshifter = {-7, -5, -3, -1, 1, 3, 5, 7};
+ uint16x8_t wordshifted =
+ vshlq_u16(vreinterpretq_u16_u8(opshifted), wordshifter);
+ return vaddvq_u16(wordshifted);
+}
+
+template <int imm>
+struct THelper_mm_srli_si128 : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ THelper_mm_srli_si128(const __m128i a) {
+ const auto zero = vdupq_n_u8(0);
+ TQType<uint8x16_t>::As(Value) = vextq_u8(a.AsUi8x16, zero, imm);
+ }
+};
+
+template <>
+struct THelper_mm_srli_si128<16> : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ THelper_mm_srli_si128(const __m128i /* a */) {
+ const auto zero = vdupq_n_u8(0);
+ TQType<uint8x16_t>::As(Value) = zero;
+ }
+};
+
+#define _mm_srli_si128(a, imm) THelper_mm_srli_si128<imm>(a)
+
+template<int imm>
+inline uint8x16_t vextq_u8_function(uint8x16_t a, uint8x16_t b) {
+ return vextq_u8(a, b, imm);
+}
+
+template<>
+inline uint8x16_t vextq_u8_function<16>(uint8x16_t /* a */, uint8x16_t b) {
+ return b;
+}
+
+
+template <int imm>
+struct THelper_mm_slli_si128 : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ THelper_mm_slli_si128(const __m128i a) {
+ auto zero = vdupq_n_u8(0);
+ TQType<uint8x16_t>::As(Value) = vextq_u8_function<16 - imm>(zero, a.AsUi8x16);
+ }
+};
+
+#define _mm_slli_si128(a, imm) THelper_mm_slli_si128<imm>(a)
+
+Y_FORCE_INLINE int _mm_cvtsi128_si32(const __m128i& op) {
+ return vgetq_lane_s32(op.AsSi32x4, 0);
+}
+
+struct _mm_set_epi16 : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ _mm_set_epi16(const short w7, const short w6,
+ const short w5, const short w4,
+ const short w3, const short w2,
+ const short w1, const short w0) {
+ int16x4_t d0 = {w0, w1, w2, w3};
+ int16x4_t d1 = {w4, w5, w6, w7};
+ TQType<int16x8_t>::As(Value) = vcombine_s16(d0, d1);
+ }
+};
+
+struct _mm_setr_epi16 : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ _mm_setr_epi16(const short w7, const short w6,
+ const short w5, const short w4,
+ const short w3, const short w2,
+ const short w1, const short w0) {
+ int16x4_t d0 = {w7, w6, w5, w4};
+ int16x4_t d1 = {w3, w2, w1, w0};
+ TQType<int16x8_t>::As(Value) = vcombine_s16(d0, d1);
+ }
+};
+
+struct _mm_set_epi32 : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ _mm_set_epi32(const int x3, const int x2,
+ const int x1, const int x0) {
+ int32x2_t d0 = {x0, x1};
+ int32x2_t d1 = {x2, x3};
+ TQType<int32x4_t>::As(Value) = vcombine_s32(d0, d1);
+ }
+};
+
+struct _mm_setr_epi32 : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ _mm_setr_epi32(const int x3, const int x2,
+ const int x1, const int x0) {
+ int32x2_t d0 = {x3, x2};
+ int32x2_t d1 = {x1, x0};
+ TQType<int32x4_t>::As(Value) = vcombine_s32(d0, d1);
+ }
+};
+
+struct _mm_cvtsi32_si128 : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ _mm_cvtsi32_si128(int op) {
+ auto zero = vdupq_n_s32(0);
+ TQType<int32x4_t>::As(Value) = vsetq_lane_s32(op, zero, 0);
+ }
+};
+
+struct _mm_cvtsi64_si128 : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ _mm_cvtsi64_si128(i64 op) {
+ auto zero = vdupq_n_s64(0);
+ TQType<int64x2_t>::As(Value) = vsetq_lane_s64(op, zero, 0);
+ }
+};
+
+template <typename TOpOut, typename TOpIn,
+ typename TFunc, TFunc* func,
+ typename TCombine, TCombine* combine>
+struct TCombineWrapper : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ TCombineWrapper(const __m128i op1, const __m128i op2) {
+ TQType<TOpOut>::As(Value) =
+ combine(func(TQType<TOpIn>::As(op1)),
+ func(TQType<TOpIn>::As(op2)));
+ }
+};
+
+using _mm_packs_epi16 =
+ TCombineWrapper<int8x16_t, int16x8_t,
+ decltype(vqmovn_s16), vqmovn_s16,
+ decltype(vcombine_s8), vcombine_s8>;
+using _mm_packs_epi32 =
+ TCombineWrapper<int16x8_t, int32x4_t,
+ decltype(vqmovn_s32), vqmovn_s32,
+ decltype(vcombine_s16), vcombine_s16>;
+using _mm_packus_epi16 =
+ TCombineWrapper<uint8x16_t, int16x8_t,
+ decltype(vqmovun_s16), vqmovun_s16,
+ decltype(vcombine_u8), vcombine_u8>;
+
+template <typename TOpOut, typename TOpIn,
+ typename TFunc, TFunc* func, typename... TParams>
+struct TScalarOutWrapper : TBaseWrapper<TOpOut> {
+ Y_FORCE_INLINE
+ TScalarOutWrapper(const __m128i op, TParams... params) {
+ TBaseWrapper<TOpOut>::Value =
+ func(TQType<TOpIn>::As(op), params...);
+ }
+};
+
+template<int imm>
+int extract_epi8_arm(__m128i arg) {
+ return vgetq_lane_u8(arg.AsUi8x16, imm);
+}
+
+template<int imm>
+int extract_epi16_arm(__m128i arg) {
+ return vgetq_lane_u16(arg.AsUi16x8, imm);
+}
+
+template<int imm>
+int extract_epi32_arm(__m128i arg) {
+ return vgetq_lane_s32(arg.AsSi32x4, imm);
+}
+
+template<int imm>
+long long extract_epi64_arm(__m128i arg) {
+ return vgetq_lane_s64(arg.AsSi64x2, imm);
+}
+
+#define _mm_extract_epi8(op, imm) extract_epi8_arm<imm>(op)
+#define _mm_extract_epi16(op, imm) extract_epi16_arm<imm>(op)
+#define _mm_extract_epi32(op, imm) extract_epi32_arm<imm>(op)
+#define _mm_extract_epi64(op, imm) extract_epi64_arm<imm>(op)
+#define _mm_extract_ps(op, imm) _mm_extract_epi32(op, imm)
+
+static Y_FORCE_INLINE
+__m128i _mm_mul_epu32(__m128i op1, __m128i op2) {
+ __m128i result;
+ uint32x4_t r1 = vuzp1q_u32(op1.AsUi32x4, op2.AsUi32x4);
+ uint32x4_t r2 = vuzp1q_u32(op2.AsUi32x4, op1.AsUi32x4);
+ result.AsUi64x2 = vmull_u32(vget_low_u32(r1), vget_low_u32(r2));
+ return result;
+}
+
+template <>
+struct TQType<float32x4_t> {
+ static inline float32x4_t& As(__m128& value) {
+ return value.AsFloat32x4;
+ }
+
+ static inline const float32x4_t& As(const __m128& value) {
+ return value.AsFloat32x4;
+ }
+
+ static inline float32x4_t& As(__m128i& value) {
+ return value.AsFloat32x4;
+ }
+
+ static inline const float32x4_t& As(const __m128i& value) {
+ return value.AsFloat32x4;
+ }
+};
+
+template <>
+struct TQType<float64x2_t> {
+ static inline float64x2_t& As(__m128& value) {
+ return value.AsFloat64x2;
+ }
+
+ static inline const float64x2_t& As(const __m128& value) {
+ return value.AsFloat64x2;
+ }
+
+ static inline float64x2_t& As(__m128i& value) {
+ return value.AsFloat64x2;
+ }
+
+ static inline const float64x2_t& As(const __m128i& value) {
+ return value.AsFloat64x2;
+ }
+
+ static inline float64x2_t& As(__m128d& value) {
+ return value;
+ }
+
+ static inline const float64x2_t& As(const __m128d& value) {
+ return value;
+ }
+};
+
+using _mm_set1_ps = TWrapperSimpleF<float32x4_t,
+ decltype(vdupq_n_f32), vdupq_n_f32, const float>;
+using _mm_set_ps1 = TWrapperSimpleF<float32x4_t,
+ decltype(vdupq_n_f32), vdupq_n_f32, const float>;
+
+struct _mm_setzero_ps : TBaseWrapper<__m128> {
+ Y_FORCE_INLINE
+ _mm_setzero_ps() {
+ TQType<float32x4_t>::As(Value) = vdupq_n_f32(0.);
+ }
+};
+
+Y_FORCE_INLINE __m128d _mm_setzero_pd() {
+ return vdupq_n_f64(0.);
+}
+
+Y_FORCE_INLINE __m128 _mm_loadu_ps(const float* ptr) {
+ __m128 result;
+ result.AsFloat32x4 = vld1q_f32(ptr);
+ return result;
+}
+
+Y_FORCE_INLINE __m128 _mm_load_ps(const float* ptr) {
+ __m128 result;
+ result.AsFloat32x4 = vld1q_f32(ptr);
+ return result;
+}
+
+Y_FORCE_INLINE void _mm_storeu_ps(float* ptr, const __m128& op) {
+ vst1q_f32(ptr, op.AsFloat32x4);
+}
+
+Y_FORCE_INLINE void _mm_store_ps(float* ptr, const __m128& op) {
+ vst1q_f32(ptr, op.AsFloat32x4);
+}
+
+struct _mm_set_ps : TBaseWrapper<__m128> {
+ Y_FORCE_INLINE
+ _mm_set_ps(const float x3, const float x2,
+ const float x1, const float x0) {
+ float32x2_t d0 = {x0, x1};
+ float32x2_t d1 = {x2, x3};
+ TQType<float32x4_t>::As(Value) = vcombine_f32(d0, d1);
+ }
+};
+
+Y_FORCE_INLINE __m128d _mm_set_pd(double d1, double d0) {
+ const float64x1_t p0 = {d0};
+ const float64x1_t p1 = {d1};
+ return vcombine_f64(p0, p1);
+}
+
+Y_FORCE_INLINE __m128d _mm_loadu_pd(const double* d) {
+ __m128d res;
+ res = vld1q_f64(d);
+ return res;
+}
+
+Y_FORCE_INLINE void _mm_storeu_pd(double* res, __m128d a) {
+ vst1q_f64(res, a);
+}
+
+Y_FORCE_INLINE void _mm_store_pd(double* res, __m128d a) {
+ vst1q_f64(res, a);
+}
+
+using _mm_add_ps = TWrapperDualF<float32x4_t, decltype(vaddq_f32), vaddq_f32>;
+using _mm_sub_ps = TWrapperDualF<float32x4_t, decltype(vsubq_f32), vsubq_f32>;
+using _mm_mul_ps = TWrapperDualF<float32x4_t, decltype(vmulq_f32), vmulq_f32>;
+using _mm_div_ps = TWrapperDualF<float32x4_t, decltype(vdivq_f32), vdivq_f32>;
+using _mm_cmpeq_ps = TWrapperDualF<float32x4_t, decltype(vceqq_f32), vceqq_f32>;
+using _mm_cmpgt_ps = TWrapperDualF<float32x4_t, decltype(vcgtq_f32), vcgtq_f32>;
+using _mm_max_ps = TWrapperDualF<float32x4_t, decltype(vmaxq_f32), vmaxq_f32>;
+using _mm_min_ps = TWrapperDualF<float32x4_t, decltype(vminq_f32), vminq_f32>;
+
+using _mm_add_pd = TWrapperDualF<float64x2_t, decltype(vaddq_f64), vaddq_f64, __m128d>;
+using _mm_sub_pd = TWrapperDualF<float64x2_t, decltype(vsubq_f64), vsubq_f64, __m128d>;
+using _mm_mul_pd = TWrapperDualF<float64x2_t, decltype(vmulq_f64), vmulq_f64, __m128d>;
+using _mm_div_pd = TWrapperDualF<float64x2_t, decltype(vdivq_f64), vdivq_f64, __m128d>;
+
+struct _mm_and_ps : TBaseWrapper<__m128> {
+ Y_FORCE_INLINE
+ _mm_and_ps(const __m128& op1, const __m128& op2) {
+ TQType<uint64x2_t>::As(Value) =
+ vandq_u64(TQType<uint64x2_t>::As(op1),
+ TQType<uint64x2_t>::As(op2));
+ }
+};
+
+Y_FORCE_INLINE __m128d _mm_and_pd(__m128d a, __m128d b) {
+ return vandq_u64(a, b);
+}
+
+Y_FORCE_INLINE void _MM_TRANSPOSE4_PS(__m128& op0, __m128& op1, __m128& op2, __m128& op3) {
+ float64x2_t im0 =
+ (float64x2_t)vtrn1q_f32(op0.AsFloat32x4, op1.AsFloat32x4);
+ float64x2_t im1 =
+ (float64x2_t)vtrn2q_f32(op0.AsFloat32x4, op1.AsFloat32x4);
+ float64x2_t im2 =
+ (float64x2_t)vtrn1q_f32(op2.AsFloat32x4, op3.AsFloat32x4);
+ float64x2_t im3 =
+ (float64x2_t)vtrn2q_f32(op2.AsFloat32x4, op3.AsFloat32x4);
+
+ TQType<float64x2_t>::As(op0) = vtrn1q_f64(im0, im2);
+ TQType<float64x2_t>::As(op1) = vtrn1q_f64(im1, im3);
+ TQType<float64x2_t>::As(op2) = vtrn2q_f64(im0, im2);
+ TQType<float64x2_t>::As(op3) = vtrn2q_f64(im1, im3);
+};
+
+Y_FORCE_INLINE __m128 _mm_castsi128_ps(__m128i op) {
+ return reinterpret_cast<__m128&>(op);
+}
+
+Y_FORCE_INLINE __m128i _mm_castps_si128(__m128 op) {
+ return reinterpret_cast<__m128i&>(op);
+}
+
+template <typename TOpOut, typename TOpIn,
+ typename TFunc, TFunc* func, typename... TParams>
+struct TCvtS2FWrapperSingle : TBaseWrapper<__m128> {
+ Y_FORCE_INLINE
+ TCvtS2FWrapperSingle(const __m128i& op, TParams... params) {
+ TQType<TOpOut>::As(Value) =
+ func(TQType<TOpIn>::As(op), params...);
+ }
+};
+
+using _mm_cvtepi32_ps =
+ TCvtS2FWrapperSingle<float32x4_t, int32x4_t,
+ decltype(vcvtq_f32_s32), vcvtq_f32_s32>;
+
+template <typename TOpOut, typename TOpIn,
+ typename TFunc, TFunc* func, typename... TParams>
+struct TCvtF2SWrapperSingle : TBaseWrapper<__m128i> {
+ Y_FORCE_INLINE
+ TCvtF2SWrapperSingle(const __m128& op, TParams... params) {
+ TQType<TOpOut>::As(Value) =
+ func(TQType<TOpIn>::As(op), params...);
+ }
+};
+
+inline __m128i _mm_cvtps_epi32(__m128 a) {
+ /// vcvtq_s32_f32 rounds to zero, but we need to round to the nearest.
+ static const float32x4_t half = vdupq_n_f32(0.5f);
+ static const float32x4_t negHalf = vdupq_n_f32(-0.5f);
+ static const float32x4_t zero = vdupq_n_f32(0.0f);
+ const float32x4_t corrections = vbslq_f32(vcgeq_f32(a.AsFloat32x4, zero), half, negHalf);
+ __m128i res;
+ res.AsSi32x4 = vcvtq_s32_f32(vaddq_f32(a.AsFloat32x4, corrections));
+ return res;
+}
+
+using _mm_cvttps_epi32 =
+ TCvtF2SWrapperSingle<int32x4_t, float32x4_t,
+ decltype(vcvtq_s32_f32), vcvtq_s32_f32>;
+
+Y_FORCE_INLINE int
+_mm_movemask_ps(const __m128& op) {
+ uint32x4_t mask = {0x80000000, 0x80000000, 0x80000000, 0x80000000};
+ uint32x4_t bits = vandq_u32(op.AsUi32x4, mask);
+ int32x4_t shifts = {-31, -30, -29, -28};
+ bits = vshlq_u32(bits, shifts);
+ return vaddvq_u32(bits);
+}
+
+Y_FORCE_INLINE i64 _mm_cvtsi128_si64(__m128i a) {
+ return vgetq_lane_s64(a.AsSi64x2, 0);
+}
+
+static inline void _mm_pause() {
+ __asm__ ("YIELD");
+}
+
+static inline __m128 _mm_rsqrt_ps(__m128 a) {
+ __m128 res;
+ res.AsFloat32x4 = vrsqrteq_f32(a.AsFloat32x4);
+ return res;
+}
+
+inline float _mm_cvtss_f32(__m128 a) {
+ return a.AsFloat32x4[0];
+}
+
+inline __m128 _mm_cmpunord_ps(__m128 a, __m128 b) {
+ __m128 res;
+ res.AsUi32x4 = vorrq_u32(
+ vmvnq_u32(vceqq_f32(a.AsFloat32x4, a.AsFloat32x4)), //!< 0xffffffff for all nans in a.
+ vmvnq_u32(vceqq_f32(b.AsFloat32x4, b.AsFloat32x4)) //!< 0xffffffff all nans in b.
+ );
+ return res;
+}
+
+inline __m128 _mm_andnot_ps(__m128 a, __m128 b) {
+ __m128 res;
+ res.AsFloat32x4 = vandq_u32(vmvnq_u32(a.AsUi32x4), b.AsUi32x4);
+ return res;
+}
+
+inline void _mm_store_ss(float* p, __m128 a) {
+ *p = vgetq_lane_f32(a.AsFloat32x4, 0);
+}
+
+inline float vgetg_lane_f32_switch(float32x4_t a, ui8 b) {
+ switch (b & 0x3) {
+ case 0:
+ return vgetq_lane_f32(a, 0);
+ case 1:
+ return vgetq_lane_f32(a, 1);
+ case 2:
+ return vgetq_lane_f32(a, 2);
+ case 3:
+ return vgetq_lane_f32(a, 3);
+ }
+ return 0;
+}
+
+inline __m128 _mm_shuffle_ps(__m128 a, __m128 b, const ShuffleStruct4& shuf) {
+ __m128 ret;
+ ret.AsFloat32x4 = vmovq_n_f32(vgetg_lane_f32_switch(a.AsFloat32x4, shuf.x[0]));
+ ret.AsFloat32x4 = vsetq_lane_f32(vgetg_lane_f32_switch(a.AsFloat32x4, shuf.x[1]), ret.AsFloat32x4, 1);
+ ret.AsFloat32x4 = vsetq_lane_f32(vgetg_lane_f32_switch(b.AsFloat32x4, shuf.x[2]), ret.AsFloat32x4, 2);
+ ret.AsFloat32x4 = vsetq_lane_f32(vgetg_lane_f32_switch(b.AsFloat32x4, shuf.x[3]), ret.AsFloat32x4, 3);
+ return ret;
+}
+
+inline __m128 _mm_or_ps(__m128 a, __m128 b) {
+ __m128 res;
+ res.AsUi32x4 = vorrq_u32(a.AsUi32x4, b.AsUi32x4);
+ return res;
+}
+
+inline __m128i _mm_sad_epu8(__m128i a, __m128i b) {
+ uint16x8_t t = vpaddlq_u8(vabdq_u8(a.AsUi8x16, b.AsUi8x16));
+ uint16_t r0 = t[0] + t[1] + t[2] + t[3];
+ uint16_t r4 = t[4] + t[5] + t[6] + t[7];
+ uint16x8_t r = vsetq_lane_u16(r0, vdupq_n_u16(0), 0);
+ __m128i ans;
+ ans.AsUi16x8 = vsetq_lane_u16(r4, r, 4);
+ return ans;
+}
+
+Y_FORCE_INLINE __m128i _mm_subs_epi8(__m128i a, __m128i b) {
+ __m128i ans;
+ ans.AsSi8x16 = vqsubq_s8(a.AsSi8x16, b.AsSi8x16);
+ return ans;
+}
+
+Y_FORCE_INLINE __m128i _mm_subs_epi16(__m128i a, __m128i b) {
+ __m128i ans;
+ ans.AsSi16x8 = vqsubq_s16(a.AsSi16x8, b.AsSi16x8);
+ return ans;
+}
+
+Y_FORCE_INLINE __m128i _mm_subs_epu8(__m128i a, __m128i b) {
+ __m128i ans;
+ ans.AsUi8x16 = vqsubq_u8(a.AsUi8x16, b.AsUi8x16);
+ return ans;
+}
+
+Y_FORCE_INLINE __m128i _mm_subs_epu16(__m128i a, __m128i b) {
+ __m128i ans;
+ ans.AsUi16x8 = vqsubq_u16(a.AsUi16x8, b.AsUi16x8);
+ return ans;
+}
+
+Y_FORCE_INLINE __m128d _mm_castsi128_pd(__m128i __A) {
+ return reinterpret_cast<__m128d&>(__A);
+}
+
+Y_FORCE_INLINE __m128i _mm_set_epi8(ui8 i15, ui8 i14, ui8 i13, ui8 i12, ui8 i11, ui8 i10, ui8 i9, ui8 i8,
+ ui8 i7, ui8 i6, ui8 i5, ui8 i4, ui8 i3, ui8 i2, ui8 i1, ui8 i0)
+{
+ int a0 = i0 | (i1<<8) | (i2<<16) | (i3<<24);
+ int a1 = i4 | (i5<<8) | (i6<<16) | (i7<<24);
+ int a2 = i8 | (i9<<8) | (i10<<16) | (i11<<24);
+ int a3 = i12 | (i13<<8) | (i14<<16) | (i15<<24);
+ return _mm_set_epi32(a3, a2, a1, a0);
+}
+
+Y_FORCE_INLINE __m128i _mm_max_epu8(__m128i a, __m128i b) {
+ __m128i ans;
+ ans.AsUi8x16 = vmaxq_u8(a.AsUi8x16, b.AsUi8x16);
+ return ans;
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wuninitialized"
+Y_FORCE_INLINE __m128d _mm_undefined_pd(void) {
+ __m128d ans = ans;
+ return ans;
+}
+#pragma GCC diagnostic pop
+
+Y_FORCE_INLINE __m128d _mm_loadh_pd(__m128d a, const double* b) {
+ a[1] = *b;
+ return a;
+}
+
+Y_FORCE_INLINE __m128d _mm_loadl_pd(__m128d a, const double* b) {
+ a[0] = *b;
+ return a;
+}
+
+Y_FORCE_INLINE double _mm_cvtsd_f64(__m128d a) {
+ return a[0];
+}
+
+Y_FORCE_INLINE __m128d _mm_shuffle_pd(__m128d a, __m128d b, int mask) {
+ __m128d result;
+ const int litmsk = mask & 0x3;
+
+ if (litmsk == 0)
+ result = vzip1q_f64(a, b);
+ else if (litmsk == 1)
+ result = __builtin_shufflevector(a, b, 1, 2);
+ else if (litmsk == 2)
+ result = __builtin_shufflevector(a, b, 0, 3);
+ else
+ result = vzip2q_f64(a, b);
+ return result;
+}
diff --git a/library/cpp/sse/ut/test.cpp b/library/cpp/sse/ut/test.cpp
new file mode 100644
index 0000000000..33c999d284
--- /dev/null
+++ b/library/cpp/sse/ut/test.cpp
@@ -0,0 +1,2088 @@
+/*
+ Unittests for all SSE instrinsics translated to NEON instrinsics or
+ software implementation.
+ Should be tested both on Intel and ARM64.
+ */
+/* Author: Vitaliy Manushkin <agri@yandex-team.ru */
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/typetraits.h>
+#include <util/string/hex.h>
+#include <util/random/fast.h>
+#include <util/stream/output.h>
+
+#include <algorithm>
+#include <array>
+#include <limits>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+template <typename TResult, typename TFunc, TFunc* func>
+struct T_mm_CallWrapper {
+ TResult Value;
+
+ template <typename... TParams>
+ T_mm_CallWrapper(TParams&&... params) {
+ Value = func(std::forward<TParams>(params)...);
+ }
+
+ operator TResult&() {
+ return Value;
+ }
+
+ operator const TResult&() const {
+ return Value;
+ }
+};
+
+#if defined(_arm64_)
+#include "library/cpp/sse/sse2neon.h"
+#elif defined(_i386_) || defined(_x86_64_)
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <smmintrin.h>
+#elif defined(_ppc64_)
+#include "library/cpp/sse/powerpc.h"
+#else
+#error "Unsupported platform"
+#endif
+
+#if defined(_arm64_)
+#define Wrap(T_mm_func) T_mm_func
+#define WrapF(T_mm_func) T_mm_func
+#define WrapD(T_mm_func) T_mm_func
+#elif defined(_ppc64_) || defined(_i386_) || defined(_x86_64_)
+#define Wrap(_mm_func) \
+ T_mm_CallWrapper<__m128i, decltype(_mm_func), _mm_func>
+#define WrapF(_mm_func) \
+ T_mm_CallWrapper<__m128, decltype(_mm_func), _mm_func>
+#define WrapD(_mm_func) \
+ T_mm_CallWrapper<__m128d, decltype(_mm_func), _mm_func>
+using int8x16_t = std::array<i8, 16>;
+using int16x8_t = std::array<i16, 8>;
+using int32x4_t = std::array<i32, 4>;
+using int64x2_t = std::array<i64, 2>;
+using uint8x16_t = std::array<ui8, 16>;
+using uint16x8_t = std::array<ui16, 8>;
+using uint32x4_t = std::array<ui32, 4>;
+using uint64x2_t = std::array<ui64, 2>;
+using float32x4_t = std::array<float, 4>;
+using float64x2_t = std::array<double, 2>;
+
+template <typename TVectorType>
+struct TQType {
+ static TVectorType As(__m128i param) {
+ TVectorType value;
+ _mm_storeu_si128((__m128i*)&value, param);
+ return value;
+ }
+ static TVectorType As(__m128 param) {
+ TVectorType value;
+ _mm_storeu_ps((float*)&value, param);
+ return value;
+ }
+ static TVectorType As(__m128d param) {
+ TVectorType value;
+ _mm_storeu_pd((double*)&value, param);
+ return value;
+ }
+};
+#endif
+
+template <typename TVectorType>
+struct TFuncLoad;
+template <typename TVectorType>
+struct TFuncStore;
+
+template <>
+struct TFuncLoad<__m128i> {
+ __m128i Value;
+
+ template <typename TPointer>
+ TFuncLoad(TPointer* ptr) {
+ Value = _mm_loadu_si128((__m128i*)ptr);
+ }
+
+ operator __m128i&() {
+ return Value;
+ }
+
+ operator const __m128i&() const {
+ return Value;
+ }
+};
+
+template <>
+struct TFuncLoad<__m128> {
+ __m128 Value;
+
+ template <typename TPointer>
+ TFuncLoad(TPointer* ptr) {
+ Value = _mm_loadu_ps((float*)ptr);
+ }
+
+ operator __m128&() {
+ return Value;
+ }
+
+ operator const __m128&() const {
+ return Value;
+ }
+};
+
+template <>
+struct TFuncLoad<__m128d> {
+ __m128d Value;
+
+ template <typename TPointer>
+ TFuncLoad(TPointer* ptr) {
+ Value = _mm_loadu_pd((double*)ptr);
+ }
+
+ operator __m128d&() {
+ return Value;
+ }
+
+ operator const __m128d&() const {
+ return Value;
+ }
+};
+
+template <>
+struct TFuncStore<__m128i> {
+ template <typename TPointer>
+ TFuncStore(TPointer* ptr, __m128i Value) {
+ _mm_storeu_si128((__m128i*)ptr, Value);
+ }
+};
+
+template <>
+struct TFuncStore<__m128> {
+ template <typename TPointer>
+ TFuncStore(TPointer* ptr, __m128 Value) {
+ _mm_storeu_ps((float*)ptr, Value);
+ }
+};
+
+class TSSEEmulTest: public TTestBase {
+private:
+ UNIT_TEST_SUITE(TSSEEmulTest);
+ UNIT_TEST(Test_mm_load_si128);
+ UNIT_TEST(Test_mm_loadu_si128);
+ UNIT_TEST(Test_mm_storeu_si128);
+ UNIT_TEST(Test_mm_loadu_si128_2);
+ UNIT_TEST(Test_mm_loadu_ps);
+ UNIT_TEST(Test_mm_storeu_ps);
+
+ UNIT_TEST(Test_mm_slli_epi16);
+ UNIT_TEST(Test_mm_slli_epi32);
+ UNIT_TEST(Test_mm_slli_epi64);
+ UNIT_TEST(Test_mm_slli_si128);
+
+ UNIT_TEST(Test_mm_srli_epi16);
+ UNIT_TEST(Test_mm_srli_epi32);
+ UNIT_TEST(Test_mm_srli_epi64);
+ UNIT_TEST(Test_mm_srli_si128);
+
+ UNIT_TEST(Test_mm_srai_epi16);
+ UNIT_TEST(Test_mm_srai_epi32);
+
+ UNIT_TEST(Test_mm_sll_epi16);
+ UNIT_TEST(Test_mm_sll_epi32);
+ UNIT_TEST(Test_mm_sll_epi64);
+
+ UNIT_TEST(Test_mm_srl_epi16);
+ UNIT_TEST(Test_mm_srl_epi32);
+ UNIT_TEST(Test_mm_srl_epi64);
+
+ UNIT_TEST(Test_mm_add_epi16);
+ UNIT_TEST(Test_mm_add_epi32);
+ UNIT_TEST(Test_mm_add_epi64);
+ UNIT_TEST(Test_mm_add_ps);
+ UNIT_TEST(Test_mm_add_pd);
+
+ UNIT_TEST(Test_mm_madd_epi16);
+
+ UNIT_TEST(Test_mm_sub_epi16);
+ UNIT_TEST(Test_mm_sub_epi32);
+ UNIT_TEST(Test_mm_sub_epi64);
+ UNIT_TEST(Test_mm_sub_ps);
+ UNIT_TEST(Test_mm_sub_pd);
+
+ UNIT_TEST(Test_mm_mul_ps);
+ UNIT_TEST(Test_mm_mul_pd);
+ UNIT_TEST(Test_mm_div_ps);
+ UNIT_TEST(Test_mm_div_pd);
+ UNIT_TEST(Test_mm_max_ps);
+ UNIT_TEST(Test_mm_min_ps);
+ UNIT_TEST(Test_mm_and_ps);
+
+ UNIT_TEST(Test_mm_unpacklo_epi8);
+ UNIT_TEST(Test_mm_unpackhi_epi8);
+ UNIT_TEST(Test_mm_unpacklo_epi16);
+ UNIT_TEST(Test_mm_unpackhi_epi16);
+ UNIT_TEST(Test_mm_unpacklo_epi32);
+ UNIT_TEST(Test_mm_unpackhi_epi32);
+ UNIT_TEST(Test_mm_unpacklo_epi64);
+ UNIT_TEST(Test_mm_unpackhi_epi64);
+
+ UNIT_TEST(Test_mm_or_si128);
+ UNIT_TEST(Test_mm_and_si128);
+ UNIT_TEST(Test_mm_andnot_si128);
+
+ UNIT_TEST(Test_mm_cmpeq_epi8);
+ UNIT_TEST(Test_mm_cmpeq_epi16);
+ UNIT_TEST(Test_mm_cmpeq_epi32);
+ UNIT_TEST(Test_mm_cmpeq_ps);
+
+ UNIT_TEST(Test_mm_cmpgt_epi8);
+ UNIT_TEST(Test_mm_cmpgt_epi16);
+ UNIT_TEST(Test_mm_cmpgt_epi32);
+ UNIT_TEST(Test_mm_cmpgt_ps);
+
+ UNIT_TEST(Test_mm_cmplt_epi8);
+ UNIT_TEST(Test_mm_cmplt_epi16);
+ UNIT_TEST(Test_mm_cmplt_epi32);
+
+ UNIT_TEST(Test_mm_set1_epi8);
+ UNIT_TEST(Test_mm_set1_epi16);
+ UNIT_TEST(Test_mm_set1_epi32);
+ UNIT_TEST(Test_mm_set1_ps);
+ UNIT_TEST(Test_mm_set_ps1);
+
+ UNIT_TEST(Test_mm_setzero_si128);
+ UNIT_TEST(Test_mm_setzero_ps);
+ UNIT_TEST(Test_mm_setzero_pd);
+
+ UNIT_TEST(Test_mm_storel_epi64);
+ UNIT_TEST(Test_mm_loadl_epi64);
+
+ UNIT_TEST(Test_mm_loadl_pd);
+ UNIT_TEST(Test_mm_loadh_pd);
+ UNIT_TEST(Test_mm_cvtsd_f64);
+
+ UNIT_TEST(Test_mm_shuffle_epi32);
+ UNIT_TEST(Test_mm_movemask_epi8);
+ UNIT_TEST(Test_mm_cvtsi128_si32);
+ UNIT_TEST(Test_mm_cvtsi128_si64);
+
+ UNIT_TEST(Test_mm_set_epi16);
+ UNIT_TEST(Test_mm_set_epi32);
+ UNIT_TEST(Test_mm_set_ps);
+ UNIT_TEST(Test_mm_set_pd);
+
+ UNIT_TEST(Test_mm_cvtsi32_si128);
+ UNIT_TEST(Test_mm_cvtsi64_si128);
+
+ UNIT_TEST(Test_mm_packs_epi16);
+ UNIT_TEST(Test_mm_packs_epi32);
+ UNIT_TEST(Test_mm_packus_epi16);
+
+ UNIT_TEST(Test_mm_extract_epi16);
+ UNIT_TEST(Test_mm_extract_epi8);
+ UNIT_TEST(Test_mm_extract_epi32);
+ UNIT_TEST(Test_mm_extract_epi64);
+
+ UNIT_TEST(Test_MM_TRANSPOSE4_PS);
+ UNIT_TEST(Test_mm_movemask_ps);
+ UNIT_TEST(Test_mm_movemask_ps_2);
+
+ UNIT_TEST(Test_mm_cvtepi32_ps);
+ UNIT_TEST(Test_mm_cvtps_epi32);
+ UNIT_TEST(Test_mm_cvttps_epi32);
+
+ UNIT_TEST(Test_mm_castsi128_ps);
+ UNIT_TEST(Test_mm_castps_si128);
+
+ UNIT_TEST(Test_mm_mul_epu32);
+
+ UNIT_TEST(Test_mm_cmpunord_ps);
+ UNIT_TEST(Test_mm_andnot_ps);
+ UNIT_TEST(Test_mm_shuffle_ps);
+ UNIT_TEST(Test_mm_shuffle_pd);
+ UNIT_TEST(Test_mm_or_ps);
+ UNIT_TEST(Test_mm_store_ss);
+ UNIT_TEST(Test_mm_store_ps);
+ UNIT_TEST(Test_mm_storeu_pd);
+ UNIT_TEST(Test_mm_loadu_pd);
+ UNIT_TEST(Test_mm_rsqrt_ps);
+ UNIT_TEST(Test_matrixnet_powerpc);
+
+ UNIT_TEST_SUITE_END();
+
+public:
+ void Test_mm_load_si128();
+ void Test_mm_loadu_si128();
+ void Test_mm_storeu_si128();
+ void Test_mm_loadu_si128_2();
+ void Test_mm_loadu_ps();
+ void Test_mm_storeu_ps();
+
+ template <typename TElem, int bits, int elemCount,
+ typename TFunc, typename TShifter, typename TOp, typename TElemFunc>
+ void Test_mm_shifter_epiXX();
+
+ enum class EDirection {
+ Left,
+ Right
+ };
+
+ struct TShiftRes {
+ __m128i Value[17];
+ };
+
+ void Test_mm_byte_shifter(EDirection direction, std::function<TShiftRes (__m128i)> foo);
+
+ void Test_mm_slli_epi16();
+ void Test_mm_slli_epi32();
+ void Test_mm_slli_epi64();
+ void Test_mm_slli_si128();
+
+ void Test_mm_srli_epi16();
+ void Test_mm_srli_epi32();
+ void Test_mm_srli_epi64();
+ void Test_mm_srli_si128();
+
+ void Test_mm_srai_epi16();
+ void Test_mm_srai_epi32();
+
+ void Test_mm_sll_epi16();
+ void Test_mm_sll_epi32();
+ void Test_mm_sll_epi64();
+
+ void Test_mm_srl_epi16();
+ void Test_mm_srl_epi32();
+ void Test_mm_srl_epi64();
+
+ void Test_mm_add_epi8();
+ void Test_mm_add_epi16();
+ void Test_mm_add_epi32();
+ void Test_mm_add_epi64();
+ void Test_mm_add_ps();
+ void Test_mm_add_pd();
+
+ void Test_mm_madd_epi16();
+
+ void Test_mm_sub_epi8();
+ void Test_mm_sub_epi16();
+ void Test_mm_sub_epi32();
+ void Test_mm_sub_epi64();
+ void Test_mm_sub_ps();
+ void Test_mm_sub_pd();
+
+ void Test_mm_mul_ps();
+ void Test_mm_mul_pd();
+ void Test_mm_div_ps();
+ void Test_mm_div_pd();
+ void Test_mm_max_ps();
+ void Test_mm_min_ps();
+ void Test_mm_and_ps();
+
+ template <typename TElem, int bits, int elemCount, int shift,
+ typename TFunc, typename TOp>
+ void Test_mm_unpack_epiXX();
+ void Test_mm_unpacklo_epi8();
+ void Test_mm_unpackhi_epi8();
+ void Test_mm_unpacklo_epi16();
+ void Test_mm_unpackhi_epi16();
+ void Test_mm_unpacklo_epi32();
+ void Test_mm_unpackhi_epi32();
+ void Test_mm_unpacklo_epi64();
+ void Test_mm_unpackhi_epi64();
+
+ template <typename TElem, unsigned elemCount,
+ typename TFunc, typename TElemFunc,
+ typename TOp, typename TVectorType = __m128i>
+ void Test_mm_dualop();
+
+ template <typename TElem, unsigned elemCount,
+ typename TFunc, typename TElemFunc,
+ typename TOp, typename TVectorType = __m128i>
+ void Test_mm_dualcmp();
+
+ void Test_mm_or_si128();
+ void Test_mm_and_si128();
+ void Test_mm_andnot_si128();
+
+ void Test_mm_cmpeq_epi8();
+ void Test_mm_cmpeq_epi16();
+ void Test_mm_cmpeq_epi32();
+ void Test_mm_cmpeq_ps();
+
+ void Test_mm_cmpgt_epi8();
+ void Test_mm_cmpgt_epi16();
+ void Test_mm_cmpgt_epi32();
+ void Test_mm_cmpgt_ps();
+
+ void Test_mm_cmplt_epi8();
+ void Test_mm_cmplt_epi16();
+ void Test_mm_cmplt_epi32();
+
+ template <typename TElem, int elemCount,
+ typename TFunc, typename TOp, typename TVectorType>
+ void Test_mm_setter_epiXX();
+ void Test_mm_set1_epi8();
+ void Test_mm_set1_epi16();
+ void Test_mm_set1_epi32();
+ void Test_mm_set1_ps();
+ void Test_mm_set_ps1();
+
+ void Test_mm_setzero_si128();
+ void Test_mm_setzero_ps();
+ void Test_mm_setzero_pd();
+
+ void Test_mm_loadl_epi64();
+ void Test_mm_storel_epi64();
+
+ void Test_mm_loadl_pd();
+ void Test_mm_loadh_pd();
+ void Test_mm_cvtsd_f64();
+
+ void Test_mm_shuffle_epi32();
+ void Test_mm_movemask_epi8();
+ void Test_mm_cvtsi128_si32();
+ void Test_mm_cvtsi128_si64();
+
+ void Test_mm_set_epi16();
+ void Test_mm_set_epi32();
+ void Test_mm_set_ps();
+ void Test_mm_set_pd();
+
+ void Test_mm_cvtsi32_si128();
+ void Test_mm_cvtsi64_si128();
+
+ template <typename TElem, typename TNarrow, unsigned elemCount,
+ typename TFunc>
+ void Test_mm_packs_epiXX();
+ void Test_mm_packs_epi16();
+ void Test_mm_packs_epi32();
+ void Test_mm_packus_epi16();
+
+ void Test_mm_extract_epi16();
+ void Test_mm_extract_epi8();
+ void Test_mm_extract_epi32();
+ void Test_mm_extract_epi64();
+
+ void Test_MM_TRANSPOSE4_PS();
+ void Test_mm_movemask_ps();
+ void Test_mm_movemask_ps_2();
+
+ template <typename TFrom, typename TTo, unsigned elemCount,
+ typename TLoadVector, typename TResultVector,
+ typename TElemFunc, typename TFunc, typename TOp>
+ void Test_mm_convertop();
+ void Test_mm_cvtepi32_ps();
+ void Test_mm_cvtps_epi32();
+ void Test_mm_cvttps_epi32();
+
+ template <typename TLoadVector, typename TCastVector,
+ typename TFunc, TFunc* func>
+ void Test_mm_castXX();
+ void Test_mm_castsi128_ps();
+ void Test_mm_castps_si128();
+
+ void Test_mm_mul_epu32();
+
+ void Test_mm_cmpunord_ps();
+ void Test_mm_store_ss();
+ void Test_mm_store_ps();
+ void Test_mm_storeu_pd();
+ void Test_mm_andnot_ps();
+ void Test_mm_shuffle_ps();
+ void Test_mm_shuffle_pd();
+ void Test_mm_or_ps();
+ void Test_mm_loadu_pd();
+ void Test_mm_rsqrt_ps();
+ void Test_mm_rsqrt_ss();
+ void Test_matrixnet_powerpc();
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TSSEEmulTest);
+
+void TSSEEmulTest::Test_mm_load_si128() {
+ alignas(16) char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ __m128i value = _mm_load_si128((__m128i*)&data);
+ UNIT_ASSERT_EQUAL(TQType<uint64x2_t>::As(value)[0], 0xAABB2211CCFF00AAUL);
+ UNIT_ASSERT_EQUAL(TQType<uint64x2_t>::As(value)[1], 0x1C66775588449933UL);
+}
+
+void TSSEEmulTest::Test_mm_loadu_si128() {
+ alignas(16) char data[17] = {
+ '\x66',
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ UNIT_ASSERT((ui64(&data[1]) & 0x1) == 0x1);
+ __m128i value = _mm_loadu_si128((__m128i*)&data[1]);
+ UNIT_ASSERT(TQType<uint64x2_t>::As(value)[0] == 0xAABB2211CCFF00AAUL);
+ UNIT_ASSERT(TQType<uint64x2_t>::As(value)[1] == 0x1C66775588449933UL);
+}
+
+void TSSEEmulTest::Test_mm_storeu_si128() {
+ alignas(16) unsigned char stub[32] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
+ };
+
+ alignas(16) unsigned char value[16] = {
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf
+ };
+
+ const __m128i val = _mm_loadu_si128((__m128i*)&value[0]);
+
+ for (size_t shift = 0; shift != 17; ++shift) {
+ alignas(16) unsigned char res[sizeof(stub)];
+ memcpy(res, stub, sizeof(res));
+
+ _mm_storeu_si128((__m128i*)&res[shift], val);
+
+
+ alignas(16) unsigned char etalon[sizeof(stub)];
+ memcpy(etalon, stub, sizeof(etalon));
+ for (size_t i = 0; i != sizeof(value); ++i) {
+ etalon[shift + i] = value[i];
+ }
+
+ for (size_t i = 0; i != sizeof(etalon) / sizeof(etalon[0]); ++i) {
+ UNIT_ASSERT_EQUAL_C(res[i], etalon[i], "res: " << HexEncode(res, 32) << " vs etalon: " << HexEncode(etalon, 32));
+ }
+ }
+
+}
+
+
+void TSSEEmulTest::Test_mm_loadu_si128_2() {
+ alignas(16) unsigned char stub[32] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
+ };
+
+ for (size_t shift = 0; shift != 17; ++shift) {
+ const __m128i val = _mm_loadu_si128((const __m128i*)&stub[shift]);
+ alignas(16) unsigned char res[16];
+ _mm_store_si128((__m128i*)res, val);
+
+ for (size_t i = 0; i != 16; ++i) {
+ UNIT_ASSERT_EQUAL_C(res[i], stub[i + shift], "res: " << HexEncode(res, 16) << " vs etalon: " << HexEncode(&stub[shift], 16));
+ }
+ }
+}
+
+
+void TSSEEmulTest::Test_mm_loadu_ps() {
+ alignas(16) float stub[8] = {
+ 0.f, 1.f, 2.f, 3.f,
+ 4.f, 5.f, 6.f, 7.f
+ };
+
+ for (size_t shift = 0; shift != 5; ++shift) {
+ const __m128 val = _mm_loadu_ps(&stub[shift]);
+ alignas(16) float res[4];
+ _mm_store_ps(res, val);
+
+ for (size_t i = 0; i != 4; ++i) {
+ UNIT_ASSERT_EQUAL_C(res[i], stub[shift + i], "res: " << HexEncode(res, 16) << " vs etalon: " << HexEncode(&stub[shift], 16));
+ }
+ }
+}
+
+
+void TSSEEmulTest::Test_mm_storeu_ps() {
+ alignas(16) float stub[8] = {
+ 0.f, 1.f, 2.f, 3.f,
+ 4.f, 5.f, 6.f, 7.f
+ };
+
+ alignas(16) float value[4] = {
+ 100.f, 101.f, 102.f, 103.f
+ };
+ const __m128 val = _mm_load_ps(value);
+
+ for (size_t shift = 0; shift != 5; ++shift) {
+ alignas(16) float res[sizeof(stub) / sizeof(stub[0])];
+ memcpy(res, stub, sizeof(stub));
+
+ _mm_storeu_ps(&res[shift], val);
+
+ float etalon[sizeof(stub) / sizeof(stub[0])];
+ memcpy(etalon, stub, sizeof(stub));
+ for (size_t i = 0; i != 4; ++i) {
+ etalon[i + shift] = value[i];
+ }
+
+ for (size_t i = 0; i != sizeof(stub) / sizeof(stub[0]); ++i) {
+ UNIT_ASSERT_EQUAL_C(res[i], etalon[i], "res: " << HexEncode(res, sizeof(res)) << " vs etalon: " << HexEncode(etalon, sizeof(etalon)));
+ }
+ }
+}
+
+template<typename C>
+C MakeNumber(unsigned number);
+
+template<>
+__m128i MakeNumber<__m128i>(unsigned number) {
+ char data[16] = {0};
+ memcpy(data, &number, sizeof(number));
+
+ return _mm_loadu_si128((__m128i*)data);
+}
+
+template<>
+unsigned MakeNumber<unsigned>(unsigned number) {
+ return number;
+}
+
+template <typename TElem, int bits, int elemCount,
+ typename TFunc, typename TShifter, typename TOp, typename TElemFunc>
+void TSSEEmulTest::Test_mm_shifter_epiXX() {
+ char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ TElem* dataw = reinterpret_cast<TElem*>(&data);
+
+ __m128i value = _mm_loadu_si128((__m128i*)&data);
+
+ for (unsigned shifter = 0; shifter <= bits; ++shifter) {
+ TElem shiftedData[elemCount];
+ for (unsigned i = 0; i < elemCount; ++i) {
+ shiftedData[i] = TElemFunc::Call(dataw[i], shifter);
+ }
+
+ const TShifter adhoc_shifter = MakeNumber<TShifter>(shifter);
+
+ __m128i result = TFunc(value, adhoc_shifter);
+
+ for (unsigned i = 0; i < elemCount; ++i) {
+ UNIT_ASSERT_EQUAL(shiftedData[i], TQType<TOp>::As(result)[i]);
+ }
+ }
+}
+
+
+void TSSEEmulTest::Test_mm_byte_shifter(EDirection direction, std::function<TShiftRes (__m128i)> foo) {
+ const char data[48] = {
+ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
+ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C',
+ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
+ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'
+ };
+
+ const __m128i a = _mm_loadu_si128((__m128i*)(data + 16));
+ const TShiftRes res = foo(a);
+ for (int shift = 0; shift <= 16; ++shift) {
+ const int etalon_offset = 16 + (direction == EDirection::Left ? -shift : shift); //!< specific to little endian byte order.
+ const char* etalon = data + etalon_offset;
+ const char* res_bytes = (const char*)&res.Value[shift];
+
+ for (size_t byte = 0; byte != 16; ++byte) {
+ UNIT_ASSERT_EQUAL(etalon[byte], res_bytes[byte]);
+ }
+ }
+}
+
+template <typename TElem>
+struct THelperASHR {
+ static TElem Call(const TElem op, const int shift) {
+ constexpr int nBitsInOp = sizeof(op) * CHAR_BIT;
+ if (op < 0) {
+ // Arithmetic shift propagates sign bit to the right
+ // while operator>> is implementation defined for negative values,
+ // so we can't use it as a reference implementation
+ // and we need to write some standard consistent code.
+ typedef TFixedWidthUnsignedInt<TElem> TUnsignedElem;
+ TUnsignedElem uOp(op);
+ const TUnsignedElem signBit = TUnsignedElem(1) << (nBitsInOp - 1);
+ Y_ENSURE(shift >= 0);
+ for (int i = 0; i != shift; ++i) {
+ uOp = signBit | (uOp >> 1);
+ }
+ // unsigned -> signed conversion is also implementation defined, so we need to use some other method.
+ return reinterpret_cast<TElem&>(uOp);
+ }
+ return shift < nBitsInOp ? op >> shift : 0;
+ }
+};
+
+template <typename TElem>
+struct THelperSHR {
+ static TElem Call(const TElem op, const int shift) {
+ constexpr int nBitsInOp = sizeof(op) * CHAR_BIT;
+ return shift < nBitsInOp ? op >> shift : 0;
+ }
+};
+
+void TSSEEmulTest::Test_mm_srli_epi16() {
+ Test_mm_shifter_epiXX<ui16, 16, 8, Wrap(_mm_srli_epi16), unsigned, uint16x8_t,
+ THelperSHR<ui16>>();
+}
+
+void TSSEEmulTest::Test_mm_srli_epi32() {
+ Test_mm_shifter_epiXX<ui32, 32, 4, Wrap(_mm_srli_epi32), unsigned, uint32x4_t,
+ THelperSHR<ui32>>();
+}
+
+void TSSEEmulTest::Test_mm_srli_epi64() {
+ Test_mm_shifter_epiXX<ui64, 64, 2, Wrap(_mm_srli_epi64), unsigned, uint64x2_t,
+ THelperSHR<ui64>>();
+}
+
+template <typename TElem>
+struct THelperSHL {
+ static TElem Call(const TElem op, const int shift) {
+ constexpr int nBitsInOp = sizeof(op) * CHAR_BIT;
+ return shift < nBitsInOp ? op << shift : 0;
+ }
+};
+
+void TSSEEmulTest::Test_mm_slli_epi16() {
+ Test_mm_shifter_epiXX<ui16, 16, 8, Wrap(_mm_slli_epi16), unsigned, uint16x8_t,
+ THelperSHL<ui16>>();
+}
+
+void TSSEEmulTest::Test_mm_slli_epi32() {
+ Test_mm_shifter_epiXX<ui32, 32, 4, Wrap(_mm_slli_epi32), unsigned, uint32x4_t,
+ THelperSHL<ui32>>();
+}
+
+void TSSEEmulTest::Test_mm_slli_epi64() {
+ Test_mm_shifter_epiXX<ui64, 64, 2, Wrap(_mm_slli_epi64), unsigned, uint64x2_t,
+ THelperSHL<ui64>>();
+}
+
+void TSSEEmulTest::Test_mm_slli_si128() {
+ Test_mm_byte_shifter(EDirection::Left, [] (__m128i a) -> TShiftRes {
+ TShiftRes res;
+ res.Value[0] = _mm_slli_si128(a, 0);
+ res.Value[1] = _mm_slli_si128(a, 1);
+ res.Value[2] = _mm_slli_si128(a, 2);
+ res.Value[3] = _mm_slli_si128(a, 3);
+ res.Value[4] = _mm_slli_si128(a, 4);
+ res.Value[5] = _mm_slli_si128(a, 5);
+ res.Value[6] = _mm_slli_si128(a, 6);
+ res.Value[7] = _mm_slli_si128(a, 7);
+ res.Value[8] = _mm_slli_si128(a, 8);
+ res.Value[9] = _mm_slli_si128(a, 9);
+ res.Value[10] = _mm_slli_si128(a, 10);
+ res.Value[11] = _mm_slli_si128(a, 11);
+ res.Value[12] = _mm_slli_si128(a, 12);
+ res.Value[13] = _mm_slli_si128(a, 13);
+ res.Value[14] = _mm_slli_si128(a, 14);
+ res.Value[15] = _mm_slli_si128(a, 15);
+ res.Value[16] = _mm_slli_si128(a, 16);
+
+ return res;
+ });
+}
+
+void TSSEEmulTest::Test_mm_srl_epi16() {
+ Test_mm_shifter_epiXX<ui16, 16, 8, T_mm_CallWrapper<__m128i, decltype(_mm_srl_epi16), _mm_srl_epi16>, __m128i, uint16x8_t,
+ THelperSHR<ui16>>();
+}
+
+void TSSEEmulTest::Test_mm_srl_epi32() {
+ Test_mm_shifter_epiXX<ui32, 32, 4, T_mm_CallWrapper<__m128i, decltype(_mm_srl_epi32), _mm_srl_epi32>, __m128i, uint32x4_t,
+ THelperSHR<ui32>>();
+}
+
+void TSSEEmulTest::Test_mm_srl_epi64() {
+ Test_mm_shifter_epiXX<ui64, 64, 2, T_mm_CallWrapper<__m128i, decltype(_mm_srl_epi64), _mm_srl_epi64>, __m128i, uint64x2_t,
+ THelperSHR<ui64>>();
+}
+
+void TSSEEmulTest::Test_mm_srai_epi16() {
+ Test_mm_shifter_epiXX<i16, 16, 8, T_mm_CallWrapper<__m128i, decltype(_mm_srai_epi16), _mm_srai_epi16>, unsigned, int16x8_t,
+ THelperASHR<i16>>();
+}
+
+void TSSEEmulTest::Test_mm_srai_epi32() {
+ Test_mm_shifter_epiXX<i32, 32, 4, T_mm_CallWrapper<__m128i, decltype(_mm_srai_epi32), _mm_srai_epi32>, unsigned, int32x4_t,
+ THelperASHR<i32>>();
+}
+
+void TSSEEmulTest::Test_mm_srli_si128() {
+ Test_mm_byte_shifter(EDirection::Right, [](__m128i a) -> TShiftRes {
+ TShiftRes res;
+ res.Value[0] = _mm_srli_si128(a, 0);
+ res.Value[1] = _mm_srli_si128(a, 1);
+ res.Value[2] = _mm_srli_si128(a, 2);
+ res.Value[3] = _mm_srli_si128(a, 3);
+ res.Value[4] = _mm_srli_si128(a, 4);
+ res.Value[5] = _mm_srli_si128(a, 5);
+ res.Value[6] = _mm_srli_si128(a, 6);
+ res.Value[7] = _mm_srli_si128(a, 7);
+ res.Value[8] = _mm_srli_si128(a, 8);
+ res.Value[9] = _mm_srli_si128(a, 9);
+ res.Value[10] = _mm_srli_si128(a, 10);
+ res.Value[11] = _mm_srli_si128(a, 11);
+ res.Value[12] = _mm_srli_si128(a, 12);
+ res.Value[13] = _mm_srli_si128(a, 13);
+ res.Value[14] = _mm_srli_si128(a, 14);
+ res.Value[15] = _mm_srli_si128(a, 15);
+ res.Value[16] = _mm_srli_si128(a, 16);
+
+ return res;
+ });
+}
+
+void TSSEEmulTest::Test_mm_sll_epi16() {
+ Test_mm_shifter_epiXX<ui16, 16, 8, T_mm_CallWrapper<__m128i, decltype(_mm_sll_epi16), _mm_sll_epi16>, __m128i, uint16x8_t,
+ THelperSHL<ui16>>();
+}
+
+void TSSEEmulTest::Test_mm_sll_epi32() {
+ Test_mm_shifter_epiXX<ui32, 32, 4, T_mm_CallWrapper<__m128i, decltype(_mm_sll_epi32), _mm_sll_epi32>, __m128i, uint32x4_t,
+ THelperSHL<ui32>>();
+}
+
+void TSSEEmulTest::Test_mm_sll_epi64() {
+ Test_mm_shifter_epiXX<ui64, 64, 2, T_mm_CallWrapper<__m128i, decltype(_mm_sll_epi64), _mm_sll_epi64>, __m128i, uint64x2_t,
+ THelperSHL<ui64>>();
+}
+
+template <typename TElem>
+struct THelperAdd {
+ static TElem Call(const TElem op1, const TElem op2) {
+ return op1 + op2;
+ }
+};
+
+void TSSEEmulTest::Test_mm_add_epi16() {
+ Test_mm_dualop<ui16, 8, Wrap(_mm_add_epi16), THelperAdd<ui16>, uint16x8_t>();
+}
+
+void TSSEEmulTest::Test_mm_add_epi32() {
+ Test_mm_dualop<ui32, 4, Wrap(_mm_add_epi32), THelperAdd<ui32>, uint32x4_t>();
+}
+
+void TSSEEmulTest::Test_mm_add_epi64() {
+ Test_mm_dualop<ui64, 2, Wrap(_mm_add_epi64), THelperAdd<ui64>, uint64x2_t>();
+}
+
+void TSSEEmulTest::Test_mm_add_ps() {
+ Test_mm_dualop<float, 2, WrapF(_mm_add_ps),
+ THelperAdd<float>, float32x4_t, __m128>();
+}
+
+void TSSEEmulTest::Test_mm_add_pd() {
+ Test_mm_dualop<double, 2, WrapD(_mm_add_pd),
+ THelperAdd<double>, float64x2_t, __m128d>();
+}
+
+void TSSEEmulTest::Test_mm_madd_epi16() {
+ alignas(16) const char data1[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'
+ };
+ alignas(16) const char data2[16] = {
+ '\x99', '\x33', '\x1C', '\x55', '\x88', '\x66', '\x77', '\x44',
+ '\x00', '\xAA', '\xAA', '\x11', '\xCC', '\xBB', '\x22', '\xFF'
+ };
+
+ const __m128i value1 = TFuncLoad<__m128i>(&data1);
+ const __m128i value2 = TFuncLoad<__m128i>(&data2);
+ const __m128i res = _mm_madd_epi16(value1, value2);
+
+ const i16* dataw1 = reinterpret_cast<const i16*>(&data1);
+ const i16* dataw2 = reinterpret_cast<const i16*>(&data2);
+
+ for (size_t i = 0; i != 4; ++i) {
+ const size_t dataIdx = i * 2;
+ const i32 etalonResult = (i32) dataw1[dataIdx] * (i32) dataw2[dataIdx] + (i32) dataw1[dataIdx + 1] * (i32) dataw2[dataIdx + 1];
+ const i32 value = TQType<int32x4_t>::As(res)[i];
+ UNIT_ASSERT_EQUAL(value, etalonResult);
+ }
+}
+
+
+template <typename TElem>
+struct THelperSub {
+ static TElem Call(const TElem op1, const TElem op2) {
+ return op1 - op2;
+ }
+};
+
+void TSSEEmulTest::Test_mm_sub_epi16() {
+ Test_mm_dualop<ui16, 8, Wrap(_mm_sub_epi16), THelperSub<ui16>, uint16x8_t>();
+}
+
+void TSSEEmulTest::Test_mm_sub_epi32() {
+ Test_mm_dualop<ui32, 4, Wrap(_mm_sub_epi32), THelperSub<ui32>, uint32x4_t>();
+}
+
+void TSSEEmulTest::Test_mm_sub_epi64() {
+ Test_mm_dualop<ui64, 2, Wrap(_mm_sub_epi64), THelperSub<ui64>, uint64x2_t>();
+}
+
+void TSSEEmulTest::Test_mm_sub_ps() {
+ Test_mm_dualop<float, 4, WrapF(_mm_sub_ps), THelperSub<float>,
+ float32x4_t, __m128>();
+}
+
+void TSSEEmulTest::Test_mm_sub_pd() {
+ Test_mm_dualop<double, 2, WrapD(_mm_sub_pd), THelperSub<double>,
+ float64x2_t, __m128d>();
+}
+
+void TSSEEmulTest::Test_mm_mul_ps() {
+ struct THelper {
+ static float Call(const float op1, const float op2) {
+ return op1 * op2;
+ }
+ };
+ Test_mm_dualop<float, 4, WrapF(_mm_mul_ps), THelper, float32x4_t, __m128>();
+}
+
+void TSSEEmulTest::Test_mm_mul_pd() {
+ struct THelper {
+ static double Call(const double op1, const double op2) {
+ return op1 * op2;
+ }
+ };
+ Test_mm_dualop<double, 2, WrapD(_mm_mul_pd), THelper, float64x2_t, __m128d>();
+}
+
+void TSSEEmulTest::Test_mm_div_ps() {
+ struct THelper {
+ static float Call(const float op1, const float op2) {
+ return op1 / op2;
+ }
+ };
+ Test_mm_dualop<float, 4, WrapF(_mm_div_ps), THelper, float32x4_t, __m128>();
+}
+
+void TSSEEmulTest::Test_mm_div_pd() {
+ struct THelper {
+ static double Call(const double op1, const double op2) {
+ return op1 / op2;
+ }
+ };
+ Test_mm_dualop<double, 2, WrapD(_mm_div_pd), THelper, float64x2_t, __m128d>();
+}
+
+void TSSEEmulTest::Test_mm_max_ps() {
+ struct THelper {
+ static float Call(const float op1, const float op2) {
+ return std::max(op1, op2);
+ }
+ };
+ Test_mm_dualop<float, 4, WrapF(_mm_max_ps), THelper, float32x4_t, __m128>();
+}
+
+void TSSEEmulTest::Test_mm_min_ps() {
+ struct THelper {
+ static float Call(const float op1, const float op2) {
+ return std::min(op1, op2);
+ }
+ };
+ Test_mm_dualop<float, 4, WrapF(_mm_min_ps), THelper, float32x4_t, __m128>();
+}
+
+void TSSEEmulTest::Test_mm_and_ps() {
+ struct THelper {
+ static float Call(const float op1, const float op2) {
+ union Cast {
+ unsigned int AsUInt;
+ float AsFloat;
+ };
+ Cast v1, v2, result;
+ v1.AsFloat = op1;
+ v2.AsFloat = op2;
+ result.AsUInt = v1.AsUInt & v2.AsUInt;
+ return result.AsFloat;
+ }
+ };
+ Test_mm_dualcmp<float, 4, WrapF(_mm_and_ps),
+ THelper, float32x4_t, __m128>();
+}
+
+template <typename TElem, int bits, int elemCount, int shift,
+ typename TFunc, typename TOp>
+void TSSEEmulTest::Test_mm_unpack_epiXX() {
+ char data1[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ char data2[16] = {
+ '\x99', '\x33', '\x1C', '\x55', '\x88', '\x66', '\x77', '\x44',
+ '\x00', '\xAA', '\xAA', '\x11', '\xCC', '\xBB', '\x22', '\xFF'};
+ TElem* dataw1 = reinterpret_cast<TElem*>(&data1);
+ TElem* dataw2 = reinterpret_cast<TElem*>(&data2);
+
+ __m128i value1 = _mm_loadu_si128((__m128i*)&data1);
+ __m128i value2 = _mm_loadu_si128((__m128i*)&data2);
+
+ TElem zippedData[elemCount];
+ for (unsigned i = 0; i < elemCount / 2; ++i) {
+ zippedData[i * 2] = dataw1[i + shift];
+ zippedData[i * 2 + 1] = dataw2[i + shift];
+ }
+ __m128i result = TFunc(value1, value2);
+
+ for (unsigned i = 0; i < elemCount / 2; ++i) {
+ UNIT_ASSERT_EQUAL(zippedData[i * 2], TQType<TOp>::As(result)[i * 2]);
+ UNIT_ASSERT_EQUAL(zippedData[i * 2 + 1],
+ TQType<TOp>::As(result)[i * 2 + 1]);
+ }
+}
+
+void TSSEEmulTest::Test_mm_unpacklo_epi8() {
+ Test_mm_unpack_epiXX<ui8, 8, 16, 0, Wrap(_mm_unpacklo_epi8), uint8x16_t>();
+}
+
+void TSSEEmulTest::Test_mm_unpackhi_epi8() {
+ Test_mm_unpack_epiXX<ui8, 8, 16, 8, Wrap(_mm_unpackhi_epi8), uint8x16_t>();
+}
+
+void TSSEEmulTest::Test_mm_unpacklo_epi16() {
+ Test_mm_unpack_epiXX<ui16, 16, 8, 0, Wrap(_mm_unpacklo_epi16), uint16x8_t>();
+}
+
+void TSSEEmulTest::Test_mm_unpackhi_epi16() {
+ Test_mm_unpack_epiXX<ui16, 16, 8, 4, Wrap(_mm_unpackhi_epi16), uint16x8_t>();
+}
+
+void TSSEEmulTest::Test_mm_unpacklo_epi32() {
+ Test_mm_unpack_epiXX<ui32, 32, 4, 0, Wrap(_mm_unpacklo_epi32), uint32x4_t>();
+}
+
+void TSSEEmulTest::Test_mm_unpackhi_epi32() {
+ Test_mm_unpack_epiXX<ui32, 32, 4, 2, Wrap(_mm_unpackhi_epi32), uint32x4_t>();
+}
+
+void TSSEEmulTest::Test_mm_unpacklo_epi64() {
+ Test_mm_unpack_epiXX<ui64, 64, 2, 0, Wrap(_mm_unpacklo_epi64), uint64x2_t>();
+}
+
+void TSSEEmulTest::Test_mm_unpackhi_epi64() {
+ Test_mm_unpack_epiXX<ui64, 64, 2, 1, Wrap(_mm_unpackhi_epi64), uint64x2_t>();
+}
+
+template <typename TElem, unsigned elemCount,
+ typename TFunc, typename TElemFunc,
+ typename TOp, typename TVectorType>
+void TSSEEmulTest::Test_mm_dualop() {
+ char data1[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ char data2[16] = {
+ '\x99', '\x33', '\x1C', '\x55', '\x88', '\x66', '\x77', '\x44',
+ '\x00', '\xAA', '\xAA', '\x11', '\xCC', '\xBB', '\x22', '\xFF'};
+ TElem* dataw1 = reinterpret_cast<TElem*>(&data1);
+ TElem* dataw2 = reinterpret_cast<TElem*>(&data2);
+
+ TVectorType value1 = TFuncLoad<TVectorType>(&data1);
+ TVectorType value2 = TFuncLoad<TVectorType>(&data2);
+
+ TElem procData[elemCount];
+ for (unsigned i = 0; i < elemCount; ++i) {
+ procData[i] = TElemFunc::Call(dataw1[i], dataw2[i]);
+ }
+ TVectorType result = TFunc(value1, value2);
+
+ for (unsigned i = 0; i < elemCount; ++i) {
+ UNIT_ASSERT_EQUAL(procData[i], TQType<TOp>::As(result)[i]);
+ }
+}
+
+/* This is almost the same as Test_mm_dualop,
+ but different data1 and data2 */
+template <typename TElem, unsigned elemCount,
+ typename TFunc, typename TElemFunc,
+ typename TOp, typename TVectorType>
+void TSSEEmulTest::Test_mm_dualcmp() {
+ char data1[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x66', '\x77', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\xCC', '\xBB', '\x66', '\x1C'};
+ char data2[16] = {
+ '\x99', '\x33', '\xFF', '\xCC', '\x88', '\x66', '\x77', '\x44',
+ '\x33', '\x99', '\x44', '\x88', '\xCC', '\xBB', '\x22', '\xFF'};
+ TElem* dataw1 = reinterpret_cast<TElem*>(&data1);
+ TElem* dataw2 = reinterpret_cast<TElem*>(&data2);
+
+ TVectorType value1 = TFuncLoad<TVectorType>(&data1);
+ TVectorType value2 = TFuncLoad<TVectorType>(&data2);
+
+ TElem procData[elemCount];
+ for (unsigned i = 0; i < elemCount; ++i) {
+ procData[i] = TElemFunc::Call(dataw1[i], dataw2[i]);
+ }
+ TVectorType result = TFunc(value1, value2);
+
+ for (unsigned i = 0; i < elemCount; ++i) {
+ /* memcmp is for compare to invalid floats in results */
+ const TElem value = TQType<TOp>::As(result)[i];
+ UNIT_ASSERT(memcmp(&(procData[i]), &value, sizeof(TElem)) == 0);
+ }
+}
+
+void TSSEEmulTest::Test_mm_or_si128() {
+ struct THelper {
+ static ui64 Call(const ui64 op1, const ui64 op2) {
+ return op1 | op2;
+ }
+ };
+
+ Test_mm_dualop<ui64, 2, Wrap(_mm_or_si128), THelper, uint64x2_t>();
+}
+
+void TSSEEmulTest::Test_mm_and_si128() {
+ struct THelper {
+ static ui64 Call(const ui64 op1, const ui64 op2) {
+ return op1 & op2;
+ }
+ };
+
+ Test_mm_dualop<ui64, 2, Wrap(_mm_and_si128), THelper, uint64x2_t>();
+}
+
+void TSSEEmulTest::Test_mm_andnot_si128() {
+ struct THelper {
+ static ui64 Call(const ui64 op1, const ui64 op2) {
+ return (~op1) & op2;
+ }
+ };
+
+ Test_mm_dualop<ui64, 2, Wrap(_mm_andnot_si128), THelper, uint64x2_t>();
+}
+
+template <typename TElem>
+struct THelperCMPEQ {
+ static TElem Call(const TElem op1, const TElem op2) {
+ return op1 == op2 ? ~TElem(0) : TElem(0);
+ }
+};
+
+void TSSEEmulTest::Test_mm_cmpeq_epi8() {
+ Test_mm_dualcmp<ui8, 16, Wrap(_mm_cmpeq_epi8),
+ THelperCMPEQ<ui8>, uint8x16_t>();
+}
+
+void TSSEEmulTest::Test_mm_cmpeq_epi16() {
+ Test_mm_dualcmp<ui16, 8, Wrap(_mm_cmpeq_epi16),
+ THelperCMPEQ<ui16>, uint16x8_t>();
+}
+
+void TSSEEmulTest::Test_mm_cmpeq_epi32() {
+ Test_mm_dualcmp<ui32, 4, Wrap(_mm_cmpeq_epi32),
+ THelperCMPEQ<ui32>, uint32x4_t>();
+}
+
+void TSSEEmulTest::Test_mm_cmpeq_ps() {
+ struct THelperFloat {
+ static float Call(const float op1, const float op2) {
+ union Cast {
+ unsigned int AsUInt;
+ float AsFloat;
+ };
+ Cast value;
+ value.AsUInt = op1 == op2 ? 0xFFFFFFFF : 0;
+ return value.AsFloat;
+ }
+ };
+
+ Test_mm_dualcmp<float, 4, WrapF(_mm_cmpeq_ps),
+ THelperFloat, float32x4_t, __m128>();
+}
+
+template <typename TElem>
+struct THelperCMPGT {
+ static TElem Call(const TElem op1, const TElem op2) {
+ return op1 > op2 ? ~TElem(0) : TElem(0);
+ }
+};
+
+void TSSEEmulTest::Test_mm_cmpgt_epi8() {
+ Test_mm_dualcmp<i8, 16, Wrap(_mm_cmpgt_epi8),
+ THelperCMPGT<i8>, int8x16_t>();
+}
+
+void TSSEEmulTest::Test_mm_cmpgt_epi16() {
+ Test_mm_dualcmp<i16, 8, Wrap(_mm_cmpgt_epi16),
+ THelperCMPGT<i16>, int16x8_t>();
+}
+
+void TSSEEmulTest::Test_mm_cmpgt_epi32() {
+ Test_mm_dualcmp<i32, 4, Wrap(_mm_cmpgt_epi32),
+ THelperCMPGT<i32>, int32x4_t>();
+}
+
+void TSSEEmulTest::Test_mm_cmpgt_ps() {
+ struct THelperFloat {
+ static float Call(const float op1, const float op2) {
+ union Cast {
+ unsigned int AsUInt;
+ float AsFloat;
+ };
+ Cast value;
+ value.AsUInt = op1 > op2 ? 0xFFFFFFFF : 0;
+ return value.AsFloat;
+ }
+ };
+
+ Test_mm_dualcmp<float, 4, WrapF(_mm_cmpgt_ps),
+ THelperFloat, float32x4_t, __m128>();
+}
+
+template <typename TElem>
+struct THelperCMPLT {
+ static TElem Call(const TElem op1, const TElem op2) {
+ return op1 < op2 ? ~TElem(0) : TElem(0);
+ }
+};
+
+void TSSEEmulTest::Test_mm_cmplt_epi8() {
+ Test_mm_dualcmp<i8, 16, Wrap(_mm_cmplt_epi8),
+ THelperCMPLT<i8>, int8x16_t>();
+}
+
+void TSSEEmulTest::Test_mm_cmplt_epi16() {
+ Test_mm_dualcmp<i16, 8, Wrap(_mm_cmplt_epi16),
+ THelperCMPLT<i16>, int16x8_t>();
+}
+
+void TSSEEmulTest::Test_mm_cmplt_epi32() {
+ Test_mm_dualcmp<i32, 4, Wrap(_mm_cmplt_epi32),
+ THelperCMPLT<i32>, int32x4_t>();
+}
+
+template <typename TElem, int elemCount,
+ typename TFunc, typename TOp, typename TVectorType>
+void TSSEEmulTest::Test_mm_setter_epiXX() {
+ char data[64] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x00', '\x55', '\x77', '\x66', '\x1C',
+ '\x99', '\x33', '\x1C', '\x55', '\x88', '\x66', '\x77', '\x44',
+ '\x00', '\xAA', '\xAA', '\x11', '\xCC', '\xBB', '\x22', '\xFF',
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x00', '\x00', '\x00',
+ '\x33', '\x99', '\x44', '\x88', '\xCC', '\xBB', '\x66', '\x1C',
+ '\x99', '\x33', '\xFF', '\xCC', '\x88', '\x66', '\x77', '\x44',
+ '\x33', '\x99', '\x44', '\x88', '\xCC', '\xBB', '\x22', '\xFF'};
+ TElem* dataw = reinterpret_cast<TElem*>(&data);
+
+ for (unsigned dataItem = 0; dataItem < elemCount * 4; ++dataItem) {
+ TVectorType value = TFunc(dataw[dataItem]);
+
+ for (unsigned i = 0; i < elemCount; ++i)
+ UNIT_ASSERT_EQUAL(dataw[dataItem], TQType<TOp>::As(value)[i]);
+ }
+}
+
+void TSSEEmulTest::Test_mm_set1_epi8() {
+ Test_mm_setter_epiXX<i8, 16, Wrap(_mm_set1_epi8), int8x16_t, __m128i>();
+}
+void TSSEEmulTest::Test_mm_set1_epi16() {
+ Test_mm_setter_epiXX<i16, 8, Wrap(_mm_set1_epi16), int16x8_t, __m128i>();
+}
+void TSSEEmulTest::Test_mm_set1_epi32() {
+ Test_mm_setter_epiXX<i32, 4, Wrap(_mm_set1_epi32), int32x4_t, __m128i>();
+}
+void TSSEEmulTest::Test_mm_set1_ps() {
+ Test_mm_setter_epiXX<float, 4, WrapF(_mm_set1_ps), float32x4_t, __m128>();
+}
+
+void TSSEEmulTest::Test_mm_set_ps1() {
+ Test_mm_setter_epiXX<float, 4, WrapF(_mm_set_ps1), float32x4_t, __m128>();
+}
+
+void TSSEEmulTest::Test_mm_setzero_si128() {
+ __m128i value = _mm_setzero_si128();
+ for (unsigned i = 0; i < 4; ++i)
+ UNIT_ASSERT_EQUAL(0, TQType<uint32x4_t>::As(value)[i]);
+}
+
+void TSSEEmulTest::Test_mm_setzero_ps() {
+ __m128 value = _mm_setzero_ps();
+ for (unsigned i = 0; i < 4; ++i)
+ UNIT_ASSERT_EQUAL(0.0, TQType<float32x4_t>::As(value)[i]);
+}
+
+void TSSEEmulTest::Test_mm_setzero_pd() {
+ __m128d value = _mm_setzero_pd();
+ for (unsigned i = 0; i < 2; ++i)
+ UNIT_ASSERT_EQUAL(0.0, TQType<float64x2_t>::As(value)[i]);
+}
+
+void TSSEEmulTest::Test_mm_loadl_epi64() {
+ char data[64] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x00', '\x55', '\x77', '\x66', '\x1C',
+ '\x99', '\x33', '\x1C', '\x55', '\x88', '\x66', '\x77', '\x44',
+ '\x00', '\xAA', '\xAA', '\x11', '\xCC', '\xBB', '\x22', '\xFF',
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x00', '\x00', '\x00',
+ '\x33', '\x99', '\x44', '\x88', '\xCC', '\xBB', '\x66', '\x1C',
+ '\x99', '\x33', '\xFF', '\xCC', '\x88', '\x66', '\x77', '\x44',
+ '\x33', '\x99', '\x44', '\x88', '\xCC', '\xBB', '\x22', '\xFF'};
+ ui64* dataw = reinterpret_cast<ui64*>(&data);
+
+ for (unsigned dataItem = 0; dataItem < 8; ++dataItem) {
+ __m128i value = _mm_loadl_epi64((__m128i const*)&dataw[dataItem]);
+
+ UNIT_ASSERT_EQUAL(dataw[dataItem], TQType<uint64x2_t>::As(value)[0]);
+ UNIT_ASSERT_EQUAL(0, TQType<uint64x2_t>::As(value)[1]);
+ }
+}
+
+void TSSEEmulTest::Test_mm_storel_epi64() {
+ char data[64] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x00', '\x55', '\x77', '\x66', '\x1C',
+ '\x99', '\x33', '\x1C', '\x55', '\x88', '\x66', '\x77', '\x44',
+ '\x00', '\xAA', '\xAA', '\x11', '\xCC', '\xBB', '\x22', '\xFF',
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x00', '\x00', '\x00',
+ '\x33', '\x99', '\x44', '\x88', '\xCC', '\xBB', '\x66', '\x1C',
+ '\x99', '\x33', '\xFF', '\xCC', '\x88', '\x66', '\x77', '\x44',
+ '\x33', '\x99', '\x44', '\x88', '\xCC', '\xBB', '\x22', '\xFF'};
+ ui64* dataw = reinterpret_cast<ui64*>(&data);
+
+ for (unsigned dataItem = 0; dataItem < 4; ++dataItem) {
+ __m128i value = _mm_loadu_si128((__m128i*)&dataw[dataItem * 2]);
+
+ ui64 buf[2] = {55, 81};
+ _mm_storel_epi64((__m128i*)&buf, value);
+
+ UNIT_ASSERT_EQUAL(dataw[dataItem * 2], buf[0]);
+ UNIT_ASSERT_EQUAL(81, buf[1]);
+ }
+}
+
+void TSSEEmulTest::Test_mm_shuffle_epi32() {
+ char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ ui32* dataw = reinterpret_cast<ui32*>(&data);
+ __m128i value = _mm_loadu_si128((__m128i*)&data);
+
+ int coding[4] = {1, 3, 0, 2};
+ __m128i result = _mm_shuffle_epi32(value, _MM_SHUFFLE(2, 0, 3, 1));
+
+ for (unsigned i = 0; i < 4; ++i)
+ UNIT_ASSERT_EQUAL(dataw[coding[i]],
+ TQType<uint32x4_t>::As(result)[i]);
+}
+
+static int GetHighBitAt(char data, int at) {
+ ui8 udata = data & 0x80;
+ return int(udata >> 7) << at;
+}
+
+void TSSEEmulTest::Test_mm_movemask_epi8() {
+ char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ __m128i value = _mm_loadu_si128((__m128i*)&data);
+
+ int result = _mm_movemask_epi8(value);
+ int verify = 0;
+ for (unsigned i = 0; i < 16; ++i) {
+ verify |= GetHighBitAt(data[i], i);
+ }
+
+ UNIT_ASSERT_EQUAL(result, verify);
+}
+
+void TSSEEmulTest::Test_mm_movemask_ps() {
+ char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ __m128 value = _mm_loadu_ps((float*)&data);
+
+ int result = _mm_movemask_ps(value);
+ int verify = 0;
+ for (unsigned i = 0; i < 4; ++i) {
+ verify |= GetHighBitAt(data[i * 4 + 3], i);
+ }
+
+ UNIT_ASSERT_EQUAL(result, verify);
+}
+
+void TSSEEmulTest::Test_mm_movemask_ps_2() {
+ char data[16] = {
+ '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF',
+ '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF'};
+ __m128 value = _mm_loadu_ps((float*)&data);
+
+ int result = _mm_movemask_ps(value);
+ UNIT_ASSERT_EQUAL(result, 0xf);
+}
+
+void TSSEEmulTest::Test_mm_cvtsi128_si32() {
+ char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ __m128i value = _mm_loadu_si128((__m128i*)&data);
+
+ int result = _mm_cvtsi128_si32(value);
+ i32* datap = reinterpret_cast<i32*>(&data);
+ int verify = datap[0];
+
+ UNIT_ASSERT_EQUAL(result, verify);
+}
+
+void TSSEEmulTest::Test_mm_cvtsi128_si64() {
+ char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ __m128i value = _mm_loadu_si128((__m128i*)&data);
+
+ i64 result = _mm_cvtsi128_si64(value);
+ i64* datap = reinterpret_cast<i64*>(&data);
+ i64 verify = datap[0];
+
+ UNIT_ASSERT_EQUAL(result, verify);
+}
+
+void TSSEEmulTest::Test_mm_set_epi16() {
+ char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ i16* dataw = reinterpret_cast<i16*>(&data);
+ ui64* dataq = reinterpret_cast<ui64*>(&data);
+
+ __m128i result = _mm_set_epi16(dataw[7], dataw[6], dataw[5], dataw[4],
+ dataw[3], dataw[2], dataw[1], dataw[0]);
+ ui64 buf[2] = {53, 81};
+ _mm_storeu_si128((__m128i*)&buf, result);
+
+ UNIT_ASSERT_EQUAL(buf[0], dataq[0]);
+ UNIT_ASSERT_EQUAL(buf[1], dataq[1]);
+}
+
+void TSSEEmulTest::Test_mm_set_epi32() {
+ char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ i32* dataw = reinterpret_cast<i32*>(&data);
+ ui64* dataq = reinterpret_cast<ui64*>(&data);
+
+ __m128i result = _mm_set_epi32(dataw[3], dataw[2], dataw[1], dataw[0]);
+ ui64 buf[2] = {53, 81};
+ _mm_storeu_si128((__m128i*)&buf, result);
+
+ UNIT_ASSERT_EQUAL(buf[0], dataq[0]);
+ UNIT_ASSERT_EQUAL(buf[1], dataq[1]);
+}
+
+void TSSEEmulTest::Test_mm_set_ps() {
+ char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ float* dataw = reinterpret_cast<float*>(&data);
+ ui64* dataq = reinterpret_cast<ui64*>(&data);
+
+ __m128 result = _mm_set_ps(dataw[3], dataw[2], dataw[1], dataw[0]);
+ ui64 buf[2] = {53, 81};
+ _mm_storeu_ps((float*)&buf, result);
+
+ UNIT_ASSERT_EQUAL(buf[0], dataq[0]);
+ UNIT_ASSERT_EQUAL(buf[1], dataq[1]);
+}
+
+void TSSEEmulTest::Test_mm_set_pd() {
+ char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ double* dataw = reinterpret_cast<double*>(&data);
+ ui64* dataq = reinterpret_cast<ui64*>(&data);
+
+ __m128d result = _mm_set_pd(dataw[1], dataw[0]);
+ ui64 buf[2] = {53, 81};
+ _mm_storeu_pd((double*)&buf, result);
+
+ UNIT_ASSERT_EQUAL(buf[0], dataq[0]);
+ UNIT_ASSERT_EQUAL(buf[1], dataq[1]);
+}
+
+void TSSEEmulTest::Test_mm_cvtsi32_si128() {
+ char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ i32* dataw = reinterpret_cast<i32*>(&data);
+
+ __m128i result = _mm_cvtsi32_si128(dataw[0]);
+ i32 buf[4] = {53, 81, -43, 2132};
+ _mm_storeu_si128((__m128i*)&buf, result);
+
+ UNIT_ASSERT_EQUAL(buf[0], dataw[0]);
+ UNIT_ASSERT_EQUAL(buf[1], 0);
+ UNIT_ASSERT_EQUAL(buf[2], 0);
+ UNIT_ASSERT_EQUAL(buf[3], 0);
+}
+
+void TSSEEmulTest::Test_mm_cvtsi64_si128() {
+ char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ i64* dataw = reinterpret_cast<i64*>(&data);
+
+ __m128i result = _mm_cvtsi64_si128(dataw[0]);
+ i64 buf[2] = {7, 8};
+ _mm_storeu_si128((__m128i*)&buf, result);
+
+ UNIT_ASSERT_EQUAL(buf[0], dataw[0]);
+ UNIT_ASSERT_EQUAL(buf[1], 0);
+}
+
+template <typename TElem, typename TNarrow, unsigned elemCount, typename TFunc>
+void TSSEEmulTest::Test_mm_packs_epiXX() {
+ char data[32] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x00', '\x66', '\x1C',
+ '\x99', '\x33', '\x1C', '\x55', '\x00', '\x00', '\x00', '\x00',
+ '\x00', '\xAA', '\x00', '\x00', '\xCC', '\xBB', '\x22', '\xFF'};
+ __m128i value0 = _mm_loadu_si128((__m128i*)&data);
+ __m128i value1 = _mm_loadu_si128(((__m128i*)&data) + 1);
+ TElem* dataw = reinterpret_cast<TElem*>(&data);
+
+ __m128i result = TFunc(value0, value1);
+
+ TNarrow verify[elemCount];
+ for (unsigned i = 0; i < elemCount; ++i) {
+ TElem sum = dataw[i];
+ if (sum > std::numeric_limits<TNarrow>::max())
+ sum = std::numeric_limits<TNarrow>::max();
+ if (sum < std::numeric_limits<TNarrow>::min())
+ sum = std::numeric_limits<TNarrow>::min();
+ verify[i] = TNarrow(sum);
+ }
+
+ ui64* verifyp = (ui64*)&verify;
+ UNIT_ASSERT_EQUAL(verifyp[0], TQType<uint64x2_t>::As(result)[0]);
+ UNIT_ASSERT_EQUAL(verifyp[1], TQType<uint64x2_t>::As(result)[1]);
+}
+
+void TSSEEmulTest::Test_mm_packs_epi16() {
+ Test_mm_packs_epiXX<i16, i8, 16, Wrap(_mm_packs_epi16)>();
+}
+void TSSEEmulTest::Test_mm_packs_epi32() {
+ Test_mm_packs_epiXX<i32, i16, 8, Wrap(_mm_packs_epi32)>();
+}
+void TSSEEmulTest::Test_mm_packus_epi16() {
+ Test_mm_packs_epiXX<i16, ui8, 16, Wrap(_mm_packus_epi16)>();
+}
+
+void TSSEEmulTest::Test_mm_extract_epi8() {
+ alignas(16) char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ const ui8* dataw = reinterpret_cast<const ui8*>(&data);
+ const __m128i value = _mm_loadu_si128((__m128i*)&data);
+
+ UNIT_ASSERT_EQUAL((_mm_extract_epi16(value, 0)), int(dataw[0]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi8(value, 1)), int(dataw[1]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi8(value, 2)), int(dataw[2]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi8(value, 3)), int(dataw[3]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi8(value, 4)), int(dataw[4]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi8(value, 5)), int(dataw[5]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi8(value, 6)), int(dataw[6]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi8(value, 7)), int(dataw[7]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi8(value, 8)), int(dataw[8]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi8(value, 9)), int(dataw[9]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi8(value, 10)), int(dataw[10]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi8(value, 11)), int(dataw[11]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi8(value, 12)), int(dataw[12]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi8(value, 13)), int(dataw[13]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi8(value, 14)), int(dataw[14]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi8(value, 15)), int(dataw[15]));
+}
+
+void TSSEEmulTest::Test_mm_extract_epi16() {
+ alignas(16) char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ const ui16* dataw = reinterpret_cast<const ui16*>(&data);
+ const __m128i value = _mm_loadu_si128((__m128i*)&data);
+
+ UNIT_ASSERT_EQUAL((_mm_extract_epi16(value, 0)), int(dataw[0]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi16(value, 1)), int(dataw[1]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi16(value, 2)), int(dataw[2]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi16(value, 3)), int(dataw[3]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi16(value, 4)), int(dataw[4]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi16(value, 5)), int(dataw[5]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi16(value, 6)), int(dataw[6]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi16(value, 7)), int(dataw[7]));
+}
+
+void TSSEEmulTest::Test_mm_extract_epi64() {
+ alignas(16) char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ const ui64* dataw = reinterpret_cast<const ui64*>(&data);
+ const __m128i value = _mm_loadu_si128((__m128i*)&data);
+
+ UNIT_ASSERT_EQUAL((_mm_extract_epi64(value, 0)), (long long)(dataw[0]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi64(value, 1)), (long long)(dataw[1]));
+}
+
+void TSSEEmulTest::Test_mm_extract_epi32() {
+ alignas(16) char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ const ui32* dataw = reinterpret_cast<const ui32*>(&data);
+ const __m128i value = _mm_loadu_si128((__m128i*)&data);
+
+ UNIT_ASSERT_EQUAL((_mm_extract_epi32(value, 0)), int(dataw[0]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi32(value, 1)), int(dataw[1]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi32(value, 2)), int(dataw[2]));
+ UNIT_ASSERT_EQUAL((_mm_extract_epi32(value, 3)), int(dataw[3]));
+}
+
+void TSSEEmulTest::Test_MM_TRANSPOSE4_PS() {
+ char data0[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ char data1[16] = {
+ '\x99', '\x33', '\x1C', '\x55', '\x88', '\x66', '\x77', '\x44',
+ '\x00', '\xAA', '\xAA', '\x11', '\xCC', '\xBB', '\x22', '\xFF'};
+ char data2[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ char data3[16] = {
+ '\x99', '\x33', '\x1C', '\x55', '\x88', '\x66', '\x77', '\x44',
+ '\x00', '\xAA', '\xAA', '\x11', '\xCC', '\xBB', '\x22', '\xFF'};
+
+ __m128 value0 = _mm_loadu_ps((float*)&data0);
+ __m128 value1 = _mm_loadu_ps((float*)&data1);
+ __m128 value2 = _mm_loadu_ps((float*)&data2);
+ __m128 value3 = _mm_loadu_ps((float*)&data3);
+
+ _MM_TRANSPOSE4_PS(value0, value1, value2, value3);
+
+ ui64 tbuf0[2] = {0, 0};
+ ui64 tbuf1[2] = {0, 0};
+ ui64 tbuf2[2] = {0, 0};
+ ui64 tbuf3[2] = {0, 0};
+
+ _mm_storeu_ps((float*)&tbuf0, value0);
+ _mm_storeu_ps((float*)&tbuf1, value1);
+ _mm_storeu_ps((float*)&tbuf2, value2);
+ _mm_storeu_ps((float*)&tbuf3, value3);
+
+ char tdata0[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x99', '\x33', '\x1C', '\x55',
+ '\xAA', '\x00', '\xFF', '\xCC', '\x99', '\x33', '\x1C', '\x55'};
+ char tdata1[16] = {
+ '\x11', '\x22', '\xBB', '\xAA', '\x88', '\x66', '\x77', '\x44',
+ '\x11', '\x22', '\xBB', '\xAA', '\x88', '\x66', '\x77', '\x44'};
+ char tdata2[16] = {
+ '\x33', '\x99', '\x44', '\x88', '\x00', '\xAA', '\xAA', '\x11',
+ '\x33', '\x99', '\x44', '\x88', '\x00', '\xAA', '\xAA', '\x11'};
+ char tdata3[16] = {
+ '\x55', '\x77', '\x66', '\x1C', '\xCC', '\xBB', '\x22', '\xFF',
+ '\x55', '\x77', '\x66', '\x1C', '\xCC', '\xBB', '\x22', '\xFF'};
+
+ UNIT_ASSERT(memcmp(tbuf0, tdata0, 16) == 0);
+ UNIT_ASSERT(memcmp(tbuf1, tdata1, 16) == 0);
+ UNIT_ASSERT(memcmp(tbuf2, tdata2, 16) == 0);
+ UNIT_ASSERT(memcmp(tbuf3, tdata3, 16) == 0);
+}
+
+template <typename TFrom, typename TTo, unsigned elemCount,
+ typename TLoadVector, typename TResultVector,
+ typename TElemFunc, typename TFunc, typename TOp>
+void TSSEEmulTest::Test_mm_convertop() {
+ char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ TFrom* datap = reinterpret_cast<TFrom*>(&data);
+
+ TLoadVector value = TFuncLoad<TLoadVector>(&data);
+
+ TTo procData[elemCount];
+ for (unsigned i = 0; i < elemCount; ++i) {
+ procData[i] = TElemFunc::Call(datap[i]);
+ }
+
+ TResultVector result = TFunc(value);
+
+ for (unsigned i = 0; i < elemCount; ++i) {
+ UNIT_ASSERT_EQUAL(procData[i], TQType<TOp>::As(result)[i]);
+ }
+}
+
+void TSSEEmulTest::Test_mm_cvtepi32_ps() {
+ struct THelper {
+ static float Call(const i32 op) {
+ return float(op);
+ }
+ };
+ Test_mm_convertop<i32, float, 4, __m128i, __m128,
+ THelper, WrapF(_mm_cvtepi32_ps), float32x4_t>();
+};
+
+void TSSEEmulTest::Test_mm_cvtps_epi32() {
+ struct THelper {
+ static i32 Call(const float op) {
+ return i32(op);
+ }
+ };
+ Test_mm_convertop<float, i32, 4, __m128, __m128i,
+ THelper, T_mm_CallWrapper<__m128i, decltype(_mm_cvtps_epi32), _mm_cvtps_epi32>, int32x4_t>();
+};
+
+void TSSEEmulTest::Test_mm_cvttps_epi32() {
+ struct THelper {
+ static i32 Call(const float op) {
+ return i32(op);
+ }
+ };
+ Test_mm_convertop<float, i32, 4, __m128, __m128i,
+ THelper, Wrap(_mm_cvttps_epi32), int32x4_t>();
+};
+
+template <typename TLoadVector, typename TCastVector,
+ typename TFunc, TFunc* func>
+void TSSEEmulTest::Test_mm_castXX() {
+ char data[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+
+ TLoadVector value = TFuncLoad<TLoadVector>(&data);
+ const TLoadVector constvalue = TFuncLoad<TLoadVector>(&data);
+ TCastVector casted = func(value);
+ const TCastVector constcasted = func(constvalue);
+ char verify[16];
+ char constverify[16];
+ TFuncStore<TCastVector>(&verify, casted);
+ TFuncStore<TCastVector>(&constverify, constcasted);
+
+ UNIT_ASSERT(memcmp(&data, &verify, 16) == 0);
+ UNIT_ASSERT(memcmp(&data, &constverify, 16) == 0);
+};
+
+void TSSEEmulTest::Test_mm_castsi128_ps() {
+ Test_mm_castXX<__m128i, __m128,
+ decltype(_mm_castsi128_ps), _mm_castsi128_ps>();
+}
+
+void TSSEEmulTest::Test_mm_castps_si128() {
+ Test_mm_castXX<__m128, __m128i,
+ decltype(_mm_castps_si128), _mm_castps_si128>();
+}
+
+void TSSEEmulTest::Test_mm_mul_epu32() {
+ char data0[16] = {
+ '\xAA', '\x00', '\xFF', '\xCC', '\x11', '\x22', '\xBB', '\xAA',
+ '\x33', '\x99', '\x44', '\x88', '\x55', '\x77', '\x66', '\x1C'};
+ char data1[16] = {
+ '\x99', '\x33', '\x1C', '\x55', '\x88', '\x66', '\x77', '\x44',
+ '\x00', '\xAA', '\xAA', '\x11', '\xCC', '\xBB', '\x22', '\xFF'};
+ ui32* dataw0 = reinterpret_cast<ui32*>(&data0);
+ ui32* dataw1 = reinterpret_cast<ui32*>(&data1);
+
+ __m128i value0 = _mm_loadu_si128((__m128i*)&data0);
+ __m128i value1 = _mm_loadu_si128((__m128i*)&data1);
+
+ ui64 mul0 = (ui64) dataw0[0] * (ui64) dataw1[0];
+ ui64 mul1 = (ui64) dataw0[2] * (ui64) dataw1[2];
+
+ __m128i result = _mm_mul_epu32(value0, value1);
+
+ UNIT_ASSERT_EQUAL(mul0, TQType<uint64x2_t>::As(result)[0]);
+ UNIT_ASSERT_EQUAL(mul1, TQType<uint64x2_t>::As(result)[1]);
+}
+
+void TSSEEmulTest::Test_mm_cmpunord_ps() {
+ alignas(16) float valuesBits[4] = {1.f, 2.f, 3.f, 4.f};
+ alignas(16) float values2Bits[4] = {5.f, 6.f, 7.f, 8.f};
+
+ alignas(16) char allfs[16] = {
+ '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff',
+ '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff'
+ };
+
+ alignas(16) char allzeroes[16] = {
+ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
+ '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'
+ };
+
+ const __m128 qnan = _mm_set_ps1(std::numeric_limits<float>::quiet_NaN());
+ const __m128 snan = _mm_set_ps1(std::numeric_limits<float>::signaling_NaN());
+ const __m128 values = _mm_loadu_ps((const float*) valuesBits);
+ const __m128 values2 = _mm_loadu_ps((const float*) values2Bits);
+
+ const __m128 mask1 = _mm_cmpunord_ps(qnan, qnan);
+ UNIT_ASSERT_EQUAL(::memcmp(&mask1, &allfs, sizeof(allfs)), 0);
+
+ const __m128 mask2 = _mm_cmpunord_ps(values, values);
+ UNIT_ASSERT_EQUAL(::memcmp(&mask2, &allzeroes, sizeof(allzeroes)), 0);
+
+ const __m128 mask3 = _mm_cmpunord_ps(snan, snan);
+ UNIT_ASSERT_EQUAL(::memcmp(&mask3, &allfs, sizeof(allfs)), 0);
+
+ const __m128 mask4 = _mm_cmpunord_ps(qnan, values);
+ UNIT_ASSERT_EQUAL(::memcmp(&mask4, &allfs, sizeof(allfs)), 0);
+
+ const __m128 mask5 = _mm_cmpunord_ps(snan, values);
+ UNIT_ASSERT_EQUAL(::memcmp(&mask5, &allfs, sizeof(allfs)), 0);
+
+ const __m128 mask6 = _mm_cmpunord_ps(qnan, snan);
+ UNIT_ASSERT_EQUAL(::memcmp(&mask6, &allfs, sizeof(allfs)), 0);
+
+ const __m128 mask7 = _mm_cmpunord_ps(values, values2);
+ UNIT_ASSERT_EQUAL(::memcmp(&mask7, &allzeroes, sizeof(allzeroes)), 0);
+}
+
+void TSSEEmulTest::Test_mm_store_ss() {
+ alignas(16) const float valueBits[4] = {1.f, 2.f, 3.f, 4.f};
+ const __m128 value = _mm_loadu_ps(valueBits);
+ float res = std::numeric_limits<float>::signaling_NaN();
+ _mm_store_ss(&res, value);
+ UNIT_ASSERT_EQUAL(res, 1.f);
+}
+
+void TSSEEmulTest::Test_mm_store_ps() {
+ alignas(16) const float valueBits[4] = {1.f, 2.f, 3.f, 4.f};
+ const __m128 value = _mm_loadu_ps(valueBits);
+ float res[4] = {0.f};
+ _mm_storeu_ps(res, value);
+ UNIT_ASSERT_EQUAL(res[0], 1.f);
+ UNIT_ASSERT_EQUAL(res[1], 2.f);
+ UNIT_ASSERT_EQUAL(res[2], 3.f);
+ UNIT_ASSERT_EQUAL(res[3], 4.f);
+}
+
+void TSSEEmulTest::Test_mm_storeu_pd() {
+ alignas(16) const double valueBits[4] = {1., 2., 3., 4.};
+ for (size_t i = 0; i != 3; ++i) {
+ const __m128d value = _mm_loadu_pd(&valueBits[i]);
+ alignas(16) double res[4];
+ for (size_t shift = 0; shift != 3; ++shift) {
+ _mm_storeu_pd(&res[shift], value);
+ for (size_t j = 0; j != 2; ++j) {
+ UNIT_ASSERT_EQUAL_C(res[j + shift], valueBits[i + j], "res: " << HexEncode(&res[shift], 16) << " vs etalon: " << HexEncode(&valueBits[i], 16));
+ }
+ }
+ }
+}
+
+void TSSEEmulTest::Test_mm_andnot_ps() {
+ alignas(16) const char firstBits[16] = {
+ '\x00', '\x00', '\xff', '\xff', '\x00', '\x00', '\xff', '\xff',
+ '\x00', '\x00', '\xff', '\xff', '\x00', '\x00', '\xff', '\xff'
+ };
+
+ alignas(16) const char secondBits[16] = {
+ '\x00', '\xff', '\x00', '\xff', '\x00', '\xff', '\x00', '\xff',
+ '\x00', '\xff', '\x00', '\xff', '\x00', '\xff', '\x00', '\xff'
+ };
+
+ alignas(16) const char resBits[16] = {
+ '\x00', '\xff', '\x00', '\x00', '\x00', '\xff', '\x00', '\x00',
+ '\x00', '\xff', '\x00', '\x00', '\x00', '\xff', '\x00', '\x00'
+ };
+
+ const __m128 value1 = _mm_loadu_ps((const float*) firstBits);
+ const __m128 value2 = _mm_loadu_ps((const float*) secondBits);
+ const __m128 res = _mm_andnot_ps(value1, value2);
+
+ UNIT_ASSERT_EQUAL(::memcmp(&res, resBits, sizeof(resBits)), 0);
+}
+
+void TSSEEmulTest::Test_mm_shuffle_ps() {
+ alignas(16) const float first[4] = {1.f, 2.f, 3.f, 4.f};
+ alignas(16) const float second[4] = {5.f, 6.f, 7.f, 8.f};
+ alignas(16) const float etalon[4] = {3.f, 4.f, 5.f, 6.f};
+
+ const __m128 value1 = _mm_loadu_ps(first);
+ const __m128 value2 = _mm_loadu_ps(second);
+ const __m128 res = _mm_shuffle_ps(value1, value2, _MM_SHUFFLE(1, 0, 3, 2));
+
+ UNIT_ASSERT_EQUAL(::memcmp(&res, etalon, sizeof(etalon)), 0);
+}
+
+void TSSEEmulTest::Test_mm_shuffle_pd() {
+ const double first[2] = {1.3, 2.3};
+ const double second[2] = {5.3, 6.3};
+ const double etalon0[2] = {1.3, 5.3};
+ const double etalon1[2] = {2.3, 5.3};
+ const double etalon2[2] = {1.3, 6.3};
+ const double etalon3[2] = {2.3, 6.3};
+
+ const __m128d value1 = _mm_loadu_pd(first);
+ const __m128d value2 = _mm_loadu_pd(second);
+
+ __m128d res = _mm_shuffle_pd(value1, value2, 0);
+ UNIT_ASSERT_EQUAL(::memcmp(&res, etalon0, sizeof(etalon0)), 0);
+
+ res = _mm_shuffle_pd(value1, value2, 1);
+ UNIT_ASSERT_EQUAL(::memcmp(&res, etalon1, sizeof(etalon1)), 0);
+
+ res = _mm_shuffle_pd(value1, value2, 2);
+ UNIT_ASSERT_EQUAL(::memcmp(&res, etalon2, sizeof(etalon2)), 0);
+
+ res = _mm_shuffle_pd(value1, value2, 3);
+ UNIT_ASSERT_EQUAL(::memcmp(&res, etalon3, sizeof(etalon3)), 0);
+}
+
+void TSSEEmulTest::Test_mm_cvtsd_f64() {
+ const double first[2] = {1.3, 2.3};
+ const double second[2] = {5.3, 6.3};
+
+ const __m128d value1 = _mm_loadu_pd(first);
+ const __m128d value2 = _mm_loadu_pd(second);
+
+ UNIT_ASSERT_EQUAL(_mm_cvtsd_f64(value1), 1.3);
+ UNIT_ASSERT_EQUAL(_mm_cvtsd_f64(value2), 5.3);
+}
+
+void TSSEEmulTest::Test_mm_loadl_pd() {
+ const double first[2] = {1.3, 2.3};
+ const double second[2] = {5.3, 6.3};
+ const double firstEtalon[2] = {10.13, 2.3};
+ const double secondEtalon[2] = {11.13, 6.3};
+
+ double newFirst = 10.13;
+ double newSecond = 11.13;
+
+ __m128d value1 = _mm_loadu_pd(first);
+ __m128d value2 = _mm_loadu_pd(second);
+ value1 = _mm_loadl_pd(value1, &newFirst);
+ value2 = _mm_loadl_pd(value2, &newSecond);
+ UNIT_ASSERT_EQUAL(::memcmp(&value1, firstEtalon, sizeof(firstEtalon)), 0);
+ UNIT_ASSERT_EQUAL(::memcmp(&value2, secondEtalon, sizeof(secondEtalon)), 0);
+}
+
+void TSSEEmulTest::Test_mm_loadh_pd() {
+ const double first[2] = {1.3, 2.3};
+ const double second[2] = {5.3, 6.3};
+ const double firstEtalon[2] = {1.3, 10.13};
+ const double secondEtalon[2] = {5.3, 11.13};
+
+ double newFirst = 10.13;
+ double newSecond = 11.13;
+
+ __m128d value1 = _mm_loadu_pd(first);
+ __m128d value2 = _mm_loadu_pd(second);
+ value1 = _mm_loadh_pd(value1, &newFirst);
+ value2 = _mm_loadh_pd(value2, &newSecond);
+ UNIT_ASSERT_EQUAL(::memcmp(&value1, firstEtalon, sizeof(firstEtalon)), 0);
+ UNIT_ASSERT_EQUAL(::memcmp(&value2, secondEtalon, sizeof(secondEtalon)), 0);
+}
+
+void TSSEEmulTest::Test_mm_or_ps() {
+ alignas(16) const char bytes1[16] = {
+ '\x00', '\x00', '\xff', '\xff', '\x00', '\x00', '\xff', '\xff',
+ '\x00', '\x00', '\xff', '\xff', '\x00', '\x00', '\xff', '\xff'
+ };
+
+ alignas(16) const char bytes2[16] = {
+ '\x00', '\xff', '\x00', '\xff', '\x00', '\xff', '\x00', '\xff',
+ '\x00', '\xff', '\x00', '\xff', '\x00', '\xff', '\x00', '\xff'
+ };
+
+ alignas(16) const char etalon[16] = {
+ '\x00', '\xff', '\xff', '\xff', '\x00', '\xff', '\xff', '\xff',
+ '\x00', '\xff', '\xff', '\xff', '\x00', '\xff', '\xff', '\xff'
+ };
+
+ const __m128 value1 = _mm_loadu_ps((const float*) bytes1);
+ const __m128 value2 = _mm_loadu_ps((const float*) bytes2);
+ const __m128 res = _mm_or_ps(value1, value2);
+
+ UNIT_ASSERT_EQUAL(::memcmp(&res, etalon, sizeof(etalon)), 0);
+}
+
+void TSSEEmulTest::Test_mm_loadu_pd() {
+ alignas(16) double stub[4] = {
+ 0.f, 1.f,
+ 2.f, 3.f
+ };
+
+ for (size_t shift = 0; shift != 3; ++shift) {
+ const __m128d val = _mm_loadu_pd(&stub[shift]);
+ alignas(16) double res[2];
+ _mm_store_pd(res, val);
+
+ for (size_t i = 0; i != 2; ++i) {
+ UNIT_ASSERT_EQUAL_C(res[i], stub[shift + i], "res: " << HexEncode(res, 16) << " vs etalon: " << HexEncode(&stub[shift], 16));
+ }
+ }
+}
+
+void TSSEEmulTest::Test_mm_rsqrt_ps() {
+ alignas(16) const char bytes[16] = {
+ '\x00', '\x00', '\x28', '\x42', // 42.f
+ '\x00', '\x98', '\x84', '\x45', // 4243.f
+ '\x60', '\x26', '\xcf', '\x48', // 424243.f
+ '\xed', '\xd5', '\x21', '\x4c' // 42424243.f
+ };
+ const __m128 value = _mm_loadu_ps((const float*)bytes);
+ const __m128 result = _mm_rsqrt_ps(value);
+ alignas(16) float res[4];
+ _mm_store_ps(res, result);
+ float fResult = 0.f;
+ for (size_t i = 0; i < 4; ++i) {
+ memcpy(&fResult, &bytes[i * 4], 4);
+ fResult = 1.f / std::sqrt(fResult);
+ UNIT_ASSERT_DOUBLES_EQUAL_C(res[i], fResult, 1e-3, "res: " << fResult << " vs etalon " << res[i]);
+ }
+}
+
+namespace NHelpers {
+
+ static __m128i Y_FORCE_INLINE GetCmp16(const __m128 &c0, const __m128 &c1, const __m128 &c2, const __m128 &c3, const __m128 test) {
+ const __m128i r0 = _mm_castps_si128(_mm_cmpgt_ps(c0, test));
+ const __m128i r1 = _mm_castps_si128(_mm_cmpgt_ps(c1, test));
+ const __m128i r2 = _mm_castps_si128(_mm_cmpgt_ps(c2, test));
+ const __m128i r3 = _mm_castps_si128(_mm_cmpgt_ps(c3, test));
+ const __m128i packed = _mm_packs_epi16(_mm_packs_epi32(r0, r1), _mm_packs_epi32(r2, r3));
+ return _mm_and_si128(_mm_set1_epi8(0x01), packed);
+ }
+
+ static __m128i Y_FORCE_INLINE GetCmp16(const float *factors, const __m128 test) {
+ const __m128 *ptr = (__m128 *)factors;
+ return GetCmp16(ptr[0], ptr[1], ptr[2], ptr[3], test);
+ }
+
+ template<size_t Num>
+ void DoLane(size_t length, const float *factors, ui32 *& dst, const float *&values) {
+ for (size_t i = 0; i < length; ++i) {
+ __m128 value = _mm_set1_ps(values[i]);
+ __m128i agg = GetCmp16(factors, value);
+ if (Num > 1) {
+ agg = _mm_add_epi16(agg, _mm_slli_epi16(GetCmp16(&factors[64], value), 1));
+ }
+ _mm_store_si128((__m128i *)&dst[4 * i], agg);
+ }
+ }
+}
+
+void TSSEEmulTest::Test_matrixnet_powerpc() {
+ static constexpr size_t length = 10;
+ alignas(16) float factors[1024];
+ alignas(16) ui32 valP[4 * length] = { 0 };
+ float values[length];
+ TReallyFastRng32 rng(42);
+ for (size_t i = 0; i < 1024; ++i) {
+ factors[i] = rng.GenRandReal2();
+ }
+ for (size_t i = 0; i < length; ++i) {
+ values[i] = rng.GenRandReal2();
+ }
+ ui32* val = reinterpret_cast<ui32*>(valP);
+ const float* vals = reinterpret_cast<const float*>(values);
+ NHelpers::DoLane<2>(length, factors, val, vals);
+ static const ui32 etalon[4 * length] = {
+ 2, 33554432, 258, 33554433, 50529027,
+ 50529027, 50529027, 50529027, 50528770,
+ 33685763, 33555203, 50462723, 50528770,
+ 33685763, 33555203, 50462723, 50529026,
+ 33751299, 50529027, 50463491, 2, 33554432,
+ 258, 33554433, 50397698, 33685761, 259,
+ 50462721, 50332162, 33554689, 259, 50462721,
+ 50528770, 33685761, 33555203, 50462723,
+ 50529026, 33685763, 50463491, 50463235
+ };
+ for (size_t i = 0; i < 4 * length; ++i) {
+ UNIT_ASSERT_EQUAL(valP[i], etalon[i]);
+ }
+}
diff --git a/library/cpp/sse/ut/ya.make b/library/cpp/sse/ut/ya.make
new file mode 100644
index 0000000000..45e104971e
--- /dev/null
+++ b/library/cpp/sse/ut/ya.make
@@ -0,0 +1,13 @@
+UNITTEST_FOR(library/cpp/sse)
+
+OWNER(danlark)
+
+SRCS(
+ test.cpp
+)
+
+IF (ARCH_X86_64)
+ CFLAGS(-msse4.1 -msse4.2)
+ENDIF()
+
+END()
diff --git a/library/cpp/sse/ya.make b/library/cpp/sse/ya.make
new file mode 100644
index 0000000000..d2351e791d
--- /dev/null
+++ b/library/cpp/sse/ya.make
@@ -0,0 +1,12 @@
+LIBRARY()
+
+OWNER(
+ g:base
+ danlark
+)
+
+SRCS(
+ sse.cpp
+)
+
+END()
diff --git a/library/cpp/streams/brotli/brotli.cpp b/library/cpp/streams/brotli/brotli.cpp
new file mode 100644
index 0000000000..38052cb688
--- /dev/null
+++ b/library/cpp/streams/brotli/brotli.cpp
@@ -0,0 +1,231 @@
+#include "brotli.h"
+
+#include <contrib/libs/brotli/include/brotli/decode.h>
+#include <contrib/libs/brotli/include/brotli/encode.h>
+
+#include <util/generic/yexception.h>
+#include <util/memory/addstorage.h>
+
+namespace {
+ struct TAllocator {
+ static void* Allocate(void* /* opaque */, size_t size) {
+ return ::operator new(size);
+ }
+
+ static void Deallocate(void* /* opaque */, void* ptr) noexcept {
+ ::operator delete(ptr);
+ }
+ };
+
+}
+
+class TBrotliCompress::TImpl {
+public:
+ TImpl(IOutputStream* slave, int quality)
+ : Slave_(slave)
+ , EncoderState_(BrotliEncoderCreateInstance(&TAllocator::Allocate, &TAllocator::Deallocate, nullptr))
+ {
+ if (!EncoderState_) {
+ ythrow yexception() << "Brotli encoder initialization failed";
+ }
+
+ auto res = BrotliEncoderSetParameter(
+ EncoderState_,
+ BROTLI_PARAM_QUALITY,
+ quality);
+
+ if (!res) {
+ BrotliEncoderDestroyInstance(EncoderState_);
+ ythrow yexception() << "Failed to set brotli encoder quality to " << quality;
+ }
+ }
+
+ ~TImpl() {
+ BrotliEncoderDestroyInstance(EncoderState_);
+ }
+
+ void Write(const void* buffer, size_t size) {
+ DoWrite(buffer, size, BROTLI_OPERATION_PROCESS);
+ }
+
+ void Flush() {
+ DoWrite(nullptr, 0, BROTLI_OPERATION_FLUSH);
+ }
+
+ void Finish() {
+ Flush();
+ DoWrite(nullptr, 0, BROTLI_OPERATION_FINISH);
+ Y_VERIFY(BrotliEncoderIsFinished(EncoderState_));
+ }
+
+private:
+ IOutputStream* Slave_;
+ BrotliEncoderState* EncoderState_;
+
+ void DoWrite(const void* buffer, size_t size, BrotliEncoderOperation operation) {
+ size_t availableOut = 0;
+ ui8* outputBuffer = nullptr;
+
+ const ui8* uBuffer = static_cast<const ui8*>(buffer);
+
+ do {
+ auto result = BrotliEncoderCompressStream(
+ EncoderState_,
+ operation,
+ &size,
+ &uBuffer,
+ &availableOut,
+ &outputBuffer,
+ nullptr);
+
+ if (result == BROTLI_FALSE) {
+ ythrow yexception() << "Brotli encoder failed to process buffer";
+ }
+
+ size_t outputLength = 0;
+ const ui8* output = BrotliEncoderTakeOutput(EncoderState_, &outputLength);
+ if (outputLength > 0) {
+ Slave_->Write(output, outputLength);
+ }
+ } while (size > 0 || BrotliEncoderHasMoreOutput(EncoderState_));
+ }
+};
+
+TBrotliCompress::TBrotliCompress(IOutputStream* slave, int quality) {
+ Impl_.Reset(new TImpl(slave, quality));
+}
+
+TBrotliCompress::~TBrotliCompress() {
+ try {
+ Finish();
+ } catch (...) {
+ }
+}
+
+void TBrotliCompress::DoWrite(const void* buffer, size_t size) {
+ Impl_->Write(buffer, size);
+}
+
+void TBrotliCompress::DoFlush() {
+ if (Impl_) {
+ Impl_->Flush();
+ }
+}
+
+void TBrotliCompress::DoFinish() {
+ THolder<TImpl> impl(Impl_.Release());
+
+ if (impl) {
+ impl->Finish();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TBrotliDecompress::TImpl: public TAdditionalStorage<TImpl> {
+public:
+ TImpl(IInputStream* slave)
+ : Slave_(slave)
+ {
+ InitDecoder();
+ }
+
+ ~TImpl() {
+ FreeDecoder();
+ }
+
+ size_t Read(void* buffer, size_t size) {
+ Y_ASSERT(size > 0);
+
+ ui8* outBuffer = static_cast<ui8*>(buffer);
+ size_t availableOut = size;
+ size_t decompressedSize = 0;
+
+ BrotliDecoderResult result;
+ do {
+ if (InputAvailable_ == 0 && !InputExhausted_) {
+ InputBuffer_ = TmpBuf();
+ InputAvailable_ = Slave_->Read((void*)InputBuffer_, TmpBufLen());
+ if (InputAvailable_ == 0) {
+ InputExhausted_ = true;
+ }
+ }
+
+ if (SubstreamFinished_ && !InputExhausted_) {
+ ResetState();
+ }
+
+ result = BrotliDecoderDecompressStream(
+ DecoderState_,
+ &InputAvailable_,
+ &InputBuffer_,
+ &availableOut,
+ &outBuffer,
+ nullptr);
+
+ decompressedSize = size - availableOut;
+ SubstreamFinished_ = (result == BROTLI_DECODER_RESULT_SUCCESS);
+
+ if (result == BROTLI_DECODER_RESULT_ERROR) {
+ BrotliDecoderErrorCode code = BrotliDecoderGetErrorCode(DecoderState_);
+ ythrow yexception() << "Brotli decoder failed to decompress buffer: "
+ << BrotliDecoderErrorString(code);
+ } else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
+ Y_VERIFY(availableOut != size,
+ "Buffer passed to read in Brotli decoder is too small");
+ break;
+ }
+ } while (decompressedSize == 0 && result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT && !InputExhausted_);
+
+ if (!SubstreamFinished_ && decompressedSize == 0) {
+ ythrow yexception() << "Input stream is incomplete";
+ }
+
+ return decompressedSize;
+ }
+
+private:
+ IInputStream* Slave_;
+ BrotliDecoderState* DecoderState_;
+
+ bool SubstreamFinished_ = false;
+ bool InputExhausted_ = false;
+ const ui8* InputBuffer_ = nullptr;
+ size_t InputAvailable_ = 0;
+
+ unsigned char* TmpBuf() noexcept {
+ return static_cast<unsigned char*>(AdditionalData());
+ }
+
+ size_t TmpBufLen() const noexcept {
+ return AdditionalDataLength();
+ }
+
+ void InitDecoder() {
+ DecoderState_ = BrotliDecoderCreateInstance(&TAllocator::Allocate, &TAllocator::Deallocate, nullptr);
+ if (!DecoderState_) {
+ ythrow yexception() << "Brotli decoder initialization failed";
+ }
+ }
+
+ void FreeDecoder() {
+ BrotliDecoderDestroyInstance(DecoderState_);
+ }
+
+ void ResetState() {
+ Y_VERIFY(BrotliDecoderIsFinished(DecoderState_));
+ FreeDecoder();
+ InitDecoder();
+ }
+};
+
+TBrotliDecompress::TBrotliDecompress(IInputStream* slave, size_t bufferSize)
+ : Impl_(new (bufferSize) TImpl(slave))
+{
+}
+
+TBrotliDecompress::~TBrotliDecompress() = default;
+
+size_t TBrotliDecompress::DoRead(void* buffer, size_t size) {
+ return Impl_->Read(buffer, size);
+}
diff --git a/library/cpp/streams/brotli/brotli.h b/library/cpp/streams/brotli/brotli.h
new file mode 100644
index 0000000000..b3af869e29
--- /dev/null
+++ b/library/cpp/streams/brotli/brotli.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/stream/input.h>
+#include <util/stream/output.h>
+
+/**
+ * @addtogroup Streams_Archs
+ * @{
+ */
+
+class TBrotliCompress: public IOutputStream {
+public:
+ static constexpr int BEST_QUALITY = 11;
+
+ /**
+ @param slave stream to write compressed data to
+ @param quality the higher the quality, the slower and better the compression. Range is 0 to 11.
+ */
+ explicit TBrotliCompress(IOutputStream* slave, int quality = BEST_QUALITY);
+ ~TBrotliCompress() override;
+
+private:
+ void DoWrite(const void* buffer, size_t size) override;
+ void DoFlush() override;
+ void DoFinish() override;
+
+public:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TBrotliDecompress: public IInputStream {
+public:
+ /**
+ @param slave stream to read compressed data from
+ @param bufferSize approximate size of buffer compressed data is read in
+ */
+ explicit TBrotliDecompress(IInputStream* slave, size_t bufferSize = 8 * 1024);
+ ~TBrotliDecompress() override;
+
+private:
+ size_t DoRead(void* buffer, size_t size) override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+/** @} */
diff --git a/library/cpp/streams/brotli/brotli_ut.cpp b/library/cpp/streams/brotli/brotli_ut.cpp
new file mode 100644
index 0000000000..aeb2e284dc
--- /dev/null
+++ b/library/cpp/streams/brotli/brotli_ut.cpp
@@ -0,0 +1,89 @@
+#include "brotli.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/random/fast.h>
+
+Y_UNIT_TEST_SUITE(TBrotliTestSuite) {
+ TString Compress(TString data) {
+ TString compressed;
+ TStringOutput output(compressed);
+ TBrotliCompress compressStream(&output, 11);
+ compressStream.Write(data.data(), data.size());
+ compressStream.Finish();
+ output.Finish();
+ return compressed;
+ }
+
+ TString Decompress(TString data) {
+ TStringInput input(data);
+ TBrotliDecompress decompressStream(&input);
+ return decompressStream.ReadAll();
+ }
+
+ void TestCase(const TString& s) {
+ UNIT_ASSERT_VALUES_EQUAL(s, Decompress(Compress(s)));
+ }
+
+ TString GenerateRandomString(size_t size) {
+ TReallyFastRng32 rng(42);
+ TString result;
+ result.reserve(size + sizeof(ui64));
+ while (result.size() < size) {
+ ui64 value = rng.GenRand64();
+ result += TStringBuf(reinterpret_cast<const char*>(&value), sizeof(value));
+ }
+ result.resize(size);
+ return result;
+ }
+
+ Y_UNIT_TEST(TestHelloWorld) {
+ TestCase("hello world");
+ }
+
+ Y_UNIT_TEST(TestFlush) {
+ TStringStream ss;
+ TBrotliCompress compressStream(&ss);
+ TBrotliDecompress decompressStream(&ss);
+
+ for (size_t i = 0; i < 3; ++i) {
+ TString s = GenerateRandomString(1 << 15);
+ compressStream.Write(s.data(), s.size());
+ compressStream.Flush();
+
+ TString r(s.size(), '*');
+ decompressStream.Load((char*)r.data(), r.size());
+
+ UNIT_ASSERT_VALUES_EQUAL(s, r);
+ }
+ }
+
+ Y_UNIT_TEST(TestSeveralStreams) {
+ auto s1 = GenerateRandomString(1 << 15);
+ auto s2 = GenerateRandomString(1 << 15);
+ auto c1 = Compress(s1);
+ auto c2 = Compress(s2);
+ UNIT_ASSERT_VALUES_EQUAL(s1 + s2, Decompress(c1 + c2));
+ }
+
+ Y_UNIT_TEST(TestIncompleteStream) {
+ TString manyAs(64 * 1024, 'a');
+ auto compressed = Compress(manyAs);
+ TString truncated(compressed.data(), compressed.size() - 1);
+ UNIT_CHECK_GENERATED_EXCEPTION(Decompress(truncated), std::exception);
+ }
+
+ Y_UNIT_TEST(Test64KB) {
+ auto manyAs = TString(64 * 1024, 'a');
+ TString str("Hello from the Matrix!@#% How are you?}{\n\t\a");
+ TestCase(manyAs + str + manyAs);
+ }
+
+ Y_UNIT_TEST(Test1MB) {
+ TestCase(GenerateRandomString(1 * 1024 * 1024));
+ }
+
+ Y_UNIT_TEST(TestEmpty) {
+ TestCase("");
+ }
+}
diff --git a/library/cpp/streams/brotli/ut/ya.make b/library/cpp/streams/brotli/ut/ya.make
new file mode 100644
index 0000000000..243462f1b2
--- /dev/null
+++ b/library/cpp/streams/brotli/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/streams/brotli)
+
+OWNER(
+ levysotsky
+ g:util
+)
+
+SRCS(
+ brotli_ut.cpp
+)
+
+END()
diff --git a/library/cpp/streams/brotli/ya.make b/library/cpp/streams/brotli/ya.make
new file mode 100644
index 0000000000..fa2bfec9cc
--- /dev/null
+++ b/library/cpp/streams/brotli/ya.make
@@ -0,0 +1,17 @@
+LIBRARY()
+
+OWNER(
+ levysotsky
+ g:util
+)
+
+PEERDIR(
+ contrib/libs/brotli/enc
+ contrib/libs/brotli/dec
+)
+
+SRCS(
+ brotli.cpp
+)
+
+END()
diff --git a/library/cpp/streams/bzip2/bzip2.cpp b/library/cpp/streams/bzip2/bzip2.cpp
new file mode 100644
index 0000000000..bccc5c6807
--- /dev/null
+++ b/library/cpp/streams/bzip2/bzip2.cpp
@@ -0,0 +1,204 @@
+#include "bzip2.h"
+
+#include <util/memory/addstorage.h>
+#include <util/generic/scope.h>
+
+#include <contrib/libs/libbz2/bzlib.h>
+
+class TBZipDecompress::TImpl: public TAdditionalStorage<TImpl> {
+public:
+ inline TImpl(IInputStream* input)
+ : Stream_(input)
+ {
+ Zero(BzStream_);
+ Init();
+ }
+
+ inline ~TImpl() {
+ Clear();
+ }
+
+ inline void Init() {
+ if (BZ2_bzDecompressInit(&BzStream_, 0, 0) != BZ_OK) {
+ ythrow TBZipDecompressError() << "can not init bzip engine";
+ }
+ }
+
+ inline void Clear() noexcept {
+ BZ2_bzDecompressEnd(&BzStream_);
+ }
+
+ inline size_t Read(void* buf, size_t size) {
+ BzStream_.next_out = (char*)buf;
+ BzStream_.avail_out = size;
+
+ while (true) {
+ if (BzStream_.avail_in == 0) {
+ if (FillInputBuffer() == 0) {
+ return 0;
+ }
+ }
+
+ switch (BZ2_bzDecompress(&BzStream_)) {
+ case BZ_STREAM_END: {
+ Clear();
+ Init();
+ [[fallthrough]];
+ }
+
+ case BZ_OK: {
+ const size_t processed = size - BzStream_.avail_out;
+
+ if (processed) {
+ return processed;
+ }
+
+ break;
+ }
+
+ default:
+ ythrow TBZipDecompressError() << "bzip error";
+ }
+ }
+ }
+
+ inline size_t FillInputBuffer() {
+ BzStream_.next_in = (char*)AdditionalData();
+ BzStream_.avail_in = Stream_->Read(BzStream_.next_in, AdditionalDataLength());
+
+ return BzStream_.avail_in;
+ }
+
+private:
+ IInputStream* Stream_;
+ bz_stream BzStream_;
+};
+
+TBZipDecompress::TBZipDecompress(IInputStream* input, size_t bufLen)
+ : Impl_(new (bufLen) TImpl(input))
+{
+}
+
+TBZipDecompress::~TBZipDecompress() {
+}
+
+size_t TBZipDecompress::DoRead(void* buf, size_t size) {
+ return Impl_->Read(buf, size);
+}
+
+class TBZipCompress::TImpl: public TAdditionalStorage<TImpl> {
+public:
+ inline TImpl(IOutputStream* stream, size_t level)
+ : Stream_(stream)
+ {
+ Zero(BzStream_);
+
+ if (BZ2_bzCompressInit(&BzStream_, level, 0, 0) != BZ_OK) {
+ ythrow TBZipCompressError() << "can not init bzip engine";
+ }
+
+ BzStream_.next_out = TmpBuf();
+ BzStream_.avail_out = TmpBufLen();
+ }
+
+ inline ~TImpl() {
+ BZ2_bzCompressEnd(&BzStream_);
+ }
+
+ inline void Write(const void* buf, size_t size) {
+ BzStream_.next_in = (char*)buf;
+ BzStream_.avail_in = size;
+
+ Y_DEFER {
+ BzStream_.next_in = 0;
+ BzStream_.avail_in = 0;
+ };
+
+ while (BzStream_.avail_in) {
+ const int ret = BZ2_bzCompress(&BzStream_, BZ_RUN);
+
+ switch (ret) {
+ case BZ_RUN_OK:
+ continue;
+
+ case BZ_PARAM_ERROR:
+ case BZ_OUTBUFF_FULL:
+ Stream_->Write(TmpBuf(), TmpBufLen() - BzStream_.avail_out);
+ BzStream_.next_out = TmpBuf();
+ BzStream_.avail_out = TmpBufLen();
+
+ break;
+
+ default:
+ ythrow TBZipCompressError() << "bzip error(" << ret << ", " << BzStream_.avail_out << ")";
+ }
+ }
+ }
+
+ inline void Flush() {
+ /*
+ * TODO ?
+ */
+ }
+
+ inline void Finish() {
+ int ret = BZ2_bzCompress(&BzStream_, BZ_FINISH);
+
+ while (ret != BZ_STREAM_END) {
+ Stream_->Write(TmpBuf(), TmpBufLen() - BzStream_.avail_out);
+ BzStream_.next_out = TmpBuf();
+ BzStream_.avail_out = TmpBufLen();
+
+ ret = BZ2_bzCompress(&BzStream_, BZ_FINISH);
+ }
+
+ Stream_->Write(TmpBuf(), TmpBufLen() - BzStream_.avail_out);
+ }
+
+private:
+ inline char* TmpBuf() noexcept {
+ return (char*)AdditionalData();
+ }
+
+ inline size_t TmpBufLen() const noexcept {
+ return AdditionalDataLength();
+ }
+
+private:
+ IOutputStream* Stream_;
+ bz_stream BzStream_;
+};
+
+TBZipCompress::TBZipCompress(IOutputStream* out, size_t compressionLevel, size_t bufLen)
+ : Impl_(new (bufLen) TImpl(out, compressionLevel))
+{
+}
+
+TBZipCompress::~TBZipCompress() {
+ try {
+ Finish();
+ } catch (...) {
+ }
+}
+
+void TBZipCompress::DoWrite(const void* buf, size_t size) {
+ if (!Impl_) {
+ ythrow TBZipCompressError() << "can not write to finished bzip stream";
+ }
+
+ Impl_->Write(buf, size);
+}
+
+void TBZipCompress::DoFlush() {
+ if (Impl_) {
+ Impl_->Flush();
+ }
+}
+
+void TBZipCompress::DoFinish() {
+ THolder<TImpl> impl(Impl_.Release());
+
+ if (impl) {
+ impl->Finish();
+ }
+}
diff --git a/library/cpp/streams/bzip2/bzip2.h b/library/cpp/streams/bzip2/bzip2.h
new file mode 100644
index 0000000000..2322277ef6
--- /dev/null
+++ b/library/cpp/streams/bzip2/bzip2.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <util/stream/input.h>
+#include <util/stream/output.h>
+#include <util/generic/ptr.h>
+#include <util/generic/yexception.h>
+
+#define BZIP_BUF_LEN (8 * 1024)
+#define BZIP_COMPRESSION_LEVEL 6
+
+/**
+ * @addtogroup Streams_Archs
+ * @{
+ */
+
+class TBZipException: public yexception {
+};
+
+class TBZipDecompressError: public TBZipException {
+};
+
+class TBZipCompressError: public TBZipException {
+};
+
+class TBZipDecompress: public IInputStream {
+public:
+ TBZipDecompress(IInputStream* input, size_t bufLen = BZIP_BUF_LEN);
+ ~TBZipDecompress() override;
+
+private:
+ size_t DoRead(void* buf, size_t size) override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+class TBZipCompress: public IOutputStream {
+public:
+ TBZipCompress(IOutputStream* out, size_t compressionLevel = BZIP_COMPRESSION_LEVEL, size_t bufLen = BZIP_BUF_LEN);
+ ~TBZipCompress() override;
+
+private:
+ void DoWrite(const void* buf, size_t size) override;
+ void DoFlush() override;
+ void DoFinish() override;
+
+public:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+/** @} */
diff --git a/library/cpp/streams/bzip2/bzip2_ut.cpp b/library/cpp/streams/bzip2/bzip2_ut.cpp
new file mode 100644
index 0000000000..69a98f296c
--- /dev/null
+++ b/library/cpp/streams/bzip2/bzip2_ut.cpp
@@ -0,0 +1,41 @@
+#include "bzip2.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/file.h>
+#include <util/system/tempfile.h>
+
+#define ZDATA "./zdata"
+
+Y_UNIT_TEST_SUITE(TBZipTest) {
+ static const TString data = "8s7d5vc6s5vc67sa4c65ascx6asd4xcv76adsfxv76s";
+
+ Y_UNIT_TEST(TestCompress) {
+ TUnbufferedFileOutput o(ZDATA);
+ TBZipCompress c(&o);
+
+ c.Write(data.data(), data.size());
+ c.Finish();
+ o.Finish();
+ }
+
+ Y_UNIT_TEST(TestDecompress) {
+ TTempFile tmp(ZDATA);
+
+ {
+ TUnbufferedFileInput i(ZDATA);
+ TBZipDecompress d(&i);
+
+ UNIT_ASSERT_EQUAL(d.ReadLine(), data);
+ }
+ }
+
+ Y_UNIT_TEST(TestCorrupted) {
+ TMemoryInput i("blablabla", 10);
+ TBZipDecompress d(&i);
+
+ UNIT_ASSERT_EXCEPTION(d.ReadLine(), TBZipDecompressError);
+ }
+}
+
+#undef ZDATA
diff --git a/library/cpp/streams/bzip2/ut/ya.make b/library/cpp/streams/bzip2/ut/ya.make
new file mode 100644
index 0000000000..5ef91498ca
--- /dev/null
+++ b/library/cpp/streams/bzip2/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/streams/bzip2)
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ bzip2_ut.cpp
+)
+
+END()
diff --git a/library/cpp/streams/bzip2/ya.make b/library/cpp/streams/bzip2/ya.make
new file mode 100644
index 0000000000..122a35837c
--- /dev/null
+++ b/library/cpp/streams/bzip2/ya.make
@@ -0,0 +1,16 @@
+LIBRARY()
+
+OWNER(
+ pg
+ g:util
+)
+
+PEERDIR(
+ contrib/libs/libbz2
+)
+
+SRCS(
+ bzip2.cpp
+)
+
+END()
diff --git a/library/cpp/streams/lz/lz.cpp b/library/cpp/streams/lz/lz.cpp
new file mode 100644
index 0000000000..b65bb3ed96
--- /dev/null
+++ b/library/cpp/streams/lz/lz.cpp
@@ -0,0 +1,731 @@
+#include "lz.h"
+
+#include <util/system/yassert.h>
+#include <util/system/byteorder.h>
+#include <util/memory/addstorage.h>
+#include <util/generic/buffer.h>
+#include <util/generic/utility.h>
+#include <util/generic/singleton.h>
+#include <util/generic/yexception.h>
+#include <util/stream/mem.h>
+
+#include <contrib/libs/lz4/lz4.h>
+#include <contrib/libs/fastlz/fastlz.h>
+#include <contrib/libs/snappy/snappy.h>
+#include <contrib/libs/quicklz/quicklz.h>
+#include <contrib/libs/minilzo/minilzo.h>
+
+static inline ui8 HostToLittle(ui8 t) noexcept {
+ return t;
+}
+
+static inline ui8 LittleToHost(ui8 t) noexcept {
+ return t;
+}
+
+struct TCommonData {
+ static const size_t overhead = sizeof(ui16) + sizeof(ui8);
+};
+
+const size_t SIGNATURE_SIZE = 4;
+
+template <class TCompressor, class TBase>
+class TCompressorBase: public TAdditionalStorage<TCompressorBase<TCompressor, TBase>>, public TCompressor, public TCommonData {
+public:
+ inline TCompressorBase(IOutputStream* slave, ui16 blockSize)
+ : Slave_(slave)
+ , BlockSize_(blockSize)
+ {
+ /*
+ * save signature
+ */
+ static_assert(sizeof(TCompressor::signature) - 1 == SIGNATURE_SIZE, "expect sizeof(TCompressor::signature) - 1 == SIGNATURE_SIZE");
+ Slave_->Write(TCompressor::signature, sizeof(TCompressor::signature) - 1);
+
+ /*
+ * save version
+ */
+ this->Save((ui32)1);
+
+ /*
+ * save block size
+ */
+ this->Save(BlockSize());
+ }
+
+ inline ~TCompressorBase() {
+ }
+
+ inline void Write(const char* buf, size_t len) {
+ while (len) {
+ const ui16 toWrite = (ui16)Min<size_t>(len, this->BlockSize());
+
+ this->WriteBlock(buf, toWrite);
+
+ buf += toWrite;
+ len -= toWrite;
+ }
+ }
+
+ inline void Flush() {
+ }
+
+ inline void Finish() {
+ this->Flush();
+ this->WriteBlock(nullptr, 0);
+ }
+
+ template <class T>
+ static inline void Save(T t, IOutputStream* out) {
+ t = HostToLittle(t);
+
+ out->Write(&t, sizeof(t));
+ }
+
+ template <class T>
+ inline void Save(T t) {
+ Save(t, Slave_);
+ }
+
+private:
+ inline void* Block() const noexcept {
+ return this->AdditionalData();
+ }
+
+ inline ui16 BlockSize() const noexcept {
+ return BlockSize_;
+ }
+
+ inline void WriteBlock(const void* ptr, ui16 len) {
+ Y_ASSERT(len <= this->BlockSize());
+
+ ui8 compressed = false;
+
+ if (len) {
+ const size_t out = this->Compress((const char*)ptr, len, (char*)Block(), this->AdditionalDataLength());
+ // catch compressor buffer overrun (e.g. SEARCH-2043)
+ //Y_VERIFY(out <= this->Hint(this->BlockSize()));
+
+ if (out < len || TCompressor::SaveIncompressibleChunks()) {
+ compressed = true;
+ ptr = Block();
+ len = (ui16)out;
+ }
+ }
+
+ char tmp[overhead];
+ TMemoryOutput header(tmp, sizeof(tmp));
+
+ this->Save(len, &header);
+ this->Save(compressed, &header);
+
+ using TPart = IOutputStream::TPart;
+ if (ptr) {
+ const TPart parts[] = {
+ TPart(tmp, sizeof(tmp)),
+ TPart(ptr, len),
+ };
+
+ Slave_->Write(parts, sizeof(parts) / sizeof(*parts));
+ } else {
+ Slave_->Write(tmp, sizeof(tmp));
+ }
+ }
+
+private:
+ IOutputStream* Slave_;
+ const ui16 BlockSize_;
+};
+
+template <class T>
+static inline T GLoad(IInputStream* input) {
+ T t;
+
+ if (input->Load(&t, sizeof(t)) != sizeof(t)) {
+ ythrow TDecompressorError() << "stream error";
+ }
+
+ return LittleToHost(t);
+}
+
+class TDecompressSignature {
+public:
+ inline TDecompressSignature(IInputStream* input) {
+ if (input->Load(Buffer_, SIGNATURE_SIZE) != SIGNATURE_SIZE) {
+ ythrow TDecompressorError() << "can not load stream signature";
+ }
+ }
+
+ template <class TDecompressor>
+ inline bool Check() const {
+ static_assert(sizeof(TDecompressor::signature) - 1 == SIGNATURE_SIZE, "expect sizeof(TDecompressor::signature) - 1 == SIGNATURE_SIZE");
+ return memcmp(TDecompressor::signature, Buffer_, SIGNATURE_SIZE) == 0;
+ }
+
+private:
+ char Buffer_[SIGNATURE_SIZE];
+};
+
+template <class TDecompressor>
+static inline IInputStream* ConsumeSignature(IInputStream* input) {
+ TDecompressSignature sign(input);
+ if (!sign.Check<TDecompressor>()) {
+ ythrow TDecompressorError() << "incorrect signature";
+ }
+ return input;
+}
+
+template <class TDecompressor>
+class TDecompressorBaseImpl: public TDecompressor, public TCommonData {
+public:
+ static inline ui32 CheckVer(ui32 v) {
+ if (v != 1) {
+ ythrow yexception() << TStringBuf("incorrect stream version: ") << v;
+ }
+
+ return v;
+ }
+
+ inline TDecompressorBaseImpl(IInputStream* slave)
+ : Slave_(slave)
+ , Input_(nullptr, 0)
+ , Eof_(false)
+ , Version_(CheckVer(Load<ui32>()))
+ , BlockSize_(Load<ui16>())
+ , OutBufSize_(TDecompressor::Hint(BlockSize_))
+ , Tmp_(2 * OutBufSize_)
+ , In_(Tmp_.Data())
+ , Out_(In_ + OutBufSize_)
+ {
+ this->InitFromStream(Slave_);
+ }
+
+ inline ~TDecompressorBaseImpl() {
+ }
+
+ inline size_t Read(void* buf, size_t len) {
+ size_t ret = Input_.Read(buf, len);
+
+ if (ret) {
+ return ret;
+ }
+
+ if (Eof_) {
+ return 0;
+ }
+
+ this->FillNextBlock();
+
+ ret = Input_.Read(buf, len);
+
+ if (ret) {
+ return ret;
+ }
+
+ Eof_ = true;
+
+ return 0;
+ }
+
+ inline void FillNextBlock() {
+ char tmp[overhead];
+
+ if (Slave_->Load(tmp, sizeof(tmp)) != sizeof(tmp)) {
+ ythrow TDecompressorError() << "can not read block header";
+ }
+
+ TMemoryInput header(tmp, sizeof(tmp));
+
+ const ui16 len = GLoad<ui16>(&header);
+ if (len > Tmp_.Capacity()) {
+ ythrow TDecompressorError() << "invalid len inside block header";
+ }
+ const ui8 compressed = GLoad<ui8>(&header);
+
+ if (compressed > 1) {
+ ythrow TDecompressorError() << "broken header";
+ }
+
+ if (Slave_->Load(In_, len) != len) {
+ ythrow TDecompressorError() << "can not read data";
+ }
+
+ if (compressed) {
+ const size_t ret = this->Decompress(In_, len, Out_, OutBufSize_);
+
+ Input_.Reset(Out_, ret);
+ } else {
+ Input_.Reset(In_, len);
+ }
+ }
+
+ template <class T>
+ inline T Load() {
+ return GLoad<T>(Slave_);
+ }
+
+protected:
+ IInputStream* Slave_;
+ TMemoryInput Input_;
+ bool Eof_;
+ const ui32 Version_;
+ const ui16 BlockSize_;
+ const size_t OutBufSize_;
+ TBuffer Tmp_;
+ char* In_;
+ char* Out_;
+};
+
+template <class TDecompressor, class TBase>
+class TDecompressorBase: public TDecompressorBaseImpl<TDecompressor> {
+public:
+ inline TDecompressorBase(IInputStream* slave)
+ : TDecompressorBaseImpl<TDecompressor>(ConsumeSignature<TDecompressor>(slave))
+ {
+ }
+
+ inline ~TDecompressorBase() {
+ }
+};
+
+#define DEF_COMPRESSOR_COMMON(rname, name) \
+ rname::~rname() { \
+ try { \
+ Finish(); \
+ } catch (...) { \
+ } \
+ } \
+ \
+ void rname::DoWrite(const void* buf, size_t len) { \
+ if (!Impl_) { \
+ ythrow yexception() << "can not write to finalized stream"; \
+ } \
+ \
+ Impl_->Write((const char*)buf, len); \
+ } \
+ \
+ void rname::DoFlush() { \
+ if (!Impl_) { \
+ ythrow yexception() << "can not flush finalized stream"; \
+ } \
+ \
+ Impl_->Flush(); \
+ } \
+ \
+ void rname::DoFinish() { \
+ THolder<TImpl> impl(Impl_.Release()); \
+ \
+ if (impl) { \
+ impl->Finish(); \
+ } \
+ }
+
+#define DEF_COMPRESSOR(rname, name) \
+ class rname::TImpl: public TCompressorBase<name, TImpl> { \
+ public: \
+ inline TImpl(IOutputStream* out, ui16 blockSize) \
+ : TCompressorBase<name, TImpl>(out, blockSize) { \
+ } \
+ }; \
+ \
+ rname::rname(IOutputStream* slave, ui16 blockSize) \
+ : Impl_(new (TImpl::Hint(blockSize)) TImpl(slave, blockSize)) { \
+ } \
+ \
+ DEF_COMPRESSOR_COMMON(rname, name)
+
+#define DEF_DECOMPRESSOR(rname, name) \
+ class rname::TImpl: public TDecompressorBase<name, TImpl> { \
+ public: \
+ inline TImpl(IInputStream* in) \
+ : TDecompressorBase<name, TImpl>(in) { \
+ } \
+ }; \
+ \
+ rname::rname(IInputStream* slave) \
+ : Impl_(new TImpl(slave)) { \
+ } \
+ \
+ rname::~rname() { \
+ } \
+ \
+ size_t rname::DoRead(void* buf, size_t len) { \
+ return Impl_->Read(buf, len); \
+ }
+
+/*
+ * MiniLzo
+ */
+class TMiniLzo {
+ class TInit {
+ public:
+ inline TInit() {
+ if (lzo_init() != LZO_E_OK) {
+ ythrow yexception() << "can not init lzo engine";
+ }
+ }
+ };
+
+public:
+ static const char signature[];
+
+ inline TMiniLzo() {
+ Singleton<TInit>();
+ }
+
+ inline ~TMiniLzo() {
+ }
+
+ static inline size_t Hint(size_t len) noexcept {
+ // see SEARCH-2043 and, e.g. examples at
+ // http://stackoverflow.com/questions/4235019/how-to-get-lzo-to-work-with-a-file-stream
+ return len + (len / 16) + 64 + 3;
+ }
+
+ static inline bool SaveIncompressibleChunks() noexcept {
+ return false;
+ }
+};
+
+const char TMiniLzo::signature[] = "YLZO";
+
+template <size_t N>
+class TFixedArray {
+public:
+ inline TFixedArray() noexcept {
+ memset(WorkMem_, 0, sizeof(WorkMem_));
+ }
+
+protected:
+ char WorkMem_[N];
+};
+
+class TMiniLzoCompressor: public TMiniLzo, public TFixedArray<LZO1X_MEM_COMPRESS + 1> {
+public:
+ inline size_t Compress(const char* data, size_t len, char* ptr, size_t /*dstMaxSize*/) {
+ lzo_uint out = 0;
+ lzo1x_1_compress((const lzo_bytep)data, len, (lzo_bytep)ptr, &out, WorkMem_);
+
+ return out;
+ }
+};
+
+class TMiniLzoDecompressor: public TMiniLzo, public TFixedArray<LZO1X_MEM_DECOMPRESS + 1> {
+public:
+ inline size_t Decompress(const char* data, size_t len, char* ptr, size_t /*max*/) {
+ lzo_uint ret = 0;
+
+ lzo1x_decompress((const lzo_bytep)data, len, (lzo_bytep)ptr, &ret, WorkMem_);
+
+ return ret;
+ }
+
+ inline void InitFromStream(IInputStream*) const noexcept {
+ }
+};
+
+DEF_COMPRESSOR(TLzoCompress, TMiniLzoCompressor)
+DEF_DECOMPRESSOR(TLzoDecompress, TMiniLzoDecompressor)
+
+/*
+ * FastLZ
+ */
+class TFastLZ {
+public:
+ static const char signature[];
+
+ static inline size_t Hint(size_t len) noexcept {
+ return Max<size_t>((size_t)(len * 1.06), 100);
+ }
+
+ inline size_t Compress(const char* data, size_t len, char* ptr, size_t /*dstMaxSize*/) {
+ return fastlz_compress(data, len, ptr);
+ }
+
+ inline size_t Decompress(const char* data, size_t len, char* ptr, size_t max) {
+ return fastlz_decompress(data, len, ptr, max);
+ }
+
+ inline void InitFromStream(IInputStream*) const noexcept {
+ }
+
+ static inline bool SaveIncompressibleChunks() noexcept {
+ return false;
+ }
+};
+
+const char TFastLZ::signature[] = "YLZF";
+
+DEF_COMPRESSOR(TLzfCompress, TFastLZ)
+DEF_DECOMPRESSOR(TLzfDecompress, TFastLZ)
+
+/*
+ * LZ4
+ */
+class TLZ4 {
+public:
+ static const char signature[];
+
+ static inline size_t Hint(size_t len) noexcept {
+ return Max<size_t>((size_t)(len * 1.06), 100);
+ }
+
+ inline size_t Compress(const char* data, size_t len, char* ptr, size_t dstMaxSize) {
+ return LZ4_compress_default(data, ptr, len, dstMaxSize);
+ }
+
+ inline size_t Decompress(const char* data, size_t len, char* ptr, size_t max) {
+ int res = LZ4_decompress_safe(data, ptr, len, max);
+ if (res < 0)
+ ythrow TDecompressorError();
+ return res;
+ }
+
+ inline void InitFromStream(IInputStream*) const noexcept {
+ }
+
+ static inline bool SaveIncompressibleChunks() noexcept {
+ return false;
+ }
+};
+
+const char TLZ4::signature[] = "LZ.4";
+
+DEF_COMPRESSOR(TLz4Compress, TLZ4)
+DEF_DECOMPRESSOR(TLz4Decompress, TLZ4)
+
+/*
+ * Snappy
+ */
+class TSnappy {
+public:
+ static const char signature[];
+
+ static inline size_t Hint(size_t len) noexcept {
+ return Max<size_t>(snappy::MaxCompressedLength(len), 100);
+ }
+
+ inline size_t Compress(const char* data, size_t len, char* ptr, size_t /*dstMaxSize*/) {
+ size_t reslen = 0;
+ snappy::RawCompress(data, len, ptr, &reslen);
+ return reslen;
+ }
+
+ inline size_t Decompress(const char* data, size_t len, char* ptr, size_t) {
+ size_t srclen = 0;
+ if (!snappy::GetUncompressedLength(data, len, &srclen) || !snappy::RawUncompress(data, len, ptr))
+ ythrow TDecompressorError();
+ return srclen;
+ }
+
+ inline void InitFromStream(IInputStream*) const noexcept {
+ }
+
+ static inline bool SaveIncompressibleChunks() noexcept {
+ return false;
+ }
+};
+
+const char TSnappy::signature[] = "Snap";
+
+DEF_COMPRESSOR(TSnappyCompress, TSnappy)
+DEF_DECOMPRESSOR(TSnappyDecompress, TSnappy)
+
+/*
+ * QuickLZ
+ */
+class TQuickLZBase {
+public:
+ static const char signature[];
+
+ static inline size_t Hint(size_t len) noexcept {
+ return len + 500;
+ }
+
+ inline TQuickLZBase()
+ : Table_(nullptr)
+ {
+ }
+
+ inline void Init(unsigned ver, unsigned lev, unsigned mod, unsigned type) {
+ Table_ = LzqTable(ver, lev, mod);
+
+ if (!Table_) {
+ ythrow yexception() << "unsupported lzq stream(" << ver << ", " << lev << ", " << mod << ")";
+ }
+
+ const size_t size = Table_->Setting(3) + Table_->Setting(type);
+
+ Mem_.Reset(::operator new(size));
+ memset(Mem_.Get(), 0, size);
+ }
+
+ inline bool SaveIncompressibleChunks() const noexcept {
+ // we must save incompressible chunks "as is"
+ // after compressor run in streaming mode
+ return Table_->Setting(3);
+ }
+
+protected:
+ const TQuickLZMethods* Table_;
+ THolder<void> Mem_;
+};
+
+const char TQuickLZBase::signature[] = "YLZQ";
+
+class TQuickLZCompress: public TQuickLZBase {
+public:
+ inline size_t Compress(const char* data, size_t len, char* ptr, size_t /*dstMaxSize*/) {
+ return Table_->Compress(data, ptr, len, (char*)Mem_.Get());
+ }
+};
+
+class TQuickLZDecompress: public TQuickLZBase {
+public:
+ inline size_t Decompress(const char* data, size_t /*len*/, char* ptr, size_t /*max*/) {
+ return Table_->Decompress(data, ptr, (char*)Mem_.Get());
+ }
+
+ inline void InitFromStream(IInputStream* in) {
+ const ui8 ver = ::GLoad<ui8>(in);
+ const ui8 lev = ::GLoad<ui8>(in);
+ const ui8 mod = ::GLoad<ui8>(in);
+
+ Init(ver, lev, mod, 2);
+ }
+};
+
+class TLzqCompress::TImpl: public TCompressorBase<TQuickLZCompress, TImpl> {
+public:
+ inline TImpl(IOutputStream* out, ui16 blockSize, EVersion ver, unsigned level, EMode mode)
+ : TCompressorBase<TQuickLZCompress, TImpl>(out, blockSize)
+ {
+ memset(AdditionalData(), 0, AdditionalDataLength());
+
+ Init(ver, level, mode, 1);
+
+ Save((ui8)ver);
+ Save((ui8)level);
+ Save((ui8)mode);
+ }
+};
+
+TLzqCompress::TLzqCompress(IOutputStream* slave, ui16 blockSize, EVersion ver, unsigned level, EMode mode)
+ : Impl_(new (TImpl::Hint(blockSize)) TImpl(slave, blockSize, ver, level, mode))
+{
+}
+
+DEF_COMPRESSOR_COMMON(TLzqCompress, TQuickLZCompress)
+DEF_DECOMPRESSOR(TLzqDecompress, TQuickLZDecompress)
+
+namespace {
+ template <class T>
+ struct TInputHolder {
+ static inline T Set(T t) noexcept {
+ return t;
+ }
+ };
+
+ template <class T>
+ struct TInputHolder<TAutoPtr<T>> {
+ inline T* Set(TAutoPtr<T> v) noexcept {
+ V_ = v;
+
+ return V_.Get();
+ }
+
+ TAutoPtr<T> V_;
+ };
+
+ // Decompressing input streams without signature verification
+ template <class TInput, class TDecompressor>
+ class TLzDecompressInput: public TInputHolder<TInput>, public IInputStream {
+ public:
+ inline TLzDecompressInput(TInput in)
+ : Impl_(this->Set(in))
+ {
+ }
+
+ private:
+ size_t DoRead(void* buf, size_t len) override {
+ return Impl_.Read(buf, len);
+ }
+
+ private:
+ TDecompressorBaseImpl<TDecompressor> Impl_;
+ };
+}
+
+template <class T>
+static TAutoPtr<IInputStream> TryOpenLzDecompressorX(const TDecompressSignature& s, T input) {
+ if (s.Check<TLZ4>())
+ return new TLzDecompressInput<T, TLZ4>(input);
+
+ if (s.Check<TSnappy>())
+ return new TLzDecompressInput<T, TSnappy>(input);
+
+ if (s.Check<TMiniLzo>())
+ return new TLzDecompressInput<T, TMiniLzoDecompressor>(input);
+
+ if (s.Check<TFastLZ>())
+ return new TLzDecompressInput<T, TFastLZ>(input);
+
+ if (s.Check<TQuickLZDecompress>())
+ return new TLzDecompressInput<T, TQuickLZDecompress>(input);
+
+ return nullptr;
+}
+
+template <class T>
+static inline TAutoPtr<IInputStream> TryOpenLzDecompressorImpl(const TStringBuf& signature, T input) {
+ if (signature.size() == SIGNATURE_SIZE) {
+ TMemoryInput mem(signature.data(), signature.size());
+ TDecompressSignature s(&mem);
+
+ return TryOpenLzDecompressorX(s, input);
+ }
+
+ return nullptr;
+}
+
+template <class T>
+static inline TAutoPtr<IInputStream> TryOpenLzDecompressorImpl(T input) {
+ TDecompressSignature s(&*input);
+
+ return TryOpenLzDecompressorX(s, input);
+}
+
+template <class T>
+static inline TAutoPtr<IInputStream> OpenLzDecompressorImpl(T input) {
+ TAutoPtr<IInputStream> ret = TryOpenLzDecompressorImpl(input);
+
+ if (!ret) {
+ ythrow TDecompressorError() << "Unknown compression format";
+ }
+
+ return ret;
+}
+
+TAutoPtr<IInputStream> OpenLzDecompressor(IInputStream* input) {
+ return OpenLzDecompressorImpl(input);
+}
+
+TAutoPtr<IInputStream> TryOpenLzDecompressor(IInputStream* input) {
+ return TryOpenLzDecompressorImpl(input);
+}
+
+TAutoPtr<IInputStream> TryOpenLzDecompressor(const TStringBuf& signature, IInputStream* input) {
+ return TryOpenLzDecompressorImpl(signature, input);
+}
+
+TAutoPtr<IInputStream> OpenOwnedLzDecompressor(TAutoPtr<IInputStream> input) {
+ return OpenLzDecompressorImpl(input);
+}
+
+TAutoPtr<IInputStream> TryOpenOwnedLzDecompressor(TAutoPtr<IInputStream> input) {
+ return TryOpenLzDecompressorImpl(input);
+}
+
+TAutoPtr<IInputStream> TryOpenOwnedLzDecompressor(const TStringBuf& signature, TAutoPtr<IInputStream> input) {
+ return TryOpenLzDecompressorImpl(signature, input);
+}
diff --git a/library/cpp/streams/lz/lz.h b/library/cpp/streams/lz/lz.h
new file mode 100644
index 0000000000..3a2eaad88b
--- /dev/null
+++ b/library/cpp/streams/lz/lz.h
@@ -0,0 +1,242 @@
+#pragma once
+
+#include <util/stream/output.h>
+#include <util/stream/input.h>
+#include <util/generic/ptr.h>
+#include <util/generic/yexception.h>
+
+/**
+ * @file
+ *
+ * All lz compressors compress blocks. `Write` method splits input data into
+ * blocks, compresses each block and then writes each compressed block to the
+ * underlying output stream. Thus compression classes are not buffered.
+ * MaxBlockSize parameter specified max allowed block size.
+ *
+ * See http://altdevblogaday.com/2011/04/22/survey-of-fast-compression-algorithms-part-1/
+ * for some comparisons.
+ */
+
+struct TDecompressorError: public yexception {
+};
+
+/**
+ * @addtogroup Streams_Archs
+ * @{
+ */
+
+/**
+ * Lz4 compressing stream.
+ *
+ * @see http://code.google.com/p/lz4/
+ */
+class TLz4Compress: public IOutputStream {
+public:
+ TLz4Compress(IOutputStream* slave, ui16 maxBlockSize = 1 << 15);
+ ~TLz4Compress() override;
+
+private:
+ void DoWrite(const void* buf, size_t len) override;
+ void DoFlush() override;
+ void DoFinish() override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+/**
+ * Lz4 decompressing stream.
+ *
+ * @see http://code.google.com/p/lz4/
+ */
+class TLz4Decompress: public IInputStream {
+public:
+ TLz4Decompress(IInputStream* slave);
+ ~TLz4Decompress() override;
+
+private:
+ size_t DoRead(void* buf, size_t len) override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+/**
+ * Snappy compressing stream.
+ *
+ * @see http://code.google.com/p/snappy/
+ */
+class TSnappyCompress: public IOutputStream {
+public:
+ TSnappyCompress(IOutputStream* slave, ui16 maxBlockSize = 1 << 15);
+ ~TSnappyCompress() override;
+
+private:
+ void DoWrite(const void* buf, size_t len) override;
+ void DoFlush() override;
+ void DoFinish() override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+/**
+ * Snappy decompressing stream.
+ *
+ * @see http://code.google.com/p/snappy/
+ */
+class TSnappyDecompress: public IInputStream {
+public:
+ TSnappyDecompress(IInputStream* slave);
+ ~TSnappyDecompress() override;
+
+private:
+ size_t DoRead(void* buf, size_t len) override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+/**
+ * MiniLZO compressing stream.
+ */
+class TLzoCompress: public IOutputStream {
+public:
+ TLzoCompress(IOutputStream* slave, ui16 maxBlockSize = 1 << 15);
+ ~TLzoCompress() override;
+
+private:
+ void DoWrite(const void* buf, size_t len) override;
+ void DoFlush() override;
+ void DoFinish() override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+/**
+ * MiniLZO decompressing stream.
+ */
+class TLzoDecompress: public IInputStream {
+public:
+ TLzoDecompress(IInputStream* slave);
+ ~TLzoDecompress() override;
+
+private:
+ size_t DoRead(void* buf, size_t len) override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+/**
+ * FastLZ compressing stream.
+ */
+class TLzfCompress: public IOutputStream {
+public:
+ TLzfCompress(IOutputStream* slave, ui16 maxBlockSize = 1 << 15);
+ ~TLzfCompress() override;
+
+private:
+ void DoWrite(const void* buf, size_t len) override;
+ void DoFlush() override;
+ void DoFinish() override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+/**
+ * FastLZ decompressing stream.
+ */
+class TLzfDecompress: public IInputStream {
+public:
+ TLzfDecompress(IInputStream* slave);
+ ~TLzfDecompress() override;
+
+private:
+ size_t DoRead(void* buf, size_t len) override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+/**
+ * QuickLZ compressing stream.
+ */
+class TLzqCompress: public IOutputStream {
+public:
+ enum EVersion {
+ V_1_31 = 0,
+ V_1_40 = 1,
+ V_1_51 = 2
+ };
+
+ /*
+ * streaming mode - actually, backlog size
+ */
+ enum EMode {
+ M_0 = 0,
+ M_100000 = 1,
+ M_1000000 = 2
+ };
+
+ TLzqCompress(IOutputStream* slave, ui16 maxBlockSize = 1 << 15,
+ EVersion ver = V_1_31,
+ unsigned level = 0,
+ EMode mode = M_0);
+ ~TLzqCompress() override;
+
+private:
+ void DoWrite(const void* buf, size_t len) override;
+ void DoFlush() override;
+ void DoFinish() override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+/**
+ * QuickLZ decompressing stream.
+ */
+class TLzqDecompress: public IInputStream {
+public:
+ TLzqDecompress(IInputStream* slave);
+ ~TLzqDecompress() override;
+
+private:
+ size_t DoRead(void* buf, size_t len) override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+/** @} */
+
+/**
+ * Reads a compression signature from the provided input stream and returns a
+ * corresponding decompressing stream.
+ *
+ * Note that returned stream doesn't own the provided input stream, thus it's
+ * up to the user to free them both.
+ *
+ * @param input Stream to decompress.
+ * @return Decompressing proxy input stream.
+ */
+TAutoPtr<IInputStream> OpenLzDecompressor(IInputStream* input);
+TAutoPtr<IInputStream> TryOpenLzDecompressor(IInputStream* input);
+TAutoPtr<IInputStream> TryOpenLzDecompressor(const TStringBuf& signature, IInputStream* input);
+
+TAutoPtr<IInputStream> OpenOwnedLzDecompressor(TAutoPtr<IInputStream> input);
+TAutoPtr<IInputStream> TryOpenOwnedLzDecompressor(TAutoPtr<IInputStream> input);
+TAutoPtr<IInputStream> TryOpenOwnedLzDecompressor(const TStringBuf& signature, TAutoPtr<IInputStream> input);
diff --git a/library/cpp/streams/lz/lz_ut.cpp b/library/cpp/streams/lz/lz_ut.cpp
new file mode 100644
index 0000000000..6876f070fc
--- /dev/null
+++ b/library/cpp/streams/lz/lz_ut.cpp
@@ -0,0 +1,287 @@
+#include "lz.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/resource/resource.h>
+
+#include <util/stream/file.h>
+#include <util/generic/vector.h>
+#include <util/system/tempfile.h>
+#include <util/generic/singleton.h>
+
+#define LDATA "./ldata"
+#define LDATA_RANDOM "./ldata.random"
+
+static const TString data = "aa aaa aa aaa aa aaa bb bbb bb bbb bb bbb";
+
+namespace {
+ /**
+ * Produces well-formed random crap
+ **/
+ TString RandomString(size_t size) {
+ TString entropy(NResource::Find("/random.data"));
+ TString result;
+ size_t seed = 1;
+ size_t j = 0;
+ for (size_t i = 0; i < size; ++i) {
+ seed *= 3;
+ char sym;
+ do {
+ sym = char((seed ^ i) % 256);
+ if (!sym) {
+ seed += 1;
+ }
+ } while (!sym);
+ Y_ASSERT(sym);
+ j = (j + 1) % entropy.size();
+ result += char(sym + entropy[j]);
+ }
+ return result;
+ }
+
+ TVector<TString> InitRandomData() {
+ static const TVector<size_t> sizes = {
+ 0,
+ 1,
+ 127,
+ 2017,
+ 32767,
+ };
+
+ TVector<TString> result;
+ for (auto size : sizes) {
+ result.push_back(RandomString(size));
+ }
+ result.push_back(NResource::Find("/request.data"));
+ return result;
+ }
+
+ TString TestFileName(const TString& d, size_t bufferSize) {
+ return LDATA_RANDOM + TString(".") + ToString(d.size()) + TString(".") + ToString(bufferSize);
+ }
+
+ struct TRandomData: public TVector<TString> {
+ inline TRandomData() {
+ InitRandomData().swap(*this);
+ }
+ };
+}
+
+static const TVector<size_t> bufferSizes = {
+ 127,
+ 1024,
+ 32768,
+};
+
+namespace {
+ template <TLzqCompress::EVersion Ver, int Level, TLzqCompress::EMode Mode>
+ struct TLzqCompressX: public TLzqCompress {
+ inline TLzqCompressX(IOutputStream* out, size_t bufLen)
+ : TLzqCompress(out, bufLen, Ver, Level, Mode)
+ {
+ }
+ };
+}
+
+template <class C>
+static inline void TestGoodDataCompress() {
+ TFixedBufferFileOutput o(LDATA);
+ C c(&o, 1024);
+
+ TString d = data;
+
+ for (size_t i = 0; i < 10; ++i) {
+ c.Write(d.data(), d.size());
+ c << Endl;
+ d = d + d;
+ }
+
+ c.Finish();
+ o.Finish();
+}
+
+template <class C>
+static inline void TestIncompressibleDataCompress(const TString& d, size_t bufferSize) {
+ TString testFileName = TestFileName(d, bufferSize);
+ TFixedBufferFileOutput o(testFileName);
+ C c(&o, bufferSize);
+ c.Write(d.data(), d.size());
+ c.Finish();
+ o.Finish();
+}
+
+template <class C>
+static inline void TestCompress() {
+ TestGoodDataCompress<C>();
+ for (auto bufferSize : bufferSizes) {
+ for (auto rd : *Singleton<TRandomData>()) {
+ TestIncompressibleDataCompress<C>(rd, bufferSize);
+ }
+ }
+}
+
+template <class D>
+static inline void TestGoodDataDecompress() {
+ TTempFile tmpFile(LDATA);
+
+ {
+ TFileInput i1(LDATA);
+ D ld(&i1);
+
+ TString d = data;
+
+ for (size_t i2 = 0; i2 < 10; ++i2) {
+ UNIT_ASSERT_EQUAL(ld.ReadLine(), d);
+
+ d = d + d;
+ }
+ }
+}
+
+template <class D>
+static inline void TestIncompressibleDataDecompress(const TString& d, size_t bufferSize) {
+ TString testFileName = TestFileName(d, bufferSize);
+ TTempFile tmpFile(testFileName);
+
+ {
+ TFileInput i(testFileName);
+ D ld(&i);
+
+ UNIT_ASSERT_EQUAL(ld.ReadAll(), d);
+ }
+}
+
+template <class D>
+static inline void TestDecompress() {
+ TestGoodDataDecompress<D>();
+ for (auto bufferSize : bufferSizes) {
+ for (auto rd : *Singleton<TRandomData>()) {
+ TestIncompressibleDataDecompress<D>(rd, bufferSize);
+ }
+ }
+}
+
+class TMixedDecompress: public IInputStream {
+public:
+ TMixedDecompress(IInputStream* input)
+ : Slave_(OpenLzDecompressor(input).Release())
+ {
+ }
+
+private:
+ size_t DoRead(void* buf, size_t len) override {
+ return Slave_->Read(buf, len);
+ }
+
+private:
+ THolder<IInputStream> Slave_;
+};
+
+template <class C>
+static inline void TestMixedDecompress() {
+ TestCompress<C>();
+ TestDecompress<TMixedDecompress>();
+}
+
+template <class D, class C>
+static inline void TestDecompressError() {
+ TestCompress<C>();
+ UNIT_ASSERT_EXCEPTION(TestDecompress<D>(), TDecompressorError);
+}
+
+Y_UNIT_TEST_SUITE(TLzTest) {
+ Y_UNIT_TEST(TestLzo) {
+ TestCompress<TLzoCompress>();
+ TestDecompress<TLzoDecompress>();
+ }
+
+ Y_UNIT_TEST(TestLzf) {
+ TestCompress<TLzfCompress>();
+ TestDecompress<TLzfDecompress>();
+ }
+
+ Y_UNIT_TEST(TestLzq) {
+ TestCompress<TLzqCompress>();
+ TestDecompress<TLzqDecompress>();
+ }
+
+ Y_UNIT_TEST(TestLzq151_1) {
+ TestCompress<TLzqCompressX<TLzqCompress::V_1_51, 1, TLzqCompress::M_0>>();
+ TestDecompress<TLzqDecompress>();
+ }
+
+ Y_UNIT_TEST(TestLzq151_2) {
+ TestCompress<TLzqCompressX<TLzqCompress::V_1_51, 2, TLzqCompress::M_100000>>();
+ TestDecompress<TLzqDecompress>();
+ }
+
+ Y_UNIT_TEST(TestLzq151_3) {
+ TestCompress<TLzqCompressX<TLzqCompress::V_1_51, 3, TLzqCompress::M_1000000>>();
+ TestDecompress<TLzqDecompress>();
+ }
+
+ Y_UNIT_TEST(TestLzq140_1) {
+ TestCompress<TLzqCompressX<TLzqCompress::V_1_40, 1, TLzqCompress::M_0>>();
+ TestDecompress<TLzqDecompress>();
+ }
+
+ Y_UNIT_TEST(TestLzq140_2) {
+ TestCompress<TLzqCompressX<TLzqCompress::V_1_40, 2, TLzqCompress::M_100000>>();
+ TestDecompress<TLzqDecompress>();
+ }
+
+ Y_UNIT_TEST(TestLzq140_3) {
+ TestCompress<TLzqCompressX<TLzqCompress::V_1_40, 3, TLzqCompress::M_1000000>>();
+ TestDecompress<TLzqDecompress>();
+ }
+
+ Y_UNIT_TEST(TestLz4) {
+ TestCompress<TLz4Compress>();
+ TestDecompress<TLz4Decompress>();
+ }
+
+ Y_UNIT_TEST(TestSnappy) {
+ TestCompress<TSnappyCompress>();
+ TestDecompress<TSnappyDecompress>();
+ }
+
+ Y_UNIT_TEST(TestGeneric) {
+ TestMixedDecompress<TLzoCompress>();
+ TestMixedDecompress<TLzfCompress>();
+ TestMixedDecompress<TLzqCompress>();
+ TestMixedDecompress<TLz4Compress>();
+ TestMixedDecompress<TSnappyCompress>();
+ }
+
+ Y_UNIT_TEST(TestDecompressorError) {
+ TestDecompressError<TLzoDecompress, TLzfCompress>();
+ TestDecompressError<TLzfDecompress, TLzqCompress>();
+ TestDecompressError<TLzqDecompress, TLz4Compress>();
+ TestDecompressError<TLz4Decompress, TSnappyCompress>();
+ TestDecompressError<TSnappyDecompress, TBufferedOutput>();
+ TestDecompressError<TMixedDecompress, TBufferedOutput>();
+ }
+
+ Y_UNIT_TEST(TestFactory) {
+ TStringStream ss;
+
+ {
+ TLz4Compress c(&ss);
+
+ c.Write("123456789", 9);
+ c.Finish();
+ }
+
+ TAutoPtr<IInputStream> is(OpenOwnedLzDecompressor(new TStringInput(ss.Str())));
+
+ UNIT_ASSERT_EQUAL(is->ReadAll(), "123456789");
+ }
+
+ Y_UNIT_TEST(TestYQ609) {
+ auto data = NResource::Find("/yq_609.data");
+
+ TMemoryInput input(data.Data(), data.Size());
+
+ TLz4Decompress d(&input);
+ UNIT_ASSERT_EXCEPTION(d.ReadAll(), TDecompressorError);
+ }
+}
diff --git a/library/cpp/streams/lz/ut/random.data b/library/cpp/streams/lz/ut/random.data
new file mode 100644
index 0000000000..6b3c159b58
--- /dev/null
+++ b/library/cpp/streams/lz/ut/random.data
Binary files differ
diff --git a/library/cpp/streams/lz/ut/request.data b/library/cpp/streams/lz/ut/request.data
new file mode 100644
index 0000000000..6a29bfe6af
--- /dev/null
+++ b/library/cpp/streams/lz/ut/request.data
@@ -0,0 +1 @@
+pron=snipfactors&pron=grmult_QUICK_SAMOHOD_ON_MIDDLE%3Ad%3A0.1%3A0.1&pron=umrfull&pron=usemiddleownerdata&pron=onlyfastrank&pron=sortbyfastmn&pron=rtb2000000&pron=tbs120000&pron=multbs0.63&pron=versiontbs2&pron=wffrm_ru.fast.download&pron=whrm_ru.hast.download&pron=rcy-lzo&qtree=cHic7V0NdFXVlb7nvpuXxyFhXgNx4Z0ljURpYFkbwZlxaR2s80apf0VmlrVvqgNIgBRI4kuE6KxZTYJABIZg_VlqUSnIj2hfIAiEAAEELag479k1SrV1KuMvrXUW2pnxr875ufe-87PvvS_JKyrGtQzvvrP3vufs_e2zz88-5-ErcEmsKB4daVSgKrPaKDNsY7QxzhhvXFgSM-IG-d6oMqqNS4omFU02rjemRmejlch4ABlrkNGFjD3IIP8dQkYGzbBfQfgHmLPFCBsVVzztlqb6m6bNsFGFJ7ZYEGtMMqjY2Y8fOd0V67Io0quNC9ClDTEUN2yXYrRRRfiq0SQ0-S6T1M2YjVJXYLc0jkayd1xgTEHtSXNdenqM8NIXD5-OySfzG43kc2T6kLhpI_ejYaNv0I-zjWbzNjNmzi5uKG5BBqmbfbAUz1JaNyzbmunJbM4uIf-3ZZfTRqKKgFa-id1GKpxQW58pYY1VKEmb38SkyebktW6TVxVhhShuek03SFtN28x0sQbGicBYtj2zObM108u-YaXZDvZ5GPkczWyTyzLbnM-IfN4pfN7tfCaazC4UZK0QeLtzNPnI8eipnEU5Gqd-JeR7K7vQeUNJ3LItUtvdzpNBytq8t0QIV5v2di6hPbs8R-XUBeDP7BL4Nws17hY-i5rao9HHCU0ssydQ370F0beqG_q0rAA655roFb5fJryhjWlyuGJ5w9U98SKUei6Kyzx4dme6vrIQFYHB4Aa2kNeq14-qIPDgJcsK2vKT7XIiAFW7egDkDpi94ySgidWH4LvQGMIEQ04Jc6dqobPvJtrrpnGmCjmeNIxoMco9jDrm7FizQcIYEsLY00W4XgljZZktmW1E6N7MLspK-qteKZQNAULZymI3lAHcUDg7aLFwBlCTkLayWA5p_4IBOtJlIDegtyYNoifEvAvSuOtDw6dXxIfYI4mYXk0gwMk0fMzEI1Ri0pfuFLos1JKMpHfsJ1WIsCrsESCwJ9TFOV1Yxb9Mzl8Rx31U8njVwhqUXW32-gB5E8L_oACZKV-CrglAd7HpQpfR62C1Lv17hlVWTNC52HTRiaaaBJ2VmJU4eEAXmFPQEoJHb3hJG6hUdnEUGDy2EJu0MmfuzewOHTw-Pio3eJQ4IW9bXuQMHiVKOmAeJXvaOIxzNIr-qQZ6GQqY_lOtJhYFdqsuYW1Kd-9jf_c7XSvc7f45Au9Awubw_DyH4fZRFKCDSPu-w0lzU1prPe8nChEc4DGj1gpW13G4RLS_ZF3-rpxtx2EFKxJ1DtqU9hwcl2mJL8jUKEetOML_mYAjtGV6icAW2pFm20Id4eDUnCNInJAj_Ak5jiBREkc4OFV2hLXUsBKRbNhnkubGNDSN9MYpRh6GzEGRR69eZ9Qrw8AUwOgNuZlJqeqlSvZB9UsQ_p6ienPCeKC7RD7qJtSQisdQNpsUjh5a7f43YXzV3dVEwUwE1e9thlCTByJ4ilKTyPTaJqkqEcDyb6cjbl0oPVSZbSazNy0mRiYM8vLAZZiWxFFuJNGvpYHUVZqcO5Lm6q1JtEUQxXg4-1Bil0hTzQznwbQjtXWzPGk_wBaRViOuWBBxa7aS_7tyJuXyanLVadSkkYcIfU-dJ3o0jhLR82rmKDCJSDAR1zm6EP6-Ypxo5onMrmxHqH0e8MzjcECx9bvMQA4BsdEDETm6no2dsr7E11dNfelpQW3djPoFjaH9yfFzvKUnhwUC1gnekbgkpOLHz5Gx9V0c5YUqvDq9qkdgeA1X4XW1IEqAhLU6vbVXFQaAioiLOJKZuAnYrbZQNbO9M4nWqXD1W_1aDXQezQ22ETzUSh_xVgsJNaTWiUyrpJAolFDLGh2FSQFTARSIlCqOpguZeKRZYVUVVRujS2M_jrcg8hjJ41FmVZ8QQSJMGSSGNi_5MkFNuWFMS9iHEP6hosAYXamcUdM4x0ZjR6MqR48xQI9rHq509egxQdpMMm16JKOp4iSN_hX2CgVome1pGQoCSnUsjLZoK6qs5BbLbdzDFp6EKQRMVvWgheTopChrkv8ycgbhGb6aGlIx5ltV51WcN7biS6Qx-y2Ea9Qm1dbNr6lrqk9R4-daFdCkT372757SPG7_VXKPRG_TldgrLPAq-WgOAuoQVjXtu5GCmbVWLF5-91VTEvadhcTMS7p3WdRsIF4sQLkfPenFLsYI6bWWzwppsa7TSZgV5KtPNsiryWPb4QWEk-pYiW2oAKiBYvLLH47wxkw-uyoz-ZCJ76ggbcBU-L2UUJQsicRi5ce2zk3YfzRxrTpfIBOrLjoKpqtgmSekzhOK79sPPeYBR-GFtPGhM2OQKR3NSDNnhSRgxvQzhOMysbN8gJzpxV4yvVjfKYz1CjG1EGaY0tqPPrVA6oDKsYSRPI6Iv7I-_qgOxCjfapMsEAUs0H3fsZW5oSFnglQ_lw8NOYGORTLA4kXCkKAfcEQ-Ac1IHiA6KL-otDlhbzH1aE3GT3Vz67nrBcae54_m-mmXCWrukxxpHo3e4snYKwyZa4QPBfnI8kpYYiGc2qJOTZy3h455Lty8IGFvRPo8r2HGTEmBUJ_V9bCnQEoP6S7B-yxSqmvtLEy_F_qsSPu6tDKB8Kv872nl_7OBQOBlHe_FJGCmSNgM7XLuXW95cwqHB2pEHZ9SOBR6Q67AblmhO2C3uetGkOZ-uIrY6q4RBQzHR4rwgjw2GaDgXJDNhgNBmw1ocK9hcK-hb3sNr5biZg3PO-gCL10IJZ-6ef4HMCaD8LwvFyAAMRCgf1niAFqj1gG9fygW6bZrG-40fmw5MH1w131w131w1z10193rQr9K6T0cVwuF9u-QfPbU6zWYxfuc8tWX5DP-bp4wJfsnC-3ZDiFpqhprXb0SsgRpbIp5rs5BOn3fKaky3fOfkPNx4p5SMk68dPX8hP1YKW4ICIXb3VTIscFDOp8QuN0_H3KjHgK3ezmRSgh8Mo8QGNly8MhgDByMgQOKgb6pj4MxcDAGful6jZMZA1X_1GPg-Uof3o9sRy9-raXxa97q-oR9ZyluUuLXCPYaJUFZimAYiGAtr5a6EQwUAMWwpTyGgfR6FDs6FIOUQhwz7zhC5nIHifaKCD43n4KYHEzz_6Kk-auWF2NdhLSf4fOUR-DgWGpwLDXgLH6fKHUoQqIUvp7MsrZH9CglH6Ih3Q2pZmiUOvFf3jwLFABFqU6eQwfS61HqU4RBSil9cr9_-qSQ9CgBBNq9FIEavifKhxTLPWMGvK1_bwgw5fvFxJSfPEYGHK8Va2vHp-nnobKtNL9OMOZQwJivvzTBNaaPCMicL0aZOX04dIOuiWIfWtGkdxx8nu5AnkaAPSzT5Xb1lMpxSsuOkuGc-1xGnjF3UpmGrst7z3Q4t1N53i08E0dnecfiO1Z4z3HyTMOQv0QeqHaToWSr56YUI-rTcuF9i2RpQpvY-6iLC99EifxtQp3ZG2n36EmV38jL27l-nbcUKXU2FQlxQhFjOxm5mtJ2divPvYHvbPPeOVzQpNjyNo9jBOEocTvgL7mNuRX7YtVhxKqcYnmI199OO_CL1y5I2CdMLYmtxHOqHnpKJSRnInOkzPV1iRHy8I95IoFEp_v1WoQlCmGPkyegkM7Znef3CNGwh8VwtbsOT0MRY35eKSlOhnuukr3akRShPkGzPTNWVV59XhOZ7Zn6Jn7jnGk3zZ4Wvom_8q2R3ia-wwMp_xEnMdgh0Xfxz8duGcu4QOEJhKjZpHv_OleBsl2olozkJpqKN_OREU_a91n435Cipgr5SDl0RFDQXxzKu3p_8ddcBYZKgzT7v3wcEsqrQ30bwqFcDP4ot8V_bjxuj6H7yiGM0F76uPhwe3Q_-IQ9eJqDlboEh0hhuQHyNkBOAt0GuCS44X3d-WZgsYhLHbFiZ5a_89T1CXuXpaVGDZle09gwd1pTXb2QMQKt-i99-m9cROR4INM_F2GmzxHpbvXXOFfaF8caB_NpOUKI5eGDtP3J7ETs1Ejfxfl6darKR1qL1gw_ylaN8lofypCMsyEE08BxFLDzsQienFS7z35562CqXf_Styzmlb-hWvz6AqLFZ038j2oC9MxUTY2kQSjx-eB-T4OMAdLe61x7rFzX3IWYFYhtlCDIm5LKdX6NTYKONF6_g1SuwpGvwoGKtOZZER_97qcnHJaMuTlhd1p4qqJfnOtaJS0XAVp-cdVcV8sCG6Tr3bznE6j08PYwwkK5EMi-EOcUaSBb5VdDq_2n9Izs51y9KlwixkX_I5Qsy9uj1KJvjLzDb0vdxdByiqE5V5M5wUcRfIu29aAOE7ozO0MXdZ57_21h7wGQAB5gc1Z1IHodYvuAxETvtLMXaIo2prsJ4qx15B_FLIVa8wxf3x3ez7W5FdIMpMOv3v1KO4QS6jkcHqRw-OzYDQl7mZUXHHpC4bDi6ftmBMGhB4LDwogvHHp0OKxDIBx65L6nkI4NzR4DnZw59qN51bPQfWS_6uqDj-N04fDpi-cn7KPF-DZ14VBrG5sRhC4cZt64d5l364WPEAgkzzpLhzCHDpMdCPvQiiGg5aF0dzKykZph3T5nBrL5pG2WaV0GA05XXjVvX-VgXL3gwVlwA65lkKvHl6L0Hbs-92Gs0h_kU2m0NGltTBNlR9al9wXey3HyNyr71-wt-TTb646-EKbycfZP6GmTrxu1Cfs4AsaXT5C2tfDLYULGl7uXluXGlx4b5NLNzvDSI9K9eAw7gU-KQ-6DGYsFMeqJiYDT-l7z_4dOX0p_PCthv27iuUrz48S8XSzc9pK3qAtO0GRw1bve_YoaM6SKN_i0RqPVNbIIYY1KbfCoeIx0lHz9SCSE1n3s-FC7LA86cXXHSQuVucLWg3wU30oHIYcua0rY70XwPFXxom_lpfjtn-70zjtp3JDm3-NjUY1W1_zP6clJhUrwcrNlZdLc1Jk0N3TSA5RJ89FOeuEC7ev2sm7vcDKyPr2P_tlPQg79s47-2USKIxvon_X0z6P0zyZKt4mWbqCfNnAOUrCx8xmhC6XU7A8t7jwsLaCg1NTA6jqzH1rhTWQAsrGTD0Ro5TekeQPWp3kjHk2zhkiDFPaGavkN_VjR4xh4njrf7QfJQGO3GYwBemo1FAOPPLYWgxig3OBEF-kYoLQ6Bs7VWrxZwTwSMZ_6Z42-VzpsSzejB2ICH4Wm6ebPlbdPTdirIkBvtoigYVe2g3ivPmaDFPrmi9fkejOFGdLng45PqbS6Pt-jvZlCJeaUtXSfSiMG__DzAo2-H9zbnLD3IXy9erY5dUtjY2342eb7fuF1fQ4LZJzr-MlmTqAvoU3ATtFALuWIxWOkUfdQtz5_y60JeyGw98XfUhe69_XRf3vntV0eqFn3OntfDonesDHYLfNdHmRLd1eAdIVZKuV6eYF657VWPTF2BDdquTUtbM-6lS5xuBe7hc67X_12LrUG4IcU1uOm1gD0uqO2mxiklE-HSoswA7t3r-9LKSch0Q30YG7UDgr2TAfx4E-Bo-YEUaFHzXs_zh01J_SQze7jIKfFOsC_hen3QftPyq7N5SpDPzeTfGD-LoX5d5qnJ-xXIrhV3dS1SXe_jcTEbnpvn3yNoaSpUujEzkPHPVUFyIE0-DRHfQCXjv0VJg6gH_QAx97vUA-IbLkxYb9k4pvVg1lcaSwVpo2pcXPowaxjv3jXu4of4AcPJ3MHAajBJBSATsoVdFJR3HV41wonMQnFR9d_oLp-6T8aEvavTSCnz23V7bxN2cXkc3hOX9f7V-dy-kARkMqzyMnpAzl0tT-IsA8tpHr3tgMfReWdppmXuQIUzjaJZ6L5bJP4BnWT2GlPT-gW57H0wtwuscsFaXUv1SrNtnNodD3ej7BXKs0plLXvCQJoKwUtVApaqBS0UCmAtlIAbaW0nlwpdB2VAmgr3VnJVCgkrKQhYd5bsxL2n4CtdrdfDdXi8baxihKzrZASO3hn79EEKTHbKiWhfc47g3SFZYxwH3LQvqBI1-tP5wPst-n6y9Gz5ibsFy3cokVp8XZdMkXbkV2WXQLMGqEovXqZl3MVIAZMkeAbQgFcuiWXRnAAfUCQHhMvtUexxTKQG1wMq4j_hT0SpP9zXIryeZ7bKMwkl0PtMPlQ_tpPahP2Dgv_EzQfnFM_L3Q--ObOD6LShJAwQSA6HMlNCAmJPl6u5DPdOfWSz7Ch7TzPuc7HroC-JHZVQVxgWtcEWP66JEqrA3cpIVNn6mfq1vdAWf3MNaICx4AC9UwwmE7LAwMnFwa9HCtWvvSBU_9yLBzHpLkP0cD5_bduSdjLI3o2d2YLO5Gqd8vQKtHKp8Z72dwiI9Twe3gAlej0rvd3CEsUX60FvGHxYaRv-zhKDHT_3U0J-50onq1dK78w0-OMeNXzvBAsW1YmcvfKS6yQkf7g_sCCRKmb6RwskYRc4nF3EVYkSkduDhzhvYMpTYxOvROXX5i7WJzDIe1f3ZsPArzvAI5Z5T0VNWR2hgt4d-ABU3NlPH3aTXNmpepvqZsB3hkIHnx8dai3I55jh1z5EJ9LC1R6sLkaC8UDXqJOTfET1_90Y-Xa4BcRTilaHFpb11Qzd27tLBqkBTVqV9ZByxSL77jOVacoB9LnFKZOkUrX5zgslosBXNsbUBr2ip4pEGtKTatrnFmTCmwVtMd2d_tp3pzWFQI16ddO-rhLA16p7RYOHB4_goX1BRzshyBSMGwsf9hsNfF07bxUTWp-7U014O2G4N7RPV6qmcsL6bTXPTfFScABnlM2cI1eA8oKTjX3O9QQcp110JN0sxbtRY3kE_Sq6zcWkTH1moi-CclHeKG7GL9tieV-eYOxQBrfwQeWDgWYVu6UyasyTrrk-s7PfXXmLBxzxrwhazOcKjhfOydNuygtaAWHm40M0mPl437TyLZZtaFnpivTTUYGT9AGKktrkMf0_n5M7oJyiRUyY7t7QblEqZvzBqyQaEu9_U6CgAYFZfEyopc9FM4398xN2I9FgJvbvfrQO-pC9fL49l_FAcVQ3oB7CxRKcA9CofkiHqG4MaCSVvtP9w4wj8jHfr10uejOjtkJ-3Er2H554Prl5_eaoP1gYG-O6PaDgD0OKyQBN-8fNXGZTOxNlr1Fkkh6x75c1yCZ-su7htj32cCo-BCewCjrK-_zDRxAR-gPBuCLfvV39i6Eb1QPijo_Q9TcELoPuXTn5d5RUY8LQs2V_KSoR6MPJM7GudJ4vr8mRNszgsxyVtM9qAefXZCwVwT9xlSIJ-T3G1NrtN-Y0n8BoVA_MTXw34QiKhrBVLST5lHd-vOmhL0B6acQs4uyLZJ-oB-KOvHpmd4pRMoAaec7_BAiLdb7hArMCgTHls2rw5XX_YRFJrGrRtYl7N8W8vdoFptaOne0uSlVM68GnMBCS4YHX77MG9NxVkgpd3HIOBQgYnjRwBetz4ZEaUvMyoTiBMI_UuehDTWpmfWpedPqfCYV0Pzzg3e9E28iP6SS-Xz-KVDparkGi-WFXkD2H_NT0BnUYWLlh38y389hMntDHabtrssFh8nsDXSYzF4fh8ns7aPDGORpKToTs19MKTs9huxy4j9fSxdPPOMv0ZUXVRjfpHWodmiIFhya08svfu22iWcYRstEXxq7nBZzGvxN-k81cmkshwaXU94zxuMbLtDkWN67ai--AnyXpcq5y06qcixBzv0N_xoix7_OVjzmyel48o_fPuPYvrGqnKhA89RzV4HvytH4vwvHsUMTKz990e_-FpKTozm9_J1ru0No_N9Fpj-hNPF43HsX03Pzm7ep7yKjBQ8_2bXVE8-Y1ZpVbUEisEfz4WcTQZoRAk3VDzsuVmnKHGzgWGxKNIbKzOsm8y-pYr0vJ5Mvh5MvS0jrhpIvi8mXkWsm1_BvaT3Eb4k__D_2jF58&rdba=clon&relev=ad_cat%3DO;ad_filtr%3D10;cl%3D2;cm2%3D0.0181118;cm%3D0.0869565;country%3Dru;ct%3D520-87%3A11886-13;dmoz_th%3D174-83%7C179-12;dnorm%3D32+autocad+bit+windows+xp+%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9+%D1%82%D0%BE%D1%80%D1%80%D0%B5%D0%BD%D1%82;dnorm_nav%3D32+autocad+bit+windows+xp+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BD%D0%BE+%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9+%D1%81%D0%BA%D0%B0%D1%87%D0%B0%D1%82%D1%8C+%D1%82%D0%BE%D1%80%D1%80%D0%B5%D0%BD%D1%82;dnorm_old%3D32+autocad+bit+windows+xp+%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9+%D1%82%D0%BE%D1%80%D1%80%D0%B5%D0%BD%D1%82;dnorm_w%3Dautoc+%D1%81%D0%BA%D0%B0%D1%87%D0%B0+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB+%D0%BD%D0%B0+%D1%80%D1%83%D1%81%D1%81%D0%BA+%D1%82%D0%BE%D1%80%D1%80%D0%B5+32+bit+%D0%B4%D0%BB%D1%8F+windo+xp;fe%3D6.48773;fir%3D0.267373;forum%3D0.59255;fqwg%3D5.218048216e-15;frqcls%3Dstrong_tail;fsm%3D177;fsml%3D11;geov%3D-0.000436704;hpq%3D0;iad%3D1;iad_vw%3D-33.57460785;il%3D0;ilp%3D0.001022;im%3D536870912;imgintent%3D0.56;is_music_ext%3D0.000;isorg%3D0.460;issite%3D0.460;issoft%3D0.750;ldatopicru%3D197;mum%3D0;mut%3D15;navmx%3D0.268605;norm%3Dautocad+%D1%81%D0%BA%D0%B0%D1%87%D0%B0%D1%82%D1%8C+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BD%D0%BE+%D0%BD%D0%B0+%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE%D0%BC+%D1%82%D0%BE%D1%80%D1%80%D0%B5%D0%BD%D1%82+32+bit+%D0%B4%D0%BB%D1%8F+windows+xp;ow%3D52;prel%3D3;qc%3D3;qlu%3D1;qmpl%3Dru;qr2r%3D0;qr2u%3D1;qr2v%3D0;qrr%3D0;qru%3D1;qrv%3D0;qt%3Dru_nloc;relev_locale%3Dru;synnorm%3D32bit+autcad+pyc+winxp+%D1%82%D0%BE%D1%80%D0%B5%D0%BD%D1%82;syq%3D1.136661591e-07;th3561%3D0.0179;th3973%3D0.0682;topicality%3D36.0447;tvm%3D0.00222546;uil%3Dru;utq%3Ddownload+here+upon+russian+for+autodesk+inventor+auto+cad+%D0%B0%D0%B2%D1%82%D0%BE%D0%BA%D0%B0%D0%B4+autoca+pdf+torrent+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BD%D0%BE+%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%B8%D1%82%D1%8C+feed+load+%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B6%D0%B0%D1%82%D1%8C+%D0%B7%D0%B0%D0%BA%D0%B0%D1%87%D0%B8%D0%B2%D0%B0%D1%82%D1%8C+%D1%81%D0%BA%D0%B0%D1%87%D0%B8%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5+%D1%81%D0%BA%D0%B0%D1%87%D0%B8%D0%B2%D0%B0%D1%82%D1%8C%D1%81%D1%8F+%D1%81%D0%BA%D0%B0%D1%87%D0%BA%D0%B0+galloping+skachat+besplatno+free+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BD%D0%B8%D0%B9+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BD%D0%B8%D0%BA+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BD%D0%BD%D1%8B%D0%B9+%D0%B4%D0%B0%D1%80%D0%BE%D0%BC+gift+%D1%81%D0%B2%D0%BE%D0%B1%D0%BE%D0%B4%D0%BD%D0%BE+freely+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D0%BD%D0%BE+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BE+%D1%85%D0%B0%D0%BB%D1%8F%D0%B2%D0%BD%D1%8B%D0%B9+russia+%D1%80%D0%BE%D1%81%D1%81%D0%B8%D0%B9%D1%81%D0%BA%D0%B8%D0%B9+rus+%D0%B2%D0%B5%D0%BB%D0%B8%D0%BA%D0%BE%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9+%D1%80%D1%83%D1%81%D0%B8%D1%81%D1%82%D0%B8%D0%BA%D0%B0+%D1%80%D1%83%D1%81%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D1%8F+russification+%D1%80%D1%83%D1%81%D0%BA+%D1%80%D1%83%D1%81%D1%81+%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE%D1%8F%D0%B7%D1%8B%D1%87%D0%BD%D1%8B%D0%B9+russkom+%D0%B1%D0%B8%D1%82%D0%BD%D1%8B%D0%B9+%D1%83%D0%BA%D1%83%D1%81%D0%B8%D1%82%D1%8C+background+intelligent+transfer+service+%D0%B1%D0%B8%D1%82+bit+%D0%B2%D0%B8%D0%BD%D0%B4%D0%BE%D0%B2%D1%81+%D0%B2%D0%B8%D0%BD%D0%B4%D0%BE%D1%83%D0%B7+%D0%B2%D0%B8%D0%BD%D0%B4%D0%BE%D1%83%D1%81+windowsxp+windows+xtreme+performance+%D1%81%D0%BA%D0%B0%D1%87%D0%B0%D1%82%D1%8C%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BD%D0%BE;vcomm%3D0.248625;vintent%3D0.95;vm%3D268435456;vnorm%3Dautocad+32+bit+%D0%B4%D0%BB%D1%8F+windows+xp;vnorm_dopp%3D32+autocad+bit+windows+xp;vnorm_syn%3D32bit+autcad+winxp;vqi2tvec%3D1%7C0rkjACu_CrE81xPoE93gAB5X2uKgUsx_JvATChj78_A%2C;vqsemvec%3D371364212%091370421533%093362250591%092760956004;wizqbundle%3DehRMWi40AQAAAACAUzAB-F8KZipZehRMWi40AQAAAACARwAB8wYSXBJGEgdhdXRvY2FkGAAgAioMCggPAHNzEAAqDQoJDgAQJw8AJAsKLAAnEAEcAIRzJxAAIJMCKh0AoDICCAI4AUAAIAAAAAAwo7-XscucoK7PAQr0ByrmB2oA8P9S1AMB9g8SjxcShgkSDtGB0LrQsNGH0LDRgtGMGAAgASoQCgwWAIfQuRAAKhYKEhIAfbLRiNC40YUYAMe90L3QvtC1EAAqEgpYAE3QtdGCLAABRAAt0LwYAH290L3Rg9GORAA9vdC-LABRtdC80YJwADsYChSgAAAcAB2DMgACdgAP0gADH7WOAAMh0L4CAQrSAD290YtcAAD-AD2w0Y-6AD-70LiiAAQRs9QACloAP7vQsFoAAS_Ri54AAy_RiwABAACKAB--AAEFA14BCjIBAjIAApAACv4BHbuOAABEARG1dgAKKgAdveYAAMwBMYvQvAABCuYAD2wBAQBYAB-4WAAAH7KCAAIRuGoBCYIAATYCCtgAAlQAD4IAACHRjpQCCZYAAAADLxAB7AIAAtYBNxQKEGQCX7XRiNGM8gABI9CwSAEMMAACqgIKSgMCeAEABgMJigAARgAN9gABLAAB5LYA8HMB5AANigAAFgAEigANdAAh0Ys-AQ8YAAEA1gMKYAATuWQDCi4AAGAAH7UaAwARu9QCDywAAAG6AAoYAAIgAna5EAAS6A0SYQQyuNCyjQEBjQQ1GgoWdwECGgAzjtGJgQII7QEBHAAAawQBQwINNgABsQACyQENHABP0Y7RiRcDAANSlAHwZdMAAhoAAusADU4AAGoAA04ACEkBAzQADzIAAQCAAA8NBQABMgABlQIKOQECGAACwQI_HAoYHgEABPMCD5wAAgOLAQ6cAAAXBQ8yAAMC7QUNbAAA6gAFxwQPOgADAiMCDToAAfIABDoADx4ABQLBBA5YAAAaRwDw2Q0cAAFYAA_mAQQBrgACYQQNcgAA5gEAYwUBSQMNVgAAHgADBwYOcgIfuXICBgGoAAEjAw9wAAIFKQQOVAABHgAPKgIHAXsHDsABACkFDWoAAhIBA5MEDtoAABYDEbhbBg1QAAGxAw0yAAFQAAJDBw0cAAJiAQ-aAQgCtQUOOAAAKgEC9QcOHAAAogAP7gMHDoUFAR4DALIBAaMHDVAAA8AAAKUICI0EAjYAAn0HDTQAAk4AASYBDWABAfQAAcAAC4MFAlIAAL4AAP8HDzgAAw-hBQECOAACNQgPigAEAQACDhwAAWwAAXAJAOAAUgICaQYOHAAAOAACkXYA8GcBOAABCgIOIAIA6wgPMgAED4QFBAAoAQKxCA4QAQFqAAOoAg6aAQKgAA42AAC8AATuBA4eAAJUAA9IBAQBCgICWAANxgACHAAB-AAPjAAAATsIDTQAACYCDxYBBQJQAACcAUcgowIqHAsA3wWgMgIIATgBQAAgRQT4AjDk_fqeq-3Q-OMBCqgCKpoC9wPwCAgBAf0XEr0GEqABEhLQsdC10YHQv9C7-QMA1gPxARgBIAEqHAoY0L_Qvh4An7UABPAlGAoUGgAELxYKUgAAHxBQAAkftVAABn21EAAS-AQSawBv0YvQuRgApQAKD1UABR--vwAFTwME-4W_AAKdtdC9EAAqGgoW8QBfsNCz0L69AAYAJwEPDQEFDz8BAT--0LyAAAI_vdGLZAADT9GL0Y8aAAYfhRoABQEaAQ_OAAFfvtC80YM2AAYAnAAPtgABEbCEAA_oAAEfsEwAAyHQvoIAD18CHgD0AQ-IAQQfvogBCBG-1gEP8AAAb9GL0LzQuKQABAFAAk8gowIqzAIAKwHovMHs0NOEgNjdAQpIKjspAfEAKQAB8QISJxIUEgTQvdCwFAXBCAoMAGEQASCjAioLbAUAdQESAWwF-AHYpuGipb-7vI8BCu0BKt8BTADxBM0AAfcPEvEEEuwCEg7RgNGD0YFyBRC4NwEEbAUhaL5RBREoAAWRFAA-vtGOFACIZwXgFAoQTgBN0LzRgxYAe7jVAPAfEAB6AAASAAw-AB-zkAAAP7jQuXwAADq8EAG4ACHRg6QAClIAH7BSAAQAugAK9iAA8Cm8ZgAADnoAH7geAQCPuNGFEAAS5AFvAQIKkQAPIQELDCwAD70AAw6VAAIPAQo-AA_7ACsP5wAGSO0AYy4C0L7QvPAAA2UC-QDW3teX_ICvr_gBCqMBKpbwAPEMhAAB-g8SmAIS-gESDtGC0L7RgNGA0LXQvdGC8ACiFgoSFgCg0L7Qst0A8hMMAAYuAE_RixAALgAAP7DQvC4AAS_QsC4AAy_RhS4AAnq1hgJQcgBv0LD_APIESAACH752AAN70YMQACoSCugAa5cBFRWXAQOnANjLxM6v-_j5l1oKRyo6lAH0GCgAAXQSJxIZEgswAQDwDTMyGAAgACoGCgIzMhABIAAqAjMyMgA4AksH-QCA877ojIGuoecBCqQBKpfvAPFthQAB9hESvQESMhIDYml0GAEgAioICgRiaXRzEAAqCQoFYml0JwsAcHMnEAAqBworAEYQARI1NADwAQsKB2JpdHRpbmcQACoKCgYNAEdlZBAATQAFNwAgQBJgADVlGABsABdlNQAVbgwAAk0AAoQAEGWEAARCAEAgkwIqg_AAB_MH2J-xsZ7qkK_2ewpJKj3wAPECKwAB8wQSLRIYEgbQtNC70Y-KAVIKCg4AYzsBEQ1LAAfSAunHnYGH9bv932YKkQEqhPIA8QNyAAHyBhLFARJBEgZ3aW5kb3f1AGEMCggOAHPnAPEaCgocAGMQACoLCgcaACYQAScAZSdzEAASQkMAPwAgAjUABzINCglCAFb8APEKRAB0ZWQQABIoEl8AD4gAAAh8AEQgkwIqK5QAB98A2MbplNn6pa_fAwpDKjffALElAAASIRIQEgJ4cDIJcAYKAnhwEAFFADoCeHAXCdiHlbXAt_bOjnUKVypKRQCwOAAB9AcSQxIsEgh-CUFkZXNrTQBgDgoKEAB1wABiKgwKIABlWAAcD50A-QDmvbXihY6InIYBCpgBKosyAR95WwAcJPEHtADwHxJiEksSCGludmVudG9yRQA0DQoJEAAARAA0DgoKDwAEVAAEEAAgEAFyAAQOAEF9AUdkAAQRnAAAWgr5ADC5xvmm0_qipSoKoAEqkpsAsIAAAfADEkwSORIE9gAB8gBhCgoGDABx8gBwCAoYAGAQAcoBQBYAVGVhAPUAIwCBZXMQACCTAiokAPECqgAQRAID8A5jYWRNAGEJCgVjYWQ1ADAICgQLACMQABUAAWEAIP4CfCAQAUcAAAqiAK_p2fTEnaq4t64BowAC4PwREpoCEvwBEhDQsNCyVQQAswoj0LSbBWAYChQYAJwcBAFTBIEyAB-1FgABjCAEURYKEkYASgQCVgTwAAI_vtGOGAADL9C5RgABingE8AIqEgoOdAAvEAGIAAGL0LwQAPcEES2jAAASAwNNBOjw7e2q0ZnMoLYBCmUqWDoCcEYAAfIFElYQAwBEASFjYUYBARADEEYyATEOAHNNATAKCipwAwBNARAoIAMAQwERGmcAB8QD6JGI7ved-9fU6wEKfypzZwDzBWEAAfUHErABEkwSCGRvd25sb2FkegNQEABkEAEfDNEeAHRzEAAqDwoLDwCUXgNxKg4KChEAb2ID0EtOABkHPQAqcydNAIWTAACCAByMggCeq4T0m6vIyclDNgWhABIkEhISA3BkZuMAIAcKCwACEQMACgAEDAICFQfosbOQvtqmg6CnAQpjKlbKABZE6QxxdG9ycmVudE8AAekMAcAAAekMwBknDwAQJx4AJAsKO-AAAK0AHA6tAPgB_Ma8_MTw4JzsAQqrCiqdCmcALwsF7wjrJPANtgfgEpoYEvgXEhLQt9Cw0LOFCODQtkIDJdGMmwIJGgBj0N8N8Du1qwAAkQAGHgAzt9C4HgAANQIKHABzttCw0LXQvLkBOxQKEHAAAAMCAH8BBk4AMLbQtd8ADS4AU7fQuNGCQwEILgABYAADKQEAl4YM8AIFKwENmgBl0Y7RidC4AwIGOi8L8GMF6QEGGAAAbgAACAEEOwMPUgAEAesBOBIKDuwAAZ0CCuoAAWYATtGMEAEYAS_Qu-oAAQKwAAFpAwzqADG10L2dAgLTAwqYAASgARG40gAKbAAAHAAAHQMNmgAAUAUNhAAALgAAAAEC4gAMhAADigEDJAK2CvAWHgARu28ED5wAAxW16QIJbgEC8gABDwQKOAAAUAABigABHAAK1AYA8WQNQAIAFgAAoAIOmAARtVgCDBgAAFIBAAUECngABQIBDzYCAyHQu5UDCjQAAkwABM0DD2gAAQCHBQ1OAQH8AARqAgweAACeAB-92gIGAx4AAaQAD4wAAgOQAwwcAANUAQFiAgAvBQaMAQX4AA2MAAQaAAQchgDwB1QAE7VMAw5uAAIaBACWAQ8cAAIDVQa7APAbcAAfvFIABQE0ARG1wAAPMgECAOwED4YCAAMyAQNfBwqOAzG30Y8gAg2iXwHw9AJUAw0cAAMQBQStBgZIAQEQAS_QvPoEAgAQBD2I0Yx2AwSeAAI0AA1sAAGIAA98BQUAJAMCHAAMeAIBfgEPbAAAA1AAAZADD0QBAwRrBwqKAACYAQBuAAKmAA5uAA9QBAEDhgADeAEK6AEBHAADEAEMiAAE2AAG8wcKYgEfuSACAgSiAALyBArmAQFkAQ3cAgRqABO4bQcK8gABNAABNgIA6AEN8gAv0Y44AgMAAAIDnAMKJAYRt14DDGQAAuwAAlYBChwABdAAAQQFCiQBBBwABEAECjoABFYAAvwGChwABDoAAr4CClYABR4CD0YDDABSBgpgAQBWAA_UBgIAKgMDvQoUAvAeMgAAUAIEfAEPHgIAAEgBDcICAzgAA1QACtwAAPgAADYCAmEKDbIBD74FAgNQjgLwAw1UBgEcAA2CAABmAAK6AA_aBBcBQQA0Ag4XAvGyD1IAAQKWAwHCBw_UAAQPoAAAAbABD04AAQDOAAPLCg0GAQGUCA-OAQUAPgEAZwsKrAEA8gAB1gQPGAIEAtgAApgFDr4AAPQAAgAICowAAF4BAjQIDW4AAw4BAowADlIAARoAD_oAAgIaBwItDQ5-AQHEAA8wAQEBcAAChAMPNgADD8IHAgNmAQ-mAAMCigAP_gYDAxwAD9gDAAHSAQC2Cg-SBAkDDAINGAEAOgACGAECHQwGNQUAewbQgtGMMgIIAV0GEAEUEvgBi5Xsua2Avp3ZAQqeCCqRCH4SX_8DAfoTKQQBAB8OIdGMMgpyHAoYGgD3ATAEANENAt8NBDQEYx25HAD3AjMEJNGLvwwQOMkCIWqPTRKxhgBdtdC90YsuAF85BPIJYAAFb9C-0Y4QALYAAAJ8AD-80Lg6AAFvOQQghADYAvEKAbIADwgBAxOwCAEKugABNgAv0YxqAAcBIDsE8QgEAS3Rg-oAADQBH7tGAAgfvOoAAHO10KgSYZgAD6ABAy0EwIQBALwBAFAADcoAT_MOwGgAAAFSAQ9oAA4A6DEN8Q4AOgAfuzwCCQHAAQq4AAAgAgKiAR-FDgEBAXQCAiIEwQBsAB-yVgECD5gAAx8EEbAfBPENAgEKlAAAMAEACgMPNgIEL9C7agICAEwAE72kAiEEglQDDWoCAZ4CIQRDAVIADyAEs9oCCsAABRwAAQwCIgSAEgI3GAoUqAIiBC8UAiIEASOeAyIEZi_QvooABB8EGTYfBLwWASHQvqIDCyIDISAEogFIAR-1ZAEEP7UdBJBABB-IQAQCAdAYEgccBBCs9wAAHAR1iAAPWAMBAhwE8QAxvtC8tgQKigAECAIP2gAjBPQEUAQKNAAAGAAADgECeAEPOgIBAiAEbwKIAA44ACAEBPIAH7hCBgQCmAERvugBDWABHAT2BAIQBwGcAwoMBhG3XgMOIgEAxAEcBBkgHARoBdgAAYYAHAT5AASSBQTsAwo6AAYQAQBABCEEUS_Rg24CIQTzAvoABHwBDuYBAAACACgICoYAIwQQHCMEZwE2AAEyASMEIrYBIwT6BA9EAwEA1gAD8AcOggAC1gAAEAkjBIpqAg5SAAHUACUE8AgPuAIGTILRjBACCgHqAAIGAQH8Aw0YAgoCNW4CCyAEphG1qAAKkgEAdAAhBCAABFEAoBoAAVIADBwAAbL6A_YADn4BAIwEDvQHAUYBI9GJJASCARQBDy4FAwQkBPEDAqYAAqYCD_wAAwQWAw_gAAMCZwJwAU4JAvwASuMKW3ULAfcBFBHp16ff677V8PFICo8IKoEhBNHvAwH3FRLkGBLAGBIUSggCNxY3uNCyIwRwFAoQHAC3sFASAh0EEBZiFBBBRQiQHAA9FgoSHABoWBbwABgKZgAASgC9vdCw0Y8QAHgSoDIAAU4AATgACmyPAZAh0LNsAAxUAF-dCHC4VAAMHbzAJBNkE75UAA9wHBIgxABdBPMDEbWmAD8eChrEAAQCOgAP5AAAQQTwET4ABgBcABOwlAAP6AADH4U8AQQAOgARuOgAD5YABQRYBwDxDAAByAEPmAEKIdGLXAAK6AF_sNC50YLQtZIAB8oSUEIBAFG9tATgOAAPrAABA8oAL9C4tAF9CPGKE7UgAQ_IAAQh0YskATcSCg6cAQKOAg8yAAcPkgIFAnAAAJICDBQDEbugAAqkAQEUAwBGAy0QAYAAH7sIAQAAXgACdgEOXgAesBYAT9GO0YJsAQMBVgIRtVIBCpIAAVQDA6QBDNYDEbXSAQwwAAa2AQ0wAA9-AAUByAACggMP0AEFBLQBDG4AABAEEb4OAw-cAQQh0L7WAA8ekwDxIjwADNoAEbsoBAysAgGmAA2GAQG0AQNwAQ-eAAADTgIKIAQCNAATuVgBCjYAAhwAAiwJAPCyggAftVYECg9MAwQD4AEA3gMPCgEBAdoAAQoBD3IAAQT4AwwQAR-1wAAJARwCCjIAAtoAH7LmAQQA2AATi7YDChIBBKAAD9wACwBkAww4AAIeAgA4AAwaAAbyAA-kAAEAbAMLFAIBlgMOIAECigQfvBgCBQNyAwx-AAM2AA9-AAMBigYPCAMAAcQBE7giAQ_GAQUC5AELPAQPRAUHD2wABQGSAwCSAQDABg8UAgEPiAAIAqgAAUQFD6YAAAEeABG1kv8A8poAA3gAALIBCnYAAjwCAJIAHYuCAwFQAQOkBw84AQUAOgAAzAAPigEBAmQGCggCAN4CEYjyAQ9SAAAA3gIF-gcPUgAAIdC-4AALQgIADAQPfgUDAFAAA9AGCk4AAvYAAioGDxABBAHoBQvwAQ9kAwUCfAED_gYNngABSgAKgAABWgEDJAUPCAEAAVAABB4EDIQAH73sAAgCcgEP0gACA1QEDxwCAAFuAAIGSRfQsAEPOgAEA0oIDx4AAHEG8glGBw8eAAUCsAIMHAEARAQCGgAPOAAFAq7cAPAOzAAAkAUPzAABAFoAAL4ID3IAAgE4BA9UAAYB0gNDAPAMADgAA5gCClYABGQCAKILChoAA4gAAXAACh4DiwnwAuQCD2oAAQG-AA8ABAoBbgFIDgRZ3QsCVQAzCBAAMwj4AZy27ceGip-f2QEK4wEq1gEzCNHEAAH9FBKMBBLoAxIU1RQARxoBEARh0L3QuNC1NQiSGAocAK7RjNGOEARQNgBv0Y9mD1A2AAEAUncPQDYABY-UFAAEBBBSmg_wAbhwAAUv0LVwAAgANgAPwABxA_AAwAAFL9GMwAAJL9GP2gADGQDwARoAA0_QuNC5GgADIdGM1ADYAvART9GM0LXuAAMAGgAB7gAPegEAAIQAD0QBBQAcAAJEAU3qAEzPAQBF-AT4AJi7qpKGyID3PQrsAyrfA-YA2s0BAfsXErYLEpALEhbmAAAZCSPRgU8TYB4KGh4AcPEMYbXQtSIAauUEwBQgACPQuxoADToAjzcJABsXQCAACU9OG_IIIAAKM7DRjyAAKxoKuADr0LvQvtGB0YwJAfAGlgACXAACHgAPOgABBBwAPyAKHDoABw3wBrNcAA_YAAIBEgEzuNC5mAAP-AACT18F8BwgAAwPQAALH7hAAAcBgAAGQAANkgEBcgEAFgEPmgADFbhSAQ0gAAJaAAFAAQfwEg8cAQUzvNGD3AAOWgEztdGCHAANXgAAEAIHXgANIAABfloAYA8EWAENnjIA8lUfsLoBCQKCAAXMAg9CAAMxuNC8HgIAAgEPpAAED7QCBwKEAAViAQ1iAAGCAA9iABAFpAANYgEl0Y5iAQ72AjG50YI6AAD-AQ0YAgWyAg5UAAMCBB8QAAQAA7IAD64CDQQgBA1cmgnwDqYDBhe1sAANLAEBTAEA8AEEbgIPIgAFBqwDDSIAtQLwHBQCCgBmAAemBA5UATK10YggBQ_-BAEB6gEAbgEPKgIFD74EBwDaAAFmAkvvAVvbBASTBecG6enM4IPgrJuYeQqUASqH1QLUdQAB8AES7gES0gESDO8BMQYAeB4ZYRAKFAB3uHcWsQ4mAD2-0LkUAJewvQLxChQKECgAMbDQvD4AClAAK7AQYgAt0YNOAD3MF-I9sNC8TAAbtRIAmLXQumMSRMEAsLCiDwIzEdiW1aqNnOWslW4KcCpjhALxBFEAAfMHEocBEikSB3NrYWNoYXT7EWANCgkPAHTLEfASKgsKHgBKEAESRisAMwwKCCsAACoABjkAKXMnDwANSABEPxEcVj8R-AC80eakh8SnqcABCosBKn9zANRtAAHwERKkAhL0ARIgCAEC8wIGOxpAEAD_AesHAR0BMCoKJjsaMywADDwa8AwmCiIoABIPVAAVH7VUABQAKAAvJArQAA5vEAGZATsnAA6XAen5xY6Ulab6tjMKrAEqnpcB8QaMAAH1CRKhAxIvEgliZXNwbGF0bm8EAWEPCgsRAHYEAfERDQoiAEwQARIeMQALIAAcUiAACFEAEGVRADUQCgxiAF_BFPAldAAOH1BUAAkBQgA1DgoKVAAAZAAIdQAPxgAhD-YAHgjVADtpbmeDACxlZBEAAKUACjoBRj0BEWo0BAerE-iJnJWDwt20i4EBCnwqcDwB8QFeAAHwBBKkARIrEgRmcmVlqAByCQoFDABwcu0XUQsAcXN0YRWxIwBOEAESNy0AcGTGAUEHLQBUuhOwRQAZczkAD2YAGUF_ABxxvAHp5MjfwIHK0NUTCpoBKo0tAdZ7AAH2CxK5AxLOARIKrgEBpgGBEAoMEgCG0YsrFTAQEgATEgI6FXAOCjoAZxABDxWwJgBavtC8EABMAE3GDVAmAByyJs8CwCYAH7BMAAAesCYAT_YCQNEAvkfLARFoHAEHLhXpy6ShvsiwpJVTCvoBKu2dANbbAAH_FBLQBBKsBBIUnQAAWwIBNgYVuTYGIAG9_BkDkhxQOgARtR4HB2ACL9GFGgDADBC5BwCRuNC8GgAGfbkQWxqAggAfuDIABS9LHDQEnbV1BvAPTAB_tdC80YMQAGgAAQ9OAAUh0Y5OAA8CAQERtc4Apw1QP7jQvLgYAMCPagAPcAEHADwBD1RIChCP6A7yBvIABQGmAQ82AAAj0LU2AA9aAQF_tcYDWhMCAbC5xwOfxY7vtvKou7MXxwICj_8UEp8FErwC_QACEbqkAQAzBzECbxBxD0A2AAFvghtgEAAeAAh_NRtgGgoWPAACgACBKh4KGhwAAl_CAfESPAAIDxwACC_RgzgACB-wrgAIP7DRhR4ACQDqAA8_Af8tBx07YgICdQP4AcaI8fa1rMGLsQEKpgIqmALJAt0GAQH_FhKnCxK4AhIWrAERvfwd4AEgASoaCh4AAz-8EAAclAeAvtC5HAAIDziNACCOOFUBkIMcAD4cChiqAMsAELPNARAFJwBgtRwABQDkBAiyVgAGP7zRgzoABY8RDPAXErw7ASIAOwAPOwEDD1cBCS_Ri8kABwNXAQ_JAAUCHwEPHgACAHIaCBAeLQiwsFsBCQ8_ASef0YuYAvEuEsgDegIhDz8BIw-WAgkPWwEQDwYDAg-yAi4PkwEpDzwAAgAJAg-2AggPDAMPD-gAAgKvAQ-zAgMPCgP_MygBPGYFA9cB6Pnp99egktmV6QEKTSpBJwGwLwAB9wgSORIgEgqVGCDRgLEBAcoBMA4KElQDACQDApcZByQDn8HXhZeluLalHj8EAPUH-xEStAESlAESENGB0LLQvtCx0L7QtGsFYhYKEhgA3aIfMBoKFncFMBwAbS4D8gMUCkwAHxBKAAMALgAPSgAFfbmnAhFLPwQHfgDY6IT9ysKFy7o5ClcqS80AuDkAAf0OEnkSLBIQ8gEFfAAwFAoYsgExLgAbTgkcRVkA2N3H666P0qrwTApTKkdZABE1WQAcS1kAAM8ZAfMDAFkAEm0sARwXVQDpn_CL1IKJ3ethCrwBKq5QBPAInAAB_RASiAMS6AISENGF0LDQu9GP0LKyDQNjHwBZAPAKHxAWAAE9tRAALAA_g9GOFgAAPovRjxYAL7EGoQEv0L5YAAGr0L70IMAWChKyAD680LgYAG7KAUDRg3IAnyCQhS4AAj6z0L4u7CPxBw8WAAARsMwAC4oAL9CwRAADINGLRAATARxTDgXorN7M1fKtjPSPAQpUKkgUARE2PBq0OxImEgZydXNzaWEKGQY1GhAcNRoAAgYCpR0HgQbY2YSlusPR2boqCm0qYFYAsk4AAfQFEngSGhIHVgCSbhgBIAIqCwoPIwhyHAAzDQoJKz4mAmEmoykQADkAByoAhCfdGw0sCPkA-6qwpt32g5SJAQrUASrGhAGgtAAB8AkS_AMS2AoMMYDQvuUgMLjQuTkIMQgAfuABANYEEV_uD_EQGgACT7jQuRA0AAM_vtGONAAGH7UaAAMv0YM0AAh9vCoUQBK4AH4WIWAaChYYAE-FAWE0AAQfuIAhDPAF6AAHL9GFaAAGEbOEAA84AQERvrYADBABmApghgAPHAABAiFiCg88AQSu1gEAgwMgvwEwDAqtBa-q4bqf8pLDtqYBdQkAsfALEmQSHBIDcnVzQgFQCAoEcnXUG_AAKgcKFQBGEAESNB4AeQoKvQFAZSAAQfEfEBXyHDQLAIBJASBAAHEFB7cB-QDj_o6a2pz4xI8BCt0BKs9JAfEIvQAB_xoS7gQSxAQSGtCy0LXQu9C40LpGIRGDVQEQusMAAVABYR4KIgAFn6gHgSogChxCAAR_ZiPAEABCAAoftSAACj-4XwwQC5ML8AKiAAkfuaIAChO-ogA_HAoYxE0BoUAADD-80YOiAAnqEPAMIAAJL9C4AgEMH75AAA0v0YVgAAw_uRABpAEIWAEQ5DEHkQcPwgELELCiASYFMCUCBY8AClIB-QDxkqauxviIwsEBCqIBKpXgANCDAAH-ExK0AhKSAhISiRqB0YHQuNGB0YLmAAJqI1EYChQaACMOADwkUBoAAX7QcwswFgpQYxRQD04AAozkBaAqFAoQTgAPMAAERAJhYgAEH7UYRALTGAADP9CwEOAAA56-0P8EHcVsC-nkupf52uG8oTcKqQEqm6UAgIkAAf8XEsoC_goVFqUAEoSjAEPRhtC4QSFxHAoYHgADj40AAf4NIwOfhR7xIhoKXAACARwAD1oABE_QtdGOHgAHAFoAD1gAB0_RjxABdAAFAVYAD5AABR-5cgAHr9DLBQCjAmrLAALA0Y9RAfkAsJKumbn30cyuAQqTASqGrADTdAAB9AkS0AESuAESCKwAEbofAmAQCgwQAGo0I6IQABIAK9GFEgCVdiNgDgoKNgBlVAHxAgwKVgAaEFQAEb5UADUSCg4wwgzyATQAB0QAK9GDVAAbtRAAdbCaABFlyAIHQga_-oj2o4emraw2CpVFDQAq9QiWACHRgREHBK0eZBAKDB4AaZ4AEpiZAGESCg4kAITuAfAIDgoKFAAr0Ys2ADuw0YUiABuDIgARvmqaAHMq0LUyAIXQlwAcq5cA-QD_-tm7xIeol4cBCqECKpTQCCACAV8DcrIGEogGEhouAQCiBKfQvtGP0LfRi9GHNgYAXwMSBt0B0BwKGEIABa8QACoiCh5tB-AiAANv0LXQtRAAYgAKf8AUYCAKHEAAAw4ncLzQuEIACy-IBPEXEB-5RAAJDyAADhGwpgAPKAEGIdC-hAAPIAAGAGoBLxAB5gAHb9C1AzBqAQn3KDBgAAefBvU14AAKEb4gAA_IAQU_tdC9PgAKAsQBD6QBBgD-AC_Rg0IACSHRiwYCD4AABT-90LA-AAkh0L4-AA-AAAkCPgEPIAEGr9D8AkzpAgbApAPpiY66wtOj_skWCpwBKo9SAhF9bA4gzgJsDgA-BjFrb238BA9sDgCRGisACRwAGigccw7QRwANRgAaRioABnEATCUF8RWAAA9IAAgaR0gAMw4KCnIAOWluZ0kAL2VkSQALD9cACQ8cAAiYDhEdMQcHIwXp1JyM4sqUsu1pCr4BKrCfAPAAngAB9QwSxAISqAISDNCxfh4HtQEAoQ8QpLQHAk4CwiYAatC-0LPQvhQAiBIo8BUQADoATNGL0LUSACrRhTgAI9CwTAAHcgAATAANOAAbjzgAW75tBvALJgA6g9GOEgAs0L6CAC3QviQAEbBcAAeAAEpPBmNIAAAYAWWsCDwBABOEAvkAgone2__i_ODlAQr7AyrtUBLzAtsBAfQOEv4IEuAIEg7Rg9C6BQUEfS1gEgoWAJeIMicA4wJxFAADKgBmEPMJoD4AIdCyLgA3tRBrGTESANvlGgHsAGEYChQwAFlKAmAyAANKAElpEsF2AAJKAAosAAIUAFmsC2BEAAMYACtvCUADXACryAQCRwUwjgB0DgQB9y1gSdGP0YKEIhLwjz-I0YzKAAITtcoAClYAMbzRghIBBvoAACoAAxIBKdGDtgAEngARtfoADzIAAQ8sAQQh0LDQAAe6ACHQuHABNA4KCswAAdwADVQAT9GL0LwaAAMFmgEGDAIAoAARuy4AD_gBAQDgAQYYAAPmACHRi5oADEQAAMYBBpwAG4gIAQU8AAE6AQ9UAAAB3AAGGAAAmAAAfAI_uNGFmgECE7jkdgAAahLyKwQCfAIJUAELCgIBpAAp0YvAAQEUAAB2AgHAAQZuAAUYAAFuAAaEAQS4ABO1CgIJcAAt0Lt6AgJKAgrWDvAIIdC7rgMGfgAGZgAPJAMDAjwCBjAAAJB_F_MLAU4BBhgABEgAEbhUAwaGAAEwAAkIAQYqAHQlJF5NBAA_AzQV-QDDn9HZ2s_81sUBCt0CKtCCBPEHPgEB9goSxgESVRIKYmFja2dyb3VuZGEDcg8KCxIAdnOJAXARAB0nEgB3RwPwEioOCkcATRABElZXADYRCg1GAF9pbmcQAGoADC5lZFgARx0KRGkA8gxEA-ESPBIiEgtpbnRlbGxpZ18j8xDJAAcTAAI9AAglAAU-AOHTARJLEgh0cmFuc2ZlcgUBWCYg8QC2AfAqDwABAQElDAovACAQAf0ABB4AAA0BKxJvTQA0EAoMIAAScvoAD18ABwH2AApfADQPCgs_AAI-AAcRIQHAABYBBZAABdYA1KMByjDyAXNlcnZpY2XVAAMPAACnAERuCoICkwADDgAB4t0jYEoQARJFSK4S8AIAowEFOQACnQAGHQAAOQEIRzQAIQRVXwMCHwQByB6fkNmj0NC6popBvxMCIPIHDQdCogESBh8EA3gGQQgOAIIzKhAO-Sgik9BzBhQKSjEgV7BJA3E6ABmLOgA4OQ9gKdCwDgBzVQ1AEAoMZl4DoLzQuD4AEL5cAEOrBxF5lwAHEQfY4__2qtGk64MoClIqRZAL8AQzAAH7DBJFEigSDtCy0LjQvdC0fwAh0YGpBwDxAw_DKgWvrNbfha7H8saFAacIAoj6DxLCAhL6AVgAQdGD0LfzAAFqKxKbYwfxBCoSCi4AHxAsAAERviwAD0QAAIy3CPAHFAoQXAAPFgABL9GDFgACH4sWAAGM0PQAQBgKFFh4C2HQuIoAAn8tAVASKPwAAl4bAVgVHPn_APkA8omD97a-ic6qAQqCAir1tgXW4wAB_xIS5AQSxgQSEgQBAdQKAEUQEQCwACQaADcXMjIAjxgHMBAAMp0AQIUYAAIZBwAHAECL0LUYJCwgtRj7CVDQvDAAAZ4No48YAAEh0LAYAHsSD_MWxgACZAA7FAoQGAAA2gAOFgAfsGAAAhG-2AA6EgoORAAuEAE2AbIHckYAAw9oAQRVHHEyAAEATAAPUADyC744AQ6yARO-sgEN2AAv0YsgAQgfuWQAAgEYBgEc9QYB2ODPj6GB5K3DQApMKkAFArIuAAH2BxI2Eh4SCTcrE3OvKjANChHiBQDGAxEQTgAC6gL4AwAAAAAw-tq7zK_BqvY-CnIqZk4AEVSGKx-BhisaASkWQRIoEhsBAjEIOAB9BxwrdAC_0omXtNqDmvtTCkcXLwZB0YXRgL0CDxcvAgO9AOmOm_CVjYH8lQMKrwEqohACEZD4DqJwEkESBnh0cmVtIxVgCwoHDgBjAgUwCgob9w4ALgSQGQA2JxAADgBpUQ2AEhhDAAc2AEMtAUVDAPcS8wT3J3QSWhILcGVyZm9ybWFuY2UYACACKhEKDRMAAFUACxMAAXYANxAKDCYAAKIAKA8KSwACcQAIEvsAAVkEn4-3-KiRx_W-bxIwCE_RhdC_-wAO8BHs9vjQu-y-q9sBEpIPCAsQABoQCgYqBBCszRkSAggAGgQA0A8KBSoDEOYKEgIIARoEAAIRAHCQBxICCAIaBAACEQBwhgISAggDGgQAAhEAcKweEgIIBBoEAAIRAHDEYBICCAUaBAAHEQAgBhoEAAJ4AIDorgMSAggHGgQAAiMAEJoRACAIGgQAAhEAcOosEgIICRoEAAI0AICuzQESAggKGgQAgB0KEwgBEAEhlQLhACCMQCoEEKKfIxICCAvLADoeChQfAFAFEPyhzz8AEQwgAAI_AJAQIXyXoXOSSYo_AHHa-RQSAggNHwACPwCQCCFY7o9JfJaNPwAwtsirPwARDiAAMR8KFT8ABX4AYAYQuJjikMIAEQ8hAAJgAJABIV24LWmnAY9gACDO2EAAERBZAQQfAHDuyi08B_aOHwAgsp8fABkRHwBhB0ZK1hsOPgB5lqYEEgIIEh8AYc2MfSSf8z4AEcBdABkTHwBnMTCaOAjUHwAZFB8AcBUHTKcN9I18AHmA3g0SAggVHwBhZmEqRwHLPgAg8uObABkWHwBhMKIgeX_1PgB55NczEgIIFx8AYawhD5xn9D4Ad9DNEhICCBgfAIEoIWSP8_0lhh8AcZDnGBICCBkfABEgtgHzDBAhbBwBtIyUQsAqBRC284YREgIIGhoECAEQAjkBkCEhxLnuH70Yi70AcYrGNxICCBugAgIfAIEBIZNP1el_OjkBBncBBh8AYTE2JtPjLh8AIMTB3AAZHD4AYXDHgNvQJJ4AcdacbBICCB0fAAIVAvABASHyO1hVremOQCoFEMzz6DoBGR4gAHASbDrXX7yLIACBjsaYZBICCB8gAAI1ApABIbYJAsO4x441AkDQ5ZaLTQMRICEABb4AUSGu6wMgXAEgvIo9ARkhHwBhMMdbmuHv8wIgnO2tAxEiHwAEnwBhrl2R_tiInwAwtv25NgIZIyAAYcP9JXiQ2CAAMKSro0AAESQgAAR-AGGLK-daiRBfAHnm1k4SAgglHwBh7EZcgN4SPAEgmMdeABEm-AMEPgBhRGexjSY2HwAg-vAQAxEnHwAxHAoSkAPxAtC9FxyK4I1AKgMQ3jwSAggoHgAEPQBh9t5A8_kRPQAgvvuYAREpHwARHhcCkAEhlLRkGAhPjFkBMMCe6iAAGSogAGFpZIFpINZ5ATDix-3YBBErIAAEXwBhtIzr7boa2AFxsvNNEgIILB8ABF8AYYY1tLkswBkBMOKug18AES0gAAQ_AGHSNJus7fwZAXnqgikSAgguHwBh8NvF-JqEtgEgoIu0AhEvHwACXgCBCCGBc64oXDJLBIHmufQGEgIIMCAAAl4AgQghOBnAMVET_AAG7AMTBfECgQEh7slu6-q8vABxkMUyEgIIMTsFAj4AgQEhMPynFpOSHwB3gJBEEgIIMh8AgQQh8KgtOBekuwB3holWEgIIMx8AgQghAReekbwQfAB54IAIEgIINB8AYdq5_0ule10Acb7sJhICCDWVBQTaAGFGheYVTpfaAImsttkQEgIINiAAYeB_xxzyESAAMNrOv-8CETcgABEfwwWRECEQW242YSd7zAPFuUcSAgg4GgQICRAKNQJwB8SqrXP5jjUCARQGGTkCBmGCqTQor5WeAHfy_SESAgg6HwCBBCHoEquIE8OXAXfE2kYSAgg7HwCBCCEMRqorWdI-ACCCk30AEDwfAC0iAAIAIQkJ7QXxCADwPy0AAIA_MgYSBBCc-QcyBRIDEKgIBwAhzAYHACGGAgcAIaARBwAhkFIHACHEYDIAIriRHQAhmgMWAJCULDIFEgMQhiQAAAA%2C;wmaxone%3D1.000;wminone%3D1.000;ydngd_mean%3D0.261882;ydngi%3D0.5063;ynhg_mean%3D0.1904;zsset%3DeNptV0ty20YQvUrvsrJLkiuu5DggMCRh4ucBYIlekZJtKbFd3Lkqt6AkgoIpkroCULlQ3usBTMpOSWj09Pz687ob9CIj7by9bJbtJf4W8urk5emZjEqTFxKbUuIyKiQzNk8Tae6autk1m3YuzbZZNpumbhfNWk5fc8/p69fy%2Bx8nJ%2BL5RYjVXhCIF1rxkrQYG7xtWiYQ5fjP8R9iyblnAxl4/gQkikCKAgoNjFeADFMLPko5mw7E9xI%2BvxWgeNI0AimTwtgXeWHDiRHfeu%2BnEnh2AlKUsQTGC0iKMWicShAaCdIRnoQPjgrSc7DW5Dlo%2BA7TZTEVMxwavxATi7E2tWJy38uMmHcww1zI0PMNiMWTj2nqMByNC1DoCwLPDSPMCAzgwjKRkRcbGYVDPDaSURoFBsI0DWRkvYSUJo%2B9aChj6gx/pTIOCwljb2QkzCOuCotc3mQjeVPGmUxCOGwSJqMgjSXyBiaSCAqChgPr2alEKQ6K0mQksWdDDxRGxvB6nAbG8gVzQeCTdDgU6CRpEk0lzfBvrKdBTEtE3yv8sWS%2BZKFflLAxi7ypZDg4S8ME8ymCOUDcMpv69GSWv5K3iiBLT8G2COdak5WDKPTFhjmE1M6m0N3CIgsf5R4Pyz1olRvfGvBjD/GRPIwznJ5nxgSgqcVMYQ0XlFBU8mk8CAEOoGxYkE5B4BhSwKtICy8CLWFEAb%2BUmSCOUwH28NA0UBxzPg5xy3kY4klUECYXIMWYTrg4EyD%2BjnmCZ/ZsgERYUvCIfJgr62TNStn2Uppbld02tWPnmK6w%2BbbZN49OdNPskH5gq2at2fjFDXZ81Vh7x5NveUnzgCys2k%2Bi%2B2/dS7OSzJbHMVcrXs0LeBUFYHFNhfld%2B7n5DhEUqTiP83a4dEHRZ71v5nRAbYDwXk/ZuyP0CrWY4l3H4q4r6LXXGrGRZqWLKzIV2fbaLeRwy31k15DP%2BOaAx7qtvNytxlYM3KErVbPmmRWurpsnZ1eFGSx9wJ57%2Btzt5JD3bES12jrf11SU0x3j3OwGupa%2B1SrXLvq5rV40Y60Tnt1%2B4AEbdfCcCmzgkyUN2mhwNmRgIHxLh3/RIfZvGcXDUOPCCGho9xBDWOGuPUW6joLuim6Dns4I3D9j4dxKMVUzqlut0rWo/eobx3RBx4CwaD/xCKJv234GLNRrW5h9LYqFGUr7yrFzVXXlfK8Ch6v2S3/mToNcuU4iehsFTInNM4GzbN88AS0Oy/QVQXeYVEgo8J0rFADSQQhmPenKazK1Tt479hNMWpLdPw8vBUy3mbJYBMjj%2Bu9u%2BBUR19A%2BOf9r4F1Q1F6Ka0Jdbb7rsuVoascTsUMzX0U/wtEJ9kRjx0K%2B7dlL7L7TwzYqghfWDoZ0zwPCMlP926suPpoYD0w1CJx1auZcAbLs7lQ7iArnvLrLoEM%2Bq2BNJ3eGVopWB59fJvdyQCveXKE1Qq%2BaE/kadLLQeof0vVQNNk70USufzrssXnbugwDJhS2PdDnDThEi034UzZ1Nn/rtX245wzXrvabAg4p0yfrYuF5U/biHCnUvLdnOO4teVHUoPQwB7NvngsWva1yBgODzEdjoCtZE0WtYVREGceYhkTsV5pRd0RdMM7fxStdeK8r6BgBfXGuf6Kz9oIVo%2B4NRUOtgwVfdw%2BSD1vwb4W6tX7VWXIJGs64fcLe%2BFIJ0M5QgACcDKQI5OX15cionZ6RnZ6/k7E9%2B5/lGu2OArx2/wMcRvj/QufktVMhoIOGFTN5LPM3fRvgyyMoIbdaizeclzvQzKZOwQJs1gzhN0Km1j95ru2In09cLhdV317Rql0eO0aLPSqStSq28Zop0Vd01kco1F1c8rrBjd6iplWujD3rtXgvwUemheO9eTxqoG8Va3ybY1RGSS%2BaKtgKubD%2B6qucawE%2BiQ1F2vYGJdimaS7dqSMXKxuGG9ZhWPbbfiJ0OUVfOsO1RFi9cPX%2Bg14jwtVItwlxw33WXVS/QOXwm0BjMdBWbgr%2BBvbnW7q6g7bu0n7uavXb5evgOcI1QG%2B7BLf8j7Fer27vKq1l51/dAN3xgV9J62WnlqqVGk78wDoVyr33isRd0FRfRXR61IYXNSvSj5t4BgTnXta%2Bjoq5W37sq476Tbg7l4qoP3k/lHpXM2VO7zdddI9zpd077VdnnrRhlY6eAa79BlRsXiidNwJVEU4uP4UnIX1exF4XJRJr1v/8wHtKdsDoCZ/uNv2HM5D%2Bak0fD;relevgeo%3D225;geochanged%3D1;;udbts%3D1459797057;downerprotobundle%3DCAwVQbwCVw%2C%2C&reqid=1461253060957657-600715567702129748010289-myt1-1909&snip=exps%3Dmarker_ratings_info%2Cmarker_movie_rating%3D0;report%3Dwww;reps%3Dall_on;snip_width%3D550;uil%3Dru;dqsigml%3D4&snip=t%3D0&text=%28autocad%3A%3A209750+^+autodesk%3A%3A288721+^+%28%28autodesk%3A%3A288721+%26/%281+1%29+inventor%3A%3A1697918%29%29+^+%28%28auto%3A%3A28861+%26/%281+1%29+cad%3A%3A171629%29%29+^+%D0%B0%D0%B2%D1%82%D0%BE%D0%BA%D0%B0%D0%B4%3A%3A1405467+^+autoca%3A%3A420234780%29+%26%26/%28-3+5%29+%28%28%D1%81%D0%BA%D0%B0%D1%87%D0%B0%D1%82%D1%8C%3A%3A691+^+download%3A%3A13863+^+pdf%3A%3A10201+^+torrent%3A%3A35211+^+%28%28%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BD%D0%BE%3A%3A456+%26/%281+1%29+%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%B8%D1%82%D1%8C%3A%3A13856%29%29+^+%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B6%D0%B0%D1%82%D1%8C%3A%3A13856+^+%D0%B7%D0%B0%D0%BA%D0%B0%D1%87%D0%B8%D0%B2%D0%B0%D1%82%D1%8C%3A%3A112512+^+%D1%81%D0%BA%D0%B0%D1%87%D0%B8%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%3A%3A14585+^+%D1%81%D0%BA%D0%B0%D1%87%D0%B8%D0%B2%D0%B0%D1%82%D1%8C%D1%81%D1%8F%3A%3A423410+^+%D1%81%D0%BA%D0%B0%D1%87%D0%BA%D0%B0%3A%3A152424+^+skachat%3A%3A203208%29+%26/%28-64+64%29+%28%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BD%D0%BE%3A%3A456+^+besplatno%3A%3A455045+^+download%3A%3A13863+^+free%3A%3A12386+^+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%3A%3A886571+^+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BD%D0%B8%D0%B9%3A%3A14490854+^+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BD%D0%B8%D0%BA%3A%3A105058695+^+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BD%D0%BD%D1%8B%D0%B9%3A%3A280156520+^+%D0%B4%D0%B0%D1%80%D0%BE%D0%BC%3A%3A148126+^+%D1%81%D0%B2%D0%BE%D0%B1%D0%BE%D0%B4%D0%BD%D0%BE%3A%3A88910+^+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D0%BD%D0%BE%3A%3A4669275+^+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BE%3A%3A10775250+^+%D1%85%D0%B0%D0%BB%D1%8F%D0%B2%D0%BD%D1%8B%D0%B9%3A%3A644531%29%29+^+%D1%81%D0%BA%D0%B0%D1%87%D0%B0%D1%82%D1%8C%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BD%D0%BE%3A%3A17882331+%26/%28-64+64%29+%D0%BD%D0%B0%3A%3A131+%26/%28-64+64%29+%28%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE%D0%BC%3A%3A1942+^+russia%3A%3A37324+^+russian%3A%3A31805+^+%D1%80%D0%BE%D1%81%D1%81%D0%B8%D0%B9%D1%81%D0%BA%D0%B8%D0%B9%3A%3A3887+^+rus%3A%3A16095+^+%D0%B2%D0%B5%D0%BB%D0%B8%D0%BA%D0%BE%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9%3A%3A1918880+^+%D1%80%D1%83%D1%81%D0%B8%D1%81%D1%82%D0%B8%D0%BA%D0%B0%3A%3A27111921+^+%D1%80%D1%83%D1%81%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D1%8F%3A%3A638169+^+!!%D1%80%D1%83%D1%81%D0%BA%3A%3A1076145+^+%D1%80%D1%83%D1%81%D1%81%3A%3A336053+^+%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE%D1%8F%D0%B7%D1%8B%D1%87%D0%BD%D1%8B%D0%B9%3A%3A139984+^+russkom%3A%3A7245427%29+%26%26/%28-3+5%29+%28%D1%82%D0%BE%D1%80%D1%80%D0%B5%D0%BD%D1%82%3A%3A6178+^+torrent%3A%3A35211%29+%26%26/%28-3+5%29+32%3A%3A6178+%26/%28-1+1%29+%28bit%3A%3A27572+^+%D0%B1%D0%B8%D1%82%D0%BD%D1%8B%D0%B9%3A%3A414024+^+%D1%83%D0%BA%D1%83%D1%81%D0%B8%D1%82%D1%8C%3A%3A558080+^+%28%28background%3A%3A96185+%26/%281+1%29+intelligent%3A%3A705091+%26/%281+1%29+transfer%3A%3A180746+%26/%281+1%29+service%3A%3A17789%29%29+^+%D0%B1%D0%B8%D1%82%3A%3A65584%29+%26%26/%28-3+5%29+%D0%B4%D0%BB%D1%8F%3A%3A205+%26/%28-64+64%29+%28%28windows%3A%3A2869+^+%D0%B2%D0%B8%D0%BD%D0%B4%D0%BE%D0%B2%D1%81%3A%3A318239+^+%D0%B2%D0%B8%D0%BD%D0%B4%D0%BE%D1%83%D0%B7%3A%3A17509782+^+%D0%B2%D0%B8%D0%BD%D0%B4%D0%BE%D1%83%D1%81%3A%3A2618285%29+%26%26/%28-3+5%29+%28xp%3A%3A13143+^+windows%3A%3A2869+^+%D1%85%D1%80%3A%3A278393+^+%28%28xtreme%3A%3A579234+%26/%281+1%29+performance%3A%3A113530%29%29+^+%D1%85%D0%BF%3A%3A582849%29%29+^+windowsxp%3A%3A585285+softness%3A6&tld=ru&uil=ru&user_request=autocad+%D1%81%D0%BA%D0%B0%D1%87%D0%B0%D1%82%D1%8C+%D0%B1%D0%B5%D1%81%D0%BF%D0%BB%D0%B0%D1%82%D0%BD%D0%BE+%D0%BD%D0%B0+%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE%D0%BC+%D1%82%D0%BE%D1%80%D1%80%D0%B5%D0%BD%D1%82+32+bit+%D0%B4%D0%BB%D1%8F+windows+xp \ No newline at end of file
diff --git a/library/cpp/streams/lz/ut/ya.make b/library/cpp/streams/lz/ut/ya.make
new file mode 100644
index 0000000000..18288c8ac9
--- /dev/null
+++ b/library/cpp/streams/lz/ut/ya.make
@@ -0,0 +1,18 @@
+UNITTEST_FOR(library/cpp/streams/lz)
+
+OWNER(
+ pg
+ g:util
+)
+
+RESOURCE(
+ random.data /random.data
+ request.data /request.data
+ yq_609.data /yq_609.data
+)
+
+SRCS(
+ lz_ut.cpp
+)
+
+END()
diff --git a/library/cpp/streams/lz/ut/yq_609.data b/library/cpp/streams/lz/ut/yq_609.data
new file mode 100644
index 0000000000..9694b0c97f
--- /dev/null
+++ b/library/cpp/streams/lz/ut/yq_609.data
Binary files differ
diff --git a/library/cpp/streams/lz/ya.make b/library/cpp/streams/lz/ya.make
new file mode 100644
index 0000000000..e5eea0b096
--- /dev/null
+++ b/library/cpp/streams/lz/ya.make
@@ -0,0 +1,20 @@
+LIBRARY()
+
+OWNER(
+ pg
+ g:util
+)
+
+PEERDIR(
+ contrib/libs/fastlz
+ contrib/libs/lz4
+ contrib/libs/minilzo
+ contrib/libs/quicklz
+ contrib/libs/snappy
+)
+
+SRCS(
+ lz.cpp
+)
+
+END()
diff --git a/library/cpp/streams/lzma/lzma.cpp b/library/cpp/streams/lzma/lzma.cpp
new file mode 100644
index 0000000000..f1942fa546
--- /dev/null
+++ b/library/cpp/streams/lzma/lzma.cpp
@@ -0,0 +1,520 @@
+#include "lzma.h"
+
+#include <util/stream/mem.h>
+#include <util/system/context.h>
+#include <util/generic/cast.h>
+#include <util/memory/addstorage.h>
+#include <util/generic/ptr.h>
+#include <util/generic/intrlist.h>
+#include <util/generic/scope.h>
+
+extern "C" {
+#include <contrib/libs/lzmasdk/LzmaEnc.h>
+#include <contrib/libs/lzmasdk/LzmaDec.h>
+}
+
+namespace {
+ class TMemoryGc {
+ class TAllocation: public TIntrusiveListItem<TAllocation>, public TAdditionalStorage<TAllocation> {
+ };
+
+ public:
+ inline void* Allocate(size_t len) {
+ if (len > 1024 * 1024 * 1024) {
+ return nullptr;
+ }
+
+ TAllocation* ret = new (len) TAllocation;
+
+ Allocs_.PushBack(ret);
+
+ return ret->AdditionalData();
+ }
+
+ inline void Deallocate(void* ptr) noexcept {
+ if (ptr) {
+ delete TAllocation::ObjectFromData(ptr);
+ }
+ }
+
+ private:
+ TIntrusiveListWithAutoDelete<TAllocation, TDelete> Allocs_;
+ };
+
+ template <class T>
+ class TInverseFilter {
+ class TTrampoLine: public ITrampoLine {
+ public:
+ inline TTrampoLine(TInverseFilter* parent)
+ : Parent_(parent)
+ {
+ }
+
+ void DoRun() override {
+ Parent_->RunFilter();
+ }
+
+ private:
+ TInverseFilter* Parent_;
+ };
+
+ class TInput: public IInputStream {
+ public:
+ inline TInput(TInverseFilter* parent)
+ : Parent_(parent)
+ {
+ }
+
+ ~TInput() override {
+ }
+
+ size_t DoRead(void* ptr, size_t len) override {
+ return Parent_->ReadImpl(ptr, len);
+ }
+
+ private:
+ TInverseFilter* Parent_;
+ };
+
+ class TOutput: public IOutputStream {
+ public:
+ inline TOutput(TInverseFilter* parent)
+ : Parent_(parent)
+ {
+ }
+
+ ~TOutput() override {
+ }
+
+ void DoWrite(const void* ptr, size_t len) override {
+ Parent_->WriteImpl(ptr, len);
+ }
+
+ private:
+ TInverseFilter* Parent_;
+ };
+
+ public:
+ inline TInverseFilter(IOutputStream* slave, T* filter)
+ : Slave_(slave)
+ , Filter_(filter)
+ , TrampoLine_(this)
+ , FilterCtx_(FilterClosure())
+ , Finished_(false)
+ , In_(nullptr, 0)
+ {
+ }
+
+ virtual ~TInverseFilter() {
+ if (!UncaughtException()) {
+ try {
+ Finish();
+ } catch (...) {
+ }
+ } else {
+ //rely on gc
+ }
+ }
+
+ inline void Write(const void* ptr, size_t len) {
+ In_.Reset(ptr, len);
+
+ Y_DEFER {
+ In_.Reset(0, 0);
+ };
+
+ while (In_.Avail()) {
+ SwitchTo();
+ }
+ }
+
+ inline void Finish() {
+ if (!Finished_) {
+ Finished_ = true;
+ SwitchTo();
+ }
+ }
+
+ private:
+ inline void RunFilter() {
+ try {
+ TInput in(this);
+ TOutput out(this);
+
+ (*Filter_)(&in, &out);
+ } catch (...) {
+ Err_ = std::current_exception();
+ }
+
+ SwitchFrom();
+ }
+
+ inline TContClosure FilterClosure() {
+ return {&TrampoLine_, TArrayRef(Stack_, sizeof(Stack_))};
+ }
+
+ inline size_t ReadImpl(void* ptr, size_t len) {
+ while (!Finished_) {
+ const size_t ret = In_.Read(ptr, len);
+
+ if (ret) {
+ return ret;
+ }
+
+ SwitchFrom();
+ }
+
+ return 0;
+ }
+
+ inline void WriteImpl(const void* ptr, size_t len) {
+ Y_ASSERT(!Out_.Avail());
+
+ Out_.Reset(ptr, len);
+
+ while (Out_.Avail()) {
+ SwitchFrom();
+ }
+ }
+
+ inline bool FlushImpl() {
+ if (Out_.Avail()) {
+ TransferData(&Out_, Slave_);
+ Out_.Reset(nullptr, 0);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ inline void SwitchTo() {
+ do {
+ CurrentCtx_.SwitchTo(&FilterCtx_);
+
+ if (Err_) {
+ Finished_ = true;
+
+ std::rethrow_exception(Err_);
+ }
+ } while (FlushImpl());
+ }
+
+ inline void SwitchFrom() {
+ FilterCtx_.SwitchTo(&CurrentCtx_);
+ }
+
+ private:
+ IOutputStream* Slave_;
+ T* Filter_;
+ TTrampoLine TrampoLine_;
+ char Stack_[16 * 1024];
+ TContMachineContext FilterCtx_;
+ TContMachineContext CurrentCtx_;
+ bool Finished_;
+ TMemoryInput In_;
+ TMemoryInput Out_;
+ std::exception_ptr Err_;
+ };
+
+ class TLzma {
+ public:
+ class TLzmaInput: public ISeqInStream {
+ public:
+ inline TLzmaInput(IInputStream* slave)
+ : Slave_(slave)
+ {
+ Read = ReadFunc;
+ }
+
+ private:
+ static inline SRes ReadFunc(const ISeqInStream* p, void* ptr, size_t* len) {
+ *len = const_cast<TLzmaInput*>(static_cast<const TLzmaInput*>(p))->Slave_->Read(ptr, *len);
+
+ return SZ_OK;
+ }
+
+ private:
+ IInputStream* Slave_;
+ };
+
+ class TLzmaOutput: public ISeqOutStream {
+ public:
+ inline TLzmaOutput(IOutputStream* slave)
+ : Slave_(slave)
+ {
+ Write = WriteFunc;
+ }
+
+ private:
+ static inline size_t WriteFunc(const ISeqOutStream* p, const void* ptr, size_t len) {
+ const_cast<TLzmaOutput*>(static_cast<const TLzmaOutput*>(p))->Slave_->Write(ptr, len);
+
+ return len;
+ }
+
+ private:
+ IOutputStream* Slave_;
+ };
+
+ class TAlloc: public ISzAlloc {
+ public:
+ inline TAlloc() {
+ Alloc = AllocFunc;
+ Free = FreeFunc;
+ }
+
+ private:
+ static void* AllocFunc(const ISzAlloc* t, size_t len) {
+ return static_cast<TAlloc*>(((ISzAlloc*)t))->Gc_.Allocate(len);
+ }
+
+ static void FreeFunc(const ISzAlloc* t, void* p) {
+ static_cast<TAlloc*>(((ISzAlloc*)t))->Gc_.Deallocate(p);
+ }
+
+ private:
+ TMemoryGc Gc_;
+ };
+
+ inline ISzAlloc* Alloc() noexcept {
+ return &Alloc_;
+ }
+
+ static inline void Check(SRes r) {
+ if (r != SZ_OK) {
+ ythrow yexception() << "lzma error(" << r << ")";
+ }
+ }
+
+ private:
+ TAlloc Alloc_;
+ };
+
+ class TLzmaCompressBase: public TLzma {
+ public:
+ inline TLzmaCompressBase(size_t level)
+ : H_(LzmaEnc_Create(Alloc()))
+ {
+ if (!H_) {
+ ythrow yexception() << "can not init lzma engine";
+ }
+
+ LzmaEncProps_Init(&Props_);
+
+ Props_.level = level;
+ Props_.dictSize = 0;
+ Props_.lc = -1;
+ Props_.lp = -1;
+ Props_.pb = -1;
+ Props_.fb = -1;
+ Props_.numThreads = -1;
+ Props_.writeEndMark = 1;
+
+ Check(LzmaEnc_SetProps(H_, &Props_));
+ size_t bufLen = sizeof(PropsBuf_);
+ Zero(PropsBuf_);
+ Check(LzmaEnc_WriteProperties(H_, PropsBuf_, &bufLen));
+ }
+
+ inline ~TLzmaCompressBase() {
+ LzmaEnc_Destroy(H_, Alloc(), Alloc());
+ }
+
+ inline void operator()(IInputStream* in, IOutputStream* out) {
+ TLzmaInput input(in);
+ TLzmaOutput output(out);
+
+ out->Write(PropsBuf_, sizeof(PropsBuf_));
+
+ Check(LzmaEnc_Encode(H_, &output, &input, nullptr, Alloc(), Alloc()));
+ }
+
+ private:
+ CLzmaEncHandle H_;
+ CLzmaEncProps Props_;
+ Byte PropsBuf_[LZMA_PROPS_SIZE];
+ };
+}
+
+class TLzmaCompress::TImpl: public TLzmaCompressBase, public TInverseFilter<TLzmaCompressBase> {
+public:
+ inline TImpl(IOutputStream* slave, size_t level)
+ : TLzmaCompressBase(level)
+ , TInverseFilter<TLzmaCompressBase>(slave, this)
+ {
+ }
+};
+
+class TLzmaDecompress::TImpl: public TLzma {
+public:
+ inline TImpl()
+ : InBegin_(nullptr)
+ , InEnd_(nullptr)
+ {
+ LzmaDec_Construct(&H_);
+ }
+ inline virtual ~TImpl() {
+ LzmaDec_Free(&H_, Alloc());
+ }
+
+ inline size_t Read(void* ptr, size_t len) {
+ Byte* pos = (Byte*)ptr;
+ Byte* end = pos + len;
+
+ retry:
+ size_t availLen = InEnd_ - InBegin_;
+ size_t bufLen = end - pos;
+ ELzmaStatus status;
+
+ Check(LzmaDec_DecodeToBuf(&H_, pos, &bufLen, (Byte*)InBegin_, &availLen, LZMA_FINISH_ANY, &status));
+
+ InBegin_ += availLen;
+ pos += bufLen;
+
+ if (status == LZMA_STATUS_NEEDS_MORE_INPUT) {
+ Y_ASSERT(InEnd_ == InBegin_);
+ if (!Fill()) {
+ ythrow yexception() << "incomplete lzma stream";
+ }
+
+ goto retry;
+ }
+
+ return pos - (Byte*)ptr;
+ }
+
+private:
+ virtual bool Fill() = 0;
+
+protected:
+ CLzmaDec H_;
+ char* InBegin_;
+ char* InEnd_;
+};
+
+class TLzmaDecompress::TImplStream: public TImpl {
+public:
+ inline TImplStream(IInputStream* slave)
+ : Slave_(slave)
+ {
+ Byte buf[LZMA_PROPS_SIZE];
+
+ if (Slave_->Load(buf, sizeof(buf)) != sizeof(buf))
+ ythrow yexception() << "can't read lzma header";
+
+ Check(LzmaDec_Allocate(&H_, buf, sizeof(buf), Alloc()));
+ LzmaDec_Init(&H_);
+ }
+
+private:
+ bool Fill() override {
+ size_t size = Slave_->Read(In_, sizeof(In_));
+ InBegin_ = In_;
+ InEnd_ = In_ + size;
+
+ return size;
+ }
+
+private:
+ IInputStream* Slave_;
+ char In_[4096];
+};
+
+class TLzmaDecompress::TImplZeroCopy: public TLzmaDecompress::TImpl {
+public:
+ inline TImplZeroCopy(IZeroCopyInput* in)
+ : Input_(in)
+ {
+ if (!Fill())
+ ythrow yexception() << "can't read lzma header";
+
+ char buf[LZMA_PROPS_SIZE];
+ char* header;
+ if (InEnd_ - InBegin_ >= LZMA_PROPS_SIZE) {
+ header = InBegin_;
+ InBegin_ += LZMA_PROPS_SIZE;
+ } else {
+ //bad luck, first part is less than header
+ //try to copy header part by part to the local buffer
+ const char* end = buf + sizeof(buf);
+ char* pos = buf;
+ while (1) {
+ size_t left = end - pos;
+ size_t avail = InEnd_ - InBegin_;
+ if (left < avail) {
+ memcpy(pos, InBegin_, left);
+ InBegin_ += left;
+ break;
+ } else {
+ memcpy(pos, InBegin_, avail);
+ pos += avail;
+ if (!Fill()) {
+ ythrow yexception() << "can't read lzma header";
+ }
+ }
+ }
+ header = buf;
+ }
+
+ Check(LzmaDec_Allocate(&H_, (Byte*)header, LZMA_PROPS_SIZE, Alloc()));
+
+ LzmaDec_Init(&H_);
+ }
+
+private:
+ bool Fill() override {
+ size_t size = Input_->Next(&InBegin_);
+
+ if (size) {
+ InEnd_ = InBegin_ + size;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ IZeroCopyInput* Input_;
+};
+
+TLzmaCompress::TLzmaCompress(IOutputStream* slave, size_t level)
+ : Impl_(new TImpl(slave, level))
+{
+}
+
+TLzmaCompress::~TLzmaCompress() {
+}
+
+void TLzmaCompress::DoWrite(const void* buf, size_t len) {
+ if (!Impl_) {
+ ythrow yexception() << "can not write to finished lzma stream";
+ }
+
+ Impl_->Write(buf, len);
+}
+
+void TLzmaCompress::DoFinish() {
+ THolder<TImpl> impl(Impl_.Release());
+
+ if (impl) {
+ impl->Finish();
+ }
+}
+
+TLzmaDecompress::TLzmaDecompress(IInputStream* slave)
+ : Impl_(new TImplStream(slave))
+{
+}
+
+TLzmaDecompress::TLzmaDecompress(IZeroCopyInput* input)
+ : Impl_(new TImplZeroCopy(input))
+{
+}
+
+TLzmaDecompress::~TLzmaDecompress() {
+}
+
+size_t TLzmaDecompress::DoRead(void* buf, size_t len) {
+ return Impl_->Read(buf, len);
+}
diff --git a/library/cpp/streams/lzma/lzma.h b/library/cpp/streams/lzma/lzma.h
new file mode 100644
index 0000000000..ca1e06e9ef
--- /dev/null
+++ b/library/cpp/streams/lzma/lzma.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include <util/stream/input.h>
+#include <util/stream/output.h>
+#include <util/stream/zerocopy.h>
+
+#include <util/generic/ptr.h>
+
+class TLzmaCompress: public IOutputStream {
+public:
+ TLzmaCompress(IOutputStream* slave, size_t level = 7);
+ ~TLzmaCompress() override;
+
+private:
+ void DoWrite(const void* buf, size_t len) override;
+ void DoFinish() override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+class TLzmaDecompress: public IInputStream {
+public:
+ TLzmaDecompress(IInputStream* slave);
+ TLzmaDecompress(IZeroCopyInput* input);
+ ~TLzmaDecompress() override;
+
+private:
+ size_t DoRead(void* buf, size_t len) override;
+
+private:
+ class TImpl;
+ class TImplStream;
+ class TImplZeroCopy;
+ THolder<TImpl> Impl_;
+};
diff --git a/library/cpp/streams/lzma/lzma_ut.cpp b/library/cpp/streams/lzma/lzma_ut.cpp
new file mode 100644
index 0000000000..847e98d1ca
--- /dev/null
+++ b/library/cpp/streams/lzma/lzma_ut.cpp
@@ -0,0 +1,127 @@
+#include "lzma.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/mem.h>
+#include <util/random/fast.h>
+#include <util/random/random.h>
+
+class TStrokaByOneByte: public IZeroCopyInput {
+public:
+ TStrokaByOneByte(const TString& s)
+ : Data(s)
+ , Pos(s.data())
+ {
+ }
+
+private:
+ size_t DoNext(const void** ptr, size_t len) override {
+ if (Pos < Data.end()) {
+ len = Min(len, static_cast<size_t>(1));
+ *ptr = Pos;
+ Pos += len;
+ return len;
+ } else {
+ return 0;
+ }
+ }
+
+ TString Data;
+ const char* Pos;
+};
+
+class TLzmaTest: public TTestBase {
+ UNIT_TEST_SUITE(TLzmaTest);
+ UNIT_TEST(Test1)
+ UNIT_TEST(Test2)
+ UNIT_TEST_SUITE_END();
+
+private:
+ inline TString GenData() {
+ TString data;
+ TReallyFastRng32 rnd(RandomNumber<ui64>());
+
+ for (size_t i = 0; i < 50000; ++i) {
+ const char ch = rnd.Uniform(256);
+ const size_t len = 1 + rnd.Uniform(10);
+
+ data += TString(len, ch);
+ }
+
+ return data;
+ }
+
+ inline void Test2() {
+ class TExcOutput: public IOutputStream {
+ public:
+ ~TExcOutput() override {
+ }
+
+ void DoWrite(const void*, size_t) override {
+ throw 12345;
+ }
+ };
+
+ TString data(GenData());
+ TMemoryInput mi(data.data(), data.size());
+ TExcOutput out;
+
+ try {
+ TLzmaCompress c(&out);
+
+ TransferData(&mi, &c);
+ } catch (int i) {
+ UNIT_ASSERT_EQUAL(i, 12345);
+ }
+ }
+
+ inline void Test1() {
+ TString data(GenData());
+ TString data1;
+ TString res;
+
+ {
+ TMemoryInput mi(data.data(), data.size());
+ TStringOutput so(res);
+ TLzmaCompress c(&so);
+
+ TransferData(&mi, &c);
+
+ c.Finish();
+ }
+
+ {
+ TMemoryInput mi(res.data(), res.size());
+ TStringOutput so(data1);
+ TLzmaDecompress d((IInputStream*)&mi);
+
+ TransferData(&d, &so);
+ }
+
+ UNIT_ASSERT_EQUAL(data, data1);
+
+ data1.clear();
+ {
+ TMemoryInput mi(res.data(), res.size());
+ TStringOutput so(data1);
+ TLzmaDecompress d(&mi);
+
+ TransferData(&d, &so);
+ }
+
+ UNIT_ASSERT_EQUAL(data, data1);
+
+ data1.clear();
+ {
+ TStrokaByOneByte mi(res);
+ TStringOutput so(data1);
+ TLzmaDecompress d(&mi);
+
+ TransferData(&d, &so);
+ }
+
+ UNIT_ASSERT_EQUAL(data, data1);
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TLzmaTest);
diff --git a/library/cpp/streams/lzma/ut/ya.make b/library/cpp/streams/lzma/ut/ya.make
new file mode 100644
index 0000000000..01624f0259
--- /dev/null
+++ b/library/cpp/streams/lzma/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/streams/lzma)
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ lzma_ut.cpp
+)
+
+END()
diff --git a/library/cpp/streams/lzma/ya.make b/library/cpp/streams/lzma/ya.make
new file mode 100644
index 0000000000..38c05145c4
--- /dev/null
+++ b/library/cpp/streams/lzma/ya.make
@@ -0,0 +1,16 @@
+LIBRARY()
+
+OWNER(
+ pg
+ g:util
+)
+
+PEERDIR(
+ contrib/libs/lzmasdk
+)
+
+SRCS(
+ lzma.cpp
+)
+
+END()
diff --git a/library/cpp/streams/ya.make b/library/cpp/streams/ya.make
new file mode 100644
index 0000000000..7426a874ee
--- /dev/null
+++ b/library/cpp/streams/ya.make
@@ -0,0 +1,26 @@
+RECURSE(
+ brotli
+ brotli/ut
+ base64
+ brotli
+ bzip2
+ bzip2/ut
+ factory
+ factory/ut
+ fields_io
+ fields_io/ut
+ growing_file_input
+ growing_file_input/ut
+ lz
+ lz/ut
+ lzma
+ lzma/ut
+ lzop
+ lzop/ut
+ special
+ special/ut
+ xz
+ zc_memory_input
+ zstd
+ zstd/ut
+)
diff --git a/library/cpp/streams/zc_memory_input/ya.make b/library/cpp/streams/zc_memory_input/ya.make
new file mode 100644
index 0000000000..bc94d6f1ed
--- /dev/null
+++ b/library/cpp/streams/zc_memory_input/ya.make
@@ -0,0 +1,12 @@
+LIBRARY()
+
+OWNER(
+ pg
+ g:util
+)
+
+SRCS(
+ zc_memory_input.cpp
+)
+
+END()
diff --git a/library/cpp/streams/zc_memory_input/zc_memory_input.cpp b/library/cpp/streams/zc_memory_input/zc_memory_input.cpp
new file mode 100644
index 0000000000..682099a239
--- /dev/null
+++ b/library/cpp/streams/zc_memory_input/zc_memory_input.cpp
@@ -0,0 +1 @@
+#include "zc_memory_input.h"
diff --git a/library/cpp/streams/zc_memory_input/zc_memory_input.h b/library/cpp/streams/zc_memory_input/zc_memory_input.h
new file mode 100644
index 0000000000..c939d8e426
--- /dev/null
+++ b/library/cpp/streams/zc_memory_input/zc_memory_input.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <util/stream/mem.h>
+#include <util/system/defaults.h>
+#include <util/generic/yexception.h>
+
+/// Zero-copy memory input with fixed read
+class TZCMemoryInput: public TMemoryInput {
+public:
+ TZCMemoryInput() {
+ }
+
+ TZCMemoryInput(const char* dataPtr, size_t size)
+ : TMemoryInput(dataPtr, size)
+ {
+ }
+
+ TZCMemoryInput(TMemoryInput& rhs)
+ : TMemoryInput(rhs.Buf(), rhs.Avail())
+ {
+ }
+
+ /// if there's 'size' data read it, otherwise just return false
+ Y_FORCE_INLINE bool ReadFixed(const char*& buf, size_t size) {
+ if (Avail() >= size) {
+ buf = Buf();
+ Reset(Buf() + size, Avail() - size);
+ return true;
+ }
+ return false;
+ }
+
+ template <class T>
+ Y_FORCE_INLINE T LoadPOD() {
+ const char* buf = nullptr;
+ if (!ReadFixed(buf, sizeof(T)))
+ ythrow yexception() << "TZCMemoryInput::LoadPOD failed: not enough data ("
+ << Avail() << " of " << sizeof(T) << " bytes)";
+ T res;
+ memcpy(&res, buf, sizeof(T));
+ return res;
+ }
+
+ template <class T>
+ Y_FORCE_INLINE void ReadPOD(T& x) {
+ x = LoadPOD<T>();
+ }
+};
diff --git a/library/cpp/streams/zstd/ut/ya.make b/library/cpp/streams/zstd/ut/ya.make
new file mode 100644
index 0000000000..1b98f0ad5e
--- /dev/null
+++ b/library/cpp/streams/zstd/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/streams/zstd)
+
+OWNER(
+ bulatman
+ g:util
+)
+
+SRCS(
+ zstd_ut.cpp
+)
+
+END()
diff --git a/library/cpp/streams/zstd/ya.make b/library/cpp/streams/zstd/ya.make
new file mode 100644
index 0000000000..c284deeeff
--- /dev/null
+++ b/library/cpp/streams/zstd/ya.make
@@ -0,0 +1,16 @@
+LIBRARY()
+
+OWNER(
+ bulatman
+ g:util
+)
+
+PEERDIR(
+ contrib/libs/zstd
+)
+
+SRCS(
+ zstd.cpp
+)
+
+END()
diff --git a/library/cpp/streams/zstd/zstd.cpp b/library/cpp/streams/zstd/zstd.cpp
new file mode 100644
index 0000000000..29816f6d4c
--- /dev/null
+++ b/library/cpp/streams/zstd/zstd.cpp
@@ -0,0 +1,173 @@
+#include "zstd.h"
+
+#include <util/generic/buffer.h>
+#include <util/generic/yexception.h>
+
+#define ZSTD_STATIC_LINKING_ONLY
+#include <contrib/libs/zstd/include/zstd.h>
+
+namespace {
+ inline void CheckError(const char* op, size_t code) {
+ if (::ZSTD_isError(code)) {
+ ythrow yexception() << op << TStringBuf(" zstd error: ") << ::ZSTD_getErrorName(code);
+ }
+ }
+
+ struct DestroyZCStream {
+ static void Destroy(::ZSTD_CStream* p) noexcept {
+ ::ZSTD_freeCStream(p);
+ }
+ };
+
+ struct DestroyZDStream {
+ static void Destroy(::ZSTD_DStream* p) noexcept {
+ ::ZSTD_freeDStream(p);
+ }
+ };
+}
+
+class TZstdCompress::TImpl {
+public:
+ TImpl(IOutputStream* slave, int quality)
+ : Slave_(slave)
+ , ZCtx_(::ZSTD_createCStream())
+ , Buffer_(::ZSTD_CStreamOutSize()) // do reserve
+ {
+ Y_ENSURE(nullptr != ZCtx_.Get(), "Failed to allocate ZSTD_CStream");
+ Y_ENSURE(0 != Buffer_.Capacity(), "ZSTD_CStreamOutSize was too small");
+ CheckError("init", ZSTD_initCStream(ZCtx_.Get(), quality));
+ }
+
+ void Write(const void* buffer, size_t size) {
+ ::ZSTD_inBuffer zIn{buffer, size, 0};
+ auto zOut = OutBuffer();
+
+ while (0 != zIn.size) {
+ CheckError("compress", ::ZSTD_compressStream(ZCtx_.Get(), &zOut, &zIn));
+ DoWrite(zOut);
+ // forget about the data we already compressed
+ zIn.src = static_cast<const unsigned char*>(zIn.src) + zIn.pos;
+ zIn.size -= zIn.pos;
+ zIn.pos = 0;
+ }
+ }
+
+ void Flush() {
+ auto zOut = OutBuffer();
+ CheckError("flush", ::ZSTD_flushStream(ZCtx_.Get(), &zOut));
+ DoWrite(zOut);
+ }
+
+ void Finish() {
+ auto zOut = OutBuffer();
+ size_t returnCode;
+ do {
+ returnCode = ::ZSTD_endStream(ZCtx_.Get(), &zOut);
+ CheckError("finish", returnCode);
+ DoWrite(zOut);
+ } while (0 != returnCode); // zero means there is no more bytes to flush
+ }
+
+private:
+ ::ZSTD_outBuffer OutBuffer() {
+ return {Buffer_.Data(), Buffer_.Capacity(), 0};
+ }
+
+ void DoWrite(::ZSTD_outBuffer& buffer) {
+ Slave_->Write(buffer.dst, buffer.pos);
+ buffer.pos = 0;
+ }
+private:
+ IOutputStream* Slave_;
+ THolder<::ZSTD_CStream, DestroyZCStream> ZCtx_;
+ TBuffer Buffer_;
+};
+
+TZstdCompress::TZstdCompress(IOutputStream* slave, int quality)
+ : Impl_(new TImpl(slave, quality)) {
+}
+
+TZstdCompress::~TZstdCompress() {
+ try {
+ Finish();
+ } catch (...) {
+ }
+}
+
+void TZstdCompress::DoWrite(const void* buffer, size_t size) {
+ Y_ENSURE(Impl_, "Cannot use stream after finish.");
+ Impl_->Write(buffer, size);
+}
+
+void TZstdCompress::DoFlush() {
+ Y_ENSURE(Impl_, "Cannot use stream after finish.");
+ Impl_->Flush();
+}
+
+void TZstdCompress::DoFinish() {
+ // Finish should be idempotent
+ if (Impl_) {
+ auto impl = std::move(Impl_);
+ impl->Finish();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TZstdDecompress::TImpl {
+public:
+ TImpl(IInputStream* slave, size_t bufferSize)
+ : Slave_(slave)
+ , ZCtx_(::ZSTD_createDStream())
+ , Buffer_(bufferSize) // do reserve
+ , Offset_(0)
+ {
+ Y_ENSURE(nullptr != ZCtx_.Get(), "Failed to allocate ZSTD_DStream");
+ Y_ENSURE(0 != Buffer_.Capacity(), "Buffer size was too small");
+ }
+
+ size_t Read(void* buffer, size_t size) {
+ Y_ASSERT(size > 0);
+
+ ::ZSTD_outBuffer zOut{buffer, size, 0};
+ ::ZSTD_inBuffer zIn{Buffer_.Data(), Buffer_.Size(), Offset_};
+
+ size_t returnCode = 0;
+ while (zOut.pos != zOut.size) {
+ if (zIn.pos == zIn.size) {
+ zIn.size = Slave_->Read(Buffer_.Data(), Buffer_.Capacity());
+ Buffer_.Resize(zIn.size);
+ zIn.pos = Offset_ = 0;
+ if (0 == zIn.size) {
+ // end of stream, need to check that there is no uncompleted blocks
+ Y_ENSURE(0 == returnCode, "Incomplete block");
+ break;
+ }
+ }
+ returnCode = ::ZSTD_decompressStream(ZCtx_.Get(), &zOut, &zIn);
+ CheckError("decompress", returnCode);
+ if (0 == returnCode) {
+ // The frame is over, prepare to (maybe) start a new frame
+ ZSTD_initDStream(ZCtx_.Get());
+ }
+ }
+ Offset_ = zIn.pos;
+ return zOut.pos;
+ }
+
+private:
+ IInputStream* Slave_;
+ THolder<::ZSTD_DStream, DestroyZDStream> ZCtx_;
+ TBuffer Buffer_;
+ size_t Offset_;
+};
+
+TZstdDecompress::TZstdDecompress(IInputStream* slave, size_t bufferSize)
+ : Impl_(new TImpl(slave, bufferSize)) {
+}
+
+TZstdDecompress::~TZstdDecompress() = default;
+
+size_t TZstdDecompress::DoRead(void* buffer, size_t size) {
+ return Impl_->Read(buffer, size);
+}
diff --git a/library/cpp/streams/zstd/zstd.h b/library/cpp/streams/zstd/zstd.h
new file mode 100644
index 0000000000..667a0494b7
--- /dev/null
+++ b/library/cpp/streams/zstd/zstd.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/stream/input.h>
+#include <util/stream/output.h>
+
+/**
+ * @addtogroup Streams_Archs
+ * @{
+ */
+
+// @brief Stream to compress into zstd archive
+class TZstdCompress: public IOutputStream {
+public:
+ /**
+ @param slave stream to write compressed data to
+ @param quality, higher quality - slower but better compression.
+ 0 is default compression (see constant ZSTD_CLEVEL_DEFAULT(3))
+ max compression is ZSTD_MAX_CLEVEL (22)
+ */
+ explicit TZstdCompress(IOutputStream* slave, int quality = 0);
+ ~TZstdCompress() override;
+private:
+ void DoWrite(const void* buffer, size_t size) override;
+ void DoFlush() override;
+ void DoFinish() override;
+
+public:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+// @brief Buffered stream to decompress from zstd archive
+class TZstdDecompress: public IInputStream {
+public:
+ /**
+ @param slave stream to read compressed data from
+ @param bufferSize approximate size of buffer compressed data is read in
+ */
+ explicit TZstdDecompress(IInputStream* slave, size_t bufferSize = 8 * 1024);
+ ~TZstdDecompress() override;
+
+private:
+ size_t DoRead(void* buffer, size_t size) override;
+
+private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+};
+
+/** @} */
diff --git a/library/cpp/streams/zstd/zstd_ut.cpp b/library/cpp/streams/zstd/zstd_ut.cpp
new file mode 100644
index 0000000000..ef479fdd97
--- /dev/null
+++ b/library/cpp/streams/zstd/zstd_ut.cpp
@@ -0,0 +1,94 @@
+#include "zstd.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/random/fast.h>
+#include <util/stream/null.h>
+#include <util/stream/str.h>
+
+Y_UNIT_TEST_SUITE(TZstdTestSuite) {
+ TString Compress(TString data, int quality = -1) {
+ TString compressed;
+ TStringOutput output(compressed);
+ TZstdCompress compressStream(&output, quality);
+ compressStream.Write(data.data(), data.size());
+ compressStream.Finish();
+ output.Finish();
+ return compressed;
+ }
+
+ TString Decompress(TString data) {
+ TStringInput input(data);
+ TZstdDecompress decompressStream(&input);
+ return decompressStream.ReadAll();
+ }
+
+ void TestCase(const TString& s) {
+ UNIT_ASSERT_VALUES_EQUAL(s, Decompress(Compress(s, -1)));
+ UNIT_ASSERT_VALUES_EQUAL(s, Decompress(Compress(s, 0)));
+ UNIT_ASSERT_VALUES_EQUAL(s, Decompress(Compress(s, 22)));
+ UNIT_ASSERT_VALUES_EQUAL(s, Decompress(Compress(s, 11)));
+ UNIT_ASSERT_VALUES_EQUAL(s, Decompress(Compress(s, 100500)));
+ }
+
+ TString GenerateRandomString(size_t size) {
+ TReallyFastRng32 rng(42);
+ TString result;
+ result.reserve(size + sizeof(ui64));
+ while (result.size() < size) {
+ ui64 value = rng.GenRand64();
+ result += TStringBuf(reinterpret_cast<const char*>(&value), sizeof(value));
+ }
+ result.resize(size);
+ return result;
+ }
+
+ Y_UNIT_TEST(TestHelloWorld) {
+ TestCase("hello world");
+ }
+
+ Y_UNIT_TEST(TestSeveralStreamsWithSameQuality) {
+ auto s1 = GenerateRandomString(1 << 15);
+ auto s2 = GenerateRandomString(1 << 15);
+ auto c1 = Compress(s1);
+ auto c2 = Compress(s2);
+ UNIT_ASSERT_VALUES_EQUAL(s1 + s2, Decompress(c1 + c2));
+ }
+
+ Y_UNIT_TEST(TestSeveralStreamsWithDifferentQuality) {
+ auto s1 = GenerateRandomString(1 << 15);
+ auto s2 = GenerateRandomString(1 << 15);
+ auto c1 = Compress(s1, 1);
+ auto c2 = Compress(s2, 2);
+ UNIT_ASSERT_VALUES_EQUAL(s1 + s2, Decompress(c1 + c2));
+ }
+
+ Y_UNIT_TEST(TestIncompleteStream) {
+ TString manyAs(64 * 1024, 'a');
+ auto compressed = Compress(manyAs);
+ TString truncated(compressed.data(), compressed.size() - 1);
+ UNIT_CHECK_GENERATED_EXCEPTION(Decompress(truncated), std::exception);
+ }
+
+ Y_UNIT_TEST(Test64KB) {
+ auto manyAs = TString(64 * 1024, 'a');
+ TString str("Hello from the Matrix!@#% How are you?}{\n\t\a");
+ TestCase(manyAs + str + manyAs);
+ }
+
+ Y_UNIT_TEST(Test1MB) {
+ TestCase(GenerateRandomString(1 * 1024 * 1024));
+ }
+
+ Y_UNIT_TEST(TestEmpty) {
+ TestCase("");
+ }
+
+ Y_UNIT_TEST(TestWriteAfterFinish) {
+ TNullOutput output;
+ TZstdCompress compressStream(&output);
+ compressStream.Finish();
+ UNIT_ASSERT_EXCEPTION_CONTAINS(compressStream.Write("a", 1), std::exception, "Cannot use stream after finish.");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(compressStream.Flush(), std::exception, "Cannot use stream after finish.");
+ }
+}
diff --git a/library/cpp/string_utils/base64/base64.cpp b/library/cpp/string_utils/base64/base64.cpp
new file mode 100644
index 0000000000..05c201f0de
--- /dev/null
+++ b/library/cpp/string_utils/base64/base64.cpp
@@ -0,0 +1,268 @@
+#include "base64.h"
+
+#include <contrib/libs/base64/avx2/libbase64.h>
+#include <contrib/libs/base64/ssse3/libbase64.h>
+#include <contrib/libs/base64/neon32/libbase64.h>
+#include <contrib/libs/base64/neon64/libbase64.h>
+#include <contrib/libs/base64/plain32/libbase64.h>
+#include <contrib/libs/base64/plain64/libbase64.h>
+
+#include <util/generic/yexception.h>
+#include <util/system/cpu_id.h>
+#include <util/system/platform.h>
+
+#include <cstdlib>
+
+namespace {
+ struct TImpl {
+ void (*Encode)(const char* src, size_t srclen, char* out, size_t* outlen);
+ int (*Decode)(const char* src, size_t srclen, char* out, size_t* outlen);
+
+ TImpl() {
+#if defined(_arm32_)
+ const bool haveNEON32 = true;
+#else
+ const bool haveNEON32 = false;
+#endif
+
+#if defined(_arm64_)
+ const bool haveNEON64 = true;
+#else
+ const bool haveNEON64 = false;
+#endif
+
+# ifdef _windows_
+ // msvc does something wrong in release-build, so we temprorary disable this branch on windows
+ // https://developercommunity.visualstudio.com/content/problem/334085/release-build-has-made-wrong-optimizaion-in-base64.html
+ const bool isWin = true;
+# else
+ const bool isWin = false;
+# endif
+ if (!isWin && NX86::HaveAVX() && NX86::HaveAVX2()) {
+ Encode = avx2_base64_encode;
+ Decode = avx2_base64_decode;
+ } else if (NX86::HaveSSSE3()) {
+ Encode = ssse3_base64_encode;
+ Decode = ssse3_base64_decode;
+ } else if (haveNEON64) {
+ Encode = neon64_base64_encode;
+ Decode = neon64_base64_decode;
+ } else if (haveNEON32) {
+ Encode = neon32_base64_encode;
+ Decode = neon32_base64_decode;
+ } else if (sizeof(void*) == 8) {
+ // running on a 64 bit platform
+ Encode = plain64_base64_encode;
+ Decode = plain64_base64_decode;
+ } else if (sizeof(void*) == 4) {
+ // running on a 32 bit platform (actually impossible in Arcadia)
+ Encode = plain32_base64_encode;
+ Decode = plain32_base64_decode;
+ } else {
+ // failed to find appropriate implementation
+ std::abort();
+ }
+ }
+ };
+
+ const TImpl GetImpl() {
+ static const TImpl IMPL;
+ return IMPL;
+ }
+}
+
+static const char base64_etab_std[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char base64_bkw[] = {
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0..15
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 16..31
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\76', '\0', '\76', '\0', '\77', // 32.47
+ '\64', '\65', '\66', '\67', '\70', '\71', '\72', '\73', '\74', '\75', '\0', '\0', '\0', '\0', '\0', '\0', // 48..63
+ '\0', '\0', '\1', '\2', '\3', '\4', '\5', '\6', '\7', '\10', '\11', '\12', '\13', '\14', '\15', '\16', // 64..79
+ '\17', '\20', '\21', '\22', '\23', '\24', '\25', '\26', '\27', '\30', '\31', '\0', '\0', '\0', '\0', '\77', // 80..95
+ '\0', '\32', '\33', '\34', '\35', '\36', '\37', '\40', '\41', '\42', '\43', '\44', '\45', '\46', '\47', '\50', // 96..111
+ '\51', '\52', '\53', '\54', '\55', '\56', '\57', '\60', '\61', '\62', '\63', '\0', '\0', '\0', '\0', '\0', // 112..127
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 128..143
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'};
+
+static_assert(Y_ARRAY_SIZE(base64_bkw) == 256, "wrong size");
+
+// Base64 for url encoding, RFC3548
+static const char base64_etab_url[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+static inline unsigned char GetBase64EncodedIndex0(unsigned char octet0) {
+ return (octet0 >> 2);
+}
+
+static inline unsigned char GetBase64EncodedIndex1(unsigned char octet0, unsigned char octet1) {
+ return (((octet0 << 4) & 0x30) | ((octet1 >> 4) & 0x0f));
+}
+
+static inline unsigned char GetBase64EncodedIndex2(unsigned char octet1, unsigned char octet2) {
+ return (((octet1 << 2) & 0x3c) | ((octet2 >> 6) & 0x03));
+}
+
+static inline unsigned char GetBase64EncodedIndex3(unsigned char octet2) {
+ return (octet2 & 0x3f);
+}
+
+template <bool urlVersion>
+static inline char* Base64EncodeImpl(char* outstr, const unsigned char* instr, size_t len) {
+ const char* const base64_etab = (urlVersion ? base64_etab_url : base64_etab_std);
+ const char pad = (urlVersion ? ',' : '=');
+
+ size_t idx = 0;
+
+ while (idx + 2 < len) {
+ *outstr++ = base64_etab[GetBase64EncodedIndex0(instr[idx])];
+ *outstr++ = base64_etab[GetBase64EncodedIndex1(instr[idx], instr[idx + 1])];
+ *outstr++ = base64_etab[GetBase64EncodedIndex2(instr[idx + 1], instr[idx + 2])];
+ *outstr++ = base64_etab[GetBase64EncodedIndex3(instr[idx + 2])];
+ idx += 3;
+ }
+ if (idx < len) {
+ *outstr++ = base64_etab[GetBase64EncodedIndex0(instr[idx])];
+ if (idx + 1 < len) {
+ *outstr++ = base64_etab[GetBase64EncodedIndex1(instr[idx], instr[idx + 1])];
+ *outstr++ = base64_etab[GetBase64EncodedIndex2(instr[idx + 1], '\0')];
+ } else {
+ *outstr++ = base64_etab[GetBase64EncodedIndex1(instr[idx], '\0')];
+ *outstr++ = pad;
+ }
+ *outstr++ = pad;
+ }
+ *outstr = 0;
+
+ return outstr;
+}
+
+static char* Base64EncodePlain(char* outstr, const unsigned char* instr, size_t len) {
+ return Base64EncodeImpl<false>(outstr, instr, len);
+}
+
+char* Base64EncodeUrl(char* outstr, const unsigned char* instr, size_t len) {
+ return Base64EncodeImpl<true>(outstr, instr, len);
+}
+
+inline void uudecode_1(char* dst, unsigned char* src) {
+ dst[0] = char((base64_bkw[src[0]] << 2) | (base64_bkw[src[1]] >> 4));
+ dst[1] = char((base64_bkw[src[1]] << 4) | (base64_bkw[src[2]] >> 2));
+ dst[2] = char((base64_bkw[src[2]] << 6) | base64_bkw[src[3]]);
+}
+
+static size_t Base64DecodePlain(void* dst, const char* b, const char* e) {
+ size_t n = 0;
+ while (b < e) {
+ uudecode_1((char*)dst + n, (unsigned char*)b);
+
+ b += 4;
+ n += 3;
+ }
+
+ if (n > 0) {
+ if (b[-1] == ',' || b[-1] == '=') {
+ n--;
+
+ if (b[-2] == ',' || b[-2] == '=') {
+ n--;
+ }
+ }
+ }
+
+ return n;
+}
+
+// Table for Base64StrictDecode
+static const char base64_bkw_strict[] =
+ "\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100"
+ "\100\100\100\100\100\100\100\100\100\100\100\76\101\76\100\77\64\65\66\67\70\71\72\73\74\75\100\100\100\101\100\100"
+ "\100\0\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\100\100\100\100\77"
+ "\100\32\33\34\35\36\37\40\41\42\43\44\45\46\47\50\51\52\53\54\55\56\57\60\61\62\63\100\100\100\100\100"
+ "\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100"
+ "\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100"
+ "\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100"
+ "\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100\100";
+
+size_t Base64StrictDecode(void* out, const char* b, const char* e) {
+ char* dst = (char*)out;
+ const unsigned char* src = (unsigned char*)b;
+ const unsigned char* const end = (unsigned char*)e;
+
+ Y_ENSURE(!((e - b) % 4), "incorrect input length for base64 decode");
+
+ while (src < end) {
+ const char zeroth = base64_bkw_strict[src[0]];
+ const char first = base64_bkw_strict[src[1]];
+ const char second = base64_bkw_strict[src[2]];
+ const char third = base64_bkw_strict[src[3]];
+
+ constexpr char invalid = 64;
+ constexpr char padding = 65;
+ if (Y_UNLIKELY(zeroth == invalid || first == invalid ||
+ second == invalid || third == invalid ||
+ zeroth == padding || first == padding))
+ {
+ ythrow yexception() << "invalid character in input";
+ }
+
+ dst[0] = char((zeroth << 2) | (first >> 4));
+ dst[1] = char((first << 4) | (second >> 2));
+ dst[2] = char((second << 6) | third);
+
+ src += 4;
+ dst += 3;
+
+ if (src[-1] == ',' || src[-1] == '=') {
+ --dst;
+
+ if (src[-2] == ',' || src[-2] == '=') {
+ --dst;
+ }
+ } else if (Y_UNLIKELY(src[-2] == ',' || src[-2] == '=')) {
+ ythrow yexception() << "incorrect padding";
+ }
+ }
+
+ return dst - (char*)out;
+}
+
+size_t Base64Decode(void* dst, const char* b, const char* e) {
+ static const TImpl IMPL = GetImpl();
+ const auto size = e - b;
+ Y_ENSURE(!(size % 4), "incorrect input length for base64 decode");
+ if (Y_LIKELY(size < 8)) {
+ return Base64DecodePlain(dst, b, e);
+ }
+
+ size_t outLen;
+ IMPL.Decode(b, size, (char*)dst, &outLen);
+
+ return outLen;
+}
+
+TString Base64DecodeUneven(const TStringBuf s) {
+ if (s.length() % 4 == 0) {
+ return Base64Decode(s);
+ }
+
+ // padding to 4
+ return Base64Decode(TString(s) + TString(4 - (s.length() % 4), '='));
+}
+
+char* Base64Encode(char* outstr, const unsigned char* instr, size_t len) {
+ static const TImpl IMPL = GetImpl();
+ if (Y_LIKELY(len < 8)) {
+ return Base64EncodePlain(outstr, instr, len);
+ }
+
+ size_t outLen;
+ IMPL.Encode((char*)instr, len, outstr, &outLen);
+
+ *(outstr + outLen) = '\0';
+ return outstr + outLen;
+}
diff --git a/library/cpp/string_utils/base64/base64.h b/library/cpp/string_utils/base64/base64.h
new file mode 100644
index 0000000000..f778a6425a
--- /dev/null
+++ b/library/cpp/string_utils/base64/base64.h
@@ -0,0 +1,130 @@
+#pragma once
+
+#include <util/system/defaults.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+
+/* @return Size of the buffer required to decode Base64 encoded data of size `len`.
+ */
+constexpr size_t Base64DecodeBufSize(const size_t len) noexcept {
+ return (len + 3) / 4 * 3;
+}
+
+/* Decode Base64 encoded data. Can decode both regular Base64 and Base64URL encoded data. Can decode
+ * only valid Base64[URL] data, behaviour for invalid data is unspecified.
+ *
+ * @throws Throws exception in case of incorrect padding.
+ *
+ * @param dst memory for writing output.
+ * @param b pointer to the beginning of base64 encoded string.
+ * @param a pointer to the end of base64 encoded string
+ *
+ * @return Return number of bytes decoded.
+ */
+size_t Base64Decode(void* dst, const char* b, const char* e);
+
+inline TStringBuf Base64Decode(const TStringBuf src, void* dst) {
+ return TStringBuf((const char*)dst, Base64Decode(dst, src.begin(), src.end()));
+}
+
+inline void Base64Decode(const TStringBuf src, TString& dst) {
+ dst.ReserveAndResize(Base64DecodeBufSize(src.size()));
+ dst.resize(Base64Decode(src, dst.begin()).size());
+}
+
+//WARNING: can process not whole input silently, use Base64StrictDecode instead of this function
+inline TString Base64Decode(const TStringBuf s) {
+ TString ret;
+ Base64Decode(s, ret);
+ return ret;
+}
+
+///
+/// @brief Decodes Base64 string with strict verification
+/// of invalid symbols, also tries to decode Base64 string with padding
+/// inside.
+//
+/// @throws Throws exceptions on inputs which contain invalid symbols
+/// or incorrect padding.
+/// @{
+///
+/// @param b a pointer to the beginning of base64 encoded string.
+/// @param e a pointer to the end of base64 encoded string.
+/// @param dst memory for writing output.
+///
+/// @return Returns number of bytes decoded.
+///
+size_t Base64StrictDecode(void* dst, const char* b, const char* e);
+
+///
+/// @param src a base64 encoded string.
+/// @param dst an pointer to allocated memory
+/// for writing result.
+///
+/// @return Returns dst wrapped into TStringBuf.
+///
+inline TStringBuf Base64StrictDecode(const TStringBuf src, void* dst) {
+ return TStringBuf((const char*)dst, Base64StrictDecode(dst, src.begin(), src.end()));
+}
+
+///
+/// @param src a base64 encoded string.
+/// @param dst a decoded string.
+///
+inline void Base64StrictDecode(const TStringBuf src, TString& dst) {
+ dst.ReserveAndResize(Base64DecodeBufSize(src.size()));
+ dst.resize(Base64StrictDecode(src, dst.begin()).size());
+}
+
+///
+/// @param src a base64 encoded string.
+///
+/// @returns a decoded string.
+///
+inline TString Base64StrictDecode(const TStringBuf src) {
+ TString ret;
+ Base64StrictDecode(src, ret);
+ return ret;
+}
+/// @}
+
+/// Works with strings which length is not divisible by 4.
+TString Base64DecodeUneven(const TStringBuf s);
+
+//encode
+constexpr size_t Base64EncodeBufSize(const size_t len) noexcept {
+ return (len + 2) / 3 * 4 + 1;
+}
+
+char* Base64Encode(char* outstr, const unsigned char* instr, size_t len);
+char* Base64EncodeUrl(char* outstr, const unsigned char* instr, size_t len);
+
+inline TStringBuf Base64Encode(const TStringBuf src, void* tmp) {
+ return TStringBuf((const char*)tmp, Base64Encode((char*)tmp, (const unsigned char*)src.data(), src.size()));
+}
+
+inline TStringBuf Base64EncodeUrl(const TStringBuf src, void* tmp) {
+ return TStringBuf((const char*)tmp, Base64EncodeUrl((char*)tmp, (const unsigned char*)src.data(), src.size()));
+}
+
+inline void Base64Encode(const TStringBuf src, TString& dst) {
+ dst.ReserveAndResize(Base64EncodeBufSize(src.size()));
+ dst.resize(Base64Encode(src, dst.begin()).size());
+}
+
+inline void Base64EncodeUrl(const TStringBuf src, TString& dst) {
+ dst.ReserveAndResize(Base64EncodeBufSize(src.size()));
+ dst.resize(Base64EncodeUrl(src, dst.begin()).size());
+}
+
+inline TString Base64Encode(const TStringBuf s) {
+ TString ret;
+ Base64Encode(s, ret);
+ return ret;
+}
+
+inline TString Base64EncodeUrl(const TStringBuf s) {
+ TString ret;
+ Base64EncodeUrl(s, ret);
+ return ret;
+}
diff --git a/library/cpp/string_utils/base64/base64_decode_uneven_ut.cpp b/library/cpp/string_utils/base64/base64_decode_uneven_ut.cpp
new file mode 100644
index 0000000000..c3ed068a37
--- /dev/null
+++ b/library/cpp/string_utils/base64/base64_decode_uneven_ut.cpp
@@ -0,0 +1,46 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/string_utils/base64/base64.h>
+
+Y_UNIT_TEST_SUITE(TBase64DecodeUneven) {
+ Y_UNIT_TEST(Base64DecodeUneven) {
+ const TString wikipedia_slogan =
+ "Man is distinguished, not only by his reason, "
+ "but by this singular passion from other animals, which is a lust of the "
+ "mind, that by a perseverance of delight in the continued and "
+ "indefatigable generation of knowledge, exceeds the short "
+ "vehemence of any carnal pleasure.";
+ const TString encoded =
+ "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0"
+ "aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1"
+ "c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0"
+ "aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdl"
+ "LCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=";
+
+ UNIT_ASSERT_VALUES_EQUAL(encoded, Base64Encode(wikipedia_slogan));
+ UNIT_ASSERT_VALUES_EQUAL(wikipedia_slogan, Base64DecodeUneven(encoded));
+
+ const TString encoded_url1 =
+ "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0"
+ "aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1"
+ "c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0"
+ "aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdl"
+ "LCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4,";
+ const TString encoded_url2 =
+ "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0"
+ "aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1"
+ "c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0"
+ "aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdl"
+ "LCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4";
+ UNIT_ASSERT_VALUES_EQUAL(wikipedia_slogan, Base64DecodeUneven(encoded_url1));
+ UNIT_ASSERT_VALUES_EQUAL(wikipedia_slogan, Base64DecodeUneven(encoded_url2));
+
+ const TString lp = "Linkin Park";
+ UNIT_ASSERT_VALUES_EQUAL(lp, Base64DecodeUneven(Base64Encode(lp)));
+ UNIT_ASSERT_VALUES_EQUAL(lp, Base64DecodeUneven(Base64EncodeUrl(lp)));
+
+ const TString dp = "ADP GmbH\nAnalyse Design & Programmierung\nGesellschaft mit beschränkter Haftung";
+ UNIT_ASSERT_VALUES_EQUAL(dp, Base64DecodeUneven(Base64Encode(dp)));
+ UNIT_ASSERT_VALUES_EQUAL(dp, Base64DecodeUneven(Base64EncodeUrl(dp)));
+ }
+}
diff --git a/library/cpp/string_utils/base64/base64_ut.cpp b/library/cpp/string_utils/base64/base64_ut.cpp
new file mode 100644
index 0000000000..bcc1e65879
--- /dev/null
+++ b/library/cpp/string_utils/base64/base64_ut.cpp
@@ -0,0 +1,497 @@
+#include "base64.h"
+
+#include <contrib/libs/base64/avx2/libbase64.h>
+#include <contrib/libs/base64/neon32/libbase64.h>
+#include <contrib/libs/base64/neon64/libbase64.h>
+#include <contrib/libs/base64/plain32/libbase64.h>
+#include <contrib/libs/base64/plain64/libbase64.h>
+#include <contrib/libs/base64/ssse3/libbase64.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/vector.h>
+#include <util/random/fast.h>
+#include <util/system/cpu_id.h>
+#include <util/system/platform.h>
+
+#include <array>
+
+using namespace std::string_view_literals;
+
+#define BASE64_UT_DECLARE_BASE64_IMPL(prefix, encFunction, decFunction) \
+ Y_DECLARE_UNUSED \
+ static size_t prefix##Base64Decode(void* dst, const char* b, const char* e) { \
+ const auto size = e - b; \
+ Y_ENSURE(!(size % 4), "incorrect input length for base64 decode"); \
+ \
+ size_t outLen; \
+ decFunction(b, size, (char*)dst, &outLen); \
+ return outLen; \
+ } \
+ \
+ Y_DECLARE_UNUSED \
+ static inline TStringBuf prefix##Base64Decode(const TStringBuf& src, void* dst) { \
+ return TStringBuf((const char*)dst, ::NB64Etalon::prefix##Base64Decode(dst, src.begin(), src.end())); \
+ } \
+ \
+ Y_DECLARE_UNUSED \
+ static inline void prefix##Base64Decode(const TStringBuf& src, TString& dst) { \
+ dst.ReserveAndResize(Base64DecodeBufSize(src.size())); \
+ dst.resize(::NB64Etalon::prefix##Base64Decode(src, dst.begin()).size()); \
+ } \
+ \
+ Y_DECLARE_UNUSED \
+ static inline TString prefix##Base64Decode(const TStringBuf& s) { \
+ TString ret; \
+ prefix##Base64Decode(s, ret); \
+ return ret; \
+ } \
+ \
+ Y_DECLARE_UNUSED \
+ static char* prefix##Base64Encode(char* outstr, const unsigned char* instr, size_t len) { \
+ size_t outLen; \
+ encFunction((char*)instr, len, outstr, &outLen); \
+ *(outstr + outLen) = '\0'; \
+ return outstr + outLen; \
+ } \
+ \
+ Y_DECLARE_UNUSED \
+ static inline TStringBuf prefix##Base64Encode(const TStringBuf& src, void* tmp) { \
+ return TStringBuf((const char*)tmp, ::NB64Etalon::prefix##Base64Encode((char*)tmp, (const unsigned char*)src.data(), src.size())); \
+ } \
+ \
+ Y_DECLARE_UNUSED \
+ static inline void prefix##Base64Encode(const TStringBuf& src, TString& dst) { \
+ dst.ReserveAndResize(Base64EncodeBufSize(src.size())); \
+ dst.resize(::NB64Etalon::prefix##Base64Encode(src, dst.begin()).size()); \
+ } \
+ \
+ Y_DECLARE_UNUSED \
+ static inline TString prefix##Base64Encode(const TStringBuf& s) { \
+ TString ret; \
+ prefix##Base64Encode(s, ret); \
+ return ret; \
+ }
+
+namespace NB64Etalon {
+ BASE64_UT_DECLARE_BASE64_IMPL(PLAIN32, plain32_base64_encode, plain32_base64_decode);
+ BASE64_UT_DECLARE_BASE64_IMPL(PLAIN64, plain64_base64_encode, plain64_base64_decode);
+ BASE64_UT_DECLARE_BASE64_IMPL(NEON32, neon32_base64_encode, neon32_base64_decode);
+ BASE64_UT_DECLARE_BASE64_IMPL(NEON64, neon64_base64_encode, neon64_base64_decode);
+ BASE64_UT_DECLARE_BASE64_IMPL(AVX2, avx2_base64_encode, avx2_base64_decode);
+ BASE64_UT_DECLARE_BASE64_IMPL(SSSE3, ssse3_base64_encode, ssse3_base64_decode);
+
+#undef BASE64_UT_DECLARE_BASE64_IMPL
+
+ struct TImpls {
+ enum EImpl : size_t {
+ PLAIN32_IMPL,
+ PLAIN64_IMPL,
+ NEON32_IMPL,
+ NEON64_IMPL,
+ AVX2_IMPL,
+ SSSE3_IMPL,
+ MAX_IMPL
+ };
+
+ using TEncodeF = void (*)(const TStringBuf&, TString&);
+ using TDecodeF = void (*)(const TStringBuf&, TString&);
+
+ struct TImpl {
+ TEncodeF Encode = nullptr;
+ TDecodeF Decode = nullptr;
+ };
+
+ std::array<TImpl, MAX_IMPL> Impl;
+
+ TImpls() {
+ Impl[PLAIN32_IMPL].Encode = PLAIN32Base64Encode;
+ Impl[PLAIN32_IMPL].Decode = PLAIN32Base64Decode;
+ Impl[PLAIN64_IMPL].Encode = PLAIN64Base64Encode;
+ Impl[PLAIN64_IMPL].Decode = PLAIN64Base64Decode;
+#if defined(_arm32_)
+ Impl[NEON32_IMPL].Encode = NEON32Base64Encode;
+ Impl[NEON32_IMPL].Decode = NEON32Base64Decode;
+#elif defined(_arm64_)
+ Impl[NEON64_IMPL].Encode = NEON64Base64Encode;
+ Impl[NEON64_IMPL].Decode = NEON64Base64Decode;
+#elif defined(_x86_64_)
+ if (NX86::HaveSSSE3()) {
+ Impl[SSSE3_IMPL].Encode = SSSE3Base64Encode;
+ Impl[SSSE3_IMPL].Decode = SSSE3Base64Decode;
+ }
+
+ if (NX86::HaveAVX2()) {
+ Impl[AVX2_IMPL].Encode = AVX2Base64Encode;
+ Impl[AVX2_IMPL].Decode = AVX2Base64Decode;
+ }
+#else
+ ythrow yexception() << "Failed to identify the platform";
+#endif
+ }
+ };
+
+ TImpls GetImpls() {
+ static const TImpls IMPLS;
+ return IMPLS;
+ }
+}
+
+template <>
+void Out<NB64Etalon::TImpls::EImpl>(IOutputStream& o, typename TTypeTraits<NB64Etalon::TImpls::EImpl>::TFuncParam v) {
+ switch (v) {
+ case NB64Etalon::TImpls::PLAIN32_IMPL:
+ o << TStringBuf{"PLAIN32"};
+ return;
+ case NB64Etalon::TImpls::PLAIN64_IMPL:
+ o << TStringBuf{"PLAIN64"};
+ return;
+ case NB64Etalon::TImpls::NEON64_IMPL:
+ o << TStringBuf{"NEON64"};
+ return;
+ case NB64Etalon::TImpls::NEON32_IMPL:
+ o << TStringBuf{"NEON32"};
+ return;
+ case NB64Etalon::TImpls::SSSE3_IMPL:
+ o << TStringBuf{"SSSE3"};
+ return;
+ case NB64Etalon::TImpls::AVX2_IMPL:
+ o << TStringBuf{"AVX2"};
+ return;
+ default:
+ ythrow yexception() << "invalid";
+ }
+}
+
+static void TestEncodeDecodeIntoString(const TString& plain, const TString& encoded, const TString& encodedUrl) {
+ TString a, b;
+
+ Base64Encode(plain, a);
+ UNIT_ASSERT_VALUES_EQUAL(a, encoded);
+
+ Base64Decode(a, b);
+ UNIT_ASSERT_VALUES_EQUAL(b, plain);
+
+ Base64EncodeUrl(plain, a);
+ UNIT_ASSERT_VALUES_EQUAL(a, encodedUrl);
+
+ Base64Decode(a, b);
+ UNIT_ASSERT_VALUES_EQUAL(b, plain);
+}
+
+static void TestEncodeStrictDecodeIntoString(const TString& plain, const TString& encoded, const TString& encodedUrl) {
+ TString a, b;
+
+ Base64Encode(plain, a);
+ UNIT_ASSERT_VALUES_EQUAL(a, encoded);
+
+ Base64StrictDecode(a, b);
+ UNIT_ASSERT_VALUES_EQUAL(b, plain);
+
+ Base64EncodeUrl(plain, a);
+ UNIT_ASSERT_VALUES_EQUAL(a, encodedUrl);
+
+ Base64StrictDecode(a, b);
+ UNIT_ASSERT_VALUES_EQUAL(b, plain);
+}
+
+Y_UNIT_TEST_SUITE(TBase64) {
+ Y_UNIT_TEST(TestEncode) {
+ UNIT_ASSERT_VALUES_EQUAL(Base64Encode("12z"), "MTJ6");
+ UNIT_ASSERT_VALUES_EQUAL(Base64Encode("123"), "MTIz");
+ UNIT_ASSERT_VALUES_EQUAL(Base64Encode("12"), "MTI=");
+ UNIT_ASSERT_VALUES_EQUAL(Base64Encode("1"), "MQ==");
+ }
+
+ Y_UNIT_TEST(TestIntoString) {
+ {
+ TString str;
+ for (size_t i = 0; i < 256; ++i)
+ str += char(i);
+
+ const TString base64 =
+ "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJy"
+ "gpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9Q"
+ "UVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eH"
+ "l6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6Ch"
+ "oqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIyc"
+ "rLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy"
+ "8/T19vf4+fr7/P3+/w==";
+ const TString base64Url =
+ "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJy"
+ "gpKissLS4vMDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9Q"
+ "UVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eH"
+ "l6e3x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6Ch"
+ "oqOkpaanqKmqq6ytrq-wsbKztLW2t7i5uru8vb6_wMHCw8TFxsfIyc"
+ "rLzM3Oz9DR0tPU1dbX2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy"
+ "8_T19vf4-fr7_P3-_w,,";
+
+ TestEncodeDecodeIntoString(str, base64, base64Url);
+ TestEncodeStrictDecodeIntoString(str, base64, base64Url);
+ }
+
+ {
+ const TString str = "http://yandex.ru:1234/request?param=value&lll=fff#fragment";
+
+ const TString base64 = "aHR0cDovL3lhbmRleC5ydToxMjM0L3JlcXVlc3Q/cGFyYW09dmFsdWUmbGxsPWZmZiNmcmFnbWVudA==";
+ const TString base64Url = "aHR0cDovL3lhbmRleC5ydToxMjM0L3JlcXVlc3Q_cGFyYW09dmFsdWUmbGxsPWZmZiNmcmFnbWVudA,,";
+
+ TestEncodeDecodeIntoString(str, base64, base64Url);
+ TestEncodeStrictDecodeIntoString(str, base64, base64Url);
+ }
+ }
+
+ Y_UNIT_TEST(TestDecode) {
+ UNIT_ASSERT_EXCEPTION(Base64Decode("a"), yexception);
+ UNIT_ASSERT_EXCEPTION(Base64StrictDecode("a"), yexception);
+
+ UNIT_ASSERT_VALUES_EQUAL(Base64Decode(""), "");
+ UNIT_ASSERT_VALUES_EQUAL(Base64StrictDecode(""), "");
+
+ UNIT_ASSERT_VALUES_EQUAL(Base64Decode("MTI="), "12");
+ UNIT_ASSERT_VALUES_EQUAL(Base64StrictDecode("MTI="), "12");
+
+ UNIT_ASSERT_VALUES_EQUAL(Base64Decode("QQ=="), "A");
+ UNIT_ASSERT_VALUES_EQUAL(Base64StrictDecode("QQ=="), "A");
+
+ UNIT_ASSERT_EXCEPTION(Base64StrictDecode("M=I="), yexception);
+
+ UNIT_ASSERT_VALUES_EQUAL(Base64Decode("dnluZHg="), "vyndx");
+ UNIT_ASSERT_VALUES_EQUAL(Base64StrictDecode("dnluZHg="), "vyndx");
+
+ UNIT_ASSERT_VALUES_EQUAL(Base64StrictDecode("dnluZHg=dmlkZW8="), "vyndxvideo");
+
+ UNIT_ASSERT_EXCEPTION(Base64StrictDecode("aHR0cDovL2ltZy5tZWdhLXBvcm5vLnJ1Lw=a"), yexception);
+
+ UNIT_ASSERT_EXCEPTION(Base64StrictDecode("aHh=="), yexception);
+ UNIT_ASSERT_EXCEPTION(Base64StrictDecode("\1\1\1\2"), yexception);
+ }
+
+ Y_UNIT_TEST(TestDecodeUneven) {
+ UNIT_ASSERT_VALUES_EQUAL(Base64DecodeUneven(""), "");
+
+ UNIT_ASSERT_VALUES_EQUAL(Base64DecodeUneven("YWFh"), "aaa");
+
+ UNIT_ASSERT_VALUES_EQUAL(Base64DecodeUneven("MTI="), "12");
+ UNIT_ASSERT_VALUES_EQUAL(Base64DecodeUneven("MTI,"), "12");
+ UNIT_ASSERT_VALUES_EQUAL(Base64DecodeUneven("MTI"), "12");
+
+ UNIT_ASSERT_VALUES_EQUAL(Base64DecodeUneven("QQ=="), "A");
+ UNIT_ASSERT_VALUES_EQUAL(Base64DecodeUneven("QQ,,"), "A");
+ UNIT_ASSERT_VALUES_EQUAL(Base64DecodeUneven("QQ"), "A");
+
+ UNIT_ASSERT_VALUES_EQUAL(Base64DecodeUneven("dnluZHg="), "vyndx");
+ UNIT_ASSERT_VALUES_EQUAL(Base64DecodeUneven("dnluZHg,"), "vyndx");
+ UNIT_ASSERT_VALUES_EQUAL(Base64DecodeUneven("dnluZHg"), "vyndx");
+ }
+
+ Y_UNIT_TEST(TestDecodeRandom) {
+ TString input;
+ constexpr size_t testSize = 240000;
+ for (size_t i = 0; i < testSize; ++i) {
+ input.push_back(rand() % 256);
+ }
+ TString output;
+ TString encoded = Base64Encode(input);
+ UNIT_ASSERT_VALUES_EQUAL(Base64Decode(encoded), input);
+ UNIT_ASSERT_VALUES_EQUAL(Base64StrictDecode(encoded), input);
+ }
+
+ Y_UNIT_TEST(TestAllPossibleOctets) {
+ const TString x("\0\x01\x02\x03\x04\x05\x06\x07\b\t\n\x0B\f\r\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7F"sv);
+ const TString xEnc = "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8=";
+ const TString y = Base64Decode(xEnc);
+ const TString yEnc = Base64Encode(x);
+ UNIT_ASSERT_VALUES_EQUAL(x, y);
+ UNIT_ASSERT_VALUES_EQUAL(xEnc, yEnc);
+ }
+
+ Y_UNIT_TEST(TestTwoPaddingCharacters) {
+ const TString x("a");
+ const TString xEnc = "YQ==";
+ const TString y = Base64Decode(xEnc);
+ const TString yEnc = Base64Encode(x);
+ UNIT_ASSERT_VALUES_EQUAL(x, y);
+ UNIT_ASSERT_VALUES_EQUAL(xEnc, yEnc);
+ }
+
+ Y_UNIT_TEST(TestOnePaddingCharacter) {
+ const TString x("aa");
+ const TString xEnc = "YWE=";
+ const TString y = Base64Decode(xEnc);
+ const TString yEnc = Base64Encode(x);
+ UNIT_ASSERT_VALUES_EQUAL(x, y);
+ UNIT_ASSERT_VALUES_EQUAL(xEnc, yEnc);
+ }
+
+ Y_UNIT_TEST(TestNoPaddingCharacters) {
+ const TString x("aaa");
+ const TString xEnc = "YWFh";
+ const TString y = Base64Decode(xEnc);
+ const TString yEnc = Base64Encode(x);
+ UNIT_ASSERT_VALUES_EQUAL(x, y);
+ UNIT_ASSERT_VALUES_EQUAL(xEnc, yEnc);
+ }
+
+ Y_UNIT_TEST(TestTrailingZero) {
+ const TString x("foo\0"sv);
+ const TString xEnc = "Zm9vAA==";
+ const TString y = Base64Decode(xEnc);
+ const TString yEnc = Base64Encode(x);
+ UNIT_ASSERT_VALUES_EQUAL(x, y);
+ UNIT_ASSERT_VALUES_EQUAL(xEnc, yEnc);
+ }
+
+ Y_UNIT_TEST(TestTwoTrailingZeroes) {
+ const TString x("foo\0\0"sv);
+ const TString xEnc = "Zm9vAAA=";
+ const TString y = Base64Decode(xEnc);
+ const TString yEnc = Base64Encode(x);
+ UNIT_ASSERT_VALUES_EQUAL(x, y);
+ UNIT_ASSERT_VALUES_EQUAL(xEnc, yEnc);
+ }
+
+ Y_UNIT_TEST(TestZero) {
+ const TString x("\0"sv);
+ const TString xEnc = "AA==";
+ const TString y = Base64Decode(xEnc);
+ const TString yEnc = Base64Encode(x);
+ UNIT_ASSERT_VALUES_EQUAL(x, y);
+ UNIT_ASSERT_VALUES_EQUAL(xEnc, yEnc);
+ }
+
+ Y_UNIT_TEST(TestSymbolsAfterZero) {
+ const TString x("\0a"sv);
+ const TString xEnc = "AGE=";
+ const TString y = Base64Decode(xEnc);
+ const TString yEnc = Base64Encode(x);
+ UNIT_ASSERT_VALUES_EQUAL(x, y);
+ UNIT_ASSERT_VALUES_EQUAL(xEnc, yEnc);
+ }
+
+ Y_UNIT_TEST(TestEmptyString) {
+ const TString x = "";
+ const TString xEnc = "";
+ const TString y = Base64Decode(xEnc);
+ const TString yEnc = Base64Encode(x);
+ UNIT_ASSERT_VALUES_EQUAL(x, y);
+ UNIT_ASSERT_VALUES_EQUAL(xEnc, yEnc);
+ }
+
+ Y_UNIT_TEST(TestBackendsConsistencyOnRandomData) {
+ constexpr size_t TEST_CASES_COUNT = 1000;
+ constexpr size_t MAX_DATA_SIZE = 1000;
+ TFastRng<ui32> prng{42};
+ TVector<TString> xs{TEST_CASES_COUNT};
+ TString xEnc;
+ TString xDec;
+ TString yEnc;
+ TString yDec;
+
+ for (auto& x : xs) {
+ const size_t size = prng() % MAX_DATA_SIZE;
+ for (size_t j = 0; j < size; ++j) {
+ x += static_cast<char>(prng() % 256);
+ }
+ }
+
+ static const auto IMPLS = NB64Etalon::GetImpls();
+ for (size_t i = 0; i < static_cast<size_t>(NB64Etalon::TImpls::MAX_IMPL); ++i) {
+ for (size_t j = 0; j < static_cast<size_t>(NB64Etalon::TImpls::MAX_IMPL); ++j) {
+ const auto ei = static_cast<NB64Etalon::TImpls::EImpl>(i);
+ const auto ej = static_cast<NB64Etalon::TImpls::EImpl>(j);
+ const auto impl = IMPLS.Impl[i];
+ const auto otherImpl = IMPLS.Impl[j];
+ if (!impl.Encode && !impl.Decode || !otherImpl.Encode && !otherImpl.Decode) {
+ continue;
+ }
+
+ for (const auto& x : xs) {
+ impl.Encode(x, xEnc);
+ impl.Decode(xEnc, xDec);
+ Y_ENSURE(x == xDec, "something is wrong with " << ei << " implementation");
+
+ otherImpl.Encode(x, yEnc);
+ otherImpl.Decode(xEnc, yDec);
+ Y_ENSURE(x == yDec, "something is wrong with " << ej << " implementation");
+
+ UNIT_ASSERT_VALUES_EQUAL(xEnc, yEnc);
+ UNIT_ASSERT_VALUES_EQUAL(xDec, yDec);
+ }
+ }
+ }
+ }
+
+ Y_UNIT_TEST(TestIfEncodedDataIsZeroTerminatedOnRandomData) {
+ constexpr size_t TEST_CASES_COUNT = 1000;
+ constexpr size_t MAX_DATA_SIZE = 1000;
+ TFastRng<ui32> prng{42};
+ TString x;
+ TVector<char> buf;
+ for (size_t i = 0; i < TEST_CASES_COUNT; ++i) {
+ const size_t size = prng() % MAX_DATA_SIZE;
+ x.clear();
+ for (size_t j = 0; j < size; ++j) {
+ x += static_cast<char>(prng() % 256);
+ }
+
+ buf.assign(Base64EncodeBufSize(x.size()), Max<char>());
+ const auto* const xEncEnd = Base64Encode(buf.data(), (const unsigned char*)x.data(), x.size());
+ UNIT_ASSERT_VALUES_EQUAL(*xEncEnd, '\0');
+ }
+ }
+
+ Y_UNIT_TEST(TestDecodeURLEncodedNoPadding) {
+ const auto x = "123";
+ const auto xDec = Base64Decode("MTIz");
+ UNIT_ASSERT_VALUES_EQUAL(x, xDec);
+ }
+
+ Y_UNIT_TEST(TestDecodeURLEncodedOnePadding) {
+ const auto x = "12";
+ const auto xDec = Base64Decode("MTI,");
+ UNIT_ASSERT_VALUES_EQUAL(x, xDec);
+ }
+
+ Y_UNIT_TEST(TestDecodeURLEncodedTwoPadding) {
+ const auto x = "1";
+ const auto xDec = Base64Decode("MQ,,");
+ UNIT_ASSERT_VALUES_EQUAL(x, xDec);
+ }
+
+ Y_UNIT_TEST(TestDecodeNoPaddingLongString) {
+ const auto x = "How do I convert between big-endian and little-endian values in C++?a";
+ const auto xDec = Base64Decode("SG93IGRvIEkgY29udmVydCBiZXR3ZWVuIGJpZy1lbmRpYW4gYW5kIGxpdHRsZS1lbmRpYW4gdmFsdWVzIGluIEMrKz9h");
+ UNIT_ASSERT_VALUES_EQUAL(x, xDec);
+ }
+
+ Y_UNIT_TEST(TestDecodeOnePaddingLongString) {
+ const auto x = "How do I convert between big-endian and little-endian values in C++?";
+ const auto xDec = Base64Decode("SG93IGRvIEkgY29udmVydCBiZXR3ZWVuIGJpZy1lbmRpYW4gYW5kIGxpdHRsZS1lbmRpYW4gdmFsdWVzIGluIEMrKz8=");
+ UNIT_ASSERT_VALUES_EQUAL(x, xDec);
+ }
+
+ Y_UNIT_TEST(TestDecodeTwoPaddingLongString) {
+ const auto x = "How do I convert between big-endian and little-endian values in C++?aa";
+ const auto xDec = Base64Decode("SG93IGRvIEkgY29udmVydCBiZXR3ZWVuIGJpZy1lbmRpYW4gYW5kIGxpdHRsZS1lbmRpYW4gdmFsdWVzIGluIEMrKz9hYQ==");
+ UNIT_ASSERT_VALUES_EQUAL(x, xDec);
+ }
+
+ Y_UNIT_TEST(TestDecodeURLEncodedNoPaddingLongString) {
+ const auto x = "How do I convert between big-endian and little-endian values in C++?a";
+ const auto xDec = Base64Decode("SG93IGRvIEkgY29udmVydCBiZXR3ZWVuIGJpZy1lbmRpYW4gYW5kIGxpdHRsZS1lbmRpYW4gdmFsdWVzIGluIEMrKz9h");
+ UNIT_ASSERT_VALUES_EQUAL(x, xDec);
+ }
+
+ Y_UNIT_TEST(TestDecodeURLEncodedOnePaddingLongString) {
+ const auto x = "How do I convert between big-endian and little-endian values in C++?";
+ const auto xDec = Base64Decode("SG93IGRvIEkgY29udmVydCBiZXR3ZWVuIGJpZy1lbmRpYW4gYW5kIGxpdHRsZS1lbmRpYW4gdmFsdWVzIGluIEMrKz8,");
+ UNIT_ASSERT_VALUES_EQUAL(x, xDec);
+ }
+
+ Y_UNIT_TEST(TestDecodeURLEncodedTwoPaddingLongString) {
+ const auto x = "How do I convert between big-endian and little-endian values in C++?aa";
+ const auto xDec = Base64Decode("SG93IGRvIEkgY29udmVydCBiZXR3ZWVuIGJpZy1lbmRpYW4gYW5kIGxpdHRsZS1lbmRpYW4gdmFsdWVzIGluIEMrKz9hYQ,,");
+ UNIT_ASSERT_VALUES_EQUAL(x, xDec);
+ }
+}
diff --git a/library/cpp/string_utils/base64/bench/main.cpp b/library/cpp/string_utils/base64/bench/main.cpp
new file mode 100644
index 0000000000..10e09bc1c7
--- /dev/null
+++ b/library/cpp/string_utils/base64/bench/main.cpp
@@ -0,0 +1,326 @@
+#include <library/cpp/string_utils/base64/base64.h>
+
+#include <library/cpp/testing/benchmark/bench.h>
+
+#include <util/generic/buffer.h>
+#include <util/generic/singleton.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/generic/xrange.h>
+#include <util/generic/yexception.h>
+#include <util/random/random.h>
+
+#include <array>
+
+static TString GenerateRandomData(const size_t minSize, const size_t maxSize) {
+ Y_ENSURE(minSize <= maxSize, "wow");
+ TString r;
+ for (size_t i = 0; i < minSize; ++i) {
+ r.push_back(RandomNumber<char>());
+ }
+
+ if (minSize == maxSize) {
+ return r;
+ }
+
+ const size_t size = RandomNumber<size_t>() % (maxSize - minSize + 1);
+ for (size_t i = 0; i < size; ++i) {
+ r.push_back(RandomNumber<char>());
+ }
+
+ return r;
+}
+
+template <size_t N>
+static std::array<TString, N> GenerateRandomDataVector(const size_t minSize, const size_t maxSize) {
+ std::array<TString, N> r;
+ for (size_t i = 0; i < N; ++i) {
+ r[i] = GenerateRandomData(minSize, maxSize);
+ }
+
+ return r;
+}
+
+template <size_t N>
+static std::array<TString, N> Encode(const std::array<TString, N>& d) {
+ std::array<TString, N> r;
+ for (size_t i = 0, iEnd = d.size(); i < iEnd; ++i) {
+ r[i] = Base64Encode(d[i]);
+ }
+
+ return r;
+}
+
+namespace {
+ template <size_t N, size_t MinSize, size_t MaxSize>
+ struct TRandomDataHolder {
+ TRandomDataHolder()
+ : Data(GenerateRandomDataVector<N>(MinSize, MaxSize))
+ , DataEncoded(Encode<N>(Data))
+ {
+ for (size_t i = 0; i < N; ++i) {
+ const size_t size = Data[i].size();
+ const size_t sizeEnc = DataEncoded[i].size();
+ PlaceToEncode[i].Resize(Base64EncodeBufSize(size));
+ PlaceToDecode[i].Resize(Base64DecodeBufSize(sizeEnc));
+ }
+ }
+
+ static constexpr size_t Size = N;
+ const std::array<TString, N> Data;
+ const std::array<TString, N> DataEncoded;
+ std::array<TBuffer, N> PlaceToEncode;
+ std::array<TBuffer, N> PlaceToDecode;
+ };
+
+ template <size_t N, size_t Size>
+ using TFixedSizeRandomDataHolder = TRandomDataHolder<N, Size, Size>;
+
+ using FSRDH_1 = TFixedSizeRandomDataHolder<10, 1>;
+ using FSRDH_2 = TFixedSizeRandomDataHolder<10, 2>;
+ using FSRDH_4 = TFixedSizeRandomDataHolder<10, 4>;
+ using FSRDH_8 = TFixedSizeRandomDataHolder<10, 8>;
+ using FSRDH_16 = TFixedSizeRandomDataHolder<10, 16>;
+ using FSRDH_32 = TFixedSizeRandomDataHolder<10, 32>;
+ using FSRDH_64 = TFixedSizeRandomDataHolder<10, 64>;
+ using FSRDH_128 = TFixedSizeRandomDataHolder<10, 128>;
+ using FSRDH_1024 = TFixedSizeRandomDataHolder<10, 1024>;
+ using FSRDH_10240 = TFixedSizeRandomDataHolder<10, 10240>;
+ using FSRDH_102400 = TFixedSizeRandomDataHolder<10, 102400>;
+ using FSRDH_1048576 = TFixedSizeRandomDataHolder<10, 1048576>;
+ using FSRDH_10485760 = TFixedSizeRandomDataHolder<10, 10485760>;
+}
+
+template <typename T>
+static inline void BenchEncode(T& d, const NBench::NCpu::TParams& iface) {
+ for (const auto it : xrange(iface.Iterations())) {
+ Y_UNUSED(it);
+ for (size_t i = 0; i < d.Size; ++i) {
+ NBench::Escape(d.PlaceToEncode[i].data());
+ Y_DO_NOT_OPTIMIZE_AWAY(
+ Base64Encode(d.PlaceToEncode[i].data(), (const unsigned char*)d.Data[i].data(), d.Data[i].size()));
+ NBench::Clobber();
+ }
+ }
+}
+
+template <typename T>
+static inline void BenchEncodeUrl(T& d, const NBench::NCpu::TParams& iface) {
+ for (const auto it : xrange(iface.Iterations())) {
+ Y_UNUSED(it);
+ for (size_t i = 0; i < d.Size; ++i) {
+ NBench::Escape(d.PlaceToEncode[i].data());
+ Y_DO_NOT_OPTIMIZE_AWAY(
+ Base64EncodeUrl(d.PlaceToEncode[i].data(), (const unsigned char*)d.Data[i].data(), d.Data[i].size()));
+ NBench::Clobber();
+ }
+ }
+}
+
+template <typename T>
+static inline void BenchDecode(T& d, const NBench::NCpu::TParams& iface) {
+ for (const auto it : xrange(iface.Iterations())) {
+ Y_UNUSED(it);
+ for (size_t i = 0; i < d.Size; ++i) {
+ NBench::Escape(d.PlaceToDecode[i].data());
+ Y_DO_NOT_OPTIMIZE_AWAY(
+ Base64Decode(d.PlaceToDecode[i].data(), (const char*)d.DataEncoded[i].data(), (const char*)(d.DataEncoded[i].data() + d.DataEncoded[i].size())));
+ NBench::Clobber();
+ }
+ }
+}
+
+Y_CPU_BENCHMARK(EncodeF1, iface) {
+ auto& d = *Singleton<FSRDH_1>();
+ BenchEncode(d, iface);
+}
+
+Y_CPU_BENCHMARK(DecodeF1, iface) {
+ auto& d = *Singleton<FSRDH_1>();
+ BenchDecode(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeF2, iface) {
+ auto& d = *Singleton<FSRDH_2>();
+ BenchEncode(d, iface);
+}
+
+Y_CPU_BENCHMARK(DecodeF2, iface) {
+ auto& d = *Singleton<FSRDH_2>();
+ BenchDecode(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeF4, iface) {
+ auto& d = *Singleton<FSRDH_4>();
+ BenchEncode(d, iface);
+}
+
+Y_CPU_BENCHMARK(DecodeF4, iface) {
+ auto& d = *Singleton<FSRDH_4>();
+ BenchDecode(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeF8, iface) {
+ auto& d = *Singleton<FSRDH_8>();
+ BenchEncode(d, iface);
+}
+
+Y_CPU_BENCHMARK(DecodeF8, iface) {
+ auto& d = *Singleton<FSRDH_8>();
+ BenchDecode(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeF16, iface) {
+ auto& d = *Singleton<FSRDH_16>();
+ BenchEncode(d, iface);
+}
+
+Y_CPU_BENCHMARK(DecodeF16, iface) {
+ auto& d = *Singleton<FSRDH_16>();
+ BenchDecode(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeF32, iface) {
+ auto& d = *Singleton<FSRDH_32>();
+ BenchEncode(d, iface);
+}
+
+Y_CPU_BENCHMARK(DecodeF32, iface) {
+ auto& d = *Singleton<FSRDH_32>();
+ BenchDecode(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeF64, iface) {
+ auto& d = *Singleton<FSRDH_64>();
+ BenchEncode(d, iface);
+}
+
+Y_CPU_BENCHMARK(DecodeF64, iface) {
+ auto& d = *Singleton<FSRDH_64>();
+ BenchDecode(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeF128, iface) {
+ auto& d = *Singleton<FSRDH_128>();
+ BenchEncode(d, iface);
+}
+
+Y_CPU_BENCHMARK(DecodeF128, iface) {
+ auto& d = *Singleton<FSRDH_128>();
+ BenchDecode(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeF1024, iface) {
+ auto& d = *Singleton<FSRDH_1024>();
+ BenchEncode(d, iface);
+}
+
+Y_CPU_BENCHMARK(DecodeF1024, iface) {
+ auto& d = *Singleton<FSRDH_1024>();
+ BenchDecode(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeF10240, iface) {
+ auto& d = *Singleton<FSRDH_10240>();
+ BenchEncode(d, iface);
+}
+
+Y_CPU_BENCHMARK(DecodeF10240, iface) {
+ auto& d = *Singleton<FSRDH_10240>();
+ BenchDecode(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeF102400, iface) {
+ auto& d = *Singleton<FSRDH_102400>();
+ BenchEncode(d, iface);
+}
+
+Y_CPU_BENCHMARK(DecodeF102400, iface) {
+ auto& d = *Singleton<FSRDH_102400>();
+ BenchDecode(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeF1048576, iface) {
+ auto& d = *Singleton<FSRDH_1048576>();
+ BenchEncode(d, iface);
+}
+
+Y_CPU_BENCHMARK(DecodeF1048576, iface) {
+ auto& d = *Singleton<FSRDH_1048576>();
+ BenchDecode(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeF10485760, iface) {
+ auto& d = *Singleton<FSRDH_10485760>();
+ BenchEncode(d, iface);
+}
+
+Y_CPU_BENCHMARK(DecodeF10485760, iface) {
+ auto& d = *Singleton<FSRDH_10485760>();
+ BenchDecode(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeUrlF1, iface) {
+ auto& d = *Singleton<FSRDH_1>();
+ BenchEncodeUrl(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeUrlF2, iface) {
+ auto& d = *Singleton<FSRDH_2>();
+ BenchEncodeUrl(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeUrlF4, iface) {
+ auto& d = *Singleton<FSRDH_4>();
+ BenchEncodeUrl(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeUrlF8, iface) {
+ auto& d = *Singleton<FSRDH_8>();
+ BenchEncodeUrl(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeUrlF16, iface) {
+ auto& d = *Singleton<FSRDH_16>();
+ BenchEncodeUrl(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeUrlF32, iface) {
+ auto& d = *Singleton<FSRDH_32>();
+ BenchEncodeUrl(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeUrlF64, iface) {
+ auto& d = *Singleton<FSRDH_64>();
+ BenchEncodeUrl(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeUrlF128, iface) {
+ auto& d = *Singleton<FSRDH_128>();
+ BenchEncodeUrl(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeUrlF1024, iface) {
+ auto& d = *Singleton<FSRDH_1024>();
+ BenchEncodeUrl(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeUrlF10240, iface) {
+ auto& d = *Singleton<FSRDH_10240>();
+ BenchEncodeUrl(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeUrlF102400, iface) {
+ auto& d = *Singleton<FSRDH_102400>();
+ BenchEncodeUrl(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeUrlF1048576, iface) {
+ auto& d = *Singleton<FSRDH_1048576>();
+ BenchEncodeUrl(d, iface);
+}
+
+Y_CPU_BENCHMARK(EncodeUrlF10485760, iface) {
+ auto& d = *Singleton<FSRDH_10485760>();
+ BenchEncodeUrl(d, iface);
+}
diff --git a/library/cpp/string_utils/base64/bench/metrics/main.py b/library/cpp/string_utils/base64/bench/metrics/main.py
new file mode 100644
index 0000000000..c35fd6d8cd
--- /dev/null
+++ b/library/cpp/string_utils/base64/bench/metrics/main.py
@@ -0,0 +1,5 @@
+import yatest.common as yc
+
+
+def test_export_metrics(metrics):
+ metrics.set_benchmark(yc.execute_benchmark('library/cpp/string_utils/base64/bench/bench'))
diff --git a/library/cpp/string_utils/base64/bench/metrics/ya.make b/library/cpp/string_utils/base64/bench/metrics/ya.make
new file mode 100644
index 0000000000..b0406516c3
--- /dev/null
+++ b/library/cpp/string_utils/base64/bench/metrics/ya.make
@@ -0,0 +1,20 @@
+OWNER(
+ yazevnul
+ g:util
+)
+
+PY2TEST()
+
+SIZE(LARGE)
+
+TAG(
+ ya:force_sandbox
+ sb:intel_e5_2660v1
+ ya:fat
+)
+
+TEST_SRCS(main.py)
+
+DEPENDS(library/cpp/string_utils/base64/bench)
+
+END()
diff --git a/library/cpp/string_utils/base64/bench/ya.make b/library/cpp/string_utils/base64/bench/ya.make
new file mode 100644
index 0000000000..5ac5f3d6ce
--- /dev/null
+++ b/library/cpp/string_utils/base64/bench/ya.make
@@ -0,0 +1,16 @@
+OWNER(
+ yazevnul
+ g:util
+)
+
+Y_BENCHMARK()
+
+SRCS(
+ main.cpp
+)
+
+PEERDIR(
+ library/cpp/string_utils/base64
+)
+
+END()
diff --git a/library/cpp/string_utils/base64/fuzz/generic/ya.make b/library/cpp/string_utils/base64/fuzz/generic/ya.make
new file mode 100644
index 0000000000..d155e2b0a0
--- /dev/null
+++ b/library/cpp/string_utils/base64/fuzz/generic/ya.make
@@ -0,0 +1,12 @@
+OWNER(
+ yazevnul
+ g:util
+)
+
+FUZZ()
+
+PEERDIR(
+ library/cpp/string_utils/base64/fuzz/lib
+)
+
+END()
diff --git a/library/cpp/string_utils/base64/fuzz/lib/main.cpp b/library/cpp/string_utils/base64/fuzz/lib/main.cpp
new file mode 100644
index 0000000000..28547ae7a5
--- /dev/null
+++ b/library/cpp/string_utils/base64/fuzz/lib/main.cpp
@@ -0,0 +1,13 @@
+#include <library/cpp/string_utils/base64/base64.h>
+
+#include <util/system/types.h>
+#include <util/system/yassert.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const ui8* data, size_t size) {
+ const TStringBuf example{reinterpret_cast<const char*>(data), size};
+ const auto converted = Base64Decode(Base64Encode(example));
+
+ Y_VERIFY(example == converted);
+
+ return 0;
+}
diff --git a/library/cpp/string_utils/base64/fuzz/lib/ya.make b/library/cpp/string_utils/base64/fuzz/lib/ya.make
new file mode 100644
index 0000000000..7b981b86a3
--- /dev/null
+++ b/library/cpp/string_utils/base64/fuzz/lib/ya.make
@@ -0,0 +1,16 @@
+OWNER(
+ yazevnul
+ g:util
+)
+
+LIBRARY()
+
+SRCS(
+ main.cpp
+)
+
+PEERDIR(
+ library/cpp/string_utils/base64
+)
+
+END()
diff --git a/library/cpp/string_utils/base64/fuzz/uneven/main.cpp b/library/cpp/string_utils/base64/fuzz/uneven/main.cpp
new file mode 100644
index 0000000000..915e81a7e5
--- /dev/null
+++ b/library/cpp/string_utils/base64/fuzz/uneven/main.cpp
@@ -0,0 +1,10 @@
+#include <library/cpp/string_utils/base64/base64.h>
+
+#include <util/system/types.h>
+#include <util/system/yassert.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const ui8* data, size_t size) {
+ const TStringBuf example{reinterpret_cast<const char*>(data), size};
+ Y_UNUSED(Base64DecodeUneven(example));
+ return 0;
+}
diff --git a/library/cpp/string_utils/base64/fuzz/uneven/ya.make b/library/cpp/string_utils/base64/fuzz/uneven/ya.make
new file mode 100644
index 0000000000..18cb18ef52
--- /dev/null
+++ b/library/cpp/string_utils/base64/fuzz/uneven/ya.make
@@ -0,0 +1,15 @@
+FUZZ()
+
+OWNER(
+ g:util
+)
+
+SRCS(
+ main.cpp
+)
+
+PEERDIR(
+ library/cpp/string_utils/base64
+)
+
+END()
diff --git a/library/cpp/string_utils/base64/fuzz/ya.make b/library/cpp/string_utils/base64/fuzz/ya.make
new file mode 100644
index 0000000000..bef82061c4
--- /dev/null
+++ b/library/cpp/string_utils/base64/fuzz/ya.make
@@ -0,0 +1,10 @@
+OWNER(
+ yazevnul
+ g:util
+)
+
+RECURSE(
+ generic
+ lib
+ uneven
+)
diff --git a/library/cpp/string_utils/base64/ut/ya.make b/library/cpp/string_utils/base64/ut/ya.make
new file mode 100644
index 0000000000..9b61241f0e
--- /dev/null
+++ b/library/cpp/string_utils/base64/ut/ya.make
@@ -0,0 +1,22 @@
+OWNER(
+ g:util
+ yazevnul
+)
+
+UNITTEST_FOR(library/cpp/string_utils/base64)
+
+SRCS(
+ base64_ut.cpp
+ base64_decode_uneven_ut.cpp
+)
+
+PEERDIR(
+ contrib/libs/base64/avx2
+ contrib/libs/base64/ssse3
+ contrib/libs/base64/neon32
+ contrib/libs/base64/neon64
+ contrib/libs/base64/plain32
+ contrib/libs/base64/plain64
+)
+
+END()
diff --git a/library/cpp/string_utils/base64/ya.make b/library/cpp/string_utils/base64/ya.make
new file mode 100644
index 0000000000..f5258c446c
--- /dev/null
+++ b/library/cpp/string_utils/base64/ya.make
@@ -0,0 +1,23 @@
+OWNER(
+ g:util
+ yazevnul
+)
+
+LIBRARY()
+
+SRCS(
+ base64.cpp
+)
+
+PEERDIR(
+ contrib/libs/base64/avx2
+ contrib/libs/base64/ssse3
+ contrib/libs/base64/neon32
+ contrib/libs/base64/neon64
+ contrib/libs/base64/plain32
+ contrib/libs/base64/plain64
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/string_utils/indent_text/indent_text.cpp b/library/cpp/string_utils/indent_text/indent_text.cpp
new file mode 100644
index 0000000000..09a4f6bca8
--- /dev/null
+++ b/library/cpp/string_utils/indent_text/indent_text.cpp
@@ -0,0 +1,25 @@
+#include "indent_text.h"
+
+#include <util/stream/str.h>
+
+TString IndentText(TStringBuf text, TStringBuf indent) {
+ if (text.empty())
+ return TString();
+
+ TStringStream ss;
+ ss.Reserve(text.size() + 20);
+
+ char pc = 0;
+ for (size_t i = 0; i < text.size(); ++i) {
+ if (i == 0 || pc == '\n')
+ ss << indent;
+
+ char c = text.at(i);
+ ss << c;
+ pc = c;
+ }
+ if (pc != '\n')
+ ss << '\n';
+
+ return ss.Str();
+}
diff --git a/library/cpp/string_utils/indent_text/indent_text.h b/library/cpp/string_utils/indent_text/indent_text.h
new file mode 100644
index 0000000000..7117d6c0ee
--- /dev/null
+++ b/library/cpp/string_utils/indent_text/indent_text.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/generic/strbuf.h>
+
+TString IndentText(TStringBuf text, TStringBuf indent = TStringBuf(" "));
diff --git a/library/cpp/string_utils/indent_text/ya.make b/library/cpp/string_utils/indent_text/ya.make
new file mode 100644
index 0000000000..cd0ed9ec61
--- /dev/null
+++ b/library/cpp/string_utils/indent_text/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(nga)
+
+SRCS(
+ indent_text.cpp
+)
+
+END()
diff --git a/library/cpp/string_utils/levenshtein_diff/levenshtein_diff.cpp b/library/cpp/string_utils/levenshtein_diff/levenshtein_diff.cpp
new file mode 100644
index 0000000000..8883d7df07
--- /dev/null
+++ b/library/cpp/string_utils/levenshtein_diff/levenshtein_diff.cpp
@@ -0,0 +1 @@
+#include "levenshtein_diff.h"
diff --git a/library/cpp/string_utils/levenshtein_diff/levenshtein_diff.h b/library/cpp/string_utils/levenshtein_diff/levenshtein_diff.h
new file mode 100644
index 0000000000..8a240bfed8
--- /dev/null
+++ b/library/cpp/string_utils/levenshtein_diff/levenshtein_diff.h
@@ -0,0 +1,192 @@
+#pragma once
+
+#include <util/draft/matrix.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/vector.h>
+#include <util/system/yassert.h>
+
+#include <type_traits>
+#include <utility>
+
+namespace NLevenshtein {
+ enum EEditMoveType {
+ EMT_SPECIAL,
+ EMT_PRESERVE,
+ EMT_REPLACE,
+ EMT_DELETE,
+ EMT_INSERT
+ };
+
+ inline bool IsImportantEditMove(EEditMoveType p) {
+ return (p != EMT_SPECIAL && p != EMT_PRESERVE);
+ }
+
+ inline void MakeMove(EEditMoveType t, int& p1, int& p2) {
+ switch (t) {
+ case EMT_PRESERVE:
+ case EMT_REPLACE:
+ p1++;
+ p2++;
+ break;
+ case EMT_DELETE:
+ p1++;
+ break;
+ case EMT_INSERT:
+ p2++;
+ break;
+ default:
+ break;
+ }
+ }
+
+ using TEditChain = TVector<EEditMoveType>;
+
+ template <typename TArgType>
+ struct TWeightOneUnaryGetter {
+ int operator()(const TArgType&) const {
+ return 1;
+ }
+ };
+
+ template <typename TArgType>
+ struct TWeightOneBinaryGetter {
+ int operator()(const TArgType&, const TArgType&) const {
+ return 1;
+ }
+ };
+
+ template <typename TStringType>
+ using TCharType = typename std::decay_t<decltype(std::add_const_t<TStringType>()[0])>;
+
+ /// Finds sequence of "edit moves" for two strings
+ template <class TStringType, class TWeightType = int,
+ class TReplaceWeigher = TWeightOneBinaryGetter<TCharType<TStringType>>,
+ class TDeleteWeigher = TWeightOneUnaryGetter<TCharType<TStringType>>,
+ class TInsertWeigher = TWeightOneUnaryGetter<TCharType<TStringType>>
+ >
+ void GetEditChain(const TStringType& str1, const TStringType& str2, TEditChain& res, TWeightType* weight = nullptr,
+ const TReplaceWeigher& replaceWeigher = TReplaceWeigher(),
+ const TDeleteWeigher& deleteWeigher = TDeleteWeigher(),
+ const TInsertWeigher& insertWeigher = TInsertWeigher())
+ {
+ int l1 = (int)str1.size();
+ int l2 = (int)str2.size();
+
+ TMatrix<std::pair<TWeightType, EEditMoveType>> ma(l1 + 1, l2 + 1); /// ma[i][j].first = diff(str1[0..i-1], str2[0..j-1])
+ ma[0][0] = std::make_pair(0, EMT_SPECIAL); // starting point
+ for (int i = 1; i <= l1; i++) {
+ ma[i][0] = std::make_pair(ma[i - 1][0].first + deleteWeigher(str1[i - 1]), EMT_DELETE);
+ }
+ for (int i = 1; i <= l2; i++) {
+ ma[0][i] = std::make_pair(ma[0][i - 1].first + insertWeigher(str2[i - 1]), EMT_INSERT);
+ }
+ // Here goes basic Levestein's algorithm
+ for (int i = 1; i <= l1; i++) {
+ for (int j = 1; j <= l2; j++) {
+ if (str1[i - 1] == str2[j - 1]) {
+ ma[i][j] = std::make_pair(ma[i - 1][j - 1].first, EMT_PRESERVE);
+ } else {
+ const TWeightType replaceWeight = replaceWeigher(str1[i - 1], str2[j - 1]);
+ Y_ASSERT(replaceWeight >= 0);
+ ma[i][j] = std::make_pair(ma[i - 1][j - 1].first + replaceWeight, EMT_REPLACE);
+ }
+
+ if (ma[i][j].first > ma[i - 1][j].first) {
+ const TWeightType deleteWeight = deleteWeigher(str1[i - 1]);
+ Y_ASSERT(deleteWeight >= 0);
+ const TWeightType deletePathWeight = ma[i - 1][j].first + deleteWeight;
+ if (deletePathWeight <= ma[i][j].first) {
+ ma[i][j] = std::make_pair(deletePathWeight, EMT_DELETE);
+ }
+ }
+
+ if (ma[i][j].first > ma[i][j - 1].first) {
+ const TWeightType insertWeight = insertWeigher(str2[j - 1]);
+ Y_ASSERT(insertWeight >= 0);
+ const TWeightType insertPathWeight = ma[i][j - 1].first + insertWeight;
+ if (insertPathWeight <= ma[i][j].first) {
+ ma[i][j] = std::make_pair(insertPathWeight, EMT_INSERT);
+ }
+ }
+ }
+ }
+ // Tracing the path from final point
+ res.clear();
+ res.reserve(Max<size_t>(l1, l2));
+ for (int i = l1, j = l2; ma[i][j].second != EMT_SPECIAL;) {
+ res.push_back(ma[i][j].second);
+ switch (ma[i][j].second) {
+ case EMT_PRESERVE:
+ case EMT_REPLACE:
+ --i;
+ --j;
+ break;
+ case EMT_DELETE:
+ --i;
+ break;
+ case EMT_INSERT:
+ --j;
+ break;
+ default:
+ // TODO: throw exception
+ break;
+ }
+ }
+ std::reverse(res.begin(), res.end());
+
+ if (weight != nullptr) {
+ *weight = ma[l1][l2].first;
+ }
+ }
+
+ template <class TStringType>
+ size_t Distance(const TStringType& str1, const TStringType& str2) {
+ TEditChain editChain;
+ GetEditChain(str1, str2, editChain);
+ size_t result = 0;
+ for (auto edit : editChain) {
+ if (IsImportantEditMove(edit))
+ result++;
+ }
+ return result;
+ }
+
+ /// Calculates substrings to be replaced for str1->str2 transformation
+ struct TReplacement {
+ int CorrectOffset, CorrectLength, MisspelledOffset, MisspelledLength;
+ TReplacement()
+ : CorrectOffset(0)
+ , CorrectLength(0)
+ , MisspelledOffset(0)
+ , MisspelledLength(0)
+ {
+ }
+ TReplacement(int correctOffset, int correctLength, int misspelledOffset, int misspelledLength)
+ : CorrectOffset(correctOffset)
+ , CorrectLength(correctLength)
+ , MisspelledOffset(misspelledOffset)
+ , MisspelledLength(misspelledLength)
+ {
+ }
+ };
+
+ template <class TStringType>
+ void GetStringReplacements(const TStringType& str1, const TStringType& str2, TVector<TReplacement>& res) {
+ TEditChain editChain;
+ GetEditChain(str1, str2, editChain);
+ editChain.push_back(EMT_SPECIAL);
+ int c1 = 0, c2 = 0;
+ res.clear();
+ for (TEditChain::const_iterator it = editChain.begin(); it != editChain.end(); it++) {
+ if (IsImportantEditMove(*it)) {
+ int sc1 = c1, sc2 = c2;
+ do {
+ MakeMove(*it, c1, c2);
+ ++it;
+ } while (IsImportantEditMove(*it));
+ res.push_back(TReplacement(sc1, c1 - sc1, sc2, c2 - sc2));
+ }
+ MakeMove(*it, c1, c2);
+ }
+ }
+}
diff --git a/library/cpp/string_utils/levenshtein_diff/levenshtein_diff_ut.cpp b/library/cpp/string_utils/levenshtein_diff/levenshtein_diff_ut.cpp
new file mode 100644
index 0000000000..cf0f78637f
--- /dev/null
+++ b/library/cpp/string_utils/levenshtein_diff/levenshtein_diff_ut.cpp
@@ -0,0 +1,190 @@
+#include "levenshtein_diff.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/string.h>
+
+namespace {
+
+ float unaryZeroWeigher(const char&) {
+ return 0.0f;
+ };
+
+ float unaryMaxWeigher(const char&) {
+ return 1.0f;
+ };
+
+ float binaryZeroWeigher(const char&, const char&) {
+ return 0.0f;
+ };
+
+ float binaryMaxWeigher(const char&, const char&) {
+ return 1.0f;
+ };
+
+}
+
+Y_UNIT_TEST_SUITE(Levenstein) {
+ Y_UNIT_TEST(Distance) {
+ UNIT_ASSERT_VALUES_EQUAL(NLevenshtein::Distance(TStringBuf("hello"), TStringBuf("hulloah")), 3);
+ UNIT_ASSERT_VALUES_EQUAL(NLevenshtein::Distance(TStringBuf("yeoman"), TStringBuf("yo man")), 2);
+ }
+}
+
+Y_UNIT_TEST_SUITE(WeightedLevenstein) {
+ Y_UNIT_TEST(EqualStrings) {
+ NLevenshtein::TEditChain chain;
+ float distance = 0.0f;
+ NLevenshtein::GetEditChain(TString("12345"), TString("12345"), chain, &distance, binaryMaxWeigher, unaryMaxWeigher, unaryMaxWeigher);
+ UNIT_ASSERT_VALUES_EQUAL(distance, 0.0f);
+ UNIT_ASSERT_VALUES_EQUAL(chain.size(), 5);
+ }
+
+ Y_UNIT_TEST(EmptyStrings) {
+ NLevenshtein::TEditChain chain;
+ float distance = 0.0f;
+ NLevenshtein::GetEditChain(TString(""), TString(""), chain, &distance, binaryMaxWeigher, unaryMaxWeigher, unaryMaxWeigher);
+ UNIT_ASSERT_VALUES_EQUAL(distance, 0.0f);
+ UNIT_ASSERT_VALUES_EQUAL(chain.size(), 0);
+ }
+
+ Y_UNIT_TEST(InsertsOnly) {
+ auto unaryWeigher = [](const char&) {
+ return 2.0f;
+ };
+ NLevenshtein::TEditChain chain;
+ float distance = 0.0f;
+ NLevenshtein::GetEditChain(TString(""), TString("12345"), chain, &distance, binaryZeroWeigher, unaryZeroWeigher, unaryWeigher);
+ UNIT_ASSERT_VALUES_EQUAL(distance, 10.0f);
+ UNIT_ASSERT_VALUES_EQUAL(chain.size(), 5);
+ }
+
+ Y_UNIT_TEST(DeletionsOnly) {
+ auto unaryWeigher = [](const char&) {
+ return 3.0f;
+ };
+ NLevenshtein::TEditChain chain;
+ float distance = 0.0f;
+ NLevenshtein::GetEditChain(TString("54321"), TString(""), chain, &distance, binaryZeroWeigher, unaryWeigher, unaryZeroWeigher);
+ UNIT_ASSERT_VALUES_EQUAL(distance, 15.0f);
+ UNIT_ASSERT_VALUES_EQUAL(chain.size(), 5);
+ }
+
+ Y_UNIT_TEST(SymmetryCheck) {
+ const TString str1 = "123x5";
+ const TString str2 = "x2345";
+ const float trgDistance = 2.0f;
+ const size_t trgChainLen = 5;
+
+ NLevenshtein::TEditChain chainLeftRight;
+ float distanceLeftRight = 0.0f;
+ NLevenshtein::GetEditChain(str1, str2, chainLeftRight, &distanceLeftRight, binaryMaxWeigher, unaryMaxWeigher, unaryMaxWeigher);
+ UNIT_ASSERT_VALUES_EQUAL(distanceLeftRight, trgDistance);
+ UNIT_ASSERT_VALUES_EQUAL(chainLeftRight.size(), trgChainLen);
+ UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(chainLeftRight[0]), static_cast<int>(NLevenshtein::EMT_REPLACE));
+ UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(chainLeftRight[1]), static_cast<int>(NLevenshtein::EMT_PRESERVE));
+ UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(chainLeftRight[2]), static_cast<int>(NLevenshtein::EMT_PRESERVE));
+ UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(chainLeftRight[3]), static_cast<int>(NLevenshtein::EMT_REPLACE));
+ UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(chainLeftRight[4]), static_cast<int>(NLevenshtein::EMT_PRESERVE));
+
+ NLevenshtein::TEditChain chainRightLeft;
+ float distanceRightLeft = 0.0f;
+ NLevenshtein::GetEditChain(str2, str1, chainRightLeft, &distanceRightLeft, binaryMaxWeigher, unaryMaxWeigher, unaryMaxWeigher);
+ UNIT_ASSERT_VALUES_EQUAL(distanceRightLeft, trgDistance);
+ UNIT_ASSERT_VALUES_EQUAL(chainRightLeft.size(), trgChainLen);
+ UNIT_ASSERT(chainRightLeft == chainLeftRight);
+ }
+
+ Y_UNIT_TEST(PreferReplacements) {
+ auto binaryWeigher = [](const char&, const char&) {
+ return 0.0625f;
+ };
+ NLevenshtein::TEditChain chain;
+ float distance = 0.0f;
+ NLevenshtein::GetEditChain(TString("54321"), TString("43210"), chain, &distance, binaryWeigher, unaryMaxWeigher, unaryMaxWeigher);
+ UNIT_ASSERT_VALUES_EQUAL(distance, 0.3125f);
+ UNIT_ASSERT_VALUES_EQUAL(chain.size(), 5);
+ }
+
+ Y_UNIT_TEST(PreferInsertDeletions) {
+ auto unaryWeigher = [](const char&) {
+ return 0.0625f;
+ };
+ NLevenshtein::TEditChain chain;
+ float distance = 0.0f;
+ NLevenshtein::GetEditChain(TString("54321"), TString("98765"), chain, &distance, binaryMaxWeigher, unaryWeigher, unaryWeigher);
+ UNIT_ASSERT_VALUES_EQUAL(distance, 0.5f);
+ UNIT_ASSERT_VALUES_EQUAL(chain.size(), 9);
+ }
+
+ Y_UNIT_TEST(NoXDeletions) {
+ auto unaryWeigher = [](const char& c) {
+ return c == 'x' ? 100.0f : 1.0f;
+ };
+ NLevenshtein::TEditChain chain;
+ float distance = 0.0f;
+ NLevenshtein::GetEditChain(TString("543x1"), TString("5431"), chain, &distance, binaryMaxWeigher, unaryWeigher, unaryMaxWeigher);
+ UNIT_ASSERT_VALUES_EQUAL(chain.size(), 5);
+ UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(chain[3]), static_cast<int>(NLevenshtein::EMT_REPLACE));
+ UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(chain[4]), static_cast<int>(NLevenshtein::EMT_DELETE));
+ UNIT_ASSERT_VALUES_EQUAL(distance, 2.0f);
+ }
+
+ Y_UNIT_TEST(NoXInsertions) {
+ auto unaryWeigher = [](const char& c) {
+ return c == 'x' ? 100.0f : 1.0f;
+ };
+ NLevenshtein::TEditChain chain;
+ float distance = 0.0f;
+ NLevenshtein::GetEditChain(TString("5431"), TString("543x1"), chain, &distance, binaryMaxWeigher, unaryMaxWeigher, unaryWeigher);
+ UNIT_ASSERT_VALUES_EQUAL(chain.size(), 5);
+ UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(chain[3]), static_cast<int>(NLevenshtein::EMT_REPLACE));
+ UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(chain[4]), static_cast<int>(NLevenshtein::EMT_INSERT));
+ UNIT_ASSERT_VALUES_EQUAL(distance, 2.0f);
+ }
+
+ Y_UNIT_TEST(NoReplacementsOfX) {
+ auto binaryWeigher = [](const char& l, const char&) {
+ return l == 'x' ? 100.0f : 1.0f;
+ };
+ NLevenshtein::TEditChain chain;
+ float distance = 0.0f;
+ NLevenshtein::GetEditChain(TString("5432x"), TString("5432y"), chain, &distance, binaryWeigher, unaryMaxWeigher, unaryMaxWeigher);
+ UNIT_ASSERT_VALUES_EQUAL(chain.size(), 6);
+ UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(chain[4]), static_cast<int>(NLevenshtein::EMT_DELETE));
+ UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(chain[5]), static_cast<int>(NLevenshtein::EMT_INSERT));
+ UNIT_ASSERT_VALUES_EQUAL(distance, 2.0f);
+ }
+
+ Y_UNIT_TEST(NoReplacementsForX) {
+ auto binaryWeigher = [](const char&, const char& r) {
+ return r == 'x' ? 100.0f : 1.0f;
+ };
+ NLevenshtein::TEditChain chain;
+ float distance = 0.0f;
+ NLevenshtein::GetEditChain(TString("y4321"), TString("x4321"), chain, &distance, binaryWeigher, unaryMaxWeigher, unaryMaxWeigher);
+ UNIT_ASSERT_VALUES_EQUAL(chain.size(), 6);
+ UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(chain[0]), static_cast<int>(NLevenshtein::EMT_DELETE));
+ UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(chain[1]), static_cast<int>(NLevenshtein::EMT_INSERT));
+ UNIT_ASSERT_VALUES_EQUAL(distance, 2.0f);
+ }
+
+ Y_UNIT_TEST(SimilarOperationPriorities) {
+ auto replaceWeigher = [](const char&, const char&) {
+ return 0.5f;
+ };
+ auto deleteWeigher = [](const char&) {
+ return 0.2f;
+ };
+ auto insertWeigher = [](const char&) {
+ return 0.9f;
+ };
+ NLevenshtein::TEditChain chain;
+ float distance = 0.0f;
+ NLevenshtein::GetEditChain(TString("y0"), TString("0x"), chain, &distance, replaceWeigher, deleteWeigher, insertWeigher);
+ UNIT_ASSERT_VALUES_EQUAL(chain.size(), 2);
+ UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(chain[0]), static_cast<int>(NLevenshtein::EMT_REPLACE));
+ UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(chain[1]), static_cast<int>(NLevenshtein::EMT_REPLACE));
+ UNIT_ASSERT_VALUES_EQUAL(distance, 1.0f);
+ }
+}
diff --git a/library/cpp/string_utils/levenshtein_diff/ut/ya.make b/library/cpp/string_utils/levenshtein_diff/ut/ya.make
new file mode 100644
index 0000000000..a3b9b8fea5
--- /dev/null
+++ b/library/cpp/string_utils/levenshtein_diff/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/string_utils/levenshtein_diff)
+
+OWNER(myltsev)
+
+SRCS(
+ levenshtein_diff_ut.cpp
+)
+
+END()
diff --git a/library/cpp/string_utils/levenshtein_diff/ya.make b/library/cpp/string_utils/levenshtein_diff/ya.make
new file mode 100644
index 0000000000..bafefe5365
--- /dev/null
+++ b/library/cpp/string_utils/levenshtein_diff/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(g:mt)
+
+SRCS(
+ levenshtein_diff.cpp
+)
+
+PEERDIR(
+ util/draft
+)
+
+END()
diff --git a/library/cpp/string_utils/parse_size/parse_size.cpp b/library/cpp/string_utils/parse_size/parse_size.cpp
new file mode 100644
index 0000000000..39188d560b
--- /dev/null
+++ b/library/cpp/string_utils/parse_size/parse_size.cpp
@@ -0,0 +1,95 @@
+#include "parse_size.h"
+
+#include <util/generic/yexception.h>
+#include <util/generic/ylimits.h>
+#include <util/string/cast.h>
+#include <util/stream/output.h>
+
+namespace {
+ enum ESuffixShifts {
+ ESS_KILO_BYTES = 10,
+ ESS_MEGA_BYTES = 20,
+ ESS_GIGA_BYTES = 30,
+ ESS_TERA_BYTES = 40,
+ };
+
+ bool TryShiftValue(ui64& value, ui64 shift) {
+ if (value > (Max<ui64>() >> shift)) {
+ return false;
+ }
+
+ value <<= shift;
+ return true;
+ }
+
+ ui64 ShiftValue(ui64 value, ui64 shift) {
+ if (!TryShiftValue(value, shift)) {
+ ythrow yexception() << "value overflow '" << value << " << " << shift << "'";
+ } else {
+ return value;
+ }
+ }
+
+}
+
+namespace NSize {
+ ui64 ParseSize(TStringBuf str) {
+ if (! str.size())
+ ythrow yexception() << "Wrong size " << str;
+ char suff = tolower(str[str.size() - 1]);
+ if (isdigit(suff))
+ return FromString<ui64>(str);
+ ui64 shift = 1;
+ switch (suff) {
+ case 'k':
+ shift = ESS_KILO_BYTES;
+ break;
+ case 'm':
+ shift = ESS_MEGA_BYTES;
+ break;
+ case 'g':
+ shift = ESS_GIGA_BYTES;
+ break;
+ case 't':
+ shift = ESS_TERA_BYTES;
+ break;
+ default:
+ ythrow yexception() << "Unknown suffix " << str;
+ }
+
+ ui64 value = FromString<ui64>(str.substr(0, str.size() - 1));
+
+ if (!TryShiftValue(value, shift)) {
+ ythrow yexception() << "Value overflow " << str;
+ } else {
+ return value;
+ }
+ }
+
+ TSize FromKiloBytes(ui64 value) {
+ return TSize(ShiftValue(value, ESS_KILO_BYTES));
+ }
+
+ TSize FromMegaBytes(ui64 value) {
+ return TSize(ShiftValue(value, ESS_MEGA_BYTES));
+ }
+
+ TSize FromGigaBytes(ui64 value) {
+ return TSize(ShiftValue(value, ESS_GIGA_BYTES));
+ }
+
+ TSize FromTeraBytes(ui64 value) {
+ return TSize(ShiftValue(value, ESS_TERA_BYTES));
+ }
+
+}
+
+template <>
+NSize::TSize FromStringImpl<NSize::TSize>(const char* data, size_t len) {
+ return NSize::TSize(NSize::ParseSize(TStringBuf(data, len)));
+}
+
+template <>
+void Out<NSize::TSize>(IOutputStream& os, const NSize::TSize& size) {
+ os << size.GetValue();
+}
diff --git a/library/cpp/string_utils/parse_size/parse_size.h b/library/cpp/string_utils/parse_size/parse_size.h
new file mode 100644
index 0000000000..ad235ef02f
--- /dev/null
+++ b/library/cpp/string_utils/parse_size/parse_size.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+namespace NSize {
+ ui64 ParseSize(TStringBuf size);
+
+ // Convenient disk size representation with string parsing and integer comparison
+ class TSize {
+ public:
+ TSize(ui64 value = 0)
+ : Value(value)
+ {
+ }
+
+ ui64 GetValue() const {
+ return Value;
+ }
+
+ operator ui64() const {
+ return Value;
+ }
+
+ private:
+ ui64 Value;
+ };
+
+ TSize FromKiloBytes(ui64 value);
+ TSize FromMegaBytes(ui64 value);
+ TSize FromGigaBytes(ui64 value);
+ TSize FromTeraBytes(ui64 value);
+
+}
diff --git a/library/cpp/string_utils/parse_size/parse_size_ut.cpp b/library/cpp/string_utils/parse_size/parse_size_ut.cpp
new file mode 100644
index 0000000000..8fff4f56b2
--- /dev/null
+++ b/library/cpp/string_utils/parse_size/parse_size_ut.cpp
@@ -0,0 +1,63 @@
+#include "parse_size.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NSize;
+
+class TParseSizeTest: public TTestBase {
+ UNIT_TEST_SUITE(TParseSizeTest);
+
+ UNIT_TEST(TestPlain);
+ UNIT_TEST(TestKiloBytes);
+ UNIT_TEST(TestMegaBytes);
+ UNIT_TEST(TestGigaBytes);
+ UNIT_TEST(TestTeraBytes);
+ UNIT_TEST(TestOverflow);
+ UNIT_TEST(TestStaticCreators);
+ UNIT_TEST(TestToString);
+
+ UNIT_TEST_SUITE_END();
+
+private:
+ void TestPlain() {
+ UNIT_ASSERT(ParseSize("1024") == 1024);
+ }
+
+ void TestKiloBytes() {
+ UNIT_ASSERT(ParseSize("10K") == 1024 * 10);
+ UNIT_ASSERT(ParseSize("10k") == 1024 * 10);
+ }
+
+ void TestMegaBytes() {
+ UNIT_ASSERT(ParseSize("10M") == 1024 * 1024 * 10);
+ UNIT_ASSERT(ParseSize("10m") == 1024 * 1024 * 10);
+ }
+
+ void TestGigaBytes() {
+ UNIT_ASSERT(ParseSize("10G") == 1024ul * 1024ul * 1024ul * 10ul);
+ UNIT_ASSERT(ParseSize("10g") == 1024ul * 1024ul * 1024ul * 10ul);
+ }
+
+ void TestTeraBytes() {
+ UNIT_ASSERT(ParseSize("10T") == 1024ul * 1024ul * 1024ul * 1024ul * 10ul);
+ UNIT_ASSERT(ParseSize("10t") == 1024ul * 1024ul * 1024ul * 1024ul * 10ul);
+ }
+
+ void TestStaticCreators() {
+ UNIT_ASSERT_EQUAL(FromKiloBytes(10), 1024ul * 10ul);
+ UNIT_ASSERT_EQUAL(FromMegaBytes(10), 1024ul * 1024ul * 10ul);
+ UNIT_ASSERT_EQUAL(FromGigaBytes(10), 1024ul * 1024ul * 1024ul * 10ul);
+ UNIT_ASSERT_EQUAL(FromTeraBytes(10), 1024ul * 1024ul * 1024ul * 1024ul * 10ul);
+ }
+
+ void TestOverflow() {
+ UNIT_ASSERT_EXCEPTION(ParseSize("20000000000G"), yexception);
+ UNIT_ASSERT_EXCEPTION(FromGigaBytes(20000000000ull), yexception);
+ }
+
+ void TestToString() {
+ UNIT_ASSERT_VALUES_EQUAL(ToString(FromKiloBytes(1)), TString("1024"));
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TParseSizeTest);
diff --git a/library/cpp/string_utils/parse_size/ut/ya.make b/library/cpp/string_utils/parse_size/ut/ya.make
new file mode 100644
index 0000000000..da19cf025b
--- /dev/null
+++ b/library/cpp/string_utils/parse_size/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/string_utils/parse_size)
+
+OWNER(g:images-robot)
+
+SRCS(
+ parse_size_ut.cpp
+)
+
+END()
diff --git a/library/cpp/string_utils/parse_size/ya.make b/library/cpp/string_utils/parse_size/ya.make
new file mode 100644
index 0000000000..4a62abcac2
--- /dev/null
+++ b/library/cpp/string_utils/parse_size/ya.make
@@ -0,0 +1,10 @@
+LIBRARY()
+
+OWNER(g:images-robot)
+
+SRCS(
+ parse_size.cpp
+ parse_size.h
+)
+
+END()
diff --git a/library/cpp/string_utils/quote/quote.cpp b/library/cpp/string_utils/quote/quote.cpp
new file mode 100644
index 0000000000..e523350b80
--- /dev/null
+++ b/library/cpp/string_utils/quote/quote.cpp
@@ -0,0 +1,311 @@
+#include "quote.h"
+
+#include <util/memory/tempbuf.h>
+#include <util/string/ascii.h>
+#include <util/string/cstriter.h>
+
+#include <cctype>
+
+/* note: (x & 0xdf) makes x upper case */
+#define GETXC \
+ do { \
+ c *= 16; \
+ c += (x[0] >= 'A' ? ((x[0] & 0xdf) - 'A') + 10 : (x[0] - '0')); \
+ ++x; \
+ } while (0)
+
+#define GETSBXC \
+ do { \
+ c *= 16; \
+ c += (x[0] >= 'A' ? ((x[0] & 0xdf) - 'A') + 10 : (x[0] - '0')); \
+ x.Skip(1); \
+ } while (0)
+
+
+namespace {
+ class TFromHexZeroTerm {
+ public:
+ static inline char x2c(const char*& x) {
+ if (!IsAsciiHex((ui8)x[0]) || !IsAsciiHex((ui8)x[1]))
+ return '%';
+ ui8 c = 0;
+
+ GETXC;
+ GETXC;
+ return c;
+ }
+
+ static inline char x2c(TStringBuf& x) {
+ if (!IsAsciiHex((ui8)x[0]) || !IsAsciiHex((ui8)x[1]))
+ return '%';
+ ui8 c = 0;
+
+ GETSBXC;
+ GETSBXC;
+ return c;
+ }
+ };
+
+ class TFromHexLenLimited {
+ public:
+ TFromHexLenLimited(const char* end)
+ : End(end)
+ {
+ }
+
+ inline char x2c(const char*& x) {
+ if (x + 2 > End)
+ return '%';
+ return TFromHexZeroTerm::x2c(x);
+ }
+
+ private:
+ const char* End;
+ };
+}
+
+static inline char d2x(unsigned x) {
+ return (char)((x < 10) ? ('0' + x) : ('A' + x - 10));
+}
+
+static inline const char* FixZero(const char* s) noexcept {
+ return s ? s : "";
+}
+
+// we escape:
+// '\"', '|', '(', ')',
+// '%', '&', '+', ',',
+// '#', '<', '=', '>',
+// '[', '\\',']', '?',
+// ':', '{', '}',
+// all below ' ' (0x20) and above '~' (0x7E).
+// ' ' converted to '+'
+static const bool chars_to_url_escape[256] = {
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //1
+ 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, //2
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, //3
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //4
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, //5
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //6
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, //7
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //8
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //9
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //A
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //B
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //C
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //D
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //E
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //F
+};
+
+template <class It1, class It2, class It3>
+static inline It1 Escape(It1 to, It2 from, It3 end, const bool* escape_map = chars_to_url_escape) {
+ while (from != end) {
+ if (escape_map[(unsigned char)*from]) {
+ *to++ = '%';
+ *to++ = d2x((unsigned char)*from >> 4);
+ *to++ = d2x((unsigned char)*from & 0xF);
+ } else {
+ *to++ = (*from == ' ' ? '+' : *from);
+ }
+
+ ++from;
+ }
+
+ *to = 0;
+
+ return to;
+}
+
+template <class It1, class It2, class It3, class FromHex>
+static inline It1 Unescape(It1 to, It2 from, It3 end, FromHex fromHex) {
+ (void)fromHex;
+
+ while (from != end) {
+ switch (*from) {
+ case '%':
+ ++from;
+ *to++ = fromHex.x2c(from);
+ break;
+ case '+':
+ *to++ = ' ';
+ ++from;
+ break;
+ default:
+ *to++ = *from++;
+ }
+ }
+ *to = 0;
+ return to;
+}
+
+// CGIEscape returns pointer to the end of the result string
+// so as it could be possible to populate single long buffer
+// with several calls to CGIEscape in a row.
+char* CGIEscape(char* to, const char* from) {
+ return Escape(to, FixZero(from), TCStringEndIterator());
+}
+
+char* CGIEscape(char* to, const char* from, size_t len) {
+ return Escape(to, from, from + len);
+}
+
+void CGIEscape(TString& url) {
+ TTempBuf tempBuf(CgiEscapeBufLen(url.size()));
+ char* to = tempBuf.Data();
+
+ url.AssignNoAlias(to, CGIEscape(to, url.data(), url.size()));
+}
+
+TString CGIEscapeRet(const TStringBuf url) {
+ TString to;
+ to.ReserveAndResize(CgiEscapeBufLen(url.size()));
+ to.resize(CGIEscape(to.begin(), url.data(), url.size()) - to.data());
+ return to;
+}
+
+TString& AppendCgiEscaped(const TStringBuf value, TString& to) {
+ const size_t origLength = to.length();
+ to.ReserveAndResize(origLength + CgiEscapeBufLen(value.size()));
+ to.resize(CGIEscape(to.begin() + origLength, value.data(), value.size()) - to.data());
+ return to;
+}
+
+// More general version of CGIEscape. The optional safe parameter specifies
+// additional characters that should not be quoted — its default value is '/'.
+
+// Also returns pointer to the end of result string.
+
+template <class It1, class It2, class It3>
+static inline It1 Quote(It1 to, It2 from, It3 end, const char* safe) {
+ bool escape_map[256];
+ memcpy(escape_map, chars_to_url_escape, 256);
+ // RFC 3986 Uniform Resource Identifiers (URI): Generic Syntax
+ // lists following reserved characters:
+ const char* reserved = ":/?#[]@!$&\'()*+,;=";
+ for (const char* p = reserved; *p; ++p) {
+ escape_map[(unsigned char)*p] = 1;
+ }
+ // characters we think are safe at the moment
+ for (const char* p = safe; *p; ++p) {
+ escape_map[(unsigned char)*p] = 0;
+ }
+
+ return Escape(to, from, end, escape_map);
+}
+
+char* Quote(char* to, const char* from, const char* safe) {
+ return Quote(to, FixZero(from), TCStringEndIterator(), safe);
+}
+
+char* Quote(char* to, const TStringBuf s, const char* safe) {
+ return Quote(to, s.data(), s.data() + s.size(), safe);
+}
+
+void Quote(TString& url, const char* safe) {
+ TTempBuf tempBuf(CgiEscapeBufLen(url.size()));
+ char* to = tempBuf.Data();
+
+ url.AssignNoAlias(to, Quote(to, url, safe));
+}
+
+char* CGIUnescape(char* to, const char* from) {
+ return Unescape(to, FixZero(from), TCStringEndIterator(), TFromHexZeroTerm());
+}
+
+char* CGIUnescape(char* to, const char* from, size_t len) {
+ return Unescape(to, from, from + len, TFromHexLenLimited(from + len));
+}
+
+void CGIUnescape(TString& url) {
+ if (url.empty()) {
+ return;
+ }
+ if (url.IsDetached()) { // in-place when refcount == 1
+ char* resBegin = url.begin();
+ const char* resEnd = CGIUnescape(resBegin, resBegin, url.size());
+ url.resize(resEnd - resBegin);
+ } else {
+ url = CGIUnescapeRet(url);
+ }
+}
+
+TString CGIUnescapeRet(const TStringBuf from) {
+ TString to;
+ to.ReserveAndResize(CgiUnescapeBufLen(from.size()));
+ to.resize(CGIUnescape(to.begin(), from.data(), from.size()) - to.data());
+ return to;
+}
+
+char* UrlUnescape(char* to, TStringBuf from) {
+ while (!from.empty()) {
+ char ch = from[0];
+ from.Skip(1);
+ if ('%' == ch && 2 <= from.length())
+ ch = TFromHexZeroTerm::x2c(from);
+ *to++ = ch;
+ }
+
+ *to = 0;
+
+ return to;
+}
+
+void UrlUnescape(TString& url) {
+ if (url.empty()) {
+ return;
+ }
+ if (url.IsDetached()) { // in-place when refcount == 1
+ char* resBegin = url.begin();
+ const char* resEnd = UrlUnescape(resBegin, url);
+ url.resize(resEnd - resBegin);
+ } else {
+ url = UrlUnescapeRet(url);
+ }
+}
+
+TString UrlUnescapeRet(const TStringBuf from) {
+ TString to;
+ to.ReserveAndResize(CgiUnescapeBufLen(from.size()));
+ to.resize(UrlUnescape(to.begin(), from) - to.data());
+ return to;
+}
+
+char* UrlEscape(char* to, const char* from, bool forceEscape) {
+ from = FixZero(from);
+
+ while (*from) {
+ const bool escapePercent = (*from == '%') &&
+ (forceEscape || !((*(from + 1) && IsAsciiHex(*(from + 1)) && *(from + 2) && IsAsciiHex(*(from + 2)))));
+
+ if (escapePercent || (unsigned char)*from <= ' ' || (unsigned char)*from > '~') {
+ *to++ = '%';
+ *to++ = d2x((unsigned char)*from >> 4);
+ *to++ = d2x((unsigned char)*from & 0xF);
+ } else
+ *to++ = *from;
+ ++from;
+ }
+
+ *to = 0;
+
+ return to;
+}
+
+void UrlEscape(TString& url, bool forceEscape) {
+ TTempBuf tempBuf(CgiEscapeBufLen(url.size()));
+ char* to = tempBuf.Data();
+ url.AssignNoAlias(to, UrlEscape(to, url.data(), forceEscape));
+}
+
+TString UrlEscapeRet(const TStringBuf from, bool forceEscape) {
+ TString to;
+ to.ReserveAndResize(CgiEscapeBufLen(from.size()));
+ to.resize(UrlEscape(to.begin(), from.begin(), forceEscape) - to.data());
+ return to;
+}
diff --git a/library/cpp/string_utils/quote/quote.h b/library/cpp/string_utils/quote/quote.h
new file mode 100644
index 0000000000..3b7221154e
--- /dev/null
+++ b/library/cpp/string_utils/quote/quote.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+
+//CGIEscape*:
+// ' ' converted to '+',
+// Some punctuation and chars outside [32, 126] range are converted to %xx
+// Use function CgiEscapeBufLen to determine number of characters needed for 'char* to' parameter.
+// Returns pointer to the end of the result string
+char* CGIEscape(char* to, const char* from);
+char* CGIEscape(char* to, const char* from, size_t len);
+inline char* CGIEscape(char* to, const TStringBuf from) {
+ return CGIEscape(to, from.data(), from.size());
+}
+void CGIEscape(TString& url);
+TString CGIEscapeRet(const TStringBuf url);
+TString& AppendCgiEscaped(const TStringBuf value, TString& to);
+
+inline TStringBuf CgiEscapeBuf(char* to, const TStringBuf from) {
+ return TStringBuf(to, CGIEscape(to, from.data(), from.size()));
+}
+inline TStringBuf CgiEscape(void* tmp, const TStringBuf s) {
+ return CgiEscapeBuf(static_cast<char*>(tmp), s);
+}
+
+//CgiUnescape*:
+// Decodes '%xx' to bytes, '+' to space.
+// Use function CgiUnescapeBufLen to determine number of characters needed for 'char* to' parameter.
+// If pointer returned, then this is pointer to the end of the result string.
+char* CGIUnescape(char* to, const char* from);
+char* CGIUnescape(char* to, const char* from, size_t len);
+void CGIUnescape(TString& url);
+TString CGIUnescapeRet(const TStringBuf from);
+
+inline TStringBuf CgiUnescapeBuf(char* to, const TStringBuf from) {
+ return TStringBuf(to, CGIUnescape(to, from.data(), from.size()));
+}
+inline TStringBuf CgiUnescape(void* tmp, const TStringBuf s) {
+ return CgiUnescapeBuf(static_cast<char*>(tmp), s);
+}
+
+//Quote:
+// Is like CGIEscape, also skips encoding of user-supplied 'safe' characters.
+char* Quote(char* to, const char* from, const char* safe = "/");
+char* Quote(char* to, const TStringBuf s, const char* safe = "/");
+void Quote(TString& url, const char* safe = "/");
+
+//UrlEscape:
+// Can't be used for cgi parameters ('&' character is not escaped)!
+// escapes only '%' not followed by two hex-digits or if forceEscape set to ture,
+// and chars outside [32, 126] range.
+// Can't handle '\0'-chars in TString.
+char* UrlEscape(char* to, const char* from, bool forceEscape = false);
+void UrlEscape(TString& url, bool forceEscape = false);
+TString UrlEscapeRet(const TStringBuf from, bool forceEscape = false);
+
+//UrlUnescape:
+// '+' is NOT converted to space!
+// %xx converted to bytes, other characters are copied unchanged.
+char* UrlUnescape(char* to, TStringBuf from);
+void UrlUnescape(TString& url);
+TString UrlUnescapeRet(const TStringBuf from);
+
+//*BufLen: how much characters you should allocate for 'char* to' buffers.
+constexpr size_t CgiEscapeBufLen(const size_t len) noexcept {
+ return 3 * len + 1;
+}
+
+constexpr size_t CgiUnescapeBufLen(const size_t len) noexcept {
+ return len + 1;
+}
diff --git a/library/cpp/string_utils/quote/quote_ut.cpp b/library/cpp/string_utils/quote/quote_ut.cpp
new file mode 100644
index 0000000000..6c552b279e
--- /dev/null
+++ b/library/cpp/string_utils/quote/quote_ut.cpp
@@ -0,0 +1,319 @@
+#include "quote.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TCGIEscapeTest) {
+ Y_UNIT_TEST(ReturnsEndOfTo) {
+ char r[10];
+ const char* returned = CGIEscape(r, "123");
+ UNIT_ASSERT_VALUES_EQUAL(r + strlen("123"), returned);
+ UNIT_ASSERT_VALUES_EQUAL('\0', *returned);
+ }
+
+ Y_UNIT_TEST(NotZeroTerminated) {
+ char r[] = {'1', '2', '3', '4'};
+ char buf[sizeof(r) * 3 + 2];
+
+ TString ret(buf, CGIEscape(buf, r, sizeof(r)));
+
+ UNIT_ASSERT_EQUAL(ret, "1234");
+ }
+
+ Y_UNIT_TEST(StringBuf) {
+ char tmp[100];
+
+ UNIT_ASSERT_VALUES_EQUAL(CgiEscape(tmp, "!@#$%^&*(){}[]\" "), TStringBuf("!@%23$%25^%26*%28%29%7B%7D%5B%5D%22+"));
+ }
+
+ Y_UNIT_TEST(StrokaRet) {
+ UNIT_ASSERT_VALUES_EQUAL(CGIEscapeRet("!@#$%^&*(){}[]\" "), TString("!@%23$%25^%26*%28%29%7B%7D%5B%5D%22+"));
+ }
+
+ Y_UNIT_TEST(StrokaAppendRet) {
+ TString param;
+ AppendCgiEscaped("!@#$%^&*(){}[]\" ", param);
+ UNIT_ASSERT_VALUES_EQUAL(param, TString("!@%23$%25^%26*%28%29%7B%7D%5B%5D%22+"));
+
+ TString param2 = "&param=";
+ AppendCgiEscaped("!@#$%^&*(){}[]\" ", param2);
+ UNIT_ASSERT_VALUES_EQUAL(param2,
+ TString("&param=!@%23$%25^%26*%28%29%7B%7D%5B%5D%22+"));
+
+ param2.append("&param_param=");
+ AppendCgiEscaped("!@#$%^&*(){}[]\" ", param2);
+ UNIT_ASSERT_VALUES_EQUAL(param2,
+ TString("&param=!@%23$%25^%26*%28%29%7B%7D%5B%5D%22+&param_param=!@%23$%25^%26*%28%29%7B%7D%5B%5D%22+"));
+ }
+
+}
+
+Y_UNIT_TEST_SUITE(TCGIUnescapeTest) {
+ Y_UNIT_TEST(StringBuf) {
+ char tmp[100];
+
+ UNIT_ASSERT_VALUES_EQUAL(CgiUnescape(tmp, "!@%23$%25^%26*%28%29"), TStringBuf("!@#$%^&*()"));
+ }
+
+ Y_UNIT_TEST(TestValidZeroTerm) {
+ char r[10];
+
+ CGIUnescape(r, "1234");
+ UNIT_ASSERT_VALUES_EQUAL(r, "1234");
+
+ CGIUnescape(r, "%3d");
+ UNIT_ASSERT_VALUES_EQUAL(r, "=");
+
+ CGIUnescape(r, "12%3D34");
+ UNIT_ASSERT_VALUES_EQUAL(r, "12=34");
+ }
+
+ Y_UNIT_TEST(TestInvalidZeroTerm) {
+ char r[10];
+
+ CGIUnescape(r, "%");
+ UNIT_ASSERT_VALUES_EQUAL(r, "%");
+
+ CGIUnescape(r, "%3");
+ UNIT_ASSERT_VALUES_EQUAL(r, "%3");
+
+ CGIUnescape(r, "%3g");
+ UNIT_ASSERT_VALUES_EQUAL(r, "%3g");
+
+ CGIUnescape(r, "12%3g34");
+ UNIT_ASSERT_VALUES_EQUAL(r, "12%3g34");
+
+ CGIUnescape(r, "%3u123");
+ UNIT_ASSERT_VALUES_EQUAL(r, "%3u123");
+ }
+
+ Y_UNIT_TEST(TestValidNotZeroTerm) {
+ char r[10];
+
+ CGIUnescape(r, "123456789", 4);
+ UNIT_ASSERT_VALUES_EQUAL(r, "1234");
+
+ CGIUnescape(r, "%3d1234", 3);
+ UNIT_ASSERT_VALUES_EQUAL(r, "=");
+
+ CGIUnescape(r, "12%3D345678", 7);
+ UNIT_ASSERT_VALUES_EQUAL(r, "12=34");
+ }
+
+ Y_UNIT_TEST(TestInvalidNotZeroTerm) {
+ char r[10];
+
+ CGIUnescape(r, "%3d", 1);
+ UNIT_ASSERT_VALUES_EQUAL(r, "%");
+
+ CGIUnescape(r, "%3d", 2);
+ UNIT_ASSERT_VALUES_EQUAL(r, "%3");
+
+ CGIUnescape(r, "%3g1234", 3);
+ UNIT_ASSERT_VALUES_EQUAL(r, "%3g");
+
+ CGIUnescape(r, "12%3g345678", 7);
+ UNIT_ASSERT_VALUES_EQUAL(r, "12%3g34");
+
+ CGIUnescape(r, "%3u1234", 2);
+ UNIT_ASSERT_VALUES_EQUAL(r, "%3");
+
+ CGIUnescape(r, "%3u1234", 3);
+ UNIT_ASSERT_VALUES_EQUAL(r, "%3u");
+
+ CGIUnescape(r, "%3u1234", 4);
+ UNIT_ASSERT_VALUES_EQUAL(r, "%3u1");
+ }
+
+ Y_UNIT_TEST(StrokaOutParameterInplace) {
+ TString s;
+
+ s = "hello%3dworld";
+ CGIUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "hello=world");
+
+ s = "+%23+";
+ CGIUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, " # ");
+
+ s = "hello%3u";
+ CGIUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "hello%3u");
+
+ s = "0123456789012345";
+ CGIUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "0123456789012345");
+
+ s = "";
+ CGIUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "");
+ }
+
+ Y_UNIT_TEST(StrokaOutParameterNotInplace) {
+ TString s, sCopy;
+
+ s = "hello%3dworld";
+ sCopy = s;
+ CGIUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "hello=world");
+
+ s = "+%23+";
+ sCopy = s;
+ CGIUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, " # ");
+
+ s = "hello%3u";
+ sCopy = s;
+ CGIUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "hello%3u");
+
+ s = "0123456789012345";
+ sCopy = s;
+ CGIUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "0123456789012345");
+
+ s = "";
+ sCopy = s;
+ CGIUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "");
+ }
+}
+
+Y_UNIT_TEST_SUITE(TUrlEscapeTest) {
+ Y_UNIT_TEST(EscapeEscaped) {
+ TString s;
+
+ s = "hello%3dworld";
+ UNIT_ASSERT_VALUES_EQUAL(UrlEscapeRet(s), "hello%3dworld");
+ UrlEscape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "hello%3dworld");
+ }
+
+ Y_UNIT_TEST(EscapeUnescape) {
+ TString s;
+
+ s = "hello%3dworld";
+ UrlEscape(s);
+ UrlUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "hello=world");
+ }
+
+ Y_UNIT_TEST(EscapeUnescapeRet) {
+ TString s;
+
+ s = "hello%3dworld";
+ UNIT_ASSERT_VALUES_EQUAL(UrlUnescapeRet(UrlEscapeRet(s)), "hello=world");
+ }
+
+ Y_UNIT_TEST(EscapeEscapedForce) {
+ TString s;
+
+ s = "hello%3dworld";
+ UNIT_ASSERT_VALUES_EQUAL(UrlEscapeRet(s, true), "hello%253dworld");
+ UrlEscape(s, true);
+ UNIT_ASSERT_VALUES_EQUAL(s, "hello%253dworld");
+ }
+
+ Y_UNIT_TEST(EscapeUnescapeForce) {
+ TString s;
+
+ s = "hello%3dworld";
+ UrlEscape(s, true);
+ UrlUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "hello%3dworld");
+ }
+
+ Y_UNIT_TEST(EscapeUnescapeForceRet) {
+ TString s;
+
+ s = "hello%3dworld";
+ UNIT_ASSERT_VALUES_EQUAL(UrlUnescapeRet(UrlEscapeRet(s, true)), "hello%3dworld");
+ }
+}
+
+Y_UNIT_TEST_SUITE(TUrlUnescapeTest) {
+ Y_UNIT_TEST(StrokaOutParameterInplace) {
+ TString s;
+
+ s = "hello%3dworld";
+ UrlUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "hello=world");
+
+ s = "+%23+";
+ UrlUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "+#+");
+
+ s = "hello%3u";
+ UrlUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "hello%3u");
+
+ s = "0123456789012345";
+ UrlUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "0123456789012345");
+
+ s = "";
+ UrlUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "");
+ }
+
+ Y_UNIT_TEST(StrokaOutParameterNotInplace) {
+ TString s, sCopy;
+
+ s = "hello%3dworld";
+ sCopy = s;
+ UrlUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "hello=world");
+
+ s = "+%23+";
+ sCopy = s;
+ UrlUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "+#+");
+
+ s = "hello%3u";
+ sCopy = s;
+ UrlUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "hello%3u");
+
+ s = "0123456789012345";
+ sCopy = s;
+ UrlUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "0123456789012345");
+
+ s = "";
+ sCopy = s;
+ UrlUnescape(s);
+ UNIT_ASSERT_VALUES_EQUAL(s, "");
+ }
+}
+
+Y_UNIT_TEST_SUITE(TQuoteTest) {
+ Y_UNIT_TEST(ReturnsEndOfTo) {
+ char r[10];
+ const char* returned = Quote(r, "123");
+ UNIT_ASSERT_VALUES_EQUAL(r + strlen("123"), returned);
+ UNIT_ASSERT_VALUES_EQUAL('\0', *returned);
+ }
+
+ Y_UNIT_TEST(SlashIsSafeByDefault) {
+ char r[100];
+ Quote(r, "/path;tail/path,tail/");
+ UNIT_ASSERT_VALUES_EQUAL("/path%3Btail/path%2Ctail/", r);
+ TString s("/path;tail/path,tail/");
+ Quote(s);
+ UNIT_ASSERT_VALUES_EQUAL("/path%3Btail/path%2Ctail/", s.c_str());
+ }
+
+ Y_UNIT_TEST(SafeColons) {
+ char r[100];
+ Quote(r, "/path;tail/path,tail/", ";,");
+ UNIT_ASSERT_VALUES_EQUAL("%2Fpath;tail%2Fpath,tail%2F", r);
+ TString s("/path;tail/path,tail/");
+ Quote(s, ";,");
+ UNIT_ASSERT_VALUES_EQUAL("%2Fpath;tail%2Fpath,tail%2F", s.c_str());
+ }
+
+ Y_UNIT_TEST(StringBuf) {
+ char r[100];
+ char* end = Quote(r, "abc\0/path", "");
+ UNIT_ASSERT_VALUES_EQUAL("abc\0%2Fpath", TStringBuf(r, end));
+ }
+}
diff --git a/library/cpp/string_utils/quote/ut/ya.make b/library/cpp/string_utils/quote/ut/ya.make
new file mode 100644
index 0000000000..eca955144f
--- /dev/null
+++ b/library/cpp/string_utils/quote/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/string_utils/quote)
+
+OWNER(vladon)
+
+SRCS(
+ quote_ut.cpp
+)
+
+END()
diff --git a/library/cpp/string_utils/quote/ya.make b/library/cpp/string_utils/quote/ya.make
new file mode 100644
index 0000000000..55bb3cf939
--- /dev/null
+++ b/library/cpp/string_utils/quote/ya.make
@@ -0,0 +1,10 @@
+LIBRARY()
+
+OWNER(g:util)
+
+SRCS(
+ quote.cpp
+ quote.h
+)
+
+END()
diff --git a/library/cpp/string_utils/relaxed_escaper/relaxed_escaper.cpp b/library/cpp/string_utils/relaxed_escaper/relaxed_escaper.cpp
new file mode 100644
index 0000000000..ac624dca85
--- /dev/null
+++ b/library/cpp/string_utils/relaxed_escaper/relaxed_escaper.cpp
@@ -0,0 +1 @@
+#include "relaxed_escaper.h"
diff --git a/library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h b/library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h
new file mode 100644
index 0000000000..d7ea7c1259
--- /dev/null
+++ b/library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h
@@ -0,0 +1,208 @@
+#pragma once
+
+#include <util/stream/output.h>
+#include <util/string/escape.h>
+#include <util/memory/tempbuf.h>
+#include <util/generic/strbuf.h>
+
+namespace NEscJ {
+ // almost copypaste from util/string/escape.h
+ // todo: move there (note difference in IsPrintable and handling of string)
+
+ inline char HexDigit(char value) {
+ if (value < 10)
+ return '0' + value;
+ else
+ return 'A' + value - 10;
+ }
+
+ inline char OctDigit(char value) {
+ return '0' + value;
+ }
+
+ inline bool IsUTF8(ui8 c) {
+ return c < 0xf5 && c != 0xC0 && c != 0xC1;
+ }
+
+ inline bool IsControl(ui8 c) {
+ return c < 0x20 || c == 0x7f;
+ }
+
+ inline bool IsPrintable(ui8 c) {
+ return IsUTF8(c) && !IsControl(c);
+ }
+
+ inline bool IsHexDigit(ui8 c) {
+ return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
+ }
+
+ inline bool IsOctDigit(ui8 c) {
+ return c >= '0' && c <= '7';
+ }
+
+ struct TEscapeUtil {
+ static const size_t ESCAPE_C_BUFFER_SIZE = 6;
+
+ template <bool asunicode>
+ static inline size_t EscapeJ(ui8 c, ui8 next, char r[ESCAPE_C_BUFFER_SIZE], TStringBuf safe, TStringBuf unsafe) {
+ // (1) Printable characters go as-is, except backslash and double quote.
+ // (2) Characters \r, \n, \t and \0 ... \7 replaced by their simple escape characters (if possible).
+ // (3) Otherwise, character is encoded using hexadecimal escape sequence (if possible), or octal.
+ if (safe.find(c) != TStringBuf::npos) {
+ r[0] = c;
+ return 1;
+ }
+ if (c == '\"') {
+ r[0] = '\\';
+ r[1] = '\"';
+ return 2;
+ } else if (c == '\\') {
+ r[0] = '\\';
+ r[1] = '\\';
+ return 2;
+ } else if (IsPrintable(c) && unsafe.find(c) == TStringBuf::npos) {
+ r[0] = c;
+ return 1;
+ } else if (c == '\b') {
+ r[0] = '\\';
+ r[1] = 'b';
+ return 2;
+ } else if (c == '\f') {
+ r[0] = '\\';
+ r[1] = 'f';
+ return 2;
+ } else if (c == '\r') {
+ r[0] = '\\';
+ r[1] = 'r';
+ return 2;
+ } else if (c == '\n') {
+ r[0] = '\\';
+ r[1] = 'n';
+ return 2;
+ } else if (c == '\t') {
+ r[0] = '\\';
+ r[1] = 't';
+ return 2;
+ } else if (asunicode && IsUTF8(c)) { // utf8 controls escape for json
+ r[0] = '\\';
+ r[1] = 'u';
+ r[2] = '0';
+ r[3] = '0';
+ r[4] = HexDigit((c & 0xF0) >> 4);
+ r[5] = HexDigit((c & 0x0F) >> 0);
+ return 6;
+ } else if (c < 8 && !IsOctDigit(next)) {
+ r[0] = '\\';
+ r[1] = OctDigit(c);
+ return 2;
+ } else if (!IsHexDigit(next)) {
+ r[0] = '\\';
+ r[1] = 'x';
+ r[2] = HexDigit((c & 0xF0) >> 4);
+ r[3] = HexDigit((c & 0x0F) >> 0);
+ return 4;
+ } else {
+ r[0] = '\\';
+ r[1] = OctDigit((c & 0700) >> 6);
+ r[2] = OctDigit((c & 0070) >> 3);
+ r[3] = OctDigit((c & 0007) >> 0);
+ return 4;
+ }
+ }
+
+ static inline size_t EscapeJ(ui8 c, ui8 next, char r[ESCAPE_C_BUFFER_SIZE], TStringBuf safe, TStringBuf unsafe) {
+ return EscapeJ<false>(c, next, r, safe, unsafe);
+ }
+ };
+
+ inline size_t SuggestBuffer(size_t len) {
+ return len * TEscapeUtil::ESCAPE_C_BUFFER_SIZE;
+ }
+
+ template <bool tounicode>
+ inline size_t EscapeJ(const char* str, size_t len, char* out, TStringBuf safe = TStringBuf(), TStringBuf unsafe = TStringBuf()) {
+ char* out0 = out;
+ char buffer[TEscapeUtil::ESCAPE_C_BUFFER_SIZE];
+
+ size_t i, j;
+ for (i = 0, j = 0; i < len; ++i) {
+ size_t rlen = TEscapeUtil::EscapeJ<tounicode>(str[i], (i + 1 < len ? str[i + 1] : 0), buffer, safe, unsafe);
+
+ if (rlen > 1) {
+ strncpy(out, str + j, i - j);
+ out += i - j;
+ j = i + 1;
+
+ strncpy(out, buffer, rlen);
+ out += rlen;
+ }
+ }
+
+ if (j > 0) {
+ strncpy(out, str + j, len - j);
+ out += len - j;
+ } else {
+ strncpy(out, str, len);
+ out += len;
+ }
+
+ return out - out0;
+ }
+
+ template <bool quote, bool tounicode>
+ inline void EscapeJ(TStringBuf in, IOutputStream& out, TStringBuf safe = TStringBuf(), TStringBuf unsafe = TStringBuf()) {
+ TTempBuf b(SuggestBuffer(in.size()) + 2);
+
+ if (quote)
+ b.Append("\"", 1);
+
+ b.Proceed(EscapeJ<tounicode>(in.data(), in.size(), b.Current(), safe, unsafe));
+
+ if (quote)
+ b.Append("\"", 1);
+
+ out.Write(b.Data(), b.Filled());
+ }
+
+ template <bool quote, bool tounicode>
+ inline void EscapeJ(TStringBuf in, TString& out, TStringBuf safe = TStringBuf(), TStringBuf unsafe = TStringBuf()) {
+ TTempBuf b(SuggestBuffer(in.size()) + 2);
+
+ if (quote)
+ b.Append("\"", 1);
+
+ b.Proceed(EscapeJ<tounicode>(in.data(), in.size(), b.Current(), safe, unsafe));
+
+ if (quote)
+ b.Append("\"", 1);
+
+ out.append(b.Data(), b.Filled());
+ }
+
+ template <bool quote, bool tounicode>
+ inline TString EscapeJ(TStringBuf in, TStringBuf safe = TStringBuf(), TStringBuf unsafe = TStringBuf()) {
+ TString s;
+ EscapeJ<quote, tounicode>(in, s, safe, unsafe);
+ return s;
+ }
+
+ // If the template parameter "tounicode" is ommited, then use the default value false
+ inline size_t EscapeJ(const char* str, size_t len, char* out, TStringBuf safe = TStringBuf(), TStringBuf unsafe = TStringBuf()) {
+ return EscapeJ<false>(str, len, out, safe, unsafe);
+ }
+
+ template <bool quote>
+ inline void EscapeJ(TStringBuf in, IOutputStream& out, TStringBuf safe = TStringBuf(), TStringBuf unsafe = TStringBuf()) {
+ EscapeJ<quote, false>(in, out, safe, unsafe);
+ }
+
+ template <bool quote>
+ inline void EscapeJ(TStringBuf in, TString& out, TStringBuf safe = TStringBuf(), TStringBuf unsafe = TStringBuf()) {
+ EscapeJ<quote, false>(in, out, safe, unsafe);
+ }
+
+ template <bool quote>
+ inline TString EscapeJ(TStringBuf in, TStringBuf safe = TStringBuf(), TStringBuf unsafe = TStringBuf()) {
+ return EscapeJ<quote, false>(in, safe, unsafe);
+ }
+}
diff --git a/library/cpp/string_utils/relaxed_escaper/relaxed_escaper_ut.cpp b/library/cpp/string_utils/relaxed_escaper/relaxed_escaper_ut.cpp
new file mode 100644
index 0000000000..768555ea3a
--- /dev/null
+++ b/library/cpp/string_utils/relaxed_escaper/relaxed_escaper_ut.cpp
@@ -0,0 +1,66 @@
+#include "relaxed_escaper.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#define RESC_FIXED_STR(s) TStringBuf(s, sizeof(s) - 1)
+static const TStringBuf CommonTestData[] = {
+ // Should be valid UTF-8.
+ RESC_FIXED_STR("http://ya.ru/"), RESC_FIXED_STR("http://ya.ru/"),
+ RESC_FIXED_STR("http://ya.ru/\\x17\\n"), RESC_FIXED_STR("http://ya.ru/\x17\n"),
+
+ RESC_FIXED_STR("http://ya.ru/\\0"), RESC_FIXED_STR("http://ya.ru/\0"),
+ RESC_FIXED_STR("http://ya.ru/\\0\\0"), RESC_FIXED_STR("http://ya.ru/\0\0"),
+ RESC_FIXED_STR("http://ya.ru/\\0\\0000"), RESC_FIXED_STR("http://ya.ru/\0\0"
+ "0"),
+ RESC_FIXED_STR("http://ya.ru/\\0\\0001"), RESC_FIXED_STR("http://ya.ru/\0\x00"
+ "1"),
+
+ RESC_FIXED_STR("\\2\\4\\00678"), RESC_FIXED_STR("\2\4\6"
+ "78"),
+ RESC_FIXED_STR("\\2\\4\\689"), RESC_FIXED_STR("\2\4\689"),
+
+ RESC_FIXED_STR("\\\"Hello\\\", Alice said."), RESC_FIXED_STR("\"Hello\", Alice said."),
+ RESC_FIXED_STR("Slash\\\\dash!"), RESC_FIXED_STR("Slash\\dash!"),
+ RESC_FIXED_STR("There\\nare\\r\\nnewlines."), RESC_FIXED_STR("There\nare\r\nnewlines."),
+ RESC_FIXED_STR("There\\tare\\ttabs."), RESC_FIXED_STR("There\tare\ttabs.")};
+#undef RESC_FIXED_STR
+
+Y_UNIT_TEST_SUITE(TRelaxedEscaperTest) {
+ Y_UNIT_TEST(TestEscaper) {
+ using namespace NEscJ;
+ for (size_t i = 0; i < Y_ARRAY_SIZE(CommonTestData); i += 2) {
+ TString expected(CommonTestData[i].data(), CommonTestData[i].size());
+ TString source(CommonTestData[i + 1].data(), CommonTestData[i + 1].size());
+ TString actual(EscapeJ<false>(source));
+ TString actual2(UnescapeC(expected));
+
+ UNIT_ASSERT_VALUES_EQUAL(expected, actual);
+ UNIT_ASSERT_VALUES_EQUAL(source, actual2);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL("http://ya.ru/\\x17\\n\xAB", EscapeJ<false>("http://ya.ru/\x17\n\xab"));
+ TString s = EscapeJ<false, true>("http://ya.ru/\x17\n\xab\xff");
+ UNIT_ASSERT_VALUES_EQUAL("http://ya.ru/\\u0017\\n\xAB\\xFF", s);
+ UNIT_ASSERT_VALUES_EQUAL("http://ya.ru/\\x17\n\xAB", EscapeJ<false>("http://ya.ru/\x17\n\xab", "\n"));
+ UNIT_ASSERT_VALUES_EQUAL("http:\\x2F\\x2Fya.ru\\x2F\\x17\n\xAB'", EscapeJ<false>("http://ya.ru/\x17\n\xab'", "\n'", "/"));
+ UNIT_ASSERT_VALUES_EQUAL("http://ya.ru/\x17\n\xab", UnescapeC("http:\\x2F\\x2Fya.ru\\x2F\\x17\n\xAB"));
+ UNIT_ASSERT_VALUES_EQUAL("http://ya.ru/\x17\n\xab", UnescapeC("http://ya.ru/\\x17\\n\xAB"));
+ UNIT_ASSERT_VALUES_EQUAL("h", EscapeJ<false>("h"));
+ UNIT_ASSERT_VALUES_EQUAL("\"h\"", EscapeJ<true>("h"));
+ UNIT_ASSERT_VALUES_EQUAL("h", UnescapeC("h"));
+ UNIT_ASSERT_VALUES_EQUAL("\\xFF", EscapeJ<false>("\xFF"));
+ UNIT_ASSERT_VALUES_EQUAL("\"\\xFF\"", EscapeJ<true>("\xFF"));
+ UNIT_ASSERT_VALUES_EQUAL("\xFF", UnescapeC("\\xFF"));
+
+ UNIT_ASSERT_VALUES_EQUAL("\\377f", EscapeJ<false>("\xff"
+ "f"));
+ UNIT_ASSERT_VALUES_EQUAL("\xff"
+ "f",
+ UnescapeC("\\377f"));
+ UNIT_ASSERT_VALUES_EQUAL("\\xFFg", EscapeJ<false>("\xff"
+ "g"));
+ UNIT_ASSERT_VALUES_EQUAL("\xff"
+ "g",
+ UnescapeC("\\xFFg"));
+ }
+}
diff --git a/library/cpp/string_utils/relaxed_escaper/ut/ya.make b/library/cpp/string_utils/relaxed_escaper/ut/ya.make
new file mode 100644
index 0000000000..7ebd393c48
--- /dev/null
+++ b/library/cpp/string_utils/relaxed_escaper/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/string_utils/relaxed_escaper)
+
+OWNER(velavokr)
+
+SRCS(
+ relaxed_escaper_ut.cpp
+)
+
+END()
diff --git a/library/cpp/string_utils/relaxed_escaper/ya.make b/library/cpp/string_utils/relaxed_escaper/ya.make
new file mode 100644
index 0000000000..3f0fa5bc07
--- /dev/null
+++ b/library/cpp/string_utils/relaxed_escaper/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(velavokr)
+
+SRCS(
+ relaxed_escaper.cpp
+)
+
+END()
diff --git a/library/cpp/string_utils/scan/scan.cpp b/library/cpp/string_utils/scan/scan.cpp
new file mode 100644
index 0000000000..fbc1fdf08f
--- /dev/null
+++ b/library/cpp/string_utils/scan/scan.cpp
@@ -0,0 +1 @@
+#include "scan.h"
diff --git a/library/cpp/string_utils/scan/scan.h b/library/cpp/string_utils/scan/scan.h
new file mode 100644
index 0000000000..703db54321
--- /dev/null
+++ b/library/cpp/string_utils/scan/scan.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+template <bool addAll, char sep, char sepKeyVal, class F>
+static inline void ScanKeyValue(TStringBuf s, F&& f) {
+ TStringBuf key, val;
+
+ while (!s.empty()) {
+ val = s.NextTok(sep);
+
+ if (val.empty()) {
+ continue; // && case
+ }
+
+ key = val.NextTok(sepKeyVal);
+
+ if (addAll || val.IsInited()) {
+ f(key, val); // includes empty keys
+ }
+ }
+}
diff --git a/library/cpp/string_utils/scan/ya.make b/library/cpp/string_utils/scan/ya.make
new file mode 100644
index 0000000000..2faae86b09
--- /dev/null
+++ b/library/cpp/string_utils/scan/ya.make
@@ -0,0 +1,11 @@
+OWNER(
+ g:util
+)
+
+LIBRARY()
+
+SRCS(
+ scan.cpp
+)
+
+END()
diff --git a/library/cpp/string_utils/url/url.cpp b/library/cpp/string_utils/url/url.cpp
new file mode 100644
index 0000000000..85f4ac5d69
--- /dev/null
+++ b/library/cpp/string_utils/url/url.cpp
@@ -0,0 +1,421 @@
+#include "url.h"
+
+#include <util/string/cast.h>
+#include <util/string/util.h>
+#include <util/string/cstriter.h>
+#include <util/string/ascii.h>
+#include <util/string/strip.h>
+
+#include <util/charset/unidata.h> // for ToLower
+#include <util/system/defaults.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/hash_set.h>
+#include <util/generic/yexception.h>
+#include <util/generic/singleton.h>
+
+#include <cstdlib>
+
+namespace {
+ struct TUncheckedSize {
+ static bool Has(size_t) {
+ return true;
+ }
+ };
+
+ struct TKnownSize {
+ size_t MySize;
+ explicit TKnownSize(size_t sz)
+ : MySize(sz)
+ {
+ }
+ bool Has(size_t sz) const {
+ return sz <= MySize;
+ }
+ };
+
+ template <typename TChar1, typename TChar2>
+ int Compare1Case2(const TChar1* s1, const TChar2* s2, size_t n) {
+ for (size_t i = 0; i < n; ++i) {
+ if ((TChar1)ToLower(s1[i]) != s2[i])
+ return (TChar1)ToLower(s1[i]) < s2[i] ? -1 : 1;
+ }
+ return 0;
+ }
+
+ template <typename TChar, typename TBounds>
+ inline size_t GetHttpPrefixSizeImpl(const TChar* url, const TBounds& urlSize, bool ignorehttps) {
+ const TChar httpPrefix[] = {'h', 't', 't', 'p', ':', '/', '/', 0};
+ const TChar httpsPrefix[] = {'h', 't', 't', 'p', 's', ':', '/', '/', 0};
+ if (urlSize.Has(7) && Compare1Case2(url, httpPrefix, 7) == 0)
+ return 7;
+ if (!ignorehttps && urlSize.Has(8) && Compare1Case2(url, httpsPrefix, 8) == 0)
+ return 8;
+ return 0;
+ }
+
+ template <typename T>
+ inline T CutHttpPrefixImpl(const T& url, bool ignorehttps) {
+ size_t prefixSize = GetHttpPrefixSizeImpl<typename T::char_type>(url.data(), TKnownSize(url.size()), ignorehttps);
+ if (prefixSize)
+ return url.substr(prefixSize);
+ return url;
+ }
+}
+
+namespace NUrl {
+
+ TSplitUrlToHostAndPathResult SplitUrlToHostAndPath(const TStringBuf url) {
+ TStringBuf host = GetSchemeHostAndPort(url, /*trimHttp=*/false, /*trimDefaultPort=*/false);
+ TStringBuf path = url;
+ path.SkipPrefix(host);
+ return {host, path};
+ }
+
+} // namespace NUrl
+
+size_t GetHttpPrefixSize(const char* url, bool ignorehttps) noexcept {
+ return GetHttpPrefixSizeImpl<char>(url, TUncheckedSize(), ignorehttps);
+}
+
+size_t GetHttpPrefixSize(const wchar16* url, bool ignorehttps) noexcept {
+ return GetHttpPrefixSizeImpl<wchar16>(url, TUncheckedSize(), ignorehttps);
+}
+
+size_t GetHttpPrefixSize(const TStringBuf url, bool ignorehttps) noexcept {
+ return GetHttpPrefixSizeImpl<char>(url.data(), TKnownSize(url.size()), ignorehttps);
+}
+
+size_t GetHttpPrefixSize(const TWtringBuf url, bool ignorehttps) noexcept {
+ return GetHttpPrefixSizeImpl<wchar16>(url.data(), TKnownSize(url.size()), ignorehttps);
+}
+
+TStringBuf CutHttpPrefix(const TStringBuf url, bool ignorehttps) noexcept {
+ return CutHttpPrefixImpl(url, ignorehttps);
+}
+
+TWtringBuf CutHttpPrefix(const TWtringBuf url, bool ignorehttps) noexcept {
+ return CutHttpPrefixImpl(url, ignorehttps);
+}
+
+size_t GetSchemePrefixSize(const TStringBuf url) noexcept {
+ struct TDelim: public str_spn {
+ inline TDelim()
+ : str_spn("!-/:-@[-`{|}", true)
+ {
+ }
+ };
+
+ const auto& delim = *Singleton<TDelim>();
+ const char* n = delim.brk(url.data(), url.end());
+
+ if (n + 2 >= url.end() || *n != ':' || n[1] != '/' || n[2] != '/') {
+ return 0;
+ }
+
+ return n + 3 - url.begin();
+}
+
+TStringBuf GetSchemePrefix(const TStringBuf url) noexcept {
+ return url.Head(GetSchemePrefixSize(url));
+}
+
+TStringBuf CutSchemePrefix(const TStringBuf url) noexcept {
+ return url.Tail(GetSchemePrefixSize(url));
+}
+
+template <bool KeepPort>
+static inline TStringBuf GetHostAndPortImpl(const TStringBuf url) {
+ TStringBuf urlNoScheme = url;
+
+ urlNoScheme.Skip(GetHttpPrefixSize(url));
+
+ struct TDelim: public str_spn {
+ inline TDelim()
+ : str_spn(KeepPort ? "/;?#" : "/:;?#")
+ {
+ }
+ };
+
+ const auto& nonHostCharacters = *Singleton<TDelim>();
+ const char* firstNonHostCharacter = nonHostCharacters.brk(urlNoScheme.begin(), urlNoScheme.end());
+
+ if (firstNonHostCharacter != urlNoScheme.end()) {
+ return urlNoScheme.substr(0, firstNonHostCharacter - urlNoScheme.data());
+ }
+
+ return urlNoScheme;
+}
+
+TStringBuf GetHost(const TStringBuf url) noexcept {
+ return GetHostAndPortImpl<false>(url);
+}
+
+TStringBuf GetHostAndPort(const TStringBuf url) noexcept {
+ return GetHostAndPortImpl<true>(url);
+}
+
+TStringBuf GetSchemeHostAndPort(const TStringBuf url, bool trimHttp, bool trimDefaultPort) noexcept {
+ const size_t schemeSize = GetSchemePrefixSize(url);
+ const TStringBuf scheme = url.Head(schemeSize);
+
+ const bool isHttp = (schemeSize == 0 || scheme == TStringBuf("http://"));
+
+ TStringBuf hostAndPort = GetHostAndPort(url.Tail(schemeSize));
+
+ if (trimDefaultPort) {
+ const size_t pos = hostAndPort.find(':');
+ if (pos != TStringBuf::npos) {
+ const bool isHttps = (scheme == TStringBuf("https://"));
+
+ const TStringBuf port = hostAndPort.Tail(pos + 1);
+ if ((isHttp && port == TStringBuf("80")) || (isHttps && port == TStringBuf("443"))) {
+ // trimming default port
+ hostAndPort = hostAndPort.Head(pos);
+ }
+ }
+ }
+
+ if (isHttp && trimHttp) {
+ return hostAndPort;
+ } else {
+ return TStringBuf(scheme.begin(), hostAndPort.end());
+ }
+}
+
+void SplitUrlToHostAndPath(const TStringBuf url, TStringBuf& host, TStringBuf& path) {
+ auto [hostBuf, pathBuf] = NUrl::SplitUrlToHostAndPath(url);
+ host = hostBuf;
+ path = pathBuf;
+}
+
+void SplitUrlToHostAndPath(const TStringBuf url, TString& host, TString& path) {
+ auto [hostBuf, pathBuf] = NUrl::SplitUrlToHostAndPath(url);
+ host = hostBuf;
+ path = pathBuf;
+}
+
+void SeparateUrlFromQueryAndFragment(const TStringBuf url, TStringBuf& sanitizedUrl, TStringBuf& query, TStringBuf& fragment) {
+ TStringBuf urlWithoutFragment;
+ if (!url.TrySplit('#', urlWithoutFragment, fragment)) {
+ fragment = "";
+ urlWithoutFragment = url;
+ }
+ if (!urlWithoutFragment.TrySplit('?', sanitizedUrl, query)) {
+ query = "";
+ sanitizedUrl = urlWithoutFragment;
+ }
+}
+
+bool TryGetSchemeHostAndPort(const TStringBuf url, TStringBuf& scheme, TStringBuf& host, ui16& port) {
+ const size_t schemeSize = GetSchemePrefixSize(url);
+ if (schemeSize != 0) {
+ scheme = url.Head(schemeSize);
+ }
+
+ TStringBuf portStr;
+ TStringBuf hostAndPort = GetHostAndPort(url.Tail(schemeSize));
+ if (hostAndPort && hostAndPort.back() != ']' && hostAndPort.TryRSplit(':', host, portStr)) {
+ // URL has port
+ if (!TryFromString(portStr, port)) {
+ return false;
+ }
+ } else {
+ host = hostAndPort;
+ if (scheme == TStringBuf("https://")) {
+ port = 443;
+ } else if (scheme == TStringBuf("http://")) {
+ port = 80;
+ }
+ }
+ return true;
+}
+
+void GetSchemeHostAndPort(const TStringBuf url, TStringBuf& scheme, TStringBuf& host, ui16& port) {
+ bool isOk = TryGetSchemeHostAndPort(url, scheme, host, port);
+ Y_ENSURE(isOk, "cannot parse port number from URL: " << url);
+}
+
+TStringBuf GetOnlyHost(const TStringBuf url) noexcept {
+ return GetHost(CutSchemePrefix(url));
+}
+
+TStringBuf GetPathAndQuery(const TStringBuf url, bool trimFragment) noexcept {
+ const size_t off = url.find('/', GetHttpPrefixSize(url));
+ TStringBuf hostUnused, path;
+ if (!url.TrySplitAt(off, hostUnused, path))
+ return "/";
+
+ return trimFragment ? path.Before('#') : path;
+}
+
+// this strange creature returns 2nd level domain, possibly with port
+TStringBuf GetDomain(const TStringBuf host) noexcept {
+ const char* c = !host ? host.data() : host.end() - 1;
+ for (bool wasPoint = false; c != host.data(); --c) {
+ if (*c == '.') {
+ if (wasPoint) {
+ ++c;
+ break;
+ }
+ wasPoint = true;
+ }
+ }
+ return TStringBuf(c, host.end());
+}
+
+TStringBuf GetParentDomain(const TStringBuf host, size_t level) noexcept {
+ size_t pos = host.size();
+ for (size_t i = 0; i < level; ++i) {
+ pos = host.rfind('.', pos);
+ if (pos == TString::npos)
+ return host;
+ }
+ return host.SubStr(pos + 1);
+}
+
+TStringBuf GetZone(const TStringBuf host) noexcept {
+ return GetParentDomain(host, 1);
+}
+
+TStringBuf CutWWWPrefix(const TStringBuf url) noexcept {
+ if (url.size() >= 4 && url[3] == '.' && !strnicmp(url.data(), "www", 3))
+ return url.substr(4);
+ return url;
+}
+
+TStringBuf CutWWWNumberedPrefix(const TStringBuf url) noexcept {
+ auto it = url.begin();
+
+ StripRangeBegin(it, url.end(), [](auto& it){ return *it == 'w' || *it == 'W'; });
+ if (it == url.begin()) {
+ return url;
+ }
+
+ StripRangeBegin(it, url.end(), [](auto& it){ return IsAsciiDigit(*it); });
+ if (it == url.end()) {
+ return url;
+ }
+
+ if (*it++ == '.') {
+ return url.Tail(it - url.begin());
+ }
+
+ return url;
+}
+
+TStringBuf CutMPrefix(const TStringBuf url) noexcept {
+ if (url.size() >= 2 && url[1] == '.' && (url[0] == 'm' || url[0] == 'M')) {
+ return url.substr(2);
+ }
+ return url;
+}
+
+static inline bool IsSchemeChar(char c) noexcept {
+ return IsAsciiAlnum(c); //what about '+' ?..
+}
+
+static bool HasPrefix(const TStringBuf url) noexcept {
+ TStringBuf scheme, unused;
+ if (!url.TrySplit(TStringBuf("://"), scheme, unused))
+ return false;
+
+ return AllOf(scheme, IsSchemeChar);
+}
+
+TString AddSchemePrefix(const TString& url) {
+ return AddSchemePrefix(url, TStringBuf("http"));
+}
+
+TString AddSchemePrefix(const TString& url, TStringBuf scheme) {
+ if (HasPrefix(url)) {
+ return url;
+ }
+
+ return TString::Join(scheme, TStringBuf("://"), url);
+}
+
+#define X(c) (c >= 'A' ? ((c & 0xdf) - 'A') + 10 : (c - '0'))
+
+static inline int x2c(unsigned char* x) {
+ if (!IsAsciiHex(x[0]) || !IsAsciiHex(x[1]))
+ return -1;
+ return X(x[0]) * 16 + X(x[1]);
+}
+
+#undef X
+
+static inline int Unescape(char* str) {
+ char *to, *from;
+ int dlen = 0;
+ if ((str = strchr(str, '%')) == nullptr)
+ return dlen;
+ for (to = str, from = str; *from; from++, to++) {
+ if ((*to = *from) == '%') {
+ int c = x2c((unsigned char*)from + 1);
+ *to = char((c > 0) ? c : '0');
+ from += 2;
+ dlen += 2;
+ }
+ }
+ *to = 0; /* terminate it at the new length */
+ return dlen;
+}
+
+size_t NormalizeUrlName(char* dest, const TStringBuf source, size_t dest_size) {
+ if (source.empty() || source[0] == '?')
+ return strlcpy(dest, "/", dest_size);
+ size_t len = Min(dest_size - 1, source.length());
+ memcpy(dest, source.data(), len);
+ dest[len] = 0;
+ len -= Unescape(dest);
+ strlwr(dest);
+ return len;
+}
+
+size_t NormalizeHostName(char* dest, const TStringBuf source, size_t dest_size, ui16 defport) {
+ size_t len = Min(dest_size - 1, source.length());
+ memcpy(dest, source.data(), len);
+ dest[len] = 0;
+ char buf[8] = ":";
+ size_t buflen = 1 + ToString(defport, buf + 1, sizeof(buf) - 2);
+ buf[buflen] = '\0';
+ char* ptr = strstr(dest, buf);
+ if (ptr && ptr[buflen] == 0) {
+ len -= buflen;
+ *ptr = 0;
+ }
+ strlwr(dest);
+ return len;
+}
+
+TStringBuf RemoveFinalSlash(TStringBuf str) noexcept {
+ if (str.EndsWith('/')) {
+ str.Chop(1);
+ }
+ return str;
+}
+
+TStringBuf CutUrlPrefixes(TStringBuf url) noexcept {
+ url = CutSchemePrefix(url);
+ url = CutWWWPrefix(url);
+ return url;
+}
+
+bool DoesUrlPathStartWithToken(TStringBuf url, const TStringBuf& token) noexcept {
+ url = CutSchemePrefix(url);
+ const TStringBuf noHostSuffix = url.After('/');
+ if (noHostSuffix == url) {
+ // no slash => no suffix with token info
+ return false;
+ }
+ const bool suffixHasPrefix = noHostSuffix.StartsWith(token);
+ if (!suffixHasPrefix) {
+ return false;
+ }
+ const bool slashAfterPrefix = noHostSuffix.find("/", token.length()) == token.length();
+ const bool qMarkAfterPrefix = noHostSuffix.find("?", token.length()) == token.length();
+ const bool nothingAfterPrefix = noHostSuffix.length() <= token.length();
+ const bool prefixIsToken = slashAfterPrefix || qMarkAfterPrefix || nothingAfterPrefix;
+ return prefixIsToken;
+}
+
diff --git a/library/cpp/string_utils/url/url.h b/library/cpp/string_utils/url/url.h
new file mode 100644
index 0000000000..84137ccc57
--- /dev/null
+++ b/library/cpp/string_utils/url/url.h
@@ -0,0 +1,170 @@
+#pragma once
+
+#include <util/generic/fwd.h>
+#include <util/generic/strbuf.h>
+
+namespace NUrl {
+
+ /**
+ * Splits URL to host and path
+ * Example:
+ * auto [host, path] = SplitUrlToHostAndPath(url);
+ *
+ * @param[in] url any URL
+ * @param[out] <host, path> parsed host and path
+ */
+ struct TSplitUrlToHostAndPathResult {
+ TStringBuf host;
+ TStringBuf path;
+ };
+
+ Y_PURE_FUNCTION
+ TSplitUrlToHostAndPathResult SplitUrlToHostAndPath(const TStringBuf url);
+
+} // namespace NUrl
+
+Y_PURE_FUNCTION
+size_t GetHttpPrefixSize(const char* url, bool ignorehttps = false) noexcept;
+Y_PURE_FUNCTION
+size_t GetHttpPrefixSize(const wchar16* url, bool ignorehttps = false) noexcept;
+
+Y_PURE_FUNCTION
+size_t GetHttpPrefixSize(const TStringBuf url, bool ignorehttps = false) noexcept;
+
+Y_PURE_FUNCTION
+size_t GetHttpPrefixSize(const TWtringBuf url, bool ignorehttps = false) noexcept;
+
+/** BEWARE of TStringBuf! You can not use operator ~ or c_str() like in TString
+ !!!!!!!!!!!! */
+Y_PURE_FUNCTION
+size_t GetSchemePrefixSize(const TStringBuf url) noexcept;
+
+Y_PURE_FUNCTION
+TStringBuf GetSchemePrefix(const TStringBuf url) noexcept;
+
+//! removes protocol prefixes 'http://' and 'https://' from given URL
+//! @note if URL has no prefix or some other prefix the function does nothing
+//! @param url URL from which the prefix should be removed
+//! @param ignorehttps if true, leaves https://
+//! @return a new URL without protocol prefix
+Y_PURE_FUNCTION
+TStringBuf CutHttpPrefix(const TStringBuf url, bool ignorehttps = false) noexcept;
+
+Y_PURE_FUNCTION
+TWtringBuf CutHttpPrefix(const TWtringBuf url, bool ignorehttps = false) noexcept;
+
+Y_PURE_FUNCTION
+TStringBuf CutSchemePrefix(const TStringBuf url) noexcept;
+
+//! adds specified scheme prefix if URL has no scheme
+//! @note if URL has scheme prefix already the function returns unchanged URL
+TString AddSchemePrefix(const TString& url, const TStringBuf scheme);
+
+//! Same as `AddSchemePrefix(url, "http")`.
+TString AddSchemePrefix(const TString& url);
+
+Y_PURE_FUNCTION
+TStringBuf GetHost(const TStringBuf url) noexcept;
+
+Y_PURE_FUNCTION
+TStringBuf GetHostAndPort(const TStringBuf url) noexcept;
+
+Y_PURE_FUNCTION
+TStringBuf GetSchemeHostAndPort(const TStringBuf url, bool trimHttp = true, bool trimDefaultPort = true) noexcept;
+
+/**
+ * Splits URL to host and path
+ *
+ * @param[in] url any URL
+ * @param[out] host parsed host
+ * @param[out] path parsed path
+ */
+void SplitUrlToHostAndPath(const TStringBuf url, TStringBuf& host, TStringBuf& path);
+void SplitUrlToHostAndPath(const TStringBuf url, TString& host, TString& path);
+
+/**
+ * Separates URL into url prefix, query (aka cgi params list), and fragment (aka part after #)
+ *
+ * @param[in] url any URL
+ * @param[out] sanitizedUrl parsed URL without query and fragment parts
+ * @param[out] query parsed query
+ * @param[out] fragment parsed fragment
+ */
+void SeparateUrlFromQueryAndFragment(const TStringBuf url, TStringBuf& sanitizedUrl, TStringBuf& query, TStringBuf& fragment);
+
+/**
+ * Extracts scheme, host and port from URL.
+ *
+ * Port will be parsed from URL with checks against ui16 overflow. If URL doesn't
+ * contain port it will be determined by one of the known schemes (currently
+ * https:// and http:// only).
+ * Given parameters will not be modified if URL has no appropriate components.
+ *
+ * @param[in] url any URL
+ * @param[out] scheme URL scheme
+ * @param[out] host host name
+ * @param[out] port parsed port number
+ * @return false if present port number cannot be parsed into ui16
+ * true otherwise.
+ */
+bool TryGetSchemeHostAndPort(const TStringBuf url, TStringBuf& scheme, TStringBuf& host, ui16& port);
+
+/**
+ * Extracts scheme, host and port from URL.
+ *
+ * This function perform the same actions as TryGetSchemeHostAndPort(), but in
+ * case of impossibility to parse port number throws yexception.
+ *
+ * @param[in] url any URL
+ * @param[out] scheme URL scheme
+ * @param[out] host host name
+ * @param[out] port parsed port number
+ * @throws yexception if present port number cannot be parsed into ui16.
+ */
+void GetSchemeHostAndPort(const TStringBuf url, TStringBuf& scheme, TStringBuf& host, ui16& port);
+
+Y_PURE_FUNCTION
+TStringBuf GetPathAndQuery(const TStringBuf url, bool trimFragment = true) noexcept;
+/**
+ * Extracts host from url and cuts http(https) protocol prefix and port if any.
+ * @param[in] url any URL
+ * @return host without port and http(https) prefix.
+ */
+Y_PURE_FUNCTION
+TStringBuf GetOnlyHost(const TStringBuf url) noexcept;
+
+Y_PURE_FUNCTION
+TStringBuf GetParentDomain(const TStringBuf host, size_t level) noexcept; // ("www.ya.ru", 2) -> "ya.ru"
+
+Y_PURE_FUNCTION
+TStringBuf GetZone(const TStringBuf host) noexcept;
+
+Y_PURE_FUNCTION
+TStringBuf CutWWWPrefix(const TStringBuf url) noexcept;
+
+Y_PURE_FUNCTION
+TStringBuf CutWWWNumberedPrefix(const TStringBuf url) noexcept;
+
+/**
+ * Cuts 'm.' prefix from url if and only if the url starts with it
+ * Example: 'm.some-domain.com' -> 'some-domain.com'.
+ * 'http://m.some-domain.com' is not changed
+ *
+ * @param[in] url any URL
+ * @return url without 'm.' or 'M.' prefix.
+ */
+Y_PURE_FUNCTION
+TStringBuf CutMPrefix(const TStringBuf url) noexcept;
+
+Y_PURE_FUNCTION
+TStringBuf GetDomain(const TStringBuf host) noexcept; // should not be used
+
+size_t NormalizeUrlName(char* dest, const TStringBuf source, size_t dest_size);
+size_t NormalizeHostName(char* dest, const TStringBuf source, size_t dest_size, ui16 defport = 80);
+
+Y_PURE_FUNCTION
+TStringBuf RemoveFinalSlash(TStringBuf str) noexcept;
+
+TStringBuf CutUrlPrefixes(TStringBuf url) noexcept;
+bool DoesUrlPathStartWithToken(TStringBuf url, const TStringBuf& token) noexcept;
+
diff --git a/library/cpp/string_utils/url/url_ut.cpp b/library/cpp/string_utils/url/url_ut.cpp
new file mode 100644
index 0000000000..1588013893
--- /dev/null
+++ b/library/cpp/string_utils/url/url_ut.cpp
@@ -0,0 +1,281 @@
+#include "url.h"
+
+#include <util/string/cast.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TUtilUrlTest) {
+ Y_UNIT_TEST(TestGetHostAndGetHostAndPort) {
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", GetHost("ya.ru/bebe"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", GetHostAndPort("ya.ru/bebe"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", GetHost("ya.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", GetHostAndPort("ya.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", GetHost("ya.ru:8080"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru:8080", GetHostAndPort("ya.ru:8080"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", GetHost("ya.ru/bebe:8080"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", GetHostAndPort("ya.ru/bebe:8080"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", GetHost("ya.ru:8080/bebe"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", GetHost("https://ya.ru:8080/bebe"));
+ UNIT_ASSERT_VALUES_EQUAL("www.ya.ru", GetHost("www.ya.ru:8080/bebe"));
+ UNIT_ASSERT_VALUES_EQUAL("www.ya.ru", GetHost("https://www.ya.ru:8080/bebe"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru:8080", GetHostAndPort("ya.ru:8080/bebe"));
+ // irl RFC3986 sometimes gets ignored
+ UNIT_ASSERT_VALUES_EQUAL("pravda-kmv.ru", GetHost("pravda-kmv.ru?page=news&id=6973"));
+ UNIT_ASSERT_VALUES_EQUAL("pravda-kmv.ru", GetHostAndPort("pravda-kmv.ru?page=news&id=6973"));
+ // check simple string
+ UNIT_ASSERT_VALUES_EQUAL("some_blender_url", GetHost("some_blender_url"));
+ UNIT_ASSERT_VALUES_EQUAL("", GetHost(""));
+ }
+
+ Y_UNIT_TEST(TestGetPathAndQuery) {
+ UNIT_ASSERT_VALUES_EQUAL("/", GetPathAndQuery("ru.wikipedia.org"));
+ UNIT_ASSERT_VALUES_EQUAL("/", GetPathAndQuery("ru.wikipedia.org/"));
+ UNIT_ASSERT_VALUES_EQUAL("/", GetPathAndQuery("ru.wikipedia.org:8080"));
+ UNIT_ASSERT_VALUES_EQUAL("/index.php?123/", GetPathAndQuery("ru.wikipedia.org/index.php?123/"));
+ UNIT_ASSERT_VALUES_EQUAL("/", GetPathAndQuery("http://ru.wikipedia.org:8080"));
+ UNIT_ASSERT_VALUES_EQUAL("/index.php?123/", GetPathAndQuery("https://ru.wikipedia.org/index.php?123/"));
+ UNIT_ASSERT_VALUES_EQUAL("/", GetPathAndQuery("ru.wikipedia.org/#comment"));
+ UNIT_ASSERT_VALUES_EQUAL("/?1", GetPathAndQuery("ru.wikipedia.org/?1#comment"));
+ UNIT_ASSERT_VALUES_EQUAL("/?1#comment", GetPathAndQuery("ru.wikipedia.org/?1#comment", false));
+ }
+
+ Y_UNIT_TEST(TestGetDomain) {
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", GetDomain("www.ya.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", GetDomain("ya.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", GetDomain("a.b.ya.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", GetDomain("ya.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("ya", GetDomain("ya"));
+ UNIT_ASSERT_VALUES_EQUAL("", GetDomain(""));
+ }
+
+ Y_UNIT_TEST(TestGetParentDomain) {
+ UNIT_ASSERT_VALUES_EQUAL("", GetParentDomain("www.ya.ru", 0));
+ UNIT_ASSERT_VALUES_EQUAL("ru", GetParentDomain("www.ya.ru", 1));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", GetParentDomain("www.ya.ru", 2));
+ UNIT_ASSERT_VALUES_EQUAL("www.ya.ru", GetParentDomain("www.ya.ru", 3));
+ UNIT_ASSERT_VALUES_EQUAL("www.ya.ru", GetParentDomain("www.ya.ru", 4));
+ UNIT_ASSERT_VALUES_EQUAL("com", GetParentDomain("ya.com", 1));
+ UNIT_ASSERT_VALUES_EQUAL("ya.com", GetParentDomain("ya.com", 2));
+ UNIT_ASSERT_VALUES_EQUAL("RU", GetParentDomain("RU", 1));
+ UNIT_ASSERT_VALUES_EQUAL("RU", GetParentDomain("RU", 2));
+ UNIT_ASSERT_VALUES_EQUAL("", GetParentDomain("", 0));
+ UNIT_ASSERT_VALUES_EQUAL("", GetParentDomain("", 1));
+ }
+
+ Y_UNIT_TEST(TestGetZone) {
+ UNIT_ASSERT_VALUES_EQUAL("ru", GetZone("www.ya.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("com", GetZone("ya.com"));
+ UNIT_ASSERT_VALUES_EQUAL("RU", GetZone("RU"));
+ UNIT_ASSERT_VALUES_EQUAL("FHFBN", GetZone("ya.FHFBN"));
+ UNIT_ASSERT_VALUES_EQUAL("", GetZone(""));
+ }
+
+ Y_UNIT_TEST(TestAddSchemePrefix) {
+ UNIT_ASSERT_VALUES_EQUAL("http://yandex.ru", AddSchemePrefix("yandex.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("http://yandex.ru", AddSchemePrefix("http://yandex.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("https://yandex.ru", AddSchemePrefix("https://yandex.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("file://yandex.ru", AddSchemePrefix("file://yandex.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("ftp://ya.ru", AddSchemePrefix("ya.ru", "ftp"));
+ }
+
+ Y_UNIT_TEST(TestSchemeGet) {
+ UNIT_ASSERT_VALUES_EQUAL("http://", GetSchemePrefix("http://ya.ru/bebe"));
+ UNIT_ASSERT_VALUES_EQUAL("", GetSchemePrefix("yaru"));
+ UNIT_ASSERT_VALUES_EQUAL("yaru://", GetSchemePrefix("yaru://ya.ru://zzz"));
+ UNIT_ASSERT_VALUES_EQUAL("", GetSchemePrefix("ya.ru://zzz"));
+ UNIT_ASSERT_VALUES_EQUAL("ftp://", GetSchemePrefix("ftp://ya.ru://zzz"));
+ UNIT_ASSERT_VALUES_EQUAL("https://", GetSchemePrefix("https://")); // is that right?
+ }
+
+ Y_UNIT_TEST(TestSchemeCut) {
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru/bebe", CutSchemePrefix("http://ya.ru/bebe"));
+ UNIT_ASSERT_VALUES_EQUAL("yaru", CutSchemePrefix("yaru"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru://zzz", CutSchemePrefix("yaru://ya.ru://zzz"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru://zzz", CutSchemePrefix("ya.ru://zzz"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru://zzz", CutSchemePrefix("ftp://ya.ru://zzz"));
+ UNIT_ASSERT_VALUES_EQUAL("", CutSchemePrefix("https://")); // is that right?
+
+ UNIT_ASSERT_VALUES_EQUAL("ftp://ya.ru", CutHttpPrefix("ftp://ya.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru/zzz", CutHttpPrefix("http://ya.ru/zzz"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru/zzz", CutHttpPrefix("http://ya.ru/zzz", true));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru/zzz", CutHttpPrefix("https://ya.ru/zzz"));
+ UNIT_ASSERT_VALUES_EQUAL("https://ya.ru/zzz", CutHttpPrefix("https://ya.ru/zzz", true));
+ UNIT_ASSERT_VALUES_EQUAL("", CutHttpPrefix("https://")); // is that right?
+ UNIT_ASSERT_VALUES_EQUAL("https://", CutHttpPrefix("https://", true)); // is that right?
+ }
+
+ Y_UNIT_TEST(TestMisc) {
+ UNIT_ASSERT_VALUES_EQUAL("", CutWWWPrefix("www."));
+ UNIT_ASSERT_VALUES_EQUAL("", CutWWWPrefix("WwW."));
+ UNIT_ASSERT_VALUES_EQUAL("www", CutWWWPrefix("www"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", CutWWWPrefix("www.ya.ru"));
+
+ UNIT_ASSERT_VALUES_EQUAL("", CutWWWNumberedPrefix("www."));
+ UNIT_ASSERT_VALUES_EQUAL("www", CutWWWNumberedPrefix("www"));
+ UNIT_ASSERT_VALUES_EQUAL("www27", CutWWWNumberedPrefix("www27"));
+ UNIT_ASSERT_VALUES_EQUAL("", CutWWWNumberedPrefix("www27."));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", CutWWWNumberedPrefix("www.ya.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", CutWWWNumberedPrefix("www2.ya.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", CutWWWNumberedPrefix("www12.ya.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", CutWWWNumberedPrefix("ww2.ya.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("w1w2w3.ya.ru", CutWWWNumberedPrefix("w1w2w3.ya.ru"));
+ UNIT_ASSERT_VALUES_EQUAL("123.ya.ru", CutWWWNumberedPrefix("123.ya.ru"));
+
+ UNIT_ASSERT_VALUES_EQUAL("", CutMPrefix("m."));
+ UNIT_ASSERT_VALUES_EQUAL("", CutMPrefix("M."));
+ UNIT_ASSERT_VALUES_EQUAL("m", CutMPrefix("m"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru", CutMPrefix("m.ya.ru"));
+ }
+
+ Y_UNIT_TEST(TestSplitUrlToHostAndPath) {
+ TStringBuf host, path;
+
+ SplitUrlToHostAndPath("https://yandex.ru/yandsearch", host, path);
+ UNIT_ASSERT_STRINGS_EQUAL(host, "https://yandex.ru");
+ UNIT_ASSERT_STRINGS_EQUAL(path, "/yandsearch");
+
+ SplitUrlToHostAndPath("yandex.ru/yandsearch", host, path);
+ UNIT_ASSERT_STRINGS_EQUAL(host, "yandex.ru");
+ UNIT_ASSERT_STRINGS_EQUAL(path, "/yandsearch");
+
+ SplitUrlToHostAndPath("https://yandex.ru", host, path);
+ UNIT_ASSERT_STRINGS_EQUAL(host, "https://yandex.ru");
+ UNIT_ASSERT_STRINGS_EQUAL(path, "");
+
+ SplitUrlToHostAndPath("invalid url /", host, path);
+ UNIT_ASSERT_STRINGS_EQUAL(host, "invalid url ");
+ UNIT_ASSERT_STRINGS_EQUAL(path, "/");
+
+ SplitUrlToHostAndPath("some_blender_url", host, path);
+ UNIT_ASSERT_STRINGS_EQUAL(host, "some_blender_url");
+ UNIT_ASSERT_STRINGS_EQUAL(path, "");
+ }
+
+ Y_UNIT_TEST(TestSeparateUrlFromQueryAndFragment) {
+ TStringBuf sanitizedUrl, query, fragment;
+
+ SeparateUrlFromQueryAndFragment("https://yandex.ru/yandsearch", sanitizedUrl, query, fragment);
+ UNIT_ASSERT_STRINGS_EQUAL(sanitizedUrl, "https://yandex.ru/yandsearch");
+ UNIT_ASSERT_STRINGS_EQUAL(query, "");
+ UNIT_ASSERT_STRINGS_EQUAL(fragment, "");
+
+ SeparateUrlFromQueryAndFragment("https://yandex.ru/yandsearch?param1=val1&param2=val2", sanitizedUrl, query, fragment);
+ UNIT_ASSERT_STRINGS_EQUAL(sanitizedUrl, "https://yandex.ru/yandsearch");
+ UNIT_ASSERT_STRINGS_EQUAL(query, "param1=val1&param2=val2");
+ UNIT_ASSERT_STRINGS_EQUAL(fragment, "");
+
+ SeparateUrlFromQueryAndFragment("https://yandex.ru/yandsearch#fragment", sanitizedUrl, query, fragment);
+ UNIT_ASSERT_STRINGS_EQUAL(sanitizedUrl, "https://yandex.ru/yandsearch");
+ UNIT_ASSERT_STRINGS_EQUAL(query, "");
+ UNIT_ASSERT_STRINGS_EQUAL(fragment, "fragment");
+
+ SeparateUrlFromQueryAndFragment("https://yandex.ru/yandsearch?param1=val1&param2=val2#fragment", sanitizedUrl, query, fragment);
+ UNIT_ASSERT_STRINGS_EQUAL(sanitizedUrl, "https://yandex.ru/yandsearch");
+ UNIT_ASSERT_STRINGS_EQUAL(query, "param1=val1&param2=val2");
+ UNIT_ASSERT_STRINGS_EQUAL(fragment, "fragment");
+ }
+
+ Y_UNIT_TEST(TestGetSchemeHostAndPort) {
+ { // all components are present
+ TStringBuf scheme("unknown"), host("unknown");
+ ui16 port = 0;
+ GetSchemeHostAndPort("https://ya.ru:8080/bebe", scheme, host, port);
+ UNIT_ASSERT_VALUES_EQUAL(scheme, "https://");
+ UNIT_ASSERT_VALUES_EQUAL(host, "ya.ru");
+ UNIT_ASSERT_VALUES_EQUAL(port, 8080);
+ }
+ { // scheme is abset
+ TStringBuf scheme("unknown"), host("unknown");
+ ui16 port = 0;
+ GetSchemeHostAndPort("ya.ru:8080/bebe", scheme, host, port);
+ UNIT_ASSERT_VALUES_EQUAL(scheme, "unknown");
+ UNIT_ASSERT_VALUES_EQUAL(host, "ya.ru");
+ UNIT_ASSERT_VALUES_EQUAL(port, 8080);
+ }
+ { // scheme and port are absent
+ TStringBuf scheme("unknown"), host("unknown");
+ ui16 port = 0;
+ GetSchemeHostAndPort("ya.ru/bebe", scheme, host, port);
+ UNIT_ASSERT_VALUES_EQUAL(scheme, "unknown");
+ UNIT_ASSERT_VALUES_EQUAL(host, "ya.ru");
+ UNIT_ASSERT_VALUES_EQUAL(port, 0);
+ }
+ { // port is absent, but returned its default value for HTTP
+ TStringBuf scheme("unknown"), host("unknown");
+ ui16 port = 0;
+ GetSchemeHostAndPort("http://ya.ru/bebe", scheme, host, port);
+ UNIT_ASSERT_VALUES_EQUAL(scheme, "http://");
+ UNIT_ASSERT_VALUES_EQUAL(host, "ya.ru");
+ UNIT_ASSERT_VALUES_EQUAL(port, 80);
+ }
+ { // port is absent, but returned its default value for HTTPS
+ TStringBuf scheme("unknown"), host("unknown");
+ ui16 port = 0;
+ GetSchemeHostAndPort("https://ya.ru/bebe", scheme, host, port);
+ UNIT_ASSERT_VALUES_EQUAL(scheme, "https://");
+ UNIT_ASSERT_VALUES_EQUAL(host, "ya.ru");
+ UNIT_ASSERT_VALUES_EQUAL(port, 443);
+ }
+ { // ipv6
+ TStringBuf scheme("unknown"), host("unknown");
+ ui16 port = 0;
+ GetSchemeHostAndPort("https://[1080:0:0:0:8:800:200C:417A]:443/bebe", scheme, host, port);
+ UNIT_ASSERT_VALUES_EQUAL(scheme, "https://");
+ UNIT_ASSERT_VALUES_EQUAL(host, "[1080:0:0:0:8:800:200C:417A]");
+ UNIT_ASSERT_VALUES_EQUAL(port, 443);
+ }
+ { // ipv6
+ TStringBuf scheme("unknown"), host("unknown");
+ ui16 port = 0;
+ GetSchemeHostAndPort("[::1]/bebe", scheme, host, port);
+ UNIT_ASSERT_VALUES_EQUAL(scheme, "unknown");
+ UNIT_ASSERT_VALUES_EQUAL(host, "[::1]");
+ UNIT_ASSERT_VALUES_EQUAL(port, 0);
+ }
+ { // ipv6
+ TStringBuf scheme("unknown"), host("unknown");
+ ui16 port = 0;
+ GetSchemeHostAndPort("unknown:///bebe", scheme, host, port);
+ UNIT_ASSERT_VALUES_EQUAL(scheme, "unknown://");
+ UNIT_ASSERT_VALUES_EQUAL(host, "");
+ UNIT_ASSERT_VALUES_EQUAL(port, 0);
+ }
+ // port overflow
+ auto testCase = []() {
+ TStringBuf scheme("unknown"), host("unknown");
+ ui16 port = 0;
+ GetSchemeHostAndPort("https://ya.ru:65536/bebe", scheme, host, port);
+ };
+ UNIT_ASSERT_EXCEPTION(testCase(), yexception);
+ }
+
+ Y_UNIT_TEST(TestCutUrlPrefixes) {
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru/bebe", CutUrlPrefixes("http://ya.ru/bebe"));
+ UNIT_ASSERT_VALUES_EQUAL("yaru", CutUrlPrefixes("yaru"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru://zzz", CutUrlPrefixes("yaru://ya.ru://zzz"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru://zzz", CutUrlPrefixes("ya.ru://zzz"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru://zzz", CutUrlPrefixes("ftp://ya.ru://zzz"));
+ UNIT_ASSERT_VALUES_EQUAL("", CutUrlPrefixes("https://"));
+
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru/bebe", CutUrlPrefixes("https://www.ya.ru/bebe"));
+ UNIT_ASSERT_VALUES_EQUAL("yaru", CutUrlPrefixes("www.yaru"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru://zzz", CutUrlPrefixes("yaru://www.ya.ru://zzz"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru://zzz", CutUrlPrefixes("www.ya.ru://zzz"));
+ UNIT_ASSERT_VALUES_EQUAL("ya.ru://zzz", CutUrlPrefixes("ftp://www.ya.ru://zzz"));
+ UNIT_ASSERT_VALUES_EQUAL("", CutUrlPrefixes("http://www."));
+ }
+
+ Y_UNIT_TEST(TestUrlPathStartWithToken) {
+ UNIT_ASSERT_VALUES_EQUAL(true, DoesUrlPathStartWithToken("http://ya.ru/bebe/zzz", "bebe"));
+ UNIT_ASSERT_VALUES_EQUAL(true, DoesUrlPathStartWithToken("http://ya.ru/bebe?zzz", "bebe"));
+ UNIT_ASSERT_VALUES_EQUAL(true, DoesUrlPathStartWithToken("http://ya.ru/bebe/", "bebe"));
+ UNIT_ASSERT_VALUES_EQUAL(true, DoesUrlPathStartWithToken("http://ya.ru/bebe?", "bebe"));
+ UNIT_ASSERT_VALUES_EQUAL(true, DoesUrlPathStartWithToken("https://ya.ru/bebe", "bebe"));
+ UNIT_ASSERT_VALUES_EQUAL(false, DoesUrlPathStartWithToken("http://ya.ru/bebezzz", "bebe"));
+ UNIT_ASSERT_VALUES_EQUAL(false, DoesUrlPathStartWithToken("http://ya.ru/bebe.zzz", "bebe"));
+ UNIT_ASSERT_VALUES_EQUAL(false, DoesUrlPathStartWithToken("http://ya.ru/", "bebe"));
+ UNIT_ASSERT_VALUES_EQUAL(false, DoesUrlPathStartWithToken("http://ya.ru", "bebe"));
+ UNIT_ASSERT_VALUES_EQUAL(false, DoesUrlPathStartWithToken("http://bebe", "bebe"));
+ UNIT_ASSERT_VALUES_EQUAL(false, DoesUrlPathStartWithToken("https://bebe/", "bebe"));
+ }
+}
diff --git a/library/cpp/string_utils/url/ut/ya.make b/library/cpp/string_utils/url/ut/ya.make
new file mode 100644
index 0000000000..0efa30e4d2
--- /dev/null
+++ b/library/cpp/string_utils/url/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/string_utils/url)
+
+OWNER(g:util)
+
+SRCS(
+ url_ut.cpp
+)
+
+END()
diff --git a/library/cpp/string_utils/url/ya.make b/library/cpp/string_utils/url/ya.make
new file mode 100644
index 0000000000..b08d69ec83
--- /dev/null
+++ b/library/cpp/string_utils/url/ya.make
@@ -0,0 +1,10 @@
+LIBRARY()
+
+OWNER(g:util)
+
+SRCS(
+ url.cpp
+ url.h
+)
+
+END()
diff --git a/library/cpp/string_utils/ya.make b/library/cpp/string_utils/ya.make
new file mode 100644
index 0000000000..cd731bda95
--- /dev/null
+++ b/library/cpp/string_utils/ya.make
@@ -0,0 +1,37 @@
+RECURSE(
+ ascii_encode
+ ascii_encode/ut
+ base64
+ base64/bench
+ base64/bench/metrics
+ base64/ut
+ base64/fuzz
+ csv
+ csv/bench
+ csv/ut
+ col_diff
+ col_diff/ut
+ indent_text
+ levenshtein_diff
+ levenshtein_diff/ut
+ old_url_normalize
+ old_url_normalize/ut
+ parse_size
+ parse_size/ut
+ parse_vector
+ parse_vector/ut
+ secret_string
+ quote
+ quote/ut
+ relaxed_escaper
+ relaxed_escaper/ut
+ scan
+ subst_buf
+ subst_buf/ut
+ tskv_format
+ tskv_format/ut
+ tskv_format/fuzz
+ url
+ url/ut
+ ztstrbuf
+)
diff --git a/library/cpp/string_utils/ztstrbuf/ya.make b/library/cpp/string_utils/ztstrbuf/ya.make
new file mode 100644
index 0000000000..28b3f32f58
--- /dev/null
+++ b/library/cpp/string_utils/ztstrbuf/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(myltsev)
+
+SRCS(
+ ztstrbuf.cpp
+)
+
+END()
diff --git a/library/cpp/string_utils/ztstrbuf/ztstrbuf.cpp b/library/cpp/string_utils/ztstrbuf/ztstrbuf.cpp
new file mode 100644
index 0000000000..4a7269ff4a
--- /dev/null
+++ b/library/cpp/string_utils/ztstrbuf/ztstrbuf.cpp
@@ -0,0 +1,8 @@
+#include "ztstrbuf.h"
+
+#include <util/stream/output.h>
+
+template <>
+void Out<TZtStringBuf>(IOutputStream& os, const TZtStringBuf& sb) {
+ os << static_cast<const TStringBuf&>(sb);
+}
diff --git a/library/cpp/string_utils/ztstrbuf/ztstrbuf.h b/library/cpp/string_utils/ztstrbuf/ztstrbuf.h
new file mode 100644
index 0000000000..5fab768d8c
--- /dev/null
+++ b/library/cpp/string_utils/ztstrbuf/ztstrbuf.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+
+/*
+ * Zero-terminated string view.
+ *
+ * Has a c_str() for use with system/cstdlib calls (like TString)
+ * but can be constructed from a string literal or command-line arg
+ * without memory allocation (like TStringBuf).
+ *
+ * Use it to reference filenames, thread names, string formats etc.
+ */
+
+class TZtStringBuf: public TStringBuf {
+public:
+ TZtStringBuf(const char* s)
+ : TStringBuf(s)
+ {
+ }
+
+ TZtStringBuf(const TString& s)
+ : TStringBuf(s)
+ {
+ }
+
+ TZtStringBuf()
+ : TZtStringBuf(TString{})
+ {
+ }
+
+ const char* c_str() const {
+ return data();
+ }
+};
diff --git a/library/cpp/svnversion/svn_interface.c b/library/cpp/svnversion/svn_interface.c
new file mode 100644
index 0000000000..12884956b1
--- /dev/null
+++ b/library/cpp/svnversion/svn_interface.c
@@ -0,0 +1 @@
+// See build/scripts/c_templates/svn_interface.c instead.
diff --git a/library/cpp/svnversion/svnversion.cpp b/library/cpp/svnversion/svnversion.cpp
new file mode 100644
index 0000000000..4c9761fa75
--- /dev/null
+++ b/library/cpp/svnversion/svnversion.cpp
@@ -0,0 +1,33 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define FROM_IMPL
+#include "svnversion.h"
+
+#include <util/generic/strbuf.h>
+
+extern "C" void PrintProgramSvnVersion() {
+ puts(GetProgramSvnVersion());
+}
+
+extern "C" void PrintSvnVersionAndExit0() {
+ PrintProgramSvnVersion();
+ exit(0);
+}
+
+extern "C" void PrintSvnVersionAndExitEx(int argc, char* argv[], const char* opts) {
+ if (2 == argc) {
+ for (TStringBuf all = opts, versionOpt; all.NextTok(';', versionOpt);) {
+ if (versionOpt == argv[1]) {
+ PrintSvnVersionAndExit0();
+ }
+ }
+ }
+}
+
+extern "C" void PrintSvnVersionAndExit(int argc, char* argv[]) {
+ PrintSvnVersionAndExitEx(argc, argv, "--version");
+}
+
+#undef FROM_IMPL
diff --git a/library/cpp/svnversion/svnversion.h b/library/cpp/svnversion/svnversion.h
new file mode 100644
index 0000000000..b99615daa9
--- /dev/null
+++ b/library/cpp/svnversion/svnversion.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#if !defined(FROM_IMPL)
+#define PROGRAM_VERSION GetProgramSvnVersion()
+#define ARCADIA_SOURCE_PATH GetArcadiaSourcePath()
+#define PRINT_VERSION PrintSvnVersionAndExit(argc, (char**)argv)
+#define PRINT_VERSION_EX(opts) PrintSvnVersionAndExitEx(argc, (char**)argv, opts)
+#endif
+
+#include <util/system/compiler.h>
+
+// Automatically generated functions.
+#include "build/scripts/c_templates/svnversion.h"
diff --git a/library/cpp/svnversion/test/main.cpp b/library/cpp/svnversion/test/main.cpp
new file mode 100644
index 0000000000..3c8209047f
--- /dev/null
+++ b/library/cpp/svnversion/test/main.cpp
@@ -0,0 +1,30 @@
+#include <build/scripts/c_templates/svnversion.h>
+#include <util/stream/str.h>
+#include <util/system/compiler.h>
+#include <util/stream/output.h>
+
+// ya make -DFORCE_VCS_INFO_UPDATE --vcs-file=<vcs.json> library/cpp/svnversion/test/
+// ./library/svnversion/test/test[.exe]
+int main() {
+ Cout << "GetProgramSvnVersion(): " << GetProgramSvnVersion() << Endl;
+ Cout << "PrintProgramSvnVersion(): " << Endl; PrintProgramSvnVersion();
+ Cout << "GetArcadiaSourcePath(): " << GetArcadiaSourcePath() << Endl;
+ Cout << "GetArcadiaSourceUrl(): " << GetArcadiaSourceUrl() << Endl;
+ Cout << "GetArcadiaLastChange(): " << GetArcadiaLastChange() << Endl;
+ Cout << "GetArcadiaLastChangeNum(): " << GetArcadiaLastChangeNum() << Endl;
+ Cout << "GetArcadiaLastAuthor(): " << GetArcadiaLastAuthor() << Endl;
+ Cout << "GetProgramSvnRevision(): " << GetProgramSvnRevision() << Endl;
+ Cout << "GetProgramHash(): " << GetProgramHash() << Endl;
+ Cout << "GetProgramCommitId(): " << GetProgramCommitId() << Endl;
+ Cout << "GetProgramScmData(): " << GetProgramScmData() << Endl;
+ Cout << "GetProgramBuildUser(): " << GetProgramBuildUser() << Endl;
+ Cout << "GetProgramBuildHost(): " << GetProgramBuildHost() << Endl;
+ Cout << "GetProgramBuildDate(): " << GetProgramBuildDate() << Endl;
+ Cout << "GetVCS(): " << GetVCS() << Endl;
+ Cout << "GetBranch(): " << GetBranch() << Endl;
+ Cout << "GetTag(): " << GetTag() << Endl;
+ Cout << "GetArcadiaPatchNumber(): " << GetArcadiaPatchNumber() << Endl;
+ Cout << "GetVCSDirty(): " << GetVCSDirty() << Endl;
+ return 0;
+}
+
diff --git a/library/cpp/svnversion/test/ya.make b/library/cpp/svnversion/test/ya.make
new file mode 100644
index 0000000000..59c0a2d970
--- /dev/null
+++ b/library/cpp/svnversion/test/ya.make
@@ -0,0 +1,6 @@
+OWNER(g:cpp-contrib)
+
+PROGRAM()
+PEERDIR(library/cpp/svnversion)
+SRCS(main.cpp)
+END()
diff --git a/library/cpp/svnversion/ya.make b/library/cpp/svnversion/ya.make
new file mode 100644
index 0000000000..04e1a4c4fd
--- /dev/null
+++ b/library/cpp/svnversion/ya.make
@@ -0,0 +1,12 @@
+OWNER(g:cpp-contrib)
+
+LIBRARY()
+
+SRCS(
+ svnversion.cpp
+ svn_interface.c
+)
+END()
+RECURSE(
+ test
+)
diff --git a/library/cpp/terminate_handler/sample/exception/main.cpp b/library/cpp/terminate_handler/sample/exception/main.cpp
new file mode 100644
index 0000000000..35bfae8874
--- /dev/null
+++ b/library/cpp/terminate_handler/sample/exception/main.cpp
@@ -0,0 +1,15 @@
+#include <util/generic/yexception.h>
+
+
+void Foo(unsigned i = 0) {
+ if (i >= 10) {
+ ythrow yexception() << "from Foo()";
+ } else {
+ Foo(i + 1);
+ }
+}
+
+int main() {
+ Foo();
+ return 0;
+}
diff --git a/library/cpp/terminate_handler/sample/exception/ya.make b/library/cpp/terminate_handler/sample/exception/ya.make
new file mode 100644
index 0000000000..958c26f89a
--- /dev/null
+++ b/library/cpp/terminate_handler/sample/exception/ya.make
@@ -0,0 +1,13 @@
+PROGRAM(exception_sample)
+
+OWNER(nga)
+
+SRCS(
+ main.cpp
+)
+
+PEERDIR(
+ library/cpp/terminate_handler
+)
+
+END()
diff --git a/library/cpp/terminate_handler/sample/pure-virtual/main.cpp b/library/cpp/terminate_handler/sample/pure-virtual/main.cpp
new file mode 100644
index 0000000000..58217d5f24
--- /dev/null
+++ b/library/cpp/terminate_handler/sample/pure-virtual/main.cpp
@@ -0,0 +1,22 @@
+
+struct TFoo {
+ TFoo() {
+ Baz();
+ }
+
+ void Baz() {
+ Bar();
+ }
+
+ virtual void Bar() = 0;
+};
+
+struct TQux: public TFoo {
+ void Bar() override {
+ }
+};
+
+int main() {
+ TQux();
+ return 0;
+}
diff --git a/library/cpp/terminate_handler/sample/pure-virtual/ya.make b/library/cpp/terminate_handler/sample/pure-virtual/ya.make
new file mode 100644
index 0000000000..4100da630d
--- /dev/null
+++ b/library/cpp/terminate_handler/sample/pure-virtual/ya.make
@@ -0,0 +1,13 @@
+PROGRAM()
+
+OWNER(nga)
+
+SRCS(
+ main.cpp
+)
+
+PEERDIR(
+ library/cpp/terminate_handler
+)
+
+END()
diff --git a/library/cpp/terminate_handler/sample/rethrow/main.cpp b/library/cpp/terminate_handler/sample/rethrow/main.cpp
new file mode 100644
index 0000000000..fcd8592613
--- /dev/null
+++ b/library/cpp/terminate_handler/sample/rethrow/main.cpp
@@ -0,0 +1,20 @@
+#include <util/generic/yexception.h>
+
+
+void Bar() {
+ ythrow yexception() << "from Foo()";
+}
+
+void Foo() {
+ try {
+ Bar();
+ } catch (...) {
+ Cerr << "caught; rethrowing\n";
+ throw;
+ }
+}
+
+int main() {
+ Foo();
+ return 0;
+}
diff --git a/library/cpp/terminate_handler/sample/rethrow/ya.make b/library/cpp/terminate_handler/sample/rethrow/ya.make
new file mode 100644
index 0000000000..4100da630d
--- /dev/null
+++ b/library/cpp/terminate_handler/sample/rethrow/ya.make
@@ -0,0 +1,13 @@
+PROGRAM()
+
+OWNER(nga)
+
+SRCS(
+ main.cpp
+)
+
+PEERDIR(
+ library/cpp/terminate_handler
+)
+
+END()
diff --git a/library/cpp/terminate_handler/sample/segv/main.cpp b/library/cpp/terminate_handler/sample/segv/main.cpp
new file mode 100644
index 0000000000..52851bdb19
--- /dev/null
+++ b/library/cpp/terminate_handler/sample/segv/main.cpp
@@ -0,0 +1,15 @@
+#include "../../segv_handler.h"
+
+void Bar(int* x) {
+ *x = 11;
+}
+
+void Foo(int* x) {
+ Bar(x);
+}
+
+int main() {
+ InstallSegvHandler();
+ Foo((int*)1);
+ return 0;
+}
diff --git a/library/cpp/terminate_handler/sample/segv/ya.make b/library/cpp/terminate_handler/sample/segv/ya.make
new file mode 100644
index 0000000000..4100da630d
--- /dev/null
+++ b/library/cpp/terminate_handler/sample/segv/ya.make
@@ -0,0 +1,13 @@
+PROGRAM()
+
+OWNER(nga)
+
+SRCS(
+ main.cpp
+)
+
+PEERDIR(
+ library/cpp/terminate_handler
+)
+
+END()
diff --git a/library/cpp/terminate_handler/sample/ya.make b/library/cpp/terminate_handler/sample/ya.make
new file mode 100644
index 0000000000..af089abc65
--- /dev/null
+++ b/library/cpp/terminate_handler/sample/ya.make
@@ -0,0 +1,6 @@
+RECURSE(
+ exception
+ pure-virtual
+ rethrow
+ segv
+)
diff --git a/library/cpp/terminate_handler/segv_handler.cpp b/library/cpp/terminate_handler/segv_handler.cpp
new file mode 100644
index 0000000000..f24ece4125
--- /dev/null
+++ b/library/cpp/terminate_handler/segv_handler.cpp
@@ -0,0 +1,34 @@
+#include <util/system/platform.h>
+#include <util/system/yassert.h>
+#include <util/stream/output.h>
+#include <util/system/backtrace.h>
+
+#ifdef _unix_
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+
+#include "segv_handler.h"
+
+#ifndef _win_
+static void SegvHandler(int sig) {
+ Y_UNUSED(sig);
+ const char msg[] = "Got SEGV\n";
+ Y_UNUSED(write(STDERR_FILENO, msg, sizeof(msg)));
+ //PrintBackTrace();
+ sig_t r = signal(SIGSEGV, SIG_DFL);
+ if (r == SIG_ERR) {
+ abort();
+ }
+ // returning back and failing
+}
+#endif // !_win_
+
+void InstallSegvHandler() {
+#ifndef _win_
+ sig_t r = signal(SIGSEGV, &SegvHandler);
+ Y_VERIFY(r != SIG_ERR, "signal failed: %s", strerror(errno));
+#endif // !_win_
+}
diff --git a/library/cpp/terminate_handler/segv_handler.h b/library/cpp/terminate_handler/segv_handler.h
new file mode 100644
index 0000000000..c9f9051c7d
--- /dev/null
+++ b/library/cpp/terminate_handler/segv_handler.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void InstallSegvHandler();
diff --git a/library/cpp/terminate_handler/terminate_handler.cpp b/library/cpp/terminate_handler/terminate_handler.cpp
new file mode 100644
index 0000000000..d7e8fbed95
--- /dev/null
+++ b/library/cpp/terminate_handler/terminate_handler.cpp
@@ -0,0 +1,36 @@
+#include <cstdlib>
+#include <exception>
+
+#include <util/stream/output.h>
+#include <util/system/backtrace.h>
+#include <util/generic/yexception.h>
+
+namespace {
+ // Avoid infinite recursion if std::terminate is triggered anew by the
+ // FancyTerminateHandler.
+ thread_local int TerminateCount = 0;
+
+ void FancyTerminateHandler() {
+ switch (++TerminateCount) {
+ case 1:
+ break;
+ case 2:
+ Cerr << "FancyTerminateHandler called recursively" << Endl;
+ [[fallthrough]];
+ default:
+ abort();
+ break;
+ }
+
+ if (std::current_exception()) {
+ Cerr << "Uncaught exception: " << CurrentExceptionMessage() << '\n';
+ } else {
+ Cerr << "Terminate for unknown reason (no current exception)\n";
+ }
+ PrintBackTrace();
+ Cerr.Flush();
+ abort();
+ }
+
+ [[maybe_unused]] auto _ = std::set_terminate(&FancyTerminateHandler);
+}
diff --git a/library/cpp/terminate_handler/ya.make b/library/cpp/terminate_handler/ya.make
new file mode 100644
index 0000000000..70a9712fed
--- /dev/null
+++ b/library/cpp/terminate_handler/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(
+ ilnurkh
+ eeight
+)
+
+SRCS(
+ GLOBAL terminate_handler.cpp
+ segv_handler.cpp
+)
+
+END()
diff --git a/library/cpp/testing/README.md b/library/cpp/testing/README.md
new file mode 100644
index 0000000000..e8e0391be4
--- /dev/null
+++ b/library/cpp/testing/README.md
@@ -0,0 +1,16 @@
+В этой директории лежат библиотеки для удобного написания тестов на C++, а именно:
+
+* `benchmark` — библиотека для реализации простых бенчмарков.
+* `boost_test` — реализация тестирования средствами библиотеки _boost_. **Не используйте этот фреймворк в новом коде.**
+* `boost_test_main` — реализация (средствами библиотеки _boost_) функции `int main(argc, argv)` для модуля `BOOSTTEST`. **Не используйте этот фреймворк в новом коде.**
+* `common` — независимые вспомогательные функции. Например функции для получения аркадийных путей.
+* `gmock` — прокси-библиотека для подключения `contrib/resticted/googltest/googlemock` без нарушения PEERDIR policy.
+* `gtest` — реализация модуля `GTEST` — средства для интеграции фреймворка _googletest_ в Аркадию.
+* `gtest_boost_extensions` — расширения gtest и gmock, улучшающие поддержку типов из boost.
+* `gtest_extensions` — расширения gtest и gmock, улучшающие поддержку Аркадийных типов. Все расширения включены в модуле `GTEST` по-умолчаниiю.
+* `gtest_main` — реализация `int main(argc, argv)` для модуля `GTEST` (вынесена в отдельную библиотеку, чтобы в перспективе была возможна реализация `GTEST_WITH_CUSTOM_ENTRY_POINT`).
+* `gtest_protobuf` — утилиты для работы с протобуфом в тестах.
+* `hook` — хуки для выполнения пользовательских функций в тестах и бенчмарках.
+* `mock_server` — реализация http-сервера для тестов.
+* `unittest` — реализация модуля UNITTEST — основного средства для тестирования тестов на С++ в Аркадии.
+* `unittest_main` — реализация `int main(argc, argv)` для модуля UNITTEST (она вынесена в отдельную библиотеку, чтобы оставить возможность для реализации `UNITTEST_WITH_CUSTOM_ENTRY_POINT` и `YT_UNITTEST`.
diff --git a/library/cpp/testing/benchmark/README.md b/library/cpp/testing/benchmark/README.md
new file mode 100644
index 0000000000..ad440e07a2
--- /dev/null
+++ b/library/cpp/testing/benchmark/README.md
@@ -0,0 +1,11 @@
+----------- YourBenchmarkName ---------------
+ samples: 403
+ iterations: 100576
+ iterations hr: 101K
+ run time: 5.016924443
+ per iteration: 119265.0829 (119K) cycles
+
+samples – сколько раз была вызвана функция с бенчмарком
+iterations – сколько всего итераций было сделано. при каждом вызове функции бенчмарка может быть разное кол-во итераций
+run time – скольку времени исполнялся бенчмарк
+per iteration – сколько времени (процессорных тактов) ушло на одну итерацию, в идеале это то сколько работает функция для которой ты написал бенчмарк \ No newline at end of file
diff --git a/library/cpp/testing/benchmark/bench.cpp b/library/cpp/testing/benchmark/bench.cpp
new file mode 100644
index 0000000000..08d8708005
--- /dev/null
+++ b/library/cpp/testing/benchmark/bench.cpp
@@ -0,0 +1,604 @@
+#include "bench.h"
+
+#include <contrib/libs/re2/re2/re2.h>
+
+#include <library/cpp/colorizer/output.h>
+#include <library/cpp/getopt/small/last_getopt.h>
+#include <library/cpp/json/json_value.h>
+#include <library/cpp/linear_regression/linear_regression.h>
+#include <library/cpp/threading/poor_man_openmp/thread_helper.h>
+
+#include <util/system/hp_timer.h>
+#include <util/system/info.h>
+#include <util/stream/output.h>
+#include <util/datetime/base.h>
+#include <util/random/random.h>
+#include <util/string/cast.h>
+#include <util/generic/xrange.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/singleton.h>
+#include <util/system/spinlock.h>
+#include <util/generic/function.h>
+#include <util/generic/maybe.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/intrlist.h>
+#include <util/stream/format.h>
+#include <util/system/yield.h>
+
+using re2::RE2;
+
+using namespace NBench;
+using namespace NColorizer;
+using namespace NLastGetopt;
+
+namespace {
+ struct TOptions {
+ double TimeBudget;
+ };
+
+ struct TResult {
+ TStringBuf TestName;
+ ui64 Samples;
+ ui64 Iterations;
+ TMaybe<double> CyclesPerIteration;
+ TMaybe<double> SecondsPerIteration;
+ double RunTime;
+ size_t TestId; // Sequential test id (zero-based)
+ };
+
+ struct ITestRunner: public TIntrusiveListItem<ITestRunner> {
+ virtual ~ITestRunner() = default;
+ void Register();
+
+ virtual TStringBuf Name() const noexcept = 0;
+ virtual TResult Run(const TOptions& opts) = 0;
+ size_t SequentialId = 0;
+ };
+
+ struct TCpuBenchmark: public ITestRunner {
+ inline TCpuBenchmark(const char* name, NCpu::TUserFunc func)
+ : F(func)
+ , N(name)
+ {
+ Register();
+ }
+
+ TResult Run(const TOptions& opts) override;
+
+ TStringBuf Name() const noexcept override {
+ return N;
+ }
+
+ std::function<NCpu::TUserFunc> F;
+ const TStringBuf N;
+ };
+
+ inline TString DoFmtTime(double t) {
+ if (t > 0.1) {
+ return ToString(t) + " seconds";
+ }
+
+ t *= 1000.0;
+
+ if (t > 0.1) {
+ return ToString(t) + " milliseconds";
+ }
+
+ t *= 1000.0;
+
+ if (t > 0.1) {
+ return ToString(t) + " microseconds";
+ }
+
+ t *= 1000.0;
+
+ if (t < 0.05) {
+ t = 0.0;
+ }
+
+ return ToString(t) + " nanoseconds";
+ }
+
+ struct THiPerfTimer: public THPTimer {
+ static inline TString FmtTime(double t) {
+ return DoFmtTime(t);
+ }
+ };
+
+ struct TSimpleTimer {
+ inline double Passed() const noexcept {
+ return (TInstant::Now() - N).MicroSeconds() / 1000000.0;
+ }
+
+ static inline TString FmtTime(double t) {
+ return DoFmtTime(t);
+ }
+
+ const TInstant N = TInstant::Now();
+ };
+
+ struct TCycleTimer {
+ inline ui64 Passed() const noexcept {
+ return GetCycleCount() - N;
+ }
+
+ static inline TString FmtTime(double t) {
+ if (t < 0.5) {
+ t = 0.0;
+ }
+
+ TString hr;
+ if (t > 10 * 1000) {
+ hr = " (" + ToString(HumanReadableSize(t, ESizeFormat::SF_QUANTITY)) + ")";
+ }
+
+ return ToString(t) + hr + " cycles";
+ }
+
+ const ui64 N = GetCycleCount();
+ };
+
+ template <class TMyTimer, class T>
+ inline double Measure(T&& t, size_t n) {
+ TMyTimer timer;
+
+ t(n);
+
+ return timer.Passed();
+ }
+
+ struct TSampleIterator {
+ inline size_t Next() noexcept {
+ return M++;
+
+ N *= 1.02;
+ M += 1;
+
+ return Max<double>(N, M);
+ }
+
+ double N = 1.0;
+ size_t M = 1;
+ };
+
+ using TSample = std::pair<size_t, double>;
+ using TSamples = TVector<TSample>;
+
+ struct TLinFunc {
+ double A;
+ double B;
+
+ inline double operator()(double x) const noexcept {
+ return A * x + B;
+ }
+ };
+
+ TLinFunc CalcModel(const TSamples& s) {
+ TKahanSLRSolver solver;
+
+ for (const auto& p : s) {
+ solver.Add(p.first, p.second);
+ }
+
+ double c = 0;
+ double i = 0;
+
+ solver.Solve(c, i);
+
+ return TLinFunc{c, i};
+ }
+
+ inline TSamples RemoveOutliers(const TSamples& s, double fraction) {
+ if (s.size() < 20) {
+ return s;
+ }
+
+ const auto predictor = CalcModel(s);
+
+ const auto errfunc = [&predictor](const TSample& p) -> double {
+ //return (1.0 + fabs(predictor(p.first) - p.second)) / (1.0 + fabs(p.second));
+ //return fabs((predictor(p.first) - p.second)) / (1.0 + fabs(p.second));
+ //return fabs((predictor(p.first) - p.second)) / (1.0 + p.first);
+ return fabs((predictor(p.first) - p.second));
+ };
+
+ using TSampleWithError = std::pair<const TSample*, double>;
+ TVector<TSampleWithError> v;
+
+ v.reserve(s.size());
+
+ for (const auto& p : s) {
+ v.emplace_back(&p, errfunc(p));
+ }
+
+ Sort(v.begin(), v.end(), [](const TSampleWithError& l, const TSampleWithError& r) -> bool {
+ return (l.second < r.second) || ((l.second == r.second) && (l.first < r.first));
+ });
+
+ if (0) {
+ for (const auto& x : v) {
+ Cout << x.first->first << ", " << x.first->second << " -> " << x.second << Endl;
+ }
+ }
+
+ TSamples ret;
+
+ ret.reserve(v.size());
+
+ for (const auto i : xrange<size_t>(0, fraction * v.size())) {
+ ret.push_back(*v[i].first);
+ }
+
+ return ret;
+ }
+
+ template <class TMyTimer, class T>
+ static inline TResult RunTest(T&& func, double budget, ITestRunner& test) {
+ THPTimer start;
+
+ start.Passed();
+
+ TSampleIterator sample;
+ TSamples samples;
+ ui64 iters = 0;
+
+ //warm up
+ func(1);
+
+ while (start.Passed() < budget) {
+ if (start.Passed() < ((budget * samples.size()) / 2000000.0)) {
+ ThreadYield();
+ } else {
+ const size_t n = sample.Next();
+
+ iters += (ui64)n;
+ samples.emplace_back(n, Measure<TMyTimer>(func, n));
+ }
+ }
+
+ auto filtered = RemoveOutliers(samples, 0.9);
+
+ return {test.Name(), filtered.size(), iters, CalcModel(filtered).A, Nothing(), start.Passed(), test.SequentialId};
+ }
+
+ using TTests = TIntrusiveListWithAutoDelete<ITestRunner, TDestructor>;
+
+ inline TTests& Tests() {
+ return *Singleton<TTests>();
+ }
+
+ void ITestRunner::Register() {
+ Tests().PushBack(this);
+ }
+
+ TResult TCpuBenchmark::Run(const TOptions& opts) {
+ return RunTest<TCycleTimer>([this](size_t n) {
+ NCpu::TParams params{n};
+
+ F(params);
+ }, opts.TimeBudget, *this);
+ }
+
+ enum EOutFormat {
+ F_CONSOLE = 0 /* "console" */,
+ F_CSV /* "csv" */,
+ F_JSON /* "json" */
+ };
+
+ TAdaptiveLock STDOUT_LOCK;
+
+ struct IReporter {
+ virtual void Report(TResult&& result) = 0;
+
+ virtual void Finish() {
+ }
+
+ virtual ~IReporter() {
+ }
+ };
+
+ class TConsoleReporter: public IReporter {
+ public:
+ ~TConsoleReporter() override {
+ }
+
+ void Report(TResult&& r) override {
+ with_lock (STDOUT_LOCK) {
+ Cout << r;
+ }
+ }
+ };
+
+ class TCSVReporter: public IReporter {
+ public:
+ TCSVReporter() {
+ Cout << "Name\tSamples\tIterations\tRun_time\tPer_iteration_sec\tPer_iteration_cycles" << Endl;
+ }
+
+ ~TCSVReporter() override {
+ }
+
+ void Report(TResult&& r) override {
+ with_lock (STDOUT_LOCK) {
+ Cout << r.TestName
+ << '\t' << r.Samples
+ << '\t' << r.Iterations
+ << '\t' << r.RunTime;
+
+ Cout << '\t';
+ if (r.CyclesPerIteration) {
+ Cout << TCycleTimer::FmtTime(*r.CyclesPerIteration);
+ } else {
+ Cout << '-';
+ }
+
+ Cout << '\t';
+ if (r.SecondsPerIteration) {
+ Cout << DoFmtTime(*r.SecondsPerIteration);
+ } else {
+ Cout << '-';
+ }
+
+ Cout << Endl;
+ }
+ }
+ };
+
+ class TJSONReporter: public IReporter {
+ public:
+ ~TJSONReporter() override {
+ }
+
+ void Report(TResult&& r) override {
+ with_lock (ResultsLock_) {
+ Results_.emplace_back(std::move(r));
+ }
+ }
+
+ void Finish() override {
+ NJson::TJsonValue report;
+ auto& bench = report["benchmark"];
+ bench.SetType(NJson::JSON_ARRAY);
+
+ NJson::TJsonValue benchReport;
+
+ for (const auto& result : Results_) {
+ NJson::TJsonValue{}.Swap(benchReport);
+ benchReport["name"] = result.TestName;
+ benchReport["samples"] = result.Samples;
+ benchReport["run_time"] = result.RunTime;
+
+ if (result.CyclesPerIteration) {
+ benchReport["per_iteration_cycles"] = *result.CyclesPerIteration;
+ }
+
+ if (result.SecondsPerIteration) {
+ benchReport["per_iteration_secons"] = *result.SecondsPerIteration;
+ }
+
+ bench.AppendValue(benchReport);
+ }
+
+ Cout << report << Endl;
+ }
+
+ private:
+ TAdaptiveLock ResultsLock_;
+ TVector<TResult> Results_;
+ };
+
+ class TOrderedReporter: public IReporter {
+ public:
+ TOrderedReporter(THolder<IReporter> slave)
+ : Slave_(std::move(slave))
+ {
+ }
+
+ void Report(TResult&& result) override {
+ with_lock (ResultsLock_) {
+ OrderedResultQueue_.emplace(result.TestId, std::move(result));
+ while (!OrderedResultQueue_.empty() && OrderedResultQueue_.begin()->first <= ExpectedTestId_) {
+ Slave_->Report(std::move(OrderedResultQueue_.begin()->second));
+ OrderedResultQueue_.erase(OrderedResultQueue_.begin());
+ ++ExpectedTestId_;
+ }
+ }
+ }
+
+ void Finish() override {
+ for (auto& it : OrderedResultQueue_) {
+ Slave_->Report(std::move(it.second));
+ }
+ OrderedResultQueue_.clear();
+ Slave_->Finish();
+ }
+
+ private:
+ THolder<IReporter> Slave_;
+ size_t ExpectedTestId_ = 0;
+ TMap<size_t, TResult> OrderedResultQueue_;
+ TAdaptiveLock ResultsLock_;
+ };
+
+ THolder<IReporter> MakeReporter(const EOutFormat type) {
+ switch (type) {
+ case F_CONSOLE:
+ return MakeHolder<TConsoleReporter>();
+
+ case F_CSV:
+ return MakeHolder<TCSVReporter>();
+
+ case F_JSON:
+ return MakeHolder<TJSONReporter>();
+
+ default:
+ break;
+ }
+
+ return MakeHolder<TConsoleReporter>(); // make compiler happy
+ }
+
+ THolder<IReporter> MakeOrderedReporter(const EOutFormat type) {
+ return MakeHolder<TOrderedReporter>(MakeReporter(type));
+ }
+
+ void EnumerateTests(TVector<ITestRunner*>& tests) {
+ for (size_t id : xrange(tests.size())) {
+ tests[id]->SequentialId = id;
+ }
+ }
+}
+
+template <>
+EOutFormat FromStringImpl<EOutFormat>(const char* data, size_t len) {
+ const auto s = TStringBuf{data, len};
+
+ if (TStringBuf("console") == s) {
+ return F_CONSOLE;
+ } else if (TStringBuf("csv") == s) {
+ return F_CSV;
+ } else if (TStringBuf("json") == s) {
+ return F_JSON;
+ }
+
+ ythrow TFromStringException{} << "failed to convert '" << s << '\'';
+}
+
+template <>
+void Out<TResult>(IOutputStream& out, const TResult& r) {
+ out << "----------- " << LightRed() << r.TestName << Old() << " ---------------" << Endl
+ << " samples: " << White() << r.Samples << Old() << Endl
+ << " iterations: " << White() << r.Iterations << Old() << Endl
+ << " iterations hr: " << White() << HumanReadableSize(r.Iterations, SF_QUANTITY) << Old() << Endl
+ << " run time: " << White() << r.RunTime << Old() << Endl;
+
+ if (r.CyclesPerIteration) {
+ out << " per iteration: " << White() << TCycleTimer::FmtTime(*r.CyclesPerIteration) << Old() << Endl;
+ }
+
+ if (r.SecondsPerIteration) {
+ out << " per iteration: " << White() << DoFmtTime(*r.SecondsPerIteration) << Old() << Endl;
+ }
+}
+
+NCpu::TRegistar::TRegistar(const char* name, TUserFunc func) {
+ static_assert(sizeof(TCpuBenchmark) + alignof(TCpuBenchmark) < sizeof(Buf), "fix Buf size");
+
+ new (AlignUp(Buf, alignof(TCpuBenchmark))) TCpuBenchmark(name, func);
+}
+
+namespace {
+ struct TProgOpts {
+ TProgOpts(int argc, char** argv) {
+ TOpts opts = TOpts::Default();
+
+ opts.AddHelpOption();
+
+ opts.AddLongOption('b', "budget")
+ .StoreResult(&TimeBudget)
+ .RequiredArgument("SEC")
+ .Optional()
+ .Help("overall time budget");
+
+ opts.AddLongOption('l', "list")
+ .NoArgument()
+ .StoreValue(&ListTests, true)
+ .Help("list all tests");
+
+ opts.AddLongOption('t', "threads")
+ .StoreResult(&Threads)
+ .OptionalValue(ToString((NSystemInfo::CachedNumberOfCpus() + 1) / 2), "JOBS")
+ .DefaultValue("1")
+ .Help("run benchmarks in parallel");
+
+ opts.AddLongOption('f', "format")
+ .AddLongName("benchmark_format")
+ .StoreResult(&OutFormat)
+ .RequiredArgument("FORMAT")
+ .DefaultValue("console")
+ .Help("output format (console|csv|json)");
+
+ opts.SetFreeArgDefaultTitle("REGEXP", "RE2 regular expression to filter tests");
+
+ const TOptsParseResult parseResult{&opts, argc, argv};
+
+ for (const auto& regexp : parseResult.GetFreeArgs()) {
+ Filters.push_back(MakeHolder<RE2>(regexp.data(), RE2::Quiet));
+ Y_ENSURE(Filters.back()->ok(), "incorrect RE2 expression '" << regexp << "'");
+ }
+ }
+
+ bool MatchFilters(const TStringBuf& name) const {
+ if (!Filters) {
+ return true;
+ }
+
+ for (auto&& re : Filters) {
+ if (RE2::FullMatchN({name.data(), name.size()}, *re, nullptr, 0)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool ListTests = false;
+ double TimeBudget = -1.0;
+ TVector<THolder<RE2>> Filters;
+ size_t Threads = 0;
+ EOutFormat OutFormat;
+ };
+}
+
+int NBench::Main(int argc, char** argv) {
+ const TProgOpts opts(argc, argv);
+
+ TVector<ITestRunner*> tests;
+
+ for (auto&& it : Tests()) {
+ if (opts.MatchFilters(it.Name())) {
+ tests.push_back(&it);
+ }
+ }
+ EnumerateTests(tests);
+
+ if (opts.ListTests) {
+ for (const auto* const it : tests) {
+ Cout << it->Name() << Endl;
+ }
+
+ return 0;
+ }
+
+ if (!tests) {
+ return 0;
+ }
+
+ double timeBudget = opts.TimeBudget;
+
+ if (timeBudget < 0) {
+ timeBudget = 5.0 * tests.size();
+ }
+
+ const TOptions testOpts = {timeBudget / tests.size()};
+ const auto reporter = MakeOrderedReporter(opts.OutFormat);
+
+ std::function<void(ITestRunner**)> func = [&](ITestRunner** it) {
+ auto&& res = (*it)->Run(testOpts);
+
+ reporter->Report(std::move(res));
+ };
+
+ if (opts.Threads > 1) {
+ NYmp::SetThreadCount(opts.Threads);
+ NYmp::ParallelForStaticChunk(tests.data(), tests.data() + tests.size(), 1, func);
+ } else {
+ for (auto it : tests) {
+ func(&it);
+ }
+ }
+
+ reporter->Finish();
+
+ return 0;
+}
diff --git a/library/cpp/testing/benchmark/bench.h b/library/cpp/testing/benchmark/bench.h
new file mode 100644
index 0000000000..21551ad0dd
--- /dev/null
+++ b/library/cpp/testing/benchmark/bench.h
@@ -0,0 +1,92 @@
+#pragma once
+
+#include <util/system/compiler.h>
+#include <util/system/types.h>
+
+#include <utility>
+
+namespace NBench {
+ namespace NCpu {
+ struct TParams {
+ inline size_t Iterations() const noexcept {
+ return Iterations_;
+ }
+
+ const size_t Iterations_;
+ };
+
+ using TUserFunc = void(TParams&);
+
+ struct TRegistar {
+ TRegistar(const char* name, TUserFunc func);
+
+ char Buf[128];
+ };
+ }
+
+ /**
+ * Functions that states "I can read and write everywhere in memory".
+ *
+ * Use it to prevent optimizer from reordering or discarding memory writes prior to it's call,
+ * and force memory reads after it's call.
+ */
+ void Clobber();
+
+ /**
+ * Forces whatever `p` points to be in memory and not in register.
+ *
+ * @param Pointer to data.
+ */
+ template <typename T>
+ void Escape(T* p);
+
+#if defined(__GNUC__)
+ Y_FORCE_INLINE void Clobber() {
+ asm volatile(""
+ :
+ :
+ : "memory");
+ }
+#elif defined(_MSC_VER)
+ Y_FORCE_INLINE void Clobber() {
+ _ReadWriteBarrier();
+ }
+
+#else
+ Y_FORCE_INLINE void Clobber() {
+ }
+#endif
+
+#if defined(__GNUC__)
+ template <typename T>
+ Y_FORCE_INLINE void Escape(T* p) {
+ asm volatile(""
+ :
+ : "g"(p)
+ : "memory");
+ }
+#else
+ template <typename T>
+ Y_FORCE_INLINE void Escape(T*) {
+ }
+#endif
+
+ /**
+ * Use this function to prevent unused variables elimination.
+ *
+ * @param Unused variable (e.g. return value of benchmarked function).
+ */
+ template <typename T>
+ Y_FORCE_INLINE void DoNotOptimize(T&& datum) {
+ ::DoNotOptimizeAway(std::forward<T>(datum));
+ }
+
+ int Main(int argc, char** argv);
+}
+
+#define Y_CPU_BENCHMARK(name, cnt) \
+ namespace N_bench_##name { \
+ static void Run(::NBench::NCpu::TParams&); \
+ const ::NBench::NCpu::TRegistar benchmark(#name, &Run); \
+ } \
+ static void N_bench_##name::Run(::NBench::NCpu::TParams& cnt)
diff --git a/library/cpp/testing/benchmark/dummy.cpp b/library/cpp/testing/benchmark/dummy.cpp
new file mode 100644
index 0000000000..cdb05c19db
--- /dev/null
+++ b/library/cpp/testing/benchmark/dummy.cpp
@@ -0,0 +1,8 @@
+#include "bench.h"
+
+namespace NBench {
+ namespace NPrivate {
+ void UseCharPointer(volatile const char*) {
+ }
+ }
+}
diff --git a/library/cpp/testing/benchmark/examples/main.cpp b/library/cpp/testing/benchmark/examples/main.cpp
new file mode 100644
index 0000000000..ddd8b05ffc
--- /dev/null
+++ b/library/cpp/testing/benchmark/examples/main.cpp
@@ -0,0 +1,215 @@
+#include <library/cpp/testing/benchmark/bench.h>
+
+#include <util/generic/xrange.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+#include <util/generic/bt_exception.h>
+
+Y_CPU_BENCHMARK(F, iface) {
+ TVector<size_t> x;
+
+ x.reserve(iface.Iterations());
+
+ for (size_t i = 0; i < iface.Iterations(); ++i) {
+ x.push_back(i);
+ }
+}
+
+Y_CPU_BENCHMARK(EmptyF, iface) {
+ (void)iface;
+}
+
+Y_CPU_BENCHMARK(AlmostEmptyF, iface) {
+ (void)iface;
+
+ TVector<size_t> x;
+ x.resize(1);
+}
+
+Y_CPU_BENCHMARK(TestThrow, iface) {
+ for (size_t i = 0; i < iface.Iterations(); ++i) {
+ try {
+ ythrow yexception() << i;
+ } catch (...) {
+ //CurrentExceptionMessage();
+ }
+ }
+}
+
+Y_CPU_BENCHMARK(TestThrowBT, iface) {
+ for (size_t i = 0; i < iface.Iterations(); ++i) {
+ try {
+ ythrow TWithBackTrace<yexception>() << i;
+ } catch (...) {
+ //CurrentExceptionMessage();
+ }
+ }
+}
+
+Y_CPU_BENCHMARK(TestThrowCatch, iface) {
+ for (size_t i = 0; i < iface.Iterations(); ++i) {
+ try {
+ ythrow yexception() << i;
+ } catch (...) {
+ Y_DO_NOT_OPTIMIZE_AWAY(CurrentExceptionMessage());
+ }
+ }
+}
+
+Y_CPU_BENCHMARK(TestThrowCatchBT, iface) {
+ for (size_t i = 0; i < iface.Iterations(); ++i) {
+ try {
+ ythrow TWithBackTrace<yexception>() << i;
+ } catch (...) {
+ Y_DO_NOT_OPTIMIZE_AWAY(CurrentExceptionMessage());
+ }
+ }
+}
+
+Y_CPU_BENCHMARK(TestRobust, iface) {
+ if (iface.Iterations() % 100 == 0) {
+ usleep(100000);
+ }
+}
+
+Y_CPU_BENCHMARK(IterationSpeed, iface) {
+ const auto n = iface.Iterations();
+
+ for (size_t i = 0; i < n; ++i) {
+ Y_DO_NOT_OPTIMIZE_AWAY(i);
+ }
+}
+
+Y_CPU_BENCHMARK(XRangeSpeed, iface) {
+ for (auto i : xrange<size_t>(0, iface.Iterations())) {
+ Y_DO_NOT_OPTIMIZE_AWAY(i);
+ }
+}
+
+Y_NO_INLINE int FFF() {
+ return 0;
+}
+
+Y_NO_INLINE int FFF(int x) {
+ return x;
+}
+
+Y_NO_INLINE int FFF(int x, int y) {
+ return x + y;
+}
+
+Y_NO_INLINE size_t FS1(TStringBuf x) {
+ return x.size();
+}
+
+Y_NO_INLINE size_t FS1_2(TStringBuf x, TStringBuf y) {
+ return x.size() + y.size();
+}
+
+Y_NO_INLINE size_t FS2(const TStringBuf& x) {
+ return x.size();
+}
+
+Y_NO_INLINE size_t FS2_2(const TStringBuf& x, const TStringBuf& y) {
+ return x.size() + y.size();
+}
+
+Y_CPU_BENCHMARK(FunctionCallCost_StringBufVal1, iface) {
+ TStringBuf x;
+
+ for (auto i : xrange<size_t>(0, iface.Iterations())) {
+ (void)i;
+ NBench::Escape(&x);
+ Y_DO_NOT_OPTIMIZE_AWAY(FS1(x));
+ NBench::Clobber();
+ }
+}
+
+Y_CPU_BENCHMARK(FunctionCallCost_StringBufRef1, iface) {
+ TStringBuf x;
+
+ for (auto i : xrange<size_t>(0, iface.Iterations())) {
+ (void)i;
+ NBench::Escape(&x);
+ Y_DO_NOT_OPTIMIZE_AWAY(FS2(x));
+ NBench::Clobber();
+ }
+}
+
+Y_CPU_BENCHMARK(FunctionCallCost_StringBufVal2, iface) {
+ TStringBuf x;
+ TStringBuf y;
+
+ for (auto i : xrange<size_t>(0, iface.Iterations())) {
+ (void)i;
+ NBench::Escape(&x);
+ NBench::Escape(&y);
+ Y_DO_NOT_OPTIMIZE_AWAY(FS1_2(x, y));
+ NBench::Clobber();
+ }
+}
+
+Y_CPU_BENCHMARK(FunctionCallCost_StringBufRef2, iface) {
+ TStringBuf x;
+ TStringBuf y;
+
+ for (auto i : xrange<size_t>(0, iface.Iterations())) {
+ (void)i;
+ NBench::Escape(&x);
+ NBench::Escape(&y);
+ Y_DO_NOT_OPTIMIZE_AWAY(FS2_2(x, y));
+ NBench::Clobber();
+ }
+}
+
+Y_CPU_BENCHMARK(FunctionCallCost_NoArg, iface) {
+ for (auto i : xrange<size_t>(0, iface.Iterations())) {
+ (void)i;
+ Y_DO_NOT_OPTIMIZE_AWAY(FFF());
+ }
+}
+
+Y_CPU_BENCHMARK(FunctionCallCost_OneArg, iface) {
+ for (auto i : xrange<size_t>(0, iface.Iterations())) {
+ Y_DO_NOT_OPTIMIZE_AWAY(FFF(i));
+ }
+}
+
+Y_CPU_BENCHMARK(FunctionCallCost_TwoArg, iface) {
+ for (auto i : xrange<size_t>(0, iface.Iterations())) {
+ Y_DO_NOT_OPTIMIZE_AWAY(FFF(i, i));
+ }
+}
+
+/* An example of incorrect benchmark. As of r2581591 Clang 3.7 produced following assembly:
+ * @code
+ * │ push %rbp
+ * │ mov %rsp,%rbp
+ * │ push %rbx
+ * │ push %rax
+ * │ mov (%rdi),%rbx
+ * │ test %rbx,%rbx
+ * │ ↓ je 25
+ * │ xor %edi,%edi
+ * │ xor %esi,%esi
+ * │ → callq FS1(TBasicStringBuf<char, std::char_traits<char
+ * │ nop
+ * 100.00 │20:┌─→dec %rbx
+ * │ └──jne 20
+ * │25: add $0x8,%rsp
+ * │ pop %rbx
+ * │ pop %rbp
+ * │ ← retq
+ * @endcode
+ *
+ * So, this benchmark is measuring empty loop!
+ */
+Y_CPU_BENCHMARK(Incorrect_FunctionCallCost_StringBufVal1, iface) {
+ TStringBuf x;
+
+ for (auto i : xrange<size_t>(0, iface.Iterations())) {
+ (void)i;
+ Y_DO_NOT_OPTIMIZE_AWAY(FS1(x));
+ }
+}
diff --git a/library/cpp/testing/benchmark/examples/metrics/main.py b/library/cpp/testing/benchmark/examples/metrics/main.py
new file mode 100644
index 0000000000..8f9d9d06ae
--- /dev/null
+++ b/library/cpp/testing/benchmark/examples/metrics/main.py
@@ -0,0 +1,7 @@
+import yatest.common as yc
+
+
+def test_export_metrics(metrics):
+ metrics.set_benchmark(yc.execute_benchmark(
+ 'library/cpp/testing/benchmark/examples/examples',
+ threads=8))
diff --git a/library/cpp/testing/benchmark/examples/metrics/ya.make b/library/cpp/testing/benchmark/examples/metrics/ya.make
new file mode 100644
index 0000000000..a9dbdca9fa
--- /dev/null
+++ b/library/cpp/testing/benchmark/examples/metrics/ya.make
@@ -0,0 +1,20 @@
+OWNER(
+ pg
+ yazevnul
+)
+
+PY2TEST()
+
+SIZE(LARGE)
+
+TAG(
+ ya:force_sandbox
+ sb:intel_e5_2660v1
+ ya:fat
+)
+
+TEST_SRCS(main.py)
+
+DEPENDS(library/cpp/testing/benchmark/examples)
+
+END()
diff --git a/library/cpp/testing/benchmark/examples/ya.make b/library/cpp/testing/benchmark/examples/ya.make
new file mode 100644
index 0000000000..7e696e127a
--- /dev/null
+++ b/library/cpp/testing/benchmark/examples/ya.make
@@ -0,0 +1,12 @@
+OWNER(
+ pg
+ yazevnul
+)
+
+Y_BENCHMARK()
+
+SRCS(
+ main.cpp
+)
+
+END()
diff --git a/library/cpp/testing/benchmark/main/main.cpp b/library/cpp/testing/benchmark/main/main.cpp
new file mode 100644
index 0000000000..aabcb89c43
--- /dev/null
+++ b/library/cpp/testing/benchmark/main/main.cpp
@@ -0,0 +1,16 @@
+#include <library/cpp/testing/benchmark/bench.h>
+
+#include <util/generic/yexception.h>
+#include <util/stream/output.h>
+
+#include <cstdlib>
+
+int main(int argc, char** argv) {
+ try {
+ return NBench::Main(argc, argv);
+ } catch (...) {
+ Cerr << CurrentExceptionMessage() << Endl;
+ }
+
+ return EXIT_FAILURE;
+}
diff --git a/library/cpp/testing/benchmark/main/ya.make b/library/cpp/testing/benchmark/main/ya.make
new file mode 100644
index 0000000000..d00cdcf9fc
--- /dev/null
+++ b/library/cpp/testing/benchmark/main/ya.make
@@ -0,0 +1,16 @@
+LIBRARY()
+
+OWNER(
+ pg
+ yazevnul
+)
+
+SRCS(
+ GLOBAL main.cpp
+)
+
+PEERDIR(
+ library/cpp/testing/benchmark
+)
+
+END()
diff --git a/library/cpp/testing/benchmark/ya.make b/library/cpp/testing/benchmark/ya.make
new file mode 100644
index 0000000000..f42be80698
--- /dev/null
+++ b/library/cpp/testing/benchmark/ya.make
@@ -0,0 +1,22 @@
+LIBRARY()
+
+OWNER(
+ pg
+ yazevnul
+)
+
+SRCS(
+ bench.cpp
+ dummy.cpp
+)
+
+PEERDIR(
+ contrib/libs/re2
+ library/cpp/colorizer
+ library/cpp/getopt/small
+ library/cpp/json
+ library/cpp/linear_regression
+ library/cpp/threading/poor_man_openmp
+)
+
+END()
diff --git a/library/cpp/testing/common/env.cpp b/library/cpp/testing/common/env.cpp
new file mode 100644
index 0000000000..fa3a47fe16
--- /dev/null
+++ b/library/cpp/testing/common/env.cpp
@@ -0,0 +1,275 @@
+#include "env.h"
+
+#include <build/scripts/c_templates/svnversion.h>
+
+#include <util/folder/dirut.h>
+#include <util/folder/path.h>
+#include <util/generic/singleton.h>
+#include <util/stream/file.h>
+#include <util/stream/fwd.h>
+#include <util/system/env.h>
+#include <util/system/file.h>
+#include <util/system/file_lock.h>
+#include <util/system/guard.h>
+
+#include <library/cpp/json/json_reader.h>
+#include <library/cpp/json/json_value.h>
+#include <library/cpp/json/json_writer.h>
+
+TString ArcadiaSourceRoot() {
+ if (const auto& sourceRoot = NPrivate::GetTestEnv().SourceRoot) {
+ return sourceRoot;
+ } else {
+ return GetArcadiaSourcePath();
+ }
+}
+
+TString BuildRoot() {
+ if (const auto& buildRoot = NPrivate::GetTestEnv().BuildRoot) {
+ return buildRoot;
+ } else {
+ return GetArcadiaSourcePath();
+ }
+}
+
+TString ArcadiaFromCurrentLocation(TStringBuf where, TStringBuf path) {
+ return (TFsPath(ArcadiaSourceRoot()) / TFsPath(where).Parent() / path).Fix();
+}
+
+TString BinaryPath(TStringBuf path) {
+ return (TFsPath(BuildRoot()) / path).Fix();
+}
+
+TString GetArcadiaTestsData() {
+ TString atdRoot = NPrivate::GetTestEnv().ArcadiaTestsDataDir;
+ if (atdRoot) {
+ return atdRoot;
+ }
+
+ TString path = NPrivate::GetCwd();
+ const char pathsep = GetDirectorySeparator();
+ while (!path.empty()) {
+ TString dataDir = path + "/arcadia_tests_data";
+ if (IsDir(dataDir)) {
+ return dataDir;
+ }
+
+ size_t pos = path.find_last_of(pathsep);
+ if (pos == TString::npos) {
+ pos = 0;
+ }
+ path.erase(pos);
+ }
+
+ return {};
+}
+
+TString GetWorkPath() {
+ TString workPath = NPrivate::GetTestEnv().WorkPath;
+ if (workPath) {
+ return workPath;
+ }
+
+ return NPrivate::GetCwd();
+}
+
+TFsPath GetOutputPath() {
+ return GetWorkPath() + "/testing_out_stuff";
+}
+
+const TString& GetRamDrivePath() {
+ return NPrivate::GetTestEnv().RamDrivePath;
+}
+
+const TString& GetYtHddPath() {
+ return NPrivate::GetTestEnv().YtHddPath;
+}
+
+const TString& GetOutputRamDrivePath() {
+ return NPrivate::GetTestEnv().TestOutputRamDrivePath;
+}
+
+const TString& GdbPath() {
+ return NPrivate::GetTestEnv().GdbPath;
+}
+
+const TString& GetTestParam(TStringBuf name) {
+ const static TString def = "";
+ return GetTestParam(name, def);
+}
+
+const TString& GetTestParam(TStringBuf name, const TString& def) {
+ auto& testParameters = NPrivate::GetTestEnv().TestParameters;
+ auto it = testParameters.find(name.data());
+ if (it != testParameters.end()) {
+ return it->second;
+ }
+ return def;
+}
+
+void AddEntryToCoreSearchFile(const TString& filename, TStringBuf cmd, int pid, const TFsPath& binaryPath = TFsPath(), const TFsPath& cwd = TFsPath()) {
+ auto lock = TFileLock(filename);
+ TGuard<TFileLock> guard(lock);
+
+ TOFStream output(TFile(filename, WrOnly | ForAppend | OpenAlways));
+
+ NJson::TJsonWriter writer(&output, false);
+ writer.OpenMap();
+ writer.Write("cmd", cmd);
+ writer.Write("pid", pid);
+ if (binaryPath) {
+ writer.Write("binary_path", binaryPath);
+ }
+ if (cwd) {
+ writer.Write("cwd", cwd);
+ }
+ writer.CloseMap();
+ writer.Flush();
+
+ output.Write("\n");
+}
+
+void WatchProcessCore(int pid, const TFsPath& binaryPath, const TFsPath& cwd) {
+ auto& filename = NPrivate::GetTestEnv().CoreSearchFile;
+ if (filename) {
+ AddEntryToCoreSearchFile(filename, "add", pid, binaryPath, cwd);
+ }
+}
+
+void StopProcessCoreWatching(int pid) {
+ auto& filename = NPrivate::GetTestEnv().CoreSearchFile;
+ if (filename) {
+ AddEntryToCoreSearchFile(filename, "drop", pid);
+ }
+}
+
+bool FromYaTest() {
+ return NPrivate::GetTestEnv().IsRunningFromTest;
+}
+
+namespace NPrivate {
+ TTestEnv::TTestEnv() {
+ ReInitialize();
+ }
+
+ void TTestEnv::ReInitialize() {
+ IsRunningFromTest = false;
+ ArcadiaTestsDataDir = "";
+ SourceRoot = "";
+ BuildRoot = "";
+ WorkPath = "";
+ RamDrivePath = "";
+ YtHddPath = "";
+ TestOutputRamDrivePath = "";
+ GdbPath = "";
+ CoreSearchFile = "";
+ TestParameters.clear();
+
+ const TString contextFilename = GetEnv("YA_TEST_CONTEXT_FILE");
+ if (contextFilename) {
+ NJson::TJsonValue context;
+ NJson::ReadJsonTree(TFileInput(contextFilename).ReadAll(), &context);
+
+ NJson::TJsonValue* value;
+
+ value = context.GetValueByPath("runtime.source_root");
+ if (value) {
+ SourceRoot = value->GetStringSafe("");
+ }
+
+ value = context.GetValueByPath("runtime.build_root");
+ if (value) {
+ BuildRoot = value->GetStringSafe("");
+ }
+
+ value = context.GetValueByPath("runtime.atd_root");
+ if (value) {
+ ArcadiaTestsDataDir = value->GetStringSafe("");
+ }
+
+ value = context.GetValueByPath("runtime.work_path");
+ if (value) {
+ WorkPath = value->GetStringSafe("");
+ }
+
+ value = context.GetValueByPath("runtime.ram_drive_path");
+ if (value) {
+ RamDrivePath = value->GetStringSafe("");
+ }
+
+ value = context.GetValueByPath("runtime.yt_hdd_path");
+ if (value) {
+ YtHddPath = value->GetStringSafe("");
+ }
+
+ value = context.GetValueByPath("runtime.test_output_ram_drive_path");
+ if (value) {
+ TestOutputRamDrivePath = value->GetStringSafe("");
+ }
+
+ value = context.GetValueByPath("runtime.gdb_bin");
+ if (value) {
+ GdbPath = value->GetStringSafe("");
+ }
+
+ value = context.GetValueByPath("runtime.test_params");
+ if (value) {
+ for (const auto& entry : context.GetValueByPath("runtime.test_params")->GetMap()) {
+ TestParameters[entry.first] = entry.second.GetStringSafe("");
+ }
+ }
+
+ value = context.GetValueByPath("internal.core_search_file");
+ if (value) {
+ CoreSearchFile = value->GetStringSafe("");
+ }
+ }
+
+ if (!YtHddPath) {
+ YtHddPath = GetEnv("HDD_PATH");
+ }
+
+ if (!SourceRoot) {
+ SourceRoot = GetEnv("ARCADIA_SOURCE_ROOT");
+ }
+
+ if (!BuildRoot) {
+ BuildRoot = GetEnv("ARCADIA_BUILD_ROOT");
+ }
+
+ if (!ArcadiaTestsDataDir) {
+ ArcadiaTestsDataDir = GetEnv("ARCADIA_TESTS_DATA_DIR");
+ }
+
+ if (!WorkPath) {
+ WorkPath = GetEnv("TEST_WORK_PATH");
+ }
+
+ if (!RamDrivePath) {
+ RamDrivePath = GetEnv("YA_TEST_RAM_DRIVE_PATH");
+ }
+
+ if (!TestOutputRamDrivePath) {
+ TestOutputRamDrivePath = GetEnv("YA_TEST_OUTPUT_RAM_DRIVE_PATH");
+ }
+
+ const TString fromEnv = GetEnv("YA_TEST_RUNNER");
+ IsRunningFromTest = (fromEnv == "1");
+ }
+
+ void TTestEnv::AddTestParam(TStringBuf name, TStringBuf value) {
+ TestParameters[TString{name}] = value;
+ }
+
+ TString GetCwd() {
+ try {
+ return NFs::CurrentWorkingDirectory();
+ } catch (...) {
+ return {};
+ }
+ }
+
+ const TTestEnv& GetTestEnv() {
+ return *Singleton<TTestEnv>();
+ }
+}
diff --git a/library/cpp/testing/common/env.h b/library/cpp/testing/common/env.h
new file mode 100644
index 0000000000..7b89aa1bed
--- /dev/null
+++ b/library/cpp/testing/common/env.h
@@ -0,0 +1,84 @@
+#pragma once
+
+#include <unordered_map>
+
+#include <util/folder/path.h>
+#include <util/generic/string.h>
+#include <util/generic/strbuf.h>
+#include <util/system/src_location.h>
+
+// @brief return full path to arcadia root
+TString ArcadiaSourceRoot();
+
+// @brief return full path for file or folder specified by known source location `where` and `path` which is relative to parent folder of `where`
+// for the instance: there is 2 files in folder test example_ut.cpp and example.data, so full path to test/example.data can be obtained
+// from example_ut.cpp as ArcadiaFromCurrentLocation(__SOURCE_FILE__, "example.data")
+TString ArcadiaFromCurrentLocation(TStringBuf where, TStringBuf path);
+
+// @brief return build folder path
+TString BuildRoot();
+
+// @brief return full path to built artefact, where path is relative from arcadia root
+TString BinaryPath(TStringBuf path);
+
+// @brief return true if environment is testenv otherwise false
+bool FromYaTest();
+
+// @brief returns TestsData dir (from env:ARCADIA_TESTS_DATA_DIR or path to existing folder `arcadia_tests_data` within parent folders)
+TString GetArcadiaTestsData();
+
+// @brief return current working dir (from env:TEST_WORK_PATH or cwd)
+TString GetWorkPath();
+
+// @brief return tests output path (workdir + testing_out_stuff)
+TFsPath GetOutputPath();
+
+// @brief return path from env:YA_TEST_RAM_DRIVE_PATH
+const TString& GetRamDrivePath();
+
+// @brief return path from env:YA_TEST_OUTPUT_RAM_DRIVE_PATH
+const TString& GetOutputRamDrivePath();
+
+// @brief return test parameter by name. If not exists, return an empty string
+const TString& GetTestParam(TStringBuf name);
+
+// @brief return test parameter by name. If not exists, return specified default value
+const TString& GetTestParam(TStringBuf name, const TString& def);
+
+// @brief return path to the gdb
+const TString& GdbPath();
+
+// @brief register the process. Test suite will be marked as failed if the process is terminated with a core dump file after testing
+void WatchProcessCore(int pid, const TFsPath& binaryPath, const TFsPath& cwd = TFsPath());
+
+// @brief mark the process as successfully completed - a test machinery won't try to recover core dump file for the process
+void StopProcessCoreWatching(int pid);
+
+#define SRC_(path) ArcadiaFromCurrentLocation(__SOURCE_FILE__, path)
+
+namespace NPrivate {
+ class TTestEnv {
+ public:
+ TTestEnv();
+
+ void ReInitialize();
+
+ void AddTestParam(TStringBuf name, TStringBuf value);
+
+ bool IsRunningFromTest;
+ TString ArcadiaTestsDataDir;
+ TString SourceRoot;
+ TString BuildRoot;
+ TString WorkPath;
+ TString RamDrivePath;
+ TString YtHddPath;
+ TString TestOutputRamDrivePath;
+ TString GdbPath;
+ TString CoreSearchFile;
+ std::unordered_map<TString, TString> TestParameters;
+ };
+
+ TString GetCwd();
+
+ const TTestEnv& GetTestEnv();
+}
diff --git a/library/cpp/testing/common/network.cpp b/library/cpp/testing/common/network.cpp
new file mode 100644
index 0000000000..230c50ee6d
--- /dev/null
+++ b/library/cpp/testing/common/network.cpp
@@ -0,0 +1,208 @@
+#include "network.h"
+
+#include <util/folder/dirut.h>
+#include <util/folder/path.h>
+#include <util/generic/singleton.h>
+#include <util/generic/utility.h>
+#include <util/generic/vector.h>
+#include <util/generic/ylimits.h>
+#include <util/network/address.h>
+#include <util/network/sock.h>
+#include <util/random/random.h>
+#include <util/stream/file.h>
+#include <util/string/split.h>
+#include <util/system/env.h>
+#include <util/system/error.h>
+#include <util/system/file_lock.h>
+#include <util/system/fs.h>
+
+#ifdef _darwin_
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
+
+namespace {
+#define Y_VERIFY_SYSERROR(expr) \
+ do { \
+ if (!(expr)) { \
+ Y_FAIL(#expr ", errno=%d", LastSystemError()); \
+ } \
+ } while (false)
+
+ class TPortGuard : public NTesting::IPort {
+ public:
+ TPortGuard(ui16 port, THolder<TFileLock> lock)
+ : Lock_(std::move(lock))
+ , Port_(port)
+ {
+ }
+
+ ~TPortGuard() override {
+ Y_VERIFY_SYSERROR(NFs::Remove(Lock_->GetName()));
+ }
+
+ ui16 Get() override {
+ return Port_;
+ }
+
+ private:
+ THolder<TFileLock> Lock_;
+ ui16 Port_;
+ };
+
+ std::pair<ui16, ui16> GetEphemeralRange() {
+ // IANA suggestion
+ std::pair<ui16, ui16> pair{(1 << 15) + (1 << 14), (1 << 16) - 1};
+ #ifdef _linux_
+ if (NFs::Exists("/proc/sys/net/ipv4/ip_local_port_range")) {
+ TIFStream fileStream("/proc/sys/net/ipv4/ip_local_port_range");
+ fileStream >> pair.first >> pair.second;
+ }
+ #endif
+ #ifdef _darwin_
+ ui32 first, last;
+ size_t size;
+ sysctlbyname("net.inet.ip.portrange.first", &first, &size, NULL, 0);
+ sysctlbyname("net.inet.ip.portrange.last", &last, &size, NULL, 0);
+ pair.first = first;
+ pair.second = last;
+ #endif
+ return pair;
+ }
+
+ TVector<std::pair<ui16, ui16>> GetPortRanges() {
+ TString givenRange = GetEnv("VALID_PORT_RANGE");
+ TVector<std::pair<ui16, ui16>> ranges;
+ if (givenRange.Contains(':')) {
+ auto res = StringSplitter(givenRange).Split(':').Limit(2).ToList<TString>();
+ ranges.emplace_back(FromString<ui16>(res.front()), FromString<ui16>(res.back()));
+ } else {
+ const ui16 firstValid = 1025;
+ const ui16 lastValid = Max<ui16>();
+
+ auto [firstEphemeral, lastEphemeral] = GetEphemeralRange();
+ const ui16 firstInvalid = Max(firstEphemeral, firstValid);
+ const ui16 lastInvalid = Min(lastEphemeral, lastValid);
+
+ if (firstInvalid > firstValid)
+ ranges.emplace_back(firstValid, firstInvalid - 1);
+ if (lastInvalid < lastValid)
+ ranges.emplace_back(lastInvalid + 1, lastValid);
+ }
+ return ranges;
+ }
+
+ class TPortManager {
+ static constexpr size_t Retries = 20;
+ public:
+ TPortManager()
+ : SyncDir_(GetEnv("PORT_SYNC_PATH"))
+ , Ranges_(GetPortRanges())
+ , TotalCount_(0)
+ {
+ if (!SyncDir_.IsDefined()) {
+ SyncDir_ = TFsPath(GetSystemTempDir()) / "yandex_port_locks";
+ }
+ Y_VERIFY(SyncDir_.IsDefined());
+ NFs::MakeDirectoryRecursive(SyncDir_);
+
+ for (auto [left, right] : Ranges_) {
+ TotalCount_ += right - left;
+ }
+ Y_VERIFY(0 != TotalCount_);
+ }
+
+ NTesting::TPortHolder GetFreePort() const {
+ ui16 salt = RandomNumber<ui16>();
+ for (ui16 attempt = 0; attempt < TotalCount_; ++attempt) {
+ ui16 probe = (salt + attempt) % TotalCount_;
+
+ for (auto [left, right] : Ranges_) {
+ if (probe >= right - left)
+ probe -= right - left;
+ else {
+ probe += left;
+ break;
+ }
+ }
+
+ auto port = TryAcquirePort(probe);
+ if (port) {
+ return NTesting::TPortHolder{std::move(port)};
+ }
+ }
+
+ Y_FAIL("Cannot get free port!");
+ }
+
+ TVector<NTesting::TPortHolder> GetFreePortsRange(size_t count) const {
+ Y_VERIFY(count > 0);
+ TVector<NTesting::TPortHolder> ports(Reserve(count));
+ for (size_t i = 0; i < Retries; ++i) {
+ for (auto[left, right] : Ranges_) {
+ if (right - left < count) {
+ continue;
+ }
+ ui16 start = left + RandomNumber<ui16>((right - left) / 2);
+ if (right - start < count) {
+ continue;
+ }
+ for (ui16 probe = start; probe < right; ++probe) {
+ auto port = TryAcquirePort(probe);
+ if (port) {
+ ports.emplace_back(std::move(port));
+ } else {
+ ports.clear();
+ }
+ if (ports.size() == count) {
+ return ports;
+ }
+ }
+ // Can't find required number of ports without gap in the current range
+ ports.clear();
+ }
+ }
+ Y_FAIL("Cannot get range of %zu ports!", count);
+ }
+
+ private:
+ THolder<NTesting::IPort> TryAcquirePort(ui16 port) const {
+ auto lock = MakeHolder<TFileLock>(TString(SyncDir_ / ::ToString(port)));
+ if (!lock->TryAcquire()) {
+ return nullptr;
+ }
+
+ TInet6StreamSocket sock;
+ Y_VERIFY_SYSERROR(INVALID_SOCKET != static_cast<SOCKET>(sock));
+
+ TSockAddrInet6 addr("::", port);
+ if (sock.Bind(&addr) != 0) {
+ lock->Release();
+ Y_VERIFY(EADDRINUSE == LastSystemError(), "unexpected error: %d", LastSystemError());
+ return nullptr;
+ }
+ return MakeHolder<TPortGuard>(port, std::move(lock));
+ }
+
+ private:
+ TFsPath SyncDir_;
+ TVector<std::pair<ui16, ui16>> Ranges_;
+ size_t TotalCount_;
+ };
+}
+
+namespace NTesting {
+ TPortHolder GetFreePort() {
+ return Singleton<TPortManager>()->GetFreePort();
+ }
+
+ namespace NLegacy {
+ TVector<TPortHolder> GetFreePortsRange(size_t count) {
+ return Singleton<TPortManager>()->GetFreePortsRange(count);
+ }
+ }
+
+ IOutputStream& operator<<(IOutputStream& out, const TPortHolder& port) {
+ return out << static_cast<ui16>(port);
+ }
+}
diff --git a/library/cpp/testing/common/network.h b/library/cpp/testing/common/network.h
new file mode 100644
index 0000000000..eb4d32f3a1
--- /dev/null
+++ b/library/cpp/testing/common/network.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+
+namespace NTesting {
+
+ //@brief network port holder interface
+ class IPort {
+ public:
+ virtual ~IPort() {}
+
+ virtual ui16 Get() = 0;
+ };
+
+ class TPortHolder : private THolder<IPort> {
+ using TBase = THolder<IPort>;
+ public:
+ using TBase::TBase;
+ using TBase::Release;
+ using TBase::Reset;
+
+ operator ui16() const& {
+ return (*this)->Get();
+ }
+
+ operator ui16() const&& = delete;
+ };
+
+ IOutputStream& operator<<(IOutputStream& out, const TPortHolder& port);
+
+ //@brief Get first free port.
+ [[nodiscard]] TPortHolder GetFreePort();
+
+ namespace NLegacy {
+ // Do not use this method, it needs only for TPortManager from unittests.
+ // Returns continuous sequence of the specified number of ports.
+ [[nodiscard]] TVector<TPortHolder> GetFreePortsRange(size_t count);
+ }
+
+ //@brief helper class for inheritance
+ struct TFreePortOwner {
+ TFreePortOwner() : Port_(GetFreePort()) {}
+
+ ui16 GetPort() const {
+ return Port_;
+ }
+
+ private:
+ TPortHolder Port_;
+ };
+}
diff --git a/library/cpp/testing/common/probe.cpp b/library/cpp/testing/common/probe.cpp
new file mode 100644
index 0000000000..73f2fb6360
--- /dev/null
+++ b/library/cpp/testing/common/probe.cpp
@@ -0,0 +1 @@
+#include "probe.h"
diff --git a/library/cpp/testing/common/probe.h b/library/cpp/testing/common/probe.h
new file mode 100644
index 0000000000..19910979b5
--- /dev/null
+++ b/library/cpp/testing/common/probe.h
@@ -0,0 +1,140 @@
+#pragma once
+
+#include <util/system/yassert.h>
+
+namespace NTesting {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ // Below there is a serie of probe classes for testing construction/destruction copying/moving of class.
+ // for examples see tests in probe_ut.cpp
+
+ struct TProbeState {
+ int Constructors = 0;
+ int Destructors = 0;
+ int ShadowDestructors = 0;
+ int CopyConstructors = 0;
+ int CopyAssignments = 0;
+ int MoveConstructors = 0;
+ int MoveAssignments = 0;
+ int Touches = 0;
+
+ TProbeState() = default;
+
+ void Reset() {
+ *this = TProbeState{};
+ }
+ };
+
+ // Used for probing the number of copies that occur if a type must be coerced.
+ class TCoercibleToProbe {
+ public:
+ TProbeState* State;
+ TProbeState* ShadowState;
+
+ public:
+ explicit TCoercibleToProbe(TProbeState* state)
+ : State(state)
+ , ShadowState(state)
+ {}
+
+ private:
+ TCoercibleToProbe(const TCoercibleToProbe&);
+ TCoercibleToProbe(TCoercibleToProbe&&);
+ TCoercibleToProbe& operator=(const TCoercibleToProbe&);
+ TCoercibleToProbe& operator=(TCoercibleToProbe&&);
+ };
+
+ // Used for probing the number of copies in an argument.
+ class TProbe {
+ public:
+ TProbeState* State;
+ TProbeState* ShadowState;
+
+ public:
+ static TProbe ExplicitlyCreateInvalidProbe() {
+ return TProbe();
+ }
+
+ explicit TProbe(TProbeState* state)
+ : State(state)
+ , ShadowState(state)
+ {
+ Y_ASSERT(State);
+ ++State->Constructors;
+ }
+
+ ~TProbe() {
+ if (State) {
+ ++State->Destructors;
+ }
+ if (ShadowState) {
+ ++ShadowState->ShadowDestructors;
+ }
+ }
+
+ TProbe(const TProbe& other)
+ : State(other.State)
+ , ShadowState(other.ShadowState)
+ {
+ Y_ASSERT(State);
+ ++State->CopyConstructors;
+ }
+
+ TProbe(TProbe&& other)
+ : State(other.State)
+ , ShadowState(other.ShadowState)
+ {
+ Y_ASSERT(State);
+ other.State = nullptr;
+ ++State->MoveConstructors;
+ }
+
+ TProbe(const TCoercibleToProbe& other)
+ : State(other.State)
+ , ShadowState(other.ShadowState)
+ {
+ Y_ASSERT(State);
+ ++State->CopyConstructors;
+ }
+
+ TProbe(TCoercibleToProbe&& other)
+ : State(other.State)
+ , ShadowState(other.ShadowState)
+ {
+ Y_ASSERT(State);
+ other.State = nullptr;
+ ++State->MoveConstructors;
+ }
+
+ TProbe& operator=(const TProbe& other) {
+ State = other.State;
+ ShadowState = other.ShadowState;
+ Y_ASSERT(State);
+ ++State->CopyAssignments;
+ return *this;
+ }
+
+ TProbe& operator=(TProbe&& other) {
+ State = other.State;
+ ShadowState = other.ShadowState;
+ Y_ASSERT(State);
+ other.State = nullptr;
+ ++State->MoveAssignments;
+ return *this;
+ }
+
+ void Touch() const {
+ Y_ASSERT(State);
+ ++State->Touches;
+ }
+
+ bool IsValid() const {
+ return nullptr != State;
+ }
+
+ private:
+ TProbe()
+ : State(nullptr)
+ {}
+ };
+} // namespace NTesting
diff --git a/library/cpp/testing/common/scope.cpp b/library/cpp/testing/common/scope.cpp
new file mode 100644
index 0000000000..c70d695c1b
--- /dev/null
+++ b/library/cpp/testing/common/scope.cpp
@@ -0,0 +1 @@
+#include "scope.h"
diff --git a/library/cpp/testing/common/scope.h b/library/cpp/testing/common/scope.h
new file mode 100644
index 0000000000..a2ca0e77e4
--- /dev/null
+++ b/library/cpp/testing/common/scope.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/system/env.h>
+
+#include <utility>
+
+namespace NTesting {
+ // @brief Assigns new values to the given environment variables and restores old values upon destruction.
+ // @note if there was no env variable with given name, it will be set to empty string upon destruction IGNIETFERRO-1486
+ struct TScopedEnvironment {
+ TScopedEnvironment(const TString& name, const TString& value)
+ : PreviousState{1, {name, ::GetEnv(name)}}
+ {
+ ::SetEnv(name, value);
+ }
+
+ TScopedEnvironment(const TVector<std::pair<TString, TString>>& vars)
+ : PreviousState(Reserve(vars.size()))
+ {
+ for (const auto& [k, v] : vars) {
+ PreviousState.emplace_back(k, ::GetEnv(k));
+ ::SetEnv(k, v);
+ }
+ }
+
+ ~TScopedEnvironment() {
+ for (const auto& [k, v] : PreviousState) {
+ ::SetEnv(k, v);
+ }
+ }
+
+ TScopedEnvironment(const TScopedEnvironment&) = delete;
+ TScopedEnvironment& operator=(const TScopedEnvironment&) = delete;
+ private:
+ TVector<std::pair<TString, TString>> PreviousState;
+ };
+}
diff --git a/library/cpp/testing/common/ut/env_ut.cpp b/library/cpp/testing/common/ut/env_ut.cpp
new file mode 100644
index 0000000000..2aed1e4a25
--- /dev/null
+++ b/library/cpp/testing/common/ut/env_ut.cpp
@@ -0,0 +1,162 @@
+#include <library/cpp/testing/common/env.h>
+#include <library/cpp/testing/common/scope.h>
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <util/folder/dirut.h>
+#include <util/stream/file.h>
+#include <util/system/env.h>
+#include <util/system/execpath.h>
+#include <util/system/fs.h>
+
+
+TEST(Runtime, ArcadiaSourceRoot) {
+ NTesting::TScopedEnvironment contextGuard("YA_TEST_CONTEXT_FILE", ""); // remove context filename
+ {
+ auto tmpDir = ::GetSystemTempDir();
+ NTesting::TScopedEnvironment guard("ARCADIA_SOURCE_ROOT", tmpDir);
+ Singleton<NPrivate::TTestEnv>()->ReInitialize();
+ EXPECT_EQ(tmpDir, ArcadiaSourceRoot());
+ }
+ {
+ NTesting::TScopedEnvironment guard("ARCADIA_SOURCE_ROOT", "");
+ Singleton<NPrivate::TTestEnv>()->ReInitialize();
+ EXPECT_FALSE(ArcadiaSourceRoot().empty());
+ }
+}
+
+TEST(Runtime, BuildRoot) {
+ NTesting::TScopedEnvironment contextGuard("YA_TEST_CONTEXT_FILE", ""); // remove context filename
+ {
+ auto tmpDir = ::GetSystemTempDir();
+ NTesting::TScopedEnvironment guard("ARCADIA_BUILD_ROOT", tmpDir);
+ Singleton<NPrivate::TTestEnv>()->ReInitialize();
+ EXPECT_EQ(tmpDir, BuildRoot());
+ }
+ {
+ NTesting::TScopedEnvironment guard("ARCADIA_BUILD_ROOT", "");
+ Singleton<NPrivate::TTestEnv>()->ReInitialize();
+ EXPECT_FALSE(BuildRoot().empty());
+ }
+}
+
+TEST(Runtime, BinaryPath) {
+ NTesting::TScopedEnvironment contextGuard("YA_TEST_CONTEXT_FILE", ""); // remove context filename
+ Singleton<NPrivate::TTestEnv>()->ReInitialize();
+ EXPECT_TRUE(TFsPath(BinaryPath("library/cpp/testing/common/ut")).Exists());
+}
+
+TEST(Runtime, GetArcadiaTestsData) {
+ NTesting::TScopedEnvironment contextGuard("YA_TEST_CONTEXT_FILE", ""); // remove context filename
+ {
+ auto tmpDir = ::GetSystemTempDir();
+ NTesting::TScopedEnvironment guard("ARCADIA_TESTS_DATA_DIR", tmpDir);
+ Singleton<NPrivate::TTestEnv>()->ReInitialize();
+ EXPECT_EQ(tmpDir, GetArcadiaTestsData());
+ }
+ {
+ NTesting::TScopedEnvironment guard("ARCADIA_TESTS_DATA_DIR", "");
+ Singleton<NPrivate::TTestEnv>()->ReInitialize();
+ auto path = GetArcadiaTestsData();
+ // it is not error if path is empty
+ const bool ok = (path.empty() || GetBaseName(path) == "arcadia_tests_data");
+ EXPECT_TRUE(ok);
+ }
+}
+
+TEST(Runtime, GetWorkPath) {
+ NTesting::TScopedEnvironment contextGuard("YA_TEST_CONTEXT_FILE", ""); // remove context filename
+ {
+ auto tmpDir = ::GetSystemTempDir();
+ NTesting::TScopedEnvironment guard("TEST_WORK_PATH", tmpDir);
+ Singleton<NPrivate::TTestEnv>()->ReInitialize();
+ EXPECT_EQ(tmpDir, GetWorkPath());
+ }
+ {
+ NTesting::TScopedEnvironment guard("TEST_WORK_PATH", "");
+ Singleton<NPrivate::TTestEnv>()->ReInitialize();
+ EXPECT_TRUE(!GetWorkPath().empty());
+ }
+}
+
+TEST(Runtime, GetOutputPath) {
+ NTesting::TScopedEnvironment contextGuard("YA_TEST_CONTEXT_FILE", ""); // remove context filename
+ Singleton<NPrivate::TTestEnv>()->ReInitialize();
+ EXPECT_EQ(GetOutputPath().Basename(), "testing_out_stuff");
+}
+
+TEST(Runtime, GetRamDrivePath) {
+ NTesting::TScopedEnvironment contextGuard("YA_TEST_CONTEXT_FILE", ""); // remove context filename
+ auto tmpDir = ::GetSystemTempDir();
+ NTesting::TScopedEnvironment guard("YA_TEST_RAM_DRIVE_PATH", tmpDir);
+ Singleton<NPrivate::TTestEnv>()->ReInitialize();
+ EXPECT_EQ(tmpDir, GetRamDrivePath());
+}
+
+TEST(Runtime, GetOutputRamDrivePath) {
+ NTesting::TScopedEnvironment contextGuard("YA_TEST_CONTEXT_FILE", ""); // remove context filename
+ auto tmpDir = ::GetSystemTempDir();
+ NTesting::TScopedEnvironment guard("YA_TEST_OUTPUT_RAM_DRIVE_PATH", tmpDir);
+ Singleton<NPrivate::TTestEnv>()->ReInitialize();
+ EXPECT_EQ(tmpDir, GetOutputRamDrivePath());
+}
+
+#ifdef _linux_
+TEST(Runtime, GdbPath) {
+ Singleton<NPrivate::TTestEnv>()->ReInitialize();
+ EXPECT_TRUE(NFs::Exists(::GdbPath()));
+}
+#endif
+
+TString ReInitializeContext(TStringBuf data) {
+ auto tmpDir = ::GetSystemTempDir();
+ auto filename = tmpDir + "/context.json";
+ TOFStream stream(filename);
+ stream.Write(data.data(), data.size());
+ stream.Finish();
+
+ NTesting::TScopedEnvironment contextGuard("YA_TEST_CONTEXT_FILE", filename);
+ Singleton<NPrivate::TTestEnv>()->ReInitialize();
+
+ return filename;
+}
+
+TEST(Runtime, GetTestParam) {
+ TString context = R"json({
+ "runtime": {
+ "test_params": {
+ "a": "b",
+ "c": "d"
+ }
+ }
+ })json";
+ auto filename = ReInitializeContext(context);
+
+ EXPECT_EQ("b", GetTestParam("a"));
+ EXPECT_EQ("d", GetTestParam("c"));
+ EXPECT_EQ("", GetTestParam("e"));
+ EXPECT_EQ("w", GetTestParam("e", "w"));
+
+ Singleton<NPrivate::TTestEnv>()->AddTestParam("e", "e");
+ EXPECT_EQ("e", GetTestParam("e"));
+}
+
+TEST(Runtime, WatchProcessCore) {
+ TString context = R"json({
+ "internal": {
+ "core_search_file": "watch_core.txt"
+ }
+ })json";
+ auto filename = ReInitializeContext(context);
+
+ WatchProcessCore(1, "bin1", "pwd");
+ WatchProcessCore(2, "bin1");
+ StopProcessCoreWatching(2);
+
+ TIFStream file("watch_core.txt");
+ auto data = file.ReadAll();
+ TString expected = R"json({"cmd":"add","pid":1,"binary_path":"bin1","cwd":"pwd"}
+{"cmd":"add","pid":2,"binary_path":"bin1"}
+{"cmd":"drop","pid":2}
+)json";
+ EXPECT_EQ(expected, data);
+}
diff --git a/library/cpp/testing/common/ut/network_ut.cpp b/library/cpp/testing/common/ut/network_ut.cpp
new file mode 100644
index 0000000000..6a40775fd9
--- /dev/null
+++ b/library/cpp/testing/common/ut/network_ut.cpp
@@ -0,0 +1,54 @@
+#include <library/cpp/testing/common/network.h>
+#include <library/cpp/testing/common/scope.h>
+
+#include <util/generic/hash_set.h>
+
+#include <util/folder/dirut.h>
+#include <util/folder/path.h>
+#include <util/folder/tempdir.h>
+#include <util/network/sock.h>
+#include <util/system/fs.h>
+
+#include <library/cpp/testing/gtest/gtest.h>
+
+static TTempDir TmpDir;
+
+TEST(NetworkTest, FreePort) {
+ NTesting::TScopedEnvironment envGuard("PORT_SYNC_PATH", TmpDir.Name());
+
+ TVector<NTesting::TPortHolder> ports(Reserve(100));
+
+ for (size_t i = 0; i < 100; ++i) {
+ ports.push_back(NTesting::GetFreePort());
+ }
+
+ THashSet<ui16> uniqPorts;
+ for (auto& port : ports) {
+ const TString guardPath = TmpDir.Path() / ToString(static_cast<ui16>(port));
+ EXPECT_TRUE(NFs::Exists(guardPath));
+ EXPECT_TRUE(uniqPorts.emplace(port).second);
+
+ TInetStreamSocket sock;
+ TSockAddrInet addr(TIpHost{INADDR_ANY}, port);
+ ASSERT_EQ(0, SetSockOpt(sock, SOL_SOCKET, SO_REUSEADDR, 1));
+ EXPECT_EQ(0, sock.Bind(&addr));
+ }
+ ports.clear();
+ for (ui16 port : uniqPorts) {
+ const TString guardPath = TmpDir.Path() / ToString(port);
+ EXPECT_FALSE(NFs::Exists(guardPath));
+ }
+}
+
+
+TEST(FreePortTest, FreePortsRange) {
+ NTesting::TScopedEnvironment envGuard("PORT_SYNC_PATH", TmpDir.Name());
+
+ for (ui16 i = 2; i < 10; ++i) {
+ TVector<NTesting::TPortHolder> ports = NTesting::NLegacy::GetFreePortsRange(i);
+ ASSERT_EQ(i, ports.size());
+ for (ui16 j = 1; j < i; ++j) {
+ EXPECT_EQ(static_cast<ui16>(ports[j]), static_cast<ui16>(ports[0]) + j);
+ }
+ }
+}
diff --git a/library/cpp/testing/common/ut/scope_ut.cpp b/library/cpp/testing/common/ut/scope_ut.cpp
new file mode 100644
index 0000000000..4fb82c2466
--- /dev/null
+++ b/library/cpp/testing/common/ut/scope_ut.cpp
@@ -0,0 +1,28 @@
+#include <library/cpp/testing/common/scope.h>
+
+#include <util/system/env.h>
+
+#include <library/cpp/testing/gtest/gtest.h>
+
+TEST(TScopedEnvironment, SingleValue) {
+ auto before = GetEnv("ARCADIA_SOURCE_ROOT");
+ {
+ NTesting::TScopedEnvironment guard("ARCADIA_SOURCE_ROOT", "source");
+ EXPECT_EQ("source", GetEnv("ARCADIA_SOURCE_ROOT"));
+ }
+ EXPECT_EQ(before, GetEnv("ARCADIA_SOURCE_ROOT"));
+}
+
+TEST(TScopedEnvironment, MultiValue) {
+ TVector<TString> before{GetEnv("ARCADIA_SOURCE_ROOT"), GetEnv("ARCADIA_BUILD_ROOT")};
+ {
+ NTesting::TScopedEnvironment guard{{
+ {"ARCADIA_SOURCE_ROOT", "source"},
+ {"ARCADIA_BUILD_ROOT", "build"},
+ }};
+ EXPECT_EQ("source", GetEnv("ARCADIA_SOURCE_ROOT"));
+ EXPECT_EQ("build", GetEnv("ARCADIA_BUILD_ROOT"));
+ }
+ TVector<TString> after{GetEnv("ARCADIA_SOURCE_ROOT"), GetEnv("ARCADIA_BUILD_ROOT")};
+ EXPECT_EQ(before, after);
+}
diff --git a/library/cpp/testing/common/ut/ya.make b/library/cpp/testing/common/ut/ya.make
new file mode 100644
index 0000000000..053aa38079
--- /dev/null
+++ b/library/cpp/testing/common/ut/ya.make
@@ -0,0 +1,19 @@
+GTEST()
+OWNER(
+ amatanhead
+ bulatman
+ thegeorg
+ g:cpp-contrib
+)
+
+SRCS(
+ env_ut.cpp
+ network_ut.cpp
+ scope_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/testing/common
+)
+
+END()
diff --git a/library/cpp/testing/common/ya.make b/library/cpp/testing/common/ya.make
new file mode 100644
index 0000000000..2f4b0ce26e
--- /dev/null
+++ b/library/cpp/testing/common/ya.make
@@ -0,0 +1,23 @@
+LIBRARY()
+
+OWNER(
+ amatanhead
+ bulatman
+ thegeorg
+ g:cpp-contrib
+)
+
+SRCS(
+ env.cpp
+ network.cpp
+ probe.cpp
+ scope.cpp
+)
+
+PEERDIR(
+ library/cpp/json
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/testing/gmock_in_unittest/events.cpp b/library/cpp/testing/gmock_in_unittest/events.cpp
new file mode 100644
index 0000000000..dbd65b727d
--- /dev/null
+++ b/library/cpp/testing/gmock_in_unittest/events.cpp
@@ -0,0 +1,32 @@
+#include "events.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+#include <util/string/builder.h>
+
+void TGMockTestEventListener::OnTestPartResult(const testing::TestPartResult& result) {
+ if (result.failed()) {
+ const TString message = result.message();
+ const TString summary = result.summary();
+ TStringBuilder msg;
+ if (result.file_name())
+ msg << result.file_name() << TStringBuf(":");
+ if (result.line_number() != -1)
+ msg << result.line_number() << TStringBuf(":");
+ if (summary) {
+ if (msg) {
+ msg << TStringBuf("\n");
+ }
+ msg << summary;
+ }
+ if (message && summary != message) {
+ if (msg) {
+ msg << TStringBuf("\n");
+ }
+ msg << message;
+ }
+ NUnitTest::NPrivate::RaiseError(result.summary(), msg, result.fatally_failed());
+ }
+}
diff --git a/library/cpp/testing/gmock_in_unittest/events.h b/library/cpp/testing/gmock_in_unittest/events.h
new file mode 100644
index 0000000000..84c10a93de
--- /dev/null
+++ b/library/cpp/testing/gmock_in_unittest/events.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include <gtest/gtest.h>
+
+class TGMockTestEventListener: public testing::EmptyTestEventListener {
+public:
+ void OnTestPartResult(const testing::TestPartResult& result) override;
+};
diff --git a/library/cpp/testing/gmock_in_unittest/example_ut/example_ut.cpp b/library/cpp/testing/gmock_in_unittest/example_ut/example_ut.cpp
new file mode 100644
index 0000000000..97f19050e4
--- /dev/null
+++ b/library/cpp/testing/gmock_in_unittest/example_ut/example_ut.cpp
@@ -0,0 +1,105 @@
+#include <library/cpp/testing/gmock_in_unittest/gmock.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/string.h>
+
+// Set this variable to true if you want to see failures
+/////////////////////////////////////////////////////////
+static const bool fail = false;
+/////////////////////////////////////////////////////////
+
+class ITestIface {
+public:
+ virtual ~ITestIface() {
+ }
+
+ virtual void Func1() = 0;
+
+ virtual int Func2(const TString&) const = 0;
+};
+
+class TTestMock: public ITestIface {
+public:
+ MOCK_METHOD(void, Func1, (), (override));
+ MOCK_METHOD(int, Func2, (const TString&), (const, override));
+};
+
+using namespace testing;
+
+Y_UNIT_TEST_SUITE(TExampleGMockTest) {
+ Y_UNIT_TEST(TSimpleTest) {
+ TTestMock mock;
+ EXPECT_CALL(mock, Func1())
+ .Times(AtLeast(1));
+
+ if (!fail) {
+ mock.Func1();
+ }
+ }
+
+ Y_UNIT_TEST(TNonExpectedCallTest) {
+ TTestMock mock;
+ EXPECT_CALL(mock, Func1())
+ .Times(AtMost(1));
+ mock.Func1();
+ if (fail) {
+ mock.Func1();
+ }
+ }
+
+ Y_UNIT_TEST(TReturnValuesTest) {
+ TTestMock mock;
+ EXPECT_CALL(mock, Func2(TString("1")))
+ .WillOnce(Return(1))
+ .WillRepeatedly(Return(42));
+
+ EXPECT_CALL(mock, Func2(TString("hello")))
+ .WillOnce(Return(-1));
+
+ UNIT_ASSERT_VALUES_EQUAL(mock.Func2("hello"), -1);
+
+ UNIT_ASSERT_VALUES_EQUAL(mock.Func2("1"), 1);
+ UNIT_ASSERT_VALUES_EQUAL(mock.Func2("1"), 42);
+ UNIT_ASSERT_VALUES_EQUAL(mock.Func2("1"), 42);
+ UNIT_ASSERT_VALUES_EQUAL(mock.Func2("1"), 42);
+ UNIT_ASSERT_VALUES_EQUAL(mock.Func2("1"), 42);
+
+ if (fail) {
+ UNIT_ASSERT_VALUES_EQUAL(mock.Func2("hello"), -1); // expected to return -1 only once
+ }
+ }
+
+ Y_UNIT_TEST(TStrictCallSequenceTest) {
+ TTestMock mock;
+ {
+ InSequence seq;
+ EXPECT_CALL(mock, Func1())
+ .Times(1);
+ EXPECT_CALL(mock, Func2(_))
+ .Times(2)
+ .WillOnce(Return(1))
+ .WillOnce(Return(2));
+ EXPECT_CALL(mock, Func1());
+ }
+ mock.Func1();
+ UNIT_ASSERT_VALUES_EQUAL(mock.Func2("sample"), 1);
+ if (fail) {
+ mock.Func1();
+ }
+ UNIT_ASSERT_VALUES_EQUAL(mock.Func2(""), 2);
+ if (!fail) {
+ mock.Func1();
+ }
+ }
+
+ Y_UNIT_TEST(TUninterestingMethodIsFailureTest) {
+ StrictMock<TTestMock> mock;
+ EXPECT_CALL(mock, Func1())
+ .Times(1);
+ mock.Func1();
+ if (fail) {
+ mock.Func1();
+ }
+ }
+}
diff --git a/library/cpp/testing/gmock_in_unittest/example_ut/ya.make b/library/cpp/testing/gmock_in_unittest/example_ut/ya.make
new file mode 100644
index 0000000000..d2e5ee5d2a
--- /dev/null
+++ b/library/cpp/testing/gmock_in_unittest/example_ut/ya.make
@@ -0,0 +1,13 @@
+UNITTEST()
+
+OWNER(galaxycrab)
+
+PEERDIR(
+ library/cpp/testing/gmock_in_unittest
+)
+
+SRCS(
+ example_ut.cpp
+)
+
+END()
diff --git a/library/cpp/testing/gmock_in_unittest/gmock.h b/library/cpp/testing/gmock_in_unittest/gmock.h
new file mode 100644
index 0000000000..31f6aee1c3
--- /dev/null
+++ b/library/cpp/testing/gmock_in_unittest/gmock.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include <library/cpp/testing/gtest_extensions/gtest_extensions.h>
+
+#include <gmock/gmock.h>
diff --git a/library/cpp/testing/gmock_in_unittest/registration.cpp b/library/cpp/testing/gmock_in_unittest/registration.cpp
new file mode 100644
index 0000000000..c2872a4c27
--- /dev/null
+++ b/library/cpp/testing/gmock_in_unittest/registration.cpp
@@ -0,0 +1,20 @@
+#include "events.h"
+
+#include <gmock/gmock.h>
+
+#include <library/cpp/testing/unittest/plugin.h>
+
+namespace {
+ class TGMockUnittestPlugin: public NUnitTest::NPlugin::IPlugin {
+ public:
+ void OnStartMain(int argc, char* argv[]) override {
+ testing::InitGoogleMock(&argc, argv);
+ testing::TestEventListeners& listeners = testing::UnitTest::GetInstance()->listeners();
+ delete listeners.Release(listeners.default_result_printer());
+ listeners.Append(new TGMockTestEventListener());
+ }
+ };
+
+ NUnitTest::NPlugin::TPluginRegistrator registerGMock(new TGMockUnittestPlugin());
+
+}
diff --git a/library/cpp/testing/gmock_in_unittest/ya.make b/library/cpp/testing/gmock_in_unittest/ya.make
new file mode 100644
index 0000000000..5de68ad98d
--- /dev/null
+++ b/library/cpp/testing/gmock_in_unittest/ya.make
@@ -0,0 +1,17 @@
+LIBRARY()
+
+OWNER(galaxycrab)
+
+PEERDIR(
+ contrib/restricted/googletest/googlemock
+ contrib/restricted/googletest/googletest
+ library/cpp/testing/gtest_extensions
+ library/cpp/testing/unittest
+)
+
+SRCS(
+ events.cpp
+ GLOBAL registration.cpp
+)
+
+END()
diff --git a/library/cpp/testing/gtest_extensions/README.md b/library/cpp/testing/gtest_extensions/README.md
new file mode 100644
index 0000000000..5445c7a464
--- /dev/null
+++ b/library/cpp/testing/gtest_extensions/README.md
@@ -0,0 +1,5 @@
+# Extensions for Gtest and Gmock
+
+Extensions that enable better support of util types in gtest and gmock: pretty printers, matchers, some convenience macros.
+
+If you're using `GTEST`, include `library/cpp/testing/gtest/gtest.h` and it will automatically enable these extensions. This is the preferred way to include gtest and gmock as opposed to including gtest, gmock and extensions directly. It eliminates chances of forgetting to include extensions.
diff --git a/library/cpp/testing/gtest_extensions/assertions.cpp b/library/cpp/testing/gtest_extensions/assertions.cpp
new file mode 100644
index 0000000000..f390409d1b
--- /dev/null
+++ b/library/cpp/testing/gtest_extensions/assertions.cpp
@@ -0,0 +1,90 @@
+#include "assertions.h"
+
+#include <util/string/builder.h>
+#include <util/string/split.h>
+#include <util/system/type_name.h>
+
+namespace NGTest::NInternal {
+ namespace {
+ void FormatActual(const std::exception& err, const TBackTrace* bt, TStringBuilder& out) {
+ out << "an exception of type " << TypeName(err) << " "
+ << "with message " << TString(err.what()).Quote() << ".";
+ if (bt) {
+ out << "\n Trace: ";
+ for (auto& line: StringSplitter(bt->PrintToString()).Split('\n')) {
+ out << " " << line.Token() << "\n";
+ }
+ }
+ }
+
+ void FormatActual(TStringBuilder& out) {
+ out << " Actual: it throws ";
+ auto exceptionPtr = std::current_exception();
+ if (exceptionPtr) {
+ try {
+ std::rethrow_exception(exceptionPtr);
+ } catch (const yexception& err) {
+ FormatActual(err, err.BackTrace(), out);
+ return;
+ } catch (const std::exception& err) {
+ FormatActual(err, nullptr, out);
+ return;
+ } catch (...) {
+ out << "an unknown exception.";
+ return;
+ }
+ }
+ out << "nothing.";
+ }
+
+ void FormatExpected(const char* statement, const char* type, const TString& contains, TStringBuilder& out) {
+ out << "Expected: ";
+ if (TStringBuf(statement).size() > 80) {
+ out << "statement";
+ } else {
+ out << statement;
+ }
+ out << " throws an exception of type " << type;
+
+ if (!contains.empty()) {
+ out << " with message containing " << contains.Quote();
+ }
+
+ out << ".";
+ }
+ }
+
+ TString FormatErrorWrongException(const char* statement, const char* type) {
+ return FormatErrorWrongException(statement, type, "");
+ }
+
+ TString FormatErrorWrongException(const char* statement, const char* type, TString contains) {
+ TStringBuilder out;
+
+ FormatExpected(statement, type, contains, out);
+ out << "\n";
+ FormatActual(out);
+
+ return out;
+ }
+
+ TString FormatErrorUnexpectedException(const char* statement) {
+ TStringBuilder out;
+
+ out << "Expected: ";
+ if (TStringBuf(statement).size() > 80) {
+ out << "statement";
+ } else {
+ out << statement;
+ }
+ out << " doesn't throw an exception.\n ";
+
+ FormatActual(out);
+
+ return out;
+ }
+
+ bool ExceptionMessageContains(const std::exception& err, TString contains) {
+ return TStringBuf(err.what()).Contains(contains);
+ }
+}
diff --git a/library/cpp/testing/gtest_extensions/assertions.h b/library/cpp/testing/gtest_extensions/assertions.h
new file mode 100644
index 0000000000..e8ea07b5df
--- /dev/null
+++ b/library/cpp/testing/gtest_extensions/assertions.h
@@ -0,0 +1,111 @@
+#pragma once
+
+#include <util/generic/string.h>
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+/**
+ * Check that the given statement throws an exception of the given type,
+ * and that the thrown exception message contains the given substring.
+ */
+#define EXPECT_THROW_MESSAGE_HAS_SUBSTR(statement, expectedException, substring) \
+ _Y_GTEST_EXPECT_THROW_MESSAGE_HAS_SUBSTR_IMPL_(statement, expectedException, substring, GTEST_NONFATAL_FAILURE_)
+
+/**
+ * Check that the given statement throws an exception of the given type,
+ * and that the thrown exception message contains the given substring.
+ */
+#define ASSERT_THROW_MESSAGE_HAS_SUBSTR(statement, expectedException, substring) \
+ _Y_GTEST_EXPECT_THROW_MESSAGE_HAS_SUBSTR_IMPL_(statement, expectedException, substring, GTEST_FATAL_FAILURE_)
+
+
+// Improve default macros. New implementation shows better exception messages.
+// See https://github.com/google/googletest/issues/2878
+
+#undef EXPECT_THROW
+#define EXPECT_THROW(statement, expectedException) \
+ _Y_GTEST_EXPECT_THROW_IMPL_(statement, expectedException, GTEST_NONFATAL_FAILURE_)
+
+#undef ASSERT_THROW
+#define ASSERT_THROW(statement, expectedException) \
+ _Y_GTEST_EXPECT_THROW_IMPL_(statement, expectedException, GTEST_FATAL_FAILURE_)
+
+#undef EXPECT_NO_THROW
+#define EXPECT_NO_THROW(statement) \
+ _Y_GTEST_EXPECT_NO_THROW_IMPL_(statement, GTEST_NONFATAL_FAILURE_)
+
+#undef ASSERT_NO_THROW
+#define ASSERT_NO_THROW(statement) \
+ _Y_GTEST_EXPECT_NO_THROW_IMPL_(statement, GTEST_FATAL_FAILURE_)
+
+
+// Implementation details
+
+namespace NGTest::NInternal {
+ TString FormatErrorWrongException(const char* statement, const char* type);
+ TString FormatErrorWrongException(const char* statement, const char* type, TString contains);
+ TString FormatErrorUnexpectedException(const char* statement);
+ bool ExceptionMessageContains(const std::exception& err, TString contains);
+}
+
+#define _Y_GTEST_EXPECT_THROW_IMPL_(statement, expectedException, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::TString gtestMsg = ""; ::testing::internal::AlwaysTrue()) { \
+ bool gtestCaughtExpected = false; \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } catch (expectedException const&) { \
+ gtestCaughtExpected = true; \
+ } catch (...) { \
+ gtestMsg = ::NGTest::NInternal::FormatErrorWrongException( \
+ #statement, #expectedException); \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ } if (!gtestCaughtExpected) { \
+ gtestMsg = ::NGTest::NInternal::FormatErrorWrongException( \
+ #statement, #expectedException); \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
+ fail(gtestMsg.c_str())
+
+#define _Y_GTEST_EXPECT_THROW_MESSAGE_HAS_SUBSTR_IMPL_(statement, expectedException, substring, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::TString gtestMsg = ""; ::testing::internal::AlwaysTrue()) { \
+ bool gtestCaughtExpected = false; \
+ ::TString gtestSubstring{substring}; \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } catch (expectedException const& gtestError) { \
+ if (!::NGTest::NInternal::ExceptionMessageContains(gtestError, gtestSubstring)) { \
+ gtestMsg = ::NGTest::NInternal::FormatErrorWrongException( \
+ #statement, #expectedException, gtestSubstring); \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrowsubstr_, __LINE__); \
+ } \
+ gtestCaughtExpected = true; \
+ } catch (...) { \
+ gtestMsg = ::NGTest::NInternal::FormatErrorWrongException( \
+ #statement, #expectedException, gtestSubstring); \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrowsubstr_, __LINE__); \
+ } if (!gtestCaughtExpected) { \
+ gtestMsg = ::NGTest::NInternal::FormatErrorWrongException( \
+ #statement, #expectedException, gtestSubstring); \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrowsubstr_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testthrowsubstr_, __LINE__): \
+ fail(gtestMsg.c_str())
+
+#define _Y_GTEST_EXPECT_NO_THROW_IMPL_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::TString gtestMsg = ""; ::testing::internal::AlwaysTrue()) { \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } catch (...) { \
+ gtestMsg = ::NGTest::NInternal::FormatErrorUnexpectedException(#statement); \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \
+ fail(gtestMsg.c_str())
diff --git a/library/cpp/testing/gtest_extensions/gtest_extensions.cpp b/library/cpp/testing/gtest_extensions/gtest_extensions.cpp
new file mode 100644
index 0000000000..1277a804bc
--- /dev/null
+++ b/library/cpp/testing/gtest_extensions/gtest_extensions.cpp
@@ -0,0 +1 @@
+#include "gtest_extensions.h"
diff --git a/library/cpp/testing/gtest_extensions/gtest_extensions.h b/library/cpp/testing/gtest_extensions/gtest_extensions.h
new file mode 100644
index 0000000000..e20532241e
--- /dev/null
+++ b/library/cpp/testing/gtest_extensions/gtest_extensions.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include "assertions.h"
+#include "matchers.h"
+#include "pretty_printers.h"
+#include "probe.h"
diff --git a/library/cpp/testing/gtest_extensions/matchers.cpp b/library/cpp/testing/gtest_extensions/matchers.cpp
new file mode 100644
index 0000000000..7da7be8b3c
--- /dev/null
+++ b/library/cpp/testing/gtest_extensions/matchers.cpp
@@ -0,0 +1 @@
+#include "matchers.h"
diff --git a/library/cpp/testing/gtest_extensions/matchers.h b/library/cpp/testing/gtest_extensions/matchers.h
new file mode 100644
index 0000000000..044c1c3ee4
--- /dev/null
+++ b/library/cpp/testing/gtest_extensions/matchers.h
@@ -0,0 +1,132 @@
+#pragma once
+
+#include <util/generic/string.h>
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+namespace testing {
+ /**
+ * When matching `const TStringBuf&`, implicitly convert other strings and string views to `Eq` matchers.
+ */
+ template <typename T, typename TT>
+ class Matcher<const TBasicStringBuf<T, TT>&>: public internal::MatcherBase<const TBasicStringBuf<T, TT>&> {
+ public:
+ Matcher() {
+ }
+
+ explicit Matcher(const MatcherInterface<const TBasicStringBuf<T, TT>&>* impl)
+ : internal::MatcherBase<const TBasicStringBuf<T, TT>&>(impl) {
+ }
+
+ template <typename M, typename = typename std::remove_reference<M>::type::is_gtest_matcher>
+ Matcher(M&& m)
+ : internal::MatcherBase<const TBasicStringBuf<T, TT>&>(std::forward<M>(m)) {
+ }
+
+ Matcher(const TBasicString<T, TT>& s) {
+ *this = Eq(TBasicStringBuf<T, TT>(s));
+ }
+
+ Matcher(const T* s) {
+ *this = Eq(TBasicStringBuf<T, TT>(s));
+ }
+
+ Matcher(TBasicStringBuf<T, TT> s) {
+ *this = Eq(s);
+ }
+ };
+
+ /**
+ * When matching `TBasicBuf`, implicitly convert other strings and string views to `Eq` matchers.
+ */
+ template <typename T, typename TT>
+ class Matcher<TBasicStringBuf<T, TT>>: public internal::MatcherBase<TBasicStringBuf<T, TT>> {
+ public:
+ Matcher() {
+ }
+
+ explicit Matcher(const MatcherInterface <TBasicStringBuf<T, TT>>* impl)
+ : internal::MatcherBase<TBasicStringBuf<T, TT>>(impl) {
+ }
+
+ explicit Matcher(const MatcherInterface<const TBasicStringBuf<T, TT>&>* impl)
+ : internal::MatcherBase<TBasicStringBuf<T, TT>>(impl) {
+ }
+
+ template <typename M, typename = typename std::remove_reference<M>::type::is_gtest_matcher>
+ Matcher(M&& m)
+ : internal::MatcherBase<TBasicStringBuf<T, TT>>(std::forward<M>(m)) {
+ }
+
+ Matcher(const TBasicString<T, TT>& s) {
+ *this = Eq(TBasicString<T, TT>(s));
+ }
+
+ Matcher(const T* s) {
+ *this = Eq(TBasicString<T, TT>(s));
+ }
+
+ Matcher(TBasicStringBuf<T, TT> s) {
+ *this = Eq(s);
+ }
+ };
+
+ /**
+ * When matching `const TString&`, implicitly convert other strings and string views to `Eq` matchers.
+ */
+ template <typename T, typename TT>
+ class Matcher<const TBasicString<T, TT>&>: public internal::MatcherBase<const TBasicString<T, TT>&> {
+ public:
+ Matcher() {
+ }
+
+ explicit Matcher(const MatcherInterface<const TBasicString<T, TT>&>* impl)
+ : internal::MatcherBase<const TBasicString<T, TT>&>(impl) {
+ }
+
+ Matcher(const TBasicString<T, TT>& s) {
+ *this = Eq(s);
+ }
+
+ template <typename M, typename = typename std::remove_reference<M>::type::is_gtest_matcher>
+ Matcher(M&& m)
+ : internal::MatcherBase<const TBasicString<T, TT>&>(std::forward<M>(m)) {
+ }
+
+ Matcher(const T* s) {
+ *this = Eq(TBasicString<T, TT>(s));
+ }
+ };
+
+ /**
+ * When matching `TString`, implicitly convert other strings and string views to `Eq` matchers.
+ */
+ template <typename T, typename TT>
+ class Matcher<TBasicString<T, TT>>: public internal::MatcherBase<TBasicString<T, TT>> {
+ public:
+ Matcher() {
+ }
+
+ explicit Matcher(const MatcherInterface <TBasicString<T, TT>>* impl)
+ : internal::MatcherBase<TBasicString<T, TT>>(impl) {
+ }
+
+ explicit Matcher(const MatcherInterface<const TBasicString<T, TT>&>* impl)
+ : internal::MatcherBase<TBasicString<T, TT>>(impl) {
+ }
+
+ template <typename M, typename = typename std::remove_reference<M>::type::is_gtest_matcher>
+ Matcher(M&& m)
+ : internal::MatcherBase<TBasicString<T, TT>>(std::forward<M>(m)) {
+ }
+
+ Matcher(const TBasicString<T, TT>& s) {
+ *this = Eq(s);
+ }
+
+ Matcher(const T* s) {
+ *this = Eq(TBasicString<T, TT>(s));
+ }
+ };
+}
diff --git a/library/cpp/testing/gtest_extensions/pretty_printers.cpp b/library/cpp/testing/gtest_extensions/pretty_printers.cpp
new file mode 100644
index 0000000000..401745cbcb
--- /dev/null
+++ b/library/cpp/testing/gtest_extensions/pretty_printers.cpp
@@ -0,0 +1 @@
+#include "pretty_printers.h"
diff --git a/library/cpp/testing/gtest_extensions/pretty_printers.h b/library/cpp/testing/gtest_extensions/pretty_printers.h
new file mode 100644
index 0000000000..14d8284446
--- /dev/null
+++ b/library/cpp/testing/gtest_extensions/pretty_printers.h
@@ -0,0 +1,84 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/maybe.h>
+#include <util/generic/variant.h>
+#include <util/stream/output.h>
+#include <util/stream/str.h>
+#include <util/datetime/base.h>
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+/**
+ * Automatically define GTest pretty printer for type that can print itself to util's `IOutputStream`.
+ *
+ * Note that this macro should be instantiated in the same namespace as the type you're printing, otherwise
+ * ADL will not find it.
+ *
+ * Example:
+ *
+ * We define a struct `TMyContainer` and an output operator that works with `IOutputStream`. We then use this macro
+ * to automatically define GTest pretty printer:
+ *
+ * ```
+ * namespace NMy {
+ * struct TMyContainer {
+ * int x, y;
+ * };
+ * }
+ *
+ * template <>
+ * inline void Out<NMy::TMyContainer>(IOutputStream& stream, TTypeTraits<NMy::TMyContainer>::TFuncParam value) {
+ * stream << "{ x=" << value.x << ", y=" << value.y << " }";
+ * }
+ *
+ * namespace NMy {
+ * Y_GTEST_ARCADIA_PRINTER(TMyContainer)
+ * }
+ * ```
+ */
+#define Y_GTEST_ARCADIA_PRINTER(T) \
+ void PrintTo(const T& value, std::ostream* stream) { \
+ ::TString ss; \
+ ::TStringOutput s{ss}; \
+ s << value; \
+ *stream << ss; \
+ }
+
+
+template <typename TCharType, typename TCharTraits>
+void PrintTo(const TBasicString<TCharType, TCharTraits>& value, std::ostream* stream) {
+ *stream << value.Quote().c_str();
+}
+
+template <typename TCharType, typename TCharTraits>
+void PrintTo(TBasicStringBuf<TCharType, TCharTraits> value, std::ostream* stream) {
+ *stream << TBasicString<TCharType, TCharTraits>{value}.Quote().c_str();
+}
+
+template <typename T, typename P>
+void PrintTo(const TMaybe<T, P>& value, std::ostream* stream) {
+ if (value.Defined()) {
+ ::testing::internal::UniversalPrint(value.GetRef(), stream);
+ } else {
+ *stream << "nothing";
+ }
+}
+
+inline void PrintTo(TNothing /* value */, std::ostream* stream) {
+ *stream << "nothing";
+}
+
+inline void PrintTo(std::monostate /* value */, std::ostream* stream) {
+ *stream << "monostate";
+}
+
+inline void PrintTo(TInstant value, std::ostream* stream) {
+ *stream << value.ToString();
+}
+
+inline void PrintTo(TDuration value, std::ostream* stream) {
+ *stream << value.ToString();
+}
diff --git a/library/cpp/testing/gtest_extensions/probe.cpp b/library/cpp/testing/gtest_extensions/probe.cpp
new file mode 100644
index 0000000000..c3a49b9323
--- /dev/null
+++ b/library/cpp/testing/gtest_extensions/probe.cpp
@@ -0,0 +1,13 @@
+#include "probe.h"
+
+#include <ostream>
+
+namespace testing {
+ void PrintTo(const TProbeState& state, ::std::ostream* os) {
+ int copies = state.CopyConstructors + state.CopyAssignments;
+ int moves = state.MoveConstructors + state.MoveAssignments;
+ *os << state.Constructors << " ctors, " << state.Destructors << " dtors; "
+ << "copies: " << copies << " = " << state.CopyConstructors << " + " << state.CopyAssignments << "; "
+ << "moves: " << moves << " = " << state.MoveConstructors << " + " << state.MoveAssignments;
+ }
+} // namespace testing
diff --git a/library/cpp/testing/gtest_extensions/probe.h b/library/cpp/testing/gtest_extensions/probe.h
new file mode 100644
index 0000000000..7d1fee83d3
--- /dev/null
+++ b/library/cpp/testing/gtest_extensions/probe.h
@@ -0,0 +1,81 @@
+#pragma once
+
+#include <util/system/yassert.h>
+
+#include <library/cpp/testing/common/probe.h>
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+namespace testing {
+ using NTesting::TProbe;
+ using NTesting::TProbeState;
+ using NTesting::TCoercibleToProbe;
+
+ // A helper functor which extracts from probe-like objectss their state.
+ struct TProbableTraits {
+ static const TProbeState& ExtractState(const TProbeState& probe) {
+ return probe;
+ }
+
+ static const TProbeState& ExtractState(const TProbeState* probe) {
+ return *probe;
+ }
+
+ static const TProbeState& ExtractState(const TProbe& probe) {
+ return *probe.State;
+ }
+
+ static const TProbeState& ExtractState(const TCoercibleToProbe& probe) {
+ return *probe.State;
+ }
+ };
+
+ void PrintTo(const TProbeState& state, ::std::ostream* os);
+
+ inline void PrintTo(const TProbe& probe, ::std::ostream* os) {
+ PrintTo(TProbableTraits::ExtractState(probe), os);
+ }
+
+ inline void PrintTo(const TCoercibleToProbe& probe, ::std::ostream* os) {
+ PrintTo(TProbableTraits::ExtractState(probe), os);
+ }
+
+ MATCHER(IsAlive, "is alive") {
+ Y_UNUSED(result_listener);
+ const auto& state = TProbableTraits::ExtractState(arg);
+ return state.Destructors < state.Constructors + state.CopyConstructors + state.CopyAssignments;
+ }
+
+ MATCHER(IsDead, "is dead") {
+ Y_UNUSED(result_listener);
+ const auto& state = TProbableTraits::ExtractState(arg);
+ return state.Destructors == state.Constructors + state.CopyConstructors + state.CopyAssignments;
+ }
+
+ MATCHER_P2(HasCopyMoveCounts, copyCount, moveCount, "" + \
+ PrintToString(copyCount) + " copy constructors and " + \
+ PrintToString(moveCount) + " move constructors were called") {
+ Y_UNUSED(result_listener);
+ const auto& state = TProbableTraits::ExtractState(arg);
+ return state.CopyConstructors == copyCount && state.MoveConstructors == moveCount;
+ }
+
+ MATCHER(NoCopies, "no copies were made") {
+ Y_UNUSED(result_listener);
+ const auto& state = TProbableTraits::ExtractState(arg);
+ return 0 == state.CopyConstructors && 0 == state.CopyAssignments;
+ }
+
+ MATCHER(NoMoves, "no moves were made") {
+ Y_UNUSED(result_listener);
+ const auto& state = TProbableTraits::ExtractState(arg);
+ return 0 == state.MoveConstructors && 0 == state.MoveAssignments;
+ }
+
+ MATCHER(NoAssignments, "no assignments were made") {
+ Y_UNUSED(result_listener);
+ const auto& state = TProbableTraits::ExtractState(arg);
+ return 0 == state.CopyAssignments && 0 == state.MoveAssignments;
+ }
+}
diff --git a/library/cpp/testing/gtest_extensions/ut/README.md b/library/cpp/testing/gtest_extensions/ut/README.md
new file mode 100644
index 0000000000..ee8d212c18
--- /dev/null
+++ b/library/cpp/testing/gtest_extensions/ut/README.md
@@ -0,0 +1 @@
+Note: integration tests are located in */devtools/ya/test/tests/gtest_beta*. Launch them as well after changing this library.
diff --git a/library/cpp/testing/gtest_extensions/ut/gtest_extensions_ut.cpp b/library/cpp/testing/gtest_extensions/ut/gtest_extensions_ut.cpp
new file mode 100644
index 0000000000..81cdfd0427
--- /dev/null
+++ b/library/cpp/testing/gtest_extensions/ut/gtest_extensions_ut.cpp
@@ -0,0 +1,346 @@
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <util/generic/string.h>
+#include <util/generic/maybe.h>
+#include <util/stream/output.h>
+#include <util/stream/str.h>
+
+namespace {
+ class IMock {
+ public:
+ virtual void M1(const TStringBuf&) = 0;
+ virtual void M2(TStringBuf) = 0;
+ virtual void M3(const TString&) = 0;
+ virtual void M4(TString) = 0;
+ };
+
+ class TSampleMock : IMock {
+ public:
+ MOCK_METHOD(void, M1, (const TStringBuf&));
+ MOCK_METHOD(void, M2, (TStringBuf));
+ MOCK_METHOD(void, M3, (const TString&));
+ MOCK_METHOD(void, M4, (TString));
+ };
+}
+
+
+TEST(MatchersSpecializations, String) {
+ TSampleMock mock;
+
+ TStringBuf simpleStringBuf = "SimpleStringBuf";
+ const TStringBuf constSimpleStringBuf = "ConstSimpleStringBuf";
+
+ TString simpleString = "SimpleString";
+ const TString constSimpleString = "ConstSimpleString";
+
+ EXPECT_CALL(mock, M1("ConstSimpleStringBuf")).Times(1);
+ EXPECT_CALL(mock, M2("SimpleStringBuf")).Times(1);
+ EXPECT_CALL(mock, M3("ConstSimpleString")).Times(1);
+ EXPECT_CALL(mock, M4("SimpleString")).Times(1);
+
+ mock.M1(constSimpleStringBuf);
+ mock.M2(simpleStringBuf);
+ mock.M3(constSimpleString);
+ mock.M4(simpleString);
+}
+
+template <typename T, typename M>
+std::pair<bool, std::string> Match(T&& t, M&& m) {
+ testing::StringMatchResultListener listener;
+ auto matches = testing::SafeMatcherCast<T>(std::forward<M>(m)).MatchAndExplain(std::forward<T>(t), &listener);
+ return {matches, listener.str()};
+}
+
+TEST(Matchers, Throws) {
+ auto matcher = testing::Throws<std::runtime_error>();
+
+ {
+ std::stringstream ss;
+ testing::SafeMatcherCast<void(*)()>(matcher).DescribeTo(&ss);
+ auto explanation = ss.str();
+
+ EXPECT_THAT(explanation, testing::HasSubstr("std::runtime_error"));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { throw std::runtime_error("error message"); }, matcher);
+ EXPECT_TRUE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("std::runtime_error"));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { throw std::logic_error("error message"); }, matcher);
+ EXPECT_FALSE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("std::logic_error"));
+ EXPECT_THAT(explanation, testing::HasSubstr("\"error message\""));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { throw 10; }, matcher);
+ EXPECT_FALSE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("throws an exception of an unknown type"));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { (void)0; }, matcher);
+ EXPECT_FALSE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("does not throw any exception"));
+ }
+}
+
+TEST(Matchers, ThrowsMessage) {
+ auto matcher = testing::ThrowsMessage<std::runtime_error>(testing::HasSubstr("error message"));
+
+ {
+ std::stringstream ss;
+ testing::SafeMatcherCast<void(*)()>(matcher).DescribeTo(&ss);
+ auto explanation = ss.str();
+
+ EXPECT_THAT(explanation, testing::HasSubstr("std::runtime_error"));
+ EXPECT_THAT(explanation, testing::HasSubstr("\"error message\""));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { throw std::runtime_error("error message"); }, matcher);
+ EXPECT_TRUE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("std::runtime_error"));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { throw std::runtime_error("message error"); }, matcher);
+ EXPECT_FALSE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("std::runtime_error"));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { throw std::logic_error("error message"); }, matcher);
+ EXPECT_FALSE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("std::logic_error"));
+ EXPECT_THAT(explanation, testing::HasSubstr("\"error message\""));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { throw 10; }, matcher);
+ EXPECT_FALSE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("throws an exception of an unknown type"));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { (void)0; }, matcher);
+ EXPECT_FALSE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("does not throw any exception"));
+ }
+}
+
+TEST(Matchers, ThrowsMessageHasSubstr) {
+ auto matcher = testing::ThrowsMessage<std::runtime_error>(testing::HasSubstr("error message"));
+
+ {
+ std::stringstream ss;
+ testing::SafeMatcherCast<void(*)()>(matcher).DescribeTo(&ss);
+ auto explanation = ss.str();
+
+ EXPECT_THAT(explanation, testing::HasSubstr("std::runtime_error"));
+ EXPECT_THAT(explanation, testing::HasSubstr("\"error message\""));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { throw std::runtime_error("error message"); }, matcher);
+ EXPECT_TRUE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("std::runtime_error"));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { throw std::runtime_error("message error"); }, matcher);
+ EXPECT_FALSE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("std::runtime_error"));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { throw std::logic_error("error message"); }, matcher);
+ EXPECT_FALSE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("std::logic_error"));
+ EXPECT_THAT(explanation, testing::HasSubstr("\"error message\""));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { throw 10; }, matcher);
+ EXPECT_FALSE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("throws an exception of an unknown type"));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { (void)0; }, matcher);
+ EXPECT_FALSE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("does not throw any exception"));
+ }
+}
+
+TEST(Matchers, ThrowsCondition) {
+ auto matcher = testing::Throws<std::runtime_error>(
+ testing::Property(&std::exception::what, testing::HasSubstr("error message")));
+
+ {
+ std::stringstream ss;
+ testing::SafeMatcherCast<void(*)()>(matcher).DescribeTo(&ss);
+ auto explanation = ss.str();
+
+ EXPECT_THAT(explanation, testing::HasSubstr("std::runtime_error"));
+ EXPECT_THAT(explanation, testing::HasSubstr("\"error message\""));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { throw std::runtime_error("error message"); }, matcher);
+ EXPECT_TRUE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("std::runtime_error"));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { throw std::runtime_error("message error"); }, matcher);
+ EXPECT_FALSE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("std::runtime_error"));
+ EXPECT_THAT(explanation, testing::HasSubstr("\"message error\""));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { throw std::logic_error("error message"); }, matcher);
+ EXPECT_FALSE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("std::logic_error"));
+ EXPECT_THAT(explanation, testing::HasSubstr("\"error message\""));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { throw 10; }, matcher);
+ EXPECT_FALSE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("throws an exception of an unknown type"));
+ }
+
+ {
+ auto [matched, explanation] = Match([]() { (void)0; }, matcher);
+ EXPECT_FALSE(matched);
+ EXPECT_THAT(explanation, testing::HasSubstr("does not throw any exception"));
+ }
+}
+
+template <typename T>
+std::string GtestPrint(T&& v) {
+ std::stringstream ss;
+ testing::internal::UniversalPrint(std::forward<T>(v), &ss);
+ return ss.str();
+}
+
+struct TThrowsOnMove {
+ TThrowsOnMove() = default;
+ TThrowsOnMove(TThrowsOnMove&&) {
+ ythrow yexception() << "move failed";
+ }
+};
+
+TEST(PrettyPrinters, String) {
+ EXPECT_EQ(GtestPrint(TString("hello world")), "\"hello world\"");
+ EXPECT_EQ(GtestPrint(TStringBuf("hello world")), "\"hello world\"");
+}
+
+TEST(PrettyPrinters, Maybe) {
+ EXPECT_EQ(GtestPrint(TMaybe<TString>("hello world")), "\"hello world\"");
+ EXPECT_EQ(GtestPrint(TMaybe<TString>()), "nothing");
+ EXPECT_EQ(GtestPrint(Nothing()), "nothing");
+}
+
+struct T1 {
+ int x;
+};
+
+void PrintTo(T1 value, std::ostream* stream) {
+ *stream << "T1{" << value.x << "}";
+}
+
+struct T2 {
+ int x;
+};
+
+Y_DECLARE_OUT_SPEC(inline, T2, stream, value) {
+ stream << "T2{" << value.x << "}";
+}
+
+Y_GTEST_ARCADIA_PRINTER(T2)
+
+TEST(PrettyPrinters, Custom) {
+ EXPECT_EQ(GtestPrint(T1{10}), "T1{10}");
+}
+
+TEST(PrettyPrinters, CustomArcadia) {
+ EXPECT_EQ(GtestPrint(T2{10}), "T2{10}");
+}
+
+TEST(Exceptions, ExpectThrow) {
+ EXPECT_THROW(ythrow yexception() << "msg", yexception);
+}
+
+TEST(Exceptions, ExpectThrowStructuredBindings) {
+ auto [a, b] = std::make_pair("a", "b");
+ EXPECT_THROW(throw yexception() << a << "-" << b, yexception);
+}
+
+TEST(Exceptions, ExpectThrowSkipInThrowTest) {
+ // this test should be skipped, not failed
+ EXPECT_THROW(GTEST_SKIP(), yexception);
+}
+
+TEST(Exceptions, AssertThrow) {
+ ASSERT_THROW(ythrow yexception() << "msg", yexception);
+}
+
+TEST(Exceptions, AssertThrowStructuredBindings) {
+ auto [a, b] = std::make_pair("a", "b");
+ ASSERT_THROW(throw yexception() << a << "-" << b, yexception);
+}
+
+TEST(Exceptions, AssertThrowSkipInThrowTest) {
+ // this test should be skipped, not failed
+ ASSERT_THROW(GTEST_SKIP(), yexception);
+}
+
+TEST(Exceptions, ExpectThrowMessageHasSubstr) {
+ EXPECT_THROW_MESSAGE_HAS_SUBSTR(ythrow yexception() << "msg", yexception, "msg");
+}
+
+TEST(Exceptions, ExpectThrowMessageHasSubstrStructuredBindings) {
+ auto [a, b] = std::make_pair("a", "b");
+ EXPECT_THROW_MESSAGE_HAS_SUBSTR(throw yexception() << a << "-" << b, yexception, "-");
+}
+
+TEST(Exceptions, ExpectThrowMessageHasSubstrSkipInThrowTest) {
+ // this test should be skipped, not failed
+ EXPECT_THROW_MESSAGE_HAS_SUBSTR(GTEST_SKIP(), yexception, "-");
+}
+
+TEST(Exceptions, AssertThrowMessageHasSubstr) {
+ ASSERT_THROW_MESSAGE_HAS_SUBSTR(ythrow yexception() << "msg", yexception, "msg");
+}
+
+TEST(Exceptions, AssertThrowMessageHasSubstrStructuredBindings) {
+ auto [a, b] = std::make_pair("a", "b");
+ ASSERT_THROW_MESSAGE_HAS_SUBSTR(throw yexception() << a << "-" << b, yexception, "-");
+}
+
+TEST(Exceptions, AssertThrowMessageHasSubstrSkipInThrowTest) {
+ // this test should be skipped, not failed
+ ASSERT_THROW_MESSAGE_HAS_SUBSTR(GTEST_SKIP(), yexception, "-");
+}
+
+TEST(Exceptions, ExpectNoThrow) {
+ EXPECT_NO_THROW((void)0);
+}
+
+TEST(Exceptions, AssertNoThrow) {
+ ASSERT_NO_THROW((void)0);
+}
+
+TEST(Exceptions, ExpectAnyThrow) {
+ EXPECT_ANY_THROW(ythrow yexception() << "msg");
+}
+
+TEST(Exceptions, AssertAnyThrow) {
+ ASSERT_ANY_THROW(ythrow yexception() << "msg");
+}
diff --git a/library/cpp/testing/gtest_extensions/ut/probe_ut.cpp b/library/cpp/testing/gtest_extensions/ut/probe_ut.cpp
new file mode 100644
index 0000000000..a9d53f896a
--- /dev/null
+++ b/library/cpp/testing/gtest_extensions/ut/probe_ut.cpp
@@ -0,0 +1,54 @@
+#include <library/cpp/testing/gtest/gtest.h>
+
+using namespace testing;
+
+TEST(ProbeStateTest, Example) {
+ // check that our test function does not make a copy of passed argument
+ auto copyless = [](auto&& x) {
+ TProbe p(std::move(x));
+ p.Touch();
+ return p;
+ };
+
+ TProbeState state;
+ auto probe = copyless(TProbe(&state));
+ EXPECT_EQ(1, state.Touches);
+ EXPECT_THAT(state, HasCopyMoveCounts(0, 2));
+}
+
+TEST(ProbeTest, Construct) {
+ TProbeState state;
+ {
+ TProbe probe(&state);
+ EXPECT_THAT(state, IsAlive());
+ }
+ EXPECT_THAT(state, IsDead());
+}
+
+TEST(ProbeTest, Copy) {
+ TProbeState state;
+
+ TProbe probe(&state);
+ TProbe copy(probe);
+ EXPECT_THAT(state, HasCopyMoveCounts(1, 0));
+ EXPECT_THAT(state, NoAssignments());
+ EXPECT_THAT(state, NoMoves());
+
+ TProbe copy2 = TProbe::ExplicitlyCreateInvalidProbe();
+ copy2 = probe;
+ EXPECT_EQ(1, state.CopyAssignments);
+}
+
+TEST(ProbeTest, Move) {
+ TProbeState state;
+ TProbe probe(&state);
+ TProbe probe2(std::move(probe));
+ EXPECT_FALSE(probe.IsValid());
+ EXPECT_THAT(state, NoCopies());
+
+ EXPECT_THAT(state, HasCopyMoveCounts(0, 1));
+
+ TProbe probe3 = TProbe::ExplicitlyCreateInvalidProbe();
+ probe3 = std::move(probe2);
+ EXPECT_EQ(1, state.MoveAssignments);
+}
diff --git a/library/cpp/testing/gtest_extensions/ut/ya.make b/library/cpp/testing/gtest_extensions/ut/ya.make
new file mode 100644
index 0000000000..39b41cecfd
--- /dev/null
+++ b/library/cpp/testing/gtest_extensions/ut/ya.make
@@ -0,0 +1,20 @@
+GTEST()
+OWNER(
+ amatanhead
+ bulatman
+ dancingqueue
+ prettyboy
+ thegeorg
+ g:cpp-contrib
+)
+
+SRCS(
+ gtest_extensions_ut.cpp
+ probe_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/testing/gtest_extensions
+)
+
+END()
diff --git a/library/cpp/testing/gtest_extensions/ya.make b/library/cpp/testing/gtest_extensions/ya.make
new file mode 100644
index 0000000000..e24e81e8bd
--- /dev/null
+++ b/library/cpp/testing/gtest_extensions/ya.make
@@ -0,0 +1,26 @@
+LIBRARY()
+OWNER(
+ amatanhead
+ bulatman
+ dancingqueue
+ prettyboy
+ thegeorg
+ g:cpp-contrib
+)
+
+PEERDIR(
+ contrib/restricted/googletest/googlemock
+ contrib/restricted/googletest/googletest
+)
+
+SRCS(
+ assertions.cpp
+ gtest_extensions.cpp
+ matchers.cpp
+ pretty_printers.cpp
+ probe.cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/testing/hook/README.md b/library/cpp/testing/hook/README.md
new file mode 100644
index 0000000000..fac8b32ef5
--- /dev/null
+++ b/library/cpp/testing/hook/README.md
@@ -0,0 +1,25 @@
+# Hook for google benchmark and gtest
+
+Y_TEST_HOOK_BEFORE_INIT - вызывается перед инициализацией соотвествующего фреймворка
+Y_TEST_HOOK_BEFORE_RUN - вызывается перед запуском тестов
+Y_TEST_HOOK_AFTER_RUN - вызывается всегда после завершения выполнения тестов,
+ если этап инициализации был успешным
+
+## Примеры:
+
+```
+Y_TEST_HOOK_BEFORE_INIT(SetupMyApp) {
+ // ваш код для выполнения перед инициализацией фреймворка
+}
+
+Y_TEST_HOOK_BEFORE_RUN(InitMyApp) {
+ // ваш код для выполнения перед запуском тестов
+}
+
+Y_TEST_HOOK_AFTER_RUN(CleanMyApp) {
+ // ваш код для выполнения после завершения тестов
+}
+```
+
+## Тесты:
+тесты лаунчерах соотвествующих фреймворков (gtest, gbenchmark и unittest)
diff --git a/library/cpp/testing/hook/hook.cpp b/library/cpp/testing/hook/hook.cpp
new file mode 100644
index 0000000000..b3c599da89
--- /dev/null
+++ b/library/cpp/testing/hook/hook.cpp
@@ -0,0 +1,45 @@
+#include "hook.h"
+
+namespace {
+ NTesting::THook* BeforeInitHead = nullptr;
+ NTesting::THook* BeforeRunHead = nullptr;
+ NTesting::THook* AfterRunHead = nullptr;
+
+ void RegisterHook(NTesting::THook*& head, NTesting::THook* hook) {
+ hook->Next = head;
+ head = hook;
+ }
+
+ void CallHooks(NTesting::THook* head) {
+ while (nullptr != head) {
+ if (nullptr != head->Fn) {
+ (*head->Fn)();
+ }
+ head = head->Next;
+ }
+ }
+}
+
+void NTesting::THook::RegisterBeforeInit(NTesting::THook* hook) noexcept {
+ RegisterHook(BeforeInitHead, hook);
+}
+
+void NTesting::THook::CallBeforeInit() {
+ CallHooks(BeforeInitHead);
+}
+
+void NTesting::THook::RegisterBeforeRun(NTesting::THook* hook) noexcept {
+ RegisterHook(BeforeRunHead, hook);
+}
+
+void NTesting::THook::CallBeforeRun() {
+ CallHooks(BeforeRunHead);
+}
+
+void NTesting::THook::RegisterAfterRun(NTesting::THook* hook) noexcept {
+ RegisterHook(AfterRunHead, hook);
+}
+
+void NTesting::THook::CallAfterRun() {
+ CallHooks(AfterRunHead);
+}
diff --git a/library/cpp/testing/hook/hook.h b/library/cpp/testing/hook/hook.h
new file mode 100644
index 0000000000..c45289cb22
--- /dev/null
+++ b/library/cpp/testing/hook/hook.h
@@ -0,0 +1,128 @@
+#pragma once
+
+namespace NTesting {
+ /**
+ * Hook class and registration system.
+ *
+ * Default implementation of the `main` function for G_BENCHMARK and GTEST calls these hooks when executing.
+ * This is a useful feature if you want to customize behaviour of the `main` function,
+ * but you don't want to write `main` yourself.
+ *
+ * Hooks form an intrusive linked list that's built at application startup. Note that hooks execute
+ * in arbitrary order.
+ *
+ * Use macros below to define hooks.
+ */
+ struct THook {
+ using TFn = void (*)();
+
+ TFn Fn = nullptr;
+ THook* Next = nullptr;
+
+ static void RegisterBeforeInit(THook* hook) noexcept;
+
+ static void CallBeforeInit();
+
+ struct TRegisterBeforeInit {
+ explicit TRegisterBeforeInit(THook* hook) noexcept {
+ THook::RegisterBeforeInit(hook);
+ }
+ };
+
+ static void RegisterBeforeRun(THook* hook) noexcept;
+
+ static void CallBeforeRun();
+
+ struct TRegisterBeforeRun {
+ explicit TRegisterBeforeRun(THook* hook) noexcept {
+ THook::RegisterBeforeRun(hook);
+ }
+ };
+
+ static void RegisterAfterRun(THook* hook) noexcept;
+
+ static void CallAfterRun();
+
+ struct TRegisterAfterRun {
+ explicit TRegisterAfterRun(THook* hook) noexcept {
+ THook::RegisterAfterRun(hook);
+ }
+ };
+ };
+
+ /**
+ * Called right before initializing test programm
+ *
+ * This hook is intended for setting up default parameters. If you're doing initialization, consider
+ * using `Y_TEST_HOOK_BEFORE_RUN` instead.
+ *
+ * *Note:* hooks execute in arbitrary order.
+ *
+ *
+ * # Usage
+ *
+ * Instantiate this class in a cpp file. Pass a unique name for your hook,
+ * implement body right after macro instantiation:
+ *
+ * ```
+ * Y_TEST_HOOK_BEFORE_INIT(SetupParams) {
+ * // hook code
+ * }
+ * ```
+ */
+#define Y_TEST_HOOK_BEFORE_INIT(N) \
+ void N(); \
+ ::NTesting::THook N##Hook{&N, nullptr}; \
+ ::NTesting::THook::TRegisterBeforeInit N##HookReg{&N##Hook}; \
+ void N()
+
+ /**
+ * Called right before launching tests.
+ *
+ * Hooks execute in arbitrary order. As such, we recommend using this hook to set up an event listener,
+ * and performing initialization and cleanup in the corresponding event handlers. This is better than performing
+ * initialization and cleanup directly in the hook's code because it gives more control over
+ * order in which initialization is performed.
+ *
+ *
+ * # Usage
+ *
+ * Instantiate this class in a cpp file. Pass a unique name for your hook,
+ * implement body right after macro instantiation:
+ *
+ * ```
+ * Y_TEST_HOOK_BEFORE_RUN(InitMyApp) {
+ * // hook code
+ * }
+ * ```
+ */
+#define Y_TEST_HOOK_BEFORE_RUN(N) \
+ void N(); \
+ ::NTesting::THook N##Hook{&N, nullptr}; \
+ ::NTesting::THook::TRegisterBeforeRun N##HookReg{&N##Hook}; \
+ void N()
+
+ /**
+ * Called after all tests has finished, just before program exit.
+ *
+ * This hook is intended for simple cleanup routines that don't care about order in which hooks are executed.
+ * For more complex cases, we recommend using `Y_TEST_HOOK_BEFORE_RUN`.
+ *
+ *
+ * # Usage
+ *
+ * Instantiate this class in a cpp file. Pass a unique name for your hook,
+ * implement body right after macro instantiation:
+ *
+ * ```
+ * Y_TEST_HOOK_AFTER_RUN(StopMyApp) {
+ * // hook code
+ * }
+ * ```
+ */
+#define Y_TEST_HOOK_AFTER_RUN(N) \
+ void N(); \
+ ::NTesting::THook N##Hook{&N, nullptr}; \
+ ::NTesting::THook::TRegisterAfterRun N##HookReg{&N##Hook}; \
+ void N()
+}
diff --git a/library/cpp/testing/hook/ya.make b/library/cpp/testing/hook/ya.make
new file mode 100644
index 0000000000..db58f4e0ae
--- /dev/null
+++ b/library/cpp/testing/hook/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+OWNER(
+ amatanhead
+ bulatman
+ thegeorg
+ g:cpp-contrib
+)
+
+SRCS(
+ hook.cpp
+)
+
+END()
diff --git a/library/cpp/testing/unittest/checks.cpp b/library/cpp/testing/unittest/checks.cpp
new file mode 100644
index 0000000000..c5712ae9d2
--- /dev/null
+++ b/library/cpp/testing/unittest/checks.cpp
@@ -0,0 +1,31 @@
+#include <util/generic/string.h>
+#include <util/string/type.h>
+
+bool CheckExceptionMessage(const char* msg, TString& err) {
+ static const char* badMsg[] = {
+ // Операция успешно завершена [cp1251]
+ "\xce\xef\xe5\xf0\xe0\xf6\xe8\xff\x20\xf3\xf1\xef\xe5\xf8\xed\xee\x20\xe7\xe0\xe2\xe5\xf0\xf8\xe5\xed\xe0",
+ "The operation completed successfully",
+ "No error"};
+
+ err.clear();
+
+ if (msg == nullptr) {
+ err = "Error message is null";
+ return false;
+ }
+
+ if (IsSpace(msg)) {
+ err = "Error message is empty";
+ return false;
+ }
+
+ for (auto& i : badMsg) {
+ if (strstr(msg, i) != nullptr) {
+ err = "Invalid error message: " + TString(msg);
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/library/cpp/testing/unittest/env.h b/library/cpp/testing/unittest/env.h
new file mode 100644
index 0000000000..4807539ab2
--- /dev/null
+++ b/library/cpp/testing/unittest/env.h
@@ -0,0 +1,3 @@
+// just shortcut
+#include <library/cpp/testing/common/env.h>
+
diff --git a/library/cpp/testing/unittest/example_ut.cpp b/library/cpp/testing/unittest/example_ut.cpp
new file mode 100644
index 0000000000..bcc1ce33f0
--- /dev/null
+++ b/library/cpp/testing/unittest/example_ut.cpp
@@ -0,0 +1,12 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+/*
+ * just copy-paste it for good start point
+ */
+
+Y_UNIT_TEST_SUITE(TUnitTest) {
+ Y_UNIT_TEST(TestEqual) {
+ UNIT_ASSERT_EQUAL(0, 0);
+ UNIT_ASSERT_EQUAL(1, 1);
+ }
+}
diff --git a/library/cpp/testing/unittest/fat/test_port_manager.cpp b/library/cpp/testing/unittest/fat/test_port_manager.cpp
new file mode 100644
index 0000000000..f77d2e3a25
--- /dev/null
+++ b/library/cpp/testing/unittest/fat/test_port_manager.cpp
@@ -0,0 +1,36 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/testing/unittest/tests_data.h>
+
+bool IsFreePort(ui16 port) {
+ TInet6StreamSocket sock;
+ TSockAddrInet6 addr("::", port);
+ Y_ENSURE(SetSockOpt(sock, SOL_SOCKET, SO_REUSEADDR, 1) == 0);
+ SetReuseAddressAndPort(sock);
+ if (sock.Bind(&addr) == 0) {
+ return true;
+ }
+ return false;
+}
+
+void get_port_ranges() {
+ for (int i = 1; i < 10; ++i) {
+ TPortManager pm;
+ ui16 port = pm.GetPortsRange(1024, i);
+ for (int p = port; p < port + i; ++p) {
+ UNIT_ASSERT(IsFreePort(p));
+ }
+ }
+}
+
+Y_UNIT_TEST_SUITE(TestTPortManager) {
+ Y_UNIT_TEST(ParallelRun0) {get_port_ranges();}
+ Y_UNIT_TEST(ParallelRun1) {get_port_ranges();}
+ Y_UNIT_TEST(ParallelRun2) {get_port_ranges();}
+ Y_UNIT_TEST(ParallelRun3) {get_port_ranges();}
+ Y_UNIT_TEST(ParallelRun4) {get_port_ranges();}
+ Y_UNIT_TEST(ParallelRun5) {get_port_ranges();}
+ Y_UNIT_TEST(ParallelRun6) {get_port_ranges();}
+ Y_UNIT_TEST(ParallelRun7) {get_port_ranges();}
+ Y_UNIT_TEST(ParallelRun8) {get_port_ranges();}
+ Y_UNIT_TEST(ParallelRun9) {get_port_ranges();}
+}
diff --git a/library/cpp/testing/unittest/fat/ya.make b/library/cpp/testing/unittest/fat/ya.make
new file mode 100644
index 0000000000..d405e599ee
--- /dev/null
+++ b/library/cpp/testing/unittest/fat/ya.make
@@ -0,0 +1,19 @@
+UNITTEST()
+
+OWNER(g:yatool)
+
+SRCS(
+ test_port_manager.cpp
+)
+
+SIZE(LARGE)
+
+# We need to run tests at the same time on the single machine
+FORK_SUBTESTS()
+
+TAG(
+ ya:fat
+ ya:force_sandbox
+)
+
+END()
diff --git a/library/cpp/testing/unittest/gtest.cpp b/library/cpp/testing/unittest/gtest.cpp
new file mode 100644
index 0000000000..ebad1ea4d6
--- /dev/null
+++ b/library/cpp/testing/unittest/gtest.cpp
@@ -0,0 +1,67 @@
+#include "gtest.h"
+#include "simple.h"
+
+#include <util/generic/map.h>
+#include <util/generic/vector.h>
+#include <util/system/type_name.h>
+
+using namespace NUnitTest;
+using namespace NUnitTest::NPrivate;
+
+IGTestFactory::~IGTestFactory() {
+}
+
+namespace {
+ struct TCurrentTest: public TSimpleTestExecutor {
+ inline TCurrentTest(TStringBuf name)
+ : MyName(name)
+ {
+ }
+
+ TString TypeId() const override {
+ return TypeName(*this) + "-" + MyName;
+ }
+
+ TString Name() const noexcept override {
+ return TString(MyName);
+ }
+
+ const TStringBuf MyName;
+ };
+
+ struct TGTestFactory: public IGTestFactory {
+ inline TGTestFactory(TStringBuf name)
+ : Test(name)
+ {
+ }
+
+ ~TGTestFactory() override {
+ }
+
+ TString Name() const noexcept override {
+ return Test.Name();
+ }
+
+ TTestBase* ConstructTest() override {
+ return new TCurrentTest(Test);
+ }
+
+ void AddTest(const char* name, void (*body)(TTestContext&), bool forceFork) override {
+ Test.Tests.push_back(TBaseTestCase(name, body, forceFork));
+ }
+
+ TCurrentTest Test;
+ };
+}
+
+IGTestFactory* NUnitTest::NPrivate::ByName(const char* name) {
+ static TMap<TStringBuf, TAutoPtr<TGTestFactory>> tests;
+
+ auto& ret = tests[name];
+
+ if (!ret) {
+ ret = new TGTestFactory(name);
+ }
+
+ return ret.Get();
+}
diff --git a/library/cpp/testing/unittest/gtest.h b/library/cpp/testing/unittest/gtest.h
new file mode 100644
index 0000000000..b6768b1bf0
--- /dev/null
+++ b/library/cpp/testing/unittest/gtest.h
@@ -0,0 +1,108 @@
+#pragma once
+
+// WARNING: this is a legacy header that tries to mimic the gtest interface while using unittest
+// under the hood. Avoid using this interface -- use the genuine gtest instead (the GTEST macro).
+// If you're already using GTEST macro and you've found yourself here, you probably meant
+// to include `library/cpp/testing/gtest/gtest.h`.
+
+#include "registar.h"
+
+#include <util/generic/ymath.h>
+#include <util/generic/ylimits.h>
+
+namespace NUnitTest {
+ namespace NPrivate {
+ struct IGTestFactory: public ITestBaseFactory {
+ ~IGTestFactory() override;
+
+ virtual void AddTest(const char* name, void (*body)(TTestContext&), bool forceFork) = 0;
+ };
+
+ IGTestFactory* ByName(const char* name);
+ }
+}
+
+namespace NTesting {
+ struct TTest {
+ virtual void SetUp() {
+ }
+
+ virtual void TearDown() {
+ }
+
+ inline TTest* _This() noexcept {
+ return this;
+ }
+ };
+}
+
+namespace testing {
+ struct Test: public ::NTesting::TTest {
+ };
+}
+
+#define TEST_IMPL(N, NN, FF) \
+ void Test##N##NN(NUnitTest::TTestContext&); \
+ namespace NTestSuite##N##NN { \
+ struct TReg { \
+ inline TReg() { \
+ ::NUnitTest::NPrivate::ByName(#N)->AddTest(#NN, &(Test##N##NN), FF); \
+ } \
+ }; \
+ static TReg reg; \
+ } \
+ void Test##N##NN(NUnitTest::TTestContext&)
+
+#define TEST_F_IMPL(N, NN, FF) \
+ namespace NTestSuite##N##NN { \
+ struct TTestSuite: public N { \
+ inline TTestSuite() { \
+ this->_This()->SetUp(); \
+ } \
+ inline ~TTestSuite() { \
+ this->_This()->TearDown(); \
+ } \
+ void NN(); \
+ }; \
+ }; \
+ TEST_IMPL(N, NN, FF) { \
+ NTestSuite##N##NN::TTestSuite().NN(); \
+ } \
+ void NTestSuite##N##NN::TTestSuite::NN()
+
+#define TEST(A, B) TEST_IMPL(A, B, false)
+#define TEST_FORKED(A, B) TEST_IMPL(A, B, true)
+
+#define TEST_F(A, B) TEST_F_IMPL(A, B, false)
+#define TEST_F_FORKED(A, B) TEST_F_IMPL(A, B, true)
+
+#define EXPECT_EQ(A, B) UNIT_ASSERT_VALUES_EQUAL(A, B)
+#define EXPECT_NE(A, B) UNIT_ASSERT_UNEQUAL(A, B)
+#define EXPECT_LE(A, B) UNIT_ASSERT((A) <= (B))
+#define EXPECT_LT(A, B) UNIT_ASSERT((A) < (B))
+#define EXPECT_GE(A, B) UNIT_ASSERT((A) >= (B))
+#define EXPECT_GT(A, B) UNIT_ASSERT((A) > (B))
+#define EXPECT_NO_THROW(A) UNIT_ASSERT_NO_EXCEPTION(A)
+#define EXPECT_THROW(A, B) UNIT_ASSERT_EXCEPTION(A, B)
+#define EXPECT_NEAR(A, B, D) UNIT_ASSERT_DOUBLES_EQUAL(A, B, D)
+#define EXPECT_STREQ(A, B) UNIT_ASSERT_VALUES_EQUAL(A, B)
+
+#define EXPECT_DOUBLE_EQ_TOLERANCE(A, B, tolerance) UNIT_ASSERT_C(fabs((A) - (B)) < tolerance * std::numeric_limits<decltype(A)>::epsilon(), TString("\n") + ToString(A) + " <> " + ToString(B))
+#define EXPECT_DOUBLE_EQ(A, B) EXPECT_DOUBLE_EQ_TOLERANCE(A, B, 4.0)
+
+//conflicts with util/system/defaults.h
+#undef EXPECT_TRUE
+#define EXPECT_TRUE(X) UNIT_ASSERT(X)
+#undef EXPECT_FALSE
+#define EXPECT_FALSE(X) UNIT_ASSERT(!(X))
+
+#define ASSERT_EQ(A, B) EXPECT_EQ(A, B)
+#define ASSERT_NE(A, B) EXPECT_NE(A, B)
+#define ASSERT_GT(A, B) EXPECT_GT(A, B)
+#define ASSERT_LT(A, B) EXPECT_LT(A, B)
+#define ASSERT_FALSE(X) EXPECT_FALSE(X)
+#define ASSERT_TRUE(X) EXPECT_TRUE(X)
+#define ASSERT_THROW(A, B) EXPECT_THROW(A, B)
+#define ASSERT_NO_THROW(A) EXPECT_NO_THROW(A)
+#define ASSERT_DOUBLE_EQ(A, B) EXPECT_DOUBLE_EQ(A, B)
+#define ASSERT_STREQ(A, B) EXPECT_STREQ(A, B)
diff --git a/library/cpp/testing/unittest/plugin.cpp b/library/cpp/testing/unittest/plugin.cpp
new file mode 100644
index 0000000000..543112f7ac
--- /dev/null
+++ b/library/cpp/testing/unittest/plugin.cpp
@@ -0,0 +1,50 @@
+#include "plugin.h"
+
+#include <util/generic/singleton.h>
+#include <util/generic/vector.h>
+#include <util/generic/utility.h>
+
+namespace NUnitTest {
+ namespace NPlugin {
+ namespace {
+ class TPlugins {
+ public:
+ void OnStartMain(int argc, char* argv[]) const {
+ for (const auto& plugin : Plugins) {
+ plugin->OnStartMain(argc, argv);
+ }
+ }
+
+ void OnStopMain(int argc, char* argv[]) const {
+ for (const auto& plugin : Plugins) {
+ plugin->OnStopMain(argc, argv);
+ }
+ }
+
+ void Register(TSimpleSharedPtr<IPlugin> plugin) {
+ Plugins.emplace_back(std::move(plugin));
+ }
+
+ static TPlugins& Instance() {
+ return *Singleton<TPlugins>();
+ }
+
+ private:
+ TVector<TSimpleSharedPtr<IPlugin>> Plugins;
+ };
+ } // anonymous namespace
+
+ TPluginRegistrator::TPluginRegistrator(TSimpleSharedPtr<IPlugin> plugin) {
+ TPlugins::Instance().Register(std::move(plugin));
+ }
+
+ void OnStartMain(int argc, char* argv[]) {
+ TPlugins::Instance().OnStartMain(argc, argv);
+ }
+
+ void OnStopMain(int argc, char* argv[]) {
+ TPlugins::Instance().OnStopMain(argc, argv);
+ }
+
+ }
+}
diff --git a/library/cpp/testing/unittest/plugin.h b/library/cpp/testing/unittest/plugin.h
new file mode 100644
index 0000000000..102f2c1469
--- /dev/null
+++ b/library/cpp/testing/unittest/plugin.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+
+namespace NUnitTest {
+ // Plugins are deprecated, please use Y_TEST_HOOK_* from library/cpp/hook/hook.h
+ namespace NPlugin {
+ class IPlugin {
+ public:
+ virtual ~IPlugin() {
+ }
+
+ virtual void OnStartMain(int /*argc*/, char* /*argv*/ []) {
+ }
+
+ virtual void OnStopMain(int /*argc*/, char* /*argv*/ []) {
+ }
+ };
+
+ void OnStartMain(int argc, char* argv[]);
+ void OnStopMain(int argc, char* argv[]);
+
+ class TPluginRegistrator {
+ public:
+ TPluginRegistrator(TSimpleSharedPtr<IPlugin> plugin);
+ };
+
+ }
+}
diff --git a/library/cpp/testing/unittest/registar.cpp b/library/cpp/testing/unittest/registar.cpp
new file mode 100644
index 0000000000..3679b768ed
--- /dev/null
+++ b/library/cpp/testing/unittest/registar.cpp
@@ -0,0 +1,513 @@
+#include "registar.h"
+
+#include <library/cpp/diff/diff.h>
+#include <library/cpp/colorizer/colors.h>
+
+#include <util/generic/bt_exception.h>
+#include <util/random/fast.h>
+#include <util/string/printf.h>
+#include <util/system/backtrace.h>
+#include <util/system/guard.h>
+#include <util/system/tls.h>
+#include <util/system/error.h>
+#include <util/string/cast.h>
+
+bool NUnitTest::ShouldColorizeDiff = true;
+bool NUnitTest::ContinueOnFail = false;
+
+TString NUnitTest::RandomString(size_t len, ui32 seed) {
+ TReallyFastRng32 rand(seed);
+ TString ret;
+
+ ret.reserve(len);
+
+ for (size_t i = 0; i < len; ++i) {
+ ret.push_back(char(rand.Uniform(1, 128)));
+ }
+
+ return ret;
+}
+
+Y_POD_STATIC_THREAD(bool)
+UnittestThread;
+Y_POD_STATIC_THREAD(NUnitTest::TTestBase*)
+currentTest;
+::NUnitTest::TRaiseErrorHandler RaiseErrorHandler;
+
+void ::NUnitTest::NPrivate::RaiseError(const char* what, const TString& msg, bool fatalFailure) {
+ Y_VERIFY(UnittestThread, "%s in non-unittest thread with message:\n%s", what, msg.data());
+ Y_VERIFY(GetCurrentTest());
+
+ if (RaiseErrorHandler) {
+ RaiseErrorHandler(what, msg, fatalFailure);
+ return;
+ }
+
+ // Default handler
+ TBackTrace bt;
+ bt.Capture();
+ GetCurrentTest()->AddError(msg.data(), bt.PrintToString());
+ if (::NUnitTest::ContinueOnFail || !fatalFailure) {
+ return;
+ }
+ throw TAssertException();
+}
+
+void ::NUnitTest::SetRaiseErrorHandler(::NUnitTest::TRaiseErrorHandler handler) {
+ Y_VERIFY(UnittestThread);
+ RaiseErrorHandler = std::move(handler);
+}
+
+void ::NUnitTest::NPrivate::SetUnittestThread(bool unittestThread) {
+ Y_VERIFY(UnittestThread != unittestThread, "state check");
+ UnittestThread = unittestThread;
+}
+
+void ::NUnitTest::NPrivate::SetCurrentTest(TTestBase* test) {
+ Y_VERIFY(!test || !currentTest, "state check");
+ currentTest = test;
+}
+
+NUnitTest::TTestBase* ::NUnitTest::NPrivate::GetCurrentTest() {
+ return currentTest;
+}
+
+struct TDiffColorizer {
+ NColorizer::TColors Colors;
+ bool Reverse = false;
+
+ explicit TDiffColorizer(bool reverse = false)
+ : Reverse(reverse)
+ {
+ }
+
+ TString Special(TStringBuf str) const {
+ return ToString(Colors.YellowColor()) + str;
+ }
+
+ TString Common(TArrayRef<const char> str) const {
+ return ToString(Colors.OldColor()) + TString(str.begin(), str.end());
+ }
+
+ TString Left(TArrayRef<const char> str) const {
+ return ToString(GetLeftColor()) + TString(str.begin(), str.end());
+ }
+
+ TString Right(TArrayRef<const char> str) const {
+ return ToString(GetRightColor()) + TString(str.begin(), str.end());
+ }
+
+ TStringBuf GetLeftColor() const {
+ return Reverse ? Colors.RedColor() : Colors.GreenColor();
+ }
+
+ TStringBuf GetRightColor() const {
+ return Reverse ? Colors.GreenColor() : Colors.RedColor();
+ }
+};
+
+struct TTraceDiffFormatter {
+ bool Reverse = false;
+
+ explicit TTraceDiffFormatter(bool reverse = false)
+ : Reverse(reverse)
+ {
+ }
+
+ TString Special(TStringBuf str) const {
+ return ToString(str);
+ }
+
+ TString Common(TArrayRef<const char> str) const {
+ return TString(str.begin(), str.end());
+ }
+
+ TString Left(TArrayRef<const char> str) const {
+ return NUnitTest::GetFormatTag("good") +
+ TString(str.begin(), str.end()) +
+ NUnitTest::GetResetTag();
+ }
+
+ TString Right(TArrayRef<const char> str) const {
+ return NUnitTest::GetFormatTag("bad") +
+ TString(str.begin(), str.end()) +
+ NUnitTest::GetResetTag();
+ }
+};
+
+TString NUnitTest::GetFormatTag(const char* name) {
+ return Sprintf("[[%s]]", name);
+}
+
+TString NUnitTest::GetResetTag() {
+ return TString("[[rst]]");
+}
+
+TString NUnitTest::ColoredDiff(TStringBuf s1, TStringBuf s2, const TString& delims, bool reverse) {
+ TStringStream res;
+ TVector<NDiff::TChunk<char>> chunks;
+ NDiff::InlineDiff(chunks, s1, s2, delims);
+ if (NUnitTest::ShouldColorizeDiff) {
+ NDiff::PrintChunks(res, TDiffColorizer(reverse), chunks);
+ } else {
+ res << NUnitTest::GetResetTag();
+ NDiff::PrintChunks(res, TTraceDiffFormatter(reverse), chunks);
+ }
+ return res.Str();
+}
+
+static TString MakeTestName(const NUnitTest::ITestSuiteProcessor::TTest& test) {
+ return TStringBuilder() << test.unit->name << "::" << test.name;
+}
+
+static size_t CountTests(const TMap<TString, size_t>& testErrors, bool succeeded) {
+ size_t cnt = 0;
+ for (const auto& t : testErrors) {
+ if (succeeded && t.second == 0) {
+ ++cnt;
+ } else if (!succeeded && t.second > 0) {
+ ++cnt;
+ }
+ }
+ return cnt;
+}
+
+NUnitTest::ITestSuiteProcessor::ITestSuiteProcessor() = default;
+
+NUnitTest::ITestSuiteProcessor::~ITestSuiteProcessor() = default;
+
+void NUnitTest::ITestSuiteProcessor::Start() {
+ OnStart();
+}
+
+void NUnitTest::ITestSuiteProcessor::End() {
+ OnEnd();
+}
+
+void NUnitTest::ITestSuiteProcessor::UnitStart(const TUnit& unit) {
+ CurTestErrors_.clear();
+
+ OnUnitStart(&unit);
+}
+
+void NUnitTest::ITestSuiteProcessor::UnitStop(const TUnit& unit) {
+ OnUnitStop(&unit);
+}
+
+void NUnitTest::ITestSuiteProcessor::Error(const TError& descr) {
+ AddTestError(*descr.test);
+
+ OnError(&descr);
+}
+
+void NUnitTest::ITestSuiteProcessor::BeforeTest(const TTest& test) {
+ OnBeforeTest(&test);
+}
+
+void NUnitTest::ITestSuiteProcessor::Finish(const TFinish& descr) {
+ AddTestFinish(*descr.test);
+
+ OnFinish(&descr);
+}
+
+unsigned NUnitTest::ITestSuiteProcessor::GoodTests() const noexcept {
+ return CountTests(TestErrors_, true);
+}
+
+unsigned NUnitTest::ITestSuiteProcessor::FailTests() const noexcept {
+ return CountTests(TestErrors_, false);
+}
+
+unsigned NUnitTest::ITestSuiteProcessor::GoodTestsInCurrentUnit() const noexcept {
+ return CountTests(CurTestErrors_, true);
+}
+
+unsigned NUnitTest::ITestSuiteProcessor::FailTestsInCurrentUnit() const noexcept {
+ return CountTests(CurTestErrors_, false);
+}
+
+bool NUnitTest::ITestSuiteProcessor::CheckAccess(TString /*name*/, size_t /*num*/) {
+ return true;
+}
+
+bool NUnitTest::ITestSuiteProcessor::CheckAccessTest(TString /*suite*/, const char* /*name*/) {
+ return true;
+}
+
+void NUnitTest::ITestSuiteProcessor::Run(std::function<void()> f, const TString& /*suite*/, const char* /*name*/, const bool /*forceFork*/) {
+ f();
+}
+
+bool NUnitTest::ITestSuiteProcessor::GetIsForked() const {
+ return false;
+}
+
+bool NUnitTest::ITestSuiteProcessor::GetForkTests() const {
+ return false;
+}
+
+void NUnitTest::ITestSuiteProcessor::OnStart() {
+}
+
+void NUnitTest::ITestSuiteProcessor::OnEnd() {
+}
+
+void NUnitTest::ITestSuiteProcessor::OnUnitStart(const TUnit* /*unit*/) {
+}
+
+void NUnitTest::ITestSuiteProcessor::OnUnitStop(const TUnit* /*unit*/) {
+}
+
+void NUnitTest::ITestSuiteProcessor::OnError(const TError* /*error*/) {
+}
+
+void NUnitTest::ITestSuiteProcessor::OnFinish(const TFinish* /*finish*/) {
+}
+
+void NUnitTest::ITestSuiteProcessor::OnBeforeTest(const TTest* /*test*/) {
+}
+
+void NUnitTest::ITestSuiteProcessor::AddTestError(const TTest& test) {
+ const TString name = MakeTestName(test);
+ ++TestErrors_[name];
+ ++CurTestErrors_[name];
+}
+
+void NUnitTest::ITestSuiteProcessor::AddTestFinish(const TTest& test) {
+ const TString name = MakeTestName(test);
+ TestErrors_[name]; // zero errors if not touched
+ CurTestErrors_[name]; // zero errors if not touched
+}
+
+NUnitTest::ITestBaseFactory::ITestBaseFactory() {
+ Register();
+}
+
+NUnitTest::ITestBaseFactory::~ITestBaseFactory() = default;
+
+void NUnitTest::ITestBaseFactory::Register() noexcept {
+ TTestFactory::Instance().Register(this);
+}
+
+NUnitTest::TTestBase::TTestBase() noexcept
+ : Parent_(nullptr)
+ , TestErrors_()
+ , CurrentSubtest_()
+{
+}
+
+NUnitTest::TTestBase::~TTestBase() = default;
+
+TString NUnitTest::TTestBase::TypeId() const {
+ return TypeName(*this);
+}
+
+void NUnitTest::TTestBase::SetUp() {
+}
+
+void NUnitTest::TTestBase::TearDown() {
+}
+
+void NUnitTest::TTestBase::AddError(const char* msg, const TString& backtrace, TTestContext* context) {
+ ++TestErrors_;
+ const NUnitTest::ITestSuiteProcessor::TUnit unit = {Name()};
+ const NUnitTest::ITestSuiteProcessor::TTest test = {&unit, CurrentSubtest_};
+ const NUnitTest::ITestSuiteProcessor::TError err = {&test, msg, backtrace, context};
+
+ Processor()->Error(err);
+}
+
+void NUnitTest::TTestBase::AddError(const char* msg, TTestContext* context) {
+ AddError(msg, TString(), context);
+}
+
+void NUnitTest::TTestBase::RunAfterTest(std::function<void()> f) {
+ with_lock (AfterTestFunctionsLock_) {
+ AfterTestFunctions_.emplace_back(std::move(f));
+ }
+}
+
+bool NUnitTest::TTestBase::CheckAccessTest(const char* test) {
+ return Processor()->CheckAccessTest(Name(), test);
+}
+
+void NUnitTest::TTestBase::BeforeTest(const char* func) {
+ const NUnitTest::ITestSuiteProcessor::TUnit unit = {Name()};
+ const NUnitTest::ITestSuiteProcessor::TTest test = {&unit, func};
+ rusage.Fill();
+ Processor()->BeforeTest(test);
+}
+
+void NUnitTest::TTestBase::Finish(const char* func, TTestContext* context) {
+ TRusage finishRusage = TRusage::Get();
+ context->Metrics["ru_rss"] = finishRusage.MaxRss - rusage.MaxRss;
+ context->Metrics["ru_major_pagefaults"] = finishRusage.MajorPageFaults - rusage.MajorPageFaults;
+ context->Metrics["ru_utime"] = (finishRusage.Utime - rusage.Utime).MicroSeconds();
+ context->Metrics["ru_stime"] = (finishRusage.Stime - rusage.Stime).MicroSeconds();
+
+ const NUnitTest::ITestSuiteProcessor::TUnit unit = {Name()};
+ const NUnitTest::ITestSuiteProcessor::TTest test = {&unit, func};
+ const NUnitTest::ITestSuiteProcessor::TFinish finish = {&test, context, TestErrors_ == 0};
+
+ Processor()->Finish(finish);
+}
+
+void NUnitTest::TTestBase::AtStart() {
+ const NUnitTest::ITestSuiteProcessor::TUnit unit = {Name()};
+
+ Processor()->UnitStart(unit);
+}
+
+void NUnitTest::TTestBase::AtEnd() {
+ const NUnitTest::ITestSuiteProcessor::TUnit unit = {Name()};
+
+ Processor()->UnitStop(unit);
+}
+
+void NUnitTest::TTestBase::Run(std::function<void()> f, const TString& suite, const char* name, const bool forceFork) {
+ TestErrors_ = 0;
+ CurrentSubtest_ = name;
+ Processor()->Run(f, suite, name, forceFork);
+}
+
+void NUnitTest::TTestBase::BeforeTest() {
+ SetUp();
+}
+
+void NUnitTest::TTestBase::AfterTest() {
+ TearDown();
+
+ TVector<std::function<void()>> afterTestFunctions;
+ with_lock (AfterTestFunctionsLock_) {
+ afterTestFunctions.swap(AfterTestFunctions_);
+ }
+
+ for (auto i = afterTestFunctions.rbegin(); i != afterTestFunctions.rend(); ++i) {
+ std::function<void()>& f = *i;
+ if (f) {
+ f();
+ }
+ }
+}
+
+bool NUnitTest::TTestBase::GetIsForked() const {
+ return Processor()->GetIsForked();
+}
+
+bool NUnitTest::TTestBase::GetForkTests() const {
+ return Processor()->GetForkTests();
+}
+
+NUnitTest::ITestSuiteProcessor* NUnitTest::TTestBase::Processor() const noexcept {
+ return Parent_->Processor();
+}
+
+NUnitTest::TTestBase::TCleanUp::TCleanUp(TTestBase* base)
+ : Base_(base)
+{
+ ::NUnitTest::NPrivate::SetCurrentTest(base);
+ ::NUnitTest::NPrivate::SetUnittestThread(true);
+ Base_->BeforeTest();
+}
+
+NUnitTest::TTestBase::TCleanUp::~TCleanUp() {
+ try {
+ Base_->AfterTest();
+ } catch (...) {
+ Base_->AddError(CurrentExceptionMessage().data());
+ }
+ ::NUnitTest::NPrivate::SetUnittestThread(false);
+ ::NUnitTest::NPrivate::SetCurrentTest(nullptr);
+}
+
+namespace {
+ /*
+ * by default do nothing
+ */
+ class TCommonProcessor: public NUnitTest::ITestSuiteProcessor {
+ public:
+ TCommonProcessor() = default;
+
+ ~TCommonProcessor() override = default;
+ };
+
+ struct TCmp {
+ template <class T>
+ inline bool operator()(const T& l, const T& r) const noexcept {
+ return stricmp(Fix(l.Name().data()), Fix(r.Name().data())) < 0;
+ }
+
+ static inline const char* Fix(const char* n) noexcept {
+ if (*n == 'T') {
+ return n + 1;
+ }
+
+ return n;
+ }
+ };
+}
+
+NUnitTest::TTestFactory::TTestFactory(ITestSuiteProcessor* processor)
+ : Processor_(processor)
+{
+}
+
+NUnitTest::TTestFactory::~TTestFactory() = default;
+
+NUnitTest::TTestFactory& NUnitTest::TTestFactory::Instance() {
+ static TCommonProcessor p;
+ static TTestFactory f(&p);
+
+ return f;
+}
+
+unsigned NUnitTest::TTestFactory::Execute() {
+ Items_.QuickSort(TCmp());
+ Processor_->Start();
+
+ TSet<TString> types;
+ size_t cnt = 0;
+
+ for (TIntrusiveList<ITestBaseFactory>::TIterator factory = Items_.Begin(); factory != Items_.End(); ++factory) {
+ if (!Processor_->CheckAccess(factory->Name(), cnt++)) {
+ continue;
+ }
+
+ THolder<TTestBase> test(factory->ConstructTest());
+
+#ifdef _unix_ // on Windows RTTI causes memory leaks
+ TString type = test->TypeId();
+ if (types.insert(type).second == false) {
+ warnx("Duplicate suite found: %s (%s). Probably you have copy-pasted suite without changing it name", factory->Name().c_str(), type.c_str());
+ return 1;
+ }
+#endif // _unix_
+
+ test->Parent_ = this;
+
+#ifdef UT_SKIP_EXCEPTIONS
+ try {
+#endif
+ test->Execute();
+#ifdef UT_SKIP_EXCEPTIONS
+ } catch (...) {
+ }
+#endif
+ }
+
+ Processor_->End();
+
+ return bool(Processor_->FailTests());
+}
+
+void NUnitTest::TTestFactory::SetProcessor(ITestSuiteProcessor* processor) {
+ Processor_ = processor;
+}
+
+void NUnitTest::TTestFactory::Register(ITestBaseFactory* b) noexcept {
+ Items_.PushBack(b);
+}
+
+NUnitTest::ITestSuiteProcessor* NUnitTest::TTestFactory::Processor() const noexcept {
+ return Processor_;
+}
diff --git a/library/cpp/testing/unittest/registar.h b/library/cpp/testing/unittest/registar.h
new file mode 100644
index 0000000000..332485bdf3
--- /dev/null
+++ b/library/cpp/testing/unittest/registar.h
@@ -0,0 +1,1013 @@
+#pragma once
+
+#include <library/cpp/dbg_output/dump.h>
+
+#include <util/generic/bt_exception.h>
+#include <util/generic/hash.h>
+#include <util/generic/intrlist.h>
+#include <util/generic/map.h>
+#include <util/generic/ptr.h>
+#include <util/generic/set.h>
+#include <util/generic/typetraits.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+
+#include <util/string/builder.h>
+#include <util/string/cast.h>
+#include <util/string/printf.h>
+
+#include <util/system/defaults.h>
+#include <util/system/type_name.h>
+#include <util/system/spinlock.h>
+#include <util/system/src_location.h>
+
+#include <util/system/rusage.h>
+
+#include <cmath>
+#include <cstdio>
+#include <functional>
+
+extern bool CheckExceptionMessage(const char*, TString&);
+
+namespace NUnitTest {
+ class TTestBase;
+
+ namespace NPrivate {
+ void RaiseError(const char* what, const TString& msg, bool fatalFailure);
+ void SetUnittestThread(bool);
+ void SetCurrentTest(TTestBase*);
+ TTestBase* GetCurrentTest();
+ }
+
+ extern bool ShouldColorizeDiff;
+ extern bool ContinueOnFail;
+ TString ColoredDiff(TStringBuf s1, TStringBuf s2, const TString& delims = TString(), bool reverse = false);
+ TString GetFormatTag(const char* name);
+ TString GetResetTag();
+
+ // Raise error handler
+ // Used for testing library/cpp/testing/unittest macroses
+ // and unittest helpers.
+ // For all other unittests standard handler is used
+ using TRaiseErrorHandler = std::function<void(const char*, const TString&, bool)>;
+
+ void SetRaiseErrorHandler(TRaiseErrorHandler handler);
+
+ inline void ClearRaiseErrorHandler() {
+ SetRaiseErrorHandler(TRaiseErrorHandler());
+ }
+
+ class TAssertException: public yexception {
+ };
+
+ class ITestSuiteProcessor;
+
+ struct TTestContext {
+ TTestContext()
+ : Processor(nullptr)
+ {
+ }
+
+ explicit TTestContext(ITestSuiteProcessor* processor)
+ : Processor(processor)
+ {
+ }
+
+ using TMetrics = THashMap<TString, double>;
+ TMetrics Metrics;
+
+ ITestSuiteProcessor* Processor;
+ };
+
+ class ITestSuiteProcessor {
+ public:
+ struct TUnit {
+ const TString name;
+ };
+
+ struct TTest {
+ const TUnit* unit;
+ const char* name;
+ };
+
+ struct TError {
+ const TTest* test;
+ const char* msg;
+ TString BackTrace;
+ TTestContext* Context;
+ };
+
+ struct TFinish {
+ const TTest* test;
+ TTestContext* Context;
+ bool Success;
+ };
+
+ ITestSuiteProcessor();
+
+ virtual ~ITestSuiteProcessor();
+
+ void Start();
+
+ void End();
+
+ void UnitStart(const TUnit& unit);
+
+ void UnitStop(const TUnit& unit);
+
+ void Error(const TError& descr);
+
+ void BeforeTest(const TTest& test);
+
+ void Finish(const TFinish& descr);
+
+ unsigned GoodTests() const noexcept;
+
+ unsigned FailTests() const noexcept;
+
+ unsigned GoodTestsInCurrentUnit() const noexcept;
+
+ unsigned FailTestsInCurrentUnit() const noexcept;
+
+ // Should execute test suite?
+ virtual bool CheckAccess(TString /*name*/, size_t /*num*/);
+
+ // Should execute a test whitin suite?
+ virtual bool CheckAccessTest(TString /*suite*/, const char* /*name*/);
+
+ virtual void Run(std::function<void()> f, const TString& /*suite*/, const char* /*name*/, bool /*forceFork*/);
+
+ // This process is forked for current test
+ virtual bool GetIsForked() const;
+
+ // --fork-tests is set (warning: this may be false, but never the less test will be forked if called inside UNIT_FORKED_TEST)
+ virtual bool GetForkTests() const;
+
+ private:
+ virtual void OnStart();
+
+ virtual void OnEnd();
+
+ virtual void OnUnitStart(const TUnit* /*unit*/);
+
+ virtual void OnUnitStop(const TUnit* /*unit*/);
+
+ virtual void OnError(const TError* /*error*/);
+
+ virtual void OnFinish(const TFinish* /*finish*/);
+
+ virtual void OnBeforeTest(const TTest* /*test*/);
+
+ void AddTestError(const TTest& test);
+
+ void AddTestFinish(const TTest& test);
+
+ private:
+ TMap<TString, size_t> TestErrors_;
+ TMap<TString, size_t> CurTestErrors_;
+ };
+
+ class TTestBase;
+ class TTestFactory;
+
+ class ITestBaseFactory: public TIntrusiveListItem<ITestBaseFactory> {
+ public:
+ ITestBaseFactory();
+
+ virtual ~ITestBaseFactory();
+
+ // name of test suite
+ virtual TString Name() const noexcept = 0;
+ virtual TTestBase* ConstructTest() = 0;
+
+ private:
+ void Register() noexcept;
+ };
+
+ class TTestBase {
+ friend class TTestFactory;
+ TRusage rusage;
+
+ public:
+ TTestBase() noexcept;
+
+ virtual ~TTestBase();
+
+ virtual TString TypeId() const;
+
+ virtual TString Name() const noexcept = 0;
+ virtual void Execute() = 0;
+
+ virtual void SetUp();
+
+ virtual void TearDown();
+
+ void AddError(const char* msg, const TString& backtrace = TString(), TTestContext* context = nullptr);
+
+ void AddError(const char* msg, TTestContext* context);
+
+ void RunAfterTest(std::function<void()> f); // function like atexit to run after current unit test
+
+ protected:
+ bool CheckAccessTest(const char* test);
+
+ void BeforeTest(const char* func);
+
+ void Finish(const char* func, TTestContext* context);
+
+ void AtStart();
+
+ void AtEnd();
+
+ void Run(std::function<void()> f, const TString& suite, const char* name, bool forceFork);
+
+ class TCleanUp {
+ public:
+ explicit TCleanUp(TTestBase* base);
+
+ ~TCleanUp();
+
+ private:
+ TTestBase* Base_;
+ };
+
+ void BeforeTest();
+
+ void AfterTest();
+
+ bool GetIsForked() const;
+
+ bool GetForkTests() const;
+
+ ITestSuiteProcessor* Processor() const noexcept;
+
+ private:
+ TTestFactory* Parent_;
+ size_t TestErrors_;
+ const char* CurrentSubtest_;
+ TAdaptiveLock AfterTestFunctionsLock_;
+ TVector<std::function<void()>> AfterTestFunctions_;
+ };
+
+#define UNIT_TEST_SUITE(N) \
+ typedef N TThisUnitTestSuite; \
+ \
+public: \
+ static TString StaticName() noexcept { \
+ return TString(#N); \
+ } \
+ \
+private: \
+ virtual TString Name() const noexcept override { \
+ return this->StaticName(); \
+ } \
+ \
+ virtual void Execute() override { \
+ this->AtStart();
+
+#define UNIT_TEST_SUITE_DEMANGLE(N) \
+ typedef N TThisUnitTestSuite; \
+ \
+public: \
+ static TString StaticName() noexcept { \
+ return TypeName<N>(); \
+ } \
+ \
+private: \
+ virtual TString Name() const noexcept override { \
+ return this->StaticName(); \
+ } \
+ \
+ virtual void Execute() override { \
+ this->AtStart();
+
+#ifndef UT_SKIP_EXCEPTIONS
+#define CATCH_REACTION(FN, e, context) this->AddError(("(" + TypeName(e) + ") " + e.what()).data(), context)
+#define CATCH_REACTION_BT(FN, e, context) this->AddError(("(" + TypeName(e) + ") " + e.what()).data(), (e.BackTrace() ? e.BackTrace()->PrintToString() : TString()), context)
+#else
+#define CATCH_REACTION(FN, e, context) throw
+#define CATCH_REACTION_BT(FN, e, context) throw
+#endif
+
+#define UNIT_TEST_CHECK_TEST_IS_DECLARED_ONLY_ONCE(F) \
+ /* If you see this message - delete multiple UNIT_TEST(TestName) with same TestName. */ \
+ /* It's forbidden to declare same test twice because it breaks --fork-tests logic. */ \
+ int You_have_declared_test_##F##_multiple_times_This_is_forbidden; \
+ Y_UNUSED(You_have_declared_test_##F##_multiple_times_This_is_forbidden);
+
+#define UNIT_TEST_RUN(F, FF, context) \
+ this->BeforeTest((#F)); \
+ { \
+ struct T##F##Caller { \
+ static void X(TThisUnitTestSuite* thiz, NUnitTest::TTestContext&) { \
+ TCleanUp cleaner(thiz); \
+ thiz->F(); \
+ } \
+ }; \
+ this->TTestBase::Run(std::bind(&T##F##Caller::X, this, context), StaticName(), (#F), FF); \
+ }
+
+#define UNIT_TEST_IMPL(F, FF) \
+ UNIT_TEST_CHECK_TEST_IS_DECLARED_ONLY_ONCE(F) { \
+ NUnitTest::TTestContext context(this->TTestBase::Processor()); \
+ if (this->CheckAccessTest((#F))) { \
+ try { \
+ UNIT_TEST_RUN(F, FF, context) \
+ } catch (const ::NUnitTest::TAssertException&) { \
+ } catch (const yexception& e) { \
+ CATCH_REACTION_BT((#F), e, &context); \
+ } catch (const std::exception& e) { \
+ CATCH_REACTION((#F), e, &context); \
+ } catch (...) { \
+ this->AddError("non-std exception!", &context); \
+ } \
+ this->Finish((#F), &context); \
+ } \
+ }
+
+#define UNIT_TEST(F) UNIT_TEST_IMPL(F, false)
+
+#define UNIT_FORKED_TEST(F) UNIT_TEST_IMPL(F, true)
+
+#define UNIT_TEST_EXCEPTION(F, E) \
+ /* main process with "--fork-tests" flag treats exceptions as errors - it's result of forked test run */ \
+ if (this->GetForkTests() && !this->GetIsForked()) { \
+ UNIT_TEST_IMPL(F, false); \
+ /* forked process (or main without "--fork-tests") treats some exceptions as success - it's exception test! */ \
+ } else { \
+ NUnitTest::TTestContext context(this->TTestBase::Processor()); \
+ if (this->CheckAccessTest((#F))) { \
+ try { \
+ UNIT_TEST_RUN(F, false, context) \
+ this->AddError("exception expected", &context); \
+ } catch (const ::NUnitTest::TAssertException&) { \
+ } catch (const E& e) { \
+ TString err; \
+ if (!CheckExceptionMessage(e.what(), err)) \
+ this->AddError(err.c_str(), &context); \
+ } catch (const std::exception& e) { \
+ this->AddError(e.what(), &context); \
+ } catch (...) { \
+ this->AddError("non-std exception!", &context); \
+ } \
+ this->Finish((#F), &context); \
+ } \
+ }
+
+#define UNIT_TEST_SUITE_END() \
+ this->AtEnd(); \
+ } \
+ \
+public: \
+ /*for ; after macros*/ void sub##F()
+
+#define UNIT_FAIL_IMPL(R, M) \
+ do { \
+ ::NUnitTest::NPrivate::RaiseError(R, ::TStringBuilder() << R << " at " << __LOCATION__ << ", " << __PRETTY_FUNCTION__ << ": " << M, true); \
+ } while (false)
+
+#define UNIT_FAIL_NONFATAL_IMPL(R, M) \
+ do { \
+ ::NUnitTest::NPrivate::RaiseError(R, ::TStringBuilder() << R << " at " << __LOCATION__ << ", " << __PRETTY_FUNCTION__ << ": " << M, false); \
+ } while (false)
+
+#define UNIT_FAIL(M) UNIT_FAIL_IMPL("forced failure", M)
+#define UNIT_FAIL_NONFATAL(M) UNIT_FAIL_NONFATAL_IMPL("forced failure", M)
+
+//types
+#define UNIT_ASSERT_TYPES_EQUAL(A, B) \
+ do { \
+ if (!std::is_same<A, B>::value) { \
+ UNIT_FAIL_IMPL("types equal assertion failed", (::TStringBuilder() << #A << " (" << TypeName<A>() << ") != " << #B << " (" << TypeName<B>() << ")").data()); \
+ } \
+ } while (false)
+
+//doubles
+// UNIT_ASSERT_DOUBLES_EQUAL_DEPRECATED* macros do not handle NaNs correctly (see IGNIETFERRO-1419) and are for backward compatibility
+// only. Consider switching to regular UNIT_ASSERT_DOUBLES_EQUAL* macros if you're still using the deprecated version.
+#define UNIT_ASSERT_DOUBLES_EQUAL_DEPRECATED_C(E, A, D, C) \
+ do { \
+ if (std::abs((E) - (A)) > (D)) { \
+ const auto _es = ToString((long double)(E)); \
+ const auto _as = ToString((long double)(A)); \
+ const auto _ds = ToString((long double)(D)); \
+ auto&& failMsg = Sprintf("std::abs(%s - %s) > %s %s", _es.data(), _as.data(), _ds.data(), (::TStringBuilder() << C).data()); \
+ UNIT_FAIL_IMPL("assertion failure", failMsg); \
+ } \
+ } while (false)
+
+#define UNIT_ASSERT_DOUBLES_EQUAL_DEPRECATED(E, A, D) UNIT_ASSERT_DOUBLES_EQUAL_DEPRECATED_C(E, A, D, "")
+
+#define UNIT_ASSERT_DOUBLES_EQUAL_C(E, A, D, C) \
+ do { \
+ const auto _ed = (E); \
+ const auto _ad = (A); \
+ const auto _dd = (D); \
+ if (std::isnan((long double)_ed) && !std::isnan((long double)_ad)) { \
+ const auto _as = ToString((long double)_ad); \
+ auto&& failMsg = Sprintf("expected NaN, got %s %s", _as.data(), (::TStringBuilder() << C).data()); \
+ UNIT_FAIL_IMPL("assertion failure", failMsg); \
+ } \
+ if (!std::isnan((long double)_ed) && std::isnan((long double)_ad)) { \
+ const auto _es = ToString((long double)_ed); \
+ auto&& failMsg = Sprintf("expected %s, got NaN %s", _es.data(), (::TStringBuilder() << C).data()); \
+ UNIT_FAIL_IMPL("assertion failure", failMsg); \
+ } \
+ if (std::abs((_ed) - (_ad)) > (_dd)) { \
+ const auto _es = ToString((long double)_ed); \
+ const auto _as = ToString((long double)_ad); \
+ const auto _ds = ToString((long double)_dd); \
+ auto&& failMsg = Sprintf("std::abs(%s - %s) > %s %s", _es.data(), _as.data(), _ds.data(), (::TStringBuilder() << C).data()); \
+ UNIT_FAIL_IMPL("assertion failure", failMsg); \
+ } \
+ } while (false)
+
+#define UNIT_ASSERT_DOUBLES_EQUAL(E, A, D) UNIT_ASSERT_DOUBLES_EQUAL_C(E, A, D, "")
+
+//strings
+#define UNIT_ASSERT_STRINGS_EQUAL_C(A, B, C) \
+ do { \
+ const TString _a(A); \
+ const TString _b(B); \
+ if (_a != _b) { \
+ auto&& failMsg = Sprintf("%s != %s %s", ToString(_a).data(), ToString(_b).data(), (::TStringBuilder() << C).data()); \
+ UNIT_FAIL_IMPL("strings equal assertion failed", failMsg); \
+ } \
+ } while (false)
+
+#define UNIT_ASSERT_STRINGS_EQUAL(A, B) UNIT_ASSERT_STRINGS_EQUAL_C(A, B, "")
+
+#define UNIT_ASSERT_STRING_CONTAINS_C(A, B, C) \
+ do { \
+ const TString _a(A); \
+ const TString _b(B); \
+ if (!_a.Contains(_b)) { \
+ auto&& msg = Sprintf("\"%s\" does not contain \"%s\", %s", ToString(_a).data(), ToString(_b).data(), (::TStringBuilder() << C).data()); \
+ UNIT_FAIL_IMPL("strings contains assertion failed", msg); \
+ } \
+ } while (false)
+
+#define UNIT_ASSERT_STRING_CONTAINS(A, B) UNIT_ASSERT_STRING_CONTAINS_C(A, B, "")
+
+#define UNIT_ASSERT_NO_DIFF(A, B) \
+ do { \
+ const TString _a(A); \
+ const TString _b(B); \
+ if (_a != _b) { \
+ UNIT_FAIL_IMPL("strings (" #A ") and (" #B ") are different", Sprintf("\n%s", ::NUnitTest::ColoredDiff(_a, _b, " \t\n.,:;'\"").data())); \
+ } \
+ } while (false)
+
+//strings
+#define UNIT_ASSERT_STRINGS_UNEQUAL_C(A, B, C) \
+ do { \
+ const TString _a(A); \
+ const TString _b(B); \
+ if (_a == _b) { \
+ auto&& msg = Sprintf("%s == %s %s", ToString(_a).data(), ToString(_b).data(), (::TStringBuilder() << C).data()); \
+ UNIT_FAIL_IMPL("strings unequal assertion failed", msg); \
+ } \
+ } while (false)
+
+#define UNIT_ASSERT_STRINGS_UNEQUAL(A, B) UNIT_ASSERT_STRINGS_UNEQUAL_C(A, B, "")
+
+//bool
+#define UNIT_ASSERT_C(A, C) \
+ do { \
+ if (!(A)) { \
+ UNIT_FAIL_IMPL("assertion failed", Sprintf("(%s) %s", #A, (::TStringBuilder() << C).data())); \
+ } \
+ } while (false)
+
+#define UNIT_ASSERT(A) UNIT_ASSERT_C(A, "")
+
+//general
+#define UNIT_ASSERT_EQUAL_C(A, B, C) \
+ do { \
+ if (!((A) == (B))) { \
+ UNIT_FAIL_IMPL("equal assertion failed", Sprintf("%s == %s %s", #A, #B, (::TStringBuilder() << C).data())); \
+ } \
+ } while (false)
+
+#define UNIT_ASSERT_EQUAL(A, B) UNIT_ASSERT_EQUAL_C(A, B, "")
+
+#define UNIT_ASSERT_UNEQUAL_C(A, B, C) \
+ do { \
+ if ((A) == (B)) { \
+ UNIT_FAIL_IMPL("unequal assertion failed", Sprintf("%s != %s %s", #A, #B, (::TStringBuilder() << C).data()));\
+ } \
+ } while (false)
+
+#define UNIT_ASSERT_UNEQUAL(A, B) UNIT_ASSERT_UNEQUAL_C(A, B, "")
+
+#define UNIT_ASSERT_LT_C(A, B, C) \
+ do { \
+ if (!((A) < (B))) { \
+ UNIT_FAIL_IMPL("less-than assertion failed", Sprintf("%s < %s %s", #A, #B, (::TStringBuilder() << C).data())); \
+ } \
+ } while (false)
+
+#define UNIT_ASSERT_LT(A, B) UNIT_ASSERT_LT_C(A, B, "")
+
+#define UNIT_ASSERT_LE_C(A, B, C) \
+ do { \
+ if (!((A) <= (B))) { \
+ UNIT_FAIL_IMPL("less-or-equal assertion failed", Sprintf("%s <= %s %s", #A, #B, (::TStringBuilder() << C).data())); \
+ } \
+ } while (false)
+
+#define UNIT_ASSERT_LE(A, B) UNIT_ASSERT_LE_C(A, B, "")
+
+#define UNIT_ASSERT_GT_C(A, B, C) \
+ do { \
+ if (!((A) > (B))) { \
+ UNIT_FAIL_IMPL("greater-than assertion failed", Sprintf("%s > %s %s", #A, #B, (::TStringBuilder() << C).data())); \
+ } \
+ } while (false)
+
+#define UNIT_ASSERT_GT(A, B) UNIT_ASSERT_GT_C(A, B, "")
+
+#define UNIT_ASSERT_GE_C(A, B, C) \
+ do { \
+ if (!((A) >= (B))) { \
+ UNIT_FAIL_IMPL("greater-or-equal assertion failed", Sprintf("%s >= %s %s", #A, #B, (::TStringBuilder() << C).data())); \
+ } \
+ } while (false)
+
+#define UNIT_ASSERT_GE(A, B) UNIT_ASSERT_GE_C(A, B, "")
+
+#define UNIT_CHECK_GENERATED_EXCEPTION_C(A, E, C) \
+ do { \
+ try { \
+ (void)(A); \
+ } catch (const ::NUnitTest::TAssertException&) { \
+ throw; \
+ } catch (const E&) { \
+ break; \
+ } \
+ UNIT_ASSERT_C(0, "Exception hasn't been thrown, but it should have happened " << C); \
+ } while (false)
+
+#define UNIT_CHECK_GENERATED_EXCEPTION(A, E) UNIT_CHECK_GENERATED_EXCEPTION_C(A, E, "")
+
+#define UNIT_CHECK_GENERATED_NO_EXCEPTION_C(A, E, C) \
+ do { \
+ try { \
+ (void)(A); \
+ } catch (const ::NUnitTest::TAssertException&) { \
+ throw; \
+ } catch (const E&) { \
+ UNIT_ASSERT_C(0, "Exception has been thrown, but it shouldn't have happened " << C); \
+ } \
+ } while (false)
+
+#define UNIT_CHECK_GENERATED_NO_EXCEPTION(A, E) UNIT_CHECK_GENERATED_NO_EXCEPTION_C(A, E, "and exception message is:\n" << CurrentExceptionMessage())
+
+// Same as UNIT_ASSERT_EXCEPTION_SATISFIES but prints additional string C when nothing was thrown
+#define UNIT_ASSERT_EXCEPTION_SATISFIES_C(A, E, pred, C) \
+ do { \
+ bool _thrown = false; \
+ try { \
+ (void)(A); \
+ } catch (const ::NUnitTest::TAssertException&) { \
+ throw; \
+ } catch (const E& e) { \
+ _thrown = true; \
+ UNIT_ASSERT_C(pred(e), "Exception does not satisfy predicate '" \
+ << #pred << "'"); \
+ } catch (...) { \
+ _thrown = true; \
+ UNIT_FAIL_IMPL("exception assertion failed", \
+ #A << " did not throw " << #E \
+ << ", but threw other exception " \
+ << "with message:\n" \
+ << CurrentExceptionMessage()); \
+ } \
+ if (!_thrown) { \
+ UNIT_FAIL_IMPL("exception assertion failed", \
+ #A << " did not throw any exception" \
+ << " (expected " << #E << ") " << C); \
+ } \
+ } while (false)
+
+// Assert that a specific exception is thrown and satisfies predicate pred(e), where e is the exception instance.
+// Example:
+// UNIT_ASSERT_EXCEPTION_SATISFIES(MakeRequest(invalidData), TError,
+// [](const TError& e){ return e.Status == HTTP_BAD_REQUEST; })
+// This code validates that MakeRequest with invalidData throws TError with code 400.
+#define UNIT_ASSERT_EXCEPTION_SATISFIES(A, E, pred) \
+ UNIT_ASSERT_EXCEPTION_SATISFIES_C(A, E, pred, "")
+
+// Same as UNIT_ASSERT_EXCEPTION_CONTAINS but prints additional string C when nothing was thrown
+#define UNIT_ASSERT_EXCEPTION_CONTAINS_C(A, E, substr, C) \
+ do { \
+ const TString _substr{substr}; \
+ UNIT_ASSERT_EXCEPTION_SATISFIES_C(A, E, \
+ [&_substr](const E&){ \
+ if (!_substr.empty()) { \
+ UNIT_ASSERT_C(CurrentExceptionMessage() \
+ .Contains(_substr), \
+ "Exception message does not contain \"" \
+ << _substr << "\".\n" \
+ << "Exception message: " \
+ << CurrentExceptionMessage()); \
+ } \
+ return true; \
+ }, \
+ C); \
+ } while (false)
+
+// Assert that a specific exception is thrown and CurrentExceptionMessage() contains substr
+#define UNIT_ASSERT_EXCEPTION_CONTAINS(A, E, substr) \
+ UNIT_ASSERT_EXCEPTION_CONTAINS_C(A, E, substr, "")
+
+// Same as UNIT_ASSERT_EXCEPTION but prints additional string C when nothing was thrown
+#define UNIT_ASSERT_EXCEPTION_C(A, E, C) UNIT_ASSERT_EXCEPTION_SATISFIES_C(A, E, [](const E&){ return true; }, C)
+
+// Assert that a specific exception is thrown
+#define UNIT_ASSERT_EXCEPTION(A, E) UNIT_ASSERT_EXCEPTION_C(A, E, "")
+
+#define UNIT_ASSERT_NO_EXCEPTION_C(A, C) \
+ do { \
+ try { \
+ (void)(A); \
+ } catch (const ::NUnitTest::TAssertException&) { \
+ throw; \
+ } catch (...) { \
+ UNIT_FAIL_IMPL("exception-free assertion failed", Sprintf("%s throws %s\nException message: %s", #A, (::TStringBuilder() << C).data(), CurrentExceptionMessage().data())); \
+ } \
+ } while (false)
+
+#define UNIT_ASSERT_NO_EXCEPTION(A) UNIT_ASSERT_NO_EXCEPTION_C(A, "")
+
+ namespace NPrivate {
+ template <class T, class U, bool Integers>
+ struct TCompareValuesImpl {
+ static inline bool Compare(const T& a, const U& b) {
+ return a == b;
+ }
+ };
+
+ template <class T, class U>
+ struct TCompareValuesImpl<T, U, true> {
+ static inline bool Compare(const T& a, const U& b) {
+ return ::ToString(a) == ::ToString(b);
+ }
+ };
+
+ template <class T, class U>
+ using TCompareValues = TCompareValuesImpl<T, U, std::is_integral<T>::value && std::is_integral<U>::value>;
+
+ template <typename T, typename U>
+ static inline bool CompareEqual(const T& a, const U& b) {
+ return TCompareValues<T, U>::Compare(a, b);
+ }
+
+ static inline bool CompareEqual(const char* a, const char* b) {
+ return 0 == strcmp(a, b);
+ }
+
+ // helper method to avoid double evaluation of A and B expressions in UNIT_ASSERT_VALUES_EQUAL_C
+ template <typename T, typename U>
+ static inline bool CompareAndMakeStrings(const T& a, const U& b, TString& as, TString& asInd, TString& bs, TString& bsInd, bool& usePlainDiff, bool want) {
+ const bool have = CompareEqual(a, b);
+ usePlainDiff = std::is_integral<T>::value && std::is_integral<U>::value;
+
+ if (want == have) {
+ return true;
+ }
+
+ as = ::TStringBuilder() << ::DbgDump(a);
+ bs = ::TStringBuilder() << ::DbgDump(b);
+ asInd = ::TStringBuilder() << ::DbgDump(a).SetIndent(true);
+ bsInd = ::TStringBuilder() << ::DbgDump(b).SetIndent(true);
+
+ return false;
+ }
+ }
+
+//values
+#define UNIT_ASSERT_VALUES_EQUAL_IMPL(A, B, C, EQflag, EQstr, NEQstr) \
+ do { \
+ TString _as; \
+ TString _bs; \
+ TString _asInd; \
+ TString _bsInd; \
+ bool _usePlainDiff; \
+ if (!::NUnitTest::NPrivate::CompareAndMakeStrings(A, B, _as, _asInd, _bs, _bsInd, _usePlainDiff, EQflag)) { \
+ auto&& failMsg = Sprintf("(%s %s %s) failed: (%s %s %s) %s", #A, EQstr, #B, _as.data(), NEQstr, _bs.data(), (::TStringBuilder() << C).data()); \
+ if (EQflag && !_usePlainDiff) { \
+ failMsg += ", with diff:\n"; \
+ failMsg += ::NUnitTest::ColoredDiff(_asInd, _bsInd); \
+ } \
+ UNIT_FAIL_IMPL("assertion failed", failMsg); \
+ } \
+ } while (false)
+
+#define UNIT_ASSERT_VALUES_EQUAL_C(A, B, C) \
+ UNIT_ASSERT_VALUES_EQUAL_IMPL(A, B, C, true, "==", "!=")
+
+#define UNIT_ASSERT_VALUES_UNEQUAL_C(A, B, C) \
+ UNIT_ASSERT_VALUES_EQUAL_IMPL(A, B, C, false, "!=", "==")
+
+#define UNIT_ASSERT_VALUES_EQUAL(A, B) UNIT_ASSERT_VALUES_EQUAL_C(A, B, "")
+#define UNIT_ASSERT_VALUES_UNEQUAL(A, B) UNIT_ASSERT_VALUES_UNEQUAL_C(A, B, "")
+
+// Checks that test will fail while executing given expression
+// Macro for using in unitests for ut helpers
+#define UNIT_ASSERT_TEST_FAILS_C(A, C) \
+ do { \
+ ::NUnitTest::TUnitTestFailChecker checker; \
+ try { \
+ auto guard = checker.InvokeGuard(); \
+ (void)(A); \
+ } catch (...) { \
+ UNIT_FAIL_IMPL("fail test assertion failure", \
+ "code is expected to generate test failure, " \
+ "but it throws exception with message: " \
+ << CurrentExceptionMessage()); \
+ } \
+ if (!checker.Failed()) { \
+ UNIT_FAIL_IMPL("fail test assertion failure", \
+ "code is expected to generate test failure"); \
+ } \
+ } while (false)
+
+#define UNIT_ASSERT_TEST_FAILS(A) UNIT_ASSERT_TEST_FAILS_C(A, "")
+
+#define UNIT_ADD_METRIC(name, value) ut_context.Metrics[name] = value
+
+ class TTestFactory {
+ friend class TTestBase;
+ friend class ITestBaseFactory;
+
+ public:
+ static TTestFactory& Instance();
+
+ unsigned Execute();
+
+ void SetProcessor(ITestSuiteProcessor* processor);
+
+ private:
+ void Register(ITestBaseFactory* b) noexcept;
+
+ ITestSuiteProcessor* Processor() const noexcept;
+
+ private:
+ explicit TTestFactory(ITestSuiteProcessor* processor);
+
+ ~TTestFactory();
+
+ private:
+ TIntrusiveList<ITestBaseFactory> Items_;
+ ITestSuiteProcessor* Processor_;
+ };
+
+ template <class T>
+ class TTestBaseFactory: public ITestBaseFactory {
+ public:
+ ~TTestBaseFactory() override = default;
+
+ inline TTestBase* ConstructTest() override {
+ return new T;
+ }
+
+ inline TString Name() const noexcept override {
+ return T::StaticName();
+ }
+ };
+
+ struct TBaseTestCase {
+ // NOTE: since EACH test case is instantiated for listing tests, its
+ // ctor/dtor are not the best place to do heavy preparations in test fixtures.
+ //
+ // Consider using SetUp()/TearDown() methods instead
+
+ inline TBaseTestCase()
+ : TBaseTestCase(nullptr, nullptr, false)
+ {
+ }
+
+ inline TBaseTestCase(const char* name, std::function<void(TTestContext&)> body, bool forceFork)
+ : Name_(name)
+ , Body_(std::move(body))
+ , ForceFork_(forceFork)
+ {
+ }
+
+ virtual ~TBaseTestCase() = default;
+
+ // Each test case is executed in 3 steps:
+ //
+ // 1. SetUp() (from fixture)
+ // 2. Execute_() (test body from Y_UNIT_TEST macro)
+ // 3. TearDown() (from fixture)
+ //
+ // Both SetUp() and TearDown() may use UNIT_* check macros and are only
+ // called when the test is executed.
+
+ virtual void SetUp(TTestContext& /* context */) {
+ }
+
+ virtual void TearDown(TTestContext& /* context */) {
+ }
+
+ virtual void Execute_(TTestContext& context) {
+ Body_(context);
+ }
+
+ const char* Name_;
+ std::function<void(TTestContext&)> Body_;
+ bool ForceFork_;
+ };
+
+ using TBaseFixture = TBaseTestCase;
+
+ // Class for checking that code raises unittest failure
+ class TUnitTestFailChecker {
+ public:
+ struct TInvokeGuard {
+ explicit TInvokeGuard(TUnitTestFailChecker& parent)
+ : Parent(&parent)
+ {
+ Parent->SetHandler();
+ }
+
+ TInvokeGuard(TInvokeGuard&& guard) noexcept
+ : Parent(guard.Parent)
+ {
+ guard.Parent = nullptr;
+ }
+
+ ~TInvokeGuard() {
+ if (Parent) {
+ ClearRaiseErrorHandler();
+ }
+ }
+
+ TUnitTestFailChecker* Parent;
+ };
+
+ TUnitTestFailChecker() = default;
+ TUnitTestFailChecker(const TUnitTestFailChecker&) = delete;
+ TUnitTestFailChecker(TUnitTestFailChecker&&) = delete;
+
+ TInvokeGuard InvokeGuard() {
+ return TInvokeGuard(*this);
+ }
+
+ const TString& What() const {
+ return What_;
+ }
+
+ const TString& Msg() const {
+ return Msg_;
+ }
+
+ bool FatalFailure() const {
+ return FatalFailure_;
+ }
+
+ bool Failed() const {
+ return Failed_;
+ }
+
+ private:
+ void Handler(const char* what, const TString& msg, bool fatalFailure) {
+ What_ = what;
+ Msg_ = msg;
+ FatalFailure_ = fatalFailure;
+ Failed_ = true;
+ }
+
+ void SetHandler() {
+ TRaiseErrorHandler handler = [this](const char* what, const TString& msg, bool fatalFailure) {
+ Handler(what, msg, fatalFailure);
+ };
+ SetRaiseErrorHandler(std::move(handler));
+ }
+
+ private:
+ TString What_;
+ TString Msg_;
+ bool FatalFailure_ = false;
+ bool Failed_ = false;
+ };
+
+#define UNIT_TEST_SUITE_REGISTRATION(T) \
+ static const ::NUnitTest::TTestBaseFactory<T> Y_GENERATE_UNIQUE_ID(UTREG_);
+
+#define Y_UNIT_TEST_SUITE_IMPL_F(N, T, F) \
+ namespace NTestSuite##N { \
+ class TCurrentTestCase: public F { \
+ }; \
+ class TCurrentTest: public T { \
+ private: \
+ typedef std::function<THolder<NUnitTest::TBaseTestCase>()> TTestCaseFactory; \
+ typedef TVector<TTestCaseFactory> TTests; \
+ \
+ static TTests& Tests() { \
+ static TTests tests; \
+ return tests; \
+ } \
+ \
+ public: \
+ static TString StaticName() { \
+ return #N; \
+ } \
+ virtual TString Name() const noexcept { \
+ return StaticName(); \
+ } \
+ \
+ static void AddTest(const char* name, \
+ const std::function<void(NUnitTest::TTestContext&)>& body, bool forceFork) \
+ { \
+ Tests().push_back([=]{ return MakeHolder<NUnitTest::TBaseTestCase>(name, body, forceFork); }); \
+ } \
+ \
+ static void AddTest(TTestCaseFactory testCaseFactory) { \
+ Tests().push_back(std::move(testCaseFactory)); \
+ } \
+ \
+ virtual void Execute() { \
+ this->AtStart(); \
+ for (TTests::iterator it = Tests().begin(), ie = Tests().end(); it != ie; ++it) { \
+ const auto i = (*it)(); \
+ if (!this->CheckAccessTest(i->Name_)) { \
+ continue; \
+ } \
+ NUnitTest::TTestContext context(this->TTestBase::Processor()); \
+ try { \
+ this->BeforeTest(i->Name_); \
+ { \
+ TCleanUp cleaner(this); \
+ auto testCase = [&i, &context] { \
+ i->SetUp(context); \
+ i->Execute_(context); \
+ i->TearDown(context); \
+ }; \
+ this->T::Run(testCase, StaticName(), i->Name_, i->ForceFork_); \
+ } \
+ } catch (const ::NUnitTest::TAssertException&) { \
+ } catch (const yexception& e) { \
+ CATCH_REACTION_BT(i->Name_, e, &context); \
+ } catch (const std::exception& e) { \
+ CATCH_REACTION(i->Name_, e, &context); \
+ } catch (...) { \
+ this->AddError("non-std exception!", &context); \
+ } \
+ this->Finish(i->Name_, &context); \
+ } \
+ this->AtEnd(); \
+ } \
+ }; \
+ UNIT_TEST_SUITE_REGISTRATION(TCurrentTest) \
+ } \
+ namespace NTestSuite##N
+
+#define Y_UNIT_TEST_SUITE_IMPL(N, T) Y_UNIT_TEST_SUITE_IMPL_F(N, T, ::NUnitTest::TBaseTestCase)
+#define Y_UNIT_TEST_SUITE(N) Y_UNIT_TEST_SUITE_IMPL(N, TTestBase)
+#define Y_UNIT_TEST_SUITE_F(N, F) Y_UNIT_TEST_SUITE_IMPL_F(N, TTestBase, F)
+#define RUSAGE_UNIT_TEST_SUITE(N) Y_UNIT_TEST_SUITE_IMPL(N, NUnitTest::TRusageTest, ::NUnitTest::TBaseTestCase)
+
+#define Y_UNIT_TEST_IMPL_REGISTER(N, FF, F) \
+ struct TTestCase##N : public F { \
+ TTestCase##N() \
+ : F() \
+ { \
+ Name_ = #N; \
+ ForceFork_ = FF; \
+ } \
+ static THolder<NUnitTest::TBaseTestCase> Create() { \
+ return ::MakeHolder<TTestCase##N>(); \
+ } \
+ void Execute_(NUnitTest::TTestContext&) override; \
+ }; \
+ struct TTestRegistration##N { \
+ TTestRegistration##N() { \
+ TCurrentTest::AddTest(TTestCase##N::Create); \
+ } \
+ }; \
+ static const TTestRegistration##N testRegistration##N;
+
+#define Y_UNIT_TEST_IMPL(N, FF, F) \
+ Y_UNIT_TEST_IMPL_REGISTER(N, FF, F) \
+ void TTestCase##N::Execute_(NUnitTest::TTestContext& ut_context Y_DECLARE_UNUSED)
+
+#define Y_UNIT_TEST(N) Y_UNIT_TEST_IMPL(N, false, TCurrentTestCase)
+#define Y_UNIT_TEST_F(N, F) Y_UNIT_TEST_IMPL(N, false, F)
+#define SIMPLE_UNIT_FORKED_TEST(N) Y_UNIT_TEST_IMPL(N, true, TCurrentTestCase)
+
+#define Y_UNIT_TEST_SUITE_IMPLEMENTATION(N) \
+ namespace NTestSuite##N
+
+#define Y_UNIT_TEST_DECLARE(N) \
+ struct TTestCase##N
+
+#define Y_UNIT_TEST_FRIEND(N, T) \
+ friend NTestSuite##N::TTestCase##T \
+
+ TString RandomString(size_t len, ui32 seed = 0);
+}
+
+using ::NUnitTest::TTestBase;
diff --git a/library/cpp/testing/unittest/registar_ut.cpp b/library/cpp/testing/unittest/registar_ut.cpp
new file mode 100644
index 0000000000..aada471030
--- /dev/null
+++ b/library/cpp/testing/unittest/registar_ut.cpp
@@ -0,0 +1,360 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TUnitTestMacroTest) {
+ Y_UNIT_TEST(Assert) {
+ auto unitAssert = [] {
+ UNIT_ASSERT(false);
+ };
+ UNIT_ASSERT_TEST_FAILS(unitAssert());
+
+ UNIT_ASSERT(true);
+ }
+
+ Y_UNIT_TEST(TypesEqual) {
+ auto typesEqual = [] {
+ UNIT_ASSERT_TYPES_EQUAL(int, long);
+ };
+ UNIT_ASSERT_TEST_FAILS(typesEqual());
+
+ UNIT_ASSERT_TYPES_EQUAL(TString, TString);
+ }
+
+ Y_UNIT_TEST(DoublesEqual) {
+ auto doublesEqual = [](double d1, double d2, double precision) {
+ UNIT_ASSERT_DOUBLES_EQUAL(d1, d2, precision);
+ };
+ UNIT_ASSERT_TEST_FAILS(doublesEqual(0.0, 0.5, 0.1));
+ UNIT_ASSERT_TEST_FAILS(doublesEqual(0.1, -0.1, 0.1));
+
+ UNIT_ASSERT_DOUBLES_EQUAL(0.0, 0.01, 0.1);
+ UNIT_ASSERT_DOUBLES_EQUAL(0.01, 0.0, 0.1);
+
+ constexpr auto nan = std::numeric_limits<double>::quiet_NaN();
+ UNIT_ASSERT_TEST_FAILS(doublesEqual(nan, 0.5, 0.1));
+ UNIT_ASSERT_TEST_FAILS(doublesEqual(0.5, nan, 0.1));
+ UNIT_ASSERT_DOUBLES_EQUAL(nan, nan, 0.1);
+ }
+
+ Y_UNIT_TEST(StringsEqual) {
+ auto stringsEqual = [](auto s1, auto s2) {
+ UNIT_ASSERT_STRINGS_EQUAL(s1, s2);
+ };
+ UNIT_ASSERT_TEST_FAILS(stringsEqual("q", "w"));
+ UNIT_ASSERT_TEST_FAILS(stringsEqual("q", TString("w")));
+ UNIT_ASSERT_TEST_FAILS(stringsEqual(TString("q"), "w"));
+ UNIT_ASSERT_TEST_FAILS(stringsEqual(TString("a"), TString("b")));
+ UNIT_ASSERT_TEST_FAILS(stringsEqual(TString("a"), TStringBuf("b")));
+ UNIT_ASSERT_TEST_FAILS(stringsEqual("a", TStringBuf("b")));
+ UNIT_ASSERT_TEST_FAILS(stringsEqual(TStringBuf("a"), "b"));
+
+ TString empty;
+ TStringBuf emptyBuf;
+ UNIT_ASSERT_STRINGS_EQUAL("", empty);
+ UNIT_ASSERT_STRINGS_EQUAL(empty, emptyBuf);
+ UNIT_ASSERT_STRINGS_EQUAL("", static_cast<const char*>(nullptr));
+ }
+
+ Y_UNIT_TEST(StringContains) {
+ auto stringContains = [](auto s, auto substr) {
+ UNIT_ASSERT_STRING_CONTAINS(s, substr);
+ };
+ UNIT_ASSERT_TEST_FAILS(stringContains("", "a"));
+ UNIT_ASSERT_TEST_FAILS(stringContains("lurkmore", "moar"));
+
+ UNIT_ASSERT_STRING_CONTAINS("", "");
+ UNIT_ASSERT_STRING_CONTAINS("a", "");
+ UNIT_ASSERT_STRING_CONTAINS("failure", "fail");
+ UNIT_ASSERT_STRING_CONTAINS("lurkmore", "more");
+ }
+
+ Y_UNIT_TEST(NoDiff) {
+ auto noDiff = [](auto s1, auto s2) {
+ UNIT_ASSERT_NO_DIFF(s1, s2);
+ };
+ UNIT_ASSERT_TEST_FAILS(noDiff("q", "w"));
+ UNIT_ASSERT_TEST_FAILS(noDiff("q", ""));
+
+ UNIT_ASSERT_NO_DIFF("", "");
+ UNIT_ASSERT_NO_DIFF("a", "a");
+ }
+
+ Y_UNIT_TEST(StringsUnequal) {
+ auto stringsUnequal = [](auto s1, auto s2) {
+ UNIT_ASSERT_STRINGS_UNEQUAL(s1, s2);
+ };
+ UNIT_ASSERT_TEST_FAILS(stringsUnequal("1", "1"));
+ UNIT_ASSERT_TEST_FAILS(stringsUnequal("", ""));
+ UNIT_ASSERT_TEST_FAILS(stringsUnequal("42", TString("42")));
+ UNIT_ASSERT_TEST_FAILS(stringsUnequal(TString("4"), "4"));
+ UNIT_ASSERT_TEST_FAILS(stringsUnequal("d", TStringBuf("d")));
+ UNIT_ASSERT_TEST_FAILS(stringsUnequal(TStringBuf("yandex"), "yandex"));
+ UNIT_ASSERT_TEST_FAILS(stringsUnequal(TStringBuf("index"), TString("index")));
+ UNIT_ASSERT_TEST_FAILS(stringsUnequal(TString("diff"), TStringBuf("diff")));
+
+ UNIT_ASSERT_STRINGS_UNEQUAL("1", "2");
+ UNIT_ASSERT_STRINGS_UNEQUAL("", "3");
+ UNIT_ASSERT_STRINGS_UNEQUAL("green", TStringBuf("red"));
+ UNIT_ASSERT_STRINGS_UNEQUAL(TStringBuf("solomon"), "golovan");
+ UNIT_ASSERT_STRINGS_UNEQUAL("d", TString("f"));
+ UNIT_ASSERT_STRINGS_UNEQUAL(TString("yandex"), "index");
+ UNIT_ASSERT_STRINGS_UNEQUAL(TString("mail"), TStringBuf("yandex"));
+ UNIT_ASSERT_STRINGS_UNEQUAL(TStringBuf("C++"), TString("python"));
+ }
+
+ Y_UNIT_TEST(Equal) {
+ auto equal = [](auto v1, auto v2) {
+ UNIT_ASSERT_EQUAL(v1, v2);
+ };
+ UNIT_ASSERT_TEST_FAILS(equal("1", TString("2")));
+ UNIT_ASSERT_TEST_FAILS(equal(1, 2));
+ UNIT_ASSERT_TEST_FAILS(equal(42ul, static_cast<unsigned short>(24)));
+
+ UNIT_ASSERT_EQUAL("abc", TString("abc"));
+ UNIT_ASSERT_EQUAL(12l, 12);
+ UNIT_ASSERT_EQUAL(55, 55);
+ }
+
+ Y_UNIT_TEST(Unequal) {
+ auto unequal = [](auto v1, auto v2) {
+ UNIT_ASSERT_UNEQUAL(v1, v2);
+ };
+ UNIT_ASSERT_TEST_FAILS(unequal("x", TString("x")));
+ UNIT_ASSERT_TEST_FAILS(unequal(1, 1));
+ UNIT_ASSERT_TEST_FAILS(unequal(static_cast<unsigned short>(42), 42ul));
+
+ UNIT_ASSERT_UNEQUAL("abc", TString("cba"));
+ UNIT_ASSERT_UNEQUAL(12l, 10);
+ UNIT_ASSERT_UNEQUAL(33, 50);
+ }
+
+ Y_UNIT_TEST(LessThan) {
+ auto lt = [](auto v1, auto v2) {
+ UNIT_ASSERT_LT(v1, v2);
+ };
+
+ // less than
+ UNIT_ASSERT_LT(TStringBuf("1"), "2");
+ UNIT_ASSERT_LT("2", TString("3"));
+ UNIT_ASSERT_LT("abc", TString("azz"));
+ UNIT_ASSERT_LT(2, 4);
+ UNIT_ASSERT_LT(42ul, static_cast<unsigned short>(48));
+
+ // equals
+ UNIT_ASSERT_TEST_FAILS(lt(TStringBuf("2"), "2"));
+ UNIT_ASSERT_TEST_FAILS(lt("2", TString("2")));
+ UNIT_ASSERT_TEST_FAILS(lt("abc", TString("abc")));
+ UNIT_ASSERT_TEST_FAILS(lt(2, 2));
+ UNIT_ASSERT_TEST_FAILS(lt(42ul, static_cast<unsigned short>(42)));
+
+ // greater than
+ UNIT_ASSERT_TEST_FAILS(lt(TStringBuf("2"), "1"));
+ UNIT_ASSERT_TEST_FAILS(lt("3", TString("2")));
+ UNIT_ASSERT_TEST_FAILS(lt("azz", TString("abc")));
+ UNIT_ASSERT_TEST_FAILS(lt(5, 2));
+ UNIT_ASSERT_TEST_FAILS(lt(100ul, static_cast<unsigned short>(42)));
+ }
+
+ Y_UNIT_TEST(LessOrEqual) {
+ auto le = [](auto v1, auto v2) {
+ UNIT_ASSERT_LE(v1, v2);
+ };
+
+ // less than
+ UNIT_ASSERT_LE(TStringBuf("1"), "2");
+ UNIT_ASSERT_LE("2", TString("3"));
+ UNIT_ASSERT_LE("abc", TString("azz"));
+ UNIT_ASSERT_LE(2, 4);
+ UNIT_ASSERT_LE(42ul, static_cast<unsigned short>(48));
+
+ // equals
+ UNIT_ASSERT_LE(TStringBuf("2"), "2");
+ UNIT_ASSERT_LE("2", TString("2"));
+ UNIT_ASSERT_LE("abc", TString("abc"));
+ UNIT_ASSERT_LE(2, 2);
+ UNIT_ASSERT_LE(42ul, static_cast<unsigned short>(42));
+
+ // greater than
+ UNIT_ASSERT_TEST_FAILS(le(TStringBuf("2"), "1"));
+ UNIT_ASSERT_TEST_FAILS(le("3", TString("2")));
+ UNIT_ASSERT_TEST_FAILS(le("azz", TString("abc")));
+ UNIT_ASSERT_TEST_FAILS(le(5, 2));
+ UNIT_ASSERT_TEST_FAILS(le(100ul, static_cast<unsigned short>(42)));
+ }
+
+ Y_UNIT_TEST(GreaterThan) {
+ auto gt = [](auto v1, auto v2) {
+ UNIT_ASSERT_GT(v1, v2);
+ };
+
+ // less than
+ UNIT_ASSERT_TEST_FAILS(gt(TStringBuf("1"), "2"));
+ UNIT_ASSERT_TEST_FAILS(gt("2", TString("3")));
+ UNIT_ASSERT_TEST_FAILS(gt("abc", TString("azz")));
+ UNIT_ASSERT_TEST_FAILS(gt(2, 4));
+ UNIT_ASSERT_TEST_FAILS(gt(42ul, static_cast<unsigned short>(48)));
+
+ // equals
+ UNIT_ASSERT_TEST_FAILS(gt(TStringBuf("2"), "2"));
+ UNIT_ASSERT_TEST_FAILS(gt("2", TString("2")));
+ UNIT_ASSERT_TEST_FAILS(gt("abc", TString("abc")));
+ UNIT_ASSERT_TEST_FAILS(gt(2, 2));
+ UNIT_ASSERT_TEST_FAILS(gt(42ul, static_cast<unsigned short>(42)));
+
+ // greater than
+ UNIT_ASSERT_GT(TStringBuf("2"), "1");
+ UNIT_ASSERT_GT("3", TString("2"));
+ UNIT_ASSERT_GT("azz", TString("abc"));
+ UNIT_ASSERT_GT(5, 2);
+ UNIT_ASSERT_GT(100ul, static_cast<unsigned short>(42));
+ }
+
+ Y_UNIT_TEST(GreaterOrEqual) {
+ auto ge = [](auto v1, auto v2) {
+ UNIT_ASSERT_GE(v1, v2);
+ };
+
+ // less than
+ UNIT_ASSERT_TEST_FAILS(ge(TStringBuf("1"), "2"));
+ UNIT_ASSERT_TEST_FAILS(ge("2", TString("3")));
+ UNIT_ASSERT_TEST_FAILS(ge("abc", TString("azz")));
+ UNIT_ASSERT_TEST_FAILS(ge(2, 4));
+ UNIT_ASSERT_TEST_FAILS(ge(42ul, static_cast<unsigned short>(48)));
+
+ // equals
+ UNIT_ASSERT_GE(TStringBuf("2"), "2");
+ UNIT_ASSERT_GE("2", TString("2"));
+ UNIT_ASSERT_GE("abc", TString("abc"));
+ UNIT_ASSERT_GE(2, 2);
+ UNIT_ASSERT_GE(42ul, static_cast<unsigned short>(42));
+
+ // greater than
+ UNIT_ASSERT_GE(TStringBuf("2"), "1");
+ UNIT_ASSERT_GE("3", TString("2"));
+ UNIT_ASSERT_GE("azz", TString("abc"));
+ UNIT_ASSERT_GE(5, 2);
+ UNIT_ASSERT_GE(100ul, static_cast<unsigned short>(42));
+ }
+
+ Y_UNIT_TEST(ValuesEqual) {
+ auto valuesEqual = [](auto v1, auto v2) {
+ UNIT_ASSERT_VALUES_EQUAL(v1, v2);
+ };
+ UNIT_ASSERT_TEST_FAILS(valuesEqual(1, 2));
+ UNIT_ASSERT_TEST_FAILS(valuesEqual(1l, static_cast<short>(2)));
+
+ UNIT_ASSERT_VALUES_EQUAL("yandex", TString("yandex"));
+ UNIT_ASSERT_VALUES_EQUAL(1.0, 1.0);
+ }
+
+ Y_UNIT_TEST(ValuesUnequal) {
+ auto valuesUnequal = [](auto v1, auto v2) {
+ UNIT_ASSERT_VALUES_UNEQUAL(v1, v2);
+ };
+ UNIT_ASSERT_TEST_FAILS(valuesUnequal(5, 5));
+ UNIT_ASSERT_TEST_FAILS(valuesUnequal(static_cast<char>(5), 5l));
+ TString test("test");
+ UNIT_ASSERT_TEST_FAILS(valuesUnequal("test", test.data()));
+
+ UNIT_ASSERT_VALUES_UNEQUAL("UNIT_ASSERT_VALUES_UNEQUAL", "UNIT_ASSERT_VALUES_EQUAL");
+ UNIT_ASSERT_VALUES_UNEQUAL(1.0, 1.1);
+ }
+
+ class TTestException: public yexception {
+ public:
+ TTestException(const TString& text = "test exception", bool throwMe = true)
+ : ThrowMe(throwMe)
+ {
+ *this << text;
+ }
+
+ virtual ~TTestException() = default;
+
+ virtual void Throw() {
+ if (ThrowMe) {
+ throw *this;
+ }
+ }
+
+ void AssertNoException() {
+ UNIT_ASSERT_NO_EXCEPTION(Throw());
+ }
+
+ template <class TExpectedException>
+ void AssertException() {
+ UNIT_ASSERT_EXCEPTION(Throw(), TExpectedException);
+ }
+
+ template <class TExpectedException, class T>
+ void AssertExceptionContains(const T& substr) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS(Throw(), TExpectedException, substr);
+ }
+
+ template <class TExpectedException, class P>
+ void AssertExceptionSatisfies(const P& predicate) {
+ UNIT_ASSERT_EXCEPTION_SATISFIES(Throw(), TExpectedException, predicate);
+ }
+
+ int GetValue() const {
+ return 5; // just some value for predicate testing
+ }
+
+ bool ThrowMe;
+ };
+
+ class TOtherTestException: public TTestException {
+ public:
+ using TTestException::TTestException;
+
+ // Throws other type of exception
+ void Throw() override {
+ if (ThrowMe) {
+ throw *this;
+ }
+ }
+ };
+
+ Y_UNIT_TEST(Exception) {
+ UNIT_ASSERT_TEST_FAILS(TTestException("", false).AssertException<TTestException>());
+ UNIT_ASSERT_TEST_FAILS(TTestException().AssertException<TOtherTestException>());
+
+ UNIT_ASSERT_EXCEPTION(TOtherTestException().Throw(), TTestException);
+ UNIT_ASSERT_EXCEPTION(TTestException().Throw(), TTestException);
+ }
+
+ Y_UNIT_TEST(ExceptionAssertionContainsOtherExceptionMessage) {
+ NUnitTest::TUnitTestFailChecker checker;
+ {
+ auto guard = checker.InvokeGuard();
+ TTestException("custom exception message").AssertException<TOtherTestException>();
+ }
+ UNIT_ASSERT(checker.Failed());
+ UNIT_ASSERT_STRING_CONTAINS(checker.Msg(), "custom exception message");
+ }
+
+ Y_UNIT_TEST(NoException) {
+ UNIT_ASSERT_TEST_FAILS(TTestException().AssertNoException());
+
+ UNIT_ASSERT_NO_EXCEPTION(TTestException("", false).Throw());
+ }
+
+ Y_UNIT_TEST(ExceptionContains) {
+ UNIT_ASSERT_TEST_FAILS(TTestException("abc").AssertExceptionContains<TTestException>("cba"));
+ UNIT_ASSERT_TEST_FAILS(TTestException("abc").AssertExceptionContains<TTestException>(TStringBuf("cba")));
+ UNIT_ASSERT_TEST_FAILS(TTestException("abc").AssertExceptionContains<TTestException>(TString("cba")));
+ UNIT_ASSERT_TEST_FAILS(TTestException("abc").AssertExceptionContains<TTestException>(TStringBuilder() << "cba"));
+
+ UNIT_ASSERT_TEST_FAILS(TTestException("abc", false).AssertExceptionContains<TTestException>("bc"));
+
+ UNIT_ASSERT_TEST_FAILS(TTestException("abc").AssertExceptionContains<TOtherTestException>("b"));
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TTestException("abc").Throw(), TTestException, "a");
+ }
+
+ Y_UNIT_TEST(ExceptionSatisfies) {
+ const auto goodPredicate = [](const TTestException& e) { return e.GetValue() == 5; };
+ const auto badPredicate = [](const TTestException& e) { return e.GetValue() != 5; };
+ UNIT_ASSERT_NO_EXCEPTION(TTestException().AssertExceptionSatisfies<TTestException>(goodPredicate));
+ UNIT_ASSERT_TEST_FAILS(TTestException().AssertExceptionSatisfies<TTestException>(badPredicate));
+ UNIT_ASSERT_TEST_FAILS(TTestException().AssertExceptionSatisfies<TOtherTestException>(goodPredicate));
+ }
+}
diff --git a/library/cpp/testing/unittest/simple.h b/library/cpp/testing/unittest/simple.h
new file mode 100644
index 0000000000..2a5300d886
--- /dev/null
+++ b/library/cpp/testing/unittest/simple.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "registar.h"
+
+namespace NUnitTest {
+ struct TSimpleTestExecutor: public TTestBase {
+ typedef TVector<TBaseTestCase> TTests;
+
+ TTests Tests;
+
+ virtual void Execute() override final {
+ AtStart();
+
+ for (typename TTests::iterator i = Tests.begin(), ie = Tests.end(); i != ie; ++i) {
+ if (!CheckAccessTest(i->Name_)) {
+ continue;
+ }
+ TTestContext context(this->Processor());
+ try {
+ BeforeTest(i->Name_);
+ {
+ TCleanUp cleaner(this);
+ TTestBase::Run([i, &context] { i->Body_(context); }, Name(), i->Name_, i->ForceFork_);
+ }
+ } catch (const ::NUnitTest::TAssertException&) {
+ } catch (const yexception& e) {
+ CATCH_REACTION_BT(i->Name_, e, &context);
+ } catch (const std::exception& e) {
+ CATCH_REACTION(i->Name_, e, &context);
+ } catch (...) {
+ AddError("non-std exception!", &context);
+ }
+ Finish(i->Name_, &context);
+ }
+
+ AtEnd();
+ }
+ };
+}
diff --git a/library/cpp/testing/unittest/tests_data.cpp b/library/cpp/testing/unittest/tests_data.cpp
new file mode 100644
index 0000000000..b51cbc4b87
--- /dev/null
+++ b/library/cpp/testing/unittest/tests_data.cpp
@@ -0,0 +1,104 @@
+#include "tests_data.h"
+#include "registar.h"
+
+#include <library/cpp/testing/common/network.h>
+
+#include <util/system/env.h>
+#include <util/system/mutex.h>
+
+class TPortManager::TPortManagerImpl {
+public:
+ TPortManagerImpl(bool reservePortsForCurrentTest)
+ : EnableReservePortsForCurrentTest(reservePortsForCurrentTest)
+ , DisableRandomPorts(!GetEnv("NO_RANDOM_PORTS").empty())
+ {
+ }
+
+ ui16 GetPort(ui16 port) {
+ if (port && DisableRandomPorts) {
+ return port;
+ }
+
+ TAtomicSharedPtr<NTesting::IPort> holder(NTesting::GetFreePort().Release());
+ ReservePortForCurrentTest(holder);
+
+ TGuard<TMutex> g(Lock);
+ ReservedPorts.push_back(holder);
+ return holder->Get();
+ }
+
+ ui16 GetUdpPort(ui16 port) {
+ return GetPort(port);
+ }
+
+ ui16 GetTcpPort(ui16 port) {
+ return GetPort(port);
+ }
+
+ ui16 GetTcpAndUdpPort(ui16 port) {
+ return GetPort(port);
+ }
+
+ ui16 GetPortsRange(const ui16 startPort, const ui16 range) {
+ Y_UNUSED(startPort);
+ auto ports = NTesting::NLegacy::GetFreePortsRange(range);
+ ui16 first = ports[0];
+ TGuard<TMutex> g(Lock);
+ for (auto& port : ports) {
+ ReservedPorts.emplace_back(port.Release());
+ ReservePortForCurrentTest(ReservedPorts.back());
+ }
+ return first;
+ }
+
+private:
+ void ReservePortForCurrentTest(const TAtomicSharedPtr<NTesting::IPort>& portGuard) {
+ if (EnableReservePortsForCurrentTest) {
+ TTestBase* currentTest = NUnitTest::NPrivate::GetCurrentTest();
+ if (currentTest != nullptr) {
+ currentTest->RunAfterTest([guard = portGuard]() mutable {
+ guard = nullptr; // remove reference for allocated port
+ });
+ }
+ }
+ }
+
+private:
+ TMutex Lock;
+ TVector<TAtomicSharedPtr<NTesting::IPort>> ReservedPorts;
+ const bool EnableReservePortsForCurrentTest;
+ const bool DisableRandomPorts;
+};
+
+TPortManager::TPortManager(bool reservePortsForCurrentTest)
+ : Impl_(new TPortManagerImpl(reservePortsForCurrentTest))
+{
+}
+
+TPortManager::~TPortManager() {
+}
+
+ui16 TPortManager::GetPort(ui16 port) {
+ return Impl_->GetTcpPort(port);
+}
+
+ui16 TPortManager::GetTcpPort(ui16 port) {
+ return Impl_->GetTcpPort(port);
+}
+
+ui16 TPortManager::GetUdpPort(ui16 port) {
+ return Impl_->GetUdpPort(port);
+}
+
+ui16 TPortManager::GetTcpAndUdpPort(ui16 port) {
+ return Impl_->GetTcpAndUdpPort(port);
+}
+
+ui16 TPortManager::GetPortsRange(const ui16 startPort, const ui16 range) {
+ return Impl_->GetPortsRange(startPort, range);
+}
+
+ui16 GetRandomPort() {
+ TPortManager* pm = Singleton<TPortManager>(false);
+ return pm->GetPort();
+}
diff --git a/library/cpp/testing/unittest/tests_data.h b/library/cpp/testing/unittest/tests_data.h
new file mode 100644
index 0000000000..6536bc1ae6
--- /dev/null
+++ b/library/cpp/testing/unittest/tests_data.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <library/cpp/testing/common/env.h>
+
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+#include <util/network/sock.h>
+
+class TInet6StreamSocket;
+
+// set two options: SO_REUSEADDR and SO_REUSEPORT, both are required for
+// correct implementation of TPortManager because of different operating systems
+// incompatibility: singe SO_REUSEADDR is enough for Linux, but not enough for Darwin
+template <class TSocketType>
+void SetReuseAddressAndPort(const TSocketType& sock) {
+ const int retAddr = SetSockOpt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+ if (retAddr < 0) {
+ ythrow yexception() << "can't set SO_REUSEADDR: " << LastSystemErrorText(-retAddr);
+ }
+
+#ifdef SO_REUSEPORT
+ const int retPort = SetSockOpt(sock, SOL_SOCKET, SO_REUSEPORT, 1);
+ if (retPort < 0) {
+ ythrow yexception() << "can't set SO_REUSEPORT: " << LastSystemErrorText(-retPort);
+ }
+#endif
+}
+
+class TPortManager: public TNonCopyable {
+public:
+ TPortManager(bool reservePortsForCurrentTest = true);
+ ~TPortManager();
+
+ // Gets free TCP port
+ ui16 GetPort(ui16 port = 0);
+
+ // Gets free TCP port
+ ui16 GetTcpPort(ui16 port = 0);
+
+ // Gets free UDP port
+ ui16 GetUdpPort(ui16 port = 0);
+
+ // Gets one free port for use in both TCP and UDP protocols
+ ui16 GetTcpAndUdpPort(ui16 port = 0);
+
+ ui16 GetPortsRange(const ui16 startPort, const ui16 range);
+
+private:
+ class TPortManagerImpl;
+ THolder<TPortManagerImpl> Impl_;
+};
+
+ui16 GetRandomPort();
diff --git a/library/cpp/testing/unittest/ut/main.cpp b/library/cpp/testing/unittest/ut/main.cpp
new file mode 100644
index 0000000000..e303e21e30
--- /dev/null
+++ b/library/cpp/testing/unittest/ut/main.cpp
@@ -0,0 +1,93 @@
+#include <library/cpp/testing/unittest/gtest.h>
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/testing/unittest/tests_data.h>
+
+#include <util/generic/set.h>
+#include <util/network/sock.h>
+#include <util/system/env.h>
+#include <util/system/fs.h>
+
+TEST(GTest, Test1) {
+ UNIT_ASSERT_EQUAL(1, 1);
+}
+
+TEST(GTest, Test2) {
+ UNIT_ASSERT_EQUAL(2, 2);
+}
+
+namespace {
+ struct TFixture : ::testing::Test {
+ TFixture()
+ : I(0)
+ {
+ }
+
+ void SetUp() override {
+ I = 5;
+ }
+
+ int I;
+ };
+
+ struct TSimpleFixture : public NUnitTest::TBaseFixture {
+ size_t Value = 24;
+ };
+
+ struct TOtherFixture : public NUnitTest::TBaseFixture {
+ size_t TheAnswer = 42;
+ };
+
+ struct TSetUpTearDownFixture : public NUnitTest::TBaseFixture {
+ int Magic = 3;
+
+ void SetUp(NUnitTest::TTestContext&) override {
+ UNIT_ASSERT_VALUES_EQUAL(Magic, 3);
+ Magic = 17;
+ }
+
+ void TearDown(NUnitTest::TTestContext&) override {
+ UNIT_ASSERT_VALUES_EQUAL(Magic, 42);
+ Magic = 100;
+ }
+ };
+}
+
+TEST_F(TFixture, Test1) {
+ ASSERT_EQ(I, 5);
+}
+
+TEST(ETest, Test1) {
+ UNIT_CHECK_GENERATED_EXCEPTION(ythrow yexception(), yexception);
+ UNIT_CHECK_GENERATED_NO_EXCEPTION(true, yexception);
+}
+
+Y_UNIT_TEST_SUITE(TestSingleTestFixture)
+{
+ Y_UNIT_TEST_F(Test3, TSimpleFixture) {
+ UNIT_ASSERT_EQUAL(Value, 24);
+ }
+}
+
+Y_UNIT_TEST_SUITE_F(TestSuiteFixture, TSimpleFixture)
+{
+ Y_UNIT_TEST(Test1) {
+ UNIT_ASSERT(Value == 24);
+ Value = 25;
+ }
+
+ Y_UNIT_TEST(Test2) {
+ UNIT_ASSERT_EQUAL(Value, 24);
+ }
+
+ Y_UNIT_TEST_F(Test3, TOtherFixture) {
+ UNIT_ASSERT_EQUAL(TheAnswer, 42);
+ }
+}
+
+Y_UNIT_TEST_SUITE(TestSetUpTearDownFixture)
+{
+ Y_UNIT_TEST_F(Test1, TSetUpTearDownFixture) {
+ UNIT_ASSERT_VALUES_EQUAL(Magic, 17);
+ Magic = 42;
+ }
+}
diff --git a/library/cpp/testing/unittest/ut/ya.make b/library/cpp/testing/unittest/ut/ya.make
new file mode 100644
index 0000000000..6d4c0959cc
--- /dev/null
+++ b/library/cpp/testing/unittest/ut/ya.make
@@ -0,0 +1,10 @@
+UNITTEST_FOR(library/cpp/testing/unittest)
+
+OWNER(snowball)
+
+SRCS(
+ main.cpp
+ registar_ut.cpp
+)
+
+END()
diff --git a/library/cpp/testing/unittest/utmain.cpp b/library/cpp/testing/unittest/utmain.cpp
new file mode 100644
index 0000000000..305bc6b40f
--- /dev/null
+++ b/library/cpp/testing/unittest/utmain.cpp
@@ -0,0 +1,771 @@
+#include "plugin.h"
+#include "registar.h"
+#include "utmain.h"
+
+#include <library/cpp/colorizer/colors.h>
+
+#include <library/cpp/json/writer/json.h>
+#include <library/cpp/json/writer/json_value.h>
+#include <library/cpp/testing/common/env.h>
+#include <library/cpp/testing/hook/hook.h>
+
+#include <util/datetime/base.h>
+
+#include <util/generic/hash.h>
+#include <util/generic/hash_set.h>
+#include <util/generic/scope.h>
+#include <util/generic/string.h>
+#include <util/generic/yexception.h>
+
+#include <util/network/init.h>
+
+#include <util/stream/file.h>
+#include <util/stream/output.h>
+#include <util/string/join.h>
+#include <util/string/util.h>
+
+#include <util/system/defaults.h>
+#include <util/system/execpath.h>
+#include <util/system/valgrind.h>
+#include <util/system/shellcommand.h>
+
+#if defined(_win_)
+#include <fcntl.h>
+#include <io.h>
+#include <windows.h>
+#include <crtdbg.h>
+#endif
+
+#if defined(_unix_)
+#include <unistd.h>
+#endif
+
+#ifdef WITH_VALGRIND
+#define NOTE_IN_VALGRIND(test) VALGRIND_PRINTF("%s::%s", test->unit->name.data(), test->name)
+#else
+#define NOTE_IN_VALGRIND(test)
+#endif
+
+const size_t MAX_COMMENT_MESSAGE_LENGTH = 1024 * 1024; // 1 MB
+
+using namespace NUnitTest;
+
+class TNullTraceWriterProcessor: public ITestSuiteProcessor {
+};
+
+class TTraceWriterProcessor: public ITestSuiteProcessor {
+public:
+ inline TTraceWriterProcessor(const char* traceFilePath, EOpenMode mode)
+ : PrevTime(TInstant::Now())
+ {
+ TraceFile = new TUnbufferedFileOutput(TFile(traceFilePath, mode | WrOnly | Seq));
+ }
+
+private:
+ TAutoPtr<TUnbufferedFileOutput> TraceFile;
+ TString TraceFilePath;
+ TInstant PrevTime;
+ TVector<TString> ErrorMessages;
+
+ inline void Trace(const TString eventName, const NJson::TJsonValue eventValue) {
+ NJsonWriter::TBuf json(NJsonWriter::HEM_UNSAFE);
+ json.BeginObject();
+
+ json.WriteKey("name").WriteString(eventName);
+ json.WriteKey("value").WriteJsonValue(&eventValue);
+ json.WriteKey("timestamp").WriteDouble(TInstant::Now().SecondsFloat(), PREC_NDIGITS, 14);
+
+ json.EndObject();
+
+ json.FlushTo(TraceFile.Get());
+ *TraceFile << "\n";
+ }
+
+ inline void TraceSubtestFinished(const char* className, const char* subtestName, const char* status, const TString comment, const TTestContext* context) {
+ const TInstant now = TInstant::Now();
+ NJson::TJsonValue event;
+ event.InsertValue("class", className);
+ event.InsertValue("subtest", subtestName);
+ event.InsertValue("status", status);
+ event.InsertValue("comment", comment.data());
+ event.InsertValue("time", (now - PrevTime).SecondsFloat());
+ if (context) {
+ for (const auto& metric : context->Metrics) {
+ event["metrics"].InsertValue(metric.first, metric.second);
+ }
+ }
+ Trace("subtest-finished", event);
+
+ PrevTime = now;
+ TString marker = Join("", "\n###subtest-finished:", className, "::", subtestName, "\n");
+ Cout << marker;
+ Cout.Flush();
+ Cerr << comment;
+ Cerr << marker;
+ Cerr.Flush();
+ }
+
+ virtual TString BuildComment(const char* message, const char* backTrace) {
+ return NUnitTest::GetFormatTag("bad") +
+ TString(message).substr(0, MAX_COMMENT_MESSAGE_LENGTH) +
+ NUnitTest::GetResetTag() +
+ TString("\n") +
+ NUnitTest::GetFormatTag("alt1") +
+ TString(backTrace).substr(0, MAX_COMMENT_MESSAGE_LENGTH) +
+ NUnitTest::GetResetTag();
+ }
+
+ void OnBeforeTest(const TTest* test) override {
+ NJson::TJsonValue event;
+ event.InsertValue("class", test->unit->name);
+ event.InsertValue("subtest", test->name);
+ Trace("subtest-started", event);
+ TString marker = Join("", "\n###subtest-started:", test->unit->name, "::", test->name, "\n");
+ Cout << marker;
+ Cout.Flush();
+ Cerr << marker;
+ Cerr.Flush();
+ }
+
+ void OnUnitStart(const TUnit* unit) override {
+ NJson::TJsonValue event;
+ event.InsertValue("class", unit->name);
+ Trace("test-started", event);
+ }
+
+ void OnUnitStop(const TUnit* unit) override {
+ NJson::TJsonValue event;
+ event.InsertValue("class", unit->name);
+ Trace("test-finished", event);
+ }
+
+ void OnError(const TError* descr) override {
+ const TString comment = BuildComment(descr->msg, descr->BackTrace.data());
+ ErrorMessages.push_back(comment);
+ }
+
+ void OnFinish(const TFinish* descr) override {
+ if (descr->Success) {
+ TraceSubtestFinished(descr->test->unit->name.data(), descr->test->name, "good", "", descr->Context);
+ } else {
+ TStringBuilder msgs;
+ for (const TString& m : ErrorMessages) {
+ if (msgs) {
+ msgs << TStringBuf("\n");
+ }
+ msgs << m;
+ }
+ if (msgs) {
+ msgs << TStringBuf("\n");
+ }
+ TraceSubtestFinished(descr->test->unit->name.data(), descr->test->name, "fail", msgs, descr->Context);
+ ErrorMessages.clear();
+ }
+ }
+};
+
+class TColoredProcessor: public ITestSuiteProcessor, public NColorizer::TColors {
+public:
+ inline TColoredProcessor(const TString& appName)
+ : PrintBeforeSuite_(true)
+ , PrintBeforeTest_(true)
+ , PrintAfterTest_(true)
+ , PrintAfterSuite_(true)
+ , PrintTimes_(false)
+ , PrintSummary_(true)
+ , PrevTime_(TInstant::Now())
+ , ShowFails(true)
+ , Start(0)
+ , End(Max<size_t>())
+ , AppName(appName)
+ , ForkTests(false)
+ , IsForked(false)
+ , Loop(false)
+ , ForkExitedCorrectly(false)
+ , TraceProcessor(new TNullTraceWriterProcessor())
+ {
+ }
+
+ ~TColoredProcessor() override {
+ }
+
+ inline void Disable(const char* name) {
+ size_t colon = TString(name).find("::");
+ if (colon == TString::npos) {
+ DisabledSuites_.insert(name);
+ } else {
+ TString suite = TString(name).substr(0, colon);
+ DisabledTests_.insert(name);
+ }
+ }
+
+ inline void Enable(const char* name) {
+ size_t colon = TString(name).rfind("::");
+ if (colon == TString::npos) {
+ EnabledSuites_.insert(name);
+ EnabledTests_.insert(TString() + name + "::*");
+ } else {
+ TString suite = TString(name).substr(0, colon);
+ EnabledSuites_.insert(suite);
+ EnabledSuites_.insert(name);
+ EnabledTests_.insert(name);
+ EnabledTests_.insert(TString() + name + "::*");
+ }
+ }
+
+ inline void SetPrintBeforeSuite(bool print) {
+ PrintBeforeSuite_ = print;
+ }
+
+ inline void SetPrintAfterSuite(bool print) {
+ PrintAfterSuite_ = print;
+ }
+
+ inline void SetPrintBeforeTest(bool print) {
+ PrintBeforeTest_ = print;
+ }
+
+ inline void SetPrintAfterTest(bool print) {
+ PrintAfterTest_ = print;
+ }
+
+ inline void SetPrintTimes(bool print) {
+ PrintTimes_ = print;
+ }
+
+ inline void SetPrintSummary(bool print) {
+ PrintSummary_ = print;
+ }
+
+ inline bool GetPrintSummary() {
+ return PrintSummary_;
+ }
+
+ inline void SetShowFails(bool show) {
+ ShowFails = show;
+ }
+
+ void SetContinueOnFail(bool val) {
+ NUnitTest::ContinueOnFail = val;
+ }
+
+ inline void BeQuiet() {
+ SetPrintTimes(false);
+ SetPrintBeforeSuite(false);
+ SetPrintAfterSuite(false);
+ SetPrintBeforeTest(false);
+ SetPrintAfterTest(false);
+ SetPrintSummary(false);
+ }
+
+ inline void SetStart(size_t val) {
+ Start = val;
+ }
+
+ inline void SetEnd(size_t val) {
+ End = val;
+ }
+
+ inline void SetForkTests(bool val) {
+ ForkTests = val;
+ }
+
+ inline bool GetForkTests() const override {
+ return ForkTests;
+ }
+
+ inline void SetIsForked(bool val) {
+ IsForked = val;
+ SetIsTTY(IsForked || CalcIsTTY(stderr));
+ }
+
+ inline bool GetIsForked() const override {
+ return IsForked;
+ }
+
+ inline void SetLoop(bool loop) {
+ Loop = loop;
+ }
+
+ inline bool IsLoop() const {
+ return Loop;
+ }
+
+ inline void SetTraceProcessor(TAutoPtr<ITestSuiteProcessor> traceProcessor) {
+ TraceProcessor = traceProcessor;
+ }
+
+private:
+ void OnUnitStart(const TUnit* unit) override {
+ TraceProcessor->UnitStart(*unit);
+ if (IsForked) {
+ return;
+ }
+ if (PrintBeforeSuite_ || PrintBeforeTest_) {
+ fprintf(stderr, "%s<-----%s %s\n", LightBlueColor().data(), OldColor().data(), unit->name.data());
+ }
+ }
+
+ void OnUnitStop(const TUnit* unit) override {
+ TraceProcessor->UnitStop(*unit);
+ if (IsForked) {
+ return;
+ }
+ if (!PrintAfterSuite_) {
+ return;
+ }
+
+ fprintf(stderr, "%s----->%s %s -> ok: %s%u%s",
+ LightBlueColor().data(), OldColor().data(), unit->name.data(),
+ LightGreenColor().data(), GoodTestsInCurrentUnit(), OldColor().data());
+ if (FailTestsInCurrentUnit()) {
+ fprintf(stderr, ", err: %s%u%s",
+ LightRedColor().data(), FailTestsInCurrentUnit(), OldColor().data());
+ }
+ fprintf(stderr, "\n");
+ }
+
+ void OnBeforeTest(const TTest* test) override {
+ TraceProcessor->BeforeTest(*test);
+ if (IsForked) {
+ return;
+ }
+ if (PrintBeforeTest_) {
+ fprintf(stderr, "[%sexec%s] %s::%s...\n", LightBlueColor().data(), OldColor().data(), test->unit->name.data(), test->name);
+ }
+ }
+
+ void OnError(const TError* descr) override {
+ TraceProcessor->Error(*descr);
+ if (!IsForked && ForkExitedCorrectly) {
+ return;
+ }
+ if (!PrintAfterTest_) {
+ return;
+ }
+
+ const TString err = Sprintf("[%sFAIL%s] %s::%s -> %s%s%s\n%s%s%s", LightRedColor().data(), OldColor().data(),
+ descr->test->unit->name.data(),
+ descr->test->name,
+ LightRedColor().data(), descr->msg, OldColor().data(), LightCyanColor().data(), descr->BackTrace.data(), OldColor().data());
+ const TDuration test_duration = SaveTestDuration();
+ if (ShowFails) {
+ if (PrintTimes_) {
+ Fails.push_back(Sprintf("%s %s", test_duration.ToString().data(), err.data()));
+ } else {
+ Fails.push_back(err);
+ }
+ }
+ fprintf(stderr, "%s", err.data());
+ NOTE_IN_VALGRIND(descr->test);
+ PrintTimes(test_duration);
+ if (IsForked) {
+ fprintf(stderr, "%s", ForkCorrectExitMsg);
+ }
+ }
+
+ void OnFinish(const TFinish* descr) override {
+ TraceProcessor->Finish(*descr);
+ if (!IsForked && ForkExitedCorrectly) {
+ return;
+ }
+ if (!PrintAfterTest_) {
+ return;
+ }
+
+ if (descr->Success) {
+ fprintf(stderr, "[%sgood%s] %s::%s\n", LightGreenColor().data(), OldColor().data(),
+ descr->test->unit->name.data(),
+ descr->test->name);
+ NOTE_IN_VALGRIND(descr->test);
+ PrintTimes(SaveTestDuration());
+ if (IsForked) {
+ fprintf(stderr, "%s", ForkCorrectExitMsg);
+ }
+ }
+ }
+
+ inline TDuration SaveTestDuration() {
+ const TInstant now = TInstant::Now();
+ TDuration d = now - PrevTime_;
+ PrevTime_ = now;
+ return d;
+ }
+
+ inline void PrintTimes(TDuration d) {
+ if (!PrintTimes_) {
+ return;
+ }
+
+ Cerr << d << "\n";
+ }
+
+ void OnEnd() override {
+ TraceProcessor->End();
+ if (IsForked) {
+ return;
+ }
+
+ if (!PrintSummary_) {
+ return;
+ }
+
+ fprintf(stderr, "[%sDONE%s] ok: %s%u%s",
+ YellowColor().data(), OldColor().data(),
+ LightGreenColor().data(), GoodTests(), OldColor().data());
+ if (FailTests())
+ fprintf(stderr, ", err: %s%u%s",
+ LightRedColor().data(), FailTests(), OldColor().data());
+ fprintf(stderr, "\n");
+
+ if (ShowFails) {
+ for (size_t i = 0; i < Fails.size(); ++i) {
+ printf("%s", Fails[i].data());
+ }
+ }
+ }
+
+ bool CheckAccess(TString name, size_t num) override {
+ if (num < Start) {
+ return false;
+ }
+
+ if (num >= End) {
+ return false;
+ }
+
+ if (DisabledSuites_.find(name.data()) != DisabledSuites_.end()) {
+ return false;
+ }
+
+ if (EnabledSuites_.empty()) {
+ return true;
+ }
+
+ return EnabledSuites_.find(name.data()) != EnabledSuites_.end();
+ }
+
+ bool CheckAccessTest(TString suite, const char* test) override {
+ TString name = suite + "::" + test;
+ if (DisabledTests_.find(name) != DisabledTests_.end()) {
+ return false;
+ }
+
+ if (EnabledTests_.empty()) {
+ return true;
+ }
+
+ if (EnabledTests_.find(TString() + suite + "::*") != EnabledTests_.end()) {
+ return true;
+ }
+
+ return EnabledTests_.find(name) != EnabledTests_.end();
+ }
+
+ void Run(std::function<void()> f, const TString& suite, const char* name, const bool forceFork) override {
+ if (!(ForkTests || forceFork) || GetIsForked()) {
+ return f();
+ }
+
+ TList<TString> args(1, "--is-forked-internal");
+ args.push_back(Sprintf("+%s::%s", suite.data(), name));
+
+ // stdin is ignored - unittest should not need them...
+ TShellCommand cmd(AppName, args,
+ TShellCommandOptions().SetUseShell(false).SetCloseAllFdsOnExec(true).SetAsync(false).SetLatency(1));
+ cmd.Run();
+
+ const TString& err = cmd.GetError();
+ const size_t msgIndex = err.find(ForkCorrectExitMsg);
+
+ // everything is printed by parent process except test's result output ("good" or "fail")
+ // which is printed by child. If there was no output - parent process prints default message.
+ ForkExitedCorrectly = msgIndex != TString::npos;
+
+ // TODO: stderr output is always printed after stdout
+ Cout.Write(cmd.GetOutput());
+ Cerr.Write(err.c_str(), Min(msgIndex, err.size()));
+
+ // do not use default case, so gcc will warn if new element in enum will be added
+ switch (cmd.GetStatus()) {
+ case TShellCommand::SHELL_FINISHED: {
+ // test could fail with zero status if it calls exit(0) in the middle.
+ if (ForkExitedCorrectly)
+ break;
+ [[fallthrough]];
+ }
+ case TShellCommand::SHELL_ERROR: {
+ ythrow yexception() << "Forked test failed";
+ }
+
+ case TShellCommand::SHELL_NONE: {
+ ythrow yexception() << "Forked test finished with unknown status";
+ }
+ case TShellCommand::SHELL_RUNNING: {
+ Y_VERIFY(false, "This can't happen, we used sync mode, it's a bug!");
+ }
+ case TShellCommand::SHELL_INTERNAL_ERROR: {
+ ythrow yexception() << "Forked test failed with internal error: " << cmd.GetInternalError();
+ }
+ }
+ }
+
+private:
+ bool PrintBeforeSuite_;
+ bool PrintBeforeTest_;
+ bool PrintAfterTest_;
+ bool PrintAfterSuite_;
+ bool PrintTimes_;
+ bool PrintSummary_;
+ THashSet<TString> DisabledSuites_;
+ THashSet<TString> EnabledSuites_;
+ THashSet<TString> DisabledTests_;
+ THashSet<TString> EnabledTests_;
+ TInstant PrevTime_;
+ bool ShowFails;
+ TVector<TString> Fails;
+ size_t Start;
+ size_t End;
+ TString AppName;
+ bool ForkTests;
+ bool IsForked;
+ bool Loop;
+ static const char* const ForkCorrectExitMsg;
+ bool ForkExitedCorrectly;
+ TAutoPtr<ITestSuiteProcessor> TraceProcessor;
+};
+
+const char* const TColoredProcessor::ForkCorrectExitMsg = "--END--";
+
+class TEnumeratingProcessor: public ITestSuiteProcessor {
+public:
+ TEnumeratingProcessor(bool verbose, IOutputStream& stream) noexcept
+ : Verbose_(verbose)
+ , Stream_(stream)
+ {
+ }
+
+ ~TEnumeratingProcessor() override {
+ }
+
+ bool CheckAccess(TString name, size_t /*num*/) override {
+ if (Verbose_) {
+ return true;
+ } else {
+ Stream_ << name << "\n";
+ return false;
+ }
+ }
+
+ bool CheckAccessTest(TString suite, const char* name) override {
+ Stream_ << suite << "::" << name << "\n";
+ return false;
+ }
+
+private:
+ bool Verbose_;
+ IOutputStream& Stream_;
+};
+
+#ifdef _win_
+class TWinEnvironment {
+public:
+ TWinEnvironment()
+ : OutputCP(GetConsoleOutputCP())
+ {
+ setmode(fileno(stdout), _O_BINARY);
+ SetConsoleOutputCP(CP_UTF8);
+
+ _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+
+ if (!IsDebuggerPresent()) {
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
+ }
+ }
+ ~TWinEnvironment() {
+ if (!IsDebuggerPresent()) {
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+ }
+
+ SetConsoleOutputCP(OutputCP); // restore original output CP at program exit
+ }
+
+private:
+ UINT OutputCP; // original codepage
+};
+static const TWinEnvironment Instance;
+#endif // _win_
+
+static int DoList(bool verbose, IOutputStream& stream) {
+ TEnumeratingProcessor eproc(verbose, stream);
+ TTestFactory::Instance().SetProcessor(&eproc);
+ TTestFactory::Instance().Execute();
+ return 0;
+}
+
+static int DoUsage(const char* progname) {
+ Cout << "Usage: " << progname << " [options] [[+|-]test]...\n\n"
+ << "Options:\n"
+ << " -h, --help print this help message\n"
+ << " -l, --list print a list of available tests\n"
+ << " -A --list-verbose print a list of available subtests\n"
+ << " --print-before-test print each test name before running it\n"
+ << " --print-before-suite print each test suite name before running it\n"
+ << " --show-fails print a list of all failed tests at the end\n"
+ << " --dont-show-fails do not print a list of all failed tests at the end\n"
+ << " --continue-on-fail print a message and continue running test suite instead of break\n"
+ << " --print-times print wall clock duration of each test\n"
+ << " --fork-tests run each test in a separate process\n"
+ << " --trace-path path to the trace file to be generated\n"
+ << " --trace-path-append path to the trace file to be appended\n";
+ return 0;
+}
+
+#if defined(_linux_) && defined(CLANG_COVERAGE)
+extern "C" int __llvm_profile_write_file(void);
+
+static void GracefulShutdownHandler(int) {
+ try {
+ __llvm_profile_write_file();
+ } catch (...) {
+ }
+ abort();
+}
+#endif
+
+int NUnitTest::RunMain(int argc, char** argv) {
+#if defined(_linux_) && defined(CLANG_COVERAGE)
+ {
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = GracefulShutdownHandler;
+ sa.sa_flags = SA_SIGINFO | SA_RESTART;
+ Y_VERIFY(!sigaction(SIGUSR2, &sa, nullptr));
+ }
+#endif
+ NTesting::THook::CallBeforeInit();
+ InitNetworkSubSystem();
+
+ try {
+ GetExecPath();
+ } catch (...) {
+ }
+
+#ifndef UT_SKIP_EXCEPTIONS
+ try {
+#endif
+ NTesting::THook::CallBeforeRun();
+ Y_DEFER { NTesting::THook::CallAfterRun(); };
+
+ NPlugin::OnStartMain(argc, argv);
+ Y_DEFER { NPlugin::OnStopMain(argc, argv); };
+
+ TColoredProcessor processor(GetExecPath());
+ IOutputStream* listStream = &Cout;
+ THolder<IOutputStream> listFile;
+
+ enum EListType {
+ DONT_LIST,
+ LIST,
+ LIST_VERBOSE
+ };
+ EListType listTests = DONT_LIST;
+
+ for (size_t i = 1; i < (size_t)argc; ++i) {
+ const char* name = argv[i];
+
+ if (name && *name) {
+ if (strcmp(name, "--help") == 0 || strcmp(name, "-h") == 0) {
+ return DoUsage(argv[0]);
+ } else if (strcmp(name, "--list") == 0 || strcmp(name, "-l") == 0) {
+ listTests = LIST;
+ } else if (strcmp(name, "--list-verbose") == 0 || strcmp(name, "-A") == 0) {
+ listTests = LIST_VERBOSE;
+ } else if (strcmp(name, "--print-before-suite=false") == 0) {
+ processor.SetPrintBeforeSuite(false);
+ } else if (strcmp(name, "--print-before-test=false") == 0) {
+ processor.SetPrintBeforeTest(false);
+ } else if (strcmp(name, "--print-before-suite") == 0) {
+ processor.SetPrintBeforeSuite(true);
+ } else if (strcmp(name, "--print-before-test") == 0) {
+ processor.SetPrintBeforeTest(true);
+ } else if (strcmp(name, "--show-fails") == 0) {
+ processor.SetShowFails(true);
+ } else if (strcmp(name, "--dont-show-fails") == 0) {
+ processor.SetShowFails(false);
+ } else if (strcmp(name, "--continue-on-fail") == 0) {
+ processor.SetContinueOnFail(true);
+ } else if (strcmp(name, "--print-times") == 0) {
+ processor.SetPrintTimes(true);
+ } else if (strcmp(name, "--from") == 0) {
+ ++i;
+ processor.SetStart(FromString<size_t>(argv[i]));
+ } else if (strcmp(name, "--to") == 0) {
+ ++i;
+ processor.SetEnd(FromString<size_t>(argv[i]));
+ } else if (strcmp(name, "--fork-tests") == 0) {
+ processor.SetForkTests(true);
+ } else if (strcmp(name, "--is-forked-internal") == 0) {
+ processor.SetIsForked(true);
+ } else if (strcmp(name, "--loop") == 0) {
+ processor.SetLoop(true);
+ } else if (strcmp(name, "--trace-path") == 0) {
+ ++i;
+ processor.BeQuiet();
+ NUnitTest::ShouldColorizeDiff = false;
+ processor.SetTraceProcessor(new TTraceWriterProcessor(argv[i], CreateAlways));
+ } else if (strcmp(name, "--trace-path-append") == 0) {
+ ++i;
+ processor.BeQuiet();
+ NUnitTest::ShouldColorizeDiff = false;
+ processor.SetTraceProcessor(new TTraceWriterProcessor(argv[i], OpenAlways | ForAppend));
+ } else if (strcmp(name, "--list-path") == 0) {
+ ++i;
+ listFile = MakeHolder<TFixedBufferFileOutput>(argv[i]);
+ listStream = listFile.Get();
+ } else if (strcmp(name, "--test-param") == 0) {
+ ++i;
+ TString param(argv[i]);
+ size_t assign = param.find('=');
+ Singleton<::NPrivate::TTestEnv>()->AddTestParam(param.substr(0, assign), param.substr(assign + 1));
+ } else if (TString(name).StartsWith("--")) {
+ return DoUsage(argv[0]), 1;
+ } else if (*name == '-') {
+ processor.Disable(name + 1);
+ } else if (*name == '+') {
+ processor.Enable(name + 1);
+ } else {
+ processor.Enable(name);
+ }
+ }
+ }
+ if (listTests != DONT_LIST) {
+ return DoList(listTests == LIST_VERBOSE, *listStream);
+ }
+
+ TTestFactory::Instance().SetProcessor(&processor);
+
+ unsigned ret;
+ for (;;) {
+ ret = TTestFactory::Instance().Execute();
+ if (!processor.GetIsForked() && ret && processor.GetPrintSummary()) {
+ Cerr << "SOME TESTS FAILED!!!!" << Endl;
+ }
+
+ if (0 != ret || !processor.IsLoop()) {
+ break;
+ }
+ }
+ return ret;
+#ifndef UT_SKIP_EXCEPTIONS
+ } catch (...) {
+ Cerr << "caught exception in test suite(" << CurrentExceptionMessage() << ")" << Endl;
+ }
+#endif
+
+ return 1;
+}
diff --git a/library/cpp/testing/unittest/utmain.h b/library/cpp/testing/unittest/utmain.h
new file mode 100644
index 0000000000..65e8082ee1
--- /dev/null
+++ b/library/cpp/testing/unittest/utmain.h
@@ -0,0 +1,5 @@
+#pragma once
+
+namespace NUnitTest {
+ int RunMain(int argc, char** argv);
+}
diff --git a/library/cpp/testing/unittest/ya.make b/library/cpp/testing/unittest/ya.make
new file mode 100644
index 0000000000..aaa4f2ba85
--- /dev/null
+++ b/library/cpp/testing/unittest/ya.make
@@ -0,0 +1,33 @@
+LIBRARY()
+
+PROVIDES(test_framework)
+
+OWNER(
+ pg
+ galaxycrab
+)
+
+PEERDIR(
+ library/cpp/colorizer
+ library/cpp/dbg_output
+ library/cpp/diff
+ library/cpp/json/writer
+ library/cpp/testing/common
+ library/cpp/testing/hook
+)
+
+SRCS(
+ gtest.cpp
+ checks.cpp
+ plugin.cpp
+ registar.cpp
+ tests_data.cpp
+ utmain.cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ fat
+ ut
+)
diff --git a/library/cpp/testing/unittest_main/main.cpp b/library/cpp/testing/unittest_main/main.cpp
new file mode 100644
index 0000000000..fc5d2d9418
--- /dev/null
+++ b/library/cpp/testing/unittest_main/main.cpp
@@ -0,0 +1,5 @@
+#include <library/cpp/testing/unittest/utmain.h>
+
+int main(int argc, char** argv) {
+ return NUnitTest::RunMain(argc, argv);
+}
diff --git a/library/cpp/testing/unittest_main/ya.make b/library/cpp/testing/unittest_main/ya.make
new file mode 100644
index 0000000000..80a6cc699b
--- /dev/null
+++ b/library/cpp/testing/unittest_main/ya.make
@@ -0,0 +1,14 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ library/cpp/testing/unittest
+ library/cpp/terminate_handler
+)
+
+SRCS(
+ main.cpp
+)
+
+END()
diff --git a/library/cpp/testing/ya.make b/library/cpp/testing/ya.make
new file mode 100644
index 0000000000..6a57ac2ee6
--- /dev/null
+++ b/library/cpp/testing/ya.make
@@ -0,0 +1,24 @@
+RECURSE(
+ common
+ benchmark
+ benchmark/examples
+ benchmark/examples/metrics
+ benchmark/main
+ boost_test
+ boost_test_main
+ dump_clang_coverage
+ gbenchmark_main
+ gmock
+ gmock_in_unittest
+ gmock_in_unittest/example_ut
+ gtest
+ gtest_boost_extensions
+ gtest_extensions
+ gtest_main
+ gtest_protobuf
+ hook
+ mock_server
+ unittest
+ unittest_main
+ urlnorm
+)
diff --git a/library/cpp/threading/atomic/bool.cpp b/library/cpp/threading/atomic/bool.cpp
new file mode 100644
index 0000000000..37917e01f1
--- /dev/null
+++ b/library/cpp/threading/atomic/bool.cpp
@@ -0,0 +1 @@
+#include "bool.h"
diff --git a/library/cpp/threading/atomic/bool.h b/library/cpp/threading/atomic/bool.h
new file mode 100644
index 0000000000..d52544e762
--- /dev/null
+++ b/library/cpp/threading/atomic/bool.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <util/system/atomic.h>
+
+namespace NAtomic {
+ class TBool {
+ public:
+ TBool() noexcept = default;
+
+ TBool(bool val) noexcept
+ : Val_(val)
+ {
+ }
+
+ TBool(const TBool& src) noexcept {
+ AtomicSet(Val_, AtomicGet(src.Val_));
+ }
+
+ operator bool() const noexcept {
+ return AtomicGet(Val_);
+ }
+
+ const TBool& operator=(bool val) noexcept {
+ AtomicSet(Val_, val);
+ return *this;
+ }
+
+ const TBool& operator=(const TBool& src) noexcept {
+ AtomicSet(Val_, AtomicGet(src.Val_));
+ return *this;
+ }
+
+ private:
+ TAtomic Val_ = 0;
+ };
+}
diff --git a/library/cpp/threading/atomic/bool_ut.cpp b/library/cpp/threading/atomic/bool_ut.cpp
new file mode 100644
index 0000000000..9481f41d8d
--- /dev/null
+++ b/library/cpp/threading/atomic/bool_ut.cpp
@@ -0,0 +1,31 @@
+#include "bool.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(AtomicBool) {
+ Y_UNIT_TEST(ReadWrite) {
+ NAtomic::TBool v;
+
+ UNIT_ASSERT_VALUES_EQUAL((bool)v, false);
+
+ v = true;
+
+ UNIT_ASSERT_VALUES_EQUAL((bool)v, true);
+
+ v = false;
+
+ UNIT_ASSERT_VALUES_EQUAL((bool)v, false);
+
+ NAtomic::TBool v2;
+
+ UNIT_ASSERT(v == v2);
+
+ v2 = true;
+
+ UNIT_ASSERT(v != v2);
+
+ v = v2;
+
+ UNIT_ASSERT(v == v2);
+ }
+}
diff --git a/library/cpp/threading/atomic/ut/ya.make b/library/cpp/threading/atomic/ut/ya.make
new file mode 100644
index 0000000000..3c555685df
--- /dev/null
+++ b/library/cpp/threading/atomic/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/threading/atomic)
+
+OWNER(vmordovin)
+
+SRCS(
+ bool_ut.cpp
+)
+
+END()
diff --git a/library/cpp/threading/atomic/ya.make b/library/cpp/threading/atomic/ya.make
new file mode 100644
index 0000000000..c3a3ef8a76
--- /dev/null
+++ b/library/cpp/threading/atomic/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(vmordovin)
+
+SRCS(
+ bool.cpp
+)
+
+END()
diff --git a/library/cpp/threading/chunk_queue/queue.cpp b/library/cpp/threading/chunk_queue/queue.cpp
new file mode 100644
index 0000000000..4ebd3f3205
--- /dev/null
+++ b/library/cpp/threading/chunk_queue/queue.cpp
@@ -0,0 +1 @@
+#include "queue.h"
diff --git a/library/cpp/threading/chunk_queue/queue.h b/library/cpp/threading/chunk_queue/queue.h
new file mode 100644
index 0000000000..55859601a1
--- /dev/null
+++ b/library/cpp/threading/chunk_queue/queue.h
@@ -0,0 +1,568 @@
+#pragma once
+
+#include <util/datetime/base.h>
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/generic/typetraits.h>
+#include <util/generic/vector.h>
+#include <util/generic/ylimits.h>
+#include <util/system/atomic.h>
+#include <util/system/guard.h>
+#include <util/system/spinlock.h>
+#include <util/system/yassert.h>
+
+#include <type_traits>
+#include <utility>
+
+namespace NThreading {
+////////////////////////////////////////////////////////////////////////////////
+// Platform helpers
+
+#if !defined(PLATFORM_CACHE_LINE)
+#define PLATFORM_CACHE_LINE 64
+#endif
+
+#if !defined(PLATFORM_PAGE_SIZE)
+#define PLATFORM_PAGE_SIZE 4 * 1024
+#endif
+
+ template <typename T, size_t PadSize = PLATFORM_CACHE_LINE>
+ struct TPadded: public T {
+ char Pad[PadSize - sizeof(T) % PadSize];
+
+ TPadded() {
+ static_assert(sizeof(*this) % PadSize == 0, "padding does not work");
+ Y_UNUSED(Pad);
+ }
+
+ template<typename... Args>
+ TPadded(Args&&... args)
+ : T(std::forward<Args>(args)...)
+ {
+ static_assert(sizeof(*this) % PadSize == 0, "padding does not work");
+ Y_UNUSED(Pad);
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Type helpers
+
+ namespace NImpl {
+ template <typename T>
+ struct TPodTypeHelper {
+ template <typename TT>
+ static void Write(T* ptr, TT&& value) {
+ *ptr = value;
+ }
+
+ static T Read(T* ptr) {
+ return *ptr;
+ }
+
+ static void Destroy(T* ptr) {
+ Y_UNUSED(ptr);
+ }
+ };
+
+ template <typename T>
+ struct TNonPodTypeHelper {
+ template <typename TT>
+ static void Write(T* ptr, TT&& value) {
+ new (ptr) T(std::forward<TT>(value));
+ }
+
+ static T Read(T* ptr) {
+ return std::move(*ptr);
+ }
+
+ static void Destroy(T* ptr) {
+ (void)ptr; /* Make MSVC happy. */
+ ptr->~T();
+ }
+ };
+
+ template <typename T>
+ using TTypeHelper = std::conditional_t<
+ TTypeTraits<T>::IsPod,
+ TPodTypeHelper<T>,
+ TNonPodTypeHelper<T>>;
+
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // One producer/one consumer chunked queue.
+
+ template <typename T, size_t ChunkSize = PLATFORM_PAGE_SIZE>
+ class TOneOneQueue: private TNonCopyable {
+ using TTypeHelper = NImpl::TTypeHelper<T>;
+
+ struct TChunk;
+
+ struct TChunkHeader {
+ size_t Count = 0;
+ TChunk* Next = nullptr;
+ };
+
+ struct TChunk: public TChunkHeader {
+ static constexpr size_t MaxCount = (ChunkSize - sizeof(TChunkHeader)) / sizeof(T);
+
+ char Entries[MaxCount * sizeof(T)];
+
+ TChunk() {
+ Y_UNUSED(Entries); // uninitialized
+ }
+
+ ~TChunk() {
+ for (size_t i = 0; i < this->Count; ++i) {
+ TTypeHelper::Destroy(GetPtr(i));
+ }
+ }
+
+ T* GetPtr(size_t i) {
+ return (T*)Entries + i;
+ }
+ };
+
+ struct TWriterState {
+ TChunk* Chunk = nullptr;
+ };
+
+ struct TReaderState {
+ TChunk* Chunk = nullptr;
+ size_t Count = 0;
+ };
+
+ private:
+ TPadded<TWriterState> Writer;
+ TPadded<TReaderState> Reader;
+
+ public:
+ using TItem = T;
+
+ TOneOneQueue() {
+ Writer.Chunk = Reader.Chunk = new TChunk();
+ }
+
+ ~TOneOneQueue() {
+ DeleteChunks(Reader.Chunk);
+ }
+
+ template <typename TT>
+ void Enqueue(TT&& value) {
+ T* ptr = PrepareWrite();
+ Y_ASSERT(ptr);
+ TTypeHelper::Write(ptr, std::forward<TT>(value));
+ CompleteWrite();
+ }
+
+ bool Dequeue(T& value) {
+ if (T* ptr = PrepareRead()) {
+ value = TTypeHelper::Read(ptr);
+ CompleteRead();
+ return true;
+ }
+ return false;
+ }
+
+ bool IsEmpty() {
+ return !PrepareRead();
+ }
+
+ protected:
+ T* PrepareWrite() {
+ TChunk* chunk = Writer.Chunk;
+ Y_ASSERT(chunk && !chunk->Next);
+
+ if (chunk->Count != TChunk::MaxCount) {
+ return chunk->GetPtr(chunk->Count);
+ }
+
+ chunk = new TChunk();
+ AtomicSet(Writer.Chunk->Next, chunk);
+ Writer.Chunk = chunk;
+ return chunk->GetPtr(0);
+ }
+
+ void CompleteWrite() {
+ AtomicSet(Writer.Chunk->Count, Writer.Chunk->Count + 1);
+ }
+
+ T* PrepareRead() {
+ TChunk* chunk = Reader.Chunk;
+ Y_ASSERT(chunk);
+
+ for (;;) {
+ size_t writerCount = AtomicGet(chunk->Count);
+ if (Reader.Count != writerCount) {
+ return chunk->GetPtr(Reader.Count);
+ }
+
+ if (writerCount != TChunk::MaxCount) {
+ return nullptr;
+ }
+
+ chunk = AtomicGet(chunk->Next);
+ if (!chunk) {
+ return nullptr;
+ }
+
+ delete Reader.Chunk;
+ Reader.Chunk = chunk;
+ Reader.Count = 0;
+ }
+ }
+
+ void CompleteRead() {
+ ++Reader.Count;
+ }
+
+ private:
+ static void DeleteChunks(TChunk* chunk) {
+ while (chunk) {
+ TChunk* next = chunk->Next;
+ delete chunk;
+ chunk = next;
+ }
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Multiple producers/single consumer partitioned queue.
+ // Provides FIFO guaranties for each producer.
+
+ template <typename T, size_t Concurrency = 4, size_t ChunkSize = PLATFORM_PAGE_SIZE>
+ class TManyOneQueue: private TNonCopyable {
+ using TTypeHelper = NImpl::TTypeHelper<T>;
+
+ struct TEntry {
+ T Value;
+ ui64 Tag;
+ };
+
+ struct TQueueType: public TOneOneQueue<TEntry, ChunkSize> {
+ TAtomic WriteLock = 0;
+
+ using TOneOneQueue<TEntry, ChunkSize>::PrepareWrite;
+ using TOneOneQueue<TEntry, ChunkSize>::CompleteWrite;
+
+ using TOneOneQueue<TEntry, ChunkSize>::PrepareRead;
+ using TOneOneQueue<TEntry, ChunkSize>::CompleteRead;
+ };
+
+ private:
+ union {
+ TAtomic WriteTag = 0;
+ char Pad[PLATFORM_CACHE_LINE];
+ };
+
+ TQueueType Queues[Concurrency];
+
+ public:
+ using TItem = T;
+
+ template <typename TT>
+ void Enqueue(TT&& value) {
+ ui64 tag = NextTag();
+ while (!TryEnqueue(std::forward<TT>(value), tag)) {
+ SpinLockPause();
+ }
+ }
+
+ bool Dequeue(T& value) {
+ size_t index = 0;
+ if (TEntry* entry = PrepareRead(index)) {
+ value = TTypeHelper::Read(&entry->Value);
+ Queues[index].CompleteRead();
+ return true;
+ }
+ return false;
+ }
+
+ bool IsEmpty() {
+ for (size_t i = 0; i < Concurrency; ++i) {
+ if (!Queues[i].IsEmpty()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private:
+ ui64 NextTag() {
+ // TODO: can we avoid synchronization here? it costs 1.5x performance penalty
+ // return GetCycleCount();
+ return AtomicIncrement(WriteTag);
+ }
+
+ template <typename TT>
+ bool TryEnqueue(TT&& value, ui64 tag) {
+ for (size_t i = 0; i < Concurrency; ++i) {
+ TQueueType& queue = Queues[i];
+ if (AtomicTryAndTryLock(&queue.WriteLock)) {
+ TEntry* entry = queue.PrepareWrite();
+ Y_ASSERT(entry);
+ TTypeHelper::Write(&entry->Value, std::forward<TT>(value));
+ entry->Tag = tag;
+ queue.CompleteWrite();
+ AtomicUnlock(&queue.WriteLock);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ TEntry* PrepareRead(size_t& index) {
+ TEntry* entry = nullptr;
+ ui64 tag = Max();
+
+ for (size_t i = 0; i < Concurrency; ++i) {
+ TEntry* e = Queues[i].PrepareRead();
+ if (e && e->Tag < tag) {
+ index = i;
+ entry = e;
+ tag = e->Tag;
+ }
+ }
+
+ if (entry) {
+ // need second pass to catch updates within already scanned range
+ size_t candidate = index;
+ for (size_t i = 0; i < candidate; ++i) {
+ TEntry* e = Queues[i].PrepareRead();
+ if (e && e->Tag < tag) {
+ index = i;
+ entry = e;
+ tag = e->Tag;
+ }
+ }
+ }
+
+ return entry;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Concurrent many-many queue with strong FIFO guaranties.
+ // Writers will not block readers (and vice versa), but will block each other.
+
+ template <typename T, size_t ChunkSize = PLATFORM_PAGE_SIZE, typename TLock = TAdaptiveLock>
+ class TManyManyQueue: private TNonCopyable {
+ private:
+ TPadded<TLock> WriteLock;
+ TPadded<TLock> ReadLock;
+
+ TOneOneQueue<T, ChunkSize> Queue;
+
+ public:
+ using TItem = T;
+
+ template <typename TT>
+ void Enqueue(TT&& value) {
+ with_lock (WriteLock) {
+ Queue.Enqueue(std::forward<TT>(value));
+ }
+ }
+
+ bool Dequeue(T& value) {
+ with_lock (ReadLock) {
+ return Queue.Dequeue(value);
+ }
+ }
+
+ bool IsEmpty() {
+ with_lock (ReadLock) {
+ return Queue.IsEmpty();
+ }
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Multiple producers/single consumer partitioned queue.
+ // Because of random partitioning reordering possible - FIFO not guaranteed!
+
+ template <typename T, size_t Concurrency = 4, size_t ChunkSize = PLATFORM_PAGE_SIZE>
+ class TRelaxedManyOneQueue: private TNonCopyable {
+ struct TQueueType: public TOneOneQueue<T, ChunkSize> {
+ TAtomic WriteLock = 0;
+ };
+
+ private:
+ union {
+ size_t ReadPos = 0;
+ char Pad[PLATFORM_CACHE_LINE];
+ };
+
+ TQueueType Queues[Concurrency];
+
+ public:
+ using TItem = T;
+
+ template <typename TT>
+ void Enqueue(TT&& value) {
+ while (!TryEnqueue(std::forward<TT>(value))) {
+ SpinLockPause();
+ }
+ }
+
+ bool Dequeue(T& value) {
+ for (size_t i = 0; i < Concurrency; ++i) {
+ TQueueType& queue = Queues[ReadPos++ % Concurrency];
+ if (queue.Dequeue(value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool IsEmpty() {
+ for (size_t i = 0; i < Concurrency; ++i) {
+ if (!Queues[i].IsEmpty()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private:
+ template <typename TT>
+ bool TryEnqueue(TT&& value) {
+ size_t writePos = GetCycleCount();
+ for (size_t i = 0; i < Concurrency; ++i) {
+ TQueueType& queue = Queues[writePos++ % Concurrency];
+ if (AtomicTryAndTryLock(&queue.WriteLock)) {
+ queue.Enqueue(std::forward<TT>(value));
+ AtomicUnlock(&queue.WriteLock);
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Concurrent many-many partitioned queue.
+ // Because of random partitioning reordering possible - FIFO not guaranteed!
+
+ template <typename T, size_t Concurrency = 4, size_t ChunkSize = PLATFORM_PAGE_SIZE>
+ class TRelaxedManyManyQueue: private TNonCopyable {
+ struct TQueueType: public TOneOneQueue<T, ChunkSize> {
+ union {
+ TAtomic WriteLock = 0;
+ char Pad1[PLATFORM_CACHE_LINE];
+ };
+ union {
+ TAtomic ReadLock = 0;
+ char Pad2[PLATFORM_CACHE_LINE];
+ };
+ };
+
+ private:
+ TQueueType Queues[Concurrency];
+
+ public:
+ using TItem = T;
+
+ template <typename TT>
+ void Enqueue(TT&& value) {
+ while (!TryEnqueue(std::forward<TT>(value))) {
+ SpinLockPause();
+ }
+ }
+
+ bool Dequeue(T& value) {
+ size_t readPos = GetCycleCount();
+ for (size_t i = 0; i < Concurrency; ++i) {
+ TQueueType& queue = Queues[readPos++ % Concurrency];
+ if (AtomicTryAndTryLock(&queue.ReadLock)) {
+ bool dequeued = queue.Dequeue(value);
+ AtomicUnlock(&queue.ReadLock);
+ if (dequeued) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ bool IsEmpty() {
+ for (size_t i = 0; i < Concurrency; ++i) {
+ TQueueType& queue = Queues[i];
+ if (AtomicTryAndTryLock(&queue.ReadLock)) {
+ bool empty = queue.IsEmpty();
+ AtomicUnlock(&queue.ReadLock);
+ if (!empty) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private:
+ template <typename TT>
+ bool TryEnqueue(TT&& value) {
+ size_t writePos = GetCycleCount();
+ for (size_t i = 0; i < Concurrency; ++i) {
+ TQueueType& queue = Queues[writePos++ % Concurrency];
+ if (AtomicTryAndTryLock(&queue.WriteLock)) {
+ queue.Enqueue(std::forward<TT>(value));
+ AtomicUnlock(&queue.WriteLock);
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Simple wrapper to deal with AutoPtrs
+
+ template <typename T, typename TImpl>
+ class TAutoQueueBase: private TNonCopyable {
+ private:
+ TImpl Impl;
+
+ public:
+ using TItem = TAutoPtr<T>;
+
+ ~TAutoQueueBase() {
+ TAutoPtr<T> value;
+ while (Dequeue(value)) {
+ // do nothing
+ }
+ }
+
+ void Enqueue(TAutoPtr<T> value) {
+ Impl.Enqueue(value.Get());
+ Y_UNUSED(value.Release());
+ }
+
+ bool Dequeue(TAutoPtr<T>& value) {
+ T* ptr = nullptr;
+ if (Impl.Dequeue(ptr)) {
+ value.Reset(ptr);
+ return true;
+ }
+ return false;
+ }
+
+ bool IsEmpty() {
+ return Impl.IsEmpty();
+ }
+ };
+
+ template <typename T, size_t ChunkSize = PLATFORM_PAGE_SIZE>
+ using TAutoOneOneQueue = TAutoQueueBase<T, TOneOneQueue<T*, ChunkSize>>;
+
+ template <typename T, size_t Concurrency = 4, size_t ChunkSize = PLATFORM_PAGE_SIZE>
+ using TAutoManyOneQueue = TAutoQueueBase<T, TManyOneQueue<T*, Concurrency, ChunkSize>>;
+
+ template <typename T, size_t ChunkSize = PLATFORM_PAGE_SIZE, typename TLock = TAdaptiveLock>
+ using TAutoManyManyQueue = TAutoQueueBase<T, TManyManyQueue<T*, ChunkSize, TLock>>;
+
+ template <typename T, size_t Concurrency = 4, size_t ChunkSize = PLATFORM_PAGE_SIZE>
+ using TAutoRelaxedManyOneQueue = TAutoQueueBase<T, TRelaxedManyOneQueue<T*, Concurrency, ChunkSize>>;
+
+ template <typename T, size_t Concurrency = 4, size_t ChunkSize = PLATFORM_PAGE_SIZE>
+ using TAutoRelaxedManyManyQueue = TAutoQueueBase<T, TRelaxedManyManyQueue<T*, Concurrency, ChunkSize>>;
+}
diff --git a/library/cpp/threading/chunk_queue/queue_ut.cpp b/library/cpp/threading/chunk_queue/queue_ut.cpp
new file mode 100644
index 0000000000..8cb36d8dd1
--- /dev/null
+++ b/library/cpp/threading/chunk_queue/queue_ut.cpp
@@ -0,0 +1,205 @@
+#include "queue.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/set.h>
+
+namespace NThreading {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ Y_UNIT_TEST_SUITE(TOneOneQueueTest){
+ Y_UNIT_TEST(ShouldBeEmptyAtStart){
+ TOneOneQueue<int> queue;
+
+ int result = 0;
+ UNIT_ASSERT(queue.IsEmpty());
+ UNIT_ASSERT(!queue.Dequeue(result));
+}
+
+Y_UNIT_TEST(ShouldReturnEntries) {
+ TOneOneQueue<int> queue;
+ queue.Enqueue(1);
+ queue.Enqueue(2);
+ queue.Enqueue(3);
+
+ int result = 0;
+ UNIT_ASSERT(!queue.IsEmpty());
+ UNIT_ASSERT(queue.Dequeue(result));
+ UNIT_ASSERT_EQUAL(result, 1);
+
+ UNIT_ASSERT(!queue.IsEmpty());
+ UNIT_ASSERT(queue.Dequeue(result));
+ UNIT_ASSERT_EQUAL(result, 2);
+
+ UNIT_ASSERT(!queue.IsEmpty());
+ UNIT_ASSERT(queue.Dequeue(result));
+ UNIT_ASSERT_EQUAL(result, 3);
+
+ UNIT_ASSERT(queue.IsEmpty());
+ UNIT_ASSERT(!queue.Dequeue(result));
+}
+
+Y_UNIT_TEST(ShouldStoreMultipleChunks) {
+ TOneOneQueue<int, 100> queue;
+ for (int i = 0; i < 1000; ++i) {
+ queue.Enqueue(i);
+ }
+
+ for (int i = 0; i < 1000; ++i) {
+ int result = 0;
+ UNIT_ASSERT(!queue.IsEmpty());
+ UNIT_ASSERT(queue.Dequeue(result));
+ UNIT_ASSERT_EQUAL(result, i);
+ }
+}
+}
+;
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_UNIT_TEST_SUITE(TManyOneQueueTest){
+ Y_UNIT_TEST(ShouldBeEmptyAtStart){
+ TManyOneQueue<int> queue;
+
+int result;
+UNIT_ASSERT(queue.IsEmpty());
+UNIT_ASSERT(!queue.Dequeue(result));
+}
+
+Y_UNIT_TEST(ShouldReturnEntries) {
+ TManyOneQueue<int> queue;
+ queue.Enqueue(1);
+ queue.Enqueue(2);
+ queue.Enqueue(3);
+
+ int result = 0;
+ UNIT_ASSERT(!queue.IsEmpty());
+ UNIT_ASSERT(queue.Dequeue(result));
+ UNIT_ASSERT_EQUAL(result, 1);
+
+ UNIT_ASSERT(!queue.IsEmpty());
+ UNIT_ASSERT(queue.Dequeue(result));
+ UNIT_ASSERT_EQUAL(result, 2);
+
+ UNIT_ASSERT(!queue.IsEmpty());
+ UNIT_ASSERT(queue.Dequeue(result));
+ UNIT_ASSERT_EQUAL(result, 3);
+
+ UNIT_ASSERT(queue.IsEmpty());
+ UNIT_ASSERT(!queue.Dequeue(result));
+}
+}
+;
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_UNIT_TEST_SUITE(TManyManyQueueTest){
+ Y_UNIT_TEST(ShouldBeEmptyAtStart){
+ TManyManyQueue<int> queue;
+
+int result = 0;
+UNIT_ASSERT(queue.IsEmpty());
+UNIT_ASSERT(!queue.Dequeue(result));
+}
+
+Y_UNIT_TEST(ShouldReturnEntries) {
+ TManyManyQueue<int> queue;
+ queue.Enqueue(1);
+ queue.Enqueue(2);
+ queue.Enqueue(3);
+
+ int result = 0;
+ UNIT_ASSERT(!queue.IsEmpty());
+ UNIT_ASSERT(queue.Dequeue(result));
+ UNIT_ASSERT_EQUAL(result, 1);
+
+ UNIT_ASSERT(!queue.IsEmpty());
+ UNIT_ASSERT(queue.Dequeue(result));
+ UNIT_ASSERT_EQUAL(result, 2);
+
+ UNIT_ASSERT(!queue.IsEmpty());
+ UNIT_ASSERT(queue.Dequeue(result));
+ UNIT_ASSERT_EQUAL(result, 3);
+
+ UNIT_ASSERT(queue.IsEmpty());
+ UNIT_ASSERT(!queue.Dequeue(result));
+}
+}
+;
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_UNIT_TEST_SUITE(TRelaxedManyOneQueueTest){
+ Y_UNIT_TEST(ShouldBeEmptyAtStart){
+ TRelaxedManyOneQueue<int> queue;
+
+int result;
+UNIT_ASSERT(queue.IsEmpty());
+UNIT_ASSERT(!queue.Dequeue(result));
+}
+
+Y_UNIT_TEST(ShouldReturnEntries) {
+ TSet<int> items = {1, 2, 3};
+
+ TRelaxedManyOneQueue<int> queue;
+ for (int item : items) {
+ queue.Enqueue(item);
+ }
+
+ int result = 0;
+ UNIT_ASSERT(!queue.IsEmpty());
+ UNIT_ASSERT(queue.Dequeue(result));
+ UNIT_ASSERT(items.erase(result));
+
+ UNIT_ASSERT(!queue.IsEmpty());
+ UNIT_ASSERT(queue.Dequeue(result));
+ UNIT_ASSERT(items.erase(result));
+
+ UNIT_ASSERT(!queue.IsEmpty());
+ UNIT_ASSERT(queue.Dequeue(result));
+ UNIT_ASSERT(items.erase(result));
+
+ UNIT_ASSERT(queue.IsEmpty());
+ UNIT_ASSERT(!queue.Dequeue(result));
+}
+}
+;
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_UNIT_TEST_SUITE(TRelaxedManyManyQueueTest){
+ Y_UNIT_TEST(ShouldBeEmptyAtStart){
+ TRelaxedManyManyQueue<int> queue;
+
+int result = 0;
+UNIT_ASSERT(queue.IsEmpty());
+UNIT_ASSERT(!queue.Dequeue(result));
+}
+
+Y_UNIT_TEST(ShouldReturnEntries) {
+ TSet<int> items = {1, 2, 3};
+
+ TRelaxedManyManyQueue<int> queue;
+ for (int item : items) {
+ queue.Enqueue(item);
+ }
+
+ int result = 0;
+ UNIT_ASSERT(!queue.IsEmpty());
+ UNIT_ASSERT(queue.Dequeue(result));
+ UNIT_ASSERT(items.erase(result));
+
+ UNIT_ASSERT(!queue.IsEmpty());
+ UNIT_ASSERT(queue.Dequeue(result));
+ UNIT_ASSERT(items.erase(result));
+
+ UNIT_ASSERT(!queue.IsEmpty());
+ UNIT_ASSERT(queue.Dequeue(result));
+ UNIT_ASSERT(items.erase(result));
+
+ UNIT_ASSERT(queue.IsEmpty());
+ UNIT_ASSERT(!queue.Dequeue(result));
+}
+}
+;
+}
diff --git a/library/cpp/threading/chunk_queue/readme.txt b/library/cpp/threading/chunk_queue/readme.txt
new file mode 100644
index 0000000000..7c9f046a86
--- /dev/null
+++ b/library/cpp/threading/chunk_queue/readme.txt
@@ -0,0 +1,60 @@
+vskipin@dev-kiwi09:~$ ./rtmr-queue-perf -w 4 -r 4 AdaptiveLock64 Mutex64 LFManyMany64 FastLFManyMany64 LFManyOne64 FastLFManyOne64 ManyMany64 ManyOne64
+2016-05-08T11:49:56.729254Z INFO: [-i] Iterations: 10000000
+2016-05-08T11:49:56.729319Z INFO: [-r] NumReaders: 4
+2016-05-08T11:49:56.729355Z INFO: [-w] NumWriters: 4
+2016-05-08T11:49:56.729502Z INFO: starting consumers...
+2016-05-08T11:49:56.729621Z INFO: starting producers...
+2016-05-08T11:49:56.729711Z INFO: wait for producers...
+2016-05-08T11:50:14.650803Z INFO: wait for consumers...
+2016-05-08T11:50:14.650859Z INFO: average producer time: 15.96846675 seconds
+2016-05-08T11:50:14.650885Z INFO: average consumer time: 17.9209995 seconds
+2016-05-08T11:50:14.650897Z INFO: test AdaptiveLock64 duration: 17.921395s (0.448034875us per iteration)
+2016-05-08T11:50:14.650913Z INFO: starting consumers...
+2016-05-08T11:50:14.651028Z INFO: starting producers...
+2016-05-08T11:50:14.651122Z INFO: wait for producers...
+2016-05-08T11:50:31.426378Z INFO: wait for consumers...
+2016-05-08T11:50:31.426447Z INFO: average producer time: 15.58770475 seconds
+2016-05-08T11:50:31.426491Z INFO: average consumer time: 16.775301 seconds
+2016-05-08T11:50:31.426527Z INFO: test Mutex64 duration: 16.775614s (0.41939035us per iteration)
+2016-05-08T11:50:31.426584Z INFO: starting consumers...
+2016-05-08T11:50:31.426655Z INFO: starting producers...
+2016-05-08T11:50:31.426749Z INFO: wait for producers...
+2016-05-08T11:50:40.578425Z INFO: wait for consumers...
+2016-05-08T11:50:40.578523Z INFO: average producer time: 8.69236075 seconds
+2016-05-08T11:50:40.578577Z INFO: average consumer time: 9.15165125 seconds
+2016-05-08T11:50:40.578617Z INFO: test LFManyMany64 duration: 9.152033s (0.228800825us per iteration)
+2016-05-08T11:50:40.578670Z INFO: starting consumers...
+2016-05-08T11:50:40.578742Z INFO: starting producers...
+2016-05-08T11:50:40.578893Z INFO: wait for producers...
+2016-05-08T11:50:47.447686Z INFO: wait for consumers...
+2016-05-08T11:50:47.447758Z INFO: average producer time: 6.81136025 seconds
+2016-05-08T11:50:47.447793Z INFO: average consumer time: 6.86875825 seconds
+2016-05-08T11:50:47.447834Z INFO: test FastLFManyMany64 duration: 6.869165s (0.171729125us per iteration)
+2016-05-08T11:50:47.447901Z INFO: starting consumers...
+2016-05-08T11:50:47.447967Z INFO: starting producers...
+2016-05-08T11:50:47.448058Z INFO: wait for producers...
+2016-05-08T11:50:50.469710Z INFO: wait for consumers...
+2016-05-08T11:50:50.469798Z INFO: average producer time: 2.9915505 seconds
+2016-05-08T11:50:50.469848Z INFO: average consumer time: 3.02161675 seconds
+2016-05-08T11:50:50.469883Z INFO: test LFManyOne64 duration: 3.021983s (0.075549575us per iteration)
+2016-05-08T11:50:50.469947Z INFO: starting consumers...
+2016-05-08T11:50:50.470012Z INFO: starting producers...
+2016-05-08T11:50:50.470104Z INFO: wait for producers...
+2016-05-08T11:50:53.139964Z INFO: wait for consumers...
+2016-05-08T11:50:53.140050Z INFO: average producer time: 2.5656465 seconds
+2016-05-08T11:50:53.140102Z INFO: average consumer time: 2.6697755 seconds
+2016-05-08T11:50:53.140149Z INFO: test FastLFManyOne64 duration: 2.670202s (0.06675505us per iteration)
+2016-05-08T11:50:53.140206Z INFO: starting consumers...
+2016-05-08T11:50:53.140281Z INFO: starting producers...
+2016-05-08T11:50:53.140371Z INFO: wait for producers...
+2016-05-08T11:50:59.067812Z INFO: wait for consumers...
+2016-05-08T11:50:59.067895Z INFO: average producer time: 5.8925505 seconds
+2016-05-08T11:50:59.067946Z INFO: average consumer time: 5.9273365 seconds
+2016-05-08T11:50:59.067978Z INFO: test ManyMany64 duration: 5.927773s (0.148194325us per iteration)
+2016-05-08T11:50:59.068068Z INFO: starting consumers...
+2016-05-08T11:50:59.068179Z INFO: starting producers...
+2016-05-08T11:50:59.068288Z INFO: wait for producers...
+2016-05-08T11:51:03.427416Z INFO: wait for consumers...
+2016-05-08T11:51:03.427514Z INFO: average producer time: 4.1055505 seconds
+2016-05-08T11:51:03.427560Z INFO: average consumer time: 4.35914975 seconds
+2016-05-08T11:51:03.427596Z INFO: test ManyOne64 duration: 4.359529s (0.108988225us per iteration)
diff --git a/library/cpp/threading/chunk_queue/ut/ya.make b/library/cpp/threading/chunk_queue/ut/ya.make
new file mode 100644
index 0000000000..a35ed6bc4b
--- /dev/null
+++ b/library/cpp/threading/chunk_queue/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/threading/chunk_queue)
+
+OWNER(g:rtmr)
+
+SRCS(
+ queue_ut.cpp
+)
+
+END()
diff --git a/library/cpp/threading/chunk_queue/ya.make b/library/cpp/threading/chunk_queue/ya.make
new file mode 100644
index 0000000000..2f883140ba
--- /dev/null
+++ b/library/cpp/threading/chunk_queue/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(g:rtmr)
+
+SRCS(
+ queue.cpp
+)
+
+END()
diff --git a/library/cpp/threading/equeue/equeue.cpp b/library/cpp/threading/equeue/equeue.cpp
new file mode 100644
index 0000000000..54a848e912
--- /dev/null
+++ b/library/cpp/threading/equeue/equeue.cpp
@@ -0,0 +1,80 @@
+#include "equeue.h"
+
+TElasticQueue::TElasticQueue(THolder<IThreadPool> slaveQueue)
+ : SlaveQueue_(std::move(slaveQueue))
+{
+}
+
+size_t TElasticQueue::ObjectCount() const {
+ return (size_t)AtomicGet(ObjectCount_);
+}
+
+bool TElasticQueue::TryIncCounter() {
+ if ((size_t)AtomicIncrement(GuardCount_) > MaxQueueSize_) {
+ AtomicDecrement(GuardCount_);
+ return false;
+ }
+
+ return true;
+}
+
+
+
+class TElasticQueue::TDecrementingWrapper: TNonCopyable, public IObjectInQueue {
+public:
+ TDecrementingWrapper(IObjectInQueue* realObject, TElasticQueue* queue)
+ : RealObject_(realObject)
+ , Queue_(queue)
+ {
+ AtomicIncrement(Queue_->ObjectCount_);
+ }
+
+ ~TDecrementingWrapper() override {
+ AtomicDecrement(Queue_->ObjectCount_);
+ AtomicDecrement(Queue_->GuardCount_);
+ }
+private:
+ void Process(void *tsr) override {
+ THolder<TDecrementingWrapper> self(this);
+ RealObject_->Process(tsr);
+ }
+private:
+ IObjectInQueue* const RealObject_;
+ TElasticQueue* const Queue_;
+};
+
+
+
+bool TElasticQueue::Add(IObjectInQueue* obj) {
+ if (!TryIncCounter()) {
+ return false;
+ }
+
+ THolder<TDecrementingWrapper> wrapper;
+ try {
+ wrapper.Reset(new TDecrementingWrapper(obj, this));
+ } catch (...) {
+ AtomicDecrement(GuardCount_);
+ throw;
+ }
+
+ if (SlaveQueue_->Add(wrapper.Get())) {
+ Y_UNUSED(wrapper.Release());
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void TElasticQueue::Start(size_t threadCount, size_t maxQueueSize) {
+ MaxQueueSize_ = maxQueueSize;
+ SlaveQueue_->Start(threadCount, maxQueueSize);
+}
+
+void TElasticQueue::Stop() noexcept {
+ return SlaveQueue_->Stop();
+}
+
+size_t TElasticQueue::Size() const noexcept {
+ return SlaveQueue_->Size();
+}
diff --git a/library/cpp/threading/equeue/equeue.h b/library/cpp/threading/equeue/equeue.h
new file mode 100644
index 0000000000..40dd342585
--- /dev/null
+++ b/library/cpp/threading/equeue/equeue.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <util/thread/pool.h>
+#include <util/system/atomic.h>
+#include <util/generic/ptr.h>
+
+//actual queue limit will be (maxQueueSize - numBusyThreads) or 0
+class TElasticQueue: public IThreadPool {
+public:
+ explicit TElasticQueue(THolder<IThreadPool> slaveQueue);
+
+ bool Add(IObjectInQueue* obj) override;
+ size_t Size() const noexcept override;
+
+ void Start(size_t threadCount, size_t maxQueueSize) override;
+ void Stop() noexcept override;
+
+ size_t ObjectCount() const;
+private:
+ class TDecrementingWrapper;
+
+ bool TryIncCounter();
+private:
+ THolder<IThreadPool> SlaveQueue_;
+ size_t MaxQueueSize_ = 0;
+ TAtomic ObjectCount_ = 0;
+ TAtomic GuardCount_ = 0;
+};
diff --git a/library/cpp/threading/equeue/equeue_ut.cpp b/library/cpp/threading/equeue/equeue_ut.cpp
new file mode 100644
index 0000000000..9cf2aced44
--- /dev/null
+++ b/library/cpp/threading/equeue/equeue_ut.cpp
@@ -0,0 +1,125 @@
+#include "equeue.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/system/event.h>
+#include <util/datetime/base.h>
+#include <util/generic/vector.h>
+
+Y_UNIT_TEST_SUITE(TElasticQueueTest) {
+ const size_t MaxQueueSize = 20;
+ const size_t ThreadCount = 10;
+ const size_t N = 100000;
+
+ static THolder<TElasticQueue> Queue;
+
+ struct TQueueSetup {
+ TQueueSetup() {
+ Queue.Reset(new TElasticQueue(MakeHolder<TSimpleThreadPool>()));
+ Queue->Start(ThreadCount, MaxQueueSize);
+ }
+ ~TQueueSetup() {
+ Queue->Stop();
+ }
+ };
+
+ struct TCounters {
+ void Reset() {
+ Processed = Scheduled = Discarded = Total = 0;
+ }
+
+ TAtomic Processed;
+ TAtomic Scheduled;
+ TAtomic Discarded;
+ TAtomic Total;
+ };
+ static TCounters Counters;
+
+//fill test -- fill queue with "endless" jobs
+ TSystemEvent WaitEvent;
+ Y_UNIT_TEST(FillTest) {
+ Counters.Reset();
+
+ struct TWaitJob: public IObjectInQueue {
+ void Process(void*) override {
+ WaitEvent.Wait();
+ AtomicIncrement(Counters.Processed);
+ }
+ } job;
+
+ struct TLocalSetup: TQueueSetup {
+ ~TLocalSetup() {
+ WaitEvent.Signal();
+ }
+ };
+
+ size_t enqueued = 0;
+ {
+ TLocalSetup setup;
+ while (Queue->Add(&job) && enqueued < MaxQueueSize + 100) {
+ ++enqueued;
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(enqueued, MaxQueueSize);
+ UNIT_ASSERT_VALUES_EQUAL(enqueued, Queue->ObjectCount());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(0u, Queue->ObjectCount());
+ UNIT_ASSERT_VALUES_EQUAL(0u, Queue->Size());
+ UNIT_ASSERT_VALUES_EQUAL((size_t)Counters.Processed, enqueued);
+ }
+
+
+//concurrent test -- send many jobs from different threads
+ struct TJob: public IObjectInQueue {
+ void Process(void*) override {
+ AtomicIncrement(Counters.Processed);
+ };
+ };
+ static TJob Job;
+
+ static bool TryAdd() {
+ AtomicIncrement(Counters.Total);
+ if (Queue->Add(&Job)) {
+ AtomicIncrement(Counters.Scheduled);
+ return true;
+ } else {
+ AtomicIncrement(Counters.Discarded);
+ return false;
+ }
+ }
+
+ static size_t TryCounter;
+
+ Y_UNIT_TEST(ConcurrentTest) {
+ Counters.Reset();
+ TryCounter = 0;
+
+ struct TSender: public IThreadFactory::IThreadAble {
+ void DoExecute() override {
+ while ((size_t)AtomicIncrement(TryCounter) <= N) {
+ if (!TryAdd()) {
+ Sleep(TDuration::MicroSeconds(50));
+ }
+ }
+ }
+ } sender;
+
+ {
+ TQueueSetup setup;
+
+ TVector< TAutoPtr<IThreadFactory::IThread> > senders;
+ for (size_t i = 0; i < ThreadCount; ++i) {
+ senders.push_back(::SystemThreadFactory()->Run(&sender));
+ }
+
+ for (size_t i = 0; i < senders.size(); ++i) {
+ senders[i]->Join();
+ }
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL((size_t)Counters.Total, N);
+ UNIT_ASSERT_VALUES_EQUAL(Counters.Processed, Counters.Scheduled);
+ UNIT_ASSERT_VALUES_EQUAL(Counters.Total, Counters.Scheduled + Counters.Discarded);
+ }
+}
diff --git a/library/cpp/threading/equeue/ut/ya.make b/library/cpp/threading/equeue/ut/ya.make
new file mode 100644
index 0000000000..2f6293d47d
--- /dev/null
+++ b/library/cpp/threading/equeue/ut/ya.make
@@ -0,0 +1,18 @@
+UNITTEST()
+
+OWNER(
+ g:base
+ g:middle
+)
+
+PEERDIR(
+ ADDINCL library/cpp/threading/equeue
+)
+
+SRCDIR(library/cpp/threading/equeue)
+
+SRCS(
+ equeue_ut.cpp
+)
+
+END()
diff --git a/library/cpp/threading/equeue/ya.make b/library/cpp/threading/equeue/ya.make
new file mode 100644
index 0000000000..314f4d3c86
--- /dev/null
+++ b/library/cpp/threading/equeue/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(
+ g:base
+ g:middle
+ ironpeter
+ mvel
+)
+
+SRCS(
+ equeue.h
+ equeue.cpp
+)
+
+END()
diff --git a/library/cpp/threading/future/async.cpp b/library/cpp/threading/future/async.cpp
new file mode 100644
index 0000000000..ad9b21a2cf
--- /dev/null
+++ b/library/cpp/threading/future/async.cpp
@@ -0,0 +1 @@
+#include "async.h"
diff --git a/library/cpp/threading/future/async.h b/library/cpp/threading/future/async.h
new file mode 100644
index 0000000000..8543fdd5c6
--- /dev/null
+++ b/library/cpp/threading/future/async.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "future.h"
+
+#include <util/generic/function.h>
+#include <util/thread/pool.h>
+
+namespace NThreading {
+ /**
+ * @brief Asynchronously executes @arg func in @arg queue returning a future for the result.
+ *
+ * @arg func should be a callable object with signature T().
+ * @arg queue where @arg will be executed
+ * @returns For @arg func with signature T() the function returns TFuture<T> unless T is TFuture<U>.
+ * In this case the function returns TFuture<U>.
+ *
+ * If you want to use another queue for execution just write an overload, @see ExtensionExample
+ * unittest.
+ */
+ template <typename Func>
+ TFuture<TFutureType<TFunctionResult<Func>>> Async(Func&& func, IThreadPool& queue) {
+ auto promise = NewPromise<TFutureType<TFunctionResult<Func>>>();
+ auto lambda = [promise, func = std::forward<Func>(func)]() mutable {
+ NImpl::SetValue(promise, func);
+ };
+ queue.SafeAddFunc(std::move(lambda));
+
+ return promise.GetFuture();
+ }
+
+}
diff --git a/library/cpp/threading/future/async_ut.cpp b/library/cpp/threading/future/async_ut.cpp
new file mode 100644
index 0000000000..a3699744e4
--- /dev/null
+++ b/library/cpp/threading/future/async_ut.cpp
@@ -0,0 +1,57 @@
+#include "async.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+
+namespace {
+ struct TMySuperTaskQueue {
+ };
+
+}
+
+namespace NThreading {
+ /* Here we provide an Async overload for TMySuperTaskQueue indide NThreading namespace
+ * so that we can call it in the way
+ *
+ * TMySuperTaskQueue queue;
+ * NThreading::Async([](){}, queue);
+ *
+ * See also ExtensionExample unittest.
+ */
+ template <typename Func>
+ TFuture<TFunctionResult<Func>> Async(Func func, TMySuperTaskQueue&) {
+ return MakeFuture(func());
+ }
+
+}
+
+Y_UNIT_TEST_SUITE(Async) {
+ Y_UNIT_TEST(ExtensionExample) {
+ TMySuperTaskQueue queue;
+ auto future = NThreading::Async([]() { return 5; }, queue);
+ future.Wait();
+ UNIT_ASSERT_VALUES_EQUAL(future.GetValue(), 5);
+ }
+
+ Y_UNIT_TEST(WorksWithIMtpQueue) {
+ auto queue = MakeHolder<TThreadPool>();
+ queue->Start(1);
+
+ auto future = NThreading::Async([]() { return 5; }, *queue);
+ future.Wait();
+ UNIT_ASSERT_VALUES_EQUAL(future.GetValue(), 5);
+ }
+
+ Y_UNIT_TEST(ProperlyDeducesFutureType) {
+ // Compileability test
+ auto queue = CreateThreadPool(1);
+
+ NThreading::TFuture<void> f1 = NThreading::Async([]() {}, *queue);
+ NThreading::TFuture<int> f2 = NThreading::Async([]() { return 5; }, *queue);
+ NThreading::TFuture<double> f3 = NThreading::Async([]() { return 5.0; }, *queue);
+ NThreading::TFuture<TVector<int>> f4 = NThreading::Async([]() { return TVector<int>(); }, *queue);
+ NThreading::TFuture<int> f5 = NThreading::Async([]() { return NThreading::MakeFuture(5); }, *queue);
+ }
+}
diff --git a/library/cpp/threading/future/core/future-inl.h b/library/cpp/threading/future/core/future-inl.h
new file mode 100644
index 0000000000..5fd4296a93
--- /dev/null
+++ b/library/cpp/threading/future/core/future-inl.h
@@ -0,0 +1,986 @@
+#pragma once
+
+#if !defined(INCLUDE_FUTURE_INL_H)
+#error "you should never include future-inl.h directly"
+#endif // INCLUDE_FUTURE_INL_H
+
+namespace NThreading {
+ namespace NImpl {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <typename T>
+ using TCallback = std::function<void(const TFuture<T>&)>;
+
+ template <typename T>
+ using TCallbackList = TVector<TCallback<T>>; // TODO: small vector
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ enum class TError {
+ Error
+ };
+
+ template <typename T>
+ class TFutureState: public TAtomicRefCount<TFutureState<T>> {
+ enum {
+ NotReady,
+ ExceptionSet,
+ ValueMoved, // keep the ordering of this and following values
+ ValueSet,
+ ValueRead,
+ };
+
+ private:
+ mutable TAtomic State;
+ TAdaptiveLock StateLock;
+
+ TCallbackList<T> Callbacks;
+ mutable THolder<TSystemEvent> ReadyEvent;
+
+ std::exception_ptr Exception;
+
+ union {
+ char NullValue;
+ T Value;
+ };
+
+ void AccessValue(TDuration timeout, int acquireState) const {
+ int state = AtomicGet(State);
+ if (Y_UNLIKELY(state == NotReady)) {
+ if (timeout == TDuration::Zero()) {
+ ythrow TFutureException() << "value not set";
+ }
+
+ if (!Wait(timeout)) {
+ ythrow TFutureException() << "wait timeout";
+ }
+
+ state = AtomicGet(State);
+ }
+
+ TryRethrowWithState(state);
+
+ switch (AtomicGetAndCas(&State, acquireState, ValueSet)) {
+ case ValueSet:
+ break;
+ case ValueRead:
+ if (acquireState != ValueRead) {
+ ythrow TFutureException() << "value being read";
+ }
+ break;
+ case ValueMoved:
+ ythrow TFutureException() << "value was moved";
+ default:
+ Y_ASSERT(state == ValueSet);
+ }
+ }
+
+ public:
+ TFutureState()
+ : State(NotReady)
+ , NullValue(0)
+ {
+ }
+
+ template <typename TT>
+ TFutureState(TT&& value)
+ : State(ValueSet)
+ , Value(std::forward<TT>(value))
+ {
+ }
+
+ TFutureState(std::exception_ptr exception, TError)
+ : State(ExceptionSet)
+ , Exception(std::move(exception))
+ , NullValue(0)
+ {
+ }
+
+ ~TFutureState() {
+ if (State >= ValueMoved) { // ValueMoved, ValueSet, ValueRead
+ Value.~T();
+ }
+ }
+
+ bool HasValue() const {
+ return AtomicGet(State) >= ValueMoved; // ValueMoved, ValueSet, ValueRead
+ }
+
+ void TryRethrow() const {
+ int state = AtomicGet(State);
+ TryRethrowWithState(state);
+ }
+
+ bool HasException() const {
+ return AtomicGet(State) == ExceptionSet;
+ }
+
+ const T& GetValue(TDuration timeout = TDuration::Zero()) const {
+ AccessValue(timeout, ValueRead);
+ return Value;
+ }
+
+ T ExtractValue(TDuration timeout = TDuration::Zero()) {
+ AccessValue(timeout, ValueMoved);
+ return std::move(Value);
+ }
+
+ template <typename TT>
+ void SetValue(TT&& value) {
+ bool success = TrySetValue(std::forward<TT>(value));
+ if (Y_UNLIKELY(!success)) {
+ ythrow TFutureException() << "value already set";
+ }
+ }
+
+ template <typename TT>
+ bool TrySetValue(TT&& value) {
+ TSystemEvent* readyEvent = nullptr;
+ TCallbackList<T> callbacks;
+
+ with_lock (StateLock) {
+ int state = AtomicGet(State);
+ if (Y_UNLIKELY(state != NotReady)) {
+ return false;
+ }
+
+ new (&Value) T(std::forward<TT>(value));
+
+ readyEvent = ReadyEvent.Get();
+ callbacks = std::move(Callbacks);
+
+ AtomicSet(State, ValueSet);
+ }
+
+ if (readyEvent) {
+ readyEvent->Signal();
+ }
+
+ if (callbacks) {
+ TFuture<T> temp(this);
+ for (auto& callback : callbacks) {
+ callback(temp);
+ }
+ }
+
+ return true;
+ }
+
+ void SetException(std::exception_ptr e) {
+ bool success = TrySetException(std::move(e));
+ if (Y_UNLIKELY(!success)) {
+ ythrow TFutureException() << "value already set";
+ }
+ }
+
+ bool TrySetException(std::exception_ptr e) {
+ TSystemEvent* readyEvent;
+ TCallbackList<T> callbacks;
+
+ with_lock (StateLock) {
+ int state = AtomicGet(State);
+ if (Y_UNLIKELY(state != NotReady)) {
+ return false;
+ }
+
+ Exception = std::move(e);
+
+ readyEvent = ReadyEvent.Get();
+ callbacks = std::move(Callbacks);
+
+ AtomicSet(State, ExceptionSet);
+ }
+
+ if (readyEvent) {
+ readyEvent->Signal();
+ }
+
+ if (callbacks) {
+ TFuture<T> temp(this);
+ for (auto& callback : callbacks) {
+ callback(temp);
+ }
+ }
+
+ return true;
+ }
+
+ template <typename F>
+ bool Subscribe(F&& func) {
+ with_lock (StateLock) {
+ int state = AtomicGet(State);
+ if (state == NotReady) {
+ Callbacks.emplace_back(std::forward<F>(func));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void Wait() const {
+ Wait(TInstant::Max());
+ }
+
+ bool Wait(TDuration timeout) const {
+ return Wait(timeout.ToDeadLine());
+ }
+
+ bool Wait(TInstant deadline) const {
+ TSystemEvent* readyEvent = nullptr;
+
+ with_lock (StateLock) {
+ int state = AtomicGet(State);
+ if (state != NotReady) {
+ return true;
+ }
+
+ if (!ReadyEvent) {
+ ReadyEvent.Reset(new TSystemEvent());
+ }
+ readyEvent = ReadyEvent.Get();
+ }
+
+ Y_ASSERT(readyEvent);
+ return readyEvent->WaitD(deadline);
+ }
+
+ void TryRethrowWithState(int state) const {
+ if (Y_UNLIKELY(state == ExceptionSet)) {
+ Y_ASSERT(Exception);
+ std::rethrow_exception(Exception);
+ }
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <>
+ class TFutureState<void>: public TAtomicRefCount<TFutureState<void>> {
+ enum {
+ NotReady,
+ ValueSet,
+ ExceptionSet,
+ };
+
+ private:
+ TAtomic State;
+ TAdaptiveLock StateLock;
+
+ TCallbackList<void> Callbacks;
+ mutable THolder<TSystemEvent> ReadyEvent;
+
+ std::exception_ptr Exception;
+
+ public:
+ TFutureState(bool valueSet = false)
+ : State(valueSet ? ValueSet : NotReady)
+ {
+ }
+
+ TFutureState(std::exception_ptr exception, TError)
+ : State(ExceptionSet)
+ , Exception(std::move(exception))
+ {
+ }
+
+ bool HasValue() const {
+ return AtomicGet(State) == ValueSet;
+ }
+
+ void TryRethrow() const {
+ int state = AtomicGet(State);
+ TryRethrowWithState(state);
+ }
+
+ bool HasException() const {
+ return AtomicGet(State) == ExceptionSet;
+ }
+
+ void GetValue(TDuration timeout = TDuration::Zero()) const {
+ int state = AtomicGet(State);
+ if (Y_UNLIKELY(state == NotReady)) {
+ if (timeout == TDuration::Zero()) {
+ ythrow TFutureException() << "value not set";
+ }
+
+ if (!Wait(timeout)) {
+ ythrow TFutureException() << "wait timeout";
+ }
+
+ state = AtomicGet(State);
+ }
+
+ TryRethrowWithState(state);
+
+ Y_ASSERT(state == ValueSet);
+ }
+
+ void SetValue() {
+ bool success = TrySetValue();
+ if (Y_UNLIKELY(!success)) {
+ ythrow TFutureException() << "value already set";
+ }
+ }
+
+ bool TrySetValue() {
+ TSystemEvent* readyEvent = nullptr;
+ TCallbackList<void> callbacks;
+
+ with_lock (StateLock) {
+ int state = AtomicGet(State);
+ if (Y_UNLIKELY(state != NotReady)) {
+ return false;
+ }
+
+ readyEvent = ReadyEvent.Get();
+ callbacks = std::move(Callbacks);
+
+ AtomicSet(State, ValueSet);
+ }
+
+ if (readyEvent) {
+ readyEvent->Signal();
+ }
+
+ if (callbacks) {
+ TFuture<void> temp(this);
+ for (auto& callback : callbacks) {
+ callback(temp);
+ }
+ }
+
+ return true;
+ }
+
+ void SetException(std::exception_ptr e) {
+ bool success = TrySetException(std::move(e));
+ if (Y_UNLIKELY(!success)) {
+ ythrow TFutureException() << "value already set";
+ }
+ }
+
+ bool TrySetException(std::exception_ptr e) {
+ TSystemEvent* readyEvent = nullptr;
+ TCallbackList<void> callbacks;
+
+ with_lock (StateLock) {
+ int state = AtomicGet(State);
+ if (Y_UNLIKELY(state != NotReady)) {
+ return false;
+ }
+
+ Exception = std::move(e);
+
+ readyEvent = ReadyEvent.Get();
+ callbacks = std::move(Callbacks);
+
+ AtomicSet(State, ExceptionSet);
+ }
+
+ if (readyEvent) {
+ readyEvent->Signal();
+ }
+
+ if (callbacks) {
+ TFuture<void> temp(this);
+ for (auto& callback : callbacks) {
+ callback(temp);
+ }
+ }
+
+ return true;
+ }
+
+ template <typename F>
+ bool Subscribe(F&& func) {
+ with_lock (StateLock) {
+ int state = AtomicGet(State);
+ if (state == NotReady) {
+ Callbacks.emplace_back(std::forward<F>(func));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void Wait() const {
+ Wait(TInstant::Max());
+ }
+
+ bool Wait(TDuration timeout) const {
+ return Wait(timeout.ToDeadLine());
+ }
+
+ bool Wait(TInstant deadline) const {
+ TSystemEvent* readyEvent = nullptr;
+
+ with_lock (StateLock) {
+ int state = AtomicGet(State);
+ if (state != NotReady) {
+ return true;
+ }
+
+ if (!ReadyEvent) {
+ ReadyEvent.Reset(new TSystemEvent());
+ }
+ readyEvent = ReadyEvent.Get();
+ }
+
+ Y_ASSERT(readyEvent);
+ return readyEvent->WaitD(deadline);
+ }
+
+ void TryRethrowWithState(int state) const {
+ if (Y_UNLIKELY(state == ExceptionSet)) {
+ Y_ASSERT(Exception);
+ std::rethrow_exception(Exception);
+ }
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <typename T>
+ inline void SetValueImpl(TPromise<T>& promise, const T& value) {
+ promise.SetValue(value);
+ }
+
+ template <typename T>
+ inline void SetValueImpl(TPromise<T>& promise, T&& value) {
+ promise.SetValue(std::move(value));
+ }
+
+ template <typename T>
+ inline void SetValueImpl(TPromise<T>& promise, const TFuture<T>& future,
+ std::enable_if_t<!std::is_void<T>::value, bool> = false) {
+ future.Subscribe([=](const TFuture<T>& f) mutable {
+ T const* value;
+ try {
+ value = &f.GetValue();
+ } catch (...) {
+ promise.SetException(std::current_exception());
+ return;
+ }
+ promise.SetValue(*value);
+ });
+ }
+
+ template <typename T>
+ inline void SetValueImpl(TPromise<void>& promise, const TFuture<T>& future) {
+ future.Subscribe([=](const TFuture<T>& f) mutable {
+ try {
+ f.TryRethrow();
+ } catch (...) {
+ promise.SetException(std::current_exception());
+ return;
+ }
+ promise.SetValue();
+ });
+ }
+
+ template <typename T, typename F>
+ inline void SetValue(TPromise<T>& promise, F&& func) {
+ try {
+ SetValueImpl(promise, func());
+ } catch (...) {
+ const bool success = promise.TrySetException(std::current_exception());
+ if (Y_UNLIKELY(!success)) {
+ throw;
+ }
+ }
+ }
+
+ template <typename F>
+ inline void SetValue(TPromise<void>& promise, F&& func,
+ std::enable_if_t<std::is_void<TFunctionResult<F>>::value, bool> = false) {
+ try {
+ func();
+ } catch (...) {
+ promise.SetException(std::current_exception());
+ return;
+ }
+ promise.SetValue();
+ }
+
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TFutureStateId {
+ private:
+ const void* Id;
+
+ public:
+ template <typename T>
+ explicit TFutureStateId(const NImpl::TFutureState<T>& state)
+ : Id(&state)
+ {
+ }
+
+ const void* Value() const noexcept {
+ return Id;
+ }
+ };
+
+ inline bool operator==(const TFutureStateId& l, const TFutureStateId& r) {
+ return l.Value() == r.Value();
+ }
+
+ inline bool operator!=(const TFutureStateId& l, const TFutureStateId& r) {
+ return !(l == r);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <typename T>
+ inline TFuture<T>::TFuture(const TIntrusivePtr<TFutureState>& state) noexcept
+ : State(state)
+ {
+ }
+
+ template <typename T>
+ inline void TFuture<T>::Swap(TFuture<T>& other) {
+ State.Swap(other.State);
+ }
+
+ template <typename T>
+ inline bool TFuture<T>::HasValue() const {
+ return State && State->HasValue();
+ }
+
+ template <typename T>
+ inline const T& TFuture<T>::GetValue(TDuration timeout) const {
+ EnsureInitialized();
+ return State->GetValue(timeout);
+ }
+
+ template <typename T>
+ inline T TFuture<T>::ExtractValue(TDuration timeout) {
+ EnsureInitialized();
+ return State->ExtractValue(timeout);
+ }
+
+ template <typename T>
+ inline const T& TFuture<T>::GetValueSync() const {
+ return GetValue(TDuration::Max());
+ }
+
+ template <typename T>
+ inline T TFuture<T>::ExtractValueSync() {
+ return ExtractValue(TDuration::Max());
+ }
+
+ template <typename T>
+ inline void TFuture<T>::TryRethrow() const {
+ if (State) {
+ State->TryRethrow();
+ }
+ }
+
+ template <typename T>
+ inline bool TFuture<T>::HasException() const {
+ return State && State->HasException();
+ }
+
+ template <typename T>
+ inline void TFuture<T>::Wait() const {
+ EnsureInitialized();
+ return State->Wait();
+ }
+
+ template <typename T>
+ inline bool TFuture<T>::Wait(TDuration timeout) const {
+ EnsureInitialized();
+ return State->Wait(timeout);
+ }
+
+ template <typename T>
+ inline bool TFuture<T>::Wait(TInstant deadline) const {
+ EnsureInitialized();
+ return State->Wait(deadline);
+ }
+
+ template <typename T>
+ template <typename F>
+ inline const TFuture<T>& TFuture<T>::Subscribe(F&& func) const {
+ EnsureInitialized();
+ if (!State->Subscribe(std::forward<F>(func))) {
+ func(*this);
+ }
+ return *this;
+ }
+
+ template <typename T>
+ template <typename F>
+ inline const TFuture<T>& TFuture<T>::NoexceptSubscribe(F&& func) const noexcept {
+ return Subscribe(std::forward<F>(func));
+ }
+
+
+ template <typename T>
+ template <typename F>
+ inline TFuture<TFutureType<TFutureCallResult<F, T>>> TFuture<T>::Apply(F&& func) const {
+ auto promise = NewPromise<TFutureType<TFutureCallResult<F, T>>>();
+ Subscribe([promise, func = std::forward<F>(func)](const TFuture<T>& future) mutable {
+ NImpl::SetValue(promise, [&]() { return func(future); });
+ });
+ return promise;
+ }
+
+ template <typename T>
+ inline TFuture<void> TFuture<T>::IgnoreResult() const {
+ auto promise = NewPromise();
+ Subscribe([=](const TFuture<T>& future) mutable {
+ NImpl::SetValueImpl(promise, future);
+ });
+ return promise;
+ }
+
+ template <typename T>
+ inline bool TFuture<T>::Initialized() const {
+ return bool(State);
+ }
+
+ template <typename T>
+ inline TMaybe<TFutureStateId> TFuture<T>::StateId() const noexcept {
+ return State != nullptr ? MakeMaybe<TFutureStateId>(*State) : Nothing();
+ }
+
+ template <typename T>
+ inline void TFuture<T>::EnsureInitialized() const {
+ if (!State) {
+ ythrow TFutureException() << "state not initialized";
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ inline TFuture<void>::TFuture(const TIntrusivePtr<TFutureState>& state) noexcept
+ : State(state)
+ {
+ }
+
+ inline void TFuture<void>::Swap(TFuture<void>& other) {
+ State.Swap(other.State);
+ }
+
+ inline bool TFuture<void>::HasValue() const {
+ return State && State->HasValue();
+ }
+
+ inline void TFuture<void>::GetValue(TDuration timeout) const {
+ EnsureInitialized();
+ State->GetValue(timeout);
+ }
+
+ inline void TFuture<void>::GetValueSync() const {
+ GetValue(TDuration::Max());
+ }
+
+ inline void TFuture<void>::TryRethrow() const {
+ if (State) {
+ State->TryRethrow();
+ }
+ }
+
+ inline bool TFuture<void>::HasException() const {
+ return State && State->HasException();
+ }
+
+ inline void TFuture<void>::Wait() const {
+ EnsureInitialized();
+ return State->Wait();
+ }
+
+ inline bool TFuture<void>::Wait(TDuration timeout) const {
+ EnsureInitialized();
+ return State->Wait(timeout);
+ }
+
+ inline bool TFuture<void>::Wait(TInstant deadline) const {
+ EnsureInitialized();
+ return State->Wait(deadline);
+ }
+
+ template <typename F>
+ inline const TFuture<void>& TFuture<void>::Subscribe(F&& func) const {
+ EnsureInitialized();
+ if (!State->Subscribe(std::forward<F>(func))) {
+ func(*this);
+ }
+ return *this;
+ }
+
+ template <typename F>
+ inline const TFuture<void>& TFuture<void>::NoexceptSubscribe(F&& func) const noexcept {
+ return Subscribe(std::forward<F>(func));
+ }
+
+
+ template <typename F>
+ inline TFuture<TFutureType<TFutureCallResult<F, void>>> TFuture<void>::Apply(F&& func) const {
+ auto promise = NewPromise<TFutureType<TFutureCallResult<F, void>>>();
+ Subscribe([promise, func = std::forward<F>(func)](const TFuture<void>& future) mutable {
+ NImpl::SetValue(promise, [&]() { return func(future); });
+ });
+ return promise;
+ }
+
+ template <typename R>
+ inline TFuture<R> TFuture<void>::Return(const R& value) const {
+ auto promise = NewPromise<R>();
+ Subscribe([=](const TFuture<void>& future) mutable {
+ try {
+ future.TryRethrow();
+ } catch (...) {
+ promise.SetException(std::current_exception());
+ return;
+ }
+ promise.SetValue(value);
+ });
+ return promise;
+ }
+
+ inline bool TFuture<void>::Initialized() const {
+ return bool(State);
+ }
+
+ inline TMaybe<TFutureStateId> TFuture<void>::StateId() const noexcept {
+ return State != nullptr ? MakeMaybe<TFutureStateId>(*State) : Nothing();
+ }
+
+ inline void TFuture<void>::EnsureInitialized() const {
+ if (!State) {
+ ythrow TFutureException() << "state not initialized";
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <typename T>
+ inline TPromise<T>::TPromise(const TIntrusivePtr<TFutureState>& state) noexcept
+ : State(state)
+ {
+ }
+
+ template <typename T>
+ inline void TPromise<T>::Swap(TPromise<T>& other) {
+ State.Swap(other.State);
+ }
+
+ template <typename T>
+ inline const T& TPromise<T>::GetValue() const {
+ EnsureInitialized();
+ return State->GetValue();
+ }
+
+ template <typename T>
+ inline T TPromise<T>::ExtractValue() {
+ EnsureInitialized();
+ return State->ExtractValue();
+ }
+
+ template <typename T>
+ inline bool TPromise<T>::HasValue() const {
+ return State && State->HasValue();
+ }
+
+ template <typename T>
+ inline void TPromise<T>::SetValue(const T& value) {
+ EnsureInitialized();
+ State->SetValue(value);
+ }
+
+ template <typename T>
+ inline void TPromise<T>::SetValue(T&& value) {
+ EnsureInitialized();
+ State->SetValue(std::move(value));
+ }
+
+ template <typename T>
+ inline bool TPromise<T>::TrySetValue(const T& value) {
+ EnsureInitialized();
+ return State->TrySetValue(value);
+ }
+
+ template <typename T>
+ inline bool TPromise<T>::TrySetValue(T&& value) {
+ EnsureInitialized();
+ return State->TrySetValue(std::move(value));
+ }
+
+ template <typename T>
+ inline void TPromise<T>::TryRethrow() const {
+ if (State) {
+ State->TryRethrow();
+ }
+ }
+
+ template <typename T>
+ inline bool TPromise<T>::HasException() const {
+ return State && State->HasException();
+ }
+
+ template <typename T>
+ inline void TPromise<T>::SetException(const TString& e) {
+ EnsureInitialized();
+ State->SetException(std::make_exception_ptr(yexception() << e));
+ }
+
+ template <typename T>
+ inline void TPromise<T>::SetException(std::exception_ptr e) {
+ EnsureInitialized();
+ State->SetException(std::move(e));
+ }
+
+ template <typename T>
+ inline bool TPromise<T>::TrySetException(std::exception_ptr e) {
+ EnsureInitialized();
+ return State->TrySetException(std::move(e));
+ }
+
+ template <typename T>
+ inline TFuture<T> TPromise<T>::GetFuture() const {
+ EnsureInitialized();
+ return TFuture<T>(State);
+ }
+
+ template <typename T>
+ inline TPromise<T>::operator TFuture<T>() const {
+ return GetFuture();
+ }
+
+ template <typename T>
+ inline bool TPromise<T>::Initialized() const {
+ return bool(State);
+ }
+
+ template <typename T>
+ inline void TPromise<T>::EnsureInitialized() const {
+ if (!State) {
+ ythrow TFutureException() << "state not initialized";
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ inline TPromise<void>::TPromise(const TIntrusivePtr<TFutureState>& state) noexcept
+ : State(state)
+ {
+ }
+
+ inline void TPromise<void>::Swap(TPromise<void>& other) {
+ State.Swap(other.State);
+ }
+
+ inline void TPromise<void>::GetValue() const {
+ EnsureInitialized();
+ State->GetValue();
+ }
+
+ inline bool TPromise<void>::HasValue() const {
+ return State && State->HasValue();
+ }
+
+ inline void TPromise<void>::SetValue() {
+ EnsureInitialized();
+ State->SetValue();
+ }
+
+ inline bool TPromise<void>::TrySetValue() {
+ EnsureInitialized();
+ return State->TrySetValue();
+ }
+
+ inline void TPromise<void>::TryRethrow() const {
+ if(State) {
+ State->TryRethrow();
+ }
+ }
+
+ inline bool TPromise<void>::HasException() const {
+ return State && State->HasException();
+ }
+
+ inline void TPromise<void>::SetException(const TString& e) {
+ EnsureInitialized();
+ State->SetException(std::make_exception_ptr(yexception() << e));
+ }
+
+ inline void TPromise<void>::SetException(std::exception_ptr e) {
+ EnsureInitialized();
+ State->SetException(std::move(e));
+ }
+
+ inline bool TPromise<void>::TrySetException(std::exception_ptr e) {
+ EnsureInitialized();
+ return State->TrySetException(std::move(e));
+ }
+
+ inline TFuture<void> TPromise<void>::GetFuture() const {
+ EnsureInitialized();
+ return TFuture<void>(State);
+ }
+
+ inline TPromise<void>::operator TFuture<void>() const {
+ return GetFuture();
+ }
+
+ inline bool TPromise<void>::Initialized() const {
+ return bool(State);
+ }
+
+ inline void TPromise<void>::EnsureInitialized() const {
+ if (!State) {
+ ythrow TFutureException() << "state not initialized";
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <typename T>
+ inline TPromise<T> NewPromise() {
+ return {new NImpl::TFutureState<T>()};
+ }
+
+ inline TPromise<void> NewPromise() {
+ return {new NImpl::TFutureState<void>()};
+ }
+
+ template <typename T>
+ inline TFuture<T> MakeFuture(const T& value) {
+ return {new NImpl::TFutureState<T>(value)};
+ }
+
+ template <typename T>
+ inline TFuture<std::remove_reference_t<T>> MakeFuture(T&& value) {
+ return {new NImpl::TFutureState<std::remove_reference_t<T>>(std::forward<T>(value))};
+ }
+
+ template <typename T>
+ inline TFuture<T> MakeFuture() {
+ struct TCache {
+ TFuture<T> Instance{new NImpl::TFutureState<T>(Default<T>())};
+
+ TCache() {
+ // Immediately advance state from ValueSet to ValueRead.
+ // This should prevent corrupting shared value with an ExtractValue() call.
+ Y_UNUSED(Instance.GetValue());
+ }
+ };
+ return Singleton<TCache>()->Instance;
+ }
+
+ template <typename T>
+ inline TFuture<T> MakeErrorFuture(std::exception_ptr exception)
+ {
+ return {new NImpl::TFutureState<T>(std::move(exception), NImpl::TError::Error)};
+ }
+
+ inline TFuture<void> MakeFuture() {
+ struct TCache {
+ TFuture<void> Instance{new NImpl::TFutureState<void>(true)};
+ };
+ return Singleton<TCache>()->Instance;
+ }
+}
diff --git a/library/cpp/threading/future/core/future.cpp b/library/cpp/threading/future/core/future.cpp
new file mode 100644
index 0000000000..3243afcb40
--- /dev/null
+++ b/library/cpp/threading/future/core/future.cpp
@@ -0,0 +1 @@
+#include "future.h"
diff --git a/library/cpp/threading/future/core/future.h b/library/cpp/threading/future/core/future.h
new file mode 100644
index 0000000000..2e82bb953e
--- /dev/null
+++ b/library/cpp/threading/future/core/future.h
@@ -0,0 +1,272 @@
+#pragma once
+
+#include "fwd.h"
+
+#include <util/datetime/base.h>
+#include <util/generic/function.h>
+#include <util/generic/maybe.h>
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+#include <util/system/event.h>
+#include <util/system/spinlock.h>
+
+namespace NThreading {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct TFutureException: public yexception {};
+
+ // creates unset promise
+ template <typename T>
+ TPromise<T> NewPromise();
+ TPromise<void> NewPromise();
+
+ // creates preset future
+ template <typename T>
+ TFuture<T> MakeFuture(const T& value);
+ template <typename T>
+ TFuture<std::remove_reference_t<T>> MakeFuture(T&& value);
+ template <typename T>
+ TFuture<T> MakeFuture();
+ template <typename T>
+ TFuture<T> MakeErrorFuture(std::exception_ptr exception);
+ TFuture<void> MakeFuture();
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ namespace NImpl {
+ template <typename T>
+ class TFutureState;
+
+ template <typename T>
+ struct TFutureType {
+ using TType = T;
+ };
+
+ template <typename T>
+ struct TFutureType<TFuture<T>> {
+ using TType = typename TFutureType<T>::TType;
+ };
+
+ template <typename F, typename T>
+ struct TFutureCallResult {
+ // NOTE: separate class for msvc compatibility
+ using TType = decltype(std::declval<F&>()(std::declval<const TFuture<T>&>()));
+ };
+ }
+
+ template <typename F>
+ using TFutureType = typename NImpl::TFutureType<F>::TType;
+
+ template <typename F, typename T>
+ using TFutureCallResult = typename NImpl::TFutureCallResult<F, T>::TType;
+
+ //! Type of the future/promise state identifier
+ class TFutureStateId;
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <typename T>
+ class TFuture {
+ using TFutureState = NImpl::TFutureState<T>;
+
+ private:
+ TIntrusivePtr<TFutureState> State;
+
+ public:
+ using value_type = T;
+
+ TFuture() noexcept = default;
+ TFuture(const TFuture<T>& other) noexcept = default;
+ TFuture(TFuture<T>&& other) noexcept = default;
+ TFuture(const TIntrusivePtr<TFutureState>& state) noexcept;
+
+ TFuture<T>& operator=(const TFuture<T>& other) noexcept = default;
+ TFuture<T>& operator=(TFuture<T>&& other) noexcept = default;
+ void Swap(TFuture<T>& other);
+
+ bool Initialized() const;
+
+ bool HasValue() const;
+ const T& GetValue(TDuration timeout = TDuration::Zero()) const;
+ const T& GetValueSync() const;
+ T ExtractValue(TDuration timeout = TDuration::Zero());
+ T ExtractValueSync();
+
+ void TryRethrow() const;
+ bool HasException() const;
+
+ void Wait() const;
+ bool Wait(TDuration timeout) const;
+ bool Wait(TInstant deadline) const;
+
+ template <typename F>
+ const TFuture<T>& Subscribe(F&& callback) const;
+
+ // precondition: EnsureInitialized() passes
+ // postcondition: std::terminate is highly unlikely
+ template <typename F>
+ const TFuture<T>& NoexceptSubscribe(F&& callback) const noexcept;
+
+ template <typename F>
+ TFuture<TFutureType<TFutureCallResult<F, T>>> Apply(F&& func) const;
+
+ TFuture<void> IgnoreResult() const;
+
+ //! If the future is initialized returns the future state identifier. Otherwise returns an empty optional
+ /** The state identifier is guaranteed to be unique during the future state lifetime and could be reused after its death
+ **/
+ TMaybe<TFutureStateId> StateId() const noexcept;
+
+ void EnsureInitialized() const;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <>
+ class TFuture<void> {
+ using TFutureState = NImpl::TFutureState<void>;
+
+ private:
+ TIntrusivePtr<TFutureState> State = nullptr;
+
+ public:
+ using value_type = void;
+
+ TFuture() noexcept = default;
+ TFuture(const TFuture<void>& other) noexcept = default;
+ TFuture(TFuture<void>&& other) noexcept = default;
+ TFuture(const TIntrusivePtr<TFutureState>& state) noexcept;
+
+ TFuture<void>& operator=(const TFuture<void>& other) noexcept = default;
+ TFuture<void>& operator=(TFuture<void>&& other) noexcept = default;
+ void Swap(TFuture<void>& other);
+
+ bool Initialized() const;
+
+ bool HasValue() const;
+ void GetValue(TDuration timeout = TDuration::Zero()) const;
+ void GetValueSync() const;
+
+ void TryRethrow() const;
+ bool HasException() const;
+
+ void Wait() const;
+ bool Wait(TDuration timeout) const;
+ bool Wait(TInstant deadline) const;
+
+ template <typename F>
+ const TFuture<void>& Subscribe(F&& callback) const;
+
+ // precondition: EnsureInitialized() passes
+ // postcondition: std::terminate is highly unlikely
+ template <typename F>
+ const TFuture<void>& NoexceptSubscribe(F&& callback) const noexcept;
+
+ template <typename F>
+ TFuture<TFutureType<TFutureCallResult<F, void>>> Apply(F&& func) const;
+
+ template <typename R>
+ TFuture<R> Return(const R& value) const;
+
+ TFuture<void> IgnoreResult() const {
+ return *this;
+ }
+
+ //! If the future is initialized returns the future state identifier. Otherwise returns an empty optional
+ /** The state identifier is guaranteed to be unique during the future state lifetime and could be reused after its death
+ **/
+ TMaybe<TFutureStateId> StateId() const noexcept;
+
+ void EnsureInitialized() const;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <typename T>
+ class TPromise {
+ using TFutureState = NImpl::TFutureState<T>;
+
+ private:
+ TIntrusivePtr<TFutureState> State = nullptr;
+
+ public:
+ TPromise() noexcept = default;
+ TPromise(const TPromise<T>& other) noexcept = default;
+ TPromise(TPromise<T>&& other) noexcept = default;
+ TPromise(const TIntrusivePtr<TFutureState>& state) noexcept;
+
+ TPromise<T>& operator=(const TPromise<T>& other) noexcept = default;
+ TPromise<T>& operator=(TPromise<T>&& other) noexcept = default;
+ void Swap(TPromise<T>& other);
+
+ bool Initialized() const;
+
+ bool HasValue() const;
+ const T& GetValue() const;
+ T ExtractValue();
+
+ void SetValue(const T& value);
+ void SetValue(T&& value);
+
+ bool TrySetValue(const T& value);
+ bool TrySetValue(T&& value);
+
+ void TryRethrow() const;
+ bool HasException() const;
+ void SetException(const TString& e);
+ void SetException(std::exception_ptr e);
+ bool TrySetException(std::exception_ptr e);
+
+ TFuture<T> GetFuture() const;
+ operator TFuture<T>() const;
+
+ private:
+ void EnsureInitialized() const;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <>
+ class TPromise<void> {
+ using TFutureState = NImpl::TFutureState<void>;
+
+ private:
+ TIntrusivePtr<TFutureState> State;
+
+ public:
+ TPromise() noexcept = default;
+ TPromise(const TPromise<void>& other) noexcept = default;
+ TPromise(TPromise<void>&& other) noexcept = default;
+ TPromise(const TIntrusivePtr<TFutureState>& state) noexcept;
+
+ TPromise<void>& operator=(const TPromise<void>& other) noexcept = default;
+ TPromise<void>& operator=(TPromise<void>&& other) noexcept = default;
+ void Swap(TPromise<void>& other);
+
+ bool Initialized() const;
+
+ bool HasValue() const;
+ void GetValue() const;
+
+ void SetValue();
+ bool TrySetValue();
+
+ void TryRethrow() const;
+ bool HasException() const;
+ void SetException(const TString& e);
+ void SetException(std::exception_ptr e);
+ bool TrySetException(std::exception_ptr e);
+
+ TFuture<void> GetFuture() const;
+ operator TFuture<void>() const;
+
+ private:
+ void EnsureInitialized() const;
+ };
+
+}
+
+#define INCLUDE_FUTURE_INL_H
+#include "future-inl.h"
+#undef INCLUDE_FUTURE_INL_H
diff --git a/library/cpp/threading/future/core/fwd.cpp b/library/cpp/threading/future/core/fwd.cpp
new file mode 100644
index 0000000000..4214b6df83
--- /dev/null
+++ b/library/cpp/threading/future/core/fwd.cpp
@@ -0,0 +1 @@
+#include "fwd.h"
diff --git a/library/cpp/threading/future/core/fwd.h b/library/cpp/threading/future/core/fwd.h
new file mode 100644
index 0000000000..96eba9e6a3
--- /dev/null
+++ b/library/cpp/threading/future/core/fwd.h
@@ -0,0 +1,11 @@
+#pragma once
+
+namespace NThreading {
+ struct TFutureException;
+
+ template <typename T>
+ class TFuture;
+
+ template <typename T>
+ class TPromise;
+}
diff --git a/library/cpp/threading/future/future.h b/library/cpp/threading/future/future.h
new file mode 100644
index 0000000000..35db9abbe2
--- /dev/null
+++ b/library/cpp/threading/future/future.h
@@ -0,0 +1,4 @@
+#pragma once
+
+#include "core/future.h"
+#include "wait/wait.h"
diff --git a/library/cpp/threading/future/future_mt_ut.cpp b/library/cpp/threading/future/future_mt_ut.cpp
new file mode 100644
index 0000000000..4f390866c1
--- /dev/null
+++ b/library/cpp/threading/future/future_mt_ut.cpp
@@ -0,0 +1,215 @@
+#include "future.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/noncopyable.h>
+#include <util/generic/xrange.h>
+#include <util/thread/pool.h>
+
+#include <atomic>
+#include <exception>
+
+using NThreading::NewPromise;
+using NThreading::TFuture;
+using NThreading::TPromise;
+using NThreading::TWaitPolicy;
+
+namespace {
+ // Wait* implementation without optimizations, to test TWaitGroup better
+ template <class WaitPolicy, class TContainer>
+ TFuture<void> WaitNoOpt(const TContainer& futures) {
+ NThreading::TWaitGroup<WaitPolicy> wg;
+ for (const auto& fut : futures) {
+ wg.Add(fut);
+ }
+
+ return std::move(wg).Finish();
+ }
+
+ class TRelaxedBarrier {
+ public:
+ explicit TRelaxedBarrier(i64 size)
+ : Waiting_{size} {
+ }
+
+ void Arrive() {
+ // barrier is not for synchronization, just to ensure good timings, so
+ // std::memory_order_relaxed is enough
+ Waiting_.fetch_add(-1, std::memory_order_relaxed);
+
+ while (Waiting_.load(std::memory_order_relaxed)) {
+ }
+
+ Y_ASSERT(Waiting_.load(std::memory_order_relaxed) >= 0);
+ }
+
+ private:
+ std::atomic<i64> Waiting_;
+ };
+
+ THolder<TThreadPool> MakePool() {
+ auto pool = MakeHolder<TThreadPool>(TThreadPool::TParams{}.SetBlocking(false).SetCatching(false));
+ pool->Start(8);
+ return pool;
+ }
+
+ template <class T>
+ TVector<TFuture<T>> ToFutures(const TVector<TPromise<T>>& promises) {
+ TVector<TFuture<void>> futures;
+
+ for (auto&& p : promises) {
+ futures.emplace_back(p);
+ }
+
+ return futures;
+ }
+
+ struct TStateSnapshot {
+ i64 Started = -1;
+ i64 StartedException = -1;
+ const TVector<TFuture<void>>* Futures = nullptr;
+ };
+
+ // note: std::memory_order_relaxed should be enough everywhere, because TFuture::SetValue must provide the
+ // needed synchronization
+ template <class TFactory>
+ void RunWaitTest(TFactory global) {
+ auto pool = MakePool();
+
+ const auto exception = std::make_exception_ptr(42);
+
+ for (auto numPromises : xrange(1, 5)) {
+ for (auto loopIter : xrange(1024 * 64)) {
+ const auto numParticipants = numPromises + 1;
+
+ TRelaxedBarrier barrier{numParticipants};
+
+ std::atomic<i64> started = 0;
+ std::atomic<i64> startedException = 0;
+ std::atomic<i64> completed = 0;
+
+ TVector<TPromise<void>> promises;
+ for (auto i : xrange(numPromises)) {
+ Y_UNUSED(i);
+ promises.push_back(NewPromise());
+ }
+
+ const auto futures = ToFutures(promises);
+
+ auto snapshotter = [&] {
+ return TStateSnapshot{
+ .Started = started.load(std::memory_order_relaxed),
+ .StartedException = startedException.load(std::memory_order_relaxed),
+ .Futures = &futures,
+ };
+ };
+
+ for (auto i : xrange(numPromises)) {
+ pool->SafeAddFunc([&, i] {
+ barrier.Arrive();
+
+ // subscribers must observe effects of this operation
+ // after .Set*
+ started.fetch_add(1, std::memory_order_relaxed);
+
+ if ((loopIter % 4 == 0) && i == 0) {
+ startedException.fetch_add(1, std::memory_order_relaxed);
+ promises[i].SetException(exception);
+ } else {
+ promises[i].SetValue();
+ }
+
+ completed.fetch_add(1, std::memory_order_release);
+ });
+ }
+
+ pool->SafeAddFunc([&] {
+ auto local = global(snapshotter);
+
+ barrier.Arrive();
+
+ local();
+
+ completed.fetch_add(1, std::memory_order_release);
+ });
+
+ while (completed.load() != numParticipants) {
+ }
+ }
+ }
+ }
+}
+
+Y_UNIT_TEST_SUITE(TFutureMultiThreadedTest) {
+ Y_UNIT_TEST(WaitAll) {
+ RunWaitTest(
+ [](auto snapshotter) {
+ return [=]() {
+ auto* futures = snapshotter().Futures;
+
+ auto all = WaitNoOpt<TWaitPolicy::TAll>(*futures);
+
+ // tests safety part
+ all.Subscribe([=] (auto&& all) {
+ TStateSnapshot snap = snapshotter();
+
+ // value safety: all is set => every future is set
+ UNIT_ASSERT(all.HasValue() <= ((snap.Started == (i64)snap.Futures->size()) && !snap.StartedException));
+
+ // safety for hasException: all is set => every future is set and some has exception
+ UNIT_ASSERT(all.HasException() <= ((snap.Started == (i64)snap.Futures->size()) && snap.StartedException > 0));
+ });
+
+ // test liveness
+ all.Wait();
+ };
+ });
+ }
+
+ Y_UNIT_TEST(WaitAny) {
+ RunWaitTest(
+ [](auto snapshotter) {
+ return [=]() {
+ auto* futures = snapshotter().Futures;
+
+ auto any = WaitNoOpt<TWaitPolicy::TAny>(*futures);
+
+ // safety: any is ready => some f is ready
+ any.Subscribe([=](auto&&) {
+ UNIT_ASSERT(snapshotter().Started > 0);
+ });
+
+ // do we need better multithreaded liveness tests?
+ any.Wait();
+ };
+ });
+ }
+
+ Y_UNIT_TEST(WaitExceptionOrAll) {
+ RunWaitTest(
+ [](auto snapshotter) {
+ return [=]() {
+ NThreading::WaitExceptionOrAll(*snapshotter().Futures)
+ .Subscribe([=](auto&&) {
+ auto* futures = snapshotter().Futures;
+
+ auto exceptionOrAll = WaitNoOpt<TWaitPolicy::TExceptionOrAll>(*futures);
+
+ exceptionOrAll.Subscribe([snapshotter](auto&& exceptionOrAll) {
+ TStateSnapshot snap = snapshotter();
+
+ // safety for hasException: exceptionOrAll has exception => some has exception
+ UNIT_ASSERT(exceptionOrAll.HasException() ? snap.StartedException > 0 : true);
+
+ // value safety: exceptionOrAll has value => all have value
+ UNIT_ASSERT(exceptionOrAll.HasValue() == ((snap.Started == (i64)snap.Futures->size()) && !snap.StartedException));
+ });
+
+ // do we need better multithreaded liveness tests?
+ exceptionOrAll.Wait();
+ });
+ };
+ });
+ }
+}
+
diff --git a/library/cpp/threading/future/future_ut.cpp b/library/cpp/threading/future/future_ut.cpp
new file mode 100644
index 0000000000..05950a568d
--- /dev/null
+++ b/library/cpp/threading/future/future_ut.cpp
@@ -0,0 +1,640 @@
+#include "future.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <list>
+#include <type_traits>
+
+namespace NThreading {
+
+namespace {
+
+ class TCopyCounter {
+ public:
+ TCopyCounter(size_t* numCopies)
+ : NumCopies(numCopies)
+ {}
+
+ TCopyCounter(const TCopyCounter& that)
+ : NumCopies(that.NumCopies)
+ {
+ ++*NumCopies;
+ }
+
+ TCopyCounter& operator=(const TCopyCounter& that) {
+ NumCopies = that.NumCopies;
+ ++*NumCopies;
+ return *this;
+ }
+
+ TCopyCounter(TCopyCounter&& that) = default;
+
+ TCopyCounter& operator=(TCopyCounter&& that) = default;
+
+ private:
+ size_t* NumCopies = nullptr;
+ };
+
+ template <typename T>
+ auto MakePromise() {
+ if constexpr (std::is_same_v<T, void>) {
+ return NewPromise();
+ }
+ return NewPromise<T>();
+ }
+
+
+ template <typename T>
+ void TestFutureStateId() {
+ TFuture<T> empty;
+ UNIT_ASSERT(!empty.StateId().Defined());
+ auto promise1 = MakePromise<T>();
+ auto future11 = promise1.GetFuture();
+ UNIT_ASSERT(future11.StateId().Defined());
+ auto future12 = promise1.GetFuture();
+ UNIT_ASSERT_EQUAL(future11.StateId(), future11.StateId()); // same result for subsequent invocations
+ UNIT_ASSERT_EQUAL(future11.StateId(), future12.StateId()); // same result for different futures with the same state
+ auto promise2 = MakePromise<T>();
+ auto future2 = promise2.GetFuture();
+ UNIT_ASSERT(future2.StateId().Defined());
+ UNIT_ASSERT_UNEQUAL(future11.StateId(), future2.StateId()); // different results for futures with different states
+ }
+
+}
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ Y_UNIT_TEST_SUITE(TFutureTest) {
+ Y_UNIT_TEST(ShouldInitiallyHasNoValue) {
+ TPromise<int> promise;
+ UNIT_ASSERT(!promise.HasValue());
+
+ promise = NewPromise<int>();
+ UNIT_ASSERT(!promise.HasValue());
+
+ TFuture<int> future;
+ UNIT_ASSERT(!future.HasValue());
+
+ future = promise.GetFuture();
+ UNIT_ASSERT(!future.HasValue());
+ }
+
+ Y_UNIT_TEST(ShouldInitiallyHasNoValueVoid) {
+ TPromise<void> promise;
+ UNIT_ASSERT(!promise.HasValue());
+
+ promise = NewPromise();
+ UNIT_ASSERT(!promise.HasValue());
+
+ TFuture<void> future;
+ UNIT_ASSERT(!future.HasValue());
+
+ future = promise.GetFuture();
+ UNIT_ASSERT(!future.HasValue());
+ }
+
+ Y_UNIT_TEST(ShouldStoreValue) {
+ TPromise<int> promise = NewPromise<int>();
+ promise.SetValue(123);
+ UNIT_ASSERT(promise.HasValue());
+ UNIT_ASSERT_EQUAL(promise.GetValue(), 123);
+
+ TFuture<int> future = promise.GetFuture();
+ UNIT_ASSERT(future.HasValue());
+ UNIT_ASSERT_EQUAL(future.GetValue(), 123);
+
+ future = MakeFuture(345);
+ UNIT_ASSERT(future.HasValue());
+ UNIT_ASSERT_EQUAL(future.GetValue(), 345);
+ }
+
+ Y_UNIT_TEST(ShouldStoreValueVoid) {
+ TPromise<void> promise = NewPromise();
+ promise.SetValue();
+ UNIT_ASSERT(promise.HasValue());
+
+ TFuture<void> future = promise.GetFuture();
+ UNIT_ASSERT(future.HasValue());
+
+ future = MakeFuture();
+ UNIT_ASSERT(future.HasValue());
+ }
+
+ struct TTestCallback {
+ int Value;
+
+ TTestCallback(int value)
+ : Value(value)
+ {
+ }
+
+ void Callback(const TFuture<int>& future) {
+ Value += future.GetValue();
+ }
+
+ int Func(const TFuture<int>& future) {
+ return (Value += future.GetValue());
+ }
+
+ void VoidFunc(const TFuture<int>& future) {
+ future.GetValue();
+ }
+
+ TFuture<int> FutureFunc(const TFuture<int>& future) {
+ return MakeFuture(Value += future.GetValue());
+ }
+
+ TPromise<void> Signal = NewPromise();
+ TFuture<void> FutureVoidFunc(const TFuture<int>& future) {
+ future.GetValue();
+ return Signal;
+ }
+ };
+
+ Y_UNIT_TEST(ShouldInvokeCallback) {
+ TPromise<int> promise = NewPromise<int>();
+
+ TTestCallback callback(123);
+ TFuture<int> future = promise.GetFuture()
+ .Subscribe([&](const TFuture<int>& theFuture) { return callback.Callback(theFuture); });
+
+ promise.SetValue(456);
+ UNIT_ASSERT_EQUAL(future.GetValue(), 456);
+ UNIT_ASSERT_EQUAL(callback.Value, 123 + 456);
+ }
+
+ Y_UNIT_TEST(ShouldApplyFunc) {
+ TPromise<int> promise = NewPromise<int>();
+
+ TTestCallback callback(123);
+ TFuture<int> future = promise.GetFuture()
+ .Apply([&](const auto& theFuture) { return callback.Func(theFuture); });
+
+ promise.SetValue(456);
+ UNIT_ASSERT_EQUAL(future.GetValue(), 123 + 456);
+ UNIT_ASSERT_EQUAL(callback.Value, 123 + 456);
+ }
+
+ Y_UNIT_TEST(ShouldApplyVoidFunc) {
+ TPromise<int> promise = NewPromise<int>();
+
+ TTestCallback callback(123);
+ TFuture<void> future = promise.GetFuture()
+ .Apply([&](const auto& theFuture) { return callback.VoidFunc(theFuture); });
+
+ promise.SetValue(456);
+ UNIT_ASSERT(future.HasValue());
+ }
+
+ Y_UNIT_TEST(ShouldApplyFutureFunc) {
+ TPromise<int> promise = NewPromise<int>();
+
+ TTestCallback callback(123);
+ TFuture<int> future = promise.GetFuture()
+ .Apply([&](const auto& theFuture) { return callback.FutureFunc(theFuture); });
+
+ promise.SetValue(456);
+ UNIT_ASSERT_EQUAL(future.GetValue(), 123 + 456);
+ UNIT_ASSERT_EQUAL(callback.Value, 123 + 456);
+ }
+
+ Y_UNIT_TEST(ShouldApplyFutureVoidFunc) {
+ TPromise<int> promise = NewPromise<int>();
+
+ TTestCallback callback(123);
+ TFuture<void> future = promise.GetFuture()
+ .Apply([&](const auto& theFuture) { return callback.FutureVoidFunc(theFuture); });
+
+ promise.SetValue(456);
+ UNIT_ASSERT(!future.HasValue());
+
+ callback.Signal.SetValue();
+ UNIT_ASSERT(future.HasValue());
+ }
+
+ Y_UNIT_TEST(ShouldIgnoreResultIfAsked) {
+ TPromise<int> promise = NewPromise<int>();
+
+ TTestCallback callback(123);
+ TFuture<int> future = promise.GetFuture().IgnoreResult().Return(42);
+
+ promise.SetValue(456);
+ UNIT_ASSERT_EQUAL(future.GetValue(), 42);
+ }
+
+ class TCustomException: public yexception {
+ };
+
+ Y_UNIT_TEST(ShouldRethrowException) {
+ TPromise<int> promise = NewPromise<int>();
+ try {
+ ythrow TCustomException();
+ } catch (...) {
+ promise.SetException(std::current_exception());
+ }
+
+ UNIT_ASSERT(!promise.HasValue());
+ UNIT_ASSERT(promise.HasException());
+ UNIT_ASSERT_EXCEPTION(promise.GetValue(), TCustomException);
+ UNIT_ASSERT_EXCEPTION(promise.TryRethrow(), TCustomException);
+ }
+
+ Y_UNIT_TEST(ShouldRethrowCallbackException) {
+ TPromise<int> promise = NewPromise<int>();
+ TFuture<int> future = promise.GetFuture();
+ future.Subscribe([](const TFuture<int>&) {
+ throw TCustomException();
+ });
+
+ UNIT_ASSERT_EXCEPTION(promise.SetValue(123), TCustomException);
+ }
+
+ Y_UNIT_TEST(ShouldRethrowCallbackExceptionIgnoreResult) {
+ TPromise<int> promise = NewPromise<int>();
+ TFuture<void> future = promise.GetFuture().IgnoreResult();
+ future.Subscribe([](const TFuture<void>&) {
+ throw TCustomException();
+ });
+
+ UNIT_ASSERT_EXCEPTION(promise.SetValue(123), TCustomException);
+ }
+
+
+ Y_UNIT_TEST(ShouldWaitExceptionOrAll) {
+ TPromise<void> promise1 = NewPromise();
+ TPromise<void> promise2 = NewPromise();
+
+ TFuture<void> future = WaitExceptionOrAll(promise1, promise2);
+ UNIT_ASSERT(!future.HasValue());
+
+ promise1.SetValue();
+ UNIT_ASSERT(!future.HasValue());
+
+ promise2.SetValue();
+ UNIT_ASSERT(future.HasValue());
+ }
+
+ Y_UNIT_TEST(ShouldWaitExceptionOrAllVector) {
+ TPromise<void> promise1 = NewPromise();
+ TPromise<void> promise2 = NewPromise();
+
+ TVector<TFuture<void>> promises;
+ promises.push_back(promise1);
+ promises.push_back(promise2);
+
+ TFuture<void> future = WaitExceptionOrAll(promises);
+ UNIT_ASSERT(!future.HasValue());
+
+ promise1.SetValue();
+ UNIT_ASSERT(!future.HasValue());
+
+ promise2.SetValue();
+ UNIT_ASSERT(future.HasValue());
+ }
+
+ Y_UNIT_TEST(ShouldWaitExceptionOrAllVectorWithValueType) {
+ TPromise<int> promise1 = NewPromise<int>();
+ TPromise<int> promise2 = NewPromise<int>();
+
+ TVector<TFuture<int>> promises;
+ promises.push_back(promise1);
+ promises.push_back(promise2);
+
+ TFuture<void> future = WaitExceptionOrAll(promises);
+ UNIT_ASSERT(!future.HasValue());
+
+ promise1.SetValue(0);
+ UNIT_ASSERT(!future.HasValue());
+
+ promise2.SetValue(0);
+ UNIT_ASSERT(future.HasValue());
+ }
+
+ Y_UNIT_TEST(ShouldWaitExceptionOrAllList) {
+ TPromise<void> promise1 = NewPromise();
+ TPromise<void> promise2 = NewPromise();
+
+ std::list<TFuture<void>> promises;
+ promises.push_back(promise1);
+ promises.push_back(promise2);
+
+ TFuture<void> future = WaitExceptionOrAll(promises);
+ UNIT_ASSERT(!future.HasValue());
+
+ promise1.SetValue();
+ UNIT_ASSERT(!future.HasValue());
+
+ promise2.SetValue();
+ UNIT_ASSERT(future.HasValue());
+ }
+
+ Y_UNIT_TEST(ShouldWaitExceptionOrAllVectorEmpty) {
+ TVector<TFuture<void>> promises;
+
+ TFuture<void> future = WaitExceptionOrAll(promises);
+ UNIT_ASSERT(future.HasValue());
+ }
+
+ Y_UNIT_TEST(ShouldWaitAnyVector) {
+ TPromise<void> promise1 = NewPromise();
+ TPromise<void> promise2 = NewPromise();
+
+ TVector<TFuture<void>> promises;
+ promises.push_back(promise1);
+ promises.push_back(promise2);
+
+ TFuture<void> future = WaitAny(promises);
+ UNIT_ASSERT(!future.HasValue());
+
+ promise1.SetValue();
+ UNIT_ASSERT(future.HasValue());
+
+ promise2.SetValue();
+ UNIT_ASSERT(future.HasValue());
+ }
+
+
+ Y_UNIT_TEST(ShouldWaitAnyVectorWithValueType) {
+ TPromise<int> promise1 = NewPromise<int>();
+ TPromise<int> promise2 = NewPromise<int>();
+
+ TVector<TFuture<int>> promises;
+ promises.push_back(promise1);
+ promises.push_back(promise2);
+
+ TFuture<void> future = WaitAny(promises);
+ UNIT_ASSERT(!future.HasValue());
+
+ promise1.SetValue(0);
+ UNIT_ASSERT(future.HasValue());
+
+ promise2.SetValue(0);
+ UNIT_ASSERT(future.HasValue());
+ }
+
+ Y_UNIT_TEST(ShouldWaitAnyList) {
+ TPromise<void> promise1 = NewPromise();
+ TPromise<void> promise2 = NewPromise();
+
+ std::list<TFuture<void>> promises;
+ promises.push_back(promise1);
+ promises.push_back(promise2);
+
+ TFuture<void> future = WaitAny(promises);
+ UNIT_ASSERT(!future.HasValue());
+
+ promise1.SetValue();
+ UNIT_ASSERT(future.HasValue());
+
+ promise2.SetValue();
+ UNIT_ASSERT(future.HasValue());
+ }
+
+ Y_UNIT_TEST(ShouldWaitAnyVectorEmpty) {
+ TVector<TFuture<void>> promises;
+
+ TFuture<void> future = WaitAny(promises);
+ UNIT_ASSERT(future.HasValue());
+ }
+
+ Y_UNIT_TEST(ShouldWaitAny) {
+ TPromise<void> promise1 = NewPromise();
+ TPromise<void> promise2 = NewPromise();
+
+ TFuture<void> future = WaitAny(promise1, promise2);
+ UNIT_ASSERT(!future.HasValue());
+
+ promise1.SetValue();
+ UNIT_ASSERT(future.HasValue());
+
+ promise2.SetValue();
+ UNIT_ASSERT(future.HasValue());
+ }
+
+ Y_UNIT_TEST(ShouldStoreTypesWithoutDefaultConstructor) {
+ // compileability test
+ struct TRec {
+ explicit TRec(int) {
+ }
+ };
+
+ auto promise = NewPromise<TRec>();
+ promise.SetValue(TRec(1));
+
+ auto future = MakeFuture(TRec(1));
+ const auto& rec = future.GetValue();
+ Y_UNUSED(rec);
+ }
+
+ Y_UNIT_TEST(ShouldStoreMovableTypes) {
+ // compileability test
+ struct TRec : TMoveOnly {
+ explicit TRec(int) {
+ }
+ };
+
+ auto promise = NewPromise<TRec>();
+ promise.SetValue(TRec(1));
+
+ auto future = MakeFuture(TRec(1));
+ const auto& rec = future.GetValue();
+ Y_UNUSED(rec);
+ }
+
+ Y_UNIT_TEST(ShouldMoveMovableTypes) {
+ // compileability test
+ struct TRec : TMoveOnly {
+ explicit TRec(int) {
+ }
+ };
+
+ auto promise = NewPromise<TRec>();
+ promise.SetValue(TRec(1));
+
+ auto future = MakeFuture(TRec(1));
+ auto rec = future.ExtractValue();
+ Y_UNUSED(rec);
+ }
+
+ Y_UNIT_TEST(ShouldNotExtractAfterGet) {
+ TPromise<int> promise = NewPromise<int>();
+ promise.SetValue(123);
+ UNIT_ASSERT(promise.HasValue());
+ UNIT_ASSERT_EQUAL(promise.GetValue(), 123);
+ UNIT_CHECK_GENERATED_EXCEPTION(promise.ExtractValue(), TFutureException);
+ }
+
+ Y_UNIT_TEST(ShouldNotGetAfterExtract) {
+ TPromise<int> promise = NewPromise<int>();
+ promise.SetValue(123);
+ UNIT_ASSERT(promise.HasValue());
+ UNIT_ASSERT_EQUAL(promise.ExtractValue(), 123);
+ UNIT_CHECK_GENERATED_EXCEPTION(promise.GetValue(), TFutureException);
+ }
+
+ Y_UNIT_TEST(ShouldNotExtractAfterExtract) {
+ TPromise<int> promise = NewPromise<int>();
+ promise.SetValue(123);
+ UNIT_ASSERT(promise.HasValue());
+ UNIT_ASSERT_EQUAL(promise.ExtractValue(), 123);
+ UNIT_CHECK_GENERATED_EXCEPTION(promise.ExtractValue(), TFutureException);
+ }
+
+ Y_UNIT_TEST(ShouldNotExtractFromSharedDefault) {
+ UNIT_CHECK_GENERATED_EXCEPTION(MakeFuture<int>().ExtractValue(), TFutureException);
+
+ struct TStorage {
+ TString String = TString(100, 'a');
+ };
+ try {
+ TString s = MakeFuture<TStorage>().ExtractValue().String;
+ Y_UNUSED(s);
+ } catch (TFutureException) {
+ // pass
+ }
+ UNIT_ASSERT_VALUES_EQUAL(MakeFuture<TStorage>().GetValue().String, TString(100, 'a'));
+ }
+
+ Y_UNIT_TEST(HandlingRepetitiveSet) {
+ TPromise<int> promise = NewPromise<int>();
+ promise.SetValue(42);
+ UNIT_CHECK_GENERATED_EXCEPTION(promise.SetValue(42), TFutureException);
+ }
+
+ Y_UNIT_TEST(HandlingRepetitiveTrySet) {
+ TPromise<int> promise = NewPromise<int>();
+ UNIT_ASSERT(promise.TrySetValue(42));
+ UNIT_ASSERT(!promise.TrySetValue(42));
+ }
+
+ Y_UNIT_TEST(HandlingRepetitiveSetException) {
+ TPromise<int> promise = NewPromise<int>();
+ promise.SetException("test");
+ UNIT_CHECK_GENERATED_EXCEPTION(promise.SetException("test"), TFutureException);
+ }
+
+ Y_UNIT_TEST(HandlingRepetitiveTrySetException) {
+ TPromise<int> promise = NewPromise<int>();
+ UNIT_ASSERT(promise.TrySetException(std::make_exception_ptr("test")));
+ UNIT_ASSERT(!promise.TrySetException(std::make_exception_ptr("test")));
+ }
+
+ Y_UNIT_TEST(ShouldAllowToMakeFutureWithException)
+ {
+ auto future1 = MakeErrorFuture<void>(std::make_exception_ptr(TFutureException()));
+ UNIT_ASSERT(future1.HasException());
+ UNIT_CHECK_GENERATED_EXCEPTION(future1.GetValue(), TFutureException);
+
+ auto future2 = MakeErrorFuture<int>(std::make_exception_ptr(TFutureException()));
+ UNIT_ASSERT(future2.HasException());
+ UNIT_CHECK_GENERATED_EXCEPTION(future2.GetValue(), TFutureException);
+
+ auto future3 = MakeFuture<std::exception_ptr>(std::make_exception_ptr(TFutureException()));
+ UNIT_ASSERT(future3.HasValue());
+ UNIT_CHECK_GENERATED_NO_EXCEPTION(future3.GetValue(), TFutureException);
+
+ auto future4 = MakeFuture<std::unique_ptr<int>>(nullptr);
+ UNIT_ASSERT(future4.HasValue());
+ UNIT_CHECK_GENERATED_NO_EXCEPTION(future4.GetValue(), TFutureException);
+ }
+
+ Y_UNIT_TEST(WaitAllowsExtract) {
+ auto future = MakeFuture<int>(42);
+ TVector vec{future, future, future};
+ WaitExceptionOrAll(vec).GetValue();
+ WaitAny(vec).GetValue();
+
+ UNIT_ASSERT_EQUAL(future.ExtractValue(), 42);
+ }
+
+ Y_UNIT_TEST(IgnoreAllowsExtract) {
+ auto future = MakeFuture<int>(42);
+ future.IgnoreResult().GetValue();
+
+ UNIT_ASSERT_EQUAL(future.ExtractValue(), 42);
+ }
+
+ Y_UNIT_TEST(WaitExceptionOrAllException) {
+ auto promise1 = NewPromise();
+ auto promise2 = NewPromise();
+ auto future1 = promise1.GetFuture();
+ auto future2 = promise2.GetFuture();
+ auto wait = WaitExceptionOrAll(future1, future2);
+ promise2.SetException("foo-exception");
+ wait.Wait();
+ UNIT_ASSERT(future2.HasException());
+ UNIT_ASSERT(!future1.HasValue() && !future1.HasException());
+ }
+
+ Y_UNIT_TEST(WaitAllException) {
+ auto promise1 = NewPromise();
+ auto promise2 = NewPromise();
+ auto future1 = promise1.GetFuture();
+ auto future2 = promise2.GetFuture();
+ auto wait = WaitAll(future1, future2);
+ promise2.SetException("foo-exception");
+ UNIT_ASSERT(!wait.HasValue() && !wait.HasException());
+ promise1.SetValue();
+ UNIT_ASSERT_EXCEPTION_CONTAINS(wait.GetValueSync(), yexception, "foo-exception");
+ }
+
+ Y_UNIT_TEST(FutureStateId) {
+ TestFutureStateId<void>();
+ TestFutureStateId<int>();
+ }
+
+ template <typename T>
+ void TestApplyNoRvalueCopyImpl() {
+ size_t numCopies = 0;
+ TCopyCounter copyCounter(&numCopies);
+
+ auto promise = MakePromise<T>();
+
+ const auto future = promise.GetFuture().Apply(
+ [copyCounter = std::move(copyCounter)] (const auto&) {}
+ );
+
+ if constexpr (std::is_same_v<T, void>) {
+ promise.SetValue();
+ } else {
+ promise.SetValue(T());
+ }
+
+ future.GetValueSync();
+
+ UNIT_ASSERT_VALUES_EQUAL(numCopies, 0);
+ }
+
+ Y_UNIT_TEST(ApplyNoRvalueCopy) {
+ TestApplyNoRvalueCopyImpl<void>();
+ TestApplyNoRvalueCopyImpl<int>();
+ }
+
+ template <typename T>
+ void TestApplyLvalueCopyImpl() {
+ size_t numCopies = 0;
+ TCopyCounter copyCounter(&numCopies);
+
+ auto promise = MakePromise<T>();
+
+ auto func = [copyCounter = std::move(copyCounter)] (const auto&) {};
+ const auto future = promise.GetFuture().Apply(func);
+
+ if constexpr (std::is_same_v<T, void>) {
+ promise.SetValue();
+ } else {
+ promise.SetValue(T());
+ }
+
+ future.GetValueSync();
+
+ UNIT_ASSERT_VALUES_EQUAL(numCopies, 1);
+ }
+
+ Y_UNIT_TEST(ApplyLvalueCopy) {
+ TestApplyLvalueCopyImpl<void>();
+ TestApplyLvalueCopyImpl<int>();
+ }
+ }
+
+}
diff --git a/library/cpp/threading/future/fwd.cpp b/library/cpp/threading/future/fwd.cpp
new file mode 100644
index 0000000000..4214b6df83
--- /dev/null
+++ b/library/cpp/threading/future/fwd.cpp
@@ -0,0 +1 @@
+#include "fwd.h"
diff --git a/library/cpp/threading/future/fwd.h b/library/cpp/threading/future/fwd.h
new file mode 100644
index 0000000000..0cd25dd288
--- /dev/null
+++ b/library/cpp/threading/future/fwd.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "core/fwd.h"
+
+namespace NThreading {
+ template <typename TR = void, bool IgnoreException = false>
+ class TLegacyFuture;
+}
diff --git a/library/cpp/threading/future/legacy_future.h b/library/cpp/threading/future/legacy_future.h
new file mode 100644
index 0000000000..6f1eabad73
--- /dev/null
+++ b/library/cpp/threading/future/legacy_future.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#include "fwd.h"
+#include "future.h"
+
+#include <util/thread/factory.h>
+
+#include <functional>
+
+namespace NThreading {
+ template <typename TR, bool IgnoreException>
+ class TLegacyFuture: public IThreadFactory::IThreadAble, TNonCopyable {
+ public:
+ typedef TR(TFunctionSignature)();
+ using TFunctionObjectType = std::function<TFunctionSignature>;
+ using TResult = typename TFunctionObjectType::result_type;
+
+ private:
+ TFunctionObjectType Func_;
+ TPromise<TResult> Result_;
+ THolder<IThreadFactory::IThread> Thread_;
+
+ public:
+ inline TLegacyFuture(const TFunctionObjectType func, IThreadFactory* pool = SystemThreadFactory())
+ : Func_(func)
+ , Result_(NewPromise<TResult>())
+ , Thread_(pool->Run(this))
+ {
+ }
+
+ inline ~TLegacyFuture() override {
+ this->Join();
+ }
+
+ inline TResult Get() {
+ this->Join();
+ return Result_.GetValue();
+ }
+
+ private:
+ inline void Join() {
+ if (Thread_) {
+ Thread_->Join();
+ Thread_.Destroy();
+ }
+ }
+
+ template <typename Result, bool IgnoreException_>
+ struct TExecutor {
+ static void SetPromise(TPromise<Result>& promise, const TFunctionObjectType& func) {
+ if (IgnoreException_) {
+ try {
+ promise.SetValue(func());
+ } catch (...) {
+ }
+ } else {
+ promise.SetValue(func());
+ }
+ }
+ };
+
+ template <bool IgnoreException_>
+ struct TExecutor<void, IgnoreException_> {
+ static void SetPromise(TPromise<void>& promise, const TFunctionObjectType& func) {
+ if (IgnoreException_) {
+ try {
+ func();
+ promise.SetValue();
+ } catch (...) {
+ }
+ } else {
+ func();
+ promise.SetValue();
+ }
+ }
+ };
+
+ void DoExecute() override {
+ TExecutor<TResult, IgnoreException>::SetPromise(Result_, Func_);
+ }
+ };
+
+}
diff --git a/library/cpp/threading/future/legacy_future_ut.cpp b/library/cpp/threading/future/legacy_future_ut.cpp
new file mode 100644
index 0000000000..ff63db1725
--- /dev/null
+++ b/library/cpp/threading/future/legacy_future_ut.cpp
@@ -0,0 +1,73 @@
+#include "legacy_future.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+namespace NThreading {
+ Y_UNIT_TEST_SUITE(TLegacyFutureTest) {
+ int intf() {
+ return 17;
+ }
+
+ Y_UNIT_TEST(TestIntFunction) {
+ TLegacyFuture<int> f((&intf));
+ UNIT_ASSERT_VALUES_EQUAL(17, f.Get());
+ }
+
+ static int r;
+
+ void voidf() {
+ r = 18;
+ }
+
+ Y_UNIT_TEST(TestVoidFunction) {
+ r = 0;
+ TLegacyFuture<> f((&voidf));
+ f.Get();
+ UNIT_ASSERT_VALUES_EQUAL(18, r);
+ }
+
+ struct TSampleClass {
+ int mValue;
+
+ TSampleClass(int value)
+ : mValue(value)
+ {
+ }
+
+ int Calc() {
+ return mValue + 1;
+ }
+ };
+
+ Y_UNIT_TEST(TestMethod) {
+ TLegacyFuture<int> f11(std::bind(&TSampleClass::Calc, TSampleClass(3)));
+ UNIT_ASSERT_VALUES_EQUAL(4, f11.Get());
+
+ TLegacyFuture<int> f12(std::bind(&TSampleClass::Calc, TSampleClass(3)), SystemThreadFactory());
+ UNIT_ASSERT_VALUES_EQUAL(4, f12.Get());
+
+ TSampleClass c(5);
+
+ TLegacyFuture<int> f21(std::bind(&TSampleClass::Calc, std::ref(c)));
+ UNIT_ASSERT_VALUES_EQUAL(6, f21.Get());
+
+ TLegacyFuture<int> f22(std::bind(&TSampleClass::Calc, std::ref(c)), SystemThreadFactory());
+ UNIT_ASSERT_VALUES_EQUAL(6, f22.Get());
+ }
+
+ struct TSomeThreadPool: public IThreadFactory {};
+
+ Y_UNIT_TEST(TestFunction) {
+ std::function<int()> f((&intf));
+
+ UNIT_ASSERT_VALUES_EQUAL(17, TLegacyFuture<int>(f).Get());
+ UNIT_ASSERT_VALUES_EQUAL(17, TLegacyFuture<int>(f, SystemThreadFactory()).Get());
+
+ if (false) {
+ TSomeThreadPool* q = nullptr;
+ TLegacyFuture<int>(f, q); // just check compiles, do not start
+ }
+ }
+ }
+
+}
diff --git a/library/cpp/threading/future/mt_ut/ya.make b/library/cpp/threading/future/mt_ut/ya.make
new file mode 100644
index 0000000000..288fe7b6bc
--- /dev/null
+++ b/library/cpp/threading/future/mt_ut/ya.make
@@ -0,0 +1,20 @@
+UNITTEST_FOR(library/cpp/threading/future)
+
+OWNER(
+ g:util
+)
+
+SRCS(
+ future_mt_ut.cpp
+)
+
+IF(NOT SANITIZER_TYPE)
+SIZE(SMALL)
+
+ELSE()
+SIZE(MEDIUM)
+
+ENDIF()
+
+
+END()
diff --git a/library/cpp/threading/future/perf/main.cpp b/library/cpp/threading/future/perf/main.cpp
new file mode 100644
index 0000000000..5a0690af47
--- /dev/null
+++ b/library/cpp/threading/future/perf/main.cpp
@@ -0,0 +1,50 @@
+#include <library/cpp/testing/benchmark/bench.h>
+#include <library/cpp/threading/future/future.h>
+
+#include <util/generic/string.h>
+#include <util/generic/xrange.h>
+
+using namespace NThreading;
+
+template <typename T>
+void TestAllocPromise(const NBench::NCpu::TParams& iface) {
+ for (const auto it : xrange(iface.Iterations())) {
+ Y_UNUSED(it);
+ Y_DO_NOT_OPTIMIZE_AWAY(NewPromise<T>());
+ }
+}
+
+template <typename T>
+TPromise<T> SetPromise(T value) {
+ auto promise = NewPromise<T>();
+ promise.SetValue(value);
+ return promise;
+}
+
+template <typename T>
+void TestSetPromise(const NBench::NCpu::TParams& iface, T value) {
+ for (const auto it : xrange(iface.Iterations())) {
+ Y_UNUSED(it);
+ Y_DO_NOT_OPTIMIZE_AWAY(SetPromise(value));
+ }
+}
+
+Y_CPU_BENCHMARK(AllocPromiseVoid, iface) {
+ TestAllocPromise<void>(iface);
+}
+
+Y_CPU_BENCHMARK(AllocPromiseUI64, iface) {
+ TestAllocPromise<ui64>(iface);
+}
+
+Y_CPU_BENCHMARK(AllocPromiseStroka, iface) {
+ TestAllocPromise<TString>(iface);
+}
+
+Y_CPU_BENCHMARK(SetPromiseUI64, iface) {
+ TestSetPromise<ui64>(iface, 1234567890ull);
+}
+
+Y_CPU_BENCHMARK(SetPromiseStroka, iface) {
+ TestSetPromise<TString>(iface, "test test test");
+}
diff --git a/library/cpp/threading/future/perf/ya.make b/library/cpp/threading/future/perf/ya.make
new file mode 100644
index 0000000000..943d585d4b
--- /dev/null
+++ b/library/cpp/threading/future/perf/ya.make
@@ -0,0 +1,16 @@
+Y_BENCHMARK(library-threading-future-perf)
+
+OWNER(
+ g:rtmr
+ ishfb
+)
+
+SRCS(
+ main.cpp
+)
+
+PEERDIR(
+ library/cpp/threading/future
+)
+
+END()
diff --git a/library/cpp/threading/future/subscription/README.md b/library/cpp/threading/future/subscription/README.md
new file mode 100644
index 0000000000..62c7e1303e
--- /dev/null
+++ b/library/cpp/threading/future/subscription/README.md
@@ -0,0 +1,104 @@
+Subscriptions manager and wait primitives library
+=================================================
+
+Wait primitives
+---------------
+
+All wait primitives are futures those being signaled when some or all of theirs dependencies are signaled.
+Wait privimitives could be constructed either from an initializer_list or from a standard container of futures.
+
+1. WaitAll is signaled when all its dependencies are signaled:
+
+ ```C++
+ #include <library/cpp/threading/subscriptions/wait_all.h>
+
+ auto w = NWait::WaitAll({ future1, future2, ..., futureN });
+ ...
+ w.Wait(); // wait for all futures
+ ```
+
+2. WaitAny is signaled when any of its dependencies is signaled:
+
+ ```C++
+ #include <library/cpp/threading/subscriptions/wait_any.h>
+
+ auto w = NWait::WaitAny(TVector<TFuture<T>>{ future1, future2, ..., futureN });
+ ...
+ w.Wait(); // wait for any future
+ ```
+
+3. WaitAllOrException is signaled when all its dependencies are signaled with values or any dependency is signaled with an exception:
+
+ ```C++
+ #include <library/cpp/threading/subscriptions/wait_all_or_exception.h>
+
+ auto w = NWait::WaitAllOrException(TVector<TFuture<T>>{ future1, future2, ..., futureN });
+ ...
+ w.Wait(); // wait for all values or for an exception
+ ```
+
+Subscriptions manager
+---------------------
+
+The subscription manager can manage multiple links beetween futures and callbacks. Multiple managed subscriptions to a single future shares just a single underlying subscription to the future. That allows dynamic creation and deletion of subscriptions and efficient implementation of different wait primitives.
+The subscription manager could be used in the following way:
+
+1. Subscribe to a single future:
+
+ ```C++
+ #include <library/cpp/threading/subscriptions/subscription.h>
+
+ TFuture<int> LongOperation();
+
+ ...
+ auto future = LongRunnigOperation();
+ auto m = MakeSubsriptionManager<int>();
+ auto id = m->Subscribe(future, [](TFuture<int> const& f) {
+ try {
+ auto value = f.GetValue();
+ ...
+ } catch (...) {
+ ... // handle exception
+ }
+ });
+ if (id.has_value()) {
+ ... // Callback will run asynchronously
+ } else {
+ ... // Future has been signaled already. The callback has been invoked synchronously
+ }
+ ```
+
+ Note that a callback could be invoked synchronously during a Subscribe call. In this case the returned optional will have no value.
+
+2. Unsubscribe from a single future:
+
+ ```C++
+ // id holds the subscription id from a previous Subscribe call
+ m->Unsubscribe(id.value());
+ ```
+
+ There is no need to call Unsubscribe if the callback has been called. In this case Unsubscribe will do nothing. And it is safe to call Unsubscribe with the same id multiple times.
+
+3. Subscribe a single callback to multiple futures:
+
+ ```C++
+ auto ids = m->Subscribe({ future1, future2, ..., futureN }, [](auto&& f) { ... });
+ ...
+ ```
+
+ Futures could be passed to Subscribe method either via an initializer_list or via a standard container like vector or list. Subscribe method accept an optional boolean parameter revertOnSignaled. If the parameter is false (default) then all suscriptions will be performed regardless of the futures states and the returned vector will have a subscription id for each future (even if callback has been executed synchronously for some futures). Otherwise the method will stop on the first signaled future (the callback will be synchronously called for it), no suscriptions will be created and an empty vector will be returned.
+
+4. Unsubscribe multiple subscriptions:
+
+ ```C++
+ // ids is the vector or subscription ids
+ m->Unsubscribe(ids);
+ ```
+
+ The vector of IDs could be a result of a previous Subscribe call or an arbitrary set of IDs of previously created subscriptions.
+
+5. If you do not want to instantiate a new instance of the subscription manager it is possible to use the default instance:
+
+ ```C++
+ auto m = TSubscriptionManager<T>::Default();
+ ```
diff --git a/library/cpp/threading/future/subscription/subscription-inl.h b/library/cpp/threading/future/subscription/subscription-inl.h
new file mode 100644
index 0000000000..a45d8999d3
--- /dev/null
+++ b/library/cpp/threading/future/subscription/subscription-inl.h
@@ -0,0 +1,118 @@
+#pragma once
+
+#if !defined(INCLUDE_LIBRARY_THREADING_FUTURE_SUBSCRIPTION_INL_H)
+#error "you should never include subscription-inl.h directly"
+#endif
+
+namespace NThreading {
+
+namespace NPrivate {
+
+template <typename T>
+TFutureStateId CheckedStateId(TFuture<T> const& future) {
+ auto const id = future.StateId();
+ if (id.Defined()) {
+ return *id;
+ }
+ ythrow TFutureException() << "Future state should be initialized";
+}
+
+}
+
+template <typename T, typename F, typename TCallbackExecutor>
+inline TSubscriptionManager::TSubscription::TSubscription(TFuture<T> future, F&& callback, TCallbackExecutor&& executor)
+ : Callback(
+ [future = std::move(future), callback = std::forward<F>(callback), executor = std::forward<TCallbackExecutor>(executor)]() mutable {
+ executor(std::as_const(future), callback);
+ })
+{
+}
+
+template <typename T, typename F, typename TCallbackExecutor>
+inline std::optional<TSubscriptionId> TSubscriptionManager::Subscribe(TFuture<T> const& future, F&& callback, TCallbackExecutor&& executor) {
+ auto stateId = NPrivate::CheckedStateId(future);
+ with_lock(Lock) {
+ auto const status = TrySubscribe(future, std::forward<F>(callback), stateId, std::forward<TCallbackExecutor>(executor));
+ switch (status) {
+ case ECallbackStatus::Subscribed:
+ return TSubscriptionId(stateId, Revision);
+ case ECallbackStatus::ExecutedSynchronously:
+ return {};
+ default:
+ Y_FAIL("Unexpected callback status");
+ }
+ }
+}
+
+template <typename TFutures, typename F, typename TCallbackExecutor>
+inline TVector<TSubscriptionId> TSubscriptionManager::Subscribe(TFutures const& futures, F&& callback, bool revertOnSignaled
+ , TCallbackExecutor&& executor)
+{
+ return SubscribeImpl(futures, std::forward<F>(callback), revertOnSignaled, std::forward<TCallbackExecutor>(executor));
+}
+
+template <typename T, typename F, typename TCallbackExecutor>
+inline TVector<TSubscriptionId> TSubscriptionManager::Subscribe(std::initializer_list<TFuture<T> const> futures, F&& callback
+ , bool revertOnSignaled, TCallbackExecutor&& executor)
+{
+ return SubscribeImpl(futures, std::forward<F>(callback), revertOnSignaled, std::forward<TCallbackExecutor>(executor));
+}
+
+template <typename T, typename F, typename TCallbackExecutor>
+inline TSubscriptionManager::ECallbackStatus TSubscriptionManager::TrySubscribe(TFuture<T> const& future, F&& callback, TFutureStateId stateId
+ , TCallbackExecutor&& executor)
+{
+ TSubscription subscription(future, std::forward<F>(callback), std::forward<TCallbackExecutor>(executor));
+ auto const it = Subscriptions.find(stateId);
+ auto const revision = ++Revision;
+ if (it == std::end(Subscriptions)) {
+ auto const success = Subscriptions.emplace(stateId, THashMap<ui64, TSubscription>{ { revision, std::move(subscription) } }).second;
+ Y_VERIFY(success);
+ auto self = TSubscriptionManagerPtr(this);
+ future.Subscribe([self, stateId](TFuture<T> const&) { self->OnCallback(stateId); });
+ if (Subscriptions.find(stateId) == std::end(Subscriptions)) {
+ return ECallbackStatus::ExecutedSynchronously;
+ }
+ } else {
+ Y_VERIFY(it->second.emplace(revision, std::move(subscription)).second);
+ }
+ return ECallbackStatus::Subscribed;
+}
+
+template <typename TFutures, typename F, typename TCallbackExecutor>
+inline TVector<TSubscriptionId> TSubscriptionManager::SubscribeImpl(TFutures const& futures, F const& callback, bool revertOnSignaled
+ , TCallbackExecutor const& executor)
+{
+ TVector<TSubscriptionId> results;
+ results.reserve(std::size(futures));
+ // resolve all state ids to minimize processing under the lock
+ for (auto const& f : futures) {
+ results.push_back(TSubscriptionId(NPrivate::CheckedStateId(f), 0));
+ }
+ with_lock(Lock) {
+ size_t i = 0;
+ for (auto const& f : futures) {
+ auto& r = results[i];
+ auto const status = TrySubscribe(f, callback, r.StateId(), executor);
+ switch (status) {
+ case ECallbackStatus::Subscribed:
+ break;
+ case ECallbackStatus::ExecutedSynchronously:
+ if (revertOnSignaled) {
+ // revert
+ results.crop(i);
+ UnsubscribeImpl(results);
+ return {};
+ }
+ break;
+ default:
+ Y_FAIL("Unexpected callback status");
+ }
+ r.SetSubId(Revision);
+ ++i;
+ }
+ }
+ return results;
+}
+
+}
diff --git a/library/cpp/threading/future/subscription/subscription.cpp b/library/cpp/threading/future/subscription/subscription.cpp
new file mode 100644
index 0000000000..a98b4a4f03
--- /dev/null
+++ b/library/cpp/threading/future/subscription/subscription.cpp
@@ -0,0 +1,65 @@
+#include "subscription.h"
+
+namespace NThreading {
+
+bool operator==(TSubscriptionId const& l, TSubscriptionId const& r) noexcept {
+ return l.StateId() == r.StateId() && l.SubId() == r.SubId();
+}
+
+bool operator!=(TSubscriptionId const& l, TSubscriptionId const& r) noexcept {
+ return !(l == r);
+}
+
+void TSubscriptionManager::TSubscription::operator()() {
+ Callback();
+}
+
+TSubscriptionManagerPtr TSubscriptionManager::NewInstance() {
+ return new TSubscriptionManager();
+}
+
+TSubscriptionManagerPtr TSubscriptionManager::Default() {
+ static auto instance = NewInstance();
+ return instance;
+}
+
+void TSubscriptionManager::Unsubscribe(TSubscriptionId id) {
+ with_lock(Lock) {
+ UnsubscribeImpl(id);
+ }
+}
+
+void TSubscriptionManager::Unsubscribe(TVector<TSubscriptionId> const& ids) {
+ with_lock(Lock) {
+ UnsubscribeImpl(ids);
+ }
+}
+
+void TSubscriptionManager::OnCallback(TFutureStateId stateId) noexcept {
+ THashMap<ui64, TSubscription> subscriptions;
+ with_lock(Lock) {
+ auto const it = Subscriptions.find(stateId);
+ Y_VERIFY(it != Subscriptions.end(), "The callback has been triggered more than once");
+ subscriptions.swap(it->second);
+ Subscriptions.erase(it);
+ }
+ for (auto& [_, subscription] : subscriptions) {
+ subscription();
+ }
+}
+
+void TSubscriptionManager::UnsubscribeImpl(TSubscriptionId id) {
+ auto const it = Subscriptions.find(id.StateId());
+ if (it == std::end(Subscriptions)) {
+ return;
+ }
+ it->second.erase(id.SubId());
+}
+
+void TSubscriptionManager::UnsubscribeImpl(TVector<TSubscriptionId> const& ids) {
+ for (auto const& id : ids) {
+ UnsubscribeImpl(id);
+ }
+}
+
+}
diff --git a/library/cpp/threading/future/subscription/subscription.h b/library/cpp/threading/future/subscription/subscription.h
new file mode 100644
index 0000000000..afe5eda711
--- /dev/null
+++ b/library/cpp/threading/future/subscription/subscription.h
@@ -0,0 +1,186 @@
+#pragma once
+
+#include <library/cpp/threading/future/future.h>
+
+#include <util/generic/hash.h>
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+#include <util/system/mutex.h>
+
+#include <functional>
+#include <optional>
+#include <utility>
+
+namespace NThreading {
+
+namespace NPrivate {
+
+struct TNoexceptExecutor {
+ template <typename T, typename F>
+ void operator()(TFuture<T> const& future, F&& callee) const noexcept {
+ return callee(future);
+ }
+};
+
+}
+
+class TSubscriptionManager;
+
+using TSubscriptionManagerPtr = TIntrusivePtr<TSubscriptionManager>;
+
+//! A subscription id
+class TSubscriptionId {
+private:
+ TFutureStateId StateId_;
+ ui64 SubId_; // Secondary id to make the whole subscription id unique
+
+ friend class TSubscriptionManager;
+
+public:
+ TFutureStateId StateId() const noexcept {
+ return StateId_;
+ }
+
+ ui64 SubId() const noexcept {
+ return SubId_;
+ }
+
+private:
+ TSubscriptionId(TFutureStateId stateId, ui64 subId)
+ : StateId_(stateId)
+ , SubId_(subId)
+ {
+ }
+
+ void SetSubId(ui64 subId) noexcept {
+ SubId_ = subId;
+ }
+};
+
+bool operator==(TSubscriptionId const& l, TSubscriptionId const& r) noexcept;
+bool operator!=(TSubscriptionId const& l, TSubscriptionId const& r) noexcept;
+
+//! The subscription manager manages subscriptions to futures
+/** It provides an ability to create (and drop) multiple subscriptions to any future
+ with just a single underlying subscription per future.
+
+ When a future is signaled all its subscriptions are removed.
+ So, there no need to call Unsubscribe for subscriptions to already signaled futures.
+
+ Warning!!! For correct operation this class imposes the following requirement to futures/promises:
+ Any used future must be signaled (value or exception set) before the future state destruction.
+ Otherwise subscriptions and futures may happen.
+ Current future design does not provide the required guarantee. But that should be fixed soon.
+**/
+class TSubscriptionManager final : public TAtomicRefCount<TSubscriptionManager> {
+private:
+ //! A single subscription
+ class TSubscription {
+ private:
+ std::function<void()> Callback;
+
+ public:
+ template <typename T, typename F, typename TCallbackExecutor>
+ TSubscription(TFuture<T> future, F&& callback, TCallbackExecutor&& executor);
+
+ void operator()();
+ };
+
+ struct TFutureStateIdHash {
+ size_t operator()(TFutureStateId const id) const noexcept {
+ auto const value = id.Value();
+ return ::hash<decltype(value)>()(value);
+ }
+ };
+
+private:
+ THashMap<TFutureStateId, THashMap<ui64, TSubscription>, TFutureStateIdHash> Subscriptions;
+ ui64 Revision = 0;
+ TMutex Lock;
+
+public:
+ //! Creates a new subscription manager instance
+ static TSubscriptionManagerPtr NewInstance();
+
+ //! The default subscription manager instance
+ static TSubscriptionManagerPtr Default();
+
+ //! Attempts to subscribe the callback to the future
+ /** Subscription should succeed if the future is not signaled yet.
+ Otherwise the callback will be called synchronously and nullopt will be returned
+
+ @param future - The future to subscribe to
+ @param callback - The callback to attach
+ @return The subscription id on success, nullopt if the future has been signaled already
+ **/
+ template <typename T, typename F, typename TCallbackExecutor = NPrivate::TNoexceptExecutor>
+ std::optional<TSubscriptionId> Subscribe(TFuture<T> const& future, F&& callback
+ , TCallbackExecutor&& executor = NPrivate::TNoexceptExecutor());
+
+ //! Drops the subscription with the given id
+ /** @param id - The subscription id
+ **/
+ void Unsubscribe(TSubscriptionId id);
+
+ //! Attempts to subscribe the callback to the set of futures
+ /** @param futures - The futures to subscribe to
+ @param callback - The callback to attach
+ @param revertOnSignaled - Shows whether to stop and revert the subscription process if one of the futures is in signaled state
+ @return The vector of subscription ids if no revert happened or an empty vector otherwise
+ A subscription id will be valid even if a corresponding future has been signaled
+ **/
+ template <typename TFutures, typename F, typename TCallbackExecutor = NPrivate::TNoexceptExecutor>
+ TVector<TSubscriptionId> Subscribe(TFutures const& futures, F&& callback, bool revertOnSignaled = false
+ , TCallbackExecutor&& executor = NPrivate::TNoexceptExecutor());
+
+ //! Attempts to subscribe the callback to the set of futures
+ /** @param futures - The futures to subscribe to
+ @param callback - The callback to attach
+ @param revertOnSignaled - Shows whether to stop and revert the subscription process if one of the futures is in signaled state
+ @return The vector of subscription ids if no revert happened or an empty vector otherwise
+ A subscription id will be valid even if a corresponding future has been signaled
+ **/
+ template <typename T, typename F, typename TCallbackExecutor = NPrivate::TNoexceptExecutor>
+ TVector<TSubscriptionId> Subscribe(std::initializer_list<TFuture<T> const> futures, F&& callback, bool revertOnSignaled = false
+ , TCallbackExecutor&& executor = NPrivate::TNoexceptExecutor());
+
+ //! Drops the subscriptions with the given ids
+ /** @param ids - The subscription ids
+ **/
+ void Unsubscribe(TVector<TSubscriptionId> const& ids);
+
+private:
+ enum class ECallbackStatus {
+ Subscribed, //! A subscription has been created. The callback will be called asynchronously.
+ ExecutedSynchronously //! A callback has been called synchronously. No subscription has been created
+ };
+
+private:
+ //! .ctor
+ TSubscriptionManager() = default;
+ //! Processes a callback from a future
+ void OnCallback(TFutureStateId stateId) noexcept;
+ //! Attempts to create a subscription
+ /** This method should be called under the lock
+ **/
+ template <typename T, typename F, typename TCallbackExecutor>
+ ECallbackStatus TrySubscribe(TFuture<T> const& future, F&& callback, TFutureStateId stateId, TCallbackExecutor&& executor);
+ //! Batch subscribe implementation
+ template <typename TFutures, typename F, typename TCallbackExecutor>
+ TVector<TSubscriptionId> SubscribeImpl(TFutures const& futures, F const& callback, bool revertOnSignaled
+ , TCallbackExecutor const& executor);
+ //! Unsubscribe implementation
+ /** This method should be called under the lock
+ **/
+ void UnsubscribeImpl(TSubscriptionId id);
+ //! Batch unsubscribe implementation
+ /** This method should be called under the lock
+ **/
+ void UnsubscribeImpl(TVector<TSubscriptionId> const& ids);
+};
+
+}
+
+#define INCLUDE_LIBRARY_THREADING_FUTURE_SUBSCRIPTION_INL_H
+#include "subscription-inl.h"
+#undef INCLUDE_LIBRARY_THREADING_FUTURE_SUBSCRIPTION_INL_H
diff --git a/library/cpp/threading/future/subscription/subscription_ut.cpp b/library/cpp/threading/future/subscription/subscription_ut.cpp
new file mode 100644
index 0000000000..d018ea15cc
--- /dev/null
+++ b/library/cpp/threading/future/subscription/subscription_ut.cpp
@@ -0,0 +1,432 @@
+#include "subscription.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NThreading;
+
+Y_UNIT_TEST_SUITE(TSubscriptionManagerTest) {
+
+ Y_UNIT_TEST(TestSubscribeUnsignaled) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto p = NewPromise();
+
+ size_t callCount = 0;
+ auto id = m->Subscribe(p.GetFuture(), [&callCount](auto&&) { ++callCount; } );
+ UNIT_ASSERT(id.has_value());
+ UNIT_ASSERT_EQUAL(callCount, 0);
+
+ p.SetValue();
+ UNIT_ASSERT_EQUAL(callCount, 1);
+ }
+
+ Y_UNIT_TEST(TestSubscribeSignaled) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto f = MakeFuture();
+
+ size_t callCount = 0;
+ auto id = m->Subscribe(f, [&callCount](auto&&) { ++callCount; } );
+ UNIT_ASSERT(!id.has_value());
+ UNIT_ASSERT_EQUAL(callCount, 1);
+ }
+
+ Y_UNIT_TEST(TestSubscribeUnsignaledAndSignaled) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto p = NewPromise();
+
+ size_t callCount1 = 0;
+ auto id1 = m->Subscribe(p.GetFuture(), [&callCount1](auto&&) { ++callCount1; } );
+ UNIT_ASSERT(id1.has_value());
+ UNIT_ASSERT_EQUAL(callCount1, 0);
+
+ p.SetValue();
+ UNIT_ASSERT_EQUAL(callCount1, 1);
+
+ size_t callCount2 = 0;
+ auto id2 = m->Subscribe(p.GetFuture(), [&callCount2](auto&&) { ++callCount2; } );
+ UNIT_ASSERT(!id2.has_value());
+ UNIT_ASSERT_EQUAL(callCount2, 1);
+ UNIT_ASSERT_EQUAL(callCount1, 1);
+ }
+
+ Y_UNIT_TEST(TestSubscribeUnsubscribeUnsignaled) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto p = NewPromise();
+
+ size_t callCount = 0;
+ auto id = m->Subscribe(p.GetFuture(), [&callCount](auto&&) { ++callCount; } );
+ UNIT_ASSERT(id.has_value());
+ UNIT_ASSERT_EQUAL(callCount, 0);
+
+ m->Unsubscribe(id.value());
+
+ p.SetValue();
+ UNIT_ASSERT_EQUAL(callCount, 0);
+ }
+
+ Y_UNIT_TEST(TestSubscribeUnsignaledUnsubscribeSignaled) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto p = NewPromise();
+
+ size_t callCount = 0;
+ auto id = m->Subscribe(p.GetFuture(), [&callCount](auto&&) { ++callCount; } );
+ UNIT_ASSERT(id.has_value());
+ UNIT_ASSERT_EQUAL(callCount, 0);
+
+ p.SetValue();
+ UNIT_ASSERT_EQUAL(callCount, 1);
+
+ m->Unsubscribe(id.value());
+ UNIT_ASSERT_EQUAL(callCount, 1);
+ }
+
+ Y_UNIT_TEST(TestUnsubscribeTwice) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto p = NewPromise();
+
+ size_t callCount = 0;
+ auto id = m->Subscribe(p.GetFuture(), [&callCount](auto&&) { ++callCount; } );
+ UNIT_ASSERT(id.has_value());
+ UNIT_ASSERT_EQUAL(callCount, 0);
+
+ m->Unsubscribe(id.value());
+ UNIT_ASSERT_EQUAL(callCount, 0);
+ m->Unsubscribe(id.value());
+ UNIT_ASSERT_EQUAL(callCount, 0);
+
+ p.SetValue();
+ UNIT_ASSERT_EQUAL(callCount, 0);
+ }
+
+ Y_UNIT_TEST(TestSubscribeOneUnsignaledManyTimes) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto p = NewPromise();
+
+ size_t callCount1 = 0;
+ auto id1 = m->Subscribe(p.GetFuture(), [&callCount1](auto&&) { ++callCount1; } );
+ size_t callCount2 = 0;
+ auto id2 = m->Subscribe(p.GetFuture(), [&callCount2](auto&&) { ++callCount2; } );
+ size_t callCount3 = 0;
+ auto id3 = m->Subscribe(p.GetFuture(), [&callCount3](auto&&) { ++callCount3; } );
+
+ UNIT_ASSERT(id1.has_value());
+ UNIT_ASSERT(id2.has_value());
+ UNIT_ASSERT(id3.has_value());
+ UNIT_ASSERT_UNEQUAL(id1.value(), id2.value());
+ UNIT_ASSERT_UNEQUAL(id2.value(), id3.value());
+ UNIT_ASSERT_UNEQUAL(id3.value(), id1.value());
+ UNIT_ASSERT_EQUAL(callCount1, 0);
+ UNIT_ASSERT_EQUAL(callCount2, 0);
+ UNIT_ASSERT_EQUAL(callCount3, 0);
+
+ p.SetValue();
+ UNIT_ASSERT_EQUAL(callCount1, 1);
+ UNIT_ASSERT_EQUAL(callCount2, 1);
+ UNIT_ASSERT_EQUAL(callCount3, 1);
+ }
+
+ Y_UNIT_TEST(TestSubscribeOneSignaledManyTimes) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto f = MakeFuture();
+
+ size_t callCount1 = 0;
+ auto id1 = m->Subscribe(f, [&callCount1](auto&&) { ++callCount1; } );
+ size_t callCount2 = 0;
+ auto id2 = m->Subscribe(f, [&callCount2](auto&&) { ++callCount2; } );
+ size_t callCount3 = 0;
+ auto id3 = m->Subscribe(f, [&callCount3](auto&&) { ++callCount3; } );
+
+ UNIT_ASSERT(!id1.has_value());
+ UNIT_ASSERT(!id2.has_value());
+ UNIT_ASSERT(!id3.has_value());
+ UNIT_ASSERT_EQUAL(callCount1, 1);
+ UNIT_ASSERT_EQUAL(callCount2, 1);
+ UNIT_ASSERT_EQUAL(callCount3, 1);
+ }
+
+ Y_UNIT_TEST(TestSubscribeUnsubscribeOneUnsignaledManyTimes) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto p = NewPromise();
+
+ size_t callCount1 = 0;
+ auto id1 = m->Subscribe(p.GetFuture(), [&callCount1](auto&&) { ++callCount1; } );
+ size_t callCount2 = 0;
+ auto id2 = m->Subscribe(p.GetFuture(), [&callCount2](auto&&) { ++callCount2; } );
+ size_t callCount3 = 0;
+ auto id3 = m->Subscribe(p.GetFuture(), [&callCount3](auto&&) { ++callCount3; } );
+ size_t callCount4 = 0;
+ auto id4 = m->Subscribe(p.GetFuture(), [&callCount4](auto&&) { ++callCount4; } );
+
+ UNIT_ASSERT(id1.has_value());
+ UNIT_ASSERT(id2.has_value());
+ UNIT_ASSERT(id3.has_value());
+ UNIT_ASSERT(id4.has_value());
+ UNIT_ASSERT_EQUAL(callCount1, 0);
+ UNIT_ASSERT_EQUAL(callCount2, 0);
+ UNIT_ASSERT_EQUAL(callCount3, 0);
+ UNIT_ASSERT_EQUAL(callCount4, 0);
+
+ m->Unsubscribe(id3.value());
+ m->Unsubscribe(id1.value());
+ UNIT_ASSERT_EQUAL(callCount1, 0);
+ UNIT_ASSERT_EQUAL(callCount2, 0);
+ UNIT_ASSERT_EQUAL(callCount3, 0);
+ UNIT_ASSERT_EQUAL(callCount4, 0);
+
+ p.SetValue();
+ UNIT_ASSERT_EQUAL(callCount1, 0);
+ UNIT_ASSERT_EQUAL(callCount2, 1);
+ UNIT_ASSERT_EQUAL(callCount3, 0);
+ UNIT_ASSERT_EQUAL(callCount4, 1);
+ }
+
+ Y_UNIT_TEST(TestSubscribeManyUnsignaled) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+
+ size_t callCount1 = 0;
+ auto id1 = m->Subscribe(p1.GetFuture(), [&callCount1](auto&&) { ++callCount1; } );
+ size_t callCount2 = 0;
+ auto id2 = m->Subscribe(p2.GetFuture(), [&callCount2](auto&&) { ++callCount2; } );
+ size_t callCount3 = 0;
+ auto id3 = m->Subscribe(p1.GetFuture(), [&callCount3](auto&&) { ++callCount3; } );
+
+ UNIT_ASSERT(id1.has_value());
+ UNIT_ASSERT(id2.has_value());
+ UNIT_ASSERT(id3.has_value());
+ UNIT_ASSERT_UNEQUAL(id1.value(), id2.value());
+ UNIT_ASSERT_UNEQUAL(id2.value(), id3.value());
+ UNIT_ASSERT_UNEQUAL(id3.value(), id1.value());
+ UNIT_ASSERT_EQUAL(callCount1, 0);
+ UNIT_ASSERT_EQUAL(callCount2, 0);
+ UNIT_ASSERT_EQUAL(callCount3, 0);
+
+ p1.SetValue(33);
+ UNIT_ASSERT_EQUAL(callCount1, 1);
+ UNIT_ASSERT_EQUAL(callCount2, 0);
+ UNIT_ASSERT_EQUAL(callCount3, 1);
+
+ p2.SetValue(111);
+ UNIT_ASSERT_EQUAL(callCount1, 1);
+ UNIT_ASSERT_EQUAL(callCount2, 1);
+ UNIT_ASSERT_EQUAL(callCount3, 1);
+ }
+
+ Y_UNIT_TEST(TestSubscribeManySignaled) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto f1 = MakeFuture(0);
+ auto f2 = MakeFuture(1);
+
+ size_t callCount1 = 0;
+ auto id1 = m->Subscribe(f1, [&callCount1](auto&&) { ++callCount1; } );
+ size_t callCount2 = 0;
+ auto id2 = m->Subscribe(f2, [&callCount2](auto&&) { ++callCount2; } );
+ size_t callCount3 = 0;
+ auto id3 = m->Subscribe(f2, [&callCount3](auto&&) { ++callCount3; } );
+
+ UNIT_ASSERT(!id1.has_value());
+ UNIT_ASSERT(!id2.has_value());
+ UNIT_ASSERT(!id3.has_value());
+ UNIT_ASSERT_EQUAL(callCount1, 1);
+ UNIT_ASSERT_EQUAL(callCount2, 1);
+ UNIT_ASSERT_EQUAL(callCount3, 1);
+ }
+
+ Y_UNIT_TEST(TestSubscribeManyMixed) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+ auto f = MakeFuture(42);
+
+ size_t callCount1 = 0;
+ auto id1 = m->Subscribe(p1.GetFuture(), [&callCount1](auto&&) { ++callCount1; } );
+ size_t callCount2 = 0;
+ auto id2 = m->Subscribe(p2.GetFuture(), [&callCount2](auto&&) { ++callCount2; } );
+ size_t callCount3 = 0;
+ auto id3 = m->Subscribe(f, [&callCount3](auto&&) { ++callCount3; } );
+
+ UNIT_ASSERT(id1.has_value());
+ UNIT_ASSERT(id2.has_value());
+ UNIT_ASSERT(!id3.has_value());
+ UNIT_ASSERT_UNEQUAL(id1.value(), id2.value());
+ UNIT_ASSERT_EQUAL(callCount1, 0);
+ UNIT_ASSERT_EQUAL(callCount2, 0);
+ UNIT_ASSERT_EQUAL(callCount3, 1);
+
+ p1.SetValue(45);
+ UNIT_ASSERT_EQUAL(callCount1, 1);
+ UNIT_ASSERT_EQUAL(callCount2, 0);
+ UNIT_ASSERT_EQUAL(callCount3, 1);
+
+ p2.SetValue(-7);
+ UNIT_ASSERT_EQUAL(callCount1, 1);
+ UNIT_ASSERT_EQUAL(callCount2, 1);
+ UNIT_ASSERT_EQUAL(callCount3, 1);
+ }
+
+ Y_UNIT_TEST(TestSubscribeUnsubscribeMany) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+ auto p3 = NewPromise<int>();
+
+ size_t callCount1 = 0;
+ auto id1 = m->Subscribe(p1.GetFuture(), [&callCount1](auto&&) { ++callCount1; } );
+ size_t callCount2 = 0;
+ auto id2 = m->Subscribe(p2.GetFuture(), [&callCount2](auto&&) { ++callCount2; } );
+ size_t callCount3 = 0;
+ auto id3 = m->Subscribe(p3.GetFuture(), [&callCount3](auto&&) { ++callCount3; } );
+ size_t callCount4 = 0;
+ auto id4 = m->Subscribe(p2.GetFuture(), [&callCount4](auto&&) { ++callCount4; } );
+ size_t callCount5 = 0;
+ auto id5 = m->Subscribe(p1.GetFuture(), [&callCount5](auto&&) { ++callCount5; } );
+
+ UNIT_ASSERT(id1.has_value());
+ UNIT_ASSERT(id2.has_value());
+ UNIT_ASSERT(id3.has_value());
+ UNIT_ASSERT(id4.has_value());
+ UNIT_ASSERT(id5.has_value());
+ UNIT_ASSERT_EQUAL(callCount1, 0);
+ UNIT_ASSERT_EQUAL(callCount2, 0);
+ UNIT_ASSERT_EQUAL(callCount3, 0);
+ UNIT_ASSERT_EQUAL(callCount4, 0);
+ UNIT_ASSERT_EQUAL(callCount5, 0);
+
+ m->Unsubscribe(id1.value());
+ p1.SetValue(-1);
+ UNIT_ASSERT_EQUAL(callCount1, 0);
+ UNIT_ASSERT_EQUAL(callCount2, 0);
+ UNIT_ASSERT_EQUAL(callCount3, 0);
+ UNIT_ASSERT_EQUAL(callCount4, 0);
+ UNIT_ASSERT_EQUAL(callCount5, 1);
+
+ m->Unsubscribe(id4.value());
+ p2.SetValue(23);
+ UNIT_ASSERT_EQUAL(callCount1, 0);
+ UNIT_ASSERT_EQUAL(callCount2, 1);
+ UNIT_ASSERT_EQUAL(callCount3, 0);
+ UNIT_ASSERT_EQUAL(callCount4, 0);
+ UNIT_ASSERT_EQUAL(callCount5, 1);
+
+ p3.SetValue(100500);
+ UNIT_ASSERT_EQUAL(callCount1, 0);
+ UNIT_ASSERT_EQUAL(callCount2, 1);
+ UNIT_ASSERT_EQUAL(callCount3, 1);
+ UNIT_ASSERT_EQUAL(callCount4, 0);
+ UNIT_ASSERT_EQUAL(callCount5, 1);
+ }
+
+ Y_UNIT_TEST(TestBulkSubscribeManyUnsignaled) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+
+ size_t callCount = 0;
+ auto ids = m->Subscribe({ p1.GetFuture(), p2.GetFuture(), p1.GetFuture() }, [&callCount](auto&&) { ++callCount; });
+
+ UNIT_ASSERT_EQUAL(ids.size(), 3);
+ UNIT_ASSERT_UNEQUAL(ids[0], ids[1]);
+ UNIT_ASSERT_UNEQUAL(ids[1], ids[2]);
+ UNIT_ASSERT_UNEQUAL(ids[2], ids[0]);
+ UNIT_ASSERT_EQUAL(callCount, 0);
+
+ p1.SetValue(33);
+ UNIT_ASSERT_EQUAL(callCount, 2);
+
+ p2.SetValue(111);
+ UNIT_ASSERT_EQUAL(callCount, 3);
+ }
+
+ Y_UNIT_TEST(TestBulkSubscribeManySignaledNoRevert) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto f1 = MakeFuture(0);
+ auto f2 = MakeFuture(1);
+
+ size_t callCount = 0;
+ auto ids = m->Subscribe({ f1, f2, f1 }, [&callCount](auto&&) { ++callCount; });
+
+ UNIT_ASSERT_EQUAL(ids.size(), 3);
+ UNIT_ASSERT_UNEQUAL(ids[0], ids[1]);
+ UNIT_ASSERT_UNEQUAL(ids[1], ids[2]);
+ UNIT_ASSERT_UNEQUAL(ids[2], ids[0]);
+ UNIT_ASSERT_EQUAL(callCount, 3);
+ }
+
+ Y_UNIT_TEST(TestBulkSubscribeManySignaledRevert) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto f1 = MakeFuture(0);
+ auto f2 = MakeFuture(1);
+
+ size_t callCount = 0;
+ auto ids = m->Subscribe({ f1, f2, f1 }, [&callCount](auto&&) { ++callCount; }, true);
+
+ UNIT_ASSERT(ids.empty());
+ UNIT_ASSERT_EQUAL(callCount, 1);
+ }
+
+ Y_UNIT_TEST(TestBulkSubscribeManyMixedNoRevert) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+ auto f = MakeFuture(42);
+
+ size_t callCount = 0;
+ auto ids = m->Subscribe({ p1.GetFuture(), p2.GetFuture(), f }, [&callCount](auto&&) { ++callCount; } );
+
+ UNIT_ASSERT_EQUAL(ids.size(), 3);
+ UNIT_ASSERT_UNEQUAL(ids[0], ids[1]);
+ UNIT_ASSERT_UNEQUAL(ids[1], ids[2]);
+ UNIT_ASSERT_UNEQUAL(ids[2], ids[0]);
+ UNIT_ASSERT_EQUAL(callCount, 1);
+
+ p1.SetValue(45);
+ UNIT_ASSERT_EQUAL(callCount, 2);
+
+ p2.SetValue(-7);
+ UNIT_ASSERT_EQUAL(callCount, 3);
+ }
+
+ Y_UNIT_TEST(TestBulkSubscribeManyMixedRevert) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto p1 = NewPromise();
+ auto p2 = NewPromise();
+ auto f = MakeFuture();
+
+ size_t callCount = 0;
+ auto ids = m->Subscribe({ p1.GetFuture(), f, p2.GetFuture() }, [&callCount](auto&&) { ++callCount; }, true);
+
+ UNIT_ASSERT(ids.empty());
+ UNIT_ASSERT_EQUAL(callCount, 1);
+
+ p1.SetValue();
+ p2.SetValue();
+ UNIT_ASSERT_EQUAL(callCount, 1);
+ }
+
+ Y_UNIT_TEST(TestBulkSubscribeUnsubscribeMany) {
+ auto m = TSubscriptionManager::NewInstance();
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+ auto p3 = NewPromise<int>();
+
+ size_t callCount = 0;
+ auto ids = m->Subscribe(
+ TVector<TFuture<int>>{ p1.GetFuture(), p2.GetFuture(), p3.GetFuture(), p2.GetFuture(), p1.GetFuture() }
+ , [&callCount](auto&&) { ++callCount; } );
+
+ UNIT_ASSERT_EQUAL(ids.size(), 5);
+ UNIT_ASSERT_EQUAL(callCount, 0);
+
+ m->Unsubscribe(TVector<TSubscriptionId>{ ids[0], ids[3] });
+ UNIT_ASSERT_EQUAL(callCount, 0);
+
+ p1.SetValue(-1);
+ UNIT_ASSERT_EQUAL(callCount, 1);
+
+ p2.SetValue(23);
+ UNIT_ASSERT_EQUAL(callCount, 2);
+
+ p3.SetValue(100500);
+ UNIT_ASSERT_EQUAL(callCount, 3);
+ }
+}
diff --git a/library/cpp/threading/future/subscription/ut/ya.make b/library/cpp/threading/future/subscription/ut/ya.make
new file mode 100644
index 0000000000..45210f7bd7
--- /dev/null
+++ b/library/cpp/threading/future/subscription/ut/ya.make
@@ -0,0 +1,17 @@
+UNITTEST_FOR(library/cpp/threading/future/subscription)
+
+OWNER(
+ g:kwyt
+ g:rtmr
+ ishfb
+)
+
+SRCS(
+ subscription_ut.cpp
+ wait_all_ut.cpp
+ wait_all_or_exception_ut.cpp
+ wait_any_ut.cpp
+ wait_ut_common.cpp
+)
+
+END()
diff --git a/library/cpp/threading/future/subscription/wait.h b/library/cpp/threading/future/subscription/wait.h
new file mode 100644
index 0000000000..533bab9d8d
--- /dev/null
+++ b/library/cpp/threading/future/subscription/wait.h
@@ -0,0 +1,119 @@
+#pragma once
+
+#include "subscription.h"
+
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+#include <util/system/spinlock.h>
+
+
+#include <initializer_list>
+
+namespace NThreading::NPrivate {
+
+template <typename TDerived>
+class TWait : public TThrRefBase {
+private:
+ TSubscriptionManagerPtr Manager;
+ TVector<TSubscriptionId> Subscriptions;
+ bool Unsubscribed = false;
+
+protected:
+ TAdaptiveLock Lock;
+ TPromise<void> Promise;
+
+public:
+ template <typename TFutures, typename TCallbackExecutor>
+ static TFuture<void> Make(TFutures const& futures, TSubscriptionManagerPtr manager, TCallbackExecutor&& executor) {
+ TIntrusivePtr<TDerived> w(new TDerived(std::move(manager)));
+ w->Subscribe(futures, std::forward<TCallbackExecutor>(executor));
+ return w->Promise.GetFuture();
+ }
+
+protected:
+ TWait(TSubscriptionManagerPtr manager)
+ : Manager(std::move(manager))
+ , Subscriptions()
+ , Unsubscribed(false)
+ , Lock()
+ , Promise(NewPromise())
+ {
+ Y_ENSURE(Manager != nullptr);
+ }
+
+protected:
+ //! Unsubscribes all existing subscriptions
+ /** Lock should be acquired!
+ **/
+ void Unsubscribe() noexcept {
+ if (Unsubscribed) {
+ return;
+ }
+ Unsubscribe(Subscriptions);
+ Subscriptions.clear();
+ }
+
+private:
+ //! Performs a subscription to the given futures
+ /** Lock should not be acquired!
+ @param future - The futures to subscribe to
+ @param callback - The callback to call for each future
+ **/
+ template <typename TFutures, typename TCallbackExecutor>
+ void Subscribe(TFutures const& futures, TCallbackExecutor&& executor) {
+ auto self = TIntrusivePtr<TDerived>(static_cast<TDerived*>(this));
+ self->BeforeSubscribe(futures);
+ auto callback = [self = std::move(self)](const auto& future) mutable {
+ self->Set(future);
+ };
+ auto subscriptions = Manager->Subscribe(futures, callback, TDerived::RevertOnSignaled, std::forward<TCallbackExecutor>(executor));
+ if (subscriptions.empty()) {
+ return;
+ }
+ with_lock (Lock) {
+ if (Unsubscribed) {
+ Unsubscribe(subscriptions);
+ } else {
+ Subscriptions = std::move(subscriptions);
+ }
+ }
+ }
+
+ void Unsubscribe(TVector<TSubscriptionId>& subscriptions) noexcept {
+ Manager->Unsubscribe(subscriptions);
+ Unsubscribed = true;
+ }
+};
+
+template <typename TWaiter, typename TFutures, typename TCallbackExecutor>
+TFuture<void> Wait(TFutures const& futures, TSubscriptionManagerPtr manager, TCallbackExecutor&& executor) {
+ switch (std::size(futures)) {
+ case 0:
+ return MakeFuture();
+ case 1:
+ return std::begin(futures)->IgnoreResult();
+ default:
+ return TWaiter::Make(futures, std::move(manager), std::forward<TCallbackExecutor>(executor));
+ }
+}
+
+template <typename TWaiter, typename T, typename TCallbackExecutor>
+TFuture<void> Wait(std::initializer_list<TFuture<T> const> futures, TSubscriptionManagerPtr manager, TCallbackExecutor&& executor) {
+ switch (std::size(futures)) {
+ case 0:
+ return MakeFuture();
+ case 1:
+ return std::begin(futures)->IgnoreResult();
+ default:
+ return TWaiter::Make(futures, std::move(manager), std::forward<TCallbackExecutor>(executor));
+ }
+}
+
+
+template <typename TWaiter, typename T, typename TCallbackExecutor>
+TFuture<void> Wait(TFuture<T> const& future1, TFuture<T> const& future2, TSubscriptionManagerPtr manager, TCallbackExecutor&& executor) {
+ return TWaiter::Make(std::initializer_list<TFuture<T> const>({ future1, future2 }), std::move(manager)
+ , std::forward<TCallbackExecutor>(executor));
+}
+
+}
diff --git a/library/cpp/threading/future/subscription/wait_all.cpp b/library/cpp/threading/future/subscription/wait_all.cpp
new file mode 100644
index 0000000000..10e7ee7598
--- /dev/null
+++ b/library/cpp/threading/future/subscription/wait_all.cpp
@@ -0,0 +1 @@
+#include "wait_all.h"
diff --git a/library/cpp/threading/future/subscription/wait_all.h b/library/cpp/threading/future/subscription/wait_all.h
new file mode 100644
index 0000000000..5c0d2bb862
--- /dev/null
+++ b/library/cpp/threading/future/subscription/wait_all.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "wait.h"
+
+namespace NThreading::NWait {
+
+template <typename TFutures, typename TCallbackExecutor>
+TFuture<void> WaitAll(TFutures const& futures, TSubscriptionManagerPtr manager = TSubscriptionManager::Default()
+ , TCallbackExecutor&& executor = TCallbackExecutor());
+
+template <typename T, typename TCallbackExecutor>
+TFuture<void> WaitAll(std::initializer_list<TFuture<T> const> futures, TSubscriptionManagerPtr manager = TSubscriptionManager::Default()
+ , TCallbackExecutor&& executor = TCallbackExecutor());
+
+template <typename T, typename TCallbackExecutor>
+TFuture<void> WaitAll(TFuture<T> const& future1, TFuture<T> const& future2, TSubscriptionManagerPtr manager = TSubscriptionManager::Default()
+ , TCallbackExecutor&& executor = TCallbackExecutor());
+
+}
+
+#define INCLUDE_LIBRARY_THREADING_FUTURE_WAIT_ALL_INL_H
+#include "wait_all_inl.h"
+#undef INCLUDE_LIBRARY_THREADING_FUTURE_WAIT_ALL_INL_H
diff --git a/library/cpp/threading/future/subscription/wait_all_inl.h b/library/cpp/threading/future/subscription/wait_all_inl.h
new file mode 100644
index 0000000000..a3b665f642
--- /dev/null
+++ b/library/cpp/threading/future/subscription/wait_all_inl.h
@@ -0,0 +1,80 @@
+#pragma once
+
+#if !defined(INCLUDE_LIBRARY_THREADING_FUTURE_WAIT_ALL_INL_H)
+#error "you should never include wait_all_inl.h directly"
+#endif
+
+#include "subscription.h"
+
+#include <initializer_list>
+
+namespace NThreading::NWait {
+
+namespace NPrivate {
+
+class TWaitAll final : public NThreading::NPrivate::TWait<TWaitAll> {
+private:
+ size_t Count = 0;
+ std::exception_ptr Exception;
+
+ static constexpr bool RevertOnSignaled = false;
+
+ using TBase = NThreading::NPrivate::TWait<TWaitAll>;
+ friend TBase;
+
+private:
+ TWaitAll(TSubscriptionManagerPtr manager)
+ : TBase(std::move(manager))
+ , Count(0)
+ , Exception()
+ {
+ }
+
+ template <typename TFutures>
+ void BeforeSubscribe(TFutures const& futures) {
+ Count = std::size(futures);
+ Y_ENSURE(Count > 0, "It is meaningless to use this class with empty futures set");
+ }
+
+ template <typename T>
+ void Set(TFuture<T> const& future) {
+ with_lock (TBase::Lock) {
+ if (!Exception) {
+ try {
+ future.TryRethrow();
+ } catch (...) {
+ Exception = std::current_exception();
+ }
+ }
+
+ if (--Count == 0) {
+ // there is no need to call Unsubscribe here since all futures are signaled
+ Y_ASSERT(!TBase::Promise.HasValue() && !TBase::Promise.HasException());
+ if (Exception) {
+ TBase::Promise.SetException(std::move(Exception));
+ } else {
+ TBase::Promise.SetValue();
+ }
+ }
+ }
+ }
+};
+
+}
+
+template <typename TFutures, typename TCallbackExecutor = NThreading::NPrivate::TNoexceptExecutor>
+TFuture<void> WaitAll(TFutures const& futures, TSubscriptionManagerPtr manager, TCallbackExecutor&& executor) {
+ return NThreading::NPrivate::Wait<NPrivate::TWaitAll>(futures, std::move(manager), std::forward<TCallbackExecutor>(executor));
+}
+
+template <typename T, typename TCallbackExecutor = NThreading::NPrivate::TNoexceptExecutor>
+TFuture<void> WaitAll(std::initializer_list<TFuture<T> const> futures, TSubscriptionManagerPtr manager, TCallbackExecutor&& executor) {
+ return NThreading::NPrivate::Wait<NPrivate::TWaitAll>(futures, std::move(manager), std::forward<TCallbackExecutor>(executor));
+}
+
+template <typename T, typename TCallbackExecutor = NThreading::NPrivate::TNoexceptExecutor>
+TFuture<void> WaitAll(TFuture<T> const& future1, TFuture<T> const& future2, TSubscriptionManagerPtr manager, TCallbackExecutor&& executor) {
+ return NThreading::NPrivate::Wait<NPrivate::TWaitAll>(future1, future2, std::move(manager), std::forward<TCallbackExecutor>(executor));
+}
+
+}
diff --git a/library/cpp/threading/future/subscription/wait_all_or_exception.cpp b/library/cpp/threading/future/subscription/wait_all_or_exception.cpp
new file mode 100644
index 0000000000..0c73ddeb84
--- /dev/null
+++ b/library/cpp/threading/future/subscription/wait_all_or_exception.cpp
@@ -0,0 +1 @@
+#include "wait_all_or_exception.h"
diff --git a/library/cpp/threading/future/subscription/wait_all_or_exception.h b/library/cpp/threading/future/subscription/wait_all_or_exception.h
new file mode 100644
index 0000000000..e3e0caf2f8
--- /dev/null
+++ b/library/cpp/threading/future/subscription/wait_all_or_exception.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "wait.h"
+
+namespace NThreading::NWait {
+
+template <typename TFutures, typename TCallbackExecutor>
+TFuture<void> WaitAllOrException(TFutures const& futures, TSubscriptionManagerPtr manager = TSubscriptionManager::Default()
+ , TCallbackExecutor&& executor = TCallbackExecutor());
+
+template <typename T, typename TCallbackExecutor>
+TFuture<void> WaitAllOrException(std::initializer_list<TFuture<T> const> futures
+ , TSubscriptionManagerPtr manager = TSubscriptionManager::Default()
+ , TCallbackExecutor&& executor = TCallbackExecutor());
+
+template <typename T, typename TCallbackExecutor>
+TFuture<void> WaitAllOrException(TFuture<T> const& future1, TFuture<T> const& future2
+ , TSubscriptionManagerPtr manager = TSubscriptionManager::Default()
+ , TCallbackExecutor&& executor = TCallbackExecutor());
+
+}
+
+#define INCLUDE_LIBRARY_THREADING_FUTURE_WAIT_ALL_OR_EXCEPTION_INL_H
+#include "wait_all_or_exception_inl.h"
+#undef INCLUDE_LIBRARY_THREADING_FUTURE_WAIT_ALL_OR_EXCEPTION_INL_H
diff --git a/library/cpp/threading/future/subscription/wait_all_or_exception_inl.h b/library/cpp/threading/future/subscription/wait_all_or_exception_inl.h
new file mode 100644
index 0000000000..fcd9782d54
--- /dev/null
+++ b/library/cpp/threading/future/subscription/wait_all_or_exception_inl.h
@@ -0,0 +1,79 @@
+#pragma once
+
+#if !defined(INCLUDE_LIBRARY_THREADING_FUTURE_WAIT_ALL_OR_EXCEPTION_INL_H)
+#error "you should never include wait_all_or_exception_inl.h directly"
+#endif
+
+#include "subscription.h"
+
+#include <initializer_list>
+
+namespace NThreading::NWait {
+
+namespace NPrivate {
+
+class TWaitAllOrException final : public NThreading::NPrivate::TWait<TWaitAllOrException>
+{
+private:
+ size_t Count = 0;
+
+ static constexpr bool RevertOnSignaled = false;
+
+ using TBase = NThreading::NPrivate::TWait<TWaitAllOrException>;
+ friend TBase;
+
+private:
+ TWaitAllOrException(TSubscriptionManagerPtr manager)
+ : TBase(std::move(manager))
+ , Count(0)
+ {
+ }
+
+ template <typename TFutures>
+ void BeforeSubscribe(TFutures const& futures) {
+ Count = std::size(futures);
+ Y_ENSURE(Count > 0, "It is meaningless to use this class with empty futures set");
+ }
+
+ template <typename T>
+ void Set(TFuture<T> const& future) {
+ with_lock (TBase::Lock) {
+ try {
+ future.TryRethrow();
+ if (--Count == 0) {
+ // there is no need to call Unsubscribe here since all futures are signaled
+ TBase::Promise.SetValue();
+ }
+ } catch (...) {
+ Y_ASSERT(!TBase::Promise.HasValue());
+ TBase::Unsubscribe();
+ if (!TBase::Promise.HasException()) {
+ TBase::Promise.SetException(std::current_exception());
+ }
+ }
+ }
+ }
+};
+
+}
+
+template <typename TFutures, typename TCallbackExecutor = NThreading::NPrivate::TNoexceptExecutor>
+TFuture<void> WaitAllOrException(TFutures const& futures, TSubscriptionManagerPtr manager, TCallbackExecutor&& executor) {
+ return NThreading::NPrivate::Wait<NPrivate::TWaitAllOrException>(futures, std::move(manager), std::forward<TCallbackExecutor>(executor));
+}
+
+template <typename T, typename TCallbackExecutor = NThreading::NPrivate::TNoexceptExecutor>
+TFuture<void> WaitAllOrException(std::initializer_list<TFuture<T> const> futures, TSubscriptionManagerPtr manager
+ , TCallbackExecutor&& executor)
+{
+ return NThreading::NPrivate::Wait<NPrivate::TWaitAllOrException>(futures, std::move(manager), std::forward<TCallbackExecutor>(executor));
+}
+template <typename T, typename TCallbackExecutor = NThreading::NPrivate::TNoexceptExecutor>
+TFuture<void> WaitAllOrException(TFuture<T> const& future1, TFuture<T> const& future2, TSubscriptionManagerPtr manager
+ , TCallbackExecutor&& executor)
+{
+ return NThreading::NPrivate::Wait<NPrivate::TWaitAllOrException>(future1, future2, std::move(manager)
+ , std::forward<TCallbackExecutor>(executor));
+}
+
+}
diff --git a/library/cpp/threading/future/subscription/wait_all_or_exception_ut.cpp b/library/cpp/threading/future/subscription/wait_all_or_exception_ut.cpp
new file mode 100644
index 0000000000..34ae9edb4e
--- /dev/null
+++ b/library/cpp/threading/future/subscription/wait_all_or_exception_ut.cpp
@@ -0,0 +1,167 @@
+#include "wait_all_or_exception.h"
+#include "wait_ut_common.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/generic/strbuf.h>
+
+#include <atomic>
+#include <exception>
+
+using namespace NThreading;
+
+Y_UNIT_TEST_SUITE(TWaitAllOrExceptionTest) {
+
+ Y_UNIT_TEST(TestTwoUnsignaled) {
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+ auto w = NWait::WaitAllOrException(p1.GetFuture(), p2.GetFuture());
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ p1.SetValue(10);
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+ p2.SetValue(1);
+ UNIT_ASSERT(w.HasValue());
+ }
+
+ Y_UNIT_TEST(TestTwoUnsignaledWithException) {
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+ auto w = NWait::WaitAllOrException(p1.GetFuture(), p2.GetFuture());
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ constexpr TStringBuf message = "Test exception";
+ p1.SetException(std::make_exception_ptr(yexception() << message));
+ UNIT_ASSERT_EXCEPTION_SATISFIES(w.TryRethrow(), yexception, [message](auto const& e) {
+ return message == e.what();
+ });
+
+ p2.SetValue(-11);
+ }
+
+ Y_UNIT_TEST(TestOneUnsignaledOneSignaled) {
+ auto p = NewPromise();
+ auto f = MakeFuture();
+ auto w = NWait::WaitAllOrException(p.GetFuture(), f);
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ p.SetValue();
+ UNIT_ASSERT(w.HasValue());
+ }
+
+ Y_UNIT_TEST(TestOneUnsignaledOneSignaledWithException) {
+ auto p = NewPromise();
+ auto f = MakeFuture();
+ auto w = NWait::WaitAllOrException(f, p.GetFuture());
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ constexpr TStringBuf message = "Test exception 2";
+ p.SetException(std::make_exception_ptr(yexception() << message));
+ UNIT_ASSERT_EXCEPTION_SATISFIES(w.TryRethrow(), yexception, [message](auto const& e) {
+ return message == e.what();
+ });
+ }
+
+ Y_UNIT_TEST(TestEmptyInitializer) {
+ auto w = NWait::WaitAllOrException(std::initializer_list<TFuture<void> const>({}));
+ UNIT_ASSERT(w.HasValue());
+ }
+
+ Y_UNIT_TEST(TestEmptyVector) {
+ auto w = NWait::WaitAllOrException(TVector<TFuture<int>>());
+ UNIT_ASSERT(w.HasValue());
+ }
+
+ Y_UNIT_TEST(TestOneUnsignaledWithInitializer) {
+ auto p = NewPromise<int>();
+ auto w = NWait::WaitAllOrException({ p.GetFuture() });
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ p.SetValue(1);
+ UNIT_ASSERT(w.HasValue());
+ }
+
+ Y_UNIT_TEST(TestOneUnsignaledWithVector) {
+ auto p = NewPromise();
+ auto w = NWait::WaitAllOrException(TVector<TFuture<void>>{ p.GetFuture() });
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ constexpr TStringBuf message = "Test exception 3";
+ p.SetException(std::make_exception_ptr(yexception() << message));
+ UNIT_ASSERT_EXCEPTION_SATISFIES(w.TryRethrow(), yexception, [message](auto const& e) {
+ return message == e.what();
+ });
+ }
+
+ Y_UNIT_TEST(TestManyWithInitializer) {
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+ auto f = MakeFuture(42);
+ auto w = NWait::WaitAllOrException({ p1.GetFuture(), f, p2.GetFuture() });
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ p1.SetValue(10);
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+ p2.SetValue(-3);
+ UNIT_ASSERT(w.HasValue());
+ }
+
+ Y_UNIT_TEST(TestManyWithVector) {
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+ auto f = MakeFuture(42);
+ auto w = NWait::WaitAllOrException(TVector<TFuture<int>>{ p1.GetFuture(), f, p2.GetFuture() });
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ constexpr TStringBuf message = "Test exception 4";
+ p1.SetException(std::make_exception_ptr(yexception() << message));
+ UNIT_ASSERT_EXCEPTION_SATISFIES(w.TryRethrow(), yexception, [message](auto const& e) {
+ return message == e.what();
+ });
+
+ p2.SetValue(34);
+ }
+
+ Y_UNIT_TEST(TestManyWithVectorAndIntialError) {
+ auto p1 = NewPromise();
+ auto p2 = NewPromise();
+ constexpr TStringBuf message = "Test exception 5";
+ auto f = MakeErrorFuture<void>(std::make_exception_ptr(yexception() << message));
+ auto w = NWait::WaitAllOrException(TVector<TFuture<void>>{ p1.GetFuture(), p2.GetFuture(), f });
+ UNIT_ASSERT_EXCEPTION_SATISFIES(w.TryRethrow(), yexception, [message](auto const& e) {
+ return message == e.what();
+ });
+
+ p1.SetValue();
+ p2.SetValue();
+ }
+
+ Y_UNIT_TEST(TestManyStress) {
+ NTest::TestManyStress<void>([](auto&& futures) { return NWait::WaitAllOrException(futures); }
+ , [](size_t) {
+ return [](auto&& p) { p.SetValue(); };
+ }
+ , [](auto&& waiter) { UNIT_ASSERT(waiter.HasValue()); });
+
+ NTest::TestManyStress<int>([](auto&& futures) { return NWait::WaitAllOrException(futures); }
+ , [](size_t) {
+ return [](auto&& p) { p.SetValue(22); };
+ }
+ , [](auto&& waiter) { UNIT_ASSERT(waiter.HasValue()); });
+ auto e = std::make_exception_ptr(yexception() << "Test exception 6");
+ std::atomic<size_t> index = 0;
+ NTest::TestManyStress<void>([](auto&& futures) { return NWait::WaitAllOrException(futures); }
+ , [e, &index](size_t size) {
+ auto exceptionIndex = size / 2;
+ index = 0;
+ return [e, exceptionIndex, &index](auto&& p) {
+ if (index++ == exceptionIndex) {
+ p.SetException(e);
+ } else {
+ p.SetValue();
+ }
+ };
+ }
+ , [](auto&& waiter) { UNIT_ASSERT(waiter.HasException()); });
+ }
+
+}
diff --git a/library/cpp/threading/future/subscription/wait_all_ut.cpp b/library/cpp/threading/future/subscription/wait_all_ut.cpp
new file mode 100644
index 0000000000..3bc9762671
--- /dev/null
+++ b/library/cpp/threading/future/subscription/wait_all_ut.cpp
@@ -0,0 +1,161 @@
+#include "wait_all.h"
+#include "wait_ut_common.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/generic/strbuf.h>
+
+#include <atomic>
+#include <exception>
+
+using namespace NThreading;
+
+Y_UNIT_TEST_SUITE(TWaitAllTest) {
+
+ Y_UNIT_TEST(TestTwoUnsignaled) {
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+ auto w = NWait::WaitAll(p1.GetFuture(), p2.GetFuture());
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ p1.SetValue(10);
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+ p2.SetValue(1);
+ UNIT_ASSERT(w.HasValue());
+ }
+
+ Y_UNIT_TEST(TestTwoUnsignaledWithException) {
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+ auto w = NWait::WaitAll(p1.GetFuture(), p2.GetFuture());
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ constexpr TStringBuf message = "Test exception";
+ p1.SetException(std::make_exception_ptr(yexception() << message));
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ p2.SetValue(-11);
+ UNIT_ASSERT_EXCEPTION_SATISFIES(w.TryRethrow(), yexception, [message](auto const& e) {
+ return message == e.what();
+ });
+ }
+
+ Y_UNIT_TEST(TestOneUnsignaledOneSignaled) {
+ auto p = NewPromise();
+ auto f = MakeFuture();
+ auto w = NWait::WaitAll(p.GetFuture(), f);
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ p.SetValue();
+ UNIT_ASSERT(w.HasValue());
+ }
+
+ Y_UNIT_TEST(TestOneUnsignaledOneSignaledWithException) {
+ auto p = NewPromise();
+ auto f = MakeFuture();
+ auto w = NWait::WaitAll(f, p.GetFuture());
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ constexpr TStringBuf message = "Test exception 2";
+ p.SetException(std::make_exception_ptr(yexception() << message));
+ UNIT_ASSERT_EXCEPTION_SATISFIES(w.TryRethrow(), yexception, [message](auto const& e) {
+ return message == e.what();
+ });
+ }
+
+ Y_UNIT_TEST(TestEmptyInitializer) {
+ auto w = NWait::WaitAll(std::initializer_list<TFuture<void> const>({}));
+ UNIT_ASSERT(w.HasValue());
+ }
+
+ Y_UNIT_TEST(TestEmptyVector) {
+ auto w = NWait::WaitAll(TVector<TFuture<int>>());
+ UNIT_ASSERT(w.HasValue());
+ }
+
+ Y_UNIT_TEST(TestOneUnsignaledWithInitializer) {
+ auto p = NewPromise<int>();
+ auto w = NWait::WaitAll({ p.GetFuture() });
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ p.SetValue(1);
+ UNIT_ASSERT(w.HasValue());
+ }
+
+ Y_UNIT_TEST(TestOneUnsignaledWithVector) {
+ auto p = NewPromise();
+ auto w = NWait::WaitAll(TVector<TFuture<void>>{ p.GetFuture() });
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ constexpr TStringBuf message = "Test exception 3";
+ p.SetException(std::make_exception_ptr(yexception() << message));
+ UNIT_ASSERT_EXCEPTION_SATISFIES(w.TryRethrow(), yexception, [message](auto const& e) {
+ return message == e.what();
+ });
+ }
+
+ Y_UNIT_TEST(TestManyWithInitializer) {
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+ auto f = MakeFuture(42);
+ auto w = NWait::WaitAll({ p1.GetFuture(), f, p2.GetFuture() });
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ p1.SetValue(10);
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+ p2.SetValue(-3);
+ UNIT_ASSERT(w.HasValue());
+ }
+
+ Y_UNIT_TEST(TestManyWithVector) {
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+ auto f = MakeFuture(42);
+ auto w = NWait::WaitAll(TVector<TFuture<int>>{ p1.GetFuture(), f, p2.GetFuture() });
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ constexpr TStringBuf message = "Test exception 4";
+ p1.SetException(std::make_exception_ptr(yexception() << message));
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ p2.SetValue(34);
+ UNIT_ASSERT_EXCEPTION_SATISFIES(w.TryRethrow(), yexception, [message](auto const& e) {
+ return message == e.what();
+ });
+ }
+
+ Y_UNIT_TEST(TestManyStress) {
+ NTest::TestManyStress<int>([](auto&& futures) { return NWait::WaitAll(futures); }
+ , [](size_t) {
+ return [](auto&& p) { p.SetValue(42); };
+ }
+ , [](auto&& waiter) { UNIT_ASSERT(waiter.HasValue()); });
+
+ NTest::TestManyStress<void>([](auto&& futures) { return NWait::WaitAll(futures); }
+ , [](size_t) {
+ return [](auto&& p) { p.SetValue(); };
+ }
+ , [](auto&& waiter) { UNIT_ASSERT(waiter.HasValue()); });
+ auto e = std::make_exception_ptr(yexception() << "Test exception 5");
+ NTest::TestManyStress<void>([](auto&& futures) { return NWait::WaitAll(futures); }
+ , [e](size_t) {
+ return [e](auto&& p) { p.SetException(e); };
+ }
+ , [](auto&& waiter) { UNIT_ASSERT(waiter.HasException()); });
+ e = std::make_exception_ptr(yexception() << "Test exception 6");
+ std::atomic<size_t> index = 0;
+ NTest::TestManyStress<int>([](auto&& futures) { return NWait::WaitAll(futures); }
+ , [e, &index](size_t size) {
+ auto exceptionIndex = size / 2;
+ index = 0;
+ return [e, exceptionIndex, &index](auto&& p) {
+ if (index++ == exceptionIndex) {
+ p.SetException(e);
+ } else {
+ p.SetValue(index);
+ }
+ };
+ }
+ , [](auto&& waiter) { UNIT_ASSERT(waiter.HasException()); });
+ }
+
+}
diff --git a/library/cpp/threading/future/subscription/wait_any.cpp b/library/cpp/threading/future/subscription/wait_any.cpp
new file mode 100644
index 0000000000..57cc1b2c25
--- /dev/null
+++ b/library/cpp/threading/future/subscription/wait_any.cpp
@@ -0,0 +1 @@
+#include "wait_any.h"
diff --git a/library/cpp/threading/future/subscription/wait_any.h b/library/cpp/threading/future/subscription/wait_any.h
new file mode 100644
index 0000000000..e770d7b59e
--- /dev/null
+++ b/library/cpp/threading/future/subscription/wait_any.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "wait.h"
+
+namespace NThreading::NWait {
+
+template <typename TFutures, typename TCallbackExecutor>
+TFuture<void> WaitAny(TFutures const& futures, TSubscriptionManagerPtr manager = TSubscriptionManager::Default()
+ , TCallbackExecutor&& executor = TCallbackExecutor());
+
+template <typename T, typename TCallbackExecutor>
+TFuture<void> WaitAny(std::initializer_list<TFuture<T> const> futures, TSubscriptionManagerPtr manager = TSubscriptionManager::Default()
+ , TCallbackExecutor&& executor = TCallbackExecutor());
+
+template <typename T, typename TCallbackExecutor>
+TFuture<void> WaitAny(TFuture<T> const& future1, TFuture<T> const& future2, TSubscriptionManagerPtr manager = TSubscriptionManager::Default()
+ , TCallbackExecutor&& executor = TCallbackExecutor());
+
+}
+
+#define INCLUDE_LIBRARY_THREADING_FUTURE_WAIT_ANY_INL_H
+#include "wait_any_inl.h"
+#undef INCLUDE_LIBRARY_THREADING_FUTURE_WAIT_ANY_INL_H
diff --git a/library/cpp/threading/future/subscription/wait_any_inl.h b/library/cpp/threading/future/subscription/wait_any_inl.h
new file mode 100644
index 0000000000..e80822bfc9
--- /dev/null
+++ b/library/cpp/threading/future/subscription/wait_any_inl.h
@@ -0,0 +1,64 @@
+#pragma once
+
+#if !defined(INCLUDE_LIBRARY_THREADING_FUTURE_WAIT_ANY_INL_H)
+#error "you should never include wait_any_inl.h directly"
+#endif
+
+#include "subscription.h"
+
+#include <initializer_list>
+
+namespace NThreading::NWait {
+
+namespace NPrivate {
+
+class TWaitAny final : public NThreading::NPrivate::TWait<TWaitAny> {
+private:
+ static constexpr bool RevertOnSignaled = true;
+
+ using TBase = NThreading::NPrivate::TWait<TWaitAny>;
+ friend TBase;
+
+private:
+ TWaitAny(TSubscriptionManagerPtr manager)
+ : TBase(std::move(manager))
+ {
+ }
+
+ template <typename TFutures>
+ void BeforeSubscribe(TFutures const& futures) {
+ Y_ENSURE(std::size(futures) > 0, "Futures set cannot be empty");
+ }
+
+ template <typename T>
+ void Set(TFuture<T> const& future) {
+ with_lock (TBase::Lock) {
+ TBase::Unsubscribe();
+ try {
+ future.TryRethrow();
+ TBase::Promise.TrySetValue();
+ } catch (...) {
+ TBase::Promise.TrySetException(std::current_exception());
+ }
+ }
+ }
+};
+
+}
+
+template <typename TFutures, typename TCallbackExecutor = NThreading::NPrivate::TNoexceptExecutor>
+TFuture<void> WaitAny(TFutures const& futures, TSubscriptionManagerPtr manager, TCallbackExecutor&& executor) {
+ return NThreading::NPrivate::Wait<NPrivate::TWaitAny>(futures, std::move(manager), std::forward<TCallbackExecutor>(executor));
+}
+
+template <typename T, typename TCallbackExecutor = NThreading::NPrivate::TNoexceptExecutor>
+TFuture<void> WaitAny(std::initializer_list<TFuture<T> const> futures, TSubscriptionManagerPtr manager, TCallbackExecutor&& executor) {
+ return NThreading::NPrivate::Wait<NPrivate::TWaitAny>(futures, std::move(manager), std::forward<TCallbackExecutor>(executor));
+}
+
+template <typename T, typename TCallbackExecutor = NThreading::NPrivate::TNoexceptExecutor>
+TFuture<void> WaitAny(TFuture<T> const& future1, TFuture<T> const& future2, TSubscriptionManagerPtr manager, TCallbackExecutor&& executor) {
+ return NThreading::NPrivate::Wait<NPrivate::TWaitAny>(future1, future2, std::move(manager), std::forward<TCallbackExecutor>(executor));
+}
+
+}
diff --git a/library/cpp/threading/future/subscription/wait_any_ut.cpp b/library/cpp/threading/future/subscription/wait_any_ut.cpp
new file mode 100644
index 0000000000..262080e8d1
--- /dev/null
+++ b/library/cpp/threading/future/subscription/wait_any_ut.cpp
@@ -0,0 +1,166 @@
+#include "wait_any.h"
+#include "wait_ut_common.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/generic/strbuf.h>
+
+#include <exception>
+
+using namespace NThreading;
+
+Y_UNIT_TEST_SUITE(TWaitAnyTest) {
+
+ Y_UNIT_TEST(TestTwoUnsignaled) {
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+ auto w = NWait::WaitAny(p1.GetFuture(), p2.GetFuture());
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ p1.SetValue(10);
+ UNIT_ASSERT(w.HasValue());
+ p2.SetValue(1);
+ }
+
+ Y_UNIT_TEST(TestTwoUnsignaledWithException) {
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+ auto w = NWait::WaitAny(p1.GetFuture(), p2.GetFuture());
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ constexpr TStringBuf message = "Test exception";
+ p2.SetException(std::make_exception_ptr(yexception() << message));
+ UNIT_ASSERT_EXCEPTION_SATISFIES(w.TryRethrow(), yexception, [message](auto const& e) {
+ return message == e.what();
+ });
+
+ p1.SetValue(-11);
+ }
+
+ Y_UNIT_TEST(TestOneUnsignaledOneSignaled) {
+ auto p = NewPromise();
+ auto f = MakeFuture();
+ auto w = NWait::WaitAny(p.GetFuture(), f);
+ UNIT_ASSERT(w.HasValue());
+
+ p.SetValue();
+ }
+
+ Y_UNIT_TEST(TestOneUnsignaledOneSignaledWithException) {
+ auto p = NewPromise();
+ constexpr TStringBuf message = "Test exception 2";
+ auto f = MakeErrorFuture<void>(std::make_exception_ptr(yexception() << message));
+ auto w = NWait::WaitAny(f, p.GetFuture());
+ UNIT_ASSERT_EXCEPTION_SATISFIES(w.TryRethrow(), yexception, [message](auto const& e) {
+ return message == e.what();
+ });
+
+ p.SetValue();
+ }
+
+ Y_UNIT_TEST(TestEmptyInitializer) {
+ auto w = NWait::WaitAny(std::initializer_list<TFuture<void> const>({}));
+ UNIT_ASSERT(w.HasValue());
+ }
+
+ Y_UNIT_TEST(TestEmptyVector) {
+ auto w = NWait::WaitAny(TVector<TFuture<int>>());
+ UNIT_ASSERT(w.HasValue());
+ }
+
+ Y_UNIT_TEST(TestOneUnsignaledWithInitializer) {
+ auto p = NewPromise<int>();
+ auto w = NWait::WaitAny({ p.GetFuture() });
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ p.SetValue(1);
+ UNIT_ASSERT(w.HasValue());
+ }
+
+ Y_UNIT_TEST(TestOneUnsignaledWithVector) {
+ auto p = NewPromise();
+ auto w = NWait::WaitAny(TVector<TFuture<void>>{ p.GetFuture() });
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ constexpr TStringBuf message = "Test exception 3";
+ p.SetException(std::make_exception_ptr(yexception() << message));
+ UNIT_ASSERT_EXCEPTION_SATISFIES(w.TryRethrow(), yexception, [message](auto const& e) {
+ return message == e.what();
+ });
+ }
+
+ Y_UNIT_TEST(TestManyUnsignaledWithInitializer) {
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+ auto p3 = NewPromise<int>();
+ auto w = NWait::WaitAny({ p1.GetFuture(), p2.GetFuture(), p3.GetFuture() });
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ p1.SetValue(42);
+ UNIT_ASSERT(w.HasValue());
+
+ p2.SetValue(-3);
+ p3.SetValue(12);
+ }
+
+ Y_UNIT_TEST(TestManyMixedWithInitializer) {
+ auto p1 = NewPromise<int>();
+ auto p2 = NewPromise<int>();
+ auto f = MakeFuture(42);
+ auto w = NWait::WaitAny({ p1.GetFuture(), f, p2.GetFuture() });
+ UNIT_ASSERT(w.HasValue());
+
+ p1.SetValue(10);
+ p2.SetValue(-3);
+ }
+
+
+ Y_UNIT_TEST(TestManyUnsignaledWithVector) {
+ auto p1 = NewPromise();
+ auto p2 = NewPromise();
+ auto p3 = NewPromise();
+ auto w = NWait::WaitAny(TVector<TFuture<void>>{ p1.GetFuture(), p2.GetFuture(), p3.GetFuture() });
+ UNIT_ASSERT(!w.HasValue() && !w.HasException());
+
+ constexpr TStringBuf message = "Test exception 4";
+ p2.SetException(std::make_exception_ptr(yexception() << message));
+ UNIT_ASSERT_EXCEPTION_SATISFIES(w.TryRethrow(), yexception, [message](auto const& e) {
+ return message == e.what();
+ });
+
+ p1.SetValue();
+ p3.SetValue();
+ }
+
+
+ Y_UNIT_TEST(TestManyMixedWithVector) {
+ auto p1 = NewPromise();
+ auto p2 = NewPromise();
+ auto f = MakeFuture();
+ auto w = NWait::WaitAny(TVector<TFuture<void>>{ p1.GetFuture(), p2.GetFuture(), f });
+ UNIT_ASSERT(w.HasValue());
+
+ p1.SetValue();
+ p2.SetValue();
+ }
+
+ Y_UNIT_TEST(TestManyStress) {
+ NTest::TestManyStress<void>([](auto&& futures) { return NWait::WaitAny(futures); }
+ , [](size_t) {
+ return [](auto&& p) { p.SetValue(); };
+ }
+ , [](auto&& waiter) { UNIT_ASSERT(waiter.HasValue()); });
+
+ NTest::TestManyStress<int>([](auto&& futures) { return NWait::WaitAny(futures); }
+ , [](size_t) {
+ return [](auto&& p) { p.SetValue(22); };
+ }
+ , [](auto&& waiter) { UNIT_ASSERT(waiter.HasValue()); });
+ auto e = std::make_exception_ptr(yexception() << "Test exception 5");
+ NTest::TestManyStress<void>([](auto&& futures) { return NWait::WaitAny(futures); }
+ , [e](size_t) {
+ return [e](auto&& p) { p.SetException(e); };
+ }
+ , [](auto&& waiter) { UNIT_ASSERT(waiter.HasException()); });
+ }
+
+}
diff --git a/library/cpp/threading/future/subscription/wait_ut_common.cpp b/library/cpp/threading/future/subscription/wait_ut_common.cpp
new file mode 100644
index 0000000000..9f961e7303
--- /dev/null
+++ b/library/cpp/threading/future/subscription/wait_ut_common.cpp
@@ -0,0 +1,26 @@
+#include "wait_ut_common.h"
+
+#include <util/random/shuffle.h>
+#include <util/system/event.h>
+#include <util/thread/pool.h>
+
+namespace NThreading::NTest::NPrivate {
+
+void ExecuteAndWait(TVector<std::function<void()>> jobs, TFuture<void> waiter, size_t threads) {
+ Y_ENSURE(threads > 0);
+ Shuffle(jobs.begin(), jobs.end());
+ auto pool = CreateThreadPool(threads);
+ TManualEvent start;
+ for (auto& j : jobs) {
+ pool->SafeAddFunc(
+ [&start, job = std::move(j)]() {
+ start.WaitI();
+ job();
+ });
+ }
+ start.Signal();
+ waiter.Wait();
+ pool->Stop();
+}
+
+}
diff --git a/library/cpp/threading/future/subscription/wait_ut_common.h b/library/cpp/threading/future/subscription/wait_ut_common.h
new file mode 100644
index 0000000000..99530dd1f6
--- /dev/null
+++ b/library/cpp/threading/future/subscription/wait_ut_common.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <library/cpp/threading/future/future.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/vector.h>
+
+#include <functional>
+#include <type_traits>
+
+namespace NThreading::NTest {
+
+namespace NPrivate {
+
+void ExecuteAndWait(TVector<std::function<void()>> jobs, TFuture<void> waiter, size_t threads);
+
+template <typename TPromises, typename FSetter>
+void SetConcurrentAndWait(TPromises&& promises, FSetter&& setter, TFuture<void> waiter, size_t threads = 8) {
+ TVector<std::function<void()>> jobs;
+ jobs.reserve(std::size(promises));
+ for (auto& p : promises) {
+ jobs.push_back([p, setter]() mutable {setter(p); });
+ }
+ ExecuteAndWait(std::move(jobs), std::move(waiter), threads);
+}
+
+template <typename T>
+auto MakePromise() {
+ if constexpr (std::is_same_v<T, void>) {
+ return NewPromise();
+ }
+ return NewPromise<T>();
+}
+
+}
+
+template <typename T, typename FWaiterFactory, typename FSetterFactory, typename FChecker>
+void TestManyStress(FWaiterFactory&& waiterFactory, FSetterFactory&& setterFactory, FChecker&& checker) {
+ for (size_t i : { 1, 2, 4, 8, 16, 32, 64, 128, 256 }) {
+ TVector<TPromise<T>> promises;
+ TVector<TFuture<T>> futures;
+ promises.reserve(i);
+ futures.reserve(i);
+ for (size_t j = 0; j < i; ++j) {
+ auto promise = NPrivate::MakePromise<T>();
+ futures.push_back(promise.GetFuture());
+ promises.push_back(std::move(promise));
+ }
+ auto waiter = waiterFactory(futures);
+ NPrivate::SetConcurrentAndWait(std::move(promises), [valueSetter = setterFactory(i)](auto&& p) { valueSetter(p); }
+ , waiter);
+ checker(waiter);
+ }
+}
+
+}
diff --git a/library/cpp/threading/future/subscription/ya.make b/library/cpp/threading/future/subscription/ya.make
new file mode 100644
index 0000000000..cb75731dbf
--- /dev/null
+++ b/library/cpp/threading/future/subscription/ya.make
@@ -0,0 +1,24 @@
+OWNER(
+ g:kwyt
+ g:rtmr
+ ishfb
+)
+
+LIBRARY()
+
+SRCS(
+ subscription.cpp
+ wait_all.cpp
+ wait_all_or_exception.cpp
+ wait_any.cpp
+)
+
+PEERDIR(
+ library/cpp/threading/future
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ ut
+)
diff --git a/library/cpp/threading/future/ut/ya.make b/library/cpp/threading/future/ut/ya.make
new file mode 100644
index 0000000000..566b622370
--- /dev/null
+++ b/library/cpp/threading/future/ut/ya.make
@@ -0,0 +1,14 @@
+UNITTEST_FOR(library/cpp/threading/future)
+
+OWNER(
+ g:rtmr
+ ishfb
+)
+
+SRCS(
+ async_ut.cpp
+ future_ut.cpp
+ legacy_future_ut.cpp
+)
+
+END()
diff --git a/library/cpp/threading/future/wait/fwd.cpp b/library/cpp/threading/future/wait/fwd.cpp
new file mode 100644
index 0000000000..4214b6df83
--- /dev/null
+++ b/library/cpp/threading/future/wait/fwd.cpp
@@ -0,0 +1 @@
+#include "fwd.h"
diff --git a/library/cpp/threading/future/wait/fwd.h b/library/cpp/threading/future/wait/fwd.h
new file mode 100644
index 0000000000..de3b1313d5
--- /dev/null
+++ b/library/cpp/threading/future/wait/fwd.h
@@ -0,0 +1 @@
+// empty (for now)
diff --git a/library/cpp/threading/future/wait/wait-inl.h b/library/cpp/threading/future/wait/wait-inl.h
new file mode 100644
index 0000000000..2753d5446c
--- /dev/null
+++ b/library/cpp/threading/future/wait/wait-inl.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#if !defined(INCLUDE_FUTURE_INL_H)
+#error "you should never include wait-inl.h directly"
+#endif // INCLUDE_FUTURE_INL_H
+
+namespace NThreading {
+ namespace NImpl {
+ template <typename TContainer>
+ TVector<TFuture<void>> ToVoidFutures(const TContainer& futures) {
+ TVector<TFuture<void>> voidFutures;
+ voidFutures.reserve(futures.size());
+
+ for (const auto& future: futures) {
+ voidFutures.push_back(future.IgnoreResult());
+ }
+
+ return voidFutures;
+ }
+ }
+
+ template <typename TContainer>
+ [[nodiscard]] NImpl::EnableGenericWait<TContainer> WaitAll(const TContainer& futures) {
+ return WaitAll(NImpl::ToVoidFutures(futures));
+ }
+
+ template <typename TContainer>
+ [[nodiscard]] NImpl::EnableGenericWait<TContainer> WaitExceptionOrAll(const TContainer& futures) {
+ return WaitExceptionOrAll(NImpl::ToVoidFutures(futures));
+ }
+
+ template <typename TContainer>
+ [[nodiscard]] NImpl::EnableGenericWait<TContainer> WaitAny(const TContainer& futures) {
+ return WaitAny(NImpl::ToVoidFutures(futures));
+ }
+}
diff --git a/library/cpp/threading/future/wait/wait.cpp b/library/cpp/threading/future/wait/wait.cpp
new file mode 100644
index 0000000000..a173833a7f
--- /dev/null
+++ b/library/cpp/threading/future/wait/wait.cpp
@@ -0,0 +1,82 @@
+#include "wait.h"
+
+#include "wait_group.h"
+#include "wait_policy.h"
+
+namespace NThreading {
+ namespace {
+ template <class WaitPolicy>
+ TFuture<void> WaitGeneric(const TFuture<void>& f1) {
+ return f1;
+ }
+
+ template <class WaitPolicy>
+ TFuture<void> WaitGeneric(const TFuture<void>& f1, const TFuture<void>& f2) {
+ TWaitGroup<WaitPolicy> wg;
+
+ wg.Add(f1).Add(f2);
+
+ return std::move(wg).Finish();
+ }
+
+ template <class WaitPolicy>
+ TFuture<void> WaitGeneric(TArrayRef<const TFuture<void>> futures) {
+ if (futures.empty()) {
+ return MakeFuture();
+ }
+ if (futures.size() == 1) {
+ return futures.front();
+ }
+
+ TWaitGroup<WaitPolicy> wg;
+ for (const auto& fut : futures) {
+ wg.Add(fut);
+ }
+
+ return std::move(wg).Finish();
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ TFuture<void> WaitAll(const TFuture<void>& f1) {
+ return WaitGeneric<TWaitPolicy::TAll>(f1);
+ }
+
+ TFuture<void> WaitAll(const TFuture<void>& f1, const TFuture<void>& f2) {
+ return WaitGeneric<TWaitPolicy::TAll>(f1, f2);
+ }
+
+ TFuture<void> WaitAll(TArrayRef<const TFuture<void>> futures) {
+ return WaitGeneric<TWaitPolicy::TAll>(futures);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ TFuture<void> WaitExceptionOrAll(const TFuture<void>& f1) {
+ return WaitGeneric<TWaitPolicy::TExceptionOrAll>(f1);
+ }
+
+ TFuture<void> WaitExceptionOrAll(const TFuture<void>& f1, const TFuture<void>& f2) {
+ return WaitGeneric<TWaitPolicy::TExceptionOrAll>(f1, f2);
+ }
+
+ TFuture<void> WaitExceptionOrAll(TArrayRef<const TFuture<void>> futures) {
+ return WaitGeneric<TWaitPolicy::TExceptionOrAll>(futures);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ TFuture<void> WaitAny(const TFuture<void>& f1) {
+ return WaitGeneric<TWaitPolicy::TAny>(f1);
+ }
+
+ TFuture<void> WaitAny(const TFuture<void>& f1, const TFuture<void>& f2) {
+ return WaitGeneric<TWaitPolicy::TAny>(f1, f2);
+ }
+
+ TFuture<void> WaitAny(TArrayRef<const TFuture<void>> futures) {
+ return WaitGeneric<TWaitPolicy::TAny>(futures);
+ }
+}
diff --git a/library/cpp/threading/future/wait/wait.h b/library/cpp/threading/future/wait/wait.h
new file mode 100644
index 0000000000..6ff7d57baa
--- /dev/null
+++ b/library/cpp/threading/future/wait/wait.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include "fwd.h"
+
+#include <library/cpp/threading/future/core/future.h>
+#include <library/cpp/threading/future/wait/wait_group.h>
+
+#include <util/generic/array_ref.h>
+
+namespace NThreading {
+ namespace NImpl {
+ template <class TContainer>
+ using EnableGenericWait = std::enable_if_t<
+ !std::is_convertible_v<TContainer, TArrayRef<const TFuture<void>>>,
+ TFuture<void>>;
+ }
+ // waits for all futures
+ [[nodiscard]] TFuture<void> WaitAll(const TFuture<void>& f1);
+ [[nodiscard]] TFuture<void> WaitAll(const TFuture<void>& f1, const TFuture<void>& f2);
+ [[nodiscard]] TFuture<void> WaitAll(TArrayRef<const TFuture<void>> futures);
+ template <typename TContainer>
+ [[nodiscard]] NImpl::EnableGenericWait<TContainer> WaitAll(const TContainer& futures);
+
+ // waits for the first exception or for all futures
+ [[nodiscard]] TFuture<void> WaitExceptionOrAll(const TFuture<void>& f1);
+ [[nodiscard]] TFuture<void> WaitExceptionOrAll(const TFuture<void>& f1, const TFuture<void>& f2);
+ [[nodiscard]] TFuture<void> WaitExceptionOrAll(TArrayRef<const TFuture<void>> futures);
+ template <typename TContainer>
+ [[nodiscard]] NImpl::EnableGenericWait<TContainer> WaitExceptionOrAll(const TContainer& futures);
+
+ // waits for any future
+ [[nodiscard]] TFuture<void> WaitAny(const TFuture<void>& f1);
+ [[nodiscard]] TFuture<void> WaitAny(const TFuture<void>& f1, const TFuture<void>& f2);
+ [[nodiscard]] TFuture<void> WaitAny(TArrayRef<const TFuture<void>> futures);
+ template <typename TContainer>
+ [[nodiscard]] NImpl::EnableGenericWait<TContainer> WaitAny(const TContainer& futures);
+}
+
+#define INCLUDE_FUTURE_INL_H
+#include "wait-inl.h"
+#undef INCLUDE_FUTURE_INL_H
diff --git a/library/cpp/threading/future/wait/wait_group-inl.h b/library/cpp/threading/future/wait/wait_group-inl.h
new file mode 100644
index 0000000000..a7da536f20
--- /dev/null
+++ b/library/cpp/threading/future/wait/wait_group-inl.h
@@ -0,0 +1,206 @@
+#pragma once
+
+#if !defined(INCLUDE_FUTURE_INL_H)
+#error "you should never include wait_group-inl.h directly"
+#endif // INCLUDE_FUTURE_INL_H
+
+#include "wait_policy.h"
+
+#include <util/generic/maybe.h>
+#include <util/generic/ptr.h>
+
+#include <library/cpp/threading/future/core/future.h>
+
+#include <util/system/spinlock.h>
+
+#include <atomic>
+#include <exception>
+
+namespace NThreading {
+ namespace NWaitGroup::NImpl {
+ template <class WaitPolicy>
+ struct TState final : TAtomicRefCount<TState<WaitPolicy>> {
+ template <class T>
+ void Add(const TFuture<T>& future);
+ TFuture<void> Finish();
+
+ void TryPublish();
+ void Publish();
+
+ bool ShouldPublishByCount() const noexcept;
+ bool ShouldPublishByException() const noexcept;
+
+ TStateRef<WaitPolicy> SharedFromThis() noexcept {
+ return TStateRef<WaitPolicy>{this};
+ }
+
+ enum class EPhase {
+ Initial,
+ Publishing,
+ };
+
+ // initially we have one imaginary discovered future which we
+ // use for synchronization with ::Finish
+ std::atomic<ui64> Discovered{1};
+
+ std::atomic<ui64> Finished{0};
+
+ std::atomic<EPhase> Phase{EPhase::Initial};
+
+ TPromise<void> Subscribers = NewPromise();
+
+ mutable TAdaptiveLock Mut;
+ std::exception_ptr ExceptionInFlight;
+
+ void TrySetException(std::exception_ptr eptr) noexcept {
+ TGuard lock{Mut};
+ if (!ExceptionInFlight) {
+ ExceptionInFlight = std::move(eptr);
+ }
+ }
+
+ std::exception_ptr GetExceptionInFlight() const noexcept {
+ TGuard lock{Mut};
+ return ExceptionInFlight;
+ }
+ };
+
+ template <class WaitPolicy>
+ inline TFuture<void> TState<WaitPolicy>::Finish() {
+ Finished.fetch_add(1); // complete the imaginary future
+
+ // handle empty case explicitly:
+ if (Discovered.load() == 1) {
+ Y_ASSERT(Phase.load() == EPhase::Initial);
+ Publish();
+ } else {
+ TryPublish();
+ }
+
+ return Subscribers;
+ }
+
+ template <class WaitPolicy>
+ template <class T>
+ inline void TState<WaitPolicy>::Add(const TFuture<T>& future) {
+ future.EnsureInitialized();
+
+ Discovered.fetch_add(1);
+
+ // NoexceptSubscribe is needed to make ::Add exception-safe
+ future.NoexceptSubscribe([self = SharedFromThis()](auto&& future) {
+ try {
+ future.TryRethrow();
+ } catch (...) {
+ self->TrySetException(std::current_exception());
+ }
+
+ self->Finished.fetch_add(1);
+ self->TryPublish();
+ });
+ }
+
+ //
+ // ============================ PublishByCount ==================================
+ //
+
+ template <class WaitPolicy>
+ inline bool TState<WaitPolicy>::ShouldPublishByCount() const noexcept {
+ // - safety: a) If the future incremented ::Finished, and we observe the effect, then we will observe ::Discovered as incremented by its discovery later
+ // b) Every discovery of a future observes discovery of the imaginary future
+ // a, b => if finishedByNow == discoveredByNow, then every future discovered in [imaginary discovered, imaginary finished] is finished
+ //
+ // - liveness: a) TryPublish is called after each increment of ::Finished
+ // b) There is some last increment of ::Finished which follows all other operations with ::Finished and ::Discovered (provided that every future is eventually set)
+ // c) For each increment of ::Discovered there is an increment of ::Finished (provided that every future is eventually set)
+ // a, b c => some call to ShouldPublishByCount will always return true
+ //
+ // order of the following two operations is significant for the proof.
+ auto finishedByNow = Finished.load();
+ auto discoveredByNow = Discovered.load();
+
+ return finishedByNow == discoveredByNow;
+ }
+
+ template <>
+ inline bool TState<TWaitPolicy::TAny>::ShouldPublishByCount() const noexcept {
+ auto finishedByNow = Finished.load();
+
+ // note that the empty case is not handled here
+ return finishedByNow >= 2; // at least one non-imaginary
+ }
+
+ //
+ // ============================ PublishByException ==================================
+ //
+
+ template <>
+ inline bool TState<TWaitPolicy::TAny>::ShouldPublishByException() const noexcept {
+ // for TAny exceptions are handled by ShouldPublishByCount
+ return false;
+ }
+
+ template <>
+ inline bool TState<TWaitPolicy::TAll>::ShouldPublishByException() const noexcept {
+ return false;
+ }
+
+ template <>
+ inline bool TState<TWaitPolicy::TExceptionOrAll>::ShouldPublishByException() const noexcept {
+ return GetExceptionInFlight() != nullptr;
+ }
+
+ //
+ //
+ //
+
+ template <class WaitPolicy>
+ inline void TState<WaitPolicy>::TryPublish() {
+ // the order is insignificant (without proof)
+ bool shouldPublish = ShouldPublishByCount() || ShouldPublishByException();
+
+ if (shouldPublish) {
+ if (auto currentPhase = EPhase::Initial;
+ Phase.compare_exchange_strong(currentPhase, EPhase::Publishing)) {
+ Publish();
+ }
+ }
+ }
+
+ template <class WaitPolicy>
+ inline void TState<WaitPolicy>::Publish() {
+ auto eptr = GetExceptionInFlight();
+
+ // can potentially throw
+ if (eptr) {
+ Subscribers.SetException(std::move(eptr));
+ } else {
+ Subscribers.SetValue();
+ }
+ }
+ }
+
+ template <class WaitPolicy>
+ inline TWaitGroup<WaitPolicy>::TWaitGroup()
+ : State_{MakeIntrusive<NWaitGroup::NImpl::TState<WaitPolicy>>()}
+ {
+ }
+
+ template <class WaitPolicy>
+ template <class T>
+ inline TWaitGroup<WaitPolicy>& TWaitGroup<WaitPolicy>::Add(const TFuture<T>& future) {
+ State_->Add(future);
+ return *this;
+ }
+
+ template <class WaitPolicy>
+ inline TFuture<void> TWaitGroup<WaitPolicy>::Finish() && {
+ auto res = State_->Finish();
+
+ // just to prevent nasty bugs from use-after-move
+ State_.Reset();
+
+ return res;
+ }
+}
+
diff --git a/library/cpp/threading/future/wait/wait_group.cpp b/library/cpp/threading/future/wait/wait_group.cpp
new file mode 100644
index 0000000000..4b9c7adb27
--- /dev/null
+++ b/library/cpp/threading/future/wait/wait_group.cpp
@@ -0,0 +1 @@
+#include "wait_group.h"
diff --git a/library/cpp/threading/future/wait/wait_group.h b/library/cpp/threading/future/wait/wait_group.h
new file mode 100644
index 0000000000..78d85594a2
--- /dev/null
+++ b/library/cpp/threading/future/wait/wait_group.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include <library/cpp/threading/future/core/future.h>
+
+#include <util/generic/ptr.h>
+
+namespace NThreading {
+ namespace NWaitGroup::NImpl {
+ template <class WaitPolicy>
+ struct TState;
+
+ template <class WaitPolicy>
+ using TStateRef = TIntrusivePtr<TState<WaitPolicy>>;
+ }
+
+ // a helper class which allows to
+ // wait for a set of futures which is
+ // not known beforehand. Might be useful, e.g., for graceful shutdown:
+ // while (!Stop()) {
+ // wg.Add(
+ // DoAsyncWork());
+ // }
+ // std::move(wg).Finish()
+ // .GetValueSync();
+ //
+ //
+ // the folowing are equivalent:
+ // {
+ // return WaitAll(futures);
+ // }
+ // {
+ // TWaitGroup<TWaitPolicy::TAll> wg;
+ // for (auto&& f: futures) { wg.Add(f); }
+ // return std::move(wg).Finish();
+ // }
+
+ template <class WaitPolicy>
+ class TWaitGroup {
+ public:
+ TWaitGroup();
+
+ // thread-safe, exception-safe
+ //
+ // adds the future to the set of futures to wait for
+ //
+ // if an exception is thrown during a call to ::Discover, the call has no effect
+ //
+ // accepts non-void T just for optimization
+ // (so that the caller does not have to use future.IgnoreResult())
+ template <class T>
+ TWaitGroup& Add(const TFuture<T>& future);
+
+ // finishes building phase
+ // and returns the future that combines the futures
+ // in the wait group according to WaitPolicy
+ [[nodiscard]] TFuture<void> Finish() &&;
+
+ private:
+ NWaitGroup::NImpl::TStateRef<WaitPolicy> State_;
+ };
+}
+
+#define INCLUDE_FUTURE_INL_H
+#include "wait_group-inl.h"
+#undef INCLUDE_FUTURE_INL_H
diff --git a/library/cpp/threading/future/wait/wait_policy.cpp b/library/cpp/threading/future/wait/wait_policy.cpp
new file mode 100644
index 0000000000..dbebec4966
--- /dev/null
+++ b/library/cpp/threading/future/wait/wait_policy.cpp
@@ -0,0 +1 @@
+#include "wait_policy.h"
diff --git a/library/cpp/threading/future/wait/wait_policy.h b/library/cpp/threading/future/wait/wait_policy.h
new file mode 100644
index 0000000000..310b702f17
--- /dev/null
+++ b/library/cpp/threading/future/wait/wait_policy.h
@@ -0,0 +1,10 @@
+#pragma once
+
+namespace NThreading {
+ struct TWaitPolicy {
+ struct TAll {};
+ struct TAny {};
+ struct TExceptionOrAll {};
+ };
+}
+
diff --git a/library/cpp/threading/future/ya.make b/library/cpp/threading/future/ya.make
new file mode 100644
index 0000000000..6591031f46
--- /dev/null
+++ b/library/cpp/threading/future/ya.make
@@ -0,0 +1,22 @@
+OWNER(
+ g:rtmr
+)
+
+LIBRARY()
+
+SRCS(
+ async.cpp
+ core/future.cpp
+ core/fwd.cpp
+ fwd.cpp
+ wait/fwd.cpp
+ wait/wait.cpp
+ wait/wait_group.cpp
+ wait/wait_policy.cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ mt_ut
+)
diff --git a/library/cpp/threading/light_rw_lock/bench/lightrwlock_test.cpp b/library/cpp/threading/light_rw_lock/bench/lightrwlock_test.cpp
new file mode 100644
index 0000000000..c3027ea544
--- /dev/null
+++ b/library/cpp/threading/light_rw_lock/bench/lightrwlock_test.cpp
@@ -0,0 +1,188 @@
+#include <library/cpp/threading/light_rw_lock/lightrwlock.h>
+#include <util/random/random.h>
+
+#ifdef _linux_
+// Light rw lock is implemented only for linux
+
+using namespace NS_LightRWLock;
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define LIGHT
+
+#ifdef RWSPINLOCK
+#include <library/cpp/lwtrace/rwspinlock.h>
+#endif
+
+#define CHECK_LOGIC 1
+#define LOOPCOUNT 1000000
+#define RANRCOUNT 100
+#define THREADCOUNT 40
+#define WRITELOCKS 100
+
+#if defined(_MSC_VER)
+static int Y_FORCE_INLINE AtomicFetchAdd(volatile int& item, int value) {
+ return _InterlockedExchangeAdd((&item, value);
+}
+#elif defined(__GNUC__)
+#else
+#error unsupported platform
+#endif
+
+class TPosixRWLock {
+public:
+ TPosixRWLock() {
+ }
+
+ ~TPosixRWLock() {
+ pthread_rwlock_destroy(&rwlock);
+ }
+
+ TPosixRWLock(const TPosixRWLock&) = delete;
+ void operator=(const TPosixRWLock&) = delete;
+
+private:
+ pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
+ friend class TPosixRWShareLocker;
+ friend class TPosixRWExclusiveLocker;
+};
+
+#if defined(LIGHT)
+TLightRWLock __attribute__((aligned(64))) rwlock;
+#elif defined(POSIX)
+TPosixRWLock rwlock;
+#elif defined(RWSPINLOCK)
+TRWSpinLock __attribute__((aligned(64))) rwlock;
+#else
+#error "define lock type"
+#endif
+
+volatile __attribute__((aligned(64))) int checkIt = 0;
+volatile int checkExcl = 0;
+
+class TPosixRWShareLocker {
+public:
+ TPosixRWShareLocker(TPosixRWLock& lock)
+ : LockP_(&lock)
+ {
+ pthread_rwlock_rdlock(&LockP_->rwlock);
+ }
+
+ ~TPosixRWShareLocker() {
+ pthread_rwlock_unlock(&LockP_->rwlock);
+ }
+
+ TPosixRWShareLocker(const TPosixRWShareLocker&) = delete;
+ void operator=(const TPosixRWShareLocker&) = delete;
+
+private:
+ TPosixRWLock* LockP_;
+};
+
+class TPosixRWExclusiveLocker {
+public:
+ TPosixRWExclusiveLocker(TPosixRWLock& lock)
+ : LockP_(&lock)
+ {
+ pthread_rwlock_wrlock(&LockP_->rwlock);
+ }
+
+ ~TPosixRWExclusiveLocker() {
+ pthread_rwlock_unlock(&LockP_->rwlock);
+ }
+ TPosixRWExclusiveLocker(const TPosixRWExclusiveLocker&) = delete;
+ void operator=(const TPosixRWExclusiveLocker&) = delete;
+
+private:
+ TPosixRWLock* LockP_;
+};
+
+template <typename TLocker, bool excl>
+static Y_FORCE_INLINE void Run() {
+ TLocker lockIt(rwlock);
+
+#if defined(CHECK_LOGIC) && CHECK_LOGIC
+ if (!excl && checkExcl == 1) {
+ printf("there is a bug\n");
+ }
+
+ int result = AtomicFetchAdd(checkIt, 1);
+ if (excl)
+ checkExcl = 1;
+
+ if (excl && result > 1)
+ printf("there is a bug\n");
+#endif
+
+ for (unsigned w = 0; w < RANRCOUNT; ++w)
+ RandomNumber<ui32>();
+
+#if defined(CHECK_LOGIC) && CHECK_LOGIC
+ if (excl)
+ checkExcl = 0;
+
+ AtomicFetchAdd(checkIt, -1);
+#endif
+}
+
+#ifdef LIGHT
+static void* fast_thread_start(__attribute__((unused)) void* arg) {
+ for (unsigned q = 0; q < LOOPCOUNT; ++q) {
+ char excl = (RandomNumber<ui32>() % WRITELOCKS) == 0;
+ if (excl)
+ Run<TLightWriteGuard, 1>();
+ else
+ Run<TLightReadGuard, 0>();
+ }
+ return NULL;
+}
+#endif
+
+#ifdef POSIX
+static void* fast_thread_start(__attribute__((unused)) void* arg) {
+ for (unsigned q = 0; q < LOOPCOUNT; ++q) {
+ char excl = (RandomNumber<ui32>() % WRITELOCKS) == 0;
+ if (excl)
+ Run<TPosixRWExclusiveLocker, 1>();
+ else
+ Run<TPosixRWShareLocker, 0>();
+ }
+ return NULL;
+}
+#endif
+
+#ifdef RWSPINLOCK
+static void* fast_thread_start(__attribute__((unused)) void* arg) {
+ for (unsigned q = 0; q < LOOPCOUNT; ++q) {
+ char excl = (RandomNumber<ui32>() % WRITELOCKS) == 0;
+ if (excl)
+ Run<TWriteSpinLockGuard, 1>();
+ else
+ Run<TReadSpinLockGuard, 0>();
+ }
+ return NULL;
+}
+#endif
+
+int main() {
+ pthread_t threads[THREADCOUNT];
+
+ for (unsigned q = 0; q < THREADCOUNT; ++q) {
+ pthread_create(&(threads[q]), NULL, &fast_thread_start, NULL);
+ }
+
+ for (unsigned q = 0; q < THREADCOUNT; ++q)
+ pthread_join(threads[q], NULL);
+
+ return 0;
+}
+
+#else // !_linux_
+
+int main() {
+ return 0;
+}
+
+#endif
diff --git a/library/cpp/threading/light_rw_lock/bench/ya.make b/library/cpp/threading/light_rw_lock/bench/ya.make
new file mode 100644
index 0000000000..7969b52a50
--- /dev/null
+++ b/library/cpp/threading/light_rw_lock/bench/ya.make
@@ -0,0 +1,13 @@
+PROGRAM(lightrwlock_test)
+
+OWNER(agri)
+
+SRCS(
+ lightrwlock_test.cpp
+)
+
+PEERDIR(
+ library/cpp/threading/light_rw_lock
+)
+
+END()
diff --git a/library/cpp/threading/light_rw_lock/lightrwlock.cpp b/library/cpp/threading/light_rw_lock/lightrwlock.cpp
new file mode 100644
index 0000000000..fbb63fd47f
--- /dev/null
+++ b/library/cpp/threading/light_rw_lock/lightrwlock.cpp
@@ -0,0 +1,113 @@
+#include "lightrwlock.h"
+#include <util/system/spinlock.h>
+
+#if defined(_linux_)
+
+using namespace NS_LightRWLock;
+
+void TLightRWLock::WaitForUntrappedShared() {
+ for (;;) {
+ for (ui32 i = 0; i < SpinCount_; ++i) {
+ SpinLockPause();
+
+ if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0)
+ return;
+ }
+
+ SequenceStore(UnshareFutex_, 1);
+ if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) {
+ AtomicStore(UnshareFutex_, 0);
+ return;
+ }
+ FutexWait(UnshareFutex_, 1);
+ }
+}
+
+void TLightRWLock::WaitForExclusiveAndUntrappedShared() {
+ for (;;) {
+ for (ui32 i = 0; i < SpinCount_; ++i) {
+ SpinLockPause();
+
+ if (AtomicLoad(Counter_) >= 0)
+ goto try_to_get_lock;
+ if (AtomicLoad(TrappedFutex_) == 1)
+ goto skip_store_trapped;
+ }
+
+ SequenceStore(TrappedFutex_, 1);
+ skip_store_trapped:
+
+ if (AtomicLoad(Counter_) < 0) {
+ FutexWait(TrappedFutex_, 1);
+ }
+
+ try_to_get_lock:
+ if (!AtomicSetBit(Counter_, 31))
+ break;
+ }
+
+ for (ui32 j = 0;; ++j) {
+ for (ui32 i = 0; i < SpinCount_; ++i) {
+ if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0)
+ return;
+
+ SpinLockPause();
+ }
+
+ SequenceStore(UnshareFutex_, 1);
+
+ if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) {
+ AtomicStore(UnshareFutex_, 0);
+ return;
+ }
+
+ FutexWait(UnshareFutex_, 1);
+ }
+}
+
+void TLightRWLock::WaitForUntrappedAndAcquireRead() {
+ if (AtomicFetchAdd(Counter_, -1) < 0)
+ goto skip_lock_try;
+
+ for (;;) {
+ again:
+ if (Y_UNLIKELY(AtomicFetchAdd(Counter_, 1) >= 0)) {
+ return;
+ } else {
+ if (AtomicFetchAdd(Counter_, -1) >= 0)
+ goto again;
+ }
+
+ skip_lock_try:
+ if (AtomicLoad(UnshareFutex_) && (AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) {
+ SequenceStore(UnshareFutex_, 0);
+ FutexWake(UnshareFutex_, 1);
+ }
+
+ for (;;) {
+ for (ui32 i = 0; i < SpinCount_; ++i) {
+ SpinLockPause();
+
+ if (AtomicLoad(Counter_) >= 0)
+ goto again;
+ if (AtomicLoad(TrappedFutex_) == 1)
+ goto skip_store_trapped;
+ }
+
+ SequenceStore(TrappedFutex_, 1);
+ skip_store_trapped:
+
+ if (AtomicLoad(Counter_) < 0) {
+ FutexWait(TrappedFutex_, 1);
+ if (AtomicLoad(Counter_) < 0)
+ goto again;
+ } else if (AtomicLoad(TrappedFutex_)) {
+ SequenceStore(TrappedFutex_, 0);
+ FutexWake(TrappedFutex_, 0x7fffffff);
+ }
+ break;
+ }
+ }
+}
+
+#endif // _linux_
diff --git a/library/cpp/threading/light_rw_lock/lightrwlock.h b/library/cpp/threading/light_rw_lock/lightrwlock.h
new file mode 100644
index 0000000000..931a1817bc
--- /dev/null
+++ b/library/cpp/threading/light_rw_lock/lightrwlock.h
@@ -0,0 +1,220 @@
+#pragma once
+
+#include <util/system/rwlock.h>
+#include <util/system/sanitizers.h>
+
+#if defined(_linux_)
+/* TLightRWLock is optimized for read lock and very fast lock/unlock switching.
+ Read lock increments counter.
+ Write lock sets highest bit of counter (makes counter negative).
+
+ Whenever a thread tries to acquire read lock that thread increments
+ the counter. If the thread gets negative value of the counter right just
+ after the increment that means write lock was acquired in another thread.
+ In that case the thread decrements the counter back, wakes one thread on
+ UnshareFutex, waits on the TrappedFutex and then tries acquire read lock
+ from the beginning.
+ If the thread gets positive value of the counter after the increment
+ then read lock was successfully acquired and
+ the thread can proceed execution.
+
+ Whenever a thread tries to acquire write lock that thread set the highest bit
+ of the counter. If the thread determine that the bit was set previously then
+ write lock was acquired in another thread. In that case the thread waits on
+ the TrappedFutex and then tries again from the beginning.
+ If the highest bit was successfully set then thread check if any read lock
+ exists at the moment. If so the thread waits on UnshareFutex. If there is
+ no more read locks then write lock was successfully acquired and the thread
+ can proceed execution.
+*/
+
+#include <linux/futex.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <errno.h>
+
+namespace NS_LightRWLock {
+ static int Y_FORCE_INLINE AtomicFetchAdd(volatile int& item, int value) {
+ return __atomic_fetch_add(&item, value, __ATOMIC_SEQ_CST);
+ }
+
+#if defined(_x86_64_) || defined(_i386_)
+
+ static char Y_FORCE_INLINE AtomicSetBit(volatile int& item, unsigned bit) {
+ char ret;
+ __asm__ __volatile__(
+ "lock bts %2,%0\n"
+ "setc %1\n"
+ : "+m"(item), "=rm"(ret)
+ : "r"(bit)
+ : "cc");
+
+ // msan doesn't treat ret as initialized
+ NSan::Unpoison(&ret, sizeof(ret));
+
+ return ret;
+ }
+
+ static char Y_FORCE_INLINE AtomicClearBit(volatile int& item, unsigned bit) {
+ char ret;
+ __asm__ __volatile__(
+ "lock btc %2,%0\n"
+ "setc %1\n"
+ : "+m"(item), "=rm"(ret)
+ : "r"(bit)
+ : "cc");
+
+ // msan doesn't treat ret as initialized
+ NSan::Unpoison(&ret, sizeof(ret));
+
+ return ret;
+ }
+
+
+#else
+
+ static char Y_FORCE_INLINE AtomicSetBit(volatile int& item, unsigned bit) {
+ int prev = __atomic_fetch_or(&item, 1 << bit, __ATOMIC_SEQ_CST);
+ return (prev & (1 << bit)) != 0 ? 1 : 0;
+ }
+
+ static char Y_FORCE_INLINE
+ AtomicClearBit(volatile int& item, unsigned bit) {
+ int prev = __atomic_fetch_and(&item, ~(1 << bit), __ATOMIC_SEQ_CST);
+ return (prev & (1 << bit)) != 0 ? 1 : 0;
+ }
+#endif
+
+#if defined(_x86_64_) || defined(_i386_) || defined (__aarch64__) || defined (__powerpc64__)
+ static bool AtomicLockHighByte(volatile int& item) {
+ union TA {
+ int x;
+ char y[4];
+ };
+
+ volatile TA* ptr = reinterpret_cast<volatile TA*>(&item);
+ char zero = 0;
+ return __atomic_compare_exchange_n(&(ptr->y[3]), &zero, (char)128, true,
+ __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
+ }
+
+#endif
+
+ template <typename TInt>
+ static void Y_FORCE_INLINE AtomicStore(volatile TInt& var, TInt value) {
+ __atomic_store_n(&var, value, __ATOMIC_RELEASE);
+ }
+
+ template <typename TInt>
+ static void Y_FORCE_INLINE SequenceStore(volatile TInt& var, TInt value) {
+ __atomic_store_n(&var, value, __ATOMIC_SEQ_CST);
+ }
+
+ template <typename TInt>
+ static TInt Y_FORCE_INLINE AtomicLoad(const volatile TInt& var) {
+ return __atomic_load_n(&var, __ATOMIC_ACQUIRE);
+ }
+
+ static void Y_FORCE_INLINE FutexWait(volatile int& fvar, int value) {
+ for (;;) {
+ int result =
+ syscall(SYS_futex, &fvar, FUTEX_WAIT_PRIVATE, value, NULL, NULL, 0);
+ if (Y_UNLIKELY(result == -1)) {
+ if (errno == EWOULDBLOCK)
+ return;
+ if (errno == EINTR)
+ continue;
+ Y_FAIL("futex error");
+ }
+ }
+ }
+
+ static void Y_FORCE_INLINE FutexWake(volatile int& fvar, int amount) {
+ const int result =
+ syscall(SYS_futex, &fvar, FUTEX_WAKE_PRIVATE, amount, NULL, NULL, 0);
+ if (Y_UNLIKELY(result == -1))
+ Y_FAIL("futex error");
+ }
+
+}
+
+class alignas(64) TLightRWLock {
+public:
+ TLightRWLock(ui32 spinCount = 10)
+ : Counter_(0)
+ , TrappedFutex_(0)
+ , UnshareFutex_(0)
+ , SpinCount_(spinCount)
+ {
+ }
+
+ TLightRWLock(const TLightRWLock&) = delete;
+ void operator=(const TLightRWLock&) = delete;
+
+ Y_FORCE_INLINE void AcquireWrite() {
+ using namespace NS_LightRWLock;
+
+ if (AtomicLockHighByte(Counter_)) {
+ if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0)
+ return;
+ return WaitForUntrappedShared();
+ }
+ WaitForExclusiveAndUntrappedShared();
+ }
+
+ Y_FORCE_INLINE void AcquireRead() {
+ using namespace NS_LightRWLock;
+
+ if (Y_LIKELY(AtomicFetchAdd(Counter_, 1) >= 0))
+ return;
+ WaitForUntrappedAndAcquireRead();
+ }
+
+ Y_FORCE_INLINE void ReleaseWrite() {
+ using namespace NS_LightRWLock;
+
+ AtomicClearBit(Counter_, 31);
+ if (AtomicLoad(TrappedFutex_)) {
+ SequenceStore(TrappedFutex_, 0);
+ FutexWake(TrappedFutex_, 0x7fffffff);
+ }
+ }
+
+ Y_FORCE_INLINE void ReleaseRead() {
+ using namespace NS_LightRWLock;
+
+ if (Y_LIKELY(AtomicFetchAdd(Counter_, -1) >= 0))
+ return;
+ if (!AtomicLoad(UnshareFutex_))
+ return;
+ if ((AtomicLoad(Counter_) & 0x7fffffff) == 0) {
+ SequenceStore(UnshareFutex_, 0);
+ FutexWake(UnshareFutex_, 1);
+ }
+ }
+
+private:
+ volatile int Counter_;
+ volatile int TrappedFutex_;
+ volatile int UnshareFutex_;
+ const ui32 SpinCount_;
+
+ void WaitForUntrappedShared();
+ void WaitForExclusiveAndUntrappedShared();
+ void WaitForUntrappedAndAcquireRead();
+};
+
+#else
+
+class TLightRWLock: public TRWMutex {
+public:
+ TLightRWLock() {
+ }
+ TLightRWLock(ui32) {
+ }
+};
+
+#endif
+
+using TLightReadGuard = TReadGuardBase<TLightRWLock>;
+using TLightWriteGuard = TWriteGuardBase<TLightRWLock>;
diff --git a/library/cpp/threading/light_rw_lock/ut/rwlock_ut.cpp b/library/cpp/threading/light_rw_lock/ut/rwlock_ut.cpp
new file mode 100644
index 0000000000..e82063d959
--- /dev/null
+++ b/library/cpp/threading/light_rw_lock/ut/rwlock_ut.cpp
@@ -0,0 +1,122 @@
+#include <library/cpp/threading/light_rw_lock/lightrwlock.h>
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/random/random.h>
+#include <util/system/atomic.h>
+#include <util/thread/pool.h>
+
+class TRWMutexTest: public TTestBase {
+ UNIT_TEST_SUITE(TRWMutexTest);
+ UNIT_TEST(TestReaders)
+ UNIT_TEST(TestReadersWriters)
+ UNIT_TEST_SUITE_END();
+
+ struct TSharedData {
+ TSharedData()
+ : writersIn(0)
+ , readersIn(0)
+ , failed(false)
+ {
+ }
+
+ TAtomic writersIn;
+ TAtomic readersIn;
+
+ bool failed;
+
+ TLightRWLock mutex;
+ };
+
+ class TThreadTask: public IObjectInQueue {
+ public:
+ using PFunc = void (TThreadTask::*)(void);
+
+ TThreadTask(PFunc func, TSharedData& data, size_t id, size_t total)
+ : Func_(func)
+ , Data_(data)
+ , Id_(id)
+ , Total_(total)
+ {
+ }
+
+ void Process(void*) override {
+ THolder<TThreadTask> This(this);
+
+ (this->*Func_)();
+ }
+
+#define FAIL_ASSERT(cond) \
+ if (!(cond)) { \
+ Data_.failed = true; \
+ }
+ void RunReaders() {
+ Data_.mutex.AcquireRead();
+
+ AtomicIncrement(Data_.readersIn);
+ usleep(100);
+ FAIL_ASSERT(Data_.readersIn == long(Total_));
+ usleep(100);
+ AtomicDecrement(Data_.readersIn);
+
+ Data_.mutex.ReleaseRead();
+ }
+
+ void RunReadersWriters() {
+ if (Id_ % 2 == 0) {
+ for (size_t i = 0; i < 10; ++i) {
+ Data_.mutex.AcquireRead();
+
+ AtomicIncrement(Data_.readersIn);
+ FAIL_ASSERT(Data_.writersIn == 0);
+ usleep(RandomNumber<ui32>() % 5);
+ AtomicDecrement(Data_.readersIn);
+
+ Data_.mutex.ReleaseRead();
+ }
+ } else {
+ for (size_t i = 0; i < 10; ++i) {
+ Data_.mutex.AcquireWrite();
+
+ AtomicIncrement(Data_.writersIn);
+ FAIL_ASSERT(Data_.readersIn == 0 && Data_.writersIn == 1);
+ usleep(RandomNumber<ui32>() % 5);
+ AtomicDecrement(Data_.writersIn);
+
+ Data_.mutex.ReleaseWrite();
+ }
+ }
+ }
+#undef FAIL_ASSERT
+
+ private:
+ PFunc Func_;
+ TSharedData& Data_;
+ size_t Id_;
+ size_t Total_;
+ };
+
+private:
+#define RUN_CYCLE(what, count) \
+ Q_.Start(count); \
+ for (size_t i = 0; i < count; ++i) { \
+ UNIT_ASSERT(Q_.Add(new TThreadTask(&TThreadTask::what, Data_, i, count))); \
+ } \
+ Q_.Stop(); \
+ bool b = Data_.failed; \
+ Data_.failed = false; \
+ UNIT_ASSERT(!b);
+
+ void TestReaders() {
+ RUN_CYCLE(RunReaders, 1);
+ }
+
+ void TestReadersWriters() {
+ RUN_CYCLE(RunReadersWriters, 1);
+ }
+
+#undef RUN_CYCLE
+private:
+ TSharedData Data_;
+ TThreadPool Q_;
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TRWMutexTest)
diff --git a/library/cpp/threading/light_rw_lock/ut/ya.make b/library/cpp/threading/light_rw_lock/ut/ya.make
new file mode 100644
index 0000000000..92928b837c
--- /dev/null
+++ b/library/cpp/threading/light_rw_lock/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/threading/light_rw_lock)
+
+OWNER(agri)
+
+SRCS(
+ rwlock_ut.cpp
+)
+
+END()
diff --git a/library/cpp/threading/light_rw_lock/ya.make b/library/cpp/threading/light_rw_lock/ya.make
new file mode 100644
index 0000000000..a196fb8588
--- /dev/null
+++ b/library/cpp/threading/light_rw_lock/ya.make
@@ -0,0 +1,10 @@
+LIBRARY()
+
+OWNER(agri)
+
+SRCS(
+ lightrwlock.cpp
+ lightrwlock.h
+)
+
+END()
diff --git a/library/cpp/threading/local_executor/README.md b/library/cpp/threading/local_executor/README.md
new file mode 100644
index 0000000000..aaad2e2986
--- /dev/null
+++ b/library/cpp/threading/local_executor/README.md
@@ -0,0 +1,74 @@
+# Library for parallel task execution in thread pool
+
+This library allows easy parallelization of existing code and cycles.
+It provides `NPar::TLocalExecutor` class and `NPar::LocalExecutor()` singleton accessor.
+At start, `TLocalExecutor` has no threads in thread pool and all async tasks will be queued for later execution when extra threads appear.
+All tasks should be `NPar::ILocallyExecutable` child class or function equal to `std::function<void(int)>`
+
+## TLocalExecutor methods
+
+`TLocalExecutor::Run(int threadcount)` - add threads to thread pool (**WARNING!** `Run(threadcount)` will *add* `threadcount` threads to pool)
+
+`void TLocalExecutor::Exec(TLocallyExecutableFunction exec, int id, int flags)` - run one task and pass id as task function input, flags - bitmask composition of:
+
+- `TLocalExecutor::HIGH_PRIORITY = 0` - put task in high priority queue
+- `TLocalExecutor::MED_PRIORITY = 1` - put task in medium priority queue
+- `TLocalExecutor::LOW_PRIORITY = 2` - put task in low priority queue
+- `TLocalExecutor::WAIT_COMPLETE = 4` - wait for task completion
+
+`void TLocalExecutor::ExecRange(TLocallyExecutableFunction exec, TExecRangeParams blockParams, int flags);` - run range of tasks `[TExecRangeParams::FirstId, TExecRangeParams::LastId).`
+
+`flags` is the same as for `TLocalExecutor::Exec`.
+
+`TExecRangeParams` is a structure that describes the range.
+By default each task is executed separately. Threads from thread pool are taking
+the tasks in the manner first come first serve.
+
+It is also possible to partition range of tasks in consequtive blocks and execute each block as a bigger task.
+`TExecRangeParams::SetBlockCountToThreadCount()` will result in thread count tasks,
+ where thread count is the count of threads in thread pool.
+ each thread will execute approximately equal count of tasks from range.
+
+`TExecRangeParams::SetBlockSize()` and `TExecRangeParams::SetBlockCount()` will partition
+the range of tasks into consequtive blocks of approximately given size, or of size calculated
+ by partitioning the range into approximately equal size blocks of given count.
+
+## Examples
+
+### Simple task async exec with medium priority
+
+```cpp
+using namespace NPar;
+
+LocalExecutor().Run(4);
+TEvent event;
+LocalExecutor().Exec([](int) {
+ SomeFunc();
+ event.Signal();
+}, 0, TLocalExecutor::MED_PRIORITY);
+
+SomeOtherCode();
+event.WaitI();
+```
+
+### Execute task range and wait completion
+
+```cpp
+using namespace NPar;
+
+LocalExecutor().Run(4);
+LocalExecutor().ExecRange([](int id) {
+ SomeFunc(id);
+}, TExecRangeParams(0, 10), TLocalExecutor::WAIT_COMPLETE | TLocalExecutor::MED_PRIORITY);
+```
+
+### Exception handling
+
+By default if a not caught exception arise in a task which runs through the Local Executor, then std::terminate() will be called immediately. The exception will be printed to stderr before the termination. Best practice is to handle exception within a task, or avoid throwing exceptions at all for performance reasons.
+
+However, if you'd like to handle and/or rethrow exceptions outside of a range, you can use ExecRangeWithFuture().
+It returns vector [0 .. LastId-FirstId] elements, where i-th element is a TFuture corresponding to task with id = (FirstId + i).
+Use method .HasValue() of the element to check in Async mode if the corresponding task is complete.
+Use .GetValue() or .GetValueSync() to wait for completion of the corresponding task. GetValue() and GetValueSync() will also rethrow an exception if it appears during execution of the task.
+
+You may also use ExecRangeWithThrow() to just receive an exception from a range if it appears. It rethrows an exception from a task with minimal id if such an exception exists, and guarantees normal flow if no exception arise.
diff --git a/library/cpp/threading/local_executor/local_executor.cpp b/library/cpp/threading/local_executor/local_executor.cpp
new file mode 100644
index 0000000000..1d3fbb4bf4
--- /dev/null
+++ b/library/cpp/threading/local_executor/local_executor.cpp
@@ -0,0 +1,369 @@
+#include "local_executor.h"
+
+#include <library/cpp/threading/future/future.h>
+
+#include <util/generic/utility.h>
+#include <util/system/atomic.h>
+#include <util/system/event.h>
+#include <util/system/thread.h>
+#include <util/system/tls.h>
+#include <util/system/yield.h>
+#include <util/thread/lfqueue.h>
+
+#include <utility>
+
+#ifdef _win_
+static void RegularYield() {
+}
+#else
+// unix actually has cooperative multitasking! :)
+// without this function program runs slower and system lags for some magic reason
+static void RegularYield() {
+ SchedYield();
+}
+#endif
+
+namespace {
+ struct TFunctionWrapper : NPar::ILocallyExecutable {
+ NPar::TLocallyExecutableFunction Exec;
+ TFunctionWrapper(NPar::TLocallyExecutableFunction exec)
+ : Exec(std::move(exec))
+ {
+ }
+ void LocalExec(int id) override {
+ Exec(id);
+ }
+ };
+
+ class TFunctionWrapperWithPromise: public NPar::ILocallyExecutable {
+ private:
+ NPar::TLocallyExecutableFunction Exec;
+ int FirstId, LastId;
+ TVector<NThreading::TPromise<void>> Promises;
+
+ public:
+ TFunctionWrapperWithPromise(NPar::TLocallyExecutableFunction exec, int firstId, int lastId)
+ : Exec(std::move(exec))
+ , FirstId(firstId)
+ , LastId(lastId)
+ {
+ Y_ASSERT(FirstId <= LastId);
+ const int rangeSize = LastId - FirstId;
+ Promises.resize(rangeSize, NThreading::NewPromise());
+ for (auto& promise : Promises) {
+ promise = NThreading::NewPromise();
+ }
+ }
+
+ void LocalExec(int id) override {
+ Y_ASSERT(FirstId <= id && id < LastId);
+ NThreading::NImpl::SetValue(Promises[id - FirstId], [=] { Exec(id); });
+ }
+
+ TVector<NThreading::TFuture<void>> GetFutures() const {
+ TVector<NThreading::TFuture<void>> out;
+ out.reserve(Promises.ysize());
+ for (auto& promise : Promises) {
+ out.push_back(promise.GetFuture());
+ }
+ return out;
+ }
+ };
+
+ struct TSingleJob {
+ TIntrusivePtr<NPar::ILocallyExecutable> Exec;
+ int Id{0};
+
+ TSingleJob() = default;
+ TSingleJob(TIntrusivePtr<NPar::ILocallyExecutable> exec, int id)
+ : Exec(std::move(exec))
+ , Id(id)
+ {
+ }
+ };
+
+ class TLocalRangeExecutor: public NPar::ILocallyExecutable {
+ TIntrusivePtr<NPar::ILocallyExecutable> Exec;
+ alignas(64) TAtomic Counter;
+ alignas(64) TAtomic WorkerCount;
+ int LastId;
+
+ void LocalExec(int) override {
+ AtomicAdd(WorkerCount, 1);
+ for (;;) {
+ if (!DoSingleOp())
+ break;
+ }
+ AtomicAdd(WorkerCount, -1);
+ }
+
+ public:
+ TLocalRangeExecutor(TIntrusivePtr<ILocallyExecutable> exec, int firstId, int lastId)
+ : Exec(std::move(exec))
+ , Counter(firstId)
+ , WorkerCount(0)
+ , LastId(lastId)
+ {
+ }
+ bool DoSingleOp() {
+ const int id = AtomicAdd(Counter, 1) - 1;
+ if (id >= LastId)
+ return false;
+ Exec->LocalExec(id);
+ RegularYield();
+ return true;
+ }
+ void WaitComplete() {
+ while (AtomicGet(WorkerCount) > 0)
+ RegularYield();
+ }
+ int GetRangeSize() const {
+ return Max<int>(LastId - Counter, 0);
+ }
+ };
+
+}
+
+//////////////////////////////////////////////////////////////////////////
+class NPar::TLocalExecutor::TImpl {
+public:
+ TLockFreeQueue<TSingleJob> JobQueue;
+ TLockFreeQueue<TSingleJob> MedJobQueue;
+ TLockFreeQueue<TSingleJob> LowJobQueue;
+ alignas(64) TSystemEvent HasJob;
+
+ TAtomic ThreadCount{0};
+ alignas(64) TAtomic QueueSize{0};
+ TAtomic MPQueueSize{0};
+ TAtomic LPQueueSize{0};
+ TAtomic ThreadId{0};
+
+ Y_THREAD(int)
+ CurrentTaskPriority;
+ Y_THREAD(int)
+ WorkerThreadId;
+
+ static void* HostWorkerThread(void* p);
+ bool GetJob(TSingleJob* job);
+ void RunNewThread();
+ void LaunchRange(TIntrusivePtr<TLocalRangeExecutor> execRange, int queueSizeLimit,
+ TAtomic* queueSize, TLockFreeQueue<TSingleJob>* jobQueue);
+
+ TImpl() = default;
+ ~TImpl();
+};
+
+NPar::TLocalExecutor::TImpl::~TImpl() {
+ AtomicAdd(QueueSize, 1);
+ JobQueue.Enqueue(TSingleJob(nullptr, 0));
+ HasJob.Signal();
+ while (AtomicGet(ThreadCount)) {
+ ThreadYield();
+ }
+}
+
+void* NPar::TLocalExecutor::TImpl::HostWorkerThread(void* p) {
+ static const int FAST_ITERATIONS = 200;
+
+ auto* const ctx = (TImpl*)p;
+ TThread::SetCurrentThreadName("ParLocalExecutor");
+ ctx->WorkerThreadId = AtomicAdd(ctx->ThreadId, 1);
+ for (bool cont = true; cont;) {
+ TSingleJob job;
+ bool gotJob = false;
+ for (int iter = 0; iter < FAST_ITERATIONS; ++iter) {
+ if (ctx->GetJob(&job)) {
+ gotJob = true;
+ break;
+ }
+ }
+ if (!gotJob) {
+ ctx->HasJob.Reset();
+ if (!ctx->GetJob(&job)) {
+ ctx->HasJob.Wait();
+ continue;
+ }
+ }
+ if (job.Exec.Get()) {
+ job.Exec->LocalExec(job.Id);
+ RegularYield();
+ } else {
+ AtomicAdd(ctx->QueueSize, 1);
+ ctx->JobQueue.Enqueue(job);
+ ctx->HasJob.Signal();
+ cont = false;
+ }
+ }
+ AtomicAdd(ctx->ThreadCount, -1);
+ return nullptr;
+}
+
+bool NPar::TLocalExecutor::TImpl::GetJob(TSingleJob* job) {
+ if (JobQueue.Dequeue(job)) {
+ CurrentTaskPriority = TLocalExecutor::HIGH_PRIORITY;
+ AtomicAdd(QueueSize, -1);
+ return true;
+ } else if (MedJobQueue.Dequeue(job)) {
+ CurrentTaskPriority = TLocalExecutor::MED_PRIORITY;
+ AtomicAdd(MPQueueSize, -1);
+ return true;
+ } else if (LowJobQueue.Dequeue(job)) {
+ CurrentTaskPriority = TLocalExecutor::LOW_PRIORITY;
+ AtomicAdd(LPQueueSize, -1);
+ return true;
+ }
+ return false;
+}
+
+void NPar::TLocalExecutor::TImpl::RunNewThread() {
+ AtomicAdd(ThreadCount, 1);
+ TThread thr(HostWorkerThread, this);
+ thr.Start();
+ thr.Detach();
+}
+
+void NPar::TLocalExecutor::TImpl::LaunchRange(TIntrusivePtr<TLocalRangeExecutor> rangeExec,
+ int queueSizeLimit,
+ TAtomic* queueSize,
+ TLockFreeQueue<TSingleJob>* jobQueue) {
+ int count = Min<int>(ThreadCount + 1, rangeExec->GetRangeSize());
+ if (queueSizeLimit >= 0 && AtomicGet(*queueSize) >= queueSizeLimit) {
+ return;
+ }
+ AtomicAdd(*queueSize, count);
+ jobQueue->EnqueueAll(TVector<TSingleJob>{size_t(count), TSingleJob(rangeExec, 0)});
+ HasJob.Signal();
+}
+
+NPar::TLocalExecutor::TLocalExecutor()
+ : Impl_{MakeHolder<TImpl>()} {
+}
+
+NPar::TLocalExecutor::~TLocalExecutor() = default;
+
+void NPar::TLocalExecutor::RunAdditionalThreads(int threadCount) {
+ for (int i = 0; i < threadCount; i++)
+ Impl_->RunNewThread();
+}
+
+void NPar::TLocalExecutor::Exec(TIntrusivePtr<ILocallyExecutable> exec, int id, int flags) {
+ Y_ASSERT((flags & WAIT_COMPLETE) == 0); // unsupported
+ int prior = Max<int>(Impl_->CurrentTaskPriority, flags & PRIORITY_MASK);
+ switch (prior) {
+ case HIGH_PRIORITY:
+ AtomicAdd(Impl_->QueueSize, 1);
+ Impl_->JobQueue.Enqueue(TSingleJob(std::move(exec), id));
+ break;
+ case MED_PRIORITY:
+ AtomicAdd(Impl_->MPQueueSize, 1);
+ Impl_->MedJobQueue.Enqueue(TSingleJob(std::move(exec), id));
+ break;
+ case LOW_PRIORITY:
+ AtomicAdd(Impl_->LPQueueSize, 1);
+ Impl_->LowJobQueue.Enqueue(TSingleJob(std::move(exec), id));
+ break;
+ default:
+ Y_ASSERT(0);
+ break;
+ }
+ Impl_->HasJob.Signal();
+}
+
+void NPar::ILocalExecutor::Exec(TLocallyExecutableFunction exec, int id, int flags) {
+ Exec(new TFunctionWrapper(std::move(exec)), id, flags);
+}
+
+void NPar::TLocalExecutor::ExecRange(TIntrusivePtr<ILocallyExecutable> exec, int firstId, int lastId, int flags) {
+ Y_ASSERT(lastId >= firstId);
+ if (TryExecRangeSequentially([=] (int id) { exec->LocalExec(id); }, firstId, lastId, flags)) {
+ return;
+ }
+ auto rangeExec = MakeIntrusive<TLocalRangeExecutor>(std::move(exec), firstId, lastId);
+ int queueSizeLimit = (flags & WAIT_COMPLETE) ? 10000 : -1;
+ int prior = Max<int>(Impl_->CurrentTaskPriority, flags & PRIORITY_MASK);
+ switch (prior) {
+ case HIGH_PRIORITY:
+ Impl_->LaunchRange(rangeExec, queueSizeLimit, &Impl_->QueueSize, &Impl_->JobQueue);
+ break;
+ case MED_PRIORITY:
+ Impl_->LaunchRange(rangeExec, queueSizeLimit, &Impl_->MPQueueSize, &Impl_->MedJobQueue);
+ break;
+ case LOW_PRIORITY:
+ Impl_->LaunchRange(rangeExec, queueSizeLimit, &Impl_->LPQueueSize, &Impl_->LowJobQueue);
+ break;
+ default:
+ Y_ASSERT(0);
+ break;
+ }
+ if (flags & WAIT_COMPLETE) {
+ int keepPrior = Impl_->CurrentTaskPriority;
+ Impl_->CurrentTaskPriority = prior;
+ while (rangeExec->DoSingleOp()) {
+ }
+ Impl_->CurrentTaskPriority = keepPrior;
+ rangeExec->WaitComplete();
+ }
+}
+
+void NPar::ILocalExecutor::ExecRange(TLocallyExecutableFunction exec, int firstId, int lastId, int flags) {
+ if (TryExecRangeSequentially(exec, firstId, lastId, flags)) {
+ return;
+ }
+ ExecRange(new TFunctionWrapper(exec), firstId, lastId, flags);
+}
+
+void NPar::ILocalExecutor::ExecRangeWithThrow(TLocallyExecutableFunction exec, int firstId, int lastId, int flags) {
+ Y_VERIFY((flags & WAIT_COMPLETE) != 0, "ExecRangeWithThrow() requires WAIT_COMPLETE to wait if exceptions arise.");
+ if (TryExecRangeSequentially(exec, firstId, lastId, flags)) {
+ return;
+ }
+ TVector<NThreading::TFuture<void>> currentRun = ExecRangeWithFutures(exec, firstId, lastId, flags);
+ for (auto& result : currentRun) {
+ result.GetValueSync(); // Exception will be rethrown if exists. If several exception - only the one with minimal id is rethrown.
+ }
+}
+
+TVector<NThreading::TFuture<void>>
+NPar::ILocalExecutor::ExecRangeWithFutures(TLocallyExecutableFunction exec, int firstId, int lastId, int flags) {
+ TFunctionWrapperWithPromise* execWrapper = new TFunctionWrapperWithPromise(exec, firstId, lastId);
+ TVector<NThreading::TFuture<void>> out = execWrapper->GetFutures();
+ ExecRange(execWrapper, firstId, lastId, flags);
+ return out;
+}
+
+void NPar::TLocalExecutor::ClearLPQueue() {
+ for (bool cont = true; cont;) {
+ cont = false;
+ TSingleJob job;
+ while (Impl_->LowJobQueue.Dequeue(&job)) {
+ AtomicAdd(Impl_->LPQueueSize, -1);
+ cont = true;
+ }
+ while (Impl_->MedJobQueue.Dequeue(&job)) {
+ AtomicAdd(Impl_->MPQueueSize, -1);
+ cont = true;
+ }
+ }
+}
+
+int NPar::TLocalExecutor::GetQueueSize() const noexcept {
+ return AtomicGet(Impl_->QueueSize);
+}
+
+int NPar::TLocalExecutor::GetMPQueueSize() const noexcept {
+ return AtomicGet(Impl_->MPQueueSize);
+}
+
+int NPar::TLocalExecutor::GetLPQueueSize() const noexcept {
+ return AtomicGet(Impl_->LPQueueSize);
+}
+
+int NPar::TLocalExecutor::GetWorkerThreadId() const noexcept {
+ return Impl_->WorkerThreadId;
+}
+
+int NPar::TLocalExecutor::GetThreadCount() const noexcept {
+ return AtomicGet(Impl_->ThreadCount);
+}
+
+//////////////////////////////////////////////////////////////////////////
diff --git a/library/cpp/threading/local_executor/local_executor.h b/library/cpp/threading/local_executor/local_executor.h
new file mode 100644
index 0000000000..c1c824f67c
--- /dev/null
+++ b/library/cpp/threading/local_executor/local_executor.h
@@ -0,0 +1,294 @@
+#pragma once
+
+#include <library/cpp/threading/future/future.h>
+
+#include <util/generic/cast.h>
+#include <util/generic/fwd.h>
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/generic/singleton.h>
+#include <util/generic/ymath.h>
+
+#include <functional>
+
+namespace NPar {
+ struct ILocallyExecutable : virtual public TThrRefBase {
+ // Must be implemented by the end user to define job that will be processed by one of
+ // executor threads.
+ //
+ // @param id Job parameter, typically an index pointing somewhere in array, or just
+ // some dummy value, e.g. `0`.
+ virtual void LocalExec(int id) = 0;
+ };
+
+ // Alternative and simpler way of describing a job for executor. Function argument has the
+ // same meaning as `id` in `ILocallyExecutable::LocalExec`.
+ //
+ using TLocallyExecutableFunction = std::function<void(int)>;
+
+ class ILocalExecutor: public TNonCopyable {
+ public:
+ ILocalExecutor() = default;
+ virtual ~ILocalExecutor() = default;
+
+ enum EFlags : int {
+ HIGH_PRIORITY = 0,
+ MED_PRIORITY = 1,
+ LOW_PRIORITY = 2,
+ PRIORITY_MASK = 3,
+ WAIT_COMPLETE = 4
+ };
+
+ // Add task for further execution.
+ //
+ // @param exec Task description.
+ // @param id Task argument.
+ // @param flags Bitmask composed by `HIGH_PRIORITY`, `MED_PRIORITY`, `LOW_PRIORITY`
+ // and `WAIT_COMPLETE`.
+ virtual void Exec(TIntrusivePtr<ILocallyExecutable> exec, int id, int flags) = 0;
+
+ // Add tasks range for further execution.
+ //
+ // @param exec Task description.
+ // @param firstId, lastId Task arguments [firstId, lastId)
+ // @param flags Same as for `Exec`.
+ virtual void ExecRange(TIntrusivePtr<ILocallyExecutable> exec, int firstId, int lastId, int flags) = 0;
+
+ // 0-based ILocalExecutor worker thread identification
+ virtual int GetWorkerThreadId() const noexcept = 0;
+ virtual int GetThreadCount() const noexcept = 0;
+
+ // Describes a range of tasks with parameters from integer range [FirstId, LastId).
+ //
+ class TExecRangeParams {
+ public:
+ template <typename TFirst, typename TLast>
+ TExecRangeParams(TFirst firstId, TLast lastId)
+ : FirstId(SafeIntegerCast<int>(firstId))
+ , LastId(SafeIntegerCast<int>(lastId))
+ {
+ Y_ASSERT(LastId >= FirstId);
+ SetBlockSize(1);
+ }
+ // Partition tasks into `blockCount` blocks of approximately equal size, each of which
+ // will be executed as a separate bigger task.
+ //
+ template <typename TBlockCount>
+ TExecRangeParams& SetBlockCount(TBlockCount blockCount) {
+ Y_ASSERT(SafeIntegerCast<int>(blockCount) > 0 || FirstId == LastId);
+ BlockSize = FirstId == LastId ? 0 : CeilDiv(LastId - FirstId, SafeIntegerCast<int>(blockCount));
+ BlockCount = BlockSize == 0 ? 0 : CeilDiv(LastId - FirstId, BlockSize);
+ BlockEqualToThreads = false;
+ return *this;
+ }
+ // Partition tasks into blocks of approximately `blockSize` size, each of which will
+ // be executed as a separate bigger task.
+ //
+ template <typename TBlockSize>
+ TExecRangeParams& SetBlockSize(TBlockSize blockSize) {
+ Y_ASSERT(SafeIntegerCast<int>(blockSize) > 0 || FirstId == LastId);
+ BlockSize = SafeIntegerCast<int>(blockSize);
+ BlockCount = BlockSize == 0 ? 0 : CeilDiv(LastId - FirstId, BlockSize);
+ BlockEqualToThreads = false;
+ return *this;
+ }
+ // Partition tasks into thread count blocks of approximately equal size, each of which
+ // will be executed as a separate bigger task.
+ //
+ TExecRangeParams& SetBlockCountToThreadCount() {
+ BlockEqualToThreads = true;
+ return *this;
+ }
+ int GetBlockCount() const {
+ Y_ASSERT(!BlockEqualToThreads);
+ return BlockCount;
+ }
+ int GetBlockSize() const {
+ Y_ASSERT(!BlockEqualToThreads);
+ return BlockSize;
+ }
+ bool GetBlockEqualToThreads() {
+ return BlockEqualToThreads;
+ }
+
+ const int FirstId = 0;
+ const int LastId = 0;
+
+ private:
+ int BlockSize;
+ int BlockCount;
+ bool BlockEqualToThreads;
+ };
+
+ // `Exec` and `ExecRange` versions that accept functions.
+ //
+ void Exec(TLocallyExecutableFunction exec, int id, int flags);
+ void ExecRange(TLocallyExecutableFunction exec, int firstId, int lastId, int flags);
+
+ // Version of `ExecRange` that throws exception from task with minimal id if at least one of
+ // task threw an exception.
+ //
+ void ExecRangeWithThrow(TLocallyExecutableFunction exec, int firstId, int lastId, int flags);
+
+ // Version of `ExecRange` that returns vector of futures, thus allowing to retry any task if
+ // it fails.
+ //
+ TVector<NThreading::TFuture<void>> ExecRangeWithFutures(TLocallyExecutableFunction exec, int firstId, int lastId, int flags);
+
+ template <typename TBody>
+ static inline auto BlockedLoopBody(const TExecRangeParams& params, const TBody& body) {
+ return [=](int blockId) {
+ const int blockFirstId = params.FirstId + blockId * params.GetBlockSize();
+ const int blockLastId = Min(params.LastId, blockFirstId + params.GetBlockSize());
+ for (int i = blockFirstId; i < blockLastId; ++i) {
+ body(i);
+ }
+ };
+ }
+
+ template <typename TBody>
+ inline void ExecRange(TBody&& body, TExecRangeParams params, int flags) {
+ if (TryExecRangeSequentially(body, params.FirstId, params.LastId, flags)) {
+ return;
+ }
+ if (params.GetBlockEqualToThreads()) {
+ params.SetBlockCount(GetThreadCount() + ((flags & WAIT_COMPLETE) != 0)); // ThreadCount or ThreadCount+1 depending on WaitFlag
+ }
+ ExecRange(BlockedLoopBody(params, body), 0, params.GetBlockCount(), flags);
+ }
+
+ template <typename TBody>
+ inline void ExecRangeBlockedWithThrow(TBody&& body, int firstId, int lastId, int batchSizeOrZeroForAutoBatchSize, int flags) {
+ if (firstId >= lastId) {
+ return;
+ }
+ const int threadCount = Max(GetThreadCount(), 1);
+ const int batchSize = batchSizeOrZeroForAutoBatchSize
+ ? batchSizeOrZeroForAutoBatchSize
+ : (lastId - firstId + threadCount - 1) / threadCount;
+ const int batchCount = (lastId - firstId + batchSize - 1) / batchSize;
+ const int batchCountPerThread = (batchCount + threadCount - 1) / threadCount;
+ auto states = ExecRangeWithFutures(
+ [=](int threadId) {
+ for (int batchIdPerThread = 0; batchIdPerThread < batchCountPerThread; ++batchIdPerThread) {
+ int batchId = batchIdPerThread * threadCount + threadId;
+ int begin = firstId + batchId * batchSize;
+ int end = Min(begin + batchSize, lastId);
+ for (int i = begin; i < end; ++i) {
+ body(i);
+ }
+ }
+ },
+ 0, threadCount, flags);
+ for (auto& state: states) {
+ state.GetValueSync(); // Re-throw exception if any.
+ }
+ }
+
+ template <typename TBody>
+ static inline bool TryExecRangeSequentially(TBody&& body, int firstId, int lastId, int flags) {
+ if (lastId == firstId) {
+ return true;
+ }
+ if ((flags & WAIT_COMPLETE) && lastId - firstId == 1) {
+ body(firstId);
+ return true;
+ }
+ return false;
+ }
+ };
+
+ // `TLocalExecutor` provides facilities for easy parallelization of existing code and cycles.
+ //
+ // Examples:
+ // Execute one task with medium priority and wait for it completion.
+ // ```
+ // LocalExecutor().Run(4);
+ // TEvent event;
+ // LocalExecutor().Exec([](int) {
+ // SomeFunc();
+ // event.Signal();
+ // }, 0, TLocalExecutor::MED_PRIORITY);
+ //
+ // SomeOtherCode();
+ // event.WaitI();
+ // ```
+ //
+ // Execute range of tasks with medium priority.
+ // ```
+ // LocalExecutor().Run(4);
+ // LocalExecutor().ExecRange([](int id) {
+ // SomeFunc(id);
+ // }, TExecRangeParams(0, 10), TLocalExecutor::WAIT_COMPLETE | TLocalExecutor::MED_PRIORITY);
+ // ```
+ //
+ class TLocalExecutor final: public ILocalExecutor {
+ public:
+ using EFlags = ILocalExecutor::EFlags;
+
+ // Creates executor without threads. You'll need to explicitly call `RunAdditionalThreads`
+ // to add threads to underlying thread pool.
+ //
+ TLocalExecutor();
+ ~TLocalExecutor();
+
+ int GetQueueSize() const noexcept;
+ int GetMPQueueSize() const noexcept;
+ int GetLPQueueSize() const noexcept;
+ void ClearLPQueue();
+
+ // 0-based TLocalExecutor worker thread identification
+ int GetWorkerThreadId() const noexcept override;
+ int GetThreadCount() const noexcept override;
+
+ // **Add** threads to underlying thread pool.
+ //
+ // @param threadCount Number of threads to add.
+ void RunAdditionalThreads(int threadCount);
+
+ // Add task for further execution.
+ //
+ // @param exec Task description.
+ // @param id Task argument.
+ // @param flags Bitmask composed by `HIGH_PRIORITY`, `MED_PRIORITY`, `LOW_PRIORITY`
+ // and `WAIT_COMPLETE`.
+ void Exec(TIntrusivePtr<ILocallyExecutable> exec, int id, int flags) override;
+
+ // Add tasks range for further execution.
+ //
+ // @param exec Task description.
+ // @param firstId, lastId Task arguments [firstId, lastId)
+ // @param flags Same as for `Exec`.
+ void ExecRange(TIntrusivePtr<ILocallyExecutable> exec, int firstId, int lastId, int flags) override;
+
+ using ILocalExecutor::Exec;
+ using ILocalExecutor::ExecRange;
+
+ private:
+ class TImpl;
+ THolder<TImpl> Impl_;
+ };
+
+ static inline TLocalExecutor& LocalExecutor() {
+ return *Singleton<TLocalExecutor>();
+ }
+
+ template <typename TBody>
+ inline void ParallelFor(ILocalExecutor& executor, ui32 from, ui32 to, TBody&& body) {
+ ILocalExecutor::TExecRangeParams params(from, to);
+ params.SetBlockCountToThreadCount();
+ executor.ExecRange(std::forward<TBody>(body), params, TLocalExecutor::WAIT_COMPLETE);
+ }
+
+ template <typename TBody>
+ inline void ParallelFor(ui32 from, ui32 to, TBody&& body) {
+ ParallelFor(LocalExecutor(), from, to, std::forward<TBody>(body));
+ }
+
+ template <typename TBody>
+ inline void AsyncParallelFor(ui32 from, ui32 to, TBody&& body) {
+ ILocalExecutor::TExecRangeParams params(from, to);
+ params.SetBlockCountToThreadCount();
+ LocalExecutor().ExecRange(std::forward<TBody>(body), params, 0);
+ }
+}
diff --git a/library/cpp/threading/local_executor/tbb_local_executor.cpp b/library/cpp/threading/local_executor/tbb_local_executor.cpp
new file mode 100644
index 0000000000..65d6659443
--- /dev/null
+++ b/library/cpp/threading/local_executor/tbb_local_executor.cpp
@@ -0,0 +1,53 @@
+#include "tbb_local_executor.h"
+
+template <bool RespectTls>
+void NPar::TTbbLocalExecutor<RespectTls>::SubmitAsyncTasks(TLocallyExecutableFunction exec, int firstId, int lastId) {
+ for (int i = firstId; i < lastId; ++i) {
+ Group.run([=] { exec(i); });
+ }
+}
+
+template <bool RespectTls>
+int NPar::TTbbLocalExecutor<RespectTls>::GetThreadCount() const noexcept {
+ return NumberOfTbbThreads - 1;
+}
+
+template <bool RespectTls>
+int NPar::TTbbLocalExecutor<RespectTls>::GetWorkerThreadId() const noexcept {
+ return TbbArena.execute([] {
+ return tbb::this_task_arena::current_thread_index();
+ });
+}
+
+template <bool RespectTls>
+void NPar::TTbbLocalExecutor<RespectTls>::Exec(TIntrusivePtr<ILocallyExecutable> exec, int id, int flags) {
+ if (flags & WAIT_COMPLETE) {
+ exec->LocalExec(id);
+ } else {
+ TbbArena.execute([=] {
+ SubmitAsyncTasks([=] (int id) { exec->LocalExec(id); }, id, id + 1);
+ });
+ }
+}
+
+template <bool RespectTls>
+void NPar::TTbbLocalExecutor<RespectTls>::ExecRange(TIntrusivePtr<ILocallyExecutable> exec, int firstId, int lastId, int flags) {
+ if (flags & WAIT_COMPLETE) {
+ TbbArena.execute([=] {
+ if (RespectTls) {
+ tbb::this_task_arena::isolate([=]{
+ tbb::parallel_for(firstId, lastId, [=] (int id) { exec->LocalExec(id); });
+ });
+ } else {
+ tbb::parallel_for(firstId, lastId, [=] (int id) { exec->LocalExec(id); });
+ }
+ });
+ } else {
+ TbbArena.execute([=] {
+ SubmitAsyncTasks([=] (int id) { exec->LocalExec(id); }, firstId, lastId);
+ });
+ }
+}
+
+template class NPar::TTbbLocalExecutor<true>;
+template class NPar::TTbbLocalExecutor<false>;
diff --git a/library/cpp/threading/local_executor/tbb_local_executor.h b/library/cpp/threading/local_executor/tbb_local_executor.h
new file mode 100644
index 0000000000..8d790db18c
--- /dev/null
+++ b/library/cpp/threading/local_executor/tbb_local_executor.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "local_executor.h"
+#define __TBB_TASK_ISOLATION 1
+#define __TBB_NO_IMPLICIT_LINKAGE 1
+
+#include <contrib/libs/tbb/include/tbb/blocked_range.h>
+#include <contrib/libs/tbb/include/tbb/parallel_for.h>
+#include <contrib/libs/tbb/include/tbb/task_arena.h>
+#include <contrib/libs/tbb/include/tbb/task_group.h>
+
+namespace NPar {
+ template <bool RespectTls = false>
+ class TTbbLocalExecutor final: public ILocalExecutor {
+ public:
+ TTbbLocalExecutor(int nThreads)
+ : ILocalExecutor()
+ , TbbArena(nThreads)
+ , NumberOfTbbThreads(nThreads) {}
+ ~TTbbLocalExecutor() noexcept override {}
+
+ // 0-based ILocalExecutor worker thread identification
+ virtual int GetWorkerThreadId() const noexcept override;
+ virtual int GetThreadCount() const noexcept override;
+
+ // Add task for further execution.
+ //
+ // @param exec Task description.
+ // @param id Task argument.
+ // @param flags Bitmask composed by `HIGH_PRIORITY`, `MED_PRIORITY`, `LOW_PRIORITY`
+ // and `WAIT_COMPLETE`.
+ virtual void Exec(TIntrusivePtr<ILocallyExecutable> exec, int id, int flags) override;
+
+ // Add tasks range for further execution.
+ //
+ // @param exec Task description.
+ // @param firstId, lastId Task arguments [firstId, lastId)
+ // @param flags Same as for `Exec`.
+ virtual void ExecRange(TIntrusivePtr<ILocallyExecutable> exec, int firstId, int lastId, int flags) override;
+
+ // Submit tasks for async run
+ void SubmitAsyncTasks(TLocallyExecutableFunction exec, int firstId, int lastId);
+
+ private:
+ mutable tbb::task_arena TbbArena;
+ tbb::task_group Group;
+ int NumberOfTbbThreads;
+ };
+}
diff --git a/library/cpp/threading/local_executor/ut/local_executor_ut.cpp b/library/cpp/threading/local_executor/ut/local_executor_ut.cpp
new file mode 100644
index 0000000000..ac5737717c
--- /dev/null
+++ b/library/cpp/threading/local_executor/ut/local_executor_ut.cpp
@@ -0,0 +1,371 @@
+#include <library/cpp/threading/local_executor/local_executor.h>
+#include <library/cpp/threading/future/future.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/system/mutex.h>
+#include <util/system/rwlock.h>
+#include <util/generic/algorithm.h>
+
+using namespace NPar;
+
+class TTestException: public yexception {
+};
+
+static const int DefaultThreadsCount = 41;
+static const int DefaultRangeSize = 999;
+
+Y_UNIT_TEST_SUITE(ExecRangeWithFutures){
+ bool AllOf(const TVector<int>& vec, int value){
+ return AllOf(vec, [value](int element) { return value == element; });
+}
+
+void AsyncRunAndWaitFuturesReady(int rangeSize, int threads) {
+ TLocalExecutor localExecutor;
+ localExecutor.RunAdditionalThreads(threads);
+ TAtomic signal = 0;
+ TVector<int> data(rangeSize, 0);
+ TVector<NThreading::TFuture<void>> futures = localExecutor.ExecRangeWithFutures([&signal, &data](int i) {
+ UNIT_ASSERT(data[i] == 0);
+ while (AtomicGet(signal) == 0)
+ ;
+ data[i] += 1;
+ },
+ 0, rangeSize, TLocalExecutor::HIGH_PRIORITY);
+ UNIT_ASSERT(AllOf(data, 0));
+ for (auto& future : futures)
+ UNIT_ASSERT(!future.HasValue());
+ AtomicSet(signal, 1);
+ for (auto& future : futures) {
+ future.GetValueSync();
+ }
+ UNIT_ASSERT(AllOf(data, 1));
+}
+
+Y_UNIT_TEST(AsyncRunRangeAndWaitFuturesReady) {
+ AsyncRunAndWaitFuturesReady(DefaultRangeSize, DefaultThreadsCount);
+}
+
+Y_UNIT_TEST(AsyncRunOneTaskAndWaitFuturesReady) {
+ AsyncRunAndWaitFuturesReady(1, DefaultThreadsCount);
+}
+
+Y_UNIT_TEST(AsyncRunRangeAndWaitFuturesReadyOneExtraThread) {
+ AsyncRunAndWaitFuturesReady(DefaultRangeSize, 1);
+}
+
+Y_UNIT_TEST(AsyncRunOneThreadAndWaitFuturesReadyOneExtraThread) {
+ AsyncRunAndWaitFuturesReady(1, 1);
+}
+
+Y_UNIT_TEST(AsyncRunTwoRangesAndWaitFuturesReady) {
+ TLocalExecutor localExecutor;
+ localExecutor.RunAdditionalThreads(DefaultThreadsCount);
+ TAtomic signal = 0;
+ TVector<int> data1(DefaultRangeSize, 0);
+ TVector<NThreading::TFuture<void>> futures1 = localExecutor.ExecRangeWithFutures([&signal, &data1](int i) {
+ UNIT_ASSERT(data1[i] == 0);
+ while (AtomicGet(signal) == 0)
+ ;
+ data1[i] += 1;
+ },
+ 0, DefaultRangeSize, TLocalExecutor::HIGH_PRIORITY);
+ TVector<int> data2(DefaultRangeSize, 0);
+ TVector<NThreading::TFuture<void>> futures2 = localExecutor.ExecRangeWithFutures([&signal, &data2](int i) {
+ UNIT_ASSERT(data2[i] == 0);
+ while (AtomicGet(signal) == 0)
+ ;
+ data2[i] += 2;
+ },
+ 0, DefaultRangeSize, TLocalExecutor::HIGH_PRIORITY);
+ UNIT_ASSERT(AllOf(data1, 0));
+ UNIT_ASSERT(AllOf(data2, 0));
+ AtomicSet(signal, 1);
+ for (int i = 0; i < DefaultRangeSize; ++i) {
+ futures1[i].GetValueSync();
+ futures2[i].GetValueSync();
+ }
+ UNIT_ASSERT(AllOf(data1, 1));
+ UNIT_ASSERT(AllOf(data2, 2));
+}
+
+void AsyncRunRangeAndWaitExceptions(int rangeSize, int threadsCount) {
+ TLocalExecutor localExecutor;
+ localExecutor.RunAdditionalThreads(threadsCount);
+ TAtomic signal = 0;
+ TVector<int> data(rangeSize, 0);
+ TVector<NThreading::TFuture<void>> futures = localExecutor.ExecRangeWithFutures([&signal, &data](int i) {
+ UNIT_ASSERT(data[i] == 0);
+ while (AtomicGet(signal) == 0)
+ ;
+ data[i] += 1;
+ throw 10000 + i;
+ },
+ 0, rangeSize, TLocalExecutor::HIGH_PRIORITY);
+ UNIT_ASSERT(AllOf(data, 0));
+ UNIT_ASSERT(futures.ysize() == rangeSize);
+ AtomicSet(signal, 1);
+ int exceptionsCaught = 0;
+ for (int i = 0; i < rangeSize; ++i) {
+ try {
+ futures[i].GetValueSync();
+ } catch (int& e) {
+ if (e == 10000 + i) {
+ ++exceptionsCaught;
+ }
+ }
+ }
+ UNIT_ASSERT(exceptionsCaught == rangeSize);
+ UNIT_ASSERT(AllOf(data, 1));
+}
+
+Y_UNIT_TEST(AsyncRunRangeAndWaitExceptions) {
+ AsyncRunRangeAndWaitExceptions(DefaultRangeSize, DefaultThreadsCount);
+}
+
+Y_UNIT_TEST(AsyncRunOneTaskAndWaitExceptions) {
+ AsyncRunRangeAndWaitExceptions(1, DefaultThreadsCount);
+}
+
+Y_UNIT_TEST(AsyncRunRangeAndWaitExceptionsOneExtraThread) {
+ AsyncRunRangeAndWaitExceptions(DefaultRangeSize, 1);
+}
+
+Y_UNIT_TEST(AsyncRunOneTaskAndWaitExceptionsOneExtraThread) {
+ AsyncRunRangeAndWaitExceptions(1, 1);
+}
+
+Y_UNIT_TEST(AsyncRunTwoRangesAndWaitExceptions) {
+ TLocalExecutor localExecutor;
+ localExecutor.RunAdditionalThreads(DefaultThreadsCount);
+ TAtomic signal = 0;
+ TVector<int> data1(DefaultRangeSize, 0);
+ TVector<NThreading::TFuture<void>> futures1 = localExecutor.ExecRangeWithFutures([&signal, &data1](int i) {
+ UNIT_ASSERT(data1[i] == 0);
+ while (AtomicGet(signal) == 0)
+ ;
+ data1[i] += 1;
+ throw 15000 + i;
+ },
+ 0, DefaultRangeSize, TLocalExecutor::LOW_PRIORITY);
+ TVector<int> data2(DefaultRangeSize, 0);
+ TVector<NThreading::TFuture<void>> futures2 = localExecutor.ExecRangeWithFutures([&signal, &data2](int i) {
+ UNIT_ASSERT(data2[i] == 0);
+ while (AtomicGet(signal) == 0)
+ ;
+ data2[i] += 2;
+ throw 16000 + i;
+ },
+ 0, DefaultRangeSize, TLocalExecutor::HIGH_PRIORITY);
+
+ UNIT_ASSERT(AllOf(data1, 0));
+ UNIT_ASSERT(AllOf(data2, 0));
+ UNIT_ASSERT(futures1.size() == DefaultRangeSize);
+ UNIT_ASSERT(futures2.size() == DefaultRangeSize);
+ AtomicSet(signal, 1);
+ int exceptionsCaught = 0;
+ for (int i = 0; i < DefaultRangeSize; ++i) {
+ try {
+ futures1[i].GetValueSync();
+ } catch (int& e) {
+ if (e == 15000 + i) {
+ ++exceptionsCaught;
+ }
+ }
+ try {
+ futures2[i].GetValueSync();
+ } catch (int& e) {
+ if (e == 16000 + i) {
+ ++exceptionsCaught;
+ }
+ }
+ }
+ UNIT_ASSERT(exceptionsCaught == 2 * DefaultRangeSize);
+ UNIT_ASSERT(AllOf(data1, 1));
+ UNIT_ASSERT(AllOf(data2, 2));
+}
+
+void RunRangeAndCheckExceptionsWithWaitComplete(int rangeSize, int threadsCount) {
+ TLocalExecutor localExecutor;
+ localExecutor.RunAdditionalThreads(threadsCount);
+ TVector<int> data(rangeSize, 0);
+ TVector<NThreading::TFuture<void>> futures = localExecutor.ExecRangeWithFutures([&data](int i) {
+ UNIT_ASSERT(data[i] == 0);
+ data[i] += 1;
+ throw 30000 + i;
+ },
+ 0, rangeSize, TLocalExecutor::EFlags::WAIT_COMPLETE);
+ UNIT_ASSERT(AllOf(data, 1));
+ int exceptionsCaught = 0;
+ for (int i = 0; i < rangeSize; ++i) {
+ try {
+ futures[i].GetValueSync();
+ } catch (int& e) {
+ if (e == 30000 + i) {
+ ++exceptionsCaught;
+ }
+ }
+ }
+ UNIT_ASSERT(exceptionsCaught == rangeSize);
+ UNIT_ASSERT(AllOf(data, 1));
+}
+
+Y_UNIT_TEST(RunRangeAndCheckExceptionsWithWaitComplete) {
+ RunRangeAndCheckExceptionsWithWaitComplete(DefaultRangeSize, DefaultThreadsCount);
+}
+
+Y_UNIT_TEST(RunOneAndCheckExceptionsWithWaitComplete) {
+ RunRangeAndCheckExceptionsWithWaitComplete(1, DefaultThreadsCount);
+}
+
+Y_UNIT_TEST(RunRangeAndCheckExceptionsWithWaitCompleteOneExtraThread) {
+ RunRangeAndCheckExceptionsWithWaitComplete(DefaultRangeSize, 1);
+}
+
+Y_UNIT_TEST(RunOneAndCheckExceptionsWithWaitCompleteOneExtraThread) {
+ RunRangeAndCheckExceptionsWithWaitComplete(1, 1);
+}
+
+Y_UNIT_TEST(RunRangeAndCheckExceptionsWithWaitCompleteZeroExtraThreads) {
+ RunRangeAndCheckExceptionsWithWaitComplete(DefaultRangeSize, 0);
+}
+
+Y_UNIT_TEST(RunOneAndCheckExceptionsWithWaitCompleteZeroExtraThreads) {
+ RunRangeAndCheckExceptionsWithWaitComplete(1, 0);
+}
+}
+;
+
+Y_UNIT_TEST_SUITE(ExecRangeWithThrow){
+ void RunParallelWhichThrowsTTestException(int rangeStart, int rangeSize, int threadsCount, int flags, TAtomic& processed){
+ AtomicSet(processed, 0);
+TLocalExecutor localExecutor;
+localExecutor.RunAdditionalThreads(threadsCount);
+localExecutor.ExecRangeWithThrow([&processed](int) {
+ AtomicAdd(processed, 1);
+ throw TTestException();
+},
+ rangeStart, rangeStart + rangeSize, flags);
+}
+
+Y_UNIT_TEST(RunParallelWhichThrowsTTestException) {
+ TAtomic processed = 0;
+ UNIT_ASSERT_EXCEPTION(
+ RunParallelWhichThrowsTTestException(10, 40, DefaultThreadsCount,
+ TLocalExecutor::EFlags::WAIT_COMPLETE, processed),
+ TTestException);
+ UNIT_ASSERT(AtomicGet(processed) == 40);
+}
+
+void ThrowAndCatchTTestException(int rangeSize, int threadsCount, int flags) {
+ TAtomic processed = 0;
+ UNIT_ASSERT_EXCEPTION(
+ RunParallelWhichThrowsTTestException(0, rangeSize, threadsCount, flags, processed),
+ TTestException);
+ UNIT_ASSERT(AtomicGet(processed) == rangeSize);
+}
+
+Y_UNIT_TEST(ThrowAndCatchTTestExceptionLowPriority) {
+ ThrowAndCatchTTestException(DefaultRangeSize, DefaultThreadsCount,
+ TLocalExecutor::EFlags::WAIT_COMPLETE | TLocalExecutor::EFlags::LOW_PRIORITY);
+}
+
+Y_UNIT_TEST(ThrowAndCatchTTestExceptionMedPriority) {
+ ThrowAndCatchTTestException(DefaultRangeSize, DefaultThreadsCount,
+ TLocalExecutor::EFlags::WAIT_COMPLETE | TLocalExecutor::EFlags::MED_PRIORITY);
+}
+
+Y_UNIT_TEST(ThrowAndCatchTTestExceptionHighPriority) {
+ ThrowAndCatchTTestException(DefaultRangeSize, DefaultThreadsCount,
+ TLocalExecutor::EFlags::WAIT_COMPLETE | TLocalExecutor::EFlags::HIGH_PRIORITY);
+}
+
+Y_UNIT_TEST(ThrowAndCatchTTestExceptionWaitComplete) {
+ ThrowAndCatchTTestException(DefaultRangeSize, DefaultThreadsCount,
+ TLocalExecutor::EFlags::WAIT_COMPLETE);
+}
+
+Y_UNIT_TEST(RethrowExeptionSequentialWaitComplete) {
+ ThrowAndCatchTTestException(DefaultRangeSize, 0,
+ TLocalExecutor::EFlags::WAIT_COMPLETE);
+}
+
+Y_UNIT_TEST(RethrowExeptionOneExtraThreadWaitComplete) {
+ ThrowAndCatchTTestException(DefaultRangeSize, 1,
+ TLocalExecutor::EFlags::WAIT_COMPLETE);
+}
+
+void ThrowsTTestExceptionFromNested(TLocalExecutor& localExecutor) {
+ localExecutor.ExecRangeWithThrow([](int) {
+ throw TTestException();
+ },
+ 0, 10, TLocalExecutor::EFlags::WAIT_COMPLETE);
+}
+
+void CatchTTestExceptionFromNested(TAtomic& processed1, TAtomic& processed2) {
+ TLocalExecutor localExecutor;
+ localExecutor.RunAdditionalThreads(DefaultThreadsCount);
+ localExecutor.ExecRangeWithThrow([&processed1, &processed2, &localExecutor](int) {
+ AtomicAdd(processed1, 1);
+ UNIT_ASSERT_EXCEPTION(
+ ThrowsTTestExceptionFromNested(localExecutor),
+ TTestException);
+ AtomicAdd(processed2, 1);
+ },
+ 0, DefaultRangeSize, TLocalExecutor::EFlags::WAIT_COMPLETE);
+}
+
+Y_UNIT_TEST(NestedParallelExceptionsDoNotLeak) {
+ TAtomic processed1 = 0;
+ TAtomic processed2 = 0;
+ UNIT_ASSERT_NO_EXCEPTION(
+ CatchTTestExceptionFromNested(processed1, processed2));
+ UNIT_ASSERT_EQUAL(AtomicGet(processed1), DefaultRangeSize);
+ UNIT_ASSERT_EQUAL(AtomicGet(processed2), DefaultRangeSize);
+}
+}
+;
+
+Y_UNIT_TEST_SUITE(ExecLargeRangeWithThrow){
+
+ constexpr int LARGE_COUNT = 128 * (1 << 20);
+
+ static auto IsValue(char v) {
+ return [=](char c) { return c == v; };
+ }
+
+ Y_UNIT_TEST(ExecLargeRangeNoExceptions) {
+ TVector<char> tasks(LARGE_COUNT);
+
+ TLocalExecutor localExecutor;
+ localExecutor.RunAdditionalThreads(DefaultThreadsCount);
+
+ localExecutor.ExecRangeBlockedWithThrow([&tasks](int i) {
+ tasks[i] = 1;
+ }, 0, tasks.size(), 0, TLocalExecutor::EFlags::WAIT_COMPLETE);
+ UNIT_ASSERT(AllOf(tasks, IsValue(1)));
+
+
+ localExecutor.ExecRangeBlockedWithThrow([&tasks](int i) {
+ tasks[i] += 1;
+ }, 0, tasks.size(), 128, TLocalExecutor::EFlags::WAIT_COMPLETE);
+ UNIT_ASSERT(AllOf(tasks, IsValue(2)));
+ }
+
+ Y_UNIT_TEST(ExecLargeRangeWithException) {
+ TVector<char> tasks(LARGE_COUNT);
+
+ TLocalExecutor localExecutor;
+ localExecutor.RunAdditionalThreads(DefaultThreadsCount);
+
+ Fill(tasks.begin(), tasks.end(), 0);
+ UNIT_ASSERT_EXCEPTION(
+ localExecutor.ExecRangeBlockedWithThrow([&tasks](int i) {
+ tasks[i] += 1;
+ if (i == LARGE_COUNT / 2) {
+ throw TTestException();
+ }
+ }, 0, tasks.size(), 0, TLocalExecutor::EFlags::WAIT_COMPLETE),
+ TTestException
+ );
+ }
+};
diff --git a/library/cpp/threading/local_executor/ut/ya.make b/library/cpp/threading/local_executor/ut/ya.make
new file mode 100644
index 0000000000..be579a5ca0
--- /dev/null
+++ b/library/cpp/threading/local_executor/ut/ya.make
@@ -0,0 +1,12 @@
+OWNER(
+ g:matrixnet
+ gulin
+)
+
+UNITTEST_FOR(library/cpp/threading/local_executor)
+
+SRCS(
+ local_executor_ut.cpp
+)
+
+END()
diff --git a/library/cpp/threading/local_executor/ya.make b/library/cpp/threading/local_executor/ya.make
new file mode 100644
index 0000000000..df210f92bb
--- /dev/null
+++ b/library/cpp/threading/local_executor/ya.make
@@ -0,0 +1,20 @@
+OWNER(
+ g:matrixnet
+ gulin
+ kirillovs
+ espetrov
+)
+
+LIBRARY()
+
+SRCS(
+ local_executor.cpp
+ tbb_local_executor.cpp
+)
+
+PEERDIR(
+ contrib/libs/tbb
+ library/cpp/threading/future
+)
+
+END()
diff --git a/library/cpp/threading/poor_man_openmp/thread_helper.cpp b/library/cpp/threading/poor_man_openmp/thread_helper.cpp
new file mode 100644
index 0000000000..34cb6507b9
--- /dev/null
+++ b/library/cpp/threading/poor_man_openmp/thread_helper.cpp
@@ -0,0 +1,7 @@
+#include "thread_helper.h"
+
+#include <util/generic/singleton.h>
+
+TMtpQueueHelper& TMtpQueueHelper::Instance() {
+ return *Singleton<TMtpQueueHelper>();
+}
diff --git a/library/cpp/threading/poor_man_openmp/thread_helper.h b/library/cpp/threading/poor_man_openmp/thread_helper.h
new file mode 100644
index 0000000000..0ecee0590b
--- /dev/null
+++ b/library/cpp/threading/poor_man_openmp/thread_helper.h
@@ -0,0 +1,105 @@
+#pragma once
+
+#include <util/thread/pool.h>
+#include <util/generic/utility.h>
+#include <util/generic/yexception.h>
+#include <util/system/info.h>
+#include <util/system/atomic.h>
+#include <util/system/condvar.h>
+#include <util/system/mutex.h>
+#include <util/stream/output.h>
+
+#include <functional>
+#include <cstdlib>
+
+class TMtpQueueHelper {
+public:
+ TMtpQueueHelper() {
+ SetThreadCount(NSystemInfo::CachedNumberOfCpus());
+ }
+ IThreadPool* Get() {
+ return q.Get();
+ }
+ size_t GetThreadCount() {
+ return ThreadCount;
+ }
+ void SetThreadCount(size_t threads) {
+ ThreadCount = threads;
+ q = CreateThreadPool(ThreadCount);
+ }
+
+ static TMtpQueueHelper& Instance();
+
+private:
+ size_t ThreadCount;
+ TAutoPtr<IThreadPool> q;
+};
+
+namespace NYmp {
+ inline void SetThreadCount(size_t threads) {
+ TMtpQueueHelper::Instance().SetThreadCount(threads);
+ }
+
+ inline size_t GetThreadCount() {
+ return TMtpQueueHelper::Instance().GetThreadCount();
+ }
+
+ template <typename T>
+ inline void ParallelForStaticChunk(T begin, T end, size_t chunkSize, std::function<void(T)> func) {
+ chunkSize = Max<size_t>(chunkSize, 1);
+
+ size_t threadCount = TMtpQueueHelper::Instance().GetThreadCount();
+ IThreadPool* queue = TMtpQueueHelper::Instance().Get();
+ TCondVar cv;
+ TMutex mutex;
+ TAtomic counter = threadCount;
+ std::exception_ptr err;
+
+ for (size_t i = 0; i < threadCount; ++i) {
+ queue->SafeAddFunc([&cv, &counter, &mutex, &func, i, begin, end, chunkSize, threadCount, &err]() {
+ try {
+ T currentChunkStart = begin + static_cast<decltype(T() - T())>(i * chunkSize);
+
+ while (currentChunkStart < end) {
+ T currentChunkEnd = Min<T>(end, currentChunkStart + chunkSize);
+
+ for (T val = currentChunkStart; val < currentChunkEnd; ++val) {
+ func(val);
+ }
+
+ currentChunkStart += chunkSize * threadCount;
+ }
+ } catch (...) {
+ with_lock (mutex) {
+ err = std::current_exception();
+ }
+ }
+
+ with_lock (mutex) {
+ if (AtomicDecrement(counter) == 0) {
+ //last one
+ cv.Signal();
+ }
+ }
+ });
+ }
+
+ with_lock (mutex) {
+ while (AtomicGet(counter) > 0) {
+ cv.WaitI(mutex);
+ }
+ }
+
+ if (err) {
+ std::rethrow_exception(err);
+ }
+ }
+
+ template <typename T>
+ inline void ParallelForStaticAutoChunk(T begin, T end, std::function<void(T)> func) {
+ const size_t taskSize = end - begin;
+ const size_t threadCount = TMtpQueueHelper::Instance().GetThreadCount();
+
+ ParallelForStaticChunk(begin, end, (taskSize + threadCount - 1) / threadCount, func);
+ }
+}
diff --git a/library/cpp/threading/poor_man_openmp/thread_helper_ut.cpp b/library/cpp/threading/poor_man_openmp/thread_helper_ut.cpp
new file mode 100644
index 0000000000..7417636864
--- /dev/null
+++ b/library/cpp/threading/poor_man_openmp/thread_helper_ut.cpp
@@ -0,0 +1,26 @@
+#include "thread_helper.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/string.h>
+#include <util/generic/yexception.h>
+
+Y_UNIT_TEST_SUITE(TestMP) {
+ Y_UNIT_TEST(TestErr) {
+ std::function<void(int)> f = [](int x) {
+ if (x == 5) {
+ ythrow yexception() << "oops";
+ }
+ };
+
+ TString s;
+
+ try {
+ NYmp::ParallelForStaticAutoChunk(0, 10, f);
+ } catch (...) {
+ s = CurrentExceptionMessage();
+ }
+
+ UNIT_ASSERT(s.find("oops") > 0);
+ }
+}
diff --git a/library/cpp/threading/poor_man_openmp/ut/ya.make b/library/cpp/threading/poor_man_openmp/ut/ya.make
new file mode 100644
index 0000000000..6d7aa123ed
--- /dev/null
+++ b/library/cpp/threading/poor_man_openmp/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/threading/poor_man_openmp)
+
+OWNER(
+ pg
+ agorodilov
+)
+
+SRCS(
+ thread_helper_ut.cpp
+)
+
+END()
diff --git a/library/cpp/threading/poor_man_openmp/ya.make b/library/cpp/threading/poor_man_openmp/ya.make
new file mode 100644
index 0000000000..241b61dead
--- /dev/null
+++ b/library/cpp/threading/poor_man_openmp/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(agorodilov)
+
+SRCS(
+ thread_helper.cpp
+)
+
+END()
diff --git a/library/cpp/threading/queue/basic_ut.cpp b/library/cpp/threading/queue/basic_ut.cpp
new file mode 100644
index 0000000000..5f56f8583e
--- /dev/null
+++ b/library/cpp/threading/queue/basic_ut.cpp
@@ -0,0 +1,92 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/generic/vector.h>
+#include <util/system/thread.h>
+
+#include "ut_helpers.h"
+
+template <typename TQueueType>
+class TQueueTestsInSingleThread: public TTestBase {
+private:
+ using TSelf = TQueueTestsInSingleThread<TQueueType>;
+ using TLink = TIntrusiveLink;
+
+ UNIT_TEST_SUITE_DEMANGLE(TSelf);
+ UNIT_TEST(OnePushOnePop)
+ UNIT_TEST(OnePushOnePop_Repeat1M)
+ UNIT_TEST(Threads8_Repeat1M_Push1Pop1)
+ UNIT_TEST_SUITE_END();
+
+public:
+ void OnePushOnePop() {
+ TQueueType queue;
+
+ auto popped = queue.Pop();
+ UNIT_ASSERT_VALUES_EQUAL(popped, nullptr);
+
+ TLink msg;
+ queue.Push(&msg);
+ popped = queue.Pop();
+ UNIT_ASSERT_VALUES_EQUAL(&msg, popped);
+
+ popped = queue.Pop();
+ UNIT_ASSERT_VALUES_EQUAL(popped, nullptr);
+ };
+
+ void OnePushOnePop_Repeat1M() {
+ TQueueType queue;
+ TLink msg;
+
+ auto popped = queue.Pop();
+ UNIT_ASSERT_VALUES_EQUAL(popped, nullptr);
+
+ for (int i = 0; i < 1000000; ++i) {
+ queue.Push(&msg);
+ popped = queue.Pop();
+ UNIT_ASSERT_VALUES_EQUAL(&msg, popped);
+
+ popped = queue.Pop();
+ UNIT_ASSERT_VALUES_EQUAL(popped, nullptr);
+ }
+ }
+
+ template <size_t NUMBER_OF_THREADS>
+ void RepeatPush1Pop1_InManyThreads() {
+ class TCycleThread: public ISimpleThread {
+ public:
+ void* ThreadProc() override {
+ TQueueType queue;
+ TLink msg;
+ auto popped = queue.Pop();
+ UNIT_ASSERT_VALUES_EQUAL(popped, nullptr);
+
+ for (size_t i = 0; i < 1000000; ++i) {
+ queue.Push(&msg);
+ popped = queue.Pop();
+ UNIT_ASSERT_VALUES_EQUAL(popped, &msg);
+
+ popped = queue.Pop();
+ UNIT_ASSERT_VALUES_EQUAL(popped, nullptr);
+ }
+ return nullptr;
+ }
+ };
+
+ TVector<TAutoPtr<TCycleThread>> cyclers;
+
+ for (size_t i = 0; i < NUMBER_OF_THREADS; ++i) {
+ cyclers.emplace_back(new TCycleThread);
+ cyclers.back()->Start();
+ }
+
+ for (size_t i = 0; i < NUMBER_OF_THREADS; ++i) {
+ cyclers[i]->Join();
+ }
+ }
+
+ void Threads8_Repeat1M_Push1Pop1() {
+ RepeatPush1Pop1_InManyThreads<8>();
+ }
+};
+
+REGISTER_TESTS_FOR_ALL_ORDERED_QUEUES(TQueueTestsInSingleThread);
+REGISTER_TESTS_FOR_ALL_UNORDERED_QUEUES(TQueueTestsInSingleThread)
diff --git a/library/cpp/threading/queue/mpmc_unordered_ring.cpp b/library/cpp/threading/queue/mpmc_unordered_ring.cpp
new file mode 100644
index 0000000000..160547f594
--- /dev/null
+++ b/library/cpp/threading/queue/mpmc_unordered_ring.cpp
@@ -0,0 +1,74 @@
+#include "mpmc_unordered_ring.h"
+
+namespace NThreading {
+ TMPMCUnorderedRing::TMPMCUnorderedRing(size_t size) {
+ Y_VERIFY(size > 0);
+ RingSize = size;
+ RingBuffer.Reset(new void*[size]);
+ memset(&RingBuffer[0], 0, sizeof(void*) * size);
+ }
+
+ bool TMPMCUnorderedRing::Push(void* msg, ui16 retryCount) noexcept {
+ if (retryCount == 0) {
+ StubbornPush(msg);
+ return true;
+ }
+ for (ui16 itry = retryCount; itry-- > 0;) {
+ if (WeakPush(msg)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool TMPMCUnorderedRing::WeakPush(void* msg) noexcept {
+ auto pawl = AtomicIncrement(WritePawl);
+ if (pawl - AtomicGet(ReadFront) >= RingSize) {
+ // Queue is full
+ AtomicDecrement(WritePawl);
+ return false;
+ }
+
+ auto writeSlot = AtomicGetAndIncrement(WriteFront);
+ if (AtomicCas(&RingBuffer[writeSlot % RingSize], msg, nullptr)) {
+ return true;
+ }
+ // slot is occupied for some reason, retry
+ return false;
+ }
+
+ void* TMPMCUnorderedRing::Pop() noexcept {
+ ui64 readSlot;
+
+ for (ui16 itry = MAX_POP_TRIES; itry-- > 0;) {
+ auto pawl = AtomicIncrement(ReadPawl);
+ if (pawl > AtomicGet(WriteFront)) {
+ // Queue is empty
+ AtomicDecrement(ReadPawl);
+ return nullptr;
+ }
+
+ readSlot = AtomicGetAndIncrement(ReadFront);
+
+ auto msg = AtomicSwap(&RingBuffer[readSlot % RingSize], nullptr);
+ if (msg != nullptr) {
+ return msg;
+ }
+ }
+
+ /* got no message in the slot, let's try to rollback readfront */
+ AtomicCas(&ReadFront, readSlot - 1, readSlot);
+ return nullptr;
+ }
+
+ void* TMPMCUnorderedRing::UnsafeScanningPop(ui64* last) noexcept {
+ for (; *last < RingSize;) {
+ auto msg = AtomicSwap(&RingBuffer[*last], nullptr);
+ ++*last;
+ if (msg != nullptr) {
+ return msg;
+ }
+ }
+ return nullptr;
+ }
+}
diff --git a/library/cpp/threading/queue/mpmc_unordered_ring.h b/library/cpp/threading/queue/mpmc_unordered_ring.h
new file mode 100644
index 0000000000..5042f7528e
--- /dev/null
+++ b/library/cpp/threading/queue/mpmc_unordered_ring.h
@@ -0,0 +1,42 @@
+#pragma once
+
+/*
+ It's not a general purpose queue.
+ No order guarantee, but it mostly ordered.
+ Items may stuck in almost empty queue.
+ Use UnsafeScanningPop to pop all stuck items.
+ Almost wait-free for producers and consumers.
+ */
+
+#include <util/system/atomic.h>
+#include <util/generic/ptr.h>
+
+namespace NThreading {
+ struct TMPMCUnorderedRing {
+ public:
+ static constexpr ui16 MAX_PUSH_TRIES = 4;
+ static constexpr ui16 MAX_POP_TRIES = 4;
+
+ TMPMCUnorderedRing(size_t size);
+
+ bool Push(void* msg, ui16 retryCount = MAX_PUSH_TRIES) noexcept;
+ void StubbornPush(void* msg) {
+ while (!WeakPush(msg)) {
+ }
+ }
+
+ void* Pop() noexcept;
+
+ void* UnsafeScanningPop(ui64* last) noexcept;
+
+ private:
+ bool WeakPush(void* msg) noexcept;
+
+ size_t RingSize;
+ TArrayPtr<void*> RingBuffer;
+ ui64 WritePawl = 0;
+ ui64 WriteFront = 0;
+ ui64 ReadPawl = 0;
+ ui64 ReadFront = 0;
+ };
+}
diff --git a/library/cpp/threading/queue/mpsc_htswap.cpp b/library/cpp/threading/queue/mpsc_htswap.cpp
new file mode 100644
index 0000000000..610c8f67f1
--- /dev/null
+++ b/library/cpp/threading/queue/mpsc_htswap.cpp
@@ -0,0 +1 @@
+#include "mpsc_htswap.h"
diff --git a/library/cpp/threading/queue/mpsc_htswap.h b/library/cpp/threading/queue/mpsc_htswap.h
new file mode 100644
index 0000000000..c42caa7ac0
--- /dev/null
+++ b/library/cpp/threading/queue/mpsc_htswap.h
@@ -0,0 +1,132 @@
+#pragma once
+
+/*
+ http://www.1024cores.net/home/lock-free-algorithms/queues/non-intrusive-mpsc-node-based-queue
+
+ Simple semi-wait-free queue. Many producers - one consumer.
+ Tracking of allocated memory is not required.
+ No CAS. Only atomic swap (exchange) operations.
+
+ WARNING: a sleeping producer can stop progress for consumer.
+
+ WARNING: there is no wait&notify mechanic for consumer,
+ consumer receives nullptr if queue was empty.
+
+ WARNING: the algorithm itself is lock-free
+ but producers and consumer could be blocked by memory allocator
+
+ Reference design: rtmapreduce/libs/threading/lfqueue.h
+ */
+
+#include <util/generic/noncopyable.h>
+#include <util/system/types.h>
+#include <util/system/atomic.h>
+
+#include "tune.h"
+
+namespace NThreading {
+ namespace NHTSwapPrivate {
+ template <typename T, typename TTuneup>
+ struct TNode
+ : public TTuneup::TNodeBase,
+ public TTuneup::template TNodeLayout<TNode<T, TTuneup>, T> {
+ TNode(const T& item) {
+ this->Next = nullptr;
+ this->Item = item;
+ }
+
+ TNode(T&& item) {
+ this->Next = nullptr;
+ this->Item = std::move(item);
+ }
+ };
+
+ struct TDefaultTuneup {
+ struct TNodeBase: private TNonCopyable {
+ };
+
+ template <typename TNode, typename T>
+ struct TNodeLayout {
+ TNode* Next;
+ T Item;
+ };
+
+ template <typename TNode>
+ struct TQueueLayout {
+ TNode* Head;
+ TNode* Tail;
+ };
+ };
+
+ template <typename T, typename TTuneup>
+ class THTSwapQueueImpl
+ : protected TTuneup::template TQueueLayout<TNode<T, TTuneup>> {
+ protected:
+ using TTunedNode = TNode<T, TTuneup>;
+
+ public:
+ using TItem = T;
+
+ THTSwapQueueImpl() {
+ this->Head = new TTunedNode(T());
+ this->Tail = this->Head;
+ }
+
+ ~THTSwapQueueImpl() {
+ TTunedNode* node = this->Head;
+ while (node != nullptr) {
+ TTunedNode* next = node->Next;
+ delete node;
+ node = next;
+ }
+ }
+
+ template <typename TT>
+ void Push(TT&& item) {
+ Enqueue(new TTunedNode(std::forward<TT>(item)));
+ }
+
+ T Peek() {
+ TTunedNode* next = AtomicGet(this->Head->Next);
+ if (next == nullptr) {
+ return T();
+ }
+ return next->Item;
+ }
+
+ void Enqueue(TTunedNode* node) {
+ // our goal is to avoid expensive CAS here,
+ // but now consumer will be blocked until new tail linked.
+ // fortunately 'window of inconsistency' is extremely small.
+ TTunedNode* prev = AtomicSwap(&this->Tail, node);
+ AtomicSet(prev->Next, node);
+ }
+
+ T Pop() {
+ TTunedNode* next = AtomicGet(this->Head->Next);
+ if (next == nullptr) {
+ return nullptr;
+ }
+ auto item = std::move(next->Item);
+ std::swap(this->Head, next); // no need atomic here
+ delete next;
+ return item;
+ }
+
+ bool IsEmpty() const {
+ TTunedNode* next = AtomicGet(this->Head->Next);
+ return (next == nullptr);
+ }
+ };
+ }
+
+ DeclareTuneTypeParam(THTSwapNodeBase, TNodeBase);
+ DeclareTuneTypeParam(THTSwapNodeLayout, TNodeLayout);
+ DeclareTuneTypeParam(THTSwapQueueLayout, TQueueLayout);
+
+ template <typename T = void*, typename... TParams>
+ class THTSwapQueue
+ : public NHTSwapPrivate::THTSwapQueueImpl<T,
+ TTune<NHTSwapPrivate::TDefaultTuneup, TParams...>> {
+ };
+}
diff --git a/library/cpp/threading/queue/mpsc_intrusive_unordered.cpp b/library/cpp/threading/queue/mpsc_intrusive_unordered.cpp
new file mode 100644
index 0000000000..3bb1a04f7e
--- /dev/null
+++ b/library/cpp/threading/queue/mpsc_intrusive_unordered.cpp
@@ -0,0 +1,79 @@
+#include "mpsc_intrusive_unordered.h"
+#include <util/system/atomic.h>
+
+namespace NThreading {
+ void TMPSCIntrusiveUnordered::Push(TIntrusiveNode* node) noexcept {
+ auto head = AtomicGet(HeadForCaS);
+ for (ui32 i = NUMBER_OF_TRIES_FOR_CAS; i-- > 0;) {
+ // no ABA here, because Next is exactly head
+ // it does not matter how many travels head was made/
+ node->Next = head;
+ auto prev = AtomicGetAndCas(&HeadForCaS, node, head);
+ if (head == prev) {
+ return;
+ }
+ head = prev;
+ }
+ // boring of trying to do cas, let's just swap
+
+ // no need for atomic here, because the next is atomic swap
+ node->Next = 0;
+
+ head = AtomicSwap(&HeadForSwap, node);
+ if (head != nullptr) {
+ AtomicSet(node->Next, head);
+ } else {
+ // consumer must know if no other thread may access the memory,
+ // setting Next to node is a way to notify consumer
+ AtomicSet(node->Next, node);
+ }
+ }
+
+ TIntrusiveNode* TMPSCIntrusiveUnordered::PopMany() noexcept {
+ if (NotReadyChain == nullptr) {
+ auto head = AtomicSwap(&HeadForSwap, nullptr);
+ NotReadyChain = head;
+ }
+
+ if (NotReadyChain != nullptr) {
+ auto next = AtomicGet(NotReadyChain->Next);
+ if (next != nullptr) {
+ auto ready = NotReadyChain;
+ TIntrusiveNode* cut;
+ do {
+ cut = NotReadyChain;
+ NotReadyChain = next;
+ next = AtomicGet(NotReadyChain->Next);
+ if (next == NotReadyChain) {
+ cut = NotReadyChain;
+ NotReadyChain = nullptr;
+ break;
+ }
+ } while (next != nullptr);
+ cut->Next = nullptr;
+ return ready;
+ }
+ }
+
+ if (AtomicGet(HeadForCaS) != nullptr) {
+ return AtomicSwap(&HeadForCaS, nullptr);
+ }
+ return nullptr;
+ }
+
+ TIntrusiveNode* TMPSCIntrusiveUnordered::Pop() noexcept {
+ if (PopOneQueue != nullptr) {
+ auto head = PopOneQueue;
+ PopOneQueue = PopOneQueue->Next;
+ return head;
+ }
+
+ PopOneQueue = PopMany();
+ if (PopOneQueue != nullptr) {
+ auto head = PopOneQueue;
+ PopOneQueue = PopOneQueue->Next;
+ return head;
+ }
+ return nullptr;
+ }
+}
diff --git a/library/cpp/threading/queue/mpsc_intrusive_unordered.h b/library/cpp/threading/queue/mpsc_intrusive_unordered.h
new file mode 100644
index 0000000000..6ac7537ae9
--- /dev/null
+++ b/library/cpp/threading/queue/mpsc_intrusive_unordered.h
@@ -0,0 +1,35 @@
+#pragma once
+
+/*
+ Simple almost-wait-free unordered queue for low contention operations.
+
+ It's wait-free for producers.
+ Hanging producer can hide some items from consumer.
+ */
+
+#include <util/system/types.h>
+
+namespace NThreading {
+ struct TIntrusiveNode {
+ TIntrusiveNode* Next;
+ };
+
+ class TMPSCIntrusiveUnordered {
+ public:
+ static constexpr ui32 NUMBER_OF_TRIES_FOR_CAS = 3;
+
+ void Push(TIntrusiveNode* node) noexcept;
+ TIntrusiveNode* PopMany() noexcept;
+ TIntrusiveNode* Pop() noexcept;
+
+ void Push(void* node) noexcept {
+ Push(reinterpret_cast<TIntrusiveNode*>(node));
+ }
+
+ private:
+ TIntrusiveNode* HeadForCaS = nullptr;
+ TIntrusiveNode* HeadForSwap = nullptr;
+ TIntrusiveNode* NotReadyChain = nullptr;
+ TIntrusiveNode* PopOneQueue = nullptr;
+ };
+}
diff --git a/library/cpp/threading/queue/mpsc_read_as_filled.cpp b/library/cpp/threading/queue/mpsc_read_as_filled.cpp
new file mode 100644
index 0000000000..8b4664a6f3
--- /dev/null
+++ b/library/cpp/threading/queue/mpsc_read_as_filled.cpp
@@ -0,0 +1 @@
+#include "mpsc_read_as_filled.h"
diff --git a/library/cpp/threading/queue/mpsc_read_as_filled.h b/library/cpp/threading/queue/mpsc_read_as_filled.h
new file mode 100644
index 0000000000..be33ba5a58
--- /dev/null
+++ b/library/cpp/threading/queue/mpsc_read_as_filled.h
@@ -0,0 +1,611 @@
+#pragma once
+
+/*
+ Completely wait-free queue, multiple producers - one consumer. Strict order.
+ The queue algorithm is using concept of virtual infinite array.
+
+ A producer takes a number from a counter and atomically increments the counter.
+ The number taken is a number of a slot for the producer to put a new message
+ into infinite array.
+
+ Then producer constructs a virtual infinite array by bidirectional linked list
+ of blocks. Each block contains several slots.
+
+ There is a hint pointer which optimistically points to the last block
+ of the list and never goes backward.
+
+ Consumer exploits the property of the hint pointer always going forward
+ to free old blocks eventually. Consumer periodically read the hint pointer
+ and the counter and thus deduce producers which potentially holds the pointer
+ to a block. Consumer can free the block if all that producers filled their
+ slots and left the queue.
+
+ No producer can stop the progress for other producers.
+
+ Consumer can't stop the progress for producers.
+ Consumer can skip not-yet-filled slots and read them later.
+ Thus no producer can stop the progress for consumer.
+ The algorithm is virtually strictly ordered because it skips slots only
+ if it is really does not matter in which order the slots were produced and
+ consumed.
+
+ WARNING: there is no wait&notify mechanic for consumer,
+ consumer receives nullptr if queue was empty.
+
+ WARNING: though the algorithm itself is completely wait-free
+ but producers and consumer could be blocked by memory allocator
+
+ WARNING: copy constructors of the queue are not thread-safe
+ */
+
+#include <util/generic/deque.h>
+#include <util/generic/ptr.h>
+#include <util/system/atomic.h>
+#include <util/system/spinlock.h>
+
+#include "tune.h"
+
+namespace NThreading {
+ namespace NReadAsFilledPrivate {
+ typedef void* TMsgLink;
+
+ static constexpr ui32 DEFAULT_BUNCH_SIZE = 251;
+
+ struct TEmpty {
+ };
+
+ struct TEmptyAux {
+ TEmptyAux Retrieve() const {
+ return TEmptyAux();
+ }
+
+ void Store(TEmptyAux&) {
+ }
+
+ static constexpr TEmptyAux Zero() {
+ return TEmptyAux();
+ }
+ };
+
+ template <typename TAux>
+ struct TSlot {
+ TMsgLink volatile Msg;
+ TAux AuxiliaryData;
+
+ inline void Store(TAux& aux) {
+ AuxiliaryData.Store(aux);
+ }
+
+ inline TAux Retrieve() const {
+ return AuxiliaryData.Retrieve();
+ }
+
+ static TSlot<TAux> NullElem() {
+ return {nullptr, TAux::Zero()};
+ }
+
+ static TSlot<TAux> Pair(TMsgLink msg, TAux aux) {
+ return {msg, std::move(aux)};
+ }
+ };
+
+ template <>
+ struct TSlot<TEmptyAux> {
+ TMsgLink volatile Msg;
+
+ inline void Store(TEmptyAux&) {
+ }
+
+ inline TEmptyAux Retrieve() const {
+ return TEmptyAux();
+ }
+
+ static TSlot<TEmptyAux> NullElem() {
+ return {nullptr};
+ }
+
+ static TSlot<TEmptyAux> Pair(TMsgLink msg, TEmptyAux) {
+ return {msg};
+ }
+ };
+
+ enum TPushResult {
+ PUSH_RESULT_OK,
+ PUSH_RESULT_BACKWARD,
+ PUSH_RESULT_FORWARD,
+ };
+
+ template <ui32 BUNCH_SIZE = DEFAULT_BUNCH_SIZE,
+ typename TBase = TEmpty,
+ typename TAux = TEmptyAux>
+ struct TMsgBunch: public TBase {
+ static constexpr size_t RELEASE_SIZE = BUNCH_SIZE * 2;
+
+ ui64 FirstSlot;
+
+ TSlot<TAux> LinkArray[BUNCH_SIZE];
+
+ TMsgBunch* volatile NextBunch;
+ TMsgBunch* volatile BackLink;
+
+ ui64 volatile Token;
+ TMsgBunch* volatile NextToken;
+
+ /* this push can return PUSH_RESULT_BLOCKED */
+ inline TPushResult Push(TMsgLink msg, ui64 slot, TAux auxiliary) {
+ if (Y_UNLIKELY(slot < FirstSlot)) {
+ return PUSH_RESULT_BACKWARD;
+ }
+
+ if (Y_UNLIKELY(slot >= FirstSlot + BUNCH_SIZE)) {
+ return PUSH_RESULT_FORWARD;
+ }
+
+ LinkArray[slot - FirstSlot].Store(auxiliary);
+
+ AtomicSet(LinkArray[slot - FirstSlot].Msg, msg);
+ return PUSH_RESULT_OK;
+ }
+
+ inline bool IsSlotHere(ui64 slot) {
+ return slot < FirstSlot + BUNCH_SIZE;
+ }
+
+ inline TMsgLink GetSlot(ui64 slot) const {
+ return AtomicGet(LinkArray[slot - FirstSlot].Msg);
+ }
+
+ inline TSlot<TAux> GetSlotAux(ui64 slot) const {
+ auto msg = GetSlot(slot);
+ auto aux = LinkArray[slot - FirstSlot].Retrieve();
+ return TSlot<TAux>::Pair(msg, aux);
+ }
+
+ inline TMsgBunch* GetNextBunch() const {
+ return AtomicGet(NextBunch);
+ }
+
+ inline bool SetNextBunch(TMsgBunch* ptr) {
+ return AtomicCas(&NextBunch, ptr, nullptr);
+ }
+
+ inline TMsgBunch* GetBackLink() const {
+ return AtomicGet(BackLink);
+ }
+
+ inline TMsgBunch* GetToken(ui64 slot) {
+ return reinterpret_cast<TMsgBunch*>(
+ LinkArray[slot - FirstSlot].Msg);
+ }
+
+ inline void IncrementToken() {
+ AtomicIncrement(Token);
+ }
+
+ // the object could be destroyed after this method
+ inline void DecrementToken() {
+ if (Y_UNLIKELY(AtomicDecrement(Token) == RELEASE_SIZE)) {
+ Release(this);
+ AtomicGet(NextToken)->DecrementToken();
+ // this could be invalid here
+ }
+ }
+
+ // the object could be destroyed after this method
+ inline void SetNextToken(TMsgBunch* next) {
+ AtomicSet(NextToken, next);
+ if (Y_UNLIKELY(AtomicAdd(Token, RELEASE_SIZE) == RELEASE_SIZE)) {
+ Release(this);
+ next->DecrementToken();
+ }
+ // this could be invalid here
+ }
+
+ TMsgBunch(ui64 start, TMsgBunch* backLink) {
+ AtomicSet(FirstSlot, start);
+ memset(&LinkArray, 0, sizeof(LinkArray));
+ AtomicSet(NextBunch, nullptr);
+ AtomicSet(BackLink, backLink);
+
+ AtomicSet(Token, 1);
+ AtomicSet(NextToken, nullptr);
+ }
+
+ static void Release(TMsgBunch* block) {
+ auto backLink = AtomicGet(block->BackLink);
+ if (backLink == nullptr) {
+ return;
+ }
+ AtomicSet(block->BackLink, nullptr);
+
+ do {
+ auto bbackLink = backLink->BackLink;
+ delete backLink;
+ backLink = bbackLink;
+ } while (backLink != nullptr);
+ }
+
+ void Destroy() {
+ for (auto tail = BackLink; tail != nullptr;) {
+ auto next = tail->BackLink;
+ delete tail;
+ tail = next;
+ }
+
+ for (auto next = this; next != nullptr;) {
+ auto nnext = next->NextBunch;
+ delete next;
+ next = nnext;
+ }
+ }
+ };
+
+ template <ui32 BUNCH_SIZE = DEFAULT_BUNCH_SIZE,
+ typename TBunchBase = NReadAsFilledPrivate::TEmpty,
+ typename TAux = TEmptyAux>
+ class TWriteBucket {
+ public:
+ using TUsingAux = TAux; // for TReadBucket binding
+ using TBunch = TMsgBunch<BUNCH_SIZE, TBunchBase, TAux>;
+
+ TWriteBucket(TBunch* bunch = new TBunch(0, nullptr)) {
+ AtomicSet(LastBunch, bunch);
+ AtomicSet(SlotCounter, 0);
+ }
+
+ TWriteBucket(TWriteBucket&& move)
+ : LastBunch(move.LastBunch)
+ , SlotCounter(move.SlotCounter)
+ {
+ move.LastBunch = nullptr;
+ }
+
+ ~TWriteBucket() {
+ if (LastBunch != nullptr) {
+ LastBunch->Destroy();
+ }
+ }
+
+ inline void Push(TMsgLink msg, TAux aux) {
+ ui64 pushSlot = AtomicGetAndIncrement(SlotCounter);
+ TBunch* hintBunch = GetLastBunch();
+
+ for (;;) {
+ auto hint = hintBunch->Push(msg, pushSlot, aux);
+ if (Y_LIKELY(hint == PUSH_RESULT_OK)) {
+ return;
+ }
+ HandleHint(hintBunch, hint);
+ }
+ }
+
+ protected:
+ template <typename, template <typename, typename...> class>
+ friend class TReadBucket;
+
+ TBunch* volatile LastBunch; // Hint
+ volatile ui64 SlotCounter;
+
+ inline TBunch* GetLastBunch() const {
+ return AtomicGet(LastBunch);
+ }
+
+ void HandleHint(TBunch*& hintBunch, TPushResult hint) {
+ if (Y_UNLIKELY(hint == PUSH_RESULT_BACKWARD)) {
+ hintBunch = hintBunch->GetBackLink();
+ return;
+ }
+
+ // PUSH_RESULT_FORWARD
+ auto nextBunch = hintBunch->GetNextBunch();
+
+ if (nextBunch == nullptr) {
+ auto first = hintBunch->FirstSlot + BUNCH_SIZE;
+ nextBunch = new TBunch(first, hintBunch);
+ if (Y_UNLIKELY(!hintBunch->SetNextBunch(nextBunch))) {
+ delete nextBunch;
+ nextBunch = hintBunch->GetNextBunch();
+ }
+ }
+
+ // hintBunch could not be freed here so it cannot be reused
+ // it's alright if this CAS was not succeeded,
+ // it means that other thread did that recently
+ AtomicCas(&LastBunch, nextBunch, hintBunch);
+
+ hintBunch = nextBunch;
+ }
+ };
+
+ template <typename TWBucket = TWriteBucket<>,
+ template <typename, typename...> class TContainer = TDeque>
+ class TReadBucket {
+ public:
+ using TAux = typename TWBucket::TUsingAux;
+ using TBunch = typename TWBucket::TBunch;
+
+ static constexpr int MAX_NUMBER_OF_TRIES_TO_READ = 5;
+
+ TReadBucket(TWBucket* writer)
+ : Writer(writer)
+ , ReadBunch(writer->GetLastBunch())
+ , LastKnownPushBunch(writer->GetLastBunch())
+ {
+ ReadBunch->DecrementToken(); // no previous token
+ }
+
+ TReadBucket(TReadBucket toCopy, TWBucket* writer)
+ : TReadBucket(std::move(toCopy))
+ {
+ Writer = writer;
+ }
+
+ ui64 ReadyCount() const {
+ return AtomicGet(Writer->SlotCounter) - ReadSlot;
+ }
+
+ TMsgLink Pop() {
+ return PopAux().Msg;
+ }
+
+ TMsgLink Peek() {
+ return PeekAux().Msg;
+ }
+
+ TSlot<TAux> PopAux() {
+ for (;;) {
+ if (Y_UNLIKELY(ReadNow.size() != 0)) {
+ auto result = PopSkipped();
+ if (Y_LIKELY(result.Msg != nullptr)) {
+ return result;
+ }
+ }
+
+ if (Y_UNLIKELY(ReadSlot == LastKnownPushSlot)) {
+ if (Y_LIKELY(!RereadPushSlot())) {
+ return TSlot<TAux>::NullElem();
+ }
+ continue;
+ }
+
+ if (Y_UNLIKELY(!ReadBunch->IsSlotHere(ReadSlot))) {
+ if (Y_UNLIKELY(!SwitchToNextBunch())) {
+ return TSlot<TAux>::NullElem();
+ }
+ }
+
+ auto result = ReadBunch->GetSlotAux(ReadSlot);
+ if (Y_LIKELY(result.Msg != nullptr)) {
+ ++ReadSlot;
+ return result;
+ }
+
+ result = StubbornPop();
+ if (Y_LIKELY(result.Msg != nullptr)) {
+ return result;
+ }
+ }
+ }
+
+ TSlot<TAux> PeekAux() {
+ for (;;) {
+ if (Y_UNLIKELY(ReadNow.size() != 0)) {
+ auto result = PeekSkipped();
+ if (Y_LIKELY(result.Msg != nullptr)) {
+ return result;
+ }
+ }
+
+ if (Y_UNLIKELY(ReadSlot == LastKnownPushSlot)) {
+ if (Y_LIKELY(!RereadPushSlot())) {
+ return TSlot<TAux>::NullElem();
+ }
+ continue;
+ }
+
+ if (Y_UNLIKELY(!ReadBunch->IsSlotHere(ReadSlot))) {
+ if (Y_UNLIKELY(!SwitchToNextBunch())) {
+ return TSlot<TAux>::NullElem();
+ }
+ }
+
+ auto result = ReadBunch->GetSlotAux(ReadSlot);
+ if (Y_LIKELY(result.Msg != nullptr)) {
+ return result;
+ }
+
+ result = StubbornPeek();
+ if (Y_LIKELY(result.Msg != nullptr)) {
+ return result;
+ }
+ }
+ }
+
+ private:
+ TWBucket* Writer;
+ TBunch* ReadBunch;
+ ui64 ReadSlot = 0;
+ TBunch* LastKnownPushBunch;
+ ui64 LastKnownPushSlot = 0;
+
+ struct TSkipItem {
+ TBunch* Bunch;
+ ui64 Slot;
+ TBunch* Token;
+ };
+
+ TContainer<TSkipItem> ReadNow;
+ TContainer<TSkipItem> ReadLater;
+
+ void AddToReadLater() {
+ ReadLater.push_back({ReadBunch, ReadSlot, LastKnownPushBunch});
+ LastKnownPushBunch->IncrementToken();
+ ++ReadSlot;
+ }
+
+ // MUST BE: ReadSlot == LastKnownPushSlot
+ bool RereadPushSlot() {
+ ReadNow = std::move(ReadLater);
+ ReadLater.clear();
+
+ auto oldSlot = LastKnownPushSlot;
+
+ auto currentPushBunch = Writer->GetLastBunch();
+ auto currentPushSlot = AtomicGet(Writer->SlotCounter);
+
+ if (currentPushBunch != LastKnownPushBunch) {
+ // LastKnownPushBunch could be invalid after this line
+ LastKnownPushBunch->SetNextToken(currentPushBunch);
+ }
+
+ LastKnownPushBunch = currentPushBunch;
+ LastKnownPushSlot = currentPushSlot;
+
+ return oldSlot != LastKnownPushSlot;
+ }
+
+ bool SwitchToNextBunch() {
+ for (int q = 0; q < MAX_NUMBER_OF_TRIES_TO_READ; ++q) {
+ auto next = ReadBunch->GetNextBunch();
+ if (next != nullptr) {
+ ReadBunch = next;
+ return true;
+ }
+ SpinLockPause();
+ }
+ return false;
+ }
+
+ TSlot<TAux> StubbornPop() {
+ for (int q = 0; q < MAX_NUMBER_OF_TRIES_TO_READ; ++q) {
+ auto result = ReadBunch->GetSlotAux(ReadSlot);
+ if (Y_LIKELY(result.Msg != nullptr)) {
+ ++ReadSlot;
+ return result;
+ }
+ SpinLockPause();
+ }
+
+ AddToReadLater();
+ return TSlot<TAux>::NullElem();
+ }
+
+ TSlot<TAux> StubbornPeek() {
+ for (int q = 0; q < MAX_NUMBER_OF_TRIES_TO_READ; ++q) {
+ auto result = ReadBunch->GetSlotAux(ReadSlot);
+ if (Y_LIKELY(result.Msg != nullptr)) {
+ return result;
+ }
+ SpinLockPause();
+ }
+
+ AddToReadLater();
+ return TSlot<TAux>::NullElem();
+ }
+
+ TSlot<TAux> PopSkipped() {
+ do {
+ auto elem = ReadNow.front();
+ ReadNow.pop_front();
+
+ auto result = elem.Bunch->GetSlotAux(elem.Slot);
+ if (Y_LIKELY(result.Msg != nullptr)) {
+ elem.Token->DecrementToken();
+ return result;
+ }
+
+ ReadLater.emplace_back(elem);
+
+ } while (ReadNow.size() > 0);
+
+ return TSlot<TAux>::NullElem();
+ }
+
+ TSlot<TAux> PeekSkipped() {
+ do {
+ auto elem = ReadNow.front();
+
+ auto result = elem.Bunch->GetSlotAux(elem.Slot);
+ if (Y_LIKELY(result.Msg != nullptr)) {
+ return result;
+ }
+
+ ReadNow.pop_front();
+ ReadLater.emplace_back(elem);
+
+ } while (ReadNow.size() > 0);
+
+ return TSlot<TAux>::NullElem();
+ }
+ };
+
+ struct TDefaultParams {
+ static constexpr ui32 BUNCH_SIZE = DEFAULT_BUNCH_SIZE;
+ using TBunchBase = TEmpty;
+
+ template <typename TElem, typename... TRest>
+ using TContainer = TDeque<TElem, TRest...>;
+
+ static constexpr bool DeleteItems = true;
+ };
+
+ } //namespace NReadAsFilledPrivate
+
+ DeclareTuneValueParam(TRaFQueueBunchSize, ui32, BUNCH_SIZE);
+ DeclareTuneTypeParam(TRaFQueueBunchBase, TBunchBase);
+ DeclareTuneContainer(TRaFQueueSkipContainer, TContainer);
+ DeclareTuneValueParam(TRaFQueueDeleteItems, bool, DeleteItems);
+
+ template <typename TItem = void, typename... TParams>
+ class TReadAsFilledQueue {
+ private:
+ using TTuned = TTune<NReadAsFilledPrivate::TDefaultParams, TParams...>;
+
+ static constexpr ui32 BUNCH_SIZE = TTuned::BUNCH_SIZE;
+
+ using TBunchBase = typename TTuned::TBunchBase;
+
+ template <typename TElem, typename... TRest>
+ using TContainer =
+ typename TTuned::template TContainer<TElem, TRest...>;
+
+ using TWriteBucket =
+ NReadAsFilledPrivate::TWriteBucket<BUNCH_SIZE, TBunchBase>;
+ using TReadBucket =
+ NReadAsFilledPrivate::TReadBucket<TWriteBucket, TContainer>;
+
+ public:
+ TReadAsFilledQueue()
+ : RBucket(&WBucket)
+ {
+ }
+
+ ~TReadAsFilledQueue() {
+ if (TTuned::DeleteItems) {
+ for (;;) {
+ auto msg = Pop();
+ if (msg == nullptr) {
+ break;
+ }
+ TDelete::Destroy(msg);
+ }
+ }
+ }
+
+ void Push(TItem* msg) {
+ WBucket.Push((void*)msg, NReadAsFilledPrivate::TEmptyAux());
+ }
+
+ TItem* Pop() {
+ return (TItem*)RBucket.Pop();
+ }
+
+ TItem* Peek() {
+ return (TItem*)RBucket.Peek();
+ }
+
+ protected:
+ TWriteBucket WBucket;
+ TReadBucket RBucket;
+ };
+}
diff --git a/library/cpp/threading/queue/mpsc_vinfarr_obstructive.cpp b/library/cpp/threading/queue/mpsc_vinfarr_obstructive.cpp
new file mode 100644
index 0000000000..2bd0c29821
--- /dev/null
+++ b/library/cpp/threading/queue/mpsc_vinfarr_obstructive.cpp
@@ -0,0 +1 @@
+#include "mpsc_vinfarr_obstructive.h"
diff --git a/library/cpp/threading/queue/mpsc_vinfarr_obstructive.h b/library/cpp/threading/queue/mpsc_vinfarr_obstructive.h
new file mode 100644
index 0000000000..5f91f1b5a8
--- /dev/null
+++ b/library/cpp/threading/queue/mpsc_vinfarr_obstructive.h
@@ -0,0 +1,528 @@
+#pragma once
+
+/*
+ Semi-wait-free queue, multiple producers - one consumer. Strict order.
+ The queue algorithm is using concept of virtual infinite array.
+
+ A producer takes a number from a counter and atomicaly increments the counter.
+ The number taken is a number of a slot for the producer to put a new message
+ into infinite array.
+
+ Then producer constructs a virtual infinite array by bidirectional linked list
+ of blocks. Each block contains several slots.
+
+ There is a hint pointer which optimisticly points to the last block
+ of the list and never goes backward.
+
+ Consumer exploits the property of the hint pointer always going forward
+ to free old blocks eventually. Consumer periodically read the hint pointer
+ and the counter and thus deduce producers which potentially holds the pointer
+ to a block. Consumer can free the block if all that producers filled their
+ slots and left the queue.
+
+ No producer can stop the progress for other producers.
+
+ Consumer can obstruct a slot of a delayed producer by putting special mark.
+ Thus no producer can stop the progress for consumer.
+ But a slow producer may be forced to retry unlimited number of times.
+ Though it's very unlikely for a non-preempted producer to be obstructed.
+ That's why the algorithm is semi-wait-free.
+
+ WARNING: there is no wait&notify mechanic for consumer,
+ consumer receives nullptr if queue was empty.
+
+ WARNING: though the algorithm itself is lock-free
+ but producers and consumer could be blocked by memory allocator
+
+ WARNING: copy constructers of the queue are not thread-safe
+ */
+
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/system/atomic.h>
+#include <util/system/spinlock.h>
+
+#include "tune.h"
+
+namespace NThreading {
+ namespace NObstructiveQueuePrivate {
+ typedef void* TMsgLink;
+
+ struct TEmpty {
+ };
+
+ struct TEmptyAux {
+ TEmptyAux Retrieve() const {
+ return TEmptyAux();
+ }
+ void Store(TEmptyAux&) {
+ }
+ static constexpr TEmptyAux Zero() {
+ return TEmptyAux();
+ }
+ };
+
+ template <typename TAux>
+ struct TSlot {
+ TMsgLink volatile Msg;
+ TAux AuxiliaryData;
+
+ inline void Store(TAux& aux) {
+ AuxiliaryData.Store(aux);
+ }
+
+ inline TAux Retrieve() const {
+ return AuxiliaryData.Retrieve();
+ }
+
+ static TSlot<TAux> NullElem() {
+ return {nullptr, TAux::Zero()};
+ }
+
+ static TSlot<TAux> Pair(TMsgLink msg, TAux aux) {
+ return {msg, std::move(aux)};
+ }
+ };
+
+ template <>
+ struct TSlot<TEmptyAux> {
+ TMsgLink volatile Msg;
+ inline void Store(TEmptyAux&) {
+ }
+ inline TEmptyAux Retrieve() const {
+ return TEmptyAux();
+ }
+
+ static TSlot<TEmptyAux> NullElem() {
+ return {nullptr};
+ }
+
+ static TSlot<TEmptyAux> Pair(TMsgLink msg, TEmptyAux) {
+ return {msg};
+ }
+ };
+
+ enum TPushResult {
+ PUSH_RESULT_OK,
+ PUSH_RESULT_BACKWARD,
+ PUSH_RESULT_FORWARD,
+ PUSH_RESULT_BLOCKED,
+ };
+
+ template <typename TAux, ui32 BUNCH_SIZE, typename TBase = TEmpty>
+ struct TMsgBunch: public TBase {
+ ui64 FirstSlot;
+
+ TSlot<TAux> LinkArray[BUNCH_SIZE];
+
+ TMsgBunch* volatile NextBunch;
+ TMsgBunch* volatile BackLink;
+
+ ui64 volatile Token;
+ TMsgBunch* volatile NextToken;
+
+ /* this push can return PUSH_RESULT_BLOCKED */
+ inline TPushResult Push(TMsgLink msg, ui64 slot, TAux auxiliary) {
+ if (Y_UNLIKELY(slot < FirstSlot)) {
+ return PUSH_RESULT_BACKWARD;
+ }
+
+ if (Y_UNLIKELY(slot >= FirstSlot + BUNCH_SIZE)) {
+ return PUSH_RESULT_FORWARD;
+ }
+
+ LinkArray[slot - FirstSlot].Store(auxiliary);
+
+ auto oldValue = AtomicSwap(&LinkArray[slot - FirstSlot].Msg, msg);
+
+ if (Y_LIKELY(oldValue == nullptr)) {
+ return PUSH_RESULT_OK;
+ } else {
+ LeaveBlocked(oldValue);
+ return PUSH_RESULT_BLOCKED;
+ }
+ }
+
+ inline bool IsSlotHere(ui64 slot) {
+ return slot < FirstSlot + BUNCH_SIZE;
+ }
+
+ inline TMsgLink GetSlot(ui64 slot) const {
+ return AtomicGet(LinkArray[slot - FirstSlot].Msg);
+ }
+
+ inline TSlot<TAux> GetSlotAux(ui64 slot) const {
+ auto msg = GetSlot(slot);
+ auto aux = LinkArray[slot - FirstSlot].Retrieve();
+ return TSlot<TAux>::Pair(msg, aux);
+ }
+
+ void LeaveBlocked(ui64 slot) {
+ auto token = GetToken(slot);
+ token->DecrementToken();
+ }
+
+ void LeaveBlocked(TMsgLink msg) {
+ auto token = reinterpret_cast<TMsgBunch*>(msg);
+ token->DecrementToken();
+ }
+
+ TSlot<TAux> BlockSlotAux(ui64 slot, TMsgBunch* token) {
+ auto old =
+ AtomicSwap(&LinkArray[slot - FirstSlot].Msg, (TMsgLink)token);
+ if (old == nullptr) {
+ // It's valid to increment after AtomicCas
+ // because token will release data only after SetNextToken
+ token->IncrementToken();
+ return TSlot<TAux>::NullElem();
+ }
+ return TSlot<TAux>::Pair(old, LinkArray[slot - FirstSlot].Retrieve());
+ }
+
+ inline TMsgBunch* GetNextBunch() const {
+ return AtomicGet(NextBunch);
+ }
+
+ inline bool SetNextBunch(TMsgBunch* ptr) {
+ return AtomicCas(&NextBunch, ptr, nullptr);
+ }
+
+ inline TMsgBunch* GetBackLink() const {
+ return AtomicGet(BackLink);
+ }
+
+ inline TMsgBunch* GetToken(ui64 slot) {
+ return reinterpret_cast<TMsgBunch*>(LinkArray[slot - FirstSlot].Msg);
+ }
+
+ inline void IncrementToken() {
+ AtomicIncrement(Token);
+ }
+
+ // the object could be destroyed after this method
+ inline void DecrementToken() {
+ if (Y_UNLIKELY(AtomicDecrement(Token) == BUNCH_SIZE)) {
+ Release(this);
+ AtomicGet(NextToken)->DecrementToken();
+ // this could be invalid here
+ }
+ }
+
+ // the object could be destroyed after this method
+ inline void SetNextToken(TMsgBunch* next) {
+ AtomicSet(NextToken, next);
+ if (Y_UNLIKELY(AtomicAdd(Token, BUNCH_SIZE) == BUNCH_SIZE)) {
+ Release(this);
+ next->DecrementToken();
+ }
+ // this could be invalid here
+ }
+
+ TMsgBunch(ui64 start, TMsgBunch* backLink) {
+ AtomicSet(FirstSlot, start);
+ memset(&LinkArray, 0, sizeof(LinkArray));
+ AtomicSet(NextBunch, nullptr);
+ AtomicSet(BackLink, backLink);
+
+ AtomicSet(Token, 1);
+ AtomicSet(NextToken, nullptr);
+ }
+
+ static void Release(TMsgBunch* bunch) {
+ auto backLink = AtomicGet(bunch->BackLink);
+ if (backLink == nullptr) {
+ return;
+ }
+ AtomicSet(bunch->BackLink, nullptr);
+
+ do {
+ auto bbackLink = backLink->BackLink;
+ delete backLink;
+ backLink = bbackLink;
+ } while (backLink != nullptr);
+ }
+
+ void Destroy() {
+ for (auto tail = BackLink; tail != nullptr;) {
+ auto next = tail->BackLink;
+ delete tail;
+ tail = next;
+ }
+
+ for (auto next = this; next != nullptr;) {
+ auto nnext = next->NextBunch;
+ delete next;
+ next = nnext;
+ }
+ }
+ };
+
+ template <typename TAux, ui32 BUNCH_SIZE, typename TBunchBase = TEmpty>
+ class TWriteBucket {
+ public:
+ static const ui64 GROSS_SIZE;
+
+ using TBunch = TMsgBunch<TAux, BUNCH_SIZE, TBunchBase>;
+
+ TWriteBucket(TBunch* bunch = new TBunch(0, nullptr))
+ : LastBunch(bunch)
+ , SlotCounter(0)
+ {
+ }
+
+ TWriteBucket(TWriteBucket&& move)
+ : LastBunch(move.LastBunch)
+ , SlotCounter(move.SlotCounter)
+ {
+ move.LastBunch = nullptr;
+ }
+
+ ~TWriteBucket() {
+ if (LastBunch != nullptr) {
+ LastBunch->Destroy();
+ }
+ }
+
+ inline bool Push(TMsgLink msg, TAux aux) {
+ ui64 pushSlot = AtomicGetAndIncrement(SlotCounter);
+ TBunch* hintBunch = GetLastBunch();
+
+ for (;;) {
+ auto hint = hintBunch->Push(msg, pushSlot, aux);
+ if (Y_LIKELY(hint == PUSH_RESULT_OK)) {
+ return true;
+ }
+ bool hhResult = HandleHint(hintBunch, hint);
+ if (Y_UNLIKELY(!hhResult)) {
+ return false;
+ }
+ }
+ }
+
+ protected:
+ template <typename, ui32, typename>
+ friend class TReadBucket;
+
+ TBunch* volatile LastBunch; // Hint
+ volatile ui64 SlotCounter;
+
+ inline TBunch* GetLastBunch() const {
+ return AtomicGet(LastBunch);
+ }
+
+ bool HandleHint(TBunch*& hintBunch, TPushResult hint) {
+ if (Y_UNLIKELY(hint == PUSH_RESULT_BLOCKED)) {
+ return false;
+ }
+
+ if (Y_UNLIKELY(hint == PUSH_RESULT_BACKWARD)) {
+ hintBunch = hintBunch->GetBackLink();
+ return true;
+ }
+
+ // PUSH_RESULT_FORWARD
+ auto nextBunch = hintBunch->GetNextBunch();
+
+ if (nextBunch == nullptr) {
+ auto first = hintBunch->FirstSlot + BUNCH_SIZE;
+ nextBunch = new TBunch(first, hintBunch);
+ if (Y_UNLIKELY(!hintBunch->SetNextBunch(nextBunch))) {
+ delete nextBunch;
+ nextBunch = hintBunch->GetNextBunch();
+ }
+ }
+
+ // hintBunch could not be freed here so it cannot be reused
+ // it's alright if this CAS was not succeeded,
+ // it means that other thread did that recently
+ AtomicCas(&LastBunch, nextBunch, hintBunch);
+
+ hintBunch = nextBunch;
+ return true;
+ }
+ };
+
+ template <typename TAux, ui32 BUNCH_SIZE, typename TBunchBase>
+ class TReadBucket {
+ public:
+ static constexpr int MAX_NUMBER_OF_TRIES_TO_READ = 20;
+
+ using TWBucket = TWriteBucket<TAux, BUNCH_SIZE, TBunchBase>;
+ using TBunch = TMsgBunch<TAux, BUNCH_SIZE, TBunchBase>;
+
+ TReadBucket(TWBucket* writer)
+ : Writer(writer)
+ , ReadBunch(writer->GetLastBunch())
+ , LastKnownPushBunch(writer->GetLastBunch())
+ {
+ ReadBunch->DecrementToken(); // no previous token
+ }
+
+ TReadBucket(TReadBucket toCopy, TWBucket* writer)
+ : TReadBucket(std::move(toCopy))
+ {
+ Writer = writer;
+ }
+
+ ui64 ReadyCount() const {
+ return AtomicGet(Writer->SlotCounter) - ReadSlot;
+ }
+
+ inline TMsgLink Pop() {
+ return PopAux().Msg;
+ }
+
+ inline TSlot<TAux> PopAux() {
+ for (;;) {
+ if (Y_UNLIKELY(ReadSlot == LastKnownPushSlot)) {
+ if (Y_LIKELY(!RereadPushSlot())) {
+ return TSlot<TAux>::NullElem();
+ }
+ }
+
+ if (Y_UNLIKELY(!ReadBunch->IsSlotHere(ReadSlot))) {
+ if (Y_UNLIKELY(!SwitchToNextBunch())) {
+ return TSlot<TAux>::NullElem();
+ }
+ }
+
+ auto result = ReadBunch->GetSlotAux(ReadSlot);
+ if (Y_LIKELY(result.Msg != nullptr)) {
+ ++ReadSlot;
+ return result;
+ }
+
+ if (ReadSlot + 1 == AtomicGet(Writer->SlotCounter)) {
+ return TSlot<TAux>::NullElem();
+ }
+
+ result = StubbornPopAux();
+
+ if (result.Msg != nullptr) {
+ return result;
+ }
+ }
+ }
+
+ private:
+ TWBucket* Writer;
+ TBunch* ReadBunch;
+ ui64 ReadSlot = 0;
+ TBunch* LastKnownPushBunch;
+ ui64 LastKnownPushSlot = 0;
+
+ // MUST BE: ReadSlot == LastKnownPushSlot
+ bool RereadPushSlot() {
+ auto oldSlot = LastKnownPushSlot;
+
+ auto currentPushBunch = Writer->GetLastBunch();
+ auto currentPushSlot = AtomicGet(Writer->SlotCounter);
+
+ if (currentPushBunch != LastKnownPushBunch) {
+ // LastKnownPushBunch could be invalid after this line
+ LastKnownPushBunch->SetNextToken(currentPushBunch);
+ }
+
+ LastKnownPushBunch = currentPushBunch;
+ LastKnownPushSlot = currentPushSlot;
+
+ return oldSlot != LastKnownPushSlot;
+ }
+
+ bool SwitchToNextBunch() {
+ for (int q = 0; q < MAX_NUMBER_OF_TRIES_TO_READ; ++q) {
+ auto next = ReadBunch->GetNextBunch();
+ if (next != nullptr) {
+ ReadBunch = next;
+ return true;
+ }
+ SpinLockPause();
+ }
+ return false;
+ }
+
+ TSlot<TAux> StubbornPopAux() {
+ for (int q = 0; q < MAX_NUMBER_OF_TRIES_TO_READ; ++q) {
+ auto result = ReadBunch->GetSlotAux(ReadSlot);
+ if (Y_LIKELY(result.Msg != nullptr)) {
+ ++ReadSlot;
+ return result;
+ }
+ SpinLockPause();
+ }
+
+ return ReadBunch->BlockSlotAux(ReadSlot++, LastKnownPushBunch);
+ }
+ };
+
+ struct TDefaultParams {
+ static constexpr bool DeleteItems = true;
+ using TAux = NObstructiveQueuePrivate::TEmptyAux;
+ using TBunchBase = NObstructiveQueuePrivate::TEmpty;
+ static constexpr ui32 BUNCH_SIZE = 251;
+ };
+
+ } //namespace NObstructiveQueuePrivate
+
+ DeclareTuneValueParam(TObstructiveQueueBunchSize, ui32, BUNCH_SIZE);
+ DeclareTuneValueParam(TObstructiveQueueDeleteItems, bool, DeleteItems);
+ DeclareTuneTypeParam(TObstructiveQueueBunchBase, TBunchBase);
+ DeclareTuneTypeParam(TObstructiveQueueAux, TAux);
+
+ template <typename TItem = void, typename... TParams>
+ class TObstructiveConsumerAuxQueue {
+ private:
+ using TTuned =
+ TTune<NObstructiveQueuePrivate::TDefaultParams, TParams...>;
+
+ using TAux = typename TTuned::TAux;
+ using TSlot = NObstructiveQueuePrivate::TSlot<TAux>;
+ using TMsgLink = NObstructiveQueuePrivate::TMsgLink;
+ using TBunchBase = typename TTuned::TBunchBase;
+ static constexpr bool DeleteItems = TTuned::DeleteItems;
+ static constexpr ui32 BUNCH_SIZE = TTuned::BUNCH_SIZE;
+
+ public:
+ TObstructiveConsumerAuxQueue()
+ : RBuckets(&WBucket)
+ {
+ }
+
+ ~TObstructiveConsumerAuxQueue() {
+ if (DeleteItems) {
+ for (;;) {
+ auto msg = Pop();
+ if (msg == nullptr) {
+ break;
+ }
+ TDelete::Destroy(msg);
+ }
+ }
+ }
+
+ void Push(TItem* msg) {
+ while (!WBucket.Push(reinterpret_cast<TMsgLink>(msg), TAux())) {
+ }
+ }
+
+ TItem* Pop() {
+ return reinterpret_cast<TItem*>(RBuckets.Pop());
+ }
+
+ TSlot PopAux() {
+ return RBuckets.PopAux();
+ }
+
+ private:
+ NObstructiveQueuePrivate::TWriteBucket<TAux, BUNCH_SIZE, TBunchBase>
+ WBucket;
+ NObstructiveQueuePrivate::TReadBucket<TAux, BUNCH_SIZE, TBunchBase>
+ RBuckets;
+ };
+
+ template <typename TItem = void, bool DeleteItems = true>
+ class TObstructiveConsumerQueue
+ : public TObstructiveConsumerAuxQueue<TItem,
+ TObstructiveQueueDeleteItems<DeleteItems>> {
+ };
+}
diff --git a/library/cpp/threading/queue/queue_ut.cpp b/library/cpp/threading/queue/queue_ut.cpp
new file mode 100644
index 0000000000..80eca147da
--- /dev/null
+++ b/library/cpp/threading/queue/queue_ut.cpp
@@ -0,0 +1,242 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/system/thread.h>
+
+#include "ut_helpers.h"
+
+typedef void* TMsgLink;
+
+template <typename TQueueType>
+class TQueueTestProcs: public TTestBase {
+private:
+ UNIT_TEST_SUITE_DEMANGLE(TQueueTestProcs<TQueueType>);
+ UNIT_TEST(Threads2_Push1M_Threads1_Pop2M)
+ UNIT_TEST(Threads4_Push1M_Threads1_Pop4M)
+ UNIT_TEST(Threads8_RndPush100K_Threads8_Queues)
+ /*
+ UNIT_TEST(Threads24_RndPush100K_Threads24_Queues)
+ UNIT_TEST(Threads24_RndPush100K_Threads8_Queues)
+ UNIT_TEST(Threads24_RndPush100K_Threads4_Queues)
+*/
+ UNIT_TEST_SUITE_END();
+
+public:
+ void Push1M_Pop1M() {
+ TQueueType queue;
+ TMsgLink msg = &queue;
+
+ auto pmsg = queue.Pop();
+ UNIT_ASSERT_VALUES_EQUAL(pmsg, nullptr);
+
+ for (int i = 0; i < 1000000; ++i) {
+ queue.Push((char*)msg + i);
+ }
+
+ for (int i = 0; i < 1000000; ++i) {
+ auto popped = queue.Pop();
+ UNIT_ASSERT_EQUAL((char*)msg + i, popped);
+ }
+
+ pmsg = queue.Pop();
+ UNIT_ASSERT_VALUES_EQUAL(pmsg, nullptr);
+ }
+
+ void Threads2_Push1M_Threads1_Pop2M() {
+ TQueueType queue;
+
+ class TPusherThread: public ISimpleThread {
+ public:
+ TPusherThread(TQueueType& theQueue, char* start)
+ : Queue(theQueue)
+ , Arg(start)
+ {
+ }
+
+ TQueueType& Queue;
+ char* Arg;
+
+ void* ThreadProc() override {
+ for (int i = 0; i < 1000000; ++i) {
+ Queue.Push(Arg + i);
+ }
+ return nullptr;
+ }
+ };
+
+ TPusherThread pusher1(queue, (char*)&queue);
+ TPusherThread pusher2(queue, (char*)&queue + 2000000);
+
+ pusher1.Start();
+ pusher2.Start();
+
+ for (int i = 0; i < 2000000; ++i) {
+ while (queue.Pop() == nullptr) {
+ SpinLockPause();
+ }
+ }
+
+ auto pmsg = queue.Pop();
+ UNIT_ASSERT_VALUES_EQUAL(pmsg, nullptr);
+ }
+
+ void Threads4_Push1M_Threads1_Pop4M() {
+ TQueueType queue;
+
+ class TPusherThread: public ISimpleThread {
+ public:
+ TPusherThread(TQueueType& theQueue, char* start)
+ : Queue(theQueue)
+ , Arg(start)
+ {
+ }
+
+ TQueueType& Queue;
+ char* Arg;
+
+ void* ThreadProc() override {
+ for (int i = 0; i < 1000000; ++i) {
+ Queue.Push(Arg + i);
+ }
+ return nullptr;
+ }
+ };
+
+ TPusherThread pusher1(queue, (char*)&queue);
+ TPusherThread pusher2(queue, (char*)&queue + 2000000);
+ TPusherThread pusher3(queue, (char*)&queue + 4000000);
+ TPusherThread pusher4(queue, (char*)&queue + 6000000);
+
+ pusher1.Start();
+ pusher2.Start();
+ pusher3.Start();
+ pusher4.Start();
+
+ for (int i = 0; i < 4000000; ++i) {
+ while (queue.Pop() == nullptr) {
+ SpinLockPause();
+ }
+ }
+
+ auto pmsg = queue.Pop();
+ UNIT_ASSERT_VALUES_EQUAL(pmsg, nullptr);
+ }
+
+ template <size_t NUMBER_OF_PUSHERS, size_t NUMBER_OF_QUEUES>
+ void ManyRndPush100K_ManyQueues() {
+ TQueueType queue[NUMBER_OF_QUEUES];
+
+ class TPusherThread: public ISimpleThread {
+ public:
+ TPusherThread(TQueueType* queues, char* start)
+ : Queues(queues)
+ , Arg(start)
+ {
+ }
+
+ TQueueType* Queues;
+ char* Arg;
+
+ void* ThreadProc() override {
+ ui64 counters[NUMBER_OF_QUEUES];
+ for (size_t i = 0; i < NUMBER_OF_QUEUES; ++i) {
+ counters[i] = 0;
+ }
+
+ for (int i = 0; i < 100000; ++i) {
+ size_t rnd = GetCycleCount() % NUMBER_OF_QUEUES;
+ int cookie = counters[rnd]++;
+ Queues[rnd].Push(Arg + cookie);
+ }
+
+ for (size_t i = 0; i < NUMBER_OF_QUEUES; ++i) {
+ Queues[i].Push((void*)2ULL);
+ }
+
+ return nullptr;
+ }
+ };
+
+ class TPopperThread: public ISimpleThread {
+ public:
+ TPopperThread(TQueueType* theQueue, char* base)
+ : Queue(theQueue)
+ , Base(base)
+ {
+ }
+
+ TQueueType* Queue;
+ char* Base;
+
+ void* ThreadProc() override {
+ ui64 counters[NUMBER_OF_PUSHERS];
+ for (size_t i = 0; i < NUMBER_OF_PUSHERS; ++i) {
+ counters[i] = 0;
+ }
+
+ for (size_t fin = 0; fin < NUMBER_OF_PUSHERS;) {
+ auto msg = Queue->Pop();
+ if (msg == nullptr) {
+ SpinLockPause();
+ continue;
+ }
+ if (msg == (void*)2ULL) {
+ ++fin;
+ continue;
+ }
+ ui64 shift = (char*)msg - Base;
+ auto pusherNum = shift / 200000000ULL;
+ auto msgNum = shift % 200000000ULL;
+
+ UNIT_ASSERT_EQUAL(counters[pusherNum], msgNum);
+ ++counters[pusherNum];
+ }
+
+ auto pmsg = Queue->Pop();
+ UNIT_ASSERT_VALUES_EQUAL(pmsg, nullptr);
+
+ return nullptr;
+ }
+ };
+
+ TVector<TAutoPtr<TPopperThread>> poppers;
+ TVector<TAutoPtr<TPusherThread>> pushers;
+
+ for (size_t i = 0; i < NUMBER_OF_QUEUES; ++i) {
+ poppers.emplace_back(new TPopperThread(&queue[i], (char*)&queue));
+ poppers.back()->Start();
+ }
+
+ for (size_t i = 0; i < NUMBER_OF_PUSHERS; ++i) {
+ pushers.emplace_back(
+ new TPusherThread(queue, (char*)&queue + 200000000ULL * i));
+ pushers.back()->Start();
+ }
+
+ for (size_t i = 0; i < NUMBER_OF_QUEUES; ++i) {
+ poppers[i]->Join();
+ }
+
+ for (size_t i = 0; i < NUMBER_OF_PUSHERS; ++i) {
+ pushers[i]->Join();
+ }
+ }
+
+ void Threads8_RndPush100K_Threads8_Queues() {
+ ManyRndPush100K_ManyQueues<8, 8>();
+ }
+
+ /*
+ void Threads24_RndPush100K_Threads24_Queues() {
+ ManyRndPush100K_ManyQueues<24, 24>();
+ }
+
+ void Threads24_RndPush100K_Threads8_Queues() {
+ ManyRndPush100K_ManyQueues<24, 8>();
+ }
+
+ void Threads24_RndPush100K_Threads4_Queues() {
+ ManyRndPush100K_ManyQueues<24, 4>();
+ }
+ */
+};
+
+REGISTER_TESTS_FOR_ALL_ORDERED_QUEUES(TQueueTestProcs);
diff --git a/library/cpp/threading/queue/tune.h b/library/cpp/threading/queue/tune.h
new file mode 100644
index 0000000000..50fc3dc17c
--- /dev/null
+++ b/library/cpp/threading/queue/tune.h
@@ -0,0 +1,125 @@
+#pragma once
+
+/*
+ Motivation: consider you have a template class with many parameters
+ with default associations
+
+ template <typename A = TDefA,
+ typename B = TDefB,
+ typename C = TDefC,
+ typename D = TDefD>
+ class TExample {
+ };
+
+ consider you would like to provide easy to use interface to tune all
+ these parameters in position independed manner,
+ In that case TTune would be helpful for you.
+
+ How to use:
+ First step: declare a struct with all default associations
+
+ struct TDefaultTune {
+ using TStructA = TDefA;
+ using TStructB = TDefB;
+ using TStructC = TDefC;
+ using TStructD = TDefD;
+ };
+
+ Second step: declare helper names visible to a user
+
+ DeclareTuneTypeParam(TTuneParamA, TStructA);
+ DeclareTuneTypeParam(TTuneParamB, TStructB);
+ DeclareTuneTypeParam(TTuneParamC, TStructC);
+ DeclareTuneTypeParam(TTuneParamD, TStructD);
+
+ Third step: declare TExample this way:
+
+ template <typename...TParams>
+ class TExample {
+ using TMyParams = TTune<TDefaultTune, TParams...>;
+
+ using TActualA = TMyParams::TStructA;
+ using TActualB = TMyParams::TStructB;
+ ...
+ };
+
+ TTune<TDefaultTune, TParams...> is a struct with the default parameteres
+ taken from TDefaultTune and overridden from "TParams...".
+
+ for example: "TTune<TDefaultTune, TTuneParamC<TUserClass>>"
+ will be virtually the same as:
+
+ struct TTunedClass {
+ using TStructA = TDefA;
+ using TStructB = TDefB;
+ using TStructC = TUserClass;
+ using TStructD = TDefD;
+ };
+
+ From now on you can tune your TExample in the following manner:
+
+ using TCustomClass =
+ TExample <TTuneParamA<TUserStruct1>, TTuneParamD<TUserStruct2>>;
+
+ You can also tweak constant expressions in your TDefaultTune.
+ Consider you have:
+
+ struct TDefaultTune {
+ static constexpr ui32 MySize = 42;
+ };
+
+ declare an interface to modify the parameter this way:
+
+ DeclareTuneValueParam(TStructSize, ui32, MySize);
+
+ and tweak your class:
+
+ using TTwiceBigger = TExample<TStructSize<84>>;
+
+ */
+
+#define DeclareTuneTypeParam(TParamName, InternalName) \
+ template <typename TNewType> \
+ struct TParamName { \
+ template <typename TBase> \
+ struct TApply: public TBase { \
+ using InternalName = TNewType; \
+ }; \
+ }
+
+#define DeclareTuneValueParam(TParamName, TValueType, InternalName) \
+ template <TValueType NewValue> \
+ struct TParamName { \
+ template <typename TBase> \
+ struct TApply: public TBase { \
+ static constexpr TValueType InternalName = NewValue; \
+ }; \
+ }
+
+#define DeclareTuneContainer(TParamName, InternalName) \
+ template <template <typename, typename...> class TNewContainer> \
+ struct TParamName { \
+ template <typename TBase> \
+ struct TApply: public TBase { \
+ template <typename TElem, typename... TRest> \
+ using InternalName = TNewContainer<TElem, TRest...>; \
+ }; \
+ }
+
+namespace NTunePrivate {
+ template <typename TBase, typename... TParams>
+ struct TFold;
+
+ template <typename TBase>
+ struct TFold<TBase>: public TBase {
+ };
+
+ template <typename TBase, typename TFirstArg, typename... TRest>
+ struct TFold<TBase, TFirstArg, TRest...>
+ : public TFold<typename TFirstArg::template TApply<TBase>, TRest...> {
+ };
+}
+
+template <typename TDefault, typename... TParams>
+struct TTune: public NTunePrivate::TFold<TDefault, TParams...> {
+};
diff --git a/library/cpp/threading/queue/tune_ut.cpp b/library/cpp/threading/queue/tune_ut.cpp
new file mode 100644
index 0000000000..7e980d3e27
--- /dev/null
+++ b/library/cpp/threading/queue/tune_ut.cpp
@@ -0,0 +1,118 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include "tune.h"
+
+struct TDefaultStructA {
+};
+
+struct TDefaultStructB {
+};
+
+struct TDefaults {
+ using TStructA = TDefaultStructA;
+ using TStructB = TDefaultStructB;
+ static constexpr ui32 Param1 = 42;
+ static constexpr ui32 Param2 = 42;
+};
+
+DeclareTuneTypeParam(TweakStructA, TStructA);
+DeclareTuneTypeParam(TweakStructB, TStructB);
+DeclareTuneValueParam(TweakParam1, ui32, Param1);
+DeclareTuneValueParam(TweakParam2, ui32, Param2);
+
+Y_UNIT_TEST_SUITE(TestTuning) {
+ Y_UNIT_TEST(Defaults) {
+ using TTuned = TTune<TDefaults>;
+ using TunedA = TTuned::TStructA;
+ using TunedB = TTuned::TStructB;
+ auto sameA = std::is_same<TDefaultStructA, TunedA>::value;
+ auto sameB = std::is_same<TDefaultStructB, TunedB>::value;
+ auto param1 = TTuned::Param1;
+ auto param2 = TTuned::Param2;
+
+ UNIT_ASSERT(sameA);
+ UNIT_ASSERT(sameB);
+ UNIT_ASSERT_EQUAL(param1, 42);
+ UNIT_ASSERT_EQUAL(param2, 42);
+ }
+
+ Y_UNIT_TEST(TuneStructA) {
+ struct TMyStruct {
+ };
+
+ using TTuned = TTune<TDefaults, TweakStructA<TMyStruct>>;
+
+ using TunedA = TTuned::TStructA;
+ using TunedB = TTuned::TStructB;
+ //auto sameA = std::is_same<TDefaultStructA, TunedA>::value;
+ auto sameB = std::is_same<TDefaultStructB, TunedB>::value;
+ auto param1 = TTuned::Param1;
+ auto param2 = TTuned::Param2;
+
+ auto sameA = std::is_same<TMyStruct, TunedA>::value;
+
+ UNIT_ASSERT(sameA);
+ UNIT_ASSERT(sameB);
+ UNIT_ASSERT_EQUAL(param1, 42);
+ UNIT_ASSERT_EQUAL(param2, 42);
+ }
+
+ Y_UNIT_TEST(TuneParam1) {
+ using TTuned = TTune<TDefaults, TweakParam1<24>>;
+
+ using TunedA = TTuned::TStructA;
+ using TunedB = TTuned::TStructB;
+ auto sameA = std::is_same<TDefaultStructA, TunedA>::value;
+ auto sameB = std::is_same<TDefaultStructB, TunedB>::value;
+ auto param1 = TTuned::Param1;
+ auto param2 = TTuned::Param2;
+
+ UNIT_ASSERT(sameA);
+ UNIT_ASSERT(sameB);
+ UNIT_ASSERT_EQUAL(param1, 24);
+ UNIT_ASSERT_EQUAL(param2, 42);
+ }
+
+ Y_UNIT_TEST(TuneStructAAndParam1) {
+ struct TMyStruct {
+ };
+
+ using TTuned =
+ TTune<TDefaults, TweakStructA<TMyStruct>, TweakParam1<24>>;
+
+ using TunedA = TTuned::TStructA;
+ using TunedB = TTuned::TStructB;
+ //auto sameA = std::is_same<TDefaultStructA, TunedA>::value;
+ auto sameB = std::is_same<TDefaultStructB, TunedB>::value;
+ auto param1 = TTuned::Param1;
+ auto param2 = TTuned::Param2;
+
+ auto sameA = std::is_same<TMyStruct, TunedA>::value;
+
+ UNIT_ASSERT(sameA);
+ UNIT_ASSERT(sameB);
+ UNIT_ASSERT_EQUAL(param1, 24);
+ UNIT_ASSERT_EQUAL(param2, 42);
+ }
+
+ Y_UNIT_TEST(TuneParam1AndStructA) {
+ struct TMyStruct {
+ };
+
+ using TTuned =
+ TTune<TDefaults, TweakParam1<24>, TweakStructA<TMyStruct>>;
+
+ using TunedA = TTuned::TStructA;
+ using TunedB = TTuned::TStructB;
+ //auto sameA = std::is_same<TDefaultStructA, TunedA>::value;
+ auto sameB = std::is_same<TDefaultStructB, TunedB>::value;
+ auto param1 = TTuned::Param1;
+ auto param2 = TTuned::Param2;
+
+ auto sameA = std::is_same<TMyStruct, TunedA>::value;
+
+ UNIT_ASSERT(sameA);
+ UNIT_ASSERT(sameB);
+ UNIT_ASSERT_EQUAL(param1, 24);
+ UNIT_ASSERT_EQUAL(param2, 42);
+ }
+}
diff --git a/library/cpp/threading/queue/unordered_ut.cpp b/library/cpp/threading/queue/unordered_ut.cpp
new file mode 100644
index 0000000000..a43b7f520e
--- /dev/null
+++ b/library/cpp/threading/queue/unordered_ut.cpp
@@ -0,0 +1,154 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/system/thread.h>
+#include <algorithm>
+#include <util/generic/vector.h>
+#include <util/random/fast.h>
+
+#include "ut_helpers.h"
+
+template <typename TQueueType>
+class TTestUnorderedQueue: public TTestBase {
+private:
+ using TLink = TIntrusiveLink;
+
+ UNIT_TEST_SUITE_DEMANGLE(TTestUnorderedQueue<TQueueType>);
+ UNIT_TEST(Push1M_Pop1M_Unordered)
+ UNIT_TEST_SUITE_END();
+
+public:
+ void Push1M_Pop1M_Unordered() {
+ constexpr int REPEAT = 1000000;
+ TQueueType queue;
+ TLink msg[REPEAT];
+
+ auto pmsg = queue.Pop();
+ UNIT_ASSERT_VALUES_EQUAL(pmsg, nullptr);
+
+ for (int i = 0; i < REPEAT; ++i) {
+ queue.Push(&msg[i]);
+ }
+
+ TVector<TLink*> popped;
+ popped.reserve(REPEAT);
+ for (int i = 0; i < REPEAT; ++i) {
+ popped.push_back((TLink*)queue.Pop());
+ }
+
+ pmsg = queue.Pop();
+ UNIT_ASSERT_VALUES_EQUAL(pmsg, nullptr);
+
+ std::sort(popped.begin(), popped.end());
+ for (int i = 0; i < REPEAT; ++i) {
+ UNIT_ASSERT_VALUES_EQUAL(&msg[i], popped[i]);
+ }
+ }
+};
+
+template <typename TQueueType>
+class TTestWeakQueue: public TTestBase {
+private:
+ UNIT_TEST_SUITE_DEMANGLE(TTestWeakQueue<TQueueType>);
+ UNIT_TEST(Threads8_Rnd_Exchange)
+ UNIT_TEST_SUITE_END();
+
+public:
+ template <ui16 COUNT = 48, ui32 MSG_COUNT = 10000>
+ void ManyThreadsRndExchange() {
+ TQueueType queues[COUNT];
+
+ class TWorker: public ISimpleThread {
+ public:
+ TWorker(
+ TQueueType* queues_,
+ ui16 mine,
+ TAtomic* pushDone)
+ : Queues(queues_)
+ , MineQueue(mine)
+ , PushDone(pushDone)
+ {
+ }
+
+ TQueueType* Queues;
+ ui16 MineQueue;
+ TVector<uintptr_t> Received;
+ TAtomic* PushDone;
+
+ void* ThreadProc() override {
+ TReallyFastRng32 rng(GetCycleCount());
+ Received.reserve(MSG_COUNT * 2);
+
+ for (ui32 loop = 1; loop <= MSG_COUNT; ++loop) {
+ for (;;) {
+ auto msg = Queues[MineQueue].Pop();
+ if (msg == nullptr) {
+ break;
+ }
+
+ Received.push_back((uintptr_t)msg);
+ }
+
+ ui16 rnd = rng.GenRand64() % COUNT;
+ ui64 msg = ((ui64)MineQueue << 32) + loop;
+ while (!Queues[rnd].Push((void*)msg)) {
+ }
+ }
+
+ AtomicIncrement(*PushDone);
+
+ for (;;) {
+ bool isItLast = AtomicGet(*PushDone) == COUNT;
+ auto msg = Queues[MineQueue].Pop();
+ if (msg != nullptr) {
+ Received.push_back((uintptr_t)msg);
+ } else {
+ if (isItLast) {
+ break;
+ }
+ SpinLockPause();
+ }
+ }
+
+ for (ui64 last = 0;;) {
+ auto msg = Queues[MineQueue].UnsafeScanningPop(&last);
+ if (msg == nullptr) {
+ break;
+ }
+ Received.push_back((uintptr_t)msg);
+ }
+
+ return nullptr;
+ }
+ };
+
+ TVector<TAutoPtr<TWorker>> workers;
+ TAtomic pushDone = 0;
+
+ for (ui32 i = 0; i < COUNT; ++i) {
+ workers.emplace_back(new TWorker(&queues[0], i, &pushDone));
+ workers.back()->Start();
+ }
+
+ TVector<uintptr_t> all;
+ for (ui32 i = 0; i < COUNT; ++i) {
+ workers[i]->Join();
+ all.insert(all.begin(),
+ workers[i]->Received.begin(), workers[i]->Received.end());
+ }
+
+ std::sort(all.begin(), all.end());
+ auto iter = all.begin();
+ for (ui32 i = 0; i < COUNT; ++i) {
+ for (ui32 k = 1; k <= MSG_COUNT; ++k) {
+ UNIT_ASSERT_VALUES_EQUAL(((ui64)i << 32) + k, *iter);
+ ++iter;
+ }
+ }
+ }
+
+ void Threads8_Rnd_Exchange() {
+ ManyThreadsRndExchange<8>();
+ }
+};
+
+REGISTER_TESTS_FOR_ALL_UNORDERED_QUEUES(TTestUnorderedQueue);
+UNIT_TEST_SUITE_REGISTRATION(TTestWeakQueue<TMPMCUnorderedRing>);
diff --git a/library/cpp/threading/queue/ut/ya.make b/library/cpp/threading/queue/ut/ya.make
new file mode 100644
index 0000000000..8883d9bf69
--- /dev/null
+++ b/library/cpp/threading/queue/ut/ya.make
@@ -0,0 +1,16 @@
+UNITTEST_FOR(library/cpp/threading/queue)
+
+OWNER(agri)
+
+ALLOCATOR(B)
+
+SRCS(
+ basic_ut.cpp
+ queue_ut.cpp
+ tune_ut.cpp
+ unordered_ut.cpp
+ ut_helpers.cpp
+ ut_helpers.h
+)
+
+END()
diff --git a/library/cpp/threading/queue/ut_helpers.cpp b/library/cpp/threading/queue/ut_helpers.cpp
new file mode 100644
index 0000000000..aa3a831441
--- /dev/null
+++ b/library/cpp/threading/queue/ut_helpers.cpp
@@ -0,0 +1 @@
+#include "ut_helpers.h"
diff --git a/library/cpp/threading/queue/ut_helpers.h b/library/cpp/threading/queue/ut_helpers.h
new file mode 100644
index 0000000000..2756b52601
--- /dev/null
+++ b/library/cpp/threading/queue/ut_helpers.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "mpsc_read_as_filled.h"
+#include "mpsc_htswap.h"
+#include "mpsc_vinfarr_obstructive.h"
+#include "mpsc_intrusive_unordered.h"
+#include "mpmc_unordered_ring.h"
+
+struct TBasicHTSwap: public NThreading::THTSwapQueue<> {
+};
+
+struct TBasicReadAsFilled: public NThreading::TReadAsFilledQueue<> {
+};
+
+struct TBasicObstructiveConsumer
+ : public NThreading::TObstructiveConsumerQueue<> {
+};
+
+struct TBasicMPSCIntrusiveUnordered
+ : public NThreading::TMPSCIntrusiveUnordered {
+};
+
+struct TIntrusiveLink: public NThreading::TIntrusiveNode {
+};
+
+struct TMPMCUnorderedRing: public NThreading::TMPMCUnorderedRing {
+ TMPMCUnorderedRing()
+ : NThreading::TMPMCUnorderedRing(10000000)
+ {
+ }
+};
+
+#define REGISTER_TESTS_FOR_ALL_ORDERED_QUEUES(TestTemplate) \
+ UNIT_TEST_SUITE_REGISTRATION(TestTemplate<TBasicHTSwap>); \
+ UNIT_TEST_SUITE_REGISTRATION(TestTemplate<TBasicReadAsFilled>); \
+ UNIT_TEST_SUITE_REGISTRATION(TestTemplate<TBasicObstructiveConsumer>)
+
+#define REGISTER_TESTS_FOR_ALL_UNORDERED_QUEUES(TestTemplate) \
+ UNIT_TEST_SUITE_REGISTRATION(TestTemplate<TBasicMPSCIntrusiveUnordered>); \
+ UNIT_TEST_SUITE_REGISTRATION(TestTemplate<TMPMCUnorderedRing>);
diff --git a/library/cpp/threading/queue/ya.make b/library/cpp/threading/queue/ya.make
new file mode 100644
index 0000000000..6570b38ce5
--- /dev/null
+++ b/library/cpp/threading/queue/ya.make
@@ -0,0 +1,18 @@
+LIBRARY()
+
+OWNER(agri)
+
+SRCS(
+ mpmc_unordered_ring.cpp
+ mpmc_unordered_ring.h
+ mpsc_htswap.cpp
+ mpsc_htswap.h
+ mpsc_intrusive_unordered.cpp
+ mpsc_intrusive_unordered.h
+ mpsc_read_as_filled.cpp
+ mpsc_read_as_filled.h
+ mpsc_vinfarr_obstructive.cpp
+ mpsc_vinfarr_obstructive.h
+)
+
+END()
diff --git a/library/cpp/threading/skip_list/compare.h b/library/cpp/threading/skip_list/compare.h
new file mode 100644
index 0000000000..ac98b3e1ce
--- /dev/null
+++ b/library/cpp/threading/skip_list/compare.h
@@ -0,0 +1,77 @@
+#pragma once
+
+#include <util/generic/typetraits.h>
+#include <util/str_stl.h>
+
+namespace NThreading {
+ namespace NImpl {
+ Y_HAS_MEMBER(compare);
+ Y_HAS_MEMBER(Compare);
+
+ template <typename T>
+ inline int CompareImpl(const T& l, const T& r) {
+ if (l < r) {
+ return -1;
+ } else if (r < l) {
+ return +1;
+ } else {
+ return 0;
+ }
+ }
+
+ template <bool val>
+ struct TSmallCompareSelector {
+ template <typename T>
+ static inline int Compare(const T& l, const T& r) {
+ return CompareImpl(l, r);
+ }
+ };
+
+ template <>
+ struct TSmallCompareSelector<true> {
+ template <typename T>
+ static inline int Compare(const T& l, const T& r) {
+ return l.compare(r);
+ }
+ };
+
+ template <bool val>
+ struct TBigCompareSelector {
+ template <typename T>
+ static inline int Compare(const T& l, const T& r) {
+ return TSmallCompareSelector<THascompare<T>::value>::Compare(l, r);
+ }
+ };
+
+ template <>
+ struct TBigCompareSelector<true> {
+ template <typename T>
+ static inline int Compare(const T& l, const T& r) {
+ return l.Compare(r);
+ }
+ };
+
+ template <typename T>
+ struct TCompareSelector: public TBigCompareSelector<THasCompare<T>::value> {
+ };
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Generic compare function
+
+ template <typename T>
+ inline int Compare(const T& l, const T& r) {
+ return NImpl::TCompareSelector<T>::Compare(l, r);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Generic compare functor
+
+ template <typename T>
+ struct TCompare {
+ inline int operator()(const T& l, const T& r) const {
+ return Compare(l, r);
+ }
+ };
+
+}
diff --git a/library/cpp/threading/skip_list/perf/main.cpp b/library/cpp/threading/skip_list/perf/main.cpp
new file mode 100644
index 0000000000..4ad52049e7
--- /dev/null
+++ b/library/cpp/threading/skip_list/perf/main.cpp
@@ -0,0 +1,362 @@
+#include <library/cpp/threading/skip_list/skiplist.h>
+
+#include <library/cpp/getopt/small/last_getopt.h>
+
+#include <library/cpp/charset/ci_string.h>
+#include <util/datetime/base.h>
+#include <util/generic/map.h>
+#include <util/generic/vector.h>
+#include <functional>
+#include <util/memory/pool.h>
+#include <util/random/random.h>
+#include <util/string/join.h>
+#include <util/system/mutex.h>
+#include <util/system/thread.h>
+
+namespace {
+ using namespace NThreading;
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ IOutputStream& LogInfo() {
+ return Cerr << TInstant::Now() << " INFO: ";
+ }
+
+ IOutputStream& LogError() {
+ return Cerr << TInstant::Now() << " ERROR: ";
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ struct TListItem {
+ TStringBuf Key;
+ TStringBuf Value;
+
+ TListItem(const TStringBuf& key, const TStringBuf& value)
+ : Key(key)
+ , Value(value)
+ {
+ }
+
+ int Compare(const TListItem& other) const {
+ return Key.compare(other.Key);
+ }
+ };
+
+ using TListType = TSkipList<TListItem>;
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TRandomData {
+ private:
+ TVector<char> Buffer;
+
+ public:
+ TRandomData()
+ : Buffer(1024 * 1024)
+ {
+ for (size_t i = 0; i < Buffer.size(); ++i) {
+ Buffer[i] = RandomNumber<char>();
+ }
+ }
+
+ TStringBuf GetString(size_t len) const {
+ size_t start = RandomNumber(Buffer.size() - len);
+ return TStringBuf(&Buffer[start], len);
+ }
+
+ TStringBuf GetString(size_t min, size_t max) const {
+ return GetString(min + RandomNumber(max - min));
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TWorkerThread: public ISimpleThread {
+ private:
+ std::function<void()> Func;
+ TDuration Time;
+
+ public:
+ TWorkerThread(std::function<void()> func)
+ : Func(func)
+ {
+ }
+
+ TDuration GetTime() const {
+ return Time;
+ }
+
+ private:
+ void* ThreadProc() noexcept override {
+ TInstant started = TInstant::Now();
+ Func();
+ Time = TInstant::Now() - started;
+ return nullptr;
+ }
+ };
+
+ inline TAutoPtr<TWorkerThread> StartThread(std::function<void()> func) {
+ TAutoPtr<TWorkerThread> thread = new TWorkerThread(func);
+ thread->Start();
+ return thread;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ typedef std::function<void()> TTestFunc;
+
+ struct TTest {
+ TString Name;
+ TTestFunc Func;
+
+ TTest() {
+ }
+
+ TTest(const TString& name, const TTestFunc& func)
+ : Name(name)
+ , Func(func)
+ {
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TTestSuite {
+ private:
+ size_t Iterations = 1000000;
+ size_t KeyLen = 10;
+ size_t ValueLen = 100;
+ size_t NumReaders = 4;
+ size_t NumWriters = 1;
+ size_t BatchSize = 20;
+
+ TMemoryPool MemoryPool;
+ TListType List;
+ TMutex Mutex;
+ TRandomData Random;
+
+ TMap<TCiString, TTest> AllTests;
+ TVector<TTest> Tests;
+
+ public:
+ TTestSuite()
+ : MemoryPool(64 * 1024)
+ , List(MemoryPool)
+ {
+ }
+
+ bool Init(int argc, const char* argv[]) {
+ TVector<TString> tests;
+ try {
+ NLastGetopt::TOpts opts;
+ opts.AddHelpOption();
+
+#define OPTION(opt, x) \
+ opts.AddLongOption(opt, #x) \
+ .Optional() \
+ .DefaultValue(ToString(x)) \
+ .StoreResult(&x) // end of OPTION
+
+ OPTION('i', Iterations);
+ OPTION('k', KeyLen);
+ OPTION('v', ValueLen);
+ OPTION('r', NumReaders);
+ OPTION('w', NumWriters);
+ OPTION('b', BatchSize);
+
+#undef OPTION
+
+ NLastGetopt::TOptsParseResultException optsRes(&opts, argc, argv);
+ for (const auto& opt : opts.Opts_) {
+ const NLastGetopt::TOptParseResult* r = optsRes.FindOptParseResult(opt.Get(), true);
+ if (r) {
+ LogInfo() << "[-" << opt->GetChar() << "] " << opt->GetName() << ": " << r->Back() << Endl;
+ }
+ }
+ tests = optsRes.GetFreeArgs();
+ } catch (...) {
+ LogError() << CurrentExceptionMessage() << Endl;
+ return false;
+ }
+
+#define TEST(type) \
+ AddTest(#type, std::bind(&TTestSuite::Y_CAT(TEST_, type), this)) // end of TEST
+
+ TEST(Clear);
+ TEST(InsertRandom);
+ TEST(InsertSequential);
+ TEST(InsertSequentialSimple);
+ TEST(LookupRandom);
+ TEST(Concurrent);
+
+#undef TEST
+
+ if (tests.empty()) {
+ LogError() << "no tests specified, choose from: " << PrintTests() << Endl;
+ return false;
+ }
+
+ for (size_t i = 0; i < tests.size(); ++i) {
+ if (!AllTests.contains(tests[i])) {
+ LogError() << "unknown test name: " << tests[i] << Endl;
+ return false;
+ }
+ Tests.push_back(AllTests[tests[i]]);
+ }
+
+ return true;
+ }
+
+ void Run() {
+#if !defined(NDEBUG)
+ LogInfo() << "*** DEBUG build! ***" << Endl;
+#endif
+
+ for (const TTest& test : Tests) {
+ LogInfo() << "Starting test " << test.Name << Endl;
+
+ TInstant started = TInstant::Now();
+ try {
+ test.Func();
+ } catch (...) {
+ LogError() << "test " << test.Name
+ << " failed: " << CurrentExceptionMessage()
+ << Endl;
+ }
+
+ LogInfo() << "List size = " << List.GetSize() << Endl;
+
+ TDuration duration = TInstant::Now() - started;
+ LogInfo() << "test " << test.Name
+ << " duration: " << duration
+ << " (" << (double)duration.MicroSeconds() / (Iterations * NumWriters) << "us per iteration)"
+ << Endl;
+ LogInfo() << "Finished test " << test.Name << Endl;
+ }
+ }
+
+ private:
+ void AddTest(const char* name, TTestFunc func) {
+ AllTests[name] = TTest(name, func);
+ }
+
+ TString PrintTests() const {
+ TVector<TString> names;
+ for (const auto& it : AllTests) {
+ names.push_back(it.first);
+ }
+ return JoinSeq(", ", names);
+ }
+
+ void TEST_Clear() {
+ List.Clear();
+ }
+
+ void TEST_InsertRandom() {
+ for (size_t i = 0; i < Iterations; ++i) {
+ List.Insert(TListItem(Random.GetString(KeyLen), Random.GetString(ValueLen)));
+ }
+ }
+
+ void TEST_InsertSequential() {
+ TString key;
+ for (size_t i = 0; i < Iterations;) {
+ key.assign(Random.GetString(KeyLen));
+ size_t batch = BatchSize / 2 + RandomNumber(BatchSize);
+ for (size_t j = 0; j < batch; ++j, ++i) {
+ key.resize(KeyLen - 1);
+ key.append((char)j);
+ List.Insert(TListItem(key, Random.GetString(ValueLen)));
+ }
+ }
+ }
+
+ void TEST_InsertSequentialSimple() {
+ for (size_t i = 0; i < Iterations; ++i) {
+ List.Insert(TListItem(Random.GetString(KeyLen), Random.GetString(ValueLen)));
+ }
+ }
+
+ void TEST_LookupRandom() {
+ for (size_t i = 0; i < Iterations; ++i) {
+ List.SeekTo(TListItem(Random.GetString(KeyLen), TStringBuf()));
+ }
+ }
+
+ void TEST_Concurrent() {
+ LogInfo() << "starting producers..." << Endl;
+
+ TVector<TAutoPtr<TWorkerThread>> producers(NumWriters);
+ for (size_t i1 = 0; i1 < producers.size(); ++i1) {
+ producers[i1] = StartThread([&] {
+ TInstant started = TInstant::Now();
+ for (size_t i2 = 0; i2 < Iterations; ++i2) {
+ {
+ TGuard<TMutex> guard(Mutex);
+ List.Insert(TListItem(Random.GetString(KeyLen), Random.GetString(ValueLen)));
+ }
+ }
+ TDuration duration = TInstant::Now() - started;
+ LogInfo()
+ << "Average time for producer = "
+ << (double)duration.MicroSeconds() / Iterations << "us per iteration"
+ << Endl;
+ });
+ }
+
+ LogInfo() << "starting consumers..." << Endl;
+
+ TVector<TAutoPtr<TWorkerThread>> consumers(NumReaders);
+ for (size_t i1 = 0; i1 < consumers.size(); ++i1) {
+ consumers[i1] = StartThread([&] {
+ TInstant started = TInstant::Now();
+ for (size_t i2 = 0; i2 < Iterations; ++i2) {
+ List.SeekTo(TListItem(Random.GetString(KeyLen), TStringBuf()));
+ }
+ TDuration duration = TInstant::Now() - started;
+ LogInfo()
+ << "Average time for consumer = "
+ << (double)duration.MicroSeconds() / Iterations << "us per iteration"
+ << Endl;
+ });
+ }
+
+ LogInfo() << "wait for producers..." << Endl;
+
+ TDuration producerTime;
+ for (size_t i = 0; i < producers.size(); ++i) {
+ producers[i]->Join();
+ producerTime += producers[i]->GetTime();
+ }
+
+ LogInfo() << "wait for consumers..." << Endl;
+
+ TDuration consumerTime;
+ for (size_t i = 0; i < consumers.size(); ++i) {
+ consumers[i]->Join();
+ consumerTime += consumers[i]->GetTime();
+ }
+
+ LogInfo() << "average producer time: "
+ << producerTime.SecondsFloat() / producers.size() << " seconds"
+ << Endl;
+
+ LogInfo() << "average consumer time: "
+ << consumerTime.SecondsFloat() / consumers.size() << " seconds"
+ << Endl;
+ }
+ };
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+int main(int argc, const char* argv[]) {
+ TTestSuite suite;
+ if (!suite.Init(argc, argv)) {
+ return -1;
+ }
+ suite.Run();
+ return 0;
+}
diff --git a/library/cpp/threading/skip_list/perf/ya.make b/library/cpp/threading/skip_list/perf/ya.make
new file mode 100644
index 0000000000..01bfafa404
--- /dev/null
+++ b/library/cpp/threading/skip_list/perf/ya.make
@@ -0,0 +1,15 @@
+PROGRAM(skiplist-perf)
+
+OWNER(g:rtmr)
+
+PEERDIR(
+ library/cpp/charset
+ library/cpp/getopt/small
+ library/cpp/threading/skip_list
+)
+
+SRCS(
+ main.cpp
+)
+
+END()
diff --git a/library/cpp/threading/skip_list/skiplist.cpp b/library/cpp/threading/skip_list/skiplist.cpp
new file mode 100644
index 0000000000..c6e98816fb
--- /dev/null
+++ b/library/cpp/threading/skip_list/skiplist.cpp
@@ -0,0 +1 @@
+#include "skiplist.h"
diff --git a/library/cpp/threading/skip_list/skiplist.h b/library/cpp/threading/skip_list/skiplist.h
new file mode 100644
index 0000000000..914a7c6ee7
--- /dev/null
+++ b/library/cpp/threading/skip_list/skiplist.h
@@ -0,0 +1,408 @@
+#pragma once
+
+#include "compare.h"
+
+#include <util/generic/algorithm.h>
+#include <util/generic/noncopyable.h>
+#include <util/generic/typetraits.h>
+#include <util/memory/pool.h>
+#include <util/random/random.h>
+#include <util/system/atomic.h>
+
+namespace NThreading {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TNopCounter {
+ protected:
+ template <typename T>
+ void OnInsert(const T&) {
+ }
+
+ template <typename T>
+ void OnUpdate(const T&) {
+ }
+
+ void Reset() {
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TSizeCounter {
+ private:
+ size_t Size;
+
+ public:
+ TSizeCounter()
+ : Size(0)
+ {
+ }
+
+ size_t GetSize() const {
+ return Size;
+ }
+
+ protected:
+ template <typename T>
+ void OnInsert(const T&) {
+ ++Size;
+ }
+
+ template <typename T>
+ void OnUpdate(const T&) {
+ }
+
+ void Reset() {
+ Size = 0;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Append-only concurrent skip-list
+ //
+ // Readers do not require any synchronization.
+ // Writers should be externally synchronized.
+ // Nodes will be allocated using TMemoryPool instance.
+
+ template <
+ typename T,
+ typename TComparer = TCompare<T>,
+ typename TAllocator = TMemoryPool,
+ typename TCounter = TSizeCounter,
+ int MaxHeight = 12,
+ int Branching = 4>
+ class TSkipList: public TCounter, private TNonCopyable {
+ class TNode {
+ private:
+ T Value; // should be immutable after insert
+ TNode* Next[]; // variable-size array maximum of MaxHeight values
+
+ public:
+ TNode(T&& value)
+ : Value(std::move(value))
+ {
+ Y_UNUSED(Next);
+ }
+
+ const T& GetValue() const {
+ return Value;
+ }
+
+ T& GetValue() {
+ return Value;
+ }
+
+ TNode* GetNext(int height) const {
+ return AtomicGet(Next[height]);
+ }
+
+ void Link(int height, TNode** prev) {
+ for (int i = 0; i < height; ++i) {
+ Next[i] = prev[i]->Next[i];
+ AtomicSet(prev[i]->Next[i], this);
+ }
+ }
+ };
+
+ public:
+ class TIterator {
+ private:
+ const TSkipList* List;
+ const TNode* Node;
+
+ public:
+ TIterator()
+ : List(nullptr)
+ , Node(nullptr)
+ {
+ }
+
+ TIterator(const TSkipList* list, const TNode* node)
+ : List(list)
+ , Node(node)
+ {
+ }
+
+ TIterator(const TIterator& other)
+ : List(other.List)
+ , Node(other.Node)
+ {
+ }
+
+ TIterator& operator=(const TIterator& other) {
+ List = other.List;
+ Node = other.Node;
+ return *this;
+ }
+
+ void Next() {
+ Node = Node ? Node->GetNext(0) : nullptr;
+ }
+
+ // much less efficient than Next as our list is single-linked
+ void Prev() {
+ if (Node) {
+ TNode* node = List->FindLessThan(Node->GetValue(), nullptr);
+ Node = (node != List->Head ? node : nullptr);
+ }
+ }
+
+ void Reset() {
+ Node = nullptr;
+ }
+
+ bool IsValid() const {
+ return Node != nullptr;
+ }
+
+ const T& GetValue() const {
+ Y_ASSERT(IsValid());
+ return Node->GetValue();
+ }
+ };
+
+ private:
+ TAllocator& Allocator;
+ TComparer Comparer;
+
+ TNode* Head;
+ TAtomic Height;
+ TCounter Counter;
+
+ TNode* Prev[MaxHeight];
+
+ template <typename TValue>
+ using TComparerReturnType = std::invoke_result_t<TComparer, const T&, const TValue&>;
+
+ public:
+ TSkipList(TAllocator& allocator, const TComparer& comparer = TComparer())
+ : Allocator(allocator)
+ , Comparer(comparer)
+ {
+ Init();
+ }
+
+ ~TSkipList() {
+ CallDtors();
+ }
+
+ void Clear() {
+ CallDtors();
+ Allocator.ClearKeepFirstChunk();
+ Init();
+ }
+
+ bool Insert(T value) {
+ TNode* node = PrepareInsert(value);
+ if (Y_UNLIKELY(node && Compare(node, value) == 0)) {
+ // we do not allow duplicates
+ return false;
+ }
+ node = DoInsert(std::move(value));
+ TCounter::OnInsert(node->GetValue());
+ return true;
+ }
+
+ template <typename TInsertAction, typename TUpdateAction>
+ bool Insert(const T& value, TInsertAction insert, TUpdateAction update) {
+ TNode* node = PrepareInsert(value);
+ if (Y_UNLIKELY(node && Compare(node, value) == 0)) {
+ if (update(node->GetValue())) {
+ TCounter::OnUpdate(node->GetValue());
+ return true;
+ }
+ // we do not allow duplicates
+ return false;
+ }
+ node = DoInsert(insert(value));
+ TCounter::OnInsert(node->GetValue());
+ return true;
+ }
+
+ template <typename TValue>
+ bool Contains(const TValue& value) const {
+ TNode* node = FindGreaterThanOrEqual(value);
+ return node && Compare(node, value) == 0;
+ }
+
+ TIterator SeekToFirst() const {
+ return TIterator(this, FindFirst());
+ }
+
+ TIterator SeekToLast() const {
+ TNode* last = FindLast();
+ return TIterator(this, last != Head ? last : nullptr);
+ }
+
+ template <typename TValue>
+ TIterator SeekTo(const TValue& value) const {
+ return TIterator(this, FindGreaterThanOrEqual(value));
+ }
+
+ private:
+ static int RandomHeight() {
+ int height = 1;
+ while (height < MaxHeight && (RandomNumber<unsigned int>() % Branching) == 0) {
+ ++height;
+ }
+ return height;
+ }
+
+ void Init() {
+ Head = AllocateRootNode();
+ Height = 1;
+ TCounter::Reset();
+
+ for (int i = 0; i < MaxHeight; ++i) {
+ Prev[i] = Head;
+ }
+ }
+
+ void CallDtors() {
+ if (!TTypeTraits<T>::IsPod) {
+ // we should explicitly call destructors for our nodes
+ TNode* node = Head->GetNext(0);
+ while (node) {
+ TNode* next = node->GetNext(0);
+ node->~TNode();
+ node = next;
+ }
+ }
+ }
+
+ TNode* AllocateRootNode() {
+ size_t size = sizeof(TNode) + sizeof(TNode*) * MaxHeight;
+ void* buffer = Allocator.Allocate(size);
+ memset(buffer, 0, size);
+ return static_cast<TNode*>(buffer);
+ }
+
+ TNode* AllocateNode(T&& value, int height) {
+ size_t size = sizeof(TNode) + sizeof(TNode*) * height;
+ void* buffer = Allocator.Allocate(size);
+ memset(buffer, 0, size);
+ return new (buffer) TNode(std::move(value));
+ }
+
+ TNode* FindFirst() const {
+ return Head->GetNext(0);
+ }
+
+ TNode* FindLast() const {
+ TNode* node = Head;
+ int height = AtomicGet(Height) - 1;
+
+ while (true) {
+ TNode* next = node->GetNext(height);
+ if (next) {
+ node = next;
+ continue;
+ }
+
+ if (height) {
+ --height;
+ } else {
+ return node;
+ }
+ }
+ }
+
+ template <typename TValue>
+ TComparerReturnType<TValue> Compare(const TNode* node, const TValue& value) const {
+ return Comparer(node->GetValue(), value);
+ }
+
+ template <typename TValue>
+ TNode* FindLessThan(const TValue& value, TNode** links) const {
+ TNode* node = Head;
+ int height = AtomicGet(Height) - 1;
+
+ TNode* prev = nullptr;
+ while (true) {
+ TNode* next = node->GetNext(height);
+ if (next && next != prev) {
+ TComparerReturnType<TValue> cmp = Compare(next, value);
+ if (cmp < 0) {
+ node = next;
+ continue;
+ }
+ }
+
+ if (links) {
+ // collect links from upper levels
+ links[height] = node;
+ }
+
+ if (height) {
+ prev = next;
+ --height;
+ } else {
+ return node;
+ }
+ }
+ }
+
+ template <typename TValue>
+ TNode* FindGreaterThanOrEqual(const TValue& value) const {
+ TNode* node = Head;
+ int height = AtomicGet(Height) - 1;
+
+ TNode* prev = nullptr;
+ while (true) {
+ TNode* next = node->GetNext(height);
+ if (next && next != prev) {
+ TComparerReturnType<TValue> cmp = Compare(next, value);
+ if (cmp < 0) {
+ node = next;
+ continue;
+ }
+ if (cmp == 0) {
+ return next;
+ }
+ }
+
+ if (height) {
+ prev = next;
+ --height;
+ } else {
+ return next;
+ }
+ }
+ }
+
+ TNode* PrepareInsert(const T& value) {
+ TNode* prev = Prev[0];
+ TNode* next = prev->GetNext(0);
+ if ((prev == Head || Compare(prev, value) < 0) && (next == nullptr || Compare(next, value) >= 0)) {
+ // avoid seek in case of sequential insert
+ } else {
+ prev = FindLessThan(value, Prev);
+ next = prev->GetNext(0);
+ }
+ return next;
+ }
+
+ TNode* DoInsert(T&& value) {
+ // choose level to place new node
+ int currentHeight = AtomicGet(Height);
+ int height = RandomHeight();
+ if (height > currentHeight) {
+ for (int i = currentHeight; i < height; ++i) {
+ // head should link to all levels
+ Prev[i] = Head;
+ }
+ AtomicSet(Height, height);
+ }
+
+ TNode* node = AllocateNode(std::move(value), height);
+ node->Link(height, Prev);
+
+ // keep last inserted node to optimize sequential inserts
+ for (int i = 0; i < height; i++) {
+ Prev[i] = node;
+ }
+ return node;
+ }
+ };
+
+}
diff --git a/library/cpp/threading/skip_list/skiplist_ut.cpp b/library/cpp/threading/skip_list/skiplist_ut.cpp
new file mode 100644
index 0000000000..52fcffda66
--- /dev/null
+++ b/library/cpp/threading/skip_list/skiplist_ut.cpp
@@ -0,0 +1,185 @@
+#include "skiplist.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+namespace NThreading {
+ namespace {
+ struct TTestObject {
+ static size_t Count;
+ int Tag;
+
+ TTestObject(int tag)
+ : Tag(tag)
+ {
+ ++Count;
+ }
+
+ TTestObject(const TTestObject& other)
+ : Tag(other.Tag)
+ {
+ ++Count;
+ }
+
+ ~TTestObject() {
+ --Count;
+ }
+
+ bool operator<(const TTestObject& other) const {
+ return Tag < other.Tag;
+ }
+ };
+
+ size_t TTestObject::Count = 0;
+
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ Y_UNIT_TEST_SUITE(TSkipListTest) {
+ Y_UNIT_TEST(ShouldBeEmptyAfterCreation) {
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
+
+ UNIT_ASSERT_EQUAL(list.GetSize(), 0);
+ }
+
+ Y_UNIT_TEST(ShouldAllowInsertion) {
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
+
+ UNIT_ASSERT(list.Insert(12345678));
+ UNIT_ASSERT_EQUAL(list.GetSize(), 1);
+ }
+
+ Y_UNIT_TEST(ShouldNotAllowDuplicates) {
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
+
+ UNIT_ASSERT(list.Insert(12345678));
+ UNIT_ASSERT_EQUAL(list.GetSize(), 1);
+
+ UNIT_ASSERT(!list.Insert(12345678));
+ UNIT_ASSERT_EQUAL(list.GetSize(), 1);
+ }
+
+ Y_UNIT_TEST(ShouldContainInsertedItem) {
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
+
+ UNIT_ASSERT(list.Insert(12345678));
+ UNIT_ASSERT(list.Contains(12345678));
+ }
+
+ Y_UNIT_TEST(ShouldNotContainNotInsertedItem) {
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
+
+ UNIT_ASSERT(list.Insert(12345678));
+ UNIT_ASSERT(!list.Contains(87654321));
+ }
+
+ Y_UNIT_TEST(ShouldIterateAllItems) {
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
+
+ for (int i = 8; i > 0; --i) {
+ UNIT_ASSERT(list.Insert(i));
+ }
+
+ TSkipList<int>::TIterator it = list.SeekToFirst();
+ for (int i = 1; i <= 8; ++i) {
+ UNIT_ASSERT(it.IsValid());
+ UNIT_ASSERT_EQUAL(it.GetValue(), i);
+ it.Next();
+ }
+ UNIT_ASSERT(!it.IsValid());
+ }
+
+ Y_UNIT_TEST(ShouldIterateAllItemsInReverseDirection) {
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
+
+ for (int i = 8; i > 0; --i) {
+ UNIT_ASSERT(list.Insert(i));
+ }
+
+ TSkipList<int>::TIterator it = list.SeekToLast();
+ for (int i = 8; i > 0; --i) {
+ UNIT_ASSERT(it.IsValid());
+ UNIT_ASSERT_EQUAL(it.GetValue(), i);
+ it.Prev();
+ }
+ UNIT_ASSERT(!it.IsValid());
+ }
+
+ Y_UNIT_TEST(ShouldSeekToFirstItem) {
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
+
+ for (int i = 1; i < 10; ++i) {
+ UNIT_ASSERT(list.Insert(i));
+ }
+
+ TSkipList<int>::TIterator it = list.SeekToFirst();
+ UNIT_ASSERT(it.IsValid());
+ UNIT_ASSERT_EQUAL(it.GetValue(), 1);
+ }
+
+ Y_UNIT_TEST(ShouldSeekToLastItem) {
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
+
+ for (int i = 1; i < 10; ++i) {
+ UNIT_ASSERT(list.Insert(i));
+ }
+
+ TSkipList<int>::TIterator it = list.SeekToLast();
+ UNIT_ASSERT(it.IsValid());
+ UNIT_ASSERT_EQUAL(it.GetValue(), 9);
+ }
+
+ Y_UNIT_TEST(ShouldSeekToExistingItem) {
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
+
+ UNIT_ASSERT(list.Insert(12345678));
+
+ TSkipList<int>::TIterator it = list.SeekTo(12345678);
+ UNIT_ASSERT(it.IsValid());
+ }
+
+ Y_UNIT_TEST(ShouldSeekAfterMissedItem) {
+ TMemoryPool pool(1024);
+ TSkipList<int> list(pool);
+
+ UNIT_ASSERT(list.Insert(100));
+ UNIT_ASSERT(list.Insert(300));
+
+ TSkipList<int>::TIterator it = list.SeekTo(200);
+ UNIT_ASSERT(it.IsValid());
+ UNIT_ASSERT_EQUAL(it.GetValue(), 300);
+
+ it.Prev();
+ UNIT_ASSERT(it.IsValid());
+ UNIT_ASSERT_EQUAL(it.GetValue(), 100);
+ }
+
+ Y_UNIT_TEST(ShouldCallDtorsOfNonPodTypes) {
+ UNIT_ASSERT(!TTypeTraits<TTestObject>::IsPod);
+ UNIT_ASSERT_EQUAL(TTestObject::Count, 0);
+
+ {
+ TMemoryPool pool(1024);
+ TSkipList<TTestObject> list(pool);
+
+ UNIT_ASSERT(list.Insert(TTestObject(1)));
+ UNIT_ASSERT(list.Insert(TTestObject(2)));
+
+ UNIT_ASSERT_EQUAL(TTestObject::Count, 2);
+ }
+
+ UNIT_ASSERT_EQUAL(TTestObject::Count, 0);
+ }
+ }
+
+}
diff --git a/library/cpp/threading/skip_list/ut/ya.make b/library/cpp/threading/skip_list/ut/ya.make
new file mode 100644
index 0000000000..704a31e9a2
--- /dev/null
+++ b/library/cpp/threading/skip_list/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/threading/skip_list)
+
+OWNER(g:rtmr)
+
+SRCS(
+ skiplist_ut.cpp
+)
+
+END()
diff --git a/library/cpp/threading/skip_list/ya.make b/library/cpp/threading/skip_list/ya.make
new file mode 100644
index 0000000000..d338aeae2b
--- /dev/null
+++ b/library/cpp/threading/skip_list/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(g:rtmr)
+
+SRCS(
+ skiplist.cpp
+)
+
+END()
diff --git a/library/cpp/threading/task_scheduler/task_scheduler.cpp b/library/cpp/threading/task_scheduler/task_scheduler.cpp
new file mode 100644
index 0000000000..174dde4bf7
--- /dev/null
+++ b/library/cpp/threading/task_scheduler/task_scheduler.cpp
@@ -0,0 +1,246 @@
+#include "task_scheduler.h"
+
+#include <util/system/thread.h>
+#include <util/string/cast.h>
+#include <util/stream/output.h>
+
+TTaskScheduler::ITask::~ITask() {}
+TTaskScheduler::IRepeatedTask::~IRepeatedTask() {}
+
+
+
+class TTaskScheduler::TWorkerThread
+ : public ISimpleThread
+{
+public:
+ TWorkerThread(TTaskScheduler& state)
+ : Scheduler_(state)
+ {
+ }
+
+ TString DebugState = "?";
+ TString DebugId = "";
+private:
+ void* ThreadProc() noexcept override {
+ Scheduler_.WorkerFunc(this);
+ return nullptr;
+ }
+private:
+ TTaskScheduler& Scheduler_;
+};
+
+
+
+TTaskScheduler::TTaskScheduler(size_t threadCount, size_t maxTaskCount)
+ : MaxTaskCount_(maxTaskCount)
+{
+ for (size_t i = 0; i < threadCount; ++i) {
+ Workers_.push_back(new TWorkerThread(*this));
+ Workers_.back()->DebugId = ToString(i);
+ }
+}
+
+TTaskScheduler::~TTaskScheduler() {
+ try {
+ Stop();
+ } catch (...) {
+ Cdbg << "task scheduled destruction error: " << CurrentExceptionMessage();
+ }
+}
+
+void TTaskScheduler::Start() {
+ for (auto& w : Workers_) {
+ w->Start();
+ }
+}
+
+void TTaskScheduler::Stop() {
+ with_lock (Lock_) {
+ IsStopped_ = true;
+ CondVar_.BroadCast();
+ }
+
+ for (auto& w: Workers_) {
+ w->Join();
+ }
+
+ Workers_.clear();
+ Queue_.clear();
+}
+
+size_t TTaskScheduler::GetTaskCount() const {
+ return static_cast<size_t>(AtomicGet(TaskCounter_));
+}
+
+namespace {
+ class TTaskWrapper
+ : public TTaskScheduler::ITask
+ , TNonCopyable
+ {
+ public:
+ TTaskWrapper(TTaskScheduler::ITaskRef task, TAtomic& counter)
+ : Task_(task)
+ , Counter_(counter)
+ {
+ AtomicIncrement(Counter_);
+ }
+
+ ~TTaskWrapper() override {
+ AtomicDecrement(Counter_);
+ }
+ private:
+ TInstant Process() override {
+ return Task_->Process();
+ }
+ private:
+ TTaskScheduler::ITaskRef Task_;
+ TAtomic& Counter_;
+ };
+}
+
+bool TTaskScheduler::Add(ITaskRef task, TInstant expire) {
+ with_lock (Lock_) {
+ if (!IsStopped_ && Workers_.size() > 0 && GetTaskCount() + 1 <= MaxTaskCount_) {
+ ITaskRef newTask = new TTaskWrapper(task, TaskCounter_);
+ Queue_.insert(std::make_pair(expire, TTaskHolder(newTask)));
+
+ if (!Queue_.begin()->second.WaitingWorker) {
+ CondVar_.Signal();
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+namespace {
+ class TRepeatedTask
+ : public TTaskScheduler::ITask
+ {
+ public:
+ TRepeatedTask(TTaskScheduler::IRepeatedTaskRef task, TDuration period, TInstant deadline)
+ : Task_(task)
+ , Period_(period)
+ , Deadline_(deadline)
+ {
+ }
+ private:
+ TInstant Process() final {
+ Deadline_ += Period_;
+ if (Task_->Process()) {
+ return Deadline_;
+ } else {
+ return TInstant::Max();
+ }
+ }
+ private:
+ TTaskScheduler::IRepeatedTaskRef Task_;
+ TDuration Period_;
+ TInstant Deadline_;
+ };
+}
+
+bool TTaskScheduler::Add(IRepeatedTaskRef task, TDuration period) {
+ const TInstant deadline = Now() + period;
+ ITaskRef t = new TRepeatedTask(task, period, deadline);
+ return Add(t, deadline);
+}
+
+
+const bool debugOutput = false;
+
+void TTaskScheduler::ChangeDebugState(TWorkerThread* thread, const TString& state) {
+ if (!debugOutput) {
+ Y_UNUSED(thread);
+ Y_UNUSED(state);
+ return;
+ }
+
+ thread->DebugState = state;
+
+ TStringStream ss;
+ ss << Now() << " " << thread->DebugId << ":\t";
+ for (auto& w : Workers_) {
+ ss << w->DebugState << " ";
+ }
+ ss << " [" << Queue_.size() << "] [" << TaskCounter_ << "]" << Endl;
+ Cerr << ss.Str();
+}
+
+bool TTaskScheduler::Wait(TWorkerThread* thread, TQueueIterator& toWait) {
+ ChangeDebugState(thread, "w");
+ toWait->second.WaitingWorker = thread;
+ return !CondVar_.WaitD(Lock_, toWait->first);
+}
+
+void TTaskScheduler::ChooseFromQueue(TQueueIterator& toWait) {
+ for (TQueueIterator it = Queue_.begin(); it != Queue_.end(); ++it) {
+ if (!it->second.WaitingWorker) {
+ if (toWait == Queue_.end()) {
+ toWait = it;
+ } else if (it->first < toWait->first) {
+ toWait->second.WaitingWorker = nullptr;
+ toWait = it;
+ }
+ break;
+ }
+ }
+}
+
+void TTaskScheduler::WorkerFunc(TWorkerThread* thread) {
+ TThread::SetCurrentThreadName("TaskSchedWorker");
+
+ TQueueIterator toWait = Queue_.end();
+ ITaskRef toDo;
+
+ for (;;) {
+ TInstant repeat = TInstant::Max();
+
+ if (!!toDo) {
+ try {
+ repeat = toDo->Process();
+ } catch (...) {
+ Cdbg << "task scheduler error: " << CurrentExceptionMessage();
+ }
+ }
+
+
+ with_lock (Lock_) {
+ ChangeDebugState(thread, "f");
+
+ if (IsStopped_) {
+ ChangeDebugState(thread, "s");
+ return ;
+ }
+
+ if (!!toDo) {
+ if (repeat < TInstant::Max()) {
+ Queue_.insert(std::make_pair(repeat, TTaskHolder(toDo)));
+ }
+ }
+
+ toDo = nullptr;
+
+ ChooseFromQueue(toWait);
+
+ if (toWait != Queue_.end()) {
+ if (toWait->first <= Now() || Wait(thread, toWait)) {
+
+ toDo = toWait->second.Task;
+ Queue_.erase(toWait);
+ toWait = Queue_.end();
+
+ if (!Queue_.empty() && !Queue_.begin()->second.WaitingWorker && Workers_.size() > 1) {
+ CondVar_.Signal();
+ }
+
+ ChangeDebugState(thread, "p");
+ }
+ } else {
+ ChangeDebugState(thread, "e");
+ CondVar_.WaitI(Lock_);
+ }
+ }
+ }
+}
diff --git a/library/cpp/threading/task_scheduler/task_scheduler.h b/library/cpp/threading/task_scheduler/task_scheduler.h
new file mode 100644
index 0000000000..df4da941a8
--- /dev/null
+++ b/library/cpp/threading/task_scheduler/task_scheduler.h
@@ -0,0 +1,86 @@
+#pragma once
+
+#include <util/generic/vector.h>
+#include <util/generic/ptr.h>
+#include <util/generic/map.h>
+
+#include <util/datetime/base.h>
+
+#include <util/system/condvar.h>
+#include <util/system/mutex.h>
+
+class TTaskScheduler {
+public:
+ class ITask;
+ using ITaskRef = TIntrusivePtr<ITask>;
+
+ class IRepeatedTask;
+ using IRepeatedTaskRef = TIntrusivePtr<IRepeatedTask>;
+public:
+ explicit TTaskScheduler(size_t threadCount = 1, size_t maxTaskCount = Max<size_t>());
+ ~TTaskScheduler();
+
+ void Start();
+ void Stop();
+
+ bool Add(ITaskRef task, TInstant expire);
+ bool Add(IRepeatedTaskRef task, TDuration period);
+
+ size_t GetTaskCount() const;
+private:
+ class TWorkerThread;
+
+ struct TTaskHolder {
+ explicit TTaskHolder(ITaskRef& task)
+ : Task(task)
+ {
+ }
+ public:
+ ITaskRef Task;
+ TWorkerThread* WaitingWorker = nullptr;
+ };
+
+ using TQueueType = TMultiMap<TInstant, TTaskHolder>;
+ using TQueueIterator = TQueueType::iterator;
+private:
+ void ChangeDebugState(TWorkerThread* thread, const TString& state);
+ void ChooseFromQueue(TQueueIterator& toWait);
+ bool Wait(TWorkerThread* thread, TQueueIterator& toWait);
+
+ void WorkerFunc(TWorkerThread* thread);
+private:
+ bool IsStopped_ = false;
+
+ TAtomic TaskCounter_ = 0;
+ TQueueType Queue_;
+
+ TCondVar CondVar_;
+ TMutex Lock_;
+
+ TVector<TAutoPtr<TWorkerThread>> Workers_;
+
+ const size_t MaxTaskCount_;
+};
+
+class TTaskScheduler::ITask
+ : public TAtomicRefCount<ITask>
+{
+public:
+ virtual ~ITask();
+
+ virtual TInstant Process() {//returns time to repeat this task
+ return TInstant::Max();
+ }
+};
+
+class TTaskScheduler::IRepeatedTask
+ : public TAtomicRefCount<IRepeatedTask>
+{
+public:
+ virtual ~IRepeatedTask();
+
+ virtual bool Process() {//returns if to repeat task again
+ return false;
+ }
+};
+
diff --git a/library/cpp/threading/task_scheduler/task_scheduler_ut.cpp b/library/cpp/threading/task_scheduler/task_scheduler_ut.cpp
new file mode 100644
index 0000000000..3b5203194a
--- /dev/null
+++ b/library/cpp/threading/task_scheduler/task_scheduler_ut.cpp
@@ -0,0 +1,86 @@
+#include <algorithm>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/output.h>
+#include <util/system/atomic.h>
+#include <util/generic/vector.h>
+
+#include "task_scheduler.h"
+
+class TTaskSchedulerTest: public TTestBase {
+ UNIT_TEST_SUITE(TTaskSchedulerTest);
+ UNIT_TEST(Test);
+ UNIT_TEST_SUITE_END();
+
+ class TCheckTask: public TTaskScheduler::IRepeatedTask {
+ public:
+ TCheckTask(const TDuration& delay)
+ : Start_(Now())
+ , Delay_(delay)
+ {
+ AtomicIncrement(ScheduledTaskCounter_);
+ }
+
+ ~TCheckTask() override {
+ }
+
+ bool Process() override {
+ const TDuration delay = Now() - Start_;
+
+ if (delay < Delay_) {
+ AtomicIncrement(BadTimeoutCounter_);
+ }
+
+ AtomicIncrement(ExecutedTaskCounter_);
+
+ return false;
+ }
+
+ static bool AllTaskExecuted() {
+ return AtomicGet(ScheduledTaskCounter_) == AtomicGet(ExecutedTaskCounter_);
+ }
+
+ static size_t BadTimeoutCount() {
+ return AtomicGet(BadTimeoutCounter_);
+ }
+
+ private:
+ TInstant Start_;
+ TDuration Delay_;
+ static TAtomic BadTimeoutCounter_;
+ static TAtomic ScheduledTaskCounter_;
+ static TAtomic ExecutedTaskCounter_;
+ };
+
+ public:
+ inline void Test() {
+ ScheduleCheckTask(200);
+ ScheduleCheckTask(100);
+ ScheduleCheckTask(1000);
+ ScheduleCheckTask(10000);
+ ScheduleCheckTask(5000);
+
+ Scheduler_.Start();
+
+ usleep(1000000);
+
+ UNIT_ASSERT_EQUAL(TCheckTask::BadTimeoutCount(), 0);
+ UNIT_ASSERT(TCheckTask::AllTaskExecuted());
+ }
+
+ private:
+ void ScheduleCheckTask(size_t delay) {
+ TDuration d = TDuration::MicroSeconds(delay);
+
+ Scheduler_.Add(new TCheckTask(d), d);
+ }
+
+ private:
+ TTaskScheduler Scheduler_;
+};
+
+TAtomic TTaskSchedulerTest::TCheckTask::BadTimeoutCounter_ = 0;
+TAtomic TTaskSchedulerTest::TCheckTask::ScheduledTaskCounter_ = 0;
+TAtomic TTaskSchedulerTest::TCheckTask::ExecutedTaskCounter_ = 0;
+
+UNIT_TEST_SUITE_REGISTRATION(TTaskSchedulerTest);
diff --git a/library/cpp/threading/task_scheduler/ut/ya.make b/library/cpp/threading/task_scheduler/ut/ya.make
new file mode 100644
index 0000000000..07ee8b0877
--- /dev/null
+++ b/library/cpp/threading/task_scheduler/ut/ya.make
@@ -0,0 +1,9 @@
+UNITTEST_FOR(library/cpp/threading/task_scheduler)
+
+OWNER(g:middle)
+
+SRCS(
+ task_scheduler_ut.cpp
+)
+
+END()
diff --git a/library/cpp/threading/task_scheduler/ya.make b/library/cpp/threading/task_scheduler/ya.make
new file mode 100644
index 0000000000..5b14c0aa63
--- /dev/null
+++ b/library/cpp/threading/task_scheduler/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(g:middle)
+
+SRCS(
+ task_scheduler.cpp
+)
+
+END()
diff --git a/library/cpp/threading/ya.make b/library/cpp/threading/ya.make
new file mode 100644
index 0000000000..f4d850ee17
--- /dev/null
+++ b/library/cpp/threading/ya.make
@@ -0,0 +1,64 @@
+RECURSE(
+ algorithm
+ async_task_batch
+ async_task_batch/ut
+ atomic
+ atomic/ut
+ atomic_shared_ptr
+ atomic_shared_ptr/ut
+ blocking_counter
+ blocking_counter/ut
+ blocking_queue
+ cancellation
+ chunk_queue
+ chunk_queue/ut
+ cron
+ cron/example
+ equeue
+ equeue/ut
+ fair_lock
+ fair_lock/ut
+ future
+ future/perf
+ future/subscription
+ future/ut
+ hot_swap
+ hot_swap/ut
+ light_rw_lock
+ light_rw_lock/bench
+ light_rw_lock/ut
+ local_executor
+ local_executor/ut
+ mtp_tasks
+ mtp_tasks/ut
+ mux_event
+ mux_event/ut
+ named_lock
+ named_lock/ut
+ name_guard
+ name_guard/ut
+ periodically_updated
+ poor_man_openmp
+ poor_man_openmp/ut
+ queue
+ queue/ut
+ rcu
+ rcu/ut
+ serial_postprocess_queue
+ skip_list
+ skip_list/perf
+ skip_list/ut
+ synchronized
+ synchronized/ut
+ task_scheduler
+ task_scheduler/ut
+ thread_local
+ thread_local/benchmark
+ thread_local/ut
+ thread_namer
+ thread_namer/ut
+ ticket_lock
+ ticket_lock/ut
+ work_stealing
+ work_stealing/ut
+)
diff --git a/library/cpp/time_provider/time_provider.cpp b/library/cpp/time_provider/time_provider.cpp
new file mode 100644
index 0000000000..6c1ba8e07c
--- /dev/null
+++ b/library/cpp/time_provider/time_provider.cpp
@@ -0,0 +1,30 @@
+#include "time_provider.h"
+
+class TDefaultTimeProvider: public ITimeProvider {
+public:
+ TInstant Now() override {
+ return TInstant::Now();
+ }
+};
+
+class TDeterministicTimeProvider: public ITimeProvider {
+public:
+ TDeterministicTimeProvider(ui64 seed) {
+ Value = TInstant::Seconds(seed);
+ }
+
+ TInstant Now() override {
+ return Value;
+ }
+
+private:
+ TInstant Value;
+};
+
+TIntrusivePtr<ITimeProvider> CreateDefaultTimeProvider() {
+ return TIntrusivePtr<ITimeProvider>(new TDefaultTimeProvider());
+}
+
+TIntrusivePtr<ITimeProvider> CreateDeterministicTimeProvider(ui64 seed) {
+ return TIntrusivePtr<ITimeProvider>(new TDeterministicTimeProvider(seed));
+}
diff --git a/library/cpp/time_provider/time_provider.h b/library/cpp/time_provider/time_provider.h
new file mode 100644
index 0000000000..46e0a885da
--- /dev/null
+++ b/library/cpp/time_provider/time_provider.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <util/datetime/base.h>
+
+class ITimeProvider: public TThrRefBase {
+public:
+ virtual TInstant Now() = 0;
+};
+
+TIntrusivePtr<ITimeProvider> CreateDefaultTimeProvider();
+TIntrusivePtr<ITimeProvider> CreateDeterministicTimeProvider(ui64 seed);
diff --git a/library/cpp/time_provider/ya.make b/library/cpp/time_provider/ya.make
new file mode 100644
index 0000000000..cf3995b2a4
--- /dev/null
+++ b/library/cpp/time_provider/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(
+ g:kikimr
+ g:yql
+)
+
+SRCS(
+ time_provider.cpp
+ time_provider.h
+)
+
+END()
diff --git a/library/cpp/timezone_conversion/README.md b/library/cpp/timezone_conversion/README.md
new file mode 100644
index 0000000000..828f1880bc
--- /dev/null
+++ b/library/cpp/timezone_conversion/README.md
@@ -0,0 +1,27 @@
+A library for translating between absolute times (i.e., `TInstant`) and civil times (i.e.,
+`NDatetime::TSimpleTM`) using the rules defined by a time zone (i.e., `NDatetime::TTimeZone`).
+
+(the terms `absolute` and `civil` come from [cctz#fundamental-concepts][cctz-fundamental-concepts])
+
+This is basically a wrapper around [CCTZ][cctz] with one important change: the time zone database is
+in Arcadia and is compiled with the library (which means your executable will end up ~2MB larger).
+
+See [contrib/libs/cctz/README][update] if you think zone database is outdated.
+
+Quick start:
+============
+```
+#include <library/cpp/timezone_conversion/convert.h>
+
+// NDatetime::{GetLocalTimeZone(),GetUtcTimeZone()} are also available.
+NDatetime::TTimeZone msk = NDatetime::GetTimeZone("Europe/Moscow");
+TInstant now = TInstant::Now();
+NDatetime::TSimpleTM civil = NDatetime::ToCivilTime(now, msk);
+Cout << "Local time in Moscow is " << civil.ToString() << Endl;
+TInstant absolute = NDatetime::ToAbsoluteTime(civil, msk);
+Cout << "The current UNIX time is " << absolute.Seconds() << Endl;
+```
+
+[cctz-fundamental-concepts]: https://github.com/google/cctz#fundamental-concepts
+[cctz]: https://github.com/google/cctz
+[update]: https://a.yandex-team.ru/arc/trunk/arcadia/contrib/libs/cctz/tzdata/README?rev=2286180
diff --git a/library/cpp/timezone_conversion/civil-inl.h b/library/cpp/timezone_conversion/civil-inl.h
new file mode 100644
index 0000000000..32afbccb64
--- /dev/null
+++ b/library/cpp/timezone_conversion/civil-inl.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include "civil.h"
+
+namespace NDatetime {
+ namespace NDetail {
+ template <typename T>
+ struct TGetCivilUnit;
+
+ template <>
+ struct TGetCivilUnit<TCivilSecond> {
+ static constexpr ECivilUnit Value = ECivilUnit::Second;
+ };
+ template <>
+ struct TGetCivilUnit<TCivilMinute> {
+ static constexpr ECivilUnit Value = ECivilUnit::Minute;
+ };
+ template <>
+ struct TGetCivilUnit<TCivilHour> {
+ static constexpr ECivilUnit Value = ECivilUnit::Hour;
+ };
+ template <>
+ struct TGetCivilUnit<TCivilDay> {
+ static constexpr ECivilUnit Value = ECivilUnit::Day;
+ };
+ template <>
+ struct TGetCivilUnit<TCivilMonth> {
+ static constexpr ECivilUnit Value = ECivilUnit::Month;
+ };
+ template <>
+ struct TGetCivilUnit<TCivilYear> {
+ static constexpr ECivilUnit Value = ECivilUnit::Year;
+ };
+
+ template <ECivilUnit Unit>
+ struct TGetCivilTime;
+
+ template <>
+ struct TGetCivilTime<ECivilUnit::Second> {
+ using TResult = TCivilSecond;
+ };
+ template <>
+ struct TGetCivilTime<ECivilUnit::Minute> {
+ using TResult = TCivilMinute;
+ };
+ template <>
+ struct TGetCivilTime<ECivilUnit::Hour> {
+ using TResult = TCivilHour;
+ };
+ template <>
+ struct TGetCivilTime<ECivilUnit::Day> {
+ using TResult = TCivilDay;
+ };
+ template <>
+ struct TGetCivilTime<ECivilUnit::Month> {
+ using TResult = TCivilMonth;
+ };
+ template <>
+ struct TGetCivilTime<ECivilUnit::Year> {
+ using TResult = TCivilYear;
+ };
+ }
+}
diff --git a/library/cpp/timezone_conversion/civil.cpp b/library/cpp/timezone_conversion/civil.cpp
new file mode 100644
index 0000000000..5986318b9a
--- /dev/null
+++ b/library/cpp/timezone_conversion/civil.cpp
@@ -0,0 +1,234 @@
+#include "civil.h"
+
+#include <util/stream/output.h>
+#include <util/stream/format.h>
+#include <util/string/ascii.h>
+
+namespace {
+ bool TryParseInt(TStringBuf& s, int& dst, size_t maxDigits) {
+ int res = 0;
+ size_t i = 0;
+ while (i < maxDigits && !s.empty() && IsAsciiDigit(s[0])) {
+ res = res * 10 + (s[0] - '0');
+ ++i;
+ s.Skip(1);
+ }
+ if (i == 0) {
+ return false;
+ }
+ dst = res;
+ return true;
+ }
+
+ bool TryParseUTCOffsetTimezone(TStringBuf name, int& offset) {
+ static constexpr TStringBuf OFFSET_PREFIX = "UTC";
+ if (!name.SkipPrefix(OFFSET_PREFIX)) {
+ return false;
+ }
+ if (name.empty()) {
+ return false;
+ }
+ bool negative;
+ if (name[0] == '+') {
+ negative = false;
+ } else if (name[0] == '-') {
+ negative = true;
+ } else {
+ return false;
+ }
+ name.Skip(1);
+ int hour;
+ int minute = 0;
+ if (!TryParseInt(name, hour, 2) || hour > 24) {
+ return false;
+ }
+ if (!name.empty()) {
+ if (name[0] == ':') {
+ name.Skip(1);
+ }
+ if (!TryParseInt(name, minute, 2) || minute >= 60) {
+ return false;
+ }
+ if (!name.empty()) {
+ return false;
+ }
+ }
+ if (hour == 24 && minute != 0) {
+ return false;
+ }
+ offset = (hour * 60 + minute) * 60;
+ if (negative)
+ offset = -offset;
+ return true;
+ }
+} // anonymous namespace
+
+namespace NDatetime {
+ TTimeZone GetTimeZone(TStringBuf name) {
+ int offset;
+ if (TryParseUTCOffsetTimezone(name, offset)) {
+ return GetFixedTimeZone(offset);
+ }
+ TTimeZone result;
+ if (!cctz::load_time_zone(static_cast<std::string>(name), &result)) {
+ ythrow TInvalidTimezone() << "Failed to load time zone " << name << ", " << result.name();
+ }
+ return result;
+ }
+
+ TTimeZone GetFixedTimeZone(const long offset) {
+ return cctz::fixed_time_zone(std::chrono::seconds(offset));
+ }
+
+ TCivilSecond Convert(const TInstant& absTime, const TTimeZone& tz) {
+ return cctz::convert(TSystemClock::from_time_t(absTime.TimeT()), tz);
+ }
+
+ TCivilSecond Convert(const TInstant& absTime, TStringBuf tzName) {
+ TTimeZone tz = GetTimeZone(tzName);
+ return cctz::convert(TSystemClock::from_time_t(absTime.TimeT()), tz);
+ }
+
+ TInstant Convert(const TCivilSecond& tp, const TTimeZone& tz) {
+ return TInstant::Seconds(cctz::convert(tp, tz).time_since_epoch().count());
+ }
+
+ TCivilSecond AddYears(const TCivilSecond& tp, TDiff diff) {
+ TCivilYear newYear = Calc<TCivilYear>(tp, diff);
+ return NDatetime::TCivilSecond(newYear.year(), tp.month(), tp.day(), tp.hour(), tp.minute(), tp.second());
+ }
+
+ TCivilSecond AddMonths(const TCivilSecond& tp, TDiff diff) {
+ TCivilMonth newMonth = Calc<TCivilMonth>(tp, diff);
+ return NDatetime::TCivilSecond(newMonth.year(), newMonth.month(), tp.day(), tp.hour(), tp.minute(), tp.second());
+ }
+
+ TCivilSecond AddDays(const TCivilSecond& tp, TDiff diff) {
+ TCivilDay newDay = Calc<TCivilDay>(tp, diff);
+ return NDatetime::TCivilSecond(newDay.year(), newDay.month(), newDay.day(), tp.hour(), tp.minute(), tp.second());
+ }
+
+ TCivilSecond AddHours(const TCivilSecond& tp, TDiff diff) {
+ TCivilHour newHour = Calc<TCivilHour>(tp, diff);
+ return NDatetime::TCivilSecond(newHour.year(), newHour.month(), newHour.day(), newHour.hour(), tp.minute(), tp.second());
+ }
+
+ TCivilSecond AddMinutes(const TCivilSecond& tp, TDiff diff) {
+ TCivilMinute newMinute = Calc<TCivilMinute>(tp, diff);
+ return NDatetime::TCivilSecond(newMinute.year(), newMinute.month(), newMinute.day(), newMinute.hour(), newMinute.minute(), tp.second());
+ }
+
+ TCivilSecond AddSeconds(const TCivilSecond& tp, TDiff diff) {
+ return Calc<TCivilSecond>(tp, diff);
+ }
+
+ TCivilSecond AddCivil(const TCivilSecond& tp, TCivilDiff diff) {
+ switch (diff.Unit) {
+ case ECivilUnit::Second: {
+ return AddSeconds(tp, diff.Value);
+ }
+ case ECivilUnit::Minute: {
+ return AddMinutes(tp, diff.Value);
+ }
+ case ECivilUnit::Hour: {
+ return AddHours(tp, diff.Value);
+ }
+ case ECivilUnit::Day: {
+ return AddDays(tp, diff.Value);
+ }
+ case ECivilUnit::Month: {
+ return AddMonths(tp, diff.Value);
+ }
+ case ECivilUnit::Year: {
+ return AddYears(tp, diff.Value);
+ }
+ default: {
+ ythrow yexception() << "Unexpected civil unit value " << static_cast<int>(diff.Unit);
+ }
+ }
+ }
+
+ TCivilDiff GetCivilDiff(const TCivilSecond& tpX, const TCivilSecond& tpY, ECivilUnit unit) {
+ switch (unit) {
+ case ECivilUnit::Second: {
+ return {tpX - tpY, unit};
+ }
+ case ECivilUnit::Minute: {
+ return {static_cast<TCivilMinute>(tpX) - static_cast<TCivilMinute>(tpY), unit};
+ }
+ case ECivilUnit::Hour: {
+ return {static_cast<TCivilHour>(tpX) - static_cast<TCivilHour>(tpY), unit};
+ }
+ case ECivilUnit::Day: {
+ return {static_cast<TCivilDay>(tpX) - static_cast<TCivilDay>(tpY), unit};
+ }
+ case ECivilUnit::Month: {
+ return {static_cast<TCivilMonth>(tpX) - static_cast<TCivilMonth>(tpY), unit};
+ }
+ case ECivilUnit::Year: {
+ return {static_cast<TCivilYear>(tpX) - static_cast<TCivilYear>(tpY), unit};
+ }
+ default: {
+ ythrow yexception() << "Unexpected civil unit value " << static_cast<int>(unit);
+ }
+ }
+ }
+}
+
+template <>
+void Out<NDatetime::TCivilYear>(IOutputStream& out, const NDatetime::TCivilYear& y) {
+ out << y.year();
+}
+
+template <>
+void Out<NDatetime::TCivilMonth>(IOutputStream& out, const NDatetime::TCivilMonth& m) {
+ out << NDatetime::TCivilYear(m) << '-' << LeftPad(m.month(), 2, '0');
+}
+
+template <>
+void Out<NDatetime::TCivilDay>(IOutputStream& out, const NDatetime::TCivilDay& d) {
+ out << NDatetime::TCivilMonth(d) << '-' << LeftPad(d.day(), 2, '0');
+}
+
+template <>
+void Out<NDatetime::TCivilHour>(IOutputStream& out, const NDatetime::TCivilHour& h) {
+ out << NDatetime::TCivilDay(h) << 'T' << LeftPad(h.hour(), 2, '0');
+}
+
+template <>
+void Out<NDatetime::TCivilMinute>(IOutputStream& out, const NDatetime::TCivilMinute& m) {
+ out << NDatetime::TCivilHour(m) << ':' << LeftPad(m.minute(), 2, '0');
+}
+
+template <>
+void Out<NDatetime::TCivilSecond>(IOutputStream& out, const NDatetime::TCivilSecond& s) {
+ out << NDatetime::TCivilMinute(s) << ':' << LeftPad(s.second(), 2, '0');
+}
+
+template <>
+void Out<NDatetime::TWeekday>(IOutputStream& out, NDatetime::TWeekday wd) {
+ using namespace cctz;
+ switch (wd) {
+ case weekday::monday:
+ out << TStringBuf("Monday");
+ break;
+ case weekday::tuesday:
+ out << TStringBuf("Tuesday");
+ break;
+ case weekday::wednesday:
+ out << TStringBuf("Wednesday");
+ break;
+ case weekday::thursday:
+ out << TStringBuf("Thursday");
+ break;
+ case weekday::friday:
+ out << TStringBuf("Friday");
+ break;
+ case weekday::saturday:
+ out << TStringBuf("Saturday");
+ break;
+ case weekday::sunday:
+ out << TStringBuf("Sunday");
+ break;
+ }
+}
diff --git a/library/cpp/timezone_conversion/civil.h b/library/cpp/timezone_conversion/civil.h
new file mode 100644
index 0000000000..0e95b807ed
--- /dev/null
+++ b/library/cpp/timezone_conversion/civil.h
@@ -0,0 +1,338 @@
+#pragma once
+
+#include <util/datetime/base.h>
+
+#include <contrib/libs/cctz/include/cctz/civil_time.h>
+#include <contrib/libs/cctz/include/cctz/time_zone.h>
+
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+#include <util/generic/yexception.h>
+
+#if __clang__ && __cpp_constexpr >= 201304
+#define CONSTEXPR_M constexpr
+#else
+#define CONSTEXPR_M inline
+#endif
+
+namespace NDatetime {
+ /** Exception class which throws when time zone is not valid
+ */
+ class TInvalidTimezone: public yexception {
+ };
+
+ using TSystemClock = std::chrono::system_clock;
+ using TTimePoint = std::chrono::time_point<TSystemClock>;
+
+ /*
+ * An opaque class representing past, present, and future rules of
+ * mapping between absolute and civil times in a given region.
+ * It is very lightweight and may be passed by value.
+ */
+ using TTimeZone = cctz::time_zone;
+
+ using TCivilYear = cctz::civil_year;
+ using TCivilMonth = cctz::civil_month;
+ using TCivilDay = cctz::civil_day;
+ using TCivilHour = cctz::civil_hour;
+ using TCivilMinute = cctz::civil_minute;
+ using TCivilSecond = cctz::civil_second;
+ using TWeekday = cctz::weekday;
+ using TDiff = cctz::diff_t;
+
+ using TYear = cctz::year_t;
+ using TMonth = cctz::detail::month_t;
+
+ enum class ECivilUnit : int {
+ Second = 0,
+ Minute = 1,
+ Hour = 2,
+ Day = 3,
+ Month = 4,
+ Year = 5
+ };
+
+ namespace NDetail {
+ template <typename T>
+ struct TGetCivilUnit;
+
+ template <ECivilUnit Unit>
+ struct TGetCivilTime;
+ }
+
+ template <typename T>
+ CONSTEXPR_M ECivilUnit GetCivilUnit(const T& = {}) {
+ return NDetail::TGetCivilUnit<T>::Value;
+ }
+
+ template <ECivilUnit Unit>
+ using TCivilTime = typename NDetail::TGetCivilTime<Unit>::TResult;
+
+ /**
+ * Class with variable unit diff.
+ */
+ struct TCivilDiff {
+ TDiff Value = 0;
+ ECivilUnit Unit = ECivilUnit::Second;
+
+ TCivilDiff() = default;
+ TCivilDiff(TDiff value, ECivilUnit unit)
+ : Value(value)
+ , Unit(unit)
+ {
+ }
+
+ /**
+ * Straightfoward implementation of operators <, == and unit conversions
+ * can be potentially misleading (e.g. 1 month == 30 days?);
+ * we leave it to user to implement it properly for each application.
+ */
+ };
+
+ /**
+ * Gets the time zone by an IANA name.
+ * @param name A name in IANA format (e.g., "Europe/Moscow").
+ * @note After you request a time zone for the first time, it is cached
+ * in a (thread-safe) cache, so subsequent requests to the
+ * same time zone should be extremely fast.
+ * @throw TInvalidTimezone if the name is invalid.
+ * @see http://www.iana.org/time-zones
+ */
+ TTimeZone GetTimeZone(TStringBuf name);
+
+ /**
+ * Returns a time zone that is a fixed offset (seconds east) from UTC.
+ * Note: If the absolute value of the offset is greater than 24 hours
+ * you'll get UTC (i.e., zero offset) instead.
+ */
+ TTimeZone GetFixedTimeZone(const long offset);
+
+ /** Convert civil time from one timezone to another
+ * @param[in] src is source time with 'from' timezone
+ * @param[in] from is a initial timezone
+ * @param[in] from is a destination timezone
+ * @return a civil time
+ */
+ template <typename T>
+ T Convert(const T& src, const TTimeZone& from, const TTimeZone& to) {
+ return cctz::convert(cctz::convert(src, from), to);
+ }
+
+ /** Convert absolute time to civil time by rules from timezone.
+ * @param[in] absTime is an absolute time which is used to convert
+ * @param[in] tz is a loaded timezone
+ * @return a civil time
+ *
+ * Note: This function doesn't work properly for dates before 1 Jan 1970!
+ */
+ TCivilSecond Convert(const TInstant& absTime, const TTimeZone& tz);
+
+ /** Convert absolute time to civil time by rules from timezone which will be loaded.
+ * @throw InvalidTimezone if the name is invalid.
+ * @param[in] absTime is an absolute time which is used to convert
+ * @param[in] tzName is a timezone name which will be loaded
+ * @return a civil time
+ *
+ * Note: This function doesn't work properly for dates before 1 Jan 1970!
+ */
+ TCivilSecond Convert(const TInstant& absTime, TStringBuf tzName);
+
+ /** Convert a civil time to absolute by using rules from timezone
+ *
+ * Note: This function doesn't work properly for dates before 1 Jan 1970!
+ */
+ TInstant Convert(const TCivilSecond& s, const TTimeZone& tz);
+
+ /** Just to simply calculations between dates/times.
+ * NDatetime::Calc<TCivilDay>(TCivilSecond(2001, 1, 1, 10, 10, 10), 5); // returns TCivilDay(2001, 1, 6);
+ * @param[in] tp is a timepoint with which calc will be
+ * @param[in] diff is quantity of which will be added (of type T) to the tp
+ * @return the calculated T type
+ */
+ template <typename T, typename S>
+ inline T Calc(const S& tp, TDiff diff) {
+ return T(tp) + diff;
+ }
+
+ /** Non-template methods for adding dates/times.
+ * @param[in] tp is a timepoint with which calc will be
+ * @param[in] diff is quantity of which will be added to the tp
+ * @return the calculated TCivilSecond object
+ */
+ TCivilSecond AddYears(const TCivilSecond& tp, TDiff diff);
+ TCivilSecond AddMonths(const TCivilSecond& tp, TDiff diff);
+ TCivilSecond AddDays(const TCivilSecond& tp, TDiff diff);
+ TCivilSecond AddHours(const TCivilSecond& tp, TDiff diff);
+ TCivilSecond AddMinutes(const TCivilSecond& tp, TDiff diff);
+ TCivilSecond AddSeconds(const TCivilSecond& tp, TDiff diff);
+
+ /** Method to add TCivilDiff
+ * @param[in] tp is a timepoint with which calc will be
+ * @param[in] diff is quantity of which will be added to the tp
+ * @return the calculated TCivilSecond object
+ */
+ TCivilSecond AddCivil(const TCivilSecond& tp, TCivilDiff diff);
+
+ /** Method to subtract to civil dates/times and get TCivilDiff.
+ * First casts to unit, then subtracts;
+ * e.g. GetCivilDiff(2017-10-01, 2017-09-30, Month) = 1.
+ *
+ * @param[in] tpX is a timepoint
+ * @param[in] tpY is a timepoint to subtract from tpX
+ * @param[in] unit is a civil time unit to use in subtraction
+ * @return the calculated diff as TCivilDiff object
+ */
+ TCivilDiff GetCivilDiff(const TCivilSecond& tpX, const TCivilSecond& tpY, ECivilUnit unit);
+
+ /** Formats the given TimePoint in the given TTimeZone according to
+ * the provided format string. Uses strftime()-like formatting options,
+ * with the following extensions:
+ *
+ * - %Ez - RFC3339-compatible numeric time zone (+hh:mm or -hh:mm)
+ * - %E#S - Seconds with # digits of fractional precision
+ * - %E*S - Seconds with full fractional precision (a literal '*')
+ * - %E#f - Fractional seconds with # digits of precision
+ * - %E*f - Fractional seconds with full precision (a literal '*')
+ * - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
+ *
+ * Note that %E0S behaves like %S, and %E0f produces no characters. In
+ * contrast %E*f always produces at least one digit, which may be '0'.
+ *
+ * Note that %Y produces as many characters as it takes to fully render the
+ * year. A year outside of [-999:9999] when formatted with %E4Y will produce
+ * more than four characters, just like %Y.
+ *
+ * Tip: Format strings should include the UTC offset (e.g., %z or %Ez) so that
+ * the resultng string uniquely identifies an absolute time.
+ *
+ * Example:
+ * NDatetime::TTimeZone lax = NDatetime::GetTimeZone("America/Los_Angeles");
+ * NDatetime::TCivilSecond tp(2013, 1, 2, 3, 4, 5);
+ * TString f = NDatetime::Format("%H:%M:%S", tp, lax); // "03:04:05"
+ * TString f = NDatetime::Format("%H:%M:%E3S", tp, lax); //"03:04:05.000"
+ */
+ template <typename TP>
+ TString Format(TStringBuf fmt, const TP& tp, const TTimeZone& tz) {
+ return TString(cctz::format(static_cast<std::string>(fmt), TTimePoint(cctz::convert(tp, tz)), tz));
+ }
+
+ /** Returns the weekday by day.
+ * @param[in] day is a given day
+ * @return a weekday (enum)
+ */
+ CONSTEXPR_M TWeekday GetWeekday(const TCivilDay& day) noexcept {
+ return cctz::get_weekday(day);
+ }
+
+ /** Returns the TCivilDay that strictly follows or precedes the given
+ * civil_day, and that falls on the given weekday.
+ * @code
+ For example, given:
+
+ August 2015
+ Su Mo Tu We Th Fr Sa
+ 1
+ 2 3 4 5 6 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
+
+ TCivilDay a(2015, 8, 13); // GetWeekday(a) == TWeekday::thursday
+ TCivilDay b = NextWeekday(a, TWeekday::thursday); // b = 2015-08-20
+ TCivilDay c = PrevWeekday(a, TWeekday::thursday); // c = 2015-08-06
+ TCivilDay d = NearestWeekday(a, TWeekday::thursday); // d = 2015-08-13
+
+ TCivilDay e = ...
+ // Gets the following Thursday if e is not already Thursday
+ TCivilDay thurs1 = PrevWeekday(e, TWeekday::thursday) + 7;
+ // Gets the previous Thursday if e is not already Thursday
+ TCivilDay thurs2 = NextWeekday(e, TWeekday::thursday) - 7;
+ * @endcode
+ * @see PrevWeekday()
+ * @see NearestWeekday()
+ * @param[in] cd is a current day
+ * @param[in] wd is a weekday which wanetd for find on next week
+ * @return a civil day on weekday next week
+ */
+ CONSTEXPR_M TCivilDay NextWeekday(const TCivilDay& cd, TWeekday wd) noexcept {
+ return cctz::next_weekday(cd, wd);
+ }
+
+ /** Returns prev weekday. See the description of NextWeekday().
+ * @see NextWeekday()
+ * @see NearestWeekday()
+ * @param[in] cd is a current day
+ * @param[in] wd is a weekday which is looking for (backward)
+ * @return a first occurence of the given weekday (backward)
+ */
+ CONSTEXPR_M TCivilDay PrevWeekday(const TCivilDay& cd, TWeekday wd) noexcept {
+ return cctz::prev_weekday(cd, wd);
+ }
+
+ /** Find a nearest occurence of the given weekday forward (could be current day).
+ * @see NextWeekday()
+ * @param[in] cd is a current day
+ * @param[in] wd is a weekday which is looking for (current day or later)
+ * @return first occurence (including current day) of the given weekday
+ */
+ CONSTEXPR_M TCivilDay NearestWeekday(const TCivilDay& cd, TWeekday wd) noexcept {
+ return get_weekday(cd) != wd ? next_weekday(cd, wd) : cd;
+ }
+
+ /** Find the date of the given weekday within the given week.
+ * @param[in] cd is a current day
+ * @param[in] wd is a requested week day
+ * @return day within a week of a given day
+ */
+ CONSTEXPR_M TCivilDay WeekdayOnTheWeek(const TCivilDay& cd, TWeekday wd) noexcept {
+ const auto d = get_weekday(cd);
+ if (d == wd)
+ return cd;
+
+ return d < wd ? NextWeekday(cd, wd) : PrevWeekday(cd, wd);
+ }
+
+ /** Returns an absolute day of year by given day.
+ */
+ CONSTEXPR_M int GetYearDay(const TCivilDay& cd) noexcept {
+ return cctz::get_yearday(cd);
+ }
+
+ CONSTEXPR_M int DaysPerMonth(TYear year, TMonth month) noexcept {
+ return cctz::detail::impl::days_per_month(year, month);
+ }
+
+ CONSTEXPR_M int DaysPerYear(TYear year, TMonth month) noexcept {
+ return cctz::detail::impl::days_per_year(year, month);
+ }
+
+ /** Calculate week number for the given date
+ * @param[in] cd is a current day
+ * @param[in] usePreviousYear (optional) true if calculate week number from previous year
+ *
+ * The week number starts from 1 for the first week, where Thursday exist (see ISO8601), i.e.
+ * Jan 2021
+ * week# mo tu we th fr sa su
+ * 53 1 2 3
+ * 01 4 5 6 7 8 9 10
+ * 02 11 ...
+ * Jan 2020
+ * week# mo tu we th fr sa su
+ * 01 1 2 3 4 5
+ * 02 6 7 8 9 10 11...
+ *
+ * In case if you received zero value, you may call function again with usePreviousYear=true
+ * Also you may use usePreviousYear to calculate week difference between two dates in different year
+ */
+ CONSTEXPR_M int GetYearWeek(const TCivilDay& cd, bool usePreviousYear = false) noexcept {
+ const auto jan1 = NDatetime::GetWeekday(NDatetime::TCivilDay{cd.year() - (usePreviousYear ? 1 : 0), 1, 1});
+ const auto daysCount = GetYearDay(cd) + (usePreviousYear ? DaysPerYear(cd.year()-1, 1) : 0);
+
+ return (daysCount + static_cast<int>(jan1) - 1) / 7 + (jan1 == cctz::weekday::monday || jan1 == cctz::weekday::tuesday || jan1 == cctz::weekday::wednesday);
+ }
+}
+
+#include "civil-inl.h"
+
+#undef CONSTEXPR_M
diff --git a/library/cpp/timezone_conversion/convert.cpp b/library/cpp/timezone_conversion/convert.cpp
new file mode 100644
index 0000000000..490bb4e270
--- /dev/null
+++ b/library/cpp/timezone_conversion/convert.cpp
@@ -0,0 +1,93 @@
+#include "convert.h"
+
+#include <contrib/libs/cctz/include/cctz/civil_time.h>
+
+#include <util/generic/yexception.h>
+
+#include <chrono>
+
+namespace NDatetime {
+ static constexpr i64 TM_YEAR_OFFSET = 1900;
+ using TSystemClock = std::chrono::system_clock;
+ using TTimePoint = std::chrono::time_point<TSystemClock>;
+
+ static TSimpleTM CivilToTM(const cctz::civil_second& cs, const cctz::time_zone::absolute_lookup& al) {
+ cctz::civil_day cd(cs);
+ TSimpleTM tm;
+ tm.GMTOff = al.offset;
+ tm.Year = cs.year() - TM_YEAR_OFFSET;
+ tm.YDay = cctz::get_yearday(cd);
+ tm.Mon = cs.month() - 1;
+ tm.MDay = cs.day();
+ tm.Hour = cs.hour();
+ tm.Min = cs.minute();
+ tm.Sec = cs.second();
+ tm.IsDst = al.is_dst;
+ tm.IsLeap = LeapYearAD(cs.year());
+
+ switch (cctz::get_weekday(cd)) {
+ case cctz::weekday::monday:
+ tm.WDay = 1;
+ break;
+ case cctz::weekday::tuesday:
+ tm.WDay = 2;
+ break;
+ case cctz::weekday::wednesday:
+ tm.WDay = 3;
+ break;
+ case cctz::weekday::thursday:
+ tm.WDay = 4;
+ break;
+ case cctz::weekday::friday:
+ tm.WDay = 5;
+ break;
+ case cctz::weekday::saturday:
+ tm.WDay = 6;
+ break;
+ case cctz::weekday::sunday:
+ tm.WDay = 0;
+ break;
+ }
+
+ return tm;
+ }
+
+ /*
+ TTimeZone GetTimeZone(const TString& name) {
+ TTimeZone result;
+ if (!cctz::load_time_zone(name, &result)) {
+ ythrow yexception() << "Failed to load time zone " << name << ", " << result.name();
+ }
+ return result;
+ }
+ */
+
+ TTimeZone GetUtcTimeZone() {
+ return cctz::utc_time_zone();
+ }
+
+ TTimeZone GetLocalTimeZone() {
+ return cctz::local_time_zone();
+ }
+
+ TSimpleTM ToCivilTime(const TInstant& absoluteTime, const TTimeZone& tz) {
+ TTimePoint tp = TSystemClock::from_time_t(absoluteTime.TimeT());
+ return CivilToTM(cctz::convert(tp, tz), tz.lookup(tp));
+ }
+
+ TSimpleTM CreateCivilTime(const TTimeZone& tz, ui32 year, ui32 mon, ui32 day, ui32 h, ui32 m, ui32 s) {
+ cctz::civil_second cs(year, mon, day, h, m, s);
+ return CivilToTM(cs, tz.lookup(tz.lookup(cs).pre));
+ }
+
+ TInstant ToAbsoluteTime(const TSimpleTM& civilTime, const TTimeZone& tz) {
+ cctz::civil_second cs(
+ civilTime.Year + TM_YEAR_OFFSET,
+ civilTime.Mon + 1,
+ civilTime.MDay,
+ civilTime.Hour,
+ civilTime.Min,
+ civilTime.Sec);
+ return TInstant::Seconds(TSystemClock::to_time_t(tz.lookup(cs).pre));
+ }
+}
diff --git a/library/cpp/timezone_conversion/convert.h b/library/cpp/timezone_conversion/convert.h
new file mode 100644
index 0000000000..768a9e110f
--- /dev/null
+++ b/library/cpp/timezone_conversion/convert.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "civil.h"
+
+#include <contrib/libs/cctz/include/cctz/time_zone.h>
+#include <util/datetime/base.h>
+#include <util/draft/datetime.h>
+
+namespace NDatetime {
+ /**
+ * @return The mother of all time zones.
+ * @see https://en.wikipedia.org/wiki/Coordinated_Universal_Time
+ */
+ TTimeZone GetUtcTimeZone();
+
+ /**
+ * @return The time zone that is curently set on your machine.
+ */
+ TTimeZone GetLocalTimeZone();
+
+ /**
+ * @param absoluteTime A TInstant representing a number of seconds elapsed
+ * since The Epoch (the microsecond part is ignored).
+ * @param tz The time zone to use for conversion.
+ * @return The civil time corresponding to absoluteTime.
+ * @note This conversion is always well-defined (i.e., there
+ * is exactly one civil time which corresponds to
+ * absoluteTime).
+ * @see https://en.wikipedia.org/wiki/Unix_time
+ */
+ TSimpleTM ToCivilTime(const TInstant& absoluteTime, const TTimeZone& tz);
+
+ /**
+ * Creates civil time in place with respect of given timezone.
+ * @param[in] tz The time zone to use for creation.
+ * @param[in] year The year of the creation time.
+ * @param[in] mon The month of the creation time.
+ * @param[in] day The day of the creation time.
+ * @param[in] h The hour of the creation time.
+ * @param[in] m The minute of the creation time.
+ * @param[in] s The second of the creation time.
+ * @return a civil time
+ */
+ TSimpleTM CreateCivilTime(const TTimeZone& tz, ui32 year, ui32 mon, ui32 day, ui32 h = 0, ui32 m = 0, ui32 s = 0);
+
+ /**
+ * @param civilTime A human-readable date and time (the following fields
+ * are used by this function: {Year,Mon,MDay,Hour,Min,Sec}).
+ * @param tz The time zone to use for conversion.
+ * @return Some absolute time corresponding to civilTime.
+ * @note If multiple absolute times match civilTime, the earliest
+ * if returned.
+ * If civilTime doesn't exist due to discontinuity in time
+ * (e.g., DST happened) we pretend the discontinuity isn't
+ * there (i.e., if we skipped from 1:59AM to 3:00AM then
+ * ToAbsoluteTime(2:30AM) == ToAbsoluteTime(3:30AM)).
+ * @see https://en.wikipedia.org/wiki/Daylight_saving_time
+ */
+ TInstant ToAbsoluteTime(const TSimpleTM& civilTime, const TTimeZone& tz);
+}
diff --git a/library/cpp/timezone_conversion/ut/civil_ut.cpp b/library/cpp/timezone_conversion/ut/civil_ut.cpp
new file mode 100644
index 0000000000..a21bd4bd7d
--- /dev/null
+++ b/library/cpp/timezone_conversion/ut/civil_ut.cpp
@@ -0,0 +1,157 @@
+#include <library/cpp/timezone_conversion/civil.h>
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/testing/unittest/tests_data.h>
+
+#include <util/stream/str.h>
+
+namespace NDatetime {
+ inline bool operator==(const NDatetime::TCivilDiff& x, const NDatetime::TCivilDiff& y) {
+ return x.Unit == y.Unit && x.Value == y.Value;
+ }
+}
+
+template <>
+inline void Out<NDatetime::TCivilDiff>(IOutputStream& out, const NDatetime::TCivilDiff& diff) {
+ out << "(" << diff.Value << "," << diff.Unit << ")";
+}
+
+Y_UNIT_TEST_SUITE(DateTime) {
+ Y_UNIT_TEST(Calc) {
+ NDatetime::TCivilSecond s(2017, 2, 1, 10, 12, 9);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::Calc<NDatetime::TCivilDay>(s, 2), NDatetime::TCivilDay(2017, 2, 3));
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::Calc<NDatetime::TCivilDay>(s, -2), NDatetime::TCivilDay(2017, 1, 30));
+ }
+ Y_UNIT_TEST(Adds) {
+ NDatetime::TCivilSecond s(2017, 2, 1, 10, 12, 9);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::AddDays(s, 2), NDatetime::TCivilSecond(2017, 2, 3, 10, 12, 9));
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::AddMonths(s, -2), NDatetime::TCivilSecond(2016, 12, 1, 10, 12, 9));
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::AddYears(s, -55), NDatetime::TCivilSecond(1962, 2, 1, 10, 12, 9));
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::AddHours(s, 40), NDatetime::TCivilSecond(2017, 2, 3, 2, 12, 9));
+ }
+ Y_UNIT_TEST(Convert) {
+ TInstant absTime = TInstant::Seconds(1500299239);
+ NDatetime::TTimeZone lax = NDatetime::GetTimeZone("America/Los_Angeles");
+ NDatetime::TCivilSecond dt1 = NDatetime::Convert(absTime, lax);
+ NDatetime::TCivilSecond dt2(2017, 7, 17, 6, 47, 19);
+ UNIT_ASSERT_VALUES_EQUAL(dt1, dt2);
+ UNIT_ASSERT_VALUES_EQUAL(absTime, NDatetime::Convert(dt2, lax));
+ UNIT_ASSERT_EXCEPTION(NDatetime::Convert(absTime, "Unknown time zone"), NDatetime::TInvalidTimezone);
+ }
+ Y_UNIT_TEST(UTCOffsetTimezone) {
+ NDatetime::TTimeZone lax = NDatetime::GetTimeZone("UTC+12");
+ auto lookup = lax.lookup(std::chrono::system_clock::from_time_t(0));
+ UNIT_ASSERT_VALUES_EQUAL(12 * 60 * 60, lookup.offset);
+ lax = NDatetime::GetTimeZone("UTC-10");
+ lookup = lax.lookup(std::chrono::system_clock::from_time_t(0));
+ UNIT_ASSERT_VALUES_EQUAL(-10 * 60 * 60, lookup.offset);
+ lax = NDatetime::GetTimeZone("UTC");
+ lookup = lax.lookup(std::chrono::system_clock::from_time_t(0));
+ UNIT_ASSERT_VALUES_EQUAL(0, lookup.offset);
+ lax = NDatetime::GetTimeZone("UTC+0");
+ lookup = lax.lookup(std::chrono::system_clock::from_time_t(0));
+ UNIT_ASSERT_VALUES_EQUAL(0, lookup.offset);
+ lax = NDatetime::GetTimeZone("UTC-2");
+ lookup = lax.lookup(std::chrono::system_clock::from_time_t(0));
+ UNIT_ASSERT_VALUES_EQUAL(-2 * 60 * 60, lookup.offset);
+ lax = NDatetime::GetTimeZone("UTC-00:30");
+ lookup = lax.lookup(std::chrono::system_clock::from_time_t(0));
+ UNIT_ASSERT_VALUES_EQUAL(-30 * 60, lookup.offset);
+ lax = NDatetime::GetTimeZone("UTC-0241");
+ lookup = lax.lookup(std::chrono::system_clock::from_time_t(0));
+ UNIT_ASSERT_VALUES_EQUAL(-(2 * 60 + 41) * 60, lookup.offset);
+ UNIT_ASSERT_EXCEPTION(NDatetime::GetTimeZone("UTCUnknown"), NDatetime::TInvalidTimezone);
+ UNIT_ASSERT_EXCEPTION(NDatetime::GetTimeZone("UTC+:"), NDatetime::TInvalidTimezone);
+ UNIT_ASSERT_EXCEPTION(NDatetime::GetTimeZone("UTC+24:01"), NDatetime::TInvalidTimezone);
+ UNIT_ASSERT_EXCEPTION(NDatetime::GetTimeZone("UTC+20:"), NDatetime::TInvalidTimezone);
+ UNIT_ASSERT_EXCEPTION(NDatetime::GetTimeZone("UTC+20:60"), NDatetime::TInvalidTimezone);
+ UNIT_ASSERT_EXCEPTION(NDatetime::GetTimeZone("UTC+20:30:"), NDatetime::TInvalidTimezone);
+ }
+ Y_UNIT_TEST(Format) {
+ NDatetime::TTimeZone lax = NDatetime::GetTimeZone("America/Los_Angeles");
+ NDatetime::TCivilSecond tp(2013, 1, 2, 3, 4, 5);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::Format("%H:%M:%S", tp, lax), "03:04:05");
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::Format("%H:%M:%E3S", tp, lax), "03:04:05.000");
+ }
+ Y_UNIT_TEST(Weekday) {
+ NDatetime::TCivilDay d(2013, 1, 2);
+ NDatetime::TWeekday wd = NDatetime::GetWeekday(d);
+ UNIT_ASSERT_VALUES_EQUAL(wd, NDatetime::TWeekday::wednesday);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::NextWeekday(d, NDatetime::TWeekday::monday), NDatetime::TCivilDay(2013, 1, 7));
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::PrevWeekday(d, NDatetime::TWeekday::monday), NDatetime::TCivilDay(2012, 12, 31));
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::WeekdayOnTheWeek(d, NDatetime::TWeekday::monday), NDatetime::TCivilDay(2012, 12, 31));
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::WeekdayOnTheWeek(d, NDatetime::TWeekday::wednesday), NDatetime::TCivilDay(2013, 1, 2));
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::WeekdayOnTheWeek(d, NDatetime::TWeekday::friday), NDatetime::TCivilDay(2013, 1, 4));
+ }
+ Y_UNIT_TEST(CivilUnit) {
+ using namespace NDatetime;
+
+ UNIT_ASSERT_VALUES_EQUAL(GetCivilUnit<TCivilMonth>(), ECivilUnit::Month);
+ UNIT_ASSERT_VALUES_EQUAL(GetCivilUnit(TCivilHour{}), ECivilUnit::Hour);
+
+ UNIT_ASSERT_VALUES_EQUAL(TCivilTime<ECivilUnit::Day>(2017, 1, 11), TCivilDay(2017, 1, 11));
+
+ NDatetime::TCivilSecond s(2017, 2, 1, 10, 12, 9);
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ NDatetime::AddCivil(s, TCivilDiff{2, ECivilUnit::Day}),
+ NDatetime::AddDays(s, 2));
+ UNIT_ASSERT_VALUES_EQUAL(
+ NDatetime::AddCivil(s, TCivilDiff{-2, ECivilUnit::Month}),
+ NDatetime::AddMonths(s, -2));
+ UNIT_ASSERT_VALUES_EQUAL(
+ NDatetime::AddCivil(s, TCivilDiff{-55, ECivilUnit::Year}),
+ NDatetime::AddYears(s, -55));
+ UNIT_ASSERT_VALUES_EQUAL(
+ NDatetime::AddCivil(s, TCivilDiff{40, ECivilUnit::Hour}),
+ NDatetime::AddHours(s, 40));
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ GetCivilDiff(TCivilSecond(2017, 10), TCivilSecond(2017, 7), ECivilUnit::Month),
+ TCivilDiff(3, ECivilUnit::Month));
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ GetCivilDiff(TCivilSecond(2017, 10, 1), TCivilSecond(2017, 9, 30), ECivilUnit::Month),
+ TCivilDiff(1, ECivilUnit::Month));
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ GetCivilDiff(TCivilSecond(2017, 10, 1), TCivilSecond(2017, 9, 31), ECivilUnit::Month),
+ TCivilDiff(0, ECivilUnit::Month));
+ }
+
+ Y_UNIT_TEST(TestYearWeekNmb) {
+
+ // YEAR 2021 - start from Friday, first dates (1-3) will have week# 0
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 1, 1}), 0);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 1, 2}), 0);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 1, 3}), 0);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 1, 4}), 1);
+
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 1, 1}, true), 53);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 1, 2}, true), 53);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 1, 3}, true), 53);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 1, 4}, true), 54);
+
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 2, 28}), 8);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 2, 29}), 9); // <- this is invalid date, should be normalized to March 1
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 3, 1}), 9);
+
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 12, 26}), 51);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 12, 27}), 52);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 12, 31}), 52);
+
+ // YEAR 2020 - start from Wednesday, all dates start from week# 1
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2020, 1, 1}), 1);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2020, 1, 5}), 1);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2020, 1, 6}), 2);
+
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2020, 2, 28}), 9);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2020, 2, 29}), 9);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2020, 3, 1}), 9);
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2020, 3, 2}), 10);
+
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2020, 12, 31}), 53);
+
+ // Max possible delta - calcuate week # for 31 Dec 2021 from 1 Jan 2020
+ UNIT_ASSERT_VALUES_EQUAL(NDatetime::GetYearWeek(NDatetime::TCivilDay{2021, 12, 31}, true), 105);
+ }
+}
diff --git a/library/cpp/timezone_conversion/ut/convert_ut.cpp b/library/cpp/timezone_conversion/ut/convert_ut.cpp
new file mode 100644
index 0000000000..bbf9e9b826
--- /dev/null
+++ b/library/cpp/timezone_conversion/ut/convert_ut.cpp
@@ -0,0 +1,204 @@
+#include <library/cpp/timezone_conversion/convert.h>
+#include <library/cpp/testing/unittest/gtest.h>
+
+using namespace NDatetime;
+
+template <>
+void Out<TSimpleTM>(IOutputStream& os, TTypeTraits<TSimpleTM>::TFuncParam value) {
+ os << value.ToString() << ", dst: " << int(value.IsDst);
+}
+
+TSimpleTM ZonedTm(i32 utcHours, bool isDst, ui32 year, ui32 mon, ui32 day, ui32 h, ui32 m, ui32 s) {
+ TSimpleTM res(year, mon, day, h, m, s);
+ res.GMTOff = utcHours * 60 * 60;
+ res.IsDst = isDst;
+ return res;
+}
+
+void CompareCivilTimes(const TSimpleTM& expected, const TSimpleTM& actual) {
+ EXPECT_EQ(expected.GMTOff, actual.GMTOff);
+ EXPECT_EQ(expected.Year, actual.Year);
+ EXPECT_EQ(expected.Mon, actual.Mon);
+ EXPECT_EQ(expected.MDay, actual.MDay);
+ EXPECT_EQ(expected.WDay, actual.WDay);
+ EXPECT_EQ(expected.Hour, actual.Hour);
+ EXPECT_EQ(expected.Min, actual.Min);
+ EXPECT_EQ(expected.Sec, actual.Sec);
+ EXPECT_EQ(expected.IsDst, actual.IsDst);
+ EXPECT_EQ(expected.IsLeap, actual.IsLeap);
+}
+
+#define CHECK_ROUND_TRIP(tz, unixTime, civil) \
+ EXPECT_EQ( \
+ TInstant::Seconds(unixTime), \
+ ToAbsoluteTime(civil, tz)); \
+ CompareCivilTimes( \
+ civil, \
+ ToCivilTime(TInstant::Seconds(unixTime), tz));
+
+// Tests only unambiguous civil times (i.e., those that occurred exactly once).
+TEST(TimeZoneConversion, Simple) {
+ TTimeZone msk = GetTimeZone("Europe/Moscow");
+ // Before and after the temporary switch to UTC+3 in 2010.
+ CHECK_ROUND_TRIP(
+ msk,
+ 1288475999,
+ ZonedTm(+4, true, 2010, 10, 31, 1, 59, 59));
+ CHECK_ROUND_TRIP(
+ msk,
+ 1288475999 + 3 * 60 * 60,
+ ZonedTm(+3, false, 2010, 10, 31, 3, 59, 59));
+
+ // Before and after the permanent switch to UTC+4 in 2011.
+ CHECK_ROUND_TRIP(
+ msk,
+ 1301180399,
+ ZonedTm(+3, false, 2011, 3, 27, 1, 59, 59));
+ CHECK_ROUND_TRIP(
+ msk,
+ 1301180399 + 60 * 60,
+ ZonedTm(+4, false, 2011, 3, 27, 3, 59, 59));
+
+ // Some random moment between 2011 and 2014 when UTC+4 (no DST) was in place.
+ CHECK_ROUND_TRIP(
+ msk,
+ 1378901234,
+ ZonedTm(+4, false, 2013, 9, 11, 16, 7, 14));
+
+ // As of right now (i.e., as I'm writing this) Moscow is in UTC+3 (no DST).
+ CHECK_ROUND_TRIP(
+ msk,
+ 1458513396,
+ ZonedTm(+3, false, 2016, 3, 21, 1, 36, 36));
+
+ // Please add a new test if the current president moves Moscow back to UTC+4
+ // or introduces DST again.
+}
+
+TEST(TimeZoneConversion, TestRepeatedDate) {
+ TTimeZone ekb = GetTimeZone("Asia/Yekaterinburg");
+
+ CompareCivilTimes(
+ ZonedTm(+6, true, 2010, 10, 31, 2, 30, 0),
+ ToCivilTime(TInstant::Seconds(1288470600), ekb));
+
+ CompareCivilTimes(
+ ZonedTm(+5, false, 2010, 10, 31, 2, 30, 0),
+ ToCivilTime(TInstant::Seconds(1288474200), ekb));
+
+ CompareCivilTimes(
+ ZonedTm(+5, false, 2016, 5, 10, 9, 8, 7),
+ CreateCivilTime(ekb, 2016, 5, 10, 9, 8, 7));
+
+ CompareCivilTimes(
+ ZonedTm(+6, true, 2010, 10, 31, 2, 30, 0),
+ CreateCivilTime(ekb, 2010, 10, 31, 2, 30, 0));
+
+ // The earlier timestamp should be chosen.
+ EXPECT_EQ(
+ TInstant::Seconds(1288470600),
+ ToAbsoluteTime(TSimpleTM(2010, 10, 31, 2, 30, 0), ekb));
+}
+
+TEST(TimeZoneConversion, TestSkippedDate) {
+ TTimeZone nsk = GetTimeZone("Asia/Novosibirsk");
+
+ CompareCivilTimes(
+ ZonedTm(+6, false, 2011, 3, 27, 1, 30, 0),
+ ToCivilTime(TInstant::Seconds(1301167800), nsk));
+
+ CompareCivilTimes(
+ ZonedTm(+7, false, 2011, 3, 27, 3, 30, 0),
+ ToCivilTime(TInstant::Seconds(1301171400), nsk));
+
+ EXPECT_EQ(
+ TInstant::Seconds(1301171400),
+ ToAbsoluteTime(TSimpleTM(2011, 3, 27, 2, 30, 0), nsk));
+
+ EXPECT_EQ(
+ TInstant::Seconds(1301171400),
+ ToAbsoluteTime(TSimpleTM(2011, 3, 27, 3, 30, 0), nsk));
+}
+
+TEST(TimeZoneConversion, Utc) {
+ CHECK_ROUND_TRIP(
+ GetUtcTimeZone(),
+ 1451703845,
+ ZonedTm(0, false, 2016, 1, 2, 3, 4, 5));
+}
+
+TEST(TimeZoneConversion, Local) {
+ TTimeZone local = GetLocalTimeZone();
+ auto nowAbsolute = TInstant::Now();
+ auto nowCivilLocal = ToCivilTime(nowAbsolute, local);
+ EXPECT_EQ(nowAbsolute.Seconds(), ToAbsoluteTime(nowCivilLocal, local).Seconds());
+}
+
+TEST(TimeZoneConversion, BeforeEpoch) {
+ {
+ //NOTE: This test will not work because NDatetime::Convert() with TInstant does not work properly for dates before 1/1/1970
+ NDatetime::TCivilSecond civilTime = NDatetime::TCivilSecond{1969, 12, 1, 0, 0, 0};
+ TInstant absTime = NDatetime::Convert(civilTime, NDatetime::GetUtcTimeZone());
+ NDatetime::TCivilSecond civilTime2 = NDatetime::Convert(absTime, NDatetime::GetUtcTimeZone());
+ EXPECT_NE(civilTime2, civilTime); // ERROR. Must be EXPECT_EQ, but Convert() functions with TInstant doesnot wotk properly for dates before EPOCH
+ }
+
+ // Right test
+ NDatetime::TCivilSecond civilTime = NDatetime::TCivilSecond{1969, 12, 1, 0, 0, 0};
+ NDatetime::TCivilSecond civilTime2 = Convert<NDatetime::TCivilSecond>(civilTime, NDatetime::GetUtcTimeZone(), NDatetime::GetUtcTimeZone());
+ EXPECT_EQ(civilTime2, civilTime);
+
+}
+
+TEST(TimeZoneConversion, InvalidTimeZone) {
+ EXPECT_THROW(GetTimeZone("Europe/Mscow"), yexception);
+ EXPECT_THROW(GetTimeZone(""), yexception);
+}
+
+TEST(TimeZoneConversion, TestSaratov) {
+ TTimeZone saratov = GetTimeZone("Europe/Saratov");
+
+ CompareCivilTimes(
+ ZonedTm(+4, false, 2016, 12, 5, 1, 55, 35),
+ ToCivilTime(TInstant::Seconds(1480888535), saratov));
+
+ CompareCivilTimes(
+ ZonedTm(+3, false, 2016, 12, 1, 0, 55, 35),
+ ToCivilTime(TInstant::Seconds(1480542935), saratov));
+}
+
+TEST(TimeZoneConversion, TestFutureDstChanges) {
+ TTimeZone london = GetTimeZone("Europe/London");
+
+ // This test assumes the British won't cancel DST before 2025.
+ // I don't think they will, but then again, nobody really expected Brexit.
+
+ // DST is still in effect in early October 2025, meaning we are in UTC+1.
+ CHECK_ROUND_TRIP(
+ london,
+ 1760124660,
+ ZonedTm(+1, true, 2025, 10, 10, 20, 31, 0));
+
+ // 31 days later we're back to UTC+0 again.
+ CHECK_ROUND_TRIP(
+ london,
+ 1760124660 + 31 * 24 * 60 * 60,
+ ZonedTm(+0, false, 2025, 11, 10, 19, 31, 0));
+}
+
+TEST(TimeZoneConversion, TWDay) {
+ TTimeZone nsk = GetTimeZone("Asia/Novosibirsk");
+
+ for (time_t e = 1301167800, to = 1301167800 + 86400 * 7, dow = 0; e < to; e += 86400, ++dow) {
+ EXPECT_EQ(dow, ToCivilTime(TInstant::Seconds(e), nsk).WDay);
+ }
+}
+
+TEST(TimeZoneConversion, TestBaikonur) {
+ // Yes, the Baikonur spaceport is located in Kyzylorda Region.
+ const auto baikonur = GetTimeZone("Asia/Qyzylorda");
+
+ CompareCivilTimes(
+ ZonedTm(+5, false, 2019, 1, 11, 23, 55, 23),
+ ToCivilTime(TInstant::Seconds(1547232923), baikonur));
+}
diff --git a/library/cpp/timezone_conversion/ut/ya.make b/library/cpp/timezone_conversion/ut/ya.make
new file mode 100644
index 0000000000..781a57da9f
--- /dev/null
+++ b/library/cpp/timezone_conversion/ut/ya.make
@@ -0,0 +1,15 @@
+UNITTEST()
+
+OWNER(dfyz)
+
+PEERDIR(
+ library/cpp/testing/unittest
+ library/cpp/timezone_conversion
+)
+
+SRCS(
+ convert_ut.cpp
+ civil_ut.cpp
+)
+
+END()
diff --git a/library/cpp/timezone_conversion/ya.make b/library/cpp/timezone_conversion/ya.make
new file mode 100644
index 0000000000..f99ebe73ee
--- /dev/null
+++ b/library/cpp/timezone_conversion/ya.make
@@ -0,0 +1,22 @@
+LIBRARY()
+
+OWNER(
+ dfyz
+ petrk
+)
+
+PEERDIR(
+ contrib/libs/cctz/tzdata
+ util/draft
+)
+
+SRCS(
+ convert.cpp
+ civil.cpp
+)
+
+GENERATE_ENUM_SERIALIZATION(civil.h)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/tld/gen_tld.py b/library/cpp/tld/gen_tld.py
new file mode 100755
index 0000000000..882b701e1d
--- /dev/null
+++ b/library/cpp/tld/gen_tld.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import sys, os
+
+def main():
+ alphabet = 'abcdefghijklmnopqrstuvwxyz'
+ tlds = dict()
+
+ for s in alphabet:
+ tlds[s] = list()
+ tlds['xn--'] = list()
+
+ tld_file = open(sys.argv[1], 'r')
+ for line in tld_file.readlines():
+ domain = line.strip().lower()
+ for label in tlds:
+ if domain.startswith('xn--'):
+ tlds['xn--'].append(domain)
+ break
+ elif domain.startswith('x'):
+ tlds['x'].append(domain)
+ break
+ else:
+ if domain.startswith(label):
+ tlds[label].append(domain)
+ break
+
+ print '// actual list can be found at http://data.iana.org/TLD/tlds-alpha-by-domain.txt'
+ print 'static const char* const TopLevelDomains[] = {'
+
+ for label, value in sorted(tlds.iteritems()):
+ if label == 'xn--':
+ sys.stdout.write(' /* ')
+ str = ''
+ for n in value:
+ unicode_domain = n.decode('idna').encode('utf-8')
+ str += ('%s, ' % unicode_domain)
+ sys.stdout.write('%s*/\n' % str.rstrip())
+
+ sys.stdout.write(' ')
+ str = ''
+ for n in value:
+ str += ('"%s", ' % n)
+ sys.stdout.write('%s\n' % str.rstrip())
+ else:
+ sys.stdout.write(' ')
+ str = ''
+ for n in value:
+ str += ('"%s", ' % n)
+ sys.stdout.write('%s\n' % str.rstrip())
+
+ print ' 0'
+ print '};'
+
+if __name__ == '__main__':
+ main()
diff --git a/library/cpp/tld/tld.cpp b/library/cpp/tld/tld.cpp
new file mode 100644
index 0000000000..e31f3f0322
--- /dev/null
+++ b/library/cpp/tld/tld.cpp
@@ -0,0 +1,48 @@
+#include "tld.h"
+
+#include <library/cpp/digest/lower_case/hash_ops.h>
+
+#include <util/generic/hash_set.h>
+#include <util/generic/singleton.h>
+
+namespace NTld {
+ namespace {
+#include <library/cpp/tld/tld.inc>
+
+ using TCiHash = THashSet<TStringBuf, TCIOps, TCIOps>;
+
+ struct TTLDHash: public TCiHash {
+ TTLDHash() {
+ for (auto tld = GetTlds(); *tld; ++tld) {
+ insert(*tld);
+ }
+ }
+ };
+
+ struct TVeryGoodTld: public TCiHash {
+ TVeryGoodTld() {
+ auto domains = {
+ "am", "az", "biz", "by", "com", "cz", "de", "ec", "fr", "ge", "gov",
+ "gr", "il", "info", "kg", "kz", "mobi", "net", "nu", "org", "lt", "lv",
+ "md", "ru", "su", "tr", "ua", "uk", "uz", "ws", "xn--p1ai", "рф"};
+
+ for (auto d : domains) {
+ insert(d);
+ }
+ }
+ };
+ }
+
+ const char* const* GetTlds() {
+ return TopLevelDomains;
+ }
+
+ bool IsTld(const TStringBuf& s) {
+ return Default<TTLDHash>().contains(s);
+ }
+
+ bool IsVeryGoodTld(const TStringBuf& s) {
+ return Default<TVeryGoodTld>().contains(s);
+ }
+
+}
diff --git a/library/cpp/tld/tld.h b/library/cpp/tld/tld.h
new file mode 100644
index 0000000000..9e241de090
--- /dev/null
+++ b/library/cpp/tld/tld.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+namespace NTld {
+ const char* const* GetTlds();
+
+ // Note that FindTld() returns empty string when @host is single domain label (without '.').
+ // If you need whole @host for such case, you can use GetZone() from library/cpp/string_utils/url/url.h
+ inline TStringBuf FindTld(const TStringBuf& host) {
+ size_t p = host.rfind('.');
+ return p != TStringBuf::npos ? host.SubStr(p + 1) : TStringBuf();
+ }
+
+ bool IsTld(const TStringBuf& tld);
+
+ inline bool InTld(const TStringBuf& host) {
+ return IsTld(FindTld(host));
+ }
+
+ // check if @s belongs to a "good" subset of reliable TLDs, defined in tld.cpp
+ bool IsVeryGoodTld(const TStringBuf& tld);
+
+ inline bool InVeryGoodTld(const TStringBuf& host) {
+ return IsVeryGoodTld(FindTld(host));
+ }
+
+}
diff --git a/library/cpp/tld/tld_ut.cpp b/library/cpp/tld/tld_ut.cpp
new file mode 100644
index 0000000000..733200f2b5
--- /dev/null
+++ b/library/cpp/tld/tld_ut.cpp
@@ -0,0 +1,59 @@
+#include "tld.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <library/cpp/charset/doccodes.h>
+
+using namespace NTld;
+
+Y_UNIT_TEST_SUITE(TTldTest) {
+ Y_UNIT_TEST(TestFindTld) {
+ UNIT_ASSERT(FindTld("yandex.ru") == "ru");
+ UNIT_ASSERT(FindTld("YandeX.Ru") == "Ru");
+ UNIT_ASSERT(FindTld("yandex.com.tr") == "tr");
+ UNIT_ASSERT(FindTld("com.tr") == "tr");
+ UNIT_ASSERT(FindTld("abc.def.ghi") == "ghi");
+ UNIT_ASSERT(FindTld("abc.def.aaaaaaaaaa") == "aaaaaaaaaa");
+ UNIT_ASSERT(FindTld("a.b.c.d.e.f.g") == "g");
+
+ UNIT_ASSERT(FindTld(".diff") == "diff");
+ UNIT_ASSERT(FindTld(".") == "");
+ UNIT_ASSERT(FindTld("ru") == "");
+ UNIT_ASSERT(FindTld("") == "");
+ }
+
+ Y_UNIT_TEST(TestTLDs) {
+ UNIT_ASSERT(IsTld("ru"));
+ UNIT_ASSERT(IsTld("Ru"));
+ UNIT_ASSERT(IsTld("BMW"));
+ UNIT_ASSERT(IsTld("TiReS"));
+ UNIT_ASSERT(IsTld("xn--p1ai"));
+ UNIT_ASSERT(IsTld("YaHOO"));
+ UNIT_ASSERT(!IsTld("xn"));
+
+ UNIT_ASSERT(InTld("ru.ru"));
+ UNIT_ASSERT(!InTld("ru"));
+ UNIT_ASSERT(!InTld("ru."));
+ UNIT_ASSERT(!InTld("ru.xn"));
+ }
+
+ Y_UNIT_TEST(TestVeryGoodTlds) {
+ UNIT_ASSERT(IsVeryGoodTld("ru"));
+ UNIT_ASSERT(IsVeryGoodTld("Ru"));
+ UNIT_ASSERT(!IsVeryGoodTld("BMW"));
+ UNIT_ASSERT(!IsVeryGoodTld("TiReS"));
+ UNIT_ASSERT(IsVeryGoodTld("рф"));
+ UNIT_ASSERT(!IsVeryGoodTld("РФ")); // note that uppercase non-ascii tlds cannot be found
+ UNIT_ASSERT(IsVeryGoodTld("xn--p1ai")); // "рф"
+ UNIT_ASSERT(!IsVeryGoodTld("xn--p1ag")); // "ру"
+ UNIT_ASSERT(!IsVeryGoodTld("YaHOO"));
+ UNIT_ASSERT(!IsVeryGoodTld("xn"));
+
+ UNIT_ASSERT(InVeryGoodTld("ru.ru"));
+ UNIT_ASSERT(InVeryGoodTld("яндекс.рф"));
+ UNIT_ASSERT(InVeryGoodTld("http://xn--d1acpjx3f.xn--p1ai"));
+ UNIT_ASSERT(!InVeryGoodTld("ru"));
+ UNIT_ASSERT(!InVeryGoodTld("ru."));
+ UNIT_ASSERT(!InVeryGoodTld("ru.xn"));
+ }
+}
diff --git a/library/cpp/tld/tlds-alpha-by-domain.txt b/library/cpp/tld/tlds-alpha-by-domain.txt
new file mode 100644
index 0000000000..412a6e29cb
--- /dev/null
+++ b/library/cpp/tld/tlds-alpha-by-domain.txt
@@ -0,0 +1,1536 @@
+# Version 2019012200, Last Updated Tue Jan 22 07:07:01 2019 UTC
+AAA
+AARP
+ABARTH
+ABB
+ABBOTT
+ABBVIE
+ABC
+ABLE
+ABOGADO
+ABUDHABI
+AC
+ACADEMY
+ACCENTURE
+ACCOUNTANT
+ACCOUNTANTS
+ACO
+ACTIVE
+ACTOR
+AD
+ADAC
+ADS
+ADULT
+AE
+AEG
+AERO
+AETNA
+AF
+AFAMILYCOMPANY
+AFL
+AFRICA
+AG
+AGAKHAN
+AGENCY
+AI
+AIG
+AIGO
+AIRBUS
+AIRFORCE
+AIRTEL
+AKDN
+AL
+ALFAROMEO
+ALIBABA
+ALIPAY
+ALLFINANZ
+ALLSTATE
+ALLY
+ALSACE
+ALSTOM
+AM
+AMERICANEXPRESS
+AMERICANFAMILY
+AMEX
+AMFAM
+AMICA
+AMSTERDAM
+ANALYTICS
+ANDROID
+ANQUAN
+ANZ
+AO
+AOL
+APARTMENTS
+APP
+APPLE
+AQ
+AQUARELLE
+AR
+ARAB
+ARAMCO
+ARCHI
+ARMY
+ARPA
+ART
+ARTE
+AS
+ASDA
+ASIA
+ASSOCIATES
+AT
+ATHLETA
+ATTORNEY
+AU
+AUCTION
+AUDI
+AUDIBLE
+AUDIO
+AUSPOST
+AUTHOR
+AUTO
+AUTOS
+AVIANCA
+AW
+AWS
+AX
+AXA
+AZ
+AZURE
+BA
+BABY
+BAIDU
+BANAMEX
+BANANAREPUBLIC
+BAND
+BANK
+BAR
+BARCELONA
+BARCLAYCARD
+BARCLAYS
+BAREFOOT
+BARGAINS
+BASEBALL
+BASKETBALL
+BAUHAUS
+BAYERN
+BB
+BBC
+BBT
+BBVA
+BCG
+BCN
+BD
+BE
+BEATS
+BEAUTY
+BEER
+BENTLEY
+BERLIN
+BEST
+BESTBUY
+BET
+BF
+BG
+BH
+BHARTI
+BI
+BIBLE
+BID
+BIKE
+BING
+BINGO
+BIO
+BIZ
+BJ
+BLACK
+BLACKFRIDAY
+BLANCO
+BLOCKBUSTER
+BLOG
+BLOOMBERG
+BLUE
+BM
+BMS
+BMW
+BN
+BNL
+BNPPARIBAS
+BO
+BOATS
+BOEHRINGER
+BOFA
+BOM
+BOND
+BOO
+BOOK
+BOOKING
+BOSCH
+BOSTIK
+BOSTON
+BOT
+BOUTIQUE
+BOX
+BR
+BRADESCO
+BRIDGESTONE
+BROADWAY
+BROKER
+BROTHER
+BRUSSELS
+BS
+BT
+BUDAPEST
+BUGATTI
+BUILD
+BUILDERS
+BUSINESS
+BUY
+BUZZ
+BV
+BW
+BY
+BZ
+BZH
+CA
+CAB
+CAFE
+CAL
+CALL
+CALVINKLEIN
+CAM
+CAMERA
+CAMP
+CANCERRESEARCH
+CANON
+CAPETOWN
+CAPITAL
+CAPITALONE
+CAR
+CARAVAN
+CARDS
+CARE
+CAREER
+CAREERS
+CARS
+CARTIER
+CASA
+CASE
+CASEIH
+CASH
+CASINO
+CAT
+CATERING
+CATHOLIC
+CBA
+CBN
+CBRE
+CBS
+CC
+CD
+CEB
+CENTER
+CEO
+CERN
+CF
+CFA
+CFD
+CG
+CH
+CHANEL
+CHANNEL
+CHARITY
+CHASE
+CHAT
+CHEAP
+CHINTAI
+CHRISTMAS
+CHROME
+CHRYSLER
+CHURCH
+CI
+CIPRIANI
+CIRCLE
+CISCO
+CITADEL
+CITI
+CITIC
+CITY
+CITYEATS
+CK
+CL
+CLAIMS
+CLEANING
+CLICK
+CLINIC
+CLINIQUE
+CLOTHING
+CLOUD
+CLUB
+CLUBMED
+CM
+CN
+CO
+COACH
+CODES
+COFFEE
+COLLEGE
+COLOGNE
+COM
+COMCAST
+COMMBANK
+COMMUNITY
+COMPANY
+COMPARE
+COMPUTER
+COMSEC
+CONDOS
+CONSTRUCTION
+CONSULTING
+CONTACT
+CONTRACTORS
+COOKING
+COOKINGCHANNEL
+COOL
+COOP
+CORSICA
+COUNTRY
+COUPON
+COUPONS
+COURSES
+CR
+CREDIT
+CREDITCARD
+CREDITUNION
+CRICKET
+CROWN
+CRS
+CRUISE
+CRUISES
+CSC
+CU
+CUISINELLA
+CV
+CW
+CX
+CY
+CYMRU
+CYOU
+CZ
+DABUR
+DAD
+DANCE
+DATA
+DATE
+DATING
+DATSUN
+DAY
+DCLK
+DDS
+DE
+DEAL
+DEALER
+DEALS
+DEGREE
+DELIVERY
+DELL
+DELOITTE
+DELTA
+DEMOCRAT
+DENTAL
+DENTIST
+DESI
+DESIGN
+DEV
+DHL
+DIAMONDS
+DIET
+DIGITAL
+DIRECT
+DIRECTORY
+DISCOUNT
+DISCOVER
+DISH
+DIY
+DJ
+DK
+DM
+DNP
+DO
+DOCS
+DOCTOR
+DODGE
+DOG
+DOHA
+DOMAINS
+DOT
+DOWNLOAD
+DRIVE
+DTV
+DUBAI
+DUCK
+DUNLOP
+DUNS
+DUPONT
+DURBAN
+DVAG
+DVR
+DZ
+EARTH
+EAT
+EC
+ECO
+EDEKA
+EDU
+EDUCATION
+EE
+EG
+EMAIL
+EMERCK
+ENERGY
+ENGINEER
+ENGINEERING
+ENTERPRISES
+EPOST
+EPSON
+EQUIPMENT
+ER
+ERICSSON
+ERNI
+ES
+ESQ
+ESTATE
+ESURANCE
+ET
+ETISALAT
+EU
+EUROVISION
+EUS
+EVENTS
+EVERBANK
+EXCHANGE
+EXPERT
+EXPOSED
+EXPRESS
+EXTRASPACE
+FAGE
+FAIL
+FAIRWINDS
+FAITH
+FAMILY
+FAN
+FANS
+FARM
+FARMERS
+FASHION
+FAST
+FEDEX
+FEEDBACK
+FERRARI
+FERRERO
+FI
+FIAT
+FIDELITY
+FIDO
+FILM
+FINAL
+FINANCE
+FINANCIAL
+FIRE
+FIRESTONE
+FIRMDALE
+FISH
+FISHING
+FIT
+FITNESS
+FJ
+FK
+FLICKR
+FLIGHTS
+FLIR
+FLORIST
+FLOWERS
+FLY
+FM
+FO
+FOO
+FOOD
+FOODNETWORK
+FOOTBALL
+FORD
+FOREX
+FORSALE
+FORUM
+FOUNDATION
+FOX
+FR
+FREE
+FRESENIUS
+FRL
+FROGANS
+FRONTDOOR
+FRONTIER
+FTR
+FUJITSU
+FUJIXEROX
+FUN
+FUND
+FURNITURE
+FUTBOL
+FYI
+GA
+GAL
+GALLERY
+GALLO
+GALLUP
+GAME
+GAMES
+GAP
+GAY
+GARDEN
+GB
+GBIZ
+GD
+GDN
+GE
+GEA
+GENT
+GENTING
+GEORGE
+GF
+GG
+GGEE
+GH
+GI
+GIFT
+GIFTS
+GIVES
+GIVING
+GL
+GLADE
+GLASS
+GLE
+GLOBAL
+GLOBO
+GM
+GMAIL
+GMBH
+GMO
+GMX
+GN
+GODADDY
+GOLD
+GOLDPOINT
+GOLF
+GOO
+GOODYEAR
+GOOG
+GOOGLE
+GOP
+GOT
+GOV
+GP
+GQ
+GR
+GRAINGER
+GRAPHICS
+GRATIS
+GREEN
+GRIPE
+GROCERY
+GROUP
+GS
+GT
+GU
+GUARDIAN
+GUCCI
+GUGE
+GUIDE
+GUITARS
+GURU
+GW
+GY
+HAIR
+HAMBURG
+HANGOUT
+HAUS
+HBO
+HDFC
+HDFCBANK
+HEALTH
+HEALTHCARE
+HELP
+HELSINKI
+HERE
+HERMES
+HGTV
+HIPHOP
+HISAMITSU
+HITACHI
+HIV
+HK
+HKT
+HM
+HN
+HOCKEY
+HOLDINGS
+HOLIDAY
+HOMEDEPOT
+HOMEGOODS
+HOMES
+HOMESENSE
+HONDA
+HONEYWELL
+HORSE
+HOSPITAL
+HOST
+HOSTING
+HOT
+HOTELES
+HOTELS
+HOTMAIL
+HOUSE
+HOW
+HR
+HSBC
+HT
+HU
+HUGHES
+HYATT
+HYUNDAI
+IBM
+ICBC
+ICE
+ICU
+ID
+IE
+IEEE
+IFM
+IKANO
+IL
+IM
+IMAMAT
+IMDB
+IMMO
+IMMOBILIEN
+IN
+INC
+INDUSTRIES
+INFINITI
+INFO
+ING
+INK
+INSTITUTE
+INSURANCE
+INSURE
+INT
+INTEL
+INTERNATIONAL
+INTUIT
+INVESTMENTS
+IO
+IPIRANGA
+IQ
+IR
+IRISH
+IS
+ISELECT
+ISMAILI
+IST
+ISTANBUL
+IT
+ITAU
+ITV
+IVECO
+JAGUAR
+JAVA
+JCB
+JCP
+JE
+JEEP
+JETZT
+JEWELRY
+JIO
+JLL
+JM
+JMP
+JNJ
+JO
+JOBS
+JOBURG
+JOT
+JOY
+JP
+JPMORGAN
+JPRS
+JUEGOS
+JUNIPER
+KAUFEN
+KDDI
+KE
+KERRYHOTELS
+KERRYLOGISTICS
+KERRYPROPERTIES
+KFH
+KG
+KH
+KI
+KIA
+KIM
+KINDER
+KINDLE
+KITCHEN
+KIWI
+KM
+KN
+KOELN
+KOMATSU
+KOSHER
+KP
+KPMG
+KPN
+KR
+KRD
+KRED
+KUOKGROUP
+KW
+KY
+KYOTO
+KZ
+LA
+LACAIXA
+LADBROKES
+LAMBORGHINI
+LAMER
+LANCASTER
+LANCIA
+LANCOME
+LAND
+LANDROVER
+LANXESS
+LASALLE
+LAT
+LATINO
+LATROBE
+LAW
+LAWYER
+LB
+LC
+LDS
+LEASE
+LECLERC
+LEFRAK
+LEGAL
+LEGO
+LEXUS
+LGBT
+LI
+LIAISON
+LIDL
+LIFE
+LIFEINSURANCE
+LIFESTYLE
+LIGHTING
+LIKE
+LILLY
+LIMITED
+LIMO
+LINCOLN
+LINDE
+LINK
+LIPSY
+LIVE
+LIVING
+LIXIL
+LK
+LLC
+LOAN
+LOANS
+LOCKER
+LOCUS
+LOFT
+LOL
+LONDON
+LOTTE
+LOTTO
+LOVE
+LPL
+LPLFINANCIAL
+LR
+LS
+LT
+LTD
+LTDA
+LU
+LUNDBECK
+LUPIN
+LUXE
+LUXURY
+LV
+LY
+MA
+MACYS
+MADRID
+MAIF
+MAISON
+MAKEUP
+MAN
+MANAGEMENT
+MANGO
+MAP
+MARKET
+MARKETING
+MARKETS
+MARRIOTT
+MARSHALLS
+MASERATI
+MATTEL
+MBA
+MC
+MCKINSEY
+MD
+ME
+MED
+MEDIA
+MEET
+MELBOURNE
+MEME
+MEMORIAL
+MEN
+MENU
+MERCKMSD
+METLIFE
+MG
+MH
+MIAMI
+MICROSOFT
+MIL
+MINI
+MINT
+MIT
+MITSUBISHI
+MK
+ML
+MLB
+MLS
+MM
+MMA
+MN
+MO
+MOBI
+MOBILE
+MOBILY
+MODA
+MOE
+MOI
+MOM
+MONASH
+MONEY
+MONSTER
+MOPAR
+MORMON
+MORTGAGE
+MOSCOW
+MOTO
+MOTORCYCLES
+MOV
+MOVIE
+MOVISTAR
+MP
+MQ
+MR
+MS
+MSD
+MT
+MTN
+MTR
+MU
+MUSEUM
+MUTUAL
+MV
+MW
+MX
+MY
+MZ
+NA
+NAB
+NADEX
+NAGOYA
+NAME
+NATIONWIDE
+NATURA
+NAVY
+NBA
+NC
+NE
+NEC
+NET
+NETBANK
+NETFLIX
+NETWORK
+NEUSTAR
+NEW
+NEWHOLLAND
+NEWS
+NEXT
+NEXTDIRECT
+NEXUS
+NF
+NFL
+NG
+NGO
+NHK
+NI
+NICO
+NIKE
+NIKON
+NINJA
+NISSAN
+NISSAY
+NL
+NO
+NOKIA
+NORTHWESTERNMUTUAL
+NORTON
+NOW
+NOWRUZ
+NOWTV
+NP
+NR
+NRA
+NRW
+NTT
+NU
+NYC
+NZ
+OBI
+OBSERVER
+OFF
+OFFICE
+OKINAWA
+OLAYAN
+OLAYANGROUP
+OLDNAVY
+OLLO
+OM
+OMEGA
+ONE
+ONG
+ONL
+ONLINE
+ONYOURSIDE
+OOO
+OPEN
+ORACLE
+ORANGE
+ORG
+ORGANIC
+ORIGINS
+OSAKA
+OTSUKA
+OTT
+OVH
+PA
+PAGE
+PANASONIC
+PARIS
+PARS
+PARTNERS
+PARTS
+PARTY
+PASSAGENS
+PAY
+PCCW
+PE
+PET
+PF
+PFIZER
+PG
+PH
+PHARMACY
+PHD
+PHILIPS
+PHONE
+PHOTO
+PHOTOGRAPHY
+PHOTOS
+PHYSIO
+PIAGET
+PICS
+PICTET
+PICTURES
+PID
+PIN
+PING
+PINK
+PIONEER
+PIZZA
+PK
+PL
+PLACE
+PLAY
+PLAYSTATION
+PLUMBING
+PLUS
+PM
+PN
+PNC
+POHL
+POKER
+POLITIE
+PORN
+POST
+PR
+PRAMERICA
+PRAXI
+PRESS
+PRIME
+PRO
+PROD
+PRODUCTIONS
+PROF
+PROGRESSIVE
+PROMO
+PROPERTIES
+PROPERTY
+PROTECTION
+PRU
+PRUDENTIAL
+PS
+PT
+PUB
+PW
+PWC
+PY
+QA
+QPON
+QUEBEC
+QUEST
+QVC
+RACING
+RADIO
+RAID
+RE
+READ
+REALESTATE
+REALTOR
+REALTY
+RECIPES
+RED
+REDSTONE
+REDUMBRELLA
+REHAB
+REISE
+REISEN
+REIT
+RELIANCE
+REN
+RENT
+RENTALS
+REPAIR
+REPORT
+REPUBLICAN
+REST
+RESTAURANT
+REVIEW
+REVIEWS
+REXROTH
+RICH
+RICHARDLI
+RICOH
+RIGHTATHOME
+RIL
+RIO
+RIP
+RMIT
+RO
+ROCHER
+ROCKS
+RODEO
+ROGERS
+ROOM
+RS
+RSVP
+RU
+RUGBY
+RUHR
+RUN
+RW
+RWE
+RYUKYU
+SA
+SAARLAND
+SAFE
+SAFETY
+SAKURA
+SALE
+SALON
+SAMSCLUB
+SAMSUNG
+SANDVIK
+SANDVIKCOROMANT
+SANOFI
+SAP
+SARL
+SAS
+SAVE
+SAXO
+SB
+SBI
+SBS
+SC
+SCA
+SCB
+SCHAEFFLER
+SCHMIDT
+SCHOLARSHIPS
+SCHOOL
+SCHULE
+SCHWARZ
+SCIENCE
+SCJOHNSON
+SCOR
+SCOT
+SD
+SE
+SEARCH
+SEAT
+SECURE
+SECURITY
+SEEK
+SELECT
+SENER
+SERVICES
+SES
+SEVEN
+SEW
+SEX
+SEXY
+SFR
+SG
+SH
+SHANGRILA
+SHARP
+SHAW
+SHELL
+SHIA
+SHIKSHA
+SHOES
+SHOP
+SHOPPING
+SHOUJI
+SHOW
+SHOWTIME
+SHRIRAM
+SI
+SILK
+SINA
+SINGLES
+SITE
+SJ
+SK
+SKI
+SKIN
+SKY
+SKYPE
+SL
+SLING
+SM
+SMART
+SMILE
+SN
+SNCF
+SO
+SOCCER
+SOCIAL
+SOFTBANK
+SOFTWARE
+SOHU
+SOLAR
+SOLUTIONS
+SONG
+SONY
+SOY
+SPACE
+SPORT
+SPOT
+SPREADBETTING
+SR
+SRL
+SRT
+ST
+STADA
+STAPLES
+STAR
+STARHUB
+STATEBANK
+STATEFARM
+STC
+STCGROUP
+STOCKHOLM
+STORAGE
+STORE
+STREAM
+STUDIO
+STUDY
+STYLE
+SU
+SUCKS
+SUPPLIES
+SUPPLY
+SUPPORT
+SURF
+SURGERY
+SUZUKI
+SV
+SWATCH
+SWIFTCOVER
+SWISS
+SX
+SY
+SYDNEY
+SYMANTEC
+SYSTEMS
+SZ
+TAB
+TAIPEI
+TALK
+TAOBAO
+TARGET
+TATAMOTORS
+TATAR
+TATTOO
+TAX
+TAXI
+TC
+TCI
+TD
+TDK
+TEAM
+TECH
+TECHNOLOGY
+TEL
+TELEFONICA
+TEMASEK
+TENNIS
+TEVA
+TF
+TG
+TH
+THD
+THEATER
+THEATRE
+TIAA
+TICKETS
+TIENDA
+TIFFANY
+TIPS
+TIRES
+TIROL
+TJ
+TJMAXX
+TJX
+TK
+TKMAXX
+TL
+TM
+TMALL
+TN
+TO
+TODAY
+TOKYO
+TOOLS
+TOP
+TORAY
+TOSHIBA
+TOTAL
+TOURS
+TOWN
+TOYOTA
+TOYS
+TR
+TRADE
+TRADING
+TRAINING
+TRAVEL
+TRAVELCHANNEL
+TRAVELERS
+TRAVELERSINSURANCE
+TRUST
+TRV
+TT
+TUBE
+TUI
+TUNES
+TUSHU
+TV
+TVS
+TW
+TZ
+UA
+UBANK
+UBS
+UCONNECT
+UG
+UK
+UNICOM
+UNIVERSITY
+UNO
+UOL
+UPS
+US
+UY
+UZ
+VA
+VACATIONS
+VANA
+VANGUARD
+VC
+VE
+VEGAS
+VENTURES
+VERISIGN
+VERSICHERUNG
+VET
+VG
+VI
+VIAJES
+VIDEO
+VIG
+VIKING
+VILLAS
+VIN
+VIP
+VIRGIN
+VISA
+VISION
+VISTAPRINT
+VIVA
+VIVO
+VLAANDEREN
+VN
+VODKA
+VOLKSWAGEN
+VOLVO
+VOTE
+VOTING
+VOTO
+VOYAGE
+VU
+VUELOS
+WALES
+WALMART
+WALTER
+WANG
+WANGGOU
+WARMAN
+WATCH
+WATCHES
+WEATHER
+WEATHERCHANNEL
+WEBCAM
+WEBER
+WEBSITE
+WED
+WEDDING
+WEIBO
+WEIR
+WF
+WHOSWHO
+WIEN
+WIKI
+WILLIAMHILL
+WIN
+WINDOWS
+WINE
+WINNERS
+WME
+WOLTERSKLUWER
+WOODSIDE
+WORK
+WORKS
+WORLD
+WOW
+WS
+WTC
+WTF
+XBOX
+XEROX
+XFINITY
+XIHUAN
+XIN
+XN--11B4C3D
+XN--1CK2E1B
+XN--1QQW23A
+XN--2SCRJ9C
+XN--30RR7Y
+XN--3BST00M
+XN--3DS443G
+XN--3E0B707E
+XN--3HCRJ9C
+XN--3OQ18VL8PN36A
+XN--3PXU8K
+XN--42C2D9A
+XN--45BR5CYL
+XN--45BRJ9C
+XN--45Q11C
+XN--4GBRIM
+XN--54B7FTA0CC
+XN--55QW42G
+XN--55QX5D
+XN--5SU34J936BGSG
+XN--5TZM5G
+XN--6FRZ82G
+XN--6QQ986B3XL
+XN--80ADXHKS
+XN--80AO21A
+XN--80AQECDR1A
+XN--80ASEHDB
+XN--80ASWG
+XN--8Y0A063A
+XN--90A3AC
+XN--90AE
+XN--90AIS
+XN--9DBQ2A
+XN--9ET52U
+XN--9KRT00A
+XN--B4W605FERD
+XN--BCK1B9A5DRE4C
+XN--C1AVG
+XN--C2BR7G
+XN--CCK2B3B
+XN--CG4BKI
+XN--CLCHC0EA0B2G2A9GCD
+XN--CZR694B
+XN--CZRS0T
+XN--CZRU2D
+XN--D1ACJ3B
+XN--D1ALF
+XN--E1A4C
+XN--ECKVDTC9D
+XN--EFVY88H
+XN--ESTV75G
+XN--FCT429K
+XN--FHBEI
+XN--FIQ228C5HS
+XN--FIQ64B
+XN--FIQS8S
+XN--FIQZ9S
+XN--FJQ720A
+XN--FLW351E
+XN--FPCRJ9C3D
+XN--FZC2C9E2C
+XN--FZYS8D69UVGM
+XN--G2XX48C
+XN--GCKR3F0F
+XN--GECRJ9C
+XN--GK3AT1E
+XN--H2BREG3EVE
+XN--H2BRJ9C
+XN--H2BRJ9C8C
+XN--HXT814E
+XN--I1B6B1A6A2E
+XN--IMR513N
+XN--IO0A7I
+XN--J1AEF
+XN--J1AMH
+XN--J6W193G
+XN--JLQ61U9W7B
+XN--JVR189M
+XN--KCRX77D1X4A
+XN--KPRW13D
+XN--KPRY57D
+XN--KPU716F
+XN--KPUT3I
+XN--L1ACC
+XN--LGBBAT1AD8J
+XN--MGB9AWBF
+XN--MGBA3A3EJT
+XN--MGBA3A4F16A
+XN--MGBA7C0BBN0A
+XN--MGBAAKC7DVF
+XN--MGBAAM7A8H
+XN--MGBAB2BD
+XN--MGBAI9AZGQP6J
+XN--MGBAYH7GPA
+XN--MGBB9FBPOB
+XN--MGBBH1A
+XN--MGBBH1A71E
+XN--MGBC0A9AZCG
+XN--MGBCA7DZDO
+XN--MGBERP4A5D4AR
+XN--MGBGU82A
+XN--MGBI4ECEXP
+XN--MGBPL2FH
+XN--MGBT3DHD
+XN--MGBTX2B
+XN--MGBX4CD0AB
+XN--MIX891F
+XN--MK1BU44C
+XN--MXTQ1M
+XN--NGBC5AZD
+XN--NGBE9E0A
+XN--NGBRX
+XN--NODE
+XN--NQV7F
+XN--NQV7FS00EMA
+XN--NYQY26A
+XN--O3CW4H
+XN--OGBPF8FL
+XN--OTU796D
+XN--P1ACF
+XN--P1AI
+XN--PBT977C
+XN--PGBS0DH
+XN--PSSY2U
+XN--Q9JYB4C
+XN--QCKA1PMC
+XN--QXAM
+XN--RHQV96G
+XN--ROVU88B
+XN--RVC1E0AM3E
+XN--S9BRJ9C
+XN--SES554G
+XN--T60B56A
+XN--TCKWE
+XN--TIQ49XQYJ
+XN--UNUP4Y
+XN--VERMGENSBERATER-CTB
+XN--VERMGENSBERATUNG-PWB
+XN--VHQUV
+XN--VUQ861B
+XN--W4R85EL8FHU5DNRA
+XN--W4RS40L
+XN--WGBH1C
+XN--WGBL6A
+XN--XHQ521B
+XN--XKC2AL3HYE2A
+XN--XKC2DL3A5EE0H
+XN--Y9A3AQ
+XN--YFRO4I67O
+XN--YGBI2AMMX
+XN--ZFR164B
+XXX
+XYZ
+YACHTS
+YAHOO
+YAMAXUN
+YANDEX
+YE
+YODOBASHI
+YOGA
+YOKOHAMA
+YOU
+YOUTUBE
+YT
+YUN
+ZA
+ZAPPOS
+ZARA
+ZERO
+ZIP
+ZIPPO
+ZM
+ZONE
+ZUERICH
+ZW
diff --git a/library/cpp/tld/ut/ya.make b/library/cpp/tld/ut/ya.make
new file mode 100644
index 0000000000..0bc5b40b2f
--- /dev/null
+++ b/library/cpp/tld/ut/ya.make
@@ -0,0 +1,15 @@
+UNITTEST()
+
+OWNER(abolkhovityanov)
+
+PEERDIR(
+ ADDINCL library/cpp/tld
+)
+
+SRCDIR(library/cpp/tld)
+
+SRCS(
+ tld_ut.cpp
+)
+
+END()
diff --git a/library/cpp/tld/ya.make b/library/cpp/tld/ya.make
new file mode 100644
index 0000000000..aeabbfeebf
--- /dev/null
+++ b/library/cpp/tld/ya.make
@@ -0,0 +1,19 @@
+LIBRARY()
+
+OWNER(abolkhovityanov)
+
+PYTHON(
+ gen_tld.py tlds-alpha-by-domain.txt
+ IN tlds-alpha-by-domain.txt
+ STDOUT tld.inc
+)
+
+SRCS(
+ tld.cpp
+)
+
+PEERDIR(
+ library/cpp/digest/lower_case
+)
+
+END()
diff --git a/library/cpp/tvmauth/README.md b/library/cpp/tvmauth/README.md
new file mode 100644
index 0000000000..ec64bbbcdb
--- /dev/null
+++ b/library/cpp/tvmauth/README.md
@@ -0,0 +1,2 @@
+This part of library contains primitives for TVM operation.
+Please use high-level [TTvmClient](https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/tvmauth/client/README.md).
diff --git a/library/cpp/tvmauth/a.yaml b/library/cpp/tvmauth/a.yaml
new file mode 100644
index 0000000000..7f1e1b8fd8
--- /dev/null
+++ b/library/cpp/tvmauth/a.yaml
@@ -0,0 +1,23 @@
+service: passport_infra
+title: tvmauth (c++)
+
+ci:
+ release-title-source: flow
+ autocheck:
+ fast-targets:
+ - library/c/tvmauth
+ - library/cpp/tvmauth
+ - library/go/yandex/ticket_parser2
+ - library/java/ticket_parser2
+ - library/java/tvmauth
+ - library/python/deprecated/ticket_parser2
+ - library/python/tvmauth
+ - passport
+ strong: true
+
+arcanum:
+ auto_merge:
+ enabled: true
+ requirements:
+ - system: arcanum
+ type: comment_issues_closed
diff --git a/library/cpp/tvmauth/checked_service_ticket.h b/library/cpp/tvmauth/checked_service_ticket.h
new file mode 100644
index 0000000000..cf4c5c43e3
--- /dev/null
+++ b/library/cpp/tvmauth/checked_service_ticket.h
@@ -0,0 +1,71 @@
+#pragma once
+
+#include "ticket_status.h"
+#include "type.h"
+#include "utils.h"
+
+#include <util/generic/ptr.h>
+
+namespace NTvmAuth::NInternal {
+ class TCanningKnife;
+}
+
+namespace NTvmAuth {
+ class TCheckedServiceTicket {
+ public:
+ class TImpl;
+
+ TCheckedServiceTicket(THolder<TImpl> impl);
+ TCheckedServiceTicket(TCheckedServiceTicket&& o);
+ ~TCheckedServiceTicket();
+
+ TCheckedServiceTicket& operator=(TCheckedServiceTicket&&);
+
+ /*!
+ * @return True value if ticket parsed and checked successfully
+ */
+ explicit operator bool() const;
+
+ /*!
+ * You should check src with your ACL
+ * @return TvmId of request source
+ */
+ TTvmId GetSrc() const;
+
+ /*!
+ * @return Ticket check status
+ */
+ ETicketStatus GetStatus() const;
+
+ /*!
+ * DebugInfo is human readable data for debug purposes
+ * @return Serialized ticket
+ */
+ TString DebugInfo() const;
+
+ /*!
+ * IssuerUID is UID of developer who is debuging something,
+ * so he(she) issued ServiceTicket with his(her) ssh-sign:
+ * it is grant_type=sshkey in tvm-api.
+ * https://wiki.yandex-team.ru/passport/tvm2/debug/#sxoditvapizakrytoeserviceticketami
+ * @return uid
+ */
+ TMaybe<TUid> GetIssuerUid() const;
+
+ public: // for python binding
+ TCheckedServiceTicket() = default;
+
+ private:
+ THolder<TImpl> Impl_;
+ friend class NInternal::TCanningKnife;
+ };
+
+ namespace NBlackboxTvmId {
+ const TStringBuf Prod = "222";
+ const TStringBuf Test = "224";
+ const TStringBuf ProdYateam = "223";
+ const TStringBuf TestYateam = "225";
+ const TStringBuf Stress = "226";
+ const TStringBuf Mimino = "239";
+ }
+}
diff --git a/library/cpp/tvmauth/checked_user_ticket.h b/library/cpp/tvmauth/checked_user_ticket.h
new file mode 100644
index 0000000000..16a2a6dc30
--- /dev/null
+++ b/library/cpp/tvmauth/checked_user_ticket.h
@@ -0,0 +1,91 @@
+#pragma once
+
+#include "ticket_status.h"
+#include "type.h"
+#include "utils.h"
+
+#include <util/generic/ptr.h>
+
+namespace NTvmAuth::NInternal {
+ class TCanningKnife;
+}
+
+namespace NTvmAuth {
+ /*!
+ * BlackboxEnv describes environment of Passport:
+ * https://wiki.yandex-team.ru/passport/tvm2/user-ticket/#0-opredeljaemsjasokruzhenijami
+ */
+ enum class EBlackboxEnv: ui8 {
+ Prod,
+ Test,
+ ProdYateam,
+ TestYateam,
+ Stress
+ };
+
+ /*!
+ * UserTicket contains only valid users.
+ * Details: https://wiki.yandex-team.ru/passport/tvm2/user-ticket/#chtoestvusertickete
+ */
+ class TCheckedUserTicket {
+ public:
+ class TImpl;
+
+ TCheckedUserTicket(THolder<TImpl> impl);
+ TCheckedUserTicket(TCheckedUserTicket&&);
+ ~TCheckedUserTicket();
+
+ TCheckedUserTicket& operator=(TCheckedUserTicket&&);
+
+ /*!
+ * @return True value if ticket parsed and checked successfully
+ */
+ explicit operator bool() const;
+
+ /*!
+ * Never empty
+ * @return UIDs of users listed in ticket
+ */
+ const TUids& GetUids() const;
+
+ /*!
+ * Maybe 0
+ * @return Default user in ticket
+ */
+ TUid GetDefaultUid() const;
+
+ /*!
+ * Scopes inherited from credential - never empty
+ * @return Newly constructed vector of scopes
+ */
+ const TScopes& GetScopes() const;
+
+ /*!
+ * Check if scope presented in ticket
+ */
+ bool HasScope(TStringBuf scopeName) const;
+
+ /*!
+ * @return Ticket check status
+ */
+ ETicketStatus GetStatus() const;
+
+ /*!
+ * DebugInfo is human readable data for debug purposes
+ * @return Serialized ticket
+ */
+ TString DebugInfo() const;
+
+ /*!
+ * Env of user
+ */
+ EBlackboxEnv GetEnv() const;
+
+ public: // for python binding
+ TCheckedUserTicket() = default;
+
+ private:
+ THolder<TImpl> Impl_;
+ friend class NInternal::TCanningKnife;
+ };
+}
diff --git a/library/cpp/tvmauth/client/README.md b/library/cpp/tvmauth/client/README.md
new file mode 100644
index 0000000000..239f55de7a
--- /dev/null
+++ b/library/cpp/tvmauth/client/README.md
@@ -0,0 +1,56 @@
+Overview
+===
+This library provides ability to operate with TVM. Library is fast enough to get or check tickets for every request without burning CPU.
+
+[Home page of project](https://wiki.yandex-team.ru/passport/tvm2/)
+You can find some examples in [here](https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/tvmauth/client/examples).
+
+You can ask questions: [PASSPORTDUTY](https://st.yandex-team.ru/createTicket?queue=PASSPORTDUTY&_form=77618)
+
+TvmClient
+===
+Don't forget to collect logs from client.
+___
+`TvmClient` allowes:
+1. `GetServiceTicketFor()` - to fetch ServiceTicket for outgoing request
+2. `CheckServiceTicket()` - to check ServiceTicket from incoming request
+3. `CheckUserTicket()` - to check UserTicket from incoming request
+
+All methods are thread-safe.
+
+You should check status of `CheckedServiceTicket` or `CheckedUserTicket` for equality 'Ok'. You can get ticket fields (src/uids/scopes) only for correct ticket. Otherwise exception will be thrown.
+___
+You should check status of client with `GetStatus()`:
+* `OK` - nothing to do here
+* `Warning` - **you should trigger your monitoring alert**
+
+ Normal operation of TvmClient is still possible but there are problems with refreshing cache, so it is expiring.
+ Is tvm-api.yandex.net accessible?
+ Have you changed your TVM-secret or your backend (dst) deleted its TVM-client?
+
+* `Error` - **you should trigger your monitoring alert and close this instance for user-traffic**
+
+ TvmClient's cache is already invalid (expired) or soon will be: you can't check valid ServiceTicket or be authenticated by your backends (dsts)
+
+___
+Constructor creates system thread for refreshing cache - so do not fork your proccess after creating `TTvmClient` instance. Constructor leads to network I/O. Other methods always use memory.
+
+Exceptions maybe thrown from constructor:
+* `TRetriableException` - maybe some network trouble: you can try to create client one more time.
+* `TNonRetriableException` - settings are bad: fix them.
+___
+You can choose way for fetching data for your service operation:
+* http://localhost:{port}/tvm - recomended way
+* https://tvm-api.yandex.net
+
+TvmTool
+------------
+`TTvmClient` uses local http-interface to get state. This interface can be provided with tvmtool (local daemon) or Qloud/YP (local http api in container).
+See more: https://wiki.yandex-team.ru/passport/tvm2/tvm-daemon/.
+
+`TTvmClient` fetches configuration from tvmtool, so you need only to tell client how to connect to it and tell which alias of tvm id should be used for this `TvmClient` instance.
+
+TvmApi
+------------
+First of all: please use `SetDiskCacheDir()` - it provides reliability for your service and for tvm-api.
+Please check restrictions of this method.
diff --git a/library/cpp/tvmauth/client/client_status.cpp b/library/cpp/tvmauth/client/client_status.cpp
new file mode 100644
index 0000000000..eca35ba22b
--- /dev/null
+++ b/library/cpp/tvmauth/client/client_status.cpp
@@ -0,0 +1,6 @@
+#include "client_status.h"
+
+template <>
+void Out<NTvmAuth::TClientStatus>(IOutputStream& out, const NTvmAuth::TClientStatus& s) {
+ out << s.GetCode() << ": " << s.GetLastError();
+}
diff --git a/library/cpp/tvmauth/client/client_status.h b/library/cpp/tvmauth/client/client_status.h
new file mode 100644
index 0000000000..bbaf29d289
--- /dev/null
+++ b/library/cpp/tvmauth/client/client_status.h
@@ -0,0 +1,82 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/string/builder.h>
+
+namespace NTvmAuth {
+ class TClientStatus {
+ public:
+ enum ECode {
+ Ok,
+ Warning,
+ Error,
+ IncompleteTicketsSet,
+ };
+
+ TClientStatus(ECode state, TString&& lastError)
+ : Code_(state)
+ , LastError_(std::move(lastError))
+ {
+ }
+
+ TClientStatus() = default;
+ TClientStatus(const TClientStatus&) = default;
+ TClientStatus(TClientStatus&&) = default;
+
+ TClientStatus& operator=(const TClientStatus&) = default;
+ TClientStatus& operator=(TClientStatus&&) = default;
+
+ ECode GetCode() const {
+ return Code_;
+ }
+
+ const TString& GetLastError() const {
+ return LastError_;
+ }
+
+ TString CreateJugglerMessage() const {
+ return TStringBuilder() << GetJugglerCode() << ";TvmClient: " << LastError_ << "\n";
+ }
+
+ private:
+ int32_t GetJugglerCode() const {
+ switch (Code_) {
+ case ECode::Ok:
+ return 0; // OK juggler check state
+ case ECode::Warning:
+ case ECode::IncompleteTicketsSet:
+ return 1; // WARN juggler check state
+ case ECode::Error:
+ return 2; // CRIT juggler check state
+ }
+ return 2; // This should not happen, so set check state as CRIT.
+ }
+
+ ECode Code_ = Ok;
+ TString LastError_;
+ };
+
+ static inline bool operator==(const TClientStatus& l, const TClientStatus& r) noexcept {
+ return l.GetCode() == r.GetCode() && l.GetLastError() == r.GetLastError();
+ }
+
+ static inline bool operator==(const TClientStatus& l, const TClientStatus::ECode r) noexcept {
+ return l.GetCode() == r;
+ }
+
+ static inline bool operator==(const TClientStatus::ECode l, const TClientStatus& r) noexcept {
+ return r.GetCode() == l;
+ }
+
+ static inline bool operator!=(const TClientStatus& l, const TClientStatus& r) noexcept {
+ return !(l == r);
+ }
+
+ static inline bool operator!=(const TClientStatus& l, const TClientStatus::ECode r) noexcept {
+ return !(l == r);
+ }
+
+ static inline bool operator!=(const TClientStatus::ECode l, const TClientStatus& r) noexcept {
+ return !(l == r);
+ }
+}
diff --git a/library/cpp/tvmauth/client/examples/create_with_tvmapi/create.cpp b/library/cpp/tvmauth/client/examples/create_with_tvmapi/create.cpp
new file mode 100644
index 0000000000..c03a7a032f
--- /dev/null
+++ b/library/cpp/tvmauth/client/examples/create_with_tvmapi/create.cpp
@@ -0,0 +1,102 @@
+#include <library/cpp/tvmauth/client/facade.h>
+
+namespace NExample {
+ NTvmAuth::TTvmClient CreateClientForCheckingAllTicketsAndFetchingServiceTickets() {
+ NTvmAuth::NTvmApi::TClientSettings setts{
+ .DiskCacheDir = "/var/cache/my_service/tvm/",
+ .SelfTvmId = 11,
+ .Secret = (TStringBuf) "AAAAAAAAAAAAAAAAAAAAAA",
+ .FetchServiceTicketsForDstsWithAliases = {
+ {"bb", 224},
+ {"datasync", 2000060},
+ },
+ .CheckServiceTickets = true,
+ .CheckUserTicketsWithBbEnv = NTvmAuth::EBlackboxEnv::Test,
+ };
+
+ NTvmAuth::TLoggerPtr log = MakeIntrusive<NTvmAuth::TCerrLogger>(7);
+
+ NTvmAuth::TTvmClient c(setts, log);
+
+ // c.CheckServiceTicket("some service ticket")
+ // c.CheckUserTicket("some user ticket")
+ // c.GetServiceTicketFor("bb")
+ // c.GetServiceTicketFor(224)
+
+ return c;
+ }
+
+ NTvmAuth::TTvmClient CreateClientForCheckingAllTickets() {
+ NTvmAuth::NTvmApi::TClientSettings setts{
+ .DiskCacheDir = "/var/cache/my_service/tvm/",
+ .SelfTvmId = 11,
+ .CheckServiceTickets = true,
+ .CheckUserTicketsWithBbEnv = NTvmAuth::EBlackboxEnv::Test,
+ };
+
+ NTvmAuth::TLoggerPtr log = MakeIntrusive<NTvmAuth::TCerrLogger>(7);
+
+ NTvmAuth::TTvmClient c(setts, log);
+
+ // c.CheckServiceTicket("some service ticket")
+ // c.CheckUserTicket("some user ticket")
+
+ return c;
+ }
+
+ NTvmAuth::TTvmClient CreateClientForFetchingServiceTickets() {
+ NTvmAuth::NTvmApi::TClientSettings setts{
+ .DiskCacheDir = "/var/cache/my_service/tvm/",
+ .SelfTvmId = 11,
+ .Secret = (TStringBuf) "AAAAAAAAAAAAAAAAAAAAAA",
+ .FetchServiceTicketsForDstsWithAliases = {
+ {"bb", 224},
+ {"datasync", 2000060},
+ },
+ };
+
+ NTvmAuth::TLoggerPtr log = MakeIntrusive<NTvmAuth::TCerrLogger>(7);
+
+ NTvmAuth::TTvmClient c(setts, log);
+
+ // c.GetServiceTicketFor("bb")
+ // c.GetServiceTicketFor(224)
+
+ return c;
+ }
+
+ NTvmAuth::TTvmClient CreateClientForCheckingServiceTickets() {
+ NTvmAuth::NTvmApi::TClientSettings setts{
+ .DiskCacheDir = "/var/cache/my_service/tvm/",
+ .SelfTvmId = 11,
+ .CheckServiceTickets = true,
+ };
+
+ NTvmAuth::TLoggerPtr log = MakeIntrusive<NTvmAuth::TCerrLogger>(7);
+
+ NTvmAuth::TTvmClient c(setts, log);
+
+ // c.CheckServiceTicket("some service ticket")
+
+ return c;
+ }
+
+ NTvmAuth::TTvmClient CreateClientForCheckingServiceTicketsWithRoles() {
+ NTvmAuth::NTvmApi::TClientSettings setts{
+ .DiskCacheDir = "/var/cache/my_service/tvm/",
+ .SelfTvmId = 11,
+ .Secret = (TStringBuf) "AAAAAAAAAAAAAAAAAAAAAA",
+ .CheckServiceTickets = true,
+ .FetchRolesForIdmSystemSlug = "passporttestservice",
+ };
+
+ NTvmAuth::TLoggerPtr log = MakeIntrusive<NTvmAuth::TCerrLogger>(7);
+
+ NTvmAuth::TTvmClient c(setts, log);
+
+ // auto t = c.CheckServiceTicket("some service ticket")
+ // c.GetRoles()->CheckServiceRole(t, "some role");
+
+ return c;
+ }
+}
diff --git a/library/cpp/tvmauth/client/examples/create_with_tvmapi/ya.make b/library/cpp/tvmauth/client/examples/create_with_tvmapi/ya.make
new file mode 100644
index 0000000000..fc69a06dbd
--- /dev/null
+++ b/library/cpp/tvmauth/client/examples/create_with_tvmapi/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(g:passport_infra)
+
+PEERDIR(
+ library/cpp/tvmauth/client
+)
+
+SRCS(
+ create.cpp
+)
+
+END()
diff --git a/library/cpp/tvmauth/client/examples/create_with_tvmtool/create.cpp b/library/cpp/tvmauth/client/examples/create_with_tvmtool/create.cpp
new file mode 100644
index 0000000000..a87d3e705d
--- /dev/null
+++ b/library/cpp/tvmauth/client/examples/create_with_tvmtool/create.cpp
@@ -0,0 +1,34 @@
+#include <library/cpp/tvmauth/client/facade.h>
+
+namespace NExample {
+ // Possibility of using functions depends on config of tvmtool
+ // CheckServiceTicket
+ // CheckUserTicket
+ // GetServiceTicketFor
+
+ NTvmAuth::TTvmClient CreateClientInQloudOrYandexDeploy() {
+ NTvmAuth::NTvmTool::TClientSettings setts(
+ "my_service" // specified in Qloud/YP/tvmtool interface
+ );
+
+ NTvmAuth::TLoggerPtr log = MakeIntrusive<NTvmAuth::TCerrLogger>(7);
+
+ NTvmAuth::TTvmClient c(setts, log);
+
+ return c;
+ }
+
+ NTvmAuth::TTvmClient CreateClientForDevOrTests() {
+ NTvmAuth::NTvmTool::TClientSettings setts(
+ "my_service" // specified in Qloud/YP/tvmtool interface
+ );
+ setts.SetPort(18080);
+ setts.SetAuthToken("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+
+ NTvmAuth::TLoggerPtr log = MakeIntrusive<NTvmAuth::TCerrLogger>(7);
+
+ NTvmAuth::TTvmClient c(setts, log);
+
+ return c;
+ }
+}
diff --git a/library/cpp/tvmauth/client/examples/create_with_tvmtool/ya.make b/library/cpp/tvmauth/client/examples/create_with_tvmtool/ya.make
new file mode 100644
index 0000000000..fc69a06dbd
--- /dev/null
+++ b/library/cpp/tvmauth/client/examples/create_with_tvmtool/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(g:passport_infra)
+
+PEERDIR(
+ library/cpp/tvmauth/client
+)
+
+SRCS(
+ create.cpp
+)
+
+END()
diff --git a/library/cpp/tvmauth/client/examples/service_using_tvmtool_client/service.cpp b/library/cpp/tvmauth/client/examples/service_using_tvmtool_client/service.cpp
new file mode 100644
index 0000000000..075bf0bded
--- /dev/null
+++ b/library/cpp/tvmauth/client/examples/service_using_tvmtool_client/service.cpp
@@ -0,0 +1,84 @@
+#include "service.h"
+
+#include <library/cpp/tvmauth/client/facade.h>
+
+#include <library/cpp/cgiparam/cgiparam.h>
+#include <library/cpp/http/server/response.h>
+#include <library/cpp/http/simple/http_client.h>
+#include <library/cpp/json/json_reader.h>
+
+namespace NExample {
+ static const TString BACK_C = "BACK_C";
+
+ TSomeService::TSomeService(const TConfig& cfg)
+ : Config_(cfg)
+ {
+ NTvmAuth::TLoggerPtr log = MakeIntrusive<NTvmAuth::TCerrLogger>(7);
+
+ Tvm_ = MakeHolder<NTvmAuth::TTvmClient>(
+ NTvmAuth::NTvmTool::TClientSettings(
+ "my_service" // specified in Qloud/YP/tvmtool interface
+ ),
+ log);
+ }
+
+ TSomeService::~TSomeService() {
+ }
+
+ void TSomeService::HandleRequest(THttpInput& in, THttpOutput& out) {
+ auto servIt = std::find_if(in.Headers().Begin(),
+ in.Headers().End(),
+ [](const auto& h) { return h.Name() == "X-Ya-Service-Ticket"; });
+ auto userIt = std::find_if(in.Headers().Begin(),
+ in.Headers().End(),
+ [](const auto& h) { return h.Name() == "X-Ya-User-Ticket"; });
+ try {
+ if (servIt == in.Headers().End() || userIt == in.Headers().End()) {
+ ythrow yexception() << "Need tickets";
+ }
+
+ // WARNING: См. Здесь
+ NTvmAuth::TCheckedServiceTicket st = Tvm_->CheckServiceTicket(servIt->Value());
+ NTvmAuth::TCheckedUserTicket ut = Tvm_->CheckUserTicket(userIt->Value());
+ if (!st || !ut) {
+ ythrow yexception() << "Invalid tickets";
+ }
+
+ // WARNING: См. Здесь
+ // Ждём ABC - после их релиза эти три строки можно будет удалить
+ if (Config_.AllowedTvmIds.find(st.GetSrc()) == Config_.AllowedTvmIds.end()) {
+ ythrow yexception() << "Consumer is not allowed";
+ }
+
+ // WARNING: См. Здесь
+ if (!ut.HasScope("some_service:allow_secret_data")) {
+ ythrow yexception() << "UserTicket does not have scopes for secret data";
+ }
+
+ // Access-log
+ Cout << "Data fetched for: " << ut.GetDefaultUid() << Endl;
+
+ THttpResponse resp(HTTP_OK);
+ resp.SetContent(GetDataFromBackendC(userIt->Value()), "text/plain");
+ resp.OutTo(out);
+ } catch (...) {
+ THttpResponse resp(HTTP_BAD_REQUEST);
+ resp.SetContent("Request can not be performed", "text/plain");
+ resp.OutTo(out);
+ }
+
+ out.Finish();
+ }
+
+ TString TSomeService::GetDataFromBackendC(const TString& userTicket) {
+ TSimpleHttpClient cl("my_backend", // specified in Qloud/YP/tvmtool interface
+ 80);
+ TStringStream s;
+ cl.DoGet("/api?",
+ &s,
+ // WARNING: См. Здесь
+ {{"X-Ya-Service-Ticket", Tvm_->GetServiceTicketFor(BACK_C)},
+ {"X-Ya-User-Ticket", userTicket}});
+ return s.Str();
+ }
+}
diff --git a/library/cpp/tvmauth/client/examples/service_using_tvmtool_client/service.h b/library/cpp/tvmauth/client/examples/service_using_tvmtool_client/service.h
new file mode 100644
index 0000000000..8ff948334e
--- /dev/null
+++ b/library/cpp/tvmauth/client/examples/service_using_tvmtool_client/service.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <library/cpp/http/io/stream.h>
+
+#include <util/generic/ptr.h>
+
+#include <unordered_set>
+
+namespace NTvmAuth {
+ class TTvmClient;
+}
+
+namespace NExample {
+ struct TConfig {
+ using TAllowedTvmIds = std::unordered_set<ui32>;
+
+ TAllowedTvmIds AllowedTvmIds;
+ };
+
+ class TSomeService {
+ public:
+ TSomeService(const TConfig& cfg);
+ ~TSomeService();
+
+ void HandleRequest(THttpInput& in, THttpOutput& out);
+
+ private:
+ TString GetDataFromBackendC(const TString& userTicket);
+
+ private:
+ // WARNING: См. Здесь
+ TConfig Config_;
+ THolder<NTvmAuth::TTvmClient> Tvm_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/examples/service_using_tvmtool_client/ya.make b/library/cpp/tvmauth/client/examples/service_using_tvmtool_client/ya.make
new file mode 100644
index 0000000000..dde9e7a00d
--- /dev/null
+++ b/library/cpp/tvmauth/client/examples/service_using_tvmtool_client/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(g:passport_infra)
+
+PEERDIR(
+ library/cpp/cgiparam
+ library/cpp/http/simple
+ library/cpp/tvmauth/client
+)
+
+SRCS(
+ service.cpp
+)
+
+END()
diff --git a/library/cpp/tvmauth/client/examples/ya.make b/library/cpp/tvmauth/client/examples/ya.make
new file mode 100644
index 0000000000..cd17e550a6
--- /dev/null
+++ b/library/cpp/tvmauth/client/examples/ya.make
@@ -0,0 +1,5 @@
+RECURSE(
+ create_with_tvmapi
+ create_with_tvmtool
+ service_using_tvmtool_client
+)
diff --git a/library/cpp/tvmauth/client/exception.h b/library/cpp/tvmauth/client/exception.h
new file mode 100644
index 0000000000..7639467671
--- /dev/null
+++ b/library/cpp/tvmauth/client/exception.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <library/cpp/tvmauth/exception.h>
+
+namespace NTvmAuth {
+ class TClientException: public TTvmException {
+ };
+
+ class TRetriableException: public TClientException {
+ };
+ class TNonRetriableException: public TClientException {
+ };
+
+ class TIllegalUsage: public TNonRetriableException {
+ };
+
+ class TBrokenTvmClientSettings: public TIllegalUsage {
+ };
+ class TMissingServiceTicket: public TNonRetriableException {
+ };
+ class TPermissionDenied: public TNonRetriableException {
+ };
+}
diff --git a/library/cpp/tvmauth/client/facade.cpp b/library/cpp/tvmauth/client/facade.cpp
new file mode 100644
index 0000000000..6e77569441
--- /dev/null
+++ b/library/cpp/tvmauth/client/facade.cpp
@@ -0,0 +1,131 @@
+#include "facade.h"
+
+#include "misc/checker.h"
+#include "misc/default_uid_checker.h"
+#include "misc/getter.h"
+#include "misc/src_checker.h"
+#include "misc/api/threaded_updater.h"
+#include "misc/tool/threaded_updater.h"
+
+namespace NTvmAuth {
+ TTvmClient::TTvmClient(const NTvmTool::TClientSettings& settings, TLoggerPtr logger)
+ : Updater_(NTvmTool::TThreadedUpdater::Create(settings, std::move(logger)))
+ , Service_(MakeHolder<TServiceTicketChecker>(Updater_))
+ , User_(MakeHolder<TUserTicketChecker>(Updater_))
+ {
+ if (Updater_->GetCachedServiceTickets()) {
+ Tickets_ = MakeHolder<TServiceTicketGetter>(Updater_);
+ }
+ }
+
+ TTvmClient::TTvmClient(const NTvmApi::TClientSettings& settings, TLoggerPtr logger)
+ : Updater_(NTvmApi::TThreadedUpdater::Create(settings, std::move(logger)))
+ {
+ if (settings.IsServiceTicketFetchingRequired()) {
+ Tickets_ = MakeHolder<TServiceTicketGetter>(Updater_);
+ }
+ if (settings.IsServiceTicketCheckingRequired()) {
+ Service_ = MakeHolder<TServiceTicketChecker>(Updater_);
+ }
+ if (settings.IsUserTicketCheckingRequired()) {
+ User_ = MakeHolder<TUserTicketChecker>(Updater_);
+ }
+ if (settings.IsRolesFetchingEnabled() && settings.ShouldCheckSrc) {
+ SrcChecker_ = MakeHolder<TSrcChecker>(Updater_);
+ }
+ if (settings.IsRolesFetchingEnabled() && settings.ShouldCheckDefaultUid) {
+ DefaultUidChecker_ = MakeHolder<TDefaultUidChecker>(Updater_);
+ }
+ }
+
+ TTvmClient::TTvmClient(TAsyncUpdaterPtr updater)
+ : Updater_(std::move(updater))
+ {
+ if (Updater_->GetCachedServiceTickets()) {
+ Tickets_ = MakeHolder<TServiceTicketGetter>(Updater_);
+ }
+ if (Updater_->GetCachedServiceContext()) {
+ Service_ = MakeHolder<TServiceTicketChecker>(Updater_);
+ }
+ if (Updater_->GetCachedUserContext()) {
+ User_ = MakeHolder<TUserTicketChecker>(Updater_);
+ }
+
+ try {
+ if (Updater_->GetRoles()) {
+ SrcChecker_ = MakeHolder<TSrcChecker>(Updater_);
+ DefaultUidChecker_ = MakeHolder<TDefaultUidChecker>(Updater_);
+ }
+ } catch (const TIllegalUsage&) {
+ // it is a test probably
+ }
+ }
+
+ TTvmClient::TTvmClient(TTvmClient&& o) = default;
+ TTvmClient::~TTvmClient() = default;
+ TTvmClient& TTvmClient::operator=(TTvmClient&& o) = default;
+
+ TClientStatus TTvmClient::GetStatus() const {
+ Y_ENSURE(Updater_);
+ return Updater_->GetStatus();
+ }
+
+ TInstant TTvmClient::GetUpdateTimeOfPublicKeys() const {
+ Y_ENSURE(Updater_);
+ return Updater_->GetUpdateTimeOfPublicKeys();
+ }
+
+ TInstant TTvmClient::GetUpdateTimeOfServiceTickets() const {
+ Y_ENSURE(Updater_);
+ return Updater_->GetUpdateTimeOfServiceTickets();
+ }
+
+ TInstant TTvmClient::GetInvalidationTimeOfPublicKeys() const {
+ Y_ENSURE(Updater_);
+ return Updater_->GetInvalidationTimeOfPublicKeys();
+ }
+
+ TInstant TTvmClient::GetInvalidationTimeOfServiceTickets() const {
+ Y_ENSURE(Updater_);
+ return Updater_->GetInvalidationTimeOfServiceTickets();
+ }
+
+ TString TTvmClient::GetServiceTicketFor(const TClientSettings::TAlias& dst) const {
+ Y_ENSURE_EX(Tickets_, TBrokenTvmClientSettings()
+ << "Need to enable ServiceTickets fetching");
+ return Tickets_->GetTicket(dst);
+ }
+
+ TString TTvmClient::GetServiceTicketFor(const TTvmId dst) const {
+ Y_ENSURE_EX(Tickets_, TBrokenTvmClientSettings()
+ << "Need to enable ServiceTickets fetching");
+ return Tickets_->GetTicket(dst);
+ }
+
+ TCheckedServiceTicket TTvmClient::CheckServiceTicket(TStringBuf ticket) const {
+ Y_ENSURE_EX(Service_, TBrokenTvmClientSettings()
+ << "Need to use TClientSettings::EnableServiceTicketChecking()");
+
+ TCheckedServiceTicket res = Service_->Check(ticket);
+ if (SrcChecker_ && res) {
+ return SrcChecker_->Check(std::move(res));
+ }
+ return res;
+ }
+
+ TCheckedUserTicket TTvmClient::CheckUserTicket(TStringBuf ticket, TMaybe<EBlackboxEnv> overrideEnv) const {
+ Y_ENSURE_EX(User_, TBrokenTvmClientSettings()
+ << "Need to use TClientSettings::EnableUserTicketChecking()");
+
+ TCheckedUserTicket res = User_->Check(ticket, overrideEnv);
+ if (DefaultUidChecker_ && res) {
+ return DefaultUidChecker_->Check(std::move(res));
+ }
+ return User_->Check(ticket, overrideEnv);
+ }
+
+ NRoles::TRolesPtr TTvmClient::GetRoles() const {
+ Y_ENSURE(Updater_);
+ return Updater_->GetRoles();
+ }
+}
diff --git a/library/cpp/tvmauth/client/facade.h b/library/cpp/tvmauth/client/facade.h
new file mode 100644
index 0000000000..34d4b11a00
--- /dev/null
+++ b/library/cpp/tvmauth/client/facade.h
@@ -0,0 +1,119 @@
+#pragma once
+
+#include "misc/async_updater.h"
+#include "misc/api/settings.h"
+#include "misc/tool/settings.h"
+
+#include <library/cpp/tvmauth/checked_service_ticket.h>
+#include <library/cpp/tvmauth/checked_user_ticket.h>
+
+namespace NTvmAuth::NInternal {
+ class TClientCaningKnife;
+}
+
+namespace NTvmAuth {
+ class TDefaultUidChecker;
+ class TServiceTicketGetter;
+ class TServiceTicketChecker;
+ class TSrcChecker;
+ class TUserTicketChecker;
+
+ /*!
+ * Long lived thread-safe object for interacting with TVM.
+ * In 99% cases TvmClient shoud be created at service startup and live for the whole process lifetime.
+ */
+ class TTvmClient {
+ public:
+ /*!
+ * Uses local http-interface to get state: http://localhost/tvm/.
+ * This interface can be provided with tvmtool (local daemon) or Qloud/YP (local http api in container).
+ * See more: https://wiki.yandex-team.ru/passport/tvm2/tvm-daemon/.
+ *
+ * Starts thread for updating of in-memory cache in background
+ * @param settings
+ * @param logger is usefull for monitoring and debuging
+ */
+ TTvmClient(const NTvmTool::TClientSettings& settings, TLoggerPtr logger);
+
+ /*!
+ * Uses general way to get state: https://tvm-api.yandex.net.
+ * It is not recomended for Qloud/YP.
+ *
+ * Starts thread for updating of in-memory cache in background
+ * Reads cache from disk if specified
+ * @param settings
+ * @param logger is usefull for monitoring and debuging
+ */
+ TTvmClient(const NTvmApi::TClientSettings& settings, TLoggerPtr logger);
+
+ /*!
+ * Feel free to use custom updating logic in tests
+ */
+ TTvmClient(TAsyncUpdaterPtr updater);
+
+ TTvmClient(TTvmClient&&);
+ ~TTvmClient();
+ TTvmClient& operator=(TTvmClient&&);
+
+ /*!
+ * You should trigger your monitoring if status is not Ok.
+ * It will be unable to operate if status is Error.
+ * Description: https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/tvmauth/client/README.md#high-level-interface
+ * @return Current status of client.
+ */
+ TClientStatus GetStatus() const;
+
+ /*!
+ * Some tools for monitoring
+ */
+
+ TInstant GetUpdateTimeOfPublicKeys() const;
+ TInstant GetUpdateTimeOfServiceTickets() const;
+ TInstant GetInvalidationTimeOfPublicKeys() const;
+ TInstant GetInvalidationTimeOfServiceTickets() const;
+
+ /*!
+ * Requires fetchinig options (from TClientSettings or Qloud/YP/tvmtool settings)
+ * Can throw exception if cache is invalid or wrong config
+ *
+ * Alias is local label for TvmID
+ * which can be used to avoid this number in every checking case in code.
+ * @param dst
+ */
+ TString GetServiceTicketFor(const TClientSettings::TAlias& dst) const;
+ TString GetServiceTicketFor(const TTvmId dst) const;
+
+ /*!
+ * For TTvmApi::TClientSettings: checking must be enabled in TClientSettings
+ * Can throw exception if checking was not enabled in settings
+ *
+ * ServiceTicket contains src: you should check it by yourself with ACL
+ * @param ticket
+ */
+ TCheckedServiceTicket CheckServiceTicket(TStringBuf ticket) const;
+
+ /*!
+ * Requires blackbox enviroment (from TClientSettings or Qloud/YP/tvmtool settings)
+ * Can throw exception if checking was not enabled in settings
+ * @param ticket
+ * @param overrideEnv allowes you to override env from settings
+ */
+ TCheckedUserTicket CheckUserTicket(TStringBuf ticket, TMaybe<EBlackboxEnv> overrideEnv = {}) const;
+
+ /*!
+ * Under construction now. It is unusable.
+ * PASSP-30283
+ */
+ NRoles::TRolesPtr GetRoles() const;
+
+ private:
+ TAsyncUpdaterPtr Updater_;
+ THolder<TServiceTicketGetter> Tickets_;
+ THolder<TServiceTicketChecker> Service_;
+ THolder<TUserTicketChecker> User_;
+ THolder<TSrcChecker> SrcChecker_;
+ THolder<TDefaultUidChecker> DefaultUidChecker_;
+
+ friend class NInternal::TClientCaningKnife;
+ };
+}
diff --git a/library/cpp/tvmauth/client/logger.cpp b/library/cpp/tvmauth/client/logger.cpp
new file mode 100644
index 0000000000..bd63773cdf
--- /dev/null
+++ b/library/cpp/tvmauth/client/logger.cpp
@@ -0,0 +1,12 @@
+#include "logger.h"
+
+#include <util/datetime/base.h>
+#include <util/generic/string.h>
+
+namespace NTvmAuth {
+ void TCerrLogger::Log(int lvl, const TString& msg) {
+ if (lvl > Level_)
+ return;
+ Cerr << TInstant::Now().ToStringLocal() << " lvl=" << lvl << " msg: " << msg << "\n";
+ }
+}
diff --git a/library/cpp/tvmauth/client/logger.h b/library/cpp/tvmauth/client/logger.h
new file mode 100644
index 0000000000..6f3718a2aa
--- /dev/null
+++ b/library/cpp/tvmauth/client/logger.h
@@ -0,0 +1,59 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+
+namespace NTvmAuth {
+ class ILogger: public TAtomicRefCount<ILogger> {
+ public:
+ virtual ~ILogger() = default;
+
+ void Debug(const TString& msg) {
+ Log(7, msg);
+ }
+
+ void Info(const TString& msg) {
+ Log(6, msg);
+ }
+
+ void Warning(const TString& msg) {
+ Log(4, msg);
+ }
+
+ void Error(const TString& msg) {
+ Log(3, msg);
+ }
+
+ protected:
+ /*!
+ * Log event
+ * @param lvl is syslog level: 0(Emergency) ... 7(Debug)
+ * @param msg
+ */
+ virtual void Log(int lvl, const TString& msg) = 0;
+ };
+
+ class TCerrLogger: public ILogger {
+ public:
+ TCerrLogger(int level)
+ : Level_(level)
+ {
+ }
+
+ void Log(int lvl, const TString& msg) override;
+
+ private:
+ const int Level_;
+ };
+
+ using TLoggerPtr = TIntrusivePtr<ILogger>;
+
+ class TDevNullLogger: public ILogger {
+ public:
+ static TLoggerPtr IAmBrave() {
+ return MakeIntrusive<TDevNullLogger>();
+ }
+
+ void Log(int, const TString&) override {
+ }
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/api/dynamic_dst/tvm_client.cpp b/library/cpp/tvmauth/client/misc/api/dynamic_dst/tvm_client.cpp
new file mode 100644
index 0000000000..6ec15c0e88
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/api/dynamic_dst/tvm_client.cpp
@@ -0,0 +1,126 @@
+#include "tvm_client.h"
+
+#include <util/string/builder.h>
+
+namespace NTvmAuth::NDynamicClient {
+ TAsyncUpdaterPtr TTvmClient::Create(const NTvmApi::TClientSettings& settings, TLoggerPtr logger) {
+ Y_ENSURE_EX(logger, TNonRetriableException() << "Logger is required");
+ THolder<TTvmClient> p(new TTvmClient(settings, std::move(logger)));
+ p->Init();
+ p->StartWorker();
+ return p.Release();
+ }
+
+ NThreading::TFuture<TAddResponse> TTvmClient::Add(TDsts&& dsts) {
+ if (dsts.empty()) {
+ LogDebug("Adding dst: got empty task");
+ return NThreading::MakeFuture<TAddResponse>(TAddResponse{});
+ }
+
+ const size_t size = dsts.size();
+ const ui64 id = ++TaskIds_;
+ NThreading::TPromise<TAddResponse> promise = NThreading::NewPromise<TAddResponse>();
+
+ TaskQueue_.Enqueue(TTask{id, promise, std::move(dsts)});
+
+ LogDebug(TStringBuilder() << "Adding dst: got task #" << id << " with " << size << " dsts");
+ return promise.GetFuture();
+ }
+
+ std::optional<TString> TTvmClient::GetOptionalServiceTicketFor(const TTvmId dst) {
+ TServiceTicketsPtr tickets = GetCachedServiceTickets();
+ Y_ENSURE_EX(tickets,
+ TBrokenTvmClientSettings()
+ << "Need to enable fetching of service tickets in settings");
+
+ auto it = tickets->TicketsById.find(dst);
+ if (it != tickets->TicketsById.end()) {
+ return it->second;
+ }
+
+ it = tickets->ErrorsById.find(dst);
+ if (it != tickets->ErrorsById.end()) {
+ ythrow TMissingServiceTicket()
+ << "Failed to get ticket for '" << dst << "': "
+ << it->second;
+ }
+
+ return {};
+ }
+
+ TTvmClient::TTvmClient(const NTvmApi::TClientSettings& settings, TLoggerPtr logger)
+ : TBase(settings, logger)
+ {
+ }
+
+ TTvmClient::~TTvmClient() {
+ TBase::StopWorker();
+ }
+
+ void TTvmClient::Worker() {
+ TBase::Worker();
+ ProcessTasks();
+ }
+
+ void TTvmClient::ProcessTasks() {
+ TaskQueue_.DequeueAll(&Tasks_);
+ if (Tasks_.empty()) {
+ return;
+ }
+
+ TDsts required;
+ for (const TTask& task : Tasks_) {
+ for (const auto& dst : task.Dsts) {
+ required.insert(dst);
+ }
+ }
+
+ TServiceTicketsPtr cache = UpdateMissingServiceTickets(required);
+
+ for (TTask& task : Tasks_) {
+ try {
+ SetResponseForTask(task, *cache);
+ } catch (const std::exception& e) {
+ LogError(TStringBuilder()
+ << "Adding dst: task #" << task.Id << ": exception: " << e.what());
+ } catch (...) {
+ LogError(TStringBuilder()
+ << "Adding dst: task #" << task.Id << ": exception: " << CurrentExceptionMessage());
+ }
+ }
+
+ Tasks_.clear();
+ }
+
+ static const TString UNKNOWN = "Unknown reason";
+ void TTvmClient::SetResponseForTask(TTvmClient::TTask& task, const TServiceTickets& cache) {
+ if (task.Promise.HasValue()) {
+ LogWarning(TStringBuilder() << "Adding dst: task #" << task.Id << " already has value");
+ return;
+ }
+
+ TAddResponse response;
+
+ for (const auto& dst : task.Dsts) {
+ if (cache.TicketsById.contains(dst.Id)) {
+ AddDstToSettings(dst);
+ response.emplace(dst, TDstResponse{EDstStatus::Success, TString()});
+
+ LogDebug(TStringBuilder() << "Adding dst: task #" << task.Id
+ << ": dst=" << dst.Id << " got ticket");
+ continue;
+ }
+
+ auto it = cache.ErrorsById.find(dst.Id);
+ const TString& error = it == cache.ErrorsById.end() ? UNKNOWN : it->second;
+ response.emplace(dst, TDstResponse{EDstStatus::Fail, error});
+
+ LogWarning(TStringBuilder() << "Adding dst: task #" << task.Id
+ << ": dst=" << dst.Id
+ << " failed to get ticket: " << error);
+ }
+
+ LogDebug(TStringBuilder() << "Adding dst: task #" << task.Id << ": set value");
+ task.Promise.SetValue(std::move(response));
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/api/dynamic_dst/tvm_client.h b/library/cpp/tvmauth/client/misc/api/dynamic_dst/tvm_client.h
new file mode 100644
index 0000000000..58ed953b63
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/api/dynamic_dst/tvm_client.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include <library/cpp/tvmauth/client/misc/api/threaded_updater.h>
+
+#include <library/cpp/threading/future/future.h>
+
+#include <util/generic/map.h>
+#include <util/thread/lfqueue.h>
+
+#include <optional>
+
+namespace NTvmAuth::NDynamicClient {
+ enum class EDstStatus {
+ Success,
+ Fail,
+ };
+
+ struct TDstResponse {
+ EDstStatus Status = EDstStatus::Fail;
+ TString Error;
+
+ bool operator==(const TDstResponse& o) const {
+ return Status == o.Status && Error == o.Error;
+ }
+ };
+
+ using TDsts = NTvmApi::TDstSet;
+ using TAddResponse = TMap<NTvmApi::TClientSettings::TDst, TDstResponse>;
+
+ class TTvmClient: public NTvmApi::TThreadedUpdater {
+ public:
+ static TAsyncUpdaterPtr Create(const NTvmApi::TClientSettings& settings, TLoggerPtr logger);
+ virtual ~TTvmClient();
+
+ NThreading::TFuture<TAddResponse> Add(TDsts&& dsts);
+ std::optional<TString> GetOptionalServiceTicketFor(const TTvmId dst);
+
+ protected: // for tests
+ struct TTask {
+ ui64 Id = 0;
+ NThreading::TPromise<TAddResponse> Promise;
+ TDsts Dsts;
+ };
+
+ using TBase = NTvmApi::TThreadedUpdater;
+
+ protected: // for tests
+ TTvmClient(const NTvmApi::TClientSettings& settings, TLoggerPtr logger);
+
+ void Worker() override;
+ void ProcessTasks();
+
+ void SetResponseForTask(TTask& task, const TServiceTickets& cache);
+
+ private:
+ std::atomic<ui64> TaskIds_ = {0};
+ TLockFreeQueue<TTask> TaskQueue_;
+ TVector<TTask> Tasks_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/api/dynamic_dst/ut/tvm_client_ut.cpp b/library/cpp/tvmauth/client/misc/api/dynamic_dst/ut/tvm_client_ut.cpp
new file mode 100644
index 0000000000..89403c15e4
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/api/dynamic_dst/ut/tvm_client_ut.cpp
@@ -0,0 +1,635 @@
+#include <library/cpp/tvmauth/client/misc/api/dynamic_dst/tvm_client.h>
+
+#include <library/cpp/tvmauth/client/misc/disk_cache.h>
+
+#include <library/cpp/tvmauth/unittest.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/file.h>
+#include <util/system/fs.h>
+
+#include <regex>
+
+using namespace NTvmAuth;
+using namespace NTvmAuth::NDynamicClient;
+
+Y_UNIT_TEST_SUITE(DynamicClient) {
+ static const std::regex TIME_REGEX(R"(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d.\d{6}Z)");
+ static const TString CACHE_DIR = "./tmp/";
+
+ static void WriteFile(TString name, TStringBuf body, TInstant time) {
+ NFs::Remove(CACHE_DIR + name);
+ TFileOutput f(CACHE_DIR + name);
+ f << TDiskWriter::PrepareData(time, body);
+ }
+
+ static void CleanCache() {
+ NFs::RemoveRecursive(CACHE_DIR);
+ NFs::MakeDirectoryRecursive(CACHE_DIR);
+ }
+
+ class TLogger: public NTvmAuth::ILogger {
+ public:
+ void Log(int lvl, const TString& msg) override {
+ Cout << TInstant::Now() << " lvl=" << lvl << " msg: " << msg << "\n";
+ Stream << lvl << ": " << msg << Endl;
+ }
+
+ TStringStream Stream;
+ };
+
+ class TOfflineUpdater: public NDynamicClient::TTvmClient {
+ public:
+ TOfflineUpdater(const NTvmApi::TClientSettings& settings,
+ TIntrusivePtr<TLogger> l,
+ bool fail = true,
+ std::vector<TString> tickets = {})
+ : TTvmClient(settings, l)
+ , Fail(fail)
+ , Tickets(std::move(tickets))
+ {
+ Init();
+ ExpBackoff_.SetEnabled(false);
+ }
+
+ NUtils::TFetchResult FetchServiceTicketsFromHttp(const TString& req) const override {
+ if (Fail) {
+ throw yexception() << "tickets: alarm";
+ }
+
+ TString response;
+ if (!Tickets.empty()) {
+ response = Tickets.front();
+ Tickets.erase(Tickets.begin());
+ }
+
+ Cout << "*** FetchServiceTicketsFromHttp. request: " << req << ". response: " << response << Endl;
+ return {200, {}, "/2/ticket", response, ""};
+ }
+
+ NUtils::TFetchResult FetchPublicKeysFromHttp() const override {
+ if (Fail) {
+ throw yexception() << "keysalarm";
+ }
+ Cout << "*** FetchPublicKeysFromHttp" << Endl;
+ return {200, {}, "/2/keys", PublicKeys, ""};
+ }
+
+ using TTvmClient::GetDsts;
+ using TTvmClient::ProcessTasks;
+ using TTvmClient::SetResponseForTask;
+ using TTvmClient::Worker;
+
+ bool Fail = true;
+ TString PublicKeys = NUnittest::TVMKNIFE_PUBLIC_KEYS;
+ mutable std::vector<TString> Tickets;
+ };
+
+ Y_UNIT_TEST(StartWithIncompleteTicketsSet) {
+ TInstant now = TInstant::Now();
+ CleanCache();
+ WriteFile("./service_tickets",
+ R"({"19" : { "ticket" : "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"}})"
+ "\t100500",
+ now);
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}, {"kolmo", 213}}, false);
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+
+ {
+ TOfflineUpdater client(s,
+ l,
+ false,
+ {
+ R"({"213" : { "error" : "some error"}})",
+ R"({"123" : { "ticket" : "service_ticket_3"}})",
+ });
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::IncompleteTicketsSet, client.GetStatus());
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(19));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->TicketsById.contains(213));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(19));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->ErrorsById.contains(213));
+
+ NThreading::TFuture<TAddResponse> fut = client.Add({123});
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::IncompleteTicketsSet, client.GetStatus());
+
+ client.Worker();
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::IncompleteTicketsSet, client.GetStatus());
+
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(19));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->TicketsById.contains(213));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(123));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(19));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->ErrorsById.contains(213));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(123));
+
+ UNIT_ASSERT(fut.HasValue());
+ TAddResponse resp{
+ {123, {EDstStatus::Success, ""}},
+ };
+ UNIT_ASSERT_VALUES_EQUAL(resp, fut.GetValue());
+
+ UNIT_ASSERT(client.Tickets.empty());
+
+ TDsts dsts{19, 123, 213};
+ UNIT_ASSERT_VALUES_EQUAL(dsts, client.GetDsts());
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(client.GetOptionalServiceTicketFor(213), TMissingServiceTicket, "some error");
+ }
+ }
+
+ Y_UNIT_TEST(StartWithEmptyTicketsSet) {
+ CleanCache();
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"kolmo", 213}}, false);
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+
+ {
+ TOfflineUpdater client(s,
+ l,
+ false,
+ {
+ R"({"213" : { "error" : "some error"}})",
+ R"({"123" : { "ticket" : "3:serv:CBAQ__________9_IgYIlJEGEHs:CcafYQH-FF5XaXMuJrgLZj98bIC54cs1ZkcFS9VV_9YM9iOM_0PXCtMkdg85rFjxE_BMpg7bE8ZuoqNfdw0FPt0BAKNeISwlydj4o0IjY82--LZBpP8CRn-EpAnkRaDShdlfrcF2pk1SSmEX8xdyZVQEnkUPY0cHGlFnu231vnE"}})",
+ });
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::IncompleteTicketsSet, client.GetStatus());
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->TicketsById.contains(213));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->ErrorsById.contains(213));
+ UNIT_ASSERT_EXCEPTION_CONTAINS(client.GetOptionalServiceTicketFor(213), TMissingServiceTicket, "some error");
+
+ NThreading::TFuture<TAddResponse> fut = client.Add({123});
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::IncompleteTicketsSet, client.GetStatus());
+
+ client.Worker();
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::IncompleteTicketsSet, client.GetStatus());
+
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->TicketsById.contains(213));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(123));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->ErrorsById.contains(213));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(123));
+
+ UNIT_ASSERT(fut.HasValue());
+ TAddResponse resp{
+ {123, {EDstStatus::Success, ""}},
+ };
+ UNIT_ASSERT_VALUES_EQUAL(resp, fut.GetValue());
+
+ UNIT_ASSERT(client.Tickets.empty());
+
+ TDsts dsts{123, 213};
+ UNIT_ASSERT_VALUES_EQUAL(dsts, client.GetDsts());
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(client.GetOptionalServiceTicketFor(213), TMissingServiceTicket, "some error");
+ }
+ };
+ Y_UNIT_TEST(StartWithIncompleteCacheAndAdd) {
+ TInstant now = TInstant::Now();
+ CleanCache();
+ WriteFile("./service_tickets",
+ R"({"19" : { "ticket" : "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"}})"
+ "\t100500",
+ now);
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}, {"kolmo", 213}});
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TOfflineUpdater(s, l),
+ TRetriableException,
+ "Failed to start TvmClient. You can retry: ServiceTickets: tickets: alarm");
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/service_tickets' was successfully read\n"
+ << "6: Got 1 service ticket(s) from disk\n"
+ << "6: Cache was updated with 1 service ticket(s): XXXXXXXXXXX\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "4: Failed to get ServiceTickets: tickets: alarm\n"
+ << "4: Failed to get ServiceTickets: tickets: alarm\n"
+ << "4: Failed to get ServiceTickets: tickets: alarm\n"
+ << "4: Failed to update service tickets: tickets: alarm\n",
+ std::regex_replace(std::string(l->Stream.Str()), TIME_REGEX, "XXXXXXXXXXX"));
+ l->Stream.Str().clear();
+
+ {
+ TOfflineUpdater client(s,
+ l,
+ false,
+ {
+ R"({"213" : { "ticket" : "service_ticket_2"}})",
+ R"({"123" : { "ticket" : "service_ticket_3"}})",
+ });
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, client.GetStatus());
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(19));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(213));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(19));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(213));
+
+ NThreading::TFuture<TAddResponse> fut = client.Add({123});
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, client.GetStatus());
+
+ client.Worker();
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, client.GetStatus());
+
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(19));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(213));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(123));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(19));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(213));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(123));
+
+ UNIT_ASSERT(fut.HasValue());
+ TAddResponse resp{
+ {123, {EDstStatus::Success, ""}},
+ };
+ UNIT_ASSERT_VALUES_EQUAL(resp, fut.GetValue());
+
+ UNIT_ASSERT(client.Tickets.empty());
+
+ TDsts dsts{19, 123, 213};
+ UNIT_ASSERT_VALUES_EQUAL(dsts, client.GetDsts());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/service_tickets' was successfully read\n"
+ << "6: Got 1 service ticket(s) from disk\n"
+ << "6: Cache was updated with 1 service ticket(s): " << TInstant::Seconds(now.Seconds()) << "\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "7: Response with service tickets for 1 destination(s) was successfully fetched from https://tvm-api.yandex.net\n"
+ << "7: Got responses with service tickets with 1 pages for 1 destination(s)\n"
+ << "6: Cache was partly updated with 1 service ticket(s). total: 2\n"
+ << "6: File './tmp/service_tickets' was successfully written\n"
+ << "7: Adding dst: got task #1 with 1 dsts\n"
+ << "7: Response with service tickets for 1 destination(s) was successfully fetched from https://tvm-api.yandex.net\n"
+ << "7: Got responses with service tickets with 1 pages for 1 destination(s)\n"
+ << "6: Cache was partly updated with 1 service ticket(s). total: 3\n"
+ << "6: File './tmp/service_tickets' was successfully written\n"
+ << "7: Adding dst: task #1: dst=123 got ticket\n"
+ << "7: Adding dst: task #1: set value\n",
+ l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(StartWithCacheAndAdd) {
+ TInstant now = TInstant::Now();
+ CleanCache();
+ WriteFile("./service_tickets",
+ R"({"19" : { "ticket" : "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"}})"
+ "\t100500",
+ now);
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}});
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TOfflineUpdater client(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, client.GetStatus());
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(19));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(19));
+
+ client.Fail = false;
+ client.Tickets = {
+ R"({"123" : { "ticket" : "service_ticket_3"}, "213" : { "ticket" : "service_ticket_2"}})",
+ };
+ NThreading::TFuture<TAddResponse> fut = client.Add({123, 213});
+
+ client.Worker();
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, client.GetStatus());
+
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(19));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(213));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(123));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(19));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(213));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(123));
+
+ UNIT_ASSERT(fut.HasValue());
+ TAddResponse resp{
+ {123, {EDstStatus::Success, ""}},
+ {213, {EDstStatus::Success, ""}},
+ };
+ UNIT_ASSERT_VALUES_EQUAL(resp, fut.GetValue());
+
+ UNIT_ASSERT(client.Tickets.empty());
+
+ TDsts dsts{19, 123, 213};
+ UNIT_ASSERT_VALUES_EQUAL(dsts, client.GetDsts());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/service_tickets' was successfully read\n"
+ << "6: Got 1 service ticket(s) from disk\n"
+ << "6: Cache was updated with 1 service ticket(s): " << TInstant::Seconds(now.Seconds()) << "\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "7: Adding dst: got task #1 with 2 dsts\n"
+ << "7: Response with service tickets for 2 destination(s) was successfully fetched from https://tvm-api.yandex.net\n"
+ << "7: Got responses with service tickets with 1 pages for 2 destination(s)\n"
+ << "6: Cache was partly updated with 2 service ticket(s). total: 3\n"
+ << "6: File './tmp/service_tickets' was successfully written\n"
+ << "7: Adding dst: task #1: dst=123 got ticket\n"
+ << "7: Adding dst: task #1: dst=213 got ticket\n"
+ << "7: Adding dst: task #1: set value\n",
+ l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(StartWithCacheAndAddSeveral) {
+ TInstant now = TInstant::Now();
+ CleanCache();
+ WriteFile("./service_tickets",
+ R"({"19" : { "ticket" : "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"}})"
+ "\t100500",
+ now);
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}});
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TOfflineUpdater client(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, client.GetStatus());
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(19));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(19));
+
+ client.Fail = false;
+ client.Tickets = {
+ R"({"123" : { "ticket" : "service_ticket_3"}, "213" : { "ticket" : "service_ticket_2"}})",
+ };
+ NThreading::TFuture<TAddResponse> fut1 = client.Add({123});
+ NThreading::TFuture<TAddResponse> fut2 = client.Add({213});
+
+ client.Worker();
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, client.GetStatus());
+
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(19));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(213));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(123));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(19));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(213));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(123));
+
+ UNIT_ASSERT(fut1.HasValue());
+ TAddResponse resp1{
+ {123, {EDstStatus::Success, ""}},
+ };
+ UNIT_ASSERT_VALUES_EQUAL(resp1, fut1.GetValue());
+
+ UNIT_ASSERT(fut2.HasValue());
+ TAddResponse resp2{
+ {213, {EDstStatus::Success, ""}},
+ };
+ UNIT_ASSERT_VALUES_EQUAL(resp2, fut2.GetValue());
+
+ UNIT_ASSERT(client.Tickets.empty());
+
+ TDsts dsts{19, 123, 213};
+ UNIT_ASSERT_VALUES_EQUAL(dsts, client.GetDsts());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/service_tickets' was successfully read\n"
+ << "6: Got 1 service ticket(s) from disk\n"
+ << "6: Cache was updated with 1 service ticket(s): " << TInstant::Seconds(now.Seconds()) << "\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "7: Adding dst: got task #1 with 1 dsts\n"
+ << "7: Adding dst: got task #2 with 1 dsts\n"
+ << "7: Response with service tickets for 2 destination(s) was successfully fetched from https://tvm-api.yandex.net\n"
+ << "7: Got responses with service tickets with 1 pages for 2 destination(s)\n"
+ << "6: Cache was partly updated with 2 service ticket(s). total: 3\n"
+ << "6: File './tmp/service_tickets' was successfully written\n"
+ << "7: Adding dst: task #1: dst=123 got ticket\n"
+ << "7: Adding dst: task #1: set value\n"
+ << "7: Adding dst: task #2: dst=213 got ticket\n"
+ << "7: Adding dst: task #2: set value\n",
+ l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(StartWithCacheAndAddSeveralWithErrors) {
+ TInstant now = TInstant::Now();
+ CleanCache();
+ WriteFile("./service_tickets",
+ R"({"19" : { "ticket" : "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"}})"
+ "\t100500",
+ now);
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}});
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TOfflineUpdater client(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, client.GetStatus());
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(19));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(19));
+
+ UNIT_ASSERT(client.GetOptionalServiceTicketFor(19));
+ UNIT_ASSERT_VALUES_EQUAL("3:serv:CBAQ__________9_IgYIKhCUkQY:CX",
+ *client.GetOptionalServiceTicketFor(19));
+ UNIT_ASSERT(!client.GetOptionalServiceTicketFor(456));
+
+ client.Fail = false;
+ client.Tickets = {
+ R"({
+ "123" : { "ticket" : "service_ticket_3"},
+ "213" : { "ticket" : "service_ticket_2"},
+ "456" : { "error" : "error_3"}
+ })",
+ };
+ NThreading::TFuture<TAddResponse> fut1 = client.Add({123, 213});
+ NThreading::TFuture<TAddResponse> fut2 = client.Add({213, 456});
+
+ client.Worker();
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, client.GetStatus());
+
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(19));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(213));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(123));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->TicketsById.contains(456));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(19));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(213));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(123));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->ErrorsById.contains(456));
+
+ UNIT_ASSERT(client.GetOptionalServiceTicketFor(19));
+ UNIT_ASSERT_VALUES_EQUAL("3:serv:CBAQ__________9_IgYIKhCUkQY:CX",
+ *client.GetOptionalServiceTicketFor(19));
+ UNIT_ASSERT_EXCEPTION_CONTAINS(client.GetOptionalServiceTicketFor(456),
+ TMissingServiceTicket,
+ "Failed to get ticket for '456': error_3");
+
+ UNIT_ASSERT(fut1.HasValue());
+ TAddResponse resp1{
+ {123, {EDstStatus::Success, ""}},
+ {213, {EDstStatus::Success, ""}},
+ };
+ UNIT_ASSERT_VALUES_EQUAL(resp1, fut1.GetValue());
+
+ UNIT_ASSERT(fut2.HasValue());
+ TAddResponse resp2{
+ {213, {EDstStatus::Success, ""}},
+ {456, {EDstStatus::Fail, "error_3"}},
+ };
+ UNIT_ASSERT_VALUES_EQUAL(resp2, fut2.GetValue());
+
+ UNIT_ASSERT(client.Tickets.empty());
+
+ TDsts dsts{19, 123, 213};
+ UNIT_ASSERT_VALUES_EQUAL(dsts, client.GetDsts());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/service_tickets' was successfully read\n"
+ << "6: Got 1 service ticket(s) from disk\n"
+ << "6: Cache was updated with 1 service ticket(s): " << TInstant::Seconds(now.Seconds()) << "\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "7: Adding dst: got task #1 with 2 dsts\n"
+ << "7: Adding dst: got task #2 with 2 dsts\n"
+ << "7: Response with service tickets for 3 destination(s) was successfully fetched from https://tvm-api.yandex.net\n"
+ << "7: Got responses with service tickets with 1 pages for 3 destination(s)\n"
+ << "3: Failed to get service ticket for dst=456: error_3\n"
+ << "6: Cache was partly updated with 2 service ticket(s). total: 3\n"
+ << "6: File './tmp/service_tickets' was successfully written\n"
+ << "7: Adding dst: task #1: dst=123 got ticket\n"
+ << "7: Adding dst: task #1: dst=213 got ticket\n"
+ << "7: Adding dst: task #1: set value\n"
+ << "7: Adding dst: task #2: dst=213 got ticket\n"
+ << "4: Adding dst: task #2: dst=456 failed to get ticket: error_3\n"
+ << "7: Adding dst: task #2: set value\n",
+ l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(WithException) {
+ TInstant now = TInstant::Now();
+ CleanCache();
+ WriteFile("./service_tickets",
+ R"({"19" : { "ticket" : "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"}})"
+ "\t100500",
+ now);
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}});
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TOfflineUpdater client(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, client.GetStatus());
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(19));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(19));
+
+ client.Fail = false;
+ client.Tickets = {
+ R"({
+ "123" : { "ticket" : "service_ticket_3"},
+ "213" : { "ticket" : "service_ticket_2"},
+ "456" : { "error" : "error_3"},
+ "789" : { "ticket" : "service_ticket_4"}
+ })",
+ };
+ NThreading::TFuture<TAddResponse> fut1 = client.Add({123, 213});
+ NThreading::TFuture<TAddResponse> fut2 = client.Add({213, 456});
+ NThreading::TFuture<TAddResponse> fut3 = client.Add({789});
+
+ fut2.Subscribe([](const auto&) {
+ throw yexception() << "planed exc";
+ });
+ fut3.Subscribe([](const auto&) {
+ throw 5;
+ });
+
+ UNIT_ASSERT_NO_EXCEPTION(client.Worker());
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, client.GetStatus());
+
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(19));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(213));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->TicketsById.contains(123));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->TicketsById.contains(456));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(19));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(213));
+ UNIT_ASSERT(!client.GetCachedServiceTickets()->ErrorsById.contains(123));
+ UNIT_ASSERT(client.GetCachedServiceTickets()->ErrorsById.contains(456));
+
+ UNIT_ASSERT(fut1.HasValue());
+ TAddResponse resp1{
+ {123, {EDstStatus::Success, ""}},
+ {213, {EDstStatus::Success, ""}},
+ };
+ UNIT_ASSERT_VALUES_EQUAL(resp1, fut1.GetValue());
+
+ UNIT_ASSERT(fut2.HasValue());
+ TAddResponse resp2{
+ {213, {EDstStatus::Success, ""}},
+ {456, {EDstStatus::Fail, "error_3"}},
+ };
+ UNIT_ASSERT_VALUES_EQUAL(resp2, fut2.GetValue());
+
+ UNIT_ASSERT(fut3.HasValue());
+ TAddResponse resp3{
+ {789, {EDstStatus::Success, ""}},
+ };
+ UNIT_ASSERT_VALUES_EQUAL(resp3, fut3.GetValue());
+
+ UNIT_ASSERT(client.Tickets.empty());
+
+ TDsts dsts{19, 123, 213, 789};
+ UNIT_ASSERT_VALUES_EQUAL(dsts, client.GetDsts());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/service_tickets' was successfully read\n"
+ << "6: Got 1 service ticket(s) from disk\n"
+ << "6: Cache was updated with 1 service ticket(s): " << TInstant::Seconds(now.Seconds()) << "\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "7: Adding dst: got task #1 with 2 dsts\n"
+ << "7: Adding dst: got task #2 with 2 dsts\n"
+ << "7: Adding dst: got task #3 with 1 dsts\n"
+ << "7: Response with service tickets for 4 destination(s) was successfully fetched from https://tvm-api.yandex.net\n"
+ << "7: Got responses with service tickets with 1 pages for 4 destination(s)\n"
+ << "3: Failed to get service ticket for dst=456: error_3\n"
+ << "6: Cache was partly updated with 3 service ticket(s). total: 4\n"
+ << "6: File './tmp/service_tickets' was successfully written\n"
+ << "7: Adding dst: task #1: dst=123 got ticket\n"
+ << "7: Adding dst: task #1: dst=213 got ticket\n"
+ << "7: Adding dst: task #1: set value\n"
+ << "7: Adding dst: task #2: dst=213 got ticket\n"
+ << "4: Adding dst: task #2: dst=456 failed to get ticket: error_3\n"
+ << "7: Adding dst: task #2: set value\n"
+ << "3: Adding dst: task #2: exception: planed exc\n"
+ << "7: Adding dst: task #3: dst=789 got ticket\n"
+ << "7: Adding dst: task #3: set value\n"
+ << "3: Adding dst: task #3: exception: unknown error\n",
+ l->Stream.Str());
+ }
+}
+
+template <>
+void Out<NTvmAuth::NDynamicClient::TDstResponse>(IOutputStream& out, const NTvmAuth::NDynamicClient::TDstResponse& m) {
+ out << m.Status << " (" << m.Error << ")";
+}
+
+template <>
+void Out<NTvmAuth::NTvmApi::TClientSettings::TDst>(IOutputStream& out, const NTvmAuth::NTvmApi::TClientSettings::TDst& m) {
+ out << m.Id;
+}
diff --git a/library/cpp/tvmauth/client/misc/api/dynamic_dst/ut/ya.make b/library/cpp/tvmauth/client/misc/api/dynamic_dst/ut/ya.make
new file mode 100644
index 0000000000..5d01ffaad8
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/api/dynamic_dst/ut/ya.make
@@ -0,0 +1,11 @@
+UNITTEST_FOR(library/cpp/tvmauth/client/misc/api/dynamic_dst)
+
+OWNER(g:passport_infra)
+
+SRCS(
+ tvm_client_ut.cpp
+)
+
+ENV(YA_TEST_SHORTEN_WINE_PATH=1)
+
+END()
diff --git a/library/cpp/tvmauth/client/misc/api/dynamic_dst/ya.make b/library/cpp/tvmauth/client/misc/api/dynamic_dst/ya.make
new file mode 100644
index 0000000000..f3858e602f
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/api/dynamic_dst/ya.make
@@ -0,0 +1,20 @@
+LIBRARY()
+
+OWNER(g:passport_infra)
+
+PEERDIR(
+ library/cpp/threading/future
+ library/cpp/tvmauth/client
+)
+
+SRCS(
+ tvm_client.cpp
+)
+
+GENERATE_ENUM_SERIALIZATION(tvm_client.h)
+
+END()
+
+RECURSE_FOR_TESTS(
+ ut
+)
diff --git a/library/cpp/tvmauth/client/misc/api/retry_settings.h b/library/cpp/tvmauth/client/misc/api/retry_settings.h
new file mode 100644
index 0000000000..607b230811
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/api/retry_settings.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <library/cpp/tvmauth/client/misc/exponential_backoff.h>
+
+namespace NTvmAuth::NTvmApi {
+ struct TRetrySettings {
+ TExponentialBackoff::TSettings BackoffSettings = {
+ TDuration::Seconds(0),
+ TDuration::Minutes(1),
+ 2,
+ 0.5,
+ };
+ TDuration MaxRandomSleepDefault = TDuration::Seconds(5);
+ TDuration MaxRandomSleepWhenOk = TDuration::Minutes(1);
+ ui32 RetriesOnStart = 3;
+ ui32 RetriesInBackground = 2;
+ TDuration WorkerAwakingPeriod = TDuration::Seconds(10);
+ ui32 DstsLimit = 300;
+ TDuration RolesUpdatePeriod = TDuration::Minutes(10);
+ TDuration RolesWarnPeriod = TDuration::Minutes(20);
+
+ bool operator==(const TRetrySettings& o) const {
+ return BackoffSettings == o.BackoffSettings &&
+ MaxRandomSleepDefault == o.MaxRandomSleepDefault &&
+ MaxRandomSleepWhenOk == o.MaxRandomSleepWhenOk &&
+ RetriesOnStart == o.RetriesOnStart &&
+ WorkerAwakingPeriod == o.WorkerAwakingPeriod &&
+ DstsLimit == o.DstsLimit &&
+ RolesUpdatePeriod == o.RolesUpdatePeriod &&
+ RolesWarnPeriod == o.RolesWarnPeriod;
+ }
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/api/roles_fetcher.cpp b/library/cpp/tvmauth/client/misc/api/roles_fetcher.cpp
new file mode 100644
index 0000000000..b46595207c
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/api/roles_fetcher.cpp
@@ -0,0 +1,163 @@
+#include "roles_fetcher.h"
+
+#include <library/cpp/tvmauth/client/misc/disk_cache.h>
+#include <library/cpp/tvmauth/client/misc/roles/decoder.h>
+#include <library/cpp/tvmauth/client/misc/roles/parser.h>
+
+#include <library/cpp/string_utils/quote/quote.h>
+
+#include <util/string/builder.h>
+#include <util/string/join.h>
+
+namespace NTvmAuth::NTvmApi {
+ static TString CreatePath(const TString& dir, const TString& file) {
+ return dir.EndsWith("/")
+ ? dir + file
+ : dir + "/" + file;
+ }
+
+ TRolesFetcher::TRolesFetcher(const TRolesFetcherSettings& settings, TLoggerPtr logger)
+ : Settings_(settings)
+ , Logger_(logger)
+ , CacheFilePath_(CreatePath(Settings_.CacheDir, "roles"))
+ {
+ Client_ = std::make_unique<TKeepAliveHttpClient>(
+ Settings_.TiroleHost,
+ Settings_.TirolePort,
+ Settings_.Timeout,
+ Settings_.Timeout);
+ }
+
+ TInstant TRolesFetcher::ReadFromDisk() {
+ TDiskReader dr(CacheFilePath_, Logger_.Get());
+ if (!dr.Read()) {
+ return {};
+ }
+
+ std::pair<TString, TString> data = ParseDiskFormat(dr.Data());
+ if (data.second != Settings_.IdmSystemSlug) {
+ Logger_->Warning(
+ TStringBuilder() << "Roles in disk cache are for another slug (" << data.second
+ << "). Self=" << Settings_.IdmSystemSlug);
+ return {};
+ }
+
+ CurrentRoles_.Set(NRoles::TParser::Parse(std::make_shared<TString>(std::move(data.first))));
+ Logger_->Debug(
+ TStringBuilder() << "Succeed to read roles with revision "
+ << CurrentRoles_.Get()->GetMeta().Revision
+ << " from " << CacheFilePath_);
+
+ return dr.Time();
+ }
+
+ bool TRolesFetcher::AreRolesOk() const {
+ return bool(GetCurrentRoles());
+ }
+
+ bool TRolesFetcher::IsTimeToUpdate(const TRetrySettings& settings, TDuration sinceUpdate) {
+ return settings.RolesUpdatePeriod < sinceUpdate;
+ }
+
+ bool TRolesFetcher::ShouldWarn(const TRetrySettings& settings, TDuration sinceUpdate) {
+ return settings.RolesWarnPeriod < sinceUpdate;
+ }
+
+ NUtils::TFetchResult TRolesFetcher::FetchActualRoles(const TString& serviceTicket) {
+ TStringStream out;
+ THttpHeaders outHeaders;
+
+ TRequest req = CreateTiroleRequest(serviceTicket);
+ TKeepAliveHttpClient::THttpCode code = Client_->DoGet(
+ req.Url,
+ &out,
+ req.Headers,
+ &outHeaders);
+
+ const THttpInputHeader* reqId = outHeaders.FindHeader("X-Request-Id");
+
+ Logger_->Debug(
+ TStringBuilder() << "Succeed to perform request for roles to " << Settings_.TiroleHost
+ << " (request_id=" << (reqId ? reqId->Value() : "")
+ << "). code=" << code);
+
+ return {code, std::move(outHeaders), "/v1/get_actual_roles", out.Str(), {}};
+ }
+
+ void TRolesFetcher::Update(NUtils::TFetchResult&& fetchResult, TInstant now) {
+ if (fetchResult.Code == 304) {
+ Y_ENSURE(CurrentRoles_.Get(),
+ "tirole did not return any roles because current roles are actual,"
+ " but there are no roles in memory - this should never happen");
+ return;
+ }
+
+ Y_ENSURE(fetchResult.Code == 200,
+ "Unexpected code from tirole: " << fetchResult.Code << ". " << fetchResult.Response);
+
+ const THttpInputHeader* codec = fetchResult.Headers.FindHeader("X-Tirole-Compression");
+ const TStringBuf codecBuf = codec ? codec->Value() : "";
+
+ NRoles::TRawPtr blob;
+ try {
+ blob = std::make_shared<TString>(NRoles::TDecoder::Decode(
+ codecBuf,
+ std::move(fetchResult.Response)));
+ } catch (const std::exception& e) {
+ throw yexception() << "Failed to decode blob with codec '" << codecBuf
+ << "': " << e.what();
+ }
+
+ CurrentRoles_.Set(NRoles::TParser::Parse(blob));
+
+ Logger_->Debug(
+ TStringBuilder() << "Succeed to update roles with revision "
+ << CurrentRoles_.Get()->GetMeta().Revision);
+
+ TDiskWriter dw(CacheFilePath_, Logger_.Get());
+ dw.Write(PrepareDiskFormat(*blob, Settings_.IdmSystemSlug), now);
+ }
+
+ NTvmAuth::NRoles::TRolesPtr TRolesFetcher::GetCurrentRoles() const {
+ return CurrentRoles_.Get();
+ }
+
+ void TRolesFetcher::ResetConnection() {
+ Client_->ResetConnection();
+ }
+
+ static const char DELIMETER = '\t';
+
+ std::pair<TString, TString> TRolesFetcher::ParseDiskFormat(TStringBuf filebody) {
+ TStringBuf slug = filebody.RNextTok(DELIMETER);
+ return {TString(filebody), CGIUnescapeRet(slug)};
+ }
+
+ TString TRolesFetcher::PrepareDiskFormat(TStringBuf roles, TStringBuf slug) {
+ TStringStream res;
+ res.Reserve(roles.size() + 1 + slug.size());
+ res << roles << DELIMETER << CGIEscapeRet(slug);
+ return res.Str();
+ }
+
+ TRolesFetcher::TRequest TRolesFetcher::CreateTiroleRequest(const TString& serviceTicket) const {
+ TRolesFetcher::TRequest res;
+
+ TStringStream url;
+ url.Reserve(512);
+ url << "/v1/get_actual_roles?";
+ url << "system_slug=" << CGIEscapeRet(Settings_.IdmSystemSlug) << "&";
+ Settings_.ProcInfo.AddToRequest(url);
+ res.Url = std::move(url.Str());
+
+ res.Headers.reserve(2);
+ res.Headers.emplace(XYaServiceTicket_, serviceTicket);
+
+ NRoles::TRolesPtr roles = CurrentRoles_.Get();
+ if (roles) {
+ res.Headers.emplace(IfNoneMatch_, Join("", "\"", roles->GetMeta().Revision, "\""));
+ }
+
+ return res;
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/api/roles_fetcher.h b/library/cpp/tvmauth/client/misc/api/roles_fetcher.h
new file mode 100644
index 0000000000..63691223b5
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/api/roles_fetcher.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include "retry_settings.h"
+
+#include <library/cpp/tvmauth/client/misc/fetch_result.h>
+#include <library/cpp/tvmauth/client/misc/proc_info.h>
+#include <library/cpp/tvmauth/client/misc/utils.h>
+#include <library/cpp/tvmauth/client/misc/roles/roles.h>
+
+#include <library/cpp/tvmauth/client/logger.h>
+
+#include <library/cpp/http/simple/http_client.h>
+
+namespace NTvmAuth::NTvmApi {
+ struct TRolesFetcherSettings {
+ TString TiroleHost;
+ ui16 TirolePort = 0;
+ TString CacheDir;
+ NUtils::TProcInfo ProcInfo;
+ TTvmId SelfTvmId = 0;
+ TString IdmSystemSlug;
+ TDuration Timeout = TDuration::Seconds(30);
+ };
+
+ class TRolesFetcher {
+ public:
+ TRolesFetcher(const TRolesFetcherSettings& settings, TLoggerPtr logger);
+
+ TInstant ReadFromDisk();
+
+ bool AreRolesOk() const;
+ static bool IsTimeToUpdate(const TRetrySettings& settings, TDuration sinceUpdate);
+ static bool ShouldWarn(const TRetrySettings& settings, TDuration sinceUpdate);
+
+ NUtils::TFetchResult FetchActualRoles(const TString& serviceTicket);
+ void Update(NUtils::TFetchResult&& fetchResult, TInstant now = TInstant::Now());
+
+ NTvmAuth::NRoles::TRolesPtr GetCurrentRoles() const;
+
+ void ResetConnection();
+
+ public:
+ static std::pair<TString, TString> ParseDiskFormat(TStringBuf filebody);
+ static TString PrepareDiskFormat(TStringBuf roles, TStringBuf slug);
+
+ struct TRequest {
+ TString Url;
+ TKeepAliveHttpClient::THeaders Headers;
+ };
+ TRequest CreateTiroleRequest(const TString& serviceTicket) const;
+
+ private:
+ const TRolesFetcherSettings Settings_;
+ const TLoggerPtr Logger_;
+ const TString CacheFilePath_;
+ const TString XYaServiceTicket_ = "X-Ya-Service-Ticket";
+ const TString IfNoneMatch_ = "If-None-Match";
+
+ NUtils::TProtectedValue<NTvmAuth::NRoles::TRolesPtr> CurrentRoles_;
+
+ std::unique_ptr<TKeepAliveHttpClient> Client_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/api/settings.cpp b/library/cpp/tvmauth/client/misc/api/settings.cpp
new file mode 100644
index 0000000000..71aad75998
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/api/settings.cpp
@@ -0,0 +1,89 @@
+#include "settings.h"
+
+#include <util/datetime/base.h>
+#include <util/stream/file.h>
+#include <util/system/fs.h>
+
+#include <set>
+
+namespace NTvmAuth::NTvmApi {
+ void TClientSettings::CheckPermissions(const TString& dir) {
+ const TString name = dir + "/check.tmp";
+
+ try {
+ NFs::EnsureExists(dir);
+
+ TFile file(name, CreateAlways | RdWr);
+
+ NFs::Remove(name);
+ } catch (const std::exception& e) {
+ NFs::Remove(name);
+ ythrow TPermissionDenied() << "Permission denied to disk cache directory: " << e.what();
+ }
+ }
+
+ void TClientSettings::CheckValid() const {
+ if (DiskCacheDir) {
+ CheckPermissions(DiskCacheDir);
+ }
+
+ if (TStringBuf(Secret)) {
+ Y_ENSURE_EX(NeedServiceTicketsFetching(),
+ TBrokenTvmClientSettings() << "Secret is present but destinations list is empty. It makes no sense");
+ }
+ if (NeedServiceTicketsFetching()) {
+ Y_ENSURE_EX(SelfTvmId != 0,
+ TBrokenTvmClientSettings() << "SelfTvmId cannot be 0 if fetching of Service Tickets required");
+ Y_ENSURE_EX((TStringBuf)Secret,
+ TBrokenTvmClientSettings() << "Secret is required for fetching of Service Tickets");
+ }
+
+ if (CheckServiceTickets) {
+ Y_ENSURE_EX(SelfTvmId != 0,
+ TBrokenTvmClientSettings() << "SelfTvmId cannot be 0 if checking of Service Tickets required");
+ }
+
+ if (FetchRolesForIdmSystemSlug) {
+ Y_ENSURE_EX(DiskCacheDir,
+ TBrokenTvmClientSettings() << "Disk cache must be enabled to use roles: "
+ "they can be heavy");
+ }
+
+ bool needSmth = NeedServiceTicketsFetching() ||
+ IsServiceTicketCheckingRequired() ||
+ IsUserTicketCheckingRequired();
+ Y_ENSURE_EX(needSmth, TBrokenTvmClientSettings() << "Invalid settings: nothing to do");
+
+ // Useless now: keep it here to avoid forgetting check from TDst. TODO: PASSP-35377
+ for (const auto& dst : FetchServiceTicketsForDsts) {
+ Y_ENSURE_EX(dst.Id != 0, TBrokenTvmClientSettings() << "TvmId cannot be 0");
+ }
+ // TODO: check only FetchServiceTicketsForDsts_
+ // Python binding checks settings before normalization
+ for (const auto& [alias, dst] : FetchServiceTicketsForDstsWithAliases) {
+ Y_ENSURE_EX(dst.Id != 0, TBrokenTvmClientSettings() << "TvmId cannot be 0");
+ }
+ Y_ENSURE_EX(TiroleTvmId != 0, TBrokenTvmClientSettings() << "TiroleTvmId cannot be 0");
+ }
+
+ TClientSettings TClientSettings::CloneNormalized() const {
+ TClientSettings res = *this;
+
+ std::set<TTvmId> allDsts;
+ for (const auto& tvmid : res.FetchServiceTicketsForDsts) {
+ allDsts.insert(tvmid.Id);
+ }
+ for (const auto& [alias, tvmid] : res.FetchServiceTicketsForDstsWithAliases) {
+ allDsts.insert(tvmid.Id);
+ }
+ if (FetchRolesForIdmSystemSlug) {
+ allDsts.insert(res.TiroleTvmId);
+ }
+
+ res.FetchServiceTicketsForDsts = {allDsts.begin(), allDsts.end()};
+
+ res.CheckValid();
+
+ return res;
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/api/settings.h b/library/cpp/tvmauth/client/misc/api/settings.h
new file mode 100644
index 0000000000..715ab3e02c
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/api/settings.h
@@ -0,0 +1,302 @@
+#pragma once
+
+#include <library/cpp/tvmauth/client/misc/settings.h>
+
+#include <library/cpp/tvmauth/client/exception.h>
+
+#include <library/cpp/tvmauth/checked_user_ticket.h>
+#include <library/cpp/tvmauth/type.h>
+
+#include <library/cpp/string_utils/secret_string/secret_string.h>
+
+#include <util/datetime/base.h>
+#include <util/generic/hash.h>
+#include <util/generic/maybe.h>
+
+namespace NTvmAuth::NTvmApi {
+ /**
+ * Settings for TVM client. Uses https://tvm-api.yandex.net to get state.
+ * At least one of them is required:
+ * FetchServiceTicketsForDsts_/FetchServiceTicketsForDstsWithAliases_
+ * CheckServiceTickets_
+ * CheckUserTicketsWithBbEnv_
+ */
+ class TClientSettings: public NTvmAuth::TClientSettings {
+ public:
+ class TDst;
+
+ /**
+ * Alias is an internal name for destinations within your code.
+ * You can associate a name with an tvm_id once in your code and use the name as an alias for
+ * tvm_id to each calling point. Useful for several environments: prod/test/etc.
+ * @example:
+ * // init
+ * static const TString MY_BACKEND = "my backend";
+ * TDstMap map = {{MY_BACKEND, TDst(config.get("my_back_tvm_id"))}};
+ * ...
+ * // per request
+ * TString t = tvmClient.GetServiceTicket(MY_BACKEND);
+ */
+ using TDstMap = THashMap<TAlias, TDst>;
+ using TDstVector = TVector<TDst>;
+
+ public:
+ /*!
+ * NOTE: Please use this option: it provides the best reliability
+ * NOTE: Client requires read/write permissions
+ * WARNING: The same directory can be used only:
+ * - for TVM clients with the same settings
+ * OR
+ * - for new client replacing previous - with another config.
+ * System user must be the same for processes with these clients inside.
+ * Implementation doesn't provide other scenarios.
+ */
+ TString DiskCacheDir;
+
+ // Required for Service Ticket fetching or checking
+ TTvmId SelfTvmId = 0;
+
+ // Options for Service Tickets fetching
+ NSecretString::TSecretString Secret;
+ /*!
+ * Client will process both attrs:
+ * FetchServiceTicketsForDsts_, FetchServiceTicketsForDstsWithAliases_
+ * WARNING: It is not way to provide authorization for incoming ServiceTickets!
+ * It is way only to send your ServiceTickets to your backend!
+ */
+ TDstVector FetchServiceTicketsForDsts;
+ TDstMap FetchServiceTicketsForDstsWithAliases;
+ bool IsIncompleteTicketsSetAnError = true;
+
+ // Options for Service Tickets checking
+ bool CheckServiceTickets = false;
+
+ // Options for User Tickets checking
+ TMaybe<EBlackboxEnv> CheckUserTicketsWithBbEnv;
+
+ // Options for roles fetching
+ TString FetchRolesForIdmSystemSlug;
+ /*!
+ * By default client checks src from ServiceTicket or default uid from UserTicket -
+ * to prevent you from forgetting to check it yourself.
+ * It does binary checks only:
+ * ticket gets status NoRoles, if there is no role for src or default uid.
+ * You need to check roles on your own if you have a non-binary role system or
+ * you have disabled ShouldCheckSrc/ShouldCheckDefaultUid
+ *
+ * You may need to disable this check in the following cases:
+ * - You use GetRoles() to provide verbose message (with revision).
+ * Double check may be inconsistent:
+ * binary check inside client uses revision of roles X - i.e. src 100500 has no role,
+ * exact check in your code uses revision of roles Y - i.e. src 100500 has some roles.
+ */
+ bool ShouldCheckSrc = true;
+ bool ShouldCheckDefaultUid = true;
+
+ // Options for tests
+ TString TvmHost = "https://tvm-api.yandex.net";
+ ui16 TvmPort = 443;
+ TString TiroleHost = "https://tirole-api.yandex.net";
+ TDuration TvmSocketTimeout = TDuration::Seconds(5);
+ TDuration TvmConnectTimeout = TDuration::Seconds(30);
+ ui16 TirolePort = 443;
+ TTvmId TiroleTvmId = TIROLE_TVMID;
+
+ // for debug purposes
+ TString LibVersionPrefix;
+
+ void CheckValid() const;
+ TClientSettings CloneNormalized() const;
+
+ static inline const TTvmId TIROLE_TVMID = 2028120;
+ static inline const TTvmId TIROLE_TVMID_TEST = 2026536;
+
+ // DEPRECATED API
+ // TODO: get rid of it: PASSP-35377
+ public:
+ // Deprecated: set attributes directly
+ void SetSelfTvmId(TTvmId selfTvmId) {
+ SelfTvmId = selfTvmId;
+ }
+
+ // Deprecated: set attributes directly
+ void EnableServiceTicketChecking() {
+ CheckServiceTickets = true;
+ }
+
+ // Deprecated: set attributes directly
+ void EnableUserTicketChecking(EBlackboxEnv env) {
+ CheckUserTicketsWithBbEnv = env;
+ }
+
+ // Deprecated: set attributes directly
+ void SetTvmHostPort(const TString& host, ui16 port) {
+ TvmHost = host;
+ TvmPort = port;
+ }
+
+ // Deprecated: set attributes directly
+ void SetTiroleHostPort(const TString& host, ui16 port) {
+ TiroleHost = host;
+ TirolePort = port;
+ }
+
+ // Deprecated: set attributes directly
+ void EnableRolesFetching(const TString& systemSlug, TTvmId tiroleTvmId = TIROLE_TVMID) {
+ TiroleTvmId = tiroleTvmId;
+ FetchRolesForIdmSystemSlug = systemSlug;
+ }
+
+ // Deprecated: set attributes directly
+ void DoNotCheckSrcByDefault() {
+ ShouldCheckSrc = false;
+ }
+
+ // Deprecated: set attributes directly
+ void DoNotCheckDefaultUidByDefault() {
+ ShouldCheckDefaultUid = false;
+ }
+
+ // Deprecated: set attributes directly
+ void SetDiskCacheDir(const TString& dir) {
+ DiskCacheDir = dir;
+ }
+
+ // Deprecated: set attributes directly
+ void EnableServiceTicketsFetchOptions(const TStringBuf selfSecret,
+ TDstMap&& dsts,
+ const bool considerIncompleteTicketsSetAsError = true) {
+ IsIncompleteTicketsSetAnError = considerIncompleteTicketsSetAsError;
+ Secret = selfSecret;
+
+ FetchServiceTicketsForDsts = TDstVector{};
+ FetchServiceTicketsForDsts.reserve(dsts.size());
+ for (const auto& pair : dsts) {
+ FetchServiceTicketsForDsts.push_back(pair.second);
+ }
+
+ FetchServiceTicketsForDstsWithAliases = std::move(dsts);
+ }
+
+ // Deprecated: set attributes directly
+ void EnableServiceTicketsFetchOptions(const TStringBuf selfSecret,
+ TDstVector&& dsts,
+ const bool considerIncompleteTicketsSetAsError = true) {
+ IsIncompleteTicketsSetAnError = considerIncompleteTicketsSetAsError;
+ Secret = selfSecret;
+ FetchServiceTicketsForDsts = std::move(dsts);
+ }
+
+ public:
+ bool IsServiceTicketFetchingRequired() const {
+ return bool(Secret.Value());
+ }
+
+ const TStringBuf GetSelfSecret() const {
+ return Secret;
+ }
+
+ bool HasDstAliases() const {
+ return !FetchServiceTicketsForDstsWithAliases.empty();
+ }
+
+ const TDstMap& GetDstAliases() const {
+ return FetchServiceTicketsForDstsWithAliases;
+ }
+
+ const TDstVector& GetDestinations() const {
+ return FetchServiceTicketsForDsts;
+ }
+
+ bool IsUserTicketCheckingRequired() const {
+ return bool(CheckUserTicketsWithBbEnv);
+ }
+
+ EBlackboxEnv GetEnvForUserTickets() const {
+ return *CheckUserTicketsWithBbEnv;
+ }
+
+ bool IsServiceTicketCheckingRequired() const {
+ return CheckServiceTickets;
+ }
+
+ bool IsDiskCacheUsed() const {
+ return bool(DiskCacheDir);
+ }
+
+ TString GetDiskCacheDir() const {
+ return DiskCacheDir;
+ }
+
+ TTvmId GetSelfTvmId() const {
+ return SelfTvmId;
+ }
+
+ const TString& GetLibVersionPrefix() const {
+ return LibVersionPrefix;
+ }
+
+ const TString& GetTvmHost() const {
+ return TvmHost;
+ }
+
+ ui16 GetTvmPort() const {
+ return TvmPort;
+ }
+
+ bool IsRolesFetchingEnabled() const {
+ return bool(FetchRolesForIdmSystemSlug);
+ }
+
+ TTvmId GetTiroleTvmId() const {
+ return TiroleTvmId;
+ }
+
+ const TString& GetIdmSystemSlug() const {
+ return FetchRolesForIdmSystemSlug;
+ }
+
+ const TString& GetTiroleHost() const {
+ return TiroleHost;
+ }
+
+ ui16 GetTirolePort() const {
+ return TirolePort;
+ }
+
+ bool NeedServiceTicketsFetching() const {
+ return !FetchServiceTicketsForDsts.empty() ||
+ !FetchServiceTicketsForDstsWithAliases.empty() ||
+ FetchRolesForIdmSystemSlug;
+ }
+
+ // TODO: get rid of TDst: PASSP-35377
+ class TDst {
+ public:
+ TDst(TTvmId id)
+ : Id(id)
+ {
+ Y_ENSURE_EX(id != 0, TBrokenTvmClientSettings() << "TvmId cannot be 0");
+ }
+
+ TTvmId Id;
+
+ bool operator==(const TDst& o) const {
+ return Id == o.Id;
+ }
+
+ bool operator<(const TDst& o) const {
+ return Id < o.Id;
+ }
+
+ public: // for python binding
+ TDst()
+ : Id(0)
+ {
+ }
+ };
+
+ public:
+ static void CheckPermissions(const TString& dir);
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/api/threaded_updater.cpp b/library/cpp/tvmauth/client/misc/api/threaded_updater.cpp
new file mode 100644
index 0000000000..a7df49c05d
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/api/threaded_updater.cpp
@@ -0,0 +1,954 @@
+#include "threaded_updater.h"
+
+#include <library/cpp/tvmauth/client/misc/disk_cache.h>
+#include <library/cpp/tvmauth/client/misc/utils.h>
+#include <library/cpp/tvmauth/client/misc/retry_settings/v1/settings.pb.h>
+
+#include <library/cpp/tvmauth/client/logger.h>
+
+#include <library/cpp/json/json_reader.h>
+
+#include <util/stream/str.h>
+#include <util/string/builder.h>
+#include <util/string/cast.h>
+#include <util/system/thread.h>
+
+namespace NTvmAuth::NTvmApi {
+ static TString CreatePublicKeysUrl(const TClientSettings& settings,
+ const NUtils::TProcInfo& procInfo) {
+ TStringStream s;
+ s << "/2/keys";
+ s << "?";
+ procInfo.AddToRequest(s);
+
+ s << "&get_retry_settings=yes";
+
+ if (settings.GetSelfTvmId() != 0) {
+ s << "&src=" << settings.GetSelfTvmId();
+ }
+
+ if (settings.IsUserTicketCheckingRequired()) {
+ s << "&env=" << static_cast<int>(settings.GetEnvForUserTickets());
+ }
+
+ return s.Str();
+ }
+
+ TAsyncUpdaterPtr TThreadedUpdater::Create(const TClientSettings& settings, TLoggerPtr logger) {
+ Y_ENSURE_EX(logger, TNonRetriableException() << "Logger is required");
+ THolder<TThreadedUpdater> p(new TThreadedUpdater(settings, std::move(logger)));
+ p->Init();
+ p->StartWorker();
+ return p.Release();
+ }
+
+ TThreadedUpdater::~TThreadedUpdater() {
+ ExpBackoff_.SetEnabled(false);
+ ExpBackoff_.Interrupt();
+ StopWorker(); // Required here to avoid using of deleted members
+ }
+
+ TClientStatus TThreadedUpdater::GetStatus() const {
+ const TClientStatus::ECode state = GetState();
+ return TClientStatus(state, GetLastError(state == TClientStatus::Ok || state == TClientStatus::IncompleteTicketsSet));
+ }
+
+ NRoles::TRolesPtr TThreadedUpdater::GetRoles() const {
+ Y_ENSURE_EX(RolesFetcher_,
+ TBrokenTvmClientSettings() << "Roles were not configured in settings");
+ return RolesFetcher_->GetCurrentRoles();
+ }
+
+ TClientStatus::ECode TThreadedUpdater::GetState() const {
+ const TInstant now = TInstant::Now();
+
+ if (Settings_.IsServiceTicketFetchingRequired()) {
+ if (AreServiceTicketsInvalid(now)) {
+ return TClientStatus::Error;
+ }
+ auto tickets = GetCachedServiceTickets();
+ if (!tickets) {
+ return TClientStatus::Error;
+ }
+ if (tickets->TicketsById.size() < Destinations_.size()) {
+ if (Settings_.IsIncompleteTicketsSetAnError) {
+ return TClientStatus::Error;
+ } else {
+ return TClientStatus::IncompleteTicketsSet;
+ }
+ }
+ }
+ if ((Settings_.IsServiceTicketCheckingRequired() || Settings_.IsUserTicketCheckingRequired()) && ArePublicKeysInvalid(now)) {
+ return TClientStatus::Error;
+ }
+
+ const TDuration sincePublicKeysUpdate = now - GetUpdateTimeOfPublicKeys();
+ const TDuration sinceServiceTicketsUpdate = now - GetUpdateTimeOfServiceTickets();
+ const TDuration sinceRolesUpdate = now - GetUpdateTimeOfRoles();
+
+ if (Settings_.IsServiceTicketFetchingRequired() && sinceServiceTicketsUpdate > ServiceTicketsDurations_.Expiring) {
+ return TClientStatus::Warning;
+ }
+ if ((Settings_.IsServiceTicketCheckingRequired() || Settings_.IsUserTicketCheckingRequired()) &&
+ sincePublicKeysUpdate > PublicKeysDurations_.Expiring)
+ {
+ return TClientStatus::Warning;
+ }
+ if (RolesFetcher_ && TRolesFetcher::ShouldWarn(RetrySettings_, sinceRolesUpdate)) {
+ return TClientStatus::Warning;
+ }
+
+ return TClientStatus::Ok;
+ }
+
+ TThreadedUpdater::TThreadedUpdater(const TClientSettings& settings, TLoggerPtr logger)
+ : TThreadedUpdaterBase(
+ TRetrySettings{}.WorkerAwakingPeriod,
+ std::move(logger),
+ settings.GetTvmHost(),
+ settings.GetTvmPort(),
+ settings.TvmSocketTimeout,
+ settings.TvmConnectTimeout)
+ , ExpBackoff_(RetrySettings_.BackoffSettings)
+ , Settings_(settings.CloneNormalized())
+ , ProcInfo_(NUtils::TProcInfo::Create(Settings_.GetLibVersionPrefix()))
+ , PublicKeysUrl_(CreatePublicKeysUrl(Settings_, ProcInfo_))
+ , DstAliases_(MakeAliasMap(Settings_))
+ , Headers_({{"Content-Type", "application/x-www-form-urlencoded"}})
+ , Random_(TInstant::Now().MicroSeconds())
+ {
+ if (Settings_.IsServiceTicketFetchingRequired()) {
+ SigningContext_ = TServiceContext::SigningFactory(Settings_.GetSelfSecret());
+ }
+
+ if (Settings_.IsServiceTicketFetchingRequired()) {
+ Destinations_ = {Settings_.GetDestinations().begin(), Settings_.GetDestinations().end()};
+ }
+
+ PublicKeysDurations_.RefreshPeriod = TDuration::Days(1);
+ ServiceTicketsDurations_.RefreshPeriod = TDuration::Hours(1);
+
+ if (Settings_.IsUserTicketCheckingRequired()) {
+ SetBbEnv(Settings_.GetEnvForUserTickets());
+ }
+
+ if (Settings_.IsRolesFetchingEnabled()) {
+ RolesFetcher_ = std::make_unique<TRolesFetcher>(
+ TRolesFetcherSettings{
+ Settings_.GetTiroleHost(),
+ Settings_.GetTirolePort(),
+ Settings_.GetDiskCacheDir(),
+ ProcInfo_,
+ Settings_.GetSelfTvmId(),
+ Settings_.GetIdmSystemSlug(),
+ },
+ Logger_);
+ }
+
+ if (Settings_.IsDiskCacheUsed()) {
+ TString path = Settings_.GetDiskCacheDir();
+ if (path.back() != '/') {
+ path.push_back('/');
+ }
+
+ if (Settings_.IsServiceTicketFetchingRequired()) {
+ ServiceTicketsFilepath_ = path;
+ ServiceTicketsFilepath_.append("service_tickets");
+ }
+
+ if (Settings_.IsServiceTicketCheckingRequired() || Settings_.IsUserTicketCheckingRequired()) {
+ PublicKeysFilepath_ = path;
+ PublicKeysFilepath_.append("public_keys");
+ }
+
+ RetrySettingsFilepath_ = path + "retry_settings";
+ } else {
+ LogInfo("Disk cache disabled. Please set disk cache directory in settings for best reliability");
+ }
+ }
+
+ void TThreadedUpdater::Init() {
+ ReadStateFromDisk();
+ ClearErrors();
+ ExpBackoff_.SetEnabled(false);
+
+ // First of all try to get tickets: there are a lot of reasons to fail this request.
+ // As far as disk cache usually disabled, client will not fetch keys before fail on every ctor call.
+ UpdateServiceTickets();
+ if (!AreServicesTicketsOk()) {
+ ThrowLastError();
+ }
+
+ UpdatePublicKeys();
+ if (!IsServiceContextOk() || !IsUserContextOk()) {
+ ThrowLastError();
+ }
+
+ UpdateRoles();
+ if (RolesFetcher_ && !RolesFetcher_->AreRolesOk()) {
+ ThrowLastError();
+ }
+
+ Inited_ = true;
+ ExpBackoff_.SetEnabled(true);
+ }
+
+ void TThreadedUpdater::UpdateServiceTickets() {
+ if (!Settings_.IsServiceTicketFetchingRequired()) {
+ return;
+ }
+
+ TInstant stut = GetUpdateTimeOfServiceTickets();
+ try {
+ if (IsTimeToUpdateServiceTickets(stut)) {
+ UpdateAllServiceTickets();
+ NeedFetchMissingServiceTickets_ = false;
+ } else if (NeedFetchMissingServiceTickets_ && GetCachedServiceTickets()->TicketsById.size() < Destinations_.size()) {
+ UpdateMissingServiceTickets(Destinations_);
+ NeedFetchMissingServiceTickets_ = false;
+ }
+ if (AreServicesTicketsOk()) {
+ ClearError(EScope::ServiceTickets);
+ }
+ } catch (const std::exception& e) {
+ ProcessError(EType::Retriable, EScope::ServiceTickets, e.what());
+ LogWarning(TStringBuilder() << "Failed to update service tickets: " << e.what());
+ if (TInstant::Now() - stut > ServiceTicketsDurations_.Expiring) {
+ LogError("Service tickets have not been refreshed for too long period");
+ }
+ }
+ }
+
+ void TThreadedUpdater::UpdateAllServiceTickets() {
+ THttpResult st = GetServiceTicketsFromHttp(Destinations_, RetrySettings_.DstsLimit);
+
+ auto oldCache = GetCachedServiceTickets();
+ if (oldCache) {
+ for (const auto& pair : oldCache->ErrorsById) {
+ st.TicketsWithErrors.Errors.insert(pair);
+ }
+ }
+
+ UpdateServiceTicketsCache(std::move(st.TicketsWithErrors), TInstant::Now());
+ if (ServiceTicketsFilepath_) {
+ DiskCacheServiceTickets_ = CreateJsonArray(st.Responses);
+ TDiskWriter w(ServiceTicketsFilepath_, Logger_.Get());
+ w.Write(PrepareTicketsForDisk(DiskCacheServiceTickets_, Settings_.GetSelfTvmId()));
+ }
+ }
+
+ TServiceTicketsPtr TThreadedUpdater::UpdateMissingServiceTickets(const TDstSet& required) {
+ TServiceTicketsPtr cache = GetCachedServiceTickets();
+ TClientSettings::TDstVector dsts = FindMissingDsts(cache, required);
+
+ if (dsts.empty()) {
+ return cache;
+ }
+
+ THttpResult st = GetServiceTicketsFromHttp(dsts, RetrySettings_.DstsLimit);
+
+ size_t gotTickets = st.TicketsWithErrors.Tickets.size();
+
+ for (const auto& pair : cache->TicketsById) {
+ st.TicketsWithErrors.Tickets.insert(pair);
+ }
+ for (const auto& pair : cache->ErrorsById) {
+ st.TicketsWithErrors.Errors.insert(pair);
+ }
+ for (const auto& pair : st.TicketsWithErrors.Tickets) {
+ st.TicketsWithErrors.Errors.erase(pair.first);
+ }
+
+ TServiceTicketsPtr c = UpdateServiceTicketsCachePartly(
+ std::move(st.TicketsWithErrors),
+ gotTickets);
+ if (!c) {
+ LogWarning("UpdateMissingServiceTickets: new cache is NULL. BUG?");
+ c = cache;
+ }
+
+ if (!ServiceTicketsFilepath_) {
+ return c;
+ }
+
+ DiskCacheServiceTickets_ = AppendToJsonArray(DiskCacheServiceTickets_, st.Responses);
+
+ TDiskWriter w(ServiceTicketsFilepath_, Logger_.Get());
+ w.Write(PrepareTicketsForDisk(DiskCacheServiceTickets_, Settings_.GetSelfTvmId()));
+
+ return c;
+ }
+
+ void TThreadedUpdater::UpdatePublicKeys() {
+ if (!Settings_.IsServiceTicketCheckingRequired() && !Settings_.IsUserTicketCheckingRequired()) {
+ return;
+ }
+
+ TInstant pkut = GetUpdateTimeOfPublicKeys();
+ if (!IsTimeToUpdatePublicKeys(pkut)) {
+ return;
+ }
+
+ try {
+ TString publicKeys = GetPublicKeysFromHttp();
+
+ UpdatePublicKeysCache(publicKeys, TInstant::Now());
+ if (PublicKeysFilepath_) {
+ TDiskWriter w(PublicKeysFilepath_, Logger_.Get());
+ w.Write(publicKeys);
+ }
+ if (IsServiceContextOk() && IsUserContextOk()) {
+ ClearError(EScope::PublicKeys);
+ }
+ } catch (const std::exception& e) {
+ ProcessError(EType::Retriable, EScope::PublicKeys, e.what());
+ LogWarning(TStringBuilder() << "Failed to update public keys: " << e.what());
+ if (TInstant::Now() - pkut > PublicKeysDurations_.Expiring) {
+ LogError("Public keys have not been refreshed for too long period");
+ }
+ }
+ }
+
+ void TThreadedUpdater::UpdateRoles() {
+ if (!RolesFetcher_) {
+ return;
+ }
+
+ TInstant rut = GetUpdateTimeOfRoles();
+ if (!TRolesFetcher::IsTimeToUpdate(RetrySettings_, TInstant::Now() - rut)) {
+ return;
+ }
+
+ struct TCloser {
+ TRolesFetcher* Fetcher;
+ ~TCloser() {
+ Fetcher->ResetConnection();
+ }
+ } closer{RolesFetcher_.get()};
+
+ try {
+ TServiceTicketsPtr st = GetCachedServiceTickets();
+ Y_ENSURE(st, "No one service ticket in memory: how it possible?");
+ auto it = st->TicketsById.find(Settings_.GetTiroleTvmId());
+ Y_ENSURE(it != st->TicketsById.end(),
+ "Missing tvmid for tirole in cache: " << Settings_.GetTiroleTvmId());
+
+ RolesFetcher_->Update(
+ FetchWithRetries(
+ [&]() { return RolesFetcher_->FetchActualRoles(it->second); },
+ EScope::Roles));
+ SetUpdateTimeOfRoles(TInstant::Now());
+
+ if (RolesFetcher_->AreRolesOk()) {
+ ClearError(EScope::Roles);
+ }
+ } catch (const std::exception& e) {
+ ProcessError(EType::Retriable, EScope::Roles, e.what());
+ LogWarning(TStringBuilder() << "Failed to update roles: " << e.what());
+ if (TRolesFetcher::ShouldWarn(RetrySettings_, TInstant::Now() - rut)) {
+ LogError("Roles have not been refreshed for too long period");
+ }
+ }
+ }
+
+ TServiceTicketsPtr TThreadedUpdater::UpdateServiceTicketsCachePartly(
+ TAsyncUpdaterBase::TPairTicketsErrors&& tickets,
+ size_t got) {
+ size_t count = tickets.Tickets.size();
+ TServiceTicketsPtr c = MakeIntrusiveConst<TServiceTickets>(std::move(tickets.Tickets),
+ std::move(tickets.Errors),
+ DstAliases_);
+ SetServiceTickets(c);
+
+ LogInfo(TStringBuilder()
+ << "Cache was partly updated with " << got
+ << " service ticket(s). total: " << count);
+
+ return c;
+ }
+
+ void TThreadedUpdater::UpdateServiceTicketsCache(TPairTicketsErrors&& tickets, TInstant time) {
+ size_t count = tickets.Tickets.size();
+ SetServiceTickets(MakeIntrusiveConst<TServiceTickets>(std::move(tickets.Tickets),
+ std::move(tickets.Errors),
+ DstAliases_));
+
+ SetUpdateTimeOfServiceTickets(time);
+
+ if (count > 0) {
+ LogInfo(TStringBuilder() << "Cache was updated with " << count << " service ticket(s): " << time);
+ }
+ }
+
+ void TThreadedUpdater::UpdatePublicKeysCache(const TString& publicKeys, TInstant time) {
+ if (publicKeys.empty()) {
+ return;
+ }
+
+ if (Settings_.IsServiceTicketCheckingRequired()) {
+ SetServiceContext(MakeIntrusiveConst<TServiceContext>(
+ TServiceContext::CheckingFactory(Settings_.GetSelfTvmId(),
+ publicKeys)));
+ }
+
+ if (Settings_.IsUserTicketCheckingRequired()) {
+ SetUserContext(publicKeys);
+ }
+
+ SetUpdateTimeOfPublicKeys(time);
+
+ LogInfo(TStringBuilder() << "Cache was updated with public keys: " << time);
+ }
+
+ void TThreadedUpdater::ReadStateFromDisk() {
+ try {
+ TServiceTicketsFromDisk st = ReadServiceTicketsFromDisk();
+ UpdateServiceTicketsCache(std::move(st.TicketsWithErrors), st.BornDate);
+ DiskCacheServiceTickets_ = st.FileBody;
+ } catch (const std::exception& e) {
+ LogWarning(TStringBuilder() << "Failed to read service tickets from disk: " << e.what());
+ }
+
+ try {
+ std::pair<TString, TInstant> pk = ReadPublicKeysFromDisk();
+ UpdatePublicKeysCache(pk.first, pk.second);
+ } catch (const std::exception& e) {
+ LogWarning(TStringBuilder() << "Failed to read public keys from disk: " << e.what());
+ }
+
+ try {
+ TString rs = ReadRetrySettingsFromDisk();
+ UpdateRetrySettings(rs);
+ } catch (const std::exception& e) {
+ LogWarning(TStringBuilder() << "Failed to read retry settings from disk: " << e.what());
+ }
+
+ try {
+ if (RolesFetcher_) {
+ SetUpdateTimeOfRoles(RolesFetcher_->ReadFromDisk());
+ }
+ } catch (const std::exception& e) {
+ LogWarning(TStringBuilder() << "Failed to read roles from disk: " << e.what());
+ }
+ }
+
+ TThreadedUpdater::TServiceTicketsFromDisk TThreadedUpdater::ReadServiceTicketsFromDisk() const {
+ if (!ServiceTicketsFilepath_) {
+ return {};
+ }
+
+ TDiskReader r(ServiceTicketsFilepath_, Logger_.Get());
+ if (!r.Read()) {
+ return {};
+ }
+
+ std::pair<TStringBuf, TTvmId> data = ParseTicketsFromDisk(r.Data());
+ if (data.second != Settings_.GetSelfTvmId()) {
+ TStringStream s;
+ s << "Disk cache is for another tvmId (" << data.second << "). ";
+ s << "Self=" << Settings_.GetSelfTvmId();
+ LogWarning(s.Str());
+ return {};
+ }
+
+ TPairTicketsErrors res;
+ ParseTicketsFromResponse(data.first, Destinations_, res);
+ if (IsInvalid(TServiceTickets::GetInvalidationTime(res.Tickets), TInstant::Now())) {
+ LogWarning("Disk cache (service tickets) is too old");
+ return {};
+ }
+
+ LogInfo(TStringBuilder() << "Got " << res.Tickets.size() << " service ticket(s) from disk");
+ return {std::move(res), r.Time(), TString(data.first)};
+ }
+
+ std::pair<TString, TInstant> TThreadedUpdater::ReadPublicKeysFromDisk() const {
+ if (!PublicKeysFilepath_) {
+ return {};
+ }
+
+ TDiskReader r(PublicKeysFilepath_, Logger_.Get());
+ if (!r.Read()) {
+ return {};
+ }
+
+ if (TInstant::Now() - r.Time() > PublicKeysDurations_.Invalid) {
+ LogWarning("Disk cache (public keys) is too old");
+ return {};
+ }
+
+ return {r.Data(), r.Time()};
+ }
+
+ TString TThreadedUpdater::ReadRetrySettingsFromDisk() const {
+ if (!RetrySettingsFilepath_) {
+ return {};
+ }
+
+ TDiskReader r(RetrySettingsFilepath_, Logger_.Get());
+ if (!r.Read()) {
+ return {};
+ }
+
+ return r.Data();
+ }
+
+ template <class Dsts>
+ TThreadedUpdater::THttpResult TThreadedUpdater::GetServiceTicketsFromHttp(const Dsts& dsts, const size_t dstLimit) const {
+ Y_ENSURE(SigningContext_, "Internal error");
+
+ TClientSettings::TDstVector part;
+ part.reserve(dstLimit);
+ THttpResult res;
+ res.TicketsWithErrors.Tickets.reserve(dsts.size());
+ res.Responses.reserve(dsts.size() / dstLimit + 1);
+
+ for (auto it = dsts.begin(); it != dsts.end();) {
+ part.clear();
+ for (size_t count = 0; it != dsts.end() && count < dstLimit; ++count, ++it) {
+ part.push_back(*it);
+ }
+
+ TString response =
+ FetchWithRetries(
+ [this, &part]() {
+ // create request here to keep 'ts' actual
+ return FetchServiceTicketsFromHttp(PrepareRequestForServiceTickets(
+ Settings_.GetSelfTvmId(),
+ *SigningContext_,
+ part,
+ ProcInfo_));
+ },
+ EScope::ServiceTickets)
+ .Response;
+ ParseTicketsFromResponse(response, part, res.TicketsWithErrors);
+ LogDebug(TStringBuilder()
+ << "Response with service tickets for " << part.size()
+ << " destination(s) was successfully fetched from " << TvmUrl_);
+
+ res.Responses.push_back(response);
+ }
+
+ LogDebug(TStringBuilder()
+ << "Got responses with service tickets with " << res.Responses.size() << " pages for "
+ << dsts.size() << " destination(s)");
+ for (const auto& p : res.TicketsWithErrors.Errors) {
+ LogError(TStringBuilder()
+ << "Failed to get service ticket for dst=" << p.first << ": " << p.second);
+ }
+
+ return res;
+ }
+
+ TString TThreadedUpdater::GetPublicKeysFromHttp() const {
+ TString publicKeys =
+ FetchWithRetries(
+ [this]() { return FetchPublicKeysFromHttp(); },
+ EScope::PublicKeys)
+ .Response;
+
+ LogDebug("Public keys were successfully fetched from " + TvmUrl_);
+
+ return publicKeys;
+ }
+
+ NUtils::TFetchResult TThreadedUpdater::FetchServiceTicketsFromHttp(const TString& body) const {
+ TStringStream s;
+
+ THttpHeaders outHeaders;
+ TKeepAliveHttpClient::THttpCode code = GetClient().DoPost("/2/ticket", body, &s, Headers_, &outHeaders);
+
+ const THttpInputHeader* settings = outHeaders.FindHeader("X-Ya-Retry-Settings");
+
+ return {code, {}, "/2/ticket", s.Str(), settings ? settings->Value() : ""};
+ }
+
+ NUtils::TFetchResult TThreadedUpdater::FetchPublicKeysFromHttp() const {
+ TStringStream s;
+
+ THttpHeaders outHeaders;
+ TKeepAliveHttpClient::THttpCode code = GetClient().DoGet(PublicKeysUrl_, &s, {}, &outHeaders);
+
+ const THttpInputHeader* settings = outHeaders.FindHeader("X-Ya-Retry-Settings");
+
+ return {code, {}, "/2/keys", s.Str(), settings ? settings->Value() : ""};
+ }
+
+ bool TThreadedUpdater::UpdateRetrySettings(const TString& header) const {
+ if (header.empty()) {
+ // Probably it is some kind of test?
+ return false;
+ }
+
+ try {
+ TString raw = NUtils::Base64url2bin(header);
+ Y_ENSURE(raw, "Invalid base64url in settings");
+
+ retry_settings::v1::Settings proto;
+ Y_ENSURE(proto.ParseFromString(raw), "Invalid proto");
+
+ // This ugly hack helps to process these settings in any case
+ TThreadedUpdater& this_ = *const_cast<TThreadedUpdater*>(this);
+ TRetrySettings& res = this_.RetrySettings_;
+
+ TStringStream diff;
+ auto update = [&diff](auto& l, const auto& r, TStringBuf desc) {
+ if (l != r) {
+ diff << desc << ":" << l << "->" << r << ";";
+ l = r;
+ }
+ };
+
+ if (proto.has_exponential_backoff_min_sec()) {
+ update(res.BackoffSettings.Min,
+ TDuration::Seconds(proto.exponential_backoff_min_sec()),
+ "exponential_backoff_min");
+ }
+ if (proto.has_exponential_backoff_max_sec()) {
+ update(res.BackoffSettings.Max,
+ TDuration::Seconds(proto.exponential_backoff_max_sec()),
+ "exponential_backoff_max");
+ }
+ if (proto.has_exponential_backoff_factor()) {
+ update(res.BackoffSettings.Factor,
+ proto.exponential_backoff_factor(),
+ "exponential_backoff_factor");
+ }
+ if (proto.has_exponential_backoff_jitter()) {
+ update(res.BackoffSettings.Jitter,
+ proto.exponential_backoff_jitter(),
+ "exponential_backoff_jitter");
+ }
+ this_.ExpBackoff_.UpdateSettings(res.BackoffSettings);
+
+ if (proto.has_max_random_sleep_default()) {
+ update(res.MaxRandomSleepDefault,
+ TDuration::MilliSeconds(proto.max_random_sleep_default()),
+ "max_random_sleep_default");
+ }
+ if (proto.has_max_random_sleep_when_ok()) {
+ update(res.MaxRandomSleepWhenOk,
+ TDuration::MilliSeconds(proto.max_random_sleep_when_ok()),
+ "max_random_sleep_when_ok");
+ }
+ if (proto.has_retries_on_start()) {
+ Y_ENSURE(proto.retries_on_start(), "retries_on_start==0");
+ update(res.RetriesOnStart,
+ proto.retries_on_start(),
+ "retries_on_start");
+ }
+ if (proto.has_retries_in_background()) {
+ Y_ENSURE(proto.retries_in_background(), "retries_in_background==0");
+ update(res.RetriesInBackground,
+ proto.retries_in_background(),
+ "retries_in_background");
+ }
+ if (proto.has_worker_awaking_period_sec()) {
+ update(res.WorkerAwakingPeriod,
+ TDuration::Seconds(proto.worker_awaking_period_sec()),
+ "worker_awaking_period");
+ this_.WorkerAwakingPeriod_ = res.WorkerAwakingPeriod;
+ }
+ if (proto.has_dsts_limit()) {
+ Y_ENSURE(proto.dsts_limit(), "dsts_limit==0");
+ update(res.DstsLimit,
+ proto.dsts_limit(),
+ "dsts_limit");
+ }
+
+ if (proto.has_roles_update_period_sec()) {
+ Y_ENSURE(proto.roles_update_period_sec(), "roles_update_period==0");
+ update(res.RolesUpdatePeriod,
+ TDuration::Seconds(proto.roles_update_period_sec()),
+ "roles_update_period_sec");
+ }
+ if (proto.has_roles_warn_period_sec()) {
+ Y_ENSURE(proto.roles_warn_period_sec(), "roles_warn_period_sec==0");
+ update(res.RolesWarnPeriod,
+ TDuration::Seconds(proto.roles_warn_period_sec()),
+ "roles_warn_period_sec");
+ }
+
+ if (diff.empty()) {
+ return false;
+ }
+
+ LogDebug("Retry settings were updated: " + diff.Str());
+ return true;
+ } catch (const std::exception& e) {
+ LogWarning(TStringBuilder()
+ << "Failed to update retry settings from server, header '"
+ << header << "': "
+ << e.what());
+ }
+
+ return false;
+ }
+
+ template <typename Func>
+ NUtils::TFetchResult TThreadedUpdater::FetchWithRetries(Func func, EScope scope) const {
+ const ui32 tries = Inited_ ? RetrySettings_.RetriesInBackground
+ : RetrySettings_.RetriesOnStart;
+
+ for (size_t idx = 1;; ++idx) {
+ RandomSleep();
+
+ try {
+ NUtils::TFetchResult result = func();
+
+ if (UpdateRetrySettings(result.RetrySettings) && RetrySettingsFilepath_) {
+ TDiskWriter w(RetrySettingsFilepath_, Logger_.Get());
+ w.Write(result.RetrySettings);
+ }
+
+ if (400 <= result.Code && result.Code <= 499) {
+ throw TNonRetriableException() << ProcessHttpError(scope, result.Path, result.Code, result.Response);
+ }
+ if (result.Code < 200 || result.Code >= 399) {
+ throw yexception() << ProcessHttpError(scope, result.Path, result.Code, result.Response);
+ }
+
+ ExpBackoff_.Decrease();
+ return result;
+ } catch (const TNonRetriableException& e) {
+ LogWarning(TStringBuilder() << "Failed to get " << scope << ": " << e.what());
+ ExpBackoff_.Increase();
+ throw;
+ } catch (const std::exception& e) {
+ LogWarning(TStringBuilder() << "Failed to get " << scope << ": " << e.what());
+ ExpBackoff_.Increase();
+ if (idx >= tries) {
+ throw;
+ }
+ }
+ }
+
+ throw yexception() << "unreachable";
+ }
+
+ void TThreadedUpdater::RandomSleep() const {
+ const TDuration maxSleep = TClientStatus::ECode::Ok == GetState()
+ ? RetrySettings_.MaxRandomSleepWhenOk
+ : RetrySettings_.MaxRandomSleepDefault;
+
+ if (maxSleep) {
+ ui32 toSleep = Random_.GenRand() % maxSleep.MilliSeconds();
+ ExpBackoff_.Sleep(TDuration::MilliSeconds(toSleep));
+ }
+ }
+
+ TString TThreadedUpdater::PrepareRequestForServiceTickets(TTvmId src,
+ const TServiceContext& ctx,
+ const TClientSettings::TDstVector& dsts,
+ const NUtils::TProcInfo& procInfo,
+ time_t now) {
+ TStringStream s;
+
+ const TString ts = IntToString<10>(now);
+ TStringStream dst;
+ dst.Reserve(10 * dsts.size());
+ for (const TClientSettings::TDst& d : dsts) {
+ if (dst.Str()) {
+ dst << ',';
+ }
+ dst << d.Id;
+ }
+
+ s << "grant_type=client_credentials";
+ s << "&src=" << src;
+ s << "&dst=" << dst.Str();
+ s << "&ts=" << ts;
+ s << "&sign=" << ctx.SignCgiParamsForTvm(ts, dst.Str());
+ s << "&get_retry_settings=yes";
+
+ s << "&";
+ procInfo.AddToRequest(s);
+
+ return s.Str();
+ }
+
+ template <class Dsts>
+ void TThreadedUpdater::ParseTicketsFromResponse(TStringBuf resp,
+ const Dsts& dsts,
+ TPairTicketsErrors& out) const {
+ NJson::TJsonValue doc;
+ Y_ENSURE(NJson::ReadJsonTree(resp, &doc), "Invalid json from tvm-api: " << resp);
+
+ const NJson::TJsonValue* currentResp = doc.IsMap() ? &doc : nullptr;
+ auto find = [&currentResp, &doc](TTvmId id, NJson::TJsonValue& obj) -> bool {
+ const TString idStr = IntToString<10>(id);
+ if (currentResp && currentResp->GetValue(idStr, &obj)) {
+ return true;
+ }
+
+ for (const NJson::TJsonValue& val : doc.GetArray()) {
+ currentResp = &val;
+ if (currentResp->GetValue(idStr, &obj)) {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ for (const TClientSettings::TDst& d : dsts) {
+ NJson::TJsonValue obj;
+ NJson::TJsonValue val;
+
+ if (!find(d.Id, obj) || !obj.GetValue("ticket", &val)) {
+ TString err;
+ if (obj.GetValue("error", &val)) {
+ err = val.GetString();
+ } else {
+ err = "Missing tvm_id in response, should never happend: " + IntToString<10>(d.Id);
+ }
+
+ TStringStream s;
+ s << "Failed to get ServiceTicket for " << d.Id << ": " << err;
+ ProcessError(EType::NonRetriable, EScope::ServiceTickets, s.Str());
+
+ out.Errors.insert({d.Id, std::move(err)});
+ continue;
+ }
+
+ out.Tickets.insert({d.Id, val.GetString()});
+ }
+ }
+
+ static const char DELIMETER = '\t';
+ TString TThreadedUpdater::PrepareTicketsForDisk(TStringBuf tvmResponse, TTvmId selfId) {
+ TStringStream s;
+ s << tvmResponse << DELIMETER << selfId;
+ return s.Str();
+ }
+
+ std::pair<TStringBuf, TTvmId> TThreadedUpdater::ParseTicketsFromDisk(TStringBuf data) {
+ TStringBuf tvmId = data.RNextTok(DELIMETER);
+ return {data, IntFromString<TTvmId, 10>(tvmId)};
+ }
+
+ const TDstSet& TThreadedUpdater::GetDsts() const {
+ return Destinations_;
+ }
+
+ void TThreadedUpdater::AddDstToSettings(const TClientSettings::TDst& dst) {
+ Destinations_.insert(dst);
+ }
+
+ bool TThreadedUpdater::IsTimeToUpdateServiceTickets(TInstant lastUpdate) const {
+ return TInstant::Now() - lastUpdate > ServiceTicketsDurations_.RefreshPeriod;
+ }
+
+ bool TThreadedUpdater::IsTimeToUpdatePublicKeys(TInstant lastUpdate) const {
+ return TInstant::Now() - lastUpdate > PublicKeysDurations_.RefreshPeriod;
+ }
+
+ bool TThreadedUpdater::AreServicesTicketsOk() const {
+ if (!Settings_.IsServiceTicketFetchingRequired()) {
+ return true;
+ }
+ auto c = GetCachedServiceTickets();
+ return c && (!Settings_.IsIncompleteTicketsSetAnError || c->TicketsById.size() == Destinations_.size());
+ }
+
+ bool TThreadedUpdater::IsServiceContextOk() const {
+ if (!Settings_.IsServiceTicketCheckingRequired()) {
+ return true;
+ }
+
+ return bool(GetCachedServiceContext());
+ }
+
+ bool TThreadedUpdater::IsUserContextOk() const {
+ if (!Settings_.IsUserTicketCheckingRequired()) {
+ return true;
+ }
+ return bool(GetCachedUserContext());
+ }
+
+ void TThreadedUpdater::Worker() {
+ UpdateServiceTickets();
+ UpdatePublicKeys();
+ UpdateRoles();
+ }
+
+ TServiceTickets::TMapAliasId TThreadedUpdater::MakeAliasMap(const TClientSettings& settings) {
+ TServiceTickets::TMapAliasId res;
+
+ if (settings.HasDstAliases()) {
+ for (const auto& pair : settings.GetDstAliases()) {
+ res.insert({pair.first, pair.second.Id});
+ }
+ }
+
+ return res;
+ }
+
+ TClientSettings::TDstVector TThreadedUpdater::FindMissingDsts(TServiceTicketsPtr available, const TDstSet& required) {
+ Y_ENSURE(available);
+ TDstSet set;
+ // available->TicketsById is not sorted
+ for (const auto& pair : available->TicketsById) {
+ set.insert(pair.first);
+ }
+ return FindMissingDsts(set, required);
+ }
+
+ TClientSettings::TDstVector TThreadedUpdater::FindMissingDsts(const TDstSet& available, const TDstSet& required) {
+ TClientSettings::TDstVector res;
+ std::set_difference(required.begin(), required.end(),
+ available.begin(), available.end(),
+ std::inserter(res, res.begin()));
+ return res;
+ }
+
+ TString TThreadedUpdater::CreateJsonArray(const TSmallVec<TString>& responses) {
+ if (responses.empty()) {
+ return "[]";
+ }
+
+ size_t size = 0;
+ for (const TString& r : responses) {
+ size += r.size() + 1;
+ }
+
+ TString res;
+ res.reserve(size + 2);
+
+ res.push_back('[');
+ for (const TString& r : responses) {
+ res.append(r).push_back(',');
+ }
+ res.back() = ']';
+
+ return res;
+ }
+
+ TString TThreadedUpdater::AppendToJsonArray(const TString& json, const TSmallVec<TString>& responses) {
+ Y_ENSURE(json, "previous body required");
+
+ size_t size = 0;
+ for (const TString& r : responses) {
+ size += r.size() + 1;
+ }
+
+ TString res;
+ res.reserve(size + 2 + json.size());
+
+ res.push_back('[');
+ if (json.StartsWith('[')) {
+ Y_ENSURE(json.EndsWith(']'), "array is broken:" << json);
+ res.append(TStringBuf(json).Chop(1).Skip(1));
+ } else {
+ res.append(json);
+ }
+
+ res.push_back(',');
+ for (const TString& r : responses) {
+ res.append(r).push_back(',');
+ }
+ res.back() = ']';
+
+ return res;
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/api/threaded_updater.h b/library/cpp/tvmauth/client/misc/api/threaded_updater.h
new file mode 100644
index 0000000000..e546bbe030
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/api/threaded_updater.h
@@ -0,0 +1,140 @@
+#pragma once
+
+#include "retry_settings.h"
+#include "roles_fetcher.h"
+#include "settings.h"
+
+#include <library/cpp/tvmauth/client/misc/async_updater.h>
+#include <library/cpp/tvmauth/client/misc/threaded_updater.h>
+
+#include <util/generic/set.h>
+#include <util/random/fast.h>
+
+namespace NTvmAuth::NTvmApi {
+ using TDstSet = TSet<TClientSettings::TDst>;
+
+ class TThreadedUpdater: public TThreadedUpdaterBase {
+ public:
+ /*!
+ * Starts thread for updating of in-memory cache in background
+ * Reads cache from disk if specified
+ * @param settings
+ * @param logger is usefull for monitoring and debuging
+ */
+ static TAsyncUpdaterPtr Create(const TClientSettings& settings, TLoggerPtr logger);
+ ~TThreadedUpdater();
+
+ TClientStatus GetStatus() const override;
+ NRoles::TRolesPtr GetRoles() const override;
+
+ protected: // for tests
+ TClientStatus::ECode GetState() const;
+
+ TThreadedUpdater(const TClientSettings& settings, TLoggerPtr logger);
+ void Init();
+
+ void UpdateServiceTickets();
+ void UpdateAllServiceTickets();
+ TServiceTicketsPtr UpdateMissingServiceTickets(const TDstSet& required);
+ void UpdatePublicKeys();
+ void UpdateRoles();
+
+ TServiceTicketsPtr UpdateServiceTicketsCachePartly(TPairTicketsErrors&& tickets, size_t got);
+ void UpdateServiceTicketsCache(TPairTicketsErrors&& tickets, TInstant time);
+ void UpdatePublicKeysCache(const TString& publicKeys, TInstant time);
+
+ void ReadStateFromDisk();
+
+ struct TServiceTicketsFromDisk {
+ TPairTicketsErrors TicketsWithErrors;
+ TInstant BornDate;
+ TString FileBody;
+ };
+
+ TServiceTicketsFromDisk ReadServiceTicketsFromDisk() const;
+ std::pair<TString, TInstant> ReadPublicKeysFromDisk() const;
+ TString ReadRetrySettingsFromDisk() const;
+
+ struct THttpResult {
+ TPairTicketsErrors TicketsWithErrors;
+ TSmallVec<TString> Responses;
+ };
+
+ template <class Dsts>
+ THttpResult GetServiceTicketsFromHttp(const Dsts& dsts, const size_t dstLimit) const;
+ TString GetPublicKeysFromHttp() const;
+
+ virtual NUtils::TFetchResult FetchServiceTicketsFromHttp(const TString& body) const;
+ virtual NUtils::TFetchResult FetchPublicKeysFromHttp() const;
+
+ bool UpdateRetrySettings(const TString& header) const;
+
+ template <typename Func>
+ NUtils::TFetchResult FetchWithRetries(Func func, EScope scope) const;
+ void RandomSleep() const;
+
+ static TString PrepareRequestForServiceTickets(TTvmId src,
+ const TServiceContext& ctx,
+ const TClientSettings::TDstVector& dsts,
+ const NUtils::TProcInfo& procInfo,
+ time_t now = time(nullptr));
+ template <class Dsts>
+ void ParseTicketsFromResponse(TStringBuf resp,
+ const Dsts& dsts,
+ TPairTicketsErrors& out) const;
+
+ static TString PrepareTicketsForDisk(TStringBuf tvmResponse, TTvmId selfId);
+ static std::pair<TStringBuf, TTvmId> ParseTicketsFromDisk(TStringBuf data);
+
+ const TDstSet& GetDsts() const;
+ void AddDstToSettings(const TClientSettings::TDst& dst);
+
+ bool IsTimeToUpdateServiceTickets(TInstant lastUpdate) const;
+ bool IsTimeToUpdatePublicKeys(TInstant lastUpdate) const;
+
+ bool AreServicesTicketsOk() const;
+ bool IsServiceContextOk() const;
+ bool IsUserContextOk() const;
+
+ void Worker() override;
+
+ static TServiceTickets::TMapAliasId MakeAliasMap(const TClientSettings& settings);
+ static TClientSettings::TDstVector FindMissingDsts(TServiceTicketsPtr available, const TDstSet& required);
+ static TClientSettings::TDstVector FindMissingDsts(const TDstSet& available, const TDstSet& required);
+
+ static TString CreateJsonArray(const TSmallVec<TString>& responses);
+ static TString AppendToJsonArray(const TString& json, const TSmallVec<TString>& responses);
+
+ private:
+ TRetrySettings RetrySettings_;
+
+ protected:
+ mutable TExponentialBackoff ExpBackoff_;
+
+ private:
+ const TClientSettings Settings_;
+
+ const NUtils::TProcInfo ProcInfo_;
+
+ const TString PublicKeysUrl_;
+
+ const TServiceTickets::TMapAliasId DstAliases_;
+
+ const TKeepAliveHttpClient::THeaders Headers_;
+ TMaybe<TServiceContext> SigningContext_;
+
+ TDstSet Destinations_;
+ TString DiskCacheServiceTickets_;
+ bool NeedFetchMissingServiceTickets_ = true;
+
+ TString PublicKeysFilepath_;
+ TString ServiceTicketsFilepath_;
+ TString RetrySettingsFilepath_;
+
+ std::unique_ptr<TRolesFetcher> RolesFetcher_;
+
+ mutable TReallyFastRng32 Random_;
+
+ bool Inited_ = false;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/async_updater.cpp b/library/cpp/tvmauth/client/misc/async_updater.cpp
new file mode 100644
index 0000000000..9cb0332ed4
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/async_updater.cpp
@@ -0,0 +1,152 @@
+#include "async_updater.h"
+
+#include "utils.h"
+
+#include <library/cpp/tvmauth/client/exception.h>
+
+#include <util/string/builder.h>
+#include <util/system/spin_wait.h>
+
+namespace NTvmAuth {
+ TAsyncUpdaterBase::TAsyncUpdaterBase() {
+ ServiceTicketsDurations_.RefreshPeriod = TDuration::Hours(1);
+ ServiceTicketsDurations_.Expiring = TDuration::Hours(2);
+ ServiceTicketsDurations_.Invalid = TDuration::Hours(11);
+
+ PublicKeysDurations_.RefreshPeriod = TDuration::Days(1);
+ PublicKeysDurations_.Expiring = TDuration::Days(2);
+ PublicKeysDurations_.Invalid = TDuration::Days(6);
+ }
+
+ NRoles::TRolesPtr TAsyncUpdaterBase::GetRoles() const {
+ ythrow TIllegalUsage() << "not implemented";
+ }
+
+ TInstant TAsyncUpdaterBase::GetUpdateTimeOfPublicKeys() const {
+ return PublicKeysTime_.Get();
+ }
+
+ TInstant TAsyncUpdaterBase::GetUpdateTimeOfServiceTickets() const {
+ return ServiceTicketsTime_.Get();
+ }
+
+ TInstant TAsyncUpdaterBase::GetUpdateTimeOfRoles() const {
+ return RolesTime_.Get();
+ }
+
+ TInstant TAsyncUpdaterBase::GetInvalidationTimeOfPublicKeys() const {
+ TInstant ins = GetUpdateTimeOfPublicKeys();
+ return ins == TInstant() ? TInstant() : ins + PublicKeysDurations_.Invalid;
+ }
+
+ TInstant TAsyncUpdaterBase::GetInvalidationTimeOfServiceTickets() const {
+ TServiceTicketsPtr c = GetCachedServiceTickets();
+ return c ? c->InvalidationTime : TInstant();
+ }
+
+ bool TAsyncUpdaterBase::ArePublicKeysInvalid(TInstant now) const {
+ return IsInvalid(GetInvalidationTimeOfPublicKeys(), now);
+ }
+
+ bool TAsyncUpdaterBase::AreServiceTicketsInvalid(TInstant now) const {
+ TServiceTicketsPtr c = GetCachedServiceTickets();
+ // Empty set of tickets is allways valid.
+ return c && !c->TicketsById.empty() && IsInvalid(GetInvalidationTimeOfServiceTickets(), now);
+ }
+
+ bool TAsyncUpdaterBase::IsInvalid(TInstant invTime, TInstant now) {
+ return invTime -
+ TDuration::Minutes(1) // lag for closing from balancer
+ < now;
+ }
+
+ void TAsyncUpdaterBase::SetBbEnv(EBlackboxEnv original, TMaybe<EBlackboxEnv> overrided) {
+ if (overrided) {
+ Y_ENSURE_EX(NUtils::CheckBbEnvOverriding(original, *overrided),
+ TBrokenTvmClientSettings() << "Overriding of BlackboxEnv is illegal: "
+ << original << " -> " << *overrided);
+ }
+
+ Envs_.store({original, overrided}, std::memory_order_relaxed);
+ }
+
+ TServiceTicketsPtr TAsyncUpdaterBase::GetCachedServiceTickets() const {
+ return ServiceTickets_.Get();
+ }
+
+ TServiceContextPtr TAsyncUpdaterBase::GetCachedServiceContext() const {
+ return ServiceContext_.Get();
+ }
+
+ TUserContextPtr TAsyncUpdaterBase::GetCachedUserContext(TMaybe<EBlackboxEnv> overridenEnv) const {
+ TAllUserContextsPtr ctx = AllUserContexts_.Get();
+ if (!ctx) {
+ return nullptr;
+ }
+
+ const TEnvs envs = Envs_.load(std::memory_order_relaxed);
+ if (!envs.Original) {
+ return nullptr;
+ }
+
+ EBlackboxEnv env = *envs.Original;
+
+ if (overridenEnv) {
+ Y_ENSURE_EX(NUtils::CheckBbEnvOverriding(*envs.Original, *overridenEnv),
+ TBrokenTvmClientSettings() << "Overriding of BlackboxEnv is illegal: "
+ << *envs.Original << " -> " << *overridenEnv);
+ env = *overridenEnv;
+ } else if (envs.Overrided) {
+ env = *envs.Overrided;
+ }
+
+ return ctx->Get(env);
+ }
+
+ void TAsyncUpdaterBase::SetServiceTickets(TServiceTicketsPtr c) {
+ ServiceTickets_.Set(std::move(c));
+ }
+
+ void TAsyncUpdaterBase::SetServiceContext(TServiceContextPtr c) {
+ ServiceContext_.Set(std::move(c));
+ }
+
+ void TAsyncUpdaterBase::SetUserContext(TStringBuf publicKeys) {
+ AllUserContexts_.Set(MakeIntrusiveConst<TAllUserContexts>(publicKeys));
+ }
+
+ void TAsyncUpdaterBase::SetUpdateTimeOfPublicKeys(TInstant ins) {
+ PublicKeysTime_.Set(ins);
+ }
+
+ void TAsyncUpdaterBase::SetUpdateTimeOfServiceTickets(TInstant ins) {
+ ServiceTicketsTime_.Set(ins);
+ }
+
+ void TAsyncUpdaterBase::SetUpdateTimeOfRoles(TInstant ins) {
+ RolesTime_.Set(ins);
+ }
+
+ bool TAsyncUpdaterBase::IsServiceTicketMapOk(TServiceTicketsPtr c, size_t expectedTicketCount, bool strict) {
+ return c &&
+ (strict
+ ? c->TicketsById.size() == expectedTicketCount
+ : !c->TicketsById.empty());
+ }
+
+ TAllUserContexts::TAllUserContexts(TStringBuf publicKeys) {
+ auto add = [&, this](EBlackboxEnv env) {
+ Ctx_[(size_t)env] = MakeIntrusiveConst<TUserContext>(env, publicKeys);
+ };
+
+ add(EBlackboxEnv::Prod);
+ add(EBlackboxEnv::Test);
+ add(EBlackboxEnv::ProdYateam);
+ add(EBlackboxEnv::TestYateam);
+ add(EBlackboxEnv::Stress);
+ }
+
+ TUserContextPtr TAllUserContexts::Get(EBlackboxEnv env) const {
+ return Ctx_[(size_t)env];
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/async_updater.h b/library/cpp/tvmauth/client/misc/async_updater.h
new file mode 100644
index 0000000000..7b556d7a38
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/async_updater.h
@@ -0,0 +1,183 @@
+#pragma once
+
+#include "last_error.h"
+#include "settings.h"
+#include "roles/roles.h"
+
+#include <library/cpp/tvmauth/client/client_status.h>
+#include <library/cpp/tvmauth/client/logger.h>
+
+#include <library/cpp/tvmauth/deprecated/service_context.h>
+#include <library/cpp/tvmauth/deprecated/user_context.h>
+#include <library/cpp/tvmauth/src/utils.h>
+
+#include <util/datetime/base.h>
+#include <util/generic/hash.h>
+#include <util/generic/maybe.h>
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+
+#include <array>
+#include <atomic>
+
+namespace NTvmAuth::NInternal {
+ class TClientCaningKnife;
+}
+
+namespace NTvmAuth {
+ class TServiceTickets: public TAtomicRefCount<TServiceTickets> {
+ public:
+ using TMapAliasStr = THashMap<TClientSettings::TAlias, TString>;
+ using TMapIdStr = THashMap<TTvmId, TString>;
+ using TIdSet = THashSet<TTvmId>;
+ using TAliasSet = THashSet<TClientSettings::TAlias>;
+ using TMapAliasId = THashMap<TClientSettings::TAlias, TTvmId>;
+
+ TServiceTickets(TMapIdStr&& tickets, TMapIdStr&& errors, const TMapAliasId& dstMap)
+ : TicketsById(std::move(tickets))
+ , ErrorsById(std::move(errors))
+ {
+ InitAliasesAndUnfetchedIds(dstMap);
+ InitInvalidationTime();
+ }
+
+ static TInstant GetInvalidationTime(const TMapIdStr& ticketsById) {
+ TInstant res;
+
+ for (const auto& pair : ticketsById) {
+ TMaybe<TInstant> t = NTvmAuth::NInternal::TCanningKnife::GetExpirationTime(pair.second);
+ if (!t) {
+ continue;
+ }
+
+ res = res == TInstant() ? *t : std::min(res, *t);
+ }
+
+ return res;
+ }
+
+ public:
+ TMapIdStr TicketsById;
+ TMapIdStr ErrorsById;
+ TMapAliasStr TicketsByAlias;
+ TMapAliasStr ErrorsByAlias;
+ TInstant InvalidationTime;
+ TIdSet UnfetchedIds;
+ TAliasSet UnfetchedAliases;
+
+ private:
+ void InitAliasesAndUnfetchedIds(const TMapAliasId& dstMap) {
+ for (const auto& pair : dstMap) {
+ auto it = TicketsById.find(pair.second);
+ auto errIt = ErrorsById.find(pair.second);
+
+ if (it == TicketsById.end()) {
+ if (errIt != ErrorsById.end()) {
+ Y_ENSURE(ErrorsByAlias.insert({pair.first, errIt->second}).second,
+ "failed to add: " << pair.first);
+ } else {
+ UnfetchedAliases.insert(pair.first);
+ UnfetchedIds.insert(pair.second);
+ }
+ } else {
+ Y_ENSURE(TicketsByAlias.insert({pair.first, it->second}).second,
+ "failed to add: " << pair.first);
+ }
+ }
+ }
+
+ void InitInvalidationTime() {
+ InvalidationTime = GetInvalidationTime(TicketsById);
+ }
+ };
+ using TServiceTicketsPtr = TIntrusiveConstPtr<TServiceTickets>;
+
+ class TAllUserContexts: public TAtomicRefCount<TAllUserContexts> {
+ public:
+ TAllUserContexts(TStringBuf publicKeys);
+
+ TUserContextPtr Get(EBlackboxEnv env) const;
+
+ private:
+ std::array<TUserContextPtr, 5> Ctx_;
+ };
+ using TAllUserContextsPtr = TIntrusiveConstPtr<TAllUserContexts>;
+
+ class TAsyncUpdaterBase: public TAtomicRefCount<TAsyncUpdaterBase>, protected TLastError, TNonCopyable {
+ public:
+ TAsyncUpdaterBase();
+ virtual ~TAsyncUpdaterBase() = default;
+
+ virtual TClientStatus GetStatus() const = 0;
+ virtual NRoles::TRolesPtr GetRoles() const;
+
+ TServiceTicketsPtr GetCachedServiceTickets() const;
+ TServiceContextPtr GetCachedServiceContext() const;
+ TUserContextPtr GetCachedUserContext(TMaybe<EBlackboxEnv> overridenEnv = {}) const;
+
+ TInstant GetUpdateTimeOfPublicKeys() const;
+ TInstant GetUpdateTimeOfServiceTickets() const;
+ TInstant GetUpdateTimeOfRoles() const;
+ TInstant GetInvalidationTimeOfPublicKeys() const;
+ TInstant GetInvalidationTimeOfServiceTickets() const;
+
+ bool ArePublicKeysInvalid(TInstant now) const;
+ bool AreServiceTicketsInvalid(TInstant now) const;
+ static bool IsInvalid(TInstant invTime, TInstant now);
+
+ protected:
+ void SetBbEnv(EBlackboxEnv original, TMaybe<EBlackboxEnv> overrided = {});
+
+ void SetServiceTickets(TServiceTicketsPtr c);
+ void SetServiceContext(TServiceContextPtr c);
+ void SetUserContext(TStringBuf publicKeys);
+ void SetUpdateTimeOfPublicKeys(TInstant ins);
+ void SetUpdateTimeOfServiceTickets(TInstant ins);
+ void SetUpdateTimeOfRoles(TInstant ins);
+
+ static bool IsServiceTicketMapOk(TServiceTicketsPtr c, size_t expectedTicketCount, bool strict);
+
+ protected:
+ struct TPairTicketsErrors {
+ TServiceTickets::TMapIdStr Tickets;
+ TServiceTickets::TMapIdStr Errors;
+
+ bool operator==(const TPairTicketsErrors& o) const {
+ return Tickets == o.Tickets && Errors == o.Errors;
+ }
+ };
+
+ struct TStateDurations {
+ TDuration RefreshPeriod;
+ TDuration Expiring;
+ TDuration Invalid;
+ };
+
+ TStateDurations ServiceTicketsDurations_;
+ TStateDurations PublicKeysDurations_;
+
+ protected:
+ virtual void StartTvmClientStopping() const {
+ }
+ virtual bool IsTvmClientStopped() const {
+ return true;
+ }
+ friend class NTvmAuth::NInternal::TClientCaningKnife;
+
+ private:
+ struct TEnvs {
+ TMaybe<EBlackboxEnv> Original;
+ TMaybe<EBlackboxEnv> Overrided;
+ };
+ static_assert(sizeof(TEnvs) <= 8, "Small struct is easy to store as atomic");
+ std::atomic<TEnvs> Envs_ = {{}};
+
+ NUtils::TProtectedValue<TServiceTicketsPtr> ServiceTickets_;
+ NUtils::TProtectedValue<TServiceContextPtr> ServiceContext_;
+ NUtils::TProtectedValue<TAllUserContextsPtr> AllUserContexts_;
+ NUtils::TProtectedValue<TInstant> PublicKeysTime_;
+ NUtils::TProtectedValue<TInstant> ServiceTicketsTime_;
+ NUtils::TProtectedValue<TInstant> RolesTime_;
+ };
+ using TAsyncUpdaterPtr = TIntrusiveConstPtr<TAsyncUpdaterBase>;
+}
diff --git a/library/cpp/tvmauth/client/misc/checker.h b/library/cpp/tvmauth/client/misc/checker.h
new file mode 100644
index 0000000000..e8ed2f5503
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/checker.h
@@ -0,0 +1,67 @@
+#pragma once
+
+#include "async_updater.h"
+
+#include <library/cpp/tvmauth/client/exception.h>
+
+#include <library/cpp/tvmauth/checked_service_ticket.h>
+#include <library/cpp/tvmauth/checked_user_ticket.h>
+
+namespace NTvmAuth {
+ class TServiceTicketChecker {
+ public:
+ TServiceTicketChecker(TAsyncUpdaterPtr updater)
+ : Updater_(std::move(updater))
+ {
+ Y_ENSURE(Updater_);
+ GetCache();
+ }
+
+ /*!
+ * Checking must be enabled in TClientSettings
+ * Can throw exception if cache is out of date or wrong config
+ * @param ticket
+ */
+ TCheckedServiceTicket Check(TStringBuf ticket) const {
+ return GetCache()->Check(ticket);
+ }
+
+ private:
+ TServiceContextPtr GetCache() const {
+ TServiceContextPtr c = Updater_->GetCachedServiceContext();
+ Y_ENSURE_EX(c, TBrokenTvmClientSettings() << "Need to use TClientSettings::EnableServiceTicketChecking()");
+ return c;
+ }
+
+ private:
+ TAsyncUpdaterPtr Updater_;
+ };
+
+ class TUserTicketChecker {
+ public:
+ TUserTicketChecker(TAsyncUpdaterPtr updater)
+ : Updater_(std::move(updater))
+ {
+ Y_ENSURE(Updater_);
+ GetCache({});
+ }
+
+ /*!
+ * Blackbox enviroment must be cofingured in TClientSettings
+ * Can throw exception if cache is out of date or wrong config
+ */
+ TCheckedUserTicket Check(TStringBuf ticket, TMaybe<EBlackboxEnv> overridenEnv) const {
+ return GetCache(overridenEnv)->Check(ticket);
+ }
+
+ private:
+ TUserContextPtr GetCache(TMaybe<EBlackboxEnv> overridenEnv) const {
+ TUserContextPtr c = Updater_->GetCachedUserContext(overridenEnv);
+ Y_ENSURE_EX(c, TBrokenTvmClientSettings() << "Need to use TClientSettings::EnableUserTicketChecking()");
+ return c;
+ }
+
+ private:
+ TAsyncUpdaterPtr Updater_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/default_uid_checker.h b/library/cpp/tvmauth/client/misc/default_uid_checker.h
new file mode 100644
index 0000000000..1594f826bd
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/default_uid_checker.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "async_updater.h"
+
+#include <library/cpp/tvmauth/client/exception.h>
+
+#include <library/cpp/tvmauth/checked_user_ticket.h>
+#include <library/cpp/tvmauth/src/user_impl.h>
+
+namespace NTvmAuth {
+ class TDefaultUidChecker {
+ public:
+ TDefaultUidChecker(TAsyncUpdaterPtr updater)
+ : Updater_(std::move(updater))
+ {
+ Y_ENSURE(Updater_);
+ GetCache();
+ }
+
+ /*!
+ * Checking must be enabled in TClientSettings
+ * Can throw exception if cache is out of date or wrong config
+ * @param ticket
+ */
+ TCheckedUserTicket Check(TCheckedUserTicket ticket) const {
+ NRoles::TConsumerRolesPtr roles = GetCache()->GetRolesForUser(ticket);
+ if (roles) {
+ return ticket;
+ }
+
+ TUserTicketImplPtr impl = THolder(NInternal::TCanningKnife::GetU(ticket));
+ impl->SetStatus(ETicketStatus::NoRoles);
+ return TCheckedUserTicket(std::move(impl));
+ }
+
+ private:
+ NRoles::TRolesPtr GetCache() const {
+ NRoles::TRolesPtr c = Updater_->GetRoles();
+ Y_ENSURE_EX(c, TBrokenTvmClientSettings() << "Need to use TClientSettings::EnableRolesFetching()");
+ return c;
+ }
+
+ private:
+ TAsyncUpdaterPtr Updater_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/disk_cache.cpp b/library/cpp/tvmauth/client/misc/disk_cache.cpp
new file mode 100644
index 0000000000..3c01be4a83
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/disk_cache.cpp
@@ -0,0 +1,165 @@
+#include "disk_cache.h"
+
+#include <library/cpp/tvmauth/client/logger.h>
+
+#include <contrib/libs/openssl/include/openssl/evp.h>
+#include <contrib/libs/openssl/include/openssl/hmac.h>
+#include <contrib/libs/openssl/include/openssl/sha.h>
+
+#include <util/folder/path.h>
+#include <util/stream/file.h>
+#include <util/stream/str.h>
+#include <util/system/fs.h>
+#include <util/system/sysstat.h>
+#include <util/system/tempfile.h>
+
+#include <exception>
+
+namespace NTvmAuth {
+ static const size_t HASH_SIZE = 32;
+ static const size_t TIMESTAMP_SIZE = sizeof(time_t);
+
+ TDiskReader::TDiskReader(const TString& filename, ILogger* logger)
+ : Filename_(filename)
+ , Logger_(logger)
+ {
+ }
+
+ bool TDiskReader::Read() {
+ TStringStream s;
+
+ try {
+ if (!NFs::Exists(Filename_)) {
+ if (Logger_) {
+ s << "File '" << Filename_ << "' does not exist";
+ Logger_->Debug(s.Str());
+ }
+ return false;
+ }
+
+ TFile file(Filename_, OpenExisting | RdOnly | Seq);
+ file.Flock(LOCK_SH | LOCK_NB);
+
+ TFileInput input(file);
+ return ParseData(input.ReadAll());
+ } catch (const std::exception& e) {
+ if (Logger_) {
+ s << "Failed to read '" << Filename_ << "': " << e.what();
+ Logger_->Error(s.Str());
+ }
+ }
+
+ return false;
+ }
+
+ bool TDiskReader::ParseData(TStringBuf buf) {
+ TStringStream s;
+
+ if (buf.size() <= HASH_SIZE + TIMESTAMP_SIZE) {
+ if (Logger_) {
+ s << "File '" << Filename_ << "' is too small";
+ Logger_->Warning(s.Str());
+ }
+ return false;
+ }
+
+ TStringBuf hash = buf.SubStr(0, HASH_SIZE);
+ if (hash != GetHash(buf.Skip(HASH_SIZE))) {
+ if (Logger_) {
+ s << "Content of '" << Filename_ << "' was incorrectly changed";
+ Logger_->Warning(s.Str());
+ }
+ return false;
+ }
+
+ Time_ = TInstant::Seconds(GetTimestamp(buf.substr(0, TIMESTAMP_SIZE)));
+ Data_ = buf.Skip(TIMESTAMP_SIZE);
+
+ if (Logger_) {
+ s << "File '" << Filename_ << "' was successfully read";
+ Logger_->Info(s.Str());
+ }
+ return true;
+ }
+
+ TString TDiskReader::GetHash(TStringBuf data) {
+ TString value(EVP_MAX_MD_SIZE, 0);
+ unsigned macLen = 0;
+ if (!::HMAC(EVP_sha256(),
+ "",
+ 0,
+ (unsigned char*)data.data(),
+ data.size(),
+ (unsigned char*)value.data(),
+ &macLen)) {
+ return {};
+ }
+
+ if (macLen != EVP_MAX_MD_SIZE) {
+ value.resize(macLen);
+ }
+
+ return value;
+ }
+
+ time_t TDiskReader::GetTimestamp(TStringBuf data) {
+ time_t time = 0;
+ for (int idx = TIMESTAMP_SIZE - 1; idx >= 0; --idx) {
+ time <<= 8;
+ time |= static_cast<unsigned char>(data.at(idx));
+ }
+ return time;
+ }
+
+ TDiskWriter::TDiskWriter(const TString& filename, ILogger* logger)
+ : Filename_(filename)
+ , Logger_(logger)
+ {
+ }
+
+ bool TDiskWriter::Write(TStringBuf data, TInstant now) {
+ TStringStream s;
+
+ try {
+ {
+ if (NFs::Exists(Filename_)) {
+ Chmod(Filename_.c_str(),
+ S_IRUSR | S_IWUSR); // 600
+ }
+
+ TFile file(Filename_, CreateAlways | WrOnly | Seq | AWUser | ARUser);
+ file.Flock(LOCK_EX | LOCK_NB);
+
+ TFileOutput output(file);
+ output << PrepareData(now, data);
+ }
+
+ if (Logger_) {
+ s << "File '" << Filename_ << "' was successfully written";
+ Logger_->Info(s.Str());
+ }
+ return true;
+ } catch (const std::exception& e) {
+ if (Logger_) {
+ s << "Failed to write '" << Filename_ << "': " << e.what();
+ Logger_->Error(s.Str());
+ }
+ }
+
+ return false;
+ }
+
+ TString TDiskWriter::PrepareData(TInstant time, TStringBuf data) {
+ TString toHash = WriteTimestamp(time.TimeT()) + data;
+ return TDiskReader::GetHash(toHash) + toHash;
+ }
+
+ TString TDiskWriter::WriteTimestamp(time_t time) {
+ TString res(TIMESTAMP_SIZE, 0);
+ for (size_t idx = 0; idx < TIMESTAMP_SIZE; ++idx) {
+ res[idx] = time & 0xFF;
+ time >>= 8;
+ }
+ return res;
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/disk_cache.h b/library/cpp/tvmauth/client/misc/disk_cache.h
new file mode 100644
index 0000000000..9e77556f86
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/disk_cache.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <util/datetime/base.h>
+#include <util/generic/string.h>
+
+namespace NTvmAuth {
+ class ILogger;
+
+ class TDiskReader {
+ public:
+ TDiskReader(const TString& filename, ILogger* logger = nullptr);
+
+ bool Read();
+
+ const TString& Data() const {
+ return Data_;
+ }
+
+ TInstant Time() const {
+ return Time_;
+ }
+
+ public: // for tests
+ bool ParseData(TStringBuf buf);
+
+ static TString GetHash(TStringBuf data);
+ static time_t GetTimestamp(TStringBuf data);
+
+ private:
+ TString Filename_;
+ ILogger* Logger_;
+ TInstant Time_;
+ TString Data_;
+ };
+
+ class TDiskWriter {
+ public:
+ TDiskWriter(const TString& filename, ILogger* logger = nullptr);
+
+ bool Write(TStringBuf data, TInstant now = TInstant::Now());
+
+ public: // for tests
+ static TString PrepareData(TInstant time, TStringBuf data);
+ static TString WriteTimestamp(time_t time);
+
+ private:
+ TString Filename_;
+ ILogger* Logger_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/exponential_backoff.h b/library/cpp/tvmauth/client/misc/exponential_backoff.h
new file mode 100644
index 0000000000..89a7a3c8ad
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/exponential_backoff.h
@@ -0,0 +1,94 @@
+#pragma once
+
+#include <util/datetime/base.h>
+#include <util/random/normal.h>
+#include <util/system/event.h>
+
+#include <atomic>
+
+namespace NTvmAuth {
+ // https://habr.com/ru/post/227225/
+ class TExponentialBackoff {
+ public:
+ struct TSettings {
+ TDuration Min;
+ TDuration Max;
+ double Factor = 1.001;
+ double Jitter = 0;
+
+ bool operator==(const TSettings& o) const {
+ return Min == o.Min &&
+ Max == o.Max &&
+ Factor == o.Factor &&
+ Jitter == o.Jitter;
+ }
+ };
+
+ TExponentialBackoff(const TSettings& settings, bool isEnabled = true)
+ : CurrentValue_(settings.Min)
+ , IsEnabled_(isEnabled)
+ {
+ UpdateSettings(settings);
+ }
+
+ void UpdateSettings(const TSettings& settings) {
+ Y_ENSURE(settings.Factor > 1, "factor=" << settings.Factor << ". Should be > 1");
+ Y_ENSURE(settings.Jitter >= 0 && settings.Jitter < 1, "jitter should be in range [0, 1)");
+
+ Min_ = settings.Min;
+ Max_ = settings.Max;
+ Factor_ = settings.Factor;
+ Jitter_ = settings.Jitter;
+ }
+
+ TDuration Increase() {
+ CurrentValue_ = std::min(CurrentValue_ * Factor_, Max_);
+
+ double rnd = StdNormalRandom<double>();
+ const bool isNegative = rnd < 0;
+ rnd = std::abs(rnd);
+
+ const TDuration diff = rnd * Jitter_ * CurrentValue_;
+ if (isNegative) {
+ CurrentValue_ -= diff;
+ } else {
+ CurrentValue_ += diff;
+ }
+
+ return CurrentValue_;
+ }
+
+ TDuration Decrease() {
+ CurrentValue_ = std::max(CurrentValue_ / Factor_, Min_);
+ return CurrentValue_;
+ }
+
+ void Sleep(TDuration add = TDuration()) {
+ if (IsEnabled_.load(std::memory_order_relaxed)) {
+ Ev_.WaitT(CurrentValue_ + add);
+ }
+ }
+
+ void Interrupt() {
+ Ev_.Signal();
+ }
+
+ TDuration GetCurrentValue() const {
+ return CurrentValue_;
+ }
+
+ void SetEnabled(bool val) {
+ IsEnabled_.store(val);
+ }
+
+ private:
+ TDuration Min_;
+ TDuration Max_;
+ double Factor_;
+ double Jitter_;
+ TDuration CurrentValue_;
+ std::atomic_bool IsEnabled_;
+
+ TAutoEvent Ev_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/fetch_result.h b/library/cpp/tvmauth/client/misc/fetch_result.h
new file mode 100644
index 0000000000..4b0774e92f
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/fetch_result.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <library/cpp/http/simple/http_client.h>
+
+namespace NTvmAuth::NUtils {
+ struct TFetchResult {
+ TKeepAliveHttpClient::THttpCode Code;
+ THttpHeaders Headers;
+ TStringBuf Path;
+ TString Response;
+ TString RetrySettings;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/getter.h b/library/cpp/tvmauth/client/misc/getter.h
new file mode 100644
index 0000000000..b0327d69e9
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/getter.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include "checker.h"
+
+namespace NTvmAuth {
+ class TServiceTicketGetter {
+ public:
+ TServiceTicketGetter(TAsyncUpdaterPtr updater)
+ : Updater_(std::move(updater))
+ {
+ Y_ENSURE(Updater_);
+ GetCache();
+ }
+
+ /*!
+ * Fetching must enabled in TClientSettings
+ * Can throw exception if cache is invalid or wrong config
+ * @param dst
+ */
+ TString GetTicket(const TClientSettings::TAlias& dst) const {
+ TServiceTicketsPtr c = GetCache();
+ return GetTicketImpl(dst, c->TicketsByAlias, c->ErrorsByAlias, c->UnfetchedAliases);
+ }
+
+ TString GetTicket(const TTvmId dst) const {
+ TServiceTicketsPtr c = GetCache();
+ return GetTicketImpl(dst, c->TicketsById, c->ErrorsById, c->UnfetchedIds);
+ }
+
+ private:
+ template <class Key, class Cont, class UnfetchedCont>
+ TString GetTicketImpl(const Key& dst, const Cont& tickets, const Cont& errors, const UnfetchedCont& unfetched) const {
+ auto it = tickets.find(dst);
+ if (it != tickets.end()) {
+ return it->second;
+ }
+
+ it = errors.find(dst);
+ if (it != errors.end()) {
+ ythrow TMissingServiceTicket()
+ << "Failed to get ticket for '" << dst << "': "
+ << it->second;
+ }
+
+ if (unfetched.contains(dst)) {
+ ythrow TMissingServiceTicket()
+ << "Failed to get ticket for '" << dst << "': this dst was not fetched yet.";
+ }
+
+ ythrow TBrokenTvmClientSettings()
+ << "Destination '" << dst << "' was not specified in settings. "
+ << "Check your settings (if you use Qloud/YP/tvmtool - check it's settings)";
+ }
+
+ private:
+ TServiceTicketsPtr GetCache() const {
+ TServiceTicketsPtr c = Updater_->GetCachedServiceTickets();
+ Y_ENSURE_EX(c, TBrokenTvmClientSettings()
+ << "Need to use TClientSettings::EnableServiceTicketsFetchOptions()");
+ return c;
+ }
+
+ private:
+ TAsyncUpdaterPtr Updater_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/last_error.cpp b/library/cpp/tvmauth/client/misc/last_error.cpp
new file mode 100644
index 0000000000..a6279bb1ef
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/last_error.cpp
@@ -0,0 +1,115 @@
+#include "last_error.h"
+
+#include <util/string/builder.h>
+
+namespace NTvmAuth {
+ TLastError::TLastError()
+ : LastErrors_(MakeIntrusiveConst<TLastErrors>())
+ {
+ }
+
+ TString TLastError::GetLastError(bool isOk, EType* type) const {
+ if (isOk) {
+ return OK_;
+ }
+
+ const TLastErrorsPtr ptr = LastErrors_.Get();
+
+ for (const TLastErr& err : ptr->Errors) {
+ if (err && err->first == EType::NonRetriable) {
+ if (type) {
+ *type = EType::NonRetriable;
+ }
+ return err->second;
+ }
+ }
+
+ for (const TLastErr& err : ptr->Errors) {
+ if (err) {
+ if (type) {
+ *type = EType::Retriable;
+ }
+ return err->second;
+ }
+ }
+
+ if (type) {
+ *type = EType::NonRetriable;
+ }
+ return "Internal client error: failed to collect last useful error message, please report this message to tvm-dev@yandex-team.ru";
+ }
+
+ TString TLastError::ProcessHttpError(TLastError::EScope scope,
+ TStringBuf path,
+ int code,
+ const TString& msg) const {
+ TString err = TStringBuilder() << "Path:" << path << ".Code=" << code << ": " << msg;
+
+ ProcessError(code >= 400 && code < 500 ? EType::NonRetriable
+ : EType::Retriable,
+ scope,
+ err);
+
+ return err;
+ }
+
+ void TLastError::ProcessError(TLastError::EType type, TLastError::EScope scope, const TStringBuf msg) const {
+ Update(scope, [&](TLastErr& lastError) {
+ if (lastError && lastError->first == EType::NonRetriable && type == EType::Retriable) {
+ return false;
+ }
+
+ TString err = TStringBuilder() << scope << ": " << msg;
+ err.erase(std::remove(err.begin(), err.vend(), '\r'), err.vend());
+ std::replace(err.begin(), err.vend(), '\n', ' ');
+
+ lastError = {type, std::move(err)};
+ return true;
+ });
+ }
+
+ void TLastError::ClearError(TLastError::EScope scope) {
+ Update(scope, [&](TLastErr& lastError) {
+ if (!lastError) {
+ return false;
+ }
+
+ lastError.Clear();
+ return true;
+ });
+ }
+
+ void TLastError::ClearErrors() {
+ for (size_t idx = 0; idx < (size_t)EScope::COUNT; ++idx) {
+ ClearError((EScope)idx);
+ }
+ }
+
+ void TLastError::ThrowLastError() {
+ EType type;
+ TString err = GetLastError(false, &type);
+
+ switch (type) {
+ case EType::NonRetriable:
+ ythrow TNonRetriableException()
+ << "Failed to start TvmClient. Do not retry: "
+ << err;
+ case EType::Retriable:
+ ythrow TRetriableException()
+ << "Failed to start TvmClient. You can retry: "
+ << err;
+ }
+ }
+
+ template <typename Func>
+ void TLastError::Update(TLastError::EScope scope, Func func) const {
+ Y_VERIFY(scope != EScope::COUNT);
+
+ TLastErrors errs = *LastErrors_.Get();
+ TLastErr& lastError = errs.Errors[(size_t)scope];
+
+ if (func(lastError)) {
+ LastErrors_.Set(MakeIntrusiveConst<TLastErrors>(std::move(errs)));
+ }
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/last_error.h b/library/cpp/tvmauth/client/misc/last_error.h
new file mode 100644
index 0000000000..b0ad33611f
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/last_error.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include "utils.h"
+
+#include <array>
+
+namespace NTvmAuth {
+ class TLastError {
+ public:
+ enum class EType {
+ NonRetriable,
+ Retriable,
+ };
+
+ enum class EScope {
+ ServiceTickets,
+ PublicKeys,
+ Roles,
+ TvmtoolConfig,
+
+ COUNT,
+ };
+
+ using TLastErr = TMaybe<std::pair<EType, TString>>;
+
+ struct TLastErrors: public TAtomicRefCount<TLastErrors> {
+ std::array<TLastErr, (int)EScope::COUNT> Errors;
+ };
+ using TLastErrorsPtr = TIntrusiveConstPtr<TLastErrors>;
+
+ public:
+ TLastError();
+
+ TString GetLastError(bool isOk, EType* type = nullptr) const;
+
+ TString ProcessHttpError(EScope scope, TStringBuf path, int code, const TString& msg) const;
+ void ProcessError(EType type, EScope scope, const TStringBuf msg) const;
+ void ClearError(EScope scope);
+ void ClearErrors();
+ void ThrowLastError();
+
+ private:
+ template <typename Func>
+ void Update(EScope scope, Func func) const;
+
+ private:
+ const TString OK_ = "OK";
+
+ mutable NUtils::TProtectedValue<TLastErrorsPtr> LastErrors_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/proc_info.cpp b/library/cpp/tvmauth/client/misc/proc_info.cpp
new file mode 100644
index 0000000000..e2e5ec15b9
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/proc_info.cpp
@@ -0,0 +1,53 @@
+#include "proc_info.h"
+
+#include <library/cpp/tvmauth/version.h>
+
+#include <library/cpp/string_utils/quote/quote.h>
+
+#include <util/stream/file.h>
+#include <util/string/cast.h>
+#include <util/system/getpid.h>
+
+namespace NTvmAuth::NUtils {
+ void TProcInfo::AddToRequest(IOutputStream& out) const {
+ out << "_pid=" << Pid;
+ if (ProcessName) {
+ out << "&_procces_name=" << *ProcessName;
+ }
+ out << "&lib_version=client_" << VersionPrefix << LibVersion();
+ }
+
+ TProcInfo TProcInfo::Create(const TString& versionPrefix) {
+ TProcInfo res;
+ res.Pid = IntToString<10>(GetPID());
+ res.ProcessName = GetProcessName();
+ res.VersionPrefix = versionPrefix;
+ return res;
+ }
+
+ std::optional<TString> TProcInfo::GetProcessName() {
+ try {
+ // works only for linux
+ TFileInput proc("/proc/self/status");
+
+ TString line;
+ while (proc.ReadLine(line)) {
+ TStringBuf buf(line);
+ if (!buf.SkipPrefix("Name:")) {
+ continue;
+ }
+
+ while (buf && isspace(buf.front())) {
+ buf.Skip(1);
+ }
+
+ TString res(buf);
+ CGIEscape(res);
+ return res;
+ }
+ } catch (...) {
+ }
+
+ return {};
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/proc_info.h b/library/cpp/tvmauth/client/misc/proc_info.h
new file mode 100644
index 0000000000..b1526e5c47
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/proc_info.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <util/generic/string.h>
+
+#include <optional>
+
+namespace NTvmAuth::NUtils {
+ struct TProcInfo {
+ TString Pid;
+ std::optional<TString> ProcessName;
+ TString VersionPrefix;
+
+ void AddToRequest(IOutputStream& out) const;
+
+ static TProcInfo Create(const TString& versionPrefix);
+ static std::optional<TString> GetProcessName();
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/retry_settings/v1/settings.proto b/library/cpp/tvmauth/client/misc/retry_settings/v1/settings.proto
new file mode 100644
index 0000000000..72817847a6
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/retry_settings/v1/settings.proto
@@ -0,0 +1,21 @@
+syntax = "proto2";
+
+package retry_settings.v1;
+
+option cc_enable_arenas = true;
+option go_package = "a.yandex-team.ru/library/cpp/tvmauth/client/misc/retry_settings/v1";
+
+message Settings {
+ optional uint32 exponential_backoff_min_sec = 1;
+ optional uint32 exponential_backoff_max_sec = 2;
+ optional double exponential_backoff_factor = 3;
+ optional double exponential_backoff_jitter = 4;
+ optional uint32 max_random_sleep_default = 5;
+ optional uint32 max_random_sleep_when_ok = 12;
+ optional uint32 retries_on_start = 6;
+ optional uint32 worker_awaking_period_sec = 7;
+ optional uint32 dsts_limit = 8;
+ optional uint32 retries_in_background = 9;
+ optional uint32 roles_update_period_sec = 10;
+ optional uint32 roles_warn_period_sec = 11;
+}
diff --git a/library/cpp/tvmauth/client/misc/retry_settings/v1/ya.make b/library/cpp/tvmauth/client/misc/retry_settings/v1/ya.make
new file mode 100644
index 0000000000..226bf7cea7
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/retry_settings/v1/ya.make
@@ -0,0 +1,15 @@
+PROTO_LIBRARY()
+
+OWNER(g:passport_infra)
+
+EXCLUDE_TAGS(
+ JAVA_PROTO
+ PY_PROTO
+ PY3_PROTO
+)
+
+SRCS(
+ settings.proto
+)
+
+END()
diff --git a/library/cpp/tvmauth/client/misc/roles/decoder.cpp b/library/cpp/tvmauth/client/misc/roles/decoder.cpp
new file mode 100644
index 0000000000..6337fb91c2
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/roles/decoder.cpp
@@ -0,0 +1,93 @@
+#include "decoder.h"
+
+#include <library/cpp/tvmauth/client/misc/utils.h>
+
+#include <library/cpp/openssl/crypto/sha.h>
+#include <library/cpp/streams/brotli/brotli.h>
+#include <library/cpp/streams/zstd/zstd.h>
+
+#include <util/generic/yexception.h>
+#include <util/stream/zlib.h>
+#include <util/string/ascii.h>
+
+namespace NTvmAuth::NRoles {
+ TString TDecoder::Decode(const TStringBuf codec, TString&& blob) {
+ if (codec.empty()) {
+ return std::move(blob);
+ }
+
+ const TCodecInfo info = ParseCodec(codec);
+ TString decoded = DecodeImpl(info.Type, blob);
+
+ VerifySize(decoded, info.Size);
+ VerifyChecksum(decoded, info.Sha256);
+
+ return decoded;
+ }
+
+ TDecoder::TCodecInfo TDecoder::ParseCodec(TStringBuf codec) {
+ const char delim = ':';
+
+ const TStringBuf version = codec.NextTok(delim);
+ Y_ENSURE(version == "1",
+ "unknown codec format version; known: 1; got: " << version);
+
+ TCodecInfo res;
+ res.Type = codec.NextTok(delim);
+ Y_ENSURE(res.Type, "codec type is empty");
+
+ const TStringBuf size = codec.NextTok(delim);
+ Y_ENSURE(TryIntFromString<10>(size, res.Size),
+ "decoded blob size is not number");
+
+ res.Sha256 = codec;
+ const size_t expectedSha256Size = 2 * NOpenSsl::NSha256::DIGEST_LENGTH;
+ Y_ENSURE(res.Sha256.size() == expectedSha256Size,
+ "sha256 of decoded blob has invalid length: expected "
+ << expectedSha256Size << ", got " << res.Sha256.size());
+
+ return res;
+ }
+
+ TString TDecoder::DecodeImpl(TStringBuf codec, const TString& blob) {
+ if (AsciiEqualsIgnoreCase(codec, "brotli")) {
+ return DecodeBrolti(blob);
+ } else if (AsciiEqualsIgnoreCase(codec, "gzip")) {
+ return DecodeGzip(blob);
+ } else if (AsciiEqualsIgnoreCase(codec, "zstd")) {
+ return DecodeZstd(blob);
+ }
+
+ ythrow yexception() << "unknown codec: '" << codec << "'";
+ }
+
+ TString TDecoder::DecodeBrolti(const TString& blob) {
+ TStringInput in(blob);
+ return TBrotliDecompress(&in).ReadAll();
+ }
+
+ TString TDecoder::DecodeGzip(const TString& blob) {
+ TStringInput in(blob);
+ return TZLibDecompress(&in).ReadAll();
+ }
+
+ TString TDecoder::DecodeZstd(const TString& blob) {
+ TStringInput in(blob);
+ return TZstdDecompress(&in).ReadAll();
+ }
+
+ void TDecoder::VerifySize(const TStringBuf decoded, size_t expected) {
+ Y_ENSURE(expected == decoded.size(),
+ "Decoded blob has bad size: expected " << expected << ", actual " << decoded.size());
+ }
+
+ void TDecoder::VerifyChecksum(const TStringBuf decoded, const TStringBuf expected) {
+ using namespace NOpenSsl::NSha256;
+
+ const TDigest dig = Calc(decoded);
+ const TString actual = NUtils::ToHex(TStringBuf((char*)dig.data(), dig.size()));
+
+ Y_ENSURE(AsciiEqualsIgnoreCase(actual, expected),
+ "Decoded blob has bad sha256: expected=" << expected << ", actual=" << actual);
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/roles/decoder.h b/library/cpp/tvmauth/client/misc/roles/decoder.h
new file mode 100644
index 0000000000..de5cdb37e0
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/roles/decoder.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <util/generic/string.h>
+
+namespace NTvmAuth::NRoles {
+ class TDecoder {
+ public:
+ static TString Decode(const TStringBuf codec, TString&& blob);
+
+ public:
+ struct TCodecInfo {
+ TStringBuf Type;
+ size_t Size = 0;
+ TStringBuf Sha256;
+
+ bool operator==(const TCodecInfo& o) const {
+ return Type == o.Type &&
+ Size == o.Size &&
+ Sha256 == o.Sha256;
+ }
+ };
+
+ static TCodecInfo ParseCodec(TStringBuf codec);
+ static TString DecodeImpl(TStringBuf codec, const TString& blob);
+ static TString DecodeBrolti(const TString& blob);
+ static TString DecodeGzip(const TString& blob);
+ static TString DecodeZstd(const TString& blob);
+
+ static void VerifySize(const TStringBuf decoded, size_t expected);
+ static void VerifyChecksum(const TStringBuf decoded, const TStringBuf expected);
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/roles/entities_index.cpp b/library/cpp/tvmauth/client/misc/roles/entities_index.cpp
new file mode 100644
index 0000000000..c9b72c3a17
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/roles/entities_index.cpp
@@ -0,0 +1,114 @@
+#include "entities_index.h"
+
+#include <util/stream/str.h>
+
+#include <set>
+
+namespace NTvmAuth::NRoles {
+ TEntitiesIndex::TStage::TStage(const std::set<TString>& k)
+ : Keys_(k.begin(), k.end())
+ {
+ }
+
+ // TODO TStringBuf
+ bool TEntitiesIndex::TStage::GetNextKeySet(std::vector<TString>& out) {
+ out.clear();
+ out.reserve(Keys_.size());
+
+ ++Id_;
+ for (size_t idx = 0; idx < Keys_.size(); ++idx) {
+ bool need = (Id_ >> idx) & 0x01;
+
+ if (need) {
+ out.push_back(Keys_[idx]);
+ }
+ }
+
+ return !out.empty();
+ }
+
+ TEntitiesIndex::TEntitiesIndex(const std::vector<TEntityPtr>& entities) {
+ const std::set<TString> uniqueKeys = GetUniqueSortedKeys(entities);
+ Idx_.Entities = entities;
+ Idx_.SubTree.reserve(uniqueKeys.size() * entities.size());
+
+ TStage stage(uniqueKeys);
+ std::vector<TString> keyset;
+ while (stage.GetNextKeySet(keyset)) {
+ for (const TEntityPtr& e : entities) {
+ TSubTree* currentBranch = &Idx_;
+
+ for (const TString& key : keyset) {
+ auto it = e->find(key);
+ if (it == e->end()) {
+ continue;
+ }
+
+ auto [i, ok] = currentBranch->SubTree.emplace(
+ TKeyValue{it->first, it->second},
+ TSubTree());
+
+ currentBranch = &i->second;
+ currentBranch->Entities.push_back(e);
+ }
+ }
+ }
+
+ MakeUnique(Idx_);
+ }
+
+ std::set<TString> TEntitiesIndex::GetUniqueSortedKeys(const std::vector<TEntityPtr>& entities) {
+ std::set<TString> res;
+
+ for (const TEntityPtr& e : entities) {
+ for (const auto& [key, value] : *e) {
+ res.insert(key);
+ }
+ }
+
+ return res;
+ }
+
+ void TEntitiesIndex::MakeUnique(TSubTree& branch) {
+ auto& vec = branch.Entities;
+ std::sort(vec.begin(), vec.end());
+ vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
+
+ for (auto& [_, restPart] : branch.SubTree) {
+ MakeUnique(restPart);
+ }
+ }
+
+ static void Print(const TEntitiesIndex::TSubTree& part, IOutputStream& out, size_t offset = 0) {
+ std::vector<std::pair<TKeyValue, const TEntitiesIndex::TSubTree*>> vec;
+ vec.reserve(part.SubTree.size());
+
+ for (const auto& [key, value] : part.SubTree) {
+ vec.push_back({key, &value});
+ }
+
+ std::sort(vec.begin(), vec.end(), [](const auto& l, const auto& r) {
+ if (l.first.Key < r.first.Key) {
+ return true;
+ }
+ if (l.first.Value < r.first.Value) {
+ return true;
+ }
+ return false;
+ });
+
+ for (const auto& [key, value] : vec) {
+ out << TString(offset, ' ') << "\"" << key.Key << "/" << key.Value << "\"" << Endl;
+ Print(*value, out, offset + 4);
+ }
+ }
+
+ TString TEntitiesIndex::PrintDebugString() const {
+ TStringStream res;
+ res << Endl;
+
+ Print(Idx_, res);
+
+ return res.Str();
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/roles/entities_index.h b/library/cpp/tvmauth/client/misc/roles/entities_index.h
new file mode 100644
index 0000000000..bf42750d52
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/roles/entities_index.h
@@ -0,0 +1,107 @@
+#pragma once
+
+#include "types.h"
+
+#include <library/cpp/tvmauth/client/exception.h>
+
+#include <set>
+#include <vector>
+
+namespace NTvmAuth::NRoles {
+ class TEntitiesIndex: TMoveOnly {
+ public:
+ struct TSubTree;
+ using TIdxByAttrs = THashMap<TKeyValue, TSubTree>;
+
+ struct TSubTree {
+ std::vector<TEntityPtr> Entities;
+ TIdxByAttrs SubTree;
+ };
+
+ class TStage {
+ public:
+ TStage(const std::set<TString>& k);
+
+ bool GetNextKeySet(std::vector<TString>& out);
+
+ private:
+ std::vector<TString> Keys_;
+ size_t Id_ = 0;
+ };
+
+ public:
+ TEntitiesIndex(const std::vector<TEntityPtr>& entities);
+
+ /**
+ * Iterators must be to sorted unique key/value
+ */
+ template <typename Iterator>
+ bool ContainsExactEntity(Iterator begin, Iterator end) const;
+
+ /**
+ * Iterators must be to sorted unique key/value
+ */
+ template <typename Iterator>
+ const std::vector<TEntityPtr>& GetEntitiesWithAttrs(Iterator begin, Iterator end) const;
+
+ public: // for tests
+ static std::set<TString> GetUniqueSortedKeys(const std::vector<TEntityPtr>& entities);
+ static void MakeUnique(TEntitiesIndex::TSubTree& branch);
+
+ TString PrintDebugString() const;
+
+ private:
+ template <typename Iterator>
+ const TSubTree* FindSubtree(Iterator begin, Iterator end, size_t& size) const;
+
+ private:
+ TSubTree Idx_;
+ std::vector<TEntityPtr> EmptyResult_;
+ };
+
+ template <typename Iterator>
+ bool TEntitiesIndex::ContainsExactEntity(Iterator begin, Iterator end) const {
+ size_t size = 0;
+ const TSubTree* subtree = FindSubtree(begin, end, size);
+ if (!subtree) {
+ return false;
+ }
+
+ auto res = std::find_if(
+ subtree->Entities.begin(),
+ subtree->Entities.end(),
+ [size](const auto& e) { return size == e->size(); });
+ return res != subtree->Entities.end();
+ }
+
+ template <typename Iterator>
+ const std::vector<TEntityPtr>& TEntitiesIndex::GetEntitiesWithAttrs(Iterator begin, Iterator end) const {
+ size_t size = 0;
+ const TSubTree* subtree = FindSubtree(begin, end, size);
+ if (!subtree) {
+ return EmptyResult_;
+ }
+
+ return subtree->Entities;
+ }
+
+ template <typename Iterator>
+ const TEntitiesIndex::TSubTree* TEntitiesIndex::FindSubtree(Iterator begin,
+ Iterator end,
+ size_t& size) const {
+ const TSubTree* subtree = &Idx_;
+ size = 0;
+
+ for (auto attr = begin; attr != end; ++attr) {
+ auto it = subtree->SubTree.find(TKeyValueView{attr->first, attr->second});
+ if (it == subtree->SubTree.end()) {
+ return nullptr;
+ }
+
+ ++size;
+ subtree = &it->second;
+ }
+
+ return subtree;
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/roles/parser.cpp b/library/cpp/tvmauth/client/misc/roles/parser.cpp
new file mode 100644
index 0000000000..eb991b5716
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/roles/parser.cpp
@@ -0,0 +1,149 @@
+#include "parser.h"
+
+#include <library/cpp/json/json_reader.h>
+
+#include <util/string/cast.h>
+
+namespace NTvmAuth::NRoles {
+ static void GetRequiredValue(const NJson::TJsonValue& doc,
+ TStringBuf key,
+ NJson::TJsonValue& obj) {
+ Y_ENSURE(doc.GetValue(key, &obj), "Missing '" << key << "'");
+ }
+
+ static ui64 GetRequiredUInt(const NJson::TJsonValue& doc,
+ TStringBuf key) {
+ NJson::TJsonValue obj;
+ GetRequiredValue(doc, key, obj);
+ Y_ENSURE(obj.IsUInteger(), "key '" << key << "' must be uint");
+ return obj.GetUInteger();
+ }
+
+ static bool GetOptionalMap(const NJson::TJsonValue& doc,
+ TStringBuf key,
+ NJson::TJsonValue& obj) {
+ if (!doc.GetValue(key, &obj)) {
+ return false;
+ }
+
+ Y_ENSURE(obj.IsMap(), "'" << key << "' must be object");
+ return true;
+ }
+
+ TRolesPtr TParser::Parse(TRawPtr decodedBlob) {
+ try {
+ return ParseImpl(decodedBlob);
+ } catch (const std::exception& e) {
+ throw yexception() << "Failed to parse roles from tirole: " << e.what()
+ << ". '" << *decodedBlob << "'";
+ }
+ }
+
+ TRolesPtr TParser::ParseImpl(TRawPtr decodedBlob) {
+ NJson::TJsonValue doc;
+ Y_ENSURE(NJson::ReadJsonTree(*decodedBlob, &doc), "Invalid json");
+ Y_ENSURE(doc.IsMap(), "Json must be object");
+
+ TRoles::TTvmConsumers tvm = GetConsumers<TTvmId>(doc, "tvm");
+ TRoles::TUserConsumers user = GetConsumers<TUid>(doc, "user");
+
+ // fetch it last to provide more correct apply instant
+ TRoles::TMeta meta = GetMeta(doc);
+
+ return std::make_shared<TRoles>(
+ std::move(meta),
+ std::move(tvm),
+ std::move(user),
+ std::move(decodedBlob));
+ }
+
+ TRoles::TMeta TParser::GetMeta(const NJson::TJsonValue& doc) {
+ TRoles::TMeta res;
+
+ NJson::TJsonValue obj;
+ GetRequiredValue(doc, "revision", obj);
+ if (obj.IsString()) {
+ res.Revision = obj.GetString();
+ } else if (obj.IsUInteger()) {
+ res.Revision = ToString(obj.GetUInteger());
+ } else {
+ ythrow yexception() << "'revision' has unexpected type: " << obj.GetType();
+ }
+
+ res.BornTime = TInstant::Seconds(GetRequiredUInt(doc, "born_date"));
+
+ return res;
+ }
+
+ template <typename Id>
+ THashMap<Id, TConsumerRolesPtr> TParser::GetConsumers(const NJson::TJsonValue& doc,
+ TStringBuf type) {
+ THashMap<Id, TConsumerRolesPtr> res;
+
+ NJson::TJsonValue obj;
+ if (!GetOptionalMap(doc, type, obj)) {
+ return res;
+ }
+
+ for (const auto& [key, value] : obj.GetMap()) {
+ Y_ENSURE(value.IsMap(),
+ "roles for consumer must be map: '" << key << "' is " << value.GetType());
+
+ Id id = 0;
+ Y_ENSURE(TryIntFromString<10>(key, id),
+ "id must be valid positive number of proper size for "
+ << type << ". got '"
+ << key << "'");
+
+ Y_ENSURE(res.emplace(id, GetConsumer(value, key)).second,
+ "consumer duplicate detected: '" << key << "' for " << type);
+ }
+
+ return res;
+ }
+
+ TConsumerRolesPtr TParser::GetConsumer(const NJson::TJsonValue& obj, TStringBuf consumer) {
+ THashMap<TString, TEntitiesPtr> entities;
+
+ for (const auto& [key, value] : obj.GetMap()) {
+ Y_ENSURE(value.IsArray(),
+ "entities for roles must be array: '" << key << "' is " << value.GetType());
+
+ entities.emplace(key, GetEntities(value, consumer, key));
+ }
+
+ return std::make_shared<TConsumerRoles>(std::move(entities));
+ }
+
+ TEntitiesPtr TParser::GetEntities(const NJson::TJsonValue& obj,
+ TStringBuf consumer,
+ TStringBuf role) {
+ std::vector<TEntityPtr> entities;
+ entities.reserve(obj.GetArray().size());
+
+ for (const NJson::TJsonValue& e : obj.GetArray()) {
+ Y_ENSURE(e.IsMap(),
+ "role entity for role must be map: consumer '"
+ << consumer << "' with role '" << role << "' has " << e.GetType());
+
+ entities.push_back(GetEntity(e, consumer, role));
+ }
+
+ return std::make_shared<TEntities>(TEntities(entities));
+ }
+
+ TEntityPtr TParser::GetEntity(const NJson::TJsonValue& obj, TStringBuf consumer, TStringBuf role) {
+ TEntityPtr res = std::make_shared<TEntity>();
+
+ for (const auto& [key, value] : obj.GetMap()) {
+ Y_ENSURE(value.IsString(),
+ "entity is map (str->str), got value "
+ << value.GetType() << ". consumer '"
+ << consumer << "' with role '" << role << "'");
+
+ res->emplace(key, value.GetString());
+ }
+
+ return res;
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/roles/parser.h b/library/cpp/tvmauth/client/misc/roles/parser.h
new file mode 100644
index 0000000000..0982ba78c6
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/roles/parser.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include "roles.h"
+#include "types.h"
+
+namespace NJson {
+ class TJsonValue;
+}
+
+namespace NTvmAuth::NRoles {
+ class TParser {
+ public:
+ static TRolesPtr Parse(TRawPtr decodedBlob);
+
+ public:
+ static TRolesPtr ParseImpl(TRawPtr decodedBlob);
+ static TRoles::TMeta GetMeta(const NJson::TJsonValue& doc);
+
+ template <typename Id>
+ static THashMap<Id, TConsumerRolesPtr> GetConsumers(
+ const NJson::TJsonValue& doc,
+ TStringBuf key);
+
+ static TConsumerRolesPtr GetConsumer(
+ const NJson::TJsonValue& obj,
+ TStringBuf consumer);
+ static TEntitiesPtr GetEntities(
+ const NJson::TJsonValue& obj,
+ TStringBuf consumer,
+ TStringBuf role);
+ static TEntityPtr GetEntity(
+ const NJson::TJsonValue& obj,
+ TStringBuf consumer,
+ TStringBuf role);
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/roles/roles.cpp b/library/cpp/tvmauth/client/misc/roles/roles.cpp
new file mode 100644
index 0000000000..f412558b99
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/roles/roles.cpp
@@ -0,0 +1,101 @@
+#include "roles.h"
+
+#include <library/cpp/tvmauth/checked_service_ticket.h>
+#include <library/cpp/tvmauth/checked_user_ticket.h>
+
+namespace NTvmAuth::NRoles {
+ TRoles::TRoles(TMeta&& meta,
+ TTvmConsumers tvm,
+ TUserConsumers user,
+ TRawPtr raw)
+ : Meta_(std::move(meta))
+ , TvmIds_(std::move(tvm))
+ , Users_(std::move(user))
+ , Raw_(std::move(raw))
+ {
+ Y_ENSURE(Raw_);
+ }
+
+ TConsumerRolesPtr TRoles::GetRolesForService(const TCheckedServiceTicket& t) const {
+ Y_ENSURE_EX(t,
+ TIllegalUsage() << "Service ticket must be valid, got: " << t.GetStatus());
+ auto it = TvmIds_.find(t.GetSrc());
+ return it == TvmIds_.end() ? TConsumerRolesPtr() : it->second;
+ }
+
+ TConsumerRolesPtr TRoles::GetRolesForUser(const TCheckedUserTicket& t,
+ std::optional<TUid> selectedUid) const {
+ Y_ENSURE_EX(t,
+ TIllegalUsage() << "User ticket must be valid, got: " << t.GetStatus());
+ Y_ENSURE_EX(t.GetEnv() == EBlackboxEnv::ProdYateam,
+ TIllegalUsage() << "User ticket must be from ProdYateam, got from " << t.GetEnv());
+
+ TUid uid = t.GetDefaultUid();
+ if (selectedUid) {
+ auto it = std::find(t.GetUids().begin(), t.GetUids().end(), *selectedUid);
+ Y_ENSURE_EX(it != t.GetUids().end(),
+ TIllegalUsage() << "selectedUid must be in user ticket but it's not: "
+ << *selectedUid);
+ uid = *selectedUid;
+ }
+
+ auto it = Users_.find(uid);
+ return it == Users_.end() ? TConsumerRolesPtr() : it->second;
+ }
+
+ const TRoles::TMeta& TRoles::GetMeta() const {
+ return Meta_;
+ }
+
+ const TString& TRoles::GetRaw() const {
+ return *Raw_;
+ }
+
+ bool TRoles::CheckServiceRole(const TCheckedServiceTicket& t,
+ const TStringBuf roleName) const {
+ TConsumerRolesPtr c = GetRolesForService(t);
+ return c ? c->HasRole(roleName) : false;
+ }
+
+ bool TRoles::CheckUserRole(const TCheckedUserTicket& t,
+ const TStringBuf roleName,
+ std::optional<TUid> selectedUid) const {
+ TConsumerRolesPtr c = GetRolesForUser(t, selectedUid);
+ return c ? c->HasRole(roleName) : false;
+ }
+
+ bool TRoles::CheckServiceRoleForExactEntity(const TCheckedServiceTicket& t,
+ const TStringBuf roleName,
+ const TEntity& exactEntity) const {
+ TConsumerRolesPtr c = GetRolesForService(t);
+ return c ? c->CheckRoleForExactEntity(roleName, exactEntity) : false;
+ }
+
+ bool TRoles::CheckUserRoleForExactEntity(const TCheckedUserTicket& t,
+ const TStringBuf roleName,
+ const TEntity& exactEntity,
+ std::optional<TUid> selectedUid) const {
+ TConsumerRolesPtr c = GetRolesForUser(t, selectedUid);
+ return c ? c->CheckRoleForExactEntity(roleName, exactEntity) : false;
+ }
+
+ TConsumerRoles::TConsumerRoles(THashMap<TString, TEntitiesPtr> roles)
+ : Roles_(std::move(roles))
+ {
+ }
+
+ bool TConsumerRoles::CheckRoleForExactEntity(const TStringBuf roleName,
+ const TEntity& exactEntity) const {
+ auto it = Roles_.find(roleName);
+ if (it == Roles_.end()) {
+ return false;
+ }
+
+ return it->second->Contains(exactEntity);
+ }
+
+ TEntities::TEntities(TEntitiesIndex idx)
+ : Idx_(std::move(idx))
+ {
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/roles/roles.h b/library/cpp/tvmauth/client/misc/roles/roles.h
new file mode 100644
index 0000000000..00ffb7e070
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/roles/roles.h
@@ -0,0 +1,182 @@
+#pragma once
+
+#include "entities_index.h"
+#include "types.h"
+
+#include <library/cpp/tvmauth/client/exception.h>
+
+#include <library/cpp/tvmauth/type.h>
+
+#include <util/datetime/base.h>
+#include <util/generic/array_ref.h>
+#include <util/generic/hash.h>
+
+#include <vector>
+
+namespace NTvmAuth {
+ class TCheckedServiceTicket;
+ class TCheckedUserTicket;
+}
+
+namespace NTvmAuth::NRoles {
+ class TRoles {
+ public:
+ struct TMeta {
+ TString Revision;
+ TInstant BornTime;
+ TInstant Applied = TInstant::Now();
+ };
+
+ using TTvmConsumers = THashMap<TTvmId, TConsumerRolesPtr>;
+ using TUserConsumers = THashMap<TUid, TConsumerRolesPtr>;
+
+ TRoles(TMeta&& meta,
+ TTvmConsumers tvm,
+ TUserConsumers user,
+ TRawPtr raw);
+
+ /**
+ * @return ptr to roles. It will be nullptr if there are no roles
+ */
+ TConsumerRolesPtr GetRolesForService(const TCheckedServiceTicket& t) const;
+
+ /**
+ * @return ptr to roles. It will be nullptr if there are no roles
+ */
+ TConsumerRolesPtr GetRolesForUser(const TCheckedUserTicket& t,
+ std::optional<TUid> selectedUid = {}) const;
+
+ const TMeta& GetMeta() const;
+ const TString& GetRaw() const;
+
+ public: // shortcuts
+ /**
+ * @brief CheckServiceRole() is shortcut for simple role checking - for any possible entity
+ */
+ bool CheckServiceRole(
+ const TCheckedServiceTicket& t,
+ const TStringBuf roleName) const;
+
+ /**
+ * @brief CheckUserRole() is shortcut for simple role checking - for any possible entity
+ */
+ bool CheckUserRole(
+ const TCheckedUserTicket& t,
+ const TStringBuf roleName,
+ std::optional<TUid> selectedUid = {}) const;
+
+ /**
+ * @brief CheckServiceRoleForExactEntity() is shortcut for simple role checking for exact entity
+ */
+ bool CheckServiceRoleForExactEntity(
+ const TCheckedServiceTicket& t,
+ const TStringBuf roleName,
+ const TEntity& exactEntity) const;
+
+ /**
+ * @brief CheckUserRoleForExactEntity() is shortcut for simple role checking for exact entity
+ */
+ bool CheckUserRoleForExactEntity(
+ const TCheckedUserTicket& t,
+ const TStringBuf roleName,
+ const TEntity& exactEntity,
+ std::optional<TUid> selectedUid = {}) const;
+
+ private:
+ TMeta Meta_;
+ TTvmConsumers TvmIds_;
+ TUserConsumers Users_;
+ TRawPtr Raw_;
+ };
+
+ class TConsumerRoles {
+ public:
+ TConsumerRoles(THashMap<TString, TEntitiesPtr> roles);
+
+ bool HasRole(const TStringBuf roleName) const {
+ return Roles_.contains(roleName);
+ }
+
+ /**
+ * @return ptr to entries. It will be nullptr if there is no role
+ */
+ TEntitiesPtr GetEntitiesForRole(const TStringBuf roleName) const {
+ auto it = Roles_.find(roleName);
+ return it == Roles_.end() ? TEntitiesPtr() : it->second;
+ }
+
+ /**
+ * @brief CheckRoleForExactEntity() is shortcut for simple role checking for exact entity
+ */
+ bool CheckRoleForExactEntity(const TStringBuf roleName,
+ const TEntity& exactEntity) const;
+
+ private:
+ THashMap<TString, TEntitiesPtr> Roles_;
+ };
+
+ class TEntities {
+ public:
+ TEntities(TEntitiesIndex idx);
+
+ /**
+ * @brief Contains() provides info about entity presence
+ */
+ bool Contains(const TEntity& exactEntity) const {
+ return Idx_.ContainsExactEntity(exactEntity.begin(), exactEntity.end());
+ }
+
+ /**
+ * @brief The same as Contains()
+ * It checks span for sorted and unique properties.
+ */
+ template <class StrKey = TString, class StrValue = TString>
+ bool ContainsSortedUnique(
+ const TArrayRef<const std::pair<StrKey, StrValue>>& exactEntity) const {
+ CheckSpan(exactEntity);
+ return Idx_.ContainsExactEntity(exactEntity.begin(), exactEntity.end());
+ }
+
+ /**
+ * @brief GetEntitiesWithAttrs() collects entities with ALL attributes from `attrs`
+ */
+ template <class StrKey = TString, class StrValue = TString>
+ const std::vector<TEntityPtr>& GetEntitiesWithAttrs(
+ const std::map<StrKey, StrValue>& attrs) const {
+ return Idx_.GetEntitiesWithAttrs(attrs.begin(), attrs.end());
+ }
+
+ /**
+ * @brief The same as GetEntitiesWithAttrs()
+ * It checks span for sorted and unique properties.
+ */
+ template <class StrKey = TString, class StrValue = TString>
+ const std::vector<TEntityPtr>& GetEntitiesWithSortedUniqueAttrs(
+ const TArrayRef<const std::pair<StrKey, StrValue>>& attrs) const {
+ CheckSpan(attrs);
+ return Idx_.GetEntitiesWithAttrs(attrs.begin(), attrs.end());
+ }
+
+ private:
+ template <class StrKey, class StrValue>
+ static void CheckSpan(const TArrayRef<const std::pair<StrKey, StrValue>>& attrs) {
+ if (attrs.empty()) {
+ return;
+ }
+
+ auto prev = attrs.begin();
+ for (auto it = prev + 1; it != attrs.end(); ++it) {
+ Y_ENSURE_EX(prev->first != it->first,
+ TIllegalUsage() << "attrs are not unique: '" << it->first << "'");
+ Y_ENSURE_EX(prev->first < it->first,
+ TIllegalUsage() << "attrs are not sorted: '" << prev->first
+ << "' before '" << it->first << "'");
+
+ prev = it;
+ }
+ }
+
+ private:
+ TEntitiesIndex Idx_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/roles/types.h b/library/cpp/tvmauth/client/misc/roles/types.h
new file mode 100644
index 0000000000..e7614bf637
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/roles/types.h
@@ -0,0 +1,68 @@
+#pragma once
+
+#include <util/generic/hash_set.h>
+
+#include <map>
+#include <memory>
+
+namespace NTvmAuth::NRoles {
+ using TEntity = std::map<TString, TString>;
+ using TEntityPtr = std::shared_ptr<TEntity>;
+
+ class TEntities;
+ using TEntitiesPtr = std::shared_ptr<TEntities>;
+
+ class TConsumerRoles;
+ using TConsumerRolesPtr = std::shared_ptr<TConsumerRoles>;
+
+ class TRoles;
+ using TRolesPtr = std::shared_ptr<TRoles>;
+
+ using TRawPtr = std::shared_ptr<TString>;
+
+ template <class T>
+ struct TKeyValueBase {
+ T Key;
+ T Value;
+
+ template <typename U>
+ bool operator==(const TKeyValueBase<U>& o) const {
+ return Key == o.Key && Value == o.Value;
+ }
+ };
+
+ using TKeyValue = TKeyValueBase<TString>;
+ using TKeyValueView = TKeyValueBase<TStringBuf>;
+}
+
+// Traits
+
+template <>
+struct THash<NTvmAuth::NRoles::TKeyValue> {
+ std::size_t operator()(const NTvmAuth::NRoles::TKeyValue& e) const {
+ return std::hash<std::string_view>()(e.Key) + std::hash<std::string_view>()(e.Value);
+ }
+
+ std::size_t operator()(const NTvmAuth::NRoles::TKeyValueView& e) const {
+ return std::hash<std::string_view>()(e.Key) + std::hash<std::string_view>()(e.Value);
+ }
+};
+
+template <>
+struct TEqualTo<NTvmAuth::NRoles::TKeyValue> {
+ using is_transparent = std::true_type;
+
+ template <typename T, typename U>
+ bool operator()(const NTvmAuth::NRoles::TKeyValueBase<T>& l,
+ const NTvmAuth::NRoles::TKeyValueBase<U>& r) {
+ return l == r;
+ }
+};
+
+inline bool operator<(const NTvmAuth::NRoles::TEntityPtr& l, const NTvmAuth::NRoles::TEntityPtr& r) {
+ return *l < *r;
+}
+
+inline bool operator==(const NTvmAuth::NRoles::TEntityPtr& l, const NTvmAuth::NRoles::TEntityPtr& r) {
+ return *l == *r;
+}
diff --git a/library/cpp/tvmauth/client/misc/settings.h b/library/cpp/tvmauth/client/misc/settings.h
new file mode 100644
index 0000000000..8fae6c34d3
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/settings.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <util/generic/fwd.h>
+
+namespace NTvmAuth {
+ class TClientSettings {
+ public:
+ /*!
+ * Look at description in relevant settings: NTvmApi::TClientSettings or NTvmTool::TClientSettings
+ */
+ using TAlias = TString;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/src_checker.h b/library/cpp/tvmauth/client/misc/src_checker.h
new file mode 100644
index 0000000000..25e8e72602
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/src_checker.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "async_updater.h"
+
+#include <library/cpp/tvmauth/client/exception.h>
+
+#include <library/cpp/tvmauth/checked_service_ticket.h>
+#include <library/cpp/tvmauth/src/service_impl.h>
+
+namespace NTvmAuth {
+ class TSrcChecker {
+ public:
+ TSrcChecker(TAsyncUpdaterPtr updater)
+ : Updater_(std::move(updater))
+ {
+ Y_ENSURE(Updater_);
+ GetCache();
+ }
+
+ /*!
+ * Checking must be enabled in TClientSettings
+ * Can throw exception if cache is out of date or wrong config
+ * @param ticket
+ */
+ TCheckedServiceTicket Check(TCheckedServiceTicket ticket) const {
+ NRoles::TConsumerRolesPtr roles = GetCache()->GetRolesForService(ticket);
+ if (roles) {
+ return ticket;
+ }
+
+ TServiceTicketImplPtr impl = THolder(NInternal::TCanningKnife::GetS(ticket));
+ impl->SetStatus(ETicketStatus::NoRoles);
+ return TCheckedServiceTicket(std::move(impl));
+ }
+
+ private:
+ NRoles::TRolesPtr GetCache() const {
+ NRoles::TRolesPtr c = Updater_->GetRoles();
+ Y_ENSURE_EX(c, TBrokenTvmClientSettings() << "Need to use TClientSettings::EnableRolesFetching()");
+ return c;
+ }
+
+ private:
+ TAsyncUpdaterPtr Updater_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/threaded_updater.cpp b/library/cpp/tvmauth/client/misc/threaded_updater.cpp
new file mode 100644
index 0000000000..5d21ce67a7
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/threaded_updater.cpp
@@ -0,0 +1,111 @@
+#include "threaded_updater.h"
+
+#include <library/cpp/tvmauth/client/exception.h>
+
+#include <util/string/builder.h>
+#include <util/system/spin_wait.h>
+#include <util/system/thread.h>
+
+namespace NTvmAuth {
+ TThreadedUpdaterBase::TThreadedUpdaterBase(TDuration workerAwakingPeriod,
+ TLoggerPtr logger,
+ const TString& url,
+ ui16 port,
+ TDuration socketTimeout,
+ TDuration connectTimeout)
+ : WorkerAwakingPeriod_(workerAwakingPeriod)
+ , Logger_(std::move(logger))
+ , TvmUrl_(url)
+ , TvmPort_(port)
+ , TvmSocketTimeout_(socketTimeout)
+ , TvmConnectTimeout_(connectTimeout)
+ , IsStopped_(true)
+ {
+ Y_ENSURE_EX(Logger_, TNonRetriableException() << "Logger is required");
+
+ ServiceTicketsDurations_.RefreshPeriod = TDuration::Hours(1);
+ ServiceTicketsDurations_.Expiring = TDuration::Hours(2);
+ ServiceTicketsDurations_.Invalid = TDuration::Hours(11);
+
+ PublicKeysDurations_.RefreshPeriod = TDuration::Days(1);
+ PublicKeysDurations_.Expiring = TDuration::Days(2);
+ PublicKeysDurations_.Invalid = TDuration::Days(6);
+ }
+
+ TThreadedUpdaterBase::~TThreadedUpdaterBase() {
+ StopWorker();
+ }
+
+ void TThreadedUpdaterBase::StartWorker() {
+ if (HttpClient_) {
+ HttpClient_->ResetConnection();
+ }
+ Thread_ = MakeHolder<TThread>(WorkerWrap, this);
+ Thread_->Start();
+ Started_.Wait();
+ IsStopped_ = false;
+ }
+
+ void TThreadedUpdaterBase::StopWorker() {
+ Event_.Signal();
+ if (Thread_) {
+ Thread_.Reset();
+ }
+ }
+
+ TKeepAliveHttpClient& TThreadedUpdaterBase::GetClient() const {
+ if (!HttpClient_) {
+ HttpClient_ = MakeHolder<TKeepAliveHttpClient>(TvmUrl_, TvmPort_, TvmSocketTimeout_, TvmConnectTimeout_);
+ }
+
+ return *HttpClient_;
+ }
+
+ void TThreadedUpdaterBase::LogDebug(const TString& msg) const {
+ if (Logger_) {
+ Logger_->Debug(msg);
+ }
+ }
+
+ void TThreadedUpdaterBase::LogInfo(const TString& msg) const {
+ if (Logger_) {
+ Logger_->Info(msg);
+ }
+ }
+
+ void TThreadedUpdaterBase::LogWarning(const TString& msg) const {
+ if (Logger_) {
+ Logger_->Warning(msg);
+ }
+ }
+
+ void TThreadedUpdaterBase::LogError(const TString& msg) const {
+ if (Logger_) {
+ Logger_->Error(msg);
+ }
+ }
+
+ void* TThreadedUpdaterBase::WorkerWrap(void* arg) {
+ TThread::SetCurrentThreadName("TicketParserUpd");
+ TThreadedUpdaterBase& this_ = *reinterpret_cast<TThreadedUpdaterBase*>(arg);
+ this_.Started_.Signal();
+ this_.LogDebug("Thread-worker started");
+
+ while (true) {
+ if (this_.Event_.WaitT(this_.WorkerAwakingPeriod_)) {
+ break;
+ }
+
+ try {
+ this_.Worker();
+ this_.GetClient().ResetConnection();
+ } catch (const std::exception& e) { // impossible now
+ this_.LogError(TStringBuilder() << "Failed to generate new cache: " << e.what());
+ }
+ }
+
+ this_.LogDebug("Thread-worker stopped");
+ this_.IsStopped_ = true;
+ return nullptr;
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/threaded_updater.h b/library/cpp/tvmauth/client/misc/threaded_updater.h
new file mode 100644
index 0000000000..783684ba3b
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/threaded_updater.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#include "async_updater.h"
+#include "settings.h"
+
+#include <library/cpp/tvmauth/client/logger.h>
+
+#include <library/cpp/http/simple/http_client.h>
+
+#include <util/datetime/base.h>
+#include <util/generic/ptr.h>
+#include <util/system/event.h>
+#include <util/system/thread.h>
+
+class TKeepAliveHttpClient;
+
+namespace NTvmAuth::NInternal {
+ class TClientCaningKnife;
+}
+namespace NTvmAuth {
+ class TThreadedUpdaterBase: public TAsyncUpdaterBase {
+ public:
+ TThreadedUpdaterBase(TDuration workerAwakingPeriod,
+ TLoggerPtr logger,
+ const TString& url,
+ ui16 port,
+ TDuration socketTimeout,
+ TDuration connectTimeout);
+ virtual ~TThreadedUpdaterBase();
+
+ protected:
+ void StartWorker();
+ void StopWorker();
+
+ virtual void Worker() {
+ }
+
+ TKeepAliveHttpClient& GetClient() const;
+
+ void LogDebug(const TString& msg) const;
+ void LogInfo(const TString& msg) const;
+ void LogWarning(const TString& msg) const;
+ void LogError(const TString& msg) const;
+
+ protected:
+ TDuration WorkerAwakingPeriod_;
+
+ const TLoggerPtr Logger_;
+
+ protected:
+ const TString TvmUrl_;
+
+ private:
+ static void* WorkerWrap(void* arg);
+
+ void StartTvmClientStopping() const override {
+ Event_.Signal();
+ }
+
+ bool IsTvmClientStopped() const override {
+ return IsStopped_;
+ }
+
+ private:
+ mutable THolder<TKeepAliveHttpClient> HttpClient_;
+
+ const ui32 TvmPort_;
+ const TDuration TvmSocketTimeout_;
+ const TDuration TvmConnectTimeout_;
+
+ mutable TAutoEvent Event_;
+ mutable TAutoEvent Started_;
+ std::atomic_bool IsStopped_;
+ THolder<TThread> Thread_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/tool/meta_info.cpp b/library/cpp/tvmauth/client/misc/tool/meta_info.cpp
new file mode 100644
index 0000000000..5d905b0cb8
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/tool/meta_info.cpp
@@ -0,0 +1,200 @@
+#include "meta_info.h"
+
+#include <library/cpp/json/json_reader.h>
+
+#include <util/string/builder.h>
+
+namespace NTvmAuth::NTvmTool {
+ TString TMetaInfo::TConfig::ToString() const {
+ TStringStream s;
+ s << "self_tvm_id=" << SelfTvmId << ", "
+ << "bb_env=" << BbEnv << ", "
+ << "dsts=[";
+
+ for (const auto& pair : DstAliases) {
+ s << "(" << pair.first << ":" << pair.second << ")";
+ }
+
+ s << "]";
+
+ return std::move(s.Str());
+ }
+
+ TMetaInfo::TMetaInfo(TLoggerPtr logger)
+ : Logger_(std::move(logger))
+ {
+ }
+
+ TMetaInfo::TConfigPtr TMetaInfo::Init(TKeepAliveHttpClient& client,
+ const TClientSettings& settings) {
+ ApplySettings(settings);
+
+ TryPing(client);
+ const TString metaString = Fetch(client);
+ if (Logger_) {
+ TStringStream s;
+ s << "Meta info fetched from " << settings.GetHostname() << ":" << settings.GetPort();
+ Logger_->Debug(s.Str());
+ }
+
+ try {
+ Config_.Set(ParseMetaString(metaString, SelfAlias_));
+ } catch (const yexception& e) {
+ ythrow TNonRetriableException() << "Malformed json from tvmtool: " << e.what();
+ }
+ TConfigPtr cfg = Config_.Get();
+ Y_ENSURE_EX(cfg, TNonRetriableException() << "Alias '" << SelfAlias_ << "' not found in meta info");
+
+ if (Logger_) {
+ Logger_->Info("Meta: " + cfg->ToString());
+ }
+
+ return cfg;
+ }
+
+ TString TMetaInfo::GetRequestForTickets(const TConfig& config) {
+ Y_ENSURE(!config.DstAliases.empty());
+
+ TStringStream s;
+ s << "/tvm/tickets"
+ << "?src=" << config.SelfTvmId
+ << "&dsts=";
+
+ for (const auto& pair : config.DstAliases) {
+ s << pair.second << ","; // avoid aliases - url-encoding required
+ }
+ s.Str().pop_back();
+
+ return s.Str();
+ }
+
+ bool TMetaInfo::TryUpdateConfig(TKeepAliveHttpClient& client) {
+ const TString metaString = Fetch(client);
+
+ TConfigPtr config;
+ try {
+ config = ParseMetaString(metaString, SelfAlias_);
+ } catch (const yexception& e) {
+ ythrow TNonRetriableException() << "Malformed json from tvmtool: " << e.what();
+ }
+ Y_ENSURE_EX(config, TNonRetriableException() << "Alias '" << SelfAlias_ << "' not found in meta info");
+
+ TConfigPtr oldConfig = Config_.Get();
+ if (*config == *oldConfig) {
+ return false;
+ }
+
+ if (Logger_) {
+ Logger_->Info(TStringBuilder()
+ << "Meta was updated. Old: (" << oldConfig->ToString()
+ << "). New: (" << config->ToString() << ")");
+ }
+
+ Config_ = config;
+ return true;
+ }
+
+ void TMetaInfo::TryPing(TKeepAliveHttpClient& client) {
+ try {
+ TStringStream s;
+ TKeepAliveHttpClient::THttpCode code = client.DoGet("/tvm/ping", &s);
+ if (code < 200 || 300 <= code) {
+ throw yexception() << "(" << code << ") " << s.Str();
+ }
+ } catch (const std::exception& e) {
+ ythrow TNonRetriableException() << "Failed to connect to tvmtool: " << e.what();
+ }
+ }
+
+ TString TMetaInfo::Fetch(TKeepAliveHttpClient& client) const {
+ TStringStream res;
+ TKeepAliveHttpClient::THttpCode code;
+ try {
+ code = client.DoGet("/tvm/private_api/__meta__", &res, AuthHeader_);
+ } catch (const std::exception& e) {
+ ythrow TRetriableException() << "Failed to fetch meta data from tvmtool: " << e.what();
+ }
+
+ if (code != 200) {
+ Y_ENSURE_EX(code != 404,
+ TNonRetriableException() << "Library does not support so old tvmtool. You need tvmtool>=1.1.0");
+
+ TStringStream err;
+ err << "Failed to fetch meta from tvmtool: " << client.GetHost() << ":" << client.GetPort()
+ << " (" << code << "): " << res.Str();
+ Y_ENSURE_EX(!(500 <= code && code < 600), TRetriableException() << err.Str());
+ ythrow TNonRetriableException() << err.Str();
+ }
+
+ return res.Str();
+ }
+
+ static TMetaInfo::TDstAliases::value_type ParsePair(const NJson::TJsonValue& val, const TString& meta) {
+ NJson::TJsonValue jAlias;
+ Y_ENSURE(val.GetValue("alias", &jAlias), meta);
+ Y_ENSURE(jAlias.IsString(), meta);
+
+ NJson::TJsonValue jClientId;
+ Y_ENSURE(val.GetValue("client_id", &jClientId), meta);
+ Y_ENSURE(jClientId.IsInteger(), meta);
+
+ return {jAlias.GetString(), jClientId.GetInteger()};
+ }
+
+ TMetaInfo::TConfigPtr TMetaInfo::ParseMetaString(const TString& meta, const TString& self) {
+ NJson::TJsonValue jDoc;
+ Y_ENSURE(NJson::ReadJsonTree(meta, &jDoc), meta);
+
+ NJson::TJsonValue jEnv;
+ Y_ENSURE(jDoc.GetValue("bb_env", &jEnv), meta);
+
+ NJson::TJsonValue jTenants;
+ Y_ENSURE(jDoc.GetValue("tenants", &jTenants), meta);
+ Y_ENSURE(jTenants.IsArray(), meta);
+
+ for (const NJson::TJsonValue& jTen : jTenants.GetArray()) {
+ NJson::TJsonValue jSelf;
+ Y_ENSURE(jTen.GetValue("self", &jSelf), meta);
+ auto selfPair = ParsePair(jSelf, meta);
+ if (selfPair.first != self) {
+ continue;
+ }
+
+ TConfigPtr config = std::make_shared<TConfig>();
+ config->SelfTvmId = selfPair.second;
+ config->BbEnv = BbEnvFromString(jEnv.GetString(), meta);
+
+ NJson::TJsonValue jDsts;
+ Y_ENSURE(jTen.GetValue("dsts", &jDsts), meta);
+ Y_ENSURE(jDsts.IsArray(), meta);
+ for (const NJson::TJsonValue& jDst : jDsts.GetArray()) {
+ config->DstAliases.insert(ParsePair(jDst, meta));
+ }
+
+ return config;
+ }
+
+ return {};
+ }
+
+ void TMetaInfo::ApplySettings(const TClientSettings& settings) {
+ AuthHeader_ = {{"Authorization", settings.GetAuthToken()}};
+ SelfAlias_ = settings.GetSelfAlias();
+ }
+
+ EBlackboxEnv TMetaInfo::BbEnvFromString(const TString& env, const TString& meta) {
+ if (env == "Prod") {
+ return EBlackboxEnv::Prod;
+ } else if (env == "Test") {
+ return EBlackboxEnv::Test;
+ } else if (env == "ProdYaTeam") {
+ return EBlackboxEnv::ProdYateam;
+ } else if (env == "TestYaTeam") {
+ return EBlackboxEnv::TestYateam;
+ } else if (env == "Stress") {
+ return EBlackboxEnv::Stress;
+ }
+
+ ythrow yexception() << "'bb_env'=='" << env << "'. " << meta;
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/tool/meta_info.h b/library/cpp/tvmauth/client/misc/tool/meta_info.h
new file mode 100644
index 0000000000..c4b9688e39
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/tool/meta_info.h
@@ -0,0 +1,67 @@
+#pragma once
+
+#include "settings.h"
+
+#include <library/cpp/tvmauth/client/misc/utils.h>
+
+#include <library/cpp/tvmauth/client/logger.h>
+
+#include <library/cpp/http/simple/http_client.h>
+
+namespace NTvmAuth::NTvmTool {
+ class TMetaInfo {
+ public:
+ using TDstAliases = THashMap<TClientSettings::TAlias, TTvmId>;
+
+ struct TConfig {
+ TTvmId SelfTvmId = 0;
+ EBlackboxEnv BbEnv = EBlackboxEnv::Prod;
+ TDstAliases DstAliases;
+
+ bool AreTicketsRequired() const {
+ return !DstAliases.empty();
+ }
+
+ TString ToString() const;
+
+ bool operator==(const TConfig& c) const {
+ return SelfTvmId == c.SelfTvmId &&
+ BbEnv == c.BbEnv &&
+ DstAliases == c.DstAliases;
+ }
+ };
+ using TConfigPtr = std::shared_ptr<TConfig>;
+
+ public:
+ TMetaInfo(TLoggerPtr logger);
+
+ TConfigPtr Init(TKeepAliveHttpClient& client,
+ const TClientSettings& settings);
+
+ static TString GetRequestForTickets(const TMetaInfo::TConfig& config);
+
+ const TKeepAliveHttpClient::THeaders& GetAuthHeader() const {
+ return AuthHeader_;
+ }
+
+ TConfigPtr GetConfig() const {
+ return Config_.Get();
+ }
+
+ bool TryUpdateConfig(TKeepAliveHttpClient& client);
+
+ protected:
+ void TryPing(TKeepAliveHttpClient& client);
+ TString Fetch(TKeepAliveHttpClient& client) const;
+ static TConfigPtr ParseMetaString(const TString& meta, const TString& self);
+ void ApplySettings(const TClientSettings& settings);
+ static EBlackboxEnv BbEnvFromString(const TString& env, const TString& meta);
+
+ protected:
+ NUtils::TProtectedValue<TConfigPtr> Config_;
+ TKeepAliveHttpClient::THeaders AuthHeader_;
+
+ TLoggerPtr Logger_;
+ TString SelfAlias_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/tool/settings.cpp b/library/cpp/tvmauth/client/misc/tool/settings.cpp
new file mode 100644
index 0000000000..894501f19d
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/tool/settings.cpp
@@ -0,0 +1,37 @@
+#include "settings.h"
+
+#include <library/cpp/string_utils/url/url.h>
+
+#include <util/system/env.h>
+
+namespace NTvmAuth::NTvmTool {
+ TClientSettings::TClientSettings(const TAlias& selfAias)
+ : SelfAias_(selfAias)
+ , Hostname_("localhost")
+ , Port_(1)
+ , SocketTimeout_(TDuration::Seconds(5))
+ , ConnectTimeout_(TDuration::Seconds(30))
+ {
+ AuthToken_ = GetEnv("TVMTOOL_LOCAL_AUTHTOKEN");
+ if (!AuthToken_) {
+ AuthToken_ = GetEnv("QLOUD_TVM_TOKEN");
+ }
+ TStringBuf auth(AuthToken_);
+ FixSpaces(auth);
+ AuthToken_ = auth;
+
+ const TString url = GetEnv("DEPLOY_TVM_TOOL_URL");
+ if (url) {
+ TStringBuf scheme, host;
+ TryGetSchemeHostAndPort(url, scheme, host, Port_);
+ }
+
+ Y_ENSURE_EX(SelfAias_, TBrokenTvmClientSettings() << "Alias for your TVM client cannot be empty");
+ }
+
+ void TClientSettings::FixSpaces(TStringBuf& str) {
+ while (str && isspace(str.back())) {
+ str.Chop(1);
+ }
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/tool/settings.h b/library/cpp/tvmauth/client/misc/tool/settings.h
new file mode 100644
index 0000000000..63255ed090
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/tool/settings.h
@@ -0,0 +1,137 @@
+#pragma once
+
+#include <library/cpp/tvmauth/client/misc/settings.h>
+
+#include <library/cpp/tvmauth/client/exception.h>
+
+#include <library/cpp/tvmauth/checked_user_ticket.h>
+
+#include <util/datetime/base.h>
+#include <util/generic/maybe.h>
+
+namespace NTvmAuth::NTvmTool {
+ /**
+ * Uses local http-interface to get state: http://localhost/tvm/.
+ * This interface can be provided with tvmtool (local daemon) or Qloud/YP (local http api in container).
+ * See more: https://wiki.yandex-team.ru/passport/tvm2/qloud/.
+ *
+ * Most part of settings will be fetched from tvmtool on start of client.
+ * You need to use aliases for TVM-clients (src and dst) which you specified in tvmtool or Qloud/YP interface
+ */
+ class TClientSettings: public NTvmAuth::TClientSettings {
+ public:
+ /*!
+ * Sets default values:
+ * - hostname == "localhost"
+ * - port detected with env["DEPLOY_TVM_TOOL_URL"] (provided with Yandex.Deploy),
+ * otherwise port == 1 (it is ok for Qloud)
+ * - authToken: env["TVMTOOL_LOCAL_AUTHTOKEN"] (provided with Yandex.Deploy),
+ * otherwise env["QLOUD_TVM_TOKEN"] (provided with Qloud)
+ *
+ * AuthToken is protection from SSRF.
+ *
+ * @param selfAias - alias for your TVM client, which you specified in tvmtool or YD interface
+ */
+ TClientSettings(const TAlias& selfAias);
+
+ /*!
+ * Look at comment for ctor
+ * @param port
+ */
+ TClientSettings& SetPort(ui16 port) {
+ Port_ = port;
+ return *this;
+ }
+
+ /*!
+ * Default value: hostname == "localhost"
+ * @param hostname
+ */
+ TClientSettings& SetHostname(const TString& hostname) {
+ Y_ENSURE_EX(hostname, TBrokenTvmClientSettings() << "Hostname cannot be empty");
+ Hostname_ = hostname;
+ return *this;
+ }
+
+ TClientSettings& SetSocketTimeout(TDuration socketTimeout) {
+ SocketTimeout_ = socketTimeout;
+ return *this;
+ }
+
+ TClientSettings& SetConnectTimeout(TDuration connectTimeout) {
+ ConnectTimeout_ = connectTimeout;
+ return *this;
+ }
+
+ /*!
+ * Look at comment for ctor
+ * @param token
+ */
+ TClientSettings& SetAuthToken(TStringBuf token) {
+ FixSpaces(token);
+ Y_ENSURE_EX(token, TBrokenTvmClientSettings() << "Auth token cannot be empty");
+ AuthToken_ = token;
+ return *this;
+ }
+
+ /*!
+ * Blackbox environmet is provided by tvmtool for client.
+ * You can override it for your purpose with limitations:
+ * (env from tvmtool) -> (override)
+ * - Prod/ProdYateam -> Prod/ProdYateam
+ * - Test/TestYateam -> Test/TestYateam
+ * - Stress -> Stress
+ *
+ * You can contact tvm-dev@yandex-team.ru if limitations are too strict
+ * @param env
+ */
+ TClientSettings& OverrideBlackboxEnv(EBlackboxEnv env) {
+ BbEnv_ = env;
+ return *this;
+ }
+
+ public: // for TAsyncUpdaterBase
+ const TAlias& GetSelfAlias() const {
+ return SelfAias_;
+ }
+
+ const TString& GetHostname() const {
+ return Hostname_;
+ }
+
+ ui16 GetPort() const {
+ return Port_;
+ }
+
+ TDuration GetSocketTimeout() const {
+ return SocketTimeout_;
+ }
+
+ TDuration GetConnectTimeout() const {
+ return ConnectTimeout_;
+ }
+
+ const TString& GetAuthToken() const {
+ Y_ENSURE_EX(AuthToken_, TBrokenTvmClientSettings()
+ << "Auth token cannot be empty. "
+ << "Env 'TVMTOOL_LOCAL_AUTHTOKEN' and 'QLOUD_TVM_TOKEN' are empty.");
+ return AuthToken_;
+ }
+
+ TMaybe<EBlackboxEnv> GetOverridedBlackboxEnv() const {
+ return BbEnv_;
+ }
+
+ private:
+ void FixSpaces(TStringBuf& str);
+
+ private:
+ TAlias SelfAias_;
+ TString Hostname_;
+ ui16 Port_;
+ TDuration SocketTimeout_;
+ TDuration ConnectTimeout_;
+ TString AuthToken_;
+ TMaybe<EBlackboxEnv> BbEnv_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/tool/threaded_updater.cpp b/library/cpp/tvmauth/client/misc/tool/threaded_updater.cpp
new file mode 100644
index 0000000000..8490f7ab54
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/tool/threaded_updater.cpp
@@ -0,0 +1,331 @@
+#include "threaded_updater.h"
+
+#include <library/cpp/tvmauth/client/misc/utils.h>
+
+#include <library/cpp/json/json_reader.h>
+
+#include <util/generic/hash_set.h>
+#include <util/stream/str.h>
+#include <util/string/ascii.h>
+#include <util/string/builder.h>
+#include <util/string/cast.h>
+
+namespace NTvmAuth::NTvmTool {
+ TAsyncUpdaterPtr TThreadedUpdater::Create(const TClientSettings& settings, TLoggerPtr logger) {
+ Y_ENSURE_EX(logger, TNonRetriableException() << "Logger is required");
+ THolder<TThreadedUpdater> p(new TThreadedUpdater(
+ settings.GetHostname(),
+ settings.GetPort(),
+ settings.GetSocketTimeout(),
+ settings.GetConnectTimeout(),
+ std::move(logger)));
+ p->Init(settings);
+ p->StartWorker();
+ return p.Release();
+ }
+
+ TThreadedUpdater::~TThreadedUpdater() {
+ StopWorker(); // Required here to avoid using of deleted members
+ }
+
+ TClientStatus TThreadedUpdater::GetStatus() const {
+ const TClientStatus::ECode state = GetState();
+ return TClientStatus(state, GetLastError(state == TClientStatus::Ok));
+ }
+
+ TClientStatus::ECode TThreadedUpdater::GetState() const {
+ const TInstant now = TInstant::Now();
+ const TMetaInfo::TConfigPtr config = MetaInfo_.GetConfig();
+
+ if ((config->AreTicketsRequired() && AreServiceTicketsInvalid(now)) || ArePublicKeysInvalid(now)) {
+ return TClientStatus::Error;
+ }
+
+ if (config->AreTicketsRequired()) {
+ if (!GetCachedServiceTickets() || config->DstAliases.size() > GetCachedServiceTickets()->TicketsByAlias.size()) {
+ return TClientStatus::Error;
+ }
+ }
+
+ const TDuration st = now - GetUpdateTimeOfServiceTickets();
+ const TDuration pk = now - GetUpdateTimeOfPublicKeys();
+
+ if ((config->AreTicketsRequired() && st > ServiceTicketsDurations_.Expiring) || pk > PublicKeysDurations_.Expiring) {
+ return TClientStatus::Warning;
+ }
+
+ if (IsConfigWarnTime()) {
+ return TClientStatus::Warning;
+ }
+
+ return TClientStatus::Ok;
+ }
+
+ TThreadedUpdater::TThreadedUpdater(const TString& host, ui16 port, TDuration socketTimeout, TDuration connectTimeout, TLoggerPtr logger)
+ : TThreadedUpdaterBase(TDuration::Seconds(5), logger, host, port, socketTimeout, connectTimeout)
+ , MetaInfo_(logger)
+ , ConfigWarnDelay_(TDuration::Seconds(30))
+ {
+ ServiceTicketsDurations_.RefreshPeriod = TDuration::Minutes(10);
+ PublicKeysDurations_.RefreshPeriod = TDuration::Minutes(10);
+ }
+
+ void TThreadedUpdater::Init(const TClientSettings& settings) {
+ const TMetaInfo::TConfigPtr config = MetaInfo_.Init(GetClient(), settings);
+ LastVisitForConfig_ = TInstant::Now();
+
+ SetBbEnv(config->BbEnv, settings.GetOverridedBlackboxEnv());
+ if (settings.GetOverridedBlackboxEnv()) {
+ LogInfo(TStringBuilder()
+ << "Meta: override blackbox env: " << config->BbEnv
+ << "->" << *settings.GetOverridedBlackboxEnv());
+ }
+
+ ui8 tries = 3;
+ do {
+ UpdateState();
+ } while (!IsEverythingOk(*config) && --tries > 0);
+
+ if (!IsEverythingOk(*config)) {
+ ThrowLastError();
+ }
+ }
+
+ void TThreadedUpdater::UpdateState() {
+ bool wasUpdated = false;
+ try {
+ wasUpdated = MetaInfo_.TryUpdateConfig(GetClient());
+ LastVisitForConfig_ = TInstant::Now();
+ ClearError(EScope::TvmtoolConfig);
+ } catch (const std::exception& e) {
+ ProcessError(EType::Retriable, EScope::TvmtoolConfig, e.what());
+ LogWarning(TStringBuilder() << "Error while fetching of tvmtool config: " << e.what());
+ }
+ if (IsConfigWarnTime()) {
+ LogError(TStringBuilder() << "Tvmtool config have not been refreshed for too long period");
+ }
+
+ TMetaInfo::TConfigPtr config = MetaInfo_.GetConfig();
+
+ if (wasUpdated || IsTimeToUpdateServiceTickets(*config, LastVisitForServiceTickets_)) {
+ try {
+ const TInstant updateTime = UpdateServiceTickets(*config);
+ SetUpdateTimeOfServiceTickets(updateTime);
+ LastVisitForServiceTickets_ = TInstant::Now();
+
+ if (AreServiceTicketsOk(*config)) {
+ ClearError(EScope::ServiceTickets);
+ }
+ LogDebug(TStringBuilder() << "Tickets fetched from tvmtool: " << updateTime);
+ } catch (const std::exception& e) {
+ ProcessError(EType::Retriable, EScope::ServiceTickets, e.what());
+ LogWarning(TStringBuilder() << "Error while fetching of tickets: " << e.what());
+ }
+
+ if (TInstant::Now() - GetUpdateTimeOfServiceTickets() > ServiceTicketsDurations_.Expiring) {
+ LogError("Service tickets have not been refreshed for too long period");
+ }
+ }
+
+ if (wasUpdated || IsTimeToUpdatePublicKeys(LastVisitForPublicKeys_)) {
+ try {
+ const TInstant updateTime = UpdateKeys(*config);
+ SetUpdateTimeOfPublicKeys(updateTime);
+ LastVisitForPublicKeys_ = TInstant::Now();
+
+ if (ArePublicKeysOk()) {
+ ClearError(EScope::PublicKeys);
+ }
+ LogDebug(TStringBuilder() << "Public keys fetched from tvmtool: " << updateTime);
+ } catch (const std::exception& e) {
+ ProcessError(EType::Retriable, EScope::PublicKeys, e.what());
+ LogWarning(TStringBuilder() << "Error while fetching of public keys: " << e.what());
+ }
+
+ if (TInstant::Now() - GetUpdateTimeOfPublicKeys() > PublicKeysDurations_.Expiring) {
+ LogError("Public keys have not been refreshed for too long period");
+ }
+ }
+ }
+
+ TInstant TThreadedUpdater::UpdateServiceTickets(const TMetaInfo::TConfig& config) {
+ const std::pair<TString, TInstant> tickets = FetchServiceTickets(config);
+
+ if (TInstant::Now() - tickets.second >= ServiceTicketsDurations_.Invalid) {
+ throw yexception() << "Service tickets are too old: " << tickets.second;
+ }
+
+ TPairTicketsErrors p = ParseFetchTicketsResponse(tickets.first, config.DstAliases);
+ SetServiceTickets(MakeIntrusiveConst<TServiceTickets>(std::move(p.Tickets),
+ std::move(p.Errors),
+ config.DstAliases));
+ return tickets.second;
+ }
+
+ std::pair<TString, TInstant> TThreadedUpdater::FetchServiceTickets(const TMetaInfo::TConfig& config) const {
+ TStringStream s;
+ THttpHeaders headers;
+
+ const TString request = TMetaInfo::GetRequestForTickets(config);
+ auto code = GetClient().DoGet(request, &s, MetaInfo_.GetAuthHeader(), &headers);
+ Y_ENSURE(code == 200, ProcessHttpError(EScope::ServiceTickets, request, code, s.Str()));
+
+ return {s.Str(), GetBirthTimeFromResponse(headers, "tickets")};
+ }
+
+ static THashSet<TTvmId> GetAllTvmIds(const TMetaInfo::TDstAliases& dsts) {
+ THashSet<TTvmId> res;
+ res.reserve(dsts.size());
+
+ for (const auto& pair : dsts) {
+ res.insert(pair.second);
+ }
+
+ return res;
+ }
+
+ TAsyncUpdaterBase::TPairTicketsErrors TThreadedUpdater::ParseFetchTicketsResponse(const TString& resp,
+ const TMetaInfo::TDstAliases& dsts) const {
+ const THashSet<TTvmId> allTvmIds = GetAllTvmIds(dsts);
+
+ TServiceTickets::TMapIdStr tickets;
+ TServiceTickets::TMapIdStr errors;
+
+ auto procErr = [this](const TString& msg) {
+ ProcessError(EType::NonRetriable, EScope::ServiceTickets, msg);
+ LogError(msg);
+ };
+
+ NJson::TJsonValue doc;
+ Y_ENSURE(NJson::ReadJsonTree(resp, &doc), "Invalid json from tvmtool: " << resp);
+
+ for (const auto& pair : doc.GetMap()) {
+ NJson::TJsonValue tvmId;
+ unsigned long long tvmIdNum = 0;
+
+ if (!pair.second.GetValue("tvm_id", &tvmId) ||
+ !tvmId.GetUInteger(&tvmIdNum)) {
+ procErr(TStringBuilder()
+ << "Failed to get 'tvm_id' from key, should never happend '"
+ << pair.first << "': " << resp);
+ continue;
+ }
+
+ if (!allTvmIds.contains(tvmIdNum)) {
+ continue;
+ }
+
+ NJson::TJsonValue val;
+ if (!pair.second.GetValue("ticket", &val)) {
+ TString err;
+ if (pair.second.GetValue("error", &val)) {
+ err = val.GetString();
+ } else {
+ err = "Failed to get 'ticket' and 'error', should never happend: " + pair.first;
+ }
+
+ procErr(TStringBuilder()
+ << "Failed to get ServiceTicket for " << pair.first
+ << " (" << tvmIdNum << "): " << err);
+
+ errors.insert({tvmIdNum, std::move(err)});
+ continue;
+ }
+
+ tickets.insert({tvmIdNum, val.GetString()});
+ }
+
+ // This work-around is required because of bug in old verions of tvmtool: PASSP-24829
+ for (const auto& pair : dsts) {
+ if (!tickets.contains(pair.second) && !errors.contains(pair.second)) {
+ TString err = "Missing tvm_id in response, should never happend: " + pair.first;
+
+ procErr(TStringBuilder()
+ << "Failed to get ServiceTicket for " << pair.first
+ << " (" << pair.second << "): " << err);
+
+ errors.emplace(pair.second, std::move(err));
+ }
+ }
+
+ return {std::move(tickets), std::move(errors)};
+ }
+
+ TInstant TThreadedUpdater::UpdateKeys(const TMetaInfo::TConfig& config) {
+ const std::pair<TString, TInstant> keys = FetchPublicKeys();
+
+ if (TInstant::Now() - keys.second >= PublicKeysDurations_.Invalid) {
+ throw yexception() << "Public keys are too old: " << keys.second;
+ }
+
+ SetServiceContext(MakeIntrusiveConst<TServiceContext>(
+ TServiceContext::CheckingFactory(config.SelfTvmId, keys.first)));
+ SetUserContext(keys.first);
+
+ return keys.second;
+ }
+
+ std::pair<TString, TInstant> TThreadedUpdater::FetchPublicKeys() const {
+ TStringStream s;
+ THttpHeaders headers;
+
+ auto code = GetClient().DoGet("/tvm/keys", &s, MetaInfo_.GetAuthHeader(), &headers);
+ Y_ENSURE(code == 200, ProcessHttpError(EScope::PublicKeys, "/tvm/keys", code, s.Str()));
+
+ return {s.Str(), GetBirthTimeFromResponse(headers, "public keys")};
+ }
+
+ TInstant TThreadedUpdater::GetBirthTimeFromResponse(const THttpHeaders& headers, TStringBuf errMsg) {
+ auto it = std::find_if(headers.begin(),
+ headers.end(),
+ [](const THttpInputHeader& h) {
+ return AsciiEqualsIgnoreCase(h.Name(), "X-Ya-Tvmtool-Data-Birthtime");
+ });
+ Y_ENSURE(it != headers.end(), "Failed to fetch bithtime of " << errMsg << " from tvmtool");
+
+ ui64 time = 0;
+ Y_ENSURE(TryIntFromString<10>(it->Value(), time),
+ "Bithtime of " << errMsg << " from tvmtool must be unixtime. Got: " << it->Value());
+
+ return TInstant::Seconds(time);
+ }
+
+ bool TThreadedUpdater::IsTimeToUpdateServiceTickets(const TMetaInfo::TConfig& config,
+ TInstant lastUpdate) const {
+ return config.AreTicketsRequired() &&
+ TInstant::Now() - lastUpdate > ServiceTicketsDurations_.RefreshPeriod;
+ }
+
+ bool TThreadedUpdater::IsTimeToUpdatePublicKeys(TInstant lastUpdate) const {
+ return TInstant::Now() - lastUpdate > PublicKeysDurations_.RefreshPeriod;
+ }
+
+ bool TThreadedUpdater::IsEverythingOk(const TMetaInfo::TConfig& config) const {
+ return AreServiceTicketsOk(config) && ArePublicKeysOk();
+ }
+
+ bool TThreadedUpdater::AreServiceTicketsOk(const TMetaInfo::TConfig& config) const {
+ return AreServiceTicketsOk(config.DstAliases.size());
+ }
+
+ bool TThreadedUpdater::AreServiceTicketsOk(size_t requiredCount) const {
+ if (requiredCount == 0) {
+ return true;
+ }
+
+ auto c = GetCachedServiceTickets();
+ return c && c->TicketsByAlias.size() == requiredCount;
+ }
+
+ bool TThreadedUpdater::ArePublicKeysOk() const {
+ return GetCachedServiceContext() && GetCachedUserContext();
+ }
+
+ bool TThreadedUpdater::IsConfigWarnTime() const {
+ return LastVisitForConfig_ + ConfigWarnDelay_ < TInstant::Now();
+ }
+
+ void TThreadedUpdater::Worker() {
+ UpdateState();
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/tool/threaded_updater.h b/library/cpp/tvmauth/client/misc/tool/threaded_updater.h
new file mode 100644
index 0000000000..7fe88adfae
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/tool/threaded_updater.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "meta_info.h"
+
+#include <library/cpp/tvmauth/client/misc/async_updater.h>
+#include <library/cpp/tvmauth/client/misc/threaded_updater.h>
+
+#include <atomic>
+
+namespace NTvmAuth::NTvmTool {
+ class TThreadedUpdater: public TThreadedUpdaterBase {
+ public:
+ static TAsyncUpdaterPtr Create(const TClientSettings& settings, TLoggerPtr logger);
+ ~TThreadedUpdater();
+
+ TClientStatus GetStatus() const override;
+
+ protected: // for tests
+ TClientStatus::ECode GetState() const;
+
+ TThreadedUpdater(const TString& host, ui16 port, TDuration socketTimeout, TDuration connectTimeout, TLoggerPtr logger);
+
+ void Init(const TClientSettings& settings);
+ void UpdateState();
+
+ TInstant UpdateServiceTickets(const TMetaInfo::TConfig& config);
+ std::pair<TString, TInstant> FetchServiceTickets(const TMetaInfo::TConfig& config) const;
+ TPairTicketsErrors ParseFetchTicketsResponse(const TString& resp,
+ const TMetaInfo::TDstAliases& dsts) const;
+
+ TInstant UpdateKeys(const TMetaInfo::TConfig& config);
+ std::pair<TString, TInstant> FetchPublicKeys() const;
+
+ static TInstant GetBirthTimeFromResponse(const THttpHeaders& headers, TStringBuf errMsg);
+
+ bool IsTimeToUpdateServiceTickets(const TMetaInfo::TConfig& config, TInstant lastUpdate) const;
+ bool IsTimeToUpdatePublicKeys(TInstant lastUpdate) const;
+
+ bool IsEverythingOk(const TMetaInfo::TConfig& config) const;
+ bool AreServiceTicketsOk(const TMetaInfo::TConfig& config) const;
+ bool AreServiceTicketsOk(size_t requiredCount) const;
+ bool ArePublicKeysOk() const;
+ bool IsConfigWarnTime() const;
+
+ private:
+ void Worker() override;
+
+ protected:
+ TMetaInfo MetaInfo_;
+ TInstant LastVisitForServiceTickets_;
+ TInstant LastVisitForPublicKeys_;
+ TInstant LastVisitForConfig_;
+ TDuration ConfigWarnDelay_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/misc/utils.cpp b/library/cpp/tvmauth/client/misc/utils.cpp
new file mode 100644
index 0000000000..a124c7b11c
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/utils.cpp
@@ -0,0 +1,46 @@
+#include "utils.h"
+
+#include <library/cpp/tvmauth/client/facade.h>
+
+#include <util/stream/format.h>
+
+namespace NTvmAuth::NInternal {
+ void TClientCaningKnife::StartTvmClientStopping(TTvmClient* c) {
+ if (c && c->Updater_) {
+ c->Updater_->StartTvmClientStopping();
+ }
+ }
+
+ bool TClientCaningKnife::IsTvmClientStopped(TTvmClient* c) {
+ return c && c->Updater_ ? c->Updater_->IsTvmClientStopped() : true;
+ }
+}
+
+namespace NTvmAuth::NUtils {
+ TString ToHex(const TStringBuf s) {
+ TStringStream res;
+ res.Reserve(2 * s.size());
+
+ for (char c : s) {
+ res << Hex(c, HF_FULL);
+ }
+
+ return std::move(res.Str());
+ }
+
+ bool CheckBbEnvOverriding(EBlackboxEnv original, EBlackboxEnv override) noexcept {
+ switch (original) {
+ case EBlackboxEnv::Prod:
+ case EBlackboxEnv::ProdYateam:
+ return override == EBlackboxEnv::Prod || override == EBlackboxEnv::ProdYateam;
+ case EBlackboxEnv::Test:
+ return true;
+ case EBlackboxEnv::TestYateam:
+ return override == EBlackboxEnv::Test || override == EBlackboxEnv::TestYateam;
+ case EBlackboxEnv::Stress:
+ return override == EBlackboxEnv::Stress;
+ }
+
+ return false;
+ }
+}
diff --git a/library/cpp/tvmauth/client/misc/utils.h b/library/cpp/tvmauth/client/misc/utils.h
new file mode 100644
index 0000000000..1aa5e61bf1
--- /dev/null
+++ b/library/cpp/tvmauth/client/misc/utils.h
@@ -0,0 +1,95 @@
+#pragma once
+
+#include "api/settings.h"
+#include "tool/settings.h"
+
+#include <util/string/cast.h>
+#include <util/system/spinlock.h>
+
+#include <optional>
+
+namespace NTvmAuth {
+ class TTvmClient;
+}
+
+namespace NTvmAuth::NInternal {
+ class TClientCaningKnife {
+ public:
+ static void StartTvmClientStopping(TTvmClient* c);
+ static bool IsTvmClientStopped(TTvmClient* c);
+ };
+}
+
+namespace NTvmAuth::NUtils {
+ TString ToHex(const TStringBuf s);
+
+ inline NTvmAuth::NTvmApi::TClientSettings::TDstMap ParseDstMap(TStringBuf dsts) {
+ NTvmAuth::NTvmApi::TClientSettings::TDstMap res;
+
+ while (dsts) {
+ TStringBuf pair = dsts.NextTok(';');
+ TStringBuf alias = pair.NextTok(':');
+ res.insert(decltype(res)::value_type(
+ alias,
+ IntFromString<TTvmId, 10>(pair)));
+ }
+
+ return res;
+ }
+
+ inline NTvmAuth::NTvmApi::TClientSettings::TDstVector ParseDstVector(TStringBuf dsts) {
+ NTvmAuth::NTvmApi::TClientSettings::TDstVector res;
+
+ while (dsts) {
+ res.push_back(IntFromString<TTvmId, 10>(dsts.NextTok(';')));
+ }
+
+ return res;
+ }
+
+ bool CheckBbEnvOverriding(EBlackboxEnv original, EBlackboxEnv override) noexcept;
+
+ template <class T>
+ class TProtectedValue {
+ class TAssignOp {
+ public:
+ static void Assign(T& l, const T& r) {
+ l = r;
+ }
+
+ template <typename U>
+ static void Assign(std::shared_ptr<U>& l, std::shared_ptr<U>& r) {
+ l.swap(r);
+ }
+
+ template <typename U>
+ static void Assign(TIntrusiveConstPtr<U>& l, TIntrusiveConstPtr<U>& r) {
+ l.Swap(r);
+ }
+ };
+
+ public:
+ TProtectedValue() = default;
+
+ TProtectedValue(T value)
+ : Value_(value)
+ {
+ }
+
+ T Get() const {
+ with_lock (Lock_) {
+ return Value_;
+ }
+ }
+
+ void Set(T o) {
+ with_lock (Lock_) {
+ TAssignOp::Assign(Value_, o);
+ }
+ }
+
+ private:
+ T Value_;
+ mutable TAdaptiveLock Lock_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/mocked_updater.cpp b/library/cpp/tvmauth/client/mocked_updater.cpp
new file mode 100644
index 0000000000..54f94bc92a
--- /dev/null
+++ b/library/cpp/tvmauth/client/mocked_updater.cpp
@@ -0,0 +1,60 @@
+#include "mocked_updater.h"
+
+#include <library/cpp/tvmauth/unittest.h>
+
+namespace NTvmAuth {
+ TMockedUpdater::TSettings TMockedUpdater::TSettings::CreateDeafult() {
+ TMockedUpdater::TSettings res;
+
+ res.SelfTvmId = 100500;
+
+ res.Backends = {
+ {
+ /*.Alias_ = */ "my_dest",
+ /*.Id_ = */ 42,
+ /*.Value_ = */ "3:serv:CBAQ__________9_IgYIlJEGECo:O9-vbod_8czkKrpwJAZCI8UgOIhNr2xKPcS-LWALrVC224jga2nIT6vLiw6q3d6pAT60g9K7NB39LEmh7vMuePtUMjzuZuL-uJg17BsH2iTLCZSxDjWxbU9piA2T6u607jiSyiy-FI74pEPqkz7KKJ28aPsefuC1VUweGkYFzNY",
+ },
+ };
+
+ res.BadBackends = {
+ {
+ /*.Alias_ = */ "my_bad_dest",
+ /*.Id_ = */ 43,
+ /*.Value_ = */ "Dst is not found",
+ },
+ };
+
+ return res;
+ }
+
+ TMockedUpdater::TMockedUpdater(const TSettings& settings)
+ : Roles_(settings.Roles)
+ {
+ SetServiceContext(MakeIntrusiveConst<TServiceContext>(TServiceContext::CheckingFactory(
+ settings.SelfTvmId,
+ NUnittest::TVMKNIFE_PUBLIC_KEYS)));
+
+ SetBbEnv(settings.UserTicketEnv);
+ SetUserContext(NUnittest::TVMKNIFE_PUBLIC_KEYS);
+
+ TServiceTickets::TMapIdStr tickets, errors;
+ TServiceTickets::TMapAliasId aliases;
+
+ for (const TSettings::TTuple& t : settings.Backends) {
+ tickets[t.Id] = t.Value;
+ aliases[t.Alias] = t.Id;
+ }
+ for (const TSettings::TTuple& t : settings.BadBackends) {
+ errors[t.Id] = t.Value;
+ aliases[t.Alias] = t.Id;
+ }
+
+ SetServiceTickets(MakeIntrusiveConst<TServiceTickets>(
+ std::move(tickets),
+ std::move(errors),
+ std::move(aliases)));
+
+ SetUpdateTimeOfPublicKeys(TInstant::Now());
+ SetUpdateTimeOfServiceTickets(TInstant::Now());
+ }
+}
diff --git a/library/cpp/tvmauth/client/mocked_updater.h b/library/cpp/tvmauth/client/mocked_updater.h
new file mode 100644
index 0000000000..f8a6394f5f
--- /dev/null
+++ b/library/cpp/tvmauth/client/mocked_updater.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include "misc/async_updater.h"
+
+namespace NTvmAuth {
+ class TMockedUpdater: public TAsyncUpdaterBase {
+ public:
+ struct TSettings {
+ struct TTuple {
+ TClientSettings::TAlias Alias;
+ TTvmId Id = 0;
+ TString Value; // ticket or error
+ };
+
+ TTvmId SelfTvmId = 0;
+ TVector<TTuple> Backends;
+ TVector<TTuple> BadBackends;
+ EBlackboxEnv UserTicketEnv = EBlackboxEnv::Test;
+ NRoles::TRolesPtr Roles;
+
+ static TSettings CreateDeafult();
+ };
+
+ TMockedUpdater(const TSettings& settings = TSettings::CreateDeafult());
+
+ TClientStatus GetStatus() const override {
+ return TClientStatus();
+ }
+
+ NRoles::TRolesPtr GetRoles() const override {
+ return Roles_;
+ }
+
+ using TAsyncUpdaterBase::SetServiceContext;
+ using TAsyncUpdaterBase::SetServiceTickets;
+ using TAsyncUpdaterBase::SetUpdateTimeOfPublicKeys;
+ using TAsyncUpdaterBase::SetUpdateTimeOfServiceTickets;
+ using TAsyncUpdaterBase::SetUserContext;
+
+ protected:
+ NRoles::TRolesPtr Roles_;
+ };
+}
diff --git a/library/cpp/tvmauth/client/ut/async_updater_ut.cpp b/library/cpp/tvmauth/client/ut/async_updater_ut.cpp
new file mode 100644
index 0000000000..1c1e8cbaae
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/async_updater_ut.cpp
@@ -0,0 +1,165 @@
+#include "common.h"
+
+#include <library/cpp/tvmauth/client/misc/async_updater.h>
+
+#include <library/cpp/tvmauth/unittest.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NTvmAuth;
+
+Y_UNIT_TEST_SUITE(AsyncUpdater) {
+ static const TString SRV_TICKET = "3:serv:CBAQ__________9_IgYIexCUkQY:GioCM49Ob6_f80y6FY0XBVN4hLXuMlFeyMvIMiDuQnZkbkLpRpQOuQo5YjWoBjM0Vf-XqOm8B7xtrvxSYHDD7Q4OatN2l-Iwg7i71lE3scUeD36x47st3nd0OThvtjrFx_D8mw_c0GT5KcniZlqq1SjhLyAk1b_zJsx8viRAhCU";
+ static const TString PROD_TICKET = "3:user:CAsQ__________9_Gg4KAgh7EHsg0oXYzAQoAA:N8PvrDNLh-5JywinxJntLeQGDEHBUxfzjuvB8-_BEUv1x9CALU7do8irDlDYVeVVDr4AIpR087YPZVzWPAqmnBuRJS0tJXekmDDvrivLnbRrzY4IUXZ_fImB0fJhTyVetKv6RD11bGqnAJeDpIukBwPTbJc_EMvKDt8V490CJFw";
+ static const TString TEST_TICKET = "3:user:CA0Q__________9_Gg4KAgh7EHsg0oXYzAQoAQ:FSADps3wNGm92Vyb1E9IVq5M6ZygdGdt1vafWWEhfDDeCLoVA-sJesxMl2pGW4OxJ8J1r_MfpG3ZoBk8rLVMHUFrPa6HheTbeXFAWl8quEniauXvKQe4VyrpA1SPgtRoFqi5upSDIJzEAe1YRJjq1EClQ_slMt8R0kA_JjKUX54";
+ static const TString PROD_YATEAM_TICKET = "3:user:CAwQ__________9_Gg4KAgh7EHsg0oXYzAQoAg:M9dEFEWHLHXiL7brCsyfYlm254PE6VeshUjI62u2qMDRzt6-0jAoJTIdDiogerItht1YFYSn8fSqmMf23_rueGj-wkmvyNzbcBSk3jtK2U5sai_W0bK6OwukR9tzWzi1Gcgg9DrNEeIKFvs1EBqYCF4mPHWo5bgk0CR580Cgit4";
+ static const TString TEST_YATEAM_TICKET = "3:user:CA4Q__________9_Gg4KAgh7EHsg0oXYzAQoAw:IlaV3htk3jYrviIOz3k3Dfwz7p-bYYpbrgdn53GiUrMGdrT9eobHeuzNvPLrWB0yuYZAD46C3MGxok4GGmHhT73mki4XOCX8yWT4jW_hzcHBik1442tjWwh8IWqV_7q5j5496suVuLWjnZORWbb7I-2iwdIlU1BUiDfhoAolCq8";
+ static const TString STRESS_TICKET = "3:user:CA8Q__________9_Gg4KAgh7EHsg0oXYzAQoBA:GBuG_TLo6SL2OYFxp7Zly04HPNzmAF7Fu2E8E9SnwQDoxq9rf7VThSPtTmnBSAl5UVRRPkMsRtzzHZ87qtj6l-PvF0K7PrDu7-yS_xiFTgAl9sEfXAIHJVzZLoksGRgpoBtpBUg9vVaJsPns0kWFKJgq8M-Mk9agrSk7sb2VUeQ";
+
+ class TTestUpdater: public TAsyncUpdaterBase {
+ public:
+ using TAsyncUpdaterBase::SetBbEnv;
+ using TAsyncUpdaterBase::SetUserContext;
+
+ TClientStatus GetStatus() const override {
+ return TClientStatus();
+ }
+ };
+
+ Y_UNIT_TEST(User) {
+ TTestUpdater u;
+
+ UNIT_ASSERT(!u.GetCachedUserContext());
+
+ u.SetUserContext(NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ UNIT_ASSERT(!u.GetCachedUserContext());
+
+ UNIT_ASSERT_NO_EXCEPTION(u.SetBbEnv(EBlackboxEnv::Prod));
+ UNIT_ASSERT(u.GetCachedUserContext());
+ UNIT_ASSERT(u.GetCachedUserContext()->Check(PROD_TICKET));
+ UNIT_ASSERT_NO_EXCEPTION(u.GetCachedUserContext(EBlackboxEnv::ProdYateam));
+ UNIT_ASSERT(u.GetCachedUserContext(EBlackboxEnv::ProdYateam)->Check(PROD_YATEAM_TICKET));
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(u.SetBbEnv(EBlackboxEnv::Prod, EBlackboxEnv::Test),
+ TBrokenTvmClientSettings,
+ "Overriding of BlackboxEnv is illegal: Prod -> Test");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(u.GetCachedUserContext(EBlackboxEnv::Test),
+ TBrokenTvmClientSettings,
+ "Overriding of BlackboxEnv is illegal: Prod -> Test");
+
+ UNIT_ASSERT(u.GetCachedUserContext());
+ UNIT_ASSERT(u.GetCachedUserContext()->Check(PROD_TICKET));
+ }
+
+ class DummyUpdater: public TAsyncUpdaterBase {
+ public:
+ TClientStatus GetStatus() const override {
+ return TClientStatus();
+ }
+
+ using TAsyncUpdaterBase::SetServiceContext;
+ using TAsyncUpdaterBase::SetServiceTickets;
+ using TAsyncUpdaterBase::SetUserContext;
+ };
+
+ Y_UNIT_TEST(Cache) {
+ DummyUpdater d;
+
+ UNIT_ASSERT(!d.GetCachedServiceTickets());
+ TServiceTicketsPtr st = MakeIntrusiveConst<TServiceTickets>(TServiceTickets::TMapIdStr(),
+ TServiceTickets::TMapIdStr(),
+ TServiceTickets::TMapAliasId());
+ d.SetServiceTickets(st);
+ UNIT_ASSERT_EQUAL(st.Get(), d.GetCachedServiceTickets().Get());
+
+ UNIT_ASSERT(!d.GetCachedServiceContext());
+ TServiceContextPtr sc = MakeIntrusiveConst<TServiceContext>(TServiceContext::SigningFactory("kjndfadfndsfafdasd"));
+ d.SetServiceContext(sc);
+ UNIT_ASSERT_EQUAL(sc.Get(), d.GetCachedServiceContext().Get());
+
+ UNIT_ASSERT(!d.GetCachedUserContext());
+ d.SetUserContext(NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ }
+
+ Y_UNIT_TEST(ServiceTickets_Aliases) {
+ using TId = TServiceTickets::TMapIdStr;
+ using TUnfetchedId = TServiceTickets::TIdSet;
+ using TStr = TServiceTickets::TMapAliasStr;
+ using TUnfetchedAlias = TServiceTickets::TAliasSet;
+ using TAls = TServiceTickets::TMapAliasId;
+ TServiceTickets t(TId{}, TId{}, TAls{});
+
+ UNIT_ASSERT_NO_EXCEPTION(t = TServiceTickets(TId({{1, "t1"}, {2, "t2"}}),
+ TId({{3, "e1"}}),
+ TAls()));
+ UNIT_ASSERT_EQUAL(TId({{1, "t1"}, {2, "t2"}}), t.TicketsById);
+ UNIT_ASSERT_EQUAL(TId({{3, "e1"}}), t.ErrorsById);
+ UNIT_ASSERT_EQUAL(TStr(), t.TicketsByAlias);
+ UNIT_ASSERT_EQUAL(TStr(), t.ErrorsByAlias);
+
+ UNIT_ASSERT_NO_EXCEPTION(t = TServiceTickets(TId({{1, "t1"}, {2, "t2"}}),
+ TId({{3, "e1"}}),
+ TAls({{"1", 1}, {"2", 2}, {"3", 3}})));
+ UNIT_ASSERT_EQUAL(TId({{1, "t1"}, {2, "t2"}}), t.TicketsById);
+ UNIT_ASSERT_EQUAL(TId({{3, "e1"}}), t.ErrorsById);
+ UNIT_ASSERT_EQUAL(TUnfetchedId(), t.UnfetchedIds);
+ UNIT_ASSERT_EQUAL(TStr({{"1", "t1"}, {"2", "t2"}}), t.TicketsByAlias);
+ UNIT_ASSERT_EQUAL(TStr({{"3", "e1"}}), t.ErrorsByAlias);
+ UNIT_ASSERT_EQUAL(TUnfetchedAlias({}), t.UnfetchedAliases);
+ }
+
+ Y_UNIT_TEST(ServiceTickets_UnfetchedIds) {
+ using TId = TServiceTickets::TMapIdStr;
+ using TUnfetchedId = TServiceTickets::TIdSet;
+ using TStr = TServiceTickets::TMapAliasStr;
+ using TUnfetchedAlias = TServiceTickets::TAliasSet;
+ using TAls = TServiceTickets::TMapAliasId;
+ TServiceTickets t(TId({{1, "t1"}, {2, "t2"}}),
+ TId(),
+ TAls({{"1", 1}, {"2", 2}, {"3", 3}}));
+
+ UNIT_ASSERT_EQUAL(TId({{1, "t1"}, {2, "t2"}}), t.TicketsById);
+ UNIT_ASSERT_EQUAL(TId({}), t.ErrorsById);
+ UNIT_ASSERT_EQUAL(TUnfetchedId({3}), t.UnfetchedIds);
+ UNIT_ASSERT_EQUAL(TUnfetchedAlias({{"3"}}), t.UnfetchedAliases);
+ UNIT_ASSERT_EQUAL(TStr({{"1", "t1"}, {"2", "t2"}}), t.TicketsByAlias);
+ UNIT_ASSERT_EQUAL(TStr(), t.ErrorsByAlias);
+ }
+
+ Y_UNIT_TEST(ServiceTickets_InvalidationTime) {
+ using TId = TServiceTickets::TMapIdStr;
+ using TAls = TServiceTickets::TMapAliasId;
+
+ TServiceTickets t(TId{}, TId{}, TAls{});
+ UNIT_ASSERT_VALUES_EQUAL(TInstant(), t.InvalidationTime);
+
+ UNIT_ASSERT_NO_EXCEPTION(t = TServiceTickets(TId({{1, SRV_TICKET}}),
+ TId(),
+ TAls()));
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(std::numeric_limits<time_t>::max()), t.InvalidationTime);
+
+ UNIT_ASSERT_NO_EXCEPTION(t = TServiceTickets(TId({
+ {1, SRV_TICKET},
+ {2, "serv"},
+ }),
+ TId(),
+ TAls()));
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(std::numeric_limits<time_t>::max()), t.InvalidationTime);
+
+ UNIT_ASSERT_NO_EXCEPTION(t = TServiceTickets(TId({
+ {2, "serv"},
+ }),
+ TId(),
+ TAls()));
+ UNIT_ASSERT_VALUES_EQUAL(TInstant(), t.InvalidationTime);
+
+ UNIT_ASSERT_NO_EXCEPTION(t = TServiceTickets(TId({
+ {1, SRV_TICKET},
+ {2, "serv"},
+ {3, "3:serv:CBAQeyIECAMQAw:TiZjG2Ut9j-9n0zcqxGW8xiYmnFa-i10-dbA0FKIInKzeDuueovWVEBcgbQHndblzRCxoIBMgbotOf7ALk2xoSBnRbOKomAIEtiTBL77GByL5O8K_HUGNYb-ygqnmZlIuLalgeRQAdsKstgUwQzufnOQyekipmamwo7EVQhr8Ug"},
+ }),
+ TId(),
+ TAls()));
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(123), t.InvalidationTime);
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/checker_ut.cpp b/library/cpp/tvmauth/client/ut/checker_ut.cpp
new file mode 100644
index 0000000000..54a25974c1
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/checker_ut.cpp
@@ -0,0 +1,176 @@
+#include "common.h"
+
+#include <library/cpp/tvmauth/client/mocked_updater.h>
+#include <library/cpp/tvmauth/client/misc/checker.h>
+#include <library/cpp/tvmauth/client/misc/getter.h>
+#include <library/cpp/tvmauth/client/misc/api/threaded_updater.h>
+
+#include <library/cpp/tvmauth/type.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NTvmAuth;
+
+Y_UNIT_TEST_SUITE(ClientChecker) {
+ static const TTvmId OK_CLIENT = 100500;
+ static const TString PROD_TICKET = "3:user:CAsQ__________9_Gg4KAgh7EHsg0oXYzAQoAA:N8PvrDNLh-5JywinxJntLeQGDEHBUxfzjuvB8-_BEUv1x9CALU7do8irDlDYVeVVDr4AIpR087YPZVzWPAqmnBuRJS0tJXekmDDvrivLnbRrzY4IUXZ_fImB0fJhTyVetKv6RD11bGqnAJeDpIukBwPTbJc_EMvKDt8V490CJFw";
+ static const TString TEST_TICKET = "3:user:CA0Q__________9_Gg4KAgh7EHsg0oXYzAQoAQ:FSADps3wNGm92Vyb1E9IVq5M6ZygdGdt1vafWWEhfDDeCLoVA-sJesxMl2pGW4OxJ8J1r_MfpG3ZoBk8rLVMHUFrPa6HheTbeXFAWl8quEniauXvKQe4VyrpA1SPgtRoFqi5upSDIJzEAe1YRJjq1EClQ_slMt8R0kA_JjKUX54";
+ static const TString PROD_YATEAM_TICKET = "3:user:CAwQ__________9_Gg4KAgh7EHsg0oXYzAQoAg:M9dEFEWHLHXiL7brCsyfYlm254PE6VeshUjI62u2qMDRzt6-0jAoJTIdDiogerItht1YFYSn8fSqmMf23_rueGj-wkmvyNzbcBSk3jtK2U5sai_W0bK6OwukR9tzWzi1Gcgg9DrNEeIKFvs1EBqYCF4mPHWo5bgk0CR580Cgit4";
+ static const TString TEST_YATEAM_TICKET = "3:user:CA4Q__________9_Gg4KAgh7EHsg0oXYzAQoAw:IlaV3htk3jYrviIOz3k3Dfwz7p-bYYpbrgdn53GiUrMGdrT9eobHeuzNvPLrWB0yuYZAD46C3MGxok4GGmHhT73mki4XOCX8yWT4jW_hzcHBik1442tjWwh8IWqV_7q5j5496suVuLWjnZORWbb7I-2iwdIlU1BUiDfhoAolCq8";
+ static const TString STRESS_TICKET = "3:user:CA8Q__________9_Gg4KAgh7EHsg0oXYzAQoBA:GBuG_TLo6SL2OYFxp7Zly04HPNzmAF7Fu2E8E9SnwQDoxq9rf7VThSPtTmnBSAl5UVRRPkMsRtzzHZ87qtj6l-PvF0K7PrDu7-yS_xiFTgAl9sEfXAIHJVzZLoksGRgpoBtpBUg9vVaJsPns0kWFKJgq8M-Mk9agrSk7sb2VUeQ";
+ static const TString SRV_TICKET = "3:serv:CBAQ__________9_IgYIexCUkQY:GioCM49Ob6_f80y6FY0XBVN4hLXuMlFeyMvIMiDuQnZkbkLpRpQOuQo5YjWoBjM0Vf-XqOm8B7xtrvxSYHDD7Q4OatN2l-Iwg7i71lE3scUeD36x47st3nd0OThvtjrFx_D8mw_c0GT5KcniZlqq1SjhLyAk1b_zJsx8viRAhCU";
+
+ Y_UNIT_TEST(User) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(OK_CLIENT);
+ s.EnableServiceTicketChecking();
+ s.SetDiskCacheDir(GetCachePath());
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ auto u = NTvmApi::TThreadedUpdater::Create(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u->GetStatus().GetCode());
+ UNIT_ASSERT_EXCEPTION(TUserTicketChecker(u), TBrokenTvmClientSettings);
+ }
+ UNIT_ASSERT_C(l->Stream.Str().find("was successfully fetched") == TString::npos, l->Stream.Str());
+
+ s.EnableUserTicketChecking(EBlackboxEnv::Prod);
+ {
+ auto u = NTvmApi::TThreadedUpdater::Create(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u->GetStatus().GetCode());
+ TUserTicketChecker c(u);
+ UNIT_ASSERT(c.Check(PROD_TICKET, {}));
+ UNIT_ASSERT(!c.Check(TEST_TICKET, {}));
+ UNIT_ASSERT(!c.Check(PROD_YATEAM_TICKET, {}));
+ UNIT_ASSERT(!c.Check(TEST_YATEAM_TICKET, {}));
+ UNIT_ASSERT(!c.Check(STRESS_TICKET, {}));
+
+ UNIT_ASSERT(!c.Check(PROD_TICKET, EBlackboxEnv::ProdYateam));
+ UNIT_ASSERT(!c.Check(TEST_TICKET, EBlackboxEnv::ProdYateam));
+ UNIT_ASSERT(c.Check(PROD_YATEAM_TICKET, EBlackboxEnv::ProdYateam));
+ UNIT_ASSERT(!c.Check(TEST_YATEAM_TICKET, EBlackboxEnv::ProdYateam));
+ UNIT_ASSERT(!c.Check(STRESS_TICKET, EBlackboxEnv::ProdYateam));
+
+ UNIT_ASSERT_EXCEPTION(c.Check(PROD_TICKET, EBlackboxEnv::Stress), TBrokenTvmClientSettings);
+ }
+
+ s.EnableUserTicketChecking(EBlackboxEnv::Test);
+ {
+ auto u = NTvmApi::TThreadedUpdater::Create(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u->GetStatus().GetCode());
+ TUserTicketChecker c(u);
+ UNIT_ASSERT(!c.Check(PROD_TICKET, {}));
+ UNIT_ASSERT(c.Check(TEST_TICKET, {}));
+ UNIT_ASSERT(!c.Check(PROD_YATEAM_TICKET, {}));
+ UNIT_ASSERT(!c.Check(TEST_YATEAM_TICKET, {}));
+ UNIT_ASSERT(!c.Check(STRESS_TICKET, {}));
+ }
+
+ s.EnableUserTicketChecking(EBlackboxEnv::ProdYateam);
+ {
+ auto u = NTvmApi::TThreadedUpdater::Create(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u->GetStatus().GetCode());
+ TUserTicketChecker c(u);
+ UNIT_ASSERT(!c.Check(PROD_TICKET, {}));
+ UNIT_ASSERT(!c.Check(TEST_TICKET, {}));
+ UNIT_ASSERT(c.Check(PROD_YATEAM_TICKET, {}));
+ UNIT_ASSERT(!c.Check(TEST_YATEAM_TICKET, {}));
+ UNIT_ASSERT(!c.Check(STRESS_TICKET, {}));
+ }
+
+ s.EnableUserTicketChecking(EBlackboxEnv::TestYateam);
+ {
+ auto u = NTvmApi::TThreadedUpdater::Create(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u->GetStatus().GetCode());
+ TUserTicketChecker c(u);
+ UNIT_ASSERT(!c.Check(PROD_TICKET, {}));
+ UNIT_ASSERT(!c.Check(TEST_TICKET, {}));
+ UNIT_ASSERT(!c.Check(PROD_YATEAM_TICKET, {}));
+ UNIT_ASSERT(c.Check(TEST_YATEAM_TICKET, {}));
+ UNIT_ASSERT(!c.Check(STRESS_TICKET, {}));
+ }
+
+ s.EnableUserTicketChecking(EBlackboxEnv::Stress);
+ {
+ auto u = NTvmApi::TThreadedUpdater::Create(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u->GetStatus().GetCode());
+ TUserTicketChecker c(u);
+ UNIT_ASSERT(c.Check(PROD_TICKET, {}));
+ UNIT_ASSERT(!c.Check(TEST_TICKET, {}));
+ UNIT_ASSERT(!c.Check(PROD_YATEAM_TICKET, {}));
+ UNIT_ASSERT(!c.Check(TEST_YATEAM_TICKET, {}));
+ UNIT_ASSERT(c.Check(STRESS_TICKET, {}));
+ }
+ }
+
+ Y_UNIT_TEST(Service) {
+ NTvmApi::TClientSettings s;
+ s.EnableUserTicketChecking(EBlackboxEnv::Stress);
+ s.SetSelfTvmId(OK_CLIENT);
+ s.SetDiskCacheDir(GetCachePath());
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ auto u = NTvmApi::TThreadedUpdater::Create(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u->GetStatus().GetCode());
+ UNIT_ASSERT_EXCEPTION(TServiceTicketChecker(u), TBrokenTvmClientSettings);
+ }
+ UNIT_ASSERT_C(l->Stream.Str().find("was successfully fetched") == TString::npos, l->Stream.Str());
+
+ s.EnableServiceTicketChecking();
+ l = MakeIntrusive<TLogger>();
+ {
+ auto u = NTvmApi::TThreadedUpdater::Create(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u->GetStatus().GetCode());
+ TServiceTicketChecker c(u);
+ UNIT_ASSERT(c.Check(SRV_TICKET));
+ UNIT_ASSERT(!c.Check(PROD_TICKET));
+ }
+ UNIT_ASSERT_C(l->Stream.Str().find("was successfully fetched") == TString::npos, l->Stream.Str());
+
+ s.SetSelfTvmId(17);
+ l = MakeIntrusive<TLogger>();
+ {
+ auto u = NTvmApi::TThreadedUpdater::Create(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u->GetStatus().GetCode());
+ TServiceTicketChecker c(u);
+ UNIT_ASSERT(!c.Check(SRV_TICKET));
+ UNIT_ASSERT(!c.Check(PROD_TICKET));
+ }
+ UNIT_ASSERT_C(l->Stream.Str().find("was successfully fetched") == TString::npos, l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(Tickets) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(OK_CLIENT);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}});
+ s.SetDiskCacheDir(GetCachePath());
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ auto u = NTvmApi::TThreadedUpdater::Create(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u->GetStatus().GetCode());
+ TServiceTicketGetter g(u);
+ UNIT_ASSERT_VALUES_EQUAL("3:serv:CBAQ__________9_IgYIKhCUkQY:CX", g.GetTicket("blackbox"));
+ UNIT_ASSERT_EXCEPTION_CONTAINS(g.GetTicket("blackbox2"),
+ TBrokenTvmClientSettings,
+ "Destination 'blackbox2' was not specified in settings. Check your settings (if you use Qloud/YP/tvmtool - check it's settings)");
+ }
+ UNIT_ASSERT_C(l->Stream.Str().find("was successfully fetched") == TString::npos, l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(ErrorForDst) {
+ TServiceTicketGetter g(new TMockedUpdater);
+
+ UNIT_ASSERT_VALUES_EQUAL(TMockedUpdater::TSettings::CreateDeafult().Backends.at(0).Value,
+ g.GetTicket("my_dest"));
+ UNIT_ASSERT_VALUES_EQUAL(TMockedUpdater::TSettings::CreateDeafult().Backends.at(0).Value,
+ g.GetTicket(42));
+ UNIT_ASSERT_EXCEPTION_CONTAINS(g.GetTicket("my_bad_dest"),
+ TMissingServiceTicket,
+ "Failed to get ticket for 'my_bad_dest': Dst is not found");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(g.GetTicket(43),
+ TMissingServiceTicket,
+ "Failed to get ticket for '43': Dst is not found");
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/client_status_ut.cpp b/library/cpp/tvmauth/client/ut/client_status_ut.cpp
new file mode 100644
index 0000000000..a1c3ae74ce
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/client_status_ut.cpp
@@ -0,0 +1,18 @@
+#include <library/cpp/tvmauth/client/client_status.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NTvmAuth;
+
+Y_UNIT_TEST_SUITE(ClientStatus) {
+ Y_UNIT_TEST(Common) {
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, TClientStatus().GetCode());
+ UNIT_ASSERT_VALUES_EQUAL("", TClientStatus().GetLastError());
+
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Warning, TClientStatus(TClientStatus::Warning, "kek"));
+ UNIT_ASSERT_VALUES_EQUAL("kek",
+ TClientStatus(TClientStatus::Warning, "kek").GetLastError());
+ UNIT_ASSERT_VALUES_EQUAL("2;TvmClient: kek\n",
+ TClientStatus(TClientStatus::Error, "kek").CreateJugglerMessage());
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/common.h b/library/cpp/tvmauth/client/ut/common.h
new file mode 100644
index 0000000000..5dddc182b5
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/common.h
@@ -0,0 +1,232 @@
+#pragma once
+
+#include <library/cpp/tvmauth/client/logger.h>
+#include <library/cpp/tvmauth/client/misc/disk_cache.h>
+#include <library/cpp/tvmauth/client/misc/roles/entities_index.h>
+
+#include <library/cpp/tvmauth/unittest.h>
+
+#include <library/cpp/cgiparam/cgiparam.h>
+#include <library/cpp/testing/mock_server/server.h>
+#include <library/cpp/testing/unittest/env.h>
+#include <library/cpp/testing/unittest/tests_data.h>
+
+#include <util/stream/str.h>
+#include <util/system/fs.h>
+
+class TLogger: public NTvmAuth::ILogger {
+public:
+ void Log(int lvl, const TString& msg) override {
+ Cout << TInstant::Now() << " lvl=" << lvl << " msg: " << msg << "\n";
+ Stream << lvl << ": " << msg << Endl;
+ }
+
+ TStringStream Stream;
+};
+
+static inline TString GetFilePath(const char* name) {
+ return ArcadiaSourceRoot() + "/library/cpp/tvmauth/client/ut/files/" + name;
+}
+
+static inline TString GetCachePath(const TString& dir = {}) {
+ if (dir) {
+ Y_ENSURE(NFs::MakeDirectoryRecursive("./" + dir));
+ }
+
+ auto wr = [](const TString& p, const TStringBuf body) {
+ NTvmAuth::TDiskWriter w(p);
+ Y_ENSURE(w.Write(body, TInstant::ParseIso8601("2050-01-01T00:00:00.000000Z")));
+ };
+ wr("./" + dir + "/public_keys", NTvmAuth::NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ wr("./" + dir + "/service_tickets",
+ R"({
+ "19" : { "ticket" : "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"},
+ "213" : { "ticket" : "service_ticket_2"},
+ "234" : { "error" : "Dst is not found" },
+ "185" : { "ticket" : "service_ticket_3"}
+} 100500)");
+
+ return "./" + dir;
+}
+
+static const TString AUTH_TOKEN = "strong_token";
+static const TString META = R"(
+{
+"bb_env" : "ProdYaTeam",
+"tenants" : [
+ {
+ "self": {
+ "alias" : "me",
+ "client_id": 100500
+ },
+ "dsts" : [
+ {
+ "alias" : "bbox",
+ "client_id": 242
+ },
+ {
+ "alias" : "pass_likers",
+ "client_id": 11
+ }
+ ]
+ },
+ {
+ "self": {
+ "alias" : "push-client",
+ "client_id": 100501
+ },
+ "dsts" : [
+ {
+ "alias" : "pass_likers",
+ "client_id": 100502
+ }
+ ]
+ },
+ {
+ "self": {
+ "alias" : "multi_names_for_dst",
+ "client_id": 100599
+ },
+ "dsts" : [
+ {
+ "alias" : "pass_likers",
+ "client_id": 100502
+ },
+ {
+ "alias" : "pass_haters",
+ "client_id": 100502
+ }
+ ]
+ },
+ {
+ "self": {
+ "alias" : "something_else",
+ "client_id": 100503
+ },
+ "dsts" : [
+ ]
+ }
+]
+})";
+
+static const TString TICKETS_ME =
+ R"({
+ "pass_likers": {
+ "ticket": "3:serv:CBAQ__________9_IgYIlJEGEAs:T-apeMNWFc_vHPQ3iLaZv9NjG-hf5-i23O4AhRu1M68ryN3FU5qvyqTSSiPbtJdFP6EE41QQBzEs59dHn9DRkqQNwwKf1is00Oewwj2XKO0uHukuzd9XxZnro7MfjPswsjWufxX28rmJtlfSXwAtyKt8TI5yKJnMeBPQ0m5R3k8",
+ "tvm_id": 11
+ },
+ "bbox": {
+ "ticket": "3:serv:CBAQ__________9_IgcIlJEGEPIB:N7luw0_rVmBosTTI130jwDbQd0-cMmqJeEl0ma4ZlIo_mHXjBzpOuMQ3A9YagbmOBOt8TZ_gzGvVSegWZkEeB24gM22acw0w-RcHaQKrzSOA5Zq8WLNIC8QUa4_WGTlAsb7R7eC4KTAGgouIquNAgMBdTuGOuZHnMLvZyLnOMKc",
+ "tvm_id": 242
+ }
+ })";
+
+static const TString SERVICE_TICKET_PC = "3:serv:CBAQ__________9_IggIlpEGEJaRBg:BAxaQJCdK4eFuJ6i_egqPwvJgWtlh0enDQRPr84Nx2phZ_8QtxKAUCwEa7KOU_jVvIBQIC5-ETTl2vjBt7UyygF8frdK4ab6zJoWj4n07np6vbmWd385l8KvzztLt4QkBrPiE7U46dK3pL0U8tfBkSXE8rvUIsl3RvvgSNH2J3c";
+static const TString TICKETS_PC =
+ R"({
+ "pass_likers": {
+ "ticket": "3:serv:CBAQ__________9_IggIlpEGEJaRBg:BAxaQJCdK4eFuJ6i_egqPwvJgWtlh0enDQRPr84Nx2phZ_8QtxKAUCwEa7KOU_jVvIBQIC5-ETTl2vjBt7UyygF8frdK4ab6zJoWj4n07np6vbmWd385l8KvzztLt4QkBrPiE7U46dK3pL0U8tfBkSXE8rvUIsl3RvvgSNH2J3c",
+ "tvm_id": 100502
+ }
+ })";
+
+static const TString TICKETS_MANY_DSTS =
+ R"({
+ "pass_likers": {
+ "ticket": "3:serv:CBAQ__________9_IggI95EGEJaRBg:D0MOLDhKQyI-OhC0ON9gYukz2hOctUipu1yXsvkw6NRuLhcBfvGayyUqF4ILrqepjz9GtPWIR_wO6oLSW35Z0YaFn60QWp5tG6IcAnr80lm_OnLHJt4kmEoLtGg1V0aWBT0YyouzGB2-QFNOVO86G7sYzU8FC6-V3Iyc4X7XTNc",
+ "tvm_id": 100502
+ },
+ "who_are_you??": {
+ "ticket": "kek",
+ "tvm_id": 100503
+ },
+ "pass_haters": {
+ "ticket": "3:serv:CBAQ__________9_IggI95EGEJaRBg:D0MOLDhKQyI-OhC0ON9gYukz2hOctUipu1yXsvkw6NRuLhcBfvGayyUqF4ILrqepjz9GtPWIR_wO6oLSW35Z0YaFn60QWp5tG6IcAnr80lm_OnLHJt4kmEoLtGg1V0aWBT0YyouzGB2-QFNOVO86G7sYzU8FC6-V3Iyc4X7XTNc",
+ "tvm_id": 100502
+ }
+ })";
+
+static const TString TICKETS_SE = R"({})";
+
+static const TInstant BIRTHTIME = TInstant::Seconds(14380887840);
+class TTvmTool: public TRequestReplier {
+public:
+ TString Meta;
+ HttpCodes Code;
+ TInstant Birthtime;
+
+ TTvmTool()
+ : Meta(META)
+ , Code(HTTP_OK)
+ , Birthtime(BIRTHTIME)
+ {
+ }
+
+ bool DoReply(const TReplyParams& params) override {
+ const TParsedHttpFull http(params.Input.FirstLine());
+ if (http.Path == "/tvm/ping") {
+ THttpResponse resp(HTTP_OK);
+ resp.SetContent("OK");
+ resp.OutTo(params.Output);
+ return true;
+ }
+
+ auto it = std::find_if(params.Input.Headers().begin(),
+ params.Input.Headers().end(),
+ [](const THttpInputHeader& h) { return h.Name() == "Authorization"; });
+ if (it == params.Input.Headers().end() || it->Value() != AUTH_TOKEN) {
+ THttpResponse resp(HTTP_UNAUTHORIZED);
+ resp.SetContent("pong");
+ resp.OutTo(params.Output);
+ return true;
+ }
+
+ THttpResponse resp(Code);
+ if (http.Path == "/tvm/keys") {
+ resp.SetContent(NTvmAuth::NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ } else if (http.Path == "/tvm/tickets") {
+ TCgiParameters cg;
+ cg.ScanAddAll(http.Cgi);
+ if (cg.Get("src") == "100500") {
+ resp.SetContent(TICKETS_ME);
+ } else if (cg.Get("src") == "100501") {
+ resp.SetContent(TICKETS_PC);
+ } else if (cg.Get("src") == "100599") {
+ resp.SetContent(TICKETS_MANY_DSTS);
+ }
+ } else if (http.Path == "/tvm/private_api/__meta__") {
+ resp.SetContent(Meta);
+ }
+ resp.AddHeader("X-Ya-Tvmtool-Data-Birthtime", IntToString<10>(Birthtime.Seconds()));
+ resp.OutTo(params.Output);
+
+ return true;
+ }
+};
+
+static inline NTvmAuth::NRoles::TEntitiesIndex CreateEntitiesIndex() {
+ using namespace NTvmAuth::NRoles;
+
+ TEntitiesIndex index(
+ {
+ std::make_shared<TEntity>(TEntity{
+ {"key#1", "value#11"},
+ }),
+ std::make_shared<TEntity>(TEntity{
+ {"key#1", "value#11"},
+ {"key#2", "value#22"},
+ {"key#3", "value#33"},
+ }),
+ std::make_shared<TEntity>(TEntity{
+ {"key#1", "value#11"},
+ {"key#2", "value#23"},
+ {"key#3", "value#33"},
+ }),
+ std::make_shared<TEntity>(TEntity{
+ {"key#1", "value#13"},
+ {"key#3", "value#33"},
+ }),
+ });
+
+ return index;
+}
diff --git a/library/cpp/tvmauth/client/ut/default_uid_checker_ut.cpp b/library/cpp/tvmauth/client/ut/default_uid_checker_ut.cpp
new file mode 100644
index 0000000000..a92530cab1
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/default_uid_checker_ut.cpp
@@ -0,0 +1,52 @@
+#include "common.h"
+
+#include <library/cpp/tvmauth/client/mocked_updater.h>
+#include <library/cpp/tvmauth/client/misc/default_uid_checker.h>
+#include <library/cpp/tvmauth/client/misc/api/threaded_updater.h>
+
+#include <library/cpp/tvmauth/type.h>
+#include <library/cpp/tvmauth/unittest.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NTvmAuth;
+
+Y_UNIT_TEST_SUITE(DefaultUidChecker) {
+ Y_UNIT_TEST(Ctor) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TDefaultUidChecker(new TMockedUpdater),
+ TBrokenTvmClientSettings,
+ "Need to use TClientSettings::EnableRolesFetching");
+ }
+
+ Y_UNIT_TEST(Check) {
+ NRoles::TRolesPtr roles = std::make_shared<NRoles::TRoles>(
+ NRoles::TRoles::TMeta{},
+ NRoles::TRoles::TTvmConsumers{},
+ NRoles::TRoles::TUserConsumers{
+ {12345, std::make_shared<NRoles::TConsumerRoles>(
+ THashMap<TString, NRoles::TEntitiesPtr>())},
+ },
+ std::make_shared<TString>());
+ const TDefaultUidChecker checker(new TMockedUpdater({.Roles = roles}));
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ checker.Check(NUnittest::CreateUserTicket(ETicketStatus::Expired, 12345, {})),
+ TIllegalUsage,
+ "User ticket must be valid");
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ checker.Check(NUnittest::CreateUserTicket(ETicketStatus::Ok, 12345, {}, {}, EBlackboxEnv::Test)),
+ TIllegalUsage,
+ "User ticket must be from ProdYateam, got from Test");
+
+ TCheckedUserTicket ticket;
+ UNIT_ASSERT_NO_EXCEPTION(
+ ticket = checker.Check(NUnittest::CreateUserTicket(ETicketStatus::Ok, 12345, {}, {}, EBlackboxEnv::ProdYateam)));
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::Ok, ticket.GetStatus());
+
+ UNIT_ASSERT_NO_EXCEPTION(
+ ticket = checker.Check(NUnittest::CreateUserTicket(ETicketStatus::Ok, 9999, {}, {}, EBlackboxEnv::ProdYateam)));
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::NoRoles, ticket.GetStatus());
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/disk_cache_ut.cpp b/library/cpp/tvmauth/client/ut/disk_cache_ut.cpp
new file mode 100644
index 0000000000..7dd851c9b3
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/disk_cache_ut.cpp
@@ -0,0 +1,204 @@
+#include "common.h"
+
+#include <library/cpp/tvmauth/client/logger.h>
+#include <library/cpp/tvmauth/client/misc/disk_cache.h>
+
+#include <library/cpp/tvmauth/src/utils.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/testing/unittest/tests_data.h>
+
+#include <util/stream/file.h>
+#include <util/system/fs.h>
+#include <util/system/sysstat.h>
+
+#include <thread>
+
+using namespace NTvmAuth;
+
+Y_UNIT_TEST_SUITE(ClientDisk) {
+ Y_UNIT_TEST(Hash) {
+ TString hash = TDiskReader::GetHash("asd");
+ UNIT_ASSERT(hash);
+ UNIT_ASSERT_VALUES_EQUAL(32, hash.size());
+ UNIT_ASSERT_VALUES_EQUAL("Zj5_qYg31bPlqjBW76z8IV0rCsHmv-iN-McV6ybS1-g", NUtils::Bin2base64url(hash));
+ }
+
+ Y_UNIT_TEST(Timestamp) {
+ time_t t = 100500;
+
+ TString s = TDiskWriter::WriteTimestamp(t);
+ UNIT_ASSERT_VALUES_EQUAL("lIgBAAAAAAA", NUtils::Bin2base64url(s));
+ UNIT_ASSERT_VALUES_EQUAL(t, TDiskReader::GetTimestamp(s));
+
+ t = 123123123213089;
+ s = TDiskWriter::WriteTimestamp(t);
+ UNIT_ASSERT_VALUES_EQUAL("IdMF1vpvAAA", NUtils::Bin2base64url(s));
+ UNIT_ASSERT_VALUES_EQUAL(t, TDiskReader::GetTimestamp(s));
+
+ t = time(nullptr);
+ s = TDiskWriter::WriteTimestamp(t);
+ UNIT_ASSERT_VALUES_EQUAL(t, TDiskReader::GetTimestamp(s));
+ }
+
+ const TInstant TIME = TInstant::Seconds(100500);
+ const TString DATA = "oiweuhn \n vw3ut hweoi uhgewproritjhwequtherwoiughfdsv 8ty34q01u 34 1=3";
+
+ Y_UNIT_TEST(ParseData_Ok) {
+ TLogger l;
+
+ const TInstant time = TInstant::Seconds(1523446554789);
+
+ TString toFile = TDiskWriter::PrepareData(time, DATA);
+ UNIT_ASSERT_VALUES_EQUAL(113, toFile.size());
+ UNIT_ASSERT_VALUES_EQUAL("T8BnRIMoC6mlMXexPg9cV5jYxeFtgDWk97JTajHDunCloH20YgEAAG9pd2V1aG4gCiB2dzN1dCBod2VvaSB1aGdld3Byb3JpdGpod2VxdXRoZXJ3b2l1Z2hmZHN2IDh0eTM0cTAxdSAgIDM0ICAxPTM",
+ NUtils::Bin2base64url(toFile));
+
+ TDiskReader r("qwerty", &l);
+ UNIT_ASSERT(r.ParseData(toFile));
+ UNIT_ASSERT_VALUES_EQUAL(DATA, r.Data());
+ UNIT_ASSERT_VALUES_EQUAL(time, r.Time());
+ UNIT_ASSERT_VALUES_EQUAL("6: File 'qwerty' was successfully read\n",
+ l.Stream.Str());
+ }
+
+ Y_UNIT_TEST(ParseData_SmallFile) {
+ TLogger l;
+
+ TString toFile = TDiskWriter::PrepareData(TIME, DATA);
+ TDiskReader r("qwerty", &l);
+ UNIT_ASSERT(!r.ParseData(toFile.substr(0, 17)));
+ UNIT_ASSERT_VALUES_EQUAL("4: File 'qwerty' is too small\n",
+ l.Stream.Str());
+ }
+
+ Y_UNIT_TEST(ParseData_Changed) {
+ TLogger l;
+
+ TString toFile = TDiskWriter::PrepareData(TIME, DATA);
+ toFile[17] = toFile[17] + 1;
+ TDiskReader r("qwerty", &l);
+ UNIT_ASSERT(!r.ParseData(toFile));
+ UNIT_ASSERT_VALUES_EQUAL("4: Content of 'qwerty' was incorrectly changed\n",
+ l.Stream.Str());
+ }
+
+ Y_UNIT_TEST(Read_Ok) {
+ TLogger l;
+
+ TDiskReader r(GetFilePath("ok.cache"), &l);
+ UNIT_ASSERT(r.Read());
+ UNIT_ASSERT_VALUES_EQUAL(DATA, r.Data());
+ UNIT_ASSERT_VALUES_EQUAL(TIME, r.Time());
+ UNIT_ASSERT_C(l.Stream.Str().find("was successfully read") != TString::npos, l.Stream.Str());
+ }
+
+ Y_UNIT_TEST(Read_NoFile) {
+ TLogger l;
+
+ TDiskReader r("missing", &l);
+ UNIT_ASSERT(!r.Read());
+ UNIT_ASSERT_VALUES_EQUAL("7: File 'missing' does not exist\n",
+ l.Stream.Str());
+ }
+
+#ifdef _unix_
+ Y_UNIT_TEST(Read_NoPermitions) {
+ TLogger l;
+
+ const TString path = GetWorkPath() + "/123";
+ {
+ TFileOutput output(path);
+ }
+ Chmod(path.data(), S_IWUSR);
+
+ TDiskReader r(path, &l);
+ UNIT_ASSERT(!r.Read());
+ UNIT_ASSERT_C(l.Stream.Str().find("Permission denied") != TString::npos, l.Stream.Str());
+
+ Chmod(path.data(), S_IRWXU);
+ NFs::Remove(path);
+ }
+#endif
+
+ Y_UNIT_TEST(Write_Ok) {
+ TLogger l;
+
+ const TString path = "./tmp_file";
+ TDiskWriter w(path, &l);
+ UNIT_ASSERT_C(w.Write(DATA), l.Stream.Str());
+ UNIT_ASSERT_C(l.Stream.Str().find("was successfully written") != TString::npos, l.Stream.Str());
+ l.Stream.Clear();
+
+ TDiskReader r(path, &l);
+ UNIT_ASSERT_C(r.Read(), l.Stream.Str());
+ UNIT_ASSERT_VALUES_EQUAL(DATA, r.Data());
+ UNIT_ASSERT(TInstant::Now() - r.Time() < TDuration::Minutes(5));
+ UNIT_ASSERT_C(l.Stream.Str().find("was successfully read") != TString::npos, l.Stream.Str());
+
+ NFs::Remove(path);
+ }
+
+ Y_UNIT_TEST(Write_NoPermitions) {
+ TLogger l;
+
+ TDiskWriter w("/some_file", &l);
+ UNIT_ASSERT(!w.Write(DATA));
+ UNIT_ASSERT_C(l.Stream.Str().Contains("3: Failed to write '/some_file': ("), l.Stream.Str());
+ UNIT_ASSERT_C(l.Stream.Str().Contains("denied"), l.Stream.Str());
+ }
+
+ Y_UNIT_TEST(race) {
+ const TString path = "./tmp_file";
+ const TString data = "ejufhsadkjfvbhsaoicnaofssdahfasdfhasdofdsaf";
+ NFs::Remove(path);
+
+ std::atomic<bool> fail = false;
+ std::vector<std::thread> thrs;
+ for (size_t idx = 0; idx < 16; ++idx) {
+ thrs.push_back(std::thread([&fail, data, path]() {
+ TDiskWriter w(path);
+ for (size_t k = 0; k < 1000; ++k) {
+ if (!w.Write(data)) {
+ fail = true;
+ }
+ }
+ }));
+ }
+ for (std::thread& t : thrs) {
+ t.join();
+ }
+ thrs.clear();
+ UNIT_ASSERT(fail);
+ {
+ TDiskWriter w(path);
+ UNIT_ASSERT(w.Write(data)); // checks unlocked flock
+ }
+
+ fail = false;
+
+ for (size_t idx = 0; idx < 4; ++idx) {
+ thrs.push_back(std::thread([&fail, data, path]() {
+ TLogger l;
+ TDiskReader r(path, &l);
+ for (size_t k = 0; k < 100; ++k) {
+ if (!r.Read()) {
+ Cerr << l.Stream.Str() << Flush;
+ fail = true;
+ return;
+ }
+ if (r.Data() != data) {
+ Cerr << (TStringBuilder() << "'" << data << "' vs '" << r.Data() << "'" << Endl) << Flush;
+ fail = true;
+ return;
+ }
+ }
+ }));
+ }
+ for (std::thread& t : thrs) {
+ t.join();
+ }
+ thrs.clear();
+ UNIT_ASSERT(!fail);
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/exponential_backoff_ut.cpp b/library/cpp/tvmauth/client/ut/exponential_backoff_ut.cpp
new file mode 100644
index 0000000000..3dcbe6ad49
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/exponential_backoff_ut.cpp
@@ -0,0 +1,44 @@
+#include <library/cpp/tvmauth/client/misc/exponential_backoff.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <thread>
+
+using namespace NTvmAuth;
+
+Y_UNIT_TEST_SUITE(PasspUtilsExpBackoff) {
+ Y_UNIT_TEST(common) {
+ TExponentialBackoff b({TDuration::Seconds(1), TDuration::Seconds(60), 2, 0.01});
+
+ UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(1), b.GetCurrentValue());
+
+ TDuration dur = b.GetCurrentValue();
+ for (size_t idx = 0; idx < 6; ++idx) {
+ TDuration newValue = b.Increase();
+ UNIT_ASSERT_LT(dur, newValue);
+ dur = newValue;
+ }
+
+ UNIT_ASSERT_LT(TDuration::Seconds(60) - TDuration::Seconds(3), dur);
+ UNIT_ASSERT_LT(dur, TDuration::Seconds(60) + TDuration::Seconds(3));
+ }
+
+ Y_UNIT_TEST(sleep) {
+ TExponentialBackoff b({TDuration::Seconds(60), TDuration::Seconds(600), 2, 0.01});
+
+ const TInstant start = TInstant::Now();
+
+ TAutoEvent started;
+ std::thread t([&b, &started]() {
+ started.Signal();
+ b.Sleep();
+ });
+
+ started.WaitT(TDuration::Seconds(30));
+ b.Interrupt();
+ t.join();
+ TDuration dur = TInstant::Now() - start;
+
+ UNIT_ASSERT_LT(dur, TDuration::Seconds(60));
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/facade_ut.cpp b/library/cpp/tvmauth/client/ut/facade_ut.cpp
new file mode 100644
index 0000000000..62e8e6c731
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/facade_ut.cpp
@@ -0,0 +1,167 @@
+#include "common.h"
+
+#include <library/cpp/tvmauth/client/facade.h>
+#include <library/cpp/tvmauth/client/mocked_updater.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/vector.h>
+
+using namespace NTvmAuth;
+
+Y_UNIT_TEST_SUITE(ClientFacade) {
+ static const TTvmId OK_CLIENT = 100500;
+ static const TString SRV_TICKET_123 = "3:serv:CBAQ__________9_IgYIexCUkQY:GioCM49Ob6_f80y6FY0XBVN4hLXuMlFeyMvIMiDuQnZkbkLpRpQOuQo5YjWoBjM0Vf-XqOm8B7xtrvxSYHDD7Q4OatN2l-Iwg7i71lE3scUeD36x47st3nd0OThvtjrFx_D8mw_c0GT5KcniZlqq1SjhLyAk1b_zJsx8viRAhCU";
+ static const TString SRV_TICKET_456 = "3:serv:CBAQ__________9_IgcIyAMQlJEG:VrnqRhpoiDnJeAQbySJluJ1moQ5Kemic99iWzOrHLGfuh7iTw_xMT7KewRAmZMUwDKzE6otj7V86Xsnxbv5xZl8746wbvNcyUXu-nGWmbByZjO7xpSIcY07sISqEhP9n9C_yMSvqDP7ho_PRIfpGCDMXxKlFZ_BhBLLp0kHEvw4";
+ static const TString PROD_TICKET = "3:user:CAsQ__________9_Gg4KAgh7EHsg0oXYzAQoAA:N8PvrDNLh-5JywinxJntLeQGDEHBUxfzjuvB8-_BEUv1x9CALU7do8irDlDYVeVVDr4AIpR087YPZVzWPAqmnBuRJS0tJXekmDDvrivLnbRrzY4IUXZ_fImB0fJhTyVetKv6RD11bGqnAJeDpIukBwPTbJc_EMvKDt8V490CJFw";
+ static const TString TEST_TICKET = "3:user:CA0Q__________9_Gg4KAgh7EHsg0oXYzAQoAQ:FSADps3wNGm92Vyb1E9IVq5M6ZygdGdt1vafWWEhfDDeCLoVA-sJesxMl2pGW4OxJ8J1r_MfpG3ZoBk8rLVMHUFrPa6HheTbeXFAWl8quEniauXvKQe4VyrpA1SPgtRoFqi5upSDIJzEAe1YRJjq1EClQ_slMt8R0kA_JjKUX54";
+
+ TTvmClient GetClient(const NTvmApi::TClientSettings& s) {
+ auto l = MakeIntrusive<TLogger>();
+ TTvmClient f(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, f.GetStatus());
+ Sleep(TDuration::MilliSeconds(300));
+ TString logs = l->Stream.Str();
+ UNIT_ASSERT_C(logs.find("was successfully read") != TString::npos, logs);
+ UNIT_ASSERT_C(logs.find("was successfully fetched") == TString::npos, logs);
+ return f;
+ }
+
+ Y_UNIT_TEST(Service) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(OK_CLIENT);
+ s.EnableServiceTicketChecking();
+ s.SetDiskCacheDir(GetCachePath());
+ TTvmClient f = GetClient(s);
+
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(2524608000), f.GetUpdateTimeOfPublicKeys());
+ UNIT_ASSERT_VALUES_EQUAL(TInstant(), f.GetUpdateTimeOfServiceTickets());
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(2525126400), f.GetInvalidationTimeOfPublicKeys());
+ UNIT_ASSERT_VALUES_EQUAL(TInstant(), f.GetInvalidationTimeOfServiceTickets());
+
+ UNIT_ASSERT(f.CheckServiceTicket(SRV_TICKET_123));
+ UNIT_ASSERT_EXCEPTION(f.CheckUserTicket(PROD_TICKET), yexception);
+ UNIT_ASSERT_EXCEPTION(f.CheckUserTicket(TEST_TICKET), yexception);
+ }
+
+ Y_UNIT_TEST(User) {
+ NTvmApi::TClientSettings s;
+ s.EnableUserTicketChecking(EBlackboxEnv::Prod);
+ s.SetDiskCacheDir(GetCachePath());
+
+ TTvmClient f = GetClient(s);
+ UNIT_ASSERT_EXCEPTION(f.CheckServiceTicket(SRV_TICKET_123), yexception);
+ UNIT_ASSERT(f.CheckUserTicket(PROD_TICKET));
+ UNIT_ASSERT(!f.CheckUserTicket(TEST_TICKET));
+ }
+
+ Y_UNIT_TEST(Ctors) {
+ NTvmApi::TClientSettings s;
+ s.EnableUserTicketChecking(EBlackboxEnv::Prod);
+ s.SetDiskCacheDir(GetCachePath());
+
+ TTvmClient f = GetClient(s);
+ f = GetClient(s);
+
+ TVector<TTvmClient> v;
+ v.push_back(std::move(f));
+ v.front() = std::move(*v.begin());
+ }
+
+ Y_UNIT_TEST(Tickets) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(OK_CLIENT);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}});
+ s.SetDiskCacheDir(GetCachePath());
+ TTvmClient f = GetClient(s);
+
+ UNIT_ASSERT_VALUES_EQUAL(TInstant(), f.GetUpdateTimeOfPublicKeys());
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::ParseIso8601("2050-01-01T00:00:00.000000Z"), f.GetUpdateTimeOfServiceTickets());
+ UNIT_ASSERT_VALUES_EQUAL(TInstant(), f.GetInvalidationTimeOfPublicKeys());
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(std::numeric_limits<size_t>::max()), f.GetInvalidationTimeOfServiceTickets());
+
+ UNIT_ASSERT_VALUES_EQUAL("3:serv:CBAQ__________9_IgYIKhCUkQY:CX", f.GetServiceTicketFor("blackbox"));
+ UNIT_ASSERT_VALUES_EQUAL("3:serv:CBAQ__________9_IgYIKhCUkQY:CX", f.GetServiceTicketFor(19));
+ UNIT_ASSERT_EXCEPTION_CONTAINS(f.GetServiceTicketFor("blackbox2"),
+ TBrokenTvmClientSettings,
+ "Destination 'blackbox2' was not specified in settings. Check your settings (if you use Qloud/YP/tvmtool - check it's settings)");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(f.GetServiceTicketFor(20),
+ TBrokenTvmClientSettings,
+ "Destination '20' was not specified in settings. Check your settings (if you use Qloud/YP/tvmtool - check it's settings)");
+ }
+
+ Y_UNIT_TEST(Tool) {
+ TPortManager pm;
+ ui16 port = pm.GetPort(80);
+ NMock::TMockServer server(port, []() { return new TTvmTool; });
+
+ NTvmTool::TClientSettings s("push-client");
+ s.SetPort(port);
+ s.SetAuthToken(AUTH_TOKEN);
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TTvmClient f(s, l);
+
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(14380887840), f.GetUpdateTimeOfPublicKeys());
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(14380887840), f.GetUpdateTimeOfServiceTickets());
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(14381406240), f.GetInvalidationTimeOfPublicKeys());
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(std::numeric_limits<time_t>::max()), f.GetInvalidationTimeOfServiceTickets());
+
+ UNIT_ASSERT_VALUES_EQUAL(SERVICE_TICKET_PC, f.GetServiceTicketFor("pass_likers"));
+ UNIT_ASSERT_VALUES_EQUAL(SERVICE_TICKET_PC, f.GetServiceTicketFor(100502));
+ UNIT_ASSERT_EXCEPTION_CONTAINS(f.GetServiceTicketFor("blackbox"),
+ TBrokenTvmClientSettings,
+ "Destination 'blackbox' was not specified in settings. Check your settings (if you use Qloud/YP/tvmtool - check it's settings)");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(f.GetServiceTicketFor(242),
+ TBrokenTvmClientSettings,
+ "Destination '242' was not specified in settings. Check your settings (if you use Qloud/YP/tvmtool - check it's settings)");
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "7: Meta info fetched from localhost:" << port << "\n"
+ << "6: Meta: self_tvm_id=100501, bb_env=ProdYateam, dsts=[(pass_likers:100502)]\n"
+ << "7: Tickets fetched from tvmtool: 2425-09-17T11:04:00.000000Z\n"
+ << "7: Public keys fetched from tvmtool: 2425-09-17T11:04:00.000000Z\n"
+ << "7: Thread-worker started\n"
+ << "7: Thread-worker stopped\n",
+ l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(CheckRoles) {
+ { // roles not configured
+ TTvmClient f(new TMockedUpdater(TMockedUpdater::TSettings{
+ .SelfTvmId = OK_CLIENT,
+ }));
+
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::Ok,
+ f.CheckServiceTicket(SRV_TICKET_123).GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::Ok,
+ f.CheckServiceTicket(SRV_TICKET_456).GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::Malformed,
+ f.CheckServiceTicket("asdfg").GetStatus());
+ }
+
+ { // roles configured
+ NRoles::TRolesPtr roles = std::make_shared<NRoles::TRoles>(
+ NRoles::TRoles::TMeta{},
+ NRoles::TRoles::TTvmConsumers{
+ {123, std::make_shared<NRoles::TConsumerRoles>(
+ THashMap<TString, NRoles::TEntitiesPtr>())},
+ },
+ NRoles::TRoles::TUserConsumers{},
+ std::make_shared<TString>());
+ TTvmClient f(new TMockedUpdater(TMockedUpdater::TSettings{
+ .SelfTvmId = OK_CLIENT,
+ .Roles = roles,
+ }));
+
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::Ok,
+ f.CheckServiceTicket(SRV_TICKET_123).GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::NoRoles,
+ f.CheckServiceTicket(SRV_TICKET_456).GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::Malformed,
+ f.CheckServiceTicket("asdfg").GetStatus());
+ }
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/files/ok.cache b/library/cpp/tvmauth/client/ut/files/ok.cache
new file mode 100644
index 0000000000..768d4953d1
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/files/ok.cache
Binary files differ
diff --git a/library/cpp/tvmauth/client/ut/files/public_keys b/library/cpp/tvmauth/client/ut/files/public_keys
new file mode 100644
index 0000000000..fa683d18f3
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/files/public_keys
Binary files differ
diff --git a/library/cpp/tvmauth/client/ut/files/roles b/library/cpp/tvmauth/client/ut/files/roles
new file mode 100644
index 0000000000..36864ae50a
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/files/roles
Binary files differ
diff --git a/library/cpp/tvmauth/client/ut/files/service_tickets b/library/cpp/tvmauth/client/ut/files/service_tickets
new file mode 100644
index 0000000000..7a6985a34d
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/files/service_tickets
Binary files differ
diff --git a/library/cpp/tvmauth/client/ut/last_error_ut.cpp b/library/cpp/tvmauth/client/ut/last_error_ut.cpp
new file mode 100644
index 0000000000..6751e78be7
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/last_error_ut.cpp
@@ -0,0 +1,56 @@
+#include <library/cpp/tvmauth/client/misc/last_error.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NTvmAuth;
+
+Y_UNIT_TEST_SUITE(LastError) {
+ Y_UNIT_TEST(common) {
+ TLastError le;
+
+ UNIT_ASSERT_VALUES_EQUAL("OK",
+ le.GetLastError(true));
+ UNIT_ASSERT_VALUES_EQUAL("Internal client error: failed to collect last useful error message, please report this message to tvm-dev@yandex-team.ru",
+ le.GetLastError(false));
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(le.ThrowLastError(),
+ TNonRetriableException,
+ "Internal client error: failed to collect last useful error message");
+
+ le.ProcessError(TLastError::EType::Retriable, TLastError::EScope::PublicKeys, "err_re#1");
+ UNIT_ASSERT_VALUES_EQUAL("PublicKeys: err_re#1",
+ le.GetLastError(false));
+ le.ProcessError(TLastError::EType::Retriable, TLastError::EScope::PublicKeys, "err_re#2");
+ UNIT_ASSERT_VALUES_EQUAL("PublicKeys: err_re#2",
+ le.GetLastError(false));
+ le.ProcessError(TLastError::EType::NonRetriable, TLastError::EScope::PublicKeys, "err_nonre#3");
+ UNIT_ASSERT_VALUES_EQUAL("PublicKeys: err_nonre#3",
+ le.GetLastError(false));
+ le.ProcessError(TLastError::EType::NonRetriable, TLastError::EScope::PublicKeys, "err_nonre#4");
+ UNIT_ASSERT_VALUES_EQUAL("PublicKeys: err_nonre#4",
+ le.GetLastError(false));
+ le.ProcessError(TLastError::EType::Retriable, TLastError::EScope::PublicKeys, "err_re#5");
+ UNIT_ASSERT_VALUES_EQUAL("PublicKeys: err_nonre#4",
+ le.GetLastError(false));
+ UNIT_ASSERT_EXCEPTION_CONTAINS(le.ThrowLastError(),
+ TNonRetriableException,
+ "Failed to start TvmClient. Do not retry: PublicKeys: err_nonre#4");
+
+ le.ProcessError(TLastError::EType::Retriable, TLastError::EScope::ServiceTickets, "err_re#6");
+ UNIT_ASSERT_VALUES_EQUAL("PublicKeys: err_nonre#4",
+ le.GetLastError(false));
+ le.ProcessError(TLastError::EType::Retriable, TLastError::EScope::ServiceTickets, "err_re#7");
+ UNIT_ASSERT_VALUES_EQUAL("PublicKeys: err_nonre#4",
+ le.GetLastError(false));
+ le.ProcessError(TLastError::EType::NonRetriable, TLastError::EScope::ServiceTickets, "err_nonre#8");
+ UNIT_ASSERT_VALUES_EQUAL("ServiceTickets: err_nonre#8",
+ le.GetLastError(false));
+
+ le.ClearError(TLastError::EScope::ServiceTickets);
+ UNIT_ASSERT_VALUES_EQUAL("PublicKeys: err_nonre#4",
+ le.GetLastError(false));
+ le.ClearError(TLastError::EScope::PublicKeys);
+ UNIT_ASSERT_VALUES_EQUAL("Internal client error: failed to collect last useful error message, please report this message to tvm-dev@yandex-team.ru",
+ le.GetLastError(false));
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/logger_ut.cpp b/library/cpp/tvmauth/client/ut/logger_ut.cpp
new file mode 100644
index 0000000000..76236e8913
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/logger_ut.cpp
@@ -0,0 +1,43 @@
+#include "common.h"
+
+#include <library/cpp/tvmauth/client/logger.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NTvmAuth;
+
+Y_UNIT_TEST_SUITE(ClientLogger) {
+ int i = 0;
+
+ Y_UNIT_TEST(Debug) {
+ TLogger l;
+ l.Debug("qwerty");
+ UNIT_ASSERT_VALUES_EQUAL("7: qwerty\n", l.Stream.Str());
+ }
+
+ Y_UNIT_TEST(Info) {
+ TLogger l;
+ l.Info("qwerty");
+ UNIT_ASSERT_VALUES_EQUAL("6: qwerty\n", l.Stream.Str());
+ }
+
+ Y_UNIT_TEST(Warning) {
+ TLogger l;
+ l.Warning("qwerty");
+ UNIT_ASSERT_VALUES_EQUAL("4: qwerty\n", l.Stream.Str());
+ }
+
+ Y_UNIT_TEST(Error) {
+ TLogger l;
+ l.Error("qwerty");
+ UNIT_ASSERT_VALUES_EQUAL("3: qwerty\n", l.Stream.Str());
+ }
+
+#ifdef _unix_
+ Y_UNIT_TEST(Cerr_) {
+ TCerrLogger l(5);
+ l.Error("hit");
+ l.Debug("miss");
+ }
+#endif
+}
diff --git a/library/cpp/tvmauth/client/ut/roles/decoder_ut.cpp b/library/cpp/tvmauth/client/ut/roles/decoder_ut.cpp
new file mode 100644
index 0000000000..0ee5fc7cb7
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/roles/decoder_ut.cpp
@@ -0,0 +1,163 @@
+#include <library/cpp/tvmauth/client/exception.h>
+#include <library/cpp/tvmauth/client/misc/roles/decoder.h>
+
+#include <library/cpp/tvmauth/unittest.h>
+#include <library/cpp/tvmauth/src/utils.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NTvmAuth;
+using namespace NTvmAuth::NRoles;
+
+Y_UNIT_TEST_SUITE(Decoder) {
+ const TString BROTLI = NUtils::Base64url2bin("GyMAAAR0Y6ku58ObclAQzDweUSUwbdqc5yOOKgI");
+ const TString GZIP = NUtils::Base64url2bin("H4sIAAAAAAAA_yrOz01VKEstqkTGCpm5BflFJYl5JQpJOflJgAAAAP__MbeeiSQAAAA");
+ const TString ZSTD = NUtils::Base64url2bin("KLUv_QBY9AAAwHNvbWUgdmVyeSBpbXBvcnRhbnQgYmxvYgEAc-4IAQAA");
+
+ Y_UNIT_TEST(Decode) {
+ // Errs
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TDecoder::Decode(
+ "1:brotli:10000:88839244E8C7C426B20729AF1A13AD792C5FA83C7F2FB6ADCFC60DA1B5EF9603",
+ TString(BROTLI)),
+ yexception,
+ "Decoded blob has bad size: expected 10000, actual 36");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TDecoder::Decode(
+ "1:brotli:36:88839244E8C7C426B20729AF1A13AD792C5FA83C7F2FB6ADCFC60DA1B5EF0000",
+ TString(BROTLI)),
+ yexception,
+ "Decoded blob has bad sha256");
+
+ // OK
+ TString decoded;
+ UNIT_ASSERT_NO_EXCEPTION(
+ decoded = TDecoder::Decode("", "some veryveryveryvery important blob"));
+ UNIT_ASSERT_VALUES_EQUAL(decoded, "some veryveryveryvery important blob");
+
+ UNIT_ASSERT_NO_EXCEPTION(
+ decoded = TDecoder::Decode(
+ "1:brotli:36:88839244E8C7C426B20729AF1A13AD792C5FA83C7F2FB6ADCFC60DA1B5EF9603",
+ TString(BROTLI)));
+ UNIT_ASSERT_VALUES_EQUAL(decoded, "some veryveryveryvery important blob");
+
+ UNIT_ASSERT_NO_EXCEPTION(
+ decoded = TDecoder::Decode(
+ "1:gzip:36:88839244E8C7C426B20729AF1A13AD792C5FA83C7F2FB6ADCFC60DA1B5EF9603",
+ TString(GZIP)));
+ UNIT_ASSERT_VALUES_EQUAL(decoded, "some veryveryveryvery important blob");
+
+ UNIT_ASSERT_NO_EXCEPTION(
+ decoded = TDecoder::Decode(
+ "1:zstd:36:88839244E8C7C426B20729AF1A13AD792C5FA83C7F2FB6ADCFC60DA1B5EF9603",
+ TString(ZSTD)));
+ UNIT_ASSERT_VALUES_EQUAL(decoded, "some veryveryveryvery important blob");
+ }
+
+ Y_UNIT_TEST(UnknownCodecs) {
+ for (const TStringBuf codec : {"lz", "lzma", "kek"}) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TDecoder::DecodeImpl(codec, ""),
+ yexception,
+ TStringBuilder() << "unknown codec: '" << codec << "'");
+ }
+ }
+
+ Y_UNIT_TEST(ParseCodec) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TDecoder::ParseCodec("2:kek"),
+ yexception,
+ "unknown codec format version; known: 1; got: 2");
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TDecoder::ParseCodec("1:::"),
+ yexception,
+ "codec type is empty");
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TDecoder::ParseCodec("1:some_codec:asd:"),
+ yexception,
+ "decoded blob size is not number");
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TDecoder::ParseCodec("1:some_codec:789:qwe"),
+ yexception,
+ "sha256 of decoded blob has invalid length: expected 64, got 3");
+
+ TDecoder::TCodecInfo info;
+ UNIT_ASSERT_NO_EXCEPTION(
+ info = TDecoder::ParseCodec("1:some_codec:789:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+
+ UNIT_ASSERT_VALUES_EQUAL("some_codec", info.Type);
+ UNIT_ASSERT_VALUES_EQUAL(789, info.Size);
+ UNIT_ASSERT_VALUES_EQUAL("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ info.Sha256);
+ }
+
+ Y_UNIT_TEST(DecodeBrolti) {
+ UNIT_ASSERT_EXCEPTION(
+ TDecoder::DecodeBrolti(""),
+ yexception);
+
+ TString blob;
+ UNIT_ASSERT_NO_EXCEPTION(
+ blob = TDecoder::DecodeBrolti(
+ TString(BROTLI)));
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ "some veryveryveryvery important blob",
+ blob);
+ }
+
+ Y_UNIT_TEST(DecodeGzip) {
+ TString blob;
+ UNIT_ASSERT_NO_EXCEPTION(blob = TDecoder::DecodeGzip(""));
+ UNIT_ASSERT_VALUES_EQUAL("", blob);
+
+ UNIT_ASSERT_NO_EXCEPTION(
+ blob = TDecoder::DecodeGzip(
+ TString(GZIP)));
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ "some veryveryveryvery important blob",
+ blob);
+ }
+
+ Y_UNIT_TEST(DecodeZstd) {
+ TString blob;
+ UNIT_ASSERT_NO_EXCEPTION(blob = TDecoder::DecodeZstd(""));
+ UNIT_ASSERT_VALUES_EQUAL("", blob);
+
+ UNIT_ASSERT_NO_EXCEPTION(
+ blob = TDecoder::DecodeZstd(
+ TString(ZSTD)));
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ "some veryveryveryvery important blob",
+ blob);
+ }
+
+ Y_UNIT_TEST(VerifySize) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TDecoder::VerifySize("qwerty", 100),
+ yexception,
+ TStringBuilder() << "Decoded blob has bad size: expected 100, actual 6");
+
+ UNIT_ASSERT_NO_EXCEPTION(TDecoder::VerifySize("qwert", 5));
+ }
+
+ Y_UNIT_TEST(VerifyChecksum) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TDecoder::VerifyChecksum("qwerty", "zzzz"),
+ yexception,
+ "Decoded blob has bad sha256: expected=zzzz,"
+ " actual=65E84BE33532FB784C48129675F9EFF3A682B27168C0EA744B2CF58EE02337C5");
+
+ UNIT_ASSERT_NO_EXCEPTION(
+ TDecoder::VerifyChecksum("qwerty",
+ "65E84BE33532FB784C48129675F9EFF3A682B27168C0EA744B2CF58EE02337C5"));
+ UNIT_ASSERT_NO_EXCEPTION(
+ TDecoder::VerifyChecksum("qwerty",
+ "65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5"));
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/roles/entities_index_ut.cpp b/library/cpp/tvmauth/client/ut/roles/entities_index_ut.cpp
new file mode 100644
index 0000000000..7e62a87b64
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/roles/entities_index_ut.cpp
@@ -0,0 +1,358 @@
+#include <library/cpp/tvmauth/client/ut/common.h>
+
+#include <library/cpp/tvmauth/client/misc/roles/entities_index.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <array>
+
+using namespace NTvmAuth::NRoles;
+
+Y_UNIT_TEST_SUITE(RolesEntitiesIndex) {
+ Y_UNIT_TEST(Stage) {
+ TEntitiesIndex::TStage stage({
+ "key#1",
+ "key#2",
+ "key#3",
+ "key#4",
+ });
+
+ const std::vector<std::vector<TString>> results = {
+ {"key#1"},
+ {"key#2"},
+ {"key#1", "key#2"},
+ {"key#3"},
+ {"key#1", "key#3"},
+ {"key#2", "key#3"},
+ {"key#1", "key#2", "key#3"},
+ {"key#4"},
+ {"key#1", "key#4"},
+ {"key#2", "key#4"},
+ {"key#1", "key#2", "key#4"},
+ {"key#3", "key#4"},
+ {"key#1", "key#3", "key#4"},
+ {"key#2", "key#3", "key#4"},
+ {"key#1", "key#2", "key#3", "key#4"},
+ };
+
+ std::vector<TString> keys;
+ for (const std::vector<TString>& res : results) {
+ UNIT_ASSERT(stage.GetNextKeySet(keys));
+ UNIT_ASSERT_VALUES_EQUAL(keys, res);
+ }
+
+ UNIT_ASSERT_C(!stage.GetNextKeySet(keys), keys);
+ }
+
+ Y_UNIT_TEST(GetUniqueSortedKeys) {
+ std::vector<TEntityPtr> entities;
+
+ UNIT_ASSERT_VALUES_EQUAL(std::set<TString>(),
+ TEntitiesIndex::GetUniqueSortedKeys(entities));
+
+ entities = {
+ std::make_shared<TEntity>(),
+ };
+ UNIT_ASSERT_VALUES_EQUAL(std::set<TString>(),
+ TEntitiesIndex::GetUniqueSortedKeys(entities));
+
+ entities = {
+ std::make_shared<TEntity>(TEntity{
+ {"key#1", "value#1"},
+ }),
+ };
+ UNIT_ASSERT_VALUES_EQUAL(std::set<TString>({
+ "key#1",
+ }),
+ TEntitiesIndex::GetUniqueSortedKeys(entities));
+
+ entities = {
+ std::make_shared<TEntity>(TEntity{
+ {"key#1", "value#1"},
+ }),
+ std::make_shared<TEntity>(TEntity{
+ {"key#1", "value#11"},
+ {"key#2", "value#22"},
+ }),
+ };
+ UNIT_ASSERT_VALUES_EQUAL(std::set<TString>({
+ "key#1",
+ "key#2",
+ }),
+ TEntitiesIndex::GetUniqueSortedKeys(entities));
+ }
+
+ Y_UNIT_TEST(MakeUnique) {
+ const TEntityPtr entityA = std::make_shared<TEntity>(TEntity{{"key#1", "aaaa"}});
+ const TEntityPtr entityA2 = std::make_shared<TEntity>(TEntity{{"key#1", "aaaa"}});
+ const TEntityPtr entityB = std::make_shared<TEntity>(TEntity{{"key#1", "bbbb"}});
+
+ TEntitiesIndex::TSubTree idx = {
+ std::vector<TEntityPtr>{
+ entityA,
+ entityA,
+ },
+ TEntitiesIndex::TIdxByAttrs{
+ {
+ TKeyValue{"key#1", "value#11"},
+ TEntitiesIndex::TSubTree{
+ std::vector<TEntityPtr>{
+ entityA,
+ entityB,
+ entityA,
+ },
+ TEntitiesIndex::TIdxByAttrs{
+ {
+ TKeyValue{"key#2", "value#21"},
+ TEntitiesIndex::TSubTree{
+ std::vector<TEntityPtr>{
+ entityA,
+ entityB,
+ entityA,
+ },
+ TEntitiesIndex::TIdxByAttrs{},
+ },
+ },
+ },
+ },
+ },
+ {
+ TKeyValue{"key#1", "value#12"},
+ TEntitiesIndex::TSubTree{
+ std::vector<TEntityPtr>{
+ entityA,
+ entityB,
+ entityA2,
+ },
+ TEntitiesIndex::TIdxByAttrs{},
+ },
+ },
+ },
+ };
+
+ TEntitiesIndex::MakeUnique(idx);
+
+ UNIT_ASSERT_VALUES_EQUAL(idx.Entities.size(), 1);
+
+ auto it = idx.SubTree.find(TKeyValue{"key#1", "value#12"});
+ UNIT_ASSERT(it != idx.SubTree.end());
+ UNIT_ASSERT_VALUES_EQUAL(it->second.Entities.size(), 2);
+
+ it = idx.SubTree.find(TKeyValue{"key#1", "value#11"});
+ UNIT_ASSERT(it != idx.SubTree.end());
+ UNIT_ASSERT_VALUES_EQUAL(it->second.Entities.size(), 2);
+
+ it = it->second.SubTree.find(TKeyValue{"key#2", "value#21"});
+ UNIT_ASSERT(it != it->second.SubTree.end());
+ UNIT_ASSERT_VALUES_EQUAL(it->second.Entities.size(), 2);
+ }
+
+ Y_UNIT_TEST(GetByAttrs) {
+ const TEntitiesIndex index = CreateEntitiesIndex();
+
+ UNIT_ASSERT_STRINGS_EQUAL(
+ index.PrintDebugString(),
+ R"(
+"key#1/value#11"
+ "key#2/value#22"
+ "key#3/value#33"
+ "key#2/value#23"
+ "key#3/value#33"
+ "key#3/value#33"
+"key#1/value#13"
+ "key#3/value#33"
+"key#2/value#22"
+ "key#3/value#33"
+"key#2/value#23"
+ "key#3/value#33"
+"key#3/value#33"
+)");
+
+ struct TCase {
+ TEntity AttrsToFind;
+ std::vector<TEntity> Result;
+ };
+
+ std::vector<TCase> cases = {
+ {
+ TEntity{},
+ std::vector<TEntity>{
+ TEntity{
+ {"key#1", "value#11"},
+ },
+ TEntity{
+ {"key#1", "value#11"},
+ {"key#2", "value#22"},
+ {"key#3", "value#33"},
+ },
+ TEntity{
+ {"key#1", "value#11"},
+ {"key#2", "value#23"},
+ {"key#3", "value#33"},
+ },
+ TEntity{
+ {"key#1", "value#13"},
+ {"key#3", "value#33"},
+ },
+ },
+ },
+ {
+ TEntity{
+ {"key#1", "value#11"},
+ },
+ std::vector<TEntity>{
+ TEntity{
+ {"key#1", "value#11"},
+ },
+ TEntity{
+ {"key#1", "value#11"},
+ {"key#2", "value#22"},
+ {"key#3", "value#33"},
+ },
+ TEntity{
+ {"key#1", "value#11"},
+ {"key#2", "value#23"},
+ {"key#3", "value#33"},
+ },
+ },
+ },
+ {
+ TEntity{
+ {"key#1", "value#13"},
+ },
+ std::vector<TEntity>{
+ TEntity{
+ {"key#1", "value#13"},
+ {"key#3", "value#33"},
+ },
+ },
+ },
+ {
+ TEntity{
+ {"key#1", "value#14"},
+ },
+ std::vector<TEntity>{},
+ },
+ {
+ TEntity{
+ {"key#2", "value#22"},
+ },
+ std::vector<TEntity>{
+ TEntity{
+ {"key#1", "value#11"},
+ {"key#2", "value#22"},
+ {"key#3", "value#33"},
+ },
+ },
+ },
+ {
+ TEntity{
+ {"key#3", "value#33"},
+ },
+ std::vector<TEntity>{
+ TEntity{
+ {"key#1", "value#11"},
+ {"key#2", "value#22"},
+ {"key#3", "value#33"},
+ },
+ TEntity{
+ {"key#1", "value#11"},
+ {"key#2", "value#23"},
+ {"key#3", "value#33"},
+ },
+ TEntity{
+ {"key#1", "value#13"},
+ {"key#3", "value#33"},
+ },
+ },
+ },
+ };
+
+ for (const TCase& c : cases) {
+ std::vector<TEntityPtr> expected;
+ for (const TEntity& e : c.Result) {
+ expected.push_back(std::make_shared<TEntity>(e));
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL_C(
+ index.GetEntitiesWithAttrs(c.AttrsToFind.begin(), c.AttrsToFind.end()),
+ expected,
+ "'" << c.AttrsToFind << "'");
+ }
+ }
+
+ Y_UNIT_TEST(Contains) {
+ const TEntitiesIndex index = CreateEntitiesIndex();
+
+ struct TCase {
+ TEntity Exact;
+ bool Result = false;
+ };
+
+ std::vector<TCase> cases = {
+ {
+ TEntity{},
+ false,
+ },
+ {
+ TEntity{
+ {"key#1", "value#11"},
+ },
+ true,
+ },
+ {
+ TEntity{
+ {"key#1", "value#13"},
+ },
+ false,
+ },
+ {
+ TEntity{
+ {"key#1", "value#13"},
+ {"key#3", "value#33"},
+ },
+ true,
+ },
+ };
+
+ for (const TCase& c : cases) {
+ UNIT_ASSERT_VALUES_EQUAL_C(
+ index.ContainsExactEntity(c.Exact.begin(), c.Exact.end()),
+ c.Result,
+ "'" << c.Exact << "'");
+ }
+ }
+}
+
+template <>
+void Out<std::vector<TString>>(IOutputStream& o, const std::vector<TString>& s) {
+ for (const auto& key : s) {
+ o << key << ",";
+ }
+}
+
+template <>
+void Out<std::set<TString>>(IOutputStream& o, const std::set<TString>& s) {
+ for (const auto& key : s) {
+ o << key << ",";
+ }
+}
+
+template <>
+void Out<std::vector<TEntityPtr>>(IOutputStream& o, const std::vector<TEntityPtr>& v) {
+ for (const TEntityPtr& p : v) {
+ o << *p << Endl;
+ }
+}
+
+template <>
+void Out<TEntityPtr>(IOutputStream& o, const TEntityPtr& v) {
+ o << *v;
+}
+
+template <>
+void Out<TEntity>(IOutputStream& o, const TEntity& v) {
+ for (const auto& [key, value] : v) {
+ o << key << "->" << value << Endl;
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/roles/parser_ut.cpp b/library/cpp/tvmauth/client/ut/roles/parser_ut.cpp
new file mode 100644
index 0000000000..87f8ade267
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/roles/parser_ut.cpp
@@ -0,0 +1,160 @@
+#include <library/cpp/tvmauth/client/misc/roles/parser.h>
+
+#include <library/cpp/tvmauth/unittest.h>
+
+#include <library/cpp/json/json_reader.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NTvmAuth;
+using namespace NTvmAuth::NRoles;
+
+Y_UNIT_TEST_SUITE(Parser) {
+ static NJson::TJsonValue ToJsonValue(TStringBuf body) {
+ NJson::TJsonValue doc;
+ UNIT_ASSERT(NJson::ReadJsonTree(body, &doc));
+ return doc;
+ }
+
+ Y_UNIT_TEST(GetEntity) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TParser::GetEntity(ToJsonValue(R"({"scope": false})"),
+ "cons",
+ "read"),
+ yexception,
+ "entity is map (str->str), got value Boolean. consumer 'cons' with role 'read'");
+
+ TEntityPtr en;
+ UNIT_ASSERT_NO_EXCEPTION(
+ en = TParser::GetEntity(ToJsonValue(R"({})"),
+ "cons",
+ "read"));
+ UNIT_ASSERT_VALUES_EQUAL(en->size(), 0);
+
+ UNIT_ASSERT_NO_EXCEPTION(
+ en = TParser::GetEntity(ToJsonValue(R"({"key1": "val1", "key2": "val2"})"),
+ "cons",
+ "read"));
+ UNIT_ASSERT_VALUES_EQUAL(en->size(), 2);
+ }
+
+ Y_UNIT_TEST(GetEntities) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TParser::GetEntities(ToJsonValue(R"([{},[]])"),
+ "cons",
+ "read"),
+ yexception,
+ "role entity for role must be map: consumer 'cons' with role 'read' has Array");
+
+ TEntitiesPtr en;
+ UNIT_ASSERT_NO_EXCEPTION(
+ en = TParser::GetEntities(ToJsonValue(R"([])"),
+ "cons",
+ "read"));
+ UNIT_ASSERT(!en->Contains({}));
+
+ UNIT_ASSERT_NO_EXCEPTION(
+ en = TParser::GetEntities(ToJsonValue(R"([{}])"),
+ "cons",
+ "read"));
+ UNIT_ASSERT(en->Contains({}));
+ }
+
+ Y_UNIT_TEST(GetConsumer) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TParser::GetConsumer(ToJsonValue(R"({"role1": [],"role2": {}})"),
+ "cons"),
+ yexception,
+ "entities for roles must be array: 'role2' is Map");
+
+ TConsumerRolesPtr c;
+ UNIT_ASSERT_NO_EXCEPTION(
+ c = TParser::GetConsumer(ToJsonValue(R"({"role1": [],"role2": []})"),
+ "cons"));
+ UNIT_ASSERT(c->HasRole("role1"));
+ UNIT_ASSERT(c->HasRole("role2"));
+ UNIT_ASSERT(!c->HasRole("role3"));
+ }
+
+ Y_UNIT_TEST(GetConsumers) {
+ TRoles::TTvmConsumers cons;
+ UNIT_ASSERT_NO_EXCEPTION(
+ cons = TParser::GetConsumers<TTvmId>(ToJsonValue(R"({})"),
+ "tvm"));
+ UNIT_ASSERT_VALUES_EQUAL(0, cons.size());
+
+ UNIT_ASSERT_NO_EXCEPTION(
+ cons = TParser::GetConsumers<TTvmId>(ToJsonValue(R"({"tvm": {}})"),
+ "tvm"));
+ UNIT_ASSERT_VALUES_EQUAL(0, cons.size());
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TParser::GetConsumers<TTvmId>(ToJsonValue(R"({"tvm": []})"),
+ "tvm"),
+ yexception,
+ "'tvm' must be object");
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TParser::GetConsumers<TTvmId>(ToJsonValue(R"({"tvm": {"asd": []}})"),
+ "tvm"),
+ yexception,
+ "roles for consumer must be map: 'asd' is Array");
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TParser::GetConsumers<TTvmId>(ToJsonValue(R"({"tvm": {"asd": {}}})"),
+ "tvm"),
+ yexception,
+ "id must be valid positive number of proper size for tvm. got 'asd'");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TParser::GetConsumers<TTvmId>(ToJsonValue(R"({"tvm": {"1120000000001062": {}}})"),
+ "tvm"),
+ yexception,
+ "id must be valid positive number of proper size for tvm. got '1120000000001062'");
+ UNIT_ASSERT_NO_EXCEPTION(
+ TParser::GetConsumers<TUid>(ToJsonValue(R"({"user": {"1120000000001062": {}}})"),
+ "user"));
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TParser::GetConsumers<TTvmId>(ToJsonValue(R"({"tvm": {"42": {}, "042": {}}})"),
+ "tvm"),
+ yexception,
+ "consumer duplicate detected: '42' for tvm");
+
+ UNIT_ASSERT_NO_EXCEPTION(
+ cons = TParser::GetConsumers<TTvmId>(ToJsonValue(R"({"tvm": {"42": {}}})"),
+ "tvm"));
+ UNIT_ASSERT_VALUES_EQUAL(1, cons.size());
+ }
+
+ Y_UNIT_TEST(GetMeta) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TParser::GetMeta(ToJsonValue(R"({})")),
+ yexception,
+ "Missing 'revision'");
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TParser::GetMeta(ToJsonValue(R"({"revision": null})")),
+ yexception,
+ "'revision' has unexpected type: Null");
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TParser::GetMeta(ToJsonValue(R"({"revision": 100500})")),
+ yexception,
+ "Missing 'born_date'");
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TParser::GetMeta(ToJsonValue(R"({"revision": 100500, "born_date": false})")),
+ yexception,
+ "key 'born_date' must be uint");
+
+ TRoles::TMeta meta;
+ UNIT_ASSERT_NO_EXCEPTION(
+ meta = TParser::GetMeta(ToJsonValue(R"({"revision": 100500, "born_date": 42})")));
+ UNIT_ASSERT_VALUES_EQUAL("100500", meta.Revision);
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(42), meta.BornTime);
+
+ UNIT_ASSERT_NO_EXCEPTION(
+ meta = TParser::GetMeta(ToJsonValue(R"({"revision": "100501", "born_date": 42})")));
+ UNIT_ASSERT_VALUES_EQUAL("100501", meta.Revision);
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(42), meta.BornTime);
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/roles/roles_ut.cpp b/library/cpp/tvmauth/client/ut/roles/roles_ut.cpp
new file mode 100644
index 0000000000..5ba28d5435
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/roles/roles_ut.cpp
@@ -0,0 +1,415 @@
+#include <library/cpp/tvmauth/client/ut/common.h>
+
+#include <library/cpp/tvmauth/client/exception.h>
+#include <library/cpp/tvmauth/client/misc/roles/roles.h>
+
+#include <library/cpp/tvmauth/unittest.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <array>
+
+using namespace NTvmAuth;
+using namespace NTvmAuth::NRoles;
+
+Y_UNIT_TEST_SUITE(Roles) {
+ Y_UNIT_TEST(EntContains) {
+ TEntities ent(CreateEntitiesIndex());
+
+ UNIT_ASSERT(ent.Contains({{"key#1", "value#11"}}));
+ UNIT_ASSERT(ent.Contains({
+ {"key#1", "value#13"},
+ {"key#3", "value#33"},
+ }));
+ UNIT_ASSERT(!ent.Contains({{"key#111", "value#11"}}));
+ UNIT_ASSERT(!ent.Contains({
+ {"key#111", "value#13"},
+ {"key#3", "value#33"},
+ }));
+
+ // valid calls
+ {
+ std::array<const std::pair<TStringBuf, TString>, 1> arr = {{{"key#1", "value#11"}}};
+ UNIT_ASSERT(ent.ContainsSortedUnique<TStringBuf>({arr.begin(), arr.end()}));
+ }
+ {
+ std::array<const std::pair<TString, TStringBuf>, 2> arr = {{
+ {"key#1", "value#13"},
+ {"key#3", "value#33"},
+ }};
+ bool res = ent.ContainsSortedUnique<TString, TStringBuf>({arr.begin(), arr.end()});
+ UNIT_ASSERT(res);
+ }
+ {
+ std::array<const std::pair<TStringBuf, TStringBuf>, 1> arr = {{{"key#111", "value#11"}}};
+ bool res = ent.ContainsSortedUnique<TStringBuf, TStringBuf>({arr.begin(), arr.end()});
+ UNIT_ASSERT(!res);
+ }
+ {
+ std::array<const std::pair<TString, TString>, 2> arr = {{
+ {"key#111", "value#13"},
+ {"key#3", "value#33"},
+ }};
+ UNIT_ASSERT(!ent.ContainsSortedUnique({arr.begin(), arr.end()}));
+ }
+
+ // invalid calls
+ {
+ std::array<const std::pair<TString, TString>, 2> arr = {{
+ {"key#3", "value#33"},
+ {"key#1", "value#13"},
+ }};
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ ent.ContainsSortedUnique({arr.begin(), arr.end()}),
+ TIllegalUsage,
+ "attrs are not sorted: 'key#3' before 'key#1'");
+ }
+ {
+ std::array<const std::pair<TString, TString>, 2> arr = {{
+ {"key#1", "value#13"},
+ {"key#1", "value#13"},
+ }};
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ ent.ContainsSortedUnique({arr.begin(), arr.end()}),
+ TIllegalUsage,
+ "attrs are not unique: 'key#1'");
+ }
+ }
+
+ Y_UNIT_TEST(EntWithAttrs) {
+ TEntities ent(CreateEntitiesIndex());
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ ent.GetEntitiesWithAttrs({{"key#1", "value#11"}}),
+ std::vector<TEntityPtr>({
+ std::make_shared<TEntity>(TEntity{
+ {"key#1", "value#11"},
+ }),
+ std::make_shared<TEntity>(TEntity{
+ {"key#1", "value#11"},
+ {"key#2", "value#22"},
+ {"key#3", "value#33"},
+ }),
+ std::make_shared<TEntity>(TEntity{
+ {"key#1", "value#11"},
+ {"key#2", "value#23"},
+ {"key#3", "value#33"},
+ }),
+ }));
+ UNIT_ASSERT_VALUES_EQUAL(
+ ent.GetEntitiesWithAttrs({{"key#111", "value#11"}}),
+ std::vector<TEntityPtr>());
+
+ // valid calls
+ {
+ std::array<const std::pair<TStringBuf, TString>, 2> arr = {{
+ {"key#1", "value#11"},
+ {"key#3", "value#33"},
+ }};
+ auto vec = ent.GetEntitiesWithSortedUniqueAttrs<TStringBuf>({arr.begin(), arr.end()});
+ UNIT_ASSERT_VALUES_EQUAL(
+ vec,
+ std::vector<TEntityPtr>({
+ std::make_shared<TEntity>(TEntity{
+ {"key#1", "value#11"},
+ {"key#2", "value#22"},
+ {"key#3", "value#33"},
+ }),
+ std::make_shared<TEntity>(TEntity{
+ {"key#1", "value#11"},
+ {"key#2", "value#23"},
+ {"key#3", "value#33"},
+ }),
+ }));
+ }
+ {
+ std::array<const std::pair<TString, TString>, 2> arr = {{
+ {"key#111", "value#13"},
+ {"key#3", "value#33"},
+ }};
+ UNIT_ASSERT_VALUES_EQUAL(
+ ent.GetEntitiesWithSortedUniqueAttrs({arr.begin(), arr.end()}),
+ std::vector<TEntityPtr>());
+ }
+
+ // invalid calls
+ {
+ std::array<const std::pair<TString, TString>, 2> arr = {{
+ {"key#3", "value#33"},
+ {"key#1", "value#13"},
+ }};
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ ent.GetEntitiesWithSortedUniqueAttrs({arr.begin(), arr.end()}),
+ TIllegalUsage,
+ "attrs are not sorted: 'key#3' before 'key#1'");
+ }
+ {
+ std::array<const std::pair<TString, TString>, 2> arr = {{
+ {"key#1", "value#13"},
+ {"key#1", "value#13"},
+ }};
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ ent.GetEntitiesWithSortedUniqueAttrs({arr.begin(), arr.end()}),
+ TIllegalUsage,
+ "attrs are not unique: 'key#1'");
+ }
+ }
+
+ Y_UNIT_TEST(Consumer) {
+ TConsumerRoles c({
+ {"read", std::make_shared<TEntities>(CreateEntitiesIndex())},
+ {"write", std::make_shared<TEntities>(CreateEntitiesIndex())},
+ });
+
+ UNIT_ASSERT(c.HasRole("read"));
+ UNIT_ASSERT(c.HasRole("write"));
+ UNIT_ASSERT(!c.HasRole("access"));
+
+ UNIT_ASSERT_EQUAL(nullptr, c.GetEntitiesForRole("access"));
+
+ TEntitiesPtr ent = c.GetEntitiesForRole("read");
+ UNIT_ASSERT_UNEQUAL(nullptr, ent);
+ UNIT_ASSERT(ent->Contains({{"key#1", "value#11"}}));
+ UNIT_ASSERT(!ent->Contains({{"key#111", "value#11"}}));
+
+ UNIT_ASSERT(c.CheckRoleForExactEntity("read", {{"key#1", "value#11"}}));
+ UNIT_ASSERT(!c.CheckRoleForExactEntity("acess", {{"key#1", "value#11"}}));
+ UNIT_ASSERT(!c.CheckRoleForExactEntity("read", {{"key#111", "value#11"}}));
+ UNIT_ASSERT(!c.CheckRoleForExactEntity("read", {}));
+ }
+
+ Y_UNIT_TEST(RolesService) {
+ TRoles r(
+ {},
+ {
+ {100500, std::make_shared<TConsumerRoles>(THashMap<TString, TEntitiesPtr>{
+ {"write", std::make_shared<TEntities>(CreateEntitiesIndex())},
+ })},
+ },
+ {},
+ std::make_shared<TString>());
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ r.GetRolesForService(NUnittest::CreateServiceTicket(
+ ETicketStatus::InvalidDst,
+ 100500)),
+ TIllegalUsage,
+ "Service ticket must be valid, got: InvalidDst");
+
+ TConsumerRolesPtr cons;
+ UNIT_ASSERT_NO_EXCEPTION(
+ cons = r.GetRolesForService(NUnittest::CreateServiceTicket(
+ ETicketStatus::Ok,
+ 100501)));
+ UNIT_ASSERT_EQUAL(nullptr, cons);
+
+ cons = r.GetRolesForService(NUnittest::CreateServiceTicket(
+ ETicketStatus::Ok,
+ 100500));
+ UNIT_ASSERT_UNEQUAL(nullptr, cons);
+ UNIT_ASSERT(!cons->HasRole("read"));
+ UNIT_ASSERT(cons->HasRole("write"));
+
+ ////shortcuts
+ // no tvmid
+ UNIT_ASSERT(!r.CheckServiceRole(
+ NUnittest::CreateServiceTicket(
+ ETicketStatus::Ok,
+ 100501),
+ "write"));
+
+ // no role
+ UNIT_ASSERT(!r.CheckServiceRole(
+ NUnittest::CreateServiceTicket(
+ ETicketStatus::Ok,
+ 100500),
+ "read"));
+
+ // success
+ UNIT_ASSERT(r.CheckServiceRole(
+ NUnittest::CreateServiceTicket(
+ ETicketStatus::Ok,
+ 100500),
+ "write"));
+
+ // no tvmid
+ UNIT_ASSERT(!r.CheckServiceRoleForExactEntity(
+ NUnittest::CreateServiceTicket(
+ ETicketStatus::Ok,
+ 100501),
+ "write",
+ {{"key#1", "value#11"}}));
+
+ // no role
+ UNIT_ASSERT(!r.CheckServiceRoleForExactEntity(
+ NUnittest::CreateServiceTicket(
+ ETicketStatus::Ok,
+ 100500),
+ "read",
+ {{"key#1", "value#11"}}));
+
+ // no entity
+ UNIT_ASSERT(!r.CheckServiceRoleForExactEntity(
+ NUnittest::CreateServiceTicket(
+ ETicketStatus::Ok,
+ 100500),
+ "write",
+ {{"key#111", "value#11"}}));
+
+ // success
+ UNIT_ASSERT(r.CheckServiceRoleForExactEntity(
+ NUnittest::CreateServiceTicket(
+ ETicketStatus::Ok,
+ 100500),
+ "write",
+ {{"key#1", "value#11"}}));
+ }
+
+ Y_UNIT_TEST(RolesUser) {
+ TRoles r(
+ {},
+ {},
+ {
+ {789654, std::make_shared<TConsumerRoles>(THashMap<TString, TEntitiesPtr>{
+ {"read", std::make_shared<TEntities>(CreateEntitiesIndex())},
+ })},
+ },
+ std::make_shared<TString>("some roles"));
+
+ UNIT_ASSERT_VALUES_EQUAL("some roles", r.GetRaw());
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ r.GetRolesForUser(NUnittest::CreateUserTicket(
+ ETicketStatus::Malformed,
+ 789654,
+ {})),
+ TIllegalUsage,
+ "User ticket must be valid, got: Malformed");
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ r.GetRolesForUser(NUnittest::CreateUserTicket(
+ ETicketStatus::Ok,
+ 789654,
+ {}),
+ 789123),
+ TIllegalUsage,
+ "User ticket must be from ProdYateam, got from Test");
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ r.GetRolesForUser(NUnittest::CreateUserTicket(
+ ETicketStatus::Ok,
+ 789654,
+ {},
+ {},
+ EBlackboxEnv::ProdYateam),
+ 789123),
+ TIllegalUsage,
+ "selectedUid must be in user ticket but it's not: 789123");
+
+ TConsumerRolesPtr cons;
+ UNIT_ASSERT_NO_EXCEPTION(
+ cons = r.GetRolesForUser(NUnittest::CreateUserTicket(
+ ETicketStatus::Ok,
+ 789123,
+ {},
+ {},
+ EBlackboxEnv::ProdYateam)));
+ UNIT_ASSERT_EQUAL(nullptr, cons);
+
+ cons = r.GetRolesForUser(NUnittest::CreateUserTicket(
+ ETicketStatus::Ok,
+ 789654,
+ {},
+ {},
+ EBlackboxEnv::ProdYateam));
+ UNIT_ASSERT_UNEQUAL(nullptr, cons);
+ UNIT_ASSERT(cons->HasRole("read"));
+ UNIT_ASSERT(!cons->HasRole("write"));
+
+ cons = r.GetRolesForUser(NUnittest::CreateUserTicket(
+ ETicketStatus::Ok,
+ 789123,
+ {},
+ {789654, 789741},
+ EBlackboxEnv::ProdYateam),
+ 789654);
+ UNIT_ASSERT_UNEQUAL(nullptr, cons);
+ UNIT_ASSERT(cons->HasRole("read"));
+ UNIT_ASSERT(!cons->HasRole("write"));
+
+ ////shortcuts
+ // no uid
+ UNIT_ASSERT(!r.CheckUserRole(
+ NUnittest::CreateUserTicket(
+ ETicketStatus::Ok,
+ 789123,
+ {},
+ {},
+ EBlackboxEnv::ProdYateam),
+ "read"));
+
+ // no role
+ UNIT_ASSERT(!r.CheckUserRole(
+ NUnittest::CreateUserTicket(
+ ETicketStatus::Ok,
+ 789654,
+ {},
+ {},
+ EBlackboxEnv::ProdYateam),
+ "wrire"));
+
+ // success
+ UNIT_ASSERT(r.CheckUserRole(
+ NUnittest::CreateUserTicket(
+ ETicketStatus::Ok,
+ 789654,
+ {},
+ {},
+ EBlackboxEnv::ProdYateam),
+ "read"));
+
+ // no uid
+ UNIT_ASSERT(!r.CheckUserRoleForExactEntity(
+ NUnittest::CreateUserTicket(
+ ETicketStatus::Ok,
+ 789123,
+ {},
+ {},
+ EBlackboxEnv::ProdYateam),
+ "read",
+ {{"key#1", "value#11"}}));
+
+ // no role
+ UNIT_ASSERT(!r.CheckUserRoleForExactEntity(
+ NUnittest::CreateUserTicket(
+ ETicketStatus::Ok,
+ 789654,
+ {},
+ {},
+ EBlackboxEnv::ProdYateam),
+ "wrire",
+ {{"key#1", "value#11"}}));
+
+ // no entity
+ UNIT_ASSERT(!r.CheckUserRoleForExactEntity(
+ NUnittest::CreateUserTicket(
+ ETicketStatus::Ok,
+ 789654,
+ {},
+ {},
+ EBlackboxEnv::ProdYateam),
+ "read",
+ {{"key#111", "value#11"}}));
+
+ // success
+ UNIT_ASSERT(r.CheckUserRoleForExactEntity(
+ NUnittest::CreateUserTicket(
+ ETicketStatus::Ok,
+ 789654,
+ {},
+ {},
+ EBlackboxEnv::ProdYateam),
+ "read",
+ {{"key#1", "value#11"}}));
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/roles/tvmapi_roles_fetcher_ut.cpp b/library/cpp/tvmauth/client/ut/roles/tvmapi_roles_fetcher_ut.cpp
new file mode 100644
index 0000000000..7eaf611e82
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/roles/tvmapi_roles_fetcher_ut.cpp
@@ -0,0 +1,197 @@
+#include <library/cpp/tvmauth/client/ut/common.h>
+
+#include <library/cpp/tvmauth/client/misc/disk_cache.h>
+#include <library/cpp/tvmauth/client/misc/api/roles_fetcher.h>
+
+#include <library/cpp/tvmauth/unittest.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/stream/file.h>
+#include <util/system/fs.h>
+
+using namespace NTvmAuth;
+using namespace NTvmAuth::NTvmApi;
+
+Y_UNIT_TEST_SUITE(TvmApiRolesFetcher) {
+ static const TString ROLES = R"({"revision": "100501", "born_date": 42})";
+
+ static const TString CACHE_DIR = "./tmp/";
+
+ static void CleanCache() {
+ NFs::RemoveRecursive(CACHE_DIR);
+ NFs::MakeDirectoryRecursive(CACHE_DIR);
+ }
+
+ Y_UNIT_TEST(ReadFromDisk) {
+ CleanCache();
+ auto logger = MakeIntrusive<TLogger>();
+
+ TRolesFetcherSettings s;
+ s.CacheDir = CACHE_DIR;
+ s.SelfTvmId = 111111;
+ s.IdmSystemSlug = "fem\tida";
+ TRolesFetcher fetcher(s, logger);
+
+ UNIT_ASSERT(!fetcher.AreRolesOk());
+
+ UNIT_ASSERT_VALUES_EQUAL(TInstant(), fetcher.ReadFromDisk());
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "7: File './tmp/roles' does not exist\n",
+ logger->Stream.Str());
+ logger->Stream.clear();
+
+ const TInstant now = TInstant::Seconds(TInstant::Now().Seconds());
+
+ TDiskWriter wr(CACHE_DIR + "roles");
+ UNIT_ASSERT(wr.Write("kek", now));
+ UNIT_ASSERT_NO_EXCEPTION(fetcher.ReadFromDisk());
+ UNIT_ASSERT(!fetcher.AreRolesOk());
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/roles' was successfully read\n"
+ << "4: Roles in disk cache are for another slug (kek). Self=fem\tida\n",
+ logger->Stream.Str());
+ logger->Stream.clear();
+
+ UNIT_ASSERT(wr.Write(TRolesFetcher::PrepareDiskFormat(ROLES, "femida_test"), now));
+ UNIT_ASSERT_VALUES_EQUAL(TInstant(), fetcher.ReadFromDisk());
+ UNIT_ASSERT(!fetcher.AreRolesOk());
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/roles' was successfully read\n"
+ "4: Roles in disk cache are for another slug (femida_test). Self=fem\tida\n",
+ logger->Stream.Str());
+ logger->Stream.clear();
+
+ UNIT_ASSERT(wr.Write(TRolesFetcher::PrepareDiskFormat(ROLES, "fem\tida"), now));
+ UNIT_ASSERT_VALUES_EQUAL(now, fetcher.ReadFromDisk());
+ UNIT_ASSERT(fetcher.AreRolesOk());
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/roles' was successfully read\n"
+ "7: Succeed to read roles with revision 100501 from ./tmp/roles\n",
+ logger->Stream.Str());
+ logger->Stream.clear();
+ }
+
+ Y_UNIT_TEST(IsTimeToUpdate) {
+ TRetrySettings settings;
+ settings.RolesUpdatePeriod = TDuration::Minutes(123);
+
+ UNIT_ASSERT(!TRolesFetcher::IsTimeToUpdate(settings, TDuration::Seconds(5)));
+ UNIT_ASSERT(TRolesFetcher::IsTimeToUpdate(settings, TDuration::Hours(5)));
+ }
+
+ Y_UNIT_TEST(ShouldWarn) {
+ TRetrySettings settings;
+ settings.RolesWarnPeriod = TDuration::Minutes(123);
+
+ UNIT_ASSERT(!TRolesFetcher::ShouldWarn(settings, TDuration::Seconds(5)));
+ UNIT_ASSERT(TRolesFetcher::ShouldWarn(settings, TDuration::Hours(5)));
+ }
+
+ Y_UNIT_TEST(Update) {
+ CleanCache();
+ auto logger = MakeIntrusive<TLogger>();
+
+ TRolesFetcherSettings s;
+ s.CacheDir = CACHE_DIR;
+ s.SelfTvmId = 111111;
+ TRolesFetcher fetcher(s, logger);
+
+ UNIT_ASSERT(!fetcher.AreRolesOk());
+
+ NUtils::TFetchResult fetchResult;
+ fetchResult.Code = 304;
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ fetcher.Update(NUtils::TFetchResult(fetchResult)),
+ yexception,
+ "tirole did not return any roles because current roles are actual, but there are no roles in memory");
+ UNIT_ASSERT(!fetcher.AreRolesOk());
+ UNIT_ASSERT(!NFs::Exists(CACHE_DIR + "roles"));
+
+ fetchResult.Code = 206;
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ fetcher.Update(NUtils::TFetchResult(fetchResult)),
+ yexception,
+ "Unexpected code from tirole: 206.");
+ UNIT_ASSERT(!fetcher.AreRolesOk());
+ UNIT_ASSERT(!NFs::Exists(CACHE_DIR + "roles"));
+
+ fetchResult.Code = 200;
+ fetchResult.Response = "kek";
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ fetcher.Update(NUtils::TFetchResult(fetchResult)),
+ yexception,
+ "Invalid json. 'kek'");
+ UNIT_ASSERT(!fetcher.AreRolesOk());
+ UNIT_ASSERT(!NFs::Exists(CACHE_DIR + "roles"));
+
+ fetchResult.Response = ROLES;
+ UNIT_ASSERT_NO_EXCEPTION(fetcher.Update(NUtils::TFetchResult(fetchResult)));
+ UNIT_ASSERT(fetcher.AreRolesOk());
+ UNIT_ASSERT(NFs::Exists(CACHE_DIR + "roles"));
+ {
+ TFileInput f(CACHE_DIR + "roles");
+ TString body = f.ReadAll();
+ UNIT_ASSERT_C(body.Contains(ROLES), "got body: '" << body << "'");
+ }
+
+ fetchResult.Code = 304;
+ fetchResult.Response.clear();
+ UNIT_ASSERT_NO_EXCEPTION(fetcher.Update(NUtils::TFetchResult(fetchResult)));
+ UNIT_ASSERT(fetcher.AreRolesOk());
+ UNIT_ASSERT(NFs::Exists(CACHE_DIR + "roles"));
+
+ fetchResult.Code = 200;
+ fetchResult.Headers.AddHeader("X-Tirole-Compression", "kek");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ fetcher.Update(NUtils::TFetchResult(fetchResult)),
+ yexception,
+ "unknown codec format version; known: 1; got: kek");
+ }
+
+ Y_UNIT_TEST(CreateTiroleRequest) {
+ CleanCache();
+ auto logger = MakeIntrusive<TLogger>();
+
+ TRolesFetcherSettings s;
+ s.CacheDir = CACHE_DIR;
+ s.SelfTvmId = 111111;
+ s.IdmSystemSlug = "some sys";
+ TRolesFetcher fetcher(s, logger);
+
+ TRolesFetcher::TRequest req = fetcher.CreateTiroleRequest("some_ticket");
+ UNIT_ASSERT_VALUES_EQUAL(
+ "/v1/get_actual_roles?system_slug=some+sys&_pid=&lib_version=client_",
+ TStringBuf(req.Url).Chop(5));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TKeepAliveHttpClient::THeaders({
+ {"X-Ya-Service-Ticket", "some_ticket"},
+ }),
+ req.Headers);
+
+ TDiskWriter wr(CACHE_DIR + "roles");
+ UNIT_ASSERT(wr.Write(TRolesFetcher::PrepareDiskFormat(
+ R"({"revision": "asd&qwe", "born_date": 42})",
+ "some sys")));
+ UNIT_ASSERT_NO_EXCEPTION(fetcher.ReadFromDisk());
+
+ req = fetcher.CreateTiroleRequest("some_ticket");
+ UNIT_ASSERT_VALUES_EQUAL(
+ "/v1/get_actual_roles?system_slug=some+sys&_pid=&lib_version=client_",
+ TStringBuf(req.Url).Chop(5));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TKeepAliveHttpClient::THeaders({
+ {"If-None-Match", R"("asd&qwe")"},
+ {"X-Ya-Service-Ticket", "some_ticket"},
+ }),
+ req.Headers);
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/settings_ut.cpp b/library/cpp/tvmauth/client/ut/settings_ut.cpp
new file mode 100644
index 0000000000..76c9542442
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/settings_ut.cpp
@@ -0,0 +1,169 @@
+#include "common.h"
+
+#include <library/cpp/tvmauth/client/misc/api/settings.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NTvmAuth;
+
+Y_UNIT_TEST_SUITE(ClientSettings) {
+#if !defined(_win_)
+ Y_UNIT_TEST(CheckValid) {
+ struct TTestCase {
+ TString Name;
+ NTvmApi::TClientSettings Settings;
+ TString Err;
+ };
+ std::vector<TTestCase> cases = {
+ TTestCase{
+ .Name = "default",
+ .Settings = {},
+ .Err = "Invalid settings: nothing to do",
+ },
+ TTestCase{
+ .Name = "only secret",
+ .Settings = {
+ .Secret = TStringBuf("foobar"),
+ },
+ .Err = "Secret is present but destinations list is empty. It makes no sense",
+ },
+ TTestCase{
+ .Name = "only dsts",
+ .Settings = {
+ .FetchServiceTicketsForDsts = {42},
+ },
+ .Err = "SelfTvmId cannot be 0 if fetching of Service Tickets required",
+ },
+ TTestCase{
+ .Name = "dsts with selfTvmId",
+ .Settings = {
+ .SelfTvmId = 43,
+ .FetchServiceTicketsForDsts = {42},
+ },
+ .Err = "Secret is required for fetching of Service Tickets",
+ },
+ TTestCase{
+ .Name = "correct service tickets fetching",
+ .Settings = {
+ .SelfTvmId = 43,
+ .Secret = TStringBuf("foobar"),
+ .FetchServiceTicketsForDsts = {42},
+ },
+ .Err = "",
+ },
+ TTestCase{
+ .Name = "only check srv flag",
+ .Settings = {
+ .CheckServiceTickets = true,
+ },
+ .Err = "SelfTvmId cannot be 0 if checking of Service Tickets required",
+ },
+ TTestCase{
+ .Name = "tirole without disk cache",
+ .Settings = {
+ .SelfTvmId = 43,
+ .Secret = TStringBuf("foobar"),
+ .FetchRolesForIdmSystemSlug = "kek",
+ },
+ .Err = "Disk cache must be enabled to use roles: they can be heavy",
+ },
+ };
+
+ for (const TTestCase& c : cases) {
+ if (c.Err) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS_C(
+ c.Settings.CheckValid(),
+ TBrokenTvmClientSettings,
+ c.Err,
+ c.Name);
+ } else {
+ UNIT_ASSERT_NO_EXCEPTION_C(c.Settings.CheckValid(), c.Name);
+ }
+ }
+
+ NTvmApi::TClientSettings s{.DiskCacheDir = "/impossible/dir"};
+ UNIT_ASSERT_EXCEPTION(s.CheckValid(), TPermissionDenied);
+ }
+
+ Y_UNIT_TEST(CloneNormalized) {
+ NTvmApi::TClientSettings original;
+ original.FetchServiceTicketsForDsts = {43};
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(original.CloneNormalized(),
+ TBrokenTvmClientSettings,
+ "SelfTvmId cannot be 0 if fetching of Service Tickets required");
+ original.SelfTvmId = 15;
+ original.Secret = "bar";
+ original.DiskCacheDir = "./";
+
+ NTvmApi::TClientSettings::TDstVector expected = {43};
+ UNIT_ASSERT_VALUES_EQUAL(expected, original.CloneNormalized().FetchServiceTicketsForDsts);
+
+ original.FetchServiceTicketsForDstsWithAliases = {{"foo", 42}};
+ expected = {42, 43};
+ UNIT_ASSERT_VALUES_EQUAL(expected, original.CloneNormalized().FetchServiceTicketsForDsts);
+
+ original.FetchRolesForIdmSystemSlug = "kek";
+ expected = {42, 43, 2028120};
+ UNIT_ASSERT_VALUES_EQUAL(expected, original.CloneNormalized().FetchServiceTicketsForDsts);
+
+ original.FetchServiceTicketsForDsts.push_back(2028120);
+ expected = {42, 43, 2028120};
+ UNIT_ASSERT_VALUES_EQUAL(expected, original.CloneNormalized().FetchServiceTicketsForDsts);
+ }
+
+ Y_UNIT_TEST(NeedServiceTicketsFetching) {
+ NTvmApi::TClientSettings s;
+
+ UNIT_ASSERT(!s.NeedServiceTicketsFetching());
+
+ s.FetchServiceTicketsForDsts = {42};
+ UNIT_ASSERT(s.NeedServiceTicketsFetching());
+ s.FetchServiceTicketsForDsts.clear();
+
+ s.FetchServiceTicketsForDstsWithAliases = {{"foo", 42}};
+ UNIT_ASSERT(s.NeedServiceTicketsFetching());
+ s.FetchServiceTicketsForDstsWithAliases.clear();
+
+ s.FetchRolesForIdmSystemSlug = "bar";
+ UNIT_ASSERT(s.NeedServiceTicketsFetching());
+ s.FetchRolesForIdmSystemSlug.clear();
+ }
+
+ Y_UNIT_TEST(permitions) {
+ UNIT_ASSERT_EXCEPTION(NTvmApi::TClientSettings::CheckPermissions("/qwerty"), TPermissionDenied);
+
+ const TString tmpDir = "./cache_dir";
+
+ NFs::RemoveRecursive(tmpDir);
+ NFs::MakeDirectory(tmpDir, NFs::FP_OWNER_WRITE | NFs::FP_GROUP_WRITE | NFs::FP_ALL_WRITE);
+ UNIT_ASSERT_EXCEPTION(NTvmApi::TClientSettings::CheckPermissions(tmpDir), TPermissionDenied);
+
+ NFs::RemoveRecursive(tmpDir);
+ NFs::MakeDirectory(tmpDir, NFs::FP_OWNER_READ | NFs::FP_GROUP_READ | NFs::FP_ALL_READ);
+ UNIT_ASSERT_EXCEPTION(NTvmApi::TClientSettings::CheckPermissions(tmpDir), TPermissionDenied);
+
+ NFs::RemoveRecursive(tmpDir);
+ NFs::MakeDirectory(tmpDir, NFs::FP_COMMON_FILE);
+ UNIT_ASSERT_NO_EXCEPTION(NTvmApi::TClientSettings::CheckPermissions(tmpDir));
+ }
+#endif
+
+ Y_UNIT_TEST(Dst) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS(NTvmApi::TClientSettings::TDst(0), yexception, "TvmId cannot be 0");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(NTvmApi::TClientSettings::TDstMap({{"blackbox", 0}}),
+ TBrokenTvmClientSettings,
+ "TvmId cannot be 0");
+ }
+
+ Y_UNIT_TEST(Fetching) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(125);
+
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}});
+ UNIT_ASSERT_NO_EXCEPTION(s.CheckValid());
+
+ UNIT_ASSERT_VALUES_EQUAL(s.FetchServiceTicketsForDsts.size(), 1);
+ UNIT_ASSERT_VALUES_EQUAL(s.FetchServiceTicketsForDsts[0], 19);
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/src_checker_ut.cpp b/library/cpp/tvmauth/client/ut/src_checker_ut.cpp
new file mode 100644
index 0000000000..bd1646d6b9
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/src_checker_ut.cpp
@@ -0,0 +1,47 @@
+#include "common.h"
+
+#include <library/cpp/tvmauth/client/mocked_updater.h>
+#include <library/cpp/tvmauth/client/misc/src_checker.h>
+#include <library/cpp/tvmauth/client/misc/api/threaded_updater.h>
+
+#include <library/cpp/tvmauth/type.h>
+#include <library/cpp/tvmauth/unittest.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NTvmAuth;
+
+Y_UNIT_TEST_SUITE(SrcChecker) {
+ Y_UNIT_TEST(Ctor) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ TSrcChecker(new TMockedUpdater),
+ TBrokenTvmClientSettings,
+ "Need to use TClientSettings::EnableRolesFetching");
+ }
+
+ Y_UNIT_TEST(Check) {
+ NRoles::TRolesPtr roles = std::make_shared<NRoles::TRoles>(
+ NRoles::TRoles::TMeta{},
+ NRoles::TRoles::TTvmConsumers{
+ {12345, std::make_shared<NRoles::TConsumerRoles>(
+ THashMap<TString, NRoles::TEntitiesPtr>())},
+ },
+ NRoles::TRoles::TUserConsumers{},
+ std::make_shared<TString>());
+ const TSrcChecker checker(new TMockedUpdater({.Roles = roles}));
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(
+ checker.Check(NUnittest::CreateServiceTicket(ETicketStatus::Expired, 12345)),
+ TIllegalUsage,
+ "Service ticket must be valid");
+
+ TCheckedServiceTicket ticket;
+ UNIT_ASSERT_NO_EXCEPTION(
+ ticket = checker.Check(NUnittest::CreateServiceTicket(ETicketStatus::Ok, 12345)));
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::Ok, ticket.GetStatus());
+
+ UNIT_ASSERT_NO_EXCEPTION(
+ ticket = checker.Check(NUnittest::CreateServiceTicket(ETicketStatus::Ok, 9999)));
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::NoRoles, ticket.GetStatus());
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/tvmapi_updater_ut.cpp b/library/cpp/tvmauth/client/ut/tvmapi_updater_ut.cpp
new file mode 100644
index 0000000000..4cf449711b
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/tvmapi_updater_ut.cpp
@@ -0,0 +1,1272 @@
+#include "common.h"
+
+#include <library/cpp/tvmauth/client/mocked_updater.h>
+#include <library/cpp/tvmauth/client/misc/disk_cache.h>
+#include <library/cpp/tvmauth/client/misc/api/threaded_updater.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/testing/unittest/tests_data.h>
+
+#include <util/stream/file.h>
+#include <util/string/subst.h>
+#include <util/system/fs.h>
+
+#include <regex>
+
+using namespace NTvmAuth;
+static const std::regex TIME_REGEX(R"(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d.\d{6}Z)");
+
+Y_UNIT_TEST_SUITE(ApiUpdater) {
+ static const TString SRV_TICKET = "3:serv:CBAQ__________9_IgYIexCUkQY:GioCM49Ob6_f80y6FY0XBVN4hLXuMlFeyMvIMiDuQnZkbkLpRpQOuQo5YjWoBjM0Vf-XqOm8B7xtrvxSYHDD7Q4OatN2l-Iwg7i71lE3scUeD36x47st3nd0OThvtjrFx_D8mw_c0GT5KcniZlqq1SjhLyAk1b_zJsx8viRAhCU";
+ static const TString TEST_TICKET = "3:user:CA0Q__________9_Gg4KAgh7EHsg0oXYzAQoAQ:FSADps3wNGm92Vyb1E9IVq5M6ZygdGdt1vafWWEhfDDeCLoVA-sJesxMl2pGW4OxJ8J1r_MfpG3ZoBk8rLVMHUFrPa6HheTbeXFAWl8quEniauXvKQe4VyrpA1SPgtRoFqi5upSDIJzEAe1YRJjq1EClQ_slMt8R0kA_JjKUX54";
+ static const TString TVM_RESPONSE =
+ R"({
+ "19" : { "ticket" : "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"},
+ "213" : { "ticket" : "service_ticket_2"},
+ "234" : { "error" : "Dst is not found" },
+ "185" : { "ticket" : "service_ticket_3"},
+ "deprecated" : { "ticket" : "deprecated_ticket" }
+ })";
+
+ static const TString CACHE_DIR = "./tmp/";
+
+ static void CleanCache() {
+ NFs::RemoveRecursive(CACHE_DIR);
+ NFs::MakeDirectoryRecursive(CACHE_DIR);
+ }
+
+ Y_UNIT_TEST(MockedUpdater) {
+ TMockedUpdater m;
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, m.GetStatus());
+ UNIT_ASSERT(m.GetCachedServiceContext()->Check(SRV_TICKET));
+ UNIT_ASSERT(m.GetCachedUserContext()->Check(TEST_TICKET));
+ }
+
+ Y_UNIT_TEST(Updater) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketChecking();
+ s.SetDiskCacheDir(GetCachePath());
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ auto u = NTvmApi::TThreadedUpdater::Create(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u->GetStatus());
+ }
+
+ UNIT_ASSERT_C(l->Stream.Str().find("was successfully read") != TString::npos, l->Stream.Str());
+ UNIT_ASSERT_C(l->Stream.Str().find("were successfully fetched") == TString::npos, l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(Updater_badConfig) {
+ NTvmApi::TClientSettings s;
+ UNIT_ASSERT_EXCEPTION(NTvmApi::TThreadedUpdater::Create(s, TDevNullLogger::IAmBrave()), yexception);
+ s.SetSelfTvmId(100500);
+ UNIT_ASSERT_EXCEPTION(NTvmApi::TThreadedUpdater::Create(s, TDevNullLogger::IAmBrave()), yexception);
+ s.SetDiskCacheDir(GetCachePath());
+ UNIT_ASSERT_EXCEPTION(NTvmApi::TThreadedUpdater::Create(s, TDevNullLogger::IAmBrave()), yexception);
+ }
+
+ class TOfflineUpdater: public NTvmApi::TThreadedUpdater {
+ bool Enabled_;
+ TString PublicKeys_;
+
+ public:
+ TOfflineUpdater(const NTvmApi::TClientSettings& settings,
+ TIntrusivePtr<TLogger> l,
+ bool enabled = false,
+ TString keys = NUnittest::TVMKNIFE_PUBLIC_KEYS)
+ : NTvmApi::TThreadedUpdater(settings, l)
+ , Enabled_(enabled)
+ , PublicKeys_(keys)
+ {
+ Init();
+ StartWorker();
+ }
+
+ NUtils::TFetchResult FetchServiceTicketsFromHttp(const TString&) const override {
+ if (!Enabled_) {
+ throw yexception() << "alarm";
+ }
+ return {200, {}, "/2/ticket", TVM_RESPONSE, ""};
+ }
+
+ NUtils::TFetchResult FetchPublicKeysFromHttp() const override {
+ if (!Enabled_) {
+ throw yexception() << "alarm";
+ }
+ return {200, {}, "/2/keys", PublicKeys_, ""};
+ }
+ };
+
+ Y_UNIT_TEST(StartWithoutCache) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}, {"kolmo", 213}});
+ s.EnableServiceTicketChecking();
+
+ auto l = MakeIntrusive<TLogger>();
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TOfflineUpdater(s, l),
+ TRetriableException,
+ "Failed to start TvmClient. You can retry:");
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: Disk cache disabled. Please set disk cache directory in settings for best reliability\n"
+ << "4: Failed to get ServiceTickets: alarm\n"
+ << "4: Failed to get ServiceTickets: alarm\n"
+ << "4: Failed to get ServiceTickets: alarm\n"
+ << "4: Failed to update service tickets: alarm\n"
+ << "3: Service tickets have not been refreshed for too long period\n",
+ l->Stream.Str());
+ }
+
+ static void WriteFile(TString name, TStringBuf body, TInstant time) {
+ NFs::Remove(CACHE_DIR + name);
+ TFileOutput f(CACHE_DIR + name);
+ f << TDiskWriter::PrepareData(time, body);
+ }
+
+ Y_UNIT_TEST(StartWithOldCache) {
+ CleanCache();
+ WriteFile("./public_keys",
+ NUnittest::TVMKNIFE_PUBLIC_KEYS,
+ TInstant::Now() - TDuration::Days(30)); // too old
+ WriteFile("./service_tickets",
+ R"({"19":{"ticket":"3:serv:CBAQACIGCJSRBhAL:Fi"}})"
+ "\t100500",
+ TInstant::Now()); // too old
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}, {"kolmo", 213}});
+ s.EnableServiceTicketChecking();
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TOfflineUpdater u(s, l, true);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u.GetStatus());
+ }
+
+ UNIT_ASSERT_C(l->Stream.Str().find("Disk cache (public keys) is too old") != TString::npos, l->Stream.Str());
+ UNIT_ASSERT_C(l->Stream.Str().find("Disk cache (service tickets) is too old") != TString::npos, l->Stream.Str());
+ UNIT_ASSERT_C(l->Stream.Str().find("were successfully fetched") != TString::npos, l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(StartWithMissingCache) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketChecking();
+ s.SetDiskCacheDir("../");
+
+ auto l = MakeIntrusive<TLogger>();
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TOfflineUpdater(s, l),
+ TRetriableException,
+ "Failed to start TvmClient. You can retry: ");
+
+ UNIT_ASSERT_C(l->Stream.Str().find("does not exist") != TString::npos, l->Stream.Str());
+ UNIT_ASSERT_C(l->Stream.Str().find("were successfully fetched") == TString::npos, l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(StartWithBadCache_Tickets) {
+ CleanCache();
+ WriteFile("./service_tickets",
+ TVM_RESPONSE,
+ TInstant::Now());
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}, {"kolmo", 213}});
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TOfflineUpdater u(s, l, true);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u.GetStatus());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/service_tickets' was successfully read\n"
+ << "4: Failed to read service tickets from disk: YYYYYYYYYYYYYYY\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "7: Response with service tickets for 2 destination(s) was successfully fetched from https://tvm-api.yandex.net\n"
+ << "7: Got responses with service tickets with 1 pages for 2 destination(s)\n"
+ << "6: Cache was updated with 2 service ticket(s): XXXXXXXXXXX\n"
+ << "6: File './tmp/service_tickets' was successfully written\n"
+ << "7: Thread-worker started\n"
+ << "7: Thread-worker stopped\n",
+ std::regex_replace(std::regex_replace(std::string(l->Stream.Str()), TIME_REGEX, "XXXXXXXXXXX"),
+ std::regex(R"(Failed to read service tickets from disk: [^\n]+)"),
+ "Failed to read service tickets from disk: YYYYYYYYYYYYYYY"));
+ }
+
+ Y_UNIT_TEST(StartWithBadCache_PublicKeys) {
+ CleanCache();
+ WriteFile("./public_keys",
+ "ksjdafnlskdjzfgbhdl",
+ TInstant::Now());
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketChecking();
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TOfflineUpdater(s, l),
+ TRetriableException,
+ "Failed to start TvmClient. You can retry:");
+
+ UNIT_ASSERT_C(l->Stream.Str().find("4: Failed to read public keys from disk: Malformed TVM keys") != TString::npos, l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(StartWithCacheForAnotherTvmId) {
+ CleanCache();
+ WriteFile("./service_tickets",
+ TVM_RESPONSE + "\t" + "100499",
+ TInstant::Now());
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}, {"kolmo", 213}});
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TOfflineUpdater u(s, l, true);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u.GetStatus());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/service_tickets' was successfully read\n"
+ << "4: Disk cache is for another tvmId (100499). Self=100500\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "7: Response with service tickets for 2 destination(s) was successfully fetched from https://tvm-api.yandex.net\n"
+ << "7: Got responses with service tickets with 1 pages for 2 destination(s)\n"
+ << "6: Cache was updated with 2 service ticket(s): XXXXXXXXXXX\n"
+ << "6: File './tmp/service_tickets' was successfully written\n"
+ << "7: Thread-worker started\n"
+ << "7: Thread-worker stopped\n",
+ std::regex_replace(std::string(l->Stream.Str()), TIME_REGEX, "XXXXXXXXXXX"));
+ }
+
+ Y_UNIT_TEST(StartWithCacheForAnotherDsts) {
+ CleanCache();
+ TInstant now = TInstant::Now();
+ WriteFile("./service_tickets",
+ R"({"213" : { "ticket" : "3:serv:CBAQ__________9_IgYIlJEGEAs:T-"}})"
+ "\t"
+ "100500",
+ now);
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}, {"kolmo", 213}});
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TOfflineUpdater u(s, l, true);
+ auto cache = u.GetCachedServiceTickets();
+ UNIT_ASSERT(cache->TicketsById.contains(213));
+ UNIT_ASSERT(cache->TicketsById.contains(19));
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u.GetStatus());
+ }
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/service_tickets' was successfully read\n"
+ << "6: Got 1 service ticket(s) from disk\n"
+ << "6: Cache was updated with 1 service ticket(s): " << TInstant::Seconds(now.Seconds()) << "\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "7: Response with service tickets for 1 destination(s) was successfully fetched from https://tvm-api.yandex.net\n"
+ << "7: Got responses with service tickets with 1 pages for 1 destination(s)\n"
+ << "6: Cache was partly updated with 1 service ticket(s). total: 2\n"
+ << "6: File './tmp/service_tickets' was successfully written\n"
+ << "7: Thread-worker started\n"
+ << "7: Thread-worker stopped\n",
+ l->Stream.Str());
+ l->Stream.Clear();
+
+ {
+ TOfflineUpdater u(s, l, true);
+ auto cache = u.GetCachedServiceTickets();
+ UNIT_ASSERT(cache->TicketsById.contains(213));
+ UNIT_ASSERT(cache->TicketsById.contains(19));
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u.GetStatus());
+ }
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/service_tickets' was successfully read\n"
+ << "6: Got 2 service ticket(s) from disk\n"
+ << "6: Cache was updated with 2 service ticket(s): XXXXXXXXXXX\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "7: Thread-worker started\n"
+ << "7: Thread-worker stopped\n",
+ std::regex_replace(std::string(l->Stream.Str()), TIME_REGEX, "XXXXXXXXXXX"));
+ }
+
+ Y_UNIT_TEST(StartWithNotFreshCacheForAnotherDsts) {
+ CleanCache();
+ TInstant now = TInstant::Now();
+ WriteFile("./service_tickets",
+ R"({"213" : { "ticket" : "3:serv:CBAQ__________9_IgYIlJEGEAs:T-"}})"
+ "\t"
+ "100500",
+ now - TDuration::Hours(2));
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}, {"kolmo", 213}});
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TOfflineUpdater u(s, l, true);
+ auto cache = u.GetCachedServiceTickets();
+ UNIT_ASSERT(cache->TicketsById.contains(213));
+ UNIT_ASSERT(cache->TicketsById.contains(19));
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u.GetStatus());
+ }
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/service_tickets' was successfully read\n"
+ << "6: Got 1 service ticket(s) from disk\n"
+ << "6: Cache was updated with 1 service ticket(s): XXXXXXXXXXX\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "7: Response with service tickets for 2 destination(s) was successfully fetched from https://tvm-api.yandex.net\n"
+ << "7: Got responses with service tickets with 1 pages for 2 destination(s)\n"
+ << "6: Cache was updated with 2 service ticket(s): XXXXXXXXXXX\n"
+ << "6: File './tmp/service_tickets' was successfully written\n"
+ << "7: Thread-worker started\n"
+ << "7: Thread-worker stopped\n",
+ std::regex_replace(std::string(l->Stream.Str()), TIME_REGEX, "XXXXXXXXXXX"));
+ l->Stream.Clear();
+
+ {
+ TOfflineUpdater u(s, l, true);
+ auto cache = u.GetCachedServiceTickets();
+ UNIT_ASSERT(cache->TicketsById.contains(213));
+ UNIT_ASSERT(cache->TicketsById.contains(19));
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u.GetStatus());
+ }
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/service_tickets' was successfully read\n"
+ << "6: Got 2 service ticket(s) from disk\n"
+ << "6: Cache was updated with 2 service ticket(s): XXXXXXXXXXX\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "7: Thread-worker started\n"
+ << "7: Thread-worker stopped\n",
+ std::regex_replace(std::string(l->Stream.Str()), TIME_REGEX, "XXXXXXXXXXX"));
+ }
+
+ Y_UNIT_TEST(StartWithPartialDiskCache) {
+ CleanCache();
+ WriteFile("./public_keys",
+ NUnittest::TVMKNIFE_PUBLIC_KEYS,
+ TInstant::Now());
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}, {"kolmo", 213}});
+ s.EnableServiceTicketChecking();
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TOfflineUpdater u(s, l, true);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u.GetStatus());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "7: File './tmp/service_tickets' does not exist\n"
+ << "6: File './tmp/public_keys' was successfully read\n"
+ << "6: Cache was updated with public keys: XXXXXXXXXXX\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "7: Response with service tickets for 2 destination(s) was successfully fetched from https://tvm-api.yandex.net\n"
+ << "7: Got responses with service tickets with 1 pages for 2 destination(s)\n"
+ << "6: Cache was updated with 2 service ticket(s): XXXXXXXXXXX\n"
+ << "6: File './tmp/service_tickets' was successfully written\n"
+ << "7: Thread-worker started\n"
+ << "7: Thread-worker stopped\n",
+ std::regex_replace(std::string(l->Stream.Str()), TIME_REGEX, "XXXXXXXXXXX"));
+ }
+
+ Y_UNIT_TEST(StartFromHttpAndRestartFromDisk) {
+ CleanCache();
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}});
+ s.EnableServiceTicketChecking();
+ s.EnableUserTicketChecking(EBlackboxEnv::Test);
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ {
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TOfflineUpdater u(s, l, true);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u.GetStatus());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "7: File './tmp/service_tickets' does not exist\n"
+ << "7: File './tmp/public_keys' does not exist\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "7: Response with service tickets for 1 destination(s) was successfully fetched from https://tvm-api.yandex.net\n"
+ << "7: Got responses with service tickets with 1 pages for 1 destination(s)\n"
+ << "6: Cache was updated with 1 service ticket(s): XXXXXXXXXXX\n"
+ << "6: File './tmp/service_tickets' was successfully written\n"
+ << "7: Public keys were successfully fetched from https://tvm-api.yandex.net\n"
+ << "6: Cache was updated with public keys: XXXXXXXXXXX\n"
+ << "6: File './tmp/public_keys' was successfully written\n"
+ << "7: Thread-worker started\n"
+ << "7: Thread-worker stopped\n",
+ std::regex_replace(std::string(l->Stream.Str()), TIME_REGEX, "XXXXXXXXXXX"));
+ }
+
+ {
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TOfflineUpdater u(s, l, true);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u.GetStatus());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/service_tickets' was successfully read\n"
+ << "6: Got 1 service ticket(s) from disk\n"
+ << "6: Cache was updated with 1 service ticket(s): XXXXXXXXXXX\n"
+ << "6: File './tmp/public_keys' was successfully read\n"
+ << "6: Cache was updated with public keys: XXXXXXXXXXX\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "7: Thread-worker started\n"
+ << "7: Thread-worker stopped\n",
+ std::regex_replace(std::string(l->Stream.Str()), TIME_REGEX, "XXXXXXXXXXX"));
+ }
+ }
+
+ class TUnstableUpdater: public NTvmApi::TThreadedUpdater {
+ mutable int V1_ = 0;
+ mutable int V2_ = 0;
+
+ public:
+ TUnstableUpdater(const NTvmApi::TClientSettings& settings, TIntrusivePtr<TLogger> l)
+ : NTvmApi::TThreadedUpdater(settings, l)
+ {
+ UNIT_ASSERT_NO_EXCEPTION_C(Init(), l->Stream.Str());
+ ExpBackoff_.SetEnabled(false);
+ StartWorker();
+
+ UNIT_ASSERT_VALUES_EQUAL_C(TClientStatus::Ok, GetStatus(), l->Stream.Str());
+
+ Sleep(TDuration::MicroSeconds(100));
+ PublicKeysDurations_.Expiring = TDuration::MicroSeconds(100);
+ UNIT_ASSERT_VALUES_EQUAL_C(TClientStatus(TClientStatus::Warning, "Internal client error: failed to collect last useful error message, please report this message to tvm-dev@yandex-team.ru"),
+ GetStatus(),
+ l->Stream.Str());
+
+ PublicKeysDurations_.Invalid = TDuration::MicroSeconds(20);
+ UNIT_ASSERT_VALUES_EQUAL_C(TClientStatus::Error, GetStatus(), l->Stream.Str());
+
+ PublicKeysDurations_.Expiring = TDuration::Seconds(100);
+ PublicKeysDurations_.Invalid = TDuration::Seconds(200);
+ UNIT_ASSERT_VALUES_EQUAL_C(TClientStatus::Ok, GetStatus(), l->Stream.Str());
+
+ ServiceTicketsDurations_.Expiring = TDuration::MicroSeconds(100);
+ UNIT_ASSERT_VALUES_EQUAL_C(TClientStatus::Warning, GetStatus(), l->Stream.Str());
+
+ ServiceTicketsDurations_.Invalid = TDuration::MicroSeconds(20);
+ UNIT_ASSERT_VALUES_EQUAL_C(TClientStatus::Warning, GetStatus(), l->Stream.Str());
+
+ const TInstant* inv = &GetCachedServiceTickets()->InvalidationTime;
+ *const_cast<TInstant*>(inv) = TInstant::Now() + TDuration::Seconds(30);
+ UNIT_ASSERT_VALUES_EQUAL_C(TClientStatus::Error, GetStatus(), l->Stream.Str());
+ }
+
+ NUtils::TFetchResult FetchServiceTicketsFromHttp(const TString&) const override {
+ Y_ENSURE_EX(++V1_ > 1, yexception() << "++v1_ > 1:" << V1_);
+ return {200, {}, "/2/ticket", TVM_RESPONSE, ""};
+ }
+
+ NUtils::TFetchResult FetchPublicKeysFromHttp() const override {
+ Y_ENSURE_EX(++V2_ > 2, yexception() << "++v2_ > 2:" << V2_);
+ return {200, {}, "/2/keys", NUnittest::TVMKNIFE_PUBLIC_KEYS, ""};
+ }
+ };
+
+ Y_UNIT_TEST(StartFromUnstableHttp) {
+ CleanCache();
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}});
+ s.EnableServiceTicketChecking();
+ s.EnableUserTicketChecking(EBlackboxEnv::Test);
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TUnstableUpdater u(s, l);
+ }
+
+ UNIT_ASSERT_C(l->Stream.Str().Contains("++v1_ > 1"), l->Stream.Str());
+ UNIT_ASSERT_C(l->Stream.Str().Contains("++v2_ > 2"), l->Stream.Str());
+ UNIT_ASSERT_C(l->Stream.Str().Contains("7: Response with service tickets for 1 destination(s) was successfully fetched from https://tvm-api.yandex.net"), l->Stream.Str());
+ UNIT_ASSERT_C(l->Stream.Str().Contains("7: Public keys were successfully fetched"), l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(GetUpdateTimeOfServiceTickets) {
+ CleanCache();
+ TInstant ins = TInstant::Now();
+ WriteFile("./service_tickets",
+ TVM_RESPONSE + "\t" + "100500",
+ ins);
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}});
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+ TOfflineUpdater u(s, l, true);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u.GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL(TInstant(), u.GetUpdateTimeOfPublicKeys());
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(ins.Seconds()), u.GetUpdateTimeOfServiceTickets());
+ }
+
+ class TSignalingUpdater: public NTvmApi::TThreadedUpdater {
+ mutable int V_ = 0;
+ TAutoEvent& Ev_;
+ const TStringBuf PublicKeys_;
+
+ public:
+ TSignalingUpdater(const NTvmApi::TClientSettings& settings,
+ TLoggerPtr l,
+ TAutoEvent& ev,
+ const TStringBuf keys = NUnittest::TVMKNIFE_PUBLIC_KEYS)
+ : NTvmApi::TThreadedUpdater(settings, l)
+ , Ev_(ev)
+ , PublicKeys_(keys)
+ {
+ WorkerAwakingPeriod_ = TDuration::MilliSeconds(300);
+ PublicKeysDurations_.RefreshPeriod = TDuration::MilliSeconds(700);
+ Init();
+ ExpBackoff_.SetEnabled(false);
+ StartWorker();
+ }
+
+ NUtils::TFetchResult FetchPublicKeysFromHttp() const override {
+ if (++V_ >= 2) {
+ Ev_.Signal();
+ }
+ return {200, {}, "/2/keys", TString(PublicKeys_), ""};
+ }
+ };
+
+ Y_UNIT_TEST(StartWorker) {
+ class TSignalingUpdater: public NTvmApi::TThreadedUpdater {
+ mutable int V_ = 0;
+ TAutoEvent& Ev_;
+
+ public:
+ TSignalingUpdater(const NTvmApi::TClientSettings& settings, TLoggerPtr l, TAutoEvent& ev)
+ : NTvmApi::TThreadedUpdater(settings, l)
+ , Ev_(ev)
+ {
+ WorkerAwakingPeriod_ = TDuration::MilliSeconds(300);
+ PublicKeysDurations_.RefreshPeriod = TDuration::MilliSeconds(700);
+ Init();
+ ExpBackoff_.SetEnabled(false);
+ StartWorker();
+ }
+
+ void Worker() override {
+ NTvmApi::TThreadedUpdater::Worker();
+ Ev_.Signal();
+ }
+
+ NUtils::TFetchResult FetchPublicKeysFromHttp() const override {
+ if (++V_ < 4) {
+ return {500, {}, "/2/keys", "lol", ""};
+ }
+ return {200, {}, "/2/keys", NUnittest::TVMKNIFE_PUBLIC_KEYS, "CAEQChkAAAAAAAD4PyGamZmZmZm5PyhkMAE4B0BGSAI"};
+ }
+ };
+
+ CleanCache();
+ TInstant expiringPubKeys = TInstant::Now() - TDuration::Days(3);
+ WriteFile("./public_keys", NUnittest::TVMKNIFE_PUBLIC_KEYS, expiringPubKeys);
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketChecking();
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+ TAutoEvent ev;
+ {
+ TSignalingUpdater u(s, l, ev);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus(TClientStatus::Warning, "PublicKeys: Path:/2/keys.Code=500: lol"),
+ u.GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(expiringPubKeys.Seconds()), u.GetUpdateTimeOfPublicKeys());
+ UNIT_ASSERT_VALUES_EQUAL(TInstant(), u.GetUpdateTimeOfServiceTickets());
+
+ UNIT_ASSERT(ev.WaitT(TDuration::Seconds(15)));
+ Sleep(TDuration::MilliSeconds(500));
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u.GetStatus());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/public_keys' was successfully read\n"
+ << "6: Cache was updated with public keys: XXXXXXXXXXX\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "4: Failed to get PublicKeys: Path:/2/keys.Code=500: lol\n"
+ << "4: Failed to get PublicKeys: Path:/2/keys.Code=500: lol\n"
+ << "4: Failed to get PublicKeys: Path:/2/keys.Code=500: lol\n"
+ << "4: Failed to update public keys: Path:/2/keys.Code=500: lol\n"
+ << "3: Public keys have not been refreshed for too long period\n"
+ << "7: Thread-worker started\n"
+ << "7: Retry settings were updated: exponential_backoff_min:0.000000s->1.000000s;exponential_backoff_max:60.000000s->10.000000s;exponential_backoff_factor:2->1.5;exponential_backoff_jitter:0.5->0.1;max_random_sleep_default:5.000000s->0.100000s;retries_on_start:3->1;worker_awaking_period:10.000000s->7.000000s;dsts_limit:300->70;\n"
+ << "6: File './tmp/retry_settings' was successfully written\n"
+ << "7: Public keys were successfully fetched from https://tvm-api.yandex.net\n"
+ << "6: Cache was updated with public keys: XXXXXXXXXXX\n"
+ << "6: File './tmp/public_keys' was successfully written\n"
+ << "7: Thread-worker stopped\n",
+ std::regex_replace(std::string(l->Stream.Str()), TIME_REGEX, "XXXXXXXXXXX"));
+ }
+
+#if defined(_unix_)
+ Y_UNIT_TEST(StartFromCacheAndBadPublicKeysFromHttp) {
+ CleanCache();
+ TInstant now = TInstant::Now();
+ WriteFile("public_keys", NUnittest::TVMKNIFE_PUBLIC_KEYS, now - TDuration::Days(3)); // expiring public keys
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketChecking();
+ s.SetDiskCacheDir(CACHE_DIR);
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TAutoEvent ev;
+ TSignalingUpdater u(s, l, ev, "malformed keys");
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus(TClientStatus::Warning, "PublicKeys: Malformed TVM keys"),
+ u.GetStatus());
+
+ UNIT_ASSERT(ev.WaitT(TDuration::Seconds(15)));
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Warning, u.GetStatus());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: File './tmp/public_keys' was successfully read\n"
+ << "6: Cache was updated with public keys: " << TInstant::Seconds((now - TDuration::Days(3)).Seconds()) << "\n"
+ << "7: File './tmp/retry_settings' does not exist\n"
+ << "7: Public keys were successfully fetched from https://tvm-api.yandex.net\n"
+ << "4: Failed to update public keys: Malformed TVM keys\n"
+ << "3: Public keys have not been refreshed for too long period\n"
+ << "7: Thread-worker started\n"
+ << "7: Public keys were successfully fetched from https://tvm-api.yandex.net\n"
+ << "4: Failed to update public keys: Malformed TVM keys\n"
+ << "3: Public keys have not been refreshed for too long period\n"
+ << "7: Thread-worker stopped\n",
+ l->Stream.Str());
+ }
+#endif
+
+ Y_UNIT_TEST(StartWithBadPublicKeysFromHttp) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketChecking();
+
+ auto l = MakeIntrusive<TLogger>();
+ TAutoEvent ev;
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TOfflineUpdater(s, l, true, "some public keys"),
+ TRetriableException,
+ "Failed to start TvmClient. You can retry:");
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: Disk cache disabled. Please set disk cache directory in settings for best reliability\n"
+ << "7: Public keys were successfully fetched from https://tvm-api.yandex.net\n"
+ << "4: Failed to update public keys: Malformed TVM keys\n"
+ << "3: Public keys have not been refreshed for too long period\n",
+ l->Stream.Str());
+ }
+
+ class TNotInitedUpdater: public NTvmApi::TThreadedUpdater {
+ public:
+ TNotInitedUpdater(const NTvmApi::TClientSettings& settings, TLoggerPtr l = TDevNullLogger::IAmBrave())
+ : NTvmApi::TThreadedUpdater(settings, l)
+ {
+ this->ExpBackoff_.SetEnabled(false);
+ }
+
+ using NTvmApi::TThreadedUpdater::AppendToJsonArray;
+ using NTvmApi::TThreadedUpdater::AreServicesTicketsOk;
+ using NTvmApi::TThreadedUpdater::CreateJsonArray;
+ using NTvmApi::TThreadedUpdater::FindMissingDsts;
+ using NTvmApi::TThreadedUpdater::GetPublicKeysFromHttp;
+ using NTvmApi::TThreadedUpdater::GetServiceTicketsFromHttp;
+ using NTvmApi::TThreadedUpdater::Init;
+ using NTvmApi::TThreadedUpdater::IsServiceContextOk;
+ using NTvmApi::TThreadedUpdater::IsTimeToUpdatePublicKeys;
+ using NTvmApi::TThreadedUpdater::IsTimeToUpdateServiceTickets;
+ using NTvmApi::TThreadedUpdater::IsUserContextOk;
+ using NTvmApi::TThreadedUpdater::ParseTicketsFromDisk;
+ using NTvmApi::TThreadedUpdater::ParseTicketsFromResponse;
+ using NTvmApi::TThreadedUpdater::PrepareRequestForServiceTickets;
+ using NTvmApi::TThreadedUpdater::PrepareTicketsForDisk;
+ using NTvmApi::TThreadedUpdater::SetServiceContext;
+ using NTvmApi::TThreadedUpdater::SetServiceTickets;
+ using NTvmApi::TThreadedUpdater::SetUserContext;
+ using NTvmApi::TThreadedUpdater::THttpResult;
+ using NTvmApi::TThreadedUpdater::TPairTicketsErrors;
+ using TAsyncUpdaterBase::IsServiceTicketMapOk;
+ };
+
+ Y_UNIT_TEST(IsCacheComplete_Empty) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}, {"blackbox2", 20}});
+ s.EnableServiceTicketChecking();
+ s.EnableUserTicketChecking(EBlackboxEnv::Test);
+
+ TNotInitedUpdater u(s);
+ UNIT_ASSERT(!u.AreServicesTicketsOk());
+ }
+
+ Y_UNIT_TEST(IsCacheComplete_Tickets) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}, {"blackbox2", 20}});
+
+ TNotInitedUpdater u(s);
+ UNIT_ASSERT(!u.AreServicesTicketsOk());
+
+ u.SetServiceTickets(MakeIntrusiveConst<TServiceTickets>(
+ TServiceTickets::TMapIdStr({{1, "mega_ticket"}}),
+ TServiceTickets::TMapIdStr({{2, "mega_error"}}),
+ TServiceTickets::TMapAliasId()));
+ UNIT_ASSERT(!u.AreServicesTicketsOk());
+
+ u.SetServiceTickets(MakeIntrusiveConst<TServiceTickets>(
+ TServiceTickets::TMapIdStr({
+ {1, "mega_ticket"},
+ {2, "mega_ticket2"},
+ }),
+ TServiceTickets::TMapIdStr({
+ {3, "mega_error3"},
+ }),
+ TServiceTickets::TMapAliasId()));
+ UNIT_ASSERT(u.AreServicesTicketsOk());
+ }
+
+ Y_UNIT_TEST(IsCacheComplete_Service) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketChecking();
+
+ TNotInitedUpdater u(s);
+ UNIT_ASSERT(!u.IsServiceContextOk());
+
+ u.SetServiceContext(MakeIntrusiveConst<TServiceContext>(
+ TServiceContext::CheckingFactory(100500, NUnittest::TVMKNIFE_PUBLIC_KEYS)));
+ UNIT_ASSERT(u.IsServiceContextOk());
+ }
+
+ Y_UNIT_TEST(IsCacheComplete_User) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableUserTicketChecking(EBlackboxEnv::Test);
+
+ TNotInitedUpdater u(s);
+ UNIT_ASSERT(!u.IsUserContextOk());
+
+ u.SetUserContext(NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ UNIT_ASSERT(u.IsUserContextOk());
+ }
+
+ Y_UNIT_TEST(TicketsOnDisk) {
+ TString res = R"({
+ "19" : { "ticket" : "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"},
+ "213" : { "ticket" : "service_ticket_2"},
+ "234" : { "error" : "Dst is not found" },
+ "185" : { "ticket" : "service_ticket_3"},
+ "deprecated" : { "ticket" : "deprecated_ticket" }
+ })";
+ res.append("\t100500");
+
+ UNIT_ASSERT_VALUES_EQUAL(res, TNotInitedUpdater::PrepareTicketsForDisk(TVM_RESPONSE, 100500));
+
+ auto pair = TNotInitedUpdater::ParseTicketsFromDisk(res);
+ UNIT_ASSERT_VALUES_EQUAL(pair.first, TVM_RESPONSE);
+ UNIT_ASSERT_VALUES_EQUAL(pair.second, 100500);
+
+ res.push_back('a');
+ UNIT_ASSERT_EXCEPTION(TNotInitedUpdater::ParseTicketsFromDisk(res), yexception);
+ }
+
+ Y_UNIT_TEST(IsTimeToUpdatePublicKeys) {
+ NTvmApi::TClientSettings s;
+ s.EnableUserTicketChecking(EBlackboxEnv::Test);
+
+ TNotInitedUpdater u(s);
+
+ UNIT_ASSERT(!u.IsTimeToUpdatePublicKeys(TInstant::Now()));
+ UNIT_ASSERT(!u.IsTimeToUpdatePublicKeys(TInstant::Now() - TDuration::Hours(23)));
+ UNIT_ASSERT(u.IsTimeToUpdatePublicKeys(TInstant::Now() - TDuration::Days(1) - TDuration::MilliSeconds(1)));
+ }
+
+ Y_UNIT_TEST(IsTimeToUpdateServiceTickets) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}, {"blackbox2", 20}});
+
+ TNotInitedUpdater u(s);
+
+ UNIT_ASSERT(!u.IsTimeToUpdateServiceTickets(TInstant::Now() - TDuration::Minutes(59)));
+ UNIT_ASSERT(u.IsTimeToUpdateServiceTickets(TInstant::Now() - TDuration::Hours(1) - TDuration::MilliSeconds(1)));
+ }
+
+ Y_UNIT_TEST(StartWithIncompliteCache) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", NTvmApi::TClientSettings::TDstVector({19, 20}));
+ s.EnableServiceTicketChecking();
+ s.EnableUserTicketChecking(EBlackboxEnv::Test);
+
+ auto l = MakeIntrusive<TLogger>();
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TOfflineUpdater(s, l, true),
+ TNonRetriableException,
+ "Failed to get ServiceTicket for 20: Missing tvm_id in response, should never happend: 20");
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: Disk cache disabled. Please set disk cache directory in settings for best reliability\n"
+ << "7: Response with service tickets for 2 destination(s) was successfully fetched from https://tvm-api.yandex.net\n"
+ << "7: Got responses with service tickets with 1 pages for 2 destination(s)\n"
+ << "3: Failed to get service ticket for dst=20: Missing tvm_id in response, should never happend: 20\n"
+ << "6: Cache was updated with 1 service ticket(s): XXXXXXXXXXX\n",
+ std::regex_replace(std::string(l->Stream.Str()), TIME_REGEX, "XXXXXXXXXXX"));
+ }
+
+ Y_UNIT_TEST(PrepareRequestForServiceTickets) {
+ const TServiceContext ctx = TServiceContext::SigningFactory("AAAAAAAAAAAAAAAAAAAAAA");
+
+ TString s = TNotInitedUpdater::PrepareRequestForServiceTickets(117,
+ ctx,
+ {19, 20},
+ NUtils::TProcInfo{
+ "__some_pid__",
+ "__some_pname__",
+ "kar",
+ },
+ 100700);
+ SubstGlobal(s.resize(s.size() - 5), "deb_", "");
+ UNIT_ASSERT_VALUES_EQUAL("grant_type=client_credentials&src=117&dst=19,20&ts=100700&sign=XTz2Obd6PII_BHxswzWPJTjju9SrKsN6hyu1VsyxBvU&get_retry_settings=yes&_pid=__some_pid__&_procces_name=__some_pname__&lib_version=client_kar",
+ s);
+
+ s = TNotInitedUpdater::PrepareRequestForServiceTickets(118,
+ ctx,
+ {19},
+ NUtils::TProcInfo{
+ "__some_pid__",
+ {},
+ "kva_",
+ },
+ 100900);
+ SubstGlobal(s.resize(s.size() - 5), "deb_", "");
+ UNIT_ASSERT_VALUES_EQUAL("grant_type=client_credentials&src=118&dst=19&ts=100900&sign=-trBo9AtBLjp2ihy6cFAdMAQ6S9afHj23rFzYQ32jkQ&get_retry_settings=yes&_pid=__some_pid__&lib_version=client_kva_",
+ s);
+ }
+
+ Y_UNIT_TEST(ParseTicketsFromResponse) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketChecking();
+
+ auto l = MakeIntrusive<TLogger>();
+ TNotInitedUpdater u(s, l);
+
+ TNotInitedUpdater::TPairTicketsErrors t;
+ UNIT_ASSERT_EXCEPTION_CONTAINS(u.ParseTicketsFromResponse("{", NTvmApi::TDstSet{19}, t),
+ yexception,
+ "Invalid json from tvm-api");
+
+ t = {};
+ u.ParseTicketsFromResponse(TVM_RESPONSE, NTvmApi::TDstSet{19}, t);
+
+ TNotInitedUpdater::TPairTicketsErrors expected{{{19, "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"}}, {}};
+ UNIT_ASSERT_VALUES_EQUAL("6: Disk cache disabled. Please set disk cache directory in settings for best reliability\n",
+ l->Stream.Str());
+ UNIT_ASSERT_EQUAL(expected, t);
+
+ t = {};
+ u.ParseTicketsFromResponse(TVM_RESPONSE,
+ NTvmApi::TDstSet{19, 213, 234, 235},
+ t);
+ expected = {{{19, "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"},
+ {213, "service_ticket_2"}},
+ {{234, "Dst is not found"},
+ {235, "Missing tvm_id in response, should never happend: 235"}}};
+ UNIT_ASSERT_EQUAL(expected, t);
+ UNIT_ASSERT_VALUES_EQUAL("6: Disk cache disabled. Please set disk cache directory in settings for best reliability\n",
+ l->Stream.Str());
+
+ t = {};
+ u.ParseTicketsFromResponse(
+ R"([
+ {"19" : { "ticket" : "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"},"234" : { "error" : "Dst is not found" }},
+ {"213" : { "ticket" : "service_ticket_2"},"185" : { "ticket" : "service_ticket_3"}},
+ {"deprecated" : { "ticket" : "deprecated_ticket" }}
+ ])",
+ NTvmApi::TDstSet{19, 213, 234, 235},
+ t);
+ expected = {{{19, "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"},
+ {213, "service_ticket_2"}},
+ {{234, "Dst is not found"},
+ {235, "Missing tvm_id in response, should never happend: 235"}}};
+ UNIT_ASSERT_EQUAL(expected, t);
+ UNIT_ASSERT_VALUES_EQUAL("6: Disk cache disabled. Please set disk cache directory in settings for best reliability\n",
+ l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(ParseTicketsFromResponseAsArray) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketChecking();
+
+ auto l = MakeIntrusive<TLogger>();
+ TNotInitedUpdater u(s, l);
+
+ TNotInitedUpdater::TPairTicketsErrors t;
+ UNIT_ASSERT_EXCEPTION_CONTAINS(u.ParseTicketsFromResponse("[", NTvmApi::TDstSet{19}, t),
+ yexception,
+ "Invalid json from tvm-api");
+
+ u.ParseTicketsFromResponse(R"([])", NTvmApi::TDstSet{19}, t);
+ UNIT_ASSERT_VALUES_EQUAL("6: Disk cache disabled. Please set disk cache directory in settings for best reliability\n",
+ l->Stream.Str());
+ TNotInitedUpdater::TPairTicketsErrors expected = {
+ {}, {{19, "Missing tvm_id in response, should never happend: 19"}}};
+ UNIT_ASSERT_VALUES_EQUAL(expected, t);
+ l->Stream.Clear();
+
+ t = {};
+ u.ParseTicketsFromResponse(
+ R"([{},{"19" : { "ticket" : "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"}}, {"213" : { "ticket" : "service_ticket_2"}}])",
+ NTvmApi::TDstSet{19},
+ t);
+ UNIT_ASSERT_VALUES_EQUAL("", l->Stream.Str());
+ expected = {{{19, "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"}}, {}};
+ UNIT_ASSERT_EQUAL(expected, t);
+
+ t = {};
+ u.ParseTicketsFromResponse(
+ R"([{
+ "19" : { "ticket" : "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"}
+ },
+ {
+ "213" : { "ticket" : "service_ticket_2"},
+ "234" : { "error" : "Dst is not found" }
+ },
+ {
+ "185" : { "ticket" : "service_ticket_3"},
+ "deprecated" : { "ticket" : "deprecated_ticket" }
+ }
+ ])",
+ NTvmApi::TDstSet{19, 213, 234, 235},
+ t);
+ expected = {{{19, "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"},
+ {213, "service_ticket_2"}},
+ {{234, "Dst is not found"},
+ {235, "Missing tvm_id in response, should never happend: 235"}}};
+ UNIT_ASSERT_EQUAL(expected, t);
+ UNIT_ASSERT_VALUES_EQUAL("", l->Stream.Str());
+ }
+
+ class TReplier: public TRequestReplier {
+ public:
+ HttpCodes Code = HTTP_OK;
+
+ bool DoReply(const TReplyParams& params) override {
+ TParsedHttpFull fl(params.Input.FirstLine());
+
+ THttpResponse resp(Code);
+ if (fl.Path == "/2/keys") {
+ resp.SetContent(NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ } else if (fl.Path == "/2/ticket") {
+ resp.SetContent(TVM_RESPONSE);
+ } else {
+ UNIT_ASSERT(false);
+ }
+ resp.OutTo(params.Output);
+
+ return true;
+ }
+ };
+
+ class TOnlineUpdater: public NTvmApi::TThreadedUpdater {
+ public:
+ TOnlineUpdater(const NTvmApi::TClientSettings& settings, TIntrusivePtr<TLogger> l)
+ : NTvmApi::TThreadedUpdater(settings, l)
+ {
+ Init();
+ ExpBackoff_.SetEnabled(false);
+ StartWorker();
+ }
+ };
+
+ Y_UNIT_TEST(MocServerOk) {
+ TPortManager pm;
+ ui16 tvmPort = pm.GetPort(80);
+ NMock::TMockServer server(tvmPort, []() { return new TReplier; });
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}});
+ s.EnableServiceTicketChecking();
+ s.EnableUserTicketChecking(EBlackboxEnv::Test);
+ s.SetTvmHostPort("http://localhost", tvmPort);
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TOnlineUpdater u(s, l);
+ UNIT_ASSERT_VALUES_EQUAL_C(TClientStatus::Ok, u.GetStatus(), l->Stream.Str());
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: Disk cache disabled. Please set disk cache directory in settings for best reliability\n"
+ << "7: Response with service tickets for 1 destination(s) was successfully fetched from http://localhost\n"
+ << "7: Got responses with service tickets with 1 pages for 1 destination(s)\n"
+ << "6: Cache was updated with 1 service ticket(s): XXXXXXXXXXX\n"
+ << "7: Public keys were successfully fetched from http://localhost\n"
+ << "6: Cache was updated with public keys: XXXXXXXXXXX\n"
+ << "7: Thread-worker started\n"
+ << "7: Thread-worker stopped\n",
+ std::regex_replace(std::string(l->Stream.Str()), TIME_REGEX, "XXXXXXXXXXX"));
+ }
+
+ Y_UNIT_TEST(MocServerBad) {
+ TPortManager pm;
+ ui16 tvmPort = pm.GetPort(80);
+ NMock::TMockServer server(tvmPort,
+ []() {
+ auto p = new TReplier;
+ p->Code = HTTP_BAD_REQUEST;
+ return p;
+ });
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", {{"blackbox", 19}});
+ s.EnableServiceTicketChecking();
+ s.EnableUserTicketChecking(EBlackboxEnv::Test);
+ s.SetTvmHostPort("localhost", tvmPort);
+
+ auto l = MakeIntrusive<TLogger>();
+ UNIT_ASSERT_EXCEPTION_CONTAINS_C(TOnlineUpdater(s, l),
+ TNonRetriableException,
+ "Failed to start TvmClient. Do not retry: ServiceTickets: Path:/2/ticket.Code=400:",
+ l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(MocServerPaginated) {
+ class TReplier: public TRequestReplier {
+ public:
+ TString Response;
+ TReplier(TString response)
+ : Response(response)
+ {
+ }
+
+ bool DoReply(const TReplyParams& params) override {
+ TParsedHttpFull fl(params.Input.FirstLine());
+ if (fl.Path != "/2/ticket") {
+ UNIT_ASSERT_C(false, fl.Path);
+ }
+
+ THttpResponse resp(HTTP_OK);
+ resp.SetContent(Response);
+ resp.OutTo(params.Output);
+ return true;
+ }
+ };
+
+ TPortManager pm;
+ ui16 tvmPort = pm.GetPort(80);
+ TVector<TString> responses = {
+ R"({"15" : { "ticket" : "service_ticket_3" },"19" : { "ticket" : "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"}})",
+ R"({"222" : { "ticket" : "service_ticket_2"}, "239" : { "error" : "Dst is not found" }})",
+ R"({"185" : { "ticket" : "service_ticket_3"}})",
+ };
+ NMock::TMockServer server(tvmPort, [&responses]() {
+ if (responses.empty()) {
+ return new TReplier("<NULL>");
+ }
+ TString r = responses.front();
+ responses.erase(responses.begin());
+ return new TReplier(r);
+ });
+
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketsFetchOptions("qwerty", NTvmApi::TClientSettings::TDstVector{19, 222, 239, 100500, 15});
+ s.SetTvmHostPort("http://localhost", tvmPort);
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TNotInitedUpdater u(s, l);
+ TNotInitedUpdater::THttpResult result = u.GetServiceTicketsFromHttp(NTvmApi::TDstSet{19, 222, 239, 100500, 15}, 2);
+ UNIT_ASSERT_VALUES_EQUAL(TSmallVec<TString>({
+ R"({"15" : { "ticket" : "service_ticket_3" },"19" : { "ticket" : "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"}})",
+ R"({"222" : { "ticket" : "service_ticket_2"}, "239" : { "error" : "Dst is not found" }})",
+ R"({"185" : { "ticket" : "service_ticket_3"}})",
+ }),
+ result.Responses);
+ TNotInitedUpdater::TPairTicketsErrors expected{
+ {
+ {19, "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"},
+ {222, "service_ticket_2"},
+ {15, "service_ticket_3"},
+ },
+ {
+ {239, "Dst is not found"},
+ {100500, "Missing tvm_id in response, should never happend: 100500"},
+ },
+ };
+ UNIT_ASSERT_VALUES_EQUAL(expected, result.TicketsWithErrors);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "6: Disk cache disabled. Please set disk cache directory in settings for best reliability\n"
+ << "7: Response with service tickets for 2 destination(s) was successfully fetched from http://localhost\n"
+ << "7: Response with service tickets for 2 destination(s) was successfully fetched from http://localhost\n"
+ << "7: Response with service tickets for 1 destination(s) was successfully fetched from http://localhost\n"
+ << "7: Got responses with service tickets with 3 pages for 5 destination(s)\n"
+ << "3: Failed to get service ticket for dst=100500: Missing tvm_id in response, should never happend: 100500\n"
+ << "3: Failed to get service ticket for dst=239: Dst is not found\n",
+ l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(FindMissingDsts) {
+ UNIT_ASSERT_VALUES_EQUAL(NTvmApi::TClientSettings::TDstVector({6, 9}),
+ TNotInitedUpdater::FindMissingDsts({1, 2, 3, 4}, {1, 4, 6, 9}));
+ UNIT_ASSERT_VALUES_EQUAL(NTvmApi::TClientSettings::TDstVector(),
+ TNotInitedUpdater::FindMissingDsts({1, 2, 3, 4, 5, 6, 7, 8, 9}, {1, 4, 6, 9}));
+ UNIT_ASSERT_VALUES_EQUAL(NTvmApi::TClientSettings::TDstVector({1, 4, 6, 9}),
+ TNotInitedUpdater::FindMissingDsts(NTvmApi::TDstSet(), {1, 4, 6, 9}));
+ UNIT_ASSERT_VALUES_EQUAL(NTvmApi::TClientSettings::TDstVector(1, 19),
+ TNotInitedUpdater::FindMissingDsts({213}, {19, 213}));
+
+ auto make = [](TVector<int> ids) {
+ TServiceTickets::TMapIdStr m;
+ for (auto i : ids) {
+ m.insert({i, ""});
+ }
+ return MakeIntrusiveConst<TServiceTickets>(std::move(m), TServiceTickets::TMapIdStr{}, TServiceTickets::TMapAliasId{});
+ };
+
+ UNIT_ASSERT_VALUES_EQUAL(NTvmApi::TClientSettings::TDstVector({6, 9}),
+ TNotInitedUpdater::FindMissingDsts(make({1, 2, 3, 4}), {1, 4, 6, 9}));
+ UNIT_ASSERT_VALUES_EQUAL(NTvmApi::TClientSettings::TDstVector(),
+ TNotInitedUpdater::FindMissingDsts(make({1, 2, 3, 4, 5, 6, 7, 8, 9}), {1, 4, 6, 9}));
+ UNIT_ASSERT_VALUES_EQUAL(NTvmApi::TClientSettings::TDstVector({1, 4, 6, 9}),
+ TNotInitedUpdater::FindMissingDsts(make({}), {1, 4, 6, 9}));
+ UNIT_ASSERT_VALUES_EQUAL(NTvmApi::TClientSettings::TDstVector(1, 19),
+ TNotInitedUpdater::FindMissingDsts(make({213}), {19, 213}));
+ }
+
+ Y_UNIT_TEST(CreateJsonArray) {
+ UNIT_ASSERT_VALUES_EQUAL("[]", TNotInitedUpdater::CreateJsonArray({}));
+ UNIT_ASSERT_VALUES_EQUAL("[sdlzkjvbsdljhfbsdajlhfbsakjdfb]",
+ TNotInitedUpdater::CreateJsonArray({"sdlzkjvbsdljhfbsdajlhfbsakjdfb"}));
+ UNIT_ASSERT_VALUES_EQUAL("[sdlzkjvbsdljhfbsdajlhfbsakjdfb,o92q83yh2uhq2eri23r]",
+ TNotInitedUpdater::CreateJsonArray({"sdlzkjvbsdljhfbsdajlhfbsakjdfb",
+ "o92q83yh2uhq2eri23r"}));
+ }
+
+ Y_UNIT_TEST(AppendArrayToJson) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TNotInitedUpdater::AppendToJsonArray("", {}),
+ yexception,
+ "previous body required");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TNotInitedUpdater::AppendToJsonArray("[kek", {}),
+ yexception,
+ "array is broken:");
+
+ UNIT_ASSERT_VALUES_EQUAL("[kek]", TNotInitedUpdater::AppendToJsonArray("kek", {}));
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ "[kek,sdlzkjvbsdljhfbsdajlhfbsakjdfb]",
+ TNotInitedUpdater::AppendToJsonArray("kek",
+ {"sdlzkjvbsdljhfbsdajlhfbsakjdfb"}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "[kek,sdlzkjvbsdljhfbsdajlhfbsakjdfb,o92q83yh2uhq2eri23r]",
+ TNotInitedUpdater::AppendToJsonArray("kek",
+ {"sdlzkjvbsdljhfbsdajlhfbsakjdfb", "o92q83yh2uhq2eri23r"}));
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ "[kek,sdlzkjvbsdljhfbsdajlhfbsakjdfb]",
+ TNotInitedUpdater::AppendToJsonArray("[kek]",
+ {"sdlzkjvbsdljhfbsdajlhfbsakjdfb"}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "[kek,sdlzkjvbsdljhfbsdajlhfbsakjdfb,o92q83yh2uhq2eri23r]",
+ TNotInitedUpdater::AppendToJsonArray("[kek]",
+ {"sdlzkjvbsdljhfbsdajlhfbsakjdfb", "o92q83yh2uhq2eri23r"}));
+ }
+
+ Y_UNIT_TEST(UpdaterTimeouts) {
+ NTvmApi::TClientSettings s;
+ s.SetSelfTvmId(100500);
+ s.EnableServiceTicketChecking();
+ s.TvmHost = "localhost";
+ s.TvmPort = GetRandomPort();
+ const auto timeout = TDuration::MilliSeconds(10);
+ s.TvmConnectTimeout = timeout;
+ s.TvmSocketTimeout = timeout;
+
+ {
+ auto l = MakeIntrusive<TLogger>();
+ auto startTs = ::Now();
+ UNIT_ASSERT_EXCEPTION(NTvmApi::TThreadedUpdater::Create(s, l), yexception);
+ UNIT_ASSERT_LT(::Now() - startTs, timeout * 2);
+ }
+ }
+}
+
+template <>
+void Out<TSmallVec<TString>>(IOutputStream& out, const TSmallVec<TString>& m) {
+ for (const TString& s : m) {
+ out << s << ";";
+ }
+}
+
+template <>
+void Out<TServiceTickets::TMapIdStr>(
+ IOutputStream& out,
+ const TServiceTickets::TMapIdStr& m) {
+ for (const auto& pair : m) {
+ out << pair.first << " -> " << pair.second << ";";
+ }
+}
+
+template <>
+void Out<NTestSuiteApiUpdater::TNotInitedUpdater::TPairTicketsErrors>(
+ IOutputStream& out,
+ const NTestSuiteApiUpdater::TNotInitedUpdater::TPairTicketsErrors& m) {
+ out << m.Tickets << "\n";
+ out << m.Errors << "\n";
+}
+
+template <>
+void Out<NTvmAuth::NTvmApi::TClientSettings::TDst>(IOutputStream& out, const NTvmAuth::NTvmApi::TClientSettings::TDst& m) {
+ out << m.Id;
+}
diff --git a/library/cpp/tvmauth/client/ut/tvmtool_updater_ut.cpp b/library/cpp/tvmauth/client/ut/tvmtool_updater_ut.cpp
new file mode 100644
index 0000000000..1295ed750e
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/tvmtool_updater_ut.cpp
@@ -0,0 +1,744 @@
+#include "common.h"
+
+#include <library/cpp/tvmauth/client/facade.h>
+#include <library/cpp/tvmauth/client/misc/tool/threaded_updater.h>
+
+#include <library/cpp/http/simple/http_client.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/system/env.h>
+
+using namespace NTvmAuth;
+using namespace NTvmAuth::NTvmTool;
+
+Y_UNIT_TEST_SUITE(ToolUpdater) {
+ static const TString SRV_TICKET = "3:serv:CBAQ__________9_IgYIexCUkQY:GioCM49Ob6_f80y6FY0XBVN4hLXuMlFeyMvIMiDuQnZkbkLpRpQOuQo5YjWoBjM0Vf-XqOm8B7xtrvxSYHDD7Q4OatN2l-Iwg7i71lE3scUeD36x47st3nd0OThvtjrFx_D8mw_c0GT5KcniZlqq1SjhLyAk1b_zJsx8viRAhCU";
+ static const TString SRV_TICKET_DST_100503 = "3:serv:CBAQ__________9_IggIwMQHEJeRBg:Kj7VApP6D91UJ8pKpeaE3vYaNTBBJcdYpJLbF9w2-Mb-75s_SmMKkPqqA2rMS358uFfoYpv9YZxq0tIaUj5HPQ1WaQ1yiVuPZ_oi3pJRdr006eRyihM8PUfl6m9ioCFftfOcAg9oN5BGeHTNhn7VWuj3yMg7feaMB0zAUpyaPG0";
+ static const TString TEST_TICKET = "3:user:CA0Q__________9_Gg4KAgh7EHsg0oXYzAQoAQ:FSADps3wNGm92Vyb1E9IVq5M6ZygdGdt1vafWWEhfDDeCLoVA-sJesxMl2pGW4OxJ8J1r_MfpG3ZoBk8rLVMHUFrPa6HheTbeXFAWl8quEniauXvKQe4VyrpA1SPgtRoFqi5upSDIJzEAe1YRJjq1EClQ_slMt8R0kA_JjKUX54";
+ static const TString PROD_YATEAM_TICKET = "3:user:CAwQ__________9_Gg4KAgh7EHsg0oXYzAQoAg:G2wloFRSi8--RLb2GDSro_sKXPF2JSdL5CVOuOHgUcRvLm-3OxIPn0NUqbJ9DWDmhPplOqEiblIbLK85My1VMJ2aG5SLbRNKEtwfmxLvkwNpl_gUEwWPJm9_8Khslfj71P3hccxtEEqM9bJSMwHueVAY-a9HSzFo-uMFMeSgQ-k";
+
+ class TMetaInfoProxy: public TMetaInfo {
+ public:
+ using TMetaInfo::ApplySettings;
+ using TMetaInfo::BbEnvFromString;
+ using TMetaInfo::Config_;
+ using TMetaInfo::Fetch;
+ using TMetaInfo::ParseMetaString;
+ using TMetaInfo::TMetaInfo;
+ };
+
+ Y_UNIT_TEST(Settings) {
+ NTvmTool::TClientSettings s("foo");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(s.SetAuthToken("\n "),
+ TBrokenTvmClientSettings,
+ "Auth token cannot be empty");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(s.GetAuthToken(),
+ TBrokenTvmClientSettings,
+ "Auth token cannot be empty. Env 'TVMTOOL_LOCAL_AUTHTOKEN' and 'QLOUD_TVM_TOKEN' are empty.");
+
+ UNIT_ASSERT_NO_EXCEPTION(s.SetAuthToken(AUTH_TOKEN + "\n"));
+ UNIT_ASSERT_VALUES_EQUAL(AUTH_TOKEN, s.GetAuthToken());
+
+ UNIT_ASSERT_VALUES_EQUAL("localhost", s.GetHostname());
+ UNIT_ASSERT_EXCEPTION_CONTAINS(s.SetHostname(""),
+ TBrokenTvmClientSettings,
+ "Hostname cannot be empty");
+
+ UNIT_ASSERT_NO_EXCEPTION(s.SetHostname("qwe"));
+ UNIT_ASSERT_VALUES_EQUAL("qwe", s.GetHostname());
+ }
+
+ Y_UNIT_TEST(SettingsCtor) {
+ UNIT_ASSERT_EXCEPTION_CONTAINS(NTvmTool::TClientSettings(""),
+ TBrokenTvmClientSettings,
+ "Alias for your TVM client cannot be empty");
+ {
+ NTvmTool::TClientSettings s("self");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(s.GetAuthToken(),
+ TBrokenTvmClientSettings,
+ "Auth token cannot be empty. "
+ "Env 'TVMTOOL_LOCAL_AUTHTOKEN' and 'QLOUD_TVM_TOKEN' are empty.");
+ }
+
+ struct TEnvs {
+ TEnvs(const std::map<TString, TString>& Env) {
+ for (const auto& [key, value] : Env) {
+ Prev[key] = GetEnv(key);
+ SetEnv(key, value);
+ }
+ }
+
+ ~TEnvs() {
+ for (const auto& [key, value] : Prev) {
+ SetEnv(key, value);
+ }
+ }
+
+ std::map<TString, TString> Prev;
+ };
+
+ struct TCase {
+ std::map<TString, TString> Env;
+ TString AuthToken;
+ ui16 Port = 0;
+ };
+
+ std::vector<TCase> cases = {
+ {
+ {
+ {"TVMTOOL_LOCAL_AUTHTOKEN", "qwerty"},
+ },
+ "qwerty",
+ 1,
+ },
+ {
+ {
+ {"TVMTOOL_LOCAL_AUTHTOKEN", "qwerty"},
+ {"QLOUD_TVM_TOKEN", "zxcvbn"},
+ },
+ "qwerty",
+ 1,
+ },
+ {
+ {
+ {"QLOUD_TVM_TOKEN", "zxcvbn"},
+ },
+ "zxcvbn",
+ 1,
+ },
+ {
+ {
+ {"TVMTOOL_LOCAL_AUTHTOKEN", "qwerty"},
+ {"DEPLOY_TVM_TOOL_URL", "32272"},
+ },
+ "qwerty",
+ 1,
+ },
+ {
+ {
+ {"TVMTOOL_LOCAL_AUTHTOKEN", "qwerty"},
+ {"DEPLOY_TVM_TOOL_URL", "localhost:32272"},
+ },
+ "qwerty",
+ 32272,
+ },
+ {
+ {
+ {"TVMTOOL_LOCAL_AUTHTOKEN", "qwerty"},
+ {"DEPLOY_TVM_TOOL_URL", "http://localhost:32272"},
+ },
+ "qwerty",
+ 32272,
+ },
+ };
+
+ for (const TCase& c : cases) {
+ TEnvs envs(c.Env);
+
+ NTvmTool::TClientSettings s("self");
+ UNIT_ASSERT_VALUES_EQUAL(c.AuthToken, s.GetAuthToken());
+ UNIT_ASSERT_VALUES_EQUAL(c.Port, s.GetPort());
+ }
+ }
+
+ Y_UNIT_TEST(Meta_Fetch) {
+ TPortManager pm;
+ ui16 port = pm.GetPort(80);
+ NMock::TMockServer server(port, []() { return new TTvmTool; });
+ TKeepAliveHttpClient client("localhost", port);
+
+ TMetaInfoProxy m(nullptr);
+ NTvmTool::TClientSettings settings("me");
+ settings.SetAuthToken(AUTH_TOKEN);
+ m.ApplySettings(settings);
+
+ UNIT_ASSERT_VALUES_EQUAL(META, m.Fetch(client));
+
+ settings.SetAuthToken("qwerty");
+ m.ApplySettings(settings);
+ UNIT_ASSERT_EXCEPTION_CONTAINS(m.Fetch(client),
+ TNonRetriableException,
+ "Failed to fetch meta from tvmtool: localhost:");
+
+ settings.SetAuthToken(AUTH_TOKEN);
+ m.ApplySettings(settings);
+ {
+ TKeepAliveHttpClient client("localhost", 0);
+ UNIT_ASSERT_EXCEPTION_CONTAINS(m.Fetch(client),
+ TRetriableException,
+ "Failed to fetch meta data from tvmtool: ");
+ }
+
+ server.SetGenerator([]() {
+ auto p = new TTvmTool;
+ p->Code = HTTP_NOT_FOUND;
+ return p; });
+ UNIT_ASSERT_EXCEPTION_CONTAINS(m.Fetch(client),
+ TNonRetriableException,
+ "Library does not support so old tvmtool. You need tvmtool>=1.1.0");
+ server.SetGenerator([]() {
+ auto p = new TTvmTool;
+ p->Code = HTTP_INTERNAL_SERVER_ERROR;
+ return p; });
+ UNIT_ASSERT_EXCEPTION_CONTAINS(m.Fetch(client),
+ TRetriableException,
+ "Failed to fetch meta from tvmtool: localhost:");
+ }
+
+ Y_UNIT_TEST(Meta_ParseMetaString_me) {
+ TMetaInfo::TConfigPtr c;
+ UNIT_ASSERT(c = TMetaInfoProxy::ParseMetaString(META, "me"));
+ UNIT_ASSERT_VALUES_EQUAL(100500, c->SelfTvmId);
+ UNIT_ASSERT_EQUAL(EBlackboxEnv::ProdYateam, c->BbEnv);
+ UNIT_ASSERT_EQUAL(TMetaInfo::TDstAliases({{"bbox", 242}, {"pass_likers", 11}}), c->DstAliases);
+ }
+
+ Y_UNIT_TEST(Meta_ParseMetaString_pc) {
+ TMetaInfo::TConfigPtr c;
+ UNIT_ASSERT(c = TMetaInfoProxy::ParseMetaString(META, "push-client"));
+ UNIT_ASSERT_VALUES_EQUAL(100501, c->SelfTvmId);
+ UNIT_ASSERT_EQUAL(EBlackboxEnv::ProdYateam, c->BbEnv);
+ UNIT_ASSERT_EQUAL(TMetaInfo::TDstAliases({{"pass_likers", 100502}}), c->DstAliases);
+ }
+
+ Y_UNIT_TEST(Meta_ParseMetaString_se) {
+ TMetaInfo::TConfigPtr c;
+ UNIT_ASSERT(c = TMetaInfoProxy::ParseMetaString(META, "something_else"));
+ UNIT_ASSERT_VALUES_EQUAL(100503, c->SelfTvmId);
+ UNIT_ASSERT_EQUAL(EBlackboxEnv::ProdYateam, c->BbEnv);
+ UNIT_ASSERT(c->DstAliases.empty());
+ }
+
+ Y_UNIT_TEST(Meta_ParseMetaString_errors) {
+ TMetaInfoProxy m(nullptr);
+ UNIT_ASSERT(!m.ParseMetaString(META, "ololo"));
+
+ TString meta = "}";
+ UNIT_ASSERT_EXCEPTION_CONTAINS(m.ParseMetaString(meta, "qqq"), yexception, meta);
+ meta = "{}";
+ UNIT_ASSERT_EXCEPTION_CONTAINS(m.ParseMetaString(meta, "qqq"), yexception, meta);
+ meta = R"({"tenants" : {}})";
+ UNIT_ASSERT_EXCEPTION_CONTAINS(m.ParseMetaString(meta, "qqq"), yexception, meta);
+ meta = R"({"tenants" : [{"self":{}}]})";
+ UNIT_ASSERT_EXCEPTION_CONTAINS(m.ParseMetaString(meta, "qqq"), yexception, meta);
+ }
+
+ Y_UNIT_TEST(Meta_BbEnvFromString) {
+ UNIT_ASSERT_VALUES_EQUAL(EBlackboxEnv::Prod, TMetaInfoProxy::BbEnvFromString("Prod", META));
+ UNIT_ASSERT_VALUES_EQUAL(EBlackboxEnv::Test, TMetaInfoProxy::BbEnvFromString("Test", META));
+ UNIT_ASSERT_VALUES_EQUAL(EBlackboxEnv::ProdYateam, TMetaInfoProxy::BbEnvFromString("ProdYaTeam", META));
+ UNIT_ASSERT_VALUES_EQUAL(EBlackboxEnv::TestYateam, TMetaInfoProxy::BbEnvFromString("TestYaTeam", META));
+ UNIT_ASSERT_VALUES_EQUAL(EBlackboxEnv::Stress, TMetaInfoProxy::BbEnvFromString("Stress", META));
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TMetaInfoProxy::BbEnvFromString("foo", META),
+ yexception,
+ "'bb_env'=='foo'");
+ }
+
+ Y_UNIT_TEST(Meta_ApplySettings) {
+ NTvmTool::TClientSettings s("foo");
+ s.SetAuthToken(AUTH_TOKEN);
+
+ TMetaInfoProxy m(nullptr);
+ m.ApplySettings(s);
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TKeepAliveHttpClient::THeaders({{"Authorization", AUTH_TOKEN}}),
+ m.GetAuthHeader());
+ }
+
+ Y_UNIT_TEST(Meta_Init) {
+ TPortManager pm;
+ ui16 port = pm.GetPort(80);
+ NMock::TMockServer server(port, []() { return new TTvmTool; });
+ TKeepAliveHttpClient client("localhost", port);
+
+ NTvmTool::TClientSettings s("me");
+ s.SetAuthToken(AUTH_TOKEN);
+ s.SetPort(port);
+ auto l = MakeIntrusive<TLogger>();
+ TMetaInfo m(l);
+ UNIT_ASSERT_NO_EXCEPTION(m.Init(client, s));
+ UNIT_ASSERT_VALUES_EQUAL(100500, m.GetConfig()->SelfTvmId);
+ UNIT_ASSERT_EQUAL(EBlackboxEnv::ProdYateam, m.GetConfig()->BbEnv);
+ UNIT_ASSERT_EQUAL(TMetaInfo::TDstAliases({{"bbox", 242}, {"pass_likers", 11}}), m.GetConfig()->DstAliases);
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuilder()
+ << "7: Meta info fetched from localhost:" << port << "\n"
+ << "6: Meta: self_tvm_id=100500, bb_env=ProdYateam, dsts=[(pass_likers:11)(bbox:242)]\n",
+ l->Stream.Str());
+ l->Stream.Clear();
+ UNIT_ASSERT_VALUES_EQUAL(
+ "/tvm/tickets?src=100500&dsts=11,242",
+ TMetaInfo::GetRequestForTickets(*m.GetConfig()));
+
+ server.SetGenerator([]() {
+ auto p = new TTvmTool;
+ p->Meta = R"({
+ "bb_env" : "Prod",
+ "tenants" : [{
+ "self": {"alias" : "me", "client_id": 100500},
+ "dsts" : [{"alias" : "pass_likers","client_id": 11}]
+ }]
+ })";
+ return p; });
+ UNIT_ASSERT(m.TryUpdateConfig(client));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "6: Meta was updated. Old: (self_tvm_id=100500, bb_env=ProdYateam, dsts=[(pass_likers:11)(bbox:242)]). New: (self_tvm_id=100500, bb_env=Prod, dsts=[(pass_likers:11)])\n",
+ l->Stream.Str());
+ l->Stream.clear();
+
+ s = NTvmTool::TClientSettings("foo");
+ s.SetAuthToken(AUTH_TOKEN);
+ s.SetPort(port);
+ TMetaInfo m2(l);
+ UNIT_ASSERT_EXCEPTION_CONTAINS(m2.Init(client, s), TNonRetriableException, "Alias 'foo' not found in meta info");
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuilder()
+ << "7: Meta info fetched from localhost:" << port << "\n",
+ l->Stream.Str());
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TMetaInfo::GetRequestForTickets({}),
+ yexception,
+ "DstAliases.empty()");
+
+ server.SetGenerator([]() {
+ auto p = new TTvmTool;
+ p->Meta = "}";
+ return p; });
+ UNIT_ASSERT_EXCEPTION_CONTAINS(m.Init(client, s),
+ TNonRetriableException,
+ "Malformed json from tvmtool:");
+ }
+
+ class TNonInitedUpdater: public TThreadedUpdater {
+ public:
+ TNonInitedUpdater(const TString& host, ui16 port, TLoggerPtr logger)
+ : TThreadedUpdater(host, port, TDuration::Seconds(5), TDuration::Seconds(30), logger)
+ {
+ }
+
+ using TThreadedUpdater::ArePublicKeysOk;
+ using TThreadedUpdater::AreServiceTicketsOk;
+ using TThreadedUpdater::FetchPublicKeys;
+ using TThreadedUpdater::FetchServiceTickets;
+ using TThreadedUpdater::GetBirthTimeFromResponse;
+ using TThreadedUpdater::Init;
+ using TThreadedUpdater::IsTimeToUpdatePublicKeys;
+ using TThreadedUpdater::IsTimeToUpdateServiceTickets;
+ using TThreadedUpdater::LastVisitForConfig_;
+ using TThreadedUpdater::MetaInfo_;
+ using TThreadedUpdater::ParseFetchTicketsResponse;
+ using TThreadedUpdater::SetBbEnv;
+ using TThreadedUpdater::SetServiceContext;
+ using TThreadedUpdater::SetServiceTickets;
+ using TThreadedUpdater::SetUpdateTimeOfPublicKeys;
+ using TThreadedUpdater::SetUpdateTimeOfServiceTickets;
+ using TThreadedUpdater::SetUserContext;
+ using TThreadedUpdater::TPairTicketsErrors;
+ using TThreadedUpdater::UpdateKeys;
+ using TThreadedUpdater::UpdateServiceTickets;
+ };
+
+ Y_UNIT_TEST(GetBirthTimeFromResponse) {
+ THttpHeaders h;
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TNonInitedUpdater::GetBirthTimeFromResponse(h, "ololo"),
+ yexception,
+ "Failed to fetch bithtime of ololo from tvmtool");
+
+ h.AddHeader(THttpInputHeader("X-Ya-Tvmtool-Data-Birthtime: qwe"));
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TNonInitedUpdater::GetBirthTimeFromResponse(h, "ololo"),
+ yexception,
+ "Bithtime of ololo from tvmtool must be unixtime. Got: qwe");
+
+ h.AddOrReplaceHeader(THttpInputHeader("X-Ya-Tvmtool-Data-Birthtime: 123"));
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(123), TNonInitedUpdater::GetBirthTimeFromResponse(h, "ololo"));
+ }
+
+ Y_UNIT_TEST(Fetch) {
+ TPortManager pm;
+ ui16 port = pm.GetPort(80);
+ NMock::TMockServer server(port, []() { return new TTvmTool; });
+ TKeepAliveHttpClient client("localhost", port);
+
+ auto l = MakeIntrusive<TLogger>();
+ TNonInitedUpdater u("localhost", port, l);
+ NTvmTool::TClientSettings s("me");
+ s.SetAuthToken(AUTH_TOKEN);
+ s.SetPort(port);
+ u.MetaInfo_.Init(client, s);
+ auto p = u.FetchPublicKeys();
+ UNIT_ASSERT_STRINGS_EQUAL(NUnittest::TVMKNIFE_PUBLIC_KEYS, p.first);
+ UNIT_ASSERT_VALUES_EQUAL(BIRTHTIME, p.second);
+
+ auto p2 = u.FetchServiceTickets(*u.MetaInfo_.GetConfig());
+ UNIT_ASSERT_STRINGS_EQUAL(TICKETS_ME, p2.first);
+ UNIT_ASSERT_VALUES_EQUAL(BIRTHTIME, p2.second);
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "7: Meta info fetched from localhost:" << port << "\n"
+ << "6: Meta: self_tvm_id=100500, bb_env=ProdYateam, dsts=[(pass_likers:11)(bbox:242)]\n",
+ l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(ParseFetchTicketsResponse) {
+ auto l = MakeIntrusive<TLogger>();
+ TNonInitedUpdater u("", 0, l);
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(u.ParseFetchTicketsResponse("}", {}),
+ yexception,
+ "Invalid json from tvmtool: }");
+
+ auto t = u.ParseFetchTicketsResponse(TICKETS_ME, {{"pass_likers", 11}, {"se", 2}});
+ auto expected = TNonInitedUpdater::TPairTicketsErrors{
+ {{11, "3:serv:CBAQ__________9_IgYIlJEGEAs:T-apeMNWFc_vHPQ3iLaZv9NjG-hf5-i23O4AhRu1M68ryN3FU5qvyqTSSiPbtJdFP6EE41QQBzEs59dHn9DRkqQNwwKf1is00Oewwj2XKO0uHukuzd9XxZnro7MfjPswsjWufxX28rmJtlfSXwAtyKt8TI5yKJnMeBPQ0m5R3k8"}},
+ {
+ {2, "Missing tvm_id in response, should never happend: se"},
+ },
+ };
+ UNIT_ASSERT_VALUES_EQUAL(expected, t);
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "3: Failed to get ServiceTicket for se (2): Missing tvm_id in response, should never happend: se\n",
+ l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(Update) {
+ TPortManager pm;
+ ui16 port = pm.GetPort(80);
+ NMock::TMockServer server(port, []() { return new TTvmTool; });
+ TKeepAliveHttpClient client("localhost", port);
+
+ auto l = MakeIntrusive<TLogger>();
+ TNonInitedUpdater u("localhost", port, l);
+ NTvmTool::TClientSettings s("me");
+ s.SetAuthToken(AUTH_TOKEN);
+ s.SetPort(port);
+ u.MetaInfo_.Init(client, s);
+
+ using TTickets = TServiceTickets::TMapAliasStr;
+ UNIT_ASSERT(!u.GetCachedServiceTickets());
+ UNIT_ASSERT_VALUES_EQUAL(BIRTHTIME, u.UpdateServiceTickets(*u.MetaInfo_.GetConfig()));
+ UNIT_ASSERT(u.GetCachedServiceTickets());
+ UNIT_ASSERT_VALUES_EQUAL(TInstant(), u.GetUpdateTimeOfServiceTickets());
+ UNIT_ASSERT_EQUAL(
+ TTickets({
+ {"bbox", "3:serv:CBAQ__________9_IgcIlJEGEPIB:N7luw0_rVmBosTTI130jwDbQd0-cMmqJeEl0ma4ZlIo_mHXjBzpOuMQ3A9YagbmOBOt8TZ_gzGvVSegWZkEeB24gM22acw0w-RcHaQKrzSOA5Zq8WLNIC8QUa4_WGTlAsb7R7eC4KTAGgouIquNAgMBdTuGOuZHnMLvZyLnOMKc"},
+ {"pass_likers", "3:serv:CBAQ__________9_IgYIlJEGEAs:T-apeMNWFc_vHPQ3iLaZv9NjG-hf5-i23O4AhRu1M68ryN3FU5qvyqTSSiPbtJdFP6EE41QQBzEs59dHn9DRkqQNwwKf1is00Oewwj2XKO0uHukuzd9XxZnro7MfjPswsjWufxX28rmJtlfSXwAtyKt8TI5yKJnMeBPQ0m5R3k8"},
+ }),
+ u.GetCachedServiceTickets()->TicketsByAlias);
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "7: Meta info fetched from localhost:" << port << "\n"
+ << "6: Meta: self_tvm_id=100500, bb_env=ProdYateam, dsts=[(pass_likers:11)(bbox:242)]\n",
+ l->Stream.Str());
+ l->Stream.Clear();
+
+ UNIT_ASSERT(!u.GetCachedServiceContext());
+ UNIT_ASSERT(!u.GetCachedUserContext());
+ UNIT_ASSERT_VALUES_EQUAL(BIRTHTIME, u.UpdateKeys(*u.MetaInfo_.GetConfig()));
+ UNIT_ASSERT(u.GetCachedServiceContext());
+ UNIT_ASSERT(!u.GetCachedUserContext());
+ u.SetBbEnv(EBlackboxEnv::Test);
+ UNIT_ASSERT(u.GetCachedUserContext());
+ UNIT_ASSERT_VALUES_EQUAL("", l->Stream.Str());
+ l->Stream.Clear();
+
+ {
+ TAsyncUpdaterPtr u = TThreadedUpdater::Create(s, l);
+ UNIT_ASSERT(u->GetCachedServiceTickets());
+ UNIT_ASSERT(u->GetCachedServiceContext());
+ UNIT_ASSERT(u->GetCachedUserContext());
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u->GetStatus());
+
+ NTvmAuth::TTvmClient c(u);
+ UNIT_ASSERT(c.CheckServiceTicket(SRV_TICKET));
+ UNIT_ASSERT(!c.CheckServiceTicket(SRV_TICKET_DST_100503));
+ UNIT_ASSERT(c.CheckUserTicket(PROD_YATEAM_TICKET));
+ UNIT_ASSERT_VALUES_EQUAL("3:serv:CBAQ__________9_IgYIlJEGEAs:T-apeMNWFc_vHPQ3iLaZv9NjG-hf5-i23O4AhRu1M68ryN3FU5qvyqTSSiPbtJdFP6EE41QQBzEs59dHn9DRkqQNwwKf1is00Oewwj2XKO0uHukuzd9XxZnro7MfjPswsjWufxX28rmJtlfSXwAtyKt8TI5yKJnMeBPQ0m5R3k8", c.GetServiceTicketFor("pass_likers"));
+ }
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "7: Meta info fetched from localhost:" << port << "\n"
+ << "6: Meta: self_tvm_id=100500, bb_env=ProdYateam, dsts=[(pass_likers:11)(bbox:242)]\n"
+ << "7: Tickets fetched from tvmtool: 2425-09-17T11:04:00.000000Z\n"
+ << "7: Public keys fetched from tvmtool: 2425-09-17T11:04:00.000000Z\n"
+ << "7: Thread-worker started\n"
+ << "7: Thread-worker stopped\n",
+ l->Stream.Str());
+ l->Stream.Clear();
+
+ {
+ NTvmTool::TClientSettings s("something_else");
+ s.SetAuthToken(AUTH_TOKEN);
+ s.SetPort(port);
+
+ TAsyncUpdaterPtr u = TThreadedUpdater::Create(s, l);
+ UNIT_ASSERT(!u->GetCachedServiceTickets());
+ UNIT_ASSERT(u->GetCachedServiceContext());
+ UNIT_ASSERT(u->GetCachedUserContext());
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u->GetStatus());
+
+ NTvmAuth::TTvmClient c(u);
+ UNIT_ASSERT(!c.CheckServiceTicket(SRV_TICKET));
+ UNIT_ASSERT(c.CheckServiceTicket(SRV_TICKET_DST_100503));
+ UNIT_ASSERT(c.CheckUserTicket(PROD_YATEAM_TICKET));
+ UNIT_ASSERT_EXCEPTION_CONTAINS(c.GetServiceTicketFor("pass_likers"),
+ TBrokenTvmClientSettings,
+ "Need to enable ServiceTickets fetching");
+ }
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "7: Meta info fetched from localhost:" << port << "\n"
+ << "6: Meta: self_tvm_id=100503, bb_env=ProdYateam, dsts=[]\n"
+ << "7: Public keys fetched from tvmtool: 2425-09-17T11:04:00.000000Z\n"
+ << "7: Thread-worker started\n"
+ << "7: Thread-worker stopped\n",
+ l->Stream.Str());
+ l->Stream.Clear();
+ }
+
+ Y_UNIT_TEST(IsOk) {
+ TNonInitedUpdater u("", 0, TDevNullLogger::IAmBrave());
+ using TTickets = TServiceTickets::TMapIdStr;
+
+ UNIT_ASSERT(u.AreServiceTicketsOk(0));
+ UNIT_ASSERT(!u.AreServiceTicketsOk(2));
+ u.SetServiceTickets(MakeIntrusiveConst<TServiceTickets>(TTickets(),
+ TTickets(),
+ TServiceTickets::TMapAliasId()));
+ UNIT_ASSERT(u.AreServiceTicketsOk(0));
+ UNIT_ASSERT(!u.AreServiceTicketsOk(2));
+ u.SetServiceTickets(MakeIntrusiveConst<TServiceTickets>(
+ TTickets({
+ {1, "mega_ticket"},
+ {2, "mega_ticket2"},
+ }),
+ TTickets({
+ {3, "mega_error3"},
+ }),
+ TServiceTickets::TMapAliasId()));
+ UNIT_ASSERT(u.AreServiceTicketsOk(0));
+ UNIT_ASSERT(!u.AreServiceTicketsOk(2));
+
+ u.SetServiceTickets(MakeIntrusiveConst<TServiceTickets>(
+ TTickets({
+ {1, "mega_ticket"},
+ {2, "mega_ticket2"},
+ }),
+ TTickets({
+ {3, "mega_error3"},
+ }),
+ TServiceTickets::TMapAliasId({
+ {"mega_ticket", 1},
+ {"mega_ticket2", 2},
+ {"mega_ticket3", 3},
+ })));
+ UNIT_ASSERT(u.AreServiceTicketsOk(2));
+
+ UNIT_ASSERT(!u.ArePublicKeysOk());
+ u.SetServiceContext(MakeIntrusiveConst<TServiceContext>(
+ TServiceContext::CheckingFactory(12, NUnittest::TVMKNIFE_PUBLIC_KEYS)));
+ UNIT_ASSERT(!u.ArePublicKeysOk());
+ u.SetUserContext(NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ UNIT_ASSERT(!u.ArePublicKeysOk());
+ u.SetBbEnv(EBlackboxEnv::Test);
+ UNIT_ASSERT(u.ArePublicKeysOk());
+ }
+
+ Y_UNIT_TEST(IsTimeToUpdate) {
+ TNonInitedUpdater u("", 0, TDevNullLogger::IAmBrave());
+
+ UNIT_ASSERT(!u.IsTimeToUpdatePublicKeys(TInstant::Now() - TDuration::Seconds(597)));
+ UNIT_ASSERT(u.IsTimeToUpdatePublicKeys(TInstant::Now() - TDuration::Seconds(603)));
+
+ TMetaInfo::TConfig cfg;
+ UNIT_ASSERT(!u.IsTimeToUpdateServiceTickets(cfg, TInstant::Now() - TDuration::Seconds(597)));
+ UNIT_ASSERT(!u.IsTimeToUpdateServiceTickets(cfg, TInstant::Now() - TDuration::Seconds(603)));
+
+ cfg.DstAliases = {{"q", 1}};
+ UNIT_ASSERT(!u.IsTimeToUpdateServiceTickets(cfg, TInstant::Now() - TDuration::Seconds(597)));
+ UNIT_ASSERT(u.IsTimeToUpdateServiceTickets(cfg, TInstant::Now() - TDuration::Seconds(603)));
+ }
+
+ Y_UNIT_TEST(InitWithOldData) {
+ TPortManager pm;
+ ui16 port = pm.GetPort(80);
+ NMock::TMockServer server(port,
+ []() {
+ auto p = new TTvmTool;
+ p->Birthtime = TInstant::Seconds(123);
+ return p;
+ });
+
+ NTvmTool::TClientSettings s("me");
+ s.SetAuthToken(AUTH_TOKEN);
+ s.SetPort(port);
+
+ auto l = MakeIntrusive<TLogger>();
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TThreadedUpdater::Create(s, l),
+ TRetriableException,
+ "Failed to start TvmClient. You can retry: ");
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "7: Meta info fetched from localhost:" << port << "\n"
+ << "6: Meta: self_tvm_id=100500, bb_env=ProdYateam, dsts=[(pass_likers:11)(bbox:242)]\n"
+ << "4: Error while fetching of tickets: Service tickets are too old: 1970-01-01T00:02:03.000000Z\n"
+ << "3: Service tickets have not been refreshed for too long period\n"
+ << "4: Error while fetching of public keys: Public keys are too old: 1970-01-01T00:02:03.000000Z\n"
+ << "3: Public keys have not been refreshed for too long period\n"
+ << "4: Error while fetching of tickets: Service tickets are too old: 1970-01-01T00:02:03.000000Z\n"
+ << "3: Service tickets have not been refreshed for too long period\n"
+ << "4: Error while fetching of public keys: Public keys are too old: 1970-01-01T00:02:03.000000Z\n"
+ << "3: Public keys have not been refreshed for too long period\n"
+ << "4: Error while fetching of tickets: Service tickets are too old: 1970-01-01T00:02:03.000000Z\n"
+ << "3: Service tickets have not been refreshed for too long period\n"
+ << "4: Error while fetching of public keys: Public keys are too old: 1970-01-01T00:02:03.000000Z\n"
+ << "3: Public keys have not been refreshed for too long period\n",
+ l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(InitWithOldData_onlyKeys) {
+ TPortManager pm;
+ ui16 port = pm.GetPort(80);
+ NMock::TMockServer server(port,
+ []() {
+ auto p = new TTvmTool;
+ p->Birthtime = TInstant::Seconds(123);
+ return p;
+ });
+
+ NTvmTool::TClientSettings s("something_else");
+ s.SetAuthToken(AUTH_TOKEN);
+ s.SetPort(port);
+
+ {
+ s.OverrideBlackboxEnv(EBlackboxEnv::Stress);
+ auto l = MakeIntrusive<TLogger>();
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TThreadedUpdater::Create(s, l),
+ TBrokenTvmClientSettings,
+ "Overriding of BlackboxEnv is illegal: ProdYateam -> Stress");
+ }
+
+ s.OverrideBlackboxEnv(EBlackboxEnv::Prod);
+ auto l = MakeIntrusive<TLogger>();
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TThreadedUpdater::Create(s, l),
+ TRetriableException,
+ "Failed to start TvmClient. You can retry: ");
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "7: Meta info fetched from localhost:" << port << "\n"
+ << "6: Meta: self_tvm_id=100503, bb_env=ProdYateam, dsts=[]\n"
+ << "6: Meta: override blackbox env: ProdYateam->Prod\n"
+ << "4: Error while fetching of public keys: Public keys are too old: 1970-01-01T00:02:03.000000Z\n"
+ << "3: Public keys have not been refreshed for too long period\n"
+ << "4: Error while fetching of public keys: Public keys are too old: 1970-01-01T00:02:03.000000Z\n"
+ << "3: Public keys have not been refreshed for too long period\n"
+ << "4: Error while fetching of public keys: Public keys are too old: 1970-01-01T00:02:03.000000Z\n"
+ << "3: Public keys have not been refreshed for too long period\n",
+ l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(Init) {
+ TPortManager pm;
+ ui16 port = pm.GetPort(80);
+ NMock::TMockServer server(port, []() { return new TTvmTool; });
+
+ NTvmTool::TClientSettings s("push-client");
+ s.SetAuthToken(AUTH_TOKEN);
+ s.SetPort(port);
+ s.SetHostname("localhost");
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TAsyncUpdaterPtr u = TThreadedUpdater::Create(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u->GetStatus());
+ }
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "7: Meta info fetched from localhost:" << port << "\n"
+ << "6: Meta: self_tvm_id=100501, bb_env=ProdYateam, dsts=[(pass_likers:100502)]\n"
+ << "7: Tickets fetched from tvmtool: 2425-09-17T11:04:00.000000Z\n"
+ << "7: Public keys fetched from tvmtool: 2425-09-17T11:04:00.000000Z\n"
+ << "7: Thread-worker started\n"
+ << "7: Thread-worker stopped\n",
+ l->Stream.Str());
+ }
+
+ Y_UNIT_TEST(InitWithoutTvmtool) {
+ NTvmTool::TClientSettings s("me");
+ s.SetAuthToken(AUTH_TOKEN);
+ s.SetPort(0);
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TThreadedUpdater::Create(s, TDevNullLogger::IAmBrave()),
+ TNonRetriableException,
+ "can not connect to ");
+ }
+
+ Y_UNIT_TEST(GetStatus) {
+ TNonInitedUpdater u("", 0, TDevNullLogger::IAmBrave());
+ TMetaInfoProxy m(nullptr);
+ m.Config_ = std::make_shared<TMetaInfo::TConfig>();
+ u.MetaInfo_ = m;
+ u.LastVisitForConfig_ = TInstant::Now();
+
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Error, u.GetStatus());
+ u.SetUpdateTimeOfPublicKeys(TInstant::Now() - TDuration::Days(3));
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Warning, u.GetStatus());
+ u.SetUpdateTimeOfPublicKeys(TInstant::Now() - TDuration::Hours(3));
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u.GetStatus());
+
+ u.SetServiceTickets(new TServiceTickets({}, {}, {}));
+
+ TMetaInfo::TConfig cfg;
+ cfg.DstAliases = {{"q", 1}, {"q2", 2}};
+ m.Config_ = std::make_shared<TMetaInfo::TConfig>(cfg);
+ u.MetaInfo_ = m;
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Error, u.GetStatus());
+ u.SetUpdateTimeOfServiceTickets(TInstant::Now() - TDuration::Hours(3));
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Error, u.GetStatus());
+
+ u.SetServiceTickets(MakeIntrusiveConst<TServiceTickets>(
+ TServiceTickets::TMapIdStr({{1, "3:serv:CBAQ__________9_IgYIKhCUkQY:CX"}, {2, "t"}}),
+ TServiceTickets::TMapIdStr({{3, "mega_error"}, {4, "error2"}}),
+ TServiceTickets::TMapAliasId({
+ {"some_alias#1", 1},
+ {"some_alias#2", 2},
+ })));
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Warning, u.GetStatus());
+
+ const TInstant* inv = &u.GetCachedServiceTickets()->InvalidationTime;
+ *const_cast<TInstant*>(inv) = TInstant::Now() + TDuration::Hours(3);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Warning, u.GetStatus());
+
+ u.SetUpdateTimeOfServiceTickets(TInstant::Now() - TDuration::Minutes(3));
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u.GetStatus());
+
+ u.LastVisitForConfig_ = TInstant::Now() - TDuration::Minutes(1);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Warning, u.GetStatus());
+ }
+
+ Y_UNIT_TEST(multiNamesForDst) {
+ TPortManager pm;
+ ui16 port = pm.GetPort(80);
+ NMock::TMockServer server(port, []() { return new TTvmTool; });
+
+ NTvmTool::TClientSettings s("multi_names_for_dst");
+ s.SetAuthToken(AUTH_TOKEN);
+ s.SetPort(port);
+ s.SetHostname("localhost");
+
+ auto l = MakeIntrusive<TLogger>();
+ {
+ TAsyncUpdaterPtr u = TThreadedUpdater::Create(s, l);
+ UNIT_ASSERT_VALUES_EQUAL(TClientStatus::Ok, u->GetStatus());
+ }
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuilder()
+ << "7: Meta info fetched from localhost:" << port << "\n"
+ << "6: Meta: self_tvm_id=100599, bb_env=ProdYateam, dsts=[(pass_haters:100502)(pass_likers:100502)]\n"
+ << "7: Tickets fetched from tvmtool: 2425-09-17T11:04:00.000000Z\n"
+ << "7: Public keys fetched from tvmtool: 2425-09-17T11:04:00.000000Z\n"
+ << "7: Thread-worker started\n"
+ << "7: Thread-worker stopped\n",
+ l->Stream.Str());
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/utils_ut.cpp b/library/cpp/tvmauth/client/ut/utils_ut.cpp
new file mode 100644
index 0000000000..e780fb2779
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/utils_ut.cpp
@@ -0,0 +1,88 @@
+#include <library/cpp/tvmauth/client/misc/utils.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(UtilsTest) {
+ using namespace NTvmAuth;
+
+ Y_UNIT_TEST(ParseDstMap) {
+ using TMap = NTvmAuth::NTvmApi::TClientSettings::TDstMap;
+ UNIT_ASSERT_EQUAL(TMap(), NUtils::ParseDstMap(""));
+ UNIT_ASSERT_EXCEPTION(NUtils::ParseDstMap(";"), TFromStringException);
+ UNIT_ASSERT_EXCEPTION(NUtils::ParseDstMap(":"), TFromStringException);
+ UNIT_ASSERT_EXCEPTION(NUtils::ParseDstMap("3;"), TFromStringException);
+ UNIT_ASSERT_EXCEPTION(NUtils::ParseDstMap("3:foo;"), TFromStringException);
+
+ UNIT_ASSERT_EQUAL(TMap({
+ {"foo", 3},
+ }),
+ NUtils::ParseDstMap("foo:3"));
+ UNIT_ASSERT_EQUAL(TMap({
+ {"foo", 3},
+ {"bar", 17},
+ }),
+ NUtils::ParseDstMap("foo:3;bar:17;"));
+ }
+
+ Y_UNIT_TEST(ParseDstVector) {
+ using TVector = NTvmAuth::NTvmApi::TClientSettings::TDstVector;
+ UNIT_ASSERT_EQUAL(TVector(), NUtils::ParseDstVector(""));
+ UNIT_ASSERT_EXCEPTION_CONTAINS(NUtils::ParseDstVector(";"),
+ yexception,
+ "Cannot parse empty string as number");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(NUtils::ParseDstVector(":"),
+ yexception,
+ "Unexpected symbol");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(NUtils::ParseDstVector("3:foo;"),
+ yexception,
+ "Unexpected symbol");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(NUtils::ParseDstVector("foo:3;"),
+ yexception,
+ "Unexpected symbol");
+
+ UNIT_ASSERT_EQUAL(TVector(1, 3),
+ NUtils::ParseDstVector("3"));
+ UNIT_ASSERT_EQUAL(TVector({3, 17}),
+ NUtils::ParseDstVector("3;17;"));
+ }
+
+ Y_UNIT_TEST(ToHex) {
+ UNIT_ASSERT_VALUES_EQUAL("", NUtils::ToHex(""));
+ UNIT_ASSERT_VALUES_EQUAL("61", NUtils::ToHex("a"));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "6C6B787A6E7620736C6A6876627761656220",
+ NUtils::ToHex("lkxznv sljhvbwaeb "));
+ }
+
+ Y_UNIT_TEST(CheckBbEnvOverriding) {
+ UNIT_ASSERT(NUtils::CheckBbEnvOverriding(EBlackboxEnv::Prod, EBlackboxEnv::Prod));
+ UNIT_ASSERT(NUtils::CheckBbEnvOverriding(EBlackboxEnv::Prod, EBlackboxEnv::ProdYateam));
+ UNIT_ASSERT(!NUtils::CheckBbEnvOverriding(EBlackboxEnv::Prod, EBlackboxEnv::Test));
+ UNIT_ASSERT(!NUtils::CheckBbEnvOverriding(EBlackboxEnv::Prod, EBlackboxEnv::TestYateam));
+ UNIT_ASSERT(!NUtils::CheckBbEnvOverriding(EBlackboxEnv::Prod, EBlackboxEnv::Stress));
+
+ UNIT_ASSERT(NUtils::CheckBbEnvOverriding(EBlackboxEnv::ProdYateam, EBlackboxEnv::Prod));
+ UNIT_ASSERT(NUtils::CheckBbEnvOverriding(EBlackboxEnv::ProdYateam, EBlackboxEnv::ProdYateam));
+ UNIT_ASSERT(!NUtils::CheckBbEnvOverriding(EBlackboxEnv::ProdYateam, EBlackboxEnv::Test));
+ UNIT_ASSERT(!NUtils::CheckBbEnvOverriding(EBlackboxEnv::ProdYateam, EBlackboxEnv::TestYateam));
+ UNIT_ASSERT(!NUtils::CheckBbEnvOverriding(EBlackboxEnv::ProdYateam, EBlackboxEnv::Stress));
+
+ UNIT_ASSERT(NUtils::CheckBbEnvOverriding(EBlackboxEnv::Test, EBlackboxEnv::Prod));
+ UNIT_ASSERT(NUtils::CheckBbEnvOverriding(EBlackboxEnv::Test, EBlackboxEnv::ProdYateam));
+ UNIT_ASSERT(NUtils::CheckBbEnvOverriding(EBlackboxEnv::Test, EBlackboxEnv::Test));
+ UNIT_ASSERT(NUtils::CheckBbEnvOverriding(EBlackboxEnv::Test, EBlackboxEnv::TestYateam));
+ UNIT_ASSERT(NUtils::CheckBbEnvOverriding(EBlackboxEnv::Test, EBlackboxEnv::Stress));
+
+ UNIT_ASSERT(!NUtils::CheckBbEnvOverriding(EBlackboxEnv::TestYateam, EBlackboxEnv::Prod));
+ UNIT_ASSERT(!NUtils::CheckBbEnvOverriding(EBlackboxEnv::TestYateam, EBlackboxEnv::ProdYateam));
+ UNIT_ASSERT(NUtils::CheckBbEnvOverriding(EBlackboxEnv::TestYateam, EBlackboxEnv::Test));
+ UNIT_ASSERT(NUtils::CheckBbEnvOverriding(EBlackboxEnv::TestYateam, EBlackboxEnv::TestYateam));
+ UNIT_ASSERT(!NUtils::CheckBbEnvOverriding(EBlackboxEnv::TestYateam, EBlackboxEnv::Stress));
+
+ UNIT_ASSERT(!NUtils::CheckBbEnvOverriding(EBlackboxEnv::Stress, EBlackboxEnv::Prod));
+ UNIT_ASSERT(!NUtils::CheckBbEnvOverriding(EBlackboxEnv::Stress, EBlackboxEnv::ProdYateam));
+ UNIT_ASSERT(!NUtils::CheckBbEnvOverriding(EBlackboxEnv::Stress, EBlackboxEnv::Test));
+ UNIT_ASSERT(!NUtils::CheckBbEnvOverriding(EBlackboxEnv::Stress, EBlackboxEnv::TestYateam));
+ UNIT_ASSERT(NUtils::CheckBbEnvOverriding(EBlackboxEnv::Stress, EBlackboxEnv::Stress));
+ }
+}
diff --git a/library/cpp/tvmauth/client/ut/ya.make b/library/cpp/tvmauth/client/ut/ya.make
new file mode 100644
index 0000000000..e2686cd8d7
--- /dev/null
+++ b/library/cpp/tvmauth/client/ut/ya.make
@@ -0,0 +1,36 @@
+UNITTEST_FOR(library/cpp/tvmauth/client)
+
+OWNER(g:passport_infra)
+
+DATA(arcadia/library/cpp/tvmauth/client/ut/files)
+
+PEERDIR(
+ library/cpp/cgiparam
+ library/cpp/testing/mock_server
+)
+
+SRCS(
+ async_updater_ut.cpp
+ checker_ut.cpp
+ client_status_ut.cpp
+ default_uid_checker_ut.cpp
+ disk_cache_ut.cpp
+ exponential_backoff_ut.cpp
+ facade_ut.cpp
+ last_error_ut.cpp
+ logger_ut.cpp
+ roles/decoder_ut.cpp
+ roles/entities_index_ut.cpp
+ roles/parser_ut.cpp
+ roles/roles_ut.cpp
+ roles/tvmapi_roles_fetcher_ut.cpp
+ settings_ut.cpp
+ src_checker_ut.cpp
+ tvmapi_updater_ut.cpp
+ tvmtool_updater_ut.cpp
+ utils_ut.cpp
+)
+
+REQUIREMENTS(ram:11)
+
+END()
diff --git a/library/cpp/tvmauth/client/ya.make b/library/cpp/tvmauth/client/ya.make
new file mode 100644
index 0000000000..8ac4e56e01
--- /dev/null
+++ b/library/cpp/tvmauth/client/ya.make
@@ -0,0 +1,49 @@
+LIBRARY()
+
+OWNER(g:passport_infra)
+
+PEERDIR(
+ library/cpp/http/simple
+ library/cpp/json
+ library/cpp/openssl/crypto
+ library/cpp/streams/brotli
+ library/cpp/streams/zstd
+ library/cpp/string_utils/quote
+ library/cpp/tvmauth
+ library/cpp/tvmauth/client/misc/retry_settings/v1
+)
+
+SRCS(
+ client_status.cpp
+ facade.cpp
+ logger.cpp
+ misc/api/roles_fetcher.cpp
+ misc/api/settings.cpp
+ misc/api/threaded_updater.cpp
+ misc/async_updater.cpp
+ misc/disk_cache.cpp
+ misc/last_error.cpp
+ misc/proc_info.cpp
+ misc/roles/decoder.cpp
+ misc/roles/entities_index.cpp
+ misc/roles/parser.cpp
+ misc/roles/roles.cpp
+ misc/threaded_updater.cpp
+ misc/tool/meta_info.cpp
+ misc/tool/settings.cpp
+ misc/tool/threaded_updater.cpp
+ misc/utils.cpp
+ mocked_updater.cpp
+)
+
+GENERATE_ENUM_SERIALIZATION(client_status.h)
+GENERATE_ENUM_SERIALIZATION(misc/async_updater.h)
+GENERATE_ENUM_SERIALIZATION(misc/last_error.h)
+
+END()
+
+RECURSE_FOR_TESTS(
+ examples
+ misc/api/dynamic_dst
+ ut
+)
diff --git a/library/cpp/tvmauth/deprecated/README.md b/library/cpp/tvmauth/deprecated/README.md
new file mode 100644
index 0000000000..d9ea09c3c0
--- /dev/null
+++ b/library/cpp/tvmauth/deprecated/README.md
@@ -0,0 +1,2 @@
+Please don't use this part of library directly.
+Please use [TTvmClient](https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/tvmauth/README.md) instead.
diff --git a/library/cpp/tvmauth/deprecated/service_context.cpp b/library/cpp/tvmauth/deprecated/service_context.cpp
new file mode 100644
index 0000000000..24822a9d53
--- /dev/null
+++ b/library/cpp/tvmauth/deprecated/service_context.cpp
@@ -0,0 +1,37 @@
+#include <library/cpp/tvmauth/checked_service_ticket.h>
+#include <library/cpp/tvmauth/src/service_impl.h>
+
+namespace NTvmAuth {
+ static const char* EX_MSG = "ServiceContext already moved out";
+
+ TServiceContext::TServiceContext(TStringBuf secretBase64, TTvmId selfTvmId, TStringBuf tvmKeysResponse)
+ : Impl_(MakeHolder<TImpl>(secretBase64, selfTvmId, tvmKeysResponse))
+ {
+ }
+
+ TServiceContext::TServiceContext(TServiceContext&& o) = default;
+ TServiceContext& TServiceContext::operator=(TServiceContext&& o) = default;
+ TServiceContext::~TServiceContext() = default;
+
+ TServiceContext TServiceContext::CheckingFactory(TTvmId selfTvmId, TStringBuf tvmKeysResponse) {
+ TServiceContext c;
+ c.Impl_ = MakeHolder<TImpl>(selfTvmId, tvmKeysResponse);
+ return c;
+ }
+
+ TServiceContext TServiceContext::SigningFactory(TStringBuf secretBase64) {
+ TServiceContext c;
+ c.Impl_ = MakeHolder<TImpl>(secretBase64);
+ return c;
+ }
+
+ TCheckedServiceTicket TServiceContext::Check(TStringBuf ticketBody) const {
+ Y_ENSURE(Impl_, EX_MSG);
+ return Impl_->Check(ticketBody);
+ }
+
+ TString TServiceContext::SignCgiParamsForTvm(TStringBuf ts, TStringBuf dst, TStringBuf scopes) const {
+ Y_ENSURE(Impl_, EX_MSG);
+ return Impl_->SignCgiParamsForTvm(ts, dst, scopes);
+ }
+}
diff --git a/library/cpp/tvmauth/deprecated/service_context.h b/library/cpp/tvmauth/deprecated/service_context.h
new file mode 100644
index 0000000000..bc14d381b2
--- /dev/null
+++ b/library/cpp/tvmauth/deprecated/service_context.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include <library/cpp/tvmauth/checked_service_ticket.h>
+
+#include <util/generic/ptr.h>
+
+namespace NTvmAuth {
+ class TServiceContext: public TAtomicRefCount<TServiceContext> {
+ public:
+ /*!
+ * Create service context. Serivce contexts are used to store TVM keys and parse service tickets.
+ * @param selfTvmId
+ * @param secretBase64
+ * @param tvmKeysResponse
+ */
+ TServiceContext(TStringBuf secretBase64, TTvmId selfTvmId, TStringBuf tvmKeysResponse);
+ TServiceContext(TServiceContext&&);
+ ~TServiceContext();
+
+ /*!
+ * Create service context only for checking service tickets
+ * \param[in] selfTvmId
+ * \param[in] tvmKeysResponse
+ * \return
+ */
+ static TServiceContext CheckingFactory(TTvmId selfTvmId, TStringBuf tvmKeysResponse);
+
+ /*!
+ * Create service context only for signing HTTP request to TVM-API
+ * \param[in] secretBase64
+ * \return
+ */
+ static TServiceContext SigningFactory(TStringBuf secretBase64);
+
+ TServiceContext& operator=(TServiceContext&&);
+
+ /*!
+ * Parse and validate service ticket body then create TCheckedServiceTicket object.
+ * @param ticketBody
+ * @return TCheckedServiceTicket object
+ */
+ TCheckedServiceTicket Check(TStringBuf ticketBody) const;
+
+ /*!
+ * Sign params for TVM API
+ * @param ts Param 'ts' of request to TVM
+ * @param dst Param 'dst' of request to TVM
+ * @param scopes Param 'scopes' of request to TVM
+ * @return Signed string
+ */
+ TString SignCgiParamsForTvm(TStringBuf ts, TStringBuf dst, TStringBuf scopes = TStringBuf()) const;
+
+ class TImpl;
+
+ private:
+ TServiceContext() = default;
+
+ private:
+ THolder<TImpl> Impl_;
+ };
+
+ using TServiceContextPtr = TIntrusiveConstPtr<TServiceContext>;
+}
diff --git a/library/cpp/tvmauth/deprecated/user_context.cpp b/library/cpp/tvmauth/deprecated/user_context.cpp
new file mode 100644
index 0000000000..712f622f1a
--- /dev/null
+++ b/library/cpp/tvmauth/deprecated/user_context.cpp
@@ -0,0 +1,20 @@
+#include <library/cpp/tvmauth/checked_user_ticket.h>
+#include <library/cpp/tvmauth/src/user_impl.h>
+
+namespace NTvmAuth {
+ static const char* EX_MSG = "UserContext already moved out";
+
+ TUserContext::TUserContext(EBlackboxEnv env, TStringBuf tvmKeysResponse)
+ : Impl_(MakeHolder<TImpl>(env, tvmKeysResponse))
+ {
+ }
+
+ TUserContext::TUserContext(TUserContext&& o) = default;
+ TUserContext& TUserContext::operator=(TUserContext&& o) = default;
+ TUserContext::~TUserContext() = default;
+
+ TCheckedUserTicket TUserContext::Check(TStringBuf ticketBody) const {
+ Y_ENSURE(Impl_, EX_MSG);
+ return Impl_->Check(ticketBody);
+ }
+}
diff --git a/library/cpp/tvmauth/deprecated/user_context.h b/library/cpp/tvmauth/deprecated/user_context.h
new file mode 100644
index 0000000000..f7fe67d02e
--- /dev/null
+++ b/library/cpp/tvmauth/deprecated/user_context.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <library/cpp/tvmauth/checked_user_ticket.h>
+
+#include <util/generic/ptr.h>
+
+namespace NTvmAuth {
+ class TUserContext: public TAtomicRefCount<TUserContext> {
+ public:
+ TUserContext(EBlackboxEnv env, TStringBuf tvmKeysResponse);
+ TUserContext(TUserContext&&);
+ ~TUserContext();
+
+ TUserContext& operator=(TUserContext&&);
+
+ /*!
+ * Parse and validate user ticket body then create TCheckedUserTicket object.
+ * @param ticketBody
+ * @return TCheckedUserTicket object
+ */
+ TCheckedUserTicket Check(TStringBuf ticketBody) const;
+
+ class TImpl;
+
+ private:
+ THolder<TImpl> Impl_;
+ };
+
+ using TUserContextPtr = TIntrusiveConstPtr<TUserContext>;
+}
diff --git a/library/cpp/tvmauth/exception.h b/library/cpp/tvmauth/exception.h
new file mode 100644
index 0000000000..f528886b95
--- /dev/null
+++ b/library/cpp/tvmauth/exception.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <util/generic/yexception.h>
+
+#include <exception>
+
+namespace NTvmAuth {
+ class TTvmException: public yexception {
+ };
+ class TContextException: public TTvmException {
+ };
+ class TMalformedTvmSecretException: public TContextException {
+ };
+ class TMalformedTvmKeysException: public TContextException {
+ };
+ class TEmptyTvmKeysException: public TContextException {
+ };
+ class TNotAllowedException: public TTvmException {
+ };
+}
diff --git a/library/cpp/tvmauth/src/parser.cpp b/library/cpp/tvmauth/src/parser.cpp
new file mode 100644
index 0000000000..358de58d36
--- /dev/null
+++ b/library/cpp/tvmauth/src/parser.cpp
@@ -0,0 +1,97 @@
+#include "parser.h"
+
+#include "utils.h"
+
+#include <library/cpp/tvmauth/exception.h>
+
+#include <util/generic/strbuf.h>
+#include <util/string/split.h>
+
+#include <ctime>
+
+namespace NTvmAuth {
+ TString TParserTvmKeys::ParseStrV1(TStringBuf str) {
+ while (str && str.back() == '\n') {
+ str.Chop(1);
+ }
+
+ TStringBuf ver = str.NextTok(DELIM);
+ if (!str || !ver || ver != "1") {
+ throw TMalformedTvmKeysException() << "Malformed TVM keys";
+ }
+ TString res = NUtils::Base64url2bin(str);
+ if (res.empty()) {
+ throw TMalformedTvmKeysException() << "Malformed TVM keys";
+ }
+ return res;
+ }
+
+ TStringBuf TParserTickets::UserFlag() {
+ static const char BUF_[] = "user";
+ return TStringBuf(BUF_, sizeof(BUF_) - 1);
+ }
+
+ TStringBuf TParserTickets::ServiceFlag() {
+ static const char BUF_[] = "serv";
+ return TStringBuf(BUF_, sizeof(BUF_) - 1);
+ }
+
+ TParserTickets::TRes TParserTickets::ParseV3(TStringBuf body, const NRw::TPublicKeys& keys, TStringBuf type) {
+ TStrRes str = ParseStrV3(body, type);
+ TRes res(str.Status);
+ if (str.Status != ETicketStatus::Ok) {
+ return TRes(str.Status);
+ }
+ if (!res.Ticket.ParseFromString(str.Proto)) {
+ res.Status = ETicketStatus::Malformed;
+ return res;
+ }
+ if (res.Ticket.expirationtime() <= time(nullptr)) {
+ res.Status = ETicketStatus::Expired;
+ return res;
+ }
+
+ auto itKey = keys.find(res.Ticket.keyid());
+ if (itKey == keys.end()) {
+ res.Status = ETicketStatus::MissingKey;
+ return res;
+ }
+ if (!itKey->second.CheckSign(str.ForCheck, str.Sign)) {
+ res.Status = ETicketStatus::SignBroken;
+ return res;
+ }
+ return res;
+ }
+
+ TParserTickets::TStrRes TParserTickets::ParseStrV3(TStringBuf body, TStringBuf type) {
+ TStringBuf forCheck = body;
+ TStringBuf version = body.NextTok(DELIM);
+ if (!body || version.size() != 1) {
+ return {ETicketStatus::Malformed, {}, {}, {}};
+ }
+ if (version != "3") {
+ return {ETicketStatus::UnsupportedVersion, {}, {}, {}};
+ }
+
+ TStringBuf ticketType = body.NextTok(DELIM);
+ if (ticketType != type) {
+ return {ETicketStatus::InvalidTicketType, {}, {}, {}};
+ }
+
+ TStringBuf proto = body.NextTok(DELIM);
+ TStringBuf sign = body.NextTok(DELIM);
+
+ if (!proto || !sign || body.size() > 0) {
+ return {ETicketStatus::Malformed, {}, {}, {}};
+ }
+
+ TString protoBin = NUtils::Base64url2bin(proto);
+ TString signBin = NUtils::Base64url2bin(sign);
+
+ if (!protoBin || !signBin) {
+ return {ETicketStatus::Malformed, {}, {}, {}};
+ }
+
+ return {ETicketStatus::Ok, std::move(protoBin), std::move(signBin), forCheck.Chop(sign.size())};
+ }
+}
diff --git a/library/cpp/tvmauth/src/parser.h b/library/cpp/tvmauth/src/parser.h
new file mode 100644
index 0000000000..678e709444
--- /dev/null
+++ b/library/cpp/tvmauth/src/parser.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <library/cpp/tvmauth/src/protos/ticket2.pb.h>
+#include <library/cpp/tvmauth/src/rw/keys.h>
+
+#include <library/cpp/tvmauth/ticket_status.h>
+
+#include <util/generic/fwd.h>
+
+#include <string>
+
+namespace NTvmAuth {
+ struct TParserTvmKeys {
+ static inline const char DELIM = ':';
+ static TString ParseStrV1(TStringBuf str);
+ };
+
+ struct TParserTickets {
+ static const char DELIM = ':';
+
+ static TStringBuf UserFlag();
+ static TStringBuf ServiceFlag();
+
+ struct TRes {
+ TRes(ETicketStatus status)
+ : Status(status)
+ {
+ }
+
+ ETicketStatus Status;
+
+ ticket2::Ticket Ticket;
+ };
+ static TRes ParseV3(TStringBuf body, const NRw::TPublicKeys& keys, TStringBuf type);
+
+ // private:
+ struct TStrRes {
+ const ETicketStatus Status;
+
+ TString Proto;
+ TString Sign;
+
+ TStringBuf ForCheck;
+
+ bool operator==(const TStrRes& o) const { // for tests
+ return Status == o.Status && Proto == o.Proto && Sign == o.Sign && ForCheck == o.ForCheck;
+ }
+ };
+ static TStrRes ParseStrV3(TStringBuf body, TStringBuf type);
+ };
+}
diff --git a/library/cpp/tvmauth/src/protos/ticket2.proto b/library/cpp/tvmauth/src/protos/ticket2.proto
new file mode 100644
index 0000000000..66c00a7d01
--- /dev/null
+++ b/library/cpp/tvmauth/src/protos/ticket2.proto
@@ -0,0 +1,31 @@
+package ticket2;
+
+option go_package = "a.yandex-team.ru/library/cpp/tvmauth/src/protos";
+
+import "library/cpp/tvmauth/src/protos/tvm_keys.proto";
+
+message User {
+ required uint64 uid = 1;
+}
+
+message UserTicket {
+ repeated User users = 1;
+ required uint64 defaultUid = 2;
+ repeated string scopes = 3;
+ required uint32 entryPoint = 4;
+ required tvm_keys.BbEnvType env = 5;
+}
+
+message ServiceTicket {
+ required uint32 srcClientId = 1;
+ required uint32 dstClientId = 2;
+ repeated string scopes = 3;
+ optional uint64 issuerUid = 4;
+}
+
+message Ticket {
+ required uint32 keyId = 1;
+ required int64 expirationTime = 2;
+ optional UserTicket user = 3;
+ optional ServiceTicket service = 4;
+}
diff --git a/library/cpp/tvmauth/src/protos/tvm_keys.proto b/library/cpp/tvmauth/src/protos/tvm_keys.proto
new file mode 100644
index 0000000000..9ba42dbf80
--- /dev/null
+++ b/library/cpp/tvmauth/src/protos/tvm_keys.proto
@@ -0,0 +1,36 @@
+package tvm_keys;
+
+option go_package = "a.yandex-team.ru/library/cpp/tvmauth/src/protos";
+
+enum KeyType {
+ RabinWilliams = 0;
+}
+
+enum BbEnvType {
+ Prod = 0;
+ Test = 1;
+ ProdYateam = 2;
+ TestYateam = 3;
+ Stress = 4;
+}
+
+message General {
+ required uint32 id = 1;
+ required KeyType type = 2;
+ required bytes body = 3;
+ optional int64 createdTime = 4;
+}
+
+message BbKey {
+ required General gen = 1;
+ required BbEnvType env = 2;
+}
+
+message TvmKey {
+ required General gen = 1;
+}
+
+message Keys {
+ repeated BbKey bb = 1;
+ repeated TvmKey tvm = 2;
+}
diff --git a/library/cpp/tvmauth/src/protos/ya.make b/library/cpp/tvmauth/src/protos/ya.make
new file mode 100644
index 0000000000..c2d579dc40
--- /dev/null
+++ b/library/cpp/tvmauth/src/protos/ya.make
@@ -0,0 +1,12 @@
+PROTO_LIBRARY()
+
+OWNER(g:passport_infra)
+
+INCLUDE_TAGS(GO_PROTO)
+
+SRCS(
+ ticket2.proto
+ tvm_keys.proto
+)
+
+END()
diff --git a/library/cpp/tvmauth/src/rw/keys.cpp b/library/cpp/tvmauth/src/rw/keys.cpp
new file mode 100644
index 0000000000..5395287f5c
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/keys.cpp
@@ -0,0 +1,138 @@
+#include "keys.h"
+
+#include "rw.h"
+
+#include <library/cpp/openssl/init/init.h>
+
+#include <contrib/libs/openssl/include/openssl/evp.h>
+
+#include <util/generic/strbuf.h>
+#include <util/generic/yexception.h>
+
+namespace {
+ struct TInit {
+ TInit() {
+ InitOpenSSL();
+ }
+ } INIT;
+}
+
+namespace NTvmAuth {
+ namespace NRw {
+ namespace NPrivate {
+ void TRwDestroyer::Destroy(TRwInternal* o) {
+ RwFree(o);
+ }
+
+ class TArrayDestroyer {
+ public:
+ static void Destroy(unsigned char* o) {
+ free(o);
+ }
+ };
+ }
+
+ static TString SerializeRW(TRwKey* rw, int (*func)(const TRwKey*, unsigned char**)) {
+ unsigned char* buf = nullptr;
+ int size = func(rw, &buf);
+ THolder<unsigned char, NPrivate::TArrayDestroyer> guard(buf);
+ return TString((char*)buf, size);
+ }
+
+ TKeyPair GenKeyPair(size_t size) {
+ TRw rw(RwNew());
+ RwGenerateKey(rw.Get(), size);
+
+ TRw skey(RwPrivateKeyDup(rw.Get()));
+ TRw vkey(RwPublicKeyDup(rw.Get()));
+
+ TKeyPair res;
+ res.Private = SerializeRW(skey.Get(), &i2d_RWPrivateKey);
+ res.Public = SerializeRW(vkey.Get(), &i2d_RWPublicKey);
+
+ TRwPrivateKey prKey(res.Private, 0);
+ TRwPublicKey pubKey(res.Public);
+
+ const TStringBuf msg = "Test test test test test";
+
+ Y_ENSURE(pubKey.CheckSign(msg, prKey.SignTicket(msg)), "Failed to gen keys");
+
+ return res;
+ }
+
+ TRwPrivateKey::TRwPrivateKey(TStringBuf body, TKeyId id)
+ : Id_(id)
+ , Rw_(Deserialize(body))
+ , SignLen_(RwModSize(Rw_.Get()))
+ {
+ Y_ENSURE(SignLen_ > 0, "Private key has bad len: " << SignLen_);
+ }
+
+ TKeyId TRwPrivateKey::GetId() const {
+ return Id_;
+ }
+
+ TString TRwPrivateKey::SignTicket(TStringBuf ticket) const {
+ TString res(SignLen_, 0x00);
+
+ int len = RwPssrSignMsg(ticket.size(),
+ (const unsigned char*)ticket.data(),
+ (unsigned char*)res.data(),
+ Rw_.Get(),
+ (EVP_MD*)EVP_sha256());
+
+ Y_ENSURE(len > 0 && len <= SignLen_, "Signing failed. len: " << len);
+
+ res.resize(len);
+ return res;
+ }
+
+ TRw TRwPrivateKey::Deserialize(TStringBuf key) {
+ TRwKey* rw = nullptr;
+ auto data = reinterpret_cast<const unsigned char*>(key.data());
+ if (!d2i_RWPrivateKey(&rw, &data, key.size())) {
+ ythrow yexception() << "Private key is malformed";
+ }
+ return TRw(rw);
+ }
+
+ TRwPublicKey::TRwPublicKey(TStringBuf body)
+ : Rw_(Deserialize(body))
+ {
+ }
+
+ bool TRwPublicKey::CheckSign(TStringBuf ticket, TStringBuf sign) const {
+ int result = RwPssrVerifyMsg(ticket.size(),
+ (const unsigned char*)ticket.data(),
+ (unsigned char*)sign.data(),
+ sign.size(),
+ Rw_.Get(),
+ (EVP_MD*)EVP_sha256());
+
+ Y_ENSURE(result >= 0, "Failed to check sign: " << result);
+ return result;
+ }
+
+ TRw TRwPublicKey::Deserialize(TStringBuf key) {
+ TRwKey* rw = nullptr;
+ auto data = reinterpret_cast<const unsigned char*>(key.data());
+ auto status = d2i_RWPublicKey(&rw, &data, key.size());
+
+ TRw res(rw);
+ Y_ENSURE(status, "Public key is malformed: " << key);
+ return res;
+ }
+
+ TSecureHeap::TSecureHeap(size_t totalSize, int minChunkSize) {
+ CRYPTO_secure_malloc_init(totalSize, minChunkSize);
+ }
+
+ TSecureHeap::~TSecureHeap() {
+ CRYPTO_secure_malloc_done();
+ }
+
+ void TSecureHeap::Init(size_t totalSize, int minChunkSize) {
+ Singleton<TSecureHeap>(totalSize, minChunkSize);
+ }
+ }
+}
diff --git a/library/cpp/tvmauth/src/rw/keys.h b/library/cpp/tvmauth/src/rw/keys.h
new file mode 100644
index 0000000000..e02b7e72a1
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/keys.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <util/generic/string.h>
+
+#include <unordered_map>
+
+struct TRwInternal;
+
+namespace NTvmAuth {
+ namespace NRw {
+ namespace NPrivate {
+ class TRwDestroyer {
+ public:
+ static void Destroy(TRwInternal* o);
+ };
+ }
+
+ using TRw = THolder<TRwInternal, NPrivate::TRwDestroyer>;
+ using TKeyId = ui32;
+
+ struct TKeyPair {
+ TString Private;
+ TString Public;
+ };
+ TKeyPair GenKeyPair(size_t size);
+
+ class TRwPrivateKey {
+ public:
+ TRwPrivateKey(TStringBuf body, TKeyId id);
+
+ TKeyId GetId() const;
+ TString SignTicket(TStringBuf ticket) const;
+
+ private:
+ static TRw Deserialize(TStringBuf key);
+
+ TKeyId Id_;
+ TRw Rw_;
+ int SignLen_;
+ };
+
+ class TRwPublicKey {
+ public:
+ TRwPublicKey(TStringBuf body);
+
+ bool CheckSign(TStringBuf ticket, TStringBuf sign) const;
+
+ private:
+ static TRw Deserialize(TStringBuf key);
+
+ TRw Rw_;
+ };
+
+ using TPublicKeys = std::unordered_map<TKeyId, TRwPublicKey>;
+
+ class TSecureHeap {
+ public:
+ TSecureHeap(size_t totalSize, int minChunkSize);
+ ~TSecureHeap();
+
+ static void Init(size_t totalSize = 16 * 1024 * 1024, int minChunkSize = 16);
+ };
+ }
+}
diff --git a/library/cpp/tvmauth/src/rw/rw.h b/library/cpp/tvmauth/src/rw/rw.h
new file mode 100644
index 0000000000..cbff96b85d
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/rw.h
@@ -0,0 +1,86 @@
+#pragma once
+
+#include <contrib/libs/openssl/include/openssl/bn.h>
+#include <contrib/libs/openssl/include/openssl/crypto.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ typedef struct {
+ BIGNUM* S;
+ } TRwSignature;
+
+ /*Rabin–Williams*/
+ typedef struct TRwInternal TRwKey;
+
+ typedef struct {
+ TRwSignature* (*RwSign)(const unsigned char* dgst, const int dlen, TRwKey* rw);
+ int (*RwVerify)(const unsigned char* dgst, int dgst_len, TRwSignature* sig, const TRwKey* rw);
+ int (*RwApply)(BIGNUM* r, BIGNUM* x, BN_CTX* ctx, const TRwKey* rw);
+ } TRwMethod;
+
+ struct TRwInternal {
+ /* first private multiplier */
+ BIGNUM* P;
+ /* second private multiplier */
+ BIGNUM* Q;
+ /* n = p*q - RW modulus */
+ BIGNUM* N;
+ /* precomputed 2^((3q-5)/8) mod q */
+ BIGNUM* Twomq;
+ /* precomputed 2^((9p-11)/8) mod p*/
+ BIGNUM* Twomp;
+ /* precomputed q^(p-2) == q^(-1) mod p */
+ BIGNUM* Iqmp;
+ /* (q+1) / 8 */
+ BIGNUM* Dq;
+ /* (p-3) / 8 */
+ BIGNUM* Dp;
+ /* functions for working with RW */
+ const TRwMethod* Meth;
+ };
+
+ TRwSignature* RwSignatureNew(void);
+ void RwSignatureFree(TRwSignature* a);
+
+ /* RW signing functions */
+ /* the function can put some tmp values to rw */
+ int RwPssrSignHash(const unsigned char* from, unsigned char* to, TRwKey* rw, const EVP_MD* md);
+ int RwPssrSignMsg(const int msgLen, const unsigned char* msg, unsigned char* to, TRwKey* rw, const EVP_MD* md);
+
+ /* RW-PSS verification functions */
+ int RwPssrVerifyHash(const unsigned char* from, const unsigned char* sig, const int sig_len, const TRwKey* rw, const EVP_MD* md);
+ int RwPssrVerifyMsg(const int msgLen, const unsigned char* msg, const unsigned char* sig, const int sig_len, const TRwKey* rw, const EVP_MD* md);
+
+ /* internal functions, use them only if you know what you're doing */
+ int RwNoPaddingSign(int flen, const unsigned char* from, unsigned char* to, TRwKey* rw);
+ int RwApply(const int flen, const unsigned char* from, unsigned char* to, const TRwKey* rw);
+
+ const TRwMethod* RwDefaultMethods(void);
+
+ TRwKey* RwNew(void);
+ void RwFree(TRwKey* r);
+ int RwSize(const TRwKey* rw);
+ int RwModSize(const TRwKey* rw);
+
+ TRwKey* RwPublicKeyDup(TRwKey* rw);
+ TRwKey* RwPrivateKeyDup(TRwKey* rw);
+
+ // NOLINTNEXTLINE(readability-identifier-naming)
+ TRwKey* d2i_RWPublicKey(TRwKey** a, const unsigned char** pp, long length);
+ // NOLINTNEXTLINE(readability-identifier-naming)
+ TRwKey* d2i_RWPrivateKey(TRwKey** a, const unsigned char** pp, long length);
+
+ int RwGenerateKey(TRwKey* a, int bits);
+ // NOLINTNEXTLINE(readability-identifier-naming)
+ int i2d_RWPublicKey(const TRwKey* a, unsigned char** pp);
+ // NOLINTNEXTLINE(readability-identifier-naming)
+ int i2d_RWPrivateKey(const TRwKey* a, unsigned char** pp);
+
+ int RwPaddingAddPssr(const TRwKey* rw, unsigned char* EM, const unsigned char* mHash, const EVP_MD* Hash, int sLen);
+ int RwVerifyPssr(const TRwKey* rw, const unsigned char* mHash, const EVP_MD* Hash, const unsigned char* EM, int sLen);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/library/cpp/tvmauth/src/rw/rw_asn1.c b/library/cpp/tvmauth/src/rw/rw_asn1.c
new file mode 100644
index 0000000000..76682dcff4
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/rw_asn1.c
@@ -0,0 +1,81 @@
+#include "rw.h"
+
+#include <contrib/libs/openssl/include/openssl/asn1.h>
+#include <contrib/libs/openssl/include/openssl/asn1t.h>
+#include <contrib/libs/openssl/include/openssl/rand.h>
+
+#include <stdio.h>
+
+/* Override the default new methods */
+/* This callback is used by OpenSSL's ASN.1 parser */
+static int SignatureCallback(int operation, ASN1_VALUE** pval, const ASN1_ITEM* it, void* exarg) {
+ (void)it;
+ (void)exarg;
+
+ if (operation == ASN1_OP_NEW_PRE) {
+ TRwSignature* sig;
+ sig = OPENSSL_malloc(sizeof(TRwSignature));
+ if (!sig)
+ return 0;
+ sig->S = NULL;
+ *pval = (ASN1_VALUE*)sig;
+ return 2;
+ }
+ return 1;
+}
+
+/* ASN.1 structure representing RW signature value */
+ASN1_SEQUENCE_cb(TRwSignature, SignatureCallback) = {
+ ASN1_SIMPLE(TRwSignature, S, BIGNUM),
+} ASN1_SEQUENCE_END_cb(TRwSignature, TRwSignature)
+
+ /* i2d_ and d2i functions implementation for RW */
+ IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(TRwSignature, TRwSignature, TRwSignature)
+
+ /* Override the default free and new methods */
+ static int RwCallback(int operation, ASN1_VALUE** pval, const ASN1_ITEM* it, void* exarg) {
+ (void)it;
+ (void)exarg;
+
+ if (operation == ASN1_OP_NEW_PRE) {
+ *pval = (ASN1_VALUE*)RwNew();
+ if (*pval)
+ return 2;
+ return 0;
+ } else if (operation == ASN1_OP_FREE_PRE) {
+ RwFree((TRwKey*)*pval);
+ *pval = NULL;
+ return 2;
+ }
+ return 1;
+}
+
+/* ASN.1 representation of RW's private key */
+ASN1_SEQUENCE_cb(RWPrivateKey, RwCallback) = {
+ ASN1_SIMPLE(TRwKey, N, BIGNUM),
+ ASN1_SIMPLE(TRwKey, P, CBIGNUM),
+ ASN1_SIMPLE(TRwKey, Q, CBIGNUM),
+ ASN1_SIMPLE(TRwKey, Iqmp, CBIGNUM),
+ ASN1_SIMPLE(TRwKey, Dq, CBIGNUM),
+ ASN1_SIMPLE(TRwKey, Dp, CBIGNUM),
+ ASN1_SIMPLE(TRwKey, Twomp, CBIGNUM),
+ ASN1_SIMPLE(TRwKey, Twomq, CBIGNUM)} ASN1_SEQUENCE_END_cb(TRwKey, RWPrivateKey);
+
+/* i2d_ and d2i_ functions for RW's private key */
+IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(TRwKey, RWPrivateKey, RWPrivateKey);
+
+/* ASN.1 representation of RW public key */
+ASN1_SEQUENCE_cb(RWPublicKey, RwCallback) = {
+ ASN1_SIMPLE(TRwKey, N, BIGNUM),
+} ASN1_SEQUENCE_END_cb(TRwKey, RWPublicKey);
+
+/* i2d_ and d2i functions for RW public key */
+IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(TRwKey, RWPublicKey, RWPublicKey);
+
+TRwKey* RwPublicKeyDup(TRwKey* rw) {
+ return ASN1_item_dup(ASN1_ITEM_rptr(RWPublicKey), rw);
+}
+
+TRwKey* RwPrivateKeyDup(TRwKey* rw) {
+ return ASN1_item_dup(ASN1_ITEM_rptr(RWPrivateKey), rw);
+}
diff --git a/library/cpp/tvmauth/src/rw/rw_key.c b/library/cpp/tvmauth/src/rw/rw_key.c
new file mode 100644
index 0000000000..8375c3ca20
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/rw_key.c
@@ -0,0 +1,135 @@
+#include "rw.h"
+
+#include <contrib/libs/openssl/include/openssl/rand.h>
+
+int RwGenerateKey(TRwKey* rw, int bits) {
+ int ok = 0;
+
+ BN_CTX* ctx = NULL;
+ BIGNUM *rem3 = NULL, *rem7 = NULL, *mod8 = NULL, *rem5 = NULL;
+ BIGNUM *nmod = NULL, *twomqexp = NULL, *twompexp = NULL, *two = NULL;
+
+ int bitsp = (bits + 1) / 2;
+ int bitsq = bits - bitsp;
+
+ /* make sure that all components are not null */
+ if ((ctx = BN_CTX_secure_new()) == NULL)
+ goto err;
+ if (!rw)
+ goto err;
+ if (!rw->N && ((rw->N = BN_new()) == NULL))
+ goto err;
+ if (!rw->P && ((rw->P = BN_new()) == NULL))
+ goto err;
+ if (!rw->Q && ((rw->Q = BN_new()) == NULL))
+ goto err;
+ if (!rw->Iqmp && ((rw->Iqmp = BN_new()) == NULL))
+ goto err;
+ if (!rw->Twomq && ((rw->Twomq = BN_new()) == NULL))
+ goto err;
+ if (!rw->Twomp && ((rw->Twomp = BN_new()) == NULL))
+ goto err;
+ if (!rw->Dq && ((rw->Dq = BN_new()) == NULL))
+ goto err;
+ if (!rw->Dp && ((rw->Dp = BN_new()) == NULL))
+ goto err;
+
+ BN_CTX_start(ctx);
+
+ rem3 = BN_CTX_get(ctx);
+ rem7 = BN_CTX_get(ctx);
+ rem5 = BN_CTX_get(ctx);
+ mod8 = BN_CTX_get(ctx);
+ nmod = BN_CTX_get(ctx);
+ twomqexp = BN_CTX_get(ctx);
+ twompexp = BN_CTX_get(ctx);
+ two = BN_CTX_get(ctx);
+
+ if (!BN_set_word(mod8, 8))
+ goto err;
+ if (!BN_set_word(rem3, 3))
+ goto err;
+ if (!BN_set_word(rem7, 7))
+ goto err;
+ if (!BN_set_word(rem5, 5))
+ goto err;
+ if (!BN_set_word(two, 2))
+ goto err;
+
+ /* generate p */
+ /* add == 8 */
+ /* rem == 3 */
+ /* safe == 0 as we don't need (p-1)/2 to be also prime */
+ if (!BN_generate_prime_ex(rw->P, bitsp, 0, mod8, rem3, NULL))
+ goto err;
+
+ /* generate q */
+ /* add == 8 */
+ /* rem == 7 */
+ /* safe == 0 */
+ if (!BN_generate_prime_ex(rw->Q, bitsq, 0, mod8, rem7, NULL))
+ goto err;
+
+ /* n == p*q */
+ if (!BN_mul(rw->N, rw->P, rw->Q, ctx))
+ goto err;
+
+ /* n == 5 mod 8 ? */
+ if (!BN_nnmod(nmod, rw->N, mod8, ctx))
+ goto err;
+ if (BN_ucmp(rem5, nmod) != 0)
+ goto err;
+
+ /* q^(-1) mod p */
+ if (!BN_mod_inverse(rw->Iqmp, rw->Q, rw->P, ctx))
+ goto err;
+
+ /* twomqexp = (3q-5)/8 */
+ if (!BN_copy(twomqexp, rw->Q))
+ goto err;
+ if (!BN_mul_word(twomqexp, 3))
+ goto err;
+ if (!BN_sub_word(twomqexp, 5))
+ goto err;
+ if (!BN_rshift(twomqexp, twomqexp, 3))
+ goto err;
+ if (!BN_mod_exp(rw->Twomq, two, twomqexp, rw->Q, ctx))
+ goto err;
+
+ /* twompexp = (9p-11)/8 */
+ if (!BN_copy(twompexp, rw->P))
+ goto err;
+ if (!BN_mul_word(twompexp, 9))
+ goto err;
+ if (!BN_sub_word(twompexp, 11))
+ goto err;
+ if (!BN_rshift(twompexp, twompexp, 3))
+ goto err;
+ if (!BN_mod_exp(rw->Twomp, two, twompexp, rw->P, ctx))
+ goto err;
+
+ /* dp = (p-3) / 8 */
+ if (!BN_copy(rw->Dp, rw->P))
+ goto err;
+ if (!BN_sub_word(rw->Dp, 3))
+ goto err;
+ if (!BN_rshift(rw->Dp, rw->Dp, 3))
+ goto err;
+
+ /* dq = (q+1) / 8 */
+ if (!BN_copy(rw->Dq, rw->Q))
+ goto err;
+ if (!BN_add_word(rw->Dq, 1))
+ goto err;
+ if (!BN_rshift(rw->Dq, rw->Dq, 3))
+ goto err;
+
+ ok = 1;
+
+err:
+ if (ctx != NULL) {
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ }
+ return ok;
+}
diff --git a/library/cpp/tvmauth/src/rw/rw_lib.c b/library/cpp/tvmauth/src/rw/rw_lib.c
new file mode 100644
index 0000000000..94d94caa4a
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/rw_lib.c
@@ -0,0 +1,77 @@
+#include "rw.h"
+
+#include <contrib/libs/openssl/include/openssl/asn1.h>
+
+#include <stdio.h>
+
+TRwKey* RwNew(void) {
+ TRwKey* ret = NULL;
+
+ ret = (TRwKey*)malloc(sizeof(TRwKey));
+ if (ret == NULL) {
+ return (NULL);
+ }
+ ret->Meth = RwDefaultMethods();
+
+ ret->P = NULL;
+ ret->Q = NULL;
+ ret->N = NULL;
+ ret->Iqmp = NULL;
+ ret->Twomq = NULL;
+ ret->Twomp = NULL;
+ ret->Dp = NULL;
+ ret->Dq = NULL;
+
+ return ret;
+}
+
+void RwFree(TRwKey* r) {
+ if (r == NULL)
+ return;
+
+ if (r->P != NULL)
+ BN_clear_free(r->P);
+ if (r->Q != NULL)
+ BN_clear_free(r->Q);
+ if (r->N != NULL)
+ BN_clear_free(r->N);
+ if (r->Iqmp != NULL)
+ BN_clear_free(r->Iqmp);
+ if (r->Dp != NULL)
+ BN_clear_free(r->Dp);
+ if (r->Dq != NULL)
+ BN_clear_free(r->Dq);
+ if (r->Twomp != NULL)
+ BN_clear_free(r->Twomp);
+ if (r->Twomq != NULL)
+ BN_clear_free(r->Twomq);
+
+ free(r);
+}
+
+int RwSize(const TRwKey* r) {
+ int ret = 0, i = 0;
+ ASN1_INTEGER bs;
+ unsigned char buf[4]; /* 4 bytes looks really small.
+ However, i2d_ASN1_INTEGER() will not look
+ beyond the first byte, as long as the second
+ parameter is NULL. */
+
+ i = BN_num_bits(r->N);
+ bs.length = (i + 7) / 8;
+ bs.data = buf;
+ bs.type = V_ASN1_INTEGER;
+ /* If the top bit is set the asn1 encoding is 1 larger. */
+ buf[0] = 0xff;
+
+ i = i2d_ASN1_INTEGER(&bs, NULL);
+
+ ret = ASN1_object_size(1, i, V_ASN1_SEQUENCE);
+ return ret;
+}
+
+int RwModSize(const TRwKey* rw) {
+ if (rw == NULL || rw->N == NULL)
+ return 0;
+ return BN_num_bytes(rw->N);
+}
diff --git a/library/cpp/tvmauth/src/rw/rw_ossl.c b/library/cpp/tvmauth/src/rw/rw_ossl.c
new file mode 100644
index 0000000000..951752bdb3
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/rw_ossl.c
@@ -0,0 +1,473 @@
+#include "rw.h"
+
+#include <contrib/libs/openssl/include/openssl/rand.h>
+
+//#define RW_PRINT_DEBUG
+//#define AVOID_IF
+//#define FAULT_TOLERANCE_CHECK
+
+#ifdef RW_PRINT_DEBUG
+ #include <stdio.h>
+#endif
+
+static TRwSignature* RwDoSign(const unsigned char* dgst, int dlen, TRwKey* rw);
+static int RwDoVerify(const unsigned char* dgst, int dgst_len, TRwSignature* sig, const TRwKey* rw);
+static int RwDoApply(BIGNUM* r, BIGNUM* x, BN_CTX* ctx, const TRwKey* rw);
+
+static TRwMethod rw_default_meth = {
+ RwDoSign,
+ RwDoVerify,
+ RwDoApply};
+
+const TRwMethod* RwDefaultMethods(void) {
+ return &rw_default_meth;
+}
+
+#ifdef RW_PRINT_DEBUG
+
+static void print_bn(char* name, BIGNUM* value) {
+ char* str_repr;
+ str_repr = BN_bn2dec(value);
+ printf("Name: %s\n", name);
+ printf("Value: %s\n", str_repr);
+ OPENSSL_free(str_repr);
+}
+
+ #define DEBUG_PRINT_BN(s, x) \
+ do { \
+ print_bn((s), (x)); \
+ } while (0);
+ #define DEBUG_PRINT_RW(r) \
+ do { \
+ DEBUG_PRINT_BN("rw->p", (r)->p); \
+ DEBUG_PRINT_BN("rw->q", (r)->q); \
+ DEBUG_PRINT_BN("rw->n", (r)->n); \
+ DEBUG_PRINT_BN("rw->iqmp", (r)->iqmp); \
+ DEBUG_PRINT_BN("rw->twomp", (r)->twomp); \
+ DEBUG_PRINT_BN("rw->twomq", (r)->twomq); \
+ DEBUG_PRINT_BN("rw->dp", (r)->dp); \
+ DEBUG_PRINT_BN("rw->dq", (r)->dq); \
+ } while (0);
+ #define DEBUG_PRINTF(s, v) \
+ do { \
+ printf((s), (v)); \
+ } while (0);
+#else
+ #define DEBUG_PRINT_BN(s, x)
+ #define DEBUG_PRINT_RW(r)
+ #define DEBUG_PRINTF(s, v)
+#endif
+
+/*
+ * The algorithms was taken from
+ * https://cr.yp.to/sigs/rwsota-20080131.pdf
+ * Section 6 -> "Avoiding Jacobi symbols"
+ * '^' means power
+ * 1. Compute U = h ^ ((q+1) / 8) mod q
+ * 2. If U ^ 4 - h mod q == 0, set e = 1 otherwise set e = -1
+ * 3. Compute V = (eh) ^ ((p-3)/8) mod p
+ * 4. If (V^4 * (eh)^2 - eh) mod p = 0; set f = 1; otherwise set f = 2
+ * 5. Precompute 2^((3q-5) / 8) mod q; Compute W = f^((3*q - 5) / 8) * U mod q
+ * 6. Precompute 2^((9p-11) / 8) mod p; Compute X = f^((9p-11) / 8) * V^3 * eh mod p
+ * 7. Precompute q^(p-2) mod p; Compute Y = W + q(q^(p-2) * (X - W) mod p)
+ * 8. Compute s = Y^2 mod pq
+ * 9. Fault tolerance: if efs^2 mod pq != h start over
+ */
+static TRwSignature* RwDoSign(const unsigned char* dgst, int dlen, TRwKey* rw) {
+ BIGNUM *m, *U, *V, *tmp, *m_q, *m_p, *tmp2;
+ /* additional variables to avoid "if" statements */
+ BIGNUM *tmp_mp, *tmp_U, *tmp_V;
+ TRwSignature* ret = NULL;
+ BN_CTX* ctx = NULL;
+ int ok = 0, e = 0, f = 0;
+
+ if (!rw || !rw->P || !rw->Q || !rw->N || !rw->Iqmp || !rw->Dp || !rw->Dq || !rw->Twomp || !rw->Twomq)
+ goto err;
+
+ if ((ctx = BN_CTX_secure_new()) == NULL)
+ goto err;
+ BN_CTX_start(ctx);
+
+ m = BN_CTX_get(ctx);
+ U = BN_CTX_get(ctx);
+ V = BN_CTX_get(ctx);
+ tmp = BN_CTX_get(ctx);
+ tmp2 = BN_CTX_get(ctx);
+ m_q = BN_CTX_get(ctx);
+ m_p = BN_CTX_get(ctx);
+ tmp_mp = BN_CTX_get(ctx);
+ tmp_U = BN_CTX_get(ctx);
+ tmp_V = BN_CTX_get(ctx);
+
+ DEBUG_PRINT_RW(rw)
+
+ /* if (!BN_set_word(four, 4)) goto err; */
+
+ if (!BN_bin2bn(dgst, dlen, m))
+ goto err;
+ if (BN_ucmp(m, rw->N) >= 0)
+ goto err;
+
+ /* check if m % 16 == 12 */
+ if (BN_mod_word(m, 16) != 12)
+ goto err;
+ DEBUG_PRINT_BN("m", m)
+
+ /* TODO: optimization to avoid memory allocation? */
+ if ((ret = RwSignatureNew()) == NULL)
+ goto err;
+ /* memory allocation */
+ if ((ret->S = BN_new()) == NULL)
+ goto err;
+
+ /* m_q = m mod q */
+ if (!BN_nnmod(m_q, m, rw->Q, ctx))
+ goto err;
+ /* m_p = m mod p */
+ if (!BN_nnmod(m_p, m, rw->P, ctx))
+ goto err;
+
+ DEBUG_PRINT_BN("m_p", m_p)
+ DEBUG_PRINT_BN("m_q", m_q)
+
+ /* U = h ** ((q+1)/8) mod q */
+ if (!BN_mod_exp(U, m_q, rw->Dq, rw->Q, ctx))
+ goto err;
+ DEBUG_PRINT_BN("U", U)
+
+ /* tmp = U^4 - h mod q */
+ if (!BN_mod_sqr(tmp, U, rw->Q, ctx))
+ goto err;
+ if (!BN_mod_sqr(tmp, tmp, rw->Q, ctx))
+ goto err;
+ DEBUG_PRINT_BN("U**4 mod q", tmp)
+
+ /* e = 1 if tmp == 0 else -1 */
+ e = 2 * (BN_ucmp(tmp, m_q) == 0) - 1;
+ DEBUG_PRINTF("e == %i\n", e)
+
+ /*
+ to avoid "if" branch
+ if e == -1: m_p = tmp_mp
+ if e == 1: m_p = m_p
+ */
+ if (!BN_sub(tmp_mp, rw->P, m_p))
+ goto err;
+ m_p = (BIGNUM*)((1 - ((1 + e) >> 1)) * (BN_ULONG)tmp_mp + ((1 + e) >> 1) * (BN_ULONG)m_p);
+ DEBUG_PRINT_BN("eh mod p", m_p)
+
+ /* V = (eh) ** ((p-3)/8) */
+ if (!BN_mod_exp(V, m_p, rw->Dp, rw->P, ctx))
+ goto err;
+ DEBUG_PRINT_BN("V == ((eh) ** ((p-3)/8))", V)
+
+ /* (eh) ** 2 */
+ if (!BN_mod_sqr(tmp2, m_p, rw->P, ctx))
+ goto err;
+ DEBUG_PRINT_BN("(eh)**2", tmp2)
+
+ /* V ** 4 */
+ if (!BN_mod_sqr(tmp, V, rw->P, ctx))
+ goto err;
+ if (!BN_mod_sqr(tmp, tmp, rw->P, ctx))
+ goto err;
+ DEBUG_PRINT_BN("V**4", tmp)
+
+ /* V**4 * (eh)**2 */
+ if (!BN_mod_mul(tmp, tmp, tmp2, rw->P, ctx))
+ goto err;
+ DEBUG_PRINT_BN("tmp = (V**4 * (eh)**2) mod p", tmp)
+
+ /* tmp = tmp - eh mod p */
+ if (!BN_mod_sub(tmp, tmp, m_p, rw->P, ctx))
+ goto err;
+
+ /* f = 1 if zero else 2 */
+ f = 2 - BN_is_zero(tmp);
+ /* f = 2 - (constant_time_is_zero(BN_ucmp(tmp, m_p)) & 1); */
+ DEBUG_PRINTF("f == %i\n", f)
+
+#ifdef AVOID_IF
+ if (!BN_mod_mul(tmp_U, U, rw->twomq, rw->q, ctx))
+ goto err;
+
+ /*
+ to avoid "if" branch we use tiny additional computation
+ */
+ U = (BIGNUM*)((2 - f) * (BN_ULONG)U + (1 - (2 - f)) * (BN_ULONG)tmp_U);
+#else
+
+ if (f == 2) {
+ if (!BN_mod_mul(U, U, rw->Twomq, rw->Q, ctx))
+ goto err;
+ }
+
+#endif
+
+ DEBUG_PRINT_BN("W", U)
+
+ /* V ** 3 */
+ if (!BN_mod_sqr(tmp, V, rw->P, ctx))
+ goto err;
+ if (!BN_mod_mul(V, V, tmp, rw->P, ctx))
+ goto err;
+ DEBUG_PRINT_BN("V**3", V)
+
+ /* *(eh) */
+ if (!BN_mod_mul(V, V, m_p, rw->P, ctx))
+ goto err;
+ DEBUG_PRINT_BN("V**3 * (eh) mod p", V)
+
+#ifdef AVOID_IF
+
+ /* to avoid "if" statement we use simple computation */
+ if (!BN_mod_mul(tmp_V, V, rw->twomp, rw->p, ctx))
+ goto err;
+ V = (BIGNUM*)((2 - f) * (BN_ULONG)V + (1 - (2 - f)) * (BN_ULONG)tmp_V);
+
+#else
+
+ if (f == 2) {
+ if (!BN_mod_mul(V, V, rw->Twomp, rw->P, ctx))
+ goto err;
+ }
+
+#endif
+
+ DEBUG_PRINT_BN("X", V)
+
+ /* W = U, X = V */
+ if (!BN_mod_sub(V, V, U, rw->P, ctx))
+ goto err;
+ DEBUG_PRINT_BN("X - W mod p", V)
+
+ if (!BN_mod_mul(V, V, rw->Iqmp, rw->P, ctx))
+ goto err;
+ DEBUG_PRINT_BN("q**(p-2) * (X-W) mod p", V)
+
+ if (!BN_mul(V, V, rw->Q, ctx))
+ goto err;
+ DEBUG_PRINT_BN("q * prev mod p", V)
+
+ if (!BN_mod_add(V, U, V, rw->N, ctx))
+ goto err;
+ DEBUG_PRINT_BN("Y", V)
+
+ /* now V = Y */
+ if (!BN_mod_sqr(V, V, rw->N, ctx))
+ goto err;
+ DEBUG_PRINT_BN("s", V)
+
+#ifdef FAULT_TOLERANCE_CHECK
+
+ /* now V = s - principal square root */
+ /* fault tolerance check */
+ if (!BN_mod_sqr(tmp, V, rw->n, ctx))
+ goto err;
+ DEBUG_PRINT_BN("s**2", tmp)
+
+ if (!BN_mul_word(tmp, f))
+ goto err;
+ DEBUG_PRINT_BN("f * s**2", tmp)
+
+ if (!BN_nnmod(tmp, tmp, rw->n, ctx))
+ goto err;
+ DEBUG_PRINT_BN("s**2 * f mod n", tmp)
+
+ /* to avoid "if" statement */
+ if (!BN_sub(tmp2, rw->n, tmp))
+ goto err;
+ tmp = (BIGNUM*)(((1 + e) >> 1) * (BN_ULONG)tmp + (1 - ((1 + e) >> 1)) * (BN_ULONG)tmp2);
+ DEBUG_PRINT_BN("ef(s**2)", tmp)
+ DEBUG_PRINT_BN("(tmp == original m)", tmp)
+
+ if (BN_ucmp(tmp, m) != 0)
+ goto err;
+
+#endif
+
+ /* making the "principal square root" to be "|principal| square root" */
+ if (!BN_sub(tmp, rw->N, V))
+ goto err;
+
+ /* if tmp = MIN(V, rw->n - V) */
+ tmp = BN_ucmp(tmp, V) >= 0 ? V : tmp;
+
+ if (!BN_copy(ret->S, tmp))
+ goto err;
+
+ ok = 1;
+
+err:
+ if (ctx != NULL) {
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ }
+ if (!ok) {
+ RwSignatureFree(ret);
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+static int RwDoVerify(const unsigned char* dgst, int dgst_len, TRwSignature* sig, const TRwKey* rw) {
+ BIGNUM *m = NULL, *x = NULL, *t1 = NULL, *t2 = NULL, *t1d = NULL, *t2d = NULL;
+ BN_CTX* ctx = NULL;
+ BN_ULONG rest1 = 0, rest2 = 0;
+ int retval = 0;
+
+ if (!rw || !rw->N || !sig || !sig->S)
+ goto err;
+
+ if ((ctx = BN_CTX_secure_new()) == NULL)
+ goto err;
+ BN_CTX_start(ctx);
+
+ m = BN_CTX_get(ctx);
+ t1 = BN_CTX_get(ctx);
+ t2 = BN_CTX_get(ctx);
+ t1d = BN_CTX_get(ctx);
+ t2d = BN_CTX_get(ctx);
+
+ if (!BN_bin2bn(dgst, dgst_len, m))
+ goto err;
+ /* dgst too big */
+ if (!BN_copy(t1, rw->N))
+ goto err;
+ if (!BN_sub_word(t1, 1))
+ goto err;
+ if (!BN_rshift(t1, t1, 1))
+ goto err;
+
+ /* check m and rw->n relation */
+ if (BN_ucmp(m, rw->N) >= 0)
+ goto err;
+ rest1 = BN_mod_word(m, 16);
+ if (rest1 != 12)
+ goto err;
+
+ if (BN_ucmp(t1, sig->S) < 0)
+ goto err;
+ if (BN_is_negative(sig->S))
+ goto err;
+
+ if (!BN_mod_sqr(t1, sig->S, rw->N, ctx))
+ goto err;
+ if (!BN_sub(t2, rw->N, t1))
+ goto err;
+ if (!BN_lshift1(t1d, t1))
+ goto err;
+ if (!BN_lshift1(t2d, t2))
+ goto err;
+
+ rest1 = BN_mod_word(t1, 16);
+ rest2 = BN_mod_word(t2, 16);
+
+ /* mod 16 */
+ if (rest1 == 12) {
+ x = t1;
+ }
+ /* mod 8 */
+ else if ((rest1 & 0x07) == 6) {
+ x = t1d;
+ }
+ /* mod 16 */
+ else if (rest2 == 12) {
+ x = t2;
+ }
+ /* mod 8 */
+ else if ((rest2 & 0x07) == 6) {
+ x = t2d;
+ } else
+ goto err;
+
+ DEBUG_PRINT_BN("m", m)
+ DEBUG_PRINT_BN("x", x)
+
+ /* check signature value */
+ retval = BN_ucmp(m, x) == 0;
+
+err:
+ if (ctx != NULL) {
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ }
+ return retval;
+}
+
+static int RwDoApply(BIGNUM* r, BIGNUM* x, BN_CTX* ctx, const TRwKey* rw) {
+ BIGNUM *t1 = NULL, *t2 = NULL, *t1d = NULL, *t2d = NULL, *rs = NULL;
+ BN_ULONG rest1 = 0, rest2 = 0;
+ int retval = 0;
+
+ if (!rw || !rw->N || !x || !ctx || !r)
+ goto err;
+
+ DEBUG_PRINT_BN("Signature = x = ", x)
+ DEBUG_PRINT_BN("n", rw->n)
+
+ BN_CTX_start(ctx);
+
+ t1 = BN_CTX_get(ctx);
+ t2 = BN_CTX_get(ctx);
+ t1d = BN_CTX_get(ctx);
+ t2d = BN_CTX_get(ctx);
+
+ if (!BN_copy(t1, rw->N))
+ goto err;
+ if (!BN_sub_word(t1, 1))
+ goto err;
+ if (!BN_rshift(t1, t1, 1))
+ goto err;
+
+ /* check m and rw->n relation */
+ if (BN_ucmp(x, rw->N) >= 0)
+ goto err;
+
+ if (BN_ucmp(t1, x) < 0)
+ goto err;
+ if (BN_is_negative(x))
+ goto err;
+
+ if (!BN_mod_sqr(t1, x, rw->N, ctx))
+ goto err;
+ DEBUG_PRINT_BN("x**2 mod n", t1)
+
+ if (!BN_sub(t2, rw->N, t1))
+ goto err;
+ DEBUG_PRINT_BN("n - x**2", t2)
+
+ if (!BN_lshift1(t1d, t1))
+ goto err;
+ if (!BN_lshift1(t2d, t2))
+ goto err;
+
+ rest1 = BN_mod_word(t1, 16);
+ rest2 = BN_mod_word(t2, 16);
+
+ /* mod 16 */
+ if (rest1 == 12) {
+ rs = t1;
+ }
+ /* mod 8 */
+ else if ((rest1 & 0x07) == 6) {
+ rs = t1d;
+ }
+ /* mod 16 */
+ else if (rest2 == 12) {
+ rs = t2;
+ }
+ /* mod 8 */
+ else if ((rest2 & 0x07) == 6) {
+ rs = t2d;
+ } else
+ goto err;
+
+ DEBUG_PRINT_BN("Squaring and shifting result (rs)", rs)
+ retval = BN_copy(r, rs) != NULL;
+
+err:
+ BN_CTX_end(ctx);
+ return retval;
+}
diff --git a/library/cpp/tvmauth/src/rw/rw_pss.c b/library/cpp/tvmauth/src/rw/rw_pss.c
new file mode 100644
index 0000000000..3bf6e2b99a
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/rw_pss.c
@@ -0,0 +1,328 @@
+/*
+ * This code was taken from the OpenSSL's RSA implementation
+ * and added to the RW project with some changes
+ *
+ * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2005.
+ *
+ */
+/* ====================================================================
+ * Copyright (c) 2005 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED 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 OpenSSL PROJECT OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include "rw.h"
+
+#include <contrib/libs/openssl/include/openssl/bn.h>
+#include <contrib/libs/openssl/include/openssl/evp.h>
+#include <contrib/libs/openssl/include/openssl/rand.h>
+#include <contrib/libs/openssl/include/openssl/sha.h>
+
+#include <stdio.h>
+#include <string.h>
+
+static const unsigned char zeroes[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+static int PkcS1MgF1(unsigned char *mask, const int len, const unsigned char *seed, const int seedlen, const EVP_MD *dgst) {
+ int i, outlen = 0;
+ unsigned char cnt[4];
+ EVP_MD_CTX* c = EVP_MD_CTX_create();
+ unsigned char md[EVP_MAX_MD_SIZE];
+ int mdlen;
+ int rv = -1;
+
+ if (!c) {
+ return rv;
+ }
+
+ mdlen = EVP_MD_size(dgst);
+
+ if (mdlen < 0 || seedlen < 0)
+ goto err;
+
+ for (i = 0; outlen < len; i++) {
+ cnt[0] = (unsigned char)((i >> 24) & 255);
+ cnt[1] = (unsigned char)((i >> 16) & 255);
+ cnt[2] = (unsigned char)((i >> 8)) & 255;
+ cnt[3] = (unsigned char)(i & 255);
+
+ if (!EVP_DigestInit_ex(c,dgst, NULL) || !EVP_DigestUpdate(c, seed, seedlen) || !EVP_DigestUpdate(c, cnt, 4))
+ goto err;
+
+ if (outlen + mdlen <= len) {
+ if (!EVP_DigestFinal_ex(c, mask + outlen, NULL))
+ goto err;
+ outlen += mdlen;
+ } else {
+ if (!EVP_DigestFinal_ex(c, md, NULL))
+ goto err;
+ memcpy(mask + outlen, md, len - outlen);
+ outlen = len;
+ }
+ }
+ rv = 0;
+
+err:
+ EVP_MD_CTX_destroy(c);
+ return rv;
+}
+
+int RwVerifyPssr(const TRwKey *rw, const unsigned char *mHash, const EVP_MD *Hash, const unsigned char *EM, int sLen) {
+ int i = 0, ret = 0, hLen = 0, maskedDBLen = 0, MSBits = 0, emLen = 0;
+ const unsigned char *H = NULL;
+ unsigned char *DB = NULL;
+ EVP_MD_CTX* ctx = NULL;
+ unsigned char H_[EVP_MAX_MD_SIZE];
+ const EVP_MD *mgf1Hash = Hash;
+
+ ctx = EVP_MD_CTX_create();
+ if (!ctx) {
+ return ret;
+ }
+ hLen = EVP_MD_size(Hash);
+
+ if (hLen < 0)
+ goto err;
+ /*
+ * Negative sLen has special meanings:
+ * -1 sLen == hLen
+ * -2 salt length is autorecovered from signature
+ * -N reserved
+ */
+ if (sLen == -1)
+ sLen = hLen;
+ else if (sLen < -2)
+ goto err;
+
+ {
+ int bits = BN_num_bits(rw->N);
+ if (bits <= 0)
+ goto err;
+
+ MSBits = (bits - 1) & 0x7;
+ }
+ emLen = RwModSize(rw);
+
+ if (EM[0] & (0xFF << MSBits)) {
+ goto err;
+ }
+
+ if (MSBits == 0) {
+ EM++;
+ emLen--;
+ }
+
+ if (emLen < (hLen + sLen + 2)) /* sLen can be small negative */
+ goto err;
+
+ if (emLen < 1)
+ goto err;
+
+ if (EM[emLen - 1] != 0xbc)
+ goto err;
+
+ maskedDBLen = emLen - hLen - 1;
+ if (maskedDBLen <= 0)
+ goto err;
+
+ H = EM + maskedDBLen;
+ DB = malloc(maskedDBLen);
+
+ if (!DB)
+ goto err;
+
+ if (PkcS1MgF1(DB, maskedDBLen, H, hLen, mgf1Hash) < 0)
+ goto err;
+
+ for (i = 0; i < maskedDBLen; i++)
+ DB[i] ^= EM[i];
+
+ if (MSBits)
+ DB[0] &= 0xFF >> (8 - MSBits);
+
+ for (i = 0; DB[i] == 0 && i < (maskedDBLen-1); i++) ;
+
+ if (DB[i++] != 0x1)
+ goto err;
+
+ if (sLen >= 0 && (maskedDBLen - i) != sLen)
+ goto err;
+
+ if (!EVP_DigestInit_ex(ctx, Hash, NULL) || !EVP_DigestUpdate(ctx, zeroes, sizeof zeroes) || !EVP_DigestUpdate(ctx, mHash, hLen))
+ goto err;
+
+ if (maskedDBLen - i) {
+ if (!EVP_DigestUpdate(ctx, DB + i, maskedDBLen - i))
+ goto err;
+ }
+
+ if (!EVP_DigestFinal_ex(ctx, H_, NULL))
+ goto err;
+
+ ret = memcmp(H, H_, hLen) ? 0 : 1;
+
+err:
+ if (DB)
+ free(DB);
+
+ EVP_MD_CTX_destroy(ctx);
+
+ return ret;
+}
+
+/*
+ rw - public key
+ EM - buffer to write padding value
+ mHash - hash value
+ Hash - EVP_MD() that will be used to pad
+ sLen - random salt len (usually == hashLen)
+ */
+int RwPaddingAddPssr(const TRwKey *rw, unsigned char *EM, const unsigned char *mHash, const EVP_MD *Hash, int sLen) {
+ int i = 0, ret = 0, hLen = 0, maskedDBLen = 0, MSBits = 0, emLen = 0;
+ unsigned char *H = NULL, *salt = NULL, *p = NULL;
+ const EVP_MD *mgf1Hash = Hash;
+ EVP_MD_CTX* ctx = EVP_MD_CTX_create();
+ if (!ctx) {
+ return ret;
+ }
+
+ hLen = EVP_MD_size(Hash);
+ if (hLen < 0)
+ goto err;
+ /*
+ * Negative sLen has special meanings:
+ * -1 sLen == hLen
+ * -2 salt length is maximized
+ * -N reserved
+ */
+ if (sLen == -1)
+ sLen = hLen;
+ else if (sLen < -2)
+ goto err;
+
+ {
+ int bits = BN_num_bits(rw->N);
+ if (bits <= 0)
+ goto err;
+ MSBits = (bits - 1) & 0x7;
+ }
+ emLen = RwModSize(rw);
+ if (emLen <= 0)
+ goto err;
+
+ if (MSBits == 0) {
+ *EM++ = 0;
+ emLen--;
+ fprintf(stderr, "MSBits == 0\n");
+ }
+
+ if (sLen == -2) {
+ sLen = emLen - hLen - 2;
+ }
+ else if (emLen < (hLen + sLen + 2))
+ goto err;
+
+ if (sLen > 0) {
+ salt = malloc(sLen);
+ if (!salt) goto err;
+ if (RAND_bytes(salt, sLen) <= 0)
+ goto err;
+ }
+
+ maskedDBLen = emLen - hLen - 1;
+ if (maskedDBLen < 0)
+ goto err;
+ H = EM + maskedDBLen;
+
+ if (!EVP_DigestInit_ex(ctx, Hash, NULL) || !EVP_DigestUpdate(ctx, zeroes, sizeof zeroes) || !EVP_DigestUpdate(ctx, mHash, hLen))
+ goto err;
+
+ if (sLen && !EVP_DigestUpdate(ctx, salt, sLen))
+ goto err;
+
+ if (!EVP_DigestFinal_ex(ctx, H, NULL))
+ goto err;
+
+ /* Generate dbMask in place then perform XOR on it */
+ if (PkcS1MgF1(EM, maskedDBLen, H, hLen, mgf1Hash))
+ goto err;
+
+ p = EM;
+
+ /* Initial PS XORs with all zeroes which is a NOP so just update
+ * pointer. Note from a test above this value is guaranteed to
+ * be non-negative.
+ */
+ p += emLen - sLen - hLen - 2;
+ *p++ ^= 0x1;
+
+ if (sLen > 0) {
+ for (i = 0; i < sLen; i++)
+ *p++ ^= salt[i];
+ }
+
+ if (MSBits)
+ EM[0] &= 0xFF >> (8 - MSBits);
+
+ /* H is already in place so just set final 0xbc */
+ EM[emLen - 1] = 0xbc;
+
+ ret = 1;
+
+err:
+ EVP_MD_CTX_destroy(ctx);
+
+ if (salt)
+ free(salt);
+
+ return ret;
+}
diff --git a/library/cpp/tvmauth/src/rw/rw_pss_sign.c b/library/cpp/tvmauth/src/rw/rw_pss_sign.c
new file mode 100644
index 0000000000..59897f1cf5
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/rw_pss_sign.c
@@ -0,0 +1,211 @@
+#include "rw.h"
+
+#include <contrib/libs/openssl/include/openssl/evp.h>
+
+//#define DBG_FUZZING
+
+int RwApply(const int flen, const unsigned char* from, unsigned char* to, const TRwKey* rw) {
+ int i, j, num, k, r = -1;
+ BN_CTX* ctx = NULL;
+ BIGNUM *f = NULL, *ret = NULL;
+
+ if ((ctx = BN_CTX_secure_new()) == NULL)
+ goto err;
+ BN_CTX_start(ctx);
+
+ f = BN_CTX_get(ctx);
+ ret = BN_CTX_get(ctx);
+
+ num = BN_num_bytes(rw->N);
+
+ if (num <= 0)
+ goto err;
+
+ if (!f || !ret)
+ goto err;
+
+ if (BN_bin2bn(from, flen, f) == NULL)
+ goto err;
+ if (BN_ucmp(f, rw->N) >= 0)
+ goto err;
+
+ if (!rw->Meth->RwApply(ret, f, ctx, rw))
+ goto err;
+
+ j = BN_num_bytes(ret);
+ if (num < j || j < 0)
+ goto err;
+
+ i = BN_bn2bin(ret, to + num - j);
+ if (i < 0 || i > num)
+ goto err;
+
+ for (k = 0; k < (num - i); k++)
+ to[k] = 0;
+ r = num;
+
+err:
+ if (ctx != NULL) {
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ }
+ return r;
+}
+
+int RwPssrSignHash(const unsigned char* from, unsigned char* to, TRwKey* rw, const EVP_MD* md) {
+ unsigned char* padding = NULL;
+ int result = 0;
+
+ if (from == NULL || to == NULL || rw == NULL || md == NULL)
+ return 0;
+
+ int digest_size = EVP_MD_size(md);
+ int sig_size = RwModSize(rw);
+
+ if (digest_size <= 0 || sig_size <= 0)
+ return 0;
+
+ int tries = 50;
+ do {
+ if (padding != NULL) {
+ free(padding);
+#ifdef DBG_FUZZING
+ fprintf(stderr, "Padding regenerating required\n");
+#endif
+ }
+
+ padding = malloc(sig_size);
+ if (padding == NULL)
+ return 0;
+
+ if (!RwPaddingAddPssr(rw, padding, from, md, digest_size))
+ goto err;
+ } while (padding[0] == 0x00 && tries-- > 0);
+
+ result = RwNoPaddingSign(sig_size, padding, to, rw);
+
+err:
+ if (padding != NULL)
+ free(padding);
+
+ return result;
+}
+
+int RwPssrSignMsg(const int msgLen, const unsigned char* msg, unsigned char* to, TRwKey* rw, const EVP_MD* md) {
+ EVP_MD_CTX* mdctx = NULL;
+ unsigned char* digest = NULL;
+ unsigned int digestLen;
+ int result = 0;
+
+ if (msg == NULL || to == NULL || rw == NULL || md == NULL)
+ goto err;
+
+ if (rw->P == NULL || rw->Q == NULL)
+ goto err;
+
+ if ((mdctx = EVP_MD_CTX_create()) == NULL)
+ goto err;
+
+ if (1 != EVP_DigestInit_ex(mdctx, md, NULL))
+ goto err;
+
+ if (1 != EVP_DigestUpdate(mdctx, msg, msgLen))
+ goto err;
+
+ if ((digest = (unsigned char*)malloc(EVP_MD_size(md))) == NULL)
+ goto err;
+
+ if (1 != EVP_DigestFinal_ex(mdctx, digest, &digestLen))
+ goto err;
+
+ result = RwPssrSignHash(digest, to, rw, md);
+
+err:
+ if (mdctx != NULL)
+ EVP_MD_CTX_destroy(mdctx);
+ if (digest != NULL)
+ free(digest);
+
+ return result;
+}
+
+int RwPssrVerifyHash(const unsigned char* from, const unsigned char* sig, const int sig_len, const TRwKey* rw, const EVP_MD* md) {
+ unsigned char* buffer = NULL;
+ int buffer_len;
+ int salt_size;
+ int result = 0;
+
+ if (from == NULL || sig == NULL || rw == NULL || md == NULL)
+ return 0;
+
+ if (rw->N == NULL || rw->Meth == NULL)
+ return 0;
+
+ salt_size = EVP_MD_size(md);
+ if (salt_size <= 0)
+ return 0;
+
+ buffer_len = RwModSize(rw);
+ if (buffer_len <= 0)
+ return 0;
+
+ buffer = (unsigned char*)malloc(buffer_len);
+ if (buffer == NULL)
+ return 0;
+
+ if (RwApply(sig_len, sig, buffer, rw) <= 0)
+ goto err;
+
+ if (RwVerifyPssr(rw, from, md, buffer, salt_size) <= 0)
+ goto err;
+
+ result = 1;
+
+err:
+ if (buffer != NULL)
+ free(buffer);
+
+ return result;
+}
+
+int RwPssrVerifyMsg(const int msgLen, const unsigned char* msg, const unsigned char* sig, const int sig_len, const TRwKey* rw, const EVP_MD* md) {
+ EVP_MD_CTX* mdctx = NULL;
+ unsigned char* digest = NULL;
+ unsigned int digestLen = 0;
+ int result = 0;
+
+ if (msg == NULL || msgLen == 0 || sig == NULL || rw == NULL || md == NULL)
+ goto err;
+
+ if (rw->N == NULL)
+ goto err;
+
+ if ((mdctx = EVP_MD_CTX_create()) == NULL)
+ goto err;
+
+ if (1 != EVP_DigestInit_ex(mdctx, md, NULL))
+ goto err;
+
+ int size_to_alloc = EVP_MD_size(md);
+ if (size_to_alloc <= 0)
+ goto err;
+
+ if ((digest = (unsigned char*)malloc(size_to_alloc)) == NULL)
+ goto err;
+
+ if (1 != EVP_DigestUpdate(mdctx, msg, msgLen))
+ goto err;
+
+ if (1 != EVP_DigestFinal_ex(mdctx, digest, &digestLen))
+ goto err;
+
+ result = RwPssrVerifyHash(digest, sig, sig_len, rw, md);
+
+err:
+ if (mdctx != NULL)
+ EVP_MD_CTX_destroy(mdctx);
+ if (digest != NULL)
+ free(digest);
+
+ return result;
+}
diff --git a/library/cpp/tvmauth/src/rw/rw_sign.c b/library/cpp/tvmauth/src/rw/rw_sign.c
new file mode 100644
index 0000000000..e320808dd3
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/rw_sign.c
@@ -0,0 +1,46 @@
+#include "rw.h"
+
+TRwSignature* RwSignatureNew(void) {
+ TRwSignature* sig = NULL;
+ sig = malloc(sizeof(TRwSignature));
+ if (!sig)
+ return NULL;
+ sig->S = NULL;
+ return sig;
+}
+
+void RwSignatureFree(TRwSignature* sig) {
+ if (sig) {
+ if (sig->S)
+ BN_free(sig->S);
+ free(sig);
+ }
+}
+
+int RwNoPaddingSign(int flen, const unsigned char* from, unsigned char* to, TRwKey* rw) {
+ int i = 0, r = 0, num = -1;
+ TRwSignature* sig = NULL;
+
+ if (!rw || !rw->N || !rw->Meth || !rw->Meth->RwSign || !from || !to)
+ goto err;
+
+ if ((sig = rw->Meth->RwSign(from, flen, rw)) == NULL)
+ goto err;
+ num = BN_num_bytes(rw->N);
+
+ r = BN_bn2bin(sig->S, to);
+ if (r < 0)
+ goto err;
+
+ /* put zeroes to the rest of the 'to' buffer */
+ for (i = r; i < num; i++) {
+ to[i] = 0x00;
+ }
+
+err:
+ if (sig != NULL) {
+ RwSignatureFree(sig);
+ }
+
+ return r;
+}
diff --git a/library/cpp/tvmauth/src/rw/ut/rw_ut.cpp b/library/cpp/tvmauth/src/rw/ut/rw_ut.cpp
new file mode 100644
index 0000000000..73f1b1d769
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/ut/rw_ut.cpp
@@ -0,0 +1,200 @@
+#include <library/cpp/tvmauth/src/rw/keys.h>
+#include <library/cpp/tvmauth/src/rw/rw.h>
+
+#include <library/cpp/string_utils/base64/base64.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <contrib/libs/openssl/include/openssl/bn.h>
+#include <contrib/libs/openssl/include/openssl/evp.h>
+
+namespace NTvmAuth {
+ /*
+ returns 0 in case of error
+ */
+ int MakeKeysRw(TRwKey** skey, TRwKey** vkey) {
+ int result = 0;
+
+ TRwKey* rw = RwNew();
+
+ do {
+ RwGenerateKey(rw, 2048);
+
+ if (rw == nullptr) {
+ printf("RwGenerateKey failed\n");
+ break; /* failed */
+ }
+
+ printf("RW key bits: %d\n", BN_num_bits(rw->N));
+
+ /* Set signing key */
+ *skey = RwPrivateKeyDup(rw);
+ if (*skey == nullptr) {
+ printf("RwPrivateKeyDup failed\n");
+ break;
+ }
+
+ /* Set verifier key */
+ *vkey = RwPublicKeyDup(rw);
+ if (*vkey == nullptr) {
+ printf("RwPublicKeyDup failed\n");
+ break;
+ }
+
+ result = 1;
+
+ } while (0);
+
+ if (rw) {
+ RwFree(rw);
+ rw = nullptr;
+ }
+
+ return result;
+ }
+
+ static void PrintIt(const char* label, const unsigned char* buff, size_t len) {
+ if (!buff || !len)
+ return;
+
+ if (label)
+ printf("%s: ", label);
+
+ for (size_t i = 0; i < len; ++i)
+ printf("%02X", buff[i]);
+
+ printf("\n");
+ }
+
+ int TestSignVerify() {
+ TRwKey *skey = nullptr, *vkey = nullptr;
+ const char* msg = "Test test test test test";
+ unsigned int msg_len = 0;
+ int res = 0;
+
+ msg_len = (unsigned int)strlen(msg);
+ if (MakeKeysRw(&skey, &vkey)) {
+ unsigned char* sign = new unsigned char[RwModSize(skey) + 10];
+ int sign_len;
+ printf("RwModSize(skey) returned %d\n", RwModSize(skey));
+ memset(sign, 0x00, RwModSize(skey) + 10);
+
+ printf("--- Signing call ---\n");
+ if ((sign_len = RwPssrSignMsg(msg_len, (unsigned char*)msg, sign, skey, (EVP_MD*)EVP_sha256())) != 0) {
+#ifdef RW_PRINT_DEBUG
+ BIGNUM* s = BN_new();
+#endif
+ printf("\n");
+ PrintIt("Signature", sign, RwModSize(skey));
+
+#ifdef RW_PRINT_DEBUG
+ BN_bin2bn(sign, RW_mod_size(skey), s);
+
+ print_bn("Signature BN", s);
+
+ BN_free(s);
+#endif
+
+ printf("--- Verification call ---\n");
+ if (RwPssrVerifyMsg(msg_len, (unsigned char*)msg, sign, sign_len, vkey, (EVP_MD*)EVP_sha256())) {
+ printf("Verification: success!\n");
+ res = 1;
+ } else {
+ printf("Verification: failed!\n");
+ printf("RwPssrVerifyMsg failed!\n");
+ return 1;
+ }
+ } else {
+ printf("RwPssrSignMsg failed!\n");
+ return 1;
+ }
+
+ if (sign != nullptr)
+ delete[] sign;
+
+ } else {
+ printf("MakeKeysRw failed!\n");
+ return 1;
+ }
+
+ if (skey != nullptr) {
+ RwFree(skey);
+ }
+ if (vkey != nullptr)
+ RwFree(vkey);
+
+ return res;
+ }
+}
+
+using namespace NTvmAuth;
+Y_UNIT_TEST_SUITE(Rw) {
+ Y_UNIT_TEST(SignVerify) {
+ for (int i = 1; i < 10; ++i) {
+ UNIT_ASSERT_VALUES_EQUAL(1, TestSignVerify());
+ }
+ }
+
+ Y_UNIT_TEST(TKeysPriv) {
+ NRw::TRwPrivateKey priv(Base64Decode("MIIEmwKCAQBwsRd4frsVARIVSfj_vCdfvA3Q9SsGhSybdBDhbm8L6rPqxdoSNLCdNXzDWj7Ppf0o8uWHMxC-5Lfw0I18ri68nhm9-ndixcnbn6ti1uetgkc28eiEP6Q8ILD_JmkynbUl1aKDNAa5XsK2vFSEX402uydRomsTn46kRY23hfqcIi0ohh5VxIrpclRsRZus0JFu-RJzhqTbKYV4y4dglWPGHh5BuTv9k_Oh0_Ra8Xp5Rith5vjaKZUQ5Hyh9UtBYTkNWdvXP9OpmbiLVeRLuMzBm4HEFHDwMZ1h6LSVP-wB_spJPaMLTn3Q3JIHe-wGBYRWzU51RRYDqv4O_H12w5C1AoGBALAwCQ7fdAPG1lGclL7iWFjUofwPCFwPyDjicDT_MRRu6_Ta4GjqOGO9zuOp0o_ePgvR-7nA0fbaspM4LZNrPZwmoYBCJMtKXetg68ylu2DO-RRSN2SSh1AIZSA_8UTABk69bPzNL31j4PyZWxrgZ3zP9uZvzggveuKt5ZhCMoB7AoGBAKO9oC2AZjLdh2RaEFotTL_dY6lVcm38VA6PnigB8gB_TMuSrd4xtRw5BxvHpOCnBcUAJE0dN4_DDe5mrotKYMD2_3_lcq9PaLZadrPDCSDL89wtoVxNQNAJTqFjBFXYNu4Ze63lrsqg45TF5XmVRemyBHzXw3erd0pJaeoUDaSPAoGAJhGoHx_nVw8sDoLzeRkOJ1_6-uh_wVmVr6407_LPjrrySEq-GiYu43M3-QDp8J_J9e3S1Rpm4nQX2bEf5Gx9n4wKz7Hp0cwkOqBOWhvrAu6YLpv59wslEtkx0LYcJy6yQk5mpU8l29rPO7b50NyLnfnE2za-9DyK038FKlr5VgICgYAUd7QFsAzGW7Dsi0ILRamX-6x1Kq5Nv4qB0fPFAD5AD-mZclW7xjajhyDjePScFOC4oASJo6bx-GG9zNXRaUwYHt_v_K5V6e0Wy07WeGEkGX57hbQriagaASnULGCKuwbdwy91vLXZVBxymLyvMqi9NkCPmvhu9W7pSS09QoG0kgKBgBYGASHb7oB42sozkpfcSwsalD-B4QuB-QccTgaf5iKN3X6bXA0dRwx3udx1OlH7x8F6P3c4Gj7bVlJnBbJtZ7OE1DAIRJlpS71sHXmUt2wZ3yKKRuySUOoBDKQH_iiYAMnXrZ-Zpe-sfB-TK2NcDO-Z_tzN-cEF71xVvLMIRlAPAoGAdeikZPh1O57RxnVY72asiMRZheMBhK-9uSNPyYEZv3bUnIjg4XdMYStF2yTHNu014XvkDSQTe-drv2BDs9ExKplM4xFOtDtPQQ3mMB3GoK1qVhM_9n1QEElreurMicahkalnPo6tU4Z6PFL7PTpjRnCN67lJp0J0fxNDL13YSagCgYBA9VJrMtPjzcAx5ZCIYJjrYUPqEG_ttQN2RJIHN3MVpdpLAMIgX3tnlfyLwQFVKK45D1JgFa_1HHcxTWGtdIX4nsIjPWt-cWCCCkkw9rM5_Iqcb-YLSood6IP2OK0w0XLD1STnFRy_BRwdjPbGOYmp6YrJDZAlajDkFSdRvsz9Vg=="),
+ 0);
+ NRw::TRwPrivateKey priv2(Base64Decode("MIIEnAKCAQEA4RATOfumLD1n6ICrW5biaAl9VldinczmkNPjpUWwc3gs8PnkCrtdnPFmpBwW3gjHdSNU1OuEg5A6K1o1xiGv9sU-jd88zQBOdK6E2zwnJnkK6bNusKE2H2CLqg3aMWCmTa9JbzSy1uO7wa-xCqqNUuCko-2lyv12HhL1ICIH951SHDa4qO1U5xZhhlUAnqWi9R4tYDeMiF41WdOjwT2fg8UkbusThmxa3yjCXjD7OyjshPtukN8Tl3UyGtV_s2CLnE3f28VAi-AVW8FtgL22xbGhuyEplXRrtF1E5oV7NSqxH1FS0SYROA8ffYQGV5tfx5WDFHiXDEP6BzoVfeBDRQKBgQDzidelKZNFMWar_yj-r_cniMkZXNaNVEQbMg1A401blGjkU1r-ufGH5mkdNx4IgEoCEYBTM834Z88fYV1lOVfdT0OqtiVoC9NkLu3xhQ1r9_r6RMaAenwsV7leH8jWMOKvhkB0KNI49oznTGDqLp0AbDbtP66xdNH4dr3rw3WFywKBgQDslDdv4sdnRKN27h2drhn4Pp_Lgw2U-6MfHiyjp6BKR8Qtlld3hdb-ZjU9F0h38DqECmFIEe35_flKfd7X21CBQs9EuKR8EdaF3OAgzA-TRWeQhyHmaV7Fas1RlNqZHm8lckaZT8dX9Ygsxn0I_vUbm9pkFivwGvQnnwNQ7Te5LwKBgCVMYOzLHW911l6EbCZE6XU2HUrTKEd1bdqWCgtxPEmDl3BZcXpnyKpqSHmlH1F7s65WBfejxDM2hjin3OnXSog_x35ql_-Azu93-79QAzbQc6Z13BuWPpQxV8iw4ijqRRhzjD2pcvXlIxgebp5-H0eDt-Md2Y8rkrzyhm8EH7mwAoGAHZKG7fxY7OiUbt3Ds7XDPwfT-XBhsp90Y-PFlHT0CUj4hbLK7vC638zGp6LpDv4HUIFMKQI9vz-_KU-72vtqEChZ6JcUj4I60LucBBmB8mis8hDkPM0r2K1ZqjKbUyPN5K5I0yn46v6xBZjPoR_eo3N7TILFfgNehPPgah2m9yYCgYAecTr0pTJopizVf-Uf1f7k8RkjK5rRqoiDZkGoHGmrco0cimtf1z4w_M0jpuPBEAlAQjAKZnm_DPnj7Cuspyr7qeh1VsStAXpshd2-MKGtfv9fSJjQD0-Fivcrw_kaxhxV8MgOhRpHHtGc6YwdRdOgDYbdp_XWLpo_Dte9eG6wuQKBgDzo0e8d8pTyvCP23825rVzvrSHBZkliGkCEu0iggDnfKOreejFhQN9JeBo8sYdQFCRBptEU6k4b5O6J3NQ1Sspiez15ddqmFMD4uhJY6VsV-JFnL9YhLqVd355xZCyU4b07mReU9-LuqK2m2chjxH_HDAgUoEvO_yzR9EDYqHbNAoGAf529Ah9HIT5aG6IGTlwQdk-M7guy63U4vj4uC7z98qgvFEsV6cr4miT6RE8Aw5yAeN5pW59rZNjBNr9i-8n8kouasho2xNMTPKP8YuSNg2PNNS5T1Ou56mgsBCY5i10TIHKNIm2RVSUgzJ97BMEOZY6jQRytFfwgYkvnFzbuA9c="),
+ 0);
+ NRw::TRwPrivateKey priv3(Base64Decode("MIICVAKBgF9t2YJGAJkRRFq6fWhi3m1TFW1UOE0f6ZrfYhHAkpqGlKlh0QVfeTNPpeJhi75xXzCe6oReRUm-0DbqDNhTShC7uGUv1INYnRBQWH6E-5Fc5XrbDFSuGQw2EYjNfHy_HefHJXxQKAqPvxBDKMKkHgV58WtM6rC8jRi9sdX_ig2NAkEAg1xBDL_UkHy347HwioMscJFP-6eKeim3LoG9rd1EvOycxkoStZ4299OdyzzEXC9cjLdq401BXe-LairiMUgZawJBALn5ziBCc2ycMaYjZDon2EN55jBEe0tJdUy4mOi0ozTV9OLcBANds0nMYPjZFOY3QymzU0LcOa_An3JknI0C2ucCQGxtwTb3h7ux5Ld8jkeRYzkNoB2Y6Is5fqCYVRIJZmz0IcQFb2iW0EX92U7_BpgVuKlvSDTP9LuaxuPfmY6WXEECQBc_OcQITm2ThjTEbIdE-whvPMYIj2lpLqmXEx0WlGaavpxbgIBrtmk5jB8bIpzG6GU2amhbhzX4E-5Mk5GgW10CQBBriCGX-pIPlvx2PhFQZY4SKf908U9FNuXQN7W7qJedk5jJQlazxt76c7lnmIuF65GW7VxpqCu98W1FXEYpAy0CQG-lpihdvxaZ8SkHqNFZGnXhELT2YesLs7GehZSTwuUwx1iTpVm88PVROLYBDZqoGM316s9aZEJBALe5zEpxQTQCQQCDMszX1cQlbBCP08isuMQ2ac3S-qNd0mfRXDCRfMm4s7iuJ5MeHU3uPUVlA_MR4ULRbg1d97TGio912z4KPgjE"),
+ 0);
+
+ UNIT_ASSERT_EXCEPTION(NRw::TRwPrivateKey("asdzxcv", 0), yexception);
+ UNIT_ASSERT_EXCEPTION(NRw::TRwPrivateKey(Base64Decode("AKBgF9t2YJGAJkRRFq6fWhi3m1TFW1UOE0f6ZrfYhHAkpqGlKlh0QVfeTNPpeJhi75xXzCe6oReRUm-0DbqDNhTShC7uGUv1INYnRBQWH6E-5Fc5XrbDFSuGQw2EYjNfHy_HefHJXxQKAqPvxBDKMKkHgV58WtM6rC8jRi9sdX_ig2NAkEAg1xBDL_UkHy347HwioMscJFP-6eKeim3LoG9rd1EvOycxkoStZ4299OdyzzEXC9cjLdq401BXe-LairiMUgZawJBALn5ziBCc2ycMaYjZDon2EN55jBEe0tJdUy4mOi0ozTV9OLcBANds0nMYPjZFOY3QymzU0LcOa_An3JknI0C2ucCQGxtwTb3h7ux5Ld8jkeRYzkNoB2Y6Is5fqCYVRIJZmz0IcQFb2iW0EX92U7_BpgVuKlvSDTP9LuaxuPfmY6WXEECQBc_OcQITm2ThjTEbIdE-whvPMYIj2lpLqmXEx0WlGaavpxbgIBrtmk5jB8bIpzG6GU2amhbhzX4E-5Mk5GgW10CQBBriCGX-pIPlvx2PhFQZY4SKf908U9FNuXQN7W7qJedk5jJQlazxt76c7lnmIuF65GW7VxpqCu98W1FXEYpAy0CQG-lpihdvxaZ8SkHqNFZGnXhELT2YesLs7GehZSTwuUwx1iTpVm88PVROLYBDZqoGM316s9aZEJBALe5zEpxQTQCQQCDMszX1cQlbBCP08isuMQ2ac3S-qNd0mfRXDCRfMm4s7iuJ5MeHU3uPUVlA_MR4ULRbg1d97TGio912z4KP"),
+ 0),
+ yexception);
+
+ UNIT_ASSERT(!priv.SignTicket("").empty());
+ }
+
+ Y_UNIT_TEST(TKeysPub) {
+ NRw::TRwPublicKey pub(Base64Decode("MIIBBAKCAQBwsRd4frsVARIVSfj_vCdfvA3Q9SsGhSybdBDhbm8L6rPqxdoSNLCdNXzDWj7Ppf0o8uWHMxC-5Lfw0I18ri68nhm9-ndixcnbn6ti1uetgkc28eiEP6Q8ILD_JmkynbUl1aKDNAa5XsK2vFSEX402uydRomsTn46kRY23hfqcIi0ohh5VxIrpclRsRZus0JFu-RJzhqTbKYV4y4dglWPGHh5BuTv9k_Oh0_Ra8Xp5Rith5vjaKZUQ5Hyh9UtBYTkNWdvXP9OpmbiLVeRLuMzBm4HEFHDwMZ1h6LSVP-wB_spJPaMLTn3Q3JIHe-wGBYRWzU51RRYDqv4O_H12w5C1"));
+ NRw::TRwPublicKey pub2(Base64Decode("MIIBBQKCAQEA4RATOfumLD1n6ICrW5biaAl9VldinczmkNPjpUWwc3gs8PnkCrtdnPFmpBwW3gjHdSNU1OuEg5A6K1o1xiGv9sU-jd88zQBOdK6E2zwnJnkK6bNusKE2H2CLqg3aMWCmTa9JbzSy1uO7wa-xCqqNUuCko-2lyv12HhL1ICIH951SHDa4qO1U5xZhhlUAnqWi9R4tYDeMiF41WdOjwT2fg8UkbusThmxa3yjCXjD7OyjshPtukN8Tl3UyGtV_s2CLnE3f28VAi-AVW8FtgL22xbGhuyEplXRrtF1E5oV7NSqxH1FS0SYROA8ffYQGV5tfx5WDFHiXDEP6BzoVfeBDRQ=="));
+ NRw::TRwPublicKey pub3(Base64Decode("MIGDAoGAX23ZgkYAmRFEWrp9aGLebVMVbVQ4TR_pmt9iEcCSmoaUqWHRBV95M0-l4mGLvnFfMJ7qhF5FSb7QNuoM2FNKELu4ZS_Ug1idEFBYfoT7kVzletsMVK4ZDDYRiM18fL8d58clfFAoCo-_EEMowqQeBXnxa0zqsLyNGL2x1f-KDY0="));
+
+ UNIT_ASSERT_EXCEPTION(NRw::TRwPublicKey("asdzxcv"), yexception);
+ UNIT_ASSERT_EXCEPTION(NRw::TRwPublicKey(Base64Decode("AoGAX23ZgkYAmRFEWrp9aGLebVMVbVQ4TR_pmt9iEcCSmoaUqWHRBV95M0-l4mGLvnFfMJ7qhF5FSb7QNuoM2FNKELu4ZS_Ug1idEFBYfoT7kVzletsMVK40")), yexception);
+
+ UNIT_ASSERT(!pub.CheckSign("~~~", "~~~"));
+ }
+
+ Y_UNIT_TEST(TKeys) {
+ NRw::TRwPrivateKey priv(Base64Decode("MIIEmwKCAQBwsRd4frsVARIVSfj_vCdfvA3Q9SsGhSybdBDhbm8L6rPqxdoSNLCdNXzDWj7Ppf0o8uWHMxC-5Lfw0I18ri68nhm9-ndixcnbn6ti1uetgkc28eiEP6Q8ILD_JmkynbUl1aKDNAa5XsK2vFSEX402uydRomsTn46kRY23hfqcIi0ohh5VxIrpclRsRZus0JFu-RJzhqTbKYV4y4dglWPGHh5BuTv9k_Oh0_Ra8Xp5Rith5vjaKZUQ5Hyh9UtBYTkNWdvXP9OpmbiLVeRLuMzBm4HEFHDwMZ1h6LSVP-wB_spJPaMLTn3Q3JIHe-wGBYRWzU51RRYDqv4O_H12w5C1AoGBALAwCQ7fdAPG1lGclL7iWFjUofwPCFwPyDjicDT_MRRu6_Ta4GjqOGO9zuOp0o_ePgvR-7nA0fbaspM4LZNrPZwmoYBCJMtKXetg68ylu2DO-RRSN2SSh1AIZSA_8UTABk69bPzNL31j4PyZWxrgZ3zP9uZvzggveuKt5ZhCMoB7AoGBAKO9oC2AZjLdh2RaEFotTL_dY6lVcm38VA6PnigB8gB_TMuSrd4xtRw5BxvHpOCnBcUAJE0dN4_DDe5mrotKYMD2_3_lcq9PaLZadrPDCSDL89wtoVxNQNAJTqFjBFXYNu4Ze63lrsqg45TF5XmVRemyBHzXw3erd0pJaeoUDaSPAoGAJhGoHx_nVw8sDoLzeRkOJ1_6-uh_wVmVr6407_LPjrrySEq-GiYu43M3-QDp8J_J9e3S1Rpm4nQX2bEf5Gx9n4wKz7Hp0cwkOqBOWhvrAu6YLpv59wslEtkx0LYcJy6yQk5mpU8l29rPO7b50NyLnfnE2za-9DyK038FKlr5VgICgYAUd7QFsAzGW7Dsi0ILRamX-6x1Kq5Nv4qB0fPFAD5AD-mZclW7xjajhyDjePScFOC4oASJo6bx-GG9zNXRaUwYHt_v_K5V6e0Wy07WeGEkGX57hbQriagaASnULGCKuwbdwy91vLXZVBxymLyvMqi9NkCPmvhu9W7pSS09QoG0kgKBgBYGASHb7oB42sozkpfcSwsalD-B4QuB-QccTgaf5iKN3X6bXA0dRwx3udx1OlH7x8F6P3c4Gj7bVlJnBbJtZ7OE1DAIRJlpS71sHXmUt2wZ3yKKRuySUOoBDKQH_iiYAMnXrZ-Zpe-sfB-TK2NcDO-Z_tzN-cEF71xVvLMIRlAPAoGAdeikZPh1O57RxnVY72asiMRZheMBhK-9uSNPyYEZv3bUnIjg4XdMYStF2yTHNu014XvkDSQTe-drv2BDs9ExKplM4xFOtDtPQQ3mMB3GoK1qVhM_9n1QEElreurMicahkalnPo6tU4Z6PFL7PTpjRnCN67lJp0J0fxNDL13YSagCgYBA9VJrMtPjzcAx5ZCIYJjrYUPqEG_ttQN2RJIHN3MVpdpLAMIgX3tnlfyLwQFVKK45D1JgFa_1HHcxTWGtdIX4nsIjPWt-cWCCCkkw9rM5_Iqcb-YLSood6IP2OK0w0XLD1STnFRy_BRwdjPbGOYmp6YrJDZAlajDkFSdRvsz9Vg=="),
+ 0);
+ NRw::TRwPublicKey pub(Base64Decode("MIIBBAKCAQBwsRd4frsVARIVSfj_vCdfvA3Q9SsGhSybdBDhbm8L6rPqxdoSNLCdNXzDWj7Ppf0o8uWHMxC-5Lfw0I18ri68nhm9-ndixcnbn6ti1uetgkc28eiEP6Q8ILD_JmkynbUl1aKDNAa5XsK2vFSEX402uydRomsTn46kRY23hfqcIi0ohh5VxIrpclRsRZus0JFu-RJzhqTbKYV4y4dglWPGHh5BuTv9k_Oh0_Ra8Xp5Rith5vjaKZUQ5Hyh9UtBYTkNWdvXP9OpmbiLVeRLuMzBm4HEFHDwMZ1h6LSVP-wB_spJPaMLTn3Q3JIHe-wGBYRWzU51RRYDqv4O_H12w5C1"));
+
+ const TString data = "my magic data";
+
+ UNIT_ASSERT(pub.CheckSign(data, priv.SignTicket(data)));
+ UNIT_ASSERT(!pub.CheckSign("~~~~" + data, priv.SignTicket(data)));
+ UNIT_ASSERT(!pub.CheckSign(data, "~~~~" + priv.SignTicket(data)));
+
+ UNIT_ASSERT(pub.CheckSign(data,
+ Base64Decode("EC5hZunmK3hOJZeov_XlNIXcwj5EsgX94lMd-tQJTNUO4NR6bCO7qQkKjEeFJmI2QFYXGY-iSf9WeMJ_brECAMyYAix-L8sZqcMPXD945QgkPsNQKyC0DX9FkgfSh6ZKkA-UvFSHrkn3QbeE9omk3-yXpqR-M8DlVqmp3mwdYlYRq0NdfTaD3AMXVA4aZTbW3OmhJoLJ8AxJ3w1oG5q_lk8dpW9vvqfIzsfPABme6sY5XyPmsjYaRDf9z4ZJgR-wTkG06_N_YzIklS5T2s_4FUKLz5gLMhsnVlNUpgZyRN9sXTAn9-zMJnCwAC8WRgykWnljPGDDJCjk-Xwsg7AOLQ==")));
+ UNIT_ASSERT(pub.CheckSign(data,
+ Base64Decode("JbHSn1QEQeOEvzyt-LpawbQv4vPEEE05bWhjB2-MkoV-tyq9FykSqGqhP3ZFc1_FPrqguwEYrHibI2l5w3q8wnI1fcyRUoNuJxmBSzf2f_Uzn9ZoUSc7D9pTGSvK_hhZoL4YMc_VfbdEdnDuvHZNlZyaDPH9EbmUqyXjnXTEwRoK0fAU1rhlHvSZvnp0ctVBWSkaQsaU8dJTKDBtIQVP1D5Py2pKB2NBF_Ytz2thWt7iLjbTyjtis6DC-JKwjFBqv6nQf42sKalHQqWFuIvBCIfNUswEw4_sGfwWVSBBmFplf7FmD7sN8znUahYUPGCe1uFNly6WwpPJsm8VtiU80g==")));
+ UNIT_ASSERT(pub.CheckSign(data,
+ Base64Decode("FeMZtDP-yuoNqK2HYw3JxTV9v7p8IoQEuRMtuHddafh4bq1ZOeEqg7g7Su6M3iq_kN9DZ_fVhuhuVcbZmNYPIvJ8oL5DE80KI3d1Qbs9mS8_X4Oq2TJpZgNfFG-z_LPRZSNRP9Q8sQhlAoSZHOSZkBFcYj1EuqEp6nSSSbX8Ji4Se-TfhIh3YFQkr-Ivk_3NmSXhDXUaW7CHo2rVm58QJ2cgSEuxzBH-Q8E8tGDCEmk4p3_iot9XY8RRN-_j0yi15etmXCUIKFbpDogtHdT8CyAEVHMYvsLqkLux9pzy3RdvNQmoPjol3wIm-H0wMtF_pMw4G2QLNev6he6xWeckxw==")));
+ }
+
+ Y_UNIT_TEST(Keygen) {
+ for (size_t idx = 0; idx < 100; ++idx) {
+ NRw::TKeyPair pair = NRw::GenKeyPair(1024);
+ NRw::TRwPrivateKey priv(pair.Private, 0);
+ NRw::TRwPublicKey pub(pair.Public);
+
+ const TString data = "my magic data";
+ TStringStream s;
+ s << "data='" << data << "'.";
+ s << "private='" << Base64Encode(pair.Private) << "'.";
+ s << "public='" << Base64Encode(pair.Public) << "'.";
+ TString sign;
+ UNIT_ASSERT_NO_EXCEPTION_C(sign = priv.SignTicket(data), s.Str());
+ s << "sign='" << Base64Encode(sign) << "'.";
+ UNIT_ASSERT_C(pub.CheckSign(data, sign), s.Str());
+ }
+ }
+}
diff --git a/library/cpp/tvmauth/src/rw/ut/ya.make b/library/cpp/tvmauth/src/rw/ut/ya.make
new file mode 100644
index 0000000000..81dda79641
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/ut/ya.make
@@ -0,0 +1,17 @@
+UNITTEST_FOR(library/cpp/tvmauth/src/rw)
+
+OWNER(
+ g:passport_infra
+ e-sidorov
+ ezaitov
+)
+
+SRCS(
+ rw_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/string_utils/base64
+)
+
+END()
diff --git a/library/cpp/tvmauth/src/rw/ut_large/gen/main.cpp b/library/cpp/tvmauth/src/rw/ut_large/gen/main.cpp
new file mode 100644
index 0000000000..31a599c996
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/ut_large/gen/main.cpp
@@ -0,0 +1,32 @@
+#include <library/cpp/tvmauth/src/rw/keys.h>
+
+#include <library/cpp/string_utils/base64/base64.h>
+
+#include <util/generic/yexception.h>
+
+using namespace NTvmAuth;
+
+const TString DATA = "my magic data";
+
+int main(int, char**) {
+ const NRw::TKeyPair pair = NRw::GenKeyPair(1024);
+ const NRw::TRwPrivateKey priv(pair.Private, 0);
+ const NRw::TRwPublicKey pub(pair.Public);
+
+ Cout << "data='" << DATA << "'."
+ << "private='" << Base64Encode(pair.Private) << "'."
+ << "public='" << Base64Encode(pair.Public) << "'.";
+
+ TString sign;
+ try {
+ sign = priv.SignTicket(DATA);
+ Cout << "sign='" << Base64Encode(sign) << "'.";
+ Y_ENSURE(pub.CheckSign(DATA, sign));
+ } catch (const std::exception& e) {
+ Cout << "what='" << e.what() << "'" << Endl;
+ return 1;
+ }
+ Cout << Endl;
+
+ return 0;
+}
diff --git a/library/cpp/tvmauth/src/rw/ut_large/gen/ya.make b/library/cpp/tvmauth/src/rw/ut_large/gen/ya.make
new file mode 100644
index 0000000000..7b62d5c726
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/ut_large/gen/ya.make
@@ -0,0 +1,14 @@
+PROGRAM()
+
+OWNER(g:passport_infra)
+
+SRCS(
+ main.cpp
+)
+
+PEERDIR(
+ library/cpp/string_utils/base64
+ library/cpp/tvmauth/src/rw
+)
+
+END()
diff --git a/library/cpp/tvmauth/src/rw/ut_large/test.py b/library/cpp/tvmauth/src/rw/ut_large/test.py
new file mode 100644
index 0000000000..0cf95d9848
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/ut_large/test.py
@@ -0,0 +1,35 @@
+from __future__ import print_function
+
+import os
+import subprocess
+import sys
+
+import yatest.common as yc
+
+
+def test_fuzzing():
+ errfile = './errfile'
+ outfile = './outfile'
+ env = os.environ.copy()
+
+ for number in range(25000):
+ with open(errfile, 'w') as fe:
+ with open(outfile, 'w') as fo:
+ p = subprocess.Popen(
+ [
+ yc.build_path('library/cpp/tvmauth/src/rw/ut_large/gen/gen'),
+ ],
+ env=env,
+ stdout=fo,
+ stderr=fe,
+ )
+ code = p.wait()
+
+ with open(errfile) as fe:
+ all = fe.read()
+ if all != '':
+ with open(outfile) as fo:
+ print(fo.read(), file=sys.stderr)
+ assert all == ''
+
+ assert code == 0
diff --git a/library/cpp/tvmauth/src/rw/ut_large/ya.make b/library/cpp/tvmauth/src/rw/ut_large/ya.make
new file mode 100644
index 0000000000..54f82065e7
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/ut_large/ya.make
@@ -0,0 +1,17 @@
+PY2TEST()
+
+OWNER(g:passport_infra)
+
+TEST_SRCS(test.py)
+
+DEPENDS(library/cpp/tvmauth/src/rw/ut_large/gen)
+
+TAG(ya:fat)
+
+SIZE(LARGE)
+
+END()
+
+RECURSE(
+ gen
+)
diff --git a/library/cpp/tvmauth/src/rw/ya.make b/library/cpp/tvmauth/src/rw/ya.make
new file mode 100644
index 0000000000..e2ef68d416
--- /dev/null
+++ b/library/cpp/tvmauth/src/rw/ya.make
@@ -0,0 +1,30 @@
+LIBRARY(ticket_parser)
+
+OWNER(
+ g:passport_infra
+ e-sidorov
+ ezaitov
+)
+
+PEERDIR(
+ contrib/libs/openssl
+ library/cpp/openssl/init
+)
+
+SRCS(
+ keys.cpp
+ rw_asn1.c
+ rw_key.c
+ rw_lib.c
+ rw_ossl.c
+ rw_pss.c
+ rw_pss_sign.c
+ rw_sign.c
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ ut
+ ut_large
+)
diff --git a/library/cpp/tvmauth/src/service_impl.cpp b/library/cpp/tvmauth/src/service_impl.cpp
new file mode 100644
index 0000000000..528a244647
--- /dev/null
+++ b/library/cpp/tvmauth/src/service_impl.cpp
@@ -0,0 +1,203 @@
+#include "service_impl.h"
+
+#include "parser.h"
+#include "utils.h"
+
+#include <library/cpp/tvmauth/exception.h>
+#include <library/cpp/tvmauth/ticket_status.h>
+
+#include <util/generic/strbuf.h>
+#include <util/string/cast.h>
+#include <util/string/split.h>
+
+namespace NTvmAuth {
+ static const char* EX_MSG = "Method cannot be used in non-valid ticket";
+
+ TCheckedServiceTicket::TImpl::operator bool() const {
+ return (Status_ == ETicketStatus::Ok);
+ }
+
+ TTvmId TCheckedServiceTicket::TImpl::GetSrc() const {
+ Y_ENSURE_EX(bool(*this), TNotAllowedException() << EX_MSG);
+ return ProtobufTicket_.service().srcclientid();
+ }
+
+ const TScopes& TCheckedServiceTicket::TImpl::GetScopes() const {
+ Y_ENSURE_EX(bool(*this), TNotAllowedException() << EX_MSG);
+ if (CachedScopes_.empty()) {
+ for (const auto& el : ProtobufTicket_.service().scopes()) {
+ CachedScopes_.push_back(el);
+ }
+ }
+ return CachedScopes_;
+ }
+
+ bool TCheckedServiceTicket::TImpl::HasScope(TStringBuf scopeName) const {
+ Y_ENSURE_EX(bool(*this), TNotAllowedException() << EX_MSG);
+ return std::binary_search(ProtobufTicket_.service().scopes().begin(), ProtobufTicket_.service().scopes().end(), scopeName);
+ }
+
+ ETicketStatus TCheckedServiceTicket::TImpl::GetStatus() const {
+ return Status_;
+ }
+
+ time_t TCheckedServiceTicket::TImpl::GetExpirationTime() const {
+ Y_ENSURE_EX(bool(*this), TNotAllowedException() << EX_MSG);
+ return ProtobufTicket_.expirationtime();
+ }
+
+ TString TCheckedServiceTicket::TImpl::DebugInfo() const {
+ if (CachedDebugInfo_) {
+ return CachedDebugInfo_;
+ }
+
+ if (Status_ == ETicketStatus::Malformed) {
+ CachedDebugInfo_ = "status=malformed;";
+ return CachedDebugInfo_;
+ }
+
+ TString targetString = "ticket_type=";
+ targetString.reserve(256);
+ if (Status_ == ETicketStatus::InvalidTicketType) {
+ targetString.append("not-serv;");
+ CachedDebugInfo_ = targetString;
+ return targetString;
+ }
+
+ targetString.append("serv");
+ if (ProtobufTicket_.has_expirationtime())
+ targetString.append(";expiration_time=").append(IntToString<10>(ProtobufTicket_.expirationtime()));
+ if (ProtobufTicket_.service().has_srcclientid()) {
+ targetString.append(";src=").append(IntToString<10>(ProtobufTicket_.service().srcclientid()));
+ }
+ if (ProtobufTicket_.service().has_dstclientid()) {
+ targetString.append(";dst=").append(IntToString<10>(ProtobufTicket_.service().dstclientid()));
+ }
+ for (const auto& scope : ProtobufTicket_.service().scopes()) {
+ targetString.append(";scope=").append(scope);
+ }
+ if (ProtobufTicket_.service().has_issueruid()) {
+ targetString.append(";issuer_uid=").append(IntToString<10>(ProtobufTicket_.service().GetissuerUid()));
+ }
+ targetString.append(";");
+
+ CachedDebugInfo_ = targetString;
+ return targetString;
+ }
+
+ TMaybe<TUid> TCheckedServiceTicket::TImpl::GetIssuerUid() const {
+ Y_ENSURE_EX(bool(*this), TNotAllowedException() << EX_MSG);
+ return ProtobufTicket_.service().has_issueruid()
+ ? ProtobufTicket_.service().GetissuerUid()
+ : TMaybe<TUid>();
+ }
+
+ void TCheckedServiceTicket::TImpl::SetStatus(ETicketStatus status) {
+ Status_ = status;
+ }
+
+ TCheckedServiceTicket::TImpl::TImpl(ETicketStatus status, ticket2::Ticket&& protobufTicket)
+ : Status_(status)
+ , ProtobufTicket_(std::move(protobufTicket))
+ {
+ }
+
+ TServiceTicketImplPtr TCheckedServiceTicket::TImpl::CreateTicketForTests(ETicketStatus status,
+ TTvmId src,
+ TMaybe<TUid> issuerUid) {
+ ticket2::Ticket proto;
+ proto.mutable_service()->set_srcclientid(src);
+ proto.mutable_service()->set_dstclientid(100500);
+ if (issuerUid) {
+ proto.mutable_service()->set_issueruid(*issuerUid);
+ }
+ return MakeHolder<TImpl>(status, std::move(proto));
+ }
+
+ TServiceContext::TImpl::TImpl(TStringBuf secretBase64, TTvmId selfTvmId, TStringBuf tvmKeysResponse)
+ : Secret_(ParseSecret(secretBase64))
+ , SelfTvmId_(selfTvmId)
+ {
+ ResetKeys(tvmKeysResponse);
+ }
+
+ TServiceContext::TImpl::TImpl(TTvmId selfTvmId, TStringBuf tvmKeysResponse)
+ : SelfTvmId_(selfTvmId)
+ {
+ ResetKeys(tvmKeysResponse);
+ }
+
+ TServiceContext::TImpl::TImpl(TStringBuf secretBase64)
+ : Secret_(ParseSecret(secretBase64))
+ {
+ }
+
+ void TServiceContext::TImpl::ResetKeys(TStringBuf tvmKeysResponse) {
+ tvm_keys::Keys protoKeys;
+ if (!protoKeys.ParseFromString(TParserTvmKeys::ParseStrV1(tvmKeysResponse))) {
+ ythrow TMalformedTvmKeysException() << "Malformed TVM keys";
+ }
+
+ NRw::TPublicKeys keys;
+ for (int idx = 0; idx < protoKeys.tvm_size(); ++idx) {
+ const tvm_keys::TvmKey& k = protoKeys.tvm(idx);
+ keys.emplace(k.gen().id(),
+ k.gen().body());
+ }
+
+ if (keys.empty()) {
+ ythrow TEmptyTvmKeysException() << "Empty TVM keys";
+ }
+
+ Keys_ = std::move(keys);
+ }
+
+ TServiceTicketImplPtr TServiceContext::TImpl::Check(TStringBuf ticketBody) const {
+ if (Keys_.empty()) {
+ ythrow TEmptyTvmKeysException() << "Empty TVM keys";
+ }
+
+ TParserTickets::TRes res = TParserTickets::ParseV3(ticketBody, Keys_, TParserTickets::ServiceFlag());
+ if (res.Status != ETicketStatus::Ok) {
+ return MakeHolder<TCheckedServiceTicket::TImpl>(res.Status, std::move(res.Ticket));
+ }
+
+ const ETicketStatus status = CheckProtobufServiceTicket(res.Ticket);
+ return MakeHolder<TCheckedServiceTicket::TImpl>(status, std::move(res.Ticket));
+ }
+
+ TString TServiceContext::TImpl::SignCgiParamsForTvm(TStringBuf ts, TStringBuf dst, TStringBuf scopes) const {
+ if (Secret_.Value().empty()) {
+ ythrow TMalformedTvmSecretException() << "Malformed TVM secret: it is empty";
+ }
+ return NUtils::SignCgiParamsForTvm(Secret_, ts, dst, scopes);
+ }
+
+ ETicketStatus TServiceContext::TImpl::CheckProtobufServiceTicket(const ticket2::Ticket& ticket) const {
+ if (!ticket.has_service()) {
+ return ETicketStatus::Malformed;
+ }
+ if (ticket.service().dstclientid() != SelfTvmId_) {
+ return ETicketStatus::InvalidDst;
+ }
+ return ETicketStatus::Ok;
+ }
+
+ TString TServiceContext::TImpl::ParseSecret(TStringBuf secretBase64) {
+ while (secretBase64 && secretBase64.back() == '\n') {
+ secretBase64.Chop(1);
+ }
+
+ if (secretBase64.empty()) {
+ ythrow TMalformedTvmSecretException() << "Malformed TVM secret: it is empty";
+ }
+
+ const TString secret = NUtils::Base64url2bin(secretBase64);
+ if (secret.empty()) {
+ ythrow TMalformedTvmSecretException() << "Malformed TVM secret: invalid base64url";
+ }
+
+ return secret;
+ }
+
+}
diff --git a/library/cpp/tvmauth/src/service_impl.h b/library/cpp/tvmauth/src/service_impl.h
new file mode 100644
index 0000000000..18dd4ec335
--- /dev/null
+++ b/library/cpp/tvmauth/src/service_impl.h
@@ -0,0 +1,77 @@
+#pragma once
+
+#include <library/cpp/tvmauth/src/protos/ticket2.pb.h>
+#include <library/cpp/tvmauth/src/protos/tvm_keys.pb.h>
+#include <library/cpp/tvmauth/src/rw/keys.h>
+
+#include <library/cpp/tvmauth/type.h>
+#include <library/cpp/tvmauth/deprecated/service_context.h>
+
+#include <library/cpp/charset/ci_string.h>
+#include <library/cpp/string_utils/secret_string/secret_string.h>
+
+#include <util/generic/maybe.h>
+
+#include <string>
+
+namespace NTvmAuth {
+ using TServiceTicketImplPtr = THolder<TCheckedServiceTicket::TImpl>;
+ class TCheckedServiceTicket::TImpl {
+ public:
+ explicit operator bool() const;
+
+ TTvmId GetSrc() const;
+ const TScopes& GetScopes() const;
+ bool HasScope(TStringBuf scopeName) const;
+ ETicketStatus GetStatus() const;
+ time_t GetExpirationTime() const;
+
+ TString DebugInfo() const;
+ TMaybe<TUid> GetIssuerUid() const;
+
+ void SetStatus(ETicketStatus status);
+
+ /*!
+ * Constructor for creation invalid ticket storing error status in TServiceContext
+ * @param status
+ * @param protobufTicket
+ */
+ TImpl(ETicketStatus status, ticket2::Ticket&& protobufTicket);
+
+ static TServiceTicketImplPtr CreateTicketForTests(ETicketStatus status,
+ TTvmId src,
+ TMaybe<TUid> issuerUid);
+
+ private:
+ ETicketStatus Status_;
+ ticket2::Ticket ProtobufTicket_;
+ mutable TScopes CachedScopes_;
+ mutable TString CachedDebugInfo_;
+ };
+
+ class TServiceContext::TImpl {
+ public:
+ TImpl(TStringBuf secretBase64, TTvmId selfTvmId, TStringBuf tvmKeysResponse);
+ TImpl(TTvmId selfTvmId, TStringBuf tvmKeysResponse);
+ TImpl(TStringBuf secretBase64);
+
+ void ResetKeys(TStringBuf tvmKeysResponse);
+
+ TServiceTicketImplPtr Check(TStringBuf ticketBody) const;
+ TString SignCgiParamsForTvm(TStringBuf ts, TStringBuf dst, TStringBuf scopes = TStringBuf()) const;
+
+ const NRw::TPublicKeys& GetKeys() const { // for tests
+ return Keys_;
+ }
+
+ private:
+ ETicketStatus CheckProtobufServiceTicket(const ticket2::Ticket& ticket) const;
+ static TString ParseSecret(TStringBuf secretBase64);
+
+ NRw::TPublicKeys Keys_;
+ const NSecretString::TSecretString Secret_;
+ const TTvmId SelfTvmId_ = 0;
+
+ ::google::protobuf::LogSilencer LogSilencer_;
+ };
+}
diff --git a/library/cpp/tvmauth/src/service_ticket.cpp b/library/cpp/tvmauth/src/service_ticket.cpp
new file mode 100644
index 0000000000..077049ef3a
--- /dev/null
+++ b/library/cpp/tvmauth/src/service_ticket.cpp
@@ -0,0 +1,41 @@
+#include "service_impl.h"
+
+#include <library/cpp/tvmauth/checked_service_ticket.h>
+
+namespace NTvmAuth {
+ static const char* EX_MSG = "Ticket already moved out";
+
+ TCheckedServiceTicket::TCheckedServiceTicket(THolder<TImpl> impl)
+ : Impl_(std::move(impl))
+ {
+ }
+
+ TCheckedServiceTicket::TCheckedServiceTicket(TCheckedServiceTicket&& o) = default;
+ TCheckedServiceTicket& TCheckedServiceTicket::operator=(TCheckedServiceTicket&& o) = default;
+ TCheckedServiceTicket::~TCheckedServiceTicket() = default;
+
+ TCheckedServiceTicket::operator bool() const {
+ Y_ENSURE(Impl_, EX_MSG);
+ return Impl_->operator bool();
+ }
+
+ TTvmId TCheckedServiceTicket::GetSrc() const {
+ Y_ENSURE(Impl_, EX_MSG);
+ return Impl_->GetSrc();
+ }
+
+ ETicketStatus TCheckedServiceTicket::GetStatus() const {
+ Y_ENSURE(Impl_, EX_MSG);
+ return Impl_->GetStatus();
+ }
+
+ TString TCheckedServiceTicket::DebugInfo() const {
+ Y_ENSURE(Impl_, EX_MSG);
+ return Impl_->DebugInfo();
+ }
+
+ TMaybe<TUid> TCheckedServiceTicket::GetIssuerUid() const {
+ Y_ENSURE(Impl_, EX_MSG);
+ return Impl_->GetIssuerUid();
+ }
+}
diff --git a/library/cpp/tvmauth/src/status.cpp b/library/cpp/tvmauth/src/status.cpp
new file mode 100644
index 0000000000..1b08fc098f
--- /dev/null
+++ b/library/cpp/tvmauth/src/status.cpp
@@ -0,0 +1,32 @@
+#include <library/cpp/tvmauth/ticket_status.h>
+
+#include <util/generic/yexception.h>
+
+namespace NTvmAuth {
+ TStringBuf StatusToString(ETicketStatus st) {
+ switch (st) {
+ case ETicketStatus::Ok:
+ return "OK";
+ case ETicketStatus::Expired:
+ return "Expired ticket";
+ case ETicketStatus::InvalidBlackboxEnv:
+ return "Invalid BlackBox environment";
+ case ETicketStatus::InvalidDst:
+ return "Invalid ticket destination";
+ case ETicketStatus::InvalidTicketType:
+ return "Invalid ticket type";
+ case ETicketStatus::Malformed:
+ return "Malformed ticket";
+ case ETicketStatus::MissingKey:
+ return "Context does not have required key to check ticket: public keys are too old";
+ case ETicketStatus::SignBroken:
+ return "Invalid ticket signature";
+ case ETicketStatus::UnsupportedVersion:
+ return "Unsupported ticket version";
+ case ETicketStatus::NoRoles:
+ return "Subject (src or defaultUid) does not have any roles in IDM";
+ }
+
+ ythrow yexception() << "Unexpected status: " << static_cast<int>(st);
+ }
+}
diff --git a/library/cpp/tvmauth/src/unittest.cpp b/library/cpp/tvmauth/src/unittest.cpp
new file mode 100644
index 0000000000..5133d79ea9
--- /dev/null
+++ b/library/cpp/tvmauth/src/unittest.cpp
@@ -0,0 +1,14 @@
+#include "service_impl.h"
+#include "user_impl.h"
+
+#include <library/cpp/tvmauth/unittest.h>
+
+namespace NTvmAuth::NUnittest {
+ TCheckedServiceTicket CreateServiceTicket(ETicketStatus status, TTvmId src, TMaybe<TUid> issuerUid) {
+ return TCheckedServiceTicket(TCheckedServiceTicket::TImpl::CreateTicketForTests(status, src, issuerUid));
+ }
+
+ TCheckedUserTicket CreateUserTicket(ETicketStatus status, TUid defaultUid, const TScopes& scopes, const TUids& uids, EBlackboxEnv env) {
+ return TCheckedUserTicket(TCheckedUserTicket::TImpl::CreateTicketForTests(status, defaultUid, scopes, uids, env));
+ }
+}
diff --git a/library/cpp/tvmauth/src/user_impl.cpp b/library/cpp/tvmauth/src/user_impl.cpp
new file mode 100644
index 0000000000..33002968d2
--- /dev/null
+++ b/library/cpp/tvmauth/src/user_impl.cpp
@@ -0,0 +1,241 @@
+#include "user_impl.h"
+
+#include "parser.h"
+
+#include <library/cpp/tvmauth/exception.h>
+#include <library/cpp/tvmauth/ticket_status.h>
+
+#include <util/generic/strbuf.h>
+#include <util/string/cast.h>
+#include <util/string/split.h>
+
+#include <algorithm>
+
+namespace NTvmAuth {
+ static const char* EX_MSG = "Method cannot be used in non-valid ticket";
+
+ TStringBuf GetBlackboxEnvAsString(EBlackboxEnv environment) {
+ switch (environment) {
+ case (EBlackboxEnv::Prod):
+ return TStringBuf("Prod");
+ case (EBlackboxEnv::Test):
+ return TStringBuf("Test");
+ case (EBlackboxEnv::ProdYateam):
+ return TStringBuf("ProdYateam");
+ case (EBlackboxEnv::TestYateam):
+ return TStringBuf("TestYateam");
+ case (EBlackboxEnv::Stress):
+ return TStringBuf("Stress");
+ default:
+ throw yexception() << "Unknown environment";
+ }
+ }
+
+ TCheckedUserTicket::TImpl::operator bool() const {
+ return (Status_ == ETicketStatus::Ok);
+ }
+
+ TUid TCheckedUserTicket::TImpl::GetDefaultUid() const {
+ Y_ENSURE_EX(bool(*this), TNotAllowedException() << EX_MSG);
+ return ProtobufTicket_.user().defaultuid();
+ }
+
+ time_t TCheckedUserTicket::TImpl::GetExpirationTime() const {
+ Y_ENSURE_EX(bool(*this), TNotAllowedException() << EX_MSG);
+ return ProtobufTicket_.expirationtime();
+ }
+
+ const TScopes& TCheckedUserTicket::TImpl::GetScopes() const {
+ Y_ENSURE_EX(bool(*this), TNotAllowedException() << EX_MSG);
+ if (CachedScopes_.empty()) {
+ for (const auto& el : ProtobufTicket_.user().scopes()) {
+ CachedScopes_.push_back(el);
+ }
+ }
+ return CachedScopes_;
+ }
+
+ bool TCheckedUserTicket::TImpl::HasScope(TStringBuf scopeName) const {
+ Y_ENSURE_EX(bool(*this), TNotAllowedException() << EX_MSG);
+ return std::binary_search(ProtobufTicket_.user().scopes().begin(), ProtobufTicket_.user().scopes().end(), scopeName);
+ }
+
+ ETicketStatus TCheckedUserTicket::TImpl::GetStatus() const {
+ return Status_;
+ }
+
+ const TUids& TCheckedUserTicket::TImpl::GetUids() const {
+ Y_ENSURE_EX(bool(*this), TNotAllowedException() << EX_MSG);
+ if (CachedUids_.empty()) {
+ for (const auto& user : ProtobufTicket_.user().users()) {
+ CachedUids_.push_back(user.uid());
+ }
+ }
+ return CachedUids_;
+ }
+
+ TString TCheckedUserTicket::TImpl::DebugInfo() const {
+ if (CachedDebugInfo_) {
+ return CachedDebugInfo_;
+ }
+
+ if (Status_ == ETicketStatus::Malformed) {
+ CachedDebugInfo_ = "status=malformed;";
+ return CachedDebugInfo_;
+ }
+
+ TString targetString = "ticket_type=";
+ targetString.reserve(256);
+ if (Status_ == ETicketStatus::InvalidTicketType) {
+ targetString.append("not-user;");
+ CachedDebugInfo_ = targetString;
+ return targetString;
+ }
+
+ targetString.append("user");
+ if (ProtobufTicket_.expirationtime() > 0)
+ targetString.append(";expiration_time=").append(IntToString<10>(ProtobufTicket_.expirationtime()));
+ for (const auto& scope : ProtobufTicket_.user().scopes()) {
+ targetString.append(";scope=").append(scope);
+ }
+
+ if (ProtobufTicket_.user().defaultuid() > 0)
+ targetString.append(";default_uid=").append(IntToString<10>(ProtobufTicket_.user().defaultuid()));
+ for (const auto& user : ProtobufTicket_.user().users()) {
+ targetString.append(";uid=").append(IntToString<10>(user.uid()));
+ }
+
+ targetString.append(";env=");
+ EBlackboxEnv environment = static_cast<EBlackboxEnv>(ProtobufTicket_.user().env());
+ targetString.append(GetBlackboxEnvAsString(environment));
+ targetString.append(";");
+
+ CachedDebugInfo_ = targetString;
+ return targetString;
+ }
+
+ EBlackboxEnv TCheckedUserTicket::TImpl::GetEnv() const {
+ return (EBlackboxEnv)ProtobufTicket_.user().env();
+ }
+
+ void TCheckedUserTicket::TImpl::SetStatus(ETicketStatus status) {
+ Status_ = status;
+ }
+
+ TCheckedUserTicket::TImpl::TImpl(ETicketStatus status, ticket2::Ticket&& protobufTicket)
+ : Status_(status)
+ , ProtobufTicket_(std::move(protobufTicket))
+ {
+ }
+
+ TUserTicketImplPtr TCheckedUserTicket::TImpl::CreateTicketForTests(ETicketStatus status,
+ TUid defaultUid,
+ TScopes scopes,
+ TUids uids,
+ EBlackboxEnv env) {
+ auto prepareCont = [](auto& cont) {
+ std::sort(cont.begin(), cont.end());
+ cont.erase(std::unique(cont.begin(), cont.end()), cont.end());
+ };
+ auto erase = [](auto& cont, auto val) {
+ auto it = std::find(cont.begin(), cont.end(), val);
+ if (it != cont.end()) {
+ cont.erase(it);
+ }
+ };
+
+ prepareCont(scopes);
+ erase(scopes, "");
+
+ uids.push_back(defaultUid);
+ prepareCont(uids);
+ erase(uids, 0);
+ Y_ENSURE(!uids.empty(), "User ticket cannot contain empty uid list");
+
+ ticket2::Ticket proto;
+ for (TUid uid : uids) {
+ proto.mutable_user()->add_users()->set_uid(uid);
+ }
+ proto.mutable_user()->set_defaultuid(defaultUid);
+ proto.mutable_user()->set_entrypoint(100500);
+ for (TStringBuf scope : scopes) {
+ proto.mutable_user()->add_scopes(TString(scope));
+ }
+
+ proto.mutable_user()->set_env((tvm_keys::BbEnvType)env);
+
+ return MakeHolder<TImpl>(status, std::move(proto));
+ }
+
+ TUserContext::TImpl::TImpl(EBlackboxEnv env, TStringBuf tvmKeysResponse)
+ : Env_(env)
+ {
+ ResetKeys(tvmKeysResponse);
+ }
+
+ void TUserContext::TImpl::ResetKeys(TStringBuf tvmKeysResponse) {
+ tvm_keys::Keys protoKeys;
+ if (!protoKeys.ParseFromString(TParserTvmKeys::ParseStrV1(tvmKeysResponse))) {
+ ythrow TMalformedTvmKeysException() << "Malformed TVM keys";
+ }
+
+ NRw::TPublicKeys keys;
+ for (int idx = 0; idx < protoKeys.bb_size(); ++idx) {
+ const tvm_keys::BbKey& k = protoKeys.bb(idx);
+ if (IsAllowed(k.env())) {
+ keys.emplace(k.gen().id(),
+ k.gen().body());
+ }
+ }
+
+ if (keys.empty()) {
+ ythrow TEmptyTvmKeysException() << "Empty TVM keys";
+ }
+
+ Keys_ = std::move(keys);
+ }
+
+ TUserTicketImplPtr TUserContext::TImpl::Check(TStringBuf ticketBody) const {
+ TParserTickets::TRes res = TParserTickets::ParseV3(ticketBody, Keys_, TParserTickets::UserFlag());
+ ETicketStatus status = CheckProtobufUserTicket(res.Ticket);
+
+ if (res.Status != ETicketStatus::Ok && !(res.Status == ETicketStatus::MissingKey && status == ETicketStatus::InvalidBlackboxEnv)) {
+ status = res.Status;
+ }
+ return MakeHolder<TCheckedUserTicket::TImpl>(status, std::move(res.Ticket));
+ }
+
+ ETicketStatus TUserContext::TImpl::CheckProtobufUserTicket(const ticket2::Ticket& ticket) const {
+ if (!ticket.has_user()) {
+ return ETicketStatus::Malformed;
+ }
+ if (!IsAllowed(ticket.user().env())) {
+ return ETicketStatus::InvalidBlackboxEnv;
+ }
+ return ETicketStatus::Ok;
+ }
+
+ const NRw::TPublicKeys& TUserContext::TImpl::GetKeys() const {
+ return Keys_;
+ }
+
+ bool TUserContext::TImpl::IsAllowed(tvm_keys::BbEnvType env) const {
+ if (env == tvm_keys::Prod && (Env_ == EBlackboxEnv::Prod || Env_ == EBlackboxEnv::Stress)) {
+ return true;
+ }
+ if (env == tvm_keys::ProdYateam && Env_ == EBlackboxEnv::ProdYateam) {
+ return true;
+ }
+ if (env == tvm_keys::Test && Env_ == EBlackboxEnv::Test) {
+ return true;
+ }
+ if (env == tvm_keys::TestYateam && Env_ == EBlackboxEnv::TestYateam) {
+ return true;
+ }
+ if (env == tvm_keys::Stress && Env_ == EBlackboxEnv::Stress) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/library/cpp/tvmauth/src/user_impl.h b/library/cpp/tvmauth/src/user_impl.h
new file mode 100644
index 0000000000..e3f1099b90
--- /dev/null
+++ b/library/cpp/tvmauth/src/user_impl.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include <library/cpp/tvmauth/src/protos/ticket2.pb.h>
+#include <library/cpp/tvmauth/src/protos/tvm_keys.pb.h>
+#include <library/cpp/tvmauth/src/rw/keys.h>
+
+#include <library/cpp/tvmauth/deprecated/user_context.h>
+
+#include <library/cpp/charset/ci_string.h>
+
+#include <unordered_map>
+
+namespace NTvmAuth {
+ using TUserTicketImplPtr = THolder<TCheckedUserTicket::TImpl>;
+ class TCheckedUserTicket::TImpl {
+ public:
+ explicit operator bool() const;
+
+ TUid GetDefaultUid() const;
+ time_t GetExpirationTime() const;
+ const TScopes& GetScopes() const;
+ bool HasScope(TStringBuf scopeName) const;
+ ETicketStatus GetStatus() const;
+ const TUids& GetUids() const;
+
+ TString DebugInfo() const;
+
+ EBlackboxEnv GetEnv() const;
+
+ void SetStatus(ETicketStatus status);
+
+ /*!
+ * Constructor for creation invalid ticket storing error status in TServiceContext
+ * @param status
+ * @param protobufTicket
+ */
+ TImpl(ETicketStatus status, ticket2::Ticket&& protobufTicket);
+
+ static TUserTicketImplPtr CreateTicketForTests(ETicketStatus status,
+ TUid defaultUid,
+ TScopes scopes,
+ TUids uids,
+ EBlackboxEnv env = EBlackboxEnv::Test);
+
+ private:
+ static const int MaxUserCount = 15;
+
+ ETicketStatus Status_;
+ ticket2::Ticket ProtobufTicket_;
+ mutable TScopes CachedScopes_;
+ mutable TUids CachedUids_;
+ mutable TString CachedDebugInfo_;
+ };
+
+ class TUserContext::TImpl {
+ public:
+ TImpl(EBlackboxEnv env, TStringBuf tvmKeysResponse);
+ void ResetKeys(TStringBuf tvmKeysResponse);
+
+ TUserTicketImplPtr Check(TStringBuf ticketBody) const;
+ const NRw::TPublicKeys& GetKeys() const;
+
+ bool IsAllowed(tvm_keys::BbEnvType env) const;
+
+ private:
+ ETicketStatus CheckProtobufUserTicket(const ticket2::Ticket& ticket) const;
+
+ NRw::TPublicKeys Keys_;
+ EBlackboxEnv Env_;
+ ::google::protobuf::LogSilencer LogSilencer_;
+ };
+}
diff --git a/library/cpp/tvmauth/src/user_ticket.cpp b/library/cpp/tvmauth/src/user_ticket.cpp
new file mode 100644
index 0000000000..3e4e0c0364
--- /dev/null
+++ b/library/cpp/tvmauth/src/user_ticket.cpp
@@ -0,0 +1,56 @@
+#include "user_impl.h"
+
+#include <library/cpp/tvmauth/checked_user_ticket.h>
+
+namespace NTvmAuth {
+ static const char* EX_MSG = "Ticket already moved out";
+
+ TCheckedUserTicket::TCheckedUserTicket(THolder<TCheckedUserTicket::TImpl> impl)
+ : Impl_(std::move(impl))
+ {
+ }
+
+ TCheckedUserTicket::TCheckedUserTicket(TCheckedUserTicket&& o) = default;
+ TCheckedUserTicket::~TCheckedUserTicket() = default;
+ TCheckedUserTicket& TCheckedUserTicket::operator=(TCheckedUserTicket&& o) = default;
+
+ TCheckedUserTicket::operator bool() const {
+ Y_ENSURE(Impl_, EX_MSG);
+ return Impl_->operator bool();
+ }
+
+ const TUids& TCheckedUserTicket::GetUids() const {
+ Y_ENSURE(Impl_, EX_MSG);
+ return Impl_->GetUids();
+ }
+
+ TUid TCheckedUserTicket::GetDefaultUid() const {
+ Y_ENSURE(Impl_, EX_MSG);
+ return Impl_->GetDefaultUid();
+ }
+
+ const TScopes& TCheckedUserTicket::GetScopes() const {
+ Y_ENSURE(Impl_, EX_MSG);
+ return Impl_->GetScopes();
+ }
+
+ bool TCheckedUserTicket::HasScope(TStringBuf scopeName) const {
+ Y_ENSURE(Impl_, EX_MSG);
+ return Impl_->HasScope(scopeName);
+ }
+
+ ETicketStatus TCheckedUserTicket::GetStatus() const {
+ Y_ENSURE(Impl_, EX_MSG);
+ return Impl_->GetStatus();
+ }
+
+ TString TCheckedUserTicket::DebugInfo() const {
+ Y_ENSURE(Impl_, EX_MSG);
+ return Impl_->DebugInfo();
+ }
+
+ EBlackboxEnv TCheckedUserTicket::GetEnv() const {
+ Y_ENSURE(Impl_, EX_MSG);
+ return Impl_->GetEnv();
+ }
+}
diff --git a/library/cpp/tvmauth/src/ut/parser_ut.cpp b/library/cpp/tvmauth/src/ut/parser_ut.cpp
new file mode 100644
index 0000000000..530f45331a
--- /dev/null
+++ b/library/cpp/tvmauth/src/ut/parser_ut.cpp
@@ -0,0 +1,143 @@
+#include <library/cpp/tvmauth/src/parser.h>
+#include <library/cpp/tvmauth/src/utils.h>
+
+#include <library/cpp/tvmauth/exception.h>
+#include <library/cpp/tvmauth/ticket_status.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(ParserTestSuite) {
+ using namespace NTvmAuth;
+
+ Y_UNIT_TEST(Keys) {
+ UNIT_ASSERT_EXCEPTION(TParserTvmKeys::ParseStrV1("2:asds"), TMalformedTvmKeysException);
+ UNIT_ASSERT_EXCEPTION(TParserTvmKeys::ParseStrV1("3:asds"), TMalformedTvmKeysException);
+ UNIT_ASSERT_EXCEPTION(TParserTvmKeys::ParseStrV1("1:+a/sds"), TMalformedTvmKeysException);
+
+ UNIT_ASSERT_VALUES_EQUAL("sdsd", NUtils::Bin2base64url(TParserTvmKeys::ParseStrV1("1:sdsd")));
+ }
+
+ Y_UNIT_TEST(TicketsStrV3) {
+ UNIT_ASSERT_EQUAL(TParserTickets::TStrRes({ETicketStatus::Ok,
+ NUtils::Base64url2bin("CgYIDRCUkQYQDBgcIgdiYjpzZXNzIghiYjpzZXNzMg"),
+ NUtils::Base64url2bin("ERmeH_yzC7K_QsoHTyw7llCsyExEz3CoEopPIuivA0ZAtTaFq_Pa0l9Fhhx_NX9WpOp2CPyY5cFc4PXhcO83jCB7-EGvHNxGN-j2NQalERzPiKqkDCO0Q5etLzSzrfTlvMz7sXDvELNBHyA0PkAQnbz4supY0l-0Q6JBYSEF3zOVMjjE-HeQIFL3ats3_PakaUMWRvgQQ88pVdYZqAtbDw9PlTla7ommygVZQjcfNFXV1pJKRgOCLs-YyCjOJHLKL04zYj0X6KsOCTUeqhj7ml96wLZ-g1X9tyOR2WAr2Ctq7wIEHwqhxOLgOSKqm05xH6Vi3E_hekf50oe2jPfKEA"),
+ "3:serv:CgYIDRCUkQYQDBgcIgdiYjpzZXNzIghiYjpzZXNzMg:"}),
+ TParserTickets::ParseStrV3("3:serv:CgYIDRCUkQYQDBgcIgdiYjpzZXNzIghiYjpzZXNzMg:ERmeH_yzC7K_QsoHTyw7llCsyExEz3CoEopPIuivA0ZAtTaFq_Pa0l9Fhhx_NX9WpOp2CPyY5cFc4PXhcO83jCB7-EGvHNxGN-j2NQalERzPiKqkDCO0Q5etLzSzrfTlvMz7sXDvELNBHyA0PkAQnbz4supY0l-0Q6JBYSEF3zOVMjjE-HeQIFL3ats3_PakaUMWRvgQQ88pVdYZqAtbDw9PlTla7ommygVZQjcfNFXV1pJKRgOCLs-YyCjOJHLKL04zYj0X6KsOCTUeqhj7ml96wLZ-g1X9tyOR2WAr2Ctq7wIEHwqhxOLgOSKqm05xH6Vi3E_hekf50oe2jPfKEA",
+ TParserTickets::ServiceFlag()));
+ UNIT_ASSERT_EQUAL(TParserTickets::TStrRes({ETicketStatus::UnsupportedVersion,
+ {},
+ {},
+ {}}),
+ TParserTickets::ParseStrV3("2:serv:CgYIDRCUkQYQDBgcIgdiYjpzZXNzIghiYjpzZXNzMg:ERmeH_yzC7K_QsoHTyw7llCsyExEz3CoEopPIuivA0ZAtTaFq_Pa0l9Fhhx_NX9WpOp2CPyY5cFc4PXhcO83jCB7-EGvHNxGN-j2NQalERzPiKqkDCO0Q5etLzSzrfTlvMz7sXDvELNBHyA0PkAQnbz4supY0l-0Q6JBYSEF3zOVMjjE-HeQIFL3ats3_PakaUMWRvgQQ88pVdYZqAtbDw9PlTla7ommygVZQjcfNFXV1pJKRgOCLs-YyCjOJHLKL04zYj0X6KsOCTUeqhj7ml96wLZ-g1X9tyOR2WAr2Ctq7wIEHwqhxOLgOSKqm05xH6Vi3E_hekf50oe2jPfKEA",
+ TParserTickets::ServiceFlag()));
+ UNIT_ASSERT_EQUAL(TParserTickets::TStrRes({ETicketStatus::InvalidTicketType,
+ {},
+ {},
+ {}}),
+ TParserTickets::ParseStrV3("3:serv:CgYIDRCUkQYQDBgcIgdiYjpzZXNzIghiYjpzZXNzMg:ERmeH_yzC7K_QsoHTyw7llCsyExEz3CoEopPIuivA0ZAtTaFq_Pa0l9Fhhx_NX9WpOp2CPyY5cFc4PXhcO83jCB7-EGvHNxGN-j2NQalERzPiKqkDCO0Q5etLzSzrfTlvMz7sXDvELNBHyA0PkAQnbz4supY0l-0Q6JBYSEF3zOVMjjE-HeQIFL3ats3_PakaUMWRvgQQ88pVdYZqAtbDw9PlTla7ommygVZQjcfNFXV1pJKRgOCLs-YyCjOJHLKL04zYj0X6KsOCTUeqhj7ml96wLZ-g1X9tyOR2WAr2Ctq7wIEHwqhxOLgOSKqm05xH6Vi3E_hekf50oe2jPfKEA",
+ TParserTickets::UserFlag()));
+ UNIT_ASSERT_EQUAL(TParserTickets::TStrRes({ETicketStatus::Malformed,
+ {},
+ {},
+ {}}),
+ TParserTickets::ParseStrV3("3:serv::ERmeH_yzC7K_QsoHTyw7llCsyExEz3CoEopPIuivA0ZAtTaFq_Pa0l9Fhhx_NX9WpOp2CPyY5cFc4PXhcO83jCB7-EGvHNxGN-j2NQalERzPiKqkDCO0Q5etLzSzrfTlvMz7sXDvELNBHyA0PkAQnbz4supY0l-0Q6JBYSEF3zOVMjjE-HeQIFL3ats3_PakaUMWRvgQQ88pVdYZqAtbDw9PlTla7ommygVZQjcfNFXV1pJKRgOCLs-YyCjOJHLKL04zYj0X6KsOCTUeqhj7ml96wLZ-g1X9tyOR2WAr2Ctq7wIEHwqhxOLgOSKqm05xH6Vi3E_hekf50oe2jPfKEA",
+ TParserTickets::ServiceFlag()));
+ UNIT_ASSERT_EQUAL(TParserTickets::TStrRes({ETicketStatus::Malformed,
+ {},
+ {},
+ {}}),
+ TParserTickets::ParseStrV3("3:serv:CgYIDRCUkQYQDBgcIgdiYjpzZXNzIghiYjpzZXNzMg:",
+ TParserTickets::ServiceFlag()));
+ UNIT_ASSERT_EQUAL(TParserTickets::TStrRes({ETicketStatus::Malformed,
+ {},
+ {},
+ {}}),
+ TParserTickets::ParseStrV3("3:serv:CgYIDRCUkQYQDBgcIgdiYjpzZXNzIghiYjpzZXNzMg:ERmeH_yzC7K_QsoHTyw7llCsyExEz3CoEopPIuivA0ZAtTaFq_Pa0l9Fhhx_NX9WpOp2CPyY5cFc4PXhcO83jCB7-EGvHNxGN-j2NQalERzPiKqkDCO0Q5etLzSzrfTlvMz7sXDvELNBHyA0PkAQnbz4supY0l-0Q6JBYSEF3zOVMjjE-HeQIFL3ats3_PakaUMWRvgQQ88pVdYZqAtbDw9PlTla7ommygVZQjcfNFXV1pJKRgOCLs-YyCjOJHLKL04zYj0X6KsOCTUeqhj7ml96wLZ-g1X9tyOR2WAr2Ctq7wIEHwqhxOLgOSKqm05xH6Vi3E_hekf50oe2jPfKEA:asd",
+ TParserTickets::ServiceFlag()));
+ UNIT_ASSERT_EQUAL(TParserTickets::TStrRes({ETicketStatus::Malformed,
+ {},
+ {},
+ {}}),
+ TParserTickets::ParseStrV3("3:serv:CgY+-*/IDRCUkQYQDBgcIgdiYjpzZXNzIghiYjpzZXNzMg:ERmeH_yzC7K_QsoHTyw7llCsyExEz3CoEopPIuivA0ZAtTaFq_Pa0l9Fhhx_NX9WpOp2CPyY5cFc4PXhcO83jCB7-EGvHNxGN-j2NQalERzPiKqkDCO0Q5etLzSzrfTlvMz7sXDvELNBHyA0PkAQnbz4supY0l-0Q6JBYSEF3zOVMjjE-HeQIFL3ats3_PakaUMWRvgQQ88pVdYZqAtbDw9PlTla7ommygVZQjcfNFXV1pJKRgOCLs-YyCjOJHLKL04zYj0X6KsOCTUeqhj7ml96wLZ-g1X9tyOR2WAr2Ctq7wIEHwqhxOLgOSKqm05xH6Vi3E_hekf50oe2jPfKEA",
+ TParserTickets::ServiceFlag()));
+ UNIT_ASSERT_EQUAL(TParserTickets::TStrRes({ETicketStatus::Malformed,
+ {},
+ {},
+ {}}),
+ TParserTickets::ParseStrV3("3:serv:CgYIDRCUkQYQDBgcIgdiYjpzZXNzIghiYjpzZXNzMg:ERme/*-+H_yzC7K_QsoHTyw7llCsyExEz3CoEopPIuivA0ZAtTaFq_Pa0l9Fhhx_NX9WpOp2CPyY5cFc4PXhcO83jCB7-EGvHNxGN-j2NQalERzPiKqkDCO0Q5etLzSzrfTlvMz7sXDvELNBHyA0PkAQnbz4supY0l-0Q6JBYSEF3zOVMjjE-HeQIFL3ats3_PakaUMWRvgQQ88pVdYZqAtbDw9PlTla7ommygVZQjcfNFXV1pJKRgOCLs-YyCjOJHLKL04zYj0X6KsOCTUeqhj7ml96wLZ-g1X9tyOR2WAr2Ctq7wIEHwqhxOLgOSKqm05xH6Vi3E_hekf50oe2jPfKEA",
+ TParserTickets::ServiceFlag()));
+ UNIT_ASSERT_EQUAL(TParserTickets::TStrRes({ETicketStatus::Malformed,
+ {},
+ {},
+ {}}),
+ TParserTickets::ParseStrV3("",
+ TParserTickets::ServiceFlag()));
+ UNIT_ASSERT_EQUAL(TParserTickets::TStrRes({ETicketStatus::Malformed,
+ {},
+ {},
+ {}}),
+ TParserTickets::ParseStrV3("'",
+ TParserTickets::ServiceFlag()));
+
+ // Invalid proto
+ UNIT_ASSERT_EQUAL(TParserTickets::TStrRes({ETicketStatus::Ok,
+ NUtils::Base64url2bin("YIDRCUkQYBgcIgdiYjpzZXNzIghiYjpzZXNzMg"),
+ NUtils::Base64url2bin("ERmeH_yzC7K_QsoHTyw7llCsyExEz3CoEopPIuivA0ZAtTaFq_Pa0l9Fhhx_NX9WpOp2CPyY5cFc4PXhcO83jCB7-EGvHNxGN-j2NQalERzPiKqkDCO0Q5etLzSzrfTlvMz7sXDvELNBHyA0PkAQnbz4supY0l-0Q6JBYSEF3zOVMjjE-HeQIFL3ats3_PakaUMWRvgQQ88pVdYZqAtbDw9PlTla7ommygVZQjcfNFXV1pJKRgOCLs-YyCjOJHLKL04zYj0X6KsOCTUeqhj7ml96wLZ-g1X9tyOR2WAr2Ctq7wIEHwqhxOLgOSKqm05xH6Vi3E_hekf50oe2jPfKEA"),
+ "3:serv:YIDRCUkQYBgcIgdiYjpzZXNzIghiYjpzZXNzMg:"}),
+ TParserTickets::ParseStrV3("3:serv:YIDRCUkQYBgcIgdiYjpzZXNzIghiYjpzZXNzMg:ERmeH_yzC7K_QsoHTyw7llCsyExEz3CoEopPIuivA0ZAtTaFq_Pa0l9Fhhx_NX9WpOp2CPyY5cFc4PXhcO83jCB7-EGvHNxGN-j2NQalERzPiKqkDCO0Q5etLzSzrfTlvMz7sXDvELNBHyA0PkAQnbz4supY0l-0Q6JBYSEF3zOVMjjE-HeQIFL3ats3_PakaUMWRvgQQ88pVdYZqAtbDw9PlTla7ommygVZQjcfNFXV1pJKRgOCLs-YyCjOJHLKL04zYj0X6KsOCTUeqhj7ml96wLZ-g1X9tyOR2WAr2Ctq7wIEHwqhxOLgOSKqm05xH6Vi3E_hekf50oe2jPfKEA",
+ TParserTickets::ServiceFlag()));
+ }
+
+ Y_UNIT_TEST(TicketsV3) {
+ NRw::TPublicKeys pub;
+
+ UNIT_ASSERT_EQUAL(ETicketStatus::Malformed,
+ TParserTickets::ParseV3("3:serv:CgYIDRCUkQYQDBgcIgdiYjpzZXNzIghiYjpzZXNzMg:ERme/*-+H_yzC7K_QsoHTyw7llCsyExEz3CoEopPIuivA0ZAtTaFq_Pa0l9Fhhx_NX9WpOp2CPyY5cFc4PXhcO83jCB7-EGvHNxGN-j2NQalERzPiKqkDCO0Q5etLzSzrfTlvMz7sXDvELNBHyA0PkAQnbz4supY0l-0Q6JBYSEF3zOVMjjE-HeQIFL3ats3_PakaUMWRvgQQ88pVdYZqAtbDw9PlTla7ommygVZQjcfNFXV1pJKRgOCLs-YyCjOJHLKL04zYj0X6KsOCTUeqhj7ml96wLZ-g1X9tyOR2WAr2Ctq7wIEHwqhxOLgOSKqm05xH6Vi3E_hekf50oe2jPfKEA",
+ pub,
+ TParserTickets::ServiceFlag())
+ .Status);
+
+ // Invalid proto
+ UNIT_ASSERT_EQUAL(ETicketStatus::Malformed,
+ TParserTickets::ParseV3("3:serv:YIDRCUkQYBgcIgdiYjpzZXNzIghiYjpzZXNzMg:ERmeH_yzC7K_QsoHTyw7llCsyExEz3CoEopPIuivA0ZAtTaFq_Pa0l9Fhhx_NX9WpOp2CPyY5cFc4PXhcO83jCB7-EGvHNxGN-j2NQalERzPiKqkDCO0Q5etLzSzrfTlvMz7sXDvELNBHyA0PkAQnbz4supY0l-0Q6JBYSEF3zOVMjjE-HeQIFL3ats3_PakaUMWRvgQQ88pVdYZqAtbDw9PlTla7ommygVZQjcfNFXV1pJKRgOCLs-YyCjOJHLKL04zYj0X6KsOCTUeqhj7ml96wLZ-g1X9tyOR2WAr2Ctq7wIEHwqhxOLgOSKqm05xH6Vi3E_hekf50oe2jPfKEA",
+ pub,
+ TParserTickets::ServiceFlag())
+ .Status);
+
+ // Expire time == 100500
+ UNIT_ASSERT_EQUAL(ETicketStatus::Expired,
+ TParserTickets::ParseV3("3:serv:CBAQlJEGIhcIDBAcGgdiYjpzZXNzGghiYjpzZXNzMg:HEzPbsjULegBvgX3nqwFX0GfVhESmN1kEWyeT7U03KAR-sQnNYgm6IuN-b9-lQYQKAJSW6p8ffyucC1yDrWSWRxXVzHJUxAVW4hnbiFDtXrurnEdpMK3izKbmTY25PJ4vH3_TkRXk-_oSAE8RvIFKXlh-aw1tezbXBUpJKvyJ0w",
+ pub,
+ TParserTickets::ServiceFlag())
+ .Status);
+
+ UNIT_ASSERT_EQUAL(ETicketStatus::MissingKey,
+ TParserTickets::ParseV3("3:serv:CBAQ__________9_IhcIDBAcGgdiYjpzZXNzGghiYjpzZXNzMg:OKjKEbygehEZWH0XEeLzvf0q0aS0VvSk_CKSXGdpqxPbE4RzU70jeM-X9rXVpbYjt76VgBLlBpumJdyiclulfGPDPiL8nwJuu8AnWIR_o-QqyXbsloo2_syE6w2aYw2Yw_5_qjnipYdxGUWegHAGCj3yeMde6O2BmNZ0OCfg6qU",
+ pub,
+ TParserTickets::ServiceFlag())
+ .Status);
+
+ pub.emplace(16, NRw::TRwPublicKey(NUtils::Base64url2bin("MIGEAoGBALhrihbf3EpjDQS2sCQHazoFgN0nBbE9eesnnFTfzQELXb2gnJU9enmV_aDqaHKjgtLIPpCgn40lHrn5k6mvH5OdedyI6cCzE-N-GFp3nAq0NDJyMe0fhtIRD__CbT0ulcvkeow65ubXWfw6dBC2gR_34rdMe_L_TGRLMWjDULbN")));
+ UNIT_ASSERT_EQUAL(ETicketStatus::SignBroken,
+ TParserTickets::ParseV3("3:serv:CBAQ__________9_IhcIDBAcGgdiYjpzZXNzGghiYjpzZXNzMa:OKjKEbygehEZWH0XEeLzvf0q0aS0VvSk_CKSXGdpqxPbE4RzU70jeM-X9rXVpbYjt76VgBLlBpumJdyiclulfGPDPiL8nwJuu8AnWIR_o-QqyXbsloo2_syE6w2aYw2Yw_5_qjnipYdxGUWegHAGCj3yeMde6O2BmNZ0OCfg6qU",
+ pub,
+ TParserTickets::ServiceFlag())
+ .Status);
+ UNIT_ASSERT_EQUAL(ETicketStatus::SignBroken,
+ TParserTickets::ParseV3("3:serv:CBAQ__________9_IhcIDBAcGgdiYjpzZXNzGghiYjpzZXNzMg:OKjKEbygehEZWH0XEeLzvf0q0aS0VvSk_CKSXGdpqxPbE4RzU70jeM-X9rXVpbYjt76VgBLlBpumJdyiclulfGPDPiL8nwJuu8AnWIR_o-QqyXbsloo2_syE6w2aYw2Yw_5_qjnipYdxGUWegHAGCj3yeMde6O2BmNZ0OCfg6qa",
+ pub,
+ TParserTickets::ServiceFlag())
+ .Status);
+ UNIT_ASSERT_EQUAL(ETicketStatus::SignBroken,
+ TParserTickets::ParseV3("3:serv:CBAQ__________9_IhcIDBAcGgdiYjpzZXNzGghiYjpzZXNzMg:EbygehEZWH0XEeLzvf0q0aS0VvSk_CKSXGdpqxPbE4RzU70jeM-X9rXVpbYjt76VgBLlBpumJdyiclulfGPDPiL8nwJuu8AnWIR_o-QqyXbsloo2_syE6w2aYw2Yw_5_qjnipYdxGUWegHAGCj3yeMde6O2BmNZ0OCfg6qU",
+ pub,
+ TParserTickets::ServiceFlag())
+ .Status);
+
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok,
+ TParserTickets::ParseV3("3:serv:CBAQ__________9_IhcIDBAcGgdiYjpzZXNzGghiYjpzZXNzMg:OKjKEbygehEZWH0XEeLzvf0q0aS0VvSk_CKSXGdpqxPbE4RzU70jeM-X9rXVpbYjt76VgBLlBpumJdyiclulfGPDPiL8nwJuu8AnWIR_o-QqyXbsloo2_syE6w2aYw2Yw_5_qjnipYdxGUWegHAGCj3yeMde6O2BmNZ0OCfg6qU",
+ pub,
+ TParserTickets::ServiceFlag())
+ .Status);
+ }
+}
diff --git a/library/cpp/tvmauth/src/ut/public_ut.cpp b/library/cpp/tvmauth/src/ut/public_ut.cpp
new file mode 100644
index 0000000000..74a483d57b
--- /dev/null
+++ b/library/cpp/tvmauth/src/ut/public_ut.cpp
@@ -0,0 +1,290 @@
+// DO_NOT_STYLE
+#include <library/cpp/tvmauth/src/service_impl.h>
+#include <library/cpp/tvmauth/src/user_impl.h>
+
+#include <library/cpp/tvmauth/exception.h>
+#include <library/cpp/tvmauth/ticket_status.h>
+#include <library/cpp/tvmauth/unittest.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NTvmAuth;
+
+Y_UNIT_TEST_SUITE(CommonPublicInterfaceTestSuite){
+ Y_UNIT_TEST(StatusTest){
+ UNIT_ASSERT_VALUES_EQUAL("OK",
+ StatusToString(ETicketStatus::Ok));
+ UNIT_ASSERT_VALUES_EQUAL("Expired ticket",
+ StatusToString(ETicketStatus::Expired));
+ UNIT_ASSERT_VALUES_EQUAL("Invalid BlackBox environment",
+ StatusToString(ETicketStatus::InvalidBlackboxEnv));
+ UNIT_ASSERT_VALUES_EQUAL("Invalid ticket destination",
+ StatusToString(ETicketStatus::InvalidDst));
+ UNIT_ASSERT_VALUES_EQUAL("Invalid ticket type",
+ StatusToString(ETicketStatus::InvalidTicketType));
+ UNIT_ASSERT_VALUES_EQUAL("Malformed ticket",
+ StatusToString(ETicketStatus::Malformed));
+ UNIT_ASSERT_VALUES_EQUAL("Invalid ticket signature",
+ StatusToString(ETicketStatus::SignBroken));
+ UNIT_ASSERT_VALUES_EQUAL("Context does not have required key to check ticket: public keys are too old",
+ StatusToString(ETicketStatus::MissingKey));
+ UNIT_ASSERT_VALUES_EQUAL("Unsupported ticket version",
+ StatusToString(ETicketStatus::UnsupportedVersion));
+ }
+}
+
+Y_UNIT_TEST_SUITE(PublicInterfaceServiceTestSuite) {
+ static const TString EMPTY_TVM_KEYS = "1:CpgCCpMCCAEQABqIAjCCAQQCggEAcLEXeH67FQESFUn4_7wnX7wN0PUrBoUsm3QQ4W5vC-qz6sXaEjSwnTV8w1o-z6X9KPLlhzMQvuS38NCNfK4uvJ4Zvfp3YsXJ25-rYtbnrYJHNvHohD-kPCCw_yZpMp21JdWigzQGuV7CtrxUhF-NNrsnUaJrE5-OpEWNt4X6nCItKIYeVcSK6XJUbEWbrNCRbvkSc4ak2ymFeMuHYJVjxh4eQbk7_ZPzodP0WvF6eUYrYeb42imVEOR8ofVLQWE5DVnb1z_TqZm4i1XkS7jMwZuBxBRw8DGdYei0lT_sAf7KST2jC0590NySB3vsBgWEVs1OdUUWA6r-Dvx9dsOQtSCVkQYQAAqZAgqUAggCEAAaiQIwggEFAoIBAQDhEBM5-6YsPWfogKtbluJoCX1WV2KdzOaQ0-OlRbBzeCzw-eQKu12c8WakHBbeCMd1I1TU64SDkDorWjXGIa_2xT6N3zzNAE50roTbPCcmeQrps26woTYfYIuqDdoxYKZNr0lvNLLW47vBr7EKqo1S4KSj7aXK_XYeEvUgIgf3nVIcNrio7VTnFmGGVQCepaL1Hi1gN4yIXjVZ06PBPZ-DxSRu6xOGbFrfKMJeMPs7KOyE-26Q3xOXdTIa1X-zYIucTd_bxUCL4BVbwW2AvbbFsaG7ISmVdGu0XUTmhXs1KrEfUVLRJhE4Dx99hAZXm1_HlYMUeJcMQ_oHOhV94ENFIJaRBhACCpYBCpEBCAMQABqGATCBgwKBgF9t2YJGAJkRRFq6fWhi3m1TFW1UOE0f6ZrfYhHAkpqGlKlh0QVfeTNPpeJhi75xXzCe6oReRUm-0DbqDNhTShC7uGUv1INYnRBQWH6E-5Fc5XrbDFSuGQw2EYjNfHy_HefHJXxQKAqPvxBDKMKkHgV58WtM6rC8jRi9sdX_ig2NIJeRBhABCpYBCpEBCAQQABqGATCBgwKBgGB4d6eLGUBv-Q6EPLehC4S-yuE2HB-_rJ7WkeYwyp-xIPolPrd-PQme2utHB4ZgpXHIu_OFksDe_0bPgZniNRSVRbl7W49DgS5Ya3kMfrYB4DnF5Fta5tn1oV6EwxYD4JONpFTenOJALPGTPawxXEfon_peiHOSBuQMu3_Vn-l1IJiRBhADCpcBCpIBCAUQABqHATCBhAKBgQCTJMKIfmfeZpaI7Q9rnsc29gdWawK7TnpVKRHws1iY7EUlYROeVcMdAwEqVM6f8BVCKLGgzQ7Gar_uuxfUGKwqEQzoppDraw4F75J464-7D5f6_oJQuGIBHZxqbMONtLjBCXRUhQW5szBLmTQ_R3qaJb5vf-h0APZfkYhq1cTttSCZkQYQBAqWAQqRAQgLEAAahgEwgYMCgYBvvGVH_M2H8qxxv94yaDYUTWbRnJ1uiIYc59KIQlfFimMPhSS7x2tqUa2-hI55JiII0Xym6GNkwLhyc1xtWChpVuIdSnbvttbrt4weDMLHqTwNOF6qAsVKGKT1Yh8yf-qb-DSmicgvFc74mBQm_6gAY1iQsf33YX8578ClhKBWHSCVkQYQAAqXAQqSAQgMEAAahwEwgYQCgYEAkuzFcd5TJu7lYWYe2hQLFfUWIIj91BvQQLa_Thln4YtGCO8gG1KJqJm-YlmJOWQG0B7H_5RVhxUxV9KpmFnsDVkzUFKOsCBaYGXc12xPVioawUlAwp5qp3QQtZyx_se97YIoLzuLr46UkLcLnkIrp-Jo46QzYi_QHq45WTm8MQ0glpEGEAIKlwEKkgEIDRAAGocBMIGEAoGBAIUzbxOknXf_rNt17_ir8JlWvrtnCWsQd1MAnl5mgArvavDtKeBYHzi5_Ak7DHlLzuA6YE8W175FxLFKpN2hkz-l-M7ltUSd8N1BvJRhK4t6WffWfC_1wPyoAbeSN2Yb1jygtZJQ8wGoXHcJQUXiMit3eFNyylwsJFj1gzAR4JCdIJeRBhABCpYBCpEBCA4QABqGATCBgwKBgFMcbEpl9ukVR6AO_R6sMyiU11I8b8MBSUCEC15iKsrVO8v_m47_TRRjWPYtQ9eZ7o1ocNJHaGUU7qqInFqtFaVnIceP6NmCsXhjs3MLrWPS8IRAy4Zf4FKmGOx3N9O2vemjUygZ9vUiSkULdVrecinRaT8JQ5RG4bUMY04XGIwFIJiRBhADCpYBCpEBCA8QABqGATCBgwKBgGpCkW-NR3li8GlRvqpq2YZGSIgm_PTyDI2Zwfw69grsBmPpVFW48Vw7xoMN35zcrojEpialB_uQzlpLYOvsMl634CRIuj-n1QE3-gaZTTTE8mg-AR4mcxnTKThPnRQpbuOlYAnriwiasWiQEMbGjq_HmWioYYxFo9USlklQn4-9IJmRBhAE";
+ static const TString EXPIRED_SERVICE_TICKET = "3:serv:CBAQACIZCOUBEBwaCGJiOnNlc3MxGghiYjpzZXNzMg:IwfMNJYEqStY_SixwqJnyHOMCPR7-3HHk4uylB2oVRkthtezq-OOA7QizDvx7VABLs_iTlXuD1r5IjufNei_EiV145eaa3HIg4xCdJXCojMexf2UYJz8mF2b0YzFAy6_KWagU7xo13CyKAqzJuQf5MJcSUf0ecY9hVh36cJ51aw";
+ static const TString MALFORMED_TVM_KEYS = "1:CpgCCpMCCAEQABqIAjCCAQQCggEAcLEXeH67FQESFUn4_7wnX7wN0PUrBoUsm3QQ4W5vC-qz6sXaEjSwnTV8w1o-z6X9KPLlhzMQvuS38NCNfK4uvJ4Zvfp3YsXJ25-rYtbnrYJHNvHohD-kPCCw_yZpMp21JdWigzQGuV7CtrxUhF-NNrsnUaJrE5-OpEWNt4X6nCItKIYeVcSK6XJUbEWbrNCRbvkSc4ak2ymFeMuHYJVjxh4eQbk7_ZPzodP0WvF6eUYrYeb42imVEOR8ofVLQWE5DVnb1z_TqZm4i1XkS7jMwZuBxBRw8DGdYei0lT_sAf7KST2jC0590NySB3vsBgWEVs1OdUUWA6r-Dvx9dsOQtSCVkQYQAAqZAgqUAggCEAAaiQIwggEFAoIBAQDhEBM5-6YsPWfogKtbluJoCX1WV2KdzOaQ0-OlRbBzeCzw-eQKu12c8WakHBbeCMd1I1TU64SDkDorWjXGIa_2xT6N3zzNAE50roTbPCcmeQrps26woTYfYIuqDdoxYKZNr0lvNLLW47vBr7EKqo1S4KSj7aXK_XYeEvUgIgf3nVIcNrio7VTnFmGGVQCepaL1Hi1gN4yIXjVZ06PBPZ-DxSRu6xOGbFrfKMJeMPs7KOyE-26Q3xOXdTIa1X-zYIucTd_bxUCL4BVbwW2AvbbFsaG7ISmVdGu0XUTmhXs1KrEfUVLRJhE4Dx99hAZXm1_HlYMUeJcMQ_oHOhV94ENFIJaRBhACCpYBCpEBCAMQABqGATCBgwKBgF9t2YJGAJkRRFq6fWhi3m1TFW1UOE0f6ZrfYhHAkpqGlKlh0QVfeTNPpeJhi75xXzCe6oReRUm-0DbqDNhTShC7uGUv1INYnRBQWH6E-5Fc5XrbDFSuGQw2EYjNfHy_HefHJXxQKAqPvxBDKMKkHgV58WtM6rC8jRi9sdX_ig2NIJeRBhABCpYBCpEBCAQQABqGATCBgwKBgGB4d6eLGUBv-Q6EPLehC4S-yuE2HB-_rJ7WkeYwyp-xIPolPrd-PQme2utHB4ZgpXHIu_OFksDe_0bPgZniNRSVRbl7W49DgS5Ya3kMfrYB4DnF5Fta5tn1oV6EwxYD4JONpFTenOJALPGTPawxXEfon_peiHOSBuQMu3_Vn-l1IJiRBhADCpcBCpIBCAUQABqHATCBhAKBgQCTJMKIfmfeZpaI7Q9rnsc29gdWawK7TnpVKRHws1iY7EUlYROeVcMdAwEqVM6f8BVCKLGgzQ7Gar_uuxfUGKwqEQzoppDraw4F75J464-7D5f6_oJQuGIBHZxqbMONtLjBCXRUhQW5szBLmTQ_R3qaJb5vf-h0APZfkYhq1cTttSCZkQYQBAqWAQqRAQgLEAAahgEwgYMCgYBvvGVH_M2H8qxxv94yaDYUTWbRnJ1uiIYc59KIQlfFimMPhSS7x2tqUa2-hI55JiII0Xym6GNkwLhyc1xtWChpVuIdSnbvttbrt4weDMLHqTwNOF6qAsVKGKT1Yh8yf-qb-DSmicgvFc74mBQm_6gAY1iQsf33YX8578ClhKBWHSCVkQYQAAqXAQqSAQgMEAAahwEwgYQCgYEAkuzFcd5TJu7lYWYe2hQLFfUWIIj91BvQQLa_Thln4YtGCO8gG1KJqJm-YlmJOWQG0B7H_5RVhxUxV9KpmFnsDVkzUFKOsCBaYGXc12xPVioawUlAwp5qp3QQtZyx_se97YIoLzuLr46UkLcLnkIrp-Jo46QzYi_QHq45WTm8MQ0glpEGEAIKlwEKkgEIDRAAGocBMIGEAoGBAIUzbxOknXf_rNt17_ir8JlWvrtnCWsQd1MAnl5mgArvavDtKeBYHzi5_Ak7DHlLzuA6YE8W175FxLFKpN2hkz-l-M7ltUSd8N1BvJRhK4t6WffWfC_1wPyoAbeSN2Yb1jygtZJQ8wGoXHcJQUXiMit3eFNyylwsJFj1gzAR4JCdIJeRBhABCpYBCpEBCA4QABqGATCBgwKBgFMcbEpl9ukVR6AO_R6sMyiU11I8b8MBSUCEC15iKsrVO8v_m47_TRRjWPYtQ9eZ7o1ocNJHaGUU7qqInFqtFaVnIceP6NmCsXhjs3MLrWPS8IRAy4Zf4FKmGOx3N9O2vemjUygZ9vUiSkULdVrecinRaT8JQ5RG4bUMY04XGIwFIJiRBhADCpYBCpEBCA8QABqGATCBgwKBgGpCkW-NR3li8GlRvqpq2YZGSIgm_PTyDI2Zwfw69grsBmPpVFW48Vw7xoMN35zcrojEpialB_uQzlpLYOvsMl634CRIuj-n1QE3-gaZTTTE8mg-AR4mcxnTKThPnRQpbuOlYAnriwiasWiQEMbGjq_HmWioYYxFo9USlklQn4-9IJmRBhAEEpUBCpIBCAYQABqHATCBhAKBgQCoZkFGm9oLTqjeXZAq6j5S6i7K20V0lNdBBLqfmFBIRuTkYxhs4vUYnWjZrKRAd5bp6_py0csmFmpl_5Yh0b-2pdo_E5PNP7LGRzKyKSiFddyykKKzVOazH8YYldDAfE8Z5HoS9e48an5JsPg0jr-TPu34DnJq3yv2a6dqiKL9zSCakQYSlQEKkgEIEBAAGocBMIGEAoGBALhrihbf3EpjDQS2sCQHazoFgN0nBbE9eesnnFTfzQELXb2gnJU9enmV_aDqaHKjgtLIPpCgn40lHrn5k6mvH5OdedyI6cCzE-N-GFp3nAq0NDJyMe0fhtIRD__CbT0ulcvkeow65ubXWfw6dBC2gR_34rdMe_L_TGRLMWjDULbNIJ";
+ static const TString MALFORMED_TVM_SECRET = "adcvxcv./-+";
+ static const TTvmId NOT_OUR_ID = 27;
+ static const TTvmId OUR_ID = 28;
+ static const TString SECRET = "GRMJrKnj4fOVnvOqe-WyD1";
+ static const TString SERVICE_TICKET_PROTOBUF = "CBAQ__________9_IhkI5QEQHBoIYmI6c2VzczEaCGJiOnNlc3My";
+ static const TTvmId SRC_ID = 229;
+ static const TString UNSUPPORTED_VERSION_SERVICE_TICKET = "2:serv:CBAQ__________9_IhkI5QEQHBoIYmI6c2VzczEaCGJiOnNlc3My:WUPx1cTf05fjD1exB35T5j2DCHWH1YaLJon_a4rN-D7JfXHK1Ai4wM4uSfboHD9xmGQH7extqtlEk1tCTCGm5qbRVloJwWzCZBXo3zKX6i1oBYP_89WcjCNPVe1e8jwGdLsnu6PpxL5cn0xCksiStILH5UmDR6xfkJdnmMG94o8";
+ static const TString VALID_SERVICE_TICKET_1 = "3:serv:CBAQ__________9_IhkI5QEQHBoIYmI6c2VzczEaCGJiOnNlc3My:WUPx1cTf05fjD1exB35T5j2DCHWH1YaLJon_a4rN-D7JfXHK1Ai4wM4uSfboHD9xmGQH7extqtlEk1tCTCGm5qbRVloJwWzCZBXo3zKX6i1oBYP_89WcjCNPVe1e8jwGdLsnu6PpxL5cn0xCksiStILH5UmDR6xfkJdnmMG94o8";
+ static const TString VALID_SERVICE_TICKET_2 = "3:serv:CBAQ__________9_IskICOUBEBwaCGJiOnNlc3MxGgliYjpzZXNzMTAaCmJiOnNlc3MxMDAaCWJiOnNlc3MxMRoJYmI6c2VzczEyGgliYjpzZXNzMTMaCWJiOnNlc3MxNBoJYmI6c2VzczE1GgliYjpzZXNzMTYaCWJiOnNlc3MxNxoJYmI6c2VzczE4GgliYjpzZXNzMTkaCGJiOnNlc3MyGgliYjpzZXNzMjAaCWJiOnNlc3MyMRoJYmI6c2VzczIyGgliYjpzZXNzMjMaCWJiOnNlc3MyNBoJYmI6c2VzczI1GgliYjpzZXNzMjYaCWJiOnNlc3MyNxoJYmI6c2VzczI4GgliYjpzZXNzMjkaCGJiOnNlc3MzGgliYjpzZXNzMzAaCWJiOnNlc3MzMRoJYmI6c2VzczMyGgliYjpzZXNzMzMaCWJiOnNlc3MzNBoJYmI6c2VzczM1GgliYjpzZXNzMzYaCWJiOnNlc3MzNxoJYmI6c2VzczM4GgliYjpzZXNzMzkaCGJiOnNlc3M0GgliYjpzZXNzNDAaCWJiOnNlc3M0MRoJYmI6c2VzczQyGgliYjpzZXNzNDMaCWJiOnNlc3M0NBoJYmI6c2VzczQ1GgliYjpzZXNzNDYaCWJiOnNlc3M0NxoJYmI6c2VzczQ4GgliYjpzZXNzNDkaCGJiOnNlc3M1GgliYjpzZXNzNTAaCWJiOnNlc3M1MRoJYmI6c2VzczUyGgliYjpzZXNzNTMaCWJiOnNlc3M1NBoJYmI6c2VzczU1GgliYjpzZXNzNTYaCWJiOnNlc3M1NxoJYmI6c2VzczU4GgliYjpzZXNzNTkaCGJiOnNlc3M2GgliYjpzZXNzNjAaCWJiOnNlc3M2MRoJYmI6c2VzczYyGgliYjpzZXNzNjMaCWJiOnNlc3M2NBoJYmI6c2VzczY1GgliYjpzZXNzNjYaCWJiOnNlc3M2NxoJYmI6c2VzczY4GgliYjpzZXNzNjkaCGJiOnNlc3M3GgliYjpzZXNzNzAaCWJiOnNlc3M3MRoJYmI6c2VzczcyGgliYjpzZXNzNzMaCWJiOnNlc3M3NBoJYmI6c2Vzczc1GgliYjpzZXNzNzYaCWJiOnNlc3M3NxoJYmI6c2Vzczc4GgliYjpzZXNzNzkaCGJiOnNlc3M4GgliYjpzZXNzODAaCWJiOnNlc3M4MRoJYmI6c2VzczgyGgliYjpzZXNzODMaCWJiOnNlc3M4NBoJYmI6c2Vzczg1GgliYjpzZXNzODYaCWJiOnNlc3M4NxoJYmI6c2Vzczg4GgliYjpzZXNzODkaCGJiOnNlc3M5GgliYjpzZXNzOTAaCWJiOnNlc3M5MRoJYmI6c2VzczkyGgliYjpzZXNzOTMaCWJiOnNlc3M5NBoJYmI6c2Vzczk1GgliYjpzZXNzOTYaCWJiOnNlc3M5NxoJYmI6c2Vzczk4GgliYjpzZXNzOTk:JYmABAVLM6y7_T4n1pRcwBfwDfzMV4JJ3cpbEG617zdGgKRZwL7MalsYn5bq1F2ibujMrsF9nzZf8l4s_e-Ivjkz_xu4KMzSp-pUh9V7XIF_smj0WHYpv6gOvWNuK8uIvlZTTKwtQX0qZOL9m-MEeZiHoQPKZGCfJ_qxMUp-J8I";
+ static const TString VALID_SERVICE_TICKET_3 = "3:serv:CBAQ__________9_IgUI5QEQHA:Sd6tmA1CNy2Nf7XevC3x7zr2DrGNRmcl-TxUsDtDW2xI3YXyCxBltWeg0-KtDlqyYuPOP5Jd_-XXNA12KlOPnNzrz3jm-5z8uQl6CjCcrVHUHJ75pGC8r9UOlS8cOgeXQB5dYP-fOWyo5CNadlozx1S2meCIxncbQRV1kCBi4KU";
+
+ Y_UNIT_TEST(BlackboxTvmIdTest) {
+ UNIT_ASSERT_VALUES_EQUAL("222", NBlackboxTvmId::Prod);
+ UNIT_ASSERT_VALUES_EQUAL("224", NBlackboxTvmId::Test);
+ UNIT_ASSERT_VALUES_EQUAL("223", NBlackboxTvmId::ProdYateam);
+ UNIT_ASSERT_VALUES_EQUAL("225", NBlackboxTvmId::TestYateam);
+ UNIT_ASSERT_VALUES_EQUAL("226", NBlackboxTvmId::Stress);
+ UNIT_ASSERT_VALUES_EQUAL("239", NBlackboxTvmId::Mimino);
+ }
+
+ Y_UNIT_TEST(Case1Test) {
+ TServiceContext context1(SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ TServiceContext context2 = std::move(context1);
+ TServiceContext context3(std::move(context2));
+
+ TCheckedServiceTicket checkedTicket1 = context3.Check(VALID_SERVICE_TICKET_1);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket1.GetStatus());
+ TCheckedServiceTicket checkedTicket2 = std::move(checkedTicket1);
+ TCheckedServiceTicket checkedTicket3(std::move(checkedTicket2));
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket3.GetStatus());
+ }
+
+ Y_UNIT_TEST(ContextExceptionsTest) {
+ UNIT_ASSERT_EXCEPTION(TServiceContext(SECRET, OUR_ID, MALFORMED_TVM_KEYS), TMalformedTvmKeysException);
+ UNIT_ASSERT_EXCEPTION(TServiceContext(SECRET, OUR_ID, EMPTY_TVM_KEYS), TEmptyTvmKeysException);
+ UNIT_ASSERT_EXCEPTION(TServiceContext(MALFORMED_TVM_SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS), TMalformedTvmSecretException);
+ }
+
+ Y_UNIT_TEST(ContextSignTest) {
+ TServiceContext context(SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ UNIT_ASSERT_VALUES_EQUAL(
+ "NsPTYak4Cfk-4vgau5lab3W4GPiTtb2etuj3y4MDPrk",
+ context.SignCgiParamsForTvm(IntToString<10>(std::numeric_limits<time_t>::max()), "13,28", ""));
+ }
+
+ Y_UNIT_TEST(ContextSignExceptionTest) {
+ TServiceContext context = TServiceContext::CheckingFactory(OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ UNIT_ASSERT_EXCEPTION(
+ context.SignCgiParamsForTvm(IntToString<10>(std::numeric_limits<time_t>::max()), "13,28", ""),
+ TMalformedTvmSecretException
+ );
+
+ context = TServiceContext::SigningFactory(SECRET);
+ UNIT_ASSERT_NO_EXCEPTION(
+ context.SignCgiParamsForTvm(IntToString<10>(std::numeric_limits<time_t>::max()), "13,28", "")
+ );
+ }
+
+ Y_UNIT_TEST(ContextCheckExceptionTest) {
+ TServiceContext context = TServiceContext::CheckingFactory(OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ UNIT_ASSERT_NO_EXCEPTION(
+ context.Check("ABCDE")
+ );
+
+ context = TServiceContext::SigningFactory(SECRET);
+ UNIT_ASSERT_EXCEPTION(
+ context.Check("ABCDE"),
+ TEmptyTvmKeysException
+ );
+ }
+
+
+ Y_UNIT_TEST(ContextTest) {
+ TServiceContext context1(SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ TServiceContext context2 = TServiceContext::CheckingFactory(OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ }
+
+ Y_UNIT_TEST(Ticket1Test) {
+ TServiceContext context(SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(VALID_SERVICE_TICKET_1);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket.GetStatus());
+ UNIT_ASSERT_EQUAL(SRC_ID, checkedTicket.GetSrc());
+ UNIT_ASSERT_EQUAL("ticket_type=serv;expiration_time=9223372036854775807;src=229;dst=28;scope=bb:sess1;scope=bb:sess2;", checkedTicket.DebugInfo());
+ }
+
+ Y_UNIT_TEST(Ticket2Test) {
+ TServiceContext context(SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(VALID_SERVICE_TICKET_2);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket.GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL("ticket_type=serv;expiration_time=9223372036854775807;src=229;dst=28;scope=bb:sess1;scope=bb:sess10;scope=bb:sess100;scope=bb:sess11;scope=bb:sess12;scope=bb:sess13;scope=bb:sess14;scope=bb:sess15;scope=bb:sess16;scope=bb:sess17;scope=bb:sess18;scope=bb:sess19;scope=bb:sess2;scope=bb:sess20;scope=bb:sess21;scope=bb:sess22;scope=bb:sess23;scope=bb:sess24;scope=bb:sess25;scope=bb:sess26;scope=bb:sess27;scope=bb:sess28;scope=bb:sess29;scope=bb:sess3;scope=bb:sess30;scope=bb:sess31;scope=bb:sess32;scope=bb:sess33;scope=bb:sess34;scope=bb:sess35;scope=bb:sess36;scope=bb:sess37;scope=bb:sess38;scope=bb:sess39;scope=bb:sess4;scope=bb:sess40;scope=bb:sess41;scope=bb:sess42;scope=bb:sess43;scope=bb:sess44;scope=bb:sess45;scope=bb:sess46;scope=bb:sess47;scope=bb:sess48;scope=bb:sess49;scope=bb:sess5;scope=bb:sess50;scope=bb:sess51;scope=bb:sess52;scope=bb:sess53;scope=bb:sess54;scope=bb:sess55;scope=bb:sess56;scope=bb:sess57;scope=bb:sess58;scope=bb:sess59;scope=bb:sess6;scope=bb:sess60;scope=bb:sess61;scope=bb:sess62;scope=bb:sess63;scope=bb:sess64;scope=bb:sess65;scope=bb:sess66;scope=bb:sess67;scope=bb:sess68;scope=bb:sess69;scope=bb:sess7;scope=bb:sess70;scope=bb:sess71;scope=bb:sess72;scope=bb:sess73;scope=bb:sess74;scope=bb:sess75;scope=bb:sess76;scope=bb:sess77;scope=bb:sess78;scope=bb:sess79;scope=bb:sess8;scope=bb:sess80;scope=bb:sess81;scope=bb:sess82;scope=bb:sess83;scope=bb:sess84;scope=bb:sess85;scope=bb:sess86;scope=bb:sess87;scope=bb:sess88;scope=bb:sess89;scope=bb:sess9;scope=bb:sess90;scope=bb:sess91;scope=bb:sess92;scope=bb:sess93;scope=bb:sess94;scope=bb:sess95;scope=bb:sess96;scope=bb:sess97;scope=bb:sess98;scope=bb:sess99;", checkedTicket.DebugInfo());
+ }
+
+ Y_UNIT_TEST(Ticket3Test) {
+ TServiceContext context(SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(VALID_SERVICE_TICKET_3);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket.GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL("ticket_type=serv;expiration_time=9223372036854775807;src=229;dst=28;", checkedTicket.DebugInfo());
+ }
+
+ Y_UNIT_TEST(TicketCheckingTest) {
+ TServiceContext context(SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto ticket = context.Check(VALID_SERVICE_TICKET_1);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, ticket.GetStatus());
+ UNIT_ASSERT_EQUAL(SRC_ID, ticket.GetSrc());
+ }
+
+ Y_UNIT_TEST(TicketErrorsTest) {
+ TServiceContext context(SECRET, NOT_OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket1 = context.Check(VALID_SERVICE_TICKET_1);
+ UNIT_ASSERT_EQUAL(ETicketStatus::InvalidDst, checkedTicket1.GetStatus());
+
+ auto checkedTicket2 = context.Check(UNSUPPORTED_VERSION_SERVICE_TICKET);
+ UNIT_ASSERT_EQUAL(ETicketStatus::UnsupportedVersion, checkedTicket2.GetStatus());
+
+ auto checkedTicket3 = context.Check(EXPIRED_SERVICE_TICKET);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Expired, checkedTicket3.GetStatus());
+ }
+
+ Y_UNIT_TEST(TicketExceptionsTest) {
+ TServiceContext context(SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(EXPIRED_SERVICE_TICKET);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Expired, checkedTicket.GetStatus());
+
+ UNIT_ASSERT(!bool(checkedTicket));
+ UNIT_ASSERT_EXCEPTION(checkedTicket.GetSrc(), TNotAllowedException);
+ UNIT_ASSERT_NO_EXCEPTION(bool(checkedTicket));
+ UNIT_ASSERT_NO_EXCEPTION(checkedTicket.DebugInfo());
+ UNIT_ASSERT_NO_EXCEPTION(checkedTicket.GetStatus());
+ }
+
+ Y_UNIT_TEST(RemoveSignatureTest) {
+ UNIT_ASSERT_VALUES_EQUAL("1:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:asdxcvbxcvniueliuweklsvds",
+ NUtils::RemoveTicketSignature("1:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:asdxcvbxcvniueliuweklsvds"));
+ UNIT_ASSERT_VALUES_EQUAL("2:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:asdxcvbxcvniueliuweklsvds",
+ NUtils::RemoveTicketSignature("2:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:asdxcvbxcvniueliuweklsvds"));
+ UNIT_ASSERT_VALUES_EQUAL("4:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:asdxcvbxcvniueliuweklsvds",
+ NUtils::RemoveTicketSignature("4:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:asdxcvbxcvniueliuweklsvds"));
+ UNIT_ASSERT_VALUES_EQUAL("3.serv.ASDkljbjhsdbfLJHABFJHBslfbsfjs.asdxcvbxcvniueliuweklsvds",
+ NUtils::RemoveTicketSignature("3.serv.ASDkljbjhsdbfLJHABFJHBslfbsfjs.asdxcvbxcvniueliuweklsvds"));
+ UNIT_ASSERT_VALUES_EQUAL("3:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:",
+ NUtils::RemoveTicketSignature("3:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:asdxcvbxcvniueliuweklsvds"));
+ UNIT_ASSERT_VALUES_EQUAL("3:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:",
+ NUtils::RemoveTicketSignature("3:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:asdxcvbxcvniueliuweklsvds"));
+ UNIT_ASSERT_VALUES_EQUAL("3:serv:",
+ NUtils::RemoveTicketSignature("3:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs.asdxcvbxcvniueliuweklsvds"));
+ UNIT_ASSERT_VALUES_EQUAL("asdxcbvfgdsgfasdfxczvdsgfxcdvbcbvf",
+ NUtils::RemoveTicketSignature("asdxcbvfgdsgfasdfxczvdsgfxcdvbcbvf"));
+ }
+
+ Y_UNIT_TEST(ResetKeysTest) {
+ TServiceContext context(SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ TCheckedServiceTicket checkedTicket = context.Check(VALID_SERVICE_TICKET_1);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket.GetStatus());
+ }
+}
+
+Y_UNIT_TEST_SUITE(PublicInterfaceUserTestSuite) {
+ static const TString EMPTY_TVM_KEYS = "1:EpUBCpIBCAYQABqHATCBhAKBgQCoZkFGm9oLTqjeXZAq6j5S6i7K20V0lNdBBLqfmFBIRuTkYxhs4vUYnWjZrKRAd5bp6_py0csmFmpl_5Yh0b-2pdo_E5PNP7LGRzKyKSiFddyykKKzVOazH8YYldDAfE8Z5HoS9e48an5JsPg0jr-TPu34DnJq3yv2a6dqiKL9zSCakQY";
+ static const TString EXPIRED_USER_TICKET = "3:user:CA0QABokCgMIyAMKAgh7EMgDGghiYjpzZXNzMRoIYmI6c2VzczIgEigB:D0CmYVwWg91LDYejjeQ2UP8AeiA_mr1q1CUD_lfJ9zQSEYEOYGDTafg4Um2rwOOvQnsD1JHM4zHyMUJ6Jtp9GAm5pmhbXBBZqaCcJpyxLTEC8a81MhJFCCJRvu_G1FiAgRgB25gI3HIbkvHFUEqAIC_nANy7NFQnbKk2S-EQPGY";
+ static const TString MALFORMED_TVM_KEYS = "1:CpgCCpMCCAEQABqIAjCCAQQCggEAcLEXeH67FQESFUn4_7wnX7wN0PUrBoUsm3QQ4W5vC-qz6sXaEjSwnTV8w1o-z6X9KPLlhzMQvuS38NCNfK4uvJ4Zvfp3YsXJ25-rYtbnrYJHNvHohD-kPCCw_yZpMp21JdWigzQGuV7CtrxUhF-NNrsnUaJrE5-OpEWNt4X6nCItKIYeVcSK6XJUbEWbrNCRbvkSc4ak2ymFeMuHYJVjxh4eQbk7_ZPzodP0WvF6eUYrYeb42imVEOR8ofVLQWE5DVnb1z_TqZm4i1XkS7jMwZuBxBRw8DGdYei0lT_sAf7KST2jC0590NySB3vsBgWEVs1OdUUWA6r-Dvx9dsOQtSCVkQYQAAqZAgqUAggCEAAaiQIwggEFAoIBAQDhEBM5-6YsPWfogKtbluJoCX1WV2KdzOaQ0-OlRbBzeCzw-eQKu12c8WakHBbeCMd1I1TU64SDkDorWjXGIa_2xT6N3zzNAE50roTbPCcmeQrps26woTYfYIuqDdoxYKZNr0lvNLLW47vBr7EKqo1S4KSj7aXK_XYeEvUgIgf3nVIcNrio7VTnFmGGVQCepaL1Hi1gN4yIXjVZ06PBPZ-DxSRu6xOGbFrfKMJeMPs7KOyE-26Q3xOXdTIa1X-zYIucTd_bxUCL4BVbwW2AvbbFsaG7ISmVdGu0XUTmhXs1KrEfUVLRJhE4Dx99hAZXm1_HlYMUeJcMQ_oHOhV94ENFIJaRBhACCpYBCpEBCAMQABqGATCBgwKBgF9t2YJGAJkRRFq6fWhi3m1TFW1UOE0f6ZrfYhHAkpqGlKlh0QVfeTNPpeJhi75xXzCe6oReRUm-0DbqDNhTShC7uGUv1INYnRBQWH6E-5Fc5XrbDFSuGQw2EYjNfHy_HefHJXxQKAqPvxBDKMKkHgV58WtM6rC8jRi9sdX_ig2NIJeRBhABCpYBCpEBCAQQABqGATCBgwKBgGB4d6eLGUBv-Q6EPLehC4S-yuE2HB-_rJ7WkeYwyp-xIPolPrd-PQme2utHB4ZgpXHIu_OFksDe_0bPgZniNRSVRbl7W49DgS5Ya3kMfrYB4DnF5Fta5tn1oV6EwxYD4JONpFTenOJALPGTPawxXEfon_peiHOSBuQMu3_Vn-l1IJiRBhADCpcBCpIBCAUQABqHATCBhAKBgQCTJMKIfmfeZpaI7Q9rnsc29gdWawK7TnpVKRHws1iY7EUlYROeVcMdAwEqVM6f8BVCKLGgzQ7Gar_uuxfUGKwqEQzoppDraw4F75J464-7D5f6_oJQuGIBHZxqbMONtLjBCXRUhQW5szBLmTQ_R3qaJb5vf-h0APZfkYhq1cTttSCZkQYQBAqWAQqRAQgLEAAahgEwgYMCgYBvvGVH_M2H8qxxv94yaDYUTWbRnJ1uiIYc59KIQlfFimMPhSS7x2tqUa2-hI55JiII0Xym6GNkwLhyc1xtWChpVuIdSnbvttbrt4weDMLHqTwNOF6qAsVKGKT1Yh8yf-qb-DSmicgvFc74mBQm_6gAY1iQsf33YX8578ClhKBWHSCVkQYQAAqXAQqSAQgMEAAahwEwgYQCgYEAkuzFcd5TJu7lYWYe2hQLFfUWIIj91BvQQLa_Thln4YtGCO8gG1KJqJm-YlmJOWQG0B7H_5RVhxUxV9KpmFnsDVkzUFKOsCBaYGXc12xPVioawUlAwp5qp3QQtZyx_se97YIoLzuLr46UkLcLnkIrp-Jo46QzYi_QHq45WTm8MQ0glpEGEAIKlwEKkgEIDRAAGocBMIGEAoGBAIUzbxOknXf_rNt17_ir8JlWvrtnCWsQd1MAnl5mgArvavDtKeBYHzi5_Ak7DHlLzuA6YE8W175FxLFKpN2hkz-l-M7ltUSd8N1BvJRhK4t6WffWfC_1wPyoAbeSN2Yb1jygtZJQ8wGoXHcJQUXiMit3eFNyylwsJFj1gzAR4JCdIJeRBhABCpYBCpEBCA4QABqGATCBgwKBgFMcbEpl9ukVR6AO_R6sMyiU11I8b8MBSUCEC15iKsrVO8v_m47_TRRjWPYtQ9eZ7o1ocNJHaGUU7qqInFqtFaVnIceP6NmCsXhjs3MLrWPS8IRAy4Zf4FKmGOx3N9O2vemjUygZ9vUiSkULdVrecinRaT8JQ5RG4bUMY04XGIwFIJiRBhADCpYBCpEBCA8QABqGATCBgwKBgGpCkW-NR3li8GlRvqpq2YZGSIgm_PTyDI2Zwfw69grsBmPpVFW48Vw7xoMN35zcrojEpialB_uQzlpLYOvsMl634CRIuj-n1QE3-gaZTTTE8mg-AR4mcxnTKThPnRQpbuOlYAnriwiasWiQEMbGjq_HmWioYYxFo9USlklQn4-9IJmRBhAEEpUBCpIBCAYQABqHATCBhAKBgQCoZkFGm9oLTqjeXZAq6j5S6i7K20V0lNdBBLqfmFBIRuTkYxhs4vUYnWjZrKRAd5bp6_py0csmFmpl_5Yh0b-2pdo_E5PNP7LGRzKyKSiFddyykKKzVOazH8YYldDAfE8Z5HoS9e48an5JsPg0jr-TPu34DnJq3yv2a6dqiKL9zSCakQYSlQEKkgEIEBAAGocBMIGEAoGBALhrihbf3EpjDQS2sCQHazoFgN0nBbE9eesnnFTfzQELXb2gnJU9enmV_aDqaHKjgtLIPpCgn40lHrn5k6mvH5OdedyI6cCzE-N-GFp3nAq0NDJyMe0fhtIRD__CbT0ulcvkeow65ubXWfw6dBC2gR_34rdMe_L_TGRLMWjDULbNIJ";
+ static const TString UNSUPPORTED_VERSION_USER_TICKET = "2:user:CA0Q__________9_GiQKAwjIAwoCCHsQyAMaCGJiOnNlc3MxGghiYjpzZXNzMiASKAE:KJFv5EcXn9krYk19LCvlFrhMW-R4q8mKfXJXCd-RBVBgUQzCOR1Dx2FiOyU-BxUoIsaU0PiwTjbVY5I2onJDilge70Cl5zEPI9pfab2qwklACq_ZBUvD1tzrfNUr88otBGAziHASJWgyVDkhyQ3p7YbN38qpb0vGQrYNxlk4e2I";
+ static const TString USER_TICKET_PROTOBUF = "CA0Q__________9_GiQKAwjIAwoCCHsQyAMaCGJiOnNlc3MxGghiYjpzZXNzMiASKAE";
+ static const TString VALID_USER_TICKET_1 = "3:user:CA0Q__________9_GiQKAwjIAwoCCHsQyAMaCGJiOnNlc3MxGghiYjpzZXNzMiASKAE:KJFv5EcXn9krYk19LCvlFrhMW-R4q8mKfXJXCd-RBVBgUQzCOR1Dx2FiOyU-BxUoIsaU0PiwTjbVY5I2onJDilge70Cl5zEPI9pfab2qwklACq_ZBUvD1tzrfNUr88otBGAziHASJWgyVDkhyQ3p7YbN38qpb0vGQrYNxlk4e2I";
+ static const TString VALID_USER_TICKET_2 = "3:user:CA0Q__________9_GhAKAwjIAwoCCHsQyAMgEigB:KRibGYTJUA2ns0Fn7VYqeMZ1-GdscB1o9pRzELyr7QJrJsfsE8Y_HoVvB8Npr-oalv6AXOpagSc8HpZjAQz8zKMAVE_tI0tL-9DEsHirpawEbpy7OWV7-k18o1m-RaDaKeTlIB45KHbBul1-9aeKkortBfbbXtz_Qy9r_mfFPiQ";
+ static const TString VALID_USER_TICKET_3 = "3:user:CA0Q__________9_Go8bCgIIAAoCCAEKAggCCgIIAwoCCAQKAggFCgIIBgoCCAcKAggICgIICQoCCAoKAggLCgIIDAoCCA0KAggOCgIIDwoCCBAKAggRCgIIEgoCCBMKAggUCgIIFQoCCBYKAggXCgIIGAoCCBkKAggaCgIIGwoCCBwKAggdCgIIHgoCCB8KAgggCgIIIQoCCCIKAggjCgIIJAoCCCUKAggmCgIIJwoCCCgKAggpCgIIKgoCCCsKAggsCgIILQoCCC4KAggvCgIIMAoCCDEKAggyCgIIMwoCCDQKAgg1CgIINgoCCDcKAgg4CgIIOQoCCDoKAgg7CgIIPAoCCD0KAgg-CgIIPwoCCEAKAghBCgIIQgoCCEMKAghECgIIRQoCCEYKAghHCgIISAoCCEkKAghKCgIISwoCCEwKAghNCgIITgoCCE8KAghQCgIIUQoCCFIKAghTCgIIVAoCCFUKAghWCgIIVwoCCFgKAghZCgIIWgoCCFsKAghcCgIIXQoCCF4KAghfCgIIYAoCCGEKAghiCgIIYwoCCGQKAghlCgIIZgoCCGcKAghoCgIIaQoCCGoKAghrCgIIbAoCCG0KAghuCgIIbwoCCHAKAghxCgIIcgoCCHMKAgh0CgIIdQoCCHYKAgh3CgIIeAoCCHkKAgh6CgIIewoCCHwKAgh9CgIIfgoCCH8KAwiAAQoDCIEBCgMIggEKAwiDAQoDCIQBCgMIhQEKAwiGAQoDCIcBCgMIiAEKAwiJAQoDCIoBCgMIiwEKAwiMAQoDCI0BCgMIjgEKAwiPAQoDCJABCgMIkQEKAwiSAQoDCJMBCgMIlAEKAwiVAQoDCJYBCgMIlwEKAwiYAQoDCJkBCgMImgEKAwibAQoDCJwBCgMInQEKAwieAQoDCJ8BCgMIoAEKAwihAQoDCKIBCgMIowEKAwikAQoDCKUBCgMIpgEKAwinAQoDCKgBCgMIqQEKAwiqAQoDCKsBCgMIrAEKAwitAQoDCK4BCgMIrwEKAwiwAQoDCLEBCgMIsgEKAwizAQoDCLQBCgMItQEKAwi2AQoDCLcBCgMIuAEKAwi5AQoDCLoBCgMIuwEKAwi8AQoDCL0BCgMIvgEKAwi_AQoDCMABCgMIwQEKAwjCAQoDCMMBCgMIxAEKAwjFAQoDCMYBCgMIxwEKAwjIAQoDCMkBCgMIygEKAwjLAQoDCMwBCgMIzQEKAwjOAQoDCM8BCgMI0AEKAwjRAQoDCNIBCgMI0wEKAwjUAQoDCNUBCgMI1gEKAwjXAQoDCNgBCgMI2QEKAwjaAQoDCNsBCgMI3AEKAwjdAQoDCN4BCgMI3wEKAwjgAQoDCOEBCgMI4gEKAwjjAQoDCOQBCgMI5QEKAwjmAQoDCOcBCgMI6AEKAwjpAQoDCOoBCgMI6wEKAwjsAQoDCO0BCgMI7gEKAwjvAQoDCPABCgMI8QEKAwjyAQoDCPMBCgMI9AEKAwj1AQoDCPYBCgMI9wEKAwj4AQoDCPkBCgMI-gEKAwj7AQoDCPwBCgMI_QEKAwj-AQoDCP8BCgMIgAIKAwiBAgoDCIICCgMIgwIKAwiEAgoDCIUCCgMIhgIKAwiHAgoDCIgCCgMIiQIKAwiKAgoDCIsCCgMIjAIKAwiNAgoDCI4CCgMIjwIKAwiQAgoDCJECCgMIkgIKAwiTAgoDCJQCCgMIlQIKAwiWAgoDCJcCCgMImAIKAwiZAgoDCJoCCgMImwIKAwicAgoDCJ0CCgMIngIKAwifAgoDCKACCgMIoQIKAwiiAgoDCKMCCgMIpAIKAwilAgoDCKYCCgMIpwIKAwioAgoDCKkCCgMIqgIKAwirAgoDCKwCCgMIrQIKAwiuAgoDCK8CCgMIsAIKAwixAgoDCLICCgMIswIKAwi0AgoDCLUCCgMItgIKAwi3AgoDCLgCCgMIuQIKAwi6AgoDCLsCCgMIvAIKAwi9AgoDCL4CCgMIvwIKAwjAAgoDCMECCgMIwgIKAwjDAgoDCMQCCgMIxQIKAwjGAgoDCMcCCgMIyAIKAwjJAgoDCMoCCgMIywIKAwjMAgoDCM0CCgMIzgIKAwjPAgoDCNACCgMI0QIKAwjSAgoDCNMCCgMI1AIKAwjVAgoDCNYCCgMI1wIKAwjYAgoDCNkCCgMI2gIKAwjbAgoDCNwCCgMI3QIKAwjeAgoDCN8CCgMI4AIKAwjhAgoDCOICCgMI4wIKAwjkAgoDCOUCCgMI5gIKAwjnAgoDCOgCCgMI6QIKAwjqAgoDCOsCCgMI7AIKAwjtAgoDCO4CCgMI7wIKAwjwAgoDCPECCgMI8gIKAwjzAgoDCPQCCgMI9QIKAwj2AgoDCPcCCgMI-AIKAwj5AgoDCPoCCgMI-wIKAwj8AgoDCP0CCgMI_gIKAwj_AgoDCIADCgMIgQMKAwiCAwoDCIMDCgMIhAMKAwiFAwoDCIYDCgMIhwMKAwiIAwoDCIkDCgMIigMKAwiLAwoDCIwDCgMIjQMKAwiOAwoDCI8DCgMIkAMKAwiRAwoDCJIDCgMIkwMKAwiUAwoDCJUDCgMIlgMKAwiXAwoDCJgDCgMImQMKAwiaAwoDCJsDCgMInAMKAwidAwoDCJ4DCgMInwMKAwigAwoDCKEDCgMIogMKAwijAwoDCKQDCgMIpQMKAwimAwoDCKcDCgMIqAMKAwipAwoDCKoDCgMIqwMKAwisAwoDCK0DCgMIrgMKAwivAwoDCLADCgMIsQMKAwiyAwoDCLMDCgMItAMKAwi1AwoDCLYDCgMItwMKAwi4AwoDCLkDCgMIugMKAwi7AwoDCLwDCgMIvQMKAwi-AwoDCL8DCgMIwAMKAwjBAwoDCMIDCgMIwwMKAwjEAwoDCMUDCgMIxgMKAwjHAwoDCMgDCgMIyQMKAwjKAwoDCMsDCgMIzAMKAwjNAwoDCM4DCgMIzwMKAwjQAwoDCNEDCgMI0gMKAwjTAwoDCNQDCgMI1QMKAwjWAwoDCNcDCgMI2AMKAwjZAwoDCNoDCgMI2wMKAwjcAwoDCN0DCgMI3gMKAwjfAwoDCOADCgMI4QMKAwjiAwoDCOMDCgMI5AMKAwjlAwoDCOYDCgMI5wMKAwjoAwoDCOkDCgMI6gMKAwjrAwoDCOwDCgMI7QMKAwjuAwoDCO8DCgMI8AMKAwjxAwoDCPIDCgMI8wMQyAMaCGJiOnNlc3MxGgliYjpzZXNzMTAaCmJiOnNlc3MxMDAaCWJiOnNlc3MxMRoJYmI6c2VzczEyGgliYjpzZXNzMTMaCWJiOnNlc3MxNBoJYmI6c2VzczE1GgliYjpzZXNzMTYaCWJiOnNlc3MxNxoJYmI6c2VzczE4GgliYjpzZXNzMTkaCGJiOnNlc3MyGgliYjpzZXNzMjAaCWJiOnNlc3MyMRoJYmI6c2VzczIyGgliYjpzZXNzMjMaCWJiOnNlc3MyNBoJYmI6c2VzczI1GgliYjpzZXNzMjYaCWJiOnNlc3MyNxoJYmI6c2VzczI4GgliYjpzZXNzMjkaCGJiOnNlc3MzGgliYjpzZXNzMzAaCWJiOnNlc3MzMRoJYmI6c2VzczMyGgliYjpzZXNzMzMaCWJiOnNlc3MzNBoJYmI6c2VzczM1GgliYjpzZXNzMzYaCWJiOnNlc3MzNxoJYmI6c2VzczM4GgliYjpzZXNzMzkaCGJiOnNlc3M0GgliYjpzZXNzNDAaCWJiOnNlc3M0MRoJYmI6c2VzczQyGgliYjpzZXNzNDMaCWJiOnNlc3M0NBoJYmI6c2VzczQ1GgliYjpzZXNzNDYaCWJiOnNlc3M0NxoJYmI6c2VzczQ4GgliYjpzZXNzNDkaCGJiOnNlc3M1GgliYjpzZXNzNTAaCWJiOnNlc3M1MRoJYmI6c2VzczUyGgliYjpzZXNzNTMaCWJiOnNlc3M1NBoJYmI6c2VzczU1GgliYjpzZXNzNTYaCWJiOnNlc3M1NxoJYmI6c2VzczU4GgliYjpzZXNzNTkaCGJiOnNlc3M2GgliYjpzZXNzNjAaCWJiOnNlc3M2MRoJYmI6c2VzczYyGgliYjpzZXNzNjMaCWJiOnNlc3M2NBoJYmI6c2VzczY1GgliYjpzZXNzNjYaCWJiOnNlc3M2NxoJYmI6c2VzczY4GgliYjpzZXNzNjkaCGJiOnNlc3M3GgliYjpzZXNzNzAaCWJiOnNlc3M3MRoJYmI6c2VzczcyGgliYjpzZXNzNzMaCWJiOnNlc3M3NBoJYmI6c2Vzczc1GgliYjpzZXNzNzYaCWJiOnNlc3M3NxoJYmI6c2Vzczc4GgliYjpzZXNzNzkaCGJiOnNlc3M4GgliYjpzZXNzODAaCWJiOnNlc3M4MRoJYmI6c2VzczgyGgliYjpzZXNzODMaCWJiOnNlc3M4NBoJYmI6c2Vzczg1GgliYjpzZXNzODYaCWJiOnNlc3M4NxoJYmI6c2Vzczg4GgliYjpzZXNzODkaCGJiOnNlc3M5GgliYjpzZXNzOTAaCWJiOnNlc3M5MRoJYmI6c2VzczkyGgliYjpzZXNzOTMaCWJiOnNlc3M5NBoJYmI6c2Vzczk1GgliYjpzZXNzOTYaCWJiOnNlc3M5NxoJYmI6c2Vzczk4GgliYjpzZXNzOTkgEigB:CX8PIOrxJnQqFXl7wAsiHJ_1VGjoI-asNlCXb8SE8jtI2vdh9x6CqbAurSgIlAAEgotVP-nuUR38x_a9YJuXzmG5AvJ458apWQtODHIDIX6ZaIwMxjS02R7S5LNqXa0gAuU_R6bCWpZdWe2uLMkdpu5KHbDgW08g-uaP_nceDOk";
+
+ Y_UNIT_TEST(Case1Test) {
+ TUserContext context1(EBlackboxEnv::Test, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+
+ TCheckedUserTicket checkedTicket1 = context1.Check("2:serv:CgYIDRCUkQYQDBgcIgdiYjpzZXNzIghiYjpzZXNzMg:ERmeH_yzC7K_QsoHTyw7llCsyExEz3CoEopPIuivA0ZAtTaFq_Pa0l9Fhhx_NX9WpOp2CPyY5cFc4PXhcO83jCB7-EGvHNxGN-j2NQalERzPiKqkDCO0Q5etLzSzrfTlvMz7sXDvELNBHyA0PkAQnbz4supY0l-0Q6JBYSEF3zOVMjjE-HeQIFL3ats3_PakaUMWRvgQQ88pVdYZqAtbDw9PlTla7ommygVZQjcfNFXV1pJKRgOCLs-YyCjOJHLKL04zYj0X6KsOCTUeqhj7ml96wLZ-g1X9tyOR2WAr2Ctq7wIEHwqhxOLgOSKqm05xH6Vi3E_hekf50oe2jPfKEA");
+ UNIT_ASSERT_EQUAL(ETicketStatus::UnsupportedVersion, checkedTicket1.GetStatus());
+ UNIT_ASSERT(!checkedTicket1);
+
+ TUserContext context2 = std::move(context1);
+ TUserContext context3(std::move(context2));
+ TCheckedUserTicket checkedTicket2 = context3.Check(VALID_USER_TICKET_1);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket2.GetStatus());
+ TCheckedUserTicket checkedTicket3 = std::move(checkedTicket2);
+ TCheckedUserTicket checkedTicket4(std::move(checkedTicket3));
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket4.GetStatus());
+ }
+
+ Y_UNIT_TEST(ContextTest) {
+ TUserContext context(EBlackboxEnv::Prod, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ }
+
+ Y_UNIT_TEST(ContextExceptionsTest) {
+ UNIT_ASSERT_EXCEPTION(TUserContext(EBlackboxEnv::Prod, EMPTY_TVM_KEYS), TEmptyTvmKeysException);
+ UNIT_ASSERT_EXCEPTION(TUserContext(EBlackboxEnv::Prod, MALFORMED_TVM_KEYS), TMalformedTvmKeysException);
+ }
+
+ Y_UNIT_TEST(Ticket1Test) {
+ TUserContext context(EBlackboxEnv::Test, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(VALID_USER_TICKET_1);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket.GetStatus());
+ UNIT_ASSERT_EQUAL(TUids({456, 123}), checkedTicket.GetUids());
+ UNIT_ASSERT_EQUAL(456, checkedTicket.GetDefaultUid());
+ UNIT_ASSERT_EQUAL(TScopes({"bb:sess1", "bb:sess2"}), checkedTicket.GetScopes());
+ UNIT_ASSERT(checkedTicket.HasScope("bb:sess1"));
+ UNIT_ASSERT(checkedTicket.HasScope("bb:sess2"));
+ UNIT_ASSERT(!checkedTicket.HasScope("bb:sess3"));
+ UNIT_ASSERT_EQUAL("ticket_type=user;expiration_time=9223372036854775807;scope=bb:sess1;scope=bb:sess2;default_uid=456;uid=456;uid=123;env=Test;", checkedTicket.DebugInfo());
+ }
+
+ Y_UNIT_TEST(Ticket2Test) {
+ TUserContext context(EBlackboxEnv::Test, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(VALID_USER_TICKET_2);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket.GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL("ticket_type=user;expiration_time=9223372036854775807;default_uid=456;uid=456;uid=123;env=Test;", checkedTicket.DebugInfo());
+ }
+
+ Y_UNIT_TEST(Ticket3Test) {
+ TUserContext context(EBlackboxEnv::Test, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(VALID_USER_TICKET_3);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket.GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL("ticket_type=user;expiration_time=9223372036854775807;scope=bb:sess1;scope=bb:sess10;scope=bb:sess100;scope=bb:sess11;scope=bb:sess12;scope=bb:sess13;scope=bb:sess14;scope=bb:sess15;scope=bb:sess16;scope=bb:sess17;scope=bb:sess18;scope=bb:sess19;scope=bb:sess2;scope=bb:sess20;scope=bb:sess21;scope=bb:sess22;scope=bb:sess23;scope=bb:sess24;scope=bb:sess25;scope=bb:sess26;scope=bb:sess27;scope=bb:sess28;scope=bb:sess29;scope=bb:sess3;scope=bb:sess30;scope=bb:sess31;scope=bb:sess32;scope=bb:sess33;scope=bb:sess34;scope=bb:sess35;scope=bb:sess36;scope=bb:sess37;scope=bb:sess38;scope=bb:sess39;scope=bb:sess4;scope=bb:sess40;scope=bb:sess41;scope=bb:sess42;scope=bb:sess43;scope=bb:sess44;scope=bb:sess45;scope=bb:sess46;scope=bb:sess47;scope=bb:sess48;scope=bb:sess49;scope=bb:sess5;scope=bb:sess50;scope=bb:sess51;scope=bb:sess52;scope=bb:sess53;scope=bb:sess54;scope=bb:sess55;scope=bb:sess56;scope=bb:sess57;scope=bb:sess58;scope=bb:sess59;scope=bb:sess6;scope=bb:sess60;scope=bb:sess61;scope=bb:sess62;scope=bb:sess63;scope=bb:sess64;scope=bb:sess65;scope=bb:sess66;scope=bb:sess67;scope=bb:sess68;scope=bb:sess69;scope=bb:sess7;scope=bb:sess70;scope=bb:sess71;scope=bb:sess72;scope=bb:sess73;scope=bb:sess74;scope=bb:sess75;scope=bb:sess76;scope=bb:sess77;scope=bb:sess78;scope=bb:sess79;scope=bb:sess8;scope=bb:sess80;scope=bb:sess81;scope=bb:sess82;scope=bb:sess83;scope=bb:sess84;scope=bb:sess85;scope=bb:sess86;scope=bb:sess87;scope=bb:sess88;scope=bb:sess89;scope=bb:sess9;scope=bb:sess90;scope=bb:sess91;scope=bb:sess92;scope=bb:sess93;scope=bb:sess94;scope=bb:sess95;scope=bb:sess96;scope=bb:sess97;scope=bb:sess98;scope=bb:sess99;default_uid=456;uid=0;uid=1;uid=2;uid=3;uid=4;uid=5;uid=6;uid=7;uid=8;uid=9;uid=10;uid=11;uid=12;uid=13;uid=14;uid=15;uid=16;uid=17;uid=18;uid=19;uid=20;uid=21;uid=22;uid=23;uid=24;uid=25;uid=26;uid=27;uid=28;uid=29;uid=30;uid=31;uid=32;uid=33;uid=34;uid=35;uid=36;uid=37;uid=38;uid=39;uid=40;uid=41;uid=42;uid=43;uid=44;uid=45;uid=46;uid=47;uid=48;uid=49;uid=50;uid=51;uid=52;uid=53;uid=54;uid=55;uid=56;uid=57;uid=58;uid=59;uid=60;uid=61;uid=62;uid=63;uid=64;uid=65;uid=66;uid=67;uid=68;uid=69;uid=70;uid=71;uid=72;uid=73;uid=74;uid=75;uid=76;uid=77;uid=78;uid=79;uid=80;uid=81;uid=82;uid=83;uid=84;uid=85;uid=86;uid=87;uid=88;uid=89;uid=90;uid=91;uid=92;uid=93;uid=94;uid=95;uid=96;uid=97;uid=98;uid=99;uid=100;uid=101;uid=102;uid=103;uid=104;uid=105;uid=106;uid=107;uid=108;uid=109;uid=110;uid=111;uid=112;uid=113;uid=114;uid=115;uid=116;uid=117;uid=118;uid=119;uid=120;uid=121;uid=122;uid=123;uid=124;uid=125;uid=126;uid=127;uid=128;uid=129;uid=130;uid=131;uid=132;uid=133;uid=134;uid=135;uid=136;uid=137;uid=138;uid=139;uid=140;uid=141;uid=142;uid=143;uid=144;uid=145;uid=146;uid=147;uid=148;uid=149;uid=150;uid=151;uid=152;uid=153;uid=154;uid=155;uid=156;uid=157;uid=158;uid=159;uid=160;uid=161;uid=162;uid=163;uid=164;uid=165;uid=166;uid=167;uid=168;uid=169;uid=170;uid=171;uid=172;uid=173;uid=174;uid=175;uid=176;uid=177;uid=178;uid=179;uid=180;uid=181;uid=182;uid=183;uid=184;uid=185;uid=186;uid=187;uid=188;uid=189;uid=190;uid=191;uid=192;uid=193;uid=194;uid=195;uid=196;uid=197;uid=198;uid=199;uid=200;uid=201;uid=202;uid=203;uid=204;uid=205;uid=206;uid=207;uid=208;uid=209;uid=210;uid=211;uid=212;uid=213;uid=214;uid=215;uid=216;uid=217;uid=218;uid=219;uid=220;uid=221;uid=222;uid=223;uid=224;uid=225;uid=226;uid=227;uid=228;uid=229;uid=230;uid=231;uid=232;uid=233;uid=234;uid=235;uid=236;uid=237;uid=238;uid=239;uid=240;uid=241;uid=242;uid=243;uid=244;uid=245;uid=246;uid=247;uid=248;uid=249;uid=250;uid=251;uid=252;uid=253;uid=254;uid=255;uid=256;uid=257;uid=258;uid=259;uid=260;uid=261;uid=262;uid=263;uid=264;uid=265;uid=266;uid=267;uid=268;uid=269;uid=270;uid=271;uid=272;uid=273;uid=274;uid=275;uid=276;uid=277;uid=278;uid=279;uid=280;uid=281;uid=282;uid=283;uid=284;uid=285;uid=286;uid=287;uid=288;uid=289;uid=290;uid=291;uid=292;uid=293;uid=294;uid=295;uid=296;uid=297;uid=298;uid=299;uid=300;uid=301;uid=302;uid=303;uid=304;uid=305;uid=306;uid=307;uid=308;uid=309;uid=310;uid=311;uid=312;uid=313;uid=314;uid=315;uid=316;uid=317;uid=318;uid=319;uid=320;uid=321;uid=322;uid=323;uid=324;uid=325;uid=326;uid=327;uid=328;uid=329;uid=330;uid=331;uid=332;uid=333;uid=334;uid=335;uid=336;uid=337;uid=338;uid=339;uid=340;uid=341;uid=342;uid=343;uid=344;uid=345;uid=346;uid=347;uid=348;uid=349;uid=350;uid=351;uid=352;uid=353;uid=354;uid=355;uid=356;uid=357;uid=358;uid=359;uid=360;uid=361;uid=362;uid=363;uid=364;uid=365;uid=366;uid=367;uid=368;uid=369;uid=370;uid=371;uid=372;uid=373;uid=374;uid=375;uid=376;uid=377;uid=378;uid=379;uid=380;uid=381;uid=382;uid=383;uid=384;uid=385;uid=386;uid=387;uid=388;uid=389;uid=390;uid=391;uid=392;uid=393;uid=394;uid=395;uid=396;uid=397;uid=398;uid=399;uid=400;uid=401;uid=402;uid=403;uid=404;uid=405;uid=406;uid=407;uid=408;uid=409;uid=410;uid=411;uid=412;uid=413;uid=414;uid=415;uid=416;uid=417;uid=418;uid=419;uid=420;uid=421;uid=422;uid=423;uid=424;uid=425;uid=426;uid=427;uid=428;uid=429;uid=430;uid=431;uid=432;uid=433;uid=434;uid=435;uid=436;uid=437;uid=438;uid=439;uid=440;uid=441;uid=442;uid=443;uid=444;uid=445;uid=446;uid=447;uid=448;uid=449;uid=450;uid=451;uid=452;uid=453;uid=454;uid=455;uid=456;uid=457;uid=458;uid=459;uid=460;uid=461;uid=462;uid=463;uid=464;uid=465;uid=466;uid=467;uid=468;uid=469;uid=470;uid=471;uid=472;uid=473;uid=474;uid=475;uid=476;uid=477;uid=478;uid=479;uid=480;uid=481;uid=482;uid=483;uid=484;uid=485;uid=486;uid=487;uid=488;uid=489;uid=490;uid=491;uid=492;uid=493;uid=494;uid=495;uid=496;uid=497;uid=498;uid=499;env=Test;", checkedTicket.DebugInfo());
+ }
+
+ Y_UNIT_TEST(TicketErrorsTest) {
+ TUserContext contextTest(EBlackboxEnv::Test, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket1 = contextTest.Check(UNSUPPORTED_VERSION_USER_TICKET);
+ UNIT_ASSERT_EQUAL(ETicketStatus::UnsupportedVersion, checkedTicket1.GetStatus());
+
+ auto checkedTicket2 = contextTest.Check(EXPIRED_USER_TICKET);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Expired, checkedTicket2.GetStatus());
+
+ TUserContext contextProd(EBlackboxEnv::Prod, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket3 = contextProd.Check(VALID_USER_TICKET_1);
+ UNIT_ASSERT_EQUAL(ETicketStatus::InvalidBlackboxEnv, checkedTicket3.GetStatus());
+ }
+
+ Y_UNIT_TEST(TicketExceptionsTest) {
+ TUserContext contextTest(EBlackboxEnv::Test, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = contextTest.Check(EXPIRED_USER_TICKET);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Expired, checkedTicket.GetStatus());
+
+ UNIT_ASSERT_EXCEPTION(checkedTicket.GetDefaultUid(), TNotAllowedException);
+ UNIT_ASSERT_EXCEPTION(checkedTicket.GetUids(), TNotAllowedException);
+ UNIT_ASSERT_EXCEPTION(checkedTicket.GetScopes(), TNotAllowedException);
+ UNIT_ASSERT_EXCEPTION(checkedTicket.HasScope(""), TNotAllowedException);
+ UNIT_ASSERT_NO_EXCEPTION(bool(checkedTicket));
+ UNIT_ASSERT_NO_EXCEPTION(checkedTicket.DebugInfo());
+ UNIT_ASSERT_NO_EXCEPTION(checkedTicket.GetStatus());
+ }
+
+ Y_UNIT_TEST(ResetKeysTest) {
+ TUserContext context(EBlackboxEnv::Test, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(VALID_USER_TICKET_1);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket.GetStatus());
+ }
+}
diff --git a/library/cpp/tvmauth/src/ut/service_ut.cpp b/library/cpp/tvmauth/src/ut/service_ut.cpp
new file mode 100644
index 0000000000..5b6b5143bd
--- /dev/null
+++ b/library/cpp/tvmauth/src/ut/service_ut.cpp
@@ -0,0 +1,156 @@
+#include <library/cpp/tvmauth/src/service_impl.h>
+#include <library/cpp/tvmauth/src/utils.h>
+
+#include <library/cpp/tvmauth/exception.h>
+#include <library/cpp/tvmauth/unittest.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/string/cast.h>
+
+using namespace NTvmAuth;
+
+Y_UNIT_TEST_SUITE(ServiceTestSuite) {
+ Y_UNIT_TEST_DECLARE(TicketProtoTest);
+}
+
+class TTestServiceTicketImpl: public TCheckedServiceTicket::TImpl {
+ using TCheckedServiceTicket::TImpl::TImpl;
+ Y_UNIT_TEST_FRIEND(ServiceTestSuite, TicketProtoTest);
+};
+
+Y_UNIT_TEST_SUITE_IMPLEMENTATION(ServiceTestSuite) {
+ static const TString EMPTY_TVM_KEYS = "1:CpgCCpMCCAEQABqIAjCCAQQCggEAcLEXeH67FQESFUn4_7wnX7wN0PUrBoUsm3QQ4W5vC-qz6sXaEjSwnTV8w1o-z6X9KPLlhzMQvuS38NCNfK4uvJ4Zvfp3YsXJ25-rYtbnrYJHNvHohD-kPCCw_yZpMp21JdWigzQGuV7CtrxUhF-NNrsnUaJrE5-OpEWNt4X6nCItKIYeVcSK6XJUbEWbrNCRbvkSc4ak2ymFeMuHYJVjxh4eQbk7_ZPzodP0WvF6eUYrYeb42imVEOR8ofVLQWE5DVnb1z_TqZm4i1XkS7jMwZuBxBRw8DGdYei0lT_sAf7KST2jC0590NySB3vsBgWEVs1OdUUWA6r-Dvx9dsOQtSCVkQYQAAqZAgqUAggCEAAaiQIwggEFAoIBAQDhEBM5-6YsPWfogKtbluJoCX1WV2KdzOaQ0-OlRbBzeCzw-eQKu12c8WakHBbeCMd1I1TU64SDkDorWjXGIa_2xT6N3zzNAE50roTbPCcmeQrps26woTYfYIuqDdoxYKZNr0lvNLLW47vBr7EKqo1S4KSj7aXK_XYeEvUgIgf3nVIcNrio7VTnFmGGVQCepaL1Hi1gN4yIXjVZ06PBPZ-DxSRu6xOGbFrfKMJeMPs7KOyE-26Q3xOXdTIa1X-zYIucTd_bxUCL4BVbwW2AvbbFsaG7ISmVdGu0XUTmhXs1KrEfUVLRJhE4Dx99hAZXm1_HlYMUeJcMQ_oHOhV94ENFIJaRBhACCpYBCpEBCAMQABqGATCBgwKBgF9t2YJGAJkRRFq6fWhi3m1TFW1UOE0f6ZrfYhHAkpqGlKlh0QVfeTNPpeJhi75xXzCe6oReRUm-0DbqDNhTShC7uGUv1INYnRBQWH6E-5Fc5XrbDFSuGQw2EYjNfHy_HefHJXxQKAqPvxBDKMKkHgV58WtM6rC8jRi9sdX_ig2NIJeRBhABCpYBCpEBCAQQABqGATCBgwKBgGB4d6eLGUBv-Q6EPLehC4S-yuE2HB-_rJ7WkeYwyp-xIPolPrd-PQme2utHB4ZgpXHIu_OFksDe_0bPgZniNRSVRbl7W49DgS5Ya3kMfrYB4DnF5Fta5tn1oV6EwxYD4JONpFTenOJALPGTPawxXEfon_peiHOSBuQMu3_Vn-l1IJiRBhADCpcBCpIBCAUQABqHATCBhAKBgQCTJMKIfmfeZpaI7Q9rnsc29gdWawK7TnpVKRHws1iY7EUlYROeVcMdAwEqVM6f8BVCKLGgzQ7Gar_uuxfUGKwqEQzoppDraw4F75J464-7D5f6_oJQuGIBHZxqbMONtLjBCXRUhQW5szBLmTQ_R3qaJb5vf-h0APZfkYhq1cTttSCZkQYQBAqWAQqRAQgLEAAahgEwgYMCgYBvvGVH_M2H8qxxv94yaDYUTWbRnJ1uiIYc59KIQlfFimMPhSS7x2tqUa2-hI55JiII0Xym6GNkwLhyc1xtWChpVuIdSnbvttbrt4weDMLHqTwNOF6qAsVKGKT1Yh8yf-qb-DSmicgvFc74mBQm_6gAY1iQsf33YX8578ClhKBWHSCVkQYQAAqXAQqSAQgMEAAahwEwgYQCgYEAkuzFcd5TJu7lYWYe2hQLFfUWIIj91BvQQLa_Thln4YtGCO8gG1KJqJm-YlmJOWQG0B7H_5RVhxUxV9KpmFnsDVkzUFKOsCBaYGXc12xPVioawUlAwp5qp3QQtZyx_se97YIoLzuLr46UkLcLnkIrp-Jo46QzYi_QHq45WTm8MQ0glpEGEAIKlwEKkgEIDRAAGocBMIGEAoGBAIUzbxOknXf_rNt17_ir8JlWvrtnCWsQd1MAnl5mgArvavDtKeBYHzi5_Ak7DHlLzuA6YE8W175FxLFKpN2hkz-l-M7ltUSd8N1BvJRhK4t6WffWfC_1wPyoAbeSN2Yb1jygtZJQ8wGoXHcJQUXiMit3eFNyylwsJFj1gzAR4JCdIJeRBhABCpYBCpEBCA4QABqGATCBgwKBgFMcbEpl9ukVR6AO_R6sMyiU11I8b8MBSUCEC15iKsrVO8v_m47_TRRjWPYtQ9eZ7o1ocNJHaGUU7qqInFqtFaVnIceP6NmCsXhjs3MLrWPS8IRAy4Zf4FKmGOx3N9O2vemjUygZ9vUiSkULdVrecinRaT8JQ5RG4bUMY04XGIwFIJiRBhADCpYBCpEBCA8QABqGATCBgwKBgGpCkW-NR3li8GlRvqpq2YZGSIgm_PTyDI2Zwfw69grsBmPpVFW48Vw7xoMN35zcrojEpialB_uQzlpLYOvsMl634CRIuj-n1QE3-gaZTTTE8mg-AR4mcxnTKThPnRQpbuOlYAnriwiasWiQEMbGjq_HmWioYYxFo9USlklQn4-9IJmRBhAE";
+ static const TString EXPIRED_SERVICE_TICKET = "3:serv:CBAQACIZCOUBEBwaCGJiOnNlc3MxGghiYjpzZXNzMg:IwfMNJYEqStY_SixwqJnyHOMCPR7-3HHk4uylB2oVRkthtezq-OOA7QizDvx7VABLs_iTlXuD1r5IjufNei_EiV145eaa3HIg4xCdJXCojMexf2UYJz8mF2b0YzFAy6_KWagU7xo13CyKAqzJuQf5MJcSUf0ecY9hVh36cJ51aw";
+ static const TString MALFORMED_TVM_KEYS = "1:CpgCCpMCCAEQABqIAjCCAQQCggEAcLEXeH67FQESFUn4_7wnX7wN0PUrBoUsm3QQ4W5vC-qz6sXaEjSwnTV8w1o-z6X9KPLlhzMQvuS38NCNfK4uvJ4Zvfp3YsXJ25-rYtbnrYJHNvHohD-kPCCw_yZpMp21JdWigzQGuV7CtrxUhF-NNrsnUaJrE5-OpEWNt4X6nCItKIYeVcSK6XJUbEWbrNCRbvkSc4ak2ymFeMuHYJVjxh4eQbk7_ZPzodP0WvF6eUYrYeb42imVEOR8ofVLQWE5DVnb1z_TqZm4i1XkS7jMwZuBxBRw8DGdYei0lT_sAf7KST2jC0590NySB3vsBgWEVs1OdUUWA6r-Dvx9dsOQtSCVkQYQAAqZAgqUAggCEAAaiQIwggEFAoIBAQDhEBM5-6YsPWfogKtbluJoCX1WV2KdzOaQ0-OlRbBzeCzw-eQKu12c8WakHBbeCMd1I1TU64SDkDorWjXGIa_2xT6N3zzNAE50roTbPCcmeQrps26woTYfYIuqDdoxYKZNr0lvNLLW47vBr7EKqo1S4KSj7aXK_XYeEvUgIgf3nVIcNrio7VTnFmGGVQCepaL1Hi1gN4yIXjVZ06PBPZ-DxSRu6xOGbFrfKMJeMPs7KOyE-26Q3xOXdTIa1X-zYIucTd_bxUCL4BVbwW2AvbbFsaG7ISmVdGu0XUTmhXs1KrEfUVLRJhE4Dx99hAZXm1_HlYMUeJcMQ_oHOhV94ENFIJaRBhACCpYBCpEBCAMQABqGATCBgwKBgF9t2YJGAJkRRFq6fWhi3m1TFW1UOE0f6ZrfYhHAkpqGlKlh0QVfeTNPpeJhi75xXzCe6oReRUm-0DbqDNhTShC7uGUv1INYnRBQWH6E-5Fc5XrbDFSuGQw2EYjNfHy_HefHJXxQKAqPvxBDKMKkHgV58WtM6rC8jRi9sdX_ig2NIJeRBhABCpYBCpEBCAQQABqGATCBgwKBgGB4d6eLGUBv-Q6EPLehC4S-yuE2HB-_rJ7WkeYwyp-xIPolPrd-PQme2utHB4ZgpXHIu_OFksDe_0bPgZniNRSVRbl7W49DgS5Ya3kMfrYB4DnF5Fta5tn1oV6EwxYD4JONpFTenOJALPGTPawxXEfon_peiHOSBuQMu3_Vn-l1IJiRBhADCpcBCpIBCAUQABqHATCBhAKBgQCTJMKIfmfeZpaI7Q9rnsc29gdWawK7TnpVKRHws1iY7EUlYROeVcMdAwEqVM6f8BVCKLGgzQ7Gar_uuxfUGKwqEQzoppDraw4F75J464-7D5f6_oJQuGIBHZxqbMONtLjBCXRUhQW5szBLmTQ_R3qaJb5vf-h0APZfkYhq1cTttSCZkQYQBAqWAQqRAQgLEAAahgEwgYMCgYBvvGVH_M2H8qxxv94yaDYUTWbRnJ1uiIYc59KIQlfFimMPhSS7x2tqUa2-hI55JiII0Xym6GNkwLhyc1xtWChpVuIdSnbvttbrt4weDMLHqTwNOF6qAsVKGKT1Yh8yf-qb-DSmicgvFc74mBQm_6gAY1iQsf33YX8578ClhKBWHSCVkQYQAAqXAQqSAQgMEAAahwEwgYQCgYEAkuzFcd5TJu7lYWYe2hQLFfUWIIj91BvQQLa_Thln4YtGCO8gG1KJqJm-YlmJOWQG0B7H_5RVhxUxV9KpmFnsDVkzUFKOsCBaYGXc12xPVioawUlAwp5qp3QQtZyx_se97YIoLzuLr46UkLcLnkIrp-Jo46QzYi_QHq45WTm8MQ0glpEGEAIKlwEKkgEIDRAAGocBMIGEAoGBAIUzbxOknXf_rNt17_ir8JlWvrtnCWsQd1MAnl5mgArvavDtKeBYHzi5_Ak7DHlLzuA6YE8W175FxLFKpN2hkz-l-M7ltUSd8N1BvJRhK4t6WffWfC_1wPyoAbeSN2Yb1jygtZJQ8wGoXHcJQUXiMit3eFNyylwsJFj1gzAR4JCdIJeRBhABCpYBCpEBCA4QABqGATCBgwKBgFMcbEpl9ukVR6AO_R6sMyiU11I8b8MBSUCEC15iKsrVO8v_m47_TRRjWPYtQ9eZ7o1ocNJHaGUU7qqInFqtFaVnIceP6NmCsXhjs3MLrWPS8IRAy4Zf4FKmGOx3N9O2vemjUygZ9vUiSkULdVrecinRaT8JQ5RG4bUMY04XGIwFIJiRBhADCpYBCpEBCA8QABqGATCBgwKBgGpCkW-NR3li8GlRvqpq2YZGSIgm_PTyDI2Zwfw69grsBmPpVFW48Vw7xoMN35zcrojEpialB_uQzlpLYOvsMl634CRIuj-n1QE3-gaZTTTE8mg-AR4mcxnTKThPnRQpbuOlYAnriwiasWiQEMbGjq_HmWioYYxFo9USlklQn4-9IJmRBhAEEpUBCpIBCAYQABqHATCBhAKBgQCoZkFGm9oLTqjeXZAq6j5S6i7K20V0lNdBBLqfmFBIRuTkYxhs4vUYnWjZrKRAd5bp6_py0csmFmpl_5Yh0b-2pdo_E5PNP7LGRzKyKSiFddyykKKzVOazH8YYldDAfE8Z5HoS9e48an5JsPg0jr-TPu34DnJq3yv2a6dqiKL9zSCakQYSlQEKkgEIEBAAGocBMIGEAoGBALhrihbf3EpjDQS2sCQHazoFgN0nBbE9eesnnFTfzQELXb2gnJU9enmV_aDqaHKjgtLIPpCgn40lHrn5k6mvH5OdedyI6cCzE-N-GFp3nAq0NDJyMe0fhtIRD__CbT0ulcvkeow65ubXWfw6dBC2gR_34rdMe_L_TGRLMWjDULbNIJ";
+ static const TString MALFORMED_TVM_SECRET = "adcvxcv./-+";
+ static const TTvmId NOT_OUR_ID = 27;
+ static const TTvmId OUR_ID = 28;
+ static const TString SECRET = "GRMJrKnj4fOVnvOqe-WyD1";
+ static const TString SERVICE_TICKET_PROTOBUF = "CBAQ__________9_IhkI5QEQHBoIYmI6c2VzczEaCGJiOnNlc3My";
+ static const TTvmId SRC_ID = 229;
+ static const TString UNSUPPORTED_VERSION_SERVICE_TICKET = "2:serv:CBAQ__________9_IhkI5QEQHBoIYmI6c2VzczEaCGJiOnNlc3My:WUPx1cTf05fjD1exB35T5j2DCHWH1YaLJon_a4rN-D7JfXHK1Ai4wM4uSfboHD9xmGQH7extqtlEk1tCTCGm5qbRVloJwWzCZBXo3zKX6i1oBYP_89WcjCNPVe1e8jwGdLsnu6PpxL5cn0xCksiStILH5UmDR6xfkJdnmMG94o8";
+ static const TString VALID_SERVICE_TICKET_1 = "3:serv:CBAQ__________9_IhkI5QEQHBoIYmI6c2VzczEaCGJiOnNlc3My:WUPx1cTf05fjD1exB35T5j2DCHWH1YaLJon_a4rN-D7JfXHK1Ai4wM4uSfboHD9xmGQH7extqtlEk1tCTCGm5qbRVloJwWzCZBXo3zKX6i1oBYP_89WcjCNPVe1e8jwGdLsnu6PpxL5cn0xCksiStILH5UmDR6xfkJdnmMG94o8";
+ static const TString VALID_SERVICE_TICKET_2 = "3:serv:CBAQ__________9_IskICOUBEBwaCGJiOnNlc3MxGgliYjpzZXNzMTAaCmJiOnNlc3MxMDAaCWJiOnNlc3MxMRoJYmI6c2VzczEyGgliYjpzZXNzMTMaCWJiOnNlc3MxNBoJYmI6c2VzczE1GgliYjpzZXNzMTYaCWJiOnNlc3MxNxoJYmI6c2VzczE4GgliYjpzZXNzMTkaCGJiOnNlc3MyGgliYjpzZXNzMjAaCWJiOnNlc3MyMRoJYmI6c2VzczIyGgliYjpzZXNzMjMaCWJiOnNlc3MyNBoJYmI6c2VzczI1GgliYjpzZXNzMjYaCWJiOnNlc3MyNxoJYmI6c2VzczI4GgliYjpzZXNzMjkaCGJiOnNlc3MzGgliYjpzZXNzMzAaCWJiOnNlc3MzMRoJYmI6c2VzczMyGgliYjpzZXNzMzMaCWJiOnNlc3MzNBoJYmI6c2VzczM1GgliYjpzZXNzMzYaCWJiOnNlc3MzNxoJYmI6c2VzczM4GgliYjpzZXNzMzkaCGJiOnNlc3M0GgliYjpzZXNzNDAaCWJiOnNlc3M0MRoJYmI6c2VzczQyGgliYjpzZXNzNDMaCWJiOnNlc3M0NBoJYmI6c2VzczQ1GgliYjpzZXNzNDYaCWJiOnNlc3M0NxoJYmI6c2VzczQ4GgliYjpzZXNzNDkaCGJiOnNlc3M1GgliYjpzZXNzNTAaCWJiOnNlc3M1MRoJYmI6c2VzczUyGgliYjpzZXNzNTMaCWJiOnNlc3M1NBoJYmI6c2VzczU1GgliYjpzZXNzNTYaCWJiOnNlc3M1NxoJYmI6c2VzczU4GgliYjpzZXNzNTkaCGJiOnNlc3M2GgliYjpzZXNzNjAaCWJiOnNlc3M2MRoJYmI6c2VzczYyGgliYjpzZXNzNjMaCWJiOnNlc3M2NBoJYmI6c2VzczY1GgliYjpzZXNzNjYaCWJiOnNlc3M2NxoJYmI6c2VzczY4GgliYjpzZXNzNjkaCGJiOnNlc3M3GgliYjpzZXNzNzAaCWJiOnNlc3M3MRoJYmI6c2VzczcyGgliYjpzZXNzNzMaCWJiOnNlc3M3NBoJYmI6c2Vzczc1GgliYjpzZXNzNzYaCWJiOnNlc3M3NxoJYmI6c2Vzczc4GgliYjpzZXNzNzkaCGJiOnNlc3M4GgliYjpzZXNzODAaCWJiOnNlc3M4MRoJYmI6c2VzczgyGgliYjpzZXNzODMaCWJiOnNlc3M4NBoJYmI6c2Vzczg1GgliYjpzZXNzODYaCWJiOnNlc3M4NxoJYmI6c2Vzczg4GgliYjpzZXNzODkaCGJiOnNlc3M5GgliYjpzZXNzOTAaCWJiOnNlc3M5MRoJYmI6c2VzczkyGgliYjpzZXNzOTMaCWJiOnNlc3M5NBoJYmI6c2Vzczk1GgliYjpzZXNzOTYaCWJiOnNlc3M5NxoJYmI6c2Vzczk4GgliYjpzZXNzOTk:JYmABAVLM6y7_T4n1pRcwBfwDfzMV4JJ3cpbEG617zdGgKRZwL7MalsYn5bq1F2ibujMrsF9nzZf8l4s_e-Ivjkz_xu4KMzSp-pUh9V7XIF_smj0WHYpv6gOvWNuK8uIvlZTTKwtQX0qZOL9m-MEeZiHoQPKZGCfJ_qxMUp-J8I";
+ static const TString VALID_SERVICE_TICKET_3 = "3:serv:CBAQ__________9_IgUI5QEQHA:Sd6tmA1CNy2Nf7XevC3x7zr2DrGNRmcl-TxUsDtDW2xI3YXyCxBltWeg0-KtDlqyYuPOP5Jd_-XXNA12KlOPnNzrz3jm-5z8uQl6CjCcrVHUHJ75pGC8r9UOlS8cOgeXQB5dYP-fOWyo5CNadlozx1S2meCIxncbQRV1kCBi4KU";
+ static const TString VALID_SERVICE_TICKET_ISSUER = "3:serv:CBAQ__________9_IgsI5QEQHCDr1MT4Ag:Gu66XJT_nKnIRJjFy1561wFhIqkJItcSTGftLo7Yvi7i5wIdV-QuKT_-IMPpgjxnnGbt1Dy3Ys2TEoeJAb0TdaCYG1uy3vpoLONmTx9AenN5dx1HHf46cypLK5D3OdiTjxvqI9uGmSIKrSdRxU8gprpu5QiBDPZqVCWhM60FVSY";
+
+ Y_UNIT_TEST(ContextExceptionsTest) {
+ UNIT_ASSERT_EXCEPTION(TServiceContext::TImpl(SECRET, OUR_ID, MALFORMED_TVM_KEYS), TMalformedTvmKeysException);
+ UNIT_ASSERT_EXCEPTION(TServiceContext::TImpl(SECRET, OUR_ID, EMPTY_TVM_KEYS), TEmptyTvmKeysException);
+ UNIT_ASSERT_EXCEPTION(TServiceContext::TImpl(MALFORMED_TVM_SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS), TMalformedTvmSecretException);
+ }
+
+ Y_UNIT_TEST(ContextSignTest) {
+ TServiceContext::TImpl context(SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ UNIT_ASSERT_VALUES_EQUAL(
+ "NsPTYak4Cfk-4vgau5lab3W4GPiTtb2etuj3y4MDPrk",
+ context.SignCgiParamsForTvm(IntToString<10>(std::numeric_limits<time_t>::max()), "13,28", ""));
+ }
+
+ Y_UNIT_TEST(Ticket1Test) {
+ TServiceContext::TImpl context(SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(VALID_SERVICE_TICKET_1);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket->GetStatus());
+ UNIT_ASSERT_EQUAL(std::numeric_limits<time_t>::max(), checkedTicket->GetExpirationTime());
+ UNIT_ASSERT_EQUAL(SRC_ID, checkedTicket->GetSrc());
+ UNIT_ASSERT_EQUAL(TScopes({"bb:sess1", "bb:sess2"}), checkedTicket->GetScopes());
+ UNIT_ASSERT(checkedTicket->HasScope("bb:sess1"));
+ UNIT_ASSERT(checkedTicket->HasScope("bb:sess2"));
+ UNIT_ASSERT(!checkedTicket->HasScope("bb:sess3"));
+ UNIT_ASSERT_EQUAL("ticket_type=serv;expiration_time=9223372036854775807;src=229;dst=28;scope=bb:sess1;scope=bb:sess2;", checkedTicket->DebugInfo());
+ UNIT_ASSERT(!checkedTicket->GetIssuerUid());
+ }
+
+ Y_UNIT_TEST(Ticket2Test) {
+ TServiceContext::TImpl context(SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(VALID_SERVICE_TICKET_2);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket->GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL("ticket_type=serv;expiration_time=9223372036854775807;src=229;dst=28;scope=bb:sess1;scope=bb:sess10;scope=bb:sess100;scope=bb:sess11;scope=bb:sess12;scope=bb:sess13;scope=bb:sess14;scope=bb:sess15;scope=bb:sess16;scope=bb:sess17;scope=bb:sess18;scope=bb:sess19;scope=bb:sess2;scope=bb:sess20;scope=bb:sess21;scope=bb:sess22;scope=bb:sess23;scope=bb:sess24;scope=bb:sess25;scope=bb:sess26;scope=bb:sess27;scope=bb:sess28;scope=bb:sess29;scope=bb:sess3;scope=bb:sess30;scope=bb:sess31;scope=bb:sess32;scope=bb:sess33;scope=bb:sess34;scope=bb:sess35;scope=bb:sess36;scope=bb:sess37;scope=bb:sess38;scope=bb:sess39;scope=bb:sess4;scope=bb:sess40;scope=bb:sess41;scope=bb:sess42;scope=bb:sess43;scope=bb:sess44;scope=bb:sess45;scope=bb:sess46;scope=bb:sess47;scope=bb:sess48;scope=bb:sess49;scope=bb:sess5;scope=bb:sess50;scope=bb:sess51;scope=bb:sess52;scope=bb:sess53;scope=bb:sess54;scope=bb:sess55;scope=bb:sess56;scope=bb:sess57;scope=bb:sess58;scope=bb:sess59;scope=bb:sess6;scope=bb:sess60;scope=bb:sess61;scope=bb:sess62;scope=bb:sess63;scope=bb:sess64;scope=bb:sess65;scope=bb:sess66;scope=bb:sess67;scope=bb:sess68;scope=bb:sess69;scope=bb:sess7;scope=bb:sess70;scope=bb:sess71;scope=bb:sess72;scope=bb:sess73;scope=bb:sess74;scope=bb:sess75;scope=bb:sess76;scope=bb:sess77;scope=bb:sess78;scope=bb:sess79;scope=bb:sess8;scope=bb:sess80;scope=bb:sess81;scope=bb:sess82;scope=bb:sess83;scope=bb:sess84;scope=bb:sess85;scope=bb:sess86;scope=bb:sess87;scope=bb:sess88;scope=bb:sess89;scope=bb:sess9;scope=bb:sess90;scope=bb:sess91;scope=bb:sess92;scope=bb:sess93;scope=bb:sess94;scope=bb:sess95;scope=bb:sess96;scope=bb:sess97;scope=bb:sess98;scope=bb:sess99;", checkedTicket->DebugInfo());
+ UNIT_ASSERT(!checkedTicket->GetIssuerUid());
+ }
+
+ Y_UNIT_TEST(Ticket3Test) {
+ TServiceContext::TImpl context(SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(VALID_SERVICE_TICKET_3);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket->GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL("ticket_type=serv;expiration_time=9223372036854775807;src=229;dst=28;", checkedTicket->DebugInfo());
+ UNIT_ASSERT(!checkedTicket->GetIssuerUid());
+ }
+
+ Y_UNIT_TEST(TicketIssuerTest) {
+ TServiceContext::TImpl context(SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(VALID_SERVICE_TICKET_ISSUER);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket->GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL("ticket_type=serv;expiration_time=9223372036854775807;src=229;dst=28;issuer_uid=789654123;",
+ checkedTicket->DebugInfo());
+ UNIT_ASSERT(checkedTicket->GetIssuerUid());
+ UNIT_ASSERT_VALUES_EQUAL(789654123, *checkedTicket->GetIssuerUid());
+ }
+
+ Y_UNIT_TEST(TicketErrorsTest) {
+ TServiceContext::TImpl context(SECRET, NOT_OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket1 = context.Check(VALID_SERVICE_TICKET_1);
+ UNIT_ASSERT_EQUAL(ETicketStatus::InvalidDst, checkedTicket1->GetStatus());
+
+ auto checkedTicket2 = context.Check(UNSUPPORTED_VERSION_SERVICE_TICKET);
+ UNIT_ASSERT_EQUAL(ETicketStatus::UnsupportedVersion, checkedTicket2->GetStatus());
+
+ auto checkedTicket3 = context.Check(EXPIRED_SERVICE_TICKET);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Expired, checkedTicket3->GetStatus());
+ }
+
+ Y_UNIT_TEST(TicketExceptionTest) {
+ TServiceContext::TImpl context(SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+
+ auto checkedTicket = context.Check(EXPIRED_SERVICE_TICKET);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Expired, checkedTicket->GetStatus());
+
+ UNIT_ASSERT_EXCEPTION(checkedTicket->GetScopes(), TNotAllowedException);
+ UNIT_ASSERT_EXCEPTION(checkedTicket->GetSrc(), TNotAllowedException);
+ UNIT_ASSERT_EXCEPTION(checkedTicket->HasScope(""), TNotAllowedException);
+ UNIT_ASSERT_NO_EXCEPTION(bool(*checkedTicket));
+ UNIT_ASSERT_NO_EXCEPTION(checkedTicket->DebugInfo());
+ }
+
+ Y_UNIT_TEST(TicketProtoTest) {
+ ticket2::Ticket protobufTicket;
+ UNIT_ASSERT(protobufTicket.ParseFromString(NUtils::Base64url2bin(SERVICE_TICKET_PROTOBUF)));
+ TTestServiceTicketImpl checkedTicket(ETicketStatus::Ok, std::move(protobufTicket));
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket.GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL(std::numeric_limits<time_t>::max(), checkedTicket.GetExpirationTime());
+ UNIT_ASSERT_EQUAL(SRC_ID, checkedTicket.GetSrc());
+ }
+
+ Y_UNIT_TEST(ResetKeysTest) {
+ TServiceContext::TImpl context(SECRET, OUR_ID, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ context.ResetKeys(NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(VALID_SERVICE_TICKET_1);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket->GetStatus());
+ }
+
+ Y_UNIT_TEST(CreateTicketForTests) {
+ TCheckedServiceTicket t = NTvmAuth::NUnittest::CreateServiceTicket(ETicketStatus::Ok, 42);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, t.GetStatus());
+ UNIT_ASSERT_EQUAL(42, t.GetSrc());
+ UNIT_ASSERT_VALUES_EQUAL("ticket_type=serv;src=42;dst=100500;", t.DebugInfo());
+ }
+
+ Y_UNIT_TEST(CreateForTests) {
+ auto t = TCheckedServiceTicket::TImpl::CreateTicketForTests(ETicketStatus::Ok, 456, {});
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::Ok, t->GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL(456, t->GetSrc());
+ UNIT_ASSERT(!t->GetIssuerUid());
+
+ t = TCheckedServiceTicket::TImpl::CreateTicketForTests(ETicketStatus::Ok, 456, 100800);
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::Ok, t->GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL(456, t->GetSrc());
+ UNIT_ASSERT(t->GetIssuerUid());
+ UNIT_ASSERT_VALUES_EQUAL(*t->GetIssuerUid(), 100800);
+
+ t = TCheckedServiceTicket::TImpl::CreateTicketForTests(ETicketStatus::Expired, 456, {});
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::Expired, t->GetStatus());
+ UNIT_ASSERT_EXCEPTION_CONTAINS(t->GetSrc(), TNotAllowedException, "Method cannot be used in non-valid ticket");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(t->GetIssuerUid(), TNotAllowedException, "Method cannot be used in non-valid ticket");
+ }
+}
diff --git a/library/cpp/tvmauth/src/ut/user_ut.cpp b/library/cpp/tvmauth/src/ut/user_ut.cpp
new file mode 100644
index 0000000000..c040e94974
--- /dev/null
+++ b/library/cpp/tvmauth/src/ut/user_ut.cpp
@@ -0,0 +1,216 @@
+#include <library/cpp/tvmauth/src/user_impl.h>
+#include <library/cpp/tvmauth/src/utils.h>
+
+#include <library/cpp/tvmauth/exception.h>
+#include <library/cpp/tvmauth/unittest.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NTvmAuth;
+
+Y_UNIT_TEST_SUITE(UserTestSuite) {
+ Y_UNIT_TEST_DECLARE(TicketProtoTest);
+}
+
+class TTestUserTicketImpl: TCheckedUserTicket::TImpl {
+ using TCheckedUserTicket::TImpl::TImpl;
+ Y_UNIT_TEST_FRIEND(UserTestSuite, TicketProtoTest);
+};
+
+Y_UNIT_TEST_SUITE_IMPLEMENTATION(UserTestSuite) {
+ static const TString EMPTY_TVM_KEYS = "1:EpUBCpIBCAYQABqHATCBhAKBgQCoZkFGm9oLTqjeXZAq6j5S6i7K20V0lNdBBLqfmFBIRuTkYxhs4vUYnWjZrKRAd5bp6_py0csmFmpl_5Yh0b-2pdo_E5PNP7LGRzKyKSiFddyykKKzVOazH8YYldDAfE8Z5HoS9e48an5JsPg0jr-TPu34DnJq3yv2a6dqiKL9zSCakQY";
+ static const TString EXPIRED_USER_TICKET = "3:user:CA0QABokCgMIyAMKAgh7EMgDGghiYjpzZXNzMRoIYmI6c2VzczIgEigB:D0CmYVwWg91LDYejjeQ2UP8AeiA_mr1q1CUD_lfJ9zQSEYEOYGDTafg4Um2rwOOvQnsD1JHM4zHyMUJ6Jtp9GAm5pmhbXBBZqaCcJpyxLTEC8a81MhJFCCJRvu_G1FiAgRgB25gI3HIbkvHFUEqAIC_nANy7NFQnbKk2S-EQPGY";
+ static const TString MALFORMED_TVM_KEYS = "1:CpgCCpMCCAEQABqIAjCCAQQCggEAcLEXeH67FQESFUn4_7wnX7wN0PUrBoUsm3QQ4W5vC-qz6sXaEjSwnTV8w1o-z6X9KPLlhzMQvuS38NCNfK4uvJ4Zvfp3YsXJ25-rYtbnrYJHNvHohD-kPCCw_yZpMp21JdWigzQGuV7CtrxUhF-NNrsnUaJrE5-OpEWNt4X6nCItKIYeVcSK6XJUbEWbrNCRbvkSc4ak2ymFeMuHYJVjxh4eQbk7_ZPzodP0WvF6eUYrYeb42imVEOR8ofVLQWE5DVnb1z_TqZm4i1XkS7jMwZuBxBRw8DGdYei0lT_sAf7KST2jC0590NySB3vsBgWEVs1OdUUWA6r-Dvx9dsOQtSCVkQYQAAqZAgqUAggCEAAaiQIwggEFAoIBAQDhEBM5-6YsPWfogKtbluJoCX1WV2KdzOaQ0-OlRbBzeCzw-eQKu12c8WakHBbeCMd1I1TU64SDkDorWjXGIa_2xT6N3zzNAE50roTbPCcmeQrps26woTYfYIuqDdoxYKZNr0lvNLLW47vBr7EKqo1S4KSj7aXK_XYeEvUgIgf3nVIcNrio7VTnFmGGVQCepaL1Hi1gN4yIXjVZ06PBPZ-DxSRu6xOGbFrfKMJeMPs7KOyE-26Q3xOXdTIa1X-zYIucTd_bxUCL4BVbwW2AvbbFsaG7ISmVdGu0XUTmhXs1KrEfUVLRJhE4Dx99hAZXm1_HlYMUeJcMQ_oHOhV94ENFIJaRBhACCpYBCpEBCAMQABqGATCBgwKBgF9t2YJGAJkRRFq6fWhi3m1TFW1UOE0f6ZrfYhHAkpqGlKlh0QVfeTNPpeJhi75xXzCe6oReRUm-0DbqDNhTShC7uGUv1INYnRBQWH6E-5Fc5XrbDFSuGQw2EYjNfHy_HefHJXxQKAqPvxBDKMKkHgV58WtM6rC8jRi9sdX_ig2NIJeRBhABCpYBCpEBCAQQABqGATCBgwKBgGB4d6eLGUBv-Q6EPLehC4S-yuE2HB-_rJ7WkeYwyp-xIPolPrd-PQme2utHB4ZgpXHIu_OFksDe_0bPgZniNRSVRbl7W49DgS5Ya3kMfrYB4DnF5Fta5tn1oV6EwxYD4JONpFTenOJALPGTPawxXEfon_peiHOSBuQMu3_Vn-l1IJiRBhADCpcBCpIBCAUQABqHATCBhAKBgQCTJMKIfmfeZpaI7Q9rnsc29gdWawK7TnpVKRHws1iY7EUlYROeVcMdAwEqVM6f8BVCKLGgzQ7Gar_uuxfUGKwqEQzoppDraw4F75J464-7D5f6_oJQuGIBHZxqbMONtLjBCXRUhQW5szBLmTQ_R3qaJb5vf-h0APZfkYhq1cTttSCZkQYQBAqWAQqRAQgLEAAahgEwgYMCgYBvvGVH_M2H8qxxv94yaDYUTWbRnJ1uiIYc59KIQlfFimMPhSS7x2tqUa2-hI55JiII0Xym6GNkwLhyc1xtWChpVuIdSnbvttbrt4weDMLHqTwNOF6qAsVKGKT1Yh8yf-qb-DSmicgvFc74mBQm_6gAY1iQsf33YX8578ClhKBWHSCVkQYQAAqXAQqSAQgMEAAahwEwgYQCgYEAkuzFcd5TJu7lYWYe2hQLFfUWIIj91BvQQLa_Thln4YtGCO8gG1KJqJm-YlmJOWQG0B7H_5RVhxUxV9KpmFnsDVkzUFKOsCBaYGXc12xPVioawUlAwp5qp3QQtZyx_se97YIoLzuLr46UkLcLnkIrp-Jo46QzYi_QHq45WTm8MQ0glpEGEAIKlwEKkgEIDRAAGocBMIGEAoGBAIUzbxOknXf_rNt17_ir8JlWvrtnCWsQd1MAnl5mgArvavDtKeBYHzi5_Ak7DHlLzuA6YE8W175FxLFKpN2hkz-l-M7ltUSd8N1BvJRhK4t6WffWfC_1wPyoAbeSN2Yb1jygtZJQ8wGoXHcJQUXiMit3eFNyylwsJFj1gzAR4JCdIJeRBhABCpYBCpEBCA4QABqGATCBgwKBgFMcbEpl9ukVR6AO_R6sMyiU11I8b8MBSUCEC15iKsrVO8v_m47_TRRjWPYtQ9eZ7o1ocNJHaGUU7qqInFqtFaVnIceP6NmCsXhjs3MLrWPS8IRAy4Zf4FKmGOx3N9O2vemjUygZ9vUiSkULdVrecinRaT8JQ5RG4bUMY04XGIwFIJiRBhADCpYBCpEBCA8QABqGATCBgwKBgGpCkW-NR3li8GlRvqpq2YZGSIgm_PTyDI2Zwfw69grsBmPpVFW48Vw7xoMN35zcrojEpialB_uQzlpLYOvsMl634CRIuj-n1QE3-gaZTTTE8mg-AR4mcxnTKThPnRQpbuOlYAnriwiasWiQEMbGjq_HmWioYYxFo9USlklQn4-9IJmRBhAEEpUBCpIBCAYQABqHATCBhAKBgQCoZkFGm9oLTqjeXZAq6j5S6i7K20V0lNdBBLqfmFBIRuTkYxhs4vUYnWjZrKRAd5bp6_py0csmFmpl_5Yh0b-2pdo_E5PNP7LGRzKyKSiFddyykKKzVOazH8YYldDAfE8Z5HoS9e48an5JsPg0jr-TPu34DnJq3yv2a6dqiKL9zSCakQYSlQEKkgEIEBAAGocBMIGEAoGBALhrihbf3EpjDQS2sCQHazoFgN0nBbE9eesnnFTfzQELXb2gnJU9enmV_aDqaHKjgtLIPpCgn40lHrn5k6mvH5OdedyI6cCzE-N-GFp3nAq0NDJyMe0fhtIRD__CbT0ulcvkeow65ubXWfw6dBC2gR_34rdMe_L_TGRLMWjDULbNIJ";
+ static const TString UNSUPPORTED_VERSION_USER_TICKET = "2:user:CA0Q__________9_GiQKAwjIAwoCCHsQyAMaCGJiOnNlc3MxGghiYjpzZXNzMiASKAE:KJFv5EcXn9krYk19LCvlFrhMW-R4q8mKfXJXCd-RBVBgUQzCOR1Dx2FiOyU-BxUoIsaU0PiwTjbVY5I2onJDilge70Cl5zEPI9pfab2qwklACq_ZBUvD1tzrfNUr88otBGAziHASJWgyVDkhyQ3p7YbN38qpb0vGQrYNxlk4e2I";
+ static const TString USER_TICKET_PROTOBUF = "CA0Q__________9_GiQKAwjIAwoCCHsQyAMaCGJiOnNlc3MxGghiYjpzZXNzMiASKAE";
+ static const TString VALID_USER_TICKET_1 = "3:user:CA0Q__________9_GiQKAwjIAwoCCHsQyAMaCGJiOnNlc3MxGghiYjpzZXNzMiASKAE:KJFv5EcXn9krYk19LCvlFrhMW-R4q8mKfXJXCd-RBVBgUQzCOR1Dx2FiOyU-BxUoIsaU0PiwTjbVY5I2onJDilge70Cl5zEPI9pfab2qwklACq_ZBUvD1tzrfNUr88otBGAziHASJWgyVDkhyQ3p7YbN38qpb0vGQrYNxlk4e2I";
+ static const TString VALID_USER_TICKET_2 = "3:user:CA0Q__________9_GhAKAwjIAwoCCHsQyAMgEigB:KRibGYTJUA2ns0Fn7VYqeMZ1-GdscB1o9pRzELyr7QJrJsfsE8Y_HoVvB8Npr-oalv6AXOpagSc8HpZjAQz8zKMAVE_tI0tL-9DEsHirpawEbpy7OWV7-k18o1m-RaDaKeTlIB45KHbBul1-9aeKkortBfbbXtz_Qy9r_mfFPiQ";
+ static const TString VALID_USER_TICKET_3 = "3:user:CA0Q__________9_Go8bCgIIAAoCCAEKAggCCgIIAwoCCAQKAggFCgIIBgoCCAcKAggICgIICQoCCAoKAggLCgIIDAoCCA0KAggOCgIIDwoCCBAKAggRCgIIEgoCCBMKAggUCgIIFQoCCBYKAggXCgIIGAoCCBkKAggaCgIIGwoCCBwKAggdCgIIHgoCCB8KAgggCgIIIQoCCCIKAggjCgIIJAoCCCUKAggmCgIIJwoCCCgKAggpCgIIKgoCCCsKAggsCgIILQoCCC4KAggvCgIIMAoCCDEKAggyCgIIMwoCCDQKAgg1CgIINgoCCDcKAgg4CgIIOQoCCDoKAgg7CgIIPAoCCD0KAgg-CgIIPwoCCEAKAghBCgIIQgoCCEMKAghECgIIRQoCCEYKAghHCgIISAoCCEkKAghKCgIISwoCCEwKAghNCgIITgoCCE8KAghQCgIIUQoCCFIKAghTCgIIVAoCCFUKAghWCgIIVwoCCFgKAghZCgIIWgoCCFsKAghcCgIIXQoCCF4KAghfCgIIYAoCCGEKAghiCgIIYwoCCGQKAghlCgIIZgoCCGcKAghoCgIIaQoCCGoKAghrCgIIbAoCCG0KAghuCgIIbwoCCHAKAghxCgIIcgoCCHMKAgh0CgIIdQoCCHYKAgh3CgIIeAoCCHkKAgh6CgIIewoCCHwKAgh9CgIIfgoCCH8KAwiAAQoDCIEBCgMIggEKAwiDAQoDCIQBCgMIhQEKAwiGAQoDCIcBCgMIiAEKAwiJAQoDCIoBCgMIiwEKAwiMAQoDCI0BCgMIjgEKAwiPAQoDCJABCgMIkQEKAwiSAQoDCJMBCgMIlAEKAwiVAQoDCJYBCgMIlwEKAwiYAQoDCJkBCgMImgEKAwibAQoDCJwBCgMInQEKAwieAQoDCJ8BCgMIoAEKAwihAQoDCKIBCgMIowEKAwikAQoDCKUBCgMIpgEKAwinAQoDCKgBCgMIqQEKAwiqAQoDCKsBCgMIrAEKAwitAQoDCK4BCgMIrwEKAwiwAQoDCLEBCgMIsgEKAwizAQoDCLQBCgMItQEKAwi2AQoDCLcBCgMIuAEKAwi5AQoDCLoBCgMIuwEKAwi8AQoDCL0BCgMIvgEKAwi_AQoDCMABCgMIwQEKAwjCAQoDCMMBCgMIxAEKAwjFAQoDCMYBCgMIxwEKAwjIAQoDCMkBCgMIygEKAwjLAQoDCMwBCgMIzQEKAwjOAQoDCM8BCgMI0AEKAwjRAQoDCNIBCgMI0wEKAwjUAQoDCNUBCgMI1gEKAwjXAQoDCNgBCgMI2QEKAwjaAQoDCNsBCgMI3AEKAwjdAQoDCN4BCgMI3wEKAwjgAQoDCOEBCgMI4gEKAwjjAQoDCOQBCgMI5QEKAwjmAQoDCOcBCgMI6AEKAwjpAQoDCOoBCgMI6wEKAwjsAQoDCO0BCgMI7gEKAwjvAQoDCPABCgMI8QEKAwjyAQoDCPMBCgMI9AEKAwj1AQoDCPYBCgMI9wEKAwj4AQoDCPkBCgMI-gEKAwj7AQoDCPwBCgMI_QEKAwj-AQoDCP8BCgMIgAIKAwiBAgoDCIICCgMIgwIKAwiEAgoDCIUCCgMIhgIKAwiHAgoDCIgCCgMIiQIKAwiKAgoDCIsCCgMIjAIKAwiNAgoDCI4CCgMIjwIKAwiQAgoDCJECCgMIkgIKAwiTAgoDCJQCCgMIlQIKAwiWAgoDCJcCCgMImAIKAwiZAgoDCJoCCgMImwIKAwicAgoDCJ0CCgMIngIKAwifAgoDCKACCgMIoQIKAwiiAgoDCKMCCgMIpAIKAwilAgoDCKYCCgMIpwIKAwioAgoDCKkCCgMIqgIKAwirAgoDCKwCCgMIrQIKAwiuAgoDCK8CCgMIsAIKAwixAgoDCLICCgMIswIKAwi0AgoDCLUCCgMItgIKAwi3AgoDCLgCCgMIuQIKAwi6AgoDCLsCCgMIvAIKAwi9AgoDCL4CCgMIvwIKAwjAAgoDCMECCgMIwgIKAwjDAgoDCMQCCgMIxQIKAwjGAgoDCMcCCgMIyAIKAwjJAgoDCMoCCgMIywIKAwjMAgoDCM0CCgMIzgIKAwjPAgoDCNACCgMI0QIKAwjSAgoDCNMCCgMI1AIKAwjVAgoDCNYCCgMI1wIKAwjYAgoDCNkCCgMI2gIKAwjbAgoDCNwCCgMI3QIKAwjeAgoDCN8CCgMI4AIKAwjhAgoDCOICCgMI4wIKAwjkAgoDCOUCCgMI5gIKAwjnAgoDCOgCCgMI6QIKAwjqAgoDCOsCCgMI7AIKAwjtAgoDCO4CCgMI7wIKAwjwAgoDCPECCgMI8gIKAwjzAgoDCPQCCgMI9QIKAwj2AgoDCPcCCgMI-AIKAwj5AgoDCPoCCgMI-wIKAwj8AgoDCP0CCgMI_gIKAwj_AgoDCIADCgMIgQMKAwiCAwoDCIMDCgMIhAMKAwiFAwoDCIYDCgMIhwMKAwiIAwoDCIkDCgMIigMKAwiLAwoDCIwDCgMIjQMKAwiOAwoDCI8DCgMIkAMKAwiRAwoDCJIDCgMIkwMKAwiUAwoDCJUDCgMIlgMKAwiXAwoDCJgDCgMImQMKAwiaAwoDCJsDCgMInAMKAwidAwoDCJ4DCgMInwMKAwigAwoDCKEDCgMIogMKAwijAwoDCKQDCgMIpQMKAwimAwoDCKcDCgMIqAMKAwipAwoDCKoDCgMIqwMKAwisAwoDCK0DCgMIrgMKAwivAwoDCLADCgMIsQMKAwiyAwoDCLMDCgMItAMKAwi1AwoDCLYDCgMItwMKAwi4AwoDCLkDCgMIugMKAwi7AwoDCLwDCgMIvQMKAwi-AwoDCL8DCgMIwAMKAwjBAwoDCMIDCgMIwwMKAwjEAwoDCMUDCgMIxgMKAwjHAwoDCMgDCgMIyQMKAwjKAwoDCMsDCgMIzAMKAwjNAwoDCM4DCgMIzwMKAwjQAwoDCNEDCgMI0gMKAwjTAwoDCNQDCgMI1QMKAwjWAwoDCNcDCgMI2AMKAwjZAwoDCNoDCgMI2wMKAwjcAwoDCN0DCgMI3gMKAwjfAwoDCOADCgMI4QMKAwjiAwoDCOMDCgMI5AMKAwjlAwoDCOYDCgMI5wMKAwjoAwoDCOkDCgMI6gMKAwjrAwoDCOwDCgMI7QMKAwjuAwoDCO8DCgMI8AMKAwjxAwoDCPIDCgMI8wMQyAMaCGJiOnNlc3MxGgliYjpzZXNzMTAaCmJiOnNlc3MxMDAaCWJiOnNlc3MxMRoJYmI6c2VzczEyGgliYjpzZXNzMTMaCWJiOnNlc3MxNBoJYmI6c2VzczE1GgliYjpzZXNzMTYaCWJiOnNlc3MxNxoJYmI6c2VzczE4GgliYjpzZXNzMTkaCGJiOnNlc3MyGgliYjpzZXNzMjAaCWJiOnNlc3MyMRoJYmI6c2VzczIyGgliYjpzZXNzMjMaCWJiOnNlc3MyNBoJYmI6c2VzczI1GgliYjpzZXNzMjYaCWJiOnNlc3MyNxoJYmI6c2VzczI4GgliYjpzZXNzMjkaCGJiOnNlc3MzGgliYjpzZXNzMzAaCWJiOnNlc3MzMRoJYmI6c2VzczMyGgliYjpzZXNzMzMaCWJiOnNlc3MzNBoJYmI6c2VzczM1GgliYjpzZXNzMzYaCWJiOnNlc3MzNxoJYmI6c2VzczM4GgliYjpzZXNzMzkaCGJiOnNlc3M0GgliYjpzZXNzNDAaCWJiOnNlc3M0MRoJYmI6c2VzczQyGgliYjpzZXNzNDMaCWJiOnNlc3M0NBoJYmI6c2VzczQ1GgliYjpzZXNzNDYaCWJiOnNlc3M0NxoJYmI6c2VzczQ4GgliYjpzZXNzNDkaCGJiOnNlc3M1GgliYjpzZXNzNTAaCWJiOnNlc3M1MRoJYmI6c2VzczUyGgliYjpzZXNzNTMaCWJiOnNlc3M1NBoJYmI6c2VzczU1GgliYjpzZXNzNTYaCWJiOnNlc3M1NxoJYmI6c2VzczU4GgliYjpzZXNzNTkaCGJiOnNlc3M2GgliYjpzZXNzNjAaCWJiOnNlc3M2MRoJYmI6c2VzczYyGgliYjpzZXNzNjMaCWJiOnNlc3M2NBoJYmI6c2VzczY1GgliYjpzZXNzNjYaCWJiOnNlc3M2NxoJYmI6c2VzczY4GgliYjpzZXNzNjkaCGJiOnNlc3M3GgliYjpzZXNzNzAaCWJiOnNlc3M3MRoJYmI6c2VzczcyGgliYjpzZXNzNzMaCWJiOnNlc3M3NBoJYmI6c2Vzczc1GgliYjpzZXNzNzYaCWJiOnNlc3M3NxoJYmI6c2Vzczc4GgliYjpzZXNzNzkaCGJiOnNlc3M4GgliYjpzZXNzODAaCWJiOnNlc3M4MRoJYmI6c2VzczgyGgliYjpzZXNzODMaCWJiOnNlc3M4NBoJYmI6c2Vzczg1GgliYjpzZXNzODYaCWJiOnNlc3M4NxoJYmI6c2Vzczg4GgliYjpzZXNzODkaCGJiOnNlc3M5GgliYjpzZXNzOTAaCWJiOnNlc3M5MRoJYmI6c2VzczkyGgliYjpzZXNzOTMaCWJiOnNlc3M5NBoJYmI6c2Vzczk1GgliYjpzZXNzOTYaCWJiOnNlc3M5NxoJYmI6c2Vzczk4GgliYjpzZXNzOTkgEigB:CX8PIOrxJnQqFXl7wAsiHJ_1VGjoI-asNlCXb8SE8jtI2vdh9x6CqbAurSgIlAAEgotVP-nuUR38x_a9YJuXzmG5AvJ458apWQtODHIDIX6ZaIwMxjS02R7S5LNqXa0gAuU_R6bCWpZdWe2uLMkdpu5KHbDgW08g-uaP_nceDOk";
+
+ Y_UNIT_TEST(ContextText) {
+ TUserContext::TImpl context(EBlackboxEnv::Prod, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ UNIT_ASSERT_EQUAL(2, context.GetKeys().size());
+ UNIT_ASSERT_NO_EXCEPTION(context.ResetKeys(NUnittest::TVMKNIFE_PUBLIC_KEYS));
+ UNIT_ASSERT_EQUAL(2, context.GetKeys().size());
+ }
+
+ Y_UNIT_TEST(ContextEnvTest) {
+ TUserContext::TImpl p(EBlackboxEnv::Prod, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ UNIT_ASSERT_EQUAL(2, p.GetKeys().size());
+ UNIT_ASSERT(p.IsAllowed(tvm_keys::Prod));
+ UNIT_ASSERT(!p.IsAllowed(tvm_keys::ProdYateam));
+ UNIT_ASSERT(!p.IsAllowed(tvm_keys::Test));
+ UNIT_ASSERT(!p.IsAllowed(tvm_keys::TestYateam));
+ UNIT_ASSERT(!p.IsAllowed(tvm_keys::Stress));
+
+ TUserContext::TImpl pt(EBlackboxEnv::ProdYateam, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ UNIT_ASSERT_EQUAL(2, pt.GetKeys().size());
+ UNIT_ASSERT(!pt.IsAllowed(tvm_keys::Prod));
+ UNIT_ASSERT(pt.IsAllowed(tvm_keys::ProdYateam));
+ UNIT_ASSERT(!pt.IsAllowed(tvm_keys::Test));
+ UNIT_ASSERT(!pt.IsAllowed(tvm_keys::TestYateam));
+ UNIT_ASSERT(!pt.IsAllowed(tvm_keys::Stress));
+
+ TUserContext::TImpl t(EBlackboxEnv::Test, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ UNIT_ASSERT_EQUAL(2, t.GetKeys().size());
+ UNIT_ASSERT(!t.IsAllowed(tvm_keys::Prod));
+ UNIT_ASSERT(!t.IsAllowed(tvm_keys::ProdYateam));
+ UNIT_ASSERT(t.IsAllowed(tvm_keys::Test));
+ UNIT_ASSERT(!t.IsAllowed(tvm_keys::TestYateam));
+ UNIT_ASSERT(!t.IsAllowed(tvm_keys::Stress));
+
+ TUserContext::TImpl tt(EBlackboxEnv::TestYateam, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ UNIT_ASSERT_EQUAL(2, tt.GetKeys().size());
+ UNIT_ASSERT(!tt.IsAllowed(tvm_keys::Prod));
+ UNIT_ASSERT(!tt.IsAllowed(tvm_keys::ProdYateam));
+ UNIT_ASSERT(!tt.IsAllowed(tvm_keys::Test));
+ UNIT_ASSERT(tt.IsAllowed(tvm_keys::TestYateam));
+ UNIT_ASSERT(!tt.IsAllowed(tvm_keys::Stress));
+
+ TUserContext::TImpl s(EBlackboxEnv::Stress, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ UNIT_ASSERT_EQUAL(4, s.GetKeys().size());
+ UNIT_ASSERT(s.IsAllowed(tvm_keys::Prod));
+ UNIT_ASSERT(!s.IsAllowed(tvm_keys::ProdYateam));
+ UNIT_ASSERT(!s.IsAllowed(tvm_keys::Test));
+ UNIT_ASSERT(!s.IsAllowed(tvm_keys::TestYateam));
+ UNIT_ASSERT(s.IsAllowed(tvm_keys::Stress));
+ }
+
+ Y_UNIT_TEST(ContextExceptionsText) {
+ UNIT_ASSERT_EXCEPTION(TUserContext::TImpl(EBlackboxEnv::Prod, EMPTY_TVM_KEYS), TEmptyTvmKeysException);
+ UNIT_ASSERT_EXCEPTION(TUserContext::TImpl(EBlackboxEnv::Prod, MALFORMED_TVM_KEYS), TMalformedTvmKeysException);
+ UNIT_ASSERT_EXCEPTION(TUserContext::TImpl(EBlackboxEnv::Prod, "adcvxcv./-+"), TMalformedTvmKeysException);
+ }
+
+ Y_UNIT_TEST(Ticket1Test) {
+ TUserContext::TImpl context(EBlackboxEnv::Test, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(VALID_USER_TICKET_1);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket->GetStatus());
+ UNIT_ASSERT_EQUAL(std::numeric_limits<time_t>::max(), checkedTicket->GetExpirationTime());
+ UNIT_ASSERT_EQUAL(TUids({456, 123}), checkedTicket->GetUids());
+ UNIT_ASSERT_EQUAL(456, checkedTicket->GetDefaultUid());
+ UNIT_ASSERT_EQUAL(TScopes({"bb:sess1", "bb:sess2"}), checkedTicket->GetScopes());
+ UNIT_ASSERT(checkedTicket->HasScope("bb:sess1"));
+ UNIT_ASSERT(checkedTicket->HasScope("bb:sess2"));
+ UNIT_ASSERT(!checkedTicket->HasScope("bb:sess3"));
+ UNIT_ASSERT_EQUAL("ticket_type=user;expiration_time=9223372036854775807;scope=bb:sess1;scope=bb:sess2;default_uid=456;uid=456;uid=123;env=Test;", checkedTicket->DebugInfo());
+ }
+
+ Y_UNIT_TEST(Ticket2Test) {
+ TUserContext::TImpl context(EBlackboxEnv::Test, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(VALID_USER_TICKET_2);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket->GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL("ticket_type=user;expiration_time=9223372036854775807;default_uid=456;uid=456;uid=123;env=Test;", checkedTicket->DebugInfo());
+ }
+
+ Y_UNIT_TEST(Ticket3Test) {
+ TUserContext::TImpl context(EBlackboxEnv::Test, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(VALID_USER_TICKET_3);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket->GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL("ticket_type=user;expiration_time=9223372036854775807;scope=bb:sess1;scope=bb:sess10;scope=bb:sess100;scope=bb:sess11;scope=bb:sess12;scope=bb:sess13;scope=bb:sess14;scope=bb:sess15;scope=bb:sess16;scope=bb:sess17;scope=bb:sess18;scope=bb:sess19;scope=bb:sess2;scope=bb:sess20;scope=bb:sess21;scope=bb:sess22;scope=bb:sess23;scope=bb:sess24;scope=bb:sess25;scope=bb:sess26;scope=bb:sess27;scope=bb:sess28;scope=bb:sess29;scope=bb:sess3;scope=bb:sess30;scope=bb:sess31;scope=bb:sess32;scope=bb:sess33;scope=bb:sess34;scope=bb:sess35;scope=bb:sess36;scope=bb:sess37;scope=bb:sess38;scope=bb:sess39;scope=bb:sess4;scope=bb:sess40;scope=bb:sess41;scope=bb:sess42;scope=bb:sess43;scope=bb:sess44;scope=bb:sess45;scope=bb:sess46;scope=bb:sess47;scope=bb:sess48;scope=bb:sess49;scope=bb:sess5;scope=bb:sess50;scope=bb:sess51;scope=bb:sess52;scope=bb:sess53;scope=bb:sess54;scope=bb:sess55;scope=bb:sess56;scope=bb:sess57;scope=bb:sess58;scope=bb:sess59;scope=bb:sess6;scope=bb:sess60;scope=bb:sess61;scope=bb:sess62;scope=bb:sess63;scope=bb:sess64;scope=bb:sess65;scope=bb:sess66;scope=bb:sess67;scope=bb:sess68;scope=bb:sess69;scope=bb:sess7;scope=bb:sess70;scope=bb:sess71;scope=bb:sess72;scope=bb:sess73;scope=bb:sess74;scope=bb:sess75;scope=bb:sess76;scope=bb:sess77;scope=bb:sess78;scope=bb:sess79;scope=bb:sess8;scope=bb:sess80;scope=bb:sess81;scope=bb:sess82;scope=bb:sess83;scope=bb:sess84;scope=bb:sess85;scope=bb:sess86;scope=bb:sess87;scope=bb:sess88;scope=bb:sess89;scope=bb:sess9;scope=bb:sess90;scope=bb:sess91;scope=bb:sess92;scope=bb:sess93;scope=bb:sess94;scope=bb:sess95;scope=bb:sess96;scope=bb:sess97;scope=bb:sess98;scope=bb:sess99;default_uid=456;uid=0;uid=1;uid=2;uid=3;uid=4;uid=5;uid=6;uid=7;uid=8;uid=9;uid=10;uid=11;uid=12;uid=13;uid=14;uid=15;uid=16;uid=17;uid=18;uid=19;uid=20;uid=21;uid=22;uid=23;uid=24;uid=25;uid=26;uid=27;uid=28;uid=29;uid=30;uid=31;uid=32;uid=33;uid=34;uid=35;uid=36;uid=37;uid=38;uid=39;uid=40;uid=41;uid=42;uid=43;uid=44;uid=45;uid=46;uid=47;uid=48;uid=49;uid=50;uid=51;uid=52;uid=53;uid=54;uid=55;uid=56;uid=57;uid=58;uid=59;uid=60;uid=61;uid=62;uid=63;uid=64;uid=65;uid=66;uid=67;uid=68;uid=69;uid=70;uid=71;uid=72;uid=73;uid=74;uid=75;uid=76;uid=77;uid=78;uid=79;uid=80;uid=81;uid=82;uid=83;uid=84;uid=85;uid=86;uid=87;uid=88;uid=89;uid=90;uid=91;uid=92;uid=93;uid=94;uid=95;uid=96;uid=97;uid=98;uid=99;uid=100;uid=101;uid=102;uid=103;uid=104;uid=105;uid=106;uid=107;uid=108;uid=109;uid=110;uid=111;uid=112;uid=113;uid=114;uid=115;uid=116;uid=117;uid=118;uid=119;uid=120;uid=121;uid=122;uid=123;uid=124;uid=125;uid=126;uid=127;uid=128;uid=129;uid=130;uid=131;uid=132;uid=133;uid=134;uid=135;uid=136;uid=137;uid=138;uid=139;uid=140;uid=141;uid=142;uid=143;uid=144;uid=145;uid=146;uid=147;uid=148;uid=149;uid=150;uid=151;uid=152;uid=153;uid=154;uid=155;uid=156;uid=157;uid=158;uid=159;uid=160;uid=161;uid=162;uid=163;uid=164;uid=165;uid=166;uid=167;uid=168;uid=169;uid=170;uid=171;uid=172;uid=173;uid=174;uid=175;uid=176;uid=177;uid=178;uid=179;uid=180;uid=181;uid=182;uid=183;uid=184;uid=185;uid=186;uid=187;uid=188;uid=189;uid=190;uid=191;uid=192;uid=193;uid=194;uid=195;uid=196;uid=197;uid=198;uid=199;uid=200;uid=201;uid=202;uid=203;uid=204;uid=205;uid=206;uid=207;uid=208;uid=209;uid=210;uid=211;uid=212;uid=213;uid=214;uid=215;uid=216;uid=217;uid=218;uid=219;uid=220;uid=221;uid=222;uid=223;uid=224;uid=225;uid=226;uid=227;uid=228;uid=229;uid=230;uid=231;uid=232;uid=233;uid=234;uid=235;uid=236;uid=237;uid=238;uid=239;uid=240;uid=241;uid=242;uid=243;uid=244;uid=245;uid=246;uid=247;uid=248;uid=249;uid=250;uid=251;uid=252;uid=253;uid=254;uid=255;uid=256;uid=257;uid=258;uid=259;uid=260;uid=261;uid=262;uid=263;uid=264;uid=265;uid=266;uid=267;uid=268;uid=269;uid=270;uid=271;uid=272;uid=273;uid=274;uid=275;uid=276;uid=277;uid=278;uid=279;uid=280;uid=281;uid=282;uid=283;uid=284;uid=285;uid=286;uid=287;uid=288;uid=289;uid=290;uid=291;uid=292;uid=293;uid=294;uid=295;uid=296;uid=297;uid=298;uid=299;uid=300;uid=301;uid=302;uid=303;uid=304;uid=305;uid=306;uid=307;uid=308;uid=309;uid=310;uid=311;uid=312;uid=313;uid=314;uid=315;uid=316;uid=317;uid=318;uid=319;uid=320;uid=321;uid=322;uid=323;uid=324;uid=325;uid=326;uid=327;uid=328;uid=329;uid=330;uid=331;uid=332;uid=333;uid=334;uid=335;uid=336;uid=337;uid=338;uid=339;uid=340;uid=341;uid=342;uid=343;uid=344;uid=345;uid=346;uid=347;uid=348;uid=349;uid=350;uid=351;uid=352;uid=353;uid=354;uid=355;uid=356;uid=357;uid=358;uid=359;uid=360;uid=361;uid=362;uid=363;uid=364;uid=365;uid=366;uid=367;uid=368;uid=369;uid=370;uid=371;uid=372;uid=373;uid=374;uid=375;uid=376;uid=377;uid=378;uid=379;uid=380;uid=381;uid=382;uid=383;uid=384;uid=385;uid=386;uid=387;uid=388;uid=389;uid=390;uid=391;uid=392;uid=393;uid=394;uid=395;uid=396;uid=397;uid=398;uid=399;uid=400;uid=401;uid=402;uid=403;uid=404;uid=405;uid=406;uid=407;uid=408;uid=409;uid=410;uid=411;uid=412;uid=413;uid=414;uid=415;uid=416;uid=417;uid=418;uid=419;uid=420;uid=421;uid=422;uid=423;uid=424;uid=425;uid=426;uid=427;uid=428;uid=429;uid=430;uid=431;uid=432;uid=433;uid=434;uid=435;uid=436;uid=437;uid=438;uid=439;uid=440;uid=441;uid=442;uid=443;uid=444;uid=445;uid=446;uid=447;uid=448;uid=449;uid=450;uid=451;uid=452;uid=453;uid=454;uid=455;uid=456;uid=457;uid=458;uid=459;uid=460;uid=461;uid=462;uid=463;uid=464;uid=465;uid=466;uid=467;uid=468;uid=469;uid=470;uid=471;uid=472;uid=473;uid=474;uid=475;uid=476;uid=477;uid=478;uid=479;uid=480;uid=481;uid=482;uid=483;uid=484;uid=485;uid=486;uid=487;uid=488;uid=489;uid=490;uid=491;uid=492;uid=493;uid=494;uid=495;uid=496;uid=497;uid=498;uid=499;env=Test;", checkedTicket->DebugInfo());
+ }
+
+ Y_UNIT_TEST(TicketExceptionsTest) {
+ TUserContext::TImpl contextTest(EBlackboxEnv::Test, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket1 = contextTest.Check(UNSUPPORTED_VERSION_USER_TICKET);
+ UNIT_ASSERT_EQUAL(ETicketStatus::UnsupportedVersion, checkedTicket1->GetStatus());
+
+ auto checkedTicket2 = contextTest.Check(EXPIRED_USER_TICKET);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Expired, checkedTicket2->GetStatus());
+
+ TUserContext::TImpl contextProd(EBlackboxEnv::Prod, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket3 = contextProd.Check(VALID_USER_TICKET_1);
+ UNIT_ASSERT_EQUAL(ETicketStatus::InvalidBlackboxEnv, checkedTicket3->GetStatus());
+
+ UNIT_ASSERT_EXCEPTION(checkedTicket3->GetDefaultUid(), TNotAllowedException);
+ UNIT_ASSERT_EXCEPTION(checkedTicket3->GetUids(), TNotAllowedException);
+ UNIT_ASSERT_EXCEPTION(checkedTicket3->GetScopes(), TNotAllowedException);
+ UNIT_ASSERT_EXCEPTION(checkedTicket3->HasScope(""), TNotAllowedException);
+ UNIT_ASSERT_NO_EXCEPTION(bool(*checkedTicket3));
+ UNIT_ASSERT_NO_EXCEPTION(checkedTicket3->DebugInfo());
+ UNIT_ASSERT_NO_EXCEPTION(checkedTicket3->GetStatus());
+ }
+
+ Y_UNIT_TEST(TicketProtoTest) {
+ ticket2::Ticket protobufTicket;
+ UNIT_ASSERT(protobufTicket.ParseFromString(NUtils::Base64url2bin(USER_TICKET_PROTOBUF)));
+ TTestUserTicketImpl userTicket(ETicketStatus::Ok, std::move(protobufTicket));
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, userTicket.GetStatus());
+ UNIT_ASSERT_EQUAL(std::numeric_limits<time_t>::max(), userTicket.GetExpirationTime());
+ UNIT_ASSERT_EQUAL(TUids({456, 123}), userTicket.GetUids());
+ UNIT_ASSERT_EQUAL(456, userTicket.GetDefaultUid());
+ UNIT_ASSERT_EQUAL(TScopes({"bb:sess1", "bb:sess2"}), userTicket.GetScopes());
+ UNIT_ASSERT(userTicket.HasScope("bb:sess1"));
+ UNIT_ASSERT(userTicket.HasScope("bb:sess2"));
+ UNIT_ASSERT(!userTicket.HasScope("bb:sess3"));
+ }
+
+ Y_UNIT_TEST(ResetKeysTest) {
+ TUserContext::TImpl context(EBlackboxEnv::Test, NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ context.ResetKeys(NUnittest::TVMKNIFE_PUBLIC_KEYS);
+ auto checkedTicket = context.Check(VALID_USER_TICKET_1);
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, checkedTicket->GetStatus());
+ }
+
+ Y_UNIT_TEST(CreateTicketForTests) {
+ TCheckedUserTicket t = NTvmAuth::NUnittest::CreateUserTicket(ETicketStatus::Ok, 42, {"qwerty", "omg"}, {43, 55, 47});
+ UNIT_ASSERT_EQUAL(ETicketStatus::Ok, t.GetStatus());
+ UNIT_ASSERT_EQUAL(42, t.GetDefaultUid());
+ UNIT_ASSERT_EQUAL(TUids({42, 43, 47, 55}), t.GetUids());
+ UNIT_ASSERT_EQUAL(TScopes({"omg", "qwerty"}), t.GetScopes());
+ UNIT_ASSERT_VALUES_EQUAL("ticket_type=user;scope=omg;scope=qwerty;default_uid=42;uid=42;uid=43;uid=47;uid=55;env=Test;", t.DebugInfo());
+ }
+
+ Y_UNIT_TEST(CreateForTests) {
+ TUids uids{456};
+ TScopes scopes{"scope1", "scope2", "scope3"};
+ TScopes scopesIn{"scope1", "scope2", "scope3", "scope1", ""};
+ auto t = TCheckedUserTicket::TImpl::CreateTicketForTests(ETicketStatus::Ok, 456, scopesIn, {});
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::Ok, t->GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL(456, t->GetDefaultUid());
+ UNIT_ASSERT_VALUES_EQUAL(uids, t->GetUids());
+ UNIT_ASSERT_VALUES_EQUAL(scopes, t->GetScopes());
+
+ t = TCheckedUserTicket::TImpl::CreateTicketForTests(ETicketStatus::Ok, 456, scopesIn, {123, 456, 789});
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::Ok, t->GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL(456, t->GetDefaultUid());
+ uids = TUids{123, 456, 789};
+ UNIT_ASSERT_VALUES_EQUAL(uids, t->GetUids());
+ UNIT_ASSERT_VALUES_EQUAL(scopes, t->GetScopes());
+
+ t = TCheckedUserTicket::TImpl::CreateTicketForTests(ETicketStatus::Ok, 456, scopesIn, {123, 789});
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::Ok, t->GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL(456, t->GetDefaultUid());
+ uids = TUids{123, 456, 789};
+ UNIT_ASSERT_VALUES_EQUAL(uids, t->GetUids());
+ UNIT_ASSERT_VALUES_EQUAL(scopes, t->GetScopes());
+
+ t = TCheckedUserTicket::TImpl::CreateTicketForTests(ETicketStatus::Ok, 0, scopesIn, {123, 789});
+ UNIT_ASSERT_VALUES_EQUAL(ETicketStatus::Ok, t->GetStatus());
+ UNIT_ASSERT_VALUES_EQUAL(0, t->GetDefaultUid());
+ uids = TUids{123, 789};
+ UNIT_ASSERT_VALUES_EQUAL(uids, t->GetUids());
+ UNIT_ASSERT_VALUES_EQUAL(scopes, t->GetScopes());
+
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TCheckedUserTicket::TImpl::CreateTicketForTests(ETicketStatus::Ok, 0, scopesIn, {}),
+ yexception,
+ "User ticket cannot contain empty uid list");
+ UNIT_ASSERT_EXCEPTION_CONTAINS(TCheckedUserTicket::TImpl::CreateTicketForTests(ETicketStatus::Ok, 0, scopesIn, {0}),
+ yexception,
+ "User ticket cannot contain empty uid list");
+ }
+}
+
+template <>
+void Out<NTvmAuth::TUids>(IOutputStream& o, const NTvmAuth::TUids& v) {
+ for (const auto& uid : v) {
+ o << uid << ",";
+ }
+}
+
+template <>
+void Out<NTvmAuth::TScopes>(IOutputStream& o, const NTvmAuth::TScopes& v) {
+ for (const auto& scope : v) {
+ o << scope << ",";
+ }
+}
diff --git a/library/cpp/tvmauth/src/ut/utils_ut.cpp b/library/cpp/tvmauth/src/ut/utils_ut.cpp
new file mode 100644
index 0000000000..c9cb81c36f
--- /dev/null
+++ b/library/cpp/tvmauth/src/ut/utils_ut.cpp
@@ -0,0 +1,95 @@
+#include <library/cpp/tvmauth/src/utils.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/maybe.h>
+
+Y_UNIT_TEST_SUITE(UtilsTestSuite) {
+ static const TString VALID_SERVICE_TICKET_1 = "3:serv:CBAQ__________9_IhkI5QEQHBoIYmI6c2VzczEaCGJiOnNlc3My:WUPx1cTf05fjD1exB35T5j2DCHWH1YaLJon_a4rN-D7JfXHK1Ai4wM4uSfboHD9xmGQH7extqtlEk1tCTCGm5qbRVloJwWzCZBXo3zKX6i1oBYP_89WcjCNPVe1e8jwGdLsnu6PpxL5cn0xCksiStILH5UmDR6xfkJdnmMG94o8";
+ static const TString EXPIRED_SERVICE_TICKET = "3:serv:CBAQACIZCOUBEBwaCGJiOnNlc3MxGghiYjpzZXNzMg:IwfMNJYEqStY_SixwqJnyHOMCPR7-3HHk4uylB2oVRkthtezq-OOA7QizDvx7VABLs_iTlXuD1r5IjufNei_EiV145eaa3HIg4xCdJXCojMexf2UYJz8mF2b0YzFAy6_KWagU7xo13CyKAqzJuQf5MJcSUf0ecY9hVh36cJ51aw";
+ using namespace NTvmAuth;
+
+ Y_UNIT_TEST(base64Test) {
+ UNIT_ASSERT_VALUES_EQUAL("-hHx", NUtils::Bin2base64url("\xfa\x11\xf1"));
+ UNIT_ASSERT_VALUES_EQUAL("-hHx_g", NUtils::Bin2base64url("\xfa\x11\xf1\xfe"));
+ UNIT_ASSERT_VALUES_EQUAL("-hHx_v8", NUtils::Bin2base64url("\xfa\x11\xf1\xfe\xff"));
+
+ UNIT_ASSERT_VALUES_EQUAL("", NUtils::Base64url2bin("hHx++"));
+ UNIT_ASSERT_VALUES_EQUAL("", NUtils::Base64url2bin("&*^"));
+ UNIT_ASSERT_VALUES_EQUAL("", NUtils::Base64url2bin(""));
+ UNIT_ASSERT_VALUES_EQUAL("", NUtils::Bin2base64url(""));
+
+ UNIT_ASSERT_VALUES_EQUAL("\xfa\x11\xf1", NUtils::Base64url2bin("-hHx"));
+ UNIT_ASSERT_VALUES_EQUAL("\xfa\x11\xf1\xfe", NUtils::Base64url2bin("-hHx_g"));
+ UNIT_ASSERT_VALUES_EQUAL("\xfa\x11\xf1\xfe", NUtils::Base64url2bin("-hHx_g="));
+ UNIT_ASSERT_VALUES_EQUAL("\xfa\x11\xf1\xfe", NUtils::Base64url2bin("-hHx_g=="));
+ UNIT_ASSERT_VALUES_EQUAL("\xfa\x11\xf1\xfe\xff", NUtils::Base64url2bin("-hHx_v8"));
+ UNIT_ASSERT_VALUES_EQUAL("\xfa\x11\xf1\xfe\xff", NUtils::Base64url2bin("-hHx_v8="));
+
+ UNIT_ASSERT_VALUES_EQUAL("SGVsbG8sIGV2ZXJ5Ym9keSE",
+ NUtils::Bin2base64url(("Hello, everybody!")));
+ UNIT_ASSERT_VALUES_EQUAL("Hello, everybody!",
+ NUtils::Base64url2bin(("SGVsbG8sIGV2ZXJ5Ym9keSE")));
+ UNIT_ASSERT_VALUES_EQUAL("VGhlIE1hZ2ljIFdvcmRzIGFyZSBTcXVlYW1pc2ggT3NzaWZyYWdl",
+ NUtils::Bin2base64url(("The Magic Words are Squeamish Ossifrage")));
+ UNIT_ASSERT_VALUES_EQUAL("The Magic Words are Squeamish Ossifrage",
+ NUtils::Base64url2bin(("VGhlIE1hZ2ljIFdvcmRzIGFyZSBTcXVlYW1pc2ggT3NzaWZyYWdl")));
+ }
+
+ Y_UNIT_TEST(sign) {
+ UNIT_ASSERT_VALUES_EQUAL("wkGfeuopf709ozPAeGcDMqtZXPzsWvuNJ1BL586dSug",
+ NUtils::SignCgiParamsForTvm(NUtils::Base64url2bin("GRMJrKnj4fOVnvOqe-WyD1"),
+ "1490000000",
+ "13,19",
+ "bb:sess,bb:sess2"));
+
+ UNIT_ASSERT_VALUES_EQUAL("HANDYrA4ApQMQ5cfSWZk_InHWJffoXAa57P_X_B5s4M",
+ NUtils::SignCgiParamsForTvm(NUtils::Base64url2bin("GRMJrKnj4fOasvOqe-WyD1"),
+ "1490000000",
+ "13,19",
+ "bb:sess,bb:sess2"));
+
+ UNIT_ASSERT_VALUES_EQUAL("T-M-3_qtjRM1dR_3hS1CRlHBTZRKK04doHXBJw-5VRk",
+ NUtils::SignCgiParamsForTvm(NUtils::Base64url2bin("GRMJrKnj4fOasvOqe-WyD1"),
+ "1490000001",
+ "13,19",
+ "bb:sess,bb:sess2"));
+
+ UNIT_ASSERT_VALUES_EQUAL("gwB6M_9Jij50ZADmlDMnoyLc6AhQmtq6MClgGzO1PBE",
+ NUtils::SignCgiParamsForTvm(NUtils::Base64url2bin("GRMJrKnj4fOasvOqe-WyD1"),
+ "1490000001",
+ "13,19",
+ ""));
+ }
+
+ Y_UNIT_TEST(GetExpirationTime) {
+ UNIT_ASSERT(!NTvmAuth::NInternal::TCanningKnife::GetExpirationTime("3:aadasdasdasdas"));
+
+ UNIT_ASSERT(NTvmAuth::NInternal::TCanningKnife::GetExpirationTime(VALID_SERVICE_TICKET_1));
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(std::numeric_limits<time_t>::max()),
+ *NTvmAuth::NInternal::TCanningKnife::GetExpirationTime(VALID_SERVICE_TICKET_1));
+
+ UNIT_ASSERT(NTvmAuth::NInternal::TCanningKnife::GetExpirationTime(EXPIRED_SERVICE_TICKET));
+ UNIT_ASSERT_VALUES_EQUAL(TInstant::Seconds(0),
+ *NTvmAuth::NInternal::TCanningKnife::GetExpirationTime(EXPIRED_SERVICE_TICKET));
+ }
+
+ Y_UNIT_TEST(RemoveSignatureTest) {
+ UNIT_ASSERT_VALUES_EQUAL("1:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:asdxcvbxcvniueliuweklsvds",
+ NUtils::RemoveTicketSignature("1:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:asdxcvbxcvniueliuweklsvds"));
+ UNIT_ASSERT_VALUES_EQUAL("2:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:asdxcvbxcvniueliuweklsvds",
+ NUtils::RemoveTicketSignature("2:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:asdxcvbxcvniueliuweklsvds"));
+ UNIT_ASSERT_VALUES_EQUAL("4:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:asdxcvbxcvniueliuweklsvds",
+ NUtils::RemoveTicketSignature("4:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:asdxcvbxcvniueliuweklsvds"));
+ UNIT_ASSERT_VALUES_EQUAL("3.serv.ASDkljbjhsdbfLJHABFJHBslfbsfjs.asdxcvbxcvniueliuweklsvds",
+ NUtils::RemoveTicketSignature("3.serv.ASDkljbjhsdbfLJHABFJHBslfbsfjs.asdxcvbxcvniueliuweklsvds"));
+ UNIT_ASSERT_VALUES_EQUAL("3:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:",
+ NUtils::RemoveTicketSignature("3:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:asdxcvbxcvniueliuweklsvds"));
+ UNIT_ASSERT_VALUES_EQUAL("3:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:",
+ NUtils::RemoveTicketSignature("3:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs:asdxcvbxcvniueliuweklsvds"));
+ UNIT_ASSERT_VALUES_EQUAL("3:serv:",
+ NUtils::RemoveTicketSignature("3:serv:ASDkljbjhsdbfLJHABFJHBslfbsfjs.asdxcvbxcvniueliuweklsvds"));
+ UNIT_ASSERT_VALUES_EQUAL("asdxcbvfgdsgfasdfxczvdsgfxcdvbcbvf",
+ NUtils::RemoveTicketSignature("asdxcbvfgdsgfasdfxczvdsgfxcdvbcbvf"));
+ }
+}
diff --git a/library/cpp/tvmauth/src/ut/version_ut.cpp b/library/cpp/tvmauth/src/ut/version_ut.cpp
new file mode 100644
index 0000000000..eeb95d1cde
--- /dev/null
+++ b/library/cpp/tvmauth/src/ut/version_ut.cpp
@@ -0,0 +1,18 @@
+#include <library/cpp/tvmauth/version.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <regex>
+
+using namespace NTvmAuth;
+
+Y_UNIT_TEST_SUITE(VersionTest) {
+ Y_UNIT_TEST(base64Test) {
+ const std::regex re(R"(^\d+\.\d+\.\d+$)");
+
+ for (size_t idx = 0; idx < 2; ++idx) {
+ TStringBuf ver = LibVersion();
+ UNIT_ASSERT(std::regex_match(ver.begin(), ver.end(), re));
+ }
+ }
+}
diff --git a/library/cpp/tvmauth/src/ut/ya.make b/library/cpp/tvmauth/src/ut/ya.make
new file mode 100644
index 0000000000..9f510a8363
--- /dev/null
+++ b/library/cpp/tvmauth/src/ut/ya.make
@@ -0,0 +1,14 @@
+UNITTEST_FOR(library/cpp/tvmauth)
+
+OWNER(g:passport_infra)
+
+SRCS(
+ parser_ut.cpp
+ public_ut.cpp
+ service_ut.cpp
+ user_ut.cpp
+ utils_ut.cpp
+ version_ut.cpp
+)
+
+END()
diff --git a/library/cpp/tvmauth/src/utils.cpp b/library/cpp/tvmauth/src/utils.cpp
new file mode 100644
index 0000000000..d49efa28b5
--- /dev/null
+++ b/library/cpp/tvmauth/src/utils.cpp
@@ -0,0 +1,162 @@
+#include "utils.h"
+
+#include "parser.h"
+
+#include <contrib/libs/openssl/include/openssl/evp.h>
+#include <contrib/libs/openssl/include/openssl/hmac.h>
+#include <contrib/libs/openssl/include/openssl/md5.h>
+#include <contrib/libs/openssl/include/openssl/sha.h>
+
+#include <util/generic/maybe.h>
+#include <util/generic/strbuf.h>
+
+#include <array>
+
+namespace {
+ constexpr const unsigned char b64_encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+ constexpr std::array<unsigned char, 256> B64Init() {
+ std::array<unsigned char, 256> buf{};
+ for (auto& i : buf)
+ i = 0xff;
+
+ for (int i = 0; i < 64; ++i)
+ buf[b64_encode[i]] = i;
+
+ return buf;
+ }
+ constexpr std::array<unsigned char, 256> b64_decode = B64Init();
+}
+
+namespace NTvmAuth::NUtils {
+ TString Bin2base64url(TStringBuf buf) {
+ if (!buf) {
+ return TString();
+ }
+
+ TString res;
+ res.resize(((buf.size() + 2) / 3) << 2, 0);
+
+ const unsigned char* pB = (const unsigned char*)buf.data();
+ const unsigned char* pE = (const unsigned char*)buf.data() + buf.size();
+ unsigned char* p = (unsigned char*)res.data();
+ for (; pB + 2 < pE; pB += 3) {
+ const unsigned char a = *pB;
+ *p++ = b64_encode[(a >> 2) & 0x3F];
+ const unsigned char b = *(pB + 1);
+ *p++ = b64_encode[((a & 0x3) << 4) | ((b & 0xF0) >> 4)];
+ const unsigned char c = *(pB + 2);
+ *p++ = b64_encode[((b & 0xF) << 2) | ((c & 0xC0) >> 6)];
+ *p++ = b64_encode[c & 0x3F];
+ }
+
+ if (pB < pE) {
+ const unsigned char a = *pB;
+ *p++ = b64_encode[(a >> 2) & 0x3F];
+
+ if (pB == (pE - 1)) {
+ *p++ = b64_encode[((a & 0x3) << 4)];
+ } else {
+ const unsigned char b = *(pB + 1);
+ *p++ = b64_encode[((a & 0x3) << 4) |
+ ((int)(b & 0xF0) >> 4)];
+ *p++ = b64_encode[((b & 0xF) << 2)];
+ }
+ }
+
+ res.resize(p - (unsigned char*)res.data());
+ return res;
+ }
+
+ TString Base64url2bin(TStringBuf buf) {
+ const unsigned char* bufin = (const unsigned char*)buf.data();
+ if (!buf || b64_decode[*bufin] > 63) {
+ return TString();
+ }
+ const unsigned char* bufend = (const unsigned char*)buf.data() + buf.size();
+ while (++bufin < bufend && b64_decode[*bufin] < 64)
+ ;
+ int nprbytes = (bufin - (const unsigned char*)buf.data());
+ int nbytesdecoded = ((nprbytes + 3) / 4) * 3;
+
+ if (nprbytes < static_cast<int>(buf.size())) {
+ int left = buf.size() - nprbytes;
+ while (left--) {
+ if (*(bufin++) != '=')
+ return TString();
+ }
+ }
+
+ TString res;
+ res.resize(nbytesdecoded);
+
+ unsigned char* bufout = (unsigned char*)res.data();
+ bufin = (const unsigned char*)buf.data();
+
+ while (nprbytes > 4) {
+ unsigned char a = b64_decode[*bufin];
+ unsigned char b = b64_decode[bufin[1]];
+ *(bufout++) = (unsigned char)(a << 2 | b >> 4);
+ unsigned char c = b64_decode[bufin[2]];
+ *(bufout++) = (unsigned char)(b << 4 | c >> 2);
+ unsigned char d = b64_decode[bufin[3]];
+ *(bufout++) = (unsigned char)(c << 6 | d);
+ bufin += 4;
+ nprbytes -= 4;
+ }
+
+ if (nprbytes == 1) {
+ return {}; // Impossible
+ }
+ if (nprbytes > 1) {
+ *(bufout++) = (unsigned char)(b64_decode[*bufin] << 2 | b64_decode[bufin[1]] >> 4);
+ }
+ if (nprbytes > 2) {
+ *(bufout++) = (unsigned char)(b64_decode[bufin[1]] << 4 | b64_decode[bufin[2]] >> 2);
+ }
+ if (nprbytes > 3) {
+ *(bufout++) = (unsigned char)(b64_decode[bufin[2]] << 6 | b64_decode[bufin[3]]);
+ }
+
+ int diff = (4 - nprbytes) & 3;
+ if (diff) {
+ nbytesdecoded -= (4 - nprbytes) & 3;
+ res.resize(nbytesdecoded);
+ }
+
+ return res;
+ }
+
+ TString SignCgiParamsForTvm(TStringBuf secret, TStringBuf ts, TStringBuf dstTvmId, TStringBuf scopes) {
+ TString data;
+ data.reserve(ts.size() + dstTvmId.size() + scopes.size() + 3);
+ const char DELIM = '|';
+ data.append(ts).push_back(DELIM);
+ data.append(dstTvmId).push_back(DELIM);
+ data.append(scopes).push_back(DELIM);
+
+ TString value(EVP_MAX_MD_SIZE, 0);
+ unsigned macLen = 0;
+
+ if (!::HMAC(EVP_sha256(), secret.data(), secret.size(), (unsigned char*)data.data(), data.size(),
+ (unsigned char*)value.data(), &macLen))
+ {
+ return {};
+ }
+
+ if (macLen != EVP_MAX_MD_SIZE) {
+ value.resize(macLen);
+ }
+ return Bin2base64url(value);
+ }
+}
+
+namespace NTvmAuth::NInternal {
+ TMaybe<TInstant> TCanningKnife::GetExpirationTime(TStringBuf ticket) {
+ const TParserTickets::TRes res = TParserTickets::ParseV3(ticket, {}, TParserTickets::ServiceFlag());
+
+ return res.Status == ETicketStatus::MissingKey || res.Status == ETicketStatus::Expired
+ ? TInstant::Seconds(res.Ticket.expirationtime())
+ : TMaybe<TInstant>();
+ }
+}
diff --git a/library/cpp/tvmauth/src/utils.h b/library/cpp/tvmauth/src/utils.h
new file mode 100644
index 0000000000..e5847ac89f
--- /dev/null
+++ b/library/cpp/tvmauth/src/utils.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <library/cpp/tvmauth/checked_service_ticket.h>
+#include <library/cpp/tvmauth/checked_user_ticket.h>
+#include <library/cpp/tvmauth/ticket_status.h>
+
+#include <util/datetime/base.h>
+#include <util/generic/fwd.h>
+
+namespace NTvmAuth::NUtils {
+ TString Bin2base64url(TStringBuf buf);
+ TString Base64url2bin(TStringBuf buf);
+
+ TString SignCgiParamsForTvm(TStringBuf secret, TStringBuf ts, TStringBuf dstTvmId, TStringBuf scopes);
+}
+
+namespace NTvmAuth::NInternal {
+ class TCanningKnife {
+ public:
+ static TCheckedServiceTicket::TImpl* GetS(TCheckedServiceTicket& t) {
+ return t.Impl_.Release();
+ }
+
+ static TCheckedUserTicket::TImpl* GetU(TCheckedUserTicket& t) {
+ return t.Impl_.Release();
+ }
+
+ static TMaybe<TInstant> GetExpirationTime(TStringBuf ticket);
+ };
+}
diff --git a/library/cpp/tvmauth/src/version b/library/cpp/tvmauth/src/version
new file mode 100644
index 0000000000..15a2799817
--- /dev/null
+++ b/library/cpp/tvmauth/src/version
@@ -0,0 +1 @@
+3.3.0
diff --git a/library/cpp/tvmauth/src/version.cpp b/library/cpp/tvmauth/src/version.cpp
new file mode 100644
index 0000000000..6b389213d0
--- /dev/null
+++ b/library/cpp/tvmauth/src/version.cpp
@@ -0,0 +1,26 @@
+#include <library/cpp/resource/resource.h>
+
+#include <util/string/strip.h>
+
+namespace {
+ class TBuiltinVersion {
+ public:
+ TBuiltinVersion() {
+ Version_ = NResource::Find("/builtin/version");
+ StripInPlace(Version_);
+ }
+
+ TStringBuf Get() const {
+ return Version_;
+ }
+
+ private:
+ TString Version_;
+ };
+}
+
+namespace NTvmAuth {
+ TStringBuf LibVersion() {
+ return Singleton<TBuiltinVersion>()->Get();
+ }
+}
diff --git a/library/cpp/tvmauth/test_all/ya.make b/library/cpp/tvmauth/test_all/ya.make
new file mode 100644
index 0000000000..bb5bb9e5ef
--- /dev/null
+++ b/library/cpp/tvmauth/test_all/ya.make
@@ -0,0 +1,21 @@
+RECURSE_ROOT_RELATIVE(
+ library/cpp/tvmauth
+ library/cpp/tvmauth/client
+ library/go/yandex/tvm
+ library/go/yandex/tvm/tvmauth
+ library/java/ticket_parser2
+ library/java/tvmauth
+ library/python/deprecated/ticket_parser2
+ library/python/tvmauth
+)
+
+IF (NOT OS_WINDOWS)
+ RECURSE_ROOT_RELATIVE(
+ library/c/tvmauth/src/ut
+ )
+ IF (NOT SANITIZER_TYPE)
+ RECURSE_ROOT_RELATIVE(
+ library/c/tvmauth/src/ut_export
+ )
+ ENDIF()
+ENDIF()
diff --git a/library/cpp/tvmauth/ticket_status.h b/library/cpp/tvmauth/ticket_status.h
new file mode 100644
index 0000000000..532d4de56e
--- /dev/null
+++ b/library/cpp/tvmauth/ticket_status.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+namespace NTvmAuth {
+ /*!
+ * Status mean result of ticket check
+ */
+ enum class ETicketStatus {
+ Ok,
+ Expired,
+ InvalidBlackboxEnv,
+ InvalidDst,
+ InvalidTicketType,
+ Malformed,
+ MissingKey,
+ SignBroken,
+ UnsupportedVersion,
+ NoRoles,
+ };
+
+ TStringBuf StatusToString(ETicketStatus st);
+}
diff --git a/library/cpp/tvmauth/type.h b/library/cpp/tvmauth/type.h
new file mode 100644
index 0000000000..7f4ce2b700
--- /dev/null
+++ b/library/cpp/tvmauth/type.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <library/cpp/containers/stack_vector/stack_vec.h>
+
+namespace NTvmAuth {
+ using TScopes = TSmallVec<TStringBuf>;
+ using TTvmId = ui32;
+ using TUid = ui64;
+ using TUids = TSmallVec<TUid>;
+ using TAlias = TString;
+}
diff --git a/library/cpp/tvmauth/unittest.h b/library/cpp/tvmauth/unittest.h
new file mode 100644
index 0000000000..efa651befa
--- /dev/null
+++ b/library/cpp/tvmauth/unittest.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "checked_service_ticket.h"
+#include "checked_user_ticket.h"
+
+#include <util/generic/maybe.h>
+
+namespace NTvmAuth::NUnittest {
+ static const TString TVMKNIFE_PUBLIC_KEYS = "1:CpgCCpMCCAEQABqIAjCCAQQCggEAcLEXeH67FQESFUn4_7wnX7wN0PUrBoUsm3QQ4W5vC-qz6sXaEjSwnTV8w1o-z6X9KPLlhzMQvuS38NCNfK4uvJ4Zvfp3YsXJ25-rYtbnrYJHNvHohD-kPCCw_yZpMp21JdWigzQGuV7CtrxUhF-NNrsnUaJrE5-OpEWNt4X6nCItKIYeVcSK6XJUbEWbrNCRbvkSc4ak2ymFeMuHYJVjxh4eQbk7_ZPzodP0WvF6eUYrYeb42imVEOR8ofVLQWE5DVnb1z_TqZm4i1XkS7jMwZuBxBRw8DGdYei0lT_sAf7KST2jC0590NySB3vsBgWEVs1OdUUWA6r-Dvx9dsOQtSCVkQYQAAqZAgqUAggCEAAaiQIwggEFAoIBAQDhEBM5-6YsPWfogKtbluJoCX1WV2KdzOaQ0-OlRbBzeCzw-eQKu12c8WakHBbeCMd1I1TU64SDkDorWjXGIa_2xT6N3zzNAE50roTbPCcmeQrps26woTYfYIuqDdoxYKZNr0lvNLLW47vBr7EKqo1S4KSj7aXK_XYeEvUgIgf3nVIcNrio7VTnFmGGVQCepaL1Hi1gN4yIXjVZ06PBPZ-DxSRu6xOGbFrfKMJeMPs7KOyE-26Q3xOXdTIa1X-zYIucTd_bxUCL4BVbwW2AvbbFsaG7ISmVdGu0XUTmhXs1KrEfUVLRJhE4Dx99hAZXm1_HlYMUeJcMQ_oHOhV94ENFIJaRBhACCpYBCpEBCAMQABqGATCBgwKBgF9t2YJGAJkRRFq6fWhi3m1TFW1UOE0f6ZrfYhHAkpqGlKlh0QVfeTNPpeJhi75xXzCe6oReRUm-0DbqDNhTShC7uGUv1INYnRBQWH6E-5Fc5XrbDFSuGQw2EYjNfHy_HefHJXxQKAqPvxBDKMKkHgV58WtM6rC8jRi9sdX_ig2NIJeRBhABCpYBCpEBCAQQABqGATCBgwKBgGB4d6eLGUBv-Q6EPLehC4S-yuE2HB-_rJ7WkeYwyp-xIPolPrd-PQme2utHB4ZgpXHIu_OFksDe_0bPgZniNRSVRbl7W49DgS5Ya3kMfrYB4DnF5Fta5tn1oV6EwxYD4JONpFTenOJALPGTPawxXEfon_peiHOSBuQMu3_Vn-l1IJiRBhADCpcBCpIBCAUQABqHATCBhAKBgQCTJMKIfmfeZpaI7Q9rnsc29gdWawK7TnpVKRHws1iY7EUlYROeVcMdAwEqVM6f8BVCKLGgzQ7Gar_uuxfUGKwqEQzoppDraw4F75J464-7D5f6_oJQuGIBHZxqbMONtLjBCXRUhQW5szBLmTQ_R3qaJb5vf-h0APZfkYhq1cTttSCZkQYQBAqWAQqRAQgLEAAahgEwgYMCgYBvvGVH_M2H8qxxv94yaDYUTWbRnJ1uiIYc59KIQlfFimMPhSS7x2tqUa2-hI55JiII0Xym6GNkwLhyc1xtWChpVuIdSnbvttbrt4weDMLHqTwNOF6qAsVKGKT1Yh8yf-qb-DSmicgvFc74mBQm_6gAY1iQsf33YX8578ClhKBWHSCVkQYQAAqXAQqSAQgMEAAahwEwgYQCgYEAkuzFcd5TJu7lYWYe2hQLFfUWIIj91BvQQLa_Thln4YtGCO8gG1KJqJm-YlmJOWQG0B7H_5RVhxUxV9KpmFnsDVkzUFKOsCBaYGXc12xPVioawUlAwp5qp3QQtZyx_se97YIoLzuLr46UkLcLnkIrp-Jo46QzYi_QHq45WTm8MQ0glpEGEAIKlwEKkgEIDRAAGocBMIGEAoGBAIUzbxOknXf_rNt17_ir8JlWvrtnCWsQd1MAnl5mgArvavDtKeBYHzi5_Ak7DHlLzuA6YE8W175FxLFKpN2hkz-l-M7ltUSd8N1BvJRhK4t6WffWfC_1wPyoAbeSN2Yb1jygtZJQ8wGoXHcJQUXiMit3eFNyylwsJFj1gzAR4JCdIJeRBhABCpYBCpEBCA4QABqGATCBgwKBgFMcbEpl9ukVR6AO_R6sMyiU11I8b8MBSUCEC15iKsrVO8v_m47_TRRjWPYtQ9eZ7o1ocNJHaGUU7qqInFqtFaVnIceP6NmCsXhjs3MLrWPS8IRAy4Zf4FKmGOx3N9O2vemjUygZ9vUiSkULdVrecinRaT8JQ5RG4bUMY04XGIwFIJiRBhADCpYBCpEBCA8QABqGATCBgwKBgGpCkW-NR3li8GlRvqpq2YZGSIgm_PTyDI2Zwfw69grsBmPpVFW48Vw7xoMN35zcrojEpialB_uQzlpLYOvsMl634CRIuj-n1QE3-gaZTTTE8mg-AR4mcxnTKThPnRQpbuOlYAnriwiasWiQEMbGjq_HmWioYYxFo9USlklQn4-9IJmRBhAEEpUBCpIBCAYQABqHATCBhAKBgQCoZkFGm9oLTqjeXZAq6j5S6i7K20V0lNdBBLqfmFBIRuTkYxhs4vUYnWjZrKRAd5bp6_py0csmFmpl_5Yh0b-2pdo_E5PNP7LGRzKyKSiFddyykKKzVOazH8YYldDAfE8Z5HoS9e48an5JsPg0jr-TPu34DnJq3yv2a6dqiKL9zSCakQYSlQEKkgEIEBAAGocBMIGEAoGBALhrihbf3EpjDQS2sCQHazoFgN0nBbE9eesnnFTfzQELXb2gnJU9enmV_aDqaHKjgtLIPpCgn40lHrn5k6mvH5OdedyI6cCzE-N-GFp3nAq0NDJyMe0fhtIRD__CbT0ulcvkeow65ubXWfw6dBC2gR_34rdMe_L_TGRLMWjDULbNIJqRBg";
+
+ TCheckedServiceTicket CreateServiceTicket(ETicketStatus status,
+ TTvmId src,
+ TMaybe<TUid> issuerUid = TMaybe<TUid>());
+
+ TCheckedUserTicket CreateUserTicket(ETicketStatus status,
+ TUid defaultUid,
+ const TScopes& scopes,
+ const TUids& uids = TUids(),
+ EBlackboxEnv env = EBlackboxEnv::Test);
+}
diff --git a/library/cpp/tvmauth/utils.cpp b/library/cpp/tvmauth/utils.cpp
new file mode 100644
index 0000000000..a06cd6f5ba
--- /dev/null
+++ b/library/cpp/tvmauth/utils.cpp
@@ -0,0 +1,18 @@
+#include "utils.h"
+
+namespace NTvmAuth::NUtils {
+ TStringBuf RemoveTicketSignature(TStringBuf ticketBody) {
+ if (ticketBody.size() < 2 ||
+ ticketBody[0] != '3' ||
+ ticketBody[1] != ':') {
+ return ticketBody;
+ }
+
+ size_t pos = ticketBody.rfind(':');
+ if (pos == TStringBuf::npos) { // impossible
+ return ticketBody;
+ }
+
+ return ticketBody.substr(0, pos + 1);
+ }
+}
diff --git a/library/cpp/tvmauth/utils.h b/library/cpp/tvmauth/utils.h
new file mode 100644
index 0000000000..ad8950cab5
--- /dev/null
+++ b/library/cpp/tvmauth/utils.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+namespace NTvmAuth::NUtils {
+ /*!
+ * Remove signature from ticket string - rest part can be parsed later with `tvmknife parse_ticket ...`
+ * @param ticketBody Raw ticket body
+ * @return safe for logging part of ticket
+ */
+ TStringBuf RemoveTicketSignature(TStringBuf ticketBody);
+}
diff --git a/library/cpp/tvmauth/version.h b/library/cpp/tvmauth/version.h
new file mode 100644
index 0000000000..48ec279829
--- /dev/null
+++ b/library/cpp/tvmauth/version.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+namespace NTvmAuth {
+ TStringBuf LibVersion();
+}
diff --git a/library/cpp/tvmauth/ya.make b/library/cpp/tvmauth/ya.make
new file mode 100644
index 0000000000..655336c902
--- /dev/null
+++ b/library/cpp/tvmauth/ya.make
@@ -0,0 +1,40 @@
+LIBRARY()
+
+OWNER(g:passport_infra)
+
+PEERDIR(
+ library/cpp/string_utils/secret_string
+ library/cpp/tvmauth/src/protos
+ library/cpp/tvmauth/src/rw
+)
+
+SRCS(
+ deprecated/service_context.cpp
+ deprecated/user_context.cpp
+ src/parser.cpp
+ src/service_impl.cpp
+ src/service_ticket.cpp
+ src/status.cpp
+ src/unittest.cpp
+ src/user_impl.cpp
+ src/user_ticket.cpp
+ src/utils.cpp
+ src/version.cpp
+ utils.cpp
+)
+
+GENERATE_ENUM_SERIALIZATION(checked_user_ticket.h)
+GENERATE_ENUM_SERIALIZATION(ticket_status.h)
+
+RESOURCE(
+ src/version /builtin/version
+)
+
+END()
+
+RECURSE(
+ client
+ src/rw
+ src/ut
+ test_all
+)
diff --git a/library/cpp/unicode/normalization/custom_encoder.cpp b/library/cpp/unicode/normalization/custom_encoder.cpp
new file mode 100644
index 0000000000..c6f186405f
--- /dev/null
+++ b/library/cpp/unicode/normalization/custom_encoder.cpp
@@ -0,0 +1,83 @@
+#include "custom_encoder.h"
+#include "normalization.h"
+
+#include <util/string/cast.h>
+#include <util/stream/output.h>
+
+void TCustomEncoder::addToTable(wchar32 ucode, unsigned char code, const CodePage* target) {
+ unsigned char plane = (unsigned char)(ucode >> 8);
+ unsigned char pos = (unsigned char)(ucode & 255);
+ if (Table[plane] == DefaultPlane) {
+ Table[plane] = new char[256];
+ memset(Table[plane], 0, 256 * sizeof(char));
+ }
+
+ if (Table[plane][pos] == 0) {
+ Table[plane][pos] = code;
+ } else {
+ Y_ASSERT(target && *target->Names);
+ if (static_cast<unsigned char>(Table[plane][pos]) > 127 && code) {
+ Cerr << "WARNING: Only lower part of ASCII should have duplicate encodings "
+ << target->Names[0]
+ << " " << IntToString<16>(ucode)
+ << " " << IntToString<16>(code)
+ << " " << IntToString<16>(static_cast<unsigned char>(Table[plane][pos]))
+ << Endl;
+ }
+ }
+}
+
+bool isGoodDecomp(wchar32 rune, wchar32 decomp) {
+ if (
+ (NUnicode::NPrivate::CharInfo(rune) == NUnicode::NPrivate::CharInfo(decomp)) || (IsAlpha(rune) && IsAlpha(decomp)) || (IsNumeric(rune) && IsNumeric(decomp)) || (IsQuotation(rune) && IsQuotation(decomp)))
+ {
+ return true;
+ }
+ return false;
+}
+
+void TCustomEncoder::Create(const CodePage* target, bool extended) {
+ Y_ASSERT(target);
+
+ DefaultChar = (const char*)target->DefaultChar;
+
+ DefaultPlane = new char[256];
+
+ memset(DefaultPlane, 0, 256 * sizeof(char));
+ for (size_t i = 0; i != 256; ++i)
+ Table[i] = DefaultPlane;
+
+ for (size_t i = 0; i != 256; ++i) {
+ wchar32 ucode = target->unicode[i];
+ if (ucode != BROKEN_RUNE) // always UNASSIGNED
+ addToTable(ucode, (unsigned char)i, target);
+ }
+
+ if (!extended)
+ return;
+
+ for (wchar32 w = 1; w < 65535; w++) {
+ if (Code(w) == 0) {
+ wchar32 dw = w;
+ while (IsComposed(dw) && Code(dw) == 0) {
+ const wchar32* decomp_p = NUnicode::Decomposition<true>(dw);
+ Y_ASSERT(decomp_p != nullptr);
+
+ dw = decomp_p[0];
+ if (std::char_traits<wchar32>::length(decomp_p) > 1 && (dw == (wchar32)' ' || dw == (wchar32)'('))
+ dw = decomp_p[1];
+ }
+ if (Code(dw) != 0 && isGoodDecomp(w, dw))
+ addToTable(w, Code(dw), target);
+ }
+ }
+}
+
+TCustomEncoder::~TCustomEncoder() {
+ for (size_t i = 0; i != 256; ++i) {
+ if (Table[i] != DefaultPlane) {
+ delete[] Table[i];
+ }
+ }
+ delete[] DefaultPlane;
+}
diff --git a/library/cpp/unicode/normalization/custom_encoder.h b/library/cpp/unicode/normalization/custom_encoder.h
new file mode 100644
index 0000000000..ef4d5b7f65
--- /dev/null
+++ b/library/cpp/unicode/normalization/custom_encoder.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <library/cpp/charset/codepage.h>
+
+struct TCustomEncoder: public Encoder {
+ void Create(const CodePage* target, bool extended = false);
+ ~TCustomEncoder();
+
+private:
+ void addToTable(wchar32 ucode, unsigned char code, const CodePage* target);
+};
diff --git a/library/cpp/unicode/normalization/decomposition_table.h b/library/cpp/unicode/normalization/decomposition_table.h
new file mode 100644
index 0000000000..23f3da334f
--- /dev/null
+++ b/library/cpp/unicode/normalization/decomposition_table.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <util/charset/unicode_table.h>
+
+namespace NUnicode {
+ namespace NPrivate {
+ typedef NUnicodeTable::TTable<NUnicodeTable::TSubtable<
+ NUnicodeTable::UNICODE_TABLE_SHIFT, NUnicodeTable::TValues<const wchar32*>>>
+ TDecompositionTable;
+
+ const TDecompositionTable& CannonDecompositionTable();
+ const TDecompositionTable& CompatDecompositionTable();
+
+ template <bool compat>
+ inline const TDecompositionTable& DecompositionTable();
+
+ template <>
+ inline const TDecompositionTable& DecompositionTable<false>() {
+ return CannonDecompositionTable();
+ }
+
+ template <>
+ inline const TDecompositionTable& DecompositionTable<true>() {
+ return CompatDecompositionTable();
+ }
+
+ }
+}; // namespace NUnicode
diff --git a/library/cpp/unicode/normalization/generated/composition.cpp b/library/cpp/unicode/normalization/generated/composition.cpp
new file mode 100644
index 0000000000..7cc4dc7b75
--- /dev/null
+++ b/library/cpp/unicode/normalization/generated/composition.cpp
@@ -0,0 +1,950 @@
+#include <library/cpp/unicode/normalization/normalization.h>
+
+const NUnicode::NPrivate::TComposition::TRawData NUnicode::NPrivate::TComposition::RawData[] = {
+ { 0x41, 0x300, 0xC0 },
+ { 0x41, 0x301, 0xC1 },
+ { 0x41, 0x302, 0xC2 },
+ { 0x41, 0x303, 0xC3 },
+ { 0x41, 0x308, 0xC4 },
+ { 0x41, 0x30A, 0xC5 },
+ { 0x43, 0x327, 0xC7 },
+ { 0x45, 0x300, 0xC8 },
+ { 0x45, 0x301, 0xC9 },
+ { 0x45, 0x302, 0xCA },
+ { 0x45, 0x308, 0xCB },
+ { 0x49, 0x300, 0xCC },
+ { 0x49, 0x301, 0xCD },
+ { 0x49, 0x302, 0xCE },
+ { 0x49, 0x308, 0xCF },
+ { 0x4E, 0x303, 0xD1 },
+ { 0x4F, 0x300, 0xD2 },
+ { 0x4F, 0x301, 0xD3 },
+ { 0x4F, 0x302, 0xD4 },
+ { 0x4F, 0x303, 0xD5 },
+ { 0x4F, 0x308, 0xD6 },
+ { 0x55, 0x300, 0xD9 },
+ { 0x55, 0x301, 0xDA },
+ { 0x55, 0x302, 0xDB },
+ { 0x55, 0x308, 0xDC },
+ { 0x59, 0x301, 0xDD },
+ { 0x61, 0x300, 0xE0 },
+ { 0x61, 0x301, 0xE1 },
+ { 0x61, 0x302, 0xE2 },
+ { 0x61, 0x303, 0xE3 },
+ { 0x61, 0x308, 0xE4 },
+ { 0x61, 0x30A, 0xE5 },
+ { 0x63, 0x327, 0xE7 },
+ { 0x65, 0x300, 0xE8 },
+ { 0x65, 0x301, 0xE9 },
+ { 0x65, 0x302, 0xEA },
+ { 0x65, 0x308, 0xEB },
+ { 0x69, 0x300, 0xEC },
+ { 0x69, 0x301, 0xED },
+ { 0x69, 0x302, 0xEE },
+ { 0x69, 0x308, 0xEF },
+ { 0x6E, 0x303, 0xF1 },
+ { 0x6F, 0x300, 0xF2 },
+ { 0x6F, 0x301, 0xF3 },
+ { 0x6F, 0x302, 0xF4 },
+ { 0x6F, 0x303, 0xF5 },
+ { 0x6F, 0x308, 0xF6 },
+ { 0x75, 0x300, 0xF9 },
+ { 0x75, 0x301, 0xFA },
+ { 0x75, 0x302, 0xFB },
+ { 0x75, 0x308, 0xFC },
+ { 0x79, 0x301, 0xFD },
+ { 0x79, 0x308, 0xFF },
+ { 0x41, 0x304, 0x100 },
+ { 0x61, 0x304, 0x101 },
+ { 0x41, 0x306, 0x102 },
+ { 0x61, 0x306, 0x103 },
+ { 0x41, 0x328, 0x104 },
+ { 0x61, 0x328, 0x105 },
+ { 0x43, 0x301, 0x106 },
+ { 0x63, 0x301, 0x107 },
+ { 0x43, 0x302, 0x108 },
+ { 0x63, 0x302, 0x109 },
+ { 0x43, 0x307, 0x10A },
+ { 0x63, 0x307, 0x10B },
+ { 0x43, 0x30C, 0x10C },
+ { 0x63, 0x30C, 0x10D },
+ { 0x44, 0x30C, 0x10E },
+ { 0x64, 0x30C, 0x10F },
+ { 0x45, 0x304, 0x112 },
+ { 0x65, 0x304, 0x113 },
+ { 0x45, 0x306, 0x114 },
+ { 0x65, 0x306, 0x115 },
+ { 0x45, 0x307, 0x116 },
+ { 0x65, 0x307, 0x117 },
+ { 0x45, 0x328, 0x118 },
+ { 0x65, 0x328, 0x119 },
+ { 0x45, 0x30C, 0x11A },
+ { 0x65, 0x30C, 0x11B },
+ { 0x47, 0x302, 0x11C },
+ { 0x67, 0x302, 0x11D },
+ { 0x47, 0x306, 0x11E },
+ { 0x67, 0x306, 0x11F },
+ { 0x47, 0x307, 0x120 },
+ { 0x67, 0x307, 0x121 },
+ { 0x47, 0x327, 0x122 },
+ { 0x67, 0x327, 0x123 },
+ { 0x48, 0x302, 0x124 },
+ { 0x68, 0x302, 0x125 },
+ { 0x49, 0x303, 0x128 },
+ { 0x69, 0x303, 0x129 },
+ { 0x49, 0x304, 0x12A },
+ { 0x69, 0x304, 0x12B },
+ { 0x49, 0x306, 0x12C },
+ { 0x69, 0x306, 0x12D },
+ { 0x49, 0x328, 0x12E },
+ { 0x69, 0x328, 0x12F },
+ { 0x49, 0x307, 0x130 },
+ { 0x4A, 0x302, 0x134 },
+ { 0x6A, 0x302, 0x135 },
+ { 0x4B, 0x327, 0x136 },
+ { 0x6B, 0x327, 0x137 },
+ { 0x4C, 0x301, 0x139 },
+ { 0x6C, 0x301, 0x13A },
+ { 0x4C, 0x327, 0x13B },
+ { 0x6C, 0x327, 0x13C },
+ { 0x4C, 0x30C, 0x13D },
+ { 0x6C, 0x30C, 0x13E },
+ { 0x4E, 0x301, 0x143 },
+ { 0x6E, 0x301, 0x144 },
+ { 0x4E, 0x327, 0x145 },
+ { 0x6E, 0x327, 0x146 },
+ { 0x4E, 0x30C, 0x147 },
+ { 0x6E, 0x30C, 0x148 },
+ { 0x4F, 0x304, 0x14C },
+ { 0x6F, 0x304, 0x14D },
+ { 0x4F, 0x306, 0x14E },
+ { 0x6F, 0x306, 0x14F },
+ { 0x4F, 0x30B, 0x150 },
+ { 0x6F, 0x30B, 0x151 },
+ { 0x52, 0x301, 0x154 },
+ { 0x72, 0x301, 0x155 },
+ { 0x52, 0x327, 0x156 },
+ { 0x72, 0x327, 0x157 },
+ { 0x52, 0x30C, 0x158 },
+ { 0x72, 0x30C, 0x159 },
+ { 0x53, 0x301, 0x15A },
+ { 0x73, 0x301, 0x15B },
+ { 0x53, 0x302, 0x15C },
+ { 0x73, 0x302, 0x15D },
+ { 0x53, 0x327, 0x15E },
+ { 0x73, 0x327, 0x15F },
+ { 0x53, 0x30C, 0x160 },
+ { 0x73, 0x30C, 0x161 },
+ { 0x54, 0x327, 0x162 },
+ { 0x74, 0x327, 0x163 },
+ { 0x54, 0x30C, 0x164 },
+ { 0x74, 0x30C, 0x165 },
+ { 0x55, 0x303, 0x168 },
+ { 0x75, 0x303, 0x169 },
+ { 0x55, 0x304, 0x16A },
+ { 0x75, 0x304, 0x16B },
+ { 0x55, 0x306, 0x16C },
+ { 0x75, 0x306, 0x16D },
+ { 0x55, 0x30A, 0x16E },
+ { 0x75, 0x30A, 0x16F },
+ { 0x55, 0x30B, 0x170 },
+ { 0x75, 0x30B, 0x171 },
+ { 0x55, 0x328, 0x172 },
+ { 0x75, 0x328, 0x173 },
+ { 0x57, 0x302, 0x174 },
+ { 0x77, 0x302, 0x175 },
+ { 0x59, 0x302, 0x176 },
+ { 0x79, 0x302, 0x177 },
+ { 0x59, 0x308, 0x178 },
+ { 0x5A, 0x301, 0x179 },
+ { 0x7A, 0x301, 0x17A },
+ { 0x5A, 0x307, 0x17B },
+ { 0x7A, 0x307, 0x17C },
+ { 0x5A, 0x30C, 0x17D },
+ { 0x7A, 0x30C, 0x17E },
+ { 0x4F, 0x31B, 0x1A0 },
+ { 0x6F, 0x31B, 0x1A1 },
+ { 0x55, 0x31B, 0x1AF },
+ { 0x75, 0x31B, 0x1B0 },
+ { 0x41, 0x30C, 0x1CD },
+ { 0x61, 0x30C, 0x1CE },
+ { 0x49, 0x30C, 0x1CF },
+ { 0x69, 0x30C, 0x1D0 },
+ { 0x4F, 0x30C, 0x1D1 },
+ { 0x6F, 0x30C, 0x1D2 },
+ { 0x55, 0x30C, 0x1D3 },
+ { 0x75, 0x30C, 0x1D4 },
+ { 0xDC, 0x304, 0x1D5 },
+ { 0xFC, 0x304, 0x1D6 },
+ { 0xDC, 0x301, 0x1D7 },
+ { 0xFC, 0x301, 0x1D8 },
+ { 0xDC, 0x30C, 0x1D9 },
+ { 0xFC, 0x30C, 0x1DA },
+ { 0xDC, 0x300, 0x1DB },
+ { 0xFC, 0x300, 0x1DC },
+ { 0xC4, 0x304, 0x1DE },
+ { 0xE4, 0x304, 0x1DF },
+ { 0x226, 0x304, 0x1E0 },
+ { 0x227, 0x304, 0x1E1 },
+ { 0xC6, 0x304, 0x1E2 },
+ { 0xE6, 0x304, 0x1E3 },
+ { 0x47, 0x30C, 0x1E6 },
+ { 0x67, 0x30C, 0x1E7 },
+ { 0x4B, 0x30C, 0x1E8 },
+ { 0x6B, 0x30C, 0x1E9 },
+ { 0x4F, 0x328, 0x1EA },
+ { 0x6F, 0x328, 0x1EB },
+ { 0x1EA, 0x304, 0x1EC },
+ { 0x1EB, 0x304, 0x1ED },
+ { 0x1B7, 0x30C, 0x1EE },
+ { 0x292, 0x30C, 0x1EF },
+ { 0x6A, 0x30C, 0x1F0 },
+ { 0x47, 0x301, 0x1F4 },
+ { 0x67, 0x301, 0x1F5 },
+ { 0x4E, 0x300, 0x1F8 },
+ { 0x6E, 0x300, 0x1F9 },
+ { 0xC5, 0x301, 0x1FA },
+ { 0xE5, 0x301, 0x1FB },
+ { 0xC6, 0x301, 0x1FC },
+ { 0xE6, 0x301, 0x1FD },
+ { 0xD8, 0x301, 0x1FE },
+ { 0xF8, 0x301, 0x1FF },
+ { 0x41, 0x30F, 0x200 },
+ { 0x61, 0x30F, 0x201 },
+ { 0x41, 0x311, 0x202 },
+ { 0x61, 0x311, 0x203 },
+ { 0x45, 0x30F, 0x204 },
+ { 0x65, 0x30F, 0x205 },
+ { 0x45, 0x311, 0x206 },
+ { 0x65, 0x311, 0x207 },
+ { 0x49, 0x30F, 0x208 },
+ { 0x69, 0x30F, 0x209 },
+ { 0x49, 0x311, 0x20A },
+ { 0x69, 0x311, 0x20B },
+ { 0x4F, 0x30F, 0x20C },
+ { 0x6F, 0x30F, 0x20D },
+ { 0x4F, 0x311, 0x20E },
+ { 0x6F, 0x311, 0x20F },
+ { 0x52, 0x30F, 0x210 },
+ { 0x72, 0x30F, 0x211 },
+ { 0x52, 0x311, 0x212 },
+ { 0x72, 0x311, 0x213 },
+ { 0x55, 0x30F, 0x214 },
+ { 0x75, 0x30F, 0x215 },
+ { 0x55, 0x311, 0x216 },
+ { 0x75, 0x311, 0x217 },
+ { 0x53, 0x326, 0x218 },
+ { 0x73, 0x326, 0x219 },
+ { 0x54, 0x326, 0x21A },
+ { 0x74, 0x326, 0x21B },
+ { 0x48, 0x30C, 0x21E },
+ { 0x68, 0x30C, 0x21F },
+ { 0x41, 0x307, 0x226 },
+ { 0x61, 0x307, 0x227 },
+ { 0x45, 0x327, 0x228 },
+ { 0x65, 0x327, 0x229 },
+ { 0xD6, 0x304, 0x22A },
+ { 0xF6, 0x304, 0x22B },
+ { 0xD5, 0x304, 0x22C },
+ { 0xF5, 0x304, 0x22D },
+ { 0x4F, 0x307, 0x22E },
+ { 0x6F, 0x307, 0x22F },
+ { 0x22E, 0x304, 0x230 },
+ { 0x22F, 0x304, 0x231 },
+ { 0x59, 0x304, 0x232 },
+ { 0x79, 0x304, 0x233 },
+ { 0x308, 0x301, 0x344 },
+ { 0xA8, 0x301, 0x385 },
+ { 0x391, 0x301, 0x386 },
+ { 0x395, 0x301, 0x388 },
+ { 0x397, 0x301, 0x389 },
+ { 0x399, 0x301, 0x38A },
+ { 0x39F, 0x301, 0x38C },
+ { 0x3A5, 0x301, 0x38E },
+ { 0x3A9, 0x301, 0x38F },
+ { 0x3CA, 0x301, 0x390 },
+ { 0x399, 0x308, 0x3AA },
+ { 0x3A5, 0x308, 0x3AB },
+ { 0x3B1, 0x301, 0x3AC },
+ { 0x3B5, 0x301, 0x3AD },
+ { 0x3B7, 0x301, 0x3AE },
+ { 0x3B9, 0x301, 0x3AF },
+ { 0x3CB, 0x301, 0x3B0 },
+ { 0x3B9, 0x308, 0x3CA },
+ { 0x3C5, 0x308, 0x3CB },
+ { 0x3BF, 0x301, 0x3CC },
+ { 0x3C5, 0x301, 0x3CD },
+ { 0x3C9, 0x301, 0x3CE },
+ { 0x3D2, 0x301, 0x3D3 },
+ { 0x3D2, 0x308, 0x3D4 },
+ { 0x415, 0x300, 0x400 },
+ { 0x415, 0x308, 0x401 },
+ { 0x413, 0x301, 0x403 },
+ { 0x406, 0x308, 0x407 },
+ { 0x41A, 0x301, 0x40C },
+ { 0x418, 0x300, 0x40D },
+ { 0x423, 0x306, 0x40E },
+ { 0x418, 0x306, 0x419 },
+ { 0x438, 0x306, 0x439 },
+ { 0x435, 0x300, 0x450 },
+ { 0x435, 0x308, 0x451 },
+ { 0x433, 0x301, 0x453 },
+ { 0x456, 0x308, 0x457 },
+ { 0x43A, 0x301, 0x45C },
+ { 0x438, 0x300, 0x45D },
+ { 0x443, 0x306, 0x45E },
+ { 0x474, 0x30F, 0x476 },
+ { 0x475, 0x30F, 0x477 },
+ { 0x416, 0x306, 0x4C1 },
+ { 0x436, 0x306, 0x4C2 },
+ { 0x410, 0x306, 0x4D0 },
+ { 0x430, 0x306, 0x4D1 },
+ { 0x410, 0x308, 0x4D2 },
+ { 0x430, 0x308, 0x4D3 },
+ { 0x415, 0x306, 0x4D6 },
+ { 0x435, 0x306, 0x4D7 },
+ { 0x4D8, 0x308, 0x4DA },
+ { 0x4D9, 0x308, 0x4DB },
+ { 0x416, 0x308, 0x4DC },
+ { 0x436, 0x308, 0x4DD },
+ { 0x417, 0x308, 0x4DE },
+ { 0x437, 0x308, 0x4DF },
+ { 0x418, 0x304, 0x4E2 },
+ { 0x438, 0x304, 0x4E3 },
+ { 0x418, 0x308, 0x4E4 },
+ { 0x438, 0x308, 0x4E5 },
+ { 0x41E, 0x308, 0x4E6 },
+ { 0x43E, 0x308, 0x4E7 },
+ { 0x4E8, 0x308, 0x4EA },
+ { 0x4E9, 0x308, 0x4EB },
+ { 0x42D, 0x308, 0x4EC },
+ { 0x44D, 0x308, 0x4ED },
+ { 0x423, 0x304, 0x4EE },
+ { 0x443, 0x304, 0x4EF },
+ { 0x423, 0x308, 0x4F0 },
+ { 0x443, 0x308, 0x4F1 },
+ { 0x423, 0x30B, 0x4F2 },
+ { 0x443, 0x30B, 0x4F3 },
+ { 0x427, 0x308, 0x4F4 },
+ { 0x447, 0x308, 0x4F5 },
+ { 0x42B, 0x308, 0x4F8 },
+ { 0x44B, 0x308, 0x4F9 },
+ { 0x627, 0x653, 0x622 },
+ { 0x627, 0x654, 0x623 },
+ { 0x648, 0x654, 0x624 },
+ { 0x627, 0x655, 0x625 },
+ { 0x64A, 0x654, 0x626 },
+ { 0x6D5, 0x654, 0x6C0 },
+ { 0x6C1, 0x654, 0x6C2 },
+ { 0x6D2, 0x654, 0x6D3 },
+ { 0x928, 0x93C, 0x929 },
+ { 0x930, 0x93C, 0x931 },
+ { 0x933, 0x93C, 0x934 },
+ { 0x9C7, 0x9BE, 0x9CB },
+ { 0x9C7, 0x9D7, 0x9CC },
+ { 0xB47, 0xB56, 0xB48 },
+ { 0xB47, 0xB3E, 0xB4B },
+ { 0xB47, 0xB57, 0xB4C },
+ { 0xB92, 0xBD7, 0xB94 },
+ { 0xBC6, 0xBBE, 0xBCA },
+ { 0xBC7, 0xBBE, 0xBCB },
+ { 0xBC6, 0xBD7, 0xBCC },
+ { 0xC46, 0xC56, 0xC48 },
+ { 0xCBF, 0xCD5, 0xCC0 },
+ { 0xCC6, 0xCD5, 0xCC7 },
+ { 0xCC6, 0xCD6, 0xCC8 },
+ { 0xCC6, 0xCC2, 0xCCA },
+ { 0xCCA, 0xCD5, 0xCCB },
+ { 0xD46, 0xD3E, 0xD4A },
+ { 0xD47, 0xD3E, 0xD4B },
+ { 0xD46, 0xD57, 0xD4C },
+ { 0xDD9, 0xDCA, 0xDDA },
+ { 0xDD9, 0xDCF, 0xDDC },
+ { 0xDDC, 0xDCA, 0xDDD },
+ { 0xDD9, 0xDDF, 0xDDE },
+ { 0xF71, 0xF72, 0xF73 },
+ { 0xF71, 0xF74, 0xF75 },
+ { 0xF71, 0xF80, 0xF81 },
+ { 0x1025, 0x102E, 0x1026 },
+ { 0x1B05, 0x1B35, 0x1B06 },
+ { 0x1B07, 0x1B35, 0x1B08 },
+ { 0x1B09, 0x1B35, 0x1B0A },
+ { 0x1B0B, 0x1B35, 0x1B0C },
+ { 0x1B0D, 0x1B35, 0x1B0E },
+ { 0x1B11, 0x1B35, 0x1B12 },
+ { 0x1B3A, 0x1B35, 0x1B3B },
+ { 0x1B3C, 0x1B35, 0x1B3D },
+ { 0x1B3E, 0x1B35, 0x1B40 },
+ { 0x1B3F, 0x1B35, 0x1B41 },
+ { 0x1B42, 0x1B35, 0x1B43 },
+ { 0x41, 0x325, 0x1E00 },
+ { 0x61, 0x325, 0x1E01 },
+ { 0x42, 0x307, 0x1E02 },
+ { 0x62, 0x307, 0x1E03 },
+ { 0x42, 0x323, 0x1E04 },
+ { 0x62, 0x323, 0x1E05 },
+ { 0x42, 0x331, 0x1E06 },
+ { 0x62, 0x331, 0x1E07 },
+ { 0xC7, 0x301, 0x1E08 },
+ { 0xE7, 0x301, 0x1E09 },
+ { 0x44, 0x307, 0x1E0A },
+ { 0x64, 0x307, 0x1E0B },
+ { 0x44, 0x323, 0x1E0C },
+ { 0x64, 0x323, 0x1E0D },
+ { 0x44, 0x331, 0x1E0E },
+ { 0x64, 0x331, 0x1E0F },
+ { 0x44, 0x327, 0x1E10 },
+ { 0x64, 0x327, 0x1E11 },
+ { 0x44, 0x32D, 0x1E12 },
+ { 0x64, 0x32D, 0x1E13 },
+ { 0x112, 0x300, 0x1E14 },
+ { 0x113, 0x300, 0x1E15 },
+ { 0x112, 0x301, 0x1E16 },
+ { 0x113, 0x301, 0x1E17 },
+ { 0x45, 0x32D, 0x1E18 },
+ { 0x65, 0x32D, 0x1E19 },
+ { 0x45, 0x330, 0x1E1A },
+ { 0x65, 0x330, 0x1E1B },
+ { 0x228, 0x306, 0x1E1C },
+ { 0x229, 0x306, 0x1E1D },
+ { 0x46, 0x307, 0x1E1E },
+ { 0x66, 0x307, 0x1E1F },
+ { 0x47, 0x304, 0x1E20 },
+ { 0x67, 0x304, 0x1E21 },
+ { 0x48, 0x307, 0x1E22 },
+ { 0x68, 0x307, 0x1E23 },
+ { 0x48, 0x323, 0x1E24 },
+ { 0x68, 0x323, 0x1E25 },
+ { 0x48, 0x308, 0x1E26 },
+ { 0x68, 0x308, 0x1E27 },
+ { 0x48, 0x327, 0x1E28 },
+ { 0x68, 0x327, 0x1E29 },
+ { 0x48, 0x32E, 0x1E2A },
+ { 0x68, 0x32E, 0x1E2B },
+ { 0x49, 0x330, 0x1E2C },
+ { 0x69, 0x330, 0x1E2D },
+ { 0xCF, 0x301, 0x1E2E },
+ { 0xEF, 0x301, 0x1E2F },
+ { 0x4B, 0x301, 0x1E30 },
+ { 0x6B, 0x301, 0x1E31 },
+ { 0x4B, 0x323, 0x1E32 },
+ { 0x6B, 0x323, 0x1E33 },
+ { 0x4B, 0x331, 0x1E34 },
+ { 0x6B, 0x331, 0x1E35 },
+ { 0x4C, 0x323, 0x1E36 },
+ { 0x6C, 0x323, 0x1E37 },
+ { 0x1E36, 0x304, 0x1E38 },
+ { 0x1E37, 0x304, 0x1E39 },
+ { 0x4C, 0x331, 0x1E3A },
+ { 0x6C, 0x331, 0x1E3B },
+ { 0x4C, 0x32D, 0x1E3C },
+ { 0x6C, 0x32D, 0x1E3D },
+ { 0x4D, 0x301, 0x1E3E },
+ { 0x6D, 0x301, 0x1E3F },
+ { 0x4D, 0x307, 0x1E40 },
+ { 0x6D, 0x307, 0x1E41 },
+ { 0x4D, 0x323, 0x1E42 },
+ { 0x6D, 0x323, 0x1E43 },
+ { 0x4E, 0x307, 0x1E44 },
+ { 0x6E, 0x307, 0x1E45 },
+ { 0x4E, 0x323, 0x1E46 },
+ { 0x6E, 0x323, 0x1E47 },
+ { 0x4E, 0x331, 0x1E48 },
+ { 0x6E, 0x331, 0x1E49 },
+ { 0x4E, 0x32D, 0x1E4A },
+ { 0x6E, 0x32D, 0x1E4B },
+ { 0xD5, 0x301, 0x1E4C },
+ { 0xF5, 0x301, 0x1E4D },
+ { 0xD5, 0x308, 0x1E4E },
+ { 0xF5, 0x308, 0x1E4F },
+ { 0x14C, 0x300, 0x1E50 },
+ { 0x14D, 0x300, 0x1E51 },
+ { 0x14C, 0x301, 0x1E52 },
+ { 0x14D, 0x301, 0x1E53 },
+ { 0x50, 0x301, 0x1E54 },
+ { 0x70, 0x301, 0x1E55 },
+ { 0x50, 0x307, 0x1E56 },
+ { 0x70, 0x307, 0x1E57 },
+ { 0x52, 0x307, 0x1E58 },
+ { 0x72, 0x307, 0x1E59 },
+ { 0x52, 0x323, 0x1E5A },
+ { 0x72, 0x323, 0x1E5B },
+ { 0x1E5A, 0x304, 0x1E5C },
+ { 0x1E5B, 0x304, 0x1E5D },
+ { 0x52, 0x331, 0x1E5E },
+ { 0x72, 0x331, 0x1E5F },
+ { 0x53, 0x307, 0x1E60 },
+ { 0x73, 0x307, 0x1E61 },
+ { 0x53, 0x323, 0x1E62 },
+ { 0x73, 0x323, 0x1E63 },
+ { 0x15A, 0x307, 0x1E64 },
+ { 0x15B, 0x307, 0x1E65 },
+ { 0x160, 0x307, 0x1E66 },
+ { 0x161, 0x307, 0x1E67 },
+ { 0x1E62, 0x307, 0x1E68 },
+ { 0x1E63, 0x307, 0x1E69 },
+ { 0x54, 0x307, 0x1E6A },
+ { 0x74, 0x307, 0x1E6B },
+ { 0x54, 0x323, 0x1E6C },
+ { 0x74, 0x323, 0x1E6D },
+ { 0x54, 0x331, 0x1E6E },
+ { 0x74, 0x331, 0x1E6F },
+ { 0x54, 0x32D, 0x1E70 },
+ { 0x74, 0x32D, 0x1E71 },
+ { 0x55, 0x324, 0x1E72 },
+ { 0x75, 0x324, 0x1E73 },
+ { 0x55, 0x330, 0x1E74 },
+ { 0x75, 0x330, 0x1E75 },
+ { 0x55, 0x32D, 0x1E76 },
+ { 0x75, 0x32D, 0x1E77 },
+ { 0x168, 0x301, 0x1E78 },
+ { 0x169, 0x301, 0x1E79 },
+ { 0x16A, 0x308, 0x1E7A },
+ { 0x16B, 0x308, 0x1E7B },
+ { 0x56, 0x303, 0x1E7C },
+ { 0x76, 0x303, 0x1E7D },
+ { 0x56, 0x323, 0x1E7E },
+ { 0x76, 0x323, 0x1E7F },
+ { 0x57, 0x300, 0x1E80 },
+ { 0x77, 0x300, 0x1E81 },
+ { 0x57, 0x301, 0x1E82 },
+ { 0x77, 0x301, 0x1E83 },
+ { 0x57, 0x308, 0x1E84 },
+ { 0x77, 0x308, 0x1E85 },
+ { 0x57, 0x307, 0x1E86 },
+ { 0x77, 0x307, 0x1E87 },
+ { 0x57, 0x323, 0x1E88 },
+ { 0x77, 0x323, 0x1E89 },
+ { 0x58, 0x307, 0x1E8A },
+ { 0x78, 0x307, 0x1E8B },
+ { 0x58, 0x308, 0x1E8C },
+ { 0x78, 0x308, 0x1E8D },
+ { 0x59, 0x307, 0x1E8E },
+ { 0x79, 0x307, 0x1E8F },
+ { 0x5A, 0x302, 0x1E90 },
+ { 0x7A, 0x302, 0x1E91 },
+ { 0x5A, 0x323, 0x1E92 },
+ { 0x7A, 0x323, 0x1E93 },
+ { 0x5A, 0x331, 0x1E94 },
+ { 0x7A, 0x331, 0x1E95 },
+ { 0x68, 0x331, 0x1E96 },
+ { 0x74, 0x308, 0x1E97 },
+ { 0x77, 0x30A, 0x1E98 },
+ { 0x79, 0x30A, 0x1E99 },
+ { 0x17F, 0x307, 0x1E9B },
+ { 0x41, 0x323, 0x1EA0 },
+ { 0x61, 0x323, 0x1EA1 },
+ { 0x41, 0x309, 0x1EA2 },
+ { 0x61, 0x309, 0x1EA3 },
+ { 0xC2, 0x301, 0x1EA4 },
+ { 0xE2, 0x301, 0x1EA5 },
+ { 0xC2, 0x300, 0x1EA6 },
+ { 0xE2, 0x300, 0x1EA7 },
+ { 0xC2, 0x309, 0x1EA8 },
+ { 0xE2, 0x309, 0x1EA9 },
+ { 0xC2, 0x303, 0x1EAA },
+ { 0xE2, 0x303, 0x1EAB },
+ { 0x1EA0, 0x302, 0x1EAC },
+ { 0x1EA1, 0x302, 0x1EAD },
+ { 0x102, 0x301, 0x1EAE },
+ { 0x103, 0x301, 0x1EAF },
+ { 0x102, 0x300, 0x1EB0 },
+ { 0x103, 0x300, 0x1EB1 },
+ { 0x102, 0x309, 0x1EB2 },
+ { 0x103, 0x309, 0x1EB3 },
+ { 0x102, 0x303, 0x1EB4 },
+ { 0x103, 0x303, 0x1EB5 },
+ { 0x1EA0, 0x306, 0x1EB6 },
+ { 0x1EA1, 0x306, 0x1EB7 },
+ { 0x45, 0x323, 0x1EB8 },
+ { 0x65, 0x323, 0x1EB9 },
+ { 0x45, 0x309, 0x1EBA },
+ { 0x65, 0x309, 0x1EBB },
+ { 0x45, 0x303, 0x1EBC },
+ { 0x65, 0x303, 0x1EBD },
+ { 0xCA, 0x301, 0x1EBE },
+ { 0xEA, 0x301, 0x1EBF },
+ { 0xCA, 0x300, 0x1EC0 },
+ { 0xEA, 0x300, 0x1EC1 },
+ { 0xCA, 0x309, 0x1EC2 },
+ { 0xEA, 0x309, 0x1EC3 },
+ { 0xCA, 0x303, 0x1EC4 },
+ { 0xEA, 0x303, 0x1EC5 },
+ { 0x1EB8, 0x302, 0x1EC6 },
+ { 0x1EB9, 0x302, 0x1EC7 },
+ { 0x49, 0x309, 0x1EC8 },
+ { 0x69, 0x309, 0x1EC9 },
+ { 0x49, 0x323, 0x1ECA },
+ { 0x69, 0x323, 0x1ECB },
+ { 0x4F, 0x323, 0x1ECC },
+ { 0x6F, 0x323, 0x1ECD },
+ { 0x4F, 0x309, 0x1ECE },
+ { 0x6F, 0x309, 0x1ECF },
+ { 0xD4, 0x301, 0x1ED0 },
+ { 0xF4, 0x301, 0x1ED1 },
+ { 0xD4, 0x300, 0x1ED2 },
+ { 0xF4, 0x300, 0x1ED3 },
+ { 0xD4, 0x309, 0x1ED4 },
+ { 0xF4, 0x309, 0x1ED5 },
+ { 0xD4, 0x303, 0x1ED6 },
+ { 0xF4, 0x303, 0x1ED7 },
+ { 0x1ECC, 0x302, 0x1ED8 },
+ { 0x1ECD, 0x302, 0x1ED9 },
+ { 0x1A0, 0x301, 0x1EDA },
+ { 0x1A1, 0x301, 0x1EDB },
+ { 0x1A0, 0x300, 0x1EDC },
+ { 0x1A1, 0x300, 0x1EDD },
+ { 0x1A0, 0x309, 0x1EDE },
+ { 0x1A1, 0x309, 0x1EDF },
+ { 0x1A0, 0x303, 0x1EE0 },
+ { 0x1A1, 0x303, 0x1EE1 },
+ { 0x1A0, 0x323, 0x1EE2 },
+ { 0x1A1, 0x323, 0x1EE3 },
+ { 0x55, 0x323, 0x1EE4 },
+ { 0x75, 0x323, 0x1EE5 },
+ { 0x55, 0x309, 0x1EE6 },
+ { 0x75, 0x309, 0x1EE7 },
+ { 0x1AF, 0x301, 0x1EE8 },
+ { 0x1B0, 0x301, 0x1EE9 },
+ { 0x1AF, 0x300, 0x1EEA },
+ { 0x1B0, 0x300, 0x1EEB },
+ { 0x1AF, 0x309, 0x1EEC },
+ { 0x1B0, 0x309, 0x1EED },
+ { 0x1AF, 0x303, 0x1EEE },
+ { 0x1B0, 0x303, 0x1EEF },
+ { 0x1AF, 0x323, 0x1EF0 },
+ { 0x1B0, 0x323, 0x1EF1 },
+ { 0x59, 0x300, 0x1EF2 },
+ { 0x79, 0x300, 0x1EF3 },
+ { 0x59, 0x323, 0x1EF4 },
+ { 0x79, 0x323, 0x1EF5 },
+ { 0x59, 0x309, 0x1EF6 },
+ { 0x79, 0x309, 0x1EF7 },
+ { 0x59, 0x303, 0x1EF8 },
+ { 0x79, 0x303, 0x1EF9 },
+ { 0x3B1, 0x313, 0x1F00 },
+ { 0x3B1, 0x314, 0x1F01 },
+ { 0x1F00, 0x300, 0x1F02 },
+ { 0x1F01, 0x300, 0x1F03 },
+ { 0x1F00, 0x301, 0x1F04 },
+ { 0x1F01, 0x301, 0x1F05 },
+ { 0x1F00, 0x342, 0x1F06 },
+ { 0x1F01, 0x342, 0x1F07 },
+ { 0x391, 0x313, 0x1F08 },
+ { 0x391, 0x314, 0x1F09 },
+ { 0x1F08, 0x300, 0x1F0A },
+ { 0x1F09, 0x300, 0x1F0B },
+ { 0x1F08, 0x301, 0x1F0C },
+ { 0x1F09, 0x301, 0x1F0D },
+ { 0x1F08, 0x342, 0x1F0E },
+ { 0x1F09, 0x342, 0x1F0F },
+ { 0x3B5, 0x313, 0x1F10 },
+ { 0x3B5, 0x314, 0x1F11 },
+ { 0x1F10, 0x300, 0x1F12 },
+ { 0x1F11, 0x300, 0x1F13 },
+ { 0x1F10, 0x301, 0x1F14 },
+ { 0x1F11, 0x301, 0x1F15 },
+ { 0x395, 0x313, 0x1F18 },
+ { 0x395, 0x314, 0x1F19 },
+ { 0x1F18, 0x300, 0x1F1A },
+ { 0x1F19, 0x300, 0x1F1B },
+ { 0x1F18, 0x301, 0x1F1C },
+ { 0x1F19, 0x301, 0x1F1D },
+ { 0x3B7, 0x313, 0x1F20 },
+ { 0x3B7, 0x314, 0x1F21 },
+ { 0x1F20, 0x300, 0x1F22 },
+ { 0x1F21, 0x300, 0x1F23 },
+ { 0x1F20, 0x301, 0x1F24 },
+ { 0x1F21, 0x301, 0x1F25 },
+ { 0x1F20, 0x342, 0x1F26 },
+ { 0x1F21, 0x342, 0x1F27 },
+ { 0x397, 0x313, 0x1F28 },
+ { 0x397, 0x314, 0x1F29 },
+ { 0x1F28, 0x300, 0x1F2A },
+ { 0x1F29, 0x300, 0x1F2B },
+ { 0x1F28, 0x301, 0x1F2C },
+ { 0x1F29, 0x301, 0x1F2D },
+ { 0x1F28, 0x342, 0x1F2E },
+ { 0x1F29, 0x342, 0x1F2F },
+ { 0x3B9, 0x313, 0x1F30 },
+ { 0x3B9, 0x314, 0x1F31 },
+ { 0x1F30, 0x300, 0x1F32 },
+ { 0x1F31, 0x300, 0x1F33 },
+ { 0x1F30, 0x301, 0x1F34 },
+ { 0x1F31, 0x301, 0x1F35 },
+ { 0x1F30, 0x342, 0x1F36 },
+ { 0x1F31, 0x342, 0x1F37 },
+ { 0x399, 0x313, 0x1F38 },
+ { 0x399, 0x314, 0x1F39 },
+ { 0x1F38, 0x300, 0x1F3A },
+ { 0x1F39, 0x300, 0x1F3B },
+ { 0x1F38, 0x301, 0x1F3C },
+ { 0x1F39, 0x301, 0x1F3D },
+ { 0x1F38, 0x342, 0x1F3E },
+ { 0x1F39, 0x342, 0x1F3F },
+ { 0x3BF, 0x313, 0x1F40 },
+ { 0x3BF, 0x314, 0x1F41 },
+ { 0x1F40, 0x300, 0x1F42 },
+ { 0x1F41, 0x300, 0x1F43 },
+ { 0x1F40, 0x301, 0x1F44 },
+ { 0x1F41, 0x301, 0x1F45 },
+ { 0x39F, 0x313, 0x1F48 },
+ { 0x39F, 0x314, 0x1F49 },
+ { 0x1F48, 0x300, 0x1F4A },
+ { 0x1F49, 0x300, 0x1F4B },
+ { 0x1F48, 0x301, 0x1F4C },
+ { 0x1F49, 0x301, 0x1F4D },
+ { 0x3C5, 0x313, 0x1F50 },
+ { 0x3C5, 0x314, 0x1F51 },
+ { 0x1F50, 0x300, 0x1F52 },
+ { 0x1F51, 0x300, 0x1F53 },
+ { 0x1F50, 0x301, 0x1F54 },
+ { 0x1F51, 0x301, 0x1F55 },
+ { 0x1F50, 0x342, 0x1F56 },
+ { 0x1F51, 0x342, 0x1F57 },
+ { 0x3A5, 0x314, 0x1F59 },
+ { 0x1F59, 0x300, 0x1F5B },
+ { 0x1F59, 0x301, 0x1F5D },
+ { 0x1F59, 0x342, 0x1F5F },
+ { 0x3C9, 0x313, 0x1F60 },
+ { 0x3C9, 0x314, 0x1F61 },
+ { 0x1F60, 0x300, 0x1F62 },
+ { 0x1F61, 0x300, 0x1F63 },
+ { 0x1F60, 0x301, 0x1F64 },
+ { 0x1F61, 0x301, 0x1F65 },
+ { 0x1F60, 0x342, 0x1F66 },
+ { 0x1F61, 0x342, 0x1F67 },
+ { 0x3A9, 0x313, 0x1F68 },
+ { 0x3A9, 0x314, 0x1F69 },
+ { 0x1F68, 0x300, 0x1F6A },
+ { 0x1F69, 0x300, 0x1F6B },
+ { 0x1F68, 0x301, 0x1F6C },
+ { 0x1F69, 0x301, 0x1F6D },
+ { 0x1F68, 0x342, 0x1F6E },
+ { 0x1F69, 0x342, 0x1F6F },
+ { 0x3B1, 0x300, 0x1F70 },
+ { 0x3B5, 0x300, 0x1F72 },
+ { 0x3B7, 0x300, 0x1F74 },
+ { 0x3B9, 0x300, 0x1F76 },
+ { 0x3BF, 0x300, 0x1F78 },
+ { 0x3C5, 0x300, 0x1F7A },
+ { 0x3C9, 0x300, 0x1F7C },
+ { 0x1F00, 0x345, 0x1F80 },
+ { 0x1F01, 0x345, 0x1F81 },
+ { 0x1F02, 0x345, 0x1F82 },
+ { 0x1F03, 0x345, 0x1F83 },
+ { 0x1F04, 0x345, 0x1F84 },
+ { 0x1F05, 0x345, 0x1F85 },
+ { 0x1F06, 0x345, 0x1F86 },
+ { 0x1F07, 0x345, 0x1F87 },
+ { 0x1F08, 0x345, 0x1F88 },
+ { 0x1F09, 0x345, 0x1F89 },
+ { 0x1F0A, 0x345, 0x1F8A },
+ { 0x1F0B, 0x345, 0x1F8B },
+ { 0x1F0C, 0x345, 0x1F8C },
+ { 0x1F0D, 0x345, 0x1F8D },
+ { 0x1F0E, 0x345, 0x1F8E },
+ { 0x1F0F, 0x345, 0x1F8F },
+ { 0x1F20, 0x345, 0x1F90 },
+ { 0x1F21, 0x345, 0x1F91 },
+ { 0x1F22, 0x345, 0x1F92 },
+ { 0x1F23, 0x345, 0x1F93 },
+ { 0x1F24, 0x345, 0x1F94 },
+ { 0x1F25, 0x345, 0x1F95 },
+ { 0x1F26, 0x345, 0x1F96 },
+ { 0x1F27, 0x345, 0x1F97 },
+ { 0x1F28, 0x345, 0x1F98 },
+ { 0x1F29, 0x345, 0x1F99 },
+ { 0x1F2A, 0x345, 0x1F9A },
+ { 0x1F2B, 0x345, 0x1F9B },
+ { 0x1F2C, 0x345, 0x1F9C },
+ { 0x1F2D, 0x345, 0x1F9D },
+ { 0x1F2E, 0x345, 0x1F9E },
+ { 0x1F2F, 0x345, 0x1F9F },
+ { 0x1F60, 0x345, 0x1FA0 },
+ { 0x1F61, 0x345, 0x1FA1 },
+ { 0x1F62, 0x345, 0x1FA2 },
+ { 0x1F63, 0x345, 0x1FA3 },
+ { 0x1F64, 0x345, 0x1FA4 },
+ { 0x1F65, 0x345, 0x1FA5 },
+ { 0x1F66, 0x345, 0x1FA6 },
+ { 0x1F67, 0x345, 0x1FA7 },
+ { 0x1F68, 0x345, 0x1FA8 },
+ { 0x1F69, 0x345, 0x1FA9 },
+ { 0x1F6A, 0x345, 0x1FAA },
+ { 0x1F6B, 0x345, 0x1FAB },
+ { 0x1F6C, 0x345, 0x1FAC },
+ { 0x1F6D, 0x345, 0x1FAD },
+ { 0x1F6E, 0x345, 0x1FAE },
+ { 0x1F6F, 0x345, 0x1FAF },
+ { 0x3B1, 0x306, 0x1FB0 },
+ { 0x3B1, 0x304, 0x1FB1 },
+ { 0x1F70, 0x345, 0x1FB2 },
+ { 0x3B1, 0x345, 0x1FB3 },
+ { 0x3AC, 0x345, 0x1FB4 },
+ { 0x3B1, 0x342, 0x1FB6 },
+ { 0x1FB6, 0x345, 0x1FB7 },
+ { 0x391, 0x306, 0x1FB8 },
+ { 0x391, 0x304, 0x1FB9 },
+ { 0x391, 0x300, 0x1FBA },
+ { 0x391, 0x345, 0x1FBC },
+ { 0xA8, 0x342, 0x1FC1 },
+ { 0x1F74, 0x345, 0x1FC2 },
+ { 0x3B7, 0x345, 0x1FC3 },
+ { 0x3AE, 0x345, 0x1FC4 },
+ { 0x3B7, 0x342, 0x1FC6 },
+ { 0x1FC6, 0x345, 0x1FC7 },
+ { 0x395, 0x300, 0x1FC8 },
+ { 0x397, 0x300, 0x1FCA },
+ { 0x397, 0x345, 0x1FCC },
+ { 0x1FBF, 0x300, 0x1FCD },
+ { 0x1FBF, 0x301, 0x1FCE },
+ { 0x1FBF, 0x342, 0x1FCF },
+ { 0x3B9, 0x306, 0x1FD0 },
+ { 0x3B9, 0x304, 0x1FD1 },
+ { 0x3CA, 0x300, 0x1FD2 },
+ { 0x3B9, 0x342, 0x1FD6 },
+ { 0x3CA, 0x342, 0x1FD7 },
+ { 0x399, 0x306, 0x1FD8 },
+ { 0x399, 0x304, 0x1FD9 },
+ { 0x399, 0x300, 0x1FDA },
+ { 0x1FFE, 0x300, 0x1FDD },
+ { 0x1FFE, 0x301, 0x1FDE },
+ { 0x1FFE, 0x342, 0x1FDF },
+ { 0x3C5, 0x306, 0x1FE0 },
+ { 0x3C5, 0x304, 0x1FE1 },
+ { 0x3CB, 0x300, 0x1FE2 },
+ { 0x3C1, 0x313, 0x1FE4 },
+ { 0x3C1, 0x314, 0x1FE5 },
+ { 0x3C5, 0x342, 0x1FE6 },
+ { 0x3CB, 0x342, 0x1FE7 },
+ { 0x3A5, 0x306, 0x1FE8 },
+ { 0x3A5, 0x304, 0x1FE9 },
+ { 0x3A5, 0x300, 0x1FEA },
+ { 0x3A1, 0x314, 0x1FEC },
+ { 0xA8, 0x300, 0x1FED },
+ { 0x1F7C, 0x345, 0x1FF2 },
+ { 0x3C9, 0x345, 0x1FF3 },
+ { 0x3CE, 0x345, 0x1FF4 },
+ { 0x3C9, 0x342, 0x1FF6 },
+ { 0x1FF6, 0x345, 0x1FF7 },
+ { 0x39F, 0x300, 0x1FF8 },
+ { 0x3A9, 0x300, 0x1FFA },
+ { 0x3A9, 0x345, 0x1FFC },
+ { 0x2190, 0x338, 0x219A },
+ { 0x2192, 0x338, 0x219B },
+ { 0x2194, 0x338, 0x21AE },
+ { 0x21D0, 0x338, 0x21CD },
+ { 0x21D4, 0x338, 0x21CE },
+ { 0x21D2, 0x338, 0x21CF },
+ { 0x2203, 0x338, 0x2204 },
+ { 0x2208, 0x338, 0x2209 },
+ { 0x220B, 0x338, 0x220C },
+ { 0x2223, 0x338, 0x2224 },
+ { 0x2225, 0x338, 0x2226 },
+ { 0x223C, 0x338, 0x2241 },
+ { 0x2243, 0x338, 0x2244 },
+ { 0x2245, 0x338, 0x2247 },
+ { 0x2248, 0x338, 0x2249 },
+ { 0x3D, 0x338, 0x2260 },
+ { 0x2261, 0x338, 0x2262 },
+ { 0x224D, 0x338, 0x226D },
+ { 0x3C, 0x338, 0x226E },
+ { 0x3E, 0x338, 0x226F },
+ { 0x2264, 0x338, 0x2270 },
+ { 0x2265, 0x338, 0x2271 },
+ { 0x2272, 0x338, 0x2274 },
+ { 0x2273, 0x338, 0x2275 },
+ { 0x2276, 0x338, 0x2278 },
+ { 0x2277, 0x338, 0x2279 },
+ { 0x227A, 0x338, 0x2280 },
+ { 0x227B, 0x338, 0x2281 },
+ { 0x2282, 0x338, 0x2284 },
+ { 0x2283, 0x338, 0x2285 },
+ { 0x2286, 0x338, 0x2288 },
+ { 0x2287, 0x338, 0x2289 },
+ { 0x22A2, 0x338, 0x22AC },
+ { 0x22A8, 0x338, 0x22AD },
+ { 0x22A9, 0x338, 0x22AE },
+ { 0x22AB, 0x338, 0x22AF },
+ { 0x227C, 0x338, 0x22E0 },
+ { 0x227D, 0x338, 0x22E1 },
+ { 0x2291, 0x338, 0x22E2 },
+ { 0x2292, 0x338, 0x22E3 },
+ { 0x22B2, 0x338, 0x22EA },
+ { 0x22B3, 0x338, 0x22EB },
+ { 0x22B4, 0x338, 0x22EC },
+ { 0x22B5, 0x338, 0x22ED },
+ { 0x304B, 0x3099, 0x304C },
+ { 0x304D, 0x3099, 0x304E },
+ { 0x304F, 0x3099, 0x3050 },
+ { 0x3051, 0x3099, 0x3052 },
+ { 0x3053, 0x3099, 0x3054 },
+ { 0x3055, 0x3099, 0x3056 },
+ { 0x3057, 0x3099, 0x3058 },
+ { 0x3059, 0x3099, 0x305A },
+ { 0x305B, 0x3099, 0x305C },
+ { 0x305D, 0x3099, 0x305E },
+ { 0x305F, 0x3099, 0x3060 },
+ { 0x3061, 0x3099, 0x3062 },
+ { 0x3064, 0x3099, 0x3065 },
+ { 0x3066, 0x3099, 0x3067 },
+ { 0x3068, 0x3099, 0x3069 },
+ { 0x306F, 0x3099, 0x3070 },
+ { 0x306F, 0x309A, 0x3071 },
+ { 0x3072, 0x3099, 0x3073 },
+ { 0x3072, 0x309A, 0x3074 },
+ { 0x3075, 0x3099, 0x3076 },
+ { 0x3075, 0x309A, 0x3077 },
+ { 0x3078, 0x3099, 0x3079 },
+ { 0x3078, 0x309A, 0x307A },
+ { 0x307B, 0x3099, 0x307C },
+ { 0x307B, 0x309A, 0x307D },
+ { 0x3046, 0x3099, 0x3094 },
+ { 0x309D, 0x3099, 0x309E },
+ { 0x30AB, 0x3099, 0x30AC },
+ { 0x30AD, 0x3099, 0x30AE },
+ { 0x30AF, 0x3099, 0x30B0 },
+ { 0x30B1, 0x3099, 0x30B2 },
+ { 0x30B3, 0x3099, 0x30B4 },
+ { 0x30B5, 0x3099, 0x30B6 },
+ { 0x30B7, 0x3099, 0x30B8 },
+ { 0x30B9, 0x3099, 0x30BA },
+ { 0x30BB, 0x3099, 0x30BC },
+ { 0x30BD, 0x3099, 0x30BE },
+ { 0x30BF, 0x3099, 0x30C0 },
+ { 0x30C1, 0x3099, 0x30C2 },
+ { 0x30C4, 0x3099, 0x30C5 },
+ { 0x30C6, 0x3099, 0x30C7 },
+ { 0x30C8, 0x3099, 0x30C9 },
+ { 0x30CF, 0x3099, 0x30D0 },
+ { 0x30CF, 0x309A, 0x30D1 },
+ { 0x30D2, 0x3099, 0x30D3 },
+ { 0x30D2, 0x309A, 0x30D4 },
+ { 0x30D5, 0x3099, 0x30D6 },
+ { 0x30D5, 0x309A, 0x30D7 },
+ { 0x30D8, 0x3099, 0x30D9 },
+ { 0x30D8, 0x309A, 0x30DA },
+ { 0x30DB, 0x3099, 0x30DC },
+ { 0x30DB, 0x309A, 0x30DD },
+ { 0x30A6, 0x3099, 0x30F4 },
+ { 0x30EF, 0x3099, 0x30F7 },
+ { 0x30F0, 0x3099, 0x30F8 },
+ { 0x30F1, 0x3099, 0x30F9 },
+ { 0x30F2, 0x3099, 0x30FA },
+ { 0x30FD, 0x3099, 0x30FE },
+ { 0x11099, 0x110BA, 0x1109A },
+ { 0x1109B, 0x110BA, 0x1109C },
+ { 0x110A5, 0x110BA, 0x110AB },
+ { 0x11131, 0x11127, 0x1112E },
+ { 0x11132, 0x11127, 0x1112F },
+ { 0x11347, 0x1133E, 0x1134B },
+ { 0x11347, 0x11357, 0x1134C },
+ { 0x114B9, 0x114BA, 0x114BB },
+ { 0x114B9, 0x114B0, 0x114BC },
+ { 0x114B9, 0x114BD, 0x114BE },
+ { 0x115B8, 0x115AF, 0x115BA },
+ { 0x115B9, 0x115AF, 0x115BB },
+}; // TRawData
+
+const size_t NUnicode::NPrivate::TComposition::RawDataSize = Y_ARRAY_SIZE(NUnicode::NPrivate::TComposition::RawData);
diff --git a/library/cpp/unicode/normalization/generated/decomposition.cpp b/library/cpp/unicode/normalization/generated/decomposition.cpp
new file mode 100644
index 0000000000..9ac6a5f92a
--- /dev/null
+++ b/library/cpp/unicode/normalization/generated/decomposition.cpp
@@ -0,0 +1,91132 @@
+#include <library/cpp/unicode/normalization/decomposition_table.h>
+
+namespace { namespace NCannonDecompositionTableGenerated {
+ using TV = const NUnicode::NPrivate::TDecompositionTable::TStored;
+
+ static const TV V = {
+#undef V0
+#define V0 (V + 0)
+ 0x41, 0x300, 0,
+#undef V1
+#define V1 (V + 3)
+ 0x41, 0x301, 0,
+#undef V2
+#define V2 (V + 6)
+ 0x41, 0x302, 0,
+#undef V3
+#define V3 (V + 9)
+ 0x41, 0x303, 0,
+#undef V4
+#define V4 (V + 12)
+ 0x41, 0x308, 0,
+#undef V5
+#define V5 (V + 15)
+ 0x41, 0x30a, 0,
+#undef V6
+#define V6 (V + 18)
+ 0x43, 0x327, 0,
+#undef V7
+#define V7 (V + 21)
+ 0x45, 0x300, 0,
+#undef V8
+#define V8 (V + 24)
+ 0x45, 0x301, 0,
+#undef V9
+#define V9 (V + 27)
+ 0x45, 0x302, 0,
+#undef V10
+#define V10 (V + 30)
+ 0x45, 0x308, 0,
+#undef V11
+#define V11 (V + 33)
+ 0x49, 0x300, 0,
+#undef V12
+#define V12 (V + 36)
+ 0x49, 0x301, 0,
+#undef V13
+#define V13 (V + 39)
+ 0x49, 0x302, 0,
+#undef V14
+#define V14 (V + 42)
+ 0x49, 0x308, 0,
+#undef V15
+#define V15 (V + 45)
+ 0x4e, 0x303, 0,
+#undef V16
+#define V16 (V + 48)
+ 0x4f, 0x300, 0,
+#undef V17
+#define V17 (V + 51)
+ 0x4f, 0x301, 0,
+#undef V18
+#define V18 (V + 54)
+ 0x4f, 0x302, 0,
+#undef V19
+#define V19 (V + 57)
+ 0x4f, 0x303, 0,
+#undef V20
+#define V20 (V + 60)
+ 0x4f, 0x308, 0,
+#undef V21
+#define V21 (V + 63)
+ 0x55, 0x300, 0,
+#undef V22
+#define V22 (V + 66)
+ 0x55, 0x301, 0,
+#undef V23
+#define V23 (V + 69)
+ 0x55, 0x302, 0,
+#undef V24
+#define V24 (V + 72)
+ 0x55, 0x308, 0,
+#undef V25
+#define V25 (V + 75)
+ 0x59, 0x301, 0,
+#undef V26
+#define V26 (V + 78)
+ 0x61, 0x300, 0,
+#undef V27
+#define V27 (V + 81)
+ 0x61, 0x301, 0,
+#undef V28
+#define V28 (V + 84)
+ 0x61, 0x302, 0,
+#undef V29
+#define V29 (V + 87)
+ 0x61, 0x303, 0,
+#undef V30
+#define V30 (V + 90)
+ 0x61, 0x308, 0,
+#undef V31
+#define V31 (V + 93)
+ 0x61, 0x30a, 0,
+#undef V32
+#define V32 (V + 96)
+ 0x63, 0x327, 0,
+#undef V33
+#define V33 (V + 99)
+ 0x65, 0x300, 0,
+#undef V34
+#define V34 (V + 102)
+ 0x65, 0x301, 0,
+#undef V35
+#define V35 (V + 105)
+ 0x65, 0x302, 0,
+#undef V36
+#define V36 (V + 108)
+ 0x65, 0x308, 0,
+#undef V37
+#define V37 (V + 111)
+ 0x69, 0x300, 0,
+#undef V38
+#define V38 (V + 114)
+ 0x69, 0x301, 0,
+#undef V39
+#define V39 (V + 117)
+ 0x69, 0x302, 0,
+#undef V40
+#define V40 (V + 120)
+ 0x69, 0x308, 0,
+#undef V41
+#define V41 (V + 123)
+ 0x6e, 0x303, 0,
+#undef V42
+#define V42 (V + 126)
+ 0x6f, 0x300, 0,
+#undef V43
+#define V43 (V + 129)
+ 0x6f, 0x301, 0,
+#undef V44
+#define V44 (V + 132)
+ 0x6f, 0x302, 0,
+#undef V45
+#define V45 (V + 135)
+ 0x6f, 0x303, 0,
+#undef V46
+#define V46 (V + 138)
+ 0x6f, 0x308, 0,
+#undef V47
+#define V47 (V + 141)
+ 0x75, 0x300, 0,
+#undef V48
+#define V48 (V + 144)
+ 0x75, 0x301, 0,
+#undef V49
+#define V49 (V + 147)
+ 0x75, 0x302, 0,
+#undef V50
+#define V50 (V + 150)
+ 0x75, 0x308, 0,
+#undef V51
+#define V51 (V + 153)
+ 0x79, 0x301, 0,
+#undef V52
+#define V52 (V + 156)
+ 0x79, 0x308, 0,
+#undef V53
+#define V53 (V + 159)
+ 0x41, 0x304, 0,
+#undef V54
+#define V54 (V + 162)
+ 0x61, 0x304, 0,
+#undef V55
+#define V55 (V + 165)
+ 0x41, 0x306, 0,
+#undef V56
+#define V56 (V + 168)
+ 0x61, 0x306, 0,
+#undef V57
+#define V57 (V + 171)
+ 0x41, 0x328, 0,
+#undef V58
+#define V58 (V + 174)
+ 0x61, 0x328, 0,
+#undef V59
+#define V59 (V + 177)
+ 0x43, 0x301, 0,
+#undef V60
+#define V60 (V + 180)
+ 0x63, 0x301, 0,
+#undef V61
+#define V61 (V + 183)
+ 0x43, 0x302, 0,
+#undef V62
+#define V62 (V + 186)
+ 0x63, 0x302, 0,
+#undef V63
+#define V63 (V + 189)
+ 0x43, 0x307, 0,
+#undef V64
+#define V64 (V + 192)
+ 0x63, 0x307, 0,
+#undef V65
+#define V65 (V + 195)
+ 0x43, 0x30c, 0,
+#undef V66
+#define V66 (V + 198)
+ 0x63, 0x30c, 0,
+#undef V67
+#define V67 (V + 201)
+ 0x44, 0x30c, 0,
+#undef V68
+#define V68 (V + 204)
+ 0x64, 0x30c, 0,
+#undef V69
+#define V69 (V + 207)
+ 0x45, 0x304, 0,
+#undef V70
+#define V70 (V + 210)
+ 0x65, 0x304, 0,
+#undef V71
+#define V71 (V + 213)
+ 0x45, 0x306, 0,
+#undef V72
+#define V72 (V + 216)
+ 0x65, 0x306, 0,
+#undef V73
+#define V73 (V + 219)
+ 0x45, 0x307, 0,
+#undef V74
+#define V74 (V + 222)
+ 0x65, 0x307, 0,
+#undef V75
+#define V75 (V + 225)
+ 0x45, 0x328, 0,
+#undef V76
+#define V76 (V + 228)
+ 0x65, 0x328, 0,
+#undef V77
+#define V77 (V + 231)
+ 0x45, 0x30c, 0,
+#undef V78
+#define V78 (V + 234)
+ 0x65, 0x30c, 0,
+#undef V79
+#define V79 (V + 237)
+ 0x47, 0x302, 0,
+#undef V80
+#define V80 (V + 240)
+ 0x67, 0x302, 0,
+#undef V81
+#define V81 (V + 243)
+ 0x47, 0x306, 0,
+#undef V82
+#define V82 (V + 246)
+ 0x67, 0x306, 0,
+#undef V83
+#define V83 (V + 249)
+ 0x47, 0x307, 0,
+#undef V84
+#define V84 (V + 252)
+ 0x67, 0x307, 0,
+#undef V85
+#define V85 (V + 255)
+ 0x47, 0x327, 0,
+#undef V86
+#define V86 (V + 258)
+ 0x67, 0x327, 0,
+#undef V87
+#define V87 (V + 261)
+ 0x48, 0x302, 0,
+#undef V88
+#define V88 (V + 264)
+ 0x68, 0x302, 0,
+#undef V89
+#define V89 (V + 267)
+ 0x49, 0x303, 0,
+#undef V90
+#define V90 (V + 270)
+ 0x69, 0x303, 0,
+#undef V91
+#define V91 (V + 273)
+ 0x49, 0x304, 0,
+#undef V92
+#define V92 (V + 276)
+ 0x69, 0x304, 0,
+#undef V93
+#define V93 (V + 279)
+ 0x49, 0x306, 0,
+#undef V94
+#define V94 (V + 282)
+ 0x69, 0x306, 0,
+#undef V95
+#define V95 (V + 285)
+ 0x49, 0x328, 0,
+#undef V96
+#define V96 (V + 288)
+ 0x69, 0x328, 0,
+#undef V97
+#define V97 (V + 291)
+ 0x49, 0x307, 0,
+#undef V98
+#define V98 (V + 294)
+ 0x4a, 0x302, 0,
+#undef V99
+#define V99 (V + 297)
+ 0x6a, 0x302, 0,
+#undef V100
+#define V100 (V + 300)
+ 0x4b, 0x327, 0,
+#undef V101
+#define V101 (V + 303)
+ 0x6b, 0x327, 0,
+#undef V102
+#define V102 (V + 306)
+ 0x4c, 0x301, 0,
+#undef V103
+#define V103 (V + 309)
+ 0x6c, 0x301, 0,
+#undef V104
+#define V104 (V + 312)
+ 0x4c, 0x327, 0,
+#undef V105
+#define V105 (V + 315)
+ 0x6c, 0x327, 0,
+#undef V106
+#define V106 (V + 318)
+ 0x4c, 0x30c, 0,
+#undef V107
+#define V107 (V + 321)
+ 0x6c, 0x30c, 0,
+#undef V108
+#define V108 (V + 324)
+ 0x4e, 0x301, 0,
+#undef V109
+#define V109 (V + 327)
+ 0x6e, 0x301, 0,
+#undef V110
+#define V110 (V + 330)
+ 0x4e, 0x327, 0,
+#undef V111
+#define V111 (V + 333)
+ 0x6e, 0x327, 0,
+#undef V112
+#define V112 (V + 336)
+ 0x4e, 0x30c, 0,
+#undef V113
+#define V113 (V + 339)
+ 0x6e, 0x30c, 0,
+#undef V114
+#define V114 (V + 342)
+ 0x4f, 0x304, 0,
+#undef V115
+#define V115 (V + 345)
+ 0x6f, 0x304, 0,
+#undef V116
+#define V116 (V + 348)
+ 0x4f, 0x306, 0,
+#undef V117
+#define V117 (V + 351)
+ 0x6f, 0x306, 0,
+#undef V118
+#define V118 (V + 354)
+ 0x4f, 0x30b, 0,
+#undef V119
+#define V119 (V + 357)
+ 0x6f, 0x30b, 0,
+#undef V120
+#define V120 (V + 360)
+ 0x52, 0x301, 0,
+#undef V121
+#define V121 (V + 363)
+ 0x72, 0x301, 0,
+#undef V122
+#define V122 (V + 366)
+ 0x52, 0x327, 0,
+#undef V123
+#define V123 (V + 369)
+ 0x72, 0x327, 0,
+#undef V124
+#define V124 (V + 372)
+ 0x52, 0x30c, 0,
+#undef V125
+#define V125 (V + 375)
+ 0x72, 0x30c, 0,
+#undef V126
+#define V126 (V + 378)
+ 0x53, 0x301, 0,
+#undef V127
+#define V127 (V + 381)
+ 0x73, 0x301, 0,
+#undef V128
+#define V128 (V + 384)
+ 0x53, 0x302, 0,
+#undef V129
+#define V129 (V + 387)
+ 0x73, 0x302, 0,
+#undef V130
+#define V130 (V + 390)
+ 0x53, 0x327, 0,
+#undef V131
+#define V131 (V + 393)
+ 0x73, 0x327, 0,
+#undef V132
+#define V132 (V + 396)
+ 0x53, 0x30c, 0,
+#undef V133
+#define V133 (V + 399)
+ 0x73, 0x30c, 0,
+#undef V134
+#define V134 (V + 402)
+ 0x54, 0x327, 0,
+#undef V135
+#define V135 (V + 405)
+ 0x74, 0x327, 0,
+#undef V136
+#define V136 (V + 408)
+ 0x54, 0x30c, 0,
+#undef V137
+#define V137 (V + 411)
+ 0x74, 0x30c, 0,
+#undef V138
+#define V138 (V + 414)
+ 0x55, 0x303, 0,
+#undef V139
+#define V139 (V + 417)
+ 0x75, 0x303, 0,
+#undef V140
+#define V140 (V + 420)
+ 0x55, 0x304, 0,
+#undef V141
+#define V141 (V + 423)
+ 0x75, 0x304, 0,
+#undef V142
+#define V142 (V + 426)
+ 0x55, 0x306, 0,
+#undef V143
+#define V143 (V + 429)
+ 0x75, 0x306, 0,
+#undef V144
+#define V144 (V + 432)
+ 0x55, 0x30a, 0,
+#undef V145
+#define V145 (V + 435)
+ 0x75, 0x30a, 0,
+#undef V146
+#define V146 (V + 438)
+ 0x55, 0x30b, 0,
+#undef V147
+#define V147 (V + 441)
+ 0x75, 0x30b, 0,
+#undef V148
+#define V148 (V + 444)
+ 0x55, 0x328, 0,
+#undef V149
+#define V149 (V + 447)
+ 0x75, 0x328, 0,
+#undef V150
+#define V150 (V + 450)
+ 0x57, 0x302, 0,
+#undef V151
+#define V151 (V + 453)
+ 0x77, 0x302, 0,
+#undef V152
+#define V152 (V + 456)
+ 0x59, 0x302, 0,
+#undef V153
+#define V153 (V + 459)
+ 0x79, 0x302, 0,
+#undef V154
+#define V154 (V + 462)
+ 0x59, 0x308, 0,
+#undef V155
+#define V155 (V + 465)
+ 0x5a, 0x301, 0,
+#undef V156
+#define V156 (V + 468)
+ 0x7a, 0x301, 0,
+#undef V157
+#define V157 (V + 471)
+ 0x5a, 0x307, 0,
+#undef V158
+#define V158 (V + 474)
+ 0x7a, 0x307, 0,
+#undef V159
+#define V159 (V + 477)
+ 0x5a, 0x30c, 0,
+#undef V160
+#define V160 (V + 480)
+ 0x7a, 0x30c, 0,
+#undef V161
+#define V161 (V + 483)
+ 0x4f, 0x31b, 0,
+#undef V162
+#define V162 (V + 486)
+ 0x6f, 0x31b, 0,
+#undef V163
+#define V163 (V + 489)
+ 0x55, 0x31b, 0,
+#undef V164
+#define V164 (V + 492)
+ 0x75, 0x31b, 0,
+#undef V165
+#define V165 (V + 495)
+ 0x41, 0x30c, 0,
+#undef V166
+#define V166 (V + 498)
+ 0x61, 0x30c, 0,
+#undef V167
+#define V167 (V + 501)
+ 0x49, 0x30c, 0,
+#undef V168
+#define V168 (V + 504)
+ 0x69, 0x30c, 0,
+#undef V169
+#define V169 (V + 507)
+ 0x4f, 0x30c, 0,
+#undef V170
+#define V170 (V + 510)
+ 0x6f, 0x30c, 0,
+#undef V171
+#define V171 (V + 513)
+ 0x55, 0x30c, 0,
+#undef V172
+#define V172 (V + 516)
+ 0x75, 0x30c, 0,
+#undef V173
+#define V173 (V + 519)
+ 0x55, 0x308, 0x304, 0,
+#undef V174
+#define V174 (V + 523)
+ 0x75, 0x308, 0x304, 0,
+#undef V175
+#define V175 (V + 527)
+ 0x55, 0x308, 0x301, 0,
+#undef V176
+#define V176 (V + 531)
+ 0x75, 0x308, 0x301, 0,
+#undef V177
+#define V177 (V + 535)
+ 0x55, 0x308, 0x30c, 0,
+#undef V178
+#define V178 (V + 539)
+ 0x75, 0x308, 0x30c, 0,
+#undef V179
+#define V179 (V + 543)
+ 0x55, 0x308, 0x300, 0,
+#undef V180
+#define V180 (V + 547)
+ 0x75, 0x308, 0x300, 0,
+#undef V181
+#define V181 (V + 551)
+ 0x41, 0x308, 0x304, 0,
+#undef V182
+#define V182 (V + 555)
+ 0x61, 0x308, 0x304, 0,
+#undef V183
+#define V183 (V + 559)
+ 0x41, 0x307, 0x304, 0,
+#undef V184
+#define V184 (V + 563)
+ 0x61, 0x307, 0x304, 0,
+#undef V185
+#define V185 (V + 567)
+ 0xc6, 0x304, 0,
+#undef V186
+#define V186 (V + 570)
+ 0xe6, 0x304, 0,
+#undef V187
+#define V187 (V + 573)
+ 0x47, 0x30c, 0,
+#undef V188
+#define V188 (V + 576)
+ 0x67, 0x30c, 0,
+#undef V189
+#define V189 (V + 579)
+ 0x4b, 0x30c, 0,
+#undef V190
+#define V190 (V + 582)
+ 0x6b, 0x30c, 0,
+#undef V191
+#define V191 (V + 585)
+ 0x4f, 0x328, 0,
+#undef V192
+#define V192 (V + 588)
+ 0x6f, 0x328, 0,
+#undef V193
+#define V193 (V + 591)
+ 0x4f, 0x328, 0x304, 0,
+#undef V194
+#define V194 (V + 595)
+ 0x6f, 0x328, 0x304, 0,
+#undef V195
+#define V195 (V + 599)
+ 0x1b7, 0x30c, 0,
+#undef V196
+#define V196 (V + 602)
+ 0x292, 0x30c, 0,
+#undef V197
+#define V197 (V + 605)
+ 0x6a, 0x30c, 0,
+#undef V198
+#define V198 (V + 608)
+ 0x47, 0x301, 0,
+#undef V199
+#define V199 (V + 611)
+ 0x67, 0x301, 0,
+#undef V200
+#define V200 (V + 614)
+ 0x4e, 0x300, 0,
+#undef V201
+#define V201 (V + 617)
+ 0x6e, 0x300, 0,
+#undef V202
+#define V202 (V + 620)
+ 0x41, 0x30a, 0x301, 0,
+#undef V203
+#define V203 (V + 624)
+ 0x61, 0x30a, 0x301, 0,
+#undef V204
+#define V204 (V + 628)
+ 0xc6, 0x301, 0,
+#undef V205
+#define V205 (V + 631)
+ 0xe6, 0x301, 0,
+#undef V206
+#define V206 (V + 634)
+ 0xd8, 0x301, 0,
+#undef V207
+#define V207 (V + 637)
+ 0xf8, 0x301, 0,
+#undef V208
+#define V208 (V + 640)
+ 0x41, 0x30f, 0,
+#undef V209
+#define V209 (V + 643)
+ 0x61, 0x30f, 0,
+#undef V210
+#define V210 (V + 646)
+ 0x41, 0x311, 0,
+#undef V211
+#define V211 (V + 649)
+ 0x61, 0x311, 0,
+#undef V212
+#define V212 (V + 652)
+ 0x45, 0x30f, 0,
+#undef V213
+#define V213 (V + 655)
+ 0x65, 0x30f, 0,
+#undef V214
+#define V214 (V + 658)
+ 0x45, 0x311, 0,
+#undef V215
+#define V215 (V + 661)
+ 0x65, 0x311, 0,
+#undef V216
+#define V216 (V + 664)
+ 0x49, 0x30f, 0,
+#undef V217
+#define V217 (V + 667)
+ 0x69, 0x30f, 0,
+#undef V218
+#define V218 (V + 670)
+ 0x49, 0x311, 0,
+#undef V219
+#define V219 (V + 673)
+ 0x69, 0x311, 0,
+#undef V220
+#define V220 (V + 676)
+ 0x4f, 0x30f, 0,
+#undef V221
+#define V221 (V + 679)
+ 0x6f, 0x30f, 0,
+#undef V222
+#define V222 (V + 682)
+ 0x4f, 0x311, 0,
+#undef V223
+#define V223 (V + 685)
+ 0x6f, 0x311, 0,
+#undef V224
+#define V224 (V + 688)
+ 0x52, 0x30f, 0,
+#undef V225
+#define V225 (V + 691)
+ 0x72, 0x30f, 0,
+#undef V226
+#define V226 (V + 694)
+ 0x52, 0x311, 0,
+#undef V227
+#define V227 (V + 697)
+ 0x72, 0x311, 0,
+#undef V228
+#define V228 (V + 700)
+ 0x55, 0x30f, 0,
+#undef V229
+#define V229 (V + 703)
+ 0x75, 0x30f, 0,
+#undef V230
+#define V230 (V + 706)
+ 0x55, 0x311, 0,
+#undef V231
+#define V231 (V + 709)
+ 0x75, 0x311, 0,
+#undef V232
+#define V232 (V + 712)
+ 0x53, 0x326, 0,
+#undef V233
+#define V233 (V + 715)
+ 0x73, 0x326, 0,
+#undef V234
+#define V234 (V + 718)
+ 0x54, 0x326, 0,
+#undef V235
+#define V235 (V + 721)
+ 0x74, 0x326, 0,
+#undef V236
+#define V236 (V + 724)
+ 0x48, 0x30c, 0,
+#undef V237
+#define V237 (V + 727)
+ 0x68, 0x30c, 0,
+#undef V238
+#define V238 (V + 730)
+ 0x41, 0x307, 0,
+#undef V239
+#define V239 (V + 733)
+ 0x61, 0x307, 0,
+#undef V240
+#define V240 (V + 736)
+ 0x45, 0x327, 0,
+#undef V241
+#define V241 (V + 739)
+ 0x65, 0x327, 0,
+#undef V242
+#define V242 (V + 742)
+ 0x4f, 0x308, 0x304, 0,
+#undef V243
+#define V243 (V + 746)
+ 0x6f, 0x308, 0x304, 0,
+#undef V244
+#define V244 (V + 750)
+ 0x4f, 0x303, 0x304, 0,
+#undef V245
+#define V245 (V + 754)
+ 0x6f, 0x303, 0x304, 0,
+#undef V246
+#define V246 (V + 758)
+ 0x4f, 0x307, 0,
+#undef V247
+#define V247 (V + 761)
+ 0x6f, 0x307, 0,
+#undef V248
+#define V248 (V + 764)
+ 0x4f, 0x307, 0x304, 0,
+#undef V249
+#define V249 (V + 768)
+ 0x6f, 0x307, 0x304, 0,
+#undef V250
+#define V250 (V + 772)
+ 0x59, 0x304, 0,
+#undef V251
+#define V251 (V + 775)
+ 0x79, 0x304, 0,
+#undef V252
+#define V252 (V + 778)
+ 0x300, 0,
+#undef V253
+#define V253 (V + 780)
+ 0x301, 0,
+#undef V254
+#define V254 (V + 782)
+ 0x313, 0,
+#undef V255
+#define V255 (V + 784)
+ 0x308, 0x301, 0,
+#undef V256
+#define V256 (V + 787)
+ 0x2b9, 0,
+#undef V257
+#define V257 (V + 789)
+ 0x3b, 0,
+#undef V258
+#define V258 (V + 791)
+ 0xa8, 0x301, 0,
+#undef V259
+#define V259 (V + 794)
+ 0x391, 0x301, 0,
+#undef V260
+#define V260 (V + 797)
+ 0xb7, 0,
+#undef V261
+#define V261 (V + 799)
+ 0x395, 0x301, 0,
+#undef V262
+#define V262 (V + 802)
+ 0x397, 0x301, 0,
+#undef V263
+#define V263 (V + 805)
+ 0x399, 0x301, 0,
+#undef V264
+#define V264 (V + 808)
+ 0x39f, 0x301, 0,
+#undef V265
+#define V265 (V + 811)
+ 0x3a5, 0x301, 0,
+#undef V266
+#define V266 (V + 814)
+ 0x3a9, 0x301, 0,
+#undef V267
+#define V267 (V + 817)
+ 0x3b9, 0x308, 0x301, 0,
+#undef V268
+#define V268 (V + 821)
+ 0x399, 0x308, 0,
+#undef V269
+#define V269 (V + 824)
+ 0x3a5, 0x308, 0,
+#undef V270
+#define V270 (V + 827)
+ 0x3b1, 0x301, 0,
+#undef V271
+#define V271 (V + 830)
+ 0x3b5, 0x301, 0,
+#undef V272
+#define V272 (V + 833)
+ 0x3b7, 0x301, 0,
+#undef V273
+#define V273 (V + 836)
+ 0x3b9, 0x301, 0,
+#undef V274
+#define V274 (V + 839)
+ 0x3c5, 0x308, 0x301, 0,
+#undef V275
+#define V275 (V + 843)
+ 0x3b9, 0x308, 0,
+#undef V276
+#define V276 (V + 846)
+ 0x3c5, 0x308, 0,
+#undef V277
+#define V277 (V + 849)
+ 0x3bf, 0x301, 0,
+#undef V278
+#define V278 (V + 852)
+ 0x3c5, 0x301, 0,
+#undef V279
+#define V279 (V + 855)
+ 0x3c9, 0x301, 0,
+#undef V280
+#define V280 (V + 858)
+ 0x3d2, 0x301, 0,
+#undef V281
+#define V281 (V + 861)
+ 0x3d2, 0x308, 0,
+#undef V282
+#define V282 (V + 864)
+ 0x415, 0x300, 0,
+#undef V283
+#define V283 (V + 867)
+ 0x415, 0x308, 0,
+#undef V284
+#define V284 (V + 870)
+ 0x413, 0x301, 0,
+#undef V285
+#define V285 (V + 873)
+ 0x406, 0x308, 0,
+#undef V286
+#define V286 (V + 876)
+ 0x41a, 0x301, 0,
+#undef V287
+#define V287 (V + 879)
+ 0x418, 0x300, 0,
+#undef V288
+#define V288 (V + 882)
+ 0x423, 0x306, 0,
+#undef V289
+#define V289 (V + 885)
+ 0x418, 0x306, 0,
+#undef V290
+#define V290 (V + 888)
+ 0x438, 0x306, 0,
+#undef V291
+#define V291 (V + 891)
+ 0x435, 0x300, 0,
+#undef V292
+#define V292 (V + 894)
+ 0x435, 0x308, 0,
+#undef V293
+#define V293 (V + 897)
+ 0x433, 0x301, 0,
+#undef V294
+#define V294 (V + 900)
+ 0x456, 0x308, 0,
+#undef V295
+#define V295 (V + 903)
+ 0x43a, 0x301, 0,
+#undef V296
+#define V296 (V + 906)
+ 0x438, 0x300, 0,
+#undef V297
+#define V297 (V + 909)
+ 0x443, 0x306, 0,
+#undef V298
+#define V298 (V + 912)
+ 0x474, 0x30f, 0,
+#undef V299
+#define V299 (V + 915)
+ 0x475, 0x30f, 0,
+#undef V300
+#define V300 (V + 918)
+ 0x416, 0x306, 0,
+#undef V301
+#define V301 (V + 921)
+ 0x436, 0x306, 0,
+#undef V302
+#define V302 (V + 924)
+ 0x410, 0x306, 0,
+#undef V303
+#define V303 (V + 927)
+ 0x430, 0x306, 0,
+#undef V304
+#define V304 (V + 930)
+ 0x410, 0x308, 0,
+#undef V305
+#define V305 (V + 933)
+ 0x430, 0x308, 0,
+#undef V306
+#define V306 (V + 936)
+ 0x415, 0x306, 0,
+#undef V307
+#define V307 (V + 939)
+ 0x435, 0x306, 0,
+#undef V308
+#define V308 (V + 942)
+ 0x4d8, 0x308, 0,
+#undef V309
+#define V309 (V + 945)
+ 0x4d9, 0x308, 0,
+#undef V310
+#define V310 (V + 948)
+ 0x416, 0x308, 0,
+#undef V311
+#define V311 (V + 951)
+ 0x436, 0x308, 0,
+#undef V312
+#define V312 (V + 954)
+ 0x417, 0x308, 0,
+#undef V313
+#define V313 (V + 957)
+ 0x437, 0x308, 0,
+#undef V314
+#define V314 (V + 960)
+ 0x418, 0x304, 0,
+#undef V315
+#define V315 (V + 963)
+ 0x438, 0x304, 0,
+#undef V316
+#define V316 (V + 966)
+ 0x418, 0x308, 0,
+#undef V317
+#define V317 (V + 969)
+ 0x438, 0x308, 0,
+#undef V318
+#define V318 (V + 972)
+ 0x41e, 0x308, 0,
+#undef V319
+#define V319 (V + 975)
+ 0x43e, 0x308, 0,
+#undef V320
+#define V320 (V + 978)
+ 0x4e8, 0x308, 0,
+#undef V321
+#define V321 (V + 981)
+ 0x4e9, 0x308, 0,
+#undef V322
+#define V322 (V + 984)
+ 0x42d, 0x308, 0,
+#undef V323
+#define V323 (V + 987)
+ 0x44d, 0x308, 0,
+#undef V324
+#define V324 (V + 990)
+ 0x423, 0x304, 0,
+#undef V325
+#define V325 (V + 993)
+ 0x443, 0x304, 0,
+#undef V326
+#define V326 (V + 996)
+ 0x423, 0x308, 0,
+#undef V327
+#define V327 (V + 999)
+ 0x443, 0x308, 0,
+#undef V328
+#define V328 (V + 1002)
+ 0x423, 0x30b, 0,
+#undef V329
+#define V329 (V + 1005)
+ 0x443, 0x30b, 0,
+#undef V330
+#define V330 (V + 1008)
+ 0x427, 0x308, 0,
+#undef V331
+#define V331 (V + 1011)
+ 0x447, 0x308, 0,
+#undef V332
+#define V332 (V + 1014)
+ 0x42b, 0x308, 0,
+#undef V333
+#define V333 (V + 1017)
+ 0x44b, 0x308, 0,
+#undef V334
+#define V334 (V + 1020)
+ 0x627, 0x653, 0,
+#undef V335
+#define V335 (V + 1023)
+ 0x627, 0x654, 0,
+#undef V336
+#define V336 (V + 1026)
+ 0x648, 0x654, 0,
+#undef V337
+#define V337 (V + 1029)
+ 0x627, 0x655, 0,
+#undef V338
+#define V338 (V + 1032)
+ 0x64a, 0x654, 0,
+#undef V339
+#define V339 (V + 1035)
+ 0x6d5, 0x654, 0,
+#undef V340
+#define V340 (V + 1038)
+ 0x6c1, 0x654, 0,
+#undef V341
+#define V341 (V + 1041)
+ 0x6d2, 0x654, 0,
+#undef V342
+#define V342 (V + 1044)
+ 0x928, 0x93c, 0,
+#undef V343
+#define V343 (V + 1047)
+ 0x930, 0x93c, 0,
+#undef V344
+#define V344 (V + 1050)
+ 0x933, 0x93c, 0,
+#undef V345
+#define V345 (V + 1053)
+ 0x915, 0x93c, 0,
+#undef V346
+#define V346 (V + 1056)
+ 0x916, 0x93c, 0,
+#undef V347
+#define V347 (V + 1059)
+ 0x917, 0x93c, 0,
+#undef V348
+#define V348 (V + 1062)
+ 0x91c, 0x93c, 0,
+#undef V349
+#define V349 (V + 1065)
+ 0x921, 0x93c, 0,
+#undef V350
+#define V350 (V + 1068)
+ 0x922, 0x93c, 0,
+#undef V351
+#define V351 (V + 1071)
+ 0x92b, 0x93c, 0,
+#undef V352
+#define V352 (V + 1074)
+ 0x92f, 0x93c, 0,
+#undef V353
+#define V353 (V + 1077)
+ 0x9c7, 0x9be, 0,
+#undef V354
+#define V354 (V + 1080)
+ 0x9c7, 0x9d7, 0,
+#undef V355
+#define V355 (V + 1083)
+ 0x9a1, 0x9bc, 0,
+#undef V356
+#define V356 (V + 1086)
+ 0x9a2, 0x9bc, 0,
+#undef V357
+#define V357 (V + 1089)
+ 0x9af, 0x9bc, 0,
+#undef V358
+#define V358 (V + 1092)
+ 0xa32, 0xa3c, 0,
+#undef V359
+#define V359 (V + 1095)
+ 0xa38, 0xa3c, 0,
+#undef V360
+#define V360 (V + 1098)
+ 0xa16, 0xa3c, 0,
+#undef V361
+#define V361 (V + 1101)
+ 0xa17, 0xa3c, 0,
+#undef V362
+#define V362 (V + 1104)
+ 0xa1c, 0xa3c, 0,
+#undef V363
+#define V363 (V + 1107)
+ 0xa2b, 0xa3c, 0,
+#undef V364
+#define V364 (V + 1110)
+ 0xb47, 0xb56, 0,
+#undef V365
+#define V365 (V + 1113)
+ 0xb47, 0xb3e, 0,
+#undef V366
+#define V366 (V + 1116)
+ 0xb47, 0xb57, 0,
+#undef V367
+#define V367 (V + 1119)
+ 0xb21, 0xb3c, 0,
+#undef V368
+#define V368 (V + 1122)
+ 0xb22, 0xb3c, 0,
+#undef V369
+#define V369 (V + 1125)
+ 0xb92, 0xbd7, 0,
+#undef V370
+#define V370 (V + 1128)
+ 0xbc6, 0xbbe, 0,
+#undef V371
+#define V371 (V + 1131)
+ 0xbc7, 0xbbe, 0,
+#undef V372
+#define V372 (V + 1134)
+ 0xbc6, 0xbd7, 0,
+#undef V373
+#define V373 (V + 1137)
+ 0xc46, 0xc56, 0,
+#undef V374
+#define V374 (V + 1140)
+ 0xcbf, 0xcd5, 0,
+#undef V375
+#define V375 (V + 1143)
+ 0xcc6, 0xcd5, 0,
+#undef V376
+#define V376 (V + 1146)
+ 0xcc6, 0xcd6, 0,
+#undef V377
+#define V377 (V + 1149)
+ 0xcc6, 0xcc2, 0,
+#undef V378
+#define V378 (V + 1152)
+ 0xcc6, 0xcc2, 0xcd5, 0,
+#undef V379
+#define V379 (V + 1156)
+ 0xd46, 0xd3e, 0,
+#undef V380
+#define V380 (V + 1159)
+ 0xd47, 0xd3e, 0,
+#undef V381
+#define V381 (V + 1162)
+ 0xd46, 0xd57, 0,
+#undef V382
+#define V382 (V + 1165)
+ 0xdd9, 0xdca, 0,
+#undef V383
+#define V383 (V + 1168)
+ 0xdd9, 0xdcf, 0,
+#undef V384
+#define V384 (V + 1171)
+ 0xdd9, 0xdcf, 0xdca, 0,
+#undef V385
+#define V385 (V + 1175)
+ 0xdd9, 0xddf, 0,
+#undef V386
+#define V386 (V + 1178)
+ 0xf42, 0xfb7, 0,
+#undef V387
+#define V387 (V + 1181)
+ 0xf4c, 0xfb7, 0,
+#undef V388
+#define V388 (V + 1184)
+ 0xf51, 0xfb7, 0,
+#undef V389
+#define V389 (V + 1187)
+ 0xf56, 0xfb7, 0,
+#undef V390
+#define V390 (V + 1190)
+ 0xf5b, 0xfb7, 0,
+#undef V391
+#define V391 (V + 1193)
+ 0xf40, 0xfb5, 0,
+#undef V392
+#define V392 (V + 1196)
+ 0xf71, 0xf72, 0,
+#undef V393
+#define V393 (V + 1199)
+ 0xf71, 0xf74, 0,
+#undef V394
+#define V394 (V + 1202)
+ 0xfb2, 0xf80, 0,
+#undef V395
+#define V395 (V + 1205)
+ 0xfb3, 0xf80, 0,
+#undef V396
+#define V396 (V + 1208)
+ 0xf71, 0xf80, 0,
+#undef V397
+#define V397 (V + 1211)
+ 0xf92, 0xfb7, 0,
+#undef V398
+#define V398 (V + 1214)
+ 0xf9c, 0xfb7, 0,
+#undef V399
+#define V399 (V + 1217)
+ 0xfa1, 0xfb7, 0,
+#undef V400
+#define V400 (V + 1220)
+ 0xfa6, 0xfb7, 0,
+#undef V401
+#define V401 (V + 1223)
+ 0xfab, 0xfb7, 0,
+#undef V402
+#define V402 (V + 1226)
+ 0xf90, 0xfb5, 0,
+#undef V403
+#define V403 (V + 1229)
+ 0x1025, 0x102e, 0,
+#undef V404
+#define V404 (V + 1232)
+ 0x1b05, 0x1b35, 0,
+#undef V405
+#define V405 (V + 1235)
+ 0x1b07, 0x1b35, 0,
+#undef V406
+#define V406 (V + 1238)
+ 0x1b09, 0x1b35, 0,
+#undef V407
+#define V407 (V + 1241)
+ 0x1b0b, 0x1b35, 0,
+#undef V408
+#define V408 (V + 1244)
+ 0x1b0d, 0x1b35, 0,
+#undef V409
+#define V409 (V + 1247)
+ 0x1b11, 0x1b35, 0,
+#undef V410
+#define V410 (V + 1250)
+ 0x1b3a, 0x1b35, 0,
+#undef V411
+#define V411 (V + 1253)
+ 0x1b3c, 0x1b35, 0,
+#undef V412
+#define V412 (V + 1256)
+ 0x1b3e, 0x1b35, 0,
+#undef V413
+#define V413 (V + 1259)
+ 0x1b3f, 0x1b35, 0,
+#undef V414
+#define V414 (V + 1262)
+ 0x1b42, 0x1b35, 0,
+#undef V415
+#define V415 (V + 1265)
+ 0x41, 0x325, 0,
+#undef V416
+#define V416 (V + 1268)
+ 0x61, 0x325, 0,
+#undef V417
+#define V417 (V + 1271)
+ 0x42, 0x307, 0,
+#undef V418
+#define V418 (V + 1274)
+ 0x62, 0x307, 0,
+#undef V419
+#define V419 (V + 1277)
+ 0x42, 0x323, 0,
+#undef V420
+#define V420 (V + 1280)
+ 0x62, 0x323, 0,
+#undef V421
+#define V421 (V + 1283)
+ 0x42, 0x331, 0,
+#undef V422
+#define V422 (V + 1286)
+ 0x62, 0x331, 0,
+#undef V423
+#define V423 (V + 1289)
+ 0x43, 0x327, 0x301, 0,
+#undef V424
+#define V424 (V + 1293)
+ 0x63, 0x327, 0x301, 0,
+#undef V425
+#define V425 (V + 1297)
+ 0x44, 0x307, 0,
+#undef V426
+#define V426 (V + 1300)
+ 0x64, 0x307, 0,
+#undef V427
+#define V427 (V + 1303)
+ 0x44, 0x323, 0,
+#undef V428
+#define V428 (V + 1306)
+ 0x64, 0x323, 0,
+#undef V429
+#define V429 (V + 1309)
+ 0x44, 0x331, 0,
+#undef V430
+#define V430 (V + 1312)
+ 0x64, 0x331, 0,
+#undef V431
+#define V431 (V + 1315)
+ 0x44, 0x327, 0,
+#undef V432
+#define V432 (V + 1318)
+ 0x64, 0x327, 0,
+#undef V433
+#define V433 (V + 1321)
+ 0x44, 0x32d, 0,
+#undef V434
+#define V434 (V + 1324)
+ 0x64, 0x32d, 0,
+#undef V435
+#define V435 (V + 1327)
+ 0x45, 0x304, 0x300, 0,
+#undef V436
+#define V436 (V + 1331)
+ 0x65, 0x304, 0x300, 0,
+#undef V437
+#define V437 (V + 1335)
+ 0x45, 0x304, 0x301, 0,
+#undef V438
+#define V438 (V + 1339)
+ 0x65, 0x304, 0x301, 0,
+#undef V439
+#define V439 (V + 1343)
+ 0x45, 0x32d, 0,
+#undef V440
+#define V440 (V + 1346)
+ 0x65, 0x32d, 0,
+#undef V441
+#define V441 (V + 1349)
+ 0x45, 0x330, 0,
+#undef V442
+#define V442 (V + 1352)
+ 0x65, 0x330, 0,
+#undef V443
+#define V443 (V + 1355)
+ 0x45, 0x327, 0x306, 0,
+#undef V444
+#define V444 (V + 1359)
+ 0x65, 0x327, 0x306, 0,
+#undef V445
+#define V445 (V + 1363)
+ 0x46, 0x307, 0,
+#undef V446
+#define V446 (V + 1366)
+ 0x66, 0x307, 0,
+#undef V447
+#define V447 (V + 1369)
+ 0x47, 0x304, 0,
+#undef V448
+#define V448 (V + 1372)
+ 0x67, 0x304, 0,
+#undef V449
+#define V449 (V + 1375)
+ 0x48, 0x307, 0,
+#undef V450
+#define V450 (V + 1378)
+ 0x68, 0x307, 0,
+#undef V451
+#define V451 (V + 1381)
+ 0x48, 0x323, 0,
+#undef V452
+#define V452 (V + 1384)
+ 0x68, 0x323, 0,
+#undef V453
+#define V453 (V + 1387)
+ 0x48, 0x308, 0,
+#undef V454
+#define V454 (V + 1390)
+ 0x68, 0x308, 0,
+#undef V455
+#define V455 (V + 1393)
+ 0x48, 0x327, 0,
+#undef V456
+#define V456 (V + 1396)
+ 0x68, 0x327, 0,
+#undef V457
+#define V457 (V + 1399)
+ 0x48, 0x32e, 0,
+#undef V458
+#define V458 (V + 1402)
+ 0x68, 0x32e, 0,
+#undef V459
+#define V459 (V + 1405)
+ 0x49, 0x330, 0,
+#undef V460
+#define V460 (V + 1408)
+ 0x69, 0x330, 0,
+#undef V461
+#define V461 (V + 1411)
+ 0x49, 0x308, 0x301, 0,
+#undef V462
+#define V462 (V + 1415)
+ 0x69, 0x308, 0x301, 0,
+#undef V463
+#define V463 (V + 1419)
+ 0x4b, 0x301, 0,
+#undef V464
+#define V464 (V + 1422)
+ 0x6b, 0x301, 0,
+#undef V465
+#define V465 (V + 1425)
+ 0x4b, 0x323, 0,
+#undef V466
+#define V466 (V + 1428)
+ 0x6b, 0x323, 0,
+#undef V467
+#define V467 (V + 1431)
+ 0x4b, 0x331, 0,
+#undef V468
+#define V468 (V + 1434)
+ 0x6b, 0x331, 0,
+#undef V469
+#define V469 (V + 1437)
+ 0x4c, 0x323, 0,
+#undef V470
+#define V470 (V + 1440)
+ 0x6c, 0x323, 0,
+#undef V471
+#define V471 (V + 1443)
+ 0x4c, 0x323, 0x304, 0,
+#undef V472
+#define V472 (V + 1447)
+ 0x6c, 0x323, 0x304, 0,
+#undef V473
+#define V473 (V + 1451)
+ 0x4c, 0x331, 0,
+#undef V474
+#define V474 (V + 1454)
+ 0x6c, 0x331, 0,
+#undef V475
+#define V475 (V + 1457)
+ 0x4c, 0x32d, 0,
+#undef V476
+#define V476 (V + 1460)
+ 0x6c, 0x32d, 0,
+#undef V477
+#define V477 (V + 1463)
+ 0x4d, 0x301, 0,
+#undef V478
+#define V478 (V + 1466)
+ 0x6d, 0x301, 0,
+#undef V479
+#define V479 (V + 1469)
+ 0x4d, 0x307, 0,
+#undef V480
+#define V480 (V + 1472)
+ 0x6d, 0x307, 0,
+#undef V481
+#define V481 (V + 1475)
+ 0x4d, 0x323, 0,
+#undef V482
+#define V482 (V + 1478)
+ 0x6d, 0x323, 0,
+#undef V483
+#define V483 (V + 1481)
+ 0x4e, 0x307, 0,
+#undef V484
+#define V484 (V + 1484)
+ 0x6e, 0x307, 0,
+#undef V485
+#define V485 (V + 1487)
+ 0x4e, 0x323, 0,
+#undef V486
+#define V486 (V + 1490)
+ 0x6e, 0x323, 0,
+#undef V487
+#define V487 (V + 1493)
+ 0x4e, 0x331, 0,
+#undef V488
+#define V488 (V + 1496)
+ 0x6e, 0x331, 0,
+#undef V489
+#define V489 (V + 1499)
+ 0x4e, 0x32d, 0,
+#undef V490
+#define V490 (V + 1502)
+ 0x6e, 0x32d, 0,
+#undef V491
+#define V491 (V + 1505)
+ 0x4f, 0x303, 0x301, 0,
+#undef V492
+#define V492 (V + 1509)
+ 0x6f, 0x303, 0x301, 0,
+#undef V493
+#define V493 (V + 1513)
+ 0x4f, 0x303, 0x308, 0,
+#undef V494
+#define V494 (V + 1517)
+ 0x6f, 0x303, 0x308, 0,
+#undef V495
+#define V495 (V + 1521)
+ 0x4f, 0x304, 0x300, 0,
+#undef V496
+#define V496 (V + 1525)
+ 0x6f, 0x304, 0x300, 0,
+#undef V497
+#define V497 (V + 1529)
+ 0x4f, 0x304, 0x301, 0,
+#undef V498
+#define V498 (V + 1533)
+ 0x6f, 0x304, 0x301, 0,
+#undef V499
+#define V499 (V + 1537)
+ 0x50, 0x301, 0,
+#undef V500
+#define V500 (V + 1540)
+ 0x70, 0x301, 0,
+#undef V501
+#define V501 (V + 1543)
+ 0x50, 0x307, 0,
+#undef V502
+#define V502 (V + 1546)
+ 0x70, 0x307, 0,
+#undef V503
+#define V503 (V + 1549)
+ 0x52, 0x307, 0,
+#undef V504
+#define V504 (V + 1552)
+ 0x72, 0x307, 0,
+#undef V505
+#define V505 (V + 1555)
+ 0x52, 0x323, 0,
+#undef V506
+#define V506 (V + 1558)
+ 0x72, 0x323, 0,
+#undef V507
+#define V507 (V + 1561)
+ 0x52, 0x323, 0x304, 0,
+#undef V508
+#define V508 (V + 1565)
+ 0x72, 0x323, 0x304, 0,
+#undef V509
+#define V509 (V + 1569)
+ 0x52, 0x331, 0,
+#undef V510
+#define V510 (V + 1572)
+ 0x72, 0x331, 0,
+#undef V511
+#define V511 (V + 1575)
+ 0x53, 0x307, 0,
+#undef V512
+#define V512 (V + 1578)
+ 0x73, 0x307, 0,
+#undef V513
+#define V513 (V + 1581)
+ 0x53, 0x323, 0,
+#undef V514
+#define V514 (V + 1584)
+ 0x73, 0x323, 0,
+#undef V515
+#define V515 (V + 1587)
+ 0x53, 0x301, 0x307, 0,
+#undef V516
+#define V516 (V + 1591)
+ 0x73, 0x301, 0x307, 0,
+#undef V517
+#define V517 (V + 1595)
+ 0x53, 0x30c, 0x307, 0,
+#undef V518
+#define V518 (V + 1599)
+ 0x73, 0x30c, 0x307, 0,
+#undef V519
+#define V519 (V + 1603)
+ 0x53, 0x323, 0x307, 0,
+#undef V520
+#define V520 (V + 1607)
+ 0x73, 0x323, 0x307, 0,
+#undef V521
+#define V521 (V + 1611)
+ 0x54, 0x307, 0,
+#undef V522
+#define V522 (V + 1614)
+ 0x74, 0x307, 0,
+#undef V523
+#define V523 (V + 1617)
+ 0x54, 0x323, 0,
+#undef V524
+#define V524 (V + 1620)
+ 0x74, 0x323, 0,
+#undef V525
+#define V525 (V + 1623)
+ 0x54, 0x331, 0,
+#undef V526
+#define V526 (V + 1626)
+ 0x74, 0x331, 0,
+#undef V527
+#define V527 (V + 1629)
+ 0x54, 0x32d, 0,
+#undef V528
+#define V528 (V + 1632)
+ 0x74, 0x32d, 0,
+#undef V529
+#define V529 (V + 1635)
+ 0x55, 0x324, 0,
+#undef V530
+#define V530 (V + 1638)
+ 0x75, 0x324, 0,
+#undef V531
+#define V531 (V + 1641)
+ 0x55, 0x330, 0,
+#undef V532
+#define V532 (V + 1644)
+ 0x75, 0x330, 0,
+#undef V533
+#define V533 (V + 1647)
+ 0x55, 0x32d, 0,
+#undef V534
+#define V534 (V + 1650)
+ 0x75, 0x32d, 0,
+#undef V535
+#define V535 (V + 1653)
+ 0x55, 0x303, 0x301, 0,
+#undef V536
+#define V536 (V + 1657)
+ 0x75, 0x303, 0x301, 0,
+#undef V537
+#define V537 (V + 1661)
+ 0x55, 0x304, 0x308, 0,
+#undef V538
+#define V538 (V + 1665)
+ 0x75, 0x304, 0x308, 0,
+#undef V539
+#define V539 (V + 1669)
+ 0x56, 0x303, 0,
+#undef V540
+#define V540 (V + 1672)
+ 0x76, 0x303, 0,
+#undef V541
+#define V541 (V + 1675)
+ 0x56, 0x323, 0,
+#undef V542
+#define V542 (V + 1678)
+ 0x76, 0x323, 0,
+#undef V543
+#define V543 (V + 1681)
+ 0x57, 0x300, 0,
+#undef V544
+#define V544 (V + 1684)
+ 0x77, 0x300, 0,
+#undef V545
+#define V545 (V + 1687)
+ 0x57, 0x301, 0,
+#undef V546
+#define V546 (V + 1690)
+ 0x77, 0x301, 0,
+#undef V547
+#define V547 (V + 1693)
+ 0x57, 0x308, 0,
+#undef V548
+#define V548 (V + 1696)
+ 0x77, 0x308, 0,
+#undef V549
+#define V549 (V + 1699)
+ 0x57, 0x307, 0,
+#undef V550
+#define V550 (V + 1702)
+ 0x77, 0x307, 0,
+#undef V551
+#define V551 (V + 1705)
+ 0x57, 0x323, 0,
+#undef V552
+#define V552 (V + 1708)
+ 0x77, 0x323, 0,
+#undef V553
+#define V553 (V + 1711)
+ 0x58, 0x307, 0,
+#undef V554
+#define V554 (V + 1714)
+ 0x78, 0x307, 0,
+#undef V555
+#define V555 (V + 1717)
+ 0x58, 0x308, 0,
+#undef V556
+#define V556 (V + 1720)
+ 0x78, 0x308, 0,
+#undef V557
+#define V557 (V + 1723)
+ 0x59, 0x307, 0,
+#undef V558
+#define V558 (V + 1726)
+ 0x79, 0x307, 0,
+#undef V559
+#define V559 (V + 1729)
+ 0x5a, 0x302, 0,
+#undef V560
+#define V560 (V + 1732)
+ 0x7a, 0x302, 0,
+#undef V561
+#define V561 (V + 1735)
+ 0x5a, 0x323, 0,
+#undef V562
+#define V562 (V + 1738)
+ 0x7a, 0x323, 0,
+#undef V563
+#define V563 (V + 1741)
+ 0x5a, 0x331, 0,
+#undef V564
+#define V564 (V + 1744)
+ 0x7a, 0x331, 0,
+#undef V565
+#define V565 (V + 1747)
+ 0x68, 0x331, 0,
+#undef V566
+#define V566 (V + 1750)
+ 0x74, 0x308, 0,
+#undef V567
+#define V567 (V + 1753)
+ 0x77, 0x30a, 0,
+#undef V568
+#define V568 (V + 1756)
+ 0x79, 0x30a, 0,
+#undef V569
+#define V569 (V + 1759)
+ 0x17f, 0x307, 0,
+#undef V570
+#define V570 (V + 1762)
+ 0x41, 0x323, 0,
+#undef V571
+#define V571 (V + 1765)
+ 0x61, 0x323, 0,
+#undef V572
+#define V572 (V + 1768)
+ 0x41, 0x309, 0,
+#undef V573
+#define V573 (V + 1771)
+ 0x61, 0x309, 0,
+#undef V574
+#define V574 (V + 1774)
+ 0x41, 0x302, 0x301, 0,
+#undef V575
+#define V575 (V + 1778)
+ 0x61, 0x302, 0x301, 0,
+#undef V576
+#define V576 (V + 1782)
+ 0x41, 0x302, 0x300, 0,
+#undef V577
+#define V577 (V + 1786)
+ 0x61, 0x302, 0x300, 0,
+#undef V578
+#define V578 (V + 1790)
+ 0x41, 0x302, 0x309, 0,
+#undef V579
+#define V579 (V + 1794)
+ 0x61, 0x302, 0x309, 0,
+#undef V580
+#define V580 (V + 1798)
+ 0x41, 0x302, 0x303, 0,
+#undef V581
+#define V581 (V + 1802)
+ 0x61, 0x302, 0x303, 0,
+#undef V582
+#define V582 (V + 1806)
+ 0x41, 0x323, 0x302, 0,
+#undef V583
+#define V583 (V + 1810)
+ 0x61, 0x323, 0x302, 0,
+#undef V584
+#define V584 (V + 1814)
+ 0x41, 0x306, 0x301, 0,
+#undef V585
+#define V585 (V + 1818)
+ 0x61, 0x306, 0x301, 0,
+#undef V586
+#define V586 (V + 1822)
+ 0x41, 0x306, 0x300, 0,
+#undef V587
+#define V587 (V + 1826)
+ 0x61, 0x306, 0x300, 0,
+#undef V588
+#define V588 (V + 1830)
+ 0x41, 0x306, 0x309, 0,
+#undef V589
+#define V589 (V + 1834)
+ 0x61, 0x306, 0x309, 0,
+#undef V590
+#define V590 (V + 1838)
+ 0x41, 0x306, 0x303, 0,
+#undef V591
+#define V591 (V + 1842)
+ 0x61, 0x306, 0x303, 0,
+#undef V592
+#define V592 (V + 1846)
+ 0x41, 0x323, 0x306, 0,
+#undef V593
+#define V593 (V + 1850)
+ 0x61, 0x323, 0x306, 0,
+#undef V594
+#define V594 (V + 1854)
+ 0x45, 0x323, 0,
+#undef V595
+#define V595 (V + 1857)
+ 0x65, 0x323, 0,
+#undef V596
+#define V596 (V + 1860)
+ 0x45, 0x309, 0,
+#undef V597
+#define V597 (V + 1863)
+ 0x65, 0x309, 0,
+#undef V598
+#define V598 (V + 1866)
+ 0x45, 0x303, 0,
+#undef V599
+#define V599 (V + 1869)
+ 0x65, 0x303, 0,
+#undef V600
+#define V600 (V + 1872)
+ 0x45, 0x302, 0x301, 0,
+#undef V601
+#define V601 (V + 1876)
+ 0x65, 0x302, 0x301, 0,
+#undef V602
+#define V602 (V + 1880)
+ 0x45, 0x302, 0x300, 0,
+#undef V603
+#define V603 (V + 1884)
+ 0x65, 0x302, 0x300, 0,
+#undef V604
+#define V604 (V + 1888)
+ 0x45, 0x302, 0x309, 0,
+#undef V605
+#define V605 (V + 1892)
+ 0x65, 0x302, 0x309, 0,
+#undef V606
+#define V606 (V + 1896)
+ 0x45, 0x302, 0x303, 0,
+#undef V607
+#define V607 (V + 1900)
+ 0x65, 0x302, 0x303, 0,
+#undef V608
+#define V608 (V + 1904)
+ 0x45, 0x323, 0x302, 0,
+#undef V609
+#define V609 (V + 1908)
+ 0x65, 0x323, 0x302, 0,
+#undef V610
+#define V610 (V + 1912)
+ 0x49, 0x309, 0,
+#undef V611
+#define V611 (V + 1915)
+ 0x69, 0x309, 0,
+#undef V612
+#define V612 (V + 1918)
+ 0x49, 0x323, 0,
+#undef V613
+#define V613 (V + 1921)
+ 0x69, 0x323, 0,
+#undef V614
+#define V614 (V + 1924)
+ 0x4f, 0x323, 0,
+#undef V615
+#define V615 (V + 1927)
+ 0x6f, 0x323, 0,
+#undef V616
+#define V616 (V + 1930)
+ 0x4f, 0x309, 0,
+#undef V617
+#define V617 (V + 1933)
+ 0x6f, 0x309, 0,
+#undef V618
+#define V618 (V + 1936)
+ 0x4f, 0x302, 0x301, 0,
+#undef V619
+#define V619 (V + 1940)
+ 0x6f, 0x302, 0x301, 0,
+#undef V620
+#define V620 (V + 1944)
+ 0x4f, 0x302, 0x300, 0,
+#undef V621
+#define V621 (V + 1948)
+ 0x6f, 0x302, 0x300, 0,
+#undef V622
+#define V622 (V + 1952)
+ 0x4f, 0x302, 0x309, 0,
+#undef V623
+#define V623 (V + 1956)
+ 0x6f, 0x302, 0x309, 0,
+#undef V624
+#define V624 (V + 1960)
+ 0x4f, 0x302, 0x303, 0,
+#undef V625
+#define V625 (V + 1964)
+ 0x6f, 0x302, 0x303, 0,
+#undef V626
+#define V626 (V + 1968)
+ 0x4f, 0x323, 0x302, 0,
+#undef V627
+#define V627 (V + 1972)
+ 0x6f, 0x323, 0x302, 0,
+#undef V628
+#define V628 (V + 1976)
+ 0x4f, 0x31b, 0x301, 0,
+#undef V629
+#define V629 (V + 1980)
+ 0x6f, 0x31b, 0x301, 0,
+#undef V630
+#define V630 (V + 1984)
+ 0x4f, 0x31b, 0x300, 0,
+#undef V631
+#define V631 (V + 1988)
+ 0x6f, 0x31b, 0x300, 0,
+#undef V632
+#define V632 (V + 1992)
+ 0x4f, 0x31b, 0x309, 0,
+#undef V633
+#define V633 (V + 1996)
+ 0x6f, 0x31b, 0x309, 0,
+#undef V634
+#define V634 (V + 2000)
+ 0x4f, 0x31b, 0x303, 0,
+#undef V635
+#define V635 (V + 2004)
+ 0x6f, 0x31b, 0x303, 0,
+#undef V636
+#define V636 (V + 2008)
+ 0x4f, 0x31b, 0x323, 0,
+#undef V637
+#define V637 (V + 2012)
+ 0x6f, 0x31b, 0x323, 0,
+#undef V638
+#define V638 (V + 2016)
+ 0x55, 0x323, 0,
+#undef V639
+#define V639 (V + 2019)
+ 0x75, 0x323, 0,
+#undef V640
+#define V640 (V + 2022)
+ 0x55, 0x309, 0,
+#undef V641
+#define V641 (V + 2025)
+ 0x75, 0x309, 0,
+#undef V642
+#define V642 (V + 2028)
+ 0x55, 0x31b, 0x301, 0,
+#undef V643
+#define V643 (V + 2032)
+ 0x75, 0x31b, 0x301, 0,
+#undef V644
+#define V644 (V + 2036)
+ 0x55, 0x31b, 0x300, 0,
+#undef V645
+#define V645 (V + 2040)
+ 0x75, 0x31b, 0x300, 0,
+#undef V646
+#define V646 (V + 2044)
+ 0x55, 0x31b, 0x309, 0,
+#undef V647
+#define V647 (V + 2048)
+ 0x75, 0x31b, 0x309, 0,
+#undef V648
+#define V648 (V + 2052)
+ 0x55, 0x31b, 0x303, 0,
+#undef V649
+#define V649 (V + 2056)
+ 0x75, 0x31b, 0x303, 0,
+#undef V650
+#define V650 (V + 2060)
+ 0x55, 0x31b, 0x323, 0,
+#undef V651
+#define V651 (V + 2064)
+ 0x75, 0x31b, 0x323, 0,
+#undef V652
+#define V652 (V + 2068)
+ 0x59, 0x300, 0,
+#undef V653
+#define V653 (V + 2071)
+ 0x79, 0x300, 0,
+#undef V654
+#define V654 (V + 2074)
+ 0x59, 0x323, 0,
+#undef V655
+#define V655 (V + 2077)
+ 0x79, 0x323, 0,
+#undef V656
+#define V656 (V + 2080)
+ 0x59, 0x309, 0,
+#undef V657
+#define V657 (V + 2083)
+ 0x79, 0x309, 0,
+#undef V658
+#define V658 (V + 2086)
+ 0x59, 0x303, 0,
+#undef V659
+#define V659 (V + 2089)
+ 0x79, 0x303, 0,
+#undef V660
+#define V660 (V + 2092)
+ 0x3b1, 0x313, 0,
+#undef V661
+#define V661 (V + 2095)
+ 0x3b1, 0x314, 0,
+#undef V662
+#define V662 (V + 2098)
+ 0x3b1, 0x313, 0x300, 0,
+#undef V663
+#define V663 (V + 2102)
+ 0x3b1, 0x314, 0x300, 0,
+#undef V664
+#define V664 (V + 2106)
+ 0x3b1, 0x313, 0x301, 0,
+#undef V665
+#define V665 (V + 2110)
+ 0x3b1, 0x314, 0x301, 0,
+#undef V666
+#define V666 (V + 2114)
+ 0x3b1, 0x313, 0x342, 0,
+#undef V667
+#define V667 (V + 2118)
+ 0x3b1, 0x314, 0x342, 0,
+#undef V668
+#define V668 (V + 2122)
+ 0x391, 0x313, 0,
+#undef V669
+#define V669 (V + 2125)
+ 0x391, 0x314, 0,
+#undef V670
+#define V670 (V + 2128)
+ 0x391, 0x313, 0x300, 0,
+#undef V671
+#define V671 (V + 2132)
+ 0x391, 0x314, 0x300, 0,
+#undef V672
+#define V672 (V + 2136)
+ 0x391, 0x313, 0x301, 0,
+#undef V673
+#define V673 (V + 2140)
+ 0x391, 0x314, 0x301, 0,
+#undef V674
+#define V674 (V + 2144)
+ 0x391, 0x313, 0x342, 0,
+#undef V675
+#define V675 (V + 2148)
+ 0x391, 0x314, 0x342, 0,
+#undef V676
+#define V676 (V + 2152)
+ 0x3b5, 0x313, 0,
+#undef V677
+#define V677 (V + 2155)
+ 0x3b5, 0x314, 0,
+#undef V678
+#define V678 (V + 2158)
+ 0x3b5, 0x313, 0x300, 0,
+#undef V679
+#define V679 (V + 2162)
+ 0x3b5, 0x314, 0x300, 0,
+#undef V680
+#define V680 (V + 2166)
+ 0x3b5, 0x313, 0x301, 0,
+#undef V681
+#define V681 (V + 2170)
+ 0x3b5, 0x314, 0x301, 0,
+#undef V682
+#define V682 (V + 2174)
+ 0x395, 0x313, 0,
+#undef V683
+#define V683 (V + 2177)
+ 0x395, 0x314, 0,
+#undef V684
+#define V684 (V + 2180)
+ 0x395, 0x313, 0x300, 0,
+#undef V685
+#define V685 (V + 2184)
+ 0x395, 0x314, 0x300, 0,
+#undef V686
+#define V686 (V + 2188)
+ 0x395, 0x313, 0x301, 0,
+#undef V687
+#define V687 (V + 2192)
+ 0x395, 0x314, 0x301, 0,
+#undef V688
+#define V688 (V + 2196)
+ 0x3b7, 0x313, 0,
+#undef V689
+#define V689 (V + 2199)
+ 0x3b7, 0x314, 0,
+#undef V690
+#define V690 (V + 2202)
+ 0x3b7, 0x313, 0x300, 0,
+#undef V691
+#define V691 (V + 2206)
+ 0x3b7, 0x314, 0x300, 0,
+#undef V692
+#define V692 (V + 2210)
+ 0x3b7, 0x313, 0x301, 0,
+#undef V693
+#define V693 (V + 2214)
+ 0x3b7, 0x314, 0x301, 0,
+#undef V694
+#define V694 (V + 2218)
+ 0x3b7, 0x313, 0x342, 0,
+#undef V695
+#define V695 (V + 2222)
+ 0x3b7, 0x314, 0x342, 0,
+#undef V696
+#define V696 (V + 2226)
+ 0x397, 0x313, 0,
+#undef V697
+#define V697 (V + 2229)
+ 0x397, 0x314, 0,
+#undef V698
+#define V698 (V + 2232)
+ 0x397, 0x313, 0x300, 0,
+#undef V699
+#define V699 (V + 2236)
+ 0x397, 0x314, 0x300, 0,
+#undef V700
+#define V700 (V + 2240)
+ 0x397, 0x313, 0x301, 0,
+#undef V701
+#define V701 (V + 2244)
+ 0x397, 0x314, 0x301, 0,
+#undef V702
+#define V702 (V + 2248)
+ 0x397, 0x313, 0x342, 0,
+#undef V703
+#define V703 (V + 2252)
+ 0x397, 0x314, 0x342, 0,
+#undef V704
+#define V704 (V + 2256)
+ 0x3b9, 0x313, 0,
+#undef V705
+#define V705 (V + 2259)
+ 0x3b9, 0x314, 0,
+#undef V706
+#define V706 (V + 2262)
+ 0x3b9, 0x313, 0x300, 0,
+#undef V707
+#define V707 (V + 2266)
+ 0x3b9, 0x314, 0x300, 0,
+#undef V708
+#define V708 (V + 2270)
+ 0x3b9, 0x313, 0x301, 0,
+#undef V709
+#define V709 (V + 2274)
+ 0x3b9, 0x314, 0x301, 0,
+#undef V710
+#define V710 (V + 2278)
+ 0x3b9, 0x313, 0x342, 0,
+#undef V711
+#define V711 (V + 2282)
+ 0x3b9, 0x314, 0x342, 0,
+#undef V712
+#define V712 (V + 2286)
+ 0x399, 0x313, 0,
+#undef V713
+#define V713 (V + 2289)
+ 0x399, 0x314, 0,
+#undef V714
+#define V714 (V + 2292)
+ 0x399, 0x313, 0x300, 0,
+#undef V715
+#define V715 (V + 2296)
+ 0x399, 0x314, 0x300, 0,
+#undef V716
+#define V716 (V + 2300)
+ 0x399, 0x313, 0x301, 0,
+#undef V717
+#define V717 (V + 2304)
+ 0x399, 0x314, 0x301, 0,
+#undef V718
+#define V718 (V + 2308)
+ 0x399, 0x313, 0x342, 0,
+#undef V719
+#define V719 (V + 2312)
+ 0x399, 0x314, 0x342, 0,
+#undef V720
+#define V720 (V + 2316)
+ 0x3bf, 0x313, 0,
+#undef V721
+#define V721 (V + 2319)
+ 0x3bf, 0x314, 0,
+#undef V722
+#define V722 (V + 2322)
+ 0x3bf, 0x313, 0x300, 0,
+#undef V723
+#define V723 (V + 2326)
+ 0x3bf, 0x314, 0x300, 0,
+#undef V724
+#define V724 (V + 2330)
+ 0x3bf, 0x313, 0x301, 0,
+#undef V725
+#define V725 (V + 2334)
+ 0x3bf, 0x314, 0x301, 0,
+#undef V726
+#define V726 (V + 2338)
+ 0x39f, 0x313, 0,
+#undef V727
+#define V727 (V + 2341)
+ 0x39f, 0x314, 0,
+#undef V728
+#define V728 (V + 2344)
+ 0x39f, 0x313, 0x300, 0,
+#undef V729
+#define V729 (V + 2348)
+ 0x39f, 0x314, 0x300, 0,
+#undef V730
+#define V730 (V + 2352)
+ 0x39f, 0x313, 0x301, 0,
+#undef V731
+#define V731 (V + 2356)
+ 0x39f, 0x314, 0x301, 0,
+#undef V732
+#define V732 (V + 2360)
+ 0x3c5, 0x313, 0,
+#undef V733
+#define V733 (V + 2363)
+ 0x3c5, 0x314, 0,
+#undef V734
+#define V734 (V + 2366)
+ 0x3c5, 0x313, 0x300, 0,
+#undef V735
+#define V735 (V + 2370)
+ 0x3c5, 0x314, 0x300, 0,
+#undef V736
+#define V736 (V + 2374)
+ 0x3c5, 0x313, 0x301, 0,
+#undef V737
+#define V737 (V + 2378)
+ 0x3c5, 0x314, 0x301, 0,
+#undef V738
+#define V738 (V + 2382)
+ 0x3c5, 0x313, 0x342, 0,
+#undef V739
+#define V739 (V + 2386)
+ 0x3c5, 0x314, 0x342, 0,
+#undef V740
+#define V740 (V + 2390)
+ 0x3a5, 0x314, 0,
+#undef V741
+#define V741 (V + 2393)
+ 0x3a5, 0x314, 0x300, 0,
+#undef V742
+#define V742 (V + 2397)
+ 0x3a5, 0x314, 0x301, 0,
+#undef V743
+#define V743 (V + 2401)
+ 0x3a5, 0x314, 0x342, 0,
+#undef V744
+#define V744 (V + 2405)
+ 0x3c9, 0x313, 0,
+#undef V745
+#define V745 (V + 2408)
+ 0x3c9, 0x314, 0,
+#undef V746
+#define V746 (V + 2411)
+ 0x3c9, 0x313, 0x300, 0,
+#undef V747
+#define V747 (V + 2415)
+ 0x3c9, 0x314, 0x300, 0,
+#undef V748
+#define V748 (V + 2419)
+ 0x3c9, 0x313, 0x301, 0,
+#undef V749
+#define V749 (V + 2423)
+ 0x3c9, 0x314, 0x301, 0,
+#undef V750
+#define V750 (V + 2427)
+ 0x3c9, 0x313, 0x342, 0,
+#undef V751
+#define V751 (V + 2431)
+ 0x3c9, 0x314, 0x342, 0,
+#undef V752
+#define V752 (V + 2435)
+ 0x3a9, 0x313, 0,
+#undef V753
+#define V753 (V + 2438)
+ 0x3a9, 0x314, 0,
+#undef V754
+#define V754 (V + 2441)
+ 0x3a9, 0x313, 0x300, 0,
+#undef V755
+#define V755 (V + 2445)
+ 0x3a9, 0x314, 0x300, 0,
+#undef V756
+#define V756 (V + 2449)
+ 0x3a9, 0x313, 0x301, 0,
+#undef V757
+#define V757 (V + 2453)
+ 0x3a9, 0x314, 0x301, 0,
+#undef V758
+#define V758 (V + 2457)
+ 0x3a9, 0x313, 0x342, 0,
+#undef V759
+#define V759 (V + 2461)
+ 0x3a9, 0x314, 0x342, 0,
+#undef V760
+#define V760 (V + 2465)
+ 0x3b1, 0x300, 0,
+#undef V761
+#define V761 (V + 2468)
+ 0x3b5, 0x300, 0,
+#undef V762
+#define V762 (V + 2471)
+ 0x3b7, 0x300, 0,
+#undef V763
+#define V763 (V + 2474)
+ 0x3b9, 0x300, 0,
+#undef V764
+#define V764 (V + 2477)
+ 0x3bf, 0x300, 0,
+#undef V765
+#define V765 (V + 2480)
+ 0x3c5, 0x300, 0,
+#undef V766
+#define V766 (V + 2483)
+ 0x3c9, 0x300, 0,
+#undef V767
+#define V767 (V + 2486)
+ 0x3b1, 0x313, 0x345, 0,
+#undef V768
+#define V768 (V + 2490)
+ 0x3b1, 0x314, 0x345, 0,
+#undef V769
+#define V769 (V + 2494)
+ 0x3b1, 0x313, 0x300, 0x345, 0,
+#undef V770
+#define V770 (V + 2499)
+ 0x3b1, 0x314, 0x300, 0x345, 0,
+#undef V771
+#define V771 (V + 2504)
+ 0x3b1, 0x313, 0x301, 0x345, 0,
+#undef V772
+#define V772 (V + 2509)
+ 0x3b1, 0x314, 0x301, 0x345, 0,
+#undef V773
+#define V773 (V + 2514)
+ 0x3b1, 0x313, 0x342, 0x345, 0,
+#undef V774
+#define V774 (V + 2519)
+ 0x3b1, 0x314, 0x342, 0x345, 0,
+#undef V775
+#define V775 (V + 2524)
+ 0x391, 0x313, 0x345, 0,
+#undef V776
+#define V776 (V + 2528)
+ 0x391, 0x314, 0x345, 0,
+#undef V777
+#define V777 (V + 2532)
+ 0x391, 0x313, 0x300, 0x345, 0,
+#undef V778
+#define V778 (V + 2537)
+ 0x391, 0x314, 0x300, 0x345, 0,
+#undef V779
+#define V779 (V + 2542)
+ 0x391, 0x313, 0x301, 0x345, 0,
+#undef V780
+#define V780 (V + 2547)
+ 0x391, 0x314, 0x301, 0x345, 0,
+#undef V781
+#define V781 (V + 2552)
+ 0x391, 0x313, 0x342, 0x345, 0,
+#undef V782
+#define V782 (V + 2557)
+ 0x391, 0x314, 0x342, 0x345, 0,
+#undef V783
+#define V783 (V + 2562)
+ 0x3b7, 0x313, 0x345, 0,
+#undef V784
+#define V784 (V + 2566)
+ 0x3b7, 0x314, 0x345, 0,
+#undef V785
+#define V785 (V + 2570)
+ 0x3b7, 0x313, 0x300, 0x345, 0,
+#undef V786
+#define V786 (V + 2575)
+ 0x3b7, 0x314, 0x300, 0x345, 0,
+#undef V787
+#define V787 (V + 2580)
+ 0x3b7, 0x313, 0x301, 0x345, 0,
+#undef V788
+#define V788 (V + 2585)
+ 0x3b7, 0x314, 0x301, 0x345, 0,
+#undef V789
+#define V789 (V + 2590)
+ 0x3b7, 0x313, 0x342, 0x345, 0,
+#undef V790
+#define V790 (V + 2595)
+ 0x3b7, 0x314, 0x342, 0x345, 0,
+#undef V791
+#define V791 (V + 2600)
+ 0x397, 0x313, 0x345, 0,
+#undef V792
+#define V792 (V + 2604)
+ 0x397, 0x314, 0x345, 0,
+#undef V793
+#define V793 (V + 2608)
+ 0x397, 0x313, 0x300, 0x345, 0,
+#undef V794
+#define V794 (V + 2613)
+ 0x397, 0x314, 0x300, 0x345, 0,
+#undef V795
+#define V795 (V + 2618)
+ 0x397, 0x313, 0x301, 0x345, 0,
+#undef V796
+#define V796 (V + 2623)
+ 0x397, 0x314, 0x301, 0x345, 0,
+#undef V797
+#define V797 (V + 2628)
+ 0x397, 0x313, 0x342, 0x345, 0,
+#undef V798
+#define V798 (V + 2633)
+ 0x397, 0x314, 0x342, 0x345, 0,
+#undef V799
+#define V799 (V + 2638)
+ 0x3c9, 0x313, 0x345, 0,
+#undef V800
+#define V800 (V + 2642)
+ 0x3c9, 0x314, 0x345, 0,
+#undef V801
+#define V801 (V + 2646)
+ 0x3c9, 0x313, 0x300, 0x345, 0,
+#undef V802
+#define V802 (V + 2651)
+ 0x3c9, 0x314, 0x300, 0x345, 0,
+#undef V803
+#define V803 (V + 2656)
+ 0x3c9, 0x313, 0x301, 0x345, 0,
+#undef V804
+#define V804 (V + 2661)
+ 0x3c9, 0x314, 0x301, 0x345, 0,
+#undef V805
+#define V805 (V + 2666)
+ 0x3c9, 0x313, 0x342, 0x345, 0,
+#undef V806
+#define V806 (V + 2671)
+ 0x3c9, 0x314, 0x342, 0x345, 0,
+#undef V807
+#define V807 (V + 2676)
+ 0x3a9, 0x313, 0x345, 0,
+#undef V808
+#define V808 (V + 2680)
+ 0x3a9, 0x314, 0x345, 0,
+#undef V809
+#define V809 (V + 2684)
+ 0x3a9, 0x313, 0x300, 0x345, 0,
+#undef V810
+#define V810 (V + 2689)
+ 0x3a9, 0x314, 0x300, 0x345, 0,
+#undef V811
+#define V811 (V + 2694)
+ 0x3a9, 0x313, 0x301, 0x345, 0,
+#undef V812
+#define V812 (V + 2699)
+ 0x3a9, 0x314, 0x301, 0x345, 0,
+#undef V813
+#define V813 (V + 2704)
+ 0x3a9, 0x313, 0x342, 0x345, 0,
+#undef V814
+#define V814 (V + 2709)
+ 0x3a9, 0x314, 0x342, 0x345, 0,
+#undef V815
+#define V815 (V + 2714)
+ 0x3b1, 0x306, 0,
+#undef V816
+#define V816 (V + 2717)
+ 0x3b1, 0x304, 0,
+#undef V817
+#define V817 (V + 2720)
+ 0x3b1, 0x300, 0x345, 0,
+#undef V818
+#define V818 (V + 2724)
+ 0x3b1, 0x345, 0,
+#undef V819
+#define V819 (V + 2727)
+ 0x3b1, 0x301, 0x345, 0,
+#undef V820
+#define V820 (V + 2731)
+ 0x3b1, 0x342, 0,
+#undef V821
+#define V821 (V + 2734)
+ 0x3b1, 0x342, 0x345, 0,
+#undef V822
+#define V822 (V + 2738)
+ 0x391, 0x306, 0,
+#undef V823
+#define V823 (V + 2741)
+ 0x391, 0x304, 0,
+#undef V824
+#define V824 (V + 2744)
+ 0x391, 0x300, 0,
+#undef V825
+#define V825 (V + 2747)
+ 0x391, 0x345, 0,
+#undef V826
+#define V826 (V + 2750)
+ 0x3b9, 0,
+#undef V827
+#define V827 (V + 2752)
+ 0xa8, 0x342, 0,
+#undef V828
+#define V828 (V + 2755)
+ 0x3b7, 0x300, 0x345, 0,
+#undef V829
+#define V829 (V + 2759)
+ 0x3b7, 0x345, 0,
+#undef V830
+#define V830 (V + 2762)
+ 0x3b7, 0x301, 0x345, 0,
+#undef V831
+#define V831 (V + 2766)
+ 0x3b7, 0x342, 0,
+#undef V832
+#define V832 (V + 2769)
+ 0x3b7, 0x342, 0x345, 0,
+#undef V833
+#define V833 (V + 2773)
+ 0x395, 0x300, 0,
+#undef V834
+#define V834 (V + 2776)
+ 0x397, 0x300, 0,
+#undef V835
+#define V835 (V + 2779)
+ 0x397, 0x345, 0,
+#undef V836
+#define V836 (V + 2782)
+ 0x1fbf, 0x300, 0,
+#undef V837
+#define V837 (V + 2785)
+ 0x1fbf, 0x301, 0,
+#undef V838
+#define V838 (V + 2788)
+ 0x1fbf, 0x342, 0,
+#undef V839
+#define V839 (V + 2791)
+ 0x3b9, 0x306, 0,
+#undef V840
+#define V840 (V + 2794)
+ 0x3b9, 0x304, 0,
+#undef V841
+#define V841 (V + 2797)
+ 0x3b9, 0x308, 0x300, 0,
+#undef V842
+#define V842 (V + 2801)
+ 0x3b9, 0x342, 0,
+#undef V843
+#define V843 (V + 2804)
+ 0x3b9, 0x308, 0x342, 0,
+#undef V844
+#define V844 (V + 2808)
+ 0x399, 0x306, 0,
+#undef V845
+#define V845 (V + 2811)
+ 0x399, 0x304, 0,
+#undef V846
+#define V846 (V + 2814)
+ 0x399, 0x300, 0,
+#undef V847
+#define V847 (V + 2817)
+ 0x1ffe, 0x300, 0,
+#undef V848
+#define V848 (V + 2820)
+ 0x1ffe, 0x301, 0,
+#undef V849
+#define V849 (V + 2823)
+ 0x1ffe, 0x342, 0,
+#undef V850
+#define V850 (V + 2826)
+ 0x3c5, 0x306, 0,
+#undef V851
+#define V851 (V + 2829)
+ 0x3c5, 0x304, 0,
+#undef V852
+#define V852 (V + 2832)
+ 0x3c5, 0x308, 0x300, 0,
+#undef V853
+#define V853 (V + 2836)
+ 0x3c1, 0x313, 0,
+#undef V854
+#define V854 (V + 2839)
+ 0x3c1, 0x314, 0,
+#undef V855
+#define V855 (V + 2842)
+ 0x3c5, 0x342, 0,
+#undef V856
+#define V856 (V + 2845)
+ 0x3c5, 0x308, 0x342, 0,
+#undef V857
+#define V857 (V + 2849)
+ 0x3a5, 0x306, 0,
+#undef V858
+#define V858 (V + 2852)
+ 0x3a5, 0x304, 0,
+#undef V859
+#define V859 (V + 2855)
+ 0x3a5, 0x300, 0,
+#undef V860
+#define V860 (V + 2858)
+ 0x3a1, 0x314, 0,
+#undef V861
+#define V861 (V + 2861)
+ 0xa8, 0x300, 0,
+#undef V862
+#define V862 (V + 2864)
+ 0x60, 0,
+#undef V863
+#define V863 (V + 2866)
+ 0x3c9, 0x300, 0x345, 0,
+#undef V864
+#define V864 (V + 2870)
+ 0x3c9, 0x345, 0,
+#undef V865
+#define V865 (V + 2873)
+ 0x3c9, 0x301, 0x345, 0,
+#undef V866
+#define V866 (V + 2877)
+ 0x3c9, 0x342, 0,
+#undef V867
+#define V867 (V + 2880)
+ 0x3c9, 0x342, 0x345, 0,
+#undef V868
+#define V868 (V + 2884)
+ 0x39f, 0x300, 0,
+#undef V869
+#define V869 (V + 2887)
+ 0x3a9, 0x300, 0,
+#undef V870
+#define V870 (V + 2890)
+ 0x3a9, 0x345, 0,
+#undef V871
+#define V871 (V + 2893)
+ 0xb4, 0,
+#undef V872
+#define V872 (V + 2895)
+ 0x2002, 0,
+#undef V873
+#define V873 (V + 2897)
+ 0x2003, 0,
+#undef V874
+#define V874 (V + 2899)
+ 0x3a9, 0,
+#undef V875
+#define V875 (V + 2901)
+ 0x4b, 0,
+#undef V876
+#define V876 (V + 2903)
+ 0x2190, 0x338, 0,
+#undef V877
+#define V877 (V + 2906)
+ 0x2192, 0x338, 0,
+#undef V878
+#define V878 (V + 2909)
+ 0x2194, 0x338, 0,
+#undef V879
+#define V879 (V + 2912)
+ 0x21d0, 0x338, 0,
+#undef V880
+#define V880 (V + 2915)
+ 0x21d4, 0x338, 0,
+#undef V881
+#define V881 (V + 2918)
+ 0x21d2, 0x338, 0,
+#undef V882
+#define V882 (V + 2921)
+ 0x2203, 0x338, 0,
+#undef V883
+#define V883 (V + 2924)
+ 0x2208, 0x338, 0,
+#undef V884
+#define V884 (V + 2927)
+ 0x220b, 0x338, 0,
+#undef V885
+#define V885 (V + 2930)
+ 0x2223, 0x338, 0,
+#undef V886
+#define V886 (V + 2933)
+ 0x2225, 0x338, 0,
+#undef V887
+#define V887 (V + 2936)
+ 0x223c, 0x338, 0,
+#undef V888
+#define V888 (V + 2939)
+ 0x2243, 0x338, 0,
+#undef V889
+#define V889 (V + 2942)
+ 0x2245, 0x338, 0,
+#undef V890
+#define V890 (V + 2945)
+ 0x2248, 0x338, 0,
+#undef V891
+#define V891 (V + 2948)
+ 0x3d, 0x338, 0,
+#undef V892
+#define V892 (V + 2951)
+ 0x2261, 0x338, 0,
+#undef V893
+#define V893 (V + 2954)
+ 0x224d, 0x338, 0,
+#undef V894
+#define V894 (V + 2957)
+ 0x3c, 0x338, 0,
+#undef V895
+#define V895 (V + 2960)
+ 0x3e, 0x338, 0,
+#undef V896
+#define V896 (V + 2963)
+ 0x2264, 0x338, 0,
+#undef V897
+#define V897 (V + 2966)
+ 0x2265, 0x338, 0,
+#undef V898
+#define V898 (V + 2969)
+ 0x2272, 0x338, 0,
+#undef V899
+#define V899 (V + 2972)
+ 0x2273, 0x338, 0,
+#undef V900
+#define V900 (V + 2975)
+ 0x2276, 0x338, 0,
+#undef V901
+#define V901 (V + 2978)
+ 0x2277, 0x338, 0,
+#undef V902
+#define V902 (V + 2981)
+ 0x227a, 0x338, 0,
+#undef V903
+#define V903 (V + 2984)
+ 0x227b, 0x338, 0,
+#undef V904
+#define V904 (V + 2987)
+ 0x2282, 0x338, 0,
+#undef V905
+#define V905 (V + 2990)
+ 0x2283, 0x338, 0,
+#undef V906
+#define V906 (V + 2993)
+ 0x2286, 0x338, 0,
+#undef V907
+#define V907 (V + 2996)
+ 0x2287, 0x338, 0,
+#undef V908
+#define V908 (V + 2999)
+ 0x22a2, 0x338, 0,
+#undef V909
+#define V909 (V + 3002)
+ 0x22a8, 0x338, 0,
+#undef V910
+#define V910 (V + 3005)
+ 0x22a9, 0x338, 0,
+#undef V911
+#define V911 (V + 3008)
+ 0x22ab, 0x338, 0,
+#undef V912
+#define V912 (V + 3011)
+ 0x227c, 0x338, 0,
+#undef V913
+#define V913 (V + 3014)
+ 0x227d, 0x338, 0,
+#undef V914
+#define V914 (V + 3017)
+ 0x2291, 0x338, 0,
+#undef V915
+#define V915 (V + 3020)
+ 0x2292, 0x338, 0,
+#undef V916
+#define V916 (V + 3023)
+ 0x22b2, 0x338, 0,
+#undef V917
+#define V917 (V + 3026)
+ 0x22b3, 0x338, 0,
+#undef V918
+#define V918 (V + 3029)
+ 0x22b4, 0x338, 0,
+#undef V919
+#define V919 (V + 3032)
+ 0x22b5, 0x338, 0,
+#undef V920
+#define V920 (V + 3035)
+ 0x3008, 0,
+#undef V921
+#define V921 (V + 3037)
+ 0x3009, 0,
+#undef V922
+#define V922 (V + 3039)
+ 0x2add, 0x338, 0,
+#undef V923
+#define V923 (V + 3042)
+ 0x304b, 0x3099, 0,
+#undef V924
+#define V924 (V + 3045)
+ 0x304d, 0x3099, 0,
+#undef V925
+#define V925 (V + 3048)
+ 0x304f, 0x3099, 0,
+#undef V926
+#define V926 (V + 3051)
+ 0x3051, 0x3099, 0,
+#undef V927
+#define V927 (V + 3054)
+ 0x3053, 0x3099, 0,
+#undef V928
+#define V928 (V + 3057)
+ 0x3055, 0x3099, 0,
+#undef V929
+#define V929 (V + 3060)
+ 0x3057, 0x3099, 0,
+#undef V930
+#define V930 (V + 3063)
+ 0x3059, 0x3099, 0,
+#undef V931
+#define V931 (V + 3066)
+ 0x305b, 0x3099, 0,
+#undef V932
+#define V932 (V + 3069)
+ 0x305d, 0x3099, 0,
+#undef V933
+#define V933 (V + 3072)
+ 0x305f, 0x3099, 0,
+#undef V934
+#define V934 (V + 3075)
+ 0x3061, 0x3099, 0,
+#undef V935
+#define V935 (V + 3078)
+ 0x3064, 0x3099, 0,
+#undef V936
+#define V936 (V + 3081)
+ 0x3066, 0x3099, 0,
+#undef V937
+#define V937 (V + 3084)
+ 0x3068, 0x3099, 0,
+#undef V938
+#define V938 (V + 3087)
+ 0x306f, 0x3099, 0,
+#undef V939
+#define V939 (V + 3090)
+ 0x306f, 0x309a, 0,
+#undef V940
+#define V940 (V + 3093)
+ 0x3072, 0x3099, 0,
+#undef V941
+#define V941 (V + 3096)
+ 0x3072, 0x309a, 0,
+#undef V942
+#define V942 (V + 3099)
+ 0x3075, 0x3099, 0,
+#undef V943
+#define V943 (V + 3102)
+ 0x3075, 0x309a, 0,
+#undef V944
+#define V944 (V + 3105)
+ 0x3078, 0x3099, 0,
+#undef V945
+#define V945 (V + 3108)
+ 0x3078, 0x309a, 0,
+#undef V946
+#define V946 (V + 3111)
+ 0x307b, 0x3099, 0,
+#undef V947
+#define V947 (V + 3114)
+ 0x307b, 0x309a, 0,
+#undef V948
+#define V948 (V + 3117)
+ 0x3046, 0x3099, 0,
+#undef V949
+#define V949 (V + 3120)
+ 0x309d, 0x3099, 0,
+#undef V950
+#define V950 (V + 3123)
+ 0x30ab, 0x3099, 0,
+#undef V951
+#define V951 (V + 3126)
+ 0x30ad, 0x3099, 0,
+#undef V952
+#define V952 (V + 3129)
+ 0x30af, 0x3099, 0,
+#undef V953
+#define V953 (V + 3132)
+ 0x30b1, 0x3099, 0,
+#undef V954
+#define V954 (V + 3135)
+ 0x30b3, 0x3099, 0,
+#undef V955
+#define V955 (V + 3138)
+ 0x30b5, 0x3099, 0,
+#undef V956
+#define V956 (V + 3141)
+ 0x30b7, 0x3099, 0,
+#undef V957
+#define V957 (V + 3144)
+ 0x30b9, 0x3099, 0,
+#undef V958
+#define V958 (V + 3147)
+ 0x30bb, 0x3099, 0,
+#undef V959
+#define V959 (V + 3150)
+ 0x30bd, 0x3099, 0,
+#undef V960
+#define V960 (V + 3153)
+ 0x30bf, 0x3099, 0,
+#undef V961
+#define V961 (V + 3156)
+ 0x30c1, 0x3099, 0,
+#undef V962
+#define V962 (V + 3159)
+ 0x30c4, 0x3099, 0,
+#undef V963
+#define V963 (V + 3162)
+ 0x30c6, 0x3099, 0,
+#undef V964
+#define V964 (V + 3165)
+ 0x30c8, 0x3099, 0,
+#undef V965
+#define V965 (V + 3168)
+ 0x30cf, 0x3099, 0,
+#undef V966
+#define V966 (V + 3171)
+ 0x30cf, 0x309a, 0,
+#undef V967
+#define V967 (V + 3174)
+ 0x30d2, 0x3099, 0,
+#undef V968
+#define V968 (V + 3177)
+ 0x30d2, 0x309a, 0,
+#undef V969
+#define V969 (V + 3180)
+ 0x30d5, 0x3099, 0,
+#undef V970
+#define V970 (V + 3183)
+ 0x30d5, 0x309a, 0,
+#undef V971
+#define V971 (V + 3186)
+ 0x30d8, 0x3099, 0,
+#undef V972
+#define V972 (V + 3189)
+ 0x30d8, 0x309a, 0,
+#undef V973
+#define V973 (V + 3192)
+ 0x30db, 0x3099, 0,
+#undef V974
+#define V974 (V + 3195)
+ 0x30db, 0x309a, 0,
+#undef V975
+#define V975 (V + 3198)
+ 0x30a6, 0x3099, 0,
+#undef V976
+#define V976 (V + 3201)
+ 0x30ef, 0x3099, 0,
+#undef V977
+#define V977 (V + 3204)
+ 0x30f0, 0x3099, 0,
+#undef V978
+#define V978 (V + 3207)
+ 0x30f1, 0x3099, 0,
+#undef V979
+#define V979 (V + 3210)
+ 0x30f2, 0x3099, 0,
+#undef V980
+#define V980 (V + 3213)
+ 0x30fd, 0x3099, 0,
+#undef V981
+#define V981 (V + 3216)
+ 0x1100, 0x1161, 0,
+#undef V982
+#define V982 (V + 3219)
+ 0x1100, 0x1161, 0x11a8, 0,
+#undef V983
+#define V983 (V + 3223)
+ 0x1100, 0x1161, 0x11a9, 0,
+#undef V984
+#define V984 (V + 3227)
+ 0x1100, 0x1161, 0x11aa, 0,
+#undef V985
+#define V985 (V + 3231)
+ 0x1100, 0x1161, 0x11ab, 0,
+#undef V986
+#define V986 (V + 3235)
+ 0x1100, 0x1161, 0x11ac, 0,
+#undef V987
+#define V987 (V + 3239)
+ 0x1100, 0x1161, 0x11ad, 0,
+#undef V988
+#define V988 (V + 3243)
+ 0x1100, 0x1161, 0x11ae, 0,
+#undef V989
+#define V989 (V + 3247)
+ 0x1100, 0x1161, 0x11af, 0,
+#undef V990
+#define V990 (V + 3251)
+ 0x1100, 0x1161, 0x11b0, 0,
+#undef V991
+#define V991 (V + 3255)
+ 0x1100, 0x1161, 0x11b1, 0,
+#undef V992
+#define V992 (V + 3259)
+ 0x1100, 0x1161, 0x11b2, 0,
+#undef V993
+#define V993 (V + 3263)
+ 0x1100, 0x1161, 0x11b3, 0,
+#undef V994
+#define V994 (V + 3267)
+ 0x1100, 0x1161, 0x11b4, 0,
+#undef V995
+#define V995 (V + 3271)
+ 0x1100, 0x1161, 0x11b5, 0,
+#undef V996
+#define V996 (V + 3275)
+ 0x1100, 0x1161, 0x11b6, 0,
+#undef V997
+#define V997 (V + 3279)
+ 0x1100, 0x1161, 0x11b7, 0,
+#undef V998
+#define V998 (V + 3283)
+ 0x1100, 0x1161, 0x11b8, 0,
+#undef V999
+#define V999 (V + 3287)
+ 0x1100, 0x1161, 0x11b9, 0,
+#undef V1000
+#define V1000 (V + 3291)
+ 0x1100, 0x1161, 0x11ba, 0,
+#undef V1001
+#define V1001 (V + 3295)
+ 0x1100, 0x1161, 0x11bb, 0,
+#undef V1002
+#define V1002 (V + 3299)
+ 0x1100, 0x1161, 0x11bc, 0,
+#undef V1003
+#define V1003 (V + 3303)
+ 0x1100, 0x1161, 0x11bd, 0,
+#undef V1004
+#define V1004 (V + 3307)
+ 0x1100, 0x1161, 0x11be, 0,
+#undef V1005
+#define V1005 (V + 3311)
+ 0x1100, 0x1161, 0x11bf, 0,
+#undef V1006
+#define V1006 (V + 3315)
+ 0x1100, 0x1161, 0x11c0, 0,
+#undef V1007
+#define V1007 (V + 3319)
+ 0x1100, 0x1161, 0x11c1, 0,
+#undef V1008
+#define V1008 (V + 3323)
+ 0x1100, 0x1161, 0x11c2, 0,
+#undef V1009
+#define V1009 (V + 3327)
+ 0x1100, 0x1162, 0,
+#undef V1010
+#define V1010 (V + 3330)
+ 0x1100, 0x1162, 0x11a8, 0,
+#undef V1011
+#define V1011 (V + 3334)
+ 0x1100, 0x1162, 0x11a9, 0,
+#undef V1012
+#define V1012 (V + 3338)
+ 0x1100, 0x1162, 0x11aa, 0,
+#undef V1013
+#define V1013 (V + 3342)
+ 0x1100, 0x1162, 0x11ab, 0,
+#undef V1014
+#define V1014 (V + 3346)
+ 0x1100, 0x1162, 0x11ac, 0,
+#undef V1015
+#define V1015 (V + 3350)
+ 0x1100, 0x1162, 0x11ad, 0,
+#undef V1016
+#define V1016 (V + 3354)
+ 0x1100, 0x1162, 0x11ae, 0,
+#undef V1017
+#define V1017 (V + 3358)
+ 0x1100, 0x1162, 0x11af, 0,
+#undef V1018
+#define V1018 (V + 3362)
+ 0x1100, 0x1162, 0x11b0, 0,
+#undef V1019
+#define V1019 (V + 3366)
+ 0x1100, 0x1162, 0x11b1, 0,
+#undef V1020
+#define V1020 (V + 3370)
+ 0x1100, 0x1162, 0x11b2, 0,
+#undef V1021
+#define V1021 (V + 3374)
+ 0x1100, 0x1162, 0x11b3, 0,
+#undef V1022
+#define V1022 (V + 3378)
+ 0x1100, 0x1162, 0x11b4, 0,
+#undef V1023
+#define V1023 (V + 3382)
+ 0x1100, 0x1162, 0x11b5, 0,
+#undef V1024
+#define V1024 (V + 3386)
+ 0x1100, 0x1162, 0x11b6, 0,
+#undef V1025
+#define V1025 (V + 3390)
+ 0x1100, 0x1162, 0x11b7, 0,
+#undef V1026
+#define V1026 (V + 3394)
+ 0x1100, 0x1162, 0x11b8, 0,
+#undef V1027
+#define V1027 (V + 3398)
+ 0x1100, 0x1162, 0x11b9, 0,
+#undef V1028
+#define V1028 (V + 3402)
+ 0x1100, 0x1162, 0x11ba, 0,
+#undef V1029
+#define V1029 (V + 3406)
+ 0x1100, 0x1162, 0x11bb, 0,
+#undef V1030
+#define V1030 (V + 3410)
+ 0x1100, 0x1162, 0x11bc, 0,
+#undef V1031
+#define V1031 (V + 3414)
+ 0x1100, 0x1162, 0x11bd, 0,
+#undef V1032
+#define V1032 (V + 3418)
+ 0x1100, 0x1162, 0x11be, 0,
+#undef V1033
+#define V1033 (V + 3422)
+ 0x1100, 0x1162, 0x11bf, 0,
+#undef V1034
+#define V1034 (V + 3426)
+ 0x1100, 0x1162, 0x11c0, 0,
+#undef V1035
+#define V1035 (V + 3430)
+ 0x1100, 0x1162, 0x11c1, 0,
+#undef V1036
+#define V1036 (V + 3434)
+ 0x1100, 0x1162, 0x11c2, 0,
+#undef V1037
+#define V1037 (V + 3438)
+ 0x1100, 0x1163, 0,
+#undef V1038
+#define V1038 (V + 3441)
+ 0x1100, 0x1163, 0x11a8, 0,
+#undef V1039
+#define V1039 (V + 3445)
+ 0x1100, 0x1163, 0x11a9, 0,
+#undef V1040
+#define V1040 (V + 3449)
+ 0x1100, 0x1163, 0x11aa, 0,
+#undef V1041
+#define V1041 (V + 3453)
+ 0x1100, 0x1163, 0x11ab, 0,
+#undef V1042
+#define V1042 (V + 3457)
+ 0x1100, 0x1163, 0x11ac, 0,
+#undef V1043
+#define V1043 (V + 3461)
+ 0x1100, 0x1163, 0x11ad, 0,
+#undef V1044
+#define V1044 (V + 3465)
+ 0x1100, 0x1163, 0x11ae, 0,
+#undef V1045
+#define V1045 (V + 3469)
+ 0x1100, 0x1163, 0x11af, 0,
+#undef V1046
+#define V1046 (V + 3473)
+ 0x1100, 0x1163, 0x11b0, 0,
+#undef V1047
+#define V1047 (V + 3477)
+ 0x1100, 0x1163, 0x11b1, 0,
+#undef V1048
+#define V1048 (V + 3481)
+ 0x1100, 0x1163, 0x11b2, 0,
+#undef V1049
+#define V1049 (V + 3485)
+ 0x1100, 0x1163, 0x11b3, 0,
+#undef V1050
+#define V1050 (V + 3489)
+ 0x1100, 0x1163, 0x11b4, 0,
+#undef V1051
+#define V1051 (V + 3493)
+ 0x1100, 0x1163, 0x11b5, 0,
+#undef V1052
+#define V1052 (V + 3497)
+ 0x1100, 0x1163, 0x11b6, 0,
+#undef V1053
+#define V1053 (V + 3501)
+ 0x1100, 0x1163, 0x11b7, 0,
+#undef V1054
+#define V1054 (V + 3505)
+ 0x1100, 0x1163, 0x11b8, 0,
+#undef V1055
+#define V1055 (V + 3509)
+ 0x1100, 0x1163, 0x11b9, 0,
+#undef V1056
+#define V1056 (V + 3513)
+ 0x1100, 0x1163, 0x11ba, 0,
+#undef V1057
+#define V1057 (V + 3517)
+ 0x1100, 0x1163, 0x11bb, 0,
+#undef V1058
+#define V1058 (V + 3521)
+ 0x1100, 0x1163, 0x11bc, 0,
+#undef V1059
+#define V1059 (V + 3525)
+ 0x1100, 0x1163, 0x11bd, 0,
+#undef V1060
+#define V1060 (V + 3529)
+ 0x1100, 0x1163, 0x11be, 0,
+#undef V1061
+#define V1061 (V + 3533)
+ 0x1100, 0x1163, 0x11bf, 0,
+#undef V1062
+#define V1062 (V + 3537)
+ 0x1100, 0x1163, 0x11c0, 0,
+#undef V1063
+#define V1063 (V + 3541)
+ 0x1100, 0x1163, 0x11c1, 0,
+#undef V1064
+#define V1064 (V + 3545)
+ 0x1100, 0x1163, 0x11c2, 0,
+#undef V1065
+#define V1065 (V + 3549)
+ 0x1100, 0x1164, 0,
+#undef V1066
+#define V1066 (V + 3552)
+ 0x1100, 0x1164, 0x11a8, 0,
+#undef V1067
+#define V1067 (V + 3556)
+ 0x1100, 0x1164, 0x11a9, 0,
+#undef V1068
+#define V1068 (V + 3560)
+ 0x1100, 0x1164, 0x11aa, 0,
+#undef V1069
+#define V1069 (V + 3564)
+ 0x1100, 0x1164, 0x11ab, 0,
+#undef V1070
+#define V1070 (V + 3568)
+ 0x1100, 0x1164, 0x11ac, 0,
+#undef V1071
+#define V1071 (V + 3572)
+ 0x1100, 0x1164, 0x11ad, 0,
+#undef V1072
+#define V1072 (V + 3576)
+ 0x1100, 0x1164, 0x11ae, 0,
+#undef V1073
+#define V1073 (V + 3580)
+ 0x1100, 0x1164, 0x11af, 0,
+#undef V1074
+#define V1074 (V + 3584)
+ 0x1100, 0x1164, 0x11b0, 0,
+#undef V1075
+#define V1075 (V + 3588)
+ 0x1100, 0x1164, 0x11b1, 0,
+#undef V1076
+#define V1076 (V + 3592)
+ 0x1100, 0x1164, 0x11b2, 0,
+#undef V1077
+#define V1077 (V + 3596)
+ 0x1100, 0x1164, 0x11b3, 0,
+#undef V1078
+#define V1078 (V + 3600)
+ 0x1100, 0x1164, 0x11b4, 0,
+#undef V1079
+#define V1079 (V + 3604)
+ 0x1100, 0x1164, 0x11b5, 0,
+#undef V1080
+#define V1080 (V + 3608)
+ 0x1100, 0x1164, 0x11b6, 0,
+#undef V1081
+#define V1081 (V + 3612)
+ 0x1100, 0x1164, 0x11b7, 0,
+#undef V1082
+#define V1082 (V + 3616)
+ 0x1100, 0x1164, 0x11b8, 0,
+#undef V1083
+#define V1083 (V + 3620)
+ 0x1100, 0x1164, 0x11b9, 0,
+#undef V1084
+#define V1084 (V + 3624)
+ 0x1100, 0x1164, 0x11ba, 0,
+#undef V1085
+#define V1085 (V + 3628)
+ 0x1100, 0x1164, 0x11bb, 0,
+#undef V1086
+#define V1086 (V + 3632)
+ 0x1100, 0x1164, 0x11bc, 0,
+#undef V1087
+#define V1087 (V + 3636)
+ 0x1100, 0x1164, 0x11bd, 0,
+#undef V1088
+#define V1088 (V + 3640)
+ 0x1100, 0x1164, 0x11be, 0,
+#undef V1089
+#define V1089 (V + 3644)
+ 0x1100, 0x1164, 0x11bf, 0,
+#undef V1090
+#define V1090 (V + 3648)
+ 0x1100, 0x1164, 0x11c0, 0,
+#undef V1091
+#define V1091 (V + 3652)
+ 0x1100, 0x1164, 0x11c1, 0,
+#undef V1092
+#define V1092 (V + 3656)
+ 0x1100, 0x1164, 0x11c2, 0,
+#undef V1093
+#define V1093 (V + 3660)
+ 0x1100, 0x1165, 0,
+#undef V1094
+#define V1094 (V + 3663)
+ 0x1100, 0x1165, 0x11a8, 0,
+#undef V1095
+#define V1095 (V + 3667)
+ 0x1100, 0x1165, 0x11a9, 0,
+#undef V1096
+#define V1096 (V + 3671)
+ 0x1100, 0x1165, 0x11aa, 0,
+#undef V1097
+#define V1097 (V + 3675)
+ 0x1100, 0x1165, 0x11ab, 0,
+#undef V1098
+#define V1098 (V + 3679)
+ 0x1100, 0x1165, 0x11ac, 0,
+#undef V1099
+#define V1099 (V + 3683)
+ 0x1100, 0x1165, 0x11ad, 0,
+#undef V1100
+#define V1100 (V + 3687)
+ 0x1100, 0x1165, 0x11ae, 0,
+#undef V1101
+#define V1101 (V + 3691)
+ 0x1100, 0x1165, 0x11af, 0,
+#undef V1102
+#define V1102 (V + 3695)
+ 0x1100, 0x1165, 0x11b0, 0,
+#undef V1103
+#define V1103 (V + 3699)
+ 0x1100, 0x1165, 0x11b1, 0,
+#undef V1104
+#define V1104 (V + 3703)
+ 0x1100, 0x1165, 0x11b2, 0,
+#undef V1105
+#define V1105 (V + 3707)
+ 0x1100, 0x1165, 0x11b3, 0,
+#undef V1106
+#define V1106 (V + 3711)
+ 0x1100, 0x1165, 0x11b4, 0,
+#undef V1107
+#define V1107 (V + 3715)
+ 0x1100, 0x1165, 0x11b5, 0,
+#undef V1108
+#define V1108 (V + 3719)
+ 0x1100, 0x1165, 0x11b6, 0,
+#undef V1109
+#define V1109 (V + 3723)
+ 0x1100, 0x1165, 0x11b7, 0,
+#undef V1110
+#define V1110 (V + 3727)
+ 0x1100, 0x1165, 0x11b8, 0,
+#undef V1111
+#define V1111 (V + 3731)
+ 0x1100, 0x1165, 0x11b9, 0,
+#undef V1112
+#define V1112 (V + 3735)
+ 0x1100, 0x1165, 0x11ba, 0,
+#undef V1113
+#define V1113 (V + 3739)
+ 0x1100, 0x1165, 0x11bb, 0,
+#undef V1114
+#define V1114 (V + 3743)
+ 0x1100, 0x1165, 0x11bc, 0,
+#undef V1115
+#define V1115 (V + 3747)
+ 0x1100, 0x1165, 0x11bd, 0,
+#undef V1116
+#define V1116 (V + 3751)
+ 0x1100, 0x1165, 0x11be, 0,
+#undef V1117
+#define V1117 (V + 3755)
+ 0x1100, 0x1165, 0x11bf, 0,
+#undef V1118
+#define V1118 (V + 3759)
+ 0x1100, 0x1165, 0x11c0, 0,
+#undef V1119
+#define V1119 (V + 3763)
+ 0x1100, 0x1165, 0x11c1, 0,
+#undef V1120
+#define V1120 (V + 3767)
+ 0x1100, 0x1165, 0x11c2, 0,
+#undef V1121
+#define V1121 (V + 3771)
+ 0x1100, 0x1166, 0,
+#undef V1122
+#define V1122 (V + 3774)
+ 0x1100, 0x1166, 0x11a8, 0,
+#undef V1123
+#define V1123 (V + 3778)
+ 0x1100, 0x1166, 0x11a9, 0,
+#undef V1124
+#define V1124 (V + 3782)
+ 0x1100, 0x1166, 0x11aa, 0,
+#undef V1125
+#define V1125 (V + 3786)
+ 0x1100, 0x1166, 0x11ab, 0,
+#undef V1126
+#define V1126 (V + 3790)
+ 0x1100, 0x1166, 0x11ac, 0,
+#undef V1127
+#define V1127 (V + 3794)
+ 0x1100, 0x1166, 0x11ad, 0,
+#undef V1128
+#define V1128 (V + 3798)
+ 0x1100, 0x1166, 0x11ae, 0,
+#undef V1129
+#define V1129 (V + 3802)
+ 0x1100, 0x1166, 0x11af, 0,
+#undef V1130
+#define V1130 (V + 3806)
+ 0x1100, 0x1166, 0x11b0, 0,
+#undef V1131
+#define V1131 (V + 3810)
+ 0x1100, 0x1166, 0x11b1, 0,
+#undef V1132
+#define V1132 (V + 3814)
+ 0x1100, 0x1166, 0x11b2, 0,
+#undef V1133
+#define V1133 (V + 3818)
+ 0x1100, 0x1166, 0x11b3, 0,
+#undef V1134
+#define V1134 (V + 3822)
+ 0x1100, 0x1166, 0x11b4, 0,
+#undef V1135
+#define V1135 (V + 3826)
+ 0x1100, 0x1166, 0x11b5, 0,
+#undef V1136
+#define V1136 (V + 3830)
+ 0x1100, 0x1166, 0x11b6, 0,
+#undef V1137
+#define V1137 (V + 3834)
+ 0x1100, 0x1166, 0x11b7, 0,
+#undef V1138
+#define V1138 (V + 3838)
+ 0x1100, 0x1166, 0x11b8, 0,
+#undef V1139
+#define V1139 (V + 3842)
+ 0x1100, 0x1166, 0x11b9, 0,
+#undef V1140
+#define V1140 (V + 3846)
+ 0x1100, 0x1166, 0x11ba, 0,
+#undef V1141
+#define V1141 (V + 3850)
+ 0x1100, 0x1166, 0x11bb, 0,
+#undef V1142
+#define V1142 (V + 3854)
+ 0x1100, 0x1166, 0x11bc, 0,
+#undef V1143
+#define V1143 (V + 3858)
+ 0x1100, 0x1166, 0x11bd, 0,
+#undef V1144
+#define V1144 (V + 3862)
+ 0x1100, 0x1166, 0x11be, 0,
+#undef V1145
+#define V1145 (V + 3866)
+ 0x1100, 0x1166, 0x11bf, 0,
+#undef V1146
+#define V1146 (V + 3870)
+ 0x1100, 0x1166, 0x11c0, 0,
+#undef V1147
+#define V1147 (V + 3874)
+ 0x1100, 0x1166, 0x11c1, 0,
+#undef V1148
+#define V1148 (V + 3878)
+ 0x1100, 0x1166, 0x11c2, 0,
+#undef V1149
+#define V1149 (V + 3882)
+ 0x1100, 0x1167, 0,
+#undef V1150
+#define V1150 (V + 3885)
+ 0x1100, 0x1167, 0x11a8, 0,
+#undef V1151
+#define V1151 (V + 3889)
+ 0x1100, 0x1167, 0x11a9, 0,
+#undef V1152
+#define V1152 (V + 3893)
+ 0x1100, 0x1167, 0x11aa, 0,
+#undef V1153
+#define V1153 (V + 3897)
+ 0x1100, 0x1167, 0x11ab, 0,
+#undef V1154
+#define V1154 (V + 3901)
+ 0x1100, 0x1167, 0x11ac, 0,
+#undef V1155
+#define V1155 (V + 3905)
+ 0x1100, 0x1167, 0x11ad, 0,
+#undef V1156
+#define V1156 (V + 3909)
+ 0x1100, 0x1167, 0x11ae, 0,
+#undef V1157
+#define V1157 (V + 3913)
+ 0x1100, 0x1167, 0x11af, 0,
+#undef V1158
+#define V1158 (V + 3917)
+ 0x1100, 0x1167, 0x11b0, 0,
+#undef V1159
+#define V1159 (V + 3921)
+ 0x1100, 0x1167, 0x11b1, 0,
+#undef V1160
+#define V1160 (V + 3925)
+ 0x1100, 0x1167, 0x11b2, 0,
+#undef V1161
+#define V1161 (V + 3929)
+ 0x1100, 0x1167, 0x11b3, 0,
+#undef V1162
+#define V1162 (V + 3933)
+ 0x1100, 0x1167, 0x11b4, 0,
+#undef V1163
+#define V1163 (V + 3937)
+ 0x1100, 0x1167, 0x11b5, 0,
+#undef V1164
+#define V1164 (V + 3941)
+ 0x1100, 0x1167, 0x11b6, 0,
+#undef V1165
+#define V1165 (V + 3945)
+ 0x1100, 0x1167, 0x11b7, 0,
+#undef V1166
+#define V1166 (V + 3949)
+ 0x1100, 0x1167, 0x11b8, 0,
+#undef V1167
+#define V1167 (V + 3953)
+ 0x1100, 0x1167, 0x11b9, 0,
+#undef V1168
+#define V1168 (V + 3957)
+ 0x1100, 0x1167, 0x11ba, 0,
+#undef V1169
+#define V1169 (V + 3961)
+ 0x1100, 0x1167, 0x11bb, 0,
+#undef V1170
+#define V1170 (V + 3965)
+ 0x1100, 0x1167, 0x11bc, 0,
+#undef V1171
+#define V1171 (V + 3969)
+ 0x1100, 0x1167, 0x11bd, 0,
+#undef V1172
+#define V1172 (V + 3973)
+ 0x1100, 0x1167, 0x11be, 0,
+#undef V1173
+#define V1173 (V + 3977)
+ 0x1100, 0x1167, 0x11bf, 0,
+#undef V1174
+#define V1174 (V + 3981)
+ 0x1100, 0x1167, 0x11c0, 0,
+#undef V1175
+#define V1175 (V + 3985)
+ 0x1100, 0x1167, 0x11c1, 0,
+#undef V1176
+#define V1176 (V + 3989)
+ 0x1100, 0x1167, 0x11c2, 0,
+#undef V1177
+#define V1177 (V + 3993)
+ 0x1100, 0x1168, 0,
+#undef V1178
+#define V1178 (V + 3996)
+ 0x1100, 0x1168, 0x11a8, 0,
+#undef V1179
+#define V1179 (V + 4000)
+ 0x1100, 0x1168, 0x11a9, 0,
+#undef V1180
+#define V1180 (V + 4004)
+ 0x1100, 0x1168, 0x11aa, 0,
+#undef V1181
+#define V1181 (V + 4008)
+ 0x1100, 0x1168, 0x11ab, 0,
+#undef V1182
+#define V1182 (V + 4012)
+ 0x1100, 0x1168, 0x11ac, 0,
+#undef V1183
+#define V1183 (V + 4016)
+ 0x1100, 0x1168, 0x11ad, 0,
+#undef V1184
+#define V1184 (V + 4020)
+ 0x1100, 0x1168, 0x11ae, 0,
+#undef V1185
+#define V1185 (V + 4024)
+ 0x1100, 0x1168, 0x11af, 0,
+#undef V1186
+#define V1186 (V + 4028)
+ 0x1100, 0x1168, 0x11b0, 0,
+#undef V1187
+#define V1187 (V + 4032)
+ 0x1100, 0x1168, 0x11b1, 0,
+#undef V1188
+#define V1188 (V + 4036)
+ 0x1100, 0x1168, 0x11b2, 0,
+#undef V1189
+#define V1189 (V + 4040)
+ 0x1100, 0x1168, 0x11b3, 0,
+#undef V1190
+#define V1190 (V + 4044)
+ 0x1100, 0x1168, 0x11b4, 0,
+#undef V1191
+#define V1191 (V + 4048)
+ 0x1100, 0x1168, 0x11b5, 0,
+#undef V1192
+#define V1192 (V + 4052)
+ 0x1100, 0x1168, 0x11b6, 0,
+#undef V1193
+#define V1193 (V + 4056)
+ 0x1100, 0x1168, 0x11b7, 0,
+#undef V1194
+#define V1194 (V + 4060)
+ 0x1100, 0x1168, 0x11b8, 0,
+#undef V1195
+#define V1195 (V + 4064)
+ 0x1100, 0x1168, 0x11b9, 0,
+#undef V1196
+#define V1196 (V + 4068)
+ 0x1100, 0x1168, 0x11ba, 0,
+#undef V1197
+#define V1197 (V + 4072)
+ 0x1100, 0x1168, 0x11bb, 0,
+#undef V1198
+#define V1198 (V + 4076)
+ 0x1100, 0x1168, 0x11bc, 0,
+#undef V1199
+#define V1199 (V + 4080)
+ 0x1100, 0x1168, 0x11bd, 0,
+#undef V1200
+#define V1200 (V + 4084)
+ 0x1100, 0x1168, 0x11be, 0,
+#undef V1201
+#define V1201 (V + 4088)
+ 0x1100, 0x1168, 0x11bf, 0,
+#undef V1202
+#define V1202 (V + 4092)
+ 0x1100, 0x1168, 0x11c0, 0,
+#undef V1203
+#define V1203 (V + 4096)
+ 0x1100, 0x1168, 0x11c1, 0,
+#undef V1204
+#define V1204 (V + 4100)
+ 0x1100, 0x1168, 0x11c2, 0,
+#undef V1205
+#define V1205 (V + 4104)
+ 0x1100, 0x1169, 0,
+#undef V1206
+#define V1206 (V + 4107)
+ 0x1100, 0x1169, 0x11a8, 0,
+#undef V1207
+#define V1207 (V + 4111)
+ 0x1100, 0x1169, 0x11a9, 0,
+#undef V1208
+#define V1208 (V + 4115)
+ 0x1100, 0x1169, 0x11aa, 0,
+#undef V1209
+#define V1209 (V + 4119)
+ 0x1100, 0x1169, 0x11ab, 0,
+#undef V1210
+#define V1210 (V + 4123)
+ 0x1100, 0x1169, 0x11ac, 0,
+#undef V1211
+#define V1211 (V + 4127)
+ 0x1100, 0x1169, 0x11ad, 0,
+#undef V1212
+#define V1212 (V + 4131)
+ 0x1100, 0x1169, 0x11ae, 0,
+#undef V1213
+#define V1213 (V + 4135)
+ 0x1100, 0x1169, 0x11af, 0,
+#undef V1214
+#define V1214 (V + 4139)
+ 0x1100, 0x1169, 0x11b0, 0,
+#undef V1215
+#define V1215 (V + 4143)
+ 0x1100, 0x1169, 0x11b1, 0,
+#undef V1216
+#define V1216 (V + 4147)
+ 0x1100, 0x1169, 0x11b2, 0,
+#undef V1217
+#define V1217 (V + 4151)
+ 0x1100, 0x1169, 0x11b3, 0,
+#undef V1218
+#define V1218 (V + 4155)
+ 0x1100, 0x1169, 0x11b4, 0,
+#undef V1219
+#define V1219 (V + 4159)
+ 0x1100, 0x1169, 0x11b5, 0,
+#undef V1220
+#define V1220 (V + 4163)
+ 0x1100, 0x1169, 0x11b6, 0,
+#undef V1221
+#define V1221 (V + 4167)
+ 0x1100, 0x1169, 0x11b7, 0,
+#undef V1222
+#define V1222 (V + 4171)
+ 0x1100, 0x1169, 0x11b8, 0,
+#undef V1223
+#define V1223 (V + 4175)
+ 0x1100, 0x1169, 0x11b9, 0,
+#undef V1224
+#define V1224 (V + 4179)
+ 0x1100, 0x1169, 0x11ba, 0,
+#undef V1225
+#define V1225 (V + 4183)
+ 0x1100, 0x1169, 0x11bb, 0,
+#undef V1226
+#define V1226 (V + 4187)
+ 0x1100, 0x1169, 0x11bc, 0,
+#undef V1227
+#define V1227 (V + 4191)
+ 0x1100, 0x1169, 0x11bd, 0,
+#undef V1228
+#define V1228 (V + 4195)
+ 0x1100, 0x1169, 0x11be, 0,
+#undef V1229
+#define V1229 (V + 4199)
+ 0x1100, 0x1169, 0x11bf, 0,
+#undef V1230
+#define V1230 (V + 4203)
+ 0x1100, 0x1169, 0x11c0, 0,
+#undef V1231
+#define V1231 (V + 4207)
+ 0x1100, 0x1169, 0x11c1, 0,
+#undef V1232
+#define V1232 (V + 4211)
+ 0x1100, 0x1169, 0x11c2, 0,
+#undef V1233
+#define V1233 (V + 4215)
+ 0x1100, 0x116a, 0,
+#undef V1234
+#define V1234 (V + 4218)
+ 0x1100, 0x116a, 0x11a8, 0,
+#undef V1235
+#define V1235 (V + 4222)
+ 0x1100, 0x116a, 0x11a9, 0,
+#undef V1236
+#define V1236 (V + 4226)
+ 0x1100, 0x116a, 0x11aa, 0,
+#undef V1237
+#define V1237 (V + 4230)
+ 0x1100, 0x116a, 0x11ab, 0,
+#undef V1238
+#define V1238 (V + 4234)
+ 0x1100, 0x116a, 0x11ac, 0,
+#undef V1239
+#define V1239 (V + 4238)
+ 0x1100, 0x116a, 0x11ad, 0,
+#undef V1240
+#define V1240 (V + 4242)
+ 0x1100, 0x116a, 0x11ae, 0,
+#undef V1241
+#define V1241 (V + 4246)
+ 0x1100, 0x116a, 0x11af, 0,
+#undef V1242
+#define V1242 (V + 4250)
+ 0x1100, 0x116a, 0x11b0, 0,
+#undef V1243
+#define V1243 (V + 4254)
+ 0x1100, 0x116a, 0x11b1, 0,
+#undef V1244
+#define V1244 (V + 4258)
+ 0x1100, 0x116a, 0x11b2, 0,
+#undef V1245
+#define V1245 (V + 4262)
+ 0x1100, 0x116a, 0x11b3, 0,
+#undef V1246
+#define V1246 (V + 4266)
+ 0x1100, 0x116a, 0x11b4, 0,
+#undef V1247
+#define V1247 (V + 4270)
+ 0x1100, 0x116a, 0x11b5, 0,
+#undef V1248
+#define V1248 (V + 4274)
+ 0x1100, 0x116a, 0x11b6, 0,
+#undef V1249
+#define V1249 (V + 4278)
+ 0x1100, 0x116a, 0x11b7, 0,
+#undef V1250
+#define V1250 (V + 4282)
+ 0x1100, 0x116a, 0x11b8, 0,
+#undef V1251
+#define V1251 (V + 4286)
+ 0x1100, 0x116a, 0x11b9, 0,
+#undef V1252
+#define V1252 (V + 4290)
+ 0x1100, 0x116a, 0x11ba, 0,
+#undef V1253
+#define V1253 (V + 4294)
+ 0x1100, 0x116a, 0x11bb, 0,
+#undef V1254
+#define V1254 (V + 4298)
+ 0x1100, 0x116a, 0x11bc, 0,
+#undef V1255
+#define V1255 (V + 4302)
+ 0x1100, 0x116a, 0x11bd, 0,
+#undef V1256
+#define V1256 (V + 4306)
+ 0x1100, 0x116a, 0x11be, 0,
+#undef V1257
+#define V1257 (V + 4310)
+ 0x1100, 0x116a, 0x11bf, 0,
+#undef V1258
+#define V1258 (V + 4314)
+ 0x1100, 0x116a, 0x11c0, 0,
+#undef V1259
+#define V1259 (V + 4318)
+ 0x1100, 0x116a, 0x11c1, 0,
+#undef V1260
+#define V1260 (V + 4322)
+ 0x1100, 0x116a, 0x11c2, 0,
+#undef V1261
+#define V1261 (V + 4326)
+ 0x1100, 0x116b, 0,
+#undef V1262
+#define V1262 (V + 4329)
+ 0x1100, 0x116b, 0x11a8, 0,
+#undef V1263
+#define V1263 (V + 4333)
+ 0x1100, 0x116b, 0x11a9, 0,
+#undef V1264
+#define V1264 (V + 4337)
+ 0x1100, 0x116b, 0x11aa, 0,
+#undef V1265
+#define V1265 (V + 4341)
+ 0x1100, 0x116b, 0x11ab, 0,
+#undef V1266
+#define V1266 (V + 4345)
+ 0x1100, 0x116b, 0x11ac, 0,
+#undef V1267
+#define V1267 (V + 4349)
+ 0x1100, 0x116b, 0x11ad, 0,
+#undef V1268
+#define V1268 (V + 4353)
+ 0x1100, 0x116b, 0x11ae, 0,
+#undef V1269
+#define V1269 (V + 4357)
+ 0x1100, 0x116b, 0x11af, 0,
+#undef V1270
+#define V1270 (V + 4361)
+ 0x1100, 0x116b, 0x11b0, 0,
+#undef V1271
+#define V1271 (V + 4365)
+ 0x1100, 0x116b, 0x11b1, 0,
+#undef V1272
+#define V1272 (V + 4369)
+ 0x1100, 0x116b, 0x11b2, 0,
+#undef V1273
+#define V1273 (V + 4373)
+ 0x1100, 0x116b, 0x11b3, 0,
+#undef V1274
+#define V1274 (V + 4377)
+ 0x1100, 0x116b, 0x11b4, 0,
+#undef V1275
+#define V1275 (V + 4381)
+ 0x1100, 0x116b, 0x11b5, 0,
+#undef V1276
+#define V1276 (V + 4385)
+ 0x1100, 0x116b, 0x11b6, 0,
+#undef V1277
+#define V1277 (V + 4389)
+ 0x1100, 0x116b, 0x11b7, 0,
+#undef V1278
+#define V1278 (V + 4393)
+ 0x1100, 0x116b, 0x11b8, 0,
+#undef V1279
+#define V1279 (V + 4397)
+ 0x1100, 0x116b, 0x11b9, 0,
+#undef V1280
+#define V1280 (V + 4401)
+ 0x1100, 0x116b, 0x11ba, 0,
+#undef V1281
+#define V1281 (V + 4405)
+ 0x1100, 0x116b, 0x11bb, 0,
+#undef V1282
+#define V1282 (V + 4409)
+ 0x1100, 0x116b, 0x11bc, 0,
+#undef V1283
+#define V1283 (V + 4413)
+ 0x1100, 0x116b, 0x11bd, 0,
+#undef V1284
+#define V1284 (V + 4417)
+ 0x1100, 0x116b, 0x11be, 0,
+#undef V1285
+#define V1285 (V + 4421)
+ 0x1100, 0x116b, 0x11bf, 0,
+#undef V1286
+#define V1286 (V + 4425)
+ 0x1100, 0x116b, 0x11c0, 0,
+#undef V1287
+#define V1287 (V + 4429)
+ 0x1100, 0x116b, 0x11c1, 0,
+#undef V1288
+#define V1288 (V + 4433)
+ 0x1100, 0x116b, 0x11c2, 0,
+#undef V1289
+#define V1289 (V + 4437)
+ 0x1100, 0x116c, 0,
+#undef V1290
+#define V1290 (V + 4440)
+ 0x1100, 0x116c, 0x11a8, 0,
+#undef V1291
+#define V1291 (V + 4444)
+ 0x1100, 0x116c, 0x11a9, 0,
+#undef V1292
+#define V1292 (V + 4448)
+ 0x1100, 0x116c, 0x11aa, 0,
+#undef V1293
+#define V1293 (V + 4452)
+ 0x1100, 0x116c, 0x11ab, 0,
+#undef V1294
+#define V1294 (V + 4456)
+ 0x1100, 0x116c, 0x11ac, 0,
+#undef V1295
+#define V1295 (V + 4460)
+ 0x1100, 0x116c, 0x11ad, 0,
+#undef V1296
+#define V1296 (V + 4464)
+ 0x1100, 0x116c, 0x11ae, 0,
+#undef V1297
+#define V1297 (V + 4468)
+ 0x1100, 0x116c, 0x11af, 0,
+#undef V1298
+#define V1298 (V + 4472)
+ 0x1100, 0x116c, 0x11b0, 0,
+#undef V1299
+#define V1299 (V + 4476)
+ 0x1100, 0x116c, 0x11b1, 0,
+#undef V1300
+#define V1300 (V + 4480)
+ 0x1100, 0x116c, 0x11b2, 0,
+#undef V1301
+#define V1301 (V + 4484)
+ 0x1100, 0x116c, 0x11b3, 0,
+#undef V1302
+#define V1302 (V + 4488)
+ 0x1100, 0x116c, 0x11b4, 0,
+#undef V1303
+#define V1303 (V + 4492)
+ 0x1100, 0x116c, 0x11b5, 0,
+#undef V1304
+#define V1304 (V + 4496)
+ 0x1100, 0x116c, 0x11b6, 0,
+#undef V1305
+#define V1305 (V + 4500)
+ 0x1100, 0x116c, 0x11b7, 0,
+#undef V1306
+#define V1306 (V + 4504)
+ 0x1100, 0x116c, 0x11b8, 0,
+#undef V1307
+#define V1307 (V + 4508)
+ 0x1100, 0x116c, 0x11b9, 0,
+#undef V1308
+#define V1308 (V + 4512)
+ 0x1100, 0x116c, 0x11ba, 0,
+#undef V1309
+#define V1309 (V + 4516)
+ 0x1100, 0x116c, 0x11bb, 0,
+#undef V1310
+#define V1310 (V + 4520)
+ 0x1100, 0x116c, 0x11bc, 0,
+#undef V1311
+#define V1311 (V + 4524)
+ 0x1100, 0x116c, 0x11bd, 0,
+#undef V1312
+#define V1312 (V + 4528)
+ 0x1100, 0x116c, 0x11be, 0,
+#undef V1313
+#define V1313 (V + 4532)
+ 0x1100, 0x116c, 0x11bf, 0,
+#undef V1314
+#define V1314 (V + 4536)
+ 0x1100, 0x116c, 0x11c0, 0,
+#undef V1315
+#define V1315 (V + 4540)
+ 0x1100, 0x116c, 0x11c1, 0,
+#undef V1316
+#define V1316 (V + 4544)
+ 0x1100, 0x116c, 0x11c2, 0,
+#undef V1317
+#define V1317 (V + 4548)
+ 0x1100, 0x116d, 0,
+#undef V1318
+#define V1318 (V + 4551)
+ 0x1100, 0x116d, 0x11a8, 0,
+#undef V1319
+#define V1319 (V + 4555)
+ 0x1100, 0x116d, 0x11a9, 0,
+#undef V1320
+#define V1320 (V + 4559)
+ 0x1100, 0x116d, 0x11aa, 0,
+#undef V1321
+#define V1321 (V + 4563)
+ 0x1100, 0x116d, 0x11ab, 0,
+#undef V1322
+#define V1322 (V + 4567)
+ 0x1100, 0x116d, 0x11ac, 0,
+#undef V1323
+#define V1323 (V + 4571)
+ 0x1100, 0x116d, 0x11ad, 0,
+#undef V1324
+#define V1324 (V + 4575)
+ 0x1100, 0x116d, 0x11ae, 0,
+#undef V1325
+#define V1325 (V + 4579)
+ 0x1100, 0x116d, 0x11af, 0,
+#undef V1326
+#define V1326 (V + 4583)
+ 0x1100, 0x116d, 0x11b0, 0,
+#undef V1327
+#define V1327 (V + 4587)
+ 0x1100, 0x116d, 0x11b1, 0,
+#undef V1328
+#define V1328 (V + 4591)
+ 0x1100, 0x116d, 0x11b2, 0,
+#undef V1329
+#define V1329 (V + 4595)
+ 0x1100, 0x116d, 0x11b3, 0,
+#undef V1330
+#define V1330 (V + 4599)
+ 0x1100, 0x116d, 0x11b4, 0,
+#undef V1331
+#define V1331 (V + 4603)
+ 0x1100, 0x116d, 0x11b5, 0,
+#undef V1332
+#define V1332 (V + 4607)
+ 0x1100, 0x116d, 0x11b6, 0,
+#undef V1333
+#define V1333 (V + 4611)
+ 0x1100, 0x116d, 0x11b7, 0,
+#undef V1334
+#define V1334 (V + 4615)
+ 0x1100, 0x116d, 0x11b8, 0,
+#undef V1335
+#define V1335 (V + 4619)
+ 0x1100, 0x116d, 0x11b9, 0,
+#undef V1336
+#define V1336 (V + 4623)
+ 0x1100, 0x116d, 0x11ba, 0,
+#undef V1337
+#define V1337 (V + 4627)
+ 0x1100, 0x116d, 0x11bb, 0,
+#undef V1338
+#define V1338 (V + 4631)
+ 0x1100, 0x116d, 0x11bc, 0,
+#undef V1339
+#define V1339 (V + 4635)
+ 0x1100, 0x116d, 0x11bd, 0,
+#undef V1340
+#define V1340 (V + 4639)
+ 0x1100, 0x116d, 0x11be, 0,
+#undef V1341
+#define V1341 (V + 4643)
+ 0x1100, 0x116d, 0x11bf, 0,
+#undef V1342
+#define V1342 (V + 4647)
+ 0x1100, 0x116d, 0x11c0, 0,
+#undef V1343
+#define V1343 (V + 4651)
+ 0x1100, 0x116d, 0x11c1, 0,
+#undef V1344
+#define V1344 (V + 4655)
+ 0x1100, 0x116d, 0x11c2, 0,
+#undef V1345
+#define V1345 (V + 4659)
+ 0x1100, 0x116e, 0,
+#undef V1346
+#define V1346 (V + 4662)
+ 0x1100, 0x116e, 0x11a8, 0,
+#undef V1347
+#define V1347 (V + 4666)
+ 0x1100, 0x116e, 0x11a9, 0,
+#undef V1348
+#define V1348 (V + 4670)
+ 0x1100, 0x116e, 0x11aa, 0,
+#undef V1349
+#define V1349 (V + 4674)
+ 0x1100, 0x116e, 0x11ab, 0,
+#undef V1350
+#define V1350 (V + 4678)
+ 0x1100, 0x116e, 0x11ac, 0,
+#undef V1351
+#define V1351 (V + 4682)
+ 0x1100, 0x116e, 0x11ad, 0,
+#undef V1352
+#define V1352 (V + 4686)
+ 0x1100, 0x116e, 0x11ae, 0,
+#undef V1353
+#define V1353 (V + 4690)
+ 0x1100, 0x116e, 0x11af, 0,
+#undef V1354
+#define V1354 (V + 4694)
+ 0x1100, 0x116e, 0x11b0, 0,
+#undef V1355
+#define V1355 (V + 4698)
+ 0x1100, 0x116e, 0x11b1, 0,
+#undef V1356
+#define V1356 (V + 4702)
+ 0x1100, 0x116e, 0x11b2, 0,
+#undef V1357
+#define V1357 (V + 4706)
+ 0x1100, 0x116e, 0x11b3, 0,
+#undef V1358
+#define V1358 (V + 4710)
+ 0x1100, 0x116e, 0x11b4, 0,
+#undef V1359
+#define V1359 (V + 4714)
+ 0x1100, 0x116e, 0x11b5, 0,
+#undef V1360
+#define V1360 (V + 4718)
+ 0x1100, 0x116e, 0x11b6, 0,
+#undef V1361
+#define V1361 (V + 4722)
+ 0x1100, 0x116e, 0x11b7, 0,
+#undef V1362
+#define V1362 (V + 4726)
+ 0x1100, 0x116e, 0x11b8, 0,
+#undef V1363
+#define V1363 (V + 4730)
+ 0x1100, 0x116e, 0x11b9, 0,
+#undef V1364
+#define V1364 (V + 4734)
+ 0x1100, 0x116e, 0x11ba, 0,
+#undef V1365
+#define V1365 (V + 4738)
+ 0x1100, 0x116e, 0x11bb, 0,
+#undef V1366
+#define V1366 (V + 4742)
+ 0x1100, 0x116e, 0x11bc, 0,
+#undef V1367
+#define V1367 (V + 4746)
+ 0x1100, 0x116e, 0x11bd, 0,
+#undef V1368
+#define V1368 (V + 4750)
+ 0x1100, 0x116e, 0x11be, 0,
+#undef V1369
+#define V1369 (V + 4754)
+ 0x1100, 0x116e, 0x11bf, 0,
+#undef V1370
+#define V1370 (V + 4758)
+ 0x1100, 0x116e, 0x11c0, 0,
+#undef V1371
+#define V1371 (V + 4762)
+ 0x1100, 0x116e, 0x11c1, 0,
+#undef V1372
+#define V1372 (V + 4766)
+ 0x1100, 0x116e, 0x11c2, 0,
+#undef V1373
+#define V1373 (V + 4770)
+ 0x1100, 0x116f, 0,
+#undef V1374
+#define V1374 (V + 4773)
+ 0x1100, 0x116f, 0x11a8, 0,
+#undef V1375
+#define V1375 (V + 4777)
+ 0x1100, 0x116f, 0x11a9, 0,
+#undef V1376
+#define V1376 (V + 4781)
+ 0x1100, 0x116f, 0x11aa, 0,
+#undef V1377
+#define V1377 (V + 4785)
+ 0x1100, 0x116f, 0x11ab, 0,
+#undef V1378
+#define V1378 (V + 4789)
+ 0x1100, 0x116f, 0x11ac, 0,
+#undef V1379
+#define V1379 (V + 4793)
+ 0x1100, 0x116f, 0x11ad, 0,
+#undef V1380
+#define V1380 (V + 4797)
+ 0x1100, 0x116f, 0x11ae, 0,
+#undef V1381
+#define V1381 (V + 4801)
+ 0x1100, 0x116f, 0x11af, 0,
+#undef V1382
+#define V1382 (V + 4805)
+ 0x1100, 0x116f, 0x11b0, 0,
+#undef V1383
+#define V1383 (V + 4809)
+ 0x1100, 0x116f, 0x11b1, 0,
+#undef V1384
+#define V1384 (V + 4813)
+ 0x1100, 0x116f, 0x11b2, 0,
+#undef V1385
+#define V1385 (V + 4817)
+ 0x1100, 0x116f, 0x11b3, 0,
+#undef V1386
+#define V1386 (V + 4821)
+ 0x1100, 0x116f, 0x11b4, 0,
+#undef V1387
+#define V1387 (V + 4825)
+ 0x1100, 0x116f, 0x11b5, 0,
+#undef V1388
+#define V1388 (V + 4829)
+ 0x1100, 0x116f, 0x11b6, 0,
+#undef V1389
+#define V1389 (V + 4833)
+ 0x1100, 0x116f, 0x11b7, 0,
+#undef V1390
+#define V1390 (V + 4837)
+ 0x1100, 0x116f, 0x11b8, 0,
+#undef V1391
+#define V1391 (V + 4841)
+ 0x1100, 0x116f, 0x11b9, 0,
+#undef V1392
+#define V1392 (V + 4845)
+ 0x1100, 0x116f, 0x11ba, 0,
+#undef V1393
+#define V1393 (V + 4849)
+ 0x1100, 0x116f, 0x11bb, 0,
+#undef V1394
+#define V1394 (V + 4853)
+ 0x1100, 0x116f, 0x11bc, 0,
+#undef V1395
+#define V1395 (V + 4857)
+ 0x1100, 0x116f, 0x11bd, 0,
+#undef V1396
+#define V1396 (V + 4861)
+ 0x1100, 0x116f, 0x11be, 0,
+#undef V1397
+#define V1397 (V + 4865)
+ 0x1100, 0x116f, 0x11bf, 0,
+#undef V1398
+#define V1398 (V + 4869)
+ 0x1100, 0x116f, 0x11c0, 0,
+#undef V1399
+#define V1399 (V + 4873)
+ 0x1100, 0x116f, 0x11c1, 0,
+#undef V1400
+#define V1400 (V + 4877)
+ 0x1100, 0x116f, 0x11c2, 0,
+#undef V1401
+#define V1401 (V + 4881)
+ 0x1100, 0x1170, 0,
+#undef V1402
+#define V1402 (V + 4884)
+ 0x1100, 0x1170, 0x11a8, 0,
+#undef V1403
+#define V1403 (V + 4888)
+ 0x1100, 0x1170, 0x11a9, 0,
+#undef V1404
+#define V1404 (V + 4892)
+ 0x1100, 0x1170, 0x11aa, 0,
+#undef V1405
+#define V1405 (V + 4896)
+ 0x1100, 0x1170, 0x11ab, 0,
+#undef V1406
+#define V1406 (V + 4900)
+ 0x1100, 0x1170, 0x11ac, 0,
+#undef V1407
+#define V1407 (V + 4904)
+ 0x1100, 0x1170, 0x11ad, 0,
+#undef V1408
+#define V1408 (V + 4908)
+ 0x1100, 0x1170, 0x11ae, 0,
+#undef V1409
+#define V1409 (V + 4912)
+ 0x1100, 0x1170, 0x11af, 0,
+#undef V1410
+#define V1410 (V + 4916)
+ 0x1100, 0x1170, 0x11b0, 0,
+#undef V1411
+#define V1411 (V + 4920)
+ 0x1100, 0x1170, 0x11b1, 0,
+#undef V1412
+#define V1412 (V + 4924)
+ 0x1100, 0x1170, 0x11b2, 0,
+#undef V1413
+#define V1413 (V + 4928)
+ 0x1100, 0x1170, 0x11b3, 0,
+#undef V1414
+#define V1414 (V + 4932)
+ 0x1100, 0x1170, 0x11b4, 0,
+#undef V1415
+#define V1415 (V + 4936)
+ 0x1100, 0x1170, 0x11b5, 0,
+#undef V1416
+#define V1416 (V + 4940)
+ 0x1100, 0x1170, 0x11b6, 0,
+#undef V1417
+#define V1417 (V + 4944)
+ 0x1100, 0x1170, 0x11b7, 0,
+#undef V1418
+#define V1418 (V + 4948)
+ 0x1100, 0x1170, 0x11b8, 0,
+#undef V1419
+#define V1419 (V + 4952)
+ 0x1100, 0x1170, 0x11b9, 0,
+#undef V1420
+#define V1420 (V + 4956)
+ 0x1100, 0x1170, 0x11ba, 0,
+#undef V1421
+#define V1421 (V + 4960)
+ 0x1100, 0x1170, 0x11bb, 0,
+#undef V1422
+#define V1422 (V + 4964)
+ 0x1100, 0x1170, 0x11bc, 0,
+#undef V1423
+#define V1423 (V + 4968)
+ 0x1100, 0x1170, 0x11bd, 0,
+#undef V1424
+#define V1424 (V + 4972)
+ 0x1100, 0x1170, 0x11be, 0,
+#undef V1425
+#define V1425 (V + 4976)
+ 0x1100, 0x1170, 0x11bf, 0,
+#undef V1426
+#define V1426 (V + 4980)
+ 0x1100, 0x1170, 0x11c0, 0,
+#undef V1427
+#define V1427 (V + 4984)
+ 0x1100, 0x1170, 0x11c1, 0,
+#undef V1428
+#define V1428 (V + 4988)
+ 0x1100, 0x1170, 0x11c2, 0,
+#undef V1429
+#define V1429 (V + 4992)
+ 0x1100, 0x1171, 0,
+#undef V1430
+#define V1430 (V + 4995)
+ 0x1100, 0x1171, 0x11a8, 0,
+#undef V1431
+#define V1431 (V + 4999)
+ 0x1100, 0x1171, 0x11a9, 0,
+#undef V1432
+#define V1432 (V + 5003)
+ 0x1100, 0x1171, 0x11aa, 0,
+#undef V1433
+#define V1433 (V + 5007)
+ 0x1100, 0x1171, 0x11ab, 0,
+#undef V1434
+#define V1434 (V + 5011)
+ 0x1100, 0x1171, 0x11ac, 0,
+#undef V1435
+#define V1435 (V + 5015)
+ 0x1100, 0x1171, 0x11ad, 0,
+#undef V1436
+#define V1436 (V + 5019)
+ 0x1100, 0x1171, 0x11ae, 0,
+#undef V1437
+#define V1437 (V + 5023)
+ 0x1100, 0x1171, 0x11af, 0,
+#undef V1438
+#define V1438 (V + 5027)
+ 0x1100, 0x1171, 0x11b0, 0,
+#undef V1439
+#define V1439 (V + 5031)
+ 0x1100, 0x1171, 0x11b1, 0,
+#undef V1440
+#define V1440 (V + 5035)
+ 0x1100, 0x1171, 0x11b2, 0,
+#undef V1441
+#define V1441 (V + 5039)
+ 0x1100, 0x1171, 0x11b3, 0,
+#undef V1442
+#define V1442 (V + 5043)
+ 0x1100, 0x1171, 0x11b4, 0,
+#undef V1443
+#define V1443 (V + 5047)
+ 0x1100, 0x1171, 0x11b5, 0,
+#undef V1444
+#define V1444 (V + 5051)
+ 0x1100, 0x1171, 0x11b6, 0,
+#undef V1445
+#define V1445 (V + 5055)
+ 0x1100, 0x1171, 0x11b7, 0,
+#undef V1446
+#define V1446 (V + 5059)
+ 0x1100, 0x1171, 0x11b8, 0,
+#undef V1447
+#define V1447 (V + 5063)
+ 0x1100, 0x1171, 0x11b9, 0,
+#undef V1448
+#define V1448 (V + 5067)
+ 0x1100, 0x1171, 0x11ba, 0,
+#undef V1449
+#define V1449 (V + 5071)
+ 0x1100, 0x1171, 0x11bb, 0,
+#undef V1450
+#define V1450 (V + 5075)
+ 0x1100, 0x1171, 0x11bc, 0,
+#undef V1451
+#define V1451 (V + 5079)
+ 0x1100, 0x1171, 0x11bd, 0,
+#undef V1452
+#define V1452 (V + 5083)
+ 0x1100, 0x1171, 0x11be, 0,
+#undef V1453
+#define V1453 (V + 5087)
+ 0x1100, 0x1171, 0x11bf, 0,
+#undef V1454
+#define V1454 (V + 5091)
+ 0x1100, 0x1171, 0x11c0, 0,
+#undef V1455
+#define V1455 (V + 5095)
+ 0x1100, 0x1171, 0x11c1, 0,
+#undef V1456
+#define V1456 (V + 5099)
+ 0x1100, 0x1171, 0x11c2, 0,
+#undef V1457
+#define V1457 (V + 5103)
+ 0x1100, 0x1172, 0,
+#undef V1458
+#define V1458 (V + 5106)
+ 0x1100, 0x1172, 0x11a8, 0,
+#undef V1459
+#define V1459 (V + 5110)
+ 0x1100, 0x1172, 0x11a9, 0,
+#undef V1460
+#define V1460 (V + 5114)
+ 0x1100, 0x1172, 0x11aa, 0,
+#undef V1461
+#define V1461 (V + 5118)
+ 0x1100, 0x1172, 0x11ab, 0,
+#undef V1462
+#define V1462 (V + 5122)
+ 0x1100, 0x1172, 0x11ac, 0,
+#undef V1463
+#define V1463 (V + 5126)
+ 0x1100, 0x1172, 0x11ad, 0,
+#undef V1464
+#define V1464 (V + 5130)
+ 0x1100, 0x1172, 0x11ae, 0,
+#undef V1465
+#define V1465 (V + 5134)
+ 0x1100, 0x1172, 0x11af, 0,
+#undef V1466
+#define V1466 (V + 5138)
+ 0x1100, 0x1172, 0x11b0, 0,
+#undef V1467
+#define V1467 (V + 5142)
+ 0x1100, 0x1172, 0x11b1, 0,
+#undef V1468
+#define V1468 (V + 5146)
+ 0x1100, 0x1172, 0x11b2, 0,
+#undef V1469
+#define V1469 (V + 5150)
+ 0x1100, 0x1172, 0x11b3, 0,
+#undef V1470
+#define V1470 (V + 5154)
+ 0x1100, 0x1172, 0x11b4, 0,
+#undef V1471
+#define V1471 (V + 5158)
+ 0x1100, 0x1172, 0x11b5, 0,
+#undef V1472
+#define V1472 (V + 5162)
+ 0x1100, 0x1172, 0x11b6, 0,
+#undef V1473
+#define V1473 (V + 5166)
+ 0x1100, 0x1172, 0x11b7, 0,
+#undef V1474
+#define V1474 (V + 5170)
+ 0x1100, 0x1172, 0x11b8, 0,
+#undef V1475
+#define V1475 (V + 5174)
+ 0x1100, 0x1172, 0x11b9, 0,
+#undef V1476
+#define V1476 (V + 5178)
+ 0x1100, 0x1172, 0x11ba, 0,
+#undef V1477
+#define V1477 (V + 5182)
+ 0x1100, 0x1172, 0x11bb, 0,
+#undef V1478
+#define V1478 (V + 5186)
+ 0x1100, 0x1172, 0x11bc, 0,
+#undef V1479
+#define V1479 (V + 5190)
+ 0x1100, 0x1172, 0x11bd, 0,
+#undef V1480
+#define V1480 (V + 5194)
+ 0x1100, 0x1172, 0x11be, 0,
+#undef V1481
+#define V1481 (V + 5198)
+ 0x1100, 0x1172, 0x11bf, 0,
+#undef V1482
+#define V1482 (V + 5202)
+ 0x1100, 0x1172, 0x11c0, 0,
+#undef V1483
+#define V1483 (V + 5206)
+ 0x1100, 0x1172, 0x11c1, 0,
+#undef V1484
+#define V1484 (V + 5210)
+ 0x1100, 0x1172, 0x11c2, 0,
+#undef V1485
+#define V1485 (V + 5214)
+ 0x1100, 0x1173, 0,
+#undef V1486
+#define V1486 (V + 5217)
+ 0x1100, 0x1173, 0x11a8, 0,
+#undef V1487
+#define V1487 (V + 5221)
+ 0x1100, 0x1173, 0x11a9, 0,
+#undef V1488
+#define V1488 (V + 5225)
+ 0x1100, 0x1173, 0x11aa, 0,
+#undef V1489
+#define V1489 (V + 5229)
+ 0x1100, 0x1173, 0x11ab, 0,
+#undef V1490
+#define V1490 (V + 5233)
+ 0x1100, 0x1173, 0x11ac, 0,
+#undef V1491
+#define V1491 (V + 5237)
+ 0x1100, 0x1173, 0x11ad, 0,
+#undef V1492
+#define V1492 (V + 5241)
+ 0x1100, 0x1173, 0x11ae, 0,
+#undef V1493
+#define V1493 (V + 5245)
+ 0x1100, 0x1173, 0x11af, 0,
+#undef V1494
+#define V1494 (V + 5249)
+ 0x1100, 0x1173, 0x11b0, 0,
+#undef V1495
+#define V1495 (V + 5253)
+ 0x1100, 0x1173, 0x11b1, 0,
+#undef V1496
+#define V1496 (V + 5257)
+ 0x1100, 0x1173, 0x11b2, 0,
+#undef V1497
+#define V1497 (V + 5261)
+ 0x1100, 0x1173, 0x11b3, 0,
+#undef V1498
+#define V1498 (V + 5265)
+ 0x1100, 0x1173, 0x11b4, 0,
+#undef V1499
+#define V1499 (V + 5269)
+ 0x1100, 0x1173, 0x11b5, 0,
+#undef V1500
+#define V1500 (V + 5273)
+ 0x1100, 0x1173, 0x11b6, 0,
+#undef V1501
+#define V1501 (V + 5277)
+ 0x1100, 0x1173, 0x11b7, 0,
+#undef V1502
+#define V1502 (V + 5281)
+ 0x1100, 0x1173, 0x11b8, 0,
+#undef V1503
+#define V1503 (V + 5285)
+ 0x1100, 0x1173, 0x11b9, 0,
+#undef V1504
+#define V1504 (V + 5289)
+ 0x1100, 0x1173, 0x11ba, 0,
+#undef V1505
+#define V1505 (V + 5293)
+ 0x1100, 0x1173, 0x11bb, 0,
+#undef V1506
+#define V1506 (V + 5297)
+ 0x1100, 0x1173, 0x11bc, 0,
+#undef V1507
+#define V1507 (V + 5301)
+ 0x1100, 0x1173, 0x11bd, 0,
+#undef V1508
+#define V1508 (V + 5305)
+ 0x1100, 0x1173, 0x11be, 0,
+#undef V1509
+#define V1509 (V + 5309)
+ 0x1100, 0x1173, 0x11bf, 0,
+#undef V1510
+#define V1510 (V + 5313)
+ 0x1100, 0x1173, 0x11c0, 0,
+#undef V1511
+#define V1511 (V + 5317)
+ 0x1100, 0x1173, 0x11c1, 0,
+#undef V1512
+#define V1512 (V + 5321)
+ 0x1100, 0x1173, 0x11c2, 0,
+#undef V1513
+#define V1513 (V + 5325)
+ 0x1100, 0x1174, 0,
+#undef V1514
+#define V1514 (V + 5328)
+ 0x1100, 0x1174, 0x11a8, 0,
+#undef V1515
+#define V1515 (V + 5332)
+ 0x1100, 0x1174, 0x11a9, 0,
+#undef V1516
+#define V1516 (V + 5336)
+ 0x1100, 0x1174, 0x11aa, 0,
+#undef V1517
+#define V1517 (V + 5340)
+ 0x1100, 0x1174, 0x11ab, 0,
+#undef V1518
+#define V1518 (V + 5344)
+ 0x1100, 0x1174, 0x11ac, 0,
+#undef V1519
+#define V1519 (V + 5348)
+ 0x1100, 0x1174, 0x11ad, 0,
+#undef V1520
+#define V1520 (V + 5352)
+ 0x1100, 0x1174, 0x11ae, 0,
+#undef V1521
+#define V1521 (V + 5356)
+ 0x1100, 0x1174, 0x11af, 0,
+#undef V1522
+#define V1522 (V + 5360)
+ 0x1100, 0x1174, 0x11b0, 0,
+#undef V1523
+#define V1523 (V + 5364)
+ 0x1100, 0x1174, 0x11b1, 0,
+#undef V1524
+#define V1524 (V + 5368)
+ 0x1100, 0x1174, 0x11b2, 0,
+#undef V1525
+#define V1525 (V + 5372)
+ 0x1100, 0x1174, 0x11b3, 0,
+#undef V1526
+#define V1526 (V + 5376)
+ 0x1100, 0x1174, 0x11b4, 0,
+#undef V1527
+#define V1527 (V + 5380)
+ 0x1100, 0x1174, 0x11b5, 0,
+#undef V1528
+#define V1528 (V + 5384)
+ 0x1100, 0x1174, 0x11b6, 0,
+#undef V1529
+#define V1529 (V + 5388)
+ 0x1100, 0x1174, 0x11b7, 0,
+#undef V1530
+#define V1530 (V + 5392)
+ 0x1100, 0x1174, 0x11b8, 0,
+#undef V1531
+#define V1531 (V + 5396)
+ 0x1100, 0x1174, 0x11b9, 0,
+#undef V1532
+#define V1532 (V + 5400)
+ 0x1100, 0x1174, 0x11ba, 0,
+#undef V1533
+#define V1533 (V + 5404)
+ 0x1100, 0x1174, 0x11bb, 0,
+#undef V1534
+#define V1534 (V + 5408)
+ 0x1100, 0x1174, 0x11bc, 0,
+#undef V1535
+#define V1535 (V + 5412)
+ 0x1100, 0x1174, 0x11bd, 0,
+#undef V1536
+#define V1536 (V + 5416)
+ 0x1100, 0x1174, 0x11be, 0,
+#undef V1537
+#define V1537 (V + 5420)
+ 0x1100, 0x1174, 0x11bf, 0,
+#undef V1538
+#define V1538 (V + 5424)
+ 0x1100, 0x1174, 0x11c0, 0,
+#undef V1539
+#define V1539 (V + 5428)
+ 0x1100, 0x1174, 0x11c1, 0,
+#undef V1540
+#define V1540 (V + 5432)
+ 0x1100, 0x1174, 0x11c2, 0,
+#undef V1541
+#define V1541 (V + 5436)
+ 0x1100, 0x1175, 0,
+#undef V1542
+#define V1542 (V + 5439)
+ 0x1100, 0x1175, 0x11a8, 0,
+#undef V1543
+#define V1543 (V + 5443)
+ 0x1100, 0x1175, 0x11a9, 0,
+#undef V1544
+#define V1544 (V + 5447)
+ 0x1100, 0x1175, 0x11aa, 0,
+#undef V1545
+#define V1545 (V + 5451)
+ 0x1100, 0x1175, 0x11ab, 0,
+#undef V1546
+#define V1546 (V + 5455)
+ 0x1100, 0x1175, 0x11ac, 0,
+#undef V1547
+#define V1547 (V + 5459)
+ 0x1100, 0x1175, 0x11ad, 0,
+#undef V1548
+#define V1548 (V + 5463)
+ 0x1100, 0x1175, 0x11ae, 0,
+#undef V1549
+#define V1549 (V + 5467)
+ 0x1100, 0x1175, 0x11af, 0,
+#undef V1550
+#define V1550 (V + 5471)
+ 0x1100, 0x1175, 0x11b0, 0,
+#undef V1551
+#define V1551 (V + 5475)
+ 0x1100, 0x1175, 0x11b1, 0,
+#undef V1552
+#define V1552 (V + 5479)
+ 0x1100, 0x1175, 0x11b2, 0,
+#undef V1553
+#define V1553 (V + 5483)
+ 0x1100, 0x1175, 0x11b3, 0,
+#undef V1554
+#define V1554 (V + 5487)
+ 0x1100, 0x1175, 0x11b4, 0,
+#undef V1555
+#define V1555 (V + 5491)
+ 0x1100, 0x1175, 0x11b5, 0,
+#undef V1556
+#define V1556 (V + 5495)
+ 0x1100, 0x1175, 0x11b6, 0,
+#undef V1557
+#define V1557 (V + 5499)
+ 0x1100, 0x1175, 0x11b7, 0,
+#undef V1558
+#define V1558 (V + 5503)
+ 0x1100, 0x1175, 0x11b8, 0,
+#undef V1559
+#define V1559 (V + 5507)
+ 0x1100, 0x1175, 0x11b9, 0,
+#undef V1560
+#define V1560 (V + 5511)
+ 0x1100, 0x1175, 0x11ba, 0,
+#undef V1561
+#define V1561 (V + 5515)
+ 0x1100, 0x1175, 0x11bb, 0,
+#undef V1562
+#define V1562 (V + 5519)
+ 0x1100, 0x1175, 0x11bc, 0,
+#undef V1563
+#define V1563 (V + 5523)
+ 0x1100, 0x1175, 0x11bd, 0,
+#undef V1564
+#define V1564 (V + 5527)
+ 0x1100, 0x1175, 0x11be, 0,
+#undef V1565
+#define V1565 (V + 5531)
+ 0x1100, 0x1175, 0x11bf, 0,
+#undef V1566
+#define V1566 (V + 5535)
+ 0x1100, 0x1175, 0x11c0, 0,
+#undef V1567
+#define V1567 (V + 5539)
+ 0x1100, 0x1175, 0x11c1, 0,
+#undef V1568
+#define V1568 (V + 5543)
+ 0x1100, 0x1175, 0x11c2, 0,
+#undef V1569
+#define V1569 (V + 5547)
+ 0x1101, 0x1161, 0,
+#undef V1570
+#define V1570 (V + 5550)
+ 0x1101, 0x1161, 0x11a8, 0,
+#undef V1571
+#define V1571 (V + 5554)
+ 0x1101, 0x1161, 0x11a9, 0,
+#undef V1572
+#define V1572 (V + 5558)
+ 0x1101, 0x1161, 0x11aa, 0,
+#undef V1573
+#define V1573 (V + 5562)
+ 0x1101, 0x1161, 0x11ab, 0,
+#undef V1574
+#define V1574 (V + 5566)
+ 0x1101, 0x1161, 0x11ac, 0,
+#undef V1575
+#define V1575 (V + 5570)
+ 0x1101, 0x1161, 0x11ad, 0,
+#undef V1576
+#define V1576 (V + 5574)
+ 0x1101, 0x1161, 0x11ae, 0,
+#undef V1577
+#define V1577 (V + 5578)
+ 0x1101, 0x1161, 0x11af, 0,
+#undef V1578
+#define V1578 (V + 5582)
+ 0x1101, 0x1161, 0x11b0, 0,
+#undef V1579
+#define V1579 (V + 5586)
+ 0x1101, 0x1161, 0x11b1, 0,
+#undef V1580
+#define V1580 (V + 5590)
+ 0x1101, 0x1161, 0x11b2, 0,
+#undef V1581
+#define V1581 (V + 5594)
+ 0x1101, 0x1161, 0x11b3, 0,
+#undef V1582
+#define V1582 (V + 5598)
+ 0x1101, 0x1161, 0x11b4, 0,
+#undef V1583
+#define V1583 (V + 5602)
+ 0x1101, 0x1161, 0x11b5, 0,
+#undef V1584
+#define V1584 (V + 5606)
+ 0x1101, 0x1161, 0x11b6, 0,
+#undef V1585
+#define V1585 (V + 5610)
+ 0x1101, 0x1161, 0x11b7, 0,
+#undef V1586
+#define V1586 (V + 5614)
+ 0x1101, 0x1161, 0x11b8, 0,
+#undef V1587
+#define V1587 (V + 5618)
+ 0x1101, 0x1161, 0x11b9, 0,
+#undef V1588
+#define V1588 (V + 5622)
+ 0x1101, 0x1161, 0x11ba, 0,
+#undef V1589
+#define V1589 (V + 5626)
+ 0x1101, 0x1161, 0x11bb, 0,
+#undef V1590
+#define V1590 (V + 5630)
+ 0x1101, 0x1161, 0x11bc, 0,
+#undef V1591
+#define V1591 (V + 5634)
+ 0x1101, 0x1161, 0x11bd, 0,
+#undef V1592
+#define V1592 (V + 5638)
+ 0x1101, 0x1161, 0x11be, 0,
+#undef V1593
+#define V1593 (V + 5642)
+ 0x1101, 0x1161, 0x11bf, 0,
+#undef V1594
+#define V1594 (V + 5646)
+ 0x1101, 0x1161, 0x11c0, 0,
+#undef V1595
+#define V1595 (V + 5650)
+ 0x1101, 0x1161, 0x11c1, 0,
+#undef V1596
+#define V1596 (V + 5654)
+ 0x1101, 0x1161, 0x11c2, 0,
+#undef V1597
+#define V1597 (V + 5658)
+ 0x1101, 0x1162, 0,
+#undef V1598
+#define V1598 (V + 5661)
+ 0x1101, 0x1162, 0x11a8, 0,
+#undef V1599
+#define V1599 (V + 5665)
+ 0x1101, 0x1162, 0x11a9, 0,
+#undef V1600
+#define V1600 (V + 5669)
+ 0x1101, 0x1162, 0x11aa, 0,
+#undef V1601
+#define V1601 (V + 5673)
+ 0x1101, 0x1162, 0x11ab, 0,
+#undef V1602
+#define V1602 (V + 5677)
+ 0x1101, 0x1162, 0x11ac, 0,
+#undef V1603
+#define V1603 (V + 5681)
+ 0x1101, 0x1162, 0x11ad, 0,
+#undef V1604
+#define V1604 (V + 5685)
+ 0x1101, 0x1162, 0x11ae, 0,
+#undef V1605
+#define V1605 (V + 5689)
+ 0x1101, 0x1162, 0x11af, 0,
+#undef V1606
+#define V1606 (V + 5693)
+ 0x1101, 0x1162, 0x11b0, 0,
+#undef V1607
+#define V1607 (V + 5697)
+ 0x1101, 0x1162, 0x11b1, 0,
+#undef V1608
+#define V1608 (V + 5701)
+ 0x1101, 0x1162, 0x11b2, 0,
+#undef V1609
+#define V1609 (V + 5705)
+ 0x1101, 0x1162, 0x11b3, 0,
+#undef V1610
+#define V1610 (V + 5709)
+ 0x1101, 0x1162, 0x11b4, 0,
+#undef V1611
+#define V1611 (V + 5713)
+ 0x1101, 0x1162, 0x11b5, 0,
+#undef V1612
+#define V1612 (V + 5717)
+ 0x1101, 0x1162, 0x11b6, 0,
+#undef V1613
+#define V1613 (V + 5721)
+ 0x1101, 0x1162, 0x11b7, 0,
+#undef V1614
+#define V1614 (V + 5725)
+ 0x1101, 0x1162, 0x11b8, 0,
+#undef V1615
+#define V1615 (V + 5729)
+ 0x1101, 0x1162, 0x11b9, 0,
+#undef V1616
+#define V1616 (V + 5733)
+ 0x1101, 0x1162, 0x11ba, 0,
+#undef V1617
+#define V1617 (V + 5737)
+ 0x1101, 0x1162, 0x11bb, 0,
+#undef V1618
+#define V1618 (V + 5741)
+ 0x1101, 0x1162, 0x11bc, 0,
+#undef V1619
+#define V1619 (V + 5745)
+ 0x1101, 0x1162, 0x11bd, 0,
+#undef V1620
+#define V1620 (V + 5749)
+ 0x1101, 0x1162, 0x11be, 0,
+#undef V1621
+#define V1621 (V + 5753)
+ 0x1101, 0x1162, 0x11bf, 0,
+#undef V1622
+#define V1622 (V + 5757)
+ 0x1101, 0x1162, 0x11c0, 0,
+#undef V1623
+#define V1623 (V + 5761)
+ 0x1101, 0x1162, 0x11c1, 0,
+#undef V1624
+#define V1624 (V + 5765)
+ 0x1101, 0x1162, 0x11c2, 0,
+#undef V1625
+#define V1625 (V + 5769)
+ 0x1101, 0x1163, 0,
+#undef V1626
+#define V1626 (V + 5772)
+ 0x1101, 0x1163, 0x11a8, 0,
+#undef V1627
+#define V1627 (V + 5776)
+ 0x1101, 0x1163, 0x11a9, 0,
+#undef V1628
+#define V1628 (V + 5780)
+ 0x1101, 0x1163, 0x11aa, 0,
+#undef V1629
+#define V1629 (V + 5784)
+ 0x1101, 0x1163, 0x11ab, 0,
+#undef V1630
+#define V1630 (V + 5788)
+ 0x1101, 0x1163, 0x11ac, 0,
+#undef V1631
+#define V1631 (V + 5792)
+ 0x1101, 0x1163, 0x11ad, 0,
+#undef V1632
+#define V1632 (V + 5796)
+ 0x1101, 0x1163, 0x11ae, 0,
+#undef V1633
+#define V1633 (V + 5800)
+ 0x1101, 0x1163, 0x11af, 0,
+#undef V1634
+#define V1634 (V + 5804)
+ 0x1101, 0x1163, 0x11b0, 0,
+#undef V1635
+#define V1635 (V + 5808)
+ 0x1101, 0x1163, 0x11b1, 0,
+#undef V1636
+#define V1636 (V + 5812)
+ 0x1101, 0x1163, 0x11b2, 0,
+#undef V1637
+#define V1637 (V + 5816)
+ 0x1101, 0x1163, 0x11b3, 0,
+#undef V1638
+#define V1638 (V + 5820)
+ 0x1101, 0x1163, 0x11b4, 0,
+#undef V1639
+#define V1639 (V + 5824)
+ 0x1101, 0x1163, 0x11b5, 0,
+#undef V1640
+#define V1640 (V + 5828)
+ 0x1101, 0x1163, 0x11b6, 0,
+#undef V1641
+#define V1641 (V + 5832)
+ 0x1101, 0x1163, 0x11b7, 0,
+#undef V1642
+#define V1642 (V + 5836)
+ 0x1101, 0x1163, 0x11b8, 0,
+#undef V1643
+#define V1643 (V + 5840)
+ 0x1101, 0x1163, 0x11b9, 0,
+#undef V1644
+#define V1644 (V + 5844)
+ 0x1101, 0x1163, 0x11ba, 0,
+#undef V1645
+#define V1645 (V + 5848)
+ 0x1101, 0x1163, 0x11bb, 0,
+#undef V1646
+#define V1646 (V + 5852)
+ 0x1101, 0x1163, 0x11bc, 0,
+#undef V1647
+#define V1647 (V + 5856)
+ 0x1101, 0x1163, 0x11bd, 0,
+#undef V1648
+#define V1648 (V + 5860)
+ 0x1101, 0x1163, 0x11be, 0,
+#undef V1649
+#define V1649 (V + 5864)
+ 0x1101, 0x1163, 0x11bf, 0,
+#undef V1650
+#define V1650 (V + 5868)
+ 0x1101, 0x1163, 0x11c0, 0,
+#undef V1651
+#define V1651 (V + 5872)
+ 0x1101, 0x1163, 0x11c1, 0,
+#undef V1652
+#define V1652 (V + 5876)
+ 0x1101, 0x1163, 0x11c2, 0,
+#undef V1653
+#define V1653 (V + 5880)
+ 0x1101, 0x1164, 0,
+#undef V1654
+#define V1654 (V + 5883)
+ 0x1101, 0x1164, 0x11a8, 0,
+#undef V1655
+#define V1655 (V + 5887)
+ 0x1101, 0x1164, 0x11a9, 0,
+#undef V1656
+#define V1656 (V + 5891)
+ 0x1101, 0x1164, 0x11aa, 0,
+#undef V1657
+#define V1657 (V + 5895)
+ 0x1101, 0x1164, 0x11ab, 0,
+#undef V1658
+#define V1658 (V + 5899)
+ 0x1101, 0x1164, 0x11ac, 0,
+#undef V1659
+#define V1659 (V + 5903)
+ 0x1101, 0x1164, 0x11ad, 0,
+#undef V1660
+#define V1660 (V + 5907)
+ 0x1101, 0x1164, 0x11ae, 0,
+#undef V1661
+#define V1661 (V + 5911)
+ 0x1101, 0x1164, 0x11af, 0,
+#undef V1662
+#define V1662 (V + 5915)
+ 0x1101, 0x1164, 0x11b0, 0,
+#undef V1663
+#define V1663 (V + 5919)
+ 0x1101, 0x1164, 0x11b1, 0,
+#undef V1664
+#define V1664 (V + 5923)
+ 0x1101, 0x1164, 0x11b2, 0,
+#undef V1665
+#define V1665 (V + 5927)
+ 0x1101, 0x1164, 0x11b3, 0,
+#undef V1666
+#define V1666 (V + 5931)
+ 0x1101, 0x1164, 0x11b4, 0,
+#undef V1667
+#define V1667 (V + 5935)
+ 0x1101, 0x1164, 0x11b5, 0,
+#undef V1668
+#define V1668 (V + 5939)
+ 0x1101, 0x1164, 0x11b6, 0,
+#undef V1669
+#define V1669 (V + 5943)
+ 0x1101, 0x1164, 0x11b7, 0,
+#undef V1670
+#define V1670 (V + 5947)
+ 0x1101, 0x1164, 0x11b8, 0,
+#undef V1671
+#define V1671 (V + 5951)
+ 0x1101, 0x1164, 0x11b9, 0,
+#undef V1672
+#define V1672 (V + 5955)
+ 0x1101, 0x1164, 0x11ba, 0,
+#undef V1673
+#define V1673 (V + 5959)
+ 0x1101, 0x1164, 0x11bb, 0,
+#undef V1674
+#define V1674 (V + 5963)
+ 0x1101, 0x1164, 0x11bc, 0,
+#undef V1675
+#define V1675 (V + 5967)
+ 0x1101, 0x1164, 0x11bd, 0,
+#undef V1676
+#define V1676 (V + 5971)
+ 0x1101, 0x1164, 0x11be, 0,
+#undef V1677
+#define V1677 (V + 5975)
+ 0x1101, 0x1164, 0x11bf, 0,
+#undef V1678
+#define V1678 (V + 5979)
+ 0x1101, 0x1164, 0x11c0, 0,
+#undef V1679
+#define V1679 (V + 5983)
+ 0x1101, 0x1164, 0x11c1, 0,
+#undef V1680
+#define V1680 (V + 5987)
+ 0x1101, 0x1164, 0x11c2, 0,
+#undef V1681
+#define V1681 (V + 5991)
+ 0x1101, 0x1165, 0,
+#undef V1682
+#define V1682 (V + 5994)
+ 0x1101, 0x1165, 0x11a8, 0,
+#undef V1683
+#define V1683 (V + 5998)
+ 0x1101, 0x1165, 0x11a9, 0,
+#undef V1684
+#define V1684 (V + 6002)
+ 0x1101, 0x1165, 0x11aa, 0,
+#undef V1685
+#define V1685 (V + 6006)
+ 0x1101, 0x1165, 0x11ab, 0,
+#undef V1686
+#define V1686 (V + 6010)
+ 0x1101, 0x1165, 0x11ac, 0,
+#undef V1687
+#define V1687 (V + 6014)
+ 0x1101, 0x1165, 0x11ad, 0,
+#undef V1688
+#define V1688 (V + 6018)
+ 0x1101, 0x1165, 0x11ae, 0,
+#undef V1689
+#define V1689 (V + 6022)
+ 0x1101, 0x1165, 0x11af, 0,
+#undef V1690
+#define V1690 (V + 6026)
+ 0x1101, 0x1165, 0x11b0, 0,
+#undef V1691
+#define V1691 (V + 6030)
+ 0x1101, 0x1165, 0x11b1, 0,
+#undef V1692
+#define V1692 (V + 6034)
+ 0x1101, 0x1165, 0x11b2, 0,
+#undef V1693
+#define V1693 (V + 6038)
+ 0x1101, 0x1165, 0x11b3, 0,
+#undef V1694
+#define V1694 (V + 6042)
+ 0x1101, 0x1165, 0x11b4, 0,
+#undef V1695
+#define V1695 (V + 6046)
+ 0x1101, 0x1165, 0x11b5, 0,
+#undef V1696
+#define V1696 (V + 6050)
+ 0x1101, 0x1165, 0x11b6, 0,
+#undef V1697
+#define V1697 (V + 6054)
+ 0x1101, 0x1165, 0x11b7, 0,
+#undef V1698
+#define V1698 (V + 6058)
+ 0x1101, 0x1165, 0x11b8, 0,
+#undef V1699
+#define V1699 (V + 6062)
+ 0x1101, 0x1165, 0x11b9, 0,
+#undef V1700
+#define V1700 (V + 6066)
+ 0x1101, 0x1165, 0x11ba, 0,
+#undef V1701
+#define V1701 (V + 6070)
+ 0x1101, 0x1165, 0x11bb, 0,
+#undef V1702
+#define V1702 (V + 6074)
+ 0x1101, 0x1165, 0x11bc, 0,
+#undef V1703
+#define V1703 (V + 6078)
+ 0x1101, 0x1165, 0x11bd, 0,
+#undef V1704
+#define V1704 (V + 6082)
+ 0x1101, 0x1165, 0x11be, 0,
+#undef V1705
+#define V1705 (V + 6086)
+ 0x1101, 0x1165, 0x11bf, 0,
+#undef V1706
+#define V1706 (V + 6090)
+ 0x1101, 0x1165, 0x11c0, 0,
+#undef V1707
+#define V1707 (V + 6094)
+ 0x1101, 0x1165, 0x11c1, 0,
+#undef V1708
+#define V1708 (V + 6098)
+ 0x1101, 0x1165, 0x11c2, 0,
+#undef V1709
+#define V1709 (V + 6102)
+ 0x1101, 0x1166, 0,
+#undef V1710
+#define V1710 (V + 6105)
+ 0x1101, 0x1166, 0x11a8, 0,
+#undef V1711
+#define V1711 (V + 6109)
+ 0x1101, 0x1166, 0x11a9, 0,
+#undef V1712
+#define V1712 (V + 6113)
+ 0x1101, 0x1166, 0x11aa, 0,
+#undef V1713
+#define V1713 (V + 6117)
+ 0x1101, 0x1166, 0x11ab, 0,
+#undef V1714
+#define V1714 (V + 6121)
+ 0x1101, 0x1166, 0x11ac, 0,
+#undef V1715
+#define V1715 (V + 6125)
+ 0x1101, 0x1166, 0x11ad, 0,
+#undef V1716
+#define V1716 (V + 6129)
+ 0x1101, 0x1166, 0x11ae, 0,
+#undef V1717
+#define V1717 (V + 6133)
+ 0x1101, 0x1166, 0x11af, 0,
+#undef V1718
+#define V1718 (V + 6137)
+ 0x1101, 0x1166, 0x11b0, 0,
+#undef V1719
+#define V1719 (V + 6141)
+ 0x1101, 0x1166, 0x11b1, 0,
+#undef V1720
+#define V1720 (V + 6145)
+ 0x1101, 0x1166, 0x11b2, 0,
+#undef V1721
+#define V1721 (V + 6149)
+ 0x1101, 0x1166, 0x11b3, 0,
+#undef V1722
+#define V1722 (V + 6153)
+ 0x1101, 0x1166, 0x11b4, 0,
+#undef V1723
+#define V1723 (V + 6157)
+ 0x1101, 0x1166, 0x11b5, 0,
+#undef V1724
+#define V1724 (V + 6161)
+ 0x1101, 0x1166, 0x11b6, 0,
+#undef V1725
+#define V1725 (V + 6165)
+ 0x1101, 0x1166, 0x11b7, 0,
+#undef V1726
+#define V1726 (V + 6169)
+ 0x1101, 0x1166, 0x11b8, 0,
+#undef V1727
+#define V1727 (V + 6173)
+ 0x1101, 0x1166, 0x11b9, 0,
+#undef V1728
+#define V1728 (V + 6177)
+ 0x1101, 0x1166, 0x11ba, 0,
+#undef V1729
+#define V1729 (V + 6181)
+ 0x1101, 0x1166, 0x11bb, 0,
+#undef V1730
+#define V1730 (V + 6185)
+ 0x1101, 0x1166, 0x11bc, 0,
+#undef V1731
+#define V1731 (V + 6189)
+ 0x1101, 0x1166, 0x11bd, 0,
+#undef V1732
+#define V1732 (V + 6193)
+ 0x1101, 0x1166, 0x11be, 0,
+#undef V1733
+#define V1733 (V + 6197)
+ 0x1101, 0x1166, 0x11bf, 0,
+#undef V1734
+#define V1734 (V + 6201)
+ 0x1101, 0x1166, 0x11c0, 0,
+#undef V1735
+#define V1735 (V + 6205)
+ 0x1101, 0x1166, 0x11c1, 0,
+#undef V1736
+#define V1736 (V + 6209)
+ 0x1101, 0x1166, 0x11c2, 0,
+#undef V1737
+#define V1737 (V + 6213)
+ 0x1101, 0x1167, 0,
+#undef V1738
+#define V1738 (V + 6216)
+ 0x1101, 0x1167, 0x11a8, 0,
+#undef V1739
+#define V1739 (V + 6220)
+ 0x1101, 0x1167, 0x11a9, 0,
+#undef V1740
+#define V1740 (V + 6224)
+ 0x1101, 0x1167, 0x11aa, 0,
+#undef V1741
+#define V1741 (V + 6228)
+ 0x1101, 0x1167, 0x11ab, 0,
+#undef V1742
+#define V1742 (V + 6232)
+ 0x1101, 0x1167, 0x11ac, 0,
+#undef V1743
+#define V1743 (V + 6236)
+ 0x1101, 0x1167, 0x11ad, 0,
+#undef V1744
+#define V1744 (V + 6240)
+ 0x1101, 0x1167, 0x11ae, 0,
+#undef V1745
+#define V1745 (V + 6244)
+ 0x1101, 0x1167, 0x11af, 0,
+#undef V1746
+#define V1746 (V + 6248)
+ 0x1101, 0x1167, 0x11b0, 0,
+#undef V1747
+#define V1747 (V + 6252)
+ 0x1101, 0x1167, 0x11b1, 0,
+#undef V1748
+#define V1748 (V + 6256)
+ 0x1101, 0x1167, 0x11b2, 0,
+#undef V1749
+#define V1749 (V + 6260)
+ 0x1101, 0x1167, 0x11b3, 0,
+#undef V1750
+#define V1750 (V + 6264)
+ 0x1101, 0x1167, 0x11b4, 0,
+#undef V1751
+#define V1751 (V + 6268)
+ 0x1101, 0x1167, 0x11b5, 0,
+#undef V1752
+#define V1752 (V + 6272)
+ 0x1101, 0x1167, 0x11b6, 0,
+#undef V1753
+#define V1753 (V + 6276)
+ 0x1101, 0x1167, 0x11b7, 0,
+#undef V1754
+#define V1754 (V + 6280)
+ 0x1101, 0x1167, 0x11b8, 0,
+#undef V1755
+#define V1755 (V + 6284)
+ 0x1101, 0x1167, 0x11b9, 0,
+#undef V1756
+#define V1756 (V + 6288)
+ 0x1101, 0x1167, 0x11ba, 0,
+#undef V1757
+#define V1757 (V + 6292)
+ 0x1101, 0x1167, 0x11bb, 0,
+#undef V1758
+#define V1758 (V + 6296)
+ 0x1101, 0x1167, 0x11bc, 0,
+#undef V1759
+#define V1759 (V + 6300)
+ 0x1101, 0x1167, 0x11bd, 0,
+#undef V1760
+#define V1760 (V + 6304)
+ 0x1101, 0x1167, 0x11be, 0,
+#undef V1761
+#define V1761 (V + 6308)
+ 0x1101, 0x1167, 0x11bf, 0,
+#undef V1762
+#define V1762 (V + 6312)
+ 0x1101, 0x1167, 0x11c0, 0,
+#undef V1763
+#define V1763 (V + 6316)
+ 0x1101, 0x1167, 0x11c1, 0,
+#undef V1764
+#define V1764 (V + 6320)
+ 0x1101, 0x1167, 0x11c2, 0,
+#undef V1765
+#define V1765 (V + 6324)
+ 0x1101, 0x1168, 0,
+#undef V1766
+#define V1766 (V + 6327)
+ 0x1101, 0x1168, 0x11a8, 0,
+#undef V1767
+#define V1767 (V + 6331)
+ 0x1101, 0x1168, 0x11a9, 0,
+#undef V1768
+#define V1768 (V + 6335)
+ 0x1101, 0x1168, 0x11aa, 0,
+#undef V1769
+#define V1769 (V + 6339)
+ 0x1101, 0x1168, 0x11ab, 0,
+#undef V1770
+#define V1770 (V + 6343)
+ 0x1101, 0x1168, 0x11ac, 0,
+#undef V1771
+#define V1771 (V + 6347)
+ 0x1101, 0x1168, 0x11ad, 0,
+#undef V1772
+#define V1772 (V + 6351)
+ 0x1101, 0x1168, 0x11ae, 0,
+#undef V1773
+#define V1773 (V + 6355)
+ 0x1101, 0x1168, 0x11af, 0,
+#undef V1774
+#define V1774 (V + 6359)
+ 0x1101, 0x1168, 0x11b0, 0,
+#undef V1775
+#define V1775 (V + 6363)
+ 0x1101, 0x1168, 0x11b1, 0,
+#undef V1776
+#define V1776 (V + 6367)
+ 0x1101, 0x1168, 0x11b2, 0,
+#undef V1777
+#define V1777 (V + 6371)
+ 0x1101, 0x1168, 0x11b3, 0,
+#undef V1778
+#define V1778 (V + 6375)
+ 0x1101, 0x1168, 0x11b4, 0,
+#undef V1779
+#define V1779 (V + 6379)
+ 0x1101, 0x1168, 0x11b5, 0,
+#undef V1780
+#define V1780 (V + 6383)
+ 0x1101, 0x1168, 0x11b6, 0,
+#undef V1781
+#define V1781 (V + 6387)
+ 0x1101, 0x1168, 0x11b7, 0,
+#undef V1782
+#define V1782 (V + 6391)
+ 0x1101, 0x1168, 0x11b8, 0,
+#undef V1783
+#define V1783 (V + 6395)
+ 0x1101, 0x1168, 0x11b9, 0,
+#undef V1784
+#define V1784 (V + 6399)
+ 0x1101, 0x1168, 0x11ba, 0,
+#undef V1785
+#define V1785 (V + 6403)
+ 0x1101, 0x1168, 0x11bb, 0,
+#undef V1786
+#define V1786 (V + 6407)
+ 0x1101, 0x1168, 0x11bc, 0,
+#undef V1787
+#define V1787 (V + 6411)
+ 0x1101, 0x1168, 0x11bd, 0,
+#undef V1788
+#define V1788 (V + 6415)
+ 0x1101, 0x1168, 0x11be, 0,
+#undef V1789
+#define V1789 (V + 6419)
+ 0x1101, 0x1168, 0x11bf, 0,
+#undef V1790
+#define V1790 (V + 6423)
+ 0x1101, 0x1168, 0x11c0, 0,
+#undef V1791
+#define V1791 (V + 6427)
+ 0x1101, 0x1168, 0x11c1, 0,
+#undef V1792
+#define V1792 (V + 6431)
+ 0x1101, 0x1168, 0x11c2, 0,
+#undef V1793
+#define V1793 (V + 6435)
+ 0x1101, 0x1169, 0,
+#undef V1794
+#define V1794 (V + 6438)
+ 0x1101, 0x1169, 0x11a8, 0,
+#undef V1795
+#define V1795 (V + 6442)
+ 0x1101, 0x1169, 0x11a9, 0,
+#undef V1796
+#define V1796 (V + 6446)
+ 0x1101, 0x1169, 0x11aa, 0,
+#undef V1797
+#define V1797 (V + 6450)
+ 0x1101, 0x1169, 0x11ab, 0,
+#undef V1798
+#define V1798 (V + 6454)
+ 0x1101, 0x1169, 0x11ac, 0,
+#undef V1799
+#define V1799 (V + 6458)
+ 0x1101, 0x1169, 0x11ad, 0,
+#undef V1800
+#define V1800 (V + 6462)
+ 0x1101, 0x1169, 0x11ae, 0,
+#undef V1801
+#define V1801 (V + 6466)
+ 0x1101, 0x1169, 0x11af, 0,
+#undef V1802
+#define V1802 (V + 6470)
+ 0x1101, 0x1169, 0x11b0, 0,
+#undef V1803
+#define V1803 (V + 6474)
+ 0x1101, 0x1169, 0x11b1, 0,
+#undef V1804
+#define V1804 (V + 6478)
+ 0x1101, 0x1169, 0x11b2, 0,
+#undef V1805
+#define V1805 (V + 6482)
+ 0x1101, 0x1169, 0x11b3, 0,
+#undef V1806
+#define V1806 (V + 6486)
+ 0x1101, 0x1169, 0x11b4, 0,
+#undef V1807
+#define V1807 (V + 6490)
+ 0x1101, 0x1169, 0x11b5, 0,
+#undef V1808
+#define V1808 (V + 6494)
+ 0x1101, 0x1169, 0x11b6, 0,
+#undef V1809
+#define V1809 (V + 6498)
+ 0x1101, 0x1169, 0x11b7, 0,
+#undef V1810
+#define V1810 (V + 6502)
+ 0x1101, 0x1169, 0x11b8, 0,
+#undef V1811
+#define V1811 (V + 6506)
+ 0x1101, 0x1169, 0x11b9, 0,
+#undef V1812
+#define V1812 (V + 6510)
+ 0x1101, 0x1169, 0x11ba, 0,
+#undef V1813
+#define V1813 (V + 6514)
+ 0x1101, 0x1169, 0x11bb, 0,
+#undef V1814
+#define V1814 (V + 6518)
+ 0x1101, 0x1169, 0x11bc, 0,
+#undef V1815
+#define V1815 (V + 6522)
+ 0x1101, 0x1169, 0x11bd, 0,
+#undef V1816
+#define V1816 (V + 6526)
+ 0x1101, 0x1169, 0x11be, 0,
+#undef V1817
+#define V1817 (V + 6530)
+ 0x1101, 0x1169, 0x11bf, 0,
+#undef V1818
+#define V1818 (V + 6534)
+ 0x1101, 0x1169, 0x11c0, 0,
+#undef V1819
+#define V1819 (V + 6538)
+ 0x1101, 0x1169, 0x11c1, 0,
+#undef V1820
+#define V1820 (V + 6542)
+ 0x1101, 0x1169, 0x11c2, 0,
+#undef V1821
+#define V1821 (V + 6546)
+ 0x1101, 0x116a, 0,
+#undef V1822
+#define V1822 (V + 6549)
+ 0x1101, 0x116a, 0x11a8, 0,
+#undef V1823
+#define V1823 (V + 6553)
+ 0x1101, 0x116a, 0x11a9, 0,
+#undef V1824
+#define V1824 (V + 6557)
+ 0x1101, 0x116a, 0x11aa, 0,
+#undef V1825
+#define V1825 (V + 6561)
+ 0x1101, 0x116a, 0x11ab, 0,
+#undef V1826
+#define V1826 (V + 6565)
+ 0x1101, 0x116a, 0x11ac, 0,
+#undef V1827
+#define V1827 (V + 6569)
+ 0x1101, 0x116a, 0x11ad, 0,
+#undef V1828
+#define V1828 (V + 6573)
+ 0x1101, 0x116a, 0x11ae, 0,
+#undef V1829
+#define V1829 (V + 6577)
+ 0x1101, 0x116a, 0x11af, 0,
+#undef V1830
+#define V1830 (V + 6581)
+ 0x1101, 0x116a, 0x11b0, 0,
+#undef V1831
+#define V1831 (V + 6585)
+ 0x1101, 0x116a, 0x11b1, 0,
+#undef V1832
+#define V1832 (V + 6589)
+ 0x1101, 0x116a, 0x11b2, 0,
+#undef V1833
+#define V1833 (V + 6593)
+ 0x1101, 0x116a, 0x11b3, 0,
+#undef V1834
+#define V1834 (V + 6597)
+ 0x1101, 0x116a, 0x11b4, 0,
+#undef V1835
+#define V1835 (V + 6601)
+ 0x1101, 0x116a, 0x11b5, 0,
+#undef V1836
+#define V1836 (V + 6605)
+ 0x1101, 0x116a, 0x11b6, 0,
+#undef V1837
+#define V1837 (V + 6609)
+ 0x1101, 0x116a, 0x11b7, 0,
+#undef V1838
+#define V1838 (V + 6613)
+ 0x1101, 0x116a, 0x11b8, 0,
+#undef V1839
+#define V1839 (V + 6617)
+ 0x1101, 0x116a, 0x11b9, 0,
+#undef V1840
+#define V1840 (V + 6621)
+ 0x1101, 0x116a, 0x11ba, 0,
+#undef V1841
+#define V1841 (V + 6625)
+ 0x1101, 0x116a, 0x11bb, 0,
+#undef V1842
+#define V1842 (V + 6629)
+ 0x1101, 0x116a, 0x11bc, 0,
+#undef V1843
+#define V1843 (V + 6633)
+ 0x1101, 0x116a, 0x11bd, 0,
+#undef V1844
+#define V1844 (V + 6637)
+ 0x1101, 0x116a, 0x11be, 0,
+#undef V1845
+#define V1845 (V + 6641)
+ 0x1101, 0x116a, 0x11bf, 0,
+#undef V1846
+#define V1846 (V + 6645)
+ 0x1101, 0x116a, 0x11c0, 0,
+#undef V1847
+#define V1847 (V + 6649)
+ 0x1101, 0x116a, 0x11c1, 0,
+#undef V1848
+#define V1848 (V + 6653)
+ 0x1101, 0x116a, 0x11c2, 0,
+#undef V1849
+#define V1849 (V + 6657)
+ 0x1101, 0x116b, 0,
+#undef V1850
+#define V1850 (V + 6660)
+ 0x1101, 0x116b, 0x11a8, 0,
+#undef V1851
+#define V1851 (V + 6664)
+ 0x1101, 0x116b, 0x11a9, 0,
+#undef V1852
+#define V1852 (V + 6668)
+ 0x1101, 0x116b, 0x11aa, 0,
+#undef V1853
+#define V1853 (V + 6672)
+ 0x1101, 0x116b, 0x11ab, 0,
+#undef V1854
+#define V1854 (V + 6676)
+ 0x1101, 0x116b, 0x11ac, 0,
+#undef V1855
+#define V1855 (V + 6680)
+ 0x1101, 0x116b, 0x11ad, 0,
+#undef V1856
+#define V1856 (V + 6684)
+ 0x1101, 0x116b, 0x11ae, 0,
+#undef V1857
+#define V1857 (V + 6688)
+ 0x1101, 0x116b, 0x11af, 0,
+#undef V1858
+#define V1858 (V + 6692)
+ 0x1101, 0x116b, 0x11b0, 0,
+#undef V1859
+#define V1859 (V + 6696)
+ 0x1101, 0x116b, 0x11b1, 0,
+#undef V1860
+#define V1860 (V + 6700)
+ 0x1101, 0x116b, 0x11b2, 0,
+#undef V1861
+#define V1861 (V + 6704)
+ 0x1101, 0x116b, 0x11b3, 0,
+#undef V1862
+#define V1862 (V + 6708)
+ 0x1101, 0x116b, 0x11b4, 0,
+#undef V1863
+#define V1863 (V + 6712)
+ 0x1101, 0x116b, 0x11b5, 0,
+#undef V1864
+#define V1864 (V + 6716)
+ 0x1101, 0x116b, 0x11b6, 0,
+#undef V1865
+#define V1865 (V + 6720)
+ 0x1101, 0x116b, 0x11b7, 0,
+#undef V1866
+#define V1866 (V + 6724)
+ 0x1101, 0x116b, 0x11b8, 0,
+#undef V1867
+#define V1867 (V + 6728)
+ 0x1101, 0x116b, 0x11b9, 0,
+#undef V1868
+#define V1868 (V + 6732)
+ 0x1101, 0x116b, 0x11ba, 0,
+#undef V1869
+#define V1869 (V + 6736)
+ 0x1101, 0x116b, 0x11bb, 0,
+#undef V1870
+#define V1870 (V + 6740)
+ 0x1101, 0x116b, 0x11bc, 0,
+#undef V1871
+#define V1871 (V + 6744)
+ 0x1101, 0x116b, 0x11bd, 0,
+#undef V1872
+#define V1872 (V + 6748)
+ 0x1101, 0x116b, 0x11be, 0,
+#undef V1873
+#define V1873 (V + 6752)
+ 0x1101, 0x116b, 0x11bf, 0,
+#undef V1874
+#define V1874 (V + 6756)
+ 0x1101, 0x116b, 0x11c0, 0,
+#undef V1875
+#define V1875 (V + 6760)
+ 0x1101, 0x116b, 0x11c1, 0,
+#undef V1876
+#define V1876 (V + 6764)
+ 0x1101, 0x116b, 0x11c2, 0,
+#undef V1877
+#define V1877 (V + 6768)
+ 0x1101, 0x116c, 0,
+#undef V1878
+#define V1878 (V + 6771)
+ 0x1101, 0x116c, 0x11a8, 0,
+#undef V1879
+#define V1879 (V + 6775)
+ 0x1101, 0x116c, 0x11a9, 0,
+#undef V1880
+#define V1880 (V + 6779)
+ 0x1101, 0x116c, 0x11aa, 0,
+#undef V1881
+#define V1881 (V + 6783)
+ 0x1101, 0x116c, 0x11ab, 0,
+#undef V1882
+#define V1882 (V + 6787)
+ 0x1101, 0x116c, 0x11ac, 0,
+#undef V1883
+#define V1883 (V + 6791)
+ 0x1101, 0x116c, 0x11ad, 0,
+#undef V1884
+#define V1884 (V + 6795)
+ 0x1101, 0x116c, 0x11ae, 0,
+#undef V1885
+#define V1885 (V + 6799)
+ 0x1101, 0x116c, 0x11af, 0,
+#undef V1886
+#define V1886 (V + 6803)
+ 0x1101, 0x116c, 0x11b0, 0,
+#undef V1887
+#define V1887 (V + 6807)
+ 0x1101, 0x116c, 0x11b1, 0,
+#undef V1888
+#define V1888 (V + 6811)
+ 0x1101, 0x116c, 0x11b2, 0,
+#undef V1889
+#define V1889 (V + 6815)
+ 0x1101, 0x116c, 0x11b3, 0,
+#undef V1890
+#define V1890 (V + 6819)
+ 0x1101, 0x116c, 0x11b4, 0,
+#undef V1891
+#define V1891 (V + 6823)
+ 0x1101, 0x116c, 0x11b5, 0,
+#undef V1892
+#define V1892 (V + 6827)
+ 0x1101, 0x116c, 0x11b6, 0,
+#undef V1893
+#define V1893 (V + 6831)
+ 0x1101, 0x116c, 0x11b7, 0,
+#undef V1894
+#define V1894 (V + 6835)
+ 0x1101, 0x116c, 0x11b8, 0,
+#undef V1895
+#define V1895 (V + 6839)
+ 0x1101, 0x116c, 0x11b9, 0,
+#undef V1896
+#define V1896 (V + 6843)
+ 0x1101, 0x116c, 0x11ba, 0,
+#undef V1897
+#define V1897 (V + 6847)
+ 0x1101, 0x116c, 0x11bb, 0,
+#undef V1898
+#define V1898 (V + 6851)
+ 0x1101, 0x116c, 0x11bc, 0,
+#undef V1899
+#define V1899 (V + 6855)
+ 0x1101, 0x116c, 0x11bd, 0,
+#undef V1900
+#define V1900 (V + 6859)
+ 0x1101, 0x116c, 0x11be, 0,
+#undef V1901
+#define V1901 (V + 6863)
+ 0x1101, 0x116c, 0x11bf, 0,
+#undef V1902
+#define V1902 (V + 6867)
+ 0x1101, 0x116c, 0x11c0, 0,
+#undef V1903
+#define V1903 (V + 6871)
+ 0x1101, 0x116c, 0x11c1, 0,
+#undef V1904
+#define V1904 (V + 6875)
+ 0x1101, 0x116c, 0x11c2, 0,
+#undef V1905
+#define V1905 (V + 6879)
+ 0x1101, 0x116d, 0,
+#undef V1906
+#define V1906 (V + 6882)
+ 0x1101, 0x116d, 0x11a8, 0,
+#undef V1907
+#define V1907 (V + 6886)
+ 0x1101, 0x116d, 0x11a9, 0,
+#undef V1908
+#define V1908 (V + 6890)
+ 0x1101, 0x116d, 0x11aa, 0,
+#undef V1909
+#define V1909 (V + 6894)
+ 0x1101, 0x116d, 0x11ab, 0,
+#undef V1910
+#define V1910 (V + 6898)
+ 0x1101, 0x116d, 0x11ac, 0,
+#undef V1911
+#define V1911 (V + 6902)
+ 0x1101, 0x116d, 0x11ad, 0,
+#undef V1912
+#define V1912 (V + 6906)
+ 0x1101, 0x116d, 0x11ae, 0,
+#undef V1913
+#define V1913 (V + 6910)
+ 0x1101, 0x116d, 0x11af, 0,
+#undef V1914
+#define V1914 (V + 6914)
+ 0x1101, 0x116d, 0x11b0, 0,
+#undef V1915
+#define V1915 (V + 6918)
+ 0x1101, 0x116d, 0x11b1, 0,
+#undef V1916
+#define V1916 (V + 6922)
+ 0x1101, 0x116d, 0x11b2, 0,
+#undef V1917
+#define V1917 (V + 6926)
+ 0x1101, 0x116d, 0x11b3, 0,
+#undef V1918
+#define V1918 (V + 6930)
+ 0x1101, 0x116d, 0x11b4, 0,
+#undef V1919
+#define V1919 (V + 6934)
+ 0x1101, 0x116d, 0x11b5, 0,
+#undef V1920
+#define V1920 (V + 6938)
+ 0x1101, 0x116d, 0x11b6, 0,
+#undef V1921
+#define V1921 (V + 6942)
+ 0x1101, 0x116d, 0x11b7, 0,
+#undef V1922
+#define V1922 (V + 6946)
+ 0x1101, 0x116d, 0x11b8, 0,
+#undef V1923
+#define V1923 (V + 6950)
+ 0x1101, 0x116d, 0x11b9, 0,
+#undef V1924
+#define V1924 (V + 6954)
+ 0x1101, 0x116d, 0x11ba, 0,
+#undef V1925
+#define V1925 (V + 6958)
+ 0x1101, 0x116d, 0x11bb, 0,
+#undef V1926
+#define V1926 (V + 6962)
+ 0x1101, 0x116d, 0x11bc, 0,
+#undef V1927
+#define V1927 (V + 6966)
+ 0x1101, 0x116d, 0x11bd, 0,
+#undef V1928
+#define V1928 (V + 6970)
+ 0x1101, 0x116d, 0x11be, 0,
+#undef V1929
+#define V1929 (V + 6974)
+ 0x1101, 0x116d, 0x11bf, 0,
+#undef V1930
+#define V1930 (V + 6978)
+ 0x1101, 0x116d, 0x11c0, 0,
+#undef V1931
+#define V1931 (V + 6982)
+ 0x1101, 0x116d, 0x11c1, 0,
+#undef V1932
+#define V1932 (V + 6986)
+ 0x1101, 0x116d, 0x11c2, 0,
+#undef V1933
+#define V1933 (V + 6990)
+ 0x1101, 0x116e, 0,
+#undef V1934
+#define V1934 (V + 6993)
+ 0x1101, 0x116e, 0x11a8, 0,
+#undef V1935
+#define V1935 (V + 6997)
+ 0x1101, 0x116e, 0x11a9, 0,
+#undef V1936
+#define V1936 (V + 7001)
+ 0x1101, 0x116e, 0x11aa, 0,
+#undef V1937
+#define V1937 (V + 7005)
+ 0x1101, 0x116e, 0x11ab, 0,
+#undef V1938
+#define V1938 (V + 7009)
+ 0x1101, 0x116e, 0x11ac, 0,
+#undef V1939
+#define V1939 (V + 7013)
+ 0x1101, 0x116e, 0x11ad, 0,
+#undef V1940
+#define V1940 (V + 7017)
+ 0x1101, 0x116e, 0x11ae, 0,
+#undef V1941
+#define V1941 (V + 7021)
+ 0x1101, 0x116e, 0x11af, 0,
+#undef V1942
+#define V1942 (V + 7025)
+ 0x1101, 0x116e, 0x11b0, 0,
+#undef V1943
+#define V1943 (V + 7029)
+ 0x1101, 0x116e, 0x11b1, 0,
+#undef V1944
+#define V1944 (V + 7033)
+ 0x1101, 0x116e, 0x11b2, 0,
+#undef V1945
+#define V1945 (V + 7037)
+ 0x1101, 0x116e, 0x11b3, 0,
+#undef V1946
+#define V1946 (V + 7041)
+ 0x1101, 0x116e, 0x11b4, 0,
+#undef V1947
+#define V1947 (V + 7045)
+ 0x1101, 0x116e, 0x11b5, 0,
+#undef V1948
+#define V1948 (V + 7049)
+ 0x1101, 0x116e, 0x11b6, 0,
+#undef V1949
+#define V1949 (V + 7053)
+ 0x1101, 0x116e, 0x11b7, 0,
+#undef V1950
+#define V1950 (V + 7057)
+ 0x1101, 0x116e, 0x11b8, 0,
+#undef V1951
+#define V1951 (V + 7061)
+ 0x1101, 0x116e, 0x11b9, 0,
+#undef V1952
+#define V1952 (V + 7065)
+ 0x1101, 0x116e, 0x11ba, 0,
+#undef V1953
+#define V1953 (V + 7069)
+ 0x1101, 0x116e, 0x11bb, 0,
+#undef V1954
+#define V1954 (V + 7073)
+ 0x1101, 0x116e, 0x11bc, 0,
+#undef V1955
+#define V1955 (V + 7077)
+ 0x1101, 0x116e, 0x11bd, 0,
+#undef V1956
+#define V1956 (V + 7081)
+ 0x1101, 0x116e, 0x11be, 0,
+#undef V1957
+#define V1957 (V + 7085)
+ 0x1101, 0x116e, 0x11bf, 0,
+#undef V1958
+#define V1958 (V + 7089)
+ 0x1101, 0x116e, 0x11c0, 0,
+#undef V1959
+#define V1959 (V + 7093)
+ 0x1101, 0x116e, 0x11c1, 0,
+#undef V1960
+#define V1960 (V + 7097)
+ 0x1101, 0x116e, 0x11c2, 0,
+#undef V1961
+#define V1961 (V + 7101)
+ 0x1101, 0x116f, 0,
+#undef V1962
+#define V1962 (V + 7104)
+ 0x1101, 0x116f, 0x11a8, 0,
+#undef V1963
+#define V1963 (V + 7108)
+ 0x1101, 0x116f, 0x11a9, 0,
+#undef V1964
+#define V1964 (V + 7112)
+ 0x1101, 0x116f, 0x11aa, 0,
+#undef V1965
+#define V1965 (V + 7116)
+ 0x1101, 0x116f, 0x11ab, 0,
+#undef V1966
+#define V1966 (V + 7120)
+ 0x1101, 0x116f, 0x11ac, 0,
+#undef V1967
+#define V1967 (V + 7124)
+ 0x1101, 0x116f, 0x11ad, 0,
+#undef V1968
+#define V1968 (V + 7128)
+ 0x1101, 0x116f, 0x11ae, 0,
+#undef V1969
+#define V1969 (V + 7132)
+ 0x1101, 0x116f, 0x11af, 0,
+#undef V1970
+#define V1970 (V + 7136)
+ 0x1101, 0x116f, 0x11b0, 0,
+#undef V1971
+#define V1971 (V + 7140)
+ 0x1101, 0x116f, 0x11b1, 0,
+#undef V1972
+#define V1972 (V + 7144)
+ 0x1101, 0x116f, 0x11b2, 0,
+#undef V1973
+#define V1973 (V + 7148)
+ 0x1101, 0x116f, 0x11b3, 0,
+#undef V1974
+#define V1974 (V + 7152)
+ 0x1101, 0x116f, 0x11b4, 0,
+#undef V1975
+#define V1975 (V + 7156)
+ 0x1101, 0x116f, 0x11b5, 0,
+#undef V1976
+#define V1976 (V + 7160)
+ 0x1101, 0x116f, 0x11b6, 0,
+#undef V1977
+#define V1977 (V + 7164)
+ 0x1101, 0x116f, 0x11b7, 0,
+#undef V1978
+#define V1978 (V + 7168)
+ 0x1101, 0x116f, 0x11b8, 0,
+#undef V1979
+#define V1979 (V + 7172)
+ 0x1101, 0x116f, 0x11b9, 0,
+#undef V1980
+#define V1980 (V + 7176)
+ 0x1101, 0x116f, 0x11ba, 0,
+#undef V1981
+#define V1981 (V + 7180)
+ 0x1101, 0x116f, 0x11bb, 0,
+#undef V1982
+#define V1982 (V + 7184)
+ 0x1101, 0x116f, 0x11bc, 0,
+#undef V1983
+#define V1983 (V + 7188)
+ 0x1101, 0x116f, 0x11bd, 0,
+#undef V1984
+#define V1984 (V + 7192)
+ 0x1101, 0x116f, 0x11be, 0,
+#undef V1985
+#define V1985 (V + 7196)
+ 0x1101, 0x116f, 0x11bf, 0,
+#undef V1986
+#define V1986 (V + 7200)
+ 0x1101, 0x116f, 0x11c0, 0,
+#undef V1987
+#define V1987 (V + 7204)
+ 0x1101, 0x116f, 0x11c1, 0,
+#undef V1988
+#define V1988 (V + 7208)
+ 0x1101, 0x116f, 0x11c2, 0,
+#undef V1989
+#define V1989 (V + 7212)
+ 0x1101, 0x1170, 0,
+#undef V1990
+#define V1990 (V + 7215)
+ 0x1101, 0x1170, 0x11a8, 0,
+#undef V1991
+#define V1991 (V + 7219)
+ 0x1101, 0x1170, 0x11a9, 0,
+#undef V1992
+#define V1992 (V + 7223)
+ 0x1101, 0x1170, 0x11aa, 0,
+#undef V1993
+#define V1993 (V + 7227)
+ 0x1101, 0x1170, 0x11ab, 0,
+#undef V1994
+#define V1994 (V + 7231)
+ 0x1101, 0x1170, 0x11ac, 0,
+#undef V1995
+#define V1995 (V + 7235)
+ 0x1101, 0x1170, 0x11ad, 0,
+#undef V1996
+#define V1996 (V + 7239)
+ 0x1101, 0x1170, 0x11ae, 0,
+#undef V1997
+#define V1997 (V + 7243)
+ 0x1101, 0x1170, 0x11af, 0,
+#undef V1998
+#define V1998 (V + 7247)
+ 0x1101, 0x1170, 0x11b0, 0,
+#undef V1999
+#define V1999 (V + 7251)
+ 0x1101, 0x1170, 0x11b1, 0,
+#undef V2000
+#define V2000 (V + 7255)
+ 0x1101, 0x1170, 0x11b2, 0,
+#undef V2001
+#define V2001 (V + 7259)
+ 0x1101, 0x1170, 0x11b3, 0,
+#undef V2002
+#define V2002 (V + 7263)
+ 0x1101, 0x1170, 0x11b4, 0,
+#undef V2003
+#define V2003 (V + 7267)
+ 0x1101, 0x1170, 0x11b5, 0,
+#undef V2004
+#define V2004 (V + 7271)
+ 0x1101, 0x1170, 0x11b6, 0,
+#undef V2005
+#define V2005 (V + 7275)
+ 0x1101, 0x1170, 0x11b7, 0,
+#undef V2006
+#define V2006 (V + 7279)
+ 0x1101, 0x1170, 0x11b8, 0,
+#undef V2007
+#define V2007 (V + 7283)
+ 0x1101, 0x1170, 0x11b9, 0,
+#undef V2008
+#define V2008 (V + 7287)
+ 0x1101, 0x1170, 0x11ba, 0,
+#undef V2009
+#define V2009 (V + 7291)
+ 0x1101, 0x1170, 0x11bb, 0,
+#undef V2010
+#define V2010 (V + 7295)
+ 0x1101, 0x1170, 0x11bc, 0,
+#undef V2011
+#define V2011 (V + 7299)
+ 0x1101, 0x1170, 0x11bd, 0,
+#undef V2012
+#define V2012 (V + 7303)
+ 0x1101, 0x1170, 0x11be, 0,
+#undef V2013
+#define V2013 (V + 7307)
+ 0x1101, 0x1170, 0x11bf, 0,
+#undef V2014
+#define V2014 (V + 7311)
+ 0x1101, 0x1170, 0x11c0, 0,
+#undef V2015
+#define V2015 (V + 7315)
+ 0x1101, 0x1170, 0x11c1, 0,
+#undef V2016
+#define V2016 (V + 7319)
+ 0x1101, 0x1170, 0x11c2, 0,
+#undef V2017
+#define V2017 (V + 7323)
+ 0x1101, 0x1171, 0,
+#undef V2018
+#define V2018 (V + 7326)
+ 0x1101, 0x1171, 0x11a8, 0,
+#undef V2019
+#define V2019 (V + 7330)
+ 0x1101, 0x1171, 0x11a9, 0,
+#undef V2020
+#define V2020 (V + 7334)
+ 0x1101, 0x1171, 0x11aa, 0,
+#undef V2021
+#define V2021 (V + 7338)
+ 0x1101, 0x1171, 0x11ab, 0,
+#undef V2022
+#define V2022 (V + 7342)
+ 0x1101, 0x1171, 0x11ac, 0,
+#undef V2023
+#define V2023 (V + 7346)
+ 0x1101, 0x1171, 0x11ad, 0,
+#undef V2024
+#define V2024 (V + 7350)
+ 0x1101, 0x1171, 0x11ae, 0,
+#undef V2025
+#define V2025 (V + 7354)
+ 0x1101, 0x1171, 0x11af, 0,
+#undef V2026
+#define V2026 (V + 7358)
+ 0x1101, 0x1171, 0x11b0, 0,
+#undef V2027
+#define V2027 (V + 7362)
+ 0x1101, 0x1171, 0x11b1, 0,
+#undef V2028
+#define V2028 (V + 7366)
+ 0x1101, 0x1171, 0x11b2, 0,
+#undef V2029
+#define V2029 (V + 7370)
+ 0x1101, 0x1171, 0x11b3, 0,
+#undef V2030
+#define V2030 (V + 7374)
+ 0x1101, 0x1171, 0x11b4, 0,
+#undef V2031
+#define V2031 (V + 7378)
+ 0x1101, 0x1171, 0x11b5, 0,
+#undef V2032
+#define V2032 (V + 7382)
+ 0x1101, 0x1171, 0x11b6, 0,
+#undef V2033
+#define V2033 (V + 7386)
+ 0x1101, 0x1171, 0x11b7, 0,
+#undef V2034
+#define V2034 (V + 7390)
+ 0x1101, 0x1171, 0x11b8, 0,
+#undef V2035
+#define V2035 (V + 7394)
+ 0x1101, 0x1171, 0x11b9, 0,
+#undef V2036
+#define V2036 (V + 7398)
+ 0x1101, 0x1171, 0x11ba, 0,
+#undef V2037
+#define V2037 (V + 7402)
+ 0x1101, 0x1171, 0x11bb, 0,
+#undef V2038
+#define V2038 (V + 7406)
+ 0x1101, 0x1171, 0x11bc, 0,
+#undef V2039
+#define V2039 (V + 7410)
+ 0x1101, 0x1171, 0x11bd, 0,
+#undef V2040
+#define V2040 (V + 7414)
+ 0x1101, 0x1171, 0x11be, 0,
+#undef V2041
+#define V2041 (V + 7418)
+ 0x1101, 0x1171, 0x11bf, 0,
+#undef V2042
+#define V2042 (V + 7422)
+ 0x1101, 0x1171, 0x11c0, 0,
+#undef V2043
+#define V2043 (V + 7426)
+ 0x1101, 0x1171, 0x11c1, 0,
+#undef V2044
+#define V2044 (V + 7430)
+ 0x1101, 0x1171, 0x11c2, 0,
+#undef V2045
+#define V2045 (V + 7434)
+ 0x1101, 0x1172, 0,
+#undef V2046
+#define V2046 (V + 7437)
+ 0x1101, 0x1172, 0x11a8, 0,
+#undef V2047
+#define V2047 (V + 7441)
+ 0x1101, 0x1172, 0x11a9, 0,
+#undef V2048
+#define V2048 (V + 7445)
+ 0x1101, 0x1172, 0x11aa, 0,
+#undef V2049
+#define V2049 (V + 7449)
+ 0x1101, 0x1172, 0x11ab, 0,
+#undef V2050
+#define V2050 (V + 7453)
+ 0x1101, 0x1172, 0x11ac, 0,
+#undef V2051
+#define V2051 (V + 7457)
+ 0x1101, 0x1172, 0x11ad, 0,
+#undef V2052
+#define V2052 (V + 7461)
+ 0x1101, 0x1172, 0x11ae, 0,
+#undef V2053
+#define V2053 (V + 7465)
+ 0x1101, 0x1172, 0x11af, 0,
+#undef V2054
+#define V2054 (V + 7469)
+ 0x1101, 0x1172, 0x11b0, 0,
+#undef V2055
+#define V2055 (V + 7473)
+ 0x1101, 0x1172, 0x11b1, 0,
+#undef V2056
+#define V2056 (V + 7477)
+ 0x1101, 0x1172, 0x11b2, 0,
+#undef V2057
+#define V2057 (V + 7481)
+ 0x1101, 0x1172, 0x11b3, 0,
+#undef V2058
+#define V2058 (V + 7485)
+ 0x1101, 0x1172, 0x11b4, 0,
+#undef V2059
+#define V2059 (V + 7489)
+ 0x1101, 0x1172, 0x11b5, 0,
+#undef V2060
+#define V2060 (V + 7493)
+ 0x1101, 0x1172, 0x11b6, 0,
+#undef V2061
+#define V2061 (V + 7497)
+ 0x1101, 0x1172, 0x11b7, 0,
+#undef V2062
+#define V2062 (V + 7501)
+ 0x1101, 0x1172, 0x11b8, 0,
+#undef V2063
+#define V2063 (V + 7505)
+ 0x1101, 0x1172, 0x11b9, 0,
+#undef V2064
+#define V2064 (V + 7509)
+ 0x1101, 0x1172, 0x11ba, 0,
+#undef V2065
+#define V2065 (V + 7513)
+ 0x1101, 0x1172, 0x11bb, 0,
+#undef V2066
+#define V2066 (V + 7517)
+ 0x1101, 0x1172, 0x11bc, 0,
+#undef V2067
+#define V2067 (V + 7521)
+ 0x1101, 0x1172, 0x11bd, 0,
+#undef V2068
+#define V2068 (V + 7525)
+ 0x1101, 0x1172, 0x11be, 0,
+#undef V2069
+#define V2069 (V + 7529)
+ 0x1101, 0x1172, 0x11bf, 0,
+#undef V2070
+#define V2070 (V + 7533)
+ 0x1101, 0x1172, 0x11c0, 0,
+#undef V2071
+#define V2071 (V + 7537)
+ 0x1101, 0x1172, 0x11c1, 0,
+#undef V2072
+#define V2072 (V + 7541)
+ 0x1101, 0x1172, 0x11c2, 0,
+#undef V2073
+#define V2073 (V + 7545)
+ 0x1101, 0x1173, 0,
+#undef V2074
+#define V2074 (V + 7548)
+ 0x1101, 0x1173, 0x11a8, 0,
+#undef V2075
+#define V2075 (V + 7552)
+ 0x1101, 0x1173, 0x11a9, 0,
+#undef V2076
+#define V2076 (V + 7556)
+ 0x1101, 0x1173, 0x11aa, 0,
+#undef V2077
+#define V2077 (V + 7560)
+ 0x1101, 0x1173, 0x11ab, 0,
+#undef V2078
+#define V2078 (V + 7564)
+ 0x1101, 0x1173, 0x11ac, 0,
+#undef V2079
+#define V2079 (V + 7568)
+ 0x1101, 0x1173, 0x11ad, 0,
+#undef V2080
+#define V2080 (V + 7572)
+ 0x1101, 0x1173, 0x11ae, 0,
+#undef V2081
+#define V2081 (V + 7576)
+ 0x1101, 0x1173, 0x11af, 0,
+#undef V2082
+#define V2082 (V + 7580)
+ 0x1101, 0x1173, 0x11b0, 0,
+#undef V2083
+#define V2083 (V + 7584)
+ 0x1101, 0x1173, 0x11b1, 0,
+#undef V2084
+#define V2084 (V + 7588)
+ 0x1101, 0x1173, 0x11b2, 0,
+#undef V2085
+#define V2085 (V + 7592)
+ 0x1101, 0x1173, 0x11b3, 0,
+#undef V2086
+#define V2086 (V + 7596)
+ 0x1101, 0x1173, 0x11b4, 0,
+#undef V2087
+#define V2087 (V + 7600)
+ 0x1101, 0x1173, 0x11b5, 0,
+#undef V2088
+#define V2088 (V + 7604)
+ 0x1101, 0x1173, 0x11b6, 0,
+#undef V2089
+#define V2089 (V + 7608)
+ 0x1101, 0x1173, 0x11b7, 0,
+#undef V2090
+#define V2090 (V + 7612)
+ 0x1101, 0x1173, 0x11b8, 0,
+#undef V2091
+#define V2091 (V + 7616)
+ 0x1101, 0x1173, 0x11b9, 0,
+#undef V2092
+#define V2092 (V + 7620)
+ 0x1101, 0x1173, 0x11ba, 0,
+#undef V2093
+#define V2093 (V + 7624)
+ 0x1101, 0x1173, 0x11bb, 0,
+#undef V2094
+#define V2094 (V + 7628)
+ 0x1101, 0x1173, 0x11bc, 0,
+#undef V2095
+#define V2095 (V + 7632)
+ 0x1101, 0x1173, 0x11bd, 0,
+#undef V2096
+#define V2096 (V + 7636)
+ 0x1101, 0x1173, 0x11be, 0,
+#undef V2097
+#define V2097 (V + 7640)
+ 0x1101, 0x1173, 0x11bf, 0,
+#undef V2098
+#define V2098 (V + 7644)
+ 0x1101, 0x1173, 0x11c0, 0,
+#undef V2099
+#define V2099 (V + 7648)
+ 0x1101, 0x1173, 0x11c1, 0,
+#undef V2100
+#define V2100 (V + 7652)
+ 0x1101, 0x1173, 0x11c2, 0,
+#undef V2101
+#define V2101 (V + 7656)
+ 0x1101, 0x1174, 0,
+#undef V2102
+#define V2102 (V + 7659)
+ 0x1101, 0x1174, 0x11a8, 0,
+#undef V2103
+#define V2103 (V + 7663)
+ 0x1101, 0x1174, 0x11a9, 0,
+#undef V2104
+#define V2104 (V + 7667)
+ 0x1101, 0x1174, 0x11aa, 0,
+#undef V2105
+#define V2105 (V + 7671)
+ 0x1101, 0x1174, 0x11ab, 0,
+#undef V2106
+#define V2106 (V + 7675)
+ 0x1101, 0x1174, 0x11ac, 0,
+#undef V2107
+#define V2107 (V + 7679)
+ 0x1101, 0x1174, 0x11ad, 0,
+#undef V2108
+#define V2108 (V + 7683)
+ 0x1101, 0x1174, 0x11ae, 0,
+#undef V2109
+#define V2109 (V + 7687)
+ 0x1101, 0x1174, 0x11af, 0,
+#undef V2110
+#define V2110 (V + 7691)
+ 0x1101, 0x1174, 0x11b0, 0,
+#undef V2111
+#define V2111 (V + 7695)
+ 0x1101, 0x1174, 0x11b1, 0,
+#undef V2112
+#define V2112 (V + 7699)
+ 0x1101, 0x1174, 0x11b2, 0,
+#undef V2113
+#define V2113 (V + 7703)
+ 0x1101, 0x1174, 0x11b3, 0,
+#undef V2114
+#define V2114 (V + 7707)
+ 0x1101, 0x1174, 0x11b4, 0,
+#undef V2115
+#define V2115 (V + 7711)
+ 0x1101, 0x1174, 0x11b5, 0,
+#undef V2116
+#define V2116 (V + 7715)
+ 0x1101, 0x1174, 0x11b6, 0,
+#undef V2117
+#define V2117 (V + 7719)
+ 0x1101, 0x1174, 0x11b7, 0,
+#undef V2118
+#define V2118 (V + 7723)
+ 0x1101, 0x1174, 0x11b8, 0,
+#undef V2119
+#define V2119 (V + 7727)
+ 0x1101, 0x1174, 0x11b9, 0,
+#undef V2120
+#define V2120 (V + 7731)
+ 0x1101, 0x1174, 0x11ba, 0,
+#undef V2121
+#define V2121 (V + 7735)
+ 0x1101, 0x1174, 0x11bb, 0,
+#undef V2122
+#define V2122 (V + 7739)
+ 0x1101, 0x1174, 0x11bc, 0,
+#undef V2123
+#define V2123 (V + 7743)
+ 0x1101, 0x1174, 0x11bd, 0,
+#undef V2124
+#define V2124 (V + 7747)
+ 0x1101, 0x1174, 0x11be, 0,
+#undef V2125
+#define V2125 (V + 7751)
+ 0x1101, 0x1174, 0x11bf, 0,
+#undef V2126
+#define V2126 (V + 7755)
+ 0x1101, 0x1174, 0x11c0, 0,
+#undef V2127
+#define V2127 (V + 7759)
+ 0x1101, 0x1174, 0x11c1, 0,
+#undef V2128
+#define V2128 (V + 7763)
+ 0x1101, 0x1174, 0x11c2, 0,
+#undef V2129
+#define V2129 (V + 7767)
+ 0x1101, 0x1175, 0,
+#undef V2130
+#define V2130 (V + 7770)
+ 0x1101, 0x1175, 0x11a8, 0,
+#undef V2131
+#define V2131 (V + 7774)
+ 0x1101, 0x1175, 0x11a9, 0,
+#undef V2132
+#define V2132 (V + 7778)
+ 0x1101, 0x1175, 0x11aa, 0,
+#undef V2133
+#define V2133 (V + 7782)
+ 0x1101, 0x1175, 0x11ab, 0,
+#undef V2134
+#define V2134 (V + 7786)
+ 0x1101, 0x1175, 0x11ac, 0,
+#undef V2135
+#define V2135 (V + 7790)
+ 0x1101, 0x1175, 0x11ad, 0,
+#undef V2136
+#define V2136 (V + 7794)
+ 0x1101, 0x1175, 0x11ae, 0,
+#undef V2137
+#define V2137 (V + 7798)
+ 0x1101, 0x1175, 0x11af, 0,
+#undef V2138
+#define V2138 (V + 7802)
+ 0x1101, 0x1175, 0x11b0, 0,
+#undef V2139
+#define V2139 (V + 7806)
+ 0x1101, 0x1175, 0x11b1, 0,
+#undef V2140
+#define V2140 (V + 7810)
+ 0x1101, 0x1175, 0x11b2, 0,
+#undef V2141
+#define V2141 (V + 7814)
+ 0x1101, 0x1175, 0x11b3, 0,
+#undef V2142
+#define V2142 (V + 7818)
+ 0x1101, 0x1175, 0x11b4, 0,
+#undef V2143
+#define V2143 (V + 7822)
+ 0x1101, 0x1175, 0x11b5, 0,
+#undef V2144
+#define V2144 (V + 7826)
+ 0x1101, 0x1175, 0x11b6, 0,
+#undef V2145
+#define V2145 (V + 7830)
+ 0x1101, 0x1175, 0x11b7, 0,
+#undef V2146
+#define V2146 (V + 7834)
+ 0x1101, 0x1175, 0x11b8, 0,
+#undef V2147
+#define V2147 (V + 7838)
+ 0x1101, 0x1175, 0x11b9, 0,
+#undef V2148
+#define V2148 (V + 7842)
+ 0x1101, 0x1175, 0x11ba, 0,
+#undef V2149
+#define V2149 (V + 7846)
+ 0x1101, 0x1175, 0x11bb, 0,
+#undef V2150
+#define V2150 (V + 7850)
+ 0x1101, 0x1175, 0x11bc, 0,
+#undef V2151
+#define V2151 (V + 7854)
+ 0x1101, 0x1175, 0x11bd, 0,
+#undef V2152
+#define V2152 (V + 7858)
+ 0x1101, 0x1175, 0x11be, 0,
+#undef V2153
+#define V2153 (V + 7862)
+ 0x1101, 0x1175, 0x11bf, 0,
+#undef V2154
+#define V2154 (V + 7866)
+ 0x1101, 0x1175, 0x11c0, 0,
+#undef V2155
+#define V2155 (V + 7870)
+ 0x1101, 0x1175, 0x11c1, 0,
+#undef V2156
+#define V2156 (V + 7874)
+ 0x1101, 0x1175, 0x11c2, 0,
+#undef V2157
+#define V2157 (V + 7878)
+ 0x1102, 0x1161, 0,
+#undef V2158
+#define V2158 (V + 7881)
+ 0x1102, 0x1161, 0x11a8, 0,
+#undef V2159
+#define V2159 (V + 7885)
+ 0x1102, 0x1161, 0x11a9, 0,
+#undef V2160
+#define V2160 (V + 7889)
+ 0x1102, 0x1161, 0x11aa, 0,
+#undef V2161
+#define V2161 (V + 7893)
+ 0x1102, 0x1161, 0x11ab, 0,
+#undef V2162
+#define V2162 (V + 7897)
+ 0x1102, 0x1161, 0x11ac, 0,
+#undef V2163
+#define V2163 (V + 7901)
+ 0x1102, 0x1161, 0x11ad, 0,
+#undef V2164
+#define V2164 (V + 7905)
+ 0x1102, 0x1161, 0x11ae, 0,
+#undef V2165
+#define V2165 (V + 7909)
+ 0x1102, 0x1161, 0x11af, 0,
+#undef V2166
+#define V2166 (V + 7913)
+ 0x1102, 0x1161, 0x11b0, 0,
+#undef V2167
+#define V2167 (V + 7917)
+ 0x1102, 0x1161, 0x11b1, 0,
+#undef V2168
+#define V2168 (V + 7921)
+ 0x1102, 0x1161, 0x11b2, 0,
+#undef V2169
+#define V2169 (V + 7925)
+ 0x1102, 0x1161, 0x11b3, 0,
+#undef V2170
+#define V2170 (V + 7929)
+ 0x1102, 0x1161, 0x11b4, 0,
+#undef V2171
+#define V2171 (V + 7933)
+ 0x1102, 0x1161, 0x11b5, 0,
+#undef V2172
+#define V2172 (V + 7937)
+ 0x1102, 0x1161, 0x11b6, 0,
+#undef V2173
+#define V2173 (V + 7941)
+ 0x1102, 0x1161, 0x11b7, 0,
+#undef V2174
+#define V2174 (V + 7945)
+ 0x1102, 0x1161, 0x11b8, 0,
+#undef V2175
+#define V2175 (V + 7949)
+ 0x1102, 0x1161, 0x11b9, 0,
+#undef V2176
+#define V2176 (V + 7953)
+ 0x1102, 0x1161, 0x11ba, 0,
+#undef V2177
+#define V2177 (V + 7957)
+ 0x1102, 0x1161, 0x11bb, 0,
+#undef V2178
+#define V2178 (V + 7961)
+ 0x1102, 0x1161, 0x11bc, 0,
+#undef V2179
+#define V2179 (V + 7965)
+ 0x1102, 0x1161, 0x11bd, 0,
+#undef V2180
+#define V2180 (V + 7969)
+ 0x1102, 0x1161, 0x11be, 0,
+#undef V2181
+#define V2181 (V + 7973)
+ 0x1102, 0x1161, 0x11bf, 0,
+#undef V2182
+#define V2182 (V + 7977)
+ 0x1102, 0x1161, 0x11c0, 0,
+#undef V2183
+#define V2183 (V + 7981)
+ 0x1102, 0x1161, 0x11c1, 0,
+#undef V2184
+#define V2184 (V + 7985)
+ 0x1102, 0x1161, 0x11c2, 0,
+#undef V2185
+#define V2185 (V + 7989)
+ 0x1102, 0x1162, 0,
+#undef V2186
+#define V2186 (V + 7992)
+ 0x1102, 0x1162, 0x11a8, 0,
+#undef V2187
+#define V2187 (V + 7996)
+ 0x1102, 0x1162, 0x11a9, 0,
+#undef V2188
+#define V2188 (V + 8000)
+ 0x1102, 0x1162, 0x11aa, 0,
+#undef V2189
+#define V2189 (V + 8004)
+ 0x1102, 0x1162, 0x11ab, 0,
+#undef V2190
+#define V2190 (V + 8008)
+ 0x1102, 0x1162, 0x11ac, 0,
+#undef V2191
+#define V2191 (V + 8012)
+ 0x1102, 0x1162, 0x11ad, 0,
+#undef V2192
+#define V2192 (V + 8016)
+ 0x1102, 0x1162, 0x11ae, 0,
+#undef V2193
+#define V2193 (V + 8020)
+ 0x1102, 0x1162, 0x11af, 0,
+#undef V2194
+#define V2194 (V + 8024)
+ 0x1102, 0x1162, 0x11b0, 0,
+#undef V2195
+#define V2195 (V + 8028)
+ 0x1102, 0x1162, 0x11b1, 0,
+#undef V2196
+#define V2196 (V + 8032)
+ 0x1102, 0x1162, 0x11b2, 0,
+#undef V2197
+#define V2197 (V + 8036)
+ 0x1102, 0x1162, 0x11b3, 0,
+#undef V2198
+#define V2198 (V + 8040)
+ 0x1102, 0x1162, 0x11b4, 0,
+#undef V2199
+#define V2199 (V + 8044)
+ 0x1102, 0x1162, 0x11b5, 0,
+#undef V2200
+#define V2200 (V + 8048)
+ 0x1102, 0x1162, 0x11b6, 0,
+#undef V2201
+#define V2201 (V + 8052)
+ 0x1102, 0x1162, 0x11b7, 0,
+#undef V2202
+#define V2202 (V + 8056)
+ 0x1102, 0x1162, 0x11b8, 0,
+#undef V2203
+#define V2203 (V + 8060)
+ 0x1102, 0x1162, 0x11b9, 0,
+#undef V2204
+#define V2204 (V + 8064)
+ 0x1102, 0x1162, 0x11ba, 0,
+#undef V2205
+#define V2205 (V + 8068)
+ 0x1102, 0x1162, 0x11bb, 0,
+#undef V2206
+#define V2206 (V + 8072)
+ 0x1102, 0x1162, 0x11bc, 0,
+#undef V2207
+#define V2207 (V + 8076)
+ 0x1102, 0x1162, 0x11bd, 0,
+#undef V2208
+#define V2208 (V + 8080)
+ 0x1102, 0x1162, 0x11be, 0,
+#undef V2209
+#define V2209 (V + 8084)
+ 0x1102, 0x1162, 0x11bf, 0,
+#undef V2210
+#define V2210 (V + 8088)
+ 0x1102, 0x1162, 0x11c0, 0,
+#undef V2211
+#define V2211 (V + 8092)
+ 0x1102, 0x1162, 0x11c1, 0,
+#undef V2212
+#define V2212 (V + 8096)
+ 0x1102, 0x1162, 0x11c2, 0,
+#undef V2213
+#define V2213 (V + 8100)
+ 0x1102, 0x1163, 0,
+#undef V2214
+#define V2214 (V + 8103)
+ 0x1102, 0x1163, 0x11a8, 0,
+#undef V2215
+#define V2215 (V + 8107)
+ 0x1102, 0x1163, 0x11a9, 0,
+#undef V2216
+#define V2216 (V + 8111)
+ 0x1102, 0x1163, 0x11aa, 0,
+#undef V2217
+#define V2217 (V + 8115)
+ 0x1102, 0x1163, 0x11ab, 0,
+#undef V2218
+#define V2218 (V + 8119)
+ 0x1102, 0x1163, 0x11ac, 0,
+#undef V2219
+#define V2219 (V + 8123)
+ 0x1102, 0x1163, 0x11ad, 0,
+#undef V2220
+#define V2220 (V + 8127)
+ 0x1102, 0x1163, 0x11ae, 0,
+#undef V2221
+#define V2221 (V + 8131)
+ 0x1102, 0x1163, 0x11af, 0,
+#undef V2222
+#define V2222 (V + 8135)
+ 0x1102, 0x1163, 0x11b0, 0,
+#undef V2223
+#define V2223 (V + 8139)
+ 0x1102, 0x1163, 0x11b1, 0,
+#undef V2224
+#define V2224 (V + 8143)
+ 0x1102, 0x1163, 0x11b2, 0,
+#undef V2225
+#define V2225 (V + 8147)
+ 0x1102, 0x1163, 0x11b3, 0,
+#undef V2226
+#define V2226 (V + 8151)
+ 0x1102, 0x1163, 0x11b4, 0,
+#undef V2227
+#define V2227 (V + 8155)
+ 0x1102, 0x1163, 0x11b5, 0,
+#undef V2228
+#define V2228 (V + 8159)
+ 0x1102, 0x1163, 0x11b6, 0,
+#undef V2229
+#define V2229 (V + 8163)
+ 0x1102, 0x1163, 0x11b7, 0,
+#undef V2230
+#define V2230 (V + 8167)
+ 0x1102, 0x1163, 0x11b8, 0,
+#undef V2231
+#define V2231 (V + 8171)
+ 0x1102, 0x1163, 0x11b9, 0,
+#undef V2232
+#define V2232 (V + 8175)
+ 0x1102, 0x1163, 0x11ba, 0,
+#undef V2233
+#define V2233 (V + 8179)
+ 0x1102, 0x1163, 0x11bb, 0,
+#undef V2234
+#define V2234 (V + 8183)
+ 0x1102, 0x1163, 0x11bc, 0,
+#undef V2235
+#define V2235 (V + 8187)
+ 0x1102, 0x1163, 0x11bd, 0,
+#undef V2236
+#define V2236 (V + 8191)
+ 0x1102, 0x1163, 0x11be, 0,
+#undef V2237
+#define V2237 (V + 8195)
+ 0x1102, 0x1163, 0x11bf, 0,
+#undef V2238
+#define V2238 (V + 8199)
+ 0x1102, 0x1163, 0x11c0, 0,
+#undef V2239
+#define V2239 (V + 8203)
+ 0x1102, 0x1163, 0x11c1, 0,
+#undef V2240
+#define V2240 (V + 8207)
+ 0x1102, 0x1163, 0x11c2, 0,
+#undef V2241
+#define V2241 (V + 8211)
+ 0x1102, 0x1164, 0,
+#undef V2242
+#define V2242 (V + 8214)
+ 0x1102, 0x1164, 0x11a8, 0,
+#undef V2243
+#define V2243 (V + 8218)
+ 0x1102, 0x1164, 0x11a9, 0,
+#undef V2244
+#define V2244 (V + 8222)
+ 0x1102, 0x1164, 0x11aa, 0,
+#undef V2245
+#define V2245 (V + 8226)
+ 0x1102, 0x1164, 0x11ab, 0,
+#undef V2246
+#define V2246 (V + 8230)
+ 0x1102, 0x1164, 0x11ac, 0,
+#undef V2247
+#define V2247 (V + 8234)
+ 0x1102, 0x1164, 0x11ad, 0,
+#undef V2248
+#define V2248 (V + 8238)
+ 0x1102, 0x1164, 0x11ae, 0,
+#undef V2249
+#define V2249 (V + 8242)
+ 0x1102, 0x1164, 0x11af, 0,
+#undef V2250
+#define V2250 (V + 8246)
+ 0x1102, 0x1164, 0x11b0, 0,
+#undef V2251
+#define V2251 (V + 8250)
+ 0x1102, 0x1164, 0x11b1, 0,
+#undef V2252
+#define V2252 (V + 8254)
+ 0x1102, 0x1164, 0x11b2, 0,
+#undef V2253
+#define V2253 (V + 8258)
+ 0x1102, 0x1164, 0x11b3, 0,
+#undef V2254
+#define V2254 (V + 8262)
+ 0x1102, 0x1164, 0x11b4, 0,
+#undef V2255
+#define V2255 (V + 8266)
+ 0x1102, 0x1164, 0x11b5, 0,
+#undef V2256
+#define V2256 (V + 8270)
+ 0x1102, 0x1164, 0x11b6, 0,
+#undef V2257
+#define V2257 (V + 8274)
+ 0x1102, 0x1164, 0x11b7, 0,
+#undef V2258
+#define V2258 (V + 8278)
+ 0x1102, 0x1164, 0x11b8, 0,
+#undef V2259
+#define V2259 (V + 8282)
+ 0x1102, 0x1164, 0x11b9, 0,
+#undef V2260
+#define V2260 (V + 8286)
+ 0x1102, 0x1164, 0x11ba, 0,
+#undef V2261
+#define V2261 (V + 8290)
+ 0x1102, 0x1164, 0x11bb, 0,
+#undef V2262
+#define V2262 (V + 8294)
+ 0x1102, 0x1164, 0x11bc, 0,
+#undef V2263
+#define V2263 (V + 8298)
+ 0x1102, 0x1164, 0x11bd, 0,
+#undef V2264
+#define V2264 (V + 8302)
+ 0x1102, 0x1164, 0x11be, 0,
+#undef V2265
+#define V2265 (V + 8306)
+ 0x1102, 0x1164, 0x11bf, 0,
+#undef V2266
+#define V2266 (V + 8310)
+ 0x1102, 0x1164, 0x11c0, 0,
+#undef V2267
+#define V2267 (V + 8314)
+ 0x1102, 0x1164, 0x11c1, 0,
+#undef V2268
+#define V2268 (V + 8318)
+ 0x1102, 0x1164, 0x11c2, 0,
+#undef V2269
+#define V2269 (V + 8322)
+ 0x1102, 0x1165, 0,
+#undef V2270
+#define V2270 (V + 8325)
+ 0x1102, 0x1165, 0x11a8, 0,
+#undef V2271
+#define V2271 (V + 8329)
+ 0x1102, 0x1165, 0x11a9, 0,
+#undef V2272
+#define V2272 (V + 8333)
+ 0x1102, 0x1165, 0x11aa, 0,
+#undef V2273
+#define V2273 (V + 8337)
+ 0x1102, 0x1165, 0x11ab, 0,
+#undef V2274
+#define V2274 (V + 8341)
+ 0x1102, 0x1165, 0x11ac, 0,
+#undef V2275
+#define V2275 (V + 8345)
+ 0x1102, 0x1165, 0x11ad, 0,
+#undef V2276
+#define V2276 (V + 8349)
+ 0x1102, 0x1165, 0x11ae, 0,
+#undef V2277
+#define V2277 (V + 8353)
+ 0x1102, 0x1165, 0x11af, 0,
+#undef V2278
+#define V2278 (V + 8357)
+ 0x1102, 0x1165, 0x11b0, 0,
+#undef V2279
+#define V2279 (V + 8361)
+ 0x1102, 0x1165, 0x11b1, 0,
+#undef V2280
+#define V2280 (V + 8365)
+ 0x1102, 0x1165, 0x11b2, 0,
+#undef V2281
+#define V2281 (V + 8369)
+ 0x1102, 0x1165, 0x11b3, 0,
+#undef V2282
+#define V2282 (V + 8373)
+ 0x1102, 0x1165, 0x11b4, 0,
+#undef V2283
+#define V2283 (V + 8377)
+ 0x1102, 0x1165, 0x11b5, 0,
+#undef V2284
+#define V2284 (V + 8381)
+ 0x1102, 0x1165, 0x11b6, 0,
+#undef V2285
+#define V2285 (V + 8385)
+ 0x1102, 0x1165, 0x11b7, 0,
+#undef V2286
+#define V2286 (V + 8389)
+ 0x1102, 0x1165, 0x11b8, 0,
+#undef V2287
+#define V2287 (V + 8393)
+ 0x1102, 0x1165, 0x11b9, 0,
+#undef V2288
+#define V2288 (V + 8397)
+ 0x1102, 0x1165, 0x11ba, 0,
+#undef V2289
+#define V2289 (V + 8401)
+ 0x1102, 0x1165, 0x11bb, 0,
+#undef V2290
+#define V2290 (V + 8405)
+ 0x1102, 0x1165, 0x11bc, 0,
+#undef V2291
+#define V2291 (V + 8409)
+ 0x1102, 0x1165, 0x11bd, 0,
+#undef V2292
+#define V2292 (V + 8413)
+ 0x1102, 0x1165, 0x11be, 0,
+#undef V2293
+#define V2293 (V + 8417)
+ 0x1102, 0x1165, 0x11bf, 0,
+#undef V2294
+#define V2294 (V + 8421)
+ 0x1102, 0x1165, 0x11c0, 0,
+#undef V2295
+#define V2295 (V + 8425)
+ 0x1102, 0x1165, 0x11c1, 0,
+#undef V2296
+#define V2296 (V + 8429)
+ 0x1102, 0x1165, 0x11c2, 0,
+#undef V2297
+#define V2297 (V + 8433)
+ 0x1102, 0x1166, 0,
+#undef V2298
+#define V2298 (V + 8436)
+ 0x1102, 0x1166, 0x11a8, 0,
+#undef V2299
+#define V2299 (V + 8440)
+ 0x1102, 0x1166, 0x11a9, 0,
+#undef V2300
+#define V2300 (V + 8444)
+ 0x1102, 0x1166, 0x11aa, 0,
+#undef V2301
+#define V2301 (V + 8448)
+ 0x1102, 0x1166, 0x11ab, 0,
+#undef V2302
+#define V2302 (V + 8452)
+ 0x1102, 0x1166, 0x11ac, 0,
+#undef V2303
+#define V2303 (V + 8456)
+ 0x1102, 0x1166, 0x11ad, 0,
+#undef V2304
+#define V2304 (V + 8460)
+ 0x1102, 0x1166, 0x11ae, 0,
+#undef V2305
+#define V2305 (V + 8464)
+ 0x1102, 0x1166, 0x11af, 0,
+#undef V2306
+#define V2306 (V + 8468)
+ 0x1102, 0x1166, 0x11b0, 0,
+#undef V2307
+#define V2307 (V + 8472)
+ 0x1102, 0x1166, 0x11b1, 0,
+#undef V2308
+#define V2308 (V + 8476)
+ 0x1102, 0x1166, 0x11b2, 0,
+#undef V2309
+#define V2309 (V + 8480)
+ 0x1102, 0x1166, 0x11b3, 0,
+#undef V2310
+#define V2310 (V + 8484)
+ 0x1102, 0x1166, 0x11b4, 0,
+#undef V2311
+#define V2311 (V + 8488)
+ 0x1102, 0x1166, 0x11b5, 0,
+#undef V2312
+#define V2312 (V + 8492)
+ 0x1102, 0x1166, 0x11b6, 0,
+#undef V2313
+#define V2313 (V + 8496)
+ 0x1102, 0x1166, 0x11b7, 0,
+#undef V2314
+#define V2314 (V + 8500)
+ 0x1102, 0x1166, 0x11b8, 0,
+#undef V2315
+#define V2315 (V + 8504)
+ 0x1102, 0x1166, 0x11b9, 0,
+#undef V2316
+#define V2316 (V + 8508)
+ 0x1102, 0x1166, 0x11ba, 0,
+#undef V2317
+#define V2317 (V + 8512)
+ 0x1102, 0x1166, 0x11bb, 0,
+#undef V2318
+#define V2318 (V + 8516)
+ 0x1102, 0x1166, 0x11bc, 0,
+#undef V2319
+#define V2319 (V + 8520)
+ 0x1102, 0x1166, 0x11bd, 0,
+#undef V2320
+#define V2320 (V + 8524)
+ 0x1102, 0x1166, 0x11be, 0,
+#undef V2321
+#define V2321 (V + 8528)
+ 0x1102, 0x1166, 0x11bf, 0,
+#undef V2322
+#define V2322 (V + 8532)
+ 0x1102, 0x1166, 0x11c0, 0,
+#undef V2323
+#define V2323 (V + 8536)
+ 0x1102, 0x1166, 0x11c1, 0,
+#undef V2324
+#define V2324 (V + 8540)
+ 0x1102, 0x1166, 0x11c2, 0,
+#undef V2325
+#define V2325 (V + 8544)
+ 0x1102, 0x1167, 0,
+#undef V2326
+#define V2326 (V + 8547)
+ 0x1102, 0x1167, 0x11a8, 0,
+#undef V2327
+#define V2327 (V + 8551)
+ 0x1102, 0x1167, 0x11a9, 0,
+#undef V2328
+#define V2328 (V + 8555)
+ 0x1102, 0x1167, 0x11aa, 0,
+#undef V2329
+#define V2329 (V + 8559)
+ 0x1102, 0x1167, 0x11ab, 0,
+#undef V2330
+#define V2330 (V + 8563)
+ 0x1102, 0x1167, 0x11ac, 0,
+#undef V2331
+#define V2331 (V + 8567)
+ 0x1102, 0x1167, 0x11ad, 0,
+#undef V2332
+#define V2332 (V + 8571)
+ 0x1102, 0x1167, 0x11ae, 0,
+#undef V2333
+#define V2333 (V + 8575)
+ 0x1102, 0x1167, 0x11af, 0,
+#undef V2334
+#define V2334 (V + 8579)
+ 0x1102, 0x1167, 0x11b0, 0,
+#undef V2335
+#define V2335 (V + 8583)
+ 0x1102, 0x1167, 0x11b1, 0,
+#undef V2336
+#define V2336 (V + 8587)
+ 0x1102, 0x1167, 0x11b2, 0,
+#undef V2337
+#define V2337 (V + 8591)
+ 0x1102, 0x1167, 0x11b3, 0,
+#undef V2338
+#define V2338 (V + 8595)
+ 0x1102, 0x1167, 0x11b4, 0,
+#undef V2339
+#define V2339 (V + 8599)
+ 0x1102, 0x1167, 0x11b5, 0,
+#undef V2340
+#define V2340 (V + 8603)
+ 0x1102, 0x1167, 0x11b6, 0,
+#undef V2341
+#define V2341 (V + 8607)
+ 0x1102, 0x1167, 0x11b7, 0,
+#undef V2342
+#define V2342 (V + 8611)
+ 0x1102, 0x1167, 0x11b8, 0,
+#undef V2343
+#define V2343 (V + 8615)
+ 0x1102, 0x1167, 0x11b9, 0,
+#undef V2344
+#define V2344 (V + 8619)
+ 0x1102, 0x1167, 0x11ba, 0,
+#undef V2345
+#define V2345 (V + 8623)
+ 0x1102, 0x1167, 0x11bb, 0,
+#undef V2346
+#define V2346 (V + 8627)
+ 0x1102, 0x1167, 0x11bc, 0,
+#undef V2347
+#define V2347 (V + 8631)
+ 0x1102, 0x1167, 0x11bd, 0,
+#undef V2348
+#define V2348 (V + 8635)
+ 0x1102, 0x1167, 0x11be, 0,
+#undef V2349
+#define V2349 (V + 8639)
+ 0x1102, 0x1167, 0x11bf, 0,
+#undef V2350
+#define V2350 (V + 8643)
+ 0x1102, 0x1167, 0x11c0, 0,
+#undef V2351
+#define V2351 (V + 8647)
+ 0x1102, 0x1167, 0x11c1, 0,
+#undef V2352
+#define V2352 (V + 8651)
+ 0x1102, 0x1167, 0x11c2, 0,
+#undef V2353
+#define V2353 (V + 8655)
+ 0x1102, 0x1168, 0,
+#undef V2354
+#define V2354 (V + 8658)
+ 0x1102, 0x1168, 0x11a8, 0,
+#undef V2355
+#define V2355 (V + 8662)
+ 0x1102, 0x1168, 0x11a9, 0,
+#undef V2356
+#define V2356 (V + 8666)
+ 0x1102, 0x1168, 0x11aa, 0,
+#undef V2357
+#define V2357 (V + 8670)
+ 0x1102, 0x1168, 0x11ab, 0,
+#undef V2358
+#define V2358 (V + 8674)
+ 0x1102, 0x1168, 0x11ac, 0,
+#undef V2359
+#define V2359 (V + 8678)
+ 0x1102, 0x1168, 0x11ad, 0,
+#undef V2360
+#define V2360 (V + 8682)
+ 0x1102, 0x1168, 0x11ae, 0,
+#undef V2361
+#define V2361 (V + 8686)
+ 0x1102, 0x1168, 0x11af, 0,
+#undef V2362
+#define V2362 (V + 8690)
+ 0x1102, 0x1168, 0x11b0, 0,
+#undef V2363
+#define V2363 (V + 8694)
+ 0x1102, 0x1168, 0x11b1, 0,
+#undef V2364
+#define V2364 (V + 8698)
+ 0x1102, 0x1168, 0x11b2, 0,
+#undef V2365
+#define V2365 (V + 8702)
+ 0x1102, 0x1168, 0x11b3, 0,
+#undef V2366
+#define V2366 (V + 8706)
+ 0x1102, 0x1168, 0x11b4, 0,
+#undef V2367
+#define V2367 (V + 8710)
+ 0x1102, 0x1168, 0x11b5, 0,
+#undef V2368
+#define V2368 (V + 8714)
+ 0x1102, 0x1168, 0x11b6, 0,
+#undef V2369
+#define V2369 (V + 8718)
+ 0x1102, 0x1168, 0x11b7, 0,
+#undef V2370
+#define V2370 (V + 8722)
+ 0x1102, 0x1168, 0x11b8, 0,
+#undef V2371
+#define V2371 (V + 8726)
+ 0x1102, 0x1168, 0x11b9, 0,
+#undef V2372
+#define V2372 (V + 8730)
+ 0x1102, 0x1168, 0x11ba, 0,
+#undef V2373
+#define V2373 (V + 8734)
+ 0x1102, 0x1168, 0x11bb, 0,
+#undef V2374
+#define V2374 (V + 8738)
+ 0x1102, 0x1168, 0x11bc, 0,
+#undef V2375
+#define V2375 (V + 8742)
+ 0x1102, 0x1168, 0x11bd, 0,
+#undef V2376
+#define V2376 (V + 8746)
+ 0x1102, 0x1168, 0x11be, 0,
+#undef V2377
+#define V2377 (V + 8750)
+ 0x1102, 0x1168, 0x11bf, 0,
+#undef V2378
+#define V2378 (V + 8754)
+ 0x1102, 0x1168, 0x11c0, 0,
+#undef V2379
+#define V2379 (V + 8758)
+ 0x1102, 0x1168, 0x11c1, 0,
+#undef V2380
+#define V2380 (V + 8762)
+ 0x1102, 0x1168, 0x11c2, 0,
+#undef V2381
+#define V2381 (V + 8766)
+ 0x1102, 0x1169, 0,
+#undef V2382
+#define V2382 (V + 8769)
+ 0x1102, 0x1169, 0x11a8, 0,
+#undef V2383
+#define V2383 (V + 8773)
+ 0x1102, 0x1169, 0x11a9, 0,
+#undef V2384
+#define V2384 (V + 8777)
+ 0x1102, 0x1169, 0x11aa, 0,
+#undef V2385
+#define V2385 (V + 8781)
+ 0x1102, 0x1169, 0x11ab, 0,
+#undef V2386
+#define V2386 (V + 8785)
+ 0x1102, 0x1169, 0x11ac, 0,
+#undef V2387
+#define V2387 (V + 8789)
+ 0x1102, 0x1169, 0x11ad, 0,
+#undef V2388
+#define V2388 (V + 8793)
+ 0x1102, 0x1169, 0x11ae, 0,
+#undef V2389
+#define V2389 (V + 8797)
+ 0x1102, 0x1169, 0x11af, 0,
+#undef V2390
+#define V2390 (V + 8801)
+ 0x1102, 0x1169, 0x11b0, 0,
+#undef V2391
+#define V2391 (V + 8805)
+ 0x1102, 0x1169, 0x11b1, 0,
+#undef V2392
+#define V2392 (V + 8809)
+ 0x1102, 0x1169, 0x11b2, 0,
+#undef V2393
+#define V2393 (V + 8813)
+ 0x1102, 0x1169, 0x11b3, 0,
+#undef V2394
+#define V2394 (V + 8817)
+ 0x1102, 0x1169, 0x11b4, 0,
+#undef V2395
+#define V2395 (V + 8821)
+ 0x1102, 0x1169, 0x11b5, 0,
+#undef V2396
+#define V2396 (V + 8825)
+ 0x1102, 0x1169, 0x11b6, 0,
+#undef V2397
+#define V2397 (V + 8829)
+ 0x1102, 0x1169, 0x11b7, 0,
+#undef V2398
+#define V2398 (V + 8833)
+ 0x1102, 0x1169, 0x11b8, 0,
+#undef V2399
+#define V2399 (V + 8837)
+ 0x1102, 0x1169, 0x11b9, 0,
+#undef V2400
+#define V2400 (V + 8841)
+ 0x1102, 0x1169, 0x11ba, 0,
+#undef V2401
+#define V2401 (V + 8845)
+ 0x1102, 0x1169, 0x11bb, 0,
+#undef V2402
+#define V2402 (V + 8849)
+ 0x1102, 0x1169, 0x11bc, 0,
+#undef V2403
+#define V2403 (V + 8853)
+ 0x1102, 0x1169, 0x11bd, 0,
+#undef V2404
+#define V2404 (V + 8857)
+ 0x1102, 0x1169, 0x11be, 0,
+#undef V2405
+#define V2405 (V + 8861)
+ 0x1102, 0x1169, 0x11bf, 0,
+#undef V2406
+#define V2406 (V + 8865)
+ 0x1102, 0x1169, 0x11c0, 0,
+#undef V2407
+#define V2407 (V + 8869)
+ 0x1102, 0x1169, 0x11c1, 0,
+#undef V2408
+#define V2408 (V + 8873)
+ 0x1102, 0x1169, 0x11c2, 0,
+#undef V2409
+#define V2409 (V + 8877)
+ 0x1102, 0x116a, 0,
+#undef V2410
+#define V2410 (V + 8880)
+ 0x1102, 0x116a, 0x11a8, 0,
+#undef V2411
+#define V2411 (V + 8884)
+ 0x1102, 0x116a, 0x11a9, 0,
+#undef V2412
+#define V2412 (V + 8888)
+ 0x1102, 0x116a, 0x11aa, 0,
+#undef V2413
+#define V2413 (V + 8892)
+ 0x1102, 0x116a, 0x11ab, 0,
+#undef V2414
+#define V2414 (V + 8896)
+ 0x1102, 0x116a, 0x11ac, 0,
+#undef V2415
+#define V2415 (V + 8900)
+ 0x1102, 0x116a, 0x11ad, 0,
+#undef V2416
+#define V2416 (V + 8904)
+ 0x1102, 0x116a, 0x11ae, 0,
+#undef V2417
+#define V2417 (V + 8908)
+ 0x1102, 0x116a, 0x11af, 0,
+#undef V2418
+#define V2418 (V + 8912)
+ 0x1102, 0x116a, 0x11b0, 0,
+#undef V2419
+#define V2419 (V + 8916)
+ 0x1102, 0x116a, 0x11b1, 0,
+#undef V2420
+#define V2420 (V + 8920)
+ 0x1102, 0x116a, 0x11b2, 0,
+#undef V2421
+#define V2421 (V + 8924)
+ 0x1102, 0x116a, 0x11b3, 0,
+#undef V2422
+#define V2422 (V + 8928)
+ 0x1102, 0x116a, 0x11b4, 0,
+#undef V2423
+#define V2423 (V + 8932)
+ 0x1102, 0x116a, 0x11b5, 0,
+#undef V2424
+#define V2424 (V + 8936)
+ 0x1102, 0x116a, 0x11b6, 0,
+#undef V2425
+#define V2425 (V + 8940)
+ 0x1102, 0x116a, 0x11b7, 0,
+#undef V2426
+#define V2426 (V + 8944)
+ 0x1102, 0x116a, 0x11b8, 0,
+#undef V2427
+#define V2427 (V + 8948)
+ 0x1102, 0x116a, 0x11b9, 0,
+#undef V2428
+#define V2428 (V + 8952)
+ 0x1102, 0x116a, 0x11ba, 0,
+#undef V2429
+#define V2429 (V + 8956)
+ 0x1102, 0x116a, 0x11bb, 0,
+#undef V2430
+#define V2430 (V + 8960)
+ 0x1102, 0x116a, 0x11bc, 0,
+#undef V2431
+#define V2431 (V + 8964)
+ 0x1102, 0x116a, 0x11bd, 0,
+#undef V2432
+#define V2432 (V + 8968)
+ 0x1102, 0x116a, 0x11be, 0,
+#undef V2433
+#define V2433 (V + 8972)
+ 0x1102, 0x116a, 0x11bf, 0,
+#undef V2434
+#define V2434 (V + 8976)
+ 0x1102, 0x116a, 0x11c0, 0,
+#undef V2435
+#define V2435 (V + 8980)
+ 0x1102, 0x116a, 0x11c1, 0,
+#undef V2436
+#define V2436 (V + 8984)
+ 0x1102, 0x116a, 0x11c2, 0,
+#undef V2437
+#define V2437 (V + 8988)
+ 0x1102, 0x116b, 0,
+#undef V2438
+#define V2438 (V + 8991)
+ 0x1102, 0x116b, 0x11a8, 0,
+#undef V2439
+#define V2439 (V + 8995)
+ 0x1102, 0x116b, 0x11a9, 0,
+#undef V2440
+#define V2440 (V + 8999)
+ 0x1102, 0x116b, 0x11aa, 0,
+#undef V2441
+#define V2441 (V + 9003)
+ 0x1102, 0x116b, 0x11ab, 0,
+#undef V2442
+#define V2442 (V + 9007)
+ 0x1102, 0x116b, 0x11ac, 0,
+#undef V2443
+#define V2443 (V + 9011)
+ 0x1102, 0x116b, 0x11ad, 0,
+#undef V2444
+#define V2444 (V + 9015)
+ 0x1102, 0x116b, 0x11ae, 0,
+#undef V2445
+#define V2445 (V + 9019)
+ 0x1102, 0x116b, 0x11af, 0,
+#undef V2446
+#define V2446 (V + 9023)
+ 0x1102, 0x116b, 0x11b0, 0,
+#undef V2447
+#define V2447 (V + 9027)
+ 0x1102, 0x116b, 0x11b1, 0,
+#undef V2448
+#define V2448 (V + 9031)
+ 0x1102, 0x116b, 0x11b2, 0,
+#undef V2449
+#define V2449 (V + 9035)
+ 0x1102, 0x116b, 0x11b3, 0,
+#undef V2450
+#define V2450 (V + 9039)
+ 0x1102, 0x116b, 0x11b4, 0,
+#undef V2451
+#define V2451 (V + 9043)
+ 0x1102, 0x116b, 0x11b5, 0,
+#undef V2452
+#define V2452 (V + 9047)
+ 0x1102, 0x116b, 0x11b6, 0,
+#undef V2453
+#define V2453 (V + 9051)
+ 0x1102, 0x116b, 0x11b7, 0,
+#undef V2454
+#define V2454 (V + 9055)
+ 0x1102, 0x116b, 0x11b8, 0,
+#undef V2455
+#define V2455 (V + 9059)
+ 0x1102, 0x116b, 0x11b9, 0,
+#undef V2456
+#define V2456 (V + 9063)
+ 0x1102, 0x116b, 0x11ba, 0,
+#undef V2457
+#define V2457 (V + 9067)
+ 0x1102, 0x116b, 0x11bb, 0,
+#undef V2458
+#define V2458 (V + 9071)
+ 0x1102, 0x116b, 0x11bc, 0,
+#undef V2459
+#define V2459 (V + 9075)
+ 0x1102, 0x116b, 0x11bd, 0,
+#undef V2460
+#define V2460 (V + 9079)
+ 0x1102, 0x116b, 0x11be, 0,
+#undef V2461
+#define V2461 (V + 9083)
+ 0x1102, 0x116b, 0x11bf, 0,
+#undef V2462
+#define V2462 (V + 9087)
+ 0x1102, 0x116b, 0x11c0, 0,
+#undef V2463
+#define V2463 (V + 9091)
+ 0x1102, 0x116b, 0x11c1, 0,
+#undef V2464
+#define V2464 (V + 9095)
+ 0x1102, 0x116b, 0x11c2, 0,
+#undef V2465
+#define V2465 (V + 9099)
+ 0x1102, 0x116c, 0,
+#undef V2466
+#define V2466 (V + 9102)
+ 0x1102, 0x116c, 0x11a8, 0,
+#undef V2467
+#define V2467 (V + 9106)
+ 0x1102, 0x116c, 0x11a9, 0,
+#undef V2468
+#define V2468 (V + 9110)
+ 0x1102, 0x116c, 0x11aa, 0,
+#undef V2469
+#define V2469 (V + 9114)
+ 0x1102, 0x116c, 0x11ab, 0,
+#undef V2470
+#define V2470 (V + 9118)
+ 0x1102, 0x116c, 0x11ac, 0,
+#undef V2471
+#define V2471 (V + 9122)
+ 0x1102, 0x116c, 0x11ad, 0,
+#undef V2472
+#define V2472 (V + 9126)
+ 0x1102, 0x116c, 0x11ae, 0,
+#undef V2473
+#define V2473 (V + 9130)
+ 0x1102, 0x116c, 0x11af, 0,
+#undef V2474
+#define V2474 (V + 9134)
+ 0x1102, 0x116c, 0x11b0, 0,
+#undef V2475
+#define V2475 (V + 9138)
+ 0x1102, 0x116c, 0x11b1, 0,
+#undef V2476
+#define V2476 (V + 9142)
+ 0x1102, 0x116c, 0x11b2, 0,
+#undef V2477
+#define V2477 (V + 9146)
+ 0x1102, 0x116c, 0x11b3, 0,
+#undef V2478
+#define V2478 (V + 9150)
+ 0x1102, 0x116c, 0x11b4, 0,
+#undef V2479
+#define V2479 (V + 9154)
+ 0x1102, 0x116c, 0x11b5, 0,
+#undef V2480
+#define V2480 (V + 9158)
+ 0x1102, 0x116c, 0x11b6, 0,
+#undef V2481
+#define V2481 (V + 9162)
+ 0x1102, 0x116c, 0x11b7, 0,
+#undef V2482
+#define V2482 (V + 9166)
+ 0x1102, 0x116c, 0x11b8, 0,
+#undef V2483
+#define V2483 (V + 9170)
+ 0x1102, 0x116c, 0x11b9, 0,
+#undef V2484
+#define V2484 (V + 9174)
+ 0x1102, 0x116c, 0x11ba, 0,
+#undef V2485
+#define V2485 (V + 9178)
+ 0x1102, 0x116c, 0x11bb, 0,
+#undef V2486
+#define V2486 (V + 9182)
+ 0x1102, 0x116c, 0x11bc, 0,
+#undef V2487
+#define V2487 (V + 9186)
+ 0x1102, 0x116c, 0x11bd, 0,
+#undef V2488
+#define V2488 (V + 9190)
+ 0x1102, 0x116c, 0x11be, 0,
+#undef V2489
+#define V2489 (V + 9194)
+ 0x1102, 0x116c, 0x11bf, 0,
+#undef V2490
+#define V2490 (V + 9198)
+ 0x1102, 0x116c, 0x11c0, 0,
+#undef V2491
+#define V2491 (V + 9202)
+ 0x1102, 0x116c, 0x11c1, 0,
+#undef V2492
+#define V2492 (V + 9206)
+ 0x1102, 0x116c, 0x11c2, 0,
+#undef V2493
+#define V2493 (V + 9210)
+ 0x1102, 0x116d, 0,
+#undef V2494
+#define V2494 (V + 9213)
+ 0x1102, 0x116d, 0x11a8, 0,
+#undef V2495
+#define V2495 (V + 9217)
+ 0x1102, 0x116d, 0x11a9, 0,
+#undef V2496
+#define V2496 (V + 9221)
+ 0x1102, 0x116d, 0x11aa, 0,
+#undef V2497
+#define V2497 (V + 9225)
+ 0x1102, 0x116d, 0x11ab, 0,
+#undef V2498
+#define V2498 (V + 9229)
+ 0x1102, 0x116d, 0x11ac, 0,
+#undef V2499
+#define V2499 (V + 9233)
+ 0x1102, 0x116d, 0x11ad, 0,
+#undef V2500
+#define V2500 (V + 9237)
+ 0x1102, 0x116d, 0x11ae, 0,
+#undef V2501
+#define V2501 (V + 9241)
+ 0x1102, 0x116d, 0x11af, 0,
+#undef V2502
+#define V2502 (V + 9245)
+ 0x1102, 0x116d, 0x11b0, 0,
+#undef V2503
+#define V2503 (V + 9249)
+ 0x1102, 0x116d, 0x11b1, 0,
+#undef V2504
+#define V2504 (V + 9253)
+ 0x1102, 0x116d, 0x11b2, 0,
+#undef V2505
+#define V2505 (V + 9257)
+ 0x1102, 0x116d, 0x11b3, 0,
+#undef V2506
+#define V2506 (V + 9261)
+ 0x1102, 0x116d, 0x11b4, 0,
+#undef V2507
+#define V2507 (V + 9265)
+ 0x1102, 0x116d, 0x11b5, 0,
+#undef V2508
+#define V2508 (V + 9269)
+ 0x1102, 0x116d, 0x11b6, 0,
+#undef V2509
+#define V2509 (V + 9273)
+ 0x1102, 0x116d, 0x11b7, 0,
+#undef V2510
+#define V2510 (V + 9277)
+ 0x1102, 0x116d, 0x11b8, 0,
+#undef V2511
+#define V2511 (V + 9281)
+ 0x1102, 0x116d, 0x11b9, 0,
+#undef V2512
+#define V2512 (V + 9285)
+ 0x1102, 0x116d, 0x11ba, 0,
+#undef V2513
+#define V2513 (V + 9289)
+ 0x1102, 0x116d, 0x11bb, 0,
+#undef V2514
+#define V2514 (V + 9293)
+ 0x1102, 0x116d, 0x11bc, 0,
+#undef V2515
+#define V2515 (V + 9297)
+ 0x1102, 0x116d, 0x11bd, 0,
+#undef V2516
+#define V2516 (V + 9301)
+ 0x1102, 0x116d, 0x11be, 0,
+#undef V2517
+#define V2517 (V + 9305)
+ 0x1102, 0x116d, 0x11bf, 0,
+#undef V2518
+#define V2518 (V + 9309)
+ 0x1102, 0x116d, 0x11c0, 0,
+#undef V2519
+#define V2519 (V + 9313)
+ 0x1102, 0x116d, 0x11c1, 0,
+#undef V2520
+#define V2520 (V + 9317)
+ 0x1102, 0x116d, 0x11c2, 0,
+#undef V2521
+#define V2521 (V + 9321)
+ 0x1102, 0x116e, 0,
+#undef V2522
+#define V2522 (V + 9324)
+ 0x1102, 0x116e, 0x11a8, 0,
+#undef V2523
+#define V2523 (V + 9328)
+ 0x1102, 0x116e, 0x11a9, 0,
+#undef V2524
+#define V2524 (V + 9332)
+ 0x1102, 0x116e, 0x11aa, 0,
+#undef V2525
+#define V2525 (V + 9336)
+ 0x1102, 0x116e, 0x11ab, 0,
+#undef V2526
+#define V2526 (V + 9340)
+ 0x1102, 0x116e, 0x11ac, 0,
+#undef V2527
+#define V2527 (V + 9344)
+ 0x1102, 0x116e, 0x11ad, 0,
+#undef V2528
+#define V2528 (V + 9348)
+ 0x1102, 0x116e, 0x11ae, 0,
+#undef V2529
+#define V2529 (V + 9352)
+ 0x1102, 0x116e, 0x11af, 0,
+#undef V2530
+#define V2530 (V + 9356)
+ 0x1102, 0x116e, 0x11b0, 0,
+#undef V2531
+#define V2531 (V + 9360)
+ 0x1102, 0x116e, 0x11b1, 0,
+#undef V2532
+#define V2532 (V + 9364)
+ 0x1102, 0x116e, 0x11b2, 0,
+#undef V2533
+#define V2533 (V + 9368)
+ 0x1102, 0x116e, 0x11b3, 0,
+#undef V2534
+#define V2534 (V + 9372)
+ 0x1102, 0x116e, 0x11b4, 0,
+#undef V2535
+#define V2535 (V + 9376)
+ 0x1102, 0x116e, 0x11b5, 0,
+#undef V2536
+#define V2536 (V + 9380)
+ 0x1102, 0x116e, 0x11b6, 0,
+#undef V2537
+#define V2537 (V + 9384)
+ 0x1102, 0x116e, 0x11b7, 0,
+#undef V2538
+#define V2538 (V + 9388)
+ 0x1102, 0x116e, 0x11b8, 0,
+#undef V2539
+#define V2539 (V + 9392)
+ 0x1102, 0x116e, 0x11b9, 0,
+#undef V2540
+#define V2540 (V + 9396)
+ 0x1102, 0x116e, 0x11ba, 0,
+#undef V2541
+#define V2541 (V + 9400)
+ 0x1102, 0x116e, 0x11bb, 0,
+#undef V2542
+#define V2542 (V + 9404)
+ 0x1102, 0x116e, 0x11bc, 0,
+#undef V2543
+#define V2543 (V + 9408)
+ 0x1102, 0x116e, 0x11bd, 0,
+#undef V2544
+#define V2544 (V + 9412)
+ 0x1102, 0x116e, 0x11be, 0,
+#undef V2545
+#define V2545 (V + 9416)
+ 0x1102, 0x116e, 0x11bf, 0,
+#undef V2546
+#define V2546 (V + 9420)
+ 0x1102, 0x116e, 0x11c0, 0,
+#undef V2547
+#define V2547 (V + 9424)
+ 0x1102, 0x116e, 0x11c1, 0,
+#undef V2548
+#define V2548 (V + 9428)
+ 0x1102, 0x116e, 0x11c2, 0,
+#undef V2549
+#define V2549 (V + 9432)
+ 0x1102, 0x116f, 0,
+#undef V2550
+#define V2550 (V + 9435)
+ 0x1102, 0x116f, 0x11a8, 0,
+#undef V2551
+#define V2551 (V + 9439)
+ 0x1102, 0x116f, 0x11a9, 0,
+#undef V2552
+#define V2552 (V + 9443)
+ 0x1102, 0x116f, 0x11aa, 0,
+#undef V2553
+#define V2553 (V + 9447)
+ 0x1102, 0x116f, 0x11ab, 0,
+#undef V2554
+#define V2554 (V + 9451)
+ 0x1102, 0x116f, 0x11ac, 0,
+#undef V2555
+#define V2555 (V + 9455)
+ 0x1102, 0x116f, 0x11ad, 0,
+#undef V2556
+#define V2556 (V + 9459)
+ 0x1102, 0x116f, 0x11ae, 0,
+#undef V2557
+#define V2557 (V + 9463)
+ 0x1102, 0x116f, 0x11af, 0,
+#undef V2558
+#define V2558 (V + 9467)
+ 0x1102, 0x116f, 0x11b0, 0,
+#undef V2559
+#define V2559 (V + 9471)
+ 0x1102, 0x116f, 0x11b1, 0,
+#undef V2560
+#define V2560 (V + 9475)
+ 0x1102, 0x116f, 0x11b2, 0,
+#undef V2561
+#define V2561 (V + 9479)
+ 0x1102, 0x116f, 0x11b3, 0,
+#undef V2562
+#define V2562 (V + 9483)
+ 0x1102, 0x116f, 0x11b4, 0,
+#undef V2563
+#define V2563 (V + 9487)
+ 0x1102, 0x116f, 0x11b5, 0,
+#undef V2564
+#define V2564 (V + 9491)
+ 0x1102, 0x116f, 0x11b6, 0,
+#undef V2565
+#define V2565 (V + 9495)
+ 0x1102, 0x116f, 0x11b7, 0,
+#undef V2566
+#define V2566 (V + 9499)
+ 0x1102, 0x116f, 0x11b8, 0,
+#undef V2567
+#define V2567 (V + 9503)
+ 0x1102, 0x116f, 0x11b9, 0,
+#undef V2568
+#define V2568 (V + 9507)
+ 0x1102, 0x116f, 0x11ba, 0,
+#undef V2569
+#define V2569 (V + 9511)
+ 0x1102, 0x116f, 0x11bb, 0,
+#undef V2570
+#define V2570 (V + 9515)
+ 0x1102, 0x116f, 0x11bc, 0,
+#undef V2571
+#define V2571 (V + 9519)
+ 0x1102, 0x116f, 0x11bd, 0,
+#undef V2572
+#define V2572 (V + 9523)
+ 0x1102, 0x116f, 0x11be, 0,
+#undef V2573
+#define V2573 (V + 9527)
+ 0x1102, 0x116f, 0x11bf, 0,
+#undef V2574
+#define V2574 (V + 9531)
+ 0x1102, 0x116f, 0x11c0, 0,
+#undef V2575
+#define V2575 (V + 9535)
+ 0x1102, 0x116f, 0x11c1, 0,
+#undef V2576
+#define V2576 (V + 9539)
+ 0x1102, 0x116f, 0x11c2, 0,
+#undef V2577
+#define V2577 (V + 9543)
+ 0x1102, 0x1170, 0,
+#undef V2578
+#define V2578 (V + 9546)
+ 0x1102, 0x1170, 0x11a8, 0,
+#undef V2579
+#define V2579 (V + 9550)
+ 0x1102, 0x1170, 0x11a9, 0,
+#undef V2580
+#define V2580 (V + 9554)
+ 0x1102, 0x1170, 0x11aa, 0,
+#undef V2581
+#define V2581 (V + 9558)
+ 0x1102, 0x1170, 0x11ab, 0,
+#undef V2582
+#define V2582 (V + 9562)
+ 0x1102, 0x1170, 0x11ac, 0,
+#undef V2583
+#define V2583 (V + 9566)
+ 0x1102, 0x1170, 0x11ad, 0,
+#undef V2584
+#define V2584 (V + 9570)
+ 0x1102, 0x1170, 0x11ae, 0,
+#undef V2585
+#define V2585 (V + 9574)
+ 0x1102, 0x1170, 0x11af, 0,
+#undef V2586
+#define V2586 (V + 9578)
+ 0x1102, 0x1170, 0x11b0, 0,
+#undef V2587
+#define V2587 (V + 9582)
+ 0x1102, 0x1170, 0x11b1, 0,
+#undef V2588
+#define V2588 (V + 9586)
+ 0x1102, 0x1170, 0x11b2, 0,
+#undef V2589
+#define V2589 (V + 9590)
+ 0x1102, 0x1170, 0x11b3, 0,
+#undef V2590
+#define V2590 (V + 9594)
+ 0x1102, 0x1170, 0x11b4, 0,
+#undef V2591
+#define V2591 (V + 9598)
+ 0x1102, 0x1170, 0x11b5, 0,
+#undef V2592
+#define V2592 (V + 9602)
+ 0x1102, 0x1170, 0x11b6, 0,
+#undef V2593
+#define V2593 (V + 9606)
+ 0x1102, 0x1170, 0x11b7, 0,
+#undef V2594
+#define V2594 (V + 9610)
+ 0x1102, 0x1170, 0x11b8, 0,
+#undef V2595
+#define V2595 (V + 9614)
+ 0x1102, 0x1170, 0x11b9, 0,
+#undef V2596
+#define V2596 (V + 9618)
+ 0x1102, 0x1170, 0x11ba, 0,
+#undef V2597
+#define V2597 (V + 9622)
+ 0x1102, 0x1170, 0x11bb, 0,
+#undef V2598
+#define V2598 (V + 9626)
+ 0x1102, 0x1170, 0x11bc, 0,
+#undef V2599
+#define V2599 (V + 9630)
+ 0x1102, 0x1170, 0x11bd, 0,
+#undef V2600
+#define V2600 (V + 9634)
+ 0x1102, 0x1170, 0x11be, 0,
+#undef V2601
+#define V2601 (V + 9638)
+ 0x1102, 0x1170, 0x11bf, 0,
+#undef V2602
+#define V2602 (V + 9642)
+ 0x1102, 0x1170, 0x11c0, 0,
+#undef V2603
+#define V2603 (V + 9646)
+ 0x1102, 0x1170, 0x11c1, 0,
+#undef V2604
+#define V2604 (V + 9650)
+ 0x1102, 0x1170, 0x11c2, 0,
+#undef V2605
+#define V2605 (V + 9654)
+ 0x1102, 0x1171, 0,
+#undef V2606
+#define V2606 (V + 9657)
+ 0x1102, 0x1171, 0x11a8, 0,
+#undef V2607
+#define V2607 (V + 9661)
+ 0x1102, 0x1171, 0x11a9, 0,
+#undef V2608
+#define V2608 (V + 9665)
+ 0x1102, 0x1171, 0x11aa, 0,
+#undef V2609
+#define V2609 (V + 9669)
+ 0x1102, 0x1171, 0x11ab, 0,
+#undef V2610
+#define V2610 (V + 9673)
+ 0x1102, 0x1171, 0x11ac, 0,
+#undef V2611
+#define V2611 (V + 9677)
+ 0x1102, 0x1171, 0x11ad, 0,
+#undef V2612
+#define V2612 (V + 9681)
+ 0x1102, 0x1171, 0x11ae, 0,
+#undef V2613
+#define V2613 (V + 9685)
+ 0x1102, 0x1171, 0x11af, 0,
+#undef V2614
+#define V2614 (V + 9689)
+ 0x1102, 0x1171, 0x11b0, 0,
+#undef V2615
+#define V2615 (V + 9693)
+ 0x1102, 0x1171, 0x11b1, 0,
+#undef V2616
+#define V2616 (V + 9697)
+ 0x1102, 0x1171, 0x11b2, 0,
+#undef V2617
+#define V2617 (V + 9701)
+ 0x1102, 0x1171, 0x11b3, 0,
+#undef V2618
+#define V2618 (V + 9705)
+ 0x1102, 0x1171, 0x11b4, 0,
+#undef V2619
+#define V2619 (V + 9709)
+ 0x1102, 0x1171, 0x11b5, 0,
+#undef V2620
+#define V2620 (V + 9713)
+ 0x1102, 0x1171, 0x11b6, 0,
+#undef V2621
+#define V2621 (V + 9717)
+ 0x1102, 0x1171, 0x11b7, 0,
+#undef V2622
+#define V2622 (V + 9721)
+ 0x1102, 0x1171, 0x11b8, 0,
+#undef V2623
+#define V2623 (V + 9725)
+ 0x1102, 0x1171, 0x11b9, 0,
+#undef V2624
+#define V2624 (V + 9729)
+ 0x1102, 0x1171, 0x11ba, 0,
+#undef V2625
+#define V2625 (V + 9733)
+ 0x1102, 0x1171, 0x11bb, 0,
+#undef V2626
+#define V2626 (V + 9737)
+ 0x1102, 0x1171, 0x11bc, 0,
+#undef V2627
+#define V2627 (V + 9741)
+ 0x1102, 0x1171, 0x11bd, 0,
+#undef V2628
+#define V2628 (V + 9745)
+ 0x1102, 0x1171, 0x11be, 0,
+#undef V2629
+#define V2629 (V + 9749)
+ 0x1102, 0x1171, 0x11bf, 0,
+#undef V2630
+#define V2630 (V + 9753)
+ 0x1102, 0x1171, 0x11c0, 0,
+#undef V2631
+#define V2631 (V + 9757)
+ 0x1102, 0x1171, 0x11c1, 0,
+#undef V2632
+#define V2632 (V + 9761)
+ 0x1102, 0x1171, 0x11c2, 0,
+#undef V2633
+#define V2633 (V + 9765)
+ 0x1102, 0x1172, 0,
+#undef V2634
+#define V2634 (V + 9768)
+ 0x1102, 0x1172, 0x11a8, 0,
+#undef V2635
+#define V2635 (V + 9772)
+ 0x1102, 0x1172, 0x11a9, 0,
+#undef V2636
+#define V2636 (V + 9776)
+ 0x1102, 0x1172, 0x11aa, 0,
+#undef V2637
+#define V2637 (V + 9780)
+ 0x1102, 0x1172, 0x11ab, 0,
+#undef V2638
+#define V2638 (V + 9784)
+ 0x1102, 0x1172, 0x11ac, 0,
+#undef V2639
+#define V2639 (V + 9788)
+ 0x1102, 0x1172, 0x11ad, 0,
+#undef V2640
+#define V2640 (V + 9792)
+ 0x1102, 0x1172, 0x11ae, 0,
+#undef V2641
+#define V2641 (V + 9796)
+ 0x1102, 0x1172, 0x11af, 0,
+#undef V2642
+#define V2642 (V + 9800)
+ 0x1102, 0x1172, 0x11b0, 0,
+#undef V2643
+#define V2643 (V + 9804)
+ 0x1102, 0x1172, 0x11b1, 0,
+#undef V2644
+#define V2644 (V + 9808)
+ 0x1102, 0x1172, 0x11b2, 0,
+#undef V2645
+#define V2645 (V + 9812)
+ 0x1102, 0x1172, 0x11b3, 0,
+#undef V2646
+#define V2646 (V + 9816)
+ 0x1102, 0x1172, 0x11b4, 0,
+#undef V2647
+#define V2647 (V + 9820)
+ 0x1102, 0x1172, 0x11b5, 0,
+#undef V2648
+#define V2648 (V + 9824)
+ 0x1102, 0x1172, 0x11b6, 0,
+#undef V2649
+#define V2649 (V + 9828)
+ 0x1102, 0x1172, 0x11b7, 0,
+#undef V2650
+#define V2650 (V + 9832)
+ 0x1102, 0x1172, 0x11b8, 0,
+#undef V2651
+#define V2651 (V + 9836)
+ 0x1102, 0x1172, 0x11b9, 0,
+#undef V2652
+#define V2652 (V + 9840)
+ 0x1102, 0x1172, 0x11ba, 0,
+#undef V2653
+#define V2653 (V + 9844)
+ 0x1102, 0x1172, 0x11bb, 0,
+#undef V2654
+#define V2654 (V + 9848)
+ 0x1102, 0x1172, 0x11bc, 0,
+#undef V2655
+#define V2655 (V + 9852)
+ 0x1102, 0x1172, 0x11bd, 0,
+#undef V2656
+#define V2656 (V + 9856)
+ 0x1102, 0x1172, 0x11be, 0,
+#undef V2657
+#define V2657 (V + 9860)
+ 0x1102, 0x1172, 0x11bf, 0,
+#undef V2658
+#define V2658 (V + 9864)
+ 0x1102, 0x1172, 0x11c0, 0,
+#undef V2659
+#define V2659 (V + 9868)
+ 0x1102, 0x1172, 0x11c1, 0,
+#undef V2660
+#define V2660 (V + 9872)
+ 0x1102, 0x1172, 0x11c2, 0,
+#undef V2661
+#define V2661 (V + 9876)
+ 0x1102, 0x1173, 0,
+#undef V2662
+#define V2662 (V + 9879)
+ 0x1102, 0x1173, 0x11a8, 0,
+#undef V2663
+#define V2663 (V + 9883)
+ 0x1102, 0x1173, 0x11a9, 0,
+#undef V2664
+#define V2664 (V + 9887)
+ 0x1102, 0x1173, 0x11aa, 0,
+#undef V2665
+#define V2665 (V + 9891)
+ 0x1102, 0x1173, 0x11ab, 0,
+#undef V2666
+#define V2666 (V + 9895)
+ 0x1102, 0x1173, 0x11ac, 0,
+#undef V2667
+#define V2667 (V + 9899)
+ 0x1102, 0x1173, 0x11ad, 0,
+#undef V2668
+#define V2668 (V + 9903)
+ 0x1102, 0x1173, 0x11ae, 0,
+#undef V2669
+#define V2669 (V + 9907)
+ 0x1102, 0x1173, 0x11af, 0,
+#undef V2670
+#define V2670 (V + 9911)
+ 0x1102, 0x1173, 0x11b0, 0,
+#undef V2671
+#define V2671 (V + 9915)
+ 0x1102, 0x1173, 0x11b1, 0,
+#undef V2672
+#define V2672 (V + 9919)
+ 0x1102, 0x1173, 0x11b2, 0,
+#undef V2673
+#define V2673 (V + 9923)
+ 0x1102, 0x1173, 0x11b3, 0,
+#undef V2674
+#define V2674 (V + 9927)
+ 0x1102, 0x1173, 0x11b4, 0,
+#undef V2675
+#define V2675 (V + 9931)
+ 0x1102, 0x1173, 0x11b5, 0,
+#undef V2676
+#define V2676 (V + 9935)
+ 0x1102, 0x1173, 0x11b6, 0,
+#undef V2677
+#define V2677 (V + 9939)
+ 0x1102, 0x1173, 0x11b7, 0,
+#undef V2678
+#define V2678 (V + 9943)
+ 0x1102, 0x1173, 0x11b8, 0,
+#undef V2679
+#define V2679 (V + 9947)
+ 0x1102, 0x1173, 0x11b9, 0,
+#undef V2680
+#define V2680 (V + 9951)
+ 0x1102, 0x1173, 0x11ba, 0,
+#undef V2681
+#define V2681 (V + 9955)
+ 0x1102, 0x1173, 0x11bb, 0,
+#undef V2682
+#define V2682 (V + 9959)
+ 0x1102, 0x1173, 0x11bc, 0,
+#undef V2683
+#define V2683 (V + 9963)
+ 0x1102, 0x1173, 0x11bd, 0,
+#undef V2684
+#define V2684 (V + 9967)
+ 0x1102, 0x1173, 0x11be, 0,
+#undef V2685
+#define V2685 (V + 9971)
+ 0x1102, 0x1173, 0x11bf, 0,
+#undef V2686
+#define V2686 (V + 9975)
+ 0x1102, 0x1173, 0x11c0, 0,
+#undef V2687
+#define V2687 (V + 9979)
+ 0x1102, 0x1173, 0x11c1, 0,
+#undef V2688
+#define V2688 (V + 9983)
+ 0x1102, 0x1173, 0x11c2, 0,
+#undef V2689
+#define V2689 (V + 9987)
+ 0x1102, 0x1174, 0,
+#undef V2690
+#define V2690 (V + 9990)
+ 0x1102, 0x1174, 0x11a8, 0,
+#undef V2691
+#define V2691 (V + 9994)
+ 0x1102, 0x1174, 0x11a9, 0,
+#undef V2692
+#define V2692 (V + 9998)
+ 0x1102, 0x1174, 0x11aa, 0,
+#undef V2693
+#define V2693 (V + 10002)
+ 0x1102, 0x1174, 0x11ab, 0,
+#undef V2694
+#define V2694 (V + 10006)
+ 0x1102, 0x1174, 0x11ac, 0,
+#undef V2695
+#define V2695 (V + 10010)
+ 0x1102, 0x1174, 0x11ad, 0,
+#undef V2696
+#define V2696 (V + 10014)
+ 0x1102, 0x1174, 0x11ae, 0,
+#undef V2697
+#define V2697 (V + 10018)
+ 0x1102, 0x1174, 0x11af, 0,
+#undef V2698
+#define V2698 (V + 10022)
+ 0x1102, 0x1174, 0x11b0, 0,
+#undef V2699
+#define V2699 (V + 10026)
+ 0x1102, 0x1174, 0x11b1, 0,
+#undef V2700
+#define V2700 (V + 10030)
+ 0x1102, 0x1174, 0x11b2, 0,
+#undef V2701
+#define V2701 (V + 10034)
+ 0x1102, 0x1174, 0x11b3, 0,
+#undef V2702
+#define V2702 (V + 10038)
+ 0x1102, 0x1174, 0x11b4, 0,
+#undef V2703
+#define V2703 (V + 10042)
+ 0x1102, 0x1174, 0x11b5, 0,
+#undef V2704
+#define V2704 (V + 10046)
+ 0x1102, 0x1174, 0x11b6, 0,
+#undef V2705
+#define V2705 (V + 10050)
+ 0x1102, 0x1174, 0x11b7, 0,
+#undef V2706
+#define V2706 (V + 10054)
+ 0x1102, 0x1174, 0x11b8, 0,
+#undef V2707
+#define V2707 (V + 10058)
+ 0x1102, 0x1174, 0x11b9, 0,
+#undef V2708
+#define V2708 (V + 10062)
+ 0x1102, 0x1174, 0x11ba, 0,
+#undef V2709
+#define V2709 (V + 10066)
+ 0x1102, 0x1174, 0x11bb, 0,
+#undef V2710
+#define V2710 (V + 10070)
+ 0x1102, 0x1174, 0x11bc, 0,
+#undef V2711
+#define V2711 (V + 10074)
+ 0x1102, 0x1174, 0x11bd, 0,
+#undef V2712
+#define V2712 (V + 10078)
+ 0x1102, 0x1174, 0x11be, 0,
+#undef V2713
+#define V2713 (V + 10082)
+ 0x1102, 0x1174, 0x11bf, 0,
+#undef V2714
+#define V2714 (V + 10086)
+ 0x1102, 0x1174, 0x11c0, 0,
+#undef V2715
+#define V2715 (V + 10090)
+ 0x1102, 0x1174, 0x11c1, 0,
+#undef V2716
+#define V2716 (V + 10094)
+ 0x1102, 0x1174, 0x11c2, 0,
+#undef V2717
+#define V2717 (V + 10098)
+ 0x1102, 0x1175, 0,
+#undef V2718
+#define V2718 (V + 10101)
+ 0x1102, 0x1175, 0x11a8, 0,
+#undef V2719
+#define V2719 (V + 10105)
+ 0x1102, 0x1175, 0x11a9, 0,
+#undef V2720
+#define V2720 (V + 10109)
+ 0x1102, 0x1175, 0x11aa, 0,
+#undef V2721
+#define V2721 (V + 10113)
+ 0x1102, 0x1175, 0x11ab, 0,
+#undef V2722
+#define V2722 (V + 10117)
+ 0x1102, 0x1175, 0x11ac, 0,
+#undef V2723
+#define V2723 (V + 10121)
+ 0x1102, 0x1175, 0x11ad, 0,
+#undef V2724
+#define V2724 (V + 10125)
+ 0x1102, 0x1175, 0x11ae, 0,
+#undef V2725
+#define V2725 (V + 10129)
+ 0x1102, 0x1175, 0x11af, 0,
+#undef V2726
+#define V2726 (V + 10133)
+ 0x1102, 0x1175, 0x11b0, 0,
+#undef V2727
+#define V2727 (V + 10137)
+ 0x1102, 0x1175, 0x11b1, 0,
+#undef V2728
+#define V2728 (V + 10141)
+ 0x1102, 0x1175, 0x11b2, 0,
+#undef V2729
+#define V2729 (V + 10145)
+ 0x1102, 0x1175, 0x11b3, 0,
+#undef V2730
+#define V2730 (V + 10149)
+ 0x1102, 0x1175, 0x11b4, 0,
+#undef V2731
+#define V2731 (V + 10153)
+ 0x1102, 0x1175, 0x11b5, 0,
+#undef V2732
+#define V2732 (V + 10157)
+ 0x1102, 0x1175, 0x11b6, 0,
+#undef V2733
+#define V2733 (V + 10161)
+ 0x1102, 0x1175, 0x11b7, 0,
+#undef V2734
+#define V2734 (V + 10165)
+ 0x1102, 0x1175, 0x11b8, 0,
+#undef V2735
+#define V2735 (V + 10169)
+ 0x1102, 0x1175, 0x11b9, 0,
+#undef V2736
+#define V2736 (V + 10173)
+ 0x1102, 0x1175, 0x11ba, 0,
+#undef V2737
+#define V2737 (V + 10177)
+ 0x1102, 0x1175, 0x11bb, 0,
+#undef V2738
+#define V2738 (V + 10181)
+ 0x1102, 0x1175, 0x11bc, 0,
+#undef V2739
+#define V2739 (V + 10185)
+ 0x1102, 0x1175, 0x11bd, 0,
+#undef V2740
+#define V2740 (V + 10189)
+ 0x1102, 0x1175, 0x11be, 0,
+#undef V2741
+#define V2741 (V + 10193)
+ 0x1102, 0x1175, 0x11bf, 0,
+#undef V2742
+#define V2742 (V + 10197)
+ 0x1102, 0x1175, 0x11c0, 0,
+#undef V2743
+#define V2743 (V + 10201)
+ 0x1102, 0x1175, 0x11c1, 0,
+#undef V2744
+#define V2744 (V + 10205)
+ 0x1102, 0x1175, 0x11c2, 0,
+#undef V2745
+#define V2745 (V + 10209)
+ 0x1103, 0x1161, 0,
+#undef V2746
+#define V2746 (V + 10212)
+ 0x1103, 0x1161, 0x11a8, 0,
+#undef V2747
+#define V2747 (V + 10216)
+ 0x1103, 0x1161, 0x11a9, 0,
+#undef V2748
+#define V2748 (V + 10220)
+ 0x1103, 0x1161, 0x11aa, 0,
+#undef V2749
+#define V2749 (V + 10224)
+ 0x1103, 0x1161, 0x11ab, 0,
+#undef V2750
+#define V2750 (V + 10228)
+ 0x1103, 0x1161, 0x11ac, 0,
+#undef V2751
+#define V2751 (V + 10232)
+ 0x1103, 0x1161, 0x11ad, 0,
+#undef V2752
+#define V2752 (V + 10236)
+ 0x1103, 0x1161, 0x11ae, 0,
+#undef V2753
+#define V2753 (V + 10240)
+ 0x1103, 0x1161, 0x11af, 0,
+#undef V2754
+#define V2754 (V + 10244)
+ 0x1103, 0x1161, 0x11b0, 0,
+#undef V2755
+#define V2755 (V + 10248)
+ 0x1103, 0x1161, 0x11b1, 0,
+#undef V2756
+#define V2756 (V + 10252)
+ 0x1103, 0x1161, 0x11b2, 0,
+#undef V2757
+#define V2757 (V + 10256)
+ 0x1103, 0x1161, 0x11b3, 0,
+#undef V2758
+#define V2758 (V + 10260)
+ 0x1103, 0x1161, 0x11b4, 0,
+#undef V2759
+#define V2759 (V + 10264)
+ 0x1103, 0x1161, 0x11b5, 0,
+#undef V2760
+#define V2760 (V + 10268)
+ 0x1103, 0x1161, 0x11b6, 0,
+#undef V2761
+#define V2761 (V + 10272)
+ 0x1103, 0x1161, 0x11b7, 0,
+#undef V2762
+#define V2762 (V + 10276)
+ 0x1103, 0x1161, 0x11b8, 0,
+#undef V2763
+#define V2763 (V + 10280)
+ 0x1103, 0x1161, 0x11b9, 0,
+#undef V2764
+#define V2764 (V + 10284)
+ 0x1103, 0x1161, 0x11ba, 0,
+#undef V2765
+#define V2765 (V + 10288)
+ 0x1103, 0x1161, 0x11bb, 0,
+#undef V2766
+#define V2766 (V + 10292)
+ 0x1103, 0x1161, 0x11bc, 0,
+#undef V2767
+#define V2767 (V + 10296)
+ 0x1103, 0x1161, 0x11bd, 0,
+#undef V2768
+#define V2768 (V + 10300)
+ 0x1103, 0x1161, 0x11be, 0,
+#undef V2769
+#define V2769 (V + 10304)
+ 0x1103, 0x1161, 0x11bf, 0,
+#undef V2770
+#define V2770 (V + 10308)
+ 0x1103, 0x1161, 0x11c0, 0,
+#undef V2771
+#define V2771 (V + 10312)
+ 0x1103, 0x1161, 0x11c1, 0,
+#undef V2772
+#define V2772 (V + 10316)
+ 0x1103, 0x1161, 0x11c2, 0,
+#undef V2773
+#define V2773 (V + 10320)
+ 0x1103, 0x1162, 0,
+#undef V2774
+#define V2774 (V + 10323)
+ 0x1103, 0x1162, 0x11a8, 0,
+#undef V2775
+#define V2775 (V + 10327)
+ 0x1103, 0x1162, 0x11a9, 0,
+#undef V2776
+#define V2776 (V + 10331)
+ 0x1103, 0x1162, 0x11aa, 0,
+#undef V2777
+#define V2777 (V + 10335)
+ 0x1103, 0x1162, 0x11ab, 0,
+#undef V2778
+#define V2778 (V + 10339)
+ 0x1103, 0x1162, 0x11ac, 0,
+#undef V2779
+#define V2779 (V + 10343)
+ 0x1103, 0x1162, 0x11ad, 0,
+#undef V2780
+#define V2780 (V + 10347)
+ 0x1103, 0x1162, 0x11ae, 0,
+#undef V2781
+#define V2781 (V + 10351)
+ 0x1103, 0x1162, 0x11af, 0,
+#undef V2782
+#define V2782 (V + 10355)
+ 0x1103, 0x1162, 0x11b0, 0,
+#undef V2783
+#define V2783 (V + 10359)
+ 0x1103, 0x1162, 0x11b1, 0,
+#undef V2784
+#define V2784 (V + 10363)
+ 0x1103, 0x1162, 0x11b2, 0,
+#undef V2785
+#define V2785 (V + 10367)
+ 0x1103, 0x1162, 0x11b3, 0,
+#undef V2786
+#define V2786 (V + 10371)
+ 0x1103, 0x1162, 0x11b4, 0,
+#undef V2787
+#define V2787 (V + 10375)
+ 0x1103, 0x1162, 0x11b5, 0,
+#undef V2788
+#define V2788 (V + 10379)
+ 0x1103, 0x1162, 0x11b6, 0,
+#undef V2789
+#define V2789 (V + 10383)
+ 0x1103, 0x1162, 0x11b7, 0,
+#undef V2790
+#define V2790 (V + 10387)
+ 0x1103, 0x1162, 0x11b8, 0,
+#undef V2791
+#define V2791 (V + 10391)
+ 0x1103, 0x1162, 0x11b9, 0,
+#undef V2792
+#define V2792 (V + 10395)
+ 0x1103, 0x1162, 0x11ba, 0,
+#undef V2793
+#define V2793 (V + 10399)
+ 0x1103, 0x1162, 0x11bb, 0,
+#undef V2794
+#define V2794 (V + 10403)
+ 0x1103, 0x1162, 0x11bc, 0,
+#undef V2795
+#define V2795 (V + 10407)
+ 0x1103, 0x1162, 0x11bd, 0,
+#undef V2796
+#define V2796 (V + 10411)
+ 0x1103, 0x1162, 0x11be, 0,
+#undef V2797
+#define V2797 (V + 10415)
+ 0x1103, 0x1162, 0x11bf, 0,
+#undef V2798
+#define V2798 (V + 10419)
+ 0x1103, 0x1162, 0x11c0, 0,
+#undef V2799
+#define V2799 (V + 10423)
+ 0x1103, 0x1162, 0x11c1, 0,
+#undef V2800
+#define V2800 (V + 10427)
+ 0x1103, 0x1162, 0x11c2, 0,
+#undef V2801
+#define V2801 (V + 10431)
+ 0x1103, 0x1163, 0,
+#undef V2802
+#define V2802 (V + 10434)
+ 0x1103, 0x1163, 0x11a8, 0,
+#undef V2803
+#define V2803 (V + 10438)
+ 0x1103, 0x1163, 0x11a9, 0,
+#undef V2804
+#define V2804 (V + 10442)
+ 0x1103, 0x1163, 0x11aa, 0,
+#undef V2805
+#define V2805 (V + 10446)
+ 0x1103, 0x1163, 0x11ab, 0,
+#undef V2806
+#define V2806 (V + 10450)
+ 0x1103, 0x1163, 0x11ac, 0,
+#undef V2807
+#define V2807 (V + 10454)
+ 0x1103, 0x1163, 0x11ad, 0,
+#undef V2808
+#define V2808 (V + 10458)
+ 0x1103, 0x1163, 0x11ae, 0,
+#undef V2809
+#define V2809 (V + 10462)
+ 0x1103, 0x1163, 0x11af, 0,
+#undef V2810
+#define V2810 (V + 10466)
+ 0x1103, 0x1163, 0x11b0, 0,
+#undef V2811
+#define V2811 (V + 10470)
+ 0x1103, 0x1163, 0x11b1, 0,
+#undef V2812
+#define V2812 (V + 10474)
+ 0x1103, 0x1163, 0x11b2, 0,
+#undef V2813
+#define V2813 (V + 10478)
+ 0x1103, 0x1163, 0x11b3, 0,
+#undef V2814
+#define V2814 (V + 10482)
+ 0x1103, 0x1163, 0x11b4, 0,
+#undef V2815
+#define V2815 (V + 10486)
+ 0x1103, 0x1163, 0x11b5, 0,
+#undef V2816
+#define V2816 (V + 10490)
+ 0x1103, 0x1163, 0x11b6, 0,
+#undef V2817
+#define V2817 (V + 10494)
+ 0x1103, 0x1163, 0x11b7, 0,
+#undef V2818
+#define V2818 (V + 10498)
+ 0x1103, 0x1163, 0x11b8, 0,
+#undef V2819
+#define V2819 (V + 10502)
+ 0x1103, 0x1163, 0x11b9, 0,
+#undef V2820
+#define V2820 (V + 10506)
+ 0x1103, 0x1163, 0x11ba, 0,
+#undef V2821
+#define V2821 (V + 10510)
+ 0x1103, 0x1163, 0x11bb, 0,
+#undef V2822
+#define V2822 (V + 10514)
+ 0x1103, 0x1163, 0x11bc, 0,
+#undef V2823
+#define V2823 (V + 10518)
+ 0x1103, 0x1163, 0x11bd, 0,
+#undef V2824
+#define V2824 (V + 10522)
+ 0x1103, 0x1163, 0x11be, 0,
+#undef V2825
+#define V2825 (V + 10526)
+ 0x1103, 0x1163, 0x11bf, 0,
+#undef V2826
+#define V2826 (V + 10530)
+ 0x1103, 0x1163, 0x11c0, 0,
+#undef V2827
+#define V2827 (V + 10534)
+ 0x1103, 0x1163, 0x11c1, 0,
+#undef V2828
+#define V2828 (V + 10538)
+ 0x1103, 0x1163, 0x11c2, 0,
+#undef V2829
+#define V2829 (V + 10542)
+ 0x1103, 0x1164, 0,
+#undef V2830
+#define V2830 (V + 10545)
+ 0x1103, 0x1164, 0x11a8, 0,
+#undef V2831
+#define V2831 (V + 10549)
+ 0x1103, 0x1164, 0x11a9, 0,
+#undef V2832
+#define V2832 (V + 10553)
+ 0x1103, 0x1164, 0x11aa, 0,
+#undef V2833
+#define V2833 (V + 10557)
+ 0x1103, 0x1164, 0x11ab, 0,
+#undef V2834
+#define V2834 (V + 10561)
+ 0x1103, 0x1164, 0x11ac, 0,
+#undef V2835
+#define V2835 (V + 10565)
+ 0x1103, 0x1164, 0x11ad, 0,
+#undef V2836
+#define V2836 (V + 10569)
+ 0x1103, 0x1164, 0x11ae, 0,
+#undef V2837
+#define V2837 (V + 10573)
+ 0x1103, 0x1164, 0x11af, 0,
+#undef V2838
+#define V2838 (V + 10577)
+ 0x1103, 0x1164, 0x11b0, 0,
+#undef V2839
+#define V2839 (V + 10581)
+ 0x1103, 0x1164, 0x11b1, 0,
+#undef V2840
+#define V2840 (V + 10585)
+ 0x1103, 0x1164, 0x11b2, 0,
+#undef V2841
+#define V2841 (V + 10589)
+ 0x1103, 0x1164, 0x11b3, 0,
+#undef V2842
+#define V2842 (V + 10593)
+ 0x1103, 0x1164, 0x11b4, 0,
+#undef V2843
+#define V2843 (V + 10597)
+ 0x1103, 0x1164, 0x11b5, 0,
+#undef V2844
+#define V2844 (V + 10601)
+ 0x1103, 0x1164, 0x11b6, 0,
+#undef V2845
+#define V2845 (V + 10605)
+ 0x1103, 0x1164, 0x11b7, 0,
+#undef V2846
+#define V2846 (V + 10609)
+ 0x1103, 0x1164, 0x11b8, 0,
+#undef V2847
+#define V2847 (V + 10613)
+ 0x1103, 0x1164, 0x11b9, 0,
+#undef V2848
+#define V2848 (V + 10617)
+ 0x1103, 0x1164, 0x11ba, 0,
+#undef V2849
+#define V2849 (V + 10621)
+ 0x1103, 0x1164, 0x11bb, 0,
+#undef V2850
+#define V2850 (V + 10625)
+ 0x1103, 0x1164, 0x11bc, 0,
+#undef V2851
+#define V2851 (V + 10629)
+ 0x1103, 0x1164, 0x11bd, 0,
+#undef V2852
+#define V2852 (V + 10633)
+ 0x1103, 0x1164, 0x11be, 0,
+#undef V2853
+#define V2853 (V + 10637)
+ 0x1103, 0x1164, 0x11bf, 0,
+#undef V2854
+#define V2854 (V + 10641)
+ 0x1103, 0x1164, 0x11c0, 0,
+#undef V2855
+#define V2855 (V + 10645)
+ 0x1103, 0x1164, 0x11c1, 0,
+#undef V2856
+#define V2856 (V + 10649)
+ 0x1103, 0x1164, 0x11c2, 0,
+#undef V2857
+#define V2857 (V + 10653)
+ 0x1103, 0x1165, 0,
+#undef V2858
+#define V2858 (V + 10656)
+ 0x1103, 0x1165, 0x11a8, 0,
+#undef V2859
+#define V2859 (V + 10660)
+ 0x1103, 0x1165, 0x11a9, 0,
+#undef V2860
+#define V2860 (V + 10664)
+ 0x1103, 0x1165, 0x11aa, 0,
+#undef V2861
+#define V2861 (V + 10668)
+ 0x1103, 0x1165, 0x11ab, 0,
+#undef V2862
+#define V2862 (V + 10672)
+ 0x1103, 0x1165, 0x11ac, 0,
+#undef V2863
+#define V2863 (V + 10676)
+ 0x1103, 0x1165, 0x11ad, 0,
+#undef V2864
+#define V2864 (V + 10680)
+ 0x1103, 0x1165, 0x11ae, 0,
+#undef V2865
+#define V2865 (V + 10684)
+ 0x1103, 0x1165, 0x11af, 0,
+#undef V2866
+#define V2866 (V + 10688)
+ 0x1103, 0x1165, 0x11b0, 0,
+#undef V2867
+#define V2867 (V + 10692)
+ 0x1103, 0x1165, 0x11b1, 0,
+#undef V2868
+#define V2868 (V + 10696)
+ 0x1103, 0x1165, 0x11b2, 0,
+#undef V2869
+#define V2869 (V + 10700)
+ 0x1103, 0x1165, 0x11b3, 0,
+#undef V2870
+#define V2870 (V + 10704)
+ 0x1103, 0x1165, 0x11b4, 0,
+#undef V2871
+#define V2871 (V + 10708)
+ 0x1103, 0x1165, 0x11b5, 0,
+#undef V2872
+#define V2872 (V + 10712)
+ 0x1103, 0x1165, 0x11b6, 0,
+#undef V2873
+#define V2873 (V + 10716)
+ 0x1103, 0x1165, 0x11b7, 0,
+#undef V2874
+#define V2874 (V + 10720)
+ 0x1103, 0x1165, 0x11b8, 0,
+#undef V2875
+#define V2875 (V + 10724)
+ 0x1103, 0x1165, 0x11b9, 0,
+#undef V2876
+#define V2876 (V + 10728)
+ 0x1103, 0x1165, 0x11ba, 0,
+#undef V2877
+#define V2877 (V + 10732)
+ 0x1103, 0x1165, 0x11bb, 0,
+#undef V2878
+#define V2878 (V + 10736)
+ 0x1103, 0x1165, 0x11bc, 0,
+#undef V2879
+#define V2879 (V + 10740)
+ 0x1103, 0x1165, 0x11bd, 0,
+#undef V2880
+#define V2880 (V + 10744)
+ 0x1103, 0x1165, 0x11be, 0,
+#undef V2881
+#define V2881 (V + 10748)
+ 0x1103, 0x1165, 0x11bf, 0,
+#undef V2882
+#define V2882 (V + 10752)
+ 0x1103, 0x1165, 0x11c0, 0,
+#undef V2883
+#define V2883 (V + 10756)
+ 0x1103, 0x1165, 0x11c1, 0,
+#undef V2884
+#define V2884 (V + 10760)
+ 0x1103, 0x1165, 0x11c2, 0,
+#undef V2885
+#define V2885 (V + 10764)
+ 0x1103, 0x1166, 0,
+#undef V2886
+#define V2886 (V + 10767)
+ 0x1103, 0x1166, 0x11a8, 0,
+#undef V2887
+#define V2887 (V + 10771)
+ 0x1103, 0x1166, 0x11a9, 0,
+#undef V2888
+#define V2888 (V + 10775)
+ 0x1103, 0x1166, 0x11aa, 0,
+#undef V2889
+#define V2889 (V + 10779)
+ 0x1103, 0x1166, 0x11ab, 0,
+#undef V2890
+#define V2890 (V + 10783)
+ 0x1103, 0x1166, 0x11ac, 0,
+#undef V2891
+#define V2891 (V + 10787)
+ 0x1103, 0x1166, 0x11ad, 0,
+#undef V2892
+#define V2892 (V + 10791)
+ 0x1103, 0x1166, 0x11ae, 0,
+#undef V2893
+#define V2893 (V + 10795)
+ 0x1103, 0x1166, 0x11af, 0,
+#undef V2894
+#define V2894 (V + 10799)
+ 0x1103, 0x1166, 0x11b0, 0,
+#undef V2895
+#define V2895 (V + 10803)
+ 0x1103, 0x1166, 0x11b1, 0,
+#undef V2896
+#define V2896 (V + 10807)
+ 0x1103, 0x1166, 0x11b2, 0,
+#undef V2897
+#define V2897 (V + 10811)
+ 0x1103, 0x1166, 0x11b3, 0,
+#undef V2898
+#define V2898 (V + 10815)
+ 0x1103, 0x1166, 0x11b4, 0,
+#undef V2899
+#define V2899 (V + 10819)
+ 0x1103, 0x1166, 0x11b5, 0,
+#undef V2900
+#define V2900 (V + 10823)
+ 0x1103, 0x1166, 0x11b6, 0,
+#undef V2901
+#define V2901 (V + 10827)
+ 0x1103, 0x1166, 0x11b7, 0,
+#undef V2902
+#define V2902 (V + 10831)
+ 0x1103, 0x1166, 0x11b8, 0,
+#undef V2903
+#define V2903 (V + 10835)
+ 0x1103, 0x1166, 0x11b9, 0,
+#undef V2904
+#define V2904 (V + 10839)
+ 0x1103, 0x1166, 0x11ba, 0,
+#undef V2905
+#define V2905 (V + 10843)
+ 0x1103, 0x1166, 0x11bb, 0,
+#undef V2906
+#define V2906 (V + 10847)
+ 0x1103, 0x1166, 0x11bc, 0,
+#undef V2907
+#define V2907 (V + 10851)
+ 0x1103, 0x1166, 0x11bd, 0,
+#undef V2908
+#define V2908 (V + 10855)
+ 0x1103, 0x1166, 0x11be, 0,
+#undef V2909
+#define V2909 (V + 10859)
+ 0x1103, 0x1166, 0x11bf, 0,
+#undef V2910
+#define V2910 (V + 10863)
+ 0x1103, 0x1166, 0x11c0, 0,
+#undef V2911
+#define V2911 (V + 10867)
+ 0x1103, 0x1166, 0x11c1, 0,
+#undef V2912
+#define V2912 (V + 10871)
+ 0x1103, 0x1166, 0x11c2, 0,
+#undef V2913
+#define V2913 (V + 10875)
+ 0x1103, 0x1167, 0,
+#undef V2914
+#define V2914 (V + 10878)
+ 0x1103, 0x1167, 0x11a8, 0,
+#undef V2915
+#define V2915 (V + 10882)
+ 0x1103, 0x1167, 0x11a9, 0,
+#undef V2916
+#define V2916 (V + 10886)
+ 0x1103, 0x1167, 0x11aa, 0,
+#undef V2917
+#define V2917 (V + 10890)
+ 0x1103, 0x1167, 0x11ab, 0,
+#undef V2918
+#define V2918 (V + 10894)
+ 0x1103, 0x1167, 0x11ac, 0,
+#undef V2919
+#define V2919 (V + 10898)
+ 0x1103, 0x1167, 0x11ad, 0,
+#undef V2920
+#define V2920 (V + 10902)
+ 0x1103, 0x1167, 0x11ae, 0,
+#undef V2921
+#define V2921 (V + 10906)
+ 0x1103, 0x1167, 0x11af, 0,
+#undef V2922
+#define V2922 (V + 10910)
+ 0x1103, 0x1167, 0x11b0, 0,
+#undef V2923
+#define V2923 (V + 10914)
+ 0x1103, 0x1167, 0x11b1, 0,
+#undef V2924
+#define V2924 (V + 10918)
+ 0x1103, 0x1167, 0x11b2, 0,
+#undef V2925
+#define V2925 (V + 10922)
+ 0x1103, 0x1167, 0x11b3, 0,
+#undef V2926
+#define V2926 (V + 10926)
+ 0x1103, 0x1167, 0x11b4, 0,
+#undef V2927
+#define V2927 (V + 10930)
+ 0x1103, 0x1167, 0x11b5, 0,
+#undef V2928
+#define V2928 (V + 10934)
+ 0x1103, 0x1167, 0x11b6, 0,
+#undef V2929
+#define V2929 (V + 10938)
+ 0x1103, 0x1167, 0x11b7, 0,
+#undef V2930
+#define V2930 (V + 10942)
+ 0x1103, 0x1167, 0x11b8, 0,
+#undef V2931
+#define V2931 (V + 10946)
+ 0x1103, 0x1167, 0x11b9, 0,
+#undef V2932
+#define V2932 (V + 10950)
+ 0x1103, 0x1167, 0x11ba, 0,
+#undef V2933
+#define V2933 (V + 10954)
+ 0x1103, 0x1167, 0x11bb, 0,
+#undef V2934
+#define V2934 (V + 10958)
+ 0x1103, 0x1167, 0x11bc, 0,
+#undef V2935
+#define V2935 (V + 10962)
+ 0x1103, 0x1167, 0x11bd, 0,
+#undef V2936
+#define V2936 (V + 10966)
+ 0x1103, 0x1167, 0x11be, 0,
+#undef V2937
+#define V2937 (V + 10970)
+ 0x1103, 0x1167, 0x11bf, 0,
+#undef V2938
+#define V2938 (V + 10974)
+ 0x1103, 0x1167, 0x11c0, 0,
+#undef V2939
+#define V2939 (V + 10978)
+ 0x1103, 0x1167, 0x11c1, 0,
+#undef V2940
+#define V2940 (V + 10982)
+ 0x1103, 0x1167, 0x11c2, 0,
+#undef V2941
+#define V2941 (V + 10986)
+ 0x1103, 0x1168, 0,
+#undef V2942
+#define V2942 (V + 10989)
+ 0x1103, 0x1168, 0x11a8, 0,
+#undef V2943
+#define V2943 (V + 10993)
+ 0x1103, 0x1168, 0x11a9, 0,
+#undef V2944
+#define V2944 (V + 10997)
+ 0x1103, 0x1168, 0x11aa, 0,
+#undef V2945
+#define V2945 (V + 11001)
+ 0x1103, 0x1168, 0x11ab, 0,
+#undef V2946
+#define V2946 (V + 11005)
+ 0x1103, 0x1168, 0x11ac, 0,
+#undef V2947
+#define V2947 (V + 11009)
+ 0x1103, 0x1168, 0x11ad, 0,
+#undef V2948
+#define V2948 (V + 11013)
+ 0x1103, 0x1168, 0x11ae, 0,
+#undef V2949
+#define V2949 (V + 11017)
+ 0x1103, 0x1168, 0x11af, 0,
+#undef V2950
+#define V2950 (V + 11021)
+ 0x1103, 0x1168, 0x11b0, 0,
+#undef V2951
+#define V2951 (V + 11025)
+ 0x1103, 0x1168, 0x11b1, 0,
+#undef V2952
+#define V2952 (V + 11029)
+ 0x1103, 0x1168, 0x11b2, 0,
+#undef V2953
+#define V2953 (V + 11033)
+ 0x1103, 0x1168, 0x11b3, 0,
+#undef V2954
+#define V2954 (V + 11037)
+ 0x1103, 0x1168, 0x11b4, 0,
+#undef V2955
+#define V2955 (V + 11041)
+ 0x1103, 0x1168, 0x11b5, 0,
+#undef V2956
+#define V2956 (V + 11045)
+ 0x1103, 0x1168, 0x11b6, 0,
+#undef V2957
+#define V2957 (V + 11049)
+ 0x1103, 0x1168, 0x11b7, 0,
+#undef V2958
+#define V2958 (V + 11053)
+ 0x1103, 0x1168, 0x11b8, 0,
+#undef V2959
+#define V2959 (V + 11057)
+ 0x1103, 0x1168, 0x11b9, 0,
+#undef V2960
+#define V2960 (V + 11061)
+ 0x1103, 0x1168, 0x11ba, 0,
+#undef V2961
+#define V2961 (V + 11065)
+ 0x1103, 0x1168, 0x11bb, 0,
+#undef V2962
+#define V2962 (V + 11069)
+ 0x1103, 0x1168, 0x11bc, 0,
+#undef V2963
+#define V2963 (V + 11073)
+ 0x1103, 0x1168, 0x11bd, 0,
+#undef V2964
+#define V2964 (V + 11077)
+ 0x1103, 0x1168, 0x11be, 0,
+#undef V2965
+#define V2965 (V + 11081)
+ 0x1103, 0x1168, 0x11bf, 0,
+#undef V2966
+#define V2966 (V + 11085)
+ 0x1103, 0x1168, 0x11c0, 0,
+#undef V2967
+#define V2967 (V + 11089)
+ 0x1103, 0x1168, 0x11c1, 0,
+#undef V2968
+#define V2968 (V + 11093)
+ 0x1103, 0x1168, 0x11c2, 0,
+#undef V2969
+#define V2969 (V + 11097)
+ 0x1103, 0x1169, 0,
+#undef V2970
+#define V2970 (V + 11100)
+ 0x1103, 0x1169, 0x11a8, 0,
+#undef V2971
+#define V2971 (V + 11104)
+ 0x1103, 0x1169, 0x11a9, 0,
+#undef V2972
+#define V2972 (V + 11108)
+ 0x1103, 0x1169, 0x11aa, 0,
+#undef V2973
+#define V2973 (V + 11112)
+ 0x1103, 0x1169, 0x11ab, 0,
+#undef V2974
+#define V2974 (V + 11116)
+ 0x1103, 0x1169, 0x11ac, 0,
+#undef V2975
+#define V2975 (V + 11120)
+ 0x1103, 0x1169, 0x11ad, 0,
+#undef V2976
+#define V2976 (V + 11124)
+ 0x1103, 0x1169, 0x11ae, 0,
+#undef V2977
+#define V2977 (V + 11128)
+ 0x1103, 0x1169, 0x11af, 0,
+#undef V2978
+#define V2978 (V + 11132)
+ 0x1103, 0x1169, 0x11b0, 0,
+#undef V2979
+#define V2979 (V + 11136)
+ 0x1103, 0x1169, 0x11b1, 0,
+#undef V2980
+#define V2980 (V + 11140)
+ 0x1103, 0x1169, 0x11b2, 0,
+#undef V2981
+#define V2981 (V + 11144)
+ 0x1103, 0x1169, 0x11b3, 0,
+#undef V2982
+#define V2982 (V + 11148)
+ 0x1103, 0x1169, 0x11b4, 0,
+#undef V2983
+#define V2983 (V + 11152)
+ 0x1103, 0x1169, 0x11b5, 0,
+#undef V2984
+#define V2984 (V + 11156)
+ 0x1103, 0x1169, 0x11b6, 0,
+#undef V2985
+#define V2985 (V + 11160)
+ 0x1103, 0x1169, 0x11b7, 0,
+#undef V2986
+#define V2986 (V + 11164)
+ 0x1103, 0x1169, 0x11b8, 0,
+#undef V2987
+#define V2987 (V + 11168)
+ 0x1103, 0x1169, 0x11b9, 0,
+#undef V2988
+#define V2988 (V + 11172)
+ 0x1103, 0x1169, 0x11ba, 0,
+#undef V2989
+#define V2989 (V + 11176)
+ 0x1103, 0x1169, 0x11bb, 0,
+#undef V2990
+#define V2990 (V + 11180)
+ 0x1103, 0x1169, 0x11bc, 0,
+#undef V2991
+#define V2991 (V + 11184)
+ 0x1103, 0x1169, 0x11bd, 0,
+#undef V2992
+#define V2992 (V + 11188)
+ 0x1103, 0x1169, 0x11be, 0,
+#undef V2993
+#define V2993 (V + 11192)
+ 0x1103, 0x1169, 0x11bf, 0,
+#undef V2994
+#define V2994 (V + 11196)
+ 0x1103, 0x1169, 0x11c0, 0,
+#undef V2995
+#define V2995 (V + 11200)
+ 0x1103, 0x1169, 0x11c1, 0,
+#undef V2996
+#define V2996 (V + 11204)
+ 0x1103, 0x1169, 0x11c2, 0,
+#undef V2997
+#define V2997 (V + 11208)
+ 0x1103, 0x116a, 0,
+#undef V2998
+#define V2998 (V + 11211)
+ 0x1103, 0x116a, 0x11a8, 0,
+#undef V2999
+#define V2999 (V + 11215)
+ 0x1103, 0x116a, 0x11a9, 0,
+#undef V3000
+#define V3000 (V + 11219)
+ 0x1103, 0x116a, 0x11aa, 0,
+#undef V3001
+#define V3001 (V + 11223)
+ 0x1103, 0x116a, 0x11ab, 0,
+#undef V3002
+#define V3002 (V + 11227)
+ 0x1103, 0x116a, 0x11ac, 0,
+#undef V3003
+#define V3003 (V + 11231)
+ 0x1103, 0x116a, 0x11ad, 0,
+#undef V3004
+#define V3004 (V + 11235)
+ 0x1103, 0x116a, 0x11ae, 0,
+#undef V3005
+#define V3005 (V + 11239)
+ 0x1103, 0x116a, 0x11af, 0,
+#undef V3006
+#define V3006 (V + 11243)
+ 0x1103, 0x116a, 0x11b0, 0,
+#undef V3007
+#define V3007 (V + 11247)
+ 0x1103, 0x116a, 0x11b1, 0,
+#undef V3008
+#define V3008 (V + 11251)
+ 0x1103, 0x116a, 0x11b2, 0,
+#undef V3009
+#define V3009 (V + 11255)
+ 0x1103, 0x116a, 0x11b3, 0,
+#undef V3010
+#define V3010 (V + 11259)
+ 0x1103, 0x116a, 0x11b4, 0,
+#undef V3011
+#define V3011 (V + 11263)
+ 0x1103, 0x116a, 0x11b5, 0,
+#undef V3012
+#define V3012 (V + 11267)
+ 0x1103, 0x116a, 0x11b6, 0,
+#undef V3013
+#define V3013 (V + 11271)
+ 0x1103, 0x116a, 0x11b7, 0,
+#undef V3014
+#define V3014 (V + 11275)
+ 0x1103, 0x116a, 0x11b8, 0,
+#undef V3015
+#define V3015 (V + 11279)
+ 0x1103, 0x116a, 0x11b9, 0,
+#undef V3016
+#define V3016 (V + 11283)
+ 0x1103, 0x116a, 0x11ba, 0,
+#undef V3017
+#define V3017 (V + 11287)
+ 0x1103, 0x116a, 0x11bb, 0,
+#undef V3018
+#define V3018 (V + 11291)
+ 0x1103, 0x116a, 0x11bc, 0,
+#undef V3019
+#define V3019 (V + 11295)
+ 0x1103, 0x116a, 0x11bd, 0,
+#undef V3020
+#define V3020 (V + 11299)
+ 0x1103, 0x116a, 0x11be, 0,
+#undef V3021
+#define V3021 (V + 11303)
+ 0x1103, 0x116a, 0x11bf, 0,
+#undef V3022
+#define V3022 (V + 11307)
+ 0x1103, 0x116a, 0x11c0, 0,
+#undef V3023
+#define V3023 (V + 11311)
+ 0x1103, 0x116a, 0x11c1, 0,
+#undef V3024
+#define V3024 (V + 11315)
+ 0x1103, 0x116a, 0x11c2, 0,
+#undef V3025
+#define V3025 (V + 11319)
+ 0x1103, 0x116b, 0,
+#undef V3026
+#define V3026 (V + 11322)
+ 0x1103, 0x116b, 0x11a8, 0,
+#undef V3027
+#define V3027 (V + 11326)
+ 0x1103, 0x116b, 0x11a9, 0,
+#undef V3028
+#define V3028 (V + 11330)
+ 0x1103, 0x116b, 0x11aa, 0,
+#undef V3029
+#define V3029 (V + 11334)
+ 0x1103, 0x116b, 0x11ab, 0,
+#undef V3030
+#define V3030 (V + 11338)
+ 0x1103, 0x116b, 0x11ac, 0,
+#undef V3031
+#define V3031 (V + 11342)
+ 0x1103, 0x116b, 0x11ad, 0,
+#undef V3032
+#define V3032 (V + 11346)
+ 0x1103, 0x116b, 0x11ae, 0,
+#undef V3033
+#define V3033 (V + 11350)
+ 0x1103, 0x116b, 0x11af, 0,
+#undef V3034
+#define V3034 (V + 11354)
+ 0x1103, 0x116b, 0x11b0, 0,
+#undef V3035
+#define V3035 (V + 11358)
+ 0x1103, 0x116b, 0x11b1, 0,
+#undef V3036
+#define V3036 (V + 11362)
+ 0x1103, 0x116b, 0x11b2, 0,
+#undef V3037
+#define V3037 (V + 11366)
+ 0x1103, 0x116b, 0x11b3, 0,
+#undef V3038
+#define V3038 (V + 11370)
+ 0x1103, 0x116b, 0x11b4, 0,
+#undef V3039
+#define V3039 (V + 11374)
+ 0x1103, 0x116b, 0x11b5, 0,
+#undef V3040
+#define V3040 (V + 11378)
+ 0x1103, 0x116b, 0x11b6, 0,
+#undef V3041
+#define V3041 (V + 11382)
+ 0x1103, 0x116b, 0x11b7, 0,
+#undef V3042
+#define V3042 (V + 11386)
+ 0x1103, 0x116b, 0x11b8, 0,
+#undef V3043
+#define V3043 (V + 11390)
+ 0x1103, 0x116b, 0x11b9, 0,
+#undef V3044
+#define V3044 (V + 11394)
+ 0x1103, 0x116b, 0x11ba, 0,
+#undef V3045
+#define V3045 (V + 11398)
+ 0x1103, 0x116b, 0x11bb, 0,
+#undef V3046
+#define V3046 (V + 11402)
+ 0x1103, 0x116b, 0x11bc, 0,
+#undef V3047
+#define V3047 (V + 11406)
+ 0x1103, 0x116b, 0x11bd, 0,
+#undef V3048
+#define V3048 (V + 11410)
+ 0x1103, 0x116b, 0x11be, 0,
+#undef V3049
+#define V3049 (V + 11414)
+ 0x1103, 0x116b, 0x11bf, 0,
+#undef V3050
+#define V3050 (V + 11418)
+ 0x1103, 0x116b, 0x11c0, 0,
+#undef V3051
+#define V3051 (V + 11422)
+ 0x1103, 0x116b, 0x11c1, 0,
+#undef V3052
+#define V3052 (V + 11426)
+ 0x1103, 0x116b, 0x11c2, 0,
+#undef V3053
+#define V3053 (V + 11430)
+ 0x1103, 0x116c, 0,
+#undef V3054
+#define V3054 (V + 11433)
+ 0x1103, 0x116c, 0x11a8, 0,
+#undef V3055
+#define V3055 (V + 11437)
+ 0x1103, 0x116c, 0x11a9, 0,
+#undef V3056
+#define V3056 (V + 11441)
+ 0x1103, 0x116c, 0x11aa, 0,
+#undef V3057
+#define V3057 (V + 11445)
+ 0x1103, 0x116c, 0x11ab, 0,
+#undef V3058
+#define V3058 (V + 11449)
+ 0x1103, 0x116c, 0x11ac, 0,
+#undef V3059
+#define V3059 (V + 11453)
+ 0x1103, 0x116c, 0x11ad, 0,
+#undef V3060
+#define V3060 (V + 11457)
+ 0x1103, 0x116c, 0x11ae, 0,
+#undef V3061
+#define V3061 (V + 11461)
+ 0x1103, 0x116c, 0x11af, 0,
+#undef V3062
+#define V3062 (V + 11465)
+ 0x1103, 0x116c, 0x11b0, 0,
+#undef V3063
+#define V3063 (V + 11469)
+ 0x1103, 0x116c, 0x11b1, 0,
+#undef V3064
+#define V3064 (V + 11473)
+ 0x1103, 0x116c, 0x11b2, 0,
+#undef V3065
+#define V3065 (V + 11477)
+ 0x1103, 0x116c, 0x11b3, 0,
+#undef V3066
+#define V3066 (V + 11481)
+ 0x1103, 0x116c, 0x11b4, 0,
+#undef V3067
+#define V3067 (V + 11485)
+ 0x1103, 0x116c, 0x11b5, 0,
+#undef V3068
+#define V3068 (V + 11489)
+ 0x1103, 0x116c, 0x11b6, 0,
+#undef V3069
+#define V3069 (V + 11493)
+ 0x1103, 0x116c, 0x11b7, 0,
+#undef V3070
+#define V3070 (V + 11497)
+ 0x1103, 0x116c, 0x11b8, 0,
+#undef V3071
+#define V3071 (V + 11501)
+ 0x1103, 0x116c, 0x11b9, 0,
+#undef V3072
+#define V3072 (V + 11505)
+ 0x1103, 0x116c, 0x11ba, 0,
+#undef V3073
+#define V3073 (V + 11509)
+ 0x1103, 0x116c, 0x11bb, 0,
+#undef V3074
+#define V3074 (V + 11513)
+ 0x1103, 0x116c, 0x11bc, 0,
+#undef V3075
+#define V3075 (V + 11517)
+ 0x1103, 0x116c, 0x11bd, 0,
+#undef V3076
+#define V3076 (V + 11521)
+ 0x1103, 0x116c, 0x11be, 0,
+#undef V3077
+#define V3077 (V + 11525)
+ 0x1103, 0x116c, 0x11bf, 0,
+#undef V3078
+#define V3078 (V + 11529)
+ 0x1103, 0x116c, 0x11c0, 0,
+#undef V3079
+#define V3079 (V + 11533)
+ 0x1103, 0x116c, 0x11c1, 0,
+#undef V3080
+#define V3080 (V + 11537)
+ 0x1103, 0x116c, 0x11c2, 0,
+#undef V3081
+#define V3081 (V + 11541)
+ 0x1103, 0x116d, 0,
+#undef V3082
+#define V3082 (V + 11544)
+ 0x1103, 0x116d, 0x11a8, 0,
+#undef V3083
+#define V3083 (V + 11548)
+ 0x1103, 0x116d, 0x11a9, 0,
+#undef V3084
+#define V3084 (V + 11552)
+ 0x1103, 0x116d, 0x11aa, 0,
+#undef V3085
+#define V3085 (V + 11556)
+ 0x1103, 0x116d, 0x11ab, 0,
+#undef V3086
+#define V3086 (V + 11560)
+ 0x1103, 0x116d, 0x11ac, 0,
+#undef V3087
+#define V3087 (V + 11564)
+ 0x1103, 0x116d, 0x11ad, 0,
+#undef V3088
+#define V3088 (V + 11568)
+ 0x1103, 0x116d, 0x11ae, 0,
+#undef V3089
+#define V3089 (V + 11572)
+ 0x1103, 0x116d, 0x11af, 0,
+#undef V3090
+#define V3090 (V + 11576)
+ 0x1103, 0x116d, 0x11b0, 0,
+#undef V3091
+#define V3091 (V + 11580)
+ 0x1103, 0x116d, 0x11b1, 0,
+#undef V3092
+#define V3092 (V + 11584)
+ 0x1103, 0x116d, 0x11b2, 0,
+#undef V3093
+#define V3093 (V + 11588)
+ 0x1103, 0x116d, 0x11b3, 0,
+#undef V3094
+#define V3094 (V + 11592)
+ 0x1103, 0x116d, 0x11b4, 0,
+#undef V3095
+#define V3095 (V + 11596)
+ 0x1103, 0x116d, 0x11b5, 0,
+#undef V3096
+#define V3096 (V + 11600)
+ 0x1103, 0x116d, 0x11b6, 0,
+#undef V3097
+#define V3097 (V + 11604)
+ 0x1103, 0x116d, 0x11b7, 0,
+#undef V3098
+#define V3098 (V + 11608)
+ 0x1103, 0x116d, 0x11b8, 0,
+#undef V3099
+#define V3099 (V + 11612)
+ 0x1103, 0x116d, 0x11b9, 0,
+#undef V3100
+#define V3100 (V + 11616)
+ 0x1103, 0x116d, 0x11ba, 0,
+#undef V3101
+#define V3101 (V + 11620)
+ 0x1103, 0x116d, 0x11bb, 0,
+#undef V3102
+#define V3102 (V + 11624)
+ 0x1103, 0x116d, 0x11bc, 0,
+#undef V3103
+#define V3103 (V + 11628)
+ 0x1103, 0x116d, 0x11bd, 0,
+#undef V3104
+#define V3104 (V + 11632)
+ 0x1103, 0x116d, 0x11be, 0,
+#undef V3105
+#define V3105 (V + 11636)
+ 0x1103, 0x116d, 0x11bf, 0,
+#undef V3106
+#define V3106 (V + 11640)
+ 0x1103, 0x116d, 0x11c0, 0,
+#undef V3107
+#define V3107 (V + 11644)
+ 0x1103, 0x116d, 0x11c1, 0,
+#undef V3108
+#define V3108 (V + 11648)
+ 0x1103, 0x116d, 0x11c2, 0,
+#undef V3109
+#define V3109 (V + 11652)
+ 0x1103, 0x116e, 0,
+#undef V3110
+#define V3110 (V + 11655)
+ 0x1103, 0x116e, 0x11a8, 0,
+#undef V3111
+#define V3111 (V + 11659)
+ 0x1103, 0x116e, 0x11a9, 0,
+#undef V3112
+#define V3112 (V + 11663)
+ 0x1103, 0x116e, 0x11aa, 0,
+#undef V3113
+#define V3113 (V + 11667)
+ 0x1103, 0x116e, 0x11ab, 0,
+#undef V3114
+#define V3114 (V + 11671)
+ 0x1103, 0x116e, 0x11ac, 0,
+#undef V3115
+#define V3115 (V + 11675)
+ 0x1103, 0x116e, 0x11ad, 0,
+#undef V3116
+#define V3116 (V + 11679)
+ 0x1103, 0x116e, 0x11ae, 0,
+#undef V3117
+#define V3117 (V + 11683)
+ 0x1103, 0x116e, 0x11af, 0,
+#undef V3118
+#define V3118 (V + 11687)
+ 0x1103, 0x116e, 0x11b0, 0,
+#undef V3119
+#define V3119 (V + 11691)
+ 0x1103, 0x116e, 0x11b1, 0,
+#undef V3120
+#define V3120 (V + 11695)
+ 0x1103, 0x116e, 0x11b2, 0,
+#undef V3121
+#define V3121 (V + 11699)
+ 0x1103, 0x116e, 0x11b3, 0,
+#undef V3122
+#define V3122 (V + 11703)
+ 0x1103, 0x116e, 0x11b4, 0,
+#undef V3123
+#define V3123 (V + 11707)
+ 0x1103, 0x116e, 0x11b5, 0,
+#undef V3124
+#define V3124 (V + 11711)
+ 0x1103, 0x116e, 0x11b6, 0,
+#undef V3125
+#define V3125 (V + 11715)
+ 0x1103, 0x116e, 0x11b7, 0,
+#undef V3126
+#define V3126 (V + 11719)
+ 0x1103, 0x116e, 0x11b8, 0,
+#undef V3127
+#define V3127 (V + 11723)
+ 0x1103, 0x116e, 0x11b9, 0,
+#undef V3128
+#define V3128 (V + 11727)
+ 0x1103, 0x116e, 0x11ba, 0,
+#undef V3129
+#define V3129 (V + 11731)
+ 0x1103, 0x116e, 0x11bb, 0,
+#undef V3130
+#define V3130 (V + 11735)
+ 0x1103, 0x116e, 0x11bc, 0,
+#undef V3131
+#define V3131 (V + 11739)
+ 0x1103, 0x116e, 0x11bd, 0,
+#undef V3132
+#define V3132 (V + 11743)
+ 0x1103, 0x116e, 0x11be, 0,
+#undef V3133
+#define V3133 (V + 11747)
+ 0x1103, 0x116e, 0x11bf, 0,
+#undef V3134
+#define V3134 (V + 11751)
+ 0x1103, 0x116e, 0x11c0, 0,
+#undef V3135
+#define V3135 (V + 11755)
+ 0x1103, 0x116e, 0x11c1, 0,
+#undef V3136
+#define V3136 (V + 11759)
+ 0x1103, 0x116e, 0x11c2, 0,
+#undef V3137
+#define V3137 (V + 11763)
+ 0x1103, 0x116f, 0,
+#undef V3138
+#define V3138 (V + 11766)
+ 0x1103, 0x116f, 0x11a8, 0,
+#undef V3139
+#define V3139 (V + 11770)
+ 0x1103, 0x116f, 0x11a9, 0,
+#undef V3140
+#define V3140 (V + 11774)
+ 0x1103, 0x116f, 0x11aa, 0,
+#undef V3141
+#define V3141 (V + 11778)
+ 0x1103, 0x116f, 0x11ab, 0,
+#undef V3142
+#define V3142 (V + 11782)
+ 0x1103, 0x116f, 0x11ac, 0,
+#undef V3143
+#define V3143 (V + 11786)
+ 0x1103, 0x116f, 0x11ad, 0,
+#undef V3144
+#define V3144 (V + 11790)
+ 0x1103, 0x116f, 0x11ae, 0,
+#undef V3145
+#define V3145 (V + 11794)
+ 0x1103, 0x116f, 0x11af, 0,
+#undef V3146
+#define V3146 (V + 11798)
+ 0x1103, 0x116f, 0x11b0, 0,
+#undef V3147
+#define V3147 (V + 11802)
+ 0x1103, 0x116f, 0x11b1, 0,
+#undef V3148
+#define V3148 (V + 11806)
+ 0x1103, 0x116f, 0x11b2, 0,
+#undef V3149
+#define V3149 (V + 11810)
+ 0x1103, 0x116f, 0x11b3, 0,
+#undef V3150
+#define V3150 (V + 11814)
+ 0x1103, 0x116f, 0x11b4, 0,
+#undef V3151
+#define V3151 (V + 11818)
+ 0x1103, 0x116f, 0x11b5, 0,
+#undef V3152
+#define V3152 (V + 11822)
+ 0x1103, 0x116f, 0x11b6, 0,
+#undef V3153
+#define V3153 (V + 11826)
+ 0x1103, 0x116f, 0x11b7, 0,
+#undef V3154
+#define V3154 (V + 11830)
+ 0x1103, 0x116f, 0x11b8, 0,
+#undef V3155
+#define V3155 (V + 11834)
+ 0x1103, 0x116f, 0x11b9, 0,
+#undef V3156
+#define V3156 (V + 11838)
+ 0x1103, 0x116f, 0x11ba, 0,
+#undef V3157
+#define V3157 (V + 11842)
+ 0x1103, 0x116f, 0x11bb, 0,
+#undef V3158
+#define V3158 (V + 11846)
+ 0x1103, 0x116f, 0x11bc, 0,
+#undef V3159
+#define V3159 (V + 11850)
+ 0x1103, 0x116f, 0x11bd, 0,
+#undef V3160
+#define V3160 (V + 11854)
+ 0x1103, 0x116f, 0x11be, 0,
+#undef V3161
+#define V3161 (V + 11858)
+ 0x1103, 0x116f, 0x11bf, 0,
+#undef V3162
+#define V3162 (V + 11862)
+ 0x1103, 0x116f, 0x11c0, 0,
+#undef V3163
+#define V3163 (V + 11866)
+ 0x1103, 0x116f, 0x11c1, 0,
+#undef V3164
+#define V3164 (V + 11870)
+ 0x1103, 0x116f, 0x11c2, 0,
+#undef V3165
+#define V3165 (V + 11874)
+ 0x1103, 0x1170, 0,
+#undef V3166
+#define V3166 (V + 11877)
+ 0x1103, 0x1170, 0x11a8, 0,
+#undef V3167
+#define V3167 (V + 11881)
+ 0x1103, 0x1170, 0x11a9, 0,
+#undef V3168
+#define V3168 (V + 11885)
+ 0x1103, 0x1170, 0x11aa, 0,
+#undef V3169
+#define V3169 (V + 11889)
+ 0x1103, 0x1170, 0x11ab, 0,
+#undef V3170
+#define V3170 (V + 11893)
+ 0x1103, 0x1170, 0x11ac, 0,
+#undef V3171
+#define V3171 (V + 11897)
+ 0x1103, 0x1170, 0x11ad, 0,
+#undef V3172
+#define V3172 (V + 11901)
+ 0x1103, 0x1170, 0x11ae, 0,
+#undef V3173
+#define V3173 (V + 11905)
+ 0x1103, 0x1170, 0x11af, 0,
+#undef V3174
+#define V3174 (V + 11909)
+ 0x1103, 0x1170, 0x11b0, 0,
+#undef V3175
+#define V3175 (V + 11913)
+ 0x1103, 0x1170, 0x11b1, 0,
+#undef V3176
+#define V3176 (V + 11917)
+ 0x1103, 0x1170, 0x11b2, 0,
+#undef V3177
+#define V3177 (V + 11921)
+ 0x1103, 0x1170, 0x11b3, 0,
+#undef V3178
+#define V3178 (V + 11925)
+ 0x1103, 0x1170, 0x11b4, 0,
+#undef V3179
+#define V3179 (V + 11929)
+ 0x1103, 0x1170, 0x11b5, 0,
+#undef V3180
+#define V3180 (V + 11933)
+ 0x1103, 0x1170, 0x11b6, 0,
+#undef V3181
+#define V3181 (V + 11937)
+ 0x1103, 0x1170, 0x11b7, 0,
+#undef V3182
+#define V3182 (V + 11941)
+ 0x1103, 0x1170, 0x11b8, 0,
+#undef V3183
+#define V3183 (V + 11945)
+ 0x1103, 0x1170, 0x11b9, 0,
+#undef V3184
+#define V3184 (V + 11949)
+ 0x1103, 0x1170, 0x11ba, 0,
+#undef V3185
+#define V3185 (V + 11953)
+ 0x1103, 0x1170, 0x11bb, 0,
+#undef V3186
+#define V3186 (V + 11957)
+ 0x1103, 0x1170, 0x11bc, 0,
+#undef V3187
+#define V3187 (V + 11961)
+ 0x1103, 0x1170, 0x11bd, 0,
+#undef V3188
+#define V3188 (V + 11965)
+ 0x1103, 0x1170, 0x11be, 0,
+#undef V3189
+#define V3189 (V + 11969)
+ 0x1103, 0x1170, 0x11bf, 0,
+#undef V3190
+#define V3190 (V + 11973)
+ 0x1103, 0x1170, 0x11c0, 0,
+#undef V3191
+#define V3191 (V + 11977)
+ 0x1103, 0x1170, 0x11c1, 0,
+#undef V3192
+#define V3192 (V + 11981)
+ 0x1103, 0x1170, 0x11c2, 0,
+#undef V3193
+#define V3193 (V + 11985)
+ 0x1103, 0x1171, 0,
+#undef V3194
+#define V3194 (V + 11988)
+ 0x1103, 0x1171, 0x11a8, 0,
+#undef V3195
+#define V3195 (V + 11992)
+ 0x1103, 0x1171, 0x11a9, 0,
+#undef V3196
+#define V3196 (V + 11996)
+ 0x1103, 0x1171, 0x11aa, 0,
+#undef V3197
+#define V3197 (V + 12000)
+ 0x1103, 0x1171, 0x11ab, 0,
+#undef V3198
+#define V3198 (V + 12004)
+ 0x1103, 0x1171, 0x11ac, 0,
+#undef V3199
+#define V3199 (V + 12008)
+ 0x1103, 0x1171, 0x11ad, 0,
+#undef V3200
+#define V3200 (V + 12012)
+ 0x1103, 0x1171, 0x11ae, 0,
+#undef V3201
+#define V3201 (V + 12016)
+ 0x1103, 0x1171, 0x11af, 0,
+#undef V3202
+#define V3202 (V + 12020)
+ 0x1103, 0x1171, 0x11b0, 0,
+#undef V3203
+#define V3203 (V + 12024)
+ 0x1103, 0x1171, 0x11b1, 0,
+#undef V3204
+#define V3204 (V + 12028)
+ 0x1103, 0x1171, 0x11b2, 0,
+#undef V3205
+#define V3205 (V + 12032)
+ 0x1103, 0x1171, 0x11b3, 0,
+#undef V3206
+#define V3206 (V + 12036)
+ 0x1103, 0x1171, 0x11b4, 0,
+#undef V3207
+#define V3207 (V + 12040)
+ 0x1103, 0x1171, 0x11b5, 0,
+#undef V3208
+#define V3208 (V + 12044)
+ 0x1103, 0x1171, 0x11b6, 0,
+#undef V3209
+#define V3209 (V + 12048)
+ 0x1103, 0x1171, 0x11b7, 0,
+#undef V3210
+#define V3210 (V + 12052)
+ 0x1103, 0x1171, 0x11b8, 0,
+#undef V3211
+#define V3211 (V + 12056)
+ 0x1103, 0x1171, 0x11b9, 0,
+#undef V3212
+#define V3212 (V + 12060)
+ 0x1103, 0x1171, 0x11ba, 0,
+#undef V3213
+#define V3213 (V + 12064)
+ 0x1103, 0x1171, 0x11bb, 0,
+#undef V3214
+#define V3214 (V + 12068)
+ 0x1103, 0x1171, 0x11bc, 0,
+#undef V3215
+#define V3215 (V + 12072)
+ 0x1103, 0x1171, 0x11bd, 0,
+#undef V3216
+#define V3216 (V + 12076)
+ 0x1103, 0x1171, 0x11be, 0,
+#undef V3217
+#define V3217 (V + 12080)
+ 0x1103, 0x1171, 0x11bf, 0,
+#undef V3218
+#define V3218 (V + 12084)
+ 0x1103, 0x1171, 0x11c0, 0,
+#undef V3219
+#define V3219 (V + 12088)
+ 0x1103, 0x1171, 0x11c1, 0,
+#undef V3220
+#define V3220 (V + 12092)
+ 0x1103, 0x1171, 0x11c2, 0,
+#undef V3221
+#define V3221 (V + 12096)
+ 0x1103, 0x1172, 0,
+#undef V3222
+#define V3222 (V + 12099)
+ 0x1103, 0x1172, 0x11a8, 0,
+#undef V3223
+#define V3223 (V + 12103)
+ 0x1103, 0x1172, 0x11a9, 0,
+#undef V3224
+#define V3224 (V + 12107)
+ 0x1103, 0x1172, 0x11aa, 0,
+#undef V3225
+#define V3225 (V + 12111)
+ 0x1103, 0x1172, 0x11ab, 0,
+#undef V3226
+#define V3226 (V + 12115)
+ 0x1103, 0x1172, 0x11ac, 0,
+#undef V3227
+#define V3227 (V + 12119)
+ 0x1103, 0x1172, 0x11ad, 0,
+#undef V3228
+#define V3228 (V + 12123)
+ 0x1103, 0x1172, 0x11ae, 0,
+#undef V3229
+#define V3229 (V + 12127)
+ 0x1103, 0x1172, 0x11af, 0,
+#undef V3230
+#define V3230 (V + 12131)
+ 0x1103, 0x1172, 0x11b0, 0,
+#undef V3231
+#define V3231 (V + 12135)
+ 0x1103, 0x1172, 0x11b1, 0,
+#undef V3232
+#define V3232 (V + 12139)
+ 0x1103, 0x1172, 0x11b2, 0,
+#undef V3233
+#define V3233 (V + 12143)
+ 0x1103, 0x1172, 0x11b3, 0,
+#undef V3234
+#define V3234 (V + 12147)
+ 0x1103, 0x1172, 0x11b4, 0,
+#undef V3235
+#define V3235 (V + 12151)
+ 0x1103, 0x1172, 0x11b5, 0,
+#undef V3236
+#define V3236 (V + 12155)
+ 0x1103, 0x1172, 0x11b6, 0,
+#undef V3237
+#define V3237 (V + 12159)
+ 0x1103, 0x1172, 0x11b7, 0,
+#undef V3238
+#define V3238 (V + 12163)
+ 0x1103, 0x1172, 0x11b8, 0,
+#undef V3239
+#define V3239 (V + 12167)
+ 0x1103, 0x1172, 0x11b9, 0,
+#undef V3240
+#define V3240 (V + 12171)
+ 0x1103, 0x1172, 0x11ba, 0,
+#undef V3241
+#define V3241 (V + 12175)
+ 0x1103, 0x1172, 0x11bb, 0,
+#undef V3242
+#define V3242 (V + 12179)
+ 0x1103, 0x1172, 0x11bc, 0,
+#undef V3243
+#define V3243 (V + 12183)
+ 0x1103, 0x1172, 0x11bd, 0,
+#undef V3244
+#define V3244 (V + 12187)
+ 0x1103, 0x1172, 0x11be, 0,
+#undef V3245
+#define V3245 (V + 12191)
+ 0x1103, 0x1172, 0x11bf, 0,
+#undef V3246
+#define V3246 (V + 12195)
+ 0x1103, 0x1172, 0x11c0, 0,
+#undef V3247
+#define V3247 (V + 12199)
+ 0x1103, 0x1172, 0x11c1, 0,
+#undef V3248
+#define V3248 (V + 12203)
+ 0x1103, 0x1172, 0x11c2, 0,
+#undef V3249
+#define V3249 (V + 12207)
+ 0x1103, 0x1173, 0,
+#undef V3250
+#define V3250 (V + 12210)
+ 0x1103, 0x1173, 0x11a8, 0,
+#undef V3251
+#define V3251 (V + 12214)
+ 0x1103, 0x1173, 0x11a9, 0,
+#undef V3252
+#define V3252 (V + 12218)
+ 0x1103, 0x1173, 0x11aa, 0,
+#undef V3253
+#define V3253 (V + 12222)
+ 0x1103, 0x1173, 0x11ab, 0,
+#undef V3254
+#define V3254 (V + 12226)
+ 0x1103, 0x1173, 0x11ac, 0,
+#undef V3255
+#define V3255 (V + 12230)
+ 0x1103, 0x1173, 0x11ad, 0,
+#undef V3256
+#define V3256 (V + 12234)
+ 0x1103, 0x1173, 0x11ae, 0,
+#undef V3257
+#define V3257 (V + 12238)
+ 0x1103, 0x1173, 0x11af, 0,
+#undef V3258
+#define V3258 (V + 12242)
+ 0x1103, 0x1173, 0x11b0, 0,
+#undef V3259
+#define V3259 (V + 12246)
+ 0x1103, 0x1173, 0x11b1, 0,
+#undef V3260
+#define V3260 (V + 12250)
+ 0x1103, 0x1173, 0x11b2, 0,
+#undef V3261
+#define V3261 (V + 12254)
+ 0x1103, 0x1173, 0x11b3, 0,
+#undef V3262
+#define V3262 (V + 12258)
+ 0x1103, 0x1173, 0x11b4, 0,
+#undef V3263
+#define V3263 (V + 12262)
+ 0x1103, 0x1173, 0x11b5, 0,
+#undef V3264
+#define V3264 (V + 12266)
+ 0x1103, 0x1173, 0x11b6, 0,
+#undef V3265
+#define V3265 (V + 12270)
+ 0x1103, 0x1173, 0x11b7, 0,
+#undef V3266
+#define V3266 (V + 12274)
+ 0x1103, 0x1173, 0x11b8, 0,
+#undef V3267
+#define V3267 (V + 12278)
+ 0x1103, 0x1173, 0x11b9, 0,
+#undef V3268
+#define V3268 (V + 12282)
+ 0x1103, 0x1173, 0x11ba, 0,
+#undef V3269
+#define V3269 (V + 12286)
+ 0x1103, 0x1173, 0x11bb, 0,
+#undef V3270
+#define V3270 (V + 12290)
+ 0x1103, 0x1173, 0x11bc, 0,
+#undef V3271
+#define V3271 (V + 12294)
+ 0x1103, 0x1173, 0x11bd, 0,
+#undef V3272
+#define V3272 (V + 12298)
+ 0x1103, 0x1173, 0x11be, 0,
+#undef V3273
+#define V3273 (V + 12302)
+ 0x1103, 0x1173, 0x11bf, 0,
+#undef V3274
+#define V3274 (V + 12306)
+ 0x1103, 0x1173, 0x11c0, 0,
+#undef V3275
+#define V3275 (V + 12310)
+ 0x1103, 0x1173, 0x11c1, 0,
+#undef V3276
+#define V3276 (V + 12314)
+ 0x1103, 0x1173, 0x11c2, 0,
+#undef V3277
+#define V3277 (V + 12318)
+ 0x1103, 0x1174, 0,
+#undef V3278
+#define V3278 (V + 12321)
+ 0x1103, 0x1174, 0x11a8, 0,
+#undef V3279
+#define V3279 (V + 12325)
+ 0x1103, 0x1174, 0x11a9, 0,
+#undef V3280
+#define V3280 (V + 12329)
+ 0x1103, 0x1174, 0x11aa, 0,
+#undef V3281
+#define V3281 (V + 12333)
+ 0x1103, 0x1174, 0x11ab, 0,
+#undef V3282
+#define V3282 (V + 12337)
+ 0x1103, 0x1174, 0x11ac, 0,
+#undef V3283
+#define V3283 (V + 12341)
+ 0x1103, 0x1174, 0x11ad, 0,
+#undef V3284
+#define V3284 (V + 12345)
+ 0x1103, 0x1174, 0x11ae, 0,
+#undef V3285
+#define V3285 (V + 12349)
+ 0x1103, 0x1174, 0x11af, 0,
+#undef V3286
+#define V3286 (V + 12353)
+ 0x1103, 0x1174, 0x11b0, 0,
+#undef V3287
+#define V3287 (V + 12357)
+ 0x1103, 0x1174, 0x11b1, 0,
+#undef V3288
+#define V3288 (V + 12361)
+ 0x1103, 0x1174, 0x11b2, 0,
+#undef V3289
+#define V3289 (V + 12365)
+ 0x1103, 0x1174, 0x11b3, 0,
+#undef V3290
+#define V3290 (V + 12369)
+ 0x1103, 0x1174, 0x11b4, 0,
+#undef V3291
+#define V3291 (V + 12373)
+ 0x1103, 0x1174, 0x11b5, 0,
+#undef V3292
+#define V3292 (V + 12377)
+ 0x1103, 0x1174, 0x11b6, 0,
+#undef V3293
+#define V3293 (V + 12381)
+ 0x1103, 0x1174, 0x11b7, 0,
+#undef V3294
+#define V3294 (V + 12385)
+ 0x1103, 0x1174, 0x11b8, 0,
+#undef V3295
+#define V3295 (V + 12389)
+ 0x1103, 0x1174, 0x11b9, 0,
+#undef V3296
+#define V3296 (V + 12393)
+ 0x1103, 0x1174, 0x11ba, 0,
+#undef V3297
+#define V3297 (V + 12397)
+ 0x1103, 0x1174, 0x11bb, 0,
+#undef V3298
+#define V3298 (V + 12401)
+ 0x1103, 0x1174, 0x11bc, 0,
+#undef V3299
+#define V3299 (V + 12405)
+ 0x1103, 0x1174, 0x11bd, 0,
+#undef V3300
+#define V3300 (V + 12409)
+ 0x1103, 0x1174, 0x11be, 0,
+#undef V3301
+#define V3301 (V + 12413)
+ 0x1103, 0x1174, 0x11bf, 0,
+#undef V3302
+#define V3302 (V + 12417)
+ 0x1103, 0x1174, 0x11c0, 0,
+#undef V3303
+#define V3303 (V + 12421)
+ 0x1103, 0x1174, 0x11c1, 0,
+#undef V3304
+#define V3304 (V + 12425)
+ 0x1103, 0x1174, 0x11c2, 0,
+#undef V3305
+#define V3305 (V + 12429)
+ 0x1103, 0x1175, 0,
+#undef V3306
+#define V3306 (V + 12432)
+ 0x1103, 0x1175, 0x11a8, 0,
+#undef V3307
+#define V3307 (V + 12436)
+ 0x1103, 0x1175, 0x11a9, 0,
+#undef V3308
+#define V3308 (V + 12440)
+ 0x1103, 0x1175, 0x11aa, 0,
+#undef V3309
+#define V3309 (V + 12444)
+ 0x1103, 0x1175, 0x11ab, 0,
+#undef V3310
+#define V3310 (V + 12448)
+ 0x1103, 0x1175, 0x11ac, 0,
+#undef V3311
+#define V3311 (V + 12452)
+ 0x1103, 0x1175, 0x11ad, 0,
+#undef V3312
+#define V3312 (V + 12456)
+ 0x1103, 0x1175, 0x11ae, 0,
+#undef V3313
+#define V3313 (V + 12460)
+ 0x1103, 0x1175, 0x11af, 0,
+#undef V3314
+#define V3314 (V + 12464)
+ 0x1103, 0x1175, 0x11b0, 0,
+#undef V3315
+#define V3315 (V + 12468)
+ 0x1103, 0x1175, 0x11b1, 0,
+#undef V3316
+#define V3316 (V + 12472)
+ 0x1103, 0x1175, 0x11b2, 0,
+#undef V3317
+#define V3317 (V + 12476)
+ 0x1103, 0x1175, 0x11b3, 0,
+#undef V3318
+#define V3318 (V + 12480)
+ 0x1103, 0x1175, 0x11b4, 0,
+#undef V3319
+#define V3319 (V + 12484)
+ 0x1103, 0x1175, 0x11b5, 0,
+#undef V3320
+#define V3320 (V + 12488)
+ 0x1103, 0x1175, 0x11b6, 0,
+#undef V3321
+#define V3321 (V + 12492)
+ 0x1103, 0x1175, 0x11b7, 0,
+#undef V3322
+#define V3322 (V + 12496)
+ 0x1103, 0x1175, 0x11b8, 0,
+#undef V3323
+#define V3323 (V + 12500)
+ 0x1103, 0x1175, 0x11b9, 0,
+#undef V3324
+#define V3324 (V + 12504)
+ 0x1103, 0x1175, 0x11ba, 0,
+#undef V3325
+#define V3325 (V + 12508)
+ 0x1103, 0x1175, 0x11bb, 0,
+#undef V3326
+#define V3326 (V + 12512)
+ 0x1103, 0x1175, 0x11bc, 0,
+#undef V3327
+#define V3327 (V + 12516)
+ 0x1103, 0x1175, 0x11bd, 0,
+#undef V3328
+#define V3328 (V + 12520)
+ 0x1103, 0x1175, 0x11be, 0,
+#undef V3329
+#define V3329 (V + 12524)
+ 0x1103, 0x1175, 0x11bf, 0,
+#undef V3330
+#define V3330 (V + 12528)
+ 0x1103, 0x1175, 0x11c0, 0,
+#undef V3331
+#define V3331 (V + 12532)
+ 0x1103, 0x1175, 0x11c1, 0,
+#undef V3332
+#define V3332 (V + 12536)
+ 0x1103, 0x1175, 0x11c2, 0,
+#undef V3333
+#define V3333 (V + 12540)
+ 0x1104, 0x1161, 0,
+#undef V3334
+#define V3334 (V + 12543)
+ 0x1104, 0x1161, 0x11a8, 0,
+#undef V3335
+#define V3335 (V + 12547)
+ 0x1104, 0x1161, 0x11a9, 0,
+#undef V3336
+#define V3336 (V + 12551)
+ 0x1104, 0x1161, 0x11aa, 0,
+#undef V3337
+#define V3337 (V + 12555)
+ 0x1104, 0x1161, 0x11ab, 0,
+#undef V3338
+#define V3338 (V + 12559)
+ 0x1104, 0x1161, 0x11ac, 0,
+#undef V3339
+#define V3339 (V + 12563)
+ 0x1104, 0x1161, 0x11ad, 0,
+#undef V3340
+#define V3340 (V + 12567)
+ 0x1104, 0x1161, 0x11ae, 0,
+#undef V3341
+#define V3341 (V + 12571)
+ 0x1104, 0x1161, 0x11af, 0,
+#undef V3342
+#define V3342 (V + 12575)
+ 0x1104, 0x1161, 0x11b0, 0,
+#undef V3343
+#define V3343 (V + 12579)
+ 0x1104, 0x1161, 0x11b1, 0,
+#undef V3344
+#define V3344 (V + 12583)
+ 0x1104, 0x1161, 0x11b2, 0,
+#undef V3345
+#define V3345 (V + 12587)
+ 0x1104, 0x1161, 0x11b3, 0,
+#undef V3346
+#define V3346 (V + 12591)
+ 0x1104, 0x1161, 0x11b4, 0,
+#undef V3347
+#define V3347 (V + 12595)
+ 0x1104, 0x1161, 0x11b5, 0,
+#undef V3348
+#define V3348 (V + 12599)
+ 0x1104, 0x1161, 0x11b6, 0,
+#undef V3349
+#define V3349 (V + 12603)
+ 0x1104, 0x1161, 0x11b7, 0,
+#undef V3350
+#define V3350 (V + 12607)
+ 0x1104, 0x1161, 0x11b8, 0,
+#undef V3351
+#define V3351 (V + 12611)
+ 0x1104, 0x1161, 0x11b9, 0,
+#undef V3352
+#define V3352 (V + 12615)
+ 0x1104, 0x1161, 0x11ba, 0,
+#undef V3353
+#define V3353 (V + 12619)
+ 0x1104, 0x1161, 0x11bb, 0,
+#undef V3354
+#define V3354 (V + 12623)
+ 0x1104, 0x1161, 0x11bc, 0,
+#undef V3355
+#define V3355 (V + 12627)
+ 0x1104, 0x1161, 0x11bd, 0,
+#undef V3356
+#define V3356 (V + 12631)
+ 0x1104, 0x1161, 0x11be, 0,
+#undef V3357
+#define V3357 (V + 12635)
+ 0x1104, 0x1161, 0x11bf, 0,
+#undef V3358
+#define V3358 (V + 12639)
+ 0x1104, 0x1161, 0x11c0, 0,
+#undef V3359
+#define V3359 (V + 12643)
+ 0x1104, 0x1161, 0x11c1, 0,
+#undef V3360
+#define V3360 (V + 12647)
+ 0x1104, 0x1161, 0x11c2, 0,
+#undef V3361
+#define V3361 (V + 12651)
+ 0x1104, 0x1162, 0,
+#undef V3362
+#define V3362 (V + 12654)
+ 0x1104, 0x1162, 0x11a8, 0,
+#undef V3363
+#define V3363 (V + 12658)
+ 0x1104, 0x1162, 0x11a9, 0,
+#undef V3364
+#define V3364 (V + 12662)
+ 0x1104, 0x1162, 0x11aa, 0,
+#undef V3365
+#define V3365 (V + 12666)
+ 0x1104, 0x1162, 0x11ab, 0,
+#undef V3366
+#define V3366 (V + 12670)
+ 0x1104, 0x1162, 0x11ac, 0,
+#undef V3367
+#define V3367 (V + 12674)
+ 0x1104, 0x1162, 0x11ad, 0,
+#undef V3368
+#define V3368 (V + 12678)
+ 0x1104, 0x1162, 0x11ae, 0,
+#undef V3369
+#define V3369 (V + 12682)
+ 0x1104, 0x1162, 0x11af, 0,
+#undef V3370
+#define V3370 (V + 12686)
+ 0x1104, 0x1162, 0x11b0, 0,
+#undef V3371
+#define V3371 (V + 12690)
+ 0x1104, 0x1162, 0x11b1, 0,
+#undef V3372
+#define V3372 (V + 12694)
+ 0x1104, 0x1162, 0x11b2, 0,
+#undef V3373
+#define V3373 (V + 12698)
+ 0x1104, 0x1162, 0x11b3, 0,
+#undef V3374
+#define V3374 (V + 12702)
+ 0x1104, 0x1162, 0x11b4, 0,
+#undef V3375
+#define V3375 (V + 12706)
+ 0x1104, 0x1162, 0x11b5, 0,
+#undef V3376
+#define V3376 (V + 12710)
+ 0x1104, 0x1162, 0x11b6, 0,
+#undef V3377
+#define V3377 (V + 12714)
+ 0x1104, 0x1162, 0x11b7, 0,
+#undef V3378
+#define V3378 (V + 12718)
+ 0x1104, 0x1162, 0x11b8, 0,
+#undef V3379
+#define V3379 (V + 12722)
+ 0x1104, 0x1162, 0x11b9, 0,
+#undef V3380
+#define V3380 (V + 12726)
+ 0x1104, 0x1162, 0x11ba, 0,
+#undef V3381
+#define V3381 (V + 12730)
+ 0x1104, 0x1162, 0x11bb, 0,
+#undef V3382
+#define V3382 (V + 12734)
+ 0x1104, 0x1162, 0x11bc, 0,
+#undef V3383
+#define V3383 (V + 12738)
+ 0x1104, 0x1162, 0x11bd, 0,
+#undef V3384
+#define V3384 (V + 12742)
+ 0x1104, 0x1162, 0x11be, 0,
+#undef V3385
+#define V3385 (V + 12746)
+ 0x1104, 0x1162, 0x11bf, 0,
+#undef V3386
+#define V3386 (V + 12750)
+ 0x1104, 0x1162, 0x11c0, 0,
+#undef V3387
+#define V3387 (V + 12754)
+ 0x1104, 0x1162, 0x11c1, 0,
+#undef V3388
+#define V3388 (V + 12758)
+ 0x1104, 0x1162, 0x11c2, 0,
+#undef V3389
+#define V3389 (V + 12762)
+ 0x1104, 0x1163, 0,
+#undef V3390
+#define V3390 (V + 12765)
+ 0x1104, 0x1163, 0x11a8, 0,
+#undef V3391
+#define V3391 (V + 12769)
+ 0x1104, 0x1163, 0x11a9, 0,
+#undef V3392
+#define V3392 (V + 12773)
+ 0x1104, 0x1163, 0x11aa, 0,
+#undef V3393
+#define V3393 (V + 12777)
+ 0x1104, 0x1163, 0x11ab, 0,
+#undef V3394
+#define V3394 (V + 12781)
+ 0x1104, 0x1163, 0x11ac, 0,
+#undef V3395
+#define V3395 (V + 12785)
+ 0x1104, 0x1163, 0x11ad, 0,
+#undef V3396
+#define V3396 (V + 12789)
+ 0x1104, 0x1163, 0x11ae, 0,
+#undef V3397
+#define V3397 (V + 12793)
+ 0x1104, 0x1163, 0x11af, 0,
+#undef V3398
+#define V3398 (V + 12797)
+ 0x1104, 0x1163, 0x11b0, 0,
+#undef V3399
+#define V3399 (V + 12801)
+ 0x1104, 0x1163, 0x11b1, 0,
+#undef V3400
+#define V3400 (V + 12805)
+ 0x1104, 0x1163, 0x11b2, 0,
+#undef V3401
+#define V3401 (V + 12809)
+ 0x1104, 0x1163, 0x11b3, 0,
+#undef V3402
+#define V3402 (V + 12813)
+ 0x1104, 0x1163, 0x11b4, 0,
+#undef V3403
+#define V3403 (V + 12817)
+ 0x1104, 0x1163, 0x11b5, 0,
+#undef V3404
+#define V3404 (V + 12821)
+ 0x1104, 0x1163, 0x11b6, 0,
+#undef V3405
+#define V3405 (V + 12825)
+ 0x1104, 0x1163, 0x11b7, 0,
+#undef V3406
+#define V3406 (V + 12829)
+ 0x1104, 0x1163, 0x11b8, 0,
+#undef V3407
+#define V3407 (V + 12833)
+ 0x1104, 0x1163, 0x11b9, 0,
+#undef V3408
+#define V3408 (V + 12837)
+ 0x1104, 0x1163, 0x11ba, 0,
+#undef V3409
+#define V3409 (V + 12841)
+ 0x1104, 0x1163, 0x11bb, 0,
+#undef V3410
+#define V3410 (V + 12845)
+ 0x1104, 0x1163, 0x11bc, 0,
+#undef V3411
+#define V3411 (V + 12849)
+ 0x1104, 0x1163, 0x11bd, 0,
+#undef V3412
+#define V3412 (V + 12853)
+ 0x1104, 0x1163, 0x11be, 0,
+#undef V3413
+#define V3413 (V + 12857)
+ 0x1104, 0x1163, 0x11bf, 0,
+#undef V3414
+#define V3414 (V + 12861)
+ 0x1104, 0x1163, 0x11c0, 0,
+#undef V3415
+#define V3415 (V + 12865)
+ 0x1104, 0x1163, 0x11c1, 0,
+#undef V3416
+#define V3416 (V + 12869)
+ 0x1104, 0x1163, 0x11c2, 0,
+#undef V3417
+#define V3417 (V + 12873)
+ 0x1104, 0x1164, 0,
+#undef V3418
+#define V3418 (V + 12876)
+ 0x1104, 0x1164, 0x11a8, 0,
+#undef V3419
+#define V3419 (V + 12880)
+ 0x1104, 0x1164, 0x11a9, 0,
+#undef V3420
+#define V3420 (V + 12884)
+ 0x1104, 0x1164, 0x11aa, 0,
+#undef V3421
+#define V3421 (V + 12888)
+ 0x1104, 0x1164, 0x11ab, 0,
+#undef V3422
+#define V3422 (V + 12892)
+ 0x1104, 0x1164, 0x11ac, 0,
+#undef V3423
+#define V3423 (V + 12896)
+ 0x1104, 0x1164, 0x11ad, 0,
+#undef V3424
+#define V3424 (V + 12900)
+ 0x1104, 0x1164, 0x11ae, 0,
+#undef V3425
+#define V3425 (V + 12904)
+ 0x1104, 0x1164, 0x11af, 0,
+#undef V3426
+#define V3426 (V + 12908)
+ 0x1104, 0x1164, 0x11b0, 0,
+#undef V3427
+#define V3427 (V + 12912)
+ 0x1104, 0x1164, 0x11b1, 0,
+#undef V3428
+#define V3428 (V + 12916)
+ 0x1104, 0x1164, 0x11b2, 0,
+#undef V3429
+#define V3429 (V + 12920)
+ 0x1104, 0x1164, 0x11b3, 0,
+#undef V3430
+#define V3430 (V + 12924)
+ 0x1104, 0x1164, 0x11b4, 0,
+#undef V3431
+#define V3431 (V + 12928)
+ 0x1104, 0x1164, 0x11b5, 0,
+#undef V3432
+#define V3432 (V + 12932)
+ 0x1104, 0x1164, 0x11b6, 0,
+#undef V3433
+#define V3433 (V + 12936)
+ 0x1104, 0x1164, 0x11b7, 0,
+#undef V3434
+#define V3434 (V + 12940)
+ 0x1104, 0x1164, 0x11b8, 0,
+#undef V3435
+#define V3435 (V + 12944)
+ 0x1104, 0x1164, 0x11b9, 0,
+#undef V3436
+#define V3436 (V + 12948)
+ 0x1104, 0x1164, 0x11ba, 0,
+#undef V3437
+#define V3437 (V + 12952)
+ 0x1104, 0x1164, 0x11bb, 0,
+#undef V3438
+#define V3438 (V + 12956)
+ 0x1104, 0x1164, 0x11bc, 0,
+#undef V3439
+#define V3439 (V + 12960)
+ 0x1104, 0x1164, 0x11bd, 0,
+#undef V3440
+#define V3440 (V + 12964)
+ 0x1104, 0x1164, 0x11be, 0,
+#undef V3441
+#define V3441 (V + 12968)
+ 0x1104, 0x1164, 0x11bf, 0,
+#undef V3442
+#define V3442 (V + 12972)
+ 0x1104, 0x1164, 0x11c0, 0,
+#undef V3443
+#define V3443 (V + 12976)
+ 0x1104, 0x1164, 0x11c1, 0,
+#undef V3444
+#define V3444 (V + 12980)
+ 0x1104, 0x1164, 0x11c2, 0,
+#undef V3445
+#define V3445 (V + 12984)
+ 0x1104, 0x1165, 0,
+#undef V3446
+#define V3446 (V + 12987)
+ 0x1104, 0x1165, 0x11a8, 0,
+#undef V3447
+#define V3447 (V + 12991)
+ 0x1104, 0x1165, 0x11a9, 0,
+#undef V3448
+#define V3448 (V + 12995)
+ 0x1104, 0x1165, 0x11aa, 0,
+#undef V3449
+#define V3449 (V + 12999)
+ 0x1104, 0x1165, 0x11ab, 0,
+#undef V3450
+#define V3450 (V + 13003)
+ 0x1104, 0x1165, 0x11ac, 0,
+#undef V3451
+#define V3451 (V + 13007)
+ 0x1104, 0x1165, 0x11ad, 0,
+#undef V3452
+#define V3452 (V + 13011)
+ 0x1104, 0x1165, 0x11ae, 0,
+#undef V3453
+#define V3453 (V + 13015)
+ 0x1104, 0x1165, 0x11af, 0,
+#undef V3454
+#define V3454 (V + 13019)
+ 0x1104, 0x1165, 0x11b0, 0,
+#undef V3455
+#define V3455 (V + 13023)
+ 0x1104, 0x1165, 0x11b1, 0,
+#undef V3456
+#define V3456 (V + 13027)
+ 0x1104, 0x1165, 0x11b2, 0,
+#undef V3457
+#define V3457 (V + 13031)
+ 0x1104, 0x1165, 0x11b3, 0,
+#undef V3458
+#define V3458 (V + 13035)
+ 0x1104, 0x1165, 0x11b4, 0,
+#undef V3459
+#define V3459 (V + 13039)
+ 0x1104, 0x1165, 0x11b5, 0,
+#undef V3460
+#define V3460 (V + 13043)
+ 0x1104, 0x1165, 0x11b6, 0,
+#undef V3461
+#define V3461 (V + 13047)
+ 0x1104, 0x1165, 0x11b7, 0,
+#undef V3462
+#define V3462 (V + 13051)
+ 0x1104, 0x1165, 0x11b8, 0,
+#undef V3463
+#define V3463 (V + 13055)
+ 0x1104, 0x1165, 0x11b9, 0,
+#undef V3464
+#define V3464 (V + 13059)
+ 0x1104, 0x1165, 0x11ba, 0,
+#undef V3465
+#define V3465 (V + 13063)
+ 0x1104, 0x1165, 0x11bb, 0,
+#undef V3466
+#define V3466 (V + 13067)
+ 0x1104, 0x1165, 0x11bc, 0,
+#undef V3467
+#define V3467 (V + 13071)
+ 0x1104, 0x1165, 0x11bd, 0,
+#undef V3468
+#define V3468 (V + 13075)
+ 0x1104, 0x1165, 0x11be, 0,
+#undef V3469
+#define V3469 (V + 13079)
+ 0x1104, 0x1165, 0x11bf, 0,
+#undef V3470
+#define V3470 (V + 13083)
+ 0x1104, 0x1165, 0x11c0, 0,
+#undef V3471
+#define V3471 (V + 13087)
+ 0x1104, 0x1165, 0x11c1, 0,
+#undef V3472
+#define V3472 (V + 13091)
+ 0x1104, 0x1165, 0x11c2, 0,
+#undef V3473
+#define V3473 (V + 13095)
+ 0x1104, 0x1166, 0,
+#undef V3474
+#define V3474 (V + 13098)
+ 0x1104, 0x1166, 0x11a8, 0,
+#undef V3475
+#define V3475 (V + 13102)
+ 0x1104, 0x1166, 0x11a9, 0,
+#undef V3476
+#define V3476 (V + 13106)
+ 0x1104, 0x1166, 0x11aa, 0,
+#undef V3477
+#define V3477 (V + 13110)
+ 0x1104, 0x1166, 0x11ab, 0,
+#undef V3478
+#define V3478 (V + 13114)
+ 0x1104, 0x1166, 0x11ac, 0,
+#undef V3479
+#define V3479 (V + 13118)
+ 0x1104, 0x1166, 0x11ad, 0,
+#undef V3480
+#define V3480 (V + 13122)
+ 0x1104, 0x1166, 0x11ae, 0,
+#undef V3481
+#define V3481 (V + 13126)
+ 0x1104, 0x1166, 0x11af, 0,
+#undef V3482
+#define V3482 (V + 13130)
+ 0x1104, 0x1166, 0x11b0, 0,
+#undef V3483
+#define V3483 (V + 13134)
+ 0x1104, 0x1166, 0x11b1, 0,
+#undef V3484
+#define V3484 (V + 13138)
+ 0x1104, 0x1166, 0x11b2, 0,
+#undef V3485
+#define V3485 (V + 13142)
+ 0x1104, 0x1166, 0x11b3, 0,
+#undef V3486
+#define V3486 (V + 13146)
+ 0x1104, 0x1166, 0x11b4, 0,
+#undef V3487
+#define V3487 (V + 13150)
+ 0x1104, 0x1166, 0x11b5, 0,
+#undef V3488
+#define V3488 (V + 13154)
+ 0x1104, 0x1166, 0x11b6, 0,
+#undef V3489
+#define V3489 (V + 13158)
+ 0x1104, 0x1166, 0x11b7, 0,
+#undef V3490
+#define V3490 (V + 13162)
+ 0x1104, 0x1166, 0x11b8, 0,
+#undef V3491
+#define V3491 (V + 13166)
+ 0x1104, 0x1166, 0x11b9, 0,
+#undef V3492
+#define V3492 (V + 13170)
+ 0x1104, 0x1166, 0x11ba, 0,
+#undef V3493
+#define V3493 (V + 13174)
+ 0x1104, 0x1166, 0x11bb, 0,
+#undef V3494
+#define V3494 (V + 13178)
+ 0x1104, 0x1166, 0x11bc, 0,
+#undef V3495
+#define V3495 (V + 13182)
+ 0x1104, 0x1166, 0x11bd, 0,
+#undef V3496
+#define V3496 (V + 13186)
+ 0x1104, 0x1166, 0x11be, 0,
+#undef V3497
+#define V3497 (V + 13190)
+ 0x1104, 0x1166, 0x11bf, 0,
+#undef V3498
+#define V3498 (V + 13194)
+ 0x1104, 0x1166, 0x11c0, 0,
+#undef V3499
+#define V3499 (V + 13198)
+ 0x1104, 0x1166, 0x11c1, 0,
+#undef V3500
+#define V3500 (V + 13202)
+ 0x1104, 0x1166, 0x11c2, 0,
+#undef V3501
+#define V3501 (V + 13206)
+ 0x1104, 0x1167, 0,
+#undef V3502
+#define V3502 (V + 13209)
+ 0x1104, 0x1167, 0x11a8, 0,
+#undef V3503
+#define V3503 (V + 13213)
+ 0x1104, 0x1167, 0x11a9, 0,
+#undef V3504
+#define V3504 (V + 13217)
+ 0x1104, 0x1167, 0x11aa, 0,
+#undef V3505
+#define V3505 (V + 13221)
+ 0x1104, 0x1167, 0x11ab, 0,
+#undef V3506
+#define V3506 (V + 13225)
+ 0x1104, 0x1167, 0x11ac, 0,
+#undef V3507
+#define V3507 (V + 13229)
+ 0x1104, 0x1167, 0x11ad, 0,
+#undef V3508
+#define V3508 (V + 13233)
+ 0x1104, 0x1167, 0x11ae, 0,
+#undef V3509
+#define V3509 (V + 13237)
+ 0x1104, 0x1167, 0x11af, 0,
+#undef V3510
+#define V3510 (V + 13241)
+ 0x1104, 0x1167, 0x11b0, 0,
+#undef V3511
+#define V3511 (V + 13245)
+ 0x1104, 0x1167, 0x11b1, 0,
+#undef V3512
+#define V3512 (V + 13249)
+ 0x1104, 0x1167, 0x11b2, 0,
+#undef V3513
+#define V3513 (V + 13253)
+ 0x1104, 0x1167, 0x11b3, 0,
+#undef V3514
+#define V3514 (V + 13257)
+ 0x1104, 0x1167, 0x11b4, 0,
+#undef V3515
+#define V3515 (V + 13261)
+ 0x1104, 0x1167, 0x11b5, 0,
+#undef V3516
+#define V3516 (V + 13265)
+ 0x1104, 0x1167, 0x11b6, 0,
+#undef V3517
+#define V3517 (V + 13269)
+ 0x1104, 0x1167, 0x11b7, 0,
+#undef V3518
+#define V3518 (V + 13273)
+ 0x1104, 0x1167, 0x11b8, 0,
+#undef V3519
+#define V3519 (V + 13277)
+ 0x1104, 0x1167, 0x11b9, 0,
+#undef V3520
+#define V3520 (V + 13281)
+ 0x1104, 0x1167, 0x11ba, 0,
+#undef V3521
+#define V3521 (V + 13285)
+ 0x1104, 0x1167, 0x11bb, 0,
+#undef V3522
+#define V3522 (V + 13289)
+ 0x1104, 0x1167, 0x11bc, 0,
+#undef V3523
+#define V3523 (V + 13293)
+ 0x1104, 0x1167, 0x11bd, 0,
+#undef V3524
+#define V3524 (V + 13297)
+ 0x1104, 0x1167, 0x11be, 0,
+#undef V3525
+#define V3525 (V + 13301)
+ 0x1104, 0x1167, 0x11bf, 0,
+#undef V3526
+#define V3526 (V + 13305)
+ 0x1104, 0x1167, 0x11c0, 0,
+#undef V3527
+#define V3527 (V + 13309)
+ 0x1104, 0x1167, 0x11c1, 0,
+#undef V3528
+#define V3528 (V + 13313)
+ 0x1104, 0x1167, 0x11c2, 0,
+#undef V3529
+#define V3529 (V + 13317)
+ 0x1104, 0x1168, 0,
+#undef V3530
+#define V3530 (V + 13320)
+ 0x1104, 0x1168, 0x11a8, 0,
+#undef V3531
+#define V3531 (V + 13324)
+ 0x1104, 0x1168, 0x11a9, 0,
+#undef V3532
+#define V3532 (V + 13328)
+ 0x1104, 0x1168, 0x11aa, 0,
+#undef V3533
+#define V3533 (V + 13332)
+ 0x1104, 0x1168, 0x11ab, 0,
+#undef V3534
+#define V3534 (V + 13336)
+ 0x1104, 0x1168, 0x11ac, 0,
+#undef V3535
+#define V3535 (V + 13340)
+ 0x1104, 0x1168, 0x11ad, 0,
+#undef V3536
+#define V3536 (V + 13344)
+ 0x1104, 0x1168, 0x11ae, 0,
+#undef V3537
+#define V3537 (V + 13348)
+ 0x1104, 0x1168, 0x11af, 0,
+#undef V3538
+#define V3538 (V + 13352)
+ 0x1104, 0x1168, 0x11b0, 0,
+#undef V3539
+#define V3539 (V + 13356)
+ 0x1104, 0x1168, 0x11b1, 0,
+#undef V3540
+#define V3540 (V + 13360)
+ 0x1104, 0x1168, 0x11b2, 0,
+#undef V3541
+#define V3541 (V + 13364)
+ 0x1104, 0x1168, 0x11b3, 0,
+#undef V3542
+#define V3542 (V + 13368)
+ 0x1104, 0x1168, 0x11b4, 0,
+#undef V3543
+#define V3543 (V + 13372)
+ 0x1104, 0x1168, 0x11b5, 0,
+#undef V3544
+#define V3544 (V + 13376)
+ 0x1104, 0x1168, 0x11b6, 0,
+#undef V3545
+#define V3545 (V + 13380)
+ 0x1104, 0x1168, 0x11b7, 0,
+#undef V3546
+#define V3546 (V + 13384)
+ 0x1104, 0x1168, 0x11b8, 0,
+#undef V3547
+#define V3547 (V + 13388)
+ 0x1104, 0x1168, 0x11b9, 0,
+#undef V3548
+#define V3548 (V + 13392)
+ 0x1104, 0x1168, 0x11ba, 0,
+#undef V3549
+#define V3549 (V + 13396)
+ 0x1104, 0x1168, 0x11bb, 0,
+#undef V3550
+#define V3550 (V + 13400)
+ 0x1104, 0x1168, 0x11bc, 0,
+#undef V3551
+#define V3551 (V + 13404)
+ 0x1104, 0x1168, 0x11bd, 0,
+#undef V3552
+#define V3552 (V + 13408)
+ 0x1104, 0x1168, 0x11be, 0,
+#undef V3553
+#define V3553 (V + 13412)
+ 0x1104, 0x1168, 0x11bf, 0,
+#undef V3554
+#define V3554 (V + 13416)
+ 0x1104, 0x1168, 0x11c0, 0,
+#undef V3555
+#define V3555 (V + 13420)
+ 0x1104, 0x1168, 0x11c1, 0,
+#undef V3556
+#define V3556 (V + 13424)
+ 0x1104, 0x1168, 0x11c2, 0,
+#undef V3557
+#define V3557 (V + 13428)
+ 0x1104, 0x1169, 0,
+#undef V3558
+#define V3558 (V + 13431)
+ 0x1104, 0x1169, 0x11a8, 0,
+#undef V3559
+#define V3559 (V + 13435)
+ 0x1104, 0x1169, 0x11a9, 0,
+#undef V3560
+#define V3560 (V + 13439)
+ 0x1104, 0x1169, 0x11aa, 0,
+#undef V3561
+#define V3561 (V + 13443)
+ 0x1104, 0x1169, 0x11ab, 0,
+#undef V3562
+#define V3562 (V + 13447)
+ 0x1104, 0x1169, 0x11ac, 0,
+#undef V3563
+#define V3563 (V + 13451)
+ 0x1104, 0x1169, 0x11ad, 0,
+#undef V3564
+#define V3564 (V + 13455)
+ 0x1104, 0x1169, 0x11ae, 0,
+#undef V3565
+#define V3565 (V + 13459)
+ 0x1104, 0x1169, 0x11af, 0,
+#undef V3566
+#define V3566 (V + 13463)
+ 0x1104, 0x1169, 0x11b0, 0,
+#undef V3567
+#define V3567 (V + 13467)
+ 0x1104, 0x1169, 0x11b1, 0,
+#undef V3568
+#define V3568 (V + 13471)
+ 0x1104, 0x1169, 0x11b2, 0,
+#undef V3569
+#define V3569 (V + 13475)
+ 0x1104, 0x1169, 0x11b3, 0,
+#undef V3570
+#define V3570 (V + 13479)
+ 0x1104, 0x1169, 0x11b4, 0,
+#undef V3571
+#define V3571 (V + 13483)
+ 0x1104, 0x1169, 0x11b5, 0,
+#undef V3572
+#define V3572 (V + 13487)
+ 0x1104, 0x1169, 0x11b6, 0,
+#undef V3573
+#define V3573 (V + 13491)
+ 0x1104, 0x1169, 0x11b7, 0,
+#undef V3574
+#define V3574 (V + 13495)
+ 0x1104, 0x1169, 0x11b8, 0,
+#undef V3575
+#define V3575 (V + 13499)
+ 0x1104, 0x1169, 0x11b9, 0,
+#undef V3576
+#define V3576 (V + 13503)
+ 0x1104, 0x1169, 0x11ba, 0,
+#undef V3577
+#define V3577 (V + 13507)
+ 0x1104, 0x1169, 0x11bb, 0,
+#undef V3578
+#define V3578 (V + 13511)
+ 0x1104, 0x1169, 0x11bc, 0,
+#undef V3579
+#define V3579 (V + 13515)
+ 0x1104, 0x1169, 0x11bd, 0,
+#undef V3580
+#define V3580 (V + 13519)
+ 0x1104, 0x1169, 0x11be, 0,
+#undef V3581
+#define V3581 (V + 13523)
+ 0x1104, 0x1169, 0x11bf, 0,
+#undef V3582
+#define V3582 (V + 13527)
+ 0x1104, 0x1169, 0x11c0, 0,
+#undef V3583
+#define V3583 (V + 13531)
+ 0x1104, 0x1169, 0x11c1, 0,
+#undef V3584
+#define V3584 (V + 13535)
+ 0x1104, 0x1169, 0x11c2, 0,
+#undef V3585
+#define V3585 (V + 13539)
+ 0x1104, 0x116a, 0,
+#undef V3586
+#define V3586 (V + 13542)
+ 0x1104, 0x116a, 0x11a8, 0,
+#undef V3587
+#define V3587 (V + 13546)
+ 0x1104, 0x116a, 0x11a9, 0,
+#undef V3588
+#define V3588 (V + 13550)
+ 0x1104, 0x116a, 0x11aa, 0,
+#undef V3589
+#define V3589 (V + 13554)
+ 0x1104, 0x116a, 0x11ab, 0,
+#undef V3590
+#define V3590 (V + 13558)
+ 0x1104, 0x116a, 0x11ac, 0,
+#undef V3591
+#define V3591 (V + 13562)
+ 0x1104, 0x116a, 0x11ad, 0,
+#undef V3592
+#define V3592 (V + 13566)
+ 0x1104, 0x116a, 0x11ae, 0,
+#undef V3593
+#define V3593 (V + 13570)
+ 0x1104, 0x116a, 0x11af, 0,
+#undef V3594
+#define V3594 (V + 13574)
+ 0x1104, 0x116a, 0x11b0, 0,
+#undef V3595
+#define V3595 (V + 13578)
+ 0x1104, 0x116a, 0x11b1, 0,
+#undef V3596
+#define V3596 (V + 13582)
+ 0x1104, 0x116a, 0x11b2, 0,
+#undef V3597
+#define V3597 (V + 13586)
+ 0x1104, 0x116a, 0x11b3, 0,
+#undef V3598
+#define V3598 (V + 13590)
+ 0x1104, 0x116a, 0x11b4, 0,
+#undef V3599
+#define V3599 (V + 13594)
+ 0x1104, 0x116a, 0x11b5, 0,
+#undef V3600
+#define V3600 (V + 13598)
+ 0x1104, 0x116a, 0x11b6, 0,
+#undef V3601
+#define V3601 (V + 13602)
+ 0x1104, 0x116a, 0x11b7, 0,
+#undef V3602
+#define V3602 (V + 13606)
+ 0x1104, 0x116a, 0x11b8, 0,
+#undef V3603
+#define V3603 (V + 13610)
+ 0x1104, 0x116a, 0x11b9, 0,
+#undef V3604
+#define V3604 (V + 13614)
+ 0x1104, 0x116a, 0x11ba, 0,
+#undef V3605
+#define V3605 (V + 13618)
+ 0x1104, 0x116a, 0x11bb, 0,
+#undef V3606
+#define V3606 (V + 13622)
+ 0x1104, 0x116a, 0x11bc, 0,
+#undef V3607
+#define V3607 (V + 13626)
+ 0x1104, 0x116a, 0x11bd, 0,
+#undef V3608
+#define V3608 (V + 13630)
+ 0x1104, 0x116a, 0x11be, 0,
+#undef V3609
+#define V3609 (V + 13634)
+ 0x1104, 0x116a, 0x11bf, 0,
+#undef V3610
+#define V3610 (V + 13638)
+ 0x1104, 0x116a, 0x11c0, 0,
+#undef V3611
+#define V3611 (V + 13642)
+ 0x1104, 0x116a, 0x11c1, 0,
+#undef V3612
+#define V3612 (V + 13646)
+ 0x1104, 0x116a, 0x11c2, 0,
+#undef V3613
+#define V3613 (V + 13650)
+ 0x1104, 0x116b, 0,
+#undef V3614
+#define V3614 (V + 13653)
+ 0x1104, 0x116b, 0x11a8, 0,
+#undef V3615
+#define V3615 (V + 13657)
+ 0x1104, 0x116b, 0x11a9, 0,
+#undef V3616
+#define V3616 (V + 13661)
+ 0x1104, 0x116b, 0x11aa, 0,
+#undef V3617
+#define V3617 (V + 13665)
+ 0x1104, 0x116b, 0x11ab, 0,
+#undef V3618
+#define V3618 (V + 13669)
+ 0x1104, 0x116b, 0x11ac, 0,
+#undef V3619
+#define V3619 (V + 13673)
+ 0x1104, 0x116b, 0x11ad, 0,
+#undef V3620
+#define V3620 (V + 13677)
+ 0x1104, 0x116b, 0x11ae, 0,
+#undef V3621
+#define V3621 (V + 13681)
+ 0x1104, 0x116b, 0x11af, 0,
+#undef V3622
+#define V3622 (V + 13685)
+ 0x1104, 0x116b, 0x11b0, 0,
+#undef V3623
+#define V3623 (V + 13689)
+ 0x1104, 0x116b, 0x11b1, 0,
+#undef V3624
+#define V3624 (V + 13693)
+ 0x1104, 0x116b, 0x11b2, 0,
+#undef V3625
+#define V3625 (V + 13697)
+ 0x1104, 0x116b, 0x11b3, 0,
+#undef V3626
+#define V3626 (V + 13701)
+ 0x1104, 0x116b, 0x11b4, 0,
+#undef V3627
+#define V3627 (V + 13705)
+ 0x1104, 0x116b, 0x11b5, 0,
+#undef V3628
+#define V3628 (V + 13709)
+ 0x1104, 0x116b, 0x11b6, 0,
+#undef V3629
+#define V3629 (V + 13713)
+ 0x1104, 0x116b, 0x11b7, 0,
+#undef V3630
+#define V3630 (V + 13717)
+ 0x1104, 0x116b, 0x11b8, 0,
+#undef V3631
+#define V3631 (V + 13721)
+ 0x1104, 0x116b, 0x11b9, 0,
+#undef V3632
+#define V3632 (V + 13725)
+ 0x1104, 0x116b, 0x11ba, 0,
+#undef V3633
+#define V3633 (V + 13729)
+ 0x1104, 0x116b, 0x11bb, 0,
+#undef V3634
+#define V3634 (V + 13733)
+ 0x1104, 0x116b, 0x11bc, 0,
+#undef V3635
+#define V3635 (V + 13737)
+ 0x1104, 0x116b, 0x11bd, 0,
+#undef V3636
+#define V3636 (V + 13741)
+ 0x1104, 0x116b, 0x11be, 0,
+#undef V3637
+#define V3637 (V + 13745)
+ 0x1104, 0x116b, 0x11bf, 0,
+#undef V3638
+#define V3638 (V + 13749)
+ 0x1104, 0x116b, 0x11c0, 0,
+#undef V3639
+#define V3639 (V + 13753)
+ 0x1104, 0x116b, 0x11c1, 0,
+#undef V3640
+#define V3640 (V + 13757)
+ 0x1104, 0x116b, 0x11c2, 0,
+#undef V3641
+#define V3641 (V + 13761)
+ 0x1104, 0x116c, 0,
+#undef V3642
+#define V3642 (V + 13764)
+ 0x1104, 0x116c, 0x11a8, 0,
+#undef V3643
+#define V3643 (V + 13768)
+ 0x1104, 0x116c, 0x11a9, 0,
+#undef V3644
+#define V3644 (V + 13772)
+ 0x1104, 0x116c, 0x11aa, 0,
+#undef V3645
+#define V3645 (V + 13776)
+ 0x1104, 0x116c, 0x11ab, 0,
+#undef V3646
+#define V3646 (V + 13780)
+ 0x1104, 0x116c, 0x11ac, 0,
+#undef V3647
+#define V3647 (V + 13784)
+ 0x1104, 0x116c, 0x11ad, 0,
+#undef V3648
+#define V3648 (V + 13788)
+ 0x1104, 0x116c, 0x11ae, 0,
+#undef V3649
+#define V3649 (V + 13792)
+ 0x1104, 0x116c, 0x11af, 0,
+#undef V3650
+#define V3650 (V + 13796)
+ 0x1104, 0x116c, 0x11b0, 0,
+#undef V3651
+#define V3651 (V + 13800)
+ 0x1104, 0x116c, 0x11b1, 0,
+#undef V3652
+#define V3652 (V + 13804)
+ 0x1104, 0x116c, 0x11b2, 0,
+#undef V3653
+#define V3653 (V + 13808)
+ 0x1104, 0x116c, 0x11b3, 0,
+#undef V3654
+#define V3654 (V + 13812)
+ 0x1104, 0x116c, 0x11b4, 0,
+#undef V3655
+#define V3655 (V + 13816)
+ 0x1104, 0x116c, 0x11b5, 0,
+#undef V3656
+#define V3656 (V + 13820)
+ 0x1104, 0x116c, 0x11b6, 0,
+#undef V3657
+#define V3657 (V + 13824)
+ 0x1104, 0x116c, 0x11b7, 0,
+#undef V3658
+#define V3658 (V + 13828)
+ 0x1104, 0x116c, 0x11b8, 0,
+#undef V3659
+#define V3659 (V + 13832)
+ 0x1104, 0x116c, 0x11b9, 0,
+#undef V3660
+#define V3660 (V + 13836)
+ 0x1104, 0x116c, 0x11ba, 0,
+#undef V3661
+#define V3661 (V + 13840)
+ 0x1104, 0x116c, 0x11bb, 0,
+#undef V3662
+#define V3662 (V + 13844)
+ 0x1104, 0x116c, 0x11bc, 0,
+#undef V3663
+#define V3663 (V + 13848)
+ 0x1104, 0x116c, 0x11bd, 0,
+#undef V3664
+#define V3664 (V + 13852)
+ 0x1104, 0x116c, 0x11be, 0,
+#undef V3665
+#define V3665 (V + 13856)
+ 0x1104, 0x116c, 0x11bf, 0,
+#undef V3666
+#define V3666 (V + 13860)
+ 0x1104, 0x116c, 0x11c0, 0,
+#undef V3667
+#define V3667 (V + 13864)
+ 0x1104, 0x116c, 0x11c1, 0,
+#undef V3668
+#define V3668 (V + 13868)
+ 0x1104, 0x116c, 0x11c2, 0,
+#undef V3669
+#define V3669 (V + 13872)
+ 0x1104, 0x116d, 0,
+#undef V3670
+#define V3670 (V + 13875)
+ 0x1104, 0x116d, 0x11a8, 0,
+#undef V3671
+#define V3671 (V + 13879)
+ 0x1104, 0x116d, 0x11a9, 0,
+#undef V3672
+#define V3672 (V + 13883)
+ 0x1104, 0x116d, 0x11aa, 0,
+#undef V3673
+#define V3673 (V + 13887)
+ 0x1104, 0x116d, 0x11ab, 0,
+#undef V3674
+#define V3674 (V + 13891)
+ 0x1104, 0x116d, 0x11ac, 0,
+#undef V3675
+#define V3675 (V + 13895)
+ 0x1104, 0x116d, 0x11ad, 0,
+#undef V3676
+#define V3676 (V + 13899)
+ 0x1104, 0x116d, 0x11ae, 0,
+#undef V3677
+#define V3677 (V + 13903)
+ 0x1104, 0x116d, 0x11af, 0,
+#undef V3678
+#define V3678 (V + 13907)
+ 0x1104, 0x116d, 0x11b0, 0,
+#undef V3679
+#define V3679 (V + 13911)
+ 0x1104, 0x116d, 0x11b1, 0,
+#undef V3680
+#define V3680 (V + 13915)
+ 0x1104, 0x116d, 0x11b2, 0,
+#undef V3681
+#define V3681 (V + 13919)
+ 0x1104, 0x116d, 0x11b3, 0,
+#undef V3682
+#define V3682 (V + 13923)
+ 0x1104, 0x116d, 0x11b4, 0,
+#undef V3683
+#define V3683 (V + 13927)
+ 0x1104, 0x116d, 0x11b5, 0,
+#undef V3684
+#define V3684 (V + 13931)
+ 0x1104, 0x116d, 0x11b6, 0,
+#undef V3685
+#define V3685 (V + 13935)
+ 0x1104, 0x116d, 0x11b7, 0,
+#undef V3686
+#define V3686 (V + 13939)
+ 0x1104, 0x116d, 0x11b8, 0,
+#undef V3687
+#define V3687 (V + 13943)
+ 0x1104, 0x116d, 0x11b9, 0,
+#undef V3688
+#define V3688 (V + 13947)
+ 0x1104, 0x116d, 0x11ba, 0,
+#undef V3689
+#define V3689 (V + 13951)
+ 0x1104, 0x116d, 0x11bb, 0,
+#undef V3690
+#define V3690 (V + 13955)
+ 0x1104, 0x116d, 0x11bc, 0,
+#undef V3691
+#define V3691 (V + 13959)
+ 0x1104, 0x116d, 0x11bd, 0,
+#undef V3692
+#define V3692 (V + 13963)
+ 0x1104, 0x116d, 0x11be, 0,
+#undef V3693
+#define V3693 (V + 13967)
+ 0x1104, 0x116d, 0x11bf, 0,
+#undef V3694
+#define V3694 (V + 13971)
+ 0x1104, 0x116d, 0x11c0, 0,
+#undef V3695
+#define V3695 (V + 13975)
+ 0x1104, 0x116d, 0x11c1, 0,
+#undef V3696
+#define V3696 (V + 13979)
+ 0x1104, 0x116d, 0x11c2, 0,
+#undef V3697
+#define V3697 (V + 13983)
+ 0x1104, 0x116e, 0,
+#undef V3698
+#define V3698 (V + 13986)
+ 0x1104, 0x116e, 0x11a8, 0,
+#undef V3699
+#define V3699 (V + 13990)
+ 0x1104, 0x116e, 0x11a9, 0,
+#undef V3700
+#define V3700 (V + 13994)
+ 0x1104, 0x116e, 0x11aa, 0,
+#undef V3701
+#define V3701 (V + 13998)
+ 0x1104, 0x116e, 0x11ab, 0,
+#undef V3702
+#define V3702 (V + 14002)
+ 0x1104, 0x116e, 0x11ac, 0,
+#undef V3703
+#define V3703 (V + 14006)
+ 0x1104, 0x116e, 0x11ad, 0,
+#undef V3704
+#define V3704 (V + 14010)
+ 0x1104, 0x116e, 0x11ae, 0,
+#undef V3705
+#define V3705 (V + 14014)
+ 0x1104, 0x116e, 0x11af, 0,
+#undef V3706
+#define V3706 (V + 14018)
+ 0x1104, 0x116e, 0x11b0, 0,
+#undef V3707
+#define V3707 (V + 14022)
+ 0x1104, 0x116e, 0x11b1, 0,
+#undef V3708
+#define V3708 (V + 14026)
+ 0x1104, 0x116e, 0x11b2, 0,
+#undef V3709
+#define V3709 (V + 14030)
+ 0x1104, 0x116e, 0x11b3, 0,
+#undef V3710
+#define V3710 (V + 14034)
+ 0x1104, 0x116e, 0x11b4, 0,
+#undef V3711
+#define V3711 (V + 14038)
+ 0x1104, 0x116e, 0x11b5, 0,
+#undef V3712
+#define V3712 (V + 14042)
+ 0x1104, 0x116e, 0x11b6, 0,
+#undef V3713
+#define V3713 (V + 14046)
+ 0x1104, 0x116e, 0x11b7, 0,
+#undef V3714
+#define V3714 (V + 14050)
+ 0x1104, 0x116e, 0x11b8, 0,
+#undef V3715
+#define V3715 (V + 14054)
+ 0x1104, 0x116e, 0x11b9, 0,
+#undef V3716
+#define V3716 (V + 14058)
+ 0x1104, 0x116e, 0x11ba, 0,
+#undef V3717
+#define V3717 (V + 14062)
+ 0x1104, 0x116e, 0x11bb, 0,
+#undef V3718
+#define V3718 (V + 14066)
+ 0x1104, 0x116e, 0x11bc, 0,
+#undef V3719
+#define V3719 (V + 14070)
+ 0x1104, 0x116e, 0x11bd, 0,
+#undef V3720
+#define V3720 (V + 14074)
+ 0x1104, 0x116e, 0x11be, 0,
+#undef V3721
+#define V3721 (V + 14078)
+ 0x1104, 0x116e, 0x11bf, 0,
+#undef V3722
+#define V3722 (V + 14082)
+ 0x1104, 0x116e, 0x11c0, 0,
+#undef V3723
+#define V3723 (V + 14086)
+ 0x1104, 0x116e, 0x11c1, 0,
+#undef V3724
+#define V3724 (V + 14090)
+ 0x1104, 0x116e, 0x11c2, 0,
+#undef V3725
+#define V3725 (V + 14094)
+ 0x1104, 0x116f, 0,
+#undef V3726
+#define V3726 (V + 14097)
+ 0x1104, 0x116f, 0x11a8, 0,
+#undef V3727
+#define V3727 (V + 14101)
+ 0x1104, 0x116f, 0x11a9, 0,
+#undef V3728
+#define V3728 (V + 14105)
+ 0x1104, 0x116f, 0x11aa, 0,
+#undef V3729
+#define V3729 (V + 14109)
+ 0x1104, 0x116f, 0x11ab, 0,
+#undef V3730
+#define V3730 (V + 14113)
+ 0x1104, 0x116f, 0x11ac, 0,
+#undef V3731
+#define V3731 (V + 14117)
+ 0x1104, 0x116f, 0x11ad, 0,
+#undef V3732
+#define V3732 (V + 14121)
+ 0x1104, 0x116f, 0x11ae, 0,
+#undef V3733
+#define V3733 (V + 14125)
+ 0x1104, 0x116f, 0x11af, 0,
+#undef V3734
+#define V3734 (V + 14129)
+ 0x1104, 0x116f, 0x11b0, 0,
+#undef V3735
+#define V3735 (V + 14133)
+ 0x1104, 0x116f, 0x11b1, 0,
+#undef V3736
+#define V3736 (V + 14137)
+ 0x1104, 0x116f, 0x11b2, 0,
+#undef V3737
+#define V3737 (V + 14141)
+ 0x1104, 0x116f, 0x11b3, 0,
+#undef V3738
+#define V3738 (V + 14145)
+ 0x1104, 0x116f, 0x11b4, 0,
+#undef V3739
+#define V3739 (V + 14149)
+ 0x1104, 0x116f, 0x11b5, 0,
+#undef V3740
+#define V3740 (V + 14153)
+ 0x1104, 0x116f, 0x11b6, 0,
+#undef V3741
+#define V3741 (V + 14157)
+ 0x1104, 0x116f, 0x11b7, 0,
+#undef V3742
+#define V3742 (V + 14161)
+ 0x1104, 0x116f, 0x11b8, 0,
+#undef V3743
+#define V3743 (V + 14165)
+ 0x1104, 0x116f, 0x11b9, 0,
+#undef V3744
+#define V3744 (V + 14169)
+ 0x1104, 0x116f, 0x11ba, 0,
+#undef V3745
+#define V3745 (V + 14173)
+ 0x1104, 0x116f, 0x11bb, 0,
+#undef V3746
+#define V3746 (V + 14177)
+ 0x1104, 0x116f, 0x11bc, 0,
+#undef V3747
+#define V3747 (V + 14181)
+ 0x1104, 0x116f, 0x11bd, 0,
+#undef V3748
+#define V3748 (V + 14185)
+ 0x1104, 0x116f, 0x11be, 0,
+#undef V3749
+#define V3749 (V + 14189)
+ 0x1104, 0x116f, 0x11bf, 0,
+#undef V3750
+#define V3750 (V + 14193)
+ 0x1104, 0x116f, 0x11c0, 0,
+#undef V3751
+#define V3751 (V + 14197)
+ 0x1104, 0x116f, 0x11c1, 0,
+#undef V3752
+#define V3752 (V + 14201)
+ 0x1104, 0x116f, 0x11c2, 0,
+#undef V3753
+#define V3753 (V + 14205)
+ 0x1104, 0x1170, 0,
+#undef V3754
+#define V3754 (V + 14208)
+ 0x1104, 0x1170, 0x11a8, 0,
+#undef V3755
+#define V3755 (V + 14212)
+ 0x1104, 0x1170, 0x11a9, 0,
+#undef V3756
+#define V3756 (V + 14216)
+ 0x1104, 0x1170, 0x11aa, 0,
+#undef V3757
+#define V3757 (V + 14220)
+ 0x1104, 0x1170, 0x11ab, 0,
+#undef V3758
+#define V3758 (V + 14224)
+ 0x1104, 0x1170, 0x11ac, 0,
+#undef V3759
+#define V3759 (V + 14228)
+ 0x1104, 0x1170, 0x11ad, 0,
+#undef V3760
+#define V3760 (V + 14232)
+ 0x1104, 0x1170, 0x11ae, 0,
+#undef V3761
+#define V3761 (V + 14236)
+ 0x1104, 0x1170, 0x11af, 0,
+#undef V3762
+#define V3762 (V + 14240)
+ 0x1104, 0x1170, 0x11b0, 0,
+#undef V3763
+#define V3763 (V + 14244)
+ 0x1104, 0x1170, 0x11b1, 0,
+#undef V3764
+#define V3764 (V + 14248)
+ 0x1104, 0x1170, 0x11b2, 0,
+#undef V3765
+#define V3765 (V + 14252)
+ 0x1104, 0x1170, 0x11b3, 0,
+#undef V3766
+#define V3766 (V + 14256)
+ 0x1104, 0x1170, 0x11b4, 0,
+#undef V3767
+#define V3767 (V + 14260)
+ 0x1104, 0x1170, 0x11b5, 0,
+#undef V3768
+#define V3768 (V + 14264)
+ 0x1104, 0x1170, 0x11b6, 0,
+#undef V3769
+#define V3769 (V + 14268)
+ 0x1104, 0x1170, 0x11b7, 0,
+#undef V3770
+#define V3770 (V + 14272)
+ 0x1104, 0x1170, 0x11b8, 0,
+#undef V3771
+#define V3771 (V + 14276)
+ 0x1104, 0x1170, 0x11b9, 0,
+#undef V3772
+#define V3772 (V + 14280)
+ 0x1104, 0x1170, 0x11ba, 0,
+#undef V3773
+#define V3773 (V + 14284)
+ 0x1104, 0x1170, 0x11bb, 0,
+#undef V3774
+#define V3774 (V + 14288)
+ 0x1104, 0x1170, 0x11bc, 0,
+#undef V3775
+#define V3775 (V + 14292)
+ 0x1104, 0x1170, 0x11bd, 0,
+#undef V3776
+#define V3776 (V + 14296)
+ 0x1104, 0x1170, 0x11be, 0,
+#undef V3777
+#define V3777 (V + 14300)
+ 0x1104, 0x1170, 0x11bf, 0,
+#undef V3778
+#define V3778 (V + 14304)
+ 0x1104, 0x1170, 0x11c0, 0,
+#undef V3779
+#define V3779 (V + 14308)
+ 0x1104, 0x1170, 0x11c1, 0,
+#undef V3780
+#define V3780 (V + 14312)
+ 0x1104, 0x1170, 0x11c2, 0,
+#undef V3781
+#define V3781 (V + 14316)
+ 0x1104, 0x1171, 0,
+#undef V3782
+#define V3782 (V + 14319)
+ 0x1104, 0x1171, 0x11a8, 0,
+#undef V3783
+#define V3783 (V + 14323)
+ 0x1104, 0x1171, 0x11a9, 0,
+#undef V3784
+#define V3784 (V + 14327)
+ 0x1104, 0x1171, 0x11aa, 0,
+#undef V3785
+#define V3785 (V + 14331)
+ 0x1104, 0x1171, 0x11ab, 0,
+#undef V3786
+#define V3786 (V + 14335)
+ 0x1104, 0x1171, 0x11ac, 0,
+#undef V3787
+#define V3787 (V + 14339)
+ 0x1104, 0x1171, 0x11ad, 0,
+#undef V3788
+#define V3788 (V + 14343)
+ 0x1104, 0x1171, 0x11ae, 0,
+#undef V3789
+#define V3789 (V + 14347)
+ 0x1104, 0x1171, 0x11af, 0,
+#undef V3790
+#define V3790 (V + 14351)
+ 0x1104, 0x1171, 0x11b0, 0,
+#undef V3791
+#define V3791 (V + 14355)
+ 0x1104, 0x1171, 0x11b1, 0,
+#undef V3792
+#define V3792 (V + 14359)
+ 0x1104, 0x1171, 0x11b2, 0,
+#undef V3793
+#define V3793 (V + 14363)
+ 0x1104, 0x1171, 0x11b3, 0,
+#undef V3794
+#define V3794 (V + 14367)
+ 0x1104, 0x1171, 0x11b4, 0,
+#undef V3795
+#define V3795 (V + 14371)
+ 0x1104, 0x1171, 0x11b5, 0,
+#undef V3796
+#define V3796 (V + 14375)
+ 0x1104, 0x1171, 0x11b6, 0,
+#undef V3797
+#define V3797 (V + 14379)
+ 0x1104, 0x1171, 0x11b7, 0,
+#undef V3798
+#define V3798 (V + 14383)
+ 0x1104, 0x1171, 0x11b8, 0,
+#undef V3799
+#define V3799 (V + 14387)
+ 0x1104, 0x1171, 0x11b9, 0,
+#undef V3800
+#define V3800 (V + 14391)
+ 0x1104, 0x1171, 0x11ba, 0,
+#undef V3801
+#define V3801 (V + 14395)
+ 0x1104, 0x1171, 0x11bb, 0,
+#undef V3802
+#define V3802 (V + 14399)
+ 0x1104, 0x1171, 0x11bc, 0,
+#undef V3803
+#define V3803 (V + 14403)
+ 0x1104, 0x1171, 0x11bd, 0,
+#undef V3804
+#define V3804 (V + 14407)
+ 0x1104, 0x1171, 0x11be, 0,
+#undef V3805
+#define V3805 (V + 14411)
+ 0x1104, 0x1171, 0x11bf, 0,
+#undef V3806
+#define V3806 (V + 14415)
+ 0x1104, 0x1171, 0x11c0, 0,
+#undef V3807
+#define V3807 (V + 14419)
+ 0x1104, 0x1171, 0x11c1, 0,
+#undef V3808
+#define V3808 (V + 14423)
+ 0x1104, 0x1171, 0x11c2, 0,
+#undef V3809
+#define V3809 (V + 14427)
+ 0x1104, 0x1172, 0,
+#undef V3810
+#define V3810 (V + 14430)
+ 0x1104, 0x1172, 0x11a8, 0,
+#undef V3811
+#define V3811 (V + 14434)
+ 0x1104, 0x1172, 0x11a9, 0,
+#undef V3812
+#define V3812 (V + 14438)
+ 0x1104, 0x1172, 0x11aa, 0,
+#undef V3813
+#define V3813 (V + 14442)
+ 0x1104, 0x1172, 0x11ab, 0,
+#undef V3814
+#define V3814 (V + 14446)
+ 0x1104, 0x1172, 0x11ac, 0,
+#undef V3815
+#define V3815 (V + 14450)
+ 0x1104, 0x1172, 0x11ad, 0,
+#undef V3816
+#define V3816 (V + 14454)
+ 0x1104, 0x1172, 0x11ae, 0,
+#undef V3817
+#define V3817 (V + 14458)
+ 0x1104, 0x1172, 0x11af, 0,
+#undef V3818
+#define V3818 (V + 14462)
+ 0x1104, 0x1172, 0x11b0, 0,
+#undef V3819
+#define V3819 (V + 14466)
+ 0x1104, 0x1172, 0x11b1, 0,
+#undef V3820
+#define V3820 (V + 14470)
+ 0x1104, 0x1172, 0x11b2, 0,
+#undef V3821
+#define V3821 (V + 14474)
+ 0x1104, 0x1172, 0x11b3, 0,
+#undef V3822
+#define V3822 (V + 14478)
+ 0x1104, 0x1172, 0x11b4, 0,
+#undef V3823
+#define V3823 (V + 14482)
+ 0x1104, 0x1172, 0x11b5, 0,
+#undef V3824
+#define V3824 (V + 14486)
+ 0x1104, 0x1172, 0x11b6, 0,
+#undef V3825
+#define V3825 (V + 14490)
+ 0x1104, 0x1172, 0x11b7, 0,
+#undef V3826
+#define V3826 (V + 14494)
+ 0x1104, 0x1172, 0x11b8, 0,
+#undef V3827
+#define V3827 (V + 14498)
+ 0x1104, 0x1172, 0x11b9, 0,
+#undef V3828
+#define V3828 (V + 14502)
+ 0x1104, 0x1172, 0x11ba, 0,
+#undef V3829
+#define V3829 (V + 14506)
+ 0x1104, 0x1172, 0x11bb, 0,
+#undef V3830
+#define V3830 (V + 14510)
+ 0x1104, 0x1172, 0x11bc, 0,
+#undef V3831
+#define V3831 (V + 14514)
+ 0x1104, 0x1172, 0x11bd, 0,
+#undef V3832
+#define V3832 (V + 14518)
+ 0x1104, 0x1172, 0x11be, 0,
+#undef V3833
+#define V3833 (V + 14522)
+ 0x1104, 0x1172, 0x11bf, 0,
+#undef V3834
+#define V3834 (V + 14526)
+ 0x1104, 0x1172, 0x11c0, 0,
+#undef V3835
+#define V3835 (V + 14530)
+ 0x1104, 0x1172, 0x11c1, 0,
+#undef V3836
+#define V3836 (V + 14534)
+ 0x1104, 0x1172, 0x11c2, 0,
+#undef V3837
+#define V3837 (V + 14538)
+ 0x1104, 0x1173, 0,
+#undef V3838
+#define V3838 (V + 14541)
+ 0x1104, 0x1173, 0x11a8, 0,
+#undef V3839
+#define V3839 (V + 14545)
+ 0x1104, 0x1173, 0x11a9, 0,
+#undef V3840
+#define V3840 (V + 14549)
+ 0x1104, 0x1173, 0x11aa, 0,
+#undef V3841
+#define V3841 (V + 14553)
+ 0x1104, 0x1173, 0x11ab, 0,
+#undef V3842
+#define V3842 (V + 14557)
+ 0x1104, 0x1173, 0x11ac, 0,
+#undef V3843
+#define V3843 (V + 14561)
+ 0x1104, 0x1173, 0x11ad, 0,
+#undef V3844
+#define V3844 (V + 14565)
+ 0x1104, 0x1173, 0x11ae, 0,
+#undef V3845
+#define V3845 (V + 14569)
+ 0x1104, 0x1173, 0x11af, 0,
+#undef V3846
+#define V3846 (V + 14573)
+ 0x1104, 0x1173, 0x11b0, 0,
+#undef V3847
+#define V3847 (V + 14577)
+ 0x1104, 0x1173, 0x11b1, 0,
+#undef V3848
+#define V3848 (V + 14581)
+ 0x1104, 0x1173, 0x11b2, 0,
+#undef V3849
+#define V3849 (V + 14585)
+ 0x1104, 0x1173, 0x11b3, 0,
+#undef V3850
+#define V3850 (V + 14589)
+ 0x1104, 0x1173, 0x11b4, 0,
+#undef V3851
+#define V3851 (V + 14593)
+ 0x1104, 0x1173, 0x11b5, 0,
+#undef V3852
+#define V3852 (V + 14597)
+ 0x1104, 0x1173, 0x11b6, 0,
+#undef V3853
+#define V3853 (V + 14601)
+ 0x1104, 0x1173, 0x11b7, 0,
+#undef V3854
+#define V3854 (V + 14605)
+ 0x1104, 0x1173, 0x11b8, 0,
+#undef V3855
+#define V3855 (V + 14609)
+ 0x1104, 0x1173, 0x11b9, 0,
+#undef V3856
+#define V3856 (V + 14613)
+ 0x1104, 0x1173, 0x11ba, 0,
+#undef V3857
+#define V3857 (V + 14617)
+ 0x1104, 0x1173, 0x11bb, 0,
+#undef V3858
+#define V3858 (V + 14621)
+ 0x1104, 0x1173, 0x11bc, 0,
+#undef V3859
+#define V3859 (V + 14625)
+ 0x1104, 0x1173, 0x11bd, 0,
+#undef V3860
+#define V3860 (V + 14629)
+ 0x1104, 0x1173, 0x11be, 0,
+#undef V3861
+#define V3861 (V + 14633)
+ 0x1104, 0x1173, 0x11bf, 0,
+#undef V3862
+#define V3862 (V + 14637)
+ 0x1104, 0x1173, 0x11c0, 0,
+#undef V3863
+#define V3863 (V + 14641)
+ 0x1104, 0x1173, 0x11c1, 0,
+#undef V3864
+#define V3864 (V + 14645)
+ 0x1104, 0x1173, 0x11c2, 0,
+#undef V3865
+#define V3865 (V + 14649)
+ 0x1104, 0x1174, 0,
+#undef V3866
+#define V3866 (V + 14652)
+ 0x1104, 0x1174, 0x11a8, 0,
+#undef V3867
+#define V3867 (V + 14656)
+ 0x1104, 0x1174, 0x11a9, 0,
+#undef V3868
+#define V3868 (V + 14660)
+ 0x1104, 0x1174, 0x11aa, 0,
+#undef V3869
+#define V3869 (V + 14664)
+ 0x1104, 0x1174, 0x11ab, 0,
+#undef V3870
+#define V3870 (V + 14668)
+ 0x1104, 0x1174, 0x11ac, 0,
+#undef V3871
+#define V3871 (V + 14672)
+ 0x1104, 0x1174, 0x11ad, 0,
+#undef V3872
+#define V3872 (V + 14676)
+ 0x1104, 0x1174, 0x11ae, 0,
+#undef V3873
+#define V3873 (V + 14680)
+ 0x1104, 0x1174, 0x11af, 0,
+#undef V3874
+#define V3874 (V + 14684)
+ 0x1104, 0x1174, 0x11b0, 0,
+#undef V3875
+#define V3875 (V + 14688)
+ 0x1104, 0x1174, 0x11b1, 0,
+#undef V3876
+#define V3876 (V + 14692)
+ 0x1104, 0x1174, 0x11b2, 0,
+#undef V3877
+#define V3877 (V + 14696)
+ 0x1104, 0x1174, 0x11b3, 0,
+#undef V3878
+#define V3878 (V + 14700)
+ 0x1104, 0x1174, 0x11b4, 0,
+#undef V3879
+#define V3879 (V + 14704)
+ 0x1104, 0x1174, 0x11b5, 0,
+#undef V3880
+#define V3880 (V + 14708)
+ 0x1104, 0x1174, 0x11b6, 0,
+#undef V3881
+#define V3881 (V + 14712)
+ 0x1104, 0x1174, 0x11b7, 0,
+#undef V3882
+#define V3882 (V + 14716)
+ 0x1104, 0x1174, 0x11b8, 0,
+#undef V3883
+#define V3883 (V + 14720)
+ 0x1104, 0x1174, 0x11b9, 0,
+#undef V3884
+#define V3884 (V + 14724)
+ 0x1104, 0x1174, 0x11ba, 0,
+#undef V3885
+#define V3885 (V + 14728)
+ 0x1104, 0x1174, 0x11bb, 0,
+#undef V3886
+#define V3886 (V + 14732)
+ 0x1104, 0x1174, 0x11bc, 0,
+#undef V3887
+#define V3887 (V + 14736)
+ 0x1104, 0x1174, 0x11bd, 0,
+#undef V3888
+#define V3888 (V + 14740)
+ 0x1104, 0x1174, 0x11be, 0,
+#undef V3889
+#define V3889 (V + 14744)
+ 0x1104, 0x1174, 0x11bf, 0,
+#undef V3890
+#define V3890 (V + 14748)
+ 0x1104, 0x1174, 0x11c0, 0,
+#undef V3891
+#define V3891 (V + 14752)
+ 0x1104, 0x1174, 0x11c1, 0,
+#undef V3892
+#define V3892 (V + 14756)
+ 0x1104, 0x1174, 0x11c2, 0,
+#undef V3893
+#define V3893 (V + 14760)
+ 0x1104, 0x1175, 0,
+#undef V3894
+#define V3894 (V + 14763)
+ 0x1104, 0x1175, 0x11a8, 0,
+#undef V3895
+#define V3895 (V + 14767)
+ 0x1104, 0x1175, 0x11a9, 0,
+#undef V3896
+#define V3896 (V + 14771)
+ 0x1104, 0x1175, 0x11aa, 0,
+#undef V3897
+#define V3897 (V + 14775)
+ 0x1104, 0x1175, 0x11ab, 0,
+#undef V3898
+#define V3898 (V + 14779)
+ 0x1104, 0x1175, 0x11ac, 0,
+#undef V3899
+#define V3899 (V + 14783)
+ 0x1104, 0x1175, 0x11ad, 0,
+#undef V3900
+#define V3900 (V + 14787)
+ 0x1104, 0x1175, 0x11ae, 0,
+#undef V3901
+#define V3901 (V + 14791)
+ 0x1104, 0x1175, 0x11af, 0,
+#undef V3902
+#define V3902 (V + 14795)
+ 0x1104, 0x1175, 0x11b0, 0,
+#undef V3903
+#define V3903 (V + 14799)
+ 0x1104, 0x1175, 0x11b1, 0,
+#undef V3904
+#define V3904 (V + 14803)
+ 0x1104, 0x1175, 0x11b2, 0,
+#undef V3905
+#define V3905 (V + 14807)
+ 0x1104, 0x1175, 0x11b3, 0,
+#undef V3906
+#define V3906 (V + 14811)
+ 0x1104, 0x1175, 0x11b4, 0,
+#undef V3907
+#define V3907 (V + 14815)
+ 0x1104, 0x1175, 0x11b5, 0,
+#undef V3908
+#define V3908 (V + 14819)
+ 0x1104, 0x1175, 0x11b6, 0,
+#undef V3909
+#define V3909 (V + 14823)
+ 0x1104, 0x1175, 0x11b7, 0,
+#undef V3910
+#define V3910 (V + 14827)
+ 0x1104, 0x1175, 0x11b8, 0,
+#undef V3911
+#define V3911 (V + 14831)
+ 0x1104, 0x1175, 0x11b9, 0,
+#undef V3912
+#define V3912 (V + 14835)
+ 0x1104, 0x1175, 0x11ba, 0,
+#undef V3913
+#define V3913 (V + 14839)
+ 0x1104, 0x1175, 0x11bb, 0,
+#undef V3914
+#define V3914 (V + 14843)
+ 0x1104, 0x1175, 0x11bc, 0,
+#undef V3915
+#define V3915 (V + 14847)
+ 0x1104, 0x1175, 0x11bd, 0,
+#undef V3916
+#define V3916 (V + 14851)
+ 0x1104, 0x1175, 0x11be, 0,
+#undef V3917
+#define V3917 (V + 14855)
+ 0x1104, 0x1175, 0x11bf, 0,
+#undef V3918
+#define V3918 (V + 14859)
+ 0x1104, 0x1175, 0x11c0, 0,
+#undef V3919
+#define V3919 (V + 14863)
+ 0x1104, 0x1175, 0x11c1, 0,
+#undef V3920
+#define V3920 (V + 14867)
+ 0x1104, 0x1175, 0x11c2, 0,
+#undef V3921
+#define V3921 (V + 14871)
+ 0x1105, 0x1161, 0,
+#undef V3922
+#define V3922 (V + 14874)
+ 0x1105, 0x1161, 0x11a8, 0,
+#undef V3923
+#define V3923 (V + 14878)
+ 0x1105, 0x1161, 0x11a9, 0,
+#undef V3924
+#define V3924 (V + 14882)
+ 0x1105, 0x1161, 0x11aa, 0,
+#undef V3925
+#define V3925 (V + 14886)
+ 0x1105, 0x1161, 0x11ab, 0,
+#undef V3926
+#define V3926 (V + 14890)
+ 0x1105, 0x1161, 0x11ac, 0,
+#undef V3927
+#define V3927 (V + 14894)
+ 0x1105, 0x1161, 0x11ad, 0,
+#undef V3928
+#define V3928 (V + 14898)
+ 0x1105, 0x1161, 0x11ae, 0,
+#undef V3929
+#define V3929 (V + 14902)
+ 0x1105, 0x1161, 0x11af, 0,
+#undef V3930
+#define V3930 (V + 14906)
+ 0x1105, 0x1161, 0x11b0, 0,
+#undef V3931
+#define V3931 (V + 14910)
+ 0x1105, 0x1161, 0x11b1, 0,
+#undef V3932
+#define V3932 (V + 14914)
+ 0x1105, 0x1161, 0x11b2, 0,
+#undef V3933
+#define V3933 (V + 14918)
+ 0x1105, 0x1161, 0x11b3, 0,
+#undef V3934
+#define V3934 (V + 14922)
+ 0x1105, 0x1161, 0x11b4, 0,
+#undef V3935
+#define V3935 (V + 14926)
+ 0x1105, 0x1161, 0x11b5, 0,
+#undef V3936
+#define V3936 (V + 14930)
+ 0x1105, 0x1161, 0x11b6, 0,
+#undef V3937
+#define V3937 (V + 14934)
+ 0x1105, 0x1161, 0x11b7, 0,
+#undef V3938
+#define V3938 (V + 14938)
+ 0x1105, 0x1161, 0x11b8, 0,
+#undef V3939
+#define V3939 (V + 14942)
+ 0x1105, 0x1161, 0x11b9, 0,
+#undef V3940
+#define V3940 (V + 14946)
+ 0x1105, 0x1161, 0x11ba, 0,
+#undef V3941
+#define V3941 (V + 14950)
+ 0x1105, 0x1161, 0x11bb, 0,
+#undef V3942
+#define V3942 (V + 14954)
+ 0x1105, 0x1161, 0x11bc, 0,
+#undef V3943
+#define V3943 (V + 14958)
+ 0x1105, 0x1161, 0x11bd, 0,
+#undef V3944
+#define V3944 (V + 14962)
+ 0x1105, 0x1161, 0x11be, 0,
+#undef V3945
+#define V3945 (V + 14966)
+ 0x1105, 0x1161, 0x11bf, 0,
+#undef V3946
+#define V3946 (V + 14970)
+ 0x1105, 0x1161, 0x11c0, 0,
+#undef V3947
+#define V3947 (V + 14974)
+ 0x1105, 0x1161, 0x11c1, 0,
+#undef V3948
+#define V3948 (V + 14978)
+ 0x1105, 0x1161, 0x11c2, 0,
+#undef V3949
+#define V3949 (V + 14982)
+ 0x1105, 0x1162, 0,
+#undef V3950
+#define V3950 (V + 14985)
+ 0x1105, 0x1162, 0x11a8, 0,
+#undef V3951
+#define V3951 (V + 14989)
+ 0x1105, 0x1162, 0x11a9, 0,
+#undef V3952
+#define V3952 (V + 14993)
+ 0x1105, 0x1162, 0x11aa, 0,
+#undef V3953
+#define V3953 (V + 14997)
+ 0x1105, 0x1162, 0x11ab, 0,
+#undef V3954
+#define V3954 (V + 15001)
+ 0x1105, 0x1162, 0x11ac, 0,
+#undef V3955
+#define V3955 (V + 15005)
+ 0x1105, 0x1162, 0x11ad, 0,
+#undef V3956
+#define V3956 (V + 15009)
+ 0x1105, 0x1162, 0x11ae, 0,
+#undef V3957
+#define V3957 (V + 15013)
+ 0x1105, 0x1162, 0x11af, 0,
+#undef V3958
+#define V3958 (V + 15017)
+ 0x1105, 0x1162, 0x11b0, 0,
+#undef V3959
+#define V3959 (V + 15021)
+ 0x1105, 0x1162, 0x11b1, 0,
+#undef V3960
+#define V3960 (V + 15025)
+ 0x1105, 0x1162, 0x11b2, 0,
+#undef V3961
+#define V3961 (V + 15029)
+ 0x1105, 0x1162, 0x11b3, 0,
+#undef V3962
+#define V3962 (V + 15033)
+ 0x1105, 0x1162, 0x11b4, 0,
+#undef V3963
+#define V3963 (V + 15037)
+ 0x1105, 0x1162, 0x11b5, 0,
+#undef V3964
+#define V3964 (V + 15041)
+ 0x1105, 0x1162, 0x11b6, 0,
+#undef V3965
+#define V3965 (V + 15045)
+ 0x1105, 0x1162, 0x11b7, 0,
+#undef V3966
+#define V3966 (V + 15049)
+ 0x1105, 0x1162, 0x11b8, 0,
+#undef V3967
+#define V3967 (V + 15053)
+ 0x1105, 0x1162, 0x11b9, 0,
+#undef V3968
+#define V3968 (V + 15057)
+ 0x1105, 0x1162, 0x11ba, 0,
+#undef V3969
+#define V3969 (V + 15061)
+ 0x1105, 0x1162, 0x11bb, 0,
+#undef V3970
+#define V3970 (V + 15065)
+ 0x1105, 0x1162, 0x11bc, 0,
+#undef V3971
+#define V3971 (V + 15069)
+ 0x1105, 0x1162, 0x11bd, 0,
+#undef V3972
+#define V3972 (V + 15073)
+ 0x1105, 0x1162, 0x11be, 0,
+#undef V3973
+#define V3973 (V + 15077)
+ 0x1105, 0x1162, 0x11bf, 0,
+#undef V3974
+#define V3974 (V + 15081)
+ 0x1105, 0x1162, 0x11c0, 0,
+#undef V3975
+#define V3975 (V + 15085)
+ 0x1105, 0x1162, 0x11c1, 0,
+#undef V3976
+#define V3976 (V + 15089)
+ 0x1105, 0x1162, 0x11c2, 0,
+#undef V3977
+#define V3977 (V + 15093)
+ 0x1105, 0x1163, 0,
+#undef V3978
+#define V3978 (V + 15096)
+ 0x1105, 0x1163, 0x11a8, 0,
+#undef V3979
+#define V3979 (V + 15100)
+ 0x1105, 0x1163, 0x11a9, 0,
+#undef V3980
+#define V3980 (V + 15104)
+ 0x1105, 0x1163, 0x11aa, 0,
+#undef V3981
+#define V3981 (V + 15108)
+ 0x1105, 0x1163, 0x11ab, 0,
+#undef V3982
+#define V3982 (V + 15112)
+ 0x1105, 0x1163, 0x11ac, 0,
+#undef V3983
+#define V3983 (V + 15116)
+ 0x1105, 0x1163, 0x11ad, 0,
+#undef V3984
+#define V3984 (V + 15120)
+ 0x1105, 0x1163, 0x11ae, 0,
+#undef V3985
+#define V3985 (V + 15124)
+ 0x1105, 0x1163, 0x11af, 0,
+#undef V3986
+#define V3986 (V + 15128)
+ 0x1105, 0x1163, 0x11b0, 0,
+#undef V3987
+#define V3987 (V + 15132)
+ 0x1105, 0x1163, 0x11b1, 0,
+#undef V3988
+#define V3988 (V + 15136)
+ 0x1105, 0x1163, 0x11b2, 0,
+#undef V3989
+#define V3989 (V + 15140)
+ 0x1105, 0x1163, 0x11b3, 0,
+#undef V3990
+#define V3990 (V + 15144)
+ 0x1105, 0x1163, 0x11b4, 0,
+#undef V3991
+#define V3991 (V + 15148)
+ 0x1105, 0x1163, 0x11b5, 0,
+#undef V3992
+#define V3992 (V + 15152)
+ 0x1105, 0x1163, 0x11b6, 0,
+#undef V3993
+#define V3993 (V + 15156)
+ 0x1105, 0x1163, 0x11b7, 0,
+#undef V3994
+#define V3994 (V + 15160)
+ 0x1105, 0x1163, 0x11b8, 0,
+#undef V3995
+#define V3995 (V + 15164)
+ 0x1105, 0x1163, 0x11b9, 0,
+#undef V3996
+#define V3996 (V + 15168)
+ 0x1105, 0x1163, 0x11ba, 0,
+#undef V3997
+#define V3997 (V + 15172)
+ 0x1105, 0x1163, 0x11bb, 0,
+#undef V3998
+#define V3998 (V + 15176)
+ 0x1105, 0x1163, 0x11bc, 0,
+#undef V3999
+#define V3999 (V + 15180)
+ 0x1105, 0x1163, 0x11bd, 0,
+#undef V4000
+#define V4000 (V + 15184)
+ 0x1105, 0x1163, 0x11be, 0,
+#undef V4001
+#define V4001 (V + 15188)
+ 0x1105, 0x1163, 0x11bf, 0,
+#undef V4002
+#define V4002 (V + 15192)
+ 0x1105, 0x1163, 0x11c0, 0,
+#undef V4003
+#define V4003 (V + 15196)
+ 0x1105, 0x1163, 0x11c1, 0,
+#undef V4004
+#define V4004 (V + 15200)
+ 0x1105, 0x1163, 0x11c2, 0,
+#undef V4005
+#define V4005 (V + 15204)
+ 0x1105, 0x1164, 0,
+#undef V4006
+#define V4006 (V + 15207)
+ 0x1105, 0x1164, 0x11a8, 0,
+#undef V4007
+#define V4007 (V + 15211)
+ 0x1105, 0x1164, 0x11a9, 0,
+#undef V4008
+#define V4008 (V + 15215)
+ 0x1105, 0x1164, 0x11aa, 0,
+#undef V4009
+#define V4009 (V + 15219)
+ 0x1105, 0x1164, 0x11ab, 0,
+#undef V4010
+#define V4010 (V + 15223)
+ 0x1105, 0x1164, 0x11ac, 0,
+#undef V4011
+#define V4011 (V + 15227)
+ 0x1105, 0x1164, 0x11ad, 0,
+#undef V4012
+#define V4012 (V + 15231)
+ 0x1105, 0x1164, 0x11ae, 0,
+#undef V4013
+#define V4013 (V + 15235)
+ 0x1105, 0x1164, 0x11af, 0,
+#undef V4014
+#define V4014 (V + 15239)
+ 0x1105, 0x1164, 0x11b0, 0,
+#undef V4015
+#define V4015 (V + 15243)
+ 0x1105, 0x1164, 0x11b1, 0,
+#undef V4016
+#define V4016 (V + 15247)
+ 0x1105, 0x1164, 0x11b2, 0,
+#undef V4017
+#define V4017 (V + 15251)
+ 0x1105, 0x1164, 0x11b3, 0,
+#undef V4018
+#define V4018 (V + 15255)
+ 0x1105, 0x1164, 0x11b4, 0,
+#undef V4019
+#define V4019 (V + 15259)
+ 0x1105, 0x1164, 0x11b5, 0,
+#undef V4020
+#define V4020 (V + 15263)
+ 0x1105, 0x1164, 0x11b6, 0,
+#undef V4021
+#define V4021 (V + 15267)
+ 0x1105, 0x1164, 0x11b7, 0,
+#undef V4022
+#define V4022 (V + 15271)
+ 0x1105, 0x1164, 0x11b8, 0,
+#undef V4023
+#define V4023 (V + 15275)
+ 0x1105, 0x1164, 0x11b9, 0,
+#undef V4024
+#define V4024 (V + 15279)
+ 0x1105, 0x1164, 0x11ba, 0,
+#undef V4025
+#define V4025 (V + 15283)
+ 0x1105, 0x1164, 0x11bb, 0,
+#undef V4026
+#define V4026 (V + 15287)
+ 0x1105, 0x1164, 0x11bc, 0,
+#undef V4027
+#define V4027 (V + 15291)
+ 0x1105, 0x1164, 0x11bd, 0,
+#undef V4028
+#define V4028 (V + 15295)
+ 0x1105, 0x1164, 0x11be, 0,
+#undef V4029
+#define V4029 (V + 15299)
+ 0x1105, 0x1164, 0x11bf, 0,
+#undef V4030
+#define V4030 (V + 15303)
+ 0x1105, 0x1164, 0x11c0, 0,
+#undef V4031
+#define V4031 (V + 15307)
+ 0x1105, 0x1164, 0x11c1, 0,
+#undef V4032
+#define V4032 (V + 15311)
+ 0x1105, 0x1164, 0x11c2, 0,
+#undef V4033
+#define V4033 (V + 15315)
+ 0x1105, 0x1165, 0,
+#undef V4034
+#define V4034 (V + 15318)
+ 0x1105, 0x1165, 0x11a8, 0,
+#undef V4035
+#define V4035 (V + 15322)
+ 0x1105, 0x1165, 0x11a9, 0,
+#undef V4036
+#define V4036 (V + 15326)
+ 0x1105, 0x1165, 0x11aa, 0,
+#undef V4037
+#define V4037 (V + 15330)
+ 0x1105, 0x1165, 0x11ab, 0,
+#undef V4038
+#define V4038 (V + 15334)
+ 0x1105, 0x1165, 0x11ac, 0,
+#undef V4039
+#define V4039 (V + 15338)
+ 0x1105, 0x1165, 0x11ad, 0,
+#undef V4040
+#define V4040 (V + 15342)
+ 0x1105, 0x1165, 0x11ae, 0,
+#undef V4041
+#define V4041 (V + 15346)
+ 0x1105, 0x1165, 0x11af, 0,
+#undef V4042
+#define V4042 (V + 15350)
+ 0x1105, 0x1165, 0x11b0, 0,
+#undef V4043
+#define V4043 (V + 15354)
+ 0x1105, 0x1165, 0x11b1, 0,
+#undef V4044
+#define V4044 (V + 15358)
+ 0x1105, 0x1165, 0x11b2, 0,
+#undef V4045
+#define V4045 (V + 15362)
+ 0x1105, 0x1165, 0x11b3, 0,
+#undef V4046
+#define V4046 (V + 15366)
+ 0x1105, 0x1165, 0x11b4, 0,
+#undef V4047
+#define V4047 (V + 15370)
+ 0x1105, 0x1165, 0x11b5, 0,
+#undef V4048
+#define V4048 (V + 15374)
+ 0x1105, 0x1165, 0x11b6, 0,
+#undef V4049
+#define V4049 (V + 15378)
+ 0x1105, 0x1165, 0x11b7, 0,
+#undef V4050
+#define V4050 (V + 15382)
+ 0x1105, 0x1165, 0x11b8, 0,
+#undef V4051
+#define V4051 (V + 15386)
+ 0x1105, 0x1165, 0x11b9, 0,
+#undef V4052
+#define V4052 (V + 15390)
+ 0x1105, 0x1165, 0x11ba, 0,
+#undef V4053
+#define V4053 (V + 15394)
+ 0x1105, 0x1165, 0x11bb, 0,
+#undef V4054
+#define V4054 (V + 15398)
+ 0x1105, 0x1165, 0x11bc, 0,
+#undef V4055
+#define V4055 (V + 15402)
+ 0x1105, 0x1165, 0x11bd, 0,
+#undef V4056
+#define V4056 (V + 15406)
+ 0x1105, 0x1165, 0x11be, 0,
+#undef V4057
+#define V4057 (V + 15410)
+ 0x1105, 0x1165, 0x11bf, 0,
+#undef V4058
+#define V4058 (V + 15414)
+ 0x1105, 0x1165, 0x11c0, 0,
+#undef V4059
+#define V4059 (V + 15418)
+ 0x1105, 0x1165, 0x11c1, 0,
+#undef V4060
+#define V4060 (V + 15422)
+ 0x1105, 0x1165, 0x11c2, 0,
+#undef V4061
+#define V4061 (V + 15426)
+ 0x1105, 0x1166, 0,
+#undef V4062
+#define V4062 (V + 15429)
+ 0x1105, 0x1166, 0x11a8, 0,
+#undef V4063
+#define V4063 (V + 15433)
+ 0x1105, 0x1166, 0x11a9, 0,
+#undef V4064
+#define V4064 (V + 15437)
+ 0x1105, 0x1166, 0x11aa, 0,
+#undef V4065
+#define V4065 (V + 15441)
+ 0x1105, 0x1166, 0x11ab, 0,
+#undef V4066
+#define V4066 (V + 15445)
+ 0x1105, 0x1166, 0x11ac, 0,
+#undef V4067
+#define V4067 (V + 15449)
+ 0x1105, 0x1166, 0x11ad, 0,
+#undef V4068
+#define V4068 (V + 15453)
+ 0x1105, 0x1166, 0x11ae, 0,
+#undef V4069
+#define V4069 (V + 15457)
+ 0x1105, 0x1166, 0x11af, 0,
+#undef V4070
+#define V4070 (V + 15461)
+ 0x1105, 0x1166, 0x11b0, 0,
+#undef V4071
+#define V4071 (V + 15465)
+ 0x1105, 0x1166, 0x11b1, 0,
+#undef V4072
+#define V4072 (V + 15469)
+ 0x1105, 0x1166, 0x11b2, 0,
+#undef V4073
+#define V4073 (V + 15473)
+ 0x1105, 0x1166, 0x11b3, 0,
+#undef V4074
+#define V4074 (V + 15477)
+ 0x1105, 0x1166, 0x11b4, 0,
+#undef V4075
+#define V4075 (V + 15481)
+ 0x1105, 0x1166, 0x11b5, 0,
+#undef V4076
+#define V4076 (V + 15485)
+ 0x1105, 0x1166, 0x11b6, 0,
+#undef V4077
+#define V4077 (V + 15489)
+ 0x1105, 0x1166, 0x11b7, 0,
+#undef V4078
+#define V4078 (V + 15493)
+ 0x1105, 0x1166, 0x11b8, 0,
+#undef V4079
+#define V4079 (V + 15497)
+ 0x1105, 0x1166, 0x11b9, 0,
+#undef V4080
+#define V4080 (V + 15501)
+ 0x1105, 0x1166, 0x11ba, 0,
+#undef V4081
+#define V4081 (V + 15505)
+ 0x1105, 0x1166, 0x11bb, 0,
+#undef V4082
+#define V4082 (V + 15509)
+ 0x1105, 0x1166, 0x11bc, 0,
+#undef V4083
+#define V4083 (V + 15513)
+ 0x1105, 0x1166, 0x11bd, 0,
+#undef V4084
+#define V4084 (V + 15517)
+ 0x1105, 0x1166, 0x11be, 0,
+#undef V4085
+#define V4085 (V + 15521)
+ 0x1105, 0x1166, 0x11bf, 0,
+#undef V4086
+#define V4086 (V + 15525)
+ 0x1105, 0x1166, 0x11c0, 0,
+#undef V4087
+#define V4087 (V + 15529)
+ 0x1105, 0x1166, 0x11c1, 0,
+#undef V4088
+#define V4088 (V + 15533)
+ 0x1105, 0x1166, 0x11c2, 0,
+#undef V4089
+#define V4089 (V + 15537)
+ 0x1105, 0x1167, 0,
+#undef V4090
+#define V4090 (V + 15540)
+ 0x1105, 0x1167, 0x11a8, 0,
+#undef V4091
+#define V4091 (V + 15544)
+ 0x1105, 0x1167, 0x11a9, 0,
+#undef V4092
+#define V4092 (V + 15548)
+ 0x1105, 0x1167, 0x11aa, 0,
+#undef V4093
+#define V4093 (V + 15552)
+ 0x1105, 0x1167, 0x11ab, 0,
+#undef V4094
+#define V4094 (V + 15556)
+ 0x1105, 0x1167, 0x11ac, 0,
+#undef V4095
+#define V4095 (V + 15560)
+ 0x1105, 0x1167, 0x11ad, 0,
+#undef V4096
+#define V4096 (V + 15564)
+ 0x1105, 0x1167, 0x11ae, 0,
+#undef V4097
+#define V4097 (V + 15568)
+ 0x1105, 0x1167, 0x11af, 0,
+#undef V4098
+#define V4098 (V + 15572)
+ 0x1105, 0x1167, 0x11b0, 0,
+#undef V4099
+#define V4099 (V + 15576)
+ 0x1105, 0x1167, 0x11b1, 0,
+#undef V4100
+#define V4100 (V + 15580)
+ 0x1105, 0x1167, 0x11b2, 0,
+#undef V4101
+#define V4101 (V + 15584)
+ 0x1105, 0x1167, 0x11b3, 0,
+#undef V4102
+#define V4102 (V + 15588)
+ 0x1105, 0x1167, 0x11b4, 0,
+#undef V4103
+#define V4103 (V + 15592)
+ 0x1105, 0x1167, 0x11b5, 0,
+#undef V4104
+#define V4104 (V + 15596)
+ 0x1105, 0x1167, 0x11b6, 0,
+#undef V4105
+#define V4105 (V + 15600)
+ 0x1105, 0x1167, 0x11b7, 0,
+#undef V4106
+#define V4106 (V + 15604)
+ 0x1105, 0x1167, 0x11b8, 0,
+#undef V4107
+#define V4107 (V + 15608)
+ 0x1105, 0x1167, 0x11b9, 0,
+#undef V4108
+#define V4108 (V + 15612)
+ 0x1105, 0x1167, 0x11ba, 0,
+#undef V4109
+#define V4109 (V + 15616)
+ 0x1105, 0x1167, 0x11bb, 0,
+#undef V4110
+#define V4110 (V + 15620)
+ 0x1105, 0x1167, 0x11bc, 0,
+#undef V4111
+#define V4111 (V + 15624)
+ 0x1105, 0x1167, 0x11bd, 0,
+#undef V4112
+#define V4112 (V + 15628)
+ 0x1105, 0x1167, 0x11be, 0,
+#undef V4113
+#define V4113 (V + 15632)
+ 0x1105, 0x1167, 0x11bf, 0,
+#undef V4114
+#define V4114 (V + 15636)
+ 0x1105, 0x1167, 0x11c0, 0,
+#undef V4115
+#define V4115 (V + 15640)
+ 0x1105, 0x1167, 0x11c1, 0,
+#undef V4116
+#define V4116 (V + 15644)
+ 0x1105, 0x1167, 0x11c2, 0,
+#undef V4117
+#define V4117 (V + 15648)
+ 0x1105, 0x1168, 0,
+#undef V4118
+#define V4118 (V + 15651)
+ 0x1105, 0x1168, 0x11a8, 0,
+#undef V4119
+#define V4119 (V + 15655)
+ 0x1105, 0x1168, 0x11a9, 0,
+#undef V4120
+#define V4120 (V + 15659)
+ 0x1105, 0x1168, 0x11aa, 0,
+#undef V4121
+#define V4121 (V + 15663)
+ 0x1105, 0x1168, 0x11ab, 0,
+#undef V4122
+#define V4122 (V + 15667)
+ 0x1105, 0x1168, 0x11ac, 0,
+#undef V4123
+#define V4123 (V + 15671)
+ 0x1105, 0x1168, 0x11ad, 0,
+#undef V4124
+#define V4124 (V + 15675)
+ 0x1105, 0x1168, 0x11ae, 0,
+#undef V4125
+#define V4125 (V + 15679)
+ 0x1105, 0x1168, 0x11af, 0,
+#undef V4126
+#define V4126 (V + 15683)
+ 0x1105, 0x1168, 0x11b0, 0,
+#undef V4127
+#define V4127 (V + 15687)
+ 0x1105, 0x1168, 0x11b1, 0,
+#undef V4128
+#define V4128 (V + 15691)
+ 0x1105, 0x1168, 0x11b2, 0,
+#undef V4129
+#define V4129 (V + 15695)
+ 0x1105, 0x1168, 0x11b3, 0,
+#undef V4130
+#define V4130 (V + 15699)
+ 0x1105, 0x1168, 0x11b4, 0,
+#undef V4131
+#define V4131 (V + 15703)
+ 0x1105, 0x1168, 0x11b5, 0,
+#undef V4132
+#define V4132 (V + 15707)
+ 0x1105, 0x1168, 0x11b6, 0,
+#undef V4133
+#define V4133 (V + 15711)
+ 0x1105, 0x1168, 0x11b7, 0,
+#undef V4134
+#define V4134 (V + 15715)
+ 0x1105, 0x1168, 0x11b8, 0,
+#undef V4135
+#define V4135 (V + 15719)
+ 0x1105, 0x1168, 0x11b9, 0,
+#undef V4136
+#define V4136 (V + 15723)
+ 0x1105, 0x1168, 0x11ba, 0,
+#undef V4137
+#define V4137 (V + 15727)
+ 0x1105, 0x1168, 0x11bb, 0,
+#undef V4138
+#define V4138 (V + 15731)
+ 0x1105, 0x1168, 0x11bc, 0,
+#undef V4139
+#define V4139 (V + 15735)
+ 0x1105, 0x1168, 0x11bd, 0,
+#undef V4140
+#define V4140 (V + 15739)
+ 0x1105, 0x1168, 0x11be, 0,
+#undef V4141
+#define V4141 (V + 15743)
+ 0x1105, 0x1168, 0x11bf, 0,
+#undef V4142
+#define V4142 (V + 15747)
+ 0x1105, 0x1168, 0x11c0, 0,
+#undef V4143
+#define V4143 (V + 15751)
+ 0x1105, 0x1168, 0x11c1, 0,
+#undef V4144
+#define V4144 (V + 15755)
+ 0x1105, 0x1168, 0x11c2, 0,
+#undef V4145
+#define V4145 (V + 15759)
+ 0x1105, 0x1169, 0,
+#undef V4146
+#define V4146 (V + 15762)
+ 0x1105, 0x1169, 0x11a8, 0,
+#undef V4147
+#define V4147 (V + 15766)
+ 0x1105, 0x1169, 0x11a9, 0,
+#undef V4148
+#define V4148 (V + 15770)
+ 0x1105, 0x1169, 0x11aa, 0,
+#undef V4149
+#define V4149 (V + 15774)
+ 0x1105, 0x1169, 0x11ab, 0,
+#undef V4150
+#define V4150 (V + 15778)
+ 0x1105, 0x1169, 0x11ac, 0,
+#undef V4151
+#define V4151 (V + 15782)
+ 0x1105, 0x1169, 0x11ad, 0,
+#undef V4152
+#define V4152 (V + 15786)
+ 0x1105, 0x1169, 0x11ae, 0,
+#undef V4153
+#define V4153 (V + 15790)
+ 0x1105, 0x1169, 0x11af, 0,
+#undef V4154
+#define V4154 (V + 15794)
+ 0x1105, 0x1169, 0x11b0, 0,
+#undef V4155
+#define V4155 (V + 15798)
+ 0x1105, 0x1169, 0x11b1, 0,
+#undef V4156
+#define V4156 (V + 15802)
+ 0x1105, 0x1169, 0x11b2, 0,
+#undef V4157
+#define V4157 (V + 15806)
+ 0x1105, 0x1169, 0x11b3, 0,
+#undef V4158
+#define V4158 (V + 15810)
+ 0x1105, 0x1169, 0x11b4, 0,
+#undef V4159
+#define V4159 (V + 15814)
+ 0x1105, 0x1169, 0x11b5, 0,
+#undef V4160
+#define V4160 (V + 15818)
+ 0x1105, 0x1169, 0x11b6, 0,
+#undef V4161
+#define V4161 (V + 15822)
+ 0x1105, 0x1169, 0x11b7, 0,
+#undef V4162
+#define V4162 (V + 15826)
+ 0x1105, 0x1169, 0x11b8, 0,
+#undef V4163
+#define V4163 (V + 15830)
+ 0x1105, 0x1169, 0x11b9, 0,
+#undef V4164
+#define V4164 (V + 15834)
+ 0x1105, 0x1169, 0x11ba, 0,
+#undef V4165
+#define V4165 (V + 15838)
+ 0x1105, 0x1169, 0x11bb, 0,
+#undef V4166
+#define V4166 (V + 15842)
+ 0x1105, 0x1169, 0x11bc, 0,
+#undef V4167
+#define V4167 (V + 15846)
+ 0x1105, 0x1169, 0x11bd, 0,
+#undef V4168
+#define V4168 (V + 15850)
+ 0x1105, 0x1169, 0x11be, 0,
+#undef V4169
+#define V4169 (V + 15854)
+ 0x1105, 0x1169, 0x11bf, 0,
+#undef V4170
+#define V4170 (V + 15858)
+ 0x1105, 0x1169, 0x11c0, 0,
+#undef V4171
+#define V4171 (V + 15862)
+ 0x1105, 0x1169, 0x11c1, 0,
+#undef V4172
+#define V4172 (V + 15866)
+ 0x1105, 0x1169, 0x11c2, 0,
+#undef V4173
+#define V4173 (V + 15870)
+ 0x1105, 0x116a, 0,
+#undef V4174
+#define V4174 (V + 15873)
+ 0x1105, 0x116a, 0x11a8, 0,
+#undef V4175
+#define V4175 (V + 15877)
+ 0x1105, 0x116a, 0x11a9, 0,
+#undef V4176
+#define V4176 (V + 15881)
+ 0x1105, 0x116a, 0x11aa, 0,
+#undef V4177
+#define V4177 (V + 15885)
+ 0x1105, 0x116a, 0x11ab, 0,
+#undef V4178
+#define V4178 (V + 15889)
+ 0x1105, 0x116a, 0x11ac, 0,
+#undef V4179
+#define V4179 (V + 15893)
+ 0x1105, 0x116a, 0x11ad, 0,
+#undef V4180
+#define V4180 (V + 15897)
+ 0x1105, 0x116a, 0x11ae, 0,
+#undef V4181
+#define V4181 (V + 15901)
+ 0x1105, 0x116a, 0x11af, 0,
+#undef V4182
+#define V4182 (V + 15905)
+ 0x1105, 0x116a, 0x11b0, 0,
+#undef V4183
+#define V4183 (V + 15909)
+ 0x1105, 0x116a, 0x11b1, 0,
+#undef V4184
+#define V4184 (V + 15913)
+ 0x1105, 0x116a, 0x11b2, 0,
+#undef V4185
+#define V4185 (V + 15917)
+ 0x1105, 0x116a, 0x11b3, 0,
+#undef V4186
+#define V4186 (V + 15921)
+ 0x1105, 0x116a, 0x11b4, 0,
+#undef V4187
+#define V4187 (V + 15925)
+ 0x1105, 0x116a, 0x11b5, 0,
+#undef V4188
+#define V4188 (V + 15929)
+ 0x1105, 0x116a, 0x11b6, 0,
+#undef V4189
+#define V4189 (V + 15933)
+ 0x1105, 0x116a, 0x11b7, 0,
+#undef V4190
+#define V4190 (V + 15937)
+ 0x1105, 0x116a, 0x11b8, 0,
+#undef V4191
+#define V4191 (V + 15941)
+ 0x1105, 0x116a, 0x11b9, 0,
+#undef V4192
+#define V4192 (V + 15945)
+ 0x1105, 0x116a, 0x11ba, 0,
+#undef V4193
+#define V4193 (V + 15949)
+ 0x1105, 0x116a, 0x11bb, 0,
+#undef V4194
+#define V4194 (V + 15953)
+ 0x1105, 0x116a, 0x11bc, 0,
+#undef V4195
+#define V4195 (V + 15957)
+ 0x1105, 0x116a, 0x11bd, 0,
+#undef V4196
+#define V4196 (V + 15961)
+ 0x1105, 0x116a, 0x11be, 0,
+#undef V4197
+#define V4197 (V + 15965)
+ 0x1105, 0x116a, 0x11bf, 0,
+#undef V4198
+#define V4198 (V + 15969)
+ 0x1105, 0x116a, 0x11c0, 0,
+#undef V4199
+#define V4199 (V + 15973)
+ 0x1105, 0x116a, 0x11c1, 0,
+#undef V4200
+#define V4200 (V + 15977)
+ 0x1105, 0x116a, 0x11c2, 0,
+#undef V4201
+#define V4201 (V + 15981)
+ 0x1105, 0x116b, 0,
+#undef V4202
+#define V4202 (V + 15984)
+ 0x1105, 0x116b, 0x11a8, 0,
+#undef V4203
+#define V4203 (V + 15988)
+ 0x1105, 0x116b, 0x11a9, 0,
+#undef V4204
+#define V4204 (V + 15992)
+ 0x1105, 0x116b, 0x11aa, 0,
+#undef V4205
+#define V4205 (V + 15996)
+ 0x1105, 0x116b, 0x11ab, 0,
+#undef V4206
+#define V4206 (V + 16000)
+ 0x1105, 0x116b, 0x11ac, 0,
+#undef V4207
+#define V4207 (V + 16004)
+ 0x1105, 0x116b, 0x11ad, 0,
+#undef V4208
+#define V4208 (V + 16008)
+ 0x1105, 0x116b, 0x11ae, 0,
+#undef V4209
+#define V4209 (V + 16012)
+ 0x1105, 0x116b, 0x11af, 0,
+#undef V4210
+#define V4210 (V + 16016)
+ 0x1105, 0x116b, 0x11b0, 0,
+#undef V4211
+#define V4211 (V + 16020)
+ 0x1105, 0x116b, 0x11b1, 0,
+#undef V4212
+#define V4212 (V + 16024)
+ 0x1105, 0x116b, 0x11b2, 0,
+#undef V4213
+#define V4213 (V + 16028)
+ 0x1105, 0x116b, 0x11b3, 0,
+#undef V4214
+#define V4214 (V + 16032)
+ 0x1105, 0x116b, 0x11b4, 0,
+#undef V4215
+#define V4215 (V + 16036)
+ 0x1105, 0x116b, 0x11b5, 0,
+#undef V4216
+#define V4216 (V + 16040)
+ 0x1105, 0x116b, 0x11b6, 0,
+#undef V4217
+#define V4217 (V + 16044)
+ 0x1105, 0x116b, 0x11b7, 0,
+#undef V4218
+#define V4218 (V + 16048)
+ 0x1105, 0x116b, 0x11b8, 0,
+#undef V4219
+#define V4219 (V + 16052)
+ 0x1105, 0x116b, 0x11b9, 0,
+#undef V4220
+#define V4220 (V + 16056)
+ 0x1105, 0x116b, 0x11ba, 0,
+#undef V4221
+#define V4221 (V + 16060)
+ 0x1105, 0x116b, 0x11bb, 0,
+#undef V4222
+#define V4222 (V + 16064)
+ 0x1105, 0x116b, 0x11bc, 0,
+#undef V4223
+#define V4223 (V + 16068)
+ 0x1105, 0x116b, 0x11bd, 0,
+#undef V4224
+#define V4224 (V + 16072)
+ 0x1105, 0x116b, 0x11be, 0,
+#undef V4225
+#define V4225 (V + 16076)
+ 0x1105, 0x116b, 0x11bf, 0,
+#undef V4226
+#define V4226 (V + 16080)
+ 0x1105, 0x116b, 0x11c0, 0,
+#undef V4227
+#define V4227 (V + 16084)
+ 0x1105, 0x116b, 0x11c1, 0,
+#undef V4228
+#define V4228 (V + 16088)
+ 0x1105, 0x116b, 0x11c2, 0,
+#undef V4229
+#define V4229 (V + 16092)
+ 0x1105, 0x116c, 0,
+#undef V4230
+#define V4230 (V + 16095)
+ 0x1105, 0x116c, 0x11a8, 0,
+#undef V4231
+#define V4231 (V + 16099)
+ 0x1105, 0x116c, 0x11a9, 0,
+#undef V4232
+#define V4232 (V + 16103)
+ 0x1105, 0x116c, 0x11aa, 0,
+#undef V4233
+#define V4233 (V + 16107)
+ 0x1105, 0x116c, 0x11ab, 0,
+#undef V4234
+#define V4234 (V + 16111)
+ 0x1105, 0x116c, 0x11ac, 0,
+#undef V4235
+#define V4235 (V + 16115)
+ 0x1105, 0x116c, 0x11ad, 0,
+#undef V4236
+#define V4236 (V + 16119)
+ 0x1105, 0x116c, 0x11ae, 0,
+#undef V4237
+#define V4237 (V + 16123)
+ 0x1105, 0x116c, 0x11af, 0,
+#undef V4238
+#define V4238 (V + 16127)
+ 0x1105, 0x116c, 0x11b0, 0,
+#undef V4239
+#define V4239 (V + 16131)
+ 0x1105, 0x116c, 0x11b1, 0,
+#undef V4240
+#define V4240 (V + 16135)
+ 0x1105, 0x116c, 0x11b2, 0,
+#undef V4241
+#define V4241 (V + 16139)
+ 0x1105, 0x116c, 0x11b3, 0,
+#undef V4242
+#define V4242 (V + 16143)
+ 0x1105, 0x116c, 0x11b4, 0,
+#undef V4243
+#define V4243 (V + 16147)
+ 0x1105, 0x116c, 0x11b5, 0,
+#undef V4244
+#define V4244 (V + 16151)
+ 0x1105, 0x116c, 0x11b6, 0,
+#undef V4245
+#define V4245 (V + 16155)
+ 0x1105, 0x116c, 0x11b7, 0,
+#undef V4246
+#define V4246 (V + 16159)
+ 0x1105, 0x116c, 0x11b8, 0,
+#undef V4247
+#define V4247 (V + 16163)
+ 0x1105, 0x116c, 0x11b9, 0,
+#undef V4248
+#define V4248 (V + 16167)
+ 0x1105, 0x116c, 0x11ba, 0,
+#undef V4249
+#define V4249 (V + 16171)
+ 0x1105, 0x116c, 0x11bb, 0,
+#undef V4250
+#define V4250 (V + 16175)
+ 0x1105, 0x116c, 0x11bc, 0,
+#undef V4251
+#define V4251 (V + 16179)
+ 0x1105, 0x116c, 0x11bd, 0,
+#undef V4252
+#define V4252 (V + 16183)
+ 0x1105, 0x116c, 0x11be, 0,
+#undef V4253
+#define V4253 (V + 16187)
+ 0x1105, 0x116c, 0x11bf, 0,
+#undef V4254
+#define V4254 (V + 16191)
+ 0x1105, 0x116c, 0x11c0, 0,
+#undef V4255
+#define V4255 (V + 16195)
+ 0x1105, 0x116c, 0x11c1, 0,
+#undef V4256
+#define V4256 (V + 16199)
+ 0x1105, 0x116c, 0x11c2, 0,
+#undef V4257
+#define V4257 (V + 16203)
+ 0x1105, 0x116d, 0,
+#undef V4258
+#define V4258 (V + 16206)
+ 0x1105, 0x116d, 0x11a8, 0,
+#undef V4259
+#define V4259 (V + 16210)
+ 0x1105, 0x116d, 0x11a9, 0,
+#undef V4260
+#define V4260 (V + 16214)
+ 0x1105, 0x116d, 0x11aa, 0,
+#undef V4261
+#define V4261 (V + 16218)
+ 0x1105, 0x116d, 0x11ab, 0,
+#undef V4262
+#define V4262 (V + 16222)
+ 0x1105, 0x116d, 0x11ac, 0,
+#undef V4263
+#define V4263 (V + 16226)
+ 0x1105, 0x116d, 0x11ad, 0,
+#undef V4264
+#define V4264 (V + 16230)
+ 0x1105, 0x116d, 0x11ae, 0,
+#undef V4265
+#define V4265 (V + 16234)
+ 0x1105, 0x116d, 0x11af, 0,
+#undef V4266
+#define V4266 (V + 16238)
+ 0x1105, 0x116d, 0x11b0, 0,
+#undef V4267
+#define V4267 (V + 16242)
+ 0x1105, 0x116d, 0x11b1, 0,
+#undef V4268
+#define V4268 (V + 16246)
+ 0x1105, 0x116d, 0x11b2, 0,
+#undef V4269
+#define V4269 (V + 16250)
+ 0x1105, 0x116d, 0x11b3, 0,
+#undef V4270
+#define V4270 (V + 16254)
+ 0x1105, 0x116d, 0x11b4, 0,
+#undef V4271
+#define V4271 (V + 16258)
+ 0x1105, 0x116d, 0x11b5, 0,
+#undef V4272
+#define V4272 (V + 16262)
+ 0x1105, 0x116d, 0x11b6, 0,
+#undef V4273
+#define V4273 (V + 16266)
+ 0x1105, 0x116d, 0x11b7, 0,
+#undef V4274
+#define V4274 (V + 16270)
+ 0x1105, 0x116d, 0x11b8, 0,
+#undef V4275
+#define V4275 (V + 16274)
+ 0x1105, 0x116d, 0x11b9, 0,
+#undef V4276
+#define V4276 (V + 16278)
+ 0x1105, 0x116d, 0x11ba, 0,
+#undef V4277
+#define V4277 (V + 16282)
+ 0x1105, 0x116d, 0x11bb, 0,
+#undef V4278
+#define V4278 (V + 16286)
+ 0x1105, 0x116d, 0x11bc, 0,
+#undef V4279
+#define V4279 (V + 16290)
+ 0x1105, 0x116d, 0x11bd, 0,
+#undef V4280
+#define V4280 (V + 16294)
+ 0x1105, 0x116d, 0x11be, 0,
+#undef V4281
+#define V4281 (V + 16298)
+ 0x1105, 0x116d, 0x11bf, 0,
+#undef V4282
+#define V4282 (V + 16302)
+ 0x1105, 0x116d, 0x11c0, 0,
+#undef V4283
+#define V4283 (V + 16306)
+ 0x1105, 0x116d, 0x11c1, 0,
+#undef V4284
+#define V4284 (V + 16310)
+ 0x1105, 0x116d, 0x11c2, 0,
+#undef V4285
+#define V4285 (V + 16314)
+ 0x1105, 0x116e, 0,
+#undef V4286
+#define V4286 (V + 16317)
+ 0x1105, 0x116e, 0x11a8, 0,
+#undef V4287
+#define V4287 (V + 16321)
+ 0x1105, 0x116e, 0x11a9, 0,
+#undef V4288
+#define V4288 (V + 16325)
+ 0x1105, 0x116e, 0x11aa, 0,
+#undef V4289
+#define V4289 (V + 16329)
+ 0x1105, 0x116e, 0x11ab, 0,
+#undef V4290
+#define V4290 (V + 16333)
+ 0x1105, 0x116e, 0x11ac, 0,
+#undef V4291
+#define V4291 (V + 16337)
+ 0x1105, 0x116e, 0x11ad, 0,
+#undef V4292
+#define V4292 (V + 16341)
+ 0x1105, 0x116e, 0x11ae, 0,
+#undef V4293
+#define V4293 (V + 16345)
+ 0x1105, 0x116e, 0x11af, 0,
+#undef V4294
+#define V4294 (V + 16349)
+ 0x1105, 0x116e, 0x11b0, 0,
+#undef V4295
+#define V4295 (V + 16353)
+ 0x1105, 0x116e, 0x11b1, 0,
+#undef V4296
+#define V4296 (V + 16357)
+ 0x1105, 0x116e, 0x11b2, 0,
+#undef V4297
+#define V4297 (V + 16361)
+ 0x1105, 0x116e, 0x11b3, 0,
+#undef V4298
+#define V4298 (V + 16365)
+ 0x1105, 0x116e, 0x11b4, 0,
+#undef V4299
+#define V4299 (V + 16369)
+ 0x1105, 0x116e, 0x11b5, 0,
+#undef V4300
+#define V4300 (V + 16373)
+ 0x1105, 0x116e, 0x11b6, 0,
+#undef V4301
+#define V4301 (V + 16377)
+ 0x1105, 0x116e, 0x11b7, 0,
+#undef V4302
+#define V4302 (V + 16381)
+ 0x1105, 0x116e, 0x11b8, 0,
+#undef V4303
+#define V4303 (V + 16385)
+ 0x1105, 0x116e, 0x11b9, 0,
+#undef V4304
+#define V4304 (V + 16389)
+ 0x1105, 0x116e, 0x11ba, 0,
+#undef V4305
+#define V4305 (V + 16393)
+ 0x1105, 0x116e, 0x11bb, 0,
+#undef V4306
+#define V4306 (V + 16397)
+ 0x1105, 0x116e, 0x11bc, 0,
+#undef V4307
+#define V4307 (V + 16401)
+ 0x1105, 0x116e, 0x11bd, 0,
+#undef V4308
+#define V4308 (V + 16405)
+ 0x1105, 0x116e, 0x11be, 0,
+#undef V4309
+#define V4309 (V + 16409)
+ 0x1105, 0x116e, 0x11bf, 0,
+#undef V4310
+#define V4310 (V + 16413)
+ 0x1105, 0x116e, 0x11c0, 0,
+#undef V4311
+#define V4311 (V + 16417)
+ 0x1105, 0x116e, 0x11c1, 0,
+#undef V4312
+#define V4312 (V + 16421)
+ 0x1105, 0x116e, 0x11c2, 0,
+#undef V4313
+#define V4313 (V + 16425)
+ 0x1105, 0x116f, 0,
+#undef V4314
+#define V4314 (V + 16428)
+ 0x1105, 0x116f, 0x11a8, 0,
+#undef V4315
+#define V4315 (V + 16432)
+ 0x1105, 0x116f, 0x11a9, 0,
+#undef V4316
+#define V4316 (V + 16436)
+ 0x1105, 0x116f, 0x11aa, 0,
+#undef V4317
+#define V4317 (V + 16440)
+ 0x1105, 0x116f, 0x11ab, 0,
+#undef V4318
+#define V4318 (V + 16444)
+ 0x1105, 0x116f, 0x11ac, 0,
+#undef V4319
+#define V4319 (V + 16448)
+ 0x1105, 0x116f, 0x11ad, 0,
+#undef V4320
+#define V4320 (V + 16452)
+ 0x1105, 0x116f, 0x11ae, 0,
+#undef V4321
+#define V4321 (V + 16456)
+ 0x1105, 0x116f, 0x11af, 0,
+#undef V4322
+#define V4322 (V + 16460)
+ 0x1105, 0x116f, 0x11b0, 0,
+#undef V4323
+#define V4323 (V + 16464)
+ 0x1105, 0x116f, 0x11b1, 0,
+#undef V4324
+#define V4324 (V + 16468)
+ 0x1105, 0x116f, 0x11b2, 0,
+#undef V4325
+#define V4325 (V + 16472)
+ 0x1105, 0x116f, 0x11b3, 0,
+#undef V4326
+#define V4326 (V + 16476)
+ 0x1105, 0x116f, 0x11b4, 0,
+#undef V4327
+#define V4327 (V + 16480)
+ 0x1105, 0x116f, 0x11b5, 0,
+#undef V4328
+#define V4328 (V + 16484)
+ 0x1105, 0x116f, 0x11b6, 0,
+#undef V4329
+#define V4329 (V + 16488)
+ 0x1105, 0x116f, 0x11b7, 0,
+#undef V4330
+#define V4330 (V + 16492)
+ 0x1105, 0x116f, 0x11b8, 0,
+#undef V4331
+#define V4331 (V + 16496)
+ 0x1105, 0x116f, 0x11b9, 0,
+#undef V4332
+#define V4332 (V + 16500)
+ 0x1105, 0x116f, 0x11ba, 0,
+#undef V4333
+#define V4333 (V + 16504)
+ 0x1105, 0x116f, 0x11bb, 0,
+#undef V4334
+#define V4334 (V + 16508)
+ 0x1105, 0x116f, 0x11bc, 0,
+#undef V4335
+#define V4335 (V + 16512)
+ 0x1105, 0x116f, 0x11bd, 0,
+#undef V4336
+#define V4336 (V + 16516)
+ 0x1105, 0x116f, 0x11be, 0,
+#undef V4337
+#define V4337 (V + 16520)
+ 0x1105, 0x116f, 0x11bf, 0,
+#undef V4338
+#define V4338 (V + 16524)
+ 0x1105, 0x116f, 0x11c0, 0,
+#undef V4339
+#define V4339 (V + 16528)
+ 0x1105, 0x116f, 0x11c1, 0,
+#undef V4340
+#define V4340 (V + 16532)
+ 0x1105, 0x116f, 0x11c2, 0,
+#undef V4341
+#define V4341 (V + 16536)
+ 0x1105, 0x1170, 0,
+#undef V4342
+#define V4342 (V + 16539)
+ 0x1105, 0x1170, 0x11a8, 0,
+#undef V4343
+#define V4343 (V + 16543)
+ 0x1105, 0x1170, 0x11a9, 0,
+#undef V4344
+#define V4344 (V + 16547)
+ 0x1105, 0x1170, 0x11aa, 0,
+#undef V4345
+#define V4345 (V + 16551)
+ 0x1105, 0x1170, 0x11ab, 0,
+#undef V4346
+#define V4346 (V + 16555)
+ 0x1105, 0x1170, 0x11ac, 0,
+#undef V4347
+#define V4347 (V + 16559)
+ 0x1105, 0x1170, 0x11ad, 0,
+#undef V4348
+#define V4348 (V + 16563)
+ 0x1105, 0x1170, 0x11ae, 0,
+#undef V4349
+#define V4349 (V + 16567)
+ 0x1105, 0x1170, 0x11af, 0,
+#undef V4350
+#define V4350 (V + 16571)
+ 0x1105, 0x1170, 0x11b0, 0,
+#undef V4351
+#define V4351 (V + 16575)
+ 0x1105, 0x1170, 0x11b1, 0,
+#undef V4352
+#define V4352 (V + 16579)
+ 0x1105, 0x1170, 0x11b2, 0,
+#undef V4353
+#define V4353 (V + 16583)
+ 0x1105, 0x1170, 0x11b3, 0,
+#undef V4354
+#define V4354 (V + 16587)
+ 0x1105, 0x1170, 0x11b4, 0,
+#undef V4355
+#define V4355 (V + 16591)
+ 0x1105, 0x1170, 0x11b5, 0,
+#undef V4356
+#define V4356 (V + 16595)
+ 0x1105, 0x1170, 0x11b6, 0,
+#undef V4357
+#define V4357 (V + 16599)
+ 0x1105, 0x1170, 0x11b7, 0,
+#undef V4358
+#define V4358 (V + 16603)
+ 0x1105, 0x1170, 0x11b8, 0,
+#undef V4359
+#define V4359 (V + 16607)
+ 0x1105, 0x1170, 0x11b9, 0,
+#undef V4360
+#define V4360 (V + 16611)
+ 0x1105, 0x1170, 0x11ba, 0,
+#undef V4361
+#define V4361 (V + 16615)
+ 0x1105, 0x1170, 0x11bb, 0,
+#undef V4362
+#define V4362 (V + 16619)
+ 0x1105, 0x1170, 0x11bc, 0,
+#undef V4363
+#define V4363 (V + 16623)
+ 0x1105, 0x1170, 0x11bd, 0,
+#undef V4364
+#define V4364 (V + 16627)
+ 0x1105, 0x1170, 0x11be, 0,
+#undef V4365
+#define V4365 (V + 16631)
+ 0x1105, 0x1170, 0x11bf, 0,
+#undef V4366
+#define V4366 (V + 16635)
+ 0x1105, 0x1170, 0x11c0, 0,
+#undef V4367
+#define V4367 (V + 16639)
+ 0x1105, 0x1170, 0x11c1, 0,
+#undef V4368
+#define V4368 (V + 16643)
+ 0x1105, 0x1170, 0x11c2, 0,
+#undef V4369
+#define V4369 (V + 16647)
+ 0x1105, 0x1171, 0,
+#undef V4370
+#define V4370 (V + 16650)
+ 0x1105, 0x1171, 0x11a8, 0,
+#undef V4371
+#define V4371 (V + 16654)
+ 0x1105, 0x1171, 0x11a9, 0,
+#undef V4372
+#define V4372 (V + 16658)
+ 0x1105, 0x1171, 0x11aa, 0,
+#undef V4373
+#define V4373 (V + 16662)
+ 0x1105, 0x1171, 0x11ab, 0,
+#undef V4374
+#define V4374 (V + 16666)
+ 0x1105, 0x1171, 0x11ac, 0,
+#undef V4375
+#define V4375 (V + 16670)
+ 0x1105, 0x1171, 0x11ad, 0,
+#undef V4376
+#define V4376 (V + 16674)
+ 0x1105, 0x1171, 0x11ae, 0,
+#undef V4377
+#define V4377 (V + 16678)
+ 0x1105, 0x1171, 0x11af, 0,
+#undef V4378
+#define V4378 (V + 16682)
+ 0x1105, 0x1171, 0x11b0, 0,
+#undef V4379
+#define V4379 (V + 16686)
+ 0x1105, 0x1171, 0x11b1, 0,
+#undef V4380
+#define V4380 (V + 16690)
+ 0x1105, 0x1171, 0x11b2, 0,
+#undef V4381
+#define V4381 (V + 16694)
+ 0x1105, 0x1171, 0x11b3, 0,
+#undef V4382
+#define V4382 (V + 16698)
+ 0x1105, 0x1171, 0x11b4, 0,
+#undef V4383
+#define V4383 (V + 16702)
+ 0x1105, 0x1171, 0x11b5, 0,
+#undef V4384
+#define V4384 (V + 16706)
+ 0x1105, 0x1171, 0x11b6, 0,
+#undef V4385
+#define V4385 (V + 16710)
+ 0x1105, 0x1171, 0x11b7, 0,
+#undef V4386
+#define V4386 (V + 16714)
+ 0x1105, 0x1171, 0x11b8, 0,
+#undef V4387
+#define V4387 (V + 16718)
+ 0x1105, 0x1171, 0x11b9, 0,
+#undef V4388
+#define V4388 (V + 16722)
+ 0x1105, 0x1171, 0x11ba, 0,
+#undef V4389
+#define V4389 (V + 16726)
+ 0x1105, 0x1171, 0x11bb, 0,
+#undef V4390
+#define V4390 (V + 16730)
+ 0x1105, 0x1171, 0x11bc, 0,
+#undef V4391
+#define V4391 (V + 16734)
+ 0x1105, 0x1171, 0x11bd, 0,
+#undef V4392
+#define V4392 (V + 16738)
+ 0x1105, 0x1171, 0x11be, 0,
+#undef V4393
+#define V4393 (V + 16742)
+ 0x1105, 0x1171, 0x11bf, 0,
+#undef V4394
+#define V4394 (V + 16746)
+ 0x1105, 0x1171, 0x11c0, 0,
+#undef V4395
+#define V4395 (V + 16750)
+ 0x1105, 0x1171, 0x11c1, 0,
+#undef V4396
+#define V4396 (V + 16754)
+ 0x1105, 0x1171, 0x11c2, 0,
+#undef V4397
+#define V4397 (V + 16758)
+ 0x1105, 0x1172, 0,
+#undef V4398
+#define V4398 (V + 16761)
+ 0x1105, 0x1172, 0x11a8, 0,
+#undef V4399
+#define V4399 (V + 16765)
+ 0x1105, 0x1172, 0x11a9, 0,
+#undef V4400
+#define V4400 (V + 16769)
+ 0x1105, 0x1172, 0x11aa, 0,
+#undef V4401
+#define V4401 (V + 16773)
+ 0x1105, 0x1172, 0x11ab, 0,
+#undef V4402
+#define V4402 (V + 16777)
+ 0x1105, 0x1172, 0x11ac, 0,
+#undef V4403
+#define V4403 (V + 16781)
+ 0x1105, 0x1172, 0x11ad, 0,
+#undef V4404
+#define V4404 (V + 16785)
+ 0x1105, 0x1172, 0x11ae, 0,
+#undef V4405
+#define V4405 (V + 16789)
+ 0x1105, 0x1172, 0x11af, 0,
+#undef V4406
+#define V4406 (V + 16793)
+ 0x1105, 0x1172, 0x11b0, 0,
+#undef V4407
+#define V4407 (V + 16797)
+ 0x1105, 0x1172, 0x11b1, 0,
+#undef V4408
+#define V4408 (V + 16801)
+ 0x1105, 0x1172, 0x11b2, 0,
+#undef V4409
+#define V4409 (V + 16805)
+ 0x1105, 0x1172, 0x11b3, 0,
+#undef V4410
+#define V4410 (V + 16809)
+ 0x1105, 0x1172, 0x11b4, 0,
+#undef V4411
+#define V4411 (V + 16813)
+ 0x1105, 0x1172, 0x11b5, 0,
+#undef V4412
+#define V4412 (V + 16817)
+ 0x1105, 0x1172, 0x11b6, 0,
+#undef V4413
+#define V4413 (V + 16821)
+ 0x1105, 0x1172, 0x11b7, 0,
+#undef V4414
+#define V4414 (V + 16825)
+ 0x1105, 0x1172, 0x11b8, 0,
+#undef V4415
+#define V4415 (V + 16829)
+ 0x1105, 0x1172, 0x11b9, 0,
+#undef V4416
+#define V4416 (V + 16833)
+ 0x1105, 0x1172, 0x11ba, 0,
+#undef V4417
+#define V4417 (V + 16837)
+ 0x1105, 0x1172, 0x11bb, 0,
+#undef V4418
+#define V4418 (V + 16841)
+ 0x1105, 0x1172, 0x11bc, 0,
+#undef V4419
+#define V4419 (V + 16845)
+ 0x1105, 0x1172, 0x11bd, 0,
+#undef V4420
+#define V4420 (V + 16849)
+ 0x1105, 0x1172, 0x11be, 0,
+#undef V4421
+#define V4421 (V + 16853)
+ 0x1105, 0x1172, 0x11bf, 0,
+#undef V4422
+#define V4422 (V + 16857)
+ 0x1105, 0x1172, 0x11c0, 0,
+#undef V4423
+#define V4423 (V + 16861)
+ 0x1105, 0x1172, 0x11c1, 0,
+#undef V4424
+#define V4424 (V + 16865)
+ 0x1105, 0x1172, 0x11c2, 0,
+#undef V4425
+#define V4425 (V + 16869)
+ 0x1105, 0x1173, 0,
+#undef V4426
+#define V4426 (V + 16872)
+ 0x1105, 0x1173, 0x11a8, 0,
+#undef V4427
+#define V4427 (V + 16876)
+ 0x1105, 0x1173, 0x11a9, 0,
+#undef V4428
+#define V4428 (V + 16880)
+ 0x1105, 0x1173, 0x11aa, 0,
+#undef V4429
+#define V4429 (V + 16884)
+ 0x1105, 0x1173, 0x11ab, 0,
+#undef V4430
+#define V4430 (V + 16888)
+ 0x1105, 0x1173, 0x11ac, 0,
+#undef V4431
+#define V4431 (V + 16892)
+ 0x1105, 0x1173, 0x11ad, 0,
+#undef V4432
+#define V4432 (V + 16896)
+ 0x1105, 0x1173, 0x11ae, 0,
+#undef V4433
+#define V4433 (V + 16900)
+ 0x1105, 0x1173, 0x11af, 0,
+#undef V4434
+#define V4434 (V + 16904)
+ 0x1105, 0x1173, 0x11b0, 0,
+#undef V4435
+#define V4435 (V + 16908)
+ 0x1105, 0x1173, 0x11b1, 0,
+#undef V4436
+#define V4436 (V + 16912)
+ 0x1105, 0x1173, 0x11b2, 0,
+#undef V4437
+#define V4437 (V + 16916)
+ 0x1105, 0x1173, 0x11b3, 0,
+#undef V4438
+#define V4438 (V + 16920)
+ 0x1105, 0x1173, 0x11b4, 0,
+#undef V4439
+#define V4439 (V + 16924)
+ 0x1105, 0x1173, 0x11b5, 0,
+#undef V4440
+#define V4440 (V + 16928)
+ 0x1105, 0x1173, 0x11b6, 0,
+#undef V4441
+#define V4441 (V + 16932)
+ 0x1105, 0x1173, 0x11b7, 0,
+#undef V4442
+#define V4442 (V + 16936)
+ 0x1105, 0x1173, 0x11b8, 0,
+#undef V4443
+#define V4443 (V + 16940)
+ 0x1105, 0x1173, 0x11b9, 0,
+#undef V4444
+#define V4444 (V + 16944)
+ 0x1105, 0x1173, 0x11ba, 0,
+#undef V4445
+#define V4445 (V + 16948)
+ 0x1105, 0x1173, 0x11bb, 0,
+#undef V4446
+#define V4446 (V + 16952)
+ 0x1105, 0x1173, 0x11bc, 0,
+#undef V4447
+#define V4447 (V + 16956)
+ 0x1105, 0x1173, 0x11bd, 0,
+#undef V4448
+#define V4448 (V + 16960)
+ 0x1105, 0x1173, 0x11be, 0,
+#undef V4449
+#define V4449 (V + 16964)
+ 0x1105, 0x1173, 0x11bf, 0,
+#undef V4450
+#define V4450 (V + 16968)
+ 0x1105, 0x1173, 0x11c0, 0,
+#undef V4451
+#define V4451 (V + 16972)
+ 0x1105, 0x1173, 0x11c1, 0,
+#undef V4452
+#define V4452 (V + 16976)
+ 0x1105, 0x1173, 0x11c2, 0,
+#undef V4453
+#define V4453 (V + 16980)
+ 0x1105, 0x1174, 0,
+#undef V4454
+#define V4454 (V + 16983)
+ 0x1105, 0x1174, 0x11a8, 0,
+#undef V4455
+#define V4455 (V + 16987)
+ 0x1105, 0x1174, 0x11a9, 0,
+#undef V4456
+#define V4456 (V + 16991)
+ 0x1105, 0x1174, 0x11aa, 0,
+#undef V4457
+#define V4457 (V + 16995)
+ 0x1105, 0x1174, 0x11ab, 0,
+#undef V4458
+#define V4458 (V + 16999)
+ 0x1105, 0x1174, 0x11ac, 0,
+#undef V4459
+#define V4459 (V + 17003)
+ 0x1105, 0x1174, 0x11ad, 0,
+#undef V4460
+#define V4460 (V + 17007)
+ 0x1105, 0x1174, 0x11ae, 0,
+#undef V4461
+#define V4461 (V + 17011)
+ 0x1105, 0x1174, 0x11af, 0,
+#undef V4462
+#define V4462 (V + 17015)
+ 0x1105, 0x1174, 0x11b0, 0,
+#undef V4463
+#define V4463 (V + 17019)
+ 0x1105, 0x1174, 0x11b1, 0,
+#undef V4464
+#define V4464 (V + 17023)
+ 0x1105, 0x1174, 0x11b2, 0,
+#undef V4465
+#define V4465 (V + 17027)
+ 0x1105, 0x1174, 0x11b3, 0,
+#undef V4466
+#define V4466 (V + 17031)
+ 0x1105, 0x1174, 0x11b4, 0,
+#undef V4467
+#define V4467 (V + 17035)
+ 0x1105, 0x1174, 0x11b5, 0,
+#undef V4468
+#define V4468 (V + 17039)
+ 0x1105, 0x1174, 0x11b6, 0,
+#undef V4469
+#define V4469 (V + 17043)
+ 0x1105, 0x1174, 0x11b7, 0,
+#undef V4470
+#define V4470 (V + 17047)
+ 0x1105, 0x1174, 0x11b8, 0,
+#undef V4471
+#define V4471 (V + 17051)
+ 0x1105, 0x1174, 0x11b9, 0,
+#undef V4472
+#define V4472 (V + 17055)
+ 0x1105, 0x1174, 0x11ba, 0,
+#undef V4473
+#define V4473 (V + 17059)
+ 0x1105, 0x1174, 0x11bb, 0,
+#undef V4474
+#define V4474 (V + 17063)
+ 0x1105, 0x1174, 0x11bc, 0,
+#undef V4475
+#define V4475 (V + 17067)
+ 0x1105, 0x1174, 0x11bd, 0,
+#undef V4476
+#define V4476 (V + 17071)
+ 0x1105, 0x1174, 0x11be, 0,
+#undef V4477
+#define V4477 (V + 17075)
+ 0x1105, 0x1174, 0x11bf, 0,
+#undef V4478
+#define V4478 (V + 17079)
+ 0x1105, 0x1174, 0x11c0, 0,
+#undef V4479
+#define V4479 (V + 17083)
+ 0x1105, 0x1174, 0x11c1, 0,
+#undef V4480
+#define V4480 (V + 17087)
+ 0x1105, 0x1174, 0x11c2, 0,
+#undef V4481
+#define V4481 (V + 17091)
+ 0x1105, 0x1175, 0,
+#undef V4482
+#define V4482 (V + 17094)
+ 0x1105, 0x1175, 0x11a8, 0,
+#undef V4483
+#define V4483 (V + 17098)
+ 0x1105, 0x1175, 0x11a9, 0,
+#undef V4484
+#define V4484 (V + 17102)
+ 0x1105, 0x1175, 0x11aa, 0,
+#undef V4485
+#define V4485 (V + 17106)
+ 0x1105, 0x1175, 0x11ab, 0,
+#undef V4486
+#define V4486 (V + 17110)
+ 0x1105, 0x1175, 0x11ac, 0,
+#undef V4487
+#define V4487 (V + 17114)
+ 0x1105, 0x1175, 0x11ad, 0,
+#undef V4488
+#define V4488 (V + 17118)
+ 0x1105, 0x1175, 0x11ae, 0,
+#undef V4489
+#define V4489 (V + 17122)
+ 0x1105, 0x1175, 0x11af, 0,
+#undef V4490
+#define V4490 (V + 17126)
+ 0x1105, 0x1175, 0x11b0, 0,
+#undef V4491
+#define V4491 (V + 17130)
+ 0x1105, 0x1175, 0x11b1, 0,
+#undef V4492
+#define V4492 (V + 17134)
+ 0x1105, 0x1175, 0x11b2, 0,
+#undef V4493
+#define V4493 (V + 17138)
+ 0x1105, 0x1175, 0x11b3, 0,
+#undef V4494
+#define V4494 (V + 17142)
+ 0x1105, 0x1175, 0x11b4, 0,
+#undef V4495
+#define V4495 (V + 17146)
+ 0x1105, 0x1175, 0x11b5, 0,
+#undef V4496
+#define V4496 (V + 17150)
+ 0x1105, 0x1175, 0x11b6, 0,
+#undef V4497
+#define V4497 (V + 17154)
+ 0x1105, 0x1175, 0x11b7, 0,
+#undef V4498
+#define V4498 (V + 17158)
+ 0x1105, 0x1175, 0x11b8, 0,
+#undef V4499
+#define V4499 (V + 17162)
+ 0x1105, 0x1175, 0x11b9, 0,
+#undef V4500
+#define V4500 (V + 17166)
+ 0x1105, 0x1175, 0x11ba, 0,
+#undef V4501
+#define V4501 (V + 17170)
+ 0x1105, 0x1175, 0x11bb, 0,
+#undef V4502
+#define V4502 (V + 17174)
+ 0x1105, 0x1175, 0x11bc, 0,
+#undef V4503
+#define V4503 (V + 17178)
+ 0x1105, 0x1175, 0x11bd, 0,
+#undef V4504
+#define V4504 (V + 17182)
+ 0x1105, 0x1175, 0x11be, 0,
+#undef V4505
+#define V4505 (V + 17186)
+ 0x1105, 0x1175, 0x11bf, 0,
+#undef V4506
+#define V4506 (V + 17190)
+ 0x1105, 0x1175, 0x11c0, 0,
+#undef V4507
+#define V4507 (V + 17194)
+ 0x1105, 0x1175, 0x11c1, 0,
+#undef V4508
+#define V4508 (V + 17198)
+ 0x1105, 0x1175, 0x11c2, 0,
+#undef V4509
+#define V4509 (V + 17202)
+ 0x1106, 0x1161, 0,
+#undef V4510
+#define V4510 (V + 17205)
+ 0x1106, 0x1161, 0x11a8, 0,
+#undef V4511
+#define V4511 (V + 17209)
+ 0x1106, 0x1161, 0x11a9, 0,
+#undef V4512
+#define V4512 (V + 17213)
+ 0x1106, 0x1161, 0x11aa, 0,
+#undef V4513
+#define V4513 (V + 17217)
+ 0x1106, 0x1161, 0x11ab, 0,
+#undef V4514
+#define V4514 (V + 17221)
+ 0x1106, 0x1161, 0x11ac, 0,
+#undef V4515
+#define V4515 (V + 17225)
+ 0x1106, 0x1161, 0x11ad, 0,
+#undef V4516
+#define V4516 (V + 17229)
+ 0x1106, 0x1161, 0x11ae, 0,
+#undef V4517
+#define V4517 (V + 17233)
+ 0x1106, 0x1161, 0x11af, 0,
+#undef V4518
+#define V4518 (V + 17237)
+ 0x1106, 0x1161, 0x11b0, 0,
+#undef V4519
+#define V4519 (V + 17241)
+ 0x1106, 0x1161, 0x11b1, 0,
+#undef V4520
+#define V4520 (V + 17245)
+ 0x1106, 0x1161, 0x11b2, 0,
+#undef V4521
+#define V4521 (V + 17249)
+ 0x1106, 0x1161, 0x11b3, 0,
+#undef V4522
+#define V4522 (V + 17253)
+ 0x1106, 0x1161, 0x11b4, 0,
+#undef V4523
+#define V4523 (V + 17257)
+ 0x1106, 0x1161, 0x11b5, 0,
+#undef V4524
+#define V4524 (V + 17261)
+ 0x1106, 0x1161, 0x11b6, 0,
+#undef V4525
+#define V4525 (V + 17265)
+ 0x1106, 0x1161, 0x11b7, 0,
+#undef V4526
+#define V4526 (V + 17269)
+ 0x1106, 0x1161, 0x11b8, 0,
+#undef V4527
+#define V4527 (V + 17273)
+ 0x1106, 0x1161, 0x11b9, 0,
+#undef V4528
+#define V4528 (V + 17277)
+ 0x1106, 0x1161, 0x11ba, 0,
+#undef V4529
+#define V4529 (V + 17281)
+ 0x1106, 0x1161, 0x11bb, 0,
+#undef V4530
+#define V4530 (V + 17285)
+ 0x1106, 0x1161, 0x11bc, 0,
+#undef V4531
+#define V4531 (V + 17289)
+ 0x1106, 0x1161, 0x11bd, 0,
+#undef V4532
+#define V4532 (V + 17293)
+ 0x1106, 0x1161, 0x11be, 0,
+#undef V4533
+#define V4533 (V + 17297)
+ 0x1106, 0x1161, 0x11bf, 0,
+#undef V4534
+#define V4534 (V + 17301)
+ 0x1106, 0x1161, 0x11c0, 0,
+#undef V4535
+#define V4535 (V + 17305)
+ 0x1106, 0x1161, 0x11c1, 0,
+#undef V4536
+#define V4536 (V + 17309)
+ 0x1106, 0x1161, 0x11c2, 0,
+#undef V4537
+#define V4537 (V + 17313)
+ 0x1106, 0x1162, 0,
+#undef V4538
+#define V4538 (V + 17316)
+ 0x1106, 0x1162, 0x11a8, 0,
+#undef V4539
+#define V4539 (V + 17320)
+ 0x1106, 0x1162, 0x11a9, 0,
+#undef V4540
+#define V4540 (V + 17324)
+ 0x1106, 0x1162, 0x11aa, 0,
+#undef V4541
+#define V4541 (V + 17328)
+ 0x1106, 0x1162, 0x11ab, 0,
+#undef V4542
+#define V4542 (V + 17332)
+ 0x1106, 0x1162, 0x11ac, 0,
+#undef V4543
+#define V4543 (V + 17336)
+ 0x1106, 0x1162, 0x11ad, 0,
+#undef V4544
+#define V4544 (V + 17340)
+ 0x1106, 0x1162, 0x11ae, 0,
+#undef V4545
+#define V4545 (V + 17344)
+ 0x1106, 0x1162, 0x11af, 0,
+#undef V4546
+#define V4546 (V + 17348)
+ 0x1106, 0x1162, 0x11b0, 0,
+#undef V4547
+#define V4547 (V + 17352)
+ 0x1106, 0x1162, 0x11b1, 0,
+#undef V4548
+#define V4548 (V + 17356)
+ 0x1106, 0x1162, 0x11b2, 0,
+#undef V4549
+#define V4549 (V + 17360)
+ 0x1106, 0x1162, 0x11b3, 0,
+#undef V4550
+#define V4550 (V + 17364)
+ 0x1106, 0x1162, 0x11b4, 0,
+#undef V4551
+#define V4551 (V + 17368)
+ 0x1106, 0x1162, 0x11b5, 0,
+#undef V4552
+#define V4552 (V + 17372)
+ 0x1106, 0x1162, 0x11b6, 0,
+#undef V4553
+#define V4553 (V + 17376)
+ 0x1106, 0x1162, 0x11b7, 0,
+#undef V4554
+#define V4554 (V + 17380)
+ 0x1106, 0x1162, 0x11b8, 0,
+#undef V4555
+#define V4555 (V + 17384)
+ 0x1106, 0x1162, 0x11b9, 0,
+#undef V4556
+#define V4556 (V + 17388)
+ 0x1106, 0x1162, 0x11ba, 0,
+#undef V4557
+#define V4557 (V + 17392)
+ 0x1106, 0x1162, 0x11bb, 0,
+#undef V4558
+#define V4558 (V + 17396)
+ 0x1106, 0x1162, 0x11bc, 0,
+#undef V4559
+#define V4559 (V + 17400)
+ 0x1106, 0x1162, 0x11bd, 0,
+#undef V4560
+#define V4560 (V + 17404)
+ 0x1106, 0x1162, 0x11be, 0,
+#undef V4561
+#define V4561 (V + 17408)
+ 0x1106, 0x1162, 0x11bf, 0,
+#undef V4562
+#define V4562 (V + 17412)
+ 0x1106, 0x1162, 0x11c0, 0,
+#undef V4563
+#define V4563 (V + 17416)
+ 0x1106, 0x1162, 0x11c1, 0,
+#undef V4564
+#define V4564 (V + 17420)
+ 0x1106, 0x1162, 0x11c2, 0,
+#undef V4565
+#define V4565 (V + 17424)
+ 0x1106, 0x1163, 0,
+#undef V4566
+#define V4566 (V + 17427)
+ 0x1106, 0x1163, 0x11a8, 0,
+#undef V4567
+#define V4567 (V + 17431)
+ 0x1106, 0x1163, 0x11a9, 0,
+#undef V4568
+#define V4568 (V + 17435)
+ 0x1106, 0x1163, 0x11aa, 0,
+#undef V4569
+#define V4569 (V + 17439)
+ 0x1106, 0x1163, 0x11ab, 0,
+#undef V4570
+#define V4570 (V + 17443)
+ 0x1106, 0x1163, 0x11ac, 0,
+#undef V4571
+#define V4571 (V + 17447)
+ 0x1106, 0x1163, 0x11ad, 0,
+#undef V4572
+#define V4572 (V + 17451)
+ 0x1106, 0x1163, 0x11ae, 0,
+#undef V4573
+#define V4573 (V + 17455)
+ 0x1106, 0x1163, 0x11af, 0,
+#undef V4574
+#define V4574 (V + 17459)
+ 0x1106, 0x1163, 0x11b0, 0,
+#undef V4575
+#define V4575 (V + 17463)
+ 0x1106, 0x1163, 0x11b1, 0,
+#undef V4576
+#define V4576 (V + 17467)
+ 0x1106, 0x1163, 0x11b2, 0,
+#undef V4577
+#define V4577 (V + 17471)
+ 0x1106, 0x1163, 0x11b3, 0,
+#undef V4578
+#define V4578 (V + 17475)
+ 0x1106, 0x1163, 0x11b4, 0,
+#undef V4579
+#define V4579 (V + 17479)
+ 0x1106, 0x1163, 0x11b5, 0,
+#undef V4580
+#define V4580 (V + 17483)
+ 0x1106, 0x1163, 0x11b6, 0,
+#undef V4581
+#define V4581 (V + 17487)
+ 0x1106, 0x1163, 0x11b7, 0,
+#undef V4582
+#define V4582 (V + 17491)
+ 0x1106, 0x1163, 0x11b8, 0,
+#undef V4583
+#define V4583 (V + 17495)
+ 0x1106, 0x1163, 0x11b9, 0,
+#undef V4584
+#define V4584 (V + 17499)
+ 0x1106, 0x1163, 0x11ba, 0,
+#undef V4585
+#define V4585 (V + 17503)
+ 0x1106, 0x1163, 0x11bb, 0,
+#undef V4586
+#define V4586 (V + 17507)
+ 0x1106, 0x1163, 0x11bc, 0,
+#undef V4587
+#define V4587 (V + 17511)
+ 0x1106, 0x1163, 0x11bd, 0,
+#undef V4588
+#define V4588 (V + 17515)
+ 0x1106, 0x1163, 0x11be, 0,
+#undef V4589
+#define V4589 (V + 17519)
+ 0x1106, 0x1163, 0x11bf, 0,
+#undef V4590
+#define V4590 (V + 17523)
+ 0x1106, 0x1163, 0x11c0, 0,
+#undef V4591
+#define V4591 (V + 17527)
+ 0x1106, 0x1163, 0x11c1, 0,
+#undef V4592
+#define V4592 (V + 17531)
+ 0x1106, 0x1163, 0x11c2, 0,
+#undef V4593
+#define V4593 (V + 17535)
+ 0x1106, 0x1164, 0,
+#undef V4594
+#define V4594 (V + 17538)
+ 0x1106, 0x1164, 0x11a8, 0,
+#undef V4595
+#define V4595 (V + 17542)
+ 0x1106, 0x1164, 0x11a9, 0,
+#undef V4596
+#define V4596 (V + 17546)
+ 0x1106, 0x1164, 0x11aa, 0,
+#undef V4597
+#define V4597 (V + 17550)
+ 0x1106, 0x1164, 0x11ab, 0,
+#undef V4598
+#define V4598 (V + 17554)
+ 0x1106, 0x1164, 0x11ac, 0,
+#undef V4599
+#define V4599 (V + 17558)
+ 0x1106, 0x1164, 0x11ad, 0,
+#undef V4600
+#define V4600 (V + 17562)
+ 0x1106, 0x1164, 0x11ae, 0,
+#undef V4601
+#define V4601 (V + 17566)
+ 0x1106, 0x1164, 0x11af, 0,
+#undef V4602
+#define V4602 (V + 17570)
+ 0x1106, 0x1164, 0x11b0, 0,
+#undef V4603
+#define V4603 (V + 17574)
+ 0x1106, 0x1164, 0x11b1, 0,
+#undef V4604
+#define V4604 (V + 17578)
+ 0x1106, 0x1164, 0x11b2, 0,
+#undef V4605
+#define V4605 (V + 17582)
+ 0x1106, 0x1164, 0x11b3, 0,
+#undef V4606
+#define V4606 (V + 17586)
+ 0x1106, 0x1164, 0x11b4, 0,
+#undef V4607
+#define V4607 (V + 17590)
+ 0x1106, 0x1164, 0x11b5, 0,
+#undef V4608
+#define V4608 (V + 17594)
+ 0x1106, 0x1164, 0x11b6, 0,
+#undef V4609
+#define V4609 (V + 17598)
+ 0x1106, 0x1164, 0x11b7, 0,
+#undef V4610
+#define V4610 (V + 17602)
+ 0x1106, 0x1164, 0x11b8, 0,
+#undef V4611
+#define V4611 (V + 17606)
+ 0x1106, 0x1164, 0x11b9, 0,
+#undef V4612
+#define V4612 (V + 17610)
+ 0x1106, 0x1164, 0x11ba, 0,
+#undef V4613
+#define V4613 (V + 17614)
+ 0x1106, 0x1164, 0x11bb, 0,
+#undef V4614
+#define V4614 (V + 17618)
+ 0x1106, 0x1164, 0x11bc, 0,
+#undef V4615
+#define V4615 (V + 17622)
+ 0x1106, 0x1164, 0x11bd, 0,
+#undef V4616
+#define V4616 (V + 17626)
+ 0x1106, 0x1164, 0x11be, 0,
+#undef V4617
+#define V4617 (V + 17630)
+ 0x1106, 0x1164, 0x11bf, 0,
+#undef V4618
+#define V4618 (V + 17634)
+ 0x1106, 0x1164, 0x11c0, 0,
+#undef V4619
+#define V4619 (V + 17638)
+ 0x1106, 0x1164, 0x11c1, 0,
+#undef V4620
+#define V4620 (V + 17642)
+ 0x1106, 0x1164, 0x11c2, 0,
+#undef V4621
+#define V4621 (V + 17646)
+ 0x1106, 0x1165, 0,
+#undef V4622
+#define V4622 (V + 17649)
+ 0x1106, 0x1165, 0x11a8, 0,
+#undef V4623
+#define V4623 (V + 17653)
+ 0x1106, 0x1165, 0x11a9, 0,
+#undef V4624
+#define V4624 (V + 17657)
+ 0x1106, 0x1165, 0x11aa, 0,
+#undef V4625
+#define V4625 (V + 17661)
+ 0x1106, 0x1165, 0x11ab, 0,
+#undef V4626
+#define V4626 (V + 17665)
+ 0x1106, 0x1165, 0x11ac, 0,
+#undef V4627
+#define V4627 (V + 17669)
+ 0x1106, 0x1165, 0x11ad, 0,
+#undef V4628
+#define V4628 (V + 17673)
+ 0x1106, 0x1165, 0x11ae, 0,
+#undef V4629
+#define V4629 (V + 17677)
+ 0x1106, 0x1165, 0x11af, 0,
+#undef V4630
+#define V4630 (V + 17681)
+ 0x1106, 0x1165, 0x11b0, 0,
+#undef V4631
+#define V4631 (V + 17685)
+ 0x1106, 0x1165, 0x11b1, 0,
+#undef V4632
+#define V4632 (V + 17689)
+ 0x1106, 0x1165, 0x11b2, 0,
+#undef V4633
+#define V4633 (V + 17693)
+ 0x1106, 0x1165, 0x11b3, 0,
+#undef V4634
+#define V4634 (V + 17697)
+ 0x1106, 0x1165, 0x11b4, 0,
+#undef V4635
+#define V4635 (V + 17701)
+ 0x1106, 0x1165, 0x11b5, 0,
+#undef V4636
+#define V4636 (V + 17705)
+ 0x1106, 0x1165, 0x11b6, 0,
+#undef V4637
+#define V4637 (V + 17709)
+ 0x1106, 0x1165, 0x11b7, 0,
+#undef V4638
+#define V4638 (V + 17713)
+ 0x1106, 0x1165, 0x11b8, 0,
+#undef V4639
+#define V4639 (V + 17717)
+ 0x1106, 0x1165, 0x11b9, 0,
+#undef V4640
+#define V4640 (V + 17721)
+ 0x1106, 0x1165, 0x11ba, 0,
+#undef V4641
+#define V4641 (V + 17725)
+ 0x1106, 0x1165, 0x11bb, 0,
+#undef V4642
+#define V4642 (V + 17729)
+ 0x1106, 0x1165, 0x11bc, 0,
+#undef V4643
+#define V4643 (V + 17733)
+ 0x1106, 0x1165, 0x11bd, 0,
+#undef V4644
+#define V4644 (V + 17737)
+ 0x1106, 0x1165, 0x11be, 0,
+#undef V4645
+#define V4645 (V + 17741)
+ 0x1106, 0x1165, 0x11bf, 0,
+#undef V4646
+#define V4646 (V + 17745)
+ 0x1106, 0x1165, 0x11c0, 0,
+#undef V4647
+#define V4647 (V + 17749)
+ 0x1106, 0x1165, 0x11c1, 0,
+#undef V4648
+#define V4648 (V + 17753)
+ 0x1106, 0x1165, 0x11c2, 0,
+#undef V4649
+#define V4649 (V + 17757)
+ 0x1106, 0x1166, 0,
+#undef V4650
+#define V4650 (V + 17760)
+ 0x1106, 0x1166, 0x11a8, 0,
+#undef V4651
+#define V4651 (V + 17764)
+ 0x1106, 0x1166, 0x11a9, 0,
+#undef V4652
+#define V4652 (V + 17768)
+ 0x1106, 0x1166, 0x11aa, 0,
+#undef V4653
+#define V4653 (V + 17772)
+ 0x1106, 0x1166, 0x11ab, 0,
+#undef V4654
+#define V4654 (V + 17776)
+ 0x1106, 0x1166, 0x11ac, 0,
+#undef V4655
+#define V4655 (V + 17780)
+ 0x1106, 0x1166, 0x11ad, 0,
+#undef V4656
+#define V4656 (V + 17784)
+ 0x1106, 0x1166, 0x11ae, 0,
+#undef V4657
+#define V4657 (V + 17788)
+ 0x1106, 0x1166, 0x11af, 0,
+#undef V4658
+#define V4658 (V + 17792)
+ 0x1106, 0x1166, 0x11b0, 0,
+#undef V4659
+#define V4659 (V + 17796)
+ 0x1106, 0x1166, 0x11b1, 0,
+#undef V4660
+#define V4660 (V + 17800)
+ 0x1106, 0x1166, 0x11b2, 0,
+#undef V4661
+#define V4661 (V + 17804)
+ 0x1106, 0x1166, 0x11b3, 0,
+#undef V4662
+#define V4662 (V + 17808)
+ 0x1106, 0x1166, 0x11b4, 0,
+#undef V4663
+#define V4663 (V + 17812)
+ 0x1106, 0x1166, 0x11b5, 0,
+#undef V4664
+#define V4664 (V + 17816)
+ 0x1106, 0x1166, 0x11b6, 0,
+#undef V4665
+#define V4665 (V + 17820)
+ 0x1106, 0x1166, 0x11b7, 0,
+#undef V4666
+#define V4666 (V + 17824)
+ 0x1106, 0x1166, 0x11b8, 0,
+#undef V4667
+#define V4667 (V + 17828)
+ 0x1106, 0x1166, 0x11b9, 0,
+#undef V4668
+#define V4668 (V + 17832)
+ 0x1106, 0x1166, 0x11ba, 0,
+#undef V4669
+#define V4669 (V + 17836)
+ 0x1106, 0x1166, 0x11bb, 0,
+#undef V4670
+#define V4670 (V + 17840)
+ 0x1106, 0x1166, 0x11bc, 0,
+#undef V4671
+#define V4671 (V + 17844)
+ 0x1106, 0x1166, 0x11bd, 0,
+#undef V4672
+#define V4672 (V + 17848)
+ 0x1106, 0x1166, 0x11be, 0,
+#undef V4673
+#define V4673 (V + 17852)
+ 0x1106, 0x1166, 0x11bf, 0,
+#undef V4674
+#define V4674 (V + 17856)
+ 0x1106, 0x1166, 0x11c0, 0,
+#undef V4675
+#define V4675 (V + 17860)
+ 0x1106, 0x1166, 0x11c1, 0,
+#undef V4676
+#define V4676 (V + 17864)
+ 0x1106, 0x1166, 0x11c2, 0,
+#undef V4677
+#define V4677 (V + 17868)
+ 0x1106, 0x1167, 0,
+#undef V4678
+#define V4678 (V + 17871)
+ 0x1106, 0x1167, 0x11a8, 0,
+#undef V4679
+#define V4679 (V + 17875)
+ 0x1106, 0x1167, 0x11a9, 0,
+#undef V4680
+#define V4680 (V + 17879)
+ 0x1106, 0x1167, 0x11aa, 0,
+#undef V4681
+#define V4681 (V + 17883)
+ 0x1106, 0x1167, 0x11ab, 0,
+#undef V4682
+#define V4682 (V + 17887)
+ 0x1106, 0x1167, 0x11ac, 0,
+#undef V4683
+#define V4683 (V + 17891)
+ 0x1106, 0x1167, 0x11ad, 0,
+#undef V4684
+#define V4684 (V + 17895)
+ 0x1106, 0x1167, 0x11ae, 0,
+#undef V4685
+#define V4685 (V + 17899)
+ 0x1106, 0x1167, 0x11af, 0,
+#undef V4686
+#define V4686 (V + 17903)
+ 0x1106, 0x1167, 0x11b0, 0,
+#undef V4687
+#define V4687 (V + 17907)
+ 0x1106, 0x1167, 0x11b1, 0,
+#undef V4688
+#define V4688 (V + 17911)
+ 0x1106, 0x1167, 0x11b2, 0,
+#undef V4689
+#define V4689 (V + 17915)
+ 0x1106, 0x1167, 0x11b3, 0,
+#undef V4690
+#define V4690 (V + 17919)
+ 0x1106, 0x1167, 0x11b4, 0,
+#undef V4691
+#define V4691 (V + 17923)
+ 0x1106, 0x1167, 0x11b5, 0,
+#undef V4692
+#define V4692 (V + 17927)
+ 0x1106, 0x1167, 0x11b6, 0,
+#undef V4693
+#define V4693 (V + 17931)
+ 0x1106, 0x1167, 0x11b7, 0,
+#undef V4694
+#define V4694 (V + 17935)
+ 0x1106, 0x1167, 0x11b8, 0,
+#undef V4695
+#define V4695 (V + 17939)
+ 0x1106, 0x1167, 0x11b9, 0,
+#undef V4696
+#define V4696 (V + 17943)
+ 0x1106, 0x1167, 0x11ba, 0,
+#undef V4697
+#define V4697 (V + 17947)
+ 0x1106, 0x1167, 0x11bb, 0,
+#undef V4698
+#define V4698 (V + 17951)
+ 0x1106, 0x1167, 0x11bc, 0,
+#undef V4699
+#define V4699 (V + 17955)
+ 0x1106, 0x1167, 0x11bd, 0,
+#undef V4700
+#define V4700 (V + 17959)
+ 0x1106, 0x1167, 0x11be, 0,
+#undef V4701
+#define V4701 (V + 17963)
+ 0x1106, 0x1167, 0x11bf, 0,
+#undef V4702
+#define V4702 (V + 17967)
+ 0x1106, 0x1167, 0x11c0, 0,
+#undef V4703
+#define V4703 (V + 17971)
+ 0x1106, 0x1167, 0x11c1, 0,
+#undef V4704
+#define V4704 (V + 17975)
+ 0x1106, 0x1167, 0x11c2, 0,
+#undef V4705
+#define V4705 (V + 17979)
+ 0x1106, 0x1168, 0,
+#undef V4706
+#define V4706 (V + 17982)
+ 0x1106, 0x1168, 0x11a8, 0,
+#undef V4707
+#define V4707 (V + 17986)
+ 0x1106, 0x1168, 0x11a9, 0,
+#undef V4708
+#define V4708 (V + 17990)
+ 0x1106, 0x1168, 0x11aa, 0,
+#undef V4709
+#define V4709 (V + 17994)
+ 0x1106, 0x1168, 0x11ab, 0,
+#undef V4710
+#define V4710 (V + 17998)
+ 0x1106, 0x1168, 0x11ac, 0,
+#undef V4711
+#define V4711 (V + 18002)
+ 0x1106, 0x1168, 0x11ad, 0,
+#undef V4712
+#define V4712 (V + 18006)
+ 0x1106, 0x1168, 0x11ae, 0,
+#undef V4713
+#define V4713 (V + 18010)
+ 0x1106, 0x1168, 0x11af, 0,
+#undef V4714
+#define V4714 (V + 18014)
+ 0x1106, 0x1168, 0x11b0, 0,
+#undef V4715
+#define V4715 (V + 18018)
+ 0x1106, 0x1168, 0x11b1, 0,
+#undef V4716
+#define V4716 (V + 18022)
+ 0x1106, 0x1168, 0x11b2, 0,
+#undef V4717
+#define V4717 (V + 18026)
+ 0x1106, 0x1168, 0x11b3, 0,
+#undef V4718
+#define V4718 (V + 18030)
+ 0x1106, 0x1168, 0x11b4, 0,
+#undef V4719
+#define V4719 (V + 18034)
+ 0x1106, 0x1168, 0x11b5, 0,
+#undef V4720
+#define V4720 (V + 18038)
+ 0x1106, 0x1168, 0x11b6, 0,
+#undef V4721
+#define V4721 (V + 18042)
+ 0x1106, 0x1168, 0x11b7, 0,
+#undef V4722
+#define V4722 (V + 18046)
+ 0x1106, 0x1168, 0x11b8, 0,
+#undef V4723
+#define V4723 (V + 18050)
+ 0x1106, 0x1168, 0x11b9, 0,
+#undef V4724
+#define V4724 (V + 18054)
+ 0x1106, 0x1168, 0x11ba, 0,
+#undef V4725
+#define V4725 (V + 18058)
+ 0x1106, 0x1168, 0x11bb, 0,
+#undef V4726
+#define V4726 (V + 18062)
+ 0x1106, 0x1168, 0x11bc, 0,
+#undef V4727
+#define V4727 (V + 18066)
+ 0x1106, 0x1168, 0x11bd, 0,
+#undef V4728
+#define V4728 (V + 18070)
+ 0x1106, 0x1168, 0x11be, 0,
+#undef V4729
+#define V4729 (V + 18074)
+ 0x1106, 0x1168, 0x11bf, 0,
+#undef V4730
+#define V4730 (V + 18078)
+ 0x1106, 0x1168, 0x11c0, 0,
+#undef V4731
+#define V4731 (V + 18082)
+ 0x1106, 0x1168, 0x11c1, 0,
+#undef V4732
+#define V4732 (V + 18086)
+ 0x1106, 0x1168, 0x11c2, 0,
+#undef V4733
+#define V4733 (V + 18090)
+ 0x1106, 0x1169, 0,
+#undef V4734
+#define V4734 (V + 18093)
+ 0x1106, 0x1169, 0x11a8, 0,
+#undef V4735
+#define V4735 (V + 18097)
+ 0x1106, 0x1169, 0x11a9, 0,
+#undef V4736
+#define V4736 (V + 18101)
+ 0x1106, 0x1169, 0x11aa, 0,
+#undef V4737
+#define V4737 (V + 18105)
+ 0x1106, 0x1169, 0x11ab, 0,
+#undef V4738
+#define V4738 (V + 18109)
+ 0x1106, 0x1169, 0x11ac, 0,
+#undef V4739
+#define V4739 (V + 18113)
+ 0x1106, 0x1169, 0x11ad, 0,
+#undef V4740
+#define V4740 (V + 18117)
+ 0x1106, 0x1169, 0x11ae, 0,
+#undef V4741
+#define V4741 (V + 18121)
+ 0x1106, 0x1169, 0x11af, 0,
+#undef V4742
+#define V4742 (V + 18125)
+ 0x1106, 0x1169, 0x11b0, 0,
+#undef V4743
+#define V4743 (V + 18129)
+ 0x1106, 0x1169, 0x11b1, 0,
+#undef V4744
+#define V4744 (V + 18133)
+ 0x1106, 0x1169, 0x11b2, 0,
+#undef V4745
+#define V4745 (V + 18137)
+ 0x1106, 0x1169, 0x11b3, 0,
+#undef V4746
+#define V4746 (V + 18141)
+ 0x1106, 0x1169, 0x11b4, 0,
+#undef V4747
+#define V4747 (V + 18145)
+ 0x1106, 0x1169, 0x11b5, 0,
+#undef V4748
+#define V4748 (V + 18149)
+ 0x1106, 0x1169, 0x11b6, 0,
+#undef V4749
+#define V4749 (V + 18153)
+ 0x1106, 0x1169, 0x11b7, 0,
+#undef V4750
+#define V4750 (V + 18157)
+ 0x1106, 0x1169, 0x11b8, 0,
+#undef V4751
+#define V4751 (V + 18161)
+ 0x1106, 0x1169, 0x11b9, 0,
+#undef V4752
+#define V4752 (V + 18165)
+ 0x1106, 0x1169, 0x11ba, 0,
+#undef V4753
+#define V4753 (V + 18169)
+ 0x1106, 0x1169, 0x11bb, 0,
+#undef V4754
+#define V4754 (V + 18173)
+ 0x1106, 0x1169, 0x11bc, 0,
+#undef V4755
+#define V4755 (V + 18177)
+ 0x1106, 0x1169, 0x11bd, 0,
+#undef V4756
+#define V4756 (V + 18181)
+ 0x1106, 0x1169, 0x11be, 0,
+#undef V4757
+#define V4757 (V + 18185)
+ 0x1106, 0x1169, 0x11bf, 0,
+#undef V4758
+#define V4758 (V + 18189)
+ 0x1106, 0x1169, 0x11c0, 0,
+#undef V4759
+#define V4759 (V + 18193)
+ 0x1106, 0x1169, 0x11c1, 0,
+#undef V4760
+#define V4760 (V + 18197)
+ 0x1106, 0x1169, 0x11c2, 0,
+#undef V4761
+#define V4761 (V + 18201)
+ 0x1106, 0x116a, 0,
+#undef V4762
+#define V4762 (V + 18204)
+ 0x1106, 0x116a, 0x11a8, 0,
+#undef V4763
+#define V4763 (V + 18208)
+ 0x1106, 0x116a, 0x11a9, 0,
+#undef V4764
+#define V4764 (V + 18212)
+ 0x1106, 0x116a, 0x11aa, 0,
+#undef V4765
+#define V4765 (V + 18216)
+ 0x1106, 0x116a, 0x11ab, 0,
+#undef V4766
+#define V4766 (V + 18220)
+ 0x1106, 0x116a, 0x11ac, 0,
+#undef V4767
+#define V4767 (V + 18224)
+ 0x1106, 0x116a, 0x11ad, 0,
+#undef V4768
+#define V4768 (V + 18228)
+ 0x1106, 0x116a, 0x11ae, 0,
+#undef V4769
+#define V4769 (V + 18232)
+ 0x1106, 0x116a, 0x11af, 0,
+#undef V4770
+#define V4770 (V + 18236)
+ 0x1106, 0x116a, 0x11b0, 0,
+#undef V4771
+#define V4771 (V + 18240)
+ 0x1106, 0x116a, 0x11b1, 0,
+#undef V4772
+#define V4772 (V + 18244)
+ 0x1106, 0x116a, 0x11b2, 0,
+#undef V4773
+#define V4773 (V + 18248)
+ 0x1106, 0x116a, 0x11b3, 0,
+#undef V4774
+#define V4774 (V + 18252)
+ 0x1106, 0x116a, 0x11b4, 0,
+#undef V4775
+#define V4775 (V + 18256)
+ 0x1106, 0x116a, 0x11b5, 0,
+#undef V4776
+#define V4776 (V + 18260)
+ 0x1106, 0x116a, 0x11b6, 0,
+#undef V4777
+#define V4777 (V + 18264)
+ 0x1106, 0x116a, 0x11b7, 0,
+#undef V4778
+#define V4778 (V + 18268)
+ 0x1106, 0x116a, 0x11b8, 0,
+#undef V4779
+#define V4779 (V + 18272)
+ 0x1106, 0x116a, 0x11b9, 0,
+#undef V4780
+#define V4780 (V + 18276)
+ 0x1106, 0x116a, 0x11ba, 0,
+#undef V4781
+#define V4781 (V + 18280)
+ 0x1106, 0x116a, 0x11bb, 0,
+#undef V4782
+#define V4782 (V + 18284)
+ 0x1106, 0x116a, 0x11bc, 0,
+#undef V4783
+#define V4783 (V + 18288)
+ 0x1106, 0x116a, 0x11bd, 0,
+#undef V4784
+#define V4784 (V + 18292)
+ 0x1106, 0x116a, 0x11be, 0,
+#undef V4785
+#define V4785 (V + 18296)
+ 0x1106, 0x116a, 0x11bf, 0,
+#undef V4786
+#define V4786 (V + 18300)
+ 0x1106, 0x116a, 0x11c0, 0,
+#undef V4787
+#define V4787 (V + 18304)
+ 0x1106, 0x116a, 0x11c1, 0,
+#undef V4788
+#define V4788 (V + 18308)
+ 0x1106, 0x116a, 0x11c2, 0,
+#undef V4789
+#define V4789 (V + 18312)
+ 0x1106, 0x116b, 0,
+#undef V4790
+#define V4790 (V + 18315)
+ 0x1106, 0x116b, 0x11a8, 0,
+#undef V4791
+#define V4791 (V + 18319)
+ 0x1106, 0x116b, 0x11a9, 0,
+#undef V4792
+#define V4792 (V + 18323)
+ 0x1106, 0x116b, 0x11aa, 0,
+#undef V4793
+#define V4793 (V + 18327)
+ 0x1106, 0x116b, 0x11ab, 0,
+#undef V4794
+#define V4794 (V + 18331)
+ 0x1106, 0x116b, 0x11ac, 0,
+#undef V4795
+#define V4795 (V + 18335)
+ 0x1106, 0x116b, 0x11ad, 0,
+#undef V4796
+#define V4796 (V + 18339)
+ 0x1106, 0x116b, 0x11ae, 0,
+#undef V4797
+#define V4797 (V + 18343)
+ 0x1106, 0x116b, 0x11af, 0,
+#undef V4798
+#define V4798 (V + 18347)
+ 0x1106, 0x116b, 0x11b0, 0,
+#undef V4799
+#define V4799 (V + 18351)
+ 0x1106, 0x116b, 0x11b1, 0,
+#undef V4800
+#define V4800 (V + 18355)
+ 0x1106, 0x116b, 0x11b2, 0,
+#undef V4801
+#define V4801 (V + 18359)
+ 0x1106, 0x116b, 0x11b3, 0,
+#undef V4802
+#define V4802 (V + 18363)
+ 0x1106, 0x116b, 0x11b4, 0,
+#undef V4803
+#define V4803 (V + 18367)
+ 0x1106, 0x116b, 0x11b5, 0,
+#undef V4804
+#define V4804 (V + 18371)
+ 0x1106, 0x116b, 0x11b6, 0,
+#undef V4805
+#define V4805 (V + 18375)
+ 0x1106, 0x116b, 0x11b7, 0,
+#undef V4806
+#define V4806 (V + 18379)
+ 0x1106, 0x116b, 0x11b8, 0,
+#undef V4807
+#define V4807 (V + 18383)
+ 0x1106, 0x116b, 0x11b9, 0,
+#undef V4808
+#define V4808 (V + 18387)
+ 0x1106, 0x116b, 0x11ba, 0,
+#undef V4809
+#define V4809 (V + 18391)
+ 0x1106, 0x116b, 0x11bb, 0,
+#undef V4810
+#define V4810 (V + 18395)
+ 0x1106, 0x116b, 0x11bc, 0,
+#undef V4811
+#define V4811 (V + 18399)
+ 0x1106, 0x116b, 0x11bd, 0,
+#undef V4812
+#define V4812 (V + 18403)
+ 0x1106, 0x116b, 0x11be, 0,
+#undef V4813
+#define V4813 (V + 18407)
+ 0x1106, 0x116b, 0x11bf, 0,
+#undef V4814
+#define V4814 (V + 18411)
+ 0x1106, 0x116b, 0x11c0, 0,
+#undef V4815
+#define V4815 (V + 18415)
+ 0x1106, 0x116b, 0x11c1, 0,
+#undef V4816
+#define V4816 (V + 18419)
+ 0x1106, 0x116b, 0x11c2, 0,
+#undef V4817
+#define V4817 (V + 18423)
+ 0x1106, 0x116c, 0,
+#undef V4818
+#define V4818 (V + 18426)
+ 0x1106, 0x116c, 0x11a8, 0,
+#undef V4819
+#define V4819 (V + 18430)
+ 0x1106, 0x116c, 0x11a9, 0,
+#undef V4820
+#define V4820 (V + 18434)
+ 0x1106, 0x116c, 0x11aa, 0,
+#undef V4821
+#define V4821 (V + 18438)
+ 0x1106, 0x116c, 0x11ab, 0,
+#undef V4822
+#define V4822 (V + 18442)
+ 0x1106, 0x116c, 0x11ac, 0,
+#undef V4823
+#define V4823 (V + 18446)
+ 0x1106, 0x116c, 0x11ad, 0,
+#undef V4824
+#define V4824 (V + 18450)
+ 0x1106, 0x116c, 0x11ae, 0,
+#undef V4825
+#define V4825 (V + 18454)
+ 0x1106, 0x116c, 0x11af, 0,
+#undef V4826
+#define V4826 (V + 18458)
+ 0x1106, 0x116c, 0x11b0, 0,
+#undef V4827
+#define V4827 (V + 18462)
+ 0x1106, 0x116c, 0x11b1, 0,
+#undef V4828
+#define V4828 (V + 18466)
+ 0x1106, 0x116c, 0x11b2, 0,
+#undef V4829
+#define V4829 (V + 18470)
+ 0x1106, 0x116c, 0x11b3, 0,
+#undef V4830
+#define V4830 (V + 18474)
+ 0x1106, 0x116c, 0x11b4, 0,
+#undef V4831
+#define V4831 (V + 18478)
+ 0x1106, 0x116c, 0x11b5, 0,
+#undef V4832
+#define V4832 (V + 18482)
+ 0x1106, 0x116c, 0x11b6, 0,
+#undef V4833
+#define V4833 (V + 18486)
+ 0x1106, 0x116c, 0x11b7, 0,
+#undef V4834
+#define V4834 (V + 18490)
+ 0x1106, 0x116c, 0x11b8, 0,
+#undef V4835
+#define V4835 (V + 18494)
+ 0x1106, 0x116c, 0x11b9, 0,
+#undef V4836
+#define V4836 (V + 18498)
+ 0x1106, 0x116c, 0x11ba, 0,
+#undef V4837
+#define V4837 (V + 18502)
+ 0x1106, 0x116c, 0x11bb, 0,
+#undef V4838
+#define V4838 (V + 18506)
+ 0x1106, 0x116c, 0x11bc, 0,
+#undef V4839
+#define V4839 (V + 18510)
+ 0x1106, 0x116c, 0x11bd, 0,
+#undef V4840
+#define V4840 (V + 18514)
+ 0x1106, 0x116c, 0x11be, 0,
+#undef V4841
+#define V4841 (V + 18518)
+ 0x1106, 0x116c, 0x11bf, 0,
+#undef V4842
+#define V4842 (V + 18522)
+ 0x1106, 0x116c, 0x11c0, 0,
+#undef V4843
+#define V4843 (V + 18526)
+ 0x1106, 0x116c, 0x11c1, 0,
+#undef V4844
+#define V4844 (V + 18530)
+ 0x1106, 0x116c, 0x11c2, 0,
+#undef V4845
+#define V4845 (V + 18534)
+ 0x1106, 0x116d, 0,
+#undef V4846
+#define V4846 (V + 18537)
+ 0x1106, 0x116d, 0x11a8, 0,
+#undef V4847
+#define V4847 (V + 18541)
+ 0x1106, 0x116d, 0x11a9, 0,
+#undef V4848
+#define V4848 (V + 18545)
+ 0x1106, 0x116d, 0x11aa, 0,
+#undef V4849
+#define V4849 (V + 18549)
+ 0x1106, 0x116d, 0x11ab, 0,
+#undef V4850
+#define V4850 (V + 18553)
+ 0x1106, 0x116d, 0x11ac, 0,
+#undef V4851
+#define V4851 (V + 18557)
+ 0x1106, 0x116d, 0x11ad, 0,
+#undef V4852
+#define V4852 (V + 18561)
+ 0x1106, 0x116d, 0x11ae, 0,
+#undef V4853
+#define V4853 (V + 18565)
+ 0x1106, 0x116d, 0x11af, 0,
+#undef V4854
+#define V4854 (V + 18569)
+ 0x1106, 0x116d, 0x11b0, 0,
+#undef V4855
+#define V4855 (V + 18573)
+ 0x1106, 0x116d, 0x11b1, 0,
+#undef V4856
+#define V4856 (V + 18577)
+ 0x1106, 0x116d, 0x11b2, 0,
+#undef V4857
+#define V4857 (V + 18581)
+ 0x1106, 0x116d, 0x11b3, 0,
+#undef V4858
+#define V4858 (V + 18585)
+ 0x1106, 0x116d, 0x11b4, 0,
+#undef V4859
+#define V4859 (V + 18589)
+ 0x1106, 0x116d, 0x11b5, 0,
+#undef V4860
+#define V4860 (V + 18593)
+ 0x1106, 0x116d, 0x11b6, 0,
+#undef V4861
+#define V4861 (V + 18597)
+ 0x1106, 0x116d, 0x11b7, 0,
+#undef V4862
+#define V4862 (V + 18601)
+ 0x1106, 0x116d, 0x11b8, 0,
+#undef V4863
+#define V4863 (V + 18605)
+ 0x1106, 0x116d, 0x11b9, 0,
+#undef V4864
+#define V4864 (V + 18609)
+ 0x1106, 0x116d, 0x11ba, 0,
+#undef V4865
+#define V4865 (V + 18613)
+ 0x1106, 0x116d, 0x11bb, 0,
+#undef V4866
+#define V4866 (V + 18617)
+ 0x1106, 0x116d, 0x11bc, 0,
+#undef V4867
+#define V4867 (V + 18621)
+ 0x1106, 0x116d, 0x11bd, 0,
+#undef V4868
+#define V4868 (V + 18625)
+ 0x1106, 0x116d, 0x11be, 0,
+#undef V4869
+#define V4869 (V + 18629)
+ 0x1106, 0x116d, 0x11bf, 0,
+#undef V4870
+#define V4870 (V + 18633)
+ 0x1106, 0x116d, 0x11c0, 0,
+#undef V4871
+#define V4871 (V + 18637)
+ 0x1106, 0x116d, 0x11c1, 0,
+#undef V4872
+#define V4872 (V + 18641)
+ 0x1106, 0x116d, 0x11c2, 0,
+#undef V4873
+#define V4873 (V + 18645)
+ 0x1106, 0x116e, 0,
+#undef V4874
+#define V4874 (V + 18648)
+ 0x1106, 0x116e, 0x11a8, 0,
+#undef V4875
+#define V4875 (V + 18652)
+ 0x1106, 0x116e, 0x11a9, 0,
+#undef V4876
+#define V4876 (V + 18656)
+ 0x1106, 0x116e, 0x11aa, 0,
+#undef V4877
+#define V4877 (V + 18660)
+ 0x1106, 0x116e, 0x11ab, 0,
+#undef V4878
+#define V4878 (V + 18664)
+ 0x1106, 0x116e, 0x11ac, 0,
+#undef V4879
+#define V4879 (V + 18668)
+ 0x1106, 0x116e, 0x11ad, 0,
+#undef V4880
+#define V4880 (V + 18672)
+ 0x1106, 0x116e, 0x11ae, 0,
+#undef V4881
+#define V4881 (V + 18676)
+ 0x1106, 0x116e, 0x11af, 0,
+#undef V4882
+#define V4882 (V + 18680)
+ 0x1106, 0x116e, 0x11b0, 0,
+#undef V4883
+#define V4883 (V + 18684)
+ 0x1106, 0x116e, 0x11b1, 0,
+#undef V4884
+#define V4884 (V + 18688)
+ 0x1106, 0x116e, 0x11b2, 0,
+#undef V4885
+#define V4885 (V + 18692)
+ 0x1106, 0x116e, 0x11b3, 0,
+#undef V4886
+#define V4886 (V + 18696)
+ 0x1106, 0x116e, 0x11b4, 0,
+#undef V4887
+#define V4887 (V + 18700)
+ 0x1106, 0x116e, 0x11b5, 0,
+#undef V4888
+#define V4888 (V + 18704)
+ 0x1106, 0x116e, 0x11b6, 0,
+#undef V4889
+#define V4889 (V + 18708)
+ 0x1106, 0x116e, 0x11b7, 0,
+#undef V4890
+#define V4890 (V + 18712)
+ 0x1106, 0x116e, 0x11b8, 0,
+#undef V4891
+#define V4891 (V + 18716)
+ 0x1106, 0x116e, 0x11b9, 0,
+#undef V4892
+#define V4892 (V + 18720)
+ 0x1106, 0x116e, 0x11ba, 0,
+#undef V4893
+#define V4893 (V + 18724)
+ 0x1106, 0x116e, 0x11bb, 0,
+#undef V4894
+#define V4894 (V + 18728)
+ 0x1106, 0x116e, 0x11bc, 0,
+#undef V4895
+#define V4895 (V + 18732)
+ 0x1106, 0x116e, 0x11bd, 0,
+#undef V4896
+#define V4896 (V + 18736)
+ 0x1106, 0x116e, 0x11be, 0,
+#undef V4897
+#define V4897 (V + 18740)
+ 0x1106, 0x116e, 0x11bf, 0,
+#undef V4898
+#define V4898 (V + 18744)
+ 0x1106, 0x116e, 0x11c0, 0,
+#undef V4899
+#define V4899 (V + 18748)
+ 0x1106, 0x116e, 0x11c1, 0,
+#undef V4900
+#define V4900 (V + 18752)
+ 0x1106, 0x116e, 0x11c2, 0,
+#undef V4901
+#define V4901 (V + 18756)
+ 0x1106, 0x116f, 0,
+#undef V4902
+#define V4902 (V + 18759)
+ 0x1106, 0x116f, 0x11a8, 0,
+#undef V4903
+#define V4903 (V + 18763)
+ 0x1106, 0x116f, 0x11a9, 0,
+#undef V4904
+#define V4904 (V + 18767)
+ 0x1106, 0x116f, 0x11aa, 0,
+#undef V4905
+#define V4905 (V + 18771)
+ 0x1106, 0x116f, 0x11ab, 0,
+#undef V4906
+#define V4906 (V + 18775)
+ 0x1106, 0x116f, 0x11ac, 0,
+#undef V4907
+#define V4907 (V + 18779)
+ 0x1106, 0x116f, 0x11ad, 0,
+#undef V4908
+#define V4908 (V + 18783)
+ 0x1106, 0x116f, 0x11ae, 0,
+#undef V4909
+#define V4909 (V + 18787)
+ 0x1106, 0x116f, 0x11af, 0,
+#undef V4910
+#define V4910 (V + 18791)
+ 0x1106, 0x116f, 0x11b0, 0,
+#undef V4911
+#define V4911 (V + 18795)
+ 0x1106, 0x116f, 0x11b1, 0,
+#undef V4912
+#define V4912 (V + 18799)
+ 0x1106, 0x116f, 0x11b2, 0,
+#undef V4913
+#define V4913 (V + 18803)
+ 0x1106, 0x116f, 0x11b3, 0,
+#undef V4914
+#define V4914 (V + 18807)
+ 0x1106, 0x116f, 0x11b4, 0,
+#undef V4915
+#define V4915 (V + 18811)
+ 0x1106, 0x116f, 0x11b5, 0,
+#undef V4916
+#define V4916 (V + 18815)
+ 0x1106, 0x116f, 0x11b6, 0,
+#undef V4917
+#define V4917 (V + 18819)
+ 0x1106, 0x116f, 0x11b7, 0,
+#undef V4918
+#define V4918 (V + 18823)
+ 0x1106, 0x116f, 0x11b8, 0,
+#undef V4919
+#define V4919 (V + 18827)
+ 0x1106, 0x116f, 0x11b9, 0,
+#undef V4920
+#define V4920 (V + 18831)
+ 0x1106, 0x116f, 0x11ba, 0,
+#undef V4921
+#define V4921 (V + 18835)
+ 0x1106, 0x116f, 0x11bb, 0,
+#undef V4922
+#define V4922 (V + 18839)
+ 0x1106, 0x116f, 0x11bc, 0,
+#undef V4923
+#define V4923 (V + 18843)
+ 0x1106, 0x116f, 0x11bd, 0,
+#undef V4924
+#define V4924 (V + 18847)
+ 0x1106, 0x116f, 0x11be, 0,
+#undef V4925
+#define V4925 (V + 18851)
+ 0x1106, 0x116f, 0x11bf, 0,
+#undef V4926
+#define V4926 (V + 18855)
+ 0x1106, 0x116f, 0x11c0, 0,
+#undef V4927
+#define V4927 (V + 18859)
+ 0x1106, 0x116f, 0x11c1, 0,
+#undef V4928
+#define V4928 (V + 18863)
+ 0x1106, 0x116f, 0x11c2, 0,
+#undef V4929
+#define V4929 (V + 18867)
+ 0x1106, 0x1170, 0,
+#undef V4930
+#define V4930 (V + 18870)
+ 0x1106, 0x1170, 0x11a8, 0,
+#undef V4931
+#define V4931 (V + 18874)
+ 0x1106, 0x1170, 0x11a9, 0,
+#undef V4932
+#define V4932 (V + 18878)
+ 0x1106, 0x1170, 0x11aa, 0,
+#undef V4933
+#define V4933 (V + 18882)
+ 0x1106, 0x1170, 0x11ab, 0,
+#undef V4934
+#define V4934 (V + 18886)
+ 0x1106, 0x1170, 0x11ac, 0,
+#undef V4935
+#define V4935 (V + 18890)
+ 0x1106, 0x1170, 0x11ad, 0,
+#undef V4936
+#define V4936 (V + 18894)
+ 0x1106, 0x1170, 0x11ae, 0,
+#undef V4937
+#define V4937 (V + 18898)
+ 0x1106, 0x1170, 0x11af, 0,
+#undef V4938
+#define V4938 (V + 18902)
+ 0x1106, 0x1170, 0x11b0, 0,
+#undef V4939
+#define V4939 (V + 18906)
+ 0x1106, 0x1170, 0x11b1, 0,
+#undef V4940
+#define V4940 (V + 18910)
+ 0x1106, 0x1170, 0x11b2, 0,
+#undef V4941
+#define V4941 (V + 18914)
+ 0x1106, 0x1170, 0x11b3, 0,
+#undef V4942
+#define V4942 (V + 18918)
+ 0x1106, 0x1170, 0x11b4, 0,
+#undef V4943
+#define V4943 (V + 18922)
+ 0x1106, 0x1170, 0x11b5, 0,
+#undef V4944
+#define V4944 (V + 18926)
+ 0x1106, 0x1170, 0x11b6, 0,
+#undef V4945
+#define V4945 (V + 18930)
+ 0x1106, 0x1170, 0x11b7, 0,
+#undef V4946
+#define V4946 (V + 18934)
+ 0x1106, 0x1170, 0x11b8, 0,
+#undef V4947
+#define V4947 (V + 18938)
+ 0x1106, 0x1170, 0x11b9, 0,
+#undef V4948
+#define V4948 (V + 18942)
+ 0x1106, 0x1170, 0x11ba, 0,
+#undef V4949
+#define V4949 (V + 18946)
+ 0x1106, 0x1170, 0x11bb, 0,
+#undef V4950
+#define V4950 (V + 18950)
+ 0x1106, 0x1170, 0x11bc, 0,
+#undef V4951
+#define V4951 (V + 18954)
+ 0x1106, 0x1170, 0x11bd, 0,
+#undef V4952
+#define V4952 (V + 18958)
+ 0x1106, 0x1170, 0x11be, 0,
+#undef V4953
+#define V4953 (V + 18962)
+ 0x1106, 0x1170, 0x11bf, 0,
+#undef V4954
+#define V4954 (V + 18966)
+ 0x1106, 0x1170, 0x11c0, 0,
+#undef V4955
+#define V4955 (V + 18970)
+ 0x1106, 0x1170, 0x11c1, 0,
+#undef V4956
+#define V4956 (V + 18974)
+ 0x1106, 0x1170, 0x11c2, 0,
+#undef V4957
+#define V4957 (V + 18978)
+ 0x1106, 0x1171, 0,
+#undef V4958
+#define V4958 (V + 18981)
+ 0x1106, 0x1171, 0x11a8, 0,
+#undef V4959
+#define V4959 (V + 18985)
+ 0x1106, 0x1171, 0x11a9, 0,
+#undef V4960
+#define V4960 (V + 18989)
+ 0x1106, 0x1171, 0x11aa, 0,
+#undef V4961
+#define V4961 (V + 18993)
+ 0x1106, 0x1171, 0x11ab, 0,
+#undef V4962
+#define V4962 (V + 18997)
+ 0x1106, 0x1171, 0x11ac, 0,
+#undef V4963
+#define V4963 (V + 19001)
+ 0x1106, 0x1171, 0x11ad, 0,
+#undef V4964
+#define V4964 (V + 19005)
+ 0x1106, 0x1171, 0x11ae, 0,
+#undef V4965
+#define V4965 (V + 19009)
+ 0x1106, 0x1171, 0x11af, 0,
+#undef V4966
+#define V4966 (V + 19013)
+ 0x1106, 0x1171, 0x11b0, 0,
+#undef V4967
+#define V4967 (V + 19017)
+ 0x1106, 0x1171, 0x11b1, 0,
+#undef V4968
+#define V4968 (V + 19021)
+ 0x1106, 0x1171, 0x11b2, 0,
+#undef V4969
+#define V4969 (V + 19025)
+ 0x1106, 0x1171, 0x11b3, 0,
+#undef V4970
+#define V4970 (V + 19029)
+ 0x1106, 0x1171, 0x11b4, 0,
+#undef V4971
+#define V4971 (V + 19033)
+ 0x1106, 0x1171, 0x11b5, 0,
+#undef V4972
+#define V4972 (V + 19037)
+ 0x1106, 0x1171, 0x11b6, 0,
+#undef V4973
+#define V4973 (V + 19041)
+ 0x1106, 0x1171, 0x11b7, 0,
+#undef V4974
+#define V4974 (V + 19045)
+ 0x1106, 0x1171, 0x11b8, 0,
+#undef V4975
+#define V4975 (V + 19049)
+ 0x1106, 0x1171, 0x11b9, 0,
+#undef V4976
+#define V4976 (V + 19053)
+ 0x1106, 0x1171, 0x11ba, 0,
+#undef V4977
+#define V4977 (V + 19057)
+ 0x1106, 0x1171, 0x11bb, 0,
+#undef V4978
+#define V4978 (V + 19061)
+ 0x1106, 0x1171, 0x11bc, 0,
+#undef V4979
+#define V4979 (V + 19065)
+ 0x1106, 0x1171, 0x11bd, 0,
+#undef V4980
+#define V4980 (V + 19069)
+ 0x1106, 0x1171, 0x11be, 0,
+#undef V4981
+#define V4981 (V + 19073)
+ 0x1106, 0x1171, 0x11bf, 0,
+#undef V4982
+#define V4982 (V + 19077)
+ 0x1106, 0x1171, 0x11c0, 0,
+#undef V4983
+#define V4983 (V + 19081)
+ 0x1106, 0x1171, 0x11c1, 0,
+#undef V4984
+#define V4984 (V + 19085)
+ 0x1106, 0x1171, 0x11c2, 0,
+#undef V4985
+#define V4985 (V + 19089)
+ 0x1106, 0x1172, 0,
+#undef V4986
+#define V4986 (V + 19092)
+ 0x1106, 0x1172, 0x11a8, 0,
+#undef V4987
+#define V4987 (V + 19096)
+ 0x1106, 0x1172, 0x11a9, 0,
+#undef V4988
+#define V4988 (V + 19100)
+ 0x1106, 0x1172, 0x11aa, 0,
+#undef V4989
+#define V4989 (V + 19104)
+ 0x1106, 0x1172, 0x11ab, 0,
+#undef V4990
+#define V4990 (V + 19108)
+ 0x1106, 0x1172, 0x11ac, 0,
+#undef V4991
+#define V4991 (V + 19112)
+ 0x1106, 0x1172, 0x11ad, 0,
+#undef V4992
+#define V4992 (V + 19116)
+ 0x1106, 0x1172, 0x11ae, 0,
+#undef V4993
+#define V4993 (V + 19120)
+ 0x1106, 0x1172, 0x11af, 0,
+#undef V4994
+#define V4994 (V + 19124)
+ 0x1106, 0x1172, 0x11b0, 0,
+#undef V4995
+#define V4995 (V + 19128)
+ 0x1106, 0x1172, 0x11b1, 0,
+#undef V4996
+#define V4996 (V + 19132)
+ 0x1106, 0x1172, 0x11b2, 0,
+#undef V4997
+#define V4997 (V + 19136)
+ 0x1106, 0x1172, 0x11b3, 0,
+#undef V4998
+#define V4998 (V + 19140)
+ 0x1106, 0x1172, 0x11b4, 0,
+#undef V4999
+#define V4999 (V + 19144)
+ 0x1106, 0x1172, 0x11b5, 0,
+#undef V5000
+#define V5000 (V + 19148)
+ 0x1106, 0x1172, 0x11b6, 0,
+#undef V5001
+#define V5001 (V + 19152)
+ 0x1106, 0x1172, 0x11b7, 0,
+#undef V5002
+#define V5002 (V + 19156)
+ 0x1106, 0x1172, 0x11b8, 0,
+#undef V5003
+#define V5003 (V + 19160)
+ 0x1106, 0x1172, 0x11b9, 0,
+#undef V5004
+#define V5004 (V + 19164)
+ 0x1106, 0x1172, 0x11ba, 0,
+#undef V5005
+#define V5005 (V + 19168)
+ 0x1106, 0x1172, 0x11bb, 0,
+#undef V5006
+#define V5006 (V + 19172)
+ 0x1106, 0x1172, 0x11bc, 0,
+#undef V5007
+#define V5007 (V + 19176)
+ 0x1106, 0x1172, 0x11bd, 0,
+#undef V5008
+#define V5008 (V + 19180)
+ 0x1106, 0x1172, 0x11be, 0,
+#undef V5009
+#define V5009 (V + 19184)
+ 0x1106, 0x1172, 0x11bf, 0,
+#undef V5010
+#define V5010 (V + 19188)
+ 0x1106, 0x1172, 0x11c0, 0,
+#undef V5011
+#define V5011 (V + 19192)
+ 0x1106, 0x1172, 0x11c1, 0,
+#undef V5012
+#define V5012 (V + 19196)
+ 0x1106, 0x1172, 0x11c2, 0,
+#undef V5013
+#define V5013 (V + 19200)
+ 0x1106, 0x1173, 0,
+#undef V5014
+#define V5014 (V + 19203)
+ 0x1106, 0x1173, 0x11a8, 0,
+#undef V5015
+#define V5015 (V + 19207)
+ 0x1106, 0x1173, 0x11a9, 0,
+#undef V5016
+#define V5016 (V + 19211)
+ 0x1106, 0x1173, 0x11aa, 0,
+#undef V5017
+#define V5017 (V + 19215)
+ 0x1106, 0x1173, 0x11ab, 0,
+#undef V5018
+#define V5018 (V + 19219)
+ 0x1106, 0x1173, 0x11ac, 0,
+#undef V5019
+#define V5019 (V + 19223)
+ 0x1106, 0x1173, 0x11ad, 0,
+#undef V5020
+#define V5020 (V + 19227)
+ 0x1106, 0x1173, 0x11ae, 0,
+#undef V5021
+#define V5021 (V + 19231)
+ 0x1106, 0x1173, 0x11af, 0,
+#undef V5022
+#define V5022 (V + 19235)
+ 0x1106, 0x1173, 0x11b0, 0,
+#undef V5023
+#define V5023 (V + 19239)
+ 0x1106, 0x1173, 0x11b1, 0,
+#undef V5024
+#define V5024 (V + 19243)
+ 0x1106, 0x1173, 0x11b2, 0,
+#undef V5025
+#define V5025 (V + 19247)
+ 0x1106, 0x1173, 0x11b3, 0,
+#undef V5026
+#define V5026 (V + 19251)
+ 0x1106, 0x1173, 0x11b4, 0,
+#undef V5027
+#define V5027 (V + 19255)
+ 0x1106, 0x1173, 0x11b5, 0,
+#undef V5028
+#define V5028 (V + 19259)
+ 0x1106, 0x1173, 0x11b6, 0,
+#undef V5029
+#define V5029 (V + 19263)
+ 0x1106, 0x1173, 0x11b7, 0,
+#undef V5030
+#define V5030 (V + 19267)
+ 0x1106, 0x1173, 0x11b8, 0,
+#undef V5031
+#define V5031 (V + 19271)
+ 0x1106, 0x1173, 0x11b9, 0,
+#undef V5032
+#define V5032 (V + 19275)
+ 0x1106, 0x1173, 0x11ba, 0,
+#undef V5033
+#define V5033 (V + 19279)
+ 0x1106, 0x1173, 0x11bb, 0,
+#undef V5034
+#define V5034 (V + 19283)
+ 0x1106, 0x1173, 0x11bc, 0,
+#undef V5035
+#define V5035 (V + 19287)
+ 0x1106, 0x1173, 0x11bd, 0,
+#undef V5036
+#define V5036 (V + 19291)
+ 0x1106, 0x1173, 0x11be, 0,
+#undef V5037
+#define V5037 (V + 19295)
+ 0x1106, 0x1173, 0x11bf, 0,
+#undef V5038
+#define V5038 (V + 19299)
+ 0x1106, 0x1173, 0x11c0, 0,
+#undef V5039
+#define V5039 (V + 19303)
+ 0x1106, 0x1173, 0x11c1, 0,
+#undef V5040
+#define V5040 (V + 19307)
+ 0x1106, 0x1173, 0x11c2, 0,
+#undef V5041
+#define V5041 (V + 19311)
+ 0x1106, 0x1174, 0,
+#undef V5042
+#define V5042 (V + 19314)
+ 0x1106, 0x1174, 0x11a8, 0,
+#undef V5043
+#define V5043 (V + 19318)
+ 0x1106, 0x1174, 0x11a9, 0,
+#undef V5044
+#define V5044 (V + 19322)
+ 0x1106, 0x1174, 0x11aa, 0,
+#undef V5045
+#define V5045 (V + 19326)
+ 0x1106, 0x1174, 0x11ab, 0,
+#undef V5046
+#define V5046 (V + 19330)
+ 0x1106, 0x1174, 0x11ac, 0,
+#undef V5047
+#define V5047 (V + 19334)
+ 0x1106, 0x1174, 0x11ad, 0,
+#undef V5048
+#define V5048 (V + 19338)
+ 0x1106, 0x1174, 0x11ae, 0,
+#undef V5049
+#define V5049 (V + 19342)
+ 0x1106, 0x1174, 0x11af, 0,
+#undef V5050
+#define V5050 (V + 19346)
+ 0x1106, 0x1174, 0x11b0, 0,
+#undef V5051
+#define V5051 (V + 19350)
+ 0x1106, 0x1174, 0x11b1, 0,
+#undef V5052
+#define V5052 (V + 19354)
+ 0x1106, 0x1174, 0x11b2, 0,
+#undef V5053
+#define V5053 (V + 19358)
+ 0x1106, 0x1174, 0x11b3, 0,
+#undef V5054
+#define V5054 (V + 19362)
+ 0x1106, 0x1174, 0x11b4, 0,
+#undef V5055
+#define V5055 (V + 19366)
+ 0x1106, 0x1174, 0x11b5, 0,
+#undef V5056
+#define V5056 (V + 19370)
+ 0x1106, 0x1174, 0x11b6, 0,
+#undef V5057
+#define V5057 (V + 19374)
+ 0x1106, 0x1174, 0x11b7, 0,
+#undef V5058
+#define V5058 (V + 19378)
+ 0x1106, 0x1174, 0x11b8, 0,
+#undef V5059
+#define V5059 (V + 19382)
+ 0x1106, 0x1174, 0x11b9, 0,
+#undef V5060
+#define V5060 (V + 19386)
+ 0x1106, 0x1174, 0x11ba, 0,
+#undef V5061
+#define V5061 (V + 19390)
+ 0x1106, 0x1174, 0x11bb, 0,
+#undef V5062
+#define V5062 (V + 19394)
+ 0x1106, 0x1174, 0x11bc, 0,
+#undef V5063
+#define V5063 (V + 19398)
+ 0x1106, 0x1174, 0x11bd, 0,
+#undef V5064
+#define V5064 (V + 19402)
+ 0x1106, 0x1174, 0x11be, 0,
+#undef V5065
+#define V5065 (V + 19406)
+ 0x1106, 0x1174, 0x11bf, 0,
+#undef V5066
+#define V5066 (V + 19410)
+ 0x1106, 0x1174, 0x11c0, 0,
+#undef V5067
+#define V5067 (V + 19414)
+ 0x1106, 0x1174, 0x11c1, 0,
+#undef V5068
+#define V5068 (V + 19418)
+ 0x1106, 0x1174, 0x11c2, 0,
+#undef V5069
+#define V5069 (V + 19422)
+ 0x1106, 0x1175, 0,
+#undef V5070
+#define V5070 (V + 19425)
+ 0x1106, 0x1175, 0x11a8, 0,
+#undef V5071
+#define V5071 (V + 19429)
+ 0x1106, 0x1175, 0x11a9, 0,
+#undef V5072
+#define V5072 (V + 19433)
+ 0x1106, 0x1175, 0x11aa, 0,
+#undef V5073
+#define V5073 (V + 19437)
+ 0x1106, 0x1175, 0x11ab, 0,
+#undef V5074
+#define V5074 (V + 19441)
+ 0x1106, 0x1175, 0x11ac, 0,
+#undef V5075
+#define V5075 (V + 19445)
+ 0x1106, 0x1175, 0x11ad, 0,
+#undef V5076
+#define V5076 (V + 19449)
+ 0x1106, 0x1175, 0x11ae, 0,
+#undef V5077
+#define V5077 (V + 19453)
+ 0x1106, 0x1175, 0x11af, 0,
+#undef V5078
+#define V5078 (V + 19457)
+ 0x1106, 0x1175, 0x11b0, 0,
+#undef V5079
+#define V5079 (V + 19461)
+ 0x1106, 0x1175, 0x11b1, 0,
+#undef V5080
+#define V5080 (V + 19465)
+ 0x1106, 0x1175, 0x11b2, 0,
+#undef V5081
+#define V5081 (V + 19469)
+ 0x1106, 0x1175, 0x11b3, 0,
+#undef V5082
+#define V5082 (V + 19473)
+ 0x1106, 0x1175, 0x11b4, 0,
+#undef V5083
+#define V5083 (V + 19477)
+ 0x1106, 0x1175, 0x11b5, 0,
+#undef V5084
+#define V5084 (V + 19481)
+ 0x1106, 0x1175, 0x11b6, 0,
+#undef V5085
+#define V5085 (V + 19485)
+ 0x1106, 0x1175, 0x11b7, 0,
+#undef V5086
+#define V5086 (V + 19489)
+ 0x1106, 0x1175, 0x11b8, 0,
+#undef V5087
+#define V5087 (V + 19493)
+ 0x1106, 0x1175, 0x11b9, 0,
+#undef V5088
+#define V5088 (V + 19497)
+ 0x1106, 0x1175, 0x11ba, 0,
+#undef V5089
+#define V5089 (V + 19501)
+ 0x1106, 0x1175, 0x11bb, 0,
+#undef V5090
+#define V5090 (V + 19505)
+ 0x1106, 0x1175, 0x11bc, 0,
+#undef V5091
+#define V5091 (V + 19509)
+ 0x1106, 0x1175, 0x11bd, 0,
+#undef V5092
+#define V5092 (V + 19513)
+ 0x1106, 0x1175, 0x11be, 0,
+#undef V5093
+#define V5093 (V + 19517)
+ 0x1106, 0x1175, 0x11bf, 0,
+#undef V5094
+#define V5094 (V + 19521)
+ 0x1106, 0x1175, 0x11c0, 0,
+#undef V5095
+#define V5095 (V + 19525)
+ 0x1106, 0x1175, 0x11c1, 0,
+#undef V5096
+#define V5096 (V + 19529)
+ 0x1106, 0x1175, 0x11c2, 0,
+#undef V5097
+#define V5097 (V + 19533)
+ 0x1107, 0x1161, 0,
+#undef V5098
+#define V5098 (V + 19536)
+ 0x1107, 0x1161, 0x11a8, 0,
+#undef V5099
+#define V5099 (V + 19540)
+ 0x1107, 0x1161, 0x11a9, 0,
+#undef V5100
+#define V5100 (V + 19544)
+ 0x1107, 0x1161, 0x11aa, 0,
+#undef V5101
+#define V5101 (V + 19548)
+ 0x1107, 0x1161, 0x11ab, 0,
+#undef V5102
+#define V5102 (V + 19552)
+ 0x1107, 0x1161, 0x11ac, 0,
+#undef V5103
+#define V5103 (V + 19556)
+ 0x1107, 0x1161, 0x11ad, 0,
+#undef V5104
+#define V5104 (V + 19560)
+ 0x1107, 0x1161, 0x11ae, 0,
+#undef V5105
+#define V5105 (V + 19564)
+ 0x1107, 0x1161, 0x11af, 0,
+#undef V5106
+#define V5106 (V + 19568)
+ 0x1107, 0x1161, 0x11b0, 0,
+#undef V5107
+#define V5107 (V + 19572)
+ 0x1107, 0x1161, 0x11b1, 0,
+#undef V5108
+#define V5108 (V + 19576)
+ 0x1107, 0x1161, 0x11b2, 0,
+#undef V5109
+#define V5109 (V + 19580)
+ 0x1107, 0x1161, 0x11b3, 0,
+#undef V5110
+#define V5110 (V + 19584)
+ 0x1107, 0x1161, 0x11b4, 0,
+#undef V5111
+#define V5111 (V + 19588)
+ 0x1107, 0x1161, 0x11b5, 0,
+#undef V5112
+#define V5112 (V + 19592)
+ 0x1107, 0x1161, 0x11b6, 0,
+#undef V5113
+#define V5113 (V + 19596)
+ 0x1107, 0x1161, 0x11b7, 0,
+#undef V5114
+#define V5114 (V + 19600)
+ 0x1107, 0x1161, 0x11b8, 0,
+#undef V5115
+#define V5115 (V + 19604)
+ 0x1107, 0x1161, 0x11b9, 0,
+#undef V5116
+#define V5116 (V + 19608)
+ 0x1107, 0x1161, 0x11ba, 0,
+#undef V5117
+#define V5117 (V + 19612)
+ 0x1107, 0x1161, 0x11bb, 0,
+#undef V5118
+#define V5118 (V + 19616)
+ 0x1107, 0x1161, 0x11bc, 0,
+#undef V5119
+#define V5119 (V + 19620)
+ 0x1107, 0x1161, 0x11bd, 0,
+#undef V5120
+#define V5120 (V + 19624)
+ 0x1107, 0x1161, 0x11be, 0,
+#undef V5121
+#define V5121 (V + 19628)
+ 0x1107, 0x1161, 0x11bf, 0,
+#undef V5122
+#define V5122 (V + 19632)
+ 0x1107, 0x1161, 0x11c0, 0,
+#undef V5123
+#define V5123 (V + 19636)
+ 0x1107, 0x1161, 0x11c1, 0,
+#undef V5124
+#define V5124 (V + 19640)
+ 0x1107, 0x1161, 0x11c2, 0,
+#undef V5125
+#define V5125 (V + 19644)
+ 0x1107, 0x1162, 0,
+#undef V5126
+#define V5126 (V + 19647)
+ 0x1107, 0x1162, 0x11a8, 0,
+#undef V5127
+#define V5127 (V + 19651)
+ 0x1107, 0x1162, 0x11a9, 0,
+#undef V5128
+#define V5128 (V + 19655)
+ 0x1107, 0x1162, 0x11aa, 0,
+#undef V5129
+#define V5129 (V + 19659)
+ 0x1107, 0x1162, 0x11ab, 0,
+#undef V5130
+#define V5130 (V + 19663)
+ 0x1107, 0x1162, 0x11ac, 0,
+#undef V5131
+#define V5131 (V + 19667)
+ 0x1107, 0x1162, 0x11ad, 0,
+#undef V5132
+#define V5132 (V + 19671)
+ 0x1107, 0x1162, 0x11ae, 0,
+#undef V5133
+#define V5133 (V + 19675)
+ 0x1107, 0x1162, 0x11af, 0,
+#undef V5134
+#define V5134 (V + 19679)
+ 0x1107, 0x1162, 0x11b0, 0,
+#undef V5135
+#define V5135 (V + 19683)
+ 0x1107, 0x1162, 0x11b1, 0,
+#undef V5136
+#define V5136 (V + 19687)
+ 0x1107, 0x1162, 0x11b2, 0,
+#undef V5137
+#define V5137 (V + 19691)
+ 0x1107, 0x1162, 0x11b3, 0,
+#undef V5138
+#define V5138 (V + 19695)
+ 0x1107, 0x1162, 0x11b4, 0,
+#undef V5139
+#define V5139 (V + 19699)
+ 0x1107, 0x1162, 0x11b5, 0,
+#undef V5140
+#define V5140 (V + 19703)
+ 0x1107, 0x1162, 0x11b6, 0,
+#undef V5141
+#define V5141 (V + 19707)
+ 0x1107, 0x1162, 0x11b7, 0,
+#undef V5142
+#define V5142 (V + 19711)
+ 0x1107, 0x1162, 0x11b8, 0,
+#undef V5143
+#define V5143 (V + 19715)
+ 0x1107, 0x1162, 0x11b9, 0,
+#undef V5144
+#define V5144 (V + 19719)
+ 0x1107, 0x1162, 0x11ba, 0,
+#undef V5145
+#define V5145 (V + 19723)
+ 0x1107, 0x1162, 0x11bb, 0,
+#undef V5146
+#define V5146 (V + 19727)
+ 0x1107, 0x1162, 0x11bc, 0,
+#undef V5147
+#define V5147 (V + 19731)
+ 0x1107, 0x1162, 0x11bd, 0,
+#undef V5148
+#define V5148 (V + 19735)
+ 0x1107, 0x1162, 0x11be, 0,
+#undef V5149
+#define V5149 (V + 19739)
+ 0x1107, 0x1162, 0x11bf, 0,
+#undef V5150
+#define V5150 (V + 19743)
+ 0x1107, 0x1162, 0x11c0, 0,
+#undef V5151
+#define V5151 (V + 19747)
+ 0x1107, 0x1162, 0x11c1, 0,
+#undef V5152
+#define V5152 (V + 19751)
+ 0x1107, 0x1162, 0x11c2, 0,
+#undef V5153
+#define V5153 (V + 19755)
+ 0x1107, 0x1163, 0,
+#undef V5154
+#define V5154 (V + 19758)
+ 0x1107, 0x1163, 0x11a8, 0,
+#undef V5155
+#define V5155 (V + 19762)
+ 0x1107, 0x1163, 0x11a9, 0,
+#undef V5156
+#define V5156 (V + 19766)
+ 0x1107, 0x1163, 0x11aa, 0,
+#undef V5157
+#define V5157 (V + 19770)
+ 0x1107, 0x1163, 0x11ab, 0,
+#undef V5158
+#define V5158 (V + 19774)
+ 0x1107, 0x1163, 0x11ac, 0,
+#undef V5159
+#define V5159 (V + 19778)
+ 0x1107, 0x1163, 0x11ad, 0,
+#undef V5160
+#define V5160 (V + 19782)
+ 0x1107, 0x1163, 0x11ae, 0,
+#undef V5161
+#define V5161 (V + 19786)
+ 0x1107, 0x1163, 0x11af, 0,
+#undef V5162
+#define V5162 (V + 19790)
+ 0x1107, 0x1163, 0x11b0, 0,
+#undef V5163
+#define V5163 (V + 19794)
+ 0x1107, 0x1163, 0x11b1, 0,
+#undef V5164
+#define V5164 (V + 19798)
+ 0x1107, 0x1163, 0x11b2, 0,
+#undef V5165
+#define V5165 (V + 19802)
+ 0x1107, 0x1163, 0x11b3, 0,
+#undef V5166
+#define V5166 (V + 19806)
+ 0x1107, 0x1163, 0x11b4, 0,
+#undef V5167
+#define V5167 (V + 19810)
+ 0x1107, 0x1163, 0x11b5, 0,
+#undef V5168
+#define V5168 (V + 19814)
+ 0x1107, 0x1163, 0x11b6, 0,
+#undef V5169
+#define V5169 (V + 19818)
+ 0x1107, 0x1163, 0x11b7, 0,
+#undef V5170
+#define V5170 (V + 19822)
+ 0x1107, 0x1163, 0x11b8, 0,
+#undef V5171
+#define V5171 (V + 19826)
+ 0x1107, 0x1163, 0x11b9, 0,
+#undef V5172
+#define V5172 (V + 19830)
+ 0x1107, 0x1163, 0x11ba, 0,
+#undef V5173
+#define V5173 (V + 19834)
+ 0x1107, 0x1163, 0x11bb, 0,
+#undef V5174
+#define V5174 (V + 19838)
+ 0x1107, 0x1163, 0x11bc, 0,
+#undef V5175
+#define V5175 (V + 19842)
+ 0x1107, 0x1163, 0x11bd, 0,
+#undef V5176
+#define V5176 (V + 19846)
+ 0x1107, 0x1163, 0x11be, 0,
+#undef V5177
+#define V5177 (V + 19850)
+ 0x1107, 0x1163, 0x11bf, 0,
+#undef V5178
+#define V5178 (V + 19854)
+ 0x1107, 0x1163, 0x11c0, 0,
+#undef V5179
+#define V5179 (V + 19858)
+ 0x1107, 0x1163, 0x11c1, 0,
+#undef V5180
+#define V5180 (V + 19862)
+ 0x1107, 0x1163, 0x11c2, 0,
+#undef V5181
+#define V5181 (V + 19866)
+ 0x1107, 0x1164, 0,
+#undef V5182
+#define V5182 (V + 19869)
+ 0x1107, 0x1164, 0x11a8, 0,
+#undef V5183
+#define V5183 (V + 19873)
+ 0x1107, 0x1164, 0x11a9, 0,
+#undef V5184
+#define V5184 (V + 19877)
+ 0x1107, 0x1164, 0x11aa, 0,
+#undef V5185
+#define V5185 (V + 19881)
+ 0x1107, 0x1164, 0x11ab, 0,
+#undef V5186
+#define V5186 (V + 19885)
+ 0x1107, 0x1164, 0x11ac, 0,
+#undef V5187
+#define V5187 (V + 19889)
+ 0x1107, 0x1164, 0x11ad, 0,
+#undef V5188
+#define V5188 (V + 19893)
+ 0x1107, 0x1164, 0x11ae, 0,
+#undef V5189
+#define V5189 (V + 19897)
+ 0x1107, 0x1164, 0x11af, 0,
+#undef V5190
+#define V5190 (V + 19901)
+ 0x1107, 0x1164, 0x11b0, 0,
+#undef V5191
+#define V5191 (V + 19905)
+ 0x1107, 0x1164, 0x11b1, 0,
+#undef V5192
+#define V5192 (V + 19909)
+ 0x1107, 0x1164, 0x11b2, 0,
+#undef V5193
+#define V5193 (V + 19913)
+ 0x1107, 0x1164, 0x11b3, 0,
+#undef V5194
+#define V5194 (V + 19917)
+ 0x1107, 0x1164, 0x11b4, 0,
+#undef V5195
+#define V5195 (V + 19921)
+ 0x1107, 0x1164, 0x11b5, 0,
+#undef V5196
+#define V5196 (V + 19925)
+ 0x1107, 0x1164, 0x11b6, 0,
+#undef V5197
+#define V5197 (V + 19929)
+ 0x1107, 0x1164, 0x11b7, 0,
+#undef V5198
+#define V5198 (V + 19933)
+ 0x1107, 0x1164, 0x11b8, 0,
+#undef V5199
+#define V5199 (V + 19937)
+ 0x1107, 0x1164, 0x11b9, 0,
+#undef V5200
+#define V5200 (V + 19941)
+ 0x1107, 0x1164, 0x11ba, 0,
+#undef V5201
+#define V5201 (V + 19945)
+ 0x1107, 0x1164, 0x11bb, 0,
+#undef V5202
+#define V5202 (V + 19949)
+ 0x1107, 0x1164, 0x11bc, 0,
+#undef V5203
+#define V5203 (V + 19953)
+ 0x1107, 0x1164, 0x11bd, 0,
+#undef V5204
+#define V5204 (V + 19957)
+ 0x1107, 0x1164, 0x11be, 0,
+#undef V5205
+#define V5205 (V + 19961)
+ 0x1107, 0x1164, 0x11bf, 0,
+#undef V5206
+#define V5206 (V + 19965)
+ 0x1107, 0x1164, 0x11c0, 0,
+#undef V5207
+#define V5207 (V + 19969)
+ 0x1107, 0x1164, 0x11c1, 0,
+#undef V5208
+#define V5208 (V + 19973)
+ 0x1107, 0x1164, 0x11c2, 0,
+#undef V5209
+#define V5209 (V + 19977)
+ 0x1107, 0x1165, 0,
+#undef V5210
+#define V5210 (V + 19980)
+ 0x1107, 0x1165, 0x11a8, 0,
+#undef V5211
+#define V5211 (V + 19984)
+ 0x1107, 0x1165, 0x11a9, 0,
+#undef V5212
+#define V5212 (V + 19988)
+ 0x1107, 0x1165, 0x11aa, 0,
+#undef V5213
+#define V5213 (V + 19992)
+ 0x1107, 0x1165, 0x11ab, 0,
+#undef V5214
+#define V5214 (V + 19996)
+ 0x1107, 0x1165, 0x11ac, 0,
+#undef V5215
+#define V5215 (V + 20000)
+ 0x1107, 0x1165, 0x11ad, 0,
+#undef V5216
+#define V5216 (V + 20004)
+ 0x1107, 0x1165, 0x11ae, 0,
+#undef V5217
+#define V5217 (V + 20008)
+ 0x1107, 0x1165, 0x11af, 0,
+#undef V5218
+#define V5218 (V + 20012)
+ 0x1107, 0x1165, 0x11b0, 0,
+#undef V5219
+#define V5219 (V + 20016)
+ 0x1107, 0x1165, 0x11b1, 0,
+#undef V5220
+#define V5220 (V + 20020)
+ 0x1107, 0x1165, 0x11b2, 0,
+#undef V5221
+#define V5221 (V + 20024)
+ 0x1107, 0x1165, 0x11b3, 0,
+#undef V5222
+#define V5222 (V + 20028)
+ 0x1107, 0x1165, 0x11b4, 0,
+#undef V5223
+#define V5223 (V + 20032)
+ 0x1107, 0x1165, 0x11b5, 0,
+#undef V5224
+#define V5224 (V + 20036)
+ 0x1107, 0x1165, 0x11b6, 0,
+#undef V5225
+#define V5225 (V + 20040)
+ 0x1107, 0x1165, 0x11b7, 0,
+#undef V5226
+#define V5226 (V + 20044)
+ 0x1107, 0x1165, 0x11b8, 0,
+#undef V5227
+#define V5227 (V + 20048)
+ 0x1107, 0x1165, 0x11b9, 0,
+#undef V5228
+#define V5228 (V + 20052)
+ 0x1107, 0x1165, 0x11ba, 0,
+#undef V5229
+#define V5229 (V + 20056)
+ 0x1107, 0x1165, 0x11bb, 0,
+#undef V5230
+#define V5230 (V + 20060)
+ 0x1107, 0x1165, 0x11bc, 0,
+#undef V5231
+#define V5231 (V + 20064)
+ 0x1107, 0x1165, 0x11bd, 0,
+#undef V5232
+#define V5232 (V + 20068)
+ 0x1107, 0x1165, 0x11be, 0,
+#undef V5233
+#define V5233 (V + 20072)
+ 0x1107, 0x1165, 0x11bf, 0,
+#undef V5234
+#define V5234 (V + 20076)
+ 0x1107, 0x1165, 0x11c0, 0,
+#undef V5235
+#define V5235 (V + 20080)
+ 0x1107, 0x1165, 0x11c1, 0,
+#undef V5236
+#define V5236 (V + 20084)
+ 0x1107, 0x1165, 0x11c2, 0,
+#undef V5237
+#define V5237 (V + 20088)
+ 0x1107, 0x1166, 0,
+#undef V5238
+#define V5238 (V + 20091)
+ 0x1107, 0x1166, 0x11a8, 0,
+#undef V5239
+#define V5239 (V + 20095)
+ 0x1107, 0x1166, 0x11a9, 0,
+#undef V5240
+#define V5240 (V + 20099)
+ 0x1107, 0x1166, 0x11aa, 0,
+#undef V5241
+#define V5241 (V + 20103)
+ 0x1107, 0x1166, 0x11ab, 0,
+#undef V5242
+#define V5242 (V + 20107)
+ 0x1107, 0x1166, 0x11ac, 0,
+#undef V5243
+#define V5243 (V + 20111)
+ 0x1107, 0x1166, 0x11ad, 0,
+#undef V5244
+#define V5244 (V + 20115)
+ 0x1107, 0x1166, 0x11ae, 0,
+#undef V5245
+#define V5245 (V + 20119)
+ 0x1107, 0x1166, 0x11af, 0,
+#undef V5246
+#define V5246 (V + 20123)
+ 0x1107, 0x1166, 0x11b0, 0,
+#undef V5247
+#define V5247 (V + 20127)
+ 0x1107, 0x1166, 0x11b1, 0,
+#undef V5248
+#define V5248 (V + 20131)
+ 0x1107, 0x1166, 0x11b2, 0,
+#undef V5249
+#define V5249 (V + 20135)
+ 0x1107, 0x1166, 0x11b3, 0,
+#undef V5250
+#define V5250 (V + 20139)
+ 0x1107, 0x1166, 0x11b4, 0,
+#undef V5251
+#define V5251 (V + 20143)
+ 0x1107, 0x1166, 0x11b5, 0,
+#undef V5252
+#define V5252 (V + 20147)
+ 0x1107, 0x1166, 0x11b6, 0,
+#undef V5253
+#define V5253 (V + 20151)
+ 0x1107, 0x1166, 0x11b7, 0,
+#undef V5254
+#define V5254 (V + 20155)
+ 0x1107, 0x1166, 0x11b8, 0,
+#undef V5255
+#define V5255 (V + 20159)
+ 0x1107, 0x1166, 0x11b9, 0,
+#undef V5256
+#define V5256 (V + 20163)
+ 0x1107, 0x1166, 0x11ba, 0,
+#undef V5257
+#define V5257 (V + 20167)
+ 0x1107, 0x1166, 0x11bb, 0,
+#undef V5258
+#define V5258 (V + 20171)
+ 0x1107, 0x1166, 0x11bc, 0,
+#undef V5259
+#define V5259 (V + 20175)
+ 0x1107, 0x1166, 0x11bd, 0,
+#undef V5260
+#define V5260 (V + 20179)
+ 0x1107, 0x1166, 0x11be, 0,
+#undef V5261
+#define V5261 (V + 20183)
+ 0x1107, 0x1166, 0x11bf, 0,
+#undef V5262
+#define V5262 (V + 20187)
+ 0x1107, 0x1166, 0x11c0, 0,
+#undef V5263
+#define V5263 (V + 20191)
+ 0x1107, 0x1166, 0x11c1, 0,
+#undef V5264
+#define V5264 (V + 20195)
+ 0x1107, 0x1166, 0x11c2, 0,
+#undef V5265
+#define V5265 (V + 20199)
+ 0x1107, 0x1167, 0,
+#undef V5266
+#define V5266 (V + 20202)
+ 0x1107, 0x1167, 0x11a8, 0,
+#undef V5267
+#define V5267 (V + 20206)
+ 0x1107, 0x1167, 0x11a9, 0,
+#undef V5268
+#define V5268 (V + 20210)
+ 0x1107, 0x1167, 0x11aa, 0,
+#undef V5269
+#define V5269 (V + 20214)
+ 0x1107, 0x1167, 0x11ab, 0,
+#undef V5270
+#define V5270 (V + 20218)
+ 0x1107, 0x1167, 0x11ac, 0,
+#undef V5271
+#define V5271 (V + 20222)
+ 0x1107, 0x1167, 0x11ad, 0,
+#undef V5272
+#define V5272 (V + 20226)
+ 0x1107, 0x1167, 0x11ae, 0,
+#undef V5273
+#define V5273 (V + 20230)
+ 0x1107, 0x1167, 0x11af, 0,
+#undef V5274
+#define V5274 (V + 20234)
+ 0x1107, 0x1167, 0x11b0, 0,
+#undef V5275
+#define V5275 (V + 20238)
+ 0x1107, 0x1167, 0x11b1, 0,
+#undef V5276
+#define V5276 (V + 20242)
+ 0x1107, 0x1167, 0x11b2, 0,
+#undef V5277
+#define V5277 (V + 20246)
+ 0x1107, 0x1167, 0x11b3, 0,
+#undef V5278
+#define V5278 (V + 20250)
+ 0x1107, 0x1167, 0x11b4, 0,
+#undef V5279
+#define V5279 (V + 20254)
+ 0x1107, 0x1167, 0x11b5, 0,
+#undef V5280
+#define V5280 (V + 20258)
+ 0x1107, 0x1167, 0x11b6, 0,
+#undef V5281
+#define V5281 (V + 20262)
+ 0x1107, 0x1167, 0x11b7, 0,
+#undef V5282
+#define V5282 (V + 20266)
+ 0x1107, 0x1167, 0x11b8, 0,
+#undef V5283
+#define V5283 (V + 20270)
+ 0x1107, 0x1167, 0x11b9, 0,
+#undef V5284
+#define V5284 (V + 20274)
+ 0x1107, 0x1167, 0x11ba, 0,
+#undef V5285
+#define V5285 (V + 20278)
+ 0x1107, 0x1167, 0x11bb, 0,
+#undef V5286
+#define V5286 (V + 20282)
+ 0x1107, 0x1167, 0x11bc, 0,
+#undef V5287
+#define V5287 (V + 20286)
+ 0x1107, 0x1167, 0x11bd, 0,
+#undef V5288
+#define V5288 (V + 20290)
+ 0x1107, 0x1167, 0x11be, 0,
+#undef V5289
+#define V5289 (V + 20294)
+ 0x1107, 0x1167, 0x11bf, 0,
+#undef V5290
+#define V5290 (V + 20298)
+ 0x1107, 0x1167, 0x11c0, 0,
+#undef V5291
+#define V5291 (V + 20302)
+ 0x1107, 0x1167, 0x11c1, 0,
+#undef V5292
+#define V5292 (V + 20306)
+ 0x1107, 0x1167, 0x11c2, 0,
+#undef V5293
+#define V5293 (V + 20310)
+ 0x1107, 0x1168, 0,
+#undef V5294
+#define V5294 (V + 20313)
+ 0x1107, 0x1168, 0x11a8, 0,
+#undef V5295
+#define V5295 (V + 20317)
+ 0x1107, 0x1168, 0x11a9, 0,
+#undef V5296
+#define V5296 (V + 20321)
+ 0x1107, 0x1168, 0x11aa, 0,
+#undef V5297
+#define V5297 (V + 20325)
+ 0x1107, 0x1168, 0x11ab, 0,
+#undef V5298
+#define V5298 (V + 20329)
+ 0x1107, 0x1168, 0x11ac, 0,
+#undef V5299
+#define V5299 (V + 20333)
+ 0x1107, 0x1168, 0x11ad, 0,
+#undef V5300
+#define V5300 (V + 20337)
+ 0x1107, 0x1168, 0x11ae, 0,
+#undef V5301
+#define V5301 (V + 20341)
+ 0x1107, 0x1168, 0x11af, 0,
+#undef V5302
+#define V5302 (V + 20345)
+ 0x1107, 0x1168, 0x11b0, 0,
+#undef V5303
+#define V5303 (V + 20349)
+ 0x1107, 0x1168, 0x11b1, 0,
+#undef V5304
+#define V5304 (V + 20353)
+ 0x1107, 0x1168, 0x11b2, 0,
+#undef V5305
+#define V5305 (V + 20357)
+ 0x1107, 0x1168, 0x11b3, 0,
+#undef V5306
+#define V5306 (V + 20361)
+ 0x1107, 0x1168, 0x11b4, 0,
+#undef V5307
+#define V5307 (V + 20365)
+ 0x1107, 0x1168, 0x11b5, 0,
+#undef V5308
+#define V5308 (V + 20369)
+ 0x1107, 0x1168, 0x11b6, 0,
+#undef V5309
+#define V5309 (V + 20373)
+ 0x1107, 0x1168, 0x11b7, 0,
+#undef V5310
+#define V5310 (V + 20377)
+ 0x1107, 0x1168, 0x11b8, 0,
+#undef V5311
+#define V5311 (V + 20381)
+ 0x1107, 0x1168, 0x11b9, 0,
+#undef V5312
+#define V5312 (V + 20385)
+ 0x1107, 0x1168, 0x11ba, 0,
+#undef V5313
+#define V5313 (V + 20389)
+ 0x1107, 0x1168, 0x11bb, 0,
+#undef V5314
+#define V5314 (V + 20393)
+ 0x1107, 0x1168, 0x11bc, 0,
+#undef V5315
+#define V5315 (V + 20397)
+ 0x1107, 0x1168, 0x11bd, 0,
+#undef V5316
+#define V5316 (V + 20401)
+ 0x1107, 0x1168, 0x11be, 0,
+#undef V5317
+#define V5317 (V + 20405)
+ 0x1107, 0x1168, 0x11bf, 0,
+#undef V5318
+#define V5318 (V + 20409)
+ 0x1107, 0x1168, 0x11c0, 0,
+#undef V5319
+#define V5319 (V + 20413)
+ 0x1107, 0x1168, 0x11c1, 0,
+#undef V5320
+#define V5320 (V + 20417)
+ 0x1107, 0x1168, 0x11c2, 0,
+#undef V5321
+#define V5321 (V + 20421)
+ 0x1107, 0x1169, 0,
+#undef V5322
+#define V5322 (V + 20424)
+ 0x1107, 0x1169, 0x11a8, 0,
+#undef V5323
+#define V5323 (V + 20428)
+ 0x1107, 0x1169, 0x11a9, 0,
+#undef V5324
+#define V5324 (V + 20432)
+ 0x1107, 0x1169, 0x11aa, 0,
+#undef V5325
+#define V5325 (V + 20436)
+ 0x1107, 0x1169, 0x11ab, 0,
+#undef V5326
+#define V5326 (V + 20440)
+ 0x1107, 0x1169, 0x11ac, 0,
+#undef V5327
+#define V5327 (V + 20444)
+ 0x1107, 0x1169, 0x11ad, 0,
+#undef V5328
+#define V5328 (V + 20448)
+ 0x1107, 0x1169, 0x11ae, 0,
+#undef V5329
+#define V5329 (V + 20452)
+ 0x1107, 0x1169, 0x11af, 0,
+#undef V5330
+#define V5330 (V + 20456)
+ 0x1107, 0x1169, 0x11b0, 0,
+#undef V5331
+#define V5331 (V + 20460)
+ 0x1107, 0x1169, 0x11b1, 0,
+#undef V5332
+#define V5332 (V + 20464)
+ 0x1107, 0x1169, 0x11b2, 0,
+#undef V5333
+#define V5333 (V + 20468)
+ 0x1107, 0x1169, 0x11b3, 0,
+#undef V5334
+#define V5334 (V + 20472)
+ 0x1107, 0x1169, 0x11b4, 0,
+#undef V5335
+#define V5335 (V + 20476)
+ 0x1107, 0x1169, 0x11b5, 0,
+#undef V5336
+#define V5336 (V + 20480)
+ 0x1107, 0x1169, 0x11b6, 0,
+#undef V5337
+#define V5337 (V + 20484)
+ 0x1107, 0x1169, 0x11b7, 0,
+#undef V5338
+#define V5338 (V + 20488)
+ 0x1107, 0x1169, 0x11b8, 0,
+#undef V5339
+#define V5339 (V + 20492)
+ 0x1107, 0x1169, 0x11b9, 0,
+#undef V5340
+#define V5340 (V + 20496)
+ 0x1107, 0x1169, 0x11ba, 0,
+#undef V5341
+#define V5341 (V + 20500)
+ 0x1107, 0x1169, 0x11bb, 0,
+#undef V5342
+#define V5342 (V + 20504)
+ 0x1107, 0x1169, 0x11bc, 0,
+#undef V5343
+#define V5343 (V + 20508)
+ 0x1107, 0x1169, 0x11bd, 0,
+#undef V5344
+#define V5344 (V + 20512)
+ 0x1107, 0x1169, 0x11be, 0,
+#undef V5345
+#define V5345 (V + 20516)
+ 0x1107, 0x1169, 0x11bf, 0,
+#undef V5346
+#define V5346 (V + 20520)
+ 0x1107, 0x1169, 0x11c0, 0,
+#undef V5347
+#define V5347 (V + 20524)
+ 0x1107, 0x1169, 0x11c1, 0,
+#undef V5348
+#define V5348 (V + 20528)
+ 0x1107, 0x1169, 0x11c2, 0,
+#undef V5349
+#define V5349 (V + 20532)
+ 0x1107, 0x116a, 0,
+#undef V5350
+#define V5350 (V + 20535)
+ 0x1107, 0x116a, 0x11a8, 0,
+#undef V5351
+#define V5351 (V + 20539)
+ 0x1107, 0x116a, 0x11a9, 0,
+#undef V5352
+#define V5352 (V + 20543)
+ 0x1107, 0x116a, 0x11aa, 0,
+#undef V5353
+#define V5353 (V + 20547)
+ 0x1107, 0x116a, 0x11ab, 0,
+#undef V5354
+#define V5354 (V + 20551)
+ 0x1107, 0x116a, 0x11ac, 0,
+#undef V5355
+#define V5355 (V + 20555)
+ 0x1107, 0x116a, 0x11ad, 0,
+#undef V5356
+#define V5356 (V + 20559)
+ 0x1107, 0x116a, 0x11ae, 0,
+#undef V5357
+#define V5357 (V + 20563)
+ 0x1107, 0x116a, 0x11af, 0,
+#undef V5358
+#define V5358 (V + 20567)
+ 0x1107, 0x116a, 0x11b0, 0,
+#undef V5359
+#define V5359 (V + 20571)
+ 0x1107, 0x116a, 0x11b1, 0,
+#undef V5360
+#define V5360 (V + 20575)
+ 0x1107, 0x116a, 0x11b2, 0,
+#undef V5361
+#define V5361 (V + 20579)
+ 0x1107, 0x116a, 0x11b3, 0,
+#undef V5362
+#define V5362 (V + 20583)
+ 0x1107, 0x116a, 0x11b4, 0,
+#undef V5363
+#define V5363 (V + 20587)
+ 0x1107, 0x116a, 0x11b5, 0,
+#undef V5364
+#define V5364 (V + 20591)
+ 0x1107, 0x116a, 0x11b6, 0,
+#undef V5365
+#define V5365 (V + 20595)
+ 0x1107, 0x116a, 0x11b7, 0,
+#undef V5366
+#define V5366 (V + 20599)
+ 0x1107, 0x116a, 0x11b8, 0,
+#undef V5367
+#define V5367 (V + 20603)
+ 0x1107, 0x116a, 0x11b9, 0,
+#undef V5368
+#define V5368 (V + 20607)
+ 0x1107, 0x116a, 0x11ba, 0,
+#undef V5369
+#define V5369 (V + 20611)
+ 0x1107, 0x116a, 0x11bb, 0,
+#undef V5370
+#define V5370 (V + 20615)
+ 0x1107, 0x116a, 0x11bc, 0,
+#undef V5371
+#define V5371 (V + 20619)
+ 0x1107, 0x116a, 0x11bd, 0,
+#undef V5372
+#define V5372 (V + 20623)
+ 0x1107, 0x116a, 0x11be, 0,
+#undef V5373
+#define V5373 (V + 20627)
+ 0x1107, 0x116a, 0x11bf, 0,
+#undef V5374
+#define V5374 (V + 20631)
+ 0x1107, 0x116a, 0x11c0, 0,
+#undef V5375
+#define V5375 (V + 20635)
+ 0x1107, 0x116a, 0x11c1, 0,
+#undef V5376
+#define V5376 (V + 20639)
+ 0x1107, 0x116a, 0x11c2, 0,
+#undef V5377
+#define V5377 (V + 20643)
+ 0x1107, 0x116b, 0,
+#undef V5378
+#define V5378 (V + 20646)
+ 0x1107, 0x116b, 0x11a8, 0,
+#undef V5379
+#define V5379 (V + 20650)
+ 0x1107, 0x116b, 0x11a9, 0,
+#undef V5380
+#define V5380 (V + 20654)
+ 0x1107, 0x116b, 0x11aa, 0,
+#undef V5381
+#define V5381 (V + 20658)
+ 0x1107, 0x116b, 0x11ab, 0,
+#undef V5382
+#define V5382 (V + 20662)
+ 0x1107, 0x116b, 0x11ac, 0,
+#undef V5383
+#define V5383 (V + 20666)
+ 0x1107, 0x116b, 0x11ad, 0,
+#undef V5384
+#define V5384 (V + 20670)
+ 0x1107, 0x116b, 0x11ae, 0,
+#undef V5385
+#define V5385 (V + 20674)
+ 0x1107, 0x116b, 0x11af, 0,
+#undef V5386
+#define V5386 (V + 20678)
+ 0x1107, 0x116b, 0x11b0, 0,
+#undef V5387
+#define V5387 (V + 20682)
+ 0x1107, 0x116b, 0x11b1, 0,
+#undef V5388
+#define V5388 (V + 20686)
+ 0x1107, 0x116b, 0x11b2, 0,
+#undef V5389
+#define V5389 (V + 20690)
+ 0x1107, 0x116b, 0x11b3, 0,
+#undef V5390
+#define V5390 (V + 20694)
+ 0x1107, 0x116b, 0x11b4, 0,
+#undef V5391
+#define V5391 (V + 20698)
+ 0x1107, 0x116b, 0x11b5, 0,
+#undef V5392
+#define V5392 (V + 20702)
+ 0x1107, 0x116b, 0x11b6, 0,
+#undef V5393
+#define V5393 (V + 20706)
+ 0x1107, 0x116b, 0x11b7, 0,
+#undef V5394
+#define V5394 (V + 20710)
+ 0x1107, 0x116b, 0x11b8, 0,
+#undef V5395
+#define V5395 (V + 20714)
+ 0x1107, 0x116b, 0x11b9, 0,
+#undef V5396
+#define V5396 (V + 20718)
+ 0x1107, 0x116b, 0x11ba, 0,
+#undef V5397
+#define V5397 (V + 20722)
+ 0x1107, 0x116b, 0x11bb, 0,
+#undef V5398
+#define V5398 (V + 20726)
+ 0x1107, 0x116b, 0x11bc, 0,
+#undef V5399
+#define V5399 (V + 20730)
+ 0x1107, 0x116b, 0x11bd, 0,
+#undef V5400
+#define V5400 (V + 20734)
+ 0x1107, 0x116b, 0x11be, 0,
+#undef V5401
+#define V5401 (V + 20738)
+ 0x1107, 0x116b, 0x11bf, 0,
+#undef V5402
+#define V5402 (V + 20742)
+ 0x1107, 0x116b, 0x11c0, 0,
+#undef V5403
+#define V5403 (V + 20746)
+ 0x1107, 0x116b, 0x11c1, 0,
+#undef V5404
+#define V5404 (V + 20750)
+ 0x1107, 0x116b, 0x11c2, 0,
+#undef V5405
+#define V5405 (V + 20754)
+ 0x1107, 0x116c, 0,
+#undef V5406
+#define V5406 (V + 20757)
+ 0x1107, 0x116c, 0x11a8, 0,
+#undef V5407
+#define V5407 (V + 20761)
+ 0x1107, 0x116c, 0x11a9, 0,
+#undef V5408
+#define V5408 (V + 20765)
+ 0x1107, 0x116c, 0x11aa, 0,
+#undef V5409
+#define V5409 (V + 20769)
+ 0x1107, 0x116c, 0x11ab, 0,
+#undef V5410
+#define V5410 (V + 20773)
+ 0x1107, 0x116c, 0x11ac, 0,
+#undef V5411
+#define V5411 (V + 20777)
+ 0x1107, 0x116c, 0x11ad, 0,
+#undef V5412
+#define V5412 (V + 20781)
+ 0x1107, 0x116c, 0x11ae, 0,
+#undef V5413
+#define V5413 (V + 20785)
+ 0x1107, 0x116c, 0x11af, 0,
+#undef V5414
+#define V5414 (V + 20789)
+ 0x1107, 0x116c, 0x11b0, 0,
+#undef V5415
+#define V5415 (V + 20793)
+ 0x1107, 0x116c, 0x11b1, 0,
+#undef V5416
+#define V5416 (V + 20797)
+ 0x1107, 0x116c, 0x11b2, 0,
+#undef V5417
+#define V5417 (V + 20801)
+ 0x1107, 0x116c, 0x11b3, 0,
+#undef V5418
+#define V5418 (V + 20805)
+ 0x1107, 0x116c, 0x11b4, 0,
+#undef V5419
+#define V5419 (V + 20809)
+ 0x1107, 0x116c, 0x11b5, 0,
+#undef V5420
+#define V5420 (V + 20813)
+ 0x1107, 0x116c, 0x11b6, 0,
+#undef V5421
+#define V5421 (V + 20817)
+ 0x1107, 0x116c, 0x11b7, 0,
+#undef V5422
+#define V5422 (V + 20821)
+ 0x1107, 0x116c, 0x11b8, 0,
+#undef V5423
+#define V5423 (V + 20825)
+ 0x1107, 0x116c, 0x11b9, 0,
+#undef V5424
+#define V5424 (V + 20829)
+ 0x1107, 0x116c, 0x11ba, 0,
+#undef V5425
+#define V5425 (V + 20833)
+ 0x1107, 0x116c, 0x11bb, 0,
+#undef V5426
+#define V5426 (V + 20837)
+ 0x1107, 0x116c, 0x11bc, 0,
+#undef V5427
+#define V5427 (V + 20841)
+ 0x1107, 0x116c, 0x11bd, 0,
+#undef V5428
+#define V5428 (V + 20845)
+ 0x1107, 0x116c, 0x11be, 0,
+#undef V5429
+#define V5429 (V + 20849)
+ 0x1107, 0x116c, 0x11bf, 0,
+#undef V5430
+#define V5430 (V + 20853)
+ 0x1107, 0x116c, 0x11c0, 0,
+#undef V5431
+#define V5431 (V + 20857)
+ 0x1107, 0x116c, 0x11c1, 0,
+#undef V5432
+#define V5432 (V + 20861)
+ 0x1107, 0x116c, 0x11c2, 0,
+#undef V5433
+#define V5433 (V + 20865)
+ 0x1107, 0x116d, 0,
+#undef V5434
+#define V5434 (V + 20868)
+ 0x1107, 0x116d, 0x11a8, 0,
+#undef V5435
+#define V5435 (V + 20872)
+ 0x1107, 0x116d, 0x11a9, 0,
+#undef V5436
+#define V5436 (V + 20876)
+ 0x1107, 0x116d, 0x11aa, 0,
+#undef V5437
+#define V5437 (V + 20880)
+ 0x1107, 0x116d, 0x11ab, 0,
+#undef V5438
+#define V5438 (V + 20884)
+ 0x1107, 0x116d, 0x11ac, 0,
+#undef V5439
+#define V5439 (V + 20888)
+ 0x1107, 0x116d, 0x11ad, 0,
+#undef V5440
+#define V5440 (V + 20892)
+ 0x1107, 0x116d, 0x11ae, 0,
+#undef V5441
+#define V5441 (V + 20896)
+ 0x1107, 0x116d, 0x11af, 0,
+#undef V5442
+#define V5442 (V + 20900)
+ 0x1107, 0x116d, 0x11b0, 0,
+#undef V5443
+#define V5443 (V + 20904)
+ 0x1107, 0x116d, 0x11b1, 0,
+#undef V5444
+#define V5444 (V + 20908)
+ 0x1107, 0x116d, 0x11b2, 0,
+#undef V5445
+#define V5445 (V + 20912)
+ 0x1107, 0x116d, 0x11b3, 0,
+#undef V5446
+#define V5446 (V + 20916)
+ 0x1107, 0x116d, 0x11b4, 0,
+#undef V5447
+#define V5447 (V + 20920)
+ 0x1107, 0x116d, 0x11b5, 0,
+#undef V5448
+#define V5448 (V + 20924)
+ 0x1107, 0x116d, 0x11b6, 0,
+#undef V5449
+#define V5449 (V + 20928)
+ 0x1107, 0x116d, 0x11b7, 0,
+#undef V5450
+#define V5450 (V + 20932)
+ 0x1107, 0x116d, 0x11b8, 0,
+#undef V5451
+#define V5451 (V + 20936)
+ 0x1107, 0x116d, 0x11b9, 0,
+#undef V5452
+#define V5452 (V + 20940)
+ 0x1107, 0x116d, 0x11ba, 0,
+#undef V5453
+#define V5453 (V + 20944)
+ 0x1107, 0x116d, 0x11bb, 0,
+#undef V5454
+#define V5454 (V + 20948)
+ 0x1107, 0x116d, 0x11bc, 0,
+#undef V5455
+#define V5455 (V + 20952)
+ 0x1107, 0x116d, 0x11bd, 0,
+#undef V5456
+#define V5456 (V + 20956)
+ 0x1107, 0x116d, 0x11be, 0,
+#undef V5457
+#define V5457 (V + 20960)
+ 0x1107, 0x116d, 0x11bf, 0,
+#undef V5458
+#define V5458 (V + 20964)
+ 0x1107, 0x116d, 0x11c0, 0,
+#undef V5459
+#define V5459 (V + 20968)
+ 0x1107, 0x116d, 0x11c1, 0,
+#undef V5460
+#define V5460 (V + 20972)
+ 0x1107, 0x116d, 0x11c2, 0,
+#undef V5461
+#define V5461 (V + 20976)
+ 0x1107, 0x116e, 0,
+#undef V5462
+#define V5462 (V + 20979)
+ 0x1107, 0x116e, 0x11a8, 0,
+#undef V5463
+#define V5463 (V + 20983)
+ 0x1107, 0x116e, 0x11a9, 0,
+#undef V5464
+#define V5464 (V + 20987)
+ 0x1107, 0x116e, 0x11aa, 0,
+#undef V5465
+#define V5465 (V + 20991)
+ 0x1107, 0x116e, 0x11ab, 0,
+#undef V5466
+#define V5466 (V + 20995)
+ 0x1107, 0x116e, 0x11ac, 0,
+#undef V5467
+#define V5467 (V + 20999)
+ 0x1107, 0x116e, 0x11ad, 0,
+#undef V5468
+#define V5468 (V + 21003)
+ 0x1107, 0x116e, 0x11ae, 0,
+#undef V5469
+#define V5469 (V + 21007)
+ 0x1107, 0x116e, 0x11af, 0,
+#undef V5470
+#define V5470 (V + 21011)
+ 0x1107, 0x116e, 0x11b0, 0,
+#undef V5471
+#define V5471 (V + 21015)
+ 0x1107, 0x116e, 0x11b1, 0,
+#undef V5472
+#define V5472 (V + 21019)
+ 0x1107, 0x116e, 0x11b2, 0,
+#undef V5473
+#define V5473 (V + 21023)
+ 0x1107, 0x116e, 0x11b3, 0,
+#undef V5474
+#define V5474 (V + 21027)
+ 0x1107, 0x116e, 0x11b4, 0,
+#undef V5475
+#define V5475 (V + 21031)
+ 0x1107, 0x116e, 0x11b5, 0,
+#undef V5476
+#define V5476 (V + 21035)
+ 0x1107, 0x116e, 0x11b6, 0,
+#undef V5477
+#define V5477 (V + 21039)
+ 0x1107, 0x116e, 0x11b7, 0,
+#undef V5478
+#define V5478 (V + 21043)
+ 0x1107, 0x116e, 0x11b8, 0,
+#undef V5479
+#define V5479 (V + 21047)
+ 0x1107, 0x116e, 0x11b9, 0,
+#undef V5480
+#define V5480 (V + 21051)
+ 0x1107, 0x116e, 0x11ba, 0,
+#undef V5481
+#define V5481 (V + 21055)
+ 0x1107, 0x116e, 0x11bb, 0,
+#undef V5482
+#define V5482 (V + 21059)
+ 0x1107, 0x116e, 0x11bc, 0,
+#undef V5483
+#define V5483 (V + 21063)
+ 0x1107, 0x116e, 0x11bd, 0,
+#undef V5484
+#define V5484 (V + 21067)
+ 0x1107, 0x116e, 0x11be, 0,
+#undef V5485
+#define V5485 (V + 21071)
+ 0x1107, 0x116e, 0x11bf, 0,
+#undef V5486
+#define V5486 (V + 21075)
+ 0x1107, 0x116e, 0x11c0, 0,
+#undef V5487
+#define V5487 (V + 21079)
+ 0x1107, 0x116e, 0x11c1, 0,
+#undef V5488
+#define V5488 (V + 21083)
+ 0x1107, 0x116e, 0x11c2, 0,
+#undef V5489
+#define V5489 (V + 21087)
+ 0x1107, 0x116f, 0,
+#undef V5490
+#define V5490 (V + 21090)
+ 0x1107, 0x116f, 0x11a8, 0,
+#undef V5491
+#define V5491 (V + 21094)
+ 0x1107, 0x116f, 0x11a9, 0,
+#undef V5492
+#define V5492 (V + 21098)
+ 0x1107, 0x116f, 0x11aa, 0,
+#undef V5493
+#define V5493 (V + 21102)
+ 0x1107, 0x116f, 0x11ab, 0,
+#undef V5494
+#define V5494 (V + 21106)
+ 0x1107, 0x116f, 0x11ac, 0,
+#undef V5495
+#define V5495 (V + 21110)
+ 0x1107, 0x116f, 0x11ad, 0,
+#undef V5496
+#define V5496 (V + 21114)
+ 0x1107, 0x116f, 0x11ae, 0,
+#undef V5497
+#define V5497 (V + 21118)
+ 0x1107, 0x116f, 0x11af, 0,
+#undef V5498
+#define V5498 (V + 21122)
+ 0x1107, 0x116f, 0x11b0, 0,
+#undef V5499
+#define V5499 (V + 21126)
+ 0x1107, 0x116f, 0x11b1, 0,
+#undef V5500
+#define V5500 (V + 21130)
+ 0x1107, 0x116f, 0x11b2, 0,
+#undef V5501
+#define V5501 (V + 21134)
+ 0x1107, 0x116f, 0x11b3, 0,
+#undef V5502
+#define V5502 (V + 21138)
+ 0x1107, 0x116f, 0x11b4, 0,
+#undef V5503
+#define V5503 (V + 21142)
+ 0x1107, 0x116f, 0x11b5, 0,
+#undef V5504
+#define V5504 (V + 21146)
+ 0x1107, 0x116f, 0x11b6, 0,
+#undef V5505
+#define V5505 (V + 21150)
+ 0x1107, 0x116f, 0x11b7, 0,
+#undef V5506
+#define V5506 (V + 21154)
+ 0x1107, 0x116f, 0x11b8, 0,
+#undef V5507
+#define V5507 (V + 21158)
+ 0x1107, 0x116f, 0x11b9, 0,
+#undef V5508
+#define V5508 (V + 21162)
+ 0x1107, 0x116f, 0x11ba, 0,
+#undef V5509
+#define V5509 (V + 21166)
+ 0x1107, 0x116f, 0x11bb, 0,
+#undef V5510
+#define V5510 (V + 21170)
+ 0x1107, 0x116f, 0x11bc, 0,
+#undef V5511
+#define V5511 (V + 21174)
+ 0x1107, 0x116f, 0x11bd, 0,
+#undef V5512
+#define V5512 (V + 21178)
+ 0x1107, 0x116f, 0x11be, 0,
+#undef V5513
+#define V5513 (V + 21182)
+ 0x1107, 0x116f, 0x11bf, 0,
+#undef V5514
+#define V5514 (V + 21186)
+ 0x1107, 0x116f, 0x11c0, 0,
+#undef V5515
+#define V5515 (V + 21190)
+ 0x1107, 0x116f, 0x11c1, 0,
+#undef V5516
+#define V5516 (V + 21194)
+ 0x1107, 0x116f, 0x11c2, 0,
+#undef V5517
+#define V5517 (V + 21198)
+ 0x1107, 0x1170, 0,
+#undef V5518
+#define V5518 (V + 21201)
+ 0x1107, 0x1170, 0x11a8, 0,
+#undef V5519
+#define V5519 (V + 21205)
+ 0x1107, 0x1170, 0x11a9, 0,
+#undef V5520
+#define V5520 (V + 21209)
+ 0x1107, 0x1170, 0x11aa, 0,
+#undef V5521
+#define V5521 (V + 21213)
+ 0x1107, 0x1170, 0x11ab, 0,
+#undef V5522
+#define V5522 (V + 21217)
+ 0x1107, 0x1170, 0x11ac, 0,
+#undef V5523
+#define V5523 (V + 21221)
+ 0x1107, 0x1170, 0x11ad, 0,
+#undef V5524
+#define V5524 (V + 21225)
+ 0x1107, 0x1170, 0x11ae, 0,
+#undef V5525
+#define V5525 (V + 21229)
+ 0x1107, 0x1170, 0x11af, 0,
+#undef V5526
+#define V5526 (V + 21233)
+ 0x1107, 0x1170, 0x11b0, 0,
+#undef V5527
+#define V5527 (V + 21237)
+ 0x1107, 0x1170, 0x11b1, 0,
+#undef V5528
+#define V5528 (V + 21241)
+ 0x1107, 0x1170, 0x11b2, 0,
+#undef V5529
+#define V5529 (V + 21245)
+ 0x1107, 0x1170, 0x11b3, 0,
+#undef V5530
+#define V5530 (V + 21249)
+ 0x1107, 0x1170, 0x11b4, 0,
+#undef V5531
+#define V5531 (V + 21253)
+ 0x1107, 0x1170, 0x11b5, 0,
+#undef V5532
+#define V5532 (V + 21257)
+ 0x1107, 0x1170, 0x11b6, 0,
+#undef V5533
+#define V5533 (V + 21261)
+ 0x1107, 0x1170, 0x11b7, 0,
+#undef V5534
+#define V5534 (V + 21265)
+ 0x1107, 0x1170, 0x11b8, 0,
+#undef V5535
+#define V5535 (V + 21269)
+ 0x1107, 0x1170, 0x11b9, 0,
+#undef V5536
+#define V5536 (V + 21273)
+ 0x1107, 0x1170, 0x11ba, 0,
+#undef V5537
+#define V5537 (V + 21277)
+ 0x1107, 0x1170, 0x11bb, 0,
+#undef V5538
+#define V5538 (V + 21281)
+ 0x1107, 0x1170, 0x11bc, 0,
+#undef V5539
+#define V5539 (V + 21285)
+ 0x1107, 0x1170, 0x11bd, 0,
+#undef V5540
+#define V5540 (V + 21289)
+ 0x1107, 0x1170, 0x11be, 0,
+#undef V5541
+#define V5541 (V + 21293)
+ 0x1107, 0x1170, 0x11bf, 0,
+#undef V5542
+#define V5542 (V + 21297)
+ 0x1107, 0x1170, 0x11c0, 0,
+#undef V5543
+#define V5543 (V + 21301)
+ 0x1107, 0x1170, 0x11c1, 0,
+#undef V5544
+#define V5544 (V + 21305)
+ 0x1107, 0x1170, 0x11c2, 0,
+#undef V5545
+#define V5545 (V + 21309)
+ 0x1107, 0x1171, 0,
+#undef V5546
+#define V5546 (V + 21312)
+ 0x1107, 0x1171, 0x11a8, 0,
+#undef V5547
+#define V5547 (V + 21316)
+ 0x1107, 0x1171, 0x11a9, 0,
+#undef V5548
+#define V5548 (V + 21320)
+ 0x1107, 0x1171, 0x11aa, 0,
+#undef V5549
+#define V5549 (V + 21324)
+ 0x1107, 0x1171, 0x11ab, 0,
+#undef V5550
+#define V5550 (V + 21328)
+ 0x1107, 0x1171, 0x11ac, 0,
+#undef V5551
+#define V5551 (V + 21332)
+ 0x1107, 0x1171, 0x11ad, 0,
+#undef V5552
+#define V5552 (V + 21336)
+ 0x1107, 0x1171, 0x11ae, 0,
+#undef V5553
+#define V5553 (V + 21340)
+ 0x1107, 0x1171, 0x11af, 0,
+#undef V5554
+#define V5554 (V + 21344)
+ 0x1107, 0x1171, 0x11b0, 0,
+#undef V5555
+#define V5555 (V + 21348)
+ 0x1107, 0x1171, 0x11b1, 0,
+#undef V5556
+#define V5556 (V + 21352)
+ 0x1107, 0x1171, 0x11b2, 0,
+#undef V5557
+#define V5557 (V + 21356)
+ 0x1107, 0x1171, 0x11b3, 0,
+#undef V5558
+#define V5558 (V + 21360)
+ 0x1107, 0x1171, 0x11b4, 0,
+#undef V5559
+#define V5559 (V + 21364)
+ 0x1107, 0x1171, 0x11b5, 0,
+#undef V5560
+#define V5560 (V + 21368)
+ 0x1107, 0x1171, 0x11b6, 0,
+#undef V5561
+#define V5561 (V + 21372)
+ 0x1107, 0x1171, 0x11b7, 0,
+#undef V5562
+#define V5562 (V + 21376)
+ 0x1107, 0x1171, 0x11b8, 0,
+#undef V5563
+#define V5563 (V + 21380)
+ 0x1107, 0x1171, 0x11b9, 0,
+#undef V5564
+#define V5564 (V + 21384)
+ 0x1107, 0x1171, 0x11ba, 0,
+#undef V5565
+#define V5565 (V + 21388)
+ 0x1107, 0x1171, 0x11bb, 0,
+#undef V5566
+#define V5566 (V + 21392)
+ 0x1107, 0x1171, 0x11bc, 0,
+#undef V5567
+#define V5567 (V + 21396)
+ 0x1107, 0x1171, 0x11bd, 0,
+#undef V5568
+#define V5568 (V + 21400)
+ 0x1107, 0x1171, 0x11be, 0,
+#undef V5569
+#define V5569 (V + 21404)
+ 0x1107, 0x1171, 0x11bf, 0,
+#undef V5570
+#define V5570 (V + 21408)
+ 0x1107, 0x1171, 0x11c0, 0,
+#undef V5571
+#define V5571 (V + 21412)
+ 0x1107, 0x1171, 0x11c1, 0,
+#undef V5572
+#define V5572 (V + 21416)
+ 0x1107, 0x1171, 0x11c2, 0,
+#undef V5573
+#define V5573 (V + 21420)
+ 0x1107, 0x1172, 0,
+#undef V5574
+#define V5574 (V + 21423)
+ 0x1107, 0x1172, 0x11a8, 0,
+#undef V5575
+#define V5575 (V + 21427)
+ 0x1107, 0x1172, 0x11a9, 0,
+#undef V5576
+#define V5576 (V + 21431)
+ 0x1107, 0x1172, 0x11aa, 0,
+#undef V5577
+#define V5577 (V + 21435)
+ 0x1107, 0x1172, 0x11ab, 0,
+#undef V5578
+#define V5578 (V + 21439)
+ 0x1107, 0x1172, 0x11ac, 0,
+#undef V5579
+#define V5579 (V + 21443)
+ 0x1107, 0x1172, 0x11ad, 0,
+#undef V5580
+#define V5580 (V + 21447)
+ 0x1107, 0x1172, 0x11ae, 0,
+#undef V5581
+#define V5581 (V + 21451)
+ 0x1107, 0x1172, 0x11af, 0,
+#undef V5582
+#define V5582 (V + 21455)
+ 0x1107, 0x1172, 0x11b0, 0,
+#undef V5583
+#define V5583 (V + 21459)
+ 0x1107, 0x1172, 0x11b1, 0,
+#undef V5584
+#define V5584 (V + 21463)
+ 0x1107, 0x1172, 0x11b2, 0,
+#undef V5585
+#define V5585 (V + 21467)
+ 0x1107, 0x1172, 0x11b3, 0,
+#undef V5586
+#define V5586 (V + 21471)
+ 0x1107, 0x1172, 0x11b4, 0,
+#undef V5587
+#define V5587 (V + 21475)
+ 0x1107, 0x1172, 0x11b5, 0,
+#undef V5588
+#define V5588 (V + 21479)
+ 0x1107, 0x1172, 0x11b6, 0,
+#undef V5589
+#define V5589 (V + 21483)
+ 0x1107, 0x1172, 0x11b7, 0,
+#undef V5590
+#define V5590 (V + 21487)
+ 0x1107, 0x1172, 0x11b8, 0,
+#undef V5591
+#define V5591 (V + 21491)
+ 0x1107, 0x1172, 0x11b9, 0,
+#undef V5592
+#define V5592 (V + 21495)
+ 0x1107, 0x1172, 0x11ba, 0,
+#undef V5593
+#define V5593 (V + 21499)
+ 0x1107, 0x1172, 0x11bb, 0,
+#undef V5594
+#define V5594 (V + 21503)
+ 0x1107, 0x1172, 0x11bc, 0,
+#undef V5595
+#define V5595 (V + 21507)
+ 0x1107, 0x1172, 0x11bd, 0,
+#undef V5596
+#define V5596 (V + 21511)
+ 0x1107, 0x1172, 0x11be, 0,
+#undef V5597
+#define V5597 (V + 21515)
+ 0x1107, 0x1172, 0x11bf, 0,
+#undef V5598
+#define V5598 (V + 21519)
+ 0x1107, 0x1172, 0x11c0, 0,
+#undef V5599
+#define V5599 (V + 21523)
+ 0x1107, 0x1172, 0x11c1, 0,
+#undef V5600
+#define V5600 (V + 21527)
+ 0x1107, 0x1172, 0x11c2, 0,
+#undef V5601
+#define V5601 (V + 21531)
+ 0x1107, 0x1173, 0,
+#undef V5602
+#define V5602 (V + 21534)
+ 0x1107, 0x1173, 0x11a8, 0,
+#undef V5603
+#define V5603 (V + 21538)
+ 0x1107, 0x1173, 0x11a9, 0,
+#undef V5604
+#define V5604 (V + 21542)
+ 0x1107, 0x1173, 0x11aa, 0,
+#undef V5605
+#define V5605 (V + 21546)
+ 0x1107, 0x1173, 0x11ab, 0,
+#undef V5606
+#define V5606 (V + 21550)
+ 0x1107, 0x1173, 0x11ac, 0,
+#undef V5607
+#define V5607 (V + 21554)
+ 0x1107, 0x1173, 0x11ad, 0,
+#undef V5608
+#define V5608 (V + 21558)
+ 0x1107, 0x1173, 0x11ae, 0,
+#undef V5609
+#define V5609 (V + 21562)
+ 0x1107, 0x1173, 0x11af, 0,
+#undef V5610
+#define V5610 (V + 21566)
+ 0x1107, 0x1173, 0x11b0, 0,
+#undef V5611
+#define V5611 (V + 21570)
+ 0x1107, 0x1173, 0x11b1, 0,
+#undef V5612
+#define V5612 (V + 21574)
+ 0x1107, 0x1173, 0x11b2, 0,
+#undef V5613
+#define V5613 (V + 21578)
+ 0x1107, 0x1173, 0x11b3, 0,
+#undef V5614
+#define V5614 (V + 21582)
+ 0x1107, 0x1173, 0x11b4, 0,
+#undef V5615
+#define V5615 (V + 21586)
+ 0x1107, 0x1173, 0x11b5, 0,
+#undef V5616
+#define V5616 (V + 21590)
+ 0x1107, 0x1173, 0x11b6, 0,
+#undef V5617
+#define V5617 (V + 21594)
+ 0x1107, 0x1173, 0x11b7, 0,
+#undef V5618
+#define V5618 (V + 21598)
+ 0x1107, 0x1173, 0x11b8, 0,
+#undef V5619
+#define V5619 (V + 21602)
+ 0x1107, 0x1173, 0x11b9, 0,
+#undef V5620
+#define V5620 (V + 21606)
+ 0x1107, 0x1173, 0x11ba, 0,
+#undef V5621
+#define V5621 (V + 21610)
+ 0x1107, 0x1173, 0x11bb, 0,
+#undef V5622
+#define V5622 (V + 21614)
+ 0x1107, 0x1173, 0x11bc, 0,
+#undef V5623
+#define V5623 (V + 21618)
+ 0x1107, 0x1173, 0x11bd, 0,
+#undef V5624
+#define V5624 (V + 21622)
+ 0x1107, 0x1173, 0x11be, 0,
+#undef V5625
+#define V5625 (V + 21626)
+ 0x1107, 0x1173, 0x11bf, 0,
+#undef V5626
+#define V5626 (V + 21630)
+ 0x1107, 0x1173, 0x11c0, 0,
+#undef V5627
+#define V5627 (V + 21634)
+ 0x1107, 0x1173, 0x11c1, 0,
+#undef V5628
+#define V5628 (V + 21638)
+ 0x1107, 0x1173, 0x11c2, 0,
+#undef V5629
+#define V5629 (V + 21642)
+ 0x1107, 0x1174, 0,
+#undef V5630
+#define V5630 (V + 21645)
+ 0x1107, 0x1174, 0x11a8, 0,
+#undef V5631
+#define V5631 (V + 21649)
+ 0x1107, 0x1174, 0x11a9, 0,
+#undef V5632
+#define V5632 (V + 21653)
+ 0x1107, 0x1174, 0x11aa, 0,
+#undef V5633
+#define V5633 (V + 21657)
+ 0x1107, 0x1174, 0x11ab, 0,
+#undef V5634
+#define V5634 (V + 21661)
+ 0x1107, 0x1174, 0x11ac, 0,
+#undef V5635
+#define V5635 (V + 21665)
+ 0x1107, 0x1174, 0x11ad, 0,
+#undef V5636
+#define V5636 (V + 21669)
+ 0x1107, 0x1174, 0x11ae, 0,
+#undef V5637
+#define V5637 (V + 21673)
+ 0x1107, 0x1174, 0x11af, 0,
+#undef V5638
+#define V5638 (V + 21677)
+ 0x1107, 0x1174, 0x11b0, 0,
+#undef V5639
+#define V5639 (V + 21681)
+ 0x1107, 0x1174, 0x11b1, 0,
+#undef V5640
+#define V5640 (V + 21685)
+ 0x1107, 0x1174, 0x11b2, 0,
+#undef V5641
+#define V5641 (V + 21689)
+ 0x1107, 0x1174, 0x11b3, 0,
+#undef V5642
+#define V5642 (V + 21693)
+ 0x1107, 0x1174, 0x11b4, 0,
+#undef V5643
+#define V5643 (V + 21697)
+ 0x1107, 0x1174, 0x11b5, 0,
+#undef V5644
+#define V5644 (V + 21701)
+ 0x1107, 0x1174, 0x11b6, 0,
+#undef V5645
+#define V5645 (V + 21705)
+ 0x1107, 0x1174, 0x11b7, 0,
+#undef V5646
+#define V5646 (V + 21709)
+ 0x1107, 0x1174, 0x11b8, 0,
+#undef V5647
+#define V5647 (V + 21713)
+ 0x1107, 0x1174, 0x11b9, 0,
+#undef V5648
+#define V5648 (V + 21717)
+ 0x1107, 0x1174, 0x11ba, 0,
+#undef V5649
+#define V5649 (V + 21721)
+ 0x1107, 0x1174, 0x11bb, 0,
+#undef V5650
+#define V5650 (V + 21725)
+ 0x1107, 0x1174, 0x11bc, 0,
+#undef V5651
+#define V5651 (V + 21729)
+ 0x1107, 0x1174, 0x11bd, 0,
+#undef V5652
+#define V5652 (V + 21733)
+ 0x1107, 0x1174, 0x11be, 0,
+#undef V5653
+#define V5653 (V + 21737)
+ 0x1107, 0x1174, 0x11bf, 0,
+#undef V5654
+#define V5654 (V + 21741)
+ 0x1107, 0x1174, 0x11c0, 0,
+#undef V5655
+#define V5655 (V + 21745)
+ 0x1107, 0x1174, 0x11c1, 0,
+#undef V5656
+#define V5656 (V + 21749)
+ 0x1107, 0x1174, 0x11c2, 0,
+#undef V5657
+#define V5657 (V + 21753)
+ 0x1107, 0x1175, 0,
+#undef V5658
+#define V5658 (V + 21756)
+ 0x1107, 0x1175, 0x11a8, 0,
+#undef V5659
+#define V5659 (V + 21760)
+ 0x1107, 0x1175, 0x11a9, 0,
+#undef V5660
+#define V5660 (V + 21764)
+ 0x1107, 0x1175, 0x11aa, 0,
+#undef V5661
+#define V5661 (V + 21768)
+ 0x1107, 0x1175, 0x11ab, 0,
+#undef V5662
+#define V5662 (V + 21772)
+ 0x1107, 0x1175, 0x11ac, 0,
+#undef V5663
+#define V5663 (V + 21776)
+ 0x1107, 0x1175, 0x11ad, 0,
+#undef V5664
+#define V5664 (V + 21780)
+ 0x1107, 0x1175, 0x11ae, 0,
+#undef V5665
+#define V5665 (V + 21784)
+ 0x1107, 0x1175, 0x11af, 0,
+#undef V5666
+#define V5666 (V + 21788)
+ 0x1107, 0x1175, 0x11b0, 0,
+#undef V5667
+#define V5667 (V + 21792)
+ 0x1107, 0x1175, 0x11b1, 0,
+#undef V5668
+#define V5668 (V + 21796)
+ 0x1107, 0x1175, 0x11b2, 0,
+#undef V5669
+#define V5669 (V + 21800)
+ 0x1107, 0x1175, 0x11b3, 0,
+#undef V5670
+#define V5670 (V + 21804)
+ 0x1107, 0x1175, 0x11b4, 0,
+#undef V5671
+#define V5671 (V + 21808)
+ 0x1107, 0x1175, 0x11b5, 0,
+#undef V5672
+#define V5672 (V + 21812)
+ 0x1107, 0x1175, 0x11b6, 0,
+#undef V5673
+#define V5673 (V + 21816)
+ 0x1107, 0x1175, 0x11b7, 0,
+#undef V5674
+#define V5674 (V + 21820)
+ 0x1107, 0x1175, 0x11b8, 0,
+#undef V5675
+#define V5675 (V + 21824)
+ 0x1107, 0x1175, 0x11b9, 0,
+#undef V5676
+#define V5676 (V + 21828)
+ 0x1107, 0x1175, 0x11ba, 0,
+#undef V5677
+#define V5677 (V + 21832)
+ 0x1107, 0x1175, 0x11bb, 0,
+#undef V5678
+#define V5678 (V + 21836)
+ 0x1107, 0x1175, 0x11bc, 0,
+#undef V5679
+#define V5679 (V + 21840)
+ 0x1107, 0x1175, 0x11bd, 0,
+#undef V5680
+#define V5680 (V + 21844)
+ 0x1107, 0x1175, 0x11be, 0,
+#undef V5681
+#define V5681 (V + 21848)
+ 0x1107, 0x1175, 0x11bf, 0,
+#undef V5682
+#define V5682 (V + 21852)
+ 0x1107, 0x1175, 0x11c0, 0,
+#undef V5683
+#define V5683 (V + 21856)
+ 0x1107, 0x1175, 0x11c1, 0,
+#undef V5684
+#define V5684 (V + 21860)
+ 0x1107, 0x1175, 0x11c2, 0,
+#undef V5685
+#define V5685 (V + 21864)
+ 0x1108, 0x1161, 0,
+#undef V5686
+#define V5686 (V + 21867)
+ 0x1108, 0x1161, 0x11a8, 0,
+#undef V5687
+#define V5687 (V + 21871)
+ 0x1108, 0x1161, 0x11a9, 0,
+#undef V5688
+#define V5688 (V + 21875)
+ 0x1108, 0x1161, 0x11aa, 0,
+#undef V5689
+#define V5689 (V + 21879)
+ 0x1108, 0x1161, 0x11ab, 0,
+#undef V5690
+#define V5690 (V + 21883)
+ 0x1108, 0x1161, 0x11ac, 0,
+#undef V5691
+#define V5691 (V + 21887)
+ 0x1108, 0x1161, 0x11ad, 0,
+#undef V5692
+#define V5692 (V + 21891)
+ 0x1108, 0x1161, 0x11ae, 0,
+#undef V5693
+#define V5693 (V + 21895)
+ 0x1108, 0x1161, 0x11af, 0,
+#undef V5694
+#define V5694 (V + 21899)
+ 0x1108, 0x1161, 0x11b0, 0,
+#undef V5695
+#define V5695 (V + 21903)
+ 0x1108, 0x1161, 0x11b1, 0,
+#undef V5696
+#define V5696 (V + 21907)
+ 0x1108, 0x1161, 0x11b2, 0,
+#undef V5697
+#define V5697 (V + 21911)
+ 0x1108, 0x1161, 0x11b3, 0,
+#undef V5698
+#define V5698 (V + 21915)
+ 0x1108, 0x1161, 0x11b4, 0,
+#undef V5699
+#define V5699 (V + 21919)
+ 0x1108, 0x1161, 0x11b5, 0,
+#undef V5700
+#define V5700 (V + 21923)
+ 0x1108, 0x1161, 0x11b6, 0,
+#undef V5701
+#define V5701 (V + 21927)
+ 0x1108, 0x1161, 0x11b7, 0,
+#undef V5702
+#define V5702 (V + 21931)
+ 0x1108, 0x1161, 0x11b8, 0,
+#undef V5703
+#define V5703 (V + 21935)
+ 0x1108, 0x1161, 0x11b9, 0,
+#undef V5704
+#define V5704 (V + 21939)
+ 0x1108, 0x1161, 0x11ba, 0,
+#undef V5705
+#define V5705 (V + 21943)
+ 0x1108, 0x1161, 0x11bb, 0,
+#undef V5706
+#define V5706 (V + 21947)
+ 0x1108, 0x1161, 0x11bc, 0,
+#undef V5707
+#define V5707 (V + 21951)
+ 0x1108, 0x1161, 0x11bd, 0,
+#undef V5708
+#define V5708 (V + 21955)
+ 0x1108, 0x1161, 0x11be, 0,
+#undef V5709
+#define V5709 (V + 21959)
+ 0x1108, 0x1161, 0x11bf, 0,
+#undef V5710
+#define V5710 (V + 21963)
+ 0x1108, 0x1161, 0x11c0, 0,
+#undef V5711
+#define V5711 (V + 21967)
+ 0x1108, 0x1161, 0x11c1, 0,
+#undef V5712
+#define V5712 (V + 21971)
+ 0x1108, 0x1161, 0x11c2, 0,
+#undef V5713
+#define V5713 (V + 21975)
+ 0x1108, 0x1162, 0,
+#undef V5714
+#define V5714 (V + 21978)
+ 0x1108, 0x1162, 0x11a8, 0,
+#undef V5715
+#define V5715 (V + 21982)
+ 0x1108, 0x1162, 0x11a9, 0,
+#undef V5716
+#define V5716 (V + 21986)
+ 0x1108, 0x1162, 0x11aa, 0,
+#undef V5717
+#define V5717 (V + 21990)
+ 0x1108, 0x1162, 0x11ab, 0,
+#undef V5718
+#define V5718 (V + 21994)
+ 0x1108, 0x1162, 0x11ac, 0,
+#undef V5719
+#define V5719 (V + 21998)
+ 0x1108, 0x1162, 0x11ad, 0,
+#undef V5720
+#define V5720 (V + 22002)
+ 0x1108, 0x1162, 0x11ae, 0,
+#undef V5721
+#define V5721 (V + 22006)
+ 0x1108, 0x1162, 0x11af, 0,
+#undef V5722
+#define V5722 (V + 22010)
+ 0x1108, 0x1162, 0x11b0, 0,
+#undef V5723
+#define V5723 (V + 22014)
+ 0x1108, 0x1162, 0x11b1, 0,
+#undef V5724
+#define V5724 (V + 22018)
+ 0x1108, 0x1162, 0x11b2, 0,
+#undef V5725
+#define V5725 (V + 22022)
+ 0x1108, 0x1162, 0x11b3, 0,
+#undef V5726
+#define V5726 (V + 22026)
+ 0x1108, 0x1162, 0x11b4, 0,
+#undef V5727
+#define V5727 (V + 22030)
+ 0x1108, 0x1162, 0x11b5, 0,
+#undef V5728
+#define V5728 (V + 22034)
+ 0x1108, 0x1162, 0x11b6, 0,
+#undef V5729
+#define V5729 (V + 22038)
+ 0x1108, 0x1162, 0x11b7, 0,
+#undef V5730
+#define V5730 (V + 22042)
+ 0x1108, 0x1162, 0x11b8, 0,
+#undef V5731
+#define V5731 (V + 22046)
+ 0x1108, 0x1162, 0x11b9, 0,
+#undef V5732
+#define V5732 (V + 22050)
+ 0x1108, 0x1162, 0x11ba, 0,
+#undef V5733
+#define V5733 (V + 22054)
+ 0x1108, 0x1162, 0x11bb, 0,
+#undef V5734
+#define V5734 (V + 22058)
+ 0x1108, 0x1162, 0x11bc, 0,
+#undef V5735
+#define V5735 (V + 22062)
+ 0x1108, 0x1162, 0x11bd, 0,
+#undef V5736
+#define V5736 (V + 22066)
+ 0x1108, 0x1162, 0x11be, 0,
+#undef V5737
+#define V5737 (V + 22070)
+ 0x1108, 0x1162, 0x11bf, 0,
+#undef V5738
+#define V5738 (V + 22074)
+ 0x1108, 0x1162, 0x11c0, 0,
+#undef V5739
+#define V5739 (V + 22078)
+ 0x1108, 0x1162, 0x11c1, 0,
+#undef V5740
+#define V5740 (V + 22082)
+ 0x1108, 0x1162, 0x11c2, 0,
+#undef V5741
+#define V5741 (V + 22086)
+ 0x1108, 0x1163, 0,
+#undef V5742
+#define V5742 (V + 22089)
+ 0x1108, 0x1163, 0x11a8, 0,
+#undef V5743
+#define V5743 (V + 22093)
+ 0x1108, 0x1163, 0x11a9, 0,
+#undef V5744
+#define V5744 (V + 22097)
+ 0x1108, 0x1163, 0x11aa, 0,
+#undef V5745
+#define V5745 (V + 22101)
+ 0x1108, 0x1163, 0x11ab, 0,
+#undef V5746
+#define V5746 (V + 22105)
+ 0x1108, 0x1163, 0x11ac, 0,
+#undef V5747
+#define V5747 (V + 22109)
+ 0x1108, 0x1163, 0x11ad, 0,
+#undef V5748
+#define V5748 (V + 22113)
+ 0x1108, 0x1163, 0x11ae, 0,
+#undef V5749
+#define V5749 (V + 22117)
+ 0x1108, 0x1163, 0x11af, 0,
+#undef V5750
+#define V5750 (V + 22121)
+ 0x1108, 0x1163, 0x11b0, 0,
+#undef V5751
+#define V5751 (V + 22125)
+ 0x1108, 0x1163, 0x11b1, 0,
+#undef V5752
+#define V5752 (V + 22129)
+ 0x1108, 0x1163, 0x11b2, 0,
+#undef V5753
+#define V5753 (V + 22133)
+ 0x1108, 0x1163, 0x11b3, 0,
+#undef V5754
+#define V5754 (V + 22137)
+ 0x1108, 0x1163, 0x11b4, 0,
+#undef V5755
+#define V5755 (V + 22141)
+ 0x1108, 0x1163, 0x11b5, 0,
+#undef V5756
+#define V5756 (V + 22145)
+ 0x1108, 0x1163, 0x11b6, 0,
+#undef V5757
+#define V5757 (V + 22149)
+ 0x1108, 0x1163, 0x11b7, 0,
+#undef V5758
+#define V5758 (V + 22153)
+ 0x1108, 0x1163, 0x11b8, 0,
+#undef V5759
+#define V5759 (V + 22157)
+ 0x1108, 0x1163, 0x11b9, 0,
+#undef V5760
+#define V5760 (V + 22161)
+ 0x1108, 0x1163, 0x11ba, 0,
+#undef V5761
+#define V5761 (V + 22165)
+ 0x1108, 0x1163, 0x11bb, 0,
+#undef V5762
+#define V5762 (V + 22169)
+ 0x1108, 0x1163, 0x11bc, 0,
+#undef V5763
+#define V5763 (V + 22173)
+ 0x1108, 0x1163, 0x11bd, 0,
+#undef V5764
+#define V5764 (V + 22177)
+ 0x1108, 0x1163, 0x11be, 0,
+#undef V5765
+#define V5765 (V + 22181)
+ 0x1108, 0x1163, 0x11bf, 0,
+#undef V5766
+#define V5766 (V + 22185)
+ 0x1108, 0x1163, 0x11c0, 0,
+#undef V5767
+#define V5767 (V + 22189)
+ 0x1108, 0x1163, 0x11c1, 0,
+#undef V5768
+#define V5768 (V + 22193)
+ 0x1108, 0x1163, 0x11c2, 0,
+#undef V5769
+#define V5769 (V + 22197)
+ 0x1108, 0x1164, 0,
+#undef V5770
+#define V5770 (V + 22200)
+ 0x1108, 0x1164, 0x11a8, 0,
+#undef V5771
+#define V5771 (V + 22204)
+ 0x1108, 0x1164, 0x11a9, 0,
+#undef V5772
+#define V5772 (V + 22208)
+ 0x1108, 0x1164, 0x11aa, 0,
+#undef V5773
+#define V5773 (V + 22212)
+ 0x1108, 0x1164, 0x11ab, 0,
+#undef V5774
+#define V5774 (V + 22216)
+ 0x1108, 0x1164, 0x11ac, 0,
+#undef V5775
+#define V5775 (V + 22220)
+ 0x1108, 0x1164, 0x11ad, 0,
+#undef V5776
+#define V5776 (V + 22224)
+ 0x1108, 0x1164, 0x11ae, 0,
+#undef V5777
+#define V5777 (V + 22228)
+ 0x1108, 0x1164, 0x11af, 0,
+#undef V5778
+#define V5778 (V + 22232)
+ 0x1108, 0x1164, 0x11b0, 0,
+#undef V5779
+#define V5779 (V + 22236)
+ 0x1108, 0x1164, 0x11b1, 0,
+#undef V5780
+#define V5780 (V + 22240)
+ 0x1108, 0x1164, 0x11b2, 0,
+#undef V5781
+#define V5781 (V + 22244)
+ 0x1108, 0x1164, 0x11b3, 0,
+#undef V5782
+#define V5782 (V + 22248)
+ 0x1108, 0x1164, 0x11b4, 0,
+#undef V5783
+#define V5783 (V + 22252)
+ 0x1108, 0x1164, 0x11b5, 0,
+#undef V5784
+#define V5784 (V + 22256)
+ 0x1108, 0x1164, 0x11b6, 0,
+#undef V5785
+#define V5785 (V + 22260)
+ 0x1108, 0x1164, 0x11b7, 0,
+#undef V5786
+#define V5786 (V + 22264)
+ 0x1108, 0x1164, 0x11b8, 0,
+#undef V5787
+#define V5787 (V + 22268)
+ 0x1108, 0x1164, 0x11b9, 0,
+#undef V5788
+#define V5788 (V + 22272)
+ 0x1108, 0x1164, 0x11ba, 0,
+#undef V5789
+#define V5789 (V + 22276)
+ 0x1108, 0x1164, 0x11bb, 0,
+#undef V5790
+#define V5790 (V + 22280)
+ 0x1108, 0x1164, 0x11bc, 0,
+#undef V5791
+#define V5791 (V + 22284)
+ 0x1108, 0x1164, 0x11bd, 0,
+#undef V5792
+#define V5792 (V + 22288)
+ 0x1108, 0x1164, 0x11be, 0,
+#undef V5793
+#define V5793 (V + 22292)
+ 0x1108, 0x1164, 0x11bf, 0,
+#undef V5794
+#define V5794 (V + 22296)
+ 0x1108, 0x1164, 0x11c0, 0,
+#undef V5795
+#define V5795 (V + 22300)
+ 0x1108, 0x1164, 0x11c1, 0,
+#undef V5796
+#define V5796 (V + 22304)
+ 0x1108, 0x1164, 0x11c2, 0,
+#undef V5797
+#define V5797 (V + 22308)
+ 0x1108, 0x1165, 0,
+#undef V5798
+#define V5798 (V + 22311)
+ 0x1108, 0x1165, 0x11a8, 0,
+#undef V5799
+#define V5799 (V + 22315)
+ 0x1108, 0x1165, 0x11a9, 0,
+#undef V5800
+#define V5800 (V + 22319)
+ 0x1108, 0x1165, 0x11aa, 0,
+#undef V5801
+#define V5801 (V + 22323)
+ 0x1108, 0x1165, 0x11ab, 0,
+#undef V5802
+#define V5802 (V + 22327)
+ 0x1108, 0x1165, 0x11ac, 0,
+#undef V5803
+#define V5803 (V + 22331)
+ 0x1108, 0x1165, 0x11ad, 0,
+#undef V5804
+#define V5804 (V + 22335)
+ 0x1108, 0x1165, 0x11ae, 0,
+#undef V5805
+#define V5805 (V + 22339)
+ 0x1108, 0x1165, 0x11af, 0,
+#undef V5806
+#define V5806 (V + 22343)
+ 0x1108, 0x1165, 0x11b0, 0,
+#undef V5807
+#define V5807 (V + 22347)
+ 0x1108, 0x1165, 0x11b1, 0,
+#undef V5808
+#define V5808 (V + 22351)
+ 0x1108, 0x1165, 0x11b2, 0,
+#undef V5809
+#define V5809 (V + 22355)
+ 0x1108, 0x1165, 0x11b3, 0,
+#undef V5810
+#define V5810 (V + 22359)
+ 0x1108, 0x1165, 0x11b4, 0,
+#undef V5811
+#define V5811 (V + 22363)
+ 0x1108, 0x1165, 0x11b5, 0,
+#undef V5812
+#define V5812 (V + 22367)
+ 0x1108, 0x1165, 0x11b6, 0,
+#undef V5813
+#define V5813 (V + 22371)
+ 0x1108, 0x1165, 0x11b7, 0,
+#undef V5814
+#define V5814 (V + 22375)
+ 0x1108, 0x1165, 0x11b8, 0,
+#undef V5815
+#define V5815 (V + 22379)
+ 0x1108, 0x1165, 0x11b9, 0,
+#undef V5816
+#define V5816 (V + 22383)
+ 0x1108, 0x1165, 0x11ba, 0,
+#undef V5817
+#define V5817 (V + 22387)
+ 0x1108, 0x1165, 0x11bb, 0,
+#undef V5818
+#define V5818 (V + 22391)
+ 0x1108, 0x1165, 0x11bc, 0,
+#undef V5819
+#define V5819 (V + 22395)
+ 0x1108, 0x1165, 0x11bd, 0,
+#undef V5820
+#define V5820 (V + 22399)
+ 0x1108, 0x1165, 0x11be, 0,
+#undef V5821
+#define V5821 (V + 22403)
+ 0x1108, 0x1165, 0x11bf, 0,
+#undef V5822
+#define V5822 (V + 22407)
+ 0x1108, 0x1165, 0x11c0, 0,
+#undef V5823
+#define V5823 (V + 22411)
+ 0x1108, 0x1165, 0x11c1, 0,
+#undef V5824
+#define V5824 (V + 22415)
+ 0x1108, 0x1165, 0x11c2, 0,
+#undef V5825
+#define V5825 (V + 22419)
+ 0x1108, 0x1166, 0,
+#undef V5826
+#define V5826 (V + 22422)
+ 0x1108, 0x1166, 0x11a8, 0,
+#undef V5827
+#define V5827 (V + 22426)
+ 0x1108, 0x1166, 0x11a9, 0,
+#undef V5828
+#define V5828 (V + 22430)
+ 0x1108, 0x1166, 0x11aa, 0,
+#undef V5829
+#define V5829 (V + 22434)
+ 0x1108, 0x1166, 0x11ab, 0,
+#undef V5830
+#define V5830 (V + 22438)
+ 0x1108, 0x1166, 0x11ac, 0,
+#undef V5831
+#define V5831 (V + 22442)
+ 0x1108, 0x1166, 0x11ad, 0,
+#undef V5832
+#define V5832 (V + 22446)
+ 0x1108, 0x1166, 0x11ae, 0,
+#undef V5833
+#define V5833 (V + 22450)
+ 0x1108, 0x1166, 0x11af, 0,
+#undef V5834
+#define V5834 (V + 22454)
+ 0x1108, 0x1166, 0x11b0, 0,
+#undef V5835
+#define V5835 (V + 22458)
+ 0x1108, 0x1166, 0x11b1, 0,
+#undef V5836
+#define V5836 (V + 22462)
+ 0x1108, 0x1166, 0x11b2, 0,
+#undef V5837
+#define V5837 (V + 22466)
+ 0x1108, 0x1166, 0x11b3, 0,
+#undef V5838
+#define V5838 (V + 22470)
+ 0x1108, 0x1166, 0x11b4, 0,
+#undef V5839
+#define V5839 (V + 22474)
+ 0x1108, 0x1166, 0x11b5, 0,
+#undef V5840
+#define V5840 (V + 22478)
+ 0x1108, 0x1166, 0x11b6, 0,
+#undef V5841
+#define V5841 (V + 22482)
+ 0x1108, 0x1166, 0x11b7, 0,
+#undef V5842
+#define V5842 (V + 22486)
+ 0x1108, 0x1166, 0x11b8, 0,
+#undef V5843
+#define V5843 (V + 22490)
+ 0x1108, 0x1166, 0x11b9, 0,
+#undef V5844
+#define V5844 (V + 22494)
+ 0x1108, 0x1166, 0x11ba, 0,
+#undef V5845
+#define V5845 (V + 22498)
+ 0x1108, 0x1166, 0x11bb, 0,
+#undef V5846
+#define V5846 (V + 22502)
+ 0x1108, 0x1166, 0x11bc, 0,
+#undef V5847
+#define V5847 (V + 22506)
+ 0x1108, 0x1166, 0x11bd, 0,
+#undef V5848
+#define V5848 (V + 22510)
+ 0x1108, 0x1166, 0x11be, 0,
+#undef V5849
+#define V5849 (V + 22514)
+ 0x1108, 0x1166, 0x11bf, 0,
+#undef V5850
+#define V5850 (V + 22518)
+ 0x1108, 0x1166, 0x11c0, 0,
+#undef V5851
+#define V5851 (V + 22522)
+ 0x1108, 0x1166, 0x11c1, 0,
+#undef V5852
+#define V5852 (V + 22526)
+ 0x1108, 0x1166, 0x11c2, 0,
+#undef V5853
+#define V5853 (V + 22530)
+ 0x1108, 0x1167, 0,
+#undef V5854
+#define V5854 (V + 22533)
+ 0x1108, 0x1167, 0x11a8, 0,
+#undef V5855
+#define V5855 (V + 22537)
+ 0x1108, 0x1167, 0x11a9, 0,
+#undef V5856
+#define V5856 (V + 22541)
+ 0x1108, 0x1167, 0x11aa, 0,
+#undef V5857
+#define V5857 (V + 22545)
+ 0x1108, 0x1167, 0x11ab, 0,
+#undef V5858
+#define V5858 (V + 22549)
+ 0x1108, 0x1167, 0x11ac, 0,
+#undef V5859
+#define V5859 (V + 22553)
+ 0x1108, 0x1167, 0x11ad, 0,
+#undef V5860
+#define V5860 (V + 22557)
+ 0x1108, 0x1167, 0x11ae, 0,
+#undef V5861
+#define V5861 (V + 22561)
+ 0x1108, 0x1167, 0x11af, 0,
+#undef V5862
+#define V5862 (V + 22565)
+ 0x1108, 0x1167, 0x11b0, 0,
+#undef V5863
+#define V5863 (V + 22569)
+ 0x1108, 0x1167, 0x11b1, 0,
+#undef V5864
+#define V5864 (V + 22573)
+ 0x1108, 0x1167, 0x11b2, 0,
+#undef V5865
+#define V5865 (V + 22577)
+ 0x1108, 0x1167, 0x11b3, 0,
+#undef V5866
+#define V5866 (V + 22581)
+ 0x1108, 0x1167, 0x11b4, 0,
+#undef V5867
+#define V5867 (V + 22585)
+ 0x1108, 0x1167, 0x11b5, 0,
+#undef V5868
+#define V5868 (V + 22589)
+ 0x1108, 0x1167, 0x11b6, 0,
+#undef V5869
+#define V5869 (V + 22593)
+ 0x1108, 0x1167, 0x11b7, 0,
+#undef V5870
+#define V5870 (V + 22597)
+ 0x1108, 0x1167, 0x11b8, 0,
+#undef V5871
+#define V5871 (V + 22601)
+ 0x1108, 0x1167, 0x11b9, 0,
+#undef V5872
+#define V5872 (V + 22605)
+ 0x1108, 0x1167, 0x11ba, 0,
+#undef V5873
+#define V5873 (V + 22609)
+ 0x1108, 0x1167, 0x11bb, 0,
+#undef V5874
+#define V5874 (V + 22613)
+ 0x1108, 0x1167, 0x11bc, 0,
+#undef V5875
+#define V5875 (V + 22617)
+ 0x1108, 0x1167, 0x11bd, 0,
+#undef V5876
+#define V5876 (V + 22621)
+ 0x1108, 0x1167, 0x11be, 0,
+#undef V5877
+#define V5877 (V + 22625)
+ 0x1108, 0x1167, 0x11bf, 0,
+#undef V5878
+#define V5878 (V + 22629)
+ 0x1108, 0x1167, 0x11c0, 0,
+#undef V5879
+#define V5879 (V + 22633)
+ 0x1108, 0x1167, 0x11c1, 0,
+#undef V5880
+#define V5880 (V + 22637)
+ 0x1108, 0x1167, 0x11c2, 0,
+#undef V5881
+#define V5881 (V + 22641)
+ 0x1108, 0x1168, 0,
+#undef V5882
+#define V5882 (V + 22644)
+ 0x1108, 0x1168, 0x11a8, 0,
+#undef V5883
+#define V5883 (V + 22648)
+ 0x1108, 0x1168, 0x11a9, 0,
+#undef V5884
+#define V5884 (V + 22652)
+ 0x1108, 0x1168, 0x11aa, 0,
+#undef V5885
+#define V5885 (V + 22656)
+ 0x1108, 0x1168, 0x11ab, 0,
+#undef V5886
+#define V5886 (V + 22660)
+ 0x1108, 0x1168, 0x11ac, 0,
+#undef V5887
+#define V5887 (V + 22664)
+ 0x1108, 0x1168, 0x11ad, 0,
+#undef V5888
+#define V5888 (V + 22668)
+ 0x1108, 0x1168, 0x11ae, 0,
+#undef V5889
+#define V5889 (V + 22672)
+ 0x1108, 0x1168, 0x11af, 0,
+#undef V5890
+#define V5890 (V + 22676)
+ 0x1108, 0x1168, 0x11b0, 0,
+#undef V5891
+#define V5891 (V + 22680)
+ 0x1108, 0x1168, 0x11b1, 0,
+#undef V5892
+#define V5892 (V + 22684)
+ 0x1108, 0x1168, 0x11b2, 0,
+#undef V5893
+#define V5893 (V + 22688)
+ 0x1108, 0x1168, 0x11b3, 0,
+#undef V5894
+#define V5894 (V + 22692)
+ 0x1108, 0x1168, 0x11b4, 0,
+#undef V5895
+#define V5895 (V + 22696)
+ 0x1108, 0x1168, 0x11b5, 0,
+#undef V5896
+#define V5896 (V + 22700)
+ 0x1108, 0x1168, 0x11b6, 0,
+#undef V5897
+#define V5897 (V + 22704)
+ 0x1108, 0x1168, 0x11b7, 0,
+#undef V5898
+#define V5898 (V + 22708)
+ 0x1108, 0x1168, 0x11b8, 0,
+#undef V5899
+#define V5899 (V + 22712)
+ 0x1108, 0x1168, 0x11b9, 0,
+#undef V5900
+#define V5900 (V + 22716)
+ 0x1108, 0x1168, 0x11ba, 0,
+#undef V5901
+#define V5901 (V + 22720)
+ 0x1108, 0x1168, 0x11bb, 0,
+#undef V5902
+#define V5902 (V + 22724)
+ 0x1108, 0x1168, 0x11bc, 0,
+#undef V5903
+#define V5903 (V + 22728)
+ 0x1108, 0x1168, 0x11bd, 0,
+#undef V5904
+#define V5904 (V + 22732)
+ 0x1108, 0x1168, 0x11be, 0,
+#undef V5905
+#define V5905 (V + 22736)
+ 0x1108, 0x1168, 0x11bf, 0,
+#undef V5906
+#define V5906 (V + 22740)
+ 0x1108, 0x1168, 0x11c0, 0,
+#undef V5907
+#define V5907 (V + 22744)
+ 0x1108, 0x1168, 0x11c1, 0,
+#undef V5908
+#define V5908 (V + 22748)
+ 0x1108, 0x1168, 0x11c2, 0,
+#undef V5909
+#define V5909 (V + 22752)
+ 0x1108, 0x1169, 0,
+#undef V5910
+#define V5910 (V + 22755)
+ 0x1108, 0x1169, 0x11a8, 0,
+#undef V5911
+#define V5911 (V + 22759)
+ 0x1108, 0x1169, 0x11a9, 0,
+#undef V5912
+#define V5912 (V + 22763)
+ 0x1108, 0x1169, 0x11aa, 0,
+#undef V5913
+#define V5913 (V + 22767)
+ 0x1108, 0x1169, 0x11ab, 0,
+#undef V5914
+#define V5914 (V + 22771)
+ 0x1108, 0x1169, 0x11ac, 0,
+#undef V5915
+#define V5915 (V + 22775)
+ 0x1108, 0x1169, 0x11ad, 0,
+#undef V5916
+#define V5916 (V + 22779)
+ 0x1108, 0x1169, 0x11ae, 0,
+#undef V5917
+#define V5917 (V + 22783)
+ 0x1108, 0x1169, 0x11af, 0,
+#undef V5918
+#define V5918 (V + 22787)
+ 0x1108, 0x1169, 0x11b0, 0,
+#undef V5919
+#define V5919 (V + 22791)
+ 0x1108, 0x1169, 0x11b1, 0,
+#undef V5920
+#define V5920 (V + 22795)
+ 0x1108, 0x1169, 0x11b2, 0,
+#undef V5921
+#define V5921 (V + 22799)
+ 0x1108, 0x1169, 0x11b3, 0,
+#undef V5922
+#define V5922 (V + 22803)
+ 0x1108, 0x1169, 0x11b4, 0,
+#undef V5923
+#define V5923 (V + 22807)
+ 0x1108, 0x1169, 0x11b5, 0,
+#undef V5924
+#define V5924 (V + 22811)
+ 0x1108, 0x1169, 0x11b6, 0,
+#undef V5925
+#define V5925 (V + 22815)
+ 0x1108, 0x1169, 0x11b7, 0,
+#undef V5926
+#define V5926 (V + 22819)
+ 0x1108, 0x1169, 0x11b8, 0,
+#undef V5927
+#define V5927 (V + 22823)
+ 0x1108, 0x1169, 0x11b9, 0,
+#undef V5928
+#define V5928 (V + 22827)
+ 0x1108, 0x1169, 0x11ba, 0,
+#undef V5929
+#define V5929 (V + 22831)
+ 0x1108, 0x1169, 0x11bb, 0,
+#undef V5930
+#define V5930 (V + 22835)
+ 0x1108, 0x1169, 0x11bc, 0,
+#undef V5931
+#define V5931 (V + 22839)
+ 0x1108, 0x1169, 0x11bd, 0,
+#undef V5932
+#define V5932 (V + 22843)
+ 0x1108, 0x1169, 0x11be, 0,
+#undef V5933
+#define V5933 (V + 22847)
+ 0x1108, 0x1169, 0x11bf, 0,
+#undef V5934
+#define V5934 (V + 22851)
+ 0x1108, 0x1169, 0x11c0, 0,
+#undef V5935
+#define V5935 (V + 22855)
+ 0x1108, 0x1169, 0x11c1, 0,
+#undef V5936
+#define V5936 (V + 22859)
+ 0x1108, 0x1169, 0x11c2, 0,
+#undef V5937
+#define V5937 (V + 22863)
+ 0x1108, 0x116a, 0,
+#undef V5938
+#define V5938 (V + 22866)
+ 0x1108, 0x116a, 0x11a8, 0,
+#undef V5939
+#define V5939 (V + 22870)
+ 0x1108, 0x116a, 0x11a9, 0,
+#undef V5940
+#define V5940 (V + 22874)
+ 0x1108, 0x116a, 0x11aa, 0,
+#undef V5941
+#define V5941 (V + 22878)
+ 0x1108, 0x116a, 0x11ab, 0,
+#undef V5942
+#define V5942 (V + 22882)
+ 0x1108, 0x116a, 0x11ac, 0,
+#undef V5943
+#define V5943 (V + 22886)
+ 0x1108, 0x116a, 0x11ad, 0,
+#undef V5944
+#define V5944 (V + 22890)
+ 0x1108, 0x116a, 0x11ae, 0,
+#undef V5945
+#define V5945 (V + 22894)
+ 0x1108, 0x116a, 0x11af, 0,
+#undef V5946
+#define V5946 (V + 22898)
+ 0x1108, 0x116a, 0x11b0, 0,
+#undef V5947
+#define V5947 (V + 22902)
+ 0x1108, 0x116a, 0x11b1, 0,
+#undef V5948
+#define V5948 (V + 22906)
+ 0x1108, 0x116a, 0x11b2, 0,
+#undef V5949
+#define V5949 (V + 22910)
+ 0x1108, 0x116a, 0x11b3, 0,
+#undef V5950
+#define V5950 (V + 22914)
+ 0x1108, 0x116a, 0x11b4, 0,
+#undef V5951
+#define V5951 (V + 22918)
+ 0x1108, 0x116a, 0x11b5, 0,
+#undef V5952
+#define V5952 (V + 22922)
+ 0x1108, 0x116a, 0x11b6, 0,
+#undef V5953
+#define V5953 (V + 22926)
+ 0x1108, 0x116a, 0x11b7, 0,
+#undef V5954
+#define V5954 (V + 22930)
+ 0x1108, 0x116a, 0x11b8, 0,
+#undef V5955
+#define V5955 (V + 22934)
+ 0x1108, 0x116a, 0x11b9, 0,
+#undef V5956
+#define V5956 (V + 22938)
+ 0x1108, 0x116a, 0x11ba, 0,
+#undef V5957
+#define V5957 (V + 22942)
+ 0x1108, 0x116a, 0x11bb, 0,
+#undef V5958
+#define V5958 (V + 22946)
+ 0x1108, 0x116a, 0x11bc, 0,
+#undef V5959
+#define V5959 (V + 22950)
+ 0x1108, 0x116a, 0x11bd, 0,
+#undef V5960
+#define V5960 (V + 22954)
+ 0x1108, 0x116a, 0x11be, 0,
+#undef V5961
+#define V5961 (V + 22958)
+ 0x1108, 0x116a, 0x11bf, 0,
+#undef V5962
+#define V5962 (V + 22962)
+ 0x1108, 0x116a, 0x11c0, 0,
+#undef V5963
+#define V5963 (V + 22966)
+ 0x1108, 0x116a, 0x11c1, 0,
+#undef V5964
+#define V5964 (V + 22970)
+ 0x1108, 0x116a, 0x11c2, 0,
+#undef V5965
+#define V5965 (V + 22974)
+ 0x1108, 0x116b, 0,
+#undef V5966
+#define V5966 (V + 22977)
+ 0x1108, 0x116b, 0x11a8, 0,
+#undef V5967
+#define V5967 (V + 22981)
+ 0x1108, 0x116b, 0x11a9, 0,
+#undef V5968
+#define V5968 (V + 22985)
+ 0x1108, 0x116b, 0x11aa, 0,
+#undef V5969
+#define V5969 (V + 22989)
+ 0x1108, 0x116b, 0x11ab, 0,
+#undef V5970
+#define V5970 (V + 22993)
+ 0x1108, 0x116b, 0x11ac, 0,
+#undef V5971
+#define V5971 (V + 22997)
+ 0x1108, 0x116b, 0x11ad, 0,
+#undef V5972
+#define V5972 (V + 23001)
+ 0x1108, 0x116b, 0x11ae, 0,
+#undef V5973
+#define V5973 (V + 23005)
+ 0x1108, 0x116b, 0x11af, 0,
+#undef V5974
+#define V5974 (V + 23009)
+ 0x1108, 0x116b, 0x11b0, 0,
+#undef V5975
+#define V5975 (V + 23013)
+ 0x1108, 0x116b, 0x11b1, 0,
+#undef V5976
+#define V5976 (V + 23017)
+ 0x1108, 0x116b, 0x11b2, 0,
+#undef V5977
+#define V5977 (V + 23021)
+ 0x1108, 0x116b, 0x11b3, 0,
+#undef V5978
+#define V5978 (V + 23025)
+ 0x1108, 0x116b, 0x11b4, 0,
+#undef V5979
+#define V5979 (V + 23029)
+ 0x1108, 0x116b, 0x11b5, 0,
+#undef V5980
+#define V5980 (V + 23033)
+ 0x1108, 0x116b, 0x11b6, 0,
+#undef V5981
+#define V5981 (V + 23037)
+ 0x1108, 0x116b, 0x11b7, 0,
+#undef V5982
+#define V5982 (V + 23041)
+ 0x1108, 0x116b, 0x11b8, 0,
+#undef V5983
+#define V5983 (V + 23045)
+ 0x1108, 0x116b, 0x11b9, 0,
+#undef V5984
+#define V5984 (V + 23049)
+ 0x1108, 0x116b, 0x11ba, 0,
+#undef V5985
+#define V5985 (V + 23053)
+ 0x1108, 0x116b, 0x11bb, 0,
+#undef V5986
+#define V5986 (V + 23057)
+ 0x1108, 0x116b, 0x11bc, 0,
+#undef V5987
+#define V5987 (V + 23061)
+ 0x1108, 0x116b, 0x11bd, 0,
+#undef V5988
+#define V5988 (V + 23065)
+ 0x1108, 0x116b, 0x11be, 0,
+#undef V5989
+#define V5989 (V + 23069)
+ 0x1108, 0x116b, 0x11bf, 0,
+#undef V5990
+#define V5990 (V + 23073)
+ 0x1108, 0x116b, 0x11c0, 0,
+#undef V5991
+#define V5991 (V + 23077)
+ 0x1108, 0x116b, 0x11c1, 0,
+#undef V5992
+#define V5992 (V + 23081)
+ 0x1108, 0x116b, 0x11c2, 0,
+#undef V5993
+#define V5993 (V + 23085)
+ 0x1108, 0x116c, 0,
+#undef V5994
+#define V5994 (V + 23088)
+ 0x1108, 0x116c, 0x11a8, 0,
+#undef V5995
+#define V5995 (V + 23092)
+ 0x1108, 0x116c, 0x11a9, 0,
+#undef V5996
+#define V5996 (V + 23096)
+ 0x1108, 0x116c, 0x11aa, 0,
+#undef V5997
+#define V5997 (V + 23100)
+ 0x1108, 0x116c, 0x11ab, 0,
+#undef V5998
+#define V5998 (V + 23104)
+ 0x1108, 0x116c, 0x11ac, 0,
+#undef V5999
+#define V5999 (V + 23108)
+ 0x1108, 0x116c, 0x11ad, 0,
+#undef V6000
+#define V6000 (V + 23112)
+ 0x1108, 0x116c, 0x11ae, 0,
+#undef V6001
+#define V6001 (V + 23116)
+ 0x1108, 0x116c, 0x11af, 0,
+#undef V6002
+#define V6002 (V + 23120)
+ 0x1108, 0x116c, 0x11b0, 0,
+#undef V6003
+#define V6003 (V + 23124)
+ 0x1108, 0x116c, 0x11b1, 0,
+#undef V6004
+#define V6004 (V + 23128)
+ 0x1108, 0x116c, 0x11b2, 0,
+#undef V6005
+#define V6005 (V + 23132)
+ 0x1108, 0x116c, 0x11b3, 0,
+#undef V6006
+#define V6006 (V + 23136)
+ 0x1108, 0x116c, 0x11b4, 0,
+#undef V6007
+#define V6007 (V + 23140)
+ 0x1108, 0x116c, 0x11b5, 0,
+#undef V6008
+#define V6008 (V + 23144)
+ 0x1108, 0x116c, 0x11b6, 0,
+#undef V6009
+#define V6009 (V + 23148)
+ 0x1108, 0x116c, 0x11b7, 0,
+#undef V6010
+#define V6010 (V + 23152)
+ 0x1108, 0x116c, 0x11b8, 0,
+#undef V6011
+#define V6011 (V + 23156)
+ 0x1108, 0x116c, 0x11b9, 0,
+#undef V6012
+#define V6012 (V + 23160)
+ 0x1108, 0x116c, 0x11ba, 0,
+#undef V6013
+#define V6013 (V + 23164)
+ 0x1108, 0x116c, 0x11bb, 0,
+#undef V6014
+#define V6014 (V + 23168)
+ 0x1108, 0x116c, 0x11bc, 0,
+#undef V6015
+#define V6015 (V + 23172)
+ 0x1108, 0x116c, 0x11bd, 0,
+#undef V6016
+#define V6016 (V + 23176)
+ 0x1108, 0x116c, 0x11be, 0,
+#undef V6017
+#define V6017 (V + 23180)
+ 0x1108, 0x116c, 0x11bf, 0,
+#undef V6018
+#define V6018 (V + 23184)
+ 0x1108, 0x116c, 0x11c0, 0,
+#undef V6019
+#define V6019 (V + 23188)
+ 0x1108, 0x116c, 0x11c1, 0,
+#undef V6020
+#define V6020 (V + 23192)
+ 0x1108, 0x116c, 0x11c2, 0,
+#undef V6021
+#define V6021 (V + 23196)
+ 0x1108, 0x116d, 0,
+#undef V6022
+#define V6022 (V + 23199)
+ 0x1108, 0x116d, 0x11a8, 0,
+#undef V6023
+#define V6023 (V + 23203)
+ 0x1108, 0x116d, 0x11a9, 0,
+#undef V6024
+#define V6024 (V + 23207)
+ 0x1108, 0x116d, 0x11aa, 0,
+#undef V6025
+#define V6025 (V + 23211)
+ 0x1108, 0x116d, 0x11ab, 0,
+#undef V6026
+#define V6026 (V + 23215)
+ 0x1108, 0x116d, 0x11ac, 0,
+#undef V6027
+#define V6027 (V + 23219)
+ 0x1108, 0x116d, 0x11ad, 0,
+#undef V6028
+#define V6028 (V + 23223)
+ 0x1108, 0x116d, 0x11ae, 0,
+#undef V6029
+#define V6029 (V + 23227)
+ 0x1108, 0x116d, 0x11af, 0,
+#undef V6030
+#define V6030 (V + 23231)
+ 0x1108, 0x116d, 0x11b0, 0,
+#undef V6031
+#define V6031 (V + 23235)
+ 0x1108, 0x116d, 0x11b1, 0,
+#undef V6032
+#define V6032 (V + 23239)
+ 0x1108, 0x116d, 0x11b2, 0,
+#undef V6033
+#define V6033 (V + 23243)
+ 0x1108, 0x116d, 0x11b3, 0,
+#undef V6034
+#define V6034 (V + 23247)
+ 0x1108, 0x116d, 0x11b4, 0,
+#undef V6035
+#define V6035 (V + 23251)
+ 0x1108, 0x116d, 0x11b5, 0,
+#undef V6036
+#define V6036 (V + 23255)
+ 0x1108, 0x116d, 0x11b6, 0,
+#undef V6037
+#define V6037 (V + 23259)
+ 0x1108, 0x116d, 0x11b7, 0,
+#undef V6038
+#define V6038 (V + 23263)
+ 0x1108, 0x116d, 0x11b8, 0,
+#undef V6039
+#define V6039 (V + 23267)
+ 0x1108, 0x116d, 0x11b9, 0,
+#undef V6040
+#define V6040 (V + 23271)
+ 0x1108, 0x116d, 0x11ba, 0,
+#undef V6041
+#define V6041 (V + 23275)
+ 0x1108, 0x116d, 0x11bb, 0,
+#undef V6042
+#define V6042 (V + 23279)
+ 0x1108, 0x116d, 0x11bc, 0,
+#undef V6043
+#define V6043 (V + 23283)
+ 0x1108, 0x116d, 0x11bd, 0,
+#undef V6044
+#define V6044 (V + 23287)
+ 0x1108, 0x116d, 0x11be, 0,
+#undef V6045
+#define V6045 (V + 23291)
+ 0x1108, 0x116d, 0x11bf, 0,
+#undef V6046
+#define V6046 (V + 23295)
+ 0x1108, 0x116d, 0x11c0, 0,
+#undef V6047
+#define V6047 (V + 23299)
+ 0x1108, 0x116d, 0x11c1, 0,
+#undef V6048
+#define V6048 (V + 23303)
+ 0x1108, 0x116d, 0x11c2, 0,
+#undef V6049
+#define V6049 (V + 23307)
+ 0x1108, 0x116e, 0,
+#undef V6050
+#define V6050 (V + 23310)
+ 0x1108, 0x116e, 0x11a8, 0,
+#undef V6051
+#define V6051 (V + 23314)
+ 0x1108, 0x116e, 0x11a9, 0,
+#undef V6052
+#define V6052 (V + 23318)
+ 0x1108, 0x116e, 0x11aa, 0,
+#undef V6053
+#define V6053 (V + 23322)
+ 0x1108, 0x116e, 0x11ab, 0,
+#undef V6054
+#define V6054 (V + 23326)
+ 0x1108, 0x116e, 0x11ac, 0,
+#undef V6055
+#define V6055 (V + 23330)
+ 0x1108, 0x116e, 0x11ad, 0,
+#undef V6056
+#define V6056 (V + 23334)
+ 0x1108, 0x116e, 0x11ae, 0,
+#undef V6057
+#define V6057 (V + 23338)
+ 0x1108, 0x116e, 0x11af, 0,
+#undef V6058
+#define V6058 (V + 23342)
+ 0x1108, 0x116e, 0x11b0, 0,
+#undef V6059
+#define V6059 (V + 23346)
+ 0x1108, 0x116e, 0x11b1, 0,
+#undef V6060
+#define V6060 (V + 23350)
+ 0x1108, 0x116e, 0x11b2, 0,
+#undef V6061
+#define V6061 (V + 23354)
+ 0x1108, 0x116e, 0x11b3, 0,
+#undef V6062
+#define V6062 (V + 23358)
+ 0x1108, 0x116e, 0x11b4, 0,
+#undef V6063
+#define V6063 (V + 23362)
+ 0x1108, 0x116e, 0x11b5, 0,
+#undef V6064
+#define V6064 (V + 23366)
+ 0x1108, 0x116e, 0x11b6, 0,
+#undef V6065
+#define V6065 (V + 23370)
+ 0x1108, 0x116e, 0x11b7, 0,
+#undef V6066
+#define V6066 (V + 23374)
+ 0x1108, 0x116e, 0x11b8, 0,
+#undef V6067
+#define V6067 (V + 23378)
+ 0x1108, 0x116e, 0x11b9, 0,
+#undef V6068
+#define V6068 (V + 23382)
+ 0x1108, 0x116e, 0x11ba, 0,
+#undef V6069
+#define V6069 (V + 23386)
+ 0x1108, 0x116e, 0x11bb, 0,
+#undef V6070
+#define V6070 (V + 23390)
+ 0x1108, 0x116e, 0x11bc, 0,
+#undef V6071
+#define V6071 (V + 23394)
+ 0x1108, 0x116e, 0x11bd, 0,
+#undef V6072
+#define V6072 (V + 23398)
+ 0x1108, 0x116e, 0x11be, 0,
+#undef V6073
+#define V6073 (V + 23402)
+ 0x1108, 0x116e, 0x11bf, 0,
+#undef V6074
+#define V6074 (V + 23406)
+ 0x1108, 0x116e, 0x11c0, 0,
+#undef V6075
+#define V6075 (V + 23410)
+ 0x1108, 0x116e, 0x11c1, 0,
+#undef V6076
+#define V6076 (V + 23414)
+ 0x1108, 0x116e, 0x11c2, 0,
+#undef V6077
+#define V6077 (V + 23418)
+ 0x1108, 0x116f, 0,
+#undef V6078
+#define V6078 (V + 23421)
+ 0x1108, 0x116f, 0x11a8, 0,
+#undef V6079
+#define V6079 (V + 23425)
+ 0x1108, 0x116f, 0x11a9, 0,
+#undef V6080
+#define V6080 (V + 23429)
+ 0x1108, 0x116f, 0x11aa, 0,
+#undef V6081
+#define V6081 (V + 23433)
+ 0x1108, 0x116f, 0x11ab, 0,
+#undef V6082
+#define V6082 (V + 23437)
+ 0x1108, 0x116f, 0x11ac, 0,
+#undef V6083
+#define V6083 (V + 23441)
+ 0x1108, 0x116f, 0x11ad, 0,
+#undef V6084
+#define V6084 (V + 23445)
+ 0x1108, 0x116f, 0x11ae, 0,
+#undef V6085
+#define V6085 (V + 23449)
+ 0x1108, 0x116f, 0x11af, 0,
+#undef V6086
+#define V6086 (V + 23453)
+ 0x1108, 0x116f, 0x11b0, 0,
+#undef V6087
+#define V6087 (V + 23457)
+ 0x1108, 0x116f, 0x11b1, 0,
+#undef V6088
+#define V6088 (V + 23461)
+ 0x1108, 0x116f, 0x11b2, 0,
+#undef V6089
+#define V6089 (V + 23465)
+ 0x1108, 0x116f, 0x11b3, 0,
+#undef V6090
+#define V6090 (V + 23469)
+ 0x1108, 0x116f, 0x11b4, 0,
+#undef V6091
+#define V6091 (V + 23473)
+ 0x1108, 0x116f, 0x11b5, 0,
+#undef V6092
+#define V6092 (V + 23477)
+ 0x1108, 0x116f, 0x11b6, 0,
+#undef V6093
+#define V6093 (V + 23481)
+ 0x1108, 0x116f, 0x11b7, 0,
+#undef V6094
+#define V6094 (V + 23485)
+ 0x1108, 0x116f, 0x11b8, 0,
+#undef V6095
+#define V6095 (V + 23489)
+ 0x1108, 0x116f, 0x11b9, 0,
+#undef V6096
+#define V6096 (V + 23493)
+ 0x1108, 0x116f, 0x11ba, 0,
+#undef V6097
+#define V6097 (V + 23497)
+ 0x1108, 0x116f, 0x11bb, 0,
+#undef V6098
+#define V6098 (V + 23501)
+ 0x1108, 0x116f, 0x11bc, 0,
+#undef V6099
+#define V6099 (V + 23505)
+ 0x1108, 0x116f, 0x11bd, 0,
+#undef V6100
+#define V6100 (V + 23509)
+ 0x1108, 0x116f, 0x11be, 0,
+#undef V6101
+#define V6101 (V + 23513)
+ 0x1108, 0x116f, 0x11bf, 0,
+#undef V6102
+#define V6102 (V + 23517)
+ 0x1108, 0x116f, 0x11c0, 0,
+#undef V6103
+#define V6103 (V + 23521)
+ 0x1108, 0x116f, 0x11c1, 0,
+#undef V6104
+#define V6104 (V + 23525)
+ 0x1108, 0x116f, 0x11c2, 0,
+#undef V6105
+#define V6105 (V + 23529)
+ 0x1108, 0x1170, 0,
+#undef V6106
+#define V6106 (V + 23532)
+ 0x1108, 0x1170, 0x11a8, 0,
+#undef V6107
+#define V6107 (V + 23536)
+ 0x1108, 0x1170, 0x11a9, 0,
+#undef V6108
+#define V6108 (V + 23540)
+ 0x1108, 0x1170, 0x11aa, 0,
+#undef V6109
+#define V6109 (V + 23544)
+ 0x1108, 0x1170, 0x11ab, 0,
+#undef V6110
+#define V6110 (V + 23548)
+ 0x1108, 0x1170, 0x11ac, 0,
+#undef V6111
+#define V6111 (V + 23552)
+ 0x1108, 0x1170, 0x11ad, 0,
+#undef V6112
+#define V6112 (V + 23556)
+ 0x1108, 0x1170, 0x11ae, 0,
+#undef V6113
+#define V6113 (V + 23560)
+ 0x1108, 0x1170, 0x11af, 0,
+#undef V6114
+#define V6114 (V + 23564)
+ 0x1108, 0x1170, 0x11b0, 0,
+#undef V6115
+#define V6115 (V + 23568)
+ 0x1108, 0x1170, 0x11b1, 0,
+#undef V6116
+#define V6116 (V + 23572)
+ 0x1108, 0x1170, 0x11b2, 0,
+#undef V6117
+#define V6117 (V + 23576)
+ 0x1108, 0x1170, 0x11b3, 0,
+#undef V6118
+#define V6118 (V + 23580)
+ 0x1108, 0x1170, 0x11b4, 0,
+#undef V6119
+#define V6119 (V + 23584)
+ 0x1108, 0x1170, 0x11b5, 0,
+#undef V6120
+#define V6120 (V + 23588)
+ 0x1108, 0x1170, 0x11b6, 0,
+#undef V6121
+#define V6121 (V + 23592)
+ 0x1108, 0x1170, 0x11b7, 0,
+#undef V6122
+#define V6122 (V + 23596)
+ 0x1108, 0x1170, 0x11b8, 0,
+#undef V6123
+#define V6123 (V + 23600)
+ 0x1108, 0x1170, 0x11b9, 0,
+#undef V6124
+#define V6124 (V + 23604)
+ 0x1108, 0x1170, 0x11ba, 0,
+#undef V6125
+#define V6125 (V + 23608)
+ 0x1108, 0x1170, 0x11bb, 0,
+#undef V6126
+#define V6126 (V + 23612)
+ 0x1108, 0x1170, 0x11bc, 0,
+#undef V6127
+#define V6127 (V + 23616)
+ 0x1108, 0x1170, 0x11bd, 0,
+#undef V6128
+#define V6128 (V + 23620)
+ 0x1108, 0x1170, 0x11be, 0,
+#undef V6129
+#define V6129 (V + 23624)
+ 0x1108, 0x1170, 0x11bf, 0,
+#undef V6130
+#define V6130 (V + 23628)
+ 0x1108, 0x1170, 0x11c0, 0,
+#undef V6131
+#define V6131 (V + 23632)
+ 0x1108, 0x1170, 0x11c1, 0,
+#undef V6132
+#define V6132 (V + 23636)
+ 0x1108, 0x1170, 0x11c2, 0,
+#undef V6133
+#define V6133 (V + 23640)
+ 0x1108, 0x1171, 0,
+#undef V6134
+#define V6134 (V + 23643)
+ 0x1108, 0x1171, 0x11a8, 0,
+#undef V6135
+#define V6135 (V + 23647)
+ 0x1108, 0x1171, 0x11a9, 0,
+#undef V6136
+#define V6136 (V + 23651)
+ 0x1108, 0x1171, 0x11aa, 0,
+#undef V6137
+#define V6137 (V + 23655)
+ 0x1108, 0x1171, 0x11ab, 0,
+#undef V6138
+#define V6138 (V + 23659)
+ 0x1108, 0x1171, 0x11ac, 0,
+#undef V6139
+#define V6139 (V + 23663)
+ 0x1108, 0x1171, 0x11ad, 0,
+#undef V6140
+#define V6140 (V + 23667)
+ 0x1108, 0x1171, 0x11ae, 0,
+#undef V6141
+#define V6141 (V + 23671)
+ 0x1108, 0x1171, 0x11af, 0,
+#undef V6142
+#define V6142 (V + 23675)
+ 0x1108, 0x1171, 0x11b0, 0,
+#undef V6143
+#define V6143 (V + 23679)
+ 0x1108, 0x1171, 0x11b1, 0,
+#undef V6144
+#define V6144 (V + 23683)
+ 0x1108, 0x1171, 0x11b2, 0,
+#undef V6145
+#define V6145 (V + 23687)
+ 0x1108, 0x1171, 0x11b3, 0,
+#undef V6146
+#define V6146 (V + 23691)
+ 0x1108, 0x1171, 0x11b4, 0,
+#undef V6147
+#define V6147 (V + 23695)
+ 0x1108, 0x1171, 0x11b5, 0,
+#undef V6148
+#define V6148 (V + 23699)
+ 0x1108, 0x1171, 0x11b6, 0,
+#undef V6149
+#define V6149 (V + 23703)
+ 0x1108, 0x1171, 0x11b7, 0,
+#undef V6150
+#define V6150 (V + 23707)
+ 0x1108, 0x1171, 0x11b8, 0,
+#undef V6151
+#define V6151 (V + 23711)
+ 0x1108, 0x1171, 0x11b9, 0,
+#undef V6152
+#define V6152 (V + 23715)
+ 0x1108, 0x1171, 0x11ba, 0,
+#undef V6153
+#define V6153 (V + 23719)
+ 0x1108, 0x1171, 0x11bb, 0,
+#undef V6154
+#define V6154 (V + 23723)
+ 0x1108, 0x1171, 0x11bc, 0,
+#undef V6155
+#define V6155 (V + 23727)
+ 0x1108, 0x1171, 0x11bd, 0,
+#undef V6156
+#define V6156 (V + 23731)
+ 0x1108, 0x1171, 0x11be, 0,
+#undef V6157
+#define V6157 (V + 23735)
+ 0x1108, 0x1171, 0x11bf, 0,
+#undef V6158
+#define V6158 (V + 23739)
+ 0x1108, 0x1171, 0x11c0, 0,
+#undef V6159
+#define V6159 (V + 23743)
+ 0x1108, 0x1171, 0x11c1, 0,
+#undef V6160
+#define V6160 (V + 23747)
+ 0x1108, 0x1171, 0x11c2, 0,
+#undef V6161
+#define V6161 (V + 23751)
+ 0x1108, 0x1172, 0,
+#undef V6162
+#define V6162 (V + 23754)
+ 0x1108, 0x1172, 0x11a8, 0,
+#undef V6163
+#define V6163 (V + 23758)
+ 0x1108, 0x1172, 0x11a9, 0,
+#undef V6164
+#define V6164 (V + 23762)
+ 0x1108, 0x1172, 0x11aa, 0,
+#undef V6165
+#define V6165 (V + 23766)
+ 0x1108, 0x1172, 0x11ab, 0,
+#undef V6166
+#define V6166 (V + 23770)
+ 0x1108, 0x1172, 0x11ac, 0,
+#undef V6167
+#define V6167 (V + 23774)
+ 0x1108, 0x1172, 0x11ad, 0,
+#undef V6168
+#define V6168 (V + 23778)
+ 0x1108, 0x1172, 0x11ae, 0,
+#undef V6169
+#define V6169 (V + 23782)
+ 0x1108, 0x1172, 0x11af, 0,
+#undef V6170
+#define V6170 (V + 23786)
+ 0x1108, 0x1172, 0x11b0, 0,
+#undef V6171
+#define V6171 (V + 23790)
+ 0x1108, 0x1172, 0x11b1, 0,
+#undef V6172
+#define V6172 (V + 23794)
+ 0x1108, 0x1172, 0x11b2, 0,
+#undef V6173
+#define V6173 (V + 23798)
+ 0x1108, 0x1172, 0x11b3, 0,
+#undef V6174
+#define V6174 (V + 23802)
+ 0x1108, 0x1172, 0x11b4, 0,
+#undef V6175
+#define V6175 (V + 23806)
+ 0x1108, 0x1172, 0x11b5, 0,
+#undef V6176
+#define V6176 (V + 23810)
+ 0x1108, 0x1172, 0x11b6, 0,
+#undef V6177
+#define V6177 (V + 23814)
+ 0x1108, 0x1172, 0x11b7, 0,
+#undef V6178
+#define V6178 (V + 23818)
+ 0x1108, 0x1172, 0x11b8, 0,
+#undef V6179
+#define V6179 (V + 23822)
+ 0x1108, 0x1172, 0x11b9, 0,
+#undef V6180
+#define V6180 (V + 23826)
+ 0x1108, 0x1172, 0x11ba, 0,
+#undef V6181
+#define V6181 (V + 23830)
+ 0x1108, 0x1172, 0x11bb, 0,
+#undef V6182
+#define V6182 (V + 23834)
+ 0x1108, 0x1172, 0x11bc, 0,
+#undef V6183
+#define V6183 (V + 23838)
+ 0x1108, 0x1172, 0x11bd, 0,
+#undef V6184
+#define V6184 (V + 23842)
+ 0x1108, 0x1172, 0x11be, 0,
+#undef V6185
+#define V6185 (V + 23846)
+ 0x1108, 0x1172, 0x11bf, 0,
+#undef V6186
+#define V6186 (V + 23850)
+ 0x1108, 0x1172, 0x11c0, 0,
+#undef V6187
+#define V6187 (V + 23854)
+ 0x1108, 0x1172, 0x11c1, 0,
+#undef V6188
+#define V6188 (V + 23858)
+ 0x1108, 0x1172, 0x11c2, 0,
+#undef V6189
+#define V6189 (V + 23862)
+ 0x1108, 0x1173, 0,
+#undef V6190
+#define V6190 (V + 23865)
+ 0x1108, 0x1173, 0x11a8, 0,
+#undef V6191
+#define V6191 (V + 23869)
+ 0x1108, 0x1173, 0x11a9, 0,
+#undef V6192
+#define V6192 (V + 23873)
+ 0x1108, 0x1173, 0x11aa, 0,
+#undef V6193
+#define V6193 (V + 23877)
+ 0x1108, 0x1173, 0x11ab, 0,
+#undef V6194
+#define V6194 (V + 23881)
+ 0x1108, 0x1173, 0x11ac, 0,
+#undef V6195
+#define V6195 (V + 23885)
+ 0x1108, 0x1173, 0x11ad, 0,
+#undef V6196
+#define V6196 (V + 23889)
+ 0x1108, 0x1173, 0x11ae, 0,
+#undef V6197
+#define V6197 (V + 23893)
+ 0x1108, 0x1173, 0x11af, 0,
+#undef V6198
+#define V6198 (V + 23897)
+ 0x1108, 0x1173, 0x11b0, 0,
+#undef V6199
+#define V6199 (V + 23901)
+ 0x1108, 0x1173, 0x11b1, 0,
+#undef V6200
+#define V6200 (V + 23905)
+ 0x1108, 0x1173, 0x11b2, 0,
+#undef V6201
+#define V6201 (V + 23909)
+ 0x1108, 0x1173, 0x11b3, 0,
+#undef V6202
+#define V6202 (V + 23913)
+ 0x1108, 0x1173, 0x11b4, 0,
+#undef V6203
+#define V6203 (V + 23917)
+ 0x1108, 0x1173, 0x11b5, 0,
+#undef V6204
+#define V6204 (V + 23921)
+ 0x1108, 0x1173, 0x11b6, 0,
+#undef V6205
+#define V6205 (V + 23925)
+ 0x1108, 0x1173, 0x11b7, 0,
+#undef V6206
+#define V6206 (V + 23929)
+ 0x1108, 0x1173, 0x11b8, 0,
+#undef V6207
+#define V6207 (V + 23933)
+ 0x1108, 0x1173, 0x11b9, 0,
+#undef V6208
+#define V6208 (V + 23937)
+ 0x1108, 0x1173, 0x11ba, 0,
+#undef V6209
+#define V6209 (V + 23941)
+ 0x1108, 0x1173, 0x11bb, 0,
+#undef V6210
+#define V6210 (V + 23945)
+ 0x1108, 0x1173, 0x11bc, 0,
+#undef V6211
+#define V6211 (V + 23949)
+ 0x1108, 0x1173, 0x11bd, 0,
+#undef V6212
+#define V6212 (V + 23953)
+ 0x1108, 0x1173, 0x11be, 0,
+#undef V6213
+#define V6213 (V + 23957)
+ 0x1108, 0x1173, 0x11bf, 0,
+#undef V6214
+#define V6214 (V + 23961)
+ 0x1108, 0x1173, 0x11c0, 0,
+#undef V6215
+#define V6215 (V + 23965)
+ 0x1108, 0x1173, 0x11c1, 0,
+#undef V6216
+#define V6216 (V + 23969)
+ 0x1108, 0x1173, 0x11c2, 0,
+#undef V6217
+#define V6217 (V + 23973)
+ 0x1108, 0x1174, 0,
+#undef V6218
+#define V6218 (V + 23976)
+ 0x1108, 0x1174, 0x11a8, 0,
+#undef V6219
+#define V6219 (V + 23980)
+ 0x1108, 0x1174, 0x11a9, 0,
+#undef V6220
+#define V6220 (V + 23984)
+ 0x1108, 0x1174, 0x11aa, 0,
+#undef V6221
+#define V6221 (V + 23988)
+ 0x1108, 0x1174, 0x11ab, 0,
+#undef V6222
+#define V6222 (V + 23992)
+ 0x1108, 0x1174, 0x11ac, 0,
+#undef V6223
+#define V6223 (V + 23996)
+ 0x1108, 0x1174, 0x11ad, 0,
+#undef V6224
+#define V6224 (V + 24000)
+ 0x1108, 0x1174, 0x11ae, 0,
+#undef V6225
+#define V6225 (V + 24004)
+ 0x1108, 0x1174, 0x11af, 0,
+#undef V6226
+#define V6226 (V + 24008)
+ 0x1108, 0x1174, 0x11b0, 0,
+#undef V6227
+#define V6227 (V + 24012)
+ 0x1108, 0x1174, 0x11b1, 0,
+#undef V6228
+#define V6228 (V + 24016)
+ 0x1108, 0x1174, 0x11b2, 0,
+#undef V6229
+#define V6229 (V + 24020)
+ 0x1108, 0x1174, 0x11b3, 0,
+#undef V6230
+#define V6230 (V + 24024)
+ 0x1108, 0x1174, 0x11b4, 0,
+#undef V6231
+#define V6231 (V + 24028)
+ 0x1108, 0x1174, 0x11b5, 0,
+#undef V6232
+#define V6232 (V + 24032)
+ 0x1108, 0x1174, 0x11b6, 0,
+#undef V6233
+#define V6233 (V + 24036)
+ 0x1108, 0x1174, 0x11b7, 0,
+#undef V6234
+#define V6234 (V + 24040)
+ 0x1108, 0x1174, 0x11b8, 0,
+#undef V6235
+#define V6235 (V + 24044)
+ 0x1108, 0x1174, 0x11b9, 0,
+#undef V6236
+#define V6236 (V + 24048)
+ 0x1108, 0x1174, 0x11ba, 0,
+#undef V6237
+#define V6237 (V + 24052)
+ 0x1108, 0x1174, 0x11bb, 0,
+#undef V6238
+#define V6238 (V + 24056)
+ 0x1108, 0x1174, 0x11bc, 0,
+#undef V6239
+#define V6239 (V + 24060)
+ 0x1108, 0x1174, 0x11bd, 0,
+#undef V6240
+#define V6240 (V + 24064)
+ 0x1108, 0x1174, 0x11be, 0,
+#undef V6241
+#define V6241 (V + 24068)
+ 0x1108, 0x1174, 0x11bf, 0,
+#undef V6242
+#define V6242 (V + 24072)
+ 0x1108, 0x1174, 0x11c0, 0,
+#undef V6243
+#define V6243 (V + 24076)
+ 0x1108, 0x1174, 0x11c1, 0,
+#undef V6244
+#define V6244 (V + 24080)
+ 0x1108, 0x1174, 0x11c2, 0,
+#undef V6245
+#define V6245 (V + 24084)
+ 0x1108, 0x1175, 0,
+#undef V6246
+#define V6246 (V + 24087)
+ 0x1108, 0x1175, 0x11a8, 0,
+#undef V6247
+#define V6247 (V + 24091)
+ 0x1108, 0x1175, 0x11a9, 0,
+#undef V6248
+#define V6248 (V + 24095)
+ 0x1108, 0x1175, 0x11aa, 0,
+#undef V6249
+#define V6249 (V + 24099)
+ 0x1108, 0x1175, 0x11ab, 0,
+#undef V6250
+#define V6250 (V + 24103)
+ 0x1108, 0x1175, 0x11ac, 0,
+#undef V6251
+#define V6251 (V + 24107)
+ 0x1108, 0x1175, 0x11ad, 0,
+#undef V6252
+#define V6252 (V + 24111)
+ 0x1108, 0x1175, 0x11ae, 0,
+#undef V6253
+#define V6253 (V + 24115)
+ 0x1108, 0x1175, 0x11af, 0,
+#undef V6254
+#define V6254 (V + 24119)
+ 0x1108, 0x1175, 0x11b0, 0,
+#undef V6255
+#define V6255 (V + 24123)
+ 0x1108, 0x1175, 0x11b1, 0,
+#undef V6256
+#define V6256 (V + 24127)
+ 0x1108, 0x1175, 0x11b2, 0,
+#undef V6257
+#define V6257 (V + 24131)
+ 0x1108, 0x1175, 0x11b3, 0,
+#undef V6258
+#define V6258 (V + 24135)
+ 0x1108, 0x1175, 0x11b4, 0,
+#undef V6259
+#define V6259 (V + 24139)
+ 0x1108, 0x1175, 0x11b5, 0,
+#undef V6260
+#define V6260 (V + 24143)
+ 0x1108, 0x1175, 0x11b6, 0,
+#undef V6261
+#define V6261 (V + 24147)
+ 0x1108, 0x1175, 0x11b7, 0,
+#undef V6262
+#define V6262 (V + 24151)
+ 0x1108, 0x1175, 0x11b8, 0,
+#undef V6263
+#define V6263 (V + 24155)
+ 0x1108, 0x1175, 0x11b9, 0,
+#undef V6264
+#define V6264 (V + 24159)
+ 0x1108, 0x1175, 0x11ba, 0,
+#undef V6265
+#define V6265 (V + 24163)
+ 0x1108, 0x1175, 0x11bb, 0,
+#undef V6266
+#define V6266 (V + 24167)
+ 0x1108, 0x1175, 0x11bc, 0,
+#undef V6267
+#define V6267 (V + 24171)
+ 0x1108, 0x1175, 0x11bd, 0,
+#undef V6268
+#define V6268 (V + 24175)
+ 0x1108, 0x1175, 0x11be, 0,
+#undef V6269
+#define V6269 (V + 24179)
+ 0x1108, 0x1175, 0x11bf, 0,
+#undef V6270
+#define V6270 (V + 24183)
+ 0x1108, 0x1175, 0x11c0, 0,
+#undef V6271
+#define V6271 (V + 24187)
+ 0x1108, 0x1175, 0x11c1, 0,
+#undef V6272
+#define V6272 (V + 24191)
+ 0x1108, 0x1175, 0x11c2, 0,
+#undef V6273
+#define V6273 (V + 24195)
+ 0x1109, 0x1161, 0,
+#undef V6274
+#define V6274 (V + 24198)
+ 0x1109, 0x1161, 0x11a8, 0,
+#undef V6275
+#define V6275 (V + 24202)
+ 0x1109, 0x1161, 0x11a9, 0,
+#undef V6276
+#define V6276 (V + 24206)
+ 0x1109, 0x1161, 0x11aa, 0,
+#undef V6277
+#define V6277 (V + 24210)
+ 0x1109, 0x1161, 0x11ab, 0,
+#undef V6278
+#define V6278 (V + 24214)
+ 0x1109, 0x1161, 0x11ac, 0,
+#undef V6279
+#define V6279 (V + 24218)
+ 0x1109, 0x1161, 0x11ad, 0,
+#undef V6280
+#define V6280 (V + 24222)
+ 0x1109, 0x1161, 0x11ae, 0,
+#undef V6281
+#define V6281 (V + 24226)
+ 0x1109, 0x1161, 0x11af, 0,
+#undef V6282
+#define V6282 (V + 24230)
+ 0x1109, 0x1161, 0x11b0, 0,
+#undef V6283
+#define V6283 (V + 24234)
+ 0x1109, 0x1161, 0x11b1, 0,
+#undef V6284
+#define V6284 (V + 24238)
+ 0x1109, 0x1161, 0x11b2, 0,
+#undef V6285
+#define V6285 (V + 24242)
+ 0x1109, 0x1161, 0x11b3, 0,
+#undef V6286
+#define V6286 (V + 24246)
+ 0x1109, 0x1161, 0x11b4, 0,
+#undef V6287
+#define V6287 (V + 24250)
+ 0x1109, 0x1161, 0x11b5, 0,
+#undef V6288
+#define V6288 (V + 24254)
+ 0x1109, 0x1161, 0x11b6, 0,
+#undef V6289
+#define V6289 (V + 24258)
+ 0x1109, 0x1161, 0x11b7, 0,
+#undef V6290
+#define V6290 (V + 24262)
+ 0x1109, 0x1161, 0x11b8, 0,
+#undef V6291
+#define V6291 (V + 24266)
+ 0x1109, 0x1161, 0x11b9, 0,
+#undef V6292
+#define V6292 (V + 24270)
+ 0x1109, 0x1161, 0x11ba, 0,
+#undef V6293
+#define V6293 (V + 24274)
+ 0x1109, 0x1161, 0x11bb, 0,
+#undef V6294
+#define V6294 (V + 24278)
+ 0x1109, 0x1161, 0x11bc, 0,
+#undef V6295
+#define V6295 (V + 24282)
+ 0x1109, 0x1161, 0x11bd, 0,
+#undef V6296
+#define V6296 (V + 24286)
+ 0x1109, 0x1161, 0x11be, 0,
+#undef V6297
+#define V6297 (V + 24290)
+ 0x1109, 0x1161, 0x11bf, 0,
+#undef V6298
+#define V6298 (V + 24294)
+ 0x1109, 0x1161, 0x11c0, 0,
+#undef V6299
+#define V6299 (V + 24298)
+ 0x1109, 0x1161, 0x11c1, 0,
+#undef V6300
+#define V6300 (V + 24302)
+ 0x1109, 0x1161, 0x11c2, 0,
+#undef V6301
+#define V6301 (V + 24306)
+ 0x1109, 0x1162, 0,
+#undef V6302
+#define V6302 (V + 24309)
+ 0x1109, 0x1162, 0x11a8, 0,
+#undef V6303
+#define V6303 (V + 24313)
+ 0x1109, 0x1162, 0x11a9, 0,
+#undef V6304
+#define V6304 (V + 24317)
+ 0x1109, 0x1162, 0x11aa, 0,
+#undef V6305
+#define V6305 (V + 24321)
+ 0x1109, 0x1162, 0x11ab, 0,
+#undef V6306
+#define V6306 (V + 24325)
+ 0x1109, 0x1162, 0x11ac, 0,
+#undef V6307
+#define V6307 (V + 24329)
+ 0x1109, 0x1162, 0x11ad, 0,
+#undef V6308
+#define V6308 (V + 24333)
+ 0x1109, 0x1162, 0x11ae, 0,
+#undef V6309
+#define V6309 (V + 24337)
+ 0x1109, 0x1162, 0x11af, 0,
+#undef V6310
+#define V6310 (V + 24341)
+ 0x1109, 0x1162, 0x11b0, 0,
+#undef V6311
+#define V6311 (V + 24345)
+ 0x1109, 0x1162, 0x11b1, 0,
+#undef V6312
+#define V6312 (V + 24349)
+ 0x1109, 0x1162, 0x11b2, 0,
+#undef V6313
+#define V6313 (V + 24353)
+ 0x1109, 0x1162, 0x11b3, 0,
+#undef V6314
+#define V6314 (V + 24357)
+ 0x1109, 0x1162, 0x11b4, 0,
+#undef V6315
+#define V6315 (V + 24361)
+ 0x1109, 0x1162, 0x11b5, 0,
+#undef V6316
+#define V6316 (V + 24365)
+ 0x1109, 0x1162, 0x11b6, 0,
+#undef V6317
+#define V6317 (V + 24369)
+ 0x1109, 0x1162, 0x11b7, 0,
+#undef V6318
+#define V6318 (V + 24373)
+ 0x1109, 0x1162, 0x11b8, 0,
+#undef V6319
+#define V6319 (V + 24377)
+ 0x1109, 0x1162, 0x11b9, 0,
+#undef V6320
+#define V6320 (V + 24381)
+ 0x1109, 0x1162, 0x11ba, 0,
+#undef V6321
+#define V6321 (V + 24385)
+ 0x1109, 0x1162, 0x11bb, 0,
+#undef V6322
+#define V6322 (V + 24389)
+ 0x1109, 0x1162, 0x11bc, 0,
+#undef V6323
+#define V6323 (V + 24393)
+ 0x1109, 0x1162, 0x11bd, 0,
+#undef V6324
+#define V6324 (V + 24397)
+ 0x1109, 0x1162, 0x11be, 0,
+#undef V6325
+#define V6325 (V + 24401)
+ 0x1109, 0x1162, 0x11bf, 0,
+#undef V6326
+#define V6326 (V + 24405)
+ 0x1109, 0x1162, 0x11c0, 0,
+#undef V6327
+#define V6327 (V + 24409)
+ 0x1109, 0x1162, 0x11c1, 0,
+#undef V6328
+#define V6328 (V + 24413)
+ 0x1109, 0x1162, 0x11c2, 0,
+#undef V6329
+#define V6329 (V + 24417)
+ 0x1109, 0x1163, 0,
+#undef V6330
+#define V6330 (V + 24420)
+ 0x1109, 0x1163, 0x11a8, 0,
+#undef V6331
+#define V6331 (V + 24424)
+ 0x1109, 0x1163, 0x11a9, 0,
+#undef V6332
+#define V6332 (V + 24428)
+ 0x1109, 0x1163, 0x11aa, 0,
+#undef V6333
+#define V6333 (V + 24432)
+ 0x1109, 0x1163, 0x11ab, 0,
+#undef V6334
+#define V6334 (V + 24436)
+ 0x1109, 0x1163, 0x11ac, 0,
+#undef V6335
+#define V6335 (V + 24440)
+ 0x1109, 0x1163, 0x11ad, 0,
+#undef V6336
+#define V6336 (V + 24444)
+ 0x1109, 0x1163, 0x11ae, 0,
+#undef V6337
+#define V6337 (V + 24448)
+ 0x1109, 0x1163, 0x11af, 0,
+#undef V6338
+#define V6338 (V + 24452)
+ 0x1109, 0x1163, 0x11b0, 0,
+#undef V6339
+#define V6339 (V + 24456)
+ 0x1109, 0x1163, 0x11b1, 0,
+#undef V6340
+#define V6340 (V + 24460)
+ 0x1109, 0x1163, 0x11b2, 0,
+#undef V6341
+#define V6341 (V + 24464)
+ 0x1109, 0x1163, 0x11b3, 0,
+#undef V6342
+#define V6342 (V + 24468)
+ 0x1109, 0x1163, 0x11b4, 0,
+#undef V6343
+#define V6343 (V + 24472)
+ 0x1109, 0x1163, 0x11b5, 0,
+#undef V6344
+#define V6344 (V + 24476)
+ 0x1109, 0x1163, 0x11b6, 0,
+#undef V6345
+#define V6345 (V + 24480)
+ 0x1109, 0x1163, 0x11b7, 0,
+#undef V6346
+#define V6346 (V + 24484)
+ 0x1109, 0x1163, 0x11b8, 0,
+#undef V6347
+#define V6347 (V + 24488)
+ 0x1109, 0x1163, 0x11b9, 0,
+#undef V6348
+#define V6348 (V + 24492)
+ 0x1109, 0x1163, 0x11ba, 0,
+#undef V6349
+#define V6349 (V + 24496)
+ 0x1109, 0x1163, 0x11bb, 0,
+#undef V6350
+#define V6350 (V + 24500)
+ 0x1109, 0x1163, 0x11bc, 0,
+#undef V6351
+#define V6351 (V + 24504)
+ 0x1109, 0x1163, 0x11bd, 0,
+#undef V6352
+#define V6352 (V + 24508)
+ 0x1109, 0x1163, 0x11be, 0,
+#undef V6353
+#define V6353 (V + 24512)
+ 0x1109, 0x1163, 0x11bf, 0,
+#undef V6354
+#define V6354 (V + 24516)
+ 0x1109, 0x1163, 0x11c0, 0,
+#undef V6355
+#define V6355 (V + 24520)
+ 0x1109, 0x1163, 0x11c1, 0,
+#undef V6356
+#define V6356 (V + 24524)
+ 0x1109, 0x1163, 0x11c2, 0,
+#undef V6357
+#define V6357 (V + 24528)
+ 0x1109, 0x1164, 0,
+#undef V6358
+#define V6358 (V + 24531)
+ 0x1109, 0x1164, 0x11a8, 0,
+#undef V6359
+#define V6359 (V + 24535)
+ 0x1109, 0x1164, 0x11a9, 0,
+#undef V6360
+#define V6360 (V + 24539)
+ 0x1109, 0x1164, 0x11aa, 0,
+#undef V6361
+#define V6361 (V + 24543)
+ 0x1109, 0x1164, 0x11ab, 0,
+#undef V6362
+#define V6362 (V + 24547)
+ 0x1109, 0x1164, 0x11ac, 0,
+#undef V6363
+#define V6363 (V + 24551)
+ 0x1109, 0x1164, 0x11ad, 0,
+#undef V6364
+#define V6364 (V + 24555)
+ 0x1109, 0x1164, 0x11ae, 0,
+#undef V6365
+#define V6365 (V + 24559)
+ 0x1109, 0x1164, 0x11af, 0,
+#undef V6366
+#define V6366 (V + 24563)
+ 0x1109, 0x1164, 0x11b0, 0,
+#undef V6367
+#define V6367 (V + 24567)
+ 0x1109, 0x1164, 0x11b1, 0,
+#undef V6368
+#define V6368 (V + 24571)
+ 0x1109, 0x1164, 0x11b2, 0,
+#undef V6369
+#define V6369 (V + 24575)
+ 0x1109, 0x1164, 0x11b3, 0,
+#undef V6370
+#define V6370 (V + 24579)
+ 0x1109, 0x1164, 0x11b4, 0,
+#undef V6371
+#define V6371 (V + 24583)
+ 0x1109, 0x1164, 0x11b5, 0,
+#undef V6372
+#define V6372 (V + 24587)
+ 0x1109, 0x1164, 0x11b6, 0,
+#undef V6373
+#define V6373 (V + 24591)
+ 0x1109, 0x1164, 0x11b7, 0,
+#undef V6374
+#define V6374 (V + 24595)
+ 0x1109, 0x1164, 0x11b8, 0,
+#undef V6375
+#define V6375 (V + 24599)
+ 0x1109, 0x1164, 0x11b9, 0,
+#undef V6376
+#define V6376 (V + 24603)
+ 0x1109, 0x1164, 0x11ba, 0,
+#undef V6377
+#define V6377 (V + 24607)
+ 0x1109, 0x1164, 0x11bb, 0,
+#undef V6378
+#define V6378 (V + 24611)
+ 0x1109, 0x1164, 0x11bc, 0,
+#undef V6379
+#define V6379 (V + 24615)
+ 0x1109, 0x1164, 0x11bd, 0,
+#undef V6380
+#define V6380 (V + 24619)
+ 0x1109, 0x1164, 0x11be, 0,
+#undef V6381
+#define V6381 (V + 24623)
+ 0x1109, 0x1164, 0x11bf, 0,
+#undef V6382
+#define V6382 (V + 24627)
+ 0x1109, 0x1164, 0x11c0, 0,
+#undef V6383
+#define V6383 (V + 24631)
+ 0x1109, 0x1164, 0x11c1, 0,
+#undef V6384
+#define V6384 (V + 24635)
+ 0x1109, 0x1164, 0x11c2, 0,
+#undef V6385
+#define V6385 (V + 24639)
+ 0x1109, 0x1165, 0,
+#undef V6386
+#define V6386 (V + 24642)
+ 0x1109, 0x1165, 0x11a8, 0,
+#undef V6387
+#define V6387 (V + 24646)
+ 0x1109, 0x1165, 0x11a9, 0,
+#undef V6388
+#define V6388 (V + 24650)
+ 0x1109, 0x1165, 0x11aa, 0,
+#undef V6389
+#define V6389 (V + 24654)
+ 0x1109, 0x1165, 0x11ab, 0,
+#undef V6390
+#define V6390 (V + 24658)
+ 0x1109, 0x1165, 0x11ac, 0,
+#undef V6391
+#define V6391 (V + 24662)
+ 0x1109, 0x1165, 0x11ad, 0,
+#undef V6392
+#define V6392 (V + 24666)
+ 0x1109, 0x1165, 0x11ae, 0,
+#undef V6393
+#define V6393 (V + 24670)
+ 0x1109, 0x1165, 0x11af, 0,
+#undef V6394
+#define V6394 (V + 24674)
+ 0x1109, 0x1165, 0x11b0, 0,
+#undef V6395
+#define V6395 (V + 24678)
+ 0x1109, 0x1165, 0x11b1, 0,
+#undef V6396
+#define V6396 (V + 24682)
+ 0x1109, 0x1165, 0x11b2, 0,
+#undef V6397
+#define V6397 (V + 24686)
+ 0x1109, 0x1165, 0x11b3, 0,
+#undef V6398
+#define V6398 (V + 24690)
+ 0x1109, 0x1165, 0x11b4, 0,
+#undef V6399
+#define V6399 (V + 24694)
+ 0x1109, 0x1165, 0x11b5, 0,
+#undef V6400
+#define V6400 (V + 24698)
+ 0x1109, 0x1165, 0x11b6, 0,
+#undef V6401
+#define V6401 (V + 24702)
+ 0x1109, 0x1165, 0x11b7, 0,
+#undef V6402
+#define V6402 (V + 24706)
+ 0x1109, 0x1165, 0x11b8, 0,
+#undef V6403
+#define V6403 (V + 24710)
+ 0x1109, 0x1165, 0x11b9, 0,
+#undef V6404
+#define V6404 (V + 24714)
+ 0x1109, 0x1165, 0x11ba, 0,
+#undef V6405
+#define V6405 (V + 24718)
+ 0x1109, 0x1165, 0x11bb, 0,
+#undef V6406
+#define V6406 (V + 24722)
+ 0x1109, 0x1165, 0x11bc, 0,
+#undef V6407
+#define V6407 (V + 24726)
+ 0x1109, 0x1165, 0x11bd, 0,
+#undef V6408
+#define V6408 (V + 24730)
+ 0x1109, 0x1165, 0x11be, 0,
+#undef V6409
+#define V6409 (V + 24734)
+ 0x1109, 0x1165, 0x11bf, 0,
+#undef V6410
+#define V6410 (V + 24738)
+ 0x1109, 0x1165, 0x11c0, 0,
+#undef V6411
+#define V6411 (V + 24742)
+ 0x1109, 0x1165, 0x11c1, 0,
+#undef V6412
+#define V6412 (V + 24746)
+ 0x1109, 0x1165, 0x11c2, 0,
+#undef V6413
+#define V6413 (V + 24750)
+ 0x1109, 0x1166, 0,
+#undef V6414
+#define V6414 (V + 24753)
+ 0x1109, 0x1166, 0x11a8, 0,
+#undef V6415
+#define V6415 (V + 24757)
+ 0x1109, 0x1166, 0x11a9, 0,
+#undef V6416
+#define V6416 (V + 24761)
+ 0x1109, 0x1166, 0x11aa, 0,
+#undef V6417
+#define V6417 (V + 24765)
+ 0x1109, 0x1166, 0x11ab, 0,
+#undef V6418
+#define V6418 (V + 24769)
+ 0x1109, 0x1166, 0x11ac, 0,
+#undef V6419
+#define V6419 (V + 24773)
+ 0x1109, 0x1166, 0x11ad, 0,
+#undef V6420
+#define V6420 (V + 24777)
+ 0x1109, 0x1166, 0x11ae, 0,
+#undef V6421
+#define V6421 (V + 24781)
+ 0x1109, 0x1166, 0x11af, 0,
+#undef V6422
+#define V6422 (V + 24785)
+ 0x1109, 0x1166, 0x11b0, 0,
+#undef V6423
+#define V6423 (V + 24789)
+ 0x1109, 0x1166, 0x11b1, 0,
+#undef V6424
+#define V6424 (V + 24793)
+ 0x1109, 0x1166, 0x11b2, 0,
+#undef V6425
+#define V6425 (V + 24797)
+ 0x1109, 0x1166, 0x11b3, 0,
+#undef V6426
+#define V6426 (V + 24801)
+ 0x1109, 0x1166, 0x11b4, 0,
+#undef V6427
+#define V6427 (V + 24805)
+ 0x1109, 0x1166, 0x11b5, 0,
+#undef V6428
+#define V6428 (V + 24809)
+ 0x1109, 0x1166, 0x11b6, 0,
+#undef V6429
+#define V6429 (V + 24813)
+ 0x1109, 0x1166, 0x11b7, 0,
+#undef V6430
+#define V6430 (V + 24817)
+ 0x1109, 0x1166, 0x11b8, 0,
+#undef V6431
+#define V6431 (V + 24821)
+ 0x1109, 0x1166, 0x11b9, 0,
+#undef V6432
+#define V6432 (V + 24825)
+ 0x1109, 0x1166, 0x11ba, 0,
+#undef V6433
+#define V6433 (V + 24829)
+ 0x1109, 0x1166, 0x11bb, 0,
+#undef V6434
+#define V6434 (V + 24833)
+ 0x1109, 0x1166, 0x11bc, 0,
+#undef V6435
+#define V6435 (V + 24837)
+ 0x1109, 0x1166, 0x11bd, 0,
+#undef V6436
+#define V6436 (V + 24841)
+ 0x1109, 0x1166, 0x11be, 0,
+#undef V6437
+#define V6437 (V + 24845)
+ 0x1109, 0x1166, 0x11bf, 0,
+#undef V6438
+#define V6438 (V + 24849)
+ 0x1109, 0x1166, 0x11c0, 0,
+#undef V6439
+#define V6439 (V + 24853)
+ 0x1109, 0x1166, 0x11c1, 0,
+#undef V6440
+#define V6440 (V + 24857)
+ 0x1109, 0x1166, 0x11c2, 0,
+#undef V6441
+#define V6441 (V + 24861)
+ 0x1109, 0x1167, 0,
+#undef V6442
+#define V6442 (V + 24864)
+ 0x1109, 0x1167, 0x11a8, 0,
+#undef V6443
+#define V6443 (V + 24868)
+ 0x1109, 0x1167, 0x11a9, 0,
+#undef V6444
+#define V6444 (V + 24872)
+ 0x1109, 0x1167, 0x11aa, 0,
+#undef V6445
+#define V6445 (V + 24876)
+ 0x1109, 0x1167, 0x11ab, 0,
+#undef V6446
+#define V6446 (V + 24880)
+ 0x1109, 0x1167, 0x11ac, 0,
+#undef V6447
+#define V6447 (V + 24884)
+ 0x1109, 0x1167, 0x11ad, 0,
+#undef V6448
+#define V6448 (V + 24888)
+ 0x1109, 0x1167, 0x11ae, 0,
+#undef V6449
+#define V6449 (V + 24892)
+ 0x1109, 0x1167, 0x11af, 0,
+#undef V6450
+#define V6450 (V + 24896)
+ 0x1109, 0x1167, 0x11b0, 0,
+#undef V6451
+#define V6451 (V + 24900)
+ 0x1109, 0x1167, 0x11b1, 0,
+#undef V6452
+#define V6452 (V + 24904)
+ 0x1109, 0x1167, 0x11b2, 0,
+#undef V6453
+#define V6453 (V + 24908)
+ 0x1109, 0x1167, 0x11b3, 0,
+#undef V6454
+#define V6454 (V + 24912)
+ 0x1109, 0x1167, 0x11b4, 0,
+#undef V6455
+#define V6455 (V + 24916)
+ 0x1109, 0x1167, 0x11b5, 0,
+#undef V6456
+#define V6456 (V + 24920)
+ 0x1109, 0x1167, 0x11b6, 0,
+#undef V6457
+#define V6457 (V + 24924)
+ 0x1109, 0x1167, 0x11b7, 0,
+#undef V6458
+#define V6458 (V + 24928)
+ 0x1109, 0x1167, 0x11b8, 0,
+#undef V6459
+#define V6459 (V + 24932)
+ 0x1109, 0x1167, 0x11b9, 0,
+#undef V6460
+#define V6460 (V + 24936)
+ 0x1109, 0x1167, 0x11ba, 0,
+#undef V6461
+#define V6461 (V + 24940)
+ 0x1109, 0x1167, 0x11bb, 0,
+#undef V6462
+#define V6462 (V + 24944)
+ 0x1109, 0x1167, 0x11bc, 0,
+#undef V6463
+#define V6463 (V + 24948)
+ 0x1109, 0x1167, 0x11bd, 0,
+#undef V6464
+#define V6464 (V + 24952)
+ 0x1109, 0x1167, 0x11be, 0,
+#undef V6465
+#define V6465 (V + 24956)
+ 0x1109, 0x1167, 0x11bf, 0,
+#undef V6466
+#define V6466 (V + 24960)
+ 0x1109, 0x1167, 0x11c0, 0,
+#undef V6467
+#define V6467 (V + 24964)
+ 0x1109, 0x1167, 0x11c1, 0,
+#undef V6468
+#define V6468 (V + 24968)
+ 0x1109, 0x1167, 0x11c2, 0,
+#undef V6469
+#define V6469 (V + 24972)
+ 0x1109, 0x1168, 0,
+#undef V6470
+#define V6470 (V + 24975)
+ 0x1109, 0x1168, 0x11a8, 0,
+#undef V6471
+#define V6471 (V + 24979)
+ 0x1109, 0x1168, 0x11a9, 0,
+#undef V6472
+#define V6472 (V + 24983)
+ 0x1109, 0x1168, 0x11aa, 0,
+#undef V6473
+#define V6473 (V + 24987)
+ 0x1109, 0x1168, 0x11ab, 0,
+#undef V6474
+#define V6474 (V + 24991)
+ 0x1109, 0x1168, 0x11ac, 0,
+#undef V6475
+#define V6475 (V + 24995)
+ 0x1109, 0x1168, 0x11ad, 0,
+#undef V6476
+#define V6476 (V + 24999)
+ 0x1109, 0x1168, 0x11ae, 0,
+#undef V6477
+#define V6477 (V + 25003)
+ 0x1109, 0x1168, 0x11af, 0,
+#undef V6478
+#define V6478 (V + 25007)
+ 0x1109, 0x1168, 0x11b0, 0,
+#undef V6479
+#define V6479 (V + 25011)
+ 0x1109, 0x1168, 0x11b1, 0,
+#undef V6480
+#define V6480 (V + 25015)
+ 0x1109, 0x1168, 0x11b2, 0,
+#undef V6481
+#define V6481 (V + 25019)
+ 0x1109, 0x1168, 0x11b3, 0,
+#undef V6482
+#define V6482 (V + 25023)
+ 0x1109, 0x1168, 0x11b4, 0,
+#undef V6483
+#define V6483 (V + 25027)
+ 0x1109, 0x1168, 0x11b5, 0,
+#undef V6484
+#define V6484 (V + 25031)
+ 0x1109, 0x1168, 0x11b6, 0,
+#undef V6485
+#define V6485 (V + 25035)
+ 0x1109, 0x1168, 0x11b7, 0,
+#undef V6486
+#define V6486 (V + 25039)
+ 0x1109, 0x1168, 0x11b8, 0,
+#undef V6487
+#define V6487 (V + 25043)
+ 0x1109, 0x1168, 0x11b9, 0,
+#undef V6488
+#define V6488 (V + 25047)
+ 0x1109, 0x1168, 0x11ba, 0,
+#undef V6489
+#define V6489 (V + 25051)
+ 0x1109, 0x1168, 0x11bb, 0,
+#undef V6490
+#define V6490 (V + 25055)
+ 0x1109, 0x1168, 0x11bc, 0,
+#undef V6491
+#define V6491 (V + 25059)
+ 0x1109, 0x1168, 0x11bd, 0,
+#undef V6492
+#define V6492 (V + 25063)
+ 0x1109, 0x1168, 0x11be, 0,
+#undef V6493
+#define V6493 (V + 25067)
+ 0x1109, 0x1168, 0x11bf, 0,
+#undef V6494
+#define V6494 (V + 25071)
+ 0x1109, 0x1168, 0x11c0, 0,
+#undef V6495
+#define V6495 (V + 25075)
+ 0x1109, 0x1168, 0x11c1, 0,
+#undef V6496
+#define V6496 (V + 25079)
+ 0x1109, 0x1168, 0x11c2, 0,
+#undef V6497
+#define V6497 (V + 25083)
+ 0x1109, 0x1169, 0,
+#undef V6498
+#define V6498 (V + 25086)
+ 0x1109, 0x1169, 0x11a8, 0,
+#undef V6499
+#define V6499 (V + 25090)
+ 0x1109, 0x1169, 0x11a9, 0,
+#undef V6500
+#define V6500 (V + 25094)
+ 0x1109, 0x1169, 0x11aa, 0,
+#undef V6501
+#define V6501 (V + 25098)
+ 0x1109, 0x1169, 0x11ab, 0,
+#undef V6502
+#define V6502 (V + 25102)
+ 0x1109, 0x1169, 0x11ac, 0,
+#undef V6503
+#define V6503 (V + 25106)
+ 0x1109, 0x1169, 0x11ad, 0,
+#undef V6504
+#define V6504 (V + 25110)
+ 0x1109, 0x1169, 0x11ae, 0,
+#undef V6505
+#define V6505 (V + 25114)
+ 0x1109, 0x1169, 0x11af, 0,
+#undef V6506
+#define V6506 (V + 25118)
+ 0x1109, 0x1169, 0x11b0, 0,
+#undef V6507
+#define V6507 (V + 25122)
+ 0x1109, 0x1169, 0x11b1, 0,
+#undef V6508
+#define V6508 (V + 25126)
+ 0x1109, 0x1169, 0x11b2, 0,
+#undef V6509
+#define V6509 (V + 25130)
+ 0x1109, 0x1169, 0x11b3, 0,
+#undef V6510
+#define V6510 (V + 25134)
+ 0x1109, 0x1169, 0x11b4, 0,
+#undef V6511
+#define V6511 (V + 25138)
+ 0x1109, 0x1169, 0x11b5, 0,
+#undef V6512
+#define V6512 (V + 25142)
+ 0x1109, 0x1169, 0x11b6, 0,
+#undef V6513
+#define V6513 (V + 25146)
+ 0x1109, 0x1169, 0x11b7, 0,
+#undef V6514
+#define V6514 (V + 25150)
+ 0x1109, 0x1169, 0x11b8, 0,
+#undef V6515
+#define V6515 (V + 25154)
+ 0x1109, 0x1169, 0x11b9, 0,
+#undef V6516
+#define V6516 (V + 25158)
+ 0x1109, 0x1169, 0x11ba, 0,
+#undef V6517
+#define V6517 (V + 25162)
+ 0x1109, 0x1169, 0x11bb, 0,
+#undef V6518
+#define V6518 (V + 25166)
+ 0x1109, 0x1169, 0x11bc, 0,
+#undef V6519
+#define V6519 (V + 25170)
+ 0x1109, 0x1169, 0x11bd, 0,
+#undef V6520
+#define V6520 (V + 25174)
+ 0x1109, 0x1169, 0x11be, 0,
+#undef V6521
+#define V6521 (V + 25178)
+ 0x1109, 0x1169, 0x11bf, 0,
+#undef V6522
+#define V6522 (V + 25182)
+ 0x1109, 0x1169, 0x11c0, 0,
+#undef V6523
+#define V6523 (V + 25186)
+ 0x1109, 0x1169, 0x11c1, 0,
+#undef V6524
+#define V6524 (V + 25190)
+ 0x1109, 0x1169, 0x11c2, 0,
+#undef V6525
+#define V6525 (V + 25194)
+ 0x1109, 0x116a, 0,
+#undef V6526
+#define V6526 (V + 25197)
+ 0x1109, 0x116a, 0x11a8, 0,
+#undef V6527
+#define V6527 (V + 25201)
+ 0x1109, 0x116a, 0x11a9, 0,
+#undef V6528
+#define V6528 (V + 25205)
+ 0x1109, 0x116a, 0x11aa, 0,
+#undef V6529
+#define V6529 (V + 25209)
+ 0x1109, 0x116a, 0x11ab, 0,
+#undef V6530
+#define V6530 (V + 25213)
+ 0x1109, 0x116a, 0x11ac, 0,
+#undef V6531
+#define V6531 (V + 25217)
+ 0x1109, 0x116a, 0x11ad, 0,
+#undef V6532
+#define V6532 (V + 25221)
+ 0x1109, 0x116a, 0x11ae, 0,
+#undef V6533
+#define V6533 (V + 25225)
+ 0x1109, 0x116a, 0x11af, 0,
+#undef V6534
+#define V6534 (V + 25229)
+ 0x1109, 0x116a, 0x11b0, 0,
+#undef V6535
+#define V6535 (V + 25233)
+ 0x1109, 0x116a, 0x11b1, 0,
+#undef V6536
+#define V6536 (V + 25237)
+ 0x1109, 0x116a, 0x11b2, 0,
+#undef V6537
+#define V6537 (V + 25241)
+ 0x1109, 0x116a, 0x11b3, 0,
+#undef V6538
+#define V6538 (V + 25245)
+ 0x1109, 0x116a, 0x11b4, 0,
+#undef V6539
+#define V6539 (V + 25249)
+ 0x1109, 0x116a, 0x11b5, 0,
+#undef V6540
+#define V6540 (V + 25253)
+ 0x1109, 0x116a, 0x11b6, 0,
+#undef V6541
+#define V6541 (V + 25257)
+ 0x1109, 0x116a, 0x11b7, 0,
+#undef V6542
+#define V6542 (V + 25261)
+ 0x1109, 0x116a, 0x11b8, 0,
+#undef V6543
+#define V6543 (V + 25265)
+ 0x1109, 0x116a, 0x11b9, 0,
+#undef V6544
+#define V6544 (V + 25269)
+ 0x1109, 0x116a, 0x11ba, 0,
+#undef V6545
+#define V6545 (V + 25273)
+ 0x1109, 0x116a, 0x11bb, 0,
+#undef V6546
+#define V6546 (V + 25277)
+ 0x1109, 0x116a, 0x11bc, 0,
+#undef V6547
+#define V6547 (V + 25281)
+ 0x1109, 0x116a, 0x11bd, 0,
+#undef V6548
+#define V6548 (V + 25285)
+ 0x1109, 0x116a, 0x11be, 0,
+#undef V6549
+#define V6549 (V + 25289)
+ 0x1109, 0x116a, 0x11bf, 0,
+#undef V6550
+#define V6550 (V + 25293)
+ 0x1109, 0x116a, 0x11c0, 0,
+#undef V6551
+#define V6551 (V + 25297)
+ 0x1109, 0x116a, 0x11c1, 0,
+#undef V6552
+#define V6552 (V + 25301)
+ 0x1109, 0x116a, 0x11c2, 0,
+#undef V6553
+#define V6553 (V + 25305)
+ 0x1109, 0x116b, 0,
+#undef V6554
+#define V6554 (V + 25308)
+ 0x1109, 0x116b, 0x11a8, 0,
+#undef V6555
+#define V6555 (V + 25312)
+ 0x1109, 0x116b, 0x11a9, 0,
+#undef V6556
+#define V6556 (V + 25316)
+ 0x1109, 0x116b, 0x11aa, 0,
+#undef V6557
+#define V6557 (V + 25320)
+ 0x1109, 0x116b, 0x11ab, 0,
+#undef V6558
+#define V6558 (V + 25324)
+ 0x1109, 0x116b, 0x11ac, 0,
+#undef V6559
+#define V6559 (V + 25328)
+ 0x1109, 0x116b, 0x11ad, 0,
+#undef V6560
+#define V6560 (V + 25332)
+ 0x1109, 0x116b, 0x11ae, 0,
+#undef V6561
+#define V6561 (V + 25336)
+ 0x1109, 0x116b, 0x11af, 0,
+#undef V6562
+#define V6562 (V + 25340)
+ 0x1109, 0x116b, 0x11b0, 0,
+#undef V6563
+#define V6563 (V + 25344)
+ 0x1109, 0x116b, 0x11b1, 0,
+#undef V6564
+#define V6564 (V + 25348)
+ 0x1109, 0x116b, 0x11b2, 0,
+#undef V6565
+#define V6565 (V + 25352)
+ 0x1109, 0x116b, 0x11b3, 0,
+#undef V6566
+#define V6566 (V + 25356)
+ 0x1109, 0x116b, 0x11b4, 0,
+#undef V6567
+#define V6567 (V + 25360)
+ 0x1109, 0x116b, 0x11b5, 0,
+#undef V6568
+#define V6568 (V + 25364)
+ 0x1109, 0x116b, 0x11b6, 0,
+#undef V6569
+#define V6569 (V + 25368)
+ 0x1109, 0x116b, 0x11b7, 0,
+#undef V6570
+#define V6570 (V + 25372)
+ 0x1109, 0x116b, 0x11b8, 0,
+#undef V6571
+#define V6571 (V + 25376)
+ 0x1109, 0x116b, 0x11b9, 0,
+#undef V6572
+#define V6572 (V + 25380)
+ 0x1109, 0x116b, 0x11ba, 0,
+#undef V6573
+#define V6573 (V + 25384)
+ 0x1109, 0x116b, 0x11bb, 0,
+#undef V6574
+#define V6574 (V + 25388)
+ 0x1109, 0x116b, 0x11bc, 0,
+#undef V6575
+#define V6575 (V + 25392)
+ 0x1109, 0x116b, 0x11bd, 0,
+#undef V6576
+#define V6576 (V + 25396)
+ 0x1109, 0x116b, 0x11be, 0,
+#undef V6577
+#define V6577 (V + 25400)
+ 0x1109, 0x116b, 0x11bf, 0,
+#undef V6578
+#define V6578 (V + 25404)
+ 0x1109, 0x116b, 0x11c0, 0,
+#undef V6579
+#define V6579 (V + 25408)
+ 0x1109, 0x116b, 0x11c1, 0,
+#undef V6580
+#define V6580 (V + 25412)
+ 0x1109, 0x116b, 0x11c2, 0,
+#undef V6581
+#define V6581 (V + 25416)
+ 0x1109, 0x116c, 0,
+#undef V6582
+#define V6582 (V + 25419)
+ 0x1109, 0x116c, 0x11a8, 0,
+#undef V6583
+#define V6583 (V + 25423)
+ 0x1109, 0x116c, 0x11a9, 0,
+#undef V6584
+#define V6584 (V + 25427)
+ 0x1109, 0x116c, 0x11aa, 0,
+#undef V6585
+#define V6585 (V + 25431)
+ 0x1109, 0x116c, 0x11ab, 0,
+#undef V6586
+#define V6586 (V + 25435)
+ 0x1109, 0x116c, 0x11ac, 0,
+#undef V6587
+#define V6587 (V + 25439)
+ 0x1109, 0x116c, 0x11ad, 0,
+#undef V6588
+#define V6588 (V + 25443)
+ 0x1109, 0x116c, 0x11ae, 0,
+#undef V6589
+#define V6589 (V + 25447)
+ 0x1109, 0x116c, 0x11af, 0,
+#undef V6590
+#define V6590 (V + 25451)
+ 0x1109, 0x116c, 0x11b0, 0,
+#undef V6591
+#define V6591 (V + 25455)
+ 0x1109, 0x116c, 0x11b1, 0,
+#undef V6592
+#define V6592 (V + 25459)
+ 0x1109, 0x116c, 0x11b2, 0,
+#undef V6593
+#define V6593 (V + 25463)
+ 0x1109, 0x116c, 0x11b3, 0,
+#undef V6594
+#define V6594 (V + 25467)
+ 0x1109, 0x116c, 0x11b4, 0,
+#undef V6595
+#define V6595 (V + 25471)
+ 0x1109, 0x116c, 0x11b5, 0,
+#undef V6596
+#define V6596 (V + 25475)
+ 0x1109, 0x116c, 0x11b6, 0,
+#undef V6597
+#define V6597 (V + 25479)
+ 0x1109, 0x116c, 0x11b7, 0,
+#undef V6598
+#define V6598 (V + 25483)
+ 0x1109, 0x116c, 0x11b8, 0,
+#undef V6599
+#define V6599 (V + 25487)
+ 0x1109, 0x116c, 0x11b9, 0,
+#undef V6600
+#define V6600 (V + 25491)
+ 0x1109, 0x116c, 0x11ba, 0,
+#undef V6601
+#define V6601 (V + 25495)
+ 0x1109, 0x116c, 0x11bb, 0,
+#undef V6602
+#define V6602 (V + 25499)
+ 0x1109, 0x116c, 0x11bc, 0,
+#undef V6603
+#define V6603 (V + 25503)
+ 0x1109, 0x116c, 0x11bd, 0,
+#undef V6604
+#define V6604 (V + 25507)
+ 0x1109, 0x116c, 0x11be, 0,
+#undef V6605
+#define V6605 (V + 25511)
+ 0x1109, 0x116c, 0x11bf, 0,
+#undef V6606
+#define V6606 (V + 25515)
+ 0x1109, 0x116c, 0x11c0, 0,
+#undef V6607
+#define V6607 (V + 25519)
+ 0x1109, 0x116c, 0x11c1, 0,
+#undef V6608
+#define V6608 (V + 25523)
+ 0x1109, 0x116c, 0x11c2, 0,
+#undef V6609
+#define V6609 (V + 25527)
+ 0x1109, 0x116d, 0,
+#undef V6610
+#define V6610 (V + 25530)
+ 0x1109, 0x116d, 0x11a8, 0,
+#undef V6611
+#define V6611 (V + 25534)
+ 0x1109, 0x116d, 0x11a9, 0,
+#undef V6612
+#define V6612 (V + 25538)
+ 0x1109, 0x116d, 0x11aa, 0,
+#undef V6613
+#define V6613 (V + 25542)
+ 0x1109, 0x116d, 0x11ab, 0,
+#undef V6614
+#define V6614 (V + 25546)
+ 0x1109, 0x116d, 0x11ac, 0,
+#undef V6615
+#define V6615 (V + 25550)
+ 0x1109, 0x116d, 0x11ad, 0,
+#undef V6616
+#define V6616 (V + 25554)
+ 0x1109, 0x116d, 0x11ae, 0,
+#undef V6617
+#define V6617 (V + 25558)
+ 0x1109, 0x116d, 0x11af, 0,
+#undef V6618
+#define V6618 (V + 25562)
+ 0x1109, 0x116d, 0x11b0, 0,
+#undef V6619
+#define V6619 (V + 25566)
+ 0x1109, 0x116d, 0x11b1, 0,
+#undef V6620
+#define V6620 (V + 25570)
+ 0x1109, 0x116d, 0x11b2, 0,
+#undef V6621
+#define V6621 (V + 25574)
+ 0x1109, 0x116d, 0x11b3, 0,
+#undef V6622
+#define V6622 (V + 25578)
+ 0x1109, 0x116d, 0x11b4, 0,
+#undef V6623
+#define V6623 (V + 25582)
+ 0x1109, 0x116d, 0x11b5, 0,
+#undef V6624
+#define V6624 (V + 25586)
+ 0x1109, 0x116d, 0x11b6, 0,
+#undef V6625
+#define V6625 (V + 25590)
+ 0x1109, 0x116d, 0x11b7, 0,
+#undef V6626
+#define V6626 (V + 25594)
+ 0x1109, 0x116d, 0x11b8, 0,
+#undef V6627
+#define V6627 (V + 25598)
+ 0x1109, 0x116d, 0x11b9, 0,
+#undef V6628
+#define V6628 (V + 25602)
+ 0x1109, 0x116d, 0x11ba, 0,
+#undef V6629
+#define V6629 (V + 25606)
+ 0x1109, 0x116d, 0x11bb, 0,
+#undef V6630
+#define V6630 (V + 25610)
+ 0x1109, 0x116d, 0x11bc, 0,
+#undef V6631
+#define V6631 (V + 25614)
+ 0x1109, 0x116d, 0x11bd, 0,
+#undef V6632
+#define V6632 (V + 25618)
+ 0x1109, 0x116d, 0x11be, 0,
+#undef V6633
+#define V6633 (V + 25622)
+ 0x1109, 0x116d, 0x11bf, 0,
+#undef V6634
+#define V6634 (V + 25626)
+ 0x1109, 0x116d, 0x11c0, 0,
+#undef V6635
+#define V6635 (V + 25630)
+ 0x1109, 0x116d, 0x11c1, 0,
+#undef V6636
+#define V6636 (V + 25634)
+ 0x1109, 0x116d, 0x11c2, 0,
+#undef V6637
+#define V6637 (V + 25638)
+ 0x1109, 0x116e, 0,
+#undef V6638
+#define V6638 (V + 25641)
+ 0x1109, 0x116e, 0x11a8, 0,
+#undef V6639
+#define V6639 (V + 25645)
+ 0x1109, 0x116e, 0x11a9, 0,
+#undef V6640
+#define V6640 (V + 25649)
+ 0x1109, 0x116e, 0x11aa, 0,
+#undef V6641
+#define V6641 (V + 25653)
+ 0x1109, 0x116e, 0x11ab, 0,
+#undef V6642
+#define V6642 (V + 25657)
+ 0x1109, 0x116e, 0x11ac, 0,
+#undef V6643
+#define V6643 (V + 25661)
+ 0x1109, 0x116e, 0x11ad, 0,
+#undef V6644
+#define V6644 (V + 25665)
+ 0x1109, 0x116e, 0x11ae, 0,
+#undef V6645
+#define V6645 (V + 25669)
+ 0x1109, 0x116e, 0x11af, 0,
+#undef V6646
+#define V6646 (V + 25673)
+ 0x1109, 0x116e, 0x11b0, 0,
+#undef V6647
+#define V6647 (V + 25677)
+ 0x1109, 0x116e, 0x11b1, 0,
+#undef V6648
+#define V6648 (V + 25681)
+ 0x1109, 0x116e, 0x11b2, 0,
+#undef V6649
+#define V6649 (V + 25685)
+ 0x1109, 0x116e, 0x11b3, 0,
+#undef V6650
+#define V6650 (V + 25689)
+ 0x1109, 0x116e, 0x11b4, 0,
+#undef V6651
+#define V6651 (V + 25693)
+ 0x1109, 0x116e, 0x11b5, 0,
+#undef V6652
+#define V6652 (V + 25697)
+ 0x1109, 0x116e, 0x11b6, 0,
+#undef V6653
+#define V6653 (V + 25701)
+ 0x1109, 0x116e, 0x11b7, 0,
+#undef V6654
+#define V6654 (V + 25705)
+ 0x1109, 0x116e, 0x11b8, 0,
+#undef V6655
+#define V6655 (V + 25709)
+ 0x1109, 0x116e, 0x11b9, 0,
+#undef V6656
+#define V6656 (V + 25713)
+ 0x1109, 0x116e, 0x11ba, 0,
+#undef V6657
+#define V6657 (V + 25717)
+ 0x1109, 0x116e, 0x11bb, 0,
+#undef V6658
+#define V6658 (V + 25721)
+ 0x1109, 0x116e, 0x11bc, 0,
+#undef V6659
+#define V6659 (V + 25725)
+ 0x1109, 0x116e, 0x11bd, 0,
+#undef V6660
+#define V6660 (V + 25729)
+ 0x1109, 0x116e, 0x11be, 0,
+#undef V6661
+#define V6661 (V + 25733)
+ 0x1109, 0x116e, 0x11bf, 0,
+#undef V6662
+#define V6662 (V + 25737)
+ 0x1109, 0x116e, 0x11c0, 0,
+#undef V6663
+#define V6663 (V + 25741)
+ 0x1109, 0x116e, 0x11c1, 0,
+#undef V6664
+#define V6664 (V + 25745)
+ 0x1109, 0x116e, 0x11c2, 0,
+#undef V6665
+#define V6665 (V + 25749)
+ 0x1109, 0x116f, 0,
+#undef V6666
+#define V6666 (V + 25752)
+ 0x1109, 0x116f, 0x11a8, 0,
+#undef V6667
+#define V6667 (V + 25756)
+ 0x1109, 0x116f, 0x11a9, 0,
+#undef V6668
+#define V6668 (V + 25760)
+ 0x1109, 0x116f, 0x11aa, 0,
+#undef V6669
+#define V6669 (V + 25764)
+ 0x1109, 0x116f, 0x11ab, 0,
+#undef V6670
+#define V6670 (V + 25768)
+ 0x1109, 0x116f, 0x11ac, 0,
+#undef V6671
+#define V6671 (V + 25772)
+ 0x1109, 0x116f, 0x11ad, 0,
+#undef V6672
+#define V6672 (V + 25776)
+ 0x1109, 0x116f, 0x11ae, 0,
+#undef V6673
+#define V6673 (V + 25780)
+ 0x1109, 0x116f, 0x11af, 0,
+#undef V6674
+#define V6674 (V + 25784)
+ 0x1109, 0x116f, 0x11b0, 0,
+#undef V6675
+#define V6675 (V + 25788)
+ 0x1109, 0x116f, 0x11b1, 0,
+#undef V6676
+#define V6676 (V + 25792)
+ 0x1109, 0x116f, 0x11b2, 0,
+#undef V6677
+#define V6677 (V + 25796)
+ 0x1109, 0x116f, 0x11b3, 0,
+#undef V6678
+#define V6678 (V + 25800)
+ 0x1109, 0x116f, 0x11b4, 0,
+#undef V6679
+#define V6679 (V + 25804)
+ 0x1109, 0x116f, 0x11b5, 0,
+#undef V6680
+#define V6680 (V + 25808)
+ 0x1109, 0x116f, 0x11b6, 0,
+#undef V6681
+#define V6681 (V + 25812)
+ 0x1109, 0x116f, 0x11b7, 0,
+#undef V6682
+#define V6682 (V + 25816)
+ 0x1109, 0x116f, 0x11b8, 0,
+#undef V6683
+#define V6683 (V + 25820)
+ 0x1109, 0x116f, 0x11b9, 0,
+#undef V6684
+#define V6684 (V + 25824)
+ 0x1109, 0x116f, 0x11ba, 0,
+#undef V6685
+#define V6685 (V + 25828)
+ 0x1109, 0x116f, 0x11bb, 0,
+#undef V6686
+#define V6686 (V + 25832)
+ 0x1109, 0x116f, 0x11bc, 0,
+#undef V6687
+#define V6687 (V + 25836)
+ 0x1109, 0x116f, 0x11bd, 0,
+#undef V6688
+#define V6688 (V + 25840)
+ 0x1109, 0x116f, 0x11be, 0,
+#undef V6689
+#define V6689 (V + 25844)
+ 0x1109, 0x116f, 0x11bf, 0,
+#undef V6690
+#define V6690 (V + 25848)
+ 0x1109, 0x116f, 0x11c0, 0,
+#undef V6691
+#define V6691 (V + 25852)
+ 0x1109, 0x116f, 0x11c1, 0,
+#undef V6692
+#define V6692 (V + 25856)
+ 0x1109, 0x116f, 0x11c2, 0,
+#undef V6693
+#define V6693 (V + 25860)
+ 0x1109, 0x1170, 0,
+#undef V6694
+#define V6694 (V + 25863)
+ 0x1109, 0x1170, 0x11a8, 0,
+#undef V6695
+#define V6695 (V + 25867)
+ 0x1109, 0x1170, 0x11a9, 0,
+#undef V6696
+#define V6696 (V + 25871)
+ 0x1109, 0x1170, 0x11aa, 0,
+#undef V6697
+#define V6697 (V + 25875)
+ 0x1109, 0x1170, 0x11ab, 0,
+#undef V6698
+#define V6698 (V + 25879)
+ 0x1109, 0x1170, 0x11ac, 0,
+#undef V6699
+#define V6699 (V + 25883)
+ 0x1109, 0x1170, 0x11ad, 0,
+#undef V6700
+#define V6700 (V + 25887)
+ 0x1109, 0x1170, 0x11ae, 0,
+#undef V6701
+#define V6701 (V + 25891)
+ 0x1109, 0x1170, 0x11af, 0,
+#undef V6702
+#define V6702 (V + 25895)
+ 0x1109, 0x1170, 0x11b0, 0,
+#undef V6703
+#define V6703 (V + 25899)
+ 0x1109, 0x1170, 0x11b1, 0,
+#undef V6704
+#define V6704 (V + 25903)
+ 0x1109, 0x1170, 0x11b2, 0,
+#undef V6705
+#define V6705 (V + 25907)
+ 0x1109, 0x1170, 0x11b3, 0,
+#undef V6706
+#define V6706 (V + 25911)
+ 0x1109, 0x1170, 0x11b4, 0,
+#undef V6707
+#define V6707 (V + 25915)
+ 0x1109, 0x1170, 0x11b5, 0,
+#undef V6708
+#define V6708 (V + 25919)
+ 0x1109, 0x1170, 0x11b6, 0,
+#undef V6709
+#define V6709 (V + 25923)
+ 0x1109, 0x1170, 0x11b7, 0,
+#undef V6710
+#define V6710 (V + 25927)
+ 0x1109, 0x1170, 0x11b8, 0,
+#undef V6711
+#define V6711 (V + 25931)
+ 0x1109, 0x1170, 0x11b9, 0,
+#undef V6712
+#define V6712 (V + 25935)
+ 0x1109, 0x1170, 0x11ba, 0,
+#undef V6713
+#define V6713 (V + 25939)
+ 0x1109, 0x1170, 0x11bb, 0,
+#undef V6714
+#define V6714 (V + 25943)
+ 0x1109, 0x1170, 0x11bc, 0,
+#undef V6715
+#define V6715 (V + 25947)
+ 0x1109, 0x1170, 0x11bd, 0,
+#undef V6716
+#define V6716 (V + 25951)
+ 0x1109, 0x1170, 0x11be, 0,
+#undef V6717
+#define V6717 (V + 25955)
+ 0x1109, 0x1170, 0x11bf, 0,
+#undef V6718
+#define V6718 (V + 25959)
+ 0x1109, 0x1170, 0x11c0, 0,
+#undef V6719
+#define V6719 (V + 25963)
+ 0x1109, 0x1170, 0x11c1, 0,
+#undef V6720
+#define V6720 (V + 25967)
+ 0x1109, 0x1170, 0x11c2, 0,
+#undef V6721
+#define V6721 (V + 25971)
+ 0x1109, 0x1171, 0,
+#undef V6722
+#define V6722 (V + 25974)
+ 0x1109, 0x1171, 0x11a8, 0,
+#undef V6723
+#define V6723 (V + 25978)
+ 0x1109, 0x1171, 0x11a9, 0,
+#undef V6724
+#define V6724 (V + 25982)
+ 0x1109, 0x1171, 0x11aa, 0,
+#undef V6725
+#define V6725 (V + 25986)
+ 0x1109, 0x1171, 0x11ab, 0,
+#undef V6726
+#define V6726 (V + 25990)
+ 0x1109, 0x1171, 0x11ac, 0,
+#undef V6727
+#define V6727 (V + 25994)
+ 0x1109, 0x1171, 0x11ad, 0,
+#undef V6728
+#define V6728 (V + 25998)
+ 0x1109, 0x1171, 0x11ae, 0,
+#undef V6729
+#define V6729 (V + 26002)
+ 0x1109, 0x1171, 0x11af, 0,
+#undef V6730
+#define V6730 (V + 26006)
+ 0x1109, 0x1171, 0x11b0, 0,
+#undef V6731
+#define V6731 (V + 26010)
+ 0x1109, 0x1171, 0x11b1, 0,
+#undef V6732
+#define V6732 (V + 26014)
+ 0x1109, 0x1171, 0x11b2, 0,
+#undef V6733
+#define V6733 (V + 26018)
+ 0x1109, 0x1171, 0x11b3, 0,
+#undef V6734
+#define V6734 (V + 26022)
+ 0x1109, 0x1171, 0x11b4, 0,
+#undef V6735
+#define V6735 (V + 26026)
+ 0x1109, 0x1171, 0x11b5, 0,
+#undef V6736
+#define V6736 (V + 26030)
+ 0x1109, 0x1171, 0x11b6, 0,
+#undef V6737
+#define V6737 (V + 26034)
+ 0x1109, 0x1171, 0x11b7, 0,
+#undef V6738
+#define V6738 (V + 26038)
+ 0x1109, 0x1171, 0x11b8, 0,
+#undef V6739
+#define V6739 (V + 26042)
+ 0x1109, 0x1171, 0x11b9, 0,
+#undef V6740
+#define V6740 (V + 26046)
+ 0x1109, 0x1171, 0x11ba, 0,
+#undef V6741
+#define V6741 (V + 26050)
+ 0x1109, 0x1171, 0x11bb, 0,
+#undef V6742
+#define V6742 (V + 26054)
+ 0x1109, 0x1171, 0x11bc, 0,
+#undef V6743
+#define V6743 (V + 26058)
+ 0x1109, 0x1171, 0x11bd, 0,
+#undef V6744
+#define V6744 (V + 26062)
+ 0x1109, 0x1171, 0x11be, 0,
+#undef V6745
+#define V6745 (V + 26066)
+ 0x1109, 0x1171, 0x11bf, 0,
+#undef V6746
+#define V6746 (V + 26070)
+ 0x1109, 0x1171, 0x11c0, 0,
+#undef V6747
+#define V6747 (V + 26074)
+ 0x1109, 0x1171, 0x11c1, 0,
+#undef V6748
+#define V6748 (V + 26078)
+ 0x1109, 0x1171, 0x11c2, 0,
+#undef V6749
+#define V6749 (V + 26082)
+ 0x1109, 0x1172, 0,
+#undef V6750
+#define V6750 (V + 26085)
+ 0x1109, 0x1172, 0x11a8, 0,
+#undef V6751
+#define V6751 (V + 26089)
+ 0x1109, 0x1172, 0x11a9, 0,
+#undef V6752
+#define V6752 (V + 26093)
+ 0x1109, 0x1172, 0x11aa, 0,
+#undef V6753
+#define V6753 (V + 26097)
+ 0x1109, 0x1172, 0x11ab, 0,
+#undef V6754
+#define V6754 (V + 26101)
+ 0x1109, 0x1172, 0x11ac, 0,
+#undef V6755
+#define V6755 (V + 26105)
+ 0x1109, 0x1172, 0x11ad, 0,
+#undef V6756
+#define V6756 (V + 26109)
+ 0x1109, 0x1172, 0x11ae, 0,
+#undef V6757
+#define V6757 (V + 26113)
+ 0x1109, 0x1172, 0x11af, 0,
+#undef V6758
+#define V6758 (V + 26117)
+ 0x1109, 0x1172, 0x11b0, 0,
+#undef V6759
+#define V6759 (V + 26121)
+ 0x1109, 0x1172, 0x11b1, 0,
+#undef V6760
+#define V6760 (V + 26125)
+ 0x1109, 0x1172, 0x11b2, 0,
+#undef V6761
+#define V6761 (V + 26129)
+ 0x1109, 0x1172, 0x11b3, 0,
+#undef V6762
+#define V6762 (V + 26133)
+ 0x1109, 0x1172, 0x11b4, 0,
+#undef V6763
+#define V6763 (V + 26137)
+ 0x1109, 0x1172, 0x11b5, 0,
+#undef V6764
+#define V6764 (V + 26141)
+ 0x1109, 0x1172, 0x11b6, 0,
+#undef V6765
+#define V6765 (V + 26145)
+ 0x1109, 0x1172, 0x11b7, 0,
+#undef V6766
+#define V6766 (V + 26149)
+ 0x1109, 0x1172, 0x11b8, 0,
+#undef V6767
+#define V6767 (V + 26153)
+ 0x1109, 0x1172, 0x11b9, 0,
+#undef V6768
+#define V6768 (V + 26157)
+ 0x1109, 0x1172, 0x11ba, 0,
+#undef V6769
+#define V6769 (V + 26161)
+ 0x1109, 0x1172, 0x11bb, 0,
+#undef V6770
+#define V6770 (V + 26165)
+ 0x1109, 0x1172, 0x11bc, 0,
+#undef V6771
+#define V6771 (V + 26169)
+ 0x1109, 0x1172, 0x11bd, 0,
+#undef V6772
+#define V6772 (V + 26173)
+ 0x1109, 0x1172, 0x11be, 0,
+#undef V6773
+#define V6773 (V + 26177)
+ 0x1109, 0x1172, 0x11bf, 0,
+#undef V6774
+#define V6774 (V + 26181)
+ 0x1109, 0x1172, 0x11c0, 0,
+#undef V6775
+#define V6775 (V + 26185)
+ 0x1109, 0x1172, 0x11c1, 0,
+#undef V6776
+#define V6776 (V + 26189)
+ 0x1109, 0x1172, 0x11c2, 0,
+#undef V6777
+#define V6777 (V + 26193)
+ 0x1109, 0x1173, 0,
+#undef V6778
+#define V6778 (V + 26196)
+ 0x1109, 0x1173, 0x11a8, 0,
+#undef V6779
+#define V6779 (V + 26200)
+ 0x1109, 0x1173, 0x11a9, 0,
+#undef V6780
+#define V6780 (V + 26204)
+ 0x1109, 0x1173, 0x11aa, 0,
+#undef V6781
+#define V6781 (V + 26208)
+ 0x1109, 0x1173, 0x11ab, 0,
+#undef V6782
+#define V6782 (V + 26212)
+ 0x1109, 0x1173, 0x11ac, 0,
+#undef V6783
+#define V6783 (V + 26216)
+ 0x1109, 0x1173, 0x11ad, 0,
+#undef V6784
+#define V6784 (V + 26220)
+ 0x1109, 0x1173, 0x11ae, 0,
+#undef V6785
+#define V6785 (V + 26224)
+ 0x1109, 0x1173, 0x11af, 0,
+#undef V6786
+#define V6786 (V + 26228)
+ 0x1109, 0x1173, 0x11b0, 0,
+#undef V6787
+#define V6787 (V + 26232)
+ 0x1109, 0x1173, 0x11b1, 0,
+#undef V6788
+#define V6788 (V + 26236)
+ 0x1109, 0x1173, 0x11b2, 0,
+#undef V6789
+#define V6789 (V + 26240)
+ 0x1109, 0x1173, 0x11b3, 0,
+#undef V6790
+#define V6790 (V + 26244)
+ 0x1109, 0x1173, 0x11b4, 0,
+#undef V6791
+#define V6791 (V + 26248)
+ 0x1109, 0x1173, 0x11b5, 0,
+#undef V6792
+#define V6792 (V + 26252)
+ 0x1109, 0x1173, 0x11b6, 0,
+#undef V6793
+#define V6793 (V + 26256)
+ 0x1109, 0x1173, 0x11b7, 0,
+#undef V6794
+#define V6794 (V + 26260)
+ 0x1109, 0x1173, 0x11b8, 0,
+#undef V6795
+#define V6795 (V + 26264)
+ 0x1109, 0x1173, 0x11b9, 0,
+#undef V6796
+#define V6796 (V + 26268)
+ 0x1109, 0x1173, 0x11ba, 0,
+#undef V6797
+#define V6797 (V + 26272)
+ 0x1109, 0x1173, 0x11bb, 0,
+#undef V6798
+#define V6798 (V + 26276)
+ 0x1109, 0x1173, 0x11bc, 0,
+#undef V6799
+#define V6799 (V + 26280)
+ 0x1109, 0x1173, 0x11bd, 0,
+#undef V6800
+#define V6800 (V + 26284)
+ 0x1109, 0x1173, 0x11be, 0,
+#undef V6801
+#define V6801 (V + 26288)
+ 0x1109, 0x1173, 0x11bf, 0,
+#undef V6802
+#define V6802 (V + 26292)
+ 0x1109, 0x1173, 0x11c0, 0,
+#undef V6803
+#define V6803 (V + 26296)
+ 0x1109, 0x1173, 0x11c1, 0,
+#undef V6804
+#define V6804 (V + 26300)
+ 0x1109, 0x1173, 0x11c2, 0,
+#undef V6805
+#define V6805 (V + 26304)
+ 0x1109, 0x1174, 0,
+#undef V6806
+#define V6806 (V + 26307)
+ 0x1109, 0x1174, 0x11a8, 0,
+#undef V6807
+#define V6807 (V + 26311)
+ 0x1109, 0x1174, 0x11a9, 0,
+#undef V6808
+#define V6808 (V + 26315)
+ 0x1109, 0x1174, 0x11aa, 0,
+#undef V6809
+#define V6809 (V + 26319)
+ 0x1109, 0x1174, 0x11ab, 0,
+#undef V6810
+#define V6810 (V + 26323)
+ 0x1109, 0x1174, 0x11ac, 0,
+#undef V6811
+#define V6811 (V + 26327)
+ 0x1109, 0x1174, 0x11ad, 0,
+#undef V6812
+#define V6812 (V + 26331)
+ 0x1109, 0x1174, 0x11ae, 0,
+#undef V6813
+#define V6813 (V + 26335)
+ 0x1109, 0x1174, 0x11af, 0,
+#undef V6814
+#define V6814 (V + 26339)
+ 0x1109, 0x1174, 0x11b0, 0,
+#undef V6815
+#define V6815 (V + 26343)
+ 0x1109, 0x1174, 0x11b1, 0,
+#undef V6816
+#define V6816 (V + 26347)
+ 0x1109, 0x1174, 0x11b2, 0,
+#undef V6817
+#define V6817 (V + 26351)
+ 0x1109, 0x1174, 0x11b3, 0,
+#undef V6818
+#define V6818 (V + 26355)
+ 0x1109, 0x1174, 0x11b4, 0,
+#undef V6819
+#define V6819 (V + 26359)
+ 0x1109, 0x1174, 0x11b5, 0,
+#undef V6820
+#define V6820 (V + 26363)
+ 0x1109, 0x1174, 0x11b6, 0,
+#undef V6821
+#define V6821 (V + 26367)
+ 0x1109, 0x1174, 0x11b7, 0,
+#undef V6822
+#define V6822 (V + 26371)
+ 0x1109, 0x1174, 0x11b8, 0,
+#undef V6823
+#define V6823 (V + 26375)
+ 0x1109, 0x1174, 0x11b9, 0,
+#undef V6824
+#define V6824 (V + 26379)
+ 0x1109, 0x1174, 0x11ba, 0,
+#undef V6825
+#define V6825 (V + 26383)
+ 0x1109, 0x1174, 0x11bb, 0,
+#undef V6826
+#define V6826 (V + 26387)
+ 0x1109, 0x1174, 0x11bc, 0,
+#undef V6827
+#define V6827 (V + 26391)
+ 0x1109, 0x1174, 0x11bd, 0,
+#undef V6828
+#define V6828 (V + 26395)
+ 0x1109, 0x1174, 0x11be, 0,
+#undef V6829
+#define V6829 (V + 26399)
+ 0x1109, 0x1174, 0x11bf, 0,
+#undef V6830
+#define V6830 (V + 26403)
+ 0x1109, 0x1174, 0x11c0, 0,
+#undef V6831
+#define V6831 (V + 26407)
+ 0x1109, 0x1174, 0x11c1, 0,
+#undef V6832
+#define V6832 (V + 26411)
+ 0x1109, 0x1174, 0x11c2, 0,
+#undef V6833
+#define V6833 (V + 26415)
+ 0x1109, 0x1175, 0,
+#undef V6834
+#define V6834 (V + 26418)
+ 0x1109, 0x1175, 0x11a8, 0,
+#undef V6835
+#define V6835 (V + 26422)
+ 0x1109, 0x1175, 0x11a9, 0,
+#undef V6836
+#define V6836 (V + 26426)
+ 0x1109, 0x1175, 0x11aa, 0,
+#undef V6837
+#define V6837 (V + 26430)
+ 0x1109, 0x1175, 0x11ab, 0,
+#undef V6838
+#define V6838 (V + 26434)
+ 0x1109, 0x1175, 0x11ac, 0,
+#undef V6839
+#define V6839 (V + 26438)
+ 0x1109, 0x1175, 0x11ad, 0,
+#undef V6840
+#define V6840 (V + 26442)
+ 0x1109, 0x1175, 0x11ae, 0,
+#undef V6841
+#define V6841 (V + 26446)
+ 0x1109, 0x1175, 0x11af, 0,
+#undef V6842
+#define V6842 (V + 26450)
+ 0x1109, 0x1175, 0x11b0, 0,
+#undef V6843
+#define V6843 (V + 26454)
+ 0x1109, 0x1175, 0x11b1, 0,
+#undef V6844
+#define V6844 (V + 26458)
+ 0x1109, 0x1175, 0x11b2, 0,
+#undef V6845
+#define V6845 (V + 26462)
+ 0x1109, 0x1175, 0x11b3, 0,
+#undef V6846
+#define V6846 (V + 26466)
+ 0x1109, 0x1175, 0x11b4, 0,
+#undef V6847
+#define V6847 (V + 26470)
+ 0x1109, 0x1175, 0x11b5, 0,
+#undef V6848
+#define V6848 (V + 26474)
+ 0x1109, 0x1175, 0x11b6, 0,
+#undef V6849
+#define V6849 (V + 26478)
+ 0x1109, 0x1175, 0x11b7, 0,
+#undef V6850
+#define V6850 (V + 26482)
+ 0x1109, 0x1175, 0x11b8, 0,
+#undef V6851
+#define V6851 (V + 26486)
+ 0x1109, 0x1175, 0x11b9, 0,
+#undef V6852
+#define V6852 (V + 26490)
+ 0x1109, 0x1175, 0x11ba, 0,
+#undef V6853
+#define V6853 (V + 26494)
+ 0x1109, 0x1175, 0x11bb, 0,
+#undef V6854
+#define V6854 (V + 26498)
+ 0x1109, 0x1175, 0x11bc, 0,
+#undef V6855
+#define V6855 (V + 26502)
+ 0x1109, 0x1175, 0x11bd, 0,
+#undef V6856
+#define V6856 (V + 26506)
+ 0x1109, 0x1175, 0x11be, 0,
+#undef V6857
+#define V6857 (V + 26510)
+ 0x1109, 0x1175, 0x11bf, 0,
+#undef V6858
+#define V6858 (V + 26514)
+ 0x1109, 0x1175, 0x11c0, 0,
+#undef V6859
+#define V6859 (V + 26518)
+ 0x1109, 0x1175, 0x11c1, 0,
+#undef V6860
+#define V6860 (V + 26522)
+ 0x1109, 0x1175, 0x11c2, 0,
+#undef V6861
+#define V6861 (V + 26526)
+ 0x110a, 0x1161, 0,
+#undef V6862
+#define V6862 (V + 26529)
+ 0x110a, 0x1161, 0x11a8, 0,
+#undef V6863
+#define V6863 (V + 26533)
+ 0x110a, 0x1161, 0x11a9, 0,
+#undef V6864
+#define V6864 (V + 26537)
+ 0x110a, 0x1161, 0x11aa, 0,
+#undef V6865
+#define V6865 (V + 26541)
+ 0x110a, 0x1161, 0x11ab, 0,
+#undef V6866
+#define V6866 (V + 26545)
+ 0x110a, 0x1161, 0x11ac, 0,
+#undef V6867
+#define V6867 (V + 26549)
+ 0x110a, 0x1161, 0x11ad, 0,
+#undef V6868
+#define V6868 (V + 26553)
+ 0x110a, 0x1161, 0x11ae, 0,
+#undef V6869
+#define V6869 (V + 26557)
+ 0x110a, 0x1161, 0x11af, 0,
+#undef V6870
+#define V6870 (V + 26561)
+ 0x110a, 0x1161, 0x11b0, 0,
+#undef V6871
+#define V6871 (V + 26565)
+ 0x110a, 0x1161, 0x11b1, 0,
+#undef V6872
+#define V6872 (V + 26569)
+ 0x110a, 0x1161, 0x11b2, 0,
+#undef V6873
+#define V6873 (V + 26573)
+ 0x110a, 0x1161, 0x11b3, 0,
+#undef V6874
+#define V6874 (V + 26577)
+ 0x110a, 0x1161, 0x11b4, 0,
+#undef V6875
+#define V6875 (V + 26581)
+ 0x110a, 0x1161, 0x11b5, 0,
+#undef V6876
+#define V6876 (V + 26585)
+ 0x110a, 0x1161, 0x11b6, 0,
+#undef V6877
+#define V6877 (V + 26589)
+ 0x110a, 0x1161, 0x11b7, 0,
+#undef V6878
+#define V6878 (V + 26593)
+ 0x110a, 0x1161, 0x11b8, 0,
+#undef V6879
+#define V6879 (V + 26597)
+ 0x110a, 0x1161, 0x11b9, 0,
+#undef V6880
+#define V6880 (V + 26601)
+ 0x110a, 0x1161, 0x11ba, 0,
+#undef V6881
+#define V6881 (V + 26605)
+ 0x110a, 0x1161, 0x11bb, 0,
+#undef V6882
+#define V6882 (V + 26609)
+ 0x110a, 0x1161, 0x11bc, 0,
+#undef V6883
+#define V6883 (V + 26613)
+ 0x110a, 0x1161, 0x11bd, 0,
+#undef V6884
+#define V6884 (V + 26617)
+ 0x110a, 0x1161, 0x11be, 0,
+#undef V6885
+#define V6885 (V + 26621)
+ 0x110a, 0x1161, 0x11bf, 0,
+#undef V6886
+#define V6886 (V + 26625)
+ 0x110a, 0x1161, 0x11c0, 0,
+#undef V6887
+#define V6887 (V + 26629)
+ 0x110a, 0x1161, 0x11c1, 0,
+#undef V6888
+#define V6888 (V + 26633)
+ 0x110a, 0x1161, 0x11c2, 0,
+#undef V6889
+#define V6889 (V + 26637)
+ 0x110a, 0x1162, 0,
+#undef V6890
+#define V6890 (V + 26640)
+ 0x110a, 0x1162, 0x11a8, 0,
+#undef V6891
+#define V6891 (V + 26644)
+ 0x110a, 0x1162, 0x11a9, 0,
+#undef V6892
+#define V6892 (V + 26648)
+ 0x110a, 0x1162, 0x11aa, 0,
+#undef V6893
+#define V6893 (V + 26652)
+ 0x110a, 0x1162, 0x11ab, 0,
+#undef V6894
+#define V6894 (V + 26656)
+ 0x110a, 0x1162, 0x11ac, 0,
+#undef V6895
+#define V6895 (V + 26660)
+ 0x110a, 0x1162, 0x11ad, 0,
+#undef V6896
+#define V6896 (V + 26664)
+ 0x110a, 0x1162, 0x11ae, 0,
+#undef V6897
+#define V6897 (V + 26668)
+ 0x110a, 0x1162, 0x11af, 0,
+#undef V6898
+#define V6898 (V + 26672)
+ 0x110a, 0x1162, 0x11b0, 0,
+#undef V6899
+#define V6899 (V + 26676)
+ 0x110a, 0x1162, 0x11b1, 0,
+#undef V6900
+#define V6900 (V + 26680)
+ 0x110a, 0x1162, 0x11b2, 0,
+#undef V6901
+#define V6901 (V + 26684)
+ 0x110a, 0x1162, 0x11b3, 0,
+#undef V6902
+#define V6902 (V + 26688)
+ 0x110a, 0x1162, 0x11b4, 0,
+#undef V6903
+#define V6903 (V + 26692)
+ 0x110a, 0x1162, 0x11b5, 0,
+#undef V6904
+#define V6904 (V + 26696)
+ 0x110a, 0x1162, 0x11b6, 0,
+#undef V6905
+#define V6905 (V + 26700)
+ 0x110a, 0x1162, 0x11b7, 0,
+#undef V6906
+#define V6906 (V + 26704)
+ 0x110a, 0x1162, 0x11b8, 0,
+#undef V6907
+#define V6907 (V + 26708)
+ 0x110a, 0x1162, 0x11b9, 0,
+#undef V6908
+#define V6908 (V + 26712)
+ 0x110a, 0x1162, 0x11ba, 0,
+#undef V6909
+#define V6909 (V + 26716)
+ 0x110a, 0x1162, 0x11bb, 0,
+#undef V6910
+#define V6910 (V + 26720)
+ 0x110a, 0x1162, 0x11bc, 0,
+#undef V6911
+#define V6911 (V + 26724)
+ 0x110a, 0x1162, 0x11bd, 0,
+#undef V6912
+#define V6912 (V + 26728)
+ 0x110a, 0x1162, 0x11be, 0,
+#undef V6913
+#define V6913 (V + 26732)
+ 0x110a, 0x1162, 0x11bf, 0,
+#undef V6914
+#define V6914 (V + 26736)
+ 0x110a, 0x1162, 0x11c0, 0,
+#undef V6915
+#define V6915 (V + 26740)
+ 0x110a, 0x1162, 0x11c1, 0,
+#undef V6916
+#define V6916 (V + 26744)
+ 0x110a, 0x1162, 0x11c2, 0,
+#undef V6917
+#define V6917 (V + 26748)
+ 0x110a, 0x1163, 0,
+#undef V6918
+#define V6918 (V + 26751)
+ 0x110a, 0x1163, 0x11a8, 0,
+#undef V6919
+#define V6919 (V + 26755)
+ 0x110a, 0x1163, 0x11a9, 0,
+#undef V6920
+#define V6920 (V + 26759)
+ 0x110a, 0x1163, 0x11aa, 0,
+#undef V6921
+#define V6921 (V + 26763)
+ 0x110a, 0x1163, 0x11ab, 0,
+#undef V6922
+#define V6922 (V + 26767)
+ 0x110a, 0x1163, 0x11ac, 0,
+#undef V6923
+#define V6923 (V + 26771)
+ 0x110a, 0x1163, 0x11ad, 0,
+#undef V6924
+#define V6924 (V + 26775)
+ 0x110a, 0x1163, 0x11ae, 0,
+#undef V6925
+#define V6925 (V + 26779)
+ 0x110a, 0x1163, 0x11af, 0,
+#undef V6926
+#define V6926 (V + 26783)
+ 0x110a, 0x1163, 0x11b0, 0,
+#undef V6927
+#define V6927 (V + 26787)
+ 0x110a, 0x1163, 0x11b1, 0,
+#undef V6928
+#define V6928 (V + 26791)
+ 0x110a, 0x1163, 0x11b2, 0,
+#undef V6929
+#define V6929 (V + 26795)
+ 0x110a, 0x1163, 0x11b3, 0,
+#undef V6930
+#define V6930 (V + 26799)
+ 0x110a, 0x1163, 0x11b4, 0,
+#undef V6931
+#define V6931 (V + 26803)
+ 0x110a, 0x1163, 0x11b5, 0,
+#undef V6932
+#define V6932 (V + 26807)
+ 0x110a, 0x1163, 0x11b6, 0,
+#undef V6933
+#define V6933 (V + 26811)
+ 0x110a, 0x1163, 0x11b7, 0,
+#undef V6934
+#define V6934 (V + 26815)
+ 0x110a, 0x1163, 0x11b8, 0,
+#undef V6935
+#define V6935 (V + 26819)
+ 0x110a, 0x1163, 0x11b9, 0,
+#undef V6936
+#define V6936 (V + 26823)
+ 0x110a, 0x1163, 0x11ba, 0,
+#undef V6937
+#define V6937 (V + 26827)
+ 0x110a, 0x1163, 0x11bb, 0,
+#undef V6938
+#define V6938 (V + 26831)
+ 0x110a, 0x1163, 0x11bc, 0,
+#undef V6939
+#define V6939 (V + 26835)
+ 0x110a, 0x1163, 0x11bd, 0,
+#undef V6940
+#define V6940 (V + 26839)
+ 0x110a, 0x1163, 0x11be, 0,
+#undef V6941
+#define V6941 (V + 26843)
+ 0x110a, 0x1163, 0x11bf, 0,
+#undef V6942
+#define V6942 (V + 26847)
+ 0x110a, 0x1163, 0x11c0, 0,
+#undef V6943
+#define V6943 (V + 26851)
+ 0x110a, 0x1163, 0x11c1, 0,
+#undef V6944
+#define V6944 (V + 26855)
+ 0x110a, 0x1163, 0x11c2, 0,
+#undef V6945
+#define V6945 (V + 26859)
+ 0x110a, 0x1164, 0,
+#undef V6946
+#define V6946 (V + 26862)
+ 0x110a, 0x1164, 0x11a8, 0,
+#undef V6947
+#define V6947 (V + 26866)
+ 0x110a, 0x1164, 0x11a9, 0,
+#undef V6948
+#define V6948 (V + 26870)
+ 0x110a, 0x1164, 0x11aa, 0,
+#undef V6949
+#define V6949 (V + 26874)
+ 0x110a, 0x1164, 0x11ab, 0,
+#undef V6950
+#define V6950 (V + 26878)
+ 0x110a, 0x1164, 0x11ac, 0,
+#undef V6951
+#define V6951 (V + 26882)
+ 0x110a, 0x1164, 0x11ad, 0,
+#undef V6952
+#define V6952 (V + 26886)
+ 0x110a, 0x1164, 0x11ae, 0,
+#undef V6953
+#define V6953 (V + 26890)
+ 0x110a, 0x1164, 0x11af, 0,
+#undef V6954
+#define V6954 (V + 26894)
+ 0x110a, 0x1164, 0x11b0, 0,
+#undef V6955
+#define V6955 (V + 26898)
+ 0x110a, 0x1164, 0x11b1, 0,
+#undef V6956
+#define V6956 (V + 26902)
+ 0x110a, 0x1164, 0x11b2, 0,
+#undef V6957
+#define V6957 (V + 26906)
+ 0x110a, 0x1164, 0x11b3, 0,
+#undef V6958
+#define V6958 (V + 26910)
+ 0x110a, 0x1164, 0x11b4, 0,
+#undef V6959
+#define V6959 (V + 26914)
+ 0x110a, 0x1164, 0x11b5, 0,
+#undef V6960
+#define V6960 (V + 26918)
+ 0x110a, 0x1164, 0x11b6, 0,
+#undef V6961
+#define V6961 (V + 26922)
+ 0x110a, 0x1164, 0x11b7, 0,
+#undef V6962
+#define V6962 (V + 26926)
+ 0x110a, 0x1164, 0x11b8, 0,
+#undef V6963
+#define V6963 (V + 26930)
+ 0x110a, 0x1164, 0x11b9, 0,
+#undef V6964
+#define V6964 (V + 26934)
+ 0x110a, 0x1164, 0x11ba, 0,
+#undef V6965
+#define V6965 (V + 26938)
+ 0x110a, 0x1164, 0x11bb, 0,
+#undef V6966
+#define V6966 (V + 26942)
+ 0x110a, 0x1164, 0x11bc, 0,
+#undef V6967
+#define V6967 (V + 26946)
+ 0x110a, 0x1164, 0x11bd, 0,
+#undef V6968
+#define V6968 (V + 26950)
+ 0x110a, 0x1164, 0x11be, 0,
+#undef V6969
+#define V6969 (V + 26954)
+ 0x110a, 0x1164, 0x11bf, 0,
+#undef V6970
+#define V6970 (V + 26958)
+ 0x110a, 0x1164, 0x11c0, 0,
+#undef V6971
+#define V6971 (V + 26962)
+ 0x110a, 0x1164, 0x11c1, 0,
+#undef V6972
+#define V6972 (V + 26966)
+ 0x110a, 0x1164, 0x11c2, 0,
+#undef V6973
+#define V6973 (V + 26970)
+ 0x110a, 0x1165, 0,
+#undef V6974
+#define V6974 (V + 26973)
+ 0x110a, 0x1165, 0x11a8, 0,
+#undef V6975
+#define V6975 (V + 26977)
+ 0x110a, 0x1165, 0x11a9, 0,
+#undef V6976
+#define V6976 (V + 26981)
+ 0x110a, 0x1165, 0x11aa, 0,
+#undef V6977
+#define V6977 (V + 26985)
+ 0x110a, 0x1165, 0x11ab, 0,
+#undef V6978
+#define V6978 (V + 26989)
+ 0x110a, 0x1165, 0x11ac, 0,
+#undef V6979
+#define V6979 (V + 26993)
+ 0x110a, 0x1165, 0x11ad, 0,
+#undef V6980
+#define V6980 (V + 26997)
+ 0x110a, 0x1165, 0x11ae, 0,
+#undef V6981
+#define V6981 (V + 27001)
+ 0x110a, 0x1165, 0x11af, 0,
+#undef V6982
+#define V6982 (V + 27005)
+ 0x110a, 0x1165, 0x11b0, 0,
+#undef V6983
+#define V6983 (V + 27009)
+ 0x110a, 0x1165, 0x11b1, 0,
+#undef V6984
+#define V6984 (V + 27013)
+ 0x110a, 0x1165, 0x11b2, 0,
+#undef V6985
+#define V6985 (V + 27017)
+ 0x110a, 0x1165, 0x11b3, 0,
+#undef V6986
+#define V6986 (V + 27021)
+ 0x110a, 0x1165, 0x11b4, 0,
+#undef V6987
+#define V6987 (V + 27025)
+ 0x110a, 0x1165, 0x11b5, 0,
+#undef V6988
+#define V6988 (V + 27029)
+ 0x110a, 0x1165, 0x11b6, 0,
+#undef V6989
+#define V6989 (V + 27033)
+ 0x110a, 0x1165, 0x11b7, 0,
+#undef V6990
+#define V6990 (V + 27037)
+ 0x110a, 0x1165, 0x11b8, 0,
+#undef V6991
+#define V6991 (V + 27041)
+ 0x110a, 0x1165, 0x11b9, 0,
+#undef V6992
+#define V6992 (V + 27045)
+ 0x110a, 0x1165, 0x11ba, 0,
+#undef V6993
+#define V6993 (V + 27049)
+ 0x110a, 0x1165, 0x11bb, 0,
+#undef V6994
+#define V6994 (V + 27053)
+ 0x110a, 0x1165, 0x11bc, 0,
+#undef V6995
+#define V6995 (V + 27057)
+ 0x110a, 0x1165, 0x11bd, 0,
+#undef V6996
+#define V6996 (V + 27061)
+ 0x110a, 0x1165, 0x11be, 0,
+#undef V6997
+#define V6997 (V + 27065)
+ 0x110a, 0x1165, 0x11bf, 0,
+#undef V6998
+#define V6998 (V + 27069)
+ 0x110a, 0x1165, 0x11c0, 0,
+#undef V6999
+#define V6999 (V + 27073)
+ 0x110a, 0x1165, 0x11c1, 0,
+#undef V7000
+#define V7000 (V + 27077)
+ 0x110a, 0x1165, 0x11c2, 0,
+#undef V7001
+#define V7001 (V + 27081)
+ 0x110a, 0x1166, 0,
+#undef V7002
+#define V7002 (V + 27084)
+ 0x110a, 0x1166, 0x11a8, 0,
+#undef V7003
+#define V7003 (V + 27088)
+ 0x110a, 0x1166, 0x11a9, 0,
+#undef V7004
+#define V7004 (V + 27092)
+ 0x110a, 0x1166, 0x11aa, 0,
+#undef V7005
+#define V7005 (V + 27096)
+ 0x110a, 0x1166, 0x11ab, 0,
+#undef V7006
+#define V7006 (V + 27100)
+ 0x110a, 0x1166, 0x11ac, 0,
+#undef V7007
+#define V7007 (V + 27104)
+ 0x110a, 0x1166, 0x11ad, 0,
+#undef V7008
+#define V7008 (V + 27108)
+ 0x110a, 0x1166, 0x11ae, 0,
+#undef V7009
+#define V7009 (V + 27112)
+ 0x110a, 0x1166, 0x11af, 0,
+#undef V7010
+#define V7010 (V + 27116)
+ 0x110a, 0x1166, 0x11b0, 0,
+#undef V7011
+#define V7011 (V + 27120)
+ 0x110a, 0x1166, 0x11b1, 0,
+#undef V7012
+#define V7012 (V + 27124)
+ 0x110a, 0x1166, 0x11b2, 0,
+#undef V7013
+#define V7013 (V + 27128)
+ 0x110a, 0x1166, 0x11b3, 0,
+#undef V7014
+#define V7014 (V + 27132)
+ 0x110a, 0x1166, 0x11b4, 0,
+#undef V7015
+#define V7015 (V + 27136)
+ 0x110a, 0x1166, 0x11b5, 0,
+#undef V7016
+#define V7016 (V + 27140)
+ 0x110a, 0x1166, 0x11b6, 0,
+#undef V7017
+#define V7017 (V + 27144)
+ 0x110a, 0x1166, 0x11b7, 0,
+#undef V7018
+#define V7018 (V + 27148)
+ 0x110a, 0x1166, 0x11b8, 0,
+#undef V7019
+#define V7019 (V + 27152)
+ 0x110a, 0x1166, 0x11b9, 0,
+#undef V7020
+#define V7020 (V + 27156)
+ 0x110a, 0x1166, 0x11ba, 0,
+#undef V7021
+#define V7021 (V + 27160)
+ 0x110a, 0x1166, 0x11bb, 0,
+#undef V7022
+#define V7022 (V + 27164)
+ 0x110a, 0x1166, 0x11bc, 0,
+#undef V7023
+#define V7023 (V + 27168)
+ 0x110a, 0x1166, 0x11bd, 0,
+#undef V7024
+#define V7024 (V + 27172)
+ 0x110a, 0x1166, 0x11be, 0,
+#undef V7025
+#define V7025 (V + 27176)
+ 0x110a, 0x1166, 0x11bf, 0,
+#undef V7026
+#define V7026 (V + 27180)
+ 0x110a, 0x1166, 0x11c0, 0,
+#undef V7027
+#define V7027 (V + 27184)
+ 0x110a, 0x1166, 0x11c1, 0,
+#undef V7028
+#define V7028 (V + 27188)
+ 0x110a, 0x1166, 0x11c2, 0,
+#undef V7029
+#define V7029 (V + 27192)
+ 0x110a, 0x1167, 0,
+#undef V7030
+#define V7030 (V + 27195)
+ 0x110a, 0x1167, 0x11a8, 0,
+#undef V7031
+#define V7031 (V + 27199)
+ 0x110a, 0x1167, 0x11a9, 0,
+#undef V7032
+#define V7032 (V + 27203)
+ 0x110a, 0x1167, 0x11aa, 0,
+#undef V7033
+#define V7033 (V + 27207)
+ 0x110a, 0x1167, 0x11ab, 0,
+#undef V7034
+#define V7034 (V + 27211)
+ 0x110a, 0x1167, 0x11ac, 0,
+#undef V7035
+#define V7035 (V + 27215)
+ 0x110a, 0x1167, 0x11ad, 0,
+#undef V7036
+#define V7036 (V + 27219)
+ 0x110a, 0x1167, 0x11ae, 0,
+#undef V7037
+#define V7037 (V + 27223)
+ 0x110a, 0x1167, 0x11af, 0,
+#undef V7038
+#define V7038 (V + 27227)
+ 0x110a, 0x1167, 0x11b0, 0,
+#undef V7039
+#define V7039 (V + 27231)
+ 0x110a, 0x1167, 0x11b1, 0,
+#undef V7040
+#define V7040 (V + 27235)
+ 0x110a, 0x1167, 0x11b2, 0,
+#undef V7041
+#define V7041 (V + 27239)
+ 0x110a, 0x1167, 0x11b3, 0,
+#undef V7042
+#define V7042 (V + 27243)
+ 0x110a, 0x1167, 0x11b4, 0,
+#undef V7043
+#define V7043 (V + 27247)
+ 0x110a, 0x1167, 0x11b5, 0,
+#undef V7044
+#define V7044 (V + 27251)
+ 0x110a, 0x1167, 0x11b6, 0,
+#undef V7045
+#define V7045 (V + 27255)
+ 0x110a, 0x1167, 0x11b7, 0,
+#undef V7046
+#define V7046 (V + 27259)
+ 0x110a, 0x1167, 0x11b8, 0,
+#undef V7047
+#define V7047 (V + 27263)
+ 0x110a, 0x1167, 0x11b9, 0,
+#undef V7048
+#define V7048 (V + 27267)
+ 0x110a, 0x1167, 0x11ba, 0,
+#undef V7049
+#define V7049 (V + 27271)
+ 0x110a, 0x1167, 0x11bb, 0,
+#undef V7050
+#define V7050 (V + 27275)
+ 0x110a, 0x1167, 0x11bc, 0,
+#undef V7051
+#define V7051 (V + 27279)
+ 0x110a, 0x1167, 0x11bd, 0,
+#undef V7052
+#define V7052 (V + 27283)
+ 0x110a, 0x1167, 0x11be, 0,
+#undef V7053
+#define V7053 (V + 27287)
+ 0x110a, 0x1167, 0x11bf, 0,
+#undef V7054
+#define V7054 (V + 27291)
+ 0x110a, 0x1167, 0x11c0, 0,
+#undef V7055
+#define V7055 (V + 27295)
+ 0x110a, 0x1167, 0x11c1, 0,
+#undef V7056
+#define V7056 (V + 27299)
+ 0x110a, 0x1167, 0x11c2, 0,
+#undef V7057
+#define V7057 (V + 27303)
+ 0x110a, 0x1168, 0,
+#undef V7058
+#define V7058 (V + 27306)
+ 0x110a, 0x1168, 0x11a8, 0,
+#undef V7059
+#define V7059 (V + 27310)
+ 0x110a, 0x1168, 0x11a9, 0,
+#undef V7060
+#define V7060 (V + 27314)
+ 0x110a, 0x1168, 0x11aa, 0,
+#undef V7061
+#define V7061 (V + 27318)
+ 0x110a, 0x1168, 0x11ab, 0,
+#undef V7062
+#define V7062 (V + 27322)
+ 0x110a, 0x1168, 0x11ac, 0,
+#undef V7063
+#define V7063 (V + 27326)
+ 0x110a, 0x1168, 0x11ad, 0,
+#undef V7064
+#define V7064 (V + 27330)
+ 0x110a, 0x1168, 0x11ae, 0,
+#undef V7065
+#define V7065 (V + 27334)
+ 0x110a, 0x1168, 0x11af, 0,
+#undef V7066
+#define V7066 (V + 27338)
+ 0x110a, 0x1168, 0x11b0, 0,
+#undef V7067
+#define V7067 (V + 27342)
+ 0x110a, 0x1168, 0x11b1, 0,
+#undef V7068
+#define V7068 (V + 27346)
+ 0x110a, 0x1168, 0x11b2, 0,
+#undef V7069
+#define V7069 (V + 27350)
+ 0x110a, 0x1168, 0x11b3, 0,
+#undef V7070
+#define V7070 (V + 27354)
+ 0x110a, 0x1168, 0x11b4, 0,
+#undef V7071
+#define V7071 (V + 27358)
+ 0x110a, 0x1168, 0x11b5, 0,
+#undef V7072
+#define V7072 (V + 27362)
+ 0x110a, 0x1168, 0x11b6, 0,
+#undef V7073
+#define V7073 (V + 27366)
+ 0x110a, 0x1168, 0x11b7, 0,
+#undef V7074
+#define V7074 (V + 27370)
+ 0x110a, 0x1168, 0x11b8, 0,
+#undef V7075
+#define V7075 (V + 27374)
+ 0x110a, 0x1168, 0x11b9, 0,
+#undef V7076
+#define V7076 (V + 27378)
+ 0x110a, 0x1168, 0x11ba, 0,
+#undef V7077
+#define V7077 (V + 27382)
+ 0x110a, 0x1168, 0x11bb, 0,
+#undef V7078
+#define V7078 (V + 27386)
+ 0x110a, 0x1168, 0x11bc, 0,
+#undef V7079
+#define V7079 (V + 27390)
+ 0x110a, 0x1168, 0x11bd, 0,
+#undef V7080
+#define V7080 (V + 27394)
+ 0x110a, 0x1168, 0x11be, 0,
+#undef V7081
+#define V7081 (V + 27398)
+ 0x110a, 0x1168, 0x11bf, 0,
+#undef V7082
+#define V7082 (V + 27402)
+ 0x110a, 0x1168, 0x11c0, 0,
+#undef V7083
+#define V7083 (V + 27406)
+ 0x110a, 0x1168, 0x11c1, 0,
+#undef V7084
+#define V7084 (V + 27410)
+ 0x110a, 0x1168, 0x11c2, 0,
+#undef V7085
+#define V7085 (V + 27414)
+ 0x110a, 0x1169, 0,
+#undef V7086
+#define V7086 (V + 27417)
+ 0x110a, 0x1169, 0x11a8, 0,
+#undef V7087
+#define V7087 (V + 27421)
+ 0x110a, 0x1169, 0x11a9, 0,
+#undef V7088
+#define V7088 (V + 27425)
+ 0x110a, 0x1169, 0x11aa, 0,
+#undef V7089
+#define V7089 (V + 27429)
+ 0x110a, 0x1169, 0x11ab, 0,
+#undef V7090
+#define V7090 (V + 27433)
+ 0x110a, 0x1169, 0x11ac, 0,
+#undef V7091
+#define V7091 (V + 27437)
+ 0x110a, 0x1169, 0x11ad, 0,
+#undef V7092
+#define V7092 (V + 27441)
+ 0x110a, 0x1169, 0x11ae, 0,
+#undef V7093
+#define V7093 (V + 27445)
+ 0x110a, 0x1169, 0x11af, 0,
+#undef V7094
+#define V7094 (V + 27449)
+ 0x110a, 0x1169, 0x11b0, 0,
+#undef V7095
+#define V7095 (V + 27453)
+ 0x110a, 0x1169, 0x11b1, 0,
+#undef V7096
+#define V7096 (V + 27457)
+ 0x110a, 0x1169, 0x11b2, 0,
+#undef V7097
+#define V7097 (V + 27461)
+ 0x110a, 0x1169, 0x11b3, 0,
+#undef V7098
+#define V7098 (V + 27465)
+ 0x110a, 0x1169, 0x11b4, 0,
+#undef V7099
+#define V7099 (V + 27469)
+ 0x110a, 0x1169, 0x11b5, 0,
+#undef V7100
+#define V7100 (V + 27473)
+ 0x110a, 0x1169, 0x11b6, 0,
+#undef V7101
+#define V7101 (V + 27477)
+ 0x110a, 0x1169, 0x11b7, 0,
+#undef V7102
+#define V7102 (V + 27481)
+ 0x110a, 0x1169, 0x11b8, 0,
+#undef V7103
+#define V7103 (V + 27485)
+ 0x110a, 0x1169, 0x11b9, 0,
+#undef V7104
+#define V7104 (V + 27489)
+ 0x110a, 0x1169, 0x11ba, 0,
+#undef V7105
+#define V7105 (V + 27493)
+ 0x110a, 0x1169, 0x11bb, 0,
+#undef V7106
+#define V7106 (V + 27497)
+ 0x110a, 0x1169, 0x11bc, 0,
+#undef V7107
+#define V7107 (V + 27501)
+ 0x110a, 0x1169, 0x11bd, 0,
+#undef V7108
+#define V7108 (V + 27505)
+ 0x110a, 0x1169, 0x11be, 0,
+#undef V7109
+#define V7109 (V + 27509)
+ 0x110a, 0x1169, 0x11bf, 0,
+#undef V7110
+#define V7110 (V + 27513)
+ 0x110a, 0x1169, 0x11c0, 0,
+#undef V7111
+#define V7111 (V + 27517)
+ 0x110a, 0x1169, 0x11c1, 0,
+#undef V7112
+#define V7112 (V + 27521)
+ 0x110a, 0x1169, 0x11c2, 0,
+#undef V7113
+#define V7113 (V + 27525)
+ 0x110a, 0x116a, 0,
+#undef V7114
+#define V7114 (V + 27528)
+ 0x110a, 0x116a, 0x11a8, 0,
+#undef V7115
+#define V7115 (V + 27532)
+ 0x110a, 0x116a, 0x11a9, 0,
+#undef V7116
+#define V7116 (V + 27536)
+ 0x110a, 0x116a, 0x11aa, 0,
+#undef V7117
+#define V7117 (V + 27540)
+ 0x110a, 0x116a, 0x11ab, 0,
+#undef V7118
+#define V7118 (V + 27544)
+ 0x110a, 0x116a, 0x11ac, 0,
+#undef V7119
+#define V7119 (V + 27548)
+ 0x110a, 0x116a, 0x11ad, 0,
+#undef V7120
+#define V7120 (V + 27552)
+ 0x110a, 0x116a, 0x11ae, 0,
+#undef V7121
+#define V7121 (V + 27556)
+ 0x110a, 0x116a, 0x11af, 0,
+#undef V7122
+#define V7122 (V + 27560)
+ 0x110a, 0x116a, 0x11b0, 0,
+#undef V7123
+#define V7123 (V + 27564)
+ 0x110a, 0x116a, 0x11b1, 0,
+#undef V7124
+#define V7124 (V + 27568)
+ 0x110a, 0x116a, 0x11b2, 0,
+#undef V7125
+#define V7125 (V + 27572)
+ 0x110a, 0x116a, 0x11b3, 0,
+#undef V7126
+#define V7126 (V + 27576)
+ 0x110a, 0x116a, 0x11b4, 0,
+#undef V7127
+#define V7127 (V + 27580)
+ 0x110a, 0x116a, 0x11b5, 0,
+#undef V7128
+#define V7128 (V + 27584)
+ 0x110a, 0x116a, 0x11b6, 0,
+#undef V7129
+#define V7129 (V + 27588)
+ 0x110a, 0x116a, 0x11b7, 0,
+#undef V7130
+#define V7130 (V + 27592)
+ 0x110a, 0x116a, 0x11b8, 0,
+#undef V7131
+#define V7131 (V + 27596)
+ 0x110a, 0x116a, 0x11b9, 0,
+#undef V7132
+#define V7132 (V + 27600)
+ 0x110a, 0x116a, 0x11ba, 0,
+#undef V7133
+#define V7133 (V + 27604)
+ 0x110a, 0x116a, 0x11bb, 0,
+#undef V7134
+#define V7134 (V + 27608)
+ 0x110a, 0x116a, 0x11bc, 0,
+#undef V7135
+#define V7135 (V + 27612)
+ 0x110a, 0x116a, 0x11bd, 0,
+#undef V7136
+#define V7136 (V + 27616)
+ 0x110a, 0x116a, 0x11be, 0,
+#undef V7137
+#define V7137 (V + 27620)
+ 0x110a, 0x116a, 0x11bf, 0,
+#undef V7138
+#define V7138 (V + 27624)
+ 0x110a, 0x116a, 0x11c0, 0,
+#undef V7139
+#define V7139 (V + 27628)
+ 0x110a, 0x116a, 0x11c1, 0,
+#undef V7140
+#define V7140 (V + 27632)
+ 0x110a, 0x116a, 0x11c2, 0,
+#undef V7141
+#define V7141 (V + 27636)
+ 0x110a, 0x116b, 0,
+#undef V7142
+#define V7142 (V + 27639)
+ 0x110a, 0x116b, 0x11a8, 0,
+#undef V7143
+#define V7143 (V + 27643)
+ 0x110a, 0x116b, 0x11a9, 0,
+#undef V7144
+#define V7144 (V + 27647)
+ 0x110a, 0x116b, 0x11aa, 0,
+#undef V7145
+#define V7145 (V + 27651)
+ 0x110a, 0x116b, 0x11ab, 0,
+#undef V7146
+#define V7146 (V + 27655)
+ 0x110a, 0x116b, 0x11ac, 0,
+#undef V7147
+#define V7147 (V + 27659)
+ 0x110a, 0x116b, 0x11ad, 0,
+#undef V7148
+#define V7148 (V + 27663)
+ 0x110a, 0x116b, 0x11ae, 0,
+#undef V7149
+#define V7149 (V + 27667)
+ 0x110a, 0x116b, 0x11af, 0,
+#undef V7150
+#define V7150 (V + 27671)
+ 0x110a, 0x116b, 0x11b0, 0,
+#undef V7151
+#define V7151 (V + 27675)
+ 0x110a, 0x116b, 0x11b1, 0,
+#undef V7152
+#define V7152 (V + 27679)
+ 0x110a, 0x116b, 0x11b2, 0,
+#undef V7153
+#define V7153 (V + 27683)
+ 0x110a, 0x116b, 0x11b3, 0,
+#undef V7154
+#define V7154 (V + 27687)
+ 0x110a, 0x116b, 0x11b4, 0,
+#undef V7155
+#define V7155 (V + 27691)
+ 0x110a, 0x116b, 0x11b5, 0,
+#undef V7156
+#define V7156 (V + 27695)
+ 0x110a, 0x116b, 0x11b6, 0,
+#undef V7157
+#define V7157 (V + 27699)
+ 0x110a, 0x116b, 0x11b7, 0,
+#undef V7158
+#define V7158 (V + 27703)
+ 0x110a, 0x116b, 0x11b8, 0,
+#undef V7159
+#define V7159 (V + 27707)
+ 0x110a, 0x116b, 0x11b9, 0,
+#undef V7160
+#define V7160 (V + 27711)
+ 0x110a, 0x116b, 0x11ba, 0,
+#undef V7161
+#define V7161 (V + 27715)
+ 0x110a, 0x116b, 0x11bb, 0,
+#undef V7162
+#define V7162 (V + 27719)
+ 0x110a, 0x116b, 0x11bc, 0,
+#undef V7163
+#define V7163 (V + 27723)
+ 0x110a, 0x116b, 0x11bd, 0,
+#undef V7164
+#define V7164 (V + 27727)
+ 0x110a, 0x116b, 0x11be, 0,
+#undef V7165
+#define V7165 (V + 27731)
+ 0x110a, 0x116b, 0x11bf, 0,
+#undef V7166
+#define V7166 (V + 27735)
+ 0x110a, 0x116b, 0x11c0, 0,
+#undef V7167
+#define V7167 (V + 27739)
+ 0x110a, 0x116b, 0x11c1, 0,
+#undef V7168
+#define V7168 (V + 27743)
+ 0x110a, 0x116b, 0x11c2, 0,
+#undef V7169
+#define V7169 (V + 27747)
+ 0x110a, 0x116c, 0,
+#undef V7170
+#define V7170 (V + 27750)
+ 0x110a, 0x116c, 0x11a8, 0,
+#undef V7171
+#define V7171 (V + 27754)
+ 0x110a, 0x116c, 0x11a9, 0,
+#undef V7172
+#define V7172 (V + 27758)
+ 0x110a, 0x116c, 0x11aa, 0,
+#undef V7173
+#define V7173 (V + 27762)
+ 0x110a, 0x116c, 0x11ab, 0,
+#undef V7174
+#define V7174 (V + 27766)
+ 0x110a, 0x116c, 0x11ac, 0,
+#undef V7175
+#define V7175 (V + 27770)
+ 0x110a, 0x116c, 0x11ad, 0,
+#undef V7176
+#define V7176 (V + 27774)
+ 0x110a, 0x116c, 0x11ae, 0,
+#undef V7177
+#define V7177 (V + 27778)
+ 0x110a, 0x116c, 0x11af, 0,
+#undef V7178
+#define V7178 (V + 27782)
+ 0x110a, 0x116c, 0x11b0, 0,
+#undef V7179
+#define V7179 (V + 27786)
+ 0x110a, 0x116c, 0x11b1, 0,
+#undef V7180
+#define V7180 (V + 27790)
+ 0x110a, 0x116c, 0x11b2, 0,
+#undef V7181
+#define V7181 (V + 27794)
+ 0x110a, 0x116c, 0x11b3, 0,
+#undef V7182
+#define V7182 (V + 27798)
+ 0x110a, 0x116c, 0x11b4, 0,
+#undef V7183
+#define V7183 (V + 27802)
+ 0x110a, 0x116c, 0x11b5, 0,
+#undef V7184
+#define V7184 (V + 27806)
+ 0x110a, 0x116c, 0x11b6, 0,
+#undef V7185
+#define V7185 (V + 27810)
+ 0x110a, 0x116c, 0x11b7, 0,
+#undef V7186
+#define V7186 (V + 27814)
+ 0x110a, 0x116c, 0x11b8, 0,
+#undef V7187
+#define V7187 (V + 27818)
+ 0x110a, 0x116c, 0x11b9, 0,
+#undef V7188
+#define V7188 (V + 27822)
+ 0x110a, 0x116c, 0x11ba, 0,
+#undef V7189
+#define V7189 (V + 27826)
+ 0x110a, 0x116c, 0x11bb, 0,
+#undef V7190
+#define V7190 (V + 27830)
+ 0x110a, 0x116c, 0x11bc, 0,
+#undef V7191
+#define V7191 (V + 27834)
+ 0x110a, 0x116c, 0x11bd, 0,
+#undef V7192
+#define V7192 (V + 27838)
+ 0x110a, 0x116c, 0x11be, 0,
+#undef V7193
+#define V7193 (V + 27842)
+ 0x110a, 0x116c, 0x11bf, 0,
+#undef V7194
+#define V7194 (V + 27846)
+ 0x110a, 0x116c, 0x11c0, 0,
+#undef V7195
+#define V7195 (V + 27850)
+ 0x110a, 0x116c, 0x11c1, 0,
+#undef V7196
+#define V7196 (V + 27854)
+ 0x110a, 0x116c, 0x11c2, 0,
+#undef V7197
+#define V7197 (V + 27858)
+ 0x110a, 0x116d, 0,
+#undef V7198
+#define V7198 (V + 27861)
+ 0x110a, 0x116d, 0x11a8, 0,
+#undef V7199
+#define V7199 (V + 27865)
+ 0x110a, 0x116d, 0x11a9, 0,
+#undef V7200
+#define V7200 (V + 27869)
+ 0x110a, 0x116d, 0x11aa, 0,
+#undef V7201
+#define V7201 (V + 27873)
+ 0x110a, 0x116d, 0x11ab, 0,
+#undef V7202
+#define V7202 (V + 27877)
+ 0x110a, 0x116d, 0x11ac, 0,
+#undef V7203
+#define V7203 (V + 27881)
+ 0x110a, 0x116d, 0x11ad, 0,
+#undef V7204
+#define V7204 (V + 27885)
+ 0x110a, 0x116d, 0x11ae, 0,
+#undef V7205
+#define V7205 (V + 27889)
+ 0x110a, 0x116d, 0x11af, 0,
+#undef V7206
+#define V7206 (V + 27893)
+ 0x110a, 0x116d, 0x11b0, 0,
+#undef V7207
+#define V7207 (V + 27897)
+ 0x110a, 0x116d, 0x11b1, 0,
+#undef V7208
+#define V7208 (V + 27901)
+ 0x110a, 0x116d, 0x11b2, 0,
+#undef V7209
+#define V7209 (V + 27905)
+ 0x110a, 0x116d, 0x11b3, 0,
+#undef V7210
+#define V7210 (V + 27909)
+ 0x110a, 0x116d, 0x11b4, 0,
+#undef V7211
+#define V7211 (V + 27913)
+ 0x110a, 0x116d, 0x11b5, 0,
+#undef V7212
+#define V7212 (V + 27917)
+ 0x110a, 0x116d, 0x11b6, 0,
+#undef V7213
+#define V7213 (V + 27921)
+ 0x110a, 0x116d, 0x11b7, 0,
+#undef V7214
+#define V7214 (V + 27925)
+ 0x110a, 0x116d, 0x11b8, 0,
+#undef V7215
+#define V7215 (V + 27929)
+ 0x110a, 0x116d, 0x11b9, 0,
+#undef V7216
+#define V7216 (V + 27933)
+ 0x110a, 0x116d, 0x11ba, 0,
+#undef V7217
+#define V7217 (V + 27937)
+ 0x110a, 0x116d, 0x11bb, 0,
+#undef V7218
+#define V7218 (V + 27941)
+ 0x110a, 0x116d, 0x11bc, 0,
+#undef V7219
+#define V7219 (V + 27945)
+ 0x110a, 0x116d, 0x11bd, 0,
+#undef V7220
+#define V7220 (V + 27949)
+ 0x110a, 0x116d, 0x11be, 0,
+#undef V7221
+#define V7221 (V + 27953)
+ 0x110a, 0x116d, 0x11bf, 0,
+#undef V7222
+#define V7222 (V + 27957)
+ 0x110a, 0x116d, 0x11c0, 0,
+#undef V7223
+#define V7223 (V + 27961)
+ 0x110a, 0x116d, 0x11c1, 0,
+#undef V7224
+#define V7224 (V + 27965)
+ 0x110a, 0x116d, 0x11c2, 0,
+#undef V7225
+#define V7225 (V + 27969)
+ 0x110a, 0x116e, 0,
+#undef V7226
+#define V7226 (V + 27972)
+ 0x110a, 0x116e, 0x11a8, 0,
+#undef V7227
+#define V7227 (V + 27976)
+ 0x110a, 0x116e, 0x11a9, 0,
+#undef V7228
+#define V7228 (V + 27980)
+ 0x110a, 0x116e, 0x11aa, 0,
+#undef V7229
+#define V7229 (V + 27984)
+ 0x110a, 0x116e, 0x11ab, 0,
+#undef V7230
+#define V7230 (V + 27988)
+ 0x110a, 0x116e, 0x11ac, 0,
+#undef V7231
+#define V7231 (V + 27992)
+ 0x110a, 0x116e, 0x11ad, 0,
+#undef V7232
+#define V7232 (V + 27996)
+ 0x110a, 0x116e, 0x11ae, 0,
+#undef V7233
+#define V7233 (V + 28000)
+ 0x110a, 0x116e, 0x11af, 0,
+#undef V7234
+#define V7234 (V + 28004)
+ 0x110a, 0x116e, 0x11b0, 0,
+#undef V7235
+#define V7235 (V + 28008)
+ 0x110a, 0x116e, 0x11b1, 0,
+#undef V7236
+#define V7236 (V + 28012)
+ 0x110a, 0x116e, 0x11b2, 0,
+#undef V7237
+#define V7237 (V + 28016)
+ 0x110a, 0x116e, 0x11b3, 0,
+#undef V7238
+#define V7238 (V + 28020)
+ 0x110a, 0x116e, 0x11b4, 0,
+#undef V7239
+#define V7239 (V + 28024)
+ 0x110a, 0x116e, 0x11b5, 0,
+#undef V7240
+#define V7240 (V + 28028)
+ 0x110a, 0x116e, 0x11b6, 0,
+#undef V7241
+#define V7241 (V + 28032)
+ 0x110a, 0x116e, 0x11b7, 0,
+#undef V7242
+#define V7242 (V + 28036)
+ 0x110a, 0x116e, 0x11b8, 0,
+#undef V7243
+#define V7243 (V + 28040)
+ 0x110a, 0x116e, 0x11b9, 0,
+#undef V7244
+#define V7244 (V + 28044)
+ 0x110a, 0x116e, 0x11ba, 0,
+#undef V7245
+#define V7245 (V + 28048)
+ 0x110a, 0x116e, 0x11bb, 0,
+#undef V7246
+#define V7246 (V + 28052)
+ 0x110a, 0x116e, 0x11bc, 0,
+#undef V7247
+#define V7247 (V + 28056)
+ 0x110a, 0x116e, 0x11bd, 0,
+#undef V7248
+#define V7248 (V + 28060)
+ 0x110a, 0x116e, 0x11be, 0,
+#undef V7249
+#define V7249 (V + 28064)
+ 0x110a, 0x116e, 0x11bf, 0,
+#undef V7250
+#define V7250 (V + 28068)
+ 0x110a, 0x116e, 0x11c0, 0,
+#undef V7251
+#define V7251 (V + 28072)
+ 0x110a, 0x116e, 0x11c1, 0,
+#undef V7252
+#define V7252 (V + 28076)
+ 0x110a, 0x116e, 0x11c2, 0,
+#undef V7253
+#define V7253 (V + 28080)
+ 0x110a, 0x116f, 0,
+#undef V7254
+#define V7254 (V + 28083)
+ 0x110a, 0x116f, 0x11a8, 0,
+#undef V7255
+#define V7255 (V + 28087)
+ 0x110a, 0x116f, 0x11a9, 0,
+#undef V7256
+#define V7256 (V + 28091)
+ 0x110a, 0x116f, 0x11aa, 0,
+#undef V7257
+#define V7257 (V + 28095)
+ 0x110a, 0x116f, 0x11ab, 0,
+#undef V7258
+#define V7258 (V + 28099)
+ 0x110a, 0x116f, 0x11ac, 0,
+#undef V7259
+#define V7259 (V + 28103)
+ 0x110a, 0x116f, 0x11ad, 0,
+#undef V7260
+#define V7260 (V + 28107)
+ 0x110a, 0x116f, 0x11ae, 0,
+#undef V7261
+#define V7261 (V + 28111)
+ 0x110a, 0x116f, 0x11af, 0,
+#undef V7262
+#define V7262 (V + 28115)
+ 0x110a, 0x116f, 0x11b0, 0,
+#undef V7263
+#define V7263 (V + 28119)
+ 0x110a, 0x116f, 0x11b1, 0,
+#undef V7264
+#define V7264 (V + 28123)
+ 0x110a, 0x116f, 0x11b2, 0,
+#undef V7265
+#define V7265 (V + 28127)
+ 0x110a, 0x116f, 0x11b3, 0,
+#undef V7266
+#define V7266 (V + 28131)
+ 0x110a, 0x116f, 0x11b4, 0,
+#undef V7267
+#define V7267 (V + 28135)
+ 0x110a, 0x116f, 0x11b5, 0,
+#undef V7268
+#define V7268 (V + 28139)
+ 0x110a, 0x116f, 0x11b6, 0,
+#undef V7269
+#define V7269 (V + 28143)
+ 0x110a, 0x116f, 0x11b7, 0,
+#undef V7270
+#define V7270 (V + 28147)
+ 0x110a, 0x116f, 0x11b8, 0,
+#undef V7271
+#define V7271 (V + 28151)
+ 0x110a, 0x116f, 0x11b9, 0,
+#undef V7272
+#define V7272 (V + 28155)
+ 0x110a, 0x116f, 0x11ba, 0,
+#undef V7273
+#define V7273 (V + 28159)
+ 0x110a, 0x116f, 0x11bb, 0,
+#undef V7274
+#define V7274 (V + 28163)
+ 0x110a, 0x116f, 0x11bc, 0,
+#undef V7275
+#define V7275 (V + 28167)
+ 0x110a, 0x116f, 0x11bd, 0,
+#undef V7276
+#define V7276 (V + 28171)
+ 0x110a, 0x116f, 0x11be, 0,
+#undef V7277
+#define V7277 (V + 28175)
+ 0x110a, 0x116f, 0x11bf, 0,
+#undef V7278
+#define V7278 (V + 28179)
+ 0x110a, 0x116f, 0x11c0, 0,
+#undef V7279
+#define V7279 (V + 28183)
+ 0x110a, 0x116f, 0x11c1, 0,
+#undef V7280
+#define V7280 (V + 28187)
+ 0x110a, 0x116f, 0x11c2, 0,
+#undef V7281
+#define V7281 (V + 28191)
+ 0x110a, 0x1170, 0,
+#undef V7282
+#define V7282 (V + 28194)
+ 0x110a, 0x1170, 0x11a8, 0,
+#undef V7283
+#define V7283 (V + 28198)
+ 0x110a, 0x1170, 0x11a9, 0,
+#undef V7284
+#define V7284 (V + 28202)
+ 0x110a, 0x1170, 0x11aa, 0,
+#undef V7285
+#define V7285 (V + 28206)
+ 0x110a, 0x1170, 0x11ab, 0,
+#undef V7286
+#define V7286 (V + 28210)
+ 0x110a, 0x1170, 0x11ac, 0,
+#undef V7287
+#define V7287 (V + 28214)
+ 0x110a, 0x1170, 0x11ad, 0,
+#undef V7288
+#define V7288 (V + 28218)
+ 0x110a, 0x1170, 0x11ae, 0,
+#undef V7289
+#define V7289 (V + 28222)
+ 0x110a, 0x1170, 0x11af, 0,
+#undef V7290
+#define V7290 (V + 28226)
+ 0x110a, 0x1170, 0x11b0, 0,
+#undef V7291
+#define V7291 (V + 28230)
+ 0x110a, 0x1170, 0x11b1, 0,
+#undef V7292
+#define V7292 (V + 28234)
+ 0x110a, 0x1170, 0x11b2, 0,
+#undef V7293
+#define V7293 (V + 28238)
+ 0x110a, 0x1170, 0x11b3, 0,
+#undef V7294
+#define V7294 (V + 28242)
+ 0x110a, 0x1170, 0x11b4, 0,
+#undef V7295
+#define V7295 (V + 28246)
+ 0x110a, 0x1170, 0x11b5, 0,
+#undef V7296
+#define V7296 (V + 28250)
+ 0x110a, 0x1170, 0x11b6, 0,
+#undef V7297
+#define V7297 (V + 28254)
+ 0x110a, 0x1170, 0x11b7, 0,
+#undef V7298
+#define V7298 (V + 28258)
+ 0x110a, 0x1170, 0x11b8, 0,
+#undef V7299
+#define V7299 (V + 28262)
+ 0x110a, 0x1170, 0x11b9, 0,
+#undef V7300
+#define V7300 (V + 28266)
+ 0x110a, 0x1170, 0x11ba, 0,
+#undef V7301
+#define V7301 (V + 28270)
+ 0x110a, 0x1170, 0x11bb, 0,
+#undef V7302
+#define V7302 (V + 28274)
+ 0x110a, 0x1170, 0x11bc, 0,
+#undef V7303
+#define V7303 (V + 28278)
+ 0x110a, 0x1170, 0x11bd, 0,
+#undef V7304
+#define V7304 (V + 28282)
+ 0x110a, 0x1170, 0x11be, 0,
+#undef V7305
+#define V7305 (V + 28286)
+ 0x110a, 0x1170, 0x11bf, 0,
+#undef V7306
+#define V7306 (V + 28290)
+ 0x110a, 0x1170, 0x11c0, 0,
+#undef V7307
+#define V7307 (V + 28294)
+ 0x110a, 0x1170, 0x11c1, 0,
+#undef V7308
+#define V7308 (V + 28298)
+ 0x110a, 0x1170, 0x11c2, 0,
+#undef V7309
+#define V7309 (V + 28302)
+ 0x110a, 0x1171, 0,
+#undef V7310
+#define V7310 (V + 28305)
+ 0x110a, 0x1171, 0x11a8, 0,
+#undef V7311
+#define V7311 (V + 28309)
+ 0x110a, 0x1171, 0x11a9, 0,
+#undef V7312
+#define V7312 (V + 28313)
+ 0x110a, 0x1171, 0x11aa, 0,
+#undef V7313
+#define V7313 (V + 28317)
+ 0x110a, 0x1171, 0x11ab, 0,
+#undef V7314
+#define V7314 (V + 28321)
+ 0x110a, 0x1171, 0x11ac, 0,
+#undef V7315
+#define V7315 (V + 28325)
+ 0x110a, 0x1171, 0x11ad, 0,
+#undef V7316
+#define V7316 (V + 28329)
+ 0x110a, 0x1171, 0x11ae, 0,
+#undef V7317
+#define V7317 (V + 28333)
+ 0x110a, 0x1171, 0x11af, 0,
+#undef V7318
+#define V7318 (V + 28337)
+ 0x110a, 0x1171, 0x11b0, 0,
+#undef V7319
+#define V7319 (V + 28341)
+ 0x110a, 0x1171, 0x11b1, 0,
+#undef V7320
+#define V7320 (V + 28345)
+ 0x110a, 0x1171, 0x11b2, 0,
+#undef V7321
+#define V7321 (V + 28349)
+ 0x110a, 0x1171, 0x11b3, 0,
+#undef V7322
+#define V7322 (V + 28353)
+ 0x110a, 0x1171, 0x11b4, 0,
+#undef V7323
+#define V7323 (V + 28357)
+ 0x110a, 0x1171, 0x11b5, 0,
+#undef V7324
+#define V7324 (V + 28361)
+ 0x110a, 0x1171, 0x11b6, 0,
+#undef V7325
+#define V7325 (V + 28365)
+ 0x110a, 0x1171, 0x11b7, 0,
+#undef V7326
+#define V7326 (V + 28369)
+ 0x110a, 0x1171, 0x11b8, 0,
+#undef V7327
+#define V7327 (V + 28373)
+ 0x110a, 0x1171, 0x11b9, 0,
+#undef V7328
+#define V7328 (V + 28377)
+ 0x110a, 0x1171, 0x11ba, 0,
+#undef V7329
+#define V7329 (V + 28381)
+ 0x110a, 0x1171, 0x11bb, 0,
+#undef V7330
+#define V7330 (V + 28385)
+ 0x110a, 0x1171, 0x11bc, 0,
+#undef V7331
+#define V7331 (V + 28389)
+ 0x110a, 0x1171, 0x11bd, 0,
+#undef V7332
+#define V7332 (V + 28393)
+ 0x110a, 0x1171, 0x11be, 0,
+#undef V7333
+#define V7333 (V + 28397)
+ 0x110a, 0x1171, 0x11bf, 0,
+#undef V7334
+#define V7334 (V + 28401)
+ 0x110a, 0x1171, 0x11c0, 0,
+#undef V7335
+#define V7335 (V + 28405)
+ 0x110a, 0x1171, 0x11c1, 0,
+#undef V7336
+#define V7336 (V + 28409)
+ 0x110a, 0x1171, 0x11c2, 0,
+#undef V7337
+#define V7337 (V + 28413)
+ 0x110a, 0x1172, 0,
+#undef V7338
+#define V7338 (V + 28416)
+ 0x110a, 0x1172, 0x11a8, 0,
+#undef V7339
+#define V7339 (V + 28420)
+ 0x110a, 0x1172, 0x11a9, 0,
+#undef V7340
+#define V7340 (V + 28424)
+ 0x110a, 0x1172, 0x11aa, 0,
+#undef V7341
+#define V7341 (V + 28428)
+ 0x110a, 0x1172, 0x11ab, 0,
+#undef V7342
+#define V7342 (V + 28432)
+ 0x110a, 0x1172, 0x11ac, 0,
+#undef V7343
+#define V7343 (V + 28436)
+ 0x110a, 0x1172, 0x11ad, 0,
+#undef V7344
+#define V7344 (V + 28440)
+ 0x110a, 0x1172, 0x11ae, 0,
+#undef V7345
+#define V7345 (V + 28444)
+ 0x110a, 0x1172, 0x11af, 0,
+#undef V7346
+#define V7346 (V + 28448)
+ 0x110a, 0x1172, 0x11b0, 0,
+#undef V7347
+#define V7347 (V + 28452)
+ 0x110a, 0x1172, 0x11b1, 0,
+#undef V7348
+#define V7348 (V + 28456)
+ 0x110a, 0x1172, 0x11b2, 0,
+#undef V7349
+#define V7349 (V + 28460)
+ 0x110a, 0x1172, 0x11b3, 0,
+#undef V7350
+#define V7350 (V + 28464)
+ 0x110a, 0x1172, 0x11b4, 0,
+#undef V7351
+#define V7351 (V + 28468)
+ 0x110a, 0x1172, 0x11b5, 0,
+#undef V7352
+#define V7352 (V + 28472)
+ 0x110a, 0x1172, 0x11b6, 0,
+#undef V7353
+#define V7353 (V + 28476)
+ 0x110a, 0x1172, 0x11b7, 0,
+#undef V7354
+#define V7354 (V + 28480)
+ 0x110a, 0x1172, 0x11b8, 0,
+#undef V7355
+#define V7355 (V + 28484)
+ 0x110a, 0x1172, 0x11b9, 0,
+#undef V7356
+#define V7356 (V + 28488)
+ 0x110a, 0x1172, 0x11ba, 0,
+#undef V7357
+#define V7357 (V + 28492)
+ 0x110a, 0x1172, 0x11bb, 0,
+#undef V7358
+#define V7358 (V + 28496)
+ 0x110a, 0x1172, 0x11bc, 0,
+#undef V7359
+#define V7359 (V + 28500)
+ 0x110a, 0x1172, 0x11bd, 0,
+#undef V7360
+#define V7360 (V + 28504)
+ 0x110a, 0x1172, 0x11be, 0,
+#undef V7361
+#define V7361 (V + 28508)
+ 0x110a, 0x1172, 0x11bf, 0,
+#undef V7362
+#define V7362 (V + 28512)
+ 0x110a, 0x1172, 0x11c0, 0,
+#undef V7363
+#define V7363 (V + 28516)
+ 0x110a, 0x1172, 0x11c1, 0,
+#undef V7364
+#define V7364 (V + 28520)
+ 0x110a, 0x1172, 0x11c2, 0,
+#undef V7365
+#define V7365 (V + 28524)
+ 0x110a, 0x1173, 0,
+#undef V7366
+#define V7366 (V + 28527)
+ 0x110a, 0x1173, 0x11a8, 0,
+#undef V7367
+#define V7367 (V + 28531)
+ 0x110a, 0x1173, 0x11a9, 0,
+#undef V7368
+#define V7368 (V + 28535)
+ 0x110a, 0x1173, 0x11aa, 0,
+#undef V7369
+#define V7369 (V + 28539)
+ 0x110a, 0x1173, 0x11ab, 0,
+#undef V7370
+#define V7370 (V + 28543)
+ 0x110a, 0x1173, 0x11ac, 0,
+#undef V7371
+#define V7371 (V + 28547)
+ 0x110a, 0x1173, 0x11ad, 0,
+#undef V7372
+#define V7372 (V + 28551)
+ 0x110a, 0x1173, 0x11ae, 0,
+#undef V7373
+#define V7373 (V + 28555)
+ 0x110a, 0x1173, 0x11af, 0,
+#undef V7374
+#define V7374 (V + 28559)
+ 0x110a, 0x1173, 0x11b0, 0,
+#undef V7375
+#define V7375 (V + 28563)
+ 0x110a, 0x1173, 0x11b1, 0,
+#undef V7376
+#define V7376 (V + 28567)
+ 0x110a, 0x1173, 0x11b2, 0,
+#undef V7377
+#define V7377 (V + 28571)
+ 0x110a, 0x1173, 0x11b3, 0,
+#undef V7378
+#define V7378 (V + 28575)
+ 0x110a, 0x1173, 0x11b4, 0,
+#undef V7379
+#define V7379 (V + 28579)
+ 0x110a, 0x1173, 0x11b5, 0,
+#undef V7380
+#define V7380 (V + 28583)
+ 0x110a, 0x1173, 0x11b6, 0,
+#undef V7381
+#define V7381 (V + 28587)
+ 0x110a, 0x1173, 0x11b7, 0,
+#undef V7382
+#define V7382 (V + 28591)
+ 0x110a, 0x1173, 0x11b8, 0,
+#undef V7383
+#define V7383 (V + 28595)
+ 0x110a, 0x1173, 0x11b9, 0,
+#undef V7384
+#define V7384 (V + 28599)
+ 0x110a, 0x1173, 0x11ba, 0,
+#undef V7385
+#define V7385 (V + 28603)
+ 0x110a, 0x1173, 0x11bb, 0,
+#undef V7386
+#define V7386 (V + 28607)
+ 0x110a, 0x1173, 0x11bc, 0,
+#undef V7387
+#define V7387 (V + 28611)
+ 0x110a, 0x1173, 0x11bd, 0,
+#undef V7388
+#define V7388 (V + 28615)
+ 0x110a, 0x1173, 0x11be, 0,
+#undef V7389
+#define V7389 (V + 28619)
+ 0x110a, 0x1173, 0x11bf, 0,
+#undef V7390
+#define V7390 (V + 28623)
+ 0x110a, 0x1173, 0x11c0, 0,
+#undef V7391
+#define V7391 (V + 28627)
+ 0x110a, 0x1173, 0x11c1, 0,
+#undef V7392
+#define V7392 (V + 28631)
+ 0x110a, 0x1173, 0x11c2, 0,
+#undef V7393
+#define V7393 (V + 28635)
+ 0x110a, 0x1174, 0,
+#undef V7394
+#define V7394 (V + 28638)
+ 0x110a, 0x1174, 0x11a8, 0,
+#undef V7395
+#define V7395 (V + 28642)
+ 0x110a, 0x1174, 0x11a9, 0,
+#undef V7396
+#define V7396 (V + 28646)
+ 0x110a, 0x1174, 0x11aa, 0,
+#undef V7397
+#define V7397 (V + 28650)
+ 0x110a, 0x1174, 0x11ab, 0,
+#undef V7398
+#define V7398 (V + 28654)
+ 0x110a, 0x1174, 0x11ac, 0,
+#undef V7399
+#define V7399 (V + 28658)
+ 0x110a, 0x1174, 0x11ad, 0,
+#undef V7400
+#define V7400 (V + 28662)
+ 0x110a, 0x1174, 0x11ae, 0,
+#undef V7401
+#define V7401 (V + 28666)
+ 0x110a, 0x1174, 0x11af, 0,
+#undef V7402
+#define V7402 (V + 28670)
+ 0x110a, 0x1174, 0x11b0, 0,
+#undef V7403
+#define V7403 (V + 28674)
+ 0x110a, 0x1174, 0x11b1, 0,
+#undef V7404
+#define V7404 (V + 28678)
+ 0x110a, 0x1174, 0x11b2, 0,
+#undef V7405
+#define V7405 (V + 28682)
+ 0x110a, 0x1174, 0x11b3, 0,
+#undef V7406
+#define V7406 (V + 28686)
+ 0x110a, 0x1174, 0x11b4, 0,
+#undef V7407
+#define V7407 (V + 28690)
+ 0x110a, 0x1174, 0x11b5, 0,
+#undef V7408
+#define V7408 (V + 28694)
+ 0x110a, 0x1174, 0x11b6, 0,
+#undef V7409
+#define V7409 (V + 28698)
+ 0x110a, 0x1174, 0x11b7, 0,
+#undef V7410
+#define V7410 (V + 28702)
+ 0x110a, 0x1174, 0x11b8, 0,
+#undef V7411
+#define V7411 (V + 28706)
+ 0x110a, 0x1174, 0x11b9, 0,
+#undef V7412
+#define V7412 (V + 28710)
+ 0x110a, 0x1174, 0x11ba, 0,
+#undef V7413
+#define V7413 (V + 28714)
+ 0x110a, 0x1174, 0x11bb, 0,
+#undef V7414
+#define V7414 (V + 28718)
+ 0x110a, 0x1174, 0x11bc, 0,
+#undef V7415
+#define V7415 (V + 28722)
+ 0x110a, 0x1174, 0x11bd, 0,
+#undef V7416
+#define V7416 (V + 28726)
+ 0x110a, 0x1174, 0x11be, 0,
+#undef V7417
+#define V7417 (V + 28730)
+ 0x110a, 0x1174, 0x11bf, 0,
+#undef V7418
+#define V7418 (V + 28734)
+ 0x110a, 0x1174, 0x11c0, 0,
+#undef V7419
+#define V7419 (V + 28738)
+ 0x110a, 0x1174, 0x11c1, 0,
+#undef V7420
+#define V7420 (V + 28742)
+ 0x110a, 0x1174, 0x11c2, 0,
+#undef V7421
+#define V7421 (V + 28746)
+ 0x110a, 0x1175, 0,
+#undef V7422
+#define V7422 (V + 28749)
+ 0x110a, 0x1175, 0x11a8, 0,
+#undef V7423
+#define V7423 (V + 28753)
+ 0x110a, 0x1175, 0x11a9, 0,
+#undef V7424
+#define V7424 (V + 28757)
+ 0x110a, 0x1175, 0x11aa, 0,
+#undef V7425
+#define V7425 (V + 28761)
+ 0x110a, 0x1175, 0x11ab, 0,
+#undef V7426
+#define V7426 (V + 28765)
+ 0x110a, 0x1175, 0x11ac, 0,
+#undef V7427
+#define V7427 (V + 28769)
+ 0x110a, 0x1175, 0x11ad, 0,
+#undef V7428
+#define V7428 (V + 28773)
+ 0x110a, 0x1175, 0x11ae, 0,
+#undef V7429
+#define V7429 (V + 28777)
+ 0x110a, 0x1175, 0x11af, 0,
+#undef V7430
+#define V7430 (V + 28781)
+ 0x110a, 0x1175, 0x11b0, 0,
+#undef V7431
+#define V7431 (V + 28785)
+ 0x110a, 0x1175, 0x11b1, 0,
+#undef V7432
+#define V7432 (V + 28789)
+ 0x110a, 0x1175, 0x11b2, 0,
+#undef V7433
+#define V7433 (V + 28793)
+ 0x110a, 0x1175, 0x11b3, 0,
+#undef V7434
+#define V7434 (V + 28797)
+ 0x110a, 0x1175, 0x11b4, 0,
+#undef V7435
+#define V7435 (V + 28801)
+ 0x110a, 0x1175, 0x11b5, 0,
+#undef V7436
+#define V7436 (V + 28805)
+ 0x110a, 0x1175, 0x11b6, 0,
+#undef V7437
+#define V7437 (V + 28809)
+ 0x110a, 0x1175, 0x11b7, 0,
+#undef V7438
+#define V7438 (V + 28813)
+ 0x110a, 0x1175, 0x11b8, 0,
+#undef V7439
+#define V7439 (V + 28817)
+ 0x110a, 0x1175, 0x11b9, 0,
+#undef V7440
+#define V7440 (V + 28821)
+ 0x110a, 0x1175, 0x11ba, 0,
+#undef V7441
+#define V7441 (V + 28825)
+ 0x110a, 0x1175, 0x11bb, 0,
+#undef V7442
+#define V7442 (V + 28829)
+ 0x110a, 0x1175, 0x11bc, 0,
+#undef V7443
+#define V7443 (V + 28833)
+ 0x110a, 0x1175, 0x11bd, 0,
+#undef V7444
+#define V7444 (V + 28837)
+ 0x110a, 0x1175, 0x11be, 0,
+#undef V7445
+#define V7445 (V + 28841)
+ 0x110a, 0x1175, 0x11bf, 0,
+#undef V7446
+#define V7446 (V + 28845)
+ 0x110a, 0x1175, 0x11c0, 0,
+#undef V7447
+#define V7447 (V + 28849)
+ 0x110a, 0x1175, 0x11c1, 0,
+#undef V7448
+#define V7448 (V + 28853)
+ 0x110a, 0x1175, 0x11c2, 0,
+#undef V7449
+#define V7449 (V + 28857)
+ 0x110b, 0x1161, 0,
+#undef V7450
+#define V7450 (V + 28860)
+ 0x110b, 0x1161, 0x11a8, 0,
+#undef V7451
+#define V7451 (V + 28864)
+ 0x110b, 0x1161, 0x11a9, 0,
+#undef V7452
+#define V7452 (V + 28868)
+ 0x110b, 0x1161, 0x11aa, 0,
+#undef V7453
+#define V7453 (V + 28872)
+ 0x110b, 0x1161, 0x11ab, 0,
+#undef V7454
+#define V7454 (V + 28876)
+ 0x110b, 0x1161, 0x11ac, 0,
+#undef V7455
+#define V7455 (V + 28880)
+ 0x110b, 0x1161, 0x11ad, 0,
+#undef V7456
+#define V7456 (V + 28884)
+ 0x110b, 0x1161, 0x11ae, 0,
+#undef V7457
+#define V7457 (V + 28888)
+ 0x110b, 0x1161, 0x11af, 0,
+#undef V7458
+#define V7458 (V + 28892)
+ 0x110b, 0x1161, 0x11b0, 0,
+#undef V7459
+#define V7459 (V + 28896)
+ 0x110b, 0x1161, 0x11b1, 0,
+#undef V7460
+#define V7460 (V + 28900)
+ 0x110b, 0x1161, 0x11b2, 0,
+#undef V7461
+#define V7461 (V + 28904)
+ 0x110b, 0x1161, 0x11b3, 0,
+#undef V7462
+#define V7462 (V + 28908)
+ 0x110b, 0x1161, 0x11b4, 0,
+#undef V7463
+#define V7463 (V + 28912)
+ 0x110b, 0x1161, 0x11b5, 0,
+#undef V7464
+#define V7464 (V + 28916)
+ 0x110b, 0x1161, 0x11b6, 0,
+#undef V7465
+#define V7465 (V + 28920)
+ 0x110b, 0x1161, 0x11b7, 0,
+#undef V7466
+#define V7466 (V + 28924)
+ 0x110b, 0x1161, 0x11b8, 0,
+#undef V7467
+#define V7467 (V + 28928)
+ 0x110b, 0x1161, 0x11b9, 0,
+#undef V7468
+#define V7468 (V + 28932)
+ 0x110b, 0x1161, 0x11ba, 0,
+#undef V7469
+#define V7469 (V + 28936)
+ 0x110b, 0x1161, 0x11bb, 0,
+#undef V7470
+#define V7470 (V + 28940)
+ 0x110b, 0x1161, 0x11bc, 0,
+#undef V7471
+#define V7471 (V + 28944)
+ 0x110b, 0x1161, 0x11bd, 0,
+#undef V7472
+#define V7472 (V + 28948)
+ 0x110b, 0x1161, 0x11be, 0,
+#undef V7473
+#define V7473 (V + 28952)
+ 0x110b, 0x1161, 0x11bf, 0,
+#undef V7474
+#define V7474 (V + 28956)
+ 0x110b, 0x1161, 0x11c0, 0,
+#undef V7475
+#define V7475 (V + 28960)
+ 0x110b, 0x1161, 0x11c1, 0,
+#undef V7476
+#define V7476 (V + 28964)
+ 0x110b, 0x1161, 0x11c2, 0,
+#undef V7477
+#define V7477 (V + 28968)
+ 0x110b, 0x1162, 0,
+#undef V7478
+#define V7478 (V + 28971)
+ 0x110b, 0x1162, 0x11a8, 0,
+#undef V7479
+#define V7479 (V + 28975)
+ 0x110b, 0x1162, 0x11a9, 0,
+#undef V7480
+#define V7480 (V + 28979)
+ 0x110b, 0x1162, 0x11aa, 0,
+#undef V7481
+#define V7481 (V + 28983)
+ 0x110b, 0x1162, 0x11ab, 0,
+#undef V7482
+#define V7482 (V + 28987)
+ 0x110b, 0x1162, 0x11ac, 0,
+#undef V7483
+#define V7483 (V + 28991)
+ 0x110b, 0x1162, 0x11ad, 0,
+#undef V7484
+#define V7484 (V + 28995)
+ 0x110b, 0x1162, 0x11ae, 0,
+#undef V7485
+#define V7485 (V + 28999)
+ 0x110b, 0x1162, 0x11af, 0,
+#undef V7486
+#define V7486 (V + 29003)
+ 0x110b, 0x1162, 0x11b0, 0,
+#undef V7487
+#define V7487 (V + 29007)
+ 0x110b, 0x1162, 0x11b1, 0,
+#undef V7488
+#define V7488 (V + 29011)
+ 0x110b, 0x1162, 0x11b2, 0,
+#undef V7489
+#define V7489 (V + 29015)
+ 0x110b, 0x1162, 0x11b3, 0,
+#undef V7490
+#define V7490 (V + 29019)
+ 0x110b, 0x1162, 0x11b4, 0,
+#undef V7491
+#define V7491 (V + 29023)
+ 0x110b, 0x1162, 0x11b5, 0,
+#undef V7492
+#define V7492 (V + 29027)
+ 0x110b, 0x1162, 0x11b6, 0,
+#undef V7493
+#define V7493 (V + 29031)
+ 0x110b, 0x1162, 0x11b7, 0,
+#undef V7494
+#define V7494 (V + 29035)
+ 0x110b, 0x1162, 0x11b8, 0,
+#undef V7495
+#define V7495 (V + 29039)
+ 0x110b, 0x1162, 0x11b9, 0,
+#undef V7496
+#define V7496 (V + 29043)
+ 0x110b, 0x1162, 0x11ba, 0,
+#undef V7497
+#define V7497 (V + 29047)
+ 0x110b, 0x1162, 0x11bb, 0,
+#undef V7498
+#define V7498 (V + 29051)
+ 0x110b, 0x1162, 0x11bc, 0,
+#undef V7499
+#define V7499 (V + 29055)
+ 0x110b, 0x1162, 0x11bd, 0,
+#undef V7500
+#define V7500 (V + 29059)
+ 0x110b, 0x1162, 0x11be, 0,
+#undef V7501
+#define V7501 (V + 29063)
+ 0x110b, 0x1162, 0x11bf, 0,
+#undef V7502
+#define V7502 (V + 29067)
+ 0x110b, 0x1162, 0x11c0, 0,
+#undef V7503
+#define V7503 (V + 29071)
+ 0x110b, 0x1162, 0x11c1, 0,
+#undef V7504
+#define V7504 (V + 29075)
+ 0x110b, 0x1162, 0x11c2, 0,
+#undef V7505
+#define V7505 (V + 29079)
+ 0x110b, 0x1163, 0,
+#undef V7506
+#define V7506 (V + 29082)
+ 0x110b, 0x1163, 0x11a8, 0,
+#undef V7507
+#define V7507 (V + 29086)
+ 0x110b, 0x1163, 0x11a9, 0,
+#undef V7508
+#define V7508 (V + 29090)
+ 0x110b, 0x1163, 0x11aa, 0,
+#undef V7509
+#define V7509 (V + 29094)
+ 0x110b, 0x1163, 0x11ab, 0,
+#undef V7510
+#define V7510 (V + 29098)
+ 0x110b, 0x1163, 0x11ac, 0,
+#undef V7511
+#define V7511 (V + 29102)
+ 0x110b, 0x1163, 0x11ad, 0,
+#undef V7512
+#define V7512 (V + 29106)
+ 0x110b, 0x1163, 0x11ae, 0,
+#undef V7513
+#define V7513 (V + 29110)
+ 0x110b, 0x1163, 0x11af, 0,
+#undef V7514
+#define V7514 (V + 29114)
+ 0x110b, 0x1163, 0x11b0, 0,
+#undef V7515
+#define V7515 (V + 29118)
+ 0x110b, 0x1163, 0x11b1, 0,
+#undef V7516
+#define V7516 (V + 29122)
+ 0x110b, 0x1163, 0x11b2, 0,
+#undef V7517
+#define V7517 (V + 29126)
+ 0x110b, 0x1163, 0x11b3, 0,
+#undef V7518
+#define V7518 (V + 29130)
+ 0x110b, 0x1163, 0x11b4, 0,
+#undef V7519
+#define V7519 (V + 29134)
+ 0x110b, 0x1163, 0x11b5, 0,
+#undef V7520
+#define V7520 (V + 29138)
+ 0x110b, 0x1163, 0x11b6, 0,
+#undef V7521
+#define V7521 (V + 29142)
+ 0x110b, 0x1163, 0x11b7, 0,
+#undef V7522
+#define V7522 (V + 29146)
+ 0x110b, 0x1163, 0x11b8, 0,
+#undef V7523
+#define V7523 (V + 29150)
+ 0x110b, 0x1163, 0x11b9, 0,
+#undef V7524
+#define V7524 (V + 29154)
+ 0x110b, 0x1163, 0x11ba, 0,
+#undef V7525
+#define V7525 (V + 29158)
+ 0x110b, 0x1163, 0x11bb, 0,
+#undef V7526
+#define V7526 (V + 29162)
+ 0x110b, 0x1163, 0x11bc, 0,
+#undef V7527
+#define V7527 (V + 29166)
+ 0x110b, 0x1163, 0x11bd, 0,
+#undef V7528
+#define V7528 (V + 29170)
+ 0x110b, 0x1163, 0x11be, 0,
+#undef V7529
+#define V7529 (V + 29174)
+ 0x110b, 0x1163, 0x11bf, 0,
+#undef V7530
+#define V7530 (V + 29178)
+ 0x110b, 0x1163, 0x11c0, 0,
+#undef V7531
+#define V7531 (V + 29182)
+ 0x110b, 0x1163, 0x11c1, 0,
+#undef V7532
+#define V7532 (V + 29186)
+ 0x110b, 0x1163, 0x11c2, 0,
+#undef V7533
+#define V7533 (V + 29190)
+ 0x110b, 0x1164, 0,
+#undef V7534
+#define V7534 (V + 29193)
+ 0x110b, 0x1164, 0x11a8, 0,
+#undef V7535
+#define V7535 (V + 29197)
+ 0x110b, 0x1164, 0x11a9, 0,
+#undef V7536
+#define V7536 (V + 29201)
+ 0x110b, 0x1164, 0x11aa, 0,
+#undef V7537
+#define V7537 (V + 29205)
+ 0x110b, 0x1164, 0x11ab, 0,
+#undef V7538
+#define V7538 (V + 29209)
+ 0x110b, 0x1164, 0x11ac, 0,
+#undef V7539
+#define V7539 (V + 29213)
+ 0x110b, 0x1164, 0x11ad, 0,
+#undef V7540
+#define V7540 (V + 29217)
+ 0x110b, 0x1164, 0x11ae, 0,
+#undef V7541
+#define V7541 (V + 29221)
+ 0x110b, 0x1164, 0x11af, 0,
+#undef V7542
+#define V7542 (V + 29225)
+ 0x110b, 0x1164, 0x11b0, 0,
+#undef V7543
+#define V7543 (V + 29229)
+ 0x110b, 0x1164, 0x11b1, 0,
+#undef V7544
+#define V7544 (V + 29233)
+ 0x110b, 0x1164, 0x11b2, 0,
+#undef V7545
+#define V7545 (V + 29237)
+ 0x110b, 0x1164, 0x11b3, 0,
+#undef V7546
+#define V7546 (V + 29241)
+ 0x110b, 0x1164, 0x11b4, 0,
+#undef V7547
+#define V7547 (V + 29245)
+ 0x110b, 0x1164, 0x11b5, 0,
+#undef V7548
+#define V7548 (V + 29249)
+ 0x110b, 0x1164, 0x11b6, 0,
+#undef V7549
+#define V7549 (V + 29253)
+ 0x110b, 0x1164, 0x11b7, 0,
+#undef V7550
+#define V7550 (V + 29257)
+ 0x110b, 0x1164, 0x11b8, 0,
+#undef V7551
+#define V7551 (V + 29261)
+ 0x110b, 0x1164, 0x11b9, 0,
+#undef V7552
+#define V7552 (V + 29265)
+ 0x110b, 0x1164, 0x11ba, 0,
+#undef V7553
+#define V7553 (V + 29269)
+ 0x110b, 0x1164, 0x11bb, 0,
+#undef V7554
+#define V7554 (V + 29273)
+ 0x110b, 0x1164, 0x11bc, 0,
+#undef V7555
+#define V7555 (V + 29277)
+ 0x110b, 0x1164, 0x11bd, 0,
+#undef V7556
+#define V7556 (V + 29281)
+ 0x110b, 0x1164, 0x11be, 0,
+#undef V7557
+#define V7557 (V + 29285)
+ 0x110b, 0x1164, 0x11bf, 0,
+#undef V7558
+#define V7558 (V + 29289)
+ 0x110b, 0x1164, 0x11c0, 0,
+#undef V7559
+#define V7559 (V + 29293)
+ 0x110b, 0x1164, 0x11c1, 0,
+#undef V7560
+#define V7560 (V + 29297)
+ 0x110b, 0x1164, 0x11c2, 0,
+#undef V7561
+#define V7561 (V + 29301)
+ 0x110b, 0x1165, 0,
+#undef V7562
+#define V7562 (V + 29304)
+ 0x110b, 0x1165, 0x11a8, 0,
+#undef V7563
+#define V7563 (V + 29308)
+ 0x110b, 0x1165, 0x11a9, 0,
+#undef V7564
+#define V7564 (V + 29312)
+ 0x110b, 0x1165, 0x11aa, 0,
+#undef V7565
+#define V7565 (V + 29316)
+ 0x110b, 0x1165, 0x11ab, 0,
+#undef V7566
+#define V7566 (V + 29320)
+ 0x110b, 0x1165, 0x11ac, 0,
+#undef V7567
+#define V7567 (V + 29324)
+ 0x110b, 0x1165, 0x11ad, 0,
+#undef V7568
+#define V7568 (V + 29328)
+ 0x110b, 0x1165, 0x11ae, 0,
+#undef V7569
+#define V7569 (V + 29332)
+ 0x110b, 0x1165, 0x11af, 0,
+#undef V7570
+#define V7570 (V + 29336)
+ 0x110b, 0x1165, 0x11b0, 0,
+#undef V7571
+#define V7571 (V + 29340)
+ 0x110b, 0x1165, 0x11b1, 0,
+#undef V7572
+#define V7572 (V + 29344)
+ 0x110b, 0x1165, 0x11b2, 0,
+#undef V7573
+#define V7573 (V + 29348)
+ 0x110b, 0x1165, 0x11b3, 0,
+#undef V7574
+#define V7574 (V + 29352)
+ 0x110b, 0x1165, 0x11b4, 0,
+#undef V7575
+#define V7575 (V + 29356)
+ 0x110b, 0x1165, 0x11b5, 0,
+#undef V7576
+#define V7576 (V + 29360)
+ 0x110b, 0x1165, 0x11b6, 0,
+#undef V7577
+#define V7577 (V + 29364)
+ 0x110b, 0x1165, 0x11b7, 0,
+#undef V7578
+#define V7578 (V + 29368)
+ 0x110b, 0x1165, 0x11b8, 0,
+#undef V7579
+#define V7579 (V + 29372)
+ 0x110b, 0x1165, 0x11b9, 0,
+#undef V7580
+#define V7580 (V + 29376)
+ 0x110b, 0x1165, 0x11ba, 0,
+#undef V7581
+#define V7581 (V + 29380)
+ 0x110b, 0x1165, 0x11bb, 0,
+#undef V7582
+#define V7582 (V + 29384)
+ 0x110b, 0x1165, 0x11bc, 0,
+#undef V7583
+#define V7583 (V + 29388)
+ 0x110b, 0x1165, 0x11bd, 0,
+#undef V7584
+#define V7584 (V + 29392)
+ 0x110b, 0x1165, 0x11be, 0,
+#undef V7585
+#define V7585 (V + 29396)
+ 0x110b, 0x1165, 0x11bf, 0,
+#undef V7586
+#define V7586 (V + 29400)
+ 0x110b, 0x1165, 0x11c0, 0,
+#undef V7587
+#define V7587 (V + 29404)
+ 0x110b, 0x1165, 0x11c1, 0,
+#undef V7588
+#define V7588 (V + 29408)
+ 0x110b, 0x1165, 0x11c2, 0,
+#undef V7589
+#define V7589 (V + 29412)
+ 0x110b, 0x1166, 0,
+#undef V7590
+#define V7590 (V + 29415)
+ 0x110b, 0x1166, 0x11a8, 0,
+#undef V7591
+#define V7591 (V + 29419)
+ 0x110b, 0x1166, 0x11a9, 0,
+#undef V7592
+#define V7592 (V + 29423)
+ 0x110b, 0x1166, 0x11aa, 0,
+#undef V7593
+#define V7593 (V + 29427)
+ 0x110b, 0x1166, 0x11ab, 0,
+#undef V7594
+#define V7594 (V + 29431)
+ 0x110b, 0x1166, 0x11ac, 0,
+#undef V7595
+#define V7595 (V + 29435)
+ 0x110b, 0x1166, 0x11ad, 0,
+#undef V7596
+#define V7596 (V + 29439)
+ 0x110b, 0x1166, 0x11ae, 0,
+#undef V7597
+#define V7597 (V + 29443)
+ 0x110b, 0x1166, 0x11af, 0,
+#undef V7598
+#define V7598 (V + 29447)
+ 0x110b, 0x1166, 0x11b0, 0,
+#undef V7599
+#define V7599 (V + 29451)
+ 0x110b, 0x1166, 0x11b1, 0,
+#undef V7600
+#define V7600 (V + 29455)
+ 0x110b, 0x1166, 0x11b2, 0,
+#undef V7601
+#define V7601 (V + 29459)
+ 0x110b, 0x1166, 0x11b3, 0,
+#undef V7602
+#define V7602 (V + 29463)
+ 0x110b, 0x1166, 0x11b4, 0,
+#undef V7603
+#define V7603 (V + 29467)
+ 0x110b, 0x1166, 0x11b5, 0,
+#undef V7604
+#define V7604 (V + 29471)
+ 0x110b, 0x1166, 0x11b6, 0,
+#undef V7605
+#define V7605 (V + 29475)
+ 0x110b, 0x1166, 0x11b7, 0,
+#undef V7606
+#define V7606 (V + 29479)
+ 0x110b, 0x1166, 0x11b8, 0,
+#undef V7607
+#define V7607 (V + 29483)
+ 0x110b, 0x1166, 0x11b9, 0,
+#undef V7608
+#define V7608 (V + 29487)
+ 0x110b, 0x1166, 0x11ba, 0,
+#undef V7609
+#define V7609 (V + 29491)
+ 0x110b, 0x1166, 0x11bb, 0,
+#undef V7610
+#define V7610 (V + 29495)
+ 0x110b, 0x1166, 0x11bc, 0,
+#undef V7611
+#define V7611 (V + 29499)
+ 0x110b, 0x1166, 0x11bd, 0,
+#undef V7612
+#define V7612 (V + 29503)
+ 0x110b, 0x1166, 0x11be, 0,
+#undef V7613
+#define V7613 (V + 29507)
+ 0x110b, 0x1166, 0x11bf, 0,
+#undef V7614
+#define V7614 (V + 29511)
+ 0x110b, 0x1166, 0x11c0, 0,
+#undef V7615
+#define V7615 (V + 29515)
+ 0x110b, 0x1166, 0x11c1, 0,
+#undef V7616
+#define V7616 (V + 29519)
+ 0x110b, 0x1166, 0x11c2, 0,
+#undef V7617
+#define V7617 (V + 29523)
+ 0x110b, 0x1167, 0,
+#undef V7618
+#define V7618 (V + 29526)
+ 0x110b, 0x1167, 0x11a8, 0,
+#undef V7619
+#define V7619 (V + 29530)
+ 0x110b, 0x1167, 0x11a9, 0,
+#undef V7620
+#define V7620 (V + 29534)
+ 0x110b, 0x1167, 0x11aa, 0,
+#undef V7621
+#define V7621 (V + 29538)
+ 0x110b, 0x1167, 0x11ab, 0,
+#undef V7622
+#define V7622 (V + 29542)
+ 0x110b, 0x1167, 0x11ac, 0,
+#undef V7623
+#define V7623 (V + 29546)
+ 0x110b, 0x1167, 0x11ad, 0,
+#undef V7624
+#define V7624 (V + 29550)
+ 0x110b, 0x1167, 0x11ae, 0,
+#undef V7625
+#define V7625 (V + 29554)
+ 0x110b, 0x1167, 0x11af, 0,
+#undef V7626
+#define V7626 (V + 29558)
+ 0x110b, 0x1167, 0x11b0, 0,
+#undef V7627
+#define V7627 (V + 29562)
+ 0x110b, 0x1167, 0x11b1, 0,
+#undef V7628
+#define V7628 (V + 29566)
+ 0x110b, 0x1167, 0x11b2, 0,
+#undef V7629
+#define V7629 (V + 29570)
+ 0x110b, 0x1167, 0x11b3, 0,
+#undef V7630
+#define V7630 (V + 29574)
+ 0x110b, 0x1167, 0x11b4, 0,
+#undef V7631
+#define V7631 (V + 29578)
+ 0x110b, 0x1167, 0x11b5, 0,
+#undef V7632
+#define V7632 (V + 29582)
+ 0x110b, 0x1167, 0x11b6, 0,
+#undef V7633
+#define V7633 (V + 29586)
+ 0x110b, 0x1167, 0x11b7, 0,
+#undef V7634
+#define V7634 (V + 29590)
+ 0x110b, 0x1167, 0x11b8, 0,
+#undef V7635
+#define V7635 (V + 29594)
+ 0x110b, 0x1167, 0x11b9, 0,
+#undef V7636
+#define V7636 (V + 29598)
+ 0x110b, 0x1167, 0x11ba, 0,
+#undef V7637
+#define V7637 (V + 29602)
+ 0x110b, 0x1167, 0x11bb, 0,
+#undef V7638
+#define V7638 (V + 29606)
+ 0x110b, 0x1167, 0x11bc, 0,
+#undef V7639
+#define V7639 (V + 29610)
+ 0x110b, 0x1167, 0x11bd, 0,
+#undef V7640
+#define V7640 (V + 29614)
+ 0x110b, 0x1167, 0x11be, 0,
+#undef V7641
+#define V7641 (V + 29618)
+ 0x110b, 0x1167, 0x11bf, 0,
+#undef V7642
+#define V7642 (V + 29622)
+ 0x110b, 0x1167, 0x11c0, 0,
+#undef V7643
+#define V7643 (V + 29626)
+ 0x110b, 0x1167, 0x11c1, 0,
+#undef V7644
+#define V7644 (V + 29630)
+ 0x110b, 0x1167, 0x11c2, 0,
+#undef V7645
+#define V7645 (V + 29634)
+ 0x110b, 0x1168, 0,
+#undef V7646
+#define V7646 (V + 29637)
+ 0x110b, 0x1168, 0x11a8, 0,
+#undef V7647
+#define V7647 (V + 29641)
+ 0x110b, 0x1168, 0x11a9, 0,
+#undef V7648
+#define V7648 (V + 29645)
+ 0x110b, 0x1168, 0x11aa, 0,
+#undef V7649
+#define V7649 (V + 29649)
+ 0x110b, 0x1168, 0x11ab, 0,
+#undef V7650
+#define V7650 (V + 29653)
+ 0x110b, 0x1168, 0x11ac, 0,
+#undef V7651
+#define V7651 (V + 29657)
+ 0x110b, 0x1168, 0x11ad, 0,
+#undef V7652
+#define V7652 (V + 29661)
+ 0x110b, 0x1168, 0x11ae, 0,
+#undef V7653
+#define V7653 (V + 29665)
+ 0x110b, 0x1168, 0x11af, 0,
+#undef V7654
+#define V7654 (V + 29669)
+ 0x110b, 0x1168, 0x11b0, 0,
+#undef V7655
+#define V7655 (V + 29673)
+ 0x110b, 0x1168, 0x11b1, 0,
+#undef V7656
+#define V7656 (V + 29677)
+ 0x110b, 0x1168, 0x11b2, 0,
+#undef V7657
+#define V7657 (V + 29681)
+ 0x110b, 0x1168, 0x11b3, 0,
+#undef V7658
+#define V7658 (V + 29685)
+ 0x110b, 0x1168, 0x11b4, 0,
+#undef V7659
+#define V7659 (V + 29689)
+ 0x110b, 0x1168, 0x11b5, 0,
+#undef V7660
+#define V7660 (V + 29693)
+ 0x110b, 0x1168, 0x11b6, 0,
+#undef V7661
+#define V7661 (V + 29697)
+ 0x110b, 0x1168, 0x11b7, 0,
+#undef V7662
+#define V7662 (V + 29701)
+ 0x110b, 0x1168, 0x11b8, 0,
+#undef V7663
+#define V7663 (V + 29705)
+ 0x110b, 0x1168, 0x11b9, 0,
+#undef V7664
+#define V7664 (V + 29709)
+ 0x110b, 0x1168, 0x11ba, 0,
+#undef V7665
+#define V7665 (V + 29713)
+ 0x110b, 0x1168, 0x11bb, 0,
+#undef V7666
+#define V7666 (V + 29717)
+ 0x110b, 0x1168, 0x11bc, 0,
+#undef V7667
+#define V7667 (V + 29721)
+ 0x110b, 0x1168, 0x11bd, 0,
+#undef V7668
+#define V7668 (V + 29725)
+ 0x110b, 0x1168, 0x11be, 0,
+#undef V7669
+#define V7669 (V + 29729)
+ 0x110b, 0x1168, 0x11bf, 0,
+#undef V7670
+#define V7670 (V + 29733)
+ 0x110b, 0x1168, 0x11c0, 0,
+#undef V7671
+#define V7671 (V + 29737)
+ 0x110b, 0x1168, 0x11c1, 0,
+#undef V7672
+#define V7672 (V + 29741)
+ 0x110b, 0x1168, 0x11c2, 0,
+#undef V7673
+#define V7673 (V + 29745)
+ 0x110b, 0x1169, 0,
+#undef V7674
+#define V7674 (V + 29748)
+ 0x110b, 0x1169, 0x11a8, 0,
+#undef V7675
+#define V7675 (V + 29752)
+ 0x110b, 0x1169, 0x11a9, 0,
+#undef V7676
+#define V7676 (V + 29756)
+ 0x110b, 0x1169, 0x11aa, 0,
+#undef V7677
+#define V7677 (V + 29760)
+ 0x110b, 0x1169, 0x11ab, 0,
+#undef V7678
+#define V7678 (V + 29764)
+ 0x110b, 0x1169, 0x11ac, 0,
+#undef V7679
+#define V7679 (V + 29768)
+ 0x110b, 0x1169, 0x11ad, 0,
+#undef V7680
+#define V7680 (V + 29772)
+ 0x110b, 0x1169, 0x11ae, 0,
+#undef V7681
+#define V7681 (V + 29776)
+ 0x110b, 0x1169, 0x11af, 0,
+#undef V7682
+#define V7682 (V + 29780)
+ 0x110b, 0x1169, 0x11b0, 0,
+#undef V7683
+#define V7683 (V + 29784)
+ 0x110b, 0x1169, 0x11b1, 0,
+#undef V7684
+#define V7684 (V + 29788)
+ 0x110b, 0x1169, 0x11b2, 0,
+#undef V7685
+#define V7685 (V + 29792)
+ 0x110b, 0x1169, 0x11b3, 0,
+#undef V7686
+#define V7686 (V + 29796)
+ 0x110b, 0x1169, 0x11b4, 0,
+#undef V7687
+#define V7687 (V + 29800)
+ 0x110b, 0x1169, 0x11b5, 0,
+#undef V7688
+#define V7688 (V + 29804)
+ 0x110b, 0x1169, 0x11b6, 0,
+#undef V7689
+#define V7689 (V + 29808)
+ 0x110b, 0x1169, 0x11b7, 0,
+#undef V7690
+#define V7690 (V + 29812)
+ 0x110b, 0x1169, 0x11b8, 0,
+#undef V7691
+#define V7691 (V + 29816)
+ 0x110b, 0x1169, 0x11b9, 0,
+#undef V7692
+#define V7692 (V + 29820)
+ 0x110b, 0x1169, 0x11ba, 0,
+#undef V7693
+#define V7693 (V + 29824)
+ 0x110b, 0x1169, 0x11bb, 0,
+#undef V7694
+#define V7694 (V + 29828)
+ 0x110b, 0x1169, 0x11bc, 0,
+#undef V7695
+#define V7695 (V + 29832)
+ 0x110b, 0x1169, 0x11bd, 0,
+#undef V7696
+#define V7696 (V + 29836)
+ 0x110b, 0x1169, 0x11be, 0,
+#undef V7697
+#define V7697 (V + 29840)
+ 0x110b, 0x1169, 0x11bf, 0,
+#undef V7698
+#define V7698 (V + 29844)
+ 0x110b, 0x1169, 0x11c0, 0,
+#undef V7699
+#define V7699 (V + 29848)
+ 0x110b, 0x1169, 0x11c1, 0,
+#undef V7700
+#define V7700 (V + 29852)
+ 0x110b, 0x1169, 0x11c2, 0,
+#undef V7701
+#define V7701 (V + 29856)
+ 0x110b, 0x116a, 0,
+#undef V7702
+#define V7702 (V + 29859)
+ 0x110b, 0x116a, 0x11a8, 0,
+#undef V7703
+#define V7703 (V + 29863)
+ 0x110b, 0x116a, 0x11a9, 0,
+#undef V7704
+#define V7704 (V + 29867)
+ 0x110b, 0x116a, 0x11aa, 0,
+#undef V7705
+#define V7705 (V + 29871)
+ 0x110b, 0x116a, 0x11ab, 0,
+#undef V7706
+#define V7706 (V + 29875)
+ 0x110b, 0x116a, 0x11ac, 0,
+#undef V7707
+#define V7707 (V + 29879)
+ 0x110b, 0x116a, 0x11ad, 0,
+#undef V7708
+#define V7708 (V + 29883)
+ 0x110b, 0x116a, 0x11ae, 0,
+#undef V7709
+#define V7709 (V + 29887)
+ 0x110b, 0x116a, 0x11af, 0,
+#undef V7710
+#define V7710 (V + 29891)
+ 0x110b, 0x116a, 0x11b0, 0,
+#undef V7711
+#define V7711 (V + 29895)
+ 0x110b, 0x116a, 0x11b1, 0,
+#undef V7712
+#define V7712 (V + 29899)
+ 0x110b, 0x116a, 0x11b2, 0,
+#undef V7713
+#define V7713 (V + 29903)
+ 0x110b, 0x116a, 0x11b3, 0,
+#undef V7714
+#define V7714 (V + 29907)
+ 0x110b, 0x116a, 0x11b4, 0,
+#undef V7715
+#define V7715 (V + 29911)
+ 0x110b, 0x116a, 0x11b5, 0,
+#undef V7716
+#define V7716 (V + 29915)
+ 0x110b, 0x116a, 0x11b6, 0,
+#undef V7717
+#define V7717 (V + 29919)
+ 0x110b, 0x116a, 0x11b7, 0,
+#undef V7718
+#define V7718 (V + 29923)
+ 0x110b, 0x116a, 0x11b8, 0,
+#undef V7719
+#define V7719 (V + 29927)
+ 0x110b, 0x116a, 0x11b9, 0,
+#undef V7720
+#define V7720 (V + 29931)
+ 0x110b, 0x116a, 0x11ba, 0,
+#undef V7721
+#define V7721 (V + 29935)
+ 0x110b, 0x116a, 0x11bb, 0,
+#undef V7722
+#define V7722 (V + 29939)
+ 0x110b, 0x116a, 0x11bc, 0,
+#undef V7723
+#define V7723 (V + 29943)
+ 0x110b, 0x116a, 0x11bd, 0,
+#undef V7724
+#define V7724 (V + 29947)
+ 0x110b, 0x116a, 0x11be, 0,
+#undef V7725
+#define V7725 (V + 29951)
+ 0x110b, 0x116a, 0x11bf, 0,
+#undef V7726
+#define V7726 (V + 29955)
+ 0x110b, 0x116a, 0x11c0, 0,
+#undef V7727
+#define V7727 (V + 29959)
+ 0x110b, 0x116a, 0x11c1, 0,
+#undef V7728
+#define V7728 (V + 29963)
+ 0x110b, 0x116a, 0x11c2, 0,
+#undef V7729
+#define V7729 (V + 29967)
+ 0x110b, 0x116b, 0,
+#undef V7730
+#define V7730 (V + 29970)
+ 0x110b, 0x116b, 0x11a8, 0,
+#undef V7731
+#define V7731 (V + 29974)
+ 0x110b, 0x116b, 0x11a9, 0,
+#undef V7732
+#define V7732 (V + 29978)
+ 0x110b, 0x116b, 0x11aa, 0,
+#undef V7733
+#define V7733 (V + 29982)
+ 0x110b, 0x116b, 0x11ab, 0,
+#undef V7734
+#define V7734 (V + 29986)
+ 0x110b, 0x116b, 0x11ac, 0,
+#undef V7735
+#define V7735 (V + 29990)
+ 0x110b, 0x116b, 0x11ad, 0,
+#undef V7736
+#define V7736 (V + 29994)
+ 0x110b, 0x116b, 0x11ae, 0,
+#undef V7737
+#define V7737 (V + 29998)
+ 0x110b, 0x116b, 0x11af, 0,
+#undef V7738
+#define V7738 (V + 30002)
+ 0x110b, 0x116b, 0x11b0, 0,
+#undef V7739
+#define V7739 (V + 30006)
+ 0x110b, 0x116b, 0x11b1, 0,
+#undef V7740
+#define V7740 (V + 30010)
+ 0x110b, 0x116b, 0x11b2, 0,
+#undef V7741
+#define V7741 (V + 30014)
+ 0x110b, 0x116b, 0x11b3, 0,
+#undef V7742
+#define V7742 (V + 30018)
+ 0x110b, 0x116b, 0x11b4, 0,
+#undef V7743
+#define V7743 (V + 30022)
+ 0x110b, 0x116b, 0x11b5, 0,
+#undef V7744
+#define V7744 (V + 30026)
+ 0x110b, 0x116b, 0x11b6, 0,
+#undef V7745
+#define V7745 (V + 30030)
+ 0x110b, 0x116b, 0x11b7, 0,
+#undef V7746
+#define V7746 (V + 30034)
+ 0x110b, 0x116b, 0x11b8, 0,
+#undef V7747
+#define V7747 (V + 30038)
+ 0x110b, 0x116b, 0x11b9, 0,
+#undef V7748
+#define V7748 (V + 30042)
+ 0x110b, 0x116b, 0x11ba, 0,
+#undef V7749
+#define V7749 (V + 30046)
+ 0x110b, 0x116b, 0x11bb, 0,
+#undef V7750
+#define V7750 (V + 30050)
+ 0x110b, 0x116b, 0x11bc, 0,
+#undef V7751
+#define V7751 (V + 30054)
+ 0x110b, 0x116b, 0x11bd, 0,
+#undef V7752
+#define V7752 (V + 30058)
+ 0x110b, 0x116b, 0x11be, 0,
+#undef V7753
+#define V7753 (V + 30062)
+ 0x110b, 0x116b, 0x11bf, 0,
+#undef V7754
+#define V7754 (V + 30066)
+ 0x110b, 0x116b, 0x11c0, 0,
+#undef V7755
+#define V7755 (V + 30070)
+ 0x110b, 0x116b, 0x11c1, 0,
+#undef V7756
+#define V7756 (V + 30074)
+ 0x110b, 0x116b, 0x11c2, 0,
+#undef V7757
+#define V7757 (V + 30078)
+ 0x110b, 0x116c, 0,
+#undef V7758
+#define V7758 (V + 30081)
+ 0x110b, 0x116c, 0x11a8, 0,
+#undef V7759
+#define V7759 (V + 30085)
+ 0x110b, 0x116c, 0x11a9, 0,
+#undef V7760
+#define V7760 (V + 30089)
+ 0x110b, 0x116c, 0x11aa, 0,
+#undef V7761
+#define V7761 (V + 30093)
+ 0x110b, 0x116c, 0x11ab, 0,
+#undef V7762
+#define V7762 (V + 30097)
+ 0x110b, 0x116c, 0x11ac, 0,
+#undef V7763
+#define V7763 (V + 30101)
+ 0x110b, 0x116c, 0x11ad, 0,
+#undef V7764
+#define V7764 (V + 30105)
+ 0x110b, 0x116c, 0x11ae, 0,
+#undef V7765
+#define V7765 (V + 30109)
+ 0x110b, 0x116c, 0x11af, 0,
+#undef V7766
+#define V7766 (V + 30113)
+ 0x110b, 0x116c, 0x11b0, 0,
+#undef V7767
+#define V7767 (V + 30117)
+ 0x110b, 0x116c, 0x11b1, 0,
+#undef V7768
+#define V7768 (V + 30121)
+ 0x110b, 0x116c, 0x11b2, 0,
+#undef V7769
+#define V7769 (V + 30125)
+ 0x110b, 0x116c, 0x11b3, 0,
+#undef V7770
+#define V7770 (V + 30129)
+ 0x110b, 0x116c, 0x11b4, 0,
+#undef V7771
+#define V7771 (V + 30133)
+ 0x110b, 0x116c, 0x11b5, 0,
+#undef V7772
+#define V7772 (V + 30137)
+ 0x110b, 0x116c, 0x11b6, 0,
+#undef V7773
+#define V7773 (V + 30141)
+ 0x110b, 0x116c, 0x11b7, 0,
+#undef V7774
+#define V7774 (V + 30145)
+ 0x110b, 0x116c, 0x11b8, 0,
+#undef V7775
+#define V7775 (V + 30149)
+ 0x110b, 0x116c, 0x11b9, 0,
+#undef V7776
+#define V7776 (V + 30153)
+ 0x110b, 0x116c, 0x11ba, 0,
+#undef V7777
+#define V7777 (V + 30157)
+ 0x110b, 0x116c, 0x11bb, 0,
+#undef V7778
+#define V7778 (V + 30161)
+ 0x110b, 0x116c, 0x11bc, 0,
+#undef V7779
+#define V7779 (V + 30165)
+ 0x110b, 0x116c, 0x11bd, 0,
+#undef V7780
+#define V7780 (V + 30169)
+ 0x110b, 0x116c, 0x11be, 0,
+#undef V7781
+#define V7781 (V + 30173)
+ 0x110b, 0x116c, 0x11bf, 0,
+#undef V7782
+#define V7782 (V + 30177)
+ 0x110b, 0x116c, 0x11c0, 0,
+#undef V7783
+#define V7783 (V + 30181)
+ 0x110b, 0x116c, 0x11c1, 0,
+#undef V7784
+#define V7784 (V + 30185)
+ 0x110b, 0x116c, 0x11c2, 0,
+#undef V7785
+#define V7785 (V + 30189)
+ 0x110b, 0x116d, 0,
+#undef V7786
+#define V7786 (V + 30192)
+ 0x110b, 0x116d, 0x11a8, 0,
+#undef V7787
+#define V7787 (V + 30196)
+ 0x110b, 0x116d, 0x11a9, 0,
+#undef V7788
+#define V7788 (V + 30200)
+ 0x110b, 0x116d, 0x11aa, 0,
+#undef V7789
+#define V7789 (V + 30204)
+ 0x110b, 0x116d, 0x11ab, 0,
+#undef V7790
+#define V7790 (V + 30208)
+ 0x110b, 0x116d, 0x11ac, 0,
+#undef V7791
+#define V7791 (V + 30212)
+ 0x110b, 0x116d, 0x11ad, 0,
+#undef V7792
+#define V7792 (V + 30216)
+ 0x110b, 0x116d, 0x11ae, 0,
+#undef V7793
+#define V7793 (V + 30220)
+ 0x110b, 0x116d, 0x11af, 0,
+#undef V7794
+#define V7794 (V + 30224)
+ 0x110b, 0x116d, 0x11b0, 0,
+#undef V7795
+#define V7795 (V + 30228)
+ 0x110b, 0x116d, 0x11b1, 0,
+#undef V7796
+#define V7796 (V + 30232)
+ 0x110b, 0x116d, 0x11b2, 0,
+#undef V7797
+#define V7797 (V + 30236)
+ 0x110b, 0x116d, 0x11b3, 0,
+#undef V7798
+#define V7798 (V + 30240)
+ 0x110b, 0x116d, 0x11b4, 0,
+#undef V7799
+#define V7799 (V + 30244)
+ 0x110b, 0x116d, 0x11b5, 0,
+#undef V7800
+#define V7800 (V + 30248)
+ 0x110b, 0x116d, 0x11b6, 0,
+#undef V7801
+#define V7801 (V + 30252)
+ 0x110b, 0x116d, 0x11b7, 0,
+#undef V7802
+#define V7802 (V + 30256)
+ 0x110b, 0x116d, 0x11b8, 0,
+#undef V7803
+#define V7803 (V + 30260)
+ 0x110b, 0x116d, 0x11b9, 0,
+#undef V7804
+#define V7804 (V + 30264)
+ 0x110b, 0x116d, 0x11ba, 0,
+#undef V7805
+#define V7805 (V + 30268)
+ 0x110b, 0x116d, 0x11bb, 0,
+#undef V7806
+#define V7806 (V + 30272)
+ 0x110b, 0x116d, 0x11bc, 0,
+#undef V7807
+#define V7807 (V + 30276)
+ 0x110b, 0x116d, 0x11bd, 0,
+#undef V7808
+#define V7808 (V + 30280)
+ 0x110b, 0x116d, 0x11be, 0,
+#undef V7809
+#define V7809 (V + 30284)
+ 0x110b, 0x116d, 0x11bf, 0,
+#undef V7810
+#define V7810 (V + 30288)
+ 0x110b, 0x116d, 0x11c0, 0,
+#undef V7811
+#define V7811 (V + 30292)
+ 0x110b, 0x116d, 0x11c1, 0,
+#undef V7812
+#define V7812 (V + 30296)
+ 0x110b, 0x116d, 0x11c2, 0,
+#undef V7813
+#define V7813 (V + 30300)
+ 0x110b, 0x116e, 0,
+#undef V7814
+#define V7814 (V + 30303)
+ 0x110b, 0x116e, 0x11a8, 0,
+#undef V7815
+#define V7815 (V + 30307)
+ 0x110b, 0x116e, 0x11a9, 0,
+#undef V7816
+#define V7816 (V + 30311)
+ 0x110b, 0x116e, 0x11aa, 0,
+#undef V7817
+#define V7817 (V + 30315)
+ 0x110b, 0x116e, 0x11ab, 0,
+#undef V7818
+#define V7818 (V + 30319)
+ 0x110b, 0x116e, 0x11ac, 0,
+#undef V7819
+#define V7819 (V + 30323)
+ 0x110b, 0x116e, 0x11ad, 0,
+#undef V7820
+#define V7820 (V + 30327)
+ 0x110b, 0x116e, 0x11ae, 0,
+#undef V7821
+#define V7821 (V + 30331)
+ 0x110b, 0x116e, 0x11af, 0,
+#undef V7822
+#define V7822 (V + 30335)
+ 0x110b, 0x116e, 0x11b0, 0,
+#undef V7823
+#define V7823 (V + 30339)
+ 0x110b, 0x116e, 0x11b1, 0,
+#undef V7824
+#define V7824 (V + 30343)
+ 0x110b, 0x116e, 0x11b2, 0,
+#undef V7825
+#define V7825 (V + 30347)
+ 0x110b, 0x116e, 0x11b3, 0,
+#undef V7826
+#define V7826 (V + 30351)
+ 0x110b, 0x116e, 0x11b4, 0,
+#undef V7827
+#define V7827 (V + 30355)
+ 0x110b, 0x116e, 0x11b5, 0,
+#undef V7828
+#define V7828 (V + 30359)
+ 0x110b, 0x116e, 0x11b6, 0,
+#undef V7829
+#define V7829 (V + 30363)
+ 0x110b, 0x116e, 0x11b7, 0,
+#undef V7830
+#define V7830 (V + 30367)
+ 0x110b, 0x116e, 0x11b8, 0,
+#undef V7831
+#define V7831 (V + 30371)
+ 0x110b, 0x116e, 0x11b9, 0,
+#undef V7832
+#define V7832 (V + 30375)
+ 0x110b, 0x116e, 0x11ba, 0,
+#undef V7833
+#define V7833 (V + 30379)
+ 0x110b, 0x116e, 0x11bb, 0,
+#undef V7834
+#define V7834 (V + 30383)
+ 0x110b, 0x116e, 0x11bc, 0,
+#undef V7835
+#define V7835 (V + 30387)
+ 0x110b, 0x116e, 0x11bd, 0,
+#undef V7836
+#define V7836 (V + 30391)
+ 0x110b, 0x116e, 0x11be, 0,
+#undef V7837
+#define V7837 (V + 30395)
+ 0x110b, 0x116e, 0x11bf, 0,
+#undef V7838
+#define V7838 (V + 30399)
+ 0x110b, 0x116e, 0x11c0, 0,
+#undef V7839
+#define V7839 (V + 30403)
+ 0x110b, 0x116e, 0x11c1, 0,
+#undef V7840
+#define V7840 (V + 30407)
+ 0x110b, 0x116e, 0x11c2, 0,
+#undef V7841
+#define V7841 (V + 30411)
+ 0x110b, 0x116f, 0,
+#undef V7842
+#define V7842 (V + 30414)
+ 0x110b, 0x116f, 0x11a8, 0,
+#undef V7843
+#define V7843 (V + 30418)
+ 0x110b, 0x116f, 0x11a9, 0,
+#undef V7844
+#define V7844 (V + 30422)
+ 0x110b, 0x116f, 0x11aa, 0,
+#undef V7845
+#define V7845 (V + 30426)
+ 0x110b, 0x116f, 0x11ab, 0,
+#undef V7846
+#define V7846 (V + 30430)
+ 0x110b, 0x116f, 0x11ac, 0,
+#undef V7847
+#define V7847 (V + 30434)
+ 0x110b, 0x116f, 0x11ad, 0,
+#undef V7848
+#define V7848 (V + 30438)
+ 0x110b, 0x116f, 0x11ae, 0,
+#undef V7849
+#define V7849 (V + 30442)
+ 0x110b, 0x116f, 0x11af, 0,
+#undef V7850
+#define V7850 (V + 30446)
+ 0x110b, 0x116f, 0x11b0, 0,
+#undef V7851
+#define V7851 (V + 30450)
+ 0x110b, 0x116f, 0x11b1, 0,
+#undef V7852
+#define V7852 (V + 30454)
+ 0x110b, 0x116f, 0x11b2, 0,
+#undef V7853
+#define V7853 (V + 30458)
+ 0x110b, 0x116f, 0x11b3, 0,
+#undef V7854
+#define V7854 (V + 30462)
+ 0x110b, 0x116f, 0x11b4, 0,
+#undef V7855
+#define V7855 (V + 30466)
+ 0x110b, 0x116f, 0x11b5, 0,
+#undef V7856
+#define V7856 (V + 30470)
+ 0x110b, 0x116f, 0x11b6, 0,
+#undef V7857
+#define V7857 (V + 30474)
+ 0x110b, 0x116f, 0x11b7, 0,
+#undef V7858
+#define V7858 (V + 30478)
+ 0x110b, 0x116f, 0x11b8, 0,
+#undef V7859
+#define V7859 (V + 30482)
+ 0x110b, 0x116f, 0x11b9, 0,
+#undef V7860
+#define V7860 (V + 30486)
+ 0x110b, 0x116f, 0x11ba, 0,
+#undef V7861
+#define V7861 (V + 30490)
+ 0x110b, 0x116f, 0x11bb, 0,
+#undef V7862
+#define V7862 (V + 30494)
+ 0x110b, 0x116f, 0x11bc, 0,
+#undef V7863
+#define V7863 (V + 30498)
+ 0x110b, 0x116f, 0x11bd, 0,
+#undef V7864
+#define V7864 (V + 30502)
+ 0x110b, 0x116f, 0x11be, 0,
+#undef V7865
+#define V7865 (V + 30506)
+ 0x110b, 0x116f, 0x11bf, 0,
+#undef V7866
+#define V7866 (V + 30510)
+ 0x110b, 0x116f, 0x11c0, 0,
+#undef V7867
+#define V7867 (V + 30514)
+ 0x110b, 0x116f, 0x11c1, 0,
+#undef V7868
+#define V7868 (V + 30518)
+ 0x110b, 0x116f, 0x11c2, 0,
+#undef V7869
+#define V7869 (V + 30522)
+ 0x110b, 0x1170, 0,
+#undef V7870
+#define V7870 (V + 30525)
+ 0x110b, 0x1170, 0x11a8, 0,
+#undef V7871
+#define V7871 (V + 30529)
+ 0x110b, 0x1170, 0x11a9, 0,
+#undef V7872
+#define V7872 (V + 30533)
+ 0x110b, 0x1170, 0x11aa, 0,
+#undef V7873
+#define V7873 (V + 30537)
+ 0x110b, 0x1170, 0x11ab, 0,
+#undef V7874
+#define V7874 (V + 30541)
+ 0x110b, 0x1170, 0x11ac, 0,
+#undef V7875
+#define V7875 (V + 30545)
+ 0x110b, 0x1170, 0x11ad, 0,
+#undef V7876
+#define V7876 (V + 30549)
+ 0x110b, 0x1170, 0x11ae, 0,
+#undef V7877
+#define V7877 (V + 30553)
+ 0x110b, 0x1170, 0x11af, 0,
+#undef V7878
+#define V7878 (V + 30557)
+ 0x110b, 0x1170, 0x11b0, 0,
+#undef V7879
+#define V7879 (V + 30561)
+ 0x110b, 0x1170, 0x11b1, 0,
+#undef V7880
+#define V7880 (V + 30565)
+ 0x110b, 0x1170, 0x11b2, 0,
+#undef V7881
+#define V7881 (V + 30569)
+ 0x110b, 0x1170, 0x11b3, 0,
+#undef V7882
+#define V7882 (V + 30573)
+ 0x110b, 0x1170, 0x11b4, 0,
+#undef V7883
+#define V7883 (V + 30577)
+ 0x110b, 0x1170, 0x11b5, 0,
+#undef V7884
+#define V7884 (V + 30581)
+ 0x110b, 0x1170, 0x11b6, 0,
+#undef V7885
+#define V7885 (V + 30585)
+ 0x110b, 0x1170, 0x11b7, 0,
+#undef V7886
+#define V7886 (V + 30589)
+ 0x110b, 0x1170, 0x11b8, 0,
+#undef V7887
+#define V7887 (V + 30593)
+ 0x110b, 0x1170, 0x11b9, 0,
+#undef V7888
+#define V7888 (V + 30597)
+ 0x110b, 0x1170, 0x11ba, 0,
+#undef V7889
+#define V7889 (V + 30601)
+ 0x110b, 0x1170, 0x11bb, 0,
+#undef V7890
+#define V7890 (V + 30605)
+ 0x110b, 0x1170, 0x11bc, 0,
+#undef V7891
+#define V7891 (V + 30609)
+ 0x110b, 0x1170, 0x11bd, 0,
+#undef V7892
+#define V7892 (V + 30613)
+ 0x110b, 0x1170, 0x11be, 0,
+#undef V7893
+#define V7893 (V + 30617)
+ 0x110b, 0x1170, 0x11bf, 0,
+#undef V7894
+#define V7894 (V + 30621)
+ 0x110b, 0x1170, 0x11c0, 0,
+#undef V7895
+#define V7895 (V + 30625)
+ 0x110b, 0x1170, 0x11c1, 0,
+#undef V7896
+#define V7896 (V + 30629)
+ 0x110b, 0x1170, 0x11c2, 0,
+#undef V7897
+#define V7897 (V + 30633)
+ 0x110b, 0x1171, 0,
+#undef V7898
+#define V7898 (V + 30636)
+ 0x110b, 0x1171, 0x11a8, 0,
+#undef V7899
+#define V7899 (V + 30640)
+ 0x110b, 0x1171, 0x11a9, 0,
+#undef V7900
+#define V7900 (V + 30644)
+ 0x110b, 0x1171, 0x11aa, 0,
+#undef V7901
+#define V7901 (V + 30648)
+ 0x110b, 0x1171, 0x11ab, 0,
+#undef V7902
+#define V7902 (V + 30652)
+ 0x110b, 0x1171, 0x11ac, 0,
+#undef V7903
+#define V7903 (V + 30656)
+ 0x110b, 0x1171, 0x11ad, 0,
+#undef V7904
+#define V7904 (V + 30660)
+ 0x110b, 0x1171, 0x11ae, 0,
+#undef V7905
+#define V7905 (V + 30664)
+ 0x110b, 0x1171, 0x11af, 0,
+#undef V7906
+#define V7906 (V + 30668)
+ 0x110b, 0x1171, 0x11b0, 0,
+#undef V7907
+#define V7907 (V + 30672)
+ 0x110b, 0x1171, 0x11b1, 0,
+#undef V7908
+#define V7908 (V + 30676)
+ 0x110b, 0x1171, 0x11b2, 0,
+#undef V7909
+#define V7909 (V + 30680)
+ 0x110b, 0x1171, 0x11b3, 0,
+#undef V7910
+#define V7910 (V + 30684)
+ 0x110b, 0x1171, 0x11b4, 0,
+#undef V7911
+#define V7911 (V + 30688)
+ 0x110b, 0x1171, 0x11b5, 0,
+#undef V7912
+#define V7912 (V + 30692)
+ 0x110b, 0x1171, 0x11b6, 0,
+#undef V7913
+#define V7913 (V + 30696)
+ 0x110b, 0x1171, 0x11b7, 0,
+#undef V7914
+#define V7914 (V + 30700)
+ 0x110b, 0x1171, 0x11b8, 0,
+#undef V7915
+#define V7915 (V + 30704)
+ 0x110b, 0x1171, 0x11b9, 0,
+#undef V7916
+#define V7916 (V + 30708)
+ 0x110b, 0x1171, 0x11ba, 0,
+#undef V7917
+#define V7917 (V + 30712)
+ 0x110b, 0x1171, 0x11bb, 0,
+#undef V7918
+#define V7918 (V + 30716)
+ 0x110b, 0x1171, 0x11bc, 0,
+#undef V7919
+#define V7919 (V + 30720)
+ 0x110b, 0x1171, 0x11bd, 0,
+#undef V7920
+#define V7920 (V + 30724)
+ 0x110b, 0x1171, 0x11be, 0,
+#undef V7921
+#define V7921 (V + 30728)
+ 0x110b, 0x1171, 0x11bf, 0,
+#undef V7922
+#define V7922 (V + 30732)
+ 0x110b, 0x1171, 0x11c0, 0,
+#undef V7923
+#define V7923 (V + 30736)
+ 0x110b, 0x1171, 0x11c1, 0,
+#undef V7924
+#define V7924 (V + 30740)
+ 0x110b, 0x1171, 0x11c2, 0,
+#undef V7925
+#define V7925 (V + 30744)
+ 0x110b, 0x1172, 0,
+#undef V7926
+#define V7926 (V + 30747)
+ 0x110b, 0x1172, 0x11a8, 0,
+#undef V7927
+#define V7927 (V + 30751)
+ 0x110b, 0x1172, 0x11a9, 0,
+#undef V7928
+#define V7928 (V + 30755)
+ 0x110b, 0x1172, 0x11aa, 0,
+#undef V7929
+#define V7929 (V + 30759)
+ 0x110b, 0x1172, 0x11ab, 0,
+#undef V7930
+#define V7930 (V + 30763)
+ 0x110b, 0x1172, 0x11ac, 0,
+#undef V7931
+#define V7931 (V + 30767)
+ 0x110b, 0x1172, 0x11ad, 0,
+#undef V7932
+#define V7932 (V + 30771)
+ 0x110b, 0x1172, 0x11ae, 0,
+#undef V7933
+#define V7933 (V + 30775)
+ 0x110b, 0x1172, 0x11af, 0,
+#undef V7934
+#define V7934 (V + 30779)
+ 0x110b, 0x1172, 0x11b0, 0,
+#undef V7935
+#define V7935 (V + 30783)
+ 0x110b, 0x1172, 0x11b1, 0,
+#undef V7936
+#define V7936 (V + 30787)
+ 0x110b, 0x1172, 0x11b2, 0,
+#undef V7937
+#define V7937 (V + 30791)
+ 0x110b, 0x1172, 0x11b3, 0,
+#undef V7938
+#define V7938 (V + 30795)
+ 0x110b, 0x1172, 0x11b4, 0,
+#undef V7939
+#define V7939 (V + 30799)
+ 0x110b, 0x1172, 0x11b5, 0,
+#undef V7940
+#define V7940 (V + 30803)
+ 0x110b, 0x1172, 0x11b6, 0,
+#undef V7941
+#define V7941 (V + 30807)
+ 0x110b, 0x1172, 0x11b7, 0,
+#undef V7942
+#define V7942 (V + 30811)
+ 0x110b, 0x1172, 0x11b8, 0,
+#undef V7943
+#define V7943 (V + 30815)
+ 0x110b, 0x1172, 0x11b9, 0,
+#undef V7944
+#define V7944 (V + 30819)
+ 0x110b, 0x1172, 0x11ba, 0,
+#undef V7945
+#define V7945 (V + 30823)
+ 0x110b, 0x1172, 0x11bb, 0,
+#undef V7946
+#define V7946 (V + 30827)
+ 0x110b, 0x1172, 0x11bc, 0,
+#undef V7947
+#define V7947 (V + 30831)
+ 0x110b, 0x1172, 0x11bd, 0,
+#undef V7948
+#define V7948 (V + 30835)
+ 0x110b, 0x1172, 0x11be, 0,
+#undef V7949
+#define V7949 (V + 30839)
+ 0x110b, 0x1172, 0x11bf, 0,
+#undef V7950
+#define V7950 (V + 30843)
+ 0x110b, 0x1172, 0x11c0, 0,
+#undef V7951
+#define V7951 (V + 30847)
+ 0x110b, 0x1172, 0x11c1, 0,
+#undef V7952
+#define V7952 (V + 30851)
+ 0x110b, 0x1172, 0x11c2, 0,
+#undef V7953
+#define V7953 (V + 30855)
+ 0x110b, 0x1173, 0,
+#undef V7954
+#define V7954 (V + 30858)
+ 0x110b, 0x1173, 0x11a8, 0,
+#undef V7955
+#define V7955 (V + 30862)
+ 0x110b, 0x1173, 0x11a9, 0,
+#undef V7956
+#define V7956 (V + 30866)
+ 0x110b, 0x1173, 0x11aa, 0,
+#undef V7957
+#define V7957 (V + 30870)
+ 0x110b, 0x1173, 0x11ab, 0,
+#undef V7958
+#define V7958 (V + 30874)
+ 0x110b, 0x1173, 0x11ac, 0,
+#undef V7959
+#define V7959 (V + 30878)
+ 0x110b, 0x1173, 0x11ad, 0,
+#undef V7960
+#define V7960 (V + 30882)
+ 0x110b, 0x1173, 0x11ae, 0,
+#undef V7961
+#define V7961 (V + 30886)
+ 0x110b, 0x1173, 0x11af, 0,
+#undef V7962
+#define V7962 (V + 30890)
+ 0x110b, 0x1173, 0x11b0, 0,
+#undef V7963
+#define V7963 (V + 30894)
+ 0x110b, 0x1173, 0x11b1, 0,
+#undef V7964
+#define V7964 (V + 30898)
+ 0x110b, 0x1173, 0x11b2, 0,
+#undef V7965
+#define V7965 (V + 30902)
+ 0x110b, 0x1173, 0x11b3, 0,
+#undef V7966
+#define V7966 (V + 30906)
+ 0x110b, 0x1173, 0x11b4, 0,
+#undef V7967
+#define V7967 (V + 30910)
+ 0x110b, 0x1173, 0x11b5, 0,
+#undef V7968
+#define V7968 (V + 30914)
+ 0x110b, 0x1173, 0x11b6, 0,
+#undef V7969
+#define V7969 (V + 30918)
+ 0x110b, 0x1173, 0x11b7, 0,
+#undef V7970
+#define V7970 (V + 30922)
+ 0x110b, 0x1173, 0x11b8, 0,
+#undef V7971
+#define V7971 (V + 30926)
+ 0x110b, 0x1173, 0x11b9, 0,
+#undef V7972
+#define V7972 (V + 30930)
+ 0x110b, 0x1173, 0x11ba, 0,
+#undef V7973
+#define V7973 (V + 30934)
+ 0x110b, 0x1173, 0x11bb, 0,
+#undef V7974
+#define V7974 (V + 30938)
+ 0x110b, 0x1173, 0x11bc, 0,
+#undef V7975
+#define V7975 (V + 30942)
+ 0x110b, 0x1173, 0x11bd, 0,
+#undef V7976
+#define V7976 (V + 30946)
+ 0x110b, 0x1173, 0x11be, 0,
+#undef V7977
+#define V7977 (V + 30950)
+ 0x110b, 0x1173, 0x11bf, 0,
+#undef V7978
+#define V7978 (V + 30954)
+ 0x110b, 0x1173, 0x11c0, 0,
+#undef V7979
+#define V7979 (V + 30958)
+ 0x110b, 0x1173, 0x11c1, 0,
+#undef V7980
+#define V7980 (V + 30962)
+ 0x110b, 0x1173, 0x11c2, 0,
+#undef V7981
+#define V7981 (V + 30966)
+ 0x110b, 0x1174, 0,
+#undef V7982
+#define V7982 (V + 30969)
+ 0x110b, 0x1174, 0x11a8, 0,
+#undef V7983
+#define V7983 (V + 30973)
+ 0x110b, 0x1174, 0x11a9, 0,
+#undef V7984
+#define V7984 (V + 30977)
+ 0x110b, 0x1174, 0x11aa, 0,
+#undef V7985
+#define V7985 (V + 30981)
+ 0x110b, 0x1174, 0x11ab, 0,
+#undef V7986
+#define V7986 (V + 30985)
+ 0x110b, 0x1174, 0x11ac, 0,
+#undef V7987
+#define V7987 (V + 30989)
+ 0x110b, 0x1174, 0x11ad, 0,
+#undef V7988
+#define V7988 (V + 30993)
+ 0x110b, 0x1174, 0x11ae, 0,
+#undef V7989
+#define V7989 (V + 30997)
+ 0x110b, 0x1174, 0x11af, 0,
+#undef V7990
+#define V7990 (V + 31001)
+ 0x110b, 0x1174, 0x11b0, 0,
+#undef V7991
+#define V7991 (V + 31005)
+ 0x110b, 0x1174, 0x11b1, 0,
+#undef V7992
+#define V7992 (V + 31009)
+ 0x110b, 0x1174, 0x11b2, 0,
+#undef V7993
+#define V7993 (V + 31013)
+ 0x110b, 0x1174, 0x11b3, 0,
+#undef V7994
+#define V7994 (V + 31017)
+ 0x110b, 0x1174, 0x11b4, 0,
+#undef V7995
+#define V7995 (V + 31021)
+ 0x110b, 0x1174, 0x11b5, 0,
+#undef V7996
+#define V7996 (V + 31025)
+ 0x110b, 0x1174, 0x11b6, 0,
+#undef V7997
+#define V7997 (V + 31029)
+ 0x110b, 0x1174, 0x11b7, 0,
+#undef V7998
+#define V7998 (V + 31033)
+ 0x110b, 0x1174, 0x11b8, 0,
+#undef V7999
+#define V7999 (V + 31037)
+ 0x110b, 0x1174, 0x11b9, 0,
+#undef V8000
+#define V8000 (V + 31041)
+ 0x110b, 0x1174, 0x11ba, 0,
+#undef V8001
+#define V8001 (V + 31045)
+ 0x110b, 0x1174, 0x11bb, 0,
+#undef V8002
+#define V8002 (V + 31049)
+ 0x110b, 0x1174, 0x11bc, 0,
+#undef V8003
+#define V8003 (V + 31053)
+ 0x110b, 0x1174, 0x11bd, 0,
+#undef V8004
+#define V8004 (V + 31057)
+ 0x110b, 0x1174, 0x11be, 0,
+#undef V8005
+#define V8005 (V + 31061)
+ 0x110b, 0x1174, 0x11bf, 0,
+#undef V8006
+#define V8006 (V + 31065)
+ 0x110b, 0x1174, 0x11c0, 0,
+#undef V8007
+#define V8007 (V + 31069)
+ 0x110b, 0x1174, 0x11c1, 0,
+#undef V8008
+#define V8008 (V + 31073)
+ 0x110b, 0x1174, 0x11c2, 0,
+#undef V8009
+#define V8009 (V + 31077)
+ 0x110b, 0x1175, 0,
+#undef V8010
+#define V8010 (V + 31080)
+ 0x110b, 0x1175, 0x11a8, 0,
+#undef V8011
+#define V8011 (V + 31084)
+ 0x110b, 0x1175, 0x11a9, 0,
+#undef V8012
+#define V8012 (V + 31088)
+ 0x110b, 0x1175, 0x11aa, 0,
+#undef V8013
+#define V8013 (V + 31092)
+ 0x110b, 0x1175, 0x11ab, 0,
+#undef V8014
+#define V8014 (V + 31096)
+ 0x110b, 0x1175, 0x11ac, 0,
+#undef V8015
+#define V8015 (V + 31100)
+ 0x110b, 0x1175, 0x11ad, 0,
+#undef V8016
+#define V8016 (V + 31104)
+ 0x110b, 0x1175, 0x11ae, 0,
+#undef V8017
+#define V8017 (V + 31108)
+ 0x110b, 0x1175, 0x11af, 0,
+#undef V8018
+#define V8018 (V + 31112)
+ 0x110b, 0x1175, 0x11b0, 0,
+#undef V8019
+#define V8019 (V + 31116)
+ 0x110b, 0x1175, 0x11b1, 0,
+#undef V8020
+#define V8020 (V + 31120)
+ 0x110b, 0x1175, 0x11b2, 0,
+#undef V8021
+#define V8021 (V + 31124)
+ 0x110b, 0x1175, 0x11b3, 0,
+#undef V8022
+#define V8022 (V + 31128)
+ 0x110b, 0x1175, 0x11b4, 0,
+#undef V8023
+#define V8023 (V + 31132)
+ 0x110b, 0x1175, 0x11b5, 0,
+#undef V8024
+#define V8024 (V + 31136)
+ 0x110b, 0x1175, 0x11b6, 0,
+#undef V8025
+#define V8025 (V + 31140)
+ 0x110b, 0x1175, 0x11b7, 0,
+#undef V8026
+#define V8026 (V + 31144)
+ 0x110b, 0x1175, 0x11b8, 0,
+#undef V8027
+#define V8027 (V + 31148)
+ 0x110b, 0x1175, 0x11b9, 0,
+#undef V8028
+#define V8028 (V + 31152)
+ 0x110b, 0x1175, 0x11ba, 0,
+#undef V8029
+#define V8029 (V + 31156)
+ 0x110b, 0x1175, 0x11bb, 0,
+#undef V8030
+#define V8030 (V + 31160)
+ 0x110b, 0x1175, 0x11bc, 0,
+#undef V8031
+#define V8031 (V + 31164)
+ 0x110b, 0x1175, 0x11bd, 0,
+#undef V8032
+#define V8032 (V + 31168)
+ 0x110b, 0x1175, 0x11be, 0,
+#undef V8033
+#define V8033 (V + 31172)
+ 0x110b, 0x1175, 0x11bf, 0,
+#undef V8034
+#define V8034 (V + 31176)
+ 0x110b, 0x1175, 0x11c0, 0,
+#undef V8035
+#define V8035 (V + 31180)
+ 0x110b, 0x1175, 0x11c1, 0,
+#undef V8036
+#define V8036 (V + 31184)
+ 0x110b, 0x1175, 0x11c2, 0,
+#undef V8037
+#define V8037 (V + 31188)
+ 0x110c, 0x1161, 0,
+#undef V8038
+#define V8038 (V + 31191)
+ 0x110c, 0x1161, 0x11a8, 0,
+#undef V8039
+#define V8039 (V + 31195)
+ 0x110c, 0x1161, 0x11a9, 0,
+#undef V8040
+#define V8040 (V + 31199)
+ 0x110c, 0x1161, 0x11aa, 0,
+#undef V8041
+#define V8041 (V + 31203)
+ 0x110c, 0x1161, 0x11ab, 0,
+#undef V8042
+#define V8042 (V + 31207)
+ 0x110c, 0x1161, 0x11ac, 0,
+#undef V8043
+#define V8043 (V + 31211)
+ 0x110c, 0x1161, 0x11ad, 0,
+#undef V8044
+#define V8044 (V + 31215)
+ 0x110c, 0x1161, 0x11ae, 0,
+#undef V8045
+#define V8045 (V + 31219)
+ 0x110c, 0x1161, 0x11af, 0,
+#undef V8046
+#define V8046 (V + 31223)
+ 0x110c, 0x1161, 0x11b0, 0,
+#undef V8047
+#define V8047 (V + 31227)
+ 0x110c, 0x1161, 0x11b1, 0,
+#undef V8048
+#define V8048 (V + 31231)
+ 0x110c, 0x1161, 0x11b2, 0,
+#undef V8049
+#define V8049 (V + 31235)
+ 0x110c, 0x1161, 0x11b3, 0,
+#undef V8050
+#define V8050 (V + 31239)
+ 0x110c, 0x1161, 0x11b4, 0,
+#undef V8051
+#define V8051 (V + 31243)
+ 0x110c, 0x1161, 0x11b5, 0,
+#undef V8052
+#define V8052 (V + 31247)
+ 0x110c, 0x1161, 0x11b6, 0,
+#undef V8053
+#define V8053 (V + 31251)
+ 0x110c, 0x1161, 0x11b7, 0,
+#undef V8054
+#define V8054 (V + 31255)
+ 0x110c, 0x1161, 0x11b8, 0,
+#undef V8055
+#define V8055 (V + 31259)
+ 0x110c, 0x1161, 0x11b9, 0,
+#undef V8056
+#define V8056 (V + 31263)
+ 0x110c, 0x1161, 0x11ba, 0,
+#undef V8057
+#define V8057 (V + 31267)
+ 0x110c, 0x1161, 0x11bb, 0,
+#undef V8058
+#define V8058 (V + 31271)
+ 0x110c, 0x1161, 0x11bc, 0,
+#undef V8059
+#define V8059 (V + 31275)
+ 0x110c, 0x1161, 0x11bd, 0,
+#undef V8060
+#define V8060 (V + 31279)
+ 0x110c, 0x1161, 0x11be, 0,
+#undef V8061
+#define V8061 (V + 31283)
+ 0x110c, 0x1161, 0x11bf, 0,
+#undef V8062
+#define V8062 (V + 31287)
+ 0x110c, 0x1161, 0x11c0, 0,
+#undef V8063
+#define V8063 (V + 31291)
+ 0x110c, 0x1161, 0x11c1, 0,
+#undef V8064
+#define V8064 (V + 31295)
+ 0x110c, 0x1161, 0x11c2, 0,
+#undef V8065
+#define V8065 (V + 31299)
+ 0x110c, 0x1162, 0,
+#undef V8066
+#define V8066 (V + 31302)
+ 0x110c, 0x1162, 0x11a8, 0,
+#undef V8067
+#define V8067 (V + 31306)
+ 0x110c, 0x1162, 0x11a9, 0,
+#undef V8068
+#define V8068 (V + 31310)
+ 0x110c, 0x1162, 0x11aa, 0,
+#undef V8069
+#define V8069 (V + 31314)
+ 0x110c, 0x1162, 0x11ab, 0,
+#undef V8070
+#define V8070 (V + 31318)
+ 0x110c, 0x1162, 0x11ac, 0,
+#undef V8071
+#define V8071 (V + 31322)
+ 0x110c, 0x1162, 0x11ad, 0,
+#undef V8072
+#define V8072 (V + 31326)
+ 0x110c, 0x1162, 0x11ae, 0,
+#undef V8073
+#define V8073 (V + 31330)
+ 0x110c, 0x1162, 0x11af, 0,
+#undef V8074
+#define V8074 (V + 31334)
+ 0x110c, 0x1162, 0x11b0, 0,
+#undef V8075
+#define V8075 (V + 31338)
+ 0x110c, 0x1162, 0x11b1, 0,
+#undef V8076
+#define V8076 (V + 31342)
+ 0x110c, 0x1162, 0x11b2, 0,
+#undef V8077
+#define V8077 (V + 31346)
+ 0x110c, 0x1162, 0x11b3, 0,
+#undef V8078
+#define V8078 (V + 31350)
+ 0x110c, 0x1162, 0x11b4, 0,
+#undef V8079
+#define V8079 (V + 31354)
+ 0x110c, 0x1162, 0x11b5, 0,
+#undef V8080
+#define V8080 (V + 31358)
+ 0x110c, 0x1162, 0x11b6, 0,
+#undef V8081
+#define V8081 (V + 31362)
+ 0x110c, 0x1162, 0x11b7, 0,
+#undef V8082
+#define V8082 (V + 31366)
+ 0x110c, 0x1162, 0x11b8, 0,
+#undef V8083
+#define V8083 (V + 31370)
+ 0x110c, 0x1162, 0x11b9, 0,
+#undef V8084
+#define V8084 (V + 31374)
+ 0x110c, 0x1162, 0x11ba, 0,
+#undef V8085
+#define V8085 (V + 31378)
+ 0x110c, 0x1162, 0x11bb, 0,
+#undef V8086
+#define V8086 (V + 31382)
+ 0x110c, 0x1162, 0x11bc, 0,
+#undef V8087
+#define V8087 (V + 31386)
+ 0x110c, 0x1162, 0x11bd, 0,
+#undef V8088
+#define V8088 (V + 31390)
+ 0x110c, 0x1162, 0x11be, 0,
+#undef V8089
+#define V8089 (V + 31394)
+ 0x110c, 0x1162, 0x11bf, 0,
+#undef V8090
+#define V8090 (V + 31398)
+ 0x110c, 0x1162, 0x11c0, 0,
+#undef V8091
+#define V8091 (V + 31402)
+ 0x110c, 0x1162, 0x11c1, 0,
+#undef V8092
+#define V8092 (V + 31406)
+ 0x110c, 0x1162, 0x11c2, 0,
+#undef V8093
+#define V8093 (V + 31410)
+ 0x110c, 0x1163, 0,
+#undef V8094
+#define V8094 (V + 31413)
+ 0x110c, 0x1163, 0x11a8, 0,
+#undef V8095
+#define V8095 (V + 31417)
+ 0x110c, 0x1163, 0x11a9, 0,
+#undef V8096
+#define V8096 (V + 31421)
+ 0x110c, 0x1163, 0x11aa, 0,
+#undef V8097
+#define V8097 (V + 31425)
+ 0x110c, 0x1163, 0x11ab, 0,
+#undef V8098
+#define V8098 (V + 31429)
+ 0x110c, 0x1163, 0x11ac, 0,
+#undef V8099
+#define V8099 (V + 31433)
+ 0x110c, 0x1163, 0x11ad, 0,
+#undef V8100
+#define V8100 (V + 31437)
+ 0x110c, 0x1163, 0x11ae, 0,
+#undef V8101
+#define V8101 (V + 31441)
+ 0x110c, 0x1163, 0x11af, 0,
+#undef V8102
+#define V8102 (V + 31445)
+ 0x110c, 0x1163, 0x11b0, 0,
+#undef V8103
+#define V8103 (V + 31449)
+ 0x110c, 0x1163, 0x11b1, 0,
+#undef V8104
+#define V8104 (V + 31453)
+ 0x110c, 0x1163, 0x11b2, 0,
+#undef V8105
+#define V8105 (V + 31457)
+ 0x110c, 0x1163, 0x11b3, 0,
+#undef V8106
+#define V8106 (V + 31461)
+ 0x110c, 0x1163, 0x11b4, 0,
+#undef V8107
+#define V8107 (V + 31465)
+ 0x110c, 0x1163, 0x11b5, 0,
+#undef V8108
+#define V8108 (V + 31469)
+ 0x110c, 0x1163, 0x11b6, 0,
+#undef V8109
+#define V8109 (V + 31473)
+ 0x110c, 0x1163, 0x11b7, 0,
+#undef V8110
+#define V8110 (V + 31477)
+ 0x110c, 0x1163, 0x11b8, 0,
+#undef V8111
+#define V8111 (V + 31481)
+ 0x110c, 0x1163, 0x11b9, 0,
+#undef V8112
+#define V8112 (V + 31485)
+ 0x110c, 0x1163, 0x11ba, 0,
+#undef V8113
+#define V8113 (V + 31489)
+ 0x110c, 0x1163, 0x11bb, 0,
+#undef V8114
+#define V8114 (V + 31493)
+ 0x110c, 0x1163, 0x11bc, 0,
+#undef V8115
+#define V8115 (V + 31497)
+ 0x110c, 0x1163, 0x11bd, 0,
+#undef V8116
+#define V8116 (V + 31501)
+ 0x110c, 0x1163, 0x11be, 0,
+#undef V8117
+#define V8117 (V + 31505)
+ 0x110c, 0x1163, 0x11bf, 0,
+#undef V8118
+#define V8118 (V + 31509)
+ 0x110c, 0x1163, 0x11c0, 0,
+#undef V8119
+#define V8119 (V + 31513)
+ 0x110c, 0x1163, 0x11c1, 0,
+#undef V8120
+#define V8120 (V + 31517)
+ 0x110c, 0x1163, 0x11c2, 0,
+#undef V8121
+#define V8121 (V + 31521)
+ 0x110c, 0x1164, 0,
+#undef V8122
+#define V8122 (V + 31524)
+ 0x110c, 0x1164, 0x11a8, 0,
+#undef V8123
+#define V8123 (V + 31528)
+ 0x110c, 0x1164, 0x11a9, 0,
+#undef V8124
+#define V8124 (V + 31532)
+ 0x110c, 0x1164, 0x11aa, 0,
+#undef V8125
+#define V8125 (V + 31536)
+ 0x110c, 0x1164, 0x11ab, 0,
+#undef V8126
+#define V8126 (V + 31540)
+ 0x110c, 0x1164, 0x11ac, 0,
+#undef V8127
+#define V8127 (V + 31544)
+ 0x110c, 0x1164, 0x11ad, 0,
+#undef V8128
+#define V8128 (V + 31548)
+ 0x110c, 0x1164, 0x11ae, 0,
+#undef V8129
+#define V8129 (V + 31552)
+ 0x110c, 0x1164, 0x11af, 0,
+#undef V8130
+#define V8130 (V + 31556)
+ 0x110c, 0x1164, 0x11b0, 0,
+#undef V8131
+#define V8131 (V + 31560)
+ 0x110c, 0x1164, 0x11b1, 0,
+#undef V8132
+#define V8132 (V + 31564)
+ 0x110c, 0x1164, 0x11b2, 0,
+#undef V8133
+#define V8133 (V + 31568)
+ 0x110c, 0x1164, 0x11b3, 0,
+#undef V8134
+#define V8134 (V + 31572)
+ 0x110c, 0x1164, 0x11b4, 0,
+#undef V8135
+#define V8135 (V + 31576)
+ 0x110c, 0x1164, 0x11b5, 0,
+#undef V8136
+#define V8136 (V + 31580)
+ 0x110c, 0x1164, 0x11b6, 0,
+#undef V8137
+#define V8137 (V + 31584)
+ 0x110c, 0x1164, 0x11b7, 0,
+#undef V8138
+#define V8138 (V + 31588)
+ 0x110c, 0x1164, 0x11b8, 0,
+#undef V8139
+#define V8139 (V + 31592)
+ 0x110c, 0x1164, 0x11b9, 0,
+#undef V8140
+#define V8140 (V + 31596)
+ 0x110c, 0x1164, 0x11ba, 0,
+#undef V8141
+#define V8141 (V + 31600)
+ 0x110c, 0x1164, 0x11bb, 0,
+#undef V8142
+#define V8142 (V + 31604)
+ 0x110c, 0x1164, 0x11bc, 0,
+#undef V8143
+#define V8143 (V + 31608)
+ 0x110c, 0x1164, 0x11bd, 0,
+#undef V8144
+#define V8144 (V + 31612)
+ 0x110c, 0x1164, 0x11be, 0,
+#undef V8145
+#define V8145 (V + 31616)
+ 0x110c, 0x1164, 0x11bf, 0,
+#undef V8146
+#define V8146 (V + 31620)
+ 0x110c, 0x1164, 0x11c0, 0,
+#undef V8147
+#define V8147 (V + 31624)
+ 0x110c, 0x1164, 0x11c1, 0,
+#undef V8148
+#define V8148 (V + 31628)
+ 0x110c, 0x1164, 0x11c2, 0,
+#undef V8149
+#define V8149 (V + 31632)
+ 0x110c, 0x1165, 0,
+#undef V8150
+#define V8150 (V + 31635)
+ 0x110c, 0x1165, 0x11a8, 0,
+#undef V8151
+#define V8151 (V + 31639)
+ 0x110c, 0x1165, 0x11a9, 0,
+#undef V8152
+#define V8152 (V + 31643)
+ 0x110c, 0x1165, 0x11aa, 0,
+#undef V8153
+#define V8153 (V + 31647)
+ 0x110c, 0x1165, 0x11ab, 0,
+#undef V8154
+#define V8154 (V + 31651)
+ 0x110c, 0x1165, 0x11ac, 0,
+#undef V8155
+#define V8155 (V + 31655)
+ 0x110c, 0x1165, 0x11ad, 0,
+#undef V8156
+#define V8156 (V + 31659)
+ 0x110c, 0x1165, 0x11ae, 0,
+#undef V8157
+#define V8157 (V + 31663)
+ 0x110c, 0x1165, 0x11af, 0,
+#undef V8158
+#define V8158 (V + 31667)
+ 0x110c, 0x1165, 0x11b0, 0,
+#undef V8159
+#define V8159 (V + 31671)
+ 0x110c, 0x1165, 0x11b1, 0,
+#undef V8160
+#define V8160 (V + 31675)
+ 0x110c, 0x1165, 0x11b2, 0,
+#undef V8161
+#define V8161 (V + 31679)
+ 0x110c, 0x1165, 0x11b3, 0,
+#undef V8162
+#define V8162 (V + 31683)
+ 0x110c, 0x1165, 0x11b4, 0,
+#undef V8163
+#define V8163 (V + 31687)
+ 0x110c, 0x1165, 0x11b5, 0,
+#undef V8164
+#define V8164 (V + 31691)
+ 0x110c, 0x1165, 0x11b6, 0,
+#undef V8165
+#define V8165 (V + 31695)
+ 0x110c, 0x1165, 0x11b7, 0,
+#undef V8166
+#define V8166 (V + 31699)
+ 0x110c, 0x1165, 0x11b8, 0,
+#undef V8167
+#define V8167 (V + 31703)
+ 0x110c, 0x1165, 0x11b9, 0,
+#undef V8168
+#define V8168 (V + 31707)
+ 0x110c, 0x1165, 0x11ba, 0,
+#undef V8169
+#define V8169 (V + 31711)
+ 0x110c, 0x1165, 0x11bb, 0,
+#undef V8170
+#define V8170 (V + 31715)
+ 0x110c, 0x1165, 0x11bc, 0,
+#undef V8171
+#define V8171 (V + 31719)
+ 0x110c, 0x1165, 0x11bd, 0,
+#undef V8172
+#define V8172 (V + 31723)
+ 0x110c, 0x1165, 0x11be, 0,
+#undef V8173
+#define V8173 (V + 31727)
+ 0x110c, 0x1165, 0x11bf, 0,
+#undef V8174
+#define V8174 (V + 31731)
+ 0x110c, 0x1165, 0x11c0, 0,
+#undef V8175
+#define V8175 (V + 31735)
+ 0x110c, 0x1165, 0x11c1, 0,
+#undef V8176
+#define V8176 (V + 31739)
+ 0x110c, 0x1165, 0x11c2, 0,
+#undef V8177
+#define V8177 (V + 31743)
+ 0x110c, 0x1166, 0,
+#undef V8178
+#define V8178 (V + 31746)
+ 0x110c, 0x1166, 0x11a8, 0,
+#undef V8179
+#define V8179 (V + 31750)
+ 0x110c, 0x1166, 0x11a9, 0,
+#undef V8180
+#define V8180 (V + 31754)
+ 0x110c, 0x1166, 0x11aa, 0,
+#undef V8181
+#define V8181 (V + 31758)
+ 0x110c, 0x1166, 0x11ab, 0,
+#undef V8182
+#define V8182 (V + 31762)
+ 0x110c, 0x1166, 0x11ac, 0,
+#undef V8183
+#define V8183 (V + 31766)
+ 0x110c, 0x1166, 0x11ad, 0,
+#undef V8184
+#define V8184 (V + 31770)
+ 0x110c, 0x1166, 0x11ae, 0,
+#undef V8185
+#define V8185 (V + 31774)
+ 0x110c, 0x1166, 0x11af, 0,
+#undef V8186
+#define V8186 (V + 31778)
+ 0x110c, 0x1166, 0x11b0, 0,
+#undef V8187
+#define V8187 (V + 31782)
+ 0x110c, 0x1166, 0x11b1, 0,
+#undef V8188
+#define V8188 (V + 31786)
+ 0x110c, 0x1166, 0x11b2, 0,
+#undef V8189
+#define V8189 (V + 31790)
+ 0x110c, 0x1166, 0x11b3, 0,
+#undef V8190
+#define V8190 (V + 31794)
+ 0x110c, 0x1166, 0x11b4, 0,
+#undef V8191
+#define V8191 (V + 31798)
+ 0x110c, 0x1166, 0x11b5, 0,
+#undef V8192
+#define V8192 (V + 31802)
+ 0x110c, 0x1166, 0x11b6, 0,
+#undef V8193
+#define V8193 (V + 31806)
+ 0x110c, 0x1166, 0x11b7, 0,
+#undef V8194
+#define V8194 (V + 31810)
+ 0x110c, 0x1166, 0x11b8, 0,
+#undef V8195
+#define V8195 (V + 31814)
+ 0x110c, 0x1166, 0x11b9, 0,
+#undef V8196
+#define V8196 (V + 31818)
+ 0x110c, 0x1166, 0x11ba, 0,
+#undef V8197
+#define V8197 (V + 31822)
+ 0x110c, 0x1166, 0x11bb, 0,
+#undef V8198
+#define V8198 (V + 31826)
+ 0x110c, 0x1166, 0x11bc, 0,
+#undef V8199
+#define V8199 (V + 31830)
+ 0x110c, 0x1166, 0x11bd, 0,
+#undef V8200
+#define V8200 (V + 31834)
+ 0x110c, 0x1166, 0x11be, 0,
+#undef V8201
+#define V8201 (V + 31838)
+ 0x110c, 0x1166, 0x11bf, 0,
+#undef V8202
+#define V8202 (V + 31842)
+ 0x110c, 0x1166, 0x11c0, 0,
+#undef V8203
+#define V8203 (V + 31846)
+ 0x110c, 0x1166, 0x11c1, 0,
+#undef V8204
+#define V8204 (V + 31850)
+ 0x110c, 0x1166, 0x11c2, 0,
+#undef V8205
+#define V8205 (V + 31854)
+ 0x110c, 0x1167, 0,
+#undef V8206
+#define V8206 (V + 31857)
+ 0x110c, 0x1167, 0x11a8, 0,
+#undef V8207
+#define V8207 (V + 31861)
+ 0x110c, 0x1167, 0x11a9, 0,
+#undef V8208
+#define V8208 (V + 31865)
+ 0x110c, 0x1167, 0x11aa, 0,
+#undef V8209
+#define V8209 (V + 31869)
+ 0x110c, 0x1167, 0x11ab, 0,
+#undef V8210
+#define V8210 (V + 31873)
+ 0x110c, 0x1167, 0x11ac, 0,
+#undef V8211
+#define V8211 (V + 31877)
+ 0x110c, 0x1167, 0x11ad, 0,
+#undef V8212
+#define V8212 (V + 31881)
+ 0x110c, 0x1167, 0x11ae, 0,
+#undef V8213
+#define V8213 (V + 31885)
+ 0x110c, 0x1167, 0x11af, 0,
+#undef V8214
+#define V8214 (V + 31889)
+ 0x110c, 0x1167, 0x11b0, 0,
+#undef V8215
+#define V8215 (V + 31893)
+ 0x110c, 0x1167, 0x11b1, 0,
+#undef V8216
+#define V8216 (V + 31897)
+ 0x110c, 0x1167, 0x11b2, 0,
+#undef V8217
+#define V8217 (V + 31901)
+ 0x110c, 0x1167, 0x11b3, 0,
+#undef V8218
+#define V8218 (V + 31905)
+ 0x110c, 0x1167, 0x11b4, 0,
+#undef V8219
+#define V8219 (V + 31909)
+ 0x110c, 0x1167, 0x11b5, 0,
+#undef V8220
+#define V8220 (V + 31913)
+ 0x110c, 0x1167, 0x11b6, 0,
+#undef V8221
+#define V8221 (V + 31917)
+ 0x110c, 0x1167, 0x11b7, 0,
+#undef V8222
+#define V8222 (V + 31921)
+ 0x110c, 0x1167, 0x11b8, 0,
+#undef V8223
+#define V8223 (V + 31925)
+ 0x110c, 0x1167, 0x11b9, 0,
+#undef V8224
+#define V8224 (V + 31929)
+ 0x110c, 0x1167, 0x11ba, 0,
+#undef V8225
+#define V8225 (V + 31933)
+ 0x110c, 0x1167, 0x11bb, 0,
+#undef V8226
+#define V8226 (V + 31937)
+ 0x110c, 0x1167, 0x11bc, 0,
+#undef V8227
+#define V8227 (V + 31941)
+ 0x110c, 0x1167, 0x11bd, 0,
+#undef V8228
+#define V8228 (V + 31945)
+ 0x110c, 0x1167, 0x11be, 0,
+#undef V8229
+#define V8229 (V + 31949)
+ 0x110c, 0x1167, 0x11bf, 0,
+#undef V8230
+#define V8230 (V + 31953)
+ 0x110c, 0x1167, 0x11c0, 0,
+#undef V8231
+#define V8231 (V + 31957)
+ 0x110c, 0x1167, 0x11c1, 0,
+#undef V8232
+#define V8232 (V + 31961)
+ 0x110c, 0x1167, 0x11c2, 0,
+#undef V8233
+#define V8233 (V + 31965)
+ 0x110c, 0x1168, 0,
+#undef V8234
+#define V8234 (V + 31968)
+ 0x110c, 0x1168, 0x11a8, 0,
+#undef V8235
+#define V8235 (V + 31972)
+ 0x110c, 0x1168, 0x11a9, 0,
+#undef V8236
+#define V8236 (V + 31976)
+ 0x110c, 0x1168, 0x11aa, 0,
+#undef V8237
+#define V8237 (V + 31980)
+ 0x110c, 0x1168, 0x11ab, 0,
+#undef V8238
+#define V8238 (V + 31984)
+ 0x110c, 0x1168, 0x11ac, 0,
+#undef V8239
+#define V8239 (V + 31988)
+ 0x110c, 0x1168, 0x11ad, 0,
+#undef V8240
+#define V8240 (V + 31992)
+ 0x110c, 0x1168, 0x11ae, 0,
+#undef V8241
+#define V8241 (V + 31996)
+ 0x110c, 0x1168, 0x11af, 0,
+#undef V8242
+#define V8242 (V + 32000)
+ 0x110c, 0x1168, 0x11b0, 0,
+#undef V8243
+#define V8243 (V + 32004)
+ 0x110c, 0x1168, 0x11b1, 0,
+#undef V8244
+#define V8244 (V + 32008)
+ 0x110c, 0x1168, 0x11b2, 0,
+#undef V8245
+#define V8245 (V + 32012)
+ 0x110c, 0x1168, 0x11b3, 0,
+#undef V8246
+#define V8246 (V + 32016)
+ 0x110c, 0x1168, 0x11b4, 0,
+#undef V8247
+#define V8247 (V + 32020)
+ 0x110c, 0x1168, 0x11b5, 0,
+#undef V8248
+#define V8248 (V + 32024)
+ 0x110c, 0x1168, 0x11b6, 0,
+#undef V8249
+#define V8249 (V + 32028)
+ 0x110c, 0x1168, 0x11b7, 0,
+#undef V8250
+#define V8250 (V + 32032)
+ 0x110c, 0x1168, 0x11b8, 0,
+#undef V8251
+#define V8251 (V + 32036)
+ 0x110c, 0x1168, 0x11b9, 0,
+#undef V8252
+#define V8252 (V + 32040)
+ 0x110c, 0x1168, 0x11ba, 0,
+#undef V8253
+#define V8253 (V + 32044)
+ 0x110c, 0x1168, 0x11bb, 0,
+#undef V8254
+#define V8254 (V + 32048)
+ 0x110c, 0x1168, 0x11bc, 0,
+#undef V8255
+#define V8255 (V + 32052)
+ 0x110c, 0x1168, 0x11bd, 0,
+#undef V8256
+#define V8256 (V + 32056)
+ 0x110c, 0x1168, 0x11be, 0,
+#undef V8257
+#define V8257 (V + 32060)
+ 0x110c, 0x1168, 0x11bf, 0,
+#undef V8258
+#define V8258 (V + 32064)
+ 0x110c, 0x1168, 0x11c0, 0,
+#undef V8259
+#define V8259 (V + 32068)
+ 0x110c, 0x1168, 0x11c1, 0,
+#undef V8260
+#define V8260 (V + 32072)
+ 0x110c, 0x1168, 0x11c2, 0,
+#undef V8261
+#define V8261 (V + 32076)
+ 0x110c, 0x1169, 0,
+#undef V8262
+#define V8262 (V + 32079)
+ 0x110c, 0x1169, 0x11a8, 0,
+#undef V8263
+#define V8263 (V + 32083)
+ 0x110c, 0x1169, 0x11a9, 0,
+#undef V8264
+#define V8264 (V + 32087)
+ 0x110c, 0x1169, 0x11aa, 0,
+#undef V8265
+#define V8265 (V + 32091)
+ 0x110c, 0x1169, 0x11ab, 0,
+#undef V8266
+#define V8266 (V + 32095)
+ 0x110c, 0x1169, 0x11ac, 0,
+#undef V8267
+#define V8267 (V + 32099)
+ 0x110c, 0x1169, 0x11ad, 0,
+#undef V8268
+#define V8268 (V + 32103)
+ 0x110c, 0x1169, 0x11ae, 0,
+#undef V8269
+#define V8269 (V + 32107)
+ 0x110c, 0x1169, 0x11af, 0,
+#undef V8270
+#define V8270 (V + 32111)
+ 0x110c, 0x1169, 0x11b0, 0,
+#undef V8271
+#define V8271 (V + 32115)
+ 0x110c, 0x1169, 0x11b1, 0,
+#undef V8272
+#define V8272 (V + 32119)
+ 0x110c, 0x1169, 0x11b2, 0,
+#undef V8273
+#define V8273 (V + 32123)
+ 0x110c, 0x1169, 0x11b3, 0,
+#undef V8274
+#define V8274 (V + 32127)
+ 0x110c, 0x1169, 0x11b4, 0,
+#undef V8275
+#define V8275 (V + 32131)
+ 0x110c, 0x1169, 0x11b5, 0,
+#undef V8276
+#define V8276 (V + 32135)
+ 0x110c, 0x1169, 0x11b6, 0,
+#undef V8277
+#define V8277 (V + 32139)
+ 0x110c, 0x1169, 0x11b7, 0,
+#undef V8278
+#define V8278 (V + 32143)
+ 0x110c, 0x1169, 0x11b8, 0,
+#undef V8279
+#define V8279 (V + 32147)
+ 0x110c, 0x1169, 0x11b9, 0,
+#undef V8280
+#define V8280 (V + 32151)
+ 0x110c, 0x1169, 0x11ba, 0,
+#undef V8281
+#define V8281 (V + 32155)
+ 0x110c, 0x1169, 0x11bb, 0,
+#undef V8282
+#define V8282 (V + 32159)
+ 0x110c, 0x1169, 0x11bc, 0,
+#undef V8283
+#define V8283 (V + 32163)
+ 0x110c, 0x1169, 0x11bd, 0,
+#undef V8284
+#define V8284 (V + 32167)
+ 0x110c, 0x1169, 0x11be, 0,
+#undef V8285
+#define V8285 (V + 32171)
+ 0x110c, 0x1169, 0x11bf, 0,
+#undef V8286
+#define V8286 (V + 32175)
+ 0x110c, 0x1169, 0x11c0, 0,
+#undef V8287
+#define V8287 (V + 32179)
+ 0x110c, 0x1169, 0x11c1, 0,
+#undef V8288
+#define V8288 (V + 32183)
+ 0x110c, 0x1169, 0x11c2, 0,
+#undef V8289
+#define V8289 (V + 32187)
+ 0x110c, 0x116a, 0,
+#undef V8290
+#define V8290 (V + 32190)
+ 0x110c, 0x116a, 0x11a8, 0,
+#undef V8291
+#define V8291 (V + 32194)
+ 0x110c, 0x116a, 0x11a9, 0,
+#undef V8292
+#define V8292 (V + 32198)
+ 0x110c, 0x116a, 0x11aa, 0,
+#undef V8293
+#define V8293 (V + 32202)
+ 0x110c, 0x116a, 0x11ab, 0,
+#undef V8294
+#define V8294 (V + 32206)
+ 0x110c, 0x116a, 0x11ac, 0,
+#undef V8295
+#define V8295 (V + 32210)
+ 0x110c, 0x116a, 0x11ad, 0,
+#undef V8296
+#define V8296 (V + 32214)
+ 0x110c, 0x116a, 0x11ae, 0,
+#undef V8297
+#define V8297 (V + 32218)
+ 0x110c, 0x116a, 0x11af, 0,
+#undef V8298
+#define V8298 (V + 32222)
+ 0x110c, 0x116a, 0x11b0, 0,
+#undef V8299
+#define V8299 (V + 32226)
+ 0x110c, 0x116a, 0x11b1, 0,
+#undef V8300
+#define V8300 (V + 32230)
+ 0x110c, 0x116a, 0x11b2, 0,
+#undef V8301
+#define V8301 (V + 32234)
+ 0x110c, 0x116a, 0x11b3, 0,
+#undef V8302
+#define V8302 (V + 32238)
+ 0x110c, 0x116a, 0x11b4, 0,
+#undef V8303
+#define V8303 (V + 32242)
+ 0x110c, 0x116a, 0x11b5, 0,
+#undef V8304
+#define V8304 (V + 32246)
+ 0x110c, 0x116a, 0x11b6, 0,
+#undef V8305
+#define V8305 (V + 32250)
+ 0x110c, 0x116a, 0x11b7, 0,
+#undef V8306
+#define V8306 (V + 32254)
+ 0x110c, 0x116a, 0x11b8, 0,
+#undef V8307
+#define V8307 (V + 32258)
+ 0x110c, 0x116a, 0x11b9, 0,
+#undef V8308
+#define V8308 (V + 32262)
+ 0x110c, 0x116a, 0x11ba, 0,
+#undef V8309
+#define V8309 (V + 32266)
+ 0x110c, 0x116a, 0x11bb, 0,
+#undef V8310
+#define V8310 (V + 32270)
+ 0x110c, 0x116a, 0x11bc, 0,
+#undef V8311
+#define V8311 (V + 32274)
+ 0x110c, 0x116a, 0x11bd, 0,
+#undef V8312
+#define V8312 (V + 32278)
+ 0x110c, 0x116a, 0x11be, 0,
+#undef V8313
+#define V8313 (V + 32282)
+ 0x110c, 0x116a, 0x11bf, 0,
+#undef V8314
+#define V8314 (V + 32286)
+ 0x110c, 0x116a, 0x11c0, 0,
+#undef V8315
+#define V8315 (V + 32290)
+ 0x110c, 0x116a, 0x11c1, 0,
+#undef V8316
+#define V8316 (V + 32294)
+ 0x110c, 0x116a, 0x11c2, 0,
+#undef V8317
+#define V8317 (V + 32298)
+ 0x110c, 0x116b, 0,
+#undef V8318
+#define V8318 (V + 32301)
+ 0x110c, 0x116b, 0x11a8, 0,
+#undef V8319
+#define V8319 (V + 32305)
+ 0x110c, 0x116b, 0x11a9, 0,
+#undef V8320
+#define V8320 (V + 32309)
+ 0x110c, 0x116b, 0x11aa, 0,
+#undef V8321
+#define V8321 (V + 32313)
+ 0x110c, 0x116b, 0x11ab, 0,
+#undef V8322
+#define V8322 (V + 32317)
+ 0x110c, 0x116b, 0x11ac, 0,
+#undef V8323
+#define V8323 (V + 32321)
+ 0x110c, 0x116b, 0x11ad, 0,
+#undef V8324
+#define V8324 (V + 32325)
+ 0x110c, 0x116b, 0x11ae, 0,
+#undef V8325
+#define V8325 (V + 32329)
+ 0x110c, 0x116b, 0x11af, 0,
+#undef V8326
+#define V8326 (V + 32333)
+ 0x110c, 0x116b, 0x11b0, 0,
+#undef V8327
+#define V8327 (V + 32337)
+ 0x110c, 0x116b, 0x11b1, 0,
+#undef V8328
+#define V8328 (V + 32341)
+ 0x110c, 0x116b, 0x11b2, 0,
+#undef V8329
+#define V8329 (V + 32345)
+ 0x110c, 0x116b, 0x11b3, 0,
+#undef V8330
+#define V8330 (V + 32349)
+ 0x110c, 0x116b, 0x11b4, 0,
+#undef V8331
+#define V8331 (V + 32353)
+ 0x110c, 0x116b, 0x11b5, 0,
+#undef V8332
+#define V8332 (V + 32357)
+ 0x110c, 0x116b, 0x11b6, 0,
+#undef V8333
+#define V8333 (V + 32361)
+ 0x110c, 0x116b, 0x11b7, 0,
+#undef V8334
+#define V8334 (V + 32365)
+ 0x110c, 0x116b, 0x11b8, 0,
+#undef V8335
+#define V8335 (V + 32369)
+ 0x110c, 0x116b, 0x11b9, 0,
+#undef V8336
+#define V8336 (V + 32373)
+ 0x110c, 0x116b, 0x11ba, 0,
+#undef V8337
+#define V8337 (V + 32377)
+ 0x110c, 0x116b, 0x11bb, 0,
+#undef V8338
+#define V8338 (V + 32381)
+ 0x110c, 0x116b, 0x11bc, 0,
+#undef V8339
+#define V8339 (V + 32385)
+ 0x110c, 0x116b, 0x11bd, 0,
+#undef V8340
+#define V8340 (V + 32389)
+ 0x110c, 0x116b, 0x11be, 0,
+#undef V8341
+#define V8341 (V + 32393)
+ 0x110c, 0x116b, 0x11bf, 0,
+#undef V8342
+#define V8342 (V + 32397)
+ 0x110c, 0x116b, 0x11c0, 0,
+#undef V8343
+#define V8343 (V + 32401)
+ 0x110c, 0x116b, 0x11c1, 0,
+#undef V8344
+#define V8344 (V + 32405)
+ 0x110c, 0x116b, 0x11c2, 0,
+#undef V8345
+#define V8345 (V + 32409)
+ 0x110c, 0x116c, 0,
+#undef V8346
+#define V8346 (V + 32412)
+ 0x110c, 0x116c, 0x11a8, 0,
+#undef V8347
+#define V8347 (V + 32416)
+ 0x110c, 0x116c, 0x11a9, 0,
+#undef V8348
+#define V8348 (V + 32420)
+ 0x110c, 0x116c, 0x11aa, 0,
+#undef V8349
+#define V8349 (V + 32424)
+ 0x110c, 0x116c, 0x11ab, 0,
+#undef V8350
+#define V8350 (V + 32428)
+ 0x110c, 0x116c, 0x11ac, 0,
+#undef V8351
+#define V8351 (V + 32432)
+ 0x110c, 0x116c, 0x11ad, 0,
+#undef V8352
+#define V8352 (V + 32436)
+ 0x110c, 0x116c, 0x11ae, 0,
+#undef V8353
+#define V8353 (V + 32440)
+ 0x110c, 0x116c, 0x11af, 0,
+#undef V8354
+#define V8354 (V + 32444)
+ 0x110c, 0x116c, 0x11b0, 0,
+#undef V8355
+#define V8355 (V + 32448)
+ 0x110c, 0x116c, 0x11b1, 0,
+#undef V8356
+#define V8356 (V + 32452)
+ 0x110c, 0x116c, 0x11b2, 0,
+#undef V8357
+#define V8357 (V + 32456)
+ 0x110c, 0x116c, 0x11b3, 0,
+#undef V8358
+#define V8358 (V + 32460)
+ 0x110c, 0x116c, 0x11b4, 0,
+#undef V8359
+#define V8359 (V + 32464)
+ 0x110c, 0x116c, 0x11b5, 0,
+#undef V8360
+#define V8360 (V + 32468)
+ 0x110c, 0x116c, 0x11b6, 0,
+#undef V8361
+#define V8361 (V + 32472)
+ 0x110c, 0x116c, 0x11b7, 0,
+#undef V8362
+#define V8362 (V + 32476)
+ 0x110c, 0x116c, 0x11b8, 0,
+#undef V8363
+#define V8363 (V + 32480)
+ 0x110c, 0x116c, 0x11b9, 0,
+#undef V8364
+#define V8364 (V + 32484)
+ 0x110c, 0x116c, 0x11ba, 0,
+#undef V8365
+#define V8365 (V + 32488)
+ 0x110c, 0x116c, 0x11bb, 0,
+#undef V8366
+#define V8366 (V + 32492)
+ 0x110c, 0x116c, 0x11bc, 0,
+#undef V8367
+#define V8367 (V + 32496)
+ 0x110c, 0x116c, 0x11bd, 0,
+#undef V8368
+#define V8368 (V + 32500)
+ 0x110c, 0x116c, 0x11be, 0,
+#undef V8369
+#define V8369 (V + 32504)
+ 0x110c, 0x116c, 0x11bf, 0,
+#undef V8370
+#define V8370 (V + 32508)
+ 0x110c, 0x116c, 0x11c0, 0,
+#undef V8371
+#define V8371 (V + 32512)
+ 0x110c, 0x116c, 0x11c1, 0,
+#undef V8372
+#define V8372 (V + 32516)
+ 0x110c, 0x116c, 0x11c2, 0,
+#undef V8373
+#define V8373 (V + 32520)
+ 0x110c, 0x116d, 0,
+#undef V8374
+#define V8374 (V + 32523)
+ 0x110c, 0x116d, 0x11a8, 0,
+#undef V8375
+#define V8375 (V + 32527)
+ 0x110c, 0x116d, 0x11a9, 0,
+#undef V8376
+#define V8376 (V + 32531)
+ 0x110c, 0x116d, 0x11aa, 0,
+#undef V8377
+#define V8377 (V + 32535)
+ 0x110c, 0x116d, 0x11ab, 0,
+#undef V8378
+#define V8378 (V + 32539)
+ 0x110c, 0x116d, 0x11ac, 0,
+#undef V8379
+#define V8379 (V + 32543)
+ 0x110c, 0x116d, 0x11ad, 0,
+#undef V8380
+#define V8380 (V + 32547)
+ 0x110c, 0x116d, 0x11ae, 0,
+#undef V8381
+#define V8381 (V + 32551)
+ 0x110c, 0x116d, 0x11af, 0,
+#undef V8382
+#define V8382 (V + 32555)
+ 0x110c, 0x116d, 0x11b0, 0,
+#undef V8383
+#define V8383 (V + 32559)
+ 0x110c, 0x116d, 0x11b1, 0,
+#undef V8384
+#define V8384 (V + 32563)
+ 0x110c, 0x116d, 0x11b2, 0,
+#undef V8385
+#define V8385 (V + 32567)
+ 0x110c, 0x116d, 0x11b3, 0,
+#undef V8386
+#define V8386 (V + 32571)
+ 0x110c, 0x116d, 0x11b4, 0,
+#undef V8387
+#define V8387 (V + 32575)
+ 0x110c, 0x116d, 0x11b5, 0,
+#undef V8388
+#define V8388 (V + 32579)
+ 0x110c, 0x116d, 0x11b6, 0,
+#undef V8389
+#define V8389 (V + 32583)
+ 0x110c, 0x116d, 0x11b7, 0,
+#undef V8390
+#define V8390 (V + 32587)
+ 0x110c, 0x116d, 0x11b8, 0,
+#undef V8391
+#define V8391 (V + 32591)
+ 0x110c, 0x116d, 0x11b9, 0,
+#undef V8392
+#define V8392 (V + 32595)
+ 0x110c, 0x116d, 0x11ba, 0,
+#undef V8393
+#define V8393 (V + 32599)
+ 0x110c, 0x116d, 0x11bb, 0,
+#undef V8394
+#define V8394 (V + 32603)
+ 0x110c, 0x116d, 0x11bc, 0,
+#undef V8395
+#define V8395 (V + 32607)
+ 0x110c, 0x116d, 0x11bd, 0,
+#undef V8396
+#define V8396 (V + 32611)
+ 0x110c, 0x116d, 0x11be, 0,
+#undef V8397
+#define V8397 (V + 32615)
+ 0x110c, 0x116d, 0x11bf, 0,
+#undef V8398
+#define V8398 (V + 32619)
+ 0x110c, 0x116d, 0x11c0, 0,
+#undef V8399
+#define V8399 (V + 32623)
+ 0x110c, 0x116d, 0x11c1, 0,
+#undef V8400
+#define V8400 (V + 32627)
+ 0x110c, 0x116d, 0x11c2, 0,
+#undef V8401
+#define V8401 (V + 32631)
+ 0x110c, 0x116e, 0,
+#undef V8402
+#define V8402 (V + 32634)
+ 0x110c, 0x116e, 0x11a8, 0,
+#undef V8403
+#define V8403 (V + 32638)
+ 0x110c, 0x116e, 0x11a9, 0,
+#undef V8404
+#define V8404 (V + 32642)
+ 0x110c, 0x116e, 0x11aa, 0,
+#undef V8405
+#define V8405 (V + 32646)
+ 0x110c, 0x116e, 0x11ab, 0,
+#undef V8406
+#define V8406 (V + 32650)
+ 0x110c, 0x116e, 0x11ac, 0,
+#undef V8407
+#define V8407 (V + 32654)
+ 0x110c, 0x116e, 0x11ad, 0,
+#undef V8408
+#define V8408 (V + 32658)
+ 0x110c, 0x116e, 0x11ae, 0,
+#undef V8409
+#define V8409 (V + 32662)
+ 0x110c, 0x116e, 0x11af, 0,
+#undef V8410
+#define V8410 (V + 32666)
+ 0x110c, 0x116e, 0x11b0, 0,
+#undef V8411
+#define V8411 (V + 32670)
+ 0x110c, 0x116e, 0x11b1, 0,
+#undef V8412
+#define V8412 (V + 32674)
+ 0x110c, 0x116e, 0x11b2, 0,
+#undef V8413
+#define V8413 (V + 32678)
+ 0x110c, 0x116e, 0x11b3, 0,
+#undef V8414
+#define V8414 (V + 32682)
+ 0x110c, 0x116e, 0x11b4, 0,
+#undef V8415
+#define V8415 (V + 32686)
+ 0x110c, 0x116e, 0x11b5, 0,
+#undef V8416
+#define V8416 (V + 32690)
+ 0x110c, 0x116e, 0x11b6, 0,
+#undef V8417
+#define V8417 (V + 32694)
+ 0x110c, 0x116e, 0x11b7, 0,
+#undef V8418
+#define V8418 (V + 32698)
+ 0x110c, 0x116e, 0x11b8, 0,
+#undef V8419
+#define V8419 (V + 32702)
+ 0x110c, 0x116e, 0x11b9, 0,
+#undef V8420
+#define V8420 (V + 32706)
+ 0x110c, 0x116e, 0x11ba, 0,
+#undef V8421
+#define V8421 (V + 32710)
+ 0x110c, 0x116e, 0x11bb, 0,
+#undef V8422
+#define V8422 (V + 32714)
+ 0x110c, 0x116e, 0x11bc, 0,
+#undef V8423
+#define V8423 (V + 32718)
+ 0x110c, 0x116e, 0x11bd, 0,
+#undef V8424
+#define V8424 (V + 32722)
+ 0x110c, 0x116e, 0x11be, 0,
+#undef V8425
+#define V8425 (V + 32726)
+ 0x110c, 0x116e, 0x11bf, 0,
+#undef V8426
+#define V8426 (V + 32730)
+ 0x110c, 0x116e, 0x11c0, 0,
+#undef V8427
+#define V8427 (V + 32734)
+ 0x110c, 0x116e, 0x11c1, 0,
+#undef V8428
+#define V8428 (V + 32738)
+ 0x110c, 0x116e, 0x11c2, 0,
+#undef V8429
+#define V8429 (V + 32742)
+ 0x110c, 0x116f, 0,
+#undef V8430
+#define V8430 (V + 32745)
+ 0x110c, 0x116f, 0x11a8, 0,
+#undef V8431
+#define V8431 (V + 32749)
+ 0x110c, 0x116f, 0x11a9, 0,
+#undef V8432
+#define V8432 (V + 32753)
+ 0x110c, 0x116f, 0x11aa, 0,
+#undef V8433
+#define V8433 (V + 32757)
+ 0x110c, 0x116f, 0x11ab, 0,
+#undef V8434
+#define V8434 (V + 32761)
+ 0x110c, 0x116f, 0x11ac, 0,
+#undef V8435
+#define V8435 (V + 32765)
+ 0x110c, 0x116f, 0x11ad, 0,
+#undef V8436
+#define V8436 (V + 32769)
+ 0x110c, 0x116f, 0x11ae, 0,
+#undef V8437
+#define V8437 (V + 32773)
+ 0x110c, 0x116f, 0x11af, 0,
+#undef V8438
+#define V8438 (V + 32777)
+ 0x110c, 0x116f, 0x11b0, 0,
+#undef V8439
+#define V8439 (V + 32781)
+ 0x110c, 0x116f, 0x11b1, 0,
+#undef V8440
+#define V8440 (V + 32785)
+ 0x110c, 0x116f, 0x11b2, 0,
+#undef V8441
+#define V8441 (V + 32789)
+ 0x110c, 0x116f, 0x11b3, 0,
+#undef V8442
+#define V8442 (V + 32793)
+ 0x110c, 0x116f, 0x11b4, 0,
+#undef V8443
+#define V8443 (V + 32797)
+ 0x110c, 0x116f, 0x11b5, 0,
+#undef V8444
+#define V8444 (V + 32801)
+ 0x110c, 0x116f, 0x11b6, 0,
+#undef V8445
+#define V8445 (V + 32805)
+ 0x110c, 0x116f, 0x11b7, 0,
+#undef V8446
+#define V8446 (V + 32809)
+ 0x110c, 0x116f, 0x11b8, 0,
+#undef V8447
+#define V8447 (V + 32813)
+ 0x110c, 0x116f, 0x11b9, 0,
+#undef V8448
+#define V8448 (V + 32817)
+ 0x110c, 0x116f, 0x11ba, 0,
+#undef V8449
+#define V8449 (V + 32821)
+ 0x110c, 0x116f, 0x11bb, 0,
+#undef V8450
+#define V8450 (V + 32825)
+ 0x110c, 0x116f, 0x11bc, 0,
+#undef V8451
+#define V8451 (V + 32829)
+ 0x110c, 0x116f, 0x11bd, 0,
+#undef V8452
+#define V8452 (V + 32833)
+ 0x110c, 0x116f, 0x11be, 0,
+#undef V8453
+#define V8453 (V + 32837)
+ 0x110c, 0x116f, 0x11bf, 0,
+#undef V8454
+#define V8454 (V + 32841)
+ 0x110c, 0x116f, 0x11c0, 0,
+#undef V8455
+#define V8455 (V + 32845)
+ 0x110c, 0x116f, 0x11c1, 0,
+#undef V8456
+#define V8456 (V + 32849)
+ 0x110c, 0x116f, 0x11c2, 0,
+#undef V8457
+#define V8457 (V + 32853)
+ 0x110c, 0x1170, 0,
+#undef V8458
+#define V8458 (V + 32856)
+ 0x110c, 0x1170, 0x11a8, 0,
+#undef V8459
+#define V8459 (V + 32860)
+ 0x110c, 0x1170, 0x11a9, 0,
+#undef V8460
+#define V8460 (V + 32864)
+ 0x110c, 0x1170, 0x11aa, 0,
+#undef V8461
+#define V8461 (V + 32868)
+ 0x110c, 0x1170, 0x11ab, 0,
+#undef V8462
+#define V8462 (V + 32872)
+ 0x110c, 0x1170, 0x11ac, 0,
+#undef V8463
+#define V8463 (V + 32876)
+ 0x110c, 0x1170, 0x11ad, 0,
+#undef V8464
+#define V8464 (V + 32880)
+ 0x110c, 0x1170, 0x11ae, 0,
+#undef V8465
+#define V8465 (V + 32884)
+ 0x110c, 0x1170, 0x11af, 0,
+#undef V8466
+#define V8466 (V + 32888)
+ 0x110c, 0x1170, 0x11b0, 0,
+#undef V8467
+#define V8467 (V + 32892)
+ 0x110c, 0x1170, 0x11b1, 0,
+#undef V8468
+#define V8468 (V + 32896)
+ 0x110c, 0x1170, 0x11b2, 0,
+#undef V8469
+#define V8469 (V + 32900)
+ 0x110c, 0x1170, 0x11b3, 0,
+#undef V8470
+#define V8470 (V + 32904)
+ 0x110c, 0x1170, 0x11b4, 0,
+#undef V8471
+#define V8471 (V + 32908)
+ 0x110c, 0x1170, 0x11b5, 0,
+#undef V8472
+#define V8472 (V + 32912)
+ 0x110c, 0x1170, 0x11b6, 0,
+#undef V8473
+#define V8473 (V + 32916)
+ 0x110c, 0x1170, 0x11b7, 0,
+#undef V8474
+#define V8474 (V + 32920)
+ 0x110c, 0x1170, 0x11b8, 0,
+#undef V8475
+#define V8475 (V + 32924)
+ 0x110c, 0x1170, 0x11b9, 0,
+#undef V8476
+#define V8476 (V + 32928)
+ 0x110c, 0x1170, 0x11ba, 0,
+#undef V8477
+#define V8477 (V + 32932)
+ 0x110c, 0x1170, 0x11bb, 0,
+#undef V8478
+#define V8478 (V + 32936)
+ 0x110c, 0x1170, 0x11bc, 0,
+#undef V8479
+#define V8479 (V + 32940)
+ 0x110c, 0x1170, 0x11bd, 0,
+#undef V8480
+#define V8480 (V + 32944)
+ 0x110c, 0x1170, 0x11be, 0,
+#undef V8481
+#define V8481 (V + 32948)
+ 0x110c, 0x1170, 0x11bf, 0,
+#undef V8482
+#define V8482 (V + 32952)
+ 0x110c, 0x1170, 0x11c0, 0,
+#undef V8483
+#define V8483 (V + 32956)
+ 0x110c, 0x1170, 0x11c1, 0,
+#undef V8484
+#define V8484 (V + 32960)
+ 0x110c, 0x1170, 0x11c2, 0,
+#undef V8485
+#define V8485 (V + 32964)
+ 0x110c, 0x1171, 0,
+#undef V8486
+#define V8486 (V + 32967)
+ 0x110c, 0x1171, 0x11a8, 0,
+#undef V8487
+#define V8487 (V + 32971)
+ 0x110c, 0x1171, 0x11a9, 0,
+#undef V8488
+#define V8488 (V + 32975)
+ 0x110c, 0x1171, 0x11aa, 0,
+#undef V8489
+#define V8489 (V + 32979)
+ 0x110c, 0x1171, 0x11ab, 0,
+#undef V8490
+#define V8490 (V + 32983)
+ 0x110c, 0x1171, 0x11ac, 0,
+#undef V8491
+#define V8491 (V + 32987)
+ 0x110c, 0x1171, 0x11ad, 0,
+#undef V8492
+#define V8492 (V + 32991)
+ 0x110c, 0x1171, 0x11ae, 0,
+#undef V8493
+#define V8493 (V + 32995)
+ 0x110c, 0x1171, 0x11af, 0,
+#undef V8494
+#define V8494 (V + 32999)
+ 0x110c, 0x1171, 0x11b0, 0,
+#undef V8495
+#define V8495 (V + 33003)
+ 0x110c, 0x1171, 0x11b1, 0,
+#undef V8496
+#define V8496 (V + 33007)
+ 0x110c, 0x1171, 0x11b2, 0,
+#undef V8497
+#define V8497 (V + 33011)
+ 0x110c, 0x1171, 0x11b3, 0,
+#undef V8498
+#define V8498 (V + 33015)
+ 0x110c, 0x1171, 0x11b4, 0,
+#undef V8499
+#define V8499 (V + 33019)
+ 0x110c, 0x1171, 0x11b5, 0,
+#undef V8500
+#define V8500 (V + 33023)
+ 0x110c, 0x1171, 0x11b6, 0,
+#undef V8501
+#define V8501 (V + 33027)
+ 0x110c, 0x1171, 0x11b7, 0,
+#undef V8502
+#define V8502 (V + 33031)
+ 0x110c, 0x1171, 0x11b8, 0,
+#undef V8503
+#define V8503 (V + 33035)
+ 0x110c, 0x1171, 0x11b9, 0,
+#undef V8504
+#define V8504 (V + 33039)
+ 0x110c, 0x1171, 0x11ba, 0,
+#undef V8505
+#define V8505 (V + 33043)
+ 0x110c, 0x1171, 0x11bb, 0,
+#undef V8506
+#define V8506 (V + 33047)
+ 0x110c, 0x1171, 0x11bc, 0,
+#undef V8507
+#define V8507 (V + 33051)
+ 0x110c, 0x1171, 0x11bd, 0,
+#undef V8508
+#define V8508 (V + 33055)
+ 0x110c, 0x1171, 0x11be, 0,
+#undef V8509
+#define V8509 (V + 33059)
+ 0x110c, 0x1171, 0x11bf, 0,
+#undef V8510
+#define V8510 (V + 33063)
+ 0x110c, 0x1171, 0x11c0, 0,
+#undef V8511
+#define V8511 (V + 33067)
+ 0x110c, 0x1171, 0x11c1, 0,
+#undef V8512
+#define V8512 (V + 33071)
+ 0x110c, 0x1171, 0x11c2, 0,
+#undef V8513
+#define V8513 (V + 33075)
+ 0x110c, 0x1172, 0,
+#undef V8514
+#define V8514 (V + 33078)
+ 0x110c, 0x1172, 0x11a8, 0,
+#undef V8515
+#define V8515 (V + 33082)
+ 0x110c, 0x1172, 0x11a9, 0,
+#undef V8516
+#define V8516 (V + 33086)
+ 0x110c, 0x1172, 0x11aa, 0,
+#undef V8517
+#define V8517 (V + 33090)
+ 0x110c, 0x1172, 0x11ab, 0,
+#undef V8518
+#define V8518 (V + 33094)
+ 0x110c, 0x1172, 0x11ac, 0,
+#undef V8519
+#define V8519 (V + 33098)
+ 0x110c, 0x1172, 0x11ad, 0,
+#undef V8520
+#define V8520 (V + 33102)
+ 0x110c, 0x1172, 0x11ae, 0,
+#undef V8521
+#define V8521 (V + 33106)
+ 0x110c, 0x1172, 0x11af, 0,
+#undef V8522
+#define V8522 (V + 33110)
+ 0x110c, 0x1172, 0x11b0, 0,
+#undef V8523
+#define V8523 (V + 33114)
+ 0x110c, 0x1172, 0x11b1, 0,
+#undef V8524
+#define V8524 (V + 33118)
+ 0x110c, 0x1172, 0x11b2, 0,
+#undef V8525
+#define V8525 (V + 33122)
+ 0x110c, 0x1172, 0x11b3, 0,
+#undef V8526
+#define V8526 (V + 33126)
+ 0x110c, 0x1172, 0x11b4, 0,
+#undef V8527
+#define V8527 (V + 33130)
+ 0x110c, 0x1172, 0x11b5, 0,
+#undef V8528
+#define V8528 (V + 33134)
+ 0x110c, 0x1172, 0x11b6, 0,
+#undef V8529
+#define V8529 (V + 33138)
+ 0x110c, 0x1172, 0x11b7, 0,
+#undef V8530
+#define V8530 (V + 33142)
+ 0x110c, 0x1172, 0x11b8, 0,
+#undef V8531
+#define V8531 (V + 33146)
+ 0x110c, 0x1172, 0x11b9, 0,
+#undef V8532
+#define V8532 (V + 33150)
+ 0x110c, 0x1172, 0x11ba, 0,
+#undef V8533
+#define V8533 (V + 33154)
+ 0x110c, 0x1172, 0x11bb, 0,
+#undef V8534
+#define V8534 (V + 33158)
+ 0x110c, 0x1172, 0x11bc, 0,
+#undef V8535
+#define V8535 (V + 33162)
+ 0x110c, 0x1172, 0x11bd, 0,
+#undef V8536
+#define V8536 (V + 33166)
+ 0x110c, 0x1172, 0x11be, 0,
+#undef V8537
+#define V8537 (V + 33170)
+ 0x110c, 0x1172, 0x11bf, 0,
+#undef V8538
+#define V8538 (V + 33174)
+ 0x110c, 0x1172, 0x11c0, 0,
+#undef V8539
+#define V8539 (V + 33178)
+ 0x110c, 0x1172, 0x11c1, 0,
+#undef V8540
+#define V8540 (V + 33182)
+ 0x110c, 0x1172, 0x11c2, 0,
+#undef V8541
+#define V8541 (V + 33186)
+ 0x110c, 0x1173, 0,
+#undef V8542
+#define V8542 (V + 33189)
+ 0x110c, 0x1173, 0x11a8, 0,
+#undef V8543
+#define V8543 (V + 33193)
+ 0x110c, 0x1173, 0x11a9, 0,
+#undef V8544
+#define V8544 (V + 33197)
+ 0x110c, 0x1173, 0x11aa, 0,
+#undef V8545
+#define V8545 (V + 33201)
+ 0x110c, 0x1173, 0x11ab, 0,
+#undef V8546
+#define V8546 (V + 33205)
+ 0x110c, 0x1173, 0x11ac, 0,
+#undef V8547
+#define V8547 (V + 33209)
+ 0x110c, 0x1173, 0x11ad, 0,
+#undef V8548
+#define V8548 (V + 33213)
+ 0x110c, 0x1173, 0x11ae, 0,
+#undef V8549
+#define V8549 (V + 33217)
+ 0x110c, 0x1173, 0x11af, 0,
+#undef V8550
+#define V8550 (V + 33221)
+ 0x110c, 0x1173, 0x11b0, 0,
+#undef V8551
+#define V8551 (V + 33225)
+ 0x110c, 0x1173, 0x11b1, 0,
+#undef V8552
+#define V8552 (V + 33229)
+ 0x110c, 0x1173, 0x11b2, 0,
+#undef V8553
+#define V8553 (V + 33233)
+ 0x110c, 0x1173, 0x11b3, 0,
+#undef V8554
+#define V8554 (V + 33237)
+ 0x110c, 0x1173, 0x11b4, 0,
+#undef V8555
+#define V8555 (V + 33241)
+ 0x110c, 0x1173, 0x11b5, 0,
+#undef V8556
+#define V8556 (V + 33245)
+ 0x110c, 0x1173, 0x11b6, 0,
+#undef V8557
+#define V8557 (V + 33249)
+ 0x110c, 0x1173, 0x11b7, 0,
+#undef V8558
+#define V8558 (V + 33253)
+ 0x110c, 0x1173, 0x11b8, 0,
+#undef V8559
+#define V8559 (V + 33257)
+ 0x110c, 0x1173, 0x11b9, 0,
+#undef V8560
+#define V8560 (V + 33261)
+ 0x110c, 0x1173, 0x11ba, 0,
+#undef V8561
+#define V8561 (V + 33265)
+ 0x110c, 0x1173, 0x11bb, 0,
+#undef V8562
+#define V8562 (V + 33269)
+ 0x110c, 0x1173, 0x11bc, 0,
+#undef V8563
+#define V8563 (V + 33273)
+ 0x110c, 0x1173, 0x11bd, 0,
+#undef V8564
+#define V8564 (V + 33277)
+ 0x110c, 0x1173, 0x11be, 0,
+#undef V8565
+#define V8565 (V + 33281)
+ 0x110c, 0x1173, 0x11bf, 0,
+#undef V8566
+#define V8566 (V + 33285)
+ 0x110c, 0x1173, 0x11c0, 0,
+#undef V8567
+#define V8567 (V + 33289)
+ 0x110c, 0x1173, 0x11c1, 0,
+#undef V8568
+#define V8568 (V + 33293)
+ 0x110c, 0x1173, 0x11c2, 0,
+#undef V8569
+#define V8569 (V + 33297)
+ 0x110c, 0x1174, 0,
+#undef V8570
+#define V8570 (V + 33300)
+ 0x110c, 0x1174, 0x11a8, 0,
+#undef V8571
+#define V8571 (V + 33304)
+ 0x110c, 0x1174, 0x11a9, 0,
+#undef V8572
+#define V8572 (V + 33308)
+ 0x110c, 0x1174, 0x11aa, 0,
+#undef V8573
+#define V8573 (V + 33312)
+ 0x110c, 0x1174, 0x11ab, 0,
+#undef V8574
+#define V8574 (V + 33316)
+ 0x110c, 0x1174, 0x11ac, 0,
+#undef V8575
+#define V8575 (V + 33320)
+ 0x110c, 0x1174, 0x11ad, 0,
+#undef V8576
+#define V8576 (V + 33324)
+ 0x110c, 0x1174, 0x11ae, 0,
+#undef V8577
+#define V8577 (V + 33328)
+ 0x110c, 0x1174, 0x11af, 0,
+#undef V8578
+#define V8578 (V + 33332)
+ 0x110c, 0x1174, 0x11b0, 0,
+#undef V8579
+#define V8579 (V + 33336)
+ 0x110c, 0x1174, 0x11b1, 0,
+#undef V8580
+#define V8580 (V + 33340)
+ 0x110c, 0x1174, 0x11b2, 0,
+#undef V8581
+#define V8581 (V + 33344)
+ 0x110c, 0x1174, 0x11b3, 0,
+#undef V8582
+#define V8582 (V + 33348)
+ 0x110c, 0x1174, 0x11b4, 0,
+#undef V8583
+#define V8583 (V + 33352)
+ 0x110c, 0x1174, 0x11b5, 0,
+#undef V8584
+#define V8584 (V + 33356)
+ 0x110c, 0x1174, 0x11b6, 0,
+#undef V8585
+#define V8585 (V + 33360)
+ 0x110c, 0x1174, 0x11b7, 0,
+#undef V8586
+#define V8586 (V + 33364)
+ 0x110c, 0x1174, 0x11b8, 0,
+#undef V8587
+#define V8587 (V + 33368)
+ 0x110c, 0x1174, 0x11b9, 0,
+#undef V8588
+#define V8588 (V + 33372)
+ 0x110c, 0x1174, 0x11ba, 0,
+#undef V8589
+#define V8589 (V + 33376)
+ 0x110c, 0x1174, 0x11bb, 0,
+#undef V8590
+#define V8590 (V + 33380)
+ 0x110c, 0x1174, 0x11bc, 0,
+#undef V8591
+#define V8591 (V + 33384)
+ 0x110c, 0x1174, 0x11bd, 0,
+#undef V8592
+#define V8592 (V + 33388)
+ 0x110c, 0x1174, 0x11be, 0,
+#undef V8593
+#define V8593 (V + 33392)
+ 0x110c, 0x1174, 0x11bf, 0,
+#undef V8594
+#define V8594 (V + 33396)
+ 0x110c, 0x1174, 0x11c0, 0,
+#undef V8595
+#define V8595 (V + 33400)
+ 0x110c, 0x1174, 0x11c1, 0,
+#undef V8596
+#define V8596 (V + 33404)
+ 0x110c, 0x1174, 0x11c2, 0,
+#undef V8597
+#define V8597 (V + 33408)
+ 0x110c, 0x1175, 0,
+#undef V8598
+#define V8598 (V + 33411)
+ 0x110c, 0x1175, 0x11a8, 0,
+#undef V8599
+#define V8599 (V + 33415)
+ 0x110c, 0x1175, 0x11a9, 0,
+#undef V8600
+#define V8600 (V + 33419)
+ 0x110c, 0x1175, 0x11aa, 0,
+#undef V8601
+#define V8601 (V + 33423)
+ 0x110c, 0x1175, 0x11ab, 0,
+#undef V8602
+#define V8602 (V + 33427)
+ 0x110c, 0x1175, 0x11ac, 0,
+#undef V8603
+#define V8603 (V + 33431)
+ 0x110c, 0x1175, 0x11ad, 0,
+#undef V8604
+#define V8604 (V + 33435)
+ 0x110c, 0x1175, 0x11ae, 0,
+#undef V8605
+#define V8605 (V + 33439)
+ 0x110c, 0x1175, 0x11af, 0,
+#undef V8606
+#define V8606 (V + 33443)
+ 0x110c, 0x1175, 0x11b0, 0,
+#undef V8607
+#define V8607 (V + 33447)
+ 0x110c, 0x1175, 0x11b1, 0,
+#undef V8608
+#define V8608 (V + 33451)
+ 0x110c, 0x1175, 0x11b2, 0,
+#undef V8609
+#define V8609 (V + 33455)
+ 0x110c, 0x1175, 0x11b3, 0,
+#undef V8610
+#define V8610 (V + 33459)
+ 0x110c, 0x1175, 0x11b4, 0,
+#undef V8611
+#define V8611 (V + 33463)
+ 0x110c, 0x1175, 0x11b5, 0,
+#undef V8612
+#define V8612 (V + 33467)
+ 0x110c, 0x1175, 0x11b6, 0,
+#undef V8613
+#define V8613 (V + 33471)
+ 0x110c, 0x1175, 0x11b7, 0,
+#undef V8614
+#define V8614 (V + 33475)
+ 0x110c, 0x1175, 0x11b8, 0,
+#undef V8615
+#define V8615 (V + 33479)
+ 0x110c, 0x1175, 0x11b9, 0,
+#undef V8616
+#define V8616 (V + 33483)
+ 0x110c, 0x1175, 0x11ba, 0,
+#undef V8617
+#define V8617 (V + 33487)
+ 0x110c, 0x1175, 0x11bb, 0,
+#undef V8618
+#define V8618 (V + 33491)
+ 0x110c, 0x1175, 0x11bc, 0,
+#undef V8619
+#define V8619 (V + 33495)
+ 0x110c, 0x1175, 0x11bd, 0,
+#undef V8620
+#define V8620 (V + 33499)
+ 0x110c, 0x1175, 0x11be, 0,
+#undef V8621
+#define V8621 (V + 33503)
+ 0x110c, 0x1175, 0x11bf, 0,
+#undef V8622
+#define V8622 (V + 33507)
+ 0x110c, 0x1175, 0x11c0, 0,
+#undef V8623
+#define V8623 (V + 33511)
+ 0x110c, 0x1175, 0x11c1, 0,
+#undef V8624
+#define V8624 (V + 33515)
+ 0x110c, 0x1175, 0x11c2, 0,
+#undef V8625
+#define V8625 (V + 33519)
+ 0x110d, 0x1161, 0,
+#undef V8626
+#define V8626 (V + 33522)
+ 0x110d, 0x1161, 0x11a8, 0,
+#undef V8627
+#define V8627 (V + 33526)
+ 0x110d, 0x1161, 0x11a9, 0,
+#undef V8628
+#define V8628 (V + 33530)
+ 0x110d, 0x1161, 0x11aa, 0,
+#undef V8629
+#define V8629 (V + 33534)
+ 0x110d, 0x1161, 0x11ab, 0,
+#undef V8630
+#define V8630 (V + 33538)
+ 0x110d, 0x1161, 0x11ac, 0,
+#undef V8631
+#define V8631 (V + 33542)
+ 0x110d, 0x1161, 0x11ad, 0,
+#undef V8632
+#define V8632 (V + 33546)
+ 0x110d, 0x1161, 0x11ae, 0,
+#undef V8633
+#define V8633 (V + 33550)
+ 0x110d, 0x1161, 0x11af, 0,
+#undef V8634
+#define V8634 (V + 33554)
+ 0x110d, 0x1161, 0x11b0, 0,
+#undef V8635
+#define V8635 (V + 33558)
+ 0x110d, 0x1161, 0x11b1, 0,
+#undef V8636
+#define V8636 (V + 33562)
+ 0x110d, 0x1161, 0x11b2, 0,
+#undef V8637
+#define V8637 (V + 33566)
+ 0x110d, 0x1161, 0x11b3, 0,
+#undef V8638
+#define V8638 (V + 33570)
+ 0x110d, 0x1161, 0x11b4, 0,
+#undef V8639
+#define V8639 (V + 33574)
+ 0x110d, 0x1161, 0x11b5, 0,
+#undef V8640
+#define V8640 (V + 33578)
+ 0x110d, 0x1161, 0x11b6, 0,
+#undef V8641
+#define V8641 (V + 33582)
+ 0x110d, 0x1161, 0x11b7, 0,
+#undef V8642
+#define V8642 (V + 33586)
+ 0x110d, 0x1161, 0x11b8, 0,
+#undef V8643
+#define V8643 (V + 33590)
+ 0x110d, 0x1161, 0x11b9, 0,
+#undef V8644
+#define V8644 (V + 33594)
+ 0x110d, 0x1161, 0x11ba, 0,
+#undef V8645
+#define V8645 (V + 33598)
+ 0x110d, 0x1161, 0x11bb, 0,
+#undef V8646
+#define V8646 (V + 33602)
+ 0x110d, 0x1161, 0x11bc, 0,
+#undef V8647
+#define V8647 (V + 33606)
+ 0x110d, 0x1161, 0x11bd, 0,
+#undef V8648
+#define V8648 (V + 33610)
+ 0x110d, 0x1161, 0x11be, 0,
+#undef V8649
+#define V8649 (V + 33614)
+ 0x110d, 0x1161, 0x11bf, 0,
+#undef V8650
+#define V8650 (V + 33618)
+ 0x110d, 0x1161, 0x11c0, 0,
+#undef V8651
+#define V8651 (V + 33622)
+ 0x110d, 0x1161, 0x11c1, 0,
+#undef V8652
+#define V8652 (V + 33626)
+ 0x110d, 0x1161, 0x11c2, 0,
+#undef V8653
+#define V8653 (V + 33630)
+ 0x110d, 0x1162, 0,
+#undef V8654
+#define V8654 (V + 33633)
+ 0x110d, 0x1162, 0x11a8, 0,
+#undef V8655
+#define V8655 (V + 33637)
+ 0x110d, 0x1162, 0x11a9, 0,
+#undef V8656
+#define V8656 (V + 33641)
+ 0x110d, 0x1162, 0x11aa, 0,
+#undef V8657
+#define V8657 (V + 33645)
+ 0x110d, 0x1162, 0x11ab, 0,
+#undef V8658
+#define V8658 (V + 33649)
+ 0x110d, 0x1162, 0x11ac, 0,
+#undef V8659
+#define V8659 (V + 33653)
+ 0x110d, 0x1162, 0x11ad, 0,
+#undef V8660
+#define V8660 (V + 33657)
+ 0x110d, 0x1162, 0x11ae, 0,
+#undef V8661
+#define V8661 (V + 33661)
+ 0x110d, 0x1162, 0x11af, 0,
+#undef V8662
+#define V8662 (V + 33665)
+ 0x110d, 0x1162, 0x11b0, 0,
+#undef V8663
+#define V8663 (V + 33669)
+ 0x110d, 0x1162, 0x11b1, 0,
+#undef V8664
+#define V8664 (V + 33673)
+ 0x110d, 0x1162, 0x11b2, 0,
+#undef V8665
+#define V8665 (V + 33677)
+ 0x110d, 0x1162, 0x11b3, 0,
+#undef V8666
+#define V8666 (V + 33681)
+ 0x110d, 0x1162, 0x11b4, 0,
+#undef V8667
+#define V8667 (V + 33685)
+ 0x110d, 0x1162, 0x11b5, 0,
+#undef V8668
+#define V8668 (V + 33689)
+ 0x110d, 0x1162, 0x11b6, 0,
+#undef V8669
+#define V8669 (V + 33693)
+ 0x110d, 0x1162, 0x11b7, 0,
+#undef V8670
+#define V8670 (V + 33697)
+ 0x110d, 0x1162, 0x11b8, 0,
+#undef V8671
+#define V8671 (V + 33701)
+ 0x110d, 0x1162, 0x11b9, 0,
+#undef V8672
+#define V8672 (V + 33705)
+ 0x110d, 0x1162, 0x11ba, 0,
+#undef V8673
+#define V8673 (V + 33709)
+ 0x110d, 0x1162, 0x11bb, 0,
+#undef V8674
+#define V8674 (V + 33713)
+ 0x110d, 0x1162, 0x11bc, 0,
+#undef V8675
+#define V8675 (V + 33717)
+ 0x110d, 0x1162, 0x11bd, 0,
+#undef V8676
+#define V8676 (V + 33721)
+ 0x110d, 0x1162, 0x11be, 0,
+#undef V8677
+#define V8677 (V + 33725)
+ 0x110d, 0x1162, 0x11bf, 0,
+#undef V8678
+#define V8678 (V + 33729)
+ 0x110d, 0x1162, 0x11c0, 0,
+#undef V8679
+#define V8679 (V + 33733)
+ 0x110d, 0x1162, 0x11c1, 0,
+#undef V8680
+#define V8680 (V + 33737)
+ 0x110d, 0x1162, 0x11c2, 0,
+#undef V8681
+#define V8681 (V + 33741)
+ 0x110d, 0x1163, 0,
+#undef V8682
+#define V8682 (V + 33744)
+ 0x110d, 0x1163, 0x11a8, 0,
+#undef V8683
+#define V8683 (V + 33748)
+ 0x110d, 0x1163, 0x11a9, 0,
+#undef V8684
+#define V8684 (V + 33752)
+ 0x110d, 0x1163, 0x11aa, 0,
+#undef V8685
+#define V8685 (V + 33756)
+ 0x110d, 0x1163, 0x11ab, 0,
+#undef V8686
+#define V8686 (V + 33760)
+ 0x110d, 0x1163, 0x11ac, 0,
+#undef V8687
+#define V8687 (V + 33764)
+ 0x110d, 0x1163, 0x11ad, 0,
+#undef V8688
+#define V8688 (V + 33768)
+ 0x110d, 0x1163, 0x11ae, 0,
+#undef V8689
+#define V8689 (V + 33772)
+ 0x110d, 0x1163, 0x11af, 0,
+#undef V8690
+#define V8690 (V + 33776)
+ 0x110d, 0x1163, 0x11b0, 0,
+#undef V8691
+#define V8691 (V + 33780)
+ 0x110d, 0x1163, 0x11b1, 0,
+#undef V8692
+#define V8692 (V + 33784)
+ 0x110d, 0x1163, 0x11b2, 0,
+#undef V8693
+#define V8693 (V + 33788)
+ 0x110d, 0x1163, 0x11b3, 0,
+#undef V8694
+#define V8694 (V + 33792)
+ 0x110d, 0x1163, 0x11b4, 0,
+#undef V8695
+#define V8695 (V + 33796)
+ 0x110d, 0x1163, 0x11b5, 0,
+#undef V8696
+#define V8696 (V + 33800)
+ 0x110d, 0x1163, 0x11b6, 0,
+#undef V8697
+#define V8697 (V + 33804)
+ 0x110d, 0x1163, 0x11b7, 0,
+#undef V8698
+#define V8698 (V + 33808)
+ 0x110d, 0x1163, 0x11b8, 0,
+#undef V8699
+#define V8699 (V + 33812)
+ 0x110d, 0x1163, 0x11b9, 0,
+#undef V8700
+#define V8700 (V + 33816)
+ 0x110d, 0x1163, 0x11ba, 0,
+#undef V8701
+#define V8701 (V + 33820)
+ 0x110d, 0x1163, 0x11bb, 0,
+#undef V8702
+#define V8702 (V + 33824)
+ 0x110d, 0x1163, 0x11bc, 0,
+#undef V8703
+#define V8703 (V + 33828)
+ 0x110d, 0x1163, 0x11bd, 0,
+#undef V8704
+#define V8704 (V + 33832)
+ 0x110d, 0x1163, 0x11be, 0,
+#undef V8705
+#define V8705 (V + 33836)
+ 0x110d, 0x1163, 0x11bf, 0,
+#undef V8706
+#define V8706 (V + 33840)
+ 0x110d, 0x1163, 0x11c0, 0,
+#undef V8707
+#define V8707 (V + 33844)
+ 0x110d, 0x1163, 0x11c1, 0,
+#undef V8708
+#define V8708 (V + 33848)
+ 0x110d, 0x1163, 0x11c2, 0,
+#undef V8709
+#define V8709 (V + 33852)
+ 0x110d, 0x1164, 0,
+#undef V8710
+#define V8710 (V + 33855)
+ 0x110d, 0x1164, 0x11a8, 0,
+#undef V8711
+#define V8711 (V + 33859)
+ 0x110d, 0x1164, 0x11a9, 0,
+#undef V8712
+#define V8712 (V + 33863)
+ 0x110d, 0x1164, 0x11aa, 0,
+#undef V8713
+#define V8713 (V + 33867)
+ 0x110d, 0x1164, 0x11ab, 0,
+#undef V8714
+#define V8714 (V + 33871)
+ 0x110d, 0x1164, 0x11ac, 0,
+#undef V8715
+#define V8715 (V + 33875)
+ 0x110d, 0x1164, 0x11ad, 0,
+#undef V8716
+#define V8716 (V + 33879)
+ 0x110d, 0x1164, 0x11ae, 0,
+#undef V8717
+#define V8717 (V + 33883)
+ 0x110d, 0x1164, 0x11af, 0,
+#undef V8718
+#define V8718 (V + 33887)
+ 0x110d, 0x1164, 0x11b0, 0,
+#undef V8719
+#define V8719 (V + 33891)
+ 0x110d, 0x1164, 0x11b1, 0,
+#undef V8720
+#define V8720 (V + 33895)
+ 0x110d, 0x1164, 0x11b2, 0,
+#undef V8721
+#define V8721 (V + 33899)
+ 0x110d, 0x1164, 0x11b3, 0,
+#undef V8722
+#define V8722 (V + 33903)
+ 0x110d, 0x1164, 0x11b4, 0,
+#undef V8723
+#define V8723 (V + 33907)
+ 0x110d, 0x1164, 0x11b5, 0,
+#undef V8724
+#define V8724 (V + 33911)
+ 0x110d, 0x1164, 0x11b6, 0,
+#undef V8725
+#define V8725 (V + 33915)
+ 0x110d, 0x1164, 0x11b7, 0,
+#undef V8726
+#define V8726 (V + 33919)
+ 0x110d, 0x1164, 0x11b8, 0,
+#undef V8727
+#define V8727 (V + 33923)
+ 0x110d, 0x1164, 0x11b9, 0,
+#undef V8728
+#define V8728 (V + 33927)
+ 0x110d, 0x1164, 0x11ba, 0,
+#undef V8729
+#define V8729 (V + 33931)
+ 0x110d, 0x1164, 0x11bb, 0,
+#undef V8730
+#define V8730 (V + 33935)
+ 0x110d, 0x1164, 0x11bc, 0,
+#undef V8731
+#define V8731 (V + 33939)
+ 0x110d, 0x1164, 0x11bd, 0,
+#undef V8732
+#define V8732 (V + 33943)
+ 0x110d, 0x1164, 0x11be, 0,
+#undef V8733
+#define V8733 (V + 33947)
+ 0x110d, 0x1164, 0x11bf, 0,
+#undef V8734
+#define V8734 (V + 33951)
+ 0x110d, 0x1164, 0x11c0, 0,
+#undef V8735
+#define V8735 (V + 33955)
+ 0x110d, 0x1164, 0x11c1, 0,
+#undef V8736
+#define V8736 (V + 33959)
+ 0x110d, 0x1164, 0x11c2, 0,
+#undef V8737
+#define V8737 (V + 33963)
+ 0x110d, 0x1165, 0,
+#undef V8738
+#define V8738 (V + 33966)
+ 0x110d, 0x1165, 0x11a8, 0,
+#undef V8739
+#define V8739 (V + 33970)
+ 0x110d, 0x1165, 0x11a9, 0,
+#undef V8740
+#define V8740 (V + 33974)
+ 0x110d, 0x1165, 0x11aa, 0,
+#undef V8741
+#define V8741 (V + 33978)
+ 0x110d, 0x1165, 0x11ab, 0,
+#undef V8742
+#define V8742 (V + 33982)
+ 0x110d, 0x1165, 0x11ac, 0,
+#undef V8743
+#define V8743 (V + 33986)
+ 0x110d, 0x1165, 0x11ad, 0,
+#undef V8744
+#define V8744 (V + 33990)
+ 0x110d, 0x1165, 0x11ae, 0,
+#undef V8745
+#define V8745 (V + 33994)
+ 0x110d, 0x1165, 0x11af, 0,
+#undef V8746
+#define V8746 (V + 33998)
+ 0x110d, 0x1165, 0x11b0, 0,
+#undef V8747
+#define V8747 (V + 34002)
+ 0x110d, 0x1165, 0x11b1, 0,
+#undef V8748
+#define V8748 (V + 34006)
+ 0x110d, 0x1165, 0x11b2, 0,
+#undef V8749
+#define V8749 (V + 34010)
+ 0x110d, 0x1165, 0x11b3, 0,
+#undef V8750
+#define V8750 (V + 34014)
+ 0x110d, 0x1165, 0x11b4, 0,
+#undef V8751
+#define V8751 (V + 34018)
+ 0x110d, 0x1165, 0x11b5, 0,
+#undef V8752
+#define V8752 (V + 34022)
+ 0x110d, 0x1165, 0x11b6, 0,
+#undef V8753
+#define V8753 (V + 34026)
+ 0x110d, 0x1165, 0x11b7, 0,
+#undef V8754
+#define V8754 (V + 34030)
+ 0x110d, 0x1165, 0x11b8, 0,
+#undef V8755
+#define V8755 (V + 34034)
+ 0x110d, 0x1165, 0x11b9, 0,
+#undef V8756
+#define V8756 (V + 34038)
+ 0x110d, 0x1165, 0x11ba, 0,
+#undef V8757
+#define V8757 (V + 34042)
+ 0x110d, 0x1165, 0x11bb, 0,
+#undef V8758
+#define V8758 (V + 34046)
+ 0x110d, 0x1165, 0x11bc, 0,
+#undef V8759
+#define V8759 (V + 34050)
+ 0x110d, 0x1165, 0x11bd, 0,
+#undef V8760
+#define V8760 (V + 34054)
+ 0x110d, 0x1165, 0x11be, 0,
+#undef V8761
+#define V8761 (V + 34058)
+ 0x110d, 0x1165, 0x11bf, 0,
+#undef V8762
+#define V8762 (V + 34062)
+ 0x110d, 0x1165, 0x11c0, 0,
+#undef V8763
+#define V8763 (V + 34066)
+ 0x110d, 0x1165, 0x11c1, 0,
+#undef V8764
+#define V8764 (V + 34070)
+ 0x110d, 0x1165, 0x11c2, 0,
+#undef V8765
+#define V8765 (V + 34074)
+ 0x110d, 0x1166, 0,
+#undef V8766
+#define V8766 (V + 34077)
+ 0x110d, 0x1166, 0x11a8, 0,
+#undef V8767
+#define V8767 (V + 34081)
+ 0x110d, 0x1166, 0x11a9, 0,
+#undef V8768
+#define V8768 (V + 34085)
+ 0x110d, 0x1166, 0x11aa, 0,
+#undef V8769
+#define V8769 (V + 34089)
+ 0x110d, 0x1166, 0x11ab, 0,
+#undef V8770
+#define V8770 (V + 34093)
+ 0x110d, 0x1166, 0x11ac, 0,
+#undef V8771
+#define V8771 (V + 34097)
+ 0x110d, 0x1166, 0x11ad, 0,
+#undef V8772
+#define V8772 (V + 34101)
+ 0x110d, 0x1166, 0x11ae, 0,
+#undef V8773
+#define V8773 (V + 34105)
+ 0x110d, 0x1166, 0x11af, 0,
+#undef V8774
+#define V8774 (V + 34109)
+ 0x110d, 0x1166, 0x11b0, 0,
+#undef V8775
+#define V8775 (V + 34113)
+ 0x110d, 0x1166, 0x11b1, 0,
+#undef V8776
+#define V8776 (V + 34117)
+ 0x110d, 0x1166, 0x11b2, 0,
+#undef V8777
+#define V8777 (V + 34121)
+ 0x110d, 0x1166, 0x11b3, 0,
+#undef V8778
+#define V8778 (V + 34125)
+ 0x110d, 0x1166, 0x11b4, 0,
+#undef V8779
+#define V8779 (V + 34129)
+ 0x110d, 0x1166, 0x11b5, 0,
+#undef V8780
+#define V8780 (V + 34133)
+ 0x110d, 0x1166, 0x11b6, 0,
+#undef V8781
+#define V8781 (V + 34137)
+ 0x110d, 0x1166, 0x11b7, 0,
+#undef V8782
+#define V8782 (V + 34141)
+ 0x110d, 0x1166, 0x11b8, 0,
+#undef V8783
+#define V8783 (V + 34145)
+ 0x110d, 0x1166, 0x11b9, 0,
+#undef V8784
+#define V8784 (V + 34149)
+ 0x110d, 0x1166, 0x11ba, 0,
+#undef V8785
+#define V8785 (V + 34153)
+ 0x110d, 0x1166, 0x11bb, 0,
+#undef V8786
+#define V8786 (V + 34157)
+ 0x110d, 0x1166, 0x11bc, 0,
+#undef V8787
+#define V8787 (V + 34161)
+ 0x110d, 0x1166, 0x11bd, 0,
+#undef V8788
+#define V8788 (V + 34165)
+ 0x110d, 0x1166, 0x11be, 0,
+#undef V8789
+#define V8789 (V + 34169)
+ 0x110d, 0x1166, 0x11bf, 0,
+#undef V8790
+#define V8790 (V + 34173)
+ 0x110d, 0x1166, 0x11c0, 0,
+#undef V8791
+#define V8791 (V + 34177)
+ 0x110d, 0x1166, 0x11c1, 0,
+#undef V8792
+#define V8792 (V + 34181)
+ 0x110d, 0x1166, 0x11c2, 0,
+#undef V8793
+#define V8793 (V + 34185)
+ 0x110d, 0x1167, 0,
+#undef V8794
+#define V8794 (V + 34188)
+ 0x110d, 0x1167, 0x11a8, 0,
+#undef V8795
+#define V8795 (V + 34192)
+ 0x110d, 0x1167, 0x11a9, 0,
+#undef V8796
+#define V8796 (V + 34196)
+ 0x110d, 0x1167, 0x11aa, 0,
+#undef V8797
+#define V8797 (V + 34200)
+ 0x110d, 0x1167, 0x11ab, 0,
+#undef V8798
+#define V8798 (V + 34204)
+ 0x110d, 0x1167, 0x11ac, 0,
+#undef V8799
+#define V8799 (V + 34208)
+ 0x110d, 0x1167, 0x11ad, 0,
+#undef V8800
+#define V8800 (V + 34212)
+ 0x110d, 0x1167, 0x11ae, 0,
+#undef V8801
+#define V8801 (V + 34216)
+ 0x110d, 0x1167, 0x11af, 0,
+#undef V8802
+#define V8802 (V + 34220)
+ 0x110d, 0x1167, 0x11b0, 0,
+#undef V8803
+#define V8803 (V + 34224)
+ 0x110d, 0x1167, 0x11b1, 0,
+#undef V8804
+#define V8804 (V + 34228)
+ 0x110d, 0x1167, 0x11b2, 0,
+#undef V8805
+#define V8805 (V + 34232)
+ 0x110d, 0x1167, 0x11b3, 0,
+#undef V8806
+#define V8806 (V + 34236)
+ 0x110d, 0x1167, 0x11b4, 0,
+#undef V8807
+#define V8807 (V + 34240)
+ 0x110d, 0x1167, 0x11b5, 0,
+#undef V8808
+#define V8808 (V + 34244)
+ 0x110d, 0x1167, 0x11b6, 0,
+#undef V8809
+#define V8809 (V + 34248)
+ 0x110d, 0x1167, 0x11b7, 0,
+#undef V8810
+#define V8810 (V + 34252)
+ 0x110d, 0x1167, 0x11b8, 0,
+#undef V8811
+#define V8811 (V + 34256)
+ 0x110d, 0x1167, 0x11b9, 0,
+#undef V8812
+#define V8812 (V + 34260)
+ 0x110d, 0x1167, 0x11ba, 0,
+#undef V8813
+#define V8813 (V + 34264)
+ 0x110d, 0x1167, 0x11bb, 0,
+#undef V8814
+#define V8814 (V + 34268)
+ 0x110d, 0x1167, 0x11bc, 0,
+#undef V8815
+#define V8815 (V + 34272)
+ 0x110d, 0x1167, 0x11bd, 0,
+#undef V8816
+#define V8816 (V + 34276)
+ 0x110d, 0x1167, 0x11be, 0,
+#undef V8817
+#define V8817 (V + 34280)
+ 0x110d, 0x1167, 0x11bf, 0,
+#undef V8818
+#define V8818 (V + 34284)
+ 0x110d, 0x1167, 0x11c0, 0,
+#undef V8819
+#define V8819 (V + 34288)
+ 0x110d, 0x1167, 0x11c1, 0,
+#undef V8820
+#define V8820 (V + 34292)
+ 0x110d, 0x1167, 0x11c2, 0,
+#undef V8821
+#define V8821 (V + 34296)
+ 0x110d, 0x1168, 0,
+#undef V8822
+#define V8822 (V + 34299)
+ 0x110d, 0x1168, 0x11a8, 0,
+#undef V8823
+#define V8823 (V + 34303)
+ 0x110d, 0x1168, 0x11a9, 0,
+#undef V8824
+#define V8824 (V + 34307)
+ 0x110d, 0x1168, 0x11aa, 0,
+#undef V8825
+#define V8825 (V + 34311)
+ 0x110d, 0x1168, 0x11ab, 0,
+#undef V8826
+#define V8826 (V + 34315)
+ 0x110d, 0x1168, 0x11ac, 0,
+#undef V8827
+#define V8827 (V + 34319)
+ 0x110d, 0x1168, 0x11ad, 0,
+#undef V8828
+#define V8828 (V + 34323)
+ 0x110d, 0x1168, 0x11ae, 0,
+#undef V8829
+#define V8829 (V + 34327)
+ 0x110d, 0x1168, 0x11af, 0,
+#undef V8830
+#define V8830 (V + 34331)
+ 0x110d, 0x1168, 0x11b0, 0,
+#undef V8831
+#define V8831 (V + 34335)
+ 0x110d, 0x1168, 0x11b1, 0,
+#undef V8832
+#define V8832 (V + 34339)
+ 0x110d, 0x1168, 0x11b2, 0,
+#undef V8833
+#define V8833 (V + 34343)
+ 0x110d, 0x1168, 0x11b3, 0,
+#undef V8834
+#define V8834 (V + 34347)
+ 0x110d, 0x1168, 0x11b4, 0,
+#undef V8835
+#define V8835 (V + 34351)
+ 0x110d, 0x1168, 0x11b5, 0,
+#undef V8836
+#define V8836 (V + 34355)
+ 0x110d, 0x1168, 0x11b6, 0,
+#undef V8837
+#define V8837 (V + 34359)
+ 0x110d, 0x1168, 0x11b7, 0,
+#undef V8838
+#define V8838 (V + 34363)
+ 0x110d, 0x1168, 0x11b8, 0,
+#undef V8839
+#define V8839 (V + 34367)
+ 0x110d, 0x1168, 0x11b9, 0,
+#undef V8840
+#define V8840 (V + 34371)
+ 0x110d, 0x1168, 0x11ba, 0,
+#undef V8841
+#define V8841 (V + 34375)
+ 0x110d, 0x1168, 0x11bb, 0,
+#undef V8842
+#define V8842 (V + 34379)
+ 0x110d, 0x1168, 0x11bc, 0,
+#undef V8843
+#define V8843 (V + 34383)
+ 0x110d, 0x1168, 0x11bd, 0,
+#undef V8844
+#define V8844 (V + 34387)
+ 0x110d, 0x1168, 0x11be, 0,
+#undef V8845
+#define V8845 (V + 34391)
+ 0x110d, 0x1168, 0x11bf, 0,
+#undef V8846
+#define V8846 (V + 34395)
+ 0x110d, 0x1168, 0x11c0, 0,
+#undef V8847
+#define V8847 (V + 34399)
+ 0x110d, 0x1168, 0x11c1, 0,
+#undef V8848
+#define V8848 (V + 34403)
+ 0x110d, 0x1168, 0x11c2, 0,
+#undef V8849
+#define V8849 (V + 34407)
+ 0x110d, 0x1169, 0,
+#undef V8850
+#define V8850 (V + 34410)
+ 0x110d, 0x1169, 0x11a8, 0,
+#undef V8851
+#define V8851 (V + 34414)
+ 0x110d, 0x1169, 0x11a9, 0,
+#undef V8852
+#define V8852 (V + 34418)
+ 0x110d, 0x1169, 0x11aa, 0,
+#undef V8853
+#define V8853 (V + 34422)
+ 0x110d, 0x1169, 0x11ab, 0,
+#undef V8854
+#define V8854 (V + 34426)
+ 0x110d, 0x1169, 0x11ac, 0,
+#undef V8855
+#define V8855 (V + 34430)
+ 0x110d, 0x1169, 0x11ad, 0,
+#undef V8856
+#define V8856 (V + 34434)
+ 0x110d, 0x1169, 0x11ae, 0,
+#undef V8857
+#define V8857 (V + 34438)
+ 0x110d, 0x1169, 0x11af, 0,
+#undef V8858
+#define V8858 (V + 34442)
+ 0x110d, 0x1169, 0x11b0, 0,
+#undef V8859
+#define V8859 (V + 34446)
+ 0x110d, 0x1169, 0x11b1, 0,
+#undef V8860
+#define V8860 (V + 34450)
+ 0x110d, 0x1169, 0x11b2, 0,
+#undef V8861
+#define V8861 (V + 34454)
+ 0x110d, 0x1169, 0x11b3, 0,
+#undef V8862
+#define V8862 (V + 34458)
+ 0x110d, 0x1169, 0x11b4, 0,
+#undef V8863
+#define V8863 (V + 34462)
+ 0x110d, 0x1169, 0x11b5, 0,
+#undef V8864
+#define V8864 (V + 34466)
+ 0x110d, 0x1169, 0x11b6, 0,
+#undef V8865
+#define V8865 (V + 34470)
+ 0x110d, 0x1169, 0x11b7, 0,
+#undef V8866
+#define V8866 (V + 34474)
+ 0x110d, 0x1169, 0x11b8, 0,
+#undef V8867
+#define V8867 (V + 34478)
+ 0x110d, 0x1169, 0x11b9, 0,
+#undef V8868
+#define V8868 (V + 34482)
+ 0x110d, 0x1169, 0x11ba, 0,
+#undef V8869
+#define V8869 (V + 34486)
+ 0x110d, 0x1169, 0x11bb, 0,
+#undef V8870
+#define V8870 (V + 34490)
+ 0x110d, 0x1169, 0x11bc, 0,
+#undef V8871
+#define V8871 (V + 34494)
+ 0x110d, 0x1169, 0x11bd, 0,
+#undef V8872
+#define V8872 (V + 34498)
+ 0x110d, 0x1169, 0x11be, 0,
+#undef V8873
+#define V8873 (V + 34502)
+ 0x110d, 0x1169, 0x11bf, 0,
+#undef V8874
+#define V8874 (V + 34506)
+ 0x110d, 0x1169, 0x11c0, 0,
+#undef V8875
+#define V8875 (V + 34510)
+ 0x110d, 0x1169, 0x11c1, 0,
+#undef V8876
+#define V8876 (V + 34514)
+ 0x110d, 0x1169, 0x11c2, 0,
+#undef V8877
+#define V8877 (V + 34518)
+ 0x110d, 0x116a, 0,
+#undef V8878
+#define V8878 (V + 34521)
+ 0x110d, 0x116a, 0x11a8, 0,
+#undef V8879
+#define V8879 (V + 34525)
+ 0x110d, 0x116a, 0x11a9, 0,
+#undef V8880
+#define V8880 (V + 34529)
+ 0x110d, 0x116a, 0x11aa, 0,
+#undef V8881
+#define V8881 (V + 34533)
+ 0x110d, 0x116a, 0x11ab, 0,
+#undef V8882
+#define V8882 (V + 34537)
+ 0x110d, 0x116a, 0x11ac, 0,
+#undef V8883
+#define V8883 (V + 34541)
+ 0x110d, 0x116a, 0x11ad, 0,
+#undef V8884
+#define V8884 (V + 34545)
+ 0x110d, 0x116a, 0x11ae, 0,
+#undef V8885
+#define V8885 (V + 34549)
+ 0x110d, 0x116a, 0x11af, 0,
+#undef V8886
+#define V8886 (V + 34553)
+ 0x110d, 0x116a, 0x11b0, 0,
+#undef V8887
+#define V8887 (V + 34557)
+ 0x110d, 0x116a, 0x11b1, 0,
+#undef V8888
+#define V8888 (V + 34561)
+ 0x110d, 0x116a, 0x11b2, 0,
+#undef V8889
+#define V8889 (V + 34565)
+ 0x110d, 0x116a, 0x11b3, 0,
+#undef V8890
+#define V8890 (V + 34569)
+ 0x110d, 0x116a, 0x11b4, 0,
+#undef V8891
+#define V8891 (V + 34573)
+ 0x110d, 0x116a, 0x11b5, 0,
+#undef V8892
+#define V8892 (V + 34577)
+ 0x110d, 0x116a, 0x11b6, 0,
+#undef V8893
+#define V8893 (V + 34581)
+ 0x110d, 0x116a, 0x11b7, 0,
+#undef V8894
+#define V8894 (V + 34585)
+ 0x110d, 0x116a, 0x11b8, 0,
+#undef V8895
+#define V8895 (V + 34589)
+ 0x110d, 0x116a, 0x11b9, 0,
+#undef V8896
+#define V8896 (V + 34593)
+ 0x110d, 0x116a, 0x11ba, 0,
+#undef V8897
+#define V8897 (V + 34597)
+ 0x110d, 0x116a, 0x11bb, 0,
+#undef V8898
+#define V8898 (V + 34601)
+ 0x110d, 0x116a, 0x11bc, 0,
+#undef V8899
+#define V8899 (V + 34605)
+ 0x110d, 0x116a, 0x11bd, 0,
+#undef V8900
+#define V8900 (V + 34609)
+ 0x110d, 0x116a, 0x11be, 0,
+#undef V8901
+#define V8901 (V + 34613)
+ 0x110d, 0x116a, 0x11bf, 0,
+#undef V8902
+#define V8902 (V + 34617)
+ 0x110d, 0x116a, 0x11c0, 0,
+#undef V8903
+#define V8903 (V + 34621)
+ 0x110d, 0x116a, 0x11c1, 0,
+#undef V8904
+#define V8904 (V + 34625)
+ 0x110d, 0x116a, 0x11c2, 0,
+#undef V8905
+#define V8905 (V + 34629)
+ 0x110d, 0x116b, 0,
+#undef V8906
+#define V8906 (V + 34632)
+ 0x110d, 0x116b, 0x11a8, 0,
+#undef V8907
+#define V8907 (V + 34636)
+ 0x110d, 0x116b, 0x11a9, 0,
+#undef V8908
+#define V8908 (V + 34640)
+ 0x110d, 0x116b, 0x11aa, 0,
+#undef V8909
+#define V8909 (V + 34644)
+ 0x110d, 0x116b, 0x11ab, 0,
+#undef V8910
+#define V8910 (V + 34648)
+ 0x110d, 0x116b, 0x11ac, 0,
+#undef V8911
+#define V8911 (V + 34652)
+ 0x110d, 0x116b, 0x11ad, 0,
+#undef V8912
+#define V8912 (V + 34656)
+ 0x110d, 0x116b, 0x11ae, 0,
+#undef V8913
+#define V8913 (V + 34660)
+ 0x110d, 0x116b, 0x11af, 0,
+#undef V8914
+#define V8914 (V + 34664)
+ 0x110d, 0x116b, 0x11b0, 0,
+#undef V8915
+#define V8915 (V + 34668)
+ 0x110d, 0x116b, 0x11b1, 0,
+#undef V8916
+#define V8916 (V + 34672)
+ 0x110d, 0x116b, 0x11b2, 0,
+#undef V8917
+#define V8917 (V + 34676)
+ 0x110d, 0x116b, 0x11b3, 0,
+#undef V8918
+#define V8918 (V + 34680)
+ 0x110d, 0x116b, 0x11b4, 0,
+#undef V8919
+#define V8919 (V + 34684)
+ 0x110d, 0x116b, 0x11b5, 0,
+#undef V8920
+#define V8920 (V + 34688)
+ 0x110d, 0x116b, 0x11b6, 0,
+#undef V8921
+#define V8921 (V + 34692)
+ 0x110d, 0x116b, 0x11b7, 0,
+#undef V8922
+#define V8922 (V + 34696)
+ 0x110d, 0x116b, 0x11b8, 0,
+#undef V8923
+#define V8923 (V + 34700)
+ 0x110d, 0x116b, 0x11b9, 0,
+#undef V8924
+#define V8924 (V + 34704)
+ 0x110d, 0x116b, 0x11ba, 0,
+#undef V8925
+#define V8925 (V + 34708)
+ 0x110d, 0x116b, 0x11bb, 0,
+#undef V8926
+#define V8926 (V + 34712)
+ 0x110d, 0x116b, 0x11bc, 0,
+#undef V8927
+#define V8927 (V + 34716)
+ 0x110d, 0x116b, 0x11bd, 0,
+#undef V8928
+#define V8928 (V + 34720)
+ 0x110d, 0x116b, 0x11be, 0,
+#undef V8929
+#define V8929 (V + 34724)
+ 0x110d, 0x116b, 0x11bf, 0,
+#undef V8930
+#define V8930 (V + 34728)
+ 0x110d, 0x116b, 0x11c0, 0,
+#undef V8931
+#define V8931 (V + 34732)
+ 0x110d, 0x116b, 0x11c1, 0,
+#undef V8932
+#define V8932 (V + 34736)
+ 0x110d, 0x116b, 0x11c2, 0,
+#undef V8933
+#define V8933 (V + 34740)
+ 0x110d, 0x116c, 0,
+#undef V8934
+#define V8934 (V + 34743)
+ 0x110d, 0x116c, 0x11a8, 0,
+#undef V8935
+#define V8935 (V + 34747)
+ 0x110d, 0x116c, 0x11a9, 0,
+#undef V8936
+#define V8936 (V + 34751)
+ 0x110d, 0x116c, 0x11aa, 0,
+#undef V8937
+#define V8937 (V + 34755)
+ 0x110d, 0x116c, 0x11ab, 0,
+#undef V8938
+#define V8938 (V + 34759)
+ 0x110d, 0x116c, 0x11ac, 0,
+#undef V8939
+#define V8939 (V + 34763)
+ 0x110d, 0x116c, 0x11ad, 0,
+#undef V8940
+#define V8940 (V + 34767)
+ 0x110d, 0x116c, 0x11ae, 0,
+#undef V8941
+#define V8941 (V + 34771)
+ 0x110d, 0x116c, 0x11af, 0,
+#undef V8942
+#define V8942 (V + 34775)
+ 0x110d, 0x116c, 0x11b0, 0,
+#undef V8943
+#define V8943 (V + 34779)
+ 0x110d, 0x116c, 0x11b1, 0,
+#undef V8944
+#define V8944 (V + 34783)
+ 0x110d, 0x116c, 0x11b2, 0,
+#undef V8945
+#define V8945 (V + 34787)
+ 0x110d, 0x116c, 0x11b3, 0,
+#undef V8946
+#define V8946 (V + 34791)
+ 0x110d, 0x116c, 0x11b4, 0,
+#undef V8947
+#define V8947 (V + 34795)
+ 0x110d, 0x116c, 0x11b5, 0,
+#undef V8948
+#define V8948 (V + 34799)
+ 0x110d, 0x116c, 0x11b6, 0,
+#undef V8949
+#define V8949 (V + 34803)
+ 0x110d, 0x116c, 0x11b7, 0,
+#undef V8950
+#define V8950 (V + 34807)
+ 0x110d, 0x116c, 0x11b8, 0,
+#undef V8951
+#define V8951 (V + 34811)
+ 0x110d, 0x116c, 0x11b9, 0,
+#undef V8952
+#define V8952 (V + 34815)
+ 0x110d, 0x116c, 0x11ba, 0,
+#undef V8953
+#define V8953 (V + 34819)
+ 0x110d, 0x116c, 0x11bb, 0,
+#undef V8954
+#define V8954 (V + 34823)
+ 0x110d, 0x116c, 0x11bc, 0,
+#undef V8955
+#define V8955 (V + 34827)
+ 0x110d, 0x116c, 0x11bd, 0,
+#undef V8956
+#define V8956 (V + 34831)
+ 0x110d, 0x116c, 0x11be, 0,
+#undef V8957
+#define V8957 (V + 34835)
+ 0x110d, 0x116c, 0x11bf, 0,
+#undef V8958
+#define V8958 (V + 34839)
+ 0x110d, 0x116c, 0x11c0, 0,
+#undef V8959
+#define V8959 (V + 34843)
+ 0x110d, 0x116c, 0x11c1, 0,
+#undef V8960
+#define V8960 (V + 34847)
+ 0x110d, 0x116c, 0x11c2, 0,
+#undef V8961
+#define V8961 (V + 34851)
+ 0x110d, 0x116d, 0,
+#undef V8962
+#define V8962 (V + 34854)
+ 0x110d, 0x116d, 0x11a8, 0,
+#undef V8963
+#define V8963 (V + 34858)
+ 0x110d, 0x116d, 0x11a9, 0,
+#undef V8964
+#define V8964 (V + 34862)
+ 0x110d, 0x116d, 0x11aa, 0,
+#undef V8965
+#define V8965 (V + 34866)
+ 0x110d, 0x116d, 0x11ab, 0,
+#undef V8966
+#define V8966 (V + 34870)
+ 0x110d, 0x116d, 0x11ac, 0,
+#undef V8967
+#define V8967 (V + 34874)
+ 0x110d, 0x116d, 0x11ad, 0,
+#undef V8968
+#define V8968 (V + 34878)
+ 0x110d, 0x116d, 0x11ae, 0,
+#undef V8969
+#define V8969 (V + 34882)
+ 0x110d, 0x116d, 0x11af, 0,
+#undef V8970
+#define V8970 (V + 34886)
+ 0x110d, 0x116d, 0x11b0, 0,
+#undef V8971
+#define V8971 (V + 34890)
+ 0x110d, 0x116d, 0x11b1, 0,
+#undef V8972
+#define V8972 (V + 34894)
+ 0x110d, 0x116d, 0x11b2, 0,
+#undef V8973
+#define V8973 (V + 34898)
+ 0x110d, 0x116d, 0x11b3, 0,
+#undef V8974
+#define V8974 (V + 34902)
+ 0x110d, 0x116d, 0x11b4, 0,
+#undef V8975
+#define V8975 (V + 34906)
+ 0x110d, 0x116d, 0x11b5, 0,
+#undef V8976
+#define V8976 (V + 34910)
+ 0x110d, 0x116d, 0x11b6, 0,
+#undef V8977
+#define V8977 (V + 34914)
+ 0x110d, 0x116d, 0x11b7, 0,
+#undef V8978
+#define V8978 (V + 34918)
+ 0x110d, 0x116d, 0x11b8, 0,
+#undef V8979
+#define V8979 (V + 34922)
+ 0x110d, 0x116d, 0x11b9, 0,
+#undef V8980
+#define V8980 (V + 34926)
+ 0x110d, 0x116d, 0x11ba, 0,
+#undef V8981
+#define V8981 (V + 34930)
+ 0x110d, 0x116d, 0x11bb, 0,
+#undef V8982
+#define V8982 (V + 34934)
+ 0x110d, 0x116d, 0x11bc, 0,
+#undef V8983
+#define V8983 (V + 34938)
+ 0x110d, 0x116d, 0x11bd, 0,
+#undef V8984
+#define V8984 (V + 34942)
+ 0x110d, 0x116d, 0x11be, 0,
+#undef V8985
+#define V8985 (V + 34946)
+ 0x110d, 0x116d, 0x11bf, 0,
+#undef V8986
+#define V8986 (V + 34950)
+ 0x110d, 0x116d, 0x11c0, 0,
+#undef V8987
+#define V8987 (V + 34954)
+ 0x110d, 0x116d, 0x11c1, 0,
+#undef V8988
+#define V8988 (V + 34958)
+ 0x110d, 0x116d, 0x11c2, 0,
+#undef V8989
+#define V8989 (V + 34962)
+ 0x110d, 0x116e, 0,
+#undef V8990
+#define V8990 (V + 34965)
+ 0x110d, 0x116e, 0x11a8, 0,
+#undef V8991
+#define V8991 (V + 34969)
+ 0x110d, 0x116e, 0x11a9, 0,
+#undef V8992
+#define V8992 (V + 34973)
+ 0x110d, 0x116e, 0x11aa, 0,
+#undef V8993
+#define V8993 (V + 34977)
+ 0x110d, 0x116e, 0x11ab, 0,
+#undef V8994
+#define V8994 (V + 34981)
+ 0x110d, 0x116e, 0x11ac, 0,
+#undef V8995
+#define V8995 (V + 34985)
+ 0x110d, 0x116e, 0x11ad, 0,
+#undef V8996
+#define V8996 (V + 34989)
+ 0x110d, 0x116e, 0x11ae, 0,
+#undef V8997
+#define V8997 (V + 34993)
+ 0x110d, 0x116e, 0x11af, 0,
+#undef V8998
+#define V8998 (V + 34997)
+ 0x110d, 0x116e, 0x11b0, 0,
+#undef V8999
+#define V8999 (V + 35001)
+ 0x110d, 0x116e, 0x11b1, 0,
+#undef V9000
+#define V9000 (V + 35005)
+ 0x110d, 0x116e, 0x11b2, 0,
+#undef V9001
+#define V9001 (V + 35009)
+ 0x110d, 0x116e, 0x11b3, 0,
+#undef V9002
+#define V9002 (V + 35013)
+ 0x110d, 0x116e, 0x11b4, 0,
+#undef V9003
+#define V9003 (V + 35017)
+ 0x110d, 0x116e, 0x11b5, 0,
+#undef V9004
+#define V9004 (V + 35021)
+ 0x110d, 0x116e, 0x11b6, 0,
+#undef V9005
+#define V9005 (V + 35025)
+ 0x110d, 0x116e, 0x11b7, 0,
+#undef V9006
+#define V9006 (V + 35029)
+ 0x110d, 0x116e, 0x11b8, 0,
+#undef V9007
+#define V9007 (V + 35033)
+ 0x110d, 0x116e, 0x11b9, 0,
+#undef V9008
+#define V9008 (V + 35037)
+ 0x110d, 0x116e, 0x11ba, 0,
+#undef V9009
+#define V9009 (V + 35041)
+ 0x110d, 0x116e, 0x11bb, 0,
+#undef V9010
+#define V9010 (V + 35045)
+ 0x110d, 0x116e, 0x11bc, 0,
+#undef V9011
+#define V9011 (V + 35049)
+ 0x110d, 0x116e, 0x11bd, 0,
+#undef V9012
+#define V9012 (V + 35053)
+ 0x110d, 0x116e, 0x11be, 0,
+#undef V9013
+#define V9013 (V + 35057)
+ 0x110d, 0x116e, 0x11bf, 0,
+#undef V9014
+#define V9014 (V + 35061)
+ 0x110d, 0x116e, 0x11c0, 0,
+#undef V9015
+#define V9015 (V + 35065)
+ 0x110d, 0x116e, 0x11c1, 0,
+#undef V9016
+#define V9016 (V + 35069)
+ 0x110d, 0x116e, 0x11c2, 0,
+#undef V9017
+#define V9017 (V + 35073)
+ 0x110d, 0x116f, 0,
+#undef V9018
+#define V9018 (V + 35076)
+ 0x110d, 0x116f, 0x11a8, 0,
+#undef V9019
+#define V9019 (V + 35080)
+ 0x110d, 0x116f, 0x11a9, 0,
+#undef V9020
+#define V9020 (V + 35084)
+ 0x110d, 0x116f, 0x11aa, 0,
+#undef V9021
+#define V9021 (V + 35088)
+ 0x110d, 0x116f, 0x11ab, 0,
+#undef V9022
+#define V9022 (V + 35092)
+ 0x110d, 0x116f, 0x11ac, 0,
+#undef V9023
+#define V9023 (V + 35096)
+ 0x110d, 0x116f, 0x11ad, 0,
+#undef V9024
+#define V9024 (V + 35100)
+ 0x110d, 0x116f, 0x11ae, 0,
+#undef V9025
+#define V9025 (V + 35104)
+ 0x110d, 0x116f, 0x11af, 0,
+#undef V9026
+#define V9026 (V + 35108)
+ 0x110d, 0x116f, 0x11b0, 0,
+#undef V9027
+#define V9027 (V + 35112)
+ 0x110d, 0x116f, 0x11b1, 0,
+#undef V9028
+#define V9028 (V + 35116)
+ 0x110d, 0x116f, 0x11b2, 0,
+#undef V9029
+#define V9029 (V + 35120)
+ 0x110d, 0x116f, 0x11b3, 0,
+#undef V9030
+#define V9030 (V + 35124)
+ 0x110d, 0x116f, 0x11b4, 0,
+#undef V9031
+#define V9031 (V + 35128)
+ 0x110d, 0x116f, 0x11b5, 0,
+#undef V9032
+#define V9032 (V + 35132)
+ 0x110d, 0x116f, 0x11b6, 0,
+#undef V9033
+#define V9033 (V + 35136)
+ 0x110d, 0x116f, 0x11b7, 0,
+#undef V9034
+#define V9034 (V + 35140)
+ 0x110d, 0x116f, 0x11b8, 0,
+#undef V9035
+#define V9035 (V + 35144)
+ 0x110d, 0x116f, 0x11b9, 0,
+#undef V9036
+#define V9036 (V + 35148)
+ 0x110d, 0x116f, 0x11ba, 0,
+#undef V9037
+#define V9037 (V + 35152)
+ 0x110d, 0x116f, 0x11bb, 0,
+#undef V9038
+#define V9038 (V + 35156)
+ 0x110d, 0x116f, 0x11bc, 0,
+#undef V9039
+#define V9039 (V + 35160)
+ 0x110d, 0x116f, 0x11bd, 0,
+#undef V9040
+#define V9040 (V + 35164)
+ 0x110d, 0x116f, 0x11be, 0,
+#undef V9041
+#define V9041 (V + 35168)
+ 0x110d, 0x116f, 0x11bf, 0,
+#undef V9042
+#define V9042 (V + 35172)
+ 0x110d, 0x116f, 0x11c0, 0,
+#undef V9043
+#define V9043 (V + 35176)
+ 0x110d, 0x116f, 0x11c1, 0,
+#undef V9044
+#define V9044 (V + 35180)
+ 0x110d, 0x116f, 0x11c2, 0,
+#undef V9045
+#define V9045 (V + 35184)
+ 0x110d, 0x1170, 0,
+#undef V9046
+#define V9046 (V + 35187)
+ 0x110d, 0x1170, 0x11a8, 0,
+#undef V9047
+#define V9047 (V + 35191)
+ 0x110d, 0x1170, 0x11a9, 0,
+#undef V9048
+#define V9048 (V + 35195)
+ 0x110d, 0x1170, 0x11aa, 0,
+#undef V9049
+#define V9049 (V + 35199)
+ 0x110d, 0x1170, 0x11ab, 0,
+#undef V9050
+#define V9050 (V + 35203)
+ 0x110d, 0x1170, 0x11ac, 0,
+#undef V9051
+#define V9051 (V + 35207)
+ 0x110d, 0x1170, 0x11ad, 0,
+#undef V9052
+#define V9052 (V + 35211)
+ 0x110d, 0x1170, 0x11ae, 0,
+#undef V9053
+#define V9053 (V + 35215)
+ 0x110d, 0x1170, 0x11af, 0,
+#undef V9054
+#define V9054 (V + 35219)
+ 0x110d, 0x1170, 0x11b0, 0,
+#undef V9055
+#define V9055 (V + 35223)
+ 0x110d, 0x1170, 0x11b1, 0,
+#undef V9056
+#define V9056 (V + 35227)
+ 0x110d, 0x1170, 0x11b2, 0,
+#undef V9057
+#define V9057 (V + 35231)
+ 0x110d, 0x1170, 0x11b3, 0,
+#undef V9058
+#define V9058 (V + 35235)
+ 0x110d, 0x1170, 0x11b4, 0,
+#undef V9059
+#define V9059 (V + 35239)
+ 0x110d, 0x1170, 0x11b5, 0,
+#undef V9060
+#define V9060 (V + 35243)
+ 0x110d, 0x1170, 0x11b6, 0,
+#undef V9061
+#define V9061 (V + 35247)
+ 0x110d, 0x1170, 0x11b7, 0,
+#undef V9062
+#define V9062 (V + 35251)
+ 0x110d, 0x1170, 0x11b8, 0,
+#undef V9063
+#define V9063 (V + 35255)
+ 0x110d, 0x1170, 0x11b9, 0,
+#undef V9064
+#define V9064 (V + 35259)
+ 0x110d, 0x1170, 0x11ba, 0,
+#undef V9065
+#define V9065 (V + 35263)
+ 0x110d, 0x1170, 0x11bb, 0,
+#undef V9066
+#define V9066 (V + 35267)
+ 0x110d, 0x1170, 0x11bc, 0,
+#undef V9067
+#define V9067 (V + 35271)
+ 0x110d, 0x1170, 0x11bd, 0,
+#undef V9068
+#define V9068 (V + 35275)
+ 0x110d, 0x1170, 0x11be, 0,
+#undef V9069
+#define V9069 (V + 35279)
+ 0x110d, 0x1170, 0x11bf, 0,
+#undef V9070
+#define V9070 (V + 35283)
+ 0x110d, 0x1170, 0x11c0, 0,
+#undef V9071
+#define V9071 (V + 35287)
+ 0x110d, 0x1170, 0x11c1, 0,
+#undef V9072
+#define V9072 (V + 35291)
+ 0x110d, 0x1170, 0x11c2, 0,
+#undef V9073
+#define V9073 (V + 35295)
+ 0x110d, 0x1171, 0,
+#undef V9074
+#define V9074 (V + 35298)
+ 0x110d, 0x1171, 0x11a8, 0,
+#undef V9075
+#define V9075 (V + 35302)
+ 0x110d, 0x1171, 0x11a9, 0,
+#undef V9076
+#define V9076 (V + 35306)
+ 0x110d, 0x1171, 0x11aa, 0,
+#undef V9077
+#define V9077 (V + 35310)
+ 0x110d, 0x1171, 0x11ab, 0,
+#undef V9078
+#define V9078 (V + 35314)
+ 0x110d, 0x1171, 0x11ac, 0,
+#undef V9079
+#define V9079 (V + 35318)
+ 0x110d, 0x1171, 0x11ad, 0,
+#undef V9080
+#define V9080 (V + 35322)
+ 0x110d, 0x1171, 0x11ae, 0,
+#undef V9081
+#define V9081 (V + 35326)
+ 0x110d, 0x1171, 0x11af, 0,
+#undef V9082
+#define V9082 (V + 35330)
+ 0x110d, 0x1171, 0x11b0, 0,
+#undef V9083
+#define V9083 (V + 35334)
+ 0x110d, 0x1171, 0x11b1, 0,
+#undef V9084
+#define V9084 (V + 35338)
+ 0x110d, 0x1171, 0x11b2, 0,
+#undef V9085
+#define V9085 (V + 35342)
+ 0x110d, 0x1171, 0x11b3, 0,
+#undef V9086
+#define V9086 (V + 35346)
+ 0x110d, 0x1171, 0x11b4, 0,
+#undef V9087
+#define V9087 (V + 35350)
+ 0x110d, 0x1171, 0x11b5, 0,
+#undef V9088
+#define V9088 (V + 35354)
+ 0x110d, 0x1171, 0x11b6, 0,
+#undef V9089
+#define V9089 (V + 35358)
+ 0x110d, 0x1171, 0x11b7, 0,
+#undef V9090
+#define V9090 (V + 35362)
+ 0x110d, 0x1171, 0x11b8, 0,
+#undef V9091
+#define V9091 (V + 35366)
+ 0x110d, 0x1171, 0x11b9, 0,
+#undef V9092
+#define V9092 (V + 35370)
+ 0x110d, 0x1171, 0x11ba, 0,
+#undef V9093
+#define V9093 (V + 35374)
+ 0x110d, 0x1171, 0x11bb, 0,
+#undef V9094
+#define V9094 (V + 35378)
+ 0x110d, 0x1171, 0x11bc, 0,
+#undef V9095
+#define V9095 (V + 35382)
+ 0x110d, 0x1171, 0x11bd, 0,
+#undef V9096
+#define V9096 (V + 35386)
+ 0x110d, 0x1171, 0x11be, 0,
+#undef V9097
+#define V9097 (V + 35390)
+ 0x110d, 0x1171, 0x11bf, 0,
+#undef V9098
+#define V9098 (V + 35394)
+ 0x110d, 0x1171, 0x11c0, 0,
+#undef V9099
+#define V9099 (V + 35398)
+ 0x110d, 0x1171, 0x11c1, 0,
+#undef V9100
+#define V9100 (V + 35402)
+ 0x110d, 0x1171, 0x11c2, 0,
+#undef V9101
+#define V9101 (V + 35406)
+ 0x110d, 0x1172, 0,
+#undef V9102
+#define V9102 (V + 35409)
+ 0x110d, 0x1172, 0x11a8, 0,
+#undef V9103
+#define V9103 (V + 35413)
+ 0x110d, 0x1172, 0x11a9, 0,
+#undef V9104
+#define V9104 (V + 35417)
+ 0x110d, 0x1172, 0x11aa, 0,
+#undef V9105
+#define V9105 (V + 35421)
+ 0x110d, 0x1172, 0x11ab, 0,
+#undef V9106
+#define V9106 (V + 35425)
+ 0x110d, 0x1172, 0x11ac, 0,
+#undef V9107
+#define V9107 (V + 35429)
+ 0x110d, 0x1172, 0x11ad, 0,
+#undef V9108
+#define V9108 (V + 35433)
+ 0x110d, 0x1172, 0x11ae, 0,
+#undef V9109
+#define V9109 (V + 35437)
+ 0x110d, 0x1172, 0x11af, 0,
+#undef V9110
+#define V9110 (V + 35441)
+ 0x110d, 0x1172, 0x11b0, 0,
+#undef V9111
+#define V9111 (V + 35445)
+ 0x110d, 0x1172, 0x11b1, 0,
+#undef V9112
+#define V9112 (V + 35449)
+ 0x110d, 0x1172, 0x11b2, 0,
+#undef V9113
+#define V9113 (V + 35453)
+ 0x110d, 0x1172, 0x11b3, 0,
+#undef V9114
+#define V9114 (V + 35457)
+ 0x110d, 0x1172, 0x11b4, 0,
+#undef V9115
+#define V9115 (V + 35461)
+ 0x110d, 0x1172, 0x11b5, 0,
+#undef V9116
+#define V9116 (V + 35465)
+ 0x110d, 0x1172, 0x11b6, 0,
+#undef V9117
+#define V9117 (V + 35469)
+ 0x110d, 0x1172, 0x11b7, 0,
+#undef V9118
+#define V9118 (V + 35473)
+ 0x110d, 0x1172, 0x11b8, 0,
+#undef V9119
+#define V9119 (V + 35477)
+ 0x110d, 0x1172, 0x11b9, 0,
+#undef V9120
+#define V9120 (V + 35481)
+ 0x110d, 0x1172, 0x11ba, 0,
+#undef V9121
+#define V9121 (V + 35485)
+ 0x110d, 0x1172, 0x11bb, 0,
+#undef V9122
+#define V9122 (V + 35489)
+ 0x110d, 0x1172, 0x11bc, 0,
+#undef V9123
+#define V9123 (V + 35493)
+ 0x110d, 0x1172, 0x11bd, 0,
+#undef V9124
+#define V9124 (V + 35497)
+ 0x110d, 0x1172, 0x11be, 0,
+#undef V9125
+#define V9125 (V + 35501)
+ 0x110d, 0x1172, 0x11bf, 0,
+#undef V9126
+#define V9126 (V + 35505)
+ 0x110d, 0x1172, 0x11c0, 0,
+#undef V9127
+#define V9127 (V + 35509)
+ 0x110d, 0x1172, 0x11c1, 0,
+#undef V9128
+#define V9128 (V + 35513)
+ 0x110d, 0x1172, 0x11c2, 0,
+#undef V9129
+#define V9129 (V + 35517)
+ 0x110d, 0x1173, 0,
+#undef V9130
+#define V9130 (V + 35520)
+ 0x110d, 0x1173, 0x11a8, 0,
+#undef V9131
+#define V9131 (V + 35524)
+ 0x110d, 0x1173, 0x11a9, 0,
+#undef V9132
+#define V9132 (V + 35528)
+ 0x110d, 0x1173, 0x11aa, 0,
+#undef V9133
+#define V9133 (V + 35532)
+ 0x110d, 0x1173, 0x11ab, 0,
+#undef V9134
+#define V9134 (V + 35536)
+ 0x110d, 0x1173, 0x11ac, 0,
+#undef V9135
+#define V9135 (V + 35540)
+ 0x110d, 0x1173, 0x11ad, 0,
+#undef V9136
+#define V9136 (V + 35544)
+ 0x110d, 0x1173, 0x11ae, 0,
+#undef V9137
+#define V9137 (V + 35548)
+ 0x110d, 0x1173, 0x11af, 0,
+#undef V9138
+#define V9138 (V + 35552)
+ 0x110d, 0x1173, 0x11b0, 0,
+#undef V9139
+#define V9139 (V + 35556)
+ 0x110d, 0x1173, 0x11b1, 0,
+#undef V9140
+#define V9140 (V + 35560)
+ 0x110d, 0x1173, 0x11b2, 0,
+#undef V9141
+#define V9141 (V + 35564)
+ 0x110d, 0x1173, 0x11b3, 0,
+#undef V9142
+#define V9142 (V + 35568)
+ 0x110d, 0x1173, 0x11b4, 0,
+#undef V9143
+#define V9143 (V + 35572)
+ 0x110d, 0x1173, 0x11b5, 0,
+#undef V9144
+#define V9144 (V + 35576)
+ 0x110d, 0x1173, 0x11b6, 0,
+#undef V9145
+#define V9145 (V + 35580)
+ 0x110d, 0x1173, 0x11b7, 0,
+#undef V9146
+#define V9146 (V + 35584)
+ 0x110d, 0x1173, 0x11b8, 0,
+#undef V9147
+#define V9147 (V + 35588)
+ 0x110d, 0x1173, 0x11b9, 0,
+#undef V9148
+#define V9148 (V + 35592)
+ 0x110d, 0x1173, 0x11ba, 0,
+#undef V9149
+#define V9149 (V + 35596)
+ 0x110d, 0x1173, 0x11bb, 0,
+#undef V9150
+#define V9150 (V + 35600)
+ 0x110d, 0x1173, 0x11bc, 0,
+#undef V9151
+#define V9151 (V + 35604)
+ 0x110d, 0x1173, 0x11bd, 0,
+#undef V9152
+#define V9152 (V + 35608)
+ 0x110d, 0x1173, 0x11be, 0,
+#undef V9153
+#define V9153 (V + 35612)
+ 0x110d, 0x1173, 0x11bf, 0,
+#undef V9154
+#define V9154 (V + 35616)
+ 0x110d, 0x1173, 0x11c0, 0,
+#undef V9155
+#define V9155 (V + 35620)
+ 0x110d, 0x1173, 0x11c1, 0,
+#undef V9156
+#define V9156 (V + 35624)
+ 0x110d, 0x1173, 0x11c2, 0,
+#undef V9157
+#define V9157 (V + 35628)
+ 0x110d, 0x1174, 0,
+#undef V9158
+#define V9158 (V + 35631)
+ 0x110d, 0x1174, 0x11a8, 0,
+#undef V9159
+#define V9159 (V + 35635)
+ 0x110d, 0x1174, 0x11a9, 0,
+#undef V9160
+#define V9160 (V + 35639)
+ 0x110d, 0x1174, 0x11aa, 0,
+#undef V9161
+#define V9161 (V + 35643)
+ 0x110d, 0x1174, 0x11ab, 0,
+#undef V9162
+#define V9162 (V + 35647)
+ 0x110d, 0x1174, 0x11ac, 0,
+#undef V9163
+#define V9163 (V + 35651)
+ 0x110d, 0x1174, 0x11ad, 0,
+#undef V9164
+#define V9164 (V + 35655)
+ 0x110d, 0x1174, 0x11ae, 0,
+#undef V9165
+#define V9165 (V + 35659)
+ 0x110d, 0x1174, 0x11af, 0,
+#undef V9166
+#define V9166 (V + 35663)
+ 0x110d, 0x1174, 0x11b0, 0,
+#undef V9167
+#define V9167 (V + 35667)
+ 0x110d, 0x1174, 0x11b1, 0,
+#undef V9168
+#define V9168 (V + 35671)
+ 0x110d, 0x1174, 0x11b2, 0,
+#undef V9169
+#define V9169 (V + 35675)
+ 0x110d, 0x1174, 0x11b3, 0,
+#undef V9170
+#define V9170 (V + 35679)
+ 0x110d, 0x1174, 0x11b4, 0,
+#undef V9171
+#define V9171 (V + 35683)
+ 0x110d, 0x1174, 0x11b5, 0,
+#undef V9172
+#define V9172 (V + 35687)
+ 0x110d, 0x1174, 0x11b6, 0,
+#undef V9173
+#define V9173 (V + 35691)
+ 0x110d, 0x1174, 0x11b7, 0,
+#undef V9174
+#define V9174 (V + 35695)
+ 0x110d, 0x1174, 0x11b8, 0,
+#undef V9175
+#define V9175 (V + 35699)
+ 0x110d, 0x1174, 0x11b9, 0,
+#undef V9176
+#define V9176 (V + 35703)
+ 0x110d, 0x1174, 0x11ba, 0,
+#undef V9177
+#define V9177 (V + 35707)
+ 0x110d, 0x1174, 0x11bb, 0,
+#undef V9178
+#define V9178 (V + 35711)
+ 0x110d, 0x1174, 0x11bc, 0,
+#undef V9179
+#define V9179 (V + 35715)
+ 0x110d, 0x1174, 0x11bd, 0,
+#undef V9180
+#define V9180 (V + 35719)
+ 0x110d, 0x1174, 0x11be, 0,
+#undef V9181
+#define V9181 (V + 35723)
+ 0x110d, 0x1174, 0x11bf, 0,
+#undef V9182
+#define V9182 (V + 35727)
+ 0x110d, 0x1174, 0x11c0, 0,
+#undef V9183
+#define V9183 (V + 35731)
+ 0x110d, 0x1174, 0x11c1, 0,
+#undef V9184
+#define V9184 (V + 35735)
+ 0x110d, 0x1174, 0x11c2, 0,
+#undef V9185
+#define V9185 (V + 35739)
+ 0x110d, 0x1175, 0,
+#undef V9186
+#define V9186 (V + 35742)
+ 0x110d, 0x1175, 0x11a8, 0,
+#undef V9187
+#define V9187 (V + 35746)
+ 0x110d, 0x1175, 0x11a9, 0,
+#undef V9188
+#define V9188 (V + 35750)
+ 0x110d, 0x1175, 0x11aa, 0,
+#undef V9189
+#define V9189 (V + 35754)
+ 0x110d, 0x1175, 0x11ab, 0,
+#undef V9190
+#define V9190 (V + 35758)
+ 0x110d, 0x1175, 0x11ac, 0,
+#undef V9191
+#define V9191 (V + 35762)
+ 0x110d, 0x1175, 0x11ad, 0,
+#undef V9192
+#define V9192 (V + 35766)
+ 0x110d, 0x1175, 0x11ae, 0,
+#undef V9193
+#define V9193 (V + 35770)
+ 0x110d, 0x1175, 0x11af, 0,
+#undef V9194
+#define V9194 (V + 35774)
+ 0x110d, 0x1175, 0x11b0, 0,
+#undef V9195
+#define V9195 (V + 35778)
+ 0x110d, 0x1175, 0x11b1, 0,
+#undef V9196
+#define V9196 (V + 35782)
+ 0x110d, 0x1175, 0x11b2, 0,
+#undef V9197
+#define V9197 (V + 35786)
+ 0x110d, 0x1175, 0x11b3, 0,
+#undef V9198
+#define V9198 (V + 35790)
+ 0x110d, 0x1175, 0x11b4, 0,
+#undef V9199
+#define V9199 (V + 35794)
+ 0x110d, 0x1175, 0x11b5, 0,
+#undef V9200
+#define V9200 (V + 35798)
+ 0x110d, 0x1175, 0x11b6, 0,
+#undef V9201
+#define V9201 (V + 35802)
+ 0x110d, 0x1175, 0x11b7, 0,
+#undef V9202
+#define V9202 (V + 35806)
+ 0x110d, 0x1175, 0x11b8, 0,
+#undef V9203
+#define V9203 (V + 35810)
+ 0x110d, 0x1175, 0x11b9, 0,
+#undef V9204
+#define V9204 (V + 35814)
+ 0x110d, 0x1175, 0x11ba, 0,
+#undef V9205
+#define V9205 (V + 35818)
+ 0x110d, 0x1175, 0x11bb, 0,
+#undef V9206
+#define V9206 (V + 35822)
+ 0x110d, 0x1175, 0x11bc, 0,
+#undef V9207
+#define V9207 (V + 35826)
+ 0x110d, 0x1175, 0x11bd, 0,
+#undef V9208
+#define V9208 (V + 35830)
+ 0x110d, 0x1175, 0x11be, 0,
+#undef V9209
+#define V9209 (V + 35834)
+ 0x110d, 0x1175, 0x11bf, 0,
+#undef V9210
+#define V9210 (V + 35838)
+ 0x110d, 0x1175, 0x11c0, 0,
+#undef V9211
+#define V9211 (V + 35842)
+ 0x110d, 0x1175, 0x11c1, 0,
+#undef V9212
+#define V9212 (V + 35846)
+ 0x110d, 0x1175, 0x11c2, 0,
+#undef V9213
+#define V9213 (V + 35850)
+ 0x110e, 0x1161, 0,
+#undef V9214
+#define V9214 (V + 35853)
+ 0x110e, 0x1161, 0x11a8, 0,
+#undef V9215
+#define V9215 (V + 35857)
+ 0x110e, 0x1161, 0x11a9, 0,
+#undef V9216
+#define V9216 (V + 35861)
+ 0x110e, 0x1161, 0x11aa, 0,
+#undef V9217
+#define V9217 (V + 35865)
+ 0x110e, 0x1161, 0x11ab, 0,
+#undef V9218
+#define V9218 (V + 35869)
+ 0x110e, 0x1161, 0x11ac, 0,
+#undef V9219
+#define V9219 (V + 35873)
+ 0x110e, 0x1161, 0x11ad, 0,
+#undef V9220
+#define V9220 (V + 35877)
+ 0x110e, 0x1161, 0x11ae, 0,
+#undef V9221
+#define V9221 (V + 35881)
+ 0x110e, 0x1161, 0x11af, 0,
+#undef V9222
+#define V9222 (V + 35885)
+ 0x110e, 0x1161, 0x11b0, 0,
+#undef V9223
+#define V9223 (V + 35889)
+ 0x110e, 0x1161, 0x11b1, 0,
+#undef V9224
+#define V9224 (V + 35893)
+ 0x110e, 0x1161, 0x11b2, 0,
+#undef V9225
+#define V9225 (V + 35897)
+ 0x110e, 0x1161, 0x11b3, 0,
+#undef V9226
+#define V9226 (V + 35901)
+ 0x110e, 0x1161, 0x11b4, 0,
+#undef V9227
+#define V9227 (V + 35905)
+ 0x110e, 0x1161, 0x11b5, 0,
+#undef V9228
+#define V9228 (V + 35909)
+ 0x110e, 0x1161, 0x11b6, 0,
+#undef V9229
+#define V9229 (V + 35913)
+ 0x110e, 0x1161, 0x11b7, 0,
+#undef V9230
+#define V9230 (V + 35917)
+ 0x110e, 0x1161, 0x11b8, 0,
+#undef V9231
+#define V9231 (V + 35921)
+ 0x110e, 0x1161, 0x11b9, 0,
+#undef V9232
+#define V9232 (V + 35925)
+ 0x110e, 0x1161, 0x11ba, 0,
+#undef V9233
+#define V9233 (V + 35929)
+ 0x110e, 0x1161, 0x11bb, 0,
+#undef V9234
+#define V9234 (V + 35933)
+ 0x110e, 0x1161, 0x11bc, 0,
+#undef V9235
+#define V9235 (V + 35937)
+ 0x110e, 0x1161, 0x11bd, 0,
+#undef V9236
+#define V9236 (V + 35941)
+ 0x110e, 0x1161, 0x11be, 0,
+#undef V9237
+#define V9237 (V + 35945)
+ 0x110e, 0x1161, 0x11bf, 0,
+#undef V9238
+#define V9238 (V + 35949)
+ 0x110e, 0x1161, 0x11c0, 0,
+#undef V9239
+#define V9239 (V + 35953)
+ 0x110e, 0x1161, 0x11c1, 0,
+#undef V9240
+#define V9240 (V + 35957)
+ 0x110e, 0x1161, 0x11c2, 0,
+#undef V9241
+#define V9241 (V + 35961)
+ 0x110e, 0x1162, 0,
+#undef V9242
+#define V9242 (V + 35964)
+ 0x110e, 0x1162, 0x11a8, 0,
+#undef V9243
+#define V9243 (V + 35968)
+ 0x110e, 0x1162, 0x11a9, 0,
+#undef V9244
+#define V9244 (V + 35972)
+ 0x110e, 0x1162, 0x11aa, 0,
+#undef V9245
+#define V9245 (V + 35976)
+ 0x110e, 0x1162, 0x11ab, 0,
+#undef V9246
+#define V9246 (V + 35980)
+ 0x110e, 0x1162, 0x11ac, 0,
+#undef V9247
+#define V9247 (V + 35984)
+ 0x110e, 0x1162, 0x11ad, 0,
+#undef V9248
+#define V9248 (V + 35988)
+ 0x110e, 0x1162, 0x11ae, 0,
+#undef V9249
+#define V9249 (V + 35992)
+ 0x110e, 0x1162, 0x11af, 0,
+#undef V9250
+#define V9250 (V + 35996)
+ 0x110e, 0x1162, 0x11b0, 0,
+#undef V9251
+#define V9251 (V + 36000)
+ 0x110e, 0x1162, 0x11b1, 0,
+#undef V9252
+#define V9252 (V + 36004)
+ 0x110e, 0x1162, 0x11b2, 0,
+#undef V9253
+#define V9253 (V + 36008)
+ 0x110e, 0x1162, 0x11b3, 0,
+#undef V9254
+#define V9254 (V + 36012)
+ 0x110e, 0x1162, 0x11b4, 0,
+#undef V9255
+#define V9255 (V + 36016)
+ 0x110e, 0x1162, 0x11b5, 0,
+#undef V9256
+#define V9256 (V + 36020)
+ 0x110e, 0x1162, 0x11b6, 0,
+#undef V9257
+#define V9257 (V + 36024)
+ 0x110e, 0x1162, 0x11b7, 0,
+#undef V9258
+#define V9258 (V + 36028)
+ 0x110e, 0x1162, 0x11b8, 0,
+#undef V9259
+#define V9259 (V + 36032)
+ 0x110e, 0x1162, 0x11b9, 0,
+#undef V9260
+#define V9260 (V + 36036)
+ 0x110e, 0x1162, 0x11ba, 0,
+#undef V9261
+#define V9261 (V + 36040)
+ 0x110e, 0x1162, 0x11bb, 0,
+#undef V9262
+#define V9262 (V + 36044)
+ 0x110e, 0x1162, 0x11bc, 0,
+#undef V9263
+#define V9263 (V + 36048)
+ 0x110e, 0x1162, 0x11bd, 0,
+#undef V9264
+#define V9264 (V + 36052)
+ 0x110e, 0x1162, 0x11be, 0,
+#undef V9265
+#define V9265 (V + 36056)
+ 0x110e, 0x1162, 0x11bf, 0,
+#undef V9266
+#define V9266 (V + 36060)
+ 0x110e, 0x1162, 0x11c0, 0,
+#undef V9267
+#define V9267 (V + 36064)
+ 0x110e, 0x1162, 0x11c1, 0,
+#undef V9268
+#define V9268 (V + 36068)
+ 0x110e, 0x1162, 0x11c2, 0,
+#undef V9269
+#define V9269 (V + 36072)
+ 0x110e, 0x1163, 0,
+#undef V9270
+#define V9270 (V + 36075)
+ 0x110e, 0x1163, 0x11a8, 0,
+#undef V9271
+#define V9271 (V + 36079)
+ 0x110e, 0x1163, 0x11a9, 0,
+#undef V9272
+#define V9272 (V + 36083)
+ 0x110e, 0x1163, 0x11aa, 0,
+#undef V9273
+#define V9273 (V + 36087)
+ 0x110e, 0x1163, 0x11ab, 0,
+#undef V9274
+#define V9274 (V + 36091)
+ 0x110e, 0x1163, 0x11ac, 0,
+#undef V9275
+#define V9275 (V + 36095)
+ 0x110e, 0x1163, 0x11ad, 0,
+#undef V9276
+#define V9276 (V + 36099)
+ 0x110e, 0x1163, 0x11ae, 0,
+#undef V9277
+#define V9277 (V + 36103)
+ 0x110e, 0x1163, 0x11af, 0,
+#undef V9278
+#define V9278 (V + 36107)
+ 0x110e, 0x1163, 0x11b0, 0,
+#undef V9279
+#define V9279 (V + 36111)
+ 0x110e, 0x1163, 0x11b1, 0,
+#undef V9280
+#define V9280 (V + 36115)
+ 0x110e, 0x1163, 0x11b2, 0,
+#undef V9281
+#define V9281 (V + 36119)
+ 0x110e, 0x1163, 0x11b3, 0,
+#undef V9282
+#define V9282 (V + 36123)
+ 0x110e, 0x1163, 0x11b4, 0,
+#undef V9283
+#define V9283 (V + 36127)
+ 0x110e, 0x1163, 0x11b5, 0,
+#undef V9284
+#define V9284 (V + 36131)
+ 0x110e, 0x1163, 0x11b6, 0,
+#undef V9285
+#define V9285 (V + 36135)
+ 0x110e, 0x1163, 0x11b7, 0,
+#undef V9286
+#define V9286 (V + 36139)
+ 0x110e, 0x1163, 0x11b8, 0,
+#undef V9287
+#define V9287 (V + 36143)
+ 0x110e, 0x1163, 0x11b9, 0,
+#undef V9288
+#define V9288 (V + 36147)
+ 0x110e, 0x1163, 0x11ba, 0,
+#undef V9289
+#define V9289 (V + 36151)
+ 0x110e, 0x1163, 0x11bb, 0,
+#undef V9290
+#define V9290 (V + 36155)
+ 0x110e, 0x1163, 0x11bc, 0,
+#undef V9291
+#define V9291 (V + 36159)
+ 0x110e, 0x1163, 0x11bd, 0,
+#undef V9292
+#define V9292 (V + 36163)
+ 0x110e, 0x1163, 0x11be, 0,
+#undef V9293
+#define V9293 (V + 36167)
+ 0x110e, 0x1163, 0x11bf, 0,
+#undef V9294
+#define V9294 (V + 36171)
+ 0x110e, 0x1163, 0x11c0, 0,
+#undef V9295
+#define V9295 (V + 36175)
+ 0x110e, 0x1163, 0x11c1, 0,
+#undef V9296
+#define V9296 (V + 36179)
+ 0x110e, 0x1163, 0x11c2, 0,
+#undef V9297
+#define V9297 (V + 36183)
+ 0x110e, 0x1164, 0,
+#undef V9298
+#define V9298 (V + 36186)
+ 0x110e, 0x1164, 0x11a8, 0,
+#undef V9299
+#define V9299 (V + 36190)
+ 0x110e, 0x1164, 0x11a9, 0,
+#undef V9300
+#define V9300 (V + 36194)
+ 0x110e, 0x1164, 0x11aa, 0,
+#undef V9301
+#define V9301 (V + 36198)
+ 0x110e, 0x1164, 0x11ab, 0,
+#undef V9302
+#define V9302 (V + 36202)
+ 0x110e, 0x1164, 0x11ac, 0,
+#undef V9303
+#define V9303 (V + 36206)
+ 0x110e, 0x1164, 0x11ad, 0,
+#undef V9304
+#define V9304 (V + 36210)
+ 0x110e, 0x1164, 0x11ae, 0,
+#undef V9305
+#define V9305 (V + 36214)
+ 0x110e, 0x1164, 0x11af, 0,
+#undef V9306
+#define V9306 (V + 36218)
+ 0x110e, 0x1164, 0x11b0, 0,
+#undef V9307
+#define V9307 (V + 36222)
+ 0x110e, 0x1164, 0x11b1, 0,
+#undef V9308
+#define V9308 (V + 36226)
+ 0x110e, 0x1164, 0x11b2, 0,
+#undef V9309
+#define V9309 (V + 36230)
+ 0x110e, 0x1164, 0x11b3, 0,
+#undef V9310
+#define V9310 (V + 36234)
+ 0x110e, 0x1164, 0x11b4, 0,
+#undef V9311
+#define V9311 (V + 36238)
+ 0x110e, 0x1164, 0x11b5, 0,
+#undef V9312
+#define V9312 (V + 36242)
+ 0x110e, 0x1164, 0x11b6, 0,
+#undef V9313
+#define V9313 (V + 36246)
+ 0x110e, 0x1164, 0x11b7, 0,
+#undef V9314
+#define V9314 (V + 36250)
+ 0x110e, 0x1164, 0x11b8, 0,
+#undef V9315
+#define V9315 (V + 36254)
+ 0x110e, 0x1164, 0x11b9, 0,
+#undef V9316
+#define V9316 (V + 36258)
+ 0x110e, 0x1164, 0x11ba, 0,
+#undef V9317
+#define V9317 (V + 36262)
+ 0x110e, 0x1164, 0x11bb, 0,
+#undef V9318
+#define V9318 (V + 36266)
+ 0x110e, 0x1164, 0x11bc, 0,
+#undef V9319
+#define V9319 (V + 36270)
+ 0x110e, 0x1164, 0x11bd, 0,
+#undef V9320
+#define V9320 (V + 36274)
+ 0x110e, 0x1164, 0x11be, 0,
+#undef V9321
+#define V9321 (V + 36278)
+ 0x110e, 0x1164, 0x11bf, 0,
+#undef V9322
+#define V9322 (V + 36282)
+ 0x110e, 0x1164, 0x11c0, 0,
+#undef V9323
+#define V9323 (V + 36286)
+ 0x110e, 0x1164, 0x11c1, 0,
+#undef V9324
+#define V9324 (V + 36290)
+ 0x110e, 0x1164, 0x11c2, 0,
+#undef V9325
+#define V9325 (V + 36294)
+ 0x110e, 0x1165, 0,
+#undef V9326
+#define V9326 (V + 36297)
+ 0x110e, 0x1165, 0x11a8, 0,
+#undef V9327
+#define V9327 (V + 36301)
+ 0x110e, 0x1165, 0x11a9, 0,
+#undef V9328
+#define V9328 (V + 36305)
+ 0x110e, 0x1165, 0x11aa, 0,
+#undef V9329
+#define V9329 (V + 36309)
+ 0x110e, 0x1165, 0x11ab, 0,
+#undef V9330
+#define V9330 (V + 36313)
+ 0x110e, 0x1165, 0x11ac, 0,
+#undef V9331
+#define V9331 (V + 36317)
+ 0x110e, 0x1165, 0x11ad, 0,
+#undef V9332
+#define V9332 (V + 36321)
+ 0x110e, 0x1165, 0x11ae, 0,
+#undef V9333
+#define V9333 (V + 36325)
+ 0x110e, 0x1165, 0x11af, 0,
+#undef V9334
+#define V9334 (V + 36329)
+ 0x110e, 0x1165, 0x11b0, 0,
+#undef V9335
+#define V9335 (V + 36333)
+ 0x110e, 0x1165, 0x11b1, 0,
+#undef V9336
+#define V9336 (V + 36337)
+ 0x110e, 0x1165, 0x11b2, 0,
+#undef V9337
+#define V9337 (V + 36341)
+ 0x110e, 0x1165, 0x11b3, 0,
+#undef V9338
+#define V9338 (V + 36345)
+ 0x110e, 0x1165, 0x11b4, 0,
+#undef V9339
+#define V9339 (V + 36349)
+ 0x110e, 0x1165, 0x11b5, 0,
+#undef V9340
+#define V9340 (V + 36353)
+ 0x110e, 0x1165, 0x11b6, 0,
+#undef V9341
+#define V9341 (V + 36357)
+ 0x110e, 0x1165, 0x11b7, 0,
+#undef V9342
+#define V9342 (V + 36361)
+ 0x110e, 0x1165, 0x11b8, 0,
+#undef V9343
+#define V9343 (V + 36365)
+ 0x110e, 0x1165, 0x11b9, 0,
+#undef V9344
+#define V9344 (V + 36369)
+ 0x110e, 0x1165, 0x11ba, 0,
+#undef V9345
+#define V9345 (V + 36373)
+ 0x110e, 0x1165, 0x11bb, 0,
+#undef V9346
+#define V9346 (V + 36377)
+ 0x110e, 0x1165, 0x11bc, 0,
+#undef V9347
+#define V9347 (V + 36381)
+ 0x110e, 0x1165, 0x11bd, 0,
+#undef V9348
+#define V9348 (V + 36385)
+ 0x110e, 0x1165, 0x11be, 0,
+#undef V9349
+#define V9349 (V + 36389)
+ 0x110e, 0x1165, 0x11bf, 0,
+#undef V9350
+#define V9350 (V + 36393)
+ 0x110e, 0x1165, 0x11c0, 0,
+#undef V9351
+#define V9351 (V + 36397)
+ 0x110e, 0x1165, 0x11c1, 0,
+#undef V9352
+#define V9352 (V + 36401)
+ 0x110e, 0x1165, 0x11c2, 0,
+#undef V9353
+#define V9353 (V + 36405)
+ 0x110e, 0x1166, 0,
+#undef V9354
+#define V9354 (V + 36408)
+ 0x110e, 0x1166, 0x11a8, 0,
+#undef V9355
+#define V9355 (V + 36412)
+ 0x110e, 0x1166, 0x11a9, 0,
+#undef V9356
+#define V9356 (V + 36416)
+ 0x110e, 0x1166, 0x11aa, 0,
+#undef V9357
+#define V9357 (V + 36420)
+ 0x110e, 0x1166, 0x11ab, 0,
+#undef V9358
+#define V9358 (V + 36424)
+ 0x110e, 0x1166, 0x11ac, 0,
+#undef V9359
+#define V9359 (V + 36428)
+ 0x110e, 0x1166, 0x11ad, 0,
+#undef V9360
+#define V9360 (V + 36432)
+ 0x110e, 0x1166, 0x11ae, 0,
+#undef V9361
+#define V9361 (V + 36436)
+ 0x110e, 0x1166, 0x11af, 0,
+#undef V9362
+#define V9362 (V + 36440)
+ 0x110e, 0x1166, 0x11b0, 0,
+#undef V9363
+#define V9363 (V + 36444)
+ 0x110e, 0x1166, 0x11b1, 0,
+#undef V9364
+#define V9364 (V + 36448)
+ 0x110e, 0x1166, 0x11b2, 0,
+#undef V9365
+#define V9365 (V + 36452)
+ 0x110e, 0x1166, 0x11b3, 0,
+#undef V9366
+#define V9366 (V + 36456)
+ 0x110e, 0x1166, 0x11b4, 0,
+#undef V9367
+#define V9367 (V + 36460)
+ 0x110e, 0x1166, 0x11b5, 0,
+#undef V9368
+#define V9368 (V + 36464)
+ 0x110e, 0x1166, 0x11b6, 0,
+#undef V9369
+#define V9369 (V + 36468)
+ 0x110e, 0x1166, 0x11b7, 0,
+#undef V9370
+#define V9370 (V + 36472)
+ 0x110e, 0x1166, 0x11b8, 0,
+#undef V9371
+#define V9371 (V + 36476)
+ 0x110e, 0x1166, 0x11b9, 0,
+#undef V9372
+#define V9372 (V + 36480)
+ 0x110e, 0x1166, 0x11ba, 0,
+#undef V9373
+#define V9373 (V + 36484)
+ 0x110e, 0x1166, 0x11bb, 0,
+#undef V9374
+#define V9374 (V + 36488)
+ 0x110e, 0x1166, 0x11bc, 0,
+#undef V9375
+#define V9375 (V + 36492)
+ 0x110e, 0x1166, 0x11bd, 0,
+#undef V9376
+#define V9376 (V + 36496)
+ 0x110e, 0x1166, 0x11be, 0,
+#undef V9377
+#define V9377 (V + 36500)
+ 0x110e, 0x1166, 0x11bf, 0,
+#undef V9378
+#define V9378 (V + 36504)
+ 0x110e, 0x1166, 0x11c0, 0,
+#undef V9379
+#define V9379 (V + 36508)
+ 0x110e, 0x1166, 0x11c1, 0,
+#undef V9380
+#define V9380 (V + 36512)
+ 0x110e, 0x1166, 0x11c2, 0,
+#undef V9381
+#define V9381 (V + 36516)
+ 0x110e, 0x1167, 0,
+#undef V9382
+#define V9382 (V + 36519)
+ 0x110e, 0x1167, 0x11a8, 0,
+#undef V9383
+#define V9383 (V + 36523)
+ 0x110e, 0x1167, 0x11a9, 0,
+#undef V9384
+#define V9384 (V + 36527)
+ 0x110e, 0x1167, 0x11aa, 0,
+#undef V9385
+#define V9385 (V + 36531)
+ 0x110e, 0x1167, 0x11ab, 0,
+#undef V9386
+#define V9386 (V + 36535)
+ 0x110e, 0x1167, 0x11ac, 0,
+#undef V9387
+#define V9387 (V + 36539)
+ 0x110e, 0x1167, 0x11ad, 0,
+#undef V9388
+#define V9388 (V + 36543)
+ 0x110e, 0x1167, 0x11ae, 0,
+#undef V9389
+#define V9389 (V + 36547)
+ 0x110e, 0x1167, 0x11af, 0,
+#undef V9390
+#define V9390 (V + 36551)
+ 0x110e, 0x1167, 0x11b0, 0,
+#undef V9391
+#define V9391 (V + 36555)
+ 0x110e, 0x1167, 0x11b1, 0,
+#undef V9392
+#define V9392 (V + 36559)
+ 0x110e, 0x1167, 0x11b2, 0,
+#undef V9393
+#define V9393 (V + 36563)
+ 0x110e, 0x1167, 0x11b3, 0,
+#undef V9394
+#define V9394 (V + 36567)
+ 0x110e, 0x1167, 0x11b4, 0,
+#undef V9395
+#define V9395 (V + 36571)
+ 0x110e, 0x1167, 0x11b5, 0,
+#undef V9396
+#define V9396 (V + 36575)
+ 0x110e, 0x1167, 0x11b6, 0,
+#undef V9397
+#define V9397 (V + 36579)
+ 0x110e, 0x1167, 0x11b7, 0,
+#undef V9398
+#define V9398 (V + 36583)
+ 0x110e, 0x1167, 0x11b8, 0,
+#undef V9399
+#define V9399 (V + 36587)
+ 0x110e, 0x1167, 0x11b9, 0,
+#undef V9400
+#define V9400 (V + 36591)
+ 0x110e, 0x1167, 0x11ba, 0,
+#undef V9401
+#define V9401 (V + 36595)
+ 0x110e, 0x1167, 0x11bb, 0,
+#undef V9402
+#define V9402 (V + 36599)
+ 0x110e, 0x1167, 0x11bc, 0,
+#undef V9403
+#define V9403 (V + 36603)
+ 0x110e, 0x1167, 0x11bd, 0,
+#undef V9404
+#define V9404 (V + 36607)
+ 0x110e, 0x1167, 0x11be, 0,
+#undef V9405
+#define V9405 (V + 36611)
+ 0x110e, 0x1167, 0x11bf, 0,
+#undef V9406
+#define V9406 (V + 36615)
+ 0x110e, 0x1167, 0x11c0, 0,
+#undef V9407
+#define V9407 (V + 36619)
+ 0x110e, 0x1167, 0x11c1, 0,
+#undef V9408
+#define V9408 (V + 36623)
+ 0x110e, 0x1167, 0x11c2, 0,
+#undef V9409
+#define V9409 (V + 36627)
+ 0x110e, 0x1168, 0,
+#undef V9410
+#define V9410 (V + 36630)
+ 0x110e, 0x1168, 0x11a8, 0,
+#undef V9411
+#define V9411 (V + 36634)
+ 0x110e, 0x1168, 0x11a9, 0,
+#undef V9412
+#define V9412 (V + 36638)
+ 0x110e, 0x1168, 0x11aa, 0,
+#undef V9413
+#define V9413 (V + 36642)
+ 0x110e, 0x1168, 0x11ab, 0,
+#undef V9414
+#define V9414 (V + 36646)
+ 0x110e, 0x1168, 0x11ac, 0,
+#undef V9415
+#define V9415 (V + 36650)
+ 0x110e, 0x1168, 0x11ad, 0,
+#undef V9416
+#define V9416 (V + 36654)
+ 0x110e, 0x1168, 0x11ae, 0,
+#undef V9417
+#define V9417 (V + 36658)
+ 0x110e, 0x1168, 0x11af, 0,
+#undef V9418
+#define V9418 (V + 36662)
+ 0x110e, 0x1168, 0x11b0, 0,
+#undef V9419
+#define V9419 (V + 36666)
+ 0x110e, 0x1168, 0x11b1, 0,
+#undef V9420
+#define V9420 (V + 36670)
+ 0x110e, 0x1168, 0x11b2, 0,
+#undef V9421
+#define V9421 (V + 36674)
+ 0x110e, 0x1168, 0x11b3, 0,
+#undef V9422
+#define V9422 (V + 36678)
+ 0x110e, 0x1168, 0x11b4, 0,
+#undef V9423
+#define V9423 (V + 36682)
+ 0x110e, 0x1168, 0x11b5, 0,
+#undef V9424
+#define V9424 (V + 36686)
+ 0x110e, 0x1168, 0x11b6, 0,
+#undef V9425
+#define V9425 (V + 36690)
+ 0x110e, 0x1168, 0x11b7, 0,
+#undef V9426
+#define V9426 (V + 36694)
+ 0x110e, 0x1168, 0x11b8, 0,
+#undef V9427
+#define V9427 (V + 36698)
+ 0x110e, 0x1168, 0x11b9, 0,
+#undef V9428
+#define V9428 (V + 36702)
+ 0x110e, 0x1168, 0x11ba, 0,
+#undef V9429
+#define V9429 (V + 36706)
+ 0x110e, 0x1168, 0x11bb, 0,
+#undef V9430
+#define V9430 (V + 36710)
+ 0x110e, 0x1168, 0x11bc, 0,
+#undef V9431
+#define V9431 (V + 36714)
+ 0x110e, 0x1168, 0x11bd, 0,
+#undef V9432
+#define V9432 (V + 36718)
+ 0x110e, 0x1168, 0x11be, 0,
+#undef V9433
+#define V9433 (V + 36722)
+ 0x110e, 0x1168, 0x11bf, 0,
+#undef V9434
+#define V9434 (V + 36726)
+ 0x110e, 0x1168, 0x11c0, 0,
+#undef V9435
+#define V9435 (V + 36730)
+ 0x110e, 0x1168, 0x11c1, 0,
+#undef V9436
+#define V9436 (V + 36734)
+ 0x110e, 0x1168, 0x11c2, 0,
+#undef V9437
+#define V9437 (V + 36738)
+ 0x110e, 0x1169, 0,
+#undef V9438
+#define V9438 (V + 36741)
+ 0x110e, 0x1169, 0x11a8, 0,
+#undef V9439
+#define V9439 (V + 36745)
+ 0x110e, 0x1169, 0x11a9, 0,
+#undef V9440
+#define V9440 (V + 36749)
+ 0x110e, 0x1169, 0x11aa, 0,
+#undef V9441
+#define V9441 (V + 36753)
+ 0x110e, 0x1169, 0x11ab, 0,
+#undef V9442
+#define V9442 (V + 36757)
+ 0x110e, 0x1169, 0x11ac, 0,
+#undef V9443
+#define V9443 (V + 36761)
+ 0x110e, 0x1169, 0x11ad, 0,
+#undef V9444
+#define V9444 (V + 36765)
+ 0x110e, 0x1169, 0x11ae, 0,
+#undef V9445
+#define V9445 (V + 36769)
+ 0x110e, 0x1169, 0x11af, 0,
+#undef V9446
+#define V9446 (V + 36773)
+ 0x110e, 0x1169, 0x11b0, 0,
+#undef V9447
+#define V9447 (V + 36777)
+ 0x110e, 0x1169, 0x11b1, 0,
+#undef V9448
+#define V9448 (V + 36781)
+ 0x110e, 0x1169, 0x11b2, 0,
+#undef V9449
+#define V9449 (V + 36785)
+ 0x110e, 0x1169, 0x11b3, 0,
+#undef V9450
+#define V9450 (V + 36789)
+ 0x110e, 0x1169, 0x11b4, 0,
+#undef V9451
+#define V9451 (V + 36793)
+ 0x110e, 0x1169, 0x11b5, 0,
+#undef V9452
+#define V9452 (V + 36797)
+ 0x110e, 0x1169, 0x11b6, 0,
+#undef V9453
+#define V9453 (V + 36801)
+ 0x110e, 0x1169, 0x11b7, 0,
+#undef V9454
+#define V9454 (V + 36805)
+ 0x110e, 0x1169, 0x11b8, 0,
+#undef V9455
+#define V9455 (V + 36809)
+ 0x110e, 0x1169, 0x11b9, 0,
+#undef V9456
+#define V9456 (V + 36813)
+ 0x110e, 0x1169, 0x11ba, 0,
+#undef V9457
+#define V9457 (V + 36817)
+ 0x110e, 0x1169, 0x11bb, 0,
+#undef V9458
+#define V9458 (V + 36821)
+ 0x110e, 0x1169, 0x11bc, 0,
+#undef V9459
+#define V9459 (V + 36825)
+ 0x110e, 0x1169, 0x11bd, 0,
+#undef V9460
+#define V9460 (V + 36829)
+ 0x110e, 0x1169, 0x11be, 0,
+#undef V9461
+#define V9461 (V + 36833)
+ 0x110e, 0x1169, 0x11bf, 0,
+#undef V9462
+#define V9462 (V + 36837)
+ 0x110e, 0x1169, 0x11c0, 0,
+#undef V9463
+#define V9463 (V + 36841)
+ 0x110e, 0x1169, 0x11c1, 0,
+#undef V9464
+#define V9464 (V + 36845)
+ 0x110e, 0x1169, 0x11c2, 0,
+#undef V9465
+#define V9465 (V + 36849)
+ 0x110e, 0x116a, 0,
+#undef V9466
+#define V9466 (V + 36852)
+ 0x110e, 0x116a, 0x11a8, 0,
+#undef V9467
+#define V9467 (V + 36856)
+ 0x110e, 0x116a, 0x11a9, 0,
+#undef V9468
+#define V9468 (V + 36860)
+ 0x110e, 0x116a, 0x11aa, 0,
+#undef V9469
+#define V9469 (V + 36864)
+ 0x110e, 0x116a, 0x11ab, 0,
+#undef V9470
+#define V9470 (V + 36868)
+ 0x110e, 0x116a, 0x11ac, 0,
+#undef V9471
+#define V9471 (V + 36872)
+ 0x110e, 0x116a, 0x11ad, 0,
+#undef V9472
+#define V9472 (V + 36876)
+ 0x110e, 0x116a, 0x11ae, 0,
+#undef V9473
+#define V9473 (V + 36880)
+ 0x110e, 0x116a, 0x11af, 0,
+#undef V9474
+#define V9474 (V + 36884)
+ 0x110e, 0x116a, 0x11b0, 0,
+#undef V9475
+#define V9475 (V + 36888)
+ 0x110e, 0x116a, 0x11b1, 0,
+#undef V9476
+#define V9476 (V + 36892)
+ 0x110e, 0x116a, 0x11b2, 0,
+#undef V9477
+#define V9477 (V + 36896)
+ 0x110e, 0x116a, 0x11b3, 0,
+#undef V9478
+#define V9478 (V + 36900)
+ 0x110e, 0x116a, 0x11b4, 0,
+#undef V9479
+#define V9479 (V + 36904)
+ 0x110e, 0x116a, 0x11b5, 0,
+#undef V9480
+#define V9480 (V + 36908)
+ 0x110e, 0x116a, 0x11b6, 0,
+#undef V9481
+#define V9481 (V + 36912)
+ 0x110e, 0x116a, 0x11b7, 0,
+#undef V9482
+#define V9482 (V + 36916)
+ 0x110e, 0x116a, 0x11b8, 0,
+#undef V9483
+#define V9483 (V + 36920)
+ 0x110e, 0x116a, 0x11b9, 0,
+#undef V9484
+#define V9484 (V + 36924)
+ 0x110e, 0x116a, 0x11ba, 0,
+#undef V9485
+#define V9485 (V + 36928)
+ 0x110e, 0x116a, 0x11bb, 0,
+#undef V9486
+#define V9486 (V + 36932)
+ 0x110e, 0x116a, 0x11bc, 0,
+#undef V9487
+#define V9487 (V + 36936)
+ 0x110e, 0x116a, 0x11bd, 0,
+#undef V9488
+#define V9488 (V + 36940)
+ 0x110e, 0x116a, 0x11be, 0,
+#undef V9489
+#define V9489 (V + 36944)
+ 0x110e, 0x116a, 0x11bf, 0,
+#undef V9490
+#define V9490 (V + 36948)
+ 0x110e, 0x116a, 0x11c0, 0,
+#undef V9491
+#define V9491 (V + 36952)
+ 0x110e, 0x116a, 0x11c1, 0,
+#undef V9492
+#define V9492 (V + 36956)
+ 0x110e, 0x116a, 0x11c2, 0,
+#undef V9493
+#define V9493 (V + 36960)
+ 0x110e, 0x116b, 0,
+#undef V9494
+#define V9494 (V + 36963)
+ 0x110e, 0x116b, 0x11a8, 0,
+#undef V9495
+#define V9495 (V + 36967)
+ 0x110e, 0x116b, 0x11a9, 0,
+#undef V9496
+#define V9496 (V + 36971)
+ 0x110e, 0x116b, 0x11aa, 0,
+#undef V9497
+#define V9497 (V + 36975)
+ 0x110e, 0x116b, 0x11ab, 0,
+#undef V9498
+#define V9498 (V + 36979)
+ 0x110e, 0x116b, 0x11ac, 0,
+#undef V9499
+#define V9499 (V + 36983)
+ 0x110e, 0x116b, 0x11ad, 0,
+#undef V9500
+#define V9500 (V + 36987)
+ 0x110e, 0x116b, 0x11ae, 0,
+#undef V9501
+#define V9501 (V + 36991)
+ 0x110e, 0x116b, 0x11af, 0,
+#undef V9502
+#define V9502 (V + 36995)
+ 0x110e, 0x116b, 0x11b0, 0,
+#undef V9503
+#define V9503 (V + 36999)
+ 0x110e, 0x116b, 0x11b1, 0,
+#undef V9504
+#define V9504 (V + 37003)
+ 0x110e, 0x116b, 0x11b2, 0,
+#undef V9505
+#define V9505 (V + 37007)
+ 0x110e, 0x116b, 0x11b3, 0,
+#undef V9506
+#define V9506 (V + 37011)
+ 0x110e, 0x116b, 0x11b4, 0,
+#undef V9507
+#define V9507 (V + 37015)
+ 0x110e, 0x116b, 0x11b5, 0,
+#undef V9508
+#define V9508 (V + 37019)
+ 0x110e, 0x116b, 0x11b6, 0,
+#undef V9509
+#define V9509 (V + 37023)
+ 0x110e, 0x116b, 0x11b7, 0,
+#undef V9510
+#define V9510 (V + 37027)
+ 0x110e, 0x116b, 0x11b8, 0,
+#undef V9511
+#define V9511 (V + 37031)
+ 0x110e, 0x116b, 0x11b9, 0,
+#undef V9512
+#define V9512 (V + 37035)
+ 0x110e, 0x116b, 0x11ba, 0,
+#undef V9513
+#define V9513 (V + 37039)
+ 0x110e, 0x116b, 0x11bb, 0,
+#undef V9514
+#define V9514 (V + 37043)
+ 0x110e, 0x116b, 0x11bc, 0,
+#undef V9515
+#define V9515 (V + 37047)
+ 0x110e, 0x116b, 0x11bd, 0,
+#undef V9516
+#define V9516 (V + 37051)
+ 0x110e, 0x116b, 0x11be, 0,
+#undef V9517
+#define V9517 (V + 37055)
+ 0x110e, 0x116b, 0x11bf, 0,
+#undef V9518
+#define V9518 (V + 37059)
+ 0x110e, 0x116b, 0x11c0, 0,
+#undef V9519
+#define V9519 (V + 37063)
+ 0x110e, 0x116b, 0x11c1, 0,
+#undef V9520
+#define V9520 (V + 37067)
+ 0x110e, 0x116b, 0x11c2, 0,
+#undef V9521
+#define V9521 (V + 37071)
+ 0x110e, 0x116c, 0,
+#undef V9522
+#define V9522 (V + 37074)
+ 0x110e, 0x116c, 0x11a8, 0,
+#undef V9523
+#define V9523 (V + 37078)
+ 0x110e, 0x116c, 0x11a9, 0,
+#undef V9524
+#define V9524 (V + 37082)
+ 0x110e, 0x116c, 0x11aa, 0,
+#undef V9525
+#define V9525 (V + 37086)
+ 0x110e, 0x116c, 0x11ab, 0,
+#undef V9526
+#define V9526 (V + 37090)
+ 0x110e, 0x116c, 0x11ac, 0,
+#undef V9527
+#define V9527 (V + 37094)
+ 0x110e, 0x116c, 0x11ad, 0,
+#undef V9528
+#define V9528 (V + 37098)
+ 0x110e, 0x116c, 0x11ae, 0,
+#undef V9529
+#define V9529 (V + 37102)
+ 0x110e, 0x116c, 0x11af, 0,
+#undef V9530
+#define V9530 (V + 37106)
+ 0x110e, 0x116c, 0x11b0, 0,
+#undef V9531
+#define V9531 (V + 37110)
+ 0x110e, 0x116c, 0x11b1, 0,
+#undef V9532
+#define V9532 (V + 37114)
+ 0x110e, 0x116c, 0x11b2, 0,
+#undef V9533
+#define V9533 (V + 37118)
+ 0x110e, 0x116c, 0x11b3, 0,
+#undef V9534
+#define V9534 (V + 37122)
+ 0x110e, 0x116c, 0x11b4, 0,
+#undef V9535
+#define V9535 (V + 37126)
+ 0x110e, 0x116c, 0x11b5, 0,
+#undef V9536
+#define V9536 (V + 37130)
+ 0x110e, 0x116c, 0x11b6, 0,
+#undef V9537
+#define V9537 (V + 37134)
+ 0x110e, 0x116c, 0x11b7, 0,
+#undef V9538
+#define V9538 (V + 37138)
+ 0x110e, 0x116c, 0x11b8, 0,
+#undef V9539
+#define V9539 (V + 37142)
+ 0x110e, 0x116c, 0x11b9, 0,
+#undef V9540
+#define V9540 (V + 37146)
+ 0x110e, 0x116c, 0x11ba, 0,
+#undef V9541
+#define V9541 (V + 37150)
+ 0x110e, 0x116c, 0x11bb, 0,
+#undef V9542
+#define V9542 (V + 37154)
+ 0x110e, 0x116c, 0x11bc, 0,
+#undef V9543
+#define V9543 (V + 37158)
+ 0x110e, 0x116c, 0x11bd, 0,
+#undef V9544
+#define V9544 (V + 37162)
+ 0x110e, 0x116c, 0x11be, 0,
+#undef V9545
+#define V9545 (V + 37166)
+ 0x110e, 0x116c, 0x11bf, 0,
+#undef V9546
+#define V9546 (V + 37170)
+ 0x110e, 0x116c, 0x11c0, 0,
+#undef V9547
+#define V9547 (V + 37174)
+ 0x110e, 0x116c, 0x11c1, 0,
+#undef V9548
+#define V9548 (V + 37178)
+ 0x110e, 0x116c, 0x11c2, 0,
+#undef V9549
+#define V9549 (V + 37182)
+ 0x110e, 0x116d, 0,
+#undef V9550
+#define V9550 (V + 37185)
+ 0x110e, 0x116d, 0x11a8, 0,
+#undef V9551
+#define V9551 (V + 37189)
+ 0x110e, 0x116d, 0x11a9, 0,
+#undef V9552
+#define V9552 (V + 37193)
+ 0x110e, 0x116d, 0x11aa, 0,
+#undef V9553
+#define V9553 (V + 37197)
+ 0x110e, 0x116d, 0x11ab, 0,
+#undef V9554
+#define V9554 (V + 37201)
+ 0x110e, 0x116d, 0x11ac, 0,
+#undef V9555
+#define V9555 (V + 37205)
+ 0x110e, 0x116d, 0x11ad, 0,
+#undef V9556
+#define V9556 (V + 37209)
+ 0x110e, 0x116d, 0x11ae, 0,
+#undef V9557
+#define V9557 (V + 37213)
+ 0x110e, 0x116d, 0x11af, 0,
+#undef V9558
+#define V9558 (V + 37217)
+ 0x110e, 0x116d, 0x11b0, 0,
+#undef V9559
+#define V9559 (V + 37221)
+ 0x110e, 0x116d, 0x11b1, 0,
+#undef V9560
+#define V9560 (V + 37225)
+ 0x110e, 0x116d, 0x11b2, 0,
+#undef V9561
+#define V9561 (V + 37229)
+ 0x110e, 0x116d, 0x11b3, 0,
+#undef V9562
+#define V9562 (V + 37233)
+ 0x110e, 0x116d, 0x11b4, 0,
+#undef V9563
+#define V9563 (V + 37237)
+ 0x110e, 0x116d, 0x11b5, 0,
+#undef V9564
+#define V9564 (V + 37241)
+ 0x110e, 0x116d, 0x11b6, 0,
+#undef V9565
+#define V9565 (V + 37245)
+ 0x110e, 0x116d, 0x11b7, 0,
+#undef V9566
+#define V9566 (V + 37249)
+ 0x110e, 0x116d, 0x11b8, 0,
+#undef V9567
+#define V9567 (V + 37253)
+ 0x110e, 0x116d, 0x11b9, 0,
+#undef V9568
+#define V9568 (V + 37257)
+ 0x110e, 0x116d, 0x11ba, 0,
+#undef V9569
+#define V9569 (V + 37261)
+ 0x110e, 0x116d, 0x11bb, 0,
+#undef V9570
+#define V9570 (V + 37265)
+ 0x110e, 0x116d, 0x11bc, 0,
+#undef V9571
+#define V9571 (V + 37269)
+ 0x110e, 0x116d, 0x11bd, 0,
+#undef V9572
+#define V9572 (V + 37273)
+ 0x110e, 0x116d, 0x11be, 0,
+#undef V9573
+#define V9573 (V + 37277)
+ 0x110e, 0x116d, 0x11bf, 0,
+#undef V9574
+#define V9574 (V + 37281)
+ 0x110e, 0x116d, 0x11c0, 0,
+#undef V9575
+#define V9575 (V + 37285)
+ 0x110e, 0x116d, 0x11c1, 0,
+#undef V9576
+#define V9576 (V + 37289)
+ 0x110e, 0x116d, 0x11c2, 0,
+#undef V9577
+#define V9577 (V + 37293)
+ 0x110e, 0x116e, 0,
+#undef V9578
+#define V9578 (V + 37296)
+ 0x110e, 0x116e, 0x11a8, 0,
+#undef V9579
+#define V9579 (V + 37300)
+ 0x110e, 0x116e, 0x11a9, 0,
+#undef V9580
+#define V9580 (V + 37304)
+ 0x110e, 0x116e, 0x11aa, 0,
+#undef V9581
+#define V9581 (V + 37308)
+ 0x110e, 0x116e, 0x11ab, 0,
+#undef V9582
+#define V9582 (V + 37312)
+ 0x110e, 0x116e, 0x11ac, 0,
+#undef V9583
+#define V9583 (V + 37316)
+ 0x110e, 0x116e, 0x11ad, 0,
+#undef V9584
+#define V9584 (V + 37320)
+ 0x110e, 0x116e, 0x11ae, 0,
+#undef V9585
+#define V9585 (V + 37324)
+ 0x110e, 0x116e, 0x11af, 0,
+#undef V9586
+#define V9586 (V + 37328)
+ 0x110e, 0x116e, 0x11b0, 0,
+#undef V9587
+#define V9587 (V + 37332)
+ 0x110e, 0x116e, 0x11b1, 0,
+#undef V9588
+#define V9588 (V + 37336)
+ 0x110e, 0x116e, 0x11b2, 0,
+#undef V9589
+#define V9589 (V + 37340)
+ 0x110e, 0x116e, 0x11b3, 0,
+#undef V9590
+#define V9590 (V + 37344)
+ 0x110e, 0x116e, 0x11b4, 0,
+#undef V9591
+#define V9591 (V + 37348)
+ 0x110e, 0x116e, 0x11b5, 0,
+#undef V9592
+#define V9592 (V + 37352)
+ 0x110e, 0x116e, 0x11b6, 0,
+#undef V9593
+#define V9593 (V + 37356)
+ 0x110e, 0x116e, 0x11b7, 0,
+#undef V9594
+#define V9594 (V + 37360)
+ 0x110e, 0x116e, 0x11b8, 0,
+#undef V9595
+#define V9595 (V + 37364)
+ 0x110e, 0x116e, 0x11b9, 0,
+#undef V9596
+#define V9596 (V + 37368)
+ 0x110e, 0x116e, 0x11ba, 0,
+#undef V9597
+#define V9597 (V + 37372)
+ 0x110e, 0x116e, 0x11bb, 0,
+#undef V9598
+#define V9598 (V + 37376)
+ 0x110e, 0x116e, 0x11bc, 0,
+#undef V9599
+#define V9599 (V + 37380)
+ 0x110e, 0x116e, 0x11bd, 0,
+#undef V9600
+#define V9600 (V + 37384)
+ 0x110e, 0x116e, 0x11be, 0,
+#undef V9601
+#define V9601 (V + 37388)
+ 0x110e, 0x116e, 0x11bf, 0,
+#undef V9602
+#define V9602 (V + 37392)
+ 0x110e, 0x116e, 0x11c0, 0,
+#undef V9603
+#define V9603 (V + 37396)
+ 0x110e, 0x116e, 0x11c1, 0,
+#undef V9604
+#define V9604 (V + 37400)
+ 0x110e, 0x116e, 0x11c2, 0,
+#undef V9605
+#define V9605 (V + 37404)
+ 0x110e, 0x116f, 0,
+#undef V9606
+#define V9606 (V + 37407)
+ 0x110e, 0x116f, 0x11a8, 0,
+#undef V9607
+#define V9607 (V + 37411)
+ 0x110e, 0x116f, 0x11a9, 0,
+#undef V9608
+#define V9608 (V + 37415)
+ 0x110e, 0x116f, 0x11aa, 0,
+#undef V9609
+#define V9609 (V + 37419)
+ 0x110e, 0x116f, 0x11ab, 0,
+#undef V9610
+#define V9610 (V + 37423)
+ 0x110e, 0x116f, 0x11ac, 0,
+#undef V9611
+#define V9611 (V + 37427)
+ 0x110e, 0x116f, 0x11ad, 0,
+#undef V9612
+#define V9612 (V + 37431)
+ 0x110e, 0x116f, 0x11ae, 0,
+#undef V9613
+#define V9613 (V + 37435)
+ 0x110e, 0x116f, 0x11af, 0,
+#undef V9614
+#define V9614 (V + 37439)
+ 0x110e, 0x116f, 0x11b0, 0,
+#undef V9615
+#define V9615 (V + 37443)
+ 0x110e, 0x116f, 0x11b1, 0,
+#undef V9616
+#define V9616 (V + 37447)
+ 0x110e, 0x116f, 0x11b2, 0,
+#undef V9617
+#define V9617 (V + 37451)
+ 0x110e, 0x116f, 0x11b3, 0,
+#undef V9618
+#define V9618 (V + 37455)
+ 0x110e, 0x116f, 0x11b4, 0,
+#undef V9619
+#define V9619 (V + 37459)
+ 0x110e, 0x116f, 0x11b5, 0,
+#undef V9620
+#define V9620 (V + 37463)
+ 0x110e, 0x116f, 0x11b6, 0,
+#undef V9621
+#define V9621 (V + 37467)
+ 0x110e, 0x116f, 0x11b7, 0,
+#undef V9622
+#define V9622 (V + 37471)
+ 0x110e, 0x116f, 0x11b8, 0,
+#undef V9623
+#define V9623 (V + 37475)
+ 0x110e, 0x116f, 0x11b9, 0,
+#undef V9624
+#define V9624 (V + 37479)
+ 0x110e, 0x116f, 0x11ba, 0,
+#undef V9625
+#define V9625 (V + 37483)
+ 0x110e, 0x116f, 0x11bb, 0,
+#undef V9626
+#define V9626 (V + 37487)
+ 0x110e, 0x116f, 0x11bc, 0,
+#undef V9627
+#define V9627 (V + 37491)
+ 0x110e, 0x116f, 0x11bd, 0,
+#undef V9628
+#define V9628 (V + 37495)
+ 0x110e, 0x116f, 0x11be, 0,
+#undef V9629
+#define V9629 (V + 37499)
+ 0x110e, 0x116f, 0x11bf, 0,
+#undef V9630
+#define V9630 (V + 37503)
+ 0x110e, 0x116f, 0x11c0, 0,
+#undef V9631
+#define V9631 (V + 37507)
+ 0x110e, 0x116f, 0x11c1, 0,
+#undef V9632
+#define V9632 (V + 37511)
+ 0x110e, 0x116f, 0x11c2, 0,
+#undef V9633
+#define V9633 (V + 37515)
+ 0x110e, 0x1170, 0,
+#undef V9634
+#define V9634 (V + 37518)
+ 0x110e, 0x1170, 0x11a8, 0,
+#undef V9635
+#define V9635 (V + 37522)
+ 0x110e, 0x1170, 0x11a9, 0,
+#undef V9636
+#define V9636 (V + 37526)
+ 0x110e, 0x1170, 0x11aa, 0,
+#undef V9637
+#define V9637 (V + 37530)
+ 0x110e, 0x1170, 0x11ab, 0,
+#undef V9638
+#define V9638 (V + 37534)
+ 0x110e, 0x1170, 0x11ac, 0,
+#undef V9639
+#define V9639 (V + 37538)
+ 0x110e, 0x1170, 0x11ad, 0,
+#undef V9640
+#define V9640 (V + 37542)
+ 0x110e, 0x1170, 0x11ae, 0,
+#undef V9641
+#define V9641 (V + 37546)
+ 0x110e, 0x1170, 0x11af, 0,
+#undef V9642
+#define V9642 (V + 37550)
+ 0x110e, 0x1170, 0x11b0, 0,
+#undef V9643
+#define V9643 (V + 37554)
+ 0x110e, 0x1170, 0x11b1, 0,
+#undef V9644
+#define V9644 (V + 37558)
+ 0x110e, 0x1170, 0x11b2, 0,
+#undef V9645
+#define V9645 (V + 37562)
+ 0x110e, 0x1170, 0x11b3, 0,
+#undef V9646
+#define V9646 (V + 37566)
+ 0x110e, 0x1170, 0x11b4, 0,
+#undef V9647
+#define V9647 (V + 37570)
+ 0x110e, 0x1170, 0x11b5, 0,
+#undef V9648
+#define V9648 (V + 37574)
+ 0x110e, 0x1170, 0x11b6, 0,
+#undef V9649
+#define V9649 (V + 37578)
+ 0x110e, 0x1170, 0x11b7, 0,
+#undef V9650
+#define V9650 (V + 37582)
+ 0x110e, 0x1170, 0x11b8, 0,
+#undef V9651
+#define V9651 (V + 37586)
+ 0x110e, 0x1170, 0x11b9, 0,
+#undef V9652
+#define V9652 (V + 37590)
+ 0x110e, 0x1170, 0x11ba, 0,
+#undef V9653
+#define V9653 (V + 37594)
+ 0x110e, 0x1170, 0x11bb, 0,
+#undef V9654
+#define V9654 (V + 37598)
+ 0x110e, 0x1170, 0x11bc, 0,
+#undef V9655
+#define V9655 (V + 37602)
+ 0x110e, 0x1170, 0x11bd, 0,
+#undef V9656
+#define V9656 (V + 37606)
+ 0x110e, 0x1170, 0x11be, 0,
+#undef V9657
+#define V9657 (V + 37610)
+ 0x110e, 0x1170, 0x11bf, 0,
+#undef V9658
+#define V9658 (V + 37614)
+ 0x110e, 0x1170, 0x11c0, 0,
+#undef V9659
+#define V9659 (V + 37618)
+ 0x110e, 0x1170, 0x11c1, 0,
+#undef V9660
+#define V9660 (V + 37622)
+ 0x110e, 0x1170, 0x11c2, 0,
+#undef V9661
+#define V9661 (V + 37626)
+ 0x110e, 0x1171, 0,
+#undef V9662
+#define V9662 (V + 37629)
+ 0x110e, 0x1171, 0x11a8, 0,
+#undef V9663
+#define V9663 (V + 37633)
+ 0x110e, 0x1171, 0x11a9, 0,
+#undef V9664
+#define V9664 (V + 37637)
+ 0x110e, 0x1171, 0x11aa, 0,
+#undef V9665
+#define V9665 (V + 37641)
+ 0x110e, 0x1171, 0x11ab, 0,
+#undef V9666
+#define V9666 (V + 37645)
+ 0x110e, 0x1171, 0x11ac, 0,
+#undef V9667
+#define V9667 (V + 37649)
+ 0x110e, 0x1171, 0x11ad, 0,
+#undef V9668
+#define V9668 (V + 37653)
+ 0x110e, 0x1171, 0x11ae, 0,
+#undef V9669
+#define V9669 (V + 37657)
+ 0x110e, 0x1171, 0x11af, 0,
+#undef V9670
+#define V9670 (V + 37661)
+ 0x110e, 0x1171, 0x11b0, 0,
+#undef V9671
+#define V9671 (V + 37665)
+ 0x110e, 0x1171, 0x11b1, 0,
+#undef V9672
+#define V9672 (V + 37669)
+ 0x110e, 0x1171, 0x11b2, 0,
+#undef V9673
+#define V9673 (V + 37673)
+ 0x110e, 0x1171, 0x11b3, 0,
+#undef V9674
+#define V9674 (V + 37677)
+ 0x110e, 0x1171, 0x11b4, 0,
+#undef V9675
+#define V9675 (V + 37681)
+ 0x110e, 0x1171, 0x11b5, 0,
+#undef V9676
+#define V9676 (V + 37685)
+ 0x110e, 0x1171, 0x11b6, 0,
+#undef V9677
+#define V9677 (V + 37689)
+ 0x110e, 0x1171, 0x11b7, 0,
+#undef V9678
+#define V9678 (V + 37693)
+ 0x110e, 0x1171, 0x11b8, 0,
+#undef V9679
+#define V9679 (V + 37697)
+ 0x110e, 0x1171, 0x11b9, 0,
+#undef V9680
+#define V9680 (V + 37701)
+ 0x110e, 0x1171, 0x11ba, 0,
+#undef V9681
+#define V9681 (V + 37705)
+ 0x110e, 0x1171, 0x11bb, 0,
+#undef V9682
+#define V9682 (V + 37709)
+ 0x110e, 0x1171, 0x11bc, 0,
+#undef V9683
+#define V9683 (V + 37713)
+ 0x110e, 0x1171, 0x11bd, 0,
+#undef V9684
+#define V9684 (V + 37717)
+ 0x110e, 0x1171, 0x11be, 0,
+#undef V9685
+#define V9685 (V + 37721)
+ 0x110e, 0x1171, 0x11bf, 0,
+#undef V9686
+#define V9686 (V + 37725)
+ 0x110e, 0x1171, 0x11c0, 0,
+#undef V9687
+#define V9687 (V + 37729)
+ 0x110e, 0x1171, 0x11c1, 0,
+#undef V9688
+#define V9688 (V + 37733)
+ 0x110e, 0x1171, 0x11c2, 0,
+#undef V9689
+#define V9689 (V + 37737)
+ 0x110e, 0x1172, 0,
+#undef V9690
+#define V9690 (V + 37740)
+ 0x110e, 0x1172, 0x11a8, 0,
+#undef V9691
+#define V9691 (V + 37744)
+ 0x110e, 0x1172, 0x11a9, 0,
+#undef V9692
+#define V9692 (V + 37748)
+ 0x110e, 0x1172, 0x11aa, 0,
+#undef V9693
+#define V9693 (V + 37752)
+ 0x110e, 0x1172, 0x11ab, 0,
+#undef V9694
+#define V9694 (V + 37756)
+ 0x110e, 0x1172, 0x11ac, 0,
+#undef V9695
+#define V9695 (V + 37760)
+ 0x110e, 0x1172, 0x11ad, 0,
+#undef V9696
+#define V9696 (V + 37764)
+ 0x110e, 0x1172, 0x11ae, 0,
+#undef V9697
+#define V9697 (V + 37768)
+ 0x110e, 0x1172, 0x11af, 0,
+#undef V9698
+#define V9698 (V + 37772)
+ 0x110e, 0x1172, 0x11b0, 0,
+#undef V9699
+#define V9699 (V + 37776)
+ 0x110e, 0x1172, 0x11b1, 0,
+#undef V9700
+#define V9700 (V + 37780)
+ 0x110e, 0x1172, 0x11b2, 0,
+#undef V9701
+#define V9701 (V + 37784)
+ 0x110e, 0x1172, 0x11b3, 0,
+#undef V9702
+#define V9702 (V + 37788)
+ 0x110e, 0x1172, 0x11b4, 0,
+#undef V9703
+#define V9703 (V + 37792)
+ 0x110e, 0x1172, 0x11b5, 0,
+#undef V9704
+#define V9704 (V + 37796)
+ 0x110e, 0x1172, 0x11b6, 0,
+#undef V9705
+#define V9705 (V + 37800)
+ 0x110e, 0x1172, 0x11b7, 0,
+#undef V9706
+#define V9706 (V + 37804)
+ 0x110e, 0x1172, 0x11b8, 0,
+#undef V9707
+#define V9707 (V + 37808)
+ 0x110e, 0x1172, 0x11b9, 0,
+#undef V9708
+#define V9708 (V + 37812)
+ 0x110e, 0x1172, 0x11ba, 0,
+#undef V9709
+#define V9709 (V + 37816)
+ 0x110e, 0x1172, 0x11bb, 0,
+#undef V9710
+#define V9710 (V + 37820)
+ 0x110e, 0x1172, 0x11bc, 0,
+#undef V9711
+#define V9711 (V + 37824)
+ 0x110e, 0x1172, 0x11bd, 0,
+#undef V9712
+#define V9712 (V + 37828)
+ 0x110e, 0x1172, 0x11be, 0,
+#undef V9713
+#define V9713 (V + 37832)
+ 0x110e, 0x1172, 0x11bf, 0,
+#undef V9714
+#define V9714 (V + 37836)
+ 0x110e, 0x1172, 0x11c0, 0,
+#undef V9715
+#define V9715 (V + 37840)
+ 0x110e, 0x1172, 0x11c1, 0,
+#undef V9716
+#define V9716 (V + 37844)
+ 0x110e, 0x1172, 0x11c2, 0,
+#undef V9717
+#define V9717 (V + 37848)
+ 0x110e, 0x1173, 0,
+#undef V9718
+#define V9718 (V + 37851)
+ 0x110e, 0x1173, 0x11a8, 0,
+#undef V9719
+#define V9719 (V + 37855)
+ 0x110e, 0x1173, 0x11a9, 0,
+#undef V9720
+#define V9720 (V + 37859)
+ 0x110e, 0x1173, 0x11aa, 0,
+#undef V9721
+#define V9721 (V + 37863)
+ 0x110e, 0x1173, 0x11ab, 0,
+#undef V9722
+#define V9722 (V + 37867)
+ 0x110e, 0x1173, 0x11ac, 0,
+#undef V9723
+#define V9723 (V + 37871)
+ 0x110e, 0x1173, 0x11ad, 0,
+#undef V9724
+#define V9724 (V + 37875)
+ 0x110e, 0x1173, 0x11ae, 0,
+#undef V9725
+#define V9725 (V + 37879)
+ 0x110e, 0x1173, 0x11af, 0,
+#undef V9726
+#define V9726 (V + 37883)
+ 0x110e, 0x1173, 0x11b0, 0,
+#undef V9727
+#define V9727 (V + 37887)
+ 0x110e, 0x1173, 0x11b1, 0,
+#undef V9728
+#define V9728 (V + 37891)
+ 0x110e, 0x1173, 0x11b2, 0,
+#undef V9729
+#define V9729 (V + 37895)
+ 0x110e, 0x1173, 0x11b3, 0,
+#undef V9730
+#define V9730 (V + 37899)
+ 0x110e, 0x1173, 0x11b4, 0,
+#undef V9731
+#define V9731 (V + 37903)
+ 0x110e, 0x1173, 0x11b5, 0,
+#undef V9732
+#define V9732 (V + 37907)
+ 0x110e, 0x1173, 0x11b6, 0,
+#undef V9733
+#define V9733 (V + 37911)
+ 0x110e, 0x1173, 0x11b7, 0,
+#undef V9734
+#define V9734 (V + 37915)
+ 0x110e, 0x1173, 0x11b8, 0,
+#undef V9735
+#define V9735 (V + 37919)
+ 0x110e, 0x1173, 0x11b9, 0,
+#undef V9736
+#define V9736 (V + 37923)
+ 0x110e, 0x1173, 0x11ba, 0,
+#undef V9737
+#define V9737 (V + 37927)
+ 0x110e, 0x1173, 0x11bb, 0,
+#undef V9738
+#define V9738 (V + 37931)
+ 0x110e, 0x1173, 0x11bc, 0,
+#undef V9739
+#define V9739 (V + 37935)
+ 0x110e, 0x1173, 0x11bd, 0,
+#undef V9740
+#define V9740 (V + 37939)
+ 0x110e, 0x1173, 0x11be, 0,
+#undef V9741
+#define V9741 (V + 37943)
+ 0x110e, 0x1173, 0x11bf, 0,
+#undef V9742
+#define V9742 (V + 37947)
+ 0x110e, 0x1173, 0x11c0, 0,
+#undef V9743
+#define V9743 (V + 37951)
+ 0x110e, 0x1173, 0x11c1, 0,
+#undef V9744
+#define V9744 (V + 37955)
+ 0x110e, 0x1173, 0x11c2, 0,
+#undef V9745
+#define V9745 (V + 37959)
+ 0x110e, 0x1174, 0,
+#undef V9746
+#define V9746 (V + 37962)
+ 0x110e, 0x1174, 0x11a8, 0,
+#undef V9747
+#define V9747 (V + 37966)
+ 0x110e, 0x1174, 0x11a9, 0,
+#undef V9748
+#define V9748 (V + 37970)
+ 0x110e, 0x1174, 0x11aa, 0,
+#undef V9749
+#define V9749 (V + 37974)
+ 0x110e, 0x1174, 0x11ab, 0,
+#undef V9750
+#define V9750 (V + 37978)
+ 0x110e, 0x1174, 0x11ac, 0,
+#undef V9751
+#define V9751 (V + 37982)
+ 0x110e, 0x1174, 0x11ad, 0,
+#undef V9752
+#define V9752 (V + 37986)
+ 0x110e, 0x1174, 0x11ae, 0,
+#undef V9753
+#define V9753 (V + 37990)
+ 0x110e, 0x1174, 0x11af, 0,
+#undef V9754
+#define V9754 (V + 37994)
+ 0x110e, 0x1174, 0x11b0, 0,
+#undef V9755
+#define V9755 (V + 37998)
+ 0x110e, 0x1174, 0x11b1, 0,
+#undef V9756
+#define V9756 (V + 38002)
+ 0x110e, 0x1174, 0x11b2, 0,
+#undef V9757
+#define V9757 (V + 38006)
+ 0x110e, 0x1174, 0x11b3, 0,
+#undef V9758
+#define V9758 (V + 38010)
+ 0x110e, 0x1174, 0x11b4, 0,
+#undef V9759
+#define V9759 (V + 38014)
+ 0x110e, 0x1174, 0x11b5, 0,
+#undef V9760
+#define V9760 (V + 38018)
+ 0x110e, 0x1174, 0x11b6, 0,
+#undef V9761
+#define V9761 (V + 38022)
+ 0x110e, 0x1174, 0x11b7, 0,
+#undef V9762
+#define V9762 (V + 38026)
+ 0x110e, 0x1174, 0x11b8, 0,
+#undef V9763
+#define V9763 (V + 38030)
+ 0x110e, 0x1174, 0x11b9, 0,
+#undef V9764
+#define V9764 (V + 38034)
+ 0x110e, 0x1174, 0x11ba, 0,
+#undef V9765
+#define V9765 (V + 38038)
+ 0x110e, 0x1174, 0x11bb, 0,
+#undef V9766
+#define V9766 (V + 38042)
+ 0x110e, 0x1174, 0x11bc, 0,
+#undef V9767
+#define V9767 (V + 38046)
+ 0x110e, 0x1174, 0x11bd, 0,
+#undef V9768
+#define V9768 (V + 38050)
+ 0x110e, 0x1174, 0x11be, 0,
+#undef V9769
+#define V9769 (V + 38054)
+ 0x110e, 0x1174, 0x11bf, 0,
+#undef V9770
+#define V9770 (V + 38058)
+ 0x110e, 0x1174, 0x11c0, 0,
+#undef V9771
+#define V9771 (V + 38062)
+ 0x110e, 0x1174, 0x11c1, 0,
+#undef V9772
+#define V9772 (V + 38066)
+ 0x110e, 0x1174, 0x11c2, 0,
+#undef V9773
+#define V9773 (V + 38070)
+ 0x110e, 0x1175, 0,
+#undef V9774
+#define V9774 (V + 38073)
+ 0x110e, 0x1175, 0x11a8, 0,
+#undef V9775
+#define V9775 (V + 38077)
+ 0x110e, 0x1175, 0x11a9, 0,
+#undef V9776
+#define V9776 (V + 38081)
+ 0x110e, 0x1175, 0x11aa, 0,
+#undef V9777
+#define V9777 (V + 38085)
+ 0x110e, 0x1175, 0x11ab, 0,
+#undef V9778
+#define V9778 (V + 38089)
+ 0x110e, 0x1175, 0x11ac, 0,
+#undef V9779
+#define V9779 (V + 38093)
+ 0x110e, 0x1175, 0x11ad, 0,
+#undef V9780
+#define V9780 (V + 38097)
+ 0x110e, 0x1175, 0x11ae, 0,
+#undef V9781
+#define V9781 (V + 38101)
+ 0x110e, 0x1175, 0x11af, 0,
+#undef V9782
+#define V9782 (V + 38105)
+ 0x110e, 0x1175, 0x11b0, 0,
+#undef V9783
+#define V9783 (V + 38109)
+ 0x110e, 0x1175, 0x11b1, 0,
+#undef V9784
+#define V9784 (V + 38113)
+ 0x110e, 0x1175, 0x11b2, 0,
+#undef V9785
+#define V9785 (V + 38117)
+ 0x110e, 0x1175, 0x11b3, 0,
+#undef V9786
+#define V9786 (V + 38121)
+ 0x110e, 0x1175, 0x11b4, 0,
+#undef V9787
+#define V9787 (V + 38125)
+ 0x110e, 0x1175, 0x11b5, 0,
+#undef V9788
+#define V9788 (V + 38129)
+ 0x110e, 0x1175, 0x11b6, 0,
+#undef V9789
+#define V9789 (V + 38133)
+ 0x110e, 0x1175, 0x11b7, 0,
+#undef V9790
+#define V9790 (V + 38137)
+ 0x110e, 0x1175, 0x11b8, 0,
+#undef V9791
+#define V9791 (V + 38141)
+ 0x110e, 0x1175, 0x11b9, 0,
+#undef V9792
+#define V9792 (V + 38145)
+ 0x110e, 0x1175, 0x11ba, 0,
+#undef V9793
+#define V9793 (V + 38149)
+ 0x110e, 0x1175, 0x11bb, 0,
+#undef V9794
+#define V9794 (V + 38153)
+ 0x110e, 0x1175, 0x11bc, 0,
+#undef V9795
+#define V9795 (V + 38157)
+ 0x110e, 0x1175, 0x11bd, 0,
+#undef V9796
+#define V9796 (V + 38161)
+ 0x110e, 0x1175, 0x11be, 0,
+#undef V9797
+#define V9797 (V + 38165)
+ 0x110e, 0x1175, 0x11bf, 0,
+#undef V9798
+#define V9798 (V + 38169)
+ 0x110e, 0x1175, 0x11c0, 0,
+#undef V9799
+#define V9799 (V + 38173)
+ 0x110e, 0x1175, 0x11c1, 0,
+#undef V9800
+#define V9800 (V + 38177)
+ 0x110e, 0x1175, 0x11c2, 0,
+#undef V9801
+#define V9801 (V + 38181)
+ 0x110f, 0x1161, 0,
+#undef V9802
+#define V9802 (V + 38184)
+ 0x110f, 0x1161, 0x11a8, 0,
+#undef V9803
+#define V9803 (V + 38188)
+ 0x110f, 0x1161, 0x11a9, 0,
+#undef V9804
+#define V9804 (V + 38192)
+ 0x110f, 0x1161, 0x11aa, 0,
+#undef V9805
+#define V9805 (V + 38196)
+ 0x110f, 0x1161, 0x11ab, 0,
+#undef V9806
+#define V9806 (V + 38200)
+ 0x110f, 0x1161, 0x11ac, 0,
+#undef V9807
+#define V9807 (V + 38204)
+ 0x110f, 0x1161, 0x11ad, 0,
+#undef V9808
+#define V9808 (V + 38208)
+ 0x110f, 0x1161, 0x11ae, 0,
+#undef V9809
+#define V9809 (V + 38212)
+ 0x110f, 0x1161, 0x11af, 0,
+#undef V9810
+#define V9810 (V + 38216)
+ 0x110f, 0x1161, 0x11b0, 0,
+#undef V9811
+#define V9811 (V + 38220)
+ 0x110f, 0x1161, 0x11b1, 0,
+#undef V9812
+#define V9812 (V + 38224)
+ 0x110f, 0x1161, 0x11b2, 0,
+#undef V9813
+#define V9813 (V + 38228)
+ 0x110f, 0x1161, 0x11b3, 0,
+#undef V9814
+#define V9814 (V + 38232)
+ 0x110f, 0x1161, 0x11b4, 0,
+#undef V9815
+#define V9815 (V + 38236)
+ 0x110f, 0x1161, 0x11b5, 0,
+#undef V9816
+#define V9816 (V + 38240)
+ 0x110f, 0x1161, 0x11b6, 0,
+#undef V9817
+#define V9817 (V + 38244)
+ 0x110f, 0x1161, 0x11b7, 0,
+#undef V9818
+#define V9818 (V + 38248)
+ 0x110f, 0x1161, 0x11b8, 0,
+#undef V9819
+#define V9819 (V + 38252)
+ 0x110f, 0x1161, 0x11b9, 0,
+#undef V9820
+#define V9820 (V + 38256)
+ 0x110f, 0x1161, 0x11ba, 0,
+#undef V9821
+#define V9821 (V + 38260)
+ 0x110f, 0x1161, 0x11bb, 0,
+#undef V9822
+#define V9822 (V + 38264)
+ 0x110f, 0x1161, 0x11bc, 0,
+#undef V9823
+#define V9823 (V + 38268)
+ 0x110f, 0x1161, 0x11bd, 0,
+#undef V9824
+#define V9824 (V + 38272)
+ 0x110f, 0x1161, 0x11be, 0,
+#undef V9825
+#define V9825 (V + 38276)
+ 0x110f, 0x1161, 0x11bf, 0,
+#undef V9826
+#define V9826 (V + 38280)
+ 0x110f, 0x1161, 0x11c0, 0,
+#undef V9827
+#define V9827 (V + 38284)
+ 0x110f, 0x1161, 0x11c1, 0,
+#undef V9828
+#define V9828 (V + 38288)
+ 0x110f, 0x1161, 0x11c2, 0,
+#undef V9829
+#define V9829 (V + 38292)
+ 0x110f, 0x1162, 0,
+#undef V9830
+#define V9830 (V + 38295)
+ 0x110f, 0x1162, 0x11a8, 0,
+#undef V9831
+#define V9831 (V + 38299)
+ 0x110f, 0x1162, 0x11a9, 0,
+#undef V9832
+#define V9832 (V + 38303)
+ 0x110f, 0x1162, 0x11aa, 0,
+#undef V9833
+#define V9833 (V + 38307)
+ 0x110f, 0x1162, 0x11ab, 0,
+#undef V9834
+#define V9834 (V + 38311)
+ 0x110f, 0x1162, 0x11ac, 0,
+#undef V9835
+#define V9835 (V + 38315)
+ 0x110f, 0x1162, 0x11ad, 0,
+#undef V9836
+#define V9836 (V + 38319)
+ 0x110f, 0x1162, 0x11ae, 0,
+#undef V9837
+#define V9837 (V + 38323)
+ 0x110f, 0x1162, 0x11af, 0,
+#undef V9838
+#define V9838 (V + 38327)
+ 0x110f, 0x1162, 0x11b0, 0,
+#undef V9839
+#define V9839 (V + 38331)
+ 0x110f, 0x1162, 0x11b1, 0,
+#undef V9840
+#define V9840 (V + 38335)
+ 0x110f, 0x1162, 0x11b2, 0,
+#undef V9841
+#define V9841 (V + 38339)
+ 0x110f, 0x1162, 0x11b3, 0,
+#undef V9842
+#define V9842 (V + 38343)
+ 0x110f, 0x1162, 0x11b4, 0,
+#undef V9843
+#define V9843 (V + 38347)
+ 0x110f, 0x1162, 0x11b5, 0,
+#undef V9844
+#define V9844 (V + 38351)
+ 0x110f, 0x1162, 0x11b6, 0,
+#undef V9845
+#define V9845 (V + 38355)
+ 0x110f, 0x1162, 0x11b7, 0,
+#undef V9846
+#define V9846 (V + 38359)
+ 0x110f, 0x1162, 0x11b8, 0,
+#undef V9847
+#define V9847 (V + 38363)
+ 0x110f, 0x1162, 0x11b9, 0,
+#undef V9848
+#define V9848 (V + 38367)
+ 0x110f, 0x1162, 0x11ba, 0,
+#undef V9849
+#define V9849 (V + 38371)
+ 0x110f, 0x1162, 0x11bb, 0,
+#undef V9850
+#define V9850 (V + 38375)
+ 0x110f, 0x1162, 0x11bc, 0,
+#undef V9851
+#define V9851 (V + 38379)
+ 0x110f, 0x1162, 0x11bd, 0,
+#undef V9852
+#define V9852 (V + 38383)
+ 0x110f, 0x1162, 0x11be, 0,
+#undef V9853
+#define V9853 (V + 38387)
+ 0x110f, 0x1162, 0x11bf, 0,
+#undef V9854
+#define V9854 (V + 38391)
+ 0x110f, 0x1162, 0x11c0, 0,
+#undef V9855
+#define V9855 (V + 38395)
+ 0x110f, 0x1162, 0x11c1, 0,
+#undef V9856
+#define V9856 (V + 38399)
+ 0x110f, 0x1162, 0x11c2, 0,
+#undef V9857
+#define V9857 (V + 38403)
+ 0x110f, 0x1163, 0,
+#undef V9858
+#define V9858 (V + 38406)
+ 0x110f, 0x1163, 0x11a8, 0,
+#undef V9859
+#define V9859 (V + 38410)
+ 0x110f, 0x1163, 0x11a9, 0,
+#undef V9860
+#define V9860 (V + 38414)
+ 0x110f, 0x1163, 0x11aa, 0,
+#undef V9861
+#define V9861 (V + 38418)
+ 0x110f, 0x1163, 0x11ab, 0,
+#undef V9862
+#define V9862 (V + 38422)
+ 0x110f, 0x1163, 0x11ac, 0,
+#undef V9863
+#define V9863 (V + 38426)
+ 0x110f, 0x1163, 0x11ad, 0,
+#undef V9864
+#define V9864 (V + 38430)
+ 0x110f, 0x1163, 0x11ae, 0,
+#undef V9865
+#define V9865 (V + 38434)
+ 0x110f, 0x1163, 0x11af, 0,
+#undef V9866
+#define V9866 (V + 38438)
+ 0x110f, 0x1163, 0x11b0, 0,
+#undef V9867
+#define V9867 (V + 38442)
+ 0x110f, 0x1163, 0x11b1, 0,
+#undef V9868
+#define V9868 (V + 38446)
+ 0x110f, 0x1163, 0x11b2, 0,
+#undef V9869
+#define V9869 (V + 38450)
+ 0x110f, 0x1163, 0x11b3, 0,
+#undef V9870
+#define V9870 (V + 38454)
+ 0x110f, 0x1163, 0x11b4, 0,
+#undef V9871
+#define V9871 (V + 38458)
+ 0x110f, 0x1163, 0x11b5, 0,
+#undef V9872
+#define V9872 (V + 38462)
+ 0x110f, 0x1163, 0x11b6, 0,
+#undef V9873
+#define V9873 (V + 38466)
+ 0x110f, 0x1163, 0x11b7, 0,
+#undef V9874
+#define V9874 (V + 38470)
+ 0x110f, 0x1163, 0x11b8, 0,
+#undef V9875
+#define V9875 (V + 38474)
+ 0x110f, 0x1163, 0x11b9, 0,
+#undef V9876
+#define V9876 (V + 38478)
+ 0x110f, 0x1163, 0x11ba, 0,
+#undef V9877
+#define V9877 (V + 38482)
+ 0x110f, 0x1163, 0x11bb, 0,
+#undef V9878
+#define V9878 (V + 38486)
+ 0x110f, 0x1163, 0x11bc, 0,
+#undef V9879
+#define V9879 (V + 38490)
+ 0x110f, 0x1163, 0x11bd, 0,
+#undef V9880
+#define V9880 (V + 38494)
+ 0x110f, 0x1163, 0x11be, 0,
+#undef V9881
+#define V9881 (V + 38498)
+ 0x110f, 0x1163, 0x11bf, 0,
+#undef V9882
+#define V9882 (V + 38502)
+ 0x110f, 0x1163, 0x11c0, 0,
+#undef V9883
+#define V9883 (V + 38506)
+ 0x110f, 0x1163, 0x11c1, 0,
+#undef V9884
+#define V9884 (V + 38510)
+ 0x110f, 0x1163, 0x11c2, 0,
+#undef V9885
+#define V9885 (V + 38514)
+ 0x110f, 0x1164, 0,
+#undef V9886
+#define V9886 (V + 38517)
+ 0x110f, 0x1164, 0x11a8, 0,
+#undef V9887
+#define V9887 (V + 38521)
+ 0x110f, 0x1164, 0x11a9, 0,
+#undef V9888
+#define V9888 (V + 38525)
+ 0x110f, 0x1164, 0x11aa, 0,
+#undef V9889
+#define V9889 (V + 38529)
+ 0x110f, 0x1164, 0x11ab, 0,
+#undef V9890
+#define V9890 (V + 38533)
+ 0x110f, 0x1164, 0x11ac, 0,
+#undef V9891
+#define V9891 (V + 38537)
+ 0x110f, 0x1164, 0x11ad, 0,
+#undef V9892
+#define V9892 (V + 38541)
+ 0x110f, 0x1164, 0x11ae, 0,
+#undef V9893
+#define V9893 (V + 38545)
+ 0x110f, 0x1164, 0x11af, 0,
+#undef V9894
+#define V9894 (V + 38549)
+ 0x110f, 0x1164, 0x11b0, 0,
+#undef V9895
+#define V9895 (V + 38553)
+ 0x110f, 0x1164, 0x11b1, 0,
+#undef V9896
+#define V9896 (V + 38557)
+ 0x110f, 0x1164, 0x11b2, 0,
+#undef V9897
+#define V9897 (V + 38561)
+ 0x110f, 0x1164, 0x11b3, 0,
+#undef V9898
+#define V9898 (V + 38565)
+ 0x110f, 0x1164, 0x11b4, 0,
+#undef V9899
+#define V9899 (V + 38569)
+ 0x110f, 0x1164, 0x11b5, 0,
+#undef V9900
+#define V9900 (V + 38573)
+ 0x110f, 0x1164, 0x11b6, 0,
+#undef V9901
+#define V9901 (V + 38577)
+ 0x110f, 0x1164, 0x11b7, 0,
+#undef V9902
+#define V9902 (V + 38581)
+ 0x110f, 0x1164, 0x11b8, 0,
+#undef V9903
+#define V9903 (V + 38585)
+ 0x110f, 0x1164, 0x11b9, 0,
+#undef V9904
+#define V9904 (V + 38589)
+ 0x110f, 0x1164, 0x11ba, 0,
+#undef V9905
+#define V9905 (V + 38593)
+ 0x110f, 0x1164, 0x11bb, 0,
+#undef V9906
+#define V9906 (V + 38597)
+ 0x110f, 0x1164, 0x11bc, 0,
+#undef V9907
+#define V9907 (V + 38601)
+ 0x110f, 0x1164, 0x11bd, 0,
+#undef V9908
+#define V9908 (V + 38605)
+ 0x110f, 0x1164, 0x11be, 0,
+#undef V9909
+#define V9909 (V + 38609)
+ 0x110f, 0x1164, 0x11bf, 0,
+#undef V9910
+#define V9910 (V + 38613)
+ 0x110f, 0x1164, 0x11c0, 0,
+#undef V9911
+#define V9911 (V + 38617)
+ 0x110f, 0x1164, 0x11c1, 0,
+#undef V9912
+#define V9912 (V + 38621)
+ 0x110f, 0x1164, 0x11c2, 0,
+#undef V9913
+#define V9913 (V + 38625)
+ 0x110f, 0x1165, 0,
+#undef V9914
+#define V9914 (V + 38628)
+ 0x110f, 0x1165, 0x11a8, 0,
+#undef V9915
+#define V9915 (V + 38632)
+ 0x110f, 0x1165, 0x11a9, 0,
+#undef V9916
+#define V9916 (V + 38636)
+ 0x110f, 0x1165, 0x11aa, 0,
+#undef V9917
+#define V9917 (V + 38640)
+ 0x110f, 0x1165, 0x11ab, 0,
+#undef V9918
+#define V9918 (V + 38644)
+ 0x110f, 0x1165, 0x11ac, 0,
+#undef V9919
+#define V9919 (V + 38648)
+ 0x110f, 0x1165, 0x11ad, 0,
+#undef V9920
+#define V9920 (V + 38652)
+ 0x110f, 0x1165, 0x11ae, 0,
+#undef V9921
+#define V9921 (V + 38656)
+ 0x110f, 0x1165, 0x11af, 0,
+#undef V9922
+#define V9922 (V + 38660)
+ 0x110f, 0x1165, 0x11b0, 0,
+#undef V9923
+#define V9923 (V + 38664)
+ 0x110f, 0x1165, 0x11b1, 0,
+#undef V9924
+#define V9924 (V + 38668)
+ 0x110f, 0x1165, 0x11b2, 0,
+#undef V9925
+#define V9925 (V + 38672)
+ 0x110f, 0x1165, 0x11b3, 0,
+#undef V9926
+#define V9926 (V + 38676)
+ 0x110f, 0x1165, 0x11b4, 0,
+#undef V9927
+#define V9927 (V + 38680)
+ 0x110f, 0x1165, 0x11b5, 0,
+#undef V9928
+#define V9928 (V + 38684)
+ 0x110f, 0x1165, 0x11b6, 0,
+#undef V9929
+#define V9929 (V + 38688)
+ 0x110f, 0x1165, 0x11b7, 0,
+#undef V9930
+#define V9930 (V + 38692)
+ 0x110f, 0x1165, 0x11b8, 0,
+#undef V9931
+#define V9931 (V + 38696)
+ 0x110f, 0x1165, 0x11b9, 0,
+#undef V9932
+#define V9932 (V + 38700)
+ 0x110f, 0x1165, 0x11ba, 0,
+#undef V9933
+#define V9933 (V + 38704)
+ 0x110f, 0x1165, 0x11bb, 0,
+#undef V9934
+#define V9934 (V + 38708)
+ 0x110f, 0x1165, 0x11bc, 0,
+#undef V9935
+#define V9935 (V + 38712)
+ 0x110f, 0x1165, 0x11bd, 0,
+#undef V9936
+#define V9936 (V + 38716)
+ 0x110f, 0x1165, 0x11be, 0,
+#undef V9937
+#define V9937 (V + 38720)
+ 0x110f, 0x1165, 0x11bf, 0,
+#undef V9938
+#define V9938 (V + 38724)
+ 0x110f, 0x1165, 0x11c0, 0,
+#undef V9939
+#define V9939 (V + 38728)
+ 0x110f, 0x1165, 0x11c1, 0,
+#undef V9940
+#define V9940 (V + 38732)
+ 0x110f, 0x1165, 0x11c2, 0,
+#undef V9941
+#define V9941 (V + 38736)
+ 0x110f, 0x1166, 0,
+#undef V9942
+#define V9942 (V + 38739)
+ 0x110f, 0x1166, 0x11a8, 0,
+#undef V9943
+#define V9943 (V + 38743)
+ 0x110f, 0x1166, 0x11a9, 0,
+#undef V9944
+#define V9944 (V + 38747)
+ 0x110f, 0x1166, 0x11aa, 0,
+#undef V9945
+#define V9945 (V + 38751)
+ 0x110f, 0x1166, 0x11ab, 0,
+#undef V9946
+#define V9946 (V + 38755)
+ 0x110f, 0x1166, 0x11ac, 0,
+#undef V9947
+#define V9947 (V + 38759)
+ 0x110f, 0x1166, 0x11ad, 0,
+#undef V9948
+#define V9948 (V + 38763)
+ 0x110f, 0x1166, 0x11ae, 0,
+#undef V9949
+#define V9949 (V + 38767)
+ 0x110f, 0x1166, 0x11af, 0,
+#undef V9950
+#define V9950 (V + 38771)
+ 0x110f, 0x1166, 0x11b0, 0,
+#undef V9951
+#define V9951 (V + 38775)
+ 0x110f, 0x1166, 0x11b1, 0,
+#undef V9952
+#define V9952 (V + 38779)
+ 0x110f, 0x1166, 0x11b2, 0,
+#undef V9953
+#define V9953 (V + 38783)
+ 0x110f, 0x1166, 0x11b3, 0,
+#undef V9954
+#define V9954 (V + 38787)
+ 0x110f, 0x1166, 0x11b4, 0,
+#undef V9955
+#define V9955 (V + 38791)
+ 0x110f, 0x1166, 0x11b5, 0,
+#undef V9956
+#define V9956 (V + 38795)
+ 0x110f, 0x1166, 0x11b6, 0,
+#undef V9957
+#define V9957 (V + 38799)
+ 0x110f, 0x1166, 0x11b7, 0,
+#undef V9958
+#define V9958 (V + 38803)
+ 0x110f, 0x1166, 0x11b8, 0,
+#undef V9959
+#define V9959 (V + 38807)
+ 0x110f, 0x1166, 0x11b9, 0,
+#undef V9960
+#define V9960 (V + 38811)
+ 0x110f, 0x1166, 0x11ba, 0,
+#undef V9961
+#define V9961 (V + 38815)
+ 0x110f, 0x1166, 0x11bb, 0,
+#undef V9962
+#define V9962 (V + 38819)
+ 0x110f, 0x1166, 0x11bc, 0,
+#undef V9963
+#define V9963 (V + 38823)
+ 0x110f, 0x1166, 0x11bd, 0,
+#undef V9964
+#define V9964 (V + 38827)
+ 0x110f, 0x1166, 0x11be, 0,
+#undef V9965
+#define V9965 (V + 38831)
+ 0x110f, 0x1166, 0x11bf, 0,
+#undef V9966
+#define V9966 (V + 38835)
+ 0x110f, 0x1166, 0x11c0, 0,
+#undef V9967
+#define V9967 (V + 38839)
+ 0x110f, 0x1166, 0x11c1, 0,
+#undef V9968
+#define V9968 (V + 38843)
+ 0x110f, 0x1166, 0x11c2, 0,
+#undef V9969
+#define V9969 (V + 38847)
+ 0x110f, 0x1167, 0,
+#undef V9970
+#define V9970 (V + 38850)
+ 0x110f, 0x1167, 0x11a8, 0,
+#undef V9971
+#define V9971 (V + 38854)
+ 0x110f, 0x1167, 0x11a9, 0,
+#undef V9972
+#define V9972 (V + 38858)
+ 0x110f, 0x1167, 0x11aa, 0,
+#undef V9973
+#define V9973 (V + 38862)
+ 0x110f, 0x1167, 0x11ab, 0,
+#undef V9974
+#define V9974 (V + 38866)
+ 0x110f, 0x1167, 0x11ac, 0,
+#undef V9975
+#define V9975 (V + 38870)
+ 0x110f, 0x1167, 0x11ad, 0,
+#undef V9976
+#define V9976 (V + 38874)
+ 0x110f, 0x1167, 0x11ae, 0,
+#undef V9977
+#define V9977 (V + 38878)
+ 0x110f, 0x1167, 0x11af, 0,
+#undef V9978
+#define V9978 (V + 38882)
+ 0x110f, 0x1167, 0x11b0, 0,
+#undef V9979
+#define V9979 (V + 38886)
+ 0x110f, 0x1167, 0x11b1, 0,
+#undef V9980
+#define V9980 (V + 38890)
+ 0x110f, 0x1167, 0x11b2, 0,
+#undef V9981
+#define V9981 (V + 38894)
+ 0x110f, 0x1167, 0x11b3, 0,
+#undef V9982
+#define V9982 (V + 38898)
+ 0x110f, 0x1167, 0x11b4, 0,
+#undef V9983
+#define V9983 (V + 38902)
+ 0x110f, 0x1167, 0x11b5, 0,
+#undef V9984
+#define V9984 (V + 38906)
+ 0x110f, 0x1167, 0x11b6, 0,
+#undef V9985
+#define V9985 (V + 38910)
+ 0x110f, 0x1167, 0x11b7, 0,
+#undef V9986
+#define V9986 (V + 38914)
+ 0x110f, 0x1167, 0x11b8, 0,
+#undef V9987
+#define V9987 (V + 38918)
+ 0x110f, 0x1167, 0x11b9, 0,
+#undef V9988
+#define V9988 (V + 38922)
+ 0x110f, 0x1167, 0x11ba, 0,
+#undef V9989
+#define V9989 (V + 38926)
+ 0x110f, 0x1167, 0x11bb, 0,
+#undef V9990
+#define V9990 (V + 38930)
+ 0x110f, 0x1167, 0x11bc, 0,
+#undef V9991
+#define V9991 (V + 38934)
+ 0x110f, 0x1167, 0x11bd, 0,
+#undef V9992
+#define V9992 (V + 38938)
+ 0x110f, 0x1167, 0x11be, 0,
+#undef V9993
+#define V9993 (V + 38942)
+ 0x110f, 0x1167, 0x11bf, 0,
+#undef V9994
+#define V9994 (V + 38946)
+ 0x110f, 0x1167, 0x11c0, 0,
+#undef V9995
+#define V9995 (V + 38950)
+ 0x110f, 0x1167, 0x11c1, 0,
+#undef V9996
+#define V9996 (V + 38954)
+ 0x110f, 0x1167, 0x11c2, 0,
+#undef V9997
+#define V9997 (V + 38958)
+ 0x110f, 0x1168, 0,
+#undef V9998
+#define V9998 (V + 38961)
+ 0x110f, 0x1168, 0x11a8, 0,
+#undef V9999
+#define V9999 (V + 38965)
+ 0x110f, 0x1168, 0x11a9, 0,
+#undef V10000
+#define V10000 (V + 38969)
+ 0x110f, 0x1168, 0x11aa, 0,
+#undef V10001
+#define V10001 (V + 38973)
+ 0x110f, 0x1168, 0x11ab, 0,
+#undef V10002
+#define V10002 (V + 38977)
+ 0x110f, 0x1168, 0x11ac, 0,
+#undef V10003
+#define V10003 (V + 38981)
+ 0x110f, 0x1168, 0x11ad, 0,
+#undef V10004
+#define V10004 (V + 38985)
+ 0x110f, 0x1168, 0x11ae, 0,
+#undef V10005
+#define V10005 (V + 38989)
+ 0x110f, 0x1168, 0x11af, 0,
+#undef V10006
+#define V10006 (V + 38993)
+ 0x110f, 0x1168, 0x11b0, 0,
+#undef V10007
+#define V10007 (V + 38997)
+ 0x110f, 0x1168, 0x11b1, 0,
+#undef V10008
+#define V10008 (V + 39001)
+ 0x110f, 0x1168, 0x11b2, 0,
+#undef V10009
+#define V10009 (V + 39005)
+ 0x110f, 0x1168, 0x11b3, 0,
+#undef V10010
+#define V10010 (V + 39009)
+ 0x110f, 0x1168, 0x11b4, 0,
+#undef V10011
+#define V10011 (V + 39013)
+ 0x110f, 0x1168, 0x11b5, 0,
+#undef V10012
+#define V10012 (V + 39017)
+ 0x110f, 0x1168, 0x11b6, 0,
+#undef V10013
+#define V10013 (V + 39021)
+ 0x110f, 0x1168, 0x11b7, 0,
+#undef V10014
+#define V10014 (V + 39025)
+ 0x110f, 0x1168, 0x11b8, 0,
+#undef V10015
+#define V10015 (V + 39029)
+ 0x110f, 0x1168, 0x11b9, 0,
+#undef V10016
+#define V10016 (V + 39033)
+ 0x110f, 0x1168, 0x11ba, 0,
+#undef V10017
+#define V10017 (V + 39037)
+ 0x110f, 0x1168, 0x11bb, 0,
+#undef V10018
+#define V10018 (V + 39041)
+ 0x110f, 0x1168, 0x11bc, 0,
+#undef V10019
+#define V10019 (V + 39045)
+ 0x110f, 0x1168, 0x11bd, 0,
+#undef V10020
+#define V10020 (V + 39049)
+ 0x110f, 0x1168, 0x11be, 0,
+#undef V10021
+#define V10021 (V + 39053)
+ 0x110f, 0x1168, 0x11bf, 0,
+#undef V10022
+#define V10022 (V + 39057)
+ 0x110f, 0x1168, 0x11c0, 0,
+#undef V10023
+#define V10023 (V + 39061)
+ 0x110f, 0x1168, 0x11c1, 0,
+#undef V10024
+#define V10024 (V + 39065)
+ 0x110f, 0x1168, 0x11c2, 0,
+#undef V10025
+#define V10025 (V + 39069)
+ 0x110f, 0x1169, 0,
+#undef V10026
+#define V10026 (V + 39072)
+ 0x110f, 0x1169, 0x11a8, 0,
+#undef V10027
+#define V10027 (V + 39076)
+ 0x110f, 0x1169, 0x11a9, 0,
+#undef V10028
+#define V10028 (V + 39080)
+ 0x110f, 0x1169, 0x11aa, 0,
+#undef V10029
+#define V10029 (V + 39084)
+ 0x110f, 0x1169, 0x11ab, 0,
+#undef V10030
+#define V10030 (V + 39088)
+ 0x110f, 0x1169, 0x11ac, 0,
+#undef V10031
+#define V10031 (V + 39092)
+ 0x110f, 0x1169, 0x11ad, 0,
+#undef V10032
+#define V10032 (V + 39096)
+ 0x110f, 0x1169, 0x11ae, 0,
+#undef V10033
+#define V10033 (V + 39100)
+ 0x110f, 0x1169, 0x11af, 0,
+#undef V10034
+#define V10034 (V + 39104)
+ 0x110f, 0x1169, 0x11b0, 0,
+#undef V10035
+#define V10035 (V + 39108)
+ 0x110f, 0x1169, 0x11b1, 0,
+#undef V10036
+#define V10036 (V + 39112)
+ 0x110f, 0x1169, 0x11b2, 0,
+#undef V10037
+#define V10037 (V + 39116)
+ 0x110f, 0x1169, 0x11b3, 0,
+#undef V10038
+#define V10038 (V + 39120)
+ 0x110f, 0x1169, 0x11b4, 0,
+#undef V10039
+#define V10039 (V + 39124)
+ 0x110f, 0x1169, 0x11b5, 0,
+#undef V10040
+#define V10040 (V + 39128)
+ 0x110f, 0x1169, 0x11b6, 0,
+#undef V10041
+#define V10041 (V + 39132)
+ 0x110f, 0x1169, 0x11b7, 0,
+#undef V10042
+#define V10042 (V + 39136)
+ 0x110f, 0x1169, 0x11b8, 0,
+#undef V10043
+#define V10043 (V + 39140)
+ 0x110f, 0x1169, 0x11b9, 0,
+#undef V10044
+#define V10044 (V + 39144)
+ 0x110f, 0x1169, 0x11ba, 0,
+#undef V10045
+#define V10045 (V + 39148)
+ 0x110f, 0x1169, 0x11bb, 0,
+#undef V10046
+#define V10046 (V + 39152)
+ 0x110f, 0x1169, 0x11bc, 0,
+#undef V10047
+#define V10047 (V + 39156)
+ 0x110f, 0x1169, 0x11bd, 0,
+#undef V10048
+#define V10048 (V + 39160)
+ 0x110f, 0x1169, 0x11be, 0,
+#undef V10049
+#define V10049 (V + 39164)
+ 0x110f, 0x1169, 0x11bf, 0,
+#undef V10050
+#define V10050 (V + 39168)
+ 0x110f, 0x1169, 0x11c0, 0,
+#undef V10051
+#define V10051 (V + 39172)
+ 0x110f, 0x1169, 0x11c1, 0,
+#undef V10052
+#define V10052 (V + 39176)
+ 0x110f, 0x1169, 0x11c2, 0,
+#undef V10053
+#define V10053 (V + 39180)
+ 0x110f, 0x116a, 0,
+#undef V10054
+#define V10054 (V + 39183)
+ 0x110f, 0x116a, 0x11a8, 0,
+#undef V10055
+#define V10055 (V + 39187)
+ 0x110f, 0x116a, 0x11a9, 0,
+#undef V10056
+#define V10056 (V + 39191)
+ 0x110f, 0x116a, 0x11aa, 0,
+#undef V10057
+#define V10057 (V + 39195)
+ 0x110f, 0x116a, 0x11ab, 0,
+#undef V10058
+#define V10058 (V + 39199)
+ 0x110f, 0x116a, 0x11ac, 0,
+#undef V10059
+#define V10059 (V + 39203)
+ 0x110f, 0x116a, 0x11ad, 0,
+#undef V10060
+#define V10060 (V + 39207)
+ 0x110f, 0x116a, 0x11ae, 0,
+#undef V10061
+#define V10061 (V + 39211)
+ 0x110f, 0x116a, 0x11af, 0,
+#undef V10062
+#define V10062 (V + 39215)
+ 0x110f, 0x116a, 0x11b0, 0,
+#undef V10063
+#define V10063 (V + 39219)
+ 0x110f, 0x116a, 0x11b1, 0,
+#undef V10064
+#define V10064 (V + 39223)
+ 0x110f, 0x116a, 0x11b2, 0,
+#undef V10065
+#define V10065 (V + 39227)
+ 0x110f, 0x116a, 0x11b3, 0,
+#undef V10066
+#define V10066 (V + 39231)
+ 0x110f, 0x116a, 0x11b4, 0,
+#undef V10067
+#define V10067 (V + 39235)
+ 0x110f, 0x116a, 0x11b5, 0,
+#undef V10068
+#define V10068 (V + 39239)
+ 0x110f, 0x116a, 0x11b6, 0,
+#undef V10069
+#define V10069 (V + 39243)
+ 0x110f, 0x116a, 0x11b7, 0,
+#undef V10070
+#define V10070 (V + 39247)
+ 0x110f, 0x116a, 0x11b8, 0,
+#undef V10071
+#define V10071 (V + 39251)
+ 0x110f, 0x116a, 0x11b9, 0,
+#undef V10072
+#define V10072 (V + 39255)
+ 0x110f, 0x116a, 0x11ba, 0,
+#undef V10073
+#define V10073 (V + 39259)
+ 0x110f, 0x116a, 0x11bb, 0,
+#undef V10074
+#define V10074 (V + 39263)
+ 0x110f, 0x116a, 0x11bc, 0,
+#undef V10075
+#define V10075 (V + 39267)
+ 0x110f, 0x116a, 0x11bd, 0,
+#undef V10076
+#define V10076 (V + 39271)
+ 0x110f, 0x116a, 0x11be, 0,
+#undef V10077
+#define V10077 (V + 39275)
+ 0x110f, 0x116a, 0x11bf, 0,
+#undef V10078
+#define V10078 (V + 39279)
+ 0x110f, 0x116a, 0x11c0, 0,
+#undef V10079
+#define V10079 (V + 39283)
+ 0x110f, 0x116a, 0x11c1, 0,
+#undef V10080
+#define V10080 (V + 39287)
+ 0x110f, 0x116a, 0x11c2, 0,
+#undef V10081
+#define V10081 (V + 39291)
+ 0x110f, 0x116b, 0,
+#undef V10082
+#define V10082 (V + 39294)
+ 0x110f, 0x116b, 0x11a8, 0,
+#undef V10083
+#define V10083 (V + 39298)
+ 0x110f, 0x116b, 0x11a9, 0,
+#undef V10084
+#define V10084 (V + 39302)
+ 0x110f, 0x116b, 0x11aa, 0,
+#undef V10085
+#define V10085 (V + 39306)
+ 0x110f, 0x116b, 0x11ab, 0,
+#undef V10086
+#define V10086 (V + 39310)
+ 0x110f, 0x116b, 0x11ac, 0,
+#undef V10087
+#define V10087 (V + 39314)
+ 0x110f, 0x116b, 0x11ad, 0,
+#undef V10088
+#define V10088 (V + 39318)
+ 0x110f, 0x116b, 0x11ae, 0,
+#undef V10089
+#define V10089 (V + 39322)
+ 0x110f, 0x116b, 0x11af, 0,
+#undef V10090
+#define V10090 (V + 39326)
+ 0x110f, 0x116b, 0x11b0, 0,
+#undef V10091
+#define V10091 (V + 39330)
+ 0x110f, 0x116b, 0x11b1, 0,
+#undef V10092
+#define V10092 (V + 39334)
+ 0x110f, 0x116b, 0x11b2, 0,
+#undef V10093
+#define V10093 (V + 39338)
+ 0x110f, 0x116b, 0x11b3, 0,
+#undef V10094
+#define V10094 (V + 39342)
+ 0x110f, 0x116b, 0x11b4, 0,
+#undef V10095
+#define V10095 (V + 39346)
+ 0x110f, 0x116b, 0x11b5, 0,
+#undef V10096
+#define V10096 (V + 39350)
+ 0x110f, 0x116b, 0x11b6, 0,
+#undef V10097
+#define V10097 (V + 39354)
+ 0x110f, 0x116b, 0x11b7, 0,
+#undef V10098
+#define V10098 (V + 39358)
+ 0x110f, 0x116b, 0x11b8, 0,
+#undef V10099
+#define V10099 (V + 39362)
+ 0x110f, 0x116b, 0x11b9, 0,
+#undef V10100
+#define V10100 (V + 39366)
+ 0x110f, 0x116b, 0x11ba, 0,
+#undef V10101
+#define V10101 (V + 39370)
+ 0x110f, 0x116b, 0x11bb, 0,
+#undef V10102
+#define V10102 (V + 39374)
+ 0x110f, 0x116b, 0x11bc, 0,
+#undef V10103
+#define V10103 (V + 39378)
+ 0x110f, 0x116b, 0x11bd, 0,
+#undef V10104
+#define V10104 (V + 39382)
+ 0x110f, 0x116b, 0x11be, 0,
+#undef V10105
+#define V10105 (V + 39386)
+ 0x110f, 0x116b, 0x11bf, 0,
+#undef V10106
+#define V10106 (V + 39390)
+ 0x110f, 0x116b, 0x11c0, 0,
+#undef V10107
+#define V10107 (V + 39394)
+ 0x110f, 0x116b, 0x11c1, 0,
+#undef V10108
+#define V10108 (V + 39398)
+ 0x110f, 0x116b, 0x11c2, 0,
+#undef V10109
+#define V10109 (V + 39402)
+ 0x110f, 0x116c, 0,
+#undef V10110
+#define V10110 (V + 39405)
+ 0x110f, 0x116c, 0x11a8, 0,
+#undef V10111
+#define V10111 (V + 39409)
+ 0x110f, 0x116c, 0x11a9, 0,
+#undef V10112
+#define V10112 (V + 39413)
+ 0x110f, 0x116c, 0x11aa, 0,
+#undef V10113
+#define V10113 (V + 39417)
+ 0x110f, 0x116c, 0x11ab, 0,
+#undef V10114
+#define V10114 (V + 39421)
+ 0x110f, 0x116c, 0x11ac, 0,
+#undef V10115
+#define V10115 (V + 39425)
+ 0x110f, 0x116c, 0x11ad, 0,
+#undef V10116
+#define V10116 (V + 39429)
+ 0x110f, 0x116c, 0x11ae, 0,
+#undef V10117
+#define V10117 (V + 39433)
+ 0x110f, 0x116c, 0x11af, 0,
+#undef V10118
+#define V10118 (V + 39437)
+ 0x110f, 0x116c, 0x11b0, 0,
+#undef V10119
+#define V10119 (V + 39441)
+ 0x110f, 0x116c, 0x11b1, 0,
+#undef V10120
+#define V10120 (V + 39445)
+ 0x110f, 0x116c, 0x11b2, 0,
+#undef V10121
+#define V10121 (V + 39449)
+ 0x110f, 0x116c, 0x11b3, 0,
+#undef V10122
+#define V10122 (V + 39453)
+ 0x110f, 0x116c, 0x11b4, 0,
+#undef V10123
+#define V10123 (V + 39457)
+ 0x110f, 0x116c, 0x11b5, 0,
+#undef V10124
+#define V10124 (V + 39461)
+ 0x110f, 0x116c, 0x11b6, 0,
+#undef V10125
+#define V10125 (V + 39465)
+ 0x110f, 0x116c, 0x11b7, 0,
+#undef V10126
+#define V10126 (V + 39469)
+ 0x110f, 0x116c, 0x11b8, 0,
+#undef V10127
+#define V10127 (V + 39473)
+ 0x110f, 0x116c, 0x11b9, 0,
+#undef V10128
+#define V10128 (V + 39477)
+ 0x110f, 0x116c, 0x11ba, 0,
+#undef V10129
+#define V10129 (V + 39481)
+ 0x110f, 0x116c, 0x11bb, 0,
+#undef V10130
+#define V10130 (V + 39485)
+ 0x110f, 0x116c, 0x11bc, 0,
+#undef V10131
+#define V10131 (V + 39489)
+ 0x110f, 0x116c, 0x11bd, 0,
+#undef V10132
+#define V10132 (V + 39493)
+ 0x110f, 0x116c, 0x11be, 0,
+#undef V10133
+#define V10133 (V + 39497)
+ 0x110f, 0x116c, 0x11bf, 0,
+#undef V10134
+#define V10134 (V + 39501)
+ 0x110f, 0x116c, 0x11c0, 0,
+#undef V10135
+#define V10135 (V + 39505)
+ 0x110f, 0x116c, 0x11c1, 0,
+#undef V10136
+#define V10136 (V + 39509)
+ 0x110f, 0x116c, 0x11c2, 0,
+#undef V10137
+#define V10137 (V + 39513)
+ 0x110f, 0x116d, 0,
+#undef V10138
+#define V10138 (V + 39516)
+ 0x110f, 0x116d, 0x11a8, 0,
+#undef V10139
+#define V10139 (V + 39520)
+ 0x110f, 0x116d, 0x11a9, 0,
+#undef V10140
+#define V10140 (V + 39524)
+ 0x110f, 0x116d, 0x11aa, 0,
+#undef V10141
+#define V10141 (V + 39528)
+ 0x110f, 0x116d, 0x11ab, 0,
+#undef V10142
+#define V10142 (V + 39532)
+ 0x110f, 0x116d, 0x11ac, 0,
+#undef V10143
+#define V10143 (V + 39536)
+ 0x110f, 0x116d, 0x11ad, 0,
+#undef V10144
+#define V10144 (V + 39540)
+ 0x110f, 0x116d, 0x11ae, 0,
+#undef V10145
+#define V10145 (V + 39544)
+ 0x110f, 0x116d, 0x11af, 0,
+#undef V10146
+#define V10146 (V + 39548)
+ 0x110f, 0x116d, 0x11b0, 0,
+#undef V10147
+#define V10147 (V + 39552)
+ 0x110f, 0x116d, 0x11b1, 0,
+#undef V10148
+#define V10148 (V + 39556)
+ 0x110f, 0x116d, 0x11b2, 0,
+#undef V10149
+#define V10149 (V + 39560)
+ 0x110f, 0x116d, 0x11b3, 0,
+#undef V10150
+#define V10150 (V + 39564)
+ 0x110f, 0x116d, 0x11b4, 0,
+#undef V10151
+#define V10151 (V + 39568)
+ 0x110f, 0x116d, 0x11b5, 0,
+#undef V10152
+#define V10152 (V + 39572)
+ 0x110f, 0x116d, 0x11b6, 0,
+#undef V10153
+#define V10153 (V + 39576)
+ 0x110f, 0x116d, 0x11b7, 0,
+#undef V10154
+#define V10154 (V + 39580)
+ 0x110f, 0x116d, 0x11b8, 0,
+#undef V10155
+#define V10155 (V + 39584)
+ 0x110f, 0x116d, 0x11b9, 0,
+#undef V10156
+#define V10156 (V + 39588)
+ 0x110f, 0x116d, 0x11ba, 0,
+#undef V10157
+#define V10157 (V + 39592)
+ 0x110f, 0x116d, 0x11bb, 0,
+#undef V10158
+#define V10158 (V + 39596)
+ 0x110f, 0x116d, 0x11bc, 0,
+#undef V10159
+#define V10159 (V + 39600)
+ 0x110f, 0x116d, 0x11bd, 0,
+#undef V10160
+#define V10160 (V + 39604)
+ 0x110f, 0x116d, 0x11be, 0,
+#undef V10161
+#define V10161 (V + 39608)
+ 0x110f, 0x116d, 0x11bf, 0,
+#undef V10162
+#define V10162 (V + 39612)
+ 0x110f, 0x116d, 0x11c0, 0,
+#undef V10163
+#define V10163 (V + 39616)
+ 0x110f, 0x116d, 0x11c1, 0,
+#undef V10164
+#define V10164 (V + 39620)
+ 0x110f, 0x116d, 0x11c2, 0,
+#undef V10165
+#define V10165 (V + 39624)
+ 0x110f, 0x116e, 0,
+#undef V10166
+#define V10166 (V + 39627)
+ 0x110f, 0x116e, 0x11a8, 0,
+#undef V10167
+#define V10167 (V + 39631)
+ 0x110f, 0x116e, 0x11a9, 0,
+#undef V10168
+#define V10168 (V + 39635)
+ 0x110f, 0x116e, 0x11aa, 0,
+#undef V10169
+#define V10169 (V + 39639)
+ 0x110f, 0x116e, 0x11ab, 0,
+#undef V10170
+#define V10170 (V + 39643)
+ 0x110f, 0x116e, 0x11ac, 0,
+#undef V10171
+#define V10171 (V + 39647)
+ 0x110f, 0x116e, 0x11ad, 0,
+#undef V10172
+#define V10172 (V + 39651)
+ 0x110f, 0x116e, 0x11ae, 0,
+#undef V10173
+#define V10173 (V + 39655)
+ 0x110f, 0x116e, 0x11af, 0,
+#undef V10174
+#define V10174 (V + 39659)
+ 0x110f, 0x116e, 0x11b0, 0,
+#undef V10175
+#define V10175 (V + 39663)
+ 0x110f, 0x116e, 0x11b1, 0,
+#undef V10176
+#define V10176 (V + 39667)
+ 0x110f, 0x116e, 0x11b2, 0,
+#undef V10177
+#define V10177 (V + 39671)
+ 0x110f, 0x116e, 0x11b3, 0,
+#undef V10178
+#define V10178 (V + 39675)
+ 0x110f, 0x116e, 0x11b4, 0,
+#undef V10179
+#define V10179 (V + 39679)
+ 0x110f, 0x116e, 0x11b5, 0,
+#undef V10180
+#define V10180 (V + 39683)
+ 0x110f, 0x116e, 0x11b6, 0,
+#undef V10181
+#define V10181 (V + 39687)
+ 0x110f, 0x116e, 0x11b7, 0,
+#undef V10182
+#define V10182 (V + 39691)
+ 0x110f, 0x116e, 0x11b8, 0,
+#undef V10183
+#define V10183 (V + 39695)
+ 0x110f, 0x116e, 0x11b9, 0,
+#undef V10184
+#define V10184 (V + 39699)
+ 0x110f, 0x116e, 0x11ba, 0,
+#undef V10185
+#define V10185 (V + 39703)
+ 0x110f, 0x116e, 0x11bb, 0,
+#undef V10186
+#define V10186 (V + 39707)
+ 0x110f, 0x116e, 0x11bc, 0,
+#undef V10187
+#define V10187 (V + 39711)
+ 0x110f, 0x116e, 0x11bd, 0,
+#undef V10188
+#define V10188 (V + 39715)
+ 0x110f, 0x116e, 0x11be, 0,
+#undef V10189
+#define V10189 (V + 39719)
+ 0x110f, 0x116e, 0x11bf, 0,
+#undef V10190
+#define V10190 (V + 39723)
+ 0x110f, 0x116e, 0x11c0, 0,
+#undef V10191
+#define V10191 (V + 39727)
+ 0x110f, 0x116e, 0x11c1, 0,
+#undef V10192
+#define V10192 (V + 39731)
+ 0x110f, 0x116e, 0x11c2, 0,
+#undef V10193
+#define V10193 (V + 39735)
+ 0x110f, 0x116f, 0,
+#undef V10194
+#define V10194 (V + 39738)
+ 0x110f, 0x116f, 0x11a8, 0,
+#undef V10195
+#define V10195 (V + 39742)
+ 0x110f, 0x116f, 0x11a9, 0,
+#undef V10196
+#define V10196 (V + 39746)
+ 0x110f, 0x116f, 0x11aa, 0,
+#undef V10197
+#define V10197 (V + 39750)
+ 0x110f, 0x116f, 0x11ab, 0,
+#undef V10198
+#define V10198 (V + 39754)
+ 0x110f, 0x116f, 0x11ac, 0,
+#undef V10199
+#define V10199 (V + 39758)
+ 0x110f, 0x116f, 0x11ad, 0,
+#undef V10200
+#define V10200 (V + 39762)
+ 0x110f, 0x116f, 0x11ae, 0,
+#undef V10201
+#define V10201 (V + 39766)
+ 0x110f, 0x116f, 0x11af, 0,
+#undef V10202
+#define V10202 (V + 39770)
+ 0x110f, 0x116f, 0x11b0, 0,
+#undef V10203
+#define V10203 (V + 39774)
+ 0x110f, 0x116f, 0x11b1, 0,
+#undef V10204
+#define V10204 (V + 39778)
+ 0x110f, 0x116f, 0x11b2, 0,
+#undef V10205
+#define V10205 (V + 39782)
+ 0x110f, 0x116f, 0x11b3, 0,
+#undef V10206
+#define V10206 (V + 39786)
+ 0x110f, 0x116f, 0x11b4, 0,
+#undef V10207
+#define V10207 (V + 39790)
+ 0x110f, 0x116f, 0x11b5, 0,
+#undef V10208
+#define V10208 (V + 39794)
+ 0x110f, 0x116f, 0x11b6, 0,
+#undef V10209
+#define V10209 (V + 39798)
+ 0x110f, 0x116f, 0x11b7, 0,
+#undef V10210
+#define V10210 (V + 39802)
+ 0x110f, 0x116f, 0x11b8, 0,
+#undef V10211
+#define V10211 (V + 39806)
+ 0x110f, 0x116f, 0x11b9, 0,
+#undef V10212
+#define V10212 (V + 39810)
+ 0x110f, 0x116f, 0x11ba, 0,
+#undef V10213
+#define V10213 (V + 39814)
+ 0x110f, 0x116f, 0x11bb, 0,
+#undef V10214
+#define V10214 (V + 39818)
+ 0x110f, 0x116f, 0x11bc, 0,
+#undef V10215
+#define V10215 (V + 39822)
+ 0x110f, 0x116f, 0x11bd, 0,
+#undef V10216
+#define V10216 (V + 39826)
+ 0x110f, 0x116f, 0x11be, 0,
+#undef V10217
+#define V10217 (V + 39830)
+ 0x110f, 0x116f, 0x11bf, 0,
+#undef V10218
+#define V10218 (V + 39834)
+ 0x110f, 0x116f, 0x11c0, 0,
+#undef V10219
+#define V10219 (V + 39838)
+ 0x110f, 0x116f, 0x11c1, 0,
+#undef V10220
+#define V10220 (V + 39842)
+ 0x110f, 0x116f, 0x11c2, 0,
+#undef V10221
+#define V10221 (V + 39846)
+ 0x110f, 0x1170, 0,
+#undef V10222
+#define V10222 (V + 39849)
+ 0x110f, 0x1170, 0x11a8, 0,
+#undef V10223
+#define V10223 (V + 39853)
+ 0x110f, 0x1170, 0x11a9, 0,
+#undef V10224
+#define V10224 (V + 39857)
+ 0x110f, 0x1170, 0x11aa, 0,
+#undef V10225
+#define V10225 (V + 39861)
+ 0x110f, 0x1170, 0x11ab, 0,
+#undef V10226
+#define V10226 (V + 39865)
+ 0x110f, 0x1170, 0x11ac, 0,
+#undef V10227
+#define V10227 (V + 39869)
+ 0x110f, 0x1170, 0x11ad, 0,
+#undef V10228
+#define V10228 (V + 39873)
+ 0x110f, 0x1170, 0x11ae, 0,
+#undef V10229
+#define V10229 (V + 39877)
+ 0x110f, 0x1170, 0x11af, 0,
+#undef V10230
+#define V10230 (V + 39881)
+ 0x110f, 0x1170, 0x11b0, 0,
+#undef V10231
+#define V10231 (V + 39885)
+ 0x110f, 0x1170, 0x11b1, 0,
+#undef V10232
+#define V10232 (V + 39889)
+ 0x110f, 0x1170, 0x11b2, 0,
+#undef V10233
+#define V10233 (V + 39893)
+ 0x110f, 0x1170, 0x11b3, 0,
+#undef V10234
+#define V10234 (V + 39897)
+ 0x110f, 0x1170, 0x11b4, 0,
+#undef V10235
+#define V10235 (V + 39901)
+ 0x110f, 0x1170, 0x11b5, 0,
+#undef V10236
+#define V10236 (V + 39905)
+ 0x110f, 0x1170, 0x11b6, 0,
+#undef V10237
+#define V10237 (V + 39909)
+ 0x110f, 0x1170, 0x11b7, 0,
+#undef V10238
+#define V10238 (V + 39913)
+ 0x110f, 0x1170, 0x11b8, 0,
+#undef V10239
+#define V10239 (V + 39917)
+ 0x110f, 0x1170, 0x11b9, 0,
+#undef V10240
+#define V10240 (V + 39921)
+ 0x110f, 0x1170, 0x11ba, 0,
+#undef V10241
+#define V10241 (V + 39925)
+ 0x110f, 0x1170, 0x11bb, 0,
+#undef V10242
+#define V10242 (V + 39929)
+ 0x110f, 0x1170, 0x11bc, 0,
+#undef V10243
+#define V10243 (V + 39933)
+ 0x110f, 0x1170, 0x11bd, 0,
+#undef V10244
+#define V10244 (V + 39937)
+ 0x110f, 0x1170, 0x11be, 0,
+#undef V10245
+#define V10245 (V + 39941)
+ 0x110f, 0x1170, 0x11bf, 0,
+#undef V10246
+#define V10246 (V + 39945)
+ 0x110f, 0x1170, 0x11c0, 0,
+#undef V10247
+#define V10247 (V + 39949)
+ 0x110f, 0x1170, 0x11c1, 0,
+#undef V10248
+#define V10248 (V + 39953)
+ 0x110f, 0x1170, 0x11c2, 0,
+#undef V10249
+#define V10249 (V + 39957)
+ 0x110f, 0x1171, 0,
+#undef V10250
+#define V10250 (V + 39960)
+ 0x110f, 0x1171, 0x11a8, 0,
+#undef V10251
+#define V10251 (V + 39964)
+ 0x110f, 0x1171, 0x11a9, 0,
+#undef V10252
+#define V10252 (V + 39968)
+ 0x110f, 0x1171, 0x11aa, 0,
+#undef V10253
+#define V10253 (V + 39972)
+ 0x110f, 0x1171, 0x11ab, 0,
+#undef V10254
+#define V10254 (V + 39976)
+ 0x110f, 0x1171, 0x11ac, 0,
+#undef V10255
+#define V10255 (V + 39980)
+ 0x110f, 0x1171, 0x11ad, 0,
+#undef V10256
+#define V10256 (V + 39984)
+ 0x110f, 0x1171, 0x11ae, 0,
+#undef V10257
+#define V10257 (V + 39988)
+ 0x110f, 0x1171, 0x11af, 0,
+#undef V10258
+#define V10258 (V + 39992)
+ 0x110f, 0x1171, 0x11b0, 0,
+#undef V10259
+#define V10259 (V + 39996)
+ 0x110f, 0x1171, 0x11b1, 0,
+#undef V10260
+#define V10260 (V + 40000)
+ 0x110f, 0x1171, 0x11b2, 0,
+#undef V10261
+#define V10261 (V + 40004)
+ 0x110f, 0x1171, 0x11b3, 0,
+#undef V10262
+#define V10262 (V + 40008)
+ 0x110f, 0x1171, 0x11b4, 0,
+#undef V10263
+#define V10263 (V + 40012)
+ 0x110f, 0x1171, 0x11b5, 0,
+#undef V10264
+#define V10264 (V + 40016)
+ 0x110f, 0x1171, 0x11b6, 0,
+#undef V10265
+#define V10265 (V + 40020)
+ 0x110f, 0x1171, 0x11b7, 0,
+#undef V10266
+#define V10266 (V + 40024)
+ 0x110f, 0x1171, 0x11b8, 0,
+#undef V10267
+#define V10267 (V + 40028)
+ 0x110f, 0x1171, 0x11b9, 0,
+#undef V10268
+#define V10268 (V + 40032)
+ 0x110f, 0x1171, 0x11ba, 0,
+#undef V10269
+#define V10269 (V + 40036)
+ 0x110f, 0x1171, 0x11bb, 0,
+#undef V10270
+#define V10270 (V + 40040)
+ 0x110f, 0x1171, 0x11bc, 0,
+#undef V10271
+#define V10271 (V + 40044)
+ 0x110f, 0x1171, 0x11bd, 0,
+#undef V10272
+#define V10272 (V + 40048)
+ 0x110f, 0x1171, 0x11be, 0,
+#undef V10273
+#define V10273 (V + 40052)
+ 0x110f, 0x1171, 0x11bf, 0,
+#undef V10274
+#define V10274 (V + 40056)
+ 0x110f, 0x1171, 0x11c0, 0,
+#undef V10275
+#define V10275 (V + 40060)
+ 0x110f, 0x1171, 0x11c1, 0,
+#undef V10276
+#define V10276 (V + 40064)
+ 0x110f, 0x1171, 0x11c2, 0,
+#undef V10277
+#define V10277 (V + 40068)
+ 0x110f, 0x1172, 0,
+#undef V10278
+#define V10278 (V + 40071)
+ 0x110f, 0x1172, 0x11a8, 0,
+#undef V10279
+#define V10279 (V + 40075)
+ 0x110f, 0x1172, 0x11a9, 0,
+#undef V10280
+#define V10280 (V + 40079)
+ 0x110f, 0x1172, 0x11aa, 0,
+#undef V10281
+#define V10281 (V + 40083)
+ 0x110f, 0x1172, 0x11ab, 0,
+#undef V10282
+#define V10282 (V + 40087)
+ 0x110f, 0x1172, 0x11ac, 0,
+#undef V10283
+#define V10283 (V + 40091)
+ 0x110f, 0x1172, 0x11ad, 0,
+#undef V10284
+#define V10284 (V + 40095)
+ 0x110f, 0x1172, 0x11ae, 0,
+#undef V10285
+#define V10285 (V + 40099)
+ 0x110f, 0x1172, 0x11af, 0,
+#undef V10286
+#define V10286 (V + 40103)
+ 0x110f, 0x1172, 0x11b0, 0,
+#undef V10287
+#define V10287 (V + 40107)
+ 0x110f, 0x1172, 0x11b1, 0,
+#undef V10288
+#define V10288 (V + 40111)
+ 0x110f, 0x1172, 0x11b2, 0,
+#undef V10289
+#define V10289 (V + 40115)
+ 0x110f, 0x1172, 0x11b3, 0,
+#undef V10290
+#define V10290 (V + 40119)
+ 0x110f, 0x1172, 0x11b4, 0,
+#undef V10291
+#define V10291 (V + 40123)
+ 0x110f, 0x1172, 0x11b5, 0,
+#undef V10292
+#define V10292 (V + 40127)
+ 0x110f, 0x1172, 0x11b6, 0,
+#undef V10293
+#define V10293 (V + 40131)
+ 0x110f, 0x1172, 0x11b7, 0,
+#undef V10294
+#define V10294 (V + 40135)
+ 0x110f, 0x1172, 0x11b8, 0,
+#undef V10295
+#define V10295 (V + 40139)
+ 0x110f, 0x1172, 0x11b9, 0,
+#undef V10296
+#define V10296 (V + 40143)
+ 0x110f, 0x1172, 0x11ba, 0,
+#undef V10297
+#define V10297 (V + 40147)
+ 0x110f, 0x1172, 0x11bb, 0,
+#undef V10298
+#define V10298 (V + 40151)
+ 0x110f, 0x1172, 0x11bc, 0,
+#undef V10299
+#define V10299 (V + 40155)
+ 0x110f, 0x1172, 0x11bd, 0,
+#undef V10300
+#define V10300 (V + 40159)
+ 0x110f, 0x1172, 0x11be, 0,
+#undef V10301
+#define V10301 (V + 40163)
+ 0x110f, 0x1172, 0x11bf, 0,
+#undef V10302
+#define V10302 (V + 40167)
+ 0x110f, 0x1172, 0x11c0, 0,
+#undef V10303
+#define V10303 (V + 40171)
+ 0x110f, 0x1172, 0x11c1, 0,
+#undef V10304
+#define V10304 (V + 40175)
+ 0x110f, 0x1172, 0x11c2, 0,
+#undef V10305
+#define V10305 (V + 40179)
+ 0x110f, 0x1173, 0,
+#undef V10306
+#define V10306 (V + 40182)
+ 0x110f, 0x1173, 0x11a8, 0,
+#undef V10307
+#define V10307 (V + 40186)
+ 0x110f, 0x1173, 0x11a9, 0,
+#undef V10308
+#define V10308 (V + 40190)
+ 0x110f, 0x1173, 0x11aa, 0,
+#undef V10309
+#define V10309 (V + 40194)
+ 0x110f, 0x1173, 0x11ab, 0,
+#undef V10310
+#define V10310 (V + 40198)
+ 0x110f, 0x1173, 0x11ac, 0,
+#undef V10311
+#define V10311 (V + 40202)
+ 0x110f, 0x1173, 0x11ad, 0,
+#undef V10312
+#define V10312 (V + 40206)
+ 0x110f, 0x1173, 0x11ae, 0,
+#undef V10313
+#define V10313 (V + 40210)
+ 0x110f, 0x1173, 0x11af, 0,
+#undef V10314
+#define V10314 (V + 40214)
+ 0x110f, 0x1173, 0x11b0, 0,
+#undef V10315
+#define V10315 (V + 40218)
+ 0x110f, 0x1173, 0x11b1, 0,
+#undef V10316
+#define V10316 (V + 40222)
+ 0x110f, 0x1173, 0x11b2, 0,
+#undef V10317
+#define V10317 (V + 40226)
+ 0x110f, 0x1173, 0x11b3, 0,
+#undef V10318
+#define V10318 (V + 40230)
+ 0x110f, 0x1173, 0x11b4, 0,
+#undef V10319
+#define V10319 (V + 40234)
+ 0x110f, 0x1173, 0x11b5, 0,
+#undef V10320
+#define V10320 (V + 40238)
+ 0x110f, 0x1173, 0x11b6, 0,
+#undef V10321
+#define V10321 (V + 40242)
+ 0x110f, 0x1173, 0x11b7, 0,
+#undef V10322
+#define V10322 (V + 40246)
+ 0x110f, 0x1173, 0x11b8, 0,
+#undef V10323
+#define V10323 (V + 40250)
+ 0x110f, 0x1173, 0x11b9, 0,
+#undef V10324
+#define V10324 (V + 40254)
+ 0x110f, 0x1173, 0x11ba, 0,
+#undef V10325
+#define V10325 (V + 40258)
+ 0x110f, 0x1173, 0x11bb, 0,
+#undef V10326
+#define V10326 (V + 40262)
+ 0x110f, 0x1173, 0x11bc, 0,
+#undef V10327
+#define V10327 (V + 40266)
+ 0x110f, 0x1173, 0x11bd, 0,
+#undef V10328
+#define V10328 (V + 40270)
+ 0x110f, 0x1173, 0x11be, 0,
+#undef V10329
+#define V10329 (V + 40274)
+ 0x110f, 0x1173, 0x11bf, 0,
+#undef V10330
+#define V10330 (V + 40278)
+ 0x110f, 0x1173, 0x11c0, 0,
+#undef V10331
+#define V10331 (V + 40282)
+ 0x110f, 0x1173, 0x11c1, 0,
+#undef V10332
+#define V10332 (V + 40286)
+ 0x110f, 0x1173, 0x11c2, 0,
+#undef V10333
+#define V10333 (V + 40290)
+ 0x110f, 0x1174, 0,
+#undef V10334
+#define V10334 (V + 40293)
+ 0x110f, 0x1174, 0x11a8, 0,
+#undef V10335
+#define V10335 (V + 40297)
+ 0x110f, 0x1174, 0x11a9, 0,
+#undef V10336
+#define V10336 (V + 40301)
+ 0x110f, 0x1174, 0x11aa, 0,
+#undef V10337
+#define V10337 (V + 40305)
+ 0x110f, 0x1174, 0x11ab, 0,
+#undef V10338
+#define V10338 (V + 40309)
+ 0x110f, 0x1174, 0x11ac, 0,
+#undef V10339
+#define V10339 (V + 40313)
+ 0x110f, 0x1174, 0x11ad, 0,
+#undef V10340
+#define V10340 (V + 40317)
+ 0x110f, 0x1174, 0x11ae, 0,
+#undef V10341
+#define V10341 (V + 40321)
+ 0x110f, 0x1174, 0x11af, 0,
+#undef V10342
+#define V10342 (V + 40325)
+ 0x110f, 0x1174, 0x11b0, 0,
+#undef V10343
+#define V10343 (V + 40329)
+ 0x110f, 0x1174, 0x11b1, 0,
+#undef V10344
+#define V10344 (V + 40333)
+ 0x110f, 0x1174, 0x11b2, 0,
+#undef V10345
+#define V10345 (V + 40337)
+ 0x110f, 0x1174, 0x11b3, 0,
+#undef V10346
+#define V10346 (V + 40341)
+ 0x110f, 0x1174, 0x11b4, 0,
+#undef V10347
+#define V10347 (V + 40345)
+ 0x110f, 0x1174, 0x11b5, 0,
+#undef V10348
+#define V10348 (V + 40349)
+ 0x110f, 0x1174, 0x11b6, 0,
+#undef V10349
+#define V10349 (V + 40353)
+ 0x110f, 0x1174, 0x11b7, 0,
+#undef V10350
+#define V10350 (V + 40357)
+ 0x110f, 0x1174, 0x11b8, 0,
+#undef V10351
+#define V10351 (V + 40361)
+ 0x110f, 0x1174, 0x11b9, 0,
+#undef V10352
+#define V10352 (V + 40365)
+ 0x110f, 0x1174, 0x11ba, 0,
+#undef V10353
+#define V10353 (V + 40369)
+ 0x110f, 0x1174, 0x11bb, 0,
+#undef V10354
+#define V10354 (V + 40373)
+ 0x110f, 0x1174, 0x11bc, 0,
+#undef V10355
+#define V10355 (V + 40377)
+ 0x110f, 0x1174, 0x11bd, 0,
+#undef V10356
+#define V10356 (V + 40381)
+ 0x110f, 0x1174, 0x11be, 0,
+#undef V10357
+#define V10357 (V + 40385)
+ 0x110f, 0x1174, 0x11bf, 0,
+#undef V10358
+#define V10358 (V + 40389)
+ 0x110f, 0x1174, 0x11c0, 0,
+#undef V10359
+#define V10359 (V + 40393)
+ 0x110f, 0x1174, 0x11c1, 0,
+#undef V10360
+#define V10360 (V + 40397)
+ 0x110f, 0x1174, 0x11c2, 0,
+#undef V10361
+#define V10361 (V + 40401)
+ 0x110f, 0x1175, 0,
+#undef V10362
+#define V10362 (V + 40404)
+ 0x110f, 0x1175, 0x11a8, 0,
+#undef V10363
+#define V10363 (V + 40408)
+ 0x110f, 0x1175, 0x11a9, 0,
+#undef V10364
+#define V10364 (V + 40412)
+ 0x110f, 0x1175, 0x11aa, 0,
+#undef V10365
+#define V10365 (V + 40416)
+ 0x110f, 0x1175, 0x11ab, 0,
+#undef V10366
+#define V10366 (V + 40420)
+ 0x110f, 0x1175, 0x11ac, 0,
+#undef V10367
+#define V10367 (V + 40424)
+ 0x110f, 0x1175, 0x11ad, 0,
+#undef V10368
+#define V10368 (V + 40428)
+ 0x110f, 0x1175, 0x11ae, 0,
+#undef V10369
+#define V10369 (V + 40432)
+ 0x110f, 0x1175, 0x11af, 0,
+#undef V10370
+#define V10370 (V + 40436)
+ 0x110f, 0x1175, 0x11b0, 0,
+#undef V10371
+#define V10371 (V + 40440)
+ 0x110f, 0x1175, 0x11b1, 0,
+#undef V10372
+#define V10372 (V + 40444)
+ 0x110f, 0x1175, 0x11b2, 0,
+#undef V10373
+#define V10373 (V + 40448)
+ 0x110f, 0x1175, 0x11b3, 0,
+#undef V10374
+#define V10374 (V + 40452)
+ 0x110f, 0x1175, 0x11b4, 0,
+#undef V10375
+#define V10375 (V + 40456)
+ 0x110f, 0x1175, 0x11b5, 0,
+#undef V10376
+#define V10376 (V + 40460)
+ 0x110f, 0x1175, 0x11b6, 0,
+#undef V10377
+#define V10377 (V + 40464)
+ 0x110f, 0x1175, 0x11b7, 0,
+#undef V10378
+#define V10378 (V + 40468)
+ 0x110f, 0x1175, 0x11b8, 0,
+#undef V10379
+#define V10379 (V + 40472)
+ 0x110f, 0x1175, 0x11b9, 0,
+#undef V10380
+#define V10380 (V + 40476)
+ 0x110f, 0x1175, 0x11ba, 0,
+#undef V10381
+#define V10381 (V + 40480)
+ 0x110f, 0x1175, 0x11bb, 0,
+#undef V10382
+#define V10382 (V + 40484)
+ 0x110f, 0x1175, 0x11bc, 0,
+#undef V10383
+#define V10383 (V + 40488)
+ 0x110f, 0x1175, 0x11bd, 0,
+#undef V10384
+#define V10384 (V + 40492)
+ 0x110f, 0x1175, 0x11be, 0,
+#undef V10385
+#define V10385 (V + 40496)
+ 0x110f, 0x1175, 0x11bf, 0,
+#undef V10386
+#define V10386 (V + 40500)
+ 0x110f, 0x1175, 0x11c0, 0,
+#undef V10387
+#define V10387 (V + 40504)
+ 0x110f, 0x1175, 0x11c1, 0,
+#undef V10388
+#define V10388 (V + 40508)
+ 0x110f, 0x1175, 0x11c2, 0,
+#undef V10389
+#define V10389 (V + 40512)
+ 0x1110, 0x1161, 0,
+#undef V10390
+#define V10390 (V + 40515)
+ 0x1110, 0x1161, 0x11a8, 0,
+#undef V10391
+#define V10391 (V + 40519)
+ 0x1110, 0x1161, 0x11a9, 0,
+#undef V10392
+#define V10392 (V + 40523)
+ 0x1110, 0x1161, 0x11aa, 0,
+#undef V10393
+#define V10393 (V + 40527)
+ 0x1110, 0x1161, 0x11ab, 0,
+#undef V10394
+#define V10394 (V + 40531)
+ 0x1110, 0x1161, 0x11ac, 0,
+#undef V10395
+#define V10395 (V + 40535)
+ 0x1110, 0x1161, 0x11ad, 0,
+#undef V10396
+#define V10396 (V + 40539)
+ 0x1110, 0x1161, 0x11ae, 0,
+#undef V10397
+#define V10397 (V + 40543)
+ 0x1110, 0x1161, 0x11af, 0,
+#undef V10398
+#define V10398 (V + 40547)
+ 0x1110, 0x1161, 0x11b0, 0,
+#undef V10399
+#define V10399 (V + 40551)
+ 0x1110, 0x1161, 0x11b1, 0,
+#undef V10400
+#define V10400 (V + 40555)
+ 0x1110, 0x1161, 0x11b2, 0,
+#undef V10401
+#define V10401 (V + 40559)
+ 0x1110, 0x1161, 0x11b3, 0,
+#undef V10402
+#define V10402 (V + 40563)
+ 0x1110, 0x1161, 0x11b4, 0,
+#undef V10403
+#define V10403 (V + 40567)
+ 0x1110, 0x1161, 0x11b5, 0,
+#undef V10404
+#define V10404 (V + 40571)
+ 0x1110, 0x1161, 0x11b6, 0,
+#undef V10405
+#define V10405 (V + 40575)
+ 0x1110, 0x1161, 0x11b7, 0,
+#undef V10406
+#define V10406 (V + 40579)
+ 0x1110, 0x1161, 0x11b8, 0,
+#undef V10407
+#define V10407 (V + 40583)
+ 0x1110, 0x1161, 0x11b9, 0,
+#undef V10408
+#define V10408 (V + 40587)
+ 0x1110, 0x1161, 0x11ba, 0,
+#undef V10409
+#define V10409 (V + 40591)
+ 0x1110, 0x1161, 0x11bb, 0,
+#undef V10410
+#define V10410 (V + 40595)
+ 0x1110, 0x1161, 0x11bc, 0,
+#undef V10411
+#define V10411 (V + 40599)
+ 0x1110, 0x1161, 0x11bd, 0,
+#undef V10412
+#define V10412 (V + 40603)
+ 0x1110, 0x1161, 0x11be, 0,
+#undef V10413
+#define V10413 (V + 40607)
+ 0x1110, 0x1161, 0x11bf, 0,
+#undef V10414
+#define V10414 (V + 40611)
+ 0x1110, 0x1161, 0x11c0, 0,
+#undef V10415
+#define V10415 (V + 40615)
+ 0x1110, 0x1161, 0x11c1, 0,
+#undef V10416
+#define V10416 (V + 40619)
+ 0x1110, 0x1161, 0x11c2, 0,
+#undef V10417
+#define V10417 (V + 40623)
+ 0x1110, 0x1162, 0,
+#undef V10418
+#define V10418 (V + 40626)
+ 0x1110, 0x1162, 0x11a8, 0,
+#undef V10419
+#define V10419 (V + 40630)
+ 0x1110, 0x1162, 0x11a9, 0,
+#undef V10420
+#define V10420 (V + 40634)
+ 0x1110, 0x1162, 0x11aa, 0,
+#undef V10421
+#define V10421 (V + 40638)
+ 0x1110, 0x1162, 0x11ab, 0,
+#undef V10422
+#define V10422 (V + 40642)
+ 0x1110, 0x1162, 0x11ac, 0,
+#undef V10423
+#define V10423 (V + 40646)
+ 0x1110, 0x1162, 0x11ad, 0,
+#undef V10424
+#define V10424 (V + 40650)
+ 0x1110, 0x1162, 0x11ae, 0,
+#undef V10425
+#define V10425 (V + 40654)
+ 0x1110, 0x1162, 0x11af, 0,
+#undef V10426
+#define V10426 (V + 40658)
+ 0x1110, 0x1162, 0x11b0, 0,
+#undef V10427
+#define V10427 (V + 40662)
+ 0x1110, 0x1162, 0x11b1, 0,
+#undef V10428
+#define V10428 (V + 40666)
+ 0x1110, 0x1162, 0x11b2, 0,
+#undef V10429
+#define V10429 (V + 40670)
+ 0x1110, 0x1162, 0x11b3, 0,
+#undef V10430
+#define V10430 (V + 40674)
+ 0x1110, 0x1162, 0x11b4, 0,
+#undef V10431
+#define V10431 (V + 40678)
+ 0x1110, 0x1162, 0x11b5, 0,
+#undef V10432
+#define V10432 (V + 40682)
+ 0x1110, 0x1162, 0x11b6, 0,
+#undef V10433
+#define V10433 (V + 40686)
+ 0x1110, 0x1162, 0x11b7, 0,
+#undef V10434
+#define V10434 (V + 40690)
+ 0x1110, 0x1162, 0x11b8, 0,
+#undef V10435
+#define V10435 (V + 40694)
+ 0x1110, 0x1162, 0x11b9, 0,
+#undef V10436
+#define V10436 (V + 40698)
+ 0x1110, 0x1162, 0x11ba, 0,
+#undef V10437
+#define V10437 (V + 40702)
+ 0x1110, 0x1162, 0x11bb, 0,
+#undef V10438
+#define V10438 (V + 40706)
+ 0x1110, 0x1162, 0x11bc, 0,
+#undef V10439
+#define V10439 (V + 40710)
+ 0x1110, 0x1162, 0x11bd, 0,
+#undef V10440
+#define V10440 (V + 40714)
+ 0x1110, 0x1162, 0x11be, 0,
+#undef V10441
+#define V10441 (V + 40718)
+ 0x1110, 0x1162, 0x11bf, 0,
+#undef V10442
+#define V10442 (V + 40722)
+ 0x1110, 0x1162, 0x11c0, 0,
+#undef V10443
+#define V10443 (V + 40726)
+ 0x1110, 0x1162, 0x11c1, 0,
+#undef V10444
+#define V10444 (V + 40730)
+ 0x1110, 0x1162, 0x11c2, 0,
+#undef V10445
+#define V10445 (V + 40734)
+ 0x1110, 0x1163, 0,
+#undef V10446
+#define V10446 (V + 40737)
+ 0x1110, 0x1163, 0x11a8, 0,
+#undef V10447
+#define V10447 (V + 40741)
+ 0x1110, 0x1163, 0x11a9, 0,
+#undef V10448
+#define V10448 (V + 40745)
+ 0x1110, 0x1163, 0x11aa, 0,
+#undef V10449
+#define V10449 (V + 40749)
+ 0x1110, 0x1163, 0x11ab, 0,
+#undef V10450
+#define V10450 (V + 40753)
+ 0x1110, 0x1163, 0x11ac, 0,
+#undef V10451
+#define V10451 (V + 40757)
+ 0x1110, 0x1163, 0x11ad, 0,
+#undef V10452
+#define V10452 (V + 40761)
+ 0x1110, 0x1163, 0x11ae, 0,
+#undef V10453
+#define V10453 (V + 40765)
+ 0x1110, 0x1163, 0x11af, 0,
+#undef V10454
+#define V10454 (V + 40769)
+ 0x1110, 0x1163, 0x11b0, 0,
+#undef V10455
+#define V10455 (V + 40773)
+ 0x1110, 0x1163, 0x11b1, 0,
+#undef V10456
+#define V10456 (V + 40777)
+ 0x1110, 0x1163, 0x11b2, 0,
+#undef V10457
+#define V10457 (V + 40781)
+ 0x1110, 0x1163, 0x11b3, 0,
+#undef V10458
+#define V10458 (V + 40785)
+ 0x1110, 0x1163, 0x11b4, 0,
+#undef V10459
+#define V10459 (V + 40789)
+ 0x1110, 0x1163, 0x11b5, 0,
+#undef V10460
+#define V10460 (V + 40793)
+ 0x1110, 0x1163, 0x11b6, 0,
+#undef V10461
+#define V10461 (V + 40797)
+ 0x1110, 0x1163, 0x11b7, 0,
+#undef V10462
+#define V10462 (V + 40801)
+ 0x1110, 0x1163, 0x11b8, 0,
+#undef V10463
+#define V10463 (V + 40805)
+ 0x1110, 0x1163, 0x11b9, 0,
+#undef V10464
+#define V10464 (V + 40809)
+ 0x1110, 0x1163, 0x11ba, 0,
+#undef V10465
+#define V10465 (V + 40813)
+ 0x1110, 0x1163, 0x11bb, 0,
+#undef V10466
+#define V10466 (V + 40817)
+ 0x1110, 0x1163, 0x11bc, 0,
+#undef V10467
+#define V10467 (V + 40821)
+ 0x1110, 0x1163, 0x11bd, 0,
+#undef V10468
+#define V10468 (V + 40825)
+ 0x1110, 0x1163, 0x11be, 0,
+#undef V10469
+#define V10469 (V + 40829)
+ 0x1110, 0x1163, 0x11bf, 0,
+#undef V10470
+#define V10470 (V + 40833)
+ 0x1110, 0x1163, 0x11c0, 0,
+#undef V10471
+#define V10471 (V + 40837)
+ 0x1110, 0x1163, 0x11c1, 0,
+#undef V10472
+#define V10472 (V + 40841)
+ 0x1110, 0x1163, 0x11c2, 0,
+#undef V10473
+#define V10473 (V + 40845)
+ 0x1110, 0x1164, 0,
+#undef V10474
+#define V10474 (V + 40848)
+ 0x1110, 0x1164, 0x11a8, 0,
+#undef V10475
+#define V10475 (V + 40852)
+ 0x1110, 0x1164, 0x11a9, 0,
+#undef V10476
+#define V10476 (V + 40856)
+ 0x1110, 0x1164, 0x11aa, 0,
+#undef V10477
+#define V10477 (V + 40860)
+ 0x1110, 0x1164, 0x11ab, 0,
+#undef V10478
+#define V10478 (V + 40864)
+ 0x1110, 0x1164, 0x11ac, 0,
+#undef V10479
+#define V10479 (V + 40868)
+ 0x1110, 0x1164, 0x11ad, 0,
+#undef V10480
+#define V10480 (V + 40872)
+ 0x1110, 0x1164, 0x11ae, 0,
+#undef V10481
+#define V10481 (V + 40876)
+ 0x1110, 0x1164, 0x11af, 0,
+#undef V10482
+#define V10482 (V + 40880)
+ 0x1110, 0x1164, 0x11b0, 0,
+#undef V10483
+#define V10483 (V + 40884)
+ 0x1110, 0x1164, 0x11b1, 0,
+#undef V10484
+#define V10484 (V + 40888)
+ 0x1110, 0x1164, 0x11b2, 0,
+#undef V10485
+#define V10485 (V + 40892)
+ 0x1110, 0x1164, 0x11b3, 0,
+#undef V10486
+#define V10486 (V + 40896)
+ 0x1110, 0x1164, 0x11b4, 0,
+#undef V10487
+#define V10487 (V + 40900)
+ 0x1110, 0x1164, 0x11b5, 0,
+#undef V10488
+#define V10488 (V + 40904)
+ 0x1110, 0x1164, 0x11b6, 0,
+#undef V10489
+#define V10489 (V + 40908)
+ 0x1110, 0x1164, 0x11b7, 0,
+#undef V10490
+#define V10490 (V + 40912)
+ 0x1110, 0x1164, 0x11b8, 0,
+#undef V10491
+#define V10491 (V + 40916)
+ 0x1110, 0x1164, 0x11b9, 0,
+#undef V10492
+#define V10492 (V + 40920)
+ 0x1110, 0x1164, 0x11ba, 0,
+#undef V10493
+#define V10493 (V + 40924)
+ 0x1110, 0x1164, 0x11bb, 0,
+#undef V10494
+#define V10494 (V + 40928)
+ 0x1110, 0x1164, 0x11bc, 0,
+#undef V10495
+#define V10495 (V + 40932)
+ 0x1110, 0x1164, 0x11bd, 0,
+#undef V10496
+#define V10496 (V + 40936)
+ 0x1110, 0x1164, 0x11be, 0,
+#undef V10497
+#define V10497 (V + 40940)
+ 0x1110, 0x1164, 0x11bf, 0,
+#undef V10498
+#define V10498 (V + 40944)
+ 0x1110, 0x1164, 0x11c0, 0,
+#undef V10499
+#define V10499 (V + 40948)
+ 0x1110, 0x1164, 0x11c1, 0,
+#undef V10500
+#define V10500 (V + 40952)
+ 0x1110, 0x1164, 0x11c2, 0,
+#undef V10501
+#define V10501 (V + 40956)
+ 0x1110, 0x1165, 0,
+#undef V10502
+#define V10502 (V + 40959)
+ 0x1110, 0x1165, 0x11a8, 0,
+#undef V10503
+#define V10503 (V + 40963)
+ 0x1110, 0x1165, 0x11a9, 0,
+#undef V10504
+#define V10504 (V + 40967)
+ 0x1110, 0x1165, 0x11aa, 0,
+#undef V10505
+#define V10505 (V + 40971)
+ 0x1110, 0x1165, 0x11ab, 0,
+#undef V10506
+#define V10506 (V + 40975)
+ 0x1110, 0x1165, 0x11ac, 0,
+#undef V10507
+#define V10507 (V + 40979)
+ 0x1110, 0x1165, 0x11ad, 0,
+#undef V10508
+#define V10508 (V + 40983)
+ 0x1110, 0x1165, 0x11ae, 0,
+#undef V10509
+#define V10509 (V + 40987)
+ 0x1110, 0x1165, 0x11af, 0,
+#undef V10510
+#define V10510 (V + 40991)
+ 0x1110, 0x1165, 0x11b0, 0,
+#undef V10511
+#define V10511 (V + 40995)
+ 0x1110, 0x1165, 0x11b1, 0,
+#undef V10512
+#define V10512 (V + 40999)
+ 0x1110, 0x1165, 0x11b2, 0,
+#undef V10513
+#define V10513 (V + 41003)
+ 0x1110, 0x1165, 0x11b3, 0,
+#undef V10514
+#define V10514 (V + 41007)
+ 0x1110, 0x1165, 0x11b4, 0,
+#undef V10515
+#define V10515 (V + 41011)
+ 0x1110, 0x1165, 0x11b5, 0,
+#undef V10516
+#define V10516 (V + 41015)
+ 0x1110, 0x1165, 0x11b6, 0,
+#undef V10517
+#define V10517 (V + 41019)
+ 0x1110, 0x1165, 0x11b7, 0,
+#undef V10518
+#define V10518 (V + 41023)
+ 0x1110, 0x1165, 0x11b8, 0,
+#undef V10519
+#define V10519 (V + 41027)
+ 0x1110, 0x1165, 0x11b9, 0,
+#undef V10520
+#define V10520 (V + 41031)
+ 0x1110, 0x1165, 0x11ba, 0,
+#undef V10521
+#define V10521 (V + 41035)
+ 0x1110, 0x1165, 0x11bb, 0,
+#undef V10522
+#define V10522 (V + 41039)
+ 0x1110, 0x1165, 0x11bc, 0,
+#undef V10523
+#define V10523 (V + 41043)
+ 0x1110, 0x1165, 0x11bd, 0,
+#undef V10524
+#define V10524 (V + 41047)
+ 0x1110, 0x1165, 0x11be, 0,
+#undef V10525
+#define V10525 (V + 41051)
+ 0x1110, 0x1165, 0x11bf, 0,
+#undef V10526
+#define V10526 (V + 41055)
+ 0x1110, 0x1165, 0x11c0, 0,
+#undef V10527
+#define V10527 (V + 41059)
+ 0x1110, 0x1165, 0x11c1, 0,
+#undef V10528
+#define V10528 (V + 41063)
+ 0x1110, 0x1165, 0x11c2, 0,
+#undef V10529
+#define V10529 (V + 41067)
+ 0x1110, 0x1166, 0,
+#undef V10530
+#define V10530 (V + 41070)
+ 0x1110, 0x1166, 0x11a8, 0,
+#undef V10531
+#define V10531 (V + 41074)
+ 0x1110, 0x1166, 0x11a9, 0,
+#undef V10532
+#define V10532 (V + 41078)
+ 0x1110, 0x1166, 0x11aa, 0,
+#undef V10533
+#define V10533 (V + 41082)
+ 0x1110, 0x1166, 0x11ab, 0,
+#undef V10534
+#define V10534 (V + 41086)
+ 0x1110, 0x1166, 0x11ac, 0,
+#undef V10535
+#define V10535 (V + 41090)
+ 0x1110, 0x1166, 0x11ad, 0,
+#undef V10536
+#define V10536 (V + 41094)
+ 0x1110, 0x1166, 0x11ae, 0,
+#undef V10537
+#define V10537 (V + 41098)
+ 0x1110, 0x1166, 0x11af, 0,
+#undef V10538
+#define V10538 (V + 41102)
+ 0x1110, 0x1166, 0x11b0, 0,
+#undef V10539
+#define V10539 (V + 41106)
+ 0x1110, 0x1166, 0x11b1, 0,
+#undef V10540
+#define V10540 (V + 41110)
+ 0x1110, 0x1166, 0x11b2, 0,
+#undef V10541
+#define V10541 (V + 41114)
+ 0x1110, 0x1166, 0x11b3, 0,
+#undef V10542
+#define V10542 (V + 41118)
+ 0x1110, 0x1166, 0x11b4, 0,
+#undef V10543
+#define V10543 (V + 41122)
+ 0x1110, 0x1166, 0x11b5, 0,
+#undef V10544
+#define V10544 (V + 41126)
+ 0x1110, 0x1166, 0x11b6, 0,
+#undef V10545
+#define V10545 (V + 41130)
+ 0x1110, 0x1166, 0x11b7, 0,
+#undef V10546
+#define V10546 (V + 41134)
+ 0x1110, 0x1166, 0x11b8, 0,
+#undef V10547
+#define V10547 (V + 41138)
+ 0x1110, 0x1166, 0x11b9, 0,
+#undef V10548
+#define V10548 (V + 41142)
+ 0x1110, 0x1166, 0x11ba, 0,
+#undef V10549
+#define V10549 (V + 41146)
+ 0x1110, 0x1166, 0x11bb, 0,
+#undef V10550
+#define V10550 (V + 41150)
+ 0x1110, 0x1166, 0x11bc, 0,
+#undef V10551
+#define V10551 (V + 41154)
+ 0x1110, 0x1166, 0x11bd, 0,
+#undef V10552
+#define V10552 (V + 41158)
+ 0x1110, 0x1166, 0x11be, 0,
+#undef V10553
+#define V10553 (V + 41162)
+ 0x1110, 0x1166, 0x11bf, 0,
+#undef V10554
+#define V10554 (V + 41166)
+ 0x1110, 0x1166, 0x11c0, 0,
+#undef V10555
+#define V10555 (V + 41170)
+ 0x1110, 0x1166, 0x11c1, 0,
+#undef V10556
+#define V10556 (V + 41174)
+ 0x1110, 0x1166, 0x11c2, 0,
+#undef V10557
+#define V10557 (V + 41178)
+ 0x1110, 0x1167, 0,
+#undef V10558
+#define V10558 (V + 41181)
+ 0x1110, 0x1167, 0x11a8, 0,
+#undef V10559
+#define V10559 (V + 41185)
+ 0x1110, 0x1167, 0x11a9, 0,
+#undef V10560
+#define V10560 (V + 41189)
+ 0x1110, 0x1167, 0x11aa, 0,
+#undef V10561
+#define V10561 (V + 41193)
+ 0x1110, 0x1167, 0x11ab, 0,
+#undef V10562
+#define V10562 (V + 41197)
+ 0x1110, 0x1167, 0x11ac, 0,
+#undef V10563
+#define V10563 (V + 41201)
+ 0x1110, 0x1167, 0x11ad, 0,
+#undef V10564
+#define V10564 (V + 41205)
+ 0x1110, 0x1167, 0x11ae, 0,
+#undef V10565
+#define V10565 (V + 41209)
+ 0x1110, 0x1167, 0x11af, 0,
+#undef V10566
+#define V10566 (V + 41213)
+ 0x1110, 0x1167, 0x11b0, 0,
+#undef V10567
+#define V10567 (V + 41217)
+ 0x1110, 0x1167, 0x11b1, 0,
+#undef V10568
+#define V10568 (V + 41221)
+ 0x1110, 0x1167, 0x11b2, 0,
+#undef V10569
+#define V10569 (V + 41225)
+ 0x1110, 0x1167, 0x11b3, 0,
+#undef V10570
+#define V10570 (V + 41229)
+ 0x1110, 0x1167, 0x11b4, 0,
+#undef V10571
+#define V10571 (V + 41233)
+ 0x1110, 0x1167, 0x11b5, 0,
+#undef V10572
+#define V10572 (V + 41237)
+ 0x1110, 0x1167, 0x11b6, 0,
+#undef V10573
+#define V10573 (V + 41241)
+ 0x1110, 0x1167, 0x11b7, 0,
+#undef V10574
+#define V10574 (V + 41245)
+ 0x1110, 0x1167, 0x11b8, 0,
+#undef V10575
+#define V10575 (V + 41249)
+ 0x1110, 0x1167, 0x11b9, 0,
+#undef V10576
+#define V10576 (V + 41253)
+ 0x1110, 0x1167, 0x11ba, 0,
+#undef V10577
+#define V10577 (V + 41257)
+ 0x1110, 0x1167, 0x11bb, 0,
+#undef V10578
+#define V10578 (V + 41261)
+ 0x1110, 0x1167, 0x11bc, 0,
+#undef V10579
+#define V10579 (V + 41265)
+ 0x1110, 0x1167, 0x11bd, 0,
+#undef V10580
+#define V10580 (V + 41269)
+ 0x1110, 0x1167, 0x11be, 0,
+#undef V10581
+#define V10581 (V + 41273)
+ 0x1110, 0x1167, 0x11bf, 0,
+#undef V10582
+#define V10582 (V + 41277)
+ 0x1110, 0x1167, 0x11c0, 0,
+#undef V10583
+#define V10583 (V + 41281)
+ 0x1110, 0x1167, 0x11c1, 0,
+#undef V10584
+#define V10584 (V + 41285)
+ 0x1110, 0x1167, 0x11c2, 0,
+#undef V10585
+#define V10585 (V + 41289)
+ 0x1110, 0x1168, 0,
+#undef V10586
+#define V10586 (V + 41292)
+ 0x1110, 0x1168, 0x11a8, 0,
+#undef V10587
+#define V10587 (V + 41296)
+ 0x1110, 0x1168, 0x11a9, 0,
+#undef V10588
+#define V10588 (V + 41300)
+ 0x1110, 0x1168, 0x11aa, 0,
+#undef V10589
+#define V10589 (V + 41304)
+ 0x1110, 0x1168, 0x11ab, 0,
+#undef V10590
+#define V10590 (V + 41308)
+ 0x1110, 0x1168, 0x11ac, 0,
+#undef V10591
+#define V10591 (V + 41312)
+ 0x1110, 0x1168, 0x11ad, 0,
+#undef V10592
+#define V10592 (V + 41316)
+ 0x1110, 0x1168, 0x11ae, 0,
+#undef V10593
+#define V10593 (V + 41320)
+ 0x1110, 0x1168, 0x11af, 0,
+#undef V10594
+#define V10594 (V + 41324)
+ 0x1110, 0x1168, 0x11b0, 0,
+#undef V10595
+#define V10595 (V + 41328)
+ 0x1110, 0x1168, 0x11b1, 0,
+#undef V10596
+#define V10596 (V + 41332)
+ 0x1110, 0x1168, 0x11b2, 0,
+#undef V10597
+#define V10597 (V + 41336)
+ 0x1110, 0x1168, 0x11b3, 0,
+#undef V10598
+#define V10598 (V + 41340)
+ 0x1110, 0x1168, 0x11b4, 0,
+#undef V10599
+#define V10599 (V + 41344)
+ 0x1110, 0x1168, 0x11b5, 0,
+#undef V10600
+#define V10600 (V + 41348)
+ 0x1110, 0x1168, 0x11b6, 0,
+#undef V10601
+#define V10601 (V + 41352)
+ 0x1110, 0x1168, 0x11b7, 0,
+#undef V10602
+#define V10602 (V + 41356)
+ 0x1110, 0x1168, 0x11b8, 0,
+#undef V10603
+#define V10603 (V + 41360)
+ 0x1110, 0x1168, 0x11b9, 0,
+#undef V10604
+#define V10604 (V + 41364)
+ 0x1110, 0x1168, 0x11ba, 0,
+#undef V10605
+#define V10605 (V + 41368)
+ 0x1110, 0x1168, 0x11bb, 0,
+#undef V10606
+#define V10606 (V + 41372)
+ 0x1110, 0x1168, 0x11bc, 0,
+#undef V10607
+#define V10607 (V + 41376)
+ 0x1110, 0x1168, 0x11bd, 0,
+#undef V10608
+#define V10608 (V + 41380)
+ 0x1110, 0x1168, 0x11be, 0,
+#undef V10609
+#define V10609 (V + 41384)
+ 0x1110, 0x1168, 0x11bf, 0,
+#undef V10610
+#define V10610 (V + 41388)
+ 0x1110, 0x1168, 0x11c0, 0,
+#undef V10611
+#define V10611 (V + 41392)
+ 0x1110, 0x1168, 0x11c1, 0,
+#undef V10612
+#define V10612 (V + 41396)
+ 0x1110, 0x1168, 0x11c2, 0,
+#undef V10613
+#define V10613 (V + 41400)
+ 0x1110, 0x1169, 0,
+#undef V10614
+#define V10614 (V + 41403)
+ 0x1110, 0x1169, 0x11a8, 0,
+#undef V10615
+#define V10615 (V + 41407)
+ 0x1110, 0x1169, 0x11a9, 0,
+#undef V10616
+#define V10616 (V + 41411)
+ 0x1110, 0x1169, 0x11aa, 0,
+#undef V10617
+#define V10617 (V + 41415)
+ 0x1110, 0x1169, 0x11ab, 0,
+#undef V10618
+#define V10618 (V + 41419)
+ 0x1110, 0x1169, 0x11ac, 0,
+#undef V10619
+#define V10619 (V + 41423)
+ 0x1110, 0x1169, 0x11ad, 0,
+#undef V10620
+#define V10620 (V + 41427)
+ 0x1110, 0x1169, 0x11ae, 0,
+#undef V10621
+#define V10621 (V + 41431)
+ 0x1110, 0x1169, 0x11af, 0,
+#undef V10622
+#define V10622 (V + 41435)
+ 0x1110, 0x1169, 0x11b0, 0,
+#undef V10623
+#define V10623 (V + 41439)
+ 0x1110, 0x1169, 0x11b1, 0,
+#undef V10624
+#define V10624 (V + 41443)
+ 0x1110, 0x1169, 0x11b2, 0,
+#undef V10625
+#define V10625 (V + 41447)
+ 0x1110, 0x1169, 0x11b3, 0,
+#undef V10626
+#define V10626 (V + 41451)
+ 0x1110, 0x1169, 0x11b4, 0,
+#undef V10627
+#define V10627 (V + 41455)
+ 0x1110, 0x1169, 0x11b5, 0,
+#undef V10628
+#define V10628 (V + 41459)
+ 0x1110, 0x1169, 0x11b6, 0,
+#undef V10629
+#define V10629 (V + 41463)
+ 0x1110, 0x1169, 0x11b7, 0,
+#undef V10630
+#define V10630 (V + 41467)
+ 0x1110, 0x1169, 0x11b8, 0,
+#undef V10631
+#define V10631 (V + 41471)
+ 0x1110, 0x1169, 0x11b9, 0,
+#undef V10632
+#define V10632 (V + 41475)
+ 0x1110, 0x1169, 0x11ba, 0,
+#undef V10633
+#define V10633 (V + 41479)
+ 0x1110, 0x1169, 0x11bb, 0,
+#undef V10634
+#define V10634 (V + 41483)
+ 0x1110, 0x1169, 0x11bc, 0,
+#undef V10635
+#define V10635 (V + 41487)
+ 0x1110, 0x1169, 0x11bd, 0,
+#undef V10636
+#define V10636 (V + 41491)
+ 0x1110, 0x1169, 0x11be, 0,
+#undef V10637
+#define V10637 (V + 41495)
+ 0x1110, 0x1169, 0x11bf, 0,
+#undef V10638
+#define V10638 (V + 41499)
+ 0x1110, 0x1169, 0x11c0, 0,
+#undef V10639
+#define V10639 (V + 41503)
+ 0x1110, 0x1169, 0x11c1, 0,
+#undef V10640
+#define V10640 (V + 41507)
+ 0x1110, 0x1169, 0x11c2, 0,
+#undef V10641
+#define V10641 (V + 41511)
+ 0x1110, 0x116a, 0,
+#undef V10642
+#define V10642 (V + 41514)
+ 0x1110, 0x116a, 0x11a8, 0,
+#undef V10643
+#define V10643 (V + 41518)
+ 0x1110, 0x116a, 0x11a9, 0,
+#undef V10644
+#define V10644 (V + 41522)
+ 0x1110, 0x116a, 0x11aa, 0,
+#undef V10645
+#define V10645 (V + 41526)
+ 0x1110, 0x116a, 0x11ab, 0,
+#undef V10646
+#define V10646 (V + 41530)
+ 0x1110, 0x116a, 0x11ac, 0,
+#undef V10647
+#define V10647 (V + 41534)
+ 0x1110, 0x116a, 0x11ad, 0,
+#undef V10648
+#define V10648 (V + 41538)
+ 0x1110, 0x116a, 0x11ae, 0,
+#undef V10649
+#define V10649 (V + 41542)
+ 0x1110, 0x116a, 0x11af, 0,
+#undef V10650
+#define V10650 (V + 41546)
+ 0x1110, 0x116a, 0x11b0, 0,
+#undef V10651
+#define V10651 (V + 41550)
+ 0x1110, 0x116a, 0x11b1, 0,
+#undef V10652
+#define V10652 (V + 41554)
+ 0x1110, 0x116a, 0x11b2, 0,
+#undef V10653
+#define V10653 (V + 41558)
+ 0x1110, 0x116a, 0x11b3, 0,
+#undef V10654
+#define V10654 (V + 41562)
+ 0x1110, 0x116a, 0x11b4, 0,
+#undef V10655
+#define V10655 (V + 41566)
+ 0x1110, 0x116a, 0x11b5, 0,
+#undef V10656
+#define V10656 (V + 41570)
+ 0x1110, 0x116a, 0x11b6, 0,
+#undef V10657
+#define V10657 (V + 41574)
+ 0x1110, 0x116a, 0x11b7, 0,
+#undef V10658
+#define V10658 (V + 41578)
+ 0x1110, 0x116a, 0x11b8, 0,
+#undef V10659
+#define V10659 (V + 41582)
+ 0x1110, 0x116a, 0x11b9, 0,
+#undef V10660
+#define V10660 (V + 41586)
+ 0x1110, 0x116a, 0x11ba, 0,
+#undef V10661
+#define V10661 (V + 41590)
+ 0x1110, 0x116a, 0x11bb, 0,
+#undef V10662
+#define V10662 (V + 41594)
+ 0x1110, 0x116a, 0x11bc, 0,
+#undef V10663
+#define V10663 (V + 41598)
+ 0x1110, 0x116a, 0x11bd, 0,
+#undef V10664
+#define V10664 (V + 41602)
+ 0x1110, 0x116a, 0x11be, 0,
+#undef V10665
+#define V10665 (V + 41606)
+ 0x1110, 0x116a, 0x11bf, 0,
+#undef V10666
+#define V10666 (V + 41610)
+ 0x1110, 0x116a, 0x11c0, 0,
+#undef V10667
+#define V10667 (V + 41614)
+ 0x1110, 0x116a, 0x11c1, 0,
+#undef V10668
+#define V10668 (V + 41618)
+ 0x1110, 0x116a, 0x11c2, 0,
+#undef V10669
+#define V10669 (V + 41622)
+ 0x1110, 0x116b, 0,
+#undef V10670
+#define V10670 (V + 41625)
+ 0x1110, 0x116b, 0x11a8, 0,
+#undef V10671
+#define V10671 (V + 41629)
+ 0x1110, 0x116b, 0x11a9, 0,
+#undef V10672
+#define V10672 (V + 41633)
+ 0x1110, 0x116b, 0x11aa, 0,
+#undef V10673
+#define V10673 (V + 41637)
+ 0x1110, 0x116b, 0x11ab, 0,
+#undef V10674
+#define V10674 (V + 41641)
+ 0x1110, 0x116b, 0x11ac, 0,
+#undef V10675
+#define V10675 (V + 41645)
+ 0x1110, 0x116b, 0x11ad, 0,
+#undef V10676
+#define V10676 (V + 41649)
+ 0x1110, 0x116b, 0x11ae, 0,
+#undef V10677
+#define V10677 (V + 41653)
+ 0x1110, 0x116b, 0x11af, 0,
+#undef V10678
+#define V10678 (V + 41657)
+ 0x1110, 0x116b, 0x11b0, 0,
+#undef V10679
+#define V10679 (V + 41661)
+ 0x1110, 0x116b, 0x11b1, 0,
+#undef V10680
+#define V10680 (V + 41665)
+ 0x1110, 0x116b, 0x11b2, 0,
+#undef V10681
+#define V10681 (V + 41669)
+ 0x1110, 0x116b, 0x11b3, 0,
+#undef V10682
+#define V10682 (V + 41673)
+ 0x1110, 0x116b, 0x11b4, 0,
+#undef V10683
+#define V10683 (V + 41677)
+ 0x1110, 0x116b, 0x11b5, 0,
+#undef V10684
+#define V10684 (V + 41681)
+ 0x1110, 0x116b, 0x11b6, 0,
+#undef V10685
+#define V10685 (V + 41685)
+ 0x1110, 0x116b, 0x11b7, 0,
+#undef V10686
+#define V10686 (V + 41689)
+ 0x1110, 0x116b, 0x11b8, 0,
+#undef V10687
+#define V10687 (V + 41693)
+ 0x1110, 0x116b, 0x11b9, 0,
+#undef V10688
+#define V10688 (V + 41697)
+ 0x1110, 0x116b, 0x11ba, 0,
+#undef V10689
+#define V10689 (V + 41701)
+ 0x1110, 0x116b, 0x11bb, 0,
+#undef V10690
+#define V10690 (V + 41705)
+ 0x1110, 0x116b, 0x11bc, 0,
+#undef V10691
+#define V10691 (V + 41709)
+ 0x1110, 0x116b, 0x11bd, 0,
+#undef V10692
+#define V10692 (V + 41713)
+ 0x1110, 0x116b, 0x11be, 0,
+#undef V10693
+#define V10693 (V + 41717)
+ 0x1110, 0x116b, 0x11bf, 0,
+#undef V10694
+#define V10694 (V + 41721)
+ 0x1110, 0x116b, 0x11c0, 0,
+#undef V10695
+#define V10695 (V + 41725)
+ 0x1110, 0x116b, 0x11c1, 0,
+#undef V10696
+#define V10696 (V + 41729)
+ 0x1110, 0x116b, 0x11c2, 0,
+#undef V10697
+#define V10697 (V + 41733)
+ 0x1110, 0x116c, 0,
+#undef V10698
+#define V10698 (V + 41736)
+ 0x1110, 0x116c, 0x11a8, 0,
+#undef V10699
+#define V10699 (V + 41740)
+ 0x1110, 0x116c, 0x11a9, 0,
+#undef V10700
+#define V10700 (V + 41744)
+ 0x1110, 0x116c, 0x11aa, 0,
+#undef V10701
+#define V10701 (V + 41748)
+ 0x1110, 0x116c, 0x11ab, 0,
+#undef V10702
+#define V10702 (V + 41752)
+ 0x1110, 0x116c, 0x11ac, 0,
+#undef V10703
+#define V10703 (V + 41756)
+ 0x1110, 0x116c, 0x11ad, 0,
+#undef V10704
+#define V10704 (V + 41760)
+ 0x1110, 0x116c, 0x11ae, 0,
+#undef V10705
+#define V10705 (V + 41764)
+ 0x1110, 0x116c, 0x11af, 0,
+#undef V10706
+#define V10706 (V + 41768)
+ 0x1110, 0x116c, 0x11b0, 0,
+#undef V10707
+#define V10707 (V + 41772)
+ 0x1110, 0x116c, 0x11b1, 0,
+#undef V10708
+#define V10708 (V + 41776)
+ 0x1110, 0x116c, 0x11b2, 0,
+#undef V10709
+#define V10709 (V + 41780)
+ 0x1110, 0x116c, 0x11b3, 0,
+#undef V10710
+#define V10710 (V + 41784)
+ 0x1110, 0x116c, 0x11b4, 0,
+#undef V10711
+#define V10711 (V + 41788)
+ 0x1110, 0x116c, 0x11b5, 0,
+#undef V10712
+#define V10712 (V + 41792)
+ 0x1110, 0x116c, 0x11b6, 0,
+#undef V10713
+#define V10713 (V + 41796)
+ 0x1110, 0x116c, 0x11b7, 0,
+#undef V10714
+#define V10714 (V + 41800)
+ 0x1110, 0x116c, 0x11b8, 0,
+#undef V10715
+#define V10715 (V + 41804)
+ 0x1110, 0x116c, 0x11b9, 0,
+#undef V10716
+#define V10716 (V + 41808)
+ 0x1110, 0x116c, 0x11ba, 0,
+#undef V10717
+#define V10717 (V + 41812)
+ 0x1110, 0x116c, 0x11bb, 0,
+#undef V10718
+#define V10718 (V + 41816)
+ 0x1110, 0x116c, 0x11bc, 0,
+#undef V10719
+#define V10719 (V + 41820)
+ 0x1110, 0x116c, 0x11bd, 0,
+#undef V10720
+#define V10720 (V + 41824)
+ 0x1110, 0x116c, 0x11be, 0,
+#undef V10721
+#define V10721 (V + 41828)
+ 0x1110, 0x116c, 0x11bf, 0,
+#undef V10722
+#define V10722 (V + 41832)
+ 0x1110, 0x116c, 0x11c0, 0,
+#undef V10723
+#define V10723 (V + 41836)
+ 0x1110, 0x116c, 0x11c1, 0,
+#undef V10724
+#define V10724 (V + 41840)
+ 0x1110, 0x116c, 0x11c2, 0,
+#undef V10725
+#define V10725 (V + 41844)
+ 0x1110, 0x116d, 0,
+#undef V10726
+#define V10726 (V + 41847)
+ 0x1110, 0x116d, 0x11a8, 0,
+#undef V10727
+#define V10727 (V + 41851)
+ 0x1110, 0x116d, 0x11a9, 0,
+#undef V10728
+#define V10728 (V + 41855)
+ 0x1110, 0x116d, 0x11aa, 0,
+#undef V10729
+#define V10729 (V + 41859)
+ 0x1110, 0x116d, 0x11ab, 0,
+#undef V10730
+#define V10730 (V + 41863)
+ 0x1110, 0x116d, 0x11ac, 0,
+#undef V10731
+#define V10731 (V + 41867)
+ 0x1110, 0x116d, 0x11ad, 0,
+#undef V10732
+#define V10732 (V + 41871)
+ 0x1110, 0x116d, 0x11ae, 0,
+#undef V10733
+#define V10733 (V + 41875)
+ 0x1110, 0x116d, 0x11af, 0,
+#undef V10734
+#define V10734 (V + 41879)
+ 0x1110, 0x116d, 0x11b0, 0,
+#undef V10735
+#define V10735 (V + 41883)
+ 0x1110, 0x116d, 0x11b1, 0,
+#undef V10736
+#define V10736 (V + 41887)
+ 0x1110, 0x116d, 0x11b2, 0,
+#undef V10737
+#define V10737 (V + 41891)
+ 0x1110, 0x116d, 0x11b3, 0,
+#undef V10738
+#define V10738 (V + 41895)
+ 0x1110, 0x116d, 0x11b4, 0,
+#undef V10739
+#define V10739 (V + 41899)
+ 0x1110, 0x116d, 0x11b5, 0,
+#undef V10740
+#define V10740 (V + 41903)
+ 0x1110, 0x116d, 0x11b6, 0,
+#undef V10741
+#define V10741 (V + 41907)
+ 0x1110, 0x116d, 0x11b7, 0,
+#undef V10742
+#define V10742 (V + 41911)
+ 0x1110, 0x116d, 0x11b8, 0,
+#undef V10743
+#define V10743 (V + 41915)
+ 0x1110, 0x116d, 0x11b9, 0,
+#undef V10744
+#define V10744 (V + 41919)
+ 0x1110, 0x116d, 0x11ba, 0,
+#undef V10745
+#define V10745 (V + 41923)
+ 0x1110, 0x116d, 0x11bb, 0,
+#undef V10746
+#define V10746 (V + 41927)
+ 0x1110, 0x116d, 0x11bc, 0,
+#undef V10747
+#define V10747 (V + 41931)
+ 0x1110, 0x116d, 0x11bd, 0,
+#undef V10748
+#define V10748 (V + 41935)
+ 0x1110, 0x116d, 0x11be, 0,
+#undef V10749
+#define V10749 (V + 41939)
+ 0x1110, 0x116d, 0x11bf, 0,
+#undef V10750
+#define V10750 (V + 41943)
+ 0x1110, 0x116d, 0x11c0, 0,
+#undef V10751
+#define V10751 (V + 41947)
+ 0x1110, 0x116d, 0x11c1, 0,
+#undef V10752
+#define V10752 (V + 41951)
+ 0x1110, 0x116d, 0x11c2, 0,
+#undef V10753
+#define V10753 (V + 41955)
+ 0x1110, 0x116e, 0,
+#undef V10754
+#define V10754 (V + 41958)
+ 0x1110, 0x116e, 0x11a8, 0,
+#undef V10755
+#define V10755 (V + 41962)
+ 0x1110, 0x116e, 0x11a9, 0,
+#undef V10756
+#define V10756 (V + 41966)
+ 0x1110, 0x116e, 0x11aa, 0,
+#undef V10757
+#define V10757 (V + 41970)
+ 0x1110, 0x116e, 0x11ab, 0,
+#undef V10758
+#define V10758 (V + 41974)
+ 0x1110, 0x116e, 0x11ac, 0,
+#undef V10759
+#define V10759 (V + 41978)
+ 0x1110, 0x116e, 0x11ad, 0,
+#undef V10760
+#define V10760 (V + 41982)
+ 0x1110, 0x116e, 0x11ae, 0,
+#undef V10761
+#define V10761 (V + 41986)
+ 0x1110, 0x116e, 0x11af, 0,
+#undef V10762
+#define V10762 (V + 41990)
+ 0x1110, 0x116e, 0x11b0, 0,
+#undef V10763
+#define V10763 (V + 41994)
+ 0x1110, 0x116e, 0x11b1, 0,
+#undef V10764
+#define V10764 (V + 41998)
+ 0x1110, 0x116e, 0x11b2, 0,
+#undef V10765
+#define V10765 (V + 42002)
+ 0x1110, 0x116e, 0x11b3, 0,
+#undef V10766
+#define V10766 (V + 42006)
+ 0x1110, 0x116e, 0x11b4, 0,
+#undef V10767
+#define V10767 (V + 42010)
+ 0x1110, 0x116e, 0x11b5, 0,
+#undef V10768
+#define V10768 (V + 42014)
+ 0x1110, 0x116e, 0x11b6, 0,
+#undef V10769
+#define V10769 (V + 42018)
+ 0x1110, 0x116e, 0x11b7, 0,
+#undef V10770
+#define V10770 (V + 42022)
+ 0x1110, 0x116e, 0x11b8, 0,
+#undef V10771
+#define V10771 (V + 42026)
+ 0x1110, 0x116e, 0x11b9, 0,
+#undef V10772
+#define V10772 (V + 42030)
+ 0x1110, 0x116e, 0x11ba, 0,
+#undef V10773
+#define V10773 (V + 42034)
+ 0x1110, 0x116e, 0x11bb, 0,
+#undef V10774
+#define V10774 (V + 42038)
+ 0x1110, 0x116e, 0x11bc, 0,
+#undef V10775
+#define V10775 (V + 42042)
+ 0x1110, 0x116e, 0x11bd, 0,
+#undef V10776
+#define V10776 (V + 42046)
+ 0x1110, 0x116e, 0x11be, 0,
+#undef V10777
+#define V10777 (V + 42050)
+ 0x1110, 0x116e, 0x11bf, 0,
+#undef V10778
+#define V10778 (V + 42054)
+ 0x1110, 0x116e, 0x11c0, 0,
+#undef V10779
+#define V10779 (V + 42058)
+ 0x1110, 0x116e, 0x11c1, 0,
+#undef V10780
+#define V10780 (V + 42062)
+ 0x1110, 0x116e, 0x11c2, 0,
+#undef V10781
+#define V10781 (V + 42066)
+ 0x1110, 0x116f, 0,
+#undef V10782
+#define V10782 (V + 42069)
+ 0x1110, 0x116f, 0x11a8, 0,
+#undef V10783
+#define V10783 (V + 42073)
+ 0x1110, 0x116f, 0x11a9, 0,
+#undef V10784
+#define V10784 (V + 42077)
+ 0x1110, 0x116f, 0x11aa, 0,
+#undef V10785
+#define V10785 (V + 42081)
+ 0x1110, 0x116f, 0x11ab, 0,
+#undef V10786
+#define V10786 (V + 42085)
+ 0x1110, 0x116f, 0x11ac, 0,
+#undef V10787
+#define V10787 (V + 42089)
+ 0x1110, 0x116f, 0x11ad, 0,
+#undef V10788
+#define V10788 (V + 42093)
+ 0x1110, 0x116f, 0x11ae, 0,
+#undef V10789
+#define V10789 (V + 42097)
+ 0x1110, 0x116f, 0x11af, 0,
+#undef V10790
+#define V10790 (V + 42101)
+ 0x1110, 0x116f, 0x11b0, 0,
+#undef V10791
+#define V10791 (V + 42105)
+ 0x1110, 0x116f, 0x11b1, 0,
+#undef V10792
+#define V10792 (V + 42109)
+ 0x1110, 0x116f, 0x11b2, 0,
+#undef V10793
+#define V10793 (V + 42113)
+ 0x1110, 0x116f, 0x11b3, 0,
+#undef V10794
+#define V10794 (V + 42117)
+ 0x1110, 0x116f, 0x11b4, 0,
+#undef V10795
+#define V10795 (V + 42121)
+ 0x1110, 0x116f, 0x11b5, 0,
+#undef V10796
+#define V10796 (V + 42125)
+ 0x1110, 0x116f, 0x11b6, 0,
+#undef V10797
+#define V10797 (V + 42129)
+ 0x1110, 0x116f, 0x11b7, 0,
+#undef V10798
+#define V10798 (V + 42133)
+ 0x1110, 0x116f, 0x11b8, 0,
+#undef V10799
+#define V10799 (V + 42137)
+ 0x1110, 0x116f, 0x11b9, 0,
+#undef V10800
+#define V10800 (V + 42141)
+ 0x1110, 0x116f, 0x11ba, 0,
+#undef V10801
+#define V10801 (V + 42145)
+ 0x1110, 0x116f, 0x11bb, 0,
+#undef V10802
+#define V10802 (V + 42149)
+ 0x1110, 0x116f, 0x11bc, 0,
+#undef V10803
+#define V10803 (V + 42153)
+ 0x1110, 0x116f, 0x11bd, 0,
+#undef V10804
+#define V10804 (V + 42157)
+ 0x1110, 0x116f, 0x11be, 0,
+#undef V10805
+#define V10805 (V + 42161)
+ 0x1110, 0x116f, 0x11bf, 0,
+#undef V10806
+#define V10806 (V + 42165)
+ 0x1110, 0x116f, 0x11c0, 0,
+#undef V10807
+#define V10807 (V + 42169)
+ 0x1110, 0x116f, 0x11c1, 0,
+#undef V10808
+#define V10808 (V + 42173)
+ 0x1110, 0x116f, 0x11c2, 0,
+#undef V10809
+#define V10809 (V + 42177)
+ 0x1110, 0x1170, 0,
+#undef V10810
+#define V10810 (V + 42180)
+ 0x1110, 0x1170, 0x11a8, 0,
+#undef V10811
+#define V10811 (V + 42184)
+ 0x1110, 0x1170, 0x11a9, 0,
+#undef V10812
+#define V10812 (V + 42188)
+ 0x1110, 0x1170, 0x11aa, 0,
+#undef V10813
+#define V10813 (V + 42192)
+ 0x1110, 0x1170, 0x11ab, 0,
+#undef V10814
+#define V10814 (V + 42196)
+ 0x1110, 0x1170, 0x11ac, 0,
+#undef V10815
+#define V10815 (V + 42200)
+ 0x1110, 0x1170, 0x11ad, 0,
+#undef V10816
+#define V10816 (V + 42204)
+ 0x1110, 0x1170, 0x11ae, 0,
+#undef V10817
+#define V10817 (V + 42208)
+ 0x1110, 0x1170, 0x11af, 0,
+#undef V10818
+#define V10818 (V + 42212)
+ 0x1110, 0x1170, 0x11b0, 0,
+#undef V10819
+#define V10819 (V + 42216)
+ 0x1110, 0x1170, 0x11b1, 0,
+#undef V10820
+#define V10820 (V + 42220)
+ 0x1110, 0x1170, 0x11b2, 0,
+#undef V10821
+#define V10821 (V + 42224)
+ 0x1110, 0x1170, 0x11b3, 0,
+#undef V10822
+#define V10822 (V + 42228)
+ 0x1110, 0x1170, 0x11b4, 0,
+#undef V10823
+#define V10823 (V + 42232)
+ 0x1110, 0x1170, 0x11b5, 0,
+#undef V10824
+#define V10824 (V + 42236)
+ 0x1110, 0x1170, 0x11b6, 0,
+#undef V10825
+#define V10825 (V + 42240)
+ 0x1110, 0x1170, 0x11b7, 0,
+#undef V10826
+#define V10826 (V + 42244)
+ 0x1110, 0x1170, 0x11b8, 0,
+#undef V10827
+#define V10827 (V + 42248)
+ 0x1110, 0x1170, 0x11b9, 0,
+#undef V10828
+#define V10828 (V + 42252)
+ 0x1110, 0x1170, 0x11ba, 0,
+#undef V10829
+#define V10829 (V + 42256)
+ 0x1110, 0x1170, 0x11bb, 0,
+#undef V10830
+#define V10830 (V + 42260)
+ 0x1110, 0x1170, 0x11bc, 0,
+#undef V10831
+#define V10831 (V + 42264)
+ 0x1110, 0x1170, 0x11bd, 0,
+#undef V10832
+#define V10832 (V + 42268)
+ 0x1110, 0x1170, 0x11be, 0,
+#undef V10833
+#define V10833 (V + 42272)
+ 0x1110, 0x1170, 0x11bf, 0,
+#undef V10834
+#define V10834 (V + 42276)
+ 0x1110, 0x1170, 0x11c0, 0,
+#undef V10835
+#define V10835 (V + 42280)
+ 0x1110, 0x1170, 0x11c1, 0,
+#undef V10836
+#define V10836 (V + 42284)
+ 0x1110, 0x1170, 0x11c2, 0,
+#undef V10837
+#define V10837 (V + 42288)
+ 0x1110, 0x1171, 0,
+#undef V10838
+#define V10838 (V + 42291)
+ 0x1110, 0x1171, 0x11a8, 0,
+#undef V10839
+#define V10839 (V + 42295)
+ 0x1110, 0x1171, 0x11a9, 0,
+#undef V10840
+#define V10840 (V + 42299)
+ 0x1110, 0x1171, 0x11aa, 0,
+#undef V10841
+#define V10841 (V + 42303)
+ 0x1110, 0x1171, 0x11ab, 0,
+#undef V10842
+#define V10842 (V + 42307)
+ 0x1110, 0x1171, 0x11ac, 0,
+#undef V10843
+#define V10843 (V + 42311)
+ 0x1110, 0x1171, 0x11ad, 0,
+#undef V10844
+#define V10844 (V + 42315)
+ 0x1110, 0x1171, 0x11ae, 0,
+#undef V10845
+#define V10845 (V + 42319)
+ 0x1110, 0x1171, 0x11af, 0,
+#undef V10846
+#define V10846 (V + 42323)
+ 0x1110, 0x1171, 0x11b0, 0,
+#undef V10847
+#define V10847 (V + 42327)
+ 0x1110, 0x1171, 0x11b1, 0,
+#undef V10848
+#define V10848 (V + 42331)
+ 0x1110, 0x1171, 0x11b2, 0,
+#undef V10849
+#define V10849 (V + 42335)
+ 0x1110, 0x1171, 0x11b3, 0,
+#undef V10850
+#define V10850 (V + 42339)
+ 0x1110, 0x1171, 0x11b4, 0,
+#undef V10851
+#define V10851 (V + 42343)
+ 0x1110, 0x1171, 0x11b5, 0,
+#undef V10852
+#define V10852 (V + 42347)
+ 0x1110, 0x1171, 0x11b6, 0,
+#undef V10853
+#define V10853 (V + 42351)
+ 0x1110, 0x1171, 0x11b7, 0,
+#undef V10854
+#define V10854 (V + 42355)
+ 0x1110, 0x1171, 0x11b8, 0,
+#undef V10855
+#define V10855 (V + 42359)
+ 0x1110, 0x1171, 0x11b9, 0,
+#undef V10856
+#define V10856 (V + 42363)
+ 0x1110, 0x1171, 0x11ba, 0,
+#undef V10857
+#define V10857 (V + 42367)
+ 0x1110, 0x1171, 0x11bb, 0,
+#undef V10858
+#define V10858 (V + 42371)
+ 0x1110, 0x1171, 0x11bc, 0,
+#undef V10859
+#define V10859 (V + 42375)
+ 0x1110, 0x1171, 0x11bd, 0,
+#undef V10860
+#define V10860 (V + 42379)
+ 0x1110, 0x1171, 0x11be, 0,
+#undef V10861
+#define V10861 (V + 42383)
+ 0x1110, 0x1171, 0x11bf, 0,
+#undef V10862
+#define V10862 (V + 42387)
+ 0x1110, 0x1171, 0x11c0, 0,
+#undef V10863
+#define V10863 (V + 42391)
+ 0x1110, 0x1171, 0x11c1, 0,
+#undef V10864
+#define V10864 (V + 42395)
+ 0x1110, 0x1171, 0x11c2, 0,
+#undef V10865
+#define V10865 (V + 42399)
+ 0x1110, 0x1172, 0,
+#undef V10866
+#define V10866 (V + 42402)
+ 0x1110, 0x1172, 0x11a8, 0,
+#undef V10867
+#define V10867 (V + 42406)
+ 0x1110, 0x1172, 0x11a9, 0,
+#undef V10868
+#define V10868 (V + 42410)
+ 0x1110, 0x1172, 0x11aa, 0,
+#undef V10869
+#define V10869 (V + 42414)
+ 0x1110, 0x1172, 0x11ab, 0,
+#undef V10870
+#define V10870 (V + 42418)
+ 0x1110, 0x1172, 0x11ac, 0,
+#undef V10871
+#define V10871 (V + 42422)
+ 0x1110, 0x1172, 0x11ad, 0,
+#undef V10872
+#define V10872 (V + 42426)
+ 0x1110, 0x1172, 0x11ae, 0,
+#undef V10873
+#define V10873 (V + 42430)
+ 0x1110, 0x1172, 0x11af, 0,
+#undef V10874
+#define V10874 (V + 42434)
+ 0x1110, 0x1172, 0x11b0, 0,
+#undef V10875
+#define V10875 (V + 42438)
+ 0x1110, 0x1172, 0x11b1, 0,
+#undef V10876
+#define V10876 (V + 42442)
+ 0x1110, 0x1172, 0x11b2, 0,
+#undef V10877
+#define V10877 (V + 42446)
+ 0x1110, 0x1172, 0x11b3, 0,
+#undef V10878
+#define V10878 (V + 42450)
+ 0x1110, 0x1172, 0x11b4, 0,
+#undef V10879
+#define V10879 (V + 42454)
+ 0x1110, 0x1172, 0x11b5, 0,
+#undef V10880
+#define V10880 (V + 42458)
+ 0x1110, 0x1172, 0x11b6, 0,
+#undef V10881
+#define V10881 (V + 42462)
+ 0x1110, 0x1172, 0x11b7, 0,
+#undef V10882
+#define V10882 (V + 42466)
+ 0x1110, 0x1172, 0x11b8, 0,
+#undef V10883
+#define V10883 (V + 42470)
+ 0x1110, 0x1172, 0x11b9, 0,
+#undef V10884
+#define V10884 (V + 42474)
+ 0x1110, 0x1172, 0x11ba, 0,
+#undef V10885
+#define V10885 (V + 42478)
+ 0x1110, 0x1172, 0x11bb, 0,
+#undef V10886
+#define V10886 (V + 42482)
+ 0x1110, 0x1172, 0x11bc, 0,
+#undef V10887
+#define V10887 (V + 42486)
+ 0x1110, 0x1172, 0x11bd, 0,
+#undef V10888
+#define V10888 (V + 42490)
+ 0x1110, 0x1172, 0x11be, 0,
+#undef V10889
+#define V10889 (V + 42494)
+ 0x1110, 0x1172, 0x11bf, 0,
+#undef V10890
+#define V10890 (V + 42498)
+ 0x1110, 0x1172, 0x11c0, 0,
+#undef V10891
+#define V10891 (V + 42502)
+ 0x1110, 0x1172, 0x11c1, 0,
+#undef V10892
+#define V10892 (V + 42506)
+ 0x1110, 0x1172, 0x11c2, 0,
+#undef V10893
+#define V10893 (V + 42510)
+ 0x1110, 0x1173, 0,
+#undef V10894
+#define V10894 (V + 42513)
+ 0x1110, 0x1173, 0x11a8, 0,
+#undef V10895
+#define V10895 (V + 42517)
+ 0x1110, 0x1173, 0x11a9, 0,
+#undef V10896
+#define V10896 (V + 42521)
+ 0x1110, 0x1173, 0x11aa, 0,
+#undef V10897
+#define V10897 (V + 42525)
+ 0x1110, 0x1173, 0x11ab, 0,
+#undef V10898
+#define V10898 (V + 42529)
+ 0x1110, 0x1173, 0x11ac, 0,
+#undef V10899
+#define V10899 (V + 42533)
+ 0x1110, 0x1173, 0x11ad, 0,
+#undef V10900
+#define V10900 (V + 42537)
+ 0x1110, 0x1173, 0x11ae, 0,
+#undef V10901
+#define V10901 (V + 42541)
+ 0x1110, 0x1173, 0x11af, 0,
+#undef V10902
+#define V10902 (V + 42545)
+ 0x1110, 0x1173, 0x11b0, 0,
+#undef V10903
+#define V10903 (V + 42549)
+ 0x1110, 0x1173, 0x11b1, 0,
+#undef V10904
+#define V10904 (V + 42553)
+ 0x1110, 0x1173, 0x11b2, 0,
+#undef V10905
+#define V10905 (V + 42557)
+ 0x1110, 0x1173, 0x11b3, 0,
+#undef V10906
+#define V10906 (V + 42561)
+ 0x1110, 0x1173, 0x11b4, 0,
+#undef V10907
+#define V10907 (V + 42565)
+ 0x1110, 0x1173, 0x11b5, 0,
+#undef V10908
+#define V10908 (V + 42569)
+ 0x1110, 0x1173, 0x11b6, 0,
+#undef V10909
+#define V10909 (V + 42573)
+ 0x1110, 0x1173, 0x11b7, 0,
+#undef V10910
+#define V10910 (V + 42577)
+ 0x1110, 0x1173, 0x11b8, 0,
+#undef V10911
+#define V10911 (V + 42581)
+ 0x1110, 0x1173, 0x11b9, 0,
+#undef V10912
+#define V10912 (V + 42585)
+ 0x1110, 0x1173, 0x11ba, 0,
+#undef V10913
+#define V10913 (V + 42589)
+ 0x1110, 0x1173, 0x11bb, 0,
+#undef V10914
+#define V10914 (V + 42593)
+ 0x1110, 0x1173, 0x11bc, 0,
+#undef V10915
+#define V10915 (V + 42597)
+ 0x1110, 0x1173, 0x11bd, 0,
+#undef V10916
+#define V10916 (V + 42601)
+ 0x1110, 0x1173, 0x11be, 0,
+#undef V10917
+#define V10917 (V + 42605)
+ 0x1110, 0x1173, 0x11bf, 0,
+#undef V10918
+#define V10918 (V + 42609)
+ 0x1110, 0x1173, 0x11c0, 0,
+#undef V10919
+#define V10919 (V + 42613)
+ 0x1110, 0x1173, 0x11c1, 0,
+#undef V10920
+#define V10920 (V + 42617)
+ 0x1110, 0x1173, 0x11c2, 0,
+#undef V10921
+#define V10921 (V + 42621)
+ 0x1110, 0x1174, 0,
+#undef V10922
+#define V10922 (V + 42624)
+ 0x1110, 0x1174, 0x11a8, 0,
+#undef V10923
+#define V10923 (V + 42628)
+ 0x1110, 0x1174, 0x11a9, 0,
+#undef V10924
+#define V10924 (V + 42632)
+ 0x1110, 0x1174, 0x11aa, 0,
+#undef V10925
+#define V10925 (V + 42636)
+ 0x1110, 0x1174, 0x11ab, 0,
+#undef V10926
+#define V10926 (V + 42640)
+ 0x1110, 0x1174, 0x11ac, 0,
+#undef V10927
+#define V10927 (V + 42644)
+ 0x1110, 0x1174, 0x11ad, 0,
+#undef V10928
+#define V10928 (V + 42648)
+ 0x1110, 0x1174, 0x11ae, 0,
+#undef V10929
+#define V10929 (V + 42652)
+ 0x1110, 0x1174, 0x11af, 0,
+#undef V10930
+#define V10930 (V + 42656)
+ 0x1110, 0x1174, 0x11b0, 0,
+#undef V10931
+#define V10931 (V + 42660)
+ 0x1110, 0x1174, 0x11b1, 0,
+#undef V10932
+#define V10932 (V + 42664)
+ 0x1110, 0x1174, 0x11b2, 0,
+#undef V10933
+#define V10933 (V + 42668)
+ 0x1110, 0x1174, 0x11b3, 0,
+#undef V10934
+#define V10934 (V + 42672)
+ 0x1110, 0x1174, 0x11b4, 0,
+#undef V10935
+#define V10935 (V + 42676)
+ 0x1110, 0x1174, 0x11b5, 0,
+#undef V10936
+#define V10936 (V + 42680)
+ 0x1110, 0x1174, 0x11b6, 0,
+#undef V10937
+#define V10937 (V + 42684)
+ 0x1110, 0x1174, 0x11b7, 0,
+#undef V10938
+#define V10938 (V + 42688)
+ 0x1110, 0x1174, 0x11b8, 0,
+#undef V10939
+#define V10939 (V + 42692)
+ 0x1110, 0x1174, 0x11b9, 0,
+#undef V10940
+#define V10940 (V + 42696)
+ 0x1110, 0x1174, 0x11ba, 0,
+#undef V10941
+#define V10941 (V + 42700)
+ 0x1110, 0x1174, 0x11bb, 0,
+#undef V10942
+#define V10942 (V + 42704)
+ 0x1110, 0x1174, 0x11bc, 0,
+#undef V10943
+#define V10943 (V + 42708)
+ 0x1110, 0x1174, 0x11bd, 0,
+#undef V10944
+#define V10944 (V + 42712)
+ 0x1110, 0x1174, 0x11be, 0,
+#undef V10945
+#define V10945 (V + 42716)
+ 0x1110, 0x1174, 0x11bf, 0,
+#undef V10946
+#define V10946 (V + 42720)
+ 0x1110, 0x1174, 0x11c0, 0,
+#undef V10947
+#define V10947 (V + 42724)
+ 0x1110, 0x1174, 0x11c1, 0,
+#undef V10948
+#define V10948 (V + 42728)
+ 0x1110, 0x1174, 0x11c2, 0,
+#undef V10949
+#define V10949 (V + 42732)
+ 0x1110, 0x1175, 0,
+#undef V10950
+#define V10950 (V + 42735)
+ 0x1110, 0x1175, 0x11a8, 0,
+#undef V10951
+#define V10951 (V + 42739)
+ 0x1110, 0x1175, 0x11a9, 0,
+#undef V10952
+#define V10952 (V + 42743)
+ 0x1110, 0x1175, 0x11aa, 0,
+#undef V10953
+#define V10953 (V + 42747)
+ 0x1110, 0x1175, 0x11ab, 0,
+#undef V10954
+#define V10954 (V + 42751)
+ 0x1110, 0x1175, 0x11ac, 0,
+#undef V10955
+#define V10955 (V + 42755)
+ 0x1110, 0x1175, 0x11ad, 0,
+#undef V10956
+#define V10956 (V + 42759)
+ 0x1110, 0x1175, 0x11ae, 0,
+#undef V10957
+#define V10957 (V + 42763)
+ 0x1110, 0x1175, 0x11af, 0,
+#undef V10958
+#define V10958 (V + 42767)
+ 0x1110, 0x1175, 0x11b0, 0,
+#undef V10959
+#define V10959 (V + 42771)
+ 0x1110, 0x1175, 0x11b1, 0,
+#undef V10960
+#define V10960 (V + 42775)
+ 0x1110, 0x1175, 0x11b2, 0,
+#undef V10961
+#define V10961 (V + 42779)
+ 0x1110, 0x1175, 0x11b3, 0,
+#undef V10962
+#define V10962 (V + 42783)
+ 0x1110, 0x1175, 0x11b4, 0,
+#undef V10963
+#define V10963 (V + 42787)
+ 0x1110, 0x1175, 0x11b5, 0,
+#undef V10964
+#define V10964 (V + 42791)
+ 0x1110, 0x1175, 0x11b6, 0,
+#undef V10965
+#define V10965 (V + 42795)
+ 0x1110, 0x1175, 0x11b7, 0,
+#undef V10966
+#define V10966 (V + 42799)
+ 0x1110, 0x1175, 0x11b8, 0,
+#undef V10967
+#define V10967 (V + 42803)
+ 0x1110, 0x1175, 0x11b9, 0,
+#undef V10968
+#define V10968 (V + 42807)
+ 0x1110, 0x1175, 0x11ba, 0,
+#undef V10969
+#define V10969 (V + 42811)
+ 0x1110, 0x1175, 0x11bb, 0,
+#undef V10970
+#define V10970 (V + 42815)
+ 0x1110, 0x1175, 0x11bc, 0,
+#undef V10971
+#define V10971 (V + 42819)
+ 0x1110, 0x1175, 0x11bd, 0,
+#undef V10972
+#define V10972 (V + 42823)
+ 0x1110, 0x1175, 0x11be, 0,
+#undef V10973
+#define V10973 (V + 42827)
+ 0x1110, 0x1175, 0x11bf, 0,
+#undef V10974
+#define V10974 (V + 42831)
+ 0x1110, 0x1175, 0x11c0, 0,
+#undef V10975
+#define V10975 (V + 42835)
+ 0x1110, 0x1175, 0x11c1, 0,
+#undef V10976
+#define V10976 (V + 42839)
+ 0x1110, 0x1175, 0x11c2, 0,
+#undef V10977
+#define V10977 (V + 42843)
+ 0x1111, 0x1161, 0,
+#undef V10978
+#define V10978 (V + 42846)
+ 0x1111, 0x1161, 0x11a8, 0,
+#undef V10979
+#define V10979 (V + 42850)
+ 0x1111, 0x1161, 0x11a9, 0,
+#undef V10980
+#define V10980 (V + 42854)
+ 0x1111, 0x1161, 0x11aa, 0,
+#undef V10981
+#define V10981 (V + 42858)
+ 0x1111, 0x1161, 0x11ab, 0,
+#undef V10982
+#define V10982 (V + 42862)
+ 0x1111, 0x1161, 0x11ac, 0,
+#undef V10983
+#define V10983 (V + 42866)
+ 0x1111, 0x1161, 0x11ad, 0,
+#undef V10984
+#define V10984 (V + 42870)
+ 0x1111, 0x1161, 0x11ae, 0,
+#undef V10985
+#define V10985 (V + 42874)
+ 0x1111, 0x1161, 0x11af, 0,
+#undef V10986
+#define V10986 (V + 42878)
+ 0x1111, 0x1161, 0x11b0, 0,
+#undef V10987
+#define V10987 (V + 42882)
+ 0x1111, 0x1161, 0x11b1, 0,
+#undef V10988
+#define V10988 (V + 42886)
+ 0x1111, 0x1161, 0x11b2, 0,
+#undef V10989
+#define V10989 (V + 42890)
+ 0x1111, 0x1161, 0x11b3, 0,
+#undef V10990
+#define V10990 (V + 42894)
+ 0x1111, 0x1161, 0x11b4, 0,
+#undef V10991
+#define V10991 (V + 42898)
+ 0x1111, 0x1161, 0x11b5, 0,
+#undef V10992
+#define V10992 (V + 42902)
+ 0x1111, 0x1161, 0x11b6, 0,
+#undef V10993
+#define V10993 (V + 42906)
+ 0x1111, 0x1161, 0x11b7, 0,
+#undef V10994
+#define V10994 (V + 42910)
+ 0x1111, 0x1161, 0x11b8, 0,
+#undef V10995
+#define V10995 (V + 42914)
+ 0x1111, 0x1161, 0x11b9, 0,
+#undef V10996
+#define V10996 (V + 42918)
+ 0x1111, 0x1161, 0x11ba, 0,
+#undef V10997
+#define V10997 (V + 42922)
+ 0x1111, 0x1161, 0x11bb, 0,
+#undef V10998
+#define V10998 (V + 42926)
+ 0x1111, 0x1161, 0x11bc, 0,
+#undef V10999
+#define V10999 (V + 42930)
+ 0x1111, 0x1161, 0x11bd, 0,
+#undef V11000
+#define V11000 (V + 42934)
+ 0x1111, 0x1161, 0x11be, 0,
+#undef V11001
+#define V11001 (V + 42938)
+ 0x1111, 0x1161, 0x11bf, 0,
+#undef V11002
+#define V11002 (V + 42942)
+ 0x1111, 0x1161, 0x11c0, 0,
+#undef V11003
+#define V11003 (V + 42946)
+ 0x1111, 0x1161, 0x11c1, 0,
+#undef V11004
+#define V11004 (V + 42950)
+ 0x1111, 0x1161, 0x11c2, 0,
+#undef V11005
+#define V11005 (V + 42954)
+ 0x1111, 0x1162, 0,
+#undef V11006
+#define V11006 (V + 42957)
+ 0x1111, 0x1162, 0x11a8, 0,
+#undef V11007
+#define V11007 (V + 42961)
+ 0x1111, 0x1162, 0x11a9, 0,
+#undef V11008
+#define V11008 (V + 42965)
+ 0x1111, 0x1162, 0x11aa, 0,
+#undef V11009
+#define V11009 (V + 42969)
+ 0x1111, 0x1162, 0x11ab, 0,
+#undef V11010
+#define V11010 (V + 42973)
+ 0x1111, 0x1162, 0x11ac, 0,
+#undef V11011
+#define V11011 (V + 42977)
+ 0x1111, 0x1162, 0x11ad, 0,
+#undef V11012
+#define V11012 (V + 42981)
+ 0x1111, 0x1162, 0x11ae, 0,
+#undef V11013
+#define V11013 (V + 42985)
+ 0x1111, 0x1162, 0x11af, 0,
+#undef V11014
+#define V11014 (V + 42989)
+ 0x1111, 0x1162, 0x11b0, 0,
+#undef V11015
+#define V11015 (V + 42993)
+ 0x1111, 0x1162, 0x11b1, 0,
+#undef V11016
+#define V11016 (V + 42997)
+ 0x1111, 0x1162, 0x11b2, 0,
+#undef V11017
+#define V11017 (V + 43001)
+ 0x1111, 0x1162, 0x11b3, 0,
+#undef V11018
+#define V11018 (V + 43005)
+ 0x1111, 0x1162, 0x11b4, 0,
+#undef V11019
+#define V11019 (V + 43009)
+ 0x1111, 0x1162, 0x11b5, 0,
+#undef V11020
+#define V11020 (V + 43013)
+ 0x1111, 0x1162, 0x11b6, 0,
+#undef V11021
+#define V11021 (V + 43017)
+ 0x1111, 0x1162, 0x11b7, 0,
+#undef V11022
+#define V11022 (V + 43021)
+ 0x1111, 0x1162, 0x11b8, 0,
+#undef V11023
+#define V11023 (V + 43025)
+ 0x1111, 0x1162, 0x11b9, 0,
+#undef V11024
+#define V11024 (V + 43029)
+ 0x1111, 0x1162, 0x11ba, 0,
+#undef V11025
+#define V11025 (V + 43033)
+ 0x1111, 0x1162, 0x11bb, 0,
+#undef V11026
+#define V11026 (V + 43037)
+ 0x1111, 0x1162, 0x11bc, 0,
+#undef V11027
+#define V11027 (V + 43041)
+ 0x1111, 0x1162, 0x11bd, 0,
+#undef V11028
+#define V11028 (V + 43045)
+ 0x1111, 0x1162, 0x11be, 0,
+#undef V11029
+#define V11029 (V + 43049)
+ 0x1111, 0x1162, 0x11bf, 0,
+#undef V11030
+#define V11030 (V + 43053)
+ 0x1111, 0x1162, 0x11c0, 0,
+#undef V11031
+#define V11031 (V + 43057)
+ 0x1111, 0x1162, 0x11c1, 0,
+#undef V11032
+#define V11032 (V + 43061)
+ 0x1111, 0x1162, 0x11c2, 0,
+#undef V11033
+#define V11033 (V + 43065)
+ 0x1111, 0x1163, 0,
+#undef V11034
+#define V11034 (V + 43068)
+ 0x1111, 0x1163, 0x11a8, 0,
+#undef V11035
+#define V11035 (V + 43072)
+ 0x1111, 0x1163, 0x11a9, 0,
+#undef V11036
+#define V11036 (V + 43076)
+ 0x1111, 0x1163, 0x11aa, 0,
+#undef V11037
+#define V11037 (V + 43080)
+ 0x1111, 0x1163, 0x11ab, 0,
+#undef V11038
+#define V11038 (V + 43084)
+ 0x1111, 0x1163, 0x11ac, 0,
+#undef V11039
+#define V11039 (V + 43088)
+ 0x1111, 0x1163, 0x11ad, 0,
+#undef V11040
+#define V11040 (V + 43092)
+ 0x1111, 0x1163, 0x11ae, 0,
+#undef V11041
+#define V11041 (V + 43096)
+ 0x1111, 0x1163, 0x11af, 0,
+#undef V11042
+#define V11042 (V + 43100)
+ 0x1111, 0x1163, 0x11b0, 0,
+#undef V11043
+#define V11043 (V + 43104)
+ 0x1111, 0x1163, 0x11b1, 0,
+#undef V11044
+#define V11044 (V + 43108)
+ 0x1111, 0x1163, 0x11b2, 0,
+#undef V11045
+#define V11045 (V + 43112)
+ 0x1111, 0x1163, 0x11b3, 0,
+#undef V11046
+#define V11046 (V + 43116)
+ 0x1111, 0x1163, 0x11b4, 0,
+#undef V11047
+#define V11047 (V + 43120)
+ 0x1111, 0x1163, 0x11b5, 0,
+#undef V11048
+#define V11048 (V + 43124)
+ 0x1111, 0x1163, 0x11b6, 0,
+#undef V11049
+#define V11049 (V + 43128)
+ 0x1111, 0x1163, 0x11b7, 0,
+#undef V11050
+#define V11050 (V + 43132)
+ 0x1111, 0x1163, 0x11b8, 0,
+#undef V11051
+#define V11051 (V + 43136)
+ 0x1111, 0x1163, 0x11b9, 0,
+#undef V11052
+#define V11052 (V + 43140)
+ 0x1111, 0x1163, 0x11ba, 0,
+#undef V11053
+#define V11053 (V + 43144)
+ 0x1111, 0x1163, 0x11bb, 0,
+#undef V11054
+#define V11054 (V + 43148)
+ 0x1111, 0x1163, 0x11bc, 0,
+#undef V11055
+#define V11055 (V + 43152)
+ 0x1111, 0x1163, 0x11bd, 0,
+#undef V11056
+#define V11056 (V + 43156)
+ 0x1111, 0x1163, 0x11be, 0,
+#undef V11057
+#define V11057 (V + 43160)
+ 0x1111, 0x1163, 0x11bf, 0,
+#undef V11058
+#define V11058 (V + 43164)
+ 0x1111, 0x1163, 0x11c0, 0,
+#undef V11059
+#define V11059 (V + 43168)
+ 0x1111, 0x1163, 0x11c1, 0,
+#undef V11060
+#define V11060 (V + 43172)
+ 0x1111, 0x1163, 0x11c2, 0,
+#undef V11061
+#define V11061 (V + 43176)
+ 0x1111, 0x1164, 0,
+#undef V11062
+#define V11062 (V + 43179)
+ 0x1111, 0x1164, 0x11a8, 0,
+#undef V11063
+#define V11063 (V + 43183)
+ 0x1111, 0x1164, 0x11a9, 0,
+#undef V11064
+#define V11064 (V + 43187)
+ 0x1111, 0x1164, 0x11aa, 0,
+#undef V11065
+#define V11065 (V + 43191)
+ 0x1111, 0x1164, 0x11ab, 0,
+#undef V11066
+#define V11066 (V + 43195)
+ 0x1111, 0x1164, 0x11ac, 0,
+#undef V11067
+#define V11067 (V + 43199)
+ 0x1111, 0x1164, 0x11ad, 0,
+#undef V11068
+#define V11068 (V + 43203)
+ 0x1111, 0x1164, 0x11ae, 0,
+#undef V11069
+#define V11069 (V + 43207)
+ 0x1111, 0x1164, 0x11af, 0,
+#undef V11070
+#define V11070 (V + 43211)
+ 0x1111, 0x1164, 0x11b0, 0,
+#undef V11071
+#define V11071 (V + 43215)
+ 0x1111, 0x1164, 0x11b1, 0,
+#undef V11072
+#define V11072 (V + 43219)
+ 0x1111, 0x1164, 0x11b2, 0,
+#undef V11073
+#define V11073 (V + 43223)
+ 0x1111, 0x1164, 0x11b3, 0,
+#undef V11074
+#define V11074 (V + 43227)
+ 0x1111, 0x1164, 0x11b4, 0,
+#undef V11075
+#define V11075 (V + 43231)
+ 0x1111, 0x1164, 0x11b5, 0,
+#undef V11076
+#define V11076 (V + 43235)
+ 0x1111, 0x1164, 0x11b6, 0,
+#undef V11077
+#define V11077 (V + 43239)
+ 0x1111, 0x1164, 0x11b7, 0,
+#undef V11078
+#define V11078 (V + 43243)
+ 0x1111, 0x1164, 0x11b8, 0,
+#undef V11079
+#define V11079 (V + 43247)
+ 0x1111, 0x1164, 0x11b9, 0,
+#undef V11080
+#define V11080 (V + 43251)
+ 0x1111, 0x1164, 0x11ba, 0,
+#undef V11081
+#define V11081 (V + 43255)
+ 0x1111, 0x1164, 0x11bb, 0,
+#undef V11082
+#define V11082 (V + 43259)
+ 0x1111, 0x1164, 0x11bc, 0,
+#undef V11083
+#define V11083 (V + 43263)
+ 0x1111, 0x1164, 0x11bd, 0,
+#undef V11084
+#define V11084 (V + 43267)
+ 0x1111, 0x1164, 0x11be, 0,
+#undef V11085
+#define V11085 (V + 43271)
+ 0x1111, 0x1164, 0x11bf, 0,
+#undef V11086
+#define V11086 (V + 43275)
+ 0x1111, 0x1164, 0x11c0, 0,
+#undef V11087
+#define V11087 (V + 43279)
+ 0x1111, 0x1164, 0x11c1, 0,
+#undef V11088
+#define V11088 (V + 43283)
+ 0x1111, 0x1164, 0x11c2, 0,
+#undef V11089
+#define V11089 (V + 43287)
+ 0x1111, 0x1165, 0,
+#undef V11090
+#define V11090 (V + 43290)
+ 0x1111, 0x1165, 0x11a8, 0,
+#undef V11091
+#define V11091 (V + 43294)
+ 0x1111, 0x1165, 0x11a9, 0,
+#undef V11092
+#define V11092 (V + 43298)
+ 0x1111, 0x1165, 0x11aa, 0,
+#undef V11093
+#define V11093 (V + 43302)
+ 0x1111, 0x1165, 0x11ab, 0,
+#undef V11094
+#define V11094 (V + 43306)
+ 0x1111, 0x1165, 0x11ac, 0,
+#undef V11095
+#define V11095 (V + 43310)
+ 0x1111, 0x1165, 0x11ad, 0,
+#undef V11096
+#define V11096 (V + 43314)
+ 0x1111, 0x1165, 0x11ae, 0,
+#undef V11097
+#define V11097 (V + 43318)
+ 0x1111, 0x1165, 0x11af, 0,
+#undef V11098
+#define V11098 (V + 43322)
+ 0x1111, 0x1165, 0x11b0, 0,
+#undef V11099
+#define V11099 (V + 43326)
+ 0x1111, 0x1165, 0x11b1, 0,
+#undef V11100
+#define V11100 (V + 43330)
+ 0x1111, 0x1165, 0x11b2, 0,
+#undef V11101
+#define V11101 (V + 43334)
+ 0x1111, 0x1165, 0x11b3, 0,
+#undef V11102
+#define V11102 (V + 43338)
+ 0x1111, 0x1165, 0x11b4, 0,
+#undef V11103
+#define V11103 (V + 43342)
+ 0x1111, 0x1165, 0x11b5, 0,
+#undef V11104
+#define V11104 (V + 43346)
+ 0x1111, 0x1165, 0x11b6, 0,
+#undef V11105
+#define V11105 (V + 43350)
+ 0x1111, 0x1165, 0x11b7, 0,
+#undef V11106
+#define V11106 (V + 43354)
+ 0x1111, 0x1165, 0x11b8, 0,
+#undef V11107
+#define V11107 (V + 43358)
+ 0x1111, 0x1165, 0x11b9, 0,
+#undef V11108
+#define V11108 (V + 43362)
+ 0x1111, 0x1165, 0x11ba, 0,
+#undef V11109
+#define V11109 (V + 43366)
+ 0x1111, 0x1165, 0x11bb, 0,
+#undef V11110
+#define V11110 (V + 43370)
+ 0x1111, 0x1165, 0x11bc, 0,
+#undef V11111
+#define V11111 (V + 43374)
+ 0x1111, 0x1165, 0x11bd, 0,
+#undef V11112
+#define V11112 (V + 43378)
+ 0x1111, 0x1165, 0x11be, 0,
+#undef V11113
+#define V11113 (V + 43382)
+ 0x1111, 0x1165, 0x11bf, 0,
+#undef V11114
+#define V11114 (V + 43386)
+ 0x1111, 0x1165, 0x11c0, 0,
+#undef V11115
+#define V11115 (V + 43390)
+ 0x1111, 0x1165, 0x11c1, 0,
+#undef V11116
+#define V11116 (V + 43394)
+ 0x1111, 0x1165, 0x11c2, 0,
+#undef V11117
+#define V11117 (V + 43398)
+ 0x1111, 0x1166, 0,
+#undef V11118
+#define V11118 (V + 43401)
+ 0x1111, 0x1166, 0x11a8, 0,
+#undef V11119
+#define V11119 (V + 43405)
+ 0x1111, 0x1166, 0x11a9, 0,
+#undef V11120
+#define V11120 (V + 43409)
+ 0x1111, 0x1166, 0x11aa, 0,
+#undef V11121
+#define V11121 (V + 43413)
+ 0x1111, 0x1166, 0x11ab, 0,
+#undef V11122
+#define V11122 (V + 43417)
+ 0x1111, 0x1166, 0x11ac, 0,
+#undef V11123
+#define V11123 (V + 43421)
+ 0x1111, 0x1166, 0x11ad, 0,
+#undef V11124
+#define V11124 (V + 43425)
+ 0x1111, 0x1166, 0x11ae, 0,
+#undef V11125
+#define V11125 (V + 43429)
+ 0x1111, 0x1166, 0x11af, 0,
+#undef V11126
+#define V11126 (V + 43433)
+ 0x1111, 0x1166, 0x11b0, 0,
+#undef V11127
+#define V11127 (V + 43437)
+ 0x1111, 0x1166, 0x11b1, 0,
+#undef V11128
+#define V11128 (V + 43441)
+ 0x1111, 0x1166, 0x11b2, 0,
+#undef V11129
+#define V11129 (V + 43445)
+ 0x1111, 0x1166, 0x11b3, 0,
+#undef V11130
+#define V11130 (V + 43449)
+ 0x1111, 0x1166, 0x11b4, 0,
+#undef V11131
+#define V11131 (V + 43453)
+ 0x1111, 0x1166, 0x11b5, 0,
+#undef V11132
+#define V11132 (V + 43457)
+ 0x1111, 0x1166, 0x11b6, 0,
+#undef V11133
+#define V11133 (V + 43461)
+ 0x1111, 0x1166, 0x11b7, 0,
+#undef V11134
+#define V11134 (V + 43465)
+ 0x1111, 0x1166, 0x11b8, 0,
+#undef V11135
+#define V11135 (V + 43469)
+ 0x1111, 0x1166, 0x11b9, 0,
+#undef V11136
+#define V11136 (V + 43473)
+ 0x1111, 0x1166, 0x11ba, 0,
+#undef V11137
+#define V11137 (V + 43477)
+ 0x1111, 0x1166, 0x11bb, 0,
+#undef V11138
+#define V11138 (V + 43481)
+ 0x1111, 0x1166, 0x11bc, 0,
+#undef V11139
+#define V11139 (V + 43485)
+ 0x1111, 0x1166, 0x11bd, 0,
+#undef V11140
+#define V11140 (V + 43489)
+ 0x1111, 0x1166, 0x11be, 0,
+#undef V11141
+#define V11141 (V + 43493)
+ 0x1111, 0x1166, 0x11bf, 0,
+#undef V11142
+#define V11142 (V + 43497)
+ 0x1111, 0x1166, 0x11c0, 0,
+#undef V11143
+#define V11143 (V + 43501)
+ 0x1111, 0x1166, 0x11c1, 0,
+#undef V11144
+#define V11144 (V + 43505)
+ 0x1111, 0x1166, 0x11c2, 0,
+#undef V11145
+#define V11145 (V + 43509)
+ 0x1111, 0x1167, 0,
+#undef V11146
+#define V11146 (V + 43512)
+ 0x1111, 0x1167, 0x11a8, 0,
+#undef V11147
+#define V11147 (V + 43516)
+ 0x1111, 0x1167, 0x11a9, 0,
+#undef V11148
+#define V11148 (V + 43520)
+ 0x1111, 0x1167, 0x11aa, 0,
+#undef V11149
+#define V11149 (V + 43524)
+ 0x1111, 0x1167, 0x11ab, 0,
+#undef V11150
+#define V11150 (V + 43528)
+ 0x1111, 0x1167, 0x11ac, 0,
+#undef V11151
+#define V11151 (V + 43532)
+ 0x1111, 0x1167, 0x11ad, 0,
+#undef V11152
+#define V11152 (V + 43536)
+ 0x1111, 0x1167, 0x11ae, 0,
+#undef V11153
+#define V11153 (V + 43540)
+ 0x1111, 0x1167, 0x11af, 0,
+#undef V11154
+#define V11154 (V + 43544)
+ 0x1111, 0x1167, 0x11b0, 0,
+#undef V11155
+#define V11155 (V + 43548)
+ 0x1111, 0x1167, 0x11b1, 0,
+#undef V11156
+#define V11156 (V + 43552)
+ 0x1111, 0x1167, 0x11b2, 0,
+#undef V11157
+#define V11157 (V + 43556)
+ 0x1111, 0x1167, 0x11b3, 0,
+#undef V11158
+#define V11158 (V + 43560)
+ 0x1111, 0x1167, 0x11b4, 0,
+#undef V11159
+#define V11159 (V + 43564)
+ 0x1111, 0x1167, 0x11b5, 0,
+#undef V11160
+#define V11160 (V + 43568)
+ 0x1111, 0x1167, 0x11b6, 0,
+#undef V11161
+#define V11161 (V + 43572)
+ 0x1111, 0x1167, 0x11b7, 0,
+#undef V11162
+#define V11162 (V + 43576)
+ 0x1111, 0x1167, 0x11b8, 0,
+#undef V11163
+#define V11163 (V + 43580)
+ 0x1111, 0x1167, 0x11b9, 0,
+#undef V11164
+#define V11164 (V + 43584)
+ 0x1111, 0x1167, 0x11ba, 0,
+#undef V11165
+#define V11165 (V + 43588)
+ 0x1111, 0x1167, 0x11bb, 0,
+#undef V11166
+#define V11166 (V + 43592)
+ 0x1111, 0x1167, 0x11bc, 0,
+#undef V11167
+#define V11167 (V + 43596)
+ 0x1111, 0x1167, 0x11bd, 0,
+#undef V11168
+#define V11168 (V + 43600)
+ 0x1111, 0x1167, 0x11be, 0,
+#undef V11169
+#define V11169 (V + 43604)
+ 0x1111, 0x1167, 0x11bf, 0,
+#undef V11170
+#define V11170 (V + 43608)
+ 0x1111, 0x1167, 0x11c0, 0,
+#undef V11171
+#define V11171 (V + 43612)
+ 0x1111, 0x1167, 0x11c1, 0,
+#undef V11172
+#define V11172 (V + 43616)
+ 0x1111, 0x1167, 0x11c2, 0,
+#undef V11173
+#define V11173 (V + 43620)
+ 0x1111, 0x1168, 0,
+#undef V11174
+#define V11174 (V + 43623)
+ 0x1111, 0x1168, 0x11a8, 0,
+#undef V11175
+#define V11175 (V + 43627)
+ 0x1111, 0x1168, 0x11a9, 0,
+#undef V11176
+#define V11176 (V + 43631)
+ 0x1111, 0x1168, 0x11aa, 0,
+#undef V11177
+#define V11177 (V + 43635)
+ 0x1111, 0x1168, 0x11ab, 0,
+#undef V11178
+#define V11178 (V + 43639)
+ 0x1111, 0x1168, 0x11ac, 0,
+#undef V11179
+#define V11179 (V + 43643)
+ 0x1111, 0x1168, 0x11ad, 0,
+#undef V11180
+#define V11180 (V + 43647)
+ 0x1111, 0x1168, 0x11ae, 0,
+#undef V11181
+#define V11181 (V + 43651)
+ 0x1111, 0x1168, 0x11af, 0,
+#undef V11182
+#define V11182 (V + 43655)
+ 0x1111, 0x1168, 0x11b0, 0,
+#undef V11183
+#define V11183 (V + 43659)
+ 0x1111, 0x1168, 0x11b1, 0,
+#undef V11184
+#define V11184 (V + 43663)
+ 0x1111, 0x1168, 0x11b2, 0,
+#undef V11185
+#define V11185 (V + 43667)
+ 0x1111, 0x1168, 0x11b3, 0,
+#undef V11186
+#define V11186 (V + 43671)
+ 0x1111, 0x1168, 0x11b4, 0,
+#undef V11187
+#define V11187 (V + 43675)
+ 0x1111, 0x1168, 0x11b5, 0,
+#undef V11188
+#define V11188 (V + 43679)
+ 0x1111, 0x1168, 0x11b6, 0,
+#undef V11189
+#define V11189 (V + 43683)
+ 0x1111, 0x1168, 0x11b7, 0,
+#undef V11190
+#define V11190 (V + 43687)
+ 0x1111, 0x1168, 0x11b8, 0,
+#undef V11191
+#define V11191 (V + 43691)
+ 0x1111, 0x1168, 0x11b9, 0,
+#undef V11192
+#define V11192 (V + 43695)
+ 0x1111, 0x1168, 0x11ba, 0,
+#undef V11193
+#define V11193 (V + 43699)
+ 0x1111, 0x1168, 0x11bb, 0,
+#undef V11194
+#define V11194 (V + 43703)
+ 0x1111, 0x1168, 0x11bc, 0,
+#undef V11195
+#define V11195 (V + 43707)
+ 0x1111, 0x1168, 0x11bd, 0,
+#undef V11196
+#define V11196 (V + 43711)
+ 0x1111, 0x1168, 0x11be, 0,
+#undef V11197
+#define V11197 (V + 43715)
+ 0x1111, 0x1168, 0x11bf, 0,
+#undef V11198
+#define V11198 (V + 43719)
+ 0x1111, 0x1168, 0x11c0, 0,
+#undef V11199
+#define V11199 (V + 43723)
+ 0x1111, 0x1168, 0x11c1, 0,
+#undef V11200
+#define V11200 (V + 43727)
+ 0x1111, 0x1168, 0x11c2, 0,
+#undef V11201
+#define V11201 (V + 43731)
+ 0x1111, 0x1169, 0,
+#undef V11202
+#define V11202 (V + 43734)
+ 0x1111, 0x1169, 0x11a8, 0,
+#undef V11203
+#define V11203 (V + 43738)
+ 0x1111, 0x1169, 0x11a9, 0,
+#undef V11204
+#define V11204 (V + 43742)
+ 0x1111, 0x1169, 0x11aa, 0,
+#undef V11205
+#define V11205 (V + 43746)
+ 0x1111, 0x1169, 0x11ab, 0,
+#undef V11206
+#define V11206 (V + 43750)
+ 0x1111, 0x1169, 0x11ac, 0,
+#undef V11207
+#define V11207 (V + 43754)
+ 0x1111, 0x1169, 0x11ad, 0,
+#undef V11208
+#define V11208 (V + 43758)
+ 0x1111, 0x1169, 0x11ae, 0,
+#undef V11209
+#define V11209 (V + 43762)
+ 0x1111, 0x1169, 0x11af, 0,
+#undef V11210
+#define V11210 (V + 43766)
+ 0x1111, 0x1169, 0x11b0, 0,
+#undef V11211
+#define V11211 (V + 43770)
+ 0x1111, 0x1169, 0x11b1, 0,
+#undef V11212
+#define V11212 (V + 43774)
+ 0x1111, 0x1169, 0x11b2, 0,
+#undef V11213
+#define V11213 (V + 43778)
+ 0x1111, 0x1169, 0x11b3, 0,
+#undef V11214
+#define V11214 (V + 43782)
+ 0x1111, 0x1169, 0x11b4, 0,
+#undef V11215
+#define V11215 (V + 43786)
+ 0x1111, 0x1169, 0x11b5, 0,
+#undef V11216
+#define V11216 (V + 43790)
+ 0x1111, 0x1169, 0x11b6, 0,
+#undef V11217
+#define V11217 (V + 43794)
+ 0x1111, 0x1169, 0x11b7, 0,
+#undef V11218
+#define V11218 (V + 43798)
+ 0x1111, 0x1169, 0x11b8, 0,
+#undef V11219
+#define V11219 (V + 43802)
+ 0x1111, 0x1169, 0x11b9, 0,
+#undef V11220
+#define V11220 (V + 43806)
+ 0x1111, 0x1169, 0x11ba, 0,
+#undef V11221
+#define V11221 (V + 43810)
+ 0x1111, 0x1169, 0x11bb, 0,
+#undef V11222
+#define V11222 (V + 43814)
+ 0x1111, 0x1169, 0x11bc, 0,
+#undef V11223
+#define V11223 (V + 43818)
+ 0x1111, 0x1169, 0x11bd, 0,
+#undef V11224
+#define V11224 (V + 43822)
+ 0x1111, 0x1169, 0x11be, 0,
+#undef V11225
+#define V11225 (V + 43826)
+ 0x1111, 0x1169, 0x11bf, 0,
+#undef V11226
+#define V11226 (V + 43830)
+ 0x1111, 0x1169, 0x11c0, 0,
+#undef V11227
+#define V11227 (V + 43834)
+ 0x1111, 0x1169, 0x11c1, 0,
+#undef V11228
+#define V11228 (V + 43838)
+ 0x1111, 0x1169, 0x11c2, 0,
+#undef V11229
+#define V11229 (V + 43842)
+ 0x1111, 0x116a, 0,
+#undef V11230
+#define V11230 (V + 43845)
+ 0x1111, 0x116a, 0x11a8, 0,
+#undef V11231
+#define V11231 (V + 43849)
+ 0x1111, 0x116a, 0x11a9, 0,
+#undef V11232
+#define V11232 (V + 43853)
+ 0x1111, 0x116a, 0x11aa, 0,
+#undef V11233
+#define V11233 (V + 43857)
+ 0x1111, 0x116a, 0x11ab, 0,
+#undef V11234
+#define V11234 (V + 43861)
+ 0x1111, 0x116a, 0x11ac, 0,
+#undef V11235
+#define V11235 (V + 43865)
+ 0x1111, 0x116a, 0x11ad, 0,
+#undef V11236
+#define V11236 (V + 43869)
+ 0x1111, 0x116a, 0x11ae, 0,
+#undef V11237
+#define V11237 (V + 43873)
+ 0x1111, 0x116a, 0x11af, 0,
+#undef V11238
+#define V11238 (V + 43877)
+ 0x1111, 0x116a, 0x11b0, 0,
+#undef V11239
+#define V11239 (V + 43881)
+ 0x1111, 0x116a, 0x11b1, 0,
+#undef V11240
+#define V11240 (V + 43885)
+ 0x1111, 0x116a, 0x11b2, 0,
+#undef V11241
+#define V11241 (V + 43889)
+ 0x1111, 0x116a, 0x11b3, 0,
+#undef V11242
+#define V11242 (V + 43893)
+ 0x1111, 0x116a, 0x11b4, 0,
+#undef V11243
+#define V11243 (V + 43897)
+ 0x1111, 0x116a, 0x11b5, 0,
+#undef V11244
+#define V11244 (V + 43901)
+ 0x1111, 0x116a, 0x11b6, 0,
+#undef V11245
+#define V11245 (V + 43905)
+ 0x1111, 0x116a, 0x11b7, 0,
+#undef V11246
+#define V11246 (V + 43909)
+ 0x1111, 0x116a, 0x11b8, 0,
+#undef V11247
+#define V11247 (V + 43913)
+ 0x1111, 0x116a, 0x11b9, 0,
+#undef V11248
+#define V11248 (V + 43917)
+ 0x1111, 0x116a, 0x11ba, 0,
+#undef V11249
+#define V11249 (V + 43921)
+ 0x1111, 0x116a, 0x11bb, 0,
+#undef V11250
+#define V11250 (V + 43925)
+ 0x1111, 0x116a, 0x11bc, 0,
+#undef V11251
+#define V11251 (V + 43929)
+ 0x1111, 0x116a, 0x11bd, 0,
+#undef V11252
+#define V11252 (V + 43933)
+ 0x1111, 0x116a, 0x11be, 0,
+#undef V11253
+#define V11253 (V + 43937)
+ 0x1111, 0x116a, 0x11bf, 0,
+#undef V11254
+#define V11254 (V + 43941)
+ 0x1111, 0x116a, 0x11c0, 0,
+#undef V11255
+#define V11255 (V + 43945)
+ 0x1111, 0x116a, 0x11c1, 0,
+#undef V11256
+#define V11256 (V + 43949)
+ 0x1111, 0x116a, 0x11c2, 0,
+#undef V11257
+#define V11257 (V + 43953)
+ 0x1111, 0x116b, 0,
+#undef V11258
+#define V11258 (V + 43956)
+ 0x1111, 0x116b, 0x11a8, 0,
+#undef V11259
+#define V11259 (V + 43960)
+ 0x1111, 0x116b, 0x11a9, 0,
+#undef V11260
+#define V11260 (V + 43964)
+ 0x1111, 0x116b, 0x11aa, 0,
+#undef V11261
+#define V11261 (V + 43968)
+ 0x1111, 0x116b, 0x11ab, 0,
+#undef V11262
+#define V11262 (V + 43972)
+ 0x1111, 0x116b, 0x11ac, 0,
+#undef V11263
+#define V11263 (V + 43976)
+ 0x1111, 0x116b, 0x11ad, 0,
+#undef V11264
+#define V11264 (V + 43980)
+ 0x1111, 0x116b, 0x11ae, 0,
+#undef V11265
+#define V11265 (V + 43984)
+ 0x1111, 0x116b, 0x11af, 0,
+#undef V11266
+#define V11266 (V + 43988)
+ 0x1111, 0x116b, 0x11b0, 0,
+#undef V11267
+#define V11267 (V + 43992)
+ 0x1111, 0x116b, 0x11b1, 0,
+#undef V11268
+#define V11268 (V + 43996)
+ 0x1111, 0x116b, 0x11b2, 0,
+#undef V11269
+#define V11269 (V + 44000)
+ 0x1111, 0x116b, 0x11b3, 0,
+#undef V11270
+#define V11270 (V + 44004)
+ 0x1111, 0x116b, 0x11b4, 0,
+#undef V11271
+#define V11271 (V + 44008)
+ 0x1111, 0x116b, 0x11b5, 0,
+#undef V11272
+#define V11272 (V + 44012)
+ 0x1111, 0x116b, 0x11b6, 0,
+#undef V11273
+#define V11273 (V + 44016)
+ 0x1111, 0x116b, 0x11b7, 0,
+#undef V11274
+#define V11274 (V + 44020)
+ 0x1111, 0x116b, 0x11b8, 0,
+#undef V11275
+#define V11275 (V + 44024)
+ 0x1111, 0x116b, 0x11b9, 0,
+#undef V11276
+#define V11276 (V + 44028)
+ 0x1111, 0x116b, 0x11ba, 0,
+#undef V11277
+#define V11277 (V + 44032)
+ 0x1111, 0x116b, 0x11bb, 0,
+#undef V11278
+#define V11278 (V + 44036)
+ 0x1111, 0x116b, 0x11bc, 0,
+#undef V11279
+#define V11279 (V + 44040)
+ 0x1111, 0x116b, 0x11bd, 0,
+#undef V11280
+#define V11280 (V + 44044)
+ 0x1111, 0x116b, 0x11be, 0,
+#undef V11281
+#define V11281 (V + 44048)
+ 0x1111, 0x116b, 0x11bf, 0,
+#undef V11282
+#define V11282 (V + 44052)
+ 0x1111, 0x116b, 0x11c0, 0,
+#undef V11283
+#define V11283 (V + 44056)
+ 0x1111, 0x116b, 0x11c1, 0,
+#undef V11284
+#define V11284 (V + 44060)
+ 0x1111, 0x116b, 0x11c2, 0,
+#undef V11285
+#define V11285 (V + 44064)
+ 0x1111, 0x116c, 0,
+#undef V11286
+#define V11286 (V + 44067)
+ 0x1111, 0x116c, 0x11a8, 0,
+#undef V11287
+#define V11287 (V + 44071)
+ 0x1111, 0x116c, 0x11a9, 0,
+#undef V11288
+#define V11288 (V + 44075)
+ 0x1111, 0x116c, 0x11aa, 0,
+#undef V11289
+#define V11289 (V + 44079)
+ 0x1111, 0x116c, 0x11ab, 0,
+#undef V11290
+#define V11290 (V + 44083)
+ 0x1111, 0x116c, 0x11ac, 0,
+#undef V11291
+#define V11291 (V + 44087)
+ 0x1111, 0x116c, 0x11ad, 0,
+#undef V11292
+#define V11292 (V + 44091)
+ 0x1111, 0x116c, 0x11ae, 0,
+#undef V11293
+#define V11293 (V + 44095)
+ 0x1111, 0x116c, 0x11af, 0,
+#undef V11294
+#define V11294 (V + 44099)
+ 0x1111, 0x116c, 0x11b0, 0,
+#undef V11295
+#define V11295 (V + 44103)
+ 0x1111, 0x116c, 0x11b1, 0,
+#undef V11296
+#define V11296 (V + 44107)
+ 0x1111, 0x116c, 0x11b2, 0,
+#undef V11297
+#define V11297 (V + 44111)
+ 0x1111, 0x116c, 0x11b3, 0,
+#undef V11298
+#define V11298 (V + 44115)
+ 0x1111, 0x116c, 0x11b4, 0,
+#undef V11299
+#define V11299 (V + 44119)
+ 0x1111, 0x116c, 0x11b5, 0,
+#undef V11300
+#define V11300 (V + 44123)
+ 0x1111, 0x116c, 0x11b6, 0,
+#undef V11301
+#define V11301 (V + 44127)
+ 0x1111, 0x116c, 0x11b7, 0,
+#undef V11302
+#define V11302 (V + 44131)
+ 0x1111, 0x116c, 0x11b8, 0,
+#undef V11303
+#define V11303 (V + 44135)
+ 0x1111, 0x116c, 0x11b9, 0,
+#undef V11304
+#define V11304 (V + 44139)
+ 0x1111, 0x116c, 0x11ba, 0,
+#undef V11305
+#define V11305 (V + 44143)
+ 0x1111, 0x116c, 0x11bb, 0,
+#undef V11306
+#define V11306 (V + 44147)
+ 0x1111, 0x116c, 0x11bc, 0,
+#undef V11307
+#define V11307 (V + 44151)
+ 0x1111, 0x116c, 0x11bd, 0,
+#undef V11308
+#define V11308 (V + 44155)
+ 0x1111, 0x116c, 0x11be, 0,
+#undef V11309
+#define V11309 (V + 44159)
+ 0x1111, 0x116c, 0x11bf, 0,
+#undef V11310
+#define V11310 (V + 44163)
+ 0x1111, 0x116c, 0x11c0, 0,
+#undef V11311
+#define V11311 (V + 44167)
+ 0x1111, 0x116c, 0x11c1, 0,
+#undef V11312
+#define V11312 (V + 44171)
+ 0x1111, 0x116c, 0x11c2, 0,
+#undef V11313
+#define V11313 (V + 44175)
+ 0x1111, 0x116d, 0,
+#undef V11314
+#define V11314 (V + 44178)
+ 0x1111, 0x116d, 0x11a8, 0,
+#undef V11315
+#define V11315 (V + 44182)
+ 0x1111, 0x116d, 0x11a9, 0,
+#undef V11316
+#define V11316 (V + 44186)
+ 0x1111, 0x116d, 0x11aa, 0,
+#undef V11317
+#define V11317 (V + 44190)
+ 0x1111, 0x116d, 0x11ab, 0,
+#undef V11318
+#define V11318 (V + 44194)
+ 0x1111, 0x116d, 0x11ac, 0,
+#undef V11319
+#define V11319 (V + 44198)
+ 0x1111, 0x116d, 0x11ad, 0,
+#undef V11320
+#define V11320 (V + 44202)
+ 0x1111, 0x116d, 0x11ae, 0,
+#undef V11321
+#define V11321 (V + 44206)
+ 0x1111, 0x116d, 0x11af, 0,
+#undef V11322
+#define V11322 (V + 44210)
+ 0x1111, 0x116d, 0x11b0, 0,
+#undef V11323
+#define V11323 (V + 44214)
+ 0x1111, 0x116d, 0x11b1, 0,
+#undef V11324
+#define V11324 (V + 44218)
+ 0x1111, 0x116d, 0x11b2, 0,
+#undef V11325
+#define V11325 (V + 44222)
+ 0x1111, 0x116d, 0x11b3, 0,
+#undef V11326
+#define V11326 (V + 44226)
+ 0x1111, 0x116d, 0x11b4, 0,
+#undef V11327
+#define V11327 (V + 44230)
+ 0x1111, 0x116d, 0x11b5, 0,
+#undef V11328
+#define V11328 (V + 44234)
+ 0x1111, 0x116d, 0x11b6, 0,
+#undef V11329
+#define V11329 (V + 44238)
+ 0x1111, 0x116d, 0x11b7, 0,
+#undef V11330
+#define V11330 (V + 44242)
+ 0x1111, 0x116d, 0x11b8, 0,
+#undef V11331
+#define V11331 (V + 44246)
+ 0x1111, 0x116d, 0x11b9, 0,
+#undef V11332
+#define V11332 (V + 44250)
+ 0x1111, 0x116d, 0x11ba, 0,
+#undef V11333
+#define V11333 (V + 44254)
+ 0x1111, 0x116d, 0x11bb, 0,
+#undef V11334
+#define V11334 (V + 44258)
+ 0x1111, 0x116d, 0x11bc, 0,
+#undef V11335
+#define V11335 (V + 44262)
+ 0x1111, 0x116d, 0x11bd, 0,
+#undef V11336
+#define V11336 (V + 44266)
+ 0x1111, 0x116d, 0x11be, 0,
+#undef V11337
+#define V11337 (V + 44270)
+ 0x1111, 0x116d, 0x11bf, 0,
+#undef V11338
+#define V11338 (V + 44274)
+ 0x1111, 0x116d, 0x11c0, 0,
+#undef V11339
+#define V11339 (V + 44278)
+ 0x1111, 0x116d, 0x11c1, 0,
+#undef V11340
+#define V11340 (V + 44282)
+ 0x1111, 0x116d, 0x11c2, 0,
+#undef V11341
+#define V11341 (V + 44286)
+ 0x1111, 0x116e, 0,
+#undef V11342
+#define V11342 (V + 44289)
+ 0x1111, 0x116e, 0x11a8, 0,
+#undef V11343
+#define V11343 (V + 44293)
+ 0x1111, 0x116e, 0x11a9, 0,
+#undef V11344
+#define V11344 (V + 44297)
+ 0x1111, 0x116e, 0x11aa, 0,
+#undef V11345
+#define V11345 (V + 44301)
+ 0x1111, 0x116e, 0x11ab, 0,
+#undef V11346
+#define V11346 (V + 44305)
+ 0x1111, 0x116e, 0x11ac, 0,
+#undef V11347
+#define V11347 (V + 44309)
+ 0x1111, 0x116e, 0x11ad, 0,
+#undef V11348
+#define V11348 (V + 44313)
+ 0x1111, 0x116e, 0x11ae, 0,
+#undef V11349
+#define V11349 (V + 44317)
+ 0x1111, 0x116e, 0x11af, 0,
+#undef V11350
+#define V11350 (V + 44321)
+ 0x1111, 0x116e, 0x11b0, 0,
+#undef V11351
+#define V11351 (V + 44325)
+ 0x1111, 0x116e, 0x11b1, 0,
+#undef V11352
+#define V11352 (V + 44329)
+ 0x1111, 0x116e, 0x11b2, 0,
+#undef V11353
+#define V11353 (V + 44333)
+ 0x1111, 0x116e, 0x11b3, 0,
+#undef V11354
+#define V11354 (V + 44337)
+ 0x1111, 0x116e, 0x11b4, 0,
+#undef V11355
+#define V11355 (V + 44341)
+ 0x1111, 0x116e, 0x11b5, 0,
+#undef V11356
+#define V11356 (V + 44345)
+ 0x1111, 0x116e, 0x11b6, 0,
+#undef V11357
+#define V11357 (V + 44349)
+ 0x1111, 0x116e, 0x11b7, 0,
+#undef V11358
+#define V11358 (V + 44353)
+ 0x1111, 0x116e, 0x11b8, 0,
+#undef V11359
+#define V11359 (V + 44357)
+ 0x1111, 0x116e, 0x11b9, 0,
+#undef V11360
+#define V11360 (V + 44361)
+ 0x1111, 0x116e, 0x11ba, 0,
+#undef V11361
+#define V11361 (V + 44365)
+ 0x1111, 0x116e, 0x11bb, 0,
+#undef V11362
+#define V11362 (V + 44369)
+ 0x1111, 0x116e, 0x11bc, 0,
+#undef V11363
+#define V11363 (V + 44373)
+ 0x1111, 0x116e, 0x11bd, 0,
+#undef V11364
+#define V11364 (V + 44377)
+ 0x1111, 0x116e, 0x11be, 0,
+#undef V11365
+#define V11365 (V + 44381)
+ 0x1111, 0x116e, 0x11bf, 0,
+#undef V11366
+#define V11366 (V + 44385)
+ 0x1111, 0x116e, 0x11c0, 0,
+#undef V11367
+#define V11367 (V + 44389)
+ 0x1111, 0x116e, 0x11c1, 0,
+#undef V11368
+#define V11368 (V + 44393)
+ 0x1111, 0x116e, 0x11c2, 0,
+#undef V11369
+#define V11369 (V + 44397)
+ 0x1111, 0x116f, 0,
+#undef V11370
+#define V11370 (V + 44400)
+ 0x1111, 0x116f, 0x11a8, 0,
+#undef V11371
+#define V11371 (V + 44404)
+ 0x1111, 0x116f, 0x11a9, 0,
+#undef V11372
+#define V11372 (V + 44408)
+ 0x1111, 0x116f, 0x11aa, 0,
+#undef V11373
+#define V11373 (V + 44412)
+ 0x1111, 0x116f, 0x11ab, 0,
+#undef V11374
+#define V11374 (V + 44416)
+ 0x1111, 0x116f, 0x11ac, 0,
+#undef V11375
+#define V11375 (V + 44420)
+ 0x1111, 0x116f, 0x11ad, 0,
+#undef V11376
+#define V11376 (V + 44424)
+ 0x1111, 0x116f, 0x11ae, 0,
+#undef V11377
+#define V11377 (V + 44428)
+ 0x1111, 0x116f, 0x11af, 0,
+#undef V11378
+#define V11378 (V + 44432)
+ 0x1111, 0x116f, 0x11b0, 0,
+#undef V11379
+#define V11379 (V + 44436)
+ 0x1111, 0x116f, 0x11b1, 0,
+#undef V11380
+#define V11380 (V + 44440)
+ 0x1111, 0x116f, 0x11b2, 0,
+#undef V11381
+#define V11381 (V + 44444)
+ 0x1111, 0x116f, 0x11b3, 0,
+#undef V11382
+#define V11382 (V + 44448)
+ 0x1111, 0x116f, 0x11b4, 0,
+#undef V11383
+#define V11383 (V + 44452)
+ 0x1111, 0x116f, 0x11b5, 0,
+#undef V11384
+#define V11384 (V + 44456)
+ 0x1111, 0x116f, 0x11b6, 0,
+#undef V11385
+#define V11385 (V + 44460)
+ 0x1111, 0x116f, 0x11b7, 0,
+#undef V11386
+#define V11386 (V + 44464)
+ 0x1111, 0x116f, 0x11b8, 0,
+#undef V11387
+#define V11387 (V + 44468)
+ 0x1111, 0x116f, 0x11b9, 0,
+#undef V11388
+#define V11388 (V + 44472)
+ 0x1111, 0x116f, 0x11ba, 0,
+#undef V11389
+#define V11389 (V + 44476)
+ 0x1111, 0x116f, 0x11bb, 0,
+#undef V11390
+#define V11390 (V + 44480)
+ 0x1111, 0x116f, 0x11bc, 0,
+#undef V11391
+#define V11391 (V + 44484)
+ 0x1111, 0x116f, 0x11bd, 0,
+#undef V11392
+#define V11392 (V + 44488)
+ 0x1111, 0x116f, 0x11be, 0,
+#undef V11393
+#define V11393 (V + 44492)
+ 0x1111, 0x116f, 0x11bf, 0,
+#undef V11394
+#define V11394 (V + 44496)
+ 0x1111, 0x116f, 0x11c0, 0,
+#undef V11395
+#define V11395 (V + 44500)
+ 0x1111, 0x116f, 0x11c1, 0,
+#undef V11396
+#define V11396 (V + 44504)
+ 0x1111, 0x116f, 0x11c2, 0,
+#undef V11397
+#define V11397 (V + 44508)
+ 0x1111, 0x1170, 0,
+#undef V11398
+#define V11398 (V + 44511)
+ 0x1111, 0x1170, 0x11a8, 0,
+#undef V11399
+#define V11399 (V + 44515)
+ 0x1111, 0x1170, 0x11a9, 0,
+#undef V11400
+#define V11400 (V + 44519)
+ 0x1111, 0x1170, 0x11aa, 0,
+#undef V11401
+#define V11401 (V + 44523)
+ 0x1111, 0x1170, 0x11ab, 0,
+#undef V11402
+#define V11402 (V + 44527)
+ 0x1111, 0x1170, 0x11ac, 0,
+#undef V11403
+#define V11403 (V + 44531)
+ 0x1111, 0x1170, 0x11ad, 0,
+#undef V11404
+#define V11404 (V + 44535)
+ 0x1111, 0x1170, 0x11ae, 0,
+#undef V11405
+#define V11405 (V + 44539)
+ 0x1111, 0x1170, 0x11af, 0,
+#undef V11406
+#define V11406 (V + 44543)
+ 0x1111, 0x1170, 0x11b0, 0,
+#undef V11407
+#define V11407 (V + 44547)
+ 0x1111, 0x1170, 0x11b1, 0,
+#undef V11408
+#define V11408 (V + 44551)
+ 0x1111, 0x1170, 0x11b2, 0,
+#undef V11409
+#define V11409 (V + 44555)
+ 0x1111, 0x1170, 0x11b3, 0,
+#undef V11410
+#define V11410 (V + 44559)
+ 0x1111, 0x1170, 0x11b4, 0,
+#undef V11411
+#define V11411 (V + 44563)
+ 0x1111, 0x1170, 0x11b5, 0,
+#undef V11412
+#define V11412 (V + 44567)
+ 0x1111, 0x1170, 0x11b6, 0,
+#undef V11413
+#define V11413 (V + 44571)
+ 0x1111, 0x1170, 0x11b7, 0,
+#undef V11414
+#define V11414 (V + 44575)
+ 0x1111, 0x1170, 0x11b8, 0,
+#undef V11415
+#define V11415 (V + 44579)
+ 0x1111, 0x1170, 0x11b9, 0,
+#undef V11416
+#define V11416 (V + 44583)
+ 0x1111, 0x1170, 0x11ba, 0,
+#undef V11417
+#define V11417 (V + 44587)
+ 0x1111, 0x1170, 0x11bb, 0,
+#undef V11418
+#define V11418 (V + 44591)
+ 0x1111, 0x1170, 0x11bc, 0,
+#undef V11419
+#define V11419 (V + 44595)
+ 0x1111, 0x1170, 0x11bd, 0,
+#undef V11420
+#define V11420 (V + 44599)
+ 0x1111, 0x1170, 0x11be, 0,
+#undef V11421
+#define V11421 (V + 44603)
+ 0x1111, 0x1170, 0x11bf, 0,
+#undef V11422
+#define V11422 (V + 44607)
+ 0x1111, 0x1170, 0x11c0, 0,
+#undef V11423
+#define V11423 (V + 44611)
+ 0x1111, 0x1170, 0x11c1, 0,
+#undef V11424
+#define V11424 (V + 44615)
+ 0x1111, 0x1170, 0x11c2, 0,
+#undef V11425
+#define V11425 (V + 44619)
+ 0x1111, 0x1171, 0,
+#undef V11426
+#define V11426 (V + 44622)
+ 0x1111, 0x1171, 0x11a8, 0,
+#undef V11427
+#define V11427 (V + 44626)
+ 0x1111, 0x1171, 0x11a9, 0,
+#undef V11428
+#define V11428 (V + 44630)
+ 0x1111, 0x1171, 0x11aa, 0,
+#undef V11429
+#define V11429 (V + 44634)
+ 0x1111, 0x1171, 0x11ab, 0,
+#undef V11430
+#define V11430 (V + 44638)
+ 0x1111, 0x1171, 0x11ac, 0,
+#undef V11431
+#define V11431 (V + 44642)
+ 0x1111, 0x1171, 0x11ad, 0,
+#undef V11432
+#define V11432 (V + 44646)
+ 0x1111, 0x1171, 0x11ae, 0,
+#undef V11433
+#define V11433 (V + 44650)
+ 0x1111, 0x1171, 0x11af, 0,
+#undef V11434
+#define V11434 (V + 44654)
+ 0x1111, 0x1171, 0x11b0, 0,
+#undef V11435
+#define V11435 (V + 44658)
+ 0x1111, 0x1171, 0x11b1, 0,
+#undef V11436
+#define V11436 (V + 44662)
+ 0x1111, 0x1171, 0x11b2, 0,
+#undef V11437
+#define V11437 (V + 44666)
+ 0x1111, 0x1171, 0x11b3, 0,
+#undef V11438
+#define V11438 (V + 44670)
+ 0x1111, 0x1171, 0x11b4, 0,
+#undef V11439
+#define V11439 (V + 44674)
+ 0x1111, 0x1171, 0x11b5, 0,
+#undef V11440
+#define V11440 (V + 44678)
+ 0x1111, 0x1171, 0x11b6, 0,
+#undef V11441
+#define V11441 (V + 44682)
+ 0x1111, 0x1171, 0x11b7, 0,
+#undef V11442
+#define V11442 (V + 44686)
+ 0x1111, 0x1171, 0x11b8, 0,
+#undef V11443
+#define V11443 (V + 44690)
+ 0x1111, 0x1171, 0x11b9, 0,
+#undef V11444
+#define V11444 (V + 44694)
+ 0x1111, 0x1171, 0x11ba, 0,
+#undef V11445
+#define V11445 (V + 44698)
+ 0x1111, 0x1171, 0x11bb, 0,
+#undef V11446
+#define V11446 (V + 44702)
+ 0x1111, 0x1171, 0x11bc, 0,
+#undef V11447
+#define V11447 (V + 44706)
+ 0x1111, 0x1171, 0x11bd, 0,
+#undef V11448
+#define V11448 (V + 44710)
+ 0x1111, 0x1171, 0x11be, 0,
+#undef V11449
+#define V11449 (V + 44714)
+ 0x1111, 0x1171, 0x11bf, 0,
+#undef V11450
+#define V11450 (V + 44718)
+ 0x1111, 0x1171, 0x11c0, 0,
+#undef V11451
+#define V11451 (V + 44722)
+ 0x1111, 0x1171, 0x11c1, 0,
+#undef V11452
+#define V11452 (V + 44726)
+ 0x1111, 0x1171, 0x11c2, 0,
+#undef V11453
+#define V11453 (V + 44730)
+ 0x1111, 0x1172, 0,
+#undef V11454
+#define V11454 (V + 44733)
+ 0x1111, 0x1172, 0x11a8, 0,
+#undef V11455
+#define V11455 (V + 44737)
+ 0x1111, 0x1172, 0x11a9, 0,
+#undef V11456
+#define V11456 (V + 44741)
+ 0x1111, 0x1172, 0x11aa, 0,
+#undef V11457
+#define V11457 (V + 44745)
+ 0x1111, 0x1172, 0x11ab, 0,
+#undef V11458
+#define V11458 (V + 44749)
+ 0x1111, 0x1172, 0x11ac, 0,
+#undef V11459
+#define V11459 (V + 44753)
+ 0x1111, 0x1172, 0x11ad, 0,
+#undef V11460
+#define V11460 (V + 44757)
+ 0x1111, 0x1172, 0x11ae, 0,
+#undef V11461
+#define V11461 (V + 44761)
+ 0x1111, 0x1172, 0x11af, 0,
+#undef V11462
+#define V11462 (V + 44765)
+ 0x1111, 0x1172, 0x11b0, 0,
+#undef V11463
+#define V11463 (V + 44769)
+ 0x1111, 0x1172, 0x11b1, 0,
+#undef V11464
+#define V11464 (V + 44773)
+ 0x1111, 0x1172, 0x11b2, 0,
+#undef V11465
+#define V11465 (V + 44777)
+ 0x1111, 0x1172, 0x11b3, 0,
+#undef V11466
+#define V11466 (V + 44781)
+ 0x1111, 0x1172, 0x11b4, 0,
+#undef V11467
+#define V11467 (V + 44785)
+ 0x1111, 0x1172, 0x11b5, 0,
+#undef V11468
+#define V11468 (V + 44789)
+ 0x1111, 0x1172, 0x11b6, 0,
+#undef V11469
+#define V11469 (V + 44793)
+ 0x1111, 0x1172, 0x11b7, 0,
+#undef V11470
+#define V11470 (V + 44797)
+ 0x1111, 0x1172, 0x11b8, 0,
+#undef V11471
+#define V11471 (V + 44801)
+ 0x1111, 0x1172, 0x11b9, 0,
+#undef V11472
+#define V11472 (V + 44805)
+ 0x1111, 0x1172, 0x11ba, 0,
+#undef V11473
+#define V11473 (V + 44809)
+ 0x1111, 0x1172, 0x11bb, 0,
+#undef V11474
+#define V11474 (V + 44813)
+ 0x1111, 0x1172, 0x11bc, 0,
+#undef V11475
+#define V11475 (V + 44817)
+ 0x1111, 0x1172, 0x11bd, 0,
+#undef V11476
+#define V11476 (V + 44821)
+ 0x1111, 0x1172, 0x11be, 0,
+#undef V11477
+#define V11477 (V + 44825)
+ 0x1111, 0x1172, 0x11bf, 0,
+#undef V11478
+#define V11478 (V + 44829)
+ 0x1111, 0x1172, 0x11c0, 0,
+#undef V11479
+#define V11479 (V + 44833)
+ 0x1111, 0x1172, 0x11c1, 0,
+#undef V11480
+#define V11480 (V + 44837)
+ 0x1111, 0x1172, 0x11c2, 0,
+#undef V11481
+#define V11481 (V + 44841)
+ 0x1111, 0x1173, 0,
+#undef V11482
+#define V11482 (V + 44844)
+ 0x1111, 0x1173, 0x11a8, 0,
+#undef V11483
+#define V11483 (V + 44848)
+ 0x1111, 0x1173, 0x11a9, 0,
+#undef V11484
+#define V11484 (V + 44852)
+ 0x1111, 0x1173, 0x11aa, 0,
+#undef V11485
+#define V11485 (V + 44856)
+ 0x1111, 0x1173, 0x11ab, 0,
+#undef V11486
+#define V11486 (V + 44860)
+ 0x1111, 0x1173, 0x11ac, 0,
+#undef V11487
+#define V11487 (V + 44864)
+ 0x1111, 0x1173, 0x11ad, 0,
+#undef V11488
+#define V11488 (V + 44868)
+ 0x1111, 0x1173, 0x11ae, 0,
+#undef V11489
+#define V11489 (V + 44872)
+ 0x1111, 0x1173, 0x11af, 0,
+#undef V11490
+#define V11490 (V + 44876)
+ 0x1111, 0x1173, 0x11b0, 0,
+#undef V11491
+#define V11491 (V + 44880)
+ 0x1111, 0x1173, 0x11b1, 0,
+#undef V11492
+#define V11492 (V + 44884)
+ 0x1111, 0x1173, 0x11b2, 0,
+#undef V11493
+#define V11493 (V + 44888)
+ 0x1111, 0x1173, 0x11b3, 0,
+#undef V11494
+#define V11494 (V + 44892)
+ 0x1111, 0x1173, 0x11b4, 0,
+#undef V11495
+#define V11495 (V + 44896)
+ 0x1111, 0x1173, 0x11b5, 0,
+#undef V11496
+#define V11496 (V + 44900)
+ 0x1111, 0x1173, 0x11b6, 0,
+#undef V11497
+#define V11497 (V + 44904)
+ 0x1111, 0x1173, 0x11b7, 0,
+#undef V11498
+#define V11498 (V + 44908)
+ 0x1111, 0x1173, 0x11b8, 0,
+#undef V11499
+#define V11499 (V + 44912)
+ 0x1111, 0x1173, 0x11b9, 0,
+#undef V11500
+#define V11500 (V + 44916)
+ 0x1111, 0x1173, 0x11ba, 0,
+#undef V11501
+#define V11501 (V + 44920)
+ 0x1111, 0x1173, 0x11bb, 0,
+#undef V11502
+#define V11502 (V + 44924)
+ 0x1111, 0x1173, 0x11bc, 0,
+#undef V11503
+#define V11503 (V + 44928)
+ 0x1111, 0x1173, 0x11bd, 0,
+#undef V11504
+#define V11504 (V + 44932)
+ 0x1111, 0x1173, 0x11be, 0,
+#undef V11505
+#define V11505 (V + 44936)
+ 0x1111, 0x1173, 0x11bf, 0,
+#undef V11506
+#define V11506 (V + 44940)
+ 0x1111, 0x1173, 0x11c0, 0,
+#undef V11507
+#define V11507 (V + 44944)
+ 0x1111, 0x1173, 0x11c1, 0,
+#undef V11508
+#define V11508 (V + 44948)
+ 0x1111, 0x1173, 0x11c2, 0,
+#undef V11509
+#define V11509 (V + 44952)
+ 0x1111, 0x1174, 0,
+#undef V11510
+#define V11510 (V + 44955)
+ 0x1111, 0x1174, 0x11a8, 0,
+#undef V11511
+#define V11511 (V + 44959)
+ 0x1111, 0x1174, 0x11a9, 0,
+#undef V11512
+#define V11512 (V + 44963)
+ 0x1111, 0x1174, 0x11aa, 0,
+#undef V11513
+#define V11513 (V + 44967)
+ 0x1111, 0x1174, 0x11ab, 0,
+#undef V11514
+#define V11514 (V + 44971)
+ 0x1111, 0x1174, 0x11ac, 0,
+#undef V11515
+#define V11515 (V + 44975)
+ 0x1111, 0x1174, 0x11ad, 0,
+#undef V11516
+#define V11516 (V + 44979)
+ 0x1111, 0x1174, 0x11ae, 0,
+#undef V11517
+#define V11517 (V + 44983)
+ 0x1111, 0x1174, 0x11af, 0,
+#undef V11518
+#define V11518 (V + 44987)
+ 0x1111, 0x1174, 0x11b0, 0,
+#undef V11519
+#define V11519 (V + 44991)
+ 0x1111, 0x1174, 0x11b1, 0,
+#undef V11520
+#define V11520 (V + 44995)
+ 0x1111, 0x1174, 0x11b2, 0,
+#undef V11521
+#define V11521 (V + 44999)
+ 0x1111, 0x1174, 0x11b3, 0,
+#undef V11522
+#define V11522 (V + 45003)
+ 0x1111, 0x1174, 0x11b4, 0,
+#undef V11523
+#define V11523 (V + 45007)
+ 0x1111, 0x1174, 0x11b5, 0,
+#undef V11524
+#define V11524 (V + 45011)
+ 0x1111, 0x1174, 0x11b6, 0,
+#undef V11525
+#define V11525 (V + 45015)
+ 0x1111, 0x1174, 0x11b7, 0,
+#undef V11526
+#define V11526 (V + 45019)
+ 0x1111, 0x1174, 0x11b8, 0,
+#undef V11527
+#define V11527 (V + 45023)
+ 0x1111, 0x1174, 0x11b9, 0,
+#undef V11528
+#define V11528 (V + 45027)
+ 0x1111, 0x1174, 0x11ba, 0,
+#undef V11529
+#define V11529 (V + 45031)
+ 0x1111, 0x1174, 0x11bb, 0,
+#undef V11530
+#define V11530 (V + 45035)
+ 0x1111, 0x1174, 0x11bc, 0,
+#undef V11531
+#define V11531 (V + 45039)
+ 0x1111, 0x1174, 0x11bd, 0,
+#undef V11532
+#define V11532 (V + 45043)
+ 0x1111, 0x1174, 0x11be, 0,
+#undef V11533
+#define V11533 (V + 45047)
+ 0x1111, 0x1174, 0x11bf, 0,
+#undef V11534
+#define V11534 (V + 45051)
+ 0x1111, 0x1174, 0x11c0, 0,
+#undef V11535
+#define V11535 (V + 45055)
+ 0x1111, 0x1174, 0x11c1, 0,
+#undef V11536
+#define V11536 (V + 45059)
+ 0x1111, 0x1174, 0x11c2, 0,
+#undef V11537
+#define V11537 (V + 45063)
+ 0x1111, 0x1175, 0,
+#undef V11538
+#define V11538 (V + 45066)
+ 0x1111, 0x1175, 0x11a8, 0,
+#undef V11539
+#define V11539 (V + 45070)
+ 0x1111, 0x1175, 0x11a9, 0,
+#undef V11540
+#define V11540 (V + 45074)
+ 0x1111, 0x1175, 0x11aa, 0,
+#undef V11541
+#define V11541 (V + 45078)
+ 0x1111, 0x1175, 0x11ab, 0,
+#undef V11542
+#define V11542 (V + 45082)
+ 0x1111, 0x1175, 0x11ac, 0,
+#undef V11543
+#define V11543 (V + 45086)
+ 0x1111, 0x1175, 0x11ad, 0,
+#undef V11544
+#define V11544 (V + 45090)
+ 0x1111, 0x1175, 0x11ae, 0,
+#undef V11545
+#define V11545 (V + 45094)
+ 0x1111, 0x1175, 0x11af, 0,
+#undef V11546
+#define V11546 (V + 45098)
+ 0x1111, 0x1175, 0x11b0, 0,
+#undef V11547
+#define V11547 (V + 45102)
+ 0x1111, 0x1175, 0x11b1, 0,
+#undef V11548
+#define V11548 (V + 45106)
+ 0x1111, 0x1175, 0x11b2, 0,
+#undef V11549
+#define V11549 (V + 45110)
+ 0x1111, 0x1175, 0x11b3, 0,
+#undef V11550
+#define V11550 (V + 45114)
+ 0x1111, 0x1175, 0x11b4, 0,
+#undef V11551
+#define V11551 (V + 45118)
+ 0x1111, 0x1175, 0x11b5, 0,
+#undef V11552
+#define V11552 (V + 45122)
+ 0x1111, 0x1175, 0x11b6, 0,
+#undef V11553
+#define V11553 (V + 45126)
+ 0x1111, 0x1175, 0x11b7, 0,
+#undef V11554
+#define V11554 (V + 45130)
+ 0x1111, 0x1175, 0x11b8, 0,
+#undef V11555
+#define V11555 (V + 45134)
+ 0x1111, 0x1175, 0x11b9, 0,
+#undef V11556
+#define V11556 (V + 45138)
+ 0x1111, 0x1175, 0x11ba, 0,
+#undef V11557
+#define V11557 (V + 45142)
+ 0x1111, 0x1175, 0x11bb, 0,
+#undef V11558
+#define V11558 (V + 45146)
+ 0x1111, 0x1175, 0x11bc, 0,
+#undef V11559
+#define V11559 (V + 45150)
+ 0x1111, 0x1175, 0x11bd, 0,
+#undef V11560
+#define V11560 (V + 45154)
+ 0x1111, 0x1175, 0x11be, 0,
+#undef V11561
+#define V11561 (V + 45158)
+ 0x1111, 0x1175, 0x11bf, 0,
+#undef V11562
+#define V11562 (V + 45162)
+ 0x1111, 0x1175, 0x11c0, 0,
+#undef V11563
+#define V11563 (V + 45166)
+ 0x1111, 0x1175, 0x11c1, 0,
+#undef V11564
+#define V11564 (V + 45170)
+ 0x1111, 0x1175, 0x11c2, 0,
+#undef V11565
+#define V11565 (V + 45174)
+ 0x1112, 0x1161, 0,
+#undef V11566
+#define V11566 (V + 45177)
+ 0x1112, 0x1161, 0x11a8, 0,
+#undef V11567
+#define V11567 (V + 45181)
+ 0x1112, 0x1161, 0x11a9, 0,
+#undef V11568
+#define V11568 (V + 45185)
+ 0x1112, 0x1161, 0x11aa, 0,
+#undef V11569
+#define V11569 (V + 45189)
+ 0x1112, 0x1161, 0x11ab, 0,
+#undef V11570
+#define V11570 (V + 45193)
+ 0x1112, 0x1161, 0x11ac, 0,
+#undef V11571
+#define V11571 (V + 45197)
+ 0x1112, 0x1161, 0x11ad, 0,
+#undef V11572
+#define V11572 (V + 45201)
+ 0x1112, 0x1161, 0x11ae, 0,
+#undef V11573
+#define V11573 (V + 45205)
+ 0x1112, 0x1161, 0x11af, 0,
+#undef V11574
+#define V11574 (V + 45209)
+ 0x1112, 0x1161, 0x11b0, 0,
+#undef V11575
+#define V11575 (V + 45213)
+ 0x1112, 0x1161, 0x11b1, 0,
+#undef V11576
+#define V11576 (V + 45217)
+ 0x1112, 0x1161, 0x11b2, 0,
+#undef V11577
+#define V11577 (V + 45221)
+ 0x1112, 0x1161, 0x11b3, 0,
+#undef V11578
+#define V11578 (V + 45225)
+ 0x1112, 0x1161, 0x11b4, 0,
+#undef V11579
+#define V11579 (V + 45229)
+ 0x1112, 0x1161, 0x11b5, 0,
+#undef V11580
+#define V11580 (V + 45233)
+ 0x1112, 0x1161, 0x11b6, 0,
+#undef V11581
+#define V11581 (V + 45237)
+ 0x1112, 0x1161, 0x11b7, 0,
+#undef V11582
+#define V11582 (V + 45241)
+ 0x1112, 0x1161, 0x11b8, 0,
+#undef V11583
+#define V11583 (V + 45245)
+ 0x1112, 0x1161, 0x11b9, 0,
+#undef V11584
+#define V11584 (V + 45249)
+ 0x1112, 0x1161, 0x11ba, 0,
+#undef V11585
+#define V11585 (V + 45253)
+ 0x1112, 0x1161, 0x11bb, 0,
+#undef V11586
+#define V11586 (V + 45257)
+ 0x1112, 0x1161, 0x11bc, 0,
+#undef V11587
+#define V11587 (V + 45261)
+ 0x1112, 0x1161, 0x11bd, 0,
+#undef V11588
+#define V11588 (V + 45265)
+ 0x1112, 0x1161, 0x11be, 0,
+#undef V11589
+#define V11589 (V + 45269)
+ 0x1112, 0x1161, 0x11bf, 0,
+#undef V11590
+#define V11590 (V + 45273)
+ 0x1112, 0x1161, 0x11c0, 0,
+#undef V11591
+#define V11591 (V + 45277)
+ 0x1112, 0x1161, 0x11c1, 0,
+#undef V11592
+#define V11592 (V + 45281)
+ 0x1112, 0x1161, 0x11c2, 0,
+#undef V11593
+#define V11593 (V + 45285)
+ 0x1112, 0x1162, 0,
+#undef V11594
+#define V11594 (V + 45288)
+ 0x1112, 0x1162, 0x11a8, 0,
+#undef V11595
+#define V11595 (V + 45292)
+ 0x1112, 0x1162, 0x11a9, 0,
+#undef V11596
+#define V11596 (V + 45296)
+ 0x1112, 0x1162, 0x11aa, 0,
+#undef V11597
+#define V11597 (V + 45300)
+ 0x1112, 0x1162, 0x11ab, 0,
+#undef V11598
+#define V11598 (V + 45304)
+ 0x1112, 0x1162, 0x11ac, 0,
+#undef V11599
+#define V11599 (V + 45308)
+ 0x1112, 0x1162, 0x11ad, 0,
+#undef V11600
+#define V11600 (V + 45312)
+ 0x1112, 0x1162, 0x11ae, 0,
+#undef V11601
+#define V11601 (V + 45316)
+ 0x1112, 0x1162, 0x11af, 0,
+#undef V11602
+#define V11602 (V + 45320)
+ 0x1112, 0x1162, 0x11b0, 0,
+#undef V11603
+#define V11603 (V + 45324)
+ 0x1112, 0x1162, 0x11b1, 0,
+#undef V11604
+#define V11604 (V + 45328)
+ 0x1112, 0x1162, 0x11b2, 0,
+#undef V11605
+#define V11605 (V + 45332)
+ 0x1112, 0x1162, 0x11b3, 0,
+#undef V11606
+#define V11606 (V + 45336)
+ 0x1112, 0x1162, 0x11b4, 0,
+#undef V11607
+#define V11607 (V + 45340)
+ 0x1112, 0x1162, 0x11b5, 0,
+#undef V11608
+#define V11608 (V + 45344)
+ 0x1112, 0x1162, 0x11b6, 0,
+#undef V11609
+#define V11609 (V + 45348)
+ 0x1112, 0x1162, 0x11b7, 0,
+#undef V11610
+#define V11610 (V + 45352)
+ 0x1112, 0x1162, 0x11b8, 0,
+#undef V11611
+#define V11611 (V + 45356)
+ 0x1112, 0x1162, 0x11b9, 0,
+#undef V11612
+#define V11612 (V + 45360)
+ 0x1112, 0x1162, 0x11ba, 0,
+#undef V11613
+#define V11613 (V + 45364)
+ 0x1112, 0x1162, 0x11bb, 0,
+#undef V11614
+#define V11614 (V + 45368)
+ 0x1112, 0x1162, 0x11bc, 0,
+#undef V11615
+#define V11615 (V + 45372)
+ 0x1112, 0x1162, 0x11bd, 0,
+#undef V11616
+#define V11616 (V + 45376)
+ 0x1112, 0x1162, 0x11be, 0,
+#undef V11617
+#define V11617 (V + 45380)
+ 0x1112, 0x1162, 0x11bf, 0,
+#undef V11618
+#define V11618 (V + 45384)
+ 0x1112, 0x1162, 0x11c0, 0,
+#undef V11619
+#define V11619 (V + 45388)
+ 0x1112, 0x1162, 0x11c1, 0,
+#undef V11620
+#define V11620 (V + 45392)
+ 0x1112, 0x1162, 0x11c2, 0,
+#undef V11621
+#define V11621 (V + 45396)
+ 0x1112, 0x1163, 0,
+#undef V11622
+#define V11622 (V + 45399)
+ 0x1112, 0x1163, 0x11a8, 0,
+#undef V11623
+#define V11623 (V + 45403)
+ 0x1112, 0x1163, 0x11a9, 0,
+#undef V11624
+#define V11624 (V + 45407)
+ 0x1112, 0x1163, 0x11aa, 0,
+#undef V11625
+#define V11625 (V + 45411)
+ 0x1112, 0x1163, 0x11ab, 0,
+#undef V11626
+#define V11626 (V + 45415)
+ 0x1112, 0x1163, 0x11ac, 0,
+#undef V11627
+#define V11627 (V + 45419)
+ 0x1112, 0x1163, 0x11ad, 0,
+#undef V11628
+#define V11628 (V + 45423)
+ 0x1112, 0x1163, 0x11ae, 0,
+#undef V11629
+#define V11629 (V + 45427)
+ 0x1112, 0x1163, 0x11af, 0,
+#undef V11630
+#define V11630 (V + 45431)
+ 0x1112, 0x1163, 0x11b0, 0,
+#undef V11631
+#define V11631 (V + 45435)
+ 0x1112, 0x1163, 0x11b1, 0,
+#undef V11632
+#define V11632 (V + 45439)
+ 0x1112, 0x1163, 0x11b2, 0,
+#undef V11633
+#define V11633 (V + 45443)
+ 0x1112, 0x1163, 0x11b3, 0,
+#undef V11634
+#define V11634 (V + 45447)
+ 0x1112, 0x1163, 0x11b4, 0,
+#undef V11635
+#define V11635 (V + 45451)
+ 0x1112, 0x1163, 0x11b5, 0,
+#undef V11636
+#define V11636 (V + 45455)
+ 0x1112, 0x1163, 0x11b6, 0,
+#undef V11637
+#define V11637 (V + 45459)
+ 0x1112, 0x1163, 0x11b7, 0,
+#undef V11638
+#define V11638 (V + 45463)
+ 0x1112, 0x1163, 0x11b8, 0,
+#undef V11639
+#define V11639 (V + 45467)
+ 0x1112, 0x1163, 0x11b9, 0,
+#undef V11640
+#define V11640 (V + 45471)
+ 0x1112, 0x1163, 0x11ba, 0,
+#undef V11641
+#define V11641 (V + 45475)
+ 0x1112, 0x1163, 0x11bb, 0,
+#undef V11642
+#define V11642 (V + 45479)
+ 0x1112, 0x1163, 0x11bc, 0,
+#undef V11643
+#define V11643 (V + 45483)
+ 0x1112, 0x1163, 0x11bd, 0,
+#undef V11644
+#define V11644 (V + 45487)
+ 0x1112, 0x1163, 0x11be, 0,
+#undef V11645
+#define V11645 (V + 45491)
+ 0x1112, 0x1163, 0x11bf, 0,
+#undef V11646
+#define V11646 (V + 45495)
+ 0x1112, 0x1163, 0x11c0, 0,
+#undef V11647
+#define V11647 (V + 45499)
+ 0x1112, 0x1163, 0x11c1, 0,
+#undef V11648
+#define V11648 (V + 45503)
+ 0x1112, 0x1163, 0x11c2, 0,
+#undef V11649
+#define V11649 (V + 45507)
+ 0x1112, 0x1164, 0,
+#undef V11650
+#define V11650 (V + 45510)
+ 0x1112, 0x1164, 0x11a8, 0,
+#undef V11651
+#define V11651 (V + 45514)
+ 0x1112, 0x1164, 0x11a9, 0,
+#undef V11652
+#define V11652 (V + 45518)
+ 0x1112, 0x1164, 0x11aa, 0,
+#undef V11653
+#define V11653 (V + 45522)
+ 0x1112, 0x1164, 0x11ab, 0,
+#undef V11654
+#define V11654 (V + 45526)
+ 0x1112, 0x1164, 0x11ac, 0,
+#undef V11655
+#define V11655 (V + 45530)
+ 0x1112, 0x1164, 0x11ad, 0,
+#undef V11656
+#define V11656 (V + 45534)
+ 0x1112, 0x1164, 0x11ae, 0,
+#undef V11657
+#define V11657 (V + 45538)
+ 0x1112, 0x1164, 0x11af, 0,
+#undef V11658
+#define V11658 (V + 45542)
+ 0x1112, 0x1164, 0x11b0, 0,
+#undef V11659
+#define V11659 (V + 45546)
+ 0x1112, 0x1164, 0x11b1, 0,
+#undef V11660
+#define V11660 (V + 45550)
+ 0x1112, 0x1164, 0x11b2, 0,
+#undef V11661
+#define V11661 (V + 45554)
+ 0x1112, 0x1164, 0x11b3, 0,
+#undef V11662
+#define V11662 (V + 45558)
+ 0x1112, 0x1164, 0x11b4, 0,
+#undef V11663
+#define V11663 (V + 45562)
+ 0x1112, 0x1164, 0x11b5, 0,
+#undef V11664
+#define V11664 (V + 45566)
+ 0x1112, 0x1164, 0x11b6, 0,
+#undef V11665
+#define V11665 (V + 45570)
+ 0x1112, 0x1164, 0x11b7, 0,
+#undef V11666
+#define V11666 (V + 45574)
+ 0x1112, 0x1164, 0x11b8, 0,
+#undef V11667
+#define V11667 (V + 45578)
+ 0x1112, 0x1164, 0x11b9, 0,
+#undef V11668
+#define V11668 (V + 45582)
+ 0x1112, 0x1164, 0x11ba, 0,
+#undef V11669
+#define V11669 (V + 45586)
+ 0x1112, 0x1164, 0x11bb, 0,
+#undef V11670
+#define V11670 (V + 45590)
+ 0x1112, 0x1164, 0x11bc, 0,
+#undef V11671
+#define V11671 (V + 45594)
+ 0x1112, 0x1164, 0x11bd, 0,
+#undef V11672
+#define V11672 (V + 45598)
+ 0x1112, 0x1164, 0x11be, 0,
+#undef V11673
+#define V11673 (V + 45602)
+ 0x1112, 0x1164, 0x11bf, 0,
+#undef V11674
+#define V11674 (V + 45606)
+ 0x1112, 0x1164, 0x11c0, 0,
+#undef V11675
+#define V11675 (V + 45610)
+ 0x1112, 0x1164, 0x11c1, 0,
+#undef V11676
+#define V11676 (V + 45614)
+ 0x1112, 0x1164, 0x11c2, 0,
+#undef V11677
+#define V11677 (V + 45618)
+ 0x1112, 0x1165, 0,
+#undef V11678
+#define V11678 (V + 45621)
+ 0x1112, 0x1165, 0x11a8, 0,
+#undef V11679
+#define V11679 (V + 45625)
+ 0x1112, 0x1165, 0x11a9, 0,
+#undef V11680
+#define V11680 (V + 45629)
+ 0x1112, 0x1165, 0x11aa, 0,
+#undef V11681
+#define V11681 (V + 45633)
+ 0x1112, 0x1165, 0x11ab, 0,
+#undef V11682
+#define V11682 (V + 45637)
+ 0x1112, 0x1165, 0x11ac, 0,
+#undef V11683
+#define V11683 (V + 45641)
+ 0x1112, 0x1165, 0x11ad, 0,
+#undef V11684
+#define V11684 (V + 45645)
+ 0x1112, 0x1165, 0x11ae, 0,
+#undef V11685
+#define V11685 (V + 45649)
+ 0x1112, 0x1165, 0x11af, 0,
+#undef V11686
+#define V11686 (V + 45653)
+ 0x1112, 0x1165, 0x11b0, 0,
+#undef V11687
+#define V11687 (V + 45657)
+ 0x1112, 0x1165, 0x11b1, 0,
+#undef V11688
+#define V11688 (V + 45661)
+ 0x1112, 0x1165, 0x11b2, 0,
+#undef V11689
+#define V11689 (V + 45665)
+ 0x1112, 0x1165, 0x11b3, 0,
+#undef V11690
+#define V11690 (V + 45669)
+ 0x1112, 0x1165, 0x11b4, 0,
+#undef V11691
+#define V11691 (V + 45673)
+ 0x1112, 0x1165, 0x11b5, 0,
+#undef V11692
+#define V11692 (V + 45677)
+ 0x1112, 0x1165, 0x11b6, 0,
+#undef V11693
+#define V11693 (V + 45681)
+ 0x1112, 0x1165, 0x11b7, 0,
+#undef V11694
+#define V11694 (V + 45685)
+ 0x1112, 0x1165, 0x11b8, 0,
+#undef V11695
+#define V11695 (V + 45689)
+ 0x1112, 0x1165, 0x11b9, 0,
+#undef V11696
+#define V11696 (V + 45693)
+ 0x1112, 0x1165, 0x11ba, 0,
+#undef V11697
+#define V11697 (V + 45697)
+ 0x1112, 0x1165, 0x11bb, 0,
+#undef V11698
+#define V11698 (V + 45701)
+ 0x1112, 0x1165, 0x11bc, 0,
+#undef V11699
+#define V11699 (V + 45705)
+ 0x1112, 0x1165, 0x11bd, 0,
+#undef V11700
+#define V11700 (V + 45709)
+ 0x1112, 0x1165, 0x11be, 0,
+#undef V11701
+#define V11701 (V + 45713)
+ 0x1112, 0x1165, 0x11bf, 0,
+#undef V11702
+#define V11702 (V + 45717)
+ 0x1112, 0x1165, 0x11c0, 0,
+#undef V11703
+#define V11703 (V + 45721)
+ 0x1112, 0x1165, 0x11c1, 0,
+#undef V11704
+#define V11704 (V + 45725)
+ 0x1112, 0x1165, 0x11c2, 0,
+#undef V11705
+#define V11705 (V + 45729)
+ 0x1112, 0x1166, 0,
+#undef V11706
+#define V11706 (V + 45732)
+ 0x1112, 0x1166, 0x11a8, 0,
+#undef V11707
+#define V11707 (V + 45736)
+ 0x1112, 0x1166, 0x11a9, 0,
+#undef V11708
+#define V11708 (V + 45740)
+ 0x1112, 0x1166, 0x11aa, 0,
+#undef V11709
+#define V11709 (V + 45744)
+ 0x1112, 0x1166, 0x11ab, 0,
+#undef V11710
+#define V11710 (V + 45748)
+ 0x1112, 0x1166, 0x11ac, 0,
+#undef V11711
+#define V11711 (V + 45752)
+ 0x1112, 0x1166, 0x11ad, 0,
+#undef V11712
+#define V11712 (V + 45756)
+ 0x1112, 0x1166, 0x11ae, 0,
+#undef V11713
+#define V11713 (V + 45760)
+ 0x1112, 0x1166, 0x11af, 0,
+#undef V11714
+#define V11714 (V + 45764)
+ 0x1112, 0x1166, 0x11b0, 0,
+#undef V11715
+#define V11715 (V + 45768)
+ 0x1112, 0x1166, 0x11b1, 0,
+#undef V11716
+#define V11716 (V + 45772)
+ 0x1112, 0x1166, 0x11b2, 0,
+#undef V11717
+#define V11717 (V + 45776)
+ 0x1112, 0x1166, 0x11b3, 0,
+#undef V11718
+#define V11718 (V + 45780)
+ 0x1112, 0x1166, 0x11b4, 0,
+#undef V11719
+#define V11719 (V + 45784)
+ 0x1112, 0x1166, 0x11b5, 0,
+#undef V11720
+#define V11720 (V + 45788)
+ 0x1112, 0x1166, 0x11b6, 0,
+#undef V11721
+#define V11721 (V + 45792)
+ 0x1112, 0x1166, 0x11b7, 0,
+#undef V11722
+#define V11722 (V + 45796)
+ 0x1112, 0x1166, 0x11b8, 0,
+#undef V11723
+#define V11723 (V + 45800)
+ 0x1112, 0x1166, 0x11b9, 0,
+#undef V11724
+#define V11724 (V + 45804)
+ 0x1112, 0x1166, 0x11ba, 0,
+#undef V11725
+#define V11725 (V + 45808)
+ 0x1112, 0x1166, 0x11bb, 0,
+#undef V11726
+#define V11726 (V + 45812)
+ 0x1112, 0x1166, 0x11bc, 0,
+#undef V11727
+#define V11727 (V + 45816)
+ 0x1112, 0x1166, 0x11bd, 0,
+#undef V11728
+#define V11728 (V + 45820)
+ 0x1112, 0x1166, 0x11be, 0,
+#undef V11729
+#define V11729 (V + 45824)
+ 0x1112, 0x1166, 0x11bf, 0,
+#undef V11730
+#define V11730 (V + 45828)
+ 0x1112, 0x1166, 0x11c0, 0,
+#undef V11731
+#define V11731 (V + 45832)
+ 0x1112, 0x1166, 0x11c1, 0,
+#undef V11732
+#define V11732 (V + 45836)
+ 0x1112, 0x1166, 0x11c2, 0,
+#undef V11733
+#define V11733 (V + 45840)
+ 0x1112, 0x1167, 0,
+#undef V11734
+#define V11734 (V + 45843)
+ 0x1112, 0x1167, 0x11a8, 0,
+#undef V11735
+#define V11735 (V + 45847)
+ 0x1112, 0x1167, 0x11a9, 0,
+#undef V11736
+#define V11736 (V + 45851)
+ 0x1112, 0x1167, 0x11aa, 0,
+#undef V11737
+#define V11737 (V + 45855)
+ 0x1112, 0x1167, 0x11ab, 0,
+#undef V11738
+#define V11738 (V + 45859)
+ 0x1112, 0x1167, 0x11ac, 0,
+#undef V11739
+#define V11739 (V + 45863)
+ 0x1112, 0x1167, 0x11ad, 0,
+#undef V11740
+#define V11740 (V + 45867)
+ 0x1112, 0x1167, 0x11ae, 0,
+#undef V11741
+#define V11741 (V + 45871)
+ 0x1112, 0x1167, 0x11af, 0,
+#undef V11742
+#define V11742 (V + 45875)
+ 0x1112, 0x1167, 0x11b0, 0,
+#undef V11743
+#define V11743 (V + 45879)
+ 0x1112, 0x1167, 0x11b1, 0,
+#undef V11744
+#define V11744 (V + 45883)
+ 0x1112, 0x1167, 0x11b2, 0,
+#undef V11745
+#define V11745 (V + 45887)
+ 0x1112, 0x1167, 0x11b3, 0,
+#undef V11746
+#define V11746 (V + 45891)
+ 0x1112, 0x1167, 0x11b4, 0,
+#undef V11747
+#define V11747 (V + 45895)
+ 0x1112, 0x1167, 0x11b5, 0,
+#undef V11748
+#define V11748 (V + 45899)
+ 0x1112, 0x1167, 0x11b6, 0,
+#undef V11749
+#define V11749 (V + 45903)
+ 0x1112, 0x1167, 0x11b7, 0,
+#undef V11750
+#define V11750 (V + 45907)
+ 0x1112, 0x1167, 0x11b8, 0,
+#undef V11751
+#define V11751 (V + 45911)
+ 0x1112, 0x1167, 0x11b9, 0,
+#undef V11752
+#define V11752 (V + 45915)
+ 0x1112, 0x1167, 0x11ba, 0,
+#undef V11753
+#define V11753 (V + 45919)
+ 0x1112, 0x1167, 0x11bb, 0,
+#undef V11754
+#define V11754 (V + 45923)
+ 0x1112, 0x1167, 0x11bc, 0,
+#undef V11755
+#define V11755 (V + 45927)
+ 0x1112, 0x1167, 0x11bd, 0,
+#undef V11756
+#define V11756 (V + 45931)
+ 0x1112, 0x1167, 0x11be, 0,
+#undef V11757
+#define V11757 (V + 45935)
+ 0x1112, 0x1167, 0x11bf, 0,
+#undef V11758
+#define V11758 (V + 45939)
+ 0x1112, 0x1167, 0x11c0, 0,
+#undef V11759
+#define V11759 (V + 45943)
+ 0x1112, 0x1167, 0x11c1, 0,
+#undef V11760
+#define V11760 (V + 45947)
+ 0x1112, 0x1167, 0x11c2, 0,
+#undef V11761
+#define V11761 (V + 45951)
+ 0x1112, 0x1168, 0,
+#undef V11762
+#define V11762 (V + 45954)
+ 0x1112, 0x1168, 0x11a8, 0,
+#undef V11763
+#define V11763 (V + 45958)
+ 0x1112, 0x1168, 0x11a9, 0,
+#undef V11764
+#define V11764 (V + 45962)
+ 0x1112, 0x1168, 0x11aa, 0,
+#undef V11765
+#define V11765 (V + 45966)
+ 0x1112, 0x1168, 0x11ab, 0,
+#undef V11766
+#define V11766 (V + 45970)
+ 0x1112, 0x1168, 0x11ac, 0,
+#undef V11767
+#define V11767 (V + 45974)
+ 0x1112, 0x1168, 0x11ad, 0,
+#undef V11768
+#define V11768 (V + 45978)
+ 0x1112, 0x1168, 0x11ae, 0,
+#undef V11769
+#define V11769 (V + 45982)
+ 0x1112, 0x1168, 0x11af, 0,
+#undef V11770
+#define V11770 (V + 45986)
+ 0x1112, 0x1168, 0x11b0, 0,
+#undef V11771
+#define V11771 (V + 45990)
+ 0x1112, 0x1168, 0x11b1, 0,
+#undef V11772
+#define V11772 (V + 45994)
+ 0x1112, 0x1168, 0x11b2, 0,
+#undef V11773
+#define V11773 (V + 45998)
+ 0x1112, 0x1168, 0x11b3, 0,
+#undef V11774
+#define V11774 (V + 46002)
+ 0x1112, 0x1168, 0x11b4, 0,
+#undef V11775
+#define V11775 (V + 46006)
+ 0x1112, 0x1168, 0x11b5, 0,
+#undef V11776
+#define V11776 (V + 46010)
+ 0x1112, 0x1168, 0x11b6, 0,
+#undef V11777
+#define V11777 (V + 46014)
+ 0x1112, 0x1168, 0x11b7, 0,
+#undef V11778
+#define V11778 (V + 46018)
+ 0x1112, 0x1168, 0x11b8, 0,
+#undef V11779
+#define V11779 (V + 46022)
+ 0x1112, 0x1168, 0x11b9, 0,
+#undef V11780
+#define V11780 (V + 46026)
+ 0x1112, 0x1168, 0x11ba, 0,
+#undef V11781
+#define V11781 (V + 46030)
+ 0x1112, 0x1168, 0x11bb, 0,
+#undef V11782
+#define V11782 (V + 46034)
+ 0x1112, 0x1168, 0x11bc, 0,
+#undef V11783
+#define V11783 (V + 46038)
+ 0x1112, 0x1168, 0x11bd, 0,
+#undef V11784
+#define V11784 (V + 46042)
+ 0x1112, 0x1168, 0x11be, 0,
+#undef V11785
+#define V11785 (V + 46046)
+ 0x1112, 0x1168, 0x11bf, 0,
+#undef V11786
+#define V11786 (V + 46050)
+ 0x1112, 0x1168, 0x11c0, 0,
+#undef V11787
+#define V11787 (V + 46054)
+ 0x1112, 0x1168, 0x11c1, 0,
+#undef V11788
+#define V11788 (V + 46058)
+ 0x1112, 0x1168, 0x11c2, 0,
+#undef V11789
+#define V11789 (V + 46062)
+ 0x1112, 0x1169, 0,
+#undef V11790
+#define V11790 (V + 46065)
+ 0x1112, 0x1169, 0x11a8, 0,
+#undef V11791
+#define V11791 (V + 46069)
+ 0x1112, 0x1169, 0x11a9, 0,
+#undef V11792
+#define V11792 (V + 46073)
+ 0x1112, 0x1169, 0x11aa, 0,
+#undef V11793
+#define V11793 (V + 46077)
+ 0x1112, 0x1169, 0x11ab, 0,
+#undef V11794
+#define V11794 (V + 46081)
+ 0x1112, 0x1169, 0x11ac, 0,
+#undef V11795
+#define V11795 (V + 46085)
+ 0x1112, 0x1169, 0x11ad, 0,
+#undef V11796
+#define V11796 (V + 46089)
+ 0x1112, 0x1169, 0x11ae, 0,
+#undef V11797
+#define V11797 (V + 46093)
+ 0x1112, 0x1169, 0x11af, 0,
+#undef V11798
+#define V11798 (V + 46097)
+ 0x1112, 0x1169, 0x11b0, 0,
+#undef V11799
+#define V11799 (V + 46101)
+ 0x1112, 0x1169, 0x11b1, 0,
+#undef V11800
+#define V11800 (V + 46105)
+ 0x1112, 0x1169, 0x11b2, 0,
+#undef V11801
+#define V11801 (V + 46109)
+ 0x1112, 0x1169, 0x11b3, 0,
+#undef V11802
+#define V11802 (V + 46113)
+ 0x1112, 0x1169, 0x11b4, 0,
+#undef V11803
+#define V11803 (V + 46117)
+ 0x1112, 0x1169, 0x11b5, 0,
+#undef V11804
+#define V11804 (V + 46121)
+ 0x1112, 0x1169, 0x11b6, 0,
+#undef V11805
+#define V11805 (V + 46125)
+ 0x1112, 0x1169, 0x11b7, 0,
+#undef V11806
+#define V11806 (V + 46129)
+ 0x1112, 0x1169, 0x11b8, 0,
+#undef V11807
+#define V11807 (V + 46133)
+ 0x1112, 0x1169, 0x11b9, 0,
+#undef V11808
+#define V11808 (V + 46137)
+ 0x1112, 0x1169, 0x11ba, 0,
+#undef V11809
+#define V11809 (V + 46141)
+ 0x1112, 0x1169, 0x11bb, 0,
+#undef V11810
+#define V11810 (V + 46145)
+ 0x1112, 0x1169, 0x11bc, 0,
+#undef V11811
+#define V11811 (V + 46149)
+ 0x1112, 0x1169, 0x11bd, 0,
+#undef V11812
+#define V11812 (V + 46153)
+ 0x1112, 0x1169, 0x11be, 0,
+#undef V11813
+#define V11813 (V + 46157)
+ 0x1112, 0x1169, 0x11bf, 0,
+#undef V11814
+#define V11814 (V + 46161)
+ 0x1112, 0x1169, 0x11c0, 0,
+#undef V11815
+#define V11815 (V + 46165)
+ 0x1112, 0x1169, 0x11c1, 0,
+#undef V11816
+#define V11816 (V + 46169)
+ 0x1112, 0x1169, 0x11c2, 0,
+#undef V11817
+#define V11817 (V + 46173)
+ 0x1112, 0x116a, 0,
+#undef V11818
+#define V11818 (V + 46176)
+ 0x1112, 0x116a, 0x11a8, 0,
+#undef V11819
+#define V11819 (V + 46180)
+ 0x1112, 0x116a, 0x11a9, 0,
+#undef V11820
+#define V11820 (V + 46184)
+ 0x1112, 0x116a, 0x11aa, 0,
+#undef V11821
+#define V11821 (V + 46188)
+ 0x1112, 0x116a, 0x11ab, 0,
+#undef V11822
+#define V11822 (V + 46192)
+ 0x1112, 0x116a, 0x11ac, 0,
+#undef V11823
+#define V11823 (V + 46196)
+ 0x1112, 0x116a, 0x11ad, 0,
+#undef V11824
+#define V11824 (V + 46200)
+ 0x1112, 0x116a, 0x11ae, 0,
+#undef V11825
+#define V11825 (V + 46204)
+ 0x1112, 0x116a, 0x11af, 0,
+#undef V11826
+#define V11826 (V + 46208)
+ 0x1112, 0x116a, 0x11b0, 0,
+#undef V11827
+#define V11827 (V + 46212)
+ 0x1112, 0x116a, 0x11b1, 0,
+#undef V11828
+#define V11828 (V + 46216)
+ 0x1112, 0x116a, 0x11b2, 0,
+#undef V11829
+#define V11829 (V + 46220)
+ 0x1112, 0x116a, 0x11b3, 0,
+#undef V11830
+#define V11830 (V + 46224)
+ 0x1112, 0x116a, 0x11b4, 0,
+#undef V11831
+#define V11831 (V + 46228)
+ 0x1112, 0x116a, 0x11b5, 0,
+#undef V11832
+#define V11832 (V + 46232)
+ 0x1112, 0x116a, 0x11b6, 0,
+#undef V11833
+#define V11833 (V + 46236)
+ 0x1112, 0x116a, 0x11b7, 0,
+#undef V11834
+#define V11834 (V + 46240)
+ 0x1112, 0x116a, 0x11b8, 0,
+#undef V11835
+#define V11835 (V + 46244)
+ 0x1112, 0x116a, 0x11b9, 0,
+#undef V11836
+#define V11836 (V + 46248)
+ 0x1112, 0x116a, 0x11ba, 0,
+#undef V11837
+#define V11837 (V + 46252)
+ 0x1112, 0x116a, 0x11bb, 0,
+#undef V11838
+#define V11838 (V + 46256)
+ 0x1112, 0x116a, 0x11bc, 0,
+#undef V11839
+#define V11839 (V + 46260)
+ 0x1112, 0x116a, 0x11bd, 0,
+#undef V11840
+#define V11840 (V + 46264)
+ 0x1112, 0x116a, 0x11be, 0,
+#undef V11841
+#define V11841 (V + 46268)
+ 0x1112, 0x116a, 0x11bf, 0,
+#undef V11842
+#define V11842 (V + 46272)
+ 0x1112, 0x116a, 0x11c0, 0,
+#undef V11843
+#define V11843 (V + 46276)
+ 0x1112, 0x116a, 0x11c1, 0,
+#undef V11844
+#define V11844 (V + 46280)
+ 0x1112, 0x116a, 0x11c2, 0,
+#undef V11845
+#define V11845 (V + 46284)
+ 0x1112, 0x116b, 0,
+#undef V11846
+#define V11846 (V + 46287)
+ 0x1112, 0x116b, 0x11a8, 0,
+#undef V11847
+#define V11847 (V + 46291)
+ 0x1112, 0x116b, 0x11a9, 0,
+#undef V11848
+#define V11848 (V + 46295)
+ 0x1112, 0x116b, 0x11aa, 0,
+#undef V11849
+#define V11849 (V + 46299)
+ 0x1112, 0x116b, 0x11ab, 0,
+#undef V11850
+#define V11850 (V + 46303)
+ 0x1112, 0x116b, 0x11ac, 0,
+#undef V11851
+#define V11851 (V + 46307)
+ 0x1112, 0x116b, 0x11ad, 0,
+#undef V11852
+#define V11852 (V + 46311)
+ 0x1112, 0x116b, 0x11ae, 0,
+#undef V11853
+#define V11853 (V + 46315)
+ 0x1112, 0x116b, 0x11af, 0,
+#undef V11854
+#define V11854 (V + 46319)
+ 0x1112, 0x116b, 0x11b0, 0,
+#undef V11855
+#define V11855 (V + 46323)
+ 0x1112, 0x116b, 0x11b1, 0,
+#undef V11856
+#define V11856 (V + 46327)
+ 0x1112, 0x116b, 0x11b2, 0,
+#undef V11857
+#define V11857 (V + 46331)
+ 0x1112, 0x116b, 0x11b3, 0,
+#undef V11858
+#define V11858 (V + 46335)
+ 0x1112, 0x116b, 0x11b4, 0,
+#undef V11859
+#define V11859 (V + 46339)
+ 0x1112, 0x116b, 0x11b5, 0,
+#undef V11860
+#define V11860 (V + 46343)
+ 0x1112, 0x116b, 0x11b6, 0,
+#undef V11861
+#define V11861 (V + 46347)
+ 0x1112, 0x116b, 0x11b7, 0,
+#undef V11862
+#define V11862 (V + 46351)
+ 0x1112, 0x116b, 0x11b8, 0,
+#undef V11863
+#define V11863 (V + 46355)
+ 0x1112, 0x116b, 0x11b9, 0,
+#undef V11864
+#define V11864 (V + 46359)
+ 0x1112, 0x116b, 0x11ba, 0,
+#undef V11865
+#define V11865 (V + 46363)
+ 0x1112, 0x116b, 0x11bb, 0,
+#undef V11866
+#define V11866 (V + 46367)
+ 0x1112, 0x116b, 0x11bc, 0,
+#undef V11867
+#define V11867 (V + 46371)
+ 0x1112, 0x116b, 0x11bd, 0,
+#undef V11868
+#define V11868 (V + 46375)
+ 0x1112, 0x116b, 0x11be, 0,
+#undef V11869
+#define V11869 (V + 46379)
+ 0x1112, 0x116b, 0x11bf, 0,
+#undef V11870
+#define V11870 (V + 46383)
+ 0x1112, 0x116b, 0x11c0, 0,
+#undef V11871
+#define V11871 (V + 46387)
+ 0x1112, 0x116b, 0x11c1, 0,
+#undef V11872
+#define V11872 (V + 46391)
+ 0x1112, 0x116b, 0x11c2, 0,
+#undef V11873
+#define V11873 (V + 46395)
+ 0x1112, 0x116c, 0,
+#undef V11874
+#define V11874 (V + 46398)
+ 0x1112, 0x116c, 0x11a8, 0,
+#undef V11875
+#define V11875 (V + 46402)
+ 0x1112, 0x116c, 0x11a9, 0,
+#undef V11876
+#define V11876 (V + 46406)
+ 0x1112, 0x116c, 0x11aa, 0,
+#undef V11877
+#define V11877 (V + 46410)
+ 0x1112, 0x116c, 0x11ab, 0,
+#undef V11878
+#define V11878 (V + 46414)
+ 0x1112, 0x116c, 0x11ac, 0,
+#undef V11879
+#define V11879 (V + 46418)
+ 0x1112, 0x116c, 0x11ad, 0,
+#undef V11880
+#define V11880 (V + 46422)
+ 0x1112, 0x116c, 0x11ae, 0,
+#undef V11881
+#define V11881 (V + 46426)
+ 0x1112, 0x116c, 0x11af, 0,
+#undef V11882
+#define V11882 (V + 46430)
+ 0x1112, 0x116c, 0x11b0, 0,
+#undef V11883
+#define V11883 (V + 46434)
+ 0x1112, 0x116c, 0x11b1, 0,
+#undef V11884
+#define V11884 (V + 46438)
+ 0x1112, 0x116c, 0x11b2, 0,
+#undef V11885
+#define V11885 (V + 46442)
+ 0x1112, 0x116c, 0x11b3, 0,
+#undef V11886
+#define V11886 (V + 46446)
+ 0x1112, 0x116c, 0x11b4, 0,
+#undef V11887
+#define V11887 (V + 46450)
+ 0x1112, 0x116c, 0x11b5, 0,
+#undef V11888
+#define V11888 (V + 46454)
+ 0x1112, 0x116c, 0x11b6, 0,
+#undef V11889
+#define V11889 (V + 46458)
+ 0x1112, 0x116c, 0x11b7, 0,
+#undef V11890
+#define V11890 (V + 46462)
+ 0x1112, 0x116c, 0x11b8, 0,
+#undef V11891
+#define V11891 (V + 46466)
+ 0x1112, 0x116c, 0x11b9, 0,
+#undef V11892
+#define V11892 (V + 46470)
+ 0x1112, 0x116c, 0x11ba, 0,
+#undef V11893
+#define V11893 (V + 46474)
+ 0x1112, 0x116c, 0x11bb, 0,
+#undef V11894
+#define V11894 (V + 46478)
+ 0x1112, 0x116c, 0x11bc, 0,
+#undef V11895
+#define V11895 (V + 46482)
+ 0x1112, 0x116c, 0x11bd, 0,
+#undef V11896
+#define V11896 (V + 46486)
+ 0x1112, 0x116c, 0x11be, 0,
+#undef V11897
+#define V11897 (V + 46490)
+ 0x1112, 0x116c, 0x11bf, 0,
+#undef V11898
+#define V11898 (V + 46494)
+ 0x1112, 0x116c, 0x11c0, 0,
+#undef V11899
+#define V11899 (V + 46498)
+ 0x1112, 0x116c, 0x11c1, 0,
+#undef V11900
+#define V11900 (V + 46502)
+ 0x1112, 0x116c, 0x11c2, 0,
+#undef V11901
+#define V11901 (V + 46506)
+ 0x1112, 0x116d, 0,
+#undef V11902
+#define V11902 (V + 46509)
+ 0x1112, 0x116d, 0x11a8, 0,
+#undef V11903
+#define V11903 (V + 46513)
+ 0x1112, 0x116d, 0x11a9, 0,
+#undef V11904
+#define V11904 (V + 46517)
+ 0x1112, 0x116d, 0x11aa, 0,
+#undef V11905
+#define V11905 (V + 46521)
+ 0x1112, 0x116d, 0x11ab, 0,
+#undef V11906
+#define V11906 (V + 46525)
+ 0x1112, 0x116d, 0x11ac, 0,
+#undef V11907
+#define V11907 (V + 46529)
+ 0x1112, 0x116d, 0x11ad, 0,
+#undef V11908
+#define V11908 (V + 46533)
+ 0x1112, 0x116d, 0x11ae, 0,
+#undef V11909
+#define V11909 (V + 46537)
+ 0x1112, 0x116d, 0x11af, 0,
+#undef V11910
+#define V11910 (V + 46541)
+ 0x1112, 0x116d, 0x11b0, 0,
+#undef V11911
+#define V11911 (V + 46545)
+ 0x1112, 0x116d, 0x11b1, 0,
+#undef V11912
+#define V11912 (V + 46549)
+ 0x1112, 0x116d, 0x11b2, 0,
+#undef V11913
+#define V11913 (V + 46553)
+ 0x1112, 0x116d, 0x11b3, 0,
+#undef V11914
+#define V11914 (V + 46557)
+ 0x1112, 0x116d, 0x11b4, 0,
+#undef V11915
+#define V11915 (V + 46561)
+ 0x1112, 0x116d, 0x11b5, 0,
+#undef V11916
+#define V11916 (V + 46565)
+ 0x1112, 0x116d, 0x11b6, 0,
+#undef V11917
+#define V11917 (V + 46569)
+ 0x1112, 0x116d, 0x11b7, 0,
+#undef V11918
+#define V11918 (V + 46573)
+ 0x1112, 0x116d, 0x11b8, 0,
+#undef V11919
+#define V11919 (V + 46577)
+ 0x1112, 0x116d, 0x11b9, 0,
+#undef V11920
+#define V11920 (V + 46581)
+ 0x1112, 0x116d, 0x11ba, 0,
+#undef V11921
+#define V11921 (V + 46585)
+ 0x1112, 0x116d, 0x11bb, 0,
+#undef V11922
+#define V11922 (V + 46589)
+ 0x1112, 0x116d, 0x11bc, 0,
+#undef V11923
+#define V11923 (V + 46593)
+ 0x1112, 0x116d, 0x11bd, 0,
+#undef V11924
+#define V11924 (V + 46597)
+ 0x1112, 0x116d, 0x11be, 0,
+#undef V11925
+#define V11925 (V + 46601)
+ 0x1112, 0x116d, 0x11bf, 0,
+#undef V11926
+#define V11926 (V + 46605)
+ 0x1112, 0x116d, 0x11c0, 0,
+#undef V11927
+#define V11927 (V + 46609)
+ 0x1112, 0x116d, 0x11c1, 0,
+#undef V11928
+#define V11928 (V + 46613)
+ 0x1112, 0x116d, 0x11c2, 0,
+#undef V11929
+#define V11929 (V + 46617)
+ 0x1112, 0x116e, 0,
+#undef V11930
+#define V11930 (V + 46620)
+ 0x1112, 0x116e, 0x11a8, 0,
+#undef V11931
+#define V11931 (V + 46624)
+ 0x1112, 0x116e, 0x11a9, 0,
+#undef V11932
+#define V11932 (V + 46628)
+ 0x1112, 0x116e, 0x11aa, 0,
+#undef V11933
+#define V11933 (V + 46632)
+ 0x1112, 0x116e, 0x11ab, 0,
+#undef V11934
+#define V11934 (V + 46636)
+ 0x1112, 0x116e, 0x11ac, 0,
+#undef V11935
+#define V11935 (V + 46640)
+ 0x1112, 0x116e, 0x11ad, 0,
+#undef V11936
+#define V11936 (V + 46644)
+ 0x1112, 0x116e, 0x11ae, 0,
+#undef V11937
+#define V11937 (V + 46648)
+ 0x1112, 0x116e, 0x11af, 0,
+#undef V11938
+#define V11938 (V + 46652)
+ 0x1112, 0x116e, 0x11b0, 0,
+#undef V11939
+#define V11939 (V + 46656)
+ 0x1112, 0x116e, 0x11b1, 0,
+#undef V11940
+#define V11940 (V + 46660)
+ 0x1112, 0x116e, 0x11b2, 0,
+#undef V11941
+#define V11941 (V + 46664)
+ 0x1112, 0x116e, 0x11b3, 0,
+#undef V11942
+#define V11942 (V + 46668)
+ 0x1112, 0x116e, 0x11b4, 0,
+#undef V11943
+#define V11943 (V + 46672)
+ 0x1112, 0x116e, 0x11b5, 0,
+#undef V11944
+#define V11944 (V + 46676)
+ 0x1112, 0x116e, 0x11b6, 0,
+#undef V11945
+#define V11945 (V + 46680)
+ 0x1112, 0x116e, 0x11b7, 0,
+#undef V11946
+#define V11946 (V + 46684)
+ 0x1112, 0x116e, 0x11b8, 0,
+#undef V11947
+#define V11947 (V + 46688)
+ 0x1112, 0x116e, 0x11b9, 0,
+#undef V11948
+#define V11948 (V + 46692)
+ 0x1112, 0x116e, 0x11ba, 0,
+#undef V11949
+#define V11949 (V + 46696)
+ 0x1112, 0x116e, 0x11bb, 0,
+#undef V11950
+#define V11950 (V + 46700)
+ 0x1112, 0x116e, 0x11bc, 0,
+#undef V11951
+#define V11951 (V + 46704)
+ 0x1112, 0x116e, 0x11bd, 0,
+#undef V11952
+#define V11952 (V + 46708)
+ 0x1112, 0x116e, 0x11be, 0,
+#undef V11953
+#define V11953 (V + 46712)
+ 0x1112, 0x116e, 0x11bf, 0,
+#undef V11954
+#define V11954 (V + 46716)
+ 0x1112, 0x116e, 0x11c0, 0,
+#undef V11955
+#define V11955 (V + 46720)
+ 0x1112, 0x116e, 0x11c1, 0,
+#undef V11956
+#define V11956 (V + 46724)
+ 0x1112, 0x116e, 0x11c2, 0,
+#undef V11957
+#define V11957 (V + 46728)
+ 0x1112, 0x116f, 0,
+#undef V11958
+#define V11958 (V + 46731)
+ 0x1112, 0x116f, 0x11a8, 0,
+#undef V11959
+#define V11959 (V + 46735)
+ 0x1112, 0x116f, 0x11a9, 0,
+#undef V11960
+#define V11960 (V + 46739)
+ 0x1112, 0x116f, 0x11aa, 0,
+#undef V11961
+#define V11961 (V + 46743)
+ 0x1112, 0x116f, 0x11ab, 0,
+#undef V11962
+#define V11962 (V + 46747)
+ 0x1112, 0x116f, 0x11ac, 0,
+#undef V11963
+#define V11963 (V + 46751)
+ 0x1112, 0x116f, 0x11ad, 0,
+#undef V11964
+#define V11964 (V + 46755)
+ 0x1112, 0x116f, 0x11ae, 0,
+#undef V11965
+#define V11965 (V + 46759)
+ 0x1112, 0x116f, 0x11af, 0,
+#undef V11966
+#define V11966 (V + 46763)
+ 0x1112, 0x116f, 0x11b0, 0,
+#undef V11967
+#define V11967 (V + 46767)
+ 0x1112, 0x116f, 0x11b1, 0,
+#undef V11968
+#define V11968 (V + 46771)
+ 0x1112, 0x116f, 0x11b2, 0,
+#undef V11969
+#define V11969 (V + 46775)
+ 0x1112, 0x116f, 0x11b3, 0,
+#undef V11970
+#define V11970 (V + 46779)
+ 0x1112, 0x116f, 0x11b4, 0,
+#undef V11971
+#define V11971 (V + 46783)
+ 0x1112, 0x116f, 0x11b5, 0,
+#undef V11972
+#define V11972 (V + 46787)
+ 0x1112, 0x116f, 0x11b6, 0,
+#undef V11973
+#define V11973 (V + 46791)
+ 0x1112, 0x116f, 0x11b7, 0,
+#undef V11974
+#define V11974 (V + 46795)
+ 0x1112, 0x116f, 0x11b8, 0,
+#undef V11975
+#define V11975 (V + 46799)
+ 0x1112, 0x116f, 0x11b9, 0,
+#undef V11976
+#define V11976 (V + 46803)
+ 0x1112, 0x116f, 0x11ba, 0,
+#undef V11977
+#define V11977 (V + 46807)
+ 0x1112, 0x116f, 0x11bb, 0,
+#undef V11978
+#define V11978 (V + 46811)
+ 0x1112, 0x116f, 0x11bc, 0,
+#undef V11979
+#define V11979 (V + 46815)
+ 0x1112, 0x116f, 0x11bd, 0,
+#undef V11980
+#define V11980 (V + 46819)
+ 0x1112, 0x116f, 0x11be, 0,
+#undef V11981
+#define V11981 (V + 46823)
+ 0x1112, 0x116f, 0x11bf, 0,
+#undef V11982
+#define V11982 (V + 46827)
+ 0x1112, 0x116f, 0x11c0, 0,
+#undef V11983
+#define V11983 (V + 46831)
+ 0x1112, 0x116f, 0x11c1, 0,
+#undef V11984
+#define V11984 (V + 46835)
+ 0x1112, 0x116f, 0x11c2, 0,
+#undef V11985
+#define V11985 (V + 46839)
+ 0x1112, 0x1170, 0,
+#undef V11986
+#define V11986 (V + 46842)
+ 0x1112, 0x1170, 0x11a8, 0,
+#undef V11987
+#define V11987 (V + 46846)
+ 0x1112, 0x1170, 0x11a9, 0,
+#undef V11988
+#define V11988 (V + 46850)
+ 0x1112, 0x1170, 0x11aa, 0,
+#undef V11989
+#define V11989 (V + 46854)
+ 0x1112, 0x1170, 0x11ab, 0,
+#undef V11990
+#define V11990 (V + 46858)
+ 0x1112, 0x1170, 0x11ac, 0,
+#undef V11991
+#define V11991 (V + 46862)
+ 0x1112, 0x1170, 0x11ad, 0,
+#undef V11992
+#define V11992 (V + 46866)
+ 0x1112, 0x1170, 0x11ae, 0,
+#undef V11993
+#define V11993 (V + 46870)
+ 0x1112, 0x1170, 0x11af, 0,
+#undef V11994
+#define V11994 (V + 46874)
+ 0x1112, 0x1170, 0x11b0, 0,
+#undef V11995
+#define V11995 (V + 46878)
+ 0x1112, 0x1170, 0x11b1, 0,
+#undef V11996
+#define V11996 (V + 46882)
+ 0x1112, 0x1170, 0x11b2, 0,
+#undef V11997
+#define V11997 (V + 46886)
+ 0x1112, 0x1170, 0x11b3, 0,
+#undef V11998
+#define V11998 (V + 46890)
+ 0x1112, 0x1170, 0x11b4, 0,
+#undef V11999
+#define V11999 (V + 46894)
+ 0x1112, 0x1170, 0x11b5, 0,
+#undef V12000
+#define V12000 (V + 46898)
+ 0x1112, 0x1170, 0x11b6, 0,
+#undef V12001
+#define V12001 (V + 46902)
+ 0x1112, 0x1170, 0x11b7, 0,
+#undef V12002
+#define V12002 (V + 46906)
+ 0x1112, 0x1170, 0x11b8, 0,
+#undef V12003
+#define V12003 (V + 46910)
+ 0x1112, 0x1170, 0x11b9, 0,
+#undef V12004
+#define V12004 (V + 46914)
+ 0x1112, 0x1170, 0x11ba, 0,
+#undef V12005
+#define V12005 (V + 46918)
+ 0x1112, 0x1170, 0x11bb, 0,
+#undef V12006
+#define V12006 (V + 46922)
+ 0x1112, 0x1170, 0x11bc, 0,
+#undef V12007
+#define V12007 (V + 46926)
+ 0x1112, 0x1170, 0x11bd, 0,
+#undef V12008
+#define V12008 (V + 46930)
+ 0x1112, 0x1170, 0x11be, 0,
+#undef V12009
+#define V12009 (V + 46934)
+ 0x1112, 0x1170, 0x11bf, 0,
+#undef V12010
+#define V12010 (V + 46938)
+ 0x1112, 0x1170, 0x11c0, 0,
+#undef V12011
+#define V12011 (V + 46942)
+ 0x1112, 0x1170, 0x11c1, 0,
+#undef V12012
+#define V12012 (V + 46946)
+ 0x1112, 0x1170, 0x11c2, 0,
+#undef V12013
+#define V12013 (V + 46950)
+ 0x1112, 0x1171, 0,
+#undef V12014
+#define V12014 (V + 46953)
+ 0x1112, 0x1171, 0x11a8, 0,
+#undef V12015
+#define V12015 (V + 46957)
+ 0x1112, 0x1171, 0x11a9, 0,
+#undef V12016
+#define V12016 (V + 46961)
+ 0x1112, 0x1171, 0x11aa, 0,
+#undef V12017
+#define V12017 (V + 46965)
+ 0x1112, 0x1171, 0x11ab, 0,
+#undef V12018
+#define V12018 (V + 46969)
+ 0x1112, 0x1171, 0x11ac, 0,
+#undef V12019
+#define V12019 (V + 46973)
+ 0x1112, 0x1171, 0x11ad, 0,
+#undef V12020
+#define V12020 (V + 46977)
+ 0x1112, 0x1171, 0x11ae, 0,
+#undef V12021
+#define V12021 (V + 46981)
+ 0x1112, 0x1171, 0x11af, 0,
+#undef V12022
+#define V12022 (V + 46985)
+ 0x1112, 0x1171, 0x11b0, 0,
+#undef V12023
+#define V12023 (V + 46989)
+ 0x1112, 0x1171, 0x11b1, 0,
+#undef V12024
+#define V12024 (V + 46993)
+ 0x1112, 0x1171, 0x11b2, 0,
+#undef V12025
+#define V12025 (V + 46997)
+ 0x1112, 0x1171, 0x11b3, 0,
+#undef V12026
+#define V12026 (V + 47001)
+ 0x1112, 0x1171, 0x11b4, 0,
+#undef V12027
+#define V12027 (V + 47005)
+ 0x1112, 0x1171, 0x11b5, 0,
+#undef V12028
+#define V12028 (V + 47009)
+ 0x1112, 0x1171, 0x11b6, 0,
+#undef V12029
+#define V12029 (V + 47013)
+ 0x1112, 0x1171, 0x11b7, 0,
+#undef V12030
+#define V12030 (V + 47017)
+ 0x1112, 0x1171, 0x11b8, 0,
+#undef V12031
+#define V12031 (V + 47021)
+ 0x1112, 0x1171, 0x11b9, 0,
+#undef V12032
+#define V12032 (V + 47025)
+ 0x1112, 0x1171, 0x11ba, 0,
+#undef V12033
+#define V12033 (V + 47029)
+ 0x1112, 0x1171, 0x11bb, 0,
+#undef V12034
+#define V12034 (V + 47033)
+ 0x1112, 0x1171, 0x11bc, 0,
+#undef V12035
+#define V12035 (V + 47037)
+ 0x1112, 0x1171, 0x11bd, 0,
+#undef V12036
+#define V12036 (V + 47041)
+ 0x1112, 0x1171, 0x11be, 0,
+#undef V12037
+#define V12037 (V + 47045)
+ 0x1112, 0x1171, 0x11bf, 0,
+#undef V12038
+#define V12038 (V + 47049)
+ 0x1112, 0x1171, 0x11c0, 0,
+#undef V12039
+#define V12039 (V + 47053)
+ 0x1112, 0x1171, 0x11c1, 0,
+#undef V12040
+#define V12040 (V + 47057)
+ 0x1112, 0x1171, 0x11c2, 0,
+#undef V12041
+#define V12041 (V + 47061)
+ 0x1112, 0x1172, 0,
+#undef V12042
+#define V12042 (V + 47064)
+ 0x1112, 0x1172, 0x11a8, 0,
+#undef V12043
+#define V12043 (V + 47068)
+ 0x1112, 0x1172, 0x11a9, 0,
+#undef V12044
+#define V12044 (V + 47072)
+ 0x1112, 0x1172, 0x11aa, 0,
+#undef V12045
+#define V12045 (V + 47076)
+ 0x1112, 0x1172, 0x11ab, 0,
+#undef V12046
+#define V12046 (V + 47080)
+ 0x1112, 0x1172, 0x11ac, 0,
+#undef V12047
+#define V12047 (V + 47084)
+ 0x1112, 0x1172, 0x11ad, 0,
+#undef V12048
+#define V12048 (V + 47088)
+ 0x1112, 0x1172, 0x11ae, 0,
+#undef V12049
+#define V12049 (V + 47092)
+ 0x1112, 0x1172, 0x11af, 0,
+#undef V12050
+#define V12050 (V + 47096)
+ 0x1112, 0x1172, 0x11b0, 0,
+#undef V12051
+#define V12051 (V + 47100)
+ 0x1112, 0x1172, 0x11b1, 0,
+#undef V12052
+#define V12052 (V + 47104)
+ 0x1112, 0x1172, 0x11b2, 0,
+#undef V12053
+#define V12053 (V + 47108)
+ 0x1112, 0x1172, 0x11b3, 0,
+#undef V12054
+#define V12054 (V + 47112)
+ 0x1112, 0x1172, 0x11b4, 0,
+#undef V12055
+#define V12055 (V + 47116)
+ 0x1112, 0x1172, 0x11b5, 0,
+#undef V12056
+#define V12056 (V + 47120)
+ 0x1112, 0x1172, 0x11b6, 0,
+#undef V12057
+#define V12057 (V + 47124)
+ 0x1112, 0x1172, 0x11b7, 0,
+#undef V12058
+#define V12058 (V + 47128)
+ 0x1112, 0x1172, 0x11b8, 0,
+#undef V12059
+#define V12059 (V + 47132)
+ 0x1112, 0x1172, 0x11b9, 0,
+#undef V12060
+#define V12060 (V + 47136)
+ 0x1112, 0x1172, 0x11ba, 0,
+#undef V12061
+#define V12061 (V + 47140)
+ 0x1112, 0x1172, 0x11bb, 0,
+#undef V12062
+#define V12062 (V + 47144)
+ 0x1112, 0x1172, 0x11bc, 0,
+#undef V12063
+#define V12063 (V + 47148)
+ 0x1112, 0x1172, 0x11bd, 0,
+#undef V12064
+#define V12064 (V + 47152)
+ 0x1112, 0x1172, 0x11be, 0,
+#undef V12065
+#define V12065 (V + 47156)
+ 0x1112, 0x1172, 0x11bf, 0,
+#undef V12066
+#define V12066 (V + 47160)
+ 0x1112, 0x1172, 0x11c0, 0,
+#undef V12067
+#define V12067 (V + 47164)
+ 0x1112, 0x1172, 0x11c1, 0,
+#undef V12068
+#define V12068 (V + 47168)
+ 0x1112, 0x1172, 0x11c2, 0,
+#undef V12069
+#define V12069 (V + 47172)
+ 0x1112, 0x1173, 0,
+#undef V12070
+#define V12070 (V + 47175)
+ 0x1112, 0x1173, 0x11a8, 0,
+#undef V12071
+#define V12071 (V + 47179)
+ 0x1112, 0x1173, 0x11a9, 0,
+#undef V12072
+#define V12072 (V + 47183)
+ 0x1112, 0x1173, 0x11aa, 0,
+#undef V12073
+#define V12073 (V + 47187)
+ 0x1112, 0x1173, 0x11ab, 0,
+#undef V12074
+#define V12074 (V + 47191)
+ 0x1112, 0x1173, 0x11ac, 0,
+#undef V12075
+#define V12075 (V + 47195)
+ 0x1112, 0x1173, 0x11ad, 0,
+#undef V12076
+#define V12076 (V + 47199)
+ 0x1112, 0x1173, 0x11ae, 0,
+#undef V12077
+#define V12077 (V + 47203)
+ 0x1112, 0x1173, 0x11af, 0,
+#undef V12078
+#define V12078 (V + 47207)
+ 0x1112, 0x1173, 0x11b0, 0,
+#undef V12079
+#define V12079 (V + 47211)
+ 0x1112, 0x1173, 0x11b1, 0,
+#undef V12080
+#define V12080 (V + 47215)
+ 0x1112, 0x1173, 0x11b2, 0,
+#undef V12081
+#define V12081 (V + 47219)
+ 0x1112, 0x1173, 0x11b3, 0,
+#undef V12082
+#define V12082 (V + 47223)
+ 0x1112, 0x1173, 0x11b4, 0,
+#undef V12083
+#define V12083 (V + 47227)
+ 0x1112, 0x1173, 0x11b5, 0,
+#undef V12084
+#define V12084 (V + 47231)
+ 0x1112, 0x1173, 0x11b6, 0,
+#undef V12085
+#define V12085 (V + 47235)
+ 0x1112, 0x1173, 0x11b7, 0,
+#undef V12086
+#define V12086 (V + 47239)
+ 0x1112, 0x1173, 0x11b8, 0,
+#undef V12087
+#define V12087 (V + 47243)
+ 0x1112, 0x1173, 0x11b9, 0,
+#undef V12088
+#define V12088 (V + 47247)
+ 0x1112, 0x1173, 0x11ba, 0,
+#undef V12089
+#define V12089 (V + 47251)
+ 0x1112, 0x1173, 0x11bb, 0,
+#undef V12090
+#define V12090 (V + 47255)
+ 0x1112, 0x1173, 0x11bc, 0,
+#undef V12091
+#define V12091 (V + 47259)
+ 0x1112, 0x1173, 0x11bd, 0,
+#undef V12092
+#define V12092 (V + 47263)
+ 0x1112, 0x1173, 0x11be, 0,
+#undef V12093
+#define V12093 (V + 47267)
+ 0x1112, 0x1173, 0x11bf, 0,
+#undef V12094
+#define V12094 (V + 47271)
+ 0x1112, 0x1173, 0x11c0, 0,
+#undef V12095
+#define V12095 (V + 47275)
+ 0x1112, 0x1173, 0x11c1, 0,
+#undef V12096
+#define V12096 (V + 47279)
+ 0x1112, 0x1173, 0x11c2, 0,
+#undef V12097
+#define V12097 (V + 47283)
+ 0x1112, 0x1174, 0,
+#undef V12098
+#define V12098 (V + 47286)
+ 0x1112, 0x1174, 0x11a8, 0,
+#undef V12099
+#define V12099 (V + 47290)
+ 0x1112, 0x1174, 0x11a9, 0,
+#undef V12100
+#define V12100 (V + 47294)
+ 0x1112, 0x1174, 0x11aa, 0,
+#undef V12101
+#define V12101 (V + 47298)
+ 0x1112, 0x1174, 0x11ab, 0,
+#undef V12102
+#define V12102 (V + 47302)
+ 0x1112, 0x1174, 0x11ac, 0,
+#undef V12103
+#define V12103 (V + 47306)
+ 0x1112, 0x1174, 0x11ad, 0,
+#undef V12104
+#define V12104 (V + 47310)
+ 0x1112, 0x1174, 0x11ae, 0,
+#undef V12105
+#define V12105 (V + 47314)
+ 0x1112, 0x1174, 0x11af, 0,
+#undef V12106
+#define V12106 (V + 47318)
+ 0x1112, 0x1174, 0x11b0, 0,
+#undef V12107
+#define V12107 (V + 47322)
+ 0x1112, 0x1174, 0x11b1, 0,
+#undef V12108
+#define V12108 (V + 47326)
+ 0x1112, 0x1174, 0x11b2, 0,
+#undef V12109
+#define V12109 (V + 47330)
+ 0x1112, 0x1174, 0x11b3, 0,
+#undef V12110
+#define V12110 (V + 47334)
+ 0x1112, 0x1174, 0x11b4, 0,
+#undef V12111
+#define V12111 (V + 47338)
+ 0x1112, 0x1174, 0x11b5, 0,
+#undef V12112
+#define V12112 (V + 47342)
+ 0x1112, 0x1174, 0x11b6, 0,
+#undef V12113
+#define V12113 (V + 47346)
+ 0x1112, 0x1174, 0x11b7, 0,
+#undef V12114
+#define V12114 (V + 47350)
+ 0x1112, 0x1174, 0x11b8, 0,
+#undef V12115
+#define V12115 (V + 47354)
+ 0x1112, 0x1174, 0x11b9, 0,
+#undef V12116
+#define V12116 (V + 47358)
+ 0x1112, 0x1174, 0x11ba, 0,
+#undef V12117
+#define V12117 (V + 47362)
+ 0x1112, 0x1174, 0x11bb, 0,
+#undef V12118
+#define V12118 (V + 47366)
+ 0x1112, 0x1174, 0x11bc, 0,
+#undef V12119
+#define V12119 (V + 47370)
+ 0x1112, 0x1174, 0x11bd, 0,
+#undef V12120
+#define V12120 (V + 47374)
+ 0x1112, 0x1174, 0x11be, 0,
+#undef V12121
+#define V12121 (V + 47378)
+ 0x1112, 0x1174, 0x11bf, 0,
+#undef V12122
+#define V12122 (V + 47382)
+ 0x1112, 0x1174, 0x11c0, 0,
+#undef V12123
+#define V12123 (V + 47386)
+ 0x1112, 0x1174, 0x11c1, 0,
+#undef V12124
+#define V12124 (V + 47390)
+ 0x1112, 0x1174, 0x11c2, 0,
+#undef V12125
+#define V12125 (V + 47394)
+ 0x1112, 0x1175, 0,
+#undef V12126
+#define V12126 (V + 47397)
+ 0x1112, 0x1175, 0x11a8, 0,
+#undef V12127
+#define V12127 (V + 47401)
+ 0x1112, 0x1175, 0x11a9, 0,
+#undef V12128
+#define V12128 (V + 47405)
+ 0x1112, 0x1175, 0x11aa, 0,
+#undef V12129
+#define V12129 (V + 47409)
+ 0x1112, 0x1175, 0x11ab, 0,
+#undef V12130
+#define V12130 (V + 47413)
+ 0x1112, 0x1175, 0x11ac, 0,
+#undef V12131
+#define V12131 (V + 47417)
+ 0x1112, 0x1175, 0x11ad, 0,
+#undef V12132
+#define V12132 (V + 47421)
+ 0x1112, 0x1175, 0x11ae, 0,
+#undef V12133
+#define V12133 (V + 47425)
+ 0x1112, 0x1175, 0x11af, 0,
+#undef V12134
+#define V12134 (V + 47429)
+ 0x1112, 0x1175, 0x11b0, 0,
+#undef V12135
+#define V12135 (V + 47433)
+ 0x1112, 0x1175, 0x11b1, 0,
+#undef V12136
+#define V12136 (V + 47437)
+ 0x1112, 0x1175, 0x11b2, 0,
+#undef V12137
+#define V12137 (V + 47441)
+ 0x1112, 0x1175, 0x11b3, 0,
+#undef V12138
+#define V12138 (V + 47445)
+ 0x1112, 0x1175, 0x11b4, 0,
+#undef V12139
+#define V12139 (V + 47449)
+ 0x1112, 0x1175, 0x11b5, 0,
+#undef V12140
+#define V12140 (V + 47453)
+ 0x1112, 0x1175, 0x11b6, 0,
+#undef V12141
+#define V12141 (V + 47457)
+ 0x1112, 0x1175, 0x11b7, 0,
+#undef V12142
+#define V12142 (V + 47461)
+ 0x1112, 0x1175, 0x11b8, 0,
+#undef V12143
+#define V12143 (V + 47465)
+ 0x1112, 0x1175, 0x11b9, 0,
+#undef V12144
+#define V12144 (V + 47469)
+ 0x1112, 0x1175, 0x11ba, 0,
+#undef V12145
+#define V12145 (V + 47473)
+ 0x1112, 0x1175, 0x11bb, 0,
+#undef V12146
+#define V12146 (V + 47477)
+ 0x1112, 0x1175, 0x11bc, 0,
+#undef V12147
+#define V12147 (V + 47481)
+ 0x1112, 0x1175, 0x11bd, 0,
+#undef V12148
+#define V12148 (V + 47485)
+ 0x1112, 0x1175, 0x11be, 0,
+#undef V12149
+#define V12149 (V + 47489)
+ 0x1112, 0x1175, 0x11bf, 0,
+#undef V12150
+#define V12150 (V + 47493)
+ 0x1112, 0x1175, 0x11c0, 0,
+#undef V12151
+#define V12151 (V + 47497)
+ 0x1112, 0x1175, 0x11c1, 0,
+#undef V12152
+#define V12152 (V + 47501)
+ 0x1112, 0x1175, 0x11c2, 0,
+#undef V12153
+#define V12153 (V + 47505)
+ 0x8c48, 0,
+#undef V12154
+#define V12154 (V + 47507)
+ 0x66f4, 0,
+#undef V12155
+#define V12155 (V + 47509)
+ 0x8eca, 0,
+#undef V12156
+#define V12156 (V + 47511)
+ 0x8cc8, 0,
+#undef V12157
+#define V12157 (V + 47513)
+ 0x6ed1, 0,
+#undef V12158
+#define V12158 (V + 47515)
+ 0x4e32, 0,
+#undef V12159
+#define V12159 (V + 47517)
+ 0x53e5, 0,
+#undef V12160
+#define V12160 (V + 47519)
+ 0x9f9c, 0,
+#undef V12161
+#define V12161 (V + 47521)
+ 0x5951, 0,
+#undef V12162
+#define V12162 (V + 47523)
+ 0x91d1, 0,
+#undef V12163
+#define V12163 (V + 47525)
+ 0x5587, 0,
+#undef V12164
+#define V12164 (V + 47527)
+ 0x5948, 0,
+#undef V12165
+#define V12165 (V + 47529)
+ 0x61f6, 0,
+#undef V12166
+#define V12166 (V + 47531)
+ 0x7669, 0,
+#undef V12167
+#define V12167 (V + 47533)
+ 0x7f85, 0,
+#undef V12168
+#define V12168 (V + 47535)
+ 0x863f, 0,
+#undef V12169
+#define V12169 (V + 47537)
+ 0x87ba, 0,
+#undef V12170
+#define V12170 (V + 47539)
+ 0x88f8, 0,
+#undef V12171
+#define V12171 (V + 47541)
+ 0x908f, 0,
+#undef V12172
+#define V12172 (V + 47543)
+ 0x6a02, 0,
+#undef V12173
+#define V12173 (V + 47545)
+ 0x6d1b, 0,
+#undef V12174
+#define V12174 (V + 47547)
+ 0x70d9, 0,
+#undef V12175
+#define V12175 (V + 47549)
+ 0x73de, 0,
+#undef V12176
+#define V12176 (V + 47551)
+ 0x843d, 0,
+#undef V12177
+#define V12177 (V + 47553)
+ 0x916a, 0,
+#undef V12178
+#define V12178 (V + 47555)
+ 0x99f1, 0,
+#undef V12179
+#define V12179 (V + 47557)
+ 0x4e82, 0,
+#undef V12180
+#define V12180 (V + 47559)
+ 0x5375, 0,
+#undef V12181
+#define V12181 (V + 47561)
+ 0x6b04, 0,
+#undef V12182
+#define V12182 (V + 47563)
+ 0x721b, 0,
+#undef V12183
+#define V12183 (V + 47565)
+ 0x862d, 0,
+#undef V12184
+#define V12184 (V + 47567)
+ 0x9e1e, 0,
+#undef V12185
+#define V12185 (V + 47569)
+ 0x5d50, 0,
+#undef V12186
+#define V12186 (V + 47571)
+ 0x6feb, 0,
+#undef V12187
+#define V12187 (V + 47573)
+ 0x85cd, 0,
+#undef V12188
+#define V12188 (V + 47575)
+ 0x8964, 0,
+#undef V12189
+#define V12189 (V + 47577)
+ 0x62c9, 0,
+#undef V12190
+#define V12190 (V + 47579)
+ 0x81d8, 0,
+#undef V12191
+#define V12191 (V + 47581)
+ 0x881f, 0,
+#undef V12192
+#define V12192 (V + 47583)
+ 0x5eca, 0,
+#undef V12193
+#define V12193 (V + 47585)
+ 0x6717, 0,
+#undef V12194
+#define V12194 (V + 47587)
+ 0x6d6a, 0,
+#undef V12195
+#define V12195 (V + 47589)
+ 0x72fc, 0,
+#undef V12196
+#define V12196 (V + 47591)
+ 0x90ce, 0,
+#undef V12197
+#define V12197 (V + 47593)
+ 0x4f86, 0,
+#undef V12198
+#define V12198 (V + 47595)
+ 0x51b7, 0,
+#undef V12199
+#define V12199 (V + 47597)
+ 0x52de, 0,
+#undef V12200
+#define V12200 (V + 47599)
+ 0x64c4, 0,
+#undef V12201
+#define V12201 (V + 47601)
+ 0x6ad3, 0,
+#undef V12202
+#define V12202 (V + 47603)
+ 0x7210, 0,
+#undef V12203
+#define V12203 (V + 47605)
+ 0x76e7, 0,
+#undef V12204
+#define V12204 (V + 47607)
+ 0x8001, 0,
+#undef V12205
+#define V12205 (V + 47609)
+ 0x8606, 0,
+#undef V12206
+#define V12206 (V + 47611)
+ 0x865c, 0,
+#undef V12207
+#define V12207 (V + 47613)
+ 0x8def, 0,
+#undef V12208
+#define V12208 (V + 47615)
+ 0x9732, 0,
+#undef V12209
+#define V12209 (V + 47617)
+ 0x9b6f, 0,
+#undef V12210
+#define V12210 (V + 47619)
+ 0x9dfa, 0,
+#undef V12211
+#define V12211 (V + 47621)
+ 0x788c, 0,
+#undef V12212
+#define V12212 (V + 47623)
+ 0x797f, 0,
+#undef V12213
+#define V12213 (V + 47625)
+ 0x7da0, 0,
+#undef V12214
+#define V12214 (V + 47627)
+ 0x83c9, 0,
+#undef V12215
+#define V12215 (V + 47629)
+ 0x9304, 0,
+#undef V12216
+#define V12216 (V + 47631)
+ 0x9e7f, 0,
+#undef V12217
+#define V12217 (V + 47633)
+ 0x8ad6, 0,
+#undef V12218
+#define V12218 (V + 47635)
+ 0x58df, 0,
+#undef V12219
+#define V12219 (V + 47637)
+ 0x5f04, 0,
+#undef V12220
+#define V12220 (V + 47639)
+ 0x7c60, 0,
+#undef V12221
+#define V12221 (V + 47641)
+ 0x807e, 0,
+#undef V12222
+#define V12222 (V + 47643)
+ 0x7262, 0,
+#undef V12223
+#define V12223 (V + 47645)
+ 0x78ca, 0,
+#undef V12224
+#define V12224 (V + 47647)
+ 0x8cc2, 0,
+#undef V12225
+#define V12225 (V + 47649)
+ 0x96f7, 0,
+#undef V12226
+#define V12226 (V + 47651)
+ 0x58d8, 0,
+#undef V12227
+#define V12227 (V + 47653)
+ 0x5c62, 0,
+#undef V12228
+#define V12228 (V + 47655)
+ 0x6a13, 0,
+#undef V12229
+#define V12229 (V + 47657)
+ 0x6dda, 0,
+#undef V12230
+#define V12230 (V + 47659)
+ 0x6f0f, 0,
+#undef V12231
+#define V12231 (V + 47661)
+ 0x7d2f, 0,
+#undef V12232
+#define V12232 (V + 47663)
+ 0x7e37, 0,
+#undef V12233
+#define V12233 (V + 47665)
+ 0x964b, 0,
+#undef V12234
+#define V12234 (V + 47667)
+ 0x52d2, 0,
+#undef V12235
+#define V12235 (V + 47669)
+ 0x808b, 0,
+#undef V12236
+#define V12236 (V + 47671)
+ 0x51dc, 0,
+#undef V12237
+#define V12237 (V + 47673)
+ 0x51cc, 0,
+#undef V12238
+#define V12238 (V + 47675)
+ 0x7a1c, 0,
+#undef V12239
+#define V12239 (V + 47677)
+ 0x7dbe, 0,
+#undef V12240
+#define V12240 (V + 47679)
+ 0x83f1, 0,
+#undef V12241
+#define V12241 (V + 47681)
+ 0x9675, 0,
+#undef V12242
+#define V12242 (V + 47683)
+ 0x8b80, 0,
+#undef V12243
+#define V12243 (V + 47685)
+ 0x62cf, 0,
+#undef V12244
+#define V12244 (V + 47687)
+ 0x8afe, 0,
+#undef V12245
+#define V12245 (V + 47689)
+ 0x4e39, 0,
+#undef V12246
+#define V12246 (V + 47691)
+ 0x5be7, 0,
+#undef V12247
+#define V12247 (V + 47693)
+ 0x6012, 0,
+#undef V12248
+#define V12248 (V + 47695)
+ 0x7387, 0,
+#undef V12249
+#define V12249 (V + 47697)
+ 0x7570, 0,
+#undef V12250
+#define V12250 (V + 47699)
+ 0x5317, 0,
+#undef V12251
+#define V12251 (V + 47701)
+ 0x78fb, 0,
+#undef V12252
+#define V12252 (V + 47703)
+ 0x4fbf, 0,
+#undef V12253
+#define V12253 (V + 47705)
+ 0x5fa9, 0,
+#undef V12254
+#define V12254 (V + 47707)
+ 0x4e0d, 0,
+#undef V12255
+#define V12255 (V + 47709)
+ 0x6ccc, 0,
+#undef V12256
+#define V12256 (V + 47711)
+ 0x6578, 0,
+#undef V12257
+#define V12257 (V + 47713)
+ 0x7d22, 0,
+#undef V12258
+#define V12258 (V + 47715)
+ 0x53c3, 0,
+#undef V12259
+#define V12259 (V + 47717)
+ 0x585e, 0,
+#undef V12260
+#define V12260 (V + 47719)
+ 0x7701, 0,
+#undef V12261
+#define V12261 (V + 47721)
+ 0x8449, 0,
+#undef V12262
+#define V12262 (V + 47723)
+ 0x8aaa, 0,
+#undef V12263
+#define V12263 (V + 47725)
+ 0x6bba, 0,
+#undef V12264
+#define V12264 (V + 47727)
+ 0x8fb0, 0,
+#undef V12265
+#define V12265 (V + 47729)
+ 0x6c88, 0,
+#undef V12266
+#define V12266 (V + 47731)
+ 0x62fe, 0,
+#undef V12267
+#define V12267 (V + 47733)
+ 0x82e5, 0,
+#undef V12268
+#define V12268 (V + 47735)
+ 0x63a0, 0,
+#undef V12269
+#define V12269 (V + 47737)
+ 0x7565, 0,
+#undef V12270
+#define V12270 (V + 47739)
+ 0x4eae, 0,
+#undef V12271
+#define V12271 (V + 47741)
+ 0x5169, 0,
+#undef V12272
+#define V12272 (V + 47743)
+ 0x51c9, 0,
+#undef V12273
+#define V12273 (V + 47745)
+ 0x6881, 0,
+#undef V12274
+#define V12274 (V + 47747)
+ 0x7ce7, 0,
+#undef V12275
+#define V12275 (V + 47749)
+ 0x826f, 0,
+#undef V12276
+#define V12276 (V + 47751)
+ 0x8ad2, 0,
+#undef V12277
+#define V12277 (V + 47753)
+ 0x91cf, 0,
+#undef V12278
+#define V12278 (V + 47755)
+ 0x52f5, 0,
+#undef V12279
+#define V12279 (V + 47757)
+ 0x5442, 0,
+#undef V12280
+#define V12280 (V + 47759)
+ 0x5973, 0,
+#undef V12281
+#define V12281 (V + 47761)
+ 0x5eec, 0,
+#undef V12282
+#define V12282 (V + 47763)
+ 0x65c5, 0,
+#undef V12283
+#define V12283 (V + 47765)
+ 0x6ffe, 0,
+#undef V12284
+#define V12284 (V + 47767)
+ 0x792a, 0,
+#undef V12285
+#define V12285 (V + 47769)
+ 0x95ad, 0,
+#undef V12286
+#define V12286 (V + 47771)
+ 0x9a6a, 0,
+#undef V12287
+#define V12287 (V + 47773)
+ 0x9e97, 0,
+#undef V12288
+#define V12288 (V + 47775)
+ 0x9ece, 0,
+#undef V12289
+#define V12289 (V + 47777)
+ 0x529b, 0,
+#undef V12290
+#define V12290 (V + 47779)
+ 0x66c6, 0,
+#undef V12291
+#define V12291 (V + 47781)
+ 0x6b77, 0,
+#undef V12292
+#define V12292 (V + 47783)
+ 0x8f62, 0,
+#undef V12293
+#define V12293 (V + 47785)
+ 0x5e74, 0,
+#undef V12294
+#define V12294 (V + 47787)
+ 0x6190, 0,
+#undef V12295
+#define V12295 (V + 47789)
+ 0x6200, 0,
+#undef V12296
+#define V12296 (V + 47791)
+ 0x649a, 0,
+#undef V12297
+#define V12297 (V + 47793)
+ 0x6f23, 0,
+#undef V12298
+#define V12298 (V + 47795)
+ 0x7149, 0,
+#undef V12299
+#define V12299 (V + 47797)
+ 0x7489, 0,
+#undef V12300
+#define V12300 (V + 47799)
+ 0x79ca, 0,
+#undef V12301
+#define V12301 (V + 47801)
+ 0x7df4, 0,
+#undef V12302
+#define V12302 (V + 47803)
+ 0x806f, 0,
+#undef V12303
+#define V12303 (V + 47805)
+ 0x8f26, 0,
+#undef V12304
+#define V12304 (V + 47807)
+ 0x84ee, 0,
+#undef V12305
+#define V12305 (V + 47809)
+ 0x9023, 0,
+#undef V12306
+#define V12306 (V + 47811)
+ 0x934a, 0,
+#undef V12307
+#define V12307 (V + 47813)
+ 0x5217, 0,
+#undef V12308
+#define V12308 (V + 47815)
+ 0x52a3, 0,
+#undef V12309
+#define V12309 (V + 47817)
+ 0x54bd, 0,
+#undef V12310
+#define V12310 (V + 47819)
+ 0x70c8, 0,
+#undef V12311
+#define V12311 (V + 47821)
+ 0x88c2, 0,
+#undef V12312
+#define V12312 (V + 47823)
+ 0x5ec9, 0,
+#undef V12313
+#define V12313 (V + 47825)
+ 0x5ff5, 0,
+#undef V12314
+#define V12314 (V + 47827)
+ 0x637b, 0,
+#undef V12315
+#define V12315 (V + 47829)
+ 0x6bae, 0,
+#undef V12316
+#define V12316 (V + 47831)
+ 0x7c3e, 0,
+#undef V12317
+#define V12317 (V + 47833)
+ 0x7375, 0,
+#undef V12318
+#define V12318 (V + 47835)
+ 0x4ee4, 0,
+#undef V12319
+#define V12319 (V + 47837)
+ 0x56f9, 0,
+#undef V12320
+#define V12320 (V + 47839)
+ 0x5dba, 0,
+#undef V12321
+#define V12321 (V + 47841)
+ 0x601c, 0,
+#undef V12322
+#define V12322 (V + 47843)
+ 0x73b2, 0,
+#undef V12323
+#define V12323 (V + 47845)
+ 0x7469, 0,
+#undef V12324
+#define V12324 (V + 47847)
+ 0x7f9a, 0,
+#undef V12325
+#define V12325 (V + 47849)
+ 0x8046, 0,
+#undef V12326
+#define V12326 (V + 47851)
+ 0x9234, 0,
+#undef V12327
+#define V12327 (V + 47853)
+ 0x96f6, 0,
+#undef V12328
+#define V12328 (V + 47855)
+ 0x9748, 0,
+#undef V12329
+#define V12329 (V + 47857)
+ 0x9818, 0,
+#undef V12330
+#define V12330 (V + 47859)
+ 0x4f8b, 0,
+#undef V12331
+#define V12331 (V + 47861)
+ 0x79ae, 0,
+#undef V12332
+#define V12332 (V + 47863)
+ 0x91b4, 0,
+#undef V12333
+#define V12333 (V + 47865)
+ 0x96b8, 0,
+#undef V12334
+#define V12334 (V + 47867)
+ 0x60e1, 0,
+#undef V12335
+#define V12335 (V + 47869)
+ 0x4e86, 0,
+#undef V12336
+#define V12336 (V + 47871)
+ 0x50da, 0,
+#undef V12337
+#define V12337 (V + 47873)
+ 0x5bee, 0,
+#undef V12338
+#define V12338 (V + 47875)
+ 0x5c3f, 0,
+#undef V12339
+#define V12339 (V + 47877)
+ 0x6599, 0,
+#undef V12340
+#define V12340 (V + 47879)
+ 0x71ce, 0,
+#undef V12341
+#define V12341 (V + 47881)
+ 0x7642, 0,
+#undef V12342
+#define V12342 (V + 47883)
+ 0x84fc, 0,
+#undef V12343
+#define V12343 (V + 47885)
+ 0x907c, 0,
+#undef V12344
+#define V12344 (V + 47887)
+ 0x9f8d, 0,
+#undef V12345
+#define V12345 (V + 47889)
+ 0x6688, 0,
+#undef V12346
+#define V12346 (V + 47891)
+ 0x962e, 0,
+#undef V12347
+#define V12347 (V + 47893)
+ 0x5289, 0,
+#undef V12348
+#define V12348 (V + 47895)
+ 0x677b, 0,
+#undef V12349
+#define V12349 (V + 47897)
+ 0x67f3, 0,
+#undef V12350
+#define V12350 (V + 47899)
+ 0x6d41, 0,
+#undef V12351
+#define V12351 (V + 47901)
+ 0x6e9c, 0,
+#undef V12352
+#define V12352 (V + 47903)
+ 0x7409, 0,
+#undef V12353
+#define V12353 (V + 47905)
+ 0x7559, 0,
+#undef V12354
+#define V12354 (V + 47907)
+ 0x786b, 0,
+#undef V12355
+#define V12355 (V + 47909)
+ 0x7d10, 0,
+#undef V12356
+#define V12356 (V + 47911)
+ 0x985e, 0,
+#undef V12357
+#define V12357 (V + 47913)
+ 0x516d, 0,
+#undef V12358
+#define V12358 (V + 47915)
+ 0x622e, 0,
+#undef V12359
+#define V12359 (V + 47917)
+ 0x9678, 0,
+#undef V12360
+#define V12360 (V + 47919)
+ 0x502b, 0,
+#undef V12361
+#define V12361 (V + 47921)
+ 0x5d19, 0,
+#undef V12362
+#define V12362 (V + 47923)
+ 0x6dea, 0,
+#undef V12363
+#define V12363 (V + 47925)
+ 0x8f2a, 0,
+#undef V12364
+#define V12364 (V + 47927)
+ 0x5f8b, 0,
+#undef V12365
+#define V12365 (V + 47929)
+ 0x6144, 0,
+#undef V12366
+#define V12366 (V + 47931)
+ 0x6817, 0,
+#undef V12367
+#define V12367 (V + 47933)
+ 0x9686, 0,
+#undef V12368
+#define V12368 (V + 47935)
+ 0x5229, 0,
+#undef V12369
+#define V12369 (V + 47937)
+ 0x540f, 0,
+#undef V12370
+#define V12370 (V + 47939)
+ 0x5c65, 0,
+#undef V12371
+#define V12371 (V + 47941)
+ 0x6613, 0,
+#undef V12372
+#define V12372 (V + 47943)
+ 0x674e, 0,
+#undef V12373
+#define V12373 (V + 47945)
+ 0x68a8, 0,
+#undef V12374
+#define V12374 (V + 47947)
+ 0x6ce5, 0,
+#undef V12375
+#define V12375 (V + 47949)
+ 0x7406, 0,
+#undef V12376
+#define V12376 (V + 47951)
+ 0x75e2, 0,
+#undef V12377
+#define V12377 (V + 47953)
+ 0x7f79, 0,
+#undef V12378
+#define V12378 (V + 47955)
+ 0x88cf, 0,
+#undef V12379
+#define V12379 (V + 47957)
+ 0x88e1, 0,
+#undef V12380
+#define V12380 (V + 47959)
+ 0x91cc, 0,
+#undef V12381
+#define V12381 (V + 47961)
+ 0x96e2, 0,
+#undef V12382
+#define V12382 (V + 47963)
+ 0x533f, 0,
+#undef V12383
+#define V12383 (V + 47965)
+ 0x6eba, 0,
+#undef V12384
+#define V12384 (V + 47967)
+ 0x541d, 0,
+#undef V12385
+#define V12385 (V + 47969)
+ 0x71d0, 0,
+#undef V12386
+#define V12386 (V + 47971)
+ 0x7498, 0,
+#undef V12387
+#define V12387 (V + 47973)
+ 0x85fa, 0,
+#undef V12388
+#define V12388 (V + 47975)
+ 0x96a3, 0,
+#undef V12389
+#define V12389 (V + 47977)
+ 0x9c57, 0,
+#undef V12390
+#define V12390 (V + 47979)
+ 0x9e9f, 0,
+#undef V12391
+#define V12391 (V + 47981)
+ 0x6797, 0,
+#undef V12392
+#define V12392 (V + 47983)
+ 0x6dcb, 0,
+#undef V12393
+#define V12393 (V + 47985)
+ 0x81e8, 0,
+#undef V12394
+#define V12394 (V + 47987)
+ 0x7acb, 0,
+#undef V12395
+#define V12395 (V + 47989)
+ 0x7b20, 0,
+#undef V12396
+#define V12396 (V + 47991)
+ 0x7c92, 0,
+#undef V12397
+#define V12397 (V + 47993)
+ 0x72c0, 0,
+#undef V12398
+#define V12398 (V + 47995)
+ 0x7099, 0,
+#undef V12399
+#define V12399 (V + 47997)
+ 0x8b58, 0,
+#undef V12400
+#define V12400 (V + 47999)
+ 0x4ec0, 0,
+#undef V12401
+#define V12401 (V + 48001)
+ 0x8336, 0,
+#undef V12402
+#define V12402 (V + 48003)
+ 0x523a, 0,
+#undef V12403
+#define V12403 (V + 48005)
+ 0x5207, 0,
+#undef V12404
+#define V12404 (V + 48007)
+ 0x5ea6, 0,
+#undef V12405
+#define V12405 (V + 48009)
+ 0x62d3, 0,
+#undef V12406
+#define V12406 (V + 48011)
+ 0x7cd6, 0,
+#undef V12407
+#define V12407 (V + 48013)
+ 0x5b85, 0,
+#undef V12408
+#define V12408 (V + 48015)
+ 0x6d1e, 0,
+#undef V12409
+#define V12409 (V + 48017)
+ 0x66b4, 0,
+#undef V12410
+#define V12410 (V + 48019)
+ 0x8f3b, 0,
+#undef V12411
+#define V12411 (V + 48021)
+ 0x884c, 0,
+#undef V12412
+#define V12412 (V + 48023)
+ 0x964d, 0,
+#undef V12413
+#define V12413 (V + 48025)
+ 0x898b, 0,
+#undef V12414
+#define V12414 (V + 48027)
+ 0x5ed3, 0,
+#undef V12415
+#define V12415 (V + 48029)
+ 0x5140, 0,
+#undef V12416
+#define V12416 (V + 48031)
+ 0x55c0, 0,
+#undef V12417
+#define V12417 (V + 48033)
+ 0x585a, 0,
+#undef V12418
+#define V12418 (V + 48035)
+ 0x6674, 0,
+#undef V12419
+#define V12419 (V + 48037)
+ 0x51de, 0,
+#undef V12420
+#define V12420 (V + 48039)
+ 0x732a, 0,
+#undef V12421
+#define V12421 (V + 48041)
+ 0x76ca, 0,
+#undef V12422
+#define V12422 (V + 48043)
+ 0x793c, 0,
+#undef V12423
+#define V12423 (V + 48045)
+ 0x795e, 0,
+#undef V12424
+#define V12424 (V + 48047)
+ 0x7965, 0,
+#undef V12425
+#define V12425 (V + 48049)
+ 0x798f, 0,
+#undef V12426
+#define V12426 (V + 48051)
+ 0x9756, 0,
+#undef V12427
+#define V12427 (V + 48053)
+ 0x7cbe, 0,
+#undef V12428
+#define V12428 (V + 48055)
+ 0x7fbd, 0,
+#undef V12429
+#define V12429 (V + 48057)
+ 0x8612, 0,
+#undef V12430
+#define V12430 (V + 48059)
+ 0x8af8, 0,
+#undef V12431
+#define V12431 (V + 48061)
+ 0x9038, 0,
+#undef V12432
+#define V12432 (V + 48063)
+ 0x90fd, 0,
+#undef V12433
+#define V12433 (V + 48065)
+ 0x98ef, 0,
+#undef V12434
+#define V12434 (V + 48067)
+ 0x98fc, 0,
+#undef V12435
+#define V12435 (V + 48069)
+ 0x9928, 0,
+#undef V12436
+#define V12436 (V + 48071)
+ 0x9db4, 0,
+#undef V12437
+#define V12437 (V + 48073)
+ 0x90de, 0,
+#undef V12438
+#define V12438 (V + 48075)
+ 0x96b7, 0,
+#undef V12439
+#define V12439 (V + 48077)
+ 0x4fae, 0,
+#undef V12440
+#define V12440 (V + 48079)
+ 0x50e7, 0,
+#undef V12441
+#define V12441 (V + 48081)
+ 0x514d, 0,
+#undef V12442
+#define V12442 (V + 48083)
+ 0x52c9, 0,
+#undef V12443
+#define V12443 (V + 48085)
+ 0x52e4, 0,
+#undef V12444
+#define V12444 (V + 48087)
+ 0x5351, 0,
+#undef V12445
+#define V12445 (V + 48089)
+ 0x559d, 0,
+#undef V12446
+#define V12446 (V + 48091)
+ 0x5606, 0,
+#undef V12447
+#define V12447 (V + 48093)
+ 0x5668, 0,
+#undef V12448
+#define V12448 (V + 48095)
+ 0x5840, 0,
+#undef V12449
+#define V12449 (V + 48097)
+ 0x58a8, 0,
+#undef V12450
+#define V12450 (V + 48099)
+ 0x5c64, 0,
+#undef V12451
+#define V12451 (V + 48101)
+ 0x5c6e, 0,
+#undef V12452
+#define V12452 (V + 48103)
+ 0x6094, 0,
+#undef V12453
+#define V12453 (V + 48105)
+ 0x6168, 0,
+#undef V12454
+#define V12454 (V + 48107)
+ 0x618e, 0,
+#undef V12455
+#define V12455 (V + 48109)
+ 0x61f2, 0,
+#undef V12456
+#define V12456 (V + 48111)
+ 0x654f, 0,
+#undef V12457
+#define V12457 (V + 48113)
+ 0x65e2, 0,
+#undef V12458
+#define V12458 (V + 48115)
+ 0x6691, 0,
+#undef V12459
+#define V12459 (V + 48117)
+ 0x6885, 0,
+#undef V12460
+#define V12460 (V + 48119)
+ 0x6d77, 0,
+#undef V12461
+#define V12461 (V + 48121)
+ 0x6e1a, 0,
+#undef V12462
+#define V12462 (V + 48123)
+ 0x6f22, 0,
+#undef V12463
+#define V12463 (V + 48125)
+ 0x716e, 0,
+#undef V12464
+#define V12464 (V + 48127)
+ 0x722b, 0,
+#undef V12465
+#define V12465 (V + 48129)
+ 0x7422, 0,
+#undef V12466
+#define V12466 (V + 48131)
+ 0x7891, 0,
+#undef V12467
+#define V12467 (V + 48133)
+ 0x793e, 0,
+#undef V12468
+#define V12468 (V + 48135)
+ 0x7949, 0,
+#undef V12469
+#define V12469 (V + 48137)
+ 0x7948, 0,
+#undef V12470
+#define V12470 (V + 48139)
+ 0x7950, 0,
+#undef V12471
+#define V12471 (V + 48141)
+ 0x7956, 0,
+#undef V12472
+#define V12472 (V + 48143)
+ 0x795d, 0,
+#undef V12473
+#define V12473 (V + 48145)
+ 0x798d, 0,
+#undef V12474
+#define V12474 (V + 48147)
+ 0x798e, 0,
+#undef V12475
+#define V12475 (V + 48149)
+ 0x7a40, 0,
+#undef V12476
+#define V12476 (V + 48151)
+ 0x7a81, 0,
+#undef V12477
+#define V12477 (V + 48153)
+ 0x7bc0, 0,
+#undef V12478
+#define V12478 (V + 48155)
+ 0x7e09, 0,
+#undef V12479
+#define V12479 (V + 48157)
+ 0x7e41, 0,
+#undef V12480
+#define V12480 (V + 48159)
+ 0x7f72, 0,
+#undef V12481
+#define V12481 (V + 48161)
+ 0x8005, 0,
+#undef V12482
+#define V12482 (V + 48163)
+ 0x81ed, 0,
+#undef V12483
+#define V12483 (V + 48165)
+ 0x8279, 0,
+#undef V12484
+#define V12484 (V + 48167)
+ 0x8457, 0,
+#undef V12485
+#define V12485 (V + 48169)
+ 0x8910, 0,
+#undef V12486
+#define V12486 (V + 48171)
+ 0x8996, 0,
+#undef V12487
+#define V12487 (V + 48173)
+ 0x8b01, 0,
+#undef V12488
+#define V12488 (V + 48175)
+ 0x8b39, 0,
+#undef V12489
+#define V12489 (V + 48177)
+ 0x8cd3, 0,
+#undef V12490
+#define V12490 (V + 48179)
+ 0x8d08, 0,
+#undef V12491
+#define V12491 (V + 48181)
+ 0x8fb6, 0,
+#undef V12492
+#define V12492 (V + 48183)
+ 0x96e3, 0,
+#undef V12493
+#define V12493 (V + 48185)
+ 0x97ff, 0,
+#undef V12494
+#define V12494 (V + 48187)
+ 0x983b, 0,
+#undef V12495
+#define V12495 (V + 48189)
+ 0x6075, 0,
+#undef V12496
+#define V12496 (V + 48191)
+ 0x242ee, 0,
+#undef V12497
+#define V12497 (V + 48193)
+ 0x8218, 0,
+#undef V12498
+#define V12498 (V + 48195)
+ 0x4e26, 0,
+#undef V12499
+#define V12499 (V + 48197)
+ 0x51b5, 0,
+#undef V12500
+#define V12500 (V + 48199)
+ 0x5168, 0,
+#undef V12501
+#define V12501 (V + 48201)
+ 0x4f80, 0,
+#undef V12502
+#define V12502 (V + 48203)
+ 0x5145, 0,
+#undef V12503
+#define V12503 (V + 48205)
+ 0x5180, 0,
+#undef V12504
+#define V12504 (V + 48207)
+ 0x52c7, 0,
+#undef V12505
+#define V12505 (V + 48209)
+ 0x52fa, 0,
+#undef V12506
+#define V12506 (V + 48211)
+ 0x5555, 0,
+#undef V12507
+#define V12507 (V + 48213)
+ 0x5599, 0,
+#undef V12508
+#define V12508 (V + 48215)
+ 0x55e2, 0,
+#undef V12509
+#define V12509 (V + 48217)
+ 0x58b3, 0,
+#undef V12510
+#define V12510 (V + 48219)
+ 0x5944, 0,
+#undef V12511
+#define V12511 (V + 48221)
+ 0x5954, 0,
+#undef V12512
+#define V12512 (V + 48223)
+ 0x5a62, 0,
+#undef V12513
+#define V12513 (V + 48225)
+ 0x5b28, 0,
+#undef V12514
+#define V12514 (V + 48227)
+ 0x5ed2, 0,
+#undef V12515
+#define V12515 (V + 48229)
+ 0x5ed9, 0,
+#undef V12516
+#define V12516 (V + 48231)
+ 0x5f69, 0,
+#undef V12517
+#define V12517 (V + 48233)
+ 0x5fad, 0,
+#undef V12518
+#define V12518 (V + 48235)
+ 0x60d8, 0,
+#undef V12519
+#define V12519 (V + 48237)
+ 0x614e, 0,
+#undef V12520
+#define V12520 (V + 48239)
+ 0x6108, 0,
+#undef V12521
+#define V12521 (V + 48241)
+ 0x6160, 0,
+#undef V12522
+#define V12522 (V + 48243)
+ 0x6234, 0,
+#undef V12523
+#define V12523 (V + 48245)
+ 0x63c4, 0,
+#undef V12524
+#define V12524 (V + 48247)
+ 0x641c, 0,
+#undef V12525
+#define V12525 (V + 48249)
+ 0x6452, 0,
+#undef V12526
+#define V12526 (V + 48251)
+ 0x6556, 0,
+#undef V12527
+#define V12527 (V + 48253)
+ 0x671b, 0,
+#undef V12528
+#define V12528 (V + 48255)
+ 0x6756, 0,
+#undef V12529
+#define V12529 (V + 48257)
+ 0x6b79, 0,
+#undef V12530
+#define V12530 (V + 48259)
+ 0x6edb, 0,
+#undef V12531
+#define V12531 (V + 48261)
+ 0x6ecb, 0,
+#undef V12532
+#define V12532 (V + 48263)
+ 0x701e, 0,
+#undef V12533
+#define V12533 (V + 48265)
+ 0x77a7, 0,
+#undef V12534
+#define V12534 (V + 48267)
+ 0x7235, 0,
+#undef V12535
+#define V12535 (V + 48269)
+ 0x72af, 0,
+#undef V12536
+#define V12536 (V + 48271)
+ 0x7471, 0,
+#undef V12537
+#define V12537 (V + 48273)
+ 0x7506, 0,
+#undef V12538
+#define V12538 (V + 48275)
+ 0x753b, 0,
+#undef V12539
+#define V12539 (V + 48277)
+ 0x761d, 0,
+#undef V12540
+#define V12540 (V + 48279)
+ 0x761f, 0,
+#undef V12541
+#define V12541 (V + 48281)
+ 0x76db, 0,
+#undef V12542
+#define V12542 (V + 48283)
+ 0x76f4, 0,
+#undef V12543
+#define V12543 (V + 48285)
+ 0x774a, 0,
+#undef V12544
+#define V12544 (V + 48287)
+ 0x7740, 0,
+#undef V12545
+#define V12545 (V + 48289)
+ 0x78cc, 0,
+#undef V12546
+#define V12546 (V + 48291)
+ 0x7ab1, 0,
+#undef V12547
+#define V12547 (V + 48293)
+ 0x7c7b, 0,
+#undef V12548
+#define V12548 (V + 48295)
+ 0x7d5b, 0,
+#undef V12549
+#define V12549 (V + 48297)
+ 0x7f3e, 0,
+#undef V12550
+#define V12550 (V + 48299)
+ 0x8352, 0,
+#undef V12551
+#define V12551 (V + 48301)
+ 0x83ef, 0,
+#undef V12552
+#define V12552 (V + 48303)
+ 0x8779, 0,
+#undef V12553
+#define V12553 (V + 48305)
+ 0x8941, 0,
+#undef V12554
+#define V12554 (V + 48307)
+ 0x8986, 0,
+#undef V12555
+#define V12555 (V + 48309)
+ 0x8abf, 0,
+#undef V12556
+#define V12556 (V + 48311)
+ 0x8acb, 0,
+#undef V12557
+#define V12557 (V + 48313)
+ 0x8aed, 0,
+#undef V12558
+#define V12558 (V + 48315)
+ 0x8b8a, 0,
+#undef V12559
+#define V12559 (V + 48317)
+ 0x8f38, 0,
+#undef V12560
+#define V12560 (V + 48319)
+ 0x9072, 0,
+#undef V12561
+#define V12561 (V + 48321)
+ 0x9199, 0,
+#undef V12562
+#define V12562 (V + 48323)
+ 0x9276, 0,
+#undef V12563
+#define V12563 (V + 48325)
+ 0x967c, 0,
+#undef V12564
+#define V12564 (V + 48327)
+ 0x97db, 0,
+#undef V12565
+#define V12565 (V + 48329)
+ 0x980b, 0,
+#undef V12566
+#define V12566 (V + 48331)
+ 0x9b12, 0,
+#undef V12567
+#define V12567 (V + 48333)
+ 0x2284a, 0,
+#undef V12568
+#define V12568 (V + 48335)
+ 0x22844, 0,
+#undef V12569
+#define V12569 (V + 48337)
+ 0x233d5, 0,
+#undef V12570
+#define V12570 (V + 48339)
+ 0x3b9d, 0,
+#undef V12571
+#define V12571 (V + 48341)
+ 0x4018, 0,
+#undef V12572
+#define V12572 (V + 48343)
+ 0x4039, 0,
+#undef V12573
+#define V12573 (V + 48345)
+ 0x25249, 0,
+#undef V12574
+#define V12574 (V + 48347)
+ 0x25cd0, 0,
+#undef V12575
+#define V12575 (V + 48349)
+ 0x27ed3, 0,
+#undef V12576
+#define V12576 (V + 48351)
+ 0x9f43, 0,
+#undef V12577
+#define V12577 (V + 48353)
+ 0x9f8e, 0,
+#undef V12578
+#define V12578 (V + 48355)
+ 0x5d9, 0x5b4, 0,
+#undef V12579
+#define V12579 (V + 48358)
+ 0x5f2, 0x5b7, 0,
+#undef V12580
+#define V12580 (V + 48361)
+ 0x5e9, 0x5c1, 0,
+#undef V12581
+#define V12581 (V + 48364)
+ 0x5e9, 0x5c2, 0,
+#undef V12582
+#define V12582 (V + 48367)
+ 0x5e9, 0x5bc, 0x5c1, 0,
+#undef V12583
+#define V12583 (V + 48371)
+ 0x5e9, 0x5bc, 0x5c2, 0,
+#undef V12584
+#define V12584 (V + 48375)
+ 0x5d0, 0x5b7, 0,
+#undef V12585
+#define V12585 (V + 48378)
+ 0x5d0, 0x5b8, 0,
+#undef V12586
+#define V12586 (V + 48381)
+ 0x5d0, 0x5bc, 0,
+#undef V12587
+#define V12587 (V + 48384)
+ 0x5d1, 0x5bc, 0,
+#undef V12588
+#define V12588 (V + 48387)
+ 0x5d2, 0x5bc, 0,
+#undef V12589
+#define V12589 (V + 48390)
+ 0x5d3, 0x5bc, 0,
+#undef V12590
+#define V12590 (V + 48393)
+ 0x5d4, 0x5bc, 0,
+#undef V12591
+#define V12591 (V + 48396)
+ 0x5d5, 0x5bc, 0,
+#undef V12592
+#define V12592 (V + 48399)
+ 0x5d6, 0x5bc, 0,
+#undef V12593
+#define V12593 (V + 48402)
+ 0x5d8, 0x5bc, 0,
+#undef V12594
+#define V12594 (V + 48405)
+ 0x5d9, 0x5bc, 0,
+#undef V12595
+#define V12595 (V + 48408)
+ 0x5da, 0x5bc, 0,
+#undef V12596
+#define V12596 (V + 48411)
+ 0x5db, 0x5bc, 0,
+#undef V12597
+#define V12597 (V + 48414)
+ 0x5dc, 0x5bc, 0,
+#undef V12598
+#define V12598 (V + 48417)
+ 0x5de, 0x5bc, 0,
+#undef V12599
+#define V12599 (V + 48420)
+ 0x5e0, 0x5bc, 0,
+#undef V12600
+#define V12600 (V + 48423)
+ 0x5e1, 0x5bc, 0,
+#undef V12601
+#define V12601 (V + 48426)
+ 0x5e3, 0x5bc, 0,
+#undef V12602
+#define V12602 (V + 48429)
+ 0x5e4, 0x5bc, 0,
+#undef V12603
+#define V12603 (V + 48432)
+ 0x5e6, 0x5bc, 0,
+#undef V12604
+#define V12604 (V + 48435)
+ 0x5e7, 0x5bc, 0,
+#undef V12605
+#define V12605 (V + 48438)
+ 0x5e8, 0x5bc, 0,
+#undef V12606
+#define V12606 (V + 48441)
+ 0x5e9, 0x5bc, 0,
+#undef V12607
+#define V12607 (V + 48444)
+ 0x5ea, 0x5bc, 0,
+#undef V12608
+#define V12608 (V + 48447)
+ 0x5d5, 0x5b9, 0,
+#undef V12609
+#define V12609 (V + 48450)
+ 0x5d1, 0x5bf, 0,
+#undef V12610
+#define V12610 (V + 48453)
+ 0x5db, 0x5bf, 0,
+#undef V12611
+#define V12611 (V + 48456)
+ 0x5e4, 0x5bf, 0,
+#undef V12612
+#define V12612 (V + 48459)
+ 0x11099, 0x110ba, 0,
+#undef V12613
+#define V12613 (V + 48462)
+ 0x1109b, 0x110ba, 0,
+#undef V12614
+#define V12614 (V + 48465)
+ 0x110a5, 0x110ba, 0,
+#undef V12615
+#define V12615 (V + 48468)
+ 0x11131, 0x11127, 0,
+#undef V12616
+#define V12616 (V + 48471)
+ 0x11132, 0x11127, 0,
+#undef V12617
+#define V12617 (V + 48474)
+ 0x11347, 0x1133e, 0,
+#undef V12618
+#define V12618 (V + 48477)
+ 0x11347, 0x11357, 0,
+#undef V12619
+#define V12619 (V + 48480)
+ 0x114b9, 0x114ba, 0,
+#undef V12620
+#define V12620 (V + 48483)
+ 0x114b9, 0x114b0, 0,
+#undef V12621
+#define V12621 (V + 48486)
+ 0x114b9, 0x114bd, 0,
+#undef V12622
+#define V12622 (V + 48489)
+ 0x115b8, 0x115af, 0,
+#undef V12623
+#define V12623 (V + 48492)
+ 0x115b9, 0x115af, 0,
+#undef V12624
+#define V12624 (V + 48495)
+ 0x1d157, 0x1d165, 0,
+#undef V12625
+#define V12625 (V + 48498)
+ 0x1d158, 0x1d165, 0,
+#undef V12626
+#define V12626 (V + 48501)
+ 0x1d158, 0x1d165, 0x1d16e, 0,
+#undef V12627
+#define V12627 (V + 48505)
+ 0x1d158, 0x1d165, 0x1d16f, 0,
+#undef V12628
+#define V12628 (V + 48509)
+ 0x1d158, 0x1d165, 0x1d170, 0,
+#undef V12629
+#define V12629 (V + 48513)
+ 0x1d158, 0x1d165, 0x1d171, 0,
+#undef V12630
+#define V12630 (V + 48517)
+ 0x1d158, 0x1d165, 0x1d172, 0,
+#undef V12631
+#define V12631 (V + 48521)
+ 0x1d1b9, 0x1d165, 0,
+#undef V12632
+#define V12632 (V + 48524)
+ 0x1d1ba, 0x1d165, 0,
+#undef V12633
+#define V12633 (V + 48527)
+ 0x1d1b9, 0x1d165, 0x1d16e, 0,
+#undef V12634
+#define V12634 (V + 48531)
+ 0x1d1ba, 0x1d165, 0x1d16e, 0,
+#undef V12635
+#define V12635 (V + 48535)
+ 0x1d1b9, 0x1d165, 0x1d16f, 0,
+#undef V12636
+#define V12636 (V + 48539)
+ 0x1d1ba, 0x1d165, 0x1d16f, 0,
+#undef V12637
+#define V12637 (V + 48543)
+ 0x4e3d, 0,
+#undef V12638
+#define V12638 (V + 48545)
+ 0x4e38, 0,
+#undef V12639
+#define V12639 (V + 48547)
+ 0x4e41, 0,
+#undef V12640
+#define V12640 (V + 48549)
+ 0x20122, 0,
+#undef V12641
+#define V12641 (V + 48551)
+ 0x4f60, 0,
+#undef V12642
+#define V12642 (V + 48553)
+ 0x4fbb, 0,
+#undef V12643
+#define V12643 (V + 48555)
+ 0x5002, 0,
+#undef V12644
+#define V12644 (V + 48557)
+ 0x507a, 0,
+#undef V12645
+#define V12645 (V + 48559)
+ 0x5099, 0,
+#undef V12646
+#define V12646 (V + 48561)
+ 0x50cf, 0,
+#undef V12647
+#define V12647 (V + 48563)
+ 0x349e, 0,
+#undef V12648
+#define V12648 (V + 48565)
+ 0x2063a, 0,
+#undef V12649
+#define V12649 (V + 48567)
+ 0x5154, 0,
+#undef V12650
+#define V12650 (V + 48569)
+ 0x5164, 0,
+#undef V12651
+#define V12651 (V + 48571)
+ 0x5177, 0,
+#undef V12652
+#define V12652 (V + 48573)
+ 0x2051c, 0,
+#undef V12653
+#define V12653 (V + 48575)
+ 0x34b9, 0,
+#undef V12654
+#define V12654 (V + 48577)
+ 0x5167, 0,
+#undef V12655
+#define V12655 (V + 48579)
+ 0x518d, 0,
+#undef V12656
+#define V12656 (V + 48581)
+ 0x2054b, 0,
+#undef V12657
+#define V12657 (V + 48583)
+ 0x5197, 0,
+#undef V12658
+#define V12658 (V + 48585)
+ 0x51a4, 0,
+#undef V12659
+#define V12659 (V + 48587)
+ 0x4ecc, 0,
+#undef V12660
+#define V12660 (V + 48589)
+ 0x51ac, 0,
+#undef V12661
+#define V12661 (V + 48591)
+ 0x291df, 0,
+#undef V12662
+#define V12662 (V + 48593)
+ 0x51f5, 0,
+#undef V12663
+#define V12663 (V + 48595)
+ 0x5203, 0,
+#undef V12664
+#define V12664 (V + 48597)
+ 0x34df, 0,
+#undef V12665
+#define V12665 (V + 48599)
+ 0x523b, 0,
+#undef V12666
+#define V12666 (V + 48601)
+ 0x5246, 0,
+#undef V12667
+#define V12667 (V + 48603)
+ 0x5272, 0,
+#undef V12668
+#define V12668 (V + 48605)
+ 0x5277, 0,
+#undef V12669
+#define V12669 (V + 48607)
+ 0x3515, 0,
+#undef V12670
+#define V12670 (V + 48609)
+ 0x5305, 0,
+#undef V12671
+#define V12671 (V + 48611)
+ 0x5306, 0,
+#undef V12672
+#define V12672 (V + 48613)
+ 0x5349, 0,
+#undef V12673
+#define V12673 (V + 48615)
+ 0x535a, 0,
+#undef V12674
+#define V12674 (V + 48617)
+ 0x5373, 0,
+#undef V12675
+#define V12675 (V + 48619)
+ 0x537d, 0,
+#undef V12676
+#define V12676 (V + 48621)
+ 0x537f, 0,
+#undef V12677
+#define V12677 (V + 48623)
+ 0x20a2c, 0,
+#undef V12678
+#define V12678 (V + 48625)
+ 0x7070, 0,
+#undef V12679
+#define V12679 (V + 48627)
+ 0x53ca, 0,
+#undef V12680
+#define V12680 (V + 48629)
+ 0x53df, 0,
+#undef V12681
+#define V12681 (V + 48631)
+ 0x20b63, 0,
+#undef V12682
+#define V12682 (V + 48633)
+ 0x53eb, 0,
+#undef V12683
+#define V12683 (V + 48635)
+ 0x53f1, 0,
+#undef V12684
+#define V12684 (V + 48637)
+ 0x5406, 0,
+#undef V12685
+#define V12685 (V + 48639)
+ 0x549e, 0,
+#undef V12686
+#define V12686 (V + 48641)
+ 0x5438, 0,
+#undef V12687
+#define V12687 (V + 48643)
+ 0x5448, 0,
+#undef V12688
+#define V12688 (V + 48645)
+ 0x5468, 0,
+#undef V12689
+#define V12689 (V + 48647)
+ 0x54a2, 0,
+#undef V12690
+#define V12690 (V + 48649)
+ 0x54f6, 0,
+#undef V12691
+#define V12691 (V + 48651)
+ 0x5510, 0,
+#undef V12692
+#define V12692 (V + 48653)
+ 0x5553, 0,
+#undef V12693
+#define V12693 (V + 48655)
+ 0x5563, 0,
+#undef V12694
+#define V12694 (V + 48657)
+ 0x5584, 0,
+#undef V12695
+#define V12695 (V + 48659)
+ 0x55ab, 0,
+#undef V12696
+#define V12696 (V + 48661)
+ 0x55b3, 0,
+#undef V12697
+#define V12697 (V + 48663)
+ 0x55c2, 0,
+#undef V12698
+#define V12698 (V + 48665)
+ 0x5716, 0,
+#undef V12699
+#define V12699 (V + 48667)
+ 0x5717, 0,
+#undef V12700
+#define V12700 (V + 48669)
+ 0x5651, 0,
+#undef V12701
+#define V12701 (V + 48671)
+ 0x5674, 0,
+#undef V12702
+#define V12702 (V + 48673)
+ 0x58ee, 0,
+#undef V12703
+#define V12703 (V + 48675)
+ 0x57ce, 0,
+#undef V12704
+#define V12704 (V + 48677)
+ 0x57f4, 0,
+#undef V12705
+#define V12705 (V + 48679)
+ 0x580d, 0,
+#undef V12706
+#define V12706 (V + 48681)
+ 0x578b, 0,
+#undef V12707
+#define V12707 (V + 48683)
+ 0x5832, 0,
+#undef V12708
+#define V12708 (V + 48685)
+ 0x5831, 0,
+#undef V12709
+#define V12709 (V + 48687)
+ 0x58ac, 0,
+#undef V12710
+#define V12710 (V + 48689)
+ 0x214e4, 0,
+#undef V12711
+#define V12711 (V + 48691)
+ 0x58f2, 0,
+#undef V12712
+#define V12712 (V + 48693)
+ 0x58f7, 0,
+#undef V12713
+#define V12713 (V + 48695)
+ 0x5906, 0,
+#undef V12714
+#define V12714 (V + 48697)
+ 0x591a, 0,
+#undef V12715
+#define V12715 (V + 48699)
+ 0x5922, 0,
+#undef V12716
+#define V12716 (V + 48701)
+ 0x5962, 0,
+#undef V12717
+#define V12717 (V + 48703)
+ 0x216a8, 0,
+#undef V12718
+#define V12718 (V + 48705)
+ 0x216ea, 0,
+#undef V12719
+#define V12719 (V + 48707)
+ 0x59ec, 0,
+#undef V12720
+#define V12720 (V + 48709)
+ 0x5a1b, 0,
+#undef V12721
+#define V12721 (V + 48711)
+ 0x5a27, 0,
+#undef V12722
+#define V12722 (V + 48713)
+ 0x59d8, 0,
+#undef V12723
+#define V12723 (V + 48715)
+ 0x5a66, 0,
+#undef V12724
+#define V12724 (V + 48717)
+ 0x36ee, 0,
+#undef V12725
+#define V12725 (V + 48719)
+ 0x36fc, 0,
+#undef V12726
+#define V12726 (V + 48721)
+ 0x5b08, 0,
+#undef V12727
+#define V12727 (V + 48723)
+ 0x5b3e, 0,
+#undef V12728
+#define V12728 (V + 48725)
+ 0x219c8, 0,
+#undef V12729
+#define V12729 (V + 48727)
+ 0x5bc3, 0,
+#undef V12730
+#define V12730 (V + 48729)
+ 0x5bd8, 0,
+#undef V12731
+#define V12731 (V + 48731)
+ 0x5bf3, 0,
+#undef V12732
+#define V12732 (V + 48733)
+ 0x21b18, 0,
+#undef V12733
+#define V12733 (V + 48735)
+ 0x5bff, 0,
+#undef V12734
+#define V12734 (V + 48737)
+ 0x5c06, 0,
+#undef V12735
+#define V12735 (V + 48739)
+ 0x5f53, 0,
+#undef V12736
+#define V12736 (V + 48741)
+ 0x5c22, 0,
+#undef V12737
+#define V12737 (V + 48743)
+ 0x3781, 0,
+#undef V12738
+#define V12738 (V + 48745)
+ 0x5c60, 0,
+#undef V12739
+#define V12739 (V + 48747)
+ 0x5cc0, 0,
+#undef V12740
+#define V12740 (V + 48749)
+ 0x5c8d, 0,
+#undef V12741
+#define V12741 (V + 48751)
+ 0x21de4, 0,
+#undef V12742
+#define V12742 (V + 48753)
+ 0x5d43, 0,
+#undef V12743
+#define V12743 (V + 48755)
+ 0x21de6, 0,
+#undef V12744
+#define V12744 (V + 48757)
+ 0x5d6e, 0,
+#undef V12745
+#define V12745 (V + 48759)
+ 0x5d6b, 0,
+#undef V12746
+#define V12746 (V + 48761)
+ 0x5d7c, 0,
+#undef V12747
+#define V12747 (V + 48763)
+ 0x5de1, 0,
+#undef V12748
+#define V12748 (V + 48765)
+ 0x5de2, 0,
+#undef V12749
+#define V12749 (V + 48767)
+ 0x382f, 0,
+#undef V12750
+#define V12750 (V + 48769)
+ 0x5dfd, 0,
+#undef V12751
+#define V12751 (V + 48771)
+ 0x5e28, 0,
+#undef V12752
+#define V12752 (V + 48773)
+ 0x5e3d, 0,
+#undef V12753
+#define V12753 (V + 48775)
+ 0x5e69, 0,
+#undef V12754
+#define V12754 (V + 48777)
+ 0x3862, 0,
+#undef V12755
+#define V12755 (V + 48779)
+ 0x22183, 0,
+#undef V12756
+#define V12756 (V + 48781)
+ 0x387c, 0,
+#undef V12757
+#define V12757 (V + 48783)
+ 0x5eb0, 0,
+#undef V12758
+#define V12758 (V + 48785)
+ 0x5eb3, 0,
+#undef V12759
+#define V12759 (V + 48787)
+ 0x5eb6, 0,
+#undef V12760
+#define V12760 (V + 48789)
+ 0x2a392, 0,
+#undef V12761
+#define V12761 (V + 48791)
+ 0x5efe, 0,
+#undef V12762
+#define V12762 (V + 48793)
+ 0x22331, 0,
+#undef V12763
+#define V12763 (V + 48795)
+ 0x8201, 0,
+#undef V12764
+#define V12764 (V + 48797)
+ 0x5f22, 0,
+#undef V12765
+#define V12765 (V + 48799)
+ 0x38c7, 0,
+#undef V12766
+#define V12766 (V + 48801)
+ 0x232b8, 0,
+#undef V12767
+#define V12767 (V + 48803)
+ 0x261da, 0,
+#undef V12768
+#define V12768 (V + 48805)
+ 0x5f62, 0,
+#undef V12769
+#define V12769 (V + 48807)
+ 0x5f6b, 0,
+#undef V12770
+#define V12770 (V + 48809)
+ 0x38e3, 0,
+#undef V12771
+#define V12771 (V + 48811)
+ 0x5f9a, 0,
+#undef V12772
+#define V12772 (V + 48813)
+ 0x5fcd, 0,
+#undef V12773
+#define V12773 (V + 48815)
+ 0x5fd7, 0,
+#undef V12774
+#define V12774 (V + 48817)
+ 0x5ff9, 0,
+#undef V12775
+#define V12775 (V + 48819)
+ 0x6081, 0,
+#undef V12776
+#define V12776 (V + 48821)
+ 0x393a, 0,
+#undef V12777
+#define V12777 (V + 48823)
+ 0x391c, 0,
+#undef V12778
+#define V12778 (V + 48825)
+ 0x226d4, 0,
+#undef V12779
+#define V12779 (V + 48827)
+ 0x60c7, 0,
+#undef V12780
+#define V12780 (V + 48829)
+ 0x6148, 0,
+#undef V12781
+#define V12781 (V + 48831)
+ 0x614c, 0,
+#undef V12782
+#define V12782 (V + 48833)
+ 0x617a, 0,
+#undef V12783
+#define V12783 (V + 48835)
+ 0x61b2, 0,
+#undef V12784
+#define V12784 (V + 48837)
+ 0x61a4, 0,
+#undef V12785
+#define V12785 (V + 48839)
+ 0x61af, 0,
+#undef V12786
+#define V12786 (V + 48841)
+ 0x61de, 0,
+#undef V12787
+#define V12787 (V + 48843)
+ 0x6210, 0,
+#undef V12788
+#define V12788 (V + 48845)
+ 0x621b, 0,
+#undef V12789
+#define V12789 (V + 48847)
+ 0x625d, 0,
+#undef V12790
+#define V12790 (V + 48849)
+ 0x62b1, 0,
+#undef V12791
+#define V12791 (V + 48851)
+ 0x62d4, 0,
+#undef V12792
+#define V12792 (V + 48853)
+ 0x6350, 0,
+#undef V12793
+#define V12793 (V + 48855)
+ 0x22b0c, 0,
+#undef V12794
+#define V12794 (V + 48857)
+ 0x633d, 0,
+#undef V12795
+#define V12795 (V + 48859)
+ 0x62fc, 0,
+#undef V12796
+#define V12796 (V + 48861)
+ 0x6368, 0,
+#undef V12797
+#define V12797 (V + 48863)
+ 0x6383, 0,
+#undef V12798
+#define V12798 (V + 48865)
+ 0x63e4, 0,
+#undef V12799
+#define V12799 (V + 48867)
+ 0x22bf1, 0,
+#undef V12800
+#define V12800 (V + 48869)
+ 0x6422, 0,
+#undef V12801
+#define V12801 (V + 48871)
+ 0x63c5, 0,
+#undef V12802
+#define V12802 (V + 48873)
+ 0x63a9, 0,
+#undef V12803
+#define V12803 (V + 48875)
+ 0x3a2e, 0,
+#undef V12804
+#define V12804 (V + 48877)
+ 0x6469, 0,
+#undef V12805
+#define V12805 (V + 48879)
+ 0x647e, 0,
+#undef V12806
+#define V12806 (V + 48881)
+ 0x649d, 0,
+#undef V12807
+#define V12807 (V + 48883)
+ 0x6477, 0,
+#undef V12808
+#define V12808 (V + 48885)
+ 0x3a6c, 0,
+#undef V12809
+#define V12809 (V + 48887)
+ 0x656c, 0,
+#undef V12810
+#define V12810 (V + 48889)
+ 0x2300a, 0,
+#undef V12811
+#define V12811 (V + 48891)
+ 0x65e3, 0,
+#undef V12812
+#define V12812 (V + 48893)
+ 0x66f8, 0,
+#undef V12813
+#define V12813 (V + 48895)
+ 0x6649, 0,
+#undef V12814
+#define V12814 (V + 48897)
+ 0x3b19, 0,
+#undef V12815
+#define V12815 (V + 48899)
+ 0x3b08, 0,
+#undef V12816
+#define V12816 (V + 48901)
+ 0x3ae4, 0,
+#undef V12817
+#define V12817 (V + 48903)
+ 0x5192, 0,
+#undef V12818
+#define V12818 (V + 48905)
+ 0x5195, 0,
+#undef V12819
+#define V12819 (V + 48907)
+ 0x6700, 0,
+#undef V12820
+#define V12820 (V + 48909)
+ 0x669c, 0,
+#undef V12821
+#define V12821 (V + 48911)
+ 0x80ad, 0,
+#undef V12822
+#define V12822 (V + 48913)
+ 0x43d9, 0,
+#undef V12823
+#define V12823 (V + 48915)
+ 0x6721, 0,
+#undef V12824
+#define V12824 (V + 48917)
+ 0x675e, 0,
+#undef V12825
+#define V12825 (V + 48919)
+ 0x6753, 0,
+#undef V12826
+#define V12826 (V + 48921)
+ 0x233c3, 0,
+#undef V12827
+#define V12827 (V + 48923)
+ 0x3b49, 0,
+#undef V12828
+#define V12828 (V + 48925)
+ 0x67fa, 0,
+#undef V12829
+#define V12829 (V + 48927)
+ 0x6785, 0,
+#undef V12830
+#define V12830 (V + 48929)
+ 0x6852, 0,
+#undef V12831
+#define V12831 (V + 48931)
+ 0x2346d, 0,
+#undef V12832
+#define V12832 (V + 48933)
+ 0x688e, 0,
+#undef V12833
+#define V12833 (V + 48935)
+ 0x681f, 0,
+#undef V12834
+#define V12834 (V + 48937)
+ 0x6914, 0,
+#undef V12835
+#define V12835 (V + 48939)
+ 0x6942, 0,
+#undef V12836
+#define V12836 (V + 48941)
+ 0x69a3, 0,
+#undef V12837
+#define V12837 (V + 48943)
+ 0x69ea, 0,
+#undef V12838
+#define V12838 (V + 48945)
+ 0x6aa8, 0,
+#undef V12839
+#define V12839 (V + 48947)
+ 0x236a3, 0,
+#undef V12840
+#define V12840 (V + 48949)
+ 0x6adb, 0,
+#undef V12841
+#define V12841 (V + 48951)
+ 0x3c18, 0,
+#undef V12842
+#define V12842 (V + 48953)
+ 0x6b21, 0,
+#undef V12843
+#define V12843 (V + 48955)
+ 0x238a7, 0,
+#undef V12844
+#define V12844 (V + 48957)
+ 0x6b54, 0,
+#undef V12845
+#define V12845 (V + 48959)
+ 0x3c4e, 0,
+#undef V12846
+#define V12846 (V + 48961)
+ 0x6b72, 0,
+#undef V12847
+#define V12847 (V + 48963)
+ 0x6b9f, 0,
+#undef V12848
+#define V12848 (V + 48965)
+ 0x6bbb, 0,
+#undef V12849
+#define V12849 (V + 48967)
+ 0x23a8d, 0,
+#undef V12850
+#define V12850 (V + 48969)
+ 0x21d0b, 0,
+#undef V12851
+#define V12851 (V + 48971)
+ 0x23afa, 0,
+#undef V12852
+#define V12852 (V + 48973)
+ 0x6c4e, 0,
+#undef V12853
+#define V12853 (V + 48975)
+ 0x23cbc, 0,
+#undef V12854
+#define V12854 (V + 48977)
+ 0x6cbf, 0,
+#undef V12855
+#define V12855 (V + 48979)
+ 0x6ccd, 0,
+#undef V12856
+#define V12856 (V + 48981)
+ 0x6c67, 0,
+#undef V12857
+#define V12857 (V + 48983)
+ 0x6d16, 0,
+#undef V12858
+#define V12858 (V + 48985)
+ 0x6d3e, 0,
+#undef V12859
+#define V12859 (V + 48987)
+ 0x6d69, 0,
+#undef V12860
+#define V12860 (V + 48989)
+ 0x6d78, 0,
+#undef V12861
+#define V12861 (V + 48991)
+ 0x6d85, 0,
+#undef V12862
+#define V12862 (V + 48993)
+ 0x23d1e, 0,
+#undef V12863
+#define V12863 (V + 48995)
+ 0x6d34, 0,
+#undef V12864
+#define V12864 (V + 48997)
+ 0x6e2f, 0,
+#undef V12865
+#define V12865 (V + 48999)
+ 0x6e6e, 0,
+#undef V12866
+#define V12866 (V + 49001)
+ 0x3d33, 0,
+#undef V12867
+#define V12867 (V + 49003)
+ 0x6ec7, 0,
+#undef V12868
+#define V12868 (V + 49005)
+ 0x23ed1, 0,
+#undef V12869
+#define V12869 (V + 49007)
+ 0x6df9, 0,
+#undef V12870
+#define V12870 (V + 49009)
+ 0x6f6e, 0,
+#undef V12871
+#define V12871 (V + 49011)
+ 0x23f5e, 0,
+#undef V12872
+#define V12872 (V + 49013)
+ 0x23f8e, 0,
+#undef V12873
+#define V12873 (V + 49015)
+ 0x6fc6, 0,
+#undef V12874
+#define V12874 (V + 49017)
+ 0x7039, 0,
+#undef V12875
+#define V12875 (V + 49019)
+ 0x701b, 0,
+#undef V12876
+#define V12876 (V + 49021)
+ 0x3d96, 0,
+#undef V12877
+#define V12877 (V + 49023)
+ 0x704a, 0,
+#undef V12878
+#define V12878 (V + 49025)
+ 0x707d, 0,
+#undef V12879
+#define V12879 (V + 49027)
+ 0x7077, 0,
+#undef V12880
+#define V12880 (V + 49029)
+ 0x70ad, 0,
+#undef V12881
+#define V12881 (V + 49031)
+ 0x20525, 0,
+#undef V12882
+#define V12882 (V + 49033)
+ 0x7145, 0,
+#undef V12883
+#define V12883 (V + 49035)
+ 0x24263, 0,
+#undef V12884
+#define V12884 (V + 49037)
+ 0x719c, 0,
+#undef V12885
+#define V12885 (V + 49039)
+ 0x243ab, 0,
+#undef V12886
+#define V12886 (V + 49041)
+ 0x7228, 0,
+#undef V12887
+#define V12887 (V + 49043)
+ 0x7250, 0,
+#undef V12888
+#define V12888 (V + 49045)
+ 0x24608, 0,
+#undef V12889
+#define V12889 (V + 49047)
+ 0x7280, 0,
+#undef V12890
+#define V12890 (V + 49049)
+ 0x7295, 0,
+#undef V12891
+#define V12891 (V + 49051)
+ 0x24735, 0,
+#undef V12892
+#define V12892 (V + 49053)
+ 0x24814, 0,
+#undef V12893
+#define V12893 (V + 49055)
+ 0x737a, 0,
+#undef V12894
+#define V12894 (V + 49057)
+ 0x738b, 0,
+#undef V12895
+#define V12895 (V + 49059)
+ 0x3eac, 0,
+#undef V12896
+#define V12896 (V + 49061)
+ 0x73a5, 0,
+#undef V12897
+#define V12897 (V + 49063)
+ 0x3eb8, 0,
+#undef V12898
+#define V12898 (V + 49065)
+ 0x7447, 0,
+#undef V12899
+#define V12899 (V + 49067)
+ 0x745c, 0,
+#undef V12900
+#define V12900 (V + 49069)
+ 0x7485, 0,
+#undef V12901
+#define V12901 (V + 49071)
+ 0x74ca, 0,
+#undef V12902
+#define V12902 (V + 49073)
+ 0x3f1b, 0,
+#undef V12903
+#define V12903 (V + 49075)
+ 0x7524, 0,
+#undef V12904
+#define V12904 (V + 49077)
+ 0x24c36, 0,
+#undef V12905
+#define V12905 (V + 49079)
+ 0x753e, 0,
+#undef V12906
+#define V12906 (V + 49081)
+ 0x24c92, 0,
+#undef V12907
+#define V12907 (V + 49083)
+ 0x2219f, 0,
+#undef V12908
+#define V12908 (V + 49085)
+ 0x7610, 0,
+#undef V12909
+#define V12909 (V + 49087)
+ 0x24fa1, 0,
+#undef V12910
+#define V12910 (V + 49089)
+ 0x24fb8, 0,
+#undef V12911
+#define V12911 (V + 49091)
+ 0x25044, 0,
+#undef V12912
+#define V12912 (V + 49093)
+ 0x3ffc, 0,
+#undef V12913
+#define V12913 (V + 49095)
+ 0x4008, 0,
+#undef V12914
+#define V12914 (V + 49097)
+ 0x250f3, 0,
+#undef V12915
+#define V12915 (V + 49099)
+ 0x250f2, 0,
+#undef V12916
+#define V12916 (V + 49101)
+ 0x25119, 0,
+#undef V12917
+#define V12917 (V + 49103)
+ 0x25133, 0,
+#undef V12918
+#define V12918 (V + 49105)
+ 0x771e, 0,
+#undef V12919
+#define V12919 (V + 49107)
+ 0x771f, 0,
+#undef V12920
+#define V12920 (V + 49109)
+ 0x778b, 0,
+#undef V12921
+#define V12921 (V + 49111)
+ 0x4046, 0,
+#undef V12922
+#define V12922 (V + 49113)
+ 0x4096, 0,
+#undef V12923
+#define V12923 (V + 49115)
+ 0x2541d, 0,
+#undef V12924
+#define V12924 (V + 49117)
+ 0x784e, 0,
+#undef V12925
+#define V12925 (V + 49119)
+ 0x40e3, 0,
+#undef V12926
+#define V12926 (V + 49121)
+ 0x25626, 0,
+#undef V12927
+#define V12927 (V + 49123)
+ 0x2569a, 0,
+#undef V12928
+#define V12928 (V + 49125)
+ 0x256c5, 0,
+#undef V12929
+#define V12929 (V + 49127)
+ 0x79eb, 0,
+#undef V12930
+#define V12930 (V + 49129)
+ 0x412f, 0,
+#undef V12931
+#define V12931 (V + 49131)
+ 0x7a4a, 0,
+#undef V12932
+#define V12932 (V + 49133)
+ 0x7a4f, 0,
+#undef V12933
+#define V12933 (V + 49135)
+ 0x2597c, 0,
+#undef V12934
+#define V12934 (V + 49137)
+ 0x25aa7, 0,
+#undef V12935
+#define V12935 (V + 49139)
+ 0x7aee, 0,
+#undef V12936
+#define V12936 (V + 49141)
+ 0x4202, 0,
+#undef V12937
+#define V12937 (V + 49143)
+ 0x25bab, 0,
+#undef V12938
+#define V12938 (V + 49145)
+ 0x7bc6, 0,
+#undef V12939
+#define V12939 (V + 49147)
+ 0x7bc9, 0,
+#undef V12940
+#define V12940 (V + 49149)
+ 0x4227, 0,
+#undef V12941
+#define V12941 (V + 49151)
+ 0x25c80, 0,
+#undef V12942
+#define V12942 (V + 49153)
+ 0x7cd2, 0,
+#undef V12943
+#define V12943 (V + 49155)
+ 0x42a0, 0,
+#undef V12944
+#define V12944 (V + 49157)
+ 0x7ce8, 0,
+#undef V12945
+#define V12945 (V + 49159)
+ 0x7ce3, 0,
+#undef V12946
+#define V12946 (V + 49161)
+ 0x7d00, 0,
+#undef V12947
+#define V12947 (V + 49163)
+ 0x25f86, 0,
+#undef V12948
+#define V12948 (V + 49165)
+ 0x7d63, 0,
+#undef V12949
+#define V12949 (V + 49167)
+ 0x4301, 0,
+#undef V12950
+#define V12950 (V + 49169)
+ 0x7dc7, 0,
+#undef V12951
+#define V12951 (V + 49171)
+ 0x7e02, 0,
+#undef V12952
+#define V12952 (V + 49173)
+ 0x7e45, 0,
+#undef V12953
+#define V12953 (V + 49175)
+ 0x4334, 0,
+#undef V12954
+#define V12954 (V + 49177)
+ 0x26228, 0,
+#undef V12955
+#define V12955 (V + 49179)
+ 0x26247, 0,
+#undef V12956
+#define V12956 (V + 49181)
+ 0x4359, 0,
+#undef V12957
+#define V12957 (V + 49183)
+ 0x262d9, 0,
+#undef V12958
+#define V12958 (V + 49185)
+ 0x7f7a, 0,
+#undef V12959
+#define V12959 (V + 49187)
+ 0x2633e, 0,
+#undef V12960
+#define V12960 (V + 49189)
+ 0x7f95, 0,
+#undef V12961
+#define V12961 (V + 49191)
+ 0x7ffa, 0,
+#undef V12962
+#define V12962 (V + 49193)
+ 0x264da, 0,
+#undef V12963
+#define V12963 (V + 49195)
+ 0x26523, 0,
+#undef V12964
+#define V12964 (V + 49197)
+ 0x8060, 0,
+#undef V12965
+#define V12965 (V + 49199)
+ 0x265a8, 0,
+#undef V12966
+#define V12966 (V + 49201)
+ 0x8070, 0,
+#undef V12967
+#define V12967 (V + 49203)
+ 0x2335f, 0,
+#undef V12968
+#define V12968 (V + 49205)
+ 0x43d5, 0,
+#undef V12969
+#define V12969 (V + 49207)
+ 0x80b2, 0,
+#undef V12970
+#define V12970 (V + 49209)
+ 0x8103, 0,
+#undef V12971
+#define V12971 (V + 49211)
+ 0x440b, 0,
+#undef V12972
+#define V12972 (V + 49213)
+ 0x813e, 0,
+#undef V12973
+#define V12973 (V + 49215)
+ 0x5ab5, 0,
+#undef V12974
+#define V12974 (V + 49217)
+ 0x267a7, 0,
+#undef V12975
+#define V12975 (V + 49219)
+ 0x267b5, 0,
+#undef V12976
+#define V12976 (V + 49221)
+ 0x23393, 0,
+#undef V12977
+#define V12977 (V + 49223)
+ 0x2339c, 0,
+#undef V12978
+#define V12978 (V + 49225)
+ 0x8204, 0,
+#undef V12979
+#define V12979 (V + 49227)
+ 0x8f9e, 0,
+#undef V12980
+#define V12980 (V + 49229)
+ 0x446b, 0,
+#undef V12981
+#define V12981 (V + 49231)
+ 0x8291, 0,
+#undef V12982
+#define V12982 (V + 49233)
+ 0x828b, 0,
+#undef V12983
+#define V12983 (V + 49235)
+ 0x829d, 0,
+#undef V12984
+#define V12984 (V + 49237)
+ 0x52b3, 0,
+#undef V12985
+#define V12985 (V + 49239)
+ 0x82b1, 0,
+#undef V12986
+#define V12986 (V + 49241)
+ 0x82b3, 0,
+#undef V12987
+#define V12987 (V + 49243)
+ 0x82bd, 0,
+#undef V12988
+#define V12988 (V + 49245)
+ 0x82e6, 0,
+#undef V12989
+#define V12989 (V + 49247)
+ 0x26b3c, 0,
+#undef V12990
+#define V12990 (V + 49249)
+ 0x831d, 0,
+#undef V12991
+#define V12991 (V + 49251)
+ 0x8363, 0,
+#undef V12992
+#define V12992 (V + 49253)
+ 0x83ad, 0,
+#undef V12993
+#define V12993 (V + 49255)
+ 0x8323, 0,
+#undef V12994
+#define V12994 (V + 49257)
+ 0x83bd, 0,
+#undef V12995
+#define V12995 (V + 49259)
+ 0x83e7, 0,
+#undef V12996
+#define V12996 (V + 49261)
+ 0x8353, 0,
+#undef V12997
+#define V12997 (V + 49263)
+ 0x83ca, 0,
+#undef V12998
+#define V12998 (V + 49265)
+ 0x83cc, 0,
+#undef V12999
+#define V12999 (V + 49267)
+ 0x83dc, 0,
+#undef V13000
+#define V13000 (V + 49269)
+ 0x26c36, 0,
+#undef V13001
+#define V13001 (V + 49271)
+ 0x26d6b, 0,
+#undef V13002
+#define V13002 (V + 49273)
+ 0x26cd5, 0,
+#undef V13003
+#define V13003 (V + 49275)
+ 0x452b, 0,
+#undef V13004
+#define V13004 (V + 49277)
+ 0x84f1, 0,
+#undef V13005
+#define V13005 (V + 49279)
+ 0x84f3, 0,
+#undef V13006
+#define V13006 (V + 49281)
+ 0x8516, 0,
+#undef V13007
+#define V13007 (V + 49283)
+ 0x273ca, 0,
+#undef V13008
+#define V13008 (V + 49285)
+ 0x8564, 0,
+#undef V13009
+#define V13009 (V + 49287)
+ 0x26f2c, 0,
+#undef V13010
+#define V13010 (V + 49289)
+ 0x455d, 0,
+#undef V13011
+#define V13011 (V + 49291)
+ 0x4561, 0,
+#undef V13012
+#define V13012 (V + 49293)
+ 0x26fb1, 0,
+#undef V13013
+#define V13013 (V + 49295)
+ 0x270d2, 0,
+#undef V13014
+#define V13014 (V + 49297)
+ 0x456b, 0,
+#undef V13015
+#define V13015 (V + 49299)
+ 0x8650, 0,
+#undef V13016
+#define V13016 (V + 49301)
+ 0x8667, 0,
+#undef V13017
+#define V13017 (V + 49303)
+ 0x8669, 0,
+#undef V13018
+#define V13018 (V + 49305)
+ 0x86a9, 0,
+#undef V13019
+#define V13019 (V + 49307)
+ 0x8688, 0,
+#undef V13020
+#define V13020 (V + 49309)
+ 0x870e, 0,
+#undef V13021
+#define V13021 (V + 49311)
+ 0x86e2, 0,
+#undef V13022
+#define V13022 (V + 49313)
+ 0x8728, 0,
+#undef V13023
+#define V13023 (V + 49315)
+ 0x876b, 0,
+#undef V13024
+#define V13024 (V + 49317)
+ 0x8786, 0,
+#undef V13025
+#define V13025 (V + 49319)
+ 0x45d7, 0,
+#undef V13026
+#define V13026 (V + 49321)
+ 0x87e1, 0,
+#undef V13027
+#define V13027 (V + 49323)
+ 0x8801, 0,
+#undef V13028
+#define V13028 (V + 49325)
+ 0x45f9, 0,
+#undef V13029
+#define V13029 (V + 49327)
+ 0x8860, 0,
+#undef V13030
+#define V13030 (V + 49329)
+ 0x8863, 0,
+#undef V13031
+#define V13031 (V + 49331)
+ 0x27667, 0,
+#undef V13032
+#define V13032 (V + 49333)
+ 0x88d7, 0,
+#undef V13033
+#define V13033 (V + 49335)
+ 0x88de, 0,
+#undef V13034
+#define V13034 (V + 49337)
+ 0x4635, 0,
+#undef V13035
+#define V13035 (V + 49339)
+ 0x88fa, 0,
+#undef V13036
+#define V13036 (V + 49341)
+ 0x34bb, 0,
+#undef V13037
+#define V13037 (V + 49343)
+ 0x278ae, 0,
+#undef V13038
+#define V13038 (V + 49345)
+ 0x27966, 0,
+#undef V13039
+#define V13039 (V + 49347)
+ 0x46be, 0,
+#undef V13040
+#define V13040 (V + 49349)
+ 0x46c7, 0,
+#undef V13041
+#define V13041 (V + 49351)
+ 0x8aa0, 0,
+#undef V13042
+#define V13042 (V + 49353)
+ 0x8c55, 0,
+#undef V13043
+#define V13043 (V + 49355)
+ 0x27ca8, 0,
+#undef V13044
+#define V13044 (V + 49357)
+ 0x8cab, 0,
+#undef V13045
+#define V13045 (V + 49359)
+ 0x8cc1, 0,
+#undef V13046
+#define V13046 (V + 49361)
+ 0x8d1b, 0,
+#undef V13047
+#define V13047 (V + 49363)
+ 0x8d77, 0,
+#undef V13048
+#define V13048 (V + 49365)
+ 0x27f2f, 0,
+#undef V13049
+#define V13049 (V + 49367)
+ 0x20804, 0,
+#undef V13050
+#define V13050 (V + 49369)
+ 0x8dcb, 0,
+#undef V13051
+#define V13051 (V + 49371)
+ 0x8dbc, 0,
+#undef V13052
+#define V13052 (V + 49373)
+ 0x8df0, 0,
+#undef V13053
+#define V13053 (V + 49375)
+ 0x208de, 0,
+#undef V13054
+#define V13054 (V + 49377)
+ 0x8ed4, 0,
+#undef V13055
+#define V13055 (V + 49379)
+ 0x285d2, 0,
+#undef V13056
+#define V13056 (V + 49381)
+ 0x285ed, 0,
+#undef V13057
+#define V13057 (V + 49383)
+ 0x9094, 0,
+#undef V13058
+#define V13058 (V + 49385)
+ 0x90f1, 0,
+#undef V13059
+#define V13059 (V + 49387)
+ 0x9111, 0,
+#undef V13060
+#define V13060 (V + 49389)
+ 0x2872e, 0,
+#undef V13061
+#define V13061 (V + 49391)
+ 0x911b, 0,
+#undef V13062
+#define V13062 (V + 49393)
+ 0x9238, 0,
+#undef V13063
+#define V13063 (V + 49395)
+ 0x92d7, 0,
+#undef V13064
+#define V13064 (V + 49397)
+ 0x92d8, 0,
+#undef V13065
+#define V13065 (V + 49399)
+ 0x927c, 0,
+#undef V13066
+#define V13066 (V + 49401)
+ 0x93f9, 0,
+#undef V13067
+#define V13067 (V + 49403)
+ 0x9415, 0,
+#undef V13068
+#define V13068 (V + 49405)
+ 0x28bfa, 0,
+#undef V13069
+#define V13069 (V + 49407)
+ 0x958b, 0,
+#undef V13070
+#define V13070 (V + 49409)
+ 0x4995, 0,
+#undef V13071
+#define V13071 (V + 49411)
+ 0x95b7, 0,
+#undef V13072
+#define V13072 (V + 49413)
+ 0x28d77, 0,
+#undef V13073
+#define V13073 (V + 49415)
+ 0x49e6, 0,
+#undef V13074
+#define V13074 (V + 49417)
+ 0x96c3, 0,
+#undef V13075
+#define V13075 (V + 49419)
+ 0x5db2, 0,
+#undef V13076
+#define V13076 (V + 49421)
+ 0x9723, 0,
+#undef V13077
+#define V13077 (V + 49423)
+ 0x29145, 0,
+#undef V13078
+#define V13078 (V + 49425)
+ 0x2921a, 0,
+#undef V13079
+#define V13079 (V + 49427)
+ 0x4a6e, 0,
+#undef V13080
+#define V13080 (V + 49429)
+ 0x4a76, 0,
+#undef V13081
+#define V13081 (V + 49431)
+ 0x97e0, 0,
+#undef V13082
+#define V13082 (V + 49433)
+ 0x2940a, 0,
+#undef V13083
+#define V13083 (V + 49435)
+ 0x4ab2, 0,
+#undef V13084
+#define V13084 (V + 49437)
+ 0x29496, 0,
+#undef V13085
+#define V13085 (V + 49439)
+ 0x9829, 0,
+#undef V13086
+#define V13086 (V + 49441)
+ 0x295b6, 0,
+#undef V13087
+#define V13087 (V + 49443)
+ 0x98e2, 0,
+#undef V13088
+#define V13088 (V + 49445)
+ 0x4b33, 0,
+#undef V13089
+#define V13089 (V + 49447)
+ 0x9929, 0,
+#undef V13090
+#define V13090 (V + 49449)
+ 0x99a7, 0,
+#undef V13091
+#define V13091 (V + 49451)
+ 0x99c2, 0,
+#undef V13092
+#define V13092 (V + 49453)
+ 0x99fe, 0,
+#undef V13093
+#define V13093 (V + 49455)
+ 0x4bce, 0,
+#undef V13094
+#define V13094 (V + 49457)
+ 0x29b30, 0,
+#undef V13095
+#define V13095 (V + 49459)
+ 0x9c40, 0,
+#undef V13096
+#define V13096 (V + 49461)
+ 0x9cfd, 0,
+#undef V13097
+#define V13097 (V + 49463)
+ 0x4cce, 0,
+#undef V13098
+#define V13098 (V + 49465)
+ 0x4ced, 0,
+#undef V13099
+#define V13099 (V + 49467)
+ 0x9d67, 0,
+#undef V13100
+#define V13100 (V + 49469)
+ 0x2a0ce, 0,
+#undef V13101
+#define V13101 (V + 49471)
+ 0x4cf8, 0,
+#undef V13102
+#define V13102 (V + 49473)
+ 0x2a105, 0,
+#undef V13103
+#define V13103 (V + 49475)
+ 0x2a20e, 0,
+#undef V13104
+#define V13104 (V + 49477)
+ 0x2a291, 0,
+#undef V13105
+#define V13105 (V + 49479)
+ 0x9ebb, 0,
+#undef V13106
+#define V13106 (V + 49481)
+ 0x4d56, 0,
+#undef V13107
+#define V13107 (V + 49483)
+ 0x9ef9, 0,
+#undef V13108
+#define V13108 (V + 49485)
+ 0x9efe, 0,
+#undef V13109
+#define V13109 (V + 49487)
+ 0x9f05, 0,
+#undef V13110
+#define V13110 (V + 49489)
+ 0x9f0f, 0,
+#undef V13111
+#define V13111 (V + 49491)
+ 0x9f16, 0,
+#undef V13112
+#define V13112 (V + 49493)
+ 0x9f3b, 0,
+#undef V13113
+#define V13113 (V + 49495)
+ 0x2a600, 0,
+ };
+
+ static const NUnicode::NPrivate::TDecompositionTable::TValuePtr P[][32] = {
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[0]
+ {
+ V0, V1, V2, V3, V4, V5, 0, V6,
+ V7, V8, V9, V10, V11, V12, V13, V14,
+ 0, V15, V16, V17, V18, V19, V20, 0,
+ 0, V21, V22, V23, V24, V25, 0, 0,
+ }, // P[1]
+ {
+ V26, V27, V28, V29, V30, V31, 0, V32,
+ V33, V34, V35, V36, V37, V38, V39, V40,
+ 0, V41, V42, V43, V44, V45, V46, 0,
+ 0, V47, V48, V49, V50, V51, 0, V52,
+ }, // P[2]
+ {
+ V53, V54, V55, V56, V57, V58, V59, V60,
+ V61, V62, V63, V64, V65, V66, V67, V68,
+ 0, 0, V69, V70, V71, V72, V73, V74,
+ V75, V76, V77, V78, V79, V80, V81, V82,
+ }, // P[3]
+ {
+ V83, V84, V85, V86, V87, V88, 0, 0,
+ V89, V90, V91, V92, V93, V94, V95, V96,
+ V97, 0, 0, 0, V98, V99, V100, V101,
+ 0, V102, V103, V104, V105, V106, V107, 0,
+ }, // P[4]
+ {
+ 0, 0, 0, V108, V109, V110, V111, V112,
+ V113, 0, 0, 0, V114, V115, V116, V117,
+ V118, V119, 0, 0, V120, V121, V122, V123,
+ V124, V125, V126, V127, V128, V129, V130, V131,
+ }, // P[5]
+ {
+ V132, V133, V134, V135, V136, V137, 0, 0,
+ V138, V139, V140, V141, V142, V143, V144, V145,
+ V146, V147, V148, V149, V150, V151, V152, V153,
+ V154, V155, V156, V157, V158, V159, V160, 0,
+ }, // P[6]
+ {
+ V161, V162, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, V163,
+ V164, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[7]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, V165, V166, V167,
+ V168, V169, V170, V171, V172, V173, V174, V175,
+ V176, V177, V178, V179, V180, 0, V181, V182,
+ }, // P[8]
+ {
+ V183, V184, V185, V186, 0, 0, V187, V188,
+ V189, V190, V191, V192, V193, V194, V195, V196,
+ V197, 0, 0, 0, V198, V199, 0, 0,
+ V200, V201, V202, V203, V204, V205, V206, V207,
+ }, // P[9]
+ {
+ V208, V209, V210, V211, V212, V213, V214, V215,
+ V216, V217, V218, V219, V220, V221, V222, V223,
+ V224, V225, V226, V227, V228, V229, V230, V231,
+ V232, V233, V234, V235, 0, 0, V236, V237,
+ }, // P[10]
+ {
+ 0, 0, 0, 0, 0, 0, V238, V239,
+ V240, V241, V242, V243, V244, V245, V246, V247,
+ V248, V249, V250, V251, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[11]
+ {
+ V252, V253, 0, V254, V255, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[12]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V256, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, V257, 0,
+ }, // P[13]
+ {
+ 0, 0, 0, 0, 0, V258, V259, V260,
+ V261, V262, V263, 0, V264, 0, V265, V266,
+ V267, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[14]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V268, V269, V270, V271, V272, V273,
+ V274, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[15]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V275, V276, V277, V278, V279, 0,
+ 0, 0, 0, V280, V281, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[16]
+ {
+ V282, V283, 0, V284, 0, 0, 0, V285,
+ 0, 0, 0, 0, V286, V287, V288, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, V289, 0, 0, 0, 0, 0, 0,
+ }, // P[17]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, V290, 0, 0, 0, 0, 0, 0,
+ }, // P[18]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V291, V292, 0, V293, 0, 0, 0, V294,
+ 0, 0, 0, 0, V295, V296, V297, 0,
+ }, // P[19]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, V298, V299,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[20]
+ {
+ 0, V300, V301, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V302, V303, V304, V305, 0, 0, V306, V307,
+ 0, 0, V308, V309, V310, V311, V312, V313,
+ }, // P[21]
+ {
+ 0, 0, V314, V315, V316, V317, V318, V319,
+ 0, 0, V320, V321, V322, V323, V324, V325,
+ V326, V327, V328, V329, V330, V331, 0, 0,
+ V332, V333, 0, 0, 0, 0, 0, 0,
+ }, // P[22]
+ {
+ 0, 0, V334, V335, V336, V337, V338, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[23]
+ {
+ V339, 0, V340, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V341, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[24]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, V342, 0, 0, 0, 0, 0, 0,
+ 0, V343, 0, 0, V344, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[25]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V345, V346, V347, V348, V349, V350, V351, V352,
+ }, // P[26]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V353, V354, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V355, V356, 0, V357,
+ }, // P[27]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V358, 0, 0, V359, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[28]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, V360, V361, V362, 0, 0, V363, 0,
+ }, // P[29]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V364, 0, 0, V365, V366, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V367, V368, 0, 0,
+ }, // P[30]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V369, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[31]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V370, V371, V372, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[32]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V373, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[33]
+ {
+ V374, 0, 0, 0, 0, 0, 0, V375,
+ V376, 0, V377, V378, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[34]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V379, V380, V381, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[35]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V382, 0, V383, V384, V385, 0,
+ }, // P[36]
+ {
+ 0, 0, 0, V386, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, V387, 0, 0,
+ 0, 0, V388, 0, 0, 0, 0, V389,
+ 0, 0, 0, 0, V390, 0, 0, 0,
+ }, // P[37]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, V391, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V392, 0, V393, V394, 0,
+ V395, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[38]
+ {
+ 0, V396, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V397, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, V398, 0, 0,
+ }, // P[39]
+ {
+ 0, 0, V399, 0, 0, 0, 0, V400,
+ 0, 0, 0, 0, V401, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, V402, 0, 0, 0, 0, 0, 0,
+ }, // P[40]
+ {
+ 0, 0, 0, 0, 0, 0, V403, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[41]
+ {
+ 0, 0, 0, 0, 0, 0, V404, 0,
+ V405, 0, V406, 0, V407, 0, V408, 0,
+ 0, 0, V409, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[42]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V410, 0, V411, 0, 0,
+ }, // P[43]
+ {
+ V412, V413, 0, V414, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[44]
+ {
+ V415, V416, V417, V418, V419, V420, V421, V422,
+ V423, V424, V425, V426, V427, V428, V429, V430,
+ V431, V432, V433, V434, V435, V436, V437, V438,
+ V439, V440, V441, V442, V443, V444, V445, V446,
+ }, // P[45]
+ {
+ V447, V448, V449, V450, V451, V452, V453, V454,
+ V455, V456, V457, V458, V459, V460, V461, V462,
+ V463, V464, V465, V466, V467, V468, V469, V470,
+ V471, V472, V473, V474, V475, V476, V477, V478,
+ }, // P[46]
+ {
+ V479, V480, V481, V482, V483, V484, V485, V486,
+ V487, V488, V489, V490, V491, V492, V493, V494,
+ V495, V496, V497, V498, V499, V500, V501, V502,
+ V503, V504, V505, V506, V507, V508, V509, V510,
+ }, // P[47]
+ {
+ V511, V512, V513, V514, V515, V516, V517, V518,
+ V519, V520, V521, V522, V523, V524, V525, V526,
+ V527, V528, V529, V530, V531, V532, V533, V534,
+ V535, V536, V537, V538, V539, V540, V541, V542,
+ }, // P[48]
+ {
+ V543, V544, V545, V546, V547, V548, V549, V550,
+ V551, V552, V553, V554, V555, V556, V557, V558,
+ V559, V560, V561, V562, V563, V564, V565, V566,
+ V567, V568, 0, V569, 0, 0, 0, 0,
+ }, // P[49]
+ {
+ V570, V571, V572, V573, V574, V575, V576, V577,
+ V578, V579, V580, V581, V582, V583, V584, V585,
+ V586, V587, V588, V589, V590, V591, V592, V593,
+ V594, V595, V596, V597, V598, V599, V600, V601,
+ }, // P[50]
+ {
+ V602, V603, V604, V605, V606, V607, V608, V609,
+ V610, V611, V612, V613, V614, V615, V616, V617,
+ V618, V619, V620, V621, V622, V623, V624, V625,
+ V626, V627, V628, V629, V630, V631, V632, V633,
+ }, // P[51]
+ {
+ V634, V635, V636, V637, V638, V639, V640, V641,
+ V642, V643, V644, V645, V646, V647, V648, V649,
+ V650, V651, V652, V653, V654, V655, V656, V657,
+ V658, V659, 0, 0, 0, 0, 0, 0,
+ }, // P[52]
+ {
+ V660, V661, V662, V663, V664, V665, V666, V667,
+ V668, V669, V670, V671, V672, V673, V674, V675,
+ V676, V677, V678, V679, V680, V681, 0, 0,
+ V682, V683, V684, V685, V686, V687, 0, 0,
+ }, // P[53]
+ {
+ V688, V689, V690, V691, V692, V693, V694, V695,
+ V696, V697, V698, V699, V700, V701, V702, V703,
+ V704, V705, V706, V707, V708, V709, V710, V711,
+ V712, V713, V714, V715, V716, V717, V718, V719,
+ }, // P[54]
+ {
+ V720, V721, V722, V723, V724, V725, 0, 0,
+ V726, V727, V728, V729, V730, V731, 0, 0,
+ V732, V733, V734, V735, V736, V737, V738, V739,
+ 0, V740, 0, V741, 0, V742, 0, V743,
+ }, // P[55]
+ {
+ V744, V745, V746, V747, V748, V749, V750, V751,
+ V752, V753, V754, V755, V756, V757, V758, V759,
+ V760, V270, V761, V271, V762, V272, V763, V273,
+ V764, V277, V765, V278, V766, V279, 0, 0,
+ }, // P[56]
+ {
+ V767, V768, V769, V770, V771, V772, V773, V774,
+ V775, V776, V777, V778, V779, V780, V781, V782,
+ V783, V784, V785, V786, V787, V788, V789, V790,
+ V791, V792, V793, V794, V795, V796, V797, V798,
+ }, // P[57]
+ {
+ V799, V800, V801, V802, V803, V804, V805, V806,
+ V807, V808, V809, V810, V811, V812, V813, V814,
+ V815, V816, V817, V818, V819, 0, V820, V821,
+ V822, V823, V824, V259, V825, 0, V826, 0,
+ }, // P[58]
+ {
+ 0, V827, V828, V829, V830, 0, V831, V832,
+ V833, V261, V834, V262, V835, V836, V837, V838,
+ V839, V840, V841, V267, 0, 0, V842, V843,
+ V844, V845, V846, V263, 0, V847, V848, V849,
+ }, // P[59]
+ {
+ V850, V851, V852, V274, V853, V854, V855, V856,
+ V857, V858, V859, V265, V860, V861, V258, V862,
+ 0, 0, V863, V864, V865, 0, V866, V867,
+ V868, V264, V869, V266, V870, V871, 0, 0,
+ }, // P[60]
+ {
+ V872, V873, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[61]
+ {
+ 0, 0, 0, 0, 0, 0, V874, 0,
+ 0, 0, V875, V5, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[62]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V876, V877, 0, 0, 0, 0,
+ }, // P[63]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, V878, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[64]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, V879, V880, V881,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[65]
+ {
+ 0, 0, 0, 0, V882, 0, 0, 0,
+ 0, V883, 0, 0, V884, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[66]
+ {
+ 0, 0, 0, 0, V885, 0, V886, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[67]
+ {
+ 0, V887, 0, 0, V888, 0, 0, V889,
+ 0, V890, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[68]
+ {
+ V891, 0, V892, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, V893, V894, V895,
+ V896, V897, 0, 0, V898, V899, 0, 0,
+ V900, V901, 0, 0, 0, 0, 0, 0,
+ }, // P[69]
+ {
+ V902, V903, 0, 0, V904, V905, 0, 0,
+ V906, V907, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[70]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V908, V909, V910, V911,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[71]
+ {
+ V912, V913, V914, V915, 0, 0, 0, 0,
+ 0, 0, V916, V917, V918, V919, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[72]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, V920, V921, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[73]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V922, 0, 0, 0,
+ }, // P[74]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V923, 0, V924, 0,
+ V925, 0, V926, 0, V927, 0, V928, 0,
+ V929, 0, V930, 0, V931, 0, V932, 0,
+ }, // P[75]
+ {
+ V933, 0, V934, 0, 0, V935, 0, V936,
+ 0, V937, 0, 0, 0, 0, 0, 0,
+ V938, V939, 0, V940, V941, 0, V942, V943,
+ 0, V944, V945, 0, V946, V947, 0, 0,
+ }, // P[76]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V948, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, V949, 0,
+ }, // P[77]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V950, 0, V951, 0,
+ V952, 0, V953, 0, V954, 0, V955, 0,
+ V956, 0, V957, 0, V958, 0, V959, 0,
+ }, // P[78]
+ {
+ V960, 0, V961, 0, 0, V962, 0, V963,
+ 0, V964, 0, 0, 0, 0, 0, 0,
+ V965, V966, 0, V967, V968, 0, V969, V970,
+ 0, V971, V972, 0, V973, V974, 0, 0,
+ }, // P[79]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V975, 0, 0, V976,
+ V977, V978, V979, 0, 0, 0, V980, 0,
+ }, // P[80]
+ {
+ V981, V982, V983, V984, V985, V986, V987, V988,
+ V989, V990, V991, V992, V993, V994, V995, V996,
+ V997, V998, V999, V1000, V1001, V1002, V1003, V1004,
+ V1005, V1006, V1007, V1008, V1009, V1010, V1011, V1012,
+ }, // P[81]
+ {
+ V1013, V1014, V1015, V1016, V1017, V1018, V1019, V1020,
+ V1021, V1022, V1023, V1024, V1025, V1026, V1027, V1028,
+ V1029, V1030, V1031, V1032, V1033, V1034, V1035, V1036,
+ V1037, V1038, V1039, V1040, V1041, V1042, V1043, V1044,
+ }, // P[82]
+ {
+ V1045, V1046, V1047, V1048, V1049, V1050, V1051, V1052,
+ V1053, V1054, V1055, V1056, V1057, V1058, V1059, V1060,
+ V1061, V1062, V1063, V1064, V1065, V1066, V1067, V1068,
+ V1069, V1070, V1071, V1072, V1073, V1074, V1075, V1076,
+ }, // P[83]
+ {
+ V1077, V1078, V1079, V1080, V1081, V1082, V1083, V1084,
+ V1085, V1086, V1087, V1088, V1089, V1090, V1091, V1092,
+ V1093, V1094, V1095, V1096, V1097, V1098, V1099, V1100,
+ V1101, V1102, V1103, V1104, V1105, V1106, V1107, V1108,
+ }, // P[84]
+ {
+ V1109, V1110, V1111, V1112, V1113, V1114, V1115, V1116,
+ V1117, V1118, V1119, V1120, V1121, V1122, V1123, V1124,
+ V1125, V1126, V1127, V1128, V1129, V1130, V1131, V1132,
+ V1133, V1134, V1135, V1136, V1137, V1138, V1139, V1140,
+ }, // P[85]
+ {
+ V1141, V1142, V1143, V1144, V1145, V1146, V1147, V1148,
+ V1149, V1150, V1151, V1152, V1153, V1154, V1155, V1156,
+ V1157, V1158, V1159, V1160, V1161, V1162, V1163, V1164,
+ V1165, V1166, V1167, V1168, V1169, V1170, V1171, V1172,
+ }, // P[86]
+ {
+ V1173, V1174, V1175, V1176, V1177, V1178, V1179, V1180,
+ V1181, V1182, V1183, V1184, V1185, V1186, V1187, V1188,
+ V1189, V1190, V1191, V1192, V1193, V1194, V1195, V1196,
+ V1197, V1198, V1199, V1200, V1201, V1202, V1203, V1204,
+ }, // P[87]
+ {
+ V1205, V1206, V1207, V1208, V1209, V1210, V1211, V1212,
+ V1213, V1214, V1215, V1216, V1217, V1218, V1219, V1220,
+ V1221, V1222, V1223, V1224, V1225, V1226, V1227, V1228,
+ V1229, V1230, V1231, V1232, V1233, V1234, V1235, V1236,
+ }, // P[88]
+ {
+ V1237, V1238, V1239, V1240, V1241, V1242, V1243, V1244,
+ V1245, V1246, V1247, V1248, V1249, V1250, V1251, V1252,
+ V1253, V1254, V1255, V1256, V1257, V1258, V1259, V1260,
+ V1261, V1262, V1263, V1264, V1265, V1266, V1267, V1268,
+ }, // P[89]
+ {
+ V1269, V1270, V1271, V1272, V1273, V1274, V1275, V1276,
+ V1277, V1278, V1279, V1280, V1281, V1282, V1283, V1284,
+ V1285, V1286, V1287, V1288, V1289, V1290, V1291, V1292,
+ V1293, V1294, V1295, V1296, V1297, V1298, V1299, V1300,
+ }, // P[90]
+ {
+ V1301, V1302, V1303, V1304, V1305, V1306, V1307, V1308,
+ V1309, V1310, V1311, V1312, V1313, V1314, V1315, V1316,
+ V1317, V1318, V1319, V1320, V1321, V1322, V1323, V1324,
+ V1325, V1326, V1327, V1328, V1329, V1330, V1331, V1332,
+ }, // P[91]
+ {
+ V1333, V1334, V1335, V1336, V1337, V1338, V1339, V1340,
+ V1341, V1342, V1343, V1344, V1345, V1346, V1347, V1348,
+ V1349, V1350, V1351, V1352, V1353, V1354, V1355, V1356,
+ V1357, V1358, V1359, V1360, V1361, V1362, V1363, V1364,
+ }, // P[92]
+ {
+ V1365, V1366, V1367, V1368, V1369, V1370, V1371, V1372,
+ V1373, V1374, V1375, V1376, V1377, V1378, V1379, V1380,
+ V1381, V1382, V1383, V1384, V1385, V1386, V1387, V1388,
+ V1389, V1390, V1391, V1392, V1393, V1394, V1395, V1396,
+ }, // P[93]
+ {
+ V1397, V1398, V1399, V1400, V1401, V1402, V1403, V1404,
+ V1405, V1406, V1407, V1408, V1409, V1410, V1411, V1412,
+ V1413, V1414, V1415, V1416, V1417, V1418, V1419, V1420,
+ V1421, V1422, V1423, V1424, V1425, V1426, V1427, V1428,
+ }, // P[94]
+ {
+ V1429, V1430, V1431, V1432, V1433, V1434, V1435, V1436,
+ V1437, V1438, V1439, V1440, V1441, V1442, V1443, V1444,
+ V1445, V1446, V1447, V1448, V1449, V1450, V1451, V1452,
+ V1453, V1454, V1455, V1456, V1457, V1458, V1459, V1460,
+ }, // P[95]
+ {
+ V1461, V1462, V1463, V1464, V1465, V1466, V1467, V1468,
+ V1469, V1470, V1471, V1472, V1473, V1474, V1475, V1476,
+ V1477, V1478, V1479, V1480, V1481, V1482, V1483, V1484,
+ V1485, V1486, V1487, V1488, V1489, V1490, V1491, V1492,
+ }, // P[96]
+ {
+ V1493, V1494, V1495, V1496, V1497, V1498, V1499, V1500,
+ V1501, V1502, V1503, V1504, V1505, V1506, V1507, V1508,
+ V1509, V1510, V1511, V1512, V1513, V1514, V1515, V1516,
+ V1517, V1518, V1519, V1520, V1521, V1522, V1523, V1524,
+ }, // P[97]
+ {
+ V1525, V1526, V1527, V1528, V1529, V1530, V1531, V1532,
+ V1533, V1534, V1535, V1536, V1537, V1538, V1539, V1540,
+ V1541, V1542, V1543, V1544, V1545, V1546, V1547, V1548,
+ V1549, V1550, V1551, V1552, V1553, V1554, V1555, V1556,
+ }, // P[98]
+ {
+ V1557, V1558, V1559, V1560, V1561, V1562, V1563, V1564,
+ V1565, V1566, V1567, V1568, V1569, V1570, V1571, V1572,
+ V1573, V1574, V1575, V1576, V1577, V1578, V1579, V1580,
+ V1581, V1582, V1583, V1584, V1585, V1586, V1587, V1588,
+ }, // P[99]
+ {
+ V1589, V1590, V1591, V1592, V1593, V1594, V1595, V1596,
+ V1597, V1598, V1599, V1600, V1601, V1602, V1603, V1604,
+ V1605, V1606, V1607, V1608, V1609, V1610, V1611, V1612,
+ V1613, V1614, V1615, V1616, V1617, V1618, V1619, V1620,
+ }, // P[100]
+ {
+ V1621, V1622, V1623, V1624, V1625, V1626, V1627, V1628,
+ V1629, V1630, V1631, V1632, V1633, V1634, V1635, V1636,
+ V1637, V1638, V1639, V1640, V1641, V1642, V1643, V1644,
+ V1645, V1646, V1647, V1648, V1649, V1650, V1651, V1652,
+ }, // P[101]
+ {
+ V1653, V1654, V1655, V1656, V1657, V1658, V1659, V1660,
+ V1661, V1662, V1663, V1664, V1665, V1666, V1667, V1668,
+ V1669, V1670, V1671, V1672, V1673, V1674, V1675, V1676,
+ V1677, V1678, V1679, V1680, V1681, V1682, V1683, V1684,
+ }, // P[102]
+ {
+ V1685, V1686, V1687, V1688, V1689, V1690, V1691, V1692,
+ V1693, V1694, V1695, V1696, V1697, V1698, V1699, V1700,
+ V1701, V1702, V1703, V1704, V1705, V1706, V1707, V1708,
+ V1709, V1710, V1711, V1712, V1713, V1714, V1715, V1716,
+ }, // P[103]
+ {
+ V1717, V1718, V1719, V1720, V1721, V1722, V1723, V1724,
+ V1725, V1726, V1727, V1728, V1729, V1730, V1731, V1732,
+ V1733, V1734, V1735, V1736, V1737, V1738, V1739, V1740,
+ V1741, V1742, V1743, V1744, V1745, V1746, V1747, V1748,
+ }, // P[104]
+ {
+ V1749, V1750, V1751, V1752, V1753, V1754, V1755, V1756,
+ V1757, V1758, V1759, V1760, V1761, V1762, V1763, V1764,
+ V1765, V1766, V1767, V1768, V1769, V1770, V1771, V1772,
+ V1773, V1774, V1775, V1776, V1777, V1778, V1779, V1780,
+ }, // P[105]
+ {
+ V1781, V1782, V1783, V1784, V1785, V1786, V1787, V1788,
+ V1789, V1790, V1791, V1792, V1793, V1794, V1795, V1796,
+ V1797, V1798, V1799, V1800, V1801, V1802, V1803, V1804,
+ V1805, V1806, V1807, V1808, V1809, V1810, V1811, V1812,
+ }, // P[106]
+ {
+ V1813, V1814, V1815, V1816, V1817, V1818, V1819, V1820,
+ V1821, V1822, V1823, V1824, V1825, V1826, V1827, V1828,
+ V1829, V1830, V1831, V1832, V1833, V1834, V1835, V1836,
+ V1837, V1838, V1839, V1840, V1841, V1842, V1843, V1844,
+ }, // P[107]
+ {
+ V1845, V1846, V1847, V1848, V1849, V1850, V1851, V1852,
+ V1853, V1854, V1855, V1856, V1857, V1858, V1859, V1860,
+ V1861, V1862, V1863, V1864, V1865, V1866, V1867, V1868,
+ V1869, V1870, V1871, V1872, V1873, V1874, V1875, V1876,
+ }, // P[108]
+ {
+ V1877, V1878, V1879, V1880, V1881, V1882, V1883, V1884,
+ V1885, V1886, V1887, V1888, V1889, V1890, V1891, V1892,
+ V1893, V1894, V1895, V1896, V1897, V1898, V1899, V1900,
+ V1901, V1902, V1903, V1904, V1905, V1906, V1907, V1908,
+ }, // P[109]
+ {
+ V1909, V1910, V1911, V1912, V1913, V1914, V1915, V1916,
+ V1917, V1918, V1919, V1920, V1921, V1922, V1923, V1924,
+ V1925, V1926, V1927, V1928, V1929, V1930, V1931, V1932,
+ V1933, V1934, V1935, V1936, V1937, V1938, V1939, V1940,
+ }, // P[110]
+ {
+ V1941, V1942, V1943, V1944, V1945, V1946, V1947, V1948,
+ V1949, V1950, V1951, V1952, V1953, V1954, V1955, V1956,
+ V1957, V1958, V1959, V1960, V1961, V1962, V1963, V1964,
+ V1965, V1966, V1967, V1968, V1969, V1970, V1971, V1972,
+ }, // P[111]
+ {
+ V1973, V1974, V1975, V1976, V1977, V1978, V1979, V1980,
+ V1981, V1982, V1983, V1984, V1985, V1986, V1987, V1988,
+ V1989, V1990, V1991, V1992, V1993, V1994, V1995, V1996,
+ V1997, V1998, V1999, V2000, V2001, V2002, V2003, V2004,
+ }, // P[112]
+ {
+ V2005, V2006, V2007, V2008, V2009, V2010, V2011, V2012,
+ V2013, V2014, V2015, V2016, V2017, V2018, V2019, V2020,
+ V2021, V2022, V2023, V2024, V2025, V2026, V2027, V2028,
+ V2029, V2030, V2031, V2032, V2033, V2034, V2035, V2036,
+ }, // P[113]
+ {
+ V2037, V2038, V2039, V2040, V2041, V2042, V2043, V2044,
+ V2045, V2046, V2047, V2048, V2049, V2050, V2051, V2052,
+ V2053, V2054, V2055, V2056, V2057, V2058, V2059, V2060,
+ V2061, V2062, V2063, V2064, V2065, V2066, V2067, V2068,
+ }, // P[114]
+ {
+ V2069, V2070, V2071, V2072, V2073, V2074, V2075, V2076,
+ V2077, V2078, V2079, V2080, V2081, V2082, V2083, V2084,
+ V2085, V2086, V2087, V2088, V2089, V2090, V2091, V2092,
+ V2093, V2094, V2095, V2096, V2097, V2098, V2099, V2100,
+ }, // P[115]
+ {
+ V2101, V2102, V2103, V2104, V2105, V2106, V2107, V2108,
+ V2109, V2110, V2111, V2112, V2113, V2114, V2115, V2116,
+ V2117, V2118, V2119, V2120, V2121, V2122, V2123, V2124,
+ V2125, V2126, V2127, V2128, V2129, V2130, V2131, V2132,
+ }, // P[116]
+ {
+ V2133, V2134, V2135, V2136, V2137, V2138, V2139, V2140,
+ V2141, V2142, V2143, V2144, V2145, V2146, V2147, V2148,
+ V2149, V2150, V2151, V2152, V2153, V2154, V2155, V2156,
+ V2157, V2158, V2159, V2160, V2161, V2162, V2163, V2164,
+ }, // P[117]
+ {
+ V2165, V2166, V2167, V2168, V2169, V2170, V2171, V2172,
+ V2173, V2174, V2175, V2176, V2177, V2178, V2179, V2180,
+ V2181, V2182, V2183, V2184, V2185, V2186, V2187, V2188,
+ V2189, V2190, V2191, V2192, V2193, V2194, V2195, V2196,
+ }, // P[118]
+ {
+ V2197, V2198, V2199, V2200, V2201, V2202, V2203, V2204,
+ V2205, V2206, V2207, V2208, V2209, V2210, V2211, V2212,
+ V2213, V2214, V2215, V2216, V2217, V2218, V2219, V2220,
+ V2221, V2222, V2223, V2224, V2225, V2226, V2227, V2228,
+ }, // P[119]
+ {
+ V2229, V2230, V2231, V2232, V2233, V2234, V2235, V2236,
+ V2237, V2238, V2239, V2240, V2241, V2242, V2243, V2244,
+ V2245, V2246, V2247, V2248, V2249, V2250, V2251, V2252,
+ V2253, V2254, V2255, V2256, V2257, V2258, V2259, V2260,
+ }, // P[120]
+ {
+ V2261, V2262, V2263, V2264, V2265, V2266, V2267, V2268,
+ V2269, V2270, V2271, V2272, V2273, V2274, V2275, V2276,
+ V2277, V2278, V2279, V2280, V2281, V2282, V2283, V2284,
+ V2285, V2286, V2287, V2288, V2289, V2290, V2291, V2292,
+ }, // P[121]
+ {
+ V2293, V2294, V2295, V2296, V2297, V2298, V2299, V2300,
+ V2301, V2302, V2303, V2304, V2305, V2306, V2307, V2308,
+ V2309, V2310, V2311, V2312, V2313, V2314, V2315, V2316,
+ V2317, V2318, V2319, V2320, V2321, V2322, V2323, V2324,
+ }, // P[122]
+ {
+ V2325, V2326, V2327, V2328, V2329, V2330, V2331, V2332,
+ V2333, V2334, V2335, V2336, V2337, V2338, V2339, V2340,
+ V2341, V2342, V2343, V2344, V2345, V2346, V2347, V2348,
+ V2349, V2350, V2351, V2352, V2353, V2354, V2355, V2356,
+ }, // P[123]
+ {
+ V2357, V2358, V2359, V2360, V2361, V2362, V2363, V2364,
+ V2365, V2366, V2367, V2368, V2369, V2370, V2371, V2372,
+ V2373, V2374, V2375, V2376, V2377, V2378, V2379, V2380,
+ V2381, V2382, V2383, V2384, V2385, V2386, V2387, V2388,
+ }, // P[124]
+ {
+ V2389, V2390, V2391, V2392, V2393, V2394, V2395, V2396,
+ V2397, V2398, V2399, V2400, V2401, V2402, V2403, V2404,
+ V2405, V2406, V2407, V2408, V2409, V2410, V2411, V2412,
+ V2413, V2414, V2415, V2416, V2417, V2418, V2419, V2420,
+ }, // P[125]
+ {
+ V2421, V2422, V2423, V2424, V2425, V2426, V2427, V2428,
+ V2429, V2430, V2431, V2432, V2433, V2434, V2435, V2436,
+ V2437, V2438, V2439, V2440, V2441, V2442, V2443, V2444,
+ V2445, V2446, V2447, V2448, V2449, V2450, V2451, V2452,
+ }, // P[126]
+ {
+ V2453, V2454, V2455, V2456, V2457, V2458, V2459, V2460,
+ V2461, V2462, V2463, V2464, V2465, V2466, V2467, V2468,
+ V2469, V2470, V2471, V2472, V2473, V2474, V2475, V2476,
+ V2477, V2478, V2479, V2480, V2481, V2482, V2483, V2484,
+ }, // P[127]
+ {
+ V2485, V2486, V2487, V2488, V2489, V2490, V2491, V2492,
+ V2493, V2494, V2495, V2496, V2497, V2498, V2499, V2500,
+ V2501, V2502, V2503, V2504, V2505, V2506, V2507, V2508,
+ V2509, V2510, V2511, V2512, V2513, V2514, V2515, V2516,
+ }, // P[128]
+ {
+ V2517, V2518, V2519, V2520, V2521, V2522, V2523, V2524,
+ V2525, V2526, V2527, V2528, V2529, V2530, V2531, V2532,
+ V2533, V2534, V2535, V2536, V2537, V2538, V2539, V2540,
+ V2541, V2542, V2543, V2544, V2545, V2546, V2547, V2548,
+ }, // P[129]
+ {
+ V2549, V2550, V2551, V2552, V2553, V2554, V2555, V2556,
+ V2557, V2558, V2559, V2560, V2561, V2562, V2563, V2564,
+ V2565, V2566, V2567, V2568, V2569, V2570, V2571, V2572,
+ V2573, V2574, V2575, V2576, V2577, V2578, V2579, V2580,
+ }, // P[130]
+ {
+ V2581, V2582, V2583, V2584, V2585, V2586, V2587, V2588,
+ V2589, V2590, V2591, V2592, V2593, V2594, V2595, V2596,
+ V2597, V2598, V2599, V2600, V2601, V2602, V2603, V2604,
+ V2605, V2606, V2607, V2608, V2609, V2610, V2611, V2612,
+ }, // P[131]
+ {
+ V2613, V2614, V2615, V2616, V2617, V2618, V2619, V2620,
+ V2621, V2622, V2623, V2624, V2625, V2626, V2627, V2628,
+ V2629, V2630, V2631, V2632, V2633, V2634, V2635, V2636,
+ V2637, V2638, V2639, V2640, V2641, V2642, V2643, V2644,
+ }, // P[132]
+ {
+ V2645, V2646, V2647, V2648, V2649, V2650, V2651, V2652,
+ V2653, V2654, V2655, V2656, V2657, V2658, V2659, V2660,
+ V2661, V2662, V2663, V2664, V2665, V2666, V2667, V2668,
+ V2669, V2670, V2671, V2672, V2673, V2674, V2675, V2676,
+ }, // P[133]
+ {
+ V2677, V2678, V2679, V2680, V2681, V2682, V2683, V2684,
+ V2685, V2686, V2687, V2688, V2689, V2690, V2691, V2692,
+ V2693, V2694, V2695, V2696, V2697, V2698, V2699, V2700,
+ V2701, V2702, V2703, V2704, V2705, V2706, V2707, V2708,
+ }, // P[134]
+ {
+ V2709, V2710, V2711, V2712, V2713, V2714, V2715, V2716,
+ V2717, V2718, V2719, V2720, V2721, V2722, V2723, V2724,
+ V2725, V2726, V2727, V2728, V2729, V2730, V2731, V2732,
+ V2733, V2734, V2735, V2736, V2737, V2738, V2739, V2740,
+ }, // P[135]
+ {
+ V2741, V2742, V2743, V2744, V2745, V2746, V2747, V2748,
+ V2749, V2750, V2751, V2752, V2753, V2754, V2755, V2756,
+ V2757, V2758, V2759, V2760, V2761, V2762, V2763, V2764,
+ V2765, V2766, V2767, V2768, V2769, V2770, V2771, V2772,
+ }, // P[136]
+ {
+ V2773, V2774, V2775, V2776, V2777, V2778, V2779, V2780,
+ V2781, V2782, V2783, V2784, V2785, V2786, V2787, V2788,
+ V2789, V2790, V2791, V2792, V2793, V2794, V2795, V2796,
+ V2797, V2798, V2799, V2800, V2801, V2802, V2803, V2804,
+ }, // P[137]
+ {
+ V2805, V2806, V2807, V2808, V2809, V2810, V2811, V2812,
+ V2813, V2814, V2815, V2816, V2817, V2818, V2819, V2820,
+ V2821, V2822, V2823, V2824, V2825, V2826, V2827, V2828,
+ V2829, V2830, V2831, V2832, V2833, V2834, V2835, V2836,
+ }, // P[138]
+ {
+ V2837, V2838, V2839, V2840, V2841, V2842, V2843, V2844,
+ V2845, V2846, V2847, V2848, V2849, V2850, V2851, V2852,
+ V2853, V2854, V2855, V2856, V2857, V2858, V2859, V2860,
+ V2861, V2862, V2863, V2864, V2865, V2866, V2867, V2868,
+ }, // P[139]
+ {
+ V2869, V2870, V2871, V2872, V2873, V2874, V2875, V2876,
+ V2877, V2878, V2879, V2880, V2881, V2882, V2883, V2884,
+ V2885, V2886, V2887, V2888, V2889, V2890, V2891, V2892,
+ V2893, V2894, V2895, V2896, V2897, V2898, V2899, V2900,
+ }, // P[140]
+ {
+ V2901, V2902, V2903, V2904, V2905, V2906, V2907, V2908,
+ V2909, V2910, V2911, V2912, V2913, V2914, V2915, V2916,
+ V2917, V2918, V2919, V2920, V2921, V2922, V2923, V2924,
+ V2925, V2926, V2927, V2928, V2929, V2930, V2931, V2932,
+ }, // P[141]
+ {
+ V2933, V2934, V2935, V2936, V2937, V2938, V2939, V2940,
+ V2941, V2942, V2943, V2944, V2945, V2946, V2947, V2948,
+ V2949, V2950, V2951, V2952, V2953, V2954, V2955, V2956,
+ V2957, V2958, V2959, V2960, V2961, V2962, V2963, V2964,
+ }, // P[142]
+ {
+ V2965, V2966, V2967, V2968, V2969, V2970, V2971, V2972,
+ V2973, V2974, V2975, V2976, V2977, V2978, V2979, V2980,
+ V2981, V2982, V2983, V2984, V2985, V2986, V2987, V2988,
+ V2989, V2990, V2991, V2992, V2993, V2994, V2995, V2996,
+ }, // P[143]
+ {
+ V2997, V2998, V2999, V3000, V3001, V3002, V3003, V3004,
+ V3005, V3006, V3007, V3008, V3009, V3010, V3011, V3012,
+ V3013, V3014, V3015, V3016, V3017, V3018, V3019, V3020,
+ V3021, V3022, V3023, V3024, V3025, V3026, V3027, V3028,
+ }, // P[144]
+ {
+ V3029, V3030, V3031, V3032, V3033, V3034, V3035, V3036,
+ V3037, V3038, V3039, V3040, V3041, V3042, V3043, V3044,
+ V3045, V3046, V3047, V3048, V3049, V3050, V3051, V3052,
+ V3053, V3054, V3055, V3056, V3057, V3058, V3059, V3060,
+ }, // P[145]
+ {
+ V3061, V3062, V3063, V3064, V3065, V3066, V3067, V3068,
+ V3069, V3070, V3071, V3072, V3073, V3074, V3075, V3076,
+ V3077, V3078, V3079, V3080, V3081, V3082, V3083, V3084,
+ V3085, V3086, V3087, V3088, V3089, V3090, V3091, V3092,
+ }, // P[146]
+ {
+ V3093, V3094, V3095, V3096, V3097, V3098, V3099, V3100,
+ V3101, V3102, V3103, V3104, V3105, V3106, V3107, V3108,
+ V3109, V3110, V3111, V3112, V3113, V3114, V3115, V3116,
+ V3117, V3118, V3119, V3120, V3121, V3122, V3123, V3124,
+ }, // P[147]
+ {
+ V3125, V3126, V3127, V3128, V3129, V3130, V3131, V3132,
+ V3133, V3134, V3135, V3136, V3137, V3138, V3139, V3140,
+ V3141, V3142, V3143, V3144, V3145, V3146, V3147, V3148,
+ V3149, V3150, V3151, V3152, V3153, V3154, V3155, V3156,
+ }, // P[148]
+ {
+ V3157, V3158, V3159, V3160, V3161, V3162, V3163, V3164,
+ V3165, V3166, V3167, V3168, V3169, V3170, V3171, V3172,
+ V3173, V3174, V3175, V3176, V3177, V3178, V3179, V3180,
+ V3181, V3182, V3183, V3184, V3185, V3186, V3187, V3188,
+ }, // P[149]
+ {
+ V3189, V3190, V3191, V3192, V3193, V3194, V3195, V3196,
+ V3197, V3198, V3199, V3200, V3201, V3202, V3203, V3204,
+ V3205, V3206, V3207, V3208, V3209, V3210, V3211, V3212,
+ V3213, V3214, V3215, V3216, V3217, V3218, V3219, V3220,
+ }, // P[150]
+ {
+ V3221, V3222, V3223, V3224, V3225, V3226, V3227, V3228,
+ V3229, V3230, V3231, V3232, V3233, V3234, V3235, V3236,
+ V3237, V3238, V3239, V3240, V3241, V3242, V3243, V3244,
+ V3245, V3246, V3247, V3248, V3249, V3250, V3251, V3252,
+ }, // P[151]
+ {
+ V3253, V3254, V3255, V3256, V3257, V3258, V3259, V3260,
+ V3261, V3262, V3263, V3264, V3265, V3266, V3267, V3268,
+ V3269, V3270, V3271, V3272, V3273, V3274, V3275, V3276,
+ V3277, V3278, V3279, V3280, V3281, V3282, V3283, V3284,
+ }, // P[152]
+ {
+ V3285, V3286, V3287, V3288, V3289, V3290, V3291, V3292,
+ V3293, V3294, V3295, V3296, V3297, V3298, V3299, V3300,
+ V3301, V3302, V3303, V3304, V3305, V3306, V3307, V3308,
+ V3309, V3310, V3311, V3312, V3313, V3314, V3315, V3316,
+ }, // P[153]
+ {
+ V3317, V3318, V3319, V3320, V3321, V3322, V3323, V3324,
+ V3325, V3326, V3327, V3328, V3329, V3330, V3331, V3332,
+ V3333, V3334, V3335, V3336, V3337, V3338, V3339, V3340,
+ V3341, V3342, V3343, V3344, V3345, V3346, V3347, V3348,
+ }, // P[154]
+ {
+ V3349, V3350, V3351, V3352, V3353, V3354, V3355, V3356,
+ V3357, V3358, V3359, V3360, V3361, V3362, V3363, V3364,
+ V3365, V3366, V3367, V3368, V3369, V3370, V3371, V3372,
+ V3373, V3374, V3375, V3376, V3377, V3378, V3379, V3380,
+ }, // P[155]
+ {
+ V3381, V3382, V3383, V3384, V3385, V3386, V3387, V3388,
+ V3389, V3390, V3391, V3392, V3393, V3394, V3395, V3396,
+ V3397, V3398, V3399, V3400, V3401, V3402, V3403, V3404,
+ V3405, V3406, V3407, V3408, V3409, V3410, V3411, V3412,
+ }, // P[156]
+ {
+ V3413, V3414, V3415, V3416, V3417, V3418, V3419, V3420,
+ V3421, V3422, V3423, V3424, V3425, V3426, V3427, V3428,
+ V3429, V3430, V3431, V3432, V3433, V3434, V3435, V3436,
+ V3437, V3438, V3439, V3440, V3441, V3442, V3443, V3444,
+ }, // P[157]
+ {
+ V3445, V3446, V3447, V3448, V3449, V3450, V3451, V3452,
+ V3453, V3454, V3455, V3456, V3457, V3458, V3459, V3460,
+ V3461, V3462, V3463, V3464, V3465, V3466, V3467, V3468,
+ V3469, V3470, V3471, V3472, V3473, V3474, V3475, V3476,
+ }, // P[158]
+ {
+ V3477, V3478, V3479, V3480, V3481, V3482, V3483, V3484,
+ V3485, V3486, V3487, V3488, V3489, V3490, V3491, V3492,
+ V3493, V3494, V3495, V3496, V3497, V3498, V3499, V3500,
+ V3501, V3502, V3503, V3504, V3505, V3506, V3507, V3508,
+ }, // P[159]
+ {
+ V3509, V3510, V3511, V3512, V3513, V3514, V3515, V3516,
+ V3517, V3518, V3519, V3520, V3521, V3522, V3523, V3524,
+ V3525, V3526, V3527, V3528, V3529, V3530, V3531, V3532,
+ V3533, V3534, V3535, V3536, V3537, V3538, V3539, V3540,
+ }, // P[160]
+ {
+ V3541, V3542, V3543, V3544, V3545, V3546, V3547, V3548,
+ V3549, V3550, V3551, V3552, V3553, V3554, V3555, V3556,
+ V3557, V3558, V3559, V3560, V3561, V3562, V3563, V3564,
+ V3565, V3566, V3567, V3568, V3569, V3570, V3571, V3572,
+ }, // P[161]
+ {
+ V3573, V3574, V3575, V3576, V3577, V3578, V3579, V3580,
+ V3581, V3582, V3583, V3584, V3585, V3586, V3587, V3588,
+ V3589, V3590, V3591, V3592, V3593, V3594, V3595, V3596,
+ V3597, V3598, V3599, V3600, V3601, V3602, V3603, V3604,
+ }, // P[162]
+ {
+ V3605, V3606, V3607, V3608, V3609, V3610, V3611, V3612,
+ V3613, V3614, V3615, V3616, V3617, V3618, V3619, V3620,
+ V3621, V3622, V3623, V3624, V3625, V3626, V3627, V3628,
+ V3629, V3630, V3631, V3632, V3633, V3634, V3635, V3636,
+ }, // P[163]
+ {
+ V3637, V3638, V3639, V3640, V3641, V3642, V3643, V3644,
+ V3645, V3646, V3647, V3648, V3649, V3650, V3651, V3652,
+ V3653, V3654, V3655, V3656, V3657, V3658, V3659, V3660,
+ V3661, V3662, V3663, V3664, V3665, V3666, V3667, V3668,
+ }, // P[164]
+ {
+ V3669, V3670, V3671, V3672, V3673, V3674, V3675, V3676,
+ V3677, V3678, V3679, V3680, V3681, V3682, V3683, V3684,
+ V3685, V3686, V3687, V3688, V3689, V3690, V3691, V3692,
+ V3693, V3694, V3695, V3696, V3697, V3698, V3699, V3700,
+ }, // P[165]
+ {
+ V3701, V3702, V3703, V3704, V3705, V3706, V3707, V3708,
+ V3709, V3710, V3711, V3712, V3713, V3714, V3715, V3716,
+ V3717, V3718, V3719, V3720, V3721, V3722, V3723, V3724,
+ V3725, V3726, V3727, V3728, V3729, V3730, V3731, V3732,
+ }, // P[166]
+ {
+ V3733, V3734, V3735, V3736, V3737, V3738, V3739, V3740,
+ V3741, V3742, V3743, V3744, V3745, V3746, V3747, V3748,
+ V3749, V3750, V3751, V3752, V3753, V3754, V3755, V3756,
+ V3757, V3758, V3759, V3760, V3761, V3762, V3763, V3764,
+ }, // P[167]
+ {
+ V3765, V3766, V3767, V3768, V3769, V3770, V3771, V3772,
+ V3773, V3774, V3775, V3776, V3777, V3778, V3779, V3780,
+ V3781, V3782, V3783, V3784, V3785, V3786, V3787, V3788,
+ V3789, V3790, V3791, V3792, V3793, V3794, V3795, V3796,
+ }, // P[168]
+ {
+ V3797, V3798, V3799, V3800, V3801, V3802, V3803, V3804,
+ V3805, V3806, V3807, V3808, V3809, V3810, V3811, V3812,
+ V3813, V3814, V3815, V3816, V3817, V3818, V3819, V3820,
+ V3821, V3822, V3823, V3824, V3825, V3826, V3827, V3828,
+ }, // P[169]
+ {
+ V3829, V3830, V3831, V3832, V3833, V3834, V3835, V3836,
+ V3837, V3838, V3839, V3840, V3841, V3842, V3843, V3844,
+ V3845, V3846, V3847, V3848, V3849, V3850, V3851, V3852,
+ V3853, V3854, V3855, V3856, V3857, V3858, V3859, V3860,
+ }, // P[170]
+ {
+ V3861, V3862, V3863, V3864, V3865, V3866, V3867, V3868,
+ V3869, V3870, V3871, V3872, V3873, V3874, V3875, V3876,
+ V3877, V3878, V3879, V3880, V3881, V3882, V3883, V3884,
+ V3885, V3886, V3887, V3888, V3889, V3890, V3891, V3892,
+ }, // P[171]
+ {
+ V3893, V3894, V3895, V3896, V3897, V3898, V3899, V3900,
+ V3901, V3902, V3903, V3904, V3905, V3906, V3907, V3908,
+ V3909, V3910, V3911, V3912, V3913, V3914, V3915, V3916,
+ V3917, V3918, V3919, V3920, V3921, V3922, V3923, V3924,
+ }, // P[172]
+ {
+ V3925, V3926, V3927, V3928, V3929, V3930, V3931, V3932,
+ V3933, V3934, V3935, V3936, V3937, V3938, V3939, V3940,
+ V3941, V3942, V3943, V3944, V3945, V3946, V3947, V3948,
+ V3949, V3950, V3951, V3952, V3953, V3954, V3955, V3956,
+ }, // P[173]
+ {
+ V3957, V3958, V3959, V3960, V3961, V3962, V3963, V3964,
+ V3965, V3966, V3967, V3968, V3969, V3970, V3971, V3972,
+ V3973, V3974, V3975, V3976, V3977, V3978, V3979, V3980,
+ V3981, V3982, V3983, V3984, V3985, V3986, V3987, V3988,
+ }, // P[174]
+ {
+ V3989, V3990, V3991, V3992, V3993, V3994, V3995, V3996,
+ V3997, V3998, V3999, V4000, V4001, V4002, V4003, V4004,
+ V4005, V4006, V4007, V4008, V4009, V4010, V4011, V4012,
+ V4013, V4014, V4015, V4016, V4017, V4018, V4019, V4020,
+ }, // P[175]
+ {
+ V4021, V4022, V4023, V4024, V4025, V4026, V4027, V4028,
+ V4029, V4030, V4031, V4032, V4033, V4034, V4035, V4036,
+ V4037, V4038, V4039, V4040, V4041, V4042, V4043, V4044,
+ V4045, V4046, V4047, V4048, V4049, V4050, V4051, V4052,
+ }, // P[176]
+ {
+ V4053, V4054, V4055, V4056, V4057, V4058, V4059, V4060,
+ V4061, V4062, V4063, V4064, V4065, V4066, V4067, V4068,
+ V4069, V4070, V4071, V4072, V4073, V4074, V4075, V4076,
+ V4077, V4078, V4079, V4080, V4081, V4082, V4083, V4084,
+ }, // P[177]
+ {
+ V4085, V4086, V4087, V4088, V4089, V4090, V4091, V4092,
+ V4093, V4094, V4095, V4096, V4097, V4098, V4099, V4100,
+ V4101, V4102, V4103, V4104, V4105, V4106, V4107, V4108,
+ V4109, V4110, V4111, V4112, V4113, V4114, V4115, V4116,
+ }, // P[178]
+ {
+ V4117, V4118, V4119, V4120, V4121, V4122, V4123, V4124,
+ V4125, V4126, V4127, V4128, V4129, V4130, V4131, V4132,
+ V4133, V4134, V4135, V4136, V4137, V4138, V4139, V4140,
+ V4141, V4142, V4143, V4144, V4145, V4146, V4147, V4148,
+ }, // P[179]
+ {
+ V4149, V4150, V4151, V4152, V4153, V4154, V4155, V4156,
+ V4157, V4158, V4159, V4160, V4161, V4162, V4163, V4164,
+ V4165, V4166, V4167, V4168, V4169, V4170, V4171, V4172,
+ V4173, V4174, V4175, V4176, V4177, V4178, V4179, V4180,
+ }, // P[180]
+ {
+ V4181, V4182, V4183, V4184, V4185, V4186, V4187, V4188,
+ V4189, V4190, V4191, V4192, V4193, V4194, V4195, V4196,
+ V4197, V4198, V4199, V4200, V4201, V4202, V4203, V4204,
+ V4205, V4206, V4207, V4208, V4209, V4210, V4211, V4212,
+ }, // P[181]
+ {
+ V4213, V4214, V4215, V4216, V4217, V4218, V4219, V4220,
+ V4221, V4222, V4223, V4224, V4225, V4226, V4227, V4228,
+ V4229, V4230, V4231, V4232, V4233, V4234, V4235, V4236,
+ V4237, V4238, V4239, V4240, V4241, V4242, V4243, V4244,
+ }, // P[182]
+ {
+ V4245, V4246, V4247, V4248, V4249, V4250, V4251, V4252,
+ V4253, V4254, V4255, V4256, V4257, V4258, V4259, V4260,
+ V4261, V4262, V4263, V4264, V4265, V4266, V4267, V4268,
+ V4269, V4270, V4271, V4272, V4273, V4274, V4275, V4276,
+ }, // P[183]
+ {
+ V4277, V4278, V4279, V4280, V4281, V4282, V4283, V4284,
+ V4285, V4286, V4287, V4288, V4289, V4290, V4291, V4292,
+ V4293, V4294, V4295, V4296, V4297, V4298, V4299, V4300,
+ V4301, V4302, V4303, V4304, V4305, V4306, V4307, V4308,
+ }, // P[184]
+ {
+ V4309, V4310, V4311, V4312, V4313, V4314, V4315, V4316,
+ V4317, V4318, V4319, V4320, V4321, V4322, V4323, V4324,
+ V4325, V4326, V4327, V4328, V4329, V4330, V4331, V4332,
+ V4333, V4334, V4335, V4336, V4337, V4338, V4339, V4340,
+ }, // P[185]
+ {
+ V4341, V4342, V4343, V4344, V4345, V4346, V4347, V4348,
+ V4349, V4350, V4351, V4352, V4353, V4354, V4355, V4356,
+ V4357, V4358, V4359, V4360, V4361, V4362, V4363, V4364,
+ V4365, V4366, V4367, V4368, V4369, V4370, V4371, V4372,
+ }, // P[186]
+ {
+ V4373, V4374, V4375, V4376, V4377, V4378, V4379, V4380,
+ V4381, V4382, V4383, V4384, V4385, V4386, V4387, V4388,
+ V4389, V4390, V4391, V4392, V4393, V4394, V4395, V4396,
+ V4397, V4398, V4399, V4400, V4401, V4402, V4403, V4404,
+ }, // P[187]
+ {
+ V4405, V4406, V4407, V4408, V4409, V4410, V4411, V4412,
+ V4413, V4414, V4415, V4416, V4417, V4418, V4419, V4420,
+ V4421, V4422, V4423, V4424, V4425, V4426, V4427, V4428,
+ V4429, V4430, V4431, V4432, V4433, V4434, V4435, V4436,
+ }, // P[188]
+ {
+ V4437, V4438, V4439, V4440, V4441, V4442, V4443, V4444,
+ V4445, V4446, V4447, V4448, V4449, V4450, V4451, V4452,
+ V4453, V4454, V4455, V4456, V4457, V4458, V4459, V4460,
+ V4461, V4462, V4463, V4464, V4465, V4466, V4467, V4468,
+ }, // P[189]
+ {
+ V4469, V4470, V4471, V4472, V4473, V4474, V4475, V4476,
+ V4477, V4478, V4479, V4480, V4481, V4482, V4483, V4484,
+ V4485, V4486, V4487, V4488, V4489, V4490, V4491, V4492,
+ V4493, V4494, V4495, V4496, V4497, V4498, V4499, V4500,
+ }, // P[190]
+ {
+ V4501, V4502, V4503, V4504, V4505, V4506, V4507, V4508,
+ V4509, V4510, V4511, V4512, V4513, V4514, V4515, V4516,
+ V4517, V4518, V4519, V4520, V4521, V4522, V4523, V4524,
+ V4525, V4526, V4527, V4528, V4529, V4530, V4531, V4532,
+ }, // P[191]
+ {
+ V4533, V4534, V4535, V4536, V4537, V4538, V4539, V4540,
+ V4541, V4542, V4543, V4544, V4545, V4546, V4547, V4548,
+ V4549, V4550, V4551, V4552, V4553, V4554, V4555, V4556,
+ V4557, V4558, V4559, V4560, V4561, V4562, V4563, V4564,
+ }, // P[192]
+ {
+ V4565, V4566, V4567, V4568, V4569, V4570, V4571, V4572,
+ V4573, V4574, V4575, V4576, V4577, V4578, V4579, V4580,
+ V4581, V4582, V4583, V4584, V4585, V4586, V4587, V4588,
+ V4589, V4590, V4591, V4592, V4593, V4594, V4595, V4596,
+ }, // P[193]
+ {
+ V4597, V4598, V4599, V4600, V4601, V4602, V4603, V4604,
+ V4605, V4606, V4607, V4608, V4609, V4610, V4611, V4612,
+ V4613, V4614, V4615, V4616, V4617, V4618, V4619, V4620,
+ V4621, V4622, V4623, V4624, V4625, V4626, V4627, V4628,
+ }, // P[194]
+ {
+ V4629, V4630, V4631, V4632, V4633, V4634, V4635, V4636,
+ V4637, V4638, V4639, V4640, V4641, V4642, V4643, V4644,
+ V4645, V4646, V4647, V4648, V4649, V4650, V4651, V4652,
+ V4653, V4654, V4655, V4656, V4657, V4658, V4659, V4660,
+ }, // P[195]
+ {
+ V4661, V4662, V4663, V4664, V4665, V4666, V4667, V4668,
+ V4669, V4670, V4671, V4672, V4673, V4674, V4675, V4676,
+ V4677, V4678, V4679, V4680, V4681, V4682, V4683, V4684,
+ V4685, V4686, V4687, V4688, V4689, V4690, V4691, V4692,
+ }, // P[196]
+ {
+ V4693, V4694, V4695, V4696, V4697, V4698, V4699, V4700,
+ V4701, V4702, V4703, V4704, V4705, V4706, V4707, V4708,
+ V4709, V4710, V4711, V4712, V4713, V4714, V4715, V4716,
+ V4717, V4718, V4719, V4720, V4721, V4722, V4723, V4724,
+ }, // P[197]
+ {
+ V4725, V4726, V4727, V4728, V4729, V4730, V4731, V4732,
+ V4733, V4734, V4735, V4736, V4737, V4738, V4739, V4740,
+ V4741, V4742, V4743, V4744, V4745, V4746, V4747, V4748,
+ V4749, V4750, V4751, V4752, V4753, V4754, V4755, V4756,
+ }, // P[198]
+ {
+ V4757, V4758, V4759, V4760, V4761, V4762, V4763, V4764,
+ V4765, V4766, V4767, V4768, V4769, V4770, V4771, V4772,
+ V4773, V4774, V4775, V4776, V4777, V4778, V4779, V4780,
+ V4781, V4782, V4783, V4784, V4785, V4786, V4787, V4788,
+ }, // P[199]
+ {
+ V4789, V4790, V4791, V4792, V4793, V4794, V4795, V4796,
+ V4797, V4798, V4799, V4800, V4801, V4802, V4803, V4804,
+ V4805, V4806, V4807, V4808, V4809, V4810, V4811, V4812,
+ V4813, V4814, V4815, V4816, V4817, V4818, V4819, V4820,
+ }, // P[200]
+ {
+ V4821, V4822, V4823, V4824, V4825, V4826, V4827, V4828,
+ V4829, V4830, V4831, V4832, V4833, V4834, V4835, V4836,
+ V4837, V4838, V4839, V4840, V4841, V4842, V4843, V4844,
+ V4845, V4846, V4847, V4848, V4849, V4850, V4851, V4852,
+ }, // P[201]
+ {
+ V4853, V4854, V4855, V4856, V4857, V4858, V4859, V4860,
+ V4861, V4862, V4863, V4864, V4865, V4866, V4867, V4868,
+ V4869, V4870, V4871, V4872, V4873, V4874, V4875, V4876,
+ V4877, V4878, V4879, V4880, V4881, V4882, V4883, V4884,
+ }, // P[202]
+ {
+ V4885, V4886, V4887, V4888, V4889, V4890, V4891, V4892,
+ V4893, V4894, V4895, V4896, V4897, V4898, V4899, V4900,
+ V4901, V4902, V4903, V4904, V4905, V4906, V4907, V4908,
+ V4909, V4910, V4911, V4912, V4913, V4914, V4915, V4916,
+ }, // P[203]
+ {
+ V4917, V4918, V4919, V4920, V4921, V4922, V4923, V4924,
+ V4925, V4926, V4927, V4928, V4929, V4930, V4931, V4932,
+ V4933, V4934, V4935, V4936, V4937, V4938, V4939, V4940,
+ V4941, V4942, V4943, V4944, V4945, V4946, V4947, V4948,
+ }, // P[204]
+ {
+ V4949, V4950, V4951, V4952, V4953, V4954, V4955, V4956,
+ V4957, V4958, V4959, V4960, V4961, V4962, V4963, V4964,
+ V4965, V4966, V4967, V4968, V4969, V4970, V4971, V4972,
+ V4973, V4974, V4975, V4976, V4977, V4978, V4979, V4980,
+ }, // P[205]
+ {
+ V4981, V4982, V4983, V4984, V4985, V4986, V4987, V4988,
+ V4989, V4990, V4991, V4992, V4993, V4994, V4995, V4996,
+ V4997, V4998, V4999, V5000, V5001, V5002, V5003, V5004,
+ V5005, V5006, V5007, V5008, V5009, V5010, V5011, V5012,
+ }, // P[206]
+ {
+ V5013, V5014, V5015, V5016, V5017, V5018, V5019, V5020,
+ V5021, V5022, V5023, V5024, V5025, V5026, V5027, V5028,
+ V5029, V5030, V5031, V5032, V5033, V5034, V5035, V5036,
+ V5037, V5038, V5039, V5040, V5041, V5042, V5043, V5044,
+ }, // P[207]
+ {
+ V5045, V5046, V5047, V5048, V5049, V5050, V5051, V5052,
+ V5053, V5054, V5055, V5056, V5057, V5058, V5059, V5060,
+ V5061, V5062, V5063, V5064, V5065, V5066, V5067, V5068,
+ V5069, V5070, V5071, V5072, V5073, V5074, V5075, V5076,
+ }, // P[208]
+ {
+ V5077, V5078, V5079, V5080, V5081, V5082, V5083, V5084,
+ V5085, V5086, V5087, V5088, V5089, V5090, V5091, V5092,
+ V5093, V5094, V5095, V5096, V5097, V5098, V5099, V5100,
+ V5101, V5102, V5103, V5104, V5105, V5106, V5107, V5108,
+ }, // P[209]
+ {
+ V5109, V5110, V5111, V5112, V5113, V5114, V5115, V5116,
+ V5117, V5118, V5119, V5120, V5121, V5122, V5123, V5124,
+ V5125, V5126, V5127, V5128, V5129, V5130, V5131, V5132,
+ V5133, V5134, V5135, V5136, V5137, V5138, V5139, V5140,
+ }, // P[210]
+ {
+ V5141, V5142, V5143, V5144, V5145, V5146, V5147, V5148,
+ V5149, V5150, V5151, V5152, V5153, V5154, V5155, V5156,
+ V5157, V5158, V5159, V5160, V5161, V5162, V5163, V5164,
+ V5165, V5166, V5167, V5168, V5169, V5170, V5171, V5172,
+ }, // P[211]
+ {
+ V5173, V5174, V5175, V5176, V5177, V5178, V5179, V5180,
+ V5181, V5182, V5183, V5184, V5185, V5186, V5187, V5188,
+ V5189, V5190, V5191, V5192, V5193, V5194, V5195, V5196,
+ V5197, V5198, V5199, V5200, V5201, V5202, V5203, V5204,
+ }, // P[212]
+ {
+ V5205, V5206, V5207, V5208, V5209, V5210, V5211, V5212,
+ V5213, V5214, V5215, V5216, V5217, V5218, V5219, V5220,
+ V5221, V5222, V5223, V5224, V5225, V5226, V5227, V5228,
+ V5229, V5230, V5231, V5232, V5233, V5234, V5235, V5236,
+ }, // P[213]
+ {
+ V5237, V5238, V5239, V5240, V5241, V5242, V5243, V5244,
+ V5245, V5246, V5247, V5248, V5249, V5250, V5251, V5252,
+ V5253, V5254, V5255, V5256, V5257, V5258, V5259, V5260,
+ V5261, V5262, V5263, V5264, V5265, V5266, V5267, V5268,
+ }, // P[214]
+ {
+ V5269, V5270, V5271, V5272, V5273, V5274, V5275, V5276,
+ V5277, V5278, V5279, V5280, V5281, V5282, V5283, V5284,
+ V5285, V5286, V5287, V5288, V5289, V5290, V5291, V5292,
+ V5293, V5294, V5295, V5296, V5297, V5298, V5299, V5300,
+ }, // P[215]
+ {
+ V5301, V5302, V5303, V5304, V5305, V5306, V5307, V5308,
+ V5309, V5310, V5311, V5312, V5313, V5314, V5315, V5316,
+ V5317, V5318, V5319, V5320, V5321, V5322, V5323, V5324,
+ V5325, V5326, V5327, V5328, V5329, V5330, V5331, V5332,
+ }, // P[216]
+ {
+ V5333, V5334, V5335, V5336, V5337, V5338, V5339, V5340,
+ V5341, V5342, V5343, V5344, V5345, V5346, V5347, V5348,
+ V5349, V5350, V5351, V5352, V5353, V5354, V5355, V5356,
+ V5357, V5358, V5359, V5360, V5361, V5362, V5363, V5364,
+ }, // P[217]
+ {
+ V5365, V5366, V5367, V5368, V5369, V5370, V5371, V5372,
+ V5373, V5374, V5375, V5376, V5377, V5378, V5379, V5380,
+ V5381, V5382, V5383, V5384, V5385, V5386, V5387, V5388,
+ V5389, V5390, V5391, V5392, V5393, V5394, V5395, V5396,
+ }, // P[218]
+ {
+ V5397, V5398, V5399, V5400, V5401, V5402, V5403, V5404,
+ V5405, V5406, V5407, V5408, V5409, V5410, V5411, V5412,
+ V5413, V5414, V5415, V5416, V5417, V5418, V5419, V5420,
+ V5421, V5422, V5423, V5424, V5425, V5426, V5427, V5428,
+ }, // P[219]
+ {
+ V5429, V5430, V5431, V5432, V5433, V5434, V5435, V5436,
+ V5437, V5438, V5439, V5440, V5441, V5442, V5443, V5444,
+ V5445, V5446, V5447, V5448, V5449, V5450, V5451, V5452,
+ V5453, V5454, V5455, V5456, V5457, V5458, V5459, V5460,
+ }, // P[220]
+ {
+ V5461, V5462, V5463, V5464, V5465, V5466, V5467, V5468,
+ V5469, V5470, V5471, V5472, V5473, V5474, V5475, V5476,
+ V5477, V5478, V5479, V5480, V5481, V5482, V5483, V5484,
+ V5485, V5486, V5487, V5488, V5489, V5490, V5491, V5492,
+ }, // P[221]
+ {
+ V5493, V5494, V5495, V5496, V5497, V5498, V5499, V5500,
+ V5501, V5502, V5503, V5504, V5505, V5506, V5507, V5508,
+ V5509, V5510, V5511, V5512, V5513, V5514, V5515, V5516,
+ V5517, V5518, V5519, V5520, V5521, V5522, V5523, V5524,
+ }, // P[222]
+ {
+ V5525, V5526, V5527, V5528, V5529, V5530, V5531, V5532,
+ V5533, V5534, V5535, V5536, V5537, V5538, V5539, V5540,
+ V5541, V5542, V5543, V5544, V5545, V5546, V5547, V5548,
+ V5549, V5550, V5551, V5552, V5553, V5554, V5555, V5556,
+ }, // P[223]
+ {
+ V5557, V5558, V5559, V5560, V5561, V5562, V5563, V5564,
+ V5565, V5566, V5567, V5568, V5569, V5570, V5571, V5572,
+ V5573, V5574, V5575, V5576, V5577, V5578, V5579, V5580,
+ V5581, V5582, V5583, V5584, V5585, V5586, V5587, V5588,
+ }, // P[224]
+ {
+ V5589, V5590, V5591, V5592, V5593, V5594, V5595, V5596,
+ V5597, V5598, V5599, V5600, V5601, V5602, V5603, V5604,
+ V5605, V5606, V5607, V5608, V5609, V5610, V5611, V5612,
+ V5613, V5614, V5615, V5616, V5617, V5618, V5619, V5620,
+ }, // P[225]
+ {
+ V5621, V5622, V5623, V5624, V5625, V5626, V5627, V5628,
+ V5629, V5630, V5631, V5632, V5633, V5634, V5635, V5636,
+ V5637, V5638, V5639, V5640, V5641, V5642, V5643, V5644,
+ V5645, V5646, V5647, V5648, V5649, V5650, V5651, V5652,
+ }, // P[226]
+ {
+ V5653, V5654, V5655, V5656, V5657, V5658, V5659, V5660,
+ V5661, V5662, V5663, V5664, V5665, V5666, V5667, V5668,
+ V5669, V5670, V5671, V5672, V5673, V5674, V5675, V5676,
+ V5677, V5678, V5679, V5680, V5681, V5682, V5683, V5684,
+ }, // P[227]
+ {
+ V5685, V5686, V5687, V5688, V5689, V5690, V5691, V5692,
+ V5693, V5694, V5695, V5696, V5697, V5698, V5699, V5700,
+ V5701, V5702, V5703, V5704, V5705, V5706, V5707, V5708,
+ V5709, V5710, V5711, V5712, V5713, V5714, V5715, V5716,
+ }, // P[228]
+ {
+ V5717, V5718, V5719, V5720, V5721, V5722, V5723, V5724,
+ V5725, V5726, V5727, V5728, V5729, V5730, V5731, V5732,
+ V5733, V5734, V5735, V5736, V5737, V5738, V5739, V5740,
+ V5741, V5742, V5743, V5744, V5745, V5746, V5747, V5748,
+ }, // P[229]
+ {
+ V5749, V5750, V5751, V5752, V5753, V5754, V5755, V5756,
+ V5757, V5758, V5759, V5760, V5761, V5762, V5763, V5764,
+ V5765, V5766, V5767, V5768, V5769, V5770, V5771, V5772,
+ V5773, V5774, V5775, V5776, V5777, V5778, V5779, V5780,
+ }, // P[230]
+ {
+ V5781, V5782, V5783, V5784, V5785, V5786, V5787, V5788,
+ V5789, V5790, V5791, V5792, V5793, V5794, V5795, V5796,
+ V5797, V5798, V5799, V5800, V5801, V5802, V5803, V5804,
+ V5805, V5806, V5807, V5808, V5809, V5810, V5811, V5812,
+ }, // P[231]
+ {
+ V5813, V5814, V5815, V5816, V5817, V5818, V5819, V5820,
+ V5821, V5822, V5823, V5824, V5825, V5826, V5827, V5828,
+ V5829, V5830, V5831, V5832, V5833, V5834, V5835, V5836,
+ V5837, V5838, V5839, V5840, V5841, V5842, V5843, V5844,
+ }, // P[232]
+ {
+ V5845, V5846, V5847, V5848, V5849, V5850, V5851, V5852,
+ V5853, V5854, V5855, V5856, V5857, V5858, V5859, V5860,
+ V5861, V5862, V5863, V5864, V5865, V5866, V5867, V5868,
+ V5869, V5870, V5871, V5872, V5873, V5874, V5875, V5876,
+ }, // P[233]
+ {
+ V5877, V5878, V5879, V5880, V5881, V5882, V5883, V5884,
+ V5885, V5886, V5887, V5888, V5889, V5890, V5891, V5892,
+ V5893, V5894, V5895, V5896, V5897, V5898, V5899, V5900,
+ V5901, V5902, V5903, V5904, V5905, V5906, V5907, V5908,
+ }, // P[234]
+ {
+ V5909, V5910, V5911, V5912, V5913, V5914, V5915, V5916,
+ V5917, V5918, V5919, V5920, V5921, V5922, V5923, V5924,
+ V5925, V5926, V5927, V5928, V5929, V5930, V5931, V5932,
+ V5933, V5934, V5935, V5936, V5937, V5938, V5939, V5940,
+ }, // P[235]
+ {
+ V5941, V5942, V5943, V5944, V5945, V5946, V5947, V5948,
+ V5949, V5950, V5951, V5952, V5953, V5954, V5955, V5956,
+ V5957, V5958, V5959, V5960, V5961, V5962, V5963, V5964,
+ V5965, V5966, V5967, V5968, V5969, V5970, V5971, V5972,
+ }, // P[236]
+ {
+ V5973, V5974, V5975, V5976, V5977, V5978, V5979, V5980,
+ V5981, V5982, V5983, V5984, V5985, V5986, V5987, V5988,
+ V5989, V5990, V5991, V5992, V5993, V5994, V5995, V5996,
+ V5997, V5998, V5999, V6000, V6001, V6002, V6003, V6004,
+ }, // P[237]
+ {
+ V6005, V6006, V6007, V6008, V6009, V6010, V6011, V6012,
+ V6013, V6014, V6015, V6016, V6017, V6018, V6019, V6020,
+ V6021, V6022, V6023, V6024, V6025, V6026, V6027, V6028,
+ V6029, V6030, V6031, V6032, V6033, V6034, V6035, V6036,
+ }, // P[238]
+ {
+ V6037, V6038, V6039, V6040, V6041, V6042, V6043, V6044,
+ V6045, V6046, V6047, V6048, V6049, V6050, V6051, V6052,
+ V6053, V6054, V6055, V6056, V6057, V6058, V6059, V6060,
+ V6061, V6062, V6063, V6064, V6065, V6066, V6067, V6068,
+ }, // P[239]
+ {
+ V6069, V6070, V6071, V6072, V6073, V6074, V6075, V6076,
+ V6077, V6078, V6079, V6080, V6081, V6082, V6083, V6084,
+ V6085, V6086, V6087, V6088, V6089, V6090, V6091, V6092,
+ V6093, V6094, V6095, V6096, V6097, V6098, V6099, V6100,
+ }, // P[240]
+ {
+ V6101, V6102, V6103, V6104, V6105, V6106, V6107, V6108,
+ V6109, V6110, V6111, V6112, V6113, V6114, V6115, V6116,
+ V6117, V6118, V6119, V6120, V6121, V6122, V6123, V6124,
+ V6125, V6126, V6127, V6128, V6129, V6130, V6131, V6132,
+ }, // P[241]
+ {
+ V6133, V6134, V6135, V6136, V6137, V6138, V6139, V6140,
+ V6141, V6142, V6143, V6144, V6145, V6146, V6147, V6148,
+ V6149, V6150, V6151, V6152, V6153, V6154, V6155, V6156,
+ V6157, V6158, V6159, V6160, V6161, V6162, V6163, V6164,
+ }, // P[242]
+ {
+ V6165, V6166, V6167, V6168, V6169, V6170, V6171, V6172,
+ V6173, V6174, V6175, V6176, V6177, V6178, V6179, V6180,
+ V6181, V6182, V6183, V6184, V6185, V6186, V6187, V6188,
+ V6189, V6190, V6191, V6192, V6193, V6194, V6195, V6196,
+ }, // P[243]
+ {
+ V6197, V6198, V6199, V6200, V6201, V6202, V6203, V6204,
+ V6205, V6206, V6207, V6208, V6209, V6210, V6211, V6212,
+ V6213, V6214, V6215, V6216, V6217, V6218, V6219, V6220,
+ V6221, V6222, V6223, V6224, V6225, V6226, V6227, V6228,
+ }, // P[244]
+ {
+ V6229, V6230, V6231, V6232, V6233, V6234, V6235, V6236,
+ V6237, V6238, V6239, V6240, V6241, V6242, V6243, V6244,
+ V6245, V6246, V6247, V6248, V6249, V6250, V6251, V6252,
+ V6253, V6254, V6255, V6256, V6257, V6258, V6259, V6260,
+ }, // P[245]
+ {
+ V6261, V6262, V6263, V6264, V6265, V6266, V6267, V6268,
+ V6269, V6270, V6271, V6272, V6273, V6274, V6275, V6276,
+ V6277, V6278, V6279, V6280, V6281, V6282, V6283, V6284,
+ V6285, V6286, V6287, V6288, V6289, V6290, V6291, V6292,
+ }, // P[246]
+ {
+ V6293, V6294, V6295, V6296, V6297, V6298, V6299, V6300,
+ V6301, V6302, V6303, V6304, V6305, V6306, V6307, V6308,
+ V6309, V6310, V6311, V6312, V6313, V6314, V6315, V6316,
+ V6317, V6318, V6319, V6320, V6321, V6322, V6323, V6324,
+ }, // P[247]
+ {
+ V6325, V6326, V6327, V6328, V6329, V6330, V6331, V6332,
+ V6333, V6334, V6335, V6336, V6337, V6338, V6339, V6340,
+ V6341, V6342, V6343, V6344, V6345, V6346, V6347, V6348,
+ V6349, V6350, V6351, V6352, V6353, V6354, V6355, V6356,
+ }, // P[248]
+ {
+ V6357, V6358, V6359, V6360, V6361, V6362, V6363, V6364,
+ V6365, V6366, V6367, V6368, V6369, V6370, V6371, V6372,
+ V6373, V6374, V6375, V6376, V6377, V6378, V6379, V6380,
+ V6381, V6382, V6383, V6384, V6385, V6386, V6387, V6388,
+ }, // P[249]
+ {
+ V6389, V6390, V6391, V6392, V6393, V6394, V6395, V6396,
+ V6397, V6398, V6399, V6400, V6401, V6402, V6403, V6404,
+ V6405, V6406, V6407, V6408, V6409, V6410, V6411, V6412,
+ V6413, V6414, V6415, V6416, V6417, V6418, V6419, V6420,
+ }, // P[250]
+ {
+ V6421, V6422, V6423, V6424, V6425, V6426, V6427, V6428,
+ V6429, V6430, V6431, V6432, V6433, V6434, V6435, V6436,
+ V6437, V6438, V6439, V6440, V6441, V6442, V6443, V6444,
+ V6445, V6446, V6447, V6448, V6449, V6450, V6451, V6452,
+ }, // P[251]
+ {
+ V6453, V6454, V6455, V6456, V6457, V6458, V6459, V6460,
+ V6461, V6462, V6463, V6464, V6465, V6466, V6467, V6468,
+ V6469, V6470, V6471, V6472, V6473, V6474, V6475, V6476,
+ V6477, V6478, V6479, V6480, V6481, V6482, V6483, V6484,
+ }, // P[252]
+ {
+ V6485, V6486, V6487, V6488, V6489, V6490, V6491, V6492,
+ V6493, V6494, V6495, V6496, V6497, V6498, V6499, V6500,
+ V6501, V6502, V6503, V6504, V6505, V6506, V6507, V6508,
+ V6509, V6510, V6511, V6512, V6513, V6514, V6515, V6516,
+ }, // P[253]
+ {
+ V6517, V6518, V6519, V6520, V6521, V6522, V6523, V6524,
+ V6525, V6526, V6527, V6528, V6529, V6530, V6531, V6532,
+ V6533, V6534, V6535, V6536, V6537, V6538, V6539, V6540,
+ V6541, V6542, V6543, V6544, V6545, V6546, V6547, V6548,
+ }, // P[254]
+ {
+ V6549, V6550, V6551, V6552, V6553, V6554, V6555, V6556,
+ V6557, V6558, V6559, V6560, V6561, V6562, V6563, V6564,
+ V6565, V6566, V6567, V6568, V6569, V6570, V6571, V6572,
+ V6573, V6574, V6575, V6576, V6577, V6578, V6579, V6580,
+ }, // P[255]
+ {
+ V6581, V6582, V6583, V6584, V6585, V6586, V6587, V6588,
+ V6589, V6590, V6591, V6592, V6593, V6594, V6595, V6596,
+ V6597, V6598, V6599, V6600, V6601, V6602, V6603, V6604,
+ V6605, V6606, V6607, V6608, V6609, V6610, V6611, V6612,
+ }, // P[256]
+ {
+ V6613, V6614, V6615, V6616, V6617, V6618, V6619, V6620,
+ V6621, V6622, V6623, V6624, V6625, V6626, V6627, V6628,
+ V6629, V6630, V6631, V6632, V6633, V6634, V6635, V6636,
+ V6637, V6638, V6639, V6640, V6641, V6642, V6643, V6644,
+ }, // P[257]
+ {
+ V6645, V6646, V6647, V6648, V6649, V6650, V6651, V6652,
+ V6653, V6654, V6655, V6656, V6657, V6658, V6659, V6660,
+ V6661, V6662, V6663, V6664, V6665, V6666, V6667, V6668,
+ V6669, V6670, V6671, V6672, V6673, V6674, V6675, V6676,
+ }, // P[258]
+ {
+ V6677, V6678, V6679, V6680, V6681, V6682, V6683, V6684,
+ V6685, V6686, V6687, V6688, V6689, V6690, V6691, V6692,
+ V6693, V6694, V6695, V6696, V6697, V6698, V6699, V6700,
+ V6701, V6702, V6703, V6704, V6705, V6706, V6707, V6708,
+ }, // P[259]
+ {
+ V6709, V6710, V6711, V6712, V6713, V6714, V6715, V6716,
+ V6717, V6718, V6719, V6720, V6721, V6722, V6723, V6724,
+ V6725, V6726, V6727, V6728, V6729, V6730, V6731, V6732,
+ V6733, V6734, V6735, V6736, V6737, V6738, V6739, V6740,
+ }, // P[260]
+ {
+ V6741, V6742, V6743, V6744, V6745, V6746, V6747, V6748,
+ V6749, V6750, V6751, V6752, V6753, V6754, V6755, V6756,
+ V6757, V6758, V6759, V6760, V6761, V6762, V6763, V6764,
+ V6765, V6766, V6767, V6768, V6769, V6770, V6771, V6772,
+ }, // P[261]
+ {
+ V6773, V6774, V6775, V6776, V6777, V6778, V6779, V6780,
+ V6781, V6782, V6783, V6784, V6785, V6786, V6787, V6788,
+ V6789, V6790, V6791, V6792, V6793, V6794, V6795, V6796,
+ V6797, V6798, V6799, V6800, V6801, V6802, V6803, V6804,
+ }, // P[262]
+ {
+ V6805, V6806, V6807, V6808, V6809, V6810, V6811, V6812,
+ V6813, V6814, V6815, V6816, V6817, V6818, V6819, V6820,
+ V6821, V6822, V6823, V6824, V6825, V6826, V6827, V6828,
+ V6829, V6830, V6831, V6832, V6833, V6834, V6835, V6836,
+ }, // P[263]
+ {
+ V6837, V6838, V6839, V6840, V6841, V6842, V6843, V6844,
+ V6845, V6846, V6847, V6848, V6849, V6850, V6851, V6852,
+ V6853, V6854, V6855, V6856, V6857, V6858, V6859, V6860,
+ V6861, V6862, V6863, V6864, V6865, V6866, V6867, V6868,
+ }, // P[264]
+ {
+ V6869, V6870, V6871, V6872, V6873, V6874, V6875, V6876,
+ V6877, V6878, V6879, V6880, V6881, V6882, V6883, V6884,
+ V6885, V6886, V6887, V6888, V6889, V6890, V6891, V6892,
+ V6893, V6894, V6895, V6896, V6897, V6898, V6899, V6900,
+ }, // P[265]
+ {
+ V6901, V6902, V6903, V6904, V6905, V6906, V6907, V6908,
+ V6909, V6910, V6911, V6912, V6913, V6914, V6915, V6916,
+ V6917, V6918, V6919, V6920, V6921, V6922, V6923, V6924,
+ V6925, V6926, V6927, V6928, V6929, V6930, V6931, V6932,
+ }, // P[266]
+ {
+ V6933, V6934, V6935, V6936, V6937, V6938, V6939, V6940,
+ V6941, V6942, V6943, V6944, V6945, V6946, V6947, V6948,
+ V6949, V6950, V6951, V6952, V6953, V6954, V6955, V6956,
+ V6957, V6958, V6959, V6960, V6961, V6962, V6963, V6964,
+ }, // P[267]
+ {
+ V6965, V6966, V6967, V6968, V6969, V6970, V6971, V6972,
+ V6973, V6974, V6975, V6976, V6977, V6978, V6979, V6980,
+ V6981, V6982, V6983, V6984, V6985, V6986, V6987, V6988,
+ V6989, V6990, V6991, V6992, V6993, V6994, V6995, V6996,
+ }, // P[268]
+ {
+ V6997, V6998, V6999, V7000, V7001, V7002, V7003, V7004,
+ V7005, V7006, V7007, V7008, V7009, V7010, V7011, V7012,
+ V7013, V7014, V7015, V7016, V7017, V7018, V7019, V7020,
+ V7021, V7022, V7023, V7024, V7025, V7026, V7027, V7028,
+ }, // P[269]
+ {
+ V7029, V7030, V7031, V7032, V7033, V7034, V7035, V7036,
+ V7037, V7038, V7039, V7040, V7041, V7042, V7043, V7044,
+ V7045, V7046, V7047, V7048, V7049, V7050, V7051, V7052,
+ V7053, V7054, V7055, V7056, V7057, V7058, V7059, V7060,
+ }, // P[270]
+ {
+ V7061, V7062, V7063, V7064, V7065, V7066, V7067, V7068,
+ V7069, V7070, V7071, V7072, V7073, V7074, V7075, V7076,
+ V7077, V7078, V7079, V7080, V7081, V7082, V7083, V7084,
+ V7085, V7086, V7087, V7088, V7089, V7090, V7091, V7092,
+ }, // P[271]
+ {
+ V7093, V7094, V7095, V7096, V7097, V7098, V7099, V7100,
+ V7101, V7102, V7103, V7104, V7105, V7106, V7107, V7108,
+ V7109, V7110, V7111, V7112, V7113, V7114, V7115, V7116,
+ V7117, V7118, V7119, V7120, V7121, V7122, V7123, V7124,
+ }, // P[272]
+ {
+ V7125, V7126, V7127, V7128, V7129, V7130, V7131, V7132,
+ V7133, V7134, V7135, V7136, V7137, V7138, V7139, V7140,
+ V7141, V7142, V7143, V7144, V7145, V7146, V7147, V7148,
+ V7149, V7150, V7151, V7152, V7153, V7154, V7155, V7156,
+ }, // P[273]
+ {
+ V7157, V7158, V7159, V7160, V7161, V7162, V7163, V7164,
+ V7165, V7166, V7167, V7168, V7169, V7170, V7171, V7172,
+ V7173, V7174, V7175, V7176, V7177, V7178, V7179, V7180,
+ V7181, V7182, V7183, V7184, V7185, V7186, V7187, V7188,
+ }, // P[274]
+ {
+ V7189, V7190, V7191, V7192, V7193, V7194, V7195, V7196,
+ V7197, V7198, V7199, V7200, V7201, V7202, V7203, V7204,
+ V7205, V7206, V7207, V7208, V7209, V7210, V7211, V7212,
+ V7213, V7214, V7215, V7216, V7217, V7218, V7219, V7220,
+ }, // P[275]
+ {
+ V7221, V7222, V7223, V7224, V7225, V7226, V7227, V7228,
+ V7229, V7230, V7231, V7232, V7233, V7234, V7235, V7236,
+ V7237, V7238, V7239, V7240, V7241, V7242, V7243, V7244,
+ V7245, V7246, V7247, V7248, V7249, V7250, V7251, V7252,
+ }, // P[276]
+ {
+ V7253, V7254, V7255, V7256, V7257, V7258, V7259, V7260,
+ V7261, V7262, V7263, V7264, V7265, V7266, V7267, V7268,
+ V7269, V7270, V7271, V7272, V7273, V7274, V7275, V7276,
+ V7277, V7278, V7279, V7280, V7281, V7282, V7283, V7284,
+ }, // P[277]
+ {
+ V7285, V7286, V7287, V7288, V7289, V7290, V7291, V7292,
+ V7293, V7294, V7295, V7296, V7297, V7298, V7299, V7300,
+ V7301, V7302, V7303, V7304, V7305, V7306, V7307, V7308,
+ V7309, V7310, V7311, V7312, V7313, V7314, V7315, V7316,
+ }, // P[278]
+ {
+ V7317, V7318, V7319, V7320, V7321, V7322, V7323, V7324,
+ V7325, V7326, V7327, V7328, V7329, V7330, V7331, V7332,
+ V7333, V7334, V7335, V7336, V7337, V7338, V7339, V7340,
+ V7341, V7342, V7343, V7344, V7345, V7346, V7347, V7348,
+ }, // P[279]
+ {
+ V7349, V7350, V7351, V7352, V7353, V7354, V7355, V7356,
+ V7357, V7358, V7359, V7360, V7361, V7362, V7363, V7364,
+ V7365, V7366, V7367, V7368, V7369, V7370, V7371, V7372,
+ V7373, V7374, V7375, V7376, V7377, V7378, V7379, V7380,
+ }, // P[280]
+ {
+ V7381, V7382, V7383, V7384, V7385, V7386, V7387, V7388,
+ V7389, V7390, V7391, V7392, V7393, V7394, V7395, V7396,
+ V7397, V7398, V7399, V7400, V7401, V7402, V7403, V7404,
+ V7405, V7406, V7407, V7408, V7409, V7410, V7411, V7412,
+ }, // P[281]
+ {
+ V7413, V7414, V7415, V7416, V7417, V7418, V7419, V7420,
+ V7421, V7422, V7423, V7424, V7425, V7426, V7427, V7428,
+ V7429, V7430, V7431, V7432, V7433, V7434, V7435, V7436,
+ V7437, V7438, V7439, V7440, V7441, V7442, V7443, V7444,
+ }, // P[282]
+ {
+ V7445, V7446, V7447, V7448, V7449, V7450, V7451, V7452,
+ V7453, V7454, V7455, V7456, V7457, V7458, V7459, V7460,
+ V7461, V7462, V7463, V7464, V7465, V7466, V7467, V7468,
+ V7469, V7470, V7471, V7472, V7473, V7474, V7475, V7476,
+ }, // P[283]
+ {
+ V7477, V7478, V7479, V7480, V7481, V7482, V7483, V7484,
+ V7485, V7486, V7487, V7488, V7489, V7490, V7491, V7492,
+ V7493, V7494, V7495, V7496, V7497, V7498, V7499, V7500,
+ V7501, V7502, V7503, V7504, V7505, V7506, V7507, V7508,
+ }, // P[284]
+ {
+ V7509, V7510, V7511, V7512, V7513, V7514, V7515, V7516,
+ V7517, V7518, V7519, V7520, V7521, V7522, V7523, V7524,
+ V7525, V7526, V7527, V7528, V7529, V7530, V7531, V7532,
+ V7533, V7534, V7535, V7536, V7537, V7538, V7539, V7540,
+ }, // P[285]
+ {
+ V7541, V7542, V7543, V7544, V7545, V7546, V7547, V7548,
+ V7549, V7550, V7551, V7552, V7553, V7554, V7555, V7556,
+ V7557, V7558, V7559, V7560, V7561, V7562, V7563, V7564,
+ V7565, V7566, V7567, V7568, V7569, V7570, V7571, V7572,
+ }, // P[286]
+ {
+ V7573, V7574, V7575, V7576, V7577, V7578, V7579, V7580,
+ V7581, V7582, V7583, V7584, V7585, V7586, V7587, V7588,
+ V7589, V7590, V7591, V7592, V7593, V7594, V7595, V7596,
+ V7597, V7598, V7599, V7600, V7601, V7602, V7603, V7604,
+ }, // P[287]
+ {
+ V7605, V7606, V7607, V7608, V7609, V7610, V7611, V7612,
+ V7613, V7614, V7615, V7616, V7617, V7618, V7619, V7620,
+ V7621, V7622, V7623, V7624, V7625, V7626, V7627, V7628,
+ V7629, V7630, V7631, V7632, V7633, V7634, V7635, V7636,
+ }, // P[288]
+ {
+ V7637, V7638, V7639, V7640, V7641, V7642, V7643, V7644,
+ V7645, V7646, V7647, V7648, V7649, V7650, V7651, V7652,
+ V7653, V7654, V7655, V7656, V7657, V7658, V7659, V7660,
+ V7661, V7662, V7663, V7664, V7665, V7666, V7667, V7668,
+ }, // P[289]
+ {
+ V7669, V7670, V7671, V7672, V7673, V7674, V7675, V7676,
+ V7677, V7678, V7679, V7680, V7681, V7682, V7683, V7684,
+ V7685, V7686, V7687, V7688, V7689, V7690, V7691, V7692,
+ V7693, V7694, V7695, V7696, V7697, V7698, V7699, V7700,
+ }, // P[290]
+ {
+ V7701, V7702, V7703, V7704, V7705, V7706, V7707, V7708,
+ V7709, V7710, V7711, V7712, V7713, V7714, V7715, V7716,
+ V7717, V7718, V7719, V7720, V7721, V7722, V7723, V7724,
+ V7725, V7726, V7727, V7728, V7729, V7730, V7731, V7732,
+ }, // P[291]
+ {
+ V7733, V7734, V7735, V7736, V7737, V7738, V7739, V7740,
+ V7741, V7742, V7743, V7744, V7745, V7746, V7747, V7748,
+ V7749, V7750, V7751, V7752, V7753, V7754, V7755, V7756,
+ V7757, V7758, V7759, V7760, V7761, V7762, V7763, V7764,
+ }, // P[292]
+ {
+ V7765, V7766, V7767, V7768, V7769, V7770, V7771, V7772,
+ V7773, V7774, V7775, V7776, V7777, V7778, V7779, V7780,
+ V7781, V7782, V7783, V7784, V7785, V7786, V7787, V7788,
+ V7789, V7790, V7791, V7792, V7793, V7794, V7795, V7796,
+ }, // P[293]
+ {
+ V7797, V7798, V7799, V7800, V7801, V7802, V7803, V7804,
+ V7805, V7806, V7807, V7808, V7809, V7810, V7811, V7812,
+ V7813, V7814, V7815, V7816, V7817, V7818, V7819, V7820,
+ V7821, V7822, V7823, V7824, V7825, V7826, V7827, V7828,
+ }, // P[294]
+ {
+ V7829, V7830, V7831, V7832, V7833, V7834, V7835, V7836,
+ V7837, V7838, V7839, V7840, V7841, V7842, V7843, V7844,
+ V7845, V7846, V7847, V7848, V7849, V7850, V7851, V7852,
+ V7853, V7854, V7855, V7856, V7857, V7858, V7859, V7860,
+ }, // P[295]
+ {
+ V7861, V7862, V7863, V7864, V7865, V7866, V7867, V7868,
+ V7869, V7870, V7871, V7872, V7873, V7874, V7875, V7876,
+ V7877, V7878, V7879, V7880, V7881, V7882, V7883, V7884,
+ V7885, V7886, V7887, V7888, V7889, V7890, V7891, V7892,
+ }, // P[296]
+ {
+ V7893, V7894, V7895, V7896, V7897, V7898, V7899, V7900,
+ V7901, V7902, V7903, V7904, V7905, V7906, V7907, V7908,
+ V7909, V7910, V7911, V7912, V7913, V7914, V7915, V7916,
+ V7917, V7918, V7919, V7920, V7921, V7922, V7923, V7924,
+ }, // P[297]
+ {
+ V7925, V7926, V7927, V7928, V7929, V7930, V7931, V7932,
+ V7933, V7934, V7935, V7936, V7937, V7938, V7939, V7940,
+ V7941, V7942, V7943, V7944, V7945, V7946, V7947, V7948,
+ V7949, V7950, V7951, V7952, V7953, V7954, V7955, V7956,
+ }, // P[298]
+ {
+ V7957, V7958, V7959, V7960, V7961, V7962, V7963, V7964,
+ V7965, V7966, V7967, V7968, V7969, V7970, V7971, V7972,
+ V7973, V7974, V7975, V7976, V7977, V7978, V7979, V7980,
+ V7981, V7982, V7983, V7984, V7985, V7986, V7987, V7988,
+ }, // P[299]
+ {
+ V7989, V7990, V7991, V7992, V7993, V7994, V7995, V7996,
+ V7997, V7998, V7999, V8000, V8001, V8002, V8003, V8004,
+ V8005, V8006, V8007, V8008, V8009, V8010, V8011, V8012,
+ V8013, V8014, V8015, V8016, V8017, V8018, V8019, V8020,
+ }, // P[300]
+ {
+ V8021, V8022, V8023, V8024, V8025, V8026, V8027, V8028,
+ V8029, V8030, V8031, V8032, V8033, V8034, V8035, V8036,
+ V8037, V8038, V8039, V8040, V8041, V8042, V8043, V8044,
+ V8045, V8046, V8047, V8048, V8049, V8050, V8051, V8052,
+ }, // P[301]
+ {
+ V8053, V8054, V8055, V8056, V8057, V8058, V8059, V8060,
+ V8061, V8062, V8063, V8064, V8065, V8066, V8067, V8068,
+ V8069, V8070, V8071, V8072, V8073, V8074, V8075, V8076,
+ V8077, V8078, V8079, V8080, V8081, V8082, V8083, V8084,
+ }, // P[302]
+ {
+ V8085, V8086, V8087, V8088, V8089, V8090, V8091, V8092,
+ V8093, V8094, V8095, V8096, V8097, V8098, V8099, V8100,
+ V8101, V8102, V8103, V8104, V8105, V8106, V8107, V8108,
+ V8109, V8110, V8111, V8112, V8113, V8114, V8115, V8116,
+ }, // P[303]
+ {
+ V8117, V8118, V8119, V8120, V8121, V8122, V8123, V8124,
+ V8125, V8126, V8127, V8128, V8129, V8130, V8131, V8132,
+ V8133, V8134, V8135, V8136, V8137, V8138, V8139, V8140,
+ V8141, V8142, V8143, V8144, V8145, V8146, V8147, V8148,
+ }, // P[304]
+ {
+ V8149, V8150, V8151, V8152, V8153, V8154, V8155, V8156,
+ V8157, V8158, V8159, V8160, V8161, V8162, V8163, V8164,
+ V8165, V8166, V8167, V8168, V8169, V8170, V8171, V8172,
+ V8173, V8174, V8175, V8176, V8177, V8178, V8179, V8180,
+ }, // P[305]
+ {
+ V8181, V8182, V8183, V8184, V8185, V8186, V8187, V8188,
+ V8189, V8190, V8191, V8192, V8193, V8194, V8195, V8196,
+ V8197, V8198, V8199, V8200, V8201, V8202, V8203, V8204,
+ V8205, V8206, V8207, V8208, V8209, V8210, V8211, V8212,
+ }, // P[306]
+ {
+ V8213, V8214, V8215, V8216, V8217, V8218, V8219, V8220,
+ V8221, V8222, V8223, V8224, V8225, V8226, V8227, V8228,
+ V8229, V8230, V8231, V8232, V8233, V8234, V8235, V8236,
+ V8237, V8238, V8239, V8240, V8241, V8242, V8243, V8244,
+ }, // P[307]
+ {
+ V8245, V8246, V8247, V8248, V8249, V8250, V8251, V8252,
+ V8253, V8254, V8255, V8256, V8257, V8258, V8259, V8260,
+ V8261, V8262, V8263, V8264, V8265, V8266, V8267, V8268,
+ V8269, V8270, V8271, V8272, V8273, V8274, V8275, V8276,
+ }, // P[308]
+ {
+ V8277, V8278, V8279, V8280, V8281, V8282, V8283, V8284,
+ V8285, V8286, V8287, V8288, V8289, V8290, V8291, V8292,
+ V8293, V8294, V8295, V8296, V8297, V8298, V8299, V8300,
+ V8301, V8302, V8303, V8304, V8305, V8306, V8307, V8308,
+ }, // P[309]
+ {
+ V8309, V8310, V8311, V8312, V8313, V8314, V8315, V8316,
+ V8317, V8318, V8319, V8320, V8321, V8322, V8323, V8324,
+ V8325, V8326, V8327, V8328, V8329, V8330, V8331, V8332,
+ V8333, V8334, V8335, V8336, V8337, V8338, V8339, V8340,
+ }, // P[310]
+ {
+ V8341, V8342, V8343, V8344, V8345, V8346, V8347, V8348,
+ V8349, V8350, V8351, V8352, V8353, V8354, V8355, V8356,
+ V8357, V8358, V8359, V8360, V8361, V8362, V8363, V8364,
+ V8365, V8366, V8367, V8368, V8369, V8370, V8371, V8372,
+ }, // P[311]
+ {
+ V8373, V8374, V8375, V8376, V8377, V8378, V8379, V8380,
+ V8381, V8382, V8383, V8384, V8385, V8386, V8387, V8388,
+ V8389, V8390, V8391, V8392, V8393, V8394, V8395, V8396,
+ V8397, V8398, V8399, V8400, V8401, V8402, V8403, V8404,
+ }, // P[312]
+ {
+ V8405, V8406, V8407, V8408, V8409, V8410, V8411, V8412,
+ V8413, V8414, V8415, V8416, V8417, V8418, V8419, V8420,
+ V8421, V8422, V8423, V8424, V8425, V8426, V8427, V8428,
+ V8429, V8430, V8431, V8432, V8433, V8434, V8435, V8436,
+ }, // P[313]
+ {
+ V8437, V8438, V8439, V8440, V8441, V8442, V8443, V8444,
+ V8445, V8446, V8447, V8448, V8449, V8450, V8451, V8452,
+ V8453, V8454, V8455, V8456, V8457, V8458, V8459, V8460,
+ V8461, V8462, V8463, V8464, V8465, V8466, V8467, V8468,
+ }, // P[314]
+ {
+ V8469, V8470, V8471, V8472, V8473, V8474, V8475, V8476,
+ V8477, V8478, V8479, V8480, V8481, V8482, V8483, V8484,
+ V8485, V8486, V8487, V8488, V8489, V8490, V8491, V8492,
+ V8493, V8494, V8495, V8496, V8497, V8498, V8499, V8500,
+ }, // P[315]
+ {
+ V8501, V8502, V8503, V8504, V8505, V8506, V8507, V8508,
+ V8509, V8510, V8511, V8512, V8513, V8514, V8515, V8516,
+ V8517, V8518, V8519, V8520, V8521, V8522, V8523, V8524,
+ V8525, V8526, V8527, V8528, V8529, V8530, V8531, V8532,
+ }, // P[316]
+ {
+ V8533, V8534, V8535, V8536, V8537, V8538, V8539, V8540,
+ V8541, V8542, V8543, V8544, V8545, V8546, V8547, V8548,
+ V8549, V8550, V8551, V8552, V8553, V8554, V8555, V8556,
+ V8557, V8558, V8559, V8560, V8561, V8562, V8563, V8564,
+ }, // P[317]
+ {
+ V8565, V8566, V8567, V8568, V8569, V8570, V8571, V8572,
+ V8573, V8574, V8575, V8576, V8577, V8578, V8579, V8580,
+ V8581, V8582, V8583, V8584, V8585, V8586, V8587, V8588,
+ V8589, V8590, V8591, V8592, V8593, V8594, V8595, V8596,
+ }, // P[318]
+ {
+ V8597, V8598, V8599, V8600, V8601, V8602, V8603, V8604,
+ V8605, V8606, V8607, V8608, V8609, V8610, V8611, V8612,
+ V8613, V8614, V8615, V8616, V8617, V8618, V8619, V8620,
+ V8621, V8622, V8623, V8624, V8625, V8626, V8627, V8628,
+ }, // P[319]
+ {
+ V8629, V8630, V8631, V8632, V8633, V8634, V8635, V8636,
+ V8637, V8638, V8639, V8640, V8641, V8642, V8643, V8644,
+ V8645, V8646, V8647, V8648, V8649, V8650, V8651, V8652,
+ V8653, V8654, V8655, V8656, V8657, V8658, V8659, V8660,
+ }, // P[320]
+ {
+ V8661, V8662, V8663, V8664, V8665, V8666, V8667, V8668,
+ V8669, V8670, V8671, V8672, V8673, V8674, V8675, V8676,
+ V8677, V8678, V8679, V8680, V8681, V8682, V8683, V8684,
+ V8685, V8686, V8687, V8688, V8689, V8690, V8691, V8692,
+ }, // P[321]
+ {
+ V8693, V8694, V8695, V8696, V8697, V8698, V8699, V8700,
+ V8701, V8702, V8703, V8704, V8705, V8706, V8707, V8708,
+ V8709, V8710, V8711, V8712, V8713, V8714, V8715, V8716,
+ V8717, V8718, V8719, V8720, V8721, V8722, V8723, V8724,
+ }, // P[322]
+ {
+ V8725, V8726, V8727, V8728, V8729, V8730, V8731, V8732,
+ V8733, V8734, V8735, V8736, V8737, V8738, V8739, V8740,
+ V8741, V8742, V8743, V8744, V8745, V8746, V8747, V8748,
+ V8749, V8750, V8751, V8752, V8753, V8754, V8755, V8756,
+ }, // P[323]
+ {
+ V8757, V8758, V8759, V8760, V8761, V8762, V8763, V8764,
+ V8765, V8766, V8767, V8768, V8769, V8770, V8771, V8772,
+ V8773, V8774, V8775, V8776, V8777, V8778, V8779, V8780,
+ V8781, V8782, V8783, V8784, V8785, V8786, V8787, V8788,
+ }, // P[324]
+ {
+ V8789, V8790, V8791, V8792, V8793, V8794, V8795, V8796,
+ V8797, V8798, V8799, V8800, V8801, V8802, V8803, V8804,
+ V8805, V8806, V8807, V8808, V8809, V8810, V8811, V8812,
+ V8813, V8814, V8815, V8816, V8817, V8818, V8819, V8820,
+ }, // P[325]
+ {
+ V8821, V8822, V8823, V8824, V8825, V8826, V8827, V8828,
+ V8829, V8830, V8831, V8832, V8833, V8834, V8835, V8836,
+ V8837, V8838, V8839, V8840, V8841, V8842, V8843, V8844,
+ V8845, V8846, V8847, V8848, V8849, V8850, V8851, V8852,
+ }, // P[326]
+ {
+ V8853, V8854, V8855, V8856, V8857, V8858, V8859, V8860,
+ V8861, V8862, V8863, V8864, V8865, V8866, V8867, V8868,
+ V8869, V8870, V8871, V8872, V8873, V8874, V8875, V8876,
+ V8877, V8878, V8879, V8880, V8881, V8882, V8883, V8884,
+ }, // P[327]
+ {
+ V8885, V8886, V8887, V8888, V8889, V8890, V8891, V8892,
+ V8893, V8894, V8895, V8896, V8897, V8898, V8899, V8900,
+ V8901, V8902, V8903, V8904, V8905, V8906, V8907, V8908,
+ V8909, V8910, V8911, V8912, V8913, V8914, V8915, V8916,
+ }, // P[328]
+ {
+ V8917, V8918, V8919, V8920, V8921, V8922, V8923, V8924,
+ V8925, V8926, V8927, V8928, V8929, V8930, V8931, V8932,
+ V8933, V8934, V8935, V8936, V8937, V8938, V8939, V8940,
+ V8941, V8942, V8943, V8944, V8945, V8946, V8947, V8948,
+ }, // P[329]
+ {
+ V8949, V8950, V8951, V8952, V8953, V8954, V8955, V8956,
+ V8957, V8958, V8959, V8960, V8961, V8962, V8963, V8964,
+ V8965, V8966, V8967, V8968, V8969, V8970, V8971, V8972,
+ V8973, V8974, V8975, V8976, V8977, V8978, V8979, V8980,
+ }, // P[330]
+ {
+ V8981, V8982, V8983, V8984, V8985, V8986, V8987, V8988,
+ V8989, V8990, V8991, V8992, V8993, V8994, V8995, V8996,
+ V8997, V8998, V8999, V9000, V9001, V9002, V9003, V9004,
+ V9005, V9006, V9007, V9008, V9009, V9010, V9011, V9012,
+ }, // P[331]
+ {
+ V9013, V9014, V9015, V9016, V9017, V9018, V9019, V9020,
+ V9021, V9022, V9023, V9024, V9025, V9026, V9027, V9028,
+ V9029, V9030, V9031, V9032, V9033, V9034, V9035, V9036,
+ V9037, V9038, V9039, V9040, V9041, V9042, V9043, V9044,
+ }, // P[332]
+ {
+ V9045, V9046, V9047, V9048, V9049, V9050, V9051, V9052,
+ V9053, V9054, V9055, V9056, V9057, V9058, V9059, V9060,
+ V9061, V9062, V9063, V9064, V9065, V9066, V9067, V9068,
+ V9069, V9070, V9071, V9072, V9073, V9074, V9075, V9076,
+ }, // P[333]
+ {
+ V9077, V9078, V9079, V9080, V9081, V9082, V9083, V9084,
+ V9085, V9086, V9087, V9088, V9089, V9090, V9091, V9092,
+ V9093, V9094, V9095, V9096, V9097, V9098, V9099, V9100,
+ V9101, V9102, V9103, V9104, V9105, V9106, V9107, V9108,
+ }, // P[334]
+ {
+ V9109, V9110, V9111, V9112, V9113, V9114, V9115, V9116,
+ V9117, V9118, V9119, V9120, V9121, V9122, V9123, V9124,
+ V9125, V9126, V9127, V9128, V9129, V9130, V9131, V9132,
+ V9133, V9134, V9135, V9136, V9137, V9138, V9139, V9140,
+ }, // P[335]
+ {
+ V9141, V9142, V9143, V9144, V9145, V9146, V9147, V9148,
+ V9149, V9150, V9151, V9152, V9153, V9154, V9155, V9156,
+ V9157, V9158, V9159, V9160, V9161, V9162, V9163, V9164,
+ V9165, V9166, V9167, V9168, V9169, V9170, V9171, V9172,
+ }, // P[336]
+ {
+ V9173, V9174, V9175, V9176, V9177, V9178, V9179, V9180,
+ V9181, V9182, V9183, V9184, V9185, V9186, V9187, V9188,
+ V9189, V9190, V9191, V9192, V9193, V9194, V9195, V9196,
+ V9197, V9198, V9199, V9200, V9201, V9202, V9203, V9204,
+ }, // P[337]
+ {
+ V9205, V9206, V9207, V9208, V9209, V9210, V9211, V9212,
+ V9213, V9214, V9215, V9216, V9217, V9218, V9219, V9220,
+ V9221, V9222, V9223, V9224, V9225, V9226, V9227, V9228,
+ V9229, V9230, V9231, V9232, V9233, V9234, V9235, V9236,
+ }, // P[338]
+ {
+ V9237, V9238, V9239, V9240, V9241, V9242, V9243, V9244,
+ V9245, V9246, V9247, V9248, V9249, V9250, V9251, V9252,
+ V9253, V9254, V9255, V9256, V9257, V9258, V9259, V9260,
+ V9261, V9262, V9263, V9264, V9265, V9266, V9267, V9268,
+ }, // P[339]
+ {
+ V9269, V9270, V9271, V9272, V9273, V9274, V9275, V9276,
+ V9277, V9278, V9279, V9280, V9281, V9282, V9283, V9284,
+ V9285, V9286, V9287, V9288, V9289, V9290, V9291, V9292,
+ V9293, V9294, V9295, V9296, V9297, V9298, V9299, V9300,
+ }, // P[340]
+ {
+ V9301, V9302, V9303, V9304, V9305, V9306, V9307, V9308,
+ V9309, V9310, V9311, V9312, V9313, V9314, V9315, V9316,
+ V9317, V9318, V9319, V9320, V9321, V9322, V9323, V9324,
+ V9325, V9326, V9327, V9328, V9329, V9330, V9331, V9332,
+ }, // P[341]
+ {
+ V9333, V9334, V9335, V9336, V9337, V9338, V9339, V9340,
+ V9341, V9342, V9343, V9344, V9345, V9346, V9347, V9348,
+ V9349, V9350, V9351, V9352, V9353, V9354, V9355, V9356,
+ V9357, V9358, V9359, V9360, V9361, V9362, V9363, V9364,
+ }, // P[342]
+ {
+ V9365, V9366, V9367, V9368, V9369, V9370, V9371, V9372,
+ V9373, V9374, V9375, V9376, V9377, V9378, V9379, V9380,
+ V9381, V9382, V9383, V9384, V9385, V9386, V9387, V9388,
+ V9389, V9390, V9391, V9392, V9393, V9394, V9395, V9396,
+ }, // P[343]
+ {
+ V9397, V9398, V9399, V9400, V9401, V9402, V9403, V9404,
+ V9405, V9406, V9407, V9408, V9409, V9410, V9411, V9412,
+ V9413, V9414, V9415, V9416, V9417, V9418, V9419, V9420,
+ V9421, V9422, V9423, V9424, V9425, V9426, V9427, V9428,
+ }, // P[344]
+ {
+ V9429, V9430, V9431, V9432, V9433, V9434, V9435, V9436,
+ V9437, V9438, V9439, V9440, V9441, V9442, V9443, V9444,
+ V9445, V9446, V9447, V9448, V9449, V9450, V9451, V9452,
+ V9453, V9454, V9455, V9456, V9457, V9458, V9459, V9460,
+ }, // P[345]
+ {
+ V9461, V9462, V9463, V9464, V9465, V9466, V9467, V9468,
+ V9469, V9470, V9471, V9472, V9473, V9474, V9475, V9476,
+ V9477, V9478, V9479, V9480, V9481, V9482, V9483, V9484,
+ V9485, V9486, V9487, V9488, V9489, V9490, V9491, V9492,
+ }, // P[346]
+ {
+ V9493, V9494, V9495, V9496, V9497, V9498, V9499, V9500,
+ V9501, V9502, V9503, V9504, V9505, V9506, V9507, V9508,
+ V9509, V9510, V9511, V9512, V9513, V9514, V9515, V9516,
+ V9517, V9518, V9519, V9520, V9521, V9522, V9523, V9524,
+ }, // P[347]
+ {
+ V9525, V9526, V9527, V9528, V9529, V9530, V9531, V9532,
+ V9533, V9534, V9535, V9536, V9537, V9538, V9539, V9540,
+ V9541, V9542, V9543, V9544, V9545, V9546, V9547, V9548,
+ V9549, V9550, V9551, V9552, V9553, V9554, V9555, V9556,
+ }, // P[348]
+ {
+ V9557, V9558, V9559, V9560, V9561, V9562, V9563, V9564,
+ V9565, V9566, V9567, V9568, V9569, V9570, V9571, V9572,
+ V9573, V9574, V9575, V9576, V9577, V9578, V9579, V9580,
+ V9581, V9582, V9583, V9584, V9585, V9586, V9587, V9588,
+ }, // P[349]
+ {
+ V9589, V9590, V9591, V9592, V9593, V9594, V9595, V9596,
+ V9597, V9598, V9599, V9600, V9601, V9602, V9603, V9604,
+ V9605, V9606, V9607, V9608, V9609, V9610, V9611, V9612,
+ V9613, V9614, V9615, V9616, V9617, V9618, V9619, V9620,
+ }, // P[350]
+ {
+ V9621, V9622, V9623, V9624, V9625, V9626, V9627, V9628,
+ V9629, V9630, V9631, V9632, V9633, V9634, V9635, V9636,
+ V9637, V9638, V9639, V9640, V9641, V9642, V9643, V9644,
+ V9645, V9646, V9647, V9648, V9649, V9650, V9651, V9652,
+ }, // P[351]
+ {
+ V9653, V9654, V9655, V9656, V9657, V9658, V9659, V9660,
+ V9661, V9662, V9663, V9664, V9665, V9666, V9667, V9668,
+ V9669, V9670, V9671, V9672, V9673, V9674, V9675, V9676,
+ V9677, V9678, V9679, V9680, V9681, V9682, V9683, V9684,
+ }, // P[352]
+ {
+ V9685, V9686, V9687, V9688, V9689, V9690, V9691, V9692,
+ V9693, V9694, V9695, V9696, V9697, V9698, V9699, V9700,
+ V9701, V9702, V9703, V9704, V9705, V9706, V9707, V9708,
+ V9709, V9710, V9711, V9712, V9713, V9714, V9715, V9716,
+ }, // P[353]
+ {
+ V9717, V9718, V9719, V9720, V9721, V9722, V9723, V9724,
+ V9725, V9726, V9727, V9728, V9729, V9730, V9731, V9732,
+ V9733, V9734, V9735, V9736, V9737, V9738, V9739, V9740,
+ V9741, V9742, V9743, V9744, V9745, V9746, V9747, V9748,
+ }, // P[354]
+ {
+ V9749, V9750, V9751, V9752, V9753, V9754, V9755, V9756,
+ V9757, V9758, V9759, V9760, V9761, V9762, V9763, V9764,
+ V9765, V9766, V9767, V9768, V9769, V9770, V9771, V9772,
+ V9773, V9774, V9775, V9776, V9777, V9778, V9779, V9780,
+ }, // P[355]
+ {
+ V9781, V9782, V9783, V9784, V9785, V9786, V9787, V9788,
+ V9789, V9790, V9791, V9792, V9793, V9794, V9795, V9796,
+ V9797, V9798, V9799, V9800, V9801, V9802, V9803, V9804,
+ V9805, V9806, V9807, V9808, V9809, V9810, V9811, V9812,
+ }, // P[356]
+ {
+ V9813, V9814, V9815, V9816, V9817, V9818, V9819, V9820,
+ V9821, V9822, V9823, V9824, V9825, V9826, V9827, V9828,
+ V9829, V9830, V9831, V9832, V9833, V9834, V9835, V9836,
+ V9837, V9838, V9839, V9840, V9841, V9842, V9843, V9844,
+ }, // P[357]
+ {
+ V9845, V9846, V9847, V9848, V9849, V9850, V9851, V9852,
+ V9853, V9854, V9855, V9856, V9857, V9858, V9859, V9860,
+ V9861, V9862, V9863, V9864, V9865, V9866, V9867, V9868,
+ V9869, V9870, V9871, V9872, V9873, V9874, V9875, V9876,
+ }, // P[358]
+ {
+ V9877, V9878, V9879, V9880, V9881, V9882, V9883, V9884,
+ V9885, V9886, V9887, V9888, V9889, V9890, V9891, V9892,
+ V9893, V9894, V9895, V9896, V9897, V9898, V9899, V9900,
+ V9901, V9902, V9903, V9904, V9905, V9906, V9907, V9908,
+ }, // P[359]
+ {
+ V9909, V9910, V9911, V9912, V9913, V9914, V9915, V9916,
+ V9917, V9918, V9919, V9920, V9921, V9922, V9923, V9924,
+ V9925, V9926, V9927, V9928, V9929, V9930, V9931, V9932,
+ V9933, V9934, V9935, V9936, V9937, V9938, V9939, V9940,
+ }, // P[360]
+ {
+ V9941, V9942, V9943, V9944, V9945, V9946, V9947, V9948,
+ V9949, V9950, V9951, V9952, V9953, V9954, V9955, V9956,
+ V9957, V9958, V9959, V9960, V9961, V9962, V9963, V9964,
+ V9965, V9966, V9967, V9968, V9969, V9970, V9971, V9972,
+ }, // P[361]
+ {
+ V9973, V9974, V9975, V9976, V9977, V9978, V9979, V9980,
+ V9981, V9982, V9983, V9984, V9985, V9986, V9987, V9988,
+ V9989, V9990, V9991, V9992, V9993, V9994, V9995, V9996,
+ V9997, V9998, V9999, V10000, V10001, V10002, V10003, V10004,
+ }, // P[362]
+ {
+ V10005, V10006, V10007, V10008, V10009, V10010, V10011, V10012,
+ V10013, V10014, V10015, V10016, V10017, V10018, V10019, V10020,
+ V10021, V10022, V10023, V10024, V10025, V10026, V10027, V10028,
+ V10029, V10030, V10031, V10032, V10033, V10034, V10035, V10036,
+ }, // P[363]
+ {
+ V10037, V10038, V10039, V10040, V10041, V10042, V10043, V10044,
+ V10045, V10046, V10047, V10048, V10049, V10050, V10051, V10052,
+ V10053, V10054, V10055, V10056, V10057, V10058, V10059, V10060,
+ V10061, V10062, V10063, V10064, V10065, V10066, V10067, V10068,
+ }, // P[364]
+ {
+ V10069, V10070, V10071, V10072, V10073, V10074, V10075, V10076,
+ V10077, V10078, V10079, V10080, V10081, V10082, V10083, V10084,
+ V10085, V10086, V10087, V10088, V10089, V10090, V10091, V10092,
+ V10093, V10094, V10095, V10096, V10097, V10098, V10099, V10100,
+ }, // P[365]
+ {
+ V10101, V10102, V10103, V10104, V10105, V10106, V10107, V10108,
+ V10109, V10110, V10111, V10112, V10113, V10114, V10115, V10116,
+ V10117, V10118, V10119, V10120, V10121, V10122, V10123, V10124,
+ V10125, V10126, V10127, V10128, V10129, V10130, V10131, V10132,
+ }, // P[366]
+ {
+ V10133, V10134, V10135, V10136, V10137, V10138, V10139, V10140,
+ V10141, V10142, V10143, V10144, V10145, V10146, V10147, V10148,
+ V10149, V10150, V10151, V10152, V10153, V10154, V10155, V10156,
+ V10157, V10158, V10159, V10160, V10161, V10162, V10163, V10164,
+ }, // P[367]
+ {
+ V10165, V10166, V10167, V10168, V10169, V10170, V10171, V10172,
+ V10173, V10174, V10175, V10176, V10177, V10178, V10179, V10180,
+ V10181, V10182, V10183, V10184, V10185, V10186, V10187, V10188,
+ V10189, V10190, V10191, V10192, V10193, V10194, V10195, V10196,
+ }, // P[368]
+ {
+ V10197, V10198, V10199, V10200, V10201, V10202, V10203, V10204,
+ V10205, V10206, V10207, V10208, V10209, V10210, V10211, V10212,
+ V10213, V10214, V10215, V10216, V10217, V10218, V10219, V10220,
+ V10221, V10222, V10223, V10224, V10225, V10226, V10227, V10228,
+ }, // P[369]
+ {
+ V10229, V10230, V10231, V10232, V10233, V10234, V10235, V10236,
+ V10237, V10238, V10239, V10240, V10241, V10242, V10243, V10244,
+ V10245, V10246, V10247, V10248, V10249, V10250, V10251, V10252,
+ V10253, V10254, V10255, V10256, V10257, V10258, V10259, V10260,
+ }, // P[370]
+ {
+ V10261, V10262, V10263, V10264, V10265, V10266, V10267, V10268,
+ V10269, V10270, V10271, V10272, V10273, V10274, V10275, V10276,
+ V10277, V10278, V10279, V10280, V10281, V10282, V10283, V10284,
+ V10285, V10286, V10287, V10288, V10289, V10290, V10291, V10292,
+ }, // P[371]
+ {
+ V10293, V10294, V10295, V10296, V10297, V10298, V10299, V10300,
+ V10301, V10302, V10303, V10304, V10305, V10306, V10307, V10308,
+ V10309, V10310, V10311, V10312, V10313, V10314, V10315, V10316,
+ V10317, V10318, V10319, V10320, V10321, V10322, V10323, V10324,
+ }, // P[372]
+ {
+ V10325, V10326, V10327, V10328, V10329, V10330, V10331, V10332,
+ V10333, V10334, V10335, V10336, V10337, V10338, V10339, V10340,
+ V10341, V10342, V10343, V10344, V10345, V10346, V10347, V10348,
+ V10349, V10350, V10351, V10352, V10353, V10354, V10355, V10356,
+ }, // P[373]
+ {
+ V10357, V10358, V10359, V10360, V10361, V10362, V10363, V10364,
+ V10365, V10366, V10367, V10368, V10369, V10370, V10371, V10372,
+ V10373, V10374, V10375, V10376, V10377, V10378, V10379, V10380,
+ V10381, V10382, V10383, V10384, V10385, V10386, V10387, V10388,
+ }, // P[374]
+ {
+ V10389, V10390, V10391, V10392, V10393, V10394, V10395, V10396,
+ V10397, V10398, V10399, V10400, V10401, V10402, V10403, V10404,
+ V10405, V10406, V10407, V10408, V10409, V10410, V10411, V10412,
+ V10413, V10414, V10415, V10416, V10417, V10418, V10419, V10420,
+ }, // P[375]
+ {
+ V10421, V10422, V10423, V10424, V10425, V10426, V10427, V10428,
+ V10429, V10430, V10431, V10432, V10433, V10434, V10435, V10436,
+ V10437, V10438, V10439, V10440, V10441, V10442, V10443, V10444,
+ V10445, V10446, V10447, V10448, V10449, V10450, V10451, V10452,
+ }, // P[376]
+ {
+ V10453, V10454, V10455, V10456, V10457, V10458, V10459, V10460,
+ V10461, V10462, V10463, V10464, V10465, V10466, V10467, V10468,
+ V10469, V10470, V10471, V10472, V10473, V10474, V10475, V10476,
+ V10477, V10478, V10479, V10480, V10481, V10482, V10483, V10484,
+ }, // P[377]
+ {
+ V10485, V10486, V10487, V10488, V10489, V10490, V10491, V10492,
+ V10493, V10494, V10495, V10496, V10497, V10498, V10499, V10500,
+ V10501, V10502, V10503, V10504, V10505, V10506, V10507, V10508,
+ V10509, V10510, V10511, V10512, V10513, V10514, V10515, V10516,
+ }, // P[378]
+ {
+ V10517, V10518, V10519, V10520, V10521, V10522, V10523, V10524,
+ V10525, V10526, V10527, V10528, V10529, V10530, V10531, V10532,
+ V10533, V10534, V10535, V10536, V10537, V10538, V10539, V10540,
+ V10541, V10542, V10543, V10544, V10545, V10546, V10547, V10548,
+ }, // P[379]
+ {
+ V10549, V10550, V10551, V10552, V10553, V10554, V10555, V10556,
+ V10557, V10558, V10559, V10560, V10561, V10562, V10563, V10564,
+ V10565, V10566, V10567, V10568, V10569, V10570, V10571, V10572,
+ V10573, V10574, V10575, V10576, V10577, V10578, V10579, V10580,
+ }, // P[380]
+ {
+ V10581, V10582, V10583, V10584, V10585, V10586, V10587, V10588,
+ V10589, V10590, V10591, V10592, V10593, V10594, V10595, V10596,
+ V10597, V10598, V10599, V10600, V10601, V10602, V10603, V10604,
+ V10605, V10606, V10607, V10608, V10609, V10610, V10611, V10612,
+ }, // P[381]
+ {
+ V10613, V10614, V10615, V10616, V10617, V10618, V10619, V10620,
+ V10621, V10622, V10623, V10624, V10625, V10626, V10627, V10628,
+ V10629, V10630, V10631, V10632, V10633, V10634, V10635, V10636,
+ V10637, V10638, V10639, V10640, V10641, V10642, V10643, V10644,
+ }, // P[382]
+ {
+ V10645, V10646, V10647, V10648, V10649, V10650, V10651, V10652,
+ V10653, V10654, V10655, V10656, V10657, V10658, V10659, V10660,
+ V10661, V10662, V10663, V10664, V10665, V10666, V10667, V10668,
+ V10669, V10670, V10671, V10672, V10673, V10674, V10675, V10676,
+ }, // P[383]
+ {
+ V10677, V10678, V10679, V10680, V10681, V10682, V10683, V10684,
+ V10685, V10686, V10687, V10688, V10689, V10690, V10691, V10692,
+ V10693, V10694, V10695, V10696, V10697, V10698, V10699, V10700,
+ V10701, V10702, V10703, V10704, V10705, V10706, V10707, V10708,
+ }, // P[384]
+ {
+ V10709, V10710, V10711, V10712, V10713, V10714, V10715, V10716,
+ V10717, V10718, V10719, V10720, V10721, V10722, V10723, V10724,
+ V10725, V10726, V10727, V10728, V10729, V10730, V10731, V10732,
+ V10733, V10734, V10735, V10736, V10737, V10738, V10739, V10740,
+ }, // P[385]
+ {
+ V10741, V10742, V10743, V10744, V10745, V10746, V10747, V10748,
+ V10749, V10750, V10751, V10752, V10753, V10754, V10755, V10756,
+ V10757, V10758, V10759, V10760, V10761, V10762, V10763, V10764,
+ V10765, V10766, V10767, V10768, V10769, V10770, V10771, V10772,
+ }, // P[386]
+ {
+ V10773, V10774, V10775, V10776, V10777, V10778, V10779, V10780,
+ V10781, V10782, V10783, V10784, V10785, V10786, V10787, V10788,
+ V10789, V10790, V10791, V10792, V10793, V10794, V10795, V10796,
+ V10797, V10798, V10799, V10800, V10801, V10802, V10803, V10804,
+ }, // P[387]
+ {
+ V10805, V10806, V10807, V10808, V10809, V10810, V10811, V10812,
+ V10813, V10814, V10815, V10816, V10817, V10818, V10819, V10820,
+ V10821, V10822, V10823, V10824, V10825, V10826, V10827, V10828,
+ V10829, V10830, V10831, V10832, V10833, V10834, V10835, V10836,
+ }, // P[388]
+ {
+ V10837, V10838, V10839, V10840, V10841, V10842, V10843, V10844,
+ V10845, V10846, V10847, V10848, V10849, V10850, V10851, V10852,
+ V10853, V10854, V10855, V10856, V10857, V10858, V10859, V10860,
+ V10861, V10862, V10863, V10864, V10865, V10866, V10867, V10868,
+ }, // P[389]
+ {
+ V10869, V10870, V10871, V10872, V10873, V10874, V10875, V10876,
+ V10877, V10878, V10879, V10880, V10881, V10882, V10883, V10884,
+ V10885, V10886, V10887, V10888, V10889, V10890, V10891, V10892,
+ V10893, V10894, V10895, V10896, V10897, V10898, V10899, V10900,
+ }, // P[390]
+ {
+ V10901, V10902, V10903, V10904, V10905, V10906, V10907, V10908,
+ V10909, V10910, V10911, V10912, V10913, V10914, V10915, V10916,
+ V10917, V10918, V10919, V10920, V10921, V10922, V10923, V10924,
+ V10925, V10926, V10927, V10928, V10929, V10930, V10931, V10932,
+ }, // P[391]
+ {
+ V10933, V10934, V10935, V10936, V10937, V10938, V10939, V10940,
+ V10941, V10942, V10943, V10944, V10945, V10946, V10947, V10948,
+ V10949, V10950, V10951, V10952, V10953, V10954, V10955, V10956,
+ V10957, V10958, V10959, V10960, V10961, V10962, V10963, V10964,
+ }, // P[392]
+ {
+ V10965, V10966, V10967, V10968, V10969, V10970, V10971, V10972,
+ V10973, V10974, V10975, V10976, V10977, V10978, V10979, V10980,
+ V10981, V10982, V10983, V10984, V10985, V10986, V10987, V10988,
+ V10989, V10990, V10991, V10992, V10993, V10994, V10995, V10996,
+ }, // P[393]
+ {
+ V10997, V10998, V10999, V11000, V11001, V11002, V11003, V11004,
+ V11005, V11006, V11007, V11008, V11009, V11010, V11011, V11012,
+ V11013, V11014, V11015, V11016, V11017, V11018, V11019, V11020,
+ V11021, V11022, V11023, V11024, V11025, V11026, V11027, V11028,
+ }, // P[394]
+ {
+ V11029, V11030, V11031, V11032, V11033, V11034, V11035, V11036,
+ V11037, V11038, V11039, V11040, V11041, V11042, V11043, V11044,
+ V11045, V11046, V11047, V11048, V11049, V11050, V11051, V11052,
+ V11053, V11054, V11055, V11056, V11057, V11058, V11059, V11060,
+ }, // P[395]
+ {
+ V11061, V11062, V11063, V11064, V11065, V11066, V11067, V11068,
+ V11069, V11070, V11071, V11072, V11073, V11074, V11075, V11076,
+ V11077, V11078, V11079, V11080, V11081, V11082, V11083, V11084,
+ V11085, V11086, V11087, V11088, V11089, V11090, V11091, V11092,
+ }, // P[396]
+ {
+ V11093, V11094, V11095, V11096, V11097, V11098, V11099, V11100,
+ V11101, V11102, V11103, V11104, V11105, V11106, V11107, V11108,
+ V11109, V11110, V11111, V11112, V11113, V11114, V11115, V11116,
+ V11117, V11118, V11119, V11120, V11121, V11122, V11123, V11124,
+ }, // P[397]
+ {
+ V11125, V11126, V11127, V11128, V11129, V11130, V11131, V11132,
+ V11133, V11134, V11135, V11136, V11137, V11138, V11139, V11140,
+ V11141, V11142, V11143, V11144, V11145, V11146, V11147, V11148,
+ V11149, V11150, V11151, V11152, V11153, V11154, V11155, V11156,
+ }, // P[398]
+ {
+ V11157, V11158, V11159, V11160, V11161, V11162, V11163, V11164,
+ V11165, V11166, V11167, V11168, V11169, V11170, V11171, V11172,
+ V11173, V11174, V11175, V11176, V11177, V11178, V11179, V11180,
+ V11181, V11182, V11183, V11184, V11185, V11186, V11187, V11188,
+ }, // P[399]
+ {
+ V11189, V11190, V11191, V11192, V11193, V11194, V11195, V11196,
+ V11197, V11198, V11199, V11200, V11201, V11202, V11203, V11204,
+ V11205, V11206, V11207, V11208, V11209, V11210, V11211, V11212,
+ V11213, V11214, V11215, V11216, V11217, V11218, V11219, V11220,
+ }, // P[400]
+ {
+ V11221, V11222, V11223, V11224, V11225, V11226, V11227, V11228,
+ V11229, V11230, V11231, V11232, V11233, V11234, V11235, V11236,
+ V11237, V11238, V11239, V11240, V11241, V11242, V11243, V11244,
+ V11245, V11246, V11247, V11248, V11249, V11250, V11251, V11252,
+ }, // P[401]
+ {
+ V11253, V11254, V11255, V11256, V11257, V11258, V11259, V11260,
+ V11261, V11262, V11263, V11264, V11265, V11266, V11267, V11268,
+ V11269, V11270, V11271, V11272, V11273, V11274, V11275, V11276,
+ V11277, V11278, V11279, V11280, V11281, V11282, V11283, V11284,
+ }, // P[402]
+ {
+ V11285, V11286, V11287, V11288, V11289, V11290, V11291, V11292,
+ V11293, V11294, V11295, V11296, V11297, V11298, V11299, V11300,
+ V11301, V11302, V11303, V11304, V11305, V11306, V11307, V11308,
+ V11309, V11310, V11311, V11312, V11313, V11314, V11315, V11316,
+ }, // P[403]
+ {
+ V11317, V11318, V11319, V11320, V11321, V11322, V11323, V11324,
+ V11325, V11326, V11327, V11328, V11329, V11330, V11331, V11332,
+ V11333, V11334, V11335, V11336, V11337, V11338, V11339, V11340,
+ V11341, V11342, V11343, V11344, V11345, V11346, V11347, V11348,
+ }, // P[404]
+ {
+ V11349, V11350, V11351, V11352, V11353, V11354, V11355, V11356,
+ V11357, V11358, V11359, V11360, V11361, V11362, V11363, V11364,
+ V11365, V11366, V11367, V11368, V11369, V11370, V11371, V11372,
+ V11373, V11374, V11375, V11376, V11377, V11378, V11379, V11380,
+ }, // P[405]
+ {
+ V11381, V11382, V11383, V11384, V11385, V11386, V11387, V11388,
+ V11389, V11390, V11391, V11392, V11393, V11394, V11395, V11396,
+ V11397, V11398, V11399, V11400, V11401, V11402, V11403, V11404,
+ V11405, V11406, V11407, V11408, V11409, V11410, V11411, V11412,
+ }, // P[406]
+ {
+ V11413, V11414, V11415, V11416, V11417, V11418, V11419, V11420,
+ V11421, V11422, V11423, V11424, V11425, V11426, V11427, V11428,
+ V11429, V11430, V11431, V11432, V11433, V11434, V11435, V11436,
+ V11437, V11438, V11439, V11440, V11441, V11442, V11443, V11444,
+ }, // P[407]
+ {
+ V11445, V11446, V11447, V11448, V11449, V11450, V11451, V11452,
+ V11453, V11454, V11455, V11456, V11457, V11458, V11459, V11460,
+ V11461, V11462, V11463, V11464, V11465, V11466, V11467, V11468,
+ V11469, V11470, V11471, V11472, V11473, V11474, V11475, V11476,
+ }, // P[408]
+ {
+ V11477, V11478, V11479, V11480, V11481, V11482, V11483, V11484,
+ V11485, V11486, V11487, V11488, V11489, V11490, V11491, V11492,
+ V11493, V11494, V11495, V11496, V11497, V11498, V11499, V11500,
+ V11501, V11502, V11503, V11504, V11505, V11506, V11507, V11508,
+ }, // P[409]
+ {
+ V11509, V11510, V11511, V11512, V11513, V11514, V11515, V11516,
+ V11517, V11518, V11519, V11520, V11521, V11522, V11523, V11524,
+ V11525, V11526, V11527, V11528, V11529, V11530, V11531, V11532,
+ V11533, V11534, V11535, V11536, V11537, V11538, V11539, V11540,
+ }, // P[410]
+ {
+ V11541, V11542, V11543, V11544, V11545, V11546, V11547, V11548,
+ V11549, V11550, V11551, V11552, V11553, V11554, V11555, V11556,
+ V11557, V11558, V11559, V11560, V11561, V11562, V11563, V11564,
+ V11565, V11566, V11567, V11568, V11569, V11570, V11571, V11572,
+ }, // P[411]
+ {
+ V11573, V11574, V11575, V11576, V11577, V11578, V11579, V11580,
+ V11581, V11582, V11583, V11584, V11585, V11586, V11587, V11588,
+ V11589, V11590, V11591, V11592, V11593, V11594, V11595, V11596,
+ V11597, V11598, V11599, V11600, V11601, V11602, V11603, V11604,
+ }, // P[412]
+ {
+ V11605, V11606, V11607, V11608, V11609, V11610, V11611, V11612,
+ V11613, V11614, V11615, V11616, V11617, V11618, V11619, V11620,
+ V11621, V11622, V11623, V11624, V11625, V11626, V11627, V11628,
+ V11629, V11630, V11631, V11632, V11633, V11634, V11635, V11636,
+ }, // P[413]
+ {
+ V11637, V11638, V11639, V11640, V11641, V11642, V11643, V11644,
+ V11645, V11646, V11647, V11648, V11649, V11650, V11651, V11652,
+ V11653, V11654, V11655, V11656, V11657, V11658, V11659, V11660,
+ V11661, V11662, V11663, V11664, V11665, V11666, V11667, V11668,
+ }, // P[414]
+ {
+ V11669, V11670, V11671, V11672, V11673, V11674, V11675, V11676,
+ V11677, V11678, V11679, V11680, V11681, V11682, V11683, V11684,
+ V11685, V11686, V11687, V11688, V11689, V11690, V11691, V11692,
+ V11693, V11694, V11695, V11696, V11697, V11698, V11699, V11700,
+ }, // P[415]
+ {
+ V11701, V11702, V11703, V11704, V11705, V11706, V11707, V11708,
+ V11709, V11710, V11711, V11712, V11713, V11714, V11715, V11716,
+ V11717, V11718, V11719, V11720, V11721, V11722, V11723, V11724,
+ V11725, V11726, V11727, V11728, V11729, V11730, V11731, V11732,
+ }, // P[416]
+ {
+ V11733, V11734, V11735, V11736, V11737, V11738, V11739, V11740,
+ V11741, V11742, V11743, V11744, V11745, V11746, V11747, V11748,
+ V11749, V11750, V11751, V11752, V11753, V11754, V11755, V11756,
+ V11757, V11758, V11759, V11760, V11761, V11762, V11763, V11764,
+ }, // P[417]
+ {
+ V11765, V11766, V11767, V11768, V11769, V11770, V11771, V11772,
+ V11773, V11774, V11775, V11776, V11777, V11778, V11779, V11780,
+ V11781, V11782, V11783, V11784, V11785, V11786, V11787, V11788,
+ V11789, V11790, V11791, V11792, V11793, V11794, V11795, V11796,
+ }, // P[418]
+ {
+ V11797, V11798, V11799, V11800, V11801, V11802, V11803, V11804,
+ V11805, V11806, V11807, V11808, V11809, V11810, V11811, V11812,
+ V11813, V11814, V11815, V11816, V11817, V11818, V11819, V11820,
+ V11821, V11822, V11823, V11824, V11825, V11826, V11827, V11828,
+ }, // P[419]
+ {
+ V11829, V11830, V11831, V11832, V11833, V11834, V11835, V11836,
+ V11837, V11838, V11839, V11840, V11841, V11842, V11843, V11844,
+ V11845, V11846, V11847, V11848, V11849, V11850, V11851, V11852,
+ V11853, V11854, V11855, V11856, V11857, V11858, V11859, V11860,
+ }, // P[420]
+ {
+ V11861, V11862, V11863, V11864, V11865, V11866, V11867, V11868,
+ V11869, V11870, V11871, V11872, V11873, V11874, V11875, V11876,
+ V11877, V11878, V11879, V11880, V11881, V11882, V11883, V11884,
+ V11885, V11886, V11887, V11888, V11889, V11890, V11891, V11892,
+ }, // P[421]
+ {
+ V11893, V11894, V11895, V11896, V11897, V11898, V11899, V11900,
+ V11901, V11902, V11903, V11904, V11905, V11906, V11907, V11908,
+ V11909, V11910, V11911, V11912, V11913, V11914, V11915, V11916,
+ V11917, V11918, V11919, V11920, V11921, V11922, V11923, V11924,
+ }, // P[422]
+ {
+ V11925, V11926, V11927, V11928, V11929, V11930, V11931, V11932,
+ V11933, V11934, V11935, V11936, V11937, V11938, V11939, V11940,
+ V11941, V11942, V11943, V11944, V11945, V11946, V11947, V11948,
+ V11949, V11950, V11951, V11952, V11953, V11954, V11955, V11956,
+ }, // P[423]
+ {
+ V11957, V11958, V11959, V11960, V11961, V11962, V11963, V11964,
+ V11965, V11966, V11967, V11968, V11969, V11970, V11971, V11972,
+ V11973, V11974, V11975, V11976, V11977, V11978, V11979, V11980,
+ V11981, V11982, V11983, V11984, V11985, V11986, V11987, V11988,
+ }, // P[424]
+ {
+ V11989, V11990, V11991, V11992, V11993, V11994, V11995, V11996,
+ V11997, V11998, V11999, V12000, V12001, V12002, V12003, V12004,
+ V12005, V12006, V12007, V12008, V12009, V12010, V12011, V12012,
+ V12013, V12014, V12015, V12016, V12017, V12018, V12019, V12020,
+ }, // P[425]
+ {
+ V12021, V12022, V12023, V12024, V12025, V12026, V12027, V12028,
+ V12029, V12030, V12031, V12032, V12033, V12034, V12035, V12036,
+ V12037, V12038, V12039, V12040, V12041, V12042, V12043, V12044,
+ V12045, V12046, V12047, V12048, V12049, V12050, V12051, V12052,
+ }, // P[426]
+ {
+ V12053, V12054, V12055, V12056, V12057, V12058, V12059, V12060,
+ V12061, V12062, V12063, V12064, V12065, V12066, V12067, V12068,
+ V12069, V12070, V12071, V12072, V12073, V12074, V12075, V12076,
+ V12077, V12078, V12079, V12080, V12081, V12082, V12083, V12084,
+ }, // P[427]
+ {
+ V12085, V12086, V12087, V12088, V12089, V12090, V12091, V12092,
+ V12093, V12094, V12095, V12096, V12097, V12098, V12099, V12100,
+ V12101, V12102, V12103, V12104, V12105, V12106, V12107, V12108,
+ V12109, V12110, V12111, V12112, V12113, V12114, V12115, V12116,
+ }, // P[428]
+ {
+ V12117, V12118, V12119, V12120, V12121, V12122, V12123, V12124,
+ V12125, V12126, V12127, V12128, V12129, V12130, V12131, V12132,
+ V12133, V12134, V12135, V12136, V12137, V12138, V12139, V12140,
+ V12141, V12142, V12143, V12144, V12145, V12146, V12147, V12148,
+ }, // P[429]
+ {
+ V12149, V12150, V12151, V12152, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[430]
+ {
+ V12153, V12154, V12155, V12156, V12157, V12158, V12159, V12160,
+ V12160, V12161, V12162, V12163, V12164, V12165, V12166, V12167,
+ V12168, V12169, V12170, V12171, V12172, V12173, V12174, V12175,
+ V12176, V12177, V12178, V12179, V12180, V12181, V12182, V12183,
+ }, // P[431]
+ {
+ V12184, V12185, V12186, V12187, V12188, V12189, V12190, V12191,
+ V12192, V12193, V12194, V12195, V12196, V12197, V12198, V12199,
+ V12200, V12201, V12202, V12203, V12204, V12205, V12206, V12207,
+ V12208, V12209, V12210, V12211, V12212, V12213, V12214, V12215,
+ }, // P[432]
+ {
+ V12216, V12217, V12218, V12219, V12220, V12221, V12222, V12223,
+ V12224, V12225, V12226, V12227, V12228, V12229, V12230, V12231,
+ V12232, V12233, V12234, V12235, V12236, V12237, V12238, V12239,
+ V12240, V12241, V12242, V12243, V12172, V12244, V12245, V12246,
+ }, // P[433]
+ {
+ V12247, V12248, V12249, V12250, V12251, V12252, V12253, V12254,
+ V12255, V12256, V12257, V12258, V12259, V12260, V12261, V12262,
+ V12263, V12264, V12265, V12266, V12267, V12268, V12269, V12270,
+ V12271, V12272, V12273, V12274, V12275, V12276, V12277, V12278,
+ }, // P[434]
+ {
+ V12279, V12280, V12281, V12282, V12283, V12284, V12285, V12286,
+ V12287, V12288, V12289, V12290, V12291, V12292, V12293, V12294,
+ V12295, V12296, V12297, V12298, V12299, V12300, V12301, V12302,
+ V12303, V12304, V12305, V12306, V12307, V12308, V12309, V12310,
+ }, // P[435]
+ {
+ V12311, V12262, V12312, V12313, V12314, V12315, V12316, V12317,
+ V12318, V12319, V12246, V12320, V12321, V12322, V12323, V12324,
+ V12325, V12326, V12327, V12328, V12329, V12330, V12331, V12332,
+ V12333, V12334, V12335, V12336, V12337, V12338, V12339, V12172,
+ }, // P[436]
+ {
+ V12340, V12341, V12342, V12343, V12344, V12345, V12346, V12347,
+ V12348, V12349, V12350, V12351, V12352, V12353, V12354, V12355,
+ V12356, V12357, V12358, V12359, V12360, V12361, V12362, V12363,
+ V12364, V12365, V12366, V12248, V12367, V12368, V12369, V12370,
+ }, // P[437]
+ {
+ V12371, V12372, V12373, V12374, V12375, V12376, V12377, V12378,
+ V12379, V12380, V12381, V12382, V12383, V12384, V12385, V12386,
+ V12387, V12388, V12389, V12390, V12391, V12392, V12393, V12394,
+ V12395, V12396, V12397, V12398, V12399, V12400, V12401, V12402,
+ }, // P[438]
+ {
+ V12403, V12404, V12405, V12406, V12407, V12408, V12409, V12410,
+ V12411, V12412, V12413, V12414, V12415, V12416, 0, 0,
+ V12417, 0, V12418, 0, 0, V12419, V12420, V12421,
+ V12422, V12423, V12424, V12425, V12426, V12427, V12428, 0,
+ }, // P[439]
+ {
+ V12429, 0, V12430, 0, 0, V12431, V12432, 0,
+ 0, 0, V12433, V12434, V12435, V12436, V12437, V12438,
+ V12439, V12440, V12441, V12442, V12443, V12444, V12445, V12446,
+ V12447, V12448, V12449, V12450, V12451, V12452, V12453, V12454,
+ }, // P[440]
+ {
+ V12455, V12456, V12457, V12458, V12459, V12460, V12461, V12462,
+ V12463, V12464, V12465, V12466, V12467, V12468, V12469, V12470,
+ V12471, V12472, V12473, V12474, V12475, V12476, V12477, V12301,
+ V12478, V12479, V12480, V12481, V12482, V12483, V12483, V12484,
+ }, // P[441]
+ {
+ V12485, V12486, V12487, V12488, V12489, V12490, V12491, V12431,
+ V12492, V12493, V12494, V12495, V12496, V12497, 0, 0,
+ V12498, V12499, V12500, V12501, V12502, V12503, V12504, V12505,
+ V12445, V12506, V12507, V12508, V12417, V12509, V12510, V12511,
+ }, // P[442]
+ {
+ V12512, V12513, V12514, V12515, V12516, V12517, V12518, V12519,
+ V12520, V12454, V12521, V12455, V12522, V12523, V12524, V12525,
+ V12526, V12418, V12193, V12527, V12528, V12529, V12263, V12350,
+ V12530, V12531, V12462, V12532, V12463, V12533, V12534, V12535,
+ }, // P[443]
+ {
+ V12420, V12536, V12537, V12538, V12539, V12540, V12421, V12541,
+ V12542, V12543, V12544, V12545, V12546, V12477, V12547, V12548,
+ V12301, V12549, V12481, V12550, V12551, V12552, V12553, V12554,
+ V12486, V12555, V12430, V12556, V12487, V12244, V12557, V12488,
+ }, // P[444]
+ {
+ V12558, V12490, V12559, V12560, V12561, V12562, V12563, V12492,
+ V12426, V12564, V12493, V12565, V12494, V12566, V12160, V12567,
+ V12568, V12569, V12570, V12571, V12572, V12573, V12574, V12575,
+ V12576, V12577, 0, 0, 0, 0, 0, 0,
+ }, // P[445]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, V12578, 0, V12579,
+ }, // P[446]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V12580, V12581, V12582, V12583, V12584, V12585,
+ V12586, V12587, V12588, V12589, V12590, V12591, V12592, 0,
+ V12593, V12594, V12595, V12596, V12597, 0, V12598, 0,
+ }, // P[447]
+ {
+ V12599, V12600, 0, V12601, V12602, 0, V12603, V12604,
+ V12605, V12606, V12607, V12608, V12609, V12610, V12611, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[448]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V12612, 0, V12613, 0, 0, 0,
+ }, // P[449]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V12614, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[450]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, V12615, V12616,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[451]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V12617, V12618, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[452]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V12619, V12620, 0, V12621, 0,
+ }, // P[453]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V12622, V12623, 0, 0, 0, 0,
+ }, // P[454]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, V12624, V12625,
+ }, // P[455]
+ {
+ V12626, V12627, V12628, V12629, V12630, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[456]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V12631, V12632, V12633, V12634, V12635,
+ }, // P[457]
+ {
+ V12636, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[458]
+ {
+ V12637, V12638, V12639, V12640, V12641, V12439, V12642, V12643,
+ V12644, V12645, V12440, V12646, V12647, V12648, V12441, V12649,
+ V12650, V12651, V12652, V12653, V12654, V12655, V12656, V12657,
+ V12658, V12659, V12660, V12499, V12661, V12662, V12663, V12664,
+ }, // P[459]
+ {
+ V12665, V12666, V12667, V12668, V12669, V12504, V12442, V12443,
+ V12505, V12670, V12671, V12250, V12672, V12444, V12673, V12674,
+ V12675, V12676, V12676, V12676, V12677, V12678, V12679, V12680,
+ V12681, V12682, V12683, V12684, V12685, V12686, V12687, V12688,
+ }, // P[460]
+ {
+ V12689, V12690, V12691, V12692, V12693, V12694, V12694, V12507,
+ V12695, V12696, V12697, V12698, V12446, V12699, V12700, V12701,
+ V12403, V12702, V12703, V12704, V12705, V12706, V12707, V12708,
+ V12709, V12710, V12711, V12712, V12713, V12714, V12715, V12716,
+ }, // P[461]
+ {
+ V12717, V12718, V12719, V12720, V12721, V12722, V12723, V12724,
+ V12725, V12726, V12727, V12727, V12728, V12729, V12730, V12246,
+ V12731, V12732, V12733, V12734, V12735, V12736, V12737, V12738,
+ V12451, V12739, V12740, V12741, V12742, V12743, V12744, V12745,
+ }, // P[462]
+ {
+ V12746, V12747, V12748, V12749, V12750, V12751, V12752, V12753,
+ V12754, V12755, V12756, V12757, V12758, V12759, V12192, V12760,
+ V12761, V12762, V12762, V12763, V12764, V12764, V12765, V12766,
+ V12767, V12768, V12769, V12770, V12771, V12772, V12773, V12774,
+ }, // P[463]
+ {
+ V12775, V12776, V12777, V12452, V12778, V12779, V12780, V12781,
+ V12519, V12781, V12782, V12454, V12783, V12784, V12785, V12786,
+ V12455, V12165, V12787, V12788, V12789, V12790, V12791, V12792,
+ V12793, V12794, V12795, V12796, V12797, V12798, V12799, V12800,
+ }, // P[464]
+ {
+ V12801, V12802, V12803, V12804, V12805, V12806, V12807, V12808,
+ V12456, V12809, V12810, V12811, V12812, V12813, V12814, V12458,
+ V12815, V12816, V12817, V12818, V12819, V12820, V12821, V12822,
+ V12193, V12527, V12823, V12824, V12825, V12826, V12827, V12828,
+ }, // P[465]
+ {
+ V12829, V12830, V12459, V12831, V12832, V12833, V12834, V12570,
+ V12835, V12836, V12837, V12838, V12839, V12840, V12841, V12842,
+ V12843, V12844, V12845, V12846, V12847, V12263, V12848, V12849,
+ V12850, V12851, V12852, V12853, V12854, V12855, V12856, V12857,
+ }, // P[466]
+ {
+ V12858, V12460, V12350, V12859, V12860, V12861, V12862, V12863,
+ V12864, V12865, V12866, V12531, V12867, V12868, V12869, V12870,
+ V12871, V12872, V12873, V12874, V12532, V12875, V12876, V12877,
+ V12878, V12879, V12880, V12881, V12882, V12883, V12884, V12885,
+ }, // P[467]
+ {
+ V12886, V12534, V12887, V12888, V12889, V12890, V12891, V12892,
+ V12893, V12894, V12895, V12896, V12897, V12897, V12898, V12899,
+ V12536, V12900, V12901, V12902, V12903, V12904, V12905, V12906,
+ V12249, V12907, V12908, V12909, V12910, V12911, V12912, V12913,
+ }, // P[468]
+ {
+ V12542, V12914, V12915, V12916, V12917, V12918, V12919, V12919,
+ V12543, V12572, V12920, V12921, V12922, V12923, V12924, V12211,
+ V12545, V12925, V12926, V12471, V12927, V12928, V12425, V12929,
+ V12930, V12475, V12931, V12932, V12933, V12934, V12934, V12935,
+ }, // P[469]
+ {
+ V12936, V12937, V12938, V12939, V12940, V12941, V12942, V12943,
+ V12944, V12945, V12946, V12947, V12948, V12949, V12950, V12951,
+ V12952, V12953, V12954, V12955, V12956, V12957, V12958, V12959,
+ V12960, V12961, V12481, V12962, V12963, V12964, V12965, V12966,
+ }, // P[470]
+ {
+ V12967, V12968, V12969, V12970, V12971, V12972, V12973, V12974,
+ V12975, V12976, V12977, V12763, V12978, V12979, V12980, V12981,
+ V12982, V12983, V12984, V12985, V12986, V12987, V12988, V12989,
+ V12267, V12990, V12991, V12992, V12993, V12994, V12995, V12484,
+ }, // P[471]
+ {
+ V12996, V12997, V12998, V12999, V13000, V13001, V13002, V13003,
+ V13004, V13005, V13006, V13007, V13008, V13009, V13010, V13011,
+ V13012, V13013, V13014, V13015, V12206, V13016, V13017, V13018,
+ V13019, V13020, V13021, V12552, V13022, V13023, V13024, V13025,
+ }, // P[472]
+ {
+ V13026, V13027, V13028, V13029, V13030, V13031, V13032, V13033,
+ V13034, V13035, V13036, V13037, V13038, V13039, V13040, V13041,
+ V12557, V12558, V13042, V13043, V13044, V13045, V13046, V13047,
+ V13048, V13049, V13050, V13051, V13052, V13053, V13054, V12559,
+ }, // P[473]
+ {
+ V13055, V13056, V13057, V13058, V13059, V13060, V13061, V13062,
+ V13063, V13064, V13065, V13066, V13067, V13068, V13069, V13070,
+ V13071, V13072, V13073, V13074, V13075, V13076, V13077, V13078,
+ V13079, V13080, V13081, V13082, V13083, V13084, V12565, V12565,
+ }, // P[474]
+ {
+ V13085, V13086, V13087, V13088, V13089, V13090, V13091, V13092,
+ V13093, V13094, V12566, V13095, V13096, V13097, V13098, V13099,
+ V13100, V13101, V13102, V13103, V13104, V13105, V13106, V13107,
+ V13108, V13109, V13110, V13111, V13112, V13113,
+ }, // P[475]
+ }; // static const NUnicode::NPrivate::TDecompositionTable::TValuePtr P[][32]
+
+ static const NUnicode::NPrivate::TDecompositionTable::TValuePtr* const Indexes[] = {
+ P[0], P[0], P[0], P[0], P[0], P[0], P[1], P[2], P[3], P[4], P[5], P[6], P[0], P[7], P[8], P[9],
+ P[10], P[11], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[12], P[13], P[14], P[15], P[16], P[0],
+ P[17], P[18], P[19], P[20], P[0], P[0], P[21], P[22], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[23], P[0], P[0], P[0], P[0], P[24], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[25], P[26], P[0], P[0], P[0], P[27], P[0],
+ P[0], P[28], P[29], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[30], P[0], P[31], P[0], P[32], P[0],
+ P[0], P[0], P[33], P[0], P[0], P[0], P[34], P[0], P[0], P[0], P[35], P[0], P[0], P[0], P[36], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[37], P[38], P[39], P[40], P[0], P[0],
+ P[0], P[41], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[42], P[43], P[44], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[45], P[46], P[47], P[48], P[49], P[50], P[51], P[52], P[53], P[54], P[55], P[56], P[57], P[58], P[59], P[60],
+ P[61], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[62], P[0], P[0], P[63], P[64], P[65], P[0],
+ P[66], P[67], P[68], P[69], P[70], P[71], P[0], P[72], P[0], P[73], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[74], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[75], P[76], P[77], P[78], P[79], P[80], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[81], P[82], P[83], P[84], P[85], P[86], P[87], P[88], P[89], P[90], P[91], P[92], P[93], P[94], P[95], P[96],
+ P[97], P[98], P[99], P[100], P[101], P[102], P[103], P[104], P[105], P[106], P[107], P[108], P[109], P[110], P[111], P[112],
+ P[113], P[114], P[115], P[116], P[117], P[118], P[119], P[120], P[121], P[122], P[123], P[124], P[125], P[126], P[127], P[128],
+ P[129], P[130], P[131], P[132], P[133], P[134], P[135], P[136], P[137], P[138], P[139], P[140], P[141], P[142], P[143], P[144],
+ P[145], P[146], P[147], P[148], P[149], P[150], P[151], P[152], P[153], P[154], P[155], P[156], P[157], P[158], P[159], P[160],
+ P[161], P[162], P[163], P[164], P[165], P[166], P[167], P[168], P[169], P[170], P[171], P[172], P[173], P[174], P[175], P[176],
+ P[177], P[178], P[179], P[180], P[181], P[182], P[183], P[184], P[185], P[186], P[187], P[188], P[189], P[190], P[191], P[192],
+ P[193], P[194], P[195], P[196], P[197], P[198], P[199], P[200], P[201], P[202], P[203], P[204], P[205], P[206], P[207], P[208],
+ P[209], P[210], P[211], P[212], P[213], P[214], P[215], P[216], P[217], P[218], P[219], P[220], P[221], P[222], P[223], P[224],
+ P[225], P[226], P[227], P[228], P[229], P[230], P[231], P[232], P[233], P[234], P[235], P[236], P[237], P[238], P[239], P[240],
+ P[241], P[242], P[243], P[244], P[245], P[246], P[247], P[248], P[249], P[250], P[251], P[252], P[253], P[254], P[255], P[256],
+ P[257], P[258], P[259], P[260], P[261], P[262], P[263], P[264], P[265], P[266], P[267], P[268], P[269], P[270], P[271], P[272],
+ P[273], P[274], P[275], P[276], P[277], P[278], P[279], P[280], P[281], P[282], P[283], P[284], P[285], P[286], P[287], P[288],
+ P[289], P[290], P[291], P[292], P[293], P[294], P[295], P[296], P[297], P[298], P[299], P[300], P[301], P[302], P[303], P[304],
+ P[305], P[306], P[307], P[308], P[309], P[310], P[311], P[312], P[313], P[314], P[315], P[316], P[317], P[318], P[319], P[320],
+ P[321], P[322], P[323], P[324], P[325], P[326], P[327], P[328], P[329], P[330], P[331], P[332], P[333], P[334], P[335], P[336],
+ P[337], P[338], P[339], P[340], P[341], P[342], P[343], P[344], P[345], P[346], P[347], P[348], P[349], P[350], P[351], P[352],
+ P[353], P[354], P[355], P[356], P[357], P[358], P[359], P[360], P[361], P[362], P[363], P[364], P[365], P[366], P[367], P[368],
+ P[369], P[370], P[371], P[372], P[373], P[374], P[375], P[376], P[377], P[378], P[379], P[380], P[381], P[382], P[383], P[384],
+ P[385], P[386], P[387], P[388], P[389], P[390], P[391], P[392], P[393], P[394], P[395], P[396], P[397], P[398], P[399], P[400],
+ P[401], P[402], P[403], P[404], P[405], P[406], P[407], P[408], P[409], P[410], P[411], P[412], P[413], P[414], P[415], P[416],
+ P[417], P[418], P[419], P[420], P[421], P[422], P[423], P[424], P[425], P[426], P[427], P[428], P[429], P[430], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[431], P[432], P[433], P[434], P[435], P[436], P[437], P[438],
+ P[439], P[440], P[441], P[442], P[443], P[444], P[445], P[0], P[446], P[447], P[448], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[449], P[450], P[0], P[0], P[0], P[451], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[452], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[453], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[454], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[455], P[456], P[0], P[457], P[458], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[459], P[460], P[461], P[462], P[463], P[464], P[465], P[466], P[467], P[468], P[469], P[470], P[471], P[472], P[473], P[474],
+ P[475],
+ }; // static const NUnicode::NPrivate::TDecompositionTable::TValuePtr* const Indexes[]
+
+ static const size_t Size = 195102;
+}} // namespace NCannonDecompositionTableGenerated
+
+namespace NUnicode {
+ namespace NPrivate {
+ const NUnicode::NPrivate::TDecompositionTable& CannonDecompositionTable() {
+ static const NUnicode::NPrivate::TDecompositionTable data(NCannonDecompositionTableGenerated::Indexes, NCannonDecompositionTableGenerated::Size);
+ return data;
+ }
+ } // namespace NPrivate
+} // namespace NUnicode
+
+namespace { namespace NCompatDecompositionTableGenerated {
+ using TV = const NUnicode::NPrivate::TDecompositionTable::TStored;
+
+ static const TV V = {
+#undef V0
+#define V0 (V + 0)
+ 0x20, 0,
+#undef V1
+#define V1 (V + 2)
+ 0x20, 0x308, 0,
+#undef V2
+#define V2 (V + 5)
+ 0x61, 0,
+#undef V3
+#define V3 (V + 7)
+ 0x20, 0x304, 0,
+#undef V4
+#define V4 (V + 10)
+ 0x32, 0,
+#undef V5
+#define V5 (V + 12)
+ 0x33, 0,
+#undef V6
+#define V6 (V + 14)
+ 0x20, 0x301, 0,
+#undef V7
+#define V7 (V + 17)
+ 0x3bc, 0,
+#undef V8
+#define V8 (V + 19)
+ 0x20, 0x327, 0,
+#undef V9
+#define V9 (V + 22)
+ 0x31, 0,
+#undef V10
+#define V10 (V + 24)
+ 0x6f, 0,
+#undef V11
+#define V11 (V + 26)
+ 0x31, 0x2044, 0x34, 0,
+#undef V12
+#define V12 (V + 30)
+ 0x31, 0x2044, 0x32, 0,
+#undef V13
+#define V13 (V + 34)
+ 0x33, 0x2044, 0x34, 0,
+#undef V14
+#define V14 (V + 38)
+ 0x41, 0x300, 0,
+#undef V15
+#define V15 (V + 41)
+ 0x41, 0x301, 0,
+#undef V16
+#define V16 (V + 44)
+ 0x41, 0x302, 0,
+#undef V17
+#define V17 (V + 47)
+ 0x41, 0x303, 0,
+#undef V18
+#define V18 (V + 50)
+ 0x41, 0x308, 0,
+#undef V19
+#define V19 (V + 53)
+ 0x41, 0x30a, 0,
+#undef V20
+#define V20 (V + 56)
+ 0x43, 0x327, 0,
+#undef V21
+#define V21 (V + 59)
+ 0x45, 0x300, 0,
+#undef V22
+#define V22 (V + 62)
+ 0x45, 0x301, 0,
+#undef V23
+#define V23 (V + 65)
+ 0x45, 0x302, 0,
+#undef V24
+#define V24 (V + 68)
+ 0x45, 0x308, 0,
+#undef V25
+#define V25 (V + 71)
+ 0x49, 0x300, 0,
+#undef V26
+#define V26 (V + 74)
+ 0x49, 0x301, 0,
+#undef V27
+#define V27 (V + 77)
+ 0x49, 0x302, 0,
+#undef V28
+#define V28 (V + 80)
+ 0x49, 0x308, 0,
+#undef V29
+#define V29 (V + 83)
+ 0x4e, 0x303, 0,
+#undef V30
+#define V30 (V + 86)
+ 0x4f, 0x300, 0,
+#undef V31
+#define V31 (V + 89)
+ 0x4f, 0x301, 0,
+#undef V32
+#define V32 (V + 92)
+ 0x4f, 0x302, 0,
+#undef V33
+#define V33 (V + 95)
+ 0x4f, 0x303, 0,
+#undef V34
+#define V34 (V + 98)
+ 0x4f, 0x308, 0,
+#undef V35
+#define V35 (V + 101)
+ 0x55, 0x300, 0,
+#undef V36
+#define V36 (V + 104)
+ 0x55, 0x301, 0,
+#undef V37
+#define V37 (V + 107)
+ 0x55, 0x302, 0,
+#undef V38
+#define V38 (V + 110)
+ 0x55, 0x308, 0,
+#undef V39
+#define V39 (V + 113)
+ 0x59, 0x301, 0,
+#undef V40
+#define V40 (V + 116)
+ 0x61, 0x300, 0,
+#undef V41
+#define V41 (V + 119)
+ 0x61, 0x301, 0,
+#undef V42
+#define V42 (V + 122)
+ 0x61, 0x302, 0,
+#undef V43
+#define V43 (V + 125)
+ 0x61, 0x303, 0,
+#undef V44
+#define V44 (V + 128)
+ 0x61, 0x308, 0,
+#undef V45
+#define V45 (V + 131)
+ 0x61, 0x30a, 0,
+#undef V46
+#define V46 (V + 134)
+ 0x63, 0x327, 0,
+#undef V47
+#define V47 (V + 137)
+ 0x65, 0x300, 0,
+#undef V48
+#define V48 (V + 140)
+ 0x65, 0x301, 0,
+#undef V49
+#define V49 (V + 143)
+ 0x65, 0x302, 0,
+#undef V50
+#define V50 (V + 146)
+ 0x65, 0x308, 0,
+#undef V51
+#define V51 (V + 149)
+ 0x69, 0x300, 0,
+#undef V52
+#define V52 (V + 152)
+ 0x69, 0x301, 0,
+#undef V53
+#define V53 (V + 155)
+ 0x69, 0x302, 0,
+#undef V54
+#define V54 (V + 158)
+ 0x69, 0x308, 0,
+#undef V55
+#define V55 (V + 161)
+ 0x6e, 0x303, 0,
+#undef V56
+#define V56 (V + 164)
+ 0x6f, 0x300, 0,
+#undef V57
+#define V57 (V + 167)
+ 0x6f, 0x301, 0,
+#undef V58
+#define V58 (V + 170)
+ 0x6f, 0x302, 0,
+#undef V59
+#define V59 (V + 173)
+ 0x6f, 0x303, 0,
+#undef V60
+#define V60 (V + 176)
+ 0x6f, 0x308, 0,
+#undef V61
+#define V61 (V + 179)
+ 0x75, 0x300, 0,
+#undef V62
+#define V62 (V + 182)
+ 0x75, 0x301, 0,
+#undef V63
+#define V63 (V + 185)
+ 0x75, 0x302, 0,
+#undef V64
+#define V64 (V + 188)
+ 0x75, 0x308, 0,
+#undef V65
+#define V65 (V + 191)
+ 0x79, 0x301, 0,
+#undef V66
+#define V66 (V + 194)
+ 0x79, 0x308, 0,
+#undef V67
+#define V67 (V + 197)
+ 0x41, 0x304, 0,
+#undef V68
+#define V68 (V + 200)
+ 0x61, 0x304, 0,
+#undef V69
+#define V69 (V + 203)
+ 0x41, 0x306, 0,
+#undef V70
+#define V70 (V + 206)
+ 0x61, 0x306, 0,
+#undef V71
+#define V71 (V + 209)
+ 0x41, 0x328, 0,
+#undef V72
+#define V72 (V + 212)
+ 0x61, 0x328, 0,
+#undef V73
+#define V73 (V + 215)
+ 0x43, 0x301, 0,
+#undef V74
+#define V74 (V + 218)
+ 0x63, 0x301, 0,
+#undef V75
+#define V75 (V + 221)
+ 0x43, 0x302, 0,
+#undef V76
+#define V76 (V + 224)
+ 0x63, 0x302, 0,
+#undef V77
+#define V77 (V + 227)
+ 0x43, 0x307, 0,
+#undef V78
+#define V78 (V + 230)
+ 0x63, 0x307, 0,
+#undef V79
+#define V79 (V + 233)
+ 0x43, 0x30c, 0,
+#undef V80
+#define V80 (V + 236)
+ 0x63, 0x30c, 0,
+#undef V81
+#define V81 (V + 239)
+ 0x44, 0x30c, 0,
+#undef V82
+#define V82 (V + 242)
+ 0x64, 0x30c, 0,
+#undef V83
+#define V83 (V + 245)
+ 0x45, 0x304, 0,
+#undef V84
+#define V84 (V + 248)
+ 0x65, 0x304, 0,
+#undef V85
+#define V85 (V + 251)
+ 0x45, 0x306, 0,
+#undef V86
+#define V86 (V + 254)
+ 0x65, 0x306, 0,
+#undef V87
+#define V87 (V + 257)
+ 0x45, 0x307, 0,
+#undef V88
+#define V88 (V + 260)
+ 0x65, 0x307, 0,
+#undef V89
+#define V89 (V + 263)
+ 0x45, 0x328, 0,
+#undef V90
+#define V90 (V + 266)
+ 0x65, 0x328, 0,
+#undef V91
+#define V91 (V + 269)
+ 0x45, 0x30c, 0,
+#undef V92
+#define V92 (V + 272)
+ 0x65, 0x30c, 0,
+#undef V93
+#define V93 (V + 275)
+ 0x47, 0x302, 0,
+#undef V94
+#define V94 (V + 278)
+ 0x67, 0x302, 0,
+#undef V95
+#define V95 (V + 281)
+ 0x47, 0x306, 0,
+#undef V96
+#define V96 (V + 284)
+ 0x67, 0x306, 0,
+#undef V97
+#define V97 (V + 287)
+ 0x47, 0x307, 0,
+#undef V98
+#define V98 (V + 290)
+ 0x67, 0x307, 0,
+#undef V99
+#define V99 (V + 293)
+ 0x47, 0x327, 0,
+#undef V100
+#define V100 (V + 296)
+ 0x67, 0x327, 0,
+#undef V101
+#define V101 (V + 299)
+ 0x48, 0x302, 0,
+#undef V102
+#define V102 (V + 302)
+ 0x68, 0x302, 0,
+#undef V103
+#define V103 (V + 305)
+ 0x49, 0x303, 0,
+#undef V104
+#define V104 (V + 308)
+ 0x69, 0x303, 0,
+#undef V105
+#define V105 (V + 311)
+ 0x49, 0x304, 0,
+#undef V106
+#define V106 (V + 314)
+ 0x69, 0x304, 0,
+#undef V107
+#define V107 (V + 317)
+ 0x49, 0x306, 0,
+#undef V108
+#define V108 (V + 320)
+ 0x69, 0x306, 0,
+#undef V109
+#define V109 (V + 323)
+ 0x49, 0x328, 0,
+#undef V110
+#define V110 (V + 326)
+ 0x69, 0x328, 0,
+#undef V111
+#define V111 (V + 329)
+ 0x49, 0x307, 0,
+#undef V112
+#define V112 (V + 332)
+ 0x49, 0x4a, 0,
+#undef V113
+#define V113 (V + 335)
+ 0x69, 0x6a, 0,
+#undef V114
+#define V114 (V + 338)
+ 0x4a, 0x302, 0,
+#undef V115
+#define V115 (V + 341)
+ 0x6a, 0x302, 0,
+#undef V116
+#define V116 (V + 344)
+ 0x4b, 0x327, 0,
+#undef V117
+#define V117 (V + 347)
+ 0x6b, 0x327, 0,
+#undef V118
+#define V118 (V + 350)
+ 0x4c, 0x301, 0,
+#undef V119
+#define V119 (V + 353)
+ 0x6c, 0x301, 0,
+#undef V120
+#define V120 (V + 356)
+ 0x4c, 0x327, 0,
+#undef V121
+#define V121 (V + 359)
+ 0x6c, 0x327, 0,
+#undef V122
+#define V122 (V + 362)
+ 0x4c, 0x30c, 0,
+#undef V123
+#define V123 (V + 365)
+ 0x6c, 0x30c, 0,
+#undef V124
+#define V124 (V + 368)
+ 0x4c, 0xb7, 0,
+#undef V125
+#define V125 (V + 371)
+ 0x6c, 0xb7, 0,
+#undef V126
+#define V126 (V + 374)
+ 0x4e, 0x301, 0,
+#undef V127
+#define V127 (V + 377)
+ 0x6e, 0x301, 0,
+#undef V128
+#define V128 (V + 380)
+ 0x4e, 0x327, 0,
+#undef V129
+#define V129 (V + 383)
+ 0x6e, 0x327, 0,
+#undef V130
+#define V130 (V + 386)
+ 0x4e, 0x30c, 0,
+#undef V131
+#define V131 (V + 389)
+ 0x6e, 0x30c, 0,
+#undef V132
+#define V132 (V + 392)
+ 0x2bc, 0x6e, 0,
+#undef V133
+#define V133 (V + 395)
+ 0x4f, 0x304, 0,
+#undef V134
+#define V134 (V + 398)
+ 0x6f, 0x304, 0,
+#undef V135
+#define V135 (V + 401)
+ 0x4f, 0x306, 0,
+#undef V136
+#define V136 (V + 404)
+ 0x6f, 0x306, 0,
+#undef V137
+#define V137 (V + 407)
+ 0x4f, 0x30b, 0,
+#undef V138
+#define V138 (V + 410)
+ 0x6f, 0x30b, 0,
+#undef V139
+#define V139 (V + 413)
+ 0x52, 0x301, 0,
+#undef V140
+#define V140 (V + 416)
+ 0x72, 0x301, 0,
+#undef V141
+#define V141 (V + 419)
+ 0x52, 0x327, 0,
+#undef V142
+#define V142 (V + 422)
+ 0x72, 0x327, 0,
+#undef V143
+#define V143 (V + 425)
+ 0x52, 0x30c, 0,
+#undef V144
+#define V144 (V + 428)
+ 0x72, 0x30c, 0,
+#undef V145
+#define V145 (V + 431)
+ 0x53, 0x301, 0,
+#undef V146
+#define V146 (V + 434)
+ 0x73, 0x301, 0,
+#undef V147
+#define V147 (V + 437)
+ 0x53, 0x302, 0,
+#undef V148
+#define V148 (V + 440)
+ 0x73, 0x302, 0,
+#undef V149
+#define V149 (V + 443)
+ 0x53, 0x327, 0,
+#undef V150
+#define V150 (V + 446)
+ 0x73, 0x327, 0,
+#undef V151
+#define V151 (V + 449)
+ 0x53, 0x30c, 0,
+#undef V152
+#define V152 (V + 452)
+ 0x73, 0x30c, 0,
+#undef V153
+#define V153 (V + 455)
+ 0x54, 0x327, 0,
+#undef V154
+#define V154 (V + 458)
+ 0x74, 0x327, 0,
+#undef V155
+#define V155 (V + 461)
+ 0x54, 0x30c, 0,
+#undef V156
+#define V156 (V + 464)
+ 0x74, 0x30c, 0,
+#undef V157
+#define V157 (V + 467)
+ 0x55, 0x303, 0,
+#undef V158
+#define V158 (V + 470)
+ 0x75, 0x303, 0,
+#undef V159
+#define V159 (V + 473)
+ 0x55, 0x304, 0,
+#undef V160
+#define V160 (V + 476)
+ 0x75, 0x304, 0,
+#undef V161
+#define V161 (V + 479)
+ 0x55, 0x306, 0,
+#undef V162
+#define V162 (V + 482)
+ 0x75, 0x306, 0,
+#undef V163
+#define V163 (V + 485)
+ 0x55, 0x30a, 0,
+#undef V164
+#define V164 (V + 488)
+ 0x75, 0x30a, 0,
+#undef V165
+#define V165 (V + 491)
+ 0x55, 0x30b, 0,
+#undef V166
+#define V166 (V + 494)
+ 0x75, 0x30b, 0,
+#undef V167
+#define V167 (V + 497)
+ 0x55, 0x328, 0,
+#undef V168
+#define V168 (V + 500)
+ 0x75, 0x328, 0,
+#undef V169
+#define V169 (V + 503)
+ 0x57, 0x302, 0,
+#undef V170
+#define V170 (V + 506)
+ 0x77, 0x302, 0,
+#undef V171
+#define V171 (V + 509)
+ 0x59, 0x302, 0,
+#undef V172
+#define V172 (V + 512)
+ 0x79, 0x302, 0,
+#undef V173
+#define V173 (V + 515)
+ 0x59, 0x308, 0,
+#undef V174
+#define V174 (V + 518)
+ 0x5a, 0x301, 0,
+#undef V175
+#define V175 (V + 521)
+ 0x7a, 0x301, 0,
+#undef V176
+#define V176 (V + 524)
+ 0x5a, 0x307, 0,
+#undef V177
+#define V177 (V + 527)
+ 0x7a, 0x307, 0,
+#undef V178
+#define V178 (V + 530)
+ 0x5a, 0x30c, 0,
+#undef V179
+#define V179 (V + 533)
+ 0x7a, 0x30c, 0,
+#undef V180
+#define V180 (V + 536)
+ 0x73, 0,
+#undef V181
+#define V181 (V + 538)
+ 0x4f, 0x31b, 0,
+#undef V182
+#define V182 (V + 541)
+ 0x6f, 0x31b, 0,
+#undef V183
+#define V183 (V + 544)
+ 0x55, 0x31b, 0,
+#undef V184
+#define V184 (V + 547)
+ 0x75, 0x31b, 0,
+#undef V185
+#define V185 (V + 550)
+ 0x44, 0x5a, 0x30c, 0,
+#undef V186
+#define V186 (V + 554)
+ 0x44, 0x7a, 0x30c, 0,
+#undef V187
+#define V187 (V + 558)
+ 0x64, 0x7a, 0x30c, 0,
+#undef V188
+#define V188 (V + 562)
+ 0x4c, 0x4a, 0,
+#undef V189
+#define V189 (V + 565)
+ 0x4c, 0x6a, 0,
+#undef V190
+#define V190 (V + 568)
+ 0x6c, 0x6a, 0,
+#undef V191
+#define V191 (V + 571)
+ 0x4e, 0x4a, 0,
+#undef V192
+#define V192 (V + 574)
+ 0x4e, 0x6a, 0,
+#undef V193
+#define V193 (V + 577)
+ 0x6e, 0x6a, 0,
+#undef V194
+#define V194 (V + 580)
+ 0x41, 0x30c, 0,
+#undef V195
+#define V195 (V + 583)
+ 0x61, 0x30c, 0,
+#undef V196
+#define V196 (V + 586)
+ 0x49, 0x30c, 0,
+#undef V197
+#define V197 (V + 589)
+ 0x69, 0x30c, 0,
+#undef V198
+#define V198 (V + 592)
+ 0x4f, 0x30c, 0,
+#undef V199
+#define V199 (V + 595)
+ 0x6f, 0x30c, 0,
+#undef V200
+#define V200 (V + 598)
+ 0x55, 0x30c, 0,
+#undef V201
+#define V201 (V + 601)
+ 0x75, 0x30c, 0,
+#undef V202
+#define V202 (V + 604)
+ 0x55, 0x308, 0x304, 0,
+#undef V203
+#define V203 (V + 608)
+ 0x75, 0x308, 0x304, 0,
+#undef V204
+#define V204 (V + 612)
+ 0x55, 0x308, 0x301, 0,
+#undef V205
+#define V205 (V + 616)
+ 0x75, 0x308, 0x301, 0,
+#undef V206
+#define V206 (V + 620)
+ 0x55, 0x308, 0x30c, 0,
+#undef V207
+#define V207 (V + 624)
+ 0x75, 0x308, 0x30c, 0,
+#undef V208
+#define V208 (V + 628)
+ 0x55, 0x308, 0x300, 0,
+#undef V209
+#define V209 (V + 632)
+ 0x75, 0x308, 0x300, 0,
+#undef V210
+#define V210 (V + 636)
+ 0x41, 0x308, 0x304, 0,
+#undef V211
+#define V211 (V + 640)
+ 0x61, 0x308, 0x304, 0,
+#undef V212
+#define V212 (V + 644)
+ 0x41, 0x307, 0x304, 0,
+#undef V213
+#define V213 (V + 648)
+ 0x61, 0x307, 0x304, 0,
+#undef V214
+#define V214 (V + 652)
+ 0xc6, 0x304, 0,
+#undef V215
+#define V215 (V + 655)
+ 0xe6, 0x304, 0,
+#undef V216
+#define V216 (V + 658)
+ 0x47, 0x30c, 0,
+#undef V217
+#define V217 (V + 661)
+ 0x67, 0x30c, 0,
+#undef V218
+#define V218 (V + 664)
+ 0x4b, 0x30c, 0,
+#undef V219
+#define V219 (V + 667)
+ 0x6b, 0x30c, 0,
+#undef V220
+#define V220 (V + 670)
+ 0x4f, 0x328, 0,
+#undef V221
+#define V221 (V + 673)
+ 0x6f, 0x328, 0,
+#undef V222
+#define V222 (V + 676)
+ 0x4f, 0x328, 0x304, 0,
+#undef V223
+#define V223 (V + 680)
+ 0x6f, 0x328, 0x304, 0,
+#undef V224
+#define V224 (V + 684)
+ 0x1b7, 0x30c, 0,
+#undef V225
+#define V225 (V + 687)
+ 0x292, 0x30c, 0,
+#undef V226
+#define V226 (V + 690)
+ 0x6a, 0x30c, 0,
+#undef V227
+#define V227 (V + 693)
+ 0x44, 0x5a, 0,
+#undef V228
+#define V228 (V + 696)
+ 0x44, 0x7a, 0,
+#undef V229
+#define V229 (V + 699)
+ 0x64, 0x7a, 0,
+#undef V230
+#define V230 (V + 702)
+ 0x47, 0x301, 0,
+#undef V231
+#define V231 (V + 705)
+ 0x67, 0x301, 0,
+#undef V232
+#define V232 (V + 708)
+ 0x4e, 0x300, 0,
+#undef V233
+#define V233 (V + 711)
+ 0x6e, 0x300, 0,
+#undef V234
+#define V234 (V + 714)
+ 0x41, 0x30a, 0x301, 0,
+#undef V235
+#define V235 (V + 718)
+ 0x61, 0x30a, 0x301, 0,
+#undef V236
+#define V236 (V + 722)
+ 0xc6, 0x301, 0,
+#undef V237
+#define V237 (V + 725)
+ 0xe6, 0x301, 0,
+#undef V238
+#define V238 (V + 728)
+ 0xd8, 0x301, 0,
+#undef V239
+#define V239 (V + 731)
+ 0xf8, 0x301, 0,
+#undef V240
+#define V240 (V + 734)
+ 0x41, 0x30f, 0,
+#undef V241
+#define V241 (V + 737)
+ 0x61, 0x30f, 0,
+#undef V242
+#define V242 (V + 740)
+ 0x41, 0x311, 0,
+#undef V243
+#define V243 (V + 743)
+ 0x61, 0x311, 0,
+#undef V244
+#define V244 (V + 746)
+ 0x45, 0x30f, 0,
+#undef V245
+#define V245 (V + 749)
+ 0x65, 0x30f, 0,
+#undef V246
+#define V246 (V + 752)
+ 0x45, 0x311, 0,
+#undef V247
+#define V247 (V + 755)
+ 0x65, 0x311, 0,
+#undef V248
+#define V248 (V + 758)
+ 0x49, 0x30f, 0,
+#undef V249
+#define V249 (V + 761)
+ 0x69, 0x30f, 0,
+#undef V250
+#define V250 (V + 764)
+ 0x49, 0x311, 0,
+#undef V251
+#define V251 (V + 767)
+ 0x69, 0x311, 0,
+#undef V252
+#define V252 (V + 770)
+ 0x4f, 0x30f, 0,
+#undef V253
+#define V253 (V + 773)
+ 0x6f, 0x30f, 0,
+#undef V254
+#define V254 (V + 776)
+ 0x4f, 0x311, 0,
+#undef V255
+#define V255 (V + 779)
+ 0x6f, 0x311, 0,
+#undef V256
+#define V256 (V + 782)
+ 0x52, 0x30f, 0,
+#undef V257
+#define V257 (V + 785)
+ 0x72, 0x30f, 0,
+#undef V258
+#define V258 (V + 788)
+ 0x52, 0x311, 0,
+#undef V259
+#define V259 (V + 791)
+ 0x72, 0x311, 0,
+#undef V260
+#define V260 (V + 794)
+ 0x55, 0x30f, 0,
+#undef V261
+#define V261 (V + 797)
+ 0x75, 0x30f, 0,
+#undef V262
+#define V262 (V + 800)
+ 0x55, 0x311, 0,
+#undef V263
+#define V263 (V + 803)
+ 0x75, 0x311, 0,
+#undef V264
+#define V264 (V + 806)
+ 0x53, 0x326, 0,
+#undef V265
+#define V265 (V + 809)
+ 0x73, 0x326, 0,
+#undef V266
+#define V266 (V + 812)
+ 0x54, 0x326, 0,
+#undef V267
+#define V267 (V + 815)
+ 0x74, 0x326, 0,
+#undef V268
+#define V268 (V + 818)
+ 0x48, 0x30c, 0,
+#undef V269
+#define V269 (V + 821)
+ 0x68, 0x30c, 0,
+#undef V270
+#define V270 (V + 824)
+ 0x41, 0x307, 0,
+#undef V271
+#define V271 (V + 827)
+ 0x61, 0x307, 0,
+#undef V272
+#define V272 (V + 830)
+ 0x45, 0x327, 0,
+#undef V273
+#define V273 (V + 833)
+ 0x65, 0x327, 0,
+#undef V274
+#define V274 (V + 836)
+ 0x4f, 0x308, 0x304, 0,
+#undef V275
+#define V275 (V + 840)
+ 0x6f, 0x308, 0x304, 0,
+#undef V276
+#define V276 (V + 844)
+ 0x4f, 0x303, 0x304, 0,
+#undef V277
+#define V277 (V + 848)
+ 0x6f, 0x303, 0x304, 0,
+#undef V278
+#define V278 (V + 852)
+ 0x4f, 0x307, 0,
+#undef V279
+#define V279 (V + 855)
+ 0x6f, 0x307, 0,
+#undef V280
+#define V280 (V + 858)
+ 0x4f, 0x307, 0x304, 0,
+#undef V281
+#define V281 (V + 862)
+ 0x6f, 0x307, 0x304, 0,
+#undef V282
+#define V282 (V + 866)
+ 0x59, 0x304, 0,
+#undef V283
+#define V283 (V + 869)
+ 0x79, 0x304, 0,
+#undef V284
+#define V284 (V + 872)
+ 0x68, 0,
+#undef V285
+#define V285 (V + 874)
+ 0x266, 0,
+#undef V286
+#define V286 (V + 876)
+ 0x6a, 0,
+#undef V287
+#define V287 (V + 878)
+ 0x72, 0,
+#undef V288
+#define V288 (V + 880)
+ 0x279, 0,
+#undef V289
+#define V289 (V + 882)
+ 0x27b, 0,
+#undef V290
+#define V290 (V + 884)
+ 0x281, 0,
+#undef V291
+#define V291 (V + 886)
+ 0x77, 0,
+#undef V292
+#define V292 (V + 888)
+ 0x79, 0,
+#undef V293
+#define V293 (V + 890)
+ 0x20, 0x306, 0,
+#undef V294
+#define V294 (V + 893)
+ 0x20, 0x307, 0,
+#undef V295
+#define V295 (V + 896)
+ 0x20, 0x30a, 0,
+#undef V296
+#define V296 (V + 899)
+ 0x20, 0x328, 0,
+#undef V297
+#define V297 (V + 902)
+ 0x20, 0x303, 0,
+#undef V298
+#define V298 (V + 905)
+ 0x20, 0x30b, 0,
+#undef V299
+#define V299 (V + 908)
+ 0x263, 0,
+#undef V300
+#define V300 (V + 910)
+ 0x6c, 0,
+#undef V301
+#define V301 (V + 912)
+ 0x78, 0,
+#undef V302
+#define V302 (V + 914)
+ 0x295, 0,
+#undef V303
+#define V303 (V + 916)
+ 0x300, 0,
+#undef V304
+#define V304 (V + 918)
+ 0x301, 0,
+#undef V305
+#define V305 (V + 920)
+ 0x313, 0,
+#undef V306
+#define V306 (V + 922)
+ 0x308, 0x301, 0,
+#undef V307
+#define V307 (V + 925)
+ 0x2b9, 0,
+#undef V308
+#define V308 (V + 927)
+ 0x20, 0x345, 0,
+#undef V309
+#define V309 (V + 930)
+ 0x3b, 0,
+#undef V310
+#define V310 (V + 932)
+ 0x20, 0x308, 0x301, 0,
+#undef V311
+#define V311 (V + 936)
+ 0x391, 0x301, 0,
+#undef V312
+#define V312 (V + 939)
+ 0xb7, 0,
+#undef V313
+#define V313 (V + 941)
+ 0x395, 0x301, 0,
+#undef V314
+#define V314 (V + 944)
+ 0x397, 0x301, 0,
+#undef V315
+#define V315 (V + 947)
+ 0x399, 0x301, 0,
+#undef V316
+#define V316 (V + 950)
+ 0x39f, 0x301, 0,
+#undef V317
+#define V317 (V + 953)
+ 0x3a5, 0x301, 0,
+#undef V318
+#define V318 (V + 956)
+ 0x3a9, 0x301, 0,
+#undef V319
+#define V319 (V + 959)
+ 0x3b9, 0x308, 0x301, 0,
+#undef V320
+#define V320 (V + 963)
+ 0x399, 0x308, 0,
+#undef V321
+#define V321 (V + 966)
+ 0x3a5, 0x308, 0,
+#undef V322
+#define V322 (V + 969)
+ 0x3b1, 0x301, 0,
+#undef V323
+#define V323 (V + 972)
+ 0x3b5, 0x301, 0,
+#undef V324
+#define V324 (V + 975)
+ 0x3b7, 0x301, 0,
+#undef V325
+#define V325 (V + 978)
+ 0x3b9, 0x301, 0,
+#undef V326
+#define V326 (V + 981)
+ 0x3c5, 0x308, 0x301, 0,
+#undef V327
+#define V327 (V + 985)
+ 0x3b9, 0x308, 0,
+#undef V328
+#define V328 (V + 988)
+ 0x3c5, 0x308, 0,
+#undef V329
+#define V329 (V + 991)
+ 0x3bf, 0x301, 0,
+#undef V330
+#define V330 (V + 994)
+ 0x3c5, 0x301, 0,
+#undef V331
+#define V331 (V + 997)
+ 0x3c9, 0x301, 0,
+#undef V332
+#define V332 (V + 1000)
+ 0x3b2, 0,
+#undef V333
+#define V333 (V + 1002)
+ 0x3b8, 0,
+#undef V334
+#define V334 (V + 1004)
+ 0x3a5, 0,
+#undef V335
+#define V335 (V + 1006)
+ 0x3c6, 0,
+#undef V336
+#define V336 (V + 1008)
+ 0x3c0, 0,
+#undef V337
+#define V337 (V + 1010)
+ 0x3ba, 0,
+#undef V338
+#define V338 (V + 1012)
+ 0x3c1, 0,
+#undef V339
+#define V339 (V + 1014)
+ 0x3c2, 0,
+#undef V340
+#define V340 (V + 1016)
+ 0x398, 0,
+#undef V341
+#define V341 (V + 1018)
+ 0x3b5, 0,
+#undef V342
+#define V342 (V + 1020)
+ 0x3a3, 0,
+#undef V343
+#define V343 (V + 1022)
+ 0x415, 0x300, 0,
+#undef V344
+#define V344 (V + 1025)
+ 0x415, 0x308, 0,
+#undef V345
+#define V345 (V + 1028)
+ 0x413, 0x301, 0,
+#undef V346
+#define V346 (V + 1031)
+ 0x406, 0x308, 0,
+#undef V347
+#define V347 (V + 1034)
+ 0x41a, 0x301, 0,
+#undef V348
+#define V348 (V + 1037)
+ 0x418, 0x300, 0,
+#undef V349
+#define V349 (V + 1040)
+ 0x423, 0x306, 0,
+#undef V350
+#define V350 (V + 1043)
+ 0x418, 0x306, 0,
+#undef V351
+#define V351 (V + 1046)
+ 0x438, 0x306, 0,
+#undef V352
+#define V352 (V + 1049)
+ 0x435, 0x300, 0,
+#undef V353
+#define V353 (V + 1052)
+ 0x435, 0x308, 0,
+#undef V354
+#define V354 (V + 1055)
+ 0x433, 0x301, 0,
+#undef V355
+#define V355 (V + 1058)
+ 0x456, 0x308, 0,
+#undef V356
+#define V356 (V + 1061)
+ 0x43a, 0x301, 0,
+#undef V357
+#define V357 (V + 1064)
+ 0x438, 0x300, 0,
+#undef V358
+#define V358 (V + 1067)
+ 0x443, 0x306, 0,
+#undef V359
+#define V359 (V + 1070)
+ 0x474, 0x30f, 0,
+#undef V360
+#define V360 (V + 1073)
+ 0x475, 0x30f, 0,
+#undef V361
+#define V361 (V + 1076)
+ 0x416, 0x306, 0,
+#undef V362
+#define V362 (V + 1079)
+ 0x436, 0x306, 0,
+#undef V363
+#define V363 (V + 1082)
+ 0x410, 0x306, 0,
+#undef V364
+#define V364 (V + 1085)
+ 0x430, 0x306, 0,
+#undef V365
+#define V365 (V + 1088)
+ 0x410, 0x308, 0,
+#undef V366
+#define V366 (V + 1091)
+ 0x430, 0x308, 0,
+#undef V367
+#define V367 (V + 1094)
+ 0x415, 0x306, 0,
+#undef V368
+#define V368 (V + 1097)
+ 0x435, 0x306, 0,
+#undef V369
+#define V369 (V + 1100)
+ 0x4d8, 0x308, 0,
+#undef V370
+#define V370 (V + 1103)
+ 0x4d9, 0x308, 0,
+#undef V371
+#define V371 (V + 1106)
+ 0x416, 0x308, 0,
+#undef V372
+#define V372 (V + 1109)
+ 0x436, 0x308, 0,
+#undef V373
+#define V373 (V + 1112)
+ 0x417, 0x308, 0,
+#undef V374
+#define V374 (V + 1115)
+ 0x437, 0x308, 0,
+#undef V375
+#define V375 (V + 1118)
+ 0x418, 0x304, 0,
+#undef V376
+#define V376 (V + 1121)
+ 0x438, 0x304, 0,
+#undef V377
+#define V377 (V + 1124)
+ 0x418, 0x308, 0,
+#undef V378
+#define V378 (V + 1127)
+ 0x438, 0x308, 0,
+#undef V379
+#define V379 (V + 1130)
+ 0x41e, 0x308, 0,
+#undef V380
+#define V380 (V + 1133)
+ 0x43e, 0x308, 0,
+#undef V381
+#define V381 (V + 1136)
+ 0x4e8, 0x308, 0,
+#undef V382
+#define V382 (V + 1139)
+ 0x4e9, 0x308, 0,
+#undef V383
+#define V383 (V + 1142)
+ 0x42d, 0x308, 0,
+#undef V384
+#define V384 (V + 1145)
+ 0x44d, 0x308, 0,
+#undef V385
+#define V385 (V + 1148)
+ 0x423, 0x304, 0,
+#undef V386
+#define V386 (V + 1151)
+ 0x443, 0x304, 0,
+#undef V387
+#define V387 (V + 1154)
+ 0x423, 0x308, 0,
+#undef V388
+#define V388 (V + 1157)
+ 0x443, 0x308, 0,
+#undef V389
+#define V389 (V + 1160)
+ 0x423, 0x30b, 0,
+#undef V390
+#define V390 (V + 1163)
+ 0x443, 0x30b, 0,
+#undef V391
+#define V391 (V + 1166)
+ 0x427, 0x308, 0,
+#undef V392
+#define V392 (V + 1169)
+ 0x447, 0x308, 0,
+#undef V393
+#define V393 (V + 1172)
+ 0x42b, 0x308, 0,
+#undef V394
+#define V394 (V + 1175)
+ 0x44b, 0x308, 0,
+#undef V395
+#define V395 (V + 1178)
+ 0x565, 0x582, 0,
+#undef V396
+#define V396 (V + 1181)
+ 0x627, 0x653, 0,
+#undef V397
+#define V397 (V + 1184)
+ 0x627, 0x654, 0,
+#undef V398
+#define V398 (V + 1187)
+ 0x648, 0x654, 0,
+#undef V399
+#define V399 (V + 1190)
+ 0x627, 0x655, 0,
+#undef V400
+#define V400 (V + 1193)
+ 0x64a, 0x654, 0,
+#undef V401
+#define V401 (V + 1196)
+ 0x627, 0x674, 0,
+#undef V402
+#define V402 (V + 1199)
+ 0x648, 0x674, 0,
+#undef V403
+#define V403 (V + 1202)
+ 0x6c7, 0x674, 0,
+#undef V404
+#define V404 (V + 1205)
+ 0x64a, 0x674, 0,
+#undef V405
+#define V405 (V + 1208)
+ 0x6d5, 0x654, 0,
+#undef V406
+#define V406 (V + 1211)
+ 0x6c1, 0x654, 0,
+#undef V407
+#define V407 (V + 1214)
+ 0x6d2, 0x654, 0,
+#undef V408
+#define V408 (V + 1217)
+ 0x928, 0x93c, 0,
+#undef V409
+#define V409 (V + 1220)
+ 0x930, 0x93c, 0,
+#undef V410
+#define V410 (V + 1223)
+ 0x933, 0x93c, 0,
+#undef V411
+#define V411 (V + 1226)
+ 0x915, 0x93c, 0,
+#undef V412
+#define V412 (V + 1229)
+ 0x916, 0x93c, 0,
+#undef V413
+#define V413 (V + 1232)
+ 0x917, 0x93c, 0,
+#undef V414
+#define V414 (V + 1235)
+ 0x91c, 0x93c, 0,
+#undef V415
+#define V415 (V + 1238)
+ 0x921, 0x93c, 0,
+#undef V416
+#define V416 (V + 1241)
+ 0x922, 0x93c, 0,
+#undef V417
+#define V417 (V + 1244)
+ 0x92b, 0x93c, 0,
+#undef V418
+#define V418 (V + 1247)
+ 0x92f, 0x93c, 0,
+#undef V419
+#define V419 (V + 1250)
+ 0x9c7, 0x9be, 0,
+#undef V420
+#define V420 (V + 1253)
+ 0x9c7, 0x9d7, 0,
+#undef V421
+#define V421 (V + 1256)
+ 0x9a1, 0x9bc, 0,
+#undef V422
+#define V422 (V + 1259)
+ 0x9a2, 0x9bc, 0,
+#undef V423
+#define V423 (V + 1262)
+ 0x9af, 0x9bc, 0,
+#undef V424
+#define V424 (V + 1265)
+ 0xa32, 0xa3c, 0,
+#undef V425
+#define V425 (V + 1268)
+ 0xa38, 0xa3c, 0,
+#undef V426
+#define V426 (V + 1271)
+ 0xa16, 0xa3c, 0,
+#undef V427
+#define V427 (V + 1274)
+ 0xa17, 0xa3c, 0,
+#undef V428
+#define V428 (V + 1277)
+ 0xa1c, 0xa3c, 0,
+#undef V429
+#define V429 (V + 1280)
+ 0xa2b, 0xa3c, 0,
+#undef V430
+#define V430 (V + 1283)
+ 0xb47, 0xb56, 0,
+#undef V431
+#define V431 (V + 1286)
+ 0xb47, 0xb3e, 0,
+#undef V432
+#define V432 (V + 1289)
+ 0xb47, 0xb57, 0,
+#undef V433
+#define V433 (V + 1292)
+ 0xb21, 0xb3c, 0,
+#undef V434
+#define V434 (V + 1295)
+ 0xb22, 0xb3c, 0,
+#undef V435
+#define V435 (V + 1298)
+ 0xb92, 0xbd7, 0,
+#undef V436
+#define V436 (V + 1301)
+ 0xbc6, 0xbbe, 0,
+#undef V437
+#define V437 (V + 1304)
+ 0xbc7, 0xbbe, 0,
+#undef V438
+#define V438 (V + 1307)
+ 0xbc6, 0xbd7, 0,
+#undef V439
+#define V439 (V + 1310)
+ 0xc46, 0xc56, 0,
+#undef V440
+#define V440 (V + 1313)
+ 0xcbf, 0xcd5, 0,
+#undef V441
+#define V441 (V + 1316)
+ 0xcc6, 0xcd5, 0,
+#undef V442
+#define V442 (V + 1319)
+ 0xcc6, 0xcd6, 0,
+#undef V443
+#define V443 (V + 1322)
+ 0xcc6, 0xcc2, 0,
+#undef V444
+#define V444 (V + 1325)
+ 0xcc6, 0xcc2, 0xcd5, 0,
+#undef V445
+#define V445 (V + 1329)
+ 0xd46, 0xd3e, 0,
+#undef V446
+#define V446 (V + 1332)
+ 0xd47, 0xd3e, 0,
+#undef V447
+#define V447 (V + 1335)
+ 0xd46, 0xd57, 0,
+#undef V448
+#define V448 (V + 1338)
+ 0xdd9, 0xdca, 0,
+#undef V449
+#define V449 (V + 1341)
+ 0xdd9, 0xdcf, 0,
+#undef V450
+#define V450 (V + 1344)
+ 0xdd9, 0xdcf, 0xdca, 0,
+#undef V451
+#define V451 (V + 1348)
+ 0xdd9, 0xddf, 0,
+#undef V452
+#define V452 (V + 1351)
+ 0xe4d, 0xe32, 0,
+#undef V453
+#define V453 (V + 1354)
+ 0xecd, 0xeb2, 0,
+#undef V454
+#define V454 (V + 1357)
+ 0xeab, 0xe99, 0,
+#undef V455
+#define V455 (V + 1360)
+ 0xeab, 0xea1, 0,
+#undef V456
+#define V456 (V + 1363)
+ 0xf0b, 0,
+#undef V457
+#define V457 (V + 1365)
+ 0xf42, 0xfb7, 0,
+#undef V458
+#define V458 (V + 1368)
+ 0xf4c, 0xfb7, 0,
+#undef V459
+#define V459 (V + 1371)
+ 0xf51, 0xfb7, 0,
+#undef V460
+#define V460 (V + 1374)
+ 0xf56, 0xfb7, 0,
+#undef V461
+#define V461 (V + 1377)
+ 0xf5b, 0xfb7, 0,
+#undef V462
+#define V462 (V + 1380)
+ 0xf40, 0xfb5, 0,
+#undef V463
+#define V463 (V + 1383)
+ 0xf71, 0xf72, 0,
+#undef V464
+#define V464 (V + 1386)
+ 0xf71, 0xf74, 0,
+#undef V465
+#define V465 (V + 1389)
+ 0xfb2, 0xf80, 0,
+#undef V466
+#define V466 (V + 1392)
+ 0xfb2, 0xf71, 0xf80, 0,
+#undef V467
+#define V467 (V + 1396)
+ 0xfb3, 0xf80, 0,
+#undef V468
+#define V468 (V + 1399)
+ 0xfb3, 0xf71, 0xf80, 0,
+#undef V469
+#define V469 (V + 1403)
+ 0xf71, 0xf80, 0,
+#undef V470
+#define V470 (V + 1406)
+ 0xf92, 0xfb7, 0,
+#undef V471
+#define V471 (V + 1409)
+ 0xf9c, 0xfb7, 0,
+#undef V472
+#define V472 (V + 1412)
+ 0xfa1, 0xfb7, 0,
+#undef V473
+#define V473 (V + 1415)
+ 0xfa6, 0xfb7, 0,
+#undef V474
+#define V474 (V + 1418)
+ 0xfab, 0xfb7, 0,
+#undef V475
+#define V475 (V + 1421)
+ 0xf90, 0xfb5, 0,
+#undef V476
+#define V476 (V + 1424)
+ 0x1025, 0x102e, 0,
+#undef V477
+#define V477 (V + 1427)
+ 0x10dc, 0,
+#undef V478
+#define V478 (V + 1429)
+ 0x1b05, 0x1b35, 0,
+#undef V479
+#define V479 (V + 1432)
+ 0x1b07, 0x1b35, 0,
+#undef V480
+#define V480 (V + 1435)
+ 0x1b09, 0x1b35, 0,
+#undef V481
+#define V481 (V + 1438)
+ 0x1b0b, 0x1b35, 0,
+#undef V482
+#define V482 (V + 1441)
+ 0x1b0d, 0x1b35, 0,
+#undef V483
+#define V483 (V + 1444)
+ 0x1b11, 0x1b35, 0,
+#undef V484
+#define V484 (V + 1447)
+ 0x1b3a, 0x1b35, 0,
+#undef V485
+#define V485 (V + 1450)
+ 0x1b3c, 0x1b35, 0,
+#undef V486
+#define V486 (V + 1453)
+ 0x1b3e, 0x1b35, 0,
+#undef V487
+#define V487 (V + 1456)
+ 0x1b3f, 0x1b35, 0,
+#undef V488
+#define V488 (V + 1459)
+ 0x1b42, 0x1b35, 0,
+#undef V489
+#define V489 (V + 1462)
+ 0x41, 0,
+#undef V490
+#define V490 (V + 1464)
+ 0xc6, 0,
+#undef V491
+#define V491 (V + 1466)
+ 0x42, 0,
+#undef V492
+#define V492 (V + 1468)
+ 0x44, 0,
+#undef V493
+#define V493 (V + 1470)
+ 0x45, 0,
+#undef V494
+#define V494 (V + 1472)
+ 0x18e, 0,
+#undef V495
+#define V495 (V + 1474)
+ 0x47, 0,
+#undef V496
+#define V496 (V + 1476)
+ 0x48, 0,
+#undef V497
+#define V497 (V + 1478)
+ 0x49, 0,
+#undef V498
+#define V498 (V + 1480)
+ 0x4a, 0,
+#undef V499
+#define V499 (V + 1482)
+ 0x4b, 0,
+#undef V500
+#define V500 (V + 1484)
+ 0x4c, 0,
+#undef V501
+#define V501 (V + 1486)
+ 0x4d, 0,
+#undef V502
+#define V502 (V + 1488)
+ 0x4e, 0,
+#undef V503
+#define V503 (V + 1490)
+ 0x4f, 0,
+#undef V504
+#define V504 (V + 1492)
+ 0x222, 0,
+#undef V505
+#define V505 (V + 1494)
+ 0x50, 0,
+#undef V506
+#define V506 (V + 1496)
+ 0x52, 0,
+#undef V507
+#define V507 (V + 1498)
+ 0x54, 0,
+#undef V508
+#define V508 (V + 1500)
+ 0x55, 0,
+#undef V509
+#define V509 (V + 1502)
+ 0x57, 0,
+#undef V510
+#define V510 (V + 1504)
+ 0x250, 0,
+#undef V511
+#define V511 (V + 1506)
+ 0x251, 0,
+#undef V512
+#define V512 (V + 1508)
+ 0x1d02, 0,
+#undef V513
+#define V513 (V + 1510)
+ 0x62, 0,
+#undef V514
+#define V514 (V + 1512)
+ 0x64, 0,
+#undef V515
+#define V515 (V + 1514)
+ 0x65, 0,
+#undef V516
+#define V516 (V + 1516)
+ 0x259, 0,
+#undef V517
+#define V517 (V + 1518)
+ 0x25b, 0,
+#undef V518
+#define V518 (V + 1520)
+ 0x25c, 0,
+#undef V519
+#define V519 (V + 1522)
+ 0x67, 0,
+#undef V520
+#define V520 (V + 1524)
+ 0x6b, 0,
+#undef V521
+#define V521 (V + 1526)
+ 0x6d, 0,
+#undef V522
+#define V522 (V + 1528)
+ 0x14b, 0,
+#undef V523
+#define V523 (V + 1530)
+ 0x254, 0,
+#undef V524
+#define V524 (V + 1532)
+ 0x1d16, 0,
+#undef V525
+#define V525 (V + 1534)
+ 0x1d17, 0,
+#undef V526
+#define V526 (V + 1536)
+ 0x70, 0,
+#undef V527
+#define V527 (V + 1538)
+ 0x74, 0,
+#undef V528
+#define V528 (V + 1540)
+ 0x75, 0,
+#undef V529
+#define V529 (V + 1542)
+ 0x1d1d, 0,
+#undef V530
+#define V530 (V + 1544)
+ 0x26f, 0,
+#undef V531
+#define V531 (V + 1546)
+ 0x76, 0,
+#undef V532
+#define V532 (V + 1548)
+ 0x1d25, 0,
+#undef V533
+#define V533 (V + 1550)
+ 0x3b3, 0,
+#undef V534
+#define V534 (V + 1552)
+ 0x3b4, 0,
+#undef V535
+#define V535 (V + 1554)
+ 0x3c7, 0,
+#undef V536
+#define V536 (V + 1556)
+ 0x69, 0,
+#undef V537
+#define V537 (V + 1558)
+ 0x43d, 0,
+#undef V538
+#define V538 (V + 1560)
+ 0x252, 0,
+#undef V539
+#define V539 (V + 1562)
+ 0x63, 0,
+#undef V540
+#define V540 (V + 1564)
+ 0x255, 0,
+#undef V541
+#define V541 (V + 1566)
+ 0xf0, 0,
+#undef V542
+#define V542 (V + 1568)
+ 0x66, 0,
+#undef V543
+#define V543 (V + 1570)
+ 0x25f, 0,
+#undef V544
+#define V544 (V + 1572)
+ 0x261, 0,
+#undef V545
+#define V545 (V + 1574)
+ 0x265, 0,
+#undef V546
+#define V546 (V + 1576)
+ 0x268, 0,
+#undef V547
+#define V547 (V + 1578)
+ 0x269, 0,
+#undef V548
+#define V548 (V + 1580)
+ 0x26a, 0,
+#undef V549
+#define V549 (V + 1582)
+ 0x1d7b, 0,
+#undef V550
+#define V550 (V + 1584)
+ 0x29d, 0,
+#undef V551
+#define V551 (V + 1586)
+ 0x26d, 0,
+#undef V552
+#define V552 (V + 1588)
+ 0x1d85, 0,
+#undef V553
+#define V553 (V + 1590)
+ 0x29f, 0,
+#undef V554
+#define V554 (V + 1592)
+ 0x271, 0,
+#undef V555
+#define V555 (V + 1594)
+ 0x270, 0,
+#undef V556
+#define V556 (V + 1596)
+ 0x272, 0,
+#undef V557
+#define V557 (V + 1598)
+ 0x273, 0,
+#undef V558
+#define V558 (V + 1600)
+ 0x274, 0,
+#undef V559
+#define V559 (V + 1602)
+ 0x275, 0,
+#undef V560
+#define V560 (V + 1604)
+ 0x278, 0,
+#undef V561
+#define V561 (V + 1606)
+ 0x282, 0,
+#undef V562
+#define V562 (V + 1608)
+ 0x283, 0,
+#undef V563
+#define V563 (V + 1610)
+ 0x1ab, 0,
+#undef V564
+#define V564 (V + 1612)
+ 0x289, 0,
+#undef V565
+#define V565 (V + 1614)
+ 0x28a, 0,
+#undef V566
+#define V566 (V + 1616)
+ 0x1d1c, 0,
+#undef V567
+#define V567 (V + 1618)
+ 0x28b, 0,
+#undef V568
+#define V568 (V + 1620)
+ 0x28c, 0,
+#undef V569
+#define V569 (V + 1622)
+ 0x7a, 0,
+#undef V570
+#define V570 (V + 1624)
+ 0x290, 0,
+#undef V571
+#define V571 (V + 1626)
+ 0x291, 0,
+#undef V572
+#define V572 (V + 1628)
+ 0x292, 0,
+#undef V573
+#define V573 (V + 1630)
+ 0x41, 0x325, 0,
+#undef V574
+#define V574 (V + 1633)
+ 0x61, 0x325, 0,
+#undef V575
+#define V575 (V + 1636)
+ 0x42, 0x307, 0,
+#undef V576
+#define V576 (V + 1639)
+ 0x62, 0x307, 0,
+#undef V577
+#define V577 (V + 1642)
+ 0x42, 0x323, 0,
+#undef V578
+#define V578 (V + 1645)
+ 0x62, 0x323, 0,
+#undef V579
+#define V579 (V + 1648)
+ 0x42, 0x331, 0,
+#undef V580
+#define V580 (V + 1651)
+ 0x62, 0x331, 0,
+#undef V581
+#define V581 (V + 1654)
+ 0x43, 0x327, 0x301, 0,
+#undef V582
+#define V582 (V + 1658)
+ 0x63, 0x327, 0x301, 0,
+#undef V583
+#define V583 (V + 1662)
+ 0x44, 0x307, 0,
+#undef V584
+#define V584 (V + 1665)
+ 0x64, 0x307, 0,
+#undef V585
+#define V585 (V + 1668)
+ 0x44, 0x323, 0,
+#undef V586
+#define V586 (V + 1671)
+ 0x64, 0x323, 0,
+#undef V587
+#define V587 (V + 1674)
+ 0x44, 0x331, 0,
+#undef V588
+#define V588 (V + 1677)
+ 0x64, 0x331, 0,
+#undef V589
+#define V589 (V + 1680)
+ 0x44, 0x327, 0,
+#undef V590
+#define V590 (V + 1683)
+ 0x64, 0x327, 0,
+#undef V591
+#define V591 (V + 1686)
+ 0x44, 0x32d, 0,
+#undef V592
+#define V592 (V + 1689)
+ 0x64, 0x32d, 0,
+#undef V593
+#define V593 (V + 1692)
+ 0x45, 0x304, 0x300, 0,
+#undef V594
+#define V594 (V + 1696)
+ 0x65, 0x304, 0x300, 0,
+#undef V595
+#define V595 (V + 1700)
+ 0x45, 0x304, 0x301, 0,
+#undef V596
+#define V596 (V + 1704)
+ 0x65, 0x304, 0x301, 0,
+#undef V597
+#define V597 (V + 1708)
+ 0x45, 0x32d, 0,
+#undef V598
+#define V598 (V + 1711)
+ 0x65, 0x32d, 0,
+#undef V599
+#define V599 (V + 1714)
+ 0x45, 0x330, 0,
+#undef V600
+#define V600 (V + 1717)
+ 0x65, 0x330, 0,
+#undef V601
+#define V601 (V + 1720)
+ 0x45, 0x327, 0x306, 0,
+#undef V602
+#define V602 (V + 1724)
+ 0x65, 0x327, 0x306, 0,
+#undef V603
+#define V603 (V + 1728)
+ 0x46, 0x307, 0,
+#undef V604
+#define V604 (V + 1731)
+ 0x66, 0x307, 0,
+#undef V605
+#define V605 (V + 1734)
+ 0x47, 0x304, 0,
+#undef V606
+#define V606 (V + 1737)
+ 0x67, 0x304, 0,
+#undef V607
+#define V607 (V + 1740)
+ 0x48, 0x307, 0,
+#undef V608
+#define V608 (V + 1743)
+ 0x68, 0x307, 0,
+#undef V609
+#define V609 (V + 1746)
+ 0x48, 0x323, 0,
+#undef V610
+#define V610 (V + 1749)
+ 0x68, 0x323, 0,
+#undef V611
+#define V611 (V + 1752)
+ 0x48, 0x308, 0,
+#undef V612
+#define V612 (V + 1755)
+ 0x68, 0x308, 0,
+#undef V613
+#define V613 (V + 1758)
+ 0x48, 0x327, 0,
+#undef V614
+#define V614 (V + 1761)
+ 0x68, 0x327, 0,
+#undef V615
+#define V615 (V + 1764)
+ 0x48, 0x32e, 0,
+#undef V616
+#define V616 (V + 1767)
+ 0x68, 0x32e, 0,
+#undef V617
+#define V617 (V + 1770)
+ 0x49, 0x330, 0,
+#undef V618
+#define V618 (V + 1773)
+ 0x69, 0x330, 0,
+#undef V619
+#define V619 (V + 1776)
+ 0x49, 0x308, 0x301, 0,
+#undef V620
+#define V620 (V + 1780)
+ 0x69, 0x308, 0x301, 0,
+#undef V621
+#define V621 (V + 1784)
+ 0x4b, 0x301, 0,
+#undef V622
+#define V622 (V + 1787)
+ 0x6b, 0x301, 0,
+#undef V623
+#define V623 (V + 1790)
+ 0x4b, 0x323, 0,
+#undef V624
+#define V624 (V + 1793)
+ 0x6b, 0x323, 0,
+#undef V625
+#define V625 (V + 1796)
+ 0x4b, 0x331, 0,
+#undef V626
+#define V626 (V + 1799)
+ 0x6b, 0x331, 0,
+#undef V627
+#define V627 (V + 1802)
+ 0x4c, 0x323, 0,
+#undef V628
+#define V628 (V + 1805)
+ 0x6c, 0x323, 0,
+#undef V629
+#define V629 (V + 1808)
+ 0x4c, 0x323, 0x304, 0,
+#undef V630
+#define V630 (V + 1812)
+ 0x6c, 0x323, 0x304, 0,
+#undef V631
+#define V631 (V + 1816)
+ 0x4c, 0x331, 0,
+#undef V632
+#define V632 (V + 1819)
+ 0x6c, 0x331, 0,
+#undef V633
+#define V633 (V + 1822)
+ 0x4c, 0x32d, 0,
+#undef V634
+#define V634 (V + 1825)
+ 0x6c, 0x32d, 0,
+#undef V635
+#define V635 (V + 1828)
+ 0x4d, 0x301, 0,
+#undef V636
+#define V636 (V + 1831)
+ 0x6d, 0x301, 0,
+#undef V637
+#define V637 (V + 1834)
+ 0x4d, 0x307, 0,
+#undef V638
+#define V638 (V + 1837)
+ 0x6d, 0x307, 0,
+#undef V639
+#define V639 (V + 1840)
+ 0x4d, 0x323, 0,
+#undef V640
+#define V640 (V + 1843)
+ 0x6d, 0x323, 0,
+#undef V641
+#define V641 (V + 1846)
+ 0x4e, 0x307, 0,
+#undef V642
+#define V642 (V + 1849)
+ 0x6e, 0x307, 0,
+#undef V643
+#define V643 (V + 1852)
+ 0x4e, 0x323, 0,
+#undef V644
+#define V644 (V + 1855)
+ 0x6e, 0x323, 0,
+#undef V645
+#define V645 (V + 1858)
+ 0x4e, 0x331, 0,
+#undef V646
+#define V646 (V + 1861)
+ 0x6e, 0x331, 0,
+#undef V647
+#define V647 (V + 1864)
+ 0x4e, 0x32d, 0,
+#undef V648
+#define V648 (V + 1867)
+ 0x6e, 0x32d, 0,
+#undef V649
+#define V649 (V + 1870)
+ 0x4f, 0x303, 0x301, 0,
+#undef V650
+#define V650 (V + 1874)
+ 0x6f, 0x303, 0x301, 0,
+#undef V651
+#define V651 (V + 1878)
+ 0x4f, 0x303, 0x308, 0,
+#undef V652
+#define V652 (V + 1882)
+ 0x6f, 0x303, 0x308, 0,
+#undef V653
+#define V653 (V + 1886)
+ 0x4f, 0x304, 0x300, 0,
+#undef V654
+#define V654 (V + 1890)
+ 0x6f, 0x304, 0x300, 0,
+#undef V655
+#define V655 (V + 1894)
+ 0x4f, 0x304, 0x301, 0,
+#undef V656
+#define V656 (V + 1898)
+ 0x6f, 0x304, 0x301, 0,
+#undef V657
+#define V657 (V + 1902)
+ 0x50, 0x301, 0,
+#undef V658
+#define V658 (V + 1905)
+ 0x70, 0x301, 0,
+#undef V659
+#define V659 (V + 1908)
+ 0x50, 0x307, 0,
+#undef V660
+#define V660 (V + 1911)
+ 0x70, 0x307, 0,
+#undef V661
+#define V661 (V + 1914)
+ 0x52, 0x307, 0,
+#undef V662
+#define V662 (V + 1917)
+ 0x72, 0x307, 0,
+#undef V663
+#define V663 (V + 1920)
+ 0x52, 0x323, 0,
+#undef V664
+#define V664 (V + 1923)
+ 0x72, 0x323, 0,
+#undef V665
+#define V665 (V + 1926)
+ 0x52, 0x323, 0x304, 0,
+#undef V666
+#define V666 (V + 1930)
+ 0x72, 0x323, 0x304, 0,
+#undef V667
+#define V667 (V + 1934)
+ 0x52, 0x331, 0,
+#undef V668
+#define V668 (V + 1937)
+ 0x72, 0x331, 0,
+#undef V669
+#define V669 (V + 1940)
+ 0x53, 0x307, 0,
+#undef V670
+#define V670 (V + 1943)
+ 0x73, 0x307, 0,
+#undef V671
+#define V671 (V + 1946)
+ 0x53, 0x323, 0,
+#undef V672
+#define V672 (V + 1949)
+ 0x73, 0x323, 0,
+#undef V673
+#define V673 (V + 1952)
+ 0x53, 0x301, 0x307, 0,
+#undef V674
+#define V674 (V + 1956)
+ 0x73, 0x301, 0x307, 0,
+#undef V675
+#define V675 (V + 1960)
+ 0x53, 0x30c, 0x307, 0,
+#undef V676
+#define V676 (V + 1964)
+ 0x73, 0x30c, 0x307, 0,
+#undef V677
+#define V677 (V + 1968)
+ 0x53, 0x323, 0x307, 0,
+#undef V678
+#define V678 (V + 1972)
+ 0x73, 0x323, 0x307, 0,
+#undef V679
+#define V679 (V + 1976)
+ 0x54, 0x307, 0,
+#undef V680
+#define V680 (V + 1979)
+ 0x74, 0x307, 0,
+#undef V681
+#define V681 (V + 1982)
+ 0x54, 0x323, 0,
+#undef V682
+#define V682 (V + 1985)
+ 0x74, 0x323, 0,
+#undef V683
+#define V683 (V + 1988)
+ 0x54, 0x331, 0,
+#undef V684
+#define V684 (V + 1991)
+ 0x74, 0x331, 0,
+#undef V685
+#define V685 (V + 1994)
+ 0x54, 0x32d, 0,
+#undef V686
+#define V686 (V + 1997)
+ 0x74, 0x32d, 0,
+#undef V687
+#define V687 (V + 2000)
+ 0x55, 0x324, 0,
+#undef V688
+#define V688 (V + 2003)
+ 0x75, 0x324, 0,
+#undef V689
+#define V689 (V + 2006)
+ 0x55, 0x330, 0,
+#undef V690
+#define V690 (V + 2009)
+ 0x75, 0x330, 0,
+#undef V691
+#define V691 (V + 2012)
+ 0x55, 0x32d, 0,
+#undef V692
+#define V692 (V + 2015)
+ 0x75, 0x32d, 0,
+#undef V693
+#define V693 (V + 2018)
+ 0x55, 0x303, 0x301, 0,
+#undef V694
+#define V694 (V + 2022)
+ 0x75, 0x303, 0x301, 0,
+#undef V695
+#define V695 (V + 2026)
+ 0x55, 0x304, 0x308, 0,
+#undef V696
+#define V696 (V + 2030)
+ 0x75, 0x304, 0x308, 0,
+#undef V697
+#define V697 (V + 2034)
+ 0x56, 0x303, 0,
+#undef V698
+#define V698 (V + 2037)
+ 0x76, 0x303, 0,
+#undef V699
+#define V699 (V + 2040)
+ 0x56, 0x323, 0,
+#undef V700
+#define V700 (V + 2043)
+ 0x76, 0x323, 0,
+#undef V701
+#define V701 (V + 2046)
+ 0x57, 0x300, 0,
+#undef V702
+#define V702 (V + 2049)
+ 0x77, 0x300, 0,
+#undef V703
+#define V703 (V + 2052)
+ 0x57, 0x301, 0,
+#undef V704
+#define V704 (V + 2055)
+ 0x77, 0x301, 0,
+#undef V705
+#define V705 (V + 2058)
+ 0x57, 0x308, 0,
+#undef V706
+#define V706 (V + 2061)
+ 0x77, 0x308, 0,
+#undef V707
+#define V707 (V + 2064)
+ 0x57, 0x307, 0,
+#undef V708
+#define V708 (V + 2067)
+ 0x77, 0x307, 0,
+#undef V709
+#define V709 (V + 2070)
+ 0x57, 0x323, 0,
+#undef V710
+#define V710 (V + 2073)
+ 0x77, 0x323, 0,
+#undef V711
+#define V711 (V + 2076)
+ 0x58, 0x307, 0,
+#undef V712
+#define V712 (V + 2079)
+ 0x78, 0x307, 0,
+#undef V713
+#define V713 (V + 2082)
+ 0x58, 0x308, 0,
+#undef V714
+#define V714 (V + 2085)
+ 0x78, 0x308, 0,
+#undef V715
+#define V715 (V + 2088)
+ 0x59, 0x307, 0,
+#undef V716
+#define V716 (V + 2091)
+ 0x79, 0x307, 0,
+#undef V717
+#define V717 (V + 2094)
+ 0x5a, 0x302, 0,
+#undef V718
+#define V718 (V + 2097)
+ 0x7a, 0x302, 0,
+#undef V719
+#define V719 (V + 2100)
+ 0x5a, 0x323, 0,
+#undef V720
+#define V720 (V + 2103)
+ 0x7a, 0x323, 0,
+#undef V721
+#define V721 (V + 2106)
+ 0x5a, 0x331, 0,
+#undef V722
+#define V722 (V + 2109)
+ 0x7a, 0x331, 0,
+#undef V723
+#define V723 (V + 2112)
+ 0x68, 0x331, 0,
+#undef V724
+#define V724 (V + 2115)
+ 0x74, 0x308, 0,
+#undef V725
+#define V725 (V + 2118)
+ 0x77, 0x30a, 0,
+#undef V726
+#define V726 (V + 2121)
+ 0x79, 0x30a, 0,
+#undef V727
+#define V727 (V + 2124)
+ 0x61, 0x2be, 0,
+#undef V728
+#define V728 (V + 2127)
+ 0x41, 0x323, 0,
+#undef V729
+#define V729 (V + 2130)
+ 0x61, 0x323, 0,
+#undef V730
+#define V730 (V + 2133)
+ 0x41, 0x309, 0,
+#undef V731
+#define V731 (V + 2136)
+ 0x61, 0x309, 0,
+#undef V732
+#define V732 (V + 2139)
+ 0x41, 0x302, 0x301, 0,
+#undef V733
+#define V733 (V + 2143)
+ 0x61, 0x302, 0x301, 0,
+#undef V734
+#define V734 (V + 2147)
+ 0x41, 0x302, 0x300, 0,
+#undef V735
+#define V735 (V + 2151)
+ 0x61, 0x302, 0x300, 0,
+#undef V736
+#define V736 (V + 2155)
+ 0x41, 0x302, 0x309, 0,
+#undef V737
+#define V737 (V + 2159)
+ 0x61, 0x302, 0x309, 0,
+#undef V738
+#define V738 (V + 2163)
+ 0x41, 0x302, 0x303, 0,
+#undef V739
+#define V739 (V + 2167)
+ 0x61, 0x302, 0x303, 0,
+#undef V740
+#define V740 (V + 2171)
+ 0x41, 0x323, 0x302, 0,
+#undef V741
+#define V741 (V + 2175)
+ 0x61, 0x323, 0x302, 0,
+#undef V742
+#define V742 (V + 2179)
+ 0x41, 0x306, 0x301, 0,
+#undef V743
+#define V743 (V + 2183)
+ 0x61, 0x306, 0x301, 0,
+#undef V744
+#define V744 (V + 2187)
+ 0x41, 0x306, 0x300, 0,
+#undef V745
+#define V745 (V + 2191)
+ 0x61, 0x306, 0x300, 0,
+#undef V746
+#define V746 (V + 2195)
+ 0x41, 0x306, 0x309, 0,
+#undef V747
+#define V747 (V + 2199)
+ 0x61, 0x306, 0x309, 0,
+#undef V748
+#define V748 (V + 2203)
+ 0x41, 0x306, 0x303, 0,
+#undef V749
+#define V749 (V + 2207)
+ 0x61, 0x306, 0x303, 0,
+#undef V750
+#define V750 (V + 2211)
+ 0x41, 0x323, 0x306, 0,
+#undef V751
+#define V751 (V + 2215)
+ 0x61, 0x323, 0x306, 0,
+#undef V752
+#define V752 (V + 2219)
+ 0x45, 0x323, 0,
+#undef V753
+#define V753 (V + 2222)
+ 0x65, 0x323, 0,
+#undef V754
+#define V754 (V + 2225)
+ 0x45, 0x309, 0,
+#undef V755
+#define V755 (V + 2228)
+ 0x65, 0x309, 0,
+#undef V756
+#define V756 (V + 2231)
+ 0x45, 0x303, 0,
+#undef V757
+#define V757 (V + 2234)
+ 0x65, 0x303, 0,
+#undef V758
+#define V758 (V + 2237)
+ 0x45, 0x302, 0x301, 0,
+#undef V759
+#define V759 (V + 2241)
+ 0x65, 0x302, 0x301, 0,
+#undef V760
+#define V760 (V + 2245)
+ 0x45, 0x302, 0x300, 0,
+#undef V761
+#define V761 (V + 2249)
+ 0x65, 0x302, 0x300, 0,
+#undef V762
+#define V762 (V + 2253)
+ 0x45, 0x302, 0x309, 0,
+#undef V763
+#define V763 (V + 2257)
+ 0x65, 0x302, 0x309, 0,
+#undef V764
+#define V764 (V + 2261)
+ 0x45, 0x302, 0x303, 0,
+#undef V765
+#define V765 (V + 2265)
+ 0x65, 0x302, 0x303, 0,
+#undef V766
+#define V766 (V + 2269)
+ 0x45, 0x323, 0x302, 0,
+#undef V767
+#define V767 (V + 2273)
+ 0x65, 0x323, 0x302, 0,
+#undef V768
+#define V768 (V + 2277)
+ 0x49, 0x309, 0,
+#undef V769
+#define V769 (V + 2280)
+ 0x69, 0x309, 0,
+#undef V770
+#define V770 (V + 2283)
+ 0x49, 0x323, 0,
+#undef V771
+#define V771 (V + 2286)
+ 0x69, 0x323, 0,
+#undef V772
+#define V772 (V + 2289)
+ 0x4f, 0x323, 0,
+#undef V773
+#define V773 (V + 2292)
+ 0x6f, 0x323, 0,
+#undef V774
+#define V774 (V + 2295)
+ 0x4f, 0x309, 0,
+#undef V775
+#define V775 (V + 2298)
+ 0x6f, 0x309, 0,
+#undef V776
+#define V776 (V + 2301)
+ 0x4f, 0x302, 0x301, 0,
+#undef V777
+#define V777 (V + 2305)
+ 0x6f, 0x302, 0x301, 0,
+#undef V778
+#define V778 (V + 2309)
+ 0x4f, 0x302, 0x300, 0,
+#undef V779
+#define V779 (V + 2313)
+ 0x6f, 0x302, 0x300, 0,
+#undef V780
+#define V780 (V + 2317)
+ 0x4f, 0x302, 0x309, 0,
+#undef V781
+#define V781 (V + 2321)
+ 0x6f, 0x302, 0x309, 0,
+#undef V782
+#define V782 (V + 2325)
+ 0x4f, 0x302, 0x303, 0,
+#undef V783
+#define V783 (V + 2329)
+ 0x6f, 0x302, 0x303, 0,
+#undef V784
+#define V784 (V + 2333)
+ 0x4f, 0x323, 0x302, 0,
+#undef V785
+#define V785 (V + 2337)
+ 0x6f, 0x323, 0x302, 0,
+#undef V786
+#define V786 (V + 2341)
+ 0x4f, 0x31b, 0x301, 0,
+#undef V787
+#define V787 (V + 2345)
+ 0x6f, 0x31b, 0x301, 0,
+#undef V788
+#define V788 (V + 2349)
+ 0x4f, 0x31b, 0x300, 0,
+#undef V789
+#define V789 (V + 2353)
+ 0x6f, 0x31b, 0x300, 0,
+#undef V790
+#define V790 (V + 2357)
+ 0x4f, 0x31b, 0x309, 0,
+#undef V791
+#define V791 (V + 2361)
+ 0x6f, 0x31b, 0x309, 0,
+#undef V792
+#define V792 (V + 2365)
+ 0x4f, 0x31b, 0x303, 0,
+#undef V793
+#define V793 (V + 2369)
+ 0x6f, 0x31b, 0x303, 0,
+#undef V794
+#define V794 (V + 2373)
+ 0x4f, 0x31b, 0x323, 0,
+#undef V795
+#define V795 (V + 2377)
+ 0x6f, 0x31b, 0x323, 0,
+#undef V796
+#define V796 (V + 2381)
+ 0x55, 0x323, 0,
+#undef V797
+#define V797 (V + 2384)
+ 0x75, 0x323, 0,
+#undef V798
+#define V798 (V + 2387)
+ 0x55, 0x309, 0,
+#undef V799
+#define V799 (V + 2390)
+ 0x75, 0x309, 0,
+#undef V800
+#define V800 (V + 2393)
+ 0x55, 0x31b, 0x301, 0,
+#undef V801
+#define V801 (V + 2397)
+ 0x75, 0x31b, 0x301, 0,
+#undef V802
+#define V802 (V + 2401)
+ 0x55, 0x31b, 0x300, 0,
+#undef V803
+#define V803 (V + 2405)
+ 0x75, 0x31b, 0x300, 0,
+#undef V804
+#define V804 (V + 2409)
+ 0x55, 0x31b, 0x309, 0,
+#undef V805
+#define V805 (V + 2413)
+ 0x75, 0x31b, 0x309, 0,
+#undef V806
+#define V806 (V + 2417)
+ 0x55, 0x31b, 0x303, 0,
+#undef V807
+#define V807 (V + 2421)
+ 0x75, 0x31b, 0x303, 0,
+#undef V808
+#define V808 (V + 2425)
+ 0x55, 0x31b, 0x323, 0,
+#undef V809
+#define V809 (V + 2429)
+ 0x75, 0x31b, 0x323, 0,
+#undef V810
+#define V810 (V + 2433)
+ 0x59, 0x300, 0,
+#undef V811
+#define V811 (V + 2436)
+ 0x79, 0x300, 0,
+#undef V812
+#define V812 (V + 2439)
+ 0x59, 0x323, 0,
+#undef V813
+#define V813 (V + 2442)
+ 0x79, 0x323, 0,
+#undef V814
+#define V814 (V + 2445)
+ 0x59, 0x309, 0,
+#undef V815
+#define V815 (V + 2448)
+ 0x79, 0x309, 0,
+#undef V816
+#define V816 (V + 2451)
+ 0x59, 0x303, 0,
+#undef V817
+#define V817 (V + 2454)
+ 0x79, 0x303, 0,
+#undef V818
+#define V818 (V + 2457)
+ 0x3b1, 0x313, 0,
+#undef V819
+#define V819 (V + 2460)
+ 0x3b1, 0x314, 0,
+#undef V820
+#define V820 (V + 2463)
+ 0x3b1, 0x313, 0x300, 0,
+#undef V821
+#define V821 (V + 2467)
+ 0x3b1, 0x314, 0x300, 0,
+#undef V822
+#define V822 (V + 2471)
+ 0x3b1, 0x313, 0x301, 0,
+#undef V823
+#define V823 (V + 2475)
+ 0x3b1, 0x314, 0x301, 0,
+#undef V824
+#define V824 (V + 2479)
+ 0x3b1, 0x313, 0x342, 0,
+#undef V825
+#define V825 (V + 2483)
+ 0x3b1, 0x314, 0x342, 0,
+#undef V826
+#define V826 (V + 2487)
+ 0x391, 0x313, 0,
+#undef V827
+#define V827 (V + 2490)
+ 0x391, 0x314, 0,
+#undef V828
+#define V828 (V + 2493)
+ 0x391, 0x313, 0x300, 0,
+#undef V829
+#define V829 (V + 2497)
+ 0x391, 0x314, 0x300, 0,
+#undef V830
+#define V830 (V + 2501)
+ 0x391, 0x313, 0x301, 0,
+#undef V831
+#define V831 (V + 2505)
+ 0x391, 0x314, 0x301, 0,
+#undef V832
+#define V832 (V + 2509)
+ 0x391, 0x313, 0x342, 0,
+#undef V833
+#define V833 (V + 2513)
+ 0x391, 0x314, 0x342, 0,
+#undef V834
+#define V834 (V + 2517)
+ 0x3b5, 0x313, 0,
+#undef V835
+#define V835 (V + 2520)
+ 0x3b5, 0x314, 0,
+#undef V836
+#define V836 (V + 2523)
+ 0x3b5, 0x313, 0x300, 0,
+#undef V837
+#define V837 (V + 2527)
+ 0x3b5, 0x314, 0x300, 0,
+#undef V838
+#define V838 (V + 2531)
+ 0x3b5, 0x313, 0x301, 0,
+#undef V839
+#define V839 (V + 2535)
+ 0x3b5, 0x314, 0x301, 0,
+#undef V840
+#define V840 (V + 2539)
+ 0x395, 0x313, 0,
+#undef V841
+#define V841 (V + 2542)
+ 0x395, 0x314, 0,
+#undef V842
+#define V842 (V + 2545)
+ 0x395, 0x313, 0x300, 0,
+#undef V843
+#define V843 (V + 2549)
+ 0x395, 0x314, 0x300, 0,
+#undef V844
+#define V844 (V + 2553)
+ 0x395, 0x313, 0x301, 0,
+#undef V845
+#define V845 (V + 2557)
+ 0x395, 0x314, 0x301, 0,
+#undef V846
+#define V846 (V + 2561)
+ 0x3b7, 0x313, 0,
+#undef V847
+#define V847 (V + 2564)
+ 0x3b7, 0x314, 0,
+#undef V848
+#define V848 (V + 2567)
+ 0x3b7, 0x313, 0x300, 0,
+#undef V849
+#define V849 (V + 2571)
+ 0x3b7, 0x314, 0x300, 0,
+#undef V850
+#define V850 (V + 2575)
+ 0x3b7, 0x313, 0x301, 0,
+#undef V851
+#define V851 (V + 2579)
+ 0x3b7, 0x314, 0x301, 0,
+#undef V852
+#define V852 (V + 2583)
+ 0x3b7, 0x313, 0x342, 0,
+#undef V853
+#define V853 (V + 2587)
+ 0x3b7, 0x314, 0x342, 0,
+#undef V854
+#define V854 (V + 2591)
+ 0x397, 0x313, 0,
+#undef V855
+#define V855 (V + 2594)
+ 0x397, 0x314, 0,
+#undef V856
+#define V856 (V + 2597)
+ 0x397, 0x313, 0x300, 0,
+#undef V857
+#define V857 (V + 2601)
+ 0x397, 0x314, 0x300, 0,
+#undef V858
+#define V858 (V + 2605)
+ 0x397, 0x313, 0x301, 0,
+#undef V859
+#define V859 (V + 2609)
+ 0x397, 0x314, 0x301, 0,
+#undef V860
+#define V860 (V + 2613)
+ 0x397, 0x313, 0x342, 0,
+#undef V861
+#define V861 (V + 2617)
+ 0x397, 0x314, 0x342, 0,
+#undef V862
+#define V862 (V + 2621)
+ 0x3b9, 0x313, 0,
+#undef V863
+#define V863 (V + 2624)
+ 0x3b9, 0x314, 0,
+#undef V864
+#define V864 (V + 2627)
+ 0x3b9, 0x313, 0x300, 0,
+#undef V865
+#define V865 (V + 2631)
+ 0x3b9, 0x314, 0x300, 0,
+#undef V866
+#define V866 (V + 2635)
+ 0x3b9, 0x313, 0x301, 0,
+#undef V867
+#define V867 (V + 2639)
+ 0x3b9, 0x314, 0x301, 0,
+#undef V868
+#define V868 (V + 2643)
+ 0x3b9, 0x313, 0x342, 0,
+#undef V869
+#define V869 (V + 2647)
+ 0x3b9, 0x314, 0x342, 0,
+#undef V870
+#define V870 (V + 2651)
+ 0x399, 0x313, 0,
+#undef V871
+#define V871 (V + 2654)
+ 0x399, 0x314, 0,
+#undef V872
+#define V872 (V + 2657)
+ 0x399, 0x313, 0x300, 0,
+#undef V873
+#define V873 (V + 2661)
+ 0x399, 0x314, 0x300, 0,
+#undef V874
+#define V874 (V + 2665)
+ 0x399, 0x313, 0x301, 0,
+#undef V875
+#define V875 (V + 2669)
+ 0x399, 0x314, 0x301, 0,
+#undef V876
+#define V876 (V + 2673)
+ 0x399, 0x313, 0x342, 0,
+#undef V877
+#define V877 (V + 2677)
+ 0x399, 0x314, 0x342, 0,
+#undef V878
+#define V878 (V + 2681)
+ 0x3bf, 0x313, 0,
+#undef V879
+#define V879 (V + 2684)
+ 0x3bf, 0x314, 0,
+#undef V880
+#define V880 (V + 2687)
+ 0x3bf, 0x313, 0x300, 0,
+#undef V881
+#define V881 (V + 2691)
+ 0x3bf, 0x314, 0x300, 0,
+#undef V882
+#define V882 (V + 2695)
+ 0x3bf, 0x313, 0x301, 0,
+#undef V883
+#define V883 (V + 2699)
+ 0x3bf, 0x314, 0x301, 0,
+#undef V884
+#define V884 (V + 2703)
+ 0x39f, 0x313, 0,
+#undef V885
+#define V885 (V + 2706)
+ 0x39f, 0x314, 0,
+#undef V886
+#define V886 (V + 2709)
+ 0x39f, 0x313, 0x300, 0,
+#undef V887
+#define V887 (V + 2713)
+ 0x39f, 0x314, 0x300, 0,
+#undef V888
+#define V888 (V + 2717)
+ 0x39f, 0x313, 0x301, 0,
+#undef V889
+#define V889 (V + 2721)
+ 0x39f, 0x314, 0x301, 0,
+#undef V890
+#define V890 (V + 2725)
+ 0x3c5, 0x313, 0,
+#undef V891
+#define V891 (V + 2728)
+ 0x3c5, 0x314, 0,
+#undef V892
+#define V892 (V + 2731)
+ 0x3c5, 0x313, 0x300, 0,
+#undef V893
+#define V893 (V + 2735)
+ 0x3c5, 0x314, 0x300, 0,
+#undef V894
+#define V894 (V + 2739)
+ 0x3c5, 0x313, 0x301, 0,
+#undef V895
+#define V895 (V + 2743)
+ 0x3c5, 0x314, 0x301, 0,
+#undef V896
+#define V896 (V + 2747)
+ 0x3c5, 0x313, 0x342, 0,
+#undef V897
+#define V897 (V + 2751)
+ 0x3c5, 0x314, 0x342, 0,
+#undef V898
+#define V898 (V + 2755)
+ 0x3a5, 0x314, 0,
+#undef V899
+#define V899 (V + 2758)
+ 0x3a5, 0x314, 0x300, 0,
+#undef V900
+#define V900 (V + 2762)
+ 0x3a5, 0x314, 0x301, 0,
+#undef V901
+#define V901 (V + 2766)
+ 0x3a5, 0x314, 0x342, 0,
+#undef V902
+#define V902 (V + 2770)
+ 0x3c9, 0x313, 0,
+#undef V903
+#define V903 (V + 2773)
+ 0x3c9, 0x314, 0,
+#undef V904
+#define V904 (V + 2776)
+ 0x3c9, 0x313, 0x300, 0,
+#undef V905
+#define V905 (V + 2780)
+ 0x3c9, 0x314, 0x300, 0,
+#undef V906
+#define V906 (V + 2784)
+ 0x3c9, 0x313, 0x301, 0,
+#undef V907
+#define V907 (V + 2788)
+ 0x3c9, 0x314, 0x301, 0,
+#undef V908
+#define V908 (V + 2792)
+ 0x3c9, 0x313, 0x342, 0,
+#undef V909
+#define V909 (V + 2796)
+ 0x3c9, 0x314, 0x342, 0,
+#undef V910
+#define V910 (V + 2800)
+ 0x3a9, 0x313, 0,
+#undef V911
+#define V911 (V + 2803)
+ 0x3a9, 0x314, 0,
+#undef V912
+#define V912 (V + 2806)
+ 0x3a9, 0x313, 0x300, 0,
+#undef V913
+#define V913 (V + 2810)
+ 0x3a9, 0x314, 0x300, 0,
+#undef V914
+#define V914 (V + 2814)
+ 0x3a9, 0x313, 0x301, 0,
+#undef V915
+#define V915 (V + 2818)
+ 0x3a9, 0x314, 0x301, 0,
+#undef V916
+#define V916 (V + 2822)
+ 0x3a9, 0x313, 0x342, 0,
+#undef V917
+#define V917 (V + 2826)
+ 0x3a9, 0x314, 0x342, 0,
+#undef V918
+#define V918 (V + 2830)
+ 0x3b1, 0x300, 0,
+#undef V919
+#define V919 (V + 2833)
+ 0x3b5, 0x300, 0,
+#undef V920
+#define V920 (V + 2836)
+ 0x3b7, 0x300, 0,
+#undef V921
+#define V921 (V + 2839)
+ 0x3b9, 0x300, 0,
+#undef V922
+#define V922 (V + 2842)
+ 0x3bf, 0x300, 0,
+#undef V923
+#define V923 (V + 2845)
+ 0x3c5, 0x300, 0,
+#undef V924
+#define V924 (V + 2848)
+ 0x3c9, 0x300, 0,
+#undef V925
+#define V925 (V + 2851)
+ 0x3b1, 0x313, 0x345, 0,
+#undef V926
+#define V926 (V + 2855)
+ 0x3b1, 0x314, 0x345, 0,
+#undef V927
+#define V927 (V + 2859)
+ 0x3b1, 0x313, 0x300, 0x345, 0,
+#undef V928
+#define V928 (V + 2864)
+ 0x3b1, 0x314, 0x300, 0x345, 0,
+#undef V929
+#define V929 (V + 2869)
+ 0x3b1, 0x313, 0x301, 0x345, 0,
+#undef V930
+#define V930 (V + 2874)
+ 0x3b1, 0x314, 0x301, 0x345, 0,
+#undef V931
+#define V931 (V + 2879)
+ 0x3b1, 0x313, 0x342, 0x345, 0,
+#undef V932
+#define V932 (V + 2884)
+ 0x3b1, 0x314, 0x342, 0x345, 0,
+#undef V933
+#define V933 (V + 2889)
+ 0x391, 0x313, 0x345, 0,
+#undef V934
+#define V934 (V + 2893)
+ 0x391, 0x314, 0x345, 0,
+#undef V935
+#define V935 (V + 2897)
+ 0x391, 0x313, 0x300, 0x345, 0,
+#undef V936
+#define V936 (V + 2902)
+ 0x391, 0x314, 0x300, 0x345, 0,
+#undef V937
+#define V937 (V + 2907)
+ 0x391, 0x313, 0x301, 0x345, 0,
+#undef V938
+#define V938 (V + 2912)
+ 0x391, 0x314, 0x301, 0x345, 0,
+#undef V939
+#define V939 (V + 2917)
+ 0x391, 0x313, 0x342, 0x345, 0,
+#undef V940
+#define V940 (V + 2922)
+ 0x391, 0x314, 0x342, 0x345, 0,
+#undef V941
+#define V941 (V + 2927)
+ 0x3b7, 0x313, 0x345, 0,
+#undef V942
+#define V942 (V + 2931)
+ 0x3b7, 0x314, 0x345, 0,
+#undef V943
+#define V943 (V + 2935)
+ 0x3b7, 0x313, 0x300, 0x345, 0,
+#undef V944
+#define V944 (V + 2940)
+ 0x3b7, 0x314, 0x300, 0x345, 0,
+#undef V945
+#define V945 (V + 2945)
+ 0x3b7, 0x313, 0x301, 0x345, 0,
+#undef V946
+#define V946 (V + 2950)
+ 0x3b7, 0x314, 0x301, 0x345, 0,
+#undef V947
+#define V947 (V + 2955)
+ 0x3b7, 0x313, 0x342, 0x345, 0,
+#undef V948
+#define V948 (V + 2960)
+ 0x3b7, 0x314, 0x342, 0x345, 0,
+#undef V949
+#define V949 (V + 2965)
+ 0x397, 0x313, 0x345, 0,
+#undef V950
+#define V950 (V + 2969)
+ 0x397, 0x314, 0x345, 0,
+#undef V951
+#define V951 (V + 2973)
+ 0x397, 0x313, 0x300, 0x345, 0,
+#undef V952
+#define V952 (V + 2978)
+ 0x397, 0x314, 0x300, 0x345, 0,
+#undef V953
+#define V953 (V + 2983)
+ 0x397, 0x313, 0x301, 0x345, 0,
+#undef V954
+#define V954 (V + 2988)
+ 0x397, 0x314, 0x301, 0x345, 0,
+#undef V955
+#define V955 (V + 2993)
+ 0x397, 0x313, 0x342, 0x345, 0,
+#undef V956
+#define V956 (V + 2998)
+ 0x397, 0x314, 0x342, 0x345, 0,
+#undef V957
+#define V957 (V + 3003)
+ 0x3c9, 0x313, 0x345, 0,
+#undef V958
+#define V958 (V + 3007)
+ 0x3c9, 0x314, 0x345, 0,
+#undef V959
+#define V959 (V + 3011)
+ 0x3c9, 0x313, 0x300, 0x345, 0,
+#undef V960
+#define V960 (V + 3016)
+ 0x3c9, 0x314, 0x300, 0x345, 0,
+#undef V961
+#define V961 (V + 3021)
+ 0x3c9, 0x313, 0x301, 0x345, 0,
+#undef V962
+#define V962 (V + 3026)
+ 0x3c9, 0x314, 0x301, 0x345, 0,
+#undef V963
+#define V963 (V + 3031)
+ 0x3c9, 0x313, 0x342, 0x345, 0,
+#undef V964
+#define V964 (V + 3036)
+ 0x3c9, 0x314, 0x342, 0x345, 0,
+#undef V965
+#define V965 (V + 3041)
+ 0x3a9, 0x313, 0x345, 0,
+#undef V966
+#define V966 (V + 3045)
+ 0x3a9, 0x314, 0x345, 0,
+#undef V967
+#define V967 (V + 3049)
+ 0x3a9, 0x313, 0x300, 0x345, 0,
+#undef V968
+#define V968 (V + 3054)
+ 0x3a9, 0x314, 0x300, 0x345, 0,
+#undef V969
+#define V969 (V + 3059)
+ 0x3a9, 0x313, 0x301, 0x345, 0,
+#undef V970
+#define V970 (V + 3064)
+ 0x3a9, 0x314, 0x301, 0x345, 0,
+#undef V971
+#define V971 (V + 3069)
+ 0x3a9, 0x313, 0x342, 0x345, 0,
+#undef V972
+#define V972 (V + 3074)
+ 0x3a9, 0x314, 0x342, 0x345, 0,
+#undef V973
+#define V973 (V + 3079)
+ 0x3b1, 0x306, 0,
+#undef V974
+#define V974 (V + 3082)
+ 0x3b1, 0x304, 0,
+#undef V975
+#define V975 (V + 3085)
+ 0x3b1, 0x300, 0x345, 0,
+#undef V976
+#define V976 (V + 3089)
+ 0x3b1, 0x345, 0,
+#undef V977
+#define V977 (V + 3092)
+ 0x3b1, 0x301, 0x345, 0,
+#undef V978
+#define V978 (V + 3096)
+ 0x3b1, 0x342, 0,
+#undef V979
+#define V979 (V + 3099)
+ 0x3b1, 0x342, 0x345, 0,
+#undef V980
+#define V980 (V + 3103)
+ 0x391, 0x306, 0,
+#undef V981
+#define V981 (V + 3106)
+ 0x391, 0x304, 0,
+#undef V982
+#define V982 (V + 3109)
+ 0x391, 0x300, 0,
+#undef V983
+#define V983 (V + 3112)
+ 0x391, 0x345, 0,
+#undef V984
+#define V984 (V + 3115)
+ 0x20, 0x313, 0,
+#undef V985
+#define V985 (V + 3118)
+ 0x3b9, 0,
+#undef V986
+#define V986 (V + 3120)
+ 0x20, 0x342, 0,
+#undef V987
+#define V987 (V + 3123)
+ 0x20, 0x308, 0x342, 0,
+#undef V988
+#define V988 (V + 3127)
+ 0x3b7, 0x300, 0x345, 0,
+#undef V989
+#define V989 (V + 3131)
+ 0x3b7, 0x345, 0,
+#undef V990
+#define V990 (V + 3134)
+ 0x3b7, 0x301, 0x345, 0,
+#undef V991
+#define V991 (V + 3138)
+ 0x3b7, 0x342, 0,
+#undef V992
+#define V992 (V + 3141)
+ 0x3b7, 0x342, 0x345, 0,
+#undef V993
+#define V993 (V + 3145)
+ 0x395, 0x300, 0,
+#undef V994
+#define V994 (V + 3148)
+ 0x397, 0x300, 0,
+#undef V995
+#define V995 (V + 3151)
+ 0x397, 0x345, 0,
+#undef V996
+#define V996 (V + 3154)
+ 0x20, 0x313, 0x300, 0,
+#undef V997
+#define V997 (V + 3158)
+ 0x20, 0x313, 0x301, 0,
+#undef V998
+#define V998 (V + 3162)
+ 0x20, 0x313, 0x342, 0,
+#undef V999
+#define V999 (V + 3166)
+ 0x3b9, 0x306, 0,
+#undef V1000
+#define V1000 (V + 3169)
+ 0x3b9, 0x304, 0,
+#undef V1001
+#define V1001 (V + 3172)
+ 0x3b9, 0x308, 0x300, 0,
+#undef V1002
+#define V1002 (V + 3176)
+ 0x3b9, 0x342, 0,
+#undef V1003
+#define V1003 (V + 3179)
+ 0x3b9, 0x308, 0x342, 0,
+#undef V1004
+#define V1004 (V + 3183)
+ 0x399, 0x306, 0,
+#undef V1005
+#define V1005 (V + 3186)
+ 0x399, 0x304, 0,
+#undef V1006
+#define V1006 (V + 3189)
+ 0x399, 0x300, 0,
+#undef V1007
+#define V1007 (V + 3192)
+ 0x20, 0x314, 0x300, 0,
+#undef V1008
+#define V1008 (V + 3196)
+ 0x20, 0x314, 0x301, 0,
+#undef V1009
+#define V1009 (V + 3200)
+ 0x20, 0x314, 0x342, 0,
+#undef V1010
+#define V1010 (V + 3204)
+ 0x3c5, 0x306, 0,
+#undef V1011
+#define V1011 (V + 3207)
+ 0x3c5, 0x304, 0,
+#undef V1012
+#define V1012 (V + 3210)
+ 0x3c5, 0x308, 0x300, 0,
+#undef V1013
+#define V1013 (V + 3214)
+ 0x3c1, 0x313, 0,
+#undef V1014
+#define V1014 (V + 3217)
+ 0x3c1, 0x314, 0,
+#undef V1015
+#define V1015 (V + 3220)
+ 0x3c5, 0x342, 0,
+#undef V1016
+#define V1016 (V + 3223)
+ 0x3c5, 0x308, 0x342, 0,
+#undef V1017
+#define V1017 (V + 3227)
+ 0x3a5, 0x306, 0,
+#undef V1018
+#define V1018 (V + 3230)
+ 0x3a5, 0x304, 0,
+#undef V1019
+#define V1019 (V + 3233)
+ 0x3a5, 0x300, 0,
+#undef V1020
+#define V1020 (V + 3236)
+ 0x3a1, 0x314, 0,
+#undef V1021
+#define V1021 (V + 3239)
+ 0x20, 0x308, 0x300, 0,
+#undef V1022
+#define V1022 (V + 3243)
+ 0x60, 0,
+#undef V1023
+#define V1023 (V + 3245)
+ 0x3c9, 0x300, 0x345, 0,
+#undef V1024
+#define V1024 (V + 3249)
+ 0x3c9, 0x345, 0,
+#undef V1025
+#define V1025 (V + 3252)
+ 0x3c9, 0x301, 0x345, 0,
+#undef V1026
+#define V1026 (V + 3256)
+ 0x3c9, 0x342, 0,
+#undef V1027
+#define V1027 (V + 3259)
+ 0x3c9, 0x342, 0x345, 0,
+#undef V1028
+#define V1028 (V + 3263)
+ 0x39f, 0x300, 0,
+#undef V1029
+#define V1029 (V + 3266)
+ 0x3a9, 0x300, 0,
+#undef V1030
+#define V1030 (V + 3269)
+ 0x3a9, 0x345, 0,
+#undef V1031
+#define V1031 (V + 3272)
+ 0x20, 0x314, 0,
+#undef V1032
+#define V1032 (V + 3275)
+ 0x2010, 0,
+#undef V1033
+#define V1033 (V + 3277)
+ 0x20, 0x333, 0,
+#undef V1034
+#define V1034 (V + 3280)
+ 0x2e, 0,
+#undef V1035
+#define V1035 (V + 3282)
+ 0x2e, 0x2e, 0,
+#undef V1036
+#define V1036 (V + 3285)
+ 0x2e, 0x2e, 0x2e, 0,
+#undef V1037
+#define V1037 (V + 3289)
+ 0x2032, 0x2032, 0,
+#undef V1038
+#define V1038 (V + 3292)
+ 0x2032, 0x2032, 0x2032, 0,
+#undef V1039
+#define V1039 (V + 3296)
+ 0x2035, 0x2035, 0,
+#undef V1040
+#define V1040 (V + 3299)
+ 0x2035, 0x2035, 0x2035, 0,
+#undef V1041
+#define V1041 (V + 3303)
+ 0x21, 0x21, 0,
+#undef V1042
+#define V1042 (V + 3306)
+ 0x20, 0x305, 0,
+#undef V1043
+#define V1043 (V + 3309)
+ 0x3f, 0x3f, 0,
+#undef V1044
+#define V1044 (V + 3312)
+ 0x3f, 0x21, 0,
+#undef V1045
+#define V1045 (V + 3315)
+ 0x21, 0x3f, 0,
+#undef V1046
+#define V1046 (V + 3318)
+ 0x2032, 0x2032, 0x2032, 0x2032, 0,
+#undef V1047
+#define V1047 (V + 3323)
+ 0x30, 0,
+#undef V1048
+#define V1048 (V + 3325)
+ 0x34, 0,
+#undef V1049
+#define V1049 (V + 3327)
+ 0x35, 0,
+#undef V1050
+#define V1050 (V + 3329)
+ 0x36, 0,
+#undef V1051
+#define V1051 (V + 3331)
+ 0x37, 0,
+#undef V1052
+#define V1052 (V + 3333)
+ 0x38, 0,
+#undef V1053
+#define V1053 (V + 3335)
+ 0x39, 0,
+#undef V1054
+#define V1054 (V + 3337)
+ 0x2b, 0,
+#undef V1055
+#define V1055 (V + 3339)
+ 0x2212, 0,
+#undef V1056
+#define V1056 (V + 3341)
+ 0x3d, 0,
+#undef V1057
+#define V1057 (V + 3343)
+ 0x28, 0,
+#undef V1058
+#define V1058 (V + 3345)
+ 0x29, 0,
+#undef V1059
+#define V1059 (V + 3347)
+ 0x6e, 0,
+#undef V1060
+#define V1060 (V + 3349)
+ 0x52, 0x73, 0,
+#undef V1061
+#define V1061 (V + 3352)
+ 0x61, 0x2f, 0x63, 0,
+#undef V1062
+#define V1062 (V + 3356)
+ 0x61, 0x2f, 0x73, 0,
+#undef V1063
+#define V1063 (V + 3360)
+ 0x43, 0,
+#undef V1064
+#define V1064 (V + 3362)
+ 0xb0, 0x43, 0,
+#undef V1065
+#define V1065 (V + 3365)
+ 0x63, 0x2f, 0x6f, 0,
+#undef V1066
+#define V1066 (V + 3369)
+ 0x63, 0x2f, 0x75, 0,
+#undef V1067
+#define V1067 (V + 3373)
+ 0x190, 0,
+#undef V1068
+#define V1068 (V + 3375)
+ 0xb0, 0x46, 0,
+#undef V1069
+#define V1069 (V + 3378)
+ 0x127, 0,
+#undef V1070
+#define V1070 (V + 3380)
+ 0x4e, 0x6f, 0,
+#undef V1071
+#define V1071 (V + 3383)
+ 0x51, 0,
+#undef V1072
+#define V1072 (V + 3385)
+ 0x53, 0x4d, 0,
+#undef V1073
+#define V1073 (V + 3388)
+ 0x54, 0x45, 0x4c, 0,
+#undef V1074
+#define V1074 (V + 3392)
+ 0x54, 0x4d, 0,
+#undef V1075
+#define V1075 (V + 3395)
+ 0x5a, 0,
+#undef V1076
+#define V1076 (V + 3397)
+ 0x3a9, 0,
+#undef V1077
+#define V1077 (V + 3399)
+ 0x46, 0,
+#undef V1078
+#define V1078 (V + 3401)
+ 0x5d0, 0,
+#undef V1079
+#define V1079 (V + 3403)
+ 0x5d1, 0,
+#undef V1080
+#define V1080 (V + 3405)
+ 0x5d2, 0,
+#undef V1081
+#define V1081 (V + 3407)
+ 0x5d3, 0,
+#undef V1082
+#define V1082 (V + 3409)
+ 0x46, 0x41, 0x58, 0,
+#undef V1083
+#define V1083 (V + 3413)
+ 0x393, 0,
+#undef V1084
+#define V1084 (V + 3415)
+ 0x3a0, 0,
+#undef V1085
+#define V1085 (V + 3417)
+ 0x2211, 0,
+#undef V1086
+#define V1086 (V + 3419)
+ 0x31, 0x2044, 0x37, 0,
+#undef V1087
+#define V1087 (V + 3423)
+ 0x31, 0x2044, 0x39, 0,
+#undef V1088
+#define V1088 (V + 3427)
+ 0x31, 0x2044, 0x31, 0x30, 0,
+#undef V1089
+#define V1089 (V + 3432)
+ 0x31, 0x2044, 0x33, 0,
+#undef V1090
+#define V1090 (V + 3436)
+ 0x32, 0x2044, 0x33, 0,
+#undef V1091
+#define V1091 (V + 3440)
+ 0x31, 0x2044, 0x35, 0,
+#undef V1092
+#define V1092 (V + 3444)
+ 0x32, 0x2044, 0x35, 0,
+#undef V1093
+#define V1093 (V + 3448)
+ 0x33, 0x2044, 0x35, 0,
+#undef V1094
+#define V1094 (V + 3452)
+ 0x34, 0x2044, 0x35, 0,
+#undef V1095
+#define V1095 (V + 3456)
+ 0x31, 0x2044, 0x36, 0,
+#undef V1096
+#define V1096 (V + 3460)
+ 0x35, 0x2044, 0x36, 0,
+#undef V1097
+#define V1097 (V + 3464)
+ 0x31, 0x2044, 0x38, 0,
+#undef V1098
+#define V1098 (V + 3468)
+ 0x33, 0x2044, 0x38, 0,
+#undef V1099
+#define V1099 (V + 3472)
+ 0x35, 0x2044, 0x38, 0,
+#undef V1100
+#define V1100 (V + 3476)
+ 0x37, 0x2044, 0x38, 0,
+#undef V1101
+#define V1101 (V + 3480)
+ 0x31, 0x2044, 0,
+#undef V1102
+#define V1102 (V + 3483)
+ 0x49, 0x49, 0,
+#undef V1103
+#define V1103 (V + 3486)
+ 0x49, 0x49, 0x49, 0,
+#undef V1104
+#define V1104 (V + 3490)
+ 0x49, 0x56, 0,
+#undef V1105
+#define V1105 (V + 3493)
+ 0x56, 0,
+#undef V1106
+#define V1106 (V + 3495)
+ 0x56, 0x49, 0,
+#undef V1107
+#define V1107 (V + 3498)
+ 0x56, 0x49, 0x49, 0,
+#undef V1108
+#define V1108 (V + 3502)
+ 0x56, 0x49, 0x49, 0x49, 0,
+#undef V1109
+#define V1109 (V + 3507)
+ 0x49, 0x58, 0,
+#undef V1110
+#define V1110 (V + 3510)
+ 0x58, 0,
+#undef V1111
+#define V1111 (V + 3512)
+ 0x58, 0x49, 0,
+#undef V1112
+#define V1112 (V + 3515)
+ 0x58, 0x49, 0x49, 0,
+#undef V1113
+#define V1113 (V + 3519)
+ 0x69, 0x69, 0,
+#undef V1114
+#define V1114 (V + 3522)
+ 0x69, 0x69, 0x69, 0,
+#undef V1115
+#define V1115 (V + 3526)
+ 0x69, 0x76, 0,
+#undef V1116
+#define V1116 (V + 3529)
+ 0x76, 0x69, 0,
+#undef V1117
+#define V1117 (V + 3532)
+ 0x76, 0x69, 0x69, 0,
+#undef V1118
+#define V1118 (V + 3536)
+ 0x76, 0x69, 0x69, 0x69, 0,
+#undef V1119
+#define V1119 (V + 3541)
+ 0x69, 0x78, 0,
+#undef V1120
+#define V1120 (V + 3544)
+ 0x78, 0x69, 0,
+#undef V1121
+#define V1121 (V + 3547)
+ 0x78, 0x69, 0x69, 0,
+#undef V1122
+#define V1122 (V + 3551)
+ 0x30, 0x2044, 0x33, 0,
+#undef V1123
+#define V1123 (V + 3555)
+ 0x2190, 0x338, 0,
+#undef V1124
+#define V1124 (V + 3558)
+ 0x2192, 0x338, 0,
+#undef V1125
+#define V1125 (V + 3561)
+ 0x2194, 0x338, 0,
+#undef V1126
+#define V1126 (V + 3564)
+ 0x21d0, 0x338, 0,
+#undef V1127
+#define V1127 (V + 3567)
+ 0x21d4, 0x338, 0,
+#undef V1128
+#define V1128 (V + 3570)
+ 0x21d2, 0x338, 0,
+#undef V1129
+#define V1129 (V + 3573)
+ 0x2203, 0x338, 0,
+#undef V1130
+#define V1130 (V + 3576)
+ 0x2208, 0x338, 0,
+#undef V1131
+#define V1131 (V + 3579)
+ 0x220b, 0x338, 0,
+#undef V1132
+#define V1132 (V + 3582)
+ 0x2223, 0x338, 0,
+#undef V1133
+#define V1133 (V + 3585)
+ 0x2225, 0x338, 0,
+#undef V1134
+#define V1134 (V + 3588)
+ 0x222b, 0x222b, 0,
+#undef V1135
+#define V1135 (V + 3591)
+ 0x222b, 0x222b, 0x222b, 0,
+#undef V1136
+#define V1136 (V + 3595)
+ 0x222e, 0x222e, 0,
+#undef V1137
+#define V1137 (V + 3598)
+ 0x222e, 0x222e, 0x222e, 0,
+#undef V1138
+#define V1138 (V + 3602)
+ 0x223c, 0x338, 0,
+#undef V1139
+#define V1139 (V + 3605)
+ 0x2243, 0x338, 0,
+#undef V1140
+#define V1140 (V + 3608)
+ 0x2245, 0x338, 0,
+#undef V1141
+#define V1141 (V + 3611)
+ 0x2248, 0x338, 0,
+#undef V1142
+#define V1142 (V + 3614)
+ 0x3d, 0x338, 0,
+#undef V1143
+#define V1143 (V + 3617)
+ 0x2261, 0x338, 0,
+#undef V1144
+#define V1144 (V + 3620)
+ 0x224d, 0x338, 0,
+#undef V1145
+#define V1145 (V + 3623)
+ 0x3c, 0x338, 0,
+#undef V1146
+#define V1146 (V + 3626)
+ 0x3e, 0x338, 0,
+#undef V1147
+#define V1147 (V + 3629)
+ 0x2264, 0x338, 0,
+#undef V1148
+#define V1148 (V + 3632)
+ 0x2265, 0x338, 0,
+#undef V1149
+#define V1149 (V + 3635)
+ 0x2272, 0x338, 0,
+#undef V1150
+#define V1150 (V + 3638)
+ 0x2273, 0x338, 0,
+#undef V1151
+#define V1151 (V + 3641)
+ 0x2276, 0x338, 0,
+#undef V1152
+#define V1152 (V + 3644)
+ 0x2277, 0x338, 0,
+#undef V1153
+#define V1153 (V + 3647)
+ 0x227a, 0x338, 0,
+#undef V1154
+#define V1154 (V + 3650)
+ 0x227b, 0x338, 0,
+#undef V1155
+#define V1155 (V + 3653)
+ 0x2282, 0x338, 0,
+#undef V1156
+#define V1156 (V + 3656)
+ 0x2283, 0x338, 0,
+#undef V1157
+#define V1157 (V + 3659)
+ 0x2286, 0x338, 0,
+#undef V1158
+#define V1158 (V + 3662)
+ 0x2287, 0x338, 0,
+#undef V1159
+#define V1159 (V + 3665)
+ 0x22a2, 0x338, 0,
+#undef V1160
+#define V1160 (V + 3668)
+ 0x22a8, 0x338, 0,
+#undef V1161
+#define V1161 (V + 3671)
+ 0x22a9, 0x338, 0,
+#undef V1162
+#define V1162 (V + 3674)
+ 0x22ab, 0x338, 0,
+#undef V1163
+#define V1163 (V + 3677)
+ 0x227c, 0x338, 0,
+#undef V1164
+#define V1164 (V + 3680)
+ 0x227d, 0x338, 0,
+#undef V1165
+#define V1165 (V + 3683)
+ 0x2291, 0x338, 0,
+#undef V1166
+#define V1166 (V + 3686)
+ 0x2292, 0x338, 0,
+#undef V1167
+#define V1167 (V + 3689)
+ 0x22b2, 0x338, 0,
+#undef V1168
+#define V1168 (V + 3692)
+ 0x22b3, 0x338, 0,
+#undef V1169
+#define V1169 (V + 3695)
+ 0x22b4, 0x338, 0,
+#undef V1170
+#define V1170 (V + 3698)
+ 0x22b5, 0x338, 0,
+#undef V1171
+#define V1171 (V + 3701)
+ 0x3008, 0,
+#undef V1172
+#define V1172 (V + 3703)
+ 0x3009, 0,
+#undef V1173
+#define V1173 (V + 3705)
+ 0x31, 0x30, 0,
+#undef V1174
+#define V1174 (V + 3708)
+ 0x31, 0x31, 0,
+#undef V1175
+#define V1175 (V + 3711)
+ 0x31, 0x32, 0,
+#undef V1176
+#define V1176 (V + 3714)
+ 0x31, 0x33, 0,
+#undef V1177
+#define V1177 (V + 3717)
+ 0x31, 0x34, 0,
+#undef V1178
+#define V1178 (V + 3720)
+ 0x31, 0x35, 0,
+#undef V1179
+#define V1179 (V + 3723)
+ 0x31, 0x36, 0,
+#undef V1180
+#define V1180 (V + 3726)
+ 0x31, 0x37, 0,
+#undef V1181
+#define V1181 (V + 3729)
+ 0x31, 0x38, 0,
+#undef V1182
+#define V1182 (V + 3732)
+ 0x31, 0x39, 0,
+#undef V1183
+#define V1183 (V + 3735)
+ 0x32, 0x30, 0,
+#undef V1184
+#define V1184 (V + 3738)
+ 0x28, 0x31, 0x29, 0,
+#undef V1185
+#define V1185 (V + 3742)
+ 0x28, 0x32, 0x29, 0,
+#undef V1186
+#define V1186 (V + 3746)
+ 0x28, 0x33, 0x29, 0,
+#undef V1187
+#define V1187 (V + 3750)
+ 0x28, 0x34, 0x29, 0,
+#undef V1188
+#define V1188 (V + 3754)
+ 0x28, 0x35, 0x29, 0,
+#undef V1189
+#define V1189 (V + 3758)
+ 0x28, 0x36, 0x29, 0,
+#undef V1190
+#define V1190 (V + 3762)
+ 0x28, 0x37, 0x29, 0,
+#undef V1191
+#define V1191 (V + 3766)
+ 0x28, 0x38, 0x29, 0,
+#undef V1192
+#define V1192 (V + 3770)
+ 0x28, 0x39, 0x29, 0,
+#undef V1193
+#define V1193 (V + 3774)
+ 0x28, 0x31, 0x30, 0x29, 0,
+#undef V1194
+#define V1194 (V + 3779)
+ 0x28, 0x31, 0x31, 0x29, 0,
+#undef V1195
+#define V1195 (V + 3784)
+ 0x28, 0x31, 0x32, 0x29, 0,
+#undef V1196
+#define V1196 (V + 3789)
+ 0x28, 0x31, 0x33, 0x29, 0,
+#undef V1197
+#define V1197 (V + 3794)
+ 0x28, 0x31, 0x34, 0x29, 0,
+#undef V1198
+#define V1198 (V + 3799)
+ 0x28, 0x31, 0x35, 0x29, 0,
+#undef V1199
+#define V1199 (V + 3804)
+ 0x28, 0x31, 0x36, 0x29, 0,
+#undef V1200
+#define V1200 (V + 3809)
+ 0x28, 0x31, 0x37, 0x29, 0,
+#undef V1201
+#define V1201 (V + 3814)
+ 0x28, 0x31, 0x38, 0x29, 0,
+#undef V1202
+#define V1202 (V + 3819)
+ 0x28, 0x31, 0x39, 0x29, 0,
+#undef V1203
+#define V1203 (V + 3824)
+ 0x28, 0x32, 0x30, 0x29, 0,
+#undef V1204
+#define V1204 (V + 3829)
+ 0x31, 0x2e, 0,
+#undef V1205
+#define V1205 (V + 3832)
+ 0x32, 0x2e, 0,
+#undef V1206
+#define V1206 (V + 3835)
+ 0x33, 0x2e, 0,
+#undef V1207
+#define V1207 (V + 3838)
+ 0x34, 0x2e, 0,
+#undef V1208
+#define V1208 (V + 3841)
+ 0x35, 0x2e, 0,
+#undef V1209
+#define V1209 (V + 3844)
+ 0x36, 0x2e, 0,
+#undef V1210
+#define V1210 (V + 3847)
+ 0x37, 0x2e, 0,
+#undef V1211
+#define V1211 (V + 3850)
+ 0x38, 0x2e, 0,
+#undef V1212
+#define V1212 (V + 3853)
+ 0x39, 0x2e, 0,
+#undef V1213
+#define V1213 (V + 3856)
+ 0x31, 0x30, 0x2e, 0,
+#undef V1214
+#define V1214 (V + 3860)
+ 0x31, 0x31, 0x2e, 0,
+#undef V1215
+#define V1215 (V + 3864)
+ 0x31, 0x32, 0x2e, 0,
+#undef V1216
+#define V1216 (V + 3868)
+ 0x31, 0x33, 0x2e, 0,
+#undef V1217
+#define V1217 (V + 3872)
+ 0x31, 0x34, 0x2e, 0,
+#undef V1218
+#define V1218 (V + 3876)
+ 0x31, 0x35, 0x2e, 0,
+#undef V1219
+#define V1219 (V + 3880)
+ 0x31, 0x36, 0x2e, 0,
+#undef V1220
+#define V1220 (V + 3884)
+ 0x31, 0x37, 0x2e, 0,
+#undef V1221
+#define V1221 (V + 3888)
+ 0x31, 0x38, 0x2e, 0,
+#undef V1222
+#define V1222 (V + 3892)
+ 0x31, 0x39, 0x2e, 0,
+#undef V1223
+#define V1223 (V + 3896)
+ 0x32, 0x30, 0x2e, 0,
+#undef V1224
+#define V1224 (V + 3900)
+ 0x28, 0x61, 0x29, 0,
+#undef V1225
+#define V1225 (V + 3904)
+ 0x28, 0x62, 0x29, 0,
+#undef V1226
+#define V1226 (V + 3908)
+ 0x28, 0x63, 0x29, 0,
+#undef V1227
+#define V1227 (V + 3912)
+ 0x28, 0x64, 0x29, 0,
+#undef V1228
+#define V1228 (V + 3916)
+ 0x28, 0x65, 0x29, 0,
+#undef V1229
+#define V1229 (V + 3920)
+ 0x28, 0x66, 0x29, 0,
+#undef V1230
+#define V1230 (V + 3924)
+ 0x28, 0x67, 0x29, 0,
+#undef V1231
+#define V1231 (V + 3928)
+ 0x28, 0x68, 0x29, 0,
+#undef V1232
+#define V1232 (V + 3932)
+ 0x28, 0x69, 0x29, 0,
+#undef V1233
+#define V1233 (V + 3936)
+ 0x28, 0x6a, 0x29, 0,
+#undef V1234
+#define V1234 (V + 3940)
+ 0x28, 0x6b, 0x29, 0,
+#undef V1235
+#define V1235 (V + 3944)
+ 0x28, 0x6c, 0x29, 0,
+#undef V1236
+#define V1236 (V + 3948)
+ 0x28, 0x6d, 0x29, 0,
+#undef V1237
+#define V1237 (V + 3952)
+ 0x28, 0x6e, 0x29, 0,
+#undef V1238
+#define V1238 (V + 3956)
+ 0x28, 0x6f, 0x29, 0,
+#undef V1239
+#define V1239 (V + 3960)
+ 0x28, 0x70, 0x29, 0,
+#undef V1240
+#define V1240 (V + 3964)
+ 0x28, 0x71, 0x29, 0,
+#undef V1241
+#define V1241 (V + 3968)
+ 0x28, 0x72, 0x29, 0,
+#undef V1242
+#define V1242 (V + 3972)
+ 0x28, 0x73, 0x29, 0,
+#undef V1243
+#define V1243 (V + 3976)
+ 0x28, 0x74, 0x29, 0,
+#undef V1244
+#define V1244 (V + 3980)
+ 0x28, 0x75, 0x29, 0,
+#undef V1245
+#define V1245 (V + 3984)
+ 0x28, 0x76, 0x29, 0,
+#undef V1246
+#define V1246 (V + 3988)
+ 0x28, 0x77, 0x29, 0,
+#undef V1247
+#define V1247 (V + 3992)
+ 0x28, 0x78, 0x29, 0,
+#undef V1248
+#define V1248 (V + 3996)
+ 0x28, 0x79, 0x29, 0,
+#undef V1249
+#define V1249 (V + 4000)
+ 0x28, 0x7a, 0x29, 0,
+#undef V1250
+#define V1250 (V + 4004)
+ 0x53, 0,
+#undef V1251
+#define V1251 (V + 4006)
+ 0x59, 0,
+#undef V1252
+#define V1252 (V + 4008)
+ 0x71, 0,
+#undef V1253
+#define V1253 (V + 4010)
+ 0x222b, 0x222b, 0x222b, 0x222b, 0,
+#undef V1254
+#define V1254 (V + 4015)
+ 0x3a, 0x3a, 0x3d, 0,
+#undef V1255
+#define V1255 (V + 4019)
+ 0x3d, 0x3d, 0,
+#undef V1256
+#define V1256 (V + 4022)
+ 0x3d, 0x3d, 0x3d, 0,
+#undef V1257
+#define V1257 (V + 4026)
+ 0x2add, 0x338, 0,
+#undef V1258
+#define V1258 (V + 4029)
+ 0x2d61, 0,
+#undef V1259
+#define V1259 (V + 4031)
+ 0x6bcd, 0,
+#undef V1260
+#define V1260 (V + 4033)
+ 0x9f9f, 0,
+#undef V1261
+#define V1261 (V + 4035)
+ 0x4e00, 0,
+#undef V1262
+#define V1262 (V + 4037)
+ 0x4e28, 0,
+#undef V1263
+#define V1263 (V + 4039)
+ 0x4e36, 0,
+#undef V1264
+#define V1264 (V + 4041)
+ 0x4e3f, 0,
+#undef V1265
+#define V1265 (V + 4043)
+ 0x4e59, 0,
+#undef V1266
+#define V1266 (V + 4045)
+ 0x4e85, 0,
+#undef V1267
+#define V1267 (V + 4047)
+ 0x4e8c, 0,
+#undef V1268
+#define V1268 (V + 4049)
+ 0x4ea0, 0,
+#undef V1269
+#define V1269 (V + 4051)
+ 0x4eba, 0,
+#undef V1270
+#define V1270 (V + 4053)
+ 0x513f, 0,
+#undef V1271
+#define V1271 (V + 4055)
+ 0x5165, 0,
+#undef V1272
+#define V1272 (V + 4057)
+ 0x516b, 0,
+#undef V1273
+#define V1273 (V + 4059)
+ 0x5182, 0,
+#undef V1274
+#define V1274 (V + 4061)
+ 0x5196, 0,
+#undef V1275
+#define V1275 (V + 4063)
+ 0x51ab, 0,
+#undef V1276
+#define V1276 (V + 4065)
+ 0x51e0, 0,
+#undef V1277
+#define V1277 (V + 4067)
+ 0x51f5, 0,
+#undef V1278
+#define V1278 (V + 4069)
+ 0x5200, 0,
+#undef V1279
+#define V1279 (V + 4071)
+ 0x529b, 0,
+#undef V1280
+#define V1280 (V + 4073)
+ 0x52f9, 0,
+#undef V1281
+#define V1281 (V + 4075)
+ 0x5315, 0,
+#undef V1282
+#define V1282 (V + 4077)
+ 0x531a, 0,
+#undef V1283
+#define V1283 (V + 4079)
+ 0x5338, 0,
+#undef V1284
+#define V1284 (V + 4081)
+ 0x5341, 0,
+#undef V1285
+#define V1285 (V + 4083)
+ 0x535c, 0,
+#undef V1286
+#define V1286 (V + 4085)
+ 0x5369, 0,
+#undef V1287
+#define V1287 (V + 4087)
+ 0x5382, 0,
+#undef V1288
+#define V1288 (V + 4089)
+ 0x53b6, 0,
+#undef V1289
+#define V1289 (V + 4091)
+ 0x53c8, 0,
+#undef V1290
+#define V1290 (V + 4093)
+ 0x53e3, 0,
+#undef V1291
+#define V1291 (V + 4095)
+ 0x56d7, 0,
+#undef V1292
+#define V1292 (V + 4097)
+ 0x571f, 0,
+#undef V1293
+#define V1293 (V + 4099)
+ 0x58eb, 0,
+#undef V1294
+#define V1294 (V + 4101)
+ 0x5902, 0,
+#undef V1295
+#define V1295 (V + 4103)
+ 0x590a, 0,
+#undef V1296
+#define V1296 (V + 4105)
+ 0x5915, 0,
+#undef V1297
+#define V1297 (V + 4107)
+ 0x5927, 0,
+#undef V1298
+#define V1298 (V + 4109)
+ 0x5973, 0,
+#undef V1299
+#define V1299 (V + 4111)
+ 0x5b50, 0,
+#undef V1300
+#define V1300 (V + 4113)
+ 0x5b80, 0,
+#undef V1301
+#define V1301 (V + 4115)
+ 0x5bf8, 0,
+#undef V1302
+#define V1302 (V + 4117)
+ 0x5c0f, 0,
+#undef V1303
+#define V1303 (V + 4119)
+ 0x5c22, 0,
+#undef V1304
+#define V1304 (V + 4121)
+ 0x5c38, 0,
+#undef V1305
+#define V1305 (V + 4123)
+ 0x5c6e, 0,
+#undef V1306
+#define V1306 (V + 4125)
+ 0x5c71, 0,
+#undef V1307
+#define V1307 (V + 4127)
+ 0x5ddb, 0,
+#undef V1308
+#define V1308 (V + 4129)
+ 0x5de5, 0,
+#undef V1309
+#define V1309 (V + 4131)
+ 0x5df1, 0,
+#undef V1310
+#define V1310 (V + 4133)
+ 0x5dfe, 0,
+#undef V1311
+#define V1311 (V + 4135)
+ 0x5e72, 0,
+#undef V1312
+#define V1312 (V + 4137)
+ 0x5e7a, 0,
+#undef V1313
+#define V1313 (V + 4139)
+ 0x5e7f, 0,
+#undef V1314
+#define V1314 (V + 4141)
+ 0x5ef4, 0,
+#undef V1315
+#define V1315 (V + 4143)
+ 0x5efe, 0,
+#undef V1316
+#define V1316 (V + 4145)
+ 0x5f0b, 0,
+#undef V1317
+#define V1317 (V + 4147)
+ 0x5f13, 0,
+#undef V1318
+#define V1318 (V + 4149)
+ 0x5f50, 0,
+#undef V1319
+#define V1319 (V + 4151)
+ 0x5f61, 0,
+#undef V1320
+#define V1320 (V + 4153)
+ 0x5f73, 0,
+#undef V1321
+#define V1321 (V + 4155)
+ 0x5fc3, 0,
+#undef V1322
+#define V1322 (V + 4157)
+ 0x6208, 0,
+#undef V1323
+#define V1323 (V + 4159)
+ 0x6236, 0,
+#undef V1324
+#define V1324 (V + 4161)
+ 0x624b, 0,
+#undef V1325
+#define V1325 (V + 4163)
+ 0x652f, 0,
+#undef V1326
+#define V1326 (V + 4165)
+ 0x6534, 0,
+#undef V1327
+#define V1327 (V + 4167)
+ 0x6587, 0,
+#undef V1328
+#define V1328 (V + 4169)
+ 0x6597, 0,
+#undef V1329
+#define V1329 (V + 4171)
+ 0x65a4, 0,
+#undef V1330
+#define V1330 (V + 4173)
+ 0x65b9, 0,
+#undef V1331
+#define V1331 (V + 4175)
+ 0x65e0, 0,
+#undef V1332
+#define V1332 (V + 4177)
+ 0x65e5, 0,
+#undef V1333
+#define V1333 (V + 4179)
+ 0x66f0, 0,
+#undef V1334
+#define V1334 (V + 4181)
+ 0x6708, 0,
+#undef V1335
+#define V1335 (V + 4183)
+ 0x6728, 0,
+#undef V1336
+#define V1336 (V + 4185)
+ 0x6b20, 0,
+#undef V1337
+#define V1337 (V + 4187)
+ 0x6b62, 0,
+#undef V1338
+#define V1338 (V + 4189)
+ 0x6b79, 0,
+#undef V1339
+#define V1339 (V + 4191)
+ 0x6bb3, 0,
+#undef V1340
+#define V1340 (V + 4193)
+ 0x6bcb, 0,
+#undef V1341
+#define V1341 (V + 4195)
+ 0x6bd4, 0,
+#undef V1342
+#define V1342 (V + 4197)
+ 0x6bdb, 0,
+#undef V1343
+#define V1343 (V + 4199)
+ 0x6c0f, 0,
+#undef V1344
+#define V1344 (V + 4201)
+ 0x6c14, 0,
+#undef V1345
+#define V1345 (V + 4203)
+ 0x6c34, 0,
+#undef V1346
+#define V1346 (V + 4205)
+ 0x706b, 0,
+#undef V1347
+#define V1347 (V + 4207)
+ 0x722a, 0,
+#undef V1348
+#define V1348 (V + 4209)
+ 0x7236, 0,
+#undef V1349
+#define V1349 (V + 4211)
+ 0x723b, 0,
+#undef V1350
+#define V1350 (V + 4213)
+ 0x723f, 0,
+#undef V1351
+#define V1351 (V + 4215)
+ 0x7247, 0,
+#undef V1352
+#define V1352 (V + 4217)
+ 0x7259, 0,
+#undef V1353
+#define V1353 (V + 4219)
+ 0x725b, 0,
+#undef V1354
+#define V1354 (V + 4221)
+ 0x72ac, 0,
+#undef V1355
+#define V1355 (V + 4223)
+ 0x7384, 0,
+#undef V1356
+#define V1356 (V + 4225)
+ 0x7389, 0,
+#undef V1357
+#define V1357 (V + 4227)
+ 0x74dc, 0,
+#undef V1358
+#define V1358 (V + 4229)
+ 0x74e6, 0,
+#undef V1359
+#define V1359 (V + 4231)
+ 0x7518, 0,
+#undef V1360
+#define V1360 (V + 4233)
+ 0x751f, 0,
+#undef V1361
+#define V1361 (V + 4235)
+ 0x7528, 0,
+#undef V1362
+#define V1362 (V + 4237)
+ 0x7530, 0,
+#undef V1363
+#define V1363 (V + 4239)
+ 0x758b, 0,
+#undef V1364
+#define V1364 (V + 4241)
+ 0x7592, 0,
+#undef V1365
+#define V1365 (V + 4243)
+ 0x7676, 0,
+#undef V1366
+#define V1366 (V + 4245)
+ 0x767d, 0,
+#undef V1367
+#define V1367 (V + 4247)
+ 0x76ae, 0,
+#undef V1368
+#define V1368 (V + 4249)
+ 0x76bf, 0,
+#undef V1369
+#define V1369 (V + 4251)
+ 0x76ee, 0,
+#undef V1370
+#define V1370 (V + 4253)
+ 0x77db, 0,
+#undef V1371
+#define V1371 (V + 4255)
+ 0x77e2, 0,
+#undef V1372
+#define V1372 (V + 4257)
+ 0x77f3, 0,
+#undef V1373
+#define V1373 (V + 4259)
+ 0x793a, 0,
+#undef V1374
+#define V1374 (V + 4261)
+ 0x79b8, 0,
+#undef V1375
+#define V1375 (V + 4263)
+ 0x79be, 0,
+#undef V1376
+#define V1376 (V + 4265)
+ 0x7a74, 0,
+#undef V1377
+#define V1377 (V + 4267)
+ 0x7acb, 0,
+#undef V1378
+#define V1378 (V + 4269)
+ 0x7af9, 0,
+#undef V1379
+#define V1379 (V + 4271)
+ 0x7c73, 0,
+#undef V1380
+#define V1380 (V + 4273)
+ 0x7cf8, 0,
+#undef V1381
+#define V1381 (V + 4275)
+ 0x7f36, 0,
+#undef V1382
+#define V1382 (V + 4277)
+ 0x7f51, 0,
+#undef V1383
+#define V1383 (V + 4279)
+ 0x7f8a, 0,
+#undef V1384
+#define V1384 (V + 4281)
+ 0x7fbd, 0,
+#undef V1385
+#define V1385 (V + 4283)
+ 0x8001, 0,
+#undef V1386
+#define V1386 (V + 4285)
+ 0x800c, 0,
+#undef V1387
+#define V1387 (V + 4287)
+ 0x8012, 0,
+#undef V1388
+#define V1388 (V + 4289)
+ 0x8033, 0,
+#undef V1389
+#define V1389 (V + 4291)
+ 0x807f, 0,
+#undef V1390
+#define V1390 (V + 4293)
+ 0x8089, 0,
+#undef V1391
+#define V1391 (V + 4295)
+ 0x81e3, 0,
+#undef V1392
+#define V1392 (V + 4297)
+ 0x81ea, 0,
+#undef V1393
+#define V1393 (V + 4299)
+ 0x81f3, 0,
+#undef V1394
+#define V1394 (V + 4301)
+ 0x81fc, 0,
+#undef V1395
+#define V1395 (V + 4303)
+ 0x820c, 0,
+#undef V1396
+#define V1396 (V + 4305)
+ 0x821b, 0,
+#undef V1397
+#define V1397 (V + 4307)
+ 0x821f, 0,
+#undef V1398
+#define V1398 (V + 4309)
+ 0x826e, 0,
+#undef V1399
+#define V1399 (V + 4311)
+ 0x8272, 0,
+#undef V1400
+#define V1400 (V + 4313)
+ 0x8278, 0,
+#undef V1401
+#define V1401 (V + 4315)
+ 0x864d, 0,
+#undef V1402
+#define V1402 (V + 4317)
+ 0x866b, 0,
+#undef V1403
+#define V1403 (V + 4319)
+ 0x8840, 0,
+#undef V1404
+#define V1404 (V + 4321)
+ 0x884c, 0,
+#undef V1405
+#define V1405 (V + 4323)
+ 0x8863, 0,
+#undef V1406
+#define V1406 (V + 4325)
+ 0x897e, 0,
+#undef V1407
+#define V1407 (V + 4327)
+ 0x898b, 0,
+#undef V1408
+#define V1408 (V + 4329)
+ 0x89d2, 0,
+#undef V1409
+#define V1409 (V + 4331)
+ 0x8a00, 0,
+#undef V1410
+#define V1410 (V + 4333)
+ 0x8c37, 0,
+#undef V1411
+#define V1411 (V + 4335)
+ 0x8c46, 0,
+#undef V1412
+#define V1412 (V + 4337)
+ 0x8c55, 0,
+#undef V1413
+#define V1413 (V + 4339)
+ 0x8c78, 0,
+#undef V1414
+#define V1414 (V + 4341)
+ 0x8c9d, 0,
+#undef V1415
+#define V1415 (V + 4343)
+ 0x8d64, 0,
+#undef V1416
+#define V1416 (V + 4345)
+ 0x8d70, 0,
+#undef V1417
+#define V1417 (V + 4347)
+ 0x8db3, 0,
+#undef V1418
+#define V1418 (V + 4349)
+ 0x8eab, 0,
+#undef V1419
+#define V1419 (V + 4351)
+ 0x8eca, 0,
+#undef V1420
+#define V1420 (V + 4353)
+ 0x8f9b, 0,
+#undef V1421
+#define V1421 (V + 4355)
+ 0x8fb0, 0,
+#undef V1422
+#define V1422 (V + 4357)
+ 0x8fb5, 0,
+#undef V1423
+#define V1423 (V + 4359)
+ 0x9091, 0,
+#undef V1424
+#define V1424 (V + 4361)
+ 0x9149, 0,
+#undef V1425
+#define V1425 (V + 4363)
+ 0x91c6, 0,
+#undef V1426
+#define V1426 (V + 4365)
+ 0x91cc, 0,
+#undef V1427
+#define V1427 (V + 4367)
+ 0x91d1, 0,
+#undef V1428
+#define V1428 (V + 4369)
+ 0x9577, 0,
+#undef V1429
+#define V1429 (V + 4371)
+ 0x9580, 0,
+#undef V1430
+#define V1430 (V + 4373)
+ 0x961c, 0,
+#undef V1431
+#define V1431 (V + 4375)
+ 0x96b6, 0,
+#undef V1432
+#define V1432 (V + 4377)
+ 0x96b9, 0,
+#undef V1433
+#define V1433 (V + 4379)
+ 0x96e8, 0,
+#undef V1434
+#define V1434 (V + 4381)
+ 0x9751, 0,
+#undef V1435
+#define V1435 (V + 4383)
+ 0x975e, 0,
+#undef V1436
+#define V1436 (V + 4385)
+ 0x9762, 0,
+#undef V1437
+#define V1437 (V + 4387)
+ 0x9769, 0,
+#undef V1438
+#define V1438 (V + 4389)
+ 0x97cb, 0,
+#undef V1439
+#define V1439 (V + 4391)
+ 0x97ed, 0,
+#undef V1440
+#define V1440 (V + 4393)
+ 0x97f3, 0,
+#undef V1441
+#define V1441 (V + 4395)
+ 0x9801, 0,
+#undef V1442
+#define V1442 (V + 4397)
+ 0x98a8, 0,
+#undef V1443
+#define V1443 (V + 4399)
+ 0x98db, 0,
+#undef V1444
+#define V1444 (V + 4401)
+ 0x98df, 0,
+#undef V1445
+#define V1445 (V + 4403)
+ 0x9996, 0,
+#undef V1446
+#define V1446 (V + 4405)
+ 0x9999, 0,
+#undef V1447
+#define V1447 (V + 4407)
+ 0x99ac, 0,
+#undef V1448
+#define V1448 (V + 4409)
+ 0x9aa8, 0,
+#undef V1449
+#define V1449 (V + 4411)
+ 0x9ad8, 0,
+#undef V1450
+#define V1450 (V + 4413)
+ 0x9adf, 0,
+#undef V1451
+#define V1451 (V + 4415)
+ 0x9b25, 0,
+#undef V1452
+#define V1452 (V + 4417)
+ 0x9b2f, 0,
+#undef V1453
+#define V1453 (V + 4419)
+ 0x9b32, 0,
+#undef V1454
+#define V1454 (V + 4421)
+ 0x9b3c, 0,
+#undef V1455
+#define V1455 (V + 4423)
+ 0x9b5a, 0,
+#undef V1456
+#define V1456 (V + 4425)
+ 0x9ce5, 0,
+#undef V1457
+#define V1457 (V + 4427)
+ 0x9e75, 0,
+#undef V1458
+#define V1458 (V + 4429)
+ 0x9e7f, 0,
+#undef V1459
+#define V1459 (V + 4431)
+ 0x9ea5, 0,
+#undef V1460
+#define V1460 (V + 4433)
+ 0x9ebb, 0,
+#undef V1461
+#define V1461 (V + 4435)
+ 0x9ec3, 0,
+#undef V1462
+#define V1462 (V + 4437)
+ 0x9ecd, 0,
+#undef V1463
+#define V1463 (V + 4439)
+ 0x9ed1, 0,
+#undef V1464
+#define V1464 (V + 4441)
+ 0x9ef9, 0,
+#undef V1465
+#define V1465 (V + 4443)
+ 0x9efd, 0,
+#undef V1466
+#define V1466 (V + 4445)
+ 0x9f0e, 0,
+#undef V1467
+#define V1467 (V + 4447)
+ 0x9f13, 0,
+#undef V1468
+#define V1468 (V + 4449)
+ 0x9f20, 0,
+#undef V1469
+#define V1469 (V + 4451)
+ 0x9f3b, 0,
+#undef V1470
+#define V1470 (V + 4453)
+ 0x9f4a, 0,
+#undef V1471
+#define V1471 (V + 4455)
+ 0x9f52, 0,
+#undef V1472
+#define V1472 (V + 4457)
+ 0x9f8d, 0,
+#undef V1473
+#define V1473 (V + 4459)
+ 0x9f9c, 0,
+#undef V1474
+#define V1474 (V + 4461)
+ 0x9fa0, 0,
+#undef V1475
+#define V1475 (V + 4463)
+ 0x3012, 0,
+#undef V1476
+#define V1476 (V + 4465)
+ 0x5344, 0,
+#undef V1477
+#define V1477 (V + 4467)
+ 0x5345, 0,
+#undef V1478
+#define V1478 (V + 4469)
+ 0x304b, 0x3099, 0,
+#undef V1479
+#define V1479 (V + 4472)
+ 0x304d, 0x3099, 0,
+#undef V1480
+#define V1480 (V + 4475)
+ 0x304f, 0x3099, 0,
+#undef V1481
+#define V1481 (V + 4478)
+ 0x3051, 0x3099, 0,
+#undef V1482
+#define V1482 (V + 4481)
+ 0x3053, 0x3099, 0,
+#undef V1483
+#define V1483 (V + 4484)
+ 0x3055, 0x3099, 0,
+#undef V1484
+#define V1484 (V + 4487)
+ 0x3057, 0x3099, 0,
+#undef V1485
+#define V1485 (V + 4490)
+ 0x3059, 0x3099, 0,
+#undef V1486
+#define V1486 (V + 4493)
+ 0x305b, 0x3099, 0,
+#undef V1487
+#define V1487 (V + 4496)
+ 0x305d, 0x3099, 0,
+#undef V1488
+#define V1488 (V + 4499)
+ 0x305f, 0x3099, 0,
+#undef V1489
+#define V1489 (V + 4502)
+ 0x3061, 0x3099, 0,
+#undef V1490
+#define V1490 (V + 4505)
+ 0x3064, 0x3099, 0,
+#undef V1491
+#define V1491 (V + 4508)
+ 0x3066, 0x3099, 0,
+#undef V1492
+#define V1492 (V + 4511)
+ 0x3068, 0x3099, 0,
+#undef V1493
+#define V1493 (V + 4514)
+ 0x306f, 0x3099, 0,
+#undef V1494
+#define V1494 (V + 4517)
+ 0x306f, 0x309a, 0,
+#undef V1495
+#define V1495 (V + 4520)
+ 0x3072, 0x3099, 0,
+#undef V1496
+#define V1496 (V + 4523)
+ 0x3072, 0x309a, 0,
+#undef V1497
+#define V1497 (V + 4526)
+ 0x3075, 0x3099, 0,
+#undef V1498
+#define V1498 (V + 4529)
+ 0x3075, 0x309a, 0,
+#undef V1499
+#define V1499 (V + 4532)
+ 0x3078, 0x3099, 0,
+#undef V1500
+#define V1500 (V + 4535)
+ 0x3078, 0x309a, 0,
+#undef V1501
+#define V1501 (V + 4538)
+ 0x307b, 0x3099, 0,
+#undef V1502
+#define V1502 (V + 4541)
+ 0x307b, 0x309a, 0,
+#undef V1503
+#define V1503 (V + 4544)
+ 0x3046, 0x3099, 0,
+#undef V1504
+#define V1504 (V + 4547)
+ 0x20, 0x3099, 0,
+#undef V1505
+#define V1505 (V + 4550)
+ 0x20, 0x309a, 0,
+#undef V1506
+#define V1506 (V + 4553)
+ 0x309d, 0x3099, 0,
+#undef V1507
+#define V1507 (V + 4556)
+ 0x3088, 0x308a, 0,
+#undef V1508
+#define V1508 (V + 4559)
+ 0x30ab, 0x3099, 0,
+#undef V1509
+#define V1509 (V + 4562)
+ 0x30ad, 0x3099, 0,
+#undef V1510
+#define V1510 (V + 4565)
+ 0x30af, 0x3099, 0,
+#undef V1511
+#define V1511 (V + 4568)
+ 0x30b1, 0x3099, 0,
+#undef V1512
+#define V1512 (V + 4571)
+ 0x30b3, 0x3099, 0,
+#undef V1513
+#define V1513 (V + 4574)
+ 0x30b5, 0x3099, 0,
+#undef V1514
+#define V1514 (V + 4577)
+ 0x30b7, 0x3099, 0,
+#undef V1515
+#define V1515 (V + 4580)
+ 0x30b9, 0x3099, 0,
+#undef V1516
+#define V1516 (V + 4583)
+ 0x30bb, 0x3099, 0,
+#undef V1517
+#define V1517 (V + 4586)
+ 0x30bd, 0x3099, 0,
+#undef V1518
+#define V1518 (V + 4589)
+ 0x30bf, 0x3099, 0,
+#undef V1519
+#define V1519 (V + 4592)
+ 0x30c1, 0x3099, 0,
+#undef V1520
+#define V1520 (V + 4595)
+ 0x30c4, 0x3099, 0,
+#undef V1521
+#define V1521 (V + 4598)
+ 0x30c6, 0x3099, 0,
+#undef V1522
+#define V1522 (V + 4601)
+ 0x30c8, 0x3099, 0,
+#undef V1523
+#define V1523 (V + 4604)
+ 0x30cf, 0x3099, 0,
+#undef V1524
+#define V1524 (V + 4607)
+ 0x30cf, 0x309a, 0,
+#undef V1525
+#define V1525 (V + 4610)
+ 0x30d2, 0x3099, 0,
+#undef V1526
+#define V1526 (V + 4613)
+ 0x30d2, 0x309a, 0,
+#undef V1527
+#define V1527 (V + 4616)
+ 0x30d5, 0x3099, 0,
+#undef V1528
+#define V1528 (V + 4619)
+ 0x30d5, 0x309a, 0,
+#undef V1529
+#define V1529 (V + 4622)
+ 0x30d8, 0x3099, 0,
+#undef V1530
+#define V1530 (V + 4625)
+ 0x30d8, 0x309a, 0,
+#undef V1531
+#define V1531 (V + 4628)
+ 0x30db, 0x3099, 0,
+#undef V1532
+#define V1532 (V + 4631)
+ 0x30db, 0x309a, 0,
+#undef V1533
+#define V1533 (V + 4634)
+ 0x30a6, 0x3099, 0,
+#undef V1534
+#define V1534 (V + 4637)
+ 0x30ef, 0x3099, 0,
+#undef V1535
+#define V1535 (V + 4640)
+ 0x30f0, 0x3099, 0,
+#undef V1536
+#define V1536 (V + 4643)
+ 0x30f1, 0x3099, 0,
+#undef V1537
+#define V1537 (V + 4646)
+ 0x30f2, 0x3099, 0,
+#undef V1538
+#define V1538 (V + 4649)
+ 0x30fd, 0x3099, 0,
+#undef V1539
+#define V1539 (V + 4652)
+ 0x30b3, 0x30c8, 0,
+#undef V1540
+#define V1540 (V + 4655)
+ 0x1100, 0,
+#undef V1541
+#define V1541 (V + 4657)
+ 0x1101, 0,
+#undef V1542
+#define V1542 (V + 4659)
+ 0x11aa, 0,
+#undef V1543
+#define V1543 (V + 4661)
+ 0x1102, 0,
+#undef V1544
+#define V1544 (V + 4663)
+ 0x11ac, 0,
+#undef V1545
+#define V1545 (V + 4665)
+ 0x11ad, 0,
+#undef V1546
+#define V1546 (V + 4667)
+ 0x1103, 0,
+#undef V1547
+#define V1547 (V + 4669)
+ 0x1104, 0,
+#undef V1548
+#define V1548 (V + 4671)
+ 0x1105, 0,
+#undef V1549
+#define V1549 (V + 4673)
+ 0x11b0, 0,
+#undef V1550
+#define V1550 (V + 4675)
+ 0x11b1, 0,
+#undef V1551
+#define V1551 (V + 4677)
+ 0x11b2, 0,
+#undef V1552
+#define V1552 (V + 4679)
+ 0x11b3, 0,
+#undef V1553
+#define V1553 (V + 4681)
+ 0x11b4, 0,
+#undef V1554
+#define V1554 (V + 4683)
+ 0x11b5, 0,
+#undef V1555
+#define V1555 (V + 4685)
+ 0x111a, 0,
+#undef V1556
+#define V1556 (V + 4687)
+ 0x1106, 0,
+#undef V1557
+#define V1557 (V + 4689)
+ 0x1107, 0,
+#undef V1558
+#define V1558 (V + 4691)
+ 0x1108, 0,
+#undef V1559
+#define V1559 (V + 4693)
+ 0x1121, 0,
+#undef V1560
+#define V1560 (V + 4695)
+ 0x1109, 0,
+#undef V1561
+#define V1561 (V + 4697)
+ 0x110a, 0,
+#undef V1562
+#define V1562 (V + 4699)
+ 0x110b, 0,
+#undef V1563
+#define V1563 (V + 4701)
+ 0x110c, 0,
+#undef V1564
+#define V1564 (V + 4703)
+ 0x110d, 0,
+#undef V1565
+#define V1565 (V + 4705)
+ 0x110e, 0,
+#undef V1566
+#define V1566 (V + 4707)
+ 0x110f, 0,
+#undef V1567
+#define V1567 (V + 4709)
+ 0x1110, 0,
+#undef V1568
+#define V1568 (V + 4711)
+ 0x1111, 0,
+#undef V1569
+#define V1569 (V + 4713)
+ 0x1112, 0,
+#undef V1570
+#define V1570 (V + 4715)
+ 0x1161, 0,
+#undef V1571
+#define V1571 (V + 4717)
+ 0x1162, 0,
+#undef V1572
+#define V1572 (V + 4719)
+ 0x1163, 0,
+#undef V1573
+#define V1573 (V + 4721)
+ 0x1164, 0,
+#undef V1574
+#define V1574 (V + 4723)
+ 0x1165, 0,
+#undef V1575
+#define V1575 (V + 4725)
+ 0x1166, 0,
+#undef V1576
+#define V1576 (V + 4727)
+ 0x1167, 0,
+#undef V1577
+#define V1577 (V + 4729)
+ 0x1168, 0,
+#undef V1578
+#define V1578 (V + 4731)
+ 0x1169, 0,
+#undef V1579
+#define V1579 (V + 4733)
+ 0x116a, 0,
+#undef V1580
+#define V1580 (V + 4735)
+ 0x116b, 0,
+#undef V1581
+#define V1581 (V + 4737)
+ 0x116c, 0,
+#undef V1582
+#define V1582 (V + 4739)
+ 0x116d, 0,
+#undef V1583
+#define V1583 (V + 4741)
+ 0x116e, 0,
+#undef V1584
+#define V1584 (V + 4743)
+ 0x116f, 0,
+#undef V1585
+#define V1585 (V + 4745)
+ 0x1170, 0,
+#undef V1586
+#define V1586 (V + 4747)
+ 0x1171, 0,
+#undef V1587
+#define V1587 (V + 4749)
+ 0x1172, 0,
+#undef V1588
+#define V1588 (V + 4751)
+ 0x1173, 0,
+#undef V1589
+#define V1589 (V + 4753)
+ 0x1174, 0,
+#undef V1590
+#define V1590 (V + 4755)
+ 0x1175, 0,
+#undef V1591
+#define V1591 (V + 4757)
+ 0x1160, 0,
+#undef V1592
+#define V1592 (V + 4759)
+ 0x1114, 0,
+#undef V1593
+#define V1593 (V + 4761)
+ 0x1115, 0,
+#undef V1594
+#define V1594 (V + 4763)
+ 0x11c7, 0,
+#undef V1595
+#define V1595 (V + 4765)
+ 0x11c8, 0,
+#undef V1596
+#define V1596 (V + 4767)
+ 0x11cc, 0,
+#undef V1597
+#define V1597 (V + 4769)
+ 0x11ce, 0,
+#undef V1598
+#define V1598 (V + 4771)
+ 0x11d3, 0,
+#undef V1599
+#define V1599 (V + 4773)
+ 0x11d7, 0,
+#undef V1600
+#define V1600 (V + 4775)
+ 0x11d9, 0,
+#undef V1601
+#define V1601 (V + 4777)
+ 0x111c, 0,
+#undef V1602
+#define V1602 (V + 4779)
+ 0x11dd, 0,
+#undef V1603
+#define V1603 (V + 4781)
+ 0x11df, 0,
+#undef V1604
+#define V1604 (V + 4783)
+ 0x111d, 0,
+#undef V1605
+#define V1605 (V + 4785)
+ 0x111e, 0,
+#undef V1606
+#define V1606 (V + 4787)
+ 0x1120, 0,
+#undef V1607
+#define V1607 (V + 4789)
+ 0x1122, 0,
+#undef V1608
+#define V1608 (V + 4791)
+ 0x1123, 0,
+#undef V1609
+#define V1609 (V + 4793)
+ 0x1127, 0,
+#undef V1610
+#define V1610 (V + 4795)
+ 0x1129, 0,
+#undef V1611
+#define V1611 (V + 4797)
+ 0x112b, 0,
+#undef V1612
+#define V1612 (V + 4799)
+ 0x112c, 0,
+#undef V1613
+#define V1613 (V + 4801)
+ 0x112d, 0,
+#undef V1614
+#define V1614 (V + 4803)
+ 0x112e, 0,
+#undef V1615
+#define V1615 (V + 4805)
+ 0x112f, 0,
+#undef V1616
+#define V1616 (V + 4807)
+ 0x1132, 0,
+#undef V1617
+#define V1617 (V + 4809)
+ 0x1136, 0,
+#undef V1618
+#define V1618 (V + 4811)
+ 0x1140, 0,
+#undef V1619
+#define V1619 (V + 4813)
+ 0x1147, 0,
+#undef V1620
+#define V1620 (V + 4815)
+ 0x114c, 0,
+#undef V1621
+#define V1621 (V + 4817)
+ 0x11f1, 0,
+#undef V1622
+#define V1622 (V + 4819)
+ 0x11f2, 0,
+#undef V1623
+#define V1623 (V + 4821)
+ 0x1157, 0,
+#undef V1624
+#define V1624 (V + 4823)
+ 0x1158, 0,
+#undef V1625
+#define V1625 (V + 4825)
+ 0x1159, 0,
+#undef V1626
+#define V1626 (V + 4827)
+ 0x1184, 0,
+#undef V1627
+#define V1627 (V + 4829)
+ 0x1185, 0,
+#undef V1628
+#define V1628 (V + 4831)
+ 0x1188, 0,
+#undef V1629
+#define V1629 (V + 4833)
+ 0x1191, 0,
+#undef V1630
+#define V1630 (V + 4835)
+ 0x1192, 0,
+#undef V1631
+#define V1631 (V + 4837)
+ 0x1194, 0,
+#undef V1632
+#define V1632 (V + 4839)
+ 0x119e, 0,
+#undef V1633
+#define V1633 (V + 4841)
+ 0x11a1, 0,
+#undef V1634
+#define V1634 (V + 4843)
+ 0x4e09, 0,
+#undef V1635
+#define V1635 (V + 4845)
+ 0x56db, 0,
+#undef V1636
+#define V1636 (V + 4847)
+ 0x4e0a, 0,
+#undef V1637
+#define V1637 (V + 4849)
+ 0x4e2d, 0,
+#undef V1638
+#define V1638 (V + 4851)
+ 0x4e0b, 0,
+#undef V1639
+#define V1639 (V + 4853)
+ 0x7532, 0,
+#undef V1640
+#define V1640 (V + 4855)
+ 0x4e19, 0,
+#undef V1641
+#define V1641 (V + 4857)
+ 0x4e01, 0,
+#undef V1642
+#define V1642 (V + 4859)
+ 0x5929, 0,
+#undef V1643
+#define V1643 (V + 4861)
+ 0x5730, 0,
+#undef V1644
+#define V1644 (V + 4863)
+ 0x28, 0x1100, 0x29, 0,
+#undef V1645
+#define V1645 (V + 4867)
+ 0x28, 0x1102, 0x29, 0,
+#undef V1646
+#define V1646 (V + 4871)
+ 0x28, 0x1103, 0x29, 0,
+#undef V1647
+#define V1647 (V + 4875)
+ 0x28, 0x1105, 0x29, 0,
+#undef V1648
+#define V1648 (V + 4879)
+ 0x28, 0x1106, 0x29, 0,
+#undef V1649
+#define V1649 (V + 4883)
+ 0x28, 0x1107, 0x29, 0,
+#undef V1650
+#define V1650 (V + 4887)
+ 0x28, 0x1109, 0x29, 0,
+#undef V1651
+#define V1651 (V + 4891)
+ 0x28, 0x110b, 0x29, 0,
+#undef V1652
+#define V1652 (V + 4895)
+ 0x28, 0x110c, 0x29, 0,
+#undef V1653
+#define V1653 (V + 4899)
+ 0x28, 0x110e, 0x29, 0,
+#undef V1654
+#define V1654 (V + 4903)
+ 0x28, 0x110f, 0x29, 0,
+#undef V1655
+#define V1655 (V + 4907)
+ 0x28, 0x1110, 0x29, 0,
+#undef V1656
+#define V1656 (V + 4911)
+ 0x28, 0x1111, 0x29, 0,
+#undef V1657
+#define V1657 (V + 4915)
+ 0x28, 0x1112, 0x29, 0,
+#undef V1658
+#define V1658 (V + 4919)
+ 0x28, 0x1100, 0x1161, 0x29, 0,
+#undef V1659
+#define V1659 (V + 4924)
+ 0x28, 0x1102, 0x1161, 0x29, 0,
+#undef V1660
+#define V1660 (V + 4929)
+ 0x28, 0x1103, 0x1161, 0x29, 0,
+#undef V1661
+#define V1661 (V + 4934)
+ 0x28, 0x1105, 0x1161, 0x29, 0,
+#undef V1662
+#define V1662 (V + 4939)
+ 0x28, 0x1106, 0x1161, 0x29, 0,
+#undef V1663
+#define V1663 (V + 4944)
+ 0x28, 0x1107, 0x1161, 0x29, 0,
+#undef V1664
+#define V1664 (V + 4949)
+ 0x28, 0x1109, 0x1161, 0x29, 0,
+#undef V1665
+#define V1665 (V + 4954)
+ 0x28, 0x110b, 0x1161, 0x29, 0,
+#undef V1666
+#define V1666 (V + 4959)
+ 0x28, 0x110c, 0x1161, 0x29, 0,
+#undef V1667
+#define V1667 (V + 4964)
+ 0x28, 0x110e, 0x1161, 0x29, 0,
+#undef V1668
+#define V1668 (V + 4969)
+ 0x28, 0x110f, 0x1161, 0x29, 0,
+#undef V1669
+#define V1669 (V + 4974)
+ 0x28, 0x1110, 0x1161, 0x29, 0,
+#undef V1670
+#define V1670 (V + 4979)
+ 0x28, 0x1111, 0x1161, 0x29, 0,
+#undef V1671
+#define V1671 (V + 4984)
+ 0x28, 0x1112, 0x1161, 0x29, 0,
+#undef V1672
+#define V1672 (V + 4989)
+ 0x28, 0x110c, 0x116e, 0x29, 0,
+#undef V1673
+#define V1673 (V + 4994)
+ 0x28, 0x110b, 0x1169, 0x110c, 0x1165, 0x11ab, 0x29, 0,
+#undef V1674
+#define V1674 (V + 5002)
+ 0x28, 0x110b, 0x1169, 0x1112, 0x116e, 0x29, 0,
+#undef V1675
+#define V1675 (V + 5009)
+ 0x28, 0x4e00, 0x29, 0,
+#undef V1676
+#define V1676 (V + 5013)
+ 0x28, 0x4e8c, 0x29, 0,
+#undef V1677
+#define V1677 (V + 5017)
+ 0x28, 0x4e09, 0x29, 0,
+#undef V1678
+#define V1678 (V + 5021)
+ 0x28, 0x56db, 0x29, 0,
+#undef V1679
+#define V1679 (V + 5025)
+ 0x28, 0x4e94, 0x29, 0,
+#undef V1680
+#define V1680 (V + 5029)
+ 0x28, 0x516d, 0x29, 0,
+#undef V1681
+#define V1681 (V + 5033)
+ 0x28, 0x4e03, 0x29, 0,
+#undef V1682
+#define V1682 (V + 5037)
+ 0x28, 0x516b, 0x29, 0,
+#undef V1683
+#define V1683 (V + 5041)
+ 0x28, 0x4e5d, 0x29, 0,
+#undef V1684
+#define V1684 (V + 5045)
+ 0x28, 0x5341, 0x29, 0,
+#undef V1685
+#define V1685 (V + 5049)
+ 0x28, 0x6708, 0x29, 0,
+#undef V1686
+#define V1686 (V + 5053)
+ 0x28, 0x706b, 0x29, 0,
+#undef V1687
+#define V1687 (V + 5057)
+ 0x28, 0x6c34, 0x29, 0,
+#undef V1688
+#define V1688 (V + 5061)
+ 0x28, 0x6728, 0x29, 0,
+#undef V1689
+#define V1689 (V + 5065)
+ 0x28, 0x91d1, 0x29, 0,
+#undef V1690
+#define V1690 (V + 5069)
+ 0x28, 0x571f, 0x29, 0,
+#undef V1691
+#define V1691 (V + 5073)
+ 0x28, 0x65e5, 0x29, 0,
+#undef V1692
+#define V1692 (V + 5077)
+ 0x28, 0x682a, 0x29, 0,
+#undef V1693
+#define V1693 (V + 5081)
+ 0x28, 0x6709, 0x29, 0,
+#undef V1694
+#define V1694 (V + 5085)
+ 0x28, 0x793e, 0x29, 0,
+#undef V1695
+#define V1695 (V + 5089)
+ 0x28, 0x540d, 0x29, 0,
+#undef V1696
+#define V1696 (V + 5093)
+ 0x28, 0x7279, 0x29, 0,
+#undef V1697
+#define V1697 (V + 5097)
+ 0x28, 0x8ca1, 0x29, 0,
+#undef V1698
+#define V1698 (V + 5101)
+ 0x28, 0x795d, 0x29, 0,
+#undef V1699
+#define V1699 (V + 5105)
+ 0x28, 0x52b4, 0x29, 0,
+#undef V1700
+#define V1700 (V + 5109)
+ 0x28, 0x4ee3, 0x29, 0,
+#undef V1701
+#define V1701 (V + 5113)
+ 0x28, 0x547c, 0x29, 0,
+#undef V1702
+#define V1702 (V + 5117)
+ 0x28, 0x5b66, 0x29, 0,
+#undef V1703
+#define V1703 (V + 5121)
+ 0x28, 0x76e3, 0x29, 0,
+#undef V1704
+#define V1704 (V + 5125)
+ 0x28, 0x4f01, 0x29, 0,
+#undef V1705
+#define V1705 (V + 5129)
+ 0x28, 0x8cc7, 0x29, 0,
+#undef V1706
+#define V1706 (V + 5133)
+ 0x28, 0x5354, 0x29, 0,
+#undef V1707
+#define V1707 (V + 5137)
+ 0x28, 0x796d, 0x29, 0,
+#undef V1708
+#define V1708 (V + 5141)
+ 0x28, 0x4f11, 0x29, 0,
+#undef V1709
+#define V1709 (V + 5145)
+ 0x28, 0x81ea, 0x29, 0,
+#undef V1710
+#define V1710 (V + 5149)
+ 0x28, 0x81f3, 0x29, 0,
+#undef V1711
+#define V1711 (V + 5153)
+ 0x554f, 0,
+#undef V1712
+#define V1712 (V + 5155)
+ 0x5e7c, 0,
+#undef V1713
+#define V1713 (V + 5157)
+ 0x7b8f, 0,
+#undef V1714
+#define V1714 (V + 5159)
+ 0x50, 0x54, 0x45, 0,
+#undef V1715
+#define V1715 (V + 5163)
+ 0x32, 0x31, 0,
+#undef V1716
+#define V1716 (V + 5166)
+ 0x32, 0x32, 0,
+#undef V1717
+#define V1717 (V + 5169)
+ 0x32, 0x33, 0,
+#undef V1718
+#define V1718 (V + 5172)
+ 0x32, 0x34, 0,
+#undef V1719
+#define V1719 (V + 5175)
+ 0x32, 0x35, 0,
+#undef V1720
+#define V1720 (V + 5178)
+ 0x32, 0x36, 0,
+#undef V1721
+#define V1721 (V + 5181)
+ 0x32, 0x37, 0,
+#undef V1722
+#define V1722 (V + 5184)
+ 0x32, 0x38, 0,
+#undef V1723
+#define V1723 (V + 5187)
+ 0x32, 0x39, 0,
+#undef V1724
+#define V1724 (V + 5190)
+ 0x33, 0x30, 0,
+#undef V1725
+#define V1725 (V + 5193)
+ 0x33, 0x31, 0,
+#undef V1726
+#define V1726 (V + 5196)
+ 0x33, 0x32, 0,
+#undef V1727
+#define V1727 (V + 5199)
+ 0x33, 0x33, 0,
+#undef V1728
+#define V1728 (V + 5202)
+ 0x33, 0x34, 0,
+#undef V1729
+#define V1729 (V + 5205)
+ 0x33, 0x35, 0,
+#undef V1730
+#define V1730 (V + 5208)
+ 0x1100, 0x1161, 0,
+#undef V1731
+#define V1731 (V + 5211)
+ 0x1102, 0x1161, 0,
+#undef V1732
+#define V1732 (V + 5214)
+ 0x1103, 0x1161, 0,
+#undef V1733
+#define V1733 (V + 5217)
+ 0x1105, 0x1161, 0,
+#undef V1734
+#define V1734 (V + 5220)
+ 0x1106, 0x1161, 0,
+#undef V1735
+#define V1735 (V + 5223)
+ 0x1107, 0x1161, 0,
+#undef V1736
+#define V1736 (V + 5226)
+ 0x1109, 0x1161, 0,
+#undef V1737
+#define V1737 (V + 5229)
+ 0x110b, 0x1161, 0,
+#undef V1738
+#define V1738 (V + 5232)
+ 0x110c, 0x1161, 0,
+#undef V1739
+#define V1739 (V + 5235)
+ 0x110e, 0x1161, 0,
+#undef V1740
+#define V1740 (V + 5238)
+ 0x110f, 0x1161, 0,
+#undef V1741
+#define V1741 (V + 5241)
+ 0x1110, 0x1161, 0,
+#undef V1742
+#define V1742 (V + 5244)
+ 0x1111, 0x1161, 0,
+#undef V1743
+#define V1743 (V + 5247)
+ 0x1112, 0x1161, 0,
+#undef V1744
+#define V1744 (V + 5250)
+ 0x110e, 0x1161, 0x11b7, 0x1100, 0x1169, 0,
+#undef V1745
+#define V1745 (V + 5256)
+ 0x110c, 0x116e, 0x110b, 0x1174, 0,
+#undef V1746
+#define V1746 (V + 5261)
+ 0x110b, 0x116e, 0,
+#undef V1747
+#define V1747 (V + 5264)
+ 0x4e94, 0,
+#undef V1748
+#define V1748 (V + 5266)
+ 0x516d, 0,
+#undef V1749
+#define V1749 (V + 5268)
+ 0x4e03, 0,
+#undef V1750
+#define V1750 (V + 5270)
+ 0x4e5d, 0,
+#undef V1751
+#define V1751 (V + 5272)
+ 0x682a, 0,
+#undef V1752
+#define V1752 (V + 5274)
+ 0x6709, 0,
+#undef V1753
+#define V1753 (V + 5276)
+ 0x793e, 0,
+#undef V1754
+#define V1754 (V + 5278)
+ 0x540d, 0,
+#undef V1755
+#define V1755 (V + 5280)
+ 0x7279, 0,
+#undef V1756
+#define V1756 (V + 5282)
+ 0x8ca1, 0,
+#undef V1757
+#define V1757 (V + 5284)
+ 0x795d, 0,
+#undef V1758
+#define V1758 (V + 5286)
+ 0x52b4, 0,
+#undef V1759
+#define V1759 (V + 5288)
+ 0x79d8, 0,
+#undef V1760
+#define V1760 (V + 5290)
+ 0x7537, 0,
+#undef V1761
+#define V1761 (V + 5292)
+ 0x9069, 0,
+#undef V1762
+#define V1762 (V + 5294)
+ 0x512a, 0,
+#undef V1763
+#define V1763 (V + 5296)
+ 0x5370, 0,
+#undef V1764
+#define V1764 (V + 5298)
+ 0x6ce8, 0,
+#undef V1765
+#define V1765 (V + 5300)
+ 0x9805, 0,
+#undef V1766
+#define V1766 (V + 5302)
+ 0x4f11, 0,
+#undef V1767
+#define V1767 (V + 5304)
+ 0x5199, 0,
+#undef V1768
+#define V1768 (V + 5306)
+ 0x6b63, 0,
+#undef V1769
+#define V1769 (V + 5308)
+ 0x5de6, 0,
+#undef V1770
+#define V1770 (V + 5310)
+ 0x53f3, 0,
+#undef V1771
+#define V1771 (V + 5312)
+ 0x533b, 0,
+#undef V1772
+#define V1772 (V + 5314)
+ 0x5b97, 0,
+#undef V1773
+#define V1773 (V + 5316)
+ 0x5b66, 0,
+#undef V1774
+#define V1774 (V + 5318)
+ 0x76e3, 0,
+#undef V1775
+#define V1775 (V + 5320)
+ 0x4f01, 0,
+#undef V1776
+#define V1776 (V + 5322)
+ 0x8cc7, 0,
+#undef V1777
+#define V1777 (V + 5324)
+ 0x5354, 0,
+#undef V1778
+#define V1778 (V + 5326)
+ 0x591c, 0,
+#undef V1779
+#define V1779 (V + 5328)
+ 0x33, 0x36, 0,
+#undef V1780
+#define V1780 (V + 5331)
+ 0x33, 0x37, 0,
+#undef V1781
+#define V1781 (V + 5334)
+ 0x33, 0x38, 0,
+#undef V1782
+#define V1782 (V + 5337)
+ 0x33, 0x39, 0,
+#undef V1783
+#define V1783 (V + 5340)
+ 0x34, 0x30, 0,
+#undef V1784
+#define V1784 (V + 5343)
+ 0x34, 0x31, 0,
+#undef V1785
+#define V1785 (V + 5346)
+ 0x34, 0x32, 0,
+#undef V1786
+#define V1786 (V + 5349)
+ 0x34, 0x33, 0,
+#undef V1787
+#define V1787 (V + 5352)
+ 0x34, 0x34, 0,
+#undef V1788
+#define V1788 (V + 5355)
+ 0x34, 0x35, 0,
+#undef V1789
+#define V1789 (V + 5358)
+ 0x34, 0x36, 0,
+#undef V1790
+#define V1790 (V + 5361)
+ 0x34, 0x37, 0,
+#undef V1791
+#define V1791 (V + 5364)
+ 0x34, 0x38, 0,
+#undef V1792
+#define V1792 (V + 5367)
+ 0x34, 0x39, 0,
+#undef V1793
+#define V1793 (V + 5370)
+ 0x35, 0x30, 0,
+#undef V1794
+#define V1794 (V + 5373)
+ 0x31, 0x6708, 0,
+#undef V1795
+#define V1795 (V + 5376)
+ 0x32, 0x6708, 0,
+#undef V1796
+#define V1796 (V + 5379)
+ 0x33, 0x6708, 0,
+#undef V1797
+#define V1797 (V + 5382)
+ 0x34, 0x6708, 0,
+#undef V1798
+#define V1798 (V + 5385)
+ 0x35, 0x6708, 0,
+#undef V1799
+#define V1799 (V + 5388)
+ 0x36, 0x6708, 0,
+#undef V1800
+#define V1800 (V + 5391)
+ 0x37, 0x6708, 0,
+#undef V1801
+#define V1801 (V + 5394)
+ 0x38, 0x6708, 0,
+#undef V1802
+#define V1802 (V + 5397)
+ 0x39, 0x6708, 0,
+#undef V1803
+#define V1803 (V + 5400)
+ 0x31, 0x30, 0x6708, 0,
+#undef V1804
+#define V1804 (V + 5404)
+ 0x31, 0x31, 0x6708, 0,
+#undef V1805
+#define V1805 (V + 5408)
+ 0x31, 0x32, 0x6708, 0,
+#undef V1806
+#define V1806 (V + 5412)
+ 0x48, 0x67, 0,
+#undef V1807
+#define V1807 (V + 5415)
+ 0x65, 0x72, 0x67, 0,
+#undef V1808
+#define V1808 (V + 5419)
+ 0x65, 0x56, 0,
+#undef V1809
+#define V1809 (V + 5422)
+ 0x4c, 0x54, 0x44, 0,
+#undef V1810
+#define V1810 (V + 5426)
+ 0x30a2, 0,
+#undef V1811
+#define V1811 (V + 5428)
+ 0x30a4, 0,
+#undef V1812
+#define V1812 (V + 5430)
+ 0x30a6, 0,
+#undef V1813
+#define V1813 (V + 5432)
+ 0x30a8, 0,
+#undef V1814
+#define V1814 (V + 5434)
+ 0x30aa, 0,
+#undef V1815
+#define V1815 (V + 5436)
+ 0x30ab, 0,
+#undef V1816
+#define V1816 (V + 5438)
+ 0x30ad, 0,
+#undef V1817
+#define V1817 (V + 5440)
+ 0x30af, 0,
+#undef V1818
+#define V1818 (V + 5442)
+ 0x30b1, 0,
+#undef V1819
+#define V1819 (V + 5444)
+ 0x30b3, 0,
+#undef V1820
+#define V1820 (V + 5446)
+ 0x30b5, 0,
+#undef V1821
+#define V1821 (V + 5448)
+ 0x30b7, 0,
+#undef V1822
+#define V1822 (V + 5450)
+ 0x30b9, 0,
+#undef V1823
+#define V1823 (V + 5452)
+ 0x30bb, 0,
+#undef V1824
+#define V1824 (V + 5454)
+ 0x30bd, 0,
+#undef V1825
+#define V1825 (V + 5456)
+ 0x30bf, 0,
+#undef V1826
+#define V1826 (V + 5458)
+ 0x30c1, 0,
+#undef V1827
+#define V1827 (V + 5460)
+ 0x30c4, 0,
+#undef V1828
+#define V1828 (V + 5462)
+ 0x30c6, 0,
+#undef V1829
+#define V1829 (V + 5464)
+ 0x30c8, 0,
+#undef V1830
+#define V1830 (V + 5466)
+ 0x30ca, 0,
+#undef V1831
+#define V1831 (V + 5468)
+ 0x30cb, 0,
+#undef V1832
+#define V1832 (V + 5470)
+ 0x30cc, 0,
+#undef V1833
+#define V1833 (V + 5472)
+ 0x30cd, 0,
+#undef V1834
+#define V1834 (V + 5474)
+ 0x30ce, 0,
+#undef V1835
+#define V1835 (V + 5476)
+ 0x30cf, 0,
+#undef V1836
+#define V1836 (V + 5478)
+ 0x30d2, 0,
+#undef V1837
+#define V1837 (V + 5480)
+ 0x30d5, 0,
+#undef V1838
+#define V1838 (V + 5482)
+ 0x30d8, 0,
+#undef V1839
+#define V1839 (V + 5484)
+ 0x30db, 0,
+#undef V1840
+#define V1840 (V + 5486)
+ 0x30de, 0,
+#undef V1841
+#define V1841 (V + 5488)
+ 0x30df, 0,
+#undef V1842
+#define V1842 (V + 5490)
+ 0x30e0, 0,
+#undef V1843
+#define V1843 (V + 5492)
+ 0x30e1, 0,
+#undef V1844
+#define V1844 (V + 5494)
+ 0x30e2, 0,
+#undef V1845
+#define V1845 (V + 5496)
+ 0x30e4, 0,
+#undef V1846
+#define V1846 (V + 5498)
+ 0x30e6, 0,
+#undef V1847
+#define V1847 (V + 5500)
+ 0x30e8, 0,
+#undef V1848
+#define V1848 (V + 5502)
+ 0x30e9, 0,
+#undef V1849
+#define V1849 (V + 5504)
+ 0x30ea, 0,
+#undef V1850
+#define V1850 (V + 5506)
+ 0x30eb, 0,
+#undef V1851
+#define V1851 (V + 5508)
+ 0x30ec, 0,
+#undef V1852
+#define V1852 (V + 5510)
+ 0x30ed, 0,
+#undef V1853
+#define V1853 (V + 5512)
+ 0x30ef, 0,
+#undef V1854
+#define V1854 (V + 5514)
+ 0x30f0, 0,
+#undef V1855
+#define V1855 (V + 5516)
+ 0x30f1, 0,
+#undef V1856
+#define V1856 (V + 5518)
+ 0x30f2, 0,
+#undef V1857
+#define V1857 (V + 5520)
+ 0x30a2, 0x30cf, 0x309a, 0x30fc, 0x30c8, 0,
+#undef V1858
+#define V1858 (V + 5526)
+ 0x30a2, 0x30eb, 0x30d5, 0x30a1, 0,
+#undef V1859
+#define V1859 (V + 5531)
+ 0x30a2, 0x30f3, 0x30d8, 0x309a, 0x30a2, 0,
+#undef V1860
+#define V1860 (V + 5537)
+ 0x30a2, 0x30fc, 0x30eb, 0,
+#undef V1861
+#define V1861 (V + 5541)
+ 0x30a4, 0x30cb, 0x30f3, 0x30af, 0x3099, 0,
+#undef V1862
+#define V1862 (V + 5547)
+ 0x30a4, 0x30f3, 0x30c1, 0,
+#undef V1863
+#define V1863 (V + 5551)
+ 0x30a6, 0x30a9, 0x30f3, 0,
+#undef V1864
+#define V1864 (V + 5555)
+ 0x30a8, 0x30b9, 0x30af, 0x30fc, 0x30c8, 0x3099, 0,
+#undef V1865
+#define V1865 (V + 5562)
+ 0x30a8, 0x30fc, 0x30ab, 0x30fc, 0,
+#undef V1866
+#define V1866 (V + 5567)
+ 0x30aa, 0x30f3, 0x30b9, 0,
+#undef V1867
+#define V1867 (V + 5571)
+ 0x30aa, 0x30fc, 0x30e0, 0,
+#undef V1868
+#define V1868 (V + 5575)
+ 0x30ab, 0x30a4, 0x30ea, 0,
+#undef V1869
+#define V1869 (V + 5579)
+ 0x30ab, 0x30e9, 0x30c3, 0x30c8, 0,
+#undef V1870
+#define V1870 (V + 5584)
+ 0x30ab, 0x30ed, 0x30ea, 0x30fc, 0,
+#undef V1871
+#define V1871 (V + 5589)
+ 0x30ab, 0x3099, 0x30ed, 0x30f3, 0,
+#undef V1872
+#define V1872 (V + 5594)
+ 0x30ab, 0x3099, 0x30f3, 0x30de, 0,
+#undef V1873
+#define V1873 (V + 5599)
+ 0x30ad, 0x3099, 0x30ab, 0x3099, 0,
+#undef V1874
+#define V1874 (V + 5604)
+ 0x30ad, 0x3099, 0x30cb, 0x30fc, 0,
+#undef V1875
+#define V1875 (V + 5609)
+ 0x30ad, 0x30e5, 0x30ea, 0x30fc, 0,
+#undef V1876
+#define V1876 (V + 5614)
+ 0x30ad, 0x3099, 0x30eb, 0x30bf, 0x3099, 0x30fc, 0,
+#undef V1877
+#define V1877 (V + 5621)
+ 0x30ad, 0x30ed, 0,
+#undef V1878
+#define V1878 (V + 5624)
+ 0x30ad, 0x30ed, 0x30af, 0x3099, 0x30e9, 0x30e0, 0,
+#undef V1879
+#define V1879 (V + 5631)
+ 0x30ad, 0x30ed, 0x30e1, 0x30fc, 0x30c8, 0x30eb, 0,
+#undef V1880
+#define V1880 (V + 5638)
+ 0x30ad, 0x30ed, 0x30ef, 0x30c3, 0x30c8, 0,
+#undef V1881
+#define V1881 (V + 5644)
+ 0x30af, 0x3099, 0x30e9, 0x30e0, 0,
+#undef V1882
+#define V1882 (V + 5649)
+ 0x30af, 0x3099, 0x30e9, 0x30e0, 0x30c8, 0x30f3, 0,
+#undef V1883
+#define V1883 (V + 5656)
+ 0x30af, 0x30eb, 0x30bb, 0x3099, 0x30a4, 0x30ed, 0,
+#undef V1884
+#define V1884 (V + 5663)
+ 0x30af, 0x30ed, 0x30fc, 0x30cd, 0,
+#undef V1885
+#define V1885 (V + 5668)
+ 0x30b1, 0x30fc, 0x30b9, 0,
+#undef V1886
+#define V1886 (V + 5672)
+ 0x30b3, 0x30eb, 0x30ca, 0,
+#undef V1887
+#define V1887 (V + 5676)
+ 0x30b3, 0x30fc, 0x30db, 0x309a, 0,
+#undef V1888
+#define V1888 (V + 5681)
+ 0x30b5, 0x30a4, 0x30af, 0x30eb, 0,
+#undef V1889
+#define V1889 (V + 5686)
+ 0x30b5, 0x30f3, 0x30c1, 0x30fc, 0x30e0, 0,
+#undef V1890
+#define V1890 (V + 5692)
+ 0x30b7, 0x30ea, 0x30f3, 0x30af, 0x3099, 0,
+#undef V1891
+#define V1891 (V + 5698)
+ 0x30bb, 0x30f3, 0x30c1, 0,
+#undef V1892
+#define V1892 (V + 5702)
+ 0x30bb, 0x30f3, 0x30c8, 0,
+#undef V1893
+#define V1893 (V + 5706)
+ 0x30bf, 0x3099, 0x30fc, 0x30b9, 0,
+#undef V1894
+#define V1894 (V + 5711)
+ 0x30c6, 0x3099, 0x30b7, 0,
+#undef V1895
+#define V1895 (V + 5715)
+ 0x30c8, 0x3099, 0x30eb, 0,
+#undef V1896
+#define V1896 (V + 5719)
+ 0x30c8, 0x30f3, 0,
+#undef V1897
+#define V1897 (V + 5722)
+ 0x30ca, 0x30ce, 0,
+#undef V1898
+#define V1898 (V + 5725)
+ 0x30ce, 0x30c3, 0x30c8, 0,
+#undef V1899
+#define V1899 (V + 5729)
+ 0x30cf, 0x30a4, 0x30c4, 0,
+#undef V1900
+#define V1900 (V + 5733)
+ 0x30cf, 0x309a, 0x30fc, 0x30bb, 0x30f3, 0x30c8, 0,
+#undef V1901
+#define V1901 (V + 5740)
+ 0x30cf, 0x309a, 0x30fc, 0x30c4, 0,
+#undef V1902
+#define V1902 (V + 5745)
+ 0x30cf, 0x3099, 0x30fc, 0x30ec, 0x30eb, 0,
+#undef V1903
+#define V1903 (V + 5751)
+ 0x30d2, 0x309a, 0x30a2, 0x30b9, 0x30c8, 0x30eb, 0,
+#undef V1904
+#define V1904 (V + 5758)
+ 0x30d2, 0x309a, 0x30af, 0x30eb, 0,
+#undef V1905
+#define V1905 (V + 5763)
+ 0x30d2, 0x309a, 0x30b3, 0,
+#undef V1906
+#define V1906 (V + 5767)
+ 0x30d2, 0x3099, 0x30eb, 0,
+#undef V1907
+#define V1907 (V + 5771)
+ 0x30d5, 0x30a1, 0x30e9, 0x30c3, 0x30c8, 0x3099, 0,
+#undef V1908
+#define V1908 (V + 5778)
+ 0x30d5, 0x30a3, 0x30fc, 0x30c8, 0,
+#undef V1909
+#define V1909 (V + 5783)
+ 0x30d5, 0x3099, 0x30c3, 0x30b7, 0x30a7, 0x30eb, 0,
+#undef V1910
+#define V1910 (V + 5790)
+ 0x30d5, 0x30e9, 0x30f3, 0,
+#undef V1911
+#define V1911 (V + 5794)
+ 0x30d8, 0x30af, 0x30bf, 0x30fc, 0x30eb, 0,
+#undef V1912
+#define V1912 (V + 5800)
+ 0x30d8, 0x309a, 0x30bd, 0,
+#undef V1913
+#define V1913 (V + 5804)
+ 0x30d8, 0x309a, 0x30cb, 0x30d2, 0,
+#undef V1914
+#define V1914 (V + 5809)
+ 0x30d8, 0x30eb, 0x30c4, 0,
+#undef V1915
+#define V1915 (V + 5813)
+ 0x30d8, 0x309a, 0x30f3, 0x30b9, 0,
+#undef V1916
+#define V1916 (V + 5818)
+ 0x30d8, 0x309a, 0x30fc, 0x30b7, 0x3099, 0,
+#undef V1917
+#define V1917 (V + 5824)
+ 0x30d8, 0x3099, 0x30fc, 0x30bf, 0,
+#undef V1918
+#define V1918 (V + 5829)
+ 0x30db, 0x309a, 0x30a4, 0x30f3, 0x30c8, 0,
+#undef V1919
+#define V1919 (V + 5835)
+ 0x30db, 0x3099, 0x30eb, 0x30c8, 0,
+#undef V1920
+#define V1920 (V + 5840)
+ 0x30db, 0x30f3, 0,
+#undef V1921
+#define V1921 (V + 5843)
+ 0x30db, 0x309a, 0x30f3, 0x30c8, 0x3099, 0,
+#undef V1922
+#define V1922 (V + 5849)
+ 0x30db, 0x30fc, 0x30eb, 0,
+#undef V1923
+#define V1923 (V + 5853)
+ 0x30db, 0x30fc, 0x30f3, 0,
+#undef V1924
+#define V1924 (V + 5857)
+ 0x30de, 0x30a4, 0x30af, 0x30ed, 0,
+#undef V1925
+#define V1925 (V + 5862)
+ 0x30de, 0x30a4, 0x30eb, 0,
+#undef V1926
+#define V1926 (V + 5866)
+ 0x30de, 0x30c3, 0x30cf, 0,
+#undef V1927
+#define V1927 (V + 5870)
+ 0x30de, 0x30eb, 0x30af, 0,
+#undef V1928
+#define V1928 (V + 5874)
+ 0x30de, 0x30f3, 0x30b7, 0x30e7, 0x30f3, 0,
+#undef V1929
+#define V1929 (V + 5880)
+ 0x30df, 0x30af, 0x30ed, 0x30f3, 0,
+#undef V1930
+#define V1930 (V + 5885)
+ 0x30df, 0x30ea, 0,
+#undef V1931
+#define V1931 (V + 5888)
+ 0x30df, 0x30ea, 0x30cf, 0x3099, 0x30fc, 0x30eb, 0,
+#undef V1932
+#define V1932 (V + 5895)
+ 0x30e1, 0x30ab, 0x3099, 0,
+#undef V1933
+#define V1933 (V + 5899)
+ 0x30e1, 0x30ab, 0x3099, 0x30c8, 0x30f3, 0,
+#undef V1934
+#define V1934 (V + 5905)
+ 0x30e1, 0x30fc, 0x30c8, 0x30eb, 0,
+#undef V1935
+#define V1935 (V + 5910)
+ 0x30e4, 0x30fc, 0x30c8, 0x3099, 0,
+#undef V1936
+#define V1936 (V + 5915)
+ 0x30e4, 0x30fc, 0x30eb, 0,
+#undef V1937
+#define V1937 (V + 5919)
+ 0x30e6, 0x30a2, 0x30f3, 0,
+#undef V1938
+#define V1938 (V + 5923)
+ 0x30ea, 0x30c3, 0x30c8, 0x30eb, 0,
+#undef V1939
+#define V1939 (V + 5928)
+ 0x30ea, 0x30e9, 0,
+#undef V1940
+#define V1940 (V + 5931)
+ 0x30eb, 0x30d2, 0x309a, 0x30fc, 0,
+#undef V1941
+#define V1941 (V + 5936)
+ 0x30eb, 0x30fc, 0x30d5, 0x3099, 0x30eb, 0,
+#undef V1942
+#define V1942 (V + 5942)
+ 0x30ec, 0x30e0, 0,
+#undef V1943
+#define V1943 (V + 5945)
+ 0x30ec, 0x30f3, 0x30c8, 0x30b1, 0x3099, 0x30f3, 0,
+#undef V1944
+#define V1944 (V + 5952)
+ 0x30ef, 0x30c3, 0x30c8, 0,
+#undef V1945
+#define V1945 (V + 5956)
+ 0x30, 0x70b9, 0,
+#undef V1946
+#define V1946 (V + 5959)
+ 0x31, 0x70b9, 0,
+#undef V1947
+#define V1947 (V + 5962)
+ 0x32, 0x70b9, 0,
+#undef V1948
+#define V1948 (V + 5965)
+ 0x33, 0x70b9, 0,
+#undef V1949
+#define V1949 (V + 5968)
+ 0x34, 0x70b9, 0,
+#undef V1950
+#define V1950 (V + 5971)
+ 0x35, 0x70b9, 0,
+#undef V1951
+#define V1951 (V + 5974)
+ 0x36, 0x70b9, 0,
+#undef V1952
+#define V1952 (V + 5977)
+ 0x37, 0x70b9, 0,
+#undef V1953
+#define V1953 (V + 5980)
+ 0x38, 0x70b9, 0,
+#undef V1954
+#define V1954 (V + 5983)
+ 0x39, 0x70b9, 0,
+#undef V1955
+#define V1955 (V + 5986)
+ 0x31, 0x30, 0x70b9, 0,
+#undef V1956
+#define V1956 (V + 5990)
+ 0x31, 0x31, 0x70b9, 0,
+#undef V1957
+#define V1957 (V + 5994)
+ 0x31, 0x32, 0x70b9, 0,
+#undef V1958
+#define V1958 (V + 5998)
+ 0x31, 0x33, 0x70b9, 0,
+#undef V1959
+#define V1959 (V + 6002)
+ 0x31, 0x34, 0x70b9, 0,
+#undef V1960
+#define V1960 (V + 6006)
+ 0x31, 0x35, 0x70b9, 0,
+#undef V1961
+#define V1961 (V + 6010)
+ 0x31, 0x36, 0x70b9, 0,
+#undef V1962
+#define V1962 (V + 6014)
+ 0x31, 0x37, 0x70b9, 0,
+#undef V1963
+#define V1963 (V + 6018)
+ 0x31, 0x38, 0x70b9, 0,
+#undef V1964
+#define V1964 (V + 6022)
+ 0x31, 0x39, 0x70b9, 0,
+#undef V1965
+#define V1965 (V + 6026)
+ 0x32, 0x30, 0x70b9, 0,
+#undef V1966
+#define V1966 (V + 6030)
+ 0x32, 0x31, 0x70b9, 0,
+#undef V1967
+#define V1967 (V + 6034)
+ 0x32, 0x32, 0x70b9, 0,
+#undef V1968
+#define V1968 (V + 6038)
+ 0x32, 0x33, 0x70b9, 0,
+#undef V1969
+#define V1969 (V + 6042)
+ 0x32, 0x34, 0x70b9, 0,
+#undef V1970
+#define V1970 (V + 6046)
+ 0x68, 0x50, 0x61, 0,
+#undef V1971
+#define V1971 (V + 6050)
+ 0x64, 0x61, 0,
+#undef V1972
+#define V1972 (V + 6053)
+ 0x41, 0x55, 0,
+#undef V1973
+#define V1973 (V + 6056)
+ 0x62, 0x61, 0x72, 0,
+#undef V1974
+#define V1974 (V + 6060)
+ 0x6f, 0x56, 0,
+#undef V1975
+#define V1975 (V + 6063)
+ 0x70, 0x63, 0,
+#undef V1976
+#define V1976 (V + 6066)
+ 0x64, 0x6d, 0,
+#undef V1977
+#define V1977 (V + 6069)
+ 0x64, 0x6d, 0x32, 0,
+#undef V1978
+#define V1978 (V + 6073)
+ 0x64, 0x6d, 0x33, 0,
+#undef V1979
+#define V1979 (V + 6077)
+ 0x49, 0x55, 0,
+#undef V1980
+#define V1980 (V + 6080)
+ 0x5e73, 0x6210, 0,
+#undef V1981
+#define V1981 (V + 6083)
+ 0x662d, 0x548c, 0,
+#undef V1982
+#define V1982 (V + 6086)
+ 0x5927, 0x6b63, 0,
+#undef V1983
+#define V1983 (V + 6089)
+ 0x660e, 0x6cbb, 0,
+#undef V1984
+#define V1984 (V + 6092)
+ 0x682a, 0x5f0f, 0x4f1a, 0x793e, 0,
+#undef V1985
+#define V1985 (V + 6097)
+ 0x70, 0x41, 0,
+#undef V1986
+#define V1986 (V + 6100)
+ 0x6e, 0x41, 0,
+#undef V1987
+#define V1987 (V + 6103)
+ 0x3bc, 0x41, 0,
+#undef V1988
+#define V1988 (V + 6106)
+ 0x6d, 0x41, 0,
+#undef V1989
+#define V1989 (V + 6109)
+ 0x6b, 0x41, 0,
+#undef V1990
+#define V1990 (V + 6112)
+ 0x4b, 0x42, 0,
+#undef V1991
+#define V1991 (V + 6115)
+ 0x4d, 0x42, 0,
+#undef V1992
+#define V1992 (V + 6118)
+ 0x47, 0x42, 0,
+#undef V1993
+#define V1993 (V + 6121)
+ 0x63, 0x61, 0x6c, 0,
+#undef V1994
+#define V1994 (V + 6125)
+ 0x6b, 0x63, 0x61, 0x6c, 0,
+#undef V1995
+#define V1995 (V + 6130)
+ 0x70, 0x46, 0,
+#undef V1996
+#define V1996 (V + 6133)
+ 0x6e, 0x46, 0,
+#undef V1997
+#define V1997 (V + 6136)
+ 0x3bc, 0x46, 0,
+#undef V1998
+#define V1998 (V + 6139)
+ 0x3bc, 0x67, 0,
+#undef V1999
+#define V1999 (V + 6142)
+ 0x6d, 0x67, 0,
+#undef V2000
+#define V2000 (V + 6145)
+ 0x6b, 0x67, 0,
+#undef V2001
+#define V2001 (V + 6148)
+ 0x48, 0x7a, 0,
+#undef V2002
+#define V2002 (V + 6151)
+ 0x6b, 0x48, 0x7a, 0,
+#undef V2003
+#define V2003 (V + 6155)
+ 0x4d, 0x48, 0x7a, 0,
+#undef V2004
+#define V2004 (V + 6159)
+ 0x47, 0x48, 0x7a, 0,
+#undef V2005
+#define V2005 (V + 6163)
+ 0x54, 0x48, 0x7a, 0,
+#undef V2006
+#define V2006 (V + 6167)
+ 0x3bc, 0x6c, 0,
+#undef V2007
+#define V2007 (V + 6170)
+ 0x6d, 0x6c, 0,
+#undef V2008
+#define V2008 (V + 6173)
+ 0x64, 0x6c, 0,
+#undef V2009
+#define V2009 (V + 6176)
+ 0x6b, 0x6c, 0,
+#undef V2010
+#define V2010 (V + 6179)
+ 0x66, 0x6d, 0,
+#undef V2011
+#define V2011 (V + 6182)
+ 0x6e, 0x6d, 0,
+#undef V2012
+#define V2012 (V + 6185)
+ 0x3bc, 0x6d, 0,
+#undef V2013
+#define V2013 (V + 6188)
+ 0x6d, 0x6d, 0,
+#undef V2014
+#define V2014 (V + 6191)
+ 0x63, 0x6d, 0,
+#undef V2015
+#define V2015 (V + 6194)
+ 0x6b, 0x6d, 0,
+#undef V2016
+#define V2016 (V + 6197)
+ 0x6d, 0x6d, 0x32, 0,
+#undef V2017
+#define V2017 (V + 6201)
+ 0x63, 0x6d, 0x32, 0,
+#undef V2018
+#define V2018 (V + 6205)
+ 0x6d, 0x32, 0,
+#undef V2019
+#define V2019 (V + 6208)
+ 0x6b, 0x6d, 0x32, 0,
+#undef V2020
+#define V2020 (V + 6212)
+ 0x6d, 0x6d, 0x33, 0,
+#undef V2021
+#define V2021 (V + 6216)
+ 0x63, 0x6d, 0x33, 0,
+#undef V2022
+#define V2022 (V + 6220)
+ 0x6d, 0x33, 0,
+#undef V2023
+#define V2023 (V + 6223)
+ 0x6b, 0x6d, 0x33, 0,
+#undef V2024
+#define V2024 (V + 6227)
+ 0x6d, 0x2215, 0x73, 0,
+#undef V2025
+#define V2025 (V + 6231)
+ 0x6d, 0x2215, 0x73, 0x32, 0,
+#undef V2026
+#define V2026 (V + 6236)
+ 0x50, 0x61, 0,
+#undef V2027
+#define V2027 (V + 6239)
+ 0x6b, 0x50, 0x61, 0,
+#undef V2028
+#define V2028 (V + 6243)
+ 0x4d, 0x50, 0x61, 0,
+#undef V2029
+#define V2029 (V + 6247)
+ 0x47, 0x50, 0x61, 0,
+#undef V2030
+#define V2030 (V + 6251)
+ 0x72, 0x61, 0x64, 0,
+#undef V2031
+#define V2031 (V + 6255)
+ 0x72, 0x61, 0x64, 0x2215, 0x73, 0,
+#undef V2032
+#define V2032 (V + 6261)
+ 0x72, 0x61, 0x64, 0x2215, 0x73, 0x32, 0,
+#undef V2033
+#define V2033 (V + 6268)
+ 0x70, 0x73, 0,
+#undef V2034
+#define V2034 (V + 6271)
+ 0x6e, 0x73, 0,
+#undef V2035
+#define V2035 (V + 6274)
+ 0x3bc, 0x73, 0,
+#undef V2036
+#define V2036 (V + 6277)
+ 0x6d, 0x73, 0,
+#undef V2037
+#define V2037 (V + 6280)
+ 0x70, 0x56, 0,
+#undef V2038
+#define V2038 (V + 6283)
+ 0x6e, 0x56, 0,
+#undef V2039
+#define V2039 (V + 6286)
+ 0x3bc, 0x56, 0,
+#undef V2040
+#define V2040 (V + 6289)
+ 0x6d, 0x56, 0,
+#undef V2041
+#define V2041 (V + 6292)
+ 0x6b, 0x56, 0,
+#undef V2042
+#define V2042 (V + 6295)
+ 0x4d, 0x56, 0,
+#undef V2043
+#define V2043 (V + 6298)
+ 0x70, 0x57, 0,
+#undef V2044
+#define V2044 (V + 6301)
+ 0x6e, 0x57, 0,
+#undef V2045
+#define V2045 (V + 6304)
+ 0x3bc, 0x57, 0,
+#undef V2046
+#define V2046 (V + 6307)
+ 0x6d, 0x57, 0,
+#undef V2047
+#define V2047 (V + 6310)
+ 0x6b, 0x57, 0,
+#undef V2048
+#define V2048 (V + 6313)
+ 0x4d, 0x57, 0,
+#undef V2049
+#define V2049 (V + 6316)
+ 0x6b, 0x3a9, 0,
+#undef V2050
+#define V2050 (V + 6319)
+ 0x4d, 0x3a9, 0,
+#undef V2051
+#define V2051 (V + 6322)
+ 0x61, 0x2e, 0x6d, 0x2e, 0,
+#undef V2052
+#define V2052 (V + 6327)
+ 0x42, 0x71, 0,
+#undef V2053
+#define V2053 (V + 6330)
+ 0x63, 0x63, 0,
+#undef V2054
+#define V2054 (V + 6333)
+ 0x63, 0x64, 0,
+#undef V2055
+#define V2055 (V + 6336)
+ 0x43, 0x2215, 0x6b, 0x67, 0,
+#undef V2056
+#define V2056 (V + 6341)
+ 0x43, 0x6f, 0x2e, 0,
+#undef V2057
+#define V2057 (V + 6345)
+ 0x64, 0x42, 0,
+#undef V2058
+#define V2058 (V + 6348)
+ 0x47, 0x79, 0,
+#undef V2059
+#define V2059 (V + 6351)
+ 0x68, 0x61, 0,
+#undef V2060
+#define V2060 (V + 6354)
+ 0x48, 0x50, 0,
+#undef V2061
+#define V2061 (V + 6357)
+ 0x69, 0x6e, 0,
+#undef V2062
+#define V2062 (V + 6360)
+ 0x4b, 0x4b, 0,
+#undef V2063
+#define V2063 (V + 6363)
+ 0x4b, 0x4d, 0,
+#undef V2064
+#define V2064 (V + 6366)
+ 0x6b, 0x74, 0,
+#undef V2065
+#define V2065 (V + 6369)
+ 0x6c, 0x6d, 0,
+#undef V2066
+#define V2066 (V + 6372)
+ 0x6c, 0x6e, 0,
+#undef V2067
+#define V2067 (V + 6375)
+ 0x6c, 0x6f, 0x67, 0,
+#undef V2068
+#define V2068 (V + 6379)
+ 0x6c, 0x78, 0,
+#undef V2069
+#define V2069 (V + 6382)
+ 0x6d, 0x62, 0,
+#undef V2070
+#define V2070 (V + 6385)
+ 0x6d, 0x69, 0x6c, 0,
+#undef V2071
+#define V2071 (V + 6389)
+ 0x6d, 0x6f, 0x6c, 0,
+#undef V2072
+#define V2072 (V + 6393)
+ 0x50, 0x48, 0,
+#undef V2073
+#define V2073 (V + 6396)
+ 0x70, 0x2e, 0x6d, 0x2e, 0,
+#undef V2074
+#define V2074 (V + 6401)
+ 0x50, 0x50, 0x4d, 0,
+#undef V2075
+#define V2075 (V + 6405)
+ 0x50, 0x52, 0,
+#undef V2076
+#define V2076 (V + 6408)
+ 0x73, 0x72, 0,
+#undef V2077
+#define V2077 (V + 6411)
+ 0x53, 0x76, 0,
+#undef V2078
+#define V2078 (V + 6414)
+ 0x57, 0x62, 0,
+#undef V2079
+#define V2079 (V + 6417)
+ 0x56, 0x2215, 0x6d, 0,
+#undef V2080
+#define V2080 (V + 6421)
+ 0x41, 0x2215, 0x6d, 0,
+#undef V2081
+#define V2081 (V + 6425)
+ 0x31, 0x65e5, 0,
+#undef V2082
+#define V2082 (V + 6428)
+ 0x32, 0x65e5, 0,
+#undef V2083
+#define V2083 (V + 6431)
+ 0x33, 0x65e5, 0,
+#undef V2084
+#define V2084 (V + 6434)
+ 0x34, 0x65e5, 0,
+#undef V2085
+#define V2085 (V + 6437)
+ 0x35, 0x65e5, 0,
+#undef V2086
+#define V2086 (V + 6440)
+ 0x36, 0x65e5, 0,
+#undef V2087
+#define V2087 (V + 6443)
+ 0x37, 0x65e5, 0,
+#undef V2088
+#define V2088 (V + 6446)
+ 0x38, 0x65e5, 0,
+#undef V2089
+#define V2089 (V + 6449)
+ 0x39, 0x65e5, 0,
+#undef V2090
+#define V2090 (V + 6452)
+ 0x31, 0x30, 0x65e5, 0,
+#undef V2091
+#define V2091 (V + 6456)
+ 0x31, 0x31, 0x65e5, 0,
+#undef V2092
+#define V2092 (V + 6460)
+ 0x31, 0x32, 0x65e5, 0,
+#undef V2093
+#define V2093 (V + 6464)
+ 0x31, 0x33, 0x65e5, 0,
+#undef V2094
+#define V2094 (V + 6468)
+ 0x31, 0x34, 0x65e5, 0,
+#undef V2095
+#define V2095 (V + 6472)
+ 0x31, 0x35, 0x65e5, 0,
+#undef V2096
+#define V2096 (V + 6476)
+ 0x31, 0x36, 0x65e5, 0,
+#undef V2097
+#define V2097 (V + 6480)
+ 0x31, 0x37, 0x65e5, 0,
+#undef V2098
+#define V2098 (V + 6484)
+ 0x31, 0x38, 0x65e5, 0,
+#undef V2099
+#define V2099 (V + 6488)
+ 0x31, 0x39, 0x65e5, 0,
+#undef V2100
+#define V2100 (V + 6492)
+ 0x32, 0x30, 0x65e5, 0,
+#undef V2101
+#define V2101 (V + 6496)
+ 0x32, 0x31, 0x65e5, 0,
+#undef V2102
+#define V2102 (V + 6500)
+ 0x32, 0x32, 0x65e5, 0,
+#undef V2103
+#define V2103 (V + 6504)
+ 0x32, 0x33, 0x65e5, 0,
+#undef V2104
+#define V2104 (V + 6508)
+ 0x32, 0x34, 0x65e5, 0,
+#undef V2105
+#define V2105 (V + 6512)
+ 0x32, 0x35, 0x65e5, 0,
+#undef V2106
+#define V2106 (V + 6516)
+ 0x32, 0x36, 0x65e5, 0,
+#undef V2107
+#define V2107 (V + 6520)
+ 0x32, 0x37, 0x65e5, 0,
+#undef V2108
+#define V2108 (V + 6524)
+ 0x32, 0x38, 0x65e5, 0,
+#undef V2109
+#define V2109 (V + 6528)
+ 0x32, 0x39, 0x65e5, 0,
+#undef V2110
+#define V2110 (V + 6532)
+ 0x33, 0x30, 0x65e5, 0,
+#undef V2111
+#define V2111 (V + 6536)
+ 0x33, 0x31, 0x65e5, 0,
+#undef V2112
+#define V2112 (V + 6540)
+ 0x67, 0x61, 0x6c, 0,
+#undef V2113
+#define V2113 (V + 6544)
+ 0x44a, 0,
+#undef V2114
+#define V2114 (V + 6546)
+ 0x44c, 0,
+#undef V2115
+#define V2115 (V + 6548)
+ 0xa76f, 0,
+#undef V2116
+#define V2116 (V + 6550)
+ 0x126, 0,
+#undef V2117
+#define V2117 (V + 6552)
+ 0x153, 0,
+#undef V2118
+#define V2118 (V + 6554)
+ 0xa727, 0,
+#undef V2119
+#define V2119 (V + 6556)
+ 0xab37, 0,
+#undef V2120
+#define V2120 (V + 6558)
+ 0x26b, 0,
+#undef V2121
+#define V2121 (V + 6560)
+ 0xab52, 0,
+#undef V2122
+#define V2122 (V + 6562)
+ 0x1100, 0x1161, 0x11a8, 0,
+#undef V2123
+#define V2123 (V + 6566)
+ 0x1100, 0x1161, 0x11a9, 0,
+#undef V2124
+#define V2124 (V + 6570)
+ 0x1100, 0x1161, 0x11aa, 0,
+#undef V2125
+#define V2125 (V + 6574)
+ 0x1100, 0x1161, 0x11ab, 0,
+#undef V2126
+#define V2126 (V + 6578)
+ 0x1100, 0x1161, 0x11ac, 0,
+#undef V2127
+#define V2127 (V + 6582)
+ 0x1100, 0x1161, 0x11ad, 0,
+#undef V2128
+#define V2128 (V + 6586)
+ 0x1100, 0x1161, 0x11ae, 0,
+#undef V2129
+#define V2129 (V + 6590)
+ 0x1100, 0x1161, 0x11af, 0,
+#undef V2130
+#define V2130 (V + 6594)
+ 0x1100, 0x1161, 0x11b0, 0,
+#undef V2131
+#define V2131 (V + 6598)
+ 0x1100, 0x1161, 0x11b1, 0,
+#undef V2132
+#define V2132 (V + 6602)
+ 0x1100, 0x1161, 0x11b2, 0,
+#undef V2133
+#define V2133 (V + 6606)
+ 0x1100, 0x1161, 0x11b3, 0,
+#undef V2134
+#define V2134 (V + 6610)
+ 0x1100, 0x1161, 0x11b4, 0,
+#undef V2135
+#define V2135 (V + 6614)
+ 0x1100, 0x1161, 0x11b5, 0,
+#undef V2136
+#define V2136 (V + 6618)
+ 0x1100, 0x1161, 0x11b6, 0,
+#undef V2137
+#define V2137 (V + 6622)
+ 0x1100, 0x1161, 0x11b7, 0,
+#undef V2138
+#define V2138 (V + 6626)
+ 0x1100, 0x1161, 0x11b8, 0,
+#undef V2139
+#define V2139 (V + 6630)
+ 0x1100, 0x1161, 0x11b9, 0,
+#undef V2140
+#define V2140 (V + 6634)
+ 0x1100, 0x1161, 0x11ba, 0,
+#undef V2141
+#define V2141 (V + 6638)
+ 0x1100, 0x1161, 0x11bb, 0,
+#undef V2142
+#define V2142 (V + 6642)
+ 0x1100, 0x1161, 0x11bc, 0,
+#undef V2143
+#define V2143 (V + 6646)
+ 0x1100, 0x1161, 0x11bd, 0,
+#undef V2144
+#define V2144 (V + 6650)
+ 0x1100, 0x1161, 0x11be, 0,
+#undef V2145
+#define V2145 (V + 6654)
+ 0x1100, 0x1161, 0x11bf, 0,
+#undef V2146
+#define V2146 (V + 6658)
+ 0x1100, 0x1161, 0x11c0, 0,
+#undef V2147
+#define V2147 (V + 6662)
+ 0x1100, 0x1161, 0x11c1, 0,
+#undef V2148
+#define V2148 (V + 6666)
+ 0x1100, 0x1161, 0x11c2, 0,
+#undef V2149
+#define V2149 (V + 6670)
+ 0x1100, 0x1162, 0,
+#undef V2150
+#define V2150 (V + 6673)
+ 0x1100, 0x1162, 0x11a8, 0,
+#undef V2151
+#define V2151 (V + 6677)
+ 0x1100, 0x1162, 0x11a9, 0,
+#undef V2152
+#define V2152 (V + 6681)
+ 0x1100, 0x1162, 0x11aa, 0,
+#undef V2153
+#define V2153 (V + 6685)
+ 0x1100, 0x1162, 0x11ab, 0,
+#undef V2154
+#define V2154 (V + 6689)
+ 0x1100, 0x1162, 0x11ac, 0,
+#undef V2155
+#define V2155 (V + 6693)
+ 0x1100, 0x1162, 0x11ad, 0,
+#undef V2156
+#define V2156 (V + 6697)
+ 0x1100, 0x1162, 0x11ae, 0,
+#undef V2157
+#define V2157 (V + 6701)
+ 0x1100, 0x1162, 0x11af, 0,
+#undef V2158
+#define V2158 (V + 6705)
+ 0x1100, 0x1162, 0x11b0, 0,
+#undef V2159
+#define V2159 (V + 6709)
+ 0x1100, 0x1162, 0x11b1, 0,
+#undef V2160
+#define V2160 (V + 6713)
+ 0x1100, 0x1162, 0x11b2, 0,
+#undef V2161
+#define V2161 (V + 6717)
+ 0x1100, 0x1162, 0x11b3, 0,
+#undef V2162
+#define V2162 (V + 6721)
+ 0x1100, 0x1162, 0x11b4, 0,
+#undef V2163
+#define V2163 (V + 6725)
+ 0x1100, 0x1162, 0x11b5, 0,
+#undef V2164
+#define V2164 (V + 6729)
+ 0x1100, 0x1162, 0x11b6, 0,
+#undef V2165
+#define V2165 (V + 6733)
+ 0x1100, 0x1162, 0x11b7, 0,
+#undef V2166
+#define V2166 (V + 6737)
+ 0x1100, 0x1162, 0x11b8, 0,
+#undef V2167
+#define V2167 (V + 6741)
+ 0x1100, 0x1162, 0x11b9, 0,
+#undef V2168
+#define V2168 (V + 6745)
+ 0x1100, 0x1162, 0x11ba, 0,
+#undef V2169
+#define V2169 (V + 6749)
+ 0x1100, 0x1162, 0x11bb, 0,
+#undef V2170
+#define V2170 (V + 6753)
+ 0x1100, 0x1162, 0x11bc, 0,
+#undef V2171
+#define V2171 (V + 6757)
+ 0x1100, 0x1162, 0x11bd, 0,
+#undef V2172
+#define V2172 (V + 6761)
+ 0x1100, 0x1162, 0x11be, 0,
+#undef V2173
+#define V2173 (V + 6765)
+ 0x1100, 0x1162, 0x11bf, 0,
+#undef V2174
+#define V2174 (V + 6769)
+ 0x1100, 0x1162, 0x11c0, 0,
+#undef V2175
+#define V2175 (V + 6773)
+ 0x1100, 0x1162, 0x11c1, 0,
+#undef V2176
+#define V2176 (V + 6777)
+ 0x1100, 0x1162, 0x11c2, 0,
+#undef V2177
+#define V2177 (V + 6781)
+ 0x1100, 0x1163, 0,
+#undef V2178
+#define V2178 (V + 6784)
+ 0x1100, 0x1163, 0x11a8, 0,
+#undef V2179
+#define V2179 (V + 6788)
+ 0x1100, 0x1163, 0x11a9, 0,
+#undef V2180
+#define V2180 (V + 6792)
+ 0x1100, 0x1163, 0x11aa, 0,
+#undef V2181
+#define V2181 (V + 6796)
+ 0x1100, 0x1163, 0x11ab, 0,
+#undef V2182
+#define V2182 (V + 6800)
+ 0x1100, 0x1163, 0x11ac, 0,
+#undef V2183
+#define V2183 (V + 6804)
+ 0x1100, 0x1163, 0x11ad, 0,
+#undef V2184
+#define V2184 (V + 6808)
+ 0x1100, 0x1163, 0x11ae, 0,
+#undef V2185
+#define V2185 (V + 6812)
+ 0x1100, 0x1163, 0x11af, 0,
+#undef V2186
+#define V2186 (V + 6816)
+ 0x1100, 0x1163, 0x11b0, 0,
+#undef V2187
+#define V2187 (V + 6820)
+ 0x1100, 0x1163, 0x11b1, 0,
+#undef V2188
+#define V2188 (V + 6824)
+ 0x1100, 0x1163, 0x11b2, 0,
+#undef V2189
+#define V2189 (V + 6828)
+ 0x1100, 0x1163, 0x11b3, 0,
+#undef V2190
+#define V2190 (V + 6832)
+ 0x1100, 0x1163, 0x11b4, 0,
+#undef V2191
+#define V2191 (V + 6836)
+ 0x1100, 0x1163, 0x11b5, 0,
+#undef V2192
+#define V2192 (V + 6840)
+ 0x1100, 0x1163, 0x11b6, 0,
+#undef V2193
+#define V2193 (V + 6844)
+ 0x1100, 0x1163, 0x11b7, 0,
+#undef V2194
+#define V2194 (V + 6848)
+ 0x1100, 0x1163, 0x11b8, 0,
+#undef V2195
+#define V2195 (V + 6852)
+ 0x1100, 0x1163, 0x11b9, 0,
+#undef V2196
+#define V2196 (V + 6856)
+ 0x1100, 0x1163, 0x11ba, 0,
+#undef V2197
+#define V2197 (V + 6860)
+ 0x1100, 0x1163, 0x11bb, 0,
+#undef V2198
+#define V2198 (V + 6864)
+ 0x1100, 0x1163, 0x11bc, 0,
+#undef V2199
+#define V2199 (V + 6868)
+ 0x1100, 0x1163, 0x11bd, 0,
+#undef V2200
+#define V2200 (V + 6872)
+ 0x1100, 0x1163, 0x11be, 0,
+#undef V2201
+#define V2201 (V + 6876)
+ 0x1100, 0x1163, 0x11bf, 0,
+#undef V2202
+#define V2202 (V + 6880)
+ 0x1100, 0x1163, 0x11c0, 0,
+#undef V2203
+#define V2203 (V + 6884)
+ 0x1100, 0x1163, 0x11c1, 0,
+#undef V2204
+#define V2204 (V + 6888)
+ 0x1100, 0x1163, 0x11c2, 0,
+#undef V2205
+#define V2205 (V + 6892)
+ 0x1100, 0x1164, 0,
+#undef V2206
+#define V2206 (V + 6895)
+ 0x1100, 0x1164, 0x11a8, 0,
+#undef V2207
+#define V2207 (V + 6899)
+ 0x1100, 0x1164, 0x11a9, 0,
+#undef V2208
+#define V2208 (V + 6903)
+ 0x1100, 0x1164, 0x11aa, 0,
+#undef V2209
+#define V2209 (V + 6907)
+ 0x1100, 0x1164, 0x11ab, 0,
+#undef V2210
+#define V2210 (V + 6911)
+ 0x1100, 0x1164, 0x11ac, 0,
+#undef V2211
+#define V2211 (V + 6915)
+ 0x1100, 0x1164, 0x11ad, 0,
+#undef V2212
+#define V2212 (V + 6919)
+ 0x1100, 0x1164, 0x11ae, 0,
+#undef V2213
+#define V2213 (V + 6923)
+ 0x1100, 0x1164, 0x11af, 0,
+#undef V2214
+#define V2214 (V + 6927)
+ 0x1100, 0x1164, 0x11b0, 0,
+#undef V2215
+#define V2215 (V + 6931)
+ 0x1100, 0x1164, 0x11b1, 0,
+#undef V2216
+#define V2216 (V + 6935)
+ 0x1100, 0x1164, 0x11b2, 0,
+#undef V2217
+#define V2217 (V + 6939)
+ 0x1100, 0x1164, 0x11b3, 0,
+#undef V2218
+#define V2218 (V + 6943)
+ 0x1100, 0x1164, 0x11b4, 0,
+#undef V2219
+#define V2219 (V + 6947)
+ 0x1100, 0x1164, 0x11b5, 0,
+#undef V2220
+#define V2220 (V + 6951)
+ 0x1100, 0x1164, 0x11b6, 0,
+#undef V2221
+#define V2221 (V + 6955)
+ 0x1100, 0x1164, 0x11b7, 0,
+#undef V2222
+#define V2222 (V + 6959)
+ 0x1100, 0x1164, 0x11b8, 0,
+#undef V2223
+#define V2223 (V + 6963)
+ 0x1100, 0x1164, 0x11b9, 0,
+#undef V2224
+#define V2224 (V + 6967)
+ 0x1100, 0x1164, 0x11ba, 0,
+#undef V2225
+#define V2225 (V + 6971)
+ 0x1100, 0x1164, 0x11bb, 0,
+#undef V2226
+#define V2226 (V + 6975)
+ 0x1100, 0x1164, 0x11bc, 0,
+#undef V2227
+#define V2227 (V + 6979)
+ 0x1100, 0x1164, 0x11bd, 0,
+#undef V2228
+#define V2228 (V + 6983)
+ 0x1100, 0x1164, 0x11be, 0,
+#undef V2229
+#define V2229 (V + 6987)
+ 0x1100, 0x1164, 0x11bf, 0,
+#undef V2230
+#define V2230 (V + 6991)
+ 0x1100, 0x1164, 0x11c0, 0,
+#undef V2231
+#define V2231 (V + 6995)
+ 0x1100, 0x1164, 0x11c1, 0,
+#undef V2232
+#define V2232 (V + 6999)
+ 0x1100, 0x1164, 0x11c2, 0,
+#undef V2233
+#define V2233 (V + 7003)
+ 0x1100, 0x1165, 0,
+#undef V2234
+#define V2234 (V + 7006)
+ 0x1100, 0x1165, 0x11a8, 0,
+#undef V2235
+#define V2235 (V + 7010)
+ 0x1100, 0x1165, 0x11a9, 0,
+#undef V2236
+#define V2236 (V + 7014)
+ 0x1100, 0x1165, 0x11aa, 0,
+#undef V2237
+#define V2237 (V + 7018)
+ 0x1100, 0x1165, 0x11ab, 0,
+#undef V2238
+#define V2238 (V + 7022)
+ 0x1100, 0x1165, 0x11ac, 0,
+#undef V2239
+#define V2239 (V + 7026)
+ 0x1100, 0x1165, 0x11ad, 0,
+#undef V2240
+#define V2240 (V + 7030)
+ 0x1100, 0x1165, 0x11ae, 0,
+#undef V2241
+#define V2241 (V + 7034)
+ 0x1100, 0x1165, 0x11af, 0,
+#undef V2242
+#define V2242 (V + 7038)
+ 0x1100, 0x1165, 0x11b0, 0,
+#undef V2243
+#define V2243 (V + 7042)
+ 0x1100, 0x1165, 0x11b1, 0,
+#undef V2244
+#define V2244 (V + 7046)
+ 0x1100, 0x1165, 0x11b2, 0,
+#undef V2245
+#define V2245 (V + 7050)
+ 0x1100, 0x1165, 0x11b3, 0,
+#undef V2246
+#define V2246 (V + 7054)
+ 0x1100, 0x1165, 0x11b4, 0,
+#undef V2247
+#define V2247 (V + 7058)
+ 0x1100, 0x1165, 0x11b5, 0,
+#undef V2248
+#define V2248 (V + 7062)
+ 0x1100, 0x1165, 0x11b6, 0,
+#undef V2249
+#define V2249 (V + 7066)
+ 0x1100, 0x1165, 0x11b7, 0,
+#undef V2250
+#define V2250 (V + 7070)
+ 0x1100, 0x1165, 0x11b8, 0,
+#undef V2251
+#define V2251 (V + 7074)
+ 0x1100, 0x1165, 0x11b9, 0,
+#undef V2252
+#define V2252 (V + 7078)
+ 0x1100, 0x1165, 0x11ba, 0,
+#undef V2253
+#define V2253 (V + 7082)
+ 0x1100, 0x1165, 0x11bb, 0,
+#undef V2254
+#define V2254 (V + 7086)
+ 0x1100, 0x1165, 0x11bc, 0,
+#undef V2255
+#define V2255 (V + 7090)
+ 0x1100, 0x1165, 0x11bd, 0,
+#undef V2256
+#define V2256 (V + 7094)
+ 0x1100, 0x1165, 0x11be, 0,
+#undef V2257
+#define V2257 (V + 7098)
+ 0x1100, 0x1165, 0x11bf, 0,
+#undef V2258
+#define V2258 (V + 7102)
+ 0x1100, 0x1165, 0x11c0, 0,
+#undef V2259
+#define V2259 (V + 7106)
+ 0x1100, 0x1165, 0x11c1, 0,
+#undef V2260
+#define V2260 (V + 7110)
+ 0x1100, 0x1165, 0x11c2, 0,
+#undef V2261
+#define V2261 (V + 7114)
+ 0x1100, 0x1166, 0,
+#undef V2262
+#define V2262 (V + 7117)
+ 0x1100, 0x1166, 0x11a8, 0,
+#undef V2263
+#define V2263 (V + 7121)
+ 0x1100, 0x1166, 0x11a9, 0,
+#undef V2264
+#define V2264 (V + 7125)
+ 0x1100, 0x1166, 0x11aa, 0,
+#undef V2265
+#define V2265 (V + 7129)
+ 0x1100, 0x1166, 0x11ab, 0,
+#undef V2266
+#define V2266 (V + 7133)
+ 0x1100, 0x1166, 0x11ac, 0,
+#undef V2267
+#define V2267 (V + 7137)
+ 0x1100, 0x1166, 0x11ad, 0,
+#undef V2268
+#define V2268 (V + 7141)
+ 0x1100, 0x1166, 0x11ae, 0,
+#undef V2269
+#define V2269 (V + 7145)
+ 0x1100, 0x1166, 0x11af, 0,
+#undef V2270
+#define V2270 (V + 7149)
+ 0x1100, 0x1166, 0x11b0, 0,
+#undef V2271
+#define V2271 (V + 7153)
+ 0x1100, 0x1166, 0x11b1, 0,
+#undef V2272
+#define V2272 (V + 7157)
+ 0x1100, 0x1166, 0x11b2, 0,
+#undef V2273
+#define V2273 (V + 7161)
+ 0x1100, 0x1166, 0x11b3, 0,
+#undef V2274
+#define V2274 (V + 7165)
+ 0x1100, 0x1166, 0x11b4, 0,
+#undef V2275
+#define V2275 (V + 7169)
+ 0x1100, 0x1166, 0x11b5, 0,
+#undef V2276
+#define V2276 (V + 7173)
+ 0x1100, 0x1166, 0x11b6, 0,
+#undef V2277
+#define V2277 (V + 7177)
+ 0x1100, 0x1166, 0x11b7, 0,
+#undef V2278
+#define V2278 (V + 7181)
+ 0x1100, 0x1166, 0x11b8, 0,
+#undef V2279
+#define V2279 (V + 7185)
+ 0x1100, 0x1166, 0x11b9, 0,
+#undef V2280
+#define V2280 (V + 7189)
+ 0x1100, 0x1166, 0x11ba, 0,
+#undef V2281
+#define V2281 (V + 7193)
+ 0x1100, 0x1166, 0x11bb, 0,
+#undef V2282
+#define V2282 (V + 7197)
+ 0x1100, 0x1166, 0x11bc, 0,
+#undef V2283
+#define V2283 (V + 7201)
+ 0x1100, 0x1166, 0x11bd, 0,
+#undef V2284
+#define V2284 (V + 7205)
+ 0x1100, 0x1166, 0x11be, 0,
+#undef V2285
+#define V2285 (V + 7209)
+ 0x1100, 0x1166, 0x11bf, 0,
+#undef V2286
+#define V2286 (V + 7213)
+ 0x1100, 0x1166, 0x11c0, 0,
+#undef V2287
+#define V2287 (V + 7217)
+ 0x1100, 0x1166, 0x11c1, 0,
+#undef V2288
+#define V2288 (V + 7221)
+ 0x1100, 0x1166, 0x11c2, 0,
+#undef V2289
+#define V2289 (V + 7225)
+ 0x1100, 0x1167, 0,
+#undef V2290
+#define V2290 (V + 7228)
+ 0x1100, 0x1167, 0x11a8, 0,
+#undef V2291
+#define V2291 (V + 7232)
+ 0x1100, 0x1167, 0x11a9, 0,
+#undef V2292
+#define V2292 (V + 7236)
+ 0x1100, 0x1167, 0x11aa, 0,
+#undef V2293
+#define V2293 (V + 7240)
+ 0x1100, 0x1167, 0x11ab, 0,
+#undef V2294
+#define V2294 (V + 7244)
+ 0x1100, 0x1167, 0x11ac, 0,
+#undef V2295
+#define V2295 (V + 7248)
+ 0x1100, 0x1167, 0x11ad, 0,
+#undef V2296
+#define V2296 (V + 7252)
+ 0x1100, 0x1167, 0x11ae, 0,
+#undef V2297
+#define V2297 (V + 7256)
+ 0x1100, 0x1167, 0x11af, 0,
+#undef V2298
+#define V2298 (V + 7260)
+ 0x1100, 0x1167, 0x11b0, 0,
+#undef V2299
+#define V2299 (V + 7264)
+ 0x1100, 0x1167, 0x11b1, 0,
+#undef V2300
+#define V2300 (V + 7268)
+ 0x1100, 0x1167, 0x11b2, 0,
+#undef V2301
+#define V2301 (V + 7272)
+ 0x1100, 0x1167, 0x11b3, 0,
+#undef V2302
+#define V2302 (V + 7276)
+ 0x1100, 0x1167, 0x11b4, 0,
+#undef V2303
+#define V2303 (V + 7280)
+ 0x1100, 0x1167, 0x11b5, 0,
+#undef V2304
+#define V2304 (V + 7284)
+ 0x1100, 0x1167, 0x11b6, 0,
+#undef V2305
+#define V2305 (V + 7288)
+ 0x1100, 0x1167, 0x11b7, 0,
+#undef V2306
+#define V2306 (V + 7292)
+ 0x1100, 0x1167, 0x11b8, 0,
+#undef V2307
+#define V2307 (V + 7296)
+ 0x1100, 0x1167, 0x11b9, 0,
+#undef V2308
+#define V2308 (V + 7300)
+ 0x1100, 0x1167, 0x11ba, 0,
+#undef V2309
+#define V2309 (V + 7304)
+ 0x1100, 0x1167, 0x11bb, 0,
+#undef V2310
+#define V2310 (V + 7308)
+ 0x1100, 0x1167, 0x11bc, 0,
+#undef V2311
+#define V2311 (V + 7312)
+ 0x1100, 0x1167, 0x11bd, 0,
+#undef V2312
+#define V2312 (V + 7316)
+ 0x1100, 0x1167, 0x11be, 0,
+#undef V2313
+#define V2313 (V + 7320)
+ 0x1100, 0x1167, 0x11bf, 0,
+#undef V2314
+#define V2314 (V + 7324)
+ 0x1100, 0x1167, 0x11c0, 0,
+#undef V2315
+#define V2315 (V + 7328)
+ 0x1100, 0x1167, 0x11c1, 0,
+#undef V2316
+#define V2316 (V + 7332)
+ 0x1100, 0x1167, 0x11c2, 0,
+#undef V2317
+#define V2317 (V + 7336)
+ 0x1100, 0x1168, 0,
+#undef V2318
+#define V2318 (V + 7339)
+ 0x1100, 0x1168, 0x11a8, 0,
+#undef V2319
+#define V2319 (V + 7343)
+ 0x1100, 0x1168, 0x11a9, 0,
+#undef V2320
+#define V2320 (V + 7347)
+ 0x1100, 0x1168, 0x11aa, 0,
+#undef V2321
+#define V2321 (V + 7351)
+ 0x1100, 0x1168, 0x11ab, 0,
+#undef V2322
+#define V2322 (V + 7355)
+ 0x1100, 0x1168, 0x11ac, 0,
+#undef V2323
+#define V2323 (V + 7359)
+ 0x1100, 0x1168, 0x11ad, 0,
+#undef V2324
+#define V2324 (V + 7363)
+ 0x1100, 0x1168, 0x11ae, 0,
+#undef V2325
+#define V2325 (V + 7367)
+ 0x1100, 0x1168, 0x11af, 0,
+#undef V2326
+#define V2326 (V + 7371)
+ 0x1100, 0x1168, 0x11b0, 0,
+#undef V2327
+#define V2327 (V + 7375)
+ 0x1100, 0x1168, 0x11b1, 0,
+#undef V2328
+#define V2328 (V + 7379)
+ 0x1100, 0x1168, 0x11b2, 0,
+#undef V2329
+#define V2329 (V + 7383)
+ 0x1100, 0x1168, 0x11b3, 0,
+#undef V2330
+#define V2330 (V + 7387)
+ 0x1100, 0x1168, 0x11b4, 0,
+#undef V2331
+#define V2331 (V + 7391)
+ 0x1100, 0x1168, 0x11b5, 0,
+#undef V2332
+#define V2332 (V + 7395)
+ 0x1100, 0x1168, 0x11b6, 0,
+#undef V2333
+#define V2333 (V + 7399)
+ 0x1100, 0x1168, 0x11b7, 0,
+#undef V2334
+#define V2334 (V + 7403)
+ 0x1100, 0x1168, 0x11b8, 0,
+#undef V2335
+#define V2335 (V + 7407)
+ 0x1100, 0x1168, 0x11b9, 0,
+#undef V2336
+#define V2336 (V + 7411)
+ 0x1100, 0x1168, 0x11ba, 0,
+#undef V2337
+#define V2337 (V + 7415)
+ 0x1100, 0x1168, 0x11bb, 0,
+#undef V2338
+#define V2338 (V + 7419)
+ 0x1100, 0x1168, 0x11bc, 0,
+#undef V2339
+#define V2339 (V + 7423)
+ 0x1100, 0x1168, 0x11bd, 0,
+#undef V2340
+#define V2340 (V + 7427)
+ 0x1100, 0x1168, 0x11be, 0,
+#undef V2341
+#define V2341 (V + 7431)
+ 0x1100, 0x1168, 0x11bf, 0,
+#undef V2342
+#define V2342 (V + 7435)
+ 0x1100, 0x1168, 0x11c0, 0,
+#undef V2343
+#define V2343 (V + 7439)
+ 0x1100, 0x1168, 0x11c1, 0,
+#undef V2344
+#define V2344 (V + 7443)
+ 0x1100, 0x1168, 0x11c2, 0,
+#undef V2345
+#define V2345 (V + 7447)
+ 0x1100, 0x1169, 0,
+#undef V2346
+#define V2346 (V + 7450)
+ 0x1100, 0x1169, 0x11a8, 0,
+#undef V2347
+#define V2347 (V + 7454)
+ 0x1100, 0x1169, 0x11a9, 0,
+#undef V2348
+#define V2348 (V + 7458)
+ 0x1100, 0x1169, 0x11aa, 0,
+#undef V2349
+#define V2349 (V + 7462)
+ 0x1100, 0x1169, 0x11ab, 0,
+#undef V2350
+#define V2350 (V + 7466)
+ 0x1100, 0x1169, 0x11ac, 0,
+#undef V2351
+#define V2351 (V + 7470)
+ 0x1100, 0x1169, 0x11ad, 0,
+#undef V2352
+#define V2352 (V + 7474)
+ 0x1100, 0x1169, 0x11ae, 0,
+#undef V2353
+#define V2353 (V + 7478)
+ 0x1100, 0x1169, 0x11af, 0,
+#undef V2354
+#define V2354 (V + 7482)
+ 0x1100, 0x1169, 0x11b0, 0,
+#undef V2355
+#define V2355 (V + 7486)
+ 0x1100, 0x1169, 0x11b1, 0,
+#undef V2356
+#define V2356 (V + 7490)
+ 0x1100, 0x1169, 0x11b2, 0,
+#undef V2357
+#define V2357 (V + 7494)
+ 0x1100, 0x1169, 0x11b3, 0,
+#undef V2358
+#define V2358 (V + 7498)
+ 0x1100, 0x1169, 0x11b4, 0,
+#undef V2359
+#define V2359 (V + 7502)
+ 0x1100, 0x1169, 0x11b5, 0,
+#undef V2360
+#define V2360 (V + 7506)
+ 0x1100, 0x1169, 0x11b6, 0,
+#undef V2361
+#define V2361 (V + 7510)
+ 0x1100, 0x1169, 0x11b7, 0,
+#undef V2362
+#define V2362 (V + 7514)
+ 0x1100, 0x1169, 0x11b8, 0,
+#undef V2363
+#define V2363 (V + 7518)
+ 0x1100, 0x1169, 0x11b9, 0,
+#undef V2364
+#define V2364 (V + 7522)
+ 0x1100, 0x1169, 0x11ba, 0,
+#undef V2365
+#define V2365 (V + 7526)
+ 0x1100, 0x1169, 0x11bb, 0,
+#undef V2366
+#define V2366 (V + 7530)
+ 0x1100, 0x1169, 0x11bc, 0,
+#undef V2367
+#define V2367 (V + 7534)
+ 0x1100, 0x1169, 0x11bd, 0,
+#undef V2368
+#define V2368 (V + 7538)
+ 0x1100, 0x1169, 0x11be, 0,
+#undef V2369
+#define V2369 (V + 7542)
+ 0x1100, 0x1169, 0x11bf, 0,
+#undef V2370
+#define V2370 (V + 7546)
+ 0x1100, 0x1169, 0x11c0, 0,
+#undef V2371
+#define V2371 (V + 7550)
+ 0x1100, 0x1169, 0x11c1, 0,
+#undef V2372
+#define V2372 (V + 7554)
+ 0x1100, 0x1169, 0x11c2, 0,
+#undef V2373
+#define V2373 (V + 7558)
+ 0x1100, 0x116a, 0,
+#undef V2374
+#define V2374 (V + 7561)
+ 0x1100, 0x116a, 0x11a8, 0,
+#undef V2375
+#define V2375 (V + 7565)
+ 0x1100, 0x116a, 0x11a9, 0,
+#undef V2376
+#define V2376 (V + 7569)
+ 0x1100, 0x116a, 0x11aa, 0,
+#undef V2377
+#define V2377 (V + 7573)
+ 0x1100, 0x116a, 0x11ab, 0,
+#undef V2378
+#define V2378 (V + 7577)
+ 0x1100, 0x116a, 0x11ac, 0,
+#undef V2379
+#define V2379 (V + 7581)
+ 0x1100, 0x116a, 0x11ad, 0,
+#undef V2380
+#define V2380 (V + 7585)
+ 0x1100, 0x116a, 0x11ae, 0,
+#undef V2381
+#define V2381 (V + 7589)
+ 0x1100, 0x116a, 0x11af, 0,
+#undef V2382
+#define V2382 (V + 7593)
+ 0x1100, 0x116a, 0x11b0, 0,
+#undef V2383
+#define V2383 (V + 7597)
+ 0x1100, 0x116a, 0x11b1, 0,
+#undef V2384
+#define V2384 (V + 7601)
+ 0x1100, 0x116a, 0x11b2, 0,
+#undef V2385
+#define V2385 (V + 7605)
+ 0x1100, 0x116a, 0x11b3, 0,
+#undef V2386
+#define V2386 (V + 7609)
+ 0x1100, 0x116a, 0x11b4, 0,
+#undef V2387
+#define V2387 (V + 7613)
+ 0x1100, 0x116a, 0x11b5, 0,
+#undef V2388
+#define V2388 (V + 7617)
+ 0x1100, 0x116a, 0x11b6, 0,
+#undef V2389
+#define V2389 (V + 7621)
+ 0x1100, 0x116a, 0x11b7, 0,
+#undef V2390
+#define V2390 (V + 7625)
+ 0x1100, 0x116a, 0x11b8, 0,
+#undef V2391
+#define V2391 (V + 7629)
+ 0x1100, 0x116a, 0x11b9, 0,
+#undef V2392
+#define V2392 (V + 7633)
+ 0x1100, 0x116a, 0x11ba, 0,
+#undef V2393
+#define V2393 (V + 7637)
+ 0x1100, 0x116a, 0x11bb, 0,
+#undef V2394
+#define V2394 (V + 7641)
+ 0x1100, 0x116a, 0x11bc, 0,
+#undef V2395
+#define V2395 (V + 7645)
+ 0x1100, 0x116a, 0x11bd, 0,
+#undef V2396
+#define V2396 (V + 7649)
+ 0x1100, 0x116a, 0x11be, 0,
+#undef V2397
+#define V2397 (V + 7653)
+ 0x1100, 0x116a, 0x11bf, 0,
+#undef V2398
+#define V2398 (V + 7657)
+ 0x1100, 0x116a, 0x11c0, 0,
+#undef V2399
+#define V2399 (V + 7661)
+ 0x1100, 0x116a, 0x11c1, 0,
+#undef V2400
+#define V2400 (V + 7665)
+ 0x1100, 0x116a, 0x11c2, 0,
+#undef V2401
+#define V2401 (V + 7669)
+ 0x1100, 0x116b, 0,
+#undef V2402
+#define V2402 (V + 7672)
+ 0x1100, 0x116b, 0x11a8, 0,
+#undef V2403
+#define V2403 (V + 7676)
+ 0x1100, 0x116b, 0x11a9, 0,
+#undef V2404
+#define V2404 (V + 7680)
+ 0x1100, 0x116b, 0x11aa, 0,
+#undef V2405
+#define V2405 (V + 7684)
+ 0x1100, 0x116b, 0x11ab, 0,
+#undef V2406
+#define V2406 (V + 7688)
+ 0x1100, 0x116b, 0x11ac, 0,
+#undef V2407
+#define V2407 (V + 7692)
+ 0x1100, 0x116b, 0x11ad, 0,
+#undef V2408
+#define V2408 (V + 7696)
+ 0x1100, 0x116b, 0x11ae, 0,
+#undef V2409
+#define V2409 (V + 7700)
+ 0x1100, 0x116b, 0x11af, 0,
+#undef V2410
+#define V2410 (V + 7704)
+ 0x1100, 0x116b, 0x11b0, 0,
+#undef V2411
+#define V2411 (V + 7708)
+ 0x1100, 0x116b, 0x11b1, 0,
+#undef V2412
+#define V2412 (V + 7712)
+ 0x1100, 0x116b, 0x11b2, 0,
+#undef V2413
+#define V2413 (V + 7716)
+ 0x1100, 0x116b, 0x11b3, 0,
+#undef V2414
+#define V2414 (V + 7720)
+ 0x1100, 0x116b, 0x11b4, 0,
+#undef V2415
+#define V2415 (V + 7724)
+ 0x1100, 0x116b, 0x11b5, 0,
+#undef V2416
+#define V2416 (V + 7728)
+ 0x1100, 0x116b, 0x11b6, 0,
+#undef V2417
+#define V2417 (V + 7732)
+ 0x1100, 0x116b, 0x11b7, 0,
+#undef V2418
+#define V2418 (V + 7736)
+ 0x1100, 0x116b, 0x11b8, 0,
+#undef V2419
+#define V2419 (V + 7740)
+ 0x1100, 0x116b, 0x11b9, 0,
+#undef V2420
+#define V2420 (V + 7744)
+ 0x1100, 0x116b, 0x11ba, 0,
+#undef V2421
+#define V2421 (V + 7748)
+ 0x1100, 0x116b, 0x11bb, 0,
+#undef V2422
+#define V2422 (V + 7752)
+ 0x1100, 0x116b, 0x11bc, 0,
+#undef V2423
+#define V2423 (V + 7756)
+ 0x1100, 0x116b, 0x11bd, 0,
+#undef V2424
+#define V2424 (V + 7760)
+ 0x1100, 0x116b, 0x11be, 0,
+#undef V2425
+#define V2425 (V + 7764)
+ 0x1100, 0x116b, 0x11bf, 0,
+#undef V2426
+#define V2426 (V + 7768)
+ 0x1100, 0x116b, 0x11c0, 0,
+#undef V2427
+#define V2427 (V + 7772)
+ 0x1100, 0x116b, 0x11c1, 0,
+#undef V2428
+#define V2428 (V + 7776)
+ 0x1100, 0x116b, 0x11c2, 0,
+#undef V2429
+#define V2429 (V + 7780)
+ 0x1100, 0x116c, 0,
+#undef V2430
+#define V2430 (V + 7783)
+ 0x1100, 0x116c, 0x11a8, 0,
+#undef V2431
+#define V2431 (V + 7787)
+ 0x1100, 0x116c, 0x11a9, 0,
+#undef V2432
+#define V2432 (V + 7791)
+ 0x1100, 0x116c, 0x11aa, 0,
+#undef V2433
+#define V2433 (V + 7795)
+ 0x1100, 0x116c, 0x11ab, 0,
+#undef V2434
+#define V2434 (V + 7799)
+ 0x1100, 0x116c, 0x11ac, 0,
+#undef V2435
+#define V2435 (V + 7803)
+ 0x1100, 0x116c, 0x11ad, 0,
+#undef V2436
+#define V2436 (V + 7807)
+ 0x1100, 0x116c, 0x11ae, 0,
+#undef V2437
+#define V2437 (V + 7811)
+ 0x1100, 0x116c, 0x11af, 0,
+#undef V2438
+#define V2438 (V + 7815)
+ 0x1100, 0x116c, 0x11b0, 0,
+#undef V2439
+#define V2439 (V + 7819)
+ 0x1100, 0x116c, 0x11b1, 0,
+#undef V2440
+#define V2440 (V + 7823)
+ 0x1100, 0x116c, 0x11b2, 0,
+#undef V2441
+#define V2441 (V + 7827)
+ 0x1100, 0x116c, 0x11b3, 0,
+#undef V2442
+#define V2442 (V + 7831)
+ 0x1100, 0x116c, 0x11b4, 0,
+#undef V2443
+#define V2443 (V + 7835)
+ 0x1100, 0x116c, 0x11b5, 0,
+#undef V2444
+#define V2444 (V + 7839)
+ 0x1100, 0x116c, 0x11b6, 0,
+#undef V2445
+#define V2445 (V + 7843)
+ 0x1100, 0x116c, 0x11b7, 0,
+#undef V2446
+#define V2446 (V + 7847)
+ 0x1100, 0x116c, 0x11b8, 0,
+#undef V2447
+#define V2447 (V + 7851)
+ 0x1100, 0x116c, 0x11b9, 0,
+#undef V2448
+#define V2448 (V + 7855)
+ 0x1100, 0x116c, 0x11ba, 0,
+#undef V2449
+#define V2449 (V + 7859)
+ 0x1100, 0x116c, 0x11bb, 0,
+#undef V2450
+#define V2450 (V + 7863)
+ 0x1100, 0x116c, 0x11bc, 0,
+#undef V2451
+#define V2451 (V + 7867)
+ 0x1100, 0x116c, 0x11bd, 0,
+#undef V2452
+#define V2452 (V + 7871)
+ 0x1100, 0x116c, 0x11be, 0,
+#undef V2453
+#define V2453 (V + 7875)
+ 0x1100, 0x116c, 0x11bf, 0,
+#undef V2454
+#define V2454 (V + 7879)
+ 0x1100, 0x116c, 0x11c0, 0,
+#undef V2455
+#define V2455 (V + 7883)
+ 0x1100, 0x116c, 0x11c1, 0,
+#undef V2456
+#define V2456 (V + 7887)
+ 0x1100, 0x116c, 0x11c2, 0,
+#undef V2457
+#define V2457 (V + 7891)
+ 0x1100, 0x116d, 0,
+#undef V2458
+#define V2458 (V + 7894)
+ 0x1100, 0x116d, 0x11a8, 0,
+#undef V2459
+#define V2459 (V + 7898)
+ 0x1100, 0x116d, 0x11a9, 0,
+#undef V2460
+#define V2460 (V + 7902)
+ 0x1100, 0x116d, 0x11aa, 0,
+#undef V2461
+#define V2461 (V + 7906)
+ 0x1100, 0x116d, 0x11ab, 0,
+#undef V2462
+#define V2462 (V + 7910)
+ 0x1100, 0x116d, 0x11ac, 0,
+#undef V2463
+#define V2463 (V + 7914)
+ 0x1100, 0x116d, 0x11ad, 0,
+#undef V2464
+#define V2464 (V + 7918)
+ 0x1100, 0x116d, 0x11ae, 0,
+#undef V2465
+#define V2465 (V + 7922)
+ 0x1100, 0x116d, 0x11af, 0,
+#undef V2466
+#define V2466 (V + 7926)
+ 0x1100, 0x116d, 0x11b0, 0,
+#undef V2467
+#define V2467 (V + 7930)
+ 0x1100, 0x116d, 0x11b1, 0,
+#undef V2468
+#define V2468 (V + 7934)
+ 0x1100, 0x116d, 0x11b2, 0,
+#undef V2469
+#define V2469 (V + 7938)
+ 0x1100, 0x116d, 0x11b3, 0,
+#undef V2470
+#define V2470 (V + 7942)
+ 0x1100, 0x116d, 0x11b4, 0,
+#undef V2471
+#define V2471 (V + 7946)
+ 0x1100, 0x116d, 0x11b5, 0,
+#undef V2472
+#define V2472 (V + 7950)
+ 0x1100, 0x116d, 0x11b6, 0,
+#undef V2473
+#define V2473 (V + 7954)
+ 0x1100, 0x116d, 0x11b7, 0,
+#undef V2474
+#define V2474 (V + 7958)
+ 0x1100, 0x116d, 0x11b8, 0,
+#undef V2475
+#define V2475 (V + 7962)
+ 0x1100, 0x116d, 0x11b9, 0,
+#undef V2476
+#define V2476 (V + 7966)
+ 0x1100, 0x116d, 0x11ba, 0,
+#undef V2477
+#define V2477 (V + 7970)
+ 0x1100, 0x116d, 0x11bb, 0,
+#undef V2478
+#define V2478 (V + 7974)
+ 0x1100, 0x116d, 0x11bc, 0,
+#undef V2479
+#define V2479 (V + 7978)
+ 0x1100, 0x116d, 0x11bd, 0,
+#undef V2480
+#define V2480 (V + 7982)
+ 0x1100, 0x116d, 0x11be, 0,
+#undef V2481
+#define V2481 (V + 7986)
+ 0x1100, 0x116d, 0x11bf, 0,
+#undef V2482
+#define V2482 (V + 7990)
+ 0x1100, 0x116d, 0x11c0, 0,
+#undef V2483
+#define V2483 (V + 7994)
+ 0x1100, 0x116d, 0x11c1, 0,
+#undef V2484
+#define V2484 (V + 7998)
+ 0x1100, 0x116d, 0x11c2, 0,
+#undef V2485
+#define V2485 (V + 8002)
+ 0x1100, 0x116e, 0,
+#undef V2486
+#define V2486 (V + 8005)
+ 0x1100, 0x116e, 0x11a8, 0,
+#undef V2487
+#define V2487 (V + 8009)
+ 0x1100, 0x116e, 0x11a9, 0,
+#undef V2488
+#define V2488 (V + 8013)
+ 0x1100, 0x116e, 0x11aa, 0,
+#undef V2489
+#define V2489 (V + 8017)
+ 0x1100, 0x116e, 0x11ab, 0,
+#undef V2490
+#define V2490 (V + 8021)
+ 0x1100, 0x116e, 0x11ac, 0,
+#undef V2491
+#define V2491 (V + 8025)
+ 0x1100, 0x116e, 0x11ad, 0,
+#undef V2492
+#define V2492 (V + 8029)
+ 0x1100, 0x116e, 0x11ae, 0,
+#undef V2493
+#define V2493 (V + 8033)
+ 0x1100, 0x116e, 0x11af, 0,
+#undef V2494
+#define V2494 (V + 8037)
+ 0x1100, 0x116e, 0x11b0, 0,
+#undef V2495
+#define V2495 (V + 8041)
+ 0x1100, 0x116e, 0x11b1, 0,
+#undef V2496
+#define V2496 (V + 8045)
+ 0x1100, 0x116e, 0x11b2, 0,
+#undef V2497
+#define V2497 (V + 8049)
+ 0x1100, 0x116e, 0x11b3, 0,
+#undef V2498
+#define V2498 (V + 8053)
+ 0x1100, 0x116e, 0x11b4, 0,
+#undef V2499
+#define V2499 (V + 8057)
+ 0x1100, 0x116e, 0x11b5, 0,
+#undef V2500
+#define V2500 (V + 8061)
+ 0x1100, 0x116e, 0x11b6, 0,
+#undef V2501
+#define V2501 (V + 8065)
+ 0x1100, 0x116e, 0x11b7, 0,
+#undef V2502
+#define V2502 (V + 8069)
+ 0x1100, 0x116e, 0x11b8, 0,
+#undef V2503
+#define V2503 (V + 8073)
+ 0x1100, 0x116e, 0x11b9, 0,
+#undef V2504
+#define V2504 (V + 8077)
+ 0x1100, 0x116e, 0x11ba, 0,
+#undef V2505
+#define V2505 (V + 8081)
+ 0x1100, 0x116e, 0x11bb, 0,
+#undef V2506
+#define V2506 (V + 8085)
+ 0x1100, 0x116e, 0x11bc, 0,
+#undef V2507
+#define V2507 (V + 8089)
+ 0x1100, 0x116e, 0x11bd, 0,
+#undef V2508
+#define V2508 (V + 8093)
+ 0x1100, 0x116e, 0x11be, 0,
+#undef V2509
+#define V2509 (V + 8097)
+ 0x1100, 0x116e, 0x11bf, 0,
+#undef V2510
+#define V2510 (V + 8101)
+ 0x1100, 0x116e, 0x11c0, 0,
+#undef V2511
+#define V2511 (V + 8105)
+ 0x1100, 0x116e, 0x11c1, 0,
+#undef V2512
+#define V2512 (V + 8109)
+ 0x1100, 0x116e, 0x11c2, 0,
+#undef V2513
+#define V2513 (V + 8113)
+ 0x1100, 0x116f, 0,
+#undef V2514
+#define V2514 (V + 8116)
+ 0x1100, 0x116f, 0x11a8, 0,
+#undef V2515
+#define V2515 (V + 8120)
+ 0x1100, 0x116f, 0x11a9, 0,
+#undef V2516
+#define V2516 (V + 8124)
+ 0x1100, 0x116f, 0x11aa, 0,
+#undef V2517
+#define V2517 (V + 8128)
+ 0x1100, 0x116f, 0x11ab, 0,
+#undef V2518
+#define V2518 (V + 8132)
+ 0x1100, 0x116f, 0x11ac, 0,
+#undef V2519
+#define V2519 (V + 8136)
+ 0x1100, 0x116f, 0x11ad, 0,
+#undef V2520
+#define V2520 (V + 8140)
+ 0x1100, 0x116f, 0x11ae, 0,
+#undef V2521
+#define V2521 (V + 8144)
+ 0x1100, 0x116f, 0x11af, 0,
+#undef V2522
+#define V2522 (V + 8148)
+ 0x1100, 0x116f, 0x11b0, 0,
+#undef V2523
+#define V2523 (V + 8152)
+ 0x1100, 0x116f, 0x11b1, 0,
+#undef V2524
+#define V2524 (V + 8156)
+ 0x1100, 0x116f, 0x11b2, 0,
+#undef V2525
+#define V2525 (V + 8160)
+ 0x1100, 0x116f, 0x11b3, 0,
+#undef V2526
+#define V2526 (V + 8164)
+ 0x1100, 0x116f, 0x11b4, 0,
+#undef V2527
+#define V2527 (V + 8168)
+ 0x1100, 0x116f, 0x11b5, 0,
+#undef V2528
+#define V2528 (V + 8172)
+ 0x1100, 0x116f, 0x11b6, 0,
+#undef V2529
+#define V2529 (V + 8176)
+ 0x1100, 0x116f, 0x11b7, 0,
+#undef V2530
+#define V2530 (V + 8180)
+ 0x1100, 0x116f, 0x11b8, 0,
+#undef V2531
+#define V2531 (V + 8184)
+ 0x1100, 0x116f, 0x11b9, 0,
+#undef V2532
+#define V2532 (V + 8188)
+ 0x1100, 0x116f, 0x11ba, 0,
+#undef V2533
+#define V2533 (V + 8192)
+ 0x1100, 0x116f, 0x11bb, 0,
+#undef V2534
+#define V2534 (V + 8196)
+ 0x1100, 0x116f, 0x11bc, 0,
+#undef V2535
+#define V2535 (V + 8200)
+ 0x1100, 0x116f, 0x11bd, 0,
+#undef V2536
+#define V2536 (V + 8204)
+ 0x1100, 0x116f, 0x11be, 0,
+#undef V2537
+#define V2537 (V + 8208)
+ 0x1100, 0x116f, 0x11bf, 0,
+#undef V2538
+#define V2538 (V + 8212)
+ 0x1100, 0x116f, 0x11c0, 0,
+#undef V2539
+#define V2539 (V + 8216)
+ 0x1100, 0x116f, 0x11c1, 0,
+#undef V2540
+#define V2540 (V + 8220)
+ 0x1100, 0x116f, 0x11c2, 0,
+#undef V2541
+#define V2541 (V + 8224)
+ 0x1100, 0x1170, 0,
+#undef V2542
+#define V2542 (V + 8227)
+ 0x1100, 0x1170, 0x11a8, 0,
+#undef V2543
+#define V2543 (V + 8231)
+ 0x1100, 0x1170, 0x11a9, 0,
+#undef V2544
+#define V2544 (V + 8235)
+ 0x1100, 0x1170, 0x11aa, 0,
+#undef V2545
+#define V2545 (V + 8239)
+ 0x1100, 0x1170, 0x11ab, 0,
+#undef V2546
+#define V2546 (V + 8243)
+ 0x1100, 0x1170, 0x11ac, 0,
+#undef V2547
+#define V2547 (V + 8247)
+ 0x1100, 0x1170, 0x11ad, 0,
+#undef V2548
+#define V2548 (V + 8251)
+ 0x1100, 0x1170, 0x11ae, 0,
+#undef V2549
+#define V2549 (V + 8255)
+ 0x1100, 0x1170, 0x11af, 0,
+#undef V2550
+#define V2550 (V + 8259)
+ 0x1100, 0x1170, 0x11b0, 0,
+#undef V2551
+#define V2551 (V + 8263)
+ 0x1100, 0x1170, 0x11b1, 0,
+#undef V2552
+#define V2552 (V + 8267)
+ 0x1100, 0x1170, 0x11b2, 0,
+#undef V2553
+#define V2553 (V + 8271)
+ 0x1100, 0x1170, 0x11b3, 0,
+#undef V2554
+#define V2554 (V + 8275)
+ 0x1100, 0x1170, 0x11b4, 0,
+#undef V2555
+#define V2555 (V + 8279)
+ 0x1100, 0x1170, 0x11b5, 0,
+#undef V2556
+#define V2556 (V + 8283)
+ 0x1100, 0x1170, 0x11b6, 0,
+#undef V2557
+#define V2557 (V + 8287)
+ 0x1100, 0x1170, 0x11b7, 0,
+#undef V2558
+#define V2558 (V + 8291)
+ 0x1100, 0x1170, 0x11b8, 0,
+#undef V2559
+#define V2559 (V + 8295)
+ 0x1100, 0x1170, 0x11b9, 0,
+#undef V2560
+#define V2560 (V + 8299)
+ 0x1100, 0x1170, 0x11ba, 0,
+#undef V2561
+#define V2561 (V + 8303)
+ 0x1100, 0x1170, 0x11bb, 0,
+#undef V2562
+#define V2562 (V + 8307)
+ 0x1100, 0x1170, 0x11bc, 0,
+#undef V2563
+#define V2563 (V + 8311)
+ 0x1100, 0x1170, 0x11bd, 0,
+#undef V2564
+#define V2564 (V + 8315)
+ 0x1100, 0x1170, 0x11be, 0,
+#undef V2565
+#define V2565 (V + 8319)
+ 0x1100, 0x1170, 0x11bf, 0,
+#undef V2566
+#define V2566 (V + 8323)
+ 0x1100, 0x1170, 0x11c0, 0,
+#undef V2567
+#define V2567 (V + 8327)
+ 0x1100, 0x1170, 0x11c1, 0,
+#undef V2568
+#define V2568 (V + 8331)
+ 0x1100, 0x1170, 0x11c2, 0,
+#undef V2569
+#define V2569 (V + 8335)
+ 0x1100, 0x1171, 0,
+#undef V2570
+#define V2570 (V + 8338)
+ 0x1100, 0x1171, 0x11a8, 0,
+#undef V2571
+#define V2571 (V + 8342)
+ 0x1100, 0x1171, 0x11a9, 0,
+#undef V2572
+#define V2572 (V + 8346)
+ 0x1100, 0x1171, 0x11aa, 0,
+#undef V2573
+#define V2573 (V + 8350)
+ 0x1100, 0x1171, 0x11ab, 0,
+#undef V2574
+#define V2574 (V + 8354)
+ 0x1100, 0x1171, 0x11ac, 0,
+#undef V2575
+#define V2575 (V + 8358)
+ 0x1100, 0x1171, 0x11ad, 0,
+#undef V2576
+#define V2576 (V + 8362)
+ 0x1100, 0x1171, 0x11ae, 0,
+#undef V2577
+#define V2577 (V + 8366)
+ 0x1100, 0x1171, 0x11af, 0,
+#undef V2578
+#define V2578 (V + 8370)
+ 0x1100, 0x1171, 0x11b0, 0,
+#undef V2579
+#define V2579 (V + 8374)
+ 0x1100, 0x1171, 0x11b1, 0,
+#undef V2580
+#define V2580 (V + 8378)
+ 0x1100, 0x1171, 0x11b2, 0,
+#undef V2581
+#define V2581 (V + 8382)
+ 0x1100, 0x1171, 0x11b3, 0,
+#undef V2582
+#define V2582 (V + 8386)
+ 0x1100, 0x1171, 0x11b4, 0,
+#undef V2583
+#define V2583 (V + 8390)
+ 0x1100, 0x1171, 0x11b5, 0,
+#undef V2584
+#define V2584 (V + 8394)
+ 0x1100, 0x1171, 0x11b6, 0,
+#undef V2585
+#define V2585 (V + 8398)
+ 0x1100, 0x1171, 0x11b7, 0,
+#undef V2586
+#define V2586 (V + 8402)
+ 0x1100, 0x1171, 0x11b8, 0,
+#undef V2587
+#define V2587 (V + 8406)
+ 0x1100, 0x1171, 0x11b9, 0,
+#undef V2588
+#define V2588 (V + 8410)
+ 0x1100, 0x1171, 0x11ba, 0,
+#undef V2589
+#define V2589 (V + 8414)
+ 0x1100, 0x1171, 0x11bb, 0,
+#undef V2590
+#define V2590 (V + 8418)
+ 0x1100, 0x1171, 0x11bc, 0,
+#undef V2591
+#define V2591 (V + 8422)
+ 0x1100, 0x1171, 0x11bd, 0,
+#undef V2592
+#define V2592 (V + 8426)
+ 0x1100, 0x1171, 0x11be, 0,
+#undef V2593
+#define V2593 (V + 8430)
+ 0x1100, 0x1171, 0x11bf, 0,
+#undef V2594
+#define V2594 (V + 8434)
+ 0x1100, 0x1171, 0x11c0, 0,
+#undef V2595
+#define V2595 (V + 8438)
+ 0x1100, 0x1171, 0x11c1, 0,
+#undef V2596
+#define V2596 (V + 8442)
+ 0x1100, 0x1171, 0x11c2, 0,
+#undef V2597
+#define V2597 (V + 8446)
+ 0x1100, 0x1172, 0,
+#undef V2598
+#define V2598 (V + 8449)
+ 0x1100, 0x1172, 0x11a8, 0,
+#undef V2599
+#define V2599 (V + 8453)
+ 0x1100, 0x1172, 0x11a9, 0,
+#undef V2600
+#define V2600 (V + 8457)
+ 0x1100, 0x1172, 0x11aa, 0,
+#undef V2601
+#define V2601 (V + 8461)
+ 0x1100, 0x1172, 0x11ab, 0,
+#undef V2602
+#define V2602 (V + 8465)
+ 0x1100, 0x1172, 0x11ac, 0,
+#undef V2603
+#define V2603 (V + 8469)
+ 0x1100, 0x1172, 0x11ad, 0,
+#undef V2604
+#define V2604 (V + 8473)
+ 0x1100, 0x1172, 0x11ae, 0,
+#undef V2605
+#define V2605 (V + 8477)
+ 0x1100, 0x1172, 0x11af, 0,
+#undef V2606
+#define V2606 (V + 8481)
+ 0x1100, 0x1172, 0x11b0, 0,
+#undef V2607
+#define V2607 (V + 8485)
+ 0x1100, 0x1172, 0x11b1, 0,
+#undef V2608
+#define V2608 (V + 8489)
+ 0x1100, 0x1172, 0x11b2, 0,
+#undef V2609
+#define V2609 (V + 8493)
+ 0x1100, 0x1172, 0x11b3, 0,
+#undef V2610
+#define V2610 (V + 8497)
+ 0x1100, 0x1172, 0x11b4, 0,
+#undef V2611
+#define V2611 (V + 8501)
+ 0x1100, 0x1172, 0x11b5, 0,
+#undef V2612
+#define V2612 (V + 8505)
+ 0x1100, 0x1172, 0x11b6, 0,
+#undef V2613
+#define V2613 (V + 8509)
+ 0x1100, 0x1172, 0x11b7, 0,
+#undef V2614
+#define V2614 (V + 8513)
+ 0x1100, 0x1172, 0x11b8, 0,
+#undef V2615
+#define V2615 (V + 8517)
+ 0x1100, 0x1172, 0x11b9, 0,
+#undef V2616
+#define V2616 (V + 8521)
+ 0x1100, 0x1172, 0x11ba, 0,
+#undef V2617
+#define V2617 (V + 8525)
+ 0x1100, 0x1172, 0x11bb, 0,
+#undef V2618
+#define V2618 (V + 8529)
+ 0x1100, 0x1172, 0x11bc, 0,
+#undef V2619
+#define V2619 (V + 8533)
+ 0x1100, 0x1172, 0x11bd, 0,
+#undef V2620
+#define V2620 (V + 8537)
+ 0x1100, 0x1172, 0x11be, 0,
+#undef V2621
+#define V2621 (V + 8541)
+ 0x1100, 0x1172, 0x11bf, 0,
+#undef V2622
+#define V2622 (V + 8545)
+ 0x1100, 0x1172, 0x11c0, 0,
+#undef V2623
+#define V2623 (V + 8549)
+ 0x1100, 0x1172, 0x11c1, 0,
+#undef V2624
+#define V2624 (V + 8553)
+ 0x1100, 0x1172, 0x11c2, 0,
+#undef V2625
+#define V2625 (V + 8557)
+ 0x1100, 0x1173, 0,
+#undef V2626
+#define V2626 (V + 8560)
+ 0x1100, 0x1173, 0x11a8, 0,
+#undef V2627
+#define V2627 (V + 8564)
+ 0x1100, 0x1173, 0x11a9, 0,
+#undef V2628
+#define V2628 (V + 8568)
+ 0x1100, 0x1173, 0x11aa, 0,
+#undef V2629
+#define V2629 (V + 8572)
+ 0x1100, 0x1173, 0x11ab, 0,
+#undef V2630
+#define V2630 (V + 8576)
+ 0x1100, 0x1173, 0x11ac, 0,
+#undef V2631
+#define V2631 (V + 8580)
+ 0x1100, 0x1173, 0x11ad, 0,
+#undef V2632
+#define V2632 (V + 8584)
+ 0x1100, 0x1173, 0x11ae, 0,
+#undef V2633
+#define V2633 (V + 8588)
+ 0x1100, 0x1173, 0x11af, 0,
+#undef V2634
+#define V2634 (V + 8592)
+ 0x1100, 0x1173, 0x11b0, 0,
+#undef V2635
+#define V2635 (V + 8596)
+ 0x1100, 0x1173, 0x11b1, 0,
+#undef V2636
+#define V2636 (V + 8600)
+ 0x1100, 0x1173, 0x11b2, 0,
+#undef V2637
+#define V2637 (V + 8604)
+ 0x1100, 0x1173, 0x11b3, 0,
+#undef V2638
+#define V2638 (V + 8608)
+ 0x1100, 0x1173, 0x11b4, 0,
+#undef V2639
+#define V2639 (V + 8612)
+ 0x1100, 0x1173, 0x11b5, 0,
+#undef V2640
+#define V2640 (V + 8616)
+ 0x1100, 0x1173, 0x11b6, 0,
+#undef V2641
+#define V2641 (V + 8620)
+ 0x1100, 0x1173, 0x11b7, 0,
+#undef V2642
+#define V2642 (V + 8624)
+ 0x1100, 0x1173, 0x11b8, 0,
+#undef V2643
+#define V2643 (V + 8628)
+ 0x1100, 0x1173, 0x11b9, 0,
+#undef V2644
+#define V2644 (V + 8632)
+ 0x1100, 0x1173, 0x11ba, 0,
+#undef V2645
+#define V2645 (V + 8636)
+ 0x1100, 0x1173, 0x11bb, 0,
+#undef V2646
+#define V2646 (V + 8640)
+ 0x1100, 0x1173, 0x11bc, 0,
+#undef V2647
+#define V2647 (V + 8644)
+ 0x1100, 0x1173, 0x11bd, 0,
+#undef V2648
+#define V2648 (V + 8648)
+ 0x1100, 0x1173, 0x11be, 0,
+#undef V2649
+#define V2649 (V + 8652)
+ 0x1100, 0x1173, 0x11bf, 0,
+#undef V2650
+#define V2650 (V + 8656)
+ 0x1100, 0x1173, 0x11c0, 0,
+#undef V2651
+#define V2651 (V + 8660)
+ 0x1100, 0x1173, 0x11c1, 0,
+#undef V2652
+#define V2652 (V + 8664)
+ 0x1100, 0x1173, 0x11c2, 0,
+#undef V2653
+#define V2653 (V + 8668)
+ 0x1100, 0x1174, 0,
+#undef V2654
+#define V2654 (V + 8671)
+ 0x1100, 0x1174, 0x11a8, 0,
+#undef V2655
+#define V2655 (V + 8675)
+ 0x1100, 0x1174, 0x11a9, 0,
+#undef V2656
+#define V2656 (V + 8679)
+ 0x1100, 0x1174, 0x11aa, 0,
+#undef V2657
+#define V2657 (V + 8683)
+ 0x1100, 0x1174, 0x11ab, 0,
+#undef V2658
+#define V2658 (V + 8687)
+ 0x1100, 0x1174, 0x11ac, 0,
+#undef V2659
+#define V2659 (V + 8691)
+ 0x1100, 0x1174, 0x11ad, 0,
+#undef V2660
+#define V2660 (V + 8695)
+ 0x1100, 0x1174, 0x11ae, 0,
+#undef V2661
+#define V2661 (V + 8699)
+ 0x1100, 0x1174, 0x11af, 0,
+#undef V2662
+#define V2662 (V + 8703)
+ 0x1100, 0x1174, 0x11b0, 0,
+#undef V2663
+#define V2663 (V + 8707)
+ 0x1100, 0x1174, 0x11b1, 0,
+#undef V2664
+#define V2664 (V + 8711)
+ 0x1100, 0x1174, 0x11b2, 0,
+#undef V2665
+#define V2665 (V + 8715)
+ 0x1100, 0x1174, 0x11b3, 0,
+#undef V2666
+#define V2666 (V + 8719)
+ 0x1100, 0x1174, 0x11b4, 0,
+#undef V2667
+#define V2667 (V + 8723)
+ 0x1100, 0x1174, 0x11b5, 0,
+#undef V2668
+#define V2668 (V + 8727)
+ 0x1100, 0x1174, 0x11b6, 0,
+#undef V2669
+#define V2669 (V + 8731)
+ 0x1100, 0x1174, 0x11b7, 0,
+#undef V2670
+#define V2670 (V + 8735)
+ 0x1100, 0x1174, 0x11b8, 0,
+#undef V2671
+#define V2671 (V + 8739)
+ 0x1100, 0x1174, 0x11b9, 0,
+#undef V2672
+#define V2672 (V + 8743)
+ 0x1100, 0x1174, 0x11ba, 0,
+#undef V2673
+#define V2673 (V + 8747)
+ 0x1100, 0x1174, 0x11bb, 0,
+#undef V2674
+#define V2674 (V + 8751)
+ 0x1100, 0x1174, 0x11bc, 0,
+#undef V2675
+#define V2675 (V + 8755)
+ 0x1100, 0x1174, 0x11bd, 0,
+#undef V2676
+#define V2676 (V + 8759)
+ 0x1100, 0x1174, 0x11be, 0,
+#undef V2677
+#define V2677 (V + 8763)
+ 0x1100, 0x1174, 0x11bf, 0,
+#undef V2678
+#define V2678 (V + 8767)
+ 0x1100, 0x1174, 0x11c0, 0,
+#undef V2679
+#define V2679 (V + 8771)
+ 0x1100, 0x1174, 0x11c1, 0,
+#undef V2680
+#define V2680 (V + 8775)
+ 0x1100, 0x1174, 0x11c2, 0,
+#undef V2681
+#define V2681 (V + 8779)
+ 0x1100, 0x1175, 0,
+#undef V2682
+#define V2682 (V + 8782)
+ 0x1100, 0x1175, 0x11a8, 0,
+#undef V2683
+#define V2683 (V + 8786)
+ 0x1100, 0x1175, 0x11a9, 0,
+#undef V2684
+#define V2684 (V + 8790)
+ 0x1100, 0x1175, 0x11aa, 0,
+#undef V2685
+#define V2685 (V + 8794)
+ 0x1100, 0x1175, 0x11ab, 0,
+#undef V2686
+#define V2686 (V + 8798)
+ 0x1100, 0x1175, 0x11ac, 0,
+#undef V2687
+#define V2687 (V + 8802)
+ 0x1100, 0x1175, 0x11ad, 0,
+#undef V2688
+#define V2688 (V + 8806)
+ 0x1100, 0x1175, 0x11ae, 0,
+#undef V2689
+#define V2689 (V + 8810)
+ 0x1100, 0x1175, 0x11af, 0,
+#undef V2690
+#define V2690 (V + 8814)
+ 0x1100, 0x1175, 0x11b0, 0,
+#undef V2691
+#define V2691 (V + 8818)
+ 0x1100, 0x1175, 0x11b1, 0,
+#undef V2692
+#define V2692 (V + 8822)
+ 0x1100, 0x1175, 0x11b2, 0,
+#undef V2693
+#define V2693 (V + 8826)
+ 0x1100, 0x1175, 0x11b3, 0,
+#undef V2694
+#define V2694 (V + 8830)
+ 0x1100, 0x1175, 0x11b4, 0,
+#undef V2695
+#define V2695 (V + 8834)
+ 0x1100, 0x1175, 0x11b5, 0,
+#undef V2696
+#define V2696 (V + 8838)
+ 0x1100, 0x1175, 0x11b6, 0,
+#undef V2697
+#define V2697 (V + 8842)
+ 0x1100, 0x1175, 0x11b7, 0,
+#undef V2698
+#define V2698 (V + 8846)
+ 0x1100, 0x1175, 0x11b8, 0,
+#undef V2699
+#define V2699 (V + 8850)
+ 0x1100, 0x1175, 0x11b9, 0,
+#undef V2700
+#define V2700 (V + 8854)
+ 0x1100, 0x1175, 0x11ba, 0,
+#undef V2701
+#define V2701 (V + 8858)
+ 0x1100, 0x1175, 0x11bb, 0,
+#undef V2702
+#define V2702 (V + 8862)
+ 0x1100, 0x1175, 0x11bc, 0,
+#undef V2703
+#define V2703 (V + 8866)
+ 0x1100, 0x1175, 0x11bd, 0,
+#undef V2704
+#define V2704 (V + 8870)
+ 0x1100, 0x1175, 0x11be, 0,
+#undef V2705
+#define V2705 (V + 8874)
+ 0x1100, 0x1175, 0x11bf, 0,
+#undef V2706
+#define V2706 (V + 8878)
+ 0x1100, 0x1175, 0x11c0, 0,
+#undef V2707
+#define V2707 (V + 8882)
+ 0x1100, 0x1175, 0x11c1, 0,
+#undef V2708
+#define V2708 (V + 8886)
+ 0x1100, 0x1175, 0x11c2, 0,
+#undef V2709
+#define V2709 (V + 8890)
+ 0x1101, 0x1161, 0,
+#undef V2710
+#define V2710 (V + 8893)
+ 0x1101, 0x1161, 0x11a8, 0,
+#undef V2711
+#define V2711 (V + 8897)
+ 0x1101, 0x1161, 0x11a9, 0,
+#undef V2712
+#define V2712 (V + 8901)
+ 0x1101, 0x1161, 0x11aa, 0,
+#undef V2713
+#define V2713 (V + 8905)
+ 0x1101, 0x1161, 0x11ab, 0,
+#undef V2714
+#define V2714 (V + 8909)
+ 0x1101, 0x1161, 0x11ac, 0,
+#undef V2715
+#define V2715 (V + 8913)
+ 0x1101, 0x1161, 0x11ad, 0,
+#undef V2716
+#define V2716 (V + 8917)
+ 0x1101, 0x1161, 0x11ae, 0,
+#undef V2717
+#define V2717 (V + 8921)
+ 0x1101, 0x1161, 0x11af, 0,
+#undef V2718
+#define V2718 (V + 8925)
+ 0x1101, 0x1161, 0x11b0, 0,
+#undef V2719
+#define V2719 (V + 8929)
+ 0x1101, 0x1161, 0x11b1, 0,
+#undef V2720
+#define V2720 (V + 8933)
+ 0x1101, 0x1161, 0x11b2, 0,
+#undef V2721
+#define V2721 (V + 8937)
+ 0x1101, 0x1161, 0x11b3, 0,
+#undef V2722
+#define V2722 (V + 8941)
+ 0x1101, 0x1161, 0x11b4, 0,
+#undef V2723
+#define V2723 (V + 8945)
+ 0x1101, 0x1161, 0x11b5, 0,
+#undef V2724
+#define V2724 (V + 8949)
+ 0x1101, 0x1161, 0x11b6, 0,
+#undef V2725
+#define V2725 (V + 8953)
+ 0x1101, 0x1161, 0x11b7, 0,
+#undef V2726
+#define V2726 (V + 8957)
+ 0x1101, 0x1161, 0x11b8, 0,
+#undef V2727
+#define V2727 (V + 8961)
+ 0x1101, 0x1161, 0x11b9, 0,
+#undef V2728
+#define V2728 (V + 8965)
+ 0x1101, 0x1161, 0x11ba, 0,
+#undef V2729
+#define V2729 (V + 8969)
+ 0x1101, 0x1161, 0x11bb, 0,
+#undef V2730
+#define V2730 (V + 8973)
+ 0x1101, 0x1161, 0x11bc, 0,
+#undef V2731
+#define V2731 (V + 8977)
+ 0x1101, 0x1161, 0x11bd, 0,
+#undef V2732
+#define V2732 (V + 8981)
+ 0x1101, 0x1161, 0x11be, 0,
+#undef V2733
+#define V2733 (V + 8985)
+ 0x1101, 0x1161, 0x11bf, 0,
+#undef V2734
+#define V2734 (V + 8989)
+ 0x1101, 0x1161, 0x11c0, 0,
+#undef V2735
+#define V2735 (V + 8993)
+ 0x1101, 0x1161, 0x11c1, 0,
+#undef V2736
+#define V2736 (V + 8997)
+ 0x1101, 0x1161, 0x11c2, 0,
+#undef V2737
+#define V2737 (V + 9001)
+ 0x1101, 0x1162, 0,
+#undef V2738
+#define V2738 (V + 9004)
+ 0x1101, 0x1162, 0x11a8, 0,
+#undef V2739
+#define V2739 (V + 9008)
+ 0x1101, 0x1162, 0x11a9, 0,
+#undef V2740
+#define V2740 (V + 9012)
+ 0x1101, 0x1162, 0x11aa, 0,
+#undef V2741
+#define V2741 (V + 9016)
+ 0x1101, 0x1162, 0x11ab, 0,
+#undef V2742
+#define V2742 (V + 9020)
+ 0x1101, 0x1162, 0x11ac, 0,
+#undef V2743
+#define V2743 (V + 9024)
+ 0x1101, 0x1162, 0x11ad, 0,
+#undef V2744
+#define V2744 (V + 9028)
+ 0x1101, 0x1162, 0x11ae, 0,
+#undef V2745
+#define V2745 (V + 9032)
+ 0x1101, 0x1162, 0x11af, 0,
+#undef V2746
+#define V2746 (V + 9036)
+ 0x1101, 0x1162, 0x11b0, 0,
+#undef V2747
+#define V2747 (V + 9040)
+ 0x1101, 0x1162, 0x11b1, 0,
+#undef V2748
+#define V2748 (V + 9044)
+ 0x1101, 0x1162, 0x11b2, 0,
+#undef V2749
+#define V2749 (V + 9048)
+ 0x1101, 0x1162, 0x11b3, 0,
+#undef V2750
+#define V2750 (V + 9052)
+ 0x1101, 0x1162, 0x11b4, 0,
+#undef V2751
+#define V2751 (V + 9056)
+ 0x1101, 0x1162, 0x11b5, 0,
+#undef V2752
+#define V2752 (V + 9060)
+ 0x1101, 0x1162, 0x11b6, 0,
+#undef V2753
+#define V2753 (V + 9064)
+ 0x1101, 0x1162, 0x11b7, 0,
+#undef V2754
+#define V2754 (V + 9068)
+ 0x1101, 0x1162, 0x11b8, 0,
+#undef V2755
+#define V2755 (V + 9072)
+ 0x1101, 0x1162, 0x11b9, 0,
+#undef V2756
+#define V2756 (V + 9076)
+ 0x1101, 0x1162, 0x11ba, 0,
+#undef V2757
+#define V2757 (V + 9080)
+ 0x1101, 0x1162, 0x11bb, 0,
+#undef V2758
+#define V2758 (V + 9084)
+ 0x1101, 0x1162, 0x11bc, 0,
+#undef V2759
+#define V2759 (V + 9088)
+ 0x1101, 0x1162, 0x11bd, 0,
+#undef V2760
+#define V2760 (V + 9092)
+ 0x1101, 0x1162, 0x11be, 0,
+#undef V2761
+#define V2761 (V + 9096)
+ 0x1101, 0x1162, 0x11bf, 0,
+#undef V2762
+#define V2762 (V + 9100)
+ 0x1101, 0x1162, 0x11c0, 0,
+#undef V2763
+#define V2763 (V + 9104)
+ 0x1101, 0x1162, 0x11c1, 0,
+#undef V2764
+#define V2764 (V + 9108)
+ 0x1101, 0x1162, 0x11c2, 0,
+#undef V2765
+#define V2765 (V + 9112)
+ 0x1101, 0x1163, 0,
+#undef V2766
+#define V2766 (V + 9115)
+ 0x1101, 0x1163, 0x11a8, 0,
+#undef V2767
+#define V2767 (V + 9119)
+ 0x1101, 0x1163, 0x11a9, 0,
+#undef V2768
+#define V2768 (V + 9123)
+ 0x1101, 0x1163, 0x11aa, 0,
+#undef V2769
+#define V2769 (V + 9127)
+ 0x1101, 0x1163, 0x11ab, 0,
+#undef V2770
+#define V2770 (V + 9131)
+ 0x1101, 0x1163, 0x11ac, 0,
+#undef V2771
+#define V2771 (V + 9135)
+ 0x1101, 0x1163, 0x11ad, 0,
+#undef V2772
+#define V2772 (V + 9139)
+ 0x1101, 0x1163, 0x11ae, 0,
+#undef V2773
+#define V2773 (V + 9143)
+ 0x1101, 0x1163, 0x11af, 0,
+#undef V2774
+#define V2774 (V + 9147)
+ 0x1101, 0x1163, 0x11b0, 0,
+#undef V2775
+#define V2775 (V + 9151)
+ 0x1101, 0x1163, 0x11b1, 0,
+#undef V2776
+#define V2776 (V + 9155)
+ 0x1101, 0x1163, 0x11b2, 0,
+#undef V2777
+#define V2777 (V + 9159)
+ 0x1101, 0x1163, 0x11b3, 0,
+#undef V2778
+#define V2778 (V + 9163)
+ 0x1101, 0x1163, 0x11b4, 0,
+#undef V2779
+#define V2779 (V + 9167)
+ 0x1101, 0x1163, 0x11b5, 0,
+#undef V2780
+#define V2780 (V + 9171)
+ 0x1101, 0x1163, 0x11b6, 0,
+#undef V2781
+#define V2781 (V + 9175)
+ 0x1101, 0x1163, 0x11b7, 0,
+#undef V2782
+#define V2782 (V + 9179)
+ 0x1101, 0x1163, 0x11b8, 0,
+#undef V2783
+#define V2783 (V + 9183)
+ 0x1101, 0x1163, 0x11b9, 0,
+#undef V2784
+#define V2784 (V + 9187)
+ 0x1101, 0x1163, 0x11ba, 0,
+#undef V2785
+#define V2785 (V + 9191)
+ 0x1101, 0x1163, 0x11bb, 0,
+#undef V2786
+#define V2786 (V + 9195)
+ 0x1101, 0x1163, 0x11bc, 0,
+#undef V2787
+#define V2787 (V + 9199)
+ 0x1101, 0x1163, 0x11bd, 0,
+#undef V2788
+#define V2788 (V + 9203)
+ 0x1101, 0x1163, 0x11be, 0,
+#undef V2789
+#define V2789 (V + 9207)
+ 0x1101, 0x1163, 0x11bf, 0,
+#undef V2790
+#define V2790 (V + 9211)
+ 0x1101, 0x1163, 0x11c0, 0,
+#undef V2791
+#define V2791 (V + 9215)
+ 0x1101, 0x1163, 0x11c1, 0,
+#undef V2792
+#define V2792 (V + 9219)
+ 0x1101, 0x1163, 0x11c2, 0,
+#undef V2793
+#define V2793 (V + 9223)
+ 0x1101, 0x1164, 0,
+#undef V2794
+#define V2794 (V + 9226)
+ 0x1101, 0x1164, 0x11a8, 0,
+#undef V2795
+#define V2795 (V + 9230)
+ 0x1101, 0x1164, 0x11a9, 0,
+#undef V2796
+#define V2796 (V + 9234)
+ 0x1101, 0x1164, 0x11aa, 0,
+#undef V2797
+#define V2797 (V + 9238)
+ 0x1101, 0x1164, 0x11ab, 0,
+#undef V2798
+#define V2798 (V + 9242)
+ 0x1101, 0x1164, 0x11ac, 0,
+#undef V2799
+#define V2799 (V + 9246)
+ 0x1101, 0x1164, 0x11ad, 0,
+#undef V2800
+#define V2800 (V + 9250)
+ 0x1101, 0x1164, 0x11ae, 0,
+#undef V2801
+#define V2801 (V + 9254)
+ 0x1101, 0x1164, 0x11af, 0,
+#undef V2802
+#define V2802 (V + 9258)
+ 0x1101, 0x1164, 0x11b0, 0,
+#undef V2803
+#define V2803 (V + 9262)
+ 0x1101, 0x1164, 0x11b1, 0,
+#undef V2804
+#define V2804 (V + 9266)
+ 0x1101, 0x1164, 0x11b2, 0,
+#undef V2805
+#define V2805 (V + 9270)
+ 0x1101, 0x1164, 0x11b3, 0,
+#undef V2806
+#define V2806 (V + 9274)
+ 0x1101, 0x1164, 0x11b4, 0,
+#undef V2807
+#define V2807 (V + 9278)
+ 0x1101, 0x1164, 0x11b5, 0,
+#undef V2808
+#define V2808 (V + 9282)
+ 0x1101, 0x1164, 0x11b6, 0,
+#undef V2809
+#define V2809 (V + 9286)
+ 0x1101, 0x1164, 0x11b7, 0,
+#undef V2810
+#define V2810 (V + 9290)
+ 0x1101, 0x1164, 0x11b8, 0,
+#undef V2811
+#define V2811 (V + 9294)
+ 0x1101, 0x1164, 0x11b9, 0,
+#undef V2812
+#define V2812 (V + 9298)
+ 0x1101, 0x1164, 0x11ba, 0,
+#undef V2813
+#define V2813 (V + 9302)
+ 0x1101, 0x1164, 0x11bb, 0,
+#undef V2814
+#define V2814 (V + 9306)
+ 0x1101, 0x1164, 0x11bc, 0,
+#undef V2815
+#define V2815 (V + 9310)
+ 0x1101, 0x1164, 0x11bd, 0,
+#undef V2816
+#define V2816 (V + 9314)
+ 0x1101, 0x1164, 0x11be, 0,
+#undef V2817
+#define V2817 (V + 9318)
+ 0x1101, 0x1164, 0x11bf, 0,
+#undef V2818
+#define V2818 (V + 9322)
+ 0x1101, 0x1164, 0x11c0, 0,
+#undef V2819
+#define V2819 (V + 9326)
+ 0x1101, 0x1164, 0x11c1, 0,
+#undef V2820
+#define V2820 (V + 9330)
+ 0x1101, 0x1164, 0x11c2, 0,
+#undef V2821
+#define V2821 (V + 9334)
+ 0x1101, 0x1165, 0,
+#undef V2822
+#define V2822 (V + 9337)
+ 0x1101, 0x1165, 0x11a8, 0,
+#undef V2823
+#define V2823 (V + 9341)
+ 0x1101, 0x1165, 0x11a9, 0,
+#undef V2824
+#define V2824 (V + 9345)
+ 0x1101, 0x1165, 0x11aa, 0,
+#undef V2825
+#define V2825 (V + 9349)
+ 0x1101, 0x1165, 0x11ab, 0,
+#undef V2826
+#define V2826 (V + 9353)
+ 0x1101, 0x1165, 0x11ac, 0,
+#undef V2827
+#define V2827 (V + 9357)
+ 0x1101, 0x1165, 0x11ad, 0,
+#undef V2828
+#define V2828 (V + 9361)
+ 0x1101, 0x1165, 0x11ae, 0,
+#undef V2829
+#define V2829 (V + 9365)
+ 0x1101, 0x1165, 0x11af, 0,
+#undef V2830
+#define V2830 (V + 9369)
+ 0x1101, 0x1165, 0x11b0, 0,
+#undef V2831
+#define V2831 (V + 9373)
+ 0x1101, 0x1165, 0x11b1, 0,
+#undef V2832
+#define V2832 (V + 9377)
+ 0x1101, 0x1165, 0x11b2, 0,
+#undef V2833
+#define V2833 (V + 9381)
+ 0x1101, 0x1165, 0x11b3, 0,
+#undef V2834
+#define V2834 (V + 9385)
+ 0x1101, 0x1165, 0x11b4, 0,
+#undef V2835
+#define V2835 (V + 9389)
+ 0x1101, 0x1165, 0x11b5, 0,
+#undef V2836
+#define V2836 (V + 9393)
+ 0x1101, 0x1165, 0x11b6, 0,
+#undef V2837
+#define V2837 (V + 9397)
+ 0x1101, 0x1165, 0x11b7, 0,
+#undef V2838
+#define V2838 (V + 9401)
+ 0x1101, 0x1165, 0x11b8, 0,
+#undef V2839
+#define V2839 (V + 9405)
+ 0x1101, 0x1165, 0x11b9, 0,
+#undef V2840
+#define V2840 (V + 9409)
+ 0x1101, 0x1165, 0x11ba, 0,
+#undef V2841
+#define V2841 (V + 9413)
+ 0x1101, 0x1165, 0x11bb, 0,
+#undef V2842
+#define V2842 (V + 9417)
+ 0x1101, 0x1165, 0x11bc, 0,
+#undef V2843
+#define V2843 (V + 9421)
+ 0x1101, 0x1165, 0x11bd, 0,
+#undef V2844
+#define V2844 (V + 9425)
+ 0x1101, 0x1165, 0x11be, 0,
+#undef V2845
+#define V2845 (V + 9429)
+ 0x1101, 0x1165, 0x11bf, 0,
+#undef V2846
+#define V2846 (V + 9433)
+ 0x1101, 0x1165, 0x11c0, 0,
+#undef V2847
+#define V2847 (V + 9437)
+ 0x1101, 0x1165, 0x11c1, 0,
+#undef V2848
+#define V2848 (V + 9441)
+ 0x1101, 0x1165, 0x11c2, 0,
+#undef V2849
+#define V2849 (V + 9445)
+ 0x1101, 0x1166, 0,
+#undef V2850
+#define V2850 (V + 9448)
+ 0x1101, 0x1166, 0x11a8, 0,
+#undef V2851
+#define V2851 (V + 9452)
+ 0x1101, 0x1166, 0x11a9, 0,
+#undef V2852
+#define V2852 (V + 9456)
+ 0x1101, 0x1166, 0x11aa, 0,
+#undef V2853
+#define V2853 (V + 9460)
+ 0x1101, 0x1166, 0x11ab, 0,
+#undef V2854
+#define V2854 (V + 9464)
+ 0x1101, 0x1166, 0x11ac, 0,
+#undef V2855
+#define V2855 (V + 9468)
+ 0x1101, 0x1166, 0x11ad, 0,
+#undef V2856
+#define V2856 (V + 9472)
+ 0x1101, 0x1166, 0x11ae, 0,
+#undef V2857
+#define V2857 (V + 9476)
+ 0x1101, 0x1166, 0x11af, 0,
+#undef V2858
+#define V2858 (V + 9480)
+ 0x1101, 0x1166, 0x11b0, 0,
+#undef V2859
+#define V2859 (V + 9484)
+ 0x1101, 0x1166, 0x11b1, 0,
+#undef V2860
+#define V2860 (V + 9488)
+ 0x1101, 0x1166, 0x11b2, 0,
+#undef V2861
+#define V2861 (V + 9492)
+ 0x1101, 0x1166, 0x11b3, 0,
+#undef V2862
+#define V2862 (V + 9496)
+ 0x1101, 0x1166, 0x11b4, 0,
+#undef V2863
+#define V2863 (V + 9500)
+ 0x1101, 0x1166, 0x11b5, 0,
+#undef V2864
+#define V2864 (V + 9504)
+ 0x1101, 0x1166, 0x11b6, 0,
+#undef V2865
+#define V2865 (V + 9508)
+ 0x1101, 0x1166, 0x11b7, 0,
+#undef V2866
+#define V2866 (V + 9512)
+ 0x1101, 0x1166, 0x11b8, 0,
+#undef V2867
+#define V2867 (V + 9516)
+ 0x1101, 0x1166, 0x11b9, 0,
+#undef V2868
+#define V2868 (V + 9520)
+ 0x1101, 0x1166, 0x11ba, 0,
+#undef V2869
+#define V2869 (V + 9524)
+ 0x1101, 0x1166, 0x11bb, 0,
+#undef V2870
+#define V2870 (V + 9528)
+ 0x1101, 0x1166, 0x11bc, 0,
+#undef V2871
+#define V2871 (V + 9532)
+ 0x1101, 0x1166, 0x11bd, 0,
+#undef V2872
+#define V2872 (V + 9536)
+ 0x1101, 0x1166, 0x11be, 0,
+#undef V2873
+#define V2873 (V + 9540)
+ 0x1101, 0x1166, 0x11bf, 0,
+#undef V2874
+#define V2874 (V + 9544)
+ 0x1101, 0x1166, 0x11c0, 0,
+#undef V2875
+#define V2875 (V + 9548)
+ 0x1101, 0x1166, 0x11c1, 0,
+#undef V2876
+#define V2876 (V + 9552)
+ 0x1101, 0x1166, 0x11c2, 0,
+#undef V2877
+#define V2877 (V + 9556)
+ 0x1101, 0x1167, 0,
+#undef V2878
+#define V2878 (V + 9559)
+ 0x1101, 0x1167, 0x11a8, 0,
+#undef V2879
+#define V2879 (V + 9563)
+ 0x1101, 0x1167, 0x11a9, 0,
+#undef V2880
+#define V2880 (V + 9567)
+ 0x1101, 0x1167, 0x11aa, 0,
+#undef V2881
+#define V2881 (V + 9571)
+ 0x1101, 0x1167, 0x11ab, 0,
+#undef V2882
+#define V2882 (V + 9575)
+ 0x1101, 0x1167, 0x11ac, 0,
+#undef V2883
+#define V2883 (V + 9579)
+ 0x1101, 0x1167, 0x11ad, 0,
+#undef V2884
+#define V2884 (V + 9583)
+ 0x1101, 0x1167, 0x11ae, 0,
+#undef V2885
+#define V2885 (V + 9587)
+ 0x1101, 0x1167, 0x11af, 0,
+#undef V2886
+#define V2886 (V + 9591)
+ 0x1101, 0x1167, 0x11b0, 0,
+#undef V2887
+#define V2887 (V + 9595)
+ 0x1101, 0x1167, 0x11b1, 0,
+#undef V2888
+#define V2888 (V + 9599)
+ 0x1101, 0x1167, 0x11b2, 0,
+#undef V2889
+#define V2889 (V + 9603)
+ 0x1101, 0x1167, 0x11b3, 0,
+#undef V2890
+#define V2890 (V + 9607)
+ 0x1101, 0x1167, 0x11b4, 0,
+#undef V2891
+#define V2891 (V + 9611)
+ 0x1101, 0x1167, 0x11b5, 0,
+#undef V2892
+#define V2892 (V + 9615)
+ 0x1101, 0x1167, 0x11b6, 0,
+#undef V2893
+#define V2893 (V + 9619)
+ 0x1101, 0x1167, 0x11b7, 0,
+#undef V2894
+#define V2894 (V + 9623)
+ 0x1101, 0x1167, 0x11b8, 0,
+#undef V2895
+#define V2895 (V + 9627)
+ 0x1101, 0x1167, 0x11b9, 0,
+#undef V2896
+#define V2896 (V + 9631)
+ 0x1101, 0x1167, 0x11ba, 0,
+#undef V2897
+#define V2897 (V + 9635)
+ 0x1101, 0x1167, 0x11bb, 0,
+#undef V2898
+#define V2898 (V + 9639)
+ 0x1101, 0x1167, 0x11bc, 0,
+#undef V2899
+#define V2899 (V + 9643)
+ 0x1101, 0x1167, 0x11bd, 0,
+#undef V2900
+#define V2900 (V + 9647)
+ 0x1101, 0x1167, 0x11be, 0,
+#undef V2901
+#define V2901 (V + 9651)
+ 0x1101, 0x1167, 0x11bf, 0,
+#undef V2902
+#define V2902 (V + 9655)
+ 0x1101, 0x1167, 0x11c0, 0,
+#undef V2903
+#define V2903 (V + 9659)
+ 0x1101, 0x1167, 0x11c1, 0,
+#undef V2904
+#define V2904 (V + 9663)
+ 0x1101, 0x1167, 0x11c2, 0,
+#undef V2905
+#define V2905 (V + 9667)
+ 0x1101, 0x1168, 0,
+#undef V2906
+#define V2906 (V + 9670)
+ 0x1101, 0x1168, 0x11a8, 0,
+#undef V2907
+#define V2907 (V + 9674)
+ 0x1101, 0x1168, 0x11a9, 0,
+#undef V2908
+#define V2908 (V + 9678)
+ 0x1101, 0x1168, 0x11aa, 0,
+#undef V2909
+#define V2909 (V + 9682)
+ 0x1101, 0x1168, 0x11ab, 0,
+#undef V2910
+#define V2910 (V + 9686)
+ 0x1101, 0x1168, 0x11ac, 0,
+#undef V2911
+#define V2911 (V + 9690)
+ 0x1101, 0x1168, 0x11ad, 0,
+#undef V2912
+#define V2912 (V + 9694)
+ 0x1101, 0x1168, 0x11ae, 0,
+#undef V2913
+#define V2913 (V + 9698)
+ 0x1101, 0x1168, 0x11af, 0,
+#undef V2914
+#define V2914 (V + 9702)
+ 0x1101, 0x1168, 0x11b0, 0,
+#undef V2915
+#define V2915 (V + 9706)
+ 0x1101, 0x1168, 0x11b1, 0,
+#undef V2916
+#define V2916 (V + 9710)
+ 0x1101, 0x1168, 0x11b2, 0,
+#undef V2917
+#define V2917 (V + 9714)
+ 0x1101, 0x1168, 0x11b3, 0,
+#undef V2918
+#define V2918 (V + 9718)
+ 0x1101, 0x1168, 0x11b4, 0,
+#undef V2919
+#define V2919 (V + 9722)
+ 0x1101, 0x1168, 0x11b5, 0,
+#undef V2920
+#define V2920 (V + 9726)
+ 0x1101, 0x1168, 0x11b6, 0,
+#undef V2921
+#define V2921 (V + 9730)
+ 0x1101, 0x1168, 0x11b7, 0,
+#undef V2922
+#define V2922 (V + 9734)
+ 0x1101, 0x1168, 0x11b8, 0,
+#undef V2923
+#define V2923 (V + 9738)
+ 0x1101, 0x1168, 0x11b9, 0,
+#undef V2924
+#define V2924 (V + 9742)
+ 0x1101, 0x1168, 0x11ba, 0,
+#undef V2925
+#define V2925 (V + 9746)
+ 0x1101, 0x1168, 0x11bb, 0,
+#undef V2926
+#define V2926 (V + 9750)
+ 0x1101, 0x1168, 0x11bc, 0,
+#undef V2927
+#define V2927 (V + 9754)
+ 0x1101, 0x1168, 0x11bd, 0,
+#undef V2928
+#define V2928 (V + 9758)
+ 0x1101, 0x1168, 0x11be, 0,
+#undef V2929
+#define V2929 (V + 9762)
+ 0x1101, 0x1168, 0x11bf, 0,
+#undef V2930
+#define V2930 (V + 9766)
+ 0x1101, 0x1168, 0x11c0, 0,
+#undef V2931
+#define V2931 (V + 9770)
+ 0x1101, 0x1168, 0x11c1, 0,
+#undef V2932
+#define V2932 (V + 9774)
+ 0x1101, 0x1168, 0x11c2, 0,
+#undef V2933
+#define V2933 (V + 9778)
+ 0x1101, 0x1169, 0,
+#undef V2934
+#define V2934 (V + 9781)
+ 0x1101, 0x1169, 0x11a8, 0,
+#undef V2935
+#define V2935 (V + 9785)
+ 0x1101, 0x1169, 0x11a9, 0,
+#undef V2936
+#define V2936 (V + 9789)
+ 0x1101, 0x1169, 0x11aa, 0,
+#undef V2937
+#define V2937 (V + 9793)
+ 0x1101, 0x1169, 0x11ab, 0,
+#undef V2938
+#define V2938 (V + 9797)
+ 0x1101, 0x1169, 0x11ac, 0,
+#undef V2939
+#define V2939 (V + 9801)
+ 0x1101, 0x1169, 0x11ad, 0,
+#undef V2940
+#define V2940 (V + 9805)
+ 0x1101, 0x1169, 0x11ae, 0,
+#undef V2941
+#define V2941 (V + 9809)
+ 0x1101, 0x1169, 0x11af, 0,
+#undef V2942
+#define V2942 (V + 9813)
+ 0x1101, 0x1169, 0x11b0, 0,
+#undef V2943
+#define V2943 (V + 9817)
+ 0x1101, 0x1169, 0x11b1, 0,
+#undef V2944
+#define V2944 (V + 9821)
+ 0x1101, 0x1169, 0x11b2, 0,
+#undef V2945
+#define V2945 (V + 9825)
+ 0x1101, 0x1169, 0x11b3, 0,
+#undef V2946
+#define V2946 (V + 9829)
+ 0x1101, 0x1169, 0x11b4, 0,
+#undef V2947
+#define V2947 (V + 9833)
+ 0x1101, 0x1169, 0x11b5, 0,
+#undef V2948
+#define V2948 (V + 9837)
+ 0x1101, 0x1169, 0x11b6, 0,
+#undef V2949
+#define V2949 (V + 9841)
+ 0x1101, 0x1169, 0x11b7, 0,
+#undef V2950
+#define V2950 (V + 9845)
+ 0x1101, 0x1169, 0x11b8, 0,
+#undef V2951
+#define V2951 (V + 9849)
+ 0x1101, 0x1169, 0x11b9, 0,
+#undef V2952
+#define V2952 (V + 9853)
+ 0x1101, 0x1169, 0x11ba, 0,
+#undef V2953
+#define V2953 (V + 9857)
+ 0x1101, 0x1169, 0x11bb, 0,
+#undef V2954
+#define V2954 (V + 9861)
+ 0x1101, 0x1169, 0x11bc, 0,
+#undef V2955
+#define V2955 (V + 9865)
+ 0x1101, 0x1169, 0x11bd, 0,
+#undef V2956
+#define V2956 (V + 9869)
+ 0x1101, 0x1169, 0x11be, 0,
+#undef V2957
+#define V2957 (V + 9873)
+ 0x1101, 0x1169, 0x11bf, 0,
+#undef V2958
+#define V2958 (V + 9877)
+ 0x1101, 0x1169, 0x11c0, 0,
+#undef V2959
+#define V2959 (V + 9881)
+ 0x1101, 0x1169, 0x11c1, 0,
+#undef V2960
+#define V2960 (V + 9885)
+ 0x1101, 0x1169, 0x11c2, 0,
+#undef V2961
+#define V2961 (V + 9889)
+ 0x1101, 0x116a, 0,
+#undef V2962
+#define V2962 (V + 9892)
+ 0x1101, 0x116a, 0x11a8, 0,
+#undef V2963
+#define V2963 (V + 9896)
+ 0x1101, 0x116a, 0x11a9, 0,
+#undef V2964
+#define V2964 (V + 9900)
+ 0x1101, 0x116a, 0x11aa, 0,
+#undef V2965
+#define V2965 (V + 9904)
+ 0x1101, 0x116a, 0x11ab, 0,
+#undef V2966
+#define V2966 (V + 9908)
+ 0x1101, 0x116a, 0x11ac, 0,
+#undef V2967
+#define V2967 (V + 9912)
+ 0x1101, 0x116a, 0x11ad, 0,
+#undef V2968
+#define V2968 (V + 9916)
+ 0x1101, 0x116a, 0x11ae, 0,
+#undef V2969
+#define V2969 (V + 9920)
+ 0x1101, 0x116a, 0x11af, 0,
+#undef V2970
+#define V2970 (V + 9924)
+ 0x1101, 0x116a, 0x11b0, 0,
+#undef V2971
+#define V2971 (V + 9928)
+ 0x1101, 0x116a, 0x11b1, 0,
+#undef V2972
+#define V2972 (V + 9932)
+ 0x1101, 0x116a, 0x11b2, 0,
+#undef V2973
+#define V2973 (V + 9936)
+ 0x1101, 0x116a, 0x11b3, 0,
+#undef V2974
+#define V2974 (V + 9940)
+ 0x1101, 0x116a, 0x11b4, 0,
+#undef V2975
+#define V2975 (V + 9944)
+ 0x1101, 0x116a, 0x11b5, 0,
+#undef V2976
+#define V2976 (V + 9948)
+ 0x1101, 0x116a, 0x11b6, 0,
+#undef V2977
+#define V2977 (V + 9952)
+ 0x1101, 0x116a, 0x11b7, 0,
+#undef V2978
+#define V2978 (V + 9956)
+ 0x1101, 0x116a, 0x11b8, 0,
+#undef V2979
+#define V2979 (V + 9960)
+ 0x1101, 0x116a, 0x11b9, 0,
+#undef V2980
+#define V2980 (V + 9964)
+ 0x1101, 0x116a, 0x11ba, 0,
+#undef V2981
+#define V2981 (V + 9968)
+ 0x1101, 0x116a, 0x11bb, 0,
+#undef V2982
+#define V2982 (V + 9972)
+ 0x1101, 0x116a, 0x11bc, 0,
+#undef V2983
+#define V2983 (V + 9976)
+ 0x1101, 0x116a, 0x11bd, 0,
+#undef V2984
+#define V2984 (V + 9980)
+ 0x1101, 0x116a, 0x11be, 0,
+#undef V2985
+#define V2985 (V + 9984)
+ 0x1101, 0x116a, 0x11bf, 0,
+#undef V2986
+#define V2986 (V + 9988)
+ 0x1101, 0x116a, 0x11c0, 0,
+#undef V2987
+#define V2987 (V + 9992)
+ 0x1101, 0x116a, 0x11c1, 0,
+#undef V2988
+#define V2988 (V + 9996)
+ 0x1101, 0x116a, 0x11c2, 0,
+#undef V2989
+#define V2989 (V + 10000)
+ 0x1101, 0x116b, 0,
+#undef V2990
+#define V2990 (V + 10003)
+ 0x1101, 0x116b, 0x11a8, 0,
+#undef V2991
+#define V2991 (V + 10007)
+ 0x1101, 0x116b, 0x11a9, 0,
+#undef V2992
+#define V2992 (V + 10011)
+ 0x1101, 0x116b, 0x11aa, 0,
+#undef V2993
+#define V2993 (V + 10015)
+ 0x1101, 0x116b, 0x11ab, 0,
+#undef V2994
+#define V2994 (V + 10019)
+ 0x1101, 0x116b, 0x11ac, 0,
+#undef V2995
+#define V2995 (V + 10023)
+ 0x1101, 0x116b, 0x11ad, 0,
+#undef V2996
+#define V2996 (V + 10027)
+ 0x1101, 0x116b, 0x11ae, 0,
+#undef V2997
+#define V2997 (V + 10031)
+ 0x1101, 0x116b, 0x11af, 0,
+#undef V2998
+#define V2998 (V + 10035)
+ 0x1101, 0x116b, 0x11b0, 0,
+#undef V2999
+#define V2999 (V + 10039)
+ 0x1101, 0x116b, 0x11b1, 0,
+#undef V3000
+#define V3000 (V + 10043)
+ 0x1101, 0x116b, 0x11b2, 0,
+#undef V3001
+#define V3001 (V + 10047)
+ 0x1101, 0x116b, 0x11b3, 0,
+#undef V3002
+#define V3002 (V + 10051)
+ 0x1101, 0x116b, 0x11b4, 0,
+#undef V3003
+#define V3003 (V + 10055)
+ 0x1101, 0x116b, 0x11b5, 0,
+#undef V3004
+#define V3004 (V + 10059)
+ 0x1101, 0x116b, 0x11b6, 0,
+#undef V3005
+#define V3005 (V + 10063)
+ 0x1101, 0x116b, 0x11b7, 0,
+#undef V3006
+#define V3006 (V + 10067)
+ 0x1101, 0x116b, 0x11b8, 0,
+#undef V3007
+#define V3007 (V + 10071)
+ 0x1101, 0x116b, 0x11b9, 0,
+#undef V3008
+#define V3008 (V + 10075)
+ 0x1101, 0x116b, 0x11ba, 0,
+#undef V3009
+#define V3009 (V + 10079)
+ 0x1101, 0x116b, 0x11bb, 0,
+#undef V3010
+#define V3010 (V + 10083)
+ 0x1101, 0x116b, 0x11bc, 0,
+#undef V3011
+#define V3011 (V + 10087)
+ 0x1101, 0x116b, 0x11bd, 0,
+#undef V3012
+#define V3012 (V + 10091)
+ 0x1101, 0x116b, 0x11be, 0,
+#undef V3013
+#define V3013 (V + 10095)
+ 0x1101, 0x116b, 0x11bf, 0,
+#undef V3014
+#define V3014 (V + 10099)
+ 0x1101, 0x116b, 0x11c0, 0,
+#undef V3015
+#define V3015 (V + 10103)
+ 0x1101, 0x116b, 0x11c1, 0,
+#undef V3016
+#define V3016 (V + 10107)
+ 0x1101, 0x116b, 0x11c2, 0,
+#undef V3017
+#define V3017 (V + 10111)
+ 0x1101, 0x116c, 0,
+#undef V3018
+#define V3018 (V + 10114)
+ 0x1101, 0x116c, 0x11a8, 0,
+#undef V3019
+#define V3019 (V + 10118)
+ 0x1101, 0x116c, 0x11a9, 0,
+#undef V3020
+#define V3020 (V + 10122)
+ 0x1101, 0x116c, 0x11aa, 0,
+#undef V3021
+#define V3021 (V + 10126)
+ 0x1101, 0x116c, 0x11ab, 0,
+#undef V3022
+#define V3022 (V + 10130)
+ 0x1101, 0x116c, 0x11ac, 0,
+#undef V3023
+#define V3023 (V + 10134)
+ 0x1101, 0x116c, 0x11ad, 0,
+#undef V3024
+#define V3024 (V + 10138)
+ 0x1101, 0x116c, 0x11ae, 0,
+#undef V3025
+#define V3025 (V + 10142)
+ 0x1101, 0x116c, 0x11af, 0,
+#undef V3026
+#define V3026 (V + 10146)
+ 0x1101, 0x116c, 0x11b0, 0,
+#undef V3027
+#define V3027 (V + 10150)
+ 0x1101, 0x116c, 0x11b1, 0,
+#undef V3028
+#define V3028 (V + 10154)
+ 0x1101, 0x116c, 0x11b2, 0,
+#undef V3029
+#define V3029 (V + 10158)
+ 0x1101, 0x116c, 0x11b3, 0,
+#undef V3030
+#define V3030 (V + 10162)
+ 0x1101, 0x116c, 0x11b4, 0,
+#undef V3031
+#define V3031 (V + 10166)
+ 0x1101, 0x116c, 0x11b5, 0,
+#undef V3032
+#define V3032 (V + 10170)
+ 0x1101, 0x116c, 0x11b6, 0,
+#undef V3033
+#define V3033 (V + 10174)
+ 0x1101, 0x116c, 0x11b7, 0,
+#undef V3034
+#define V3034 (V + 10178)
+ 0x1101, 0x116c, 0x11b8, 0,
+#undef V3035
+#define V3035 (V + 10182)
+ 0x1101, 0x116c, 0x11b9, 0,
+#undef V3036
+#define V3036 (V + 10186)
+ 0x1101, 0x116c, 0x11ba, 0,
+#undef V3037
+#define V3037 (V + 10190)
+ 0x1101, 0x116c, 0x11bb, 0,
+#undef V3038
+#define V3038 (V + 10194)
+ 0x1101, 0x116c, 0x11bc, 0,
+#undef V3039
+#define V3039 (V + 10198)
+ 0x1101, 0x116c, 0x11bd, 0,
+#undef V3040
+#define V3040 (V + 10202)
+ 0x1101, 0x116c, 0x11be, 0,
+#undef V3041
+#define V3041 (V + 10206)
+ 0x1101, 0x116c, 0x11bf, 0,
+#undef V3042
+#define V3042 (V + 10210)
+ 0x1101, 0x116c, 0x11c0, 0,
+#undef V3043
+#define V3043 (V + 10214)
+ 0x1101, 0x116c, 0x11c1, 0,
+#undef V3044
+#define V3044 (V + 10218)
+ 0x1101, 0x116c, 0x11c2, 0,
+#undef V3045
+#define V3045 (V + 10222)
+ 0x1101, 0x116d, 0,
+#undef V3046
+#define V3046 (V + 10225)
+ 0x1101, 0x116d, 0x11a8, 0,
+#undef V3047
+#define V3047 (V + 10229)
+ 0x1101, 0x116d, 0x11a9, 0,
+#undef V3048
+#define V3048 (V + 10233)
+ 0x1101, 0x116d, 0x11aa, 0,
+#undef V3049
+#define V3049 (V + 10237)
+ 0x1101, 0x116d, 0x11ab, 0,
+#undef V3050
+#define V3050 (V + 10241)
+ 0x1101, 0x116d, 0x11ac, 0,
+#undef V3051
+#define V3051 (V + 10245)
+ 0x1101, 0x116d, 0x11ad, 0,
+#undef V3052
+#define V3052 (V + 10249)
+ 0x1101, 0x116d, 0x11ae, 0,
+#undef V3053
+#define V3053 (V + 10253)
+ 0x1101, 0x116d, 0x11af, 0,
+#undef V3054
+#define V3054 (V + 10257)
+ 0x1101, 0x116d, 0x11b0, 0,
+#undef V3055
+#define V3055 (V + 10261)
+ 0x1101, 0x116d, 0x11b1, 0,
+#undef V3056
+#define V3056 (V + 10265)
+ 0x1101, 0x116d, 0x11b2, 0,
+#undef V3057
+#define V3057 (V + 10269)
+ 0x1101, 0x116d, 0x11b3, 0,
+#undef V3058
+#define V3058 (V + 10273)
+ 0x1101, 0x116d, 0x11b4, 0,
+#undef V3059
+#define V3059 (V + 10277)
+ 0x1101, 0x116d, 0x11b5, 0,
+#undef V3060
+#define V3060 (V + 10281)
+ 0x1101, 0x116d, 0x11b6, 0,
+#undef V3061
+#define V3061 (V + 10285)
+ 0x1101, 0x116d, 0x11b7, 0,
+#undef V3062
+#define V3062 (V + 10289)
+ 0x1101, 0x116d, 0x11b8, 0,
+#undef V3063
+#define V3063 (V + 10293)
+ 0x1101, 0x116d, 0x11b9, 0,
+#undef V3064
+#define V3064 (V + 10297)
+ 0x1101, 0x116d, 0x11ba, 0,
+#undef V3065
+#define V3065 (V + 10301)
+ 0x1101, 0x116d, 0x11bb, 0,
+#undef V3066
+#define V3066 (V + 10305)
+ 0x1101, 0x116d, 0x11bc, 0,
+#undef V3067
+#define V3067 (V + 10309)
+ 0x1101, 0x116d, 0x11bd, 0,
+#undef V3068
+#define V3068 (V + 10313)
+ 0x1101, 0x116d, 0x11be, 0,
+#undef V3069
+#define V3069 (V + 10317)
+ 0x1101, 0x116d, 0x11bf, 0,
+#undef V3070
+#define V3070 (V + 10321)
+ 0x1101, 0x116d, 0x11c0, 0,
+#undef V3071
+#define V3071 (V + 10325)
+ 0x1101, 0x116d, 0x11c1, 0,
+#undef V3072
+#define V3072 (V + 10329)
+ 0x1101, 0x116d, 0x11c2, 0,
+#undef V3073
+#define V3073 (V + 10333)
+ 0x1101, 0x116e, 0,
+#undef V3074
+#define V3074 (V + 10336)
+ 0x1101, 0x116e, 0x11a8, 0,
+#undef V3075
+#define V3075 (V + 10340)
+ 0x1101, 0x116e, 0x11a9, 0,
+#undef V3076
+#define V3076 (V + 10344)
+ 0x1101, 0x116e, 0x11aa, 0,
+#undef V3077
+#define V3077 (V + 10348)
+ 0x1101, 0x116e, 0x11ab, 0,
+#undef V3078
+#define V3078 (V + 10352)
+ 0x1101, 0x116e, 0x11ac, 0,
+#undef V3079
+#define V3079 (V + 10356)
+ 0x1101, 0x116e, 0x11ad, 0,
+#undef V3080
+#define V3080 (V + 10360)
+ 0x1101, 0x116e, 0x11ae, 0,
+#undef V3081
+#define V3081 (V + 10364)
+ 0x1101, 0x116e, 0x11af, 0,
+#undef V3082
+#define V3082 (V + 10368)
+ 0x1101, 0x116e, 0x11b0, 0,
+#undef V3083
+#define V3083 (V + 10372)
+ 0x1101, 0x116e, 0x11b1, 0,
+#undef V3084
+#define V3084 (V + 10376)
+ 0x1101, 0x116e, 0x11b2, 0,
+#undef V3085
+#define V3085 (V + 10380)
+ 0x1101, 0x116e, 0x11b3, 0,
+#undef V3086
+#define V3086 (V + 10384)
+ 0x1101, 0x116e, 0x11b4, 0,
+#undef V3087
+#define V3087 (V + 10388)
+ 0x1101, 0x116e, 0x11b5, 0,
+#undef V3088
+#define V3088 (V + 10392)
+ 0x1101, 0x116e, 0x11b6, 0,
+#undef V3089
+#define V3089 (V + 10396)
+ 0x1101, 0x116e, 0x11b7, 0,
+#undef V3090
+#define V3090 (V + 10400)
+ 0x1101, 0x116e, 0x11b8, 0,
+#undef V3091
+#define V3091 (V + 10404)
+ 0x1101, 0x116e, 0x11b9, 0,
+#undef V3092
+#define V3092 (V + 10408)
+ 0x1101, 0x116e, 0x11ba, 0,
+#undef V3093
+#define V3093 (V + 10412)
+ 0x1101, 0x116e, 0x11bb, 0,
+#undef V3094
+#define V3094 (V + 10416)
+ 0x1101, 0x116e, 0x11bc, 0,
+#undef V3095
+#define V3095 (V + 10420)
+ 0x1101, 0x116e, 0x11bd, 0,
+#undef V3096
+#define V3096 (V + 10424)
+ 0x1101, 0x116e, 0x11be, 0,
+#undef V3097
+#define V3097 (V + 10428)
+ 0x1101, 0x116e, 0x11bf, 0,
+#undef V3098
+#define V3098 (V + 10432)
+ 0x1101, 0x116e, 0x11c0, 0,
+#undef V3099
+#define V3099 (V + 10436)
+ 0x1101, 0x116e, 0x11c1, 0,
+#undef V3100
+#define V3100 (V + 10440)
+ 0x1101, 0x116e, 0x11c2, 0,
+#undef V3101
+#define V3101 (V + 10444)
+ 0x1101, 0x116f, 0,
+#undef V3102
+#define V3102 (V + 10447)
+ 0x1101, 0x116f, 0x11a8, 0,
+#undef V3103
+#define V3103 (V + 10451)
+ 0x1101, 0x116f, 0x11a9, 0,
+#undef V3104
+#define V3104 (V + 10455)
+ 0x1101, 0x116f, 0x11aa, 0,
+#undef V3105
+#define V3105 (V + 10459)
+ 0x1101, 0x116f, 0x11ab, 0,
+#undef V3106
+#define V3106 (V + 10463)
+ 0x1101, 0x116f, 0x11ac, 0,
+#undef V3107
+#define V3107 (V + 10467)
+ 0x1101, 0x116f, 0x11ad, 0,
+#undef V3108
+#define V3108 (V + 10471)
+ 0x1101, 0x116f, 0x11ae, 0,
+#undef V3109
+#define V3109 (V + 10475)
+ 0x1101, 0x116f, 0x11af, 0,
+#undef V3110
+#define V3110 (V + 10479)
+ 0x1101, 0x116f, 0x11b0, 0,
+#undef V3111
+#define V3111 (V + 10483)
+ 0x1101, 0x116f, 0x11b1, 0,
+#undef V3112
+#define V3112 (V + 10487)
+ 0x1101, 0x116f, 0x11b2, 0,
+#undef V3113
+#define V3113 (V + 10491)
+ 0x1101, 0x116f, 0x11b3, 0,
+#undef V3114
+#define V3114 (V + 10495)
+ 0x1101, 0x116f, 0x11b4, 0,
+#undef V3115
+#define V3115 (V + 10499)
+ 0x1101, 0x116f, 0x11b5, 0,
+#undef V3116
+#define V3116 (V + 10503)
+ 0x1101, 0x116f, 0x11b6, 0,
+#undef V3117
+#define V3117 (V + 10507)
+ 0x1101, 0x116f, 0x11b7, 0,
+#undef V3118
+#define V3118 (V + 10511)
+ 0x1101, 0x116f, 0x11b8, 0,
+#undef V3119
+#define V3119 (V + 10515)
+ 0x1101, 0x116f, 0x11b9, 0,
+#undef V3120
+#define V3120 (V + 10519)
+ 0x1101, 0x116f, 0x11ba, 0,
+#undef V3121
+#define V3121 (V + 10523)
+ 0x1101, 0x116f, 0x11bb, 0,
+#undef V3122
+#define V3122 (V + 10527)
+ 0x1101, 0x116f, 0x11bc, 0,
+#undef V3123
+#define V3123 (V + 10531)
+ 0x1101, 0x116f, 0x11bd, 0,
+#undef V3124
+#define V3124 (V + 10535)
+ 0x1101, 0x116f, 0x11be, 0,
+#undef V3125
+#define V3125 (V + 10539)
+ 0x1101, 0x116f, 0x11bf, 0,
+#undef V3126
+#define V3126 (V + 10543)
+ 0x1101, 0x116f, 0x11c0, 0,
+#undef V3127
+#define V3127 (V + 10547)
+ 0x1101, 0x116f, 0x11c1, 0,
+#undef V3128
+#define V3128 (V + 10551)
+ 0x1101, 0x116f, 0x11c2, 0,
+#undef V3129
+#define V3129 (V + 10555)
+ 0x1101, 0x1170, 0,
+#undef V3130
+#define V3130 (V + 10558)
+ 0x1101, 0x1170, 0x11a8, 0,
+#undef V3131
+#define V3131 (V + 10562)
+ 0x1101, 0x1170, 0x11a9, 0,
+#undef V3132
+#define V3132 (V + 10566)
+ 0x1101, 0x1170, 0x11aa, 0,
+#undef V3133
+#define V3133 (V + 10570)
+ 0x1101, 0x1170, 0x11ab, 0,
+#undef V3134
+#define V3134 (V + 10574)
+ 0x1101, 0x1170, 0x11ac, 0,
+#undef V3135
+#define V3135 (V + 10578)
+ 0x1101, 0x1170, 0x11ad, 0,
+#undef V3136
+#define V3136 (V + 10582)
+ 0x1101, 0x1170, 0x11ae, 0,
+#undef V3137
+#define V3137 (V + 10586)
+ 0x1101, 0x1170, 0x11af, 0,
+#undef V3138
+#define V3138 (V + 10590)
+ 0x1101, 0x1170, 0x11b0, 0,
+#undef V3139
+#define V3139 (V + 10594)
+ 0x1101, 0x1170, 0x11b1, 0,
+#undef V3140
+#define V3140 (V + 10598)
+ 0x1101, 0x1170, 0x11b2, 0,
+#undef V3141
+#define V3141 (V + 10602)
+ 0x1101, 0x1170, 0x11b3, 0,
+#undef V3142
+#define V3142 (V + 10606)
+ 0x1101, 0x1170, 0x11b4, 0,
+#undef V3143
+#define V3143 (V + 10610)
+ 0x1101, 0x1170, 0x11b5, 0,
+#undef V3144
+#define V3144 (V + 10614)
+ 0x1101, 0x1170, 0x11b6, 0,
+#undef V3145
+#define V3145 (V + 10618)
+ 0x1101, 0x1170, 0x11b7, 0,
+#undef V3146
+#define V3146 (V + 10622)
+ 0x1101, 0x1170, 0x11b8, 0,
+#undef V3147
+#define V3147 (V + 10626)
+ 0x1101, 0x1170, 0x11b9, 0,
+#undef V3148
+#define V3148 (V + 10630)
+ 0x1101, 0x1170, 0x11ba, 0,
+#undef V3149
+#define V3149 (V + 10634)
+ 0x1101, 0x1170, 0x11bb, 0,
+#undef V3150
+#define V3150 (V + 10638)
+ 0x1101, 0x1170, 0x11bc, 0,
+#undef V3151
+#define V3151 (V + 10642)
+ 0x1101, 0x1170, 0x11bd, 0,
+#undef V3152
+#define V3152 (V + 10646)
+ 0x1101, 0x1170, 0x11be, 0,
+#undef V3153
+#define V3153 (V + 10650)
+ 0x1101, 0x1170, 0x11bf, 0,
+#undef V3154
+#define V3154 (V + 10654)
+ 0x1101, 0x1170, 0x11c0, 0,
+#undef V3155
+#define V3155 (V + 10658)
+ 0x1101, 0x1170, 0x11c1, 0,
+#undef V3156
+#define V3156 (V + 10662)
+ 0x1101, 0x1170, 0x11c2, 0,
+#undef V3157
+#define V3157 (V + 10666)
+ 0x1101, 0x1171, 0,
+#undef V3158
+#define V3158 (V + 10669)
+ 0x1101, 0x1171, 0x11a8, 0,
+#undef V3159
+#define V3159 (V + 10673)
+ 0x1101, 0x1171, 0x11a9, 0,
+#undef V3160
+#define V3160 (V + 10677)
+ 0x1101, 0x1171, 0x11aa, 0,
+#undef V3161
+#define V3161 (V + 10681)
+ 0x1101, 0x1171, 0x11ab, 0,
+#undef V3162
+#define V3162 (V + 10685)
+ 0x1101, 0x1171, 0x11ac, 0,
+#undef V3163
+#define V3163 (V + 10689)
+ 0x1101, 0x1171, 0x11ad, 0,
+#undef V3164
+#define V3164 (V + 10693)
+ 0x1101, 0x1171, 0x11ae, 0,
+#undef V3165
+#define V3165 (V + 10697)
+ 0x1101, 0x1171, 0x11af, 0,
+#undef V3166
+#define V3166 (V + 10701)
+ 0x1101, 0x1171, 0x11b0, 0,
+#undef V3167
+#define V3167 (V + 10705)
+ 0x1101, 0x1171, 0x11b1, 0,
+#undef V3168
+#define V3168 (V + 10709)
+ 0x1101, 0x1171, 0x11b2, 0,
+#undef V3169
+#define V3169 (V + 10713)
+ 0x1101, 0x1171, 0x11b3, 0,
+#undef V3170
+#define V3170 (V + 10717)
+ 0x1101, 0x1171, 0x11b4, 0,
+#undef V3171
+#define V3171 (V + 10721)
+ 0x1101, 0x1171, 0x11b5, 0,
+#undef V3172
+#define V3172 (V + 10725)
+ 0x1101, 0x1171, 0x11b6, 0,
+#undef V3173
+#define V3173 (V + 10729)
+ 0x1101, 0x1171, 0x11b7, 0,
+#undef V3174
+#define V3174 (V + 10733)
+ 0x1101, 0x1171, 0x11b8, 0,
+#undef V3175
+#define V3175 (V + 10737)
+ 0x1101, 0x1171, 0x11b9, 0,
+#undef V3176
+#define V3176 (V + 10741)
+ 0x1101, 0x1171, 0x11ba, 0,
+#undef V3177
+#define V3177 (V + 10745)
+ 0x1101, 0x1171, 0x11bb, 0,
+#undef V3178
+#define V3178 (V + 10749)
+ 0x1101, 0x1171, 0x11bc, 0,
+#undef V3179
+#define V3179 (V + 10753)
+ 0x1101, 0x1171, 0x11bd, 0,
+#undef V3180
+#define V3180 (V + 10757)
+ 0x1101, 0x1171, 0x11be, 0,
+#undef V3181
+#define V3181 (V + 10761)
+ 0x1101, 0x1171, 0x11bf, 0,
+#undef V3182
+#define V3182 (V + 10765)
+ 0x1101, 0x1171, 0x11c0, 0,
+#undef V3183
+#define V3183 (V + 10769)
+ 0x1101, 0x1171, 0x11c1, 0,
+#undef V3184
+#define V3184 (V + 10773)
+ 0x1101, 0x1171, 0x11c2, 0,
+#undef V3185
+#define V3185 (V + 10777)
+ 0x1101, 0x1172, 0,
+#undef V3186
+#define V3186 (V + 10780)
+ 0x1101, 0x1172, 0x11a8, 0,
+#undef V3187
+#define V3187 (V + 10784)
+ 0x1101, 0x1172, 0x11a9, 0,
+#undef V3188
+#define V3188 (V + 10788)
+ 0x1101, 0x1172, 0x11aa, 0,
+#undef V3189
+#define V3189 (V + 10792)
+ 0x1101, 0x1172, 0x11ab, 0,
+#undef V3190
+#define V3190 (V + 10796)
+ 0x1101, 0x1172, 0x11ac, 0,
+#undef V3191
+#define V3191 (V + 10800)
+ 0x1101, 0x1172, 0x11ad, 0,
+#undef V3192
+#define V3192 (V + 10804)
+ 0x1101, 0x1172, 0x11ae, 0,
+#undef V3193
+#define V3193 (V + 10808)
+ 0x1101, 0x1172, 0x11af, 0,
+#undef V3194
+#define V3194 (V + 10812)
+ 0x1101, 0x1172, 0x11b0, 0,
+#undef V3195
+#define V3195 (V + 10816)
+ 0x1101, 0x1172, 0x11b1, 0,
+#undef V3196
+#define V3196 (V + 10820)
+ 0x1101, 0x1172, 0x11b2, 0,
+#undef V3197
+#define V3197 (V + 10824)
+ 0x1101, 0x1172, 0x11b3, 0,
+#undef V3198
+#define V3198 (V + 10828)
+ 0x1101, 0x1172, 0x11b4, 0,
+#undef V3199
+#define V3199 (V + 10832)
+ 0x1101, 0x1172, 0x11b5, 0,
+#undef V3200
+#define V3200 (V + 10836)
+ 0x1101, 0x1172, 0x11b6, 0,
+#undef V3201
+#define V3201 (V + 10840)
+ 0x1101, 0x1172, 0x11b7, 0,
+#undef V3202
+#define V3202 (V + 10844)
+ 0x1101, 0x1172, 0x11b8, 0,
+#undef V3203
+#define V3203 (V + 10848)
+ 0x1101, 0x1172, 0x11b9, 0,
+#undef V3204
+#define V3204 (V + 10852)
+ 0x1101, 0x1172, 0x11ba, 0,
+#undef V3205
+#define V3205 (V + 10856)
+ 0x1101, 0x1172, 0x11bb, 0,
+#undef V3206
+#define V3206 (V + 10860)
+ 0x1101, 0x1172, 0x11bc, 0,
+#undef V3207
+#define V3207 (V + 10864)
+ 0x1101, 0x1172, 0x11bd, 0,
+#undef V3208
+#define V3208 (V + 10868)
+ 0x1101, 0x1172, 0x11be, 0,
+#undef V3209
+#define V3209 (V + 10872)
+ 0x1101, 0x1172, 0x11bf, 0,
+#undef V3210
+#define V3210 (V + 10876)
+ 0x1101, 0x1172, 0x11c0, 0,
+#undef V3211
+#define V3211 (V + 10880)
+ 0x1101, 0x1172, 0x11c1, 0,
+#undef V3212
+#define V3212 (V + 10884)
+ 0x1101, 0x1172, 0x11c2, 0,
+#undef V3213
+#define V3213 (V + 10888)
+ 0x1101, 0x1173, 0,
+#undef V3214
+#define V3214 (V + 10891)
+ 0x1101, 0x1173, 0x11a8, 0,
+#undef V3215
+#define V3215 (V + 10895)
+ 0x1101, 0x1173, 0x11a9, 0,
+#undef V3216
+#define V3216 (V + 10899)
+ 0x1101, 0x1173, 0x11aa, 0,
+#undef V3217
+#define V3217 (V + 10903)
+ 0x1101, 0x1173, 0x11ab, 0,
+#undef V3218
+#define V3218 (V + 10907)
+ 0x1101, 0x1173, 0x11ac, 0,
+#undef V3219
+#define V3219 (V + 10911)
+ 0x1101, 0x1173, 0x11ad, 0,
+#undef V3220
+#define V3220 (V + 10915)
+ 0x1101, 0x1173, 0x11ae, 0,
+#undef V3221
+#define V3221 (V + 10919)
+ 0x1101, 0x1173, 0x11af, 0,
+#undef V3222
+#define V3222 (V + 10923)
+ 0x1101, 0x1173, 0x11b0, 0,
+#undef V3223
+#define V3223 (V + 10927)
+ 0x1101, 0x1173, 0x11b1, 0,
+#undef V3224
+#define V3224 (V + 10931)
+ 0x1101, 0x1173, 0x11b2, 0,
+#undef V3225
+#define V3225 (V + 10935)
+ 0x1101, 0x1173, 0x11b3, 0,
+#undef V3226
+#define V3226 (V + 10939)
+ 0x1101, 0x1173, 0x11b4, 0,
+#undef V3227
+#define V3227 (V + 10943)
+ 0x1101, 0x1173, 0x11b5, 0,
+#undef V3228
+#define V3228 (V + 10947)
+ 0x1101, 0x1173, 0x11b6, 0,
+#undef V3229
+#define V3229 (V + 10951)
+ 0x1101, 0x1173, 0x11b7, 0,
+#undef V3230
+#define V3230 (V + 10955)
+ 0x1101, 0x1173, 0x11b8, 0,
+#undef V3231
+#define V3231 (V + 10959)
+ 0x1101, 0x1173, 0x11b9, 0,
+#undef V3232
+#define V3232 (V + 10963)
+ 0x1101, 0x1173, 0x11ba, 0,
+#undef V3233
+#define V3233 (V + 10967)
+ 0x1101, 0x1173, 0x11bb, 0,
+#undef V3234
+#define V3234 (V + 10971)
+ 0x1101, 0x1173, 0x11bc, 0,
+#undef V3235
+#define V3235 (V + 10975)
+ 0x1101, 0x1173, 0x11bd, 0,
+#undef V3236
+#define V3236 (V + 10979)
+ 0x1101, 0x1173, 0x11be, 0,
+#undef V3237
+#define V3237 (V + 10983)
+ 0x1101, 0x1173, 0x11bf, 0,
+#undef V3238
+#define V3238 (V + 10987)
+ 0x1101, 0x1173, 0x11c0, 0,
+#undef V3239
+#define V3239 (V + 10991)
+ 0x1101, 0x1173, 0x11c1, 0,
+#undef V3240
+#define V3240 (V + 10995)
+ 0x1101, 0x1173, 0x11c2, 0,
+#undef V3241
+#define V3241 (V + 10999)
+ 0x1101, 0x1174, 0,
+#undef V3242
+#define V3242 (V + 11002)
+ 0x1101, 0x1174, 0x11a8, 0,
+#undef V3243
+#define V3243 (V + 11006)
+ 0x1101, 0x1174, 0x11a9, 0,
+#undef V3244
+#define V3244 (V + 11010)
+ 0x1101, 0x1174, 0x11aa, 0,
+#undef V3245
+#define V3245 (V + 11014)
+ 0x1101, 0x1174, 0x11ab, 0,
+#undef V3246
+#define V3246 (V + 11018)
+ 0x1101, 0x1174, 0x11ac, 0,
+#undef V3247
+#define V3247 (V + 11022)
+ 0x1101, 0x1174, 0x11ad, 0,
+#undef V3248
+#define V3248 (V + 11026)
+ 0x1101, 0x1174, 0x11ae, 0,
+#undef V3249
+#define V3249 (V + 11030)
+ 0x1101, 0x1174, 0x11af, 0,
+#undef V3250
+#define V3250 (V + 11034)
+ 0x1101, 0x1174, 0x11b0, 0,
+#undef V3251
+#define V3251 (V + 11038)
+ 0x1101, 0x1174, 0x11b1, 0,
+#undef V3252
+#define V3252 (V + 11042)
+ 0x1101, 0x1174, 0x11b2, 0,
+#undef V3253
+#define V3253 (V + 11046)
+ 0x1101, 0x1174, 0x11b3, 0,
+#undef V3254
+#define V3254 (V + 11050)
+ 0x1101, 0x1174, 0x11b4, 0,
+#undef V3255
+#define V3255 (V + 11054)
+ 0x1101, 0x1174, 0x11b5, 0,
+#undef V3256
+#define V3256 (V + 11058)
+ 0x1101, 0x1174, 0x11b6, 0,
+#undef V3257
+#define V3257 (V + 11062)
+ 0x1101, 0x1174, 0x11b7, 0,
+#undef V3258
+#define V3258 (V + 11066)
+ 0x1101, 0x1174, 0x11b8, 0,
+#undef V3259
+#define V3259 (V + 11070)
+ 0x1101, 0x1174, 0x11b9, 0,
+#undef V3260
+#define V3260 (V + 11074)
+ 0x1101, 0x1174, 0x11ba, 0,
+#undef V3261
+#define V3261 (V + 11078)
+ 0x1101, 0x1174, 0x11bb, 0,
+#undef V3262
+#define V3262 (V + 11082)
+ 0x1101, 0x1174, 0x11bc, 0,
+#undef V3263
+#define V3263 (V + 11086)
+ 0x1101, 0x1174, 0x11bd, 0,
+#undef V3264
+#define V3264 (V + 11090)
+ 0x1101, 0x1174, 0x11be, 0,
+#undef V3265
+#define V3265 (V + 11094)
+ 0x1101, 0x1174, 0x11bf, 0,
+#undef V3266
+#define V3266 (V + 11098)
+ 0x1101, 0x1174, 0x11c0, 0,
+#undef V3267
+#define V3267 (V + 11102)
+ 0x1101, 0x1174, 0x11c1, 0,
+#undef V3268
+#define V3268 (V + 11106)
+ 0x1101, 0x1174, 0x11c2, 0,
+#undef V3269
+#define V3269 (V + 11110)
+ 0x1101, 0x1175, 0,
+#undef V3270
+#define V3270 (V + 11113)
+ 0x1101, 0x1175, 0x11a8, 0,
+#undef V3271
+#define V3271 (V + 11117)
+ 0x1101, 0x1175, 0x11a9, 0,
+#undef V3272
+#define V3272 (V + 11121)
+ 0x1101, 0x1175, 0x11aa, 0,
+#undef V3273
+#define V3273 (V + 11125)
+ 0x1101, 0x1175, 0x11ab, 0,
+#undef V3274
+#define V3274 (V + 11129)
+ 0x1101, 0x1175, 0x11ac, 0,
+#undef V3275
+#define V3275 (V + 11133)
+ 0x1101, 0x1175, 0x11ad, 0,
+#undef V3276
+#define V3276 (V + 11137)
+ 0x1101, 0x1175, 0x11ae, 0,
+#undef V3277
+#define V3277 (V + 11141)
+ 0x1101, 0x1175, 0x11af, 0,
+#undef V3278
+#define V3278 (V + 11145)
+ 0x1101, 0x1175, 0x11b0, 0,
+#undef V3279
+#define V3279 (V + 11149)
+ 0x1101, 0x1175, 0x11b1, 0,
+#undef V3280
+#define V3280 (V + 11153)
+ 0x1101, 0x1175, 0x11b2, 0,
+#undef V3281
+#define V3281 (V + 11157)
+ 0x1101, 0x1175, 0x11b3, 0,
+#undef V3282
+#define V3282 (V + 11161)
+ 0x1101, 0x1175, 0x11b4, 0,
+#undef V3283
+#define V3283 (V + 11165)
+ 0x1101, 0x1175, 0x11b5, 0,
+#undef V3284
+#define V3284 (V + 11169)
+ 0x1101, 0x1175, 0x11b6, 0,
+#undef V3285
+#define V3285 (V + 11173)
+ 0x1101, 0x1175, 0x11b7, 0,
+#undef V3286
+#define V3286 (V + 11177)
+ 0x1101, 0x1175, 0x11b8, 0,
+#undef V3287
+#define V3287 (V + 11181)
+ 0x1101, 0x1175, 0x11b9, 0,
+#undef V3288
+#define V3288 (V + 11185)
+ 0x1101, 0x1175, 0x11ba, 0,
+#undef V3289
+#define V3289 (V + 11189)
+ 0x1101, 0x1175, 0x11bb, 0,
+#undef V3290
+#define V3290 (V + 11193)
+ 0x1101, 0x1175, 0x11bc, 0,
+#undef V3291
+#define V3291 (V + 11197)
+ 0x1101, 0x1175, 0x11bd, 0,
+#undef V3292
+#define V3292 (V + 11201)
+ 0x1101, 0x1175, 0x11be, 0,
+#undef V3293
+#define V3293 (V + 11205)
+ 0x1101, 0x1175, 0x11bf, 0,
+#undef V3294
+#define V3294 (V + 11209)
+ 0x1101, 0x1175, 0x11c0, 0,
+#undef V3295
+#define V3295 (V + 11213)
+ 0x1101, 0x1175, 0x11c1, 0,
+#undef V3296
+#define V3296 (V + 11217)
+ 0x1101, 0x1175, 0x11c2, 0,
+#undef V3297
+#define V3297 (V + 11221)
+ 0x1102, 0x1161, 0x11a8, 0,
+#undef V3298
+#define V3298 (V + 11225)
+ 0x1102, 0x1161, 0x11a9, 0,
+#undef V3299
+#define V3299 (V + 11229)
+ 0x1102, 0x1161, 0x11aa, 0,
+#undef V3300
+#define V3300 (V + 11233)
+ 0x1102, 0x1161, 0x11ab, 0,
+#undef V3301
+#define V3301 (V + 11237)
+ 0x1102, 0x1161, 0x11ac, 0,
+#undef V3302
+#define V3302 (V + 11241)
+ 0x1102, 0x1161, 0x11ad, 0,
+#undef V3303
+#define V3303 (V + 11245)
+ 0x1102, 0x1161, 0x11ae, 0,
+#undef V3304
+#define V3304 (V + 11249)
+ 0x1102, 0x1161, 0x11af, 0,
+#undef V3305
+#define V3305 (V + 11253)
+ 0x1102, 0x1161, 0x11b0, 0,
+#undef V3306
+#define V3306 (V + 11257)
+ 0x1102, 0x1161, 0x11b1, 0,
+#undef V3307
+#define V3307 (V + 11261)
+ 0x1102, 0x1161, 0x11b2, 0,
+#undef V3308
+#define V3308 (V + 11265)
+ 0x1102, 0x1161, 0x11b3, 0,
+#undef V3309
+#define V3309 (V + 11269)
+ 0x1102, 0x1161, 0x11b4, 0,
+#undef V3310
+#define V3310 (V + 11273)
+ 0x1102, 0x1161, 0x11b5, 0,
+#undef V3311
+#define V3311 (V + 11277)
+ 0x1102, 0x1161, 0x11b6, 0,
+#undef V3312
+#define V3312 (V + 11281)
+ 0x1102, 0x1161, 0x11b7, 0,
+#undef V3313
+#define V3313 (V + 11285)
+ 0x1102, 0x1161, 0x11b8, 0,
+#undef V3314
+#define V3314 (V + 11289)
+ 0x1102, 0x1161, 0x11b9, 0,
+#undef V3315
+#define V3315 (V + 11293)
+ 0x1102, 0x1161, 0x11ba, 0,
+#undef V3316
+#define V3316 (V + 11297)
+ 0x1102, 0x1161, 0x11bb, 0,
+#undef V3317
+#define V3317 (V + 11301)
+ 0x1102, 0x1161, 0x11bc, 0,
+#undef V3318
+#define V3318 (V + 11305)
+ 0x1102, 0x1161, 0x11bd, 0,
+#undef V3319
+#define V3319 (V + 11309)
+ 0x1102, 0x1161, 0x11be, 0,
+#undef V3320
+#define V3320 (V + 11313)
+ 0x1102, 0x1161, 0x11bf, 0,
+#undef V3321
+#define V3321 (V + 11317)
+ 0x1102, 0x1161, 0x11c0, 0,
+#undef V3322
+#define V3322 (V + 11321)
+ 0x1102, 0x1161, 0x11c1, 0,
+#undef V3323
+#define V3323 (V + 11325)
+ 0x1102, 0x1161, 0x11c2, 0,
+#undef V3324
+#define V3324 (V + 11329)
+ 0x1102, 0x1162, 0,
+#undef V3325
+#define V3325 (V + 11332)
+ 0x1102, 0x1162, 0x11a8, 0,
+#undef V3326
+#define V3326 (V + 11336)
+ 0x1102, 0x1162, 0x11a9, 0,
+#undef V3327
+#define V3327 (V + 11340)
+ 0x1102, 0x1162, 0x11aa, 0,
+#undef V3328
+#define V3328 (V + 11344)
+ 0x1102, 0x1162, 0x11ab, 0,
+#undef V3329
+#define V3329 (V + 11348)
+ 0x1102, 0x1162, 0x11ac, 0,
+#undef V3330
+#define V3330 (V + 11352)
+ 0x1102, 0x1162, 0x11ad, 0,
+#undef V3331
+#define V3331 (V + 11356)
+ 0x1102, 0x1162, 0x11ae, 0,
+#undef V3332
+#define V3332 (V + 11360)
+ 0x1102, 0x1162, 0x11af, 0,
+#undef V3333
+#define V3333 (V + 11364)
+ 0x1102, 0x1162, 0x11b0, 0,
+#undef V3334
+#define V3334 (V + 11368)
+ 0x1102, 0x1162, 0x11b1, 0,
+#undef V3335
+#define V3335 (V + 11372)
+ 0x1102, 0x1162, 0x11b2, 0,
+#undef V3336
+#define V3336 (V + 11376)
+ 0x1102, 0x1162, 0x11b3, 0,
+#undef V3337
+#define V3337 (V + 11380)
+ 0x1102, 0x1162, 0x11b4, 0,
+#undef V3338
+#define V3338 (V + 11384)
+ 0x1102, 0x1162, 0x11b5, 0,
+#undef V3339
+#define V3339 (V + 11388)
+ 0x1102, 0x1162, 0x11b6, 0,
+#undef V3340
+#define V3340 (V + 11392)
+ 0x1102, 0x1162, 0x11b7, 0,
+#undef V3341
+#define V3341 (V + 11396)
+ 0x1102, 0x1162, 0x11b8, 0,
+#undef V3342
+#define V3342 (V + 11400)
+ 0x1102, 0x1162, 0x11b9, 0,
+#undef V3343
+#define V3343 (V + 11404)
+ 0x1102, 0x1162, 0x11ba, 0,
+#undef V3344
+#define V3344 (V + 11408)
+ 0x1102, 0x1162, 0x11bb, 0,
+#undef V3345
+#define V3345 (V + 11412)
+ 0x1102, 0x1162, 0x11bc, 0,
+#undef V3346
+#define V3346 (V + 11416)
+ 0x1102, 0x1162, 0x11bd, 0,
+#undef V3347
+#define V3347 (V + 11420)
+ 0x1102, 0x1162, 0x11be, 0,
+#undef V3348
+#define V3348 (V + 11424)
+ 0x1102, 0x1162, 0x11bf, 0,
+#undef V3349
+#define V3349 (V + 11428)
+ 0x1102, 0x1162, 0x11c0, 0,
+#undef V3350
+#define V3350 (V + 11432)
+ 0x1102, 0x1162, 0x11c1, 0,
+#undef V3351
+#define V3351 (V + 11436)
+ 0x1102, 0x1162, 0x11c2, 0,
+#undef V3352
+#define V3352 (V + 11440)
+ 0x1102, 0x1163, 0,
+#undef V3353
+#define V3353 (V + 11443)
+ 0x1102, 0x1163, 0x11a8, 0,
+#undef V3354
+#define V3354 (V + 11447)
+ 0x1102, 0x1163, 0x11a9, 0,
+#undef V3355
+#define V3355 (V + 11451)
+ 0x1102, 0x1163, 0x11aa, 0,
+#undef V3356
+#define V3356 (V + 11455)
+ 0x1102, 0x1163, 0x11ab, 0,
+#undef V3357
+#define V3357 (V + 11459)
+ 0x1102, 0x1163, 0x11ac, 0,
+#undef V3358
+#define V3358 (V + 11463)
+ 0x1102, 0x1163, 0x11ad, 0,
+#undef V3359
+#define V3359 (V + 11467)
+ 0x1102, 0x1163, 0x11ae, 0,
+#undef V3360
+#define V3360 (V + 11471)
+ 0x1102, 0x1163, 0x11af, 0,
+#undef V3361
+#define V3361 (V + 11475)
+ 0x1102, 0x1163, 0x11b0, 0,
+#undef V3362
+#define V3362 (V + 11479)
+ 0x1102, 0x1163, 0x11b1, 0,
+#undef V3363
+#define V3363 (V + 11483)
+ 0x1102, 0x1163, 0x11b2, 0,
+#undef V3364
+#define V3364 (V + 11487)
+ 0x1102, 0x1163, 0x11b3, 0,
+#undef V3365
+#define V3365 (V + 11491)
+ 0x1102, 0x1163, 0x11b4, 0,
+#undef V3366
+#define V3366 (V + 11495)
+ 0x1102, 0x1163, 0x11b5, 0,
+#undef V3367
+#define V3367 (V + 11499)
+ 0x1102, 0x1163, 0x11b6, 0,
+#undef V3368
+#define V3368 (V + 11503)
+ 0x1102, 0x1163, 0x11b7, 0,
+#undef V3369
+#define V3369 (V + 11507)
+ 0x1102, 0x1163, 0x11b8, 0,
+#undef V3370
+#define V3370 (V + 11511)
+ 0x1102, 0x1163, 0x11b9, 0,
+#undef V3371
+#define V3371 (V + 11515)
+ 0x1102, 0x1163, 0x11ba, 0,
+#undef V3372
+#define V3372 (V + 11519)
+ 0x1102, 0x1163, 0x11bb, 0,
+#undef V3373
+#define V3373 (V + 11523)
+ 0x1102, 0x1163, 0x11bc, 0,
+#undef V3374
+#define V3374 (V + 11527)
+ 0x1102, 0x1163, 0x11bd, 0,
+#undef V3375
+#define V3375 (V + 11531)
+ 0x1102, 0x1163, 0x11be, 0,
+#undef V3376
+#define V3376 (V + 11535)
+ 0x1102, 0x1163, 0x11bf, 0,
+#undef V3377
+#define V3377 (V + 11539)
+ 0x1102, 0x1163, 0x11c0, 0,
+#undef V3378
+#define V3378 (V + 11543)
+ 0x1102, 0x1163, 0x11c1, 0,
+#undef V3379
+#define V3379 (V + 11547)
+ 0x1102, 0x1163, 0x11c2, 0,
+#undef V3380
+#define V3380 (V + 11551)
+ 0x1102, 0x1164, 0,
+#undef V3381
+#define V3381 (V + 11554)
+ 0x1102, 0x1164, 0x11a8, 0,
+#undef V3382
+#define V3382 (V + 11558)
+ 0x1102, 0x1164, 0x11a9, 0,
+#undef V3383
+#define V3383 (V + 11562)
+ 0x1102, 0x1164, 0x11aa, 0,
+#undef V3384
+#define V3384 (V + 11566)
+ 0x1102, 0x1164, 0x11ab, 0,
+#undef V3385
+#define V3385 (V + 11570)
+ 0x1102, 0x1164, 0x11ac, 0,
+#undef V3386
+#define V3386 (V + 11574)
+ 0x1102, 0x1164, 0x11ad, 0,
+#undef V3387
+#define V3387 (V + 11578)
+ 0x1102, 0x1164, 0x11ae, 0,
+#undef V3388
+#define V3388 (V + 11582)
+ 0x1102, 0x1164, 0x11af, 0,
+#undef V3389
+#define V3389 (V + 11586)
+ 0x1102, 0x1164, 0x11b0, 0,
+#undef V3390
+#define V3390 (V + 11590)
+ 0x1102, 0x1164, 0x11b1, 0,
+#undef V3391
+#define V3391 (V + 11594)
+ 0x1102, 0x1164, 0x11b2, 0,
+#undef V3392
+#define V3392 (V + 11598)
+ 0x1102, 0x1164, 0x11b3, 0,
+#undef V3393
+#define V3393 (V + 11602)
+ 0x1102, 0x1164, 0x11b4, 0,
+#undef V3394
+#define V3394 (V + 11606)
+ 0x1102, 0x1164, 0x11b5, 0,
+#undef V3395
+#define V3395 (V + 11610)
+ 0x1102, 0x1164, 0x11b6, 0,
+#undef V3396
+#define V3396 (V + 11614)
+ 0x1102, 0x1164, 0x11b7, 0,
+#undef V3397
+#define V3397 (V + 11618)
+ 0x1102, 0x1164, 0x11b8, 0,
+#undef V3398
+#define V3398 (V + 11622)
+ 0x1102, 0x1164, 0x11b9, 0,
+#undef V3399
+#define V3399 (V + 11626)
+ 0x1102, 0x1164, 0x11ba, 0,
+#undef V3400
+#define V3400 (V + 11630)
+ 0x1102, 0x1164, 0x11bb, 0,
+#undef V3401
+#define V3401 (V + 11634)
+ 0x1102, 0x1164, 0x11bc, 0,
+#undef V3402
+#define V3402 (V + 11638)
+ 0x1102, 0x1164, 0x11bd, 0,
+#undef V3403
+#define V3403 (V + 11642)
+ 0x1102, 0x1164, 0x11be, 0,
+#undef V3404
+#define V3404 (V + 11646)
+ 0x1102, 0x1164, 0x11bf, 0,
+#undef V3405
+#define V3405 (V + 11650)
+ 0x1102, 0x1164, 0x11c0, 0,
+#undef V3406
+#define V3406 (V + 11654)
+ 0x1102, 0x1164, 0x11c1, 0,
+#undef V3407
+#define V3407 (V + 11658)
+ 0x1102, 0x1164, 0x11c2, 0,
+#undef V3408
+#define V3408 (V + 11662)
+ 0x1102, 0x1165, 0,
+#undef V3409
+#define V3409 (V + 11665)
+ 0x1102, 0x1165, 0x11a8, 0,
+#undef V3410
+#define V3410 (V + 11669)
+ 0x1102, 0x1165, 0x11a9, 0,
+#undef V3411
+#define V3411 (V + 11673)
+ 0x1102, 0x1165, 0x11aa, 0,
+#undef V3412
+#define V3412 (V + 11677)
+ 0x1102, 0x1165, 0x11ab, 0,
+#undef V3413
+#define V3413 (V + 11681)
+ 0x1102, 0x1165, 0x11ac, 0,
+#undef V3414
+#define V3414 (V + 11685)
+ 0x1102, 0x1165, 0x11ad, 0,
+#undef V3415
+#define V3415 (V + 11689)
+ 0x1102, 0x1165, 0x11ae, 0,
+#undef V3416
+#define V3416 (V + 11693)
+ 0x1102, 0x1165, 0x11af, 0,
+#undef V3417
+#define V3417 (V + 11697)
+ 0x1102, 0x1165, 0x11b0, 0,
+#undef V3418
+#define V3418 (V + 11701)
+ 0x1102, 0x1165, 0x11b1, 0,
+#undef V3419
+#define V3419 (V + 11705)
+ 0x1102, 0x1165, 0x11b2, 0,
+#undef V3420
+#define V3420 (V + 11709)
+ 0x1102, 0x1165, 0x11b3, 0,
+#undef V3421
+#define V3421 (V + 11713)
+ 0x1102, 0x1165, 0x11b4, 0,
+#undef V3422
+#define V3422 (V + 11717)
+ 0x1102, 0x1165, 0x11b5, 0,
+#undef V3423
+#define V3423 (V + 11721)
+ 0x1102, 0x1165, 0x11b6, 0,
+#undef V3424
+#define V3424 (V + 11725)
+ 0x1102, 0x1165, 0x11b7, 0,
+#undef V3425
+#define V3425 (V + 11729)
+ 0x1102, 0x1165, 0x11b8, 0,
+#undef V3426
+#define V3426 (V + 11733)
+ 0x1102, 0x1165, 0x11b9, 0,
+#undef V3427
+#define V3427 (V + 11737)
+ 0x1102, 0x1165, 0x11ba, 0,
+#undef V3428
+#define V3428 (V + 11741)
+ 0x1102, 0x1165, 0x11bb, 0,
+#undef V3429
+#define V3429 (V + 11745)
+ 0x1102, 0x1165, 0x11bc, 0,
+#undef V3430
+#define V3430 (V + 11749)
+ 0x1102, 0x1165, 0x11bd, 0,
+#undef V3431
+#define V3431 (V + 11753)
+ 0x1102, 0x1165, 0x11be, 0,
+#undef V3432
+#define V3432 (V + 11757)
+ 0x1102, 0x1165, 0x11bf, 0,
+#undef V3433
+#define V3433 (V + 11761)
+ 0x1102, 0x1165, 0x11c0, 0,
+#undef V3434
+#define V3434 (V + 11765)
+ 0x1102, 0x1165, 0x11c1, 0,
+#undef V3435
+#define V3435 (V + 11769)
+ 0x1102, 0x1165, 0x11c2, 0,
+#undef V3436
+#define V3436 (V + 11773)
+ 0x1102, 0x1166, 0,
+#undef V3437
+#define V3437 (V + 11776)
+ 0x1102, 0x1166, 0x11a8, 0,
+#undef V3438
+#define V3438 (V + 11780)
+ 0x1102, 0x1166, 0x11a9, 0,
+#undef V3439
+#define V3439 (V + 11784)
+ 0x1102, 0x1166, 0x11aa, 0,
+#undef V3440
+#define V3440 (V + 11788)
+ 0x1102, 0x1166, 0x11ab, 0,
+#undef V3441
+#define V3441 (V + 11792)
+ 0x1102, 0x1166, 0x11ac, 0,
+#undef V3442
+#define V3442 (V + 11796)
+ 0x1102, 0x1166, 0x11ad, 0,
+#undef V3443
+#define V3443 (V + 11800)
+ 0x1102, 0x1166, 0x11ae, 0,
+#undef V3444
+#define V3444 (V + 11804)
+ 0x1102, 0x1166, 0x11af, 0,
+#undef V3445
+#define V3445 (V + 11808)
+ 0x1102, 0x1166, 0x11b0, 0,
+#undef V3446
+#define V3446 (V + 11812)
+ 0x1102, 0x1166, 0x11b1, 0,
+#undef V3447
+#define V3447 (V + 11816)
+ 0x1102, 0x1166, 0x11b2, 0,
+#undef V3448
+#define V3448 (V + 11820)
+ 0x1102, 0x1166, 0x11b3, 0,
+#undef V3449
+#define V3449 (V + 11824)
+ 0x1102, 0x1166, 0x11b4, 0,
+#undef V3450
+#define V3450 (V + 11828)
+ 0x1102, 0x1166, 0x11b5, 0,
+#undef V3451
+#define V3451 (V + 11832)
+ 0x1102, 0x1166, 0x11b6, 0,
+#undef V3452
+#define V3452 (V + 11836)
+ 0x1102, 0x1166, 0x11b7, 0,
+#undef V3453
+#define V3453 (V + 11840)
+ 0x1102, 0x1166, 0x11b8, 0,
+#undef V3454
+#define V3454 (V + 11844)
+ 0x1102, 0x1166, 0x11b9, 0,
+#undef V3455
+#define V3455 (V + 11848)
+ 0x1102, 0x1166, 0x11ba, 0,
+#undef V3456
+#define V3456 (V + 11852)
+ 0x1102, 0x1166, 0x11bb, 0,
+#undef V3457
+#define V3457 (V + 11856)
+ 0x1102, 0x1166, 0x11bc, 0,
+#undef V3458
+#define V3458 (V + 11860)
+ 0x1102, 0x1166, 0x11bd, 0,
+#undef V3459
+#define V3459 (V + 11864)
+ 0x1102, 0x1166, 0x11be, 0,
+#undef V3460
+#define V3460 (V + 11868)
+ 0x1102, 0x1166, 0x11bf, 0,
+#undef V3461
+#define V3461 (V + 11872)
+ 0x1102, 0x1166, 0x11c0, 0,
+#undef V3462
+#define V3462 (V + 11876)
+ 0x1102, 0x1166, 0x11c1, 0,
+#undef V3463
+#define V3463 (V + 11880)
+ 0x1102, 0x1166, 0x11c2, 0,
+#undef V3464
+#define V3464 (V + 11884)
+ 0x1102, 0x1167, 0,
+#undef V3465
+#define V3465 (V + 11887)
+ 0x1102, 0x1167, 0x11a8, 0,
+#undef V3466
+#define V3466 (V + 11891)
+ 0x1102, 0x1167, 0x11a9, 0,
+#undef V3467
+#define V3467 (V + 11895)
+ 0x1102, 0x1167, 0x11aa, 0,
+#undef V3468
+#define V3468 (V + 11899)
+ 0x1102, 0x1167, 0x11ab, 0,
+#undef V3469
+#define V3469 (V + 11903)
+ 0x1102, 0x1167, 0x11ac, 0,
+#undef V3470
+#define V3470 (V + 11907)
+ 0x1102, 0x1167, 0x11ad, 0,
+#undef V3471
+#define V3471 (V + 11911)
+ 0x1102, 0x1167, 0x11ae, 0,
+#undef V3472
+#define V3472 (V + 11915)
+ 0x1102, 0x1167, 0x11af, 0,
+#undef V3473
+#define V3473 (V + 11919)
+ 0x1102, 0x1167, 0x11b0, 0,
+#undef V3474
+#define V3474 (V + 11923)
+ 0x1102, 0x1167, 0x11b1, 0,
+#undef V3475
+#define V3475 (V + 11927)
+ 0x1102, 0x1167, 0x11b2, 0,
+#undef V3476
+#define V3476 (V + 11931)
+ 0x1102, 0x1167, 0x11b3, 0,
+#undef V3477
+#define V3477 (V + 11935)
+ 0x1102, 0x1167, 0x11b4, 0,
+#undef V3478
+#define V3478 (V + 11939)
+ 0x1102, 0x1167, 0x11b5, 0,
+#undef V3479
+#define V3479 (V + 11943)
+ 0x1102, 0x1167, 0x11b6, 0,
+#undef V3480
+#define V3480 (V + 11947)
+ 0x1102, 0x1167, 0x11b7, 0,
+#undef V3481
+#define V3481 (V + 11951)
+ 0x1102, 0x1167, 0x11b8, 0,
+#undef V3482
+#define V3482 (V + 11955)
+ 0x1102, 0x1167, 0x11b9, 0,
+#undef V3483
+#define V3483 (V + 11959)
+ 0x1102, 0x1167, 0x11ba, 0,
+#undef V3484
+#define V3484 (V + 11963)
+ 0x1102, 0x1167, 0x11bb, 0,
+#undef V3485
+#define V3485 (V + 11967)
+ 0x1102, 0x1167, 0x11bc, 0,
+#undef V3486
+#define V3486 (V + 11971)
+ 0x1102, 0x1167, 0x11bd, 0,
+#undef V3487
+#define V3487 (V + 11975)
+ 0x1102, 0x1167, 0x11be, 0,
+#undef V3488
+#define V3488 (V + 11979)
+ 0x1102, 0x1167, 0x11bf, 0,
+#undef V3489
+#define V3489 (V + 11983)
+ 0x1102, 0x1167, 0x11c0, 0,
+#undef V3490
+#define V3490 (V + 11987)
+ 0x1102, 0x1167, 0x11c1, 0,
+#undef V3491
+#define V3491 (V + 11991)
+ 0x1102, 0x1167, 0x11c2, 0,
+#undef V3492
+#define V3492 (V + 11995)
+ 0x1102, 0x1168, 0,
+#undef V3493
+#define V3493 (V + 11998)
+ 0x1102, 0x1168, 0x11a8, 0,
+#undef V3494
+#define V3494 (V + 12002)
+ 0x1102, 0x1168, 0x11a9, 0,
+#undef V3495
+#define V3495 (V + 12006)
+ 0x1102, 0x1168, 0x11aa, 0,
+#undef V3496
+#define V3496 (V + 12010)
+ 0x1102, 0x1168, 0x11ab, 0,
+#undef V3497
+#define V3497 (V + 12014)
+ 0x1102, 0x1168, 0x11ac, 0,
+#undef V3498
+#define V3498 (V + 12018)
+ 0x1102, 0x1168, 0x11ad, 0,
+#undef V3499
+#define V3499 (V + 12022)
+ 0x1102, 0x1168, 0x11ae, 0,
+#undef V3500
+#define V3500 (V + 12026)
+ 0x1102, 0x1168, 0x11af, 0,
+#undef V3501
+#define V3501 (V + 12030)
+ 0x1102, 0x1168, 0x11b0, 0,
+#undef V3502
+#define V3502 (V + 12034)
+ 0x1102, 0x1168, 0x11b1, 0,
+#undef V3503
+#define V3503 (V + 12038)
+ 0x1102, 0x1168, 0x11b2, 0,
+#undef V3504
+#define V3504 (V + 12042)
+ 0x1102, 0x1168, 0x11b3, 0,
+#undef V3505
+#define V3505 (V + 12046)
+ 0x1102, 0x1168, 0x11b4, 0,
+#undef V3506
+#define V3506 (V + 12050)
+ 0x1102, 0x1168, 0x11b5, 0,
+#undef V3507
+#define V3507 (V + 12054)
+ 0x1102, 0x1168, 0x11b6, 0,
+#undef V3508
+#define V3508 (V + 12058)
+ 0x1102, 0x1168, 0x11b7, 0,
+#undef V3509
+#define V3509 (V + 12062)
+ 0x1102, 0x1168, 0x11b8, 0,
+#undef V3510
+#define V3510 (V + 12066)
+ 0x1102, 0x1168, 0x11b9, 0,
+#undef V3511
+#define V3511 (V + 12070)
+ 0x1102, 0x1168, 0x11ba, 0,
+#undef V3512
+#define V3512 (V + 12074)
+ 0x1102, 0x1168, 0x11bb, 0,
+#undef V3513
+#define V3513 (V + 12078)
+ 0x1102, 0x1168, 0x11bc, 0,
+#undef V3514
+#define V3514 (V + 12082)
+ 0x1102, 0x1168, 0x11bd, 0,
+#undef V3515
+#define V3515 (V + 12086)
+ 0x1102, 0x1168, 0x11be, 0,
+#undef V3516
+#define V3516 (V + 12090)
+ 0x1102, 0x1168, 0x11bf, 0,
+#undef V3517
+#define V3517 (V + 12094)
+ 0x1102, 0x1168, 0x11c0, 0,
+#undef V3518
+#define V3518 (V + 12098)
+ 0x1102, 0x1168, 0x11c1, 0,
+#undef V3519
+#define V3519 (V + 12102)
+ 0x1102, 0x1168, 0x11c2, 0,
+#undef V3520
+#define V3520 (V + 12106)
+ 0x1102, 0x1169, 0,
+#undef V3521
+#define V3521 (V + 12109)
+ 0x1102, 0x1169, 0x11a8, 0,
+#undef V3522
+#define V3522 (V + 12113)
+ 0x1102, 0x1169, 0x11a9, 0,
+#undef V3523
+#define V3523 (V + 12117)
+ 0x1102, 0x1169, 0x11aa, 0,
+#undef V3524
+#define V3524 (V + 12121)
+ 0x1102, 0x1169, 0x11ab, 0,
+#undef V3525
+#define V3525 (V + 12125)
+ 0x1102, 0x1169, 0x11ac, 0,
+#undef V3526
+#define V3526 (V + 12129)
+ 0x1102, 0x1169, 0x11ad, 0,
+#undef V3527
+#define V3527 (V + 12133)
+ 0x1102, 0x1169, 0x11ae, 0,
+#undef V3528
+#define V3528 (V + 12137)
+ 0x1102, 0x1169, 0x11af, 0,
+#undef V3529
+#define V3529 (V + 12141)
+ 0x1102, 0x1169, 0x11b0, 0,
+#undef V3530
+#define V3530 (V + 12145)
+ 0x1102, 0x1169, 0x11b1, 0,
+#undef V3531
+#define V3531 (V + 12149)
+ 0x1102, 0x1169, 0x11b2, 0,
+#undef V3532
+#define V3532 (V + 12153)
+ 0x1102, 0x1169, 0x11b3, 0,
+#undef V3533
+#define V3533 (V + 12157)
+ 0x1102, 0x1169, 0x11b4, 0,
+#undef V3534
+#define V3534 (V + 12161)
+ 0x1102, 0x1169, 0x11b5, 0,
+#undef V3535
+#define V3535 (V + 12165)
+ 0x1102, 0x1169, 0x11b6, 0,
+#undef V3536
+#define V3536 (V + 12169)
+ 0x1102, 0x1169, 0x11b7, 0,
+#undef V3537
+#define V3537 (V + 12173)
+ 0x1102, 0x1169, 0x11b8, 0,
+#undef V3538
+#define V3538 (V + 12177)
+ 0x1102, 0x1169, 0x11b9, 0,
+#undef V3539
+#define V3539 (V + 12181)
+ 0x1102, 0x1169, 0x11ba, 0,
+#undef V3540
+#define V3540 (V + 12185)
+ 0x1102, 0x1169, 0x11bb, 0,
+#undef V3541
+#define V3541 (V + 12189)
+ 0x1102, 0x1169, 0x11bc, 0,
+#undef V3542
+#define V3542 (V + 12193)
+ 0x1102, 0x1169, 0x11bd, 0,
+#undef V3543
+#define V3543 (V + 12197)
+ 0x1102, 0x1169, 0x11be, 0,
+#undef V3544
+#define V3544 (V + 12201)
+ 0x1102, 0x1169, 0x11bf, 0,
+#undef V3545
+#define V3545 (V + 12205)
+ 0x1102, 0x1169, 0x11c0, 0,
+#undef V3546
+#define V3546 (V + 12209)
+ 0x1102, 0x1169, 0x11c1, 0,
+#undef V3547
+#define V3547 (V + 12213)
+ 0x1102, 0x1169, 0x11c2, 0,
+#undef V3548
+#define V3548 (V + 12217)
+ 0x1102, 0x116a, 0,
+#undef V3549
+#define V3549 (V + 12220)
+ 0x1102, 0x116a, 0x11a8, 0,
+#undef V3550
+#define V3550 (V + 12224)
+ 0x1102, 0x116a, 0x11a9, 0,
+#undef V3551
+#define V3551 (V + 12228)
+ 0x1102, 0x116a, 0x11aa, 0,
+#undef V3552
+#define V3552 (V + 12232)
+ 0x1102, 0x116a, 0x11ab, 0,
+#undef V3553
+#define V3553 (V + 12236)
+ 0x1102, 0x116a, 0x11ac, 0,
+#undef V3554
+#define V3554 (V + 12240)
+ 0x1102, 0x116a, 0x11ad, 0,
+#undef V3555
+#define V3555 (V + 12244)
+ 0x1102, 0x116a, 0x11ae, 0,
+#undef V3556
+#define V3556 (V + 12248)
+ 0x1102, 0x116a, 0x11af, 0,
+#undef V3557
+#define V3557 (V + 12252)
+ 0x1102, 0x116a, 0x11b0, 0,
+#undef V3558
+#define V3558 (V + 12256)
+ 0x1102, 0x116a, 0x11b1, 0,
+#undef V3559
+#define V3559 (V + 12260)
+ 0x1102, 0x116a, 0x11b2, 0,
+#undef V3560
+#define V3560 (V + 12264)
+ 0x1102, 0x116a, 0x11b3, 0,
+#undef V3561
+#define V3561 (V + 12268)
+ 0x1102, 0x116a, 0x11b4, 0,
+#undef V3562
+#define V3562 (V + 12272)
+ 0x1102, 0x116a, 0x11b5, 0,
+#undef V3563
+#define V3563 (V + 12276)
+ 0x1102, 0x116a, 0x11b6, 0,
+#undef V3564
+#define V3564 (V + 12280)
+ 0x1102, 0x116a, 0x11b7, 0,
+#undef V3565
+#define V3565 (V + 12284)
+ 0x1102, 0x116a, 0x11b8, 0,
+#undef V3566
+#define V3566 (V + 12288)
+ 0x1102, 0x116a, 0x11b9, 0,
+#undef V3567
+#define V3567 (V + 12292)
+ 0x1102, 0x116a, 0x11ba, 0,
+#undef V3568
+#define V3568 (V + 12296)
+ 0x1102, 0x116a, 0x11bb, 0,
+#undef V3569
+#define V3569 (V + 12300)
+ 0x1102, 0x116a, 0x11bc, 0,
+#undef V3570
+#define V3570 (V + 12304)
+ 0x1102, 0x116a, 0x11bd, 0,
+#undef V3571
+#define V3571 (V + 12308)
+ 0x1102, 0x116a, 0x11be, 0,
+#undef V3572
+#define V3572 (V + 12312)
+ 0x1102, 0x116a, 0x11bf, 0,
+#undef V3573
+#define V3573 (V + 12316)
+ 0x1102, 0x116a, 0x11c0, 0,
+#undef V3574
+#define V3574 (V + 12320)
+ 0x1102, 0x116a, 0x11c1, 0,
+#undef V3575
+#define V3575 (V + 12324)
+ 0x1102, 0x116a, 0x11c2, 0,
+#undef V3576
+#define V3576 (V + 12328)
+ 0x1102, 0x116b, 0,
+#undef V3577
+#define V3577 (V + 12331)
+ 0x1102, 0x116b, 0x11a8, 0,
+#undef V3578
+#define V3578 (V + 12335)
+ 0x1102, 0x116b, 0x11a9, 0,
+#undef V3579
+#define V3579 (V + 12339)
+ 0x1102, 0x116b, 0x11aa, 0,
+#undef V3580
+#define V3580 (V + 12343)
+ 0x1102, 0x116b, 0x11ab, 0,
+#undef V3581
+#define V3581 (V + 12347)
+ 0x1102, 0x116b, 0x11ac, 0,
+#undef V3582
+#define V3582 (V + 12351)
+ 0x1102, 0x116b, 0x11ad, 0,
+#undef V3583
+#define V3583 (V + 12355)
+ 0x1102, 0x116b, 0x11ae, 0,
+#undef V3584
+#define V3584 (V + 12359)
+ 0x1102, 0x116b, 0x11af, 0,
+#undef V3585
+#define V3585 (V + 12363)
+ 0x1102, 0x116b, 0x11b0, 0,
+#undef V3586
+#define V3586 (V + 12367)
+ 0x1102, 0x116b, 0x11b1, 0,
+#undef V3587
+#define V3587 (V + 12371)
+ 0x1102, 0x116b, 0x11b2, 0,
+#undef V3588
+#define V3588 (V + 12375)
+ 0x1102, 0x116b, 0x11b3, 0,
+#undef V3589
+#define V3589 (V + 12379)
+ 0x1102, 0x116b, 0x11b4, 0,
+#undef V3590
+#define V3590 (V + 12383)
+ 0x1102, 0x116b, 0x11b5, 0,
+#undef V3591
+#define V3591 (V + 12387)
+ 0x1102, 0x116b, 0x11b6, 0,
+#undef V3592
+#define V3592 (V + 12391)
+ 0x1102, 0x116b, 0x11b7, 0,
+#undef V3593
+#define V3593 (V + 12395)
+ 0x1102, 0x116b, 0x11b8, 0,
+#undef V3594
+#define V3594 (V + 12399)
+ 0x1102, 0x116b, 0x11b9, 0,
+#undef V3595
+#define V3595 (V + 12403)
+ 0x1102, 0x116b, 0x11ba, 0,
+#undef V3596
+#define V3596 (V + 12407)
+ 0x1102, 0x116b, 0x11bb, 0,
+#undef V3597
+#define V3597 (V + 12411)
+ 0x1102, 0x116b, 0x11bc, 0,
+#undef V3598
+#define V3598 (V + 12415)
+ 0x1102, 0x116b, 0x11bd, 0,
+#undef V3599
+#define V3599 (V + 12419)
+ 0x1102, 0x116b, 0x11be, 0,
+#undef V3600
+#define V3600 (V + 12423)
+ 0x1102, 0x116b, 0x11bf, 0,
+#undef V3601
+#define V3601 (V + 12427)
+ 0x1102, 0x116b, 0x11c0, 0,
+#undef V3602
+#define V3602 (V + 12431)
+ 0x1102, 0x116b, 0x11c1, 0,
+#undef V3603
+#define V3603 (V + 12435)
+ 0x1102, 0x116b, 0x11c2, 0,
+#undef V3604
+#define V3604 (V + 12439)
+ 0x1102, 0x116c, 0,
+#undef V3605
+#define V3605 (V + 12442)
+ 0x1102, 0x116c, 0x11a8, 0,
+#undef V3606
+#define V3606 (V + 12446)
+ 0x1102, 0x116c, 0x11a9, 0,
+#undef V3607
+#define V3607 (V + 12450)
+ 0x1102, 0x116c, 0x11aa, 0,
+#undef V3608
+#define V3608 (V + 12454)
+ 0x1102, 0x116c, 0x11ab, 0,
+#undef V3609
+#define V3609 (V + 12458)
+ 0x1102, 0x116c, 0x11ac, 0,
+#undef V3610
+#define V3610 (V + 12462)
+ 0x1102, 0x116c, 0x11ad, 0,
+#undef V3611
+#define V3611 (V + 12466)
+ 0x1102, 0x116c, 0x11ae, 0,
+#undef V3612
+#define V3612 (V + 12470)
+ 0x1102, 0x116c, 0x11af, 0,
+#undef V3613
+#define V3613 (V + 12474)
+ 0x1102, 0x116c, 0x11b0, 0,
+#undef V3614
+#define V3614 (V + 12478)
+ 0x1102, 0x116c, 0x11b1, 0,
+#undef V3615
+#define V3615 (V + 12482)
+ 0x1102, 0x116c, 0x11b2, 0,
+#undef V3616
+#define V3616 (V + 12486)
+ 0x1102, 0x116c, 0x11b3, 0,
+#undef V3617
+#define V3617 (V + 12490)
+ 0x1102, 0x116c, 0x11b4, 0,
+#undef V3618
+#define V3618 (V + 12494)
+ 0x1102, 0x116c, 0x11b5, 0,
+#undef V3619
+#define V3619 (V + 12498)
+ 0x1102, 0x116c, 0x11b6, 0,
+#undef V3620
+#define V3620 (V + 12502)
+ 0x1102, 0x116c, 0x11b7, 0,
+#undef V3621
+#define V3621 (V + 12506)
+ 0x1102, 0x116c, 0x11b8, 0,
+#undef V3622
+#define V3622 (V + 12510)
+ 0x1102, 0x116c, 0x11b9, 0,
+#undef V3623
+#define V3623 (V + 12514)
+ 0x1102, 0x116c, 0x11ba, 0,
+#undef V3624
+#define V3624 (V + 12518)
+ 0x1102, 0x116c, 0x11bb, 0,
+#undef V3625
+#define V3625 (V + 12522)
+ 0x1102, 0x116c, 0x11bc, 0,
+#undef V3626
+#define V3626 (V + 12526)
+ 0x1102, 0x116c, 0x11bd, 0,
+#undef V3627
+#define V3627 (V + 12530)
+ 0x1102, 0x116c, 0x11be, 0,
+#undef V3628
+#define V3628 (V + 12534)
+ 0x1102, 0x116c, 0x11bf, 0,
+#undef V3629
+#define V3629 (V + 12538)
+ 0x1102, 0x116c, 0x11c0, 0,
+#undef V3630
+#define V3630 (V + 12542)
+ 0x1102, 0x116c, 0x11c1, 0,
+#undef V3631
+#define V3631 (V + 12546)
+ 0x1102, 0x116c, 0x11c2, 0,
+#undef V3632
+#define V3632 (V + 12550)
+ 0x1102, 0x116d, 0,
+#undef V3633
+#define V3633 (V + 12553)
+ 0x1102, 0x116d, 0x11a8, 0,
+#undef V3634
+#define V3634 (V + 12557)
+ 0x1102, 0x116d, 0x11a9, 0,
+#undef V3635
+#define V3635 (V + 12561)
+ 0x1102, 0x116d, 0x11aa, 0,
+#undef V3636
+#define V3636 (V + 12565)
+ 0x1102, 0x116d, 0x11ab, 0,
+#undef V3637
+#define V3637 (V + 12569)
+ 0x1102, 0x116d, 0x11ac, 0,
+#undef V3638
+#define V3638 (V + 12573)
+ 0x1102, 0x116d, 0x11ad, 0,
+#undef V3639
+#define V3639 (V + 12577)
+ 0x1102, 0x116d, 0x11ae, 0,
+#undef V3640
+#define V3640 (V + 12581)
+ 0x1102, 0x116d, 0x11af, 0,
+#undef V3641
+#define V3641 (V + 12585)
+ 0x1102, 0x116d, 0x11b0, 0,
+#undef V3642
+#define V3642 (V + 12589)
+ 0x1102, 0x116d, 0x11b1, 0,
+#undef V3643
+#define V3643 (V + 12593)
+ 0x1102, 0x116d, 0x11b2, 0,
+#undef V3644
+#define V3644 (V + 12597)
+ 0x1102, 0x116d, 0x11b3, 0,
+#undef V3645
+#define V3645 (V + 12601)
+ 0x1102, 0x116d, 0x11b4, 0,
+#undef V3646
+#define V3646 (V + 12605)
+ 0x1102, 0x116d, 0x11b5, 0,
+#undef V3647
+#define V3647 (V + 12609)
+ 0x1102, 0x116d, 0x11b6, 0,
+#undef V3648
+#define V3648 (V + 12613)
+ 0x1102, 0x116d, 0x11b7, 0,
+#undef V3649
+#define V3649 (V + 12617)
+ 0x1102, 0x116d, 0x11b8, 0,
+#undef V3650
+#define V3650 (V + 12621)
+ 0x1102, 0x116d, 0x11b9, 0,
+#undef V3651
+#define V3651 (V + 12625)
+ 0x1102, 0x116d, 0x11ba, 0,
+#undef V3652
+#define V3652 (V + 12629)
+ 0x1102, 0x116d, 0x11bb, 0,
+#undef V3653
+#define V3653 (V + 12633)
+ 0x1102, 0x116d, 0x11bc, 0,
+#undef V3654
+#define V3654 (V + 12637)
+ 0x1102, 0x116d, 0x11bd, 0,
+#undef V3655
+#define V3655 (V + 12641)
+ 0x1102, 0x116d, 0x11be, 0,
+#undef V3656
+#define V3656 (V + 12645)
+ 0x1102, 0x116d, 0x11bf, 0,
+#undef V3657
+#define V3657 (V + 12649)
+ 0x1102, 0x116d, 0x11c0, 0,
+#undef V3658
+#define V3658 (V + 12653)
+ 0x1102, 0x116d, 0x11c1, 0,
+#undef V3659
+#define V3659 (V + 12657)
+ 0x1102, 0x116d, 0x11c2, 0,
+#undef V3660
+#define V3660 (V + 12661)
+ 0x1102, 0x116e, 0,
+#undef V3661
+#define V3661 (V + 12664)
+ 0x1102, 0x116e, 0x11a8, 0,
+#undef V3662
+#define V3662 (V + 12668)
+ 0x1102, 0x116e, 0x11a9, 0,
+#undef V3663
+#define V3663 (V + 12672)
+ 0x1102, 0x116e, 0x11aa, 0,
+#undef V3664
+#define V3664 (V + 12676)
+ 0x1102, 0x116e, 0x11ab, 0,
+#undef V3665
+#define V3665 (V + 12680)
+ 0x1102, 0x116e, 0x11ac, 0,
+#undef V3666
+#define V3666 (V + 12684)
+ 0x1102, 0x116e, 0x11ad, 0,
+#undef V3667
+#define V3667 (V + 12688)
+ 0x1102, 0x116e, 0x11ae, 0,
+#undef V3668
+#define V3668 (V + 12692)
+ 0x1102, 0x116e, 0x11af, 0,
+#undef V3669
+#define V3669 (V + 12696)
+ 0x1102, 0x116e, 0x11b0, 0,
+#undef V3670
+#define V3670 (V + 12700)
+ 0x1102, 0x116e, 0x11b1, 0,
+#undef V3671
+#define V3671 (V + 12704)
+ 0x1102, 0x116e, 0x11b2, 0,
+#undef V3672
+#define V3672 (V + 12708)
+ 0x1102, 0x116e, 0x11b3, 0,
+#undef V3673
+#define V3673 (V + 12712)
+ 0x1102, 0x116e, 0x11b4, 0,
+#undef V3674
+#define V3674 (V + 12716)
+ 0x1102, 0x116e, 0x11b5, 0,
+#undef V3675
+#define V3675 (V + 12720)
+ 0x1102, 0x116e, 0x11b6, 0,
+#undef V3676
+#define V3676 (V + 12724)
+ 0x1102, 0x116e, 0x11b7, 0,
+#undef V3677
+#define V3677 (V + 12728)
+ 0x1102, 0x116e, 0x11b8, 0,
+#undef V3678
+#define V3678 (V + 12732)
+ 0x1102, 0x116e, 0x11b9, 0,
+#undef V3679
+#define V3679 (V + 12736)
+ 0x1102, 0x116e, 0x11ba, 0,
+#undef V3680
+#define V3680 (V + 12740)
+ 0x1102, 0x116e, 0x11bb, 0,
+#undef V3681
+#define V3681 (V + 12744)
+ 0x1102, 0x116e, 0x11bc, 0,
+#undef V3682
+#define V3682 (V + 12748)
+ 0x1102, 0x116e, 0x11bd, 0,
+#undef V3683
+#define V3683 (V + 12752)
+ 0x1102, 0x116e, 0x11be, 0,
+#undef V3684
+#define V3684 (V + 12756)
+ 0x1102, 0x116e, 0x11bf, 0,
+#undef V3685
+#define V3685 (V + 12760)
+ 0x1102, 0x116e, 0x11c0, 0,
+#undef V3686
+#define V3686 (V + 12764)
+ 0x1102, 0x116e, 0x11c1, 0,
+#undef V3687
+#define V3687 (V + 12768)
+ 0x1102, 0x116e, 0x11c2, 0,
+#undef V3688
+#define V3688 (V + 12772)
+ 0x1102, 0x116f, 0,
+#undef V3689
+#define V3689 (V + 12775)
+ 0x1102, 0x116f, 0x11a8, 0,
+#undef V3690
+#define V3690 (V + 12779)
+ 0x1102, 0x116f, 0x11a9, 0,
+#undef V3691
+#define V3691 (V + 12783)
+ 0x1102, 0x116f, 0x11aa, 0,
+#undef V3692
+#define V3692 (V + 12787)
+ 0x1102, 0x116f, 0x11ab, 0,
+#undef V3693
+#define V3693 (V + 12791)
+ 0x1102, 0x116f, 0x11ac, 0,
+#undef V3694
+#define V3694 (V + 12795)
+ 0x1102, 0x116f, 0x11ad, 0,
+#undef V3695
+#define V3695 (V + 12799)
+ 0x1102, 0x116f, 0x11ae, 0,
+#undef V3696
+#define V3696 (V + 12803)
+ 0x1102, 0x116f, 0x11af, 0,
+#undef V3697
+#define V3697 (V + 12807)
+ 0x1102, 0x116f, 0x11b0, 0,
+#undef V3698
+#define V3698 (V + 12811)
+ 0x1102, 0x116f, 0x11b1, 0,
+#undef V3699
+#define V3699 (V + 12815)
+ 0x1102, 0x116f, 0x11b2, 0,
+#undef V3700
+#define V3700 (V + 12819)
+ 0x1102, 0x116f, 0x11b3, 0,
+#undef V3701
+#define V3701 (V + 12823)
+ 0x1102, 0x116f, 0x11b4, 0,
+#undef V3702
+#define V3702 (V + 12827)
+ 0x1102, 0x116f, 0x11b5, 0,
+#undef V3703
+#define V3703 (V + 12831)
+ 0x1102, 0x116f, 0x11b6, 0,
+#undef V3704
+#define V3704 (V + 12835)
+ 0x1102, 0x116f, 0x11b7, 0,
+#undef V3705
+#define V3705 (V + 12839)
+ 0x1102, 0x116f, 0x11b8, 0,
+#undef V3706
+#define V3706 (V + 12843)
+ 0x1102, 0x116f, 0x11b9, 0,
+#undef V3707
+#define V3707 (V + 12847)
+ 0x1102, 0x116f, 0x11ba, 0,
+#undef V3708
+#define V3708 (V + 12851)
+ 0x1102, 0x116f, 0x11bb, 0,
+#undef V3709
+#define V3709 (V + 12855)
+ 0x1102, 0x116f, 0x11bc, 0,
+#undef V3710
+#define V3710 (V + 12859)
+ 0x1102, 0x116f, 0x11bd, 0,
+#undef V3711
+#define V3711 (V + 12863)
+ 0x1102, 0x116f, 0x11be, 0,
+#undef V3712
+#define V3712 (V + 12867)
+ 0x1102, 0x116f, 0x11bf, 0,
+#undef V3713
+#define V3713 (V + 12871)
+ 0x1102, 0x116f, 0x11c0, 0,
+#undef V3714
+#define V3714 (V + 12875)
+ 0x1102, 0x116f, 0x11c1, 0,
+#undef V3715
+#define V3715 (V + 12879)
+ 0x1102, 0x116f, 0x11c2, 0,
+#undef V3716
+#define V3716 (V + 12883)
+ 0x1102, 0x1170, 0,
+#undef V3717
+#define V3717 (V + 12886)
+ 0x1102, 0x1170, 0x11a8, 0,
+#undef V3718
+#define V3718 (V + 12890)
+ 0x1102, 0x1170, 0x11a9, 0,
+#undef V3719
+#define V3719 (V + 12894)
+ 0x1102, 0x1170, 0x11aa, 0,
+#undef V3720
+#define V3720 (V + 12898)
+ 0x1102, 0x1170, 0x11ab, 0,
+#undef V3721
+#define V3721 (V + 12902)
+ 0x1102, 0x1170, 0x11ac, 0,
+#undef V3722
+#define V3722 (V + 12906)
+ 0x1102, 0x1170, 0x11ad, 0,
+#undef V3723
+#define V3723 (V + 12910)
+ 0x1102, 0x1170, 0x11ae, 0,
+#undef V3724
+#define V3724 (V + 12914)
+ 0x1102, 0x1170, 0x11af, 0,
+#undef V3725
+#define V3725 (V + 12918)
+ 0x1102, 0x1170, 0x11b0, 0,
+#undef V3726
+#define V3726 (V + 12922)
+ 0x1102, 0x1170, 0x11b1, 0,
+#undef V3727
+#define V3727 (V + 12926)
+ 0x1102, 0x1170, 0x11b2, 0,
+#undef V3728
+#define V3728 (V + 12930)
+ 0x1102, 0x1170, 0x11b3, 0,
+#undef V3729
+#define V3729 (V + 12934)
+ 0x1102, 0x1170, 0x11b4, 0,
+#undef V3730
+#define V3730 (V + 12938)
+ 0x1102, 0x1170, 0x11b5, 0,
+#undef V3731
+#define V3731 (V + 12942)
+ 0x1102, 0x1170, 0x11b6, 0,
+#undef V3732
+#define V3732 (V + 12946)
+ 0x1102, 0x1170, 0x11b7, 0,
+#undef V3733
+#define V3733 (V + 12950)
+ 0x1102, 0x1170, 0x11b8, 0,
+#undef V3734
+#define V3734 (V + 12954)
+ 0x1102, 0x1170, 0x11b9, 0,
+#undef V3735
+#define V3735 (V + 12958)
+ 0x1102, 0x1170, 0x11ba, 0,
+#undef V3736
+#define V3736 (V + 12962)
+ 0x1102, 0x1170, 0x11bb, 0,
+#undef V3737
+#define V3737 (V + 12966)
+ 0x1102, 0x1170, 0x11bc, 0,
+#undef V3738
+#define V3738 (V + 12970)
+ 0x1102, 0x1170, 0x11bd, 0,
+#undef V3739
+#define V3739 (V + 12974)
+ 0x1102, 0x1170, 0x11be, 0,
+#undef V3740
+#define V3740 (V + 12978)
+ 0x1102, 0x1170, 0x11bf, 0,
+#undef V3741
+#define V3741 (V + 12982)
+ 0x1102, 0x1170, 0x11c0, 0,
+#undef V3742
+#define V3742 (V + 12986)
+ 0x1102, 0x1170, 0x11c1, 0,
+#undef V3743
+#define V3743 (V + 12990)
+ 0x1102, 0x1170, 0x11c2, 0,
+#undef V3744
+#define V3744 (V + 12994)
+ 0x1102, 0x1171, 0,
+#undef V3745
+#define V3745 (V + 12997)
+ 0x1102, 0x1171, 0x11a8, 0,
+#undef V3746
+#define V3746 (V + 13001)
+ 0x1102, 0x1171, 0x11a9, 0,
+#undef V3747
+#define V3747 (V + 13005)
+ 0x1102, 0x1171, 0x11aa, 0,
+#undef V3748
+#define V3748 (V + 13009)
+ 0x1102, 0x1171, 0x11ab, 0,
+#undef V3749
+#define V3749 (V + 13013)
+ 0x1102, 0x1171, 0x11ac, 0,
+#undef V3750
+#define V3750 (V + 13017)
+ 0x1102, 0x1171, 0x11ad, 0,
+#undef V3751
+#define V3751 (V + 13021)
+ 0x1102, 0x1171, 0x11ae, 0,
+#undef V3752
+#define V3752 (V + 13025)
+ 0x1102, 0x1171, 0x11af, 0,
+#undef V3753
+#define V3753 (V + 13029)
+ 0x1102, 0x1171, 0x11b0, 0,
+#undef V3754
+#define V3754 (V + 13033)
+ 0x1102, 0x1171, 0x11b1, 0,
+#undef V3755
+#define V3755 (V + 13037)
+ 0x1102, 0x1171, 0x11b2, 0,
+#undef V3756
+#define V3756 (V + 13041)
+ 0x1102, 0x1171, 0x11b3, 0,
+#undef V3757
+#define V3757 (V + 13045)
+ 0x1102, 0x1171, 0x11b4, 0,
+#undef V3758
+#define V3758 (V + 13049)
+ 0x1102, 0x1171, 0x11b5, 0,
+#undef V3759
+#define V3759 (V + 13053)
+ 0x1102, 0x1171, 0x11b6, 0,
+#undef V3760
+#define V3760 (V + 13057)
+ 0x1102, 0x1171, 0x11b7, 0,
+#undef V3761
+#define V3761 (V + 13061)
+ 0x1102, 0x1171, 0x11b8, 0,
+#undef V3762
+#define V3762 (V + 13065)
+ 0x1102, 0x1171, 0x11b9, 0,
+#undef V3763
+#define V3763 (V + 13069)
+ 0x1102, 0x1171, 0x11ba, 0,
+#undef V3764
+#define V3764 (V + 13073)
+ 0x1102, 0x1171, 0x11bb, 0,
+#undef V3765
+#define V3765 (V + 13077)
+ 0x1102, 0x1171, 0x11bc, 0,
+#undef V3766
+#define V3766 (V + 13081)
+ 0x1102, 0x1171, 0x11bd, 0,
+#undef V3767
+#define V3767 (V + 13085)
+ 0x1102, 0x1171, 0x11be, 0,
+#undef V3768
+#define V3768 (V + 13089)
+ 0x1102, 0x1171, 0x11bf, 0,
+#undef V3769
+#define V3769 (V + 13093)
+ 0x1102, 0x1171, 0x11c0, 0,
+#undef V3770
+#define V3770 (V + 13097)
+ 0x1102, 0x1171, 0x11c1, 0,
+#undef V3771
+#define V3771 (V + 13101)
+ 0x1102, 0x1171, 0x11c2, 0,
+#undef V3772
+#define V3772 (V + 13105)
+ 0x1102, 0x1172, 0,
+#undef V3773
+#define V3773 (V + 13108)
+ 0x1102, 0x1172, 0x11a8, 0,
+#undef V3774
+#define V3774 (V + 13112)
+ 0x1102, 0x1172, 0x11a9, 0,
+#undef V3775
+#define V3775 (V + 13116)
+ 0x1102, 0x1172, 0x11aa, 0,
+#undef V3776
+#define V3776 (V + 13120)
+ 0x1102, 0x1172, 0x11ab, 0,
+#undef V3777
+#define V3777 (V + 13124)
+ 0x1102, 0x1172, 0x11ac, 0,
+#undef V3778
+#define V3778 (V + 13128)
+ 0x1102, 0x1172, 0x11ad, 0,
+#undef V3779
+#define V3779 (V + 13132)
+ 0x1102, 0x1172, 0x11ae, 0,
+#undef V3780
+#define V3780 (V + 13136)
+ 0x1102, 0x1172, 0x11af, 0,
+#undef V3781
+#define V3781 (V + 13140)
+ 0x1102, 0x1172, 0x11b0, 0,
+#undef V3782
+#define V3782 (V + 13144)
+ 0x1102, 0x1172, 0x11b1, 0,
+#undef V3783
+#define V3783 (V + 13148)
+ 0x1102, 0x1172, 0x11b2, 0,
+#undef V3784
+#define V3784 (V + 13152)
+ 0x1102, 0x1172, 0x11b3, 0,
+#undef V3785
+#define V3785 (V + 13156)
+ 0x1102, 0x1172, 0x11b4, 0,
+#undef V3786
+#define V3786 (V + 13160)
+ 0x1102, 0x1172, 0x11b5, 0,
+#undef V3787
+#define V3787 (V + 13164)
+ 0x1102, 0x1172, 0x11b6, 0,
+#undef V3788
+#define V3788 (V + 13168)
+ 0x1102, 0x1172, 0x11b7, 0,
+#undef V3789
+#define V3789 (V + 13172)
+ 0x1102, 0x1172, 0x11b8, 0,
+#undef V3790
+#define V3790 (V + 13176)
+ 0x1102, 0x1172, 0x11b9, 0,
+#undef V3791
+#define V3791 (V + 13180)
+ 0x1102, 0x1172, 0x11ba, 0,
+#undef V3792
+#define V3792 (V + 13184)
+ 0x1102, 0x1172, 0x11bb, 0,
+#undef V3793
+#define V3793 (V + 13188)
+ 0x1102, 0x1172, 0x11bc, 0,
+#undef V3794
+#define V3794 (V + 13192)
+ 0x1102, 0x1172, 0x11bd, 0,
+#undef V3795
+#define V3795 (V + 13196)
+ 0x1102, 0x1172, 0x11be, 0,
+#undef V3796
+#define V3796 (V + 13200)
+ 0x1102, 0x1172, 0x11bf, 0,
+#undef V3797
+#define V3797 (V + 13204)
+ 0x1102, 0x1172, 0x11c0, 0,
+#undef V3798
+#define V3798 (V + 13208)
+ 0x1102, 0x1172, 0x11c1, 0,
+#undef V3799
+#define V3799 (V + 13212)
+ 0x1102, 0x1172, 0x11c2, 0,
+#undef V3800
+#define V3800 (V + 13216)
+ 0x1102, 0x1173, 0,
+#undef V3801
+#define V3801 (V + 13219)
+ 0x1102, 0x1173, 0x11a8, 0,
+#undef V3802
+#define V3802 (V + 13223)
+ 0x1102, 0x1173, 0x11a9, 0,
+#undef V3803
+#define V3803 (V + 13227)
+ 0x1102, 0x1173, 0x11aa, 0,
+#undef V3804
+#define V3804 (V + 13231)
+ 0x1102, 0x1173, 0x11ab, 0,
+#undef V3805
+#define V3805 (V + 13235)
+ 0x1102, 0x1173, 0x11ac, 0,
+#undef V3806
+#define V3806 (V + 13239)
+ 0x1102, 0x1173, 0x11ad, 0,
+#undef V3807
+#define V3807 (V + 13243)
+ 0x1102, 0x1173, 0x11ae, 0,
+#undef V3808
+#define V3808 (V + 13247)
+ 0x1102, 0x1173, 0x11af, 0,
+#undef V3809
+#define V3809 (V + 13251)
+ 0x1102, 0x1173, 0x11b0, 0,
+#undef V3810
+#define V3810 (V + 13255)
+ 0x1102, 0x1173, 0x11b1, 0,
+#undef V3811
+#define V3811 (V + 13259)
+ 0x1102, 0x1173, 0x11b2, 0,
+#undef V3812
+#define V3812 (V + 13263)
+ 0x1102, 0x1173, 0x11b3, 0,
+#undef V3813
+#define V3813 (V + 13267)
+ 0x1102, 0x1173, 0x11b4, 0,
+#undef V3814
+#define V3814 (V + 13271)
+ 0x1102, 0x1173, 0x11b5, 0,
+#undef V3815
+#define V3815 (V + 13275)
+ 0x1102, 0x1173, 0x11b6, 0,
+#undef V3816
+#define V3816 (V + 13279)
+ 0x1102, 0x1173, 0x11b7, 0,
+#undef V3817
+#define V3817 (V + 13283)
+ 0x1102, 0x1173, 0x11b8, 0,
+#undef V3818
+#define V3818 (V + 13287)
+ 0x1102, 0x1173, 0x11b9, 0,
+#undef V3819
+#define V3819 (V + 13291)
+ 0x1102, 0x1173, 0x11ba, 0,
+#undef V3820
+#define V3820 (V + 13295)
+ 0x1102, 0x1173, 0x11bb, 0,
+#undef V3821
+#define V3821 (V + 13299)
+ 0x1102, 0x1173, 0x11bc, 0,
+#undef V3822
+#define V3822 (V + 13303)
+ 0x1102, 0x1173, 0x11bd, 0,
+#undef V3823
+#define V3823 (V + 13307)
+ 0x1102, 0x1173, 0x11be, 0,
+#undef V3824
+#define V3824 (V + 13311)
+ 0x1102, 0x1173, 0x11bf, 0,
+#undef V3825
+#define V3825 (V + 13315)
+ 0x1102, 0x1173, 0x11c0, 0,
+#undef V3826
+#define V3826 (V + 13319)
+ 0x1102, 0x1173, 0x11c1, 0,
+#undef V3827
+#define V3827 (V + 13323)
+ 0x1102, 0x1173, 0x11c2, 0,
+#undef V3828
+#define V3828 (V + 13327)
+ 0x1102, 0x1174, 0,
+#undef V3829
+#define V3829 (V + 13330)
+ 0x1102, 0x1174, 0x11a8, 0,
+#undef V3830
+#define V3830 (V + 13334)
+ 0x1102, 0x1174, 0x11a9, 0,
+#undef V3831
+#define V3831 (V + 13338)
+ 0x1102, 0x1174, 0x11aa, 0,
+#undef V3832
+#define V3832 (V + 13342)
+ 0x1102, 0x1174, 0x11ab, 0,
+#undef V3833
+#define V3833 (V + 13346)
+ 0x1102, 0x1174, 0x11ac, 0,
+#undef V3834
+#define V3834 (V + 13350)
+ 0x1102, 0x1174, 0x11ad, 0,
+#undef V3835
+#define V3835 (V + 13354)
+ 0x1102, 0x1174, 0x11ae, 0,
+#undef V3836
+#define V3836 (V + 13358)
+ 0x1102, 0x1174, 0x11af, 0,
+#undef V3837
+#define V3837 (V + 13362)
+ 0x1102, 0x1174, 0x11b0, 0,
+#undef V3838
+#define V3838 (V + 13366)
+ 0x1102, 0x1174, 0x11b1, 0,
+#undef V3839
+#define V3839 (V + 13370)
+ 0x1102, 0x1174, 0x11b2, 0,
+#undef V3840
+#define V3840 (V + 13374)
+ 0x1102, 0x1174, 0x11b3, 0,
+#undef V3841
+#define V3841 (V + 13378)
+ 0x1102, 0x1174, 0x11b4, 0,
+#undef V3842
+#define V3842 (V + 13382)
+ 0x1102, 0x1174, 0x11b5, 0,
+#undef V3843
+#define V3843 (V + 13386)
+ 0x1102, 0x1174, 0x11b6, 0,
+#undef V3844
+#define V3844 (V + 13390)
+ 0x1102, 0x1174, 0x11b7, 0,
+#undef V3845
+#define V3845 (V + 13394)
+ 0x1102, 0x1174, 0x11b8, 0,
+#undef V3846
+#define V3846 (V + 13398)
+ 0x1102, 0x1174, 0x11b9, 0,
+#undef V3847
+#define V3847 (V + 13402)
+ 0x1102, 0x1174, 0x11ba, 0,
+#undef V3848
+#define V3848 (V + 13406)
+ 0x1102, 0x1174, 0x11bb, 0,
+#undef V3849
+#define V3849 (V + 13410)
+ 0x1102, 0x1174, 0x11bc, 0,
+#undef V3850
+#define V3850 (V + 13414)
+ 0x1102, 0x1174, 0x11bd, 0,
+#undef V3851
+#define V3851 (V + 13418)
+ 0x1102, 0x1174, 0x11be, 0,
+#undef V3852
+#define V3852 (V + 13422)
+ 0x1102, 0x1174, 0x11bf, 0,
+#undef V3853
+#define V3853 (V + 13426)
+ 0x1102, 0x1174, 0x11c0, 0,
+#undef V3854
+#define V3854 (V + 13430)
+ 0x1102, 0x1174, 0x11c1, 0,
+#undef V3855
+#define V3855 (V + 13434)
+ 0x1102, 0x1174, 0x11c2, 0,
+#undef V3856
+#define V3856 (V + 13438)
+ 0x1102, 0x1175, 0,
+#undef V3857
+#define V3857 (V + 13441)
+ 0x1102, 0x1175, 0x11a8, 0,
+#undef V3858
+#define V3858 (V + 13445)
+ 0x1102, 0x1175, 0x11a9, 0,
+#undef V3859
+#define V3859 (V + 13449)
+ 0x1102, 0x1175, 0x11aa, 0,
+#undef V3860
+#define V3860 (V + 13453)
+ 0x1102, 0x1175, 0x11ab, 0,
+#undef V3861
+#define V3861 (V + 13457)
+ 0x1102, 0x1175, 0x11ac, 0,
+#undef V3862
+#define V3862 (V + 13461)
+ 0x1102, 0x1175, 0x11ad, 0,
+#undef V3863
+#define V3863 (V + 13465)
+ 0x1102, 0x1175, 0x11ae, 0,
+#undef V3864
+#define V3864 (V + 13469)
+ 0x1102, 0x1175, 0x11af, 0,
+#undef V3865
+#define V3865 (V + 13473)
+ 0x1102, 0x1175, 0x11b0, 0,
+#undef V3866
+#define V3866 (V + 13477)
+ 0x1102, 0x1175, 0x11b1, 0,
+#undef V3867
+#define V3867 (V + 13481)
+ 0x1102, 0x1175, 0x11b2, 0,
+#undef V3868
+#define V3868 (V + 13485)
+ 0x1102, 0x1175, 0x11b3, 0,
+#undef V3869
+#define V3869 (V + 13489)
+ 0x1102, 0x1175, 0x11b4, 0,
+#undef V3870
+#define V3870 (V + 13493)
+ 0x1102, 0x1175, 0x11b5, 0,
+#undef V3871
+#define V3871 (V + 13497)
+ 0x1102, 0x1175, 0x11b6, 0,
+#undef V3872
+#define V3872 (V + 13501)
+ 0x1102, 0x1175, 0x11b7, 0,
+#undef V3873
+#define V3873 (V + 13505)
+ 0x1102, 0x1175, 0x11b8, 0,
+#undef V3874
+#define V3874 (V + 13509)
+ 0x1102, 0x1175, 0x11b9, 0,
+#undef V3875
+#define V3875 (V + 13513)
+ 0x1102, 0x1175, 0x11ba, 0,
+#undef V3876
+#define V3876 (V + 13517)
+ 0x1102, 0x1175, 0x11bb, 0,
+#undef V3877
+#define V3877 (V + 13521)
+ 0x1102, 0x1175, 0x11bc, 0,
+#undef V3878
+#define V3878 (V + 13525)
+ 0x1102, 0x1175, 0x11bd, 0,
+#undef V3879
+#define V3879 (V + 13529)
+ 0x1102, 0x1175, 0x11be, 0,
+#undef V3880
+#define V3880 (V + 13533)
+ 0x1102, 0x1175, 0x11bf, 0,
+#undef V3881
+#define V3881 (V + 13537)
+ 0x1102, 0x1175, 0x11c0, 0,
+#undef V3882
+#define V3882 (V + 13541)
+ 0x1102, 0x1175, 0x11c1, 0,
+#undef V3883
+#define V3883 (V + 13545)
+ 0x1102, 0x1175, 0x11c2, 0,
+#undef V3884
+#define V3884 (V + 13549)
+ 0x1103, 0x1161, 0x11a8, 0,
+#undef V3885
+#define V3885 (V + 13553)
+ 0x1103, 0x1161, 0x11a9, 0,
+#undef V3886
+#define V3886 (V + 13557)
+ 0x1103, 0x1161, 0x11aa, 0,
+#undef V3887
+#define V3887 (V + 13561)
+ 0x1103, 0x1161, 0x11ab, 0,
+#undef V3888
+#define V3888 (V + 13565)
+ 0x1103, 0x1161, 0x11ac, 0,
+#undef V3889
+#define V3889 (V + 13569)
+ 0x1103, 0x1161, 0x11ad, 0,
+#undef V3890
+#define V3890 (V + 13573)
+ 0x1103, 0x1161, 0x11ae, 0,
+#undef V3891
+#define V3891 (V + 13577)
+ 0x1103, 0x1161, 0x11af, 0,
+#undef V3892
+#define V3892 (V + 13581)
+ 0x1103, 0x1161, 0x11b0, 0,
+#undef V3893
+#define V3893 (V + 13585)
+ 0x1103, 0x1161, 0x11b1, 0,
+#undef V3894
+#define V3894 (V + 13589)
+ 0x1103, 0x1161, 0x11b2, 0,
+#undef V3895
+#define V3895 (V + 13593)
+ 0x1103, 0x1161, 0x11b3, 0,
+#undef V3896
+#define V3896 (V + 13597)
+ 0x1103, 0x1161, 0x11b4, 0,
+#undef V3897
+#define V3897 (V + 13601)
+ 0x1103, 0x1161, 0x11b5, 0,
+#undef V3898
+#define V3898 (V + 13605)
+ 0x1103, 0x1161, 0x11b6, 0,
+#undef V3899
+#define V3899 (V + 13609)
+ 0x1103, 0x1161, 0x11b7, 0,
+#undef V3900
+#define V3900 (V + 13613)
+ 0x1103, 0x1161, 0x11b8, 0,
+#undef V3901
+#define V3901 (V + 13617)
+ 0x1103, 0x1161, 0x11b9, 0,
+#undef V3902
+#define V3902 (V + 13621)
+ 0x1103, 0x1161, 0x11ba, 0,
+#undef V3903
+#define V3903 (V + 13625)
+ 0x1103, 0x1161, 0x11bb, 0,
+#undef V3904
+#define V3904 (V + 13629)
+ 0x1103, 0x1161, 0x11bc, 0,
+#undef V3905
+#define V3905 (V + 13633)
+ 0x1103, 0x1161, 0x11bd, 0,
+#undef V3906
+#define V3906 (V + 13637)
+ 0x1103, 0x1161, 0x11be, 0,
+#undef V3907
+#define V3907 (V + 13641)
+ 0x1103, 0x1161, 0x11bf, 0,
+#undef V3908
+#define V3908 (V + 13645)
+ 0x1103, 0x1161, 0x11c0, 0,
+#undef V3909
+#define V3909 (V + 13649)
+ 0x1103, 0x1161, 0x11c1, 0,
+#undef V3910
+#define V3910 (V + 13653)
+ 0x1103, 0x1161, 0x11c2, 0,
+#undef V3911
+#define V3911 (V + 13657)
+ 0x1103, 0x1162, 0,
+#undef V3912
+#define V3912 (V + 13660)
+ 0x1103, 0x1162, 0x11a8, 0,
+#undef V3913
+#define V3913 (V + 13664)
+ 0x1103, 0x1162, 0x11a9, 0,
+#undef V3914
+#define V3914 (V + 13668)
+ 0x1103, 0x1162, 0x11aa, 0,
+#undef V3915
+#define V3915 (V + 13672)
+ 0x1103, 0x1162, 0x11ab, 0,
+#undef V3916
+#define V3916 (V + 13676)
+ 0x1103, 0x1162, 0x11ac, 0,
+#undef V3917
+#define V3917 (V + 13680)
+ 0x1103, 0x1162, 0x11ad, 0,
+#undef V3918
+#define V3918 (V + 13684)
+ 0x1103, 0x1162, 0x11ae, 0,
+#undef V3919
+#define V3919 (V + 13688)
+ 0x1103, 0x1162, 0x11af, 0,
+#undef V3920
+#define V3920 (V + 13692)
+ 0x1103, 0x1162, 0x11b0, 0,
+#undef V3921
+#define V3921 (V + 13696)
+ 0x1103, 0x1162, 0x11b1, 0,
+#undef V3922
+#define V3922 (V + 13700)
+ 0x1103, 0x1162, 0x11b2, 0,
+#undef V3923
+#define V3923 (V + 13704)
+ 0x1103, 0x1162, 0x11b3, 0,
+#undef V3924
+#define V3924 (V + 13708)
+ 0x1103, 0x1162, 0x11b4, 0,
+#undef V3925
+#define V3925 (V + 13712)
+ 0x1103, 0x1162, 0x11b5, 0,
+#undef V3926
+#define V3926 (V + 13716)
+ 0x1103, 0x1162, 0x11b6, 0,
+#undef V3927
+#define V3927 (V + 13720)
+ 0x1103, 0x1162, 0x11b7, 0,
+#undef V3928
+#define V3928 (V + 13724)
+ 0x1103, 0x1162, 0x11b8, 0,
+#undef V3929
+#define V3929 (V + 13728)
+ 0x1103, 0x1162, 0x11b9, 0,
+#undef V3930
+#define V3930 (V + 13732)
+ 0x1103, 0x1162, 0x11ba, 0,
+#undef V3931
+#define V3931 (V + 13736)
+ 0x1103, 0x1162, 0x11bb, 0,
+#undef V3932
+#define V3932 (V + 13740)
+ 0x1103, 0x1162, 0x11bc, 0,
+#undef V3933
+#define V3933 (V + 13744)
+ 0x1103, 0x1162, 0x11bd, 0,
+#undef V3934
+#define V3934 (V + 13748)
+ 0x1103, 0x1162, 0x11be, 0,
+#undef V3935
+#define V3935 (V + 13752)
+ 0x1103, 0x1162, 0x11bf, 0,
+#undef V3936
+#define V3936 (V + 13756)
+ 0x1103, 0x1162, 0x11c0, 0,
+#undef V3937
+#define V3937 (V + 13760)
+ 0x1103, 0x1162, 0x11c1, 0,
+#undef V3938
+#define V3938 (V + 13764)
+ 0x1103, 0x1162, 0x11c2, 0,
+#undef V3939
+#define V3939 (V + 13768)
+ 0x1103, 0x1163, 0,
+#undef V3940
+#define V3940 (V + 13771)
+ 0x1103, 0x1163, 0x11a8, 0,
+#undef V3941
+#define V3941 (V + 13775)
+ 0x1103, 0x1163, 0x11a9, 0,
+#undef V3942
+#define V3942 (V + 13779)
+ 0x1103, 0x1163, 0x11aa, 0,
+#undef V3943
+#define V3943 (V + 13783)
+ 0x1103, 0x1163, 0x11ab, 0,
+#undef V3944
+#define V3944 (V + 13787)
+ 0x1103, 0x1163, 0x11ac, 0,
+#undef V3945
+#define V3945 (V + 13791)
+ 0x1103, 0x1163, 0x11ad, 0,
+#undef V3946
+#define V3946 (V + 13795)
+ 0x1103, 0x1163, 0x11ae, 0,
+#undef V3947
+#define V3947 (V + 13799)
+ 0x1103, 0x1163, 0x11af, 0,
+#undef V3948
+#define V3948 (V + 13803)
+ 0x1103, 0x1163, 0x11b0, 0,
+#undef V3949
+#define V3949 (V + 13807)
+ 0x1103, 0x1163, 0x11b1, 0,
+#undef V3950
+#define V3950 (V + 13811)
+ 0x1103, 0x1163, 0x11b2, 0,
+#undef V3951
+#define V3951 (V + 13815)
+ 0x1103, 0x1163, 0x11b3, 0,
+#undef V3952
+#define V3952 (V + 13819)
+ 0x1103, 0x1163, 0x11b4, 0,
+#undef V3953
+#define V3953 (V + 13823)
+ 0x1103, 0x1163, 0x11b5, 0,
+#undef V3954
+#define V3954 (V + 13827)
+ 0x1103, 0x1163, 0x11b6, 0,
+#undef V3955
+#define V3955 (V + 13831)
+ 0x1103, 0x1163, 0x11b7, 0,
+#undef V3956
+#define V3956 (V + 13835)
+ 0x1103, 0x1163, 0x11b8, 0,
+#undef V3957
+#define V3957 (V + 13839)
+ 0x1103, 0x1163, 0x11b9, 0,
+#undef V3958
+#define V3958 (V + 13843)
+ 0x1103, 0x1163, 0x11ba, 0,
+#undef V3959
+#define V3959 (V + 13847)
+ 0x1103, 0x1163, 0x11bb, 0,
+#undef V3960
+#define V3960 (V + 13851)
+ 0x1103, 0x1163, 0x11bc, 0,
+#undef V3961
+#define V3961 (V + 13855)
+ 0x1103, 0x1163, 0x11bd, 0,
+#undef V3962
+#define V3962 (V + 13859)
+ 0x1103, 0x1163, 0x11be, 0,
+#undef V3963
+#define V3963 (V + 13863)
+ 0x1103, 0x1163, 0x11bf, 0,
+#undef V3964
+#define V3964 (V + 13867)
+ 0x1103, 0x1163, 0x11c0, 0,
+#undef V3965
+#define V3965 (V + 13871)
+ 0x1103, 0x1163, 0x11c1, 0,
+#undef V3966
+#define V3966 (V + 13875)
+ 0x1103, 0x1163, 0x11c2, 0,
+#undef V3967
+#define V3967 (V + 13879)
+ 0x1103, 0x1164, 0,
+#undef V3968
+#define V3968 (V + 13882)
+ 0x1103, 0x1164, 0x11a8, 0,
+#undef V3969
+#define V3969 (V + 13886)
+ 0x1103, 0x1164, 0x11a9, 0,
+#undef V3970
+#define V3970 (V + 13890)
+ 0x1103, 0x1164, 0x11aa, 0,
+#undef V3971
+#define V3971 (V + 13894)
+ 0x1103, 0x1164, 0x11ab, 0,
+#undef V3972
+#define V3972 (V + 13898)
+ 0x1103, 0x1164, 0x11ac, 0,
+#undef V3973
+#define V3973 (V + 13902)
+ 0x1103, 0x1164, 0x11ad, 0,
+#undef V3974
+#define V3974 (V + 13906)
+ 0x1103, 0x1164, 0x11ae, 0,
+#undef V3975
+#define V3975 (V + 13910)
+ 0x1103, 0x1164, 0x11af, 0,
+#undef V3976
+#define V3976 (V + 13914)
+ 0x1103, 0x1164, 0x11b0, 0,
+#undef V3977
+#define V3977 (V + 13918)
+ 0x1103, 0x1164, 0x11b1, 0,
+#undef V3978
+#define V3978 (V + 13922)
+ 0x1103, 0x1164, 0x11b2, 0,
+#undef V3979
+#define V3979 (V + 13926)
+ 0x1103, 0x1164, 0x11b3, 0,
+#undef V3980
+#define V3980 (V + 13930)
+ 0x1103, 0x1164, 0x11b4, 0,
+#undef V3981
+#define V3981 (V + 13934)
+ 0x1103, 0x1164, 0x11b5, 0,
+#undef V3982
+#define V3982 (V + 13938)
+ 0x1103, 0x1164, 0x11b6, 0,
+#undef V3983
+#define V3983 (V + 13942)
+ 0x1103, 0x1164, 0x11b7, 0,
+#undef V3984
+#define V3984 (V + 13946)
+ 0x1103, 0x1164, 0x11b8, 0,
+#undef V3985
+#define V3985 (V + 13950)
+ 0x1103, 0x1164, 0x11b9, 0,
+#undef V3986
+#define V3986 (V + 13954)
+ 0x1103, 0x1164, 0x11ba, 0,
+#undef V3987
+#define V3987 (V + 13958)
+ 0x1103, 0x1164, 0x11bb, 0,
+#undef V3988
+#define V3988 (V + 13962)
+ 0x1103, 0x1164, 0x11bc, 0,
+#undef V3989
+#define V3989 (V + 13966)
+ 0x1103, 0x1164, 0x11bd, 0,
+#undef V3990
+#define V3990 (V + 13970)
+ 0x1103, 0x1164, 0x11be, 0,
+#undef V3991
+#define V3991 (V + 13974)
+ 0x1103, 0x1164, 0x11bf, 0,
+#undef V3992
+#define V3992 (V + 13978)
+ 0x1103, 0x1164, 0x11c0, 0,
+#undef V3993
+#define V3993 (V + 13982)
+ 0x1103, 0x1164, 0x11c1, 0,
+#undef V3994
+#define V3994 (V + 13986)
+ 0x1103, 0x1164, 0x11c2, 0,
+#undef V3995
+#define V3995 (V + 13990)
+ 0x1103, 0x1165, 0,
+#undef V3996
+#define V3996 (V + 13993)
+ 0x1103, 0x1165, 0x11a8, 0,
+#undef V3997
+#define V3997 (V + 13997)
+ 0x1103, 0x1165, 0x11a9, 0,
+#undef V3998
+#define V3998 (V + 14001)
+ 0x1103, 0x1165, 0x11aa, 0,
+#undef V3999
+#define V3999 (V + 14005)
+ 0x1103, 0x1165, 0x11ab, 0,
+#undef V4000
+#define V4000 (V + 14009)
+ 0x1103, 0x1165, 0x11ac, 0,
+#undef V4001
+#define V4001 (V + 14013)
+ 0x1103, 0x1165, 0x11ad, 0,
+#undef V4002
+#define V4002 (V + 14017)
+ 0x1103, 0x1165, 0x11ae, 0,
+#undef V4003
+#define V4003 (V + 14021)
+ 0x1103, 0x1165, 0x11af, 0,
+#undef V4004
+#define V4004 (V + 14025)
+ 0x1103, 0x1165, 0x11b0, 0,
+#undef V4005
+#define V4005 (V + 14029)
+ 0x1103, 0x1165, 0x11b1, 0,
+#undef V4006
+#define V4006 (V + 14033)
+ 0x1103, 0x1165, 0x11b2, 0,
+#undef V4007
+#define V4007 (V + 14037)
+ 0x1103, 0x1165, 0x11b3, 0,
+#undef V4008
+#define V4008 (V + 14041)
+ 0x1103, 0x1165, 0x11b4, 0,
+#undef V4009
+#define V4009 (V + 14045)
+ 0x1103, 0x1165, 0x11b5, 0,
+#undef V4010
+#define V4010 (V + 14049)
+ 0x1103, 0x1165, 0x11b6, 0,
+#undef V4011
+#define V4011 (V + 14053)
+ 0x1103, 0x1165, 0x11b7, 0,
+#undef V4012
+#define V4012 (V + 14057)
+ 0x1103, 0x1165, 0x11b8, 0,
+#undef V4013
+#define V4013 (V + 14061)
+ 0x1103, 0x1165, 0x11b9, 0,
+#undef V4014
+#define V4014 (V + 14065)
+ 0x1103, 0x1165, 0x11ba, 0,
+#undef V4015
+#define V4015 (V + 14069)
+ 0x1103, 0x1165, 0x11bb, 0,
+#undef V4016
+#define V4016 (V + 14073)
+ 0x1103, 0x1165, 0x11bc, 0,
+#undef V4017
+#define V4017 (V + 14077)
+ 0x1103, 0x1165, 0x11bd, 0,
+#undef V4018
+#define V4018 (V + 14081)
+ 0x1103, 0x1165, 0x11be, 0,
+#undef V4019
+#define V4019 (V + 14085)
+ 0x1103, 0x1165, 0x11bf, 0,
+#undef V4020
+#define V4020 (V + 14089)
+ 0x1103, 0x1165, 0x11c0, 0,
+#undef V4021
+#define V4021 (V + 14093)
+ 0x1103, 0x1165, 0x11c1, 0,
+#undef V4022
+#define V4022 (V + 14097)
+ 0x1103, 0x1165, 0x11c2, 0,
+#undef V4023
+#define V4023 (V + 14101)
+ 0x1103, 0x1166, 0,
+#undef V4024
+#define V4024 (V + 14104)
+ 0x1103, 0x1166, 0x11a8, 0,
+#undef V4025
+#define V4025 (V + 14108)
+ 0x1103, 0x1166, 0x11a9, 0,
+#undef V4026
+#define V4026 (V + 14112)
+ 0x1103, 0x1166, 0x11aa, 0,
+#undef V4027
+#define V4027 (V + 14116)
+ 0x1103, 0x1166, 0x11ab, 0,
+#undef V4028
+#define V4028 (V + 14120)
+ 0x1103, 0x1166, 0x11ac, 0,
+#undef V4029
+#define V4029 (V + 14124)
+ 0x1103, 0x1166, 0x11ad, 0,
+#undef V4030
+#define V4030 (V + 14128)
+ 0x1103, 0x1166, 0x11ae, 0,
+#undef V4031
+#define V4031 (V + 14132)
+ 0x1103, 0x1166, 0x11af, 0,
+#undef V4032
+#define V4032 (V + 14136)
+ 0x1103, 0x1166, 0x11b0, 0,
+#undef V4033
+#define V4033 (V + 14140)
+ 0x1103, 0x1166, 0x11b1, 0,
+#undef V4034
+#define V4034 (V + 14144)
+ 0x1103, 0x1166, 0x11b2, 0,
+#undef V4035
+#define V4035 (V + 14148)
+ 0x1103, 0x1166, 0x11b3, 0,
+#undef V4036
+#define V4036 (V + 14152)
+ 0x1103, 0x1166, 0x11b4, 0,
+#undef V4037
+#define V4037 (V + 14156)
+ 0x1103, 0x1166, 0x11b5, 0,
+#undef V4038
+#define V4038 (V + 14160)
+ 0x1103, 0x1166, 0x11b6, 0,
+#undef V4039
+#define V4039 (V + 14164)
+ 0x1103, 0x1166, 0x11b7, 0,
+#undef V4040
+#define V4040 (V + 14168)
+ 0x1103, 0x1166, 0x11b8, 0,
+#undef V4041
+#define V4041 (V + 14172)
+ 0x1103, 0x1166, 0x11b9, 0,
+#undef V4042
+#define V4042 (V + 14176)
+ 0x1103, 0x1166, 0x11ba, 0,
+#undef V4043
+#define V4043 (V + 14180)
+ 0x1103, 0x1166, 0x11bb, 0,
+#undef V4044
+#define V4044 (V + 14184)
+ 0x1103, 0x1166, 0x11bc, 0,
+#undef V4045
+#define V4045 (V + 14188)
+ 0x1103, 0x1166, 0x11bd, 0,
+#undef V4046
+#define V4046 (V + 14192)
+ 0x1103, 0x1166, 0x11be, 0,
+#undef V4047
+#define V4047 (V + 14196)
+ 0x1103, 0x1166, 0x11bf, 0,
+#undef V4048
+#define V4048 (V + 14200)
+ 0x1103, 0x1166, 0x11c0, 0,
+#undef V4049
+#define V4049 (V + 14204)
+ 0x1103, 0x1166, 0x11c1, 0,
+#undef V4050
+#define V4050 (V + 14208)
+ 0x1103, 0x1166, 0x11c2, 0,
+#undef V4051
+#define V4051 (V + 14212)
+ 0x1103, 0x1167, 0,
+#undef V4052
+#define V4052 (V + 14215)
+ 0x1103, 0x1167, 0x11a8, 0,
+#undef V4053
+#define V4053 (V + 14219)
+ 0x1103, 0x1167, 0x11a9, 0,
+#undef V4054
+#define V4054 (V + 14223)
+ 0x1103, 0x1167, 0x11aa, 0,
+#undef V4055
+#define V4055 (V + 14227)
+ 0x1103, 0x1167, 0x11ab, 0,
+#undef V4056
+#define V4056 (V + 14231)
+ 0x1103, 0x1167, 0x11ac, 0,
+#undef V4057
+#define V4057 (V + 14235)
+ 0x1103, 0x1167, 0x11ad, 0,
+#undef V4058
+#define V4058 (V + 14239)
+ 0x1103, 0x1167, 0x11ae, 0,
+#undef V4059
+#define V4059 (V + 14243)
+ 0x1103, 0x1167, 0x11af, 0,
+#undef V4060
+#define V4060 (V + 14247)
+ 0x1103, 0x1167, 0x11b0, 0,
+#undef V4061
+#define V4061 (V + 14251)
+ 0x1103, 0x1167, 0x11b1, 0,
+#undef V4062
+#define V4062 (V + 14255)
+ 0x1103, 0x1167, 0x11b2, 0,
+#undef V4063
+#define V4063 (V + 14259)
+ 0x1103, 0x1167, 0x11b3, 0,
+#undef V4064
+#define V4064 (V + 14263)
+ 0x1103, 0x1167, 0x11b4, 0,
+#undef V4065
+#define V4065 (V + 14267)
+ 0x1103, 0x1167, 0x11b5, 0,
+#undef V4066
+#define V4066 (V + 14271)
+ 0x1103, 0x1167, 0x11b6, 0,
+#undef V4067
+#define V4067 (V + 14275)
+ 0x1103, 0x1167, 0x11b7, 0,
+#undef V4068
+#define V4068 (V + 14279)
+ 0x1103, 0x1167, 0x11b8, 0,
+#undef V4069
+#define V4069 (V + 14283)
+ 0x1103, 0x1167, 0x11b9, 0,
+#undef V4070
+#define V4070 (V + 14287)
+ 0x1103, 0x1167, 0x11ba, 0,
+#undef V4071
+#define V4071 (V + 14291)
+ 0x1103, 0x1167, 0x11bb, 0,
+#undef V4072
+#define V4072 (V + 14295)
+ 0x1103, 0x1167, 0x11bc, 0,
+#undef V4073
+#define V4073 (V + 14299)
+ 0x1103, 0x1167, 0x11bd, 0,
+#undef V4074
+#define V4074 (V + 14303)
+ 0x1103, 0x1167, 0x11be, 0,
+#undef V4075
+#define V4075 (V + 14307)
+ 0x1103, 0x1167, 0x11bf, 0,
+#undef V4076
+#define V4076 (V + 14311)
+ 0x1103, 0x1167, 0x11c0, 0,
+#undef V4077
+#define V4077 (V + 14315)
+ 0x1103, 0x1167, 0x11c1, 0,
+#undef V4078
+#define V4078 (V + 14319)
+ 0x1103, 0x1167, 0x11c2, 0,
+#undef V4079
+#define V4079 (V + 14323)
+ 0x1103, 0x1168, 0,
+#undef V4080
+#define V4080 (V + 14326)
+ 0x1103, 0x1168, 0x11a8, 0,
+#undef V4081
+#define V4081 (V + 14330)
+ 0x1103, 0x1168, 0x11a9, 0,
+#undef V4082
+#define V4082 (V + 14334)
+ 0x1103, 0x1168, 0x11aa, 0,
+#undef V4083
+#define V4083 (V + 14338)
+ 0x1103, 0x1168, 0x11ab, 0,
+#undef V4084
+#define V4084 (V + 14342)
+ 0x1103, 0x1168, 0x11ac, 0,
+#undef V4085
+#define V4085 (V + 14346)
+ 0x1103, 0x1168, 0x11ad, 0,
+#undef V4086
+#define V4086 (V + 14350)
+ 0x1103, 0x1168, 0x11ae, 0,
+#undef V4087
+#define V4087 (V + 14354)
+ 0x1103, 0x1168, 0x11af, 0,
+#undef V4088
+#define V4088 (V + 14358)
+ 0x1103, 0x1168, 0x11b0, 0,
+#undef V4089
+#define V4089 (V + 14362)
+ 0x1103, 0x1168, 0x11b1, 0,
+#undef V4090
+#define V4090 (V + 14366)
+ 0x1103, 0x1168, 0x11b2, 0,
+#undef V4091
+#define V4091 (V + 14370)
+ 0x1103, 0x1168, 0x11b3, 0,
+#undef V4092
+#define V4092 (V + 14374)
+ 0x1103, 0x1168, 0x11b4, 0,
+#undef V4093
+#define V4093 (V + 14378)
+ 0x1103, 0x1168, 0x11b5, 0,
+#undef V4094
+#define V4094 (V + 14382)
+ 0x1103, 0x1168, 0x11b6, 0,
+#undef V4095
+#define V4095 (V + 14386)
+ 0x1103, 0x1168, 0x11b7, 0,
+#undef V4096
+#define V4096 (V + 14390)
+ 0x1103, 0x1168, 0x11b8, 0,
+#undef V4097
+#define V4097 (V + 14394)
+ 0x1103, 0x1168, 0x11b9, 0,
+#undef V4098
+#define V4098 (V + 14398)
+ 0x1103, 0x1168, 0x11ba, 0,
+#undef V4099
+#define V4099 (V + 14402)
+ 0x1103, 0x1168, 0x11bb, 0,
+#undef V4100
+#define V4100 (V + 14406)
+ 0x1103, 0x1168, 0x11bc, 0,
+#undef V4101
+#define V4101 (V + 14410)
+ 0x1103, 0x1168, 0x11bd, 0,
+#undef V4102
+#define V4102 (V + 14414)
+ 0x1103, 0x1168, 0x11be, 0,
+#undef V4103
+#define V4103 (V + 14418)
+ 0x1103, 0x1168, 0x11bf, 0,
+#undef V4104
+#define V4104 (V + 14422)
+ 0x1103, 0x1168, 0x11c0, 0,
+#undef V4105
+#define V4105 (V + 14426)
+ 0x1103, 0x1168, 0x11c1, 0,
+#undef V4106
+#define V4106 (V + 14430)
+ 0x1103, 0x1168, 0x11c2, 0,
+#undef V4107
+#define V4107 (V + 14434)
+ 0x1103, 0x1169, 0,
+#undef V4108
+#define V4108 (V + 14437)
+ 0x1103, 0x1169, 0x11a8, 0,
+#undef V4109
+#define V4109 (V + 14441)
+ 0x1103, 0x1169, 0x11a9, 0,
+#undef V4110
+#define V4110 (V + 14445)
+ 0x1103, 0x1169, 0x11aa, 0,
+#undef V4111
+#define V4111 (V + 14449)
+ 0x1103, 0x1169, 0x11ab, 0,
+#undef V4112
+#define V4112 (V + 14453)
+ 0x1103, 0x1169, 0x11ac, 0,
+#undef V4113
+#define V4113 (V + 14457)
+ 0x1103, 0x1169, 0x11ad, 0,
+#undef V4114
+#define V4114 (V + 14461)
+ 0x1103, 0x1169, 0x11ae, 0,
+#undef V4115
+#define V4115 (V + 14465)
+ 0x1103, 0x1169, 0x11af, 0,
+#undef V4116
+#define V4116 (V + 14469)
+ 0x1103, 0x1169, 0x11b0, 0,
+#undef V4117
+#define V4117 (V + 14473)
+ 0x1103, 0x1169, 0x11b1, 0,
+#undef V4118
+#define V4118 (V + 14477)
+ 0x1103, 0x1169, 0x11b2, 0,
+#undef V4119
+#define V4119 (V + 14481)
+ 0x1103, 0x1169, 0x11b3, 0,
+#undef V4120
+#define V4120 (V + 14485)
+ 0x1103, 0x1169, 0x11b4, 0,
+#undef V4121
+#define V4121 (V + 14489)
+ 0x1103, 0x1169, 0x11b5, 0,
+#undef V4122
+#define V4122 (V + 14493)
+ 0x1103, 0x1169, 0x11b6, 0,
+#undef V4123
+#define V4123 (V + 14497)
+ 0x1103, 0x1169, 0x11b7, 0,
+#undef V4124
+#define V4124 (V + 14501)
+ 0x1103, 0x1169, 0x11b8, 0,
+#undef V4125
+#define V4125 (V + 14505)
+ 0x1103, 0x1169, 0x11b9, 0,
+#undef V4126
+#define V4126 (V + 14509)
+ 0x1103, 0x1169, 0x11ba, 0,
+#undef V4127
+#define V4127 (V + 14513)
+ 0x1103, 0x1169, 0x11bb, 0,
+#undef V4128
+#define V4128 (V + 14517)
+ 0x1103, 0x1169, 0x11bc, 0,
+#undef V4129
+#define V4129 (V + 14521)
+ 0x1103, 0x1169, 0x11bd, 0,
+#undef V4130
+#define V4130 (V + 14525)
+ 0x1103, 0x1169, 0x11be, 0,
+#undef V4131
+#define V4131 (V + 14529)
+ 0x1103, 0x1169, 0x11bf, 0,
+#undef V4132
+#define V4132 (V + 14533)
+ 0x1103, 0x1169, 0x11c0, 0,
+#undef V4133
+#define V4133 (V + 14537)
+ 0x1103, 0x1169, 0x11c1, 0,
+#undef V4134
+#define V4134 (V + 14541)
+ 0x1103, 0x1169, 0x11c2, 0,
+#undef V4135
+#define V4135 (V + 14545)
+ 0x1103, 0x116a, 0,
+#undef V4136
+#define V4136 (V + 14548)
+ 0x1103, 0x116a, 0x11a8, 0,
+#undef V4137
+#define V4137 (V + 14552)
+ 0x1103, 0x116a, 0x11a9, 0,
+#undef V4138
+#define V4138 (V + 14556)
+ 0x1103, 0x116a, 0x11aa, 0,
+#undef V4139
+#define V4139 (V + 14560)
+ 0x1103, 0x116a, 0x11ab, 0,
+#undef V4140
+#define V4140 (V + 14564)
+ 0x1103, 0x116a, 0x11ac, 0,
+#undef V4141
+#define V4141 (V + 14568)
+ 0x1103, 0x116a, 0x11ad, 0,
+#undef V4142
+#define V4142 (V + 14572)
+ 0x1103, 0x116a, 0x11ae, 0,
+#undef V4143
+#define V4143 (V + 14576)
+ 0x1103, 0x116a, 0x11af, 0,
+#undef V4144
+#define V4144 (V + 14580)
+ 0x1103, 0x116a, 0x11b0, 0,
+#undef V4145
+#define V4145 (V + 14584)
+ 0x1103, 0x116a, 0x11b1, 0,
+#undef V4146
+#define V4146 (V + 14588)
+ 0x1103, 0x116a, 0x11b2, 0,
+#undef V4147
+#define V4147 (V + 14592)
+ 0x1103, 0x116a, 0x11b3, 0,
+#undef V4148
+#define V4148 (V + 14596)
+ 0x1103, 0x116a, 0x11b4, 0,
+#undef V4149
+#define V4149 (V + 14600)
+ 0x1103, 0x116a, 0x11b5, 0,
+#undef V4150
+#define V4150 (V + 14604)
+ 0x1103, 0x116a, 0x11b6, 0,
+#undef V4151
+#define V4151 (V + 14608)
+ 0x1103, 0x116a, 0x11b7, 0,
+#undef V4152
+#define V4152 (V + 14612)
+ 0x1103, 0x116a, 0x11b8, 0,
+#undef V4153
+#define V4153 (V + 14616)
+ 0x1103, 0x116a, 0x11b9, 0,
+#undef V4154
+#define V4154 (V + 14620)
+ 0x1103, 0x116a, 0x11ba, 0,
+#undef V4155
+#define V4155 (V + 14624)
+ 0x1103, 0x116a, 0x11bb, 0,
+#undef V4156
+#define V4156 (V + 14628)
+ 0x1103, 0x116a, 0x11bc, 0,
+#undef V4157
+#define V4157 (V + 14632)
+ 0x1103, 0x116a, 0x11bd, 0,
+#undef V4158
+#define V4158 (V + 14636)
+ 0x1103, 0x116a, 0x11be, 0,
+#undef V4159
+#define V4159 (V + 14640)
+ 0x1103, 0x116a, 0x11bf, 0,
+#undef V4160
+#define V4160 (V + 14644)
+ 0x1103, 0x116a, 0x11c0, 0,
+#undef V4161
+#define V4161 (V + 14648)
+ 0x1103, 0x116a, 0x11c1, 0,
+#undef V4162
+#define V4162 (V + 14652)
+ 0x1103, 0x116a, 0x11c2, 0,
+#undef V4163
+#define V4163 (V + 14656)
+ 0x1103, 0x116b, 0,
+#undef V4164
+#define V4164 (V + 14659)
+ 0x1103, 0x116b, 0x11a8, 0,
+#undef V4165
+#define V4165 (V + 14663)
+ 0x1103, 0x116b, 0x11a9, 0,
+#undef V4166
+#define V4166 (V + 14667)
+ 0x1103, 0x116b, 0x11aa, 0,
+#undef V4167
+#define V4167 (V + 14671)
+ 0x1103, 0x116b, 0x11ab, 0,
+#undef V4168
+#define V4168 (V + 14675)
+ 0x1103, 0x116b, 0x11ac, 0,
+#undef V4169
+#define V4169 (V + 14679)
+ 0x1103, 0x116b, 0x11ad, 0,
+#undef V4170
+#define V4170 (V + 14683)
+ 0x1103, 0x116b, 0x11ae, 0,
+#undef V4171
+#define V4171 (V + 14687)
+ 0x1103, 0x116b, 0x11af, 0,
+#undef V4172
+#define V4172 (V + 14691)
+ 0x1103, 0x116b, 0x11b0, 0,
+#undef V4173
+#define V4173 (V + 14695)
+ 0x1103, 0x116b, 0x11b1, 0,
+#undef V4174
+#define V4174 (V + 14699)
+ 0x1103, 0x116b, 0x11b2, 0,
+#undef V4175
+#define V4175 (V + 14703)
+ 0x1103, 0x116b, 0x11b3, 0,
+#undef V4176
+#define V4176 (V + 14707)
+ 0x1103, 0x116b, 0x11b4, 0,
+#undef V4177
+#define V4177 (V + 14711)
+ 0x1103, 0x116b, 0x11b5, 0,
+#undef V4178
+#define V4178 (V + 14715)
+ 0x1103, 0x116b, 0x11b6, 0,
+#undef V4179
+#define V4179 (V + 14719)
+ 0x1103, 0x116b, 0x11b7, 0,
+#undef V4180
+#define V4180 (V + 14723)
+ 0x1103, 0x116b, 0x11b8, 0,
+#undef V4181
+#define V4181 (V + 14727)
+ 0x1103, 0x116b, 0x11b9, 0,
+#undef V4182
+#define V4182 (V + 14731)
+ 0x1103, 0x116b, 0x11ba, 0,
+#undef V4183
+#define V4183 (V + 14735)
+ 0x1103, 0x116b, 0x11bb, 0,
+#undef V4184
+#define V4184 (V + 14739)
+ 0x1103, 0x116b, 0x11bc, 0,
+#undef V4185
+#define V4185 (V + 14743)
+ 0x1103, 0x116b, 0x11bd, 0,
+#undef V4186
+#define V4186 (V + 14747)
+ 0x1103, 0x116b, 0x11be, 0,
+#undef V4187
+#define V4187 (V + 14751)
+ 0x1103, 0x116b, 0x11bf, 0,
+#undef V4188
+#define V4188 (V + 14755)
+ 0x1103, 0x116b, 0x11c0, 0,
+#undef V4189
+#define V4189 (V + 14759)
+ 0x1103, 0x116b, 0x11c1, 0,
+#undef V4190
+#define V4190 (V + 14763)
+ 0x1103, 0x116b, 0x11c2, 0,
+#undef V4191
+#define V4191 (V + 14767)
+ 0x1103, 0x116c, 0,
+#undef V4192
+#define V4192 (V + 14770)
+ 0x1103, 0x116c, 0x11a8, 0,
+#undef V4193
+#define V4193 (V + 14774)
+ 0x1103, 0x116c, 0x11a9, 0,
+#undef V4194
+#define V4194 (V + 14778)
+ 0x1103, 0x116c, 0x11aa, 0,
+#undef V4195
+#define V4195 (V + 14782)
+ 0x1103, 0x116c, 0x11ab, 0,
+#undef V4196
+#define V4196 (V + 14786)
+ 0x1103, 0x116c, 0x11ac, 0,
+#undef V4197
+#define V4197 (V + 14790)
+ 0x1103, 0x116c, 0x11ad, 0,
+#undef V4198
+#define V4198 (V + 14794)
+ 0x1103, 0x116c, 0x11ae, 0,
+#undef V4199
+#define V4199 (V + 14798)
+ 0x1103, 0x116c, 0x11af, 0,
+#undef V4200
+#define V4200 (V + 14802)
+ 0x1103, 0x116c, 0x11b0, 0,
+#undef V4201
+#define V4201 (V + 14806)
+ 0x1103, 0x116c, 0x11b1, 0,
+#undef V4202
+#define V4202 (V + 14810)
+ 0x1103, 0x116c, 0x11b2, 0,
+#undef V4203
+#define V4203 (V + 14814)
+ 0x1103, 0x116c, 0x11b3, 0,
+#undef V4204
+#define V4204 (V + 14818)
+ 0x1103, 0x116c, 0x11b4, 0,
+#undef V4205
+#define V4205 (V + 14822)
+ 0x1103, 0x116c, 0x11b5, 0,
+#undef V4206
+#define V4206 (V + 14826)
+ 0x1103, 0x116c, 0x11b6, 0,
+#undef V4207
+#define V4207 (V + 14830)
+ 0x1103, 0x116c, 0x11b7, 0,
+#undef V4208
+#define V4208 (V + 14834)
+ 0x1103, 0x116c, 0x11b8, 0,
+#undef V4209
+#define V4209 (V + 14838)
+ 0x1103, 0x116c, 0x11b9, 0,
+#undef V4210
+#define V4210 (V + 14842)
+ 0x1103, 0x116c, 0x11ba, 0,
+#undef V4211
+#define V4211 (V + 14846)
+ 0x1103, 0x116c, 0x11bb, 0,
+#undef V4212
+#define V4212 (V + 14850)
+ 0x1103, 0x116c, 0x11bc, 0,
+#undef V4213
+#define V4213 (V + 14854)
+ 0x1103, 0x116c, 0x11bd, 0,
+#undef V4214
+#define V4214 (V + 14858)
+ 0x1103, 0x116c, 0x11be, 0,
+#undef V4215
+#define V4215 (V + 14862)
+ 0x1103, 0x116c, 0x11bf, 0,
+#undef V4216
+#define V4216 (V + 14866)
+ 0x1103, 0x116c, 0x11c0, 0,
+#undef V4217
+#define V4217 (V + 14870)
+ 0x1103, 0x116c, 0x11c1, 0,
+#undef V4218
+#define V4218 (V + 14874)
+ 0x1103, 0x116c, 0x11c2, 0,
+#undef V4219
+#define V4219 (V + 14878)
+ 0x1103, 0x116d, 0,
+#undef V4220
+#define V4220 (V + 14881)
+ 0x1103, 0x116d, 0x11a8, 0,
+#undef V4221
+#define V4221 (V + 14885)
+ 0x1103, 0x116d, 0x11a9, 0,
+#undef V4222
+#define V4222 (V + 14889)
+ 0x1103, 0x116d, 0x11aa, 0,
+#undef V4223
+#define V4223 (V + 14893)
+ 0x1103, 0x116d, 0x11ab, 0,
+#undef V4224
+#define V4224 (V + 14897)
+ 0x1103, 0x116d, 0x11ac, 0,
+#undef V4225
+#define V4225 (V + 14901)
+ 0x1103, 0x116d, 0x11ad, 0,
+#undef V4226
+#define V4226 (V + 14905)
+ 0x1103, 0x116d, 0x11ae, 0,
+#undef V4227
+#define V4227 (V + 14909)
+ 0x1103, 0x116d, 0x11af, 0,
+#undef V4228
+#define V4228 (V + 14913)
+ 0x1103, 0x116d, 0x11b0, 0,
+#undef V4229
+#define V4229 (V + 14917)
+ 0x1103, 0x116d, 0x11b1, 0,
+#undef V4230
+#define V4230 (V + 14921)
+ 0x1103, 0x116d, 0x11b2, 0,
+#undef V4231
+#define V4231 (V + 14925)
+ 0x1103, 0x116d, 0x11b3, 0,
+#undef V4232
+#define V4232 (V + 14929)
+ 0x1103, 0x116d, 0x11b4, 0,
+#undef V4233
+#define V4233 (V + 14933)
+ 0x1103, 0x116d, 0x11b5, 0,
+#undef V4234
+#define V4234 (V + 14937)
+ 0x1103, 0x116d, 0x11b6, 0,
+#undef V4235
+#define V4235 (V + 14941)
+ 0x1103, 0x116d, 0x11b7, 0,
+#undef V4236
+#define V4236 (V + 14945)
+ 0x1103, 0x116d, 0x11b8, 0,
+#undef V4237
+#define V4237 (V + 14949)
+ 0x1103, 0x116d, 0x11b9, 0,
+#undef V4238
+#define V4238 (V + 14953)
+ 0x1103, 0x116d, 0x11ba, 0,
+#undef V4239
+#define V4239 (V + 14957)
+ 0x1103, 0x116d, 0x11bb, 0,
+#undef V4240
+#define V4240 (V + 14961)
+ 0x1103, 0x116d, 0x11bc, 0,
+#undef V4241
+#define V4241 (V + 14965)
+ 0x1103, 0x116d, 0x11bd, 0,
+#undef V4242
+#define V4242 (V + 14969)
+ 0x1103, 0x116d, 0x11be, 0,
+#undef V4243
+#define V4243 (V + 14973)
+ 0x1103, 0x116d, 0x11bf, 0,
+#undef V4244
+#define V4244 (V + 14977)
+ 0x1103, 0x116d, 0x11c0, 0,
+#undef V4245
+#define V4245 (V + 14981)
+ 0x1103, 0x116d, 0x11c1, 0,
+#undef V4246
+#define V4246 (V + 14985)
+ 0x1103, 0x116d, 0x11c2, 0,
+#undef V4247
+#define V4247 (V + 14989)
+ 0x1103, 0x116e, 0,
+#undef V4248
+#define V4248 (V + 14992)
+ 0x1103, 0x116e, 0x11a8, 0,
+#undef V4249
+#define V4249 (V + 14996)
+ 0x1103, 0x116e, 0x11a9, 0,
+#undef V4250
+#define V4250 (V + 15000)
+ 0x1103, 0x116e, 0x11aa, 0,
+#undef V4251
+#define V4251 (V + 15004)
+ 0x1103, 0x116e, 0x11ab, 0,
+#undef V4252
+#define V4252 (V + 15008)
+ 0x1103, 0x116e, 0x11ac, 0,
+#undef V4253
+#define V4253 (V + 15012)
+ 0x1103, 0x116e, 0x11ad, 0,
+#undef V4254
+#define V4254 (V + 15016)
+ 0x1103, 0x116e, 0x11ae, 0,
+#undef V4255
+#define V4255 (V + 15020)
+ 0x1103, 0x116e, 0x11af, 0,
+#undef V4256
+#define V4256 (V + 15024)
+ 0x1103, 0x116e, 0x11b0, 0,
+#undef V4257
+#define V4257 (V + 15028)
+ 0x1103, 0x116e, 0x11b1, 0,
+#undef V4258
+#define V4258 (V + 15032)
+ 0x1103, 0x116e, 0x11b2, 0,
+#undef V4259
+#define V4259 (V + 15036)
+ 0x1103, 0x116e, 0x11b3, 0,
+#undef V4260
+#define V4260 (V + 15040)
+ 0x1103, 0x116e, 0x11b4, 0,
+#undef V4261
+#define V4261 (V + 15044)
+ 0x1103, 0x116e, 0x11b5, 0,
+#undef V4262
+#define V4262 (V + 15048)
+ 0x1103, 0x116e, 0x11b6, 0,
+#undef V4263
+#define V4263 (V + 15052)
+ 0x1103, 0x116e, 0x11b7, 0,
+#undef V4264
+#define V4264 (V + 15056)
+ 0x1103, 0x116e, 0x11b8, 0,
+#undef V4265
+#define V4265 (V + 15060)
+ 0x1103, 0x116e, 0x11b9, 0,
+#undef V4266
+#define V4266 (V + 15064)
+ 0x1103, 0x116e, 0x11ba, 0,
+#undef V4267
+#define V4267 (V + 15068)
+ 0x1103, 0x116e, 0x11bb, 0,
+#undef V4268
+#define V4268 (V + 15072)
+ 0x1103, 0x116e, 0x11bc, 0,
+#undef V4269
+#define V4269 (V + 15076)
+ 0x1103, 0x116e, 0x11bd, 0,
+#undef V4270
+#define V4270 (V + 15080)
+ 0x1103, 0x116e, 0x11be, 0,
+#undef V4271
+#define V4271 (V + 15084)
+ 0x1103, 0x116e, 0x11bf, 0,
+#undef V4272
+#define V4272 (V + 15088)
+ 0x1103, 0x116e, 0x11c0, 0,
+#undef V4273
+#define V4273 (V + 15092)
+ 0x1103, 0x116e, 0x11c1, 0,
+#undef V4274
+#define V4274 (V + 15096)
+ 0x1103, 0x116e, 0x11c2, 0,
+#undef V4275
+#define V4275 (V + 15100)
+ 0x1103, 0x116f, 0,
+#undef V4276
+#define V4276 (V + 15103)
+ 0x1103, 0x116f, 0x11a8, 0,
+#undef V4277
+#define V4277 (V + 15107)
+ 0x1103, 0x116f, 0x11a9, 0,
+#undef V4278
+#define V4278 (V + 15111)
+ 0x1103, 0x116f, 0x11aa, 0,
+#undef V4279
+#define V4279 (V + 15115)
+ 0x1103, 0x116f, 0x11ab, 0,
+#undef V4280
+#define V4280 (V + 15119)
+ 0x1103, 0x116f, 0x11ac, 0,
+#undef V4281
+#define V4281 (V + 15123)
+ 0x1103, 0x116f, 0x11ad, 0,
+#undef V4282
+#define V4282 (V + 15127)
+ 0x1103, 0x116f, 0x11ae, 0,
+#undef V4283
+#define V4283 (V + 15131)
+ 0x1103, 0x116f, 0x11af, 0,
+#undef V4284
+#define V4284 (V + 15135)
+ 0x1103, 0x116f, 0x11b0, 0,
+#undef V4285
+#define V4285 (V + 15139)
+ 0x1103, 0x116f, 0x11b1, 0,
+#undef V4286
+#define V4286 (V + 15143)
+ 0x1103, 0x116f, 0x11b2, 0,
+#undef V4287
+#define V4287 (V + 15147)
+ 0x1103, 0x116f, 0x11b3, 0,
+#undef V4288
+#define V4288 (V + 15151)
+ 0x1103, 0x116f, 0x11b4, 0,
+#undef V4289
+#define V4289 (V + 15155)
+ 0x1103, 0x116f, 0x11b5, 0,
+#undef V4290
+#define V4290 (V + 15159)
+ 0x1103, 0x116f, 0x11b6, 0,
+#undef V4291
+#define V4291 (V + 15163)
+ 0x1103, 0x116f, 0x11b7, 0,
+#undef V4292
+#define V4292 (V + 15167)
+ 0x1103, 0x116f, 0x11b8, 0,
+#undef V4293
+#define V4293 (V + 15171)
+ 0x1103, 0x116f, 0x11b9, 0,
+#undef V4294
+#define V4294 (V + 15175)
+ 0x1103, 0x116f, 0x11ba, 0,
+#undef V4295
+#define V4295 (V + 15179)
+ 0x1103, 0x116f, 0x11bb, 0,
+#undef V4296
+#define V4296 (V + 15183)
+ 0x1103, 0x116f, 0x11bc, 0,
+#undef V4297
+#define V4297 (V + 15187)
+ 0x1103, 0x116f, 0x11bd, 0,
+#undef V4298
+#define V4298 (V + 15191)
+ 0x1103, 0x116f, 0x11be, 0,
+#undef V4299
+#define V4299 (V + 15195)
+ 0x1103, 0x116f, 0x11bf, 0,
+#undef V4300
+#define V4300 (V + 15199)
+ 0x1103, 0x116f, 0x11c0, 0,
+#undef V4301
+#define V4301 (V + 15203)
+ 0x1103, 0x116f, 0x11c1, 0,
+#undef V4302
+#define V4302 (V + 15207)
+ 0x1103, 0x116f, 0x11c2, 0,
+#undef V4303
+#define V4303 (V + 15211)
+ 0x1103, 0x1170, 0,
+#undef V4304
+#define V4304 (V + 15214)
+ 0x1103, 0x1170, 0x11a8, 0,
+#undef V4305
+#define V4305 (V + 15218)
+ 0x1103, 0x1170, 0x11a9, 0,
+#undef V4306
+#define V4306 (V + 15222)
+ 0x1103, 0x1170, 0x11aa, 0,
+#undef V4307
+#define V4307 (V + 15226)
+ 0x1103, 0x1170, 0x11ab, 0,
+#undef V4308
+#define V4308 (V + 15230)
+ 0x1103, 0x1170, 0x11ac, 0,
+#undef V4309
+#define V4309 (V + 15234)
+ 0x1103, 0x1170, 0x11ad, 0,
+#undef V4310
+#define V4310 (V + 15238)
+ 0x1103, 0x1170, 0x11ae, 0,
+#undef V4311
+#define V4311 (V + 15242)
+ 0x1103, 0x1170, 0x11af, 0,
+#undef V4312
+#define V4312 (V + 15246)
+ 0x1103, 0x1170, 0x11b0, 0,
+#undef V4313
+#define V4313 (V + 15250)
+ 0x1103, 0x1170, 0x11b1, 0,
+#undef V4314
+#define V4314 (V + 15254)
+ 0x1103, 0x1170, 0x11b2, 0,
+#undef V4315
+#define V4315 (V + 15258)
+ 0x1103, 0x1170, 0x11b3, 0,
+#undef V4316
+#define V4316 (V + 15262)
+ 0x1103, 0x1170, 0x11b4, 0,
+#undef V4317
+#define V4317 (V + 15266)
+ 0x1103, 0x1170, 0x11b5, 0,
+#undef V4318
+#define V4318 (V + 15270)
+ 0x1103, 0x1170, 0x11b6, 0,
+#undef V4319
+#define V4319 (V + 15274)
+ 0x1103, 0x1170, 0x11b7, 0,
+#undef V4320
+#define V4320 (V + 15278)
+ 0x1103, 0x1170, 0x11b8, 0,
+#undef V4321
+#define V4321 (V + 15282)
+ 0x1103, 0x1170, 0x11b9, 0,
+#undef V4322
+#define V4322 (V + 15286)
+ 0x1103, 0x1170, 0x11ba, 0,
+#undef V4323
+#define V4323 (V + 15290)
+ 0x1103, 0x1170, 0x11bb, 0,
+#undef V4324
+#define V4324 (V + 15294)
+ 0x1103, 0x1170, 0x11bc, 0,
+#undef V4325
+#define V4325 (V + 15298)
+ 0x1103, 0x1170, 0x11bd, 0,
+#undef V4326
+#define V4326 (V + 15302)
+ 0x1103, 0x1170, 0x11be, 0,
+#undef V4327
+#define V4327 (V + 15306)
+ 0x1103, 0x1170, 0x11bf, 0,
+#undef V4328
+#define V4328 (V + 15310)
+ 0x1103, 0x1170, 0x11c0, 0,
+#undef V4329
+#define V4329 (V + 15314)
+ 0x1103, 0x1170, 0x11c1, 0,
+#undef V4330
+#define V4330 (V + 15318)
+ 0x1103, 0x1170, 0x11c2, 0,
+#undef V4331
+#define V4331 (V + 15322)
+ 0x1103, 0x1171, 0,
+#undef V4332
+#define V4332 (V + 15325)
+ 0x1103, 0x1171, 0x11a8, 0,
+#undef V4333
+#define V4333 (V + 15329)
+ 0x1103, 0x1171, 0x11a9, 0,
+#undef V4334
+#define V4334 (V + 15333)
+ 0x1103, 0x1171, 0x11aa, 0,
+#undef V4335
+#define V4335 (V + 15337)
+ 0x1103, 0x1171, 0x11ab, 0,
+#undef V4336
+#define V4336 (V + 15341)
+ 0x1103, 0x1171, 0x11ac, 0,
+#undef V4337
+#define V4337 (V + 15345)
+ 0x1103, 0x1171, 0x11ad, 0,
+#undef V4338
+#define V4338 (V + 15349)
+ 0x1103, 0x1171, 0x11ae, 0,
+#undef V4339
+#define V4339 (V + 15353)
+ 0x1103, 0x1171, 0x11af, 0,
+#undef V4340
+#define V4340 (V + 15357)
+ 0x1103, 0x1171, 0x11b0, 0,
+#undef V4341
+#define V4341 (V + 15361)
+ 0x1103, 0x1171, 0x11b1, 0,
+#undef V4342
+#define V4342 (V + 15365)
+ 0x1103, 0x1171, 0x11b2, 0,
+#undef V4343
+#define V4343 (V + 15369)
+ 0x1103, 0x1171, 0x11b3, 0,
+#undef V4344
+#define V4344 (V + 15373)
+ 0x1103, 0x1171, 0x11b4, 0,
+#undef V4345
+#define V4345 (V + 15377)
+ 0x1103, 0x1171, 0x11b5, 0,
+#undef V4346
+#define V4346 (V + 15381)
+ 0x1103, 0x1171, 0x11b6, 0,
+#undef V4347
+#define V4347 (V + 15385)
+ 0x1103, 0x1171, 0x11b7, 0,
+#undef V4348
+#define V4348 (V + 15389)
+ 0x1103, 0x1171, 0x11b8, 0,
+#undef V4349
+#define V4349 (V + 15393)
+ 0x1103, 0x1171, 0x11b9, 0,
+#undef V4350
+#define V4350 (V + 15397)
+ 0x1103, 0x1171, 0x11ba, 0,
+#undef V4351
+#define V4351 (V + 15401)
+ 0x1103, 0x1171, 0x11bb, 0,
+#undef V4352
+#define V4352 (V + 15405)
+ 0x1103, 0x1171, 0x11bc, 0,
+#undef V4353
+#define V4353 (V + 15409)
+ 0x1103, 0x1171, 0x11bd, 0,
+#undef V4354
+#define V4354 (V + 15413)
+ 0x1103, 0x1171, 0x11be, 0,
+#undef V4355
+#define V4355 (V + 15417)
+ 0x1103, 0x1171, 0x11bf, 0,
+#undef V4356
+#define V4356 (V + 15421)
+ 0x1103, 0x1171, 0x11c0, 0,
+#undef V4357
+#define V4357 (V + 15425)
+ 0x1103, 0x1171, 0x11c1, 0,
+#undef V4358
+#define V4358 (V + 15429)
+ 0x1103, 0x1171, 0x11c2, 0,
+#undef V4359
+#define V4359 (V + 15433)
+ 0x1103, 0x1172, 0,
+#undef V4360
+#define V4360 (V + 15436)
+ 0x1103, 0x1172, 0x11a8, 0,
+#undef V4361
+#define V4361 (V + 15440)
+ 0x1103, 0x1172, 0x11a9, 0,
+#undef V4362
+#define V4362 (V + 15444)
+ 0x1103, 0x1172, 0x11aa, 0,
+#undef V4363
+#define V4363 (V + 15448)
+ 0x1103, 0x1172, 0x11ab, 0,
+#undef V4364
+#define V4364 (V + 15452)
+ 0x1103, 0x1172, 0x11ac, 0,
+#undef V4365
+#define V4365 (V + 15456)
+ 0x1103, 0x1172, 0x11ad, 0,
+#undef V4366
+#define V4366 (V + 15460)
+ 0x1103, 0x1172, 0x11ae, 0,
+#undef V4367
+#define V4367 (V + 15464)
+ 0x1103, 0x1172, 0x11af, 0,
+#undef V4368
+#define V4368 (V + 15468)
+ 0x1103, 0x1172, 0x11b0, 0,
+#undef V4369
+#define V4369 (V + 15472)
+ 0x1103, 0x1172, 0x11b1, 0,
+#undef V4370
+#define V4370 (V + 15476)
+ 0x1103, 0x1172, 0x11b2, 0,
+#undef V4371
+#define V4371 (V + 15480)
+ 0x1103, 0x1172, 0x11b3, 0,
+#undef V4372
+#define V4372 (V + 15484)
+ 0x1103, 0x1172, 0x11b4, 0,
+#undef V4373
+#define V4373 (V + 15488)
+ 0x1103, 0x1172, 0x11b5, 0,
+#undef V4374
+#define V4374 (V + 15492)
+ 0x1103, 0x1172, 0x11b6, 0,
+#undef V4375
+#define V4375 (V + 15496)
+ 0x1103, 0x1172, 0x11b7, 0,
+#undef V4376
+#define V4376 (V + 15500)
+ 0x1103, 0x1172, 0x11b8, 0,
+#undef V4377
+#define V4377 (V + 15504)
+ 0x1103, 0x1172, 0x11b9, 0,
+#undef V4378
+#define V4378 (V + 15508)
+ 0x1103, 0x1172, 0x11ba, 0,
+#undef V4379
+#define V4379 (V + 15512)
+ 0x1103, 0x1172, 0x11bb, 0,
+#undef V4380
+#define V4380 (V + 15516)
+ 0x1103, 0x1172, 0x11bc, 0,
+#undef V4381
+#define V4381 (V + 15520)
+ 0x1103, 0x1172, 0x11bd, 0,
+#undef V4382
+#define V4382 (V + 15524)
+ 0x1103, 0x1172, 0x11be, 0,
+#undef V4383
+#define V4383 (V + 15528)
+ 0x1103, 0x1172, 0x11bf, 0,
+#undef V4384
+#define V4384 (V + 15532)
+ 0x1103, 0x1172, 0x11c0, 0,
+#undef V4385
+#define V4385 (V + 15536)
+ 0x1103, 0x1172, 0x11c1, 0,
+#undef V4386
+#define V4386 (V + 15540)
+ 0x1103, 0x1172, 0x11c2, 0,
+#undef V4387
+#define V4387 (V + 15544)
+ 0x1103, 0x1173, 0,
+#undef V4388
+#define V4388 (V + 15547)
+ 0x1103, 0x1173, 0x11a8, 0,
+#undef V4389
+#define V4389 (V + 15551)
+ 0x1103, 0x1173, 0x11a9, 0,
+#undef V4390
+#define V4390 (V + 15555)
+ 0x1103, 0x1173, 0x11aa, 0,
+#undef V4391
+#define V4391 (V + 15559)
+ 0x1103, 0x1173, 0x11ab, 0,
+#undef V4392
+#define V4392 (V + 15563)
+ 0x1103, 0x1173, 0x11ac, 0,
+#undef V4393
+#define V4393 (V + 15567)
+ 0x1103, 0x1173, 0x11ad, 0,
+#undef V4394
+#define V4394 (V + 15571)
+ 0x1103, 0x1173, 0x11ae, 0,
+#undef V4395
+#define V4395 (V + 15575)
+ 0x1103, 0x1173, 0x11af, 0,
+#undef V4396
+#define V4396 (V + 15579)
+ 0x1103, 0x1173, 0x11b0, 0,
+#undef V4397
+#define V4397 (V + 15583)
+ 0x1103, 0x1173, 0x11b1, 0,
+#undef V4398
+#define V4398 (V + 15587)
+ 0x1103, 0x1173, 0x11b2, 0,
+#undef V4399
+#define V4399 (V + 15591)
+ 0x1103, 0x1173, 0x11b3, 0,
+#undef V4400
+#define V4400 (V + 15595)
+ 0x1103, 0x1173, 0x11b4, 0,
+#undef V4401
+#define V4401 (V + 15599)
+ 0x1103, 0x1173, 0x11b5, 0,
+#undef V4402
+#define V4402 (V + 15603)
+ 0x1103, 0x1173, 0x11b6, 0,
+#undef V4403
+#define V4403 (V + 15607)
+ 0x1103, 0x1173, 0x11b7, 0,
+#undef V4404
+#define V4404 (V + 15611)
+ 0x1103, 0x1173, 0x11b8, 0,
+#undef V4405
+#define V4405 (V + 15615)
+ 0x1103, 0x1173, 0x11b9, 0,
+#undef V4406
+#define V4406 (V + 15619)
+ 0x1103, 0x1173, 0x11ba, 0,
+#undef V4407
+#define V4407 (V + 15623)
+ 0x1103, 0x1173, 0x11bb, 0,
+#undef V4408
+#define V4408 (V + 15627)
+ 0x1103, 0x1173, 0x11bc, 0,
+#undef V4409
+#define V4409 (V + 15631)
+ 0x1103, 0x1173, 0x11bd, 0,
+#undef V4410
+#define V4410 (V + 15635)
+ 0x1103, 0x1173, 0x11be, 0,
+#undef V4411
+#define V4411 (V + 15639)
+ 0x1103, 0x1173, 0x11bf, 0,
+#undef V4412
+#define V4412 (V + 15643)
+ 0x1103, 0x1173, 0x11c0, 0,
+#undef V4413
+#define V4413 (V + 15647)
+ 0x1103, 0x1173, 0x11c1, 0,
+#undef V4414
+#define V4414 (V + 15651)
+ 0x1103, 0x1173, 0x11c2, 0,
+#undef V4415
+#define V4415 (V + 15655)
+ 0x1103, 0x1174, 0,
+#undef V4416
+#define V4416 (V + 15658)
+ 0x1103, 0x1174, 0x11a8, 0,
+#undef V4417
+#define V4417 (V + 15662)
+ 0x1103, 0x1174, 0x11a9, 0,
+#undef V4418
+#define V4418 (V + 15666)
+ 0x1103, 0x1174, 0x11aa, 0,
+#undef V4419
+#define V4419 (V + 15670)
+ 0x1103, 0x1174, 0x11ab, 0,
+#undef V4420
+#define V4420 (V + 15674)
+ 0x1103, 0x1174, 0x11ac, 0,
+#undef V4421
+#define V4421 (V + 15678)
+ 0x1103, 0x1174, 0x11ad, 0,
+#undef V4422
+#define V4422 (V + 15682)
+ 0x1103, 0x1174, 0x11ae, 0,
+#undef V4423
+#define V4423 (V + 15686)
+ 0x1103, 0x1174, 0x11af, 0,
+#undef V4424
+#define V4424 (V + 15690)
+ 0x1103, 0x1174, 0x11b0, 0,
+#undef V4425
+#define V4425 (V + 15694)
+ 0x1103, 0x1174, 0x11b1, 0,
+#undef V4426
+#define V4426 (V + 15698)
+ 0x1103, 0x1174, 0x11b2, 0,
+#undef V4427
+#define V4427 (V + 15702)
+ 0x1103, 0x1174, 0x11b3, 0,
+#undef V4428
+#define V4428 (V + 15706)
+ 0x1103, 0x1174, 0x11b4, 0,
+#undef V4429
+#define V4429 (V + 15710)
+ 0x1103, 0x1174, 0x11b5, 0,
+#undef V4430
+#define V4430 (V + 15714)
+ 0x1103, 0x1174, 0x11b6, 0,
+#undef V4431
+#define V4431 (V + 15718)
+ 0x1103, 0x1174, 0x11b7, 0,
+#undef V4432
+#define V4432 (V + 15722)
+ 0x1103, 0x1174, 0x11b8, 0,
+#undef V4433
+#define V4433 (V + 15726)
+ 0x1103, 0x1174, 0x11b9, 0,
+#undef V4434
+#define V4434 (V + 15730)
+ 0x1103, 0x1174, 0x11ba, 0,
+#undef V4435
+#define V4435 (V + 15734)
+ 0x1103, 0x1174, 0x11bb, 0,
+#undef V4436
+#define V4436 (V + 15738)
+ 0x1103, 0x1174, 0x11bc, 0,
+#undef V4437
+#define V4437 (V + 15742)
+ 0x1103, 0x1174, 0x11bd, 0,
+#undef V4438
+#define V4438 (V + 15746)
+ 0x1103, 0x1174, 0x11be, 0,
+#undef V4439
+#define V4439 (V + 15750)
+ 0x1103, 0x1174, 0x11bf, 0,
+#undef V4440
+#define V4440 (V + 15754)
+ 0x1103, 0x1174, 0x11c0, 0,
+#undef V4441
+#define V4441 (V + 15758)
+ 0x1103, 0x1174, 0x11c1, 0,
+#undef V4442
+#define V4442 (V + 15762)
+ 0x1103, 0x1174, 0x11c2, 0,
+#undef V4443
+#define V4443 (V + 15766)
+ 0x1103, 0x1175, 0,
+#undef V4444
+#define V4444 (V + 15769)
+ 0x1103, 0x1175, 0x11a8, 0,
+#undef V4445
+#define V4445 (V + 15773)
+ 0x1103, 0x1175, 0x11a9, 0,
+#undef V4446
+#define V4446 (V + 15777)
+ 0x1103, 0x1175, 0x11aa, 0,
+#undef V4447
+#define V4447 (V + 15781)
+ 0x1103, 0x1175, 0x11ab, 0,
+#undef V4448
+#define V4448 (V + 15785)
+ 0x1103, 0x1175, 0x11ac, 0,
+#undef V4449
+#define V4449 (V + 15789)
+ 0x1103, 0x1175, 0x11ad, 0,
+#undef V4450
+#define V4450 (V + 15793)
+ 0x1103, 0x1175, 0x11ae, 0,
+#undef V4451
+#define V4451 (V + 15797)
+ 0x1103, 0x1175, 0x11af, 0,
+#undef V4452
+#define V4452 (V + 15801)
+ 0x1103, 0x1175, 0x11b0, 0,
+#undef V4453
+#define V4453 (V + 15805)
+ 0x1103, 0x1175, 0x11b1, 0,
+#undef V4454
+#define V4454 (V + 15809)
+ 0x1103, 0x1175, 0x11b2, 0,
+#undef V4455
+#define V4455 (V + 15813)
+ 0x1103, 0x1175, 0x11b3, 0,
+#undef V4456
+#define V4456 (V + 15817)
+ 0x1103, 0x1175, 0x11b4, 0,
+#undef V4457
+#define V4457 (V + 15821)
+ 0x1103, 0x1175, 0x11b5, 0,
+#undef V4458
+#define V4458 (V + 15825)
+ 0x1103, 0x1175, 0x11b6, 0,
+#undef V4459
+#define V4459 (V + 15829)
+ 0x1103, 0x1175, 0x11b7, 0,
+#undef V4460
+#define V4460 (V + 15833)
+ 0x1103, 0x1175, 0x11b8, 0,
+#undef V4461
+#define V4461 (V + 15837)
+ 0x1103, 0x1175, 0x11b9, 0,
+#undef V4462
+#define V4462 (V + 15841)
+ 0x1103, 0x1175, 0x11ba, 0,
+#undef V4463
+#define V4463 (V + 15845)
+ 0x1103, 0x1175, 0x11bb, 0,
+#undef V4464
+#define V4464 (V + 15849)
+ 0x1103, 0x1175, 0x11bc, 0,
+#undef V4465
+#define V4465 (V + 15853)
+ 0x1103, 0x1175, 0x11bd, 0,
+#undef V4466
+#define V4466 (V + 15857)
+ 0x1103, 0x1175, 0x11be, 0,
+#undef V4467
+#define V4467 (V + 15861)
+ 0x1103, 0x1175, 0x11bf, 0,
+#undef V4468
+#define V4468 (V + 15865)
+ 0x1103, 0x1175, 0x11c0, 0,
+#undef V4469
+#define V4469 (V + 15869)
+ 0x1103, 0x1175, 0x11c1, 0,
+#undef V4470
+#define V4470 (V + 15873)
+ 0x1103, 0x1175, 0x11c2, 0,
+#undef V4471
+#define V4471 (V + 15877)
+ 0x1104, 0x1161, 0,
+#undef V4472
+#define V4472 (V + 15880)
+ 0x1104, 0x1161, 0x11a8, 0,
+#undef V4473
+#define V4473 (V + 15884)
+ 0x1104, 0x1161, 0x11a9, 0,
+#undef V4474
+#define V4474 (V + 15888)
+ 0x1104, 0x1161, 0x11aa, 0,
+#undef V4475
+#define V4475 (V + 15892)
+ 0x1104, 0x1161, 0x11ab, 0,
+#undef V4476
+#define V4476 (V + 15896)
+ 0x1104, 0x1161, 0x11ac, 0,
+#undef V4477
+#define V4477 (V + 15900)
+ 0x1104, 0x1161, 0x11ad, 0,
+#undef V4478
+#define V4478 (V + 15904)
+ 0x1104, 0x1161, 0x11ae, 0,
+#undef V4479
+#define V4479 (V + 15908)
+ 0x1104, 0x1161, 0x11af, 0,
+#undef V4480
+#define V4480 (V + 15912)
+ 0x1104, 0x1161, 0x11b0, 0,
+#undef V4481
+#define V4481 (V + 15916)
+ 0x1104, 0x1161, 0x11b1, 0,
+#undef V4482
+#define V4482 (V + 15920)
+ 0x1104, 0x1161, 0x11b2, 0,
+#undef V4483
+#define V4483 (V + 15924)
+ 0x1104, 0x1161, 0x11b3, 0,
+#undef V4484
+#define V4484 (V + 15928)
+ 0x1104, 0x1161, 0x11b4, 0,
+#undef V4485
+#define V4485 (V + 15932)
+ 0x1104, 0x1161, 0x11b5, 0,
+#undef V4486
+#define V4486 (V + 15936)
+ 0x1104, 0x1161, 0x11b6, 0,
+#undef V4487
+#define V4487 (V + 15940)
+ 0x1104, 0x1161, 0x11b7, 0,
+#undef V4488
+#define V4488 (V + 15944)
+ 0x1104, 0x1161, 0x11b8, 0,
+#undef V4489
+#define V4489 (V + 15948)
+ 0x1104, 0x1161, 0x11b9, 0,
+#undef V4490
+#define V4490 (V + 15952)
+ 0x1104, 0x1161, 0x11ba, 0,
+#undef V4491
+#define V4491 (V + 15956)
+ 0x1104, 0x1161, 0x11bb, 0,
+#undef V4492
+#define V4492 (V + 15960)
+ 0x1104, 0x1161, 0x11bc, 0,
+#undef V4493
+#define V4493 (V + 15964)
+ 0x1104, 0x1161, 0x11bd, 0,
+#undef V4494
+#define V4494 (V + 15968)
+ 0x1104, 0x1161, 0x11be, 0,
+#undef V4495
+#define V4495 (V + 15972)
+ 0x1104, 0x1161, 0x11bf, 0,
+#undef V4496
+#define V4496 (V + 15976)
+ 0x1104, 0x1161, 0x11c0, 0,
+#undef V4497
+#define V4497 (V + 15980)
+ 0x1104, 0x1161, 0x11c1, 0,
+#undef V4498
+#define V4498 (V + 15984)
+ 0x1104, 0x1161, 0x11c2, 0,
+#undef V4499
+#define V4499 (V + 15988)
+ 0x1104, 0x1162, 0,
+#undef V4500
+#define V4500 (V + 15991)
+ 0x1104, 0x1162, 0x11a8, 0,
+#undef V4501
+#define V4501 (V + 15995)
+ 0x1104, 0x1162, 0x11a9, 0,
+#undef V4502
+#define V4502 (V + 15999)
+ 0x1104, 0x1162, 0x11aa, 0,
+#undef V4503
+#define V4503 (V + 16003)
+ 0x1104, 0x1162, 0x11ab, 0,
+#undef V4504
+#define V4504 (V + 16007)
+ 0x1104, 0x1162, 0x11ac, 0,
+#undef V4505
+#define V4505 (V + 16011)
+ 0x1104, 0x1162, 0x11ad, 0,
+#undef V4506
+#define V4506 (V + 16015)
+ 0x1104, 0x1162, 0x11ae, 0,
+#undef V4507
+#define V4507 (V + 16019)
+ 0x1104, 0x1162, 0x11af, 0,
+#undef V4508
+#define V4508 (V + 16023)
+ 0x1104, 0x1162, 0x11b0, 0,
+#undef V4509
+#define V4509 (V + 16027)
+ 0x1104, 0x1162, 0x11b1, 0,
+#undef V4510
+#define V4510 (V + 16031)
+ 0x1104, 0x1162, 0x11b2, 0,
+#undef V4511
+#define V4511 (V + 16035)
+ 0x1104, 0x1162, 0x11b3, 0,
+#undef V4512
+#define V4512 (V + 16039)
+ 0x1104, 0x1162, 0x11b4, 0,
+#undef V4513
+#define V4513 (V + 16043)
+ 0x1104, 0x1162, 0x11b5, 0,
+#undef V4514
+#define V4514 (V + 16047)
+ 0x1104, 0x1162, 0x11b6, 0,
+#undef V4515
+#define V4515 (V + 16051)
+ 0x1104, 0x1162, 0x11b7, 0,
+#undef V4516
+#define V4516 (V + 16055)
+ 0x1104, 0x1162, 0x11b8, 0,
+#undef V4517
+#define V4517 (V + 16059)
+ 0x1104, 0x1162, 0x11b9, 0,
+#undef V4518
+#define V4518 (V + 16063)
+ 0x1104, 0x1162, 0x11ba, 0,
+#undef V4519
+#define V4519 (V + 16067)
+ 0x1104, 0x1162, 0x11bb, 0,
+#undef V4520
+#define V4520 (V + 16071)
+ 0x1104, 0x1162, 0x11bc, 0,
+#undef V4521
+#define V4521 (V + 16075)
+ 0x1104, 0x1162, 0x11bd, 0,
+#undef V4522
+#define V4522 (V + 16079)
+ 0x1104, 0x1162, 0x11be, 0,
+#undef V4523
+#define V4523 (V + 16083)
+ 0x1104, 0x1162, 0x11bf, 0,
+#undef V4524
+#define V4524 (V + 16087)
+ 0x1104, 0x1162, 0x11c0, 0,
+#undef V4525
+#define V4525 (V + 16091)
+ 0x1104, 0x1162, 0x11c1, 0,
+#undef V4526
+#define V4526 (V + 16095)
+ 0x1104, 0x1162, 0x11c2, 0,
+#undef V4527
+#define V4527 (V + 16099)
+ 0x1104, 0x1163, 0,
+#undef V4528
+#define V4528 (V + 16102)
+ 0x1104, 0x1163, 0x11a8, 0,
+#undef V4529
+#define V4529 (V + 16106)
+ 0x1104, 0x1163, 0x11a9, 0,
+#undef V4530
+#define V4530 (V + 16110)
+ 0x1104, 0x1163, 0x11aa, 0,
+#undef V4531
+#define V4531 (V + 16114)
+ 0x1104, 0x1163, 0x11ab, 0,
+#undef V4532
+#define V4532 (V + 16118)
+ 0x1104, 0x1163, 0x11ac, 0,
+#undef V4533
+#define V4533 (V + 16122)
+ 0x1104, 0x1163, 0x11ad, 0,
+#undef V4534
+#define V4534 (V + 16126)
+ 0x1104, 0x1163, 0x11ae, 0,
+#undef V4535
+#define V4535 (V + 16130)
+ 0x1104, 0x1163, 0x11af, 0,
+#undef V4536
+#define V4536 (V + 16134)
+ 0x1104, 0x1163, 0x11b0, 0,
+#undef V4537
+#define V4537 (V + 16138)
+ 0x1104, 0x1163, 0x11b1, 0,
+#undef V4538
+#define V4538 (V + 16142)
+ 0x1104, 0x1163, 0x11b2, 0,
+#undef V4539
+#define V4539 (V + 16146)
+ 0x1104, 0x1163, 0x11b3, 0,
+#undef V4540
+#define V4540 (V + 16150)
+ 0x1104, 0x1163, 0x11b4, 0,
+#undef V4541
+#define V4541 (V + 16154)
+ 0x1104, 0x1163, 0x11b5, 0,
+#undef V4542
+#define V4542 (V + 16158)
+ 0x1104, 0x1163, 0x11b6, 0,
+#undef V4543
+#define V4543 (V + 16162)
+ 0x1104, 0x1163, 0x11b7, 0,
+#undef V4544
+#define V4544 (V + 16166)
+ 0x1104, 0x1163, 0x11b8, 0,
+#undef V4545
+#define V4545 (V + 16170)
+ 0x1104, 0x1163, 0x11b9, 0,
+#undef V4546
+#define V4546 (V + 16174)
+ 0x1104, 0x1163, 0x11ba, 0,
+#undef V4547
+#define V4547 (V + 16178)
+ 0x1104, 0x1163, 0x11bb, 0,
+#undef V4548
+#define V4548 (V + 16182)
+ 0x1104, 0x1163, 0x11bc, 0,
+#undef V4549
+#define V4549 (V + 16186)
+ 0x1104, 0x1163, 0x11bd, 0,
+#undef V4550
+#define V4550 (V + 16190)
+ 0x1104, 0x1163, 0x11be, 0,
+#undef V4551
+#define V4551 (V + 16194)
+ 0x1104, 0x1163, 0x11bf, 0,
+#undef V4552
+#define V4552 (V + 16198)
+ 0x1104, 0x1163, 0x11c0, 0,
+#undef V4553
+#define V4553 (V + 16202)
+ 0x1104, 0x1163, 0x11c1, 0,
+#undef V4554
+#define V4554 (V + 16206)
+ 0x1104, 0x1163, 0x11c2, 0,
+#undef V4555
+#define V4555 (V + 16210)
+ 0x1104, 0x1164, 0,
+#undef V4556
+#define V4556 (V + 16213)
+ 0x1104, 0x1164, 0x11a8, 0,
+#undef V4557
+#define V4557 (V + 16217)
+ 0x1104, 0x1164, 0x11a9, 0,
+#undef V4558
+#define V4558 (V + 16221)
+ 0x1104, 0x1164, 0x11aa, 0,
+#undef V4559
+#define V4559 (V + 16225)
+ 0x1104, 0x1164, 0x11ab, 0,
+#undef V4560
+#define V4560 (V + 16229)
+ 0x1104, 0x1164, 0x11ac, 0,
+#undef V4561
+#define V4561 (V + 16233)
+ 0x1104, 0x1164, 0x11ad, 0,
+#undef V4562
+#define V4562 (V + 16237)
+ 0x1104, 0x1164, 0x11ae, 0,
+#undef V4563
+#define V4563 (V + 16241)
+ 0x1104, 0x1164, 0x11af, 0,
+#undef V4564
+#define V4564 (V + 16245)
+ 0x1104, 0x1164, 0x11b0, 0,
+#undef V4565
+#define V4565 (V + 16249)
+ 0x1104, 0x1164, 0x11b1, 0,
+#undef V4566
+#define V4566 (V + 16253)
+ 0x1104, 0x1164, 0x11b2, 0,
+#undef V4567
+#define V4567 (V + 16257)
+ 0x1104, 0x1164, 0x11b3, 0,
+#undef V4568
+#define V4568 (V + 16261)
+ 0x1104, 0x1164, 0x11b4, 0,
+#undef V4569
+#define V4569 (V + 16265)
+ 0x1104, 0x1164, 0x11b5, 0,
+#undef V4570
+#define V4570 (V + 16269)
+ 0x1104, 0x1164, 0x11b6, 0,
+#undef V4571
+#define V4571 (V + 16273)
+ 0x1104, 0x1164, 0x11b7, 0,
+#undef V4572
+#define V4572 (V + 16277)
+ 0x1104, 0x1164, 0x11b8, 0,
+#undef V4573
+#define V4573 (V + 16281)
+ 0x1104, 0x1164, 0x11b9, 0,
+#undef V4574
+#define V4574 (V + 16285)
+ 0x1104, 0x1164, 0x11ba, 0,
+#undef V4575
+#define V4575 (V + 16289)
+ 0x1104, 0x1164, 0x11bb, 0,
+#undef V4576
+#define V4576 (V + 16293)
+ 0x1104, 0x1164, 0x11bc, 0,
+#undef V4577
+#define V4577 (V + 16297)
+ 0x1104, 0x1164, 0x11bd, 0,
+#undef V4578
+#define V4578 (V + 16301)
+ 0x1104, 0x1164, 0x11be, 0,
+#undef V4579
+#define V4579 (V + 16305)
+ 0x1104, 0x1164, 0x11bf, 0,
+#undef V4580
+#define V4580 (V + 16309)
+ 0x1104, 0x1164, 0x11c0, 0,
+#undef V4581
+#define V4581 (V + 16313)
+ 0x1104, 0x1164, 0x11c1, 0,
+#undef V4582
+#define V4582 (V + 16317)
+ 0x1104, 0x1164, 0x11c2, 0,
+#undef V4583
+#define V4583 (V + 16321)
+ 0x1104, 0x1165, 0,
+#undef V4584
+#define V4584 (V + 16324)
+ 0x1104, 0x1165, 0x11a8, 0,
+#undef V4585
+#define V4585 (V + 16328)
+ 0x1104, 0x1165, 0x11a9, 0,
+#undef V4586
+#define V4586 (V + 16332)
+ 0x1104, 0x1165, 0x11aa, 0,
+#undef V4587
+#define V4587 (V + 16336)
+ 0x1104, 0x1165, 0x11ab, 0,
+#undef V4588
+#define V4588 (V + 16340)
+ 0x1104, 0x1165, 0x11ac, 0,
+#undef V4589
+#define V4589 (V + 16344)
+ 0x1104, 0x1165, 0x11ad, 0,
+#undef V4590
+#define V4590 (V + 16348)
+ 0x1104, 0x1165, 0x11ae, 0,
+#undef V4591
+#define V4591 (V + 16352)
+ 0x1104, 0x1165, 0x11af, 0,
+#undef V4592
+#define V4592 (V + 16356)
+ 0x1104, 0x1165, 0x11b0, 0,
+#undef V4593
+#define V4593 (V + 16360)
+ 0x1104, 0x1165, 0x11b1, 0,
+#undef V4594
+#define V4594 (V + 16364)
+ 0x1104, 0x1165, 0x11b2, 0,
+#undef V4595
+#define V4595 (V + 16368)
+ 0x1104, 0x1165, 0x11b3, 0,
+#undef V4596
+#define V4596 (V + 16372)
+ 0x1104, 0x1165, 0x11b4, 0,
+#undef V4597
+#define V4597 (V + 16376)
+ 0x1104, 0x1165, 0x11b5, 0,
+#undef V4598
+#define V4598 (V + 16380)
+ 0x1104, 0x1165, 0x11b6, 0,
+#undef V4599
+#define V4599 (V + 16384)
+ 0x1104, 0x1165, 0x11b7, 0,
+#undef V4600
+#define V4600 (V + 16388)
+ 0x1104, 0x1165, 0x11b8, 0,
+#undef V4601
+#define V4601 (V + 16392)
+ 0x1104, 0x1165, 0x11b9, 0,
+#undef V4602
+#define V4602 (V + 16396)
+ 0x1104, 0x1165, 0x11ba, 0,
+#undef V4603
+#define V4603 (V + 16400)
+ 0x1104, 0x1165, 0x11bb, 0,
+#undef V4604
+#define V4604 (V + 16404)
+ 0x1104, 0x1165, 0x11bc, 0,
+#undef V4605
+#define V4605 (V + 16408)
+ 0x1104, 0x1165, 0x11bd, 0,
+#undef V4606
+#define V4606 (V + 16412)
+ 0x1104, 0x1165, 0x11be, 0,
+#undef V4607
+#define V4607 (V + 16416)
+ 0x1104, 0x1165, 0x11bf, 0,
+#undef V4608
+#define V4608 (V + 16420)
+ 0x1104, 0x1165, 0x11c0, 0,
+#undef V4609
+#define V4609 (V + 16424)
+ 0x1104, 0x1165, 0x11c1, 0,
+#undef V4610
+#define V4610 (V + 16428)
+ 0x1104, 0x1165, 0x11c2, 0,
+#undef V4611
+#define V4611 (V + 16432)
+ 0x1104, 0x1166, 0,
+#undef V4612
+#define V4612 (V + 16435)
+ 0x1104, 0x1166, 0x11a8, 0,
+#undef V4613
+#define V4613 (V + 16439)
+ 0x1104, 0x1166, 0x11a9, 0,
+#undef V4614
+#define V4614 (V + 16443)
+ 0x1104, 0x1166, 0x11aa, 0,
+#undef V4615
+#define V4615 (V + 16447)
+ 0x1104, 0x1166, 0x11ab, 0,
+#undef V4616
+#define V4616 (V + 16451)
+ 0x1104, 0x1166, 0x11ac, 0,
+#undef V4617
+#define V4617 (V + 16455)
+ 0x1104, 0x1166, 0x11ad, 0,
+#undef V4618
+#define V4618 (V + 16459)
+ 0x1104, 0x1166, 0x11ae, 0,
+#undef V4619
+#define V4619 (V + 16463)
+ 0x1104, 0x1166, 0x11af, 0,
+#undef V4620
+#define V4620 (V + 16467)
+ 0x1104, 0x1166, 0x11b0, 0,
+#undef V4621
+#define V4621 (V + 16471)
+ 0x1104, 0x1166, 0x11b1, 0,
+#undef V4622
+#define V4622 (V + 16475)
+ 0x1104, 0x1166, 0x11b2, 0,
+#undef V4623
+#define V4623 (V + 16479)
+ 0x1104, 0x1166, 0x11b3, 0,
+#undef V4624
+#define V4624 (V + 16483)
+ 0x1104, 0x1166, 0x11b4, 0,
+#undef V4625
+#define V4625 (V + 16487)
+ 0x1104, 0x1166, 0x11b5, 0,
+#undef V4626
+#define V4626 (V + 16491)
+ 0x1104, 0x1166, 0x11b6, 0,
+#undef V4627
+#define V4627 (V + 16495)
+ 0x1104, 0x1166, 0x11b7, 0,
+#undef V4628
+#define V4628 (V + 16499)
+ 0x1104, 0x1166, 0x11b8, 0,
+#undef V4629
+#define V4629 (V + 16503)
+ 0x1104, 0x1166, 0x11b9, 0,
+#undef V4630
+#define V4630 (V + 16507)
+ 0x1104, 0x1166, 0x11ba, 0,
+#undef V4631
+#define V4631 (V + 16511)
+ 0x1104, 0x1166, 0x11bb, 0,
+#undef V4632
+#define V4632 (V + 16515)
+ 0x1104, 0x1166, 0x11bc, 0,
+#undef V4633
+#define V4633 (V + 16519)
+ 0x1104, 0x1166, 0x11bd, 0,
+#undef V4634
+#define V4634 (V + 16523)
+ 0x1104, 0x1166, 0x11be, 0,
+#undef V4635
+#define V4635 (V + 16527)
+ 0x1104, 0x1166, 0x11bf, 0,
+#undef V4636
+#define V4636 (V + 16531)
+ 0x1104, 0x1166, 0x11c0, 0,
+#undef V4637
+#define V4637 (V + 16535)
+ 0x1104, 0x1166, 0x11c1, 0,
+#undef V4638
+#define V4638 (V + 16539)
+ 0x1104, 0x1166, 0x11c2, 0,
+#undef V4639
+#define V4639 (V + 16543)
+ 0x1104, 0x1167, 0,
+#undef V4640
+#define V4640 (V + 16546)
+ 0x1104, 0x1167, 0x11a8, 0,
+#undef V4641
+#define V4641 (V + 16550)
+ 0x1104, 0x1167, 0x11a9, 0,
+#undef V4642
+#define V4642 (V + 16554)
+ 0x1104, 0x1167, 0x11aa, 0,
+#undef V4643
+#define V4643 (V + 16558)
+ 0x1104, 0x1167, 0x11ab, 0,
+#undef V4644
+#define V4644 (V + 16562)
+ 0x1104, 0x1167, 0x11ac, 0,
+#undef V4645
+#define V4645 (V + 16566)
+ 0x1104, 0x1167, 0x11ad, 0,
+#undef V4646
+#define V4646 (V + 16570)
+ 0x1104, 0x1167, 0x11ae, 0,
+#undef V4647
+#define V4647 (V + 16574)
+ 0x1104, 0x1167, 0x11af, 0,
+#undef V4648
+#define V4648 (V + 16578)
+ 0x1104, 0x1167, 0x11b0, 0,
+#undef V4649
+#define V4649 (V + 16582)
+ 0x1104, 0x1167, 0x11b1, 0,
+#undef V4650
+#define V4650 (V + 16586)
+ 0x1104, 0x1167, 0x11b2, 0,
+#undef V4651
+#define V4651 (V + 16590)
+ 0x1104, 0x1167, 0x11b3, 0,
+#undef V4652
+#define V4652 (V + 16594)
+ 0x1104, 0x1167, 0x11b4, 0,
+#undef V4653
+#define V4653 (V + 16598)
+ 0x1104, 0x1167, 0x11b5, 0,
+#undef V4654
+#define V4654 (V + 16602)
+ 0x1104, 0x1167, 0x11b6, 0,
+#undef V4655
+#define V4655 (V + 16606)
+ 0x1104, 0x1167, 0x11b7, 0,
+#undef V4656
+#define V4656 (V + 16610)
+ 0x1104, 0x1167, 0x11b8, 0,
+#undef V4657
+#define V4657 (V + 16614)
+ 0x1104, 0x1167, 0x11b9, 0,
+#undef V4658
+#define V4658 (V + 16618)
+ 0x1104, 0x1167, 0x11ba, 0,
+#undef V4659
+#define V4659 (V + 16622)
+ 0x1104, 0x1167, 0x11bb, 0,
+#undef V4660
+#define V4660 (V + 16626)
+ 0x1104, 0x1167, 0x11bc, 0,
+#undef V4661
+#define V4661 (V + 16630)
+ 0x1104, 0x1167, 0x11bd, 0,
+#undef V4662
+#define V4662 (V + 16634)
+ 0x1104, 0x1167, 0x11be, 0,
+#undef V4663
+#define V4663 (V + 16638)
+ 0x1104, 0x1167, 0x11bf, 0,
+#undef V4664
+#define V4664 (V + 16642)
+ 0x1104, 0x1167, 0x11c0, 0,
+#undef V4665
+#define V4665 (V + 16646)
+ 0x1104, 0x1167, 0x11c1, 0,
+#undef V4666
+#define V4666 (V + 16650)
+ 0x1104, 0x1167, 0x11c2, 0,
+#undef V4667
+#define V4667 (V + 16654)
+ 0x1104, 0x1168, 0,
+#undef V4668
+#define V4668 (V + 16657)
+ 0x1104, 0x1168, 0x11a8, 0,
+#undef V4669
+#define V4669 (V + 16661)
+ 0x1104, 0x1168, 0x11a9, 0,
+#undef V4670
+#define V4670 (V + 16665)
+ 0x1104, 0x1168, 0x11aa, 0,
+#undef V4671
+#define V4671 (V + 16669)
+ 0x1104, 0x1168, 0x11ab, 0,
+#undef V4672
+#define V4672 (V + 16673)
+ 0x1104, 0x1168, 0x11ac, 0,
+#undef V4673
+#define V4673 (V + 16677)
+ 0x1104, 0x1168, 0x11ad, 0,
+#undef V4674
+#define V4674 (V + 16681)
+ 0x1104, 0x1168, 0x11ae, 0,
+#undef V4675
+#define V4675 (V + 16685)
+ 0x1104, 0x1168, 0x11af, 0,
+#undef V4676
+#define V4676 (V + 16689)
+ 0x1104, 0x1168, 0x11b0, 0,
+#undef V4677
+#define V4677 (V + 16693)
+ 0x1104, 0x1168, 0x11b1, 0,
+#undef V4678
+#define V4678 (V + 16697)
+ 0x1104, 0x1168, 0x11b2, 0,
+#undef V4679
+#define V4679 (V + 16701)
+ 0x1104, 0x1168, 0x11b3, 0,
+#undef V4680
+#define V4680 (V + 16705)
+ 0x1104, 0x1168, 0x11b4, 0,
+#undef V4681
+#define V4681 (V + 16709)
+ 0x1104, 0x1168, 0x11b5, 0,
+#undef V4682
+#define V4682 (V + 16713)
+ 0x1104, 0x1168, 0x11b6, 0,
+#undef V4683
+#define V4683 (V + 16717)
+ 0x1104, 0x1168, 0x11b7, 0,
+#undef V4684
+#define V4684 (V + 16721)
+ 0x1104, 0x1168, 0x11b8, 0,
+#undef V4685
+#define V4685 (V + 16725)
+ 0x1104, 0x1168, 0x11b9, 0,
+#undef V4686
+#define V4686 (V + 16729)
+ 0x1104, 0x1168, 0x11ba, 0,
+#undef V4687
+#define V4687 (V + 16733)
+ 0x1104, 0x1168, 0x11bb, 0,
+#undef V4688
+#define V4688 (V + 16737)
+ 0x1104, 0x1168, 0x11bc, 0,
+#undef V4689
+#define V4689 (V + 16741)
+ 0x1104, 0x1168, 0x11bd, 0,
+#undef V4690
+#define V4690 (V + 16745)
+ 0x1104, 0x1168, 0x11be, 0,
+#undef V4691
+#define V4691 (V + 16749)
+ 0x1104, 0x1168, 0x11bf, 0,
+#undef V4692
+#define V4692 (V + 16753)
+ 0x1104, 0x1168, 0x11c0, 0,
+#undef V4693
+#define V4693 (V + 16757)
+ 0x1104, 0x1168, 0x11c1, 0,
+#undef V4694
+#define V4694 (V + 16761)
+ 0x1104, 0x1168, 0x11c2, 0,
+#undef V4695
+#define V4695 (V + 16765)
+ 0x1104, 0x1169, 0,
+#undef V4696
+#define V4696 (V + 16768)
+ 0x1104, 0x1169, 0x11a8, 0,
+#undef V4697
+#define V4697 (V + 16772)
+ 0x1104, 0x1169, 0x11a9, 0,
+#undef V4698
+#define V4698 (V + 16776)
+ 0x1104, 0x1169, 0x11aa, 0,
+#undef V4699
+#define V4699 (V + 16780)
+ 0x1104, 0x1169, 0x11ab, 0,
+#undef V4700
+#define V4700 (V + 16784)
+ 0x1104, 0x1169, 0x11ac, 0,
+#undef V4701
+#define V4701 (V + 16788)
+ 0x1104, 0x1169, 0x11ad, 0,
+#undef V4702
+#define V4702 (V + 16792)
+ 0x1104, 0x1169, 0x11ae, 0,
+#undef V4703
+#define V4703 (V + 16796)
+ 0x1104, 0x1169, 0x11af, 0,
+#undef V4704
+#define V4704 (V + 16800)
+ 0x1104, 0x1169, 0x11b0, 0,
+#undef V4705
+#define V4705 (V + 16804)
+ 0x1104, 0x1169, 0x11b1, 0,
+#undef V4706
+#define V4706 (V + 16808)
+ 0x1104, 0x1169, 0x11b2, 0,
+#undef V4707
+#define V4707 (V + 16812)
+ 0x1104, 0x1169, 0x11b3, 0,
+#undef V4708
+#define V4708 (V + 16816)
+ 0x1104, 0x1169, 0x11b4, 0,
+#undef V4709
+#define V4709 (V + 16820)
+ 0x1104, 0x1169, 0x11b5, 0,
+#undef V4710
+#define V4710 (V + 16824)
+ 0x1104, 0x1169, 0x11b6, 0,
+#undef V4711
+#define V4711 (V + 16828)
+ 0x1104, 0x1169, 0x11b7, 0,
+#undef V4712
+#define V4712 (V + 16832)
+ 0x1104, 0x1169, 0x11b8, 0,
+#undef V4713
+#define V4713 (V + 16836)
+ 0x1104, 0x1169, 0x11b9, 0,
+#undef V4714
+#define V4714 (V + 16840)
+ 0x1104, 0x1169, 0x11ba, 0,
+#undef V4715
+#define V4715 (V + 16844)
+ 0x1104, 0x1169, 0x11bb, 0,
+#undef V4716
+#define V4716 (V + 16848)
+ 0x1104, 0x1169, 0x11bc, 0,
+#undef V4717
+#define V4717 (V + 16852)
+ 0x1104, 0x1169, 0x11bd, 0,
+#undef V4718
+#define V4718 (V + 16856)
+ 0x1104, 0x1169, 0x11be, 0,
+#undef V4719
+#define V4719 (V + 16860)
+ 0x1104, 0x1169, 0x11bf, 0,
+#undef V4720
+#define V4720 (V + 16864)
+ 0x1104, 0x1169, 0x11c0, 0,
+#undef V4721
+#define V4721 (V + 16868)
+ 0x1104, 0x1169, 0x11c1, 0,
+#undef V4722
+#define V4722 (V + 16872)
+ 0x1104, 0x1169, 0x11c2, 0,
+#undef V4723
+#define V4723 (V + 16876)
+ 0x1104, 0x116a, 0,
+#undef V4724
+#define V4724 (V + 16879)
+ 0x1104, 0x116a, 0x11a8, 0,
+#undef V4725
+#define V4725 (V + 16883)
+ 0x1104, 0x116a, 0x11a9, 0,
+#undef V4726
+#define V4726 (V + 16887)
+ 0x1104, 0x116a, 0x11aa, 0,
+#undef V4727
+#define V4727 (V + 16891)
+ 0x1104, 0x116a, 0x11ab, 0,
+#undef V4728
+#define V4728 (V + 16895)
+ 0x1104, 0x116a, 0x11ac, 0,
+#undef V4729
+#define V4729 (V + 16899)
+ 0x1104, 0x116a, 0x11ad, 0,
+#undef V4730
+#define V4730 (V + 16903)
+ 0x1104, 0x116a, 0x11ae, 0,
+#undef V4731
+#define V4731 (V + 16907)
+ 0x1104, 0x116a, 0x11af, 0,
+#undef V4732
+#define V4732 (V + 16911)
+ 0x1104, 0x116a, 0x11b0, 0,
+#undef V4733
+#define V4733 (V + 16915)
+ 0x1104, 0x116a, 0x11b1, 0,
+#undef V4734
+#define V4734 (V + 16919)
+ 0x1104, 0x116a, 0x11b2, 0,
+#undef V4735
+#define V4735 (V + 16923)
+ 0x1104, 0x116a, 0x11b3, 0,
+#undef V4736
+#define V4736 (V + 16927)
+ 0x1104, 0x116a, 0x11b4, 0,
+#undef V4737
+#define V4737 (V + 16931)
+ 0x1104, 0x116a, 0x11b5, 0,
+#undef V4738
+#define V4738 (V + 16935)
+ 0x1104, 0x116a, 0x11b6, 0,
+#undef V4739
+#define V4739 (V + 16939)
+ 0x1104, 0x116a, 0x11b7, 0,
+#undef V4740
+#define V4740 (V + 16943)
+ 0x1104, 0x116a, 0x11b8, 0,
+#undef V4741
+#define V4741 (V + 16947)
+ 0x1104, 0x116a, 0x11b9, 0,
+#undef V4742
+#define V4742 (V + 16951)
+ 0x1104, 0x116a, 0x11ba, 0,
+#undef V4743
+#define V4743 (V + 16955)
+ 0x1104, 0x116a, 0x11bb, 0,
+#undef V4744
+#define V4744 (V + 16959)
+ 0x1104, 0x116a, 0x11bc, 0,
+#undef V4745
+#define V4745 (V + 16963)
+ 0x1104, 0x116a, 0x11bd, 0,
+#undef V4746
+#define V4746 (V + 16967)
+ 0x1104, 0x116a, 0x11be, 0,
+#undef V4747
+#define V4747 (V + 16971)
+ 0x1104, 0x116a, 0x11bf, 0,
+#undef V4748
+#define V4748 (V + 16975)
+ 0x1104, 0x116a, 0x11c0, 0,
+#undef V4749
+#define V4749 (V + 16979)
+ 0x1104, 0x116a, 0x11c1, 0,
+#undef V4750
+#define V4750 (V + 16983)
+ 0x1104, 0x116a, 0x11c2, 0,
+#undef V4751
+#define V4751 (V + 16987)
+ 0x1104, 0x116b, 0,
+#undef V4752
+#define V4752 (V + 16990)
+ 0x1104, 0x116b, 0x11a8, 0,
+#undef V4753
+#define V4753 (V + 16994)
+ 0x1104, 0x116b, 0x11a9, 0,
+#undef V4754
+#define V4754 (V + 16998)
+ 0x1104, 0x116b, 0x11aa, 0,
+#undef V4755
+#define V4755 (V + 17002)
+ 0x1104, 0x116b, 0x11ab, 0,
+#undef V4756
+#define V4756 (V + 17006)
+ 0x1104, 0x116b, 0x11ac, 0,
+#undef V4757
+#define V4757 (V + 17010)
+ 0x1104, 0x116b, 0x11ad, 0,
+#undef V4758
+#define V4758 (V + 17014)
+ 0x1104, 0x116b, 0x11ae, 0,
+#undef V4759
+#define V4759 (V + 17018)
+ 0x1104, 0x116b, 0x11af, 0,
+#undef V4760
+#define V4760 (V + 17022)
+ 0x1104, 0x116b, 0x11b0, 0,
+#undef V4761
+#define V4761 (V + 17026)
+ 0x1104, 0x116b, 0x11b1, 0,
+#undef V4762
+#define V4762 (V + 17030)
+ 0x1104, 0x116b, 0x11b2, 0,
+#undef V4763
+#define V4763 (V + 17034)
+ 0x1104, 0x116b, 0x11b3, 0,
+#undef V4764
+#define V4764 (V + 17038)
+ 0x1104, 0x116b, 0x11b4, 0,
+#undef V4765
+#define V4765 (V + 17042)
+ 0x1104, 0x116b, 0x11b5, 0,
+#undef V4766
+#define V4766 (V + 17046)
+ 0x1104, 0x116b, 0x11b6, 0,
+#undef V4767
+#define V4767 (V + 17050)
+ 0x1104, 0x116b, 0x11b7, 0,
+#undef V4768
+#define V4768 (V + 17054)
+ 0x1104, 0x116b, 0x11b8, 0,
+#undef V4769
+#define V4769 (V + 17058)
+ 0x1104, 0x116b, 0x11b9, 0,
+#undef V4770
+#define V4770 (V + 17062)
+ 0x1104, 0x116b, 0x11ba, 0,
+#undef V4771
+#define V4771 (V + 17066)
+ 0x1104, 0x116b, 0x11bb, 0,
+#undef V4772
+#define V4772 (V + 17070)
+ 0x1104, 0x116b, 0x11bc, 0,
+#undef V4773
+#define V4773 (V + 17074)
+ 0x1104, 0x116b, 0x11bd, 0,
+#undef V4774
+#define V4774 (V + 17078)
+ 0x1104, 0x116b, 0x11be, 0,
+#undef V4775
+#define V4775 (V + 17082)
+ 0x1104, 0x116b, 0x11bf, 0,
+#undef V4776
+#define V4776 (V + 17086)
+ 0x1104, 0x116b, 0x11c0, 0,
+#undef V4777
+#define V4777 (V + 17090)
+ 0x1104, 0x116b, 0x11c1, 0,
+#undef V4778
+#define V4778 (V + 17094)
+ 0x1104, 0x116b, 0x11c2, 0,
+#undef V4779
+#define V4779 (V + 17098)
+ 0x1104, 0x116c, 0,
+#undef V4780
+#define V4780 (V + 17101)
+ 0x1104, 0x116c, 0x11a8, 0,
+#undef V4781
+#define V4781 (V + 17105)
+ 0x1104, 0x116c, 0x11a9, 0,
+#undef V4782
+#define V4782 (V + 17109)
+ 0x1104, 0x116c, 0x11aa, 0,
+#undef V4783
+#define V4783 (V + 17113)
+ 0x1104, 0x116c, 0x11ab, 0,
+#undef V4784
+#define V4784 (V + 17117)
+ 0x1104, 0x116c, 0x11ac, 0,
+#undef V4785
+#define V4785 (V + 17121)
+ 0x1104, 0x116c, 0x11ad, 0,
+#undef V4786
+#define V4786 (V + 17125)
+ 0x1104, 0x116c, 0x11ae, 0,
+#undef V4787
+#define V4787 (V + 17129)
+ 0x1104, 0x116c, 0x11af, 0,
+#undef V4788
+#define V4788 (V + 17133)
+ 0x1104, 0x116c, 0x11b0, 0,
+#undef V4789
+#define V4789 (V + 17137)
+ 0x1104, 0x116c, 0x11b1, 0,
+#undef V4790
+#define V4790 (V + 17141)
+ 0x1104, 0x116c, 0x11b2, 0,
+#undef V4791
+#define V4791 (V + 17145)
+ 0x1104, 0x116c, 0x11b3, 0,
+#undef V4792
+#define V4792 (V + 17149)
+ 0x1104, 0x116c, 0x11b4, 0,
+#undef V4793
+#define V4793 (V + 17153)
+ 0x1104, 0x116c, 0x11b5, 0,
+#undef V4794
+#define V4794 (V + 17157)
+ 0x1104, 0x116c, 0x11b6, 0,
+#undef V4795
+#define V4795 (V + 17161)
+ 0x1104, 0x116c, 0x11b7, 0,
+#undef V4796
+#define V4796 (V + 17165)
+ 0x1104, 0x116c, 0x11b8, 0,
+#undef V4797
+#define V4797 (V + 17169)
+ 0x1104, 0x116c, 0x11b9, 0,
+#undef V4798
+#define V4798 (V + 17173)
+ 0x1104, 0x116c, 0x11ba, 0,
+#undef V4799
+#define V4799 (V + 17177)
+ 0x1104, 0x116c, 0x11bb, 0,
+#undef V4800
+#define V4800 (V + 17181)
+ 0x1104, 0x116c, 0x11bc, 0,
+#undef V4801
+#define V4801 (V + 17185)
+ 0x1104, 0x116c, 0x11bd, 0,
+#undef V4802
+#define V4802 (V + 17189)
+ 0x1104, 0x116c, 0x11be, 0,
+#undef V4803
+#define V4803 (V + 17193)
+ 0x1104, 0x116c, 0x11bf, 0,
+#undef V4804
+#define V4804 (V + 17197)
+ 0x1104, 0x116c, 0x11c0, 0,
+#undef V4805
+#define V4805 (V + 17201)
+ 0x1104, 0x116c, 0x11c1, 0,
+#undef V4806
+#define V4806 (V + 17205)
+ 0x1104, 0x116c, 0x11c2, 0,
+#undef V4807
+#define V4807 (V + 17209)
+ 0x1104, 0x116d, 0,
+#undef V4808
+#define V4808 (V + 17212)
+ 0x1104, 0x116d, 0x11a8, 0,
+#undef V4809
+#define V4809 (V + 17216)
+ 0x1104, 0x116d, 0x11a9, 0,
+#undef V4810
+#define V4810 (V + 17220)
+ 0x1104, 0x116d, 0x11aa, 0,
+#undef V4811
+#define V4811 (V + 17224)
+ 0x1104, 0x116d, 0x11ab, 0,
+#undef V4812
+#define V4812 (V + 17228)
+ 0x1104, 0x116d, 0x11ac, 0,
+#undef V4813
+#define V4813 (V + 17232)
+ 0x1104, 0x116d, 0x11ad, 0,
+#undef V4814
+#define V4814 (V + 17236)
+ 0x1104, 0x116d, 0x11ae, 0,
+#undef V4815
+#define V4815 (V + 17240)
+ 0x1104, 0x116d, 0x11af, 0,
+#undef V4816
+#define V4816 (V + 17244)
+ 0x1104, 0x116d, 0x11b0, 0,
+#undef V4817
+#define V4817 (V + 17248)
+ 0x1104, 0x116d, 0x11b1, 0,
+#undef V4818
+#define V4818 (V + 17252)
+ 0x1104, 0x116d, 0x11b2, 0,
+#undef V4819
+#define V4819 (V + 17256)
+ 0x1104, 0x116d, 0x11b3, 0,
+#undef V4820
+#define V4820 (V + 17260)
+ 0x1104, 0x116d, 0x11b4, 0,
+#undef V4821
+#define V4821 (V + 17264)
+ 0x1104, 0x116d, 0x11b5, 0,
+#undef V4822
+#define V4822 (V + 17268)
+ 0x1104, 0x116d, 0x11b6, 0,
+#undef V4823
+#define V4823 (V + 17272)
+ 0x1104, 0x116d, 0x11b7, 0,
+#undef V4824
+#define V4824 (V + 17276)
+ 0x1104, 0x116d, 0x11b8, 0,
+#undef V4825
+#define V4825 (V + 17280)
+ 0x1104, 0x116d, 0x11b9, 0,
+#undef V4826
+#define V4826 (V + 17284)
+ 0x1104, 0x116d, 0x11ba, 0,
+#undef V4827
+#define V4827 (V + 17288)
+ 0x1104, 0x116d, 0x11bb, 0,
+#undef V4828
+#define V4828 (V + 17292)
+ 0x1104, 0x116d, 0x11bc, 0,
+#undef V4829
+#define V4829 (V + 17296)
+ 0x1104, 0x116d, 0x11bd, 0,
+#undef V4830
+#define V4830 (V + 17300)
+ 0x1104, 0x116d, 0x11be, 0,
+#undef V4831
+#define V4831 (V + 17304)
+ 0x1104, 0x116d, 0x11bf, 0,
+#undef V4832
+#define V4832 (V + 17308)
+ 0x1104, 0x116d, 0x11c0, 0,
+#undef V4833
+#define V4833 (V + 17312)
+ 0x1104, 0x116d, 0x11c1, 0,
+#undef V4834
+#define V4834 (V + 17316)
+ 0x1104, 0x116d, 0x11c2, 0,
+#undef V4835
+#define V4835 (V + 17320)
+ 0x1104, 0x116e, 0,
+#undef V4836
+#define V4836 (V + 17323)
+ 0x1104, 0x116e, 0x11a8, 0,
+#undef V4837
+#define V4837 (V + 17327)
+ 0x1104, 0x116e, 0x11a9, 0,
+#undef V4838
+#define V4838 (V + 17331)
+ 0x1104, 0x116e, 0x11aa, 0,
+#undef V4839
+#define V4839 (V + 17335)
+ 0x1104, 0x116e, 0x11ab, 0,
+#undef V4840
+#define V4840 (V + 17339)
+ 0x1104, 0x116e, 0x11ac, 0,
+#undef V4841
+#define V4841 (V + 17343)
+ 0x1104, 0x116e, 0x11ad, 0,
+#undef V4842
+#define V4842 (V + 17347)
+ 0x1104, 0x116e, 0x11ae, 0,
+#undef V4843
+#define V4843 (V + 17351)
+ 0x1104, 0x116e, 0x11af, 0,
+#undef V4844
+#define V4844 (V + 17355)
+ 0x1104, 0x116e, 0x11b0, 0,
+#undef V4845
+#define V4845 (V + 17359)
+ 0x1104, 0x116e, 0x11b1, 0,
+#undef V4846
+#define V4846 (V + 17363)
+ 0x1104, 0x116e, 0x11b2, 0,
+#undef V4847
+#define V4847 (V + 17367)
+ 0x1104, 0x116e, 0x11b3, 0,
+#undef V4848
+#define V4848 (V + 17371)
+ 0x1104, 0x116e, 0x11b4, 0,
+#undef V4849
+#define V4849 (V + 17375)
+ 0x1104, 0x116e, 0x11b5, 0,
+#undef V4850
+#define V4850 (V + 17379)
+ 0x1104, 0x116e, 0x11b6, 0,
+#undef V4851
+#define V4851 (V + 17383)
+ 0x1104, 0x116e, 0x11b7, 0,
+#undef V4852
+#define V4852 (V + 17387)
+ 0x1104, 0x116e, 0x11b8, 0,
+#undef V4853
+#define V4853 (V + 17391)
+ 0x1104, 0x116e, 0x11b9, 0,
+#undef V4854
+#define V4854 (V + 17395)
+ 0x1104, 0x116e, 0x11ba, 0,
+#undef V4855
+#define V4855 (V + 17399)
+ 0x1104, 0x116e, 0x11bb, 0,
+#undef V4856
+#define V4856 (V + 17403)
+ 0x1104, 0x116e, 0x11bc, 0,
+#undef V4857
+#define V4857 (V + 17407)
+ 0x1104, 0x116e, 0x11bd, 0,
+#undef V4858
+#define V4858 (V + 17411)
+ 0x1104, 0x116e, 0x11be, 0,
+#undef V4859
+#define V4859 (V + 17415)
+ 0x1104, 0x116e, 0x11bf, 0,
+#undef V4860
+#define V4860 (V + 17419)
+ 0x1104, 0x116e, 0x11c0, 0,
+#undef V4861
+#define V4861 (V + 17423)
+ 0x1104, 0x116e, 0x11c1, 0,
+#undef V4862
+#define V4862 (V + 17427)
+ 0x1104, 0x116e, 0x11c2, 0,
+#undef V4863
+#define V4863 (V + 17431)
+ 0x1104, 0x116f, 0,
+#undef V4864
+#define V4864 (V + 17434)
+ 0x1104, 0x116f, 0x11a8, 0,
+#undef V4865
+#define V4865 (V + 17438)
+ 0x1104, 0x116f, 0x11a9, 0,
+#undef V4866
+#define V4866 (V + 17442)
+ 0x1104, 0x116f, 0x11aa, 0,
+#undef V4867
+#define V4867 (V + 17446)
+ 0x1104, 0x116f, 0x11ab, 0,
+#undef V4868
+#define V4868 (V + 17450)
+ 0x1104, 0x116f, 0x11ac, 0,
+#undef V4869
+#define V4869 (V + 17454)
+ 0x1104, 0x116f, 0x11ad, 0,
+#undef V4870
+#define V4870 (V + 17458)
+ 0x1104, 0x116f, 0x11ae, 0,
+#undef V4871
+#define V4871 (V + 17462)
+ 0x1104, 0x116f, 0x11af, 0,
+#undef V4872
+#define V4872 (V + 17466)
+ 0x1104, 0x116f, 0x11b0, 0,
+#undef V4873
+#define V4873 (V + 17470)
+ 0x1104, 0x116f, 0x11b1, 0,
+#undef V4874
+#define V4874 (V + 17474)
+ 0x1104, 0x116f, 0x11b2, 0,
+#undef V4875
+#define V4875 (V + 17478)
+ 0x1104, 0x116f, 0x11b3, 0,
+#undef V4876
+#define V4876 (V + 17482)
+ 0x1104, 0x116f, 0x11b4, 0,
+#undef V4877
+#define V4877 (V + 17486)
+ 0x1104, 0x116f, 0x11b5, 0,
+#undef V4878
+#define V4878 (V + 17490)
+ 0x1104, 0x116f, 0x11b6, 0,
+#undef V4879
+#define V4879 (V + 17494)
+ 0x1104, 0x116f, 0x11b7, 0,
+#undef V4880
+#define V4880 (V + 17498)
+ 0x1104, 0x116f, 0x11b8, 0,
+#undef V4881
+#define V4881 (V + 17502)
+ 0x1104, 0x116f, 0x11b9, 0,
+#undef V4882
+#define V4882 (V + 17506)
+ 0x1104, 0x116f, 0x11ba, 0,
+#undef V4883
+#define V4883 (V + 17510)
+ 0x1104, 0x116f, 0x11bb, 0,
+#undef V4884
+#define V4884 (V + 17514)
+ 0x1104, 0x116f, 0x11bc, 0,
+#undef V4885
+#define V4885 (V + 17518)
+ 0x1104, 0x116f, 0x11bd, 0,
+#undef V4886
+#define V4886 (V + 17522)
+ 0x1104, 0x116f, 0x11be, 0,
+#undef V4887
+#define V4887 (V + 17526)
+ 0x1104, 0x116f, 0x11bf, 0,
+#undef V4888
+#define V4888 (V + 17530)
+ 0x1104, 0x116f, 0x11c0, 0,
+#undef V4889
+#define V4889 (V + 17534)
+ 0x1104, 0x116f, 0x11c1, 0,
+#undef V4890
+#define V4890 (V + 17538)
+ 0x1104, 0x116f, 0x11c2, 0,
+#undef V4891
+#define V4891 (V + 17542)
+ 0x1104, 0x1170, 0,
+#undef V4892
+#define V4892 (V + 17545)
+ 0x1104, 0x1170, 0x11a8, 0,
+#undef V4893
+#define V4893 (V + 17549)
+ 0x1104, 0x1170, 0x11a9, 0,
+#undef V4894
+#define V4894 (V + 17553)
+ 0x1104, 0x1170, 0x11aa, 0,
+#undef V4895
+#define V4895 (V + 17557)
+ 0x1104, 0x1170, 0x11ab, 0,
+#undef V4896
+#define V4896 (V + 17561)
+ 0x1104, 0x1170, 0x11ac, 0,
+#undef V4897
+#define V4897 (V + 17565)
+ 0x1104, 0x1170, 0x11ad, 0,
+#undef V4898
+#define V4898 (V + 17569)
+ 0x1104, 0x1170, 0x11ae, 0,
+#undef V4899
+#define V4899 (V + 17573)
+ 0x1104, 0x1170, 0x11af, 0,
+#undef V4900
+#define V4900 (V + 17577)
+ 0x1104, 0x1170, 0x11b0, 0,
+#undef V4901
+#define V4901 (V + 17581)
+ 0x1104, 0x1170, 0x11b1, 0,
+#undef V4902
+#define V4902 (V + 17585)
+ 0x1104, 0x1170, 0x11b2, 0,
+#undef V4903
+#define V4903 (V + 17589)
+ 0x1104, 0x1170, 0x11b3, 0,
+#undef V4904
+#define V4904 (V + 17593)
+ 0x1104, 0x1170, 0x11b4, 0,
+#undef V4905
+#define V4905 (V + 17597)
+ 0x1104, 0x1170, 0x11b5, 0,
+#undef V4906
+#define V4906 (V + 17601)
+ 0x1104, 0x1170, 0x11b6, 0,
+#undef V4907
+#define V4907 (V + 17605)
+ 0x1104, 0x1170, 0x11b7, 0,
+#undef V4908
+#define V4908 (V + 17609)
+ 0x1104, 0x1170, 0x11b8, 0,
+#undef V4909
+#define V4909 (V + 17613)
+ 0x1104, 0x1170, 0x11b9, 0,
+#undef V4910
+#define V4910 (V + 17617)
+ 0x1104, 0x1170, 0x11ba, 0,
+#undef V4911
+#define V4911 (V + 17621)
+ 0x1104, 0x1170, 0x11bb, 0,
+#undef V4912
+#define V4912 (V + 17625)
+ 0x1104, 0x1170, 0x11bc, 0,
+#undef V4913
+#define V4913 (V + 17629)
+ 0x1104, 0x1170, 0x11bd, 0,
+#undef V4914
+#define V4914 (V + 17633)
+ 0x1104, 0x1170, 0x11be, 0,
+#undef V4915
+#define V4915 (V + 17637)
+ 0x1104, 0x1170, 0x11bf, 0,
+#undef V4916
+#define V4916 (V + 17641)
+ 0x1104, 0x1170, 0x11c0, 0,
+#undef V4917
+#define V4917 (V + 17645)
+ 0x1104, 0x1170, 0x11c1, 0,
+#undef V4918
+#define V4918 (V + 17649)
+ 0x1104, 0x1170, 0x11c2, 0,
+#undef V4919
+#define V4919 (V + 17653)
+ 0x1104, 0x1171, 0,
+#undef V4920
+#define V4920 (V + 17656)
+ 0x1104, 0x1171, 0x11a8, 0,
+#undef V4921
+#define V4921 (V + 17660)
+ 0x1104, 0x1171, 0x11a9, 0,
+#undef V4922
+#define V4922 (V + 17664)
+ 0x1104, 0x1171, 0x11aa, 0,
+#undef V4923
+#define V4923 (V + 17668)
+ 0x1104, 0x1171, 0x11ab, 0,
+#undef V4924
+#define V4924 (V + 17672)
+ 0x1104, 0x1171, 0x11ac, 0,
+#undef V4925
+#define V4925 (V + 17676)
+ 0x1104, 0x1171, 0x11ad, 0,
+#undef V4926
+#define V4926 (V + 17680)
+ 0x1104, 0x1171, 0x11ae, 0,
+#undef V4927
+#define V4927 (V + 17684)
+ 0x1104, 0x1171, 0x11af, 0,
+#undef V4928
+#define V4928 (V + 17688)
+ 0x1104, 0x1171, 0x11b0, 0,
+#undef V4929
+#define V4929 (V + 17692)
+ 0x1104, 0x1171, 0x11b1, 0,
+#undef V4930
+#define V4930 (V + 17696)
+ 0x1104, 0x1171, 0x11b2, 0,
+#undef V4931
+#define V4931 (V + 17700)
+ 0x1104, 0x1171, 0x11b3, 0,
+#undef V4932
+#define V4932 (V + 17704)
+ 0x1104, 0x1171, 0x11b4, 0,
+#undef V4933
+#define V4933 (V + 17708)
+ 0x1104, 0x1171, 0x11b5, 0,
+#undef V4934
+#define V4934 (V + 17712)
+ 0x1104, 0x1171, 0x11b6, 0,
+#undef V4935
+#define V4935 (V + 17716)
+ 0x1104, 0x1171, 0x11b7, 0,
+#undef V4936
+#define V4936 (V + 17720)
+ 0x1104, 0x1171, 0x11b8, 0,
+#undef V4937
+#define V4937 (V + 17724)
+ 0x1104, 0x1171, 0x11b9, 0,
+#undef V4938
+#define V4938 (V + 17728)
+ 0x1104, 0x1171, 0x11ba, 0,
+#undef V4939
+#define V4939 (V + 17732)
+ 0x1104, 0x1171, 0x11bb, 0,
+#undef V4940
+#define V4940 (V + 17736)
+ 0x1104, 0x1171, 0x11bc, 0,
+#undef V4941
+#define V4941 (V + 17740)
+ 0x1104, 0x1171, 0x11bd, 0,
+#undef V4942
+#define V4942 (V + 17744)
+ 0x1104, 0x1171, 0x11be, 0,
+#undef V4943
+#define V4943 (V + 17748)
+ 0x1104, 0x1171, 0x11bf, 0,
+#undef V4944
+#define V4944 (V + 17752)
+ 0x1104, 0x1171, 0x11c0, 0,
+#undef V4945
+#define V4945 (V + 17756)
+ 0x1104, 0x1171, 0x11c1, 0,
+#undef V4946
+#define V4946 (V + 17760)
+ 0x1104, 0x1171, 0x11c2, 0,
+#undef V4947
+#define V4947 (V + 17764)
+ 0x1104, 0x1172, 0,
+#undef V4948
+#define V4948 (V + 17767)
+ 0x1104, 0x1172, 0x11a8, 0,
+#undef V4949
+#define V4949 (V + 17771)
+ 0x1104, 0x1172, 0x11a9, 0,
+#undef V4950
+#define V4950 (V + 17775)
+ 0x1104, 0x1172, 0x11aa, 0,
+#undef V4951
+#define V4951 (V + 17779)
+ 0x1104, 0x1172, 0x11ab, 0,
+#undef V4952
+#define V4952 (V + 17783)
+ 0x1104, 0x1172, 0x11ac, 0,
+#undef V4953
+#define V4953 (V + 17787)
+ 0x1104, 0x1172, 0x11ad, 0,
+#undef V4954
+#define V4954 (V + 17791)
+ 0x1104, 0x1172, 0x11ae, 0,
+#undef V4955
+#define V4955 (V + 17795)
+ 0x1104, 0x1172, 0x11af, 0,
+#undef V4956
+#define V4956 (V + 17799)
+ 0x1104, 0x1172, 0x11b0, 0,
+#undef V4957
+#define V4957 (V + 17803)
+ 0x1104, 0x1172, 0x11b1, 0,
+#undef V4958
+#define V4958 (V + 17807)
+ 0x1104, 0x1172, 0x11b2, 0,
+#undef V4959
+#define V4959 (V + 17811)
+ 0x1104, 0x1172, 0x11b3, 0,
+#undef V4960
+#define V4960 (V + 17815)
+ 0x1104, 0x1172, 0x11b4, 0,
+#undef V4961
+#define V4961 (V + 17819)
+ 0x1104, 0x1172, 0x11b5, 0,
+#undef V4962
+#define V4962 (V + 17823)
+ 0x1104, 0x1172, 0x11b6, 0,
+#undef V4963
+#define V4963 (V + 17827)
+ 0x1104, 0x1172, 0x11b7, 0,
+#undef V4964
+#define V4964 (V + 17831)
+ 0x1104, 0x1172, 0x11b8, 0,
+#undef V4965
+#define V4965 (V + 17835)
+ 0x1104, 0x1172, 0x11b9, 0,
+#undef V4966
+#define V4966 (V + 17839)
+ 0x1104, 0x1172, 0x11ba, 0,
+#undef V4967
+#define V4967 (V + 17843)
+ 0x1104, 0x1172, 0x11bb, 0,
+#undef V4968
+#define V4968 (V + 17847)
+ 0x1104, 0x1172, 0x11bc, 0,
+#undef V4969
+#define V4969 (V + 17851)
+ 0x1104, 0x1172, 0x11bd, 0,
+#undef V4970
+#define V4970 (V + 17855)
+ 0x1104, 0x1172, 0x11be, 0,
+#undef V4971
+#define V4971 (V + 17859)
+ 0x1104, 0x1172, 0x11bf, 0,
+#undef V4972
+#define V4972 (V + 17863)
+ 0x1104, 0x1172, 0x11c0, 0,
+#undef V4973
+#define V4973 (V + 17867)
+ 0x1104, 0x1172, 0x11c1, 0,
+#undef V4974
+#define V4974 (V + 17871)
+ 0x1104, 0x1172, 0x11c2, 0,
+#undef V4975
+#define V4975 (V + 17875)
+ 0x1104, 0x1173, 0,
+#undef V4976
+#define V4976 (V + 17878)
+ 0x1104, 0x1173, 0x11a8, 0,
+#undef V4977
+#define V4977 (V + 17882)
+ 0x1104, 0x1173, 0x11a9, 0,
+#undef V4978
+#define V4978 (V + 17886)
+ 0x1104, 0x1173, 0x11aa, 0,
+#undef V4979
+#define V4979 (V + 17890)
+ 0x1104, 0x1173, 0x11ab, 0,
+#undef V4980
+#define V4980 (V + 17894)
+ 0x1104, 0x1173, 0x11ac, 0,
+#undef V4981
+#define V4981 (V + 17898)
+ 0x1104, 0x1173, 0x11ad, 0,
+#undef V4982
+#define V4982 (V + 17902)
+ 0x1104, 0x1173, 0x11ae, 0,
+#undef V4983
+#define V4983 (V + 17906)
+ 0x1104, 0x1173, 0x11af, 0,
+#undef V4984
+#define V4984 (V + 17910)
+ 0x1104, 0x1173, 0x11b0, 0,
+#undef V4985
+#define V4985 (V + 17914)
+ 0x1104, 0x1173, 0x11b1, 0,
+#undef V4986
+#define V4986 (V + 17918)
+ 0x1104, 0x1173, 0x11b2, 0,
+#undef V4987
+#define V4987 (V + 17922)
+ 0x1104, 0x1173, 0x11b3, 0,
+#undef V4988
+#define V4988 (V + 17926)
+ 0x1104, 0x1173, 0x11b4, 0,
+#undef V4989
+#define V4989 (V + 17930)
+ 0x1104, 0x1173, 0x11b5, 0,
+#undef V4990
+#define V4990 (V + 17934)
+ 0x1104, 0x1173, 0x11b6, 0,
+#undef V4991
+#define V4991 (V + 17938)
+ 0x1104, 0x1173, 0x11b7, 0,
+#undef V4992
+#define V4992 (V + 17942)
+ 0x1104, 0x1173, 0x11b8, 0,
+#undef V4993
+#define V4993 (V + 17946)
+ 0x1104, 0x1173, 0x11b9, 0,
+#undef V4994
+#define V4994 (V + 17950)
+ 0x1104, 0x1173, 0x11ba, 0,
+#undef V4995
+#define V4995 (V + 17954)
+ 0x1104, 0x1173, 0x11bb, 0,
+#undef V4996
+#define V4996 (V + 17958)
+ 0x1104, 0x1173, 0x11bc, 0,
+#undef V4997
+#define V4997 (V + 17962)
+ 0x1104, 0x1173, 0x11bd, 0,
+#undef V4998
+#define V4998 (V + 17966)
+ 0x1104, 0x1173, 0x11be, 0,
+#undef V4999
+#define V4999 (V + 17970)
+ 0x1104, 0x1173, 0x11bf, 0,
+#undef V5000
+#define V5000 (V + 17974)
+ 0x1104, 0x1173, 0x11c0, 0,
+#undef V5001
+#define V5001 (V + 17978)
+ 0x1104, 0x1173, 0x11c1, 0,
+#undef V5002
+#define V5002 (V + 17982)
+ 0x1104, 0x1173, 0x11c2, 0,
+#undef V5003
+#define V5003 (V + 17986)
+ 0x1104, 0x1174, 0,
+#undef V5004
+#define V5004 (V + 17989)
+ 0x1104, 0x1174, 0x11a8, 0,
+#undef V5005
+#define V5005 (V + 17993)
+ 0x1104, 0x1174, 0x11a9, 0,
+#undef V5006
+#define V5006 (V + 17997)
+ 0x1104, 0x1174, 0x11aa, 0,
+#undef V5007
+#define V5007 (V + 18001)
+ 0x1104, 0x1174, 0x11ab, 0,
+#undef V5008
+#define V5008 (V + 18005)
+ 0x1104, 0x1174, 0x11ac, 0,
+#undef V5009
+#define V5009 (V + 18009)
+ 0x1104, 0x1174, 0x11ad, 0,
+#undef V5010
+#define V5010 (V + 18013)
+ 0x1104, 0x1174, 0x11ae, 0,
+#undef V5011
+#define V5011 (V + 18017)
+ 0x1104, 0x1174, 0x11af, 0,
+#undef V5012
+#define V5012 (V + 18021)
+ 0x1104, 0x1174, 0x11b0, 0,
+#undef V5013
+#define V5013 (V + 18025)
+ 0x1104, 0x1174, 0x11b1, 0,
+#undef V5014
+#define V5014 (V + 18029)
+ 0x1104, 0x1174, 0x11b2, 0,
+#undef V5015
+#define V5015 (V + 18033)
+ 0x1104, 0x1174, 0x11b3, 0,
+#undef V5016
+#define V5016 (V + 18037)
+ 0x1104, 0x1174, 0x11b4, 0,
+#undef V5017
+#define V5017 (V + 18041)
+ 0x1104, 0x1174, 0x11b5, 0,
+#undef V5018
+#define V5018 (V + 18045)
+ 0x1104, 0x1174, 0x11b6, 0,
+#undef V5019
+#define V5019 (V + 18049)
+ 0x1104, 0x1174, 0x11b7, 0,
+#undef V5020
+#define V5020 (V + 18053)
+ 0x1104, 0x1174, 0x11b8, 0,
+#undef V5021
+#define V5021 (V + 18057)
+ 0x1104, 0x1174, 0x11b9, 0,
+#undef V5022
+#define V5022 (V + 18061)
+ 0x1104, 0x1174, 0x11ba, 0,
+#undef V5023
+#define V5023 (V + 18065)
+ 0x1104, 0x1174, 0x11bb, 0,
+#undef V5024
+#define V5024 (V + 18069)
+ 0x1104, 0x1174, 0x11bc, 0,
+#undef V5025
+#define V5025 (V + 18073)
+ 0x1104, 0x1174, 0x11bd, 0,
+#undef V5026
+#define V5026 (V + 18077)
+ 0x1104, 0x1174, 0x11be, 0,
+#undef V5027
+#define V5027 (V + 18081)
+ 0x1104, 0x1174, 0x11bf, 0,
+#undef V5028
+#define V5028 (V + 18085)
+ 0x1104, 0x1174, 0x11c0, 0,
+#undef V5029
+#define V5029 (V + 18089)
+ 0x1104, 0x1174, 0x11c1, 0,
+#undef V5030
+#define V5030 (V + 18093)
+ 0x1104, 0x1174, 0x11c2, 0,
+#undef V5031
+#define V5031 (V + 18097)
+ 0x1104, 0x1175, 0,
+#undef V5032
+#define V5032 (V + 18100)
+ 0x1104, 0x1175, 0x11a8, 0,
+#undef V5033
+#define V5033 (V + 18104)
+ 0x1104, 0x1175, 0x11a9, 0,
+#undef V5034
+#define V5034 (V + 18108)
+ 0x1104, 0x1175, 0x11aa, 0,
+#undef V5035
+#define V5035 (V + 18112)
+ 0x1104, 0x1175, 0x11ab, 0,
+#undef V5036
+#define V5036 (V + 18116)
+ 0x1104, 0x1175, 0x11ac, 0,
+#undef V5037
+#define V5037 (V + 18120)
+ 0x1104, 0x1175, 0x11ad, 0,
+#undef V5038
+#define V5038 (V + 18124)
+ 0x1104, 0x1175, 0x11ae, 0,
+#undef V5039
+#define V5039 (V + 18128)
+ 0x1104, 0x1175, 0x11af, 0,
+#undef V5040
+#define V5040 (V + 18132)
+ 0x1104, 0x1175, 0x11b0, 0,
+#undef V5041
+#define V5041 (V + 18136)
+ 0x1104, 0x1175, 0x11b1, 0,
+#undef V5042
+#define V5042 (V + 18140)
+ 0x1104, 0x1175, 0x11b2, 0,
+#undef V5043
+#define V5043 (V + 18144)
+ 0x1104, 0x1175, 0x11b3, 0,
+#undef V5044
+#define V5044 (V + 18148)
+ 0x1104, 0x1175, 0x11b4, 0,
+#undef V5045
+#define V5045 (V + 18152)
+ 0x1104, 0x1175, 0x11b5, 0,
+#undef V5046
+#define V5046 (V + 18156)
+ 0x1104, 0x1175, 0x11b6, 0,
+#undef V5047
+#define V5047 (V + 18160)
+ 0x1104, 0x1175, 0x11b7, 0,
+#undef V5048
+#define V5048 (V + 18164)
+ 0x1104, 0x1175, 0x11b8, 0,
+#undef V5049
+#define V5049 (V + 18168)
+ 0x1104, 0x1175, 0x11b9, 0,
+#undef V5050
+#define V5050 (V + 18172)
+ 0x1104, 0x1175, 0x11ba, 0,
+#undef V5051
+#define V5051 (V + 18176)
+ 0x1104, 0x1175, 0x11bb, 0,
+#undef V5052
+#define V5052 (V + 18180)
+ 0x1104, 0x1175, 0x11bc, 0,
+#undef V5053
+#define V5053 (V + 18184)
+ 0x1104, 0x1175, 0x11bd, 0,
+#undef V5054
+#define V5054 (V + 18188)
+ 0x1104, 0x1175, 0x11be, 0,
+#undef V5055
+#define V5055 (V + 18192)
+ 0x1104, 0x1175, 0x11bf, 0,
+#undef V5056
+#define V5056 (V + 18196)
+ 0x1104, 0x1175, 0x11c0, 0,
+#undef V5057
+#define V5057 (V + 18200)
+ 0x1104, 0x1175, 0x11c1, 0,
+#undef V5058
+#define V5058 (V + 18204)
+ 0x1104, 0x1175, 0x11c2, 0,
+#undef V5059
+#define V5059 (V + 18208)
+ 0x1105, 0x1161, 0x11a8, 0,
+#undef V5060
+#define V5060 (V + 18212)
+ 0x1105, 0x1161, 0x11a9, 0,
+#undef V5061
+#define V5061 (V + 18216)
+ 0x1105, 0x1161, 0x11aa, 0,
+#undef V5062
+#define V5062 (V + 18220)
+ 0x1105, 0x1161, 0x11ab, 0,
+#undef V5063
+#define V5063 (V + 18224)
+ 0x1105, 0x1161, 0x11ac, 0,
+#undef V5064
+#define V5064 (V + 18228)
+ 0x1105, 0x1161, 0x11ad, 0,
+#undef V5065
+#define V5065 (V + 18232)
+ 0x1105, 0x1161, 0x11ae, 0,
+#undef V5066
+#define V5066 (V + 18236)
+ 0x1105, 0x1161, 0x11af, 0,
+#undef V5067
+#define V5067 (V + 18240)
+ 0x1105, 0x1161, 0x11b0, 0,
+#undef V5068
+#define V5068 (V + 18244)
+ 0x1105, 0x1161, 0x11b1, 0,
+#undef V5069
+#define V5069 (V + 18248)
+ 0x1105, 0x1161, 0x11b2, 0,
+#undef V5070
+#define V5070 (V + 18252)
+ 0x1105, 0x1161, 0x11b3, 0,
+#undef V5071
+#define V5071 (V + 18256)
+ 0x1105, 0x1161, 0x11b4, 0,
+#undef V5072
+#define V5072 (V + 18260)
+ 0x1105, 0x1161, 0x11b5, 0,
+#undef V5073
+#define V5073 (V + 18264)
+ 0x1105, 0x1161, 0x11b6, 0,
+#undef V5074
+#define V5074 (V + 18268)
+ 0x1105, 0x1161, 0x11b7, 0,
+#undef V5075
+#define V5075 (V + 18272)
+ 0x1105, 0x1161, 0x11b8, 0,
+#undef V5076
+#define V5076 (V + 18276)
+ 0x1105, 0x1161, 0x11b9, 0,
+#undef V5077
+#define V5077 (V + 18280)
+ 0x1105, 0x1161, 0x11ba, 0,
+#undef V5078
+#define V5078 (V + 18284)
+ 0x1105, 0x1161, 0x11bb, 0,
+#undef V5079
+#define V5079 (V + 18288)
+ 0x1105, 0x1161, 0x11bc, 0,
+#undef V5080
+#define V5080 (V + 18292)
+ 0x1105, 0x1161, 0x11bd, 0,
+#undef V5081
+#define V5081 (V + 18296)
+ 0x1105, 0x1161, 0x11be, 0,
+#undef V5082
+#define V5082 (V + 18300)
+ 0x1105, 0x1161, 0x11bf, 0,
+#undef V5083
+#define V5083 (V + 18304)
+ 0x1105, 0x1161, 0x11c0, 0,
+#undef V5084
+#define V5084 (V + 18308)
+ 0x1105, 0x1161, 0x11c1, 0,
+#undef V5085
+#define V5085 (V + 18312)
+ 0x1105, 0x1161, 0x11c2, 0,
+#undef V5086
+#define V5086 (V + 18316)
+ 0x1105, 0x1162, 0,
+#undef V5087
+#define V5087 (V + 18319)
+ 0x1105, 0x1162, 0x11a8, 0,
+#undef V5088
+#define V5088 (V + 18323)
+ 0x1105, 0x1162, 0x11a9, 0,
+#undef V5089
+#define V5089 (V + 18327)
+ 0x1105, 0x1162, 0x11aa, 0,
+#undef V5090
+#define V5090 (V + 18331)
+ 0x1105, 0x1162, 0x11ab, 0,
+#undef V5091
+#define V5091 (V + 18335)
+ 0x1105, 0x1162, 0x11ac, 0,
+#undef V5092
+#define V5092 (V + 18339)
+ 0x1105, 0x1162, 0x11ad, 0,
+#undef V5093
+#define V5093 (V + 18343)
+ 0x1105, 0x1162, 0x11ae, 0,
+#undef V5094
+#define V5094 (V + 18347)
+ 0x1105, 0x1162, 0x11af, 0,
+#undef V5095
+#define V5095 (V + 18351)
+ 0x1105, 0x1162, 0x11b0, 0,
+#undef V5096
+#define V5096 (V + 18355)
+ 0x1105, 0x1162, 0x11b1, 0,
+#undef V5097
+#define V5097 (V + 18359)
+ 0x1105, 0x1162, 0x11b2, 0,
+#undef V5098
+#define V5098 (V + 18363)
+ 0x1105, 0x1162, 0x11b3, 0,
+#undef V5099
+#define V5099 (V + 18367)
+ 0x1105, 0x1162, 0x11b4, 0,
+#undef V5100
+#define V5100 (V + 18371)
+ 0x1105, 0x1162, 0x11b5, 0,
+#undef V5101
+#define V5101 (V + 18375)
+ 0x1105, 0x1162, 0x11b6, 0,
+#undef V5102
+#define V5102 (V + 18379)
+ 0x1105, 0x1162, 0x11b7, 0,
+#undef V5103
+#define V5103 (V + 18383)
+ 0x1105, 0x1162, 0x11b8, 0,
+#undef V5104
+#define V5104 (V + 18387)
+ 0x1105, 0x1162, 0x11b9, 0,
+#undef V5105
+#define V5105 (V + 18391)
+ 0x1105, 0x1162, 0x11ba, 0,
+#undef V5106
+#define V5106 (V + 18395)
+ 0x1105, 0x1162, 0x11bb, 0,
+#undef V5107
+#define V5107 (V + 18399)
+ 0x1105, 0x1162, 0x11bc, 0,
+#undef V5108
+#define V5108 (V + 18403)
+ 0x1105, 0x1162, 0x11bd, 0,
+#undef V5109
+#define V5109 (V + 18407)
+ 0x1105, 0x1162, 0x11be, 0,
+#undef V5110
+#define V5110 (V + 18411)
+ 0x1105, 0x1162, 0x11bf, 0,
+#undef V5111
+#define V5111 (V + 18415)
+ 0x1105, 0x1162, 0x11c0, 0,
+#undef V5112
+#define V5112 (V + 18419)
+ 0x1105, 0x1162, 0x11c1, 0,
+#undef V5113
+#define V5113 (V + 18423)
+ 0x1105, 0x1162, 0x11c2, 0,
+#undef V5114
+#define V5114 (V + 18427)
+ 0x1105, 0x1163, 0,
+#undef V5115
+#define V5115 (V + 18430)
+ 0x1105, 0x1163, 0x11a8, 0,
+#undef V5116
+#define V5116 (V + 18434)
+ 0x1105, 0x1163, 0x11a9, 0,
+#undef V5117
+#define V5117 (V + 18438)
+ 0x1105, 0x1163, 0x11aa, 0,
+#undef V5118
+#define V5118 (V + 18442)
+ 0x1105, 0x1163, 0x11ab, 0,
+#undef V5119
+#define V5119 (V + 18446)
+ 0x1105, 0x1163, 0x11ac, 0,
+#undef V5120
+#define V5120 (V + 18450)
+ 0x1105, 0x1163, 0x11ad, 0,
+#undef V5121
+#define V5121 (V + 18454)
+ 0x1105, 0x1163, 0x11ae, 0,
+#undef V5122
+#define V5122 (V + 18458)
+ 0x1105, 0x1163, 0x11af, 0,
+#undef V5123
+#define V5123 (V + 18462)
+ 0x1105, 0x1163, 0x11b0, 0,
+#undef V5124
+#define V5124 (V + 18466)
+ 0x1105, 0x1163, 0x11b1, 0,
+#undef V5125
+#define V5125 (V + 18470)
+ 0x1105, 0x1163, 0x11b2, 0,
+#undef V5126
+#define V5126 (V + 18474)
+ 0x1105, 0x1163, 0x11b3, 0,
+#undef V5127
+#define V5127 (V + 18478)
+ 0x1105, 0x1163, 0x11b4, 0,
+#undef V5128
+#define V5128 (V + 18482)
+ 0x1105, 0x1163, 0x11b5, 0,
+#undef V5129
+#define V5129 (V + 18486)
+ 0x1105, 0x1163, 0x11b6, 0,
+#undef V5130
+#define V5130 (V + 18490)
+ 0x1105, 0x1163, 0x11b7, 0,
+#undef V5131
+#define V5131 (V + 18494)
+ 0x1105, 0x1163, 0x11b8, 0,
+#undef V5132
+#define V5132 (V + 18498)
+ 0x1105, 0x1163, 0x11b9, 0,
+#undef V5133
+#define V5133 (V + 18502)
+ 0x1105, 0x1163, 0x11ba, 0,
+#undef V5134
+#define V5134 (V + 18506)
+ 0x1105, 0x1163, 0x11bb, 0,
+#undef V5135
+#define V5135 (V + 18510)
+ 0x1105, 0x1163, 0x11bc, 0,
+#undef V5136
+#define V5136 (V + 18514)
+ 0x1105, 0x1163, 0x11bd, 0,
+#undef V5137
+#define V5137 (V + 18518)
+ 0x1105, 0x1163, 0x11be, 0,
+#undef V5138
+#define V5138 (V + 18522)
+ 0x1105, 0x1163, 0x11bf, 0,
+#undef V5139
+#define V5139 (V + 18526)
+ 0x1105, 0x1163, 0x11c0, 0,
+#undef V5140
+#define V5140 (V + 18530)
+ 0x1105, 0x1163, 0x11c1, 0,
+#undef V5141
+#define V5141 (V + 18534)
+ 0x1105, 0x1163, 0x11c2, 0,
+#undef V5142
+#define V5142 (V + 18538)
+ 0x1105, 0x1164, 0,
+#undef V5143
+#define V5143 (V + 18541)
+ 0x1105, 0x1164, 0x11a8, 0,
+#undef V5144
+#define V5144 (V + 18545)
+ 0x1105, 0x1164, 0x11a9, 0,
+#undef V5145
+#define V5145 (V + 18549)
+ 0x1105, 0x1164, 0x11aa, 0,
+#undef V5146
+#define V5146 (V + 18553)
+ 0x1105, 0x1164, 0x11ab, 0,
+#undef V5147
+#define V5147 (V + 18557)
+ 0x1105, 0x1164, 0x11ac, 0,
+#undef V5148
+#define V5148 (V + 18561)
+ 0x1105, 0x1164, 0x11ad, 0,
+#undef V5149
+#define V5149 (V + 18565)
+ 0x1105, 0x1164, 0x11ae, 0,
+#undef V5150
+#define V5150 (V + 18569)
+ 0x1105, 0x1164, 0x11af, 0,
+#undef V5151
+#define V5151 (V + 18573)
+ 0x1105, 0x1164, 0x11b0, 0,
+#undef V5152
+#define V5152 (V + 18577)
+ 0x1105, 0x1164, 0x11b1, 0,
+#undef V5153
+#define V5153 (V + 18581)
+ 0x1105, 0x1164, 0x11b2, 0,
+#undef V5154
+#define V5154 (V + 18585)
+ 0x1105, 0x1164, 0x11b3, 0,
+#undef V5155
+#define V5155 (V + 18589)
+ 0x1105, 0x1164, 0x11b4, 0,
+#undef V5156
+#define V5156 (V + 18593)
+ 0x1105, 0x1164, 0x11b5, 0,
+#undef V5157
+#define V5157 (V + 18597)
+ 0x1105, 0x1164, 0x11b6, 0,
+#undef V5158
+#define V5158 (V + 18601)
+ 0x1105, 0x1164, 0x11b7, 0,
+#undef V5159
+#define V5159 (V + 18605)
+ 0x1105, 0x1164, 0x11b8, 0,
+#undef V5160
+#define V5160 (V + 18609)
+ 0x1105, 0x1164, 0x11b9, 0,
+#undef V5161
+#define V5161 (V + 18613)
+ 0x1105, 0x1164, 0x11ba, 0,
+#undef V5162
+#define V5162 (V + 18617)
+ 0x1105, 0x1164, 0x11bb, 0,
+#undef V5163
+#define V5163 (V + 18621)
+ 0x1105, 0x1164, 0x11bc, 0,
+#undef V5164
+#define V5164 (V + 18625)
+ 0x1105, 0x1164, 0x11bd, 0,
+#undef V5165
+#define V5165 (V + 18629)
+ 0x1105, 0x1164, 0x11be, 0,
+#undef V5166
+#define V5166 (V + 18633)
+ 0x1105, 0x1164, 0x11bf, 0,
+#undef V5167
+#define V5167 (V + 18637)
+ 0x1105, 0x1164, 0x11c0, 0,
+#undef V5168
+#define V5168 (V + 18641)
+ 0x1105, 0x1164, 0x11c1, 0,
+#undef V5169
+#define V5169 (V + 18645)
+ 0x1105, 0x1164, 0x11c2, 0,
+#undef V5170
+#define V5170 (V + 18649)
+ 0x1105, 0x1165, 0,
+#undef V5171
+#define V5171 (V + 18652)
+ 0x1105, 0x1165, 0x11a8, 0,
+#undef V5172
+#define V5172 (V + 18656)
+ 0x1105, 0x1165, 0x11a9, 0,
+#undef V5173
+#define V5173 (V + 18660)
+ 0x1105, 0x1165, 0x11aa, 0,
+#undef V5174
+#define V5174 (V + 18664)
+ 0x1105, 0x1165, 0x11ab, 0,
+#undef V5175
+#define V5175 (V + 18668)
+ 0x1105, 0x1165, 0x11ac, 0,
+#undef V5176
+#define V5176 (V + 18672)
+ 0x1105, 0x1165, 0x11ad, 0,
+#undef V5177
+#define V5177 (V + 18676)
+ 0x1105, 0x1165, 0x11ae, 0,
+#undef V5178
+#define V5178 (V + 18680)
+ 0x1105, 0x1165, 0x11af, 0,
+#undef V5179
+#define V5179 (V + 18684)
+ 0x1105, 0x1165, 0x11b0, 0,
+#undef V5180
+#define V5180 (V + 18688)
+ 0x1105, 0x1165, 0x11b1, 0,
+#undef V5181
+#define V5181 (V + 18692)
+ 0x1105, 0x1165, 0x11b2, 0,
+#undef V5182
+#define V5182 (V + 18696)
+ 0x1105, 0x1165, 0x11b3, 0,
+#undef V5183
+#define V5183 (V + 18700)
+ 0x1105, 0x1165, 0x11b4, 0,
+#undef V5184
+#define V5184 (V + 18704)
+ 0x1105, 0x1165, 0x11b5, 0,
+#undef V5185
+#define V5185 (V + 18708)
+ 0x1105, 0x1165, 0x11b6, 0,
+#undef V5186
+#define V5186 (V + 18712)
+ 0x1105, 0x1165, 0x11b7, 0,
+#undef V5187
+#define V5187 (V + 18716)
+ 0x1105, 0x1165, 0x11b8, 0,
+#undef V5188
+#define V5188 (V + 18720)
+ 0x1105, 0x1165, 0x11b9, 0,
+#undef V5189
+#define V5189 (V + 18724)
+ 0x1105, 0x1165, 0x11ba, 0,
+#undef V5190
+#define V5190 (V + 18728)
+ 0x1105, 0x1165, 0x11bb, 0,
+#undef V5191
+#define V5191 (V + 18732)
+ 0x1105, 0x1165, 0x11bc, 0,
+#undef V5192
+#define V5192 (V + 18736)
+ 0x1105, 0x1165, 0x11bd, 0,
+#undef V5193
+#define V5193 (V + 18740)
+ 0x1105, 0x1165, 0x11be, 0,
+#undef V5194
+#define V5194 (V + 18744)
+ 0x1105, 0x1165, 0x11bf, 0,
+#undef V5195
+#define V5195 (V + 18748)
+ 0x1105, 0x1165, 0x11c0, 0,
+#undef V5196
+#define V5196 (V + 18752)
+ 0x1105, 0x1165, 0x11c1, 0,
+#undef V5197
+#define V5197 (V + 18756)
+ 0x1105, 0x1165, 0x11c2, 0,
+#undef V5198
+#define V5198 (V + 18760)
+ 0x1105, 0x1166, 0,
+#undef V5199
+#define V5199 (V + 18763)
+ 0x1105, 0x1166, 0x11a8, 0,
+#undef V5200
+#define V5200 (V + 18767)
+ 0x1105, 0x1166, 0x11a9, 0,
+#undef V5201
+#define V5201 (V + 18771)
+ 0x1105, 0x1166, 0x11aa, 0,
+#undef V5202
+#define V5202 (V + 18775)
+ 0x1105, 0x1166, 0x11ab, 0,
+#undef V5203
+#define V5203 (V + 18779)
+ 0x1105, 0x1166, 0x11ac, 0,
+#undef V5204
+#define V5204 (V + 18783)
+ 0x1105, 0x1166, 0x11ad, 0,
+#undef V5205
+#define V5205 (V + 18787)
+ 0x1105, 0x1166, 0x11ae, 0,
+#undef V5206
+#define V5206 (V + 18791)
+ 0x1105, 0x1166, 0x11af, 0,
+#undef V5207
+#define V5207 (V + 18795)
+ 0x1105, 0x1166, 0x11b0, 0,
+#undef V5208
+#define V5208 (V + 18799)
+ 0x1105, 0x1166, 0x11b1, 0,
+#undef V5209
+#define V5209 (V + 18803)
+ 0x1105, 0x1166, 0x11b2, 0,
+#undef V5210
+#define V5210 (V + 18807)
+ 0x1105, 0x1166, 0x11b3, 0,
+#undef V5211
+#define V5211 (V + 18811)
+ 0x1105, 0x1166, 0x11b4, 0,
+#undef V5212
+#define V5212 (V + 18815)
+ 0x1105, 0x1166, 0x11b5, 0,
+#undef V5213
+#define V5213 (V + 18819)
+ 0x1105, 0x1166, 0x11b6, 0,
+#undef V5214
+#define V5214 (V + 18823)
+ 0x1105, 0x1166, 0x11b7, 0,
+#undef V5215
+#define V5215 (V + 18827)
+ 0x1105, 0x1166, 0x11b8, 0,
+#undef V5216
+#define V5216 (V + 18831)
+ 0x1105, 0x1166, 0x11b9, 0,
+#undef V5217
+#define V5217 (V + 18835)
+ 0x1105, 0x1166, 0x11ba, 0,
+#undef V5218
+#define V5218 (V + 18839)
+ 0x1105, 0x1166, 0x11bb, 0,
+#undef V5219
+#define V5219 (V + 18843)
+ 0x1105, 0x1166, 0x11bc, 0,
+#undef V5220
+#define V5220 (V + 18847)
+ 0x1105, 0x1166, 0x11bd, 0,
+#undef V5221
+#define V5221 (V + 18851)
+ 0x1105, 0x1166, 0x11be, 0,
+#undef V5222
+#define V5222 (V + 18855)
+ 0x1105, 0x1166, 0x11bf, 0,
+#undef V5223
+#define V5223 (V + 18859)
+ 0x1105, 0x1166, 0x11c0, 0,
+#undef V5224
+#define V5224 (V + 18863)
+ 0x1105, 0x1166, 0x11c1, 0,
+#undef V5225
+#define V5225 (V + 18867)
+ 0x1105, 0x1166, 0x11c2, 0,
+#undef V5226
+#define V5226 (V + 18871)
+ 0x1105, 0x1167, 0,
+#undef V5227
+#define V5227 (V + 18874)
+ 0x1105, 0x1167, 0x11a8, 0,
+#undef V5228
+#define V5228 (V + 18878)
+ 0x1105, 0x1167, 0x11a9, 0,
+#undef V5229
+#define V5229 (V + 18882)
+ 0x1105, 0x1167, 0x11aa, 0,
+#undef V5230
+#define V5230 (V + 18886)
+ 0x1105, 0x1167, 0x11ab, 0,
+#undef V5231
+#define V5231 (V + 18890)
+ 0x1105, 0x1167, 0x11ac, 0,
+#undef V5232
+#define V5232 (V + 18894)
+ 0x1105, 0x1167, 0x11ad, 0,
+#undef V5233
+#define V5233 (V + 18898)
+ 0x1105, 0x1167, 0x11ae, 0,
+#undef V5234
+#define V5234 (V + 18902)
+ 0x1105, 0x1167, 0x11af, 0,
+#undef V5235
+#define V5235 (V + 18906)
+ 0x1105, 0x1167, 0x11b0, 0,
+#undef V5236
+#define V5236 (V + 18910)
+ 0x1105, 0x1167, 0x11b1, 0,
+#undef V5237
+#define V5237 (V + 18914)
+ 0x1105, 0x1167, 0x11b2, 0,
+#undef V5238
+#define V5238 (V + 18918)
+ 0x1105, 0x1167, 0x11b3, 0,
+#undef V5239
+#define V5239 (V + 18922)
+ 0x1105, 0x1167, 0x11b4, 0,
+#undef V5240
+#define V5240 (V + 18926)
+ 0x1105, 0x1167, 0x11b5, 0,
+#undef V5241
+#define V5241 (V + 18930)
+ 0x1105, 0x1167, 0x11b6, 0,
+#undef V5242
+#define V5242 (V + 18934)
+ 0x1105, 0x1167, 0x11b7, 0,
+#undef V5243
+#define V5243 (V + 18938)
+ 0x1105, 0x1167, 0x11b8, 0,
+#undef V5244
+#define V5244 (V + 18942)
+ 0x1105, 0x1167, 0x11b9, 0,
+#undef V5245
+#define V5245 (V + 18946)
+ 0x1105, 0x1167, 0x11ba, 0,
+#undef V5246
+#define V5246 (V + 18950)
+ 0x1105, 0x1167, 0x11bb, 0,
+#undef V5247
+#define V5247 (V + 18954)
+ 0x1105, 0x1167, 0x11bc, 0,
+#undef V5248
+#define V5248 (V + 18958)
+ 0x1105, 0x1167, 0x11bd, 0,
+#undef V5249
+#define V5249 (V + 18962)
+ 0x1105, 0x1167, 0x11be, 0,
+#undef V5250
+#define V5250 (V + 18966)
+ 0x1105, 0x1167, 0x11bf, 0,
+#undef V5251
+#define V5251 (V + 18970)
+ 0x1105, 0x1167, 0x11c0, 0,
+#undef V5252
+#define V5252 (V + 18974)
+ 0x1105, 0x1167, 0x11c1, 0,
+#undef V5253
+#define V5253 (V + 18978)
+ 0x1105, 0x1167, 0x11c2, 0,
+#undef V5254
+#define V5254 (V + 18982)
+ 0x1105, 0x1168, 0,
+#undef V5255
+#define V5255 (V + 18985)
+ 0x1105, 0x1168, 0x11a8, 0,
+#undef V5256
+#define V5256 (V + 18989)
+ 0x1105, 0x1168, 0x11a9, 0,
+#undef V5257
+#define V5257 (V + 18993)
+ 0x1105, 0x1168, 0x11aa, 0,
+#undef V5258
+#define V5258 (V + 18997)
+ 0x1105, 0x1168, 0x11ab, 0,
+#undef V5259
+#define V5259 (V + 19001)
+ 0x1105, 0x1168, 0x11ac, 0,
+#undef V5260
+#define V5260 (V + 19005)
+ 0x1105, 0x1168, 0x11ad, 0,
+#undef V5261
+#define V5261 (V + 19009)
+ 0x1105, 0x1168, 0x11ae, 0,
+#undef V5262
+#define V5262 (V + 19013)
+ 0x1105, 0x1168, 0x11af, 0,
+#undef V5263
+#define V5263 (V + 19017)
+ 0x1105, 0x1168, 0x11b0, 0,
+#undef V5264
+#define V5264 (V + 19021)
+ 0x1105, 0x1168, 0x11b1, 0,
+#undef V5265
+#define V5265 (V + 19025)
+ 0x1105, 0x1168, 0x11b2, 0,
+#undef V5266
+#define V5266 (V + 19029)
+ 0x1105, 0x1168, 0x11b3, 0,
+#undef V5267
+#define V5267 (V + 19033)
+ 0x1105, 0x1168, 0x11b4, 0,
+#undef V5268
+#define V5268 (V + 19037)
+ 0x1105, 0x1168, 0x11b5, 0,
+#undef V5269
+#define V5269 (V + 19041)
+ 0x1105, 0x1168, 0x11b6, 0,
+#undef V5270
+#define V5270 (V + 19045)
+ 0x1105, 0x1168, 0x11b7, 0,
+#undef V5271
+#define V5271 (V + 19049)
+ 0x1105, 0x1168, 0x11b8, 0,
+#undef V5272
+#define V5272 (V + 19053)
+ 0x1105, 0x1168, 0x11b9, 0,
+#undef V5273
+#define V5273 (V + 19057)
+ 0x1105, 0x1168, 0x11ba, 0,
+#undef V5274
+#define V5274 (V + 19061)
+ 0x1105, 0x1168, 0x11bb, 0,
+#undef V5275
+#define V5275 (V + 19065)
+ 0x1105, 0x1168, 0x11bc, 0,
+#undef V5276
+#define V5276 (V + 19069)
+ 0x1105, 0x1168, 0x11bd, 0,
+#undef V5277
+#define V5277 (V + 19073)
+ 0x1105, 0x1168, 0x11be, 0,
+#undef V5278
+#define V5278 (V + 19077)
+ 0x1105, 0x1168, 0x11bf, 0,
+#undef V5279
+#define V5279 (V + 19081)
+ 0x1105, 0x1168, 0x11c0, 0,
+#undef V5280
+#define V5280 (V + 19085)
+ 0x1105, 0x1168, 0x11c1, 0,
+#undef V5281
+#define V5281 (V + 19089)
+ 0x1105, 0x1168, 0x11c2, 0,
+#undef V5282
+#define V5282 (V + 19093)
+ 0x1105, 0x1169, 0,
+#undef V5283
+#define V5283 (V + 19096)
+ 0x1105, 0x1169, 0x11a8, 0,
+#undef V5284
+#define V5284 (V + 19100)
+ 0x1105, 0x1169, 0x11a9, 0,
+#undef V5285
+#define V5285 (V + 19104)
+ 0x1105, 0x1169, 0x11aa, 0,
+#undef V5286
+#define V5286 (V + 19108)
+ 0x1105, 0x1169, 0x11ab, 0,
+#undef V5287
+#define V5287 (V + 19112)
+ 0x1105, 0x1169, 0x11ac, 0,
+#undef V5288
+#define V5288 (V + 19116)
+ 0x1105, 0x1169, 0x11ad, 0,
+#undef V5289
+#define V5289 (V + 19120)
+ 0x1105, 0x1169, 0x11ae, 0,
+#undef V5290
+#define V5290 (V + 19124)
+ 0x1105, 0x1169, 0x11af, 0,
+#undef V5291
+#define V5291 (V + 19128)
+ 0x1105, 0x1169, 0x11b0, 0,
+#undef V5292
+#define V5292 (V + 19132)
+ 0x1105, 0x1169, 0x11b1, 0,
+#undef V5293
+#define V5293 (V + 19136)
+ 0x1105, 0x1169, 0x11b2, 0,
+#undef V5294
+#define V5294 (V + 19140)
+ 0x1105, 0x1169, 0x11b3, 0,
+#undef V5295
+#define V5295 (V + 19144)
+ 0x1105, 0x1169, 0x11b4, 0,
+#undef V5296
+#define V5296 (V + 19148)
+ 0x1105, 0x1169, 0x11b5, 0,
+#undef V5297
+#define V5297 (V + 19152)
+ 0x1105, 0x1169, 0x11b6, 0,
+#undef V5298
+#define V5298 (V + 19156)
+ 0x1105, 0x1169, 0x11b7, 0,
+#undef V5299
+#define V5299 (V + 19160)
+ 0x1105, 0x1169, 0x11b8, 0,
+#undef V5300
+#define V5300 (V + 19164)
+ 0x1105, 0x1169, 0x11b9, 0,
+#undef V5301
+#define V5301 (V + 19168)
+ 0x1105, 0x1169, 0x11ba, 0,
+#undef V5302
+#define V5302 (V + 19172)
+ 0x1105, 0x1169, 0x11bb, 0,
+#undef V5303
+#define V5303 (V + 19176)
+ 0x1105, 0x1169, 0x11bc, 0,
+#undef V5304
+#define V5304 (V + 19180)
+ 0x1105, 0x1169, 0x11bd, 0,
+#undef V5305
+#define V5305 (V + 19184)
+ 0x1105, 0x1169, 0x11be, 0,
+#undef V5306
+#define V5306 (V + 19188)
+ 0x1105, 0x1169, 0x11bf, 0,
+#undef V5307
+#define V5307 (V + 19192)
+ 0x1105, 0x1169, 0x11c0, 0,
+#undef V5308
+#define V5308 (V + 19196)
+ 0x1105, 0x1169, 0x11c1, 0,
+#undef V5309
+#define V5309 (V + 19200)
+ 0x1105, 0x1169, 0x11c2, 0,
+#undef V5310
+#define V5310 (V + 19204)
+ 0x1105, 0x116a, 0,
+#undef V5311
+#define V5311 (V + 19207)
+ 0x1105, 0x116a, 0x11a8, 0,
+#undef V5312
+#define V5312 (V + 19211)
+ 0x1105, 0x116a, 0x11a9, 0,
+#undef V5313
+#define V5313 (V + 19215)
+ 0x1105, 0x116a, 0x11aa, 0,
+#undef V5314
+#define V5314 (V + 19219)
+ 0x1105, 0x116a, 0x11ab, 0,
+#undef V5315
+#define V5315 (V + 19223)
+ 0x1105, 0x116a, 0x11ac, 0,
+#undef V5316
+#define V5316 (V + 19227)
+ 0x1105, 0x116a, 0x11ad, 0,
+#undef V5317
+#define V5317 (V + 19231)
+ 0x1105, 0x116a, 0x11ae, 0,
+#undef V5318
+#define V5318 (V + 19235)
+ 0x1105, 0x116a, 0x11af, 0,
+#undef V5319
+#define V5319 (V + 19239)
+ 0x1105, 0x116a, 0x11b0, 0,
+#undef V5320
+#define V5320 (V + 19243)
+ 0x1105, 0x116a, 0x11b1, 0,
+#undef V5321
+#define V5321 (V + 19247)
+ 0x1105, 0x116a, 0x11b2, 0,
+#undef V5322
+#define V5322 (V + 19251)
+ 0x1105, 0x116a, 0x11b3, 0,
+#undef V5323
+#define V5323 (V + 19255)
+ 0x1105, 0x116a, 0x11b4, 0,
+#undef V5324
+#define V5324 (V + 19259)
+ 0x1105, 0x116a, 0x11b5, 0,
+#undef V5325
+#define V5325 (V + 19263)
+ 0x1105, 0x116a, 0x11b6, 0,
+#undef V5326
+#define V5326 (V + 19267)
+ 0x1105, 0x116a, 0x11b7, 0,
+#undef V5327
+#define V5327 (V + 19271)
+ 0x1105, 0x116a, 0x11b8, 0,
+#undef V5328
+#define V5328 (V + 19275)
+ 0x1105, 0x116a, 0x11b9, 0,
+#undef V5329
+#define V5329 (V + 19279)
+ 0x1105, 0x116a, 0x11ba, 0,
+#undef V5330
+#define V5330 (V + 19283)
+ 0x1105, 0x116a, 0x11bb, 0,
+#undef V5331
+#define V5331 (V + 19287)
+ 0x1105, 0x116a, 0x11bc, 0,
+#undef V5332
+#define V5332 (V + 19291)
+ 0x1105, 0x116a, 0x11bd, 0,
+#undef V5333
+#define V5333 (V + 19295)
+ 0x1105, 0x116a, 0x11be, 0,
+#undef V5334
+#define V5334 (V + 19299)
+ 0x1105, 0x116a, 0x11bf, 0,
+#undef V5335
+#define V5335 (V + 19303)
+ 0x1105, 0x116a, 0x11c0, 0,
+#undef V5336
+#define V5336 (V + 19307)
+ 0x1105, 0x116a, 0x11c1, 0,
+#undef V5337
+#define V5337 (V + 19311)
+ 0x1105, 0x116a, 0x11c2, 0,
+#undef V5338
+#define V5338 (V + 19315)
+ 0x1105, 0x116b, 0,
+#undef V5339
+#define V5339 (V + 19318)
+ 0x1105, 0x116b, 0x11a8, 0,
+#undef V5340
+#define V5340 (V + 19322)
+ 0x1105, 0x116b, 0x11a9, 0,
+#undef V5341
+#define V5341 (V + 19326)
+ 0x1105, 0x116b, 0x11aa, 0,
+#undef V5342
+#define V5342 (V + 19330)
+ 0x1105, 0x116b, 0x11ab, 0,
+#undef V5343
+#define V5343 (V + 19334)
+ 0x1105, 0x116b, 0x11ac, 0,
+#undef V5344
+#define V5344 (V + 19338)
+ 0x1105, 0x116b, 0x11ad, 0,
+#undef V5345
+#define V5345 (V + 19342)
+ 0x1105, 0x116b, 0x11ae, 0,
+#undef V5346
+#define V5346 (V + 19346)
+ 0x1105, 0x116b, 0x11af, 0,
+#undef V5347
+#define V5347 (V + 19350)
+ 0x1105, 0x116b, 0x11b0, 0,
+#undef V5348
+#define V5348 (V + 19354)
+ 0x1105, 0x116b, 0x11b1, 0,
+#undef V5349
+#define V5349 (V + 19358)
+ 0x1105, 0x116b, 0x11b2, 0,
+#undef V5350
+#define V5350 (V + 19362)
+ 0x1105, 0x116b, 0x11b3, 0,
+#undef V5351
+#define V5351 (V + 19366)
+ 0x1105, 0x116b, 0x11b4, 0,
+#undef V5352
+#define V5352 (V + 19370)
+ 0x1105, 0x116b, 0x11b5, 0,
+#undef V5353
+#define V5353 (V + 19374)
+ 0x1105, 0x116b, 0x11b6, 0,
+#undef V5354
+#define V5354 (V + 19378)
+ 0x1105, 0x116b, 0x11b7, 0,
+#undef V5355
+#define V5355 (V + 19382)
+ 0x1105, 0x116b, 0x11b8, 0,
+#undef V5356
+#define V5356 (V + 19386)
+ 0x1105, 0x116b, 0x11b9, 0,
+#undef V5357
+#define V5357 (V + 19390)
+ 0x1105, 0x116b, 0x11ba, 0,
+#undef V5358
+#define V5358 (V + 19394)
+ 0x1105, 0x116b, 0x11bb, 0,
+#undef V5359
+#define V5359 (V + 19398)
+ 0x1105, 0x116b, 0x11bc, 0,
+#undef V5360
+#define V5360 (V + 19402)
+ 0x1105, 0x116b, 0x11bd, 0,
+#undef V5361
+#define V5361 (V + 19406)
+ 0x1105, 0x116b, 0x11be, 0,
+#undef V5362
+#define V5362 (V + 19410)
+ 0x1105, 0x116b, 0x11bf, 0,
+#undef V5363
+#define V5363 (V + 19414)
+ 0x1105, 0x116b, 0x11c0, 0,
+#undef V5364
+#define V5364 (V + 19418)
+ 0x1105, 0x116b, 0x11c1, 0,
+#undef V5365
+#define V5365 (V + 19422)
+ 0x1105, 0x116b, 0x11c2, 0,
+#undef V5366
+#define V5366 (V + 19426)
+ 0x1105, 0x116c, 0,
+#undef V5367
+#define V5367 (V + 19429)
+ 0x1105, 0x116c, 0x11a8, 0,
+#undef V5368
+#define V5368 (V + 19433)
+ 0x1105, 0x116c, 0x11a9, 0,
+#undef V5369
+#define V5369 (V + 19437)
+ 0x1105, 0x116c, 0x11aa, 0,
+#undef V5370
+#define V5370 (V + 19441)
+ 0x1105, 0x116c, 0x11ab, 0,
+#undef V5371
+#define V5371 (V + 19445)
+ 0x1105, 0x116c, 0x11ac, 0,
+#undef V5372
+#define V5372 (V + 19449)
+ 0x1105, 0x116c, 0x11ad, 0,
+#undef V5373
+#define V5373 (V + 19453)
+ 0x1105, 0x116c, 0x11ae, 0,
+#undef V5374
+#define V5374 (V + 19457)
+ 0x1105, 0x116c, 0x11af, 0,
+#undef V5375
+#define V5375 (V + 19461)
+ 0x1105, 0x116c, 0x11b0, 0,
+#undef V5376
+#define V5376 (V + 19465)
+ 0x1105, 0x116c, 0x11b1, 0,
+#undef V5377
+#define V5377 (V + 19469)
+ 0x1105, 0x116c, 0x11b2, 0,
+#undef V5378
+#define V5378 (V + 19473)
+ 0x1105, 0x116c, 0x11b3, 0,
+#undef V5379
+#define V5379 (V + 19477)
+ 0x1105, 0x116c, 0x11b4, 0,
+#undef V5380
+#define V5380 (V + 19481)
+ 0x1105, 0x116c, 0x11b5, 0,
+#undef V5381
+#define V5381 (V + 19485)
+ 0x1105, 0x116c, 0x11b6, 0,
+#undef V5382
+#define V5382 (V + 19489)
+ 0x1105, 0x116c, 0x11b7, 0,
+#undef V5383
+#define V5383 (V + 19493)
+ 0x1105, 0x116c, 0x11b8, 0,
+#undef V5384
+#define V5384 (V + 19497)
+ 0x1105, 0x116c, 0x11b9, 0,
+#undef V5385
+#define V5385 (V + 19501)
+ 0x1105, 0x116c, 0x11ba, 0,
+#undef V5386
+#define V5386 (V + 19505)
+ 0x1105, 0x116c, 0x11bb, 0,
+#undef V5387
+#define V5387 (V + 19509)
+ 0x1105, 0x116c, 0x11bc, 0,
+#undef V5388
+#define V5388 (V + 19513)
+ 0x1105, 0x116c, 0x11bd, 0,
+#undef V5389
+#define V5389 (V + 19517)
+ 0x1105, 0x116c, 0x11be, 0,
+#undef V5390
+#define V5390 (V + 19521)
+ 0x1105, 0x116c, 0x11bf, 0,
+#undef V5391
+#define V5391 (V + 19525)
+ 0x1105, 0x116c, 0x11c0, 0,
+#undef V5392
+#define V5392 (V + 19529)
+ 0x1105, 0x116c, 0x11c1, 0,
+#undef V5393
+#define V5393 (V + 19533)
+ 0x1105, 0x116c, 0x11c2, 0,
+#undef V5394
+#define V5394 (V + 19537)
+ 0x1105, 0x116d, 0,
+#undef V5395
+#define V5395 (V + 19540)
+ 0x1105, 0x116d, 0x11a8, 0,
+#undef V5396
+#define V5396 (V + 19544)
+ 0x1105, 0x116d, 0x11a9, 0,
+#undef V5397
+#define V5397 (V + 19548)
+ 0x1105, 0x116d, 0x11aa, 0,
+#undef V5398
+#define V5398 (V + 19552)
+ 0x1105, 0x116d, 0x11ab, 0,
+#undef V5399
+#define V5399 (V + 19556)
+ 0x1105, 0x116d, 0x11ac, 0,
+#undef V5400
+#define V5400 (V + 19560)
+ 0x1105, 0x116d, 0x11ad, 0,
+#undef V5401
+#define V5401 (V + 19564)
+ 0x1105, 0x116d, 0x11ae, 0,
+#undef V5402
+#define V5402 (V + 19568)
+ 0x1105, 0x116d, 0x11af, 0,
+#undef V5403
+#define V5403 (V + 19572)
+ 0x1105, 0x116d, 0x11b0, 0,
+#undef V5404
+#define V5404 (V + 19576)
+ 0x1105, 0x116d, 0x11b1, 0,
+#undef V5405
+#define V5405 (V + 19580)
+ 0x1105, 0x116d, 0x11b2, 0,
+#undef V5406
+#define V5406 (V + 19584)
+ 0x1105, 0x116d, 0x11b3, 0,
+#undef V5407
+#define V5407 (V + 19588)
+ 0x1105, 0x116d, 0x11b4, 0,
+#undef V5408
+#define V5408 (V + 19592)
+ 0x1105, 0x116d, 0x11b5, 0,
+#undef V5409
+#define V5409 (V + 19596)
+ 0x1105, 0x116d, 0x11b6, 0,
+#undef V5410
+#define V5410 (V + 19600)
+ 0x1105, 0x116d, 0x11b7, 0,
+#undef V5411
+#define V5411 (V + 19604)
+ 0x1105, 0x116d, 0x11b8, 0,
+#undef V5412
+#define V5412 (V + 19608)
+ 0x1105, 0x116d, 0x11b9, 0,
+#undef V5413
+#define V5413 (V + 19612)
+ 0x1105, 0x116d, 0x11ba, 0,
+#undef V5414
+#define V5414 (V + 19616)
+ 0x1105, 0x116d, 0x11bb, 0,
+#undef V5415
+#define V5415 (V + 19620)
+ 0x1105, 0x116d, 0x11bc, 0,
+#undef V5416
+#define V5416 (V + 19624)
+ 0x1105, 0x116d, 0x11bd, 0,
+#undef V5417
+#define V5417 (V + 19628)
+ 0x1105, 0x116d, 0x11be, 0,
+#undef V5418
+#define V5418 (V + 19632)
+ 0x1105, 0x116d, 0x11bf, 0,
+#undef V5419
+#define V5419 (V + 19636)
+ 0x1105, 0x116d, 0x11c0, 0,
+#undef V5420
+#define V5420 (V + 19640)
+ 0x1105, 0x116d, 0x11c1, 0,
+#undef V5421
+#define V5421 (V + 19644)
+ 0x1105, 0x116d, 0x11c2, 0,
+#undef V5422
+#define V5422 (V + 19648)
+ 0x1105, 0x116e, 0,
+#undef V5423
+#define V5423 (V + 19651)
+ 0x1105, 0x116e, 0x11a8, 0,
+#undef V5424
+#define V5424 (V + 19655)
+ 0x1105, 0x116e, 0x11a9, 0,
+#undef V5425
+#define V5425 (V + 19659)
+ 0x1105, 0x116e, 0x11aa, 0,
+#undef V5426
+#define V5426 (V + 19663)
+ 0x1105, 0x116e, 0x11ab, 0,
+#undef V5427
+#define V5427 (V + 19667)
+ 0x1105, 0x116e, 0x11ac, 0,
+#undef V5428
+#define V5428 (V + 19671)
+ 0x1105, 0x116e, 0x11ad, 0,
+#undef V5429
+#define V5429 (V + 19675)
+ 0x1105, 0x116e, 0x11ae, 0,
+#undef V5430
+#define V5430 (V + 19679)
+ 0x1105, 0x116e, 0x11af, 0,
+#undef V5431
+#define V5431 (V + 19683)
+ 0x1105, 0x116e, 0x11b0, 0,
+#undef V5432
+#define V5432 (V + 19687)
+ 0x1105, 0x116e, 0x11b1, 0,
+#undef V5433
+#define V5433 (V + 19691)
+ 0x1105, 0x116e, 0x11b2, 0,
+#undef V5434
+#define V5434 (V + 19695)
+ 0x1105, 0x116e, 0x11b3, 0,
+#undef V5435
+#define V5435 (V + 19699)
+ 0x1105, 0x116e, 0x11b4, 0,
+#undef V5436
+#define V5436 (V + 19703)
+ 0x1105, 0x116e, 0x11b5, 0,
+#undef V5437
+#define V5437 (V + 19707)
+ 0x1105, 0x116e, 0x11b6, 0,
+#undef V5438
+#define V5438 (V + 19711)
+ 0x1105, 0x116e, 0x11b7, 0,
+#undef V5439
+#define V5439 (V + 19715)
+ 0x1105, 0x116e, 0x11b8, 0,
+#undef V5440
+#define V5440 (V + 19719)
+ 0x1105, 0x116e, 0x11b9, 0,
+#undef V5441
+#define V5441 (V + 19723)
+ 0x1105, 0x116e, 0x11ba, 0,
+#undef V5442
+#define V5442 (V + 19727)
+ 0x1105, 0x116e, 0x11bb, 0,
+#undef V5443
+#define V5443 (V + 19731)
+ 0x1105, 0x116e, 0x11bc, 0,
+#undef V5444
+#define V5444 (V + 19735)
+ 0x1105, 0x116e, 0x11bd, 0,
+#undef V5445
+#define V5445 (V + 19739)
+ 0x1105, 0x116e, 0x11be, 0,
+#undef V5446
+#define V5446 (V + 19743)
+ 0x1105, 0x116e, 0x11bf, 0,
+#undef V5447
+#define V5447 (V + 19747)
+ 0x1105, 0x116e, 0x11c0, 0,
+#undef V5448
+#define V5448 (V + 19751)
+ 0x1105, 0x116e, 0x11c1, 0,
+#undef V5449
+#define V5449 (V + 19755)
+ 0x1105, 0x116e, 0x11c2, 0,
+#undef V5450
+#define V5450 (V + 19759)
+ 0x1105, 0x116f, 0,
+#undef V5451
+#define V5451 (V + 19762)
+ 0x1105, 0x116f, 0x11a8, 0,
+#undef V5452
+#define V5452 (V + 19766)
+ 0x1105, 0x116f, 0x11a9, 0,
+#undef V5453
+#define V5453 (V + 19770)
+ 0x1105, 0x116f, 0x11aa, 0,
+#undef V5454
+#define V5454 (V + 19774)
+ 0x1105, 0x116f, 0x11ab, 0,
+#undef V5455
+#define V5455 (V + 19778)
+ 0x1105, 0x116f, 0x11ac, 0,
+#undef V5456
+#define V5456 (V + 19782)
+ 0x1105, 0x116f, 0x11ad, 0,
+#undef V5457
+#define V5457 (V + 19786)
+ 0x1105, 0x116f, 0x11ae, 0,
+#undef V5458
+#define V5458 (V + 19790)
+ 0x1105, 0x116f, 0x11af, 0,
+#undef V5459
+#define V5459 (V + 19794)
+ 0x1105, 0x116f, 0x11b0, 0,
+#undef V5460
+#define V5460 (V + 19798)
+ 0x1105, 0x116f, 0x11b1, 0,
+#undef V5461
+#define V5461 (V + 19802)
+ 0x1105, 0x116f, 0x11b2, 0,
+#undef V5462
+#define V5462 (V + 19806)
+ 0x1105, 0x116f, 0x11b3, 0,
+#undef V5463
+#define V5463 (V + 19810)
+ 0x1105, 0x116f, 0x11b4, 0,
+#undef V5464
+#define V5464 (V + 19814)
+ 0x1105, 0x116f, 0x11b5, 0,
+#undef V5465
+#define V5465 (V + 19818)
+ 0x1105, 0x116f, 0x11b6, 0,
+#undef V5466
+#define V5466 (V + 19822)
+ 0x1105, 0x116f, 0x11b7, 0,
+#undef V5467
+#define V5467 (V + 19826)
+ 0x1105, 0x116f, 0x11b8, 0,
+#undef V5468
+#define V5468 (V + 19830)
+ 0x1105, 0x116f, 0x11b9, 0,
+#undef V5469
+#define V5469 (V + 19834)
+ 0x1105, 0x116f, 0x11ba, 0,
+#undef V5470
+#define V5470 (V + 19838)
+ 0x1105, 0x116f, 0x11bb, 0,
+#undef V5471
+#define V5471 (V + 19842)
+ 0x1105, 0x116f, 0x11bc, 0,
+#undef V5472
+#define V5472 (V + 19846)
+ 0x1105, 0x116f, 0x11bd, 0,
+#undef V5473
+#define V5473 (V + 19850)
+ 0x1105, 0x116f, 0x11be, 0,
+#undef V5474
+#define V5474 (V + 19854)
+ 0x1105, 0x116f, 0x11bf, 0,
+#undef V5475
+#define V5475 (V + 19858)
+ 0x1105, 0x116f, 0x11c0, 0,
+#undef V5476
+#define V5476 (V + 19862)
+ 0x1105, 0x116f, 0x11c1, 0,
+#undef V5477
+#define V5477 (V + 19866)
+ 0x1105, 0x116f, 0x11c2, 0,
+#undef V5478
+#define V5478 (V + 19870)
+ 0x1105, 0x1170, 0,
+#undef V5479
+#define V5479 (V + 19873)
+ 0x1105, 0x1170, 0x11a8, 0,
+#undef V5480
+#define V5480 (V + 19877)
+ 0x1105, 0x1170, 0x11a9, 0,
+#undef V5481
+#define V5481 (V + 19881)
+ 0x1105, 0x1170, 0x11aa, 0,
+#undef V5482
+#define V5482 (V + 19885)
+ 0x1105, 0x1170, 0x11ab, 0,
+#undef V5483
+#define V5483 (V + 19889)
+ 0x1105, 0x1170, 0x11ac, 0,
+#undef V5484
+#define V5484 (V + 19893)
+ 0x1105, 0x1170, 0x11ad, 0,
+#undef V5485
+#define V5485 (V + 19897)
+ 0x1105, 0x1170, 0x11ae, 0,
+#undef V5486
+#define V5486 (V + 19901)
+ 0x1105, 0x1170, 0x11af, 0,
+#undef V5487
+#define V5487 (V + 19905)
+ 0x1105, 0x1170, 0x11b0, 0,
+#undef V5488
+#define V5488 (V + 19909)
+ 0x1105, 0x1170, 0x11b1, 0,
+#undef V5489
+#define V5489 (V + 19913)
+ 0x1105, 0x1170, 0x11b2, 0,
+#undef V5490
+#define V5490 (V + 19917)
+ 0x1105, 0x1170, 0x11b3, 0,
+#undef V5491
+#define V5491 (V + 19921)
+ 0x1105, 0x1170, 0x11b4, 0,
+#undef V5492
+#define V5492 (V + 19925)
+ 0x1105, 0x1170, 0x11b5, 0,
+#undef V5493
+#define V5493 (V + 19929)
+ 0x1105, 0x1170, 0x11b6, 0,
+#undef V5494
+#define V5494 (V + 19933)
+ 0x1105, 0x1170, 0x11b7, 0,
+#undef V5495
+#define V5495 (V + 19937)
+ 0x1105, 0x1170, 0x11b8, 0,
+#undef V5496
+#define V5496 (V + 19941)
+ 0x1105, 0x1170, 0x11b9, 0,
+#undef V5497
+#define V5497 (V + 19945)
+ 0x1105, 0x1170, 0x11ba, 0,
+#undef V5498
+#define V5498 (V + 19949)
+ 0x1105, 0x1170, 0x11bb, 0,
+#undef V5499
+#define V5499 (V + 19953)
+ 0x1105, 0x1170, 0x11bc, 0,
+#undef V5500
+#define V5500 (V + 19957)
+ 0x1105, 0x1170, 0x11bd, 0,
+#undef V5501
+#define V5501 (V + 19961)
+ 0x1105, 0x1170, 0x11be, 0,
+#undef V5502
+#define V5502 (V + 19965)
+ 0x1105, 0x1170, 0x11bf, 0,
+#undef V5503
+#define V5503 (V + 19969)
+ 0x1105, 0x1170, 0x11c0, 0,
+#undef V5504
+#define V5504 (V + 19973)
+ 0x1105, 0x1170, 0x11c1, 0,
+#undef V5505
+#define V5505 (V + 19977)
+ 0x1105, 0x1170, 0x11c2, 0,
+#undef V5506
+#define V5506 (V + 19981)
+ 0x1105, 0x1171, 0,
+#undef V5507
+#define V5507 (V + 19984)
+ 0x1105, 0x1171, 0x11a8, 0,
+#undef V5508
+#define V5508 (V + 19988)
+ 0x1105, 0x1171, 0x11a9, 0,
+#undef V5509
+#define V5509 (V + 19992)
+ 0x1105, 0x1171, 0x11aa, 0,
+#undef V5510
+#define V5510 (V + 19996)
+ 0x1105, 0x1171, 0x11ab, 0,
+#undef V5511
+#define V5511 (V + 20000)
+ 0x1105, 0x1171, 0x11ac, 0,
+#undef V5512
+#define V5512 (V + 20004)
+ 0x1105, 0x1171, 0x11ad, 0,
+#undef V5513
+#define V5513 (V + 20008)
+ 0x1105, 0x1171, 0x11ae, 0,
+#undef V5514
+#define V5514 (V + 20012)
+ 0x1105, 0x1171, 0x11af, 0,
+#undef V5515
+#define V5515 (V + 20016)
+ 0x1105, 0x1171, 0x11b0, 0,
+#undef V5516
+#define V5516 (V + 20020)
+ 0x1105, 0x1171, 0x11b1, 0,
+#undef V5517
+#define V5517 (V + 20024)
+ 0x1105, 0x1171, 0x11b2, 0,
+#undef V5518
+#define V5518 (V + 20028)
+ 0x1105, 0x1171, 0x11b3, 0,
+#undef V5519
+#define V5519 (V + 20032)
+ 0x1105, 0x1171, 0x11b4, 0,
+#undef V5520
+#define V5520 (V + 20036)
+ 0x1105, 0x1171, 0x11b5, 0,
+#undef V5521
+#define V5521 (V + 20040)
+ 0x1105, 0x1171, 0x11b6, 0,
+#undef V5522
+#define V5522 (V + 20044)
+ 0x1105, 0x1171, 0x11b7, 0,
+#undef V5523
+#define V5523 (V + 20048)
+ 0x1105, 0x1171, 0x11b8, 0,
+#undef V5524
+#define V5524 (V + 20052)
+ 0x1105, 0x1171, 0x11b9, 0,
+#undef V5525
+#define V5525 (V + 20056)
+ 0x1105, 0x1171, 0x11ba, 0,
+#undef V5526
+#define V5526 (V + 20060)
+ 0x1105, 0x1171, 0x11bb, 0,
+#undef V5527
+#define V5527 (V + 20064)
+ 0x1105, 0x1171, 0x11bc, 0,
+#undef V5528
+#define V5528 (V + 20068)
+ 0x1105, 0x1171, 0x11bd, 0,
+#undef V5529
+#define V5529 (V + 20072)
+ 0x1105, 0x1171, 0x11be, 0,
+#undef V5530
+#define V5530 (V + 20076)
+ 0x1105, 0x1171, 0x11bf, 0,
+#undef V5531
+#define V5531 (V + 20080)
+ 0x1105, 0x1171, 0x11c0, 0,
+#undef V5532
+#define V5532 (V + 20084)
+ 0x1105, 0x1171, 0x11c1, 0,
+#undef V5533
+#define V5533 (V + 20088)
+ 0x1105, 0x1171, 0x11c2, 0,
+#undef V5534
+#define V5534 (V + 20092)
+ 0x1105, 0x1172, 0,
+#undef V5535
+#define V5535 (V + 20095)
+ 0x1105, 0x1172, 0x11a8, 0,
+#undef V5536
+#define V5536 (V + 20099)
+ 0x1105, 0x1172, 0x11a9, 0,
+#undef V5537
+#define V5537 (V + 20103)
+ 0x1105, 0x1172, 0x11aa, 0,
+#undef V5538
+#define V5538 (V + 20107)
+ 0x1105, 0x1172, 0x11ab, 0,
+#undef V5539
+#define V5539 (V + 20111)
+ 0x1105, 0x1172, 0x11ac, 0,
+#undef V5540
+#define V5540 (V + 20115)
+ 0x1105, 0x1172, 0x11ad, 0,
+#undef V5541
+#define V5541 (V + 20119)
+ 0x1105, 0x1172, 0x11ae, 0,
+#undef V5542
+#define V5542 (V + 20123)
+ 0x1105, 0x1172, 0x11af, 0,
+#undef V5543
+#define V5543 (V + 20127)
+ 0x1105, 0x1172, 0x11b0, 0,
+#undef V5544
+#define V5544 (V + 20131)
+ 0x1105, 0x1172, 0x11b1, 0,
+#undef V5545
+#define V5545 (V + 20135)
+ 0x1105, 0x1172, 0x11b2, 0,
+#undef V5546
+#define V5546 (V + 20139)
+ 0x1105, 0x1172, 0x11b3, 0,
+#undef V5547
+#define V5547 (V + 20143)
+ 0x1105, 0x1172, 0x11b4, 0,
+#undef V5548
+#define V5548 (V + 20147)
+ 0x1105, 0x1172, 0x11b5, 0,
+#undef V5549
+#define V5549 (V + 20151)
+ 0x1105, 0x1172, 0x11b6, 0,
+#undef V5550
+#define V5550 (V + 20155)
+ 0x1105, 0x1172, 0x11b7, 0,
+#undef V5551
+#define V5551 (V + 20159)
+ 0x1105, 0x1172, 0x11b8, 0,
+#undef V5552
+#define V5552 (V + 20163)
+ 0x1105, 0x1172, 0x11b9, 0,
+#undef V5553
+#define V5553 (V + 20167)
+ 0x1105, 0x1172, 0x11ba, 0,
+#undef V5554
+#define V5554 (V + 20171)
+ 0x1105, 0x1172, 0x11bb, 0,
+#undef V5555
+#define V5555 (V + 20175)
+ 0x1105, 0x1172, 0x11bc, 0,
+#undef V5556
+#define V5556 (V + 20179)
+ 0x1105, 0x1172, 0x11bd, 0,
+#undef V5557
+#define V5557 (V + 20183)
+ 0x1105, 0x1172, 0x11be, 0,
+#undef V5558
+#define V5558 (V + 20187)
+ 0x1105, 0x1172, 0x11bf, 0,
+#undef V5559
+#define V5559 (V + 20191)
+ 0x1105, 0x1172, 0x11c0, 0,
+#undef V5560
+#define V5560 (V + 20195)
+ 0x1105, 0x1172, 0x11c1, 0,
+#undef V5561
+#define V5561 (V + 20199)
+ 0x1105, 0x1172, 0x11c2, 0,
+#undef V5562
+#define V5562 (V + 20203)
+ 0x1105, 0x1173, 0,
+#undef V5563
+#define V5563 (V + 20206)
+ 0x1105, 0x1173, 0x11a8, 0,
+#undef V5564
+#define V5564 (V + 20210)
+ 0x1105, 0x1173, 0x11a9, 0,
+#undef V5565
+#define V5565 (V + 20214)
+ 0x1105, 0x1173, 0x11aa, 0,
+#undef V5566
+#define V5566 (V + 20218)
+ 0x1105, 0x1173, 0x11ab, 0,
+#undef V5567
+#define V5567 (V + 20222)
+ 0x1105, 0x1173, 0x11ac, 0,
+#undef V5568
+#define V5568 (V + 20226)
+ 0x1105, 0x1173, 0x11ad, 0,
+#undef V5569
+#define V5569 (V + 20230)
+ 0x1105, 0x1173, 0x11ae, 0,
+#undef V5570
+#define V5570 (V + 20234)
+ 0x1105, 0x1173, 0x11af, 0,
+#undef V5571
+#define V5571 (V + 20238)
+ 0x1105, 0x1173, 0x11b0, 0,
+#undef V5572
+#define V5572 (V + 20242)
+ 0x1105, 0x1173, 0x11b1, 0,
+#undef V5573
+#define V5573 (V + 20246)
+ 0x1105, 0x1173, 0x11b2, 0,
+#undef V5574
+#define V5574 (V + 20250)
+ 0x1105, 0x1173, 0x11b3, 0,
+#undef V5575
+#define V5575 (V + 20254)
+ 0x1105, 0x1173, 0x11b4, 0,
+#undef V5576
+#define V5576 (V + 20258)
+ 0x1105, 0x1173, 0x11b5, 0,
+#undef V5577
+#define V5577 (V + 20262)
+ 0x1105, 0x1173, 0x11b6, 0,
+#undef V5578
+#define V5578 (V + 20266)
+ 0x1105, 0x1173, 0x11b7, 0,
+#undef V5579
+#define V5579 (V + 20270)
+ 0x1105, 0x1173, 0x11b8, 0,
+#undef V5580
+#define V5580 (V + 20274)
+ 0x1105, 0x1173, 0x11b9, 0,
+#undef V5581
+#define V5581 (V + 20278)
+ 0x1105, 0x1173, 0x11ba, 0,
+#undef V5582
+#define V5582 (V + 20282)
+ 0x1105, 0x1173, 0x11bb, 0,
+#undef V5583
+#define V5583 (V + 20286)
+ 0x1105, 0x1173, 0x11bc, 0,
+#undef V5584
+#define V5584 (V + 20290)
+ 0x1105, 0x1173, 0x11bd, 0,
+#undef V5585
+#define V5585 (V + 20294)
+ 0x1105, 0x1173, 0x11be, 0,
+#undef V5586
+#define V5586 (V + 20298)
+ 0x1105, 0x1173, 0x11bf, 0,
+#undef V5587
+#define V5587 (V + 20302)
+ 0x1105, 0x1173, 0x11c0, 0,
+#undef V5588
+#define V5588 (V + 20306)
+ 0x1105, 0x1173, 0x11c1, 0,
+#undef V5589
+#define V5589 (V + 20310)
+ 0x1105, 0x1173, 0x11c2, 0,
+#undef V5590
+#define V5590 (V + 20314)
+ 0x1105, 0x1174, 0,
+#undef V5591
+#define V5591 (V + 20317)
+ 0x1105, 0x1174, 0x11a8, 0,
+#undef V5592
+#define V5592 (V + 20321)
+ 0x1105, 0x1174, 0x11a9, 0,
+#undef V5593
+#define V5593 (V + 20325)
+ 0x1105, 0x1174, 0x11aa, 0,
+#undef V5594
+#define V5594 (V + 20329)
+ 0x1105, 0x1174, 0x11ab, 0,
+#undef V5595
+#define V5595 (V + 20333)
+ 0x1105, 0x1174, 0x11ac, 0,
+#undef V5596
+#define V5596 (V + 20337)
+ 0x1105, 0x1174, 0x11ad, 0,
+#undef V5597
+#define V5597 (V + 20341)
+ 0x1105, 0x1174, 0x11ae, 0,
+#undef V5598
+#define V5598 (V + 20345)
+ 0x1105, 0x1174, 0x11af, 0,
+#undef V5599
+#define V5599 (V + 20349)
+ 0x1105, 0x1174, 0x11b0, 0,
+#undef V5600
+#define V5600 (V + 20353)
+ 0x1105, 0x1174, 0x11b1, 0,
+#undef V5601
+#define V5601 (V + 20357)
+ 0x1105, 0x1174, 0x11b2, 0,
+#undef V5602
+#define V5602 (V + 20361)
+ 0x1105, 0x1174, 0x11b3, 0,
+#undef V5603
+#define V5603 (V + 20365)
+ 0x1105, 0x1174, 0x11b4, 0,
+#undef V5604
+#define V5604 (V + 20369)
+ 0x1105, 0x1174, 0x11b5, 0,
+#undef V5605
+#define V5605 (V + 20373)
+ 0x1105, 0x1174, 0x11b6, 0,
+#undef V5606
+#define V5606 (V + 20377)
+ 0x1105, 0x1174, 0x11b7, 0,
+#undef V5607
+#define V5607 (V + 20381)
+ 0x1105, 0x1174, 0x11b8, 0,
+#undef V5608
+#define V5608 (V + 20385)
+ 0x1105, 0x1174, 0x11b9, 0,
+#undef V5609
+#define V5609 (V + 20389)
+ 0x1105, 0x1174, 0x11ba, 0,
+#undef V5610
+#define V5610 (V + 20393)
+ 0x1105, 0x1174, 0x11bb, 0,
+#undef V5611
+#define V5611 (V + 20397)
+ 0x1105, 0x1174, 0x11bc, 0,
+#undef V5612
+#define V5612 (V + 20401)
+ 0x1105, 0x1174, 0x11bd, 0,
+#undef V5613
+#define V5613 (V + 20405)
+ 0x1105, 0x1174, 0x11be, 0,
+#undef V5614
+#define V5614 (V + 20409)
+ 0x1105, 0x1174, 0x11bf, 0,
+#undef V5615
+#define V5615 (V + 20413)
+ 0x1105, 0x1174, 0x11c0, 0,
+#undef V5616
+#define V5616 (V + 20417)
+ 0x1105, 0x1174, 0x11c1, 0,
+#undef V5617
+#define V5617 (V + 20421)
+ 0x1105, 0x1174, 0x11c2, 0,
+#undef V5618
+#define V5618 (V + 20425)
+ 0x1105, 0x1175, 0,
+#undef V5619
+#define V5619 (V + 20428)
+ 0x1105, 0x1175, 0x11a8, 0,
+#undef V5620
+#define V5620 (V + 20432)
+ 0x1105, 0x1175, 0x11a9, 0,
+#undef V5621
+#define V5621 (V + 20436)
+ 0x1105, 0x1175, 0x11aa, 0,
+#undef V5622
+#define V5622 (V + 20440)
+ 0x1105, 0x1175, 0x11ab, 0,
+#undef V5623
+#define V5623 (V + 20444)
+ 0x1105, 0x1175, 0x11ac, 0,
+#undef V5624
+#define V5624 (V + 20448)
+ 0x1105, 0x1175, 0x11ad, 0,
+#undef V5625
+#define V5625 (V + 20452)
+ 0x1105, 0x1175, 0x11ae, 0,
+#undef V5626
+#define V5626 (V + 20456)
+ 0x1105, 0x1175, 0x11af, 0,
+#undef V5627
+#define V5627 (V + 20460)
+ 0x1105, 0x1175, 0x11b0, 0,
+#undef V5628
+#define V5628 (V + 20464)
+ 0x1105, 0x1175, 0x11b1, 0,
+#undef V5629
+#define V5629 (V + 20468)
+ 0x1105, 0x1175, 0x11b2, 0,
+#undef V5630
+#define V5630 (V + 20472)
+ 0x1105, 0x1175, 0x11b3, 0,
+#undef V5631
+#define V5631 (V + 20476)
+ 0x1105, 0x1175, 0x11b4, 0,
+#undef V5632
+#define V5632 (V + 20480)
+ 0x1105, 0x1175, 0x11b5, 0,
+#undef V5633
+#define V5633 (V + 20484)
+ 0x1105, 0x1175, 0x11b6, 0,
+#undef V5634
+#define V5634 (V + 20488)
+ 0x1105, 0x1175, 0x11b7, 0,
+#undef V5635
+#define V5635 (V + 20492)
+ 0x1105, 0x1175, 0x11b8, 0,
+#undef V5636
+#define V5636 (V + 20496)
+ 0x1105, 0x1175, 0x11b9, 0,
+#undef V5637
+#define V5637 (V + 20500)
+ 0x1105, 0x1175, 0x11ba, 0,
+#undef V5638
+#define V5638 (V + 20504)
+ 0x1105, 0x1175, 0x11bb, 0,
+#undef V5639
+#define V5639 (V + 20508)
+ 0x1105, 0x1175, 0x11bc, 0,
+#undef V5640
+#define V5640 (V + 20512)
+ 0x1105, 0x1175, 0x11bd, 0,
+#undef V5641
+#define V5641 (V + 20516)
+ 0x1105, 0x1175, 0x11be, 0,
+#undef V5642
+#define V5642 (V + 20520)
+ 0x1105, 0x1175, 0x11bf, 0,
+#undef V5643
+#define V5643 (V + 20524)
+ 0x1105, 0x1175, 0x11c0, 0,
+#undef V5644
+#define V5644 (V + 20528)
+ 0x1105, 0x1175, 0x11c1, 0,
+#undef V5645
+#define V5645 (V + 20532)
+ 0x1105, 0x1175, 0x11c2, 0,
+#undef V5646
+#define V5646 (V + 20536)
+ 0x1106, 0x1161, 0x11a8, 0,
+#undef V5647
+#define V5647 (V + 20540)
+ 0x1106, 0x1161, 0x11a9, 0,
+#undef V5648
+#define V5648 (V + 20544)
+ 0x1106, 0x1161, 0x11aa, 0,
+#undef V5649
+#define V5649 (V + 20548)
+ 0x1106, 0x1161, 0x11ab, 0,
+#undef V5650
+#define V5650 (V + 20552)
+ 0x1106, 0x1161, 0x11ac, 0,
+#undef V5651
+#define V5651 (V + 20556)
+ 0x1106, 0x1161, 0x11ad, 0,
+#undef V5652
+#define V5652 (V + 20560)
+ 0x1106, 0x1161, 0x11ae, 0,
+#undef V5653
+#define V5653 (V + 20564)
+ 0x1106, 0x1161, 0x11af, 0,
+#undef V5654
+#define V5654 (V + 20568)
+ 0x1106, 0x1161, 0x11b0, 0,
+#undef V5655
+#define V5655 (V + 20572)
+ 0x1106, 0x1161, 0x11b1, 0,
+#undef V5656
+#define V5656 (V + 20576)
+ 0x1106, 0x1161, 0x11b2, 0,
+#undef V5657
+#define V5657 (V + 20580)
+ 0x1106, 0x1161, 0x11b3, 0,
+#undef V5658
+#define V5658 (V + 20584)
+ 0x1106, 0x1161, 0x11b4, 0,
+#undef V5659
+#define V5659 (V + 20588)
+ 0x1106, 0x1161, 0x11b5, 0,
+#undef V5660
+#define V5660 (V + 20592)
+ 0x1106, 0x1161, 0x11b6, 0,
+#undef V5661
+#define V5661 (V + 20596)
+ 0x1106, 0x1161, 0x11b7, 0,
+#undef V5662
+#define V5662 (V + 20600)
+ 0x1106, 0x1161, 0x11b8, 0,
+#undef V5663
+#define V5663 (V + 20604)
+ 0x1106, 0x1161, 0x11b9, 0,
+#undef V5664
+#define V5664 (V + 20608)
+ 0x1106, 0x1161, 0x11ba, 0,
+#undef V5665
+#define V5665 (V + 20612)
+ 0x1106, 0x1161, 0x11bb, 0,
+#undef V5666
+#define V5666 (V + 20616)
+ 0x1106, 0x1161, 0x11bc, 0,
+#undef V5667
+#define V5667 (V + 20620)
+ 0x1106, 0x1161, 0x11bd, 0,
+#undef V5668
+#define V5668 (V + 20624)
+ 0x1106, 0x1161, 0x11be, 0,
+#undef V5669
+#define V5669 (V + 20628)
+ 0x1106, 0x1161, 0x11bf, 0,
+#undef V5670
+#define V5670 (V + 20632)
+ 0x1106, 0x1161, 0x11c0, 0,
+#undef V5671
+#define V5671 (V + 20636)
+ 0x1106, 0x1161, 0x11c1, 0,
+#undef V5672
+#define V5672 (V + 20640)
+ 0x1106, 0x1161, 0x11c2, 0,
+#undef V5673
+#define V5673 (V + 20644)
+ 0x1106, 0x1162, 0,
+#undef V5674
+#define V5674 (V + 20647)
+ 0x1106, 0x1162, 0x11a8, 0,
+#undef V5675
+#define V5675 (V + 20651)
+ 0x1106, 0x1162, 0x11a9, 0,
+#undef V5676
+#define V5676 (V + 20655)
+ 0x1106, 0x1162, 0x11aa, 0,
+#undef V5677
+#define V5677 (V + 20659)
+ 0x1106, 0x1162, 0x11ab, 0,
+#undef V5678
+#define V5678 (V + 20663)
+ 0x1106, 0x1162, 0x11ac, 0,
+#undef V5679
+#define V5679 (V + 20667)
+ 0x1106, 0x1162, 0x11ad, 0,
+#undef V5680
+#define V5680 (V + 20671)
+ 0x1106, 0x1162, 0x11ae, 0,
+#undef V5681
+#define V5681 (V + 20675)
+ 0x1106, 0x1162, 0x11af, 0,
+#undef V5682
+#define V5682 (V + 20679)
+ 0x1106, 0x1162, 0x11b0, 0,
+#undef V5683
+#define V5683 (V + 20683)
+ 0x1106, 0x1162, 0x11b1, 0,
+#undef V5684
+#define V5684 (V + 20687)
+ 0x1106, 0x1162, 0x11b2, 0,
+#undef V5685
+#define V5685 (V + 20691)
+ 0x1106, 0x1162, 0x11b3, 0,
+#undef V5686
+#define V5686 (V + 20695)
+ 0x1106, 0x1162, 0x11b4, 0,
+#undef V5687
+#define V5687 (V + 20699)
+ 0x1106, 0x1162, 0x11b5, 0,
+#undef V5688
+#define V5688 (V + 20703)
+ 0x1106, 0x1162, 0x11b6, 0,
+#undef V5689
+#define V5689 (V + 20707)
+ 0x1106, 0x1162, 0x11b7, 0,
+#undef V5690
+#define V5690 (V + 20711)
+ 0x1106, 0x1162, 0x11b8, 0,
+#undef V5691
+#define V5691 (V + 20715)
+ 0x1106, 0x1162, 0x11b9, 0,
+#undef V5692
+#define V5692 (V + 20719)
+ 0x1106, 0x1162, 0x11ba, 0,
+#undef V5693
+#define V5693 (V + 20723)
+ 0x1106, 0x1162, 0x11bb, 0,
+#undef V5694
+#define V5694 (V + 20727)
+ 0x1106, 0x1162, 0x11bc, 0,
+#undef V5695
+#define V5695 (V + 20731)
+ 0x1106, 0x1162, 0x11bd, 0,
+#undef V5696
+#define V5696 (V + 20735)
+ 0x1106, 0x1162, 0x11be, 0,
+#undef V5697
+#define V5697 (V + 20739)
+ 0x1106, 0x1162, 0x11bf, 0,
+#undef V5698
+#define V5698 (V + 20743)
+ 0x1106, 0x1162, 0x11c0, 0,
+#undef V5699
+#define V5699 (V + 20747)
+ 0x1106, 0x1162, 0x11c1, 0,
+#undef V5700
+#define V5700 (V + 20751)
+ 0x1106, 0x1162, 0x11c2, 0,
+#undef V5701
+#define V5701 (V + 20755)
+ 0x1106, 0x1163, 0,
+#undef V5702
+#define V5702 (V + 20758)
+ 0x1106, 0x1163, 0x11a8, 0,
+#undef V5703
+#define V5703 (V + 20762)
+ 0x1106, 0x1163, 0x11a9, 0,
+#undef V5704
+#define V5704 (V + 20766)
+ 0x1106, 0x1163, 0x11aa, 0,
+#undef V5705
+#define V5705 (V + 20770)
+ 0x1106, 0x1163, 0x11ab, 0,
+#undef V5706
+#define V5706 (V + 20774)
+ 0x1106, 0x1163, 0x11ac, 0,
+#undef V5707
+#define V5707 (V + 20778)
+ 0x1106, 0x1163, 0x11ad, 0,
+#undef V5708
+#define V5708 (V + 20782)
+ 0x1106, 0x1163, 0x11ae, 0,
+#undef V5709
+#define V5709 (V + 20786)
+ 0x1106, 0x1163, 0x11af, 0,
+#undef V5710
+#define V5710 (V + 20790)
+ 0x1106, 0x1163, 0x11b0, 0,
+#undef V5711
+#define V5711 (V + 20794)
+ 0x1106, 0x1163, 0x11b1, 0,
+#undef V5712
+#define V5712 (V + 20798)
+ 0x1106, 0x1163, 0x11b2, 0,
+#undef V5713
+#define V5713 (V + 20802)
+ 0x1106, 0x1163, 0x11b3, 0,
+#undef V5714
+#define V5714 (V + 20806)
+ 0x1106, 0x1163, 0x11b4, 0,
+#undef V5715
+#define V5715 (V + 20810)
+ 0x1106, 0x1163, 0x11b5, 0,
+#undef V5716
+#define V5716 (V + 20814)
+ 0x1106, 0x1163, 0x11b6, 0,
+#undef V5717
+#define V5717 (V + 20818)
+ 0x1106, 0x1163, 0x11b7, 0,
+#undef V5718
+#define V5718 (V + 20822)
+ 0x1106, 0x1163, 0x11b8, 0,
+#undef V5719
+#define V5719 (V + 20826)
+ 0x1106, 0x1163, 0x11b9, 0,
+#undef V5720
+#define V5720 (V + 20830)
+ 0x1106, 0x1163, 0x11ba, 0,
+#undef V5721
+#define V5721 (V + 20834)
+ 0x1106, 0x1163, 0x11bb, 0,
+#undef V5722
+#define V5722 (V + 20838)
+ 0x1106, 0x1163, 0x11bc, 0,
+#undef V5723
+#define V5723 (V + 20842)
+ 0x1106, 0x1163, 0x11bd, 0,
+#undef V5724
+#define V5724 (V + 20846)
+ 0x1106, 0x1163, 0x11be, 0,
+#undef V5725
+#define V5725 (V + 20850)
+ 0x1106, 0x1163, 0x11bf, 0,
+#undef V5726
+#define V5726 (V + 20854)
+ 0x1106, 0x1163, 0x11c0, 0,
+#undef V5727
+#define V5727 (V + 20858)
+ 0x1106, 0x1163, 0x11c1, 0,
+#undef V5728
+#define V5728 (V + 20862)
+ 0x1106, 0x1163, 0x11c2, 0,
+#undef V5729
+#define V5729 (V + 20866)
+ 0x1106, 0x1164, 0,
+#undef V5730
+#define V5730 (V + 20869)
+ 0x1106, 0x1164, 0x11a8, 0,
+#undef V5731
+#define V5731 (V + 20873)
+ 0x1106, 0x1164, 0x11a9, 0,
+#undef V5732
+#define V5732 (V + 20877)
+ 0x1106, 0x1164, 0x11aa, 0,
+#undef V5733
+#define V5733 (V + 20881)
+ 0x1106, 0x1164, 0x11ab, 0,
+#undef V5734
+#define V5734 (V + 20885)
+ 0x1106, 0x1164, 0x11ac, 0,
+#undef V5735
+#define V5735 (V + 20889)
+ 0x1106, 0x1164, 0x11ad, 0,
+#undef V5736
+#define V5736 (V + 20893)
+ 0x1106, 0x1164, 0x11ae, 0,
+#undef V5737
+#define V5737 (V + 20897)
+ 0x1106, 0x1164, 0x11af, 0,
+#undef V5738
+#define V5738 (V + 20901)
+ 0x1106, 0x1164, 0x11b0, 0,
+#undef V5739
+#define V5739 (V + 20905)
+ 0x1106, 0x1164, 0x11b1, 0,
+#undef V5740
+#define V5740 (V + 20909)
+ 0x1106, 0x1164, 0x11b2, 0,
+#undef V5741
+#define V5741 (V + 20913)
+ 0x1106, 0x1164, 0x11b3, 0,
+#undef V5742
+#define V5742 (V + 20917)
+ 0x1106, 0x1164, 0x11b4, 0,
+#undef V5743
+#define V5743 (V + 20921)
+ 0x1106, 0x1164, 0x11b5, 0,
+#undef V5744
+#define V5744 (V + 20925)
+ 0x1106, 0x1164, 0x11b6, 0,
+#undef V5745
+#define V5745 (V + 20929)
+ 0x1106, 0x1164, 0x11b7, 0,
+#undef V5746
+#define V5746 (V + 20933)
+ 0x1106, 0x1164, 0x11b8, 0,
+#undef V5747
+#define V5747 (V + 20937)
+ 0x1106, 0x1164, 0x11b9, 0,
+#undef V5748
+#define V5748 (V + 20941)
+ 0x1106, 0x1164, 0x11ba, 0,
+#undef V5749
+#define V5749 (V + 20945)
+ 0x1106, 0x1164, 0x11bb, 0,
+#undef V5750
+#define V5750 (V + 20949)
+ 0x1106, 0x1164, 0x11bc, 0,
+#undef V5751
+#define V5751 (V + 20953)
+ 0x1106, 0x1164, 0x11bd, 0,
+#undef V5752
+#define V5752 (V + 20957)
+ 0x1106, 0x1164, 0x11be, 0,
+#undef V5753
+#define V5753 (V + 20961)
+ 0x1106, 0x1164, 0x11bf, 0,
+#undef V5754
+#define V5754 (V + 20965)
+ 0x1106, 0x1164, 0x11c0, 0,
+#undef V5755
+#define V5755 (V + 20969)
+ 0x1106, 0x1164, 0x11c1, 0,
+#undef V5756
+#define V5756 (V + 20973)
+ 0x1106, 0x1164, 0x11c2, 0,
+#undef V5757
+#define V5757 (V + 20977)
+ 0x1106, 0x1165, 0,
+#undef V5758
+#define V5758 (V + 20980)
+ 0x1106, 0x1165, 0x11a8, 0,
+#undef V5759
+#define V5759 (V + 20984)
+ 0x1106, 0x1165, 0x11a9, 0,
+#undef V5760
+#define V5760 (V + 20988)
+ 0x1106, 0x1165, 0x11aa, 0,
+#undef V5761
+#define V5761 (V + 20992)
+ 0x1106, 0x1165, 0x11ab, 0,
+#undef V5762
+#define V5762 (V + 20996)
+ 0x1106, 0x1165, 0x11ac, 0,
+#undef V5763
+#define V5763 (V + 21000)
+ 0x1106, 0x1165, 0x11ad, 0,
+#undef V5764
+#define V5764 (V + 21004)
+ 0x1106, 0x1165, 0x11ae, 0,
+#undef V5765
+#define V5765 (V + 21008)
+ 0x1106, 0x1165, 0x11af, 0,
+#undef V5766
+#define V5766 (V + 21012)
+ 0x1106, 0x1165, 0x11b0, 0,
+#undef V5767
+#define V5767 (V + 21016)
+ 0x1106, 0x1165, 0x11b1, 0,
+#undef V5768
+#define V5768 (V + 21020)
+ 0x1106, 0x1165, 0x11b2, 0,
+#undef V5769
+#define V5769 (V + 21024)
+ 0x1106, 0x1165, 0x11b3, 0,
+#undef V5770
+#define V5770 (V + 21028)
+ 0x1106, 0x1165, 0x11b4, 0,
+#undef V5771
+#define V5771 (V + 21032)
+ 0x1106, 0x1165, 0x11b5, 0,
+#undef V5772
+#define V5772 (V + 21036)
+ 0x1106, 0x1165, 0x11b6, 0,
+#undef V5773
+#define V5773 (V + 21040)
+ 0x1106, 0x1165, 0x11b7, 0,
+#undef V5774
+#define V5774 (V + 21044)
+ 0x1106, 0x1165, 0x11b8, 0,
+#undef V5775
+#define V5775 (V + 21048)
+ 0x1106, 0x1165, 0x11b9, 0,
+#undef V5776
+#define V5776 (V + 21052)
+ 0x1106, 0x1165, 0x11ba, 0,
+#undef V5777
+#define V5777 (V + 21056)
+ 0x1106, 0x1165, 0x11bb, 0,
+#undef V5778
+#define V5778 (V + 21060)
+ 0x1106, 0x1165, 0x11bc, 0,
+#undef V5779
+#define V5779 (V + 21064)
+ 0x1106, 0x1165, 0x11bd, 0,
+#undef V5780
+#define V5780 (V + 21068)
+ 0x1106, 0x1165, 0x11be, 0,
+#undef V5781
+#define V5781 (V + 21072)
+ 0x1106, 0x1165, 0x11bf, 0,
+#undef V5782
+#define V5782 (V + 21076)
+ 0x1106, 0x1165, 0x11c0, 0,
+#undef V5783
+#define V5783 (V + 21080)
+ 0x1106, 0x1165, 0x11c1, 0,
+#undef V5784
+#define V5784 (V + 21084)
+ 0x1106, 0x1165, 0x11c2, 0,
+#undef V5785
+#define V5785 (V + 21088)
+ 0x1106, 0x1166, 0,
+#undef V5786
+#define V5786 (V + 21091)
+ 0x1106, 0x1166, 0x11a8, 0,
+#undef V5787
+#define V5787 (V + 21095)
+ 0x1106, 0x1166, 0x11a9, 0,
+#undef V5788
+#define V5788 (V + 21099)
+ 0x1106, 0x1166, 0x11aa, 0,
+#undef V5789
+#define V5789 (V + 21103)
+ 0x1106, 0x1166, 0x11ab, 0,
+#undef V5790
+#define V5790 (V + 21107)
+ 0x1106, 0x1166, 0x11ac, 0,
+#undef V5791
+#define V5791 (V + 21111)
+ 0x1106, 0x1166, 0x11ad, 0,
+#undef V5792
+#define V5792 (V + 21115)
+ 0x1106, 0x1166, 0x11ae, 0,
+#undef V5793
+#define V5793 (V + 21119)
+ 0x1106, 0x1166, 0x11af, 0,
+#undef V5794
+#define V5794 (V + 21123)
+ 0x1106, 0x1166, 0x11b0, 0,
+#undef V5795
+#define V5795 (V + 21127)
+ 0x1106, 0x1166, 0x11b1, 0,
+#undef V5796
+#define V5796 (V + 21131)
+ 0x1106, 0x1166, 0x11b2, 0,
+#undef V5797
+#define V5797 (V + 21135)
+ 0x1106, 0x1166, 0x11b3, 0,
+#undef V5798
+#define V5798 (V + 21139)
+ 0x1106, 0x1166, 0x11b4, 0,
+#undef V5799
+#define V5799 (V + 21143)
+ 0x1106, 0x1166, 0x11b5, 0,
+#undef V5800
+#define V5800 (V + 21147)
+ 0x1106, 0x1166, 0x11b6, 0,
+#undef V5801
+#define V5801 (V + 21151)
+ 0x1106, 0x1166, 0x11b7, 0,
+#undef V5802
+#define V5802 (V + 21155)
+ 0x1106, 0x1166, 0x11b8, 0,
+#undef V5803
+#define V5803 (V + 21159)
+ 0x1106, 0x1166, 0x11b9, 0,
+#undef V5804
+#define V5804 (V + 21163)
+ 0x1106, 0x1166, 0x11ba, 0,
+#undef V5805
+#define V5805 (V + 21167)
+ 0x1106, 0x1166, 0x11bb, 0,
+#undef V5806
+#define V5806 (V + 21171)
+ 0x1106, 0x1166, 0x11bc, 0,
+#undef V5807
+#define V5807 (V + 21175)
+ 0x1106, 0x1166, 0x11bd, 0,
+#undef V5808
+#define V5808 (V + 21179)
+ 0x1106, 0x1166, 0x11be, 0,
+#undef V5809
+#define V5809 (V + 21183)
+ 0x1106, 0x1166, 0x11bf, 0,
+#undef V5810
+#define V5810 (V + 21187)
+ 0x1106, 0x1166, 0x11c0, 0,
+#undef V5811
+#define V5811 (V + 21191)
+ 0x1106, 0x1166, 0x11c1, 0,
+#undef V5812
+#define V5812 (V + 21195)
+ 0x1106, 0x1166, 0x11c2, 0,
+#undef V5813
+#define V5813 (V + 21199)
+ 0x1106, 0x1167, 0,
+#undef V5814
+#define V5814 (V + 21202)
+ 0x1106, 0x1167, 0x11a8, 0,
+#undef V5815
+#define V5815 (V + 21206)
+ 0x1106, 0x1167, 0x11a9, 0,
+#undef V5816
+#define V5816 (V + 21210)
+ 0x1106, 0x1167, 0x11aa, 0,
+#undef V5817
+#define V5817 (V + 21214)
+ 0x1106, 0x1167, 0x11ab, 0,
+#undef V5818
+#define V5818 (V + 21218)
+ 0x1106, 0x1167, 0x11ac, 0,
+#undef V5819
+#define V5819 (V + 21222)
+ 0x1106, 0x1167, 0x11ad, 0,
+#undef V5820
+#define V5820 (V + 21226)
+ 0x1106, 0x1167, 0x11ae, 0,
+#undef V5821
+#define V5821 (V + 21230)
+ 0x1106, 0x1167, 0x11af, 0,
+#undef V5822
+#define V5822 (V + 21234)
+ 0x1106, 0x1167, 0x11b0, 0,
+#undef V5823
+#define V5823 (V + 21238)
+ 0x1106, 0x1167, 0x11b1, 0,
+#undef V5824
+#define V5824 (V + 21242)
+ 0x1106, 0x1167, 0x11b2, 0,
+#undef V5825
+#define V5825 (V + 21246)
+ 0x1106, 0x1167, 0x11b3, 0,
+#undef V5826
+#define V5826 (V + 21250)
+ 0x1106, 0x1167, 0x11b4, 0,
+#undef V5827
+#define V5827 (V + 21254)
+ 0x1106, 0x1167, 0x11b5, 0,
+#undef V5828
+#define V5828 (V + 21258)
+ 0x1106, 0x1167, 0x11b6, 0,
+#undef V5829
+#define V5829 (V + 21262)
+ 0x1106, 0x1167, 0x11b7, 0,
+#undef V5830
+#define V5830 (V + 21266)
+ 0x1106, 0x1167, 0x11b8, 0,
+#undef V5831
+#define V5831 (V + 21270)
+ 0x1106, 0x1167, 0x11b9, 0,
+#undef V5832
+#define V5832 (V + 21274)
+ 0x1106, 0x1167, 0x11ba, 0,
+#undef V5833
+#define V5833 (V + 21278)
+ 0x1106, 0x1167, 0x11bb, 0,
+#undef V5834
+#define V5834 (V + 21282)
+ 0x1106, 0x1167, 0x11bc, 0,
+#undef V5835
+#define V5835 (V + 21286)
+ 0x1106, 0x1167, 0x11bd, 0,
+#undef V5836
+#define V5836 (V + 21290)
+ 0x1106, 0x1167, 0x11be, 0,
+#undef V5837
+#define V5837 (V + 21294)
+ 0x1106, 0x1167, 0x11bf, 0,
+#undef V5838
+#define V5838 (V + 21298)
+ 0x1106, 0x1167, 0x11c0, 0,
+#undef V5839
+#define V5839 (V + 21302)
+ 0x1106, 0x1167, 0x11c1, 0,
+#undef V5840
+#define V5840 (V + 21306)
+ 0x1106, 0x1167, 0x11c2, 0,
+#undef V5841
+#define V5841 (V + 21310)
+ 0x1106, 0x1168, 0,
+#undef V5842
+#define V5842 (V + 21313)
+ 0x1106, 0x1168, 0x11a8, 0,
+#undef V5843
+#define V5843 (V + 21317)
+ 0x1106, 0x1168, 0x11a9, 0,
+#undef V5844
+#define V5844 (V + 21321)
+ 0x1106, 0x1168, 0x11aa, 0,
+#undef V5845
+#define V5845 (V + 21325)
+ 0x1106, 0x1168, 0x11ab, 0,
+#undef V5846
+#define V5846 (V + 21329)
+ 0x1106, 0x1168, 0x11ac, 0,
+#undef V5847
+#define V5847 (V + 21333)
+ 0x1106, 0x1168, 0x11ad, 0,
+#undef V5848
+#define V5848 (V + 21337)
+ 0x1106, 0x1168, 0x11ae, 0,
+#undef V5849
+#define V5849 (V + 21341)
+ 0x1106, 0x1168, 0x11af, 0,
+#undef V5850
+#define V5850 (V + 21345)
+ 0x1106, 0x1168, 0x11b0, 0,
+#undef V5851
+#define V5851 (V + 21349)
+ 0x1106, 0x1168, 0x11b1, 0,
+#undef V5852
+#define V5852 (V + 21353)
+ 0x1106, 0x1168, 0x11b2, 0,
+#undef V5853
+#define V5853 (V + 21357)
+ 0x1106, 0x1168, 0x11b3, 0,
+#undef V5854
+#define V5854 (V + 21361)
+ 0x1106, 0x1168, 0x11b4, 0,
+#undef V5855
+#define V5855 (V + 21365)
+ 0x1106, 0x1168, 0x11b5, 0,
+#undef V5856
+#define V5856 (V + 21369)
+ 0x1106, 0x1168, 0x11b6, 0,
+#undef V5857
+#define V5857 (V + 21373)
+ 0x1106, 0x1168, 0x11b7, 0,
+#undef V5858
+#define V5858 (V + 21377)
+ 0x1106, 0x1168, 0x11b8, 0,
+#undef V5859
+#define V5859 (V + 21381)
+ 0x1106, 0x1168, 0x11b9, 0,
+#undef V5860
+#define V5860 (V + 21385)
+ 0x1106, 0x1168, 0x11ba, 0,
+#undef V5861
+#define V5861 (V + 21389)
+ 0x1106, 0x1168, 0x11bb, 0,
+#undef V5862
+#define V5862 (V + 21393)
+ 0x1106, 0x1168, 0x11bc, 0,
+#undef V5863
+#define V5863 (V + 21397)
+ 0x1106, 0x1168, 0x11bd, 0,
+#undef V5864
+#define V5864 (V + 21401)
+ 0x1106, 0x1168, 0x11be, 0,
+#undef V5865
+#define V5865 (V + 21405)
+ 0x1106, 0x1168, 0x11bf, 0,
+#undef V5866
+#define V5866 (V + 21409)
+ 0x1106, 0x1168, 0x11c0, 0,
+#undef V5867
+#define V5867 (V + 21413)
+ 0x1106, 0x1168, 0x11c1, 0,
+#undef V5868
+#define V5868 (V + 21417)
+ 0x1106, 0x1168, 0x11c2, 0,
+#undef V5869
+#define V5869 (V + 21421)
+ 0x1106, 0x1169, 0,
+#undef V5870
+#define V5870 (V + 21424)
+ 0x1106, 0x1169, 0x11a8, 0,
+#undef V5871
+#define V5871 (V + 21428)
+ 0x1106, 0x1169, 0x11a9, 0,
+#undef V5872
+#define V5872 (V + 21432)
+ 0x1106, 0x1169, 0x11aa, 0,
+#undef V5873
+#define V5873 (V + 21436)
+ 0x1106, 0x1169, 0x11ab, 0,
+#undef V5874
+#define V5874 (V + 21440)
+ 0x1106, 0x1169, 0x11ac, 0,
+#undef V5875
+#define V5875 (V + 21444)
+ 0x1106, 0x1169, 0x11ad, 0,
+#undef V5876
+#define V5876 (V + 21448)
+ 0x1106, 0x1169, 0x11ae, 0,
+#undef V5877
+#define V5877 (V + 21452)
+ 0x1106, 0x1169, 0x11af, 0,
+#undef V5878
+#define V5878 (V + 21456)
+ 0x1106, 0x1169, 0x11b0, 0,
+#undef V5879
+#define V5879 (V + 21460)
+ 0x1106, 0x1169, 0x11b1, 0,
+#undef V5880
+#define V5880 (V + 21464)
+ 0x1106, 0x1169, 0x11b2, 0,
+#undef V5881
+#define V5881 (V + 21468)
+ 0x1106, 0x1169, 0x11b3, 0,
+#undef V5882
+#define V5882 (V + 21472)
+ 0x1106, 0x1169, 0x11b4, 0,
+#undef V5883
+#define V5883 (V + 21476)
+ 0x1106, 0x1169, 0x11b5, 0,
+#undef V5884
+#define V5884 (V + 21480)
+ 0x1106, 0x1169, 0x11b6, 0,
+#undef V5885
+#define V5885 (V + 21484)
+ 0x1106, 0x1169, 0x11b7, 0,
+#undef V5886
+#define V5886 (V + 21488)
+ 0x1106, 0x1169, 0x11b8, 0,
+#undef V5887
+#define V5887 (V + 21492)
+ 0x1106, 0x1169, 0x11b9, 0,
+#undef V5888
+#define V5888 (V + 21496)
+ 0x1106, 0x1169, 0x11ba, 0,
+#undef V5889
+#define V5889 (V + 21500)
+ 0x1106, 0x1169, 0x11bb, 0,
+#undef V5890
+#define V5890 (V + 21504)
+ 0x1106, 0x1169, 0x11bc, 0,
+#undef V5891
+#define V5891 (V + 21508)
+ 0x1106, 0x1169, 0x11bd, 0,
+#undef V5892
+#define V5892 (V + 21512)
+ 0x1106, 0x1169, 0x11be, 0,
+#undef V5893
+#define V5893 (V + 21516)
+ 0x1106, 0x1169, 0x11bf, 0,
+#undef V5894
+#define V5894 (V + 21520)
+ 0x1106, 0x1169, 0x11c0, 0,
+#undef V5895
+#define V5895 (V + 21524)
+ 0x1106, 0x1169, 0x11c1, 0,
+#undef V5896
+#define V5896 (V + 21528)
+ 0x1106, 0x1169, 0x11c2, 0,
+#undef V5897
+#define V5897 (V + 21532)
+ 0x1106, 0x116a, 0,
+#undef V5898
+#define V5898 (V + 21535)
+ 0x1106, 0x116a, 0x11a8, 0,
+#undef V5899
+#define V5899 (V + 21539)
+ 0x1106, 0x116a, 0x11a9, 0,
+#undef V5900
+#define V5900 (V + 21543)
+ 0x1106, 0x116a, 0x11aa, 0,
+#undef V5901
+#define V5901 (V + 21547)
+ 0x1106, 0x116a, 0x11ab, 0,
+#undef V5902
+#define V5902 (V + 21551)
+ 0x1106, 0x116a, 0x11ac, 0,
+#undef V5903
+#define V5903 (V + 21555)
+ 0x1106, 0x116a, 0x11ad, 0,
+#undef V5904
+#define V5904 (V + 21559)
+ 0x1106, 0x116a, 0x11ae, 0,
+#undef V5905
+#define V5905 (V + 21563)
+ 0x1106, 0x116a, 0x11af, 0,
+#undef V5906
+#define V5906 (V + 21567)
+ 0x1106, 0x116a, 0x11b0, 0,
+#undef V5907
+#define V5907 (V + 21571)
+ 0x1106, 0x116a, 0x11b1, 0,
+#undef V5908
+#define V5908 (V + 21575)
+ 0x1106, 0x116a, 0x11b2, 0,
+#undef V5909
+#define V5909 (V + 21579)
+ 0x1106, 0x116a, 0x11b3, 0,
+#undef V5910
+#define V5910 (V + 21583)
+ 0x1106, 0x116a, 0x11b4, 0,
+#undef V5911
+#define V5911 (V + 21587)
+ 0x1106, 0x116a, 0x11b5, 0,
+#undef V5912
+#define V5912 (V + 21591)
+ 0x1106, 0x116a, 0x11b6, 0,
+#undef V5913
+#define V5913 (V + 21595)
+ 0x1106, 0x116a, 0x11b7, 0,
+#undef V5914
+#define V5914 (V + 21599)
+ 0x1106, 0x116a, 0x11b8, 0,
+#undef V5915
+#define V5915 (V + 21603)
+ 0x1106, 0x116a, 0x11b9, 0,
+#undef V5916
+#define V5916 (V + 21607)
+ 0x1106, 0x116a, 0x11ba, 0,
+#undef V5917
+#define V5917 (V + 21611)
+ 0x1106, 0x116a, 0x11bb, 0,
+#undef V5918
+#define V5918 (V + 21615)
+ 0x1106, 0x116a, 0x11bc, 0,
+#undef V5919
+#define V5919 (V + 21619)
+ 0x1106, 0x116a, 0x11bd, 0,
+#undef V5920
+#define V5920 (V + 21623)
+ 0x1106, 0x116a, 0x11be, 0,
+#undef V5921
+#define V5921 (V + 21627)
+ 0x1106, 0x116a, 0x11bf, 0,
+#undef V5922
+#define V5922 (V + 21631)
+ 0x1106, 0x116a, 0x11c0, 0,
+#undef V5923
+#define V5923 (V + 21635)
+ 0x1106, 0x116a, 0x11c1, 0,
+#undef V5924
+#define V5924 (V + 21639)
+ 0x1106, 0x116a, 0x11c2, 0,
+#undef V5925
+#define V5925 (V + 21643)
+ 0x1106, 0x116b, 0,
+#undef V5926
+#define V5926 (V + 21646)
+ 0x1106, 0x116b, 0x11a8, 0,
+#undef V5927
+#define V5927 (V + 21650)
+ 0x1106, 0x116b, 0x11a9, 0,
+#undef V5928
+#define V5928 (V + 21654)
+ 0x1106, 0x116b, 0x11aa, 0,
+#undef V5929
+#define V5929 (V + 21658)
+ 0x1106, 0x116b, 0x11ab, 0,
+#undef V5930
+#define V5930 (V + 21662)
+ 0x1106, 0x116b, 0x11ac, 0,
+#undef V5931
+#define V5931 (V + 21666)
+ 0x1106, 0x116b, 0x11ad, 0,
+#undef V5932
+#define V5932 (V + 21670)
+ 0x1106, 0x116b, 0x11ae, 0,
+#undef V5933
+#define V5933 (V + 21674)
+ 0x1106, 0x116b, 0x11af, 0,
+#undef V5934
+#define V5934 (V + 21678)
+ 0x1106, 0x116b, 0x11b0, 0,
+#undef V5935
+#define V5935 (V + 21682)
+ 0x1106, 0x116b, 0x11b1, 0,
+#undef V5936
+#define V5936 (V + 21686)
+ 0x1106, 0x116b, 0x11b2, 0,
+#undef V5937
+#define V5937 (V + 21690)
+ 0x1106, 0x116b, 0x11b3, 0,
+#undef V5938
+#define V5938 (V + 21694)
+ 0x1106, 0x116b, 0x11b4, 0,
+#undef V5939
+#define V5939 (V + 21698)
+ 0x1106, 0x116b, 0x11b5, 0,
+#undef V5940
+#define V5940 (V + 21702)
+ 0x1106, 0x116b, 0x11b6, 0,
+#undef V5941
+#define V5941 (V + 21706)
+ 0x1106, 0x116b, 0x11b7, 0,
+#undef V5942
+#define V5942 (V + 21710)
+ 0x1106, 0x116b, 0x11b8, 0,
+#undef V5943
+#define V5943 (V + 21714)
+ 0x1106, 0x116b, 0x11b9, 0,
+#undef V5944
+#define V5944 (V + 21718)
+ 0x1106, 0x116b, 0x11ba, 0,
+#undef V5945
+#define V5945 (V + 21722)
+ 0x1106, 0x116b, 0x11bb, 0,
+#undef V5946
+#define V5946 (V + 21726)
+ 0x1106, 0x116b, 0x11bc, 0,
+#undef V5947
+#define V5947 (V + 21730)
+ 0x1106, 0x116b, 0x11bd, 0,
+#undef V5948
+#define V5948 (V + 21734)
+ 0x1106, 0x116b, 0x11be, 0,
+#undef V5949
+#define V5949 (V + 21738)
+ 0x1106, 0x116b, 0x11bf, 0,
+#undef V5950
+#define V5950 (V + 21742)
+ 0x1106, 0x116b, 0x11c0, 0,
+#undef V5951
+#define V5951 (V + 21746)
+ 0x1106, 0x116b, 0x11c1, 0,
+#undef V5952
+#define V5952 (V + 21750)
+ 0x1106, 0x116b, 0x11c2, 0,
+#undef V5953
+#define V5953 (V + 21754)
+ 0x1106, 0x116c, 0,
+#undef V5954
+#define V5954 (V + 21757)
+ 0x1106, 0x116c, 0x11a8, 0,
+#undef V5955
+#define V5955 (V + 21761)
+ 0x1106, 0x116c, 0x11a9, 0,
+#undef V5956
+#define V5956 (V + 21765)
+ 0x1106, 0x116c, 0x11aa, 0,
+#undef V5957
+#define V5957 (V + 21769)
+ 0x1106, 0x116c, 0x11ab, 0,
+#undef V5958
+#define V5958 (V + 21773)
+ 0x1106, 0x116c, 0x11ac, 0,
+#undef V5959
+#define V5959 (V + 21777)
+ 0x1106, 0x116c, 0x11ad, 0,
+#undef V5960
+#define V5960 (V + 21781)
+ 0x1106, 0x116c, 0x11ae, 0,
+#undef V5961
+#define V5961 (V + 21785)
+ 0x1106, 0x116c, 0x11af, 0,
+#undef V5962
+#define V5962 (V + 21789)
+ 0x1106, 0x116c, 0x11b0, 0,
+#undef V5963
+#define V5963 (V + 21793)
+ 0x1106, 0x116c, 0x11b1, 0,
+#undef V5964
+#define V5964 (V + 21797)
+ 0x1106, 0x116c, 0x11b2, 0,
+#undef V5965
+#define V5965 (V + 21801)
+ 0x1106, 0x116c, 0x11b3, 0,
+#undef V5966
+#define V5966 (V + 21805)
+ 0x1106, 0x116c, 0x11b4, 0,
+#undef V5967
+#define V5967 (V + 21809)
+ 0x1106, 0x116c, 0x11b5, 0,
+#undef V5968
+#define V5968 (V + 21813)
+ 0x1106, 0x116c, 0x11b6, 0,
+#undef V5969
+#define V5969 (V + 21817)
+ 0x1106, 0x116c, 0x11b7, 0,
+#undef V5970
+#define V5970 (V + 21821)
+ 0x1106, 0x116c, 0x11b8, 0,
+#undef V5971
+#define V5971 (V + 21825)
+ 0x1106, 0x116c, 0x11b9, 0,
+#undef V5972
+#define V5972 (V + 21829)
+ 0x1106, 0x116c, 0x11ba, 0,
+#undef V5973
+#define V5973 (V + 21833)
+ 0x1106, 0x116c, 0x11bb, 0,
+#undef V5974
+#define V5974 (V + 21837)
+ 0x1106, 0x116c, 0x11bc, 0,
+#undef V5975
+#define V5975 (V + 21841)
+ 0x1106, 0x116c, 0x11bd, 0,
+#undef V5976
+#define V5976 (V + 21845)
+ 0x1106, 0x116c, 0x11be, 0,
+#undef V5977
+#define V5977 (V + 21849)
+ 0x1106, 0x116c, 0x11bf, 0,
+#undef V5978
+#define V5978 (V + 21853)
+ 0x1106, 0x116c, 0x11c0, 0,
+#undef V5979
+#define V5979 (V + 21857)
+ 0x1106, 0x116c, 0x11c1, 0,
+#undef V5980
+#define V5980 (V + 21861)
+ 0x1106, 0x116c, 0x11c2, 0,
+#undef V5981
+#define V5981 (V + 21865)
+ 0x1106, 0x116d, 0,
+#undef V5982
+#define V5982 (V + 21868)
+ 0x1106, 0x116d, 0x11a8, 0,
+#undef V5983
+#define V5983 (V + 21872)
+ 0x1106, 0x116d, 0x11a9, 0,
+#undef V5984
+#define V5984 (V + 21876)
+ 0x1106, 0x116d, 0x11aa, 0,
+#undef V5985
+#define V5985 (V + 21880)
+ 0x1106, 0x116d, 0x11ab, 0,
+#undef V5986
+#define V5986 (V + 21884)
+ 0x1106, 0x116d, 0x11ac, 0,
+#undef V5987
+#define V5987 (V + 21888)
+ 0x1106, 0x116d, 0x11ad, 0,
+#undef V5988
+#define V5988 (V + 21892)
+ 0x1106, 0x116d, 0x11ae, 0,
+#undef V5989
+#define V5989 (V + 21896)
+ 0x1106, 0x116d, 0x11af, 0,
+#undef V5990
+#define V5990 (V + 21900)
+ 0x1106, 0x116d, 0x11b0, 0,
+#undef V5991
+#define V5991 (V + 21904)
+ 0x1106, 0x116d, 0x11b1, 0,
+#undef V5992
+#define V5992 (V + 21908)
+ 0x1106, 0x116d, 0x11b2, 0,
+#undef V5993
+#define V5993 (V + 21912)
+ 0x1106, 0x116d, 0x11b3, 0,
+#undef V5994
+#define V5994 (V + 21916)
+ 0x1106, 0x116d, 0x11b4, 0,
+#undef V5995
+#define V5995 (V + 21920)
+ 0x1106, 0x116d, 0x11b5, 0,
+#undef V5996
+#define V5996 (V + 21924)
+ 0x1106, 0x116d, 0x11b6, 0,
+#undef V5997
+#define V5997 (V + 21928)
+ 0x1106, 0x116d, 0x11b7, 0,
+#undef V5998
+#define V5998 (V + 21932)
+ 0x1106, 0x116d, 0x11b8, 0,
+#undef V5999
+#define V5999 (V + 21936)
+ 0x1106, 0x116d, 0x11b9, 0,
+#undef V6000
+#define V6000 (V + 21940)
+ 0x1106, 0x116d, 0x11ba, 0,
+#undef V6001
+#define V6001 (V + 21944)
+ 0x1106, 0x116d, 0x11bb, 0,
+#undef V6002
+#define V6002 (V + 21948)
+ 0x1106, 0x116d, 0x11bc, 0,
+#undef V6003
+#define V6003 (V + 21952)
+ 0x1106, 0x116d, 0x11bd, 0,
+#undef V6004
+#define V6004 (V + 21956)
+ 0x1106, 0x116d, 0x11be, 0,
+#undef V6005
+#define V6005 (V + 21960)
+ 0x1106, 0x116d, 0x11bf, 0,
+#undef V6006
+#define V6006 (V + 21964)
+ 0x1106, 0x116d, 0x11c0, 0,
+#undef V6007
+#define V6007 (V + 21968)
+ 0x1106, 0x116d, 0x11c1, 0,
+#undef V6008
+#define V6008 (V + 21972)
+ 0x1106, 0x116d, 0x11c2, 0,
+#undef V6009
+#define V6009 (V + 21976)
+ 0x1106, 0x116e, 0,
+#undef V6010
+#define V6010 (V + 21979)
+ 0x1106, 0x116e, 0x11a8, 0,
+#undef V6011
+#define V6011 (V + 21983)
+ 0x1106, 0x116e, 0x11a9, 0,
+#undef V6012
+#define V6012 (V + 21987)
+ 0x1106, 0x116e, 0x11aa, 0,
+#undef V6013
+#define V6013 (V + 21991)
+ 0x1106, 0x116e, 0x11ab, 0,
+#undef V6014
+#define V6014 (V + 21995)
+ 0x1106, 0x116e, 0x11ac, 0,
+#undef V6015
+#define V6015 (V + 21999)
+ 0x1106, 0x116e, 0x11ad, 0,
+#undef V6016
+#define V6016 (V + 22003)
+ 0x1106, 0x116e, 0x11ae, 0,
+#undef V6017
+#define V6017 (V + 22007)
+ 0x1106, 0x116e, 0x11af, 0,
+#undef V6018
+#define V6018 (V + 22011)
+ 0x1106, 0x116e, 0x11b0, 0,
+#undef V6019
+#define V6019 (V + 22015)
+ 0x1106, 0x116e, 0x11b1, 0,
+#undef V6020
+#define V6020 (V + 22019)
+ 0x1106, 0x116e, 0x11b2, 0,
+#undef V6021
+#define V6021 (V + 22023)
+ 0x1106, 0x116e, 0x11b3, 0,
+#undef V6022
+#define V6022 (V + 22027)
+ 0x1106, 0x116e, 0x11b4, 0,
+#undef V6023
+#define V6023 (V + 22031)
+ 0x1106, 0x116e, 0x11b5, 0,
+#undef V6024
+#define V6024 (V + 22035)
+ 0x1106, 0x116e, 0x11b6, 0,
+#undef V6025
+#define V6025 (V + 22039)
+ 0x1106, 0x116e, 0x11b7, 0,
+#undef V6026
+#define V6026 (V + 22043)
+ 0x1106, 0x116e, 0x11b8, 0,
+#undef V6027
+#define V6027 (V + 22047)
+ 0x1106, 0x116e, 0x11b9, 0,
+#undef V6028
+#define V6028 (V + 22051)
+ 0x1106, 0x116e, 0x11ba, 0,
+#undef V6029
+#define V6029 (V + 22055)
+ 0x1106, 0x116e, 0x11bb, 0,
+#undef V6030
+#define V6030 (V + 22059)
+ 0x1106, 0x116e, 0x11bc, 0,
+#undef V6031
+#define V6031 (V + 22063)
+ 0x1106, 0x116e, 0x11bd, 0,
+#undef V6032
+#define V6032 (V + 22067)
+ 0x1106, 0x116e, 0x11be, 0,
+#undef V6033
+#define V6033 (V + 22071)
+ 0x1106, 0x116e, 0x11bf, 0,
+#undef V6034
+#define V6034 (V + 22075)
+ 0x1106, 0x116e, 0x11c0, 0,
+#undef V6035
+#define V6035 (V + 22079)
+ 0x1106, 0x116e, 0x11c1, 0,
+#undef V6036
+#define V6036 (V + 22083)
+ 0x1106, 0x116e, 0x11c2, 0,
+#undef V6037
+#define V6037 (V + 22087)
+ 0x1106, 0x116f, 0,
+#undef V6038
+#define V6038 (V + 22090)
+ 0x1106, 0x116f, 0x11a8, 0,
+#undef V6039
+#define V6039 (V + 22094)
+ 0x1106, 0x116f, 0x11a9, 0,
+#undef V6040
+#define V6040 (V + 22098)
+ 0x1106, 0x116f, 0x11aa, 0,
+#undef V6041
+#define V6041 (V + 22102)
+ 0x1106, 0x116f, 0x11ab, 0,
+#undef V6042
+#define V6042 (V + 22106)
+ 0x1106, 0x116f, 0x11ac, 0,
+#undef V6043
+#define V6043 (V + 22110)
+ 0x1106, 0x116f, 0x11ad, 0,
+#undef V6044
+#define V6044 (V + 22114)
+ 0x1106, 0x116f, 0x11ae, 0,
+#undef V6045
+#define V6045 (V + 22118)
+ 0x1106, 0x116f, 0x11af, 0,
+#undef V6046
+#define V6046 (V + 22122)
+ 0x1106, 0x116f, 0x11b0, 0,
+#undef V6047
+#define V6047 (V + 22126)
+ 0x1106, 0x116f, 0x11b1, 0,
+#undef V6048
+#define V6048 (V + 22130)
+ 0x1106, 0x116f, 0x11b2, 0,
+#undef V6049
+#define V6049 (V + 22134)
+ 0x1106, 0x116f, 0x11b3, 0,
+#undef V6050
+#define V6050 (V + 22138)
+ 0x1106, 0x116f, 0x11b4, 0,
+#undef V6051
+#define V6051 (V + 22142)
+ 0x1106, 0x116f, 0x11b5, 0,
+#undef V6052
+#define V6052 (V + 22146)
+ 0x1106, 0x116f, 0x11b6, 0,
+#undef V6053
+#define V6053 (V + 22150)
+ 0x1106, 0x116f, 0x11b7, 0,
+#undef V6054
+#define V6054 (V + 22154)
+ 0x1106, 0x116f, 0x11b8, 0,
+#undef V6055
+#define V6055 (V + 22158)
+ 0x1106, 0x116f, 0x11b9, 0,
+#undef V6056
+#define V6056 (V + 22162)
+ 0x1106, 0x116f, 0x11ba, 0,
+#undef V6057
+#define V6057 (V + 22166)
+ 0x1106, 0x116f, 0x11bb, 0,
+#undef V6058
+#define V6058 (V + 22170)
+ 0x1106, 0x116f, 0x11bc, 0,
+#undef V6059
+#define V6059 (V + 22174)
+ 0x1106, 0x116f, 0x11bd, 0,
+#undef V6060
+#define V6060 (V + 22178)
+ 0x1106, 0x116f, 0x11be, 0,
+#undef V6061
+#define V6061 (V + 22182)
+ 0x1106, 0x116f, 0x11bf, 0,
+#undef V6062
+#define V6062 (V + 22186)
+ 0x1106, 0x116f, 0x11c0, 0,
+#undef V6063
+#define V6063 (V + 22190)
+ 0x1106, 0x116f, 0x11c1, 0,
+#undef V6064
+#define V6064 (V + 22194)
+ 0x1106, 0x116f, 0x11c2, 0,
+#undef V6065
+#define V6065 (V + 22198)
+ 0x1106, 0x1170, 0,
+#undef V6066
+#define V6066 (V + 22201)
+ 0x1106, 0x1170, 0x11a8, 0,
+#undef V6067
+#define V6067 (V + 22205)
+ 0x1106, 0x1170, 0x11a9, 0,
+#undef V6068
+#define V6068 (V + 22209)
+ 0x1106, 0x1170, 0x11aa, 0,
+#undef V6069
+#define V6069 (V + 22213)
+ 0x1106, 0x1170, 0x11ab, 0,
+#undef V6070
+#define V6070 (V + 22217)
+ 0x1106, 0x1170, 0x11ac, 0,
+#undef V6071
+#define V6071 (V + 22221)
+ 0x1106, 0x1170, 0x11ad, 0,
+#undef V6072
+#define V6072 (V + 22225)
+ 0x1106, 0x1170, 0x11ae, 0,
+#undef V6073
+#define V6073 (V + 22229)
+ 0x1106, 0x1170, 0x11af, 0,
+#undef V6074
+#define V6074 (V + 22233)
+ 0x1106, 0x1170, 0x11b0, 0,
+#undef V6075
+#define V6075 (V + 22237)
+ 0x1106, 0x1170, 0x11b1, 0,
+#undef V6076
+#define V6076 (V + 22241)
+ 0x1106, 0x1170, 0x11b2, 0,
+#undef V6077
+#define V6077 (V + 22245)
+ 0x1106, 0x1170, 0x11b3, 0,
+#undef V6078
+#define V6078 (V + 22249)
+ 0x1106, 0x1170, 0x11b4, 0,
+#undef V6079
+#define V6079 (V + 22253)
+ 0x1106, 0x1170, 0x11b5, 0,
+#undef V6080
+#define V6080 (V + 22257)
+ 0x1106, 0x1170, 0x11b6, 0,
+#undef V6081
+#define V6081 (V + 22261)
+ 0x1106, 0x1170, 0x11b7, 0,
+#undef V6082
+#define V6082 (V + 22265)
+ 0x1106, 0x1170, 0x11b8, 0,
+#undef V6083
+#define V6083 (V + 22269)
+ 0x1106, 0x1170, 0x11b9, 0,
+#undef V6084
+#define V6084 (V + 22273)
+ 0x1106, 0x1170, 0x11ba, 0,
+#undef V6085
+#define V6085 (V + 22277)
+ 0x1106, 0x1170, 0x11bb, 0,
+#undef V6086
+#define V6086 (V + 22281)
+ 0x1106, 0x1170, 0x11bc, 0,
+#undef V6087
+#define V6087 (V + 22285)
+ 0x1106, 0x1170, 0x11bd, 0,
+#undef V6088
+#define V6088 (V + 22289)
+ 0x1106, 0x1170, 0x11be, 0,
+#undef V6089
+#define V6089 (V + 22293)
+ 0x1106, 0x1170, 0x11bf, 0,
+#undef V6090
+#define V6090 (V + 22297)
+ 0x1106, 0x1170, 0x11c0, 0,
+#undef V6091
+#define V6091 (V + 22301)
+ 0x1106, 0x1170, 0x11c1, 0,
+#undef V6092
+#define V6092 (V + 22305)
+ 0x1106, 0x1170, 0x11c2, 0,
+#undef V6093
+#define V6093 (V + 22309)
+ 0x1106, 0x1171, 0,
+#undef V6094
+#define V6094 (V + 22312)
+ 0x1106, 0x1171, 0x11a8, 0,
+#undef V6095
+#define V6095 (V + 22316)
+ 0x1106, 0x1171, 0x11a9, 0,
+#undef V6096
+#define V6096 (V + 22320)
+ 0x1106, 0x1171, 0x11aa, 0,
+#undef V6097
+#define V6097 (V + 22324)
+ 0x1106, 0x1171, 0x11ab, 0,
+#undef V6098
+#define V6098 (V + 22328)
+ 0x1106, 0x1171, 0x11ac, 0,
+#undef V6099
+#define V6099 (V + 22332)
+ 0x1106, 0x1171, 0x11ad, 0,
+#undef V6100
+#define V6100 (V + 22336)
+ 0x1106, 0x1171, 0x11ae, 0,
+#undef V6101
+#define V6101 (V + 22340)
+ 0x1106, 0x1171, 0x11af, 0,
+#undef V6102
+#define V6102 (V + 22344)
+ 0x1106, 0x1171, 0x11b0, 0,
+#undef V6103
+#define V6103 (V + 22348)
+ 0x1106, 0x1171, 0x11b1, 0,
+#undef V6104
+#define V6104 (V + 22352)
+ 0x1106, 0x1171, 0x11b2, 0,
+#undef V6105
+#define V6105 (V + 22356)
+ 0x1106, 0x1171, 0x11b3, 0,
+#undef V6106
+#define V6106 (V + 22360)
+ 0x1106, 0x1171, 0x11b4, 0,
+#undef V6107
+#define V6107 (V + 22364)
+ 0x1106, 0x1171, 0x11b5, 0,
+#undef V6108
+#define V6108 (V + 22368)
+ 0x1106, 0x1171, 0x11b6, 0,
+#undef V6109
+#define V6109 (V + 22372)
+ 0x1106, 0x1171, 0x11b7, 0,
+#undef V6110
+#define V6110 (V + 22376)
+ 0x1106, 0x1171, 0x11b8, 0,
+#undef V6111
+#define V6111 (V + 22380)
+ 0x1106, 0x1171, 0x11b9, 0,
+#undef V6112
+#define V6112 (V + 22384)
+ 0x1106, 0x1171, 0x11ba, 0,
+#undef V6113
+#define V6113 (V + 22388)
+ 0x1106, 0x1171, 0x11bb, 0,
+#undef V6114
+#define V6114 (V + 22392)
+ 0x1106, 0x1171, 0x11bc, 0,
+#undef V6115
+#define V6115 (V + 22396)
+ 0x1106, 0x1171, 0x11bd, 0,
+#undef V6116
+#define V6116 (V + 22400)
+ 0x1106, 0x1171, 0x11be, 0,
+#undef V6117
+#define V6117 (V + 22404)
+ 0x1106, 0x1171, 0x11bf, 0,
+#undef V6118
+#define V6118 (V + 22408)
+ 0x1106, 0x1171, 0x11c0, 0,
+#undef V6119
+#define V6119 (V + 22412)
+ 0x1106, 0x1171, 0x11c1, 0,
+#undef V6120
+#define V6120 (V + 22416)
+ 0x1106, 0x1171, 0x11c2, 0,
+#undef V6121
+#define V6121 (V + 22420)
+ 0x1106, 0x1172, 0,
+#undef V6122
+#define V6122 (V + 22423)
+ 0x1106, 0x1172, 0x11a8, 0,
+#undef V6123
+#define V6123 (V + 22427)
+ 0x1106, 0x1172, 0x11a9, 0,
+#undef V6124
+#define V6124 (V + 22431)
+ 0x1106, 0x1172, 0x11aa, 0,
+#undef V6125
+#define V6125 (V + 22435)
+ 0x1106, 0x1172, 0x11ab, 0,
+#undef V6126
+#define V6126 (V + 22439)
+ 0x1106, 0x1172, 0x11ac, 0,
+#undef V6127
+#define V6127 (V + 22443)
+ 0x1106, 0x1172, 0x11ad, 0,
+#undef V6128
+#define V6128 (V + 22447)
+ 0x1106, 0x1172, 0x11ae, 0,
+#undef V6129
+#define V6129 (V + 22451)
+ 0x1106, 0x1172, 0x11af, 0,
+#undef V6130
+#define V6130 (V + 22455)
+ 0x1106, 0x1172, 0x11b0, 0,
+#undef V6131
+#define V6131 (V + 22459)
+ 0x1106, 0x1172, 0x11b1, 0,
+#undef V6132
+#define V6132 (V + 22463)
+ 0x1106, 0x1172, 0x11b2, 0,
+#undef V6133
+#define V6133 (V + 22467)
+ 0x1106, 0x1172, 0x11b3, 0,
+#undef V6134
+#define V6134 (V + 22471)
+ 0x1106, 0x1172, 0x11b4, 0,
+#undef V6135
+#define V6135 (V + 22475)
+ 0x1106, 0x1172, 0x11b5, 0,
+#undef V6136
+#define V6136 (V + 22479)
+ 0x1106, 0x1172, 0x11b6, 0,
+#undef V6137
+#define V6137 (V + 22483)
+ 0x1106, 0x1172, 0x11b7, 0,
+#undef V6138
+#define V6138 (V + 22487)
+ 0x1106, 0x1172, 0x11b8, 0,
+#undef V6139
+#define V6139 (V + 22491)
+ 0x1106, 0x1172, 0x11b9, 0,
+#undef V6140
+#define V6140 (V + 22495)
+ 0x1106, 0x1172, 0x11ba, 0,
+#undef V6141
+#define V6141 (V + 22499)
+ 0x1106, 0x1172, 0x11bb, 0,
+#undef V6142
+#define V6142 (V + 22503)
+ 0x1106, 0x1172, 0x11bc, 0,
+#undef V6143
+#define V6143 (V + 22507)
+ 0x1106, 0x1172, 0x11bd, 0,
+#undef V6144
+#define V6144 (V + 22511)
+ 0x1106, 0x1172, 0x11be, 0,
+#undef V6145
+#define V6145 (V + 22515)
+ 0x1106, 0x1172, 0x11bf, 0,
+#undef V6146
+#define V6146 (V + 22519)
+ 0x1106, 0x1172, 0x11c0, 0,
+#undef V6147
+#define V6147 (V + 22523)
+ 0x1106, 0x1172, 0x11c1, 0,
+#undef V6148
+#define V6148 (V + 22527)
+ 0x1106, 0x1172, 0x11c2, 0,
+#undef V6149
+#define V6149 (V + 22531)
+ 0x1106, 0x1173, 0,
+#undef V6150
+#define V6150 (V + 22534)
+ 0x1106, 0x1173, 0x11a8, 0,
+#undef V6151
+#define V6151 (V + 22538)
+ 0x1106, 0x1173, 0x11a9, 0,
+#undef V6152
+#define V6152 (V + 22542)
+ 0x1106, 0x1173, 0x11aa, 0,
+#undef V6153
+#define V6153 (V + 22546)
+ 0x1106, 0x1173, 0x11ab, 0,
+#undef V6154
+#define V6154 (V + 22550)
+ 0x1106, 0x1173, 0x11ac, 0,
+#undef V6155
+#define V6155 (V + 22554)
+ 0x1106, 0x1173, 0x11ad, 0,
+#undef V6156
+#define V6156 (V + 22558)
+ 0x1106, 0x1173, 0x11ae, 0,
+#undef V6157
+#define V6157 (V + 22562)
+ 0x1106, 0x1173, 0x11af, 0,
+#undef V6158
+#define V6158 (V + 22566)
+ 0x1106, 0x1173, 0x11b0, 0,
+#undef V6159
+#define V6159 (V + 22570)
+ 0x1106, 0x1173, 0x11b1, 0,
+#undef V6160
+#define V6160 (V + 22574)
+ 0x1106, 0x1173, 0x11b2, 0,
+#undef V6161
+#define V6161 (V + 22578)
+ 0x1106, 0x1173, 0x11b3, 0,
+#undef V6162
+#define V6162 (V + 22582)
+ 0x1106, 0x1173, 0x11b4, 0,
+#undef V6163
+#define V6163 (V + 22586)
+ 0x1106, 0x1173, 0x11b5, 0,
+#undef V6164
+#define V6164 (V + 22590)
+ 0x1106, 0x1173, 0x11b6, 0,
+#undef V6165
+#define V6165 (V + 22594)
+ 0x1106, 0x1173, 0x11b7, 0,
+#undef V6166
+#define V6166 (V + 22598)
+ 0x1106, 0x1173, 0x11b8, 0,
+#undef V6167
+#define V6167 (V + 22602)
+ 0x1106, 0x1173, 0x11b9, 0,
+#undef V6168
+#define V6168 (V + 22606)
+ 0x1106, 0x1173, 0x11ba, 0,
+#undef V6169
+#define V6169 (V + 22610)
+ 0x1106, 0x1173, 0x11bb, 0,
+#undef V6170
+#define V6170 (V + 22614)
+ 0x1106, 0x1173, 0x11bc, 0,
+#undef V6171
+#define V6171 (V + 22618)
+ 0x1106, 0x1173, 0x11bd, 0,
+#undef V6172
+#define V6172 (V + 22622)
+ 0x1106, 0x1173, 0x11be, 0,
+#undef V6173
+#define V6173 (V + 22626)
+ 0x1106, 0x1173, 0x11bf, 0,
+#undef V6174
+#define V6174 (V + 22630)
+ 0x1106, 0x1173, 0x11c0, 0,
+#undef V6175
+#define V6175 (V + 22634)
+ 0x1106, 0x1173, 0x11c1, 0,
+#undef V6176
+#define V6176 (V + 22638)
+ 0x1106, 0x1173, 0x11c2, 0,
+#undef V6177
+#define V6177 (V + 22642)
+ 0x1106, 0x1174, 0,
+#undef V6178
+#define V6178 (V + 22645)
+ 0x1106, 0x1174, 0x11a8, 0,
+#undef V6179
+#define V6179 (V + 22649)
+ 0x1106, 0x1174, 0x11a9, 0,
+#undef V6180
+#define V6180 (V + 22653)
+ 0x1106, 0x1174, 0x11aa, 0,
+#undef V6181
+#define V6181 (V + 22657)
+ 0x1106, 0x1174, 0x11ab, 0,
+#undef V6182
+#define V6182 (V + 22661)
+ 0x1106, 0x1174, 0x11ac, 0,
+#undef V6183
+#define V6183 (V + 22665)
+ 0x1106, 0x1174, 0x11ad, 0,
+#undef V6184
+#define V6184 (V + 22669)
+ 0x1106, 0x1174, 0x11ae, 0,
+#undef V6185
+#define V6185 (V + 22673)
+ 0x1106, 0x1174, 0x11af, 0,
+#undef V6186
+#define V6186 (V + 22677)
+ 0x1106, 0x1174, 0x11b0, 0,
+#undef V6187
+#define V6187 (V + 22681)
+ 0x1106, 0x1174, 0x11b1, 0,
+#undef V6188
+#define V6188 (V + 22685)
+ 0x1106, 0x1174, 0x11b2, 0,
+#undef V6189
+#define V6189 (V + 22689)
+ 0x1106, 0x1174, 0x11b3, 0,
+#undef V6190
+#define V6190 (V + 22693)
+ 0x1106, 0x1174, 0x11b4, 0,
+#undef V6191
+#define V6191 (V + 22697)
+ 0x1106, 0x1174, 0x11b5, 0,
+#undef V6192
+#define V6192 (V + 22701)
+ 0x1106, 0x1174, 0x11b6, 0,
+#undef V6193
+#define V6193 (V + 22705)
+ 0x1106, 0x1174, 0x11b7, 0,
+#undef V6194
+#define V6194 (V + 22709)
+ 0x1106, 0x1174, 0x11b8, 0,
+#undef V6195
+#define V6195 (V + 22713)
+ 0x1106, 0x1174, 0x11b9, 0,
+#undef V6196
+#define V6196 (V + 22717)
+ 0x1106, 0x1174, 0x11ba, 0,
+#undef V6197
+#define V6197 (V + 22721)
+ 0x1106, 0x1174, 0x11bb, 0,
+#undef V6198
+#define V6198 (V + 22725)
+ 0x1106, 0x1174, 0x11bc, 0,
+#undef V6199
+#define V6199 (V + 22729)
+ 0x1106, 0x1174, 0x11bd, 0,
+#undef V6200
+#define V6200 (V + 22733)
+ 0x1106, 0x1174, 0x11be, 0,
+#undef V6201
+#define V6201 (V + 22737)
+ 0x1106, 0x1174, 0x11bf, 0,
+#undef V6202
+#define V6202 (V + 22741)
+ 0x1106, 0x1174, 0x11c0, 0,
+#undef V6203
+#define V6203 (V + 22745)
+ 0x1106, 0x1174, 0x11c1, 0,
+#undef V6204
+#define V6204 (V + 22749)
+ 0x1106, 0x1174, 0x11c2, 0,
+#undef V6205
+#define V6205 (V + 22753)
+ 0x1106, 0x1175, 0,
+#undef V6206
+#define V6206 (V + 22756)
+ 0x1106, 0x1175, 0x11a8, 0,
+#undef V6207
+#define V6207 (V + 22760)
+ 0x1106, 0x1175, 0x11a9, 0,
+#undef V6208
+#define V6208 (V + 22764)
+ 0x1106, 0x1175, 0x11aa, 0,
+#undef V6209
+#define V6209 (V + 22768)
+ 0x1106, 0x1175, 0x11ab, 0,
+#undef V6210
+#define V6210 (V + 22772)
+ 0x1106, 0x1175, 0x11ac, 0,
+#undef V6211
+#define V6211 (V + 22776)
+ 0x1106, 0x1175, 0x11ad, 0,
+#undef V6212
+#define V6212 (V + 22780)
+ 0x1106, 0x1175, 0x11ae, 0,
+#undef V6213
+#define V6213 (V + 22784)
+ 0x1106, 0x1175, 0x11af, 0,
+#undef V6214
+#define V6214 (V + 22788)
+ 0x1106, 0x1175, 0x11b0, 0,
+#undef V6215
+#define V6215 (V + 22792)
+ 0x1106, 0x1175, 0x11b1, 0,
+#undef V6216
+#define V6216 (V + 22796)
+ 0x1106, 0x1175, 0x11b2, 0,
+#undef V6217
+#define V6217 (V + 22800)
+ 0x1106, 0x1175, 0x11b3, 0,
+#undef V6218
+#define V6218 (V + 22804)
+ 0x1106, 0x1175, 0x11b4, 0,
+#undef V6219
+#define V6219 (V + 22808)
+ 0x1106, 0x1175, 0x11b5, 0,
+#undef V6220
+#define V6220 (V + 22812)
+ 0x1106, 0x1175, 0x11b6, 0,
+#undef V6221
+#define V6221 (V + 22816)
+ 0x1106, 0x1175, 0x11b7, 0,
+#undef V6222
+#define V6222 (V + 22820)
+ 0x1106, 0x1175, 0x11b8, 0,
+#undef V6223
+#define V6223 (V + 22824)
+ 0x1106, 0x1175, 0x11b9, 0,
+#undef V6224
+#define V6224 (V + 22828)
+ 0x1106, 0x1175, 0x11ba, 0,
+#undef V6225
+#define V6225 (V + 22832)
+ 0x1106, 0x1175, 0x11bb, 0,
+#undef V6226
+#define V6226 (V + 22836)
+ 0x1106, 0x1175, 0x11bc, 0,
+#undef V6227
+#define V6227 (V + 22840)
+ 0x1106, 0x1175, 0x11bd, 0,
+#undef V6228
+#define V6228 (V + 22844)
+ 0x1106, 0x1175, 0x11be, 0,
+#undef V6229
+#define V6229 (V + 22848)
+ 0x1106, 0x1175, 0x11bf, 0,
+#undef V6230
+#define V6230 (V + 22852)
+ 0x1106, 0x1175, 0x11c0, 0,
+#undef V6231
+#define V6231 (V + 22856)
+ 0x1106, 0x1175, 0x11c1, 0,
+#undef V6232
+#define V6232 (V + 22860)
+ 0x1106, 0x1175, 0x11c2, 0,
+#undef V6233
+#define V6233 (V + 22864)
+ 0x1107, 0x1161, 0x11a8, 0,
+#undef V6234
+#define V6234 (V + 22868)
+ 0x1107, 0x1161, 0x11a9, 0,
+#undef V6235
+#define V6235 (V + 22872)
+ 0x1107, 0x1161, 0x11aa, 0,
+#undef V6236
+#define V6236 (V + 22876)
+ 0x1107, 0x1161, 0x11ab, 0,
+#undef V6237
+#define V6237 (V + 22880)
+ 0x1107, 0x1161, 0x11ac, 0,
+#undef V6238
+#define V6238 (V + 22884)
+ 0x1107, 0x1161, 0x11ad, 0,
+#undef V6239
+#define V6239 (V + 22888)
+ 0x1107, 0x1161, 0x11ae, 0,
+#undef V6240
+#define V6240 (V + 22892)
+ 0x1107, 0x1161, 0x11af, 0,
+#undef V6241
+#define V6241 (V + 22896)
+ 0x1107, 0x1161, 0x11b0, 0,
+#undef V6242
+#define V6242 (V + 22900)
+ 0x1107, 0x1161, 0x11b1, 0,
+#undef V6243
+#define V6243 (V + 22904)
+ 0x1107, 0x1161, 0x11b2, 0,
+#undef V6244
+#define V6244 (V + 22908)
+ 0x1107, 0x1161, 0x11b3, 0,
+#undef V6245
+#define V6245 (V + 22912)
+ 0x1107, 0x1161, 0x11b4, 0,
+#undef V6246
+#define V6246 (V + 22916)
+ 0x1107, 0x1161, 0x11b5, 0,
+#undef V6247
+#define V6247 (V + 22920)
+ 0x1107, 0x1161, 0x11b6, 0,
+#undef V6248
+#define V6248 (V + 22924)
+ 0x1107, 0x1161, 0x11b7, 0,
+#undef V6249
+#define V6249 (V + 22928)
+ 0x1107, 0x1161, 0x11b8, 0,
+#undef V6250
+#define V6250 (V + 22932)
+ 0x1107, 0x1161, 0x11b9, 0,
+#undef V6251
+#define V6251 (V + 22936)
+ 0x1107, 0x1161, 0x11ba, 0,
+#undef V6252
+#define V6252 (V + 22940)
+ 0x1107, 0x1161, 0x11bb, 0,
+#undef V6253
+#define V6253 (V + 22944)
+ 0x1107, 0x1161, 0x11bc, 0,
+#undef V6254
+#define V6254 (V + 22948)
+ 0x1107, 0x1161, 0x11bd, 0,
+#undef V6255
+#define V6255 (V + 22952)
+ 0x1107, 0x1161, 0x11be, 0,
+#undef V6256
+#define V6256 (V + 22956)
+ 0x1107, 0x1161, 0x11bf, 0,
+#undef V6257
+#define V6257 (V + 22960)
+ 0x1107, 0x1161, 0x11c0, 0,
+#undef V6258
+#define V6258 (V + 22964)
+ 0x1107, 0x1161, 0x11c1, 0,
+#undef V6259
+#define V6259 (V + 22968)
+ 0x1107, 0x1161, 0x11c2, 0,
+#undef V6260
+#define V6260 (V + 22972)
+ 0x1107, 0x1162, 0,
+#undef V6261
+#define V6261 (V + 22975)
+ 0x1107, 0x1162, 0x11a8, 0,
+#undef V6262
+#define V6262 (V + 22979)
+ 0x1107, 0x1162, 0x11a9, 0,
+#undef V6263
+#define V6263 (V + 22983)
+ 0x1107, 0x1162, 0x11aa, 0,
+#undef V6264
+#define V6264 (V + 22987)
+ 0x1107, 0x1162, 0x11ab, 0,
+#undef V6265
+#define V6265 (V + 22991)
+ 0x1107, 0x1162, 0x11ac, 0,
+#undef V6266
+#define V6266 (V + 22995)
+ 0x1107, 0x1162, 0x11ad, 0,
+#undef V6267
+#define V6267 (V + 22999)
+ 0x1107, 0x1162, 0x11ae, 0,
+#undef V6268
+#define V6268 (V + 23003)
+ 0x1107, 0x1162, 0x11af, 0,
+#undef V6269
+#define V6269 (V + 23007)
+ 0x1107, 0x1162, 0x11b0, 0,
+#undef V6270
+#define V6270 (V + 23011)
+ 0x1107, 0x1162, 0x11b1, 0,
+#undef V6271
+#define V6271 (V + 23015)
+ 0x1107, 0x1162, 0x11b2, 0,
+#undef V6272
+#define V6272 (V + 23019)
+ 0x1107, 0x1162, 0x11b3, 0,
+#undef V6273
+#define V6273 (V + 23023)
+ 0x1107, 0x1162, 0x11b4, 0,
+#undef V6274
+#define V6274 (V + 23027)
+ 0x1107, 0x1162, 0x11b5, 0,
+#undef V6275
+#define V6275 (V + 23031)
+ 0x1107, 0x1162, 0x11b6, 0,
+#undef V6276
+#define V6276 (V + 23035)
+ 0x1107, 0x1162, 0x11b7, 0,
+#undef V6277
+#define V6277 (V + 23039)
+ 0x1107, 0x1162, 0x11b8, 0,
+#undef V6278
+#define V6278 (V + 23043)
+ 0x1107, 0x1162, 0x11b9, 0,
+#undef V6279
+#define V6279 (V + 23047)
+ 0x1107, 0x1162, 0x11ba, 0,
+#undef V6280
+#define V6280 (V + 23051)
+ 0x1107, 0x1162, 0x11bb, 0,
+#undef V6281
+#define V6281 (V + 23055)
+ 0x1107, 0x1162, 0x11bc, 0,
+#undef V6282
+#define V6282 (V + 23059)
+ 0x1107, 0x1162, 0x11bd, 0,
+#undef V6283
+#define V6283 (V + 23063)
+ 0x1107, 0x1162, 0x11be, 0,
+#undef V6284
+#define V6284 (V + 23067)
+ 0x1107, 0x1162, 0x11bf, 0,
+#undef V6285
+#define V6285 (V + 23071)
+ 0x1107, 0x1162, 0x11c0, 0,
+#undef V6286
+#define V6286 (V + 23075)
+ 0x1107, 0x1162, 0x11c1, 0,
+#undef V6287
+#define V6287 (V + 23079)
+ 0x1107, 0x1162, 0x11c2, 0,
+#undef V6288
+#define V6288 (V + 23083)
+ 0x1107, 0x1163, 0,
+#undef V6289
+#define V6289 (V + 23086)
+ 0x1107, 0x1163, 0x11a8, 0,
+#undef V6290
+#define V6290 (V + 23090)
+ 0x1107, 0x1163, 0x11a9, 0,
+#undef V6291
+#define V6291 (V + 23094)
+ 0x1107, 0x1163, 0x11aa, 0,
+#undef V6292
+#define V6292 (V + 23098)
+ 0x1107, 0x1163, 0x11ab, 0,
+#undef V6293
+#define V6293 (V + 23102)
+ 0x1107, 0x1163, 0x11ac, 0,
+#undef V6294
+#define V6294 (V + 23106)
+ 0x1107, 0x1163, 0x11ad, 0,
+#undef V6295
+#define V6295 (V + 23110)
+ 0x1107, 0x1163, 0x11ae, 0,
+#undef V6296
+#define V6296 (V + 23114)
+ 0x1107, 0x1163, 0x11af, 0,
+#undef V6297
+#define V6297 (V + 23118)
+ 0x1107, 0x1163, 0x11b0, 0,
+#undef V6298
+#define V6298 (V + 23122)
+ 0x1107, 0x1163, 0x11b1, 0,
+#undef V6299
+#define V6299 (V + 23126)
+ 0x1107, 0x1163, 0x11b2, 0,
+#undef V6300
+#define V6300 (V + 23130)
+ 0x1107, 0x1163, 0x11b3, 0,
+#undef V6301
+#define V6301 (V + 23134)
+ 0x1107, 0x1163, 0x11b4, 0,
+#undef V6302
+#define V6302 (V + 23138)
+ 0x1107, 0x1163, 0x11b5, 0,
+#undef V6303
+#define V6303 (V + 23142)
+ 0x1107, 0x1163, 0x11b6, 0,
+#undef V6304
+#define V6304 (V + 23146)
+ 0x1107, 0x1163, 0x11b7, 0,
+#undef V6305
+#define V6305 (V + 23150)
+ 0x1107, 0x1163, 0x11b8, 0,
+#undef V6306
+#define V6306 (V + 23154)
+ 0x1107, 0x1163, 0x11b9, 0,
+#undef V6307
+#define V6307 (V + 23158)
+ 0x1107, 0x1163, 0x11ba, 0,
+#undef V6308
+#define V6308 (V + 23162)
+ 0x1107, 0x1163, 0x11bb, 0,
+#undef V6309
+#define V6309 (V + 23166)
+ 0x1107, 0x1163, 0x11bc, 0,
+#undef V6310
+#define V6310 (V + 23170)
+ 0x1107, 0x1163, 0x11bd, 0,
+#undef V6311
+#define V6311 (V + 23174)
+ 0x1107, 0x1163, 0x11be, 0,
+#undef V6312
+#define V6312 (V + 23178)
+ 0x1107, 0x1163, 0x11bf, 0,
+#undef V6313
+#define V6313 (V + 23182)
+ 0x1107, 0x1163, 0x11c0, 0,
+#undef V6314
+#define V6314 (V + 23186)
+ 0x1107, 0x1163, 0x11c1, 0,
+#undef V6315
+#define V6315 (V + 23190)
+ 0x1107, 0x1163, 0x11c2, 0,
+#undef V6316
+#define V6316 (V + 23194)
+ 0x1107, 0x1164, 0,
+#undef V6317
+#define V6317 (V + 23197)
+ 0x1107, 0x1164, 0x11a8, 0,
+#undef V6318
+#define V6318 (V + 23201)
+ 0x1107, 0x1164, 0x11a9, 0,
+#undef V6319
+#define V6319 (V + 23205)
+ 0x1107, 0x1164, 0x11aa, 0,
+#undef V6320
+#define V6320 (V + 23209)
+ 0x1107, 0x1164, 0x11ab, 0,
+#undef V6321
+#define V6321 (V + 23213)
+ 0x1107, 0x1164, 0x11ac, 0,
+#undef V6322
+#define V6322 (V + 23217)
+ 0x1107, 0x1164, 0x11ad, 0,
+#undef V6323
+#define V6323 (V + 23221)
+ 0x1107, 0x1164, 0x11ae, 0,
+#undef V6324
+#define V6324 (V + 23225)
+ 0x1107, 0x1164, 0x11af, 0,
+#undef V6325
+#define V6325 (V + 23229)
+ 0x1107, 0x1164, 0x11b0, 0,
+#undef V6326
+#define V6326 (V + 23233)
+ 0x1107, 0x1164, 0x11b1, 0,
+#undef V6327
+#define V6327 (V + 23237)
+ 0x1107, 0x1164, 0x11b2, 0,
+#undef V6328
+#define V6328 (V + 23241)
+ 0x1107, 0x1164, 0x11b3, 0,
+#undef V6329
+#define V6329 (V + 23245)
+ 0x1107, 0x1164, 0x11b4, 0,
+#undef V6330
+#define V6330 (V + 23249)
+ 0x1107, 0x1164, 0x11b5, 0,
+#undef V6331
+#define V6331 (V + 23253)
+ 0x1107, 0x1164, 0x11b6, 0,
+#undef V6332
+#define V6332 (V + 23257)
+ 0x1107, 0x1164, 0x11b7, 0,
+#undef V6333
+#define V6333 (V + 23261)
+ 0x1107, 0x1164, 0x11b8, 0,
+#undef V6334
+#define V6334 (V + 23265)
+ 0x1107, 0x1164, 0x11b9, 0,
+#undef V6335
+#define V6335 (V + 23269)
+ 0x1107, 0x1164, 0x11ba, 0,
+#undef V6336
+#define V6336 (V + 23273)
+ 0x1107, 0x1164, 0x11bb, 0,
+#undef V6337
+#define V6337 (V + 23277)
+ 0x1107, 0x1164, 0x11bc, 0,
+#undef V6338
+#define V6338 (V + 23281)
+ 0x1107, 0x1164, 0x11bd, 0,
+#undef V6339
+#define V6339 (V + 23285)
+ 0x1107, 0x1164, 0x11be, 0,
+#undef V6340
+#define V6340 (V + 23289)
+ 0x1107, 0x1164, 0x11bf, 0,
+#undef V6341
+#define V6341 (V + 23293)
+ 0x1107, 0x1164, 0x11c0, 0,
+#undef V6342
+#define V6342 (V + 23297)
+ 0x1107, 0x1164, 0x11c1, 0,
+#undef V6343
+#define V6343 (V + 23301)
+ 0x1107, 0x1164, 0x11c2, 0,
+#undef V6344
+#define V6344 (V + 23305)
+ 0x1107, 0x1165, 0,
+#undef V6345
+#define V6345 (V + 23308)
+ 0x1107, 0x1165, 0x11a8, 0,
+#undef V6346
+#define V6346 (V + 23312)
+ 0x1107, 0x1165, 0x11a9, 0,
+#undef V6347
+#define V6347 (V + 23316)
+ 0x1107, 0x1165, 0x11aa, 0,
+#undef V6348
+#define V6348 (V + 23320)
+ 0x1107, 0x1165, 0x11ab, 0,
+#undef V6349
+#define V6349 (V + 23324)
+ 0x1107, 0x1165, 0x11ac, 0,
+#undef V6350
+#define V6350 (V + 23328)
+ 0x1107, 0x1165, 0x11ad, 0,
+#undef V6351
+#define V6351 (V + 23332)
+ 0x1107, 0x1165, 0x11ae, 0,
+#undef V6352
+#define V6352 (V + 23336)
+ 0x1107, 0x1165, 0x11af, 0,
+#undef V6353
+#define V6353 (V + 23340)
+ 0x1107, 0x1165, 0x11b0, 0,
+#undef V6354
+#define V6354 (V + 23344)
+ 0x1107, 0x1165, 0x11b1, 0,
+#undef V6355
+#define V6355 (V + 23348)
+ 0x1107, 0x1165, 0x11b2, 0,
+#undef V6356
+#define V6356 (V + 23352)
+ 0x1107, 0x1165, 0x11b3, 0,
+#undef V6357
+#define V6357 (V + 23356)
+ 0x1107, 0x1165, 0x11b4, 0,
+#undef V6358
+#define V6358 (V + 23360)
+ 0x1107, 0x1165, 0x11b5, 0,
+#undef V6359
+#define V6359 (V + 23364)
+ 0x1107, 0x1165, 0x11b6, 0,
+#undef V6360
+#define V6360 (V + 23368)
+ 0x1107, 0x1165, 0x11b7, 0,
+#undef V6361
+#define V6361 (V + 23372)
+ 0x1107, 0x1165, 0x11b8, 0,
+#undef V6362
+#define V6362 (V + 23376)
+ 0x1107, 0x1165, 0x11b9, 0,
+#undef V6363
+#define V6363 (V + 23380)
+ 0x1107, 0x1165, 0x11ba, 0,
+#undef V6364
+#define V6364 (V + 23384)
+ 0x1107, 0x1165, 0x11bb, 0,
+#undef V6365
+#define V6365 (V + 23388)
+ 0x1107, 0x1165, 0x11bc, 0,
+#undef V6366
+#define V6366 (V + 23392)
+ 0x1107, 0x1165, 0x11bd, 0,
+#undef V6367
+#define V6367 (V + 23396)
+ 0x1107, 0x1165, 0x11be, 0,
+#undef V6368
+#define V6368 (V + 23400)
+ 0x1107, 0x1165, 0x11bf, 0,
+#undef V6369
+#define V6369 (V + 23404)
+ 0x1107, 0x1165, 0x11c0, 0,
+#undef V6370
+#define V6370 (V + 23408)
+ 0x1107, 0x1165, 0x11c1, 0,
+#undef V6371
+#define V6371 (V + 23412)
+ 0x1107, 0x1165, 0x11c2, 0,
+#undef V6372
+#define V6372 (V + 23416)
+ 0x1107, 0x1166, 0,
+#undef V6373
+#define V6373 (V + 23419)
+ 0x1107, 0x1166, 0x11a8, 0,
+#undef V6374
+#define V6374 (V + 23423)
+ 0x1107, 0x1166, 0x11a9, 0,
+#undef V6375
+#define V6375 (V + 23427)
+ 0x1107, 0x1166, 0x11aa, 0,
+#undef V6376
+#define V6376 (V + 23431)
+ 0x1107, 0x1166, 0x11ab, 0,
+#undef V6377
+#define V6377 (V + 23435)
+ 0x1107, 0x1166, 0x11ac, 0,
+#undef V6378
+#define V6378 (V + 23439)
+ 0x1107, 0x1166, 0x11ad, 0,
+#undef V6379
+#define V6379 (V + 23443)
+ 0x1107, 0x1166, 0x11ae, 0,
+#undef V6380
+#define V6380 (V + 23447)
+ 0x1107, 0x1166, 0x11af, 0,
+#undef V6381
+#define V6381 (V + 23451)
+ 0x1107, 0x1166, 0x11b0, 0,
+#undef V6382
+#define V6382 (V + 23455)
+ 0x1107, 0x1166, 0x11b1, 0,
+#undef V6383
+#define V6383 (V + 23459)
+ 0x1107, 0x1166, 0x11b2, 0,
+#undef V6384
+#define V6384 (V + 23463)
+ 0x1107, 0x1166, 0x11b3, 0,
+#undef V6385
+#define V6385 (V + 23467)
+ 0x1107, 0x1166, 0x11b4, 0,
+#undef V6386
+#define V6386 (V + 23471)
+ 0x1107, 0x1166, 0x11b5, 0,
+#undef V6387
+#define V6387 (V + 23475)
+ 0x1107, 0x1166, 0x11b6, 0,
+#undef V6388
+#define V6388 (V + 23479)
+ 0x1107, 0x1166, 0x11b7, 0,
+#undef V6389
+#define V6389 (V + 23483)
+ 0x1107, 0x1166, 0x11b8, 0,
+#undef V6390
+#define V6390 (V + 23487)
+ 0x1107, 0x1166, 0x11b9, 0,
+#undef V6391
+#define V6391 (V + 23491)
+ 0x1107, 0x1166, 0x11ba, 0,
+#undef V6392
+#define V6392 (V + 23495)
+ 0x1107, 0x1166, 0x11bb, 0,
+#undef V6393
+#define V6393 (V + 23499)
+ 0x1107, 0x1166, 0x11bc, 0,
+#undef V6394
+#define V6394 (V + 23503)
+ 0x1107, 0x1166, 0x11bd, 0,
+#undef V6395
+#define V6395 (V + 23507)
+ 0x1107, 0x1166, 0x11be, 0,
+#undef V6396
+#define V6396 (V + 23511)
+ 0x1107, 0x1166, 0x11bf, 0,
+#undef V6397
+#define V6397 (V + 23515)
+ 0x1107, 0x1166, 0x11c0, 0,
+#undef V6398
+#define V6398 (V + 23519)
+ 0x1107, 0x1166, 0x11c1, 0,
+#undef V6399
+#define V6399 (V + 23523)
+ 0x1107, 0x1166, 0x11c2, 0,
+#undef V6400
+#define V6400 (V + 23527)
+ 0x1107, 0x1167, 0,
+#undef V6401
+#define V6401 (V + 23530)
+ 0x1107, 0x1167, 0x11a8, 0,
+#undef V6402
+#define V6402 (V + 23534)
+ 0x1107, 0x1167, 0x11a9, 0,
+#undef V6403
+#define V6403 (V + 23538)
+ 0x1107, 0x1167, 0x11aa, 0,
+#undef V6404
+#define V6404 (V + 23542)
+ 0x1107, 0x1167, 0x11ab, 0,
+#undef V6405
+#define V6405 (V + 23546)
+ 0x1107, 0x1167, 0x11ac, 0,
+#undef V6406
+#define V6406 (V + 23550)
+ 0x1107, 0x1167, 0x11ad, 0,
+#undef V6407
+#define V6407 (V + 23554)
+ 0x1107, 0x1167, 0x11ae, 0,
+#undef V6408
+#define V6408 (V + 23558)
+ 0x1107, 0x1167, 0x11af, 0,
+#undef V6409
+#define V6409 (V + 23562)
+ 0x1107, 0x1167, 0x11b0, 0,
+#undef V6410
+#define V6410 (V + 23566)
+ 0x1107, 0x1167, 0x11b1, 0,
+#undef V6411
+#define V6411 (V + 23570)
+ 0x1107, 0x1167, 0x11b2, 0,
+#undef V6412
+#define V6412 (V + 23574)
+ 0x1107, 0x1167, 0x11b3, 0,
+#undef V6413
+#define V6413 (V + 23578)
+ 0x1107, 0x1167, 0x11b4, 0,
+#undef V6414
+#define V6414 (V + 23582)
+ 0x1107, 0x1167, 0x11b5, 0,
+#undef V6415
+#define V6415 (V + 23586)
+ 0x1107, 0x1167, 0x11b6, 0,
+#undef V6416
+#define V6416 (V + 23590)
+ 0x1107, 0x1167, 0x11b7, 0,
+#undef V6417
+#define V6417 (V + 23594)
+ 0x1107, 0x1167, 0x11b8, 0,
+#undef V6418
+#define V6418 (V + 23598)
+ 0x1107, 0x1167, 0x11b9, 0,
+#undef V6419
+#define V6419 (V + 23602)
+ 0x1107, 0x1167, 0x11ba, 0,
+#undef V6420
+#define V6420 (V + 23606)
+ 0x1107, 0x1167, 0x11bb, 0,
+#undef V6421
+#define V6421 (V + 23610)
+ 0x1107, 0x1167, 0x11bc, 0,
+#undef V6422
+#define V6422 (V + 23614)
+ 0x1107, 0x1167, 0x11bd, 0,
+#undef V6423
+#define V6423 (V + 23618)
+ 0x1107, 0x1167, 0x11be, 0,
+#undef V6424
+#define V6424 (V + 23622)
+ 0x1107, 0x1167, 0x11bf, 0,
+#undef V6425
+#define V6425 (V + 23626)
+ 0x1107, 0x1167, 0x11c0, 0,
+#undef V6426
+#define V6426 (V + 23630)
+ 0x1107, 0x1167, 0x11c1, 0,
+#undef V6427
+#define V6427 (V + 23634)
+ 0x1107, 0x1167, 0x11c2, 0,
+#undef V6428
+#define V6428 (V + 23638)
+ 0x1107, 0x1168, 0,
+#undef V6429
+#define V6429 (V + 23641)
+ 0x1107, 0x1168, 0x11a8, 0,
+#undef V6430
+#define V6430 (V + 23645)
+ 0x1107, 0x1168, 0x11a9, 0,
+#undef V6431
+#define V6431 (V + 23649)
+ 0x1107, 0x1168, 0x11aa, 0,
+#undef V6432
+#define V6432 (V + 23653)
+ 0x1107, 0x1168, 0x11ab, 0,
+#undef V6433
+#define V6433 (V + 23657)
+ 0x1107, 0x1168, 0x11ac, 0,
+#undef V6434
+#define V6434 (V + 23661)
+ 0x1107, 0x1168, 0x11ad, 0,
+#undef V6435
+#define V6435 (V + 23665)
+ 0x1107, 0x1168, 0x11ae, 0,
+#undef V6436
+#define V6436 (V + 23669)
+ 0x1107, 0x1168, 0x11af, 0,
+#undef V6437
+#define V6437 (V + 23673)
+ 0x1107, 0x1168, 0x11b0, 0,
+#undef V6438
+#define V6438 (V + 23677)
+ 0x1107, 0x1168, 0x11b1, 0,
+#undef V6439
+#define V6439 (V + 23681)
+ 0x1107, 0x1168, 0x11b2, 0,
+#undef V6440
+#define V6440 (V + 23685)
+ 0x1107, 0x1168, 0x11b3, 0,
+#undef V6441
+#define V6441 (V + 23689)
+ 0x1107, 0x1168, 0x11b4, 0,
+#undef V6442
+#define V6442 (V + 23693)
+ 0x1107, 0x1168, 0x11b5, 0,
+#undef V6443
+#define V6443 (V + 23697)
+ 0x1107, 0x1168, 0x11b6, 0,
+#undef V6444
+#define V6444 (V + 23701)
+ 0x1107, 0x1168, 0x11b7, 0,
+#undef V6445
+#define V6445 (V + 23705)
+ 0x1107, 0x1168, 0x11b8, 0,
+#undef V6446
+#define V6446 (V + 23709)
+ 0x1107, 0x1168, 0x11b9, 0,
+#undef V6447
+#define V6447 (V + 23713)
+ 0x1107, 0x1168, 0x11ba, 0,
+#undef V6448
+#define V6448 (V + 23717)
+ 0x1107, 0x1168, 0x11bb, 0,
+#undef V6449
+#define V6449 (V + 23721)
+ 0x1107, 0x1168, 0x11bc, 0,
+#undef V6450
+#define V6450 (V + 23725)
+ 0x1107, 0x1168, 0x11bd, 0,
+#undef V6451
+#define V6451 (V + 23729)
+ 0x1107, 0x1168, 0x11be, 0,
+#undef V6452
+#define V6452 (V + 23733)
+ 0x1107, 0x1168, 0x11bf, 0,
+#undef V6453
+#define V6453 (V + 23737)
+ 0x1107, 0x1168, 0x11c0, 0,
+#undef V6454
+#define V6454 (V + 23741)
+ 0x1107, 0x1168, 0x11c1, 0,
+#undef V6455
+#define V6455 (V + 23745)
+ 0x1107, 0x1168, 0x11c2, 0,
+#undef V6456
+#define V6456 (V + 23749)
+ 0x1107, 0x1169, 0,
+#undef V6457
+#define V6457 (V + 23752)
+ 0x1107, 0x1169, 0x11a8, 0,
+#undef V6458
+#define V6458 (V + 23756)
+ 0x1107, 0x1169, 0x11a9, 0,
+#undef V6459
+#define V6459 (V + 23760)
+ 0x1107, 0x1169, 0x11aa, 0,
+#undef V6460
+#define V6460 (V + 23764)
+ 0x1107, 0x1169, 0x11ab, 0,
+#undef V6461
+#define V6461 (V + 23768)
+ 0x1107, 0x1169, 0x11ac, 0,
+#undef V6462
+#define V6462 (V + 23772)
+ 0x1107, 0x1169, 0x11ad, 0,
+#undef V6463
+#define V6463 (V + 23776)
+ 0x1107, 0x1169, 0x11ae, 0,
+#undef V6464
+#define V6464 (V + 23780)
+ 0x1107, 0x1169, 0x11af, 0,
+#undef V6465
+#define V6465 (V + 23784)
+ 0x1107, 0x1169, 0x11b0, 0,
+#undef V6466
+#define V6466 (V + 23788)
+ 0x1107, 0x1169, 0x11b1, 0,
+#undef V6467
+#define V6467 (V + 23792)
+ 0x1107, 0x1169, 0x11b2, 0,
+#undef V6468
+#define V6468 (V + 23796)
+ 0x1107, 0x1169, 0x11b3, 0,
+#undef V6469
+#define V6469 (V + 23800)
+ 0x1107, 0x1169, 0x11b4, 0,
+#undef V6470
+#define V6470 (V + 23804)
+ 0x1107, 0x1169, 0x11b5, 0,
+#undef V6471
+#define V6471 (V + 23808)
+ 0x1107, 0x1169, 0x11b6, 0,
+#undef V6472
+#define V6472 (V + 23812)
+ 0x1107, 0x1169, 0x11b7, 0,
+#undef V6473
+#define V6473 (V + 23816)
+ 0x1107, 0x1169, 0x11b8, 0,
+#undef V6474
+#define V6474 (V + 23820)
+ 0x1107, 0x1169, 0x11b9, 0,
+#undef V6475
+#define V6475 (V + 23824)
+ 0x1107, 0x1169, 0x11ba, 0,
+#undef V6476
+#define V6476 (V + 23828)
+ 0x1107, 0x1169, 0x11bb, 0,
+#undef V6477
+#define V6477 (V + 23832)
+ 0x1107, 0x1169, 0x11bc, 0,
+#undef V6478
+#define V6478 (V + 23836)
+ 0x1107, 0x1169, 0x11bd, 0,
+#undef V6479
+#define V6479 (V + 23840)
+ 0x1107, 0x1169, 0x11be, 0,
+#undef V6480
+#define V6480 (V + 23844)
+ 0x1107, 0x1169, 0x11bf, 0,
+#undef V6481
+#define V6481 (V + 23848)
+ 0x1107, 0x1169, 0x11c0, 0,
+#undef V6482
+#define V6482 (V + 23852)
+ 0x1107, 0x1169, 0x11c1, 0,
+#undef V6483
+#define V6483 (V + 23856)
+ 0x1107, 0x1169, 0x11c2, 0,
+#undef V6484
+#define V6484 (V + 23860)
+ 0x1107, 0x116a, 0,
+#undef V6485
+#define V6485 (V + 23863)
+ 0x1107, 0x116a, 0x11a8, 0,
+#undef V6486
+#define V6486 (V + 23867)
+ 0x1107, 0x116a, 0x11a9, 0,
+#undef V6487
+#define V6487 (V + 23871)
+ 0x1107, 0x116a, 0x11aa, 0,
+#undef V6488
+#define V6488 (V + 23875)
+ 0x1107, 0x116a, 0x11ab, 0,
+#undef V6489
+#define V6489 (V + 23879)
+ 0x1107, 0x116a, 0x11ac, 0,
+#undef V6490
+#define V6490 (V + 23883)
+ 0x1107, 0x116a, 0x11ad, 0,
+#undef V6491
+#define V6491 (V + 23887)
+ 0x1107, 0x116a, 0x11ae, 0,
+#undef V6492
+#define V6492 (V + 23891)
+ 0x1107, 0x116a, 0x11af, 0,
+#undef V6493
+#define V6493 (V + 23895)
+ 0x1107, 0x116a, 0x11b0, 0,
+#undef V6494
+#define V6494 (V + 23899)
+ 0x1107, 0x116a, 0x11b1, 0,
+#undef V6495
+#define V6495 (V + 23903)
+ 0x1107, 0x116a, 0x11b2, 0,
+#undef V6496
+#define V6496 (V + 23907)
+ 0x1107, 0x116a, 0x11b3, 0,
+#undef V6497
+#define V6497 (V + 23911)
+ 0x1107, 0x116a, 0x11b4, 0,
+#undef V6498
+#define V6498 (V + 23915)
+ 0x1107, 0x116a, 0x11b5, 0,
+#undef V6499
+#define V6499 (V + 23919)
+ 0x1107, 0x116a, 0x11b6, 0,
+#undef V6500
+#define V6500 (V + 23923)
+ 0x1107, 0x116a, 0x11b7, 0,
+#undef V6501
+#define V6501 (V + 23927)
+ 0x1107, 0x116a, 0x11b8, 0,
+#undef V6502
+#define V6502 (V + 23931)
+ 0x1107, 0x116a, 0x11b9, 0,
+#undef V6503
+#define V6503 (V + 23935)
+ 0x1107, 0x116a, 0x11ba, 0,
+#undef V6504
+#define V6504 (V + 23939)
+ 0x1107, 0x116a, 0x11bb, 0,
+#undef V6505
+#define V6505 (V + 23943)
+ 0x1107, 0x116a, 0x11bc, 0,
+#undef V6506
+#define V6506 (V + 23947)
+ 0x1107, 0x116a, 0x11bd, 0,
+#undef V6507
+#define V6507 (V + 23951)
+ 0x1107, 0x116a, 0x11be, 0,
+#undef V6508
+#define V6508 (V + 23955)
+ 0x1107, 0x116a, 0x11bf, 0,
+#undef V6509
+#define V6509 (V + 23959)
+ 0x1107, 0x116a, 0x11c0, 0,
+#undef V6510
+#define V6510 (V + 23963)
+ 0x1107, 0x116a, 0x11c1, 0,
+#undef V6511
+#define V6511 (V + 23967)
+ 0x1107, 0x116a, 0x11c2, 0,
+#undef V6512
+#define V6512 (V + 23971)
+ 0x1107, 0x116b, 0,
+#undef V6513
+#define V6513 (V + 23974)
+ 0x1107, 0x116b, 0x11a8, 0,
+#undef V6514
+#define V6514 (V + 23978)
+ 0x1107, 0x116b, 0x11a9, 0,
+#undef V6515
+#define V6515 (V + 23982)
+ 0x1107, 0x116b, 0x11aa, 0,
+#undef V6516
+#define V6516 (V + 23986)
+ 0x1107, 0x116b, 0x11ab, 0,
+#undef V6517
+#define V6517 (V + 23990)
+ 0x1107, 0x116b, 0x11ac, 0,
+#undef V6518
+#define V6518 (V + 23994)
+ 0x1107, 0x116b, 0x11ad, 0,
+#undef V6519
+#define V6519 (V + 23998)
+ 0x1107, 0x116b, 0x11ae, 0,
+#undef V6520
+#define V6520 (V + 24002)
+ 0x1107, 0x116b, 0x11af, 0,
+#undef V6521
+#define V6521 (V + 24006)
+ 0x1107, 0x116b, 0x11b0, 0,
+#undef V6522
+#define V6522 (V + 24010)
+ 0x1107, 0x116b, 0x11b1, 0,
+#undef V6523
+#define V6523 (V + 24014)
+ 0x1107, 0x116b, 0x11b2, 0,
+#undef V6524
+#define V6524 (V + 24018)
+ 0x1107, 0x116b, 0x11b3, 0,
+#undef V6525
+#define V6525 (V + 24022)
+ 0x1107, 0x116b, 0x11b4, 0,
+#undef V6526
+#define V6526 (V + 24026)
+ 0x1107, 0x116b, 0x11b5, 0,
+#undef V6527
+#define V6527 (V + 24030)
+ 0x1107, 0x116b, 0x11b6, 0,
+#undef V6528
+#define V6528 (V + 24034)
+ 0x1107, 0x116b, 0x11b7, 0,
+#undef V6529
+#define V6529 (V + 24038)
+ 0x1107, 0x116b, 0x11b8, 0,
+#undef V6530
+#define V6530 (V + 24042)
+ 0x1107, 0x116b, 0x11b9, 0,
+#undef V6531
+#define V6531 (V + 24046)
+ 0x1107, 0x116b, 0x11ba, 0,
+#undef V6532
+#define V6532 (V + 24050)
+ 0x1107, 0x116b, 0x11bb, 0,
+#undef V6533
+#define V6533 (V + 24054)
+ 0x1107, 0x116b, 0x11bc, 0,
+#undef V6534
+#define V6534 (V + 24058)
+ 0x1107, 0x116b, 0x11bd, 0,
+#undef V6535
+#define V6535 (V + 24062)
+ 0x1107, 0x116b, 0x11be, 0,
+#undef V6536
+#define V6536 (V + 24066)
+ 0x1107, 0x116b, 0x11bf, 0,
+#undef V6537
+#define V6537 (V + 24070)
+ 0x1107, 0x116b, 0x11c0, 0,
+#undef V6538
+#define V6538 (V + 24074)
+ 0x1107, 0x116b, 0x11c1, 0,
+#undef V6539
+#define V6539 (V + 24078)
+ 0x1107, 0x116b, 0x11c2, 0,
+#undef V6540
+#define V6540 (V + 24082)
+ 0x1107, 0x116c, 0,
+#undef V6541
+#define V6541 (V + 24085)
+ 0x1107, 0x116c, 0x11a8, 0,
+#undef V6542
+#define V6542 (V + 24089)
+ 0x1107, 0x116c, 0x11a9, 0,
+#undef V6543
+#define V6543 (V + 24093)
+ 0x1107, 0x116c, 0x11aa, 0,
+#undef V6544
+#define V6544 (V + 24097)
+ 0x1107, 0x116c, 0x11ab, 0,
+#undef V6545
+#define V6545 (V + 24101)
+ 0x1107, 0x116c, 0x11ac, 0,
+#undef V6546
+#define V6546 (V + 24105)
+ 0x1107, 0x116c, 0x11ad, 0,
+#undef V6547
+#define V6547 (V + 24109)
+ 0x1107, 0x116c, 0x11ae, 0,
+#undef V6548
+#define V6548 (V + 24113)
+ 0x1107, 0x116c, 0x11af, 0,
+#undef V6549
+#define V6549 (V + 24117)
+ 0x1107, 0x116c, 0x11b0, 0,
+#undef V6550
+#define V6550 (V + 24121)
+ 0x1107, 0x116c, 0x11b1, 0,
+#undef V6551
+#define V6551 (V + 24125)
+ 0x1107, 0x116c, 0x11b2, 0,
+#undef V6552
+#define V6552 (V + 24129)
+ 0x1107, 0x116c, 0x11b3, 0,
+#undef V6553
+#define V6553 (V + 24133)
+ 0x1107, 0x116c, 0x11b4, 0,
+#undef V6554
+#define V6554 (V + 24137)
+ 0x1107, 0x116c, 0x11b5, 0,
+#undef V6555
+#define V6555 (V + 24141)
+ 0x1107, 0x116c, 0x11b6, 0,
+#undef V6556
+#define V6556 (V + 24145)
+ 0x1107, 0x116c, 0x11b7, 0,
+#undef V6557
+#define V6557 (V + 24149)
+ 0x1107, 0x116c, 0x11b8, 0,
+#undef V6558
+#define V6558 (V + 24153)
+ 0x1107, 0x116c, 0x11b9, 0,
+#undef V6559
+#define V6559 (V + 24157)
+ 0x1107, 0x116c, 0x11ba, 0,
+#undef V6560
+#define V6560 (V + 24161)
+ 0x1107, 0x116c, 0x11bb, 0,
+#undef V6561
+#define V6561 (V + 24165)
+ 0x1107, 0x116c, 0x11bc, 0,
+#undef V6562
+#define V6562 (V + 24169)
+ 0x1107, 0x116c, 0x11bd, 0,
+#undef V6563
+#define V6563 (V + 24173)
+ 0x1107, 0x116c, 0x11be, 0,
+#undef V6564
+#define V6564 (V + 24177)
+ 0x1107, 0x116c, 0x11bf, 0,
+#undef V6565
+#define V6565 (V + 24181)
+ 0x1107, 0x116c, 0x11c0, 0,
+#undef V6566
+#define V6566 (V + 24185)
+ 0x1107, 0x116c, 0x11c1, 0,
+#undef V6567
+#define V6567 (V + 24189)
+ 0x1107, 0x116c, 0x11c2, 0,
+#undef V6568
+#define V6568 (V + 24193)
+ 0x1107, 0x116d, 0,
+#undef V6569
+#define V6569 (V + 24196)
+ 0x1107, 0x116d, 0x11a8, 0,
+#undef V6570
+#define V6570 (V + 24200)
+ 0x1107, 0x116d, 0x11a9, 0,
+#undef V6571
+#define V6571 (V + 24204)
+ 0x1107, 0x116d, 0x11aa, 0,
+#undef V6572
+#define V6572 (V + 24208)
+ 0x1107, 0x116d, 0x11ab, 0,
+#undef V6573
+#define V6573 (V + 24212)
+ 0x1107, 0x116d, 0x11ac, 0,
+#undef V6574
+#define V6574 (V + 24216)
+ 0x1107, 0x116d, 0x11ad, 0,
+#undef V6575
+#define V6575 (V + 24220)
+ 0x1107, 0x116d, 0x11ae, 0,
+#undef V6576
+#define V6576 (V + 24224)
+ 0x1107, 0x116d, 0x11af, 0,
+#undef V6577
+#define V6577 (V + 24228)
+ 0x1107, 0x116d, 0x11b0, 0,
+#undef V6578
+#define V6578 (V + 24232)
+ 0x1107, 0x116d, 0x11b1, 0,
+#undef V6579
+#define V6579 (V + 24236)
+ 0x1107, 0x116d, 0x11b2, 0,
+#undef V6580
+#define V6580 (V + 24240)
+ 0x1107, 0x116d, 0x11b3, 0,
+#undef V6581
+#define V6581 (V + 24244)
+ 0x1107, 0x116d, 0x11b4, 0,
+#undef V6582
+#define V6582 (V + 24248)
+ 0x1107, 0x116d, 0x11b5, 0,
+#undef V6583
+#define V6583 (V + 24252)
+ 0x1107, 0x116d, 0x11b6, 0,
+#undef V6584
+#define V6584 (V + 24256)
+ 0x1107, 0x116d, 0x11b7, 0,
+#undef V6585
+#define V6585 (V + 24260)
+ 0x1107, 0x116d, 0x11b8, 0,
+#undef V6586
+#define V6586 (V + 24264)
+ 0x1107, 0x116d, 0x11b9, 0,
+#undef V6587
+#define V6587 (V + 24268)
+ 0x1107, 0x116d, 0x11ba, 0,
+#undef V6588
+#define V6588 (V + 24272)
+ 0x1107, 0x116d, 0x11bb, 0,
+#undef V6589
+#define V6589 (V + 24276)
+ 0x1107, 0x116d, 0x11bc, 0,
+#undef V6590
+#define V6590 (V + 24280)
+ 0x1107, 0x116d, 0x11bd, 0,
+#undef V6591
+#define V6591 (V + 24284)
+ 0x1107, 0x116d, 0x11be, 0,
+#undef V6592
+#define V6592 (V + 24288)
+ 0x1107, 0x116d, 0x11bf, 0,
+#undef V6593
+#define V6593 (V + 24292)
+ 0x1107, 0x116d, 0x11c0, 0,
+#undef V6594
+#define V6594 (V + 24296)
+ 0x1107, 0x116d, 0x11c1, 0,
+#undef V6595
+#define V6595 (V + 24300)
+ 0x1107, 0x116d, 0x11c2, 0,
+#undef V6596
+#define V6596 (V + 24304)
+ 0x1107, 0x116e, 0,
+#undef V6597
+#define V6597 (V + 24307)
+ 0x1107, 0x116e, 0x11a8, 0,
+#undef V6598
+#define V6598 (V + 24311)
+ 0x1107, 0x116e, 0x11a9, 0,
+#undef V6599
+#define V6599 (V + 24315)
+ 0x1107, 0x116e, 0x11aa, 0,
+#undef V6600
+#define V6600 (V + 24319)
+ 0x1107, 0x116e, 0x11ab, 0,
+#undef V6601
+#define V6601 (V + 24323)
+ 0x1107, 0x116e, 0x11ac, 0,
+#undef V6602
+#define V6602 (V + 24327)
+ 0x1107, 0x116e, 0x11ad, 0,
+#undef V6603
+#define V6603 (V + 24331)
+ 0x1107, 0x116e, 0x11ae, 0,
+#undef V6604
+#define V6604 (V + 24335)
+ 0x1107, 0x116e, 0x11af, 0,
+#undef V6605
+#define V6605 (V + 24339)
+ 0x1107, 0x116e, 0x11b0, 0,
+#undef V6606
+#define V6606 (V + 24343)
+ 0x1107, 0x116e, 0x11b1, 0,
+#undef V6607
+#define V6607 (V + 24347)
+ 0x1107, 0x116e, 0x11b2, 0,
+#undef V6608
+#define V6608 (V + 24351)
+ 0x1107, 0x116e, 0x11b3, 0,
+#undef V6609
+#define V6609 (V + 24355)
+ 0x1107, 0x116e, 0x11b4, 0,
+#undef V6610
+#define V6610 (V + 24359)
+ 0x1107, 0x116e, 0x11b5, 0,
+#undef V6611
+#define V6611 (V + 24363)
+ 0x1107, 0x116e, 0x11b6, 0,
+#undef V6612
+#define V6612 (V + 24367)
+ 0x1107, 0x116e, 0x11b7, 0,
+#undef V6613
+#define V6613 (V + 24371)
+ 0x1107, 0x116e, 0x11b8, 0,
+#undef V6614
+#define V6614 (V + 24375)
+ 0x1107, 0x116e, 0x11b9, 0,
+#undef V6615
+#define V6615 (V + 24379)
+ 0x1107, 0x116e, 0x11ba, 0,
+#undef V6616
+#define V6616 (V + 24383)
+ 0x1107, 0x116e, 0x11bb, 0,
+#undef V6617
+#define V6617 (V + 24387)
+ 0x1107, 0x116e, 0x11bc, 0,
+#undef V6618
+#define V6618 (V + 24391)
+ 0x1107, 0x116e, 0x11bd, 0,
+#undef V6619
+#define V6619 (V + 24395)
+ 0x1107, 0x116e, 0x11be, 0,
+#undef V6620
+#define V6620 (V + 24399)
+ 0x1107, 0x116e, 0x11bf, 0,
+#undef V6621
+#define V6621 (V + 24403)
+ 0x1107, 0x116e, 0x11c0, 0,
+#undef V6622
+#define V6622 (V + 24407)
+ 0x1107, 0x116e, 0x11c1, 0,
+#undef V6623
+#define V6623 (V + 24411)
+ 0x1107, 0x116e, 0x11c2, 0,
+#undef V6624
+#define V6624 (V + 24415)
+ 0x1107, 0x116f, 0,
+#undef V6625
+#define V6625 (V + 24418)
+ 0x1107, 0x116f, 0x11a8, 0,
+#undef V6626
+#define V6626 (V + 24422)
+ 0x1107, 0x116f, 0x11a9, 0,
+#undef V6627
+#define V6627 (V + 24426)
+ 0x1107, 0x116f, 0x11aa, 0,
+#undef V6628
+#define V6628 (V + 24430)
+ 0x1107, 0x116f, 0x11ab, 0,
+#undef V6629
+#define V6629 (V + 24434)
+ 0x1107, 0x116f, 0x11ac, 0,
+#undef V6630
+#define V6630 (V + 24438)
+ 0x1107, 0x116f, 0x11ad, 0,
+#undef V6631
+#define V6631 (V + 24442)
+ 0x1107, 0x116f, 0x11ae, 0,
+#undef V6632
+#define V6632 (V + 24446)
+ 0x1107, 0x116f, 0x11af, 0,
+#undef V6633
+#define V6633 (V + 24450)
+ 0x1107, 0x116f, 0x11b0, 0,
+#undef V6634
+#define V6634 (V + 24454)
+ 0x1107, 0x116f, 0x11b1, 0,
+#undef V6635
+#define V6635 (V + 24458)
+ 0x1107, 0x116f, 0x11b2, 0,
+#undef V6636
+#define V6636 (V + 24462)
+ 0x1107, 0x116f, 0x11b3, 0,
+#undef V6637
+#define V6637 (V + 24466)
+ 0x1107, 0x116f, 0x11b4, 0,
+#undef V6638
+#define V6638 (V + 24470)
+ 0x1107, 0x116f, 0x11b5, 0,
+#undef V6639
+#define V6639 (V + 24474)
+ 0x1107, 0x116f, 0x11b6, 0,
+#undef V6640
+#define V6640 (V + 24478)
+ 0x1107, 0x116f, 0x11b7, 0,
+#undef V6641
+#define V6641 (V + 24482)
+ 0x1107, 0x116f, 0x11b8, 0,
+#undef V6642
+#define V6642 (V + 24486)
+ 0x1107, 0x116f, 0x11b9, 0,
+#undef V6643
+#define V6643 (V + 24490)
+ 0x1107, 0x116f, 0x11ba, 0,
+#undef V6644
+#define V6644 (V + 24494)
+ 0x1107, 0x116f, 0x11bb, 0,
+#undef V6645
+#define V6645 (V + 24498)
+ 0x1107, 0x116f, 0x11bc, 0,
+#undef V6646
+#define V6646 (V + 24502)
+ 0x1107, 0x116f, 0x11bd, 0,
+#undef V6647
+#define V6647 (V + 24506)
+ 0x1107, 0x116f, 0x11be, 0,
+#undef V6648
+#define V6648 (V + 24510)
+ 0x1107, 0x116f, 0x11bf, 0,
+#undef V6649
+#define V6649 (V + 24514)
+ 0x1107, 0x116f, 0x11c0, 0,
+#undef V6650
+#define V6650 (V + 24518)
+ 0x1107, 0x116f, 0x11c1, 0,
+#undef V6651
+#define V6651 (V + 24522)
+ 0x1107, 0x116f, 0x11c2, 0,
+#undef V6652
+#define V6652 (V + 24526)
+ 0x1107, 0x1170, 0,
+#undef V6653
+#define V6653 (V + 24529)
+ 0x1107, 0x1170, 0x11a8, 0,
+#undef V6654
+#define V6654 (V + 24533)
+ 0x1107, 0x1170, 0x11a9, 0,
+#undef V6655
+#define V6655 (V + 24537)
+ 0x1107, 0x1170, 0x11aa, 0,
+#undef V6656
+#define V6656 (V + 24541)
+ 0x1107, 0x1170, 0x11ab, 0,
+#undef V6657
+#define V6657 (V + 24545)
+ 0x1107, 0x1170, 0x11ac, 0,
+#undef V6658
+#define V6658 (V + 24549)
+ 0x1107, 0x1170, 0x11ad, 0,
+#undef V6659
+#define V6659 (V + 24553)
+ 0x1107, 0x1170, 0x11ae, 0,
+#undef V6660
+#define V6660 (V + 24557)
+ 0x1107, 0x1170, 0x11af, 0,
+#undef V6661
+#define V6661 (V + 24561)
+ 0x1107, 0x1170, 0x11b0, 0,
+#undef V6662
+#define V6662 (V + 24565)
+ 0x1107, 0x1170, 0x11b1, 0,
+#undef V6663
+#define V6663 (V + 24569)
+ 0x1107, 0x1170, 0x11b2, 0,
+#undef V6664
+#define V6664 (V + 24573)
+ 0x1107, 0x1170, 0x11b3, 0,
+#undef V6665
+#define V6665 (V + 24577)
+ 0x1107, 0x1170, 0x11b4, 0,
+#undef V6666
+#define V6666 (V + 24581)
+ 0x1107, 0x1170, 0x11b5, 0,
+#undef V6667
+#define V6667 (V + 24585)
+ 0x1107, 0x1170, 0x11b6, 0,
+#undef V6668
+#define V6668 (V + 24589)
+ 0x1107, 0x1170, 0x11b7, 0,
+#undef V6669
+#define V6669 (V + 24593)
+ 0x1107, 0x1170, 0x11b8, 0,
+#undef V6670
+#define V6670 (V + 24597)
+ 0x1107, 0x1170, 0x11b9, 0,
+#undef V6671
+#define V6671 (V + 24601)
+ 0x1107, 0x1170, 0x11ba, 0,
+#undef V6672
+#define V6672 (V + 24605)
+ 0x1107, 0x1170, 0x11bb, 0,
+#undef V6673
+#define V6673 (V + 24609)
+ 0x1107, 0x1170, 0x11bc, 0,
+#undef V6674
+#define V6674 (V + 24613)
+ 0x1107, 0x1170, 0x11bd, 0,
+#undef V6675
+#define V6675 (V + 24617)
+ 0x1107, 0x1170, 0x11be, 0,
+#undef V6676
+#define V6676 (V + 24621)
+ 0x1107, 0x1170, 0x11bf, 0,
+#undef V6677
+#define V6677 (V + 24625)
+ 0x1107, 0x1170, 0x11c0, 0,
+#undef V6678
+#define V6678 (V + 24629)
+ 0x1107, 0x1170, 0x11c1, 0,
+#undef V6679
+#define V6679 (V + 24633)
+ 0x1107, 0x1170, 0x11c2, 0,
+#undef V6680
+#define V6680 (V + 24637)
+ 0x1107, 0x1171, 0,
+#undef V6681
+#define V6681 (V + 24640)
+ 0x1107, 0x1171, 0x11a8, 0,
+#undef V6682
+#define V6682 (V + 24644)
+ 0x1107, 0x1171, 0x11a9, 0,
+#undef V6683
+#define V6683 (V + 24648)
+ 0x1107, 0x1171, 0x11aa, 0,
+#undef V6684
+#define V6684 (V + 24652)
+ 0x1107, 0x1171, 0x11ab, 0,
+#undef V6685
+#define V6685 (V + 24656)
+ 0x1107, 0x1171, 0x11ac, 0,
+#undef V6686
+#define V6686 (V + 24660)
+ 0x1107, 0x1171, 0x11ad, 0,
+#undef V6687
+#define V6687 (V + 24664)
+ 0x1107, 0x1171, 0x11ae, 0,
+#undef V6688
+#define V6688 (V + 24668)
+ 0x1107, 0x1171, 0x11af, 0,
+#undef V6689
+#define V6689 (V + 24672)
+ 0x1107, 0x1171, 0x11b0, 0,
+#undef V6690
+#define V6690 (V + 24676)
+ 0x1107, 0x1171, 0x11b1, 0,
+#undef V6691
+#define V6691 (V + 24680)
+ 0x1107, 0x1171, 0x11b2, 0,
+#undef V6692
+#define V6692 (V + 24684)
+ 0x1107, 0x1171, 0x11b3, 0,
+#undef V6693
+#define V6693 (V + 24688)
+ 0x1107, 0x1171, 0x11b4, 0,
+#undef V6694
+#define V6694 (V + 24692)
+ 0x1107, 0x1171, 0x11b5, 0,
+#undef V6695
+#define V6695 (V + 24696)
+ 0x1107, 0x1171, 0x11b6, 0,
+#undef V6696
+#define V6696 (V + 24700)
+ 0x1107, 0x1171, 0x11b7, 0,
+#undef V6697
+#define V6697 (V + 24704)
+ 0x1107, 0x1171, 0x11b8, 0,
+#undef V6698
+#define V6698 (V + 24708)
+ 0x1107, 0x1171, 0x11b9, 0,
+#undef V6699
+#define V6699 (V + 24712)
+ 0x1107, 0x1171, 0x11ba, 0,
+#undef V6700
+#define V6700 (V + 24716)
+ 0x1107, 0x1171, 0x11bb, 0,
+#undef V6701
+#define V6701 (V + 24720)
+ 0x1107, 0x1171, 0x11bc, 0,
+#undef V6702
+#define V6702 (V + 24724)
+ 0x1107, 0x1171, 0x11bd, 0,
+#undef V6703
+#define V6703 (V + 24728)
+ 0x1107, 0x1171, 0x11be, 0,
+#undef V6704
+#define V6704 (V + 24732)
+ 0x1107, 0x1171, 0x11bf, 0,
+#undef V6705
+#define V6705 (V + 24736)
+ 0x1107, 0x1171, 0x11c0, 0,
+#undef V6706
+#define V6706 (V + 24740)
+ 0x1107, 0x1171, 0x11c1, 0,
+#undef V6707
+#define V6707 (V + 24744)
+ 0x1107, 0x1171, 0x11c2, 0,
+#undef V6708
+#define V6708 (V + 24748)
+ 0x1107, 0x1172, 0,
+#undef V6709
+#define V6709 (V + 24751)
+ 0x1107, 0x1172, 0x11a8, 0,
+#undef V6710
+#define V6710 (V + 24755)
+ 0x1107, 0x1172, 0x11a9, 0,
+#undef V6711
+#define V6711 (V + 24759)
+ 0x1107, 0x1172, 0x11aa, 0,
+#undef V6712
+#define V6712 (V + 24763)
+ 0x1107, 0x1172, 0x11ab, 0,
+#undef V6713
+#define V6713 (V + 24767)
+ 0x1107, 0x1172, 0x11ac, 0,
+#undef V6714
+#define V6714 (V + 24771)
+ 0x1107, 0x1172, 0x11ad, 0,
+#undef V6715
+#define V6715 (V + 24775)
+ 0x1107, 0x1172, 0x11ae, 0,
+#undef V6716
+#define V6716 (V + 24779)
+ 0x1107, 0x1172, 0x11af, 0,
+#undef V6717
+#define V6717 (V + 24783)
+ 0x1107, 0x1172, 0x11b0, 0,
+#undef V6718
+#define V6718 (V + 24787)
+ 0x1107, 0x1172, 0x11b1, 0,
+#undef V6719
+#define V6719 (V + 24791)
+ 0x1107, 0x1172, 0x11b2, 0,
+#undef V6720
+#define V6720 (V + 24795)
+ 0x1107, 0x1172, 0x11b3, 0,
+#undef V6721
+#define V6721 (V + 24799)
+ 0x1107, 0x1172, 0x11b4, 0,
+#undef V6722
+#define V6722 (V + 24803)
+ 0x1107, 0x1172, 0x11b5, 0,
+#undef V6723
+#define V6723 (V + 24807)
+ 0x1107, 0x1172, 0x11b6, 0,
+#undef V6724
+#define V6724 (V + 24811)
+ 0x1107, 0x1172, 0x11b7, 0,
+#undef V6725
+#define V6725 (V + 24815)
+ 0x1107, 0x1172, 0x11b8, 0,
+#undef V6726
+#define V6726 (V + 24819)
+ 0x1107, 0x1172, 0x11b9, 0,
+#undef V6727
+#define V6727 (V + 24823)
+ 0x1107, 0x1172, 0x11ba, 0,
+#undef V6728
+#define V6728 (V + 24827)
+ 0x1107, 0x1172, 0x11bb, 0,
+#undef V6729
+#define V6729 (V + 24831)
+ 0x1107, 0x1172, 0x11bc, 0,
+#undef V6730
+#define V6730 (V + 24835)
+ 0x1107, 0x1172, 0x11bd, 0,
+#undef V6731
+#define V6731 (V + 24839)
+ 0x1107, 0x1172, 0x11be, 0,
+#undef V6732
+#define V6732 (V + 24843)
+ 0x1107, 0x1172, 0x11bf, 0,
+#undef V6733
+#define V6733 (V + 24847)
+ 0x1107, 0x1172, 0x11c0, 0,
+#undef V6734
+#define V6734 (V + 24851)
+ 0x1107, 0x1172, 0x11c1, 0,
+#undef V6735
+#define V6735 (V + 24855)
+ 0x1107, 0x1172, 0x11c2, 0,
+#undef V6736
+#define V6736 (V + 24859)
+ 0x1107, 0x1173, 0,
+#undef V6737
+#define V6737 (V + 24862)
+ 0x1107, 0x1173, 0x11a8, 0,
+#undef V6738
+#define V6738 (V + 24866)
+ 0x1107, 0x1173, 0x11a9, 0,
+#undef V6739
+#define V6739 (V + 24870)
+ 0x1107, 0x1173, 0x11aa, 0,
+#undef V6740
+#define V6740 (V + 24874)
+ 0x1107, 0x1173, 0x11ab, 0,
+#undef V6741
+#define V6741 (V + 24878)
+ 0x1107, 0x1173, 0x11ac, 0,
+#undef V6742
+#define V6742 (V + 24882)
+ 0x1107, 0x1173, 0x11ad, 0,
+#undef V6743
+#define V6743 (V + 24886)
+ 0x1107, 0x1173, 0x11ae, 0,
+#undef V6744
+#define V6744 (V + 24890)
+ 0x1107, 0x1173, 0x11af, 0,
+#undef V6745
+#define V6745 (V + 24894)
+ 0x1107, 0x1173, 0x11b0, 0,
+#undef V6746
+#define V6746 (V + 24898)
+ 0x1107, 0x1173, 0x11b1, 0,
+#undef V6747
+#define V6747 (V + 24902)
+ 0x1107, 0x1173, 0x11b2, 0,
+#undef V6748
+#define V6748 (V + 24906)
+ 0x1107, 0x1173, 0x11b3, 0,
+#undef V6749
+#define V6749 (V + 24910)
+ 0x1107, 0x1173, 0x11b4, 0,
+#undef V6750
+#define V6750 (V + 24914)
+ 0x1107, 0x1173, 0x11b5, 0,
+#undef V6751
+#define V6751 (V + 24918)
+ 0x1107, 0x1173, 0x11b6, 0,
+#undef V6752
+#define V6752 (V + 24922)
+ 0x1107, 0x1173, 0x11b7, 0,
+#undef V6753
+#define V6753 (V + 24926)
+ 0x1107, 0x1173, 0x11b8, 0,
+#undef V6754
+#define V6754 (V + 24930)
+ 0x1107, 0x1173, 0x11b9, 0,
+#undef V6755
+#define V6755 (V + 24934)
+ 0x1107, 0x1173, 0x11ba, 0,
+#undef V6756
+#define V6756 (V + 24938)
+ 0x1107, 0x1173, 0x11bb, 0,
+#undef V6757
+#define V6757 (V + 24942)
+ 0x1107, 0x1173, 0x11bc, 0,
+#undef V6758
+#define V6758 (V + 24946)
+ 0x1107, 0x1173, 0x11bd, 0,
+#undef V6759
+#define V6759 (V + 24950)
+ 0x1107, 0x1173, 0x11be, 0,
+#undef V6760
+#define V6760 (V + 24954)
+ 0x1107, 0x1173, 0x11bf, 0,
+#undef V6761
+#define V6761 (V + 24958)
+ 0x1107, 0x1173, 0x11c0, 0,
+#undef V6762
+#define V6762 (V + 24962)
+ 0x1107, 0x1173, 0x11c1, 0,
+#undef V6763
+#define V6763 (V + 24966)
+ 0x1107, 0x1173, 0x11c2, 0,
+#undef V6764
+#define V6764 (V + 24970)
+ 0x1107, 0x1174, 0,
+#undef V6765
+#define V6765 (V + 24973)
+ 0x1107, 0x1174, 0x11a8, 0,
+#undef V6766
+#define V6766 (V + 24977)
+ 0x1107, 0x1174, 0x11a9, 0,
+#undef V6767
+#define V6767 (V + 24981)
+ 0x1107, 0x1174, 0x11aa, 0,
+#undef V6768
+#define V6768 (V + 24985)
+ 0x1107, 0x1174, 0x11ab, 0,
+#undef V6769
+#define V6769 (V + 24989)
+ 0x1107, 0x1174, 0x11ac, 0,
+#undef V6770
+#define V6770 (V + 24993)
+ 0x1107, 0x1174, 0x11ad, 0,
+#undef V6771
+#define V6771 (V + 24997)
+ 0x1107, 0x1174, 0x11ae, 0,
+#undef V6772
+#define V6772 (V + 25001)
+ 0x1107, 0x1174, 0x11af, 0,
+#undef V6773
+#define V6773 (V + 25005)
+ 0x1107, 0x1174, 0x11b0, 0,
+#undef V6774
+#define V6774 (V + 25009)
+ 0x1107, 0x1174, 0x11b1, 0,
+#undef V6775
+#define V6775 (V + 25013)
+ 0x1107, 0x1174, 0x11b2, 0,
+#undef V6776
+#define V6776 (V + 25017)
+ 0x1107, 0x1174, 0x11b3, 0,
+#undef V6777
+#define V6777 (V + 25021)
+ 0x1107, 0x1174, 0x11b4, 0,
+#undef V6778
+#define V6778 (V + 25025)
+ 0x1107, 0x1174, 0x11b5, 0,
+#undef V6779
+#define V6779 (V + 25029)
+ 0x1107, 0x1174, 0x11b6, 0,
+#undef V6780
+#define V6780 (V + 25033)
+ 0x1107, 0x1174, 0x11b7, 0,
+#undef V6781
+#define V6781 (V + 25037)
+ 0x1107, 0x1174, 0x11b8, 0,
+#undef V6782
+#define V6782 (V + 25041)
+ 0x1107, 0x1174, 0x11b9, 0,
+#undef V6783
+#define V6783 (V + 25045)
+ 0x1107, 0x1174, 0x11ba, 0,
+#undef V6784
+#define V6784 (V + 25049)
+ 0x1107, 0x1174, 0x11bb, 0,
+#undef V6785
+#define V6785 (V + 25053)
+ 0x1107, 0x1174, 0x11bc, 0,
+#undef V6786
+#define V6786 (V + 25057)
+ 0x1107, 0x1174, 0x11bd, 0,
+#undef V6787
+#define V6787 (V + 25061)
+ 0x1107, 0x1174, 0x11be, 0,
+#undef V6788
+#define V6788 (V + 25065)
+ 0x1107, 0x1174, 0x11bf, 0,
+#undef V6789
+#define V6789 (V + 25069)
+ 0x1107, 0x1174, 0x11c0, 0,
+#undef V6790
+#define V6790 (V + 25073)
+ 0x1107, 0x1174, 0x11c1, 0,
+#undef V6791
+#define V6791 (V + 25077)
+ 0x1107, 0x1174, 0x11c2, 0,
+#undef V6792
+#define V6792 (V + 25081)
+ 0x1107, 0x1175, 0,
+#undef V6793
+#define V6793 (V + 25084)
+ 0x1107, 0x1175, 0x11a8, 0,
+#undef V6794
+#define V6794 (V + 25088)
+ 0x1107, 0x1175, 0x11a9, 0,
+#undef V6795
+#define V6795 (V + 25092)
+ 0x1107, 0x1175, 0x11aa, 0,
+#undef V6796
+#define V6796 (V + 25096)
+ 0x1107, 0x1175, 0x11ab, 0,
+#undef V6797
+#define V6797 (V + 25100)
+ 0x1107, 0x1175, 0x11ac, 0,
+#undef V6798
+#define V6798 (V + 25104)
+ 0x1107, 0x1175, 0x11ad, 0,
+#undef V6799
+#define V6799 (V + 25108)
+ 0x1107, 0x1175, 0x11ae, 0,
+#undef V6800
+#define V6800 (V + 25112)
+ 0x1107, 0x1175, 0x11af, 0,
+#undef V6801
+#define V6801 (V + 25116)
+ 0x1107, 0x1175, 0x11b0, 0,
+#undef V6802
+#define V6802 (V + 25120)
+ 0x1107, 0x1175, 0x11b1, 0,
+#undef V6803
+#define V6803 (V + 25124)
+ 0x1107, 0x1175, 0x11b2, 0,
+#undef V6804
+#define V6804 (V + 25128)
+ 0x1107, 0x1175, 0x11b3, 0,
+#undef V6805
+#define V6805 (V + 25132)
+ 0x1107, 0x1175, 0x11b4, 0,
+#undef V6806
+#define V6806 (V + 25136)
+ 0x1107, 0x1175, 0x11b5, 0,
+#undef V6807
+#define V6807 (V + 25140)
+ 0x1107, 0x1175, 0x11b6, 0,
+#undef V6808
+#define V6808 (V + 25144)
+ 0x1107, 0x1175, 0x11b7, 0,
+#undef V6809
+#define V6809 (V + 25148)
+ 0x1107, 0x1175, 0x11b8, 0,
+#undef V6810
+#define V6810 (V + 25152)
+ 0x1107, 0x1175, 0x11b9, 0,
+#undef V6811
+#define V6811 (V + 25156)
+ 0x1107, 0x1175, 0x11ba, 0,
+#undef V6812
+#define V6812 (V + 25160)
+ 0x1107, 0x1175, 0x11bb, 0,
+#undef V6813
+#define V6813 (V + 25164)
+ 0x1107, 0x1175, 0x11bc, 0,
+#undef V6814
+#define V6814 (V + 25168)
+ 0x1107, 0x1175, 0x11bd, 0,
+#undef V6815
+#define V6815 (V + 25172)
+ 0x1107, 0x1175, 0x11be, 0,
+#undef V6816
+#define V6816 (V + 25176)
+ 0x1107, 0x1175, 0x11bf, 0,
+#undef V6817
+#define V6817 (V + 25180)
+ 0x1107, 0x1175, 0x11c0, 0,
+#undef V6818
+#define V6818 (V + 25184)
+ 0x1107, 0x1175, 0x11c1, 0,
+#undef V6819
+#define V6819 (V + 25188)
+ 0x1107, 0x1175, 0x11c2, 0,
+#undef V6820
+#define V6820 (V + 25192)
+ 0x1108, 0x1161, 0,
+#undef V6821
+#define V6821 (V + 25195)
+ 0x1108, 0x1161, 0x11a8, 0,
+#undef V6822
+#define V6822 (V + 25199)
+ 0x1108, 0x1161, 0x11a9, 0,
+#undef V6823
+#define V6823 (V + 25203)
+ 0x1108, 0x1161, 0x11aa, 0,
+#undef V6824
+#define V6824 (V + 25207)
+ 0x1108, 0x1161, 0x11ab, 0,
+#undef V6825
+#define V6825 (V + 25211)
+ 0x1108, 0x1161, 0x11ac, 0,
+#undef V6826
+#define V6826 (V + 25215)
+ 0x1108, 0x1161, 0x11ad, 0,
+#undef V6827
+#define V6827 (V + 25219)
+ 0x1108, 0x1161, 0x11ae, 0,
+#undef V6828
+#define V6828 (V + 25223)
+ 0x1108, 0x1161, 0x11af, 0,
+#undef V6829
+#define V6829 (V + 25227)
+ 0x1108, 0x1161, 0x11b0, 0,
+#undef V6830
+#define V6830 (V + 25231)
+ 0x1108, 0x1161, 0x11b1, 0,
+#undef V6831
+#define V6831 (V + 25235)
+ 0x1108, 0x1161, 0x11b2, 0,
+#undef V6832
+#define V6832 (V + 25239)
+ 0x1108, 0x1161, 0x11b3, 0,
+#undef V6833
+#define V6833 (V + 25243)
+ 0x1108, 0x1161, 0x11b4, 0,
+#undef V6834
+#define V6834 (V + 25247)
+ 0x1108, 0x1161, 0x11b5, 0,
+#undef V6835
+#define V6835 (V + 25251)
+ 0x1108, 0x1161, 0x11b6, 0,
+#undef V6836
+#define V6836 (V + 25255)
+ 0x1108, 0x1161, 0x11b7, 0,
+#undef V6837
+#define V6837 (V + 25259)
+ 0x1108, 0x1161, 0x11b8, 0,
+#undef V6838
+#define V6838 (V + 25263)
+ 0x1108, 0x1161, 0x11b9, 0,
+#undef V6839
+#define V6839 (V + 25267)
+ 0x1108, 0x1161, 0x11ba, 0,
+#undef V6840
+#define V6840 (V + 25271)
+ 0x1108, 0x1161, 0x11bb, 0,
+#undef V6841
+#define V6841 (V + 25275)
+ 0x1108, 0x1161, 0x11bc, 0,
+#undef V6842
+#define V6842 (V + 25279)
+ 0x1108, 0x1161, 0x11bd, 0,
+#undef V6843
+#define V6843 (V + 25283)
+ 0x1108, 0x1161, 0x11be, 0,
+#undef V6844
+#define V6844 (V + 25287)
+ 0x1108, 0x1161, 0x11bf, 0,
+#undef V6845
+#define V6845 (V + 25291)
+ 0x1108, 0x1161, 0x11c0, 0,
+#undef V6846
+#define V6846 (V + 25295)
+ 0x1108, 0x1161, 0x11c1, 0,
+#undef V6847
+#define V6847 (V + 25299)
+ 0x1108, 0x1161, 0x11c2, 0,
+#undef V6848
+#define V6848 (V + 25303)
+ 0x1108, 0x1162, 0,
+#undef V6849
+#define V6849 (V + 25306)
+ 0x1108, 0x1162, 0x11a8, 0,
+#undef V6850
+#define V6850 (V + 25310)
+ 0x1108, 0x1162, 0x11a9, 0,
+#undef V6851
+#define V6851 (V + 25314)
+ 0x1108, 0x1162, 0x11aa, 0,
+#undef V6852
+#define V6852 (V + 25318)
+ 0x1108, 0x1162, 0x11ab, 0,
+#undef V6853
+#define V6853 (V + 25322)
+ 0x1108, 0x1162, 0x11ac, 0,
+#undef V6854
+#define V6854 (V + 25326)
+ 0x1108, 0x1162, 0x11ad, 0,
+#undef V6855
+#define V6855 (V + 25330)
+ 0x1108, 0x1162, 0x11ae, 0,
+#undef V6856
+#define V6856 (V + 25334)
+ 0x1108, 0x1162, 0x11af, 0,
+#undef V6857
+#define V6857 (V + 25338)
+ 0x1108, 0x1162, 0x11b0, 0,
+#undef V6858
+#define V6858 (V + 25342)
+ 0x1108, 0x1162, 0x11b1, 0,
+#undef V6859
+#define V6859 (V + 25346)
+ 0x1108, 0x1162, 0x11b2, 0,
+#undef V6860
+#define V6860 (V + 25350)
+ 0x1108, 0x1162, 0x11b3, 0,
+#undef V6861
+#define V6861 (V + 25354)
+ 0x1108, 0x1162, 0x11b4, 0,
+#undef V6862
+#define V6862 (V + 25358)
+ 0x1108, 0x1162, 0x11b5, 0,
+#undef V6863
+#define V6863 (V + 25362)
+ 0x1108, 0x1162, 0x11b6, 0,
+#undef V6864
+#define V6864 (V + 25366)
+ 0x1108, 0x1162, 0x11b7, 0,
+#undef V6865
+#define V6865 (V + 25370)
+ 0x1108, 0x1162, 0x11b8, 0,
+#undef V6866
+#define V6866 (V + 25374)
+ 0x1108, 0x1162, 0x11b9, 0,
+#undef V6867
+#define V6867 (V + 25378)
+ 0x1108, 0x1162, 0x11ba, 0,
+#undef V6868
+#define V6868 (V + 25382)
+ 0x1108, 0x1162, 0x11bb, 0,
+#undef V6869
+#define V6869 (V + 25386)
+ 0x1108, 0x1162, 0x11bc, 0,
+#undef V6870
+#define V6870 (V + 25390)
+ 0x1108, 0x1162, 0x11bd, 0,
+#undef V6871
+#define V6871 (V + 25394)
+ 0x1108, 0x1162, 0x11be, 0,
+#undef V6872
+#define V6872 (V + 25398)
+ 0x1108, 0x1162, 0x11bf, 0,
+#undef V6873
+#define V6873 (V + 25402)
+ 0x1108, 0x1162, 0x11c0, 0,
+#undef V6874
+#define V6874 (V + 25406)
+ 0x1108, 0x1162, 0x11c1, 0,
+#undef V6875
+#define V6875 (V + 25410)
+ 0x1108, 0x1162, 0x11c2, 0,
+#undef V6876
+#define V6876 (V + 25414)
+ 0x1108, 0x1163, 0,
+#undef V6877
+#define V6877 (V + 25417)
+ 0x1108, 0x1163, 0x11a8, 0,
+#undef V6878
+#define V6878 (V + 25421)
+ 0x1108, 0x1163, 0x11a9, 0,
+#undef V6879
+#define V6879 (V + 25425)
+ 0x1108, 0x1163, 0x11aa, 0,
+#undef V6880
+#define V6880 (V + 25429)
+ 0x1108, 0x1163, 0x11ab, 0,
+#undef V6881
+#define V6881 (V + 25433)
+ 0x1108, 0x1163, 0x11ac, 0,
+#undef V6882
+#define V6882 (V + 25437)
+ 0x1108, 0x1163, 0x11ad, 0,
+#undef V6883
+#define V6883 (V + 25441)
+ 0x1108, 0x1163, 0x11ae, 0,
+#undef V6884
+#define V6884 (V + 25445)
+ 0x1108, 0x1163, 0x11af, 0,
+#undef V6885
+#define V6885 (V + 25449)
+ 0x1108, 0x1163, 0x11b0, 0,
+#undef V6886
+#define V6886 (V + 25453)
+ 0x1108, 0x1163, 0x11b1, 0,
+#undef V6887
+#define V6887 (V + 25457)
+ 0x1108, 0x1163, 0x11b2, 0,
+#undef V6888
+#define V6888 (V + 25461)
+ 0x1108, 0x1163, 0x11b3, 0,
+#undef V6889
+#define V6889 (V + 25465)
+ 0x1108, 0x1163, 0x11b4, 0,
+#undef V6890
+#define V6890 (V + 25469)
+ 0x1108, 0x1163, 0x11b5, 0,
+#undef V6891
+#define V6891 (V + 25473)
+ 0x1108, 0x1163, 0x11b6, 0,
+#undef V6892
+#define V6892 (V + 25477)
+ 0x1108, 0x1163, 0x11b7, 0,
+#undef V6893
+#define V6893 (V + 25481)
+ 0x1108, 0x1163, 0x11b8, 0,
+#undef V6894
+#define V6894 (V + 25485)
+ 0x1108, 0x1163, 0x11b9, 0,
+#undef V6895
+#define V6895 (V + 25489)
+ 0x1108, 0x1163, 0x11ba, 0,
+#undef V6896
+#define V6896 (V + 25493)
+ 0x1108, 0x1163, 0x11bb, 0,
+#undef V6897
+#define V6897 (V + 25497)
+ 0x1108, 0x1163, 0x11bc, 0,
+#undef V6898
+#define V6898 (V + 25501)
+ 0x1108, 0x1163, 0x11bd, 0,
+#undef V6899
+#define V6899 (V + 25505)
+ 0x1108, 0x1163, 0x11be, 0,
+#undef V6900
+#define V6900 (V + 25509)
+ 0x1108, 0x1163, 0x11bf, 0,
+#undef V6901
+#define V6901 (V + 25513)
+ 0x1108, 0x1163, 0x11c0, 0,
+#undef V6902
+#define V6902 (V + 25517)
+ 0x1108, 0x1163, 0x11c1, 0,
+#undef V6903
+#define V6903 (V + 25521)
+ 0x1108, 0x1163, 0x11c2, 0,
+#undef V6904
+#define V6904 (V + 25525)
+ 0x1108, 0x1164, 0,
+#undef V6905
+#define V6905 (V + 25528)
+ 0x1108, 0x1164, 0x11a8, 0,
+#undef V6906
+#define V6906 (V + 25532)
+ 0x1108, 0x1164, 0x11a9, 0,
+#undef V6907
+#define V6907 (V + 25536)
+ 0x1108, 0x1164, 0x11aa, 0,
+#undef V6908
+#define V6908 (V + 25540)
+ 0x1108, 0x1164, 0x11ab, 0,
+#undef V6909
+#define V6909 (V + 25544)
+ 0x1108, 0x1164, 0x11ac, 0,
+#undef V6910
+#define V6910 (V + 25548)
+ 0x1108, 0x1164, 0x11ad, 0,
+#undef V6911
+#define V6911 (V + 25552)
+ 0x1108, 0x1164, 0x11ae, 0,
+#undef V6912
+#define V6912 (V + 25556)
+ 0x1108, 0x1164, 0x11af, 0,
+#undef V6913
+#define V6913 (V + 25560)
+ 0x1108, 0x1164, 0x11b0, 0,
+#undef V6914
+#define V6914 (V + 25564)
+ 0x1108, 0x1164, 0x11b1, 0,
+#undef V6915
+#define V6915 (V + 25568)
+ 0x1108, 0x1164, 0x11b2, 0,
+#undef V6916
+#define V6916 (V + 25572)
+ 0x1108, 0x1164, 0x11b3, 0,
+#undef V6917
+#define V6917 (V + 25576)
+ 0x1108, 0x1164, 0x11b4, 0,
+#undef V6918
+#define V6918 (V + 25580)
+ 0x1108, 0x1164, 0x11b5, 0,
+#undef V6919
+#define V6919 (V + 25584)
+ 0x1108, 0x1164, 0x11b6, 0,
+#undef V6920
+#define V6920 (V + 25588)
+ 0x1108, 0x1164, 0x11b7, 0,
+#undef V6921
+#define V6921 (V + 25592)
+ 0x1108, 0x1164, 0x11b8, 0,
+#undef V6922
+#define V6922 (V + 25596)
+ 0x1108, 0x1164, 0x11b9, 0,
+#undef V6923
+#define V6923 (V + 25600)
+ 0x1108, 0x1164, 0x11ba, 0,
+#undef V6924
+#define V6924 (V + 25604)
+ 0x1108, 0x1164, 0x11bb, 0,
+#undef V6925
+#define V6925 (V + 25608)
+ 0x1108, 0x1164, 0x11bc, 0,
+#undef V6926
+#define V6926 (V + 25612)
+ 0x1108, 0x1164, 0x11bd, 0,
+#undef V6927
+#define V6927 (V + 25616)
+ 0x1108, 0x1164, 0x11be, 0,
+#undef V6928
+#define V6928 (V + 25620)
+ 0x1108, 0x1164, 0x11bf, 0,
+#undef V6929
+#define V6929 (V + 25624)
+ 0x1108, 0x1164, 0x11c0, 0,
+#undef V6930
+#define V6930 (V + 25628)
+ 0x1108, 0x1164, 0x11c1, 0,
+#undef V6931
+#define V6931 (V + 25632)
+ 0x1108, 0x1164, 0x11c2, 0,
+#undef V6932
+#define V6932 (V + 25636)
+ 0x1108, 0x1165, 0,
+#undef V6933
+#define V6933 (V + 25639)
+ 0x1108, 0x1165, 0x11a8, 0,
+#undef V6934
+#define V6934 (V + 25643)
+ 0x1108, 0x1165, 0x11a9, 0,
+#undef V6935
+#define V6935 (V + 25647)
+ 0x1108, 0x1165, 0x11aa, 0,
+#undef V6936
+#define V6936 (V + 25651)
+ 0x1108, 0x1165, 0x11ab, 0,
+#undef V6937
+#define V6937 (V + 25655)
+ 0x1108, 0x1165, 0x11ac, 0,
+#undef V6938
+#define V6938 (V + 25659)
+ 0x1108, 0x1165, 0x11ad, 0,
+#undef V6939
+#define V6939 (V + 25663)
+ 0x1108, 0x1165, 0x11ae, 0,
+#undef V6940
+#define V6940 (V + 25667)
+ 0x1108, 0x1165, 0x11af, 0,
+#undef V6941
+#define V6941 (V + 25671)
+ 0x1108, 0x1165, 0x11b0, 0,
+#undef V6942
+#define V6942 (V + 25675)
+ 0x1108, 0x1165, 0x11b1, 0,
+#undef V6943
+#define V6943 (V + 25679)
+ 0x1108, 0x1165, 0x11b2, 0,
+#undef V6944
+#define V6944 (V + 25683)
+ 0x1108, 0x1165, 0x11b3, 0,
+#undef V6945
+#define V6945 (V + 25687)
+ 0x1108, 0x1165, 0x11b4, 0,
+#undef V6946
+#define V6946 (V + 25691)
+ 0x1108, 0x1165, 0x11b5, 0,
+#undef V6947
+#define V6947 (V + 25695)
+ 0x1108, 0x1165, 0x11b6, 0,
+#undef V6948
+#define V6948 (V + 25699)
+ 0x1108, 0x1165, 0x11b7, 0,
+#undef V6949
+#define V6949 (V + 25703)
+ 0x1108, 0x1165, 0x11b8, 0,
+#undef V6950
+#define V6950 (V + 25707)
+ 0x1108, 0x1165, 0x11b9, 0,
+#undef V6951
+#define V6951 (V + 25711)
+ 0x1108, 0x1165, 0x11ba, 0,
+#undef V6952
+#define V6952 (V + 25715)
+ 0x1108, 0x1165, 0x11bb, 0,
+#undef V6953
+#define V6953 (V + 25719)
+ 0x1108, 0x1165, 0x11bc, 0,
+#undef V6954
+#define V6954 (V + 25723)
+ 0x1108, 0x1165, 0x11bd, 0,
+#undef V6955
+#define V6955 (V + 25727)
+ 0x1108, 0x1165, 0x11be, 0,
+#undef V6956
+#define V6956 (V + 25731)
+ 0x1108, 0x1165, 0x11bf, 0,
+#undef V6957
+#define V6957 (V + 25735)
+ 0x1108, 0x1165, 0x11c0, 0,
+#undef V6958
+#define V6958 (V + 25739)
+ 0x1108, 0x1165, 0x11c1, 0,
+#undef V6959
+#define V6959 (V + 25743)
+ 0x1108, 0x1165, 0x11c2, 0,
+#undef V6960
+#define V6960 (V + 25747)
+ 0x1108, 0x1166, 0,
+#undef V6961
+#define V6961 (V + 25750)
+ 0x1108, 0x1166, 0x11a8, 0,
+#undef V6962
+#define V6962 (V + 25754)
+ 0x1108, 0x1166, 0x11a9, 0,
+#undef V6963
+#define V6963 (V + 25758)
+ 0x1108, 0x1166, 0x11aa, 0,
+#undef V6964
+#define V6964 (V + 25762)
+ 0x1108, 0x1166, 0x11ab, 0,
+#undef V6965
+#define V6965 (V + 25766)
+ 0x1108, 0x1166, 0x11ac, 0,
+#undef V6966
+#define V6966 (V + 25770)
+ 0x1108, 0x1166, 0x11ad, 0,
+#undef V6967
+#define V6967 (V + 25774)
+ 0x1108, 0x1166, 0x11ae, 0,
+#undef V6968
+#define V6968 (V + 25778)
+ 0x1108, 0x1166, 0x11af, 0,
+#undef V6969
+#define V6969 (V + 25782)
+ 0x1108, 0x1166, 0x11b0, 0,
+#undef V6970
+#define V6970 (V + 25786)
+ 0x1108, 0x1166, 0x11b1, 0,
+#undef V6971
+#define V6971 (V + 25790)
+ 0x1108, 0x1166, 0x11b2, 0,
+#undef V6972
+#define V6972 (V + 25794)
+ 0x1108, 0x1166, 0x11b3, 0,
+#undef V6973
+#define V6973 (V + 25798)
+ 0x1108, 0x1166, 0x11b4, 0,
+#undef V6974
+#define V6974 (V + 25802)
+ 0x1108, 0x1166, 0x11b5, 0,
+#undef V6975
+#define V6975 (V + 25806)
+ 0x1108, 0x1166, 0x11b6, 0,
+#undef V6976
+#define V6976 (V + 25810)
+ 0x1108, 0x1166, 0x11b7, 0,
+#undef V6977
+#define V6977 (V + 25814)
+ 0x1108, 0x1166, 0x11b8, 0,
+#undef V6978
+#define V6978 (V + 25818)
+ 0x1108, 0x1166, 0x11b9, 0,
+#undef V6979
+#define V6979 (V + 25822)
+ 0x1108, 0x1166, 0x11ba, 0,
+#undef V6980
+#define V6980 (V + 25826)
+ 0x1108, 0x1166, 0x11bb, 0,
+#undef V6981
+#define V6981 (V + 25830)
+ 0x1108, 0x1166, 0x11bc, 0,
+#undef V6982
+#define V6982 (V + 25834)
+ 0x1108, 0x1166, 0x11bd, 0,
+#undef V6983
+#define V6983 (V + 25838)
+ 0x1108, 0x1166, 0x11be, 0,
+#undef V6984
+#define V6984 (V + 25842)
+ 0x1108, 0x1166, 0x11bf, 0,
+#undef V6985
+#define V6985 (V + 25846)
+ 0x1108, 0x1166, 0x11c0, 0,
+#undef V6986
+#define V6986 (V + 25850)
+ 0x1108, 0x1166, 0x11c1, 0,
+#undef V6987
+#define V6987 (V + 25854)
+ 0x1108, 0x1166, 0x11c2, 0,
+#undef V6988
+#define V6988 (V + 25858)
+ 0x1108, 0x1167, 0,
+#undef V6989
+#define V6989 (V + 25861)
+ 0x1108, 0x1167, 0x11a8, 0,
+#undef V6990
+#define V6990 (V + 25865)
+ 0x1108, 0x1167, 0x11a9, 0,
+#undef V6991
+#define V6991 (V + 25869)
+ 0x1108, 0x1167, 0x11aa, 0,
+#undef V6992
+#define V6992 (V + 25873)
+ 0x1108, 0x1167, 0x11ab, 0,
+#undef V6993
+#define V6993 (V + 25877)
+ 0x1108, 0x1167, 0x11ac, 0,
+#undef V6994
+#define V6994 (V + 25881)
+ 0x1108, 0x1167, 0x11ad, 0,
+#undef V6995
+#define V6995 (V + 25885)
+ 0x1108, 0x1167, 0x11ae, 0,
+#undef V6996
+#define V6996 (V + 25889)
+ 0x1108, 0x1167, 0x11af, 0,
+#undef V6997
+#define V6997 (V + 25893)
+ 0x1108, 0x1167, 0x11b0, 0,
+#undef V6998
+#define V6998 (V + 25897)
+ 0x1108, 0x1167, 0x11b1, 0,
+#undef V6999
+#define V6999 (V + 25901)
+ 0x1108, 0x1167, 0x11b2, 0,
+#undef V7000
+#define V7000 (V + 25905)
+ 0x1108, 0x1167, 0x11b3, 0,
+#undef V7001
+#define V7001 (V + 25909)
+ 0x1108, 0x1167, 0x11b4, 0,
+#undef V7002
+#define V7002 (V + 25913)
+ 0x1108, 0x1167, 0x11b5, 0,
+#undef V7003
+#define V7003 (V + 25917)
+ 0x1108, 0x1167, 0x11b6, 0,
+#undef V7004
+#define V7004 (V + 25921)
+ 0x1108, 0x1167, 0x11b7, 0,
+#undef V7005
+#define V7005 (V + 25925)
+ 0x1108, 0x1167, 0x11b8, 0,
+#undef V7006
+#define V7006 (V + 25929)
+ 0x1108, 0x1167, 0x11b9, 0,
+#undef V7007
+#define V7007 (V + 25933)
+ 0x1108, 0x1167, 0x11ba, 0,
+#undef V7008
+#define V7008 (V + 25937)
+ 0x1108, 0x1167, 0x11bb, 0,
+#undef V7009
+#define V7009 (V + 25941)
+ 0x1108, 0x1167, 0x11bc, 0,
+#undef V7010
+#define V7010 (V + 25945)
+ 0x1108, 0x1167, 0x11bd, 0,
+#undef V7011
+#define V7011 (V + 25949)
+ 0x1108, 0x1167, 0x11be, 0,
+#undef V7012
+#define V7012 (V + 25953)
+ 0x1108, 0x1167, 0x11bf, 0,
+#undef V7013
+#define V7013 (V + 25957)
+ 0x1108, 0x1167, 0x11c0, 0,
+#undef V7014
+#define V7014 (V + 25961)
+ 0x1108, 0x1167, 0x11c1, 0,
+#undef V7015
+#define V7015 (V + 25965)
+ 0x1108, 0x1167, 0x11c2, 0,
+#undef V7016
+#define V7016 (V + 25969)
+ 0x1108, 0x1168, 0,
+#undef V7017
+#define V7017 (V + 25972)
+ 0x1108, 0x1168, 0x11a8, 0,
+#undef V7018
+#define V7018 (V + 25976)
+ 0x1108, 0x1168, 0x11a9, 0,
+#undef V7019
+#define V7019 (V + 25980)
+ 0x1108, 0x1168, 0x11aa, 0,
+#undef V7020
+#define V7020 (V + 25984)
+ 0x1108, 0x1168, 0x11ab, 0,
+#undef V7021
+#define V7021 (V + 25988)
+ 0x1108, 0x1168, 0x11ac, 0,
+#undef V7022
+#define V7022 (V + 25992)
+ 0x1108, 0x1168, 0x11ad, 0,
+#undef V7023
+#define V7023 (V + 25996)
+ 0x1108, 0x1168, 0x11ae, 0,
+#undef V7024
+#define V7024 (V + 26000)
+ 0x1108, 0x1168, 0x11af, 0,
+#undef V7025
+#define V7025 (V + 26004)
+ 0x1108, 0x1168, 0x11b0, 0,
+#undef V7026
+#define V7026 (V + 26008)
+ 0x1108, 0x1168, 0x11b1, 0,
+#undef V7027
+#define V7027 (V + 26012)
+ 0x1108, 0x1168, 0x11b2, 0,
+#undef V7028
+#define V7028 (V + 26016)
+ 0x1108, 0x1168, 0x11b3, 0,
+#undef V7029
+#define V7029 (V + 26020)
+ 0x1108, 0x1168, 0x11b4, 0,
+#undef V7030
+#define V7030 (V + 26024)
+ 0x1108, 0x1168, 0x11b5, 0,
+#undef V7031
+#define V7031 (V + 26028)
+ 0x1108, 0x1168, 0x11b6, 0,
+#undef V7032
+#define V7032 (V + 26032)
+ 0x1108, 0x1168, 0x11b7, 0,
+#undef V7033
+#define V7033 (V + 26036)
+ 0x1108, 0x1168, 0x11b8, 0,
+#undef V7034
+#define V7034 (V + 26040)
+ 0x1108, 0x1168, 0x11b9, 0,
+#undef V7035
+#define V7035 (V + 26044)
+ 0x1108, 0x1168, 0x11ba, 0,
+#undef V7036
+#define V7036 (V + 26048)
+ 0x1108, 0x1168, 0x11bb, 0,
+#undef V7037
+#define V7037 (V + 26052)
+ 0x1108, 0x1168, 0x11bc, 0,
+#undef V7038
+#define V7038 (V + 26056)
+ 0x1108, 0x1168, 0x11bd, 0,
+#undef V7039
+#define V7039 (V + 26060)
+ 0x1108, 0x1168, 0x11be, 0,
+#undef V7040
+#define V7040 (V + 26064)
+ 0x1108, 0x1168, 0x11bf, 0,
+#undef V7041
+#define V7041 (V + 26068)
+ 0x1108, 0x1168, 0x11c0, 0,
+#undef V7042
+#define V7042 (V + 26072)
+ 0x1108, 0x1168, 0x11c1, 0,
+#undef V7043
+#define V7043 (V + 26076)
+ 0x1108, 0x1168, 0x11c2, 0,
+#undef V7044
+#define V7044 (V + 26080)
+ 0x1108, 0x1169, 0,
+#undef V7045
+#define V7045 (V + 26083)
+ 0x1108, 0x1169, 0x11a8, 0,
+#undef V7046
+#define V7046 (V + 26087)
+ 0x1108, 0x1169, 0x11a9, 0,
+#undef V7047
+#define V7047 (V + 26091)
+ 0x1108, 0x1169, 0x11aa, 0,
+#undef V7048
+#define V7048 (V + 26095)
+ 0x1108, 0x1169, 0x11ab, 0,
+#undef V7049
+#define V7049 (V + 26099)
+ 0x1108, 0x1169, 0x11ac, 0,
+#undef V7050
+#define V7050 (V + 26103)
+ 0x1108, 0x1169, 0x11ad, 0,
+#undef V7051
+#define V7051 (V + 26107)
+ 0x1108, 0x1169, 0x11ae, 0,
+#undef V7052
+#define V7052 (V + 26111)
+ 0x1108, 0x1169, 0x11af, 0,
+#undef V7053
+#define V7053 (V + 26115)
+ 0x1108, 0x1169, 0x11b0, 0,
+#undef V7054
+#define V7054 (V + 26119)
+ 0x1108, 0x1169, 0x11b1, 0,
+#undef V7055
+#define V7055 (V + 26123)
+ 0x1108, 0x1169, 0x11b2, 0,
+#undef V7056
+#define V7056 (V + 26127)
+ 0x1108, 0x1169, 0x11b3, 0,
+#undef V7057
+#define V7057 (V + 26131)
+ 0x1108, 0x1169, 0x11b4, 0,
+#undef V7058
+#define V7058 (V + 26135)
+ 0x1108, 0x1169, 0x11b5, 0,
+#undef V7059
+#define V7059 (V + 26139)
+ 0x1108, 0x1169, 0x11b6, 0,
+#undef V7060
+#define V7060 (V + 26143)
+ 0x1108, 0x1169, 0x11b7, 0,
+#undef V7061
+#define V7061 (V + 26147)
+ 0x1108, 0x1169, 0x11b8, 0,
+#undef V7062
+#define V7062 (V + 26151)
+ 0x1108, 0x1169, 0x11b9, 0,
+#undef V7063
+#define V7063 (V + 26155)
+ 0x1108, 0x1169, 0x11ba, 0,
+#undef V7064
+#define V7064 (V + 26159)
+ 0x1108, 0x1169, 0x11bb, 0,
+#undef V7065
+#define V7065 (V + 26163)
+ 0x1108, 0x1169, 0x11bc, 0,
+#undef V7066
+#define V7066 (V + 26167)
+ 0x1108, 0x1169, 0x11bd, 0,
+#undef V7067
+#define V7067 (V + 26171)
+ 0x1108, 0x1169, 0x11be, 0,
+#undef V7068
+#define V7068 (V + 26175)
+ 0x1108, 0x1169, 0x11bf, 0,
+#undef V7069
+#define V7069 (V + 26179)
+ 0x1108, 0x1169, 0x11c0, 0,
+#undef V7070
+#define V7070 (V + 26183)
+ 0x1108, 0x1169, 0x11c1, 0,
+#undef V7071
+#define V7071 (V + 26187)
+ 0x1108, 0x1169, 0x11c2, 0,
+#undef V7072
+#define V7072 (V + 26191)
+ 0x1108, 0x116a, 0,
+#undef V7073
+#define V7073 (V + 26194)
+ 0x1108, 0x116a, 0x11a8, 0,
+#undef V7074
+#define V7074 (V + 26198)
+ 0x1108, 0x116a, 0x11a9, 0,
+#undef V7075
+#define V7075 (V + 26202)
+ 0x1108, 0x116a, 0x11aa, 0,
+#undef V7076
+#define V7076 (V + 26206)
+ 0x1108, 0x116a, 0x11ab, 0,
+#undef V7077
+#define V7077 (V + 26210)
+ 0x1108, 0x116a, 0x11ac, 0,
+#undef V7078
+#define V7078 (V + 26214)
+ 0x1108, 0x116a, 0x11ad, 0,
+#undef V7079
+#define V7079 (V + 26218)
+ 0x1108, 0x116a, 0x11ae, 0,
+#undef V7080
+#define V7080 (V + 26222)
+ 0x1108, 0x116a, 0x11af, 0,
+#undef V7081
+#define V7081 (V + 26226)
+ 0x1108, 0x116a, 0x11b0, 0,
+#undef V7082
+#define V7082 (V + 26230)
+ 0x1108, 0x116a, 0x11b1, 0,
+#undef V7083
+#define V7083 (V + 26234)
+ 0x1108, 0x116a, 0x11b2, 0,
+#undef V7084
+#define V7084 (V + 26238)
+ 0x1108, 0x116a, 0x11b3, 0,
+#undef V7085
+#define V7085 (V + 26242)
+ 0x1108, 0x116a, 0x11b4, 0,
+#undef V7086
+#define V7086 (V + 26246)
+ 0x1108, 0x116a, 0x11b5, 0,
+#undef V7087
+#define V7087 (V + 26250)
+ 0x1108, 0x116a, 0x11b6, 0,
+#undef V7088
+#define V7088 (V + 26254)
+ 0x1108, 0x116a, 0x11b7, 0,
+#undef V7089
+#define V7089 (V + 26258)
+ 0x1108, 0x116a, 0x11b8, 0,
+#undef V7090
+#define V7090 (V + 26262)
+ 0x1108, 0x116a, 0x11b9, 0,
+#undef V7091
+#define V7091 (V + 26266)
+ 0x1108, 0x116a, 0x11ba, 0,
+#undef V7092
+#define V7092 (V + 26270)
+ 0x1108, 0x116a, 0x11bb, 0,
+#undef V7093
+#define V7093 (V + 26274)
+ 0x1108, 0x116a, 0x11bc, 0,
+#undef V7094
+#define V7094 (V + 26278)
+ 0x1108, 0x116a, 0x11bd, 0,
+#undef V7095
+#define V7095 (V + 26282)
+ 0x1108, 0x116a, 0x11be, 0,
+#undef V7096
+#define V7096 (V + 26286)
+ 0x1108, 0x116a, 0x11bf, 0,
+#undef V7097
+#define V7097 (V + 26290)
+ 0x1108, 0x116a, 0x11c0, 0,
+#undef V7098
+#define V7098 (V + 26294)
+ 0x1108, 0x116a, 0x11c1, 0,
+#undef V7099
+#define V7099 (V + 26298)
+ 0x1108, 0x116a, 0x11c2, 0,
+#undef V7100
+#define V7100 (V + 26302)
+ 0x1108, 0x116b, 0,
+#undef V7101
+#define V7101 (V + 26305)
+ 0x1108, 0x116b, 0x11a8, 0,
+#undef V7102
+#define V7102 (V + 26309)
+ 0x1108, 0x116b, 0x11a9, 0,
+#undef V7103
+#define V7103 (V + 26313)
+ 0x1108, 0x116b, 0x11aa, 0,
+#undef V7104
+#define V7104 (V + 26317)
+ 0x1108, 0x116b, 0x11ab, 0,
+#undef V7105
+#define V7105 (V + 26321)
+ 0x1108, 0x116b, 0x11ac, 0,
+#undef V7106
+#define V7106 (V + 26325)
+ 0x1108, 0x116b, 0x11ad, 0,
+#undef V7107
+#define V7107 (V + 26329)
+ 0x1108, 0x116b, 0x11ae, 0,
+#undef V7108
+#define V7108 (V + 26333)
+ 0x1108, 0x116b, 0x11af, 0,
+#undef V7109
+#define V7109 (V + 26337)
+ 0x1108, 0x116b, 0x11b0, 0,
+#undef V7110
+#define V7110 (V + 26341)
+ 0x1108, 0x116b, 0x11b1, 0,
+#undef V7111
+#define V7111 (V + 26345)
+ 0x1108, 0x116b, 0x11b2, 0,
+#undef V7112
+#define V7112 (V + 26349)
+ 0x1108, 0x116b, 0x11b3, 0,
+#undef V7113
+#define V7113 (V + 26353)
+ 0x1108, 0x116b, 0x11b4, 0,
+#undef V7114
+#define V7114 (V + 26357)
+ 0x1108, 0x116b, 0x11b5, 0,
+#undef V7115
+#define V7115 (V + 26361)
+ 0x1108, 0x116b, 0x11b6, 0,
+#undef V7116
+#define V7116 (V + 26365)
+ 0x1108, 0x116b, 0x11b7, 0,
+#undef V7117
+#define V7117 (V + 26369)
+ 0x1108, 0x116b, 0x11b8, 0,
+#undef V7118
+#define V7118 (V + 26373)
+ 0x1108, 0x116b, 0x11b9, 0,
+#undef V7119
+#define V7119 (V + 26377)
+ 0x1108, 0x116b, 0x11ba, 0,
+#undef V7120
+#define V7120 (V + 26381)
+ 0x1108, 0x116b, 0x11bb, 0,
+#undef V7121
+#define V7121 (V + 26385)
+ 0x1108, 0x116b, 0x11bc, 0,
+#undef V7122
+#define V7122 (V + 26389)
+ 0x1108, 0x116b, 0x11bd, 0,
+#undef V7123
+#define V7123 (V + 26393)
+ 0x1108, 0x116b, 0x11be, 0,
+#undef V7124
+#define V7124 (V + 26397)
+ 0x1108, 0x116b, 0x11bf, 0,
+#undef V7125
+#define V7125 (V + 26401)
+ 0x1108, 0x116b, 0x11c0, 0,
+#undef V7126
+#define V7126 (V + 26405)
+ 0x1108, 0x116b, 0x11c1, 0,
+#undef V7127
+#define V7127 (V + 26409)
+ 0x1108, 0x116b, 0x11c2, 0,
+#undef V7128
+#define V7128 (V + 26413)
+ 0x1108, 0x116c, 0,
+#undef V7129
+#define V7129 (V + 26416)
+ 0x1108, 0x116c, 0x11a8, 0,
+#undef V7130
+#define V7130 (V + 26420)
+ 0x1108, 0x116c, 0x11a9, 0,
+#undef V7131
+#define V7131 (V + 26424)
+ 0x1108, 0x116c, 0x11aa, 0,
+#undef V7132
+#define V7132 (V + 26428)
+ 0x1108, 0x116c, 0x11ab, 0,
+#undef V7133
+#define V7133 (V + 26432)
+ 0x1108, 0x116c, 0x11ac, 0,
+#undef V7134
+#define V7134 (V + 26436)
+ 0x1108, 0x116c, 0x11ad, 0,
+#undef V7135
+#define V7135 (V + 26440)
+ 0x1108, 0x116c, 0x11ae, 0,
+#undef V7136
+#define V7136 (V + 26444)
+ 0x1108, 0x116c, 0x11af, 0,
+#undef V7137
+#define V7137 (V + 26448)
+ 0x1108, 0x116c, 0x11b0, 0,
+#undef V7138
+#define V7138 (V + 26452)
+ 0x1108, 0x116c, 0x11b1, 0,
+#undef V7139
+#define V7139 (V + 26456)
+ 0x1108, 0x116c, 0x11b2, 0,
+#undef V7140
+#define V7140 (V + 26460)
+ 0x1108, 0x116c, 0x11b3, 0,
+#undef V7141
+#define V7141 (V + 26464)
+ 0x1108, 0x116c, 0x11b4, 0,
+#undef V7142
+#define V7142 (V + 26468)
+ 0x1108, 0x116c, 0x11b5, 0,
+#undef V7143
+#define V7143 (V + 26472)
+ 0x1108, 0x116c, 0x11b6, 0,
+#undef V7144
+#define V7144 (V + 26476)
+ 0x1108, 0x116c, 0x11b7, 0,
+#undef V7145
+#define V7145 (V + 26480)
+ 0x1108, 0x116c, 0x11b8, 0,
+#undef V7146
+#define V7146 (V + 26484)
+ 0x1108, 0x116c, 0x11b9, 0,
+#undef V7147
+#define V7147 (V + 26488)
+ 0x1108, 0x116c, 0x11ba, 0,
+#undef V7148
+#define V7148 (V + 26492)
+ 0x1108, 0x116c, 0x11bb, 0,
+#undef V7149
+#define V7149 (V + 26496)
+ 0x1108, 0x116c, 0x11bc, 0,
+#undef V7150
+#define V7150 (V + 26500)
+ 0x1108, 0x116c, 0x11bd, 0,
+#undef V7151
+#define V7151 (V + 26504)
+ 0x1108, 0x116c, 0x11be, 0,
+#undef V7152
+#define V7152 (V + 26508)
+ 0x1108, 0x116c, 0x11bf, 0,
+#undef V7153
+#define V7153 (V + 26512)
+ 0x1108, 0x116c, 0x11c0, 0,
+#undef V7154
+#define V7154 (V + 26516)
+ 0x1108, 0x116c, 0x11c1, 0,
+#undef V7155
+#define V7155 (V + 26520)
+ 0x1108, 0x116c, 0x11c2, 0,
+#undef V7156
+#define V7156 (V + 26524)
+ 0x1108, 0x116d, 0,
+#undef V7157
+#define V7157 (V + 26527)
+ 0x1108, 0x116d, 0x11a8, 0,
+#undef V7158
+#define V7158 (V + 26531)
+ 0x1108, 0x116d, 0x11a9, 0,
+#undef V7159
+#define V7159 (V + 26535)
+ 0x1108, 0x116d, 0x11aa, 0,
+#undef V7160
+#define V7160 (V + 26539)
+ 0x1108, 0x116d, 0x11ab, 0,
+#undef V7161
+#define V7161 (V + 26543)
+ 0x1108, 0x116d, 0x11ac, 0,
+#undef V7162
+#define V7162 (V + 26547)
+ 0x1108, 0x116d, 0x11ad, 0,
+#undef V7163
+#define V7163 (V + 26551)
+ 0x1108, 0x116d, 0x11ae, 0,
+#undef V7164
+#define V7164 (V + 26555)
+ 0x1108, 0x116d, 0x11af, 0,
+#undef V7165
+#define V7165 (V + 26559)
+ 0x1108, 0x116d, 0x11b0, 0,
+#undef V7166
+#define V7166 (V + 26563)
+ 0x1108, 0x116d, 0x11b1, 0,
+#undef V7167
+#define V7167 (V + 26567)
+ 0x1108, 0x116d, 0x11b2, 0,
+#undef V7168
+#define V7168 (V + 26571)
+ 0x1108, 0x116d, 0x11b3, 0,
+#undef V7169
+#define V7169 (V + 26575)
+ 0x1108, 0x116d, 0x11b4, 0,
+#undef V7170
+#define V7170 (V + 26579)
+ 0x1108, 0x116d, 0x11b5, 0,
+#undef V7171
+#define V7171 (V + 26583)
+ 0x1108, 0x116d, 0x11b6, 0,
+#undef V7172
+#define V7172 (V + 26587)
+ 0x1108, 0x116d, 0x11b7, 0,
+#undef V7173
+#define V7173 (V + 26591)
+ 0x1108, 0x116d, 0x11b8, 0,
+#undef V7174
+#define V7174 (V + 26595)
+ 0x1108, 0x116d, 0x11b9, 0,
+#undef V7175
+#define V7175 (V + 26599)
+ 0x1108, 0x116d, 0x11ba, 0,
+#undef V7176
+#define V7176 (V + 26603)
+ 0x1108, 0x116d, 0x11bb, 0,
+#undef V7177
+#define V7177 (V + 26607)
+ 0x1108, 0x116d, 0x11bc, 0,
+#undef V7178
+#define V7178 (V + 26611)
+ 0x1108, 0x116d, 0x11bd, 0,
+#undef V7179
+#define V7179 (V + 26615)
+ 0x1108, 0x116d, 0x11be, 0,
+#undef V7180
+#define V7180 (V + 26619)
+ 0x1108, 0x116d, 0x11bf, 0,
+#undef V7181
+#define V7181 (V + 26623)
+ 0x1108, 0x116d, 0x11c0, 0,
+#undef V7182
+#define V7182 (V + 26627)
+ 0x1108, 0x116d, 0x11c1, 0,
+#undef V7183
+#define V7183 (V + 26631)
+ 0x1108, 0x116d, 0x11c2, 0,
+#undef V7184
+#define V7184 (V + 26635)
+ 0x1108, 0x116e, 0,
+#undef V7185
+#define V7185 (V + 26638)
+ 0x1108, 0x116e, 0x11a8, 0,
+#undef V7186
+#define V7186 (V + 26642)
+ 0x1108, 0x116e, 0x11a9, 0,
+#undef V7187
+#define V7187 (V + 26646)
+ 0x1108, 0x116e, 0x11aa, 0,
+#undef V7188
+#define V7188 (V + 26650)
+ 0x1108, 0x116e, 0x11ab, 0,
+#undef V7189
+#define V7189 (V + 26654)
+ 0x1108, 0x116e, 0x11ac, 0,
+#undef V7190
+#define V7190 (V + 26658)
+ 0x1108, 0x116e, 0x11ad, 0,
+#undef V7191
+#define V7191 (V + 26662)
+ 0x1108, 0x116e, 0x11ae, 0,
+#undef V7192
+#define V7192 (V + 26666)
+ 0x1108, 0x116e, 0x11af, 0,
+#undef V7193
+#define V7193 (V + 26670)
+ 0x1108, 0x116e, 0x11b0, 0,
+#undef V7194
+#define V7194 (V + 26674)
+ 0x1108, 0x116e, 0x11b1, 0,
+#undef V7195
+#define V7195 (V + 26678)
+ 0x1108, 0x116e, 0x11b2, 0,
+#undef V7196
+#define V7196 (V + 26682)
+ 0x1108, 0x116e, 0x11b3, 0,
+#undef V7197
+#define V7197 (V + 26686)
+ 0x1108, 0x116e, 0x11b4, 0,
+#undef V7198
+#define V7198 (V + 26690)
+ 0x1108, 0x116e, 0x11b5, 0,
+#undef V7199
+#define V7199 (V + 26694)
+ 0x1108, 0x116e, 0x11b6, 0,
+#undef V7200
+#define V7200 (V + 26698)
+ 0x1108, 0x116e, 0x11b7, 0,
+#undef V7201
+#define V7201 (V + 26702)
+ 0x1108, 0x116e, 0x11b8, 0,
+#undef V7202
+#define V7202 (V + 26706)
+ 0x1108, 0x116e, 0x11b9, 0,
+#undef V7203
+#define V7203 (V + 26710)
+ 0x1108, 0x116e, 0x11ba, 0,
+#undef V7204
+#define V7204 (V + 26714)
+ 0x1108, 0x116e, 0x11bb, 0,
+#undef V7205
+#define V7205 (V + 26718)
+ 0x1108, 0x116e, 0x11bc, 0,
+#undef V7206
+#define V7206 (V + 26722)
+ 0x1108, 0x116e, 0x11bd, 0,
+#undef V7207
+#define V7207 (V + 26726)
+ 0x1108, 0x116e, 0x11be, 0,
+#undef V7208
+#define V7208 (V + 26730)
+ 0x1108, 0x116e, 0x11bf, 0,
+#undef V7209
+#define V7209 (V + 26734)
+ 0x1108, 0x116e, 0x11c0, 0,
+#undef V7210
+#define V7210 (V + 26738)
+ 0x1108, 0x116e, 0x11c1, 0,
+#undef V7211
+#define V7211 (V + 26742)
+ 0x1108, 0x116e, 0x11c2, 0,
+#undef V7212
+#define V7212 (V + 26746)
+ 0x1108, 0x116f, 0,
+#undef V7213
+#define V7213 (V + 26749)
+ 0x1108, 0x116f, 0x11a8, 0,
+#undef V7214
+#define V7214 (V + 26753)
+ 0x1108, 0x116f, 0x11a9, 0,
+#undef V7215
+#define V7215 (V + 26757)
+ 0x1108, 0x116f, 0x11aa, 0,
+#undef V7216
+#define V7216 (V + 26761)
+ 0x1108, 0x116f, 0x11ab, 0,
+#undef V7217
+#define V7217 (V + 26765)
+ 0x1108, 0x116f, 0x11ac, 0,
+#undef V7218
+#define V7218 (V + 26769)
+ 0x1108, 0x116f, 0x11ad, 0,
+#undef V7219
+#define V7219 (V + 26773)
+ 0x1108, 0x116f, 0x11ae, 0,
+#undef V7220
+#define V7220 (V + 26777)
+ 0x1108, 0x116f, 0x11af, 0,
+#undef V7221
+#define V7221 (V + 26781)
+ 0x1108, 0x116f, 0x11b0, 0,
+#undef V7222
+#define V7222 (V + 26785)
+ 0x1108, 0x116f, 0x11b1, 0,
+#undef V7223
+#define V7223 (V + 26789)
+ 0x1108, 0x116f, 0x11b2, 0,
+#undef V7224
+#define V7224 (V + 26793)
+ 0x1108, 0x116f, 0x11b3, 0,
+#undef V7225
+#define V7225 (V + 26797)
+ 0x1108, 0x116f, 0x11b4, 0,
+#undef V7226
+#define V7226 (V + 26801)
+ 0x1108, 0x116f, 0x11b5, 0,
+#undef V7227
+#define V7227 (V + 26805)
+ 0x1108, 0x116f, 0x11b6, 0,
+#undef V7228
+#define V7228 (V + 26809)
+ 0x1108, 0x116f, 0x11b7, 0,
+#undef V7229
+#define V7229 (V + 26813)
+ 0x1108, 0x116f, 0x11b8, 0,
+#undef V7230
+#define V7230 (V + 26817)
+ 0x1108, 0x116f, 0x11b9, 0,
+#undef V7231
+#define V7231 (V + 26821)
+ 0x1108, 0x116f, 0x11ba, 0,
+#undef V7232
+#define V7232 (V + 26825)
+ 0x1108, 0x116f, 0x11bb, 0,
+#undef V7233
+#define V7233 (V + 26829)
+ 0x1108, 0x116f, 0x11bc, 0,
+#undef V7234
+#define V7234 (V + 26833)
+ 0x1108, 0x116f, 0x11bd, 0,
+#undef V7235
+#define V7235 (V + 26837)
+ 0x1108, 0x116f, 0x11be, 0,
+#undef V7236
+#define V7236 (V + 26841)
+ 0x1108, 0x116f, 0x11bf, 0,
+#undef V7237
+#define V7237 (V + 26845)
+ 0x1108, 0x116f, 0x11c0, 0,
+#undef V7238
+#define V7238 (V + 26849)
+ 0x1108, 0x116f, 0x11c1, 0,
+#undef V7239
+#define V7239 (V + 26853)
+ 0x1108, 0x116f, 0x11c2, 0,
+#undef V7240
+#define V7240 (V + 26857)
+ 0x1108, 0x1170, 0,
+#undef V7241
+#define V7241 (V + 26860)
+ 0x1108, 0x1170, 0x11a8, 0,
+#undef V7242
+#define V7242 (V + 26864)
+ 0x1108, 0x1170, 0x11a9, 0,
+#undef V7243
+#define V7243 (V + 26868)
+ 0x1108, 0x1170, 0x11aa, 0,
+#undef V7244
+#define V7244 (V + 26872)
+ 0x1108, 0x1170, 0x11ab, 0,
+#undef V7245
+#define V7245 (V + 26876)
+ 0x1108, 0x1170, 0x11ac, 0,
+#undef V7246
+#define V7246 (V + 26880)
+ 0x1108, 0x1170, 0x11ad, 0,
+#undef V7247
+#define V7247 (V + 26884)
+ 0x1108, 0x1170, 0x11ae, 0,
+#undef V7248
+#define V7248 (V + 26888)
+ 0x1108, 0x1170, 0x11af, 0,
+#undef V7249
+#define V7249 (V + 26892)
+ 0x1108, 0x1170, 0x11b0, 0,
+#undef V7250
+#define V7250 (V + 26896)
+ 0x1108, 0x1170, 0x11b1, 0,
+#undef V7251
+#define V7251 (V + 26900)
+ 0x1108, 0x1170, 0x11b2, 0,
+#undef V7252
+#define V7252 (V + 26904)
+ 0x1108, 0x1170, 0x11b3, 0,
+#undef V7253
+#define V7253 (V + 26908)
+ 0x1108, 0x1170, 0x11b4, 0,
+#undef V7254
+#define V7254 (V + 26912)
+ 0x1108, 0x1170, 0x11b5, 0,
+#undef V7255
+#define V7255 (V + 26916)
+ 0x1108, 0x1170, 0x11b6, 0,
+#undef V7256
+#define V7256 (V + 26920)
+ 0x1108, 0x1170, 0x11b7, 0,
+#undef V7257
+#define V7257 (V + 26924)
+ 0x1108, 0x1170, 0x11b8, 0,
+#undef V7258
+#define V7258 (V + 26928)
+ 0x1108, 0x1170, 0x11b9, 0,
+#undef V7259
+#define V7259 (V + 26932)
+ 0x1108, 0x1170, 0x11ba, 0,
+#undef V7260
+#define V7260 (V + 26936)
+ 0x1108, 0x1170, 0x11bb, 0,
+#undef V7261
+#define V7261 (V + 26940)
+ 0x1108, 0x1170, 0x11bc, 0,
+#undef V7262
+#define V7262 (V + 26944)
+ 0x1108, 0x1170, 0x11bd, 0,
+#undef V7263
+#define V7263 (V + 26948)
+ 0x1108, 0x1170, 0x11be, 0,
+#undef V7264
+#define V7264 (V + 26952)
+ 0x1108, 0x1170, 0x11bf, 0,
+#undef V7265
+#define V7265 (V + 26956)
+ 0x1108, 0x1170, 0x11c0, 0,
+#undef V7266
+#define V7266 (V + 26960)
+ 0x1108, 0x1170, 0x11c1, 0,
+#undef V7267
+#define V7267 (V + 26964)
+ 0x1108, 0x1170, 0x11c2, 0,
+#undef V7268
+#define V7268 (V + 26968)
+ 0x1108, 0x1171, 0,
+#undef V7269
+#define V7269 (V + 26971)
+ 0x1108, 0x1171, 0x11a8, 0,
+#undef V7270
+#define V7270 (V + 26975)
+ 0x1108, 0x1171, 0x11a9, 0,
+#undef V7271
+#define V7271 (V + 26979)
+ 0x1108, 0x1171, 0x11aa, 0,
+#undef V7272
+#define V7272 (V + 26983)
+ 0x1108, 0x1171, 0x11ab, 0,
+#undef V7273
+#define V7273 (V + 26987)
+ 0x1108, 0x1171, 0x11ac, 0,
+#undef V7274
+#define V7274 (V + 26991)
+ 0x1108, 0x1171, 0x11ad, 0,
+#undef V7275
+#define V7275 (V + 26995)
+ 0x1108, 0x1171, 0x11ae, 0,
+#undef V7276
+#define V7276 (V + 26999)
+ 0x1108, 0x1171, 0x11af, 0,
+#undef V7277
+#define V7277 (V + 27003)
+ 0x1108, 0x1171, 0x11b0, 0,
+#undef V7278
+#define V7278 (V + 27007)
+ 0x1108, 0x1171, 0x11b1, 0,
+#undef V7279
+#define V7279 (V + 27011)
+ 0x1108, 0x1171, 0x11b2, 0,
+#undef V7280
+#define V7280 (V + 27015)
+ 0x1108, 0x1171, 0x11b3, 0,
+#undef V7281
+#define V7281 (V + 27019)
+ 0x1108, 0x1171, 0x11b4, 0,
+#undef V7282
+#define V7282 (V + 27023)
+ 0x1108, 0x1171, 0x11b5, 0,
+#undef V7283
+#define V7283 (V + 27027)
+ 0x1108, 0x1171, 0x11b6, 0,
+#undef V7284
+#define V7284 (V + 27031)
+ 0x1108, 0x1171, 0x11b7, 0,
+#undef V7285
+#define V7285 (V + 27035)
+ 0x1108, 0x1171, 0x11b8, 0,
+#undef V7286
+#define V7286 (V + 27039)
+ 0x1108, 0x1171, 0x11b9, 0,
+#undef V7287
+#define V7287 (V + 27043)
+ 0x1108, 0x1171, 0x11ba, 0,
+#undef V7288
+#define V7288 (V + 27047)
+ 0x1108, 0x1171, 0x11bb, 0,
+#undef V7289
+#define V7289 (V + 27051)
+ 0x1108, 0x1171, 0x11bc, 0,
+#undef V7290
+#define V7290 (V + 27055)
+ 0x1108, 0x1171, 0x11bd, 0,
+#undef V7291
+#define V7291 (V + 27059)
+ 0x1108, 0x1171, 0x11be, 0,
+#undef V7292
+#define V7292 (V + 27063)
+ 0x1108, 0x1171, 0x11bf, 0,
+#undef V7293
+#define V7293 (V + 27067)
+ 0x1108, 0x1171, 0x11c0, 0,
+#undef V7294
+#define V7294 (V + 27071)
+ 0x1108, 0x1171, 0x11c1, 0,
+#undef V7295
+#define V7295 (V + 27075)
+ 0x1108, 0x1171, 0x11c2, 0,
+#undef V7296
+#define V7296 (V + 27079)
+ 0x1108, 0x1172, 0,
+#undef V7297
+#define V7297 (V + 27082)
+ 0x1108, 0x1172, 0x11a8, 0,
+#undef V7298
+#define V7298 (V + 27086)
+ 0x1108, 0x1172, 0x11a9, 0,
+#undef V7299
+#define V7299 (V + 27090)
+ 0x1108, 0x1172, 0x11aa, 0,
+#undef V7300
+#define V7300 (V + 27094)
+ 0x1108, 0x1172, 0x11ab, 0,
+#undef V7301
+#define V7301 (V + 27098)
+ 0x1108, 0x1172, 0x11ac, 0,
+#undef V7302
+#define V7302 (V + 27102)
+ 0x1108, 0x1172, 0x11ad, 0,
+#undef V7303
+#define V7303 (V + 27106)
+ 0x1108, 0x1172, 0x11ae, 0,
+#undef V7304
+#define V7304 (V + 27110)
+ 0x1108, 0x1172, 0x11af, 0,
+#undef V7305
+#define V7305 (V + 27114)
+ 0x1108, 0x1172, 0x11b0, 0,
+#undef V7306
+#define V7306 (V + 27118)
+ 0x1108, 0x1172, 0x11b1, 0,
+#undef V7307
+#define V7307 (V + 27122)
+ 0x1108, 0x1172, 0x11b2, 0,
+#undef V7308
+#define V7308 (V + 27126)
+ 0x1108, 0x1172, 0x11b3, 0,
+#undef V7309
+#define V7309 (V + 27130)
+ 0x1108, 0x1172, 0x11b4, 0,
+#undef V7310
+#define V7310 (V + 27134)
+ 0x1108, 0x1172, 0x11b5, 0,
+#undef V7311
+#define V7311 (V + 27138)
+ 0x1108, 0x1172, 0x11b6, 0,
+#undef V7312
+#define V7312 (V + 27142)
+ 0x1108, 0x1172, 0x11b7, 0,
+#undef V7313
+#define V7313 (V + 27146)
+ 0x1108, 0x1172, 0x11b8, 0,
+#undef V7314
+#define V7314 (V + 27150)
+ 0x1108, 0x1172, 0x11b9, 0,
+#undef V7315
+#define V7315 (V + 27154)
+ 0x1108, 0x1172, 0x11ba, 0,
+#undef V7316
+#define V7316 (V + 27158)
+ 0x1108, 0x1172, 0x11bb, 0,
+#undef V7317
+#define V7317 (V + 27162)
+ 0x1108, 0x1172, 0x11bc, 0,
+#undef V7318
+#define V7318 (V + 27166)
+ 0x1108, 0x1172, 0x11bd, 0,
+#undef V7319
+#define V7319 (V + 27170)
+ 0x1108, 0x1172, 0x11be, 0,
+#undef V7320
+#define V7320 (V + 27174)
+ 0x1108, 0x1172, 0x11bf, 0,
+#undef V7321
+#define V7321 (V + 27178)
+ 0x1108, 0x1172, 0x11c0, 0,
+#undef V7322
+#define V7322 (V + 27182)
+ 0x1108, 0x1172, 0x11c1, 0,
+#undef V7323
+#define V7323 (V + 27186)
+ 0x1108, 0x1172, 0x11c2, 0,
+#undef V7324
+#define V7324 (V + 27190)
+ 0x1108, 0x1173, 0,
+#undef V7325
+#define V7325 (V + 27193)
+ 0x1108, 0x1173, 0x11a8, 0,
+#undef V7326
+#define V7326 (V + 27197)
+ 0x1108, 0x1173, 0x11a9, 0,
+#undef V7327
+#define V7327 (V + 27201)
+ 0x1108, 0x1173, 0x11aa, 0,
+#undef V7328
+#define V7328 (V + 27205)
+ 0x1108, 0x1173, 0x11ab, 0,
+#undef V7329
+#define V7329 (V + 27209)
+ 0x1108, 0x1173, 0x11ac, 0,
+#undef V7330
+#define V7330 (V + 27213)
+ 0x1108, 0x1173, 0x11ad, 0,
+#undef V7331
+#define V7331 (V + 27217)
+ 0x1108, 0x1173, 0x11ae, 0,
+#undef V7332
+#define V7332 (V + 27221)
+ 0x1108, 0x1173, 0x11af, 0,
+#undef V7333
+#define V7333 (V + 27225)
+ 0x1108, 0x1173, 0x11b0, 0,
+#undef V7334
+#define V7334 (V + 27229)
+ 0x1108, 0x1173, 0x11b1, 0,
+#undef V7335
+#define V7335 (V + 27233)
+ 0x1108, 0x1173, 0x11b2, 0,
+#undef V7336
+#define V7336 (V + 27237)
+ 0x1108, 0x1173, 0x11b3, 0,
+#undef V7337
+#define V7337 (V + 27241)
+ 0x1108, 0x1173, 0x11b4, 0,
+#undef V7338
+#define V7338 (V + 27245)
+ 0x1108, 0x1173, 0x11b5, 0,
+#undef V7339
+#define V7339 (V + 27249)
+ 0x1108, 0x1173, 0x11b6, 0,
+#undef V7340
+#define V7340 (V + 27253)
+ 0x1108, 0x1173, 0x11b7, 0,
+#undef V7341
+#define V7341 (V + 27257)
+ 0x1108, 0x1173, 0x11b8, 0,
+#undef V7342
+#define V7342 (V + 27261)
+ 0x1108, 0x1173, 0x11b9, 0,
+#undef V7343
+#define V7343 (V + 27265)
+ 0x1108, 0x1173, 0x11ba, 0,
+#undef V7344
+#define V7344 (V + 27269)
+ 0x1108, 0x1173, 0x11bb, 0,
+#undef V7345
+#define V7345 (V + 27273)
+ 0x1108, 0x1173, 0x11bc, 0,
+#undef V7346
+#define V7346 (V + 27277)
+ 0x1108, 0x1173, 0x11bd, 0,
+#undef V7347
+#define V7347 (V + 27281)
+ 0x1108, 0x1173, 0x11be, 0,
+#undef V7348
+#define V7348 (V + 27285)
+ 0x1108, 0x1173, 0x11bf, 0,
+#undef V7349
+#define V7349 (V + 27289)
+ 0x1108, 0x1173, 0x11c0, 0,
+#undef V7350
+#define V7350 (V + 27293)
+ 0x1108, 0x1173, 0x11c1, 0,
+#undef V7351
+#define V7351 (V + 27297)
+ 0x1108, 0x1173, 0x11c2, 0,
+#undef V7352
+#define V7352 (V + 27301)
+ 0x1108, 0x1174, 0,
+#undef V7353
+#define V7353 (V + 27304)
+ 0x1108, 0x1174, 0x11a8, 0,
+#undef V7354
+#define V7354 (V + 27308)
+ 0x1108, 0x1174, 0x11a9, 0,
+#undef V7355
+#define V7355 (V + 27312)
+ 0x1108, 0x1174, 0x11aa, 0,
+#undef V7356
+#define V7356 (V + 27316)
+ 0x1108, 0x1174, 0x11ab, 0,
+#undef V7357
+#define V7357 (V + 27320)
+ 0x1108, 0x1174, 0x11ac, 0,
+#undef V7358
+#define V7358 (V + 27324)
+ 0x1108, 0x1174, 0x11ad, 0,
+#undef V7359
+#define V7359 (V + 27328)
+ 0x1108, 0x1174, 0x11ae, 0,
+#undef V7360
+#define V7360 (V + 27332)
+ 0x1108, 0x1174, 0x11af, 0,
+#undef V7361
+#define V7361 (V + 27336)
+ 0x1108, 0x1174, 0x11b0, 0,
+#undef V7362
+#define V7362 (V + 27340)
+ 0x1108, 0x1174, 0x11b1, 0,
+#undef V7363
+#define V7363 (V + 27344)
+ 0x1108, 0x1174, 0x11b2, 0,
+#undef V7364
+#define V7364 (V + 27348)
+ 0x1108, 0x1174, 0x11b3, 0,
+#undef V7365
+#define V7365 (V + 27352)
+ 0x1108, 0x1174, 0x11b4, 0,
+#undef V7366
+#define V7366 (V + 27356)
+ 0x1108, 0x1174, 0x11b5, 0,
+#undef V7367
+#define V7367 (V + 27360)
+ 0x1108, 0x1174, 0x11b6, 0,
+#undef V7368
+#define V7368 (V + 27364)
+ 0x1108, 0x1174, 0x11b7, 0,
+#undef V7369
+#define V7369 (V + 27368)
+ 0x1108, 0x1174, 0x11b8, 0,
+#undef V7370
+#define V7370 (V + 27372)
+ 0x1108, 0x1174, 0x11b9, 0,
+#undef V7371
+#define V7371 (V + 27376)
+ 0x1108, 0x1174, 0x11ba, 0,
+#undef V7372
+#define V7372 (V + 27380)
+ 0x1108, 0x1174, 0x11bb, 0,
+#undef V7373
+#define V7373 (V + 27384)
+ 0x1108, 0x1174, 0x11bc, 0,
+#undef V7374
+#define V7374 (V + 27388)
+ 0x1108, 0x1174, 0x11bd, 0,
+#undef V7375
+#define V7375 (V + 27392)
+ 0x1108, 0x1174, 0x11be, 0,
+#undef V7376
+#define V7376 (V + 27396)
+ 0x1108, 0x1174, 0x11bf, 0,
+#undef V7377
+#define V7377 (V + 27400)
+ 0x1108, 0x1174, 0x11c0, 0,
+#undef V7378
+#define V7378 (V + 27404)
+ 0x1108, 0x1174, 0x11c1, 0,
+#undef V7379
+#define V7379 (V + 27408)
+ 0x1108, 0x1174, 0x11c2, 0,
+#undef V7380
+#define V7380 (V + 27412)
+ 0x1108, 0x1175, 0,
+#undef V7381
+#define V7381 (V + 27415)
+ 0x1108, 0x1175, 0x11a8, 0,
+#undef V7382
+#define V7382 (V + 27419)
+ 0x1108, 0x1175, 0x11a9, 0,
+#undef V7383
+#define V7383 (V + 27423)
+ 0x1108, 0x1175, 0x11aa, 0,
+#undef V7384
+#define V7384 (V + 27427)
+ 0x1108, 0x1175, 0x11ab, 0,
+#undef V7385
+#define V7385 (V + 27431)
+ 0x1108, 0x1175, 0x11ac, 0,
+#undef V7386
+#define V7386 (V + 27435)
+ 0x1108, 0x1175, 0x11ad, 0,
+#undef V7387
+#define V7387 (V + 27439)
+ 0x1108, 0x1175, 0x11ae, 0,
+#undef V7388
+#define V7388 (V + 27443)
+ 0x1108, 0x1175, 0x11af, 0,
+#undef V7389
+#define V7389 (V + 27447)
+ 0x1108, 0x1175, 0x11b0, 0,
+#undef V7390
+#define V7390 (V + 27451)
+ 0x1108, 0x1175, 0x11b1, 0,
+#undef V7391
+#define V7391 (V + 27455)
+ 0x1108, 0x1175, 0x11b2, 0,
+#undef V7392
+#define V7392 (V + 27459)
+ 0x1108, 0x1175, 0x11b3, 0,
+#undef V7393
+#define V7393 (V + 27463)
+ 0x1108, 0x1175, 0x11b4, 0,
+#undef V7394
+#define V7394 (V + 27467)
+ 0x1108, 0x1175, 0x11b5, 0,
+#undef V7395
+#define V7395 (V + 27471)
+ 0x1108, 0x1175, 0x11b6, 0,
+#undef V7396
+#define V7396 (V + 27475)
+ 0x1108, 0x1175, 0x11b7, 0,
+#undef V7397
+#define V7397 (V + 27479)
+ 0x1108, 0x1175, 0x11b8, 0,
+#undef V7398
+#define V7398 (V + 27483)
+ 0x1108, 0x1175, 0x11b9, 0,
+#undef V7399
+#define V7399 (V + 27487)
+ 0x1108, 0x1175, 0x11ba, 0,
+#undef V7400
+#define V7400 (V + 27491)
+ 0x1108, 0x1175, 0x11bb, 0,
+#undef V7401
+#define V7401 (V + 27495)
+ 0x1108, 0x1175, 0x11bc, 0,
+#undef V7402
+#define V7402 (V + 27499)
+ 0x1108, 0x1175, 0x11bd, 0,
+#undef V7403
+#define V7403 (V + 27503)
+ 0x1108, 0x1175, 0x11be, 0,
+#undef V7404
+#define V7404 (V + 27507)
+ 0x1108, 0x1175, 0x11bf, 0,
+#undef V7405
+#define V7405 (V + 27511)
+ 0x1108, 0x1175, 0x11c0, 0,
+#undef V7406
+#define V7406 (V + 27515)
+ 0x1108, 0x1175, 0x11c1, 0,
+#undef V7407
+#define V7407 (V + 27519)
+ 0x1108, 0x1175, 0x11c2, 0,
+#undef V7408
+#define V7408 (V + 27523)
+ 0x1109, 0x1161, 0x11a8, 0,
+#undef V7409
+#define V7409 (V + 27527)
+ 0x1109, 0x1161, 0x11a9, 0,
+#undef V7410
+#define V7410 (V + 27531)
+ 0x1109, 0x1161, 0x11aa, 0,
+#undef V7411
+#define V7411 (V + 27535)
+ 0x1109, 0x1161, 0x11ab, 0,
+#undef V7412
+#define V7412 (V + 27539)
+ 0x1109, 0x1161, 0x11ac, 0,
+#undef V7413
+#define V7413 (V + 27543)
+ 0x1109, 0x1161, 0x11ad, 0,
+#undef V7414
+#define V7414 (V + 27547)
+ 0x1109, 0x1161, 0x11ae, 0,
+#undef V7415
+#define V7415 (V + 27551)
+ 0x1109, 0x1161, 0x11af, 0,
+#undef V7416
+#define V7416 (V + 27555)
+ 0x1109, 0x1161, 0x11b0, 0,
+#undef V7417
+#define V7417 (V + 27559)
+ 0x1109, 0x1161, 0x11b1, 0,
+#undef V7418
+#define V7418 (V + 27563)
+ 0x1109, 0x1161, 0x11b2, 0,
+#undef V7419
+#define V7419 (V + 27567)
+ 0x1109, 0x1161, 0x11b3, 0,
+#undef V7420
+#define V7420 (V + 27571)
+ 0x1109, 0x1161, 0x11b4, 0,
+#undef V7421
+#define V7421 (V + 27575)
+ 0x1109, 0x1161, 0x11b5, 0,
+#undef V7422
+#define V7422 (V + 27579)
+ 0x1109, 0x1161, 0x11b6, 0,
+#undef V7423
+#define V7423 (V + 27583)
+ 0x1109, 0x1161, 0x11b7, 0,
+#undef V7424
+#define V7424 (V + 27587)
+ 0x1109, 0x1161, 0x11b8, 0,
+#undef V7425
+#define V7425 (V + 27591)
+ 0x1109, 0x1161, 0x11b9, 0,
+#undef V7426
+#define V7426 (V + 27595)
+ 0x1109, 0x1161, 0x11ba, 0,
+#undef V7427
+#define V7427 (V + 27599)
+ 0x1109, 0x1161, 0x11bb, 0,
+#undef V7428
+#define V7428 (V + 27603)
+ 0x1109, 0x1161, 0x11bc, 0,
+#undef V7429
+#define V7429 (V + 27607)
+ 0x1109, 0x1161, 0x11bd, 0,
+#undef V7430
+#define V7430 (V + 27611)
+ 0x1109, 0x1161, 0x11be, 0,
+#undef V7431
+#define V7431 (V + 27615)
+ 0x1109, 0x1161, 0x11bf, 0,
+#undef V7432
+#define V7432 (V + 27619)
+ 0x1109, 0x1161, 0x11c0, 0,
+#undef V7433
+#define V7433 (V + 27623)
+ 0x1109, 0x1161, 0x11c1, 0,
+#undef V7434
+#define V7434 (V + 27627)
+ 0x1109, 0x1161, 0x11c2, 0,
+#undef V7435
+#define V7435 (V + 27631)
+ 0x1109, 0x1162, 0,
+#undef V7436
+#define V7436 (V + 27634)
+ 0x1109, 0x1162, 0x11a8, 0,
+#undef V7437
+#define V7437 (V + 27638)
+ 0x1109, 0x1162, 0x11a9, 0,
+#undef V7438
+#define V7438 (V + 27642)
+ 0x1109, 0x1162, 0x11aa, 0,
+#undef V7439
+#define V7439 (V + 27646)
+ 0x1109, 0x1162, 0x11ab, 0,
+#undef V7440
+#define V7440 (V + 27650)
+ 0x1109, 0x1162, 0x11ac, 0,
+#undef V7441
+#define V7441 (V + 27654)
+ 0x1109, 0x1162, 0x11ad, 0,
+#undef V7442
+#define V7442 (V + 27658)
+ 0x1109, 0x1162, 0x11ae, 0,
+#undef V7443
+#define V7443 (V + 27662)
+ 0x1109, 0x1162, 0x11af, 0,
+#undef V7444
+#define V7444 (V + 27666)
+ 0x1109, 0x1162, 0x11b0, 0,
+#undef V7445
+#define V7445 (V + 27670)
+ 0x1109, 0x1162, 0x11b1, 0,
+#undef V7446
+#define V7446 (V + 27674)
+ 0x1109, 0x1162, 0x11b2, 0,
+#undef V7447
+#define V7447 (V + 27678)
+ 0x1109, 0x1162, 0x11b3, 0,
+#undef V7448
+#define V7448 (V + 27682)
+ 0x1109, 0x1162, 0x11b4, 0,
+#undef V7449
+#define V7449 (V + 27686)
+ 0x1109, 0x1162, 0x11b5, 0,
+#undef V7450
+#define V7450 (V + 27690)
+ 0x1109, 0x1162, 0x11b6, 0,
+#undef V7451
+#define V7451 (V + 27694)
+ 0x1109, 0x1162, 0x11b7, 0,
+#undef V7452
+#define V7452 (V + 27698)
+ 0x1109, 0x1162, 0x11b8, 0,
+#undef V7453
+#define V7453 (V + 27702)
+ 0x1109, 0x1162, 0x11b9, 0,
+#undef V7454
+#define V7454 (V + 27706)
+ 0x1109, 0x1162, 0x11ba, 0,
+#undef V7455
+#define V7455 (V + 27710)
+ 0x1109, 0x1162, 0x11bb, 0,
+#undef V7456
+#define V7456 (V + 27714)
+ 0x1109, 0x1162, 0x11bc, 0,
+#undef V7457
+#define V7457 (V + 27718)
+ 0x1109, 0x1162, 0x11bd, 0,
+#undef V7458
+#define V7458 (V + 27722)
+ 0x1109, 0x1162, 0x11be, 0,
+#undef V7459
+#define V7459 (V + 27726)
+ 0x1109, 0x1162, 0x11bf, 0,
+#undef V7460
+#define V7460 (V + 27730)
+ 0x1109, 0x1162, 0x11c0, 0,
+#undef V7461
+#define V7461 (V + 27734)
+ 0x1109, 0x1162, 0x11c1, 0,
+#undef V7462
+#define V7462 (V + 27738)
+ 0x1109, 0x1162, 0x11c2, 0,
+#undef V7463
+#define V7463 (V + 27742)
+ 0x1109, 0x1163, 0,
+#undef V7464
+#define V7464 (V + 27745)
+ 0x1109, 0x1163, 0x11a8, 0,
+#undef V7465
+#define V7465 (V + 27749)
+ 0x1109, 0x1163, 0x11a9, 0,
+#undef V7466
+#define V7466 (V + 27753)
+ 0x1109, 0x1163, 0x11aa, 0,
+#undef V7467
+#define V7467 (V + 27757)
+ 0x1109, 0x1163, 0x11ab, 0,
+#undef V7468
+#define V7468 (V + 27761)
+ 0x1109, 0x1163, 0x11ac, 0,
+#undef V7469
+#define V7469 (V + 27765)
+ 0x1109, 0x1163, 0x11ad, 0,
+#undef V7470
+#define V7470 (V + 27769)
+ 0x1109, 0x1163, 0x11ae, 0,
+#undef V7471
+#define V7471 (V + 27773)
+ 0x1109, 0x1163, 0x11af, 0,
+#undef V7472
+#define V7472 (V + 27777)
+ 0x1109, 0x1163, 0x11b0, 0,
+#undef V7473
+#define V7473 (V + 27781)
+ 0x1109, 0x1163, 0x11b1, 0,
+#undef V7474
+#define V7474 (V + 27785)
+ 0x1109, 0x1163, 0x11b2, 0,
+#undef V7475
+#define V7475 (V + 27789)
+ 0x1109, 0x1163, 0x11b3, 0,
+#undef V7476
+#define V7476 (V + 27793)
+ 0x1109, 0x1163, 0x11b4, 0,
+#undef V7477
+#define V7477 (V + 27797)
+ 0x1109, 0x1163, 0x11b5, 0,
+#undef V7478
+#define V7478 (V + 27801)
+ 0x1109, 0x1163, 0x11b6, 0,
+#undef V7479
+#define V7479 (V + 27805)
+ 0x1109, 0x1163, 0x11b7, 0,
+#undef V7480
+#define V7480 (V + 27809)
+ 0x1109, 0x1163, 0x11b8, 0,
+#undef V7481
+#define V7481 (V + 27813)
+ 0x1109, 0x1163, 0x11b9, 0,
+#undef V7482
+#define V7482 (V + 27817)
+ 0x1109, 0x1163, 0x11ba, 0,
+#undef V7483
+#define V7483 (V + 27821)
+ 0x1109, 0x1163, 0x11bb, 0,
+#undef V7484
+#define V7484 (V + 27825)
+ 0x1109, 0x1163, 0x11bc, 0,
+#undef V7485
+#define V7485 (V + 27829)
+ 0x1109, 0x1163, 0x11bd, 0,
+#undef V7486
+#define V7486 (V + 27833)
+ 0x1109, 0x1163, 0x11be, 0,
+#undef V7487
+#define V7487 (V + 27837)
+ 0x1109, 0x1163, 0x11bf, 0,
+#undef V7488
+#define V7488 (V + 27841)
+ 0x1109, 0x1163, 0x11c0, 0,
+#undef V7489
+#define V7489 (V + 27845)
+ 0x1109, 0x1163, 0x11c1, 0,
+#undef V7490
+#define V7490 (V + 27849)
+ 0x1109, 0x1163, 0x11c2, 0,
+#undef V7491
+#define V7491 (V + 27853)
+ 0x1109, 0x1164, 0,
+#undef V7492
+#define V7492 (V + 27856)
+ 0x1109, 0x1164, 0x11a8, 0,
+#undef V7493
+#define V7493 (V + 27860)
+ 0x1109, 0x1164, 0x11a9, 0,
+#undef V7494
+#define V7494 (V + 27864)
+ 0x1109, 0x1164, 0x11aa, 0,
+#undef V7495
+#define V7495 (V + 27868)
+ 0x1109, 0x1164, 0x11ab, 0,
+#undef V7496
+#define V7496 (V + 27872)
+ 0x1109, 0x1164, 0x11ac, 0,
+#undef V7497
+#define V7497 (V + 27876)
+ 0x1109, 0x1164, 0x11ad, 0,
+#undef V7498
+#define V7498 (V + 27880)
+ 0x1109, 0x1164, 0x11ae, 0,
+#undef V7499
+#define V7499 (V + 27884)
+ 0x1109, 0x1164, 0x11af, 0,
+#undef V7500
+#define V7500 (V + 27888)
+ 0x1109, 0x1164, 0x11b0, 0,
+#undef V7501
+#define V7501 (V + 27892)
+ 0x1109, 0x1164, 0x11b1, 0,
+#undef V7502
+#define V7502 (V + 27896)
+ 0x1109, 0x1164, 0x11b2, 0,
+#undef V7503
+#define V7503 (V + 27900)
+ 0x1109, 0x1164, 0x11b3, 0,
+#undef V7504
+#define V7504 (V + 27904)
+ 0x1109, 0x1164, 0x11b4, 0,
+#undef V7505
+#define V7505 (V + 27908)
+ 0x1109, 0x1164, 0x11b5, 0,
+#undef V7506
+#define V7506 (V + 27912)
+ 0x1109, 0x1164, 0x11b6, 0,
+#undef V7507
+#define V7507 (V + 27916)
+ 0x1109, 0x1164, 0x11b7, 0,
+#undef V7508
+#define V7508 (V + 27920)
+ 0x1109, 0x1164, 0x11b8, 0,
+#undef V7509
+#define V7509 (V + 27924)
+ 0x1109, 0x1164, 0x11b9, 0,
+#undef V7510
+#define V7510 (V + 27928)
+ 0x1109, 0x1164, 0x11ba, 0,
+#undef V7511
+#define V7511 (V + 27932)
+ 0x1109, 0x1164, 0x11bb, 0,
+#undef V7512
+#define V7512 (V + 27936)
+ 0x1109, 0x1164, 0x11bc, 0,
+#undef V7513
+#define V7513 (V + 27940)
+ 0x1109, 0x1164, 0x11bd, 0,
+#undef V7514
+#define V7514 (V + 27944)
+ 0x1109, 0x1164, 0x11be, 0,
+#undef V7515
+#define V7515 (V + 27948)
+ 0x1109, 0x1164, 0x11bf, 0,
+#undef V7516
+#define V7516 (V + 27952)
+ 0x1109, 0x1164, 0x11c0, 0,
+#undef V7517
+#define V7517 (V + 27956)
+ 0x1109, 0x1164, 0x11c1, 0,
+#undef V7518
+#define V7518 (V + 27960)
+ 0x1109, 0x1164, 0x11c2, 0,
+#undef V7519
+#define V7519 (V + 27964)
+ 0x1109, 0x1165, 0,
+#undef V7520
+#define V7520 (V + 27967)
+ 0x1109, 0x1165, 0x11a8, 0,
+#undef V7521
+#define V7521 (V + 27971)
+ 0x1109, 0x1165, 0x11a9, 0,
+#undef V7522
+#define V7522 (V + 27975)
+ 0x1109, 0x1165, 0x11aa, 0,
+#undef V7523
+#define V7523 (V + 27979)
+ 0x1109, 0x1165, 0x11ab, 0,
+#undef V7524
+#define V7524 (V + 27983)
+ 0x1109, 0x1165, 0x11ac, 0,
+#undef V7525
+#define V7525 (V + 27987)
+ 0x1109, 0x1165, 0x11ad, 0,
+#undef V7526
+#define V7526 (V + 27991)
+ 0x1109, 0x1165, 0x11ae, 0,
+#undef V7527
+#define V7527 (V + 27995)
+ 0x1109, 0x1165, 0x11af, 0,
+#undef V7528
+#define V7528 (V + 27999)
+ 0x1109, 0x1165, 0x11b0, 0,
+#undef V7529
+#define V7529 (V + 28003)
+ 0x1109, 0x1165, 0x11b1, 0,
+#undef V7530
+#define V7530 (V + 28007)
+ 0x1109, 0x1165, 0x11b2, 0,
+#undef V7531
+#define V7531 (V + 28011)
+ 0x1109, 0x1165, 0x11b3, 0,
+#undef V7532
+#define V7532 (V + 28015)
+ 0x1109, 0x1165, 0x11b4, 0,
+#undef V7533
+#define V7533 (V + 28019)
+ 0x1109, 0x1165, 0x11b5, 0,
+#undef V7534
+#define V7534 (V + 28023)
+ 0x1109, 0x1165, 0x11b6, 0,
+#undef V7535
+#define V7535 (V + 28027)
+ 0x1109, 0x1165, 0x11b7, 0,
+#undef V7536
+#define V7536 (V + 28031)
+ 0x1109, 0x1165, 0x11b8, 0,
+#undef V7537
+#define V7537 (V + 28035)
+ 0x1109, 0x1165, 0x11b9, 0,
+#undef V7538
+#define V7538 (V + 28039)
+ 0x1109, 0x1165, 0x11ba, 0,
+#undef V7539
+#define V7539 (V + 28043)
+ 0x1109, 0x1165, 0x11bb, 0,
+#undef V7540
+#define V7540 (V + 28047)
+ 0x1109, 0x1165, 0x11bc, 0,
+#undef V7541
+#define V7541 (V + 28051)
+ 0x1109, 0x1165, 0x11bd, 0,
+#undef V7542
+#define V7542 (V + 28055)
+ 0x1109, 0x1165, 0x11be, 0,
+#undef V7543
+#define V7543 (V + 28059)
+ 0x1109, 0x1165, 0x11bf, 0,
+#undef V7544
+#define V7544 (V + 28063)
+ 0x1109, 0x1165, 0x11c0, 0,
+#undef V7545
+#define V7545 (V + 28067)
+ 0x1109, 0x1165, 0x11c1, 0,
+#undef V7546
+#define V7546 (V + 28071)
+ 0x1109, 0x1165, 0x11c2, 0,
+#undef V7547
+#define V7547 (V + 28075)
+ 0x1109, 0x1166, 0,
+#undef V7548
+#define V7548 (V + 28078)
+ 0x1109, 0x1166, 0x11a8, 0,
+#undef V7549
+#define V7549 (V + 28082)
+ 0x1109, 0x1166, 0x11a9, 0,
+#undef V7550
+#define V7550 (V + 28086)
+ 0x1109, 0x1166, 0x11aa, 0,
+#undef V7551
+#define V7551 (V + 28090)
+ 0x1109, 0x1166, 0x11ab, 0,
+#undef V7552
+#define V7552 (V + 28094)
+ 0x1109, 0x1166, 0x11ac, 0,
+#undef V7553
+#define V7553 (V + 28098)
+ 0x1109, 0x1166, 0x11ad, 0,
+#undef V7554
+#define V7554 (V + 28102)
+ 0x1109, 0x1166, 0x11ae, 0,
+#undef V7555
+#define V7555 (V + 28106)
+ 0x1109, 0x1166, 0x11af, 0,
+#undef V7556
+#define V7556 (V + 28110)
+ 0x1109, 0x1166, 0x11b0, 0,
+#undef V7557
+#define V7557 (V + 28114)
+ 0x1109, 0x1166, 0x11b1, 0,
+#undef V7558
+#define V7558 (V + 28118)
+ 0x1109, 0x1166, 0x11b2, 0,
+#undef V7559
+#define V7559 (V + 28122)
+ 0x1109, 0x1166, 0x11b3, 0,
+#undef V7560
+#define V7560 (V + 28126)
+ 0x1109, 0x1166, 0x11b4, 0,
+#undef V7561
+#define V7561 (V + 28130)
+ 0x1109, 0x1166, 0x11b5, 0,
+#undef V7562
+#define V7562 (V + 28134)
+ 0x1109, 0x1166, 0x11b6, 0,
+#undef V7563
+#define V7563 (V + 28138)
+ 0x1109, 0x1166, 0x11b7, 0,
+#undef V7564
+#define V7564 (V + 28142)
+ 0x1109, 0x1166, 0x11b8, 0,
+#undef V7565
+#define V7565 (V + 28146)
+ 0x1109, 0x1166, 0x11b9, 0,
+#undef V7566
+#define V7566 (V + 28150)
+ 0x1109, 0x1166, 0x11ba, 0,
+#undef V7567
+#define V7567 (V + 28154)
+ 0x1109, 0x1166, 0x11bb, 0,
+#undef V7568
+#define V7568 (V + 28158)
+ 0x1109, 0x1166, 0x11bc, 0,
+#undef V7569
+#define V7569 (V + 28162)
+ 0x1109, 0x1166, 0x11bd, 0,
+#undef V7570
+#define V7570 (V + 28166)
+ 0x1109, 0x1166, 0x11be, 0,
+#undef V7571
+#define V7571 (V + 28170)
+ 0x1109, 0x1166, 0x11bf, 0,
+#undef V7572
+#define V7572 (V + 28174)
+ 0x1109, 0x1166, 0x11c0, 0,
+#undef V7573
+#define V7573 (V + 28178)
+ 0x1109, 0x1166, 0x11c1, 0,
+#undef V7574
+#define V7574 (V + 28182)
+ 0x1109, 0x1166, 0x11c2, 0,
+#undef V7575
+#define V7575 (V + 28186)
+ 0x1109, 0x1167, 0,
+#undef V7576
+#define V7576 (V + 28189)
+ 0x1109, 0x1167, 0x11a8, 0,
+#undef V7577
+#define V7577 (V + 28193)
+ 0x1109, 0x1167, 0x11a9, 0,
+#undef V7578
+#define V7578 (V + 28197)
+ 0x1109, 0x1167, 0x11aa, 0,
+#undef V7579
+#define V7579 (V + 28201)
+ 0x1109, 0x1167, 0x11ab, 0,
+#undef V7580
+#define V7580 (V + 28205)
+ 0x1109, 0x1167, 0x11ac, 0,
+#undef V7581
+#define V7581 (V + 28209)
+ 0x1109, 0x1167, 0x11ad, 0,
+#undef V7582
+#define V7582 (V + 28213)
+ 0x1109, 0x1167, 0x11ae, 0,
+#undef V7583
+#define V7583 (V + 28217)
+ 0x1109, 0x1167, 0x11af, 0,
+#undef V7584
+#define V7584 (V + 28221)
+ 0x1109, 0x1167, 0x11b0, 0,
+#undef V7585
+#define V7585 (V + 28225)
+ 0x1109, 0x1167, 0x11b1, 0,
+#undef V7586
+#define V7586 (V + 28229)
+ 0x1109, 0x1167, 0x11b2, 0,
+#undef V7587
+#define V7587 (V + 28233)
+ 0x1109, 0x1167, 0x11b3, 0,
+#undef V7588
+#define V7588 (V + 28237)
+ 0x1109, 0x1167, 0x11b4, 0,
+#undef V7589
+#define V7589 (V + 28241)
+ 0x1109, 0x1167, 0x11b5, 0,
+#undef V7590
+#define V7590 (V + 28245)
+ 0x1109, 0x1167, 0x11b6, 0,
+#undef V7591
+#define V7591 (V + 28249)
+ 0x1109, 0x1167, 0x11b7, 0,
+#undef V7592
+#define V7592 (V + 28253)
+ 0x1109, 0x1167, 0x11b8, 0,
+#undef V7593
+#define V7593 (V + 28257)
+ 0x1109, 0x1167, 0x11b9, 0,
+#undef V7594
+#define V7594 (V + 28261)
+ 0x1109, 0x1167, 0x11ba, 0,
+#undef V7595
+#define V7595 (V + 28265)
+ 0x1109, 0x1167, 0x11bb, 0,
+#undef V7596
+#define V7596 (V + 28269)
+ 0x1109, 0x1167, 0x11bc, 0,
+#undef V7597
+#define V7597 (V + 28273)
+ 0x1109, 0x1167, 0x11bd, 0,
+#undef V7598
+#define V7598 (V + 28277)
+ 0x1109, 0x1167, 0x11be, 0,
+#undef V7599
+#define V7599 (V + 28281)
+ 0x1109, 0x1167, 0x11bf, 0,
+#undef V7600
+#define V7600 (V + 28285)
+ 0x1109, 0x1167, 0x11c0, 0,
+#undef V7601
+#define V7601 (V + 28289)
+ 0x1109, 0x1167, 0x11c1, 0,
+#undef V7602
+#define V7602 (V + 28293)
+ 0x1109, 0x1167, 0x11c2, 0,
+#undef V7603
+#define V7603 (V + 28297)
+ 0x1109, 0x1168, 0,
+#undef V7604
+#define V7604 (V + 28300)
+ 0x1109, 0x1168, 0x11a8, 0,
+#undef V7605
+#define V7605 (V + 28304)
+ 0x1109, 0x1168, 0x11a9, 0,
+#undef V7606
+#define V7606 (V + 28308)
+ 0x1109, 0x1168, 0x11aa, 0,
+#undef V7607
+#define V7607 (V + 28312)
+ 0x1109, 0x1168, 0x11ab, 0,
+#undef V7608
+#define V7608 (V + 28316)
+ 0x1109, 0x1168, 0x11ac, 0,
+#undef V7609
+#define V7609 (V + 28320)
+ 0x1109, 0x1168, 0x11ad, 0,
+#undef V7610
+#define V7610 (V + 28324)
+ 0x1109, 0x1168, 0x11ae, 0,
+#undef V7611
+#define V7611 (V + 28328)
+ 0x1109, 0x1168, 0x11af, 0,
+#undef V7612
+#define V7612 (V + 28332)
+ 0x1109, 0x1168, 0x11b0, 0,
+#undef V7613
+#define V7613 (V + 28336)
+ 0x1109, 0x1168, 0x11b1, 0,
+#undef V7614
+#define V7614 (V + 28340)
+ 0x1109, 0x1168, 0x11b2, 0,
+#undef V7615
+#define V7615 (V + 28344)
+ 0x1109, 0x1168, 0x11b3, 0,
+#undef V7616
+#define V7616 (V + 28348)
+ 0x1109, 0x1168, 0x11b4, 0,
+#undef V7617
+#define V7617 (V + 28352)
+ 0x1109, 0x1168, 0x11b5, 0,
+#undef V7618
+#define V7618 (V + 28356)
+ 0x1109, 0x1168, 0x11b6, 0,
+#undef V7619
+#define V7619 (V + 28360)
+ 0x1109, 0x1168, 0x11b7, 0,
+#undef V7620
+#define V7620 (V + 28364)
+ 0x1109, 0x1168, 0x11b8, 0,
+#undef V7621
+#define V7621 (V + 28368)
+ 0x1109, 0x1168, 0x11b9, 0,
+#undef V7622
+#define V7622 (V + 28372)
+ 0x1109, 0x1168, 0x11ba, 0,
+#undef V7623
+#define V7623 (V + 28376)
+ 0x1109, 0x1168, 0x11bb, 0,
+#undef V7624
+#define V7624 (V + 28380)
+ 0x1109, 0x1168, 0x11bc, 0,
+#undef V7625
+#define V7625 (V + 28384)
+ 0x1109, 0x1168, 0x11bd, 0,
+#undef V7626
+#define V7626 (V + 28388)
+ 0x1109, 0x1168, 0x11be, 0,
+#undef V7627
+#define V7627 (V + 28392)
+ 0x1109, 0x1168, 0x11bf, 0,
+#undef V7628
+#define V7628 (V + 28396)
+ 0x1109, 0x1168, 0x11c0, 0,
+#undef V7629
+#define V7629 (V + 28400)
+ 0x1109, 0x1168, 0x11c1, 0,
+#undef V7630
+#define V7630 (V + 28404)
+ 0x1109, 0x1168, 0x11c2, 0,
+#undef V7631
+#define V7631 (V + 28408)
+ 0x1109, 0x1169, 0,
+#undef V7632
+#define V7632 (V + 28411)
+ 0x1109, 0x1169, 0x11a8, 0,
+#undef V7633
+#define V7633 (V + 28415)
+ 0x1109, 0x1169, 0x11a9, 0,
+#undef V7634
+#define V7634 (V + 28419)
+ 0x1109, 0x1169, 0x11aa, 0,
+#undef V7635
+#define V7635 (V + 28423)
+ 0x1109, 0x1169, 0x11ab, 0,
+#undef V7636
+#define V7636 (V + 28427)
+ 0x1109, 0x1169, 0x11ac, 0,
+#undef V7637
+#define V7637 (V + 28431)
+ 0x1109, 0x1169, 0x11ad, 0,
+#undef V7638
+#define V7638 (V + 28435)
+ 0x1109, 0x1169, 0x11ae, 0,
+#undef V7639
+#define V7639 (V + 28439)
+ 0x1109, 0x1169, 0x11af, 0,
+#undef V7640
+#define V7640 (V + 28443)
+ 0x1109, 0x1169, 0x11b0, 0,
+#undef V7641
+#define V7641 (V + 28447)
+ 0x1109, 0x1169, 0x11b1, 0,
+#undef V7642
+#define V7642 (V + 28451)
+ 0x1109, 0x1169, 0x11b2, 0,
+#undef V7643
+#define V7643 (V + 28455)
+ 0x1109, 0x1169, 0x11b3, 0,
+#undef V7644
+#define V7644 (V + 28459)
+ 0x1109, 0x1169, 0x11b4, 0,
+#undef V7645
+#define V7645 (V + 28463)
+ 0x1109, 0x1169, 0x11b5, 0,
+#undef V7646
+#define V7646 (V + 28467)
+ 0x1109, 0x1169, 0x11b6, 0,
+#undef V7647
+#define V7647 (V + 28471)
+ 0x1109, 0x1169, 0x11b7, 0,
+#undef V7648
+#define V7648 (V + 28475)
+ 0x1109, 0x1169, 0x11b8, 0,
+#undef V7649
+#define V7649 (V + 28479)
+ 0x1109, 0x1169, 0x11b9, 0,
+#undef V7650
+#define V7650 (V + 28483)
+ 0x1109, 0x1169, 0x11ba, 0,
+#undef V7651
+#define V7651 (V + 28487)
+ 0x1109, 0x1169, 0x11bb, 0,
+#undef V7652
+#define V7652 (V + 28491)
+ 0x1109, 0x1169, 0x11bc, 0,
+#undef V7653
+#define V7653 (V + 28495)
+ 0x1109, 0x1169, 0x11bd, 0,
+#undef V7654
+#define V7654 (V + 28499)
+ 0x1109, 0x1169, 0x11be, 0,
+#undef V7655
+#define V7655 (V + 28503)
+ 0x1109, 0x1169, 0x11bf, 0,
+#undef V7656
+#define V7656 (V + 28507)
+ 0x1109, 0x1169, 0x11c0, 0,
+#undef V7657
+#define V7657 (V + 28511)
+ 0x1109, 0x1169, 0x11c1, 0,
+#undef V7658
+#define V7658 (V + 28515)
+ 0x1109, 0x1169, 0x11c2, 0,
+#undef V7659
+#define V7659 (V + 28519)
+ 0x1109, 0x116a, 0,
+#undef V7660
+#define V7660 (V + 28522)
+ 0x1109, 0x116a, 0x11a8, 0,
+#undef V7661
+#define V7661 (V + 28526)
+ 0x1109, 0x116a, 0x11a9, 0,
+#undef V7662
+#define V7662 (V + 28530)
+ 0x1109, 0x116a, 0x11aa, 0,
+#undef V7663
+#define V7663 (V + 28534)
+ 0x1109, 0x116a, 0x11ab, 0,
+#undef V7664
+#define V7664 (V + 28538)
+ 0x1109, 0x116a, 0x11ac, 0,
+#undef V7665
+#define V7665 (V + 28542)
+ 0x1109, 0x116a, 0x11ad, 0,
+#undef V7666
+#define V7666 (V + 28546)
+ 0x1109, 0x116a, 0x11ae, 0,
+#undef V7667
+#define V7667 (V + 28550)
+ 0x1109, 0x116a, 0x11af, 0,
+#undef V7668
+#define V7668 (V + 28554)
+ 0x1109, 0x116a, 0x11b0, 0,
+#undef V7669
+#define V7669 (V + 28558)
+ 0x1109, 0x116a, 0x11b1, 0,
+#undef V7670
+#define V7670 (V + 28562)
+ 0x1109, 0x116a, 0x11b2, 0,
+#undef V7671
+#define V7671 (V + 28566)
+ 0x1109, 0x116a, 0x11b3, 0,
+#undef V7672
+#define V7672 (V + 28570)
+ 0x1109, 0x116a, 0x11b4, 0,
+#undef V7673
+#define V7673 (V + 28574)
+ 0x1109, 0x116a, 0x11b5, 0,
+#undef V7674
+#define V7674 (V + 28578)
+ 0x1109, 0x116a, 0x11b6, 0,
+#undef V7675
+#define V7675 (V + 28582)
+ 0x1109, 0x116a, 0x11b7, 0,
+#undef V7676
+#define V7676 (V + 28586)
+ 0x1109, 0x116a, 0x11b8, 0,
+#undef V7677
+#define V7677 (V + 28590)
+ 0x1109, 0x116a, 0x11b9, 0,
+#undef V7678
+#define V7678 (V + 28594)
+ 0x1109, 0x116a, 0x11ba, 0,
+#undef V7679
+#define V7679 (V + 28598)
+ 0x1109, 0x116a, 0x11bb, 0,
+#undef V7680
+#define V7680 (V + 28602)
+ 0x1109, 0x116a, 0x11bc, 0,
+#undef V7681
+#define V7681 (V + 28606)
+ 0x1109, 0x116a, 0x11bd, 0,
+#undef V7682
+#define V7682 (V + 28610)
+ 0x1109, 0x116a, 0x11be, 0,
+#undef V7683
+#define V7683 (V + 28614)
+ 0x1109, 0x116a, 0x11bf, 0,
+#undef V7684
+#define V7684 (V + 28618)
+ 0x1109, 0x116a, 0x11c0, 0,
+#undef V7685
+#define V7685 (V + 28622)
+ 0x1109, 0x116a, 0x11c1, 0,
+#undef V7686
+#define V7686 (V + 28626)
+ 0x1109, 0x116a, 0x11c2, 0,
+#undef V7687
+#define V7687 (V + 28630)
+ 0x1109, 0x116b, 0,
+#undef V7688
+#define V7688 (V + 28633)
+ 0x1109, 0x116b, 0x11a8, 0,
+#undef V7689
+#define V7689 (V + 28637)
+ 0x1109, 0x116b, 0x11a9, 0,
+#undef V7690
+#define V7690 (V + 28641)
+ 0x1109, 0x116b, 0x11aa, 0,
+#undef V7691
+#define V7691 (V + 28645)
+ 0x1109, 0x116b, 0x11ab, 0,
+#undef V7692
+#define V7692 (V + 28649)
+ 0x1109, 0x116b, 0x11ac, 0,
+#undef V7693
+#define V7693 (V + 28653)
+ 0x1109, 0x116b, 0x11ad, 0,
+#undef V7694
+#define V7694 (V + 28657)
+ 0x1109, 0x116b, 0x11ae, 0,
+#undef V7695
+#define V7695 (V + 28661)
+ 0x1109, 0x116b, 0x11af, 0,
+#undef V7696
+#define V7696 (V + 28665)
+ 0x1109, 0x116b, 0x11b0, 0,
+#undef V7697
+#define V7697 (V + 28669)
+ 0x1109, 0x116b, 0x11b1, 0,
+#undef V7698
+#define V7698 (V + 28673)
+ 0x1109, 0x116b, 0x11b2, 0,
+#undef V7699
+#define V7699 (V + 28677)
+ 0x1109, 0x116b, 0x11b3, 0,
+#undef V7700
+#define V7700 (V + 28681)
+ 0x1109, 0x116b, 0x11b4, 0,
+#undef V7701
+#define V7701 (V + 28685)
+ 0x1109, 0x116b, 0x11b5, 0,
+#undef V7702
+#define V7702 (V + 28689)
+ 0x1109, 0x116b, 0x11b6, 0,
+#undef V7703
+#define V7703 (V + 28693)
+ 0x1109, 0x116b, 0x11b7, 0,
+#undef V7704
+#define V7704 (V + 28697)
+ 0x1109, 0x116b, 0x11b8, 0,
+#undef V7705
+#define V7705 (V + 28701)
+ 0x1109, 0x116b, 0x11b9, 0,
+#undef V7706
+#define V7706 (V + 28705)
+ 0x1109, 0x116b, 0x11ba, 0,
+#undef V7707
+#define V7707 (V + 28709)
+ 0x1109, 0x116b, 0x11bb, 0,
+#undef V7708
+#define V7708 (V + 28713)
+ 0x1109, 0x116b, 0x11bc, 0,
+#undef V7709
+#define V7709 (V + 28717)
+ 0x1109, 0x116b, 0x11bd, 0,
+#undef V7710
+#define V7710 (V + 28721)
+ 0x1109, 0x116b, 0x11be, 0,
+#undef V7711
+#define V7711 (V + 28725)
+ 0x1109, 0x116b, 0x11bf, 0,
+#undef V7712
+#define V7712 (V + 28729)
+ 0x1109, 0x116b, 0x11c0, 0,
+#undef V7713
+#define V7713 (V + 28733)
+ 0x1109, 0x116b, 0x11c1, 0,
+#undef V7714
+#define V7714 (V + 28737)
+ 0x1109, 0x116b, 0x11c2, 0,
+#undef V7715
+#define V7715 (V + 28741)
+ 0x1109, 0x116c, 0,
+#undef V7716
+#define V7716 (V + 28744)
+ 0x1109, 0x116c, 0x11a8, 0,
+#undef V7717
+#define V7717 (V + 28748)
+ 0x1109, 0x116c, 0x11a9, 0,
+#undef V7718
+#define V7718 (V + 28752)
+ 0x1109, 0x116c, 0x11aa, 0,
+#undef V7719
+#define V7719 (V + 28756)
+ 0x1109, 0x116c, 0x11ab, 0,
+#undef V7720
+#define V7720 (V + 28760)
+ 0x1109, 0x116c, 0x11ac, 0,
+#undef V7721
+#define V7721 (V + 28764)
+ 0x1109, 0x116c, 0x11ad, 0,
+#undef V7722
+#define V7722 (V + 28768)
+ 0x1109, 0x116c, 0x11ae, 0,
+#undef V7723
+#define V7723 (V + 28772)
+ 0x1109, 0x116c, 0x11af, 0,
+#undef V7724
+#define V7724 (V + 28776)
+ 0x1109, 0x116c, 0x11b0, 0,
+#undef V7725
+#define V7725 (V + 28780)
+ 0x1109, 0x116c, 0x11b1, 0,
+#undef V7726
+#define V7726 (V + 28784)
+ 0x1109, 0x116c, 0x11b2, 0,
+#undef V7727
+#define V7727 (V + 28788)
+ 0x1109, 0x116c, 0x11b3, 0,
+#undef V7728
+#define V7728 (V + 28792)
+ 0x1109, 0x116c, 0x11b4, 0,
+#undef V7729
+#define V7729 (V + 28796)
+ 0x1109, 0x116c, 0x11b5, 0,
+#undef V7730
+#define V7730 (V + 28800)
+ 0x1109, 0x116c, 0x11b6, 0,
+#undef V7731
+#define V7731 (V + 28804)
+ 0x1109, 0x116c, 0x11b7, 0,
+#undef V7732
+#define V7732 (V + 28808)
+ 0x1109, 0x116c, 0x11b8, 0,
+#undef V7733
+#define V7733 (V + 28812)
+ 0x1109, 0x116c, 0x11b9, 0,
+#undef V7734
+#define V7734 (V + 28816)
+ 0x1109, 0x116c, 0x11ba, 0,
+#undef V7735
+#define V7735 (V + 28820)
+ 0x1109, 0x116c, 0x11bb, 0,
+#undef V7736
+#define V7736 (V + 28824)
+ 0x1109, 0x116c, 0x11bc, 0,
+#undef V7737
+#define V7737 (V + 28828)
+ 0x1109, 0x116c, 0x11bd, 0,
+#undef V7738
+#define V7738 (V + 28832)
+ 0x1109, 0x116c, 0x11be, 0,
+#undef V7739
+#define V7739 (V + 28836)
+ 0x1109, 0x116c, 0x11bf, 0,
+#undef V7740
+#define V7740 (V + 28840)
+ 0x1109, 0x116c, 0x11c0, 0,
+#undef V7741
+#define V7741 (V + 28844)
+ 0x1109, 0x116c, 0x11c1, 0,
+#undef V7742
+#define V7742 (V + 28848)
+ 0x1109, 0x116c, 0x11c2, 0,
+#undef V7743
+#define V7743 (V + 28852)
+ 0x1109, 0x116d, 0,
+#undef V7744
+#define V7744 (V + 28855)
+ 0x1109, 0x116d, 0x11a8, 0,
+#undef V7745
+#define V7745 (V + 28859)
+ 0x1109, 0x116d, 0x11a9, 0,
+#undef V7746
+#define V7746 (V + 28863)
+ 0x1109, 0x116d, 0x11aa, 0,
+#undef V7747
+#define V7747 (V + 28867)
+ 0x1109, 0x116d, 0x11ab, 0,
+#undef V7748
+#define V7748 (V + 28871)
+ 0x1109, 0x116d, 0x11ac, 0,
+#undef V7749
+#define V7749 (V + 28875)
+ 0x1109, 0x116d, 0x11ad, 0,
+#undef V7750
+#define V7750 (V + 28879)
+ 0x1109, 0x116d, 0x11ae, 0,
+#undef V7751
+#define V7751 (V + 28883)
+ 0x1109, 0x116d, 0x11af, 0,
+#undef V7752
+#define V7752 (V + 28887)
+ 0x1109, 0x116d, 0x11b0, 0,
+#undef V7753
+#define V7753 (V + 28891)
+ 0x1109, 0x116d, 0x11b1, 0,
+#undef V7754
+#define V7754 (V + 28895)
+ 0x1109, 0x116d, 0x11b2, 0,
+#undef V7755
+#define V7755 (V + 28899)
+ 0x1109, 0x116d, 0x11b3, 0,
+#undef V7756
+#define V7756 (V + 28903)
+ 0x1109, 0x116d, 0x11b4, 0,
+#undef V7757
+#define V7757 (V + 28907)
+ 0x1109, 0x116d, 0x11b5, 0,
+#undef V7758
+#define V7758 (V + 28911)
+ 0x1109, 0x116d, 0x11b6, 0,
+#undef V7759
+#define V7759 (V + 28915)
+ 0x1109, 0x116d, 0x11b7, 0,
+#undef V7760
+#define V7760 (V + 28919)
+ 0x1109, 0x116d, 0x11b8, 0,
+#undef V7761
+#define V7761 (V + 28923)
+ 0x1109, 0x116d, 0x11b9, 0,
+#undef V7762
+#define V7762 (V + 28927)
+ 0x1109, 0x116d, 0x11ba, 0,
+#undef V7763
+#define V7763 (V + 28931)
+ 0x1109, 0x116d, 0x11bb, 0,
+#undef V7764
+#define V7764 (V + 28935)
+ 0x1109, 0x116d, 0x11bc, 0,
+#undef V7765
+#define V7765 (V + 28939)
+ 0x1109, 0x116d, 0x11bd, 0,
+#undef V7766
+#define V7766 (V + 28943)
+ 0x1109, 0x116d, 0x11be, 0,
+#undef V7767
+#define V7767 (V + 28947)
+ 0x1109, 0x116d, 0x11bf, 0,
+#undef V7768
+#define V7768 (V + 28951)
+ 0x1109, 0x116d, 0x11c0, 0,
+#undef V7769
+#define V7769 (V + 28955)
+ 0x1109, 0x116d, 0x11c1, 0,
+#undef V7770
+#define V7770 (V + 28959)
+ 0x1109, 0x116d, 0x11c2, 0,
+#undef V7771
+#define V7771 (V + 28963)
+ 0x1109, 0x116e, 0,
+#undef V7772
+#define V7772 (V + 28966)
+ 0x1109, 0x116e, 0x11a8, 0,
+#undef V7773
+#define V7773 (V + 28970)
+ 0x1109, 0x116e, 0x11a9, 0,
+#undef V7774
+#define V7774 (V + 28974)
+ 0x1109, 0x116e, 0x11aa, 0,
+#undef V7775
+#define V7775 (V + 28978)
+ 0x1109, 0x116e, 0x11ab, 0,
+#undef V7776
+#define V7776 (V + 28982)
+ 0x1109, 0x116e, 0x11ac, 0,
+#undef V7777
+#define V7777 (V + 28986)
+ 0x1109, 0x116e, 0x11ad, 0,
+#undef V7778
+#define V7778 (V + 28990)
+ 0x1109, 0x116e, 0x11ae, 0,
+#undef V7779
+#define V7779 (V + 28994)
+ 0x1109, 0x116e, 0x11af, 0,
+#undef V7780
+#define V7780 (V + 28998)
+ 0x1109, 0x116e, 0x11b0, 0,
+#undef V7781
+#define V7781 (V + 29002)
+ 0x1109, 0x116e, 0x11b1, 0,
+#undef V7782
+#define V7782 (V + 29006)
+ 0x1109, 0x116e, 0x11b2, 0,
+#undef V7783
+#define V7783 (V + 29010)
+ 0x1109, 0x116e, 0x11b3, 0,
+#undef V7784
+#define V7784 (V + 29014)
+ 0x1109, 0x116e, 0x11b4, 0,
+#undef V7785
+#define V7785 (V + 29018)
+ 0x1109, 0x116e, 0x11b5, 0,
+#undef V7786
+#define V7786 (V + 29022)
+ 0x1109, 0x116e, 0x11b6, 0,
+#undef V7787
+#define V7787 (V + 29026)
+ 0x1109, 0x116e, 0x11b7, 0,
+#undef V7788
+#define V7788 (V + 29030)
+ 0x1109, 0x116e, 0x11b8, 0,
+#undef V7789
+#define V7789 (V + 29034)
+ 0x1109, 0x116e, 0x11b9, 0,
+#undef V7790
+#define V7790 (V + 29038)
+ 0x1109, 0x116e, 0x11ba, 0,
+#undef V7791
+#define V7791 (V + 29042)
+ 0x1109, 0x116e, 0x11bb, 0,
+#undef V7792
+#define V7792 (V + 29046)
+ 0x1109, 0x116e, 0x11bc, 0,
+#undef V7793
+#define V7793 (V + 29050)
+ 0x1109, 0x116e, 0x11bd, 0,
+#undef V7794
+#define V7794 (V + 29054)
+ 0x1109, 0x116e, 0x11be, 0,
+#undef V7795
+#define V7795 (V + 29058)
+ 0x1109, 0x116e, 0x11bf, 0,
+#undef V7796
+#define V7796 (V + 29062)
+ 0x1109, 0x116e, 0x11c0, 0,
+#undef V7797
+#define V7797 (V + 29066)
+ 0x1109, 0x116e, 0x11c1, 0,
+#undef V7798
+#define V7798 (V + 29070)
+ 0x1109, 0x116e, 0x11c2, 0,
+#undef V7799
+#define V7799 (V + 29074)
+ 0x1109, 0x116f, 0,
+#undef V7800
+#define V7800 (V + 29077)
+ 0x1109, 0x116f, 0x11a8, 0,
+#undef V7801
+#define V7801 (V + 29081)
+ 0x1109, 0x116f, 0x11a9, 0,
+#undef V7802
+#define V7802 (V + 29085)
+ 0x1109, 0x116f, 0x11aa, 0,
+#undef V7803
+#define V7803 (V + 29089)
+ 0x1109, 0x116f, 0x11ab, 0,
+#undef V7804
+#define V7804 (V + 29093)
+ 0x1109, 0x116f, 0x11ac, 0,
+#undef V7805
+#define V7805 (V + 29097)
+ 0x1109, 0x116f, 0x11ad, 0,
+#undef V7806
+#define V7806 (V + 29101)
+ 0x1109, 0x116f, 0x11ae, 0,
+#undef V7807
+#define V7807 (V + 29105)
+ 0x1109, 0x116f, 0x11af, 0,
+#undef V7808
+#define V7808 (V + 29109)
+ 0x1109, 0x116f, 0x11b0, 0,
+#undef V7809
+#define V7809 (V + 29113)
+ 0x1109, 0x116f, 0x11b1, 0,
+#undef V7810
+#define V7810 (V + 29117)
+ 0x1109, 0x116f, 0x11b2, 0,
+#undef V7811
+#define V7811 (V + 29121)
+ 0x1109, 0x116f, 0x11b3, 0,
+#undef V7812
+#define V7812 (V + 29125)
+ 0x1109, 0x116f, 0x11b4, 0,
+#undef V7813
+#define V7813 (V + 29129)
+ 0x1109, 0x116f, 0x11b5, 0,
+#undef V7814
+#define V7814 (V + 29133)
+ 0x1109, 0x116f, 0x11b6, 0,
+#undef V7815
+#define V7815 (V + 29137)
+ 0x1109, 0x116f, 0x11b7, 0,
+#undef V7816
+#define V7816 (V + 29141)
+ 0x1109, 0x116f, 0x11b8, 0,
+#undef V7817
+#define V7817 (V + 29145)
+ 0x1109, 0x116f, 0x11b9, 0,
+#undef V7818
+#define V7818 (V + 29149)
+ 0x1109, 0x116f, 0x11ba, 0,
+#undef V7819
+#define V7819 (V + 29153)
+ 0x1109, 0x116f, 0x11bb, 0,
+#undef V7820
+#define V7820 (V + 29157)
+ 0x1109, 0x116f, 0x11bc, 0,
+#undef V7821
+#define V7821 (V + 29161)
+ 0x1109, 0x116f, 0x11bd, 0,
+#undef V7822
+#define V7822 (V + 29165)
+ 0x1109, 0x116f, 0x11be, 0,
+#undef V7823
+#define V7823 (V + 29169)
+ 0x1109, 0x116f, 0x11bf, 0,
+#undef V7824
+#define V7824 (V + 29173)
+ 0x1109, 0x116f, 0x11c0, 0,
+#undef V7825
+#define V7825 (V + 29177)
+ 0x1109, 0x116f, 0x11c1, 0,
+#undef V7826
+#define V7826 (V + 29181)
+ 0x1109, 0x116f, 0x11c2, 0,
+#undef V7827
+#define V7827 (V + 29185)
+ 0x1109, 0x1170, 0,
+#undef V7828
+#define V7828 (V + 29188)
+ 0x1109, 0x1170, 0x11a8, 0,
+#undef V7829
+#define V7829 (V + 29192)
+ 0x1109, 0x1170, 0x11a9, 0,
+#undef V7830
+#define V7830 (V + 29196)
+ 0x1109, 0x1170, 0x11aa, 0,
+#undef V7831
+#define V7831 (V + 29200)
+ 0x1109, 0x1170, 0x11ab, 0,
+#undef V7832
+#define V7832 (V + 29204)
+ 0x1109, 0x1170, 0x11ac, 0,
+#undef V7833
+#define V7833 (V + 29208)
+ 0x1109, 0x1170, 0x11ad, 0,
+#undef V7834
+#define V7834 (V + 29212)
+ 0x1109, 0x1170, 0x11ae, 0,
+#undef V7835
+#define V7835 (V + 29216)
+ 0x1109, 0x1170, 0x11af, 0,
+#undef V7836
+#define V7836 (V + 29220)
+ 0x1109, 0x1170, 0x11b0, 0,
+#undef V7837
+#define V7837 (V + 29224)
+ 0x1109, 0x1170, 0x11b1, 0,
+#undef V7838
+#define V7838 (V + 29228)
+ 0x1109, 0x1170, 0x11b2, 0,
+#undef V7839
+#define V7839 (V + 29232)
+ 0x1109, 0x1170, 0x11b3, 0,
+#undef V7840
+#define V7840 (V + 29236)
+ 0x1109, 0x1170, 0x11b4, 0,
+#undef V7841
+#define V7841 (V + 29240)
+ 0x1109, 0x1170, 0x11b5, 0,
+#undef V7842
+#define V7842 (V + 29244)
+ 0x1109, 0x1170, 0x11b6, 0,
+#undef V7843
+#define V7843 (V + 29248)
+ 0x1109, 0x1170, 0x11b7, 0,
+#undef V7844
+#define V7844 (V + 29252)
+ 0x1109, 0x1170, 0x11b8, 0,
+#undef V7845
+#define V7845 (V + 29256)
+ 0x1109, 0x1170, 0x11b9, 0,
+#undef V7846
+#define V7846 (V + 29260)
+ 0x1109, 0x1170, 0x11ba, 0,
+#undef V7847
+#define V7847 (V + 29264)
+ 0x1109, 0x1170, 0x11bb, 0,
+#undef V7848
+#define V7848 (V + 29268)
+ 0x1109, 0x1170, 0x11bc, 0,
+#undef V7849
+#define V7849 (V + 29272)
+ 0x1109, 0x1170, 0x11bd, 0,
+#undef V7850
+#define V7850 (V + 29276)
+ 0x1109, 0x1170, 0x11be, 0,
+#undef V7851
+#define V7851 (V + 29280)
+ 0x1109, 0x1170, 0x11bf, 0,
+#undef V7852
+#define V7852 (V + 29284)
+ 0x1109, 0x1170, 0x11c0, 0,
+#undef V7853
+#define V7853 (V + 29288)
+ 0x1109, 0x1170, 0x11c1, 0,
+#undef V7854
+#define V7854 (V + 29292)
+ 0x1109, 0x1170, 0x11c2, 0,
+#undef V7855
+#define V7855 (V + 29296)
+ 0x1109, 0x1171, 0,
+#undef V7856
+#define V7856 (V + 29299)
+ 0x1109, 0x1171, 0x11a8, 0,
+#undef V7857
+#define V7857 (V + 29303)
+ 0x1109, 0x1171, 0x11a9, 0,
+#undef V7858
+#define V7858 (V + 29307)
+ 0x1109, 0x1171, 0x11aa, 0,
+#undef V7859
+#define V7859 (V + 29311)
+ 0x1109, 0x1171, 0x11ab, 0,
+#undef V7860
+#define V7860 (V + 29315)
+ 0x1109, 0x1171, 0x11ac, 0,
+#undef V7861
+#define V7861 (V + 29319)
+ 0x1109, 0x1171, 0x11ad, 0,
+#undef V7862
+#define V7862 (V + 29323)
+ 0x1109, 0x1171, 0x11ae, 0,
+#undef V7863
+#define V7863 (V + 29327)
+ 0x1109, 0x1171, 0x11af, 0,
+#undef V7864
+#define V7864 (V + 29331)
+ 0x1109, 0x1171, 0x11b0, 0,
+#undef V7865
+#define V7865 (V + 29335)
+ 0x1109, 0x1171, 0x11b1, 0,
+#undef V7866
+#define V7866 (V + 29339)
+ 0x1109, 0x1171, 0x11b2, 0,
+#undef V7867
+#define V7867 (V + 29343)
+ 0x1109, 0x1171, 0x11b3, 0,
+#undef V7868
+#define V7868 (V + 29347)
+ 0x1109, 0x1171, 0x11b4, 0,
+#undef V7869
+#define V7869 (V + 29351)
+ 0x1109, 0x1171, 0x11b5, 0,
+#undef V7870
+#define V7870 (V + 29355)
+ 0x1109, 0x1171, 0x11b6, 0,
+#undef V7871
+#define V7871 (V + 29359)
+ 0x1109, 0x1171, 0x11b7, 0,
+#undef V7872
+#define V7872 (V + 29363)
+ 0x1109, 0x1171, 0x11b8, 0,
+#undef V7873
+#define V7873 (V + 29367)
+ 0x1109, 0x1171, 0x11b9, 0,
+#undef V7874
+#define V7874 (V + 29371)
+ 0x1109, 0x1171, 0x11ba, 0,
+#undef V7875
+#define V7875 (V + 29375)
+ 0x1109, 0x1171, 0x11bb, 0,
+#undef V7876
+#define V7876 (V + 29379)
+ 0x1109, 0x1171, 0x11bc, 0,
+#undef V7877
+#define V7877 (V + 29383)
+ 0x1109, 0x1171, 0x11bd, 0,
+#undef V7878
+#define V7878 (V + 29387)
+ 0x1109, 0x1171, 0x11be, 0,
+#undef V7879
+#define V7879 (V + 29391)
+ 0x1109, 0x1171, 0x11bf, 0,
+#undef V7880
+#define V7880 (V + 29395)
+ 0x1109, 0x1171, 0x11c0, 0,
+#undef V7881
+#define V7881 (V + 29399)
+ 0x1109, 0x1171, 0x11c1, 0,
+#undef V7882
+#define V7882 (V + 29403)
+ 0x1109, 0x1171, 0x11c2, 0,
+#undef V7883
+#define V7883 (V + 29407)
+ 0x1109, 0x1172, 0,
+#undef V7884
+#define V7884 (V + 29410)
+ 0x1109, 0x1172, 0x11a8, 0,
+#undef V7885
+#define V7885 (V + 29414)
+ 0x1109, 0x1172, 0x11a9, 0,
+#undef V7886
+#define V7886 (V + 29418)
+ 0x1109, 0x1172, 0x11aa, 0,
+#undef V7887
+#define V7887 (V + 29422)
+ 0x1109, 0x1172, 0x11ab, 0,
+#undef V7888
+#define V7888 (V + 29426)
+ 0x1109, 0x1172, 0x11ac, 0,
+#undef V7889
+#define V7889 (V + 29430)
+ 0x1109, 0x1172, 0x11ad, 0,
+#undef V7890
+#define V7890 (V + 29434)
+ 0x1109, 0x1172, 0x11ae, 0,
+#undef V7891
+#define V7891 (V + 29438)
+ 0x1109, 0x1172, 0x11af, 0,
+#undef V7892
+#define V7892 (V + 29442)
+ 0x1109, 0x1172, 0x11b0, 0,
+#undef V7893
+#define V7893 (V + 29446)
+ 0x1109, 0x1172, 0x11b1, 0,
+#undef V7894
+#define V7894 (V + 29450)
+ 0x1109, 0x1172, 0x11b2, 0,
+#undef V7895
+#define V7895 (V + 29454)
+ 0x1109, 0x1172, 0x11b3, 0,
+#undef V7896
+#define V7896 (V + 29458)
+ 0x1109, 0x1172, 0x11b4, 0,
+#undef V7897
+#define V7897 (V + 29462)
+ 0x1109, 0x1172, 0x11b5, 0,
+#undef V7898
+#define V7898 (V + 29466)
+ 0x1109, 0x1172, 0x11b6, 0,
+#undef V7899
+#define V7899 (V + 29470)
+ 0x1109, 0x1172, 0x11b7, 0,
+#undef V7900
+#define V7900 (V + 29474)
+ 0x1109, 0x1172, 0x11b8, 0,
+#undef V7901
+#define V7901 (V + 29478)
+ 0x1109, 0x1172, 0x11b9, 0,
+#undef V7902
+#define V7902 (V + 29482)
+ 0x1109, 0x1172, 0x11ba, 0,
+#undef V7903
+#define V7903 (V + 29486)
+ 0x1109, 0x1172, 0x11bb, 0,
+#undef V7904
+#define V7904 (V + 29490)
+ 0x1109, 0x1172, 0x11bc, 0,
+#undef V7905
+#define V7905 (V + 29494)
+ 0x1109, 0x1172, 0x11bd, 0,
+#undef V7906
+#define V7906 (V + 29498)
+ 0x1109, 0x1172, 0x11be, 0,
+#undef V7907
+#define V7907 (V + 29502)
+ 0x1109, 0x1172, 0x11bf, 0,
+#undef V7908
+#define V7908 (V + 29506)
+ 0x1109, 0x1172, 0x11c0, 0,
+#undef V7909
+#define V7909 (V + 29510)
+ 0x1109, 0x1172, 0x11c1, 0,
+#undef V7910
+#define V7910 (V + 29514)
+ 0x1109, 0x1172, 0x11c2, 0,
+#undef V7911
+#define V7911 (V + 29518)
+ 0x1109, 0x1173, 0,
+#undef V7912
+#define V7912 (V + 29521)
+ 0x1109, 0x1173, 0x11a8, 0,
+#undef V7913
+#define V7913 (V + 29525)
+ 0x1109, 0x1173, 0x11a9, 0,
+#undef V7914
+#define V7914 (V + 29529)
+ 0x1109, 0x1173, 0x11aa, 0,
+#undef V7915
+#define V7915 (V + 29533)
+ 0x1109, 0x1173, 0x11ab, 0,
+#undef V7916
+#define V7916 (V + 29537)
+ 0x1109, 0x1173, 0x11ac, 0,
+#undef V7917
+#define V7917 (V + 29541)
+ 0x1109, 0x1173, 0x11ad, 0,
+#undef V7918
+#define V7918 (V + 29545)
+ 0x1109, 0x1173, 0x11ae, 0,
+#undef V7919
+#define V7919 (V + 29549)
+ 0x1109, 0x1173, 0x11af, 0,
+#undef V7920
+#define V7920 (V + 29553)
+ 0x1109, 0x1173, 0x11b0, 0,
+#undef V7921
+#define V7921 (V + 29557)
+ 0x1109, 0x1173, 0x11b1, 0,
+#undef V7922
+#define V7922 (V + 29561)
+ 0x1109, 0x1173, 0x11b2, 0,
+#undef V7923
+#define V7923 (V + 29565)
+ 0x1109, 0x1173, 0x11b3, 0,
+#undef V7924
+#define V7924 (V + 29569)
+ 0x1109, 0x1173, 0x11b4, 0,
+#undef V7925
+#define V7925 (V + 29573)
+ 0x1109, 0x1173, 0x11b5, 0,
+#undef V7926
+#define V7926 (V + 29577)
+ 0x1109, 0x1173, 0x11b6, 0,
+#undef V7927
+#define V7927 (V + 29581)
+ 0x1109, 0x1173, 0x11b7, 0,
+#undef V7928
+#define V7928 (V + 29585)
+ 0x1109, 0x1173, 0x11b8, 0,
+#undef V7929
+#define V7929 (V + 29589)
+ 0x1109, 0x1173, 0x11b9, 0,
+#undef V7930
+#define V7930 (V + 29593)
+ 0x1109, 0x1173, 0x11ba, 0,
+#undef V7931
+#define V7931 (V + 29597)
+ 0x1109, 0x1173, 0x11bb, 0,
+#undef V7932
+#define V7932 (V + 29601)
+ 0x1109, 0x1173, 0x11bc, 0,
+#undef V7933
+#define V7933 (V + 29605)
+ 0x1109, 0x1173, 0x11bd, 0,
+#undef V7934
+#define V7934 (V + 29609)
+ 0x1109, 0x1173, 0x11be, 0,
+#undef V7935
+#define V7935 (V + 29613)
+ 0x1109, 0x1173, 0x11bf, 0,
+#undef V7936
+#define V7936 (V + 29617)
+ 0x1109, 0x1173, 0x11c0, 0,
+#undef V7937
+#define V7937 (V + 29621)
+ 0x1109, 0x1173, 0x11c1, 0,
+#undef V7938
+#define V7938 (V + 29625)
+ 0x1109, 0x1173, 0x11c2, 0,
+#undef V7939
+#define V7939 (V + 29629)
+ 0x1109, 0x1174, 0,
+#undef V7940
+#define V7940 (V + 29632)
+ 0x1109, 0x1174, 0x11a8, 0,
+#undef V7941
+#define V7941 (V + 29636)
+ 0x1109, 0x1174, 0x11a9, 0,
+#undef V7942
+#define V7942 (V + 29640)
+ 0x1109, 0x1174, 0x11aa, 0,
+#undef V7943
+#define V7943 (V + 29644)
+ 0x1109, 0x1174, 0x11ab, 0,
+#undef V7944
+#define V7944 (V + 29648)
+ 0x1109, 0x1174, 0x11ac, 0,
+#undef V7945
+#define V7945 (V + 29652)
+ 0x1109, 0x1174, 0x11ad, 0,
+#undef V7946
+#define V7946 (V + 29656)
+ 0x1109, 0x1174, 0x11ae, 0,
+#undef V7947
+#define V7947 (V + 29660)
+ 0x1109, 0x1174, 0x11af, 0,
+#undef V7948
+#define V7948 (V + 29664)
+ 0x1109, 0x1174, 0x11b0, 0,
+#undef V7949
+#define V7949 (V + 29668)
+ 0x1109, 0x1174, 0x11b1, 0,
+#undef V7950
+#define V7950 (V + 29672)
+ 0x1109, 0x1174, 0x11b2, 0,
+#undef V7951
+#define V7951 (V + 29676)
+ 0x1109, 0x1174, 0x11b3, 0,
+#undef V7952
+#define V7952 (V + 29680)
+ 0x1109, 0x1174, 0x11b4, 0,
+#undef V7953
+#define V7953 (V + 29684)
+ 0x1109, 0x1174, 0x11b5, 0,
+#undef V7954
+#define V7954 (V + 29688)
+ 0x1109, 0x1174, 0x11b6, 0,
+#undef V7955
+#define V7955 (V + 29692)
+ 0x1109, 0x1174, 0x11b7, 0,
+#undef V7956
+#define V7956 (V + 29696)
+ 0x1109, 0x1174, 0x11b8, 0,
+#undef V7957
+#define V7957 (V + 29700)
+ 0x1109, 0x1174, 0x11b9, 0,
+#undef V7958
+#define V7958 (V + 29704)
+ 0x1109, 0x1174, 0x11ba, 0,
+#undef V7959
+#define V7959 (V + 29708)
+ 0x1109, 0x1174, 0x11bb, 0,
+#undef V7960
+#define V7960 (V + 29712)
+ 0x1109, 0x1174, 0x11bc, 0,
+#undef V7961
+#define V7961 (V + 29716)
+ 0x1109, 0x1174, 0x11bd, 0,
+#undef V7962
+#define V7962 (V + 29720)
+ 0x1109, 0x1174, 0x11be, 0,
+#undef V7963
+#define V7963 (V + 29724)
+ 0x1109, 0x1174, 0x11bf, 0,
+#undef V7964
+#define V7964 (V + 29728)
+ 0x1109, 0x1174, 0x11c0, 0,
+#undef V7965
+#define V7965 (V + 29732)
+ 0x1109, 0x1174, 0x11c1, 0,
+#undef V7966
+#define V7966 (V + 29736)
+ 0x1109, 0x1174, 0x11c2, 0,
+#undef V7967
+#define V7967 (V + 29740)
+ 0x1109, 0x1175, 0,
+#undef V7968
+#define V7968 (V + 29743)
+ 0x1109, 0x1175, 0x11a8, 0,
+#undef V7969
+#define V7969 (V + 29747)
+ 0x1109, 0x1175, 0x11a9, 0,
+#undef V7970
+#define V7970 (V + 29751)
+ 0x1109, 0x1175, 0x11aa, 0,
+#undef V7971
+#define V7971 (V + 29755)
+ 0x1109, 0x1175, 0x11ab, 0,
+#undef V7972
+#define V7972 (V + 29759)
+ 0x1109, 0x1175, 0x11ac, 0,
+#undef V7973
+#define V7973 (V + 29763)
+ 0x1109, 0x1175, 0x11ad, 0,
+#undef V7974
+#define V7974 (V + 29767)
+ 0x1109, 0x1175, 0x11ae, 0,
+#undef V7975
+#define V7975 (V + 29771)
+ 0x1109, 0x1175, 0x11af, 0,
+#undef V7976
+#define V7976 (V + 29775)
+ 0x1109, 0x1175, 0x11b0, 0,
+#undef V7977
+#define V7977 (V + 29779)
+ 0x1109, 0x1175, 0x11b1, 0,
+#undef V7978
+#define V7978 (V + 29783)
+ 0x1109, 0x1175, 0x11b2, 0,
+#undef V7979
+#define V7979 (V + 29787)
+ 0x1109, 0x1175, 0x11b3, 0,
+#undef V7980
+#define V7980 (V + 29791)
+ 0x1109, 0x1175, 0x11b4, 0,
+#undef V7981
+#define V7981 (V + 29795)
+ 0x1109, 0x1175, 0x11b5, 0,
+#undef V7982
+#define V7982 (V + 29799)
+ 0x1109, 0x1175, 0x11b6, 0,
+#undef V7983
+#define V7983 (V + 29803)
+ 0x1109, 0x1175, 0x11b7, 0,
+#undef V7984
+#define V7984 (V + 29807)
+ 0x1109, 0x1175, 0x11b8, 0,
+#undef V7985
+#define V7985 (V + 29811)
+ 0x1109, 0x1175, 0x11b9, 0,
+#undef V7986
+#define V7986 (V + 29815)
+ 0x1109, 0x1175, 0x11ba, 0,
+#undef V7987
+#define V7987 (V + 29819)
+ 0x1109, 0x1175, 0x11bb, 0,
+#undef V7988
+#define V7988 (V + 29823)
+ 0x1109, 0x1175, 0x11bc, 0,
+#undef V7989
+#define V7989 (V + 29827)
+ 0x1109, 0x1175, 0x11bd, 0,
+#undef V7990
+#define V7990 (V + 29831)
+ 0x1109, 0x1175, 0x11be, 0,
+#undef V7991
+#define V7991 (V + 29835)
+ 0x1109, 0x1175, 0x11bf, 0,
+#undef V7992
+#define V7992 (V + 29839)
+ 0x1109, 0x1175, 0x11c0, 0,
+#undef V7993
+#define V7993 (V + 29843)
+ 0x1109, 0x1175, 0x11c1, 0,
+#undef V7994
+#define V7994 (V + 29847)
+ 0x1109, 0x1175, 0x11c2, 0,
+#undef V7995
+#define V7995 (V + 29851)
+ 0x110a, 0x1161, 0,
+#undef V7996
+#define V7996 (V + 29854)
+ 0x110a, 0x1161, 0x11a8, 0,
+#undef V7997
+#define V7997 (V + 29858)
+ 0x110a, 0x1161, 0x11a9, 0,
+#undef V7998
+#define V7998 (V + 29862)
+ 0x110a, 0x1161, 0x11aa, 0,
+#undef V7999
+#define V7999 (V + 29866)
+ 0x110a, 0x1161, 0x11ab, 0,
+#undef V8000
+#define V8000 (V + 29870)
+ 0x110a, 0x1161, 0x11ac, 0,
+#undef V8001
+#define V8001 (V + 29874)
+ 0x110a, 0x1161, 0x11ad, 0,
+#undef V8002
+#define V8002 (V + 29878)
+ 0x110a, 0x1161, 0x11ae, 0,
+#undef V8003
+#define V8003 (V + 29882)
+ 0x110a, 0x1161, 0x11af, 0,
+#undef V8004
+#define V8004 (V + 29886)
+ 0x110a, 0x1161, 0x11b0, 0,
+#undef V8005
+#define V8005 (V + 29890)
+ 0x110a, 0x1161, 0x11b1, 0,
+#undef V8006
+#define V8006 (V + 29894)
+ 0x110a, 0x1161, 0x11b2, 0,
+#undef V8007
+#define V8007 (V + 29898)
+ 0x110a, 0x1161, 0x11b3, 0,
+#undef V8008
+#define V8008 (V + 29902)
+ 0x110a, 0x1161, 0x11b4, 0,
+#undef V8009
+#define V8009 (V + 29906)
+ 0x110a, 0x1161, 0x11b5, 0,
+#undef V8010
+#define V8010 (V + 29910)
+ 0x110a, 0x1161, 0x11b6, 0,
+#undef V8011
+#define V8011 (V + 29914)
+ 0x110a, 0x1161, 0x11b7, 0,
+#undef V8012
+#define V8012 (V + 29918)
+ 0x110a, 0x1161, 0x11b8, 0,
+#undef V8013
+#define V8013 (V + 29922)
+ 0x110a, 0x1161, 0x11b9, 0,
+#undef V8014
+#define V8014 (V + 29926)
+ 0x110a, 0x1161, 0x11ba, 0,
+#undef V8015
+#define V8015 (V + 29930)
+ 0x110a, 0x1161, 0x11bb, 0,
+#undef V8016
+#define V8016 (V + 29934)
+ 0x110a, 0x1161, 0x11bc, 0,
+#undef V8017
+#define V8017 (V + 29938)
+ 0x110a, 0x1161, 0x11bd, 0,
+#undef V8018
+#define V8018 (V + 29942)
+ 0x110a, 0x1161, 0x11be, 0,
+#undef V8019
+#define V8019 (V + 29946)
+ 0x110a, 0x1161, 0x11bf, 0,
+#undef V8020
+#define V8020 (V + 29950)
+ 0x110a, 0x1161, 0x11c0, 0,
+#undef V8021
+#define V8021 (V + 29954)
+ 0x110a, 0x1161, 0x11c1, 0,
+#undef V8022
+#define V8022 (V + 29958)
+ 0x110a, 0x1161, 0x11c2, 0,
+#undef V8023
+#define V8023 (V + 29962)
+ 0x110a, 0x1162, 0,
+#undef V8024
+#define V8024 (V + 29965)
+ 0x110a, 0x1162, 0x11a8, 0,
+#undef V8025
+#define V8025 (V + 29969)
+ 0x110a, 0x1162, 0x11a9, 0,
+#undef V8026
+#define V8026 (V + 29973)
+ 0x110a, 0x1162, 0x11aa, 0,
+#undef V8027
+#define V8027 (V + 29977)
+ 0x110a, 0x1162, 0x11ab, 0,
+#undef V8028
+#define V8028 (V + 29981)
+ 0x110a, 0x1162, 0x11ac, 0,
+#undef V8029
+#define V8029 (V + 29985)
+ 0x110a, 0x1162, 0x11ad, 0,
+#undef V8030
+#define V8030 (V + 29989)
+ 0x110a, 0x1162, 0x11ae, 0,
+#undef V8031
+#define V8031 (V + 29993)
+ 0x110a, 0x1162, 0x11af, 0,
+#undef V8032
+#define V8032 (V + 29997)
+ 0x110a, 0x1162, 0x11b0, 0,
+#undef V8033
+#define V8033 (V + 30001)
+ 0x110a, 0x1162, 0x11b1, 0,
+#undef V8034
+#define V8034 (V + 30005)
+ 0x110a, 0x1162, 0x11b2, 0,
+#undef V8035
+#define V8035 (V + 30009)
+ 0x110a, 0x1162, 0x11b3, 0,
+#undef V8036
+#define V8036 (V + 30013)
+ 0x110a, 0x1162, 0x11b4, 0,
+#undef V8037
+#define V8037 (V + 30017)
+ 0x110a, 0x1162, 0x11b5, 0,
+#undef V8038
+#define V8038 (V + 30021)
+ 0x110a, 0x1162, 0x11b6, 0,
+#undef V8039
+#define V8039 (V + 30025)
+ 0x110a, 0x1162, 0x11b7, 0,
+#undef V8040
+#define V8040 (V + 30029)
+ 0x110a, 0x1162, 0x11b8, 0,
+#undef V8041
+#define V8041 (V + 30033)
+ 0x110a, 0x1162, 0x11b9, 0,
+#undef V8042
+#define V8042 (V + 30037)
+ 0x110a, 0x1162, 0x11ba, 0,
+#undef V8043
+#define V8043 (V + 30041)
+ 0x110a, 0x1162, 0x11bb, 0,
+#undef V8044
+#define V8044 (V + 30045)
+ 0x110a, 0x1162, 0x11bc, 0,
+#undef V8045
+#define V8045 (V + 30049)
+ 0x110a, 0x1162, 0x11bd, 0,
+#undef V8046
+#define V8046 (V + 30053)
+ 0x110a, 0x1162, 0x11be, 0,
+#undef V8047
+#define V8047 (V + 30057)
+ 0x110a, 0x1162, 0x11bf, 0,
+#undef V8048
+#define V8048 (V + 30061)
+ 0x110a, 0x1162, 0x11c0, 0,
+#undef V8049
+#define V8049 (V + 30065)
+ 0x110a, 0x1162, 0x11c1, 0,
+#undef V8050
+#define V8050 (V + 30069)
+ 0x110a, 0x1162, 0x11c2, 0,
+#undef V8051
+#define V8051 (V + 30073)
+ 0x110a, 0x1163, 0,
+#undef V8052
+#define V8052 (V + 30076)
+ 0x110a, 0x1163, 0x11a8, 0,
+#undef V8053
+#define V8053 (V + 30080)
+ 0x110a, 0x1163, 0x11a9, 0,
+#undef V8054
+#define V8054 (V + 30084)
+ 0x110a, 0x1163, 0x11aa, 0,
+#undef V8055
+#define V8055 (V + 30088)
+ 0x110a, 0x1163, 0x11ab, 0,
+#undef V8056
+#define V8056 (V + 30092)
+ 0x110a, 0x1163, 0x11ac, 0,
+#undef V8057
+#define V8057 (V + 30096)
+ 0x110a, 0x1163, 0x11ad, 0,
+#undef V8058
+#define V8058 (V + 30100)
+ 0x110a, 0x1163, 0x11ae, 0,
+#undef V8059
+#define V8059 (V + 30104)
+ 0x110a, 0x1163, 0x11af, 0,
+#undef V8060
+#define V8060 (V + 30108)
+ 0x110a, 0x1163, 0x11b0, 0,
+#undef V8061
+#define V8061 (V + 30112)
+ 0x110a, 0x1163, 0x11b1, 0,
+#undef V8062
+#define V8062 (V + 30116)
+ 0x110a, 0x1163, 0x11b2, 0,
+#undef V8063
+#define V8063 (V + 30120)
+ 0x110a, 0x1163, 0x11b3, 0,
+#undef V8064
+#define V8064 (V + 30124)
+ 0x110a, 0x1163, 0x11b4, 0,
+#undef V8065
+#define V8065 (V + 30128)
+ 0x110a, 0x1163, 0x11b5, 0,
+#undef V8066
+#define V8066 (V + 30132)
+ 0x110a, 0x1163, 0x11b6, 0,
+#undef V8067
+#define V8067 (V + 30136)
+ 0x110a, 0x1163, 0x11b7, 0,
+#undef V8068
+#define V8068 (V + 30140)
+ 0x110a, 0x1163, 0x11b8, 0,
+#undef V8069
+#define V8069 (V + 30144)
+ 0x110a, 0x1163, 0x11b9, 0,
+#undef V8070
+#define V8070 (V + 30148)
+ 0x110a, 0x1163, 0x11ba, 0,
+#undef V8071
+#define V8071 (V + 30152)
+ 0x110a, 0x1163, 0x11bb, 0,
+#undef V8072
+#define V8072 (V + 30156)
+ 0x110a, 0x1163, 0x11bc, 0,
+#undef V8073
+#define V8073 (V + 30160)
+ 0x110a, 0x1163, 0x11bd, 0,
+#undef V8074
+#define V8074 (V + 30164)
+ 0x110a, 0x1163, 0x11be, 0,
+#undef V8075
+#define V8075 (V + 30168)
+ 0x110a, 0x1163, 0x11bf, 0,
+#undef V8076
+#define V8076 (V + 30172)
+ 0x110a, 0x1163, 0x11c0, 0,
+#undef V8077
+#define V8077 (V + 30176)
+ 0x110a, 0x1163, 0x11c1, 0,
+#undef V8078
+#define V8078 (V + 30180)
+ 0x110a, 0x1163, 0x11c2, 0,
+#undef V8079
+#define V8079 (V + 30184)
+ 0x110a, 0x1164, 0,
+#undef V8080
+#define V8080 (V + 30187)
+ 0x110a, 0x1164, 0x11a8, 0,
+#undef V8081
+#define V8081 (V + 30191)
+ 0x110a, 0x1164, 0x11a9, 0,
+#undef V8082
+#define V8082 (V + 30195)
+ 0x110a, 0x1164, 0x11aa, 0,
+#undef V8083
+#define V8083 (V + 30199)
+ 0x110a, 0x1164, 0x11ab, 0,
+#undef V8084
+#define V8084 (V + 30203)
+ 0x110a, 0x1164, 0x11ac, 0,
+#undef V8085
+#define V8085 (V + 30207)
+ 0x110a, 0x1164, 0x11ad, 0,
+#undef V8086
+#define V8086 (V + 30211)
+ 0x110a, 0x1164, 0x11ae, 0,
+#undef V8087
+#define V8087 (V + 30215)
+ 0x110a, 0x1164, 0x11af, 0,
+#undef V8088
+#define V8088 (V + 30219)
+ 0x110a, 0x1164, 0x11b0, 0,
+#undef V8089
+#define V8089 (V + 30223)
+ 0x110a, 0x1164, 0x11b1, 0,
+#undef V8090
+#define V8090 (V + 30227)
+ 0x110a, 0x1164, 0x11b2, 0,
+#undef V8091
+#define V8091 (V + 30231)
+ 0x110a, 0x1164, 0x11b3, 0,
+#undef V8092
+#define V8092 (V + 30235)
+ 0x110a, 0x1164, 0x11b4, 0,
+#undef V8093
+#define V8093 (V + 30239)
+ 0x110a, 0x1164, 0x11b5, 0,
+#undef V8094
+#define V8094 (V + 30243)
+ 0x110a, 0x1164, 0x11b6, 0,
+#undef V8095
+#define V8095 (V + 30247)
+ 0x110a, 0x1164, 0x11b7, 0,
+#undef V8096
+#define V8096 (V + 30251)
+ 0x110a, 0x1164, 0x11b8, 0,
+#undef V8097
+#define V8097 (V + 30255)
+ 0x110a, 0x1164, 0x11b9, 0,
+#undef V8098
+#define V8098 (V + 30259)
+ 0x110a, 0x1164, 0x11ba, 0,
+#undef V8099
+#define V8099 (V + 30263)
+ 0x110a, 0x1164, 0x11bb, 0,
+#undef V8100
+#define V8100 (V + 30267)
+ 0x110a, 0x1164, 0x11bc, 0,
+#undef V8101
+#define V8101 (V + 30271)
+ 0x110a, 0x1164, 0x11bd, 0,
+#undef V8102
+#define V8102 (V + 30275)
+ 0x110a, 0x1164, 0x11be, 0,
+#undef V8103
+#define V8103 (V + 30279)
+ 0x110a, 0x1164, 0x11bf, 0,
+#undef V8104
+#define V8104 (V + 30283)
+ 0x110a, 0x1164, 0x11c0, 0,
+#undef V8105
+#define V8105 (V + 30287)
+ 0x110a, 0x1164, 0x11c1, 0,
+#undef V8106
+#define V8106 (V + 30291)
+ 0x110a, 0x1164, 0x11c2, 0,
+#undef V8107
+#define V8107 (V + 30295)
+ 0x110a, 0x1165, 0,
+#undef V8108
+#define V8108 (V + 30298)
+ 0x110a, 0x1165, 0x11a8, 0,
+#undef V8109
+#define V8109 (V + 30302)
+ 0x110a, 0x1165, 0x11a9, 0,
+#undef V8110
+#define V8110 (V + 30306)
+ 0x110a, 0x1165, 0x11aa, 0,
+#undef V8111
+#define V8111 (V + 30310)
+ 0x110a, 0x1165, 0x11ab, 0,
+#undef V8112
+#define V8112 (V + 30314)
+ 0x110a, 0x1165, 0x11ac, 0,
+#undef V8113
+#define V8113 (V + 30318)
+ 0x110a, 0x1165, 0x11ad, 0,
+#undef V8114
+#define V8114 (V + 30322)
+ 0x110a, 0x1165, 0x11ae, 0,
+#undef V8115
+#define V8115 (V + 30326)
+ 0x110a, 0x1165, 0x11af, 0,
+#undef V8116
+#define V8116 (V + 30330)
+ 0x110a, 0x1165, 0x11b0, 0,
+#undef V8117
+#define V8117 (V + 30334)
+ 0x110a, 0x1165, 0x11b1, 0,
+#undef V8118
+#define V8118 (V + 30338)
+ 0x110a, 0x1165, 0x11b2, 0,
+#undef V8119
+#define V8119 (V + 30342)
+ 0x110a, 0x1165, 0x11b3, 0,
+#undef V8120
+#define V8120 (V + 30346)
+ 0x110a, 0x1165, 0x11b4, 0,
+#undef V8121
+#define V8121 (V + 30350)
+ 0x110a, 0x1165, 0x11b5, 0,
+#undef V8122
+#define V8122 (V + 30354)
+ 0x110a, 0x1165, 0x11b6, 0,
+#undef V8123
+#define V8123 (V + 30358)
+ 0x110a, 0x1165, 0x11b7, 0,
+#undef V8124
+#define V8124 (V + 30362)
+ 0x110a, 0x1165, 0x11b8, 0,
+#undef V8125
+#define V8125 (V + 30366)
+ 0x110a, 0x1165, 0x11b9, 0,
+#undef V8126
+#define V8126 (V + 30370)
+ 0x110a, 0x1165, 0x11ba, 0,
+#undef V8127
+#define V8127 (V + 30374)
+ 0x110a, 0x1165, 0x11bb, 0,
+#undef V8128
+#define V8128 (V + 30378)
+ 0x110a, 0x1165, 0x11bc, 0,
+#undef V8129
+#define V8129 (V + 30382)
+ 0x110a, 0x1165, 0x11bd, 0,
+#undef V8130
+#define V8130 (V + 30386)
+ 0x110a, 0x1165, 0x11be, 0,
+#undef V8131
+#define V8131 (V + 30390)
+ 0x110a, 0x1165, 0x11bf, 0,
+#undef V8132
+#define V8132 (V + 30394)
+ 0x110a, 0x1165, 0x11c0, 0,
+#undef V8133
+#define V8133 (V + 30398)
+ 0x110a, 0x1165, 0x11c1, 0,
+#undef V8134
+#define V8134 (V + 30402)
+ 0x110a, 0x1165, 0x11c2, 0,
+#undef V8135
+#define V8135 (V + 30406)
+ 0x110a, 0x1166, 0,
+#undef V8136
+#define V8136 (V + 30409)
+ 0x110a, 0x1166, 0x11a8, 0,
+#undef V8137
+#define V8137 (V + 30413)
+ 0x110a, 0x1166, 0x11a9, 0,
+#undef V8138
+#define V8138 (V + 30417)
+ 0x110a, 0x1166, 0x11aa, 0,
+#undef V8139
+#define V8139 (V + 30421)
+ 0x110a, 0x1166, 0x11ab, 0,
+#undef V8140
+#define V8140 (V + 30425)
+ 0x110a, 0x1166, 0x11ac, 0,
+#undef V8141
+#define V8141 (V + 30429)
+ 0x110a, 0x1166, 0x11ad, 0,
+#undef V8142
+#define V8142 (V + 30433)
+ 0x110a, 0x1166, 0x11ae, 0,
+#undef V8143
+#define V8143 (V + 30437)
+ 0x110a, 0x1166, 0x11af, 0,
+#undef V8144
+#define V8144 (V + 30441)
+ 0x110a, 0x1166, 0x11b0, 0,
+#undef V8145
+#define V8145 (V + 30445)
+ 0x110a, 0x1166, 0x11b1, 0,
+#undef V8146
+#define V8146 (V + 30449)
+ 0x110a, 0x1166, 0x11b2, 0,
+#undef V8147
+#define V8147 (V + 30453)
+ 0x110a, 0x1166, 0x11b3, 0,
+#undef V8148
+#define V8148 (V + 30457)
+ 0x110a, 0x1166, 0x11b4, 0,
+#undef V8149
+#define V8149 (V + 30461)
+ 0x110a, 0x1166, 0x11b5, 0,
+#undef V8150
+#define V8150 (V + 30465)
+ 0x110a, 0x1166, 0x11b6, 0,
+#undef V8151
+#define V8151 (V + 30469)
+ 0x110a, 0x1166, 0x11b7, 0,
+#undef V8152
+#define V8152 (V + 30473)
+ 0x110a, 0x1166, 0x11b8, 0,
+#undef V8153
+#define V8153 (V + 30477)
+ 0x110a, 0x1166, 0x11b9, 0,
+#undef V8154
+#define V8154 (V + 30481)
+ 0x110a, 0x1166, 0x11ba, 0,
+#undef V8155
+#define V8155 (V + 30485)
+ 0x110a, 0x1166, 0x11bb, 0,
+#undef V8156
+#define V8156 (V + 30489)
+ 0x110a, 0x1166, 0x11bc, 0,
+#undef V8157
+#define V8157 (V + 30493)
+ 0x110a, 0x1166, 0x11bd, 0,
+#undef V8158
+#define V8158 (V + 30497)
+ 0x110a, 0x1166, 0x11be, 0,
+#undef V8159
+#define V8159 (V + 30501)
+ 0x110a, 0x1166, 0x11bf, 0,
+#undef V8160
+#define V8160 (V + 30505)
+ 0x110a, 0x1166, 0x11c0, 0,
+#undef V8161
+#define V8161 (V + 30509)
+ 0x110a, 0x1166, 0x11c1, 0,
+#undef V8162
+#define V8162 (V + 30513)
+ 0x110a, 0x1166, 0x11c2, 0,
+#undef V8163
+#define V8163 (V + 30517)
+ 0x110a, 0x1167, 0,
+#undef V8164
+#define V8164 (V + 30520)
+ 0x110a, 0x1167, 0x11a8, 0,
+#undef V8165
+#define V8165 (V + 30524)
+ 0x110a, 0x1167, 0x11a9, 0,
+#undef V8166
+#define V8166 (V + 30528)
+ 0x110a, 0x1167, 0x11aa, 0,
+#undef V8167
+#define V8167 (V + 30532)
+ 0x110a, 0x1167, 0x11ab, 0,
+#undef V8168
+#define V8168 (V + 30536)
+ 0x110a, 0x1167, 0x11ac, 0,
+#undef V8169
+#define V8169 (V + 30540)
+ 0x110a, 0x1167, 0x11ad, 0,
+#undef V8170
+#define V8170 (V + 30544)
+ 0x110a, 0x1167, 0x11ae, 0,
+#undef V8171
+#define V8171 (V + 30548)
+ 0x110a, 0x1167, 0x11af, 0,
+#undef V8172
+#define V8172 (V + 30552)
+ 0x110a, 0x1167, 0x11b0, 0,
+#undef V8173
+#define V8173 (V + 30556)
+ 0x110a, 0x1167, 0x11b1, 0,
+#undef V8174
+#define V8174 (V + 30560)
+ 0x110a, 0x1167, 0x11b2, 0,
+#undef V8175
+#define V8175 (V + 30564)
+ 0x110a, 0x1167, 0x11b3, 0,
+#undef V8176
+#define V8176 (V + 30568)
+ 0x110a, 0x1167, 0x11b4, 0,
+#undef V8177
+#define V8177 (V + 30572)
+ 0x110a, 0x1167, 0x11b5, 0,
+#undef V8178
+#define V8178 (V + 30576)
+ 0x110a, 0x1167, 0x11b6, 0,
+#undef V8179
+#define V8179 (V + 30580)
+ 0x110a, 0x1167, 0x11b7, 0,
+#undef V8180
+#define V8180 (V + 30584)
+ 0x110a, 0x1167, 0x11b8, 0,
+#undef V8181
+#define V8181 (V + 30588)
+ 0x110a, 0x1167, 0x11b9, 0,
+#undef V8182
+#define V8182 (V + 30592)
+ 0x110a, 0x1167, 0x11ba, 0,
+#undef V8183
+#define V8183 (V + 30596)
+ 0x110a, 0x1167, 0x11bb, 0,
+#undef V8184
+#define V8184 (V + 30600)
+ 0x110a, 0x1167, 0x11bc, 0,
+#undef V8185
+#define V8185 (V + 30604)
+ 0x110a, 0x1167, 0x11bd, 0,
+#undef V8186
+#define V8186 (V + 30608)
+ 0x110a, 0x1167, 0x11be, 0,
+#undef V8187
+#define V8187 (V + 30612)
+ 0x110a, 0x1167, 0x11bf, 0,
+#undef V8188
+#define V8188 (V + 30616)
+ 0x110a, 0x1167, 0x11c0, 0,
+#undef V8189
+#define V8189 (V + 30620)
+ 0x110a, 0x1167, 0x11c1, 0,
+#undef V8190
+#define V8190 (V + 30624)
+ 0x110a, 0x1167, 0x11c2, 0,
+#undef V8191
+#define V8191 (V + 30628)
+ 0x110a, 0x1168, 0,
+#undef V8192
+#define V8192 (V + 30631)
+ 0x110a, 0x1168, 0x11a8, 0,
+#undef V8193
+#define V8193 (V + 30635)
+ 0x110a, 0x1168, 0x11a9, 0,
+#undef V8194
+#define V8194 (V + 30639)
+ 0x110a, 0x1168, 0x11aa, 0,
+#undef V8195
+#define V8195 (V + 30643)
+ 0x110a, 0x1168, 0x11ab, 0,
+#undef V8196
+#define V8196 (V + 30647)
+ 0x110a, 0x1168, 0x11ac, 0,
+#undef V8197
+#define V8197 (V + 30651)
+ 0x110a, 0x1168, 0x11ad, 0,
+#undef V8198
+#define V8198 (V + 30655)
+ 0x110a, 0x1168, 0x11ae, 0,
+#undef V8199
+#define V8199 (V + 30659)
+ 0x110a, 0x1168, 0x11af, 0,
+#undef V8200
+#define V8200 (V + 30663)
+ 0x110a, 0x1168, 0x11b0, 0,
+#undef V8201
+#define V8201 (V + 30667)
+ 0x110a, 0x1168, 0x11b1, 0,
+#undef V8202
+#define V8202 (V + 30671)
+ 0x110a, 0x1168, 0x11b2, 0,
+#undef V8203
+#define V8203 (V + 30675)
+ 0x110a, 0x1168, 0x11b3, 0,
+#undef V8204
+#define V8204 (V + 30679)
+ 0x110a, 0x1168, 0x11b4, 0,
+#undef V8205
+#define V8205 (V + 30683)
+ 0x110a, 0x1168, 0x11b5, 0,
+#undef V8206
+#define V8206 (V + 30687)
+ 0x110a, 0x1168, 0x11b6, 0,
+#undef V8207
+#define V8207 (V + 30691)
+ 0x110a, 0x1168, 0x11b7, 0,
+#undef V8208
+#define V8208 (V + 30695)
+ 0x110a, 0x1168, 0x11b8, 0,
+#undef V8209
+#define V8209 (V + 30699)
+ 0x110a, 0x1168, 0x11b9, 0,
+#undef V8210
+#define V8210 (V + 30703)
+ 0x110a, 0x1168, 0x11ba, 0,
+#undef V8211
+#define V8211 (V + 30707)
+ 0x110a, 0x1168, 0x11bb, 0,
+#undef V8212
+#define V8212 (V + 30711)
+ 0x110a, 0x1168, 0x11bc, 0,
+#undef V8213
+#define V8213 (V + 30715)
+ 0x110a, 0x1168, 0x11bd, 0,
+#undef V8214
+#define V8214 (V + 30719)
+ 0x110a, 0x1168, 0x11be, 0,
+#undef V8215
+#define V8215 (V + 30723)
+ 0x110a, 0x1168, 0x11bf, 0,
+#undef V8216
+#define V8216 (V + 30727)
+ 0x110a, 0x1168, 0x11c0, 0,
+#undef V8217
+#define V8217 (V + 30731)
+ 0x110a, 0x1168, 0x11c1, 0,
+#undef V8218
+#define V8218 (V + 30735)
+ 0x110a, 0x1168, 0x11c2, 0,
+#undef V8219
+#define V8219 (V + 30739)
+ 0x110a, 0x1169, 0,
+#undef V8220
+#define V8220 (V + 30742)
+ 0x110a, 0x1169, 0x11a8, 0,
+#undef V8221
+#define V8221 (V + 30746)
+ 0x110a, 0x1169, 0x11a9, 0,
+#undef V8222
+#define V8222 (V + 30750)
+ 0x110a, 0x1169, 0x11aa, 0,
+#undef V8223
+#define V8223 (V + 30754)
+ 0x110a, 0x1169, 0x11ab, 0,
+#undef V8224
+#define V8224 (V + 30758)
+ 0x110a, 0x1169, 0x11ac, 0,
+#undef V8225
+#define V8225 (V + 30762)
+ 0x110a, 0x1169, 0x11ad, 0,
+#undef V8226
+#define V8226 (V + 30766)
+ 0x110a, 0x1169, 0x11ae, 0,
+#undef V8227
+#define V8227 (V + 30770)
+ 0x110a, 0x1169, 0x11af, 0,
+#undef V8228
+#define V8228 (V + 30774)
+ 0x110a, 0x1169, 0x11b0, 0,
+#undef V8229
+#define V8229 (V + 30778)
+ 0x110a, 0x1169, 0x11b1, 0,
+#undef V8230
+#define V8230 (V + 30782)
+ 0x110a, 0x1169, 0x11b2, 0,
+#undef V8231
+#define V8231 (V + 30786)
+ 0x110a, 0x1169, 0x11b3, 0,
+#undef V8232
+#define V8232 (V + 30790)
+ 0x110a, 0x1169, 0x11b4, 0,
+#undef V8233
+#define V8233 (V + 30794)
+ 0x110a, 0x1169, 0x11b5, 0,
+#undef V8234
+#define V8234 (V + 30798)
+ 0x110a, 0x1169, 0x11b6, 0,
+#undef V8235
+#define V8235 (V + 30802)
+ 0x110a, 0x1169, 0x11b7, 0,
+#undef V8236
+#define V8236 (V + 30806)
+ 0x110a, 0x1169, 0x11b8, 0,
+#undef V8237
+#define V8237 (V + 30810)
+ 0x110a, 0x1169, 0x11b9, 0,
+#undef V8238
+#define V8238 (V + 30814)
+ 0x110a, 0x1169, 0x11ba, 0,
+#undef V8239
+#define V8239 (V + 30818)
+ 0x110a, 0x1169, 0x11bb, 0,
+#undef V8240
+#define V8240 (V + 30822)
+ 0x110a, 0x1169, 0x11bc, 0,
+#undef V8241
+#define V8241 (V + 30826)
+ 0x110a, 0x1169, 0x11bd, 0,
+#undef V8242
+#define V8242 (V + 30830)
+ 0x110a, 0x1169, 0x11be, 0,
+#undef V8243
+#define V8243 (V + 30834)
+ 0x110a, 0x1169, 0x11bf, 0,
+#undef V8244
+#define V8244 (V + 30838)
+ 0x110a, 0x1169, 0x11c0, 0,
+#undef V8245
+#define V8245 (V + 30842)
+ 0x110a, 0x1169, 0x11c1, 0,
+#undef V8246
+#define V8246 (V + 30846)
+ 0x110a, 0x1169, 0x11c2, 0,
+#undef V8247
+#define V8247 (V + 30850)
+ 0x110a, 0x116a, 0,
+#undef V8248
+#define V8248 (V + 30853)
+ 0x110a, 0x116a, 0x11a8, 0,
+#undef V8249
+#define V8249 (V + 30857)
+ 0x110a, 0x116a, 0x11a9, 0,
+#undef V8250
+#define V8250 (V + 30861)
+ 0x110a, 0x116a, 0x11aa, 0,
+#undef V8251
+#define V8251 (V + 30865)
+ 0x110a, 0x116a, 0x11ab, 0,
+#undef V8252
+#define V8252 (V + 30869)
+ 0x110a, 0x116a, 0x11ac, 0,
+#undef V8253
+#define V8253 (V + 30873)
+ 0x110a, 0x116a, 0x11ad, 0,
+#undef V8254
+#define V8254 (V + 30877)
+ 0x110a, 0x116a, 0x11ae, 0,
+#undef V8255
+#define V8255 (V + 30881)
+ 0x110a, 0x116a, 0x11af, 0,
+#undef V8256
+#define V8256 (V + 30885)
+ 0x110a, 0x116a, 0x11b0, 0,
+#undef V8257
+#define V8257 (V + 30889)
+ 0x110a, 0x116a, 0x11b1, 0,
+#undef V8258
+#define V8258 (V + 30893)
+ 0x110a, 0x116a, 0x11b2, 0,
+#undef V8259
+#define V8259 (V + 30897)
+ 0x110a, 0x116a, 0x11b3, 0,
+#undef V8260
+#define V8260 (V + 30901)
+ 0x110a, 0x116a, 0x11b4, 0,
+#undef V8261
+#define V8261 (V + 30905)
+ 0x110a, 0x116a, 0x11b5, 0,
+#undef V8262
+#define V8262 (V + 30909)
+ 0x110a, 0x116a, 0x11b6, 0,
+#undef V8263
+#define V8263 (V + 30913)
+ 0x110a, 0x116a, 0x11b7, 0,
+#undef V8264
+#define V8264 (V + 30917)
+ 0x110a, 0x116a, 0x11b8, 0,
+#undef V8265
+#define V8265 (V + 30921)
+ 0x110a, 0x116a, 0x11b9, 0,
+#undef V8266
+#define V8266 (V + 30925)
+ 0x110a, 0x116a, 0x11ba, 0,
+#undef V8267
+#define V8267 (V + 30929)
+ 0x110a, 0x116a, 0x11bb, 0,
+#undef V8268
+#define V8268 (V + 30933)
+ 0x110a, 0x116a, 0x11bc, 0,
+#undef V8269
+#define V8269 (V + 30937)
+ 0x110a, 0x116a, 0x11bd, 0,
+#undef V8270
+#define V8270 (V + 30941)
+ 0x110a, 0x116a, 0x11be, 0,
+#undef V8271
+#define V8271 (V + 30945)
+ 0x110a, 0x116a, 0x11bf, 0,
+#undef V8272
+#define V8272 (V + 30949)
+ 0x110a, 0x116a, 0x11c0, 0,
+#undef V8273
+#define V8273 (V + 30953)
+ 0x110a, 0x116a, 0x11c1, 0,
+#undef V8274
+#define V8274 (V + 30957)
+ 0x110a, 0x116a, 0x11c2, 0,
+#undef V8275
+#define V8275 (V + 30961)
+ 0x110a, 0x116b, 0,
+#undef V8276
+#define V8276 (V + 30964)
+ 0x110a, 0x116b, 0x11a8, 0,
+#undef V8277
+#define V8277 (V + 30968)
+ 0x110a, 0x116b, 0x11a9, 0,
+#undef V8278
+#define V8278 (V + 30972)
+ 0x110a, 0x116b, 0x11aa, 0,
+#undef V8279
+#define V8279 (V + 30976)
+ 0x110a, 0x116b, 0x11ab, 0,
+#undef V8280
+#define V8280 (V + 30980)
+ 0x110a, 0x116b, 0x11ac, 0,
+#undef V8281
+#define V8281 (V + 30984)
+ 0x110a, 0x116b, 0x11ad, 0,
+#undef V8282
+#define V8282 (V + 30988)
+ 0x110a, 0x116b, 0x11ae, 0,
+#undef V8283
+#define V8283 (V + 30992)
+ 0x110a, 0x116b, 0x11af, 0,
+#undef V8284
+#define V8284 (V + 30996)
+ 0x110a, 0x116b, 0x11b0, 0,
+#undef V8285
+#define V8285 (V + 31000)
+ 0x110a, 0x116b, 0x11b1, 0,
+#undef V8286
+#define V8286 (V + 31004)
+ 0x110a, 0x116b, 0x11b2, 0,
+#undef V8287
+#define V8287 (V + 31008)
+ 0x110a, 0x116b, 0x11b3, 0,
+#undef V8288
+#define V8288 (V + 31012)
+ 0x110a, 0x116b, 0x11b4, 0,
+#undef V8289
+#define V8289 (V + 31016)
+ 0x110a, 0x116b, 0x11b5, 0,
+#undef V8290
+#define V8290 (V + 31020)
+ 0x110a, 0x116b, 0x11b6, 0,
+#undef V8291
+#define V8291 (V + 31024)
+ 0x110a, 0x116b, 0x11b7, 0,
+#undef V8292
+#define V8292 (V + 31028)
+ 0x110a, 0x116b, 0x11b8, 0,
+#undef V8293
+#define V8293 (V + 31032)
+ 0x110a, 0x116b, 0x11b9, 0,
+#undef V8294
+#define V8294 (V + 31036)
+ 0x110a, 0x116b, 0x11ba, 0,
+#undef V8295
+#define V8295 (V + 31040)
+ 0x110a, 0x116b, 0x11bb, 0,
+#undef V8296
+#define V8296 (V + 31044)
+ 0x110a, 0x116b, 0x11bc, 0,
+#undef V8297
+#define V8297 (V + 31048)
+ 0x110a, 0x116b, 0x11bd, 0,
+#undef V8298
+#define V8298 (V + 31052)
+ 0x110a, 0x116b, 0x11be, 0,
+#undef V8299
+#define V8299 (V + 31056)
+ 0x110a, 0x116b, 0x11bf, 0,
+#undef V8300
+#define V8300 (V + 31060)
+ 0x110a, 0x116b, 0x11c0, 0,
+#undef V8301
+#define V8301 (V + 31064)
+ 0x110a, 0x116b, 0x11c1, 0,
+#undef V8302
+#define V8302 (V + 31068)
+ 0x110a, 0x116b, 0x11c2, 0,
+#undef V8303
+#define V8303 (V + 31072)
+ 0x110a, 0x116c, 0,
+#undef V8304
+#define V8304 (V + 31075)
+ 0x110a, 0x116c, 0x11a8, 0,
+#undef V8305
+#define V8305 (V + 31079)
+ 0x110a, 0x116c, 0x11a9, 0,
+#undef V8306
+#define V8306 (V + 31083)
+ 0x110a, 0x116c, 0x11aa, 0,
+#undef V8307
+#define V8307 (V + 31087)
+ 0x110a, 0x116c, 0x11ab, 0,
+#undef V8308
+#define V8308 (V + 31091)
+ 0x110a, 0x116c, 0x11ac, 0,
+#undef V8309
+#define V8309 (V + 31095)
+ 0x110a, 0x116c, 0x11ad, 0,
+#undef V8310
+#define V8310 (V + 31099)
+ 0x110a, 0x116c, 0x11ae, 0,
+#undef V8311
+#define V8311 (V + 31103)
+ 0x110a, 0x116c, 0x11af, 0,
+#undef V8312
+#define V8312 (V + 31107)
+ 0x110a, 0x116c, 0x11b0, 0,
+#undef V8313
+#define V8313 (V + 31111)
+ 0x110a, 0x116c, 0x11b1, 0,
+#undef V8314
+#define V8314 (V + 31115)
+ 0x110a, 0x116c, 0x11b2, 0,
+#undef V8315
+#define V8315 (V + 31119)
+ 0x110a, 0x116c, 0x11b3, 0,
+#undef V8316
+#define V8316 (V + 31123)
+ 0x110a, 0x116c, 0x11b4, 0,
+#undef V8317
+#define V8317 (V + 31127)
+ 0x110a, 0x116c, 0x11b5, 0,
+#undef V8318
+#define V8318 (V + 31131)
+ 0x110a, 0x116c, 0x11b6, 0,
+#undef V8319
+#define V8319 (V + 31135)
+ 0x110a, 0x116c, 0x11b7, 0,
+#undef V8320
+#define V8320 (V + 31139)
+ 0x110a, 0x116c, 0x11b8, 0,
+#undef V8321
+#define V8321 (V + 31143)
+ 0x110a, 0x116c, 0x11b9, 0,
+#undef V8322
+#define V8322 (V + 31147)
+ 0x110a, 0x116c, 0x11ba, 0,
+#undef V8323
+#define V8323 (V + 31151)
+ 0x110a, 0x116c, 0x11bb, 0,
+#undef V8324
+#define V8324 (V + 31155)
+ 0x110a, 0x116c, 0x11bc, 0,
+#undef V8325
+#define V8325 (V + 31159)
+ 0x110a, 0x116c, 0x11bd, 0,
+#undef V8326
+#define V8326 (V + 31163)
+ 0x110a, 0x116c, 0x11be, 0,
+#undef V8327
+#define V8327 (V + 31167)
+ 0x110a, 0x116c, 0x11bf, 0,
+#undef V8328
+#define V8328 (V + 31171)
+ 0x110a, 0x116c, 0x11c0, 0,
+#undef V8329
+#define V8329 (V + 31175)
+ 0x110a, 0x116c, 0x11c1, 0,
+#undef V8330
+#define V8330 (V + 31179)
+ 0x110a, 0x116c, 0x11c2, 0,
+#undef V8331
+#define V8331 (V + 31183)
+ 0x110a, 0x116d, 0,
+#undef V8332
+#define V8332 (V + 31186)
+ 0x110a, 0x116d, 0x11a8, 0,
+#undef V8333
+#define V8333 (V + 31190)
+ 0x110a, 0x116d, 0x11a9, 0,
+#undef V8334
+#define V8334 (V + 31194)
+ 0x110a, 0x116d, 0x11aa, 0,
+#undef V8335
+#define V8335 (V + 31198)
+ 0x110a, 0x116d, 0x11ab, 0,
+#undef V8336
+#define V8336 (V + 31202)
+ 0x110a, 0x116d, 0x11ac, 0,
+#undef V8337
+#define V8337 (V + 31206)
+ 0x110a, 0x116d, 0x11ad, 0,
+#undef V8338
+#define V8338 (V + 31210)
+ 0x110a, 0x116d, 0x11ae, 0,
+#undef V8339
+#define V8339 (V + 31214)
+ 0x110a, 0x116d, 0x11af, 0,
+#undef V8340
+#define V8340 (V + 31218)
+ 0x110a, 0x116d, 0x11b0, 0,
+#undef V8341
+#define V8341 (V + 31222)
+ 0x110a, 0x116d, 0x11b1, 0,
+#undef V8342
+#define V8342 (V + 31226)
+ 0x110a, 0x116d, 0x11b2, 0,
+#undef V8343
+#define V8343 (V + 31230)
+ 0x110a, 0x116d, 0x11b3, 0,
+#undef V8344
+#define V8344 (V + 31234)
+ 0x110a, 0x116d, 0x11b4, 0,
+#undef V8345
+#define V8345 (V + 31238)
+ 0x110a, 0x116d, 0x11b5, 0,
+#undef V8346
+#define V8346 (V + 31242)
+ 0x110a, 0x116d, 0x11b6, 0,
+#undef V8347
+#define V8347 (V + 31246)
+ 0x110a, 0x116d, 0x11b7, 0,
+#undef V8348
+#define V8348 (V + 31250)
+ 0x110a, 0x116d, 0x11b8, 0,
+#undef V8349
+#define V8349 (V + 31254)
+ 0x110a, 0x116d, 0x11b9, 0,
+#undef V8350
+#define V8350 (V + 31258)
+ 0x110a, 0x116d, 0x11ba, 0,
+#undef V8351
+#define V8351 (V + 31262)
+ 0x110a, 0x116d, 0x11bb, 0,
+#undef V8352
+#define V8352 (V + 31266)
+ 0x110a, 0x116d, 0x11bc, 0,
+#undef V8353
+#define V8353 (V + 31270)
+ 0x110a, 0x116d, 0x11bd, 0,
+#undef V8354
+#define V8354 (V + 31274)
+ 0x110a, 0x116d, 0x11be, 0,
+#undef V8355
+#define V8355 (V + 31278)
+ 0x110a, 0x116d, 0x11bf, 0,
+#undef V8356
+#define V8356 (V + 31282)
+ 0x110a, 0x116d, 0x11c0, 0,
+#undef V8357
+#define V8357 (V + 31286)
+ 0x110a, 0x116d, 0x11c1, 0,
+#undef V8358
+#define V8358 (V + 31290)
+ 0x110a, 0x116d, 0x11c2, 0,
+#undef V8359
+#define V8359 (V + 31294)
+ 0x110a, 0x116e, 0,
+#undef V8360
+#define V8360 (V + 31297)
+ 0x110a, 0x116e, 0x11a8, 0,
+#undef V8361
+#define V8361 (V + 31301)
+ 0x110a, 0x116e, 0x11a9, 0,
+#undef V8362
+#define V8362 (V + 31305)
+ 0x110a, 0x116e, 0x11aa, 0,
+#undef V8363
+#define V8363 (V + 31309)
+ 0x110a, 0x116e, 0x11ab, 0,
+#undef V8364
+#define V8364 (V + 31313)
+ 0x110a, 0x116e, 0x11ac, 0,
+#undef V8365
+#define V8365 (V + 31317)
+ 0x110a, 0x116e, 0x11ad, 0,
+#undef V8366
+#define V8366 (V + 31321)
+ 0x110a, 0x116e, 0x11ae, 0,
+#undef V8367
+#define V8367 (V + 31325)
+ 0x110a, 0x116e, 0x11af, 0,
+#undef V8368
+#define V8368 (V + 31329)
+ 0x110a, 0x116e, 0x11b0, 0,
+#undef V8369
+#define V8369 (V + 31333)
+ 0x110a, 0x116e, 0x11b1, 0,
+#undef V8370
+#define V8370 (V + 31337)
+ 0x110a, 0x116e, 0x11b2, 0,
+#undef V8371
+#define V8371 (V + 31341)
+ 0x110a, 0x116e, 0x11b3, 0,
+#undef V8372
+#define V8372 (V + 31345)
+ 0x110a, 0x116e, 0x11b4, 0,
+#undef V8373
+#define V8373 (V + 31349)
+ 0x110a, 0x116e, 0x11b5, 0,
+#undef V8374
+#define V8374 (V + 31353)
+ 0x110a, 0x116e, 0x11b6, 0,
+#undef V8375
+#define V8375 (V + 31357)
+ 0x110a, 0x116e, 0x11b7, 0,
+#undef V8376
+#define V8376 (V + 31361)
+ 0x110a, 0x116e, 0x11b8, 0,
+#undef V8377
+#define V8377 (V + 31365)
+ 0x110a, 0x116e, 0x11b9, 0,
+#undef V8378
+#define V8378 (V + 31369)
+ 0x110a, 0x116e, 0x11ba, 0,
+#undef V8379
+#define V8379 (V + 31373)
+ 0x110a, 0x116e, 0x11bb, 0,
+#undef V8380
+#define V8380 (V + 31377)
+ 0x110a, 0x116e, 0x11bc, 0,
+#undef V8381
+#define V8381 (V + 31381)
+ 0x110a, 0x116e, 0x11bd, 0,
+#undef V8382
+#define V8382 (V + 31385)
+ 0x110a, 0x116e, 0x11be, 0,
+#undef V8383
+#define V8383 (V + 31389)
+ 0x110a, 0x116e, 0x11bf, 0,
+#undef V8384
+#define V8384 (V + 31393)
+ 0x110a, 0x116e, 0x11c0, 0,
+#undef V8385
+#define V8385 (V + 31397)
+ 0x110a, 0x116e, 0x11c1, 0,
+#undef V8386
+#define V8386 (V + 31401)
+ 0x110a, 0x116e, 0x11c2, 0,
+#undef V8387
+#define V8387 (V + 31405)
+ 0x110a, 0x116f, 0,
+#undef V8388
+#define V8388 (V + 31408)
+ 0x110a, 0x116f, 0x11a8, 0,
+#undef V8389
+#define V8389 (V + 31412)
+ 0x110a, 0x116f, 0x11a9, 0,
+#undef V8390
+#define V8390 (V + 31416)
+ 0x110a, 0x116f, 0x11aa, 0,
+#undef V8391
+#define V8391 (V + 31420)
+ 0x110a, 0x116f, 0x11ab, 0,
+#undef V8392
+#define V8392 (V + 31424)
+ 0x110a, 0x116f, 0x11ac, 0,
+#undef V8393
+#define V8393 (V + 31428)
+ 0x110a, 0x116f, 0x11ad, 0,
+#undef V8394
+#define V8394 (V + 31432)
+ 0x110a, 0x116f, 0x11ae, 0,
+#undef V8395
+#define V8395 (V + 31436)
+ 0x110a, 0x116f, 0x11af, 0,
+#undef V8396
+#define V8396 (V + 31440)
+ 0x110a, 0x116f, 0x11b0, 0,
+#undef V8397
+#define V8397 (V + 31444)
+ 0x110a, 0x116f, 0x11b1, 0,
+#undef V8398
+#define V8398 (V + 31448)
+ 0x110a, 0x116f, 0x11b2, 0,
+#undef V8399
+#define V8399 (V + 31452)
+ 0x110a, 0x116f, 0x11b3, 0,
+#undef V8400
+#define V8400 (V + 31456)
+ 0x110a, 0x116f, 0x11b4, 0,
+#undef V8401
+#define V8401 (V + 31460)
+ 0x110a, 0x116f, 0x11b5, 0,
+#undef V8402
+#define V8402 (V + 31464)
+ 0x110a, 0x116f, 0x11b6, 0,
+#undef V8403
+#define V8403 (V + 31468)
+ 0x110a, 0x116f, 0x11b7, 0,
+#undef V8404
+#define V8404 (V + 31472)
+ 0x110a, 0x116f, 0x11b8, 0,
+#undef V8405
+#define V8405 (V + 31476)
+ 0x110a, 0x116f, 0x11b9, 0,
+#undef V8406
+#define V8406 (V + 31480)
+ 0x110a, 0x116f, 0x11ba, 0,
+#undef V8407
+#define V8407 (V + 31484)
+ 0x110a, 0x116f, 0x11bb, 0,
+#undef V8408
+#define V8408 (V + 31488)
+ 0x110a, 0x116f, 0x11bc, 0,
+#undef V8409
+#define V8409 (V + 31492)
+ 0x110a, 0x116f, 0x11bd, 0,
+#undef V8410
+#define V8410 (V + 31496)
+ 0x110a, 0x116f, 0x11be, 0,
+#undef V8411
+#define V8411 (V + 31500)
+ 0x110a, 0x116f, 0x11bf, 0,
+#undef V8412
+#define V8412 (V + 31504)
+ 0x110a, 0x116f, 0x11c0, 0,
+#undef V8413
+#define V8413 (V + 31508)
+ 0x110a, 0x116f, 0x11c1, 0,
+#undef V8414
+#define V8414 (V + 31512)
+ 0x110a, 0x116f, 0x11c2, 0,
+#undef V8415
+#define V8415 (V + 31516)
+ 0x110a, 0x1170, 0,
+#undef V8416
+#define V8416 (V + 31519)
+ 0x110a, 0x1170, 0x11a8, 0,
+#undef V8417
+#define V8417 (V + 31523)
+ 0x110a, 0x1170, 0x11a9, 0,
+#undef V8418
+#define V8418 (V + 31527)
+ 0x110a, 0x1170, 0x11aa, 0,
+#undef V8419
+#define V8419 (V + 31531)
+ 0x110a, 0x1170, 0x11ab, 0,
+#undef V8420
+#define V8420 (V + 31535)
+ 0x110a, 0x1170, 0x11ac, 0,
+#undef V8421
+#define V8421 (V + 31539)
+ 0x110a, 0x1170, 0x11ad, 0,
+#undef V8422
+#define V8422 (V + 31543)
+ 0x110a, 0x1170, 0x11ae, 0,
+#undef V8423
+#define V8423 (V + 31547)
+ 0x110a, 0x1170, 0x11af, 0,
+#undef V8424
+#define V8424 (V + 31551)
+ 0x110a, 0x1170, 0x11b0, 0,
+#undef V8425
+#define V8425 (V + 31555)
+ 0x110a, 0x1170, 0x11b1, 0,
+#undef V8426
+#define V8426 (V + 31559)
+ 0x110a, 0x1170, 0x11b2, 0,
+#undef V8427
+#define V8427 (V + 31563)
+ 0x110a, 0x1170, 0x11b3, 0,
+#undef V8428
+#define V8428 (V + 31567)
+ 0x110a, 0x1170, 0x11b4, 0,
+#undef V8429
+#define V8429 (V + 31571)
+ 0x110a, 0x1170, 0x11b5, 0,
+#undef V8430
+#define V8430 (V + 31575)
+ 0x110a, 0x1170, 0x11b6, 0,
+#undef V8431
+#define V8431 (V + 31579)
+ 0x110a, 0x1170, 0x11b7, 0,
+#undef V8432
+#define V8432 (V + 31583)
+ 0x110a, 0x1170, 0x11b8, 0,
+#undef V8433
+#define V8433 (V + 31587)
+ 0x110a, 0x1170, 0x11b9, 0,
+#undef V8434
+#define V8434 (V + 31591)
+ 0x110a, 0x1170, 0x11ba, 0,
+#undef V8435
+#define V8435 (V + 31595)
+ 0x110a, 0x1170, 0x11bb, 0,
+#undef V8436
+#define V8436 (V + 31599)
+ 0x110a, 0x1170, 0x11bc, 0,
+#undef V8437
+#define V8437 (V + 31603)
+ 0x110a, 0x1170, 0x11bd, 0,
+#undef V8438
+#define V8438 (V + 31607)
+ 0x110a, 0x1170, 0x11be, 0,
+#undef V8439
+#define V8439 (V + 31611)
+ 0x110a, 0x1170, 0x11bf, 0,
+#undef V8440
+#define V8440 (V + 31615)
+ 0x110a, 0x1170, 0x11c0, 0,
+#undef V8441
+#define V8441 (V + 31619)
+ 0x110a, 0x1170, 0x11c1, 0,
+#undef V8442
+#define V8442 (V + 31623)
+ 0x110a, 0x1170, 0x11c2, 0,
+#undef V8443
+#define V8443 (V + 31627)
+ 0x110a, 0x1171, 0,
+#undef V8444
+#define V8444 (V + 31630)
+ 0x110a, 0x1171, 0x11a8, 0,
+#undef V8445
+#define V8445 (V + 31634)
+ 0x110a, 0x1171, 0x11a9, 0,
+#undef V8446
+#define V8446 (V + 31638)
+ 0x110a, 0x1171, 0x11aa, 0,
+#undef V8447
+#define V8447 (V + 31642)
+ 0x110a, 0x1171, 0x11ab, 0,
+#undef V8448
+#define V8448 (V + 31646)
+ 0x110a, 0x1171, 0x11ac, 0,
+#undef V8449
+#define V8449 (V + 31650)
+ 0x110a, 0x1171, 0x11ad, 0,
+#undef V8450
+#define V8450 (V + 31654)
+ 0x110a, 0x1171, 0x11ae, 0,
+#undef V8451
+#define V8451 (V + 31658)
+ 0x110a, 0x1171, 0x11af, 0,
+#undef V8452
+#define V8452 (V + 31662)
+ 0x110a, 0x1171, 0x11b0, 0,
+#undef V8453
+#define V8453 (V + 31666)
+ 0x110a, 0x1171, 0x11b1, 0,
+#undef V8454
+#define V8454 (V + 31670)
+ 0x110a, 0x1171, 0x11b2, 0,
+#undef V8455
+#define V8455 (V + 31674)
+ 0x110a, 0x1171, 0x11b3, 0,
+#undef V8456
+#define V8456 (V + 31678)
+ 0x110a, 0x1171, 0x11b4, 0,
+#undef V8457
+#define V8457 (V + 31682)
+ 0x110a, 0x1171, 0x11b5, 0,
+#undef V8458
+#define V8458 (V + 31686)
+ 0x110a, 0x1171, 0x11b6, 0,
+#undef V8459
+#define V8459 (V + 31690)
+ 0x110a, 0x1171, 0x11b7, 0,
+#undef V8460
+#define V8460 (V + 31694)
+ 0x110a, 0x1171, 0x11b8, 0,
+#undef V8461
+#define V8461 (V + 31698)
+ 0x110a, 0x1171, 0x11b9, 0,
+#undef V8462
+#define V8462 (V + 31702)
+ 0x110a, 0x1171, 0x11ba, 0,
+#undef V8463
+#define V8463 (V + 31706)
+ 0x110a, 0x1171, 0x11bb, 0,
+#undef V8464
+#define V8464 (V + 31710)
+ 0x110a, 0x1171, 0x11bc, 0,
+#undef V8465
+#define V8465 (V + 31714)
+ 0x110a, 0x1171, 0x11bd, 0,
+#undef V8466
+#define V8466 (V + 31718)
+ 0x110a, 0x1171, 0x11be, 0,
+#undef V8467
+#define V8467 (V + 31722)
+ 0x110a, 0x1171, 0x11bf, 0,
+#undef V8468
+#define V8468 (V + 31726)
+ 0x110a, 0x1171, 0x11c0, 0,
+#undef V8469
+#define V8469 (V + 31730)
+ 0x110a, 0x1171, 0x11c1, 0,
+#undef V8470
+#define V8470 (V + 31734)
+ 0x110a, 0x1171, 0x11c2, 0,
+#undef V8471
+#define V8471 (V + 31738)
+ 0x110a, 0x1172, 0,
+#undef V8472
+#define V8472 (V + 31741)
+ 0x110a, 0x1172, 0x11a8, 0,
+#undef V8473
+#define V8473 (V + 31745)
+ 0x110a, 0x1172, 0x11a9, 0,
+#undef V8474
+#define V8474 (V + 31749)
+ 0x110a, 0x1172, 0x11aa, 0,
+#undef V8475
+#define V8475 (V + 31753)
+ 0x110a, 0x1172, 0x11ab, 0,
+#undef V8476
+#define V8476 (V + 31757)
+ 0x110a, 0x1172, 0x11ac, 0,
+#undef V8477
+#define V8477 (V + 31761)
+ 0x110a, 0x1172, 0x11ad, 0,
+#undef V8478
+#define V8478 (V + 31765)
+ 0x110a, 0x1172, 0x11ae, 0,
+#undef V8479
+#define V8479 (V + 31769)
+ 0x110a, 0x1172, 0x11af, 0,
+#undef V8480
+#define V8480 (V + 31773)
+ 0x110a, 0x1172, 0x11b0, 0,
+#undef V8481
+#define V8481 (V + 31777)
+ 0x110a, 0x1172, 0x11b1, 0,
+#undef V8482
+#define V8482 (V + 31781)
+ 0x110a, 0x1172, 0x11b2, 0,
+#undef V8483
+#define V8483 (V + 31785)
+ 0x110a, 0x1172, 0x11b3, 0,
+#undef V8484
+#define V8484 (V + 31789)
+ 0x110a, 0x1172, 0x11b4, 0,
+#undef V8485
+#define V8485 (V + 31793)
+ 0x110a, 0x1172, 0x11b5, 0,
+#undef V8486
+#define V8486 (V + 31797)
+ 0x110a, 0x1172, 0x11b6, 0,
+#undef V8487
+#define V8487 (V + 31801)
+ 0x110a, 0x1172, 0x11b7, 0,
+#undef V8488
+#define V8488 (V + 31805)
+ 0x110a, 0x1172, 0x11b8, 0,
+#undef V8489
+#define V8489 (V + 31809)
+ 0x110a, 0x1172, 0x11b9, 0,
+#undef V8490
+#define V8490 (V + 31813)
+ 0x110a, 0x1172, 0x11ba, 0,
+#undef V8491
+#define V8491 (V + 31817)
+ 0x110a, 0x1172, 0x11bb, 0,
+#undef V8492
+#define V8492 (V + 31821)
+ 0x110a, 0x1172, 0x11bc, 0,
+#undef V8493
+#define V8493 (V + 31825)
+ 0x110a, 0x1172, 0x11bd, 0,
+#undef V8494
+#define V8494 (V + 31829)
+ 0x110a, 0x1172, 0x11be, 0,
+#undef V8495
+#define V8495 (V + 31833)
+ 0x110a, 0x1172, 0x11bf, 0,
+#undef V8496
+#define V8496 (V + 31837)
+ 0x110a, 0x1172, 0x11c0, 0,
+#undef V8497
+#define V8497 (V + 31841)
+ 0x110a, 0x1172, 0x11c1, 0,
+#undef V8498
+#define V8498 (V + 31845)
+ 0x110a, 0x1172, 0x11c2, 0,
+#undef V8499
+#define V8499 (V + 31849)
+ 0x110a, 0x1173, 0,
+#undef V8500
+#define V8500 (V + 31852)
+ 0x110a, 0x1173, 0x11a8, 0,
+#undef V8501
+#define V8501 (V + 31856)
+ 0x110a, 0x1173, 0x11a9, 0,
+#undef V8502
+#define V8502 (V + 31860)
+ 0x110a, 0x1173, 0x11aa, 0,
+#undef V8503
+#define V8503 (V + 31864)
+ 0x110a, 0x1173, 0x11ab, 0,
+#undef V8504
+#define V8504 (V + 31868)
+ 0x110a, 0x1173, 0x11ac, 0,
+#undef V8505
+#define V8505 (V + 31872)
+ 0x110a, 0x1173, 0x11ad, 0,
+#undef V8506
+#define V8506 (V + 31876)
+ 0x110a, 0x1173, 0x11ae, 0,
+#undef V8507
+#define V8507 (V + 31880)
+ 0x110a, 0x1173, 0x11af, 0,
+#undef V8508
+#define V8508 (V + 31884)
+ 0x110a, 0x1173, 0x11b0, 0,
+#undef V8509
+#define V8509 (V + 31888)
+ 0x110a, 0x1173, 0x11b1, 0,
+#undef V8510
+#define V8510 (V + 31892)
+ 0x110a, 0x1173, 0x11b2, 0,
+#undef V8511
+#define V8511 (V + 31896)
+ 0x110a, 0x1173, 0x11b3, 0,
+#undef V8512
+#define V8512 (V + 31900)
+ 0x110a, 0x1173, 0x11b4, 0,
+#undef V8513
+#define V8513 (V + 31904)
+ 0x110a, 0x1173, 0x11b5, 0,
+#undef V8514
+#define V8514 (V + 31908)
+ 0x110a, 0x1173, 0x11b6, 0,
+#undef V8515
+#define V8515 (V + 31912)
+ 0x110a, 0x1173, 0x11b7, 0,
+#undef V8516
+#define V8516 (V + 31916)
+ 0x110a, 0x1173, 0x11b8, 0,
+#undef V8517
+#define V8517 (V + 31920)
+ 0x110a, 0x1173, 0x11b9, 0,
+#undef V8518
+#define V8518 (V + 31924)
+ 0x110a, 0x1173, 0x11ba, 0,
+#undef V8519
+#define V8519 (V + 31928)
+ 0x110a, 0x1173, 0x11bb, 0,
+#undef V8520
+#define V8520 (V + 31932)
+ 0x110a, 0x1173, 0x11bc, 0,
+#undef V8521
+#define V8521 (V + 31936)
+ 0x110a, 0x1173, 0x11bd, 0,
+#undef V8522
+#define V8522 (V + 31940)
+ 0x110a, 0x1173, 0x11be, 0,
+#undef V8523
+#define V8523 (V + 31944)
+ 0x110a, 0x1173, 0x11bf, 0,
+#undef V8524
+#define V8524 (V + 31948)
+ 0x110a, 0x1173, 0x11c0, 0,
+#undef V8525
+#define V8525 (V + 31952)
+ 0x110a, 0x1173, 0x11c1, 0,
+#undef V8526
+#define V8526 (V + 31956)
+ 0x110a, 0x1173, 0x11c2, 0,
+#undef V8527
+#define V8527 (V + 31960)
+ 0x110a, 0x1174, 0,
+#undef V8528
+#define V8528 (V + 31963)
+ 0x110a, 0x1174, 0x11a8, 0,
+#undef V8529
+#define V8529 (V + 31967)
+ 0x110a, 0x1174, 0x11a9, 0,
+#undef V8530
+#define V8530 (V + 31971)
+ 0x110a, 0x1174, 0x11aa, 0,
+#undef V8531
+#define V8531 (V + 31975)
+ 0x110a, 0x1174, 0x11ab, 0,
+#undef V8532
+#define V8532 (V + 31979)
+ 0x110a, 0x1174, 0x11ac, 0,
+#undef V8533
+#define V8533 (V + 31983)
+ 0x110a, 0x1174, 0x11ad, 0,
+#undef V8534
+#define V8534 (V + 31987)
+ 0x110a, 0x1174, 0x11ae, 0,
+#undef V8535
+#define V8535 (V + 31991)
+ 0x110a, 0x1174, 0x11af, 0,
+#undef V8536
+#define V8536 (V + 31995)
+ 0x110a, 0x1174, 0x11b0, 0,
+#undef V8537
+#define V8537 (V + 31999)
+ 0x110a, 0x1174, 0x11b1, 0,
+#undef V8538
+#define V8538 (V + 32003)
+ 0x110a, 0x1174, 0x11b2, 0,
+#undef V8539
+#define V8539 (V + 32007)
+ 0x110a, 0x1174, 0x11b3, 0,
+#undef V8540
+#define V8540 (V + 32011)
+ 0x110a, 0x1174, 0x11b4, 0,
+#undef V8541
+#define V8541 (V + 32015)
+ 0x110a, 0x1174, 0x11b5, 0,
+#undef V8542
+#define V8542 (V + 32019)
+ 0x110a, 0x1174, 0x11b6, 0,
+#undef V8543
+#define V8543 (V + 32023)
+ 0x110a, 0x1174, 0x11b7, 0,
+#undef V8544
+#define V8544 (V + 32027)
+ 0x110a, 0x1174, 0x11b8, 0,
+#undef V8545
+#define V8545 (V + 32031)
+ 0x110a, 0x1174, 0x11b9, 0,
+#undef V8546
+#define V8546 (V + 32035)
+ 0x110a, 0x1174, 0x11ba, 0,
+#undef V8547
+#define V8547 (V + 32039)
+ 0x110a, 0x1174, 0x11bb, 0,
+#undef V8548
+#define V8548 (V + 32043)
+ 0x110a, 0x1174, 0x11bc, 0,
+#undef V8549
+#define V8549 (V + 32047)
+ 0x110a, 0x1174, 0x11bd, 0,
+#undef V8550
+#define V8550 (V + 32051)
+ 0x110a, 0x1174, 0x11be, 0,
+#undef V8551
+#define V8551 (V + 32055)
+ 0x110a, 0x1174, 0x11bf, 0,
+#undef V8552
+#define V8552 (V + 32059)
+ 0x110a, 0x1174, 0x11c0, 0,
+#undef V8553
+#define V8553 (V + 32063)
+ 0x110a, 0x1174, 0x11c1, 0,
+#undef V8554
+#define V8554 (V + 32067)
+ 0x110a, 0x1174, 0x11c2, 0,
+#undef V8555
+#define V8555 (V + 32071)
+ 0x110a, 0x1175, 0,
+#undef V8556
+#define V8556 (V + 32074)
+ 0x110a, 0x1175, 0x11a8, 0,
+#undef V8557
+#define V8557 (V + 32078)
+ 0x110a, 0x1175, 0x11a9, 0,
+#undef V8558
+#define V8558 (V + 32082)
+ 0x110a, 0x1175, 0x11aa, 0,
+#undef V8559
+#define V8559 (V + 32086)
+ 0x110a, 0x1175, 0x11ab, 0,
+#undef V8560
+#define V8560 (V + 32090)
+ 0x110a, 0x1175, 0x11ac, 0,
+#undef V8561
+#define V8561 (V + 32094)
+ 0x110a, 0x1175, 0x11ad, 0,
+#undef V8562
+#define V8562 (V + 32098)
+ 0x110a, 0x1175, 0x11ae, 0,
+#undef V8563
+#define V8563 (V + 32102)
+ 0x110a, 0x1175, 0x11af, 0,
+#undef V8564
+#define V8564 (V + 32106)
+ 0x110a, 0x1175, 0x11b0, 0,
+#undef V8565
+#define V8565 (V + 32110)
+ 0x110a, 0x1175, 0x11b1, 0,
+#undef V8566
+#define V8566 (V + 32114)
+ 0x110a, 0x1175, 0x11b2, 0,
+#undef V8567
+#define V8567 (V + 32118)
+ 0x110a, 0x1175, 0x11b3, 0,
+#undef V8568
+#define V8568 (V + 32122)
+ 0x110a, 0x1175, 0x11b4, 0,
+#undef V8569
+#define V8569 (V + 32126)
+ 0x110a, 0x1175, 0x11b5, 0,
+#undef V8570
+#define V8570 (V + 32130)
+ 0x110a, 0x1175, 0x11b6, 0,
+#undef V8571
+#define V8571 (V + 32134)
+ 0x110a, 0x1175, 0x11b7, 0,
+#undef V8572
+#define V8572 (V + 32138)
+ 0x110a, 0x1175, 0x11b8, 0,
+#undef V8573
+#define V8573 (V + 32142)
+ 0x110a, 0x1175, 0x11b9, 0,
+#undef V8574
+#define V8574 (V + 32146)
+ 0x110a, 0x1175, 0x11ba, 0,
+#undef V8575
+#define V8575 (V + 32150)
+ 0x110a, 0x1175, 0x11bb, 0,
+#undef V8576
+#define V8576 (V + 32154)
+ 0x110a, 0x1175, 0x11bc, 0,
+#undef V8577
+#define V8577 (V + 32158)
+ 0x110a, 0x1175, 0x11bd, 0,
+#undef V8578
+#define V8578 (V + 32162)
+ 0x110a, 0x1175, 0x11be, 0,
+#undef V8579
+#define V8579 (V + 32166)
+ 0x110a, 0x1175, 0x11bf, 0,
+#undef V8580
+#define V8580 (V + 32170)
+ 0x110a, 0x1175, 0x11c0, 0,
+#undef V8581
+#define V8581 (V + 32174)
+ 0x110a, 0x1175, 0x11c1, 0,
+#undef V8582
+#define V8582 (V + 32178)
+ 0x110a, 0x1175, 0x11c2, 0,
+#undef V8583
+#define V8583 (V + 32182)
+ 0x110b, 0x1161, 0x11a8, 0,
+#undef V8584
+#define V8584 (V + 32186)
+ 0x110b, 0x1161, 0x11a9, 0,
+#undef V8585
+#define V8585 (V + 32190)
+ 0x110b, 0x1161, 0x11aa, 0,
+#undef V8586
+#define V8586 (V + 32194)
+ 0x110b, 0x1161, 0x11ab, 0,
+#undef V8587
+#define V8587 (V + 32198)
+ 0x110b, 0x1161, 0x11ac, 0,
+#undef V8588
+#define V8588 (V + 32202)
+ 0x110b, 0x1161, 0x11ad, 0,
+#undef V8589
+#define V8589 (V + 32206)
+ 0x110b, 0x1161, 0x11ae, 0,
+#undef V8590
+#define V8590 (V + 32210)
+ 0x110b, 0x1161, 0x11af, 0,
+#undef V8591
+#define V8591 (V + 32214)
+ 0x110b, 0x1161, 0x11b0, 0,
+#undef V8592
+#define V8592 (V + 32218)
+ 0x110b, 0x1161, 0x11b1, 0,
+#undef V8593
+#define V8593 (V + 32222)
+ 0x110b, 0x1161, 0x11b2, 0,
+#undef V8594
+#define V8594 (V + 32226)
+ 0x110b, 0x1161, 0x11b3, 0,
+#undef V8595
+#define V8595 (V + 32230)
+ 0x110b, 0x1161, 0x11b4, 0,
+#undef V8596
+#define V8596 (V + 32234)
+ 0x110b, 0x1161, 0x11b5, 0,
+#undef V8597
+#define V8597 (V + 32238)
+ 0x110b, 0x1161, 0x11b6, 0,
+#undef V8598
+#define V8598 (V + 32242)
+ 0x110b, 0x1161, 0x11b7, 0,
+#undef V8599
+#define V8599 (V + 32246)
+ 0x110b, 0x1161, 0x11b8, 0,
+#undef V8600
+#define V8600 (V + 32250)
+ 0x110b, 0x1161, 0x11b9, 0,
+#undef V8601
+#define V8601 (V + 32254)
+ 0x110b, 0x1161, 0x11ba, 0,
+#undef V8602
+#define V8602 (V + 32258)
+ 0x110b, 0x1161, 0x11bb, 0,
+#undef V8603
+#define V8603 (V + 32262)
+ 0x110b, 0x1161, 0x11bc, 0,
+#undef V8604
+#define V8604 (V + 32266)
+ 0x110b, 0x1161, 0x11bd, 0,
+#undef V8605
+#define V8605 (V + 32270)
+ 0x110b, 0x1161, 0x11be, 0,
+#undef V8606
+#define V8606 (V + 32274)
+ 0x110b, 0x1161, 0x11bf, 0,
+#undef V8607
+#define V8607 (V + 32278)
+ 0x110b, 0x1161, 0x11c0, 0,
+#undef V8608
+#define V8608 (V + 32282)
+ 0x110b, 0x1161, 0x11c1, 0,
+#undef V8609
+#define V8609 (V + 32286)
+ 0x110b, 0x1161, 0x11c2, 0,
+#undef V8610
+#define V8610 (V + 32290)
+ 0x110b, 0x1162, 0,
+#undef V8611
+#define V8611 (V + 32293)
+ 0x110b, 0x1162, 0x11a8, 0,
+#undef V8612
+#define V8612 (V + 32297)
+ 0x110b, 0x1162, 0x11a9, 0,
+#undef V8613
+#define V8613 (V + 32301)
+ 0x110b, 0x1162, 0x11aa, 0,
+#undef V8614
+#define V8614 (V + 32305)
+ 0x110b, 0x1162, 0x11ab, 0,
+#undef V8615
+#define V8615 (V + 32309)
+ 0x110b, 0x1162, 0x11ac, 0,
+#undef V8616
+#define V8616 (V + 32313)
+ 0x110b, 0x1162, 0x11ad, 0,
+#undef V8617
+#define V8617 (V + 32317)
+ 0x110b, 0x1162, 0x11ae, 0,
+#undef V8618
+#define V8618 (V + 32321)
+ 0x110b, 0x1162, 0x11af, 0,
+#undef V8619
+#define V8619 (V + 32325)
+ 0x110b, 0x1162, 0x11b0, 0,
+#undef V8620
+#define V8620 (V + 32329)
+ 0x110b, 0x1162, 0x11b1, 0,
+#undef V8621
+#define V8621 (V + 32333)
+ 0x110b, 0x1162, 0x11b2, 0,
+#undef V8622
+#define V8622 (V + 32337)
+ 0x110b, 0x1162, 0x11b3, 0,
+#undef V8623
+#define V8623 (V + 32341)
+ 0x110b, 0x1162, 0x11b4, 0,
+#undef V8624
+#define V8624 (V + 32345)
+ 0x110b, 0x1162, 0x11b5, 0,
+#undef V8625
+#define V8625 (V + 32349)
+ 0x110b, 0x1162, 0x11b6, 0,
+#undef V8626
+#define V8626 (V + 32353)
+ 0x110b, 0x1162, 0x11b7, 0,
+#undef V8627
+#define V8627 (V + 32357)
+ 0x110b, 0x1162, 0x11b8, 0,
+#undef V8628
+#define V8628 (V + 32361)
+ 0x110b, 0x1162, 0x11b9, 0,
+#undef V8629
+#define V8629 (V + 32365)
+ 0x110b, 0x1162, 0x11ba, 0,
+#undef V8630
+#define V8630 (V + 32369)
+ 0x110b, 0x1162, 0x11bb, 0,
+#undef V8631
+#define V8631 (V + 32373)
+ 0x110b, 0x1162, 0x11bc, 0,
+#undef V8632
+#define V8632 (V + 32377)
+ 0x110b, 0x1162, 0x11bd, 0,
+#undef V8633
+#define V8633 (V + 32381)
+ 0x110b, 0x1162, 0x11be, 0,
+#undef V8634
+#define V8634 (V + 32385)
+ 0x110b, 0x1162, 0x11bf, 0,
+#undef V8635
+#define V8635 (V + 32389)
+ 0x110b, 0x1162, 0x11c0, 0,
+#undef V8636
+#define V8636 (V + 32393)
+ 0x110b, 0x1162, 0x11c1, 0,
+#undef V8637
+#define V8637 (V + 32397)
+ 0x110b, 0x1162, 0x11c2, 0,
+#undef V8638
+#define V8638 (V + 32401)
+ 0x110b, 0x1163, 0,
+#undef V8639
+#define V8639 (V + 32404)
+ 0x110b, 0x1163, 0x11a8, 0,
+#undef V8640
+#define V8640 (V + 32408)
+ 0x110b, 0x1163, 0x11a9, 0,
+#undef V8641
+#define V8641 (V + 32412)
+ 0x110b, 0x1163, 0x11aa, 0,
+#undef V8642
+#define V8642 (V + 32416)
+ 0x110b, 0x1163, 0x11ab, 0,
+#undef V8643
+#define V8643 (V + 32420)
+ 0x110b, 0x1163, 0x11ac, 0,
+#undef V8644
+#define V8644 (V + 32424)
+ 0x110b, 0x1163, 0x11ad, 0,
+#undef V8645
+#define V8645 (V + 32428)
+ 0x110b, 0x1163, 0x11ae, 0,
+#undef V8646
+#define V8646 (V + 32432)
+ 0x110b, 0x1163, 0x11af, 0,
+#undef V8647
+#define V8647 (V + 32436)
+ 0x110b, 0x1163, 0x11b0, 0,
+#undef V8648
+#define V8648 (V + 32440)
+ 0x110b, 0x1163, 0x11b1, 0,
+#undef V8649
+#define V8649 (V + 32444)
+ 0x110b, 0x1163, 0x11b2, 0,
+#undef V8650
+#define V8650 (V + 32448)
+ 0x110b, 0x1163, 0x11b3, 0,
+#undef V8651
+#define V8651 (V + 32452)
+ 0x110b, 0x1163, 0x11b4, 0,
+#undef V8652
+#define V8652 (V + 32456)
+ 0x110b, 0x1163, 0x11b5, 0,
+#undef V8653
+#define V8653 (V + 32460)
+ 0x110b, 0x1163, 0x11b6, 0,
+#undef V8654
+#define V8654 (V + 32464)
+ 0x110b, 0x1163, 0x11b7, 0,
+#undef V8655
+#define V8655 (V + 32468)
+ 0x110b, 0x1163, 0x11b8, 0,
+#undef V8656
+#define V8656 (V + 32472)
+ 0x110b, 0x1163, 0x11b9, 0,
+#undef V8657
+#define V8657 (V + 32476)
+ 0x110b, 0x1163, 0x11ba, 0,
+#undef V8658
+#define V8658 (V + 32480)
+ 0x110b, 0x1163, 0x11bb, 0,
+#undef V8659
+#define V8659 (V + 32484)
+ 0x110b, 0x1163, 0x11bc, 0,
+#undef V8660
+#define V8660 (V + 32488)
+ 0x110b, 0x1163, 0x11bd, 0,
+#undef V8661
+#define V8661 (V + 32492)
+ 0x110b, 0x1163, 0x11be, 0,
+#undef V8662
+#define V8662 (V + 32496)
+ 0x110b, 0x1163, 0x11bf, 0,
+#undef V8663
+#define V8663 (V + 32500)
+ 0x110b, 0x1163, 0x11c0, 0,
+#undef V8664
+#define V8664 (V + 32504)
+ 0x110b, 0x1163, 0x11c1, 0,
+#undef V8665
+#define V8665 (V + 32508)
+ 0x110b, 0x1163, 0x11c2, 0,
+#undef V8666
+#define V8666 (V + 32512)
+ 0x110b, 0x1164, 0,
+#undef V8667
+#define V8667 (V + 32515)
+ 0x110b, 0x1164, 0x11a8, 0,
+#undef V8668
+#define V8668 (V + 32519)
+ 0x110b, 0x1164, 0x11a9, 0,
+#undef V8669
+#define V8669 (V + 32523)
+ 0x110b, 0x1164, 0x11aa, 0,
+#undef V8670
+#define V8670 (V + 32527)
+ 0x110b, 0x1164, 0x11ab, 0,
+#undef V8671
+#define V8671 (V + 32531)
+ 0x110b, 0x1164, 0x11ac, 0,
+#undef V8672
+#define V8672 (V + 32535)
+ 0x110b, 0x1164, 0x11ad, 0,
+#undef V8673
+#define V8673 (V + 32539)
+ 0x110b, 0x1164, 0x11ae, 0,
+#undef V8674
+#define V8674 (V + 32543)
+ 0x110b, 0x1164, 0x11af, 0,
+#undef V8675
+#define V8675 (V + 32547)
+ 0x110b, 0x1164, 0x11b0, 0,
+#undef V8676
+#define V8676 (V + 32551)
+ 0x110b, 0x1164, 0x11b1, 0,
+#undef V8677
+#define V8677 (V + 32555)
+ 0x110b, 0x1164, 0x11b2, 0,
+#undef V8678
+#define V8678 (V + 32559)
+ 0x110b, 0x1164, 0x11b3, 0,
+#undef V8679
+#define V8679 (V + 32563)
+ 0x110b, 0x1164, 0x11b4, 0,
+#undef V8680
+#define V8680 (V + 32567)
+ 0x110b, 0x1164, 0x11b5, 0,
+#undef V8681
+#define V8681 (V + 32571)
+ 0x110b, 0x1164, 0x11b6, 0,
+#undef V8682
+#define V8682 (V + 32575)
+ 0x110b, 0x1164, 0x11b7, 0,
+#undef V8683
+#define V8683 (V + 32579)
+ 0x110b, 0x1164, 0x11b8, 0,
+#undef V8684
+#define V8684 (V + 32583)
+ 0x110b, 0x1164, 0x11b9, 0,
+#undef V8685
+#define V8685 (V + 32587)
+ 0x110b, 0x1164, 0x11ba, 0,
+#undef V8686
+#define V8686 (V + 32591)
+ 0x110b, 0x1164, 0x11bb, 0,
+#undef V8687
+#define V8687 (V + 32595)
+ 0x110b, 0x1164, 0x11bc, 0,
+#undef V8688
+#define V8688 (V + 32599)
+ 0x110b, 0x1164, 0x11bd, 0,
+#undef V8689
+#define V8689 (V + 32603)
+ 0x110b, 0x1164, 0x11be, 0,
+#undef V8690
+#define V8690 (V + 32607)
+ 0x110b, 0x1164, 0x11bf, 0,
+#undef V8691
+#define V8691 (V + 32611)
+ 0x110b, 0x1164, 0x11c0, 0,
+#undef V8692
+#define V8692 (V + 32615)
+ 0x110b, 0x1164, 0x11c1, 0,
+#undef V8693
+#define V8693 (V + 32619)
+ 0x110b, 0x1164, 0x11c2, 0,
+#undef V8694
+#define V8694 (V + 32623)
+ 0x110b, 0x1165, 0,
+#undef V8695
+#define V8695 (V + 32626)
+ 0x110b, 0x1165, 0x11a8, 0,
+#undef V8696
+#define V8696 (V + 32630)
+ 0x110b, 0x1165, 0x11a9, 0,
+#undef V8697
+#define V8697 (V + 32634)
+ 0x110b, 0x1165, 0x11aa, 0,
+#undef V8698
+#define V8698 (V + 32638)
+ 0x110b, 0x1165, 0x11ab, 0,
+#undef V8699
+#define V8699 (V + 32642)
+ 0x110b, 0x1165, 0x11ac, 0,
+#undef V8700
+#define V8700 (V + 32646)
+ 0x110b, 0x1165, 0x11ad, 0,
+#undef V8701
+#define V8701 (V + 32650)
+ 0x110b, 0x1165, 0x11ae, 0,
+#undef V8702
+#define V8702 (V + 32654)
+ 0x110b, 0x1165, 0x11af, 0,
+#undef V8703
+#define V8703 (V + 32658)
+ 0x110b, 0x1165, 0x11b0, 0,
+#undef V8704
+#define V8704 (V + 32662)
+ 0x110b, 0x1165, 0x11b1, 0,
+#undef V8705
+#define V8705 (V + 32666)
+ 0x110b, 0x1165, 0x11b2, 0,
+#undef V8706
+#define V8706 (V + 32670)
+ 0x110b, 0x1165, 0x11b3, 0,
+#undef V8707
+#define V8707 (V + 32674)
+ 0x110b, 0x1165, 0x11b4, 0,
+#undef V8708
+#define V8708 (V + 32678)
+ 0x110b, 0x1165, 0x11b5, 0,
+#undef V8709
+#define V8709 (V + 32682)
+ 0x110b, 0x1165, 0x11b6, 0,
+#undef V8710
+#define V8710 (V + 32686)
+ 0x110b, 0x1165, 0x11b7, 0,
+#undef V8711
+#define V8711 (V + 32690)
+ 0x110b, 0x1165, 0x11b8, 0,
+#undef V8712
+#define V8712 (V + 32694)
+ 0x110b, 0x1165, 0x11b9, 0,
+#undef V8713
+#define V8713 (V + 32698)
+ 0x110b, 0x1165, 0x11ba, 0,
+#undef V8714
+#define V8714 (V + 32702)
+ 0x110b, 0x1165, 0x11bb, 0,
+#undef V8715
+#define V8715 (V + 32706)
+ 0x110b, 0x1165, 0x11bc, 0,
+#undef V8716
+#define V8716 (V + 32710)
+ 0x110b, 0x1165, 0x11bd, 0,
+#undef V8717
+#define V8717 (V + 32714)
+ 0x110b, 0x1165, 0x11be, 0,
+#undef V8718
+#define V8718 (V + 32718)
+ 0x110b, 0x1165, 0x11bf, 0,
+#undef V8719
+#define V8719 (V + 32722)
+ 0x110b, 0x1165, 0x11c0, 0,
+#undef V8720
+#define V8720 (V + 32726)
+ 0x110b, 0x1165, 0x11c1, 0,
+#undef V8721
+#define V8721 (V + 32730)
+ 0x110b, 0x1165, 0x11c2, 0,
+#undef V8722
+#define V8722 (V + 32734)
+ 0x110b, 0x1166, 0,
+#undef V8723
+#define V8723 (V + 32737)
+ 0x110b, 0x1166, 0x11a8, 0,
+#undef V8724
+#define V8724 (V + 32741)
+ 0x110b, 0x1166, 0x11a9, 0,
+#undef V8725
+#define V8725 (V + 32745)
+ 0x110b, 0x1166, 0x11aa, 0,
+#undef V8726
+#define V8726 (V + 32749)
+ 0x110b, 0x1166, 0x11ab, 0,
+#undef V8727
+#define V8727 (V + 32753)
+ 0x110b, 0x1166, 0x11ac, 0,
+#undef V8728
+#define V8728 (V + 32757)
+ 0x110b, 0x1166, 0x11ad, 0,
+#undef V8729
+#define V8729 (V + 32761)
+ 0x110b, 0x1166, 0x11ae, 0,
+#undef V8730
+#define V8730 (V + 32765)
+ 0x110b, 0x1166, 0x11af, 0,
+#undef V8731
+#define V8731 (V + 32769)
+ 0x110b, 0x1166, 0x11b0, 0,
+#undef V8732
+#define V8732 (V + 32773)
+ 0x110b, 0x1166, 0x11b1, 0,
+#undef V8733
+#define V8733 (V + 32777)
+ 0x110b, 0x1166, 0x11b2, 0,
+#undef V8734
+#define V8734 (V + 32781)
+ 0x110b, 0x1166, 0x11b3, 0,
+#undef V8735
+#define V8735 (V + 32785)
+ 0x110b, 0x1166, 0x11b4, 0,
+#undef V8736
+#define V8736 (V + 32789)
+ 0x110b, 0x1166, 0x11b5, 0,
+#undef V8737
+#define V8737 (V + 32793)
+ 0x110b, 0x1166, 0x11b6, 0,
+#undef V8738
+#define V8738 (V + 32797)
+ 0x110b, 0x1166, 0x11b7, 0,
+#undef V8739
+#define V8739 (V + 32801)
+ 0x110b, 0x1166, 0x11b8, 0,
+#undef V8740
+#define V8740 (V + 32805)
+ 0x110b, 0x1166, 0x11b9, 0,
+#undef V8741
+#define V8741 (V + 32809)
+ 0x110b, 0x1166, 0x11ba, 0,
+#undef V8742
+#define V8742 (V + 32813)
+ 0x110b, 0x1166, 0x11bb, 0,
+#undef V8743
+#define V8743 (V + 32817)
+ 0x110b, 0x1166, 0x11bc, 0,
+#undef V8744
+#define V8744 (V + 32821)
+ 0x110b, 0x1166, 0x11bd, 0,
+#undef V8745
+#define V8745 (V + 32825)
+ 0x110b, 0x1166, 0x11be, 0,
+#undef V8746
+#define V8746 (V + 32829)
+ 0x110b, 0x1166, 0x11bf, 0,
+#undef V8747
+#define V8747 (V + 32833)
+ 0x110b, 0x1166, 0x11c0, 0,
+#undef V8748
+#define V8748 (V + 32837)
+ 0x110b, 0x1166, 0x11c1, 0,
+#undef V8749
+#define V8749 (V + 32841)
+ 0x110b, 0x1166, 0x11c2, 0,
+#undef V8750
+#define V8750 (V + 32845)
+ 0x110b, 0x1167, 0,
+#undef V8751
+#define V8751 (V + 32848)
+ 0x110b, 0x1167, 0x11a8, 0,
+#undef V8752
+#define V8752 (V + 32852)
+ 0x110b, 0x1167, 0x11a9, 0,
+#undef V8753
+#define V8753 (V + 32856)
+ 0x110b, 0x1167, 0x11aa, 0,
+#undef V8754
+#define V8754 (V + 32860)
+ 0x110b, 0x1167, 0x11ab, 0,
+#undef V8755
+#define V8755 (V + 32864)
+ 0x110b, 0x1167, 0x11ac, 0,
+#undef V8756
+#define V8756 (V + 32868)
+ 0x110b, 0x1167, 0x11ad, 0,
+#undef V8757
+#define V8757 (V + 32872)
+ 0x110b, 0x1167, 0x11ae, 0,
+#undef V8758
+#define V8758 (V + 32876)
+ 0x110b, 0x1167, 0x11af, 0,
+#undef V8759
+#define V8759 (V + 32880)
+ 0x110b, 0x1167, 0x11b0, 0,
+#undef V8760
+#define V8760 (V + 32884)
+ 0x110b, 0x1167, 0x11b1, 0,
+#undef V8761
+#define V8761 (V + 32888)
+ 0x110b, 0x1167, 0x11b2, 0,
+#undef V8762
+#define V8762 (V + 32892)
+ 0x110b, 0x1167, 0x11b3, 0,
+#undef V8763
+#define V8763 (V + 32896)
+ 0x110b, 0x1167, 0x11b4, 0,
+#undef V8764
+#define V8764 (V + 32900)
+ 0x110b, 0x1167, 0x11b5, 0,
+#undef V8765
+#define V8765 (V + 32904)
+ 0x110b, 0x1167, 0x11b6, 0,
+#undef V8766
+#define V8766 (V + 32908)
+ 0x110b, 0x1167, 0x11b7, 0,
+#undef V8767
+#define V8767 (V + 32912)
+ 0x110b, 0x1167, 0x11b8, 0,
+#undef V8768
+#define V8768 (V + 32916)
+ 0x110b, 0x1167, 0x11b9, 0,
+#undef V8769
+#define V8769 (V + 32920)
+ 0x110b, 0x1167, 0x11ba, 0,
+#undef V8770
+#define V8770 (V + 32924)
+ 0x110b, 0x1167, 0x11bb, 0,
+#undef V8771
+#define V8771 (V + 32928)
+ 0x110b, 0x1167, 0x11bc, 0,
+#undef V8772
+#define V8772 (V + 32932)
+ 0x110b, 0x1167, 0x11bd, 0,
+#undef V8773
+#define V8773 (V + 32936)
+ 0x110b, 0x1167, 0x11be, 0,
+#undef V8774
+#define V8774 (V + 32940)
+ 0x110b, 0x1167, 0x11bf, 0,
+#undef V8775
+#define V8775 (V + 32944)
+ 0x110b, 0x1167, 0x11c0, 0,
+#undef V8776
+#define V8776 (V + 32948)
+ 0x110b, 0x1167, 0x11c1, 0,
+#undef V8777
+#define V8777 (V + 32952)
+ 0x110b, 0x1167, 0x11c2, 0,
+#undef V8778
+#define V8778 (V + 32956)
+ 0x110b, 0x1168, 0,
+#undef V8779
+#define V8779 (V + 32959)
+ 0x110b, 0x1168, 0x11a8, 0,
+#undef V8780
+#define V8780 (V + 32963)
+ 0x110b, 0x1168, 0x11a9, 0,
+#undef V8781
+#define V8781 (V + 32967)
+ 0x110b, 0x1168, 0x11aa, 0,
+#undef V8782
+#define V8782 (V + 32971)
+ 0x110b, 0x1168, 0x11ab, 0,
+#undef V8783
+#define V8783 (V + 32975)
+ 0x110b, 0x1168, 0x11ac, 0,
+#undef V8784
+#define V8784 (V + 32979)
+ 0x110b, 0x1168, 0x11ad, 0,
+#undef V8785
+#define V8785 (V + 32983)
+ 0x110b, 0x1168, 0x11ae, 0,
+#undef V8786
+#define V8786 (V + 32987)
+ 0x110b, 0x1168, 0x11af, 0,
+#undef V8787
+#define V8787 (V + 32991)
+ 0x110b, 0x1168, 0x11b0, 0,
+#undef V8788
+#define V8788 (V + 32995)
+ 0x110b, 0x1168, 0x11b1, 0,
+#undef V8789
+#define V8789 (V + 32999)
+ 0x110b, 0x1168, 0x11b2, 0,
+#undef V8790
+#define V8790 (V + 33003)
+ 0x110b, 0x1168, 0x11b3, 0,
+#undef V8791
+#define V8791 (V + 33007)
+ 0x110b, 0x1168, 0x11b4, 0,
+#undef V8792
+#define V8792 (V + 33011)
+ 0x110b, 0x1168, 0x11b5, 0,
+#undef V8793
+#define V8793 (V + 33015)
+ 0x110b, 0x1168, 0x11b6, 0,
+#undef V8794
+#define V8794 (V + 33019)
+ 0x110b, 0x1168, 0x11b7, 0,
+#undef V8795
+#define V8795 (V + 33023)
+ 0x110b, 0x1168, 0x11b8, 0,
+#undef V8796
+#define V8796 (V + 33027)
+ 0x110b, 0x1168, 0x11b9, 0,
+#undef V8797
+#define V8797 (V + 33031)
+ 0x110b, 0x1168, 0x11ba, 0,
+#undef V8798
+#define V8798 (V + 33035)
+ 0x110b, 0x1168, 0x11bb, 0,
+#undef V8799
+#define V8799 (V + 33039)
+ 0x110b, 0x1168, 0x11bc, 0,
+#undef V8800
+#define V8800 (V + 33043)
+ 0x110b, 0x1168, 0x11bd, 0,
+#undef V8801
+#define V8801 (V + 33047)
+ 0x110b, 0x1168, 0x11be, 0,
+#undef V8802
+#define V8802 (V + 33051)
+ 0x110b, 0x1168, 0x11bf, 0,
+#undef V8803
+#define V8803 (V + 33055)
+ 0x110b, 0x1168, 0x11c0, 0,
+#undef V8804
+#define V8804 (V + 33059)
+ 0x110b, 0x1168, 0x11c1, 0,
+#undef V8805
+#define V8805 (V + 33063)
+ 0x110b, 0x1168, 0x11c2, 0,
+#undef V8806
+#define V8806 (V + 33067)
+ 0x110b, 0x1169, 0,
+#undef V8807
+#define V8807 (V + 33070)
+ 0x110b, 0x1169, 0x11a8, 0,
+#undef V8808
+#define V8808 (V + 33074)
+ 0x110b, 0x1169, 0x11a9, 0,
+#undef V8809
+#define V8809 (V + 33078)
+ 0x110b, 0x1169, 0x11aa, 0,
+#undef V8810
+#define V8810 (V + 33082)
+ 0x110b, 0x1169, 0x11ab, 0,
+#undef V8811
+#define V8811 (V + 33086)
+ 0x110b, 0x1169, 0x11ac, 0,
+#undef V8812
+#define V8812 (V + 33090)
+ 0x110b, 0x1169, 0x11ad, 0,
+#undef V8813
+#define V8813 (V + 33094)
+ 0x110b, 0x1169, 0x11ae, 0,
+#undef V8814
+#define V8814 (V + 33098)
+ 0x110b, 0x1169, 0x11af, 0,
+#undef V8815
+#define V8815 (V + 33102)
+ 0x110b, 0x1169, 0x11b0, 0,
+#undef V8816
+#define V8816 (V + 33106)
+ 0x110b, 0x1169, 0x11b1, 0,
+#undef V8817
+#define V8817 (V + 33110)
+ 0x110b, 0x1169, 0x11b2, 0,
+#undef V8818
+#define V8818 (V + 33114)
+ 0x110b, 0x1169, 0x11b3, 0,
+#undef V8819
+#define V8819 (V + 33118)
+ 0x110b, 0x1169, 0x11b4, 0,
+#undef V8820
+#define V8820 (V + 33122)
+ 0x110b, 0x1169, 0x11b5, 0,
+#undef V8821
+#define V8821 (V + 33126)
+ 0x110b, 0x1169, 0x11b6, 0,
+#undef V8822
+#define V8822 (V + 33130)
+ 0x110b, 0x1169, 0x11b7, 0,
+#undef V8823
+#define V8823 (V + 33134)
+ 0x110b, 0x1169, 0x11b8, 0,
+#undef V8824
+#define V8824 (V + 33138)
+ 0x110b, 0x1169, 0x11b9, 0,
+#undef V8825
+#define V8825 (V + 33142)
+ 0x110b, 0x1169, 0x11ba, 0,
+#undef V8826
+#define V8826 (V + 33146)
+ 0x110b, 0x1169, 0x11bb, 0,
+#undef V8827
+#define V8827 (V + 33150)
+ 0x110b, 0x1169, 0x11bc, 0,
+#undef V8828
+#define V8828 (V + 33154)
+ 0x110b, 0x1169, 0x11bd, 0,
+#undef V8829
+#define V8829 (V + 33158)
+ 0x110b, 0x1169, 0x11be, 0,
+#undef V8830
+#define V8830 (V + 33162)
+ 0x110b, 0x1169, 0x11bf, 0,
+#undef V8831
+#define V8831 (V + 33166)
+ 0x110b, 0x1169, 0x11c0, 0,
+#undef V8832
+#define V8832 (V + 33170)
+ 0x110b, 0x1169, 0x11c1, 0,
+#undef V8833
+#define V8833 (V + 33174)
+ 0x110b, 0x1169, 0x11c2, 0,
+#undef V8834
+#define V8834 (V + 33178)
+ 0x110b, 0x116a, 0,
+#undef V8835
+#define V8835 (V + 33181)
+ 0x110b, 0x116a, 0x11a8, 0,
+#undef V8836
+#define V8836 (V + 33185)
+ 0x110b, 0x116a, 0x11a9, 0,
+#undef V8837
+#define V8837 (V + 33189)
+ 0x110b, 0x116a, 0x11aa, 0,
+#undef V8838
+#define V8838 (V + 33193)
+ 0x110b, 0x116a, 0x11ab, 0,
+#undef V8839
+#define V8839 (V + 33197)
+ 0x110b, 0x116a, 0x11ac, 0,
+#undef V8840
+#define V8840 (V + 33201)
+ 0x110b, 0x116a, 0x11ad, 0,
+#undef V8841
+#define V8841 (V + 33205)
+ 0x110b, 0x116a, 0x11ae, 0,
+#undef V8842
+#define V8842 (V + 33209)
+ 0x110b, 0x116a, 0x11af, 0,
+#undef V8843
+#define V8843 (V + 33213)
+ 0x110b, 0x116a, 0x11b0, 0,
+#undef V8844
+#define V8844 (V + 33217)
+ 0x110b, 0x116a, 0x11b1, 0,
+#undef V8845
+#define V8845 (V + 33221)
+ 0x110b, 0x116a, 0x11b2, 0,
+#undef V8846
+#define V8846 (V + 33225)
+ 0x110b, 0x116a, 0x11b3, 0,
+#undef V8847
+#define V8847 (V + 33229)
+ 0x110b, 0x116a, 0x11b4, 0,
+#undef V8848
+#define V8848 (V + 33233)
+ 0x110b, 0x116a, 0x11b5, 0,
+#undef V8849
+#define V8849 (V + 33237)
+ 0x110b, 0x116a, 0x11b6, 0,
+#undef V8850
+#define V8850 (V + 33241)
+ 0x110b, 0x116a, 0x11b7, 0,
+#undef V8851
+#define V8851 (V + 33245)
+ 0x110b, 0x116a, 0x11b8, 0,
+#undef V8852
+#define V8852 (V + 33249)
+ 0x110b, 0x116a, 0x11b9, 0,
+#undef V8853
+#define V8853 (V + 33253)
+ 0x110b, 0x116a, 0x11ba, 0,
+#undef V8854
+#define V8854 (V + 33257)
+ 0x110b, 0x116a, 0x11bb, 0,
+#undef V8855
+#define V8855 (V + 33261)
+ 0x110b, 0x116a, 0x11bc, 0,
+#undef V8856
+#define V8856 (V + 33265)
+ 0x110b, 0x116a, 0x11bd, 0,
+#undef V8857
+#define V8857 (V + 33269)
+ 0x110b, 0x116a, 0x11be, 0,
+#undef V8858
+#define V8858 (V + 33273)
+ 0x110b, 0x116a, 0x11bf, 0,
+#undef V8859
+#define V8859 (V + 33277)
+ 0x110b, 0x116a, 0x11c0, 0,
+#undef V8860
+#define V8860 (V + 33281)
+ 0x110b, 0x116a, 0x11c1, 0,
+#undef V8861
+#define V8861 (V + 33285)
+ 0x110b, 0x116a, 0x11c2, 0,
+#undef V8862
+#define V8862 (V + 33289)
+ 0x110b, 0x116b, 0,
+#undef V8863
+#define V8863 (V + 33292)
+ 0x110b, 0x116b, 0x11a8, 0,
+#undef V8864
+#define V8864 (V + 33296)
+ 0x110b, 0x116b, 0x11a9, 0,
+#undef V8865
+#define V8865 (V + 33300)
+ 0x110b, 0x116b, 0x11aa, 0,
+#undef V8866
+#define V8866 (V + 33304)
+ 0x110b, 0x116b, 0x11ab, 0,
+#undef V8867
+#define V8867 (V + 33308)
+ 0x110b, 0x116b, 0x11ac, 0,
+#undef V8868
+#define V8868 (V + 33312)
+ 0x110b, 0x116b, 0x11ad, 0,
+#undef V8869
+#define V8869 (V + 33316)
+ 0x110b, 0x116b, 0x11ae, 0,
+#undef V8870
+#define V8870 (V + 33320)
+ 0x110b, 0x116b, 0x11af, 0,
+#undef V8871
+#define V8871 (V + 33324)
+ 0x110b, 0x116b, 0x11b0, 0,
+#undef V8872
+#define V8872 (V + 33328)
+ 0x110b, 0x116b, 0x11b1, 0,
+#undef V8873
+#define V8873 (V + 33332)
+ 0x110b, 0x116b, 0x11b2, 0,
+#undef V8874
+#define V8874 (V + 33336)
+ 0x110b, 0x116b, 0x11b3, 0,
+#undef V8875
+#define V8875 (V + 33340)
+ 0x110b, 0x116b, 0x11b4, 0,
+#undef V8876
+#define V8876 (V + 33344)
+ 0x110b, 0x116b, 0x11b5, 0,
+#undef V8877
+#define V8877 (V + 33348)
+ 0x110b, 0x116b, 0x11b6, 0,
+#undef V8878
+#define V8878 (V + 33352)
+ 0x110b, 0x116b, 0x11b7, 0,
+#undef V8879
+#define V8879 (V + 33356)
+ 0x110b, 0x116b, 0x11b8, 0,
+#undef V8880
+#define V8880 (V + 33360)
+ 0x110b, 0x116b, 0x11b9, 0,
+#undef V8881
+#define V8881 (V + 33364)
+ 0x110b, 0x116b, 0x11ba, 0,
+#undef V8882
+#define V8882 (V + 33368)
+ 0x110b, 0x116b, 0x11bb, 0,
+#undef V8883
+#define V8883 (V + 33372)
+ 0x110b, 0x116b, 0x11bc, 0,
+#undef V8884
+#define V8884 (V + 33376)
+ 0x110b, 0x116b, 0x11bd, 0,
+#undef V8885
+#define V8885 (V + 33380)
+ 0x110b, 0x116b, 0x11be, 0,
+#undef V8886
+#define V8886 (V + 33384)
+ 0x110b, 0x116b, 0x11bf, 0,
+#undef V8887
+#define V8887 (V + 33388)
+ 0x110b, 0x116b, 0x11c0, 0,
+#undef V8888
+#define V8888 (V + 33392)
+ 0x110b, 0x116b, 0x11c1, 0,
+#undef V8889
+#define V8889 (V + 33396)
+ 0x110b, 0x116b, 0x11c2, 0,
+#undef V8890
+#define V8890 (V + 33400)
+ 0x110b, 0x116c, 0,
+#undef V8891
+#define V8891 (V + 33403)
+ 0x110b, 0x116c, 0x11a8, 0,
+#undef V8892
+#define V8892 (V + 33407)
+ 0x110b, 0x116c, 0x11a9, 0,
+#undef V8893
+#define V8893 (V + 33411)
+ 0x110b, 0x116c, 0x11aa, 0,
+#undef V8894
+#define V8894 (V + 33415)
+ 0x110b, 0x116c, 0x11ab, 0,
+#undef V8895
+#define V8895 (V + 33419)
+ 0x110b, 0x116c, 0x11ac, 0,
+#undef V8896
+#define V8896 (V + 33423)
+ 0x110b, 0x116c, 0x11ad, 0,
+#undef V8897
+#define V8897 (V + 33427)
+ 0x110b, 0x116c, 0x11ae, 0,
+#undef V8898
+#define V8898 (V + 33431)
+ 0x110b, 0x116c, 0x11af, 0,
+#undef V8899
+#define V8899 (V + 33435)
+ 0x110b, 0x116c, 0x11b0, 0,
+#undef V8900
+#define V8900 (V + 33439)
+ 0x110b, 0x116c, 0x11b1, 0,
+#undef V8901
+#define V8901 (V + 33443)
+ 0x110b, 0x116c, 0x11b2, 0,
+#undef V8902
+#define V8902 (V + 33447)
+ 0x110b, 0x116c, 0x11b3, 0,
+#undef V8903
+#define V8903 (V + 33451)
+ 0x110b, 0x116c, 0x11b4, 0,
+#undef V8904
+#define V8904 (V + 33455)
+ 0x110b, 0x116c, 0x11b5, 0,
+#undef V8905
+#define V8905 (V + 33459)
+ 0x110b, 0x116c, 0x11b6, 0,
+#undef V8906
+#define V8906 (V + 33463)
+ 0x110b, 0x116c, 0x11b7, 0,
+#undef V8907
+#define V8907 (V + 33467)
+ 0x110b, 0x116c, 0x11b8, 0,
+#undef V8908
+#define V8908 (V + 33471)
+ 0x110b, 0x116c, 0x11b9, 0,
+#undef V8909
+#define V8909 (V + 33475)
+ 0x110b, 0x116c, 0x11ba, 0,
+#undef V8910
+#define V8910 (V + 33479)
+ 0x110b, 0x116c, 0x11bb, 0,
+#undef V8911
+#define V8911 (V + 33483)
+ 0x110b, 0x116c, 0x11bc, 0,
+#undef V8912
+#define V8912 (V + 33487)
+ 0x110b, 0x116c, 0x11bd, 0,
+#undef V8913
+#define V8913 (V + 33491)
+ 0x110b, 0x116c, 0x11be, 0,
+#undef V8914
+#define V8914 (V + 33495)
+ 0x110b, 0x116c, 0x11bf, 0,
+#undef V8915
+#define V8915 (V + 33499)
+ 0x110b, 0x116c, 0x11c0, 0,
+#undef V8916
+#define V8916 (V + 33503)
+ 0x110b, 0x116c, 0x11c1, 0,
+#undef V8917
+#define V8917 (V + 33507)
+ 0x110b, 0x116c, 0x11c2, 0,
+#undef V8918
+#define V8918 (V + 33511)
+ 0x110b, 0x116d, 0,
+#undef V8919
+#define V8919 (V + 33514)
+ 0x110b, 0x116d, 0x11a8, 0,
+#undef V8920
+#define V8920 (V + 33518)
+ 0x110b, 0x116d, 0x11a9, 0,
+#undef V8921
+#define V8921 (V + 33522)
+ 0x110b, 0x116d, 0x11aa, 0,
+#undef V8922
+#define V8922 (V + 33526)
+ 0x110b, 0x116d, 0x11ab, 0,
+#undef V8923
+#define V8923 (V + 33530)
+ 0x110b, 0x116d, 0x11ac, 0,
+#undef V8924
+#define V8924 (V + 33534)
+ 0x110b, 0x116d, 0x11ad, 0,
+#undef V8925
+#define V8925 (V + 33538)
+ 0x110b, 0x116d, 0x11ae, 0,
+#undef V8926
+#define V8926 (V + 33542)
+ 0x110b, 0x116d, 0x11af, 0,
+#undef V8927
+#define V8927 (V + 33546)
+ 0x110b, 0x116d, 0x11b0, 0,
+#undef V8928
+#define V8928 (V + 33550)
+ 0x110b, 0x116d, 0x11b1, 0,
+#undef V8929
+#define V8929 (V + 33554)
+ 0x110b, 0x116d, 0x11b2, 0,
+#undef V8930
+#define V8930 (V + 33558)
+ 0x110b, 0x116d, 0x11b3, 0,
+#undef V8931
+#define V8931 (V + 33562)
+ 0x110b, 0x116d, 0x11b4, 0,
+#undef V8932
+#define V8932 (V + 33566)
+ 0x110b, 0x116d, 0x11b5, 0,
+#undef V8933
+#define V8933 (V + 33570)
+ 0x110b, 0x116d, 0x11b6, 0,
+#undef V8934
+#define V8934 (V + 33574)
+ 0x110b, 0x116d, 0x11b7, 0,
+#undef V8935
+#define V8935 (V + 33578)
+ 0x110b, 0x116d, 0x11b8, 0,
+#undef V8936
+#define V8936 (V + 33582)
+ 0x110b, 0x116d, 0x11b9, 0,
+#undef V8937
+#define V8937 (V + 33586)
+ 0x110b, 0x116d, 0x11ba, 0,
+#undef V8938
+#define V8938 (V + 33590)
+ 0x110b, 0x116d, 0x11bb, 0,
+#undef V8939
+#define V8939 (V + 33594)
+ 0x110b, 0x116d, 0x11bc, 0,
+#undef V8940
+#define V8940 (V + 33598)
+ 0x110b, 0x116d, 0x11bd, 0,
+#undef V8941
+#define V8941 (V + 33602)
+ 0x110b, 0x116d, 0x11be, 0,
+#undef V8942
+#define V8942 (V + 33606)
+ 0x110b, 0x116d, 0x11bf, 0,
+#undef V8943
+#define V8943 (V + 33610)
+ 0x110b, 0x116d, 0x11c0, 0,
+#undef V8944
+#define V8944 (V + 33614)
+ 0x110b, 0x116d, 0x11c1, 0,
+#undef V8945
+#define V8945 (V + 33618)
+ 0x110b, 0x116d, 0x11c2, 0,
+#undef V8946
+#define V8946 (V + 33622)
+ 0x110b, 0x116e, 0x11a8, 0,
+#undef V8947
+#define V8947 (V + 33626)
+ 0x110b, 0x116e, 0x11a9, 0,
+#undef V8948
+#define V8948 (V + 33630)
+ 0x110b, 0x116e, 0x11aa, 0,
+#undef V8949
+#define V8949 (V + 33634)
+ 0x110b, 0x116e, 0x11ab, 0,
+#undef V8950
+#define V8950 (V + 33638)
+ 0x110b, 0x116e, 0x11ac, 0,
+#undef V8951
+#define V8951 (V + 33642)
+ 0x110b, 0x116e, 0x11ad, 0,
+#undef V8952
+#define V8952 (V + 33646)
+ 0x110b, 0x116e, 0x11ae, 0,
+#undef V8953
+#define V8953 (V + 33650)
+ 0x110b, 0x116e, 0x11af, 0,
+#undef V8954
+#define V8954 (V + 33654)
+ 0x110b, 0x116e, 0x11b0, 0,
+#undef V8955
+#define V8955 (V + 33658)
+ 0x110b, 0x116e, 0x11b1, 0,
+#undef V8956
+#define V8956 (V + 33662)
+ 0x110b, 0x116e, 0x11b2, 0,
+#undef V8957
+#define V8957 (V + 33666)
+ 0x110b, 0x116e, 0x11b3, 0,
+#undef V8958
+#define V8958 (V + 33670)
+ 0x110b, 0x116e, 0x11b4, 0,
+#undef V8959
+#define V8959 (V + 33674)
+ 0x110b, 0x116e, 0x11b5, 0,
+#undef V8960
+#define V8960 (V + 33678)
+ 0x110b, 0x116e, 0x11b6, 0,
+#undef V8961
+#define V8961 (V + 33682)
+ 0x110b, 0x116e, 0x11b7, 0,
+#undef V8962
+#define V8962 (V + 33686)
+ 0x110b, 0x116e, 0x11b8, 0,
+#undef V8963
+#define V8963 (V + 33690)
+ 0x110b, 0x116e, 0x11b9, 0,
+#undef V8964
+#define V8964 (V + 33694)
+ 0x110b, 0x116e, 0x11ba, 0,
+#undef V8965
+#define V8965 (V + 33698)
+ 0x110b, 0x116e, 0x11bb, 0,
+#undef V8966
+#define V8966 (V + 33702)
+ 0x110b, 0x116e, 0x11bc, 0,
+#undef V8967
+#define V8967 (V + 33706)
+ 0x110b, 0x116e, 0x11bd, 0,
+#undef V8968
+#define V8968 (V + 33710)
+ 0x110b, 0x116e, 0x11be, 0,
+#undef V8969
+#define V8969 (V + 33714)
+ 0x110b, 0x116e, 0x11bf, 0,
+#undef V8970
+#define V8970 (V + 33718)
+ 0x110b, 0x116e, 0x11c0, 0,
+#undef V8971
+#define V8971 (V + 33722)
+ 0x110b, 0x116e, 0x11c1, 0,
+#undef V8972
+#define V8972 (V + 33726)
+ 0x110b, 0x116e, 0x11c2, 0,
+#undef V8973
+#define V8973 (V + 33730)
+ 0x110b, 0x116f, 0,
+#undef V8974
+#define V8974 (V + 33733)
+ 0x110b, 0x116f, 0x11a8, 0,
+#undef V8975
+#define V8975 (V + 33737)
+ 0x110b, 0x116f, 0x11a9, 0,
+#undef V8976
+#define V8976 (V + 33741)
+ 0x110b, 0x116f, 0x11aa, 0,
+#undef V8977
+#define V8977 (V + 33745)
+ 0x110b, 0x116f, 0x11ab, 0,
+#undef V8978
+#define V8978 (V + 33749)
+ 0x110b, 0x116f, 0x11ac, 0,
+#undef V8979
+#define V8979 (V + 33753)
+ 0x110b, 0x116f, 0x11ad, 0,
+#undef V8980
+#define V8980 (V + 33757)
+ 0x110b, 0x116f, 0x11ae, 0,
+#undef V8981
+#define V8981 (V + 33761)
+ 0x110b, 0x116f, 0x11af, 0,
+#undef V8982
+#define V8982 (V + 33765)
+ 0x110b, 0x116f, 0x11b0, 0,
+#undef V8983
+#define V8983 (V + 33769)
+ 0x110b, 0x116f, 0x11b1, 0,
+#undef V8984
+#define V8984 (V + 33773)
+ 0x110b, 0x116f, 0x11b2, 0,
+#undef V8985
+#define V8985 (V + 33777)
+ 0x110b, 0x116f, 0x11b3, 0,
+#undef V8986
+#define V8986 (V + 33781)
+ 0x110b, 0x116f, 0x11b4, 0,
+#undef V8987
+#define V8987 (V + 33785)
+ 0x110b, 0x116f, 0x11b5, 0,
+#undef V8988
+#define V8988 (V + 33789)
+ 0x110b, 0x116f, 0x11b6, 0,
+#undef V8989
+#define V8989 (V + 33793)
+ 0x110b, 0x116f, 0x11b7, 0,
+#undef V8990
+#define V8990 (V + 33797)
+ 0x110b, 0x116f, 0x11b8, 0,
+#undef V8991
+#define V8991 (V + 33801)
+ 0x110b, 0x116f, 0x11b9, 0,
+#undef V8992
+#define V8992 (V + 33805)
+ 0x110b, 0x116f, 0x11ba, 0,
+#undef V8993
+#define V8993 (V + 33809)
+ 0x110b, 0x116f, 0x11bb, 0,
+#undef V8994
+#define V8994 (V + 33813)
+ 0x110b, 0x116f, 0x11bc, 0,
+#undef V8995
+#define V8995 (V + 33817)
+ 0x110b, 0x116f, 0x11bd, 0,
+#undef V8996
+#define V8996 (V + 33821)
+ 0x110b, 0x116f, 0x11be, 0,
+#undef V8997
+#define V8997 (V + 33825)
+ 0x110b, 0x116f, 0x11bf, 0,
+#undef V8998
+#define V8998 (V + 33829)
+ 0x110b, 0x116f, 0x11c0, 0,
+#undef V8999
+#define V8999 (V + 33833)
+ 0x110b, 0x116f, 0x11c1, 0,
+#undef V9000
+#define V9000 (V + 33837)
+ 0x110b, 0x116f, 0x11c2, 0,
+#undef V9001
+#define V9001 (V + 33841)
+ 0x110b, 0x1170, 0,
+#undef V9002
+#define V9002 (V + 33844)
+ 0x110b, 0x1170, 0x11a8, 0,
+#undef V9003
+#define V9003 (V + 33848)
+ 0x110b, 0x1170, 0x11a9, 0,
+#undef V9004
+#define V9004 (V + 33852)
+ 0x110b, 0x1170, 0x11aa, 0,
+#undef V9005
+#define V9005 (V + 33856)
+ 0x110b, 0x1170, 0x11ab, 0,
+#undef V9006
+#define V9006 (V + 33860)
+ 0x110b, 0x1170, 0x11ac, 0,
+#undef V9007
+#define V9007 (V + 33864)
+ 0x110b, 0x1170, 0x11ad, 0,
+#undef V9008
+#define V9008 (V + 33868)
+ 0x110b, 0x1170, 0x11ae, 0,
+#undef V9009
+#define V9009 (V + 33872)
+ 0x110b, 0x1170, 0x11af, 0,
+#undef V9010
+#define V9010 (V + 33876)
+ 0x110b, 0x1170, 0x11b0, 0,
+#undef V9011
+#define V9011 (V + 33880)
+ 0x110b, 0x1170, 0x11b1, 0,
+#undef V9012
+#define V9012 (V + 33884)
+ 0x110b, 0x1170, 0x11b2, 0,
+#undef V9013
+#define V9013 (V + 33888)
+ 0x110b, 0x1170, 0x11b3, 0,
+#undef V9014
+#define V9014 (V + 33892)
+ 0x110b, 0x1170, 0x11b4, 0,
+#undef V9015
+#define V9015 (V + 33896)
+ 0x110b, 0x1170, 0x11b5, 0,
+#undef V9016
+#define V9016 (V + 33900)
+ 0x110b, 0x1170, 0x11b6, 0,
+#undef V9017
+#define V9017 (V + 33904)
+ 0x110b, 0x1170, 0x11b7, 0,
+#undef V9018
+#define V9018 (V + 33908)
+ 0x110b, 0x1170, 0x11b8, 0,
+#undef V9019
+#define V9019 (V + 33912)
+ 0x110b, 0x1170, 0x11b9, 0,
+#undef V9020
+#define V9020 (V + 33916)
+ 0x110b, 0x1170, 0x11ba, 0,
+#undef V9021
+#define V9021 (V + 33920)
+ 0x110b, 0x1170, 0x11bb, 0,
+#undef V9022
+#define V9022 (V + 33924)
+ 0x110b, 0x1170, 0x11bc, 0,
+#undef V9023
+#define V9023 (V + 33928)
+ 0x110b, 0x1170, 0x11bd, 0,
+#undef V9024
+#define V9024 (V + 33932)
+ 0x110b, 0x1170, 0x11be, 0,
+#undef V9025
+#define V9025 (V + 33936)
+ 0x110b, 0x1170, 0x11bf, 0,
+#undef V9026
+#define V9026 (V + 33940)
+ 0x110b, 0x1170, 0x11c0, 0,
+#undef V9027
+#define V9027 (V + 33944)
+ 0x110b, 0x1170, 0x11c1, 0,
+#undef V9028
+#define V9028 (V + 33948)
+ 0x110b, 0x1170, 0x11c2, 0,
+#undef V9029
+#define V9029 (V + 33952)
+ 0x110b, 0x1171, 0,
+#undef V9030
+#define V9030 (V + 33955)
+ 0x110b, 0x1171, 0x11a8, 0,
+#undef V9031
+#define V9031 (V + 33959)
+ 0x110b, 0x1171, 0x11a9, 0,
+#undef V9032
+#define V9032 (V + 33963)
+ 0x110b, 0x1171, 0x11aa, 0,
+#undef V9033
+#define V9033 (V + 33967)
+ 0x110b, 0x1171, 0x11ab, 0,
+#undef V9034
+#define V9034 (V + 33971)
+ 0x110b, 0x1171, 0x11ac, 0,
+#undef V9035
+#define V9035 (V + 33975)
+ 0x110b, 0x1171, 0x11ad, 0,
+#undef V9036
+#define V9036 (V + 33979)
+ 0x110b, 0x1171, 0x11ae, 0,
+#undef V9037
+#define V9037 (V + 33983)
+ 0x110b, 0x1171, 0x11af, 0,
+#undef V9038
+#define V9038 (V + 33987)
+ 0x110b, 0x1171, 0x11b0, 0,
+#undef V9039
+#define V9039 (V + 33991)
+ 0x110b, 0x1171, 0x11b1, 0,
+#undef V9040
+#define V9040 (V + 33995)
+ 0x110b, 0x1171, 0x11b2, 0,
+#undef V9041
+#define V9041 (V + 33999)
+ 0x110b, 0x1171, 0x11b3, 0,
+#undef V9042
+#define V9042 (V + 34003)
+ 0x110b, 0x1171, 0x11b4, 0,
+#undef V9043
+#define V9043 (V + 34007)
+ 0x110b, 0x1171, 0x11b5, 0,
+#undef V9044
+#define V9044 (V + 34011)
+ 0x110b, 0x1171, 0x11b6, 0,
+#undef V9045
+#define V9045 (V + 34015)
+ 0x110b, 0x1171, 0x11b7, 0,
+#undef V9046
+#define V9046 (V + 34019)
+ 0x110b, 0x1171, 0x11b8, 0,
+#undef V9047
+#define V9047 (V + 34023)
+ 0x110b, 0x1171, 0x11b9, 0,
+#undef V9048
+#define V9048 (V + 34027)
+ 0x110b, 0x1171, 0x11ba, 0,
+#undef V9049
+#define V9049 (V + 34031)
+ 0x110b, 0x1171, 0x11bb, 0,
+#undef V9050
+#define V9050 (V + 34035)
+ 0x110b, 0x1171, 0x11bc, 0,
+#undef V9051
+#define V9051 (V + 34039)
+ 0x110b, 0x1171, 0x11bd, 0,
+#undef V9052
+#define V9052 (V + 34043)
+ 0x110b, 0x1171, 0x11be, 0,
+#undef V9053
+#define V9053 (V + 34047)
+ 0x110b, 0x1171, 0x11bf, 0,
+#undef V9054
+#define V9054 (V + 34051)
+ 0x110b, 0x1171, 0x11c0, 0,
+#undef V9055
+#define V9055 (V + 34055)
+ 0x110b, 0x1171, 0x11c1, 0,
+#undef V9056
+#define V9056 (V + 34059)
+ 0x110b, 0x1171, 0x11c2, 0,
+#undef V9057
+#define V9057 (V + 34063)
+ 0x110b, 0x1172, 0,
+#undef V9058
+#define V9058 (V + 34066)
+ 0x110b, 0x1172, 0x11a8, 0,
+#undef V9059
+#define V9059 (V + 34070)
+ 0x110b, 0x1172, 0x11a9, 0,
+#undef V9060
+#define V9060 (V + 34074)
+ 0x110b, 0x1172, 0x11aa, 0,
+#undef V9061
+#define V9061 (V + 34078)
+ 0x110b, 0x1172, 0x11ab, 0,
+#undef V9062
+#define V9062 (V + 34082)
+ 0x110b, 0x1172, 0x11ac, 0,
+#undef V9063
+#define V9063 (V + 34086)
+ 0x110b, 0x1172, 0x11ad, 0,
+#undef V9064
+#define V9064 (V + 34090)
+ 0x110b, 0x1172, 0x11ae, 0,
+#undef V9065
+#define V9065 (V + 34094)
+ 0x110b, 0x1172, 0x11af, 0,
+#undef V9066
+#define V9066 (V + 34098)
+ 0x110b, 0x1172, 0x11b0, 0,
+#undef V9067
+#define V9067 (V + 34102)
+ 0x110b, 0x1172, 0x11b1, 0,
+#undef V9068
+#define V9068 (V + 34106)
+ 0x110b, 0x1172, 0x11b2, 0,
+#undef V9069
+#define V9069 (V + 34110)
+ 0x110b, 0x1172, 0x11b3, 0,
+#undef V9070
+#define V9070 (V + 34114)
+ 0x110b, 0x1172, 0x11b4, 0,
+#undef V9071
+#define V9071 (V + 34118)
+ 0x110b, 0x1172, 0x11b5, 0,
+#undef V9072
+#define V9072 (V + 34122)
+ 0x110b, 0x1172, 0x11b6, 0,
+#undef V9073
+#define V9073 (V + 34126)
+ 0x110b, 0x1172, 0x11b7, 0,
+#undef V9074
+#define V9074 (V + 34130)
+ 0x110b, 0x1172, 0x11b8, 0,
+#undef V9075
+#define V9075 (V + 34134)
+ 0x110b, 0x1172, 0x11b9, 0,
+#undef V9076
+#define V9076 (V + 34138)
+ 0x110b, 0x1172, 0x11ba, 0,
+#undef V9077
+#define V9077 (V + 34142)
+ 0x110b, 0x1172, 0x11bb, 0,
+#undef V9078
+#define V9078 (V + 34146)
+ 0x110b, 0x1172, 0x11bc, 0,
+#undef V9079
+#define V9079 (V + 34150)
+ 0x110b, 0x1172, 0x11bd, 0,
+#undef V9080
+#define V9080 (V + 34154)
+ 0x110b, 0x1172, 0x11be, 0,
+#undef V9081
+#define V9081 (V + 34158)
+ 0x110b, 0x1172, 0x11bf, 0,
+#undef V9082
+#define V9082 (V + 34162)
+ 0x110b, 0x1172, 0x11c0, 0,
+#undef V9083
+#define V9083 (V + 34166)
+ 0x110b, 0x1172, 0x11c1, 0,
+#undef V9084
+#define V9084 (V + 34170)
+ 0x110b, 0x1172, 0x11c2, 0,
+#undef V9085
+#define V9085 (V + 34174)
+ 0x110b, 0x1173, 0,
+#undef V9086
+#define V9086 (V + 34177)
+ 0x110b, 0x1173, 0x11a8, 0,
+#undef V9087
+#define V9087 (V + 34181)
+ 0x110b, 0x1173, 0x11a9, 0,
+#undef V9088
+#define V9088 (V + 34185)
+ 0x110b, 0x1173, 0x11aa, 0,
+#undef V9089
+#define V9089 (V + 34189)
+ 0x110b, 0x1173, 0x11ab, 0,
+#undef V9090
+#define V9090 (V + 34193)
+ 0x110b, 0x1173, 0x11ac, 0,
+#undef V9091
+#define V9091 (V + 34197)
+ 0x110b, 0x1173, 0x11ad, 0,
+#undef V9092
+#define V9092 (V + 34201)
+ 0x110b, 0x1173, 0x11ae, 0,
+#undef V9093
+#define V9093 (V + 34205)
+ 0x110b, 0x1173, 0x11af, 0,
+#undef V9094
+#define V9094 (V + 34209)
+ 0x110b, 0x1173, 0x11b0, 0,
+#undef V9095
+#define V9095 (V + 34213)
+ 0x110b, 0x1173, 0x11b1, 0,
+#undef V9096
+#define V9096 (V + 34217)
+ 0x110b, 0x1173, 0x11b2, 0,
+#undef V9097
+#define V9097 (V + 34221)
+ 0x110b, 0x1173, 0x11b3, 0,
+#undef V9098
+#define V9098 (V + 34225)
+ 0x110b, 0x1173, 0x11b4, 0,
+#undef V9099
+#define V9099 (V + 34229)
+ 0x110b, 0x1173, 0x11b5, 0,
+#undef V9100
+#define V9100 (V + 34233)
+ 0x110b, 0x1173, 0x11b6, 0,
+#undef V9101
+#define V9101 (V + 34237)
+ 0x110b, 0x1173, 0x11b7, 0,
+#undef V9102
+#define V9102 (V + 34241)
+ 0x110b, 0x1173, 0x11b8, 0,
+#undef V9103
+#define V9103 (V + 34245)
+ 0x110b, 0x1173, 0x11b9, 0,
+#undef V9104
+#define V9104 (V + 34249)
+ 0x110b, 0x1173, 0x11ba, 0,
+#undef V9105
+#define V9105 (V + 34253)
+ 0x110b, 0x1173, 0x11bb, 0,
+#undef V9106
+#define V9106 (V + 34257)
+ 0x110b, 0x1173, 0x11bc, 0,
+#undef V9107
+#define V9107 (V + 34261)
+ 0x110b, 0x1173, 0x11bd, 0,
+#undef V9108
+#define V9108 (V + 34265)
+ 0x110b, 0x1173, 0x11be, 0,
+#undef V9109
+#define V9109 (V + 34269)
+ 0x110b, 0x1173, 0x11bf, 0,
+#undef V9110
+#define V9110 (V + 34273)
+ 0x110b, 0x1173, 0x11c0, 0,
+#undef V9111
+#define V9111 (V + 34277)
+ 0x110b, 0x1173, 0x11c1, 0,
+#undef V9112
+#define V9112 (V + 34281)
+ 0x110b, 0x1173, 0x11c2, 0,
+#undef V9113
+#define V9113 (V + 34285)
+ 0x110b, 0x1174, 0,
+#undef V9114
+#define V9114 (V + 34288)
+ 0x110b, 0x1174, 0x11a8, 0,
+#undef V9115
+#define V9115 (V + 34292)
+ 0x110b, 0x1174, 0x11a9, 0,
+#undef V9116
+#define V9116 (V + 34296)
+ 0x110b, 0x1174, 0x11aa, 0,
+#undef V9117
+#define V9117 (V + 34300)
+ 0x110b, 0x1174, 0x11ab, 0,
+#undef V9118
+#define V9118 (V + 34304)
+ 0x110b, 0x1174, 0x11ac, 0,
+#undef V9119
+#define V9119 (V + 34308)
+ 0x110b, 0x1174, 0x11ad, 0,
+#undef V9120
+#define V9120 (V + 34312)
+ 0x110b, 0x1174, 0x11ae, 0,
+#undef V9121
+#define V9121 (V + 34316)
+ 0x110b, 0x1174, 0x11af, 0,
+#undef V9122
+#define V9122 (V + 34320)
+ 0x110b, 0x1174, 0x11b0, 0,
+#undef V9123
+#define V9123 (V + 34324)
+ 0x110b, 0x1174, 0x11b1, 0,
+#undef V9124
+#define V9124 (V + 34328)
+ 0x110b, 0x1174, 0x11b2, 0,
+#undef V9125
+#define V9125 (V + 34332)
+ 0x110b, 0x1174, 0x11b3, 0,
+#undef V9126
+#define V9126 (V + 34336)
+ 0x110b, 0x1174, 0x11b4, 0,
+#undef V9127
+#define V9127 (V + 34340)
+ 0x110b, 0x1174, 0x11b5, 0,
+#undef V9128
+#define V9128 (V + 34344)
+ 0x110b, 0x1174, 0x11b6, 0,
+#undef V9129
+#define V9129 (V + 34348)
+ 0x110b, 0x1174, 0x11b7, 0,
+#undef V9130
+#define V9130 (V + 34352)
+ 0x110b, 0x1174, 0x11b8, 0,
+#undef V9131
+#define V9131 (V + 34356)
+ 0x110b, 0x1174, 0x11b9, 0,
+#undef V9132
+#define V9132 (V + 34360)
+ 0x110b, 0x1174, 0x11ba, 0,
+#undef V9133
+#define V9133 (V + 34364)
+ 0x110b, 0x1174, 0x11bb, 0,
+#undef V9134
+#define V9134 (V + 34368)
+ 0x110b, 0x1174, 0x11bc, 0,
+#undef V9135
+#define V9135 (V + 34372)
+ 0x110b, 0x1174, 0x11bd, 0,
+#undef V9136
+#define V9136 (V + 34376)
+ 0x110b, 0x1174, 0x11be, 0,
+#undef V9137
+#define V9137 (V + 34380)
+ 0x110b, 0x1174, 0x11bf, 0,
+#undef V9138
+#define V9138 (V + 34384)
+ 0x110b, 0x1174, 0x11c0, 0,
+#undef V9139
+#define V9139 (V + 34388)
+ 0x110b, 0x1174, 0x11c1, 0,
+#undef V9140
+#define V9140 (V + 34392)
+ 0x110b, 0x1174, 0x11c2, 0,
+#undef V9141
+#define V9141 (V + 34396)
+ 0x110b, 0x1175, 0,
+#undef V9142
+#define V9142 (V + 34399)
+ 0x110b, 0x1175, 0x11a8, 0,
+#undef V9143
+#define V9143 (V + 34403)
+ 0x110b, 0x1175, 0x11a9, 0,
+#undef V9144
+#define V9144 (V + 34407)
+ 0x110b, 0x1175, 0x11aa, 0,
+#undef V9145
+#define V9145 (V + 34411)
+ 0x110b, 0x1175, 0x11ab, 0,
+#undef V9146
+#define V9146 (V + 34415)
+ 0x110b, 0x1175, 0x11ac, 0,
+#undef V9147
+#define V9147 (V + 34419)
+ 0x110b, 0x1175, 0x11ad, 0,
+#undef V9148
+#define V9148 (V + 34423)
+ 0x110b, 0x1175, 0x11ae, 0,
+#undef V9149
+#define V9149 (V + 34427)
+ 0x110b, 0x1175, 0x11af, 0,
+#undef V9150
+#define V9150 (V + 34431)
+ 0x110b, 0x1175, 0x11b0, 0,
+#undef V9151
+#define V9151 (V + 34435)
+ 0x110b, 0x1175, 0x11b1, 0,
+#undef V9152
+#define V9152 (V + 34439)
+ 0x110b, 0x1175, 0x11b2, 0,
+#undef V9153
+#define V9153 (V + 34443)
+ 0x110b, 0x1175, 0x11b3, 0,
+#undef V9154
+#define V9154 (V + 34447)
+ 0x110b, 0x1175, 0x11b4, 0,
+#undef V9155
+#define V9155 (V + 34451)
+ 0x110b, 0x1175, 0x11b5, 0,
+#undef V9156
+#define V9156 (V + 34455)
+ 0x110b, 0x1175, 0x11b6, 0,
+#undef V9157
+#define V9157 (V + 34459)
+ 0x110b, 0x1175, 0x11b7, 0,
+#undef V9158
+#define V9158 (V + 34463)
+ 0x110b, 0x1175, 0x11b8, 0,
+#undef V9159
+#define V9159 (V + 34467)
+ 0x110b, 0x1175, 0x11b9, 0,
+#undef V9160
+#define V9160 (V + 34471)
+ 0x110b, 0x1175, 0x11ba, 0,
+#undef V9161
+#define V9161 (V + 34475)
+ 0x110b, 0x1175, 0x11bb, 0,
+#undef V9162
+#define V9162 (V + 34479)
+ 0x110b, 0x1175, 0x11bc, 0,
+#undef V9163
+#define V9163 (V + 34483)
+ 0x110b, 0x1175, 0x11bd, 0,
+#undef V9164
+#define V9164 (V + 34487)
+ 0x110b, 0x1175, 0x11be, 0,
+#undef V9165
+#define V9165 (V + 34491)
+ 0x110b, 0x1175, 0x11bf, 0,
+#undef V9166
+#define V9166 (V + 34495)
+ 0x110b, 0x1175, 0x11c0, 0,
+#undef V9167
+#define V9167 (V + 34499)
+ 0x110b, 0x1175, 0x11c1, 0,
+#undef V9168
+#define V9168 (V + 34503)
+ 0x110b, 0x1175, 0x11c2, 0,
+#undef V9169
+#define V9169 (V + 34507)
+ 0x110c, 0x1161, 0x11a8, 0,
+#undef V9170
+#define V9170 (V + 34511)
+ 0x110c, 0x1161, 0x11a9, 0,
+#undef V9171
+#define V9171 (V + 34515)
+ 0x110c, 0x1161, 0x11aa, 0,
+#undef V9172
+#define V9172 (V + 34519)
+ 0x110c, 0x1161, 0x11ab, 0,
+#undef V9173
+#define V9173 (V + 34523)
+ 0x110c, 0x1161, 0x11ac, 0,
+#undef V9174
+#define V9174 (V + 34527)
+ 0x110c, 0x1161, 0x11ad, 0,
+#undef V9175
+#define V9175 (V + 34531)
+ 0x110c, 0x1161, 0x11ae, 0,
+#undef V9176
+#define V9176 (V + 34535)
+ 0x110c, 0x1161, 0x11af, 0,
+#undef V9177
+#define V9177 (V + 34539)
+ 0x110c, 0x1161, 0x11b0, 0,
+#undef V9178
+#define V9178 (V + 34543)
+ 0x110c, 0x1161, 0x11b1, 0,
+#undef V9179
+#define V9179 (V + 34547)
+ 0x110c, 0x1161, 0x11b2, 0,
+#undef V9180
+#define V9180 (V + 34551)
+ 0x110c, 0x1161, 0x11b3, 0,
+#undef V9181
+#define V9181 (V + 34555)
+ 0x110c, 0x1161, 0x11b4, 0,
+#undef V9182
+#define V9182 (V + 34559)
+ 0x110c, 0x1161, 0x11b5, 0,
+#undef V9183
+#define V9183 (V + 34563)
+ 0x110c, 0x1161, 0x11b6, 0,
+#undef V9184
+#define V9184 (V + 34567)
+ 0x110c, 0x1161, 0x11b7, 0,
+#undef V9185
+#define V9185 (V + 34571)
+ 0x110c, 0x1161, 0x11b8, 0,
+#undef V9186
+#define V9186 (V + 34575)
+ 0x110c, 0x1161, 0x11b9, 0,
+#undef V9187
+#define V9187 (V + 34579)
+ 0x110c, 0x1161, 0x11ba, 0,
+#undef V9188
+#define V9188 (V + 34583)
+ 0x110c, 0x1161, 0x11bb, 0,
+#undef V9189
+#define V9189 (V + 34587)
+ 0x110c, 0x1161, 0x11bc, 0,
+#undef V9190
+#define V9190 (V + 34591)
+ 0x110c, 0x1161, 0x11bd, 0,
+#undef V9191
+#define V9191 (V + 34595)
+ 0x110c, 0x1161, 0x11be, 0,
+#undef V9192
+#define V9192 (V + 34599)
+ 0x110c, 0x1161, 0x11bf, 0,
+#undef V9193
+#define V9193 (V + 34603)
+ 0x110c, 0x1161, 0x11c0, 0,
+#undef V9194
+#define V9194 (V + 34607)
+ 0x110c, 0x1161, 0x11c1, 0,
+#undef V9195
+#define V9195 (V + 34611)
+ 0x110c, 0x1161, 0x11c2, 0,
+#undef V9196
+#define V9196 (V + 34615)
+ 0x110c, 0x1162, 0,
+#undef V9197
+#define V9197 (V + 34618)
+ 0x110c, 0x1162, 0x11a8, 0,
+#undef V9198
+#define V9198 (V + 34622)
+ 0x110c, 0x1162, 0x11a9, 0,
+#undef V9199
+#define V9199 (V + 34626)
+ 0x110c, 0x1162, 0x11aa, 0,
+#undef V9200
+#define V9200 (V + 34630)
+ 0x110c, 0x1162, 0x11ab, 0,
+#undef V9201
+#define V9201 (V + 34634)
+ 0x110c, 0x1162, 0x11ac, 0,
+#undef V9202
+#define V9202 (V + 34638)
+ 0x110c, 0x1162, 0x11ad, 0,
+#undef V9203
+#define V9203 (V + 34642)
+ 0x110c, 0x1162, 0x11ae, 0,
+#undef V9204
+#define V9204 (V + 34646)
+ 0x110c, 0x1162, 0x11af, 0,
+#undef V9205
+#define V9205 (V + 34650)
+ 0x110c, 0x1162, 0x11b0, 0,
+#undef V9206
+#define V9206 (V + 34654)
+ 0x110c, 0x1162, 0x11b1, 0,
+#undef V9207
+#define V9207 (V + 34658)
+ 0x110c, 0x1162, 0x11b2, 0,
+#undef V9208
+#define V9208 (V + 34662)
+ 0x110c, 0x1162, 0x11b3, 0,
+#undef V9209
+#define V9209 (V + 34666)
+ 0x110c, 0x1162, 0x11b4, 0,
+#undef V9210
+#define V9210 (V + 34670)
+ 0x110c, 0x1162, 0x11b5, 0,
+#undef V9211
+#define V9211 (V + 34674)
+ 0x110c, 0x1162, 0x11b6, 0,
+#undef V9212
+#define V9212 (V + 34678)
+ 0x110c, 0x1162, 0x11b7, 0,
+#undef V9213
+#define V9213 (V + 34682)
+ 0x110c, 0x1162, 0x11b8, 0,
+#undef V9214
+#define V9214 (V + 34686)
+ 0x110c, 0x1162, 0x11b9, 0,
+#undef V9215
+#define V9215 (V + 34690)
+ 0x110c, 0x1162, 0x11ba, 0,
+#undef V9216
+#define V9216 (V + 34694)
+ 0x110c, 0x1162, 0x11bb, 0,
+#undef V9217
+#define V9217 (V + 34698)
+ 0x110c, 0x1162, 0x11bc, 0,
+#undef V9218
+#define V9218 (V + 34702)
+ 0x110c, 0x1162, 0x11bd, 0,
+#undef V9219
+#define V9219 (V + 34706)
+ 0x110c, 0x1162, 0x11be, 0,
+#undef V9220
+#define V9220 (V + 34710)
+ 0x110c, 0x1162, 0x11bf, 0,
+#undef V9221
+#define V9221 (V + 34714)
+ 0x110c, 0x1162, 0x11c0, 0,
+#undef V9222
+#define V9222 (V + 34718)
+ 0x110c, 0x1162, 0x11c1, 0,
+#undef V9223
+#define V9223 (V + 34722)
+ 0x110c, 0x1162, 0x11c2, 0,
+#undef V9224
+#define V9224 (V + 34726)
+ 0x110c, 0x1163, 0,
+#undef V9225
+#define V9225 (V + 34729)
+ 0x110c, 0x1163, 0x11a8, 0,
+#undef V9226
+#define V9226 (V + 34733)
+ 0x110c, 0x1163, 0x11a9, 0,
+#undef V9227
+#define V9227 (V + 34737)
+ 0x110c, 0x1163, 0x11aa, 0,
+#undef V9228
+#define V9228 (V + 34741)
+ 0x110c, 0x1163, 0x11ab, 0,
+#undef V9229
+#define V9229 (V + 34745)
+ 0x110c, 0x1163, 0x11ac, 0,
+#undef V9230
+#define V9230 (V + 34749)
+ 0x110c, 0x1163, 0x11ad, 0,
+#undef V9231
+#define V9231 (V + 34753)
+ 0x110c, 0x1163, 0x11ae, 0,
+#undef V9232
+#define V9232 (V + 34757)
+ 0x110c, 0x1163, 0x11af, 0,
+#undef V9233
+#define V9233 (V + 34761)
+ 0x110c, 0x1163, 0x11b0, 0,
+#undef V9234
+#define V9234 (V + 34765)
+ 0x110c, 0x1163, 0x11b1, 0,
+#undef V9235
+#define V9235 (V + 34769)
+ 0x110c, 0x1163, 0x11b2, 0,
+#undef V9236
+#define V9236 (V + 34773)
+ 0x110c, 0x1163, 0x11b3, 0,
+#undef V9237
+#define V9237 (V + 34777)
+ 0x110c, 0x1163, 0x11b4, 0,
+#undef V9238
+#define V9238 (V + 34781)
+ 0x110c, 0x1163, 0x11b5, 0,
+#undef V9239
+#define V9239 (V + 34785)
+ 0x110c, 0x1163, 0x11b6, 0,
+#undef V9240
+#define V9240 (V + 34789)
+ 0x110c, 0x1163, 0x11b7, 0,
+#undef V9241
+#define V9241 (V + 34793)
+ 0x110c, 0x1163, 0x11b8, 0,
+#undef V9242
+#define V9242 (V + 34797)
+ 0x110c, 0x1163, 0x11b9, 0,
+#undef V9243
+#define V9243 (V + 34801)
+ 0x110c, 0x1163, 0x11ba, 0,
+#undef V9244
+#define V9244 (V + 34805)
+ 0x110c, 0x1163, 0x11bb, 0,
+#undef V9245
+#define V9245 (V + 34809)
+ 0x110c, 0x1163, 0x11bc, 0,
+#undef V9246
+#define V9246 (V + 34813)
+ 0x110c, 0x1163, 0x11bd, 0,
+#undef V9247
+#define V9247 (V + 34817)
+ 0x110c, 0x1163, 0x11be, 0,
+#undef V9248
+#define V9248 (V + 34821)
+ 0x110c, 0x1163, 0x11bf, 0,
+#undef V9249
+#define V9249 (V + 34825)
+ 0x110c, 0x1163, 0x11c0, 0,
+#undef V9250
+#define V9250 (V + 34829)
+ 0x110c, 0x1163, 0x11c1, 0,
+#undef V9251
+#define V9251 (V + 34833)
+ 0x110c, 0x1163, 0x11c2, 0,
+#undef V9252
+#define V9252 (V + 34837)
+ 0x110c, 0x1164, 0,
+#undef V9253
+#define V9253 (V + 34840)
+ 0x110c, 0x1164, 0x11a8, 0,
+#undef V9254
+#define V9254 (V + 34844)
+ 0x110c, 0x1164, 0x11a9, 0,
+#undef V9255
+#define V9255 (V + 34848)
+ 0x110c, 0x1164, 0x11aa, 0,
+#undef V9256
+#define V9256 (V + 34852)
+ 0x110c, 0x1164, 0x11ab, 0,
+#undef V9257
+#define V9257 (V + 34856)
+ 0x110c, 0x1164, 0x11ac, 0,
+#undef V9258
+#define V9258 (V + 34860)
+ 0x110c, 0x1164, 0x11ad, 0,
+#undef V9259
+#define V9259 (V + 34864)
+ 0x110c, 0x1164, 0x11ae, 0,
+#undef V9260
+#define V9260 (V + 34868)
+ 0x110c, 0x1164, 0x11af, 0,
+#undef V9261
+#define V9261 (V + 34872)
+ 0x110c, 0x1164, 0x11b0, 0,
+#undef V9262
+#define V9262 (V + 34876)
+ 0x110c, 0x1164, 0x11b1, 0,
+#undef V9263
+#define V9263 (V + 34880)
+ 0x110c, 0x1164, 0x11b2, 0,
+#undef V9264
+#define V9264 (V + 34884)
+ 0x110c, 0x1164, 0x11b3, 0,
+#undef V9265
+#define V9265 (V + 34888)
+ 0x110c, 0x1164, 0x11b4, 0,
+#undef V9266
+#define V9266 (V + 34892)
+ 0x110c, 0x1164, 0x11b5, 0,
+#undef V9267
+#define V9267 (V + 34896)
+ 0x110c, 0x1164, 0x11b6, 0,
+#undef V9268
+#define V9268 (V + 34900)
+ 0x110c, 0x1164, 0x11b7, 0,
+#undef V9269
+#define V9269 (V + 34904)
+ 0x110c, 0x1164, 0x11b8, 0,
+#undef V9270
+#define V9270 (V + 34908)
+ 0x110c, 0x1164, 0x11b9, 0,
+#undef V9271
+#define V9271 (V + 34912)
+ 0x110c, 0x1164, 0x11ba, 0,
+#undef V9272
+#define V9272 (V + 34916)
+ 0x110c, 0x1164, 0x11bb, 0,
+#undef V9273
+#define V9273 (V + 34920)
+ 0x110c, 0x1164, 0x11bc, 0,
+#undef V9274
+#define V9274 (V + 34924)
+ 0x110c, 0x1164, 0x11bd, 0,
+#undef V9275
+#define V9275 (V + 34928)
+ 0x110c, 0x1164, 0x11be, 0,
+#undef V9276
+#define V9276 (V + 34932)
+ 0x110c, 0x1164, 0x11bf, 0,
+#undef V9277
+#define V9277 (V + 34936)
+ 0x110c, 0x1164, 0x11c0, 0,
+#undef V9278
+#define V9278 (V + 34940)
+ 0x110c, 0x1164, 0x11c1, 0,
+#undef V9279
+#define V9279 (V + 34944)
+ 0x110c, 0x1164, 0x11c2, 0,
+#undef V9280
+#define V9280 (V + 34948)
+ 0x110c, 0x1165, 0,
+#undef V9281
+#define V9281 (V + 34951)
+ 0x110c, 0x1165, 0x11a8, 0,
+#undef V9282
+#define V9282 (V + 34955)
+ 0x110c, 0x1165, 0x11a9, 0,
+#undef V9283
+#define V9283 (V + 34959)
+ 0x110c, 0x1165, 0x11aa, 0,
+#undef V9284
+#define V9284 (V + 34963)
+ 0x110c, 0x1165, 0x11ab, 0,
+#undef V9285
+#define V9285 (V + 34967)
+ 0x110c, 0x1165, 0x11ac, 0,
+#undef V9286
+#define V9286 (V + 34971)
+ 0x110c, 0x1165, 0x11ad, 0,
+#undef V9287
+#define V9287 (V + 34975)
+ 0x110c, 0x1165, 0x11ae, 0,
+#undef V9288
+#define V9288 (V + 34979)
+ 0x110c, 0x1165, 0x11af, 0,
+#undef V9289
+#define V9289 (V + 34983)
+ 0x110c, 0x1165, 0x11b0, 0,
+#undef V9290
+#define V9290 (V + 34987)
+ 0x110c, 0x1165, 0x11b1, 0,
+#undef V9291
+#define V9291 (V + 34991)
+ 0x110c, 0x1165, 0x11b2, 0,
+#undef V9292
+#define V9292 (V + 34995)
+ 0x110c, 0x1165, 0x11b3, 0,
+#undef V9293
+#define V9293 (V + 34999)
+ 0x110c, 0x1165, 0x11b4, 0,
+#undef V9294
+#define V9294 (V + 35003)
+ 0x110c, 0x1165, 0x11b5, 0,
+#undef V9295
+#define V9295 (V + 35007)
+ 0x110c, 0x1165, 0x11b6, 0,
+#undef V9296
+#define V9296 (V + 35011)
+ 0x110c, 0x1165, 0x11b7, 0,
+#undef V9297
+#define V9297 (V + 35015)
+ 0x110c, 0x1165, 0x11b8, 0,
+#undef V9298
+#define V9298 (V + 35019)
+ 0x110c, 0x1165, 0x11b9, 0,
+#undef V9299
+#define V9299 (V + 35023)
+ 0x110c, 0x1165, 0x11ba, 0,
+#undef V9300
+#define V9300 (V + 35027)
+ 0x110c, 0x1165, 0x11bb, 0,
+#undef V9301
+#define V9301 (V + 35031)
+ 0x110c, 0x1165, 0x11bc, 0,
+#undef V9302
+#define V9302 (V + 35035)
+ 0x110c, 0x1165, 0x11bd, 0,
+#undef V9303
+#define V9303 (V + 35039)
+ 0x110c, 0x1165, 0x11be, 0,
+#undef V9304
+#define V9304 (V + 35043)
+ 0x110c, 0x1165, 0x11bf, 0,
+#undef V9305
+#define V9305 (V + 35047)
+ 0x110c, 0x1165, 0x11c0, 0,
+#undef V9306
+#define V9306 (V + 35051)
+ 0x110c, 0x1165, 0x11c1, 0,
+#undef V9307
+#define V9307 (V + 35055)
+ 0x110c, 0x1165, 0x11c2, 0,
+#undef V9308
+#define V9308 (V + 35059)
+ 0x110c, 0x1166, 0,
+#undef V9309
+#define V9309 (V + 35062)
+ 0x110c, 0x1166, 0x11a8, 0,
+#undef V9310
+#define V9310 (V + 35066)
+ 0x110c, 0x1166, 0x11a9, 0,
+#undef V9311
+#define V9311 (V + 35070)
+ 0x110c, 0x1166, 0x11aa, 0,
+#undef V9312
+#define V9312 (V + 35074)
+ 0x110c, 0x1166, 0x11ab, 0,
+#undef V9313
+#define V9313 (V + 35078)
+ 0x110c, 0x1166, 0x11ac, 0,
+#undef V9314
+#define V9314 (V + 35082)
+ 0x110c, 0x1166, 0x11ad, 0,
+#undef V9315
+#define V9315 (V + 35086)
+ 0x110c, 0x1166, 0x11ae, 0,
+#undef V9316
+#define V9316 (V + 35090)
+ 0x110c, 0x1166, 0x11af, 0,
+#undef V9317
+#define V9317 (V + 35094)
+ 0x110c, 0x1166, 0x11b0, 0,
+#undef V9318
+#define V9318 (V + 35098)
+ 0x110c, 0x1166, 0x11b1, 0,
+#undef V9319
+#define V9319 (V + 35102)
+ 0x110c, 0x1166, 0x11b2, 0,
+#undef V9320
+#define V9320 (V + 35106)
+ 0x110c, 0x1166, 0x11b3, 0,
+#undef V9321
+#define V9321 (V + 35110)
+ 0x110c, 0x1166, 0x11b4, 0,
+#undef V9322
+#define V9322 (V + 35114)
+ 0x110c, 0x1166, 0x11b5, 0,
+#undef V9323
+#define V9323 (V + 35118)
+ 0x110c, 0x1166, 0x11b6, 0,
+#undef V9324
+#define V9324 (V + 35122)
+ 0x110c, 0x1166, 0x11b7, 0,
+#undef V9325
+#define V9325 (V + 35126)
+ 0x110c, 0x1166, 0x11b8, 0,
+#undef V9326
+#define V9326 (V + 35130)
+ 0x110c, 0x1166, 0x11b9, 0,
+#undef V9327
+#define V9327 (V + 35134)
+ 0x110c, 0x1166, 0x11ba, 0,
+#undef V9328
+#define V9328 (V + 35138)
+ 0x110c, 0x1166, 0x11bb, 0,
+#undef V9329
+#define V9329 (V + 35142)
+ 0x110c, 0x1166, 0x11bc, 0,
+#undef V9330
+#define V9330 (V + 35146)
+ 0x110c, 0x1166, 0x11bd, 0,
+#undef V9331
+#define V9331 (V + 35150)
+ 0x110c, 0x1166, 0x11be, 0,
+#undef V9332
+#define V9332 (V + 35154)
+ 0x110c, 0x1166, 0x11bf, 0,
+#undef V9333
+#define V9333 (V + 35158)
+ 0x110c, 0x1166, 0x11c0, 0,
+#undef V9334
+#define V9334 (V + 35162)
+ 0x110c, 0x1166, 0x11c1, 0,
+#undef V9335
+#define V9335 (V + 35166)
+ 0x110c, 0x1166, 0x11c2, 0,
+#undef V9336
+#define V9336 (V + 35170)
+ 0x110c, 0x1167, 0,
+#undef V9337
+#define V9337 (V + 35173)
+ 0x110c, 0x1167, 0x11a8, 0,
+#undef V9338
+#define V9338 (V + 35177)
+ 0x110c, 0x1167, 0x11a9, 0,
+#undef V9339
+#define V9339 (V + 35181)
+ 0x110c, 0x1167, 0x11aa, 0,
+#undef V9340
+#define V9340 (V + 35185)
+ 0x110c, 0x1167, 0x11ab, 0,
+#undef V9341
+#define V9341 (V + 35189)
+ 0x110c, 0x1167, 0x11ac, 0,
+#undef V9342
+#define V9342 (V + 35193)
+ 0x110c, 0x1167, 0x11ad, 0,
+#undef V9343
+#define V9343 (V + 35197)
+ 0x110c, 0x1167, 0x11ae, 0,
+#undef V9344
+#define V9344 (V + 35201)
+ 0x110c, 0x1167, 0x11af, 0,
+#undef V9345
+#define V9345 (V + 35205)
+ 0x110c, 0x1167, 0x11b0, 0,
+#undef V9346
+#define V9346 (V + 35209)
+ 0x110c, 0x1167, 0x11b1, 0,
+#undef V9347
+#define V9347 (V + 35213)
+ 0x110c, 0x1167, 0x11b2, 0,
+#undef V9348
+#define V9348 (V + 35217)
+ 0x110c, 0x1167, 0x11b3, 0,
+#undef V9349
+#define V9349 (V + 35221)
+ 0x110c, 0x1167, 0x11b4, 0,
+#undef V9350
+#define V9350 (V + 35225)
+ 0x110c, 0x1167, 0x11b5, 0,
+#undef V9351
+#define V9351 (V + 35229)
+ 0x110c, 0x1167, 0x11b6, 0,
+#undef V9352
+#define V9352 (V + 35233)
+ 0x110c, 0x1167, 0x11b7, 0,
+#undef V9353
+#define V9353 (V + 35237)
+ 0x110c, 0x1167, 0x11b8, 0,
+#undef V9354
+#define V9354 (V + 35241)
+ 0x110c, 0x1167, 0x11b9, 0,
+#undef V9355
+#define V9355 (V + 35245)
+ 0x110c, 0x1167, 0x11ba, 0,
+#undef V9356
+#define V9356 (V + 35249)
+ 0x110c, 0x1167, 0x11bb, 0,
+#undef V9357
+#define V9357 (V + 35253)
+ 0x110c, 0x1167, 0x11bc, 0,
+#undef V9358
+#define V9358 (V + 35257)
+ 0x110c, 0x1167, 0x11bd, 0,
+#undef V9359
+#define V9359 (V + 35261)
+ 0x110c, 0x1167, 0x11be, 0,
+#undef V9360
+#define V9360 (V + 35265)
+ 0x110c, 0x1167, 0x11bf, 0,
+#undef V9361
+#define V9361 (V + 35269)
+ 0x110c, 0x1167, 0x11c0, 0,
+#undef V9362
+#define V9362 (V + 35273)
+ 0x110c, 0x1167, 0x11c1, 0,
+#undef V9363
+#define V9363 (V + 35277)
+ 0x110c, 0x1167, 0x11c2, 0,
+#undef V9364
+#define V9364 (V + 35281)
+ 0x110c, 0x1168, 0,
+#undef V9365
+#define V9365 (V + 35284)
+ 0x110c, 0x1168, 0x11a8, 0,
+#undef V9366
+#define V9366 (V + 35288)
+ 0x110c, 0x1168, 0x11a9, 0,
+#undef V9367
+#define V9367 (V + 35292)
+ 0x110c, 0x1168, 0x11aa, 0,
+#undef V9368
+#define V9368 (V + 35296)
+ 0x110c, 0x1168, 0x11ab, 0,
+#undef V9369
+#define V9369 (V + 35300)
+ 0x110c, 0x1168, 0x11ac, 0,
+#undef V9370
+#define V9370 (V + 35304)
+ 0x110c, 0x1168, 0x11ad, 0,
+#undef V9371
+#define V9371 (V + 35308)
+ 0x110c, 0x1168, 0x11ae, 0,
+#undef V9372
+#define V9372 (V + 35312)
+ 0x110c, 0x1168, 0x11af, 0,
+#undef V9373
+#define V9373 (V + 35316)
+ 0x110c, 0x1168, 0x11b0, 0,
+#undef V9374
+#define V9374 (V + 35320)
+ 0x110c, 0x1168, 0x11b1, 0,
+#undef V9375
+#define V9375 (V + 35324)
+ 0x110c, 0x1168, 0x11b2, 0,
+#undef V9376
+#define V9376 (V + 35328)
+ 0x110c, 0x1168, 0x11b3, 0,
+#undef V9377
+#define V9377 (V + 35332)
+ 0x110c, 0x1168, 0x11b4, 0,
+#undef V9378
+#define V9378 (V + 35336)
+ 0x110c, 0x1168, 0x11b5, 0,
+#undef V9379
+#define V9379 (V + 35340)
+ 0x110c, 0x1168, 0x11b6, 0,
+#undef V9380
+#define V9380 (V + 35344)
+ 0x110c, 0x1168, 0x11b7, 0,
+#undef V9381
+#define V9381 (V + 35348)
+ 0x110c, 0x1168, 0x11b8, 0,
+#undef V9382
+#define V9382 (V + 35352)
+ 0x110c, 0x1168, 0x11b9, 0,
+#undef V9383
+#define V9383 (V + 35356)
+ 0x110c, 0x1168, 0x11ba, 0,
+#undef V9384
+#define V9384 (V + 35360)
+ 0x110c, 0x1168, 0x11bb, 0,
+#undef V9385
+#define V9385 (V + 35364)
+ 0x110c, 0x1168, 0x11bc, 0,
+#undef V9386
+#define V9386 (V + 35368)
+ 0x110c, 0x1168, 0x11bd, 0,
+#undef V9387
+#define V9387 (V + 35372)
+ 0x110c, 0x1168, 0x11be, 0,
+#undef V9388
+#define V9388 (V + 35376)
+ 0x110c, 0x1168, 0x11bf, 0,
+#undef V9389
+#define V9389 (V + 35380)
+ 0x110c, 0x1168, 0x11c0, 0,
+#undef V9390
+#define V9390 (V + 35384)
+ 0x110c, 0x1168, 0x11c1, 0,
+#undef V9391
+#define V9391 (V + 35388)
+ 0x110c, 0x1168, 0x11c2, 0,
+#undef V9392
+#define V9392 (V + 35392)
+ 0x110c, 0x1169, 0,
+#undef V9393
+#define V9393 (V + 35395)
+ 0x110c, 0x1169, 0x11a8, 0,
+#undef V9394
+#define V9394 (V + 35399)
+ 0x110c, 0x1169, 0x11a9, 0,
+#undef V9395
+#define V9395 (V + 35403)
+ 0x110c, 0x1169, 0x11aa, 0,
+#undef V9396
+#define V9396 (V + 35407)
+ 0x110c, 0x1169, 0x11ab, 0,
+#undef V9397
+#define V9397 (V + 35411)
+ 0x110c, 0x1169, 0x11ac, 0,
+#undef V9398
+#define V9398 (V + 35415)
+ 0x110c, 0x1169, 0x11ad, 0,
+#undef V9399
+#define V9399 (V + 35419)
+ 0x110c, 0x1169, 0x11ae, 0,
+#undef V9400
+#define V9400 (V + 35423)
+ 0x110c, 0x1169, 0x11af, 0,
+#undef V9401
+#define V9401 (V + 35427)
+ 0x110c, 0x1169, 0x11b0, 0,
+#undef V9402
+#define V9402 (V + 35431)
+ 0x110c, 0x1169, 0x11b1, 0,
+#undef V9403
+#define V9403 (V + 35435)
+ 0x110c, 0x1169, 0x11b2, 0,
+#undef V9404
+#define V9404 (V + 35439)
+ 0x110c, 0x1169, 0x11b3, 0,
+#undef V9405
+#define V9405 (V + 35443)
+ 0x110c, 0x1169, 0x11b4, 0,
+#undef V9406
+#define V9406 (V + 35447)
+ 0x110c, 0x1169, 0x11b5, 0,
+#undef V9407
+#define V9407 (V + 35451)
+ 0x110c, 0x1169, 0x11b6, 0,
+#undef V9408
+#define V9408 (V + 35455)
+ 0x110c, 0x1169, 0x11b7, 0,
+#undef V9409
+#define V9409 (V + 35459)
+ 0x110c, 0x1169, 0x11b8, 0,
+#undef V9410
+#define V9410 (V + 35463)
+ 0x110c, 0x1169, 0x11b9, 0,
+#undef V9411
+#define V9411 (V + 35467)
+ 0x110c, 0x1169, 0x11ba, 0,
+#undef V9412
+#define V9412 (V + 35471)
+ 0x110c, 0x1169, 0x11bb, 0,
+#undef V9413
+#define V9413 (V + 35475)
+ 0x110c, 0x1169, 0x11bc, 0,
+#undef V9414
+#define V9414 (V + 35479)
+ 0x110c, 0x1169, 0x11bd, 0,
+#undef V9415
+#define V9415 (V + 35483)
+ 0x110c, 0x1169, 0x11be, 0,
+#undef V9416
+#define V9416 (V + 35487)
+ 0x110c, 0x1169, 0x11bf, 0,
+#undef V9417
+#define V9417 (V + 35491)
+ 0x110c, 0x1169, 0x11c0, 0,
+#undef V9418
+#define V9418 (V + 35495)
+ 0x110c, 0x1169, 0x11c1, 0,
+#undef V9419
+#define V9419 (V + 35499)
+ 0x110c, 0x1169, 0x11c2, 0,
+#undef V9420
+#define V9420 (V + 35503)
+ 0x110c, 0x116a, 0,
+#undef V9421
+#define V9421 (V + 35506)
+ 0x110c, 0x116a, 0x11a8, 0,
+#undef V9422
+#define V9422 (V + 35510)
+ 0x110c, 0x116a, 0x11a9, 0,
+#undef V9423
+#define V9423 (V + 35514)
+ 0x110c, 0x116a, 0x11aa, 0,
+#undef V9424
+#define V9424 (V + 35518)
+ 0x110c, 0x116a, 0x11ab, 0,
+#undef V9425
+#define V9425 (V + 35522)
+ 0x110c, 0x116a, 0x11ac, 0,
+#undef V9426
+#define V9426 (V + 35526)
+ 0x110c, 0x116a, 0x11ad, 0,
+#undef V9427
+#define V9427 (V + 35530)
+ 0x110c, 0x116a, 0x11ae, 0,
+#undef V9428
+#define V9428 (V + 35534)
+ 0x110c, 0x116a, 0x11af, 0,
+#undef V9429
+#define V9429 (V + 35538)
+ 0x110c, 0x116a, 0x11b0, 0,
+#undef V9430
+#define V9430 (V + 35542)
+ 0x110c, 0x116a, 0x11b1, 0,
+#undef V9431
+#define V9431 (V + 35546)
+ 0x110c, 0x116a, 0x11b2, 0,
+#undef V9432
+#define V9432 (V + 35550)
+ 0x110c, 0x116a, 0x11b3, 0,
+#undef V9433
+#define V9433 (V + 35554)
+ 0x110c, 0x116a, 0x11b4, 0,
+#undef V9434
+#define V9434 (V + 35558)
+ 0x110c, 0x116a, 0x11b5, 0,
+#undef V9435
+#define V9435 (V + 35562)
+ 0x110c, 0x116a, 0x11b6, 0,
+#undef V9436
+#define V9436 (V + 35566)
+ 0x110c, 0x116a, 0x11b7, 0,
+#undef V9437
+#define V9437 (V + 35570)
+ 0x110c, 0x116a, 0x11b8, 0,
+#undef V9438
+#define V9438 (V + 35574)
+ 0x110c, 0x116a, 0x11b9, 0,
+#undef V9439
+#define V9439 (V + 35578)
+ 0x110c, 0x116a, 0x11ba, 0,
+#undef V9440
+#define V9440 (V + 35582)
+ 0x110c, 0x116a, 0x11bb, 0,
+#undef V9441
+#define V9441 (V + 35586)
+ 0x110c, 0x116a, 0x11bc, 0,
+#undef V9442
+#define V9442 (V + 35590)
+ 0x110c, 0x116a, 0x11bd, 0,
+#undef V9443
+#define V9443 (V + 35594)
+ 0x110c, 0x116a, 0x11be, 0,
+#undef V9444
+#define V9444 (V + 35598)
+ 0x110c, 0x116a, 0x11bf, 0,
+#undef V9445
+#define V9445 (V + 35602)
+ 0x110c, 0x116a, 0x11c0, 0,
+#undef V9446
+#define V9446 (V + 35606)
+ 0x110c, 0x116a, 0x11c1, 0,
+#undef V9447
+#define V9447 (V + 35610)
+ 0x110c, 0x116a, 0x11c2, 0,
+#undef V9448
+#define V9448 (V + 35614)
+ 0x110c, 0x116b, 0,
+#undef V9449
+#define V9449 (V + 35617)
+ 0x110c, 0x116b, 0x11a8, 0,
+#undef V9450
+#define V9450 (V + 35621)
+ 0x110c, 0x116b, 0x11a9, 0,
+#undef V9451
+#define V9451 (V + 35625)
+ 0x110c, 0x116b, 0x11aa, 0,
+#undef V9452
+#define V9452 (V + 35629)
+ 0x110c, 0x116b, 0x11ab, 0,
+#undef V9453
+#define V9453 (V + 35633)
+ 0x110c, 0x116b, 0x11ac, 0,
+#undef V9454
+#define V9454 (V + 35637)
+ 0x110c, 0x116b, 0x11ad, 0,
+#undef V9455
+#define V9455 (V + 35641)
+ 0x110c, 0x116b, 0x11ae, 0,
+#undef V9456
+#define V9456 (V + 35645)
+ 0x110c, 0x116b, 0x11af, 0,
+#undef V9457
+#define V9457 (V + 35649)
+ 0x110c, 0x116b, 0x11b0, 0,
+#undef V9458
+#define V9458 (V + 35653)
+ 0x110c, 0x116b, 0x11b1, 0,
+#undef V9459
+#define V9459 (V + 35657)
+ 0x110c, 0x116b, 0x11b2, 0,
+#undef V9460
+#define V9460 (V + 35661)
+ 0x110c, 0x116b, 0x11b3, 0,
+#undef V9461
+#define V9461 (V + 35665)
+ 0x110c, 0x116b, 0x11b4, 0,
+#undef V9462
+#define V9462 (V + 35669)
+ 0x110c, 0x116b, 0x11b5, 0,
+#undef V9463
+#define V9463 (V + 35673)
+ 0x110c, 0x116b, 0x11b6, 0,
+#undef V9464
+#define V9464 (V + 35677)
+ 0x110c, 0x116b, 0x11b7, 0,
+#undef V9465
+#define V9465 (V + 35681)
+ 0x110c, 0x116b, 0x11b8, 0,
+#undef V9466
+#define V9466 (V + 35685)
+ 0x110c, 0x116b, 0x11b9, 0,
+#undef V9467
+#define V9467 (V + 35689)
+ 0x110c, 0x116b, 0x11ba, 0,
+#undef V9468
+#define V9468 (V + 35693)
+ 0x110c, 0x116b, 0x11bb, 0,
+#undef V9469
+#define V9469 (V + 35697)
+ 0x110c, 0x116b, 0x11bc, 0,
+#undef V9470
+#define V9470 (V + 35701)
+ 0x110c, 0x116b, 0x11bd, 0,
+#undef V9471
+#define V9471 (V + 35705)
+ 0x110c, 0x116b, 0x11be, 0,
+#undef V9472
+#define V9472 (V + 35709)
+ 0x110c, 0x116b, 0x11bf, 0,
+#undef V9473
+#define V9473 (V + 35713)
+ 0x110c, 0x116b, 0x11c0, 0,
+#undef V9474
+#define V9474 (V + 35717)
+ 0x110c, 0x116b, 0x11c1, 0,
+#undef V9475
+#define V9475 (V + 35721)
+ 0x110c, 0x116b, 0x11c2, 0,
+#undef V9476
+#define V9476 (V + 35725)
+ 0x110c, 0x116c, 0,
+#undef V9477
+#define V9477 (V + 35728)
+ 0x110c, 0x116c, 0x11a8, 0,
+#undef V9478
+#define V9478 (V + 35732)
+ 0x110c, 0x116c, 0x11a9, 0,
+#undef V9479
+#define V9479 (V + 35736)
+ 0x110c, 0x116c, 0x11aa, 0,
+#undef V9480
+#define V9480 (V + 35740)
+ 0x110c, 0x116c, 0x11ab, 0,
+#undef V9481
+#define V9481 (V + 35744)
+ 0x110c, 0x116c, 0x11ac, 0,
+#undef V9482
+#define V9482 (V + 35748)
+ 0x110c, 0x116c, 0x11ad, 0,
+#undef V9483
+#define V9483 (V + 35752)
+ 0x110c, 0x116c, 0x11ae, 0,
+#undef V9484
+#define V9484 (V + 35756)
+ 0x110c, 0x116c, 0x11af, 0,
+#undef V9485
+#define V9485 (V + 35760)
+ 0x110c, 0x116c, 0x11b0, 0,
+#undef V9486
+#define V9486 (V + 35764)
+ 0x110c, 0x116c, 0x11b1, 0,
+#undef V9487
+#define V9487 (V + 35768)
+ 0x110c, 0x116c, 0x11b2, 0,
+#undef V9488
+#define V9488 (V + 35772)
+ 0x110c, 0x116c, 0x11b3, 0,
+#undef V9489
+#define V9489 (V + 35776)
+ 0x110c, 0x116c, 0x11b4, 0,
+#undef V9490
+#define V9490 (V + 35780)
+ 0x110c, 0x116c, 0x11b5, 0,
+#undef V9491
+#define V9491 (V + 35784)
+ 0x110c, 0x116c, 0x11b6, 0,
+#undef V9492
+#define V9492 (V + 35788)
+ 0x110c, 0x116c, 0x11b7, 0,
+#undef V9493
+#define V9493 (V + 35792)
+ 0x110c, 0x116c, 0x11b8, 0,
+#undef V9494
+#define V9494 (V + 35796)
+ 0x110c, 0x116c, 0x11b9, 0,
+#undef V9495
+#define V9495 (V + 35800)
+ 0x110c, 0x116c, 0x11ba, 0,
+#undef V9496
+#define V9496 (V + 35804)
+ 0x110c, 0x116c, 0x11bb, 0,
+#undef V9497
+#define V9497 (V + 35808)
+ 0x110c, 0x116c, 0x11bc, 0,
+#undef V9498
+#define V9498 (V + 35812)
+ 0x110c, 0x116c, 0x11bd, 0,
+#undef V9499
+#define V9499 (V + 35816)
+ 0x110c, 0x116c, 0x11be, 0,
+#undef V9500
+#define V9500 (V + 35820)
+ 0x110c, 0x116c, 0x11bf, 0,
+#undef V9501
+#define V9501 (V + 35824)
+ 0x110c, 0x116c, 0x11c0, 0,
+#undef V9502
+#define V9502 (V + 35828)
+ 0x110c, 0x116c, 0x11c1, 0,
+#undef V9503
+#define V9503 (V + 35832)
+ 0x110c, 0x116c, 0x11c2, 0,
+#undef V9504
+#define V9504 (V + 35836)
+ 0x110c, 0x116d, 0,
+#undef V9505
+#define V9505 (V + 35839)
+ 0x110c, 0x116d, 0x11a8, 0,
+#undef V9506
+#define V9506 (V + 35843)
+ 0x110c, 0x116d, 0x11a9, 0,
+#undef V9507
+#define V9507 (V + 35847)
+ 0x110c, 0x116d, 0x11aa, 0,
+#undef V9508
+#define V9508 (V + 35851)
+ 0x110c, 0x116d, 0x11ab, 0,
+#undef V9509
+#define V9509 (V + 35855)
+ 0x110c, 0x116d, 0x11ac, 0,
+#undef V9510
+#define V9510 (V + 35859)
+ 0x110c, 0x116d, 0x11ad, 0,
+#undef V9511
+#define V9511 (V + 35863)
+ 0x110c, 0x116d, 0x11ae, 0,
+#undef V9512
+#define V9512 (V + 35867)
+ 0x110c, 0x116d, 0x11af, 0,
+#undef V9513
+#define V9513 (V + 35871)
+ 0x110c, 0x116d, 0x11b0, 0,
+#undef V9514
+#define V9514 (V + 35875)
+ 0x110c, 0x116d, 0x11b1, 0,
+#undef V9515
+#define V9515 (V + 35879)
+ 0x110c, 0x116d, 0x11b2, 0,
+#undef V9516
+#define V9516 (V + 35883)
+ 0x110c, 0x116d, 0x11b3, 0,
+#undef V9517
+#define V9517 (V + 35887)
+ 0x110c, 0x116d, 0x11b4, 0,
+#undef V9518
+#define V9518 (V + 35891)
+ 0x110c, 0x116d, 0x11b5, 0,
+#undef V9519
+#define V9519 (V + 35895)
+ 0x110c, 0x116d, 0x11b6, 0,
+#undef V9520
+#define V9520 (V + 35899)
+ 0x110c, 0x116d, 0x11b7, 0,
+#undef V9521
+#define V9521 (V + 35903)
+ 0x110c, 0x116d, 0x11b8, 0,
+#undef V9522
+#define V9522 (V + 35907)
+ 0x110c, 0x116d, 0x11b9, 0,
+#undef V9523
+#define V9523 (V + 35911)
+ 0x110c, 0x116d, 0x11ba, 0,
+#undef V9524
+#define V9524 (V + 35915)
+ 0x110c, 0x116d, 0x11bb, 0,
+#undef V9525
+#define V9525 (V + 35919)
+ 0x110c, 0x116d, 0x11bc, 0,
+#undef V9526
+#define V9526 (V + 35923)
+ 0x110c, 0x116d, 0x11bd, 0,
+#undef V9527
+#define V9527 (V + 35927)
+ 0x110c, 0x116d, 0x11be, 0,
+#undef V9528
+#define V9528 (V + 35931)
+ 0x110c, 0x116d, 0x11bf, 0,
+#undef V9529
+#define V9529 (V + 35935)
+ 0x110c, 0x116d, 0x11c0, 0,
+#undef V9530
+#define V9530 (V + 35939)
+ 0x110c, 0x116d, 0x11c1, 0,
+#undef V9531
+#define V9531 (V + 35943)
+ 0x110c, 0x116d, 0x11c2, 0,
+#undef V9532
+#define V9532 (V + 35947)
+ 0x110c, 0x116e, 0,
+#undef V9533
+#define V9533 (V + 35950)
+ 0x110c, 0x116e, 0x11a8, 0,
+#undef V9534
+#define V9534 (V + 35954)
+ 0x110c, 0x116e, 0x11a9, 0,
+#undef V9535
+#define V9535 (V + 35958)
+ 0x110c, 0x116e, 0x11aa, 0,
+#undef V9536
+#define V9536 (V + 35962)
+ 0x110c, 0x116e, 0x11ab, 0,
+#undef V9537
+#define V9537 (V + 35966)
+ 0x110c, 0x116e, 0x11ac, 0,
+#undef V9538
+#define V9538 (V + 35970)
+ 0x110c, 0x116e, 0x11ad, 0,
+#undef V9539
+#define V9539 (V + 35974)
+ 0x110c, 0x116e, 0x11ae, 0,
+#undef V9540
+#define V9540 (V + 35978)
+ 0x110c, 0x116e, 0x11af, 0,
+#undef V9541
+#define V9541 (V + 35982)
+ 0x110c, 0x116e, 0x11b0, 0,
+#undef V9542
+#define V9542 (V + 35986)
+ 0x110c, 0x116e, 0x11b1, 0,
+#undef V9543
+#define V9543 (V + 35990)
+ 0x110c, 0x116e, 0x11b2, 0,
+#undef V9544
+#define V9544 (V + 35994)
+ 0x110c, 0x116e, 0x11b3, 0,
+#undef V9545
+#define V9545 (V + 35998)
+ 0x110c, 0x116e, 0x11b4, 0,
+#undef V9546
+#define V9546 (V + 36002)
+ 0x110c, 0x116e, 0x11b5, 0,
+#undef V9547
+#define V9547 (V + 36006)
+ 0x110c, 0x116e, 0x11b6, 0,
+#undef V9548
+#define V9548 (V + 36010)
+ 0x110c, 0x116e, 0x11b7, 0,
+#undef V9549
+#define V9549 (V + 36014)
+ 0x110c, 0x116e, 0x11b8, 0,
+#undef V9550
+#define V9550 (V + 36018)
+ 0x110c, 0x116e, 0x11b9, 0,
+#undef V9551
+#define V9551 (V + 36022)
+ 0x110c, 0x116e, 0x11ba, 0,
+#undef V9552
+#define V9552 (V + 36026)
+ 0x110c, 0x116e, 0x11bb, 0,
+#undef V9553
+#define V9553 (V + 36030)
+ 0x110c, 0x116e, 0x11bc, 0,
+#undef V9554
+#define V9554 (V + 36034)
+ 0x110c, 0x116e, 0x11bd, 0,
+#undef V9555
+#define V9555 (V + 36038)
+ 0x110c, 0x116e, 0x11be, 0,
+#undef V9556
+#define V9556 (V + 36042)
+ 0x110c, 0x116e, 0x11bf, 0,
+#undef V9557
+#define V9557 (V + 36046)
+ 0x110c, 0x116e, 0x11c0, 0,
+#undef V9558
+#define V9558 (V + 36050)
+ 0x110c, 0x116e, 0x11c1, 0,
+#undef V9559
+#define V9559 (V + 36054)
+ 0x110c, 0x116e, 0x11c2, 0,
+#undef V9560
+#define V9560 (V + 36058)
+ 0x110c, 0x116f, 0,
+#undef V9561
+#define V9561 (V + 36061)
+ 0x110c, 0x116f, 0x11a8, 0,
+#undef V9562
+#define V9562 (V + 36065)
+ 0x110c, 0x116f, 0x11a9, 0,
+#undef V9563
+#define V9563 (V + 36069)
+ 0x110c, 0x116f, 0x11aa, 0,
+#undef V9564
+#define V9564 (V + 36073)
+ 0x110c, 0x116f, 0x11ab, 0,
+#undef V9565
+#define V9565 (V + 36077)
+ 0x110c, 0x116f, 0x11ac, 0,
+#undef V9566
+#define V9566 (V + 36081)
+ 0x110c, 0x116f, 0x11ad, 0,
+#undef V9567
+#define V9567 (V + 36085)
+ 0x110c, 0x116f, 0x11ae, 0,
+#undef V9568
+#define V9568 (V + 36089)
+ 0x110c, 0x116f, 0x11af, 0,
+#undef V9569
+#define V9569 (V + 36093)
+ 0x110c, 0x116f, 0x11b0, 0,
+#undef V9570
+#define V9570 (V + 36097)
+ 0x110c, 0x116f, 0x11b1, 0,
+#undef V9571
+#define V9571 (V + 36101)
+ 0x110c, 0x116f, 0x11b2, 0,
+#undef V9572
+#define V9572 (V + 36105)
+ 0x110c, 0x116f, 0x11b3, 0,
+#undef V9573
+#define V9573 (V + 36109)
+ 0x110c, 0x116f, 0x11b4, 0,
+#undef V9574
+#define V9574 (V + 36113)
+ 0x110c, 0x116f, 0x11b5, 0,
+#undef V9575
+#define V9575 (V + 36117)
+ 0x110c, 0x116f, 0x11b6, 0,
+#undef V9576
+#define V9576 (V + 36121)
+ 0x110c, 0x116f, 0x11b7, 0,
+#undef V9577
+#define V9577 (V + 36125)
+ 0x110c, 0x116f, 0x11b8, 0,
+#undef V9578
+#define V9578 (V + 36129)
+ 0x110c, 0x116f, 0x11b9, 0,
+#undef V9579
+#define V9579 (V + 36133)
+ 0x110c, 0x116f, 0x11ba, 0,
+#undef V9580
+#define V9580 (V + 36137)
+ 0x110c, 0x116f, 0x11bb, 0,
+#undef V9581
+#define V9581 (V + 36141)
+ 0x110c, 0x116f, 0x11bc, 0,
+#undef V9582
+#define V9582 (V + 36145)
+ 0x110c, 0x116f, 0x11bd, 0,
+#undef V9583
+#define V9583 (V + 36149)
+ 0x110c, 0x116f, 0x11be, 0,
+#undef V9584
+#define V9584 (V + 36153)
+ 0x110c, 0x116f, 0x11bf, 0,
+#undef V9585
+#define V9585 (V + 36157)
+ 0x110c, 0x116f, 0x11c0, 0,
+#undef V9586
+#define V9586 (V + 36161)
+ 0x110c, 0x116f, 0x11c1, 0,
+#undef V9587
+#define V9587 (V + 36165)
+ 0x110c, 0x116f, 0x11c2, 0,
+#undef V9588
+#define V9588 (V + 36169)
+ 0x110c, 0x1170, 0,
+#undef V9589
+#define V9589 (V + 36172)
+ 0x110c, 0x1170, 0x11a8, 0,
+#undef V9590
+#define V9590 (V + 36176)
+ 0x110c, 0x1170, 0x11a9, 0,
+#undef V9591
+#define V9591 (V + 36180)
+ 0x110c, 0x1170, 0x11aa, 0,
+#undef V9592
+#define V9592 (V + 36184)
+ 0x110c, 0x1170, 0x11ab, 0,
+#undef V9593
+#define V9593 (V + 36188)
+ 0x110c, 0x1170, 0x11ac, 0,
+#undef V9594
+#define V9594 (V + 36192)
+ 0x110c, 0x1170, 0x11ad, 0,
+#undef V9595
+#define V9595 (V + 36196)
+ 0x110c, 0x1170, 0x11ae, 0,
+#undef V9596
+#define V9596 (V + 36200)
+ 0x110c, 0x1170, 0x11af, 0,
+#undef V9597
+#define V9597 (V + 36204)
+ 0x110c, 0x1170, 0x11b0, 0,
+#undef V9598
+#define V9598 (V + 36208)
+ 0x110c, 0x1170, 0x11b1, 0,
+#undef V9599
+#define V9599 (V + 36212)
+ 0x110c, 0x1170, 0x11b2, 0,
+#undef V9600
+#define V9600 (V + 36216)
+ 0x110c, 0x1170, 0x11b3, 0,
+#undef V9601
+#define V9601 (V + 36220)
+ 0x110c, 0x1170, 0x11b4, 0,
+#undef V9602
+#define V9602 (V + 36224)
+ 0x110c, 0x1170, 0x11b5, 0,
+#undef V9603
+#define V9603 (V + 36228)
+ 0x110c, 0x1170, 0x11b6, 0,
+#undef V9604
+#define V9604 (V + 36232)
+ 0x110c, 0x1170, 0x11b7, 0,
+#undef V9605
+#define V9605 (V + 36236)
+ 0x110c, 0x1170, 0x11b8, 0,
+#undef V9606
+#define V9606 (V + 36240)
+ 0x110c, 0x1170, 0x11b9, 0,
+#undef V9607
+#define V9607 (V + 36244)
+ 0x110c, 0x1170, 0x11ba, 0,
+#undef V9608
+#define V9608 (V + 36248)
+ 0x110c, 0x1170, 0x11bb, 0,
+#undef V9609
+#define V9609 (V + 36252)
+ 0x110c, 0x1170, 0x11bc, 0,
+#undef V9610
+#define V9610 (V + 36256)
+ 0x110c, 0x1170, 0x11bd, 0,
+#undef V9611
+#define V9611 (V + 36260)
+ 0x110c, 0x1170, 0x11be, 0,
+#undef V9612
+#define V9612 (V + 36264)
+ 0x110c, 0x1170, 0x11bf, 0,
+#undef V9613
+#define V9613 (V + 36268)
+ 0x110c, 0x1170, 0x11c0, 0,
+#undef V9614
+#define V9614 (V + 36272)
+ 0x110c, 0x1170, 0x11c1, 0,
+#undef V9615
+#define V9615 (V + 36276)
+ 0x110c, 0x1170, 0x11c2, 0,
+#undef V9616
+#define V9616 (V + 36280)
+ 0x110c, 0x1171, 0,
+#undef V9617
+#define V9617 (V + 36283)
+ 0x110c, 0x1171, 0x11a8, 0,
+#undef V9618
+#define V9618 (V + 36287)
+ 0x110c, 0x1171, 0x11a9, 0,
+#undef V9619
+#define V9619 (V + 36291)
+ 0x110c, 0x1171, 0x11aa, 0,
+#undef V9620
+#define V9620 (V + 36295)
+ 0x110c, 0x1171, 0x11ab, 0,
+#undef V9621
+#define V9621 (V + 36299)
+ 0x110c, 0x1171, 0x11ac, 0,
+#undef V9622
+#define V9622 (V + 36303)
+ 0x110c, 0x1171, 0x11ad, 0,
+#undef V9623
+#define V9623 (V + 36307)
+ 0x110c, 0x1171, 0x11ae, 0,
+#undef V9624
+#define V9624 (V + 36311)
+ 0x110c, 0x1171, 0x11af, 0,
+#undef V9625
+#define V9625 (V + 36315)
+ 0x110c, 0x1171, 0x11b0, 0,
+#undef V9626
+#define V9626 (V + 36319)
+ 0x110c, 0x1171, 0x11b1, 0,
+#undef V9627
+#define V9627 (V + 36323)
+ 0x110c, 0x1171, 0x11b2, 0,
+#undef V9628
+#define V9628 (V + 36327)
+ 0x110c, 0x1171, 0x11b3, 0,
+#undef V9629
+#define V9629 (V + 36331)
+ 0x110c, 0x1171, 0x11b4, 0,
+#undef V9630
+#define V9630 (V + 36335)
+ 0x110c, 0x1171, 0x11b5, 0,
+#undef V9631
+#define V9631 (V + 36339)
+ 0x110c, 0x1171, 0x11b6, 0,
+#undef V9632
+#define V9632 (V + 36343)
+ 0x110c, 0x1171, 0x11b7, 0,
+#undef V9633
+#define V9633 (V + 36347)
+ 0x110c, 0x1171, 0x11b8, 0,
+#undef V9634
+#define V9634 (V + 36351)
+ 0x110c, 0x1171, 0x11b9, 0,
+#undef V9635
+#define V9635 (V + 36355)
+ 0x110c, 0x1171, 0x11ba, 0,
+#undef V9636
+#define V9636 (V + 36359)
+ 0x110c, 0x1171, 0x11bb, 0,
+#undef V9637
+#define V9637 (V + 36363)
+ 0x110c, 0x1171, 0x11bc, 0,
+#undef V9638
+#define V9638 (V + 36367)
+ 0x110c, 0x1171, 0x11bd, 0,
+#undef V9639
+#define V9639 (V + 36371)
+ 0x110c, 0x1171, 0x11be, 0,
+#undef V9640
+#define V9640 (V + 36375)
+ 0x110c, 0x1171, 0x11bf, 0,
+#undef V9641
+#define V9641 (V + 36379)
+ 0x110c, 0x1171, 0x11c0, 0,
+#undef V9642
+#define V9642 (V + 36383)
+ 0x110c, 0x1171, 0x11c1, 0,
+#undef V9643
+#define V9643 (V + 36387)
+ 0x110c, 0x1171, 0x11c2, 0,
+#undef V9644
+#define V9644 (V + 36391)
+ 0x110c, 0x1172, 0,
+#undef V9645
+#define V9645 (V + 36394)
+ 0x110c, 0x1172, 0x11a8, 0,
+#undef V9646
+#define V9646 (V + 36398)
+ 0x110c, 0x1172, 0x11a9, 0,
+#undef V9647
+#define V9647 (V + 36402)
+ 0x110c, 0x1172, 0x11aa, 0,
+#undef V9648
+#define V9648 (V + 36406)
+ 0x110c, 0x1172, 0x11ab, 0,
+#undef V9649
+#define V9649 (V + 36410)
+ 0x110c, 0x1172, 0x11ac, 0,
+#undef V9650
+#define V9650 (V + 36414)
+ 0x110c, 0x1172, 0x11ad, 0,
+#undef V9651
+#define V9651 (V + 36418)
+ 0x110c, 0x1172, 0x11ae, 0,
+#undef V9652
+#define V9652 (V + 36422)
+ 0x110c, 0x1172, 0x11af, 0,
+#undef V9653
+#define V9653 (V + 36426)
+ 0x110c, 0x1172, 0x11b0, 0,
+#undef V9654
+#define V9654 (V + 36430)
+ 0x110c, 0x1172, 0x11b1, 0,
+#undef V9655
+#define V9655 (V + 36434)
+ 0x110c, 0x1172, 0x11b2, 0,
+#undef V9656
+#define V9656 (V + 36438)
+ 0x110c, 0x1172, 0x11b3, 0,
+#undef V9657
+#define V9657 (V + 36442)
+ 0x110c, 0x1172, 0x11b4, 0,
+#undef V9658
+#define V9658 (V + 36446)
+ 0x110c, 0x1172, 0x11b5, 0,
+#undef V9659
+#define V9659 (V + 36450)
+ 0x110c, 0x1172, 0x11b6, 0,
+#undef V9660
+#define V9660 (V + 36454)
+ 0x110c, 0x1172, 0x11b7, 0,
+#undef V9661
+#define V9661 (V + 36458)
+ 0x110c, 0x1172, 0x11b8, 0,
+#undef V9662
+#define V9662 (V + 36462)
+ 0x110c, 0x1172, 0x11b9, 0,
+#undef V9663
+#define V9663 (V + 36466)
+ 0x110c, 0x1172, 0x11ba, 0,
+#undef V9664
+#define V9664 (V + 36470)
+ 0x110c, 0x1172, 0x11bb, 0,
+#undef V9665
+#define V9665 (V + 36474)
+ 0x110c, 0x1172, 0x11bc, 0,
+#undef V9666
+#define V9666 (V + 36478)
+ 0x110c, 0x1172, 0x11bd, 0,
+#undef V9667
+#define V9667 (V + 36482)
+ 0x110c, 0x1172, 0x11be, 0,
+#undef V9668
+#define V9668 (V + 36486)
+ 0x110c, 0x1172, 0x11bf, 0,
+#undef V9669
+#define V9669 (V + 36490)
+ 0x110c, 0x1172, 0x11c0, 0,
+#undef V9670
+#define V9670 (V + 36494)
+ 0x110c, 0x1172, 0x11c1, 0,
+#undef V9671
+#define V9671 (V + 36498)
+ 0x110c, 0x1172, 0x11c2, 0,
+#undef V9672
+#define V9672 (V + 36502)
+ 0x110c, 0x1173, 0,
+#undef V9673
+#define V9673 (V + 36505)
+ 0x110c, 0x1173, 0x11a8, 0,
+#undef V9674
+#define V9674 (V + 36509)
+ 0x110c, 0x1173, 0x11a9, 0,
+#undef V9675
+#define V9675 (V + 36513)
+ 0x110c, 0x1173, 0x11aa, 0,
+#undef V9676
+#define V9676 (V + 36517)
+ 0x110c, 0x1173, 0x11ab, 0,
+#undef V9677
+#define V9677 (V + 36521)
+ 0x110c, 0x1173, 0x11ac, 0,
+#undef V9678
+#define V9678 (V + 36525)
+ 0x110c, 0x1173, 0x11ad, 0,
+#undef V9679
+#define V9679 (V + 36529)
+ 0x110c, 0x1173, 0x11ae, 0,
+#undef V9680
+#define V9680 (V + 36533)
+ 0x110c, 0x1173, 0x11af, 0,
+#undef V9681
+#define V9681 (V + 36537)
+ 0x110c, 0x1173, 0x11b0, 0,
+#undef V9682
+#define V9682 (V + 36541)
+ 0x110c, 0x1173, 0x11b1, 0,
+#undef V9683
+#define V9683 (V + 36545)
+ 0x110c, 0x1173, 0x11b2, 0,
+#undef V9684
+#define V9684 (V + 36549)
+ 0x110c, 0x1173, 0x11b3, 0,
+#undef V9685
+#define V9685 (V + 36553)
+ 0x110c, 0x1173, 0x11b4, 0,
+#undef V9686
+#define V9686 (V + 36557)
+ 0x110c, 0x1173, 0x11b5, 0,
+#undef V9687
+#define V9687 (V + 36561)
+ 0x110c, 0x1173, 0x11b6, 0,
+#undef V9688
+#define V9688 (V + 36565)
+ 0x110c, 0x1173, 0x11b7, 0,
+#undef V9689
+#define V9689 (V + 36569)
+ 0x110c, 0x1173, 0x11b8, 0,
+#undef V9690
+#define V9690 (V + 36573)
+ 0x110c, 0x1173, 0x11b9, 0,
+#undef V9691
+#define V9691 (V + 36577)
+ 0x110c, 0x1173, 0x11ba, 0,
+#undef V9692
+#define V9692 (V + 36581)
+ 0x110c, 0x1173, 0x11bb, 0,
+#undef V9693
+#define V9693 (V + 36585)
+ 0x110c, 0x1173, 0x11bc, 0,
+#undef V9694
+#define V9694 (V + 36589)
+ 0x110c, 0x1173, 0x11bd, 0,
+#undef V9695
+#define V9695 (V + 36593)
+ 0x110c, 0x1173, 0x11be, 0,
+#undef V9696
+#define V9696 (V + 36597)
+ 0x110c, 0x1173, 0x11bf, 0,
+#undef V9697
+#define V9697 (V + 36601)
+ 0x110c, 0x1173, 0x11c0, 0,
+#undef V9698
+#define V9698 (V + 36605)
+ 0x110c, 0x1173, 0x11c1, 0,
+#undef V9699
+#define V9699 (V + 36609)
+ 0x110c, 0x1173, 0x11c2, 0,
+#undef V9700
+#define V9700 (V + 36613)
+ 0x110c, 0x1174, 0,
+#undef V9701
+#define V9701 (V + 36616)
+ 0x110c, 0x1174, 0x11a8, 0,
+#undef V9702
+#define V9702 (V + 36620)
+ 0x110c, 0x1174, 0x11a9, 0,
+#undef V9703
+#define V9703 (V + 36624)
+ 0x110c, 0x1174, 0x11aa, 0,
+#undef V9704
+#define V9704 (V + 36628)
+ 0x110c, 0x1174, 0x11ab, 0,
+#undef V9705
+#define V9705 (V + 36632)
+ 0x110c, 0x1174, 0x11ac, 0,
+#undef V9706
+#define V9706 (V + 36636)
+ 0x110c, 0x1174, 0x11ad, 0,
+#undef V9707
+#define V9707 (V + 36640)
+ 0x110c, 0x1174, 0x11ae, 0,
+#undef V9708
+#define V9708 (V + 36644)
+ 0x110c, 0x1174, 0x11af, 0,
+#undef V9709
+#define V9709 (V + 36648)
+ 0x110c, 0x1174, 0x11b0, 0,
+#undef V9710
+#define V9710 (V + 36652)
+ 0x110c, 0x1174, 0x11b1, 0,
+#undef V9711
+#define V9711 (V + 36656)
+ 0x110c, 0x1174, 0x11b2, 0,
+#undef V9712
+#define V9712 (V + 36660)
+ 0x110c, 0x1174, 0x11b3, 0,
+#undef V9713
+#define V9713 (V + 36664)
+ 0x110c, 0x1174, 0x11b4, 0,
+#undef V9714
+#define V9714 (V + 36668)
+ 0x110c, 0x1174, 0x11b5, 0,
+#undef V9715
+#define V9715 (V + 36672)
+ 0x110c, 0x1174, 0x11b6, 0,
+#undef V9716
+#define V9716 (V + 36676)
+ 0x110c, 0x1174, 0x11b7, 0,
+#undef V9717
+#define V9717 (V + 36680)
+ 0x110c, 0x1174, 0x11b8, 0,
+#undef V9718
+#define V9718 (V + 36684)
+ 0x110c, 0x1174, 0x11b9, 0,
+#undef V9719
+#define V9719 (V + 36688)
+ 0x110c, 0x1174, 0x11ba, 0,
+#undef V9720
+#define V9720 (V + 36692)
+ 0x110c, 0x1174, 0x11bb, 0,
+#undef V9721
+#define V9721 (V + 36696)
+ 0x110c, 0x1174, 0x11bc, 0,
+#undef V9722
+#define V9722 (V + 36700)
+ 0x110c, 0x1174, 0x11bd, 0,
+#undef V9723
+#define V9723 (V + 36704)
+ 0x110c, 0x1174, 0x11be, 0,
+#undef V9724
+#define V9724 (V + 36708)
+ 0x110c, 0x1174, 0x11bf, 0,
+#undef V9725
+#define V9725 (V + 36712)
+ 0x110c, 0x1174, 0x11c0, 0,
+#undef V9726
+#define V9726 (V + 36716)
+ 0x110c, 0x1174, 0x11c1, 0,
+#undef V9727
+#define V9727 (V + 36720)
+ 0x110c, 0x1174, 0x11c2, 0,
+#undef V9728
+#define V9728 (V + 36724)
+ 0x110c, 0x1175, 0,
+#undef V9729
+#define V9729 (V + 36727)
+ 0x110c, 0x1175, 0x11a8, 0,
+#undef V9730
+#define V9730 (V + 36731)
+ 0x110c, 0x1175, 0x11a9, 0,
+#undef V9731
+#define V9731 (V + 36735)
+ 0x110c, 0x1175, 0x11aa, 0,
+#undef V9732
+#define V9732 (V + 36739)
+ 0x110c, 0x1175, 0x11ab, 0,
+#undef V9733
+#define V9733 (V + 36743)
+ 0x110c, 0x1175, 0x11ac, 0,
+#undef V9734
+#define V9734 (V + 36747)
+ 0x110c, 0x1175, 0x11ad, 0,
+#undef V9735
+#define V9735 (V + 36751)
+ 0x110c, 0x1175, 0x11ae, 0,
+#undef V9736
+#define V9736 (V + 36755)
+ 0x110c, 0x1175, 0x11af, 0,
+#undef V9737
+#define V9737 (V + 36759)
+ 0x110c, 0x1175, 0x11b0, 0,
+#undef V9738
+#define V9738 (V + 36763)
+ 0x110c, 0x1175, 0x11b1, 0,
+#undef V9739
+#define V9739 (V + 36767)
+ 0x110c, 0x1175, 0x11b2, 0,
+#undef V9740
+#define V9740 (V + 36771)
+ 0x110c, 0x1175, 0x11b3, 0,
+#undef V9741
+#define V9741 (V + 36775)
+ 0x110c, 0x1175, 0x11b4, 0,
+#undef V9742
+#define V9742 (V + 36779)
+ 0x110c, 0x1175, 0x11b5, 0,
+#undef V9743
+#define V9743 (V + 36783)
+ 0x110c, 0x1175, 0x11b6, 0,
+#undef V9744
+#define V9744 (V + 36787)
+ 0x110c, 0x1175, 0x11b7, 0,
+#undef V9745
+#define V9745 (V + 36791)
+ 0x110c, 0x1175, 0x11b8, 0,
+#undef V9746
+#define V9746 (V + 36795)
+ 0x110c, 0x1175, 0x11b9, 0,
+#undef V9747
+#define V9747 (V + 36799)
+ 0x110c, 0x1175, 0x11ba, 0,
+#undef V9748
+#define V9748 (V + 36803)
+ 0x110c, 0x1175, 0x11bb, 0,
+#undef V9749
+#define V9749 (V + 36807)
+ 0x110c, 0x1175, 0x11bc, 0,
+#undef V9750
+#define V9750 (V + 36811)
+ 0x110c, 0x1175, 0x11bd, 0,
+#undef V9751
+#define V9751 (V + 36815)
+ 0x110c, 0x1175, 0x11be, 0,
+#undef V9752
+#define V9752 (V + 36819)
+ 0x110c, 0x1175, 0x11bf, 0,
+#undef V9753
+#define V9753 (V + 36823)
+ 0x110c, 0x1175, 0x11c0, 0,
+#undef V9754
+#define V9754 (V + 36827)
+ 0x110c, 0x1175, 0x11c1, 0,
+#undef V9755
+#define V9755 (V + 36831)
+ 0x110c, 0x1175, 0x11c2, 0,
+#undef V9756
+#define V9756 (V + 36835)
+ 0x110d, 0x1161, 0,
+#undef V9757
+#define V9757 (V + 36838)
+ 0x110d, 0x1161, 0x11a8, 0,
+#undef V9758
+#define V9758 (V + 36842)
+ 0x110d, 0x1161, 0x11a9, 0,
+#undef V9759
+#define V9759 (V + 36846)
+ 0x110d, 0x1161, 0x11aa, 0,
+#undef V9760
+#define V9760 (V + 36850)
+ 0x110d, 0x1161, 0x11ab, 0,
+#undef V9761
+#define V9761 (V + 36854)
+ 0x110d, 0x1161, 0x11ac, 0,
+#undef V9762
+#define V9762 (V + 36858)
+ 0x110d, 0x1161, 0x11ad, 0,
+#undef V9763
+#define V9763 (V + 36862)
+ 0x110d, 0x1161, 0x11ae, 0,
+#undef V9764
+#define V9764 (V + 36866)
+ 0x110d, 0x1161, 0x11af, 0,
+#undef V9765
+#define V9765 (V + 36870)
+ 0x110d, 0x1161, 0x11b0, 0,
+#undef V9766
+#define V9766 (V + 36874)
+ 0x110d, 0x1161, 0x11b1, 0,
+#undef V9767
+#define V9767 (V + 36878)
+ 0x110d, 0x1161, 0x11b2, 0,
+#undef V9768
+#define V9768 (V + 36882)
+ 0x110d, 0x1161, 0x11b3, 0,
+#undef V9769
+#define V9769 (V + 36886)
+ 0x110d, 0x1161, 0x11b4, 0,
+#undef V9770
+#define V9770 (V + 36890)
+ 0x110d, 0x1161, 0x11b5, 0,
+#undef V9771
+#define V9771 (V + 36894)
+ 0x110d, 0x1161, 0x11b6, 0,
+#undef V9772
+#define V9772 (V + 36898)
+ 0x110d, 0x1161, 0x11b7, 0,
+#undef V9773
+#define V9773 (V + 36902)
+ 0x110d, 0x1161, 0x11b8, 0,
+#undef V9774
+#define V9774 (V + 36906)
+ 0x110d, 0x1161, 0x11b9, 0,
+#undef V9775
+#define V9775 (V + 36910)
+ 0x110d, 0x1161, 0x11ba, 0,
+#undef V9776
+#define V9776 (V + 36914)
+ 0x110d, 0x1161, 0x11bb, 0,
+#undef V9777
+#define V9777 (V + 36918)
+ 0x110d, 0x1161, 0x11bc, 0,
+#undef V9778
+#define V9778 (V + 36922)
+ 0x110d, 0x1161, 0x11bd, 0,
+#undef V9779
+#define V9779 (V + 36926)
+ 0x110d, 0x1161, 0x11be, 0,
+#undef V9780
+#define V9780 (V + 36930)
+ 0x110d, 0x1161, 0x11bf, 0,
+#undef V9781
+#define V9781 (V + 36934)
+ 0x110d, 0x1161, 0x11c0, 0,
+#undef V9782
+#define V9782 (V + 36938)
+ 0x110d, 0x1161, 0x11c1, 0,
+#undef V9783
+#define V9783 (V + 36942)
+ 0x110d, 0x1161, 0x11c2, 0,
+#undef V9784
+#define V9784 (V + 36946)
+ 0x110d, 0x1162, 0,
+#undef V9785
+#define V9785 (V + 36949)
+ 0x110d, 0x1162, 0x11a8, 0,
+#undef V9786
+#define V9786 (V + 36953)
+ 0x110d, 0x1162, 0x11a9, 0,
+#undef V9787
+#define V9787 (V + 36957)
+ 0x110d, 0x1162, 0x11aa, 0,
+#undef V9788
+#define V9788 (V + 36961)
+ 0x110d, 0x1162, 0x11ab, 0,
+#undef V9789
+#define V9789 (V + 36965)
+ 0x110d, 0x1162, 0x11ac, 0,
+#undef V9790
+#define V9790 (V + 36969)
+ 0x110d, 0x1162, 0x11ad, 0,
+#undef V9791
+#define V9791 (V + 36973)
+ 0x110d, 0x1162, 0x11ae, 0,
+#undef V9792
+#define V9792 (V + 36977)
+ 0x110d, 0x1162, 0x11af, 0,
+#undef V9793
+#define V9793 (V + 36981)
+ 0x110d, 0x1162, 0x11b0, 0,
+#undef V9794
+#define V9794 (V + 36985)
+ 0x110d, 0x1162, 0x11b1, 0,
+#undef V9795
+#define V9795 (V + 36989)
+ 0x110d, 0x1162, 0x11b2, 0,
+#undef V9796
+#define V9796 (V + 36993)
+ 0x110d, 0x1162, 0x11b3, 0,
+#undef V9797
+#define V9797 (V + 36997)
+ 0x110d, 0x1162, 0x11b4, 0,
+#undef V9798
+#define V9798 (V + 37001)
+ 0x110d, 0x1162, 0x11b5, 0,
+#undef V9799
+#define V9799 (V + 37005)
+ 0x110d, 0x1162, 0x11b6, 0,
+#undef V9800
+#define V9800 (V + 37009)
+ 0x110d, 0x1162, 0x11b7, 0,
+#undef V9801
+#define V9801 (V + 37013)
+ 0x110d, 0x1162, 0x11b8, 0,
+#undef V9802
+#define V9802 (V + 37017)
+ 0x110d, 0x1162, 0x11b9, 0,
+#undef V9803
+#define V9803 (V + 37021)
+ 0x110d, 0x1162, 0x11ba, 0,
+#undef V9804
+#define V9804 (V + 37025)
+ 0x110d, 0x1162, 0x11bb, 0,
+#undef V9805
+#define V9805 (V + 37029)
+ 0x110d, 0x1162, 0x11bc, 0,
+#undef V9806
+#define V9806 (V + 37033)
+ 0x110d, 0x1162, 0x11bd, 0,
+#undef V9807
+#define V9807 (V + 37037)
+ 0x110d, 0x1162, 0x11be, 0,
+#undef V9808
+#define V9808 (V + 37041)
+ 0x110d, 0x1162, 0x11bf, 0,
+#undef V9809
+#define V9809 (V + 37045)
+ 0x110d, 0x1162, 0x11c0, 0,
+#undef V9810
+#define V9810 (V + 37049)
+ 0x110d, 0x1162, 0x11c1, 0,
+#undef V9811
+#define V9811 (V + 37053)
+ 0x110d, 0x1162, 0x11c2, 0,
+#undef V9812
+#define V9812 (V + 37057)
+ 0x110d, 0x1163, 0,
+#undef V9813
+#define V9813 (V + 37060)
+ 0x110d, 0x1163, 0x11a8, 0,
+#undef V9814
+#define V9814 (V + 37064)
+ 0x110d, 0x1163, 0x11a9, 0,
+#undef V9815
+#define V9815 (V + 37068)
+ 0x110d, 0x1163, 0x11aa, 0,
+#undef V9816
+#define V9816 (V + 37072)
+ 0x110d, 0x1163, 0x11ab, 0,
+#undef V9817
+#define V9817 (V + 37076)
+ 0x110d, 0x1163, 0x11ac, 0,
+#undef V9818
+#define V9818 (V + 37080)
+ 0x110d, 0x1163, 0x11ad, 0,
+#undef V9819
+#define V9819 (V + 37084)
+ 0x110d, 0x1163, 0x11ae, 0,
+#undef V9820
+#define V9820 (V + 37088)
+ 0x110d, 0x1163, 0x11af, 0,
+#undef V9821
+#define V9821 (V + 37092)
+ 0x110d, 0x1163, 0x11b0, 0,
+#undef V9822
+#define V9822 (V + 37096)
+ 0x110d, 0x1163, 0x11b1, 0,
+#undef V9823
+#define V9823 (V + 37100)
+ 0x110d, 0x1163, 0x11b2, 0,
+#undef V9824
+#define V9824 (V + 37104)
+ 0x110d, 0x1163, 0x11b3, 0,
+#undef V9825
+#define V9825 (V + 37108)
+ 0x110d, 0x1163, 0x11b4, 0,
+#undef V9826
+#define V9826 (V + 37112)
+ 0x110d, 0x1163, 0x11b5, 0,
+#undef V9827
+#define V9827 (V + 37116)
+ 0x110d, 0x1163, 0x11b6, 0,
+#undef V9828
+#define V9828 (V + 37120)
+ 0x110d, 0x1163, 0x11b7, 0,
+#undef V9829
+#define V9829 (V + 37124)
+ 0x110d, 0x1163, 0x11b8, 0,
+#undef V9830
+#define V9830 (V + 37128)
+ 0x110d, 0x1163, 0x11b9, 0,
+#undef V9831
+#define V9831 (V + 37132)
+ 0x110d, 0x1163, 0x11ba, 0,
+#undef V9832
+#define V9832 (V + 37136)
+ 0x110d, 0x1163, 0x11bb, 0,
+#undef V9833
+#define V9833 (V + 37140)
+ 0x110d, 0x1163, 0x11bc, 0,
+#undef V9834
+#define V9834 (V + 37144)
+ 0x110d, 0x1163, 0x11bd, 0,
+#undef V9835
+#define V9835 (V + 37148)
+ 0x110d, 0x1163, 0x11be, 0,
+#undef V9836
+#define V9836 (V + 37152)
+ 0x110d, 0x1163, 0x11bf, 0,
+#undef V9837
+#define V9837 (V + 37156)
+ 0x110d, 0x1163, 0x11c0, 0,
+#undef V9838
+#define V9838 (V + 37160)
+ 0x110d, 0x1163, 0x11c1, 0,
+#undef V9839
+#define V9839 (V + 37164)
+ 0x110d, 0x1163, 0x11c2, 0,
+#undef V9840
+#define V9840 (V + 37168)
+ 0x110d, 0x1164, 0,
+#undef V9841
+#define V9841 (V + 37171)
+ 0x110d, 0x1164, 0x11a8, 0,
+#undef V9842
+#define V9842 (V + 37175)
+ 0x110d, 0x1164, 0x11a9, 0,
+#undef V9843
+#define V9843 (V + 37179)
+ 0x110d, 0x1164, 0x11aa, 0,
+#undef V9844
+#define V9844 (V + 37183)
+ 0x110d, 0x1164, 0x11ab, 0,
+#undef V9845
+#define V9845 (V + 37187)
+ 0x110d, 0x1164, 0x11ac, 0,
+#undef V9846
+#define V9846 (V + 37191)
+ 0x110d, 0x1164, 0x11ad, 0,
+#undef V9847
+#define V9847 (V + 37195)
+ 0x110d, 0x1164, 0x11ae, 0,
+#undef V9848
+#define V9848 (V + 37199)
+ 0x110d, 0x1164, 0x11af, 0,
+#undef V9849
+#define V9849 (V + 37203)
+ 0x110d, 0x1164, 0x11b0, 0,
+#undef V9850
+#define V9850 (V + 37207)
+ 0x110d, 0x1164, 0x11b1, 0,
+#undef V9851
+#define V9851 (V + 37211)
+ 0x110d, 0x1164, 0x11b2, 0,
+#undef V9852
+#define V9852 (V + 37215)
+ 0x110d, 0x1164, 0x11b3, 0,
+#undef V9853
+#define V9853 (V + 37219)
+ 0x110d, 0x1164, 0x11b4, 0,
+#undef V9854
+#define V9854 (V + 37223)
+ 0x110d, 0x1164, 0x11b5, 0,
+#undef V9855
+#define V9855 (V + 37227)
+ 0x110d, 0x1164, 0x11b6, 0,
+#undef V9856
+#define V9856 (V + 37231)
+ 0x110d, 0x1164, 0x11b7, 0,
+#undef V9857
+#define V9857 (V + 37235)
+ 0x110d, 0x1164, 0x11b8, 0,
+#undef V9858
+#define V9858 (V + 37239)
+ 0x110d, 0x1164, 0x11b9, 0,
+#undef V9859
+#define V9859 (V + 37243)
+ 0x110d, 0x1164, 0x11ba, 0,
+#undef V9860
+#define V9860 (V + 37247)
+ 0x110d, 0x1164, 0x11bb, 0,
+#undef V9861
+#define V9861 (V + 37251)
+ 0x110d, 0x1164, 0x11bc, 0,
+#undef V9862
+#define V9862 (V + 37255)
+ 0x110d, 0x1164, 0x11bd, 0,
+#undef V9863
+#define V9863 (V + 37259)
+ 0x110d, 0x1164, 0x11be, 0,
+#undef V9864
+#define V9864 (V + 37263)
+ 0x110d, 0x1164, 0x11bf, 0,
+#undef V9865
+#define V9865 (V + 37267)
+ 0x110d, 0x1164, 0x11c0, 0,
+#undef V9866
+#define V9866 (V + 37271)
+ 0x110d, 0x1164, 0x11c1, 0,
+#undef V9867
+#define V9867 (V + 37275)
+ 0x110d, 0x1164, 0x11c2, 0,
+#undef V9868
+#define V9868 (V + 37279)
+ 0x110d, 0x1165, 0,
+#undef V9869
+#define V9869 (V + 37282)
+ 0x110d, 0x1165, 0x11a8, 0,
+#undef V9870
+#define V9870 (V + 37286)
+ 0x110d, 0x1165, 0x11a9, 0,
+#undef V9871
+#define V9871 (V + 37290)
+ 0x110d, 0x1165, 0x11aa, 0,
+#undef V9872
+#define V9872 (V + 37294)
+ 0x110d, 0x1165, 0x11ab, 0,
+#undef V9873
+#define V9873 (V + 37298)
+ 0x110d, 0x1165, 0x11ac, 0,
+#undef V9874
+#define V9874 (V + 37302)
+ 0x110d, 0x1165, 0x11ad, 0,
+#undef V9875
+#define V9875 (V + 37306)
+ 0x110d, 0x1165, 0x11ae, 0,
+#undef V9876
+#define V9876 (V + 37310)
+ 0x110d, 0x1165, 0x11af, 0,
+#undef V9877
+#define V9877 (V + 37314)
+ 0x110d, 0x1165, 0x11b0, 0,
+#undef V9878
+#define V9878 (V + 37318)
+ 0x110d, 0x1165, 0x11b1, 0,
+#undef V9879
+#define V9879 (V + 37322)
+ 0x110d, 0x1165, 0x11b2, 0,
+#undef V9880
+#define V9880 (V + 37326)
+ 0x110d, 0x1165, 0x11b3, 0,
+#undef V9881
+#define V9881 (V + 37330)
+ 0x110d, 0x1165, 0x11b4, 0,
+#undef V9882
+#define V9882 (V + 37334)
+ 0x110d, 0x1165, 0x11b5, 0,
+#undef V9883
+#define V9883 (V + 37338)
+ 0x110d, 0x1165, 0x11b6, 0,
+#undef V9884
+#define V9884 (V + 37342)
+ 0x110d, 0x1165, 0x11b7, 0,
+#undef V9885
+#define V9885 (V + 37346)
+ 0x110d, 0x1165, 0x11b8, 0,
+#undef V9886
+#define V9886 (V + 37350)
+ 0x110d, 0x1165, 0x11b9, 0,
+#undef V9887
+#define V9887 (V + 37354)
+ 0x110d, 0x1165, 0x11ba, 0,
+#undef V9888
+#define V9888 (V + 37358)
+ 0x110d, 0x1165, 0x11bb, 0,
+#undef V9889
+#define V9889 (V + 37362)
+ 0x110d, 0x1165, 0x11bc, 0,
+#undef V9890
+#define V9890 (V + 37366)
+ 0x110d, 0x1165, 0x11bd, 0,
+#undef V9891
+#define V9891 (V + 37370)
+ 0x110d, 0x1165, 0x11be, 0,
+#undef V9892
+#define V9892 (V + 37374)
+ 0x110d, 0x1165, 0x11bf, 0,
+#undef V9893
+#define V9893 (V + 37378)
+ 0x110d, 0x1165, 0x11c0, 0,
+#undef V9894
+#define V9894 (V + 37382)
+ 0x110d, 0x1165, 0x11c1, 0,
+#undef V9895
+#define V9895 (V + 37386)
+ 0x110d, 0x1165, 0x11c2, 0,
+#undef V9896
+#define V9896 (V + 37390)
+ 0x110d, 0x1166, 0,
+#undef V9897
+#define V9897 (V + 37393)
+ 0x110d, 0x1166, 0x11a8, 0,
+#undef V9898
+#define V9898 (V + 37397)
+ 0x110d, 0x1166, 0x11a9, 0,
+#undef V9899
+#define V9899 (V + 37401)
+ 0x110d, 0x1166, 0x11aa, 0,
+#undef V9900
+#define V9900 (V + 37405)
+ 0x110d, 0x1166, 0x11ab, 0,
+#undef V9901
+#define V9901 (V + 37409)
+ 0x110d, 0x1166, 0x11ac, 0,
+#undef V9902
+#define V9902 (V + 37413)
+ 0x110d, 0x1166, 0x11ad, 0,
+#undef V9903
+#define V9903 (V + 37417)
+ 0x110d, 0x1166, 0x11ae, 0,
+#undef V9904
+#define V9904 (V + 37421)
+ 0x110d, 0x1166, 0x11af, 0,
+#undef V9905
+#define V9905 (V + 37425)
+ 0x110d, 0x1166, 0x11b0, 0,
+#undef V9906
+#define V9906 (V + 37429)
+ 0x110d, 0x1166, 0x11b1, 0,
+#undef V9907
+#define V9907 (V + 37433)
+ 0x110d, 0x1166, 0x11b2, 0,
+#undef V9908
+#define V9908 (V + 37437)
+ 0x110d, 0x1166, 0x11b3, 0,
+#undef V9909
+#define V9909 (V + 37441)
+ 0x110d, 0x1166, 0x11b4, 0,
+#undef V9910
+#define V9910 (V + 37445)
+ 0x110d, 0x1166, 0x11b5, 0,
+#undef V9911
+#define V9911 (V + 37449)
+ 0x110d, 0x1166, 0x11b6, 0,
+#undef V9912
+#define V9912 (V + 37453)
+ 0x110d, 0x1166, 0x11b7, 0,
+#undef V9913
+#define V9913 (V + 37457)
+ 0x110d, 0x1166, 0x11b8, 0,
+#undef V9914
+#define V9914 (V + 37461)
+ 0x110d, 0x1166, 0x11b9, 0,
+#undef V9915
+#define V9915 (V + 37465)
+ 0x110d, 0x1166, 0x11ba, 0,
+#undef V9916
+#define V9916 (V + 37469)
+ 0x110d, 0x1166, 0x11bb, 0,
+#undef V9917
+#define V9917 (V + 37473)
+ 0x110d, 0x1166, 0x11bc, 0,
+#undef V9918
+#define V9918 (V + 37477)
+ 0x110d, 0x1166, 0x11bd, 0,
+#undef V9919
+#define V9919 (V + 37481)
+ 0x110d, 0x1166, 0x11be, 0,
+#undef V9920
+#define V9920 (V + 37485)
+ 0x110d, 0x1166, 0x11bf, 0,
+#undef V9921
+#define V9921 (V + 37489)
+ 0x110d, 0x1166, 0x11c0, 0,
+#undef V9922
+#define V9922 (V + 37493)
+ 0x110d, 0x1166, 0x11c1, 0,
+#undef V9923
+#define V9923 (V + 37497)
+ 0x110d, 0x1166, 0x11c2, 0,
+#undef V9924
+#define V9924 (V + 37501)
+ 0x110d, 0x1167, 0,
+#undef V9925
+#define V9925 (V + 37504)
+ 0x110d, 0x1167, 0x11a8, 0,
+#undef V9926
+#define V9926 (V + 37508)
+ 0x110d, 0x1167, 0x11a9, 0,
+#undef V9927
+#define V9927 (V + 37512)
+ 0x110d, 0x1167, 0x11aa, 0,
+#undef V9928
+#define V9928 (V + 37516)
+ 0x110d, 0x1167, 0x11ab, 0,
+#undef V9929
+#define V9929 (V + 37520)
+ 0x110d, 0x1167, 0x11ac, 0,
+#undef V9930
+#define V9930 (V + 37524)
+ 0x110d, 0x1167, 0x11ad, 0,
+#undef V9931
+#define V9931 (V + 37528)
+ 0x110d, 0x1167, 0x11ae, 0,
+#undef V9932
+#define V9932 (V + 37532)
+ 0x110d, 0x1167, 0x11af, 0,
+#undef V9933
+#define V9933 (V + 37536)
+ 0x110d, 0x1167, 0x11b0, 0,
+#undef V9934
+#define V9934 (V + 37540)
+ 0x110d, 0x1167, 0x11b1, 0,
+#undef V9935
+#define V9935 (V + 37544)
+ 0x110d, 0x1167, 0x11b2, 0,
+#undef V9936
+#define V9936 (V + 37548)
+ 0x110d, 0x1167, 0x11b3, 0,
+#undef V9937
+#define V9937 (V + 37552)
+ 0x110d, 0x1167, 0x11b4, 0,
+#undef V9938
+#define V9938 (V + 37556)
+ 0x110d, 0x1167, 0x11b5, 0,
+#undef V9939
+#define V9939 (V + 37560)
+ 0x110d, 0x1167, 0x11b6, 0,
+#undef V9940
+#define V9940 (V + 37564)
+ 0x110d, 0x1167, 0x11b7, 0,
+#undef V9941
+#define V9941 (V + 37568)
+ 0x110d, 0x1167, 0x11b8, 0,
+#undef V9942
+#define V9942 (V + 37572)
+ 0x110d, 0x1167, 0x11b9, 0,
+#undef V9943
+#define V9943 (V + 37576)
+ 0x110d, 0x1167, 0x11ba, 0,
+#undef V9944
+#define V9944 (V + 37580)
+ 0x110d, 0x1167, 0x11bb, 0,
+#undef V9945
+#define V9945 (V + 37584)
+ 0x110d, 0x1167, 0x11bc, 0,
+#undef V9946
+#define V9946 (V + 37588)
+ 0x110d, 0x1167, 0x11bd, 0,
+#undef V9947
+#define V9947 (V + 37592)
+ 0x110d, 0x1167, 0x11be, 0,
+#undef V9948
+#define V9948 (V + 37596)
+ 0x110d, 0x1167, 0x11bf, 0,
+#undef V9949
+#define V9949 (V + 37600)
+ 0x110d, 0x1167, 0x11c0, 0,
+#undef V9950
+#define V9950 (V + 37604)
+ 0x110d, 0x1167, 0x11c1, 0,
+#undef V9951
+#define V9951 (V + 37608)
+ 0x110d, 0x1167, 0x11c2, 0,
+#undef V9952
+#define V9952 (V + 37612)
+ 0x110d, 0x1168, 0,
+#undef V9953
+#define V9953 (V + 37615)
+ 0x110d, 0x1168, 0x11a8, 0,
+#undef V9954
+#define V9954 (V + 37619)
+ 0x110d, 0x1168, 0x11a9, 0,
+#undef V9955
+#define V9955 (V + 37623)
+ 0x110d, 0x1168, 0x11aa, 0,
+#undef V9956
+#define V9956 (V + 37627)
+ 0x110d, 0x1168, 0x11ab, 0,
+#undef V9957
+#define V9957 (V + 37631)
+ 0x110d, 0x1168, 0x11ac, 0,
+#undef V9958
+#define V9958 (V + 37635)
+ 0x110d, 0x1168, 0x11ad, 0,
+#undef V9959
+#define V9959 (V + 37639)
+ 0x110d, 0x1168, 0x11ae, 0,
+#undef V9960
+#define V9960 (V + 37643)
+ 0x110d, 0x1168, 0x11af, 0,
+#undef V9961
+#define V9961 (V + 37647)
+ 0x110d, 0x1168, 0x11b0, 0,
+#undef V9962
+#define V9962 (V + 37651)
+ 0x110d, 0x1168, 0x11b1, 0,
+#undef V9963
+#define V9963 (V + 37655)
+ 0x110d, 0x1168, 0x11b2, 0,
+#undef V9964
+#define V9964 (V + 37659)
+ 0x110d, 0x1168, 0x11b3, 0,
+#undef V9965
+#define V9965 (V + 37663)
+ 0x110d, 0x1168, 0x11b4, 0,
+#undef V9966
+#define V9966 (V + 37667)
+ 0x110d, 0x1168, 0x11b5, 0,
+#undef V9967
+#define V9967 (V + 37671)
+ 0x110d, 0x1168, 0x11b6, 0,
+#undef V9968
+#define V9968 (V + 37675)
+ 0x110d, 0x1168, 0x11b7, 0,
+#undef V9969
+#define V9969 (V + 37679)
+ 0x110d, 0x1168, 0x11b8, 0,
+#undef V9970
+#define V9970 (V + 37683)
+ 0x110d, 0x1168, 0x11b9, 0,
+#undef V9971
+#define V9971 (V + 37687)
+ 0x110d, 0x1168, 0x11ba, 0,
+#undef V9972
+#define V9972 (V + 37691)
+ 0x110d, 0x1168, 0x11bb, 0,
+#undef V9973
+#define V9973 (V + 37695)
+ 0x110d, 0x1168, 0x11bc, 0,
+#undef V9974
+#define V9974 (V + 37699)
+ 0x110d, 0x1168, 0x11bd, 0,
+#undef V9975
+#define V9975 (V + 37703)
+ 0x110d, 0x1168, 0x11be, 0,
+#undef V9976
+#define V9976 (V + 37707)
+ 0x110d, 0x1168, 0x11bf, 0,
+#undef V9977
+#define V9977 (V + 37711)
+ 0x110d, 0x1168, 0x11c0, 0,
+#undef V9978
+#define V9978 (V + 37715)
+ 0x110d, 0x1168, 0x11c1, 0,
+#undef V9979
+#define V9979 (V + 37719)
+ 0x110d, 0x1168, 0x11c2, 0,
+#undef V9980
+#define V9980 (V + 37723)
+ 0x110d, 0x1169, 0,
+#undef V9981
+#define V9981 (V + 37726)
+ 0x110d, 0x1169, 0x11a8, 0,
+#undef V9982
+#define V9982 (V + 37730)
+ 0x110d, 0x1169, 0x11a9, 0,
+#undef V9983
+#define V9983 (V + 37734)
+ 0x110d, 0x1169, 0x11aa, 0,
+#undef V9984
+#define V9984 (V + 37738)
+ 0x110d, 0x1169, 0x11ab, 0,
+#undef V9985
+#define V9985 (V + 37742)
+ 0x110d, 0x1169, 0x11ac, 0,
+#undef V9986
+#define V9986 (V + 37746)
+ 0x110d, 0x1169, 0x11ad, 0,
+#undef V9987
+#define V9987 (V + 37750)
+ 0x110d, 0x1169, 0x11ae, 0,
+#undef V9988
+#define V9988 (V + 37754)
+ 0x110d, 0x1169, 0x11af, 0,
+#undef V9989
+#define V9989 (V + 37758)
+ 0x110d, 0x1169, 0x11b0, 0,
+#undef V9990
+#define V9990 (V + 37762)
+ 0x110d, 0x1169, 0x11b1, 0,
+#undef V9991
+#define V9991 (V + 37766)
+ 0x110d, 0x1169, 0x11b2, 0,
+#undef V9992
+#define V9992 (V + 37770)
+ 0x110d, 0x1169, 0x11b3, 0,
+#undef V9993
+#define V9993 (V + 37774)
+ 0x110d, 0x1169, 0x11b4, 0,
+#undef V9994
+#define V9994 (V + 37778)
+ 0x110d, 0x1169, 0x11b5, 0,
+#undef V9995
+#define V9995 (V + 37782)
+ 0x110d, 0x1169, 0x11b6, 0,
+#undef V9996
+#define V9996 (V + 37786)
+ 0x110d, 0x1169, 0x11b7, 0,
+#undef V9997
+#define V9997 (V + 37790)
+ 0x110d, 0x1169, 0x11b8, 0,
+#undef V9998
+#define V9998 (V + 37794)
+ 0x110d, 0x1169, 0x11b9, 0,
+#undef V9999
+#define V9999 (V + 37798)
+ 0x110d, 0x1169, 0x11ba, 0,
+#undef V10000
+#define V10000 (V + 37802)
+ 0x110d, 0x1169, 0x11bb, 0,
+#undef V10001
+#define V10001 (V + 37806)
+ 0x110d, 0x1169, 0x11bc, 0,
+#undef V10002
+#define V10002 (V + 37810)
+ 0x110d, 0x1169, 0x11bd, 0,
+#undef V10003
+#define V10003 (V + 37814)
+ 0x110d, 0x1169, 0x11be, 0,
+#undef V10004
+#define V10004 (V + 37818)
+ 0x110d, 0x1169, 0x11bf, 0,
+#undef V10005
+#define V10005 (V + 37822)
+ 0x110d, 0x1169, 0x11c0, 0,
+#undef V10006
+#define V10006 (V + 37826)
+ 0x110d, 0x1169, 0x11c1, 0,
+#undef V10007
+#define V10007 (V + 37830)
+ 0x110d, 0x1169, 0x11c2, 0,
+#undef V10008
+#define V10008 (V + 37834)
+ 0x110d, 0x116a, 0,
+#undef V10009
+#define V10009 (V + 37837)
+ 0x110d, 0x116a, 0x11a8, 0,
+#undef V10010
+#define V10010 (V + 37841)
+ 0x110d, 0x116a, 0x11a9, 0,
+#undef V10011
+#define V10011 (V + 37845)
+ 0x110d, 0x116a, 0x11aa, 0,
+#undef V10012
+#define V10012 (V + 37849)
+ 0x110d, 0x116a, 0x11ab, 0,
+#undef V10013
+#define V10013 (V + 37853)
+ 0x110d, 0x116a, 0x11ac, 0,
+#undef V10014
+#define V10014 (V + 37857)
+ 0x110d, 0x116a, 0x11ad, 0,
+#undef V10015
+#define V10015 (V + 37861)
+ 0x110d, 0x116a, 0x11ae, 0,
+#undef V10016
+#define V10016 (V + 37865)
+ 0x110d, 0x116a, 0x11af, 0,
+#undef V10017
+#define V10017 (V + 37869)
+ 0x110d, 0x116a, 0x11b0, 0,
+#undef V10018
+#define V10018 (V + 37873)
+ 0x110d, 0x116a, 0x11b1, 0,
+#undef V10019
+#define V10019 (V + 37877)
+ 0x110d, 0x116a, 0x11b2, 0,
+#undef V10020
+#define V10020 (V + 37881)
+ 0x110d, 0x116a, 0x11b3, 0,
+#undef V10021
+#define V10021 (V + 37885)
+ 0x110d, 0x116a, 0x11b4, 0,
+#undef V10022
+#define V10022 (V + 37889)
+ 0x110d, 0x116a, 0x11b5, 0,
+#undef V10023
+#define V10023 (V + 37893)
+ 0x110d, 0x116a, 0x11b6, 0,
+#undef V10024
+#define V10024 (V + 37897)
+ 0x110d, 0x116a, 0x11b7, 0,
+#undef V10025
+#define V10025 (V + 37901)
+ 0x110d, 0x116a, 0x11b8, 0,
+#undef V10026
+#define V10026 (V + 37905)
+ 0x110d, 0x116a, 0x11b9, 0,
+#undef V10027
+#define V10027 (V + 37909)
+ 0x110d, 0x116a, 0x11ba, 0,
+#undef V10028
+#define V10028 (V + 37913)
+ 0x110d, 0x116a, 0x11bb, 0,
+#undef V10029
+#define V10029 (V + 37917)
+ 0x110d, 0x116a, 0x11bc, 0,
+#undef V10030
+#define V10030 (V + 37921)
+ 0x110d, 0x116a, 0x11bd, 0,
+#undef V10031
+#define V10031 (V + 37925)
+ 0x110d, 0x116a, 0x11be, 0,
+#undef V10032
+#define V10032 (V + 37929)
+ 0x110d, 0x116a, 0x11bf, 0,
+#undef V10033
+#define V10033 (V + 37933)
+ 0x110d, 0x116a, 0x11c0, 0,
+#undef V10034
+#define V10034 (V + 37937)
+ 0x110d, 0x116a, 0x11c1, 0,
+#undef V10035
+#define V10035 (V + 37941)
+ 0x110d, 0x116a, 0x11c2, 0,
+#undef V10036
+#define V10036 (V + 37945)
+ 0x110d, 0x116b, 0,
+#undef V10037
+#define V10037 (V + 37948)
+ 0x110d, 0x116b, 0x11a8, 0,
+#undef V10038
+#define V10038 (V + 37952)
+ 0x110d, 0x116b, 0x11a9, 0,
+#undef V10039
+#define V10039 (V + 37956)
+ 0x110d, 0x116b, 0x11aa, 0,
+#undef V10040
+#define V10040 (V + 37960)
+ 0x110d, 0x116b, 0x11ab, 0,
+#undef V10041
+#define V10041 (V + 37964)
+ 0x110d, 0x116b, 0x11ac, 0,
+#undef V10042
+#define V10042 (V + 37968)
+ 0x110d, 0x116b, 0x11ad, 0,
+#undef V10043
+#define V10043 (V + 37972)
+ 0x110d, 0x116b, 0x11ae, 0,
+#undef V10044
+#define V10044 (V + 37976)
+ 0x110d, 0x116b, 0x11af, 0,
+#undef V10045
+#define V10045 (V + 37980)
+ 0x110d, 0x116b, 0x11b0, 0,
+#undef V10046
+#define V10046 (V + 37984)
+ 0x110d, 0x116b, 0x11b1, 0,
+#undef V10047
+#define V10047 (V + 37988)
+ 0x110d, 0x116b, 0x11b2, 0,
+#undef V10048
+#define V10048 (V + 37992)
+ 0x110d, 0x116b, 0x11b3, 0,
+#undef V10049
+#define V10049 (V + 37996)
+ 0x110d, 0x116b, 0x11b4, 0,
+#undef V10050
+#define V10050 (V + 38000)
+ 0x110d, 0x116b, 0x11b5, 0,
+#undef V10051
+#define V10051 (V + 38004)
+ 0x110d, 0x116b, 0x11b6, 0,
+#undef V10052
+#define V10052 (V + 38008)
+ 0x110d, 0x116b, 0x11b7, 0,
+#undef V10053
+#define V10053 (V + 38012)
+ 0x110d, 0x116b, 0x11b8, 0,
+#undef V10054
+#define V10054 (V + 38016)
+ 0x110d, 0x116b, 0x11b9, 0,
+#undef V10055
+#define V10055 (V + 38020)
+ 0x110d, 0x116b, 0x11ba, 0,
+#undef V10056
+#define V10056 (V + 38024)
+ 0x110d, 0x116b, 0x11bb, 0,
+#undef V10057
+#define V10057 (V + 38028)
+ 0x110d, 0x116b, 0x11bc, 0,
+#undef V10058
+#define V10058 (V + 38032)
+ 0x110d, 0x116b, 0x11bd, 0,
+#undef V10059
+#define V10059 (V + 38036)
+ 0x110d, 0x116b, 0x11be, 0,
+#undef V10060
+#define V10060 (V + 38040)
+ 0x110d, 0x116b, 0x11bf, 0,
+#undef V10061
+#define V10061 (V + 38044)
+ 0x110d, 0x116b, 0x11c0, 0,
+#undef V10062
+#define V10062 (V + 38048)
+ 0x110d, 0x116b, 0x11c1, 0,
+#undef V10063
+#define V10063 (V + 38052)
+ 0x110d, 0x116b, 0x11c2, 0,
+#undef V10064
+#define V10064 (V + 38056)
+ 0x110d, 0x116c, 0,
+#undef V10065
+#define V10065 (V + 38059)
+ 0x110d, 0x116c, 0x11a8, 0,
+#undef V10066
+#define V10066 (V + 38063)
+ 0x110d, 0x116c, 0x11a9, 0,
+#undef V10067
+#define V10067 (V + 38067)
+ 0x110d, 0x116c, 0x11aa, 0,
+#undef V10068
+#define V10068 (V + 38071)
+ 0x110d, 0x116c, 0x11ab, 0,
+#undef V10069
+#define V10069 (V + 38075)
+ 0x110d, 0x116c, 0x11ac, 0,
+#undef V10070
+#define V10070 (V + 38079)
+ 0x110d, 0x116c, 0x11ad, 0,
+#undef V10071
+#define V10071 (V + 38083)
+ 0x110d, 0x116c, 0x11ae, 0,
+#undef V10072
+#define V10072 (V + 38087)
+ 0x110d, 0x116c, 0x11af, 0,
+#undef V10073
+#define V10073 (V + 38091)
+ 0x110d, 0x116c, 0x11b0, 0,
+#undef V10074
+#define V10074 (V + 38095)
+ 0x110d, 0x116c, 0x11b1, 0,
+#undef V10075
+#define V10075 (V + 38099)
+ 0x110d, 0x116c, 0x11b2, 0,
+#undef V10076
+#define V10076 (V + 38103)
+ 0x110d, 0x116c, 0x11b3, 0,
+#undef V10077
+#define V10077 (V + 38107)
+ 0x110d, 0x116c, 0x11b4, 0,
+#undef V10078
+#define V10078 (V + 38111)
+ 0x110d, 0x116c, 0x11b5, 0,
+#undef V10079
+#define V10079 (V + 38115)
+ 0x110d, 0x116c, 0x11b6, 0,
+#undef V10080
+#define V10080 (V + 38119)
+ 0x110d, 0x116c, 0x11b7, 0,
+#undef V10081
+#define V10081 (V + 38123)
+ 0x110d, 0x116c, 0x11b8, 0,
+#undef V10082
+#define V10082 (V + 38127)
+ 0x110d, 0x116c, 0x11b9, 0,
+#undef V10083
+#define V10083 (V + 38131)
+ 0x110d, 0x116c, 0x11ba, 0,
+#undef V10084
+#define V10084 (V + 38135)
+ 0x110d, 0x116c, 0x11bb, 0,
+#undef V10085
+#define V10085 (V + 38139)
+ 0x110d, 0x116c, 0x11bc, 0,
+#undef V10086
+#define V10086 (V + 38143)
+ 0x110d, 0x116c, 0x11bd, 0,
+#undef V10087
+#define V10087 (V + 38147)
+ 0x110d, 0x116c, 0x11be, 0,
+#undef V10088
+#define V10088 (V + 38151)
+ 0x110d, 0x116c, 0x11bf, 0,
+#undef V10089
+#define V10089 (V + 38155)
+ 0x110d, 0x116c, 0x11c0, 0,
+#undef V10090
+#define V10090 (V + 38159)
+ 0x110d, 0x116c, 0x11c1, 0,
+#undef V10091
+#define V10091 (V + 38163)
+ 0x110d, 0x116c, 0x11c2, 0,
+#undef V10092
+#define V10092 (V + 38167)
+ 0x110d, 0x116d, 0,
+#undef V10093
+#define V10093 (V + 38170)
+ 0x110d, 0x116d, 0x11a8, 0,
+#undef V10094
+#define V10094 (V + 38174)
+ 0x110d, 0x116d, 0x11a9, 0,
+#undef V10095
+#define V10095 (V + 38178)
+ 0x110d, 0x116d, 0x11aa, 0,
+#undef V10096
+#define V10096 (V + 38182)
+ 0x110d, 0x116d, 0x11ab, 0,
+#undef V10097
+#define V10097 (V + 38186)
+ 0x110d, 0x116d, 0x11ac, 0,
+#undef V10098
+#define V10098 (V + 38190)
+ 0x110d, 0x116d, 0x11ad, 0,
+#undef V10099
+#define V10099 (V + 38194)
+ 0x110d, 0x116d, 0x11ae, 0,
+#undef V10100
+#define V10100 (V + 38198)
+ 0x110d, 0x116d, 0x11af, 0,
+#undef V10101
+#define V10101 (V + 38202)
+ 0x110d, 0x116d, 0x11b0, 0,
+#undef V10102
+#define V10102 (V + 38206)
+ 0x110d, 0x116d, 0x11b1, 0,
+#undef V10103
+#define V10103 (V + 38210)
+ 0x110d, 0x116d, 0x11b2, 0,
+#undef V10104
+#define V10104 (V + 38214)
+ 0x110d, 0x116d, 0x11b3, 0,
+#undef V10105
+#define V10105 (V + 38218)
+ 0x110d, 0x116d, 0x11b4, 0,
+#undef V10106
+#define V10106 (V + 38222)
+ 0x110d, 0x116d, 0x11b5, 0,
+#undef V10107
+#define V10107 (V + 38226)
+ 0x110d, 0x116d, 0x11b6, 0,
+#undef V10108
+#define V10108 (V + 38230)
+ 0x110d, 0x116d, 0x11b7, 0,
+#undef V10109
+#define V10109 (V + 38234)
+ 0x110d, 0x116d, 0x11b8, 0,
+#undef V10110
+#define V10110 (V + 38238)
+ 0x110d, 0x116d, 0x11b9, 0,
+#undef V10111
+#define V10111 (V + 38242)
+ 0x110d, 0x116d, 0x11ba, 0,
+#undef V10112
+#define V10112 (V + 38246)
+ 0x110d, 0x116d, 0x11bb, 0,
+#undef V10113
+#define V10113 (V + 38250)
+ 0x110d, 0x116d, 0x11bc, 0,
+#undef V10114
+#define V10114 (V + 38254)
+ 0x110d, 0x116d, 0x11bd, 0,
+#undef V10115
+#define V10115 (V + 38258)
+ 0x110d, 0x116d, 0x11be, 0,
+#undef V10116
+#define V10116 (V + 38262)
+ 0x110d, 0x116d, 0x11bf, 0,
+#undef V10117
+#define V10117 (V + 38266)
+ 0x110d, 0x116d, 0x11c0, 0,
+#undef V10118
+#define V10118 (V + 38270)
+ 0x110d, 0x116d, 0x11c1, 0,
+#undef V10119
+#define V10119 (V + 38274)
+ 0x110d, 0x116d, 0x11c2, 0,
+#undef V10120
+#define V10120 (V + 38278)
+ 0x110d, 0x116e, 0,
+#undef V10121
+#define V10121 (V + 38281)
+ 0x110d, 0x116e, 0x11a8, 0,
+#undef V10122
+#define V10122 (V + 38285)
+ 0x110d, 0x116e, 0x11a9, 0,
+#undef V10123
+#define V10123 (V + 38289)
+ 0x110d, 0x116e, 0x11aa, 0,
+#undef V10124
+#define V10124 (V + 38293)
+ 0x110d, 0x116e, 0x11ab, 0,
+#undef V10125
+#define V10125 (V + 38297)
+ 0x110d, 0x116e, 0x11ac, 0,
+#undef V10126
+#define V10126 (V + 38301)
+ 0x110d, 0x116e, 0x11ad, 0,
+#undef V10127
+#define V10127 (V + 38305)
+ 0x110d, 0x116e, 0x11ae, 0,
+#undef V10128
+#define V10128 (V + 38309)
+ 0x110d, 0x116e, 0x11af, 0,
+#undef V10129
+#define V10129 (V + 38313)
+ 0x110d, 0x116e, 0x11b0, 0,
+#undef V10130
+#define V10130 (V + 38317)
+ 0x110d, 0x116e, 0x11b1, 0,
+#undef V10131
+#define V10131 (V + 38321)
+ 0x110d, 0x116e, 0x11b2, 0,
+#undef V10132
+#define V10132 (V + 38325)
+ 0x110d, 0x116e, 0x11b3, 0,
+#undef V10133
+#define V10133 (V + 38329)
+ 0x110d, 0x116e, 0x11b4, 0,
+#undef V10134
+#define V10134 (V + 38333)
+ 0x110d, 0x116e, 0x11b5, 0,
+#undef V10135
+#define V10135 (V + 38337)
+ 0x110d, 0x116e, 0x11b6, 0,
+#undef V10136
+#define V10136 (V + 38341)
+ 0x110d, 0x116e, 0x11b7, 0,
+#undef V10137
+#define V10137 (V + 38345)
+ 0x110d, 0x116e, 0x11b8, 0,
+#undef V10138
+#define V10138 (V + 38349)
+ 0x110d, 0x116e, 0x11b9, 0,
+#undef V10139
+#define V10139 (V + 38353)
+ 0x110d, 0x116e, 0x11ba, 0,
+#undef V10140
+#define V10140 (V + 38357)
+ 0x110d, 0x116e, 0x11bb, 0,
+#undef V10141
+#define V10141 (V + 38361)
+ 0x110d, 0x116e, 0x11bc, 0,
+#undef V10142
+#define V10142 (V + 38365)
+ 0x110d, 0x116e, 0x11bd, 0,
+#undef V10143
+#define V10143 (V + 38369)
+ 0x110d, 0x116e, 0x11be, 0,
+#undef V10144
+#define V10144 (V + 38373)
+ 0x110d, 0x116e, 0x11bf, 0,
+#undef V10145
+#define V10145 (V + 38377)
+ 0x110d, 0x116e, 0x11c0, 0,
+#undef V10146
+#define V10146 (V + 38381)
+ 0x110d, 0x116e, 0x11c1, 0,
+#undef V10147
+#define V10147 (V + 38385)
+ 0x110d, 0x116e, 0x11c2, 0,
+#undef V10148
+#define V10148 (V + 38389)
+ 0x110d, 0x116f, 0,
+#undef V10149
+#define V10149 (V + 38392)
+ 0x110d, 0x116f, 0x11a8, 0,
+#undef V10150
+#define V10150 (V + 38396)
+ 0x110d, 0x116f, 0x11a9, 0,
+#undef V10151
+#define V10151 (V + 38400)
+ 0x110d, 0x116f, 0x11aa, 0,
+#undef V10152
+#define V10152 (V + 38404)
+ 0x110d, 0x116f, 0x11ab, 0,
+#undef V10153
+#define V10153 (V + 38408)
+ 0x110d, 0x116f, 0x11ac, 0,
+#undef V10154
+#define V10154 (V + 38412)
+ 0x110d, 0x116f, 0x11ad, 0,
+#undef V10155
+#define V10155 (V + 38416)
+ 0x110d, 0x116f, 0x11ae, 0,
+#undef V10156
+#define V10156 (V + 38420)
+ 0x110d, 0x116f, 0x11af, 0,
+#undef V10157
+#define V10157 (V + 38424)
+ 0x110d, 0x116f, 0x11b0, 0,
+#undef V10158
+#define V10158 (V + 38428)
+ 0x110d, 0x116f, 0x11b1, 0,
+#undef V10159
+#define V10159 (V + 38432)
+ 0x110d, 0x116f, 0x11b2, 0,
+#undef V10160
+#define V10160 (V + 38436)
+ 0x110d, 0x116f, 0x11b3, 0,
+#undef V10161
+#define V10161 (V + 38440)
+ 0x110d, 0x116f, 0x11b4, 0,
+#undef V10162
+#define V10162 (V + 38444)
+ 0x110d, 0x116f, 0x11b5, 0,
+#undef V10163
+#define V10163 (V + 38448)
+ 0x110d, 0x116f, 0x11b6, 0,
+#undef V10164
+#define V10164 (V + 38452)
+ 0x110d, 0x116f, 0x11b7, 0,
+#undef V10165
+#define V10165 (V + 38456)
+ 0x110d, 0x116f, 0x11b8, 0,
+#undef V10166
+#define V10166 (V + 38460)
+ 0x110d, 0x116f, 0x11b9, 0,
+#undef V10167
+#define V10167 (V + 38464)
+ 0x110d, 0x116f, 0x11ba, 0,
+#undef V10168
+#define V10168 (V + 38468)
+ 0x110d, 0x116f, 0x11bb, 0,
+#undef V10169
+#define V10169 (V + 38472)
+ 0x110d, 0x116f, 0x11bc, 0,
+#undef V10170
+#define V10170 (V + 38476)
+ 0x110d, 0x116f, 0x11bd, 0,
+#undef V10171
+#define V10171 (V + 38480)
+ 0x110d, 0x116f, 0x11be, 0,
+#undef V10172
+#define V10172 (V + 38484)
+ 0x110d, 0x116f, 0x11bf, 0,
+#undef V10173
+#define V10173 (V + 38488)
+ 0x110d, 0x116f, 0x11c0, 0,
+#undef V10174
+#define V10174 (V + 38492)
+ 0x110d, 0x116f, 0x11c1, 0,
+#undef V10175
+#define V10175 (V + 38496)
+ 0x110d, 0x116f, 0x11c2, 0,
+#undef V10176
+#define V10176 (V + 38500)
+ 0x110d, 0x1170, 0,
+#undef V10177
+#define V10177 (V + 38503)
+ 0x110d, 0x1170, 0x11a8, 0,
+#undef V10178
+#define V10178 (V + 38507)
+ 0x110d, 0x1170, 0x11a9, 0,
+#undef V10179
+#define V10179 (V + 38511)
+ 0x110d, 0x1170, 0x11aa, 0,
+#undef V10180
+#define V10180 (V + 38515)
+ 0x110d, 0x1170, 0x11ab, 0,
+#undef V10181
+#define V10181 (V + 38519)
+ 0x110d, 0x1170, 0x11ac, 0,
+#undef V10182
+#define V10182 (V + 38523)
+ 0x110d, 0x1170, 0x11ad, 0,
+#undef V10183
+#define V10183 (V + 38527)
+ 0x110d, 0x1170, 0x11ae, 0,
+#undef V10184
+#define V10184 (V + 38531)
+ 0x110d, 0x1170, 0x11af, 0,
+#undef V10185
+#define V10185 (V + 38535)
+ 0x110d, 0x1170, 0x11b0, 0,
+#undef V10186
+#define V10186 (V + 38539)
+ 0x110d, 0x1170, 0x11b1, 0,
+#undef V10187
+#define V10187 (V + 38543)
+ 0x110d, 0x1170, 0x11b2, 0,
+#undef V10188
+#define V10188 (V + 38547)
+ 0x110d, 0x1170, 0x11b3, 0,
+#undef V10189
+#define V10189 (V + 38551)
+ 0x110d, 0x1170, 0x11b4, 0,
+#undef V10190
+#define V10190 (V + 38555)
+ 0x110d, 0x1170, 0x11b5, 0,
+#undef V10191
+#define V10191 (V + 38559)
+ 0x110d, 0x1170, 0x11b6, 0,
+#undef V10192
+#define V10192 (V + 38563)
+ 0x110d, 0x1170, 0x11b7, 0,
+#undef V10193
+#define V10193 (V + 38567)
+ 0x110d, 0x1170, 0x11b8, 0,
+#undef V10194
+#define V10194 (V + 38571)
+ 0x110d, 0x1170, 0x11b9, 0,
+#undef V10195
+#define V10195 (V + 38575)
+ 0x110d, 0x1170, 0x11ba, 0,
+#undef V10196
+#define V10196 (V + 38579)
+ 0x110d, 0x1170, 0x11bb, 0,
+#undef V10197
+#define V10197 (V + 38583)
+ 0x110d, 0x1170, 0x11bc, 0,
+#undef V10198
+#define V10198 (V + 38587)
+ 0x110d, 0x1170, 0x11bd, 0,
+#undef V10199
+#define V10199 (V + 38591)
+ 0x110d, 0x1170, 0x11be, 0,
+#undef V10200
+#define V10200 (V + 38595)
+ 0x110d, 0x1170, 0x11bf, 0,
+#undef V10201
+#define V10201 (V + 38599)
+ 0x110d, 0x1170, 0x11c0, 0,
+#undef V10202
+#define V10202 (V + 38603)
+ 0x110d, 0x1170, 0x11c1, 0,
+#undef V10203
+#define V10203 (V + 38607)
+ 0x110d, 0x1170, 0x11c2, 0,
+#undef V10204
+#define V10204 (V + 38611)
+ 0x110d, 0x1171, 0,
+#undef V10205
+#define V10205 (V + 38614)
+ 0x110d, 0x1171, 0x11a8, 0,
+#undef V10206
+#define V10206 (V + 38618)
+ 0x110d, 0x1171, 0x11a9, 0,
+#undef V10207
+#define V10207 (V + 38622)
+ 0x110d, 0x1171, 0x11aa, 0,
+#undef V10208
+#define V10208 (V + 38626)
+ 0x110d, 0x1171, 0x11ab, 0,
+#undef V10209
+#define V10209 (V + 38630)
+ 0x110d, 0x1171, 0x11ac, 0,
+#undef V10210
+#define V10210 (V + 38634)
+ 0x110d, 0x1171, 0x11ad, 0,
+#undef V10211
+#define V10211 (V + 38638)
+ 0x110d, 0x1171, 0x11ae, 0,
+#undef V10212
+#define V10212 (V + 38642)
+ 0x110d, 0x1171, 0x11af, 0,
+#undef V10213
+#define V10213 (V + 38646)
+ 0x110d, 0x1171, 0x11b0, 0,
+#undef V10214
+#define V10214 (V + 38650)
+ 0x110d, 0x1171, 0x11b1, 0,
+#undef V10215
+#define V10215 (V + 38654)
+ 0x110d, 0x1171, 0x11b2, 0,
+#undef V10216
+#define V10216 (V + 38658)
+ 0x110d, 0x1171, 0x11b3, 0,
+#undef V10217
+#define V10217 (V + 38662)
+ 0x110d, 0x1171, 0x11b4, 0,
+#undef V10218
+#define V10218 (V + 38666)
+ 0x110d, 0x1171, 0x11b5, 0,
+#undef V10219
+#define V10219 (V + 38670)
+ 0x110d, 0x1171, 0x11b6, 0,
+#undef V10220
+#define V10220 (V + 38674)
+ 0x110d, 0x1171, 0x11b7, 0,
+#undef V10221
+#define V10221 (V + 38678)
+ 0x110d, 0x1171, 0x11b8, 0,
+#undef V10222
+#define V10222 (V + 38682)
+ 0x110d, 0x1171, 0x11b9, 0,
+#undef V10223
+#define V10223 (V + 38686)
+ 0x110d, 0x1171, 0x11ba, 0,
+#undef V10224
+#define V10224 (V + 38690)
+ 0x110d, 0x1171, 0x11bb, 0,
+#undef V10225
+#define V10225 (V + 38694)
+ 0x110d, 0x1171, 0x11bc, 0,
+#undef V10226
+#define V10226 (V + 38698)
+ 0x110d, 0x1171, 0x11bd, 0,
+#undef V10227
+#define V10227 (V + 38702)
+ 0x110d, 0x1171, 0x11be, 0,
+#undef V10228
+#define V10228 (V + 38706)
+ 0x110d, 0x1171, 0x11bf, 0,
+#undef V10229
+#define V10229 (V + 38710)
+ 0x110d, 0x1171, 0x11c0, 0,
+#undef V10230
+#define V10230 (V + 38714)
+ 0x110d, 0x1171, 0x11c1, 0,
+#undef V10231
+#define V10231 (V + 38718)
+ 0x110d, 0x1171, 0x11c2, 0,
+#undef V10232
+#define V10232 (V + 38722)
+ 0x110d, 0x1172, 0,
+#undef V10233
+#define V10233 (V + 38725)
+ 0x110d, 0x1172, 0x11a8, 0,
+#undef V10234
+#define V10234 (V + 38729)
+ 0x110d, 0x1172, 0x11a9, 0,
+#undef V10235
+#define V10235 (V + 38733)
+ 0x110d, 0x1172, 0x11aa, 0,
+#undef V10236
+#define V10236 (V + 38737)
+ 0x110d, 0x1172, 0x11ab, 0,
+#undef V10237
+#define V10237 (V + 38741)
+ 0x110d, 0x1172, 0x11ac, 0,
+#undef V10238
+#define V10238 (V + 38745)
+ 0x110d, 0x1172, 0x11ad, 0,
+#undef V10239
+#define V10239 (V + 38749)
+ 0x110d, 0x1172, 0x11ae, 0,
+#undef V10240
+#define V10240 (V + 38753)
+ 0x110d, 0x1172, 0x11af, 0,
+#undef V10241
+#define V10241 (V + 38757)
+ 0x110d, 0x1172, 0x11b0, 0,
+#undef V10242
+#define V10242 (V + 38761)
+ 0x110d, 0x1172, 0x11b1, 0,
+#undef V10243
+#define V10243 (V + 38765)
+ 0x110d, 0x1172, 0x11b2, 0,
+#undef V10244
+#define V10244 (V + 38769)
+ 0x110d, 0x1172, 0x11b3, 0,
+#undef V10245
+#define V10245 (V + 38773)
+ 0x110d, 0x1172, 0x11b4, 0,
+#undef V10246
+#define V10246 (V + 38777)
+ 0x110d, 0x1172, 0x11b5, 0,
+#undef V10247
+#define V10247 (V + 38781)
+ 0x110d, 0x1172, 0x11b6, 0,
+#undef V10248
+#define V10248 (V + 38785)
+ 0x110d, 0x1172, 0x11b7, 0,
+#undef V10249
+#define V10249 (V + 38789)
+ 0x110d, 0x1172, 0x11b8, 0,
+#undef V10250
+#define V10250 (V + 38793)
+ 0x110d, 0x1172, 0x11b9, 0,
+#undef V10251
+#define V10251 (V + 38797)
+ 0x110d, 0x1172, 0x11ba, 0,
+#undef V10252
+#define V10252 (V + 38801)
+ 0x110d, 0x1172, 0x11bb, 0,
+#undef V10253
+#define V10253 (V + 38805)
+ 0x110d, 0x1172, 0x11bc, 0,
+#undef V10254
+#define V10254 (V + 38809)
+ 0x110d, 0x1172, 0x11bd, 0,
+#undef V10255
+#define V10255 (V + 38813)
+ 0x110d, 0x1172, 0x11be, 0,
+#undef V10256
+#define V10256 (V + 38817)
+ 0x110d, 0x1172, 0x11bf, 0,
+#undef V10257
+#define V10257 (V + 38821)
+ 0x110d, 0x1172, 0x11c0, 0,
+#undef V10258
+#define V10258 (V + 38825)
+ 0x110d, 0x1172, 0x11c1, 0,
+#undef V10259
+#define V10259 (V + 38829)
+ 0x110d, 0x1172, 0x11c2, 0,
+#undef V10260
+#define V10260 (V + 38833)
+ 0x110d, 0x1173, 0,
+#undef V10261
+#define V10261 (V + 38836)
+ 0x110d, 0x1173, 0x11a8, 0,
+#undef V10262
+#define V10262 (V + 38840)
+ 0x110d, 0x1173, 0x11a9, 0,
+#undef V10263
+#define V10263 (V + 38844)
+ 0x110d, 0x1173, 0x11aa, 0,
+#undef V10264
+#define V10264 (V + 38848)
+ 0x110d, 0x1173, 0x11ab, 0,
+#undef V10265
+#define V10265 (V + 38852)
+ 0x110d, 0x1173, 0x11ac, 0,
+#undef V10266
+#define V10266 (V + 38856)
+ 0x110d, 0x1173, 0x11ad, 0,
+#undef V10267
+#define V10267 (V + 38860)
+ 0x110d, 0x1173, 0x11ae, 0,
+#undef V10268
+#define V10268 (V + 38864)
+ 0x110d, 0x1173, 0x11af, 0,
+#undef V10269
+#define V10269 (V + 38868)
+ 0x110d, 0x1173, 0x11b0, 0,
+#undef V10270
+#define V10270 (V + 38872)
+ 0x110d, 0x1173, 0x11b1, 0,
+#undef V10271
+#define V10271 (V + 38876)
+ 0x110d, 0x1173, 0x11b2, 0,
+#undef V10272
+#define V10272 (V + 38880)
+ 0x110d, 0x1173, 0x11b3, 0,
+#undef V10273
+#define V10273 (V + 38884)
+ 0x110d, 0x1173, 0x11b4, 0,
+#undef V10274
+#define V10274 (V + 38888)
+ 0x110d, 0x1173, 0x11b5, 0,
+#undef V10275
+#define V10275 (V + 38892)
+ 0x110d, 0x1173, 0x11b6, 0,
+#undef V10276
+#define V10276 (V + 38896)
+ 0x110d, 0x1173, 0x11b7, 0,
+#undef V10277
+#define V10277 (V + 38900)
+ 0x110d, 0x1173, 0x11b8, 0,
+#undef V10278
+#define V10278 (V + 38904)
+ 0x110d, 0x1173, 0x11b9, 0,
+#undef V10279
+#define V10279 (V + 38908)
+ 0x110d, 0x1173, 0x11ba, 0,
+#undef V10280
+#define V10280 (V + 38912)
+ 0x110d, 0x1173, 0x11bb, 0,
+#undef V10281
+#define V10281 (V + 38916)
+ 0x110d, 0x1173, 0x11bc, 0,
+#undef V10282
+#define V10282 (V + 38920)
+ 0x110d, 0x1173, 0x11bd, 0,
+#undef V10283
+#define V10283 (V + 38924)
+ 0x110d, 0x1173, 0x11be, 0,
+#undef V10284
+#define V10284 (V + 38928)
+ 0x110d, 0x1173, 0x11bf, 0,
+#undef V10285
+#define V10285 (V + 38932)
+ 0x110d, 0x1173, 0x11c0, 0,
+#undef V10286
+#define V10286 (V + 38936)
+ 0x110d, 0x1173, 0x11c1, 0,
+#undef V10287
+#define V10287 (V + 38940)
+ 0x110d, 0x1173, 0x11c2, 0,
+#undef V10288
+#define V10288 (V + 38944)
+ 0x110d, 0x1174, 0,
+#undef V10289
+#define V10289 (V + 38947)
+ 0x110d, 0x1174, 0x11a8, 0,
+#undef V10290
+#define V10290 (V + 38951)
+ 0x110d, 0x1174, 0x11a9, 0,
+#undef V10291
+#define V10291 (V + 38955)
+ 0x110d, 0x1174, 0x11aa, 0,
+#undef V10292
+#define V10292 (V + 38959)
+ 0x110d, 0x1174, 0x11ab, 0,
+#undef V10293
+#define V10293 (V + 38963)
+ 0x110d, 0x1174, 0x11ac, 0,
+#undef V10294
+#define V10294 (V + 38967)
+ 0x110d, 0x1174, 0x11ad, 0,
+#undef V10295
+#define V10295 (V + 38971)
+ 0x110d, 0x1174, 0x11ae, 0,
+#undef V10296
+#define V10296 (V + 38975)
+ 0x110d, 0x1174, 0x11af, 0,
+#undef V10297
+#define V10297 (V + 38979)
+ 0x110d, 0x1174, 0x11b0, 0,
+#undef V10298
+#define V10298 (V + 38983)
+ 0x110d, 0x1174, 0x11b1, 0,
+#undef V10299
+#define V10299 (V + 38987)
+ 0x110d, 0x1174, 0x11b2, 0,
+#undef V10300
+#define V10300 (V + 38991)
+ 0x110d, 0x1174, 0x11b3, 0,
+#undef V10301
+#define V10301 (V + 38995)
+ 0x110d, 0x1174, 0x11b4, 0,
+#undef V10302
+#define V10302 (V + 38999)
+ 0x110d, 0x1174, 0x11b5, 0,
+#undef V10303
+#define V10303 (V + 39003)
+ 0x110d, 0x1174, 0x11b6, 0,
+#undef V10304
+#define V10304 (V + 39007)
+ 0x110d, 0x1174, 0x11b7, 0,
+#undef V10305
+#define V10305 (V + 39011)
+ 0x110d, 0x1174, 0x11b8, 0,
+#undef V10306
+#define V10306 (V + 39015)
+ 0x110d, 0x1174, 0x11b9, 0,
+#undef V10307
+#define V10307 (V + 39019)
+ 0x110d, 0x1174, 0x11ba, 0,
+#undef V10308
+#define V10308 (V + 39023)
+ 0x110d, 0x1174, 0x11bb, 0,
+#undef V10309
+#define V10309 (V + 39027)
+ 0x110d, 0x1174, 0x11bc, 0,
+#undef V10310
+#define V10310 (V + 39031)
+ 0x110d, 0x1174, 0x11bd, 0,
+#undef V10311
+#define V10311 (V + 39035)
+ 0x110d, 0x1174, 0x11be, 0,
+#undef V10312
+#define V10312 (V + 39039)
+ 0x110d, 0x1174, 0x11bf, 0,
+#undef V10313
+#define V10313 (V + 39043)
+ 0x110d, 0x1174, 0x11c0, 0,
+#undef V10314
+#define V10314 (V + 39047)
+ 0x110d, 0x1174, 0x11c1, 0,
+#undef V10315
+#define V10315 (V + 39051)
+ 0x110d, 0x1174, 0x11c2, 0,
+#undef V10316
+#define V10316 (V + 39055)
+ 0x110d, 0x1175, 0,
+#undef V10317
+#define V10317 (V + 39058)
+ 0x110d, 0x1175, 0x11a8, 0,
+#undef V10318
+#define V10318 (V + 39062)
+ 0x110d, 0x1175, 0x11a9, 0,
+#undef V10319
+#define V10319 (V + 39066)
+ 0x110d, 0x1175, 0x11aa, 0,
+#undef V10320
+#define V10320 (V + 39070)
+ 0x110d, 0x1175, 0x11ab, 0,
+#undef V10321
+#define V10321 (V + 39074)
+ 0x110d, 0x1175, 0x11ac, 0,
+#undef V10322
+#define V10322 (V + 39078)
+ 0x110d, 0x1175, 0x11ad, 0,
+#undef V10323
+#define V10323 (V + 39082)
+ 0x110d, 0x1175, 0x11ae, 0,
+#undef V10324
+#define V10324 (V + 39086)
+ 0x110d, 0x1175, 0x11af, 0,
+#undef V10325
+#define V10325 (V + 39090)
+ 0x110d, 0x1175, 0x11b0, 0,
+#undef V10326
+#define V10326 (V + 39094)
+ 0x110d, 0x1175, 0x11b1, 0,
+#undef V10327
+#define V10327 (V + 39098)
+ 0x110d, 0x1175, 0x11b2, 0,
+#undef V10328
+#define V10328 (V + 39102)
+ 0x110d, 0x1175, 0x11b3, 0,
+#undef V10329
+#define V10329 (V + 39106)
+ 0x110d, 0x1175, 0x11b4, 0,
+#undef V10330
+#define V10330 (V + 39110)
+ 0x110d, 0x1175, 0x11b5, 0,
+#undef V10331
+#define V10331 (V + 39114)
+ 0x110d, 0x1175, 0x11b6, 0,
+#undef V10332
+#define V10332 (V + 39118)
+ 0x110d, 0x1175, 0x11b7, 0,
+#undef V10333
+#define V10333 (V + 39122)
+ 0x110d, 0x1175, 0x11b8, 0,
+#undef V10334
+#define V10334 (V + 39126)
+ 0x110d, 0x1175, 0x11b9, 0,
+#undef V10335
+#define V10335 (V + 39130)
+ 0x110d, 0x1175, 0x11ba, 0,
+#undef V10336
+#define V10336 (V + 39134)
+ 0x110d, 0x1175, 0x11bb, 0,
+#undef V10337
+#define V10337 (V + 39138)
+ 0x110d, 0x1175, 0x11bc, 0,
+#undef V10338
+#define V10338 (V + 39142)
+ 0x110d, 0x1175, 0x11bd, 0,
+#undef V10339
+#define V10339 (V + 39146)
+ 0x110d, 0x1175, 0x11be, 0,
+#undef V10340
+#define V10340 (V + 39150)
+ 0x110d, 0x1175, 0x11bf, 0,
+#undef V10341
+#define V10341 (V + 39154)
+ 0x110d, 0x1175, 0x11c0, 0,
+#undef V10342
+#define V10342 (V + 39158)
+ 0x110d, 0x1175, 0x11c1, 0,
+#undef V10343
+#define V10343 (V + 39162)
+ 0x110d, 0x1175, 0x11c2, 0,
+#undef V10344
+#define V10344 (V + 39166)
+ 0x110e, 0x1161, 0x11a8, 0,
+#undef V10345
+#define V10345 (V + 39170)
+ 0x110e, 0x1161, 0x11a9, 0,
+#undef V10346
+#define V10346 (V + 39174)
+ 0x110e, 0x1161, 0x11aa, 0,
+#undef V10347
+#define V10347 (V + 39178)
+ 0x110e, 0x1161, 0x11ab, 0,
+#undef V10348
+#define V10348 (V + 39182)
+ 0x110e, 0x1161, 0x11ac, 0,
+#undef V10349
+#define V10349 (V + 39186)
+ 0x110e, 0x1161, 0x11ad, 0,
+#undef V10350
+#define V10350 (V + 39190)
+ 0x110e, 0x1161, 0x11ae, 0,
+#undef V10351
+#define V10351 (V + 39194)
+ 0x110e, 0x1161, 0x11af, 0,
+#undef V10352
+#define V10352 (V + 39198)
+ 0x110e, 0x1161, 0x11b0, 0,
+#undef V10353
+#define V10353 (V + 39202)
+ 0x110e, 0x1161, 0x11b1, 0,
+#undef V10354
+#define V10354 (V + 39206)
+ 0x110e, 0x1161, 0x11b2, 0,
+#undef V10355
+#define V10355 (V + 39210)
+ 0x110e, 0x1161, 0x11b3, 0,
+#undef V10356
+#define V10356 (V + 39214)
+ 0x110e, 0x1161, 0x11b4, 0,
+#undef V10357
+#define V10357 (V + 39218)
+ 0x110e, 0x1161, 0x11b5, 0,
+#undef V10358
+#define V10358 (V + 39222)
+ 0x110e, 0x1161, 0x11b6, 0,
+#undef V10359
+#define V10359 (V + 39226)
+ 0x110e, 0x1161, 0x11b7, 0,
+#undef V10360
+#define V10360 (V + 39230)
+ 0x110e, 0x1161, 0x11b8, 0,
+#undef V10361
+#define V10361 (V + 39234)
+ 0x110e, 0x1161, 0x11b9, 0,
+#undef V10362
+#define V10362 (V + 39238)
+ 0x110e, 0x1161, 0x11ba, 0,
+#undef V10363
+#define V10363 (V + 39242)
+ 0x110e, 0x1161, 0x11bb, 0,
+#undef V10364
+#define V10364 (V + 39246)
+ 0x110e, 0x1161, 0x11bc, 0,
+#undef V10365
+#define V10365 (V + 39250)
+ 0x110e, 0x1161, 0x11bd, 0,
+#undef V10366
+#define V10366 (V + 39254)
+ 0x110e, 0x1161, 0x11be, 0,
+#undef V10367
+#define V10367 (V + 39258)
+ 0x110e, 0x1161, 0x11bf, 0,
+#undef V10368
+#define V10368 (V + 39262)
+ 0x110e, 0x1161, 0x11c0, 0,
+#undef V10369
+#define V10369 (V + 39266)
+ 0x110e, 0x1161, 0x11c1, 0,
+#undef V10370
+#define V10370 (V + 39270)
+ 0x110e, 0x1161, 0x11c2, 0,
+#undef V10371
+#define V10371 (V + 39274)
+ 0x110e, 0x1162, 0,
+#undef V10372
+#define V10372 (V + 39277)
+ 0x110e, 0x1162, 0x11a8, 0,
+#undef V10373
+#define V10373 (V + 39281)
+ 0x110e, 0x1162, 0x11a9, 0,
+#undef V10374
+#define V10374 (V + 39285)
+ 0x110e, 0x1162, 0x11aa, 0,
+#undef V10375
+#define V10375 (V + 39289)
+ 0x110e, 0x1162, 0x11ab, 0,
+#undef V10376
+#define V10376 (V + 39293)
+ 0x110e, 0x1162, 0x11ac, 0,
+#undef V10377
+#define V10377 (V + 39297)
+ 0x110e, 0x1162, 0x11ad, 0,
+#undef V10378
+#define V10378 (V + 39301)
+ 0x110e, 0x1162, 0x11ae, 0,
+#undef V10379
+#define V10379 (V + 39305)
+ 0x110e, 0x1162, 0x11af, 0,
+#undef V10380
+#define V10380 (V + 39309)
+ 0x110e, 0x1162, 0x11b0, 0,
+#undef V10381
+#define V10381 (V + 39313)
+ 0x110e, 0x1162, 0x11b1, 0,
+#undef V10382
+#define V10382 (V + 39317)
+ 0x110e, 0x1162, 0x11b2, 0,
+#undef V10383
+#define V10383 (V + 39321)
+ 0x110e, 0x1162, 0x11b3, 0,
+#undef V10384
+#define V10384 (V + 39325)
+ 0x110e, 0x1162, 0x11b4, 0,
+#undef V10385
+#define V10385 (V + 39329)
+ 0x110e, 0x1162, 0x11b5, 0,
+#undef V10386
+#define V10386 (V + 39333)
+ 0x110e, 0x1162, 0x11b6, 0,
+#undef V10387
+#define V10387 (V + 39337)
+ 0x110e, 0x1162, 0x11b7, 0,
+#undef V10388
+#define V10388 (V + 39341)
+ 0x110e, 0x1162, 0x11b8, 0,
+#undef V10389
+#define V10389 (V + 39345)
+ 0x110e, 0x1162, 0x11b9, 0,
+#undef V10390
+#define V10390 (V + 39349)
+ 0x110e, 0x1162, 0x11ba, 0,
+#undef V10391
+#define V10391 (V + 39353)
+ 0x110e, 0x1162, 0x11bb, 0,
+#undef V10392
+#define V10392 (V + 39357)
+ 0x110e, 0x1162, 0x11bc, 0,
+#undef V10393
+#define V10393 (V + 39361)
+ 0x110e, 0x1162, 0x11bd, 0,
+#undef V10394
+#define V10394 (V + 39365)
+ 0x110e, 0x1162, 0x11be, 0,
+#undef V10395
+#define V10395 (V + 39369)
+ 0x110e, 0x1162, 0x11bf, 0,
+#undef V10396
+#define V10396 (V + 39373)
+ 0x110e, 0x1162, 0x11c0, 0,
+#undef V10397
+#define V10397 (V + 39377)
+ 0x110e, 0x1162, 0x11c1, 0,
+#undef V10398
+#define V10398 (V + 39381)
+ 0x110e, 0x1162, 0x11c2, 0,
+#undef V10399
+#define V10399 (V + 39385)
+ 0x110e, 0x1163, 0,
+#undef V10400
+#define V10400 (V + 39388)
+ 0x110e, 0x1163, 0x11a8, 0,
+#undef V10401
+#define V10401 (V + 39392)
+ 0x110e, 0x1163, 0x11a9, 0,
+#undef V10402
+#define V10402 (V + 39396)
+ 0x110e, 0x1163, 0x11aa, 0,
+#undef V10403
+#define V10403 (V + 39400)
+ 0x110e, 0x1163, 0x11ab, 0,
+#undef V10404
+#define V10404 (V + 39404)
+ 0x110e, 0x1163, 0x11ac, 0,
+#undef V10405
+#define V10405 (V + 39408)
+ 0x110e, 0x1163, 0x11ad, 0,
+#undef V10406
+#define V10406 (V + 39412)
+ 0x110e, 0x1163, 0x11ae, 0,
+#undef V10407
+#define V10407 (V + 39416)
+ 0x110e, 0x1163, 0x11af, 0,
+#undef V10408
+#define V10408 (V + 39420)
+ 0x110e, 0x1163, 0x11b0, 0,
+#undef V10409
+#define V10409 (V + 39424)
+ 0x110e, 0x1163, 0x11b1, 0,
+#undef V10410
+#define V10410 (V + 39428)
+ 0x110e, 0x1163, 0x11b2, 0,
+#undef V10411
+#define V10411 (V + 39432)
+ 0x110e, 0x1163, 0x11b3, 0,
+#undef V10412
+#define V10412 (V + 39436)
+ 0x110e, 0x1163, 0x11b4, 0,
+#undef V10413
+#define V10413 (V + 39440)
+ 0x110e, 0x1163, 0x11b5, 0,
+#undef V10414
+#define V10414 (V + 39444)
+ 0x110e, 0x1163, 0x11b6, 0,
+#undef V10415
+#define V10415 (V + 39448)
+ 0x110e, 0x1163, 0x11b7, 0,
+#undef V10416
+#define V10416 (V + 39452)
+ 0x110e, 0x1163, 0x11b8, 0,
+#undef V10417
+#define V10417 (V + 39456)
+ 0x110e, 0x1163, 0x11b9, 0,
+#undef V10418
+#define V10418 (V + 39460)
+ 0x110e, 0x1163, 0x11ba, 0,
+#undef V10419
+#define V10419 (V + 39464)
+ 0x110e, 0x1163, 0x11bb, 0,
+#undef V10420
+#define V10420 (V + 39468)
+ 0x110e, 0x1163, 0x11bc, 0,
+#undef V10421
+#define V10421 (V + 39472)
+ 0x110e, 0x1163, 0x11bd, 0,
+#undef V10422
+#define V10422 (V + 39476)
+ 0x110e, 0x1163, 0x11be, 0,
+#undef V10423
+#define V10423 (V + 39480)
+ 0x110e, 0x1163, 0x11bf, 0,
+#undef V10424
+#define V10424 (V + 39484)
+ 0x110e, 0x1163, 0x11c0, 0,
+#undef V10425
+#define V10425 (V + 39488)
+ 0x110e, 0x1163, 0x11c1, 0,
+#undef V10426
+#define V10426 (V + 39492)
+ 0x110e, 0x1163, 0x11c2, 0,
+#undef V10427
+#define V10427 (V + 39496)
+ 0x110e, 0x1164, 0,
+#undef V10428
+#define V10428 (V + 39499)
+ 0x110e, 0x1164, 0x11a8, 0,
+#undef V10429
+#define V10429 (V + 39503)
+ 0x110e, 0x1164, 0x11a9, 0,
+#undef V10430
+#define V10430 (V + 39507)
+ 0x110e, 0x1164, 0x11aa, 0,
+#undef V10431
+#define V10431 (V + 39511)
+ 0x110e, 0x1164, 0x11ab, 0,
+#undef V10432
+#define V10432 (V + 39515)
+ 0x110e, 0x1164, 0x11ac, 0,
+#undef V10433
+#define V10433 (V + 39519)
+ 0x110e, 0x1164, 0x11ad, 0,
+#undef V10434
+#define V10434 (V + 39523)
+ 0x110e, 0x1164, 0x11ae, 0,
+#undef V10435
+#define V10435 (V + 39527)
+ 0x110e, 0x1164, 0x11af, 0,
+#undef V10436
+#define V10436 (V + 39531)
+ 0x110e, 0x1164, 0x11b0, 0,
+#undef V10437
+#define V10437 (V + 39535)
+ 0x110e, 0x1164, 0x11b1, 0,
+#undef V10438
+#define V10438 (V + 39539)
+ 0x110e, 0x1164, 0x11b2, 0,
+#undef V10439
+#define V10439 (V + 39543)
+ 0x110e, 0x1164, 0x11b3, 0,
+#undef V10440
+#define V10440 (V + 39547)
+ 0x110e, 0x1164, 0x11b4, 0,
+#undef V10441
+#define V10441 (V + 39551)
+ 0x110e, 0x1164, 0x11b5, 0,
+#undef V10442
+#define V10442 (V + 39555)
+ 0x110e, 0x1164, 0x11b6, 0,
+#undef V10443
+#define V10443 (V + 39559)
+ 0x110e, 0x1164, 0x11b7, 0,
+#undef V10444
+#define V10444 (V + 39563)
+ 0x110e, 0x1164, 0x11b8, 0,
+#undef V10445
+#define V10445 (V + 39567)
+ 0x110e, 0x1164, 0x11b9, 0,
+#undef V10446
+#define V10446 (V + 39571)
+ 0x110e, 0x1164, 0x11ba, 0,
+#undef V10447
+#define V10447 (V + 39575)
+ 0x110e, 0x1164, 0x11bb, 0,
+#undef V10448
+#define V10448 (V + 39579)
+ 0x110e, 0x1164, 0x11bc, 0,
+#undef V10449
+#define V10449 (V + 39583)
+ 0x110e, 0x1164, 0x11bd, 0,
+#undef V10450
+#define V10450 (V + 39587)
+ 0x110e, 0x1164, 0x11be, 0,
+#undef V10451
+#define V10451 (V + 39591)
+ 0x110e, 0x1164, 0x11bf, 0,
+#undef V10452
+#define V10452 (V + 39595)
+ 0x110e, 0x1164, 0x11c0, 0,
+#undef V10453
+#define V10453 (V + 39599)
+ 0x110e, 0x1164, 0x11c1, 0,
+#undef V10454
+#define V10454 (V + 39603)
+ 0x110e, 0x1164, 0x11c2, 0,
+#undef V10455
+#define V10455 (V + 39607)
+ 0x110e, 0x1165, 0,
+#undef V10456
+#define V10456 (V + 39610)
+ 0x110e, 0x1165, 0x11a8, 0,
+#undef V10457
+#define V10457 (V + 39614)
+ 0x110e, 0x1165, 0x11a9, 0,
+#undef V10458
+#define V10458 (V + 39618)
+ 0x110e, 0x1165, 0x11aa, 0,
+#undef V10459
+#define V10459 (V + 39622)
+ 0x110e, 0x1165, 0x11ab, 0,
+#undef V10460
+#define V10460 (V + 39626)
+ 0x110e, 0x1165, 0x11ac, 0,
+#undef V10461
+#define V10461 (V + 39630)
+ 0x110e, 0x1165, 0x11ad, 0,
+#undef V10462
+#define V10462 (V + 39634)
+ 0x110e, 0x1165, 0x11ae, 0,
+#undef V10463
+#define V10463 (V + 39638)
+ 0x110e, 0x1165, 0x11af, 0,
+#undef V10464
+#define V10464 (V + 39642)
+ 0x110e, 0x1165, 0x11b0, 0,
+#undef V10465
+#define V10465 (V + 39646)
+ 0x110e, 0x1165, 0x11b1, 0,
+#undef V10466
+#define V10466 (V + 39650)
+ 0x110e, 0x1165, 0x11b2, 0,
+#undef V10467
+#define V10467 (V + 39654)
+ 0x110e, 0x1165, 0x11b3, 0,
+#undef V10468
+#define V10468 (V + 39658)
+ 0x110e, 0x1165, 0x11b4, 0,
+#undef V10469
+#define V10469 (V + 39662)
+ 0x110e, 0x1165, 0x11b5, 0,
+#undef V10470
+#define V10470 (V + 39666)
+ 0x110e, 0x1165, 0x11b6, 0,
+#undef V10471
+#define V10471 (V + 39670)
+ 0x110e, 0x1165, 0x11b7, 0,
+#undef V10472
+#define V10472 (V + 39674)
+ 0x110e, 0x1165, 0x11b8, 0,
+#undef V10473
+#define V10473 (V + 39678)
+ 0x110e, 0x1165, 0x11b9, 0,
+#undef V10474
+#define V10474 (V + 39682)
+ 0x110e, 0x1165, 0x11ba, 0,
+#undef V10475
+#define V10475 (V + 39686)
+ 0x110e, 0x1165, 0x11bb, 0,
+#undef V10476
+#define V10476 (V + 39690)
+ 0x110e, 0x1165, 0x11bc, 0,
+#undef V10477
+#define V10477 (V + 39694)
+ 0x110e, 0x1165, 0x11bd, 0,
+#undef V10478
+#define V10478 (V + 39698)
+ 0x110e, 0x1165, 0x11be, 0,
+#undef V10479
+#define V10479 (V + 39702)
+ 0x110e, 0x1165, 0x11bf, 0,
+#undef V10480
+#define V10480 (V + 39706)
+ 0x110e, 0x1165, 0x11c0, 0,
+#undef V10481
+#define V10481 (V + 39710)
+ 0x110e, 0x1165, 0x11c1, 0,
+#undef V10482
+#define V10482 (V + 39714)
+ 0x110e, 0x1165, 0x11c2, 0,
+#undef V10483
+#define V10483 (V + 39718)
+ 0x110e, 0x1166, 0,
+#undef V10484
+#define V10484 (V + 39721)
+ 0x110e, 0x1166, 0x11a8, 0,
+#undef V10485
+#define V10485 (V + 39725)
+ 0x110e, 0x1166, 0x11a9, 0,
+#undef V10486
+#define V10486 (V + 39729)
+ 0x110e, 0x1166, 0x11aa, 0,
+#undef V10487
+#define V10487 (V + 39733)
+ 0x110e, 0x1166, 0x11ab, 0,
+#undef V10488
+#define V10488 (V + 39737)
+ 0x110e, 0x1166, 0x11ac, 0,
+#undef V10489
+#define V10489 (V + 39741)
+ 0x110e, 0x1166, 0x11ad, 0,
+#undef V10490
+#define V10490 (V + 39745)
+ 0x110e, 0x1166, 0x11ae, 0,
+#undef V10491
+#define V10491 (V + 39749)
+ 0x110e, 0x1166, 0x11af, 0,
+#undef V10492
+#define V10492 (V + 39753)
+ 0x110e, 0x1166, 0x11b0, 0,
+#undef V10493
+#define V10493 (V + 39757)
+ 0x110e, 0x1166, 0x11b1, 0,
+#undef V10494
+#define V10494 (V + 39761)
+ 0x110e, 0x1166, 0x11b2, 0,
+#undef V10495
+#define V10495 (V + 39765)
+ 0x110e, 0x1166, 0x11b3, 0,
+#undef V10496
+#define V10496 (V + 39769)
+ 0x110e, 0x1166, 0x11b4, 0,
+#undef V10497
+#define V10497 (V + 39773)
+ 0x110e, 0x1166, 0x11b5, 0,
+#undef V10498
+#define V10498 (V + 39777)
+ 0x110e, 0x1166, 0x11b6, 0,
+#undef V10499
+#define V10499 (V + 39781)
+ 0x110e, 0x1166, 0x11b7, 0,
+#undef V10500
+#define V10500 (V + 39785)
+ 0x110e, 0x1166, 0x11b8, 0,
+#undef V10501
+#define V10501 (V + 39789)
+ 0x110e, 0x1166, 0x11b9, 0,
+#undef V10502
+#define V10502 (V + 39793)
+ 0x110e, 0x1166, 0x11ba, 0,
+#undef V10503
+#define V10503 (V + 39797)
+ 0x110e, 0x1166, 0x11bb, 0,
+#undef V10504
+#define V10504 (V + 39801)
+ 0x110e, 0x1166, 0x11bc, 0,
+#undef V10505
+#define V10505 (V + 39805)
+ 0x110e, 0x1166, 0x11bd, 0,
+#undef V10506
+#define V10506 (V + 39809)
+ 0x110e, 0x1166, 0x11be, 0,
+#undef V10507
+#define V10507 (V + 39813)
+ 0x110e, 0x1166, 0x11bf, 0,
+#undef V10508
+#define V10508 (V + 39817)
+ 0x110e, 0x1166, 0x11c0, 0,
+#undef V10509
+#define V10509 (V + 39821)
+ 0x110e, 0x1166, 0x11c1, 0,
+#undef V10510
+#define V10510 (V + 39825)
+ 0x110e, 0x1166, 0x11c2, 0,
+#undef V10511
+#define V10511 (V + 39829)
+ 0x110e, 0x1167, 0,
+#undef V10512
+#define V10512 (V + 39832)
+ 0x110e, 0x1167, 0x11a8, 0,
+#undef V10513
+#define V10513 (V + 39836)
+ 0x110e, 0x1167, 0x11a9, 0,
+#undef V10514
+#define V10514 (V + 39840)
+ 0x110e, 0x1167, 0x11aa, 0,
+#undef V10515
+#define V10515 (V + 39844)
+ 0x110e, 0x1167, 0x11ab, 0,
+#undef V10516
+#define V10516 (V + 39848)
+ 0x110e, 0x1167, 0x11ac, 0,
+#undef V10517
+#define V10517 (V + 39852)
+ 0x110e, 0x1167, 0x11ad, 0,
+#undef V10518
+#define V10518 (V + 39856)
+ 0x110e, 0x1167, 0x11ae, 0,
+#undef V10519
+#define V10519 (V + 39860)
+ 0x110e, 0x1167, 0x11af, 0,
+#undef V10520
+#define V10520 (V + 39864)
+ 0x110e, 0x1167, 0x11b0, 0,
+#undef V10521
+#define V10521 (V + 39868)
+ 0x110e, 0x1167, 0x11b1, 0,
+#undef V10522
+#define V10522 (V + 39872)
+ 0x110e, 0x1167, 0x11b2, 0,
+#undef V10523
+#define V10523 (V + 39876)
+ 0x110e, 0x1167, 0x11b3, 0,
+#undef V10524
+#define V10524 (V + 39880)
+ 0x110e, 0x1167, 0x11b4, 0,
+#undef V10525
+#define V10525 (V + 39884)
+ 0x110e, 0x1167, 0x11b5, 0,
+#undef V10526
+#define V10526 (V + 39888)
+ 0x110e, 0x1167, 0x11b6, 0,
+#undef V10527
+#define V10527 (V + 39892)
+ 0x110e, 0x1167, 0x11b7, 0,
+#undef V10528
+#define V10528 (V + 39896)
+ 0x110e, 0x1167, 0x11b8, 0,
+#undef V10529
+#define V10529 (V + 39900)
+ 0x110e, 0x1167, 0x11b9, 0,
+#undef V10530
+#define V10530 (V + 39904)
+ 0x110e, 0x1167, 0x11ba, 0,
+#undef V10531
+#define V10531 (V + 39908)
+ 0x110e, 0x1167, 0x11bb, 0,
+#undef V10532
+#define V10532 (V + 39912)
+ 0x110e, 0x1167, 0x11bc, 0,
+#undef V10533
+#define V10533 (V + 39916)
+ 0x110e, 0x1167, 0x11bd, 0,
+#undef V10534
+#define V10534 (V + 39920)
+ 0x110e, 0x1167, 0x11be, 0,
+#undef V10535
+#define V10535 (V + 39924)
+ 0x110e, 0x1167, 0x11bf, 0,
+#undef V10536
+#define V10536 (V + 39928)
+ 0x110e, 0x1167, 0x11c0, 0,
+#undef V10537
+#define V10537 (V + 39932)
+ 0x110e, 0x1167, 0x11c1, 0,
+#undef V10538
+#define V10538 (V + 39936)
+ 0x110e, 0x1167, 0x11c2, 0,
+#undef V10539
+#define V10539 (V + 39940)
+ 0x110e, 0x1168, 0,
+#undef V10540
+#define V10540 (V + 39943)
+ 0x110e, 0x1168, 0x11a8, 0,
+#undef V10541
+#define V10541 (V + 39947)
+ 0x110e, 0x1168, 0x11a9, 0,
+#undef V10542
+#define V10542 (V + 39951)
+ 0x110e, 0x1168, 0x11aa, 0,
+#undef V10543
+#define V10543 (V + 39955)
+ 0x110e, 0x1168, 0x11ab, 0,
+#undef V10544
+#define V10544 (V + 39959)
+ 0x110e, 0x1168, 0x11ac, 0,
+#undef V10545
+#define V10545 (V + 39963)
+ 0x110e, 0x1168, 0x11ad, 0,
+#undef V10546
+#define V10546 (V + 39967)
+ 0x110e, 0x1168, 0x11ae, 0,
+#undef V10547
+#define V10547 (V + 39971)
+ 0x110e, 0x1168, 0x11af, 0,
+#undef V10548
+#define V10548 (V + 39975)
+ 0x110e, 0x1168, 0x11b0, 0,
+#undef V10549
+#define V10549 (V + 39979)
+ 0x110e, 0x1168, 0x11b1, 0,
+#undef V10550
+#define V10550 (V + 39983)
+ 0x110e, 0x1168, 0x11b2, 0,
+#undef V10551
+#define V10551 (V + 39987)
+ 0x110e, 0x1168, 0x11b3, 0,
+#undef V10552
+#define V10552 (V + 39991)
+ 0x110e, 0x1168, 0x11b4, 0,
+#undef V10553
+#define V10553 (V + 39995)
+ 0x110e, 0x1168, 0x11b5, 0,
+#undef V10554
+#define V10554 (V + 39999)
+ 0x110e, 0x1168, 0x11b6, 0,
+#undef V10555
+#define V10555 (V + 40003)
+ 0x110e, 0x1168, 0x11b7, 0,
+#undef V10556
+#define V10556 (V + 40007)
+ 0x110e, 0x1168, 0x11b8, 0,
+#undef V10557
+#define V10557 (V + 40011)
+ 0x110e, 0x1168, 0x11b9, 0,
+#undef V10558
+#define V10558 (V + 40015)
+ 0x110e, 0x1168, 0x11ba, 0,
+#undef V10559
+#define V10559 (V + 40019)
+ 0x110e, 0x1168, 0x11bb, 0,
+#undef V10560
+#define V10560 (V + 40023)
+ 0x110e, 0x1168, 0x11bc, 0,
+#undef V10561
+#define V10561 (V + 40027)
+ 0x110e, 0x1168, 0x11bd, 0,
+#undef V10562
+#define V10562 (V + 40031)
+ 0x110e, 0x1168, 0x11be, 0,
+#undef V10563
+#define V10563 (V + 40035)
+ 0x110e, 0x1168, 0x11bf, 0,
+#undef V10564
+#define V10564 (V + 40039)
+ 0x110e, 0x1168, 0x11c0, 0,
+#undef V10565
+#define V10565 (V + 40043)
+ 0x110e, 0x1168, 0x11c1, 0,
+#undef V10566
+#define V10566 (V + 40047)
+ 0x110e, 0x1168, 0x11c2, 0,
+#undef V10567
+#define V10567 (V + 40051)
+ 0x110e, 0x1169, 0,
+#undef V10568
+#define V10568 (V + 40054)
+ 0x110e, 0x1169, 0x11a8, 0,
+#undef V10569
+#define V10569 (V + 40058)
+ 0x110e, 0x1169, 0x11a9, 0,
+#undef V10570
+#define V10570 (V + 40062)
+ 0x110e, 0x1169, 0x11aa, 0,
+#undef V10571
+#define V10571 (V + 40066)
+ 0x110e, 0x1169, 0x11ab, 0,
+#undef V10572
+#define V10572 (V + 40070)
+ 0x110e, 0x1169, 0x11ac, 0,
+#undef V10573
+#define V10573 (V + 40074)
+ 0x110e, 0x1169, 0x11ad, 0,
+#undef V10574
+#define V10574 (V + 40078)
+ 0x110e, 0x1169, 0x11ae, 0,
+#undef V10575
+#define V10575 (V + 40082)
+ 0x110e, 0x1169, 0x11af, 0,
+#undef V10576
+#define V10576 (V + 40086)
+ 0x110e, 0x1169, 0x11b0, 0,
+#undef V10577
+#define V10577 (V + 40090)
+ 0x110e, 0x1169, 0x11b1, 0,
+#undef V10578
+#define V10578 (V + 40094)
+ 0x110e, 0x1169, 0x11b2, 0,
+#undef V10579
+#define V10579 (V + 40098)
+ 0x110e, 0x1169, 0x11b3, 0,
+#undef V10580
+#define V10580 (V + 40102)
+ 0x110e, 0x1169, 0x11b4, 0,
+#undef V10581
+#define V10581 (V + 40106)
+ 0x110e, 0x1169, 0x11b5, 0,
+#undef V10582
+#define V10582 (V + 40110)
+ 0x110e, 0x1169, 0x11b6, 0,
+#undef V10583
+#define V10583 (V + 40114)
+ 0x110e, 0x1169, 0x11b7, 0,
+#undef V10584
+#define V10584 (V + 40118)
+ 0x110e, 0x1169, 0x11b8, 0,
+#undef V10585
+#define V10585 (V + 40122)
+ 0x110e, 0x1169, 0x11b9, 0,
+#undef V10586
+#define V10586 (V + 40126)
+ 0x110e, 0x1169, 0x11ba, 0,
+#undef V10587
+#define V10587 (V + 40130)
+ 0x110e, 0x1169, 0x11bb, 0,
+#undef V10588
+#define V10588 (V + 40134)
+ 0x110e, 0x1169, 0x11bc, 0,
+#undef V10589
+#define V10589 (V + 40138)
+ 0x110e, 0x1169, 0x11bd, 0,
+#undef V10590
+#define V10590 (V + 40142)
+ 0x110e, 0x1169, 0x11be, 0,
+#undef V10591
+#define V10591 (V + 40146)
+ 0x110e, 0x1169, 0x11bf, 0,
+#undef V10592
+#define V10592 (V + 40150)
+ 0x110e, 0x1169, 0x11c0, 0,
+#undef V10593
+#define V10593 (V + 40154)
+ 0x110e, 0x1169, 0x11c1, 0,
+#undef V10594
+#define V10594 (V + 40158)
+ 0x110e, 0x1169, 0x11c2, 0,
+#undef V10595
+#define V10595 (V + 40162)
+ 0x110e, 0x116a, 0,
+#undef V10596
+#define V10596 (V + 40165)
+ 0x110e, 0x116a, 0x11a8, 0,
+#undef V10597
+#define V10597 (V + 40169)
+ 0x110e, 0x116a, 0x11a9, 0,
+#undef V10598
+#define V10598 (V + 40173)
+ 0x110e, 0x116a, 0x11aa, 0,
+#undef V10599
+#define V10599 (V + 40177)
+ 0x110e, 0x116a, 0x11ab, 0,
+#undef V10600
+#define V10600 (V + 40181)
+ 0x110e, 0x116a, 0x11ac, 0,
+#undef V10601
+#define V10601 (V + 40185)
+ 0x110e, 0x116a, 0x11ad, 0,
+#undef V10602
+#define V10602 (V + 40189)
+ 0x110e, 0x116a, 0x11ae, 0,
+#undef V10603
+#define V10603 (V + 40193)
+ 0x110e, 0x116a, 0x11af, 0,
+#undef V10604
+#define V10604 (V + 40197)
+ 0x110e, 0x116a, 0x11b0, 0,
+#undef V10605
+#define V10605 (V + 40201)
+ 0x110e, 0x116a, 0x11b1, 0,
+#undef V10606
+#define V10606 (V + 40205)
+ 0x110e, 0x116a, 0x11b2, 0,
+#undef V10607
+#define V10607 (V + 40209)
+ 0x110e, 0x116a, 0x11b3, 0,
+#undef V10608
+#define V10608 (V + 40213)
+ 0x110e, 0x116a, 0x11b4, 0,
+#undef V10609
+#define V10609 (V + 40217)
+ 0x110e, 0x116a, 0x11b5, 0,
+#undef V10610
+#define V10610 (V + 40221)
+ 0x110e, 0x116a, 0x11b6, 0,
+#undef V10611
+#define V10611 (V + 40225)
+ 0x110e, 0x116a, 0x11b7, 0,
+#undef V10612
+#define V10612 (V + 40229)
+ 0x110e, 0x116a, 0x11b8, 0,
+#undef V10613
+#define V10613 (V + 40233)
+ 0x110e, 0x116a, 0x11b9, 0,
+#undef V10614
+#define V10614 (V + 40237)
+ 0x110e, 0x116a, 0x11ba, 0,
+#undef V10615
+#define V10615 (V + 40241)
+ 0x110e, 0x116a, 0x11bb, 0,
+#undef V10616
+#define V10616 (V + 40245)
+ 0x110e, 0x116a, 0x11bc, 0,
+#undef V10617
+#define V10617 (V + 40249)
+ 0x110e, 0x116a, 0x11bd, 0,
+#undef V10618
+#define V10618 (V + 40253)
+ 0x110e, 0x116a, 0x11be, 0,
+#undef V10619
+#define V10619 (V + 40257)
+ 0x110e, 0x116a, 0x11bf, 0,
+#undef V10620
+#define V10620 (V + 40261)
+ 0x110e, 0x116a, 0x11c0, 0,
+#undef V10621
+#define V10621 (V + 40265)
+ 0x110e, 0x116a, 0x11c1, 0,
+#undef V10622
+#define V10622 (V + 40269)
+ 0x110e, 0x116a, 0x11c2, 0,
+#undef V10623
+#define V10623 (V + 40273)
+ 0x110e, 0x116b, 0,
+#undef V10624
+#define V10624 (V + 40276)
+ 0x110e, 0x116b, 0x11a8, 0,
+#undef V10625
+#define V10625 (V + 40280)
+ 0x110e, 0x116b, 0x11a9, 0,
+#undef V10626
+#define V10626 (V + 40284)
+ 0x110e, 0x116b, 0x11aa, 0,
+#undef V10627
+#define V10627 (V + 40288)
+ 0x110e, 0x116b, 0x11ab, 0,
+#undef V10628
+#define V10628 (V + 40292)
+ 0x110e, 0x116b, 0x11ac, 0,
+#undef V10629
+#define V10629 (V + 40296)
+ 0x110e, 0x116b, 0x11ad, 0,
+#undef V10630
+#define V10630 (V + 40300)
+ 0x110e, 0x116b, 0x11ae, 0,
+#undef V10631
+#define V10631 (V + 40304)
+ 0x110e, 0x116b, 0x11af, 0,
+#undef V10632
+#define V10632 (V + 40308)
+ 0x110e, 0x116b, 0x11b0, 0,
+#undef V10633
+#define V10633 (V + 40312)
+ 0x110e, 0x116b, 0x11b1, 0,
+#undef V10634
+#define V10634 (V + 40316)
+ 0x110e, 0x116b, 0x11b2, 0,
+#undef V10635
+#define V10635 (V + 40320)
+ 0x110e, 0x116b, 0x11b3, 0,
+#undef V10636
+#define V10636 (V + 40324)
+ 0x110e, 0x116b, 0x11b4, 0,
+#undef V10637
+#define V10637 (V + 40328)
+ 0x110e, 0x116b, 0x11b5, 0,
+#undef V10638
+#define V10638 (V + 40332)
+ 0x110e, 0x116b, 0x11b6, 0,
+#undef V10639
+#define V10639 (V + 40336)
+ 0x110e, 0x116b, 0x11b7, 0,
+#undef V10640
+#define V10640 (V + 40340)
+ 0x110e, 0x116b, 0x11b8, 0,
+#undef V10641
+#define V10641 (V + 40344)
+ 0x110e, 0x116b, 0x11b9, 0,
+#undef V10642
+#define V10642 (V + 40348)
+ 0x110e, 0x116b, 0x11ba, 0,
+#undef V10643
+#define V10643 (V + 40352)
+ 0x110e, 0x116b, 0x11bb, 0,
+#undef V10644
+#define V10644 (V + 40356)
+ 0x110e, 0x116b, 0x11bc, 0,
+#undef V10645
+#define V10645 (V + 40360)
+ 0x110e, 0x116b, 0x11bd, 0,
+#undef V10646
+#define V10646 (V + 40364)
+ 0x110e, 0x116b, 0x11be, 0,
+#undef V10647
+#define V10647 (V + 40368)
+ 0x110e, 0x116b, 0x11bf, 0,
+#undef V10648
+#define V10648 (V + 40372)
+ 0x110e, 0x116b, 0x11c0, 0,
+#undef V10649
+#define V10649 (V + 40376)
+ 0x110e, 0x116b, 0x11c1, 0,
+#undef V10650
+#define V10650 (V + 40380)
+ 0x110e, 0x116b, 0x11c2, 0,
+#undef V10651
+#define V10651 (V + 40384)
+ 0x110e, 0x116c, 0,
+#undef V10652
+#define V10652 (V + 40387)
+ 0x110e, 0x116c, 0x11a8, 0,
+#undef V10653
+#define V10653 (V + 40391)
+ 0x110e, 0x116c, 0x11a9, 0,
+#undef V10654
+#define V10654 (V + 40395)
+ 0x110e, 0x116c, 0x11aa, 0,
+#undef V10655
+#define V10655 (V + 40399)
+ 0x110e, 0x116c, 0x11ab, 0,
+#undef V10656
+#define V10656 (V + 40403)
+ 0x110e, 0x116c, 0x11ac, 0,
+#undef V10657
+#define V10657 (V + 40407)
+ 0x110e, 0x116c, 0x11ad, 0,
+#undef V10658
+#define V10658 (V + 40411)
+ 0x110e, 0x116c, 0x11ae, 0,
+#undef V10659
+#define V10659 (V + 40415)
+ 0x110e, 0x116c, 0x11af, 0,
+#undef V10660
+#define V10660 (V + 40419)
+ 0x110e, 0x116c, 0x11b0, 0,
+#undef V10661
+#define V10661 (V + 40423)
+ 0x110e, 0x116c, 0x11b1, 0,
+#undef V10662
+#define V10662 (V + 40427)
+ 0x110e, 0x116c, 0x11b2, 0,
+#undef V10663
+#define V10663 (V + 40431)
+ 0x110e, 0x116c, 0x11b3, 0,
+#undef V10664
+#define V10664 (V + 40435)
+ 0x110e, 0x116c, 0x11b4, 0,
+#undef V10665
+#define V10665 (V + 40439)
+ 0x110e, 0x116c, 0x11b5, 0,
+#undef V10666
+#define V10666 (V + 40443)
+ 0x110e, 0x116c, 0x11b6, 0,
+#undef V10667
+#define V10667 (V + 40447)
+ 0x110e, 0x116c, 0x11b7, 0,
+#undef V10668
+#define V10668 (V + 40451)
+ 0x110e, 0x116c, 0x11b8, 0,
+#undef V10669
+#define V10669 (V + 40455)
+ 0x110e, 0x116c, 0x11b9, 0,
+#undef V10670
+#define V10670 (V + 40459)
+ 0x110e, 0x116c, 0x11ba, 0,
+#undef V10671
+#define V10671 (V + 40463)
+ 0x110e, 0x116c, 0x11bb, 0,
+#undef V10672
+#define V10672 (V + 40467)
+ 0x110e, 0x116c, 0x11bc, 0,
+#undef V10673
+#define V10673 (V + 40471)
+ 0x110e, 0x116c, 0x11bd, 0,
+#undef V10674
+#define V10674 (V + 40475)
+ 0x110e, 0x116c, 0x11be, 0,
+#undef V10675
+#define V10675 (V + 40479)
+ 0x110e, 0x116c, 0x11bf, 0,
+#undef V10676
+#define V10676 (V + 40483)
+ 0x110e, 0x116c, 0x11c0, 0,
+#undef V10677
+#define V10677 (V + 40487)
+ 0x110e, 0x116c, 0x11c1, 0,
+#undef V10678
+#define V10678 (V + 40491)
+ 0x110e, 0x116c, 0x11c2, 0,
+#undef V10679
+#define V10679 (V + 40495)
+ 0x110e, 0x116d, 0,
+#undef V10680
+#define V10680 (V + 40498)
+ 0x110e, 0x116d, 0x11a8, 0,
+#undef V10681
+#define V10681 (V + 40502)
+ 0x110e, 0x116d, 0x11a9, 0,
+#undef V10682
+#define V10682 (V + 40506)
+ 0x110e, 0x116d, 0x11aa, 0,
+#undef V10683
+#define V10683 (V + 40510)
+ 0x110e, 0x116d, 0x11ab, 0,
+#undef V10684
+#define V10684 (V + 40514)
+ 0x110e, 0x116d, 0x11ac, 0,
+#undef V10685
+#define V10685 (V + 40518)
+ 0x110e, 0x116d, 0x11ad, 0,
+#undef V10686
+#define V10686 (V + 40522)
+ 0x110e, 0x116d, 0x11ae, 0,
+#undef V10687
+#define V10687 (V + 40526)
+ 0x110e, 0x116d, 0x11af, 0,
+#undef V10688
+#define V10688 (V + 40530)
+ 0x110e, 0x116d, 0x11b0, 0,
+#undef V10689
+#define V10689 (V + 40534)
+ 0x110e, 0x116d, 0x11b1, 0,
+#undef V10690
+#define V10690 (V + 40538)
+ 0x110e, 0x116d, 0x11b2, 0,
+#undef V10691
+#define V10691 (V + 40542)
+ 0x110e, 0x116d, 0x11b3, 0,
+#undef V10692
+#define V10692 (V + 40546)
+ 0x110e, 0x116d, 0x11b4, 0,
+#undef V10693
+#define V10693 (V + 40550)
+ 0x110e, 0x116d, 0x11b5, 0,
+#undef V10694
+#define V10694 (V + 40554)
+ 0x110e, 0x116d, 0x11b6, 0,
+#undef V10695
+#define V10695 (V + 40558)
+ 0x110e, 0x116d, 0x11b7, 0,
+#undef V10696
+#define V10696 (V + 40562)
+ 0x110e, 0x116d, 0x11b8, 0,
+#undef V10697
+#define V10697 (V + 40566)
+ 0x110e, 0x116d, 0x11b9, 0,
+#undef V10698
+#define V10698 (V + 40570)
+ 0x110e, 0x116d, 0x11ba, 0,
+#undef V10699
+#define V10699 (V + 40574)
+ 0x110e, 0x116d, 0x11bb, 0,
+#undef V10700
+#define V10700 (V + 40578)
+ 0x110e, 0x116d, 0x11bc, 0,
+#undef V10701
+#define V10701 (V + 40582)
+ 0x110e, 0x116d, 0x11bd, 0,
+#undef V10702
+#define V10702 (V + 40586)
+ 0x110e, 0x116d, 0x11be, 0,
+#undef V10703
+#define V10703 (V + 40590)
+ 0x110e, 0x116d, 0x11bf, 0,
+#undef V10704
+#define V10704 (V + 40594)
+ 0x110e, 0x116d, 0x11c0, 0,
+#undef V10705
+#define V10705 (V + 40598)
+ 0x110e, 0x116d, 0x11c1, 0,
+#undef V10706
+#define V10706 (V + 40602)
+ 0x110e, 0x116d, 0x11c2, 0,
+#undef V10707
+#define V10707 (V + 40606)
+ 0x110e, 0x116e, 0,
+#undef V10708
+#define V10708 (V + 40609)
+ 0x110e, 0x116e, 0x11a8, 0,
+#undef V10709
+#define V10709 (V + 40613)
+ 0x110e, 0x116e, 0x11a9, 0,
+#undef V10710
+#define V10710 (V + 40617)
+ 0x110e, 0x116e, 0x11aa, 0,
+#undef V10711
+#define V10711 (V + 40621)
+ 0x110e, 0x116e, 0x11ab, 0,
+#undef V10712
+#define V10712 (V + 40625)
+ 0x110e, 0x116e, 0x11ac, 0,
+#undef V10713
+#define V10713 (V + 40629)
+ 0x110e, 0x116e, 0x11ad, 0,
+#undef V10714
+#define V10714 (V + 40633)
+ 0x110e, 0x116e, 0x11ae, 0,
+#undef V10715
+#define V10715 (V + 40637)
+ 0x110e, 0x116e, 0x11af, 0,
+#undef V10716
+#define V10716 (V + 40641)
+ 0x110e, 0x116e, 0x11b0, 0,
+#undef V10717
+#define V10717 (V + 40645)
+ 0x110e, 0x116e, 0x11b1, 0,
+#undef V10718
+#define V10718 (V + 40649)
+ 0x110e, 0x116e, 0x11b2, 0,
+#undef V10719
+#define V10719 (V + 40653)
+ 0x110e, 0x116e, 0x11b3, 0,
+#undef V10720
+#define V10720 (V + 40657)
+ 0x110e, 0x116e, 0x11b4, 0,
+#undef V10721
+#define V10721 (V + 40661)
+ 0x110e, 0x116e, 0x11b5, 0,
+#undef V10722
+#define V10722 (V + 40665)
+ 0x110e, 0x116e, 0x11b6, 0,
+#undef V10723
+#define V10723 (V + 40669)
+ 0x110e, 0x116e, 0x11b7, 0,
+#undef V10724
+#define V10724 (V + 40673)
+ 0x110e, 0x116e, 0x11b8, 0,
+#undef V10725
+#define V10725 (V + 40677)
+ 0x110e, 0x116e, 0x11b9, 0,
+#undef V10726
+#define V10726 (V + 40681)
+ 0x110e, 0x116e, 0x11ba, 0,
+#undef V10727
+#define V10727 (V + 40685)
+ 0x110e, 0x116e, 0x11bb, 0,
+#undef V10728
+#define V10728 (V + 40689)
+ 0x110e, 0x116e, 0x11bc, 0,
+#undef V10729
+#define V10729 (V + 40693)
+ 0x110e, 0x116e, 0x11bd, 0,
+#undef V10730
+#define V10730 (V + 40697)
+ 0x110e, 0x116e, 0x11be, 0,
+#undef V10731
+#define V10731 (V + 40701)
+ 0x110e, 0x116e, 0x11bf, 0,
+#undef V10732
+#define V10732 (V + 40705)
+ 0x110e, 0x116e, 0x11c0, 0,
+#undef V10733
+#define V10733 (V + 40709)
+ 0x110e, 0x116e, 0x11c1, 0,
+#undef V10734
+#define V10734 (V + 40713)
+ 0x110e, 0x116e, 0x11c2, 0,
+#undef V10735
+#define V10735 (V + 40717)
+ 0x110e, 0x116f, 0,
+#undef V10736
+#define V10736 (V + 40720)
+ 0x110e, 0x116f, 0x11a8, 0,
+#undef V10737
+#define V10737 (V + 40724)
+ 0x110e, 0x116f, 0x11a9, 0,
+#undef V10738
+#define V10738 (V + 40728)
+ 0x110e, 0x116f, 0x11aa, 0,
+#undef V10739
+#define V10739 (V + 40732)
+ 0x110e, 0x116f, 0x11ab, 0,
+#undef V10740
+#define V10740 (V + 40736)
+ 0x110e, 0x116f, 0x11ac, 0,
+#undef V10741
+#define V10741 (V + 40740)
+ 0x110e, 0x116f, 0x11ad, 0,
+#undef V10742
+#define V10742 (V + 40744)
+ 0x110e, 0x116f, 0x11ae, 0,
+#undef V10743
+#define V10743 (V + 40748)
+ 0x110e, 0x116f, 0x11af, 0,
+#undef V10744
+#define V10744 (V + 40752)
+ 0x110e, 0x116f, 0x11b0, 0,
+#undef V10745
+#define V10745 (V + 40756)
+ 0x110e, 0x116f, 0x11b1, 0,
+#undef V10746
+#define V10746 (V + 40760)
+ 0x110e, 0x116f, 0x11b2, 0,
+#undef V10747
+#define V10747 (V + 40764)
+ 0x110e, 0x116f, 0x11b3, 0,
+#undef V10748
+#define V10748 (V + 40768)
+ 0x110e, 0x116f, 0x11b4, 0,
+#undef V10749
+#define V10749 (V + 40772)
+ 0x110e, 0x116f, 0x11b5, 0,
+#undef V10750
+#define V10750 (V + 40776)
+ 0x110e, 0x116f, 0x11b6, 0,
+#undef V10751
+#define V10751 (V + 40780)
+ 0x110e, 0x116f, 0x11b7, 0,
+#undef V10752
+#define V10752 (V + 40784)
+ 0x110e, 0x116f, 0x11b8, 0,
+#undef V10753
+#define V10753 (V + 40788)
+ 0x110e, 0x116f, 0x11b9, 0,
+#undef V10754
+#define V10754 (V + 40792)
+ 0x110e, 0x116f, 0x11ba, 0,
+#undef V10755
+#define V10755 (V + 40796)
+ 0x110e, 0x116f, 0x11bb, 0,
+#undef V10756
+#define V10756 (V + 40800)
+ 0x110e, 0x116f, 0x11bc, 0,
+#undef V10757
+#define V10757 (V + 40804)
+ 0x110e, 0x116f, 0x11bd, 0,
+#undef V10758
+#define V10758 (V + 40808)
+ 0x110e, 0x116f, 0x11be, 0,
+#undef V10759
+#define V10759 (V + 40812)
+ 0x110e, 0x116f, 0x11bf, 0,
+#undef V10760
+#define V10760 (V + 40816)
+ 0x110e, 0x116f, 0x11c0, 0,
+#undef V10761
+#define V10761 (V + 40820)
+ 0x110e, 0x116f, 0x11c1, 0,
+#undef V10762
+#define V10762 (V + 40824)
+ 0x110e, 0x116f, 0x11c2, 0,
+#undef V10763
+#define V10763 (V + 40828)
+ 0x110e, 0x1170, 0,
+#undef V10764
+#define V10764 (V + 40831)
+ 0x110e, 0x1170, 0x11a8, 0,
+#undef V10765
+#define V10765 (V + 40835)
+ 0x110e, 0x1170, 0x11a9, 0,
+#undef V10766
+#define V10766 (V + 40839)
+ 0x110e, 0x1170, 0x11aa, 0,
+#undef V10767
+#define V10767 (V + 40843)
+ 0x110e, 0x1170, 0x11ab, 0,
+#undef V10768
+#define V10768 (V + 40847)
+ 0x110e, 0x1170, 0x11ac, 0,
+#undef V10769
+#define V10769 (V + 40851)
+ 0x110e, 0x1170, 0x11ad, 0,
+#undef V10770
+#define V10770 (V + 40855)
+ 0x110e, 0x1170, 0x11ae, 0,
+#undef V10771
+#define V10771 (V + 40859)
+ 0x110e, 0x1170, 0x11af, 0,
+#undef V10772
+#define V10772 (V + 40863)
+ 0x110e, 0x1170, 0x11b0, 0,
+#undef V10773
+#define V10773 (V + 40867)
+ 0x110e, 0x1170, 0x11b1, 0,
+#undef V10774
+#define V10774 (V + 40871)
+ 0x110e, 0x1170, 0x11b2, 0,
+#undef V10775
+#define V10775 (V + 40875)
+ 0x110e, 0x1170, 0x11b3, 0,
+#undef V10776
+#define V10776 (V + 40879)
+ 0x110e, 0x1170, 0x11b4, 0,
+#undef V10777
+#define V10777 (V + 40883)
+ 0x110e, 0x1170, 0x11b5, 0,
+#undef V10778
+#define V10778 (V + 40887)
+ 0x110e, 0x1170, 0x11b6, 0,
+#undef V10779
+#define V10779 (V + 40891)
+ 0x110e, 0x1170, 0x11b7, 0,
+#undef V10780
+#define V10780 (V + 40895)
+ 0x110e, 0x1170, 0x11b8, 0,
+#undef V10781
+#define V10781 (V + 40899)
+ 0x110e, 0x1170, 0x11b9, 0,
+#undef V10782
+#define V10782 (V + 40903)
+ 0x110e, 0x1170, 0x11ba, 0,
+#undef V10783
+#define V10783 (V + 40907)
+ 0x110e, 0x1170, 0x11bb, 0,
+#undef V10784
+#define V10784 (V + 40911)
+ 0x110e, 0x1170, 0x11bc, 0,
+#undef V10785
+#define V10785 (V + 40915)
+ 0x110e, 0x1170, 0x11bd, 0,
+#undef V10786
+#define V10786 (V + 40919)
+ 0x110e, 0x1170, 0x11be, 0,
+#undef V10787
+#define V10787 (V + 40923)
+ 0x110e, 0x1170, 0x11bf, 0,
+#undef V10788
+#define V10788 (V + 40927)
+ 0x110e, 0x1170, 0x11c0, 0,
+#undef V10789
+#define V10789 (V + 40931)
+ 0x110e, 0x1170, 0x11c1, 0,
+#undef V10790
+#define V10790 (V + 40935)
+ 0x110e, 0x1170, 0x11c2, 0,
+#undef V10791
+#define V10791 (V + 40939)
+ 0x110e, 0x1171, 0,
+#undef V10792
+#define V10792 (V + 40942)
+ 0x110e, 0x1171, 0x11a8, 0,
+#undef V10793
+#define V10793 (V + 40946)
+ 0x110e, 0x1171, 0x11a9, 0,
+#undef V10794
+#define V10794 (V + 40950)
+ 0x110e, 0x1171, 0x11aa, 0,
+#undef V10795
+#define V10795 (V + 40954)
+ 0x110e, 0x1171, 0x11ab, 0,
+#undef V10796
+#define V10796 (V + 40958)
+ 0x110e, 0x1171, 0x11ac, 0,
+#undef V10797
+#define V10797 (V + 40962)
+ 0x110e, 0x1171, 0x11ad, 0,
+#undef V10798
+#define V10798 (V + 40966)
+ 0x110e, 0x1171, 0x11ae, 0,
+#undef V10799
+#define V10799 (V + 40970)
+ 0x110e, 0x1171, 0x11af, 0,
+#undef V10800
+#define V10800 (V + 40974)
+ 0x110e, 0x1171, 0x11b0, 0,
+#undef V10801
+#define V10801 (V + 40978)
+ 0x110e, 0x1171, 0x11b1, 0,
+#undef V10802
+#define V10802 (V + 40982)
+ 0x110e, 0x1171, 0x11b2, 0,
+#undef V10803
+#define V10803 (V + 40986)
+ 0x110e, 0x1171, 0x11b3, 0,
+#undef V10804
+#define V10804 (V + 40990)
+ 0x110e, 0x1171, 0x11b4, 0,
+#undef V10805
+#define V10805 (V + 40994)
+ 0x110e, 0x1171, 0x11b5, 0,
+#undef V10806
+#define V10806 (V + 40998)
+ 0x110e, 0x1171, 0x11b6, 0,
+#undef V10807
+#define V10807 (V + 41002)
+ 0x110e, 0x1171, 0x11b7, 0,
+#undef V10808
+#define V10808 (V + 41006)
+ 0x110e, 0x1171, 0x11b8, 0,
+#undef V10809
+#define V10809 (V + 41010)
+ 0x110e, 0x1171, 0x11b9, 0,
+#undef V10810
+#define V10810 (V + 41014)
+ 0x110e, 0x1171, 0x11ba, 0,
+#undef V10811
+#define V10811 (V + 41018)
+ 0x110e, 0x1171, 0x11bb, 0,
+#undef V10812
+#define V10812 (V + 41022)
+ 0x110e, 0x1171, 0x11bc, 0,
+#undef V10813
+#define V10813 (V + 41026)
+ 0x110e, 0x1171, 0x11bd, 0,
+#undef V10814
+#define V10814 (V + 41030)
+ 0x110e, 0x1171, 0x11be, 0,
+#undef V10815
+#define V10815 (V + 41034)
+ 0x110e, 0x1171, 0x11bf, 0,
+#undef V10816
+#define V10816 (V + 41038)
+ 0x110e, 0x1171, 0x11c0, 0,
+#undef V10817
+#define V10817 (V + 41042)
+ 0x110e, 0x1171, 0x11c1, 0,
+#undef V10818
+#define V10818 (V + 41046)
+ 0x110e, 0x1171, 0x11c2, 0,
+#undef V10819
+#define V10819 (V + 41050)
+ 0x110e, 0x1172, 0,
+#undef V10820
+#define V10820 (V + 41053)
+ 0x110e, 0x1172, 0x11a8, 0,
+#undef V10821
+#define V10821 (V + 41057)
+ 0x110e, 0x1172, 0x11a9, 0,
+#undef V10822
+#define V10822 (V + 41061)
+ 0x110e, 0x1172, 0x11aa, 0,
+#undef V10823
+#define V10823 (V + 41065)
+ 0x110e, 0x1172, 0x11ab, 0,
+#undef V10824
+#define V10824 (V + 41069)
+ 0x110e, 0x1172, 0x11ac, 0,
+#undef V10825
+#define V10825 (V + 41073)
+ 0x110e, 0x1172, 0x11ad, 0,
+#undef V10826
+#define V10826 (V + 41077)
+ 0x110e, 0x1172, 0x11ae, 0,
+#undef V10827
+#define V10827 (V + 41081)
+ 0x110e, 0x1172, 0x11af, 0,
+#undef V10828
+#define V10828 (V + 41085)
+ 0x110e, 0x1172, 0x11b0, 0,
+#undef V10829
+#define V10829 (V + 41089)
+ 0x110e, 0x1172, 0x11b1, 0,
+#undef V10830
+#define V10830 (V + 41093)
+ 0x110e, 0x1172, 0x11b2, 0,
+#undef V10831
+#define V10831 (V + 41097)
+ 0x110e, 0x1172, 0x11b3, 0,
+#undef V10832
+#define V10832 (V + 41101)
+ 0x110e, 0x1172, 0x11b4, 0,
+#undef V10833
+#define V10833 (V + 41105)
+ 0x110e, 0x1172, 0x11b5, 0,
+#undef V10834
+#define V10834 (V + 41109)
+ 0x110e, 0x1172, 0x11b6, 0,
+#undef V10835
+#define V10835 (V + 41113)
+ 0x110e, 0x1172, 0x11b7, 0,
+#undef V10836
+#define V10836 (V + 41117)
+ 0x110e, 0x1172, 0x11b8, 0,
+#undef V10837
+#define V10837 (V + 41121)
+ 0x110e, 0x1172, 0x11b9, 0,
+#undef V10838
+#define V10838 (V + 41125)
+ 0x110e, 0x1172, 0x11ba, 0,
+#undef V10839
+#define V10839 (V + 41129)
+ 0x110e, 0x1172, 0x11bb, 0,
+#undef V10840
+#define V10840 (V + 41133)
+ 0x110e, 0x1172, 0x11bc, 0,
+#undef V10841
+#define V10841 (V + 41137)
+ 0x110e, 0x1172, 0x11bd, 0,
+#undef V10842
+#define V10842 (V + 41141)
+ 0x110e, 0x1172, 0x11be, 0,
+#undef V10843
+#define V10843 (V + 41145)
+ 0x110e, 0x1172, 0x11bf, 0,
+#undef V10844
+#define V10844 (V + 41149)
+ 0x110e, 0x1172, 0x11c0, 0,
+#undef V10845
+#define V10845 (V + 41153)
+ 0x110e, 0x1172, 0x11c1, 0,
+#undef V10846
+#define V10846 (V + 41157)
+ 0x110e, 0x1172, 0x11c2, 0,
+#undef V10847
+#define V10847 (V + 41161)
+ 0x110e, 0x1173, 0,
+#undef V10848
+#define V10848 (V + 41164)
+ 0x110e, 0x1173, 0x11a8, 0,
+#undef V10849
+#define V10849 (V + 41168)
+ 0x110e, 0x1173, 0x11a9, 0,
+#undef V10850
+#define V10850 (V + 41172)
+ 0x110e, 0x1173, 0x11aa, 0,
+#undef V10851
+#define V10851 (V + 41176)
+ 0x110e, 0x1173, 0x11ab, 0,
+#undef V10852
+#define V10852 (V + 41180)
+ 0x110e, 0x1173, 0x11ac, 0,
+#undef V10853
+#define V10853 (V + 41184)
+ 0x110e, 0x1173, 0x11ad, 0,
+#undef V10854
+#define V10854 (V + 41188)
+ 0x110e, 0x1173, 0x11ae, 0,
+#undef V10855
+#define V10855 (V + 41192)
+ 0x110e, 0x1173, 0x11af, 0,
+#undef V10856
+#define V10856 (V + 41196)
+ 0x110e, 0x1173, 0x11b0, 0,
+#undef V10857
+#define V10857 (V + 41200)
+ 0x110e, 0x1173, 0x11b1, 0,
+#undef V10858
+#define V10858 (V + 41204)
+ 0x110e, 0x1173, 0x11b2, 0,
+#undef V10859
+#define V10859 (V + 41208)
+ 0x110e, 0x1173, 0x11b3, 0,
+#undef V10860
+#define V10860 (V + 41212)
+ 0x110e, 0x1173, 0x11b4, 0,
+#undef V10861
+#define V10861 (V + 41216)
+ 0x110e, 0x1173, 0x11b5, 0,
+#undef V10862
+#define V10862 (V + 41220)
+ 0x110e, 0x1173, 0x11b6, 0,
+#undef V10863
+#define V10863 (V + 41224)
+ 0x110e, 0x1173, 0x11b7, 0,
+#undef V10864
+#define V10864 (V + 41228)
+ 0x110e, 0x1173, 0x11b8, 0,
+#undef V10865
+#define V10865 (V + 41232)
+ 0x110e, 0x1173, 0x11b9, 0,
+#undef V10866
+#define V10866 (V + 41236)
+ 0x110e, 0x1173, 0x11ba, 0,
+#undef V10867
+#define V10867 (V + 41240)
+ 0x110e, 0x1173, 0x11bb, 0,
+#undef V10868
+#define V10868 (V + 41244)
+ 0x110e, 0x1173, 0x11bc, 0,
+#undef V10869
+#define V10869 (V + 41248)
+ 0x110e, 0x1173, 0x11bd, 0,
+#undef V10870
+#define V10870 (V + 41252)
+ 0x110e, 0x1173, 0x11be, 0,
+#undef V10871
+#define V10871 (V + 41256)
+ 0x110e, 0x1173, 0x11bf, 0,
+#undef V10872
+#define V10872 (V + 41260)
+ 0x110e, 0x1173, 0x11c0, 0,
+#undef V10873
+#define V10873 (V + 41264)
+ 0x110e, 0x1173, 0x11c1, 0,
+#undef V10874
+#define V10874 (V + 41268)
+ 0x110e, 0x1173, 0x11c2, 0,
+#undef V10875
+#define V10875 (V + 41272)
+ 0x110e, 0x1174, 0,
+#undef V10876
+#define V10876 (V + 41275)
+ 0x110e, 0x1174, 0x11a8, 0,
+#undef V10877
+#define V10877 (V + 41279)
+ 0x110e, 0x1174, 0x11a9, 0,
+#undef V10878
+#define V10878 (V + 41283)
+ 0x110e, 0x1174, 0x11aa, 0,
+#undef V10879
+#define V10879 (V + 41287)
+ 0x110e, 0x1174, 0x11ab, 0,
+#undef V10880
+#define V10880 (V + 41291)
+ 0x110e, 0x1174, 0x11ac, 0,
+#undef V10881
+#define V10881 (V + 41295)
+ 0x110e, 0x1174, 0x11ad, 0,
+#undef V10882
+#define V10882 (V + 41299)
+ 0x110e, 0x1174, 0x11ae, 0,
+#undef V10883
+#define V10883 (V + 41303)
+ 0x110e, 0x1174, 0x11af, 0,
+#undef V10884
+#define V10884 (V + 41307)
+ 0x110e, 0x1174, 0x11b0, 0,
+#undef V10885
+#define V10885 (V + 41311)
+ 0x110e, 0x1174, 0x11b1, 0,
+#undef V10886
+#define V10886 (V + 41315)
+ 0x110e, 0x1174, 0x11b2, 0,
+#undef V10887
+#define V10887 (V + 41319)
+ 0x110e, 0x1174, 0x11b3, 0,
+#undef V10888
+#define V10888 (V + 41323)
+ 0x110e, 0x1174, 0x11b4, 0,
+#undef V10889
+#define V10889 (V + 41327)
+ 0x110e, 0x1174, 0x11b5, 0,
+#undef V10890
+#define V10890 (V + 41331)
+ 0x110e, 0x1174, 0x11b6, 0,
+#undef V10891
+#define V10891 (V + 41335)
+ 0x110e, 0x1174, 0x11b7, 0,
+#undef V10892
+#define V10892 (V + 41339)
+ 0x110e, 0x1174, 0x11b8, 0,
+#undef V10893
+#define V10893 (V + 41343)
+ 0x110e, 0x1174, 0x11b9, 0,
+#undef V10894
+#define V10894 (V + 41347)
+ 0x110e, 0x1174, 0x11ba, 0,
+#undef V10895
+#define V10895 (V + 41351)
+ 0x110e, 0x1174, 0x11bb, 0,
+#undef V10896
+#define V10896 (V + 41355)
+ 0x110e, 0x1174, 0x11bc, 0,
+#undef V10897
+#define V10897 (V + 41359)
+ 0x110e, 0x1174, 0x11bd, 0,
+#undef V10898
+#define V10898 (V + 41363)
+ 0x110e, 0x1174, 0x11be, 0,
+#undef V10899
+#define V10899 (V + 41367)
+ 0x110e, 0x1174, 0x11bf, 0,
+#undef V10900
+#define V10900 (V + 41371)
+ 0x110e, 0x1174, 0x11c0, 0,
+#undef V10901
+#define V10901 (V + 41375)
+ 0x110e, 0x1174, 0x11c1, 0,
+#undef V10902
+#define V10902 (V + 41379)
+ 0x110e, 0x1174, 0x11c2, 0,
+#undef V10903
+#define V10903 (V + 41383)
+ 0x110e, 0x1175, 0,
+#undef V10904
+#define V10904 (V + 41386)
+ 0x110e, 0x1175, 0x11a8, 0,
+#undef V10905
+#define V10905 (V + 41390)
+ 0x110e, 0x1175, 0x11a9, 0,
+#undef V10906
+#define V10906 (V + 41394)
+ 0x110e, 0x1175, 0x11aa, 0,
+#undef V10907
+#define V10907 (V + 41398)
+ 0x110e, 0x1175, 0x11ab, 0,
+#undef V10908
+#define V10908 (V + 41402)
+ 0x110e, 0x1175, 0x11ac, 0,
+#undef V10909
+#define V10909 (V + 41406)
+ 0x110e, 0x1175, 0x11ad, 0,
+#undef V10910
+#define V10910 (V + 41410)
+ 0x110e, 0x1175, 0x11ae, 0,
+#undef V10911
+#define V10911 (V + 41414)
+ 0x110e, 0x1175, 0x11af, 0,
+#undef V10912
+#define V10912 (V + 41418)
+ 0x110e, 0x1175, 0x11b0, 0,
+#undef V10913
+#define V10913 (V + 41422)
+ 0x110e, 0x1175, 0x11b1, 0,
+#undef V10914
+#define V10914 (V + 41426)
+ 0x110e, 0x1175, 0x11b2, 0,
+#undef V10915
+#define V10915 (V + 41430)
+ 0x110e, 0x1175, 0x11b3, 0,
+#undef V10916
+#define V10916 (V + 41434)
+ 0x110e, 0x1175, 0x11b4, 0,
+#undef V10917
+#define V10917 (V + 41438)
+ 0x110e, 0x1175, 0x11b5, 0,
+#undef V10918
+#define V10918 (V + 41442)
+ 0x110e, 0x1175, 0x11b6, 0,
+#undef V10919
+#define V10919 (V + 41446)
+ 0x110e, 0x1175, 0x11b7, 0,
+#undef V10920
+#define V10920 (V + 41450)
+ 0x110e, 0x1175, 0x11b8, 0,
+#undef V10921
+#define V10921 (V + 41454)
+ 0x110e, 0x1175, 0x11b9, 0,
+#undef V10922
+#define V10922 (V + 41458)
+ 0x110e, 0x1175, 0x11ba, 0,
+#undef V10923
+#define V10923 (V + 41462)
+ 0x110e, 0x1175, 0x11bb, 0,
+#undef V10924
+#define V10924 (V + 41466)
+ 0x110e, 0x1175, 0x11bc, 0,
+#undef V10925
+#define V10925 (V + 41470)
+ 0x110e, 0x1175, 0x11bd, 0,
+#undef V10926
+#define V10926 (V + 41474)
+ 0x110e, 0x1175, 0x11be, 0,
+#undef V10927
+#define V10927 (V + 41478)
+ 0x110e, 0x1175, 0x11bf, 0,
+#undef V10928
+#define V10928 (V + 41482)
+ 0x110e, 0x1175, 0x11c0, 0,
+#undef V10929
+#define V10929 (V + 41486)
+ 0x110e, 0x1175, 0x11c1, 0,
+#undef V10930
+#define V10930 (V + 41490)
+ 0x110e, 0x1175, 0x11c2, 0,
+#undef V10931
+#define V10931 (V + 41494)
+ 0x110f, 0x1161, 0x11a8, 0,
+#undef V10932
+#define V10932 (V + 41498)
+ 0x110f, 0x1161, 0x11a9, 0,
+#undef V10933
+#define V10933 (V + 41502)
+ 0x110f, 0x1161, 0x11aa, 0,
+#undef V10934
+#define V10934 (V + 41506)
+ 0x110f, 0x1161, 0x11ab, 0,
+#undef V10935
+#define V10935 (V + 41510)
+ 0x110f, 0x1161, 0x11ac, 0,
+#undef V10936
+#define V10936 (V + 41514)
+ 0x110f, 0x1161, 0x11ad, 0,
+#undef V10937
+#define V10937 (V + 41518)
+ 0x110f, 0x1161, 0x11ae, 0,
+#undef V10938
+#define V10938 (V + 41522)
+ 0x110f, 0x1161, 0x11af, 0,
+#undef V10939
+#define V10939 (V + 41526)
+ 0x110f, 0x1161, 0x11b0, 0,
+#undef V10940
+#define V10940 (V + 41530)
+ 0x110f, 0x1161, 0x11b1, 0,
+#undef V10941
+#define V10941 (V + 41534)
+ 0x110f, 0x1161, 0x11b2, 0,
+#undef V10942
+#define V10942 (V + 41538)
+ 0x110f, 0x1161, 0x11b3, 0,
+#undef V10943
+#define V10943 (V + 41542)
+ 0x110f, 0x1161, 0x11b4, 0,
+#undef V10944
+#define V10944 (V + 41546)
+ 0x110f, 0x1161, 0x11b5, 0,
+#undef V10945
+#define V10945 (V + 41550)
+ 0x110f, 0x1161, 0x11b6, 0,
+#undef V10946
+#define V10946 (V + 41554)
+ 0x110f, 0x1161, 0x11b7, 0,
+#undef V10947
+#define V10947 (V + 41558)
+ 0x110f, 0x1161, 0x11b8, 0,
+#undef V10948
+#define V10948 (V + 41562)
+ 0x110f, 0x1161, 0x11b9, 0,
+#undef V10949
+#define V10949 (V + 41566)
+ 0x110f, 0x1161, 0x11ba, 0,
+#undef V10950
+#define V10950 (V + 41570)
+ 0x110f, 0x1161, 0x11bb, 0,
+#undef V10951
+#define V10951 (V + 41574)
+ 0x110f, 0x1161, 0x11bc, 0,
+#undef V10952
+#define V10952 (V + 41578)
+ 0x110f, 0x1161, 0x11bd, 0,
+#undef V10953
+#define V10953 (V + 41582)
+ 0x110f, 0x1161, 0x11be, 0,
+#undef V10954
+#define V10954 (V + 41586)
+ 0x110f, 0x1161, 0x11bf, 0,
+#undef V10955
+#define V10955 (V + 41590)
+ 0x110f, 0x1161, 0x11c0, 0,
+#undef V10956
+#define V10956 (V + 41594)
+ 0x110f, 0x1161, 0x11c1, 0,
+#undef V10957
+#define V10957 (V + 41598)
+ 0x110f, 0x1161, 0x11c2, 0,
+#undef V10958
+#define V10958 (V + 41602)
+ 0x110f, 0x1162, 0,
+#undef V10959
+#define V10959 (V + 41605)
+ 0x110f, 0x1162, 0x11a8, 0,
+#undef V10960
+#define V10960 (V + 41609)
+ 0x110f, 0x1162, 0x11a9, 0,
+#undef V10961
+#define V10961 (V + 41613)
+ 0x110f, 0x1162, 0x11aa, 0,
+#undef V10962
+#define V10962 (V + 41617)
+ 0x110f, 0x1162, 0x11ab, 0,
+#undef V10963
+#define V10963 (V + 41621)
+ 0x110f, 0x1162, 0x11ac, 0,
+#undef V10964
+#define V10964 (V + 41625)
+ 0x110f, 0x1162, 0x11ad, 0,
+#undef V10965
+#define V10965 (V + 41629)
+ 0x110f, 0x1162, 0x11ae, 0,
+#undef V10966
+#define V10966 (V + 41633)
+ 0x110f, 0x1162, 0x11af, 0,
+#undef V10967
+#define V10967 (V + 41637)
+ 0x110f, 0x1162, 0x11b0, 0,
+#undef V10968
+#define V10968 (V + 41641)
+ 0x110f, 0x1162, 0x11b1, 0,
+#undef V10969
+#define V10969 (V + 41645)
+ 0x110f, 0x1162, 0x11b2, 0,
+#undef V10970
+#define V10970 (V + 41649)
+ 0x110f, 0x1162, 0x11b3, 0,
+#undef V10971
+#define V10971 (V + 41653)
+ 0x110f, 0x1162, 0x11b4, 0,
+#undef V10972
+#define V10972 (V + 41657)
+ 0x110f, 0x1162, 0x11b5, 0,
+#undef V10973
+#define V10973 (V + 41661)
+ 0x110f, 0x1162, 0x11b6, 0,
+#undef V10974
+#define V10974 (V + 41665)
+ 0x110f, 0x1162, 0x11b7, 0,
+#undef V10975
+#define V10975 (V + 41669)
+ 0x110f, 0x1162, 0x11b8, 0,
+#undef V10976
+#define V10976 (V + 41673)
+ 0x110f, 0x1162, 0x11b9, 0,
+#undef V10977
+#define V10977 (V + 41677)
+ 0x110f, 0x1162, 0x11ba, 0,
+#undef V10978
+#define V10978 (V + 41681)
+ 0x110f, 0x1162, 0x11bb, 0,
+#undef V10979
+#define V10979 (V + 41685)
+ 0x110f, 0x1162, 0x11bc, 0,
+#undef V10980
+#define V10980 (V + 41689)
+ 0x110f, 0x1162, 0x11bd, 0,
+#undef V10981
+#define V10981 (V + 41693)
+ 0x110f, 0x1162, 0x11be, 0,
+#undef V10982
+#define V10982 (V + 41697)
+ 0x110f, 0x1162, 0x11bf, 0,
+#undef V10983
+#define V10983 (V + 41701)
+ 0x110f, 0x1162, 0x11c0, 0,
+#undef V10984
+#define V10984 (V + 41705)
+ 0x110f, 0x1162, 0x11c1, 0,
+#undef V10985
+#define V10985 (V + 41709)
+ 0x110f, 0x1162, 0x11c2, 0,
+#undef V10986
+#define V10986 (V + 41713)
+ 0x110f, 0x1163, 0,
+#undef V10987
+#define V10987 (V + 41716)
+ 0x110f, 0x1163, 0x11a8, 0,
+#undef V10988
+#define V10988 (V + 41720)
+ 0x110f, 0x1163, 0x11a9, 0,
+#undef V10989
+#define V10989 (V + 41724)
+ 0x110f, 0x1163, 0x11aa, 0,
+#undef V10990
+#define V10990 (V + 41728)
+ 0x110f, 0x1163, 0x11ab, 0,
+#undef V10991
+#define V10991 (V + 41732)
+ 0x110f, 0x1163, 0x11ac, 0,
+#undef V10992
+#define V10992 (V + 41736)
+ 0x110f, 0x1163, 0x11ad, 0,
+#undef V10993
+#define V10993 (V + 41740)
+ 0x110f, 0x1163, 0x11ae, 0,
+#undef V10994
+#define V10994 (V + 41744)
+ 0x110f, 0x1163, 0x11af, 0,
+#undef V10995
+#define V10995 (V + 41748)
+ 0x110f, 0x1163, 0x11b0, 0,
+#undef V10996
+#define V10996 (V + 41752)
+ 0x110f, 0x1163, 0x11b1, 0,
+#undef V10997
+#define V10997 (V + 41756)
+ 0x110f, 0x1163, 0x11b2, 0,
+#undef V10998
+#define V10998 (V + 41760)
+ 0x110f, 0x1163, 0x11b3, 0,
+#undef V10999
+#define V10999 (V + 41764)
+ 0x110f, 0x1163, 0x11b4, 0,
+#undef V11000
+#define V11000 (V + 41768)
+ 0x110f, 0x1163, 0x11b5, 0,
+#undef V11001
+#define V11001 (V + 41772)
+ 0x110f, 0x1163, 0x11b6, 0,
+#undef V11002
+#define V11002 (V + 41776)
+ 0x110f, 0x1163, 0x11b7, 0,
+#undef V11003
+#define V11003 (V + 41780)
+ 0x110f, 0x1163, 0x11b8, 0,
+#undef V11004
+#define V11004 (V + 41784)
+ 0x110f, 0x1163, 0x11b9, 0,
+#undef V11005
+#define V11005 (V + 41788)
+ 0x110f, 0x1163, 0x11ba, 0,
+#undef V11006
+#define V11006 (V + 41792)
+ 0x110f, 0x1163, 0x11bb, 0,
+#undef V11007
+#define V11007 (V + 41796)
+ 0x110f, 0x1163, 0x11bc, 0,
+#undef V11008
+#define V11008 (V + 41800)
+ 0x110f, 0x1163, 0x11bd, 0,
+#undef V11009
+#define V11009 (V + 41804)
+ 0x110f, 0x1163, 0x11be, 0,
+#undef V11010
+#define V11010 (V + 41808)
+ 0x110f, 0x1163, 0x11bf, 0,
+#undef V11011
+#define V11011 (V + 41812)
+ 0x110f, 0x1163, 0x11c0, 0,
+#undef V11012
+#define V11012 (V + 41816)
+ 0x110f, 0x1163, 0x11c1, 0,
+#undef V11013
+#define V11013 (V + 41820)
+ 0x110f, 0x1163, 0x11c2, 0,
+#undef V11014
+#define V11014 (V + 41824)
+ 0x110f, 0x1164, 0,
+#undef V11015
+#define V11015 (V + 41827)
+ 0x110f, 0x1164, 0x11a8, 0,
+#undef V11016
+#define V11016 (V + 41831)
+ 0x110f, 0x1164, 0x11a9, 0,
+#undef V11017
+#define V11017 (V + 41835)
+ 0x110f, 0x1164, 0x11aa, 0,
+#undef V11018
+#define V11018 (V + 41839)
+ 0x110f, 0x1164, 0x11ab, 0,
+#undef V11019
+#define V11019 (V + 41843)
+ 0x110f, 0x1164, 0x11ac, 0,
+#undef V11020
+#define V11020 (V + 41847)
+ 0x110f, 0x1164, 0x11ad, 0,
+#undef V11021
+#define V11021 (V + 41851)
+ 0x110f, 0x1164, 0x11ae, 0,
+#undef V11022
+#define V11022 (V + 41855)
+ 0x110f, 0x1164, 0x11af, 0,
+#undef V11023
+#define V11023 (V + 41859)
+ 0x110f, 0x1164, 0x11b0, 0,
+#undef V11024
+#define V11024 (V + 41863)
+ 0x110f, 0x1164, 0x11b1, 0,
+#undef V11025
+#define V11025 (V + 41867)
+ 0x110f, 0x1164, 0x11b2, 0,
+#undef V11026
+#define V11026 (V + 41871)
+ 0x110f, 0x1164, 0x11b3, 0,
+#undef V11027
+#define V11027 (V + 41875)
+ 0x110f, 0x1164, 0x11b4, 0,
+#undef V11028
+#define V11028 (V + 41879)
+ 0x110f, 0x1164, 0x11b5, 0,
+#undef V11029
+#define V11029 (V + 41883)
+ 0x110f, 0x1164, 0x11b6, 0,
+#undef V11030
+#define V11030 (V + 41887)
+ 0x110f, 0x1164, 0x11b7, 0,
+#undef V11031
+#define V11031 (V + 41891)
+ 0x110f, 0x1164, 0x11b8, 0,
+#undef V11032
+#define V11032 (V + 41895)
+ 0x110f, 0x1164, 0x11b9, 0,
+#undef V11033
+#define V11033 (V + 41899)
+ 0x110f, 0x1164, 0x11ba, 0,
+#undef V11034
+#define V11034 (V + 41903)
+ 0x110f, 0x1164, 0x11bb, 0,
+#undef V11035
+#define V11035 (V + 41907)
+ 0x110f, 0x1164, 0x11bc, 0,
+#undef V11036
+#define V11036 (V + 41911)
+ 0x110f, 0x1164, 0x11bd, 0,
+#undef V11037
+#define V11037 (V + 41915)
+ 0x110f, 0x1164, 0x11be, 0,
+#undef V11038
+#define V11038 (V + 41919)
+ 0x110f, 0x1164, 0x11bf, 0,
+#undef V11039
+#define V11039 (V + 41923)
+ 0x110f, 0x1164, 0x11c0, 0,
+#undef V11040
+#define V11040 (V + 41927)
+ 0x110f, 0x1164, 0x11c1, 0,
+#undef V11041
+#define V11041 (V + 41931)
+ 0x110f, 0x1164, 0x11c2, 0,
+#undef V11042
+#define V11042 (V + 41935)
+ 0x110f, 0x1165, 0,
+#undef V11043
+#define V11043 (V + 41938)
+ 0x110f, 0x1165, 0x11a8, 0,
+#undef V11044
+#define V11044 (V + 41942)
+ 0x110f, 0x1165, 0x11a9, 0,
+#undef V11045
+#define V11045 (V + 41946)
+ 0x110f, 0x1165, 0x11aa, 0,
+#undef V11046
+#define V11046 (V + 41950)
+ 0x110f, 0x1165, 0x11ab, 0,
+#undef V11047
+#define V11047 (V + 41954)
+ 0x110f, 0x1165, 0x11ac, 0,
+#undef V11048
+#define V11048 (V + 41958)
+ 0x110f, 0x1165, 0x11ad, 0,
+#undef V11049
+#define V11049 (V + 41962)
+ 0x110f, 0x1165, 0x11ae, 0,
+#undef V11050
+#define V11050 (V + 41966)
+ 0x110f, 0x1165, 0x11af, 0,
+#undef V11051
+#define V11051 (V + 41970)
+ 0x110f, 0x1165, 0x11b0, 0,
+#undef V11052
+#define V11052 (V + 41974)
+ 0x110f, 0x1165, 0x11b1, 0,
+#undef V11053
+#define V11053 (V + 41978)
+ 0x110f, 0x1165, 0x11b2, 0,
+#undef V11054
+#define V11054 (V + 41982)
+ 0x110f, 0x1165, 0x11b3, 0,
+#undef V11055
+#define V11055 (V + 41986)
+ 0x110f, 0x1165, 0x11b4, 0,
+#undef V11056
+#define V11056 (V + 41990)
+ 0x110f, 0x1165, 0x11b5, 0,
+#undef V11057
+#define V11057 (V + 41994)
+ 0x110f, 0x1165, 0x11b6, 0,
+#undef V11058
+#define V11058 (V + 41998)
+ 0x110f, 0x1165, 0x11b7, 0,
+#undef V11059
+#define V11059 (V + 42002)
+ 0x110f, 0x1165, 0x11b8, 0,
+#undef V11060
+#define V11060 (V + 42006)
+ 0x110f, 0x1165, 0x11b9, 0,
+#undef V11061
+#define V11061 (V + 42010)
+ 0x110f, 0x1165, 0x11ba, 0,
+#undef V11062
+#define V11062 (V + 42014)
+ 0x110f, 0x1165, 0x11bb, 0,
+#undef V11063
+#define V11063 (V + 42018)
+ 0x110f, 0x1165, 0x11bc, 0,
+#undef V11064
+#define V11064 (V + 42022)
+ 0x110f, 0x1165, 0x11bd, 0,
+#undef V11065
+#define V11065 (V + 42026)
+ 0x110f, 0x1165, 0x11be, 0,
+#undef V11066
+#define V11066 (V + 42030)
+ 0x110f, 0x1165, 0x11bf, 0,
+#undef V11067
+#define V11067 (V + 42034)
+ 0x110f, 0x1165, 0x11c0, 0,
+#undef V11068
+#define V11068 (V + 42038)
+ 0x110f, 0x1165, 0x11c1, 0,
+#undef V11069
+#define V11069 (V + 42042)
+ 0x110f, 0x1165, 0x11c2, 0,
+#undef V11070
+#define V11070 (V + 42046)
+ 0x110f, 0x1166, 0,
+#undef V11071
+#define V11071 (V + 42049)
+ 0x110f, 0x1166, 0x11a8, 0,
+#undef V11072
+#define V11072 (V + 42053)
+ 0x110f, 0x1166, 0x11a9, 0,
+#undef V11073
+#define V11073 (V + 42057)
+ 0x110f, 0x1166, 0x11aa, 0,
+#undef V11074
+#define V11074 (V + 42061)
+ 0x110f, 0x1166, 0x11ab, 0,
+#undef V11075
+#define V11075 (V + 42065)
+ 0x110f, 0x1166, 0x11ac, 0,
+#undef V11076
+#define V11076 (V + 42069)
+ 0x110f, 0x1166, 0x11ad, 0,
+#undef V11077
+#define V11077 (V + 42073)
+ 0x110f, 0x1166, 0x11ae, 0,
+#undef V11078
+#define V11078 (V + 42077)
+ 0x110f, 0x1166, 0x11af, 0,
+#undef V11079
+#define V11079 (V + 42081)
+ 0x110f, 0x1166, 0x11b0, 0,
+#undef V11080
+#define V11080 (V + 42085)
+ 0x110f, 0x1166, 0x11b1, 0,
+#undef V11081
+#define V11081 (V + 42089)
+ 0x110f, 0x1166, 0x11b2, 0,
+#undef V11082
+#define V11082 (V + 42093)
+ 0x110f, 0x1166, 0x11b3, 0,
+#undef V11083
+#define V11083 (V + 42097)
+ 0x110f, 0x1166, 0x11b4, 0,
+#undef V11084
+#define V11084 (V + 42101)
+ 0x110f, 0x1166, 0x11b5, 0,
+#undef V11085
+#define V11085 (V + 42105)
+ 0x110f, 0x1166, 0x11b6, 0,
+#undef V11086
+#define V11086 (V + 42109)
+ 0x110f, 0x1166, 0x11b7, 0,
+#undef V11087
+#define V11087 (V + 42113)
+ 0x110f, 0x1166, 0x11b8, 0,
+#undef V11088
+#define V11088 (V + 42117)
+ 0x110f, 0x1166, 0x11b9, 0,
+#undef V11089
+#define V11089 (V + 42121)
+ 0x110f, 0x1166, 0x11ba, 0,
+#undef V11090
+#define V11090 (V + 42125)
+ 0x110f, 0x1166, 0x11bb, 0,
+#undef V11091
+#define V11091 (V + 42129)
+ 0x110f, 0x1166, 0x11bc, 0,
+#undef V11092
+#define V11092 (V + 42133)
+ 0x110f, 0x1166, 0x11bd, 0,
+#undef V11093
+#define V11093 (V + 42137)
+ 0x110f, 0x1166, 0x11be, 0,
+#undef V11094
+#define V11094 (V + 42141)
+ 0x110f, 0x1166, 0x11bf, 0,
+#undef V11095
+#define V11095 (V + 42145)
+ 0x110f, 0x1166, 0x11c0, 0,
+#undef V11096
+#define V11096 (V + 42149)
+ 0x110f, 0x1166, 0x11c1, 0,
+#undef V11097
+#define V11097 (V + 42153)
+ 0x110f, 0x1166, 0x11c2, 0,
+#undef V11098
+#define V11098 (V + 42157)
+ 0x110f, 0x1167, 0,
+#undef V11099
+#define V11099 (V + 42160)
+ 0x110f, 0x1167, 0x11a8, 0,
+#undef V11100
+#define V11100 (V + 42164)
+ 0x110f, 0x1167, 0x11a9, 0,
+#undef V11101
+#define V11101 (V + 42168)
+ 0x110f, 0x1167, 0x11aa, 0,
+#undef V11102
+#define V11102 (V + 42172)
+ 0x110f, 0x1167, 0x11ab, 0,
+#undef V11103
+#define V11103 (V + 42176)
+ 0x110f, 0x1167, 0x11ac, 0,
+#undef V11104
+#define V11104 (V + 42180)
+ 0x110f, 0x1167, 0x11ad, 0,
+#undef V11105
+#define V11105 (V + 42184)
+ 0x110f, 0x1167, 0x11ae, 0,
+#undef V11106
+#define V11106 (V + 42188)
+ 0x110f, 0x1167, 0x11af, 0,
+#undef V11107
+#define V11107 (V + 42192)
+ 0x110f, 0x1167, 0x11b0, 0,
+#undef V11108
+#define V11108 (V + 42196)
+ 0x110f, 0x1167, 0x11b1, 0,
+#undef V11109
+#define V11109 (V + 42200)
+ 0x110f, 0x1167, 0x11b2, 0,
+#undef V11110
+#define V11110 (V + 42204)
+ 0x110f, 0x1167, 0x11b3, 0,
+#undef V11111
+#define V11111 (V + 42208)
+ 0x110f, 0x1167, 0x11b4, 0,
+#undef V11112
+#define V11112 (V + 42212)
+ 0x110f, 0x1167, 0x11b5, 0,
+#undef V11113
+#define V11113 (V + 42216)
+ 0x110f, 0x1167, 0x11b6, 0,
+#undef V11114
+#define V11114 (V + 42220)
+ 0x110f, 0x1167, 0x11b7, 0,
+#undef V11115
+#define V11115 (V + 42224)
+ 0x110f, 0x1167, 0x11b8, 0,
+#undef V11116
+#define V11116 (V + 42228)
+ 0x110f, 0x1167, 0x11b9, 0,
+#undef V11117
+#define V11117 (V + 42232)
+ 0x110f, 0x1167, 0x11ba, 0,
+#undef V11118
+#define V11118 (V + 42236)
+ 0x110f, 0x1167, 0x11bb, 0,
+#undef V11119
+#define V11119 (V + 42240)
+ 0x110f, 0x1167, 0x11bc, 0,
+#undef V11120
+#define V11120 (V + 42244)
+ 0x110f, 0x1167, 0x11bd, 0,
+#undef V11121
+#define V11121 (V + 42248)
+ 0x110f, 0x1167, 0x11be, 0,
+#undef V11122
+#define V11122 (V + 42252)
+ 0x110f, 0x1167, 0x11bf, 0,
+#undef V11123
+#define V11123 (V + 42256)
+ 0x110f, 0x1167, 0x11c0, 0,
+#undef V11124
+#define V11124 (V + 42260)
+ 0x110f, 0x1167, 0x11c1, 0,
+#undef V11125
+#define V11125 (V + 42264)
+ 0x110f, 0x1167, 0x11c2, 0,
+#undef V11126
+#define V11126 (V + 42268)
+ 0x110f, 0x1168, 0,
+#undef V11127
+#define V11127 (V + 42271)
+ 0x110f, 0x1168, 0x11a8, 0,
+#undef V11128
+#define V11128 (V + 42275)
+ 0x110f, 0x1168, 0x11a9, 0,
+#undef V11129
+#define V11129 (V + 42279)
+ 0x110f, 0x1168, 0x11aa, 0,
+#undef V11130
+#define V11130 (V + 42283)
+ 0x110f, 0x1168, 0x11ab, 0,
+#undef V11131
+#define V11131 (V + 42287)
+ 0x110f, 0x1168, 0x11ac, 0,
+#undef V11132
+#define V11132 (V + 42291)
+ 0x110f, 0x1168, 0x11ad, 0,
+#undef V11133
+#define V11133 (V + 42295)
+ 0x110f, 0x1168, 0x11ae, 0,
+#undef V11134
+#define V11134 (V + 42299)
+ 0x110f, 0x1168, 0x11af, 0,
+#undef V11135
+#define V11135 (V + 42303)
+ 0x110f, 0x1168, 0x11b0, 0,
+#undef V11136
+#define V11136 (V + 42307)
+ 0x110f, 0x1168, 0x11b1, 0,
+#undef V11137
+#define V11137 (V + 42311)
+ 0x110f, 0x1168, 0x11b2, 0,
+#undef V11138
+#define V11138 (V + 42315)
+ 0x110f, 0x1168, 0x11b3, 0,
+#undef V11139
+#define V11139 (V + 42319)
+ 0x110f, 0x1168, 0x11b4, 0,
+#undef V11140
+#define V11140 (V + 42323)
+ 0x110f, 0x1168, 0x11b5, 0,
+#undef V11141
+#define V11141 (V + 42327)
+ 0x110f, 0x1168, 0x11b6, 0,
+#undef V11142
+#define V11142 (V + 42331)
+ 0x110f, 0x1168, 0x11b7, 0,
+#undef V11143
+#define V11143 (V + 42335)
+ 0x110f, 0x1168, 0x11b8, 0,
+#undef V11144
+#define V11144 (V + 42339)
+ 0x110f, 0x1168, 0x11b9, 0,
+#undef V11145
+#define V11145 (V + 42343)
+ 0x110f, 0x1168, 0x11ba, 0,
+#undef V11146
+#define V11146 (V + 42347)
+ 0x110f, 0x1168, 0x11bb, 0,
+#undef V11147
+#define V11147 (V + 42351)
+ 0x110f, 0x1168, 0x11bc, 0,
+#undef V11148
+#define V11148 (V + 42355)
+ 0x110f, 0x1168, 0x11bd, 0,
+#undef V11149
+#define V11149 (V + 42359)
+ 0x110f, 0x1168, 0x11be, 0,
+#undef V11150
+#define V11150 (V + 42363)
+ 0x110f, 0x1168, 0x11bf, 0,
+#undef V11151
+#define V11151 (V + 42367)
+ 0x110f, 0x1168, 0x11c0, 0,
+#undef V11152
+#define V11152 (V + 42371)
+ 0x110f, 0x1168, 0x11c1, 0,
+#undef V11153
+#define V11153 (V + 42375)
+ 0x110f, 0x1168, 0x11c2, 0,
+#undef V11154
+#define V11154 (V + 42379)
+ 0x110f, 0x1169, 0,
+#undef V11155
+#define V11155 (V + 42382)
+ 0x110f, 0x1169, 0x11a8, 0,
+#undef V11156
+#define V11156 (V + 42386)
+ 0x110f, 0x1169, 0x11a9, 0,
+#undef V11157
+#define V11157 (V + 42390)
+ 0x110f, 0x1169, 0x11aa, 0,
+#undef V11158
+#define V11158 (V + 42394)
+ 0x110f, 0x1169, 0x11ab, 0,
+#undef V11159
+#define V11159 (V + 42398)
+ 0x110f, 0x1169, 0x11ac, 0,
+#undef V11160
+#define V11160 (V + 42402)
+ 0x110f, 0x1169, 0x11ad, 0,
+#undef V11161
+#define V11161 (V + 42406)
+ 0x110f, 0x1169, 0x11ae, 0,
+#undef V11162
+#define V11162 (V + 42410)
+ 0x110f, 0x1169, 0x11af, 0,
+#undef V11163
+#define V11163 (V + 42414)
+ 0x110f, 0x1169, 0x11b0, 0,
+#undef V11164
+#define V11164 (V + 42418)
+ 0x110f, 0x1169, 0x11b1, 0,
+#undef V11165
+#define V11165 (V + 42422)
+ 0x110f, 0x1169, 0x11b2, 0,
+#undef V11166
+#define V11166 (V + 42426)
+ 0x110f, 0x1169, 0x11b3, 0,
+#undef V11167
+#define V11167 (V + 42430)
+ 0x110f, 0x1169, 0x11b4, 0,
+#undef V11168
+#define V11168 (V + 42434)
+ 0x110f, 0x1169, 0x11b5, 0,
+#undef V11169
+#define V11169 (V + 42438)
+ 0x110f, 0x1169, 0x11b6, 0,
+#undef V11170
+#define V11170 (V + 42442)
+ 0x110f, 0x1169, 0x11b7, 0,
+#undef V11171
+#define V11171 (V + 42446)
+ 0x110f, 0x1169, 0x11b8, 0,
+#undef V11172
+#define V11172 (V + 42450)
+ 0x110f, 0x1169, 0x11b9, 0,
+#undef V11173
+#define V11173 (V + 42454)
+ 0x110f, 0x1169, 0x11ba, 0,
+#undef V11174
+#define V11174 (V + 42458)
+ 0x110f, 0x1169, 0x11bb, 0,
+#undef V11175
+#define V11175 (V + 42462)
+ 0x110f, 0x1169, 0x11bc, 0,
+#undef V11176
+#define V11176 (V + 42466)
+ 0x110f, 0x1169, 0x11bd, 0,
+#undef V11177
+#define V11177 (V + 42470)
+ 0x110f, 0x1169, 0x11be, 0,
+#undef V11178
+#define V11178 (V + 42474)
+ 0x110f, 0x1169, 0x11bf, 0,
+#undef V11179
+#define V11179 (V + 42478)
+ 0x110f, 0x1169, 0x11c0, 0,
+#undef V11180
+#define V11180 (V + 42482)
+ 0x110f, 0x1169, 0x11c1, 0,
+#undef V11181
+#define V11181 (V + 42486)
+ 0x110f, 0x1169, 0x11c2, 0,
+#undef V11182
+#define V11182 (V + 42490)
+ 0x110f, 0x116a, 0,
+#undef V11183
+#define V11183 (V + 42493)
+ 0x110f, 0x116a, 0x11a8, 0,
+#undef V11184
+#define V11184 (V + 42497)
+ 0x110f, 0x116a, 0x11a9, 0,
+#undef V11185
+#define V11185 (V + 42501)
+ 0x110f, 0x116a, 0x11aa, 0,
+#undef V11186
+#define V11186 (V + 42505)
+ 0x110f, 0x116a, 0x11ab, 0,
+#undef V11187
+#define V11187 (V + 42509)
+ 0x110f, 0x116a, 0x11ac, 0,
+#undef V11188
+#define V11188 (V + 42513)
+ 0x110f, 0x116a, 0x11ad, 0,
+#undef V11189
+#define V11189 (V + 42517)
+ 0x110f, 0x116a, 0x11ae, 0,
+#undef V11190
+#define V11190 (V + 42521)
+ 0x110f, 0x116a, 0x11af, 0,
+#undef V11191
+#define V11191 (V + 42525)
+ 0x110f, 0x116a, 0x11b0, 0,
+#undef V11192
+#define V11192 (V + 42529)
+ 0x110f, 0x116a, 0x11b1, 0,
+#undef V11193
+#define V11193 (V + 42533)
+ 0x110f, 0x116a, 0x11b2, 0,
+#undef V11194
+#define V11194 (V + 42537)
+ 0x110f, 0x116a, 0x11b3, 0,
+#undef V11195
+#define V11195 (V + 42541)
+ 0x110f, 0x116a, 0x11b4, 0,
+#undef V11196
+#define V11196 (V + 42545)
+ 0x110f, 0x116a, 0x11b5, 0,
+#undef V11197
+#define V11197 (V + 42549)
+ 0x110f, 0x116a, 0x11b6, 0,
+#undef V11198
+#define V11198 (V + 42553)
+ 0x110f, 0x116a, 0x11b7, 0,
+#undef V11199
+#define V11199 (V + 42557)
+ 0x110f, 0x116a, 0x11b8, 0,
+#undef V11200
+#define V11200 (V + 42561)
+ 0x110f, 0x116a, 0x11b9, 0,
+#undef V11201
+#define V11201 (V + 42565)
+ 0x110f, 0x116a, 0x11ba, 0,
+#undef V11202
+#define V11202 (V + 42569)
+ 0x110f, 0x116a, 0x11bb, 0,
+#undef V11203
+#define V11203 (V + 42573)
+ 0x110f, 0x116a, 0x11bc, 0,
+#undef V11204
+#define V11204 (V + 42577)
+ 0x110f, 0x116a, 0x11bd, 0,
+#undef V11205
+#define V11205 (V + 42581)
+ 0x110f, 0x116a, 0x11be, 0,
+#undef V11206
+#define V11206 (V + 42585)
+ 0x110f, 0x116a, 0x11bf, 0,
+#undef V11207
+#define V11207 (V + 42589)
+ 0x110f, 0x116a, 0x11c0, 0,
+#undef V11208
+#define V11208 (V + 42593)
+ 0x110f, 0x116a, 0x11c1, 0,
+#undef V11209
+#define V11209 (V + 42597)
+ 0x110f, 0x116a, 0x11c2, 0,
+#undef V11210
+#define V11210 (V + 42601)
+ 0x110f, 0x116b, 0,
+#undef V11211
+#define V11211 (V + 42604)
+ 0x110f, 0x116b, 0x11a8, 0,
+#undef V11212
+#define V11212 (V + 42608)
+ 0x110f, 0x116b, 0x11a9, 0,
+#undef V11213
+#define V11213 (V + 42612)
+ 0x110f, 0x116b, 0x11aa, 0,
+#undef V11214
+#define V11214 (V + 42616)
+ 0x110f, 0x116b, 0x11ab, 0,
+#undef V11215
+#define V11215 (V + 42620)
+ 0x110f, 0x116b, 0x11ac, 0,
+#undef V11216
+#define V11216 (V + 42624)
+ 0x110f, 0x116b, 0x11ad, 0,
+#undef V11217
+#define V11217 (V + 42628)
+ 0x110f, 0x116b, 0x11ae, 0,
+#undef V11218
+#define V11218 (V + 42632)
+ 0x110f, 0x116b, 0x11af, 0,
+#undef V11219
+#define V11219 (V + 42636)
+ 0x110f, 0x116b, 0x11b0, 0,
+#undef V11220
+#define V11220 (V + 42640)
+ 0x110f, 0x116b, 0x11b1, 0,
+#undef V11221
+#define V11221 (V + 42644)
+ 0x110f, 0x116b, 0x11b2, 0,
+#undef V11222
+#define V11222 (V + 42648)
+ 0x110f, 0x116b, 0x11b3, 0,
+#undef V11223
+#define V11223 (V + 42652)
+ 0x110f, 0x116b, 0x11b4, 0,
+#undef V11224
+#define V11224 (V + 42656)
+ 0x110f, 0x116b, 0x11b5, 0,
+#undef V11225
+#define V11225 (V + 42660)
+ 0x110f, 0x116b, 0x11b6, 0,
+#undef V11226
+#define V11226 (V + 42664)
+ 0x110f, 0x116b, 0x11b7, 0,
+#undef V11227
+#define V11227 (V + 42668)
+ 0x110f, 0x116b, 0x11b8, 0,
+#undef V11228
+#define V11228 (V + 42672)
+ 0x110f, 0x116b, 0x11b9, 0,
+#undef V11229
+#define V11229 (V + 42676)
+ 0x110f, 0x116b, 0x11ba, 0,
+#undef V11230
+#define V11230 (V + 42680)
+ 0x110f, 0x116b, 0x11bb, 0,
+#undef V11231
+#define V11231 (V + 42684)
+ 0x110f, 0x116b, 0x11bc, 0,
+#undef V11232
+#define V11232 (V + 42688)
+ 0x110f, 0x116b, 0x11bd, 0,
+#undef V11233
+#define V11233 (V + 42692)
+ 0x110f, 0x116b, 0x11be, 0,
+#undef V11234
+#define V11234 (V + 42696)
+ 0x110f, 0x116b, 0x11bf, 0,
+#undef V11235
+#define V11235 (V + 42700)
+ 0x110f, 0x116b, 0x11c0, 0,
+#undef V11236
+#define V11236 (V + 42704)
+ 0x110f, 0x116b, 0x11c1, 0,
+#undef V11237
+#define V11237 (V + 42708)
+ 0x110f, 0x116b, 0x11c2, 0,
+#undef V11238
+#define V11238 (V + 42712)
+ 0x110f, 0x116c, 0,
+#undef V11239
+#define V11239 (V + 42715)
+ 0x110f, 0x116c, 0x11a8, 0,
+#undef V11240
+#define V11240 (V + 42719)
+ 0x110f, 0x116c, 0x11a9, 0,
+#undef V11241
+#define V11241 (V + 42723)
+ 0x110f, 0x116c, 0x11aa, 0,
+#undef V11242
+#define V11242 (V + 42727)
+ 0x110f, 0x116c, 0x11ab, 0,
+#undef V11243
+#define V11243 (V + 42731)
+ 0x110f, 0x116c, 0x11ac, 0,
+#undef V11244
+#define V11244 (V + 42735)
+ 0x110f, 0x116c, 0x11ad, 0,
+#undef V11245
+#define V11245 (V + 42739)
+ 0x110f, 0x116c, 0x11ae, 0,
+#undef V11246
+#define V11246 (V + 42743)
+ 0x110f, 0x116c, 0x11af, 0,
+#undef V11247
+#define V11247 (V + 42747)
+ 0x110f, 0x116c, 0x11b0, 0,
+#undef V11248
+#define V11248 (V + 42751)
+ 0x110f, 0x116c, 0x11b1, 0,
+#undef V11249
+#define V11249 (V + 42755)
+ 0x110f, 0x116c, 0x11b2, 0,
+#undef V11250
+#define V11250 (V + 42759)
+ 0x110f, 0x116c, 0x11b3, 0,
+#undef V11251
+#define V11251 (V + 42763)
+ 0x110f, 0x116c, 0x11b4, 0,
+#undef V11252
+#define V11252 (V + 42767)
+ 0x110f, 0x116c, 0x11b5, 0,
+#undef V11253
+#define V11253 (V + 42771)
+ 0x110f, 0x116c, 0x11b6, 0,
+#undef V11254
+#define V11254 (V + 42775)
+ 0x110f, 0x116c, 0x11b7, 0,
+#undef V11255
+#define V11255 (V + 42779)
+ 0x110f, 0x116c, 0x11b8, 0,
+#undef V11256
+#define V11256 (V + 42783)
+ 0x110f, 0x116c, 0x11b9, 0,
+#undef V11257
+#define V11257 (V + 42787)
+ 0x110f, 0x116c, 0x11ba, 0,
+#undef V11258
+#define V11258 (V + 42791)
+ 0x110f, 0x116c, 0x11bb, 0,
+#undef V11259
+#define V11259 (V + 42795)
+ 0x110f, 0x116c, 0x11bc, 0,
+#undef V11260
+#define V11260 (V + 42799)
+ 0x110f, 0x116c, 0x11bd, 0,
+#undef V11261
+#define V11261 (V + 42803)
+ 0x110f, 0x116c, 0x11be, 0,
+#undef V11262
+#define V11262 (V + 42807)
+ 0x110f, 0x116c, 0x11bf, 0,
+#undef V11263
+#define V11263 (V + 42811)
+ 0x110f, 0x116c, 0x11c0, 0,
+#undef V11264
+#define V11264 (V + 42815)
+ 0x110f, 0x116c, 0x11c1, 0,
+#undef V11265
+#define V11265 (V + 42819)
+ 0x110f, 0x116c, 0x11c2, 0,
+#undef V11266
+#define V11266 (V + 42823)
+ 0x110f, 0x116d, 0,
+#undef V11267
+#define V11267 (V + 42826)
+ 0x110f, 0x116d, 0x11a8, 0,
+#undef V11268
+#define V11268 (V + 42830)
+ 0x110f, 0x116d, 0x11a9, 0,
+#undef V11269
+#define V11269 (V + 42834)
+ 0x110f, 0x116d, 0x11aa, 0,
+#undef V11270
+#define V11270 (V + 42838)
+ 0x110f, 0x116d, 0x11ab, 0,
+#undef V11271
+#define V11271 (V + 42842)
+ 0x110f, 0x116d, 0x11ac, 0,
+#undef V11272
+#define V11272 (V + 42846)
+ 0x110f, 0x116d, 0x11ad, 0,
+#undef V11273
+#define V11273 (V + 42850)
+ 0x110f, 0x116d, 0x11ae, 0,
+#undef V11274
+#define V11274 (V + 42854)
+ 0x110f, 0x116d, 0x11af, 0,
+#undef V11275
+#define V11275 (V + 42858)
+ 0x110f, 0x116d, 0x11b0, 0,
+#undef V11276
+#define V11276 (V + 42862)
+ 0x110f, 0x116d, 0x11b1, 0,
+#undef V11277
+#define V11277 (V + 42866)
+ 0x110f, 0x116d, 0x11b2, 0,
+#undef V11278
+#define V11278 (V + 42870)
+ 0x110f, 0x116d, 0x11b3, 0,
+#undef V11279
+#define V11279 (V + 42874)
+ 0x110f, 0x116d, 0x11b4, 0,
+#undef V11280
+#define V11280 (V + 42878)
+ 0x110f, 0x116d, 0x11b5, 0,
+#undef V11281
+#define V11281 (V + 42882)
+ 0x110f, 0x116d, 0x11b6, 0,
+#undef V11282
+#define V11282 (V + 42886)
+ 0x110f, 0x116d, 0x11b7, 0,
+#undef V11283
+#define V11283 (V + 42890)
+ 0x110f, 0x116d, 0x11b8, 0,
+#undef V11284
+#define V11284 (V + 42894)
+ 0x110f, 0x116d, 0x11b9, 0,
+#undef V11285
+#define V11285 (V + 42898)
+ 0x110f, 0x116d, 0x11ba, 0,
+#undef V11286
+#define V11286 (V + 42902)
+ 0x110f, 0x116d, 0x11bb, 0,
+#undef V11287
+#define V11287 (V + 42906)
+ 0x110f, 0x116d, 0x11bc, 0,
+#undef V11288
+#define V11288 (V + 42910)
+ 0x110f, 0x116d, 0x11bd, 0,
+#undef V11289
+#define V11289 (V + 42914)
+ 0x110f, 0x116d, 0x11be, 0,
+#undef V11290
+#define V11290 (V + 42918)
+ 0x110f, 0x116d, 0x11bf, 0,
+#undef V11291
+#define V11291 (V + 42922)
+ 0x110f, 0x116d, 0x11c0, 0,
+#undef V11292
+#define V11292 (V + 42926)
+ 0x110f, 0x116d, 0x11c1, 0,
+#undef V11293
+#define V11293 (V + 42930)
+ 0x110f, 0x116d, 0x11c2, 0,
+#undef V11294
+#define V11294 (V + 42934)
+ 0x110f, 0x116e, 0,
+#undef V11295
+#define V11295 (V + 42937)
+ 0x110f, 0x116e, 0x11a8, 0,
+#undef V11296
+#define V11296 (V + 42941)
+ 0x110f, 0x116e, 0x11a9, 0,
+#undef V11297
+#define V11297 (V + 42945)
+ 0x110f, 0x116e, 0x11aa, 0,
+#undef V11298
+#define V11298 (V + 42949)
+ 0x110f, 0x116e, 0x11ab, 0,
+#undef V11299
+#define V11299 (V + 42953)
+ 0x110f, 0x116e, 0x11ac, 0,
+#undef V11300
+#define V11300 (V + 42957)
+ 0x110f, 0x116e, 0x11ad, 0,
+#undef V11301
+#define V11301 (V + 42961)
+ 0x110f, 0x116e, 0x11ae, 0,
+#undef V11302
+#define V11302 (V + 42965)
+ 0x110f, 0x116e, 0x11af, 0,
+#undef V11303
+#define V11303 (V + 42969)
+ 0x110f, 0x116e, 0x11b0, 0,
+#undef V11304
+#define V11304 (V + 42973)
+ 0x110f, 0x116e, 0x11b1, 0,
+#undef V11305
+#define V11305 (V + 42977)
+ 0x110f, 0x116e, 0x11b2, 0,
+#undef V11306
+#define V11306 (V + 42981)
+ 0x110f, 0x116e, 0x11b3, 0,
+#undef V11307
+#define V11307 (V + 42985)
+ 0x110f, 0x116e, 0x11b4, 0,
+#undef V11308
+#define V11308 (V + 42989)
+ 0x110f, 0x116e, 0x11b5, 0,
+#undef V11309
+#define V11309 (V + 42993)
+ 0x110f, 0x116e, 0x11b6, 0,
+#undef V11310
+#define V11310 (V + 42997)
+ 0x110f, 0x116e, 0x11b7, 0,
+#undef V11311
+#define V11311 (V + 43001)
+ 0x110f, 0x116e, 0x11b8, 0,
+#undef V11312
+#define V11312 (V + 43005)
+ 0x110f, 0x116e, 0x11b9, 0,
+#undef V11313
+#define V11313 (V + 43009)
+ 0x110f, 0x116e, 0x11ba, 0,
+#undef V11314
+#define V11314 (V + 43013)
+ 0x110f, 0x116e, 0x11bb, 0,
+#undef V11315
+#define V11315 (V + 43017)
+ 0x110f, 0x116e, 0x11bc, 0,
+#undef V11316
+#define V11316 (V + 43021)
+ 0x110f, 0x116e, 0x11bd, 0,
+#undef V11317
+#define V11317 (V + 43025)
+ 0x110f, 0x116e, 0x11be, 0,
+#undef V11318
+#define V11318 (V + 43029)
+ 0x110f, 0x116e, 0x11bf, 0,
+#undef V11319
+#define V11319 (V + 43033)
+ 0x110f, 0x116e, 0x11c0, 0,
+#undef V11320
+#define V11320 (V + 43037)
+ 0x110f, 0x116e, 0x11c1, 0,
+#undef V11321
+#define V11321 (V + 43041)
+ 0x110f, 0x116e, 0x11c2, 0,
+#undef V11322
+#define V11322 (V + 43045)
+ 0x110f, 0x116f, 0,
+#undef V11323
+#define V11323 (V + 43048)
+ 0x110f, 0x116f, 0x11a8, 0,
+#undef V11324
+#define V11324 (V + 43052)
+ 0x110f, 0x116f, 0x11a9, 0,
+#undef V11325
+#define V11325 (V + 43056)
+ 0x110f, 0x116f, 0x11aa, 0,
+#undef V11326
+#define V11326 (V + 43060)
+ 0x110f, 0x116f, 0x11ab, 0,
+#undef V11327
+#define V11327 (V + 43064)
+ 0x110f, 0x116f, 0x11ac, 0,
+#undef V11328
+#define V11328 (V + 43068)
+ 0x110f, 0x116f, 0x11ad, 0,
+#undef V11329
+#define V11329 (V + 43072)
+ 0x110f, 0x116f, 0x11ae, 0,
+#undef V11330
+#define V11330 (V + 43076)
+ 0x110f, 0x116f, 0x11af, 0,
+#undef V11331
+#define V11331 (V + 43080)
+ 0x110f, 0x116f, 0x11b0, 0,
+#undef V11332
+#define V11332 (V + 43084)
+ 0x110f, 0x116f, 0x11b1, 0,
+#undef V11333
+#define V11333 (V + 43088)
+ 0x110f, 0x116f, 0x11b2, 0,
+#undef V11334
+#define V11334 (V + 43092)
+ 0x110f, 0x116f, 0x11b3, 0,
+#undef V11335
+#define V11335 (V + 43096)
+ 0x110f, 0x116f, 0x11b4, 0,
+#undef V11336
+#define V11336 (V + 43100)
+ 0x110f, 0x116f, 0x11b5, 0,
+#undef V11337
+#define V11337 (V + 43104)
+ 0x110f, 0x116f, 0x11b6, 0,
+#undef V11338
+#define V11338 (V + 43108)
+ 0x110f, 0x116f, 0x11b7, 0,
+#undef V11339
+#define V11339 (V + 43112)
+ 0x110f, 0x116f, 0x11b8, 0,
+#undef V11340
+#define V11340 (V + 43116)
+ 0x110f, 0x116f, 0x11b9, 0,
+#undef V11341
+#define V11341 (V + 43120)
+ 0x110f, 0x116f, 0x11ba, 0,
+#undef V11342
+#define V11342 (V + 43124)
+ 0x110f, 0x116f, 0x11bb, 0,
+#undef V11343
+#define V11343 (V + 43128)
+ 0x110f, 0x116f, 0x11bc, 0,
+#undef V11344
+#define V11344 (V + 43132)
+ 0x110f, 0x116f, 0x11bd, 0,
+#undef V11345
+#define V11345 (V + 43136)
+ 0x110f, 0x116f, 0x11be, 0,
+#undef V11346
+#define V11346 (V + 43140)
+ 0x110f, 0x116f, 0x11bf, 0,
+#undef V11347
+#define V11347 (V + 43144)
+ 0x110f, 0x116f, 0x11c0, 0,
+#undef V11348
+#define V11348 (V + 43148)
+ 0x110f, 0x116f, 0x11c1, 0,
+#undef V11349
+#define V11349 (V + 43152)
+ 0x110f, 0x116f, 0x11c2, 0,
+#undef V11350
+#define V11350 (V + 43156)
+ 0x110f, 0x1170, 0,
+#undef V11351
+#define V11351 (V + 43159)
+ 0x110f, 0x1170, 0x11a8, 0,
+#undef V11352
+#define V11352 (V + 43163)
+ 0x110f, 0x1170, 0x11a9, 0,
+#undef V11353
+#define V11353 (V + 43167)
+ 0x110f, 0x1170, 0x11aa, 0,
+#undef V11354
+#define V11354 (V + 43171)
+ 0x110f, 0x1170, 0x11ab, 0,
+#undef V11355
+#define V11355 (V + 43175)
+ 0x110f, 0x1170, 0x11ac, 0,
+#undef V11356
+#define V11356 (V + 43179)
+ 0x110f, 0x1170, 0x11ad, 0,
+#undef V11357
+#define V11357 (V + 43183)
+ 0x110f, 0x1170, 0x11ae, 0,
+#undef V11358
+#define V11358 (V + 43187)
+ 0x110f, 0x1170, 0x11af, 0,
+#undef V11359
+#define V11359 (V + 43191)
+ 0x110f, 0x1170, 0x11b0, 0,
+#undef V11360
+#define V11360 (V + 43195)
+ 0x110f, 0x1170, 0x11b1, 0,
+#undef V11361
+#define V11361 (V + 43199)
+ 0x110f, 0x1170, 0x11b2, 0,
+#undef V11362
+#define V11362 (V + 43203)
+ 0x110f, 0x1170, 0x11b3, 0,
+#undef V11363
+#define V11363 (V + 43207)
+ 0x110f, 0x1170, 0x11b4, 0,
+#undef V11364
+#define V11364 (V + 43211)
+ 0x110f, 0x1170, 0x11b5, 0,
+#undef V11365
+#define V11365 (V + 43215)
+ 0x110f, 0x1170, 0x11b6, 0,
+#undef V11366
+#define V11366 (V + 43219)
+ 0x110f, 0x1170, 0x11b7, 0,
+#undef V11367
+#define V11367 (V + 43223)
+ 0x110f, 0x1170, 0x11b8, 0,
+#undef V11368
+#define V11368 (V + 43227)
+ 0x110f, 0x1170, 0x11b9, 0,
+#undef V11369
+#define V11369 (V + 43231)
+ 0x110f, 0x1170, 0x11ba, 0,
+#undef V11370
+#define V11370 (V + 43235)
+ 0x110f, 0x1170, 0x11bb, 0,
+#undef V11371
+#define V11371 (V + 43239)
+ 0x110f, 0x1170, 0x11bc, 0,
+#undef V11372
+#define V11372 (V + 43243)
+ 0x110f, 0x1170, 0x11bd, 0,
+#undef V11373
+#define V11373 (V + 43247)
+ 0x110f, 0x1170, 0x11be, 0,
+#undef V11374
+#define V11374 (V + 43251)
+ 0x110f, 0x1170, 0x11bf, 0,
+#undef V11375
+#define V11375 (V + 43255)
+ 0x110f, 0x1170, 0x11c0, 0,
+#undef V11376
+#define V11376 (V + 43259)
+ 0x110f, 0x1170, 0x11c1, 0,
+#undef V11377
+#define V11377 (V + 43263)
+ 0x110f, 0x1170, 0x11c2, 0,
+#undef V11378
+#define V11378 (V + 43267)
+ 0x110f, 0x1171, 0,
+#undef V11379
+#define V11379 (V + 43270)
+ 0x110f, 0x1171, 0x11a8, 0,
+#undef V11380
+#define V11380 (V + 43274)
+ 0x110f, 0x1171, 0x11a9, 0,
+#undef V11381
+#define V11381 (V + 43278)
+ 0x110f, 0x1171, 0x11aa, 0,
+#undef V11382
+#define V11382 (V + 43282)
+ 0x110f, 0x1171, 0x11ab, 0,
+#undef V11383
+#define V11383 (V + 43286)
+ 0x110f, 0x1171, 0x11ac, 0,
+#undef V11384
+#define V11384 (V + 43290)
+ 0x110f, 0x1171, 0x11ad, 0,
+#undef V11385
+#define V11385 (V + 43294)
+ 0x110f, 0x1171, 0x11ae, 0,
+#undef V11386
+#define V11386 (V + 43298)
+ 0x110f, 0x1171, 0x11af, 0,
+#undef V11387
+#define V11387 (V + 43302)
+ 0x110f, 0x1171, 0x11b0, 0,
+#undef V11388
+#define V11388 (V + 43306)
+ 0x110f, 0x1171, 0x11b1, 0,
+#undef V11389
+#define V11389 (V + 43310)
+ 0x110f, 0x1171, 0x11b2, 0,
+#undef V11390
+#define V11390 (V + 43314)
+ 0x110f, 0x1171, 0x11b3, 0,
+#undef V11391
+#define V11391 (V + 43318)
+ 0x110f, 0x1171, 0x11b4, 0,
+#undef V11392
+#define V11392 (V + 43322)
+ 0x110f, 0x1171, 0x11b5, 0,
+#undef V11393
+#define V11393 (V + 43326)
+ 0x110f, 0x1171, 0x11b6, 0,
+#undef V11394
+#define V11394 (V + 43330)
+ 0x110f, 0x1171, 0x11b7, 0,
+#undef V11395
+#define V11395 (V + 43334)
+ 0x110f, 0x1171, 0x11b8, 0,
+#undef V11396
+#define V11396 (V + 43338)
+ 0x110f, 0x1171, 0x11b9, 0,
+#undef V11397
+#define V11397 (V + 43342)
+ 0x110f, 0x1171, 0x11ba, 0,
+#undef V11398
+#define V11398 (V + 43346)
+ 0x110f, 0x1171, 0x11bb, 0,
+#undef V11399
+#define V11399 (V + 43350)
+ 0x110f, 0x1171, 0x11bc, 0,
+#undef V11400
+#define V11400 (V + 43354)
+ 0x110f, 0x1171, 0x11bd, 0,
+#undef V11401
+#define V11401 (V + 43358)
+ 0x110f, 0x1171, 0x11be, 0,
+#undef V11402
+#define V11402 (V + 43362)
+ 0x110f, 0x1171, 0x11bf, 0,
+#undef V11403
+#define V11403 (V + 43366)
+ 0x110f, 0x1171, 0x11c0, 0,
+#undef V11404
+#define V11404 (V + 43370)
+ 0x110f, 0x1171, 0x11c1, 0,
+#undef V11405
+#define V11405 (V + 43374)
+ 0x110f, 0x1171, 0x11c2, 0,
+#undef V11406
+#define V11406 (V + 43378)
+ 0x110f, 0x1172, 0,
+#undef V11407
+#define V11407 (V + 43381)
+ 0x110f, 0x1172, 0x11a8, 0,
+#undef V11408
+#define V11408 (V + 43385)
+ 0x110f, 0x1172, 0x11a9, 0,
+#undef V11409
+#define V11409 (V + 43389)
+ 0x110f, 0x1172, 0x11aa, 0,
+#undef V11410
+#define V11410 (V + 43393)
+ 0x110f, 0x1172, 0x11ab, 0,
+#undef V11411
+#define V11411 (V + 43397)
+ 0x110f, 0x1172, 0x11ac, 0,
+#undef V11412
+#define V11412 (V + 43401)
+ 0x110f, 0x1172, 0x11ad, 0,
+#undef V11413
+#define V11413 (V + 43405)
+ 0x110f, 0x1172, 0x11ae, 0,
+#undef V11414
+#define V11414 (V + 43409)
+ 0x110f, 0x1172, 0x11af, 0,
+#undef V11415
+#define V11415 (V + 43413)
+ 0x110f, 0x1172, 0x11b0, 0,
+#undef V11416
+#define V11416 (V + 43417)
+ 0x110f, 0x1172, 0x11b1, 0,
+#undef V11417
+#define V11417 (V + 43421)
+ 0x110f, 0x1172, 0x11b2, 0,
+#undef V11418
+#define V11418 (V + 43425)
+ 0x110f, 0x1172, 0x11b3, 0,
+#undef V11419
+#define V11419 (V + 43429)
+ 0x110f, 0x1172, 0x11b4, 0,
+#undef V11420
+#define V11420 (V + 43433)
+ 0x110f, 0x1172, 0x11b5, 0,
+#undef V11421
+#define V11421 (V + 43437)
+ 0x110f, 0x1172, 0x11b6, 0,
+#undef V11422
+#define V11422 (V + 43441)
+ 0x110f, 0x1172, 0x11b7, 0,
+#undef V11423
+#define V11423 (V + 43445)
+ 0x110f, 0x1172, 0x11b8, 0,
+#undef V11424
+#define V11424 (V + 43449)
+ 0x110f, 0x1172, 0x11b9, 0,
+#undef V11425
+#define V11425 (V + 43453)
+ 0x110f, 0x1172, 0x11ba, 0,
+#undef V11426
+#define V11426 (V + 43457)
+ 0x110f, 0x1172, 0x11bb, 0,
+#undef V11427
+#define V11427 (V + 43461)
+ 0x110f, 0x1172, 0x11bc, 0,
+#undef V11428
+#define V11428 (V + 43465)
+ 0x110f, 0x1172, 0x11bd, 0,
+#undef V11429
+#define V11429 (V + 43469)
+ 0x110f, 0x1172, 0x11be, 0,
+#undef V11430
+#define V11430 (V + 43473)
+ 0x110f, 0x1172, 0x11bf, 0,
+#undef V11431
+#define V11431 (V + 43477)
+ 0x110f, 0x1172, 0x11c0, 0,
+#undef V11432
+#define V11432 (V + 43481)
+ 0x110f, 0x1172, 0x11c1, 0,
+#undef V11433
+#define V11433 (V + 43485)
+ 0x110f, 0x1172, 0x11c2, 0,
+#undef V11434
+#define V11434 (V + 43489)
+ 0x110f, 0x1173, 0,
+#undef V11435
+#define V11435 (V + 43492)
+ 0x110f, 0x1173, 0x11a8, 0,
+#undef V11436
+#define V11436 (V + 43496)
+ 0x110f, 0x1173, 0x11a9, 0,
+#undef V11437
+#define V11437 (V + 43500)
+ 0x110f, 0x1173, 0x11aa, 0,
+#undef V11438
+#define V11438 (V + 43504)
+ 0x110f, 0x1173, 0x11ab, 0,
+#undef V11439
+#define V11439 (V + 43508)
+ 0x110f, 0x1173, 0x11ac, 0,
+#undef V11440
+#define V11440 (V + 43512)
+ 0x110f, 0x1173, 0x11ad, 0,
+#undef V11441
+#define V11441 (V + 43516)
+ 0x110f, 0x1173, 0x11ae, 0,
+#undef V11442
+#define V11442 (V + 43520)
+ 0x110f, 0x1173, 0x11af, 0,
+#undef V11443
+#define V11443 (V + 43524)
+ 0x110f, 0x1173, 0x11b0, 0,
+#undef V11444
+#define V11444 (V + 43528)
+ 0x110f, 0x1173, 0x11b1, 0,
+#undef V11445
+#define V11445 (V + 43532)
+ 0x110f, 0x1173, 0x11b2, 0,
+#undef V11446
+#define V11446 (V + 43536)
+ 0x110f, 0x1173, 0x11b3, 0,
+#undef V11447
+#define V11447 (V + 43540)
+ 0x110f, 0x1173, 0x11b4, 0,
+#undef V11448
+#define V11448 (V + 43544)
+ 0x110f, 0x1173, 0x11b5, 0,
+#undef V11449
+#define V11449 (V + 43548)
+ 0x110f, 0x1173, 0x11b6, 0,
+#undef V11450
+#define V11450 (V + 43552)
+ 0x110f, 0x1173, 0x11b7, 0,
+#undef V11451
+#define V11451 (V + 43556)
+ 0x110f, 0x1173, 0x11b8, 0,
+#undef V11452
+#define V11452 (V + 43560)
+ 0x110f, 0x1173, 0x11b9, 0,
+#undef V11453
+#define V11453 (V + 43564)
+ 0x110f, 0x1173, 0x11ba, 0,
+#undef V11454
+#define V11454 (V + 43568)
+ 0x110f, 0x1173, 0x11bb, 0,
+#undef V11455
+#define V11455 (V + 43572)
+ 0x110f, 0x1173, 0x11bc, 0,
+#undef V11456
+#define V11456 (V + 43576)
+ 0x110f, 0x1173, 0x11bd, 0,
+#undef V11457
+#define V11457 (V + 43580)
+ 0x110f, 0x1173, 0x11be, 0,
+#undef V11458
+#define V11458 (V + 43584)
+ 0x110f, 0x1173, 0x11bf, 0,
+#undef V11459
+#define V11459 (V + 43588)
+ 0x110f, 0x1173, 0x11c0, 0,
+#undef V11460
+#define V11460 (V + 43592)
+ 0x110f, 0x1173, 0x11c1, 0,
+#undef V11461
+#define V11461 (V + 43596)
+ 0x110f, 0x1173, 0x11c2, 0,
+#undef V11462
+#define V11462 (V + 43600)
+ 0x110f, 0x1174, 0,
+#undef V11463
+#define V11463 (V + 43603)
+ 0x110f, 0x1174, 0x11a8, 0,
+#undef V11464
+#define V11464 (V + 43607)
+ 0x110f, 0x1174, 0x11a9, 0,
+#undef V11465
+#define V11465 (V + 43611)
+ 0x110f, 0x1174, 0x11aa, 0,
+#undef V11466
+#define V11466 (V + 43615)
+ 0x110f, 0x1174, 0x11ab, 0,
+#undef V11467
+#define V11467 (V + 43619)
+ 0x110f, 0x1174, 0x11ac, 0,
+#undef V11468
+#define V11468 (V + 43623)
+ 0x110f, 0x1174, 0x11ad, 0,
+#undef V11469
+#define V11469 (V + 43627)
+ 0x110f, 0x1174, 0x11ae, 0,
+#undef V11470
+#define V11470 (V + 43631)
+ 0x110f, 0x1174, 0x11af, 0,
+#undef V11471
+#define V11471 (V + 43635)
+ 0x110f, 0x1174, 0x11b0, 0,
+#undef V11472
+#define V11472 (V + 43639)
+ 0x110f, 0x1174, 0x11b1, 0,
+#undef V11473
+#define V11473 (V + 43643)
+ 0x110f, 0x1174, 0x11b2, 0,
+#undef V11474
+#define V11474 (V + 43647)
+ 0x110f, 0x1174, 0x11b3, 0,
+#undef V11475
+#define V11475 (V + 43651)
+ 0x110f, 0x1174, 0x11b4, 0,
+#undef V11476
+#define V11476 (V + 43655)
+ 0x110f, 0x1174, 0x11b5, 0,
+#undef V11477
+#define V11477 (V + 43659)
+ 0x110f, 0x1174, 0x11b6, 0,
+#undef V11478
+#define V11478 (V + 43663)
+ 0x110f, 0x1174, 0x11b7, 0,
+#undef V11479
+#define V11479 (V + 43667)
+ 0x110f, 0x1174, 0x11b8, 0,
+#undef V11480
+#define V11480 (V + 43671)
+ 0x110f, 0x1174, 0x11b9, 0,
+#undef V11481
+#define V11481 (V + 43675)
+ 0x110f, 0x1174, 0x11ba, 0,
+#undef V11482
+#define V11482 (V + 43679)
+ 0x110f, 0x1174, 0x11bb, 0,
+#undef V11483
+#define V11483 (V + 43683)
+ 0x110f, 0x1174, 0x11bc, 0,
+#undef V11484
+#define V11484 (V + 43687)
+ 0x110f, 0x1174, 0x11bd, 0,
+#undef V11485
+#define V11485 (V + 43691)
+ 0x110f, 0x1174, 0x11be, 0,
+#undef V11486
+#define V11486 (V + 43695)
+ 0x110f, 0x1174, 0x11bf, 0,
+#undef V11487
+#define V11487 (V + 43699)
+ 0x110f, 0x1174, 0x11c0, 0,
+#undef V11488
+#define V11488 (V + 43703)
+ 0x110f, 0x1174, 0x11c1, 0,
+#undef V11489
+#define V11489 (V + 43707)
+ 0x110f, 0x1174, 0x11c2, 0,
+#undef V11490
+#define V11490 (V + 43711)
+ 0x110f, 0x1175, 0,
+#undef V11491
+#define V11491 (V + 43714)
+ 0x110f, 0x1175, 0x11a8, 0,
+#undef V11492
+#define V11492 (V + 43718)
+ 0x110f, 0x1175, 0x11a9, 0,
+#undef V11493
+#define V11493 (V + 43722)
+ 0x110f, 0x1175, 0x11aa, 0,
+#undef V11494
+#define V11494 (V + 43726)
+ 0x110f, 0x1175, 0x11ab, 0,
+#undef V11495
+#define V11495 (V + 43730)
+ 0x110f, 0x1175, 0x11ac, 0,
+#undef V11496
+#define V11496 (V + 43734)
+ 0x110f, 0x1175, 0x11ad, 0,
+#undef V11497
+#define V11497 (V + 43738)
+ 0x110f, 0x1175, 0x11ae, 0,
+#undef V11498
+#define V11498 (V + 43742)
+ 0x110f, 0x1175, 0x11af, 0,
+#undef V11499
+#define V11499 (V + 43746)
+ 0x110f, 0x1175, 0x11b0, 0,
+#undef V11500
+#define V11500 (V + 43750)
+ 0x110f, 0x1175, 0x11b1, 0,
+#undef V11501
+#define V11501 (V + 43754)
+ 0x110f, 0x1175, 0x11b2, 0,
+#undef V11502
+#define V11502 (V + 43758)
+ 0x110f, 0x1175, 0x11b3, 0,
+#undef V11503
+#define V11503 (V + 43762)
+ 0x110f, 0x1175, 0x11b4, 0,
+#undef V11504
+#define V11504 (V + 43766)
+ 0x110f, 0x1175, 0x11b5, 0,
+#undef V11505
+#define V11505 (V + 43770)
+ 0x110f, 0x1175, 0x11b6, 0,
+#undef V11506
+#define V11506 (V + 43774)
+ 0x110f, 0x1175, 0x11b7, 0,
+#undef V11507
+#define V11507 (V + 43778)
+ 0x110f, 0x1175, 0x11b8, 0,
+#undef V11508
+#define V11508 (V + 43782)
+ 0x110f, 0x1175, 0x11b9, 0,
+#undef V11509
+#define V11509 (V + 43786)
+ 0x110f, 0x1175, 0x11ba, 0,
+#undef V11510
+#define V11510 (V + 43790)
+ 0x110f, 0x1175, 0x11bb, 0,
+#undef V11511
+#define V11511 (V + 43794)
+ 0x110f, 0x1175, 0x11bc, 0,
+#undef V11512
+#define V11512 (V + 43798)
+ 0x110f, 0x1175, 0x11bd, 0,
+#undef V11513
+#define V11513 (V + 43802)
+ 0x110f, 0x1175, 0x11be, 0,
+#undef V11514
+#define V11514 (V + 43806)
+ 0x110f, 0x1175, 0x11bf, 0,
+#undef V11515
+#define V11515 (V + 43810)
+ 0x110f, 0x1175, 0x11c0, 0,
+#undef V11516
+#define V11516 (V + 43814)
+ 0x110f, 0x1175, 0x11c1, 0,
+#undef V11517
+#define V11517 (V + 43818)
+ 0x110f, 0x1175, 0x11c2, 0,
+#undef V11518
+#define V11518 (V + 43822)
+ 0x1110, 0x1161, 0x11a8, 0,
+#undef V11519
+#define V11519 (V + 43826)
+ 0x1110, 0x1161, 0x11a9, 0,
+#undef V11520
+#define V11520 (V + 43830)
+ 0x1110, 0x1161, 0x11aa, 0,
+#undef V11521
+#define V11521 (V + 43834)
+ 0x1110, 0x1161, 0x11ab, 0,
+#undef V11522
+#define V11522 (V + 43838)
+ 0x1110, 0x1161, 0x11ac, 0,
+#undef V11523
+#define V11523 (V + 43842)
+ 0x1110, 0x1161, 0x11ad, 0,
+#undef V11524
+#define V11524 (V + 43846)
+ 0x1110, 0x1161, 0x11ae, 0,
+#undef V11525
+#define V11525 (V + 43850)
+ 0x1110, 0x1161, 0x11af, 0,
+#undef V11526
+#define V11526 (V + 43854)
+ 0x1110, 0x1161, 0x11b0, 0,
+#undef V11527
+#define V11527 (V + 43858)
+ 0x1110, 0x1161, 0x11b1, 0,
+#undef V11528
+#define V11528 (V + 43862)
+ 0x1110, 0x1161, 0x11b2, 0,
+#undef V11529
+#define V11529 (V + 43866)
+ 0x1110, 0x1161, 0x11b3, 0,
+#undef V11530
+#define V11530 (V + 43870)
+ 0x1110, 0x1161, 0x11b4, 0,
+#undef V11531
+#define V11531 (V + 43874)
+ 0x1110, 0x1161, 0x11b5, 0,
+#undef V11532
+#define V11532 (V + 43878)
+ 0x1110, 0x1161, 0x11b6, 0,
+#undef V11533
+#define V11533 (V + 43882)
+ 0x1110, 0x1161, 0x11b7, 0,
+#undef V11534
+#define V11534 (V + 43886)
+ 0x1110, 0x1161, 0x11b8, 0,
+#undef V11535
+#define V11535 (V + 43890)
+ 0x1110, 0x1161, 0x11b9, 0,
+#undef V11536
+#define V11536 (V + 43894)
+ 0x1110, 0x1161, 0x11ba, 0,
+#undef V11537
+#define V11537 (V + 43898)
+ 0x1110, 0x1161, 0x11bb, 0,
+#undef V11538
+#define V11538 (V + 43902)
+ 0x1110, 0x1161, 0x11bc, 0,
+#undef V11539
+#define V11539 (V + 43906)
+ 0x1110, 0x1161, 0x11bd, 0,
+#undef V11540
+#define V11540 (V + 43910)
+ 0x1110, 0x1161, 0x11be, 0,
+#undef V11541
+#define V11541 (V + 43914)
+ 0x1110, 0x1161, 0x11bf, 0,
+#undef V11542
+#define V11542 (V + 43918)
+ 0x1110, 0x1161, 0x11c0, 0,
+#undef V11543
+#define V11543 (V + 43922)
+ 0x1110, 0x1161, 0x11c1, 0,
+#undef V11544
+#define V11544 (V + 43926)
+ 0x1110, 0x1161, 0x11c2, 0,
+#undef V11545
+#define V11545 (V + 43930)
+ 0x1110, 0x1162, 0,
+#undef V11546
+#define V11546 (V + 43933)
+ 0x1110, 0x1162, 0x11a8, 0,
+#undef V11547
+#define V11547 (V + 43937)
+ 0x1110, 0x1162, 0x11a9, 0,
+#undef V11548
+#define V11548 (V + 43941)
+ 0x1110, 0x1162, 0x11aa, 0,
+#undef V11549
+#define V11549 (V + 43945)
+ 0x1110, 0x1162, 0x11ab, 0,
+#undef V11550
+#define V11550 (V + 43949)
+ 0x1110, 0x1162, 0x11ac, 0,
+#undef V11551
+#define V11551 (V + 43953)
+ 0x1110, 0x1162, 0x11ad, 0,
+#undef V11552
+#define V11552 (V + 43957)
+ 0x1110, 0x1162, 0x11ae, 0,
+#undef V11553
+#define V11553 (V + 43961)
+ 0x1110, 0x1162, 0x11af, 0,
+#undef V11554
+#define V11554 (V + 43965)
+ 0x1110, 0x1162, 0x11b0, 0,
+#undef V11555
+#define V11555 (V + 43969)
+ 0x1110, 0x1162, 0x11b1, 0,
+#undef V11556
+#define V11556 (V + 43973)
+ 0x1110, 0x1162, 0x11b2, 0,
+#undef V11557
+#define V11557 (V + 43977)
+ 0x1110, 0x1162, 0x11b3, 0,
+#undef V11558
+#define V11558 (V + 43981)
+ 0x1110, 0x1162, 0x11b4, 0,
+#undef V11559
+#define V11559 (V + 43985)
+ 0x1110, 0x1162, 0x11b5, 0,
+#undef V11560
+#define V11560 (V + 43989)
+ 0x1110, 0x1162, 0x11b6, 0,
+#undef V11561
+#define V11561 (V + 43993)
+ 0x1110, 0x1162, 0x11b7, 0,
+#undef V11562
+#define V11562 (V + 43997)
+ 0x1110, 0x1162, 0x11b8, 0,
+#undef V11563
+#define V11563 (V + 44001)
+ 0x1110, 0x1162, 0x11b9, 0,
+#undef V11564
+#define V11564 (V + 44005)
+ 0x1110, 0x1162, 0x11ba, 0,
+#undef V11565
+#define V11565 (V + 44009)
+ 0x1110, 0x1162, 0x11bb, 0,
+#undef V11566
+#define V11566 (V + 44013)
+ 0x1110, 0x1162, 0x11bc, 0,
+#undef V11567
+#define V11567 (V + 44017)
+ 0x1110, 0x1162, 0x11bd, 0,
+#undef V11568
+#define V11568 (V + 44021)
+ 0x1110, 0x1162, 0x11be, 0,
+#undef V11569
+#define V11569 (V + 44025)
+ 0x1110, 0x1162, 0x11bf, 0,
+#undef V11570
+#define V11570 (V + 44029)
+ 0x1110, 0x1162, 0x11c0, 0,
+#undef V11571
+#define V11571 (V + 44033)
+ 0x1110, 0x1162, 0x11c1, 0,
+#undef V11572
+#define V11572 (V + 44037)
+ 0x1110, 0x1162, 0x11c2, 0,
+#undef V11573
+#define V11573 (V + 44041)
+ 0x1110, 0x1163, 0,
+#undef V11574
+#define V11574 (V + 44044)
+ 0x1110, 0x1163, 0x11a8, 0,
+#undef V11575
+#define V11575 (V + 44048)
+ 0x1110, 0x1163, 0x11a9, 0,
+#undef V11576
+#define V11576 (V + 44052)
+ 0x1110, 0x1163, 0x11aa, 0,
+#undef V11577
+#define V11577 (V + 44056)
+ 0x1110, 0x1163, 0x11ab, 0,
+#undef V11578
+#define V11578 (V + 44060)
+ 0x1110, 0x1163, 0x11ac, 0,
+#undef V11579
+#define V11579 (V + 44064)
+ 0x1110, 0x1163, 0x11ad, 0,
+#undef V11580
+#define V11580 (V + 44068)
+ 0x1110, 0x1163, 0x11ae, 0,
+#undef V11581
+#define V11581 (V + 44072)
+ 0x1110, 0x1163, 0x11af, 0,
+#undef V11582
+#define V11582 (V + 44076)
+ 0x1110, 0x1163, 0x11b0, 0,
+#undef V11583
+#define V11583 (V + 44080)
+ 0x1110, 0x1163, 0x11b1, 0,
+#undef V11584
+#define V11584 (V + 44084)
+ 0x1110, 0x1163, 0x11b2, 0,
+#undef V11585
+#define V11585 (V + 44088)
+ 0x1110, 0x1163, 0x11b3, 0,
+#undef V11586
+#define V11586 (V + 44092)
+ 0x1110, 0x1163, 0x11b4, 0,
+#undef V11587
+#define V11587 (V + 44096)
+ 0x1110, 0x1163, 0x11b5, 0,
+#undef V11588
+#define V11588 (V + 44100)
+ 0x1110, 0x1163, 0x11b6, 0,
+#undef V11589
+#define V11589 (V + 44104)
+ 0x1110, 0x1163, 0x11b7, 0,
+#undef V11590
+#define V11590 (V + 44108)
+ 0x1110, 0x1163, 0x11b8, 0,
+#undef V11591
+#define V11591 (V + 44112)
+ 0x1110, 0x1163, 0x11b9, 0,
+#undef V11592
+#define V11592 (V + 44116)
+ 0x1110, 0x1163, 0x11ba, 0,
+#undef V11593
+#define V11593 (V + 44120)
+ 0x1110, 0x1163, 0x11bb, 0,
+#undef V11594
+#define V11594 (V + 44124)
+ 0x1110, 0x1163, 0x11bc, 0,
+#undef V11595
+#define V11595 (V + 44128)
+ 0x1110, 0x1163, 0x11bd, 0,
+#undef V11596
+#define V11596 (V + 44132)
+ 0x1110, 0x1163, 0x11be, 0,
+#undef V11597
+#define V11597 (V + 44136)
+ 0x1110, 0x1163, 0x11bf, 0,
+#undef V11598
+#define V11598 (V + 44140)
+ 0x1110, 0x1163, 0x11c0, 0,
+#undef V11599
+#define V11599 (V + 44144)
+ 0x1110, 0x1163, 0x11c1, 0,
+#undef V11600
+#define V11600 (V + 44148)
+ 0x1110, 0x1163, 0x11c2, 0,
+#undef V11601
+#define V11601 (V + 44152)
+ 0x1110, 0x1164, 0,
+#undef V11602
+#define V11602 (V + 44155)
+ 0x1110, 0x1164, 0x11a8, 0,
+#undef V11603
+#define V11603 (V + 44159)
+ 0x1110, 0x1164, 0x11a9, 0,
+#undef V11604
+#define V11604 (V + 44163)
+ 0x1110, 0x1164, 0x11aa, 0,
+#undef V11605
+#define V11605 (V + 44167)
+ 0x1110, 0x1164, 0x11ab, 0,
+#undef V11606
+#define V11606 (V + 44171)
+ 0x1110, 0x1164, 0x11ac, 0,
+#undef V11607
+#define V11607 (V + 44175)
+ 0x1110, 0x1164, 0x11ad, 0,
+#undef V11608
+#define V11608 (V + 44179)
+ 0x1110, 0x1164, 0x11ae, 0,
+#undef V11609
+#define V11609 (V + 44183)
+ 0x1110, 0x1164, 0x11af, 0,
+#undef V11610
+#define V11610 (V + 44187)
+ 0x1110, 0x1164, 0x11b0, 0,
+#undef V11611
+#define V11611 (V + 44191)
+ 0x1110, 0x1164, 0x11b1, 0,
+#undef V11612
+#define V11612 (V + 44195)
+ 0x1110, 0x1164, 0x11b2, 0,
+#undef V11613
+#define V11613 (V + 44199)
+ 0x1110, 0x1164, 0x11b3, 0,
+#undef V11614
+#define V11614 (V + 44203)
+ 0x1110, 0x1164, 0x11b4, 0,
+#undef V11615
+#define V11615 (V + 44207)
+ 0x1110, 0x1164, 0x11b5, 0,
+#undef V11616
+#define V11616 (V + 44211)
+ 0x1110, 0x1164, 0x11b6, 0,
+#undef V11617
+#define V11617 (V + 44215)
+ 0x1110, 0x1164, 0x11b7, 0,
+#undef V11618
+#define V11618 (V + 44219)
+ 0x1110, 0x1164, 0x11b8, 0,
+#undef V11619
+#define V11619 (V + 44223)
+ 0x1110, 0x1164, 0x11b9, 0,
+#undef V11620
+#define V11620 (V + 44227)
+ 0x1110, 0x1164, 0x11ba, 0,
+#undef V11621
+#define V11621 (V + 44231)
+ 0x1110, 0x1164, 0x11bb, 0,
+#undef V11622
+#define V11622 (V + 44235)
+ 0x1110, 0x1164, 0x11bc, 0,
+#undef V11623
+#define V11623 (V + 44239)
+ 0x1110, 0x1164, 0x11bd, 0,
+#undef V11624
+#define V11624 (V + 44243)
+ 0x1110, 0x1164, 0x11be, 0,
+#undef V11625
+#define V11625 (V + 44247)
+ 0x1110, 0x1164, 0x11bf, 0,
+#undef V11626
+#define V11626 (V + 44251)
+ 0x1110, 0x1164, 0x11c0, 0,
+#undef V11627
+#define V11627 (V + 44255)
+ 0x1110, 0x1164, 0x11c1, 0,
+#undef V11628
+#define V11628 (V + 44259)
+ 0x1110, 0x1164, 0x11c2, 0,
+#undef V11629
+#define V11629 (V + 44263)
+ 0x1110, 0x1165, 0,
+#undef V11630
+#define V11630 (V + 44266)
+ 0x1110, 0x1165, 0x11a8, 0,
+#undef V11631
+#define V11631 (V + 44270)
+ 0x1110, 0x1165, 0x11a9, 0,
+#undef V11632
+#define V11632 (V + 44274)
+ 0x1110, 0x1165, 0x11aa, 0,
+#undef V11633
+#define V11633 (V + 44278)
+ 0x1110, 0x1165, 0x11ab, 0,
+#undef V11634
+#define V11634 (V + 44282)
+ 0x1110, 0x1165, 0x11ac, 0,
+#undef V11635
+#define V11635 (V + 44286)
+ 0x1110, 0x1165, 0x11ad, 0,
+#undef V11636
+#define V11636 (V + 44290)
+ 0x1110, 0x1165, 0x11ae, 0,
+#undef V11637
+#define V11637 (V + 44294)
+ 0x1110, 0x1165, 0x11af, 0,
+#undef V11638
+#define V11638 (V + 44298)
+ 0x1110, 0x1165, 0x11b0, 0,
+#undef V11639
+#define V11639 (V + 44302)
+ 0x1110, 0x1165, 0x11b1, 0,
+#undef V11640
+#define V11640 (V + 44306)
+ 0x1110, 0x1165, 0x11b2, 0,
+#undef V11641
+#define V11641 (V + 44310)
+ 0x1110, 0x1165, 0x11b3, 0,
+#undef V11642
+#define V11642 (V + 44314)
+ 0x1110, 0x1165, 0x11b4, 0,
+#undef V11643
+#define V11643 (V + 44318)
+ 0x1110, 0x1165, 0x11b5, 0,
+#undef V11644
+#define V11644 (V + 44322)
+ 0x1110, 0x1165, 0x11b6, 0,
+#undef V11645
+#define V11645 (V + 44326)
+ 0x1110, 0x1165, 0x11b7, 0,
+#undef V11646
+#define V11646 (V + 44330)
+ 0x1110, 0x1165, 0x11b8, 0,
+#undef V11647
+#define V11647 (V + 44334)
+ 0x1110, 0x1165, 0x11b9, 0,
+#undef V11648
+#define V11648 (V + 44338)
+ 0x1110, 0x1165, 0x11ba, 0,
+#undef V11649
+#define V11649 (V + 44342)
+ 0x1110, 0x1165, 0x11bb, 0,
+#undef V11650
+#define V11650 (V + 44346)
+ 0x1110, 0x1165, 0x11bc, 0,
+#undef V11651
+#define V11651 (V + 44350)
+ 0x1110, 0x1165, 0x11bd, 0,
+#undef V11652
+#define V11652 (V + 44354)
+ 0x1110, 0x1165, 0x11be, 0,
+#undef V11653
+#define V11653 (V + 44358)
+ 0x1110, 0x1165, 0x11bf, 0,
+#undef V11654
+#define V11654 (V + 44362)
+ 0x1110, 0x1165, 0x11c0, 0,
+#undef V11655
+#define V11655 (V + 44366)
+ 0x1110, 0x1165, 0x11c1, 0,
+#undef V11656
+#define V11656 (V + 44370)
+ 0x1110, 0x1165, 0x11c2, 0,
+#undef V11657
+#define V11657 (V + 44374)
+ 0x1110, 0x1166, 0,
+#undef V11658
+#define V11658 (V + 44377)
+ 0x1110, 0x1166, 0x11a8, 0,
+#undef V11659
+#define V11659 (V + 44381)
+ 0x1110, 0x1166, 0x11a9, 0,
+#undef V11660
+#define V11660 (V + 44385)
+ 0x1110, 0x1166, 0x11aa, 0,
+#undef V11661
+#define V11661 (V + 44389)
+ 0x1110, 0x1166, 0x11ab, 0,
+#undef V11662
+#define V11662 (V + 44393)
+ 0x1110, 0x1166, 0x11ac, 0,
+#undef V11663
+#define V11663 (V + 44397)
+ 0x1110, 0x1166, 0x11ad, 0,
+#undef V11664
+#define V11664 (V + 44401)
+ 0x1110, 0x1166, 0x11ae, 0,
+#undef V11665
+#define V11665 (V + 44405)
+ 0x1110, 0x1166, 0x11af, 0,
+#undef V11666
+#define V11666 (V + 44409)
+ 0x1110, 0x1166, 0x11b0, 0,
+#undef V11667
+#define V11667 (V + 44413)
+ 0x1110, 0x1166, 0x11b1, 0,
+#undef V11668
+#define V11668 (V + 44417)
+ 0x1110, 0x1166, 0x11b2, 0,
+#undef V11669
+#define V11669 (V + 44421)
+ 0x1110, 0x1166, 0x11b3, 0,
+#undef V11670
+#define V11670 (V + 44425)
+ 0x1110, 0x1166, 0x11b4, 0,
+#undef V11671
+#define V11671 (V + 44429)
+ 0x1110, 0x1166, 0x11b5, 0,
+#undef V11672
+#define V11672 (V + 44433)
+ 0x1110, 0x1166, 0x11b6, 0,
+#undef V11673
+#define V11673 (V + 44437)
+ 0x1110, 0x1166, 0x11b7, 0,
+#undef V11674
+#define V11674 (V + 44441)
+ 0x1110, 0x1166, 0x11b8, 0,
+#undef V11675
+#define V11675 (V + 44445)
+ 0x1110, 0x1166, 0x11b9, 0,
+#undef V11676
+#define V11676 (V + 44449)
+ 0x1110, 0x1166, 0x11ba, 0,
+#undef V11677
+#define V11677 (V + 44453)
+ 0x1110, 0x1166, 0x11bb, 0,
+#undef V11678
+#define V11678 (V + 44457)
+ 0x1110, 0x1166, 0x11bc, 0,
+#undef V11679
+#define V11679 (V + 44461)
+ 0x1110, 0x1166, 0x11bd, 0,
+#undef V11680
+#define V11680 (V + 44465)
+ 0x1110, 0x1166, 0x11be, 0,
+#undef V11681
+#define V11681 (V + 44469)
+ 0x1110, 0x1166, 0x11bf, 0,
+#undef V11682
+#define V11682 (V + 44473)
+ 0x1110, 0x1166, 0x11c0, 0,
+#undef V11683
+#define V11683 (V + 44477)
+ 0x1110, 0x1166, 0x11c1, 0,
+#undef V11684
+#define V11684 (V + 44481)
+ 0x1110, 0x1166, 0x11c2, 0,
+#undef V11685
+#define V11685 (V + 44485)
+ 0x1110, 0x1167, 0,
+#undef V11686
+#define V11686 (V + 44488)
+ 0x1110, 0x1167, 0x11a8, 0,
+#undef V11687
+#define V11687 (V + 44492)
+ 0x1110, 0x1167, 0x11a9, 0,
+#undef V11688
+#define V11688 (V + 44496)
+ 0x1110, 0x1167, 0x11aa, 0,
+#undef V11689
+#define V11689 (V + 44500)
+ 0x1110, 0x1167, 0x11ab, 0,
+#undef V11690
+#define V11690 (V + 44504)
+ 0x1110, 0x1167, 0x11ac, 0,
+#undef V11691
+#define V11691 (V + 44508)
+ 0x1110, 0x1167, 0x11ad, 0,
+#undef V11692
+#define V11692 (V + 44512)
+ 0x1110, 0x1167, 0x11ae, 0,
+#undef V11693
+#define V11693 (V + 44516)
+ 0x1110, 0x1167, 0x11af, 0,
+#undef V11694
+#define V11694 (V + 44520)
+ 0x1110, 0x1167, 0x11b0, 0,
+#undef V11695
+#define V11695 (V + 44524)
+ 0x1110, 0x1167, 0x11b1, 0,
+#undef V11696
+#define V11696 (V + 44528)
+ 0x1110, 0x1167, 0x11b2, 0,
+#undef V11697
+#define V11697 (V + 44532)
+ 0x1110, 0x1167, 0x11b3, 0,
+#undef V11698
+#define V11698 (V + 44536)
+ 0x1110, 0x1167, 0x11b4, 0,
+#undef V11699
+#define V11699 (V + 44540)
+ 0x1110, 0x1167, 0x11b5, 0,
+#undef V11700
+#define V11700 (V + 44544)
+ 0x1110, 0x1167, 0x11b6, 0,
+#undef V11701
+#define V11701 (V + 44548)
+ 0x1110, 0x1167, 0x11b7, 0,
+#undef V11702
+#define V11702 (V + 44552)
+ 0x1110, 0x1167, 0x11b8, 0,
+#undef V11703
+#define V11703 (V + 44556)
+ 0x1110, 0x1167, 0x11b9, 0,
+#undef V11704
+#define V11704 (V + 44560)
+ 0x1110, 0x1167, 0x11ba, 0,
+#undef V11705
+#define V11705 (V + 44564)
+ 0x1110, 0x1167, 0x11bb, 0,
+#undef V11706
+#define V11706 (V + 44568)
+ 0x1110, 0x1167, 0x11bc, 0,
+#undef V11707
+#define V11707 (V + 44572)
+ 0x1110, 0x1167, 0x11bd, 0,
+#undef V11708
+#define V11708 (V + 44576)
+ 0x1110, 0x1167, 0x11be, 0,
+#undef V11709
+#define V11709 (V + 44580)
+ 0x1110, 0x1167, 0x11bf, 0,
+#undef V11710
+#define V11710 (V + 44584)
+ 0x1110, 0x1167, 0x11c0, 0,
+#undef V11711
+#define V11711 (V + 44588)
+ 0x1110, 0x1167, 0x11c1, 0,
+#undef V11712
+#define V11712 (V + 44592)
+ 0x1110, 0x1167, 0x11c2, 0,
+#undef V11713
+#define V11713 (V + 44596)
+ 0x1110, 0x1168, 0,
+#undef V11714
+#define V11714 (V + 44599)
+ 0x1110, 0x1168, 0x11a8, 0,
+#undef V11715
+#define V11715 (V + 44603)
+ 0x1110, 0x1168, 0x11a9, 0,
+#undef V11716
+#define V11716 (V + 44607)
+ 0x1110, 0x1168, 0x11aa, 0,
+#undef V11717
+#define V11717 (V + 44611)
+ 0x1110, 0x1168, 0x11ab, 0,
+#undef V11718
+#define V11718 (V + 44615)
+ 0x1110, 0x1168, 0x11ac, 0,
+#undef V11719
+#define V11719 (V + 44619)
+ 0x1110, 0x1168, 0x11ad, 0,
+#undef V11720
+#define V11720 (V + 44623)
+ 0x1110, 0x1168, 0x11ae, 0,
+#undef V11721
+#define V11721 (V + 44627)
+ 0x1110, 0x1168, 0x11af, 0,
+#undef V11722
+#define V11722 (V + 44631)
+ 0x1110, 0x1168, 0x11b0, 0,
+#undef V11723
+#define V11723 (V + 44635)
+ 0x1110, 0x1168, 0x11b1, 0,
+#undef V11724
+#define V11724 (V + 44639)
+ 0x1110, 0x1168, 0x11b2, 0,
+#undef V11725
+#define V11725 (V + 44643)
+ 0x1110, 0x1168, 0x11b3, 0,
+#undef V11726
+#define V11726 (V + 44647)
+ 0x1110, 0x1168, 0x11b4, 0,
+#undef V11727
+#define V11727 (V + 44651)
+ 0x1110, 0x1168, 0x11b5, 0,
+#undef V11728
+#define V11728 (V + 44655)
+ 0x1110, 0x1168, 0x11b6, 0,
+#undef V11729
+#define V11729 (V + 44659)
+ 0x1110, 0x1168, 0x11b7, 0,
+#undef V11730
+#define V11730 (V + 44663)
+ 0x1110, 0x1168, 0x11b8, 0,
+#undef V11731
+#define V11731 (V + 44667)
+ 0x1110, 0x1168, 0x11b9, 0,
+#undef V11732
+#define V11732 (V + 44671)
+ 0x1110, 0x1168, 0x11ba, 0,
+#undef V11733
+#define V11733 (V + 44675)
+ 0x1110, 0x1168, 0x11bb, 0,
+#undef V11734
+#define V11734 (V + 44679)
+ 0x1110, 0x1168, 0x11bc, 0,
+#undef V11735
+#define V11735 (V + 44683)
+ 0x1110, 0x1168, 0x11bd, 0,
+#undef V11736
+#define V11736 (V + 44687)
+ 0x1110, 0x1168, 0x11be, 0,
+#undef V11737
+#define V11737 (V + 44691)
+ 0x1110, 0x1168, 0x11bf, 0,
+#undef V11738
+#define V11738 (V + 44695)
+ 0x1110, 0x1168, 0x11c0, 0,
+#undef V11739
+#define V11739 (V + 44699)
+ 0x1110, 0x1168, 0x11c1, 0,
+#undef V11740
+#define V11740 (V + 44703)
+ 0x1110, 0x1168, 0x11c2, 0,
+#undef V11741
+#define V11741 (V + 44707)
+ 0x1110, 0x1169, 0,
+#undef V11742
+#define V11742 (V + 44710)
+ 0x1110, 0x1169, 0x11a8, 0,
+#undef V11743
+#define V11743 (V + 44714)
+ 0x1110, 0x1169, 0x11a9, 0,
+#undef V11744
+#define V11744 (V + 44718)
+ 0x1110, 0x1169, 0x11aa, 0,
+#undef V11745
+#define V11745 (V + 44722)
+ 0x1110, 0x1169, 0x11ab, 0,
+#undef V11746
+#define V11746 (V + 44726)
+ 0x1110, 0x1169, 0x11ac, 0,
+#undef V11747
+#define V11747 (V + 44730)
+ 0x1110, 0x1169, 0x11ad, 0,
+#undef V11748
+#define V11748 (V + 44734)
+ 0x1110, 0x1169, 0x11ae, 0,
+#undef V11749
+#define V11749 (V + 44738)
+ 0x1110, 0x1169, 0x11af, 0,
+#undef V11750
+#define V11750 (V + 44742)
+ 0x1110, 0x1169, 0x11b0, 0,
+#undef V11751
+#define V11751 (V + 44746)
+ 0x1110, 0x1169, 0x11b1, 0,
+#undef V11752
+#define V11752 (V + 44750)
+ 0x1110, 0x1169, 0x11b2, 0,
+#undef V11753
+#define V11753 (V + 44754)
+ 0x1110, 0x1169, 0x11b3, 0,
+#undef V11754
+#define V11754 (V + 44758)
+ 0x1110, 0x1169, 0x11b4, 0,
+#undef V11755
+#define V11755 (V + 44762)
+ 0x1110, 0x1169, 0x11b5, 0,
+#undef V11756
+#define V11756 (V + 44766)
+ 0x1110, 0x1169, 0x11b6, 0,
+#undef V11757
+#define V11757 (V + 44770)
+ 0x1110, 0x1169, 0x11b7, 0,
+#undef V11758
+#define V11758 (V + 44774)
+ 0x1110, 0x1169, 0x11b8, 0,
+#undef V11759
+#define V11759 (V + 44778)
+ 0x1110, 0x1169, 0x11b9, 0,
+#undef V11760
+#define V11760 (V + 44782)
+ 0x1110, 0x1169, 0x11ba, 0,
+#undef V11761
+#define V11761 (V + 44786)
+ 0x1110, 0x1169, 0x11bb, 0,
+#undef V11762
+#define V11762 (V + 44790)
+ 0x1110, 0x1169, 0x11bc, 0,
+#undef V11763
+#define V11763 (V + 44794)
+ 0x1110, 0x1169, 0x11bd, 0,
+#undef V11764
+#define V11764 (V + 44798)
+ 0x1110, 0x1169, 0x11be, 0,
+#undef V11765
+#define V11765 (V + 44802)
+ 0x1110, 0x1169, 0x11bf, 0,
+#undef V11766
+#define V11766 (V + 44806)
+ 0x1110, 0x1169, 0x11c0, 0,
+#undef V11767
+#define V11767 (V + 44810)
+ 0x1110, 0x1169, 0x11c1, 0,
+#undef V11768
+#define V11768 (V + 44814)
+ 0x1110, 0x1169, 0x11c2, 0,
+#undef V11769
+#define V11769 (V + 44818)
+ 0x1110, 0x116a, 0,
+#undef V11770
+#define V11770 (V + 44821)
+ 0x1110, 0x116a, 0x11a8, 0,
+#undef V11771
+#define V11771 (V + 44825)
+ 0x1110, 0x116a, 0x11a9, 0,
+#undef V11772
+#define V11772 (V + 44829)
+ 0x1110, 0x116a, 0x11aa, 0,
+#undef V11773
+#define V11773 (V + 44833)
+ 0x1110, 0x116a, 0x11ab, 0,
+#undef V11774
+#define V11774 (V + 44837)
+ 0x1110, 0x116a, 0x11ac, 0,
+#undef V11775
+#define V11775 (V + 44841)
+ 0x1110, 0x116a, 0x11ad, 0,
+#undef V11776
+#define V11776 (V + 44845)
+ 0x1110, 0x116a, 0x11ae, 0,
+#undef V11777
+#define V11777 (V + 44849)
+ 0x1110, 0x116a, 0x11af, 0,
+#undef V11778
+#define V11778 (V + 44853)
+ 0x1110, 0x116a, 0x11b0, 0,
+#undef V11779
+#define V11779 (V + 44857)
+ 0x1110, 0x116a, 0x11b1, 0,
+#undef V11780
+#define V11780 (V + 44861)
+ 0x1110, 0x116a, 0x11b2, 0,
+#undef V11781
+#define V11781 (V + 44865)
+ 0x1110, 0x116a, 0x11b3, 0,
+#undef V11782
+#define V11782 (V + 44869)
+ 0x1110, 0x116a, 0x11b4, 0,
+#undef V11783
+#define V11783 (V + 44873)
+ 0x1110, 0x116a, 0x11b5, 0,
+#undef V11784
+#define V11784 (V + 44877)
+ 0x1110, 0x116a, 0x11b6, 0,
+#undef V11785
+#define V11785 (V + 44881)
+ 0x1110, 0x116a, 0x11b7, 0,
+#undef V11786
+#define V11786 (V + 44885)
+ 0x1110, 0x116a, 0x11b8, 0,
+#undef V11787
+#define V11787 (V + 44889)
+ 0x1110, 0x116a, 0x11b9, 0,
+#undef V11788
+#define V11788 (V + 44893)
+ 0x1110, 0x116a, 0x11ba, 0,
+#undef V11789
+#define V11789 (V + 44897)
+ 0x1110, 0x116a, 0x11bb, 0,
+#undef V11790
+#define V11790 (V + 44901)
+ 0x1110, 0x116a, 0x11bc, 0,
+#undef V11791
+#define V11791 (V + 44905)
+ 0x1110, 0x116a, 0x11bd, 0,
+#undef V11792
+#define V11792 (V + 44909)
+ 0x1110, 0x116a, 0x11be, 0,
+#undef V11793
+#define V11793 (V + 44913)
+ 0x1110, 0x116a, 0x11bf, 0,
+#undef V11794
+#define V11794 (V + 44917)
+ 0x1110, 0x116a, 0x11c0, 0,
+#undef V11795
+#define V11795 (V + 44921)
+ 0x1110, 0x116a, 0x11c1, 0,
+#undef V11796
+#define V11796 (V + 44925)
+ 0x1110, 0x116a, 0x11c2, 0,
+#undef V11797
+#define V11797 (V + 44929)
+ 0x1110, 0x116b, 0,
+#undef V11798
+#define V11798 (V + 44932)
+ 0x1110, 0x116b, 0x11a8, 0,
+#undef V11799
+#define V11799 (V + 44936)
+ 0x1110, 0x116b, 0x11a9, 0,
+#undef V11800
+#define V11800 (V + 44940)
+ 0x1110, 0x116b, 0x11aa, 0,
+#undef V11801
+#define V11801 (V + 44944)
+ 0x1110, 0x116b, 0x11ab, 0,
+#undef V11802
+#define V11802 (V + 44948)
+ 0x1110, 0x116b, 0x11ac, 0,
+#undef V11803
+#define V11803 (V + 44952)
+ 0x1110, 0x116b, 0x11ad, 0,
+#undef V11804
+#define V11804 (V + 44956)
+ 0x1110, 0x116b, 0x11ae, 0,
+#undef V11805
+#define V11805 (V + 44960)
+ 0x1110, 0x116b, 0x11af, 0,
+#undef V11806
+#define V11806 (V + 44964)
+ 0x1110, 0x116b, 0x11b0, 0,
+#undef V11807
+#define V11807 (V + 44968)
+ 0x1110, 0x116b, 0x11b1, 0,
+#undef V11808
+#define V11808 (V + 44972)
+ 0x1110, 0x116b, 0x11b2, 0,
+#undef V11809
+#define V11809 (V + 44976)
+ 0x1110, 0x116b, 0x11b3, 0,
+#undef V11810
+#define V11810 (V + 44980)
+ 0x1110, 0x116b, 0x11b4, 0,
+#undef V11811
+#define V11811 (V + 44984)
+ 0x1110, 0x116b, 0x11b5, 0,
+#undef V11812
+#define V11812 (V + 44988)
+ 0x1110, 0x116b, 0x11b6, 0,
+#undef V11813
+#define V11813 (V + 44992)
+ 0x1110, 0x116b, 0x11b7, 0,
+#undef V11814
+#define V11814 (V + 44996)
+ 0x1110, 0x116b, 0x11b8, 0,
+#undef V11815
+#define V11815 (V + 45000)
+ 0x1110, 0x116b, 0x11b9, 0,
+#undef V11816
+#define V11816 (V + 45004)
+ 0x1110, 0x116b, 0x11ba, 0,
+#undef V11817
+#define V11817 (V + 45008)
+ 0x1110, 0x116b, 0x11bb, 0,
+#undef V11818
+#define V11818 (V + 45012)
+ 0x1110, 0x116b, 0x11bc, 0,
+#undef V11819
+#define V11819 (V + 45016)
+ 0x1110, 0x116b, 0x11bd, 0,
+#undef V11820
+#define V11820 (V + 45020)
+ 0x1110, 0x116b, 0x11be, 0,
+#undef V11821
+#define V11821 (V + 45024)
+ 0x1110, 0x116b, 0x11bf, 0,
+#undef V11822
+#define V11822 (V + 45028)
+ 0x1110, 0x116b, 0x11c0, 0,
+#undef V11823
+#define V11823 (V + 45032)
+ 0x1110, 0x116b, 0x11c1, 0,
+#undef V11824
+#define V11824 (V + 45036)
+ 0x1110, 0x116b, 0x11c2, 0,
+#undef V11825
+#define V11825 (V + 45040)
+ 0x1110, 0x116c, 0,
+#undef V11826
+#define V11826 (V + 45043)
+ 0x1110, 0x116c, 0x11a8, 0,
+#undef V11827
+#define V11827 (V + 45047)
+ 0x1110, 0x116c, 0x11a9, 0,
+#undef V11828
+#define V11828 (V + 45051)
+ 0x1110, 0x116c, 0x11aa, 0,
+#undef V11829
+#define V11829 (V + 45055)
+ 0x1110, 0x116c, 0x11ab, 0,
+#undef V11830
+#define V11830 (V + 45059)
+ 0x1110, 0x116c, 0x11ac, 0,
+#undef V11831
+#define V11831 (V + 45063)
+ 0x1110, 0x116c, 0x11ad, 0,
+#undef V11832
+#define V11832 (V + 45067)
+ 0x1110, 0x116c, 0x11ae, 0,
+#undef V11833
+#define V11833 (V + 45071)
+ 0x1110, 0x116c, 0x11af, 0,
+#undef V11834
+#define V11834 (V + 45075)
+ 0x1110, 0x116c, 0x11b0, 0,
+#undef V11835
+#define V11835 (V + 45079)
+ 0x1110, 0x116c, 0x11b1, 0,
+#undef V11836
+#define V11836 (V + 45083)
+ 0x1110, 0x116c, 0x11b2, 0,
+#undef V11837
+#define V11837 (V + 45087)
+ 0x1110, 0x116c, 0x11b3, 0,
+#undef V11838
+#define V11838 (V + 45091)
+ 0x1110, 0x116c, 0x11b4, 0,
+#undef V11839
+#define V11839 (V + 45095)
+ 0x1110, 0x116c, 0x11b5, 0,
+#undef V11840
+#define V11840 (V + 45099)
+ 0x1110, 0x116c, 0x11b6, 0,
+#undef V11841
+#define V11841 (V + 45103)
+ 0x1110, 0x116c, 0x11b7, 0,
+#undef V11842
+#define V11842 (V + 45107)
+ 0x1110, 0x116c, 0x11b8, 0,
+#undef V11843
+#define V11843 (V + 45111)
+ 0x1110, 0x116c, 0x11b9, 0,
+#undef V11844
+#define V11844 (V + 45115)
+ 0x1110, 0x116c, 0x11ba, 0,
+#undef V11845
+#define V11845 (V + 45119)
+ 0x1110, 0x116c, 0x11bb, 0,
+#undef V11846
+#define V11846 (V + 45123)
+ 0x1110, 0x116c, 0x11bc, 0,
+#undef V11847
+#define V11847 (V + 45127)
+ 0x1110, 0x116c, 0x11bd, 0,
+#undef V11848
+#define V11848 (V + 45131)
+ 0x1110, 0x116c, 0x11be, 0,
+#undef V11849
+#define V11849 (V + 45135)
+ 0x1110, 0x116c, 0x11bf, 0,
+#undef V11850
+#define V11850 (V + 45139)
+ 0x1110, 0x116c, 0x11c0, 0,
+#undef V11851
+#define V11851 (V + 45143)
+ 0x1110, 0x116c, 0x11c1, 0,
+#undef V11852
+#define V11852 (V + 45147)
+ 0x1110, 0x116c, 0x11c2, 0,
+#undef V11853
+#define V11853 (V + 45151)
+ 0x1110, 0x116d, 0,
+#undef V11854
+#define V11854 (V + 45154)
+ 0x1110, 0x116d, 0x11a8, 0,
+#undef V11855
+#define V11855 (V + 45158)
+ 0x1110, 0x116d, 0x11a9, 0,
+#undef V11856
+#define V11856 (V + 45162)
+ 0x1110, 0x116d, 0x11aa, 0,
+#undef V11857
+#define V11857 (V + 45166)
+ 0x1110, 0x116d, 0x11ab, 0,
+#undef V11858
+#define V11858 (V + 45170)
+ 0x1110, 0x116d, 0x11ac, 0,
+#undef V11859
+#define V11859 (V + 45174)
+ 0x1110, 0x116d, 0x11ad, 0,
+#undef V11860
+#define V11860 (V + 45178)
+ 0x1110, 0x116d, 0x11ae, 0,
+#undef V11861
+#define V11861 (V + 45182)
+ 0x1110, 0x116d, 0x11af, 0,
+#undef V11862
+#define V11862 (V + 45186)
+ 0x1110, 0x116d, 0x11b0, 0,
+#undef V11863
+#define V11863 (V + 45190)
+ 0x1110, 0x116d, 0x11b1, 0,
+#undef V11864
+#define V11864 (V + 45194)
+ 0x1110, 0x116d, 0x11b2, 0,
+#undef V11865
+#define V11865 (V + 45198)
+ 0x1110, 0x116d, 0x11b3, 0,
+#undef V11866
+#define V11866 (V + 45202)
+ 0x1110, 0x116d, 0x11b4, 0,
+#undef V11867
+#define V11867 (V + 45206)
+ 0x1110, 0x116d, 0x11b5, 0,
+#undef V11868
+#define V11868 (V + 45210)
+ 0x1110, 0x116d, 0x11b6, 0,
+#undef V11869
+#define V11869 (V + 45214)
+ 0x1110, 0x116d, 0x11b7, 0,
+#undef V11870
+#define V11870 (V + 45218)
+ 0x1110, 0x116d, 0x11b8, 0,
+#undef V11871
+#define V11871 (V + 45222)
+ 0x1110, 0x116d, 0x11b9, 0,
+#undef V11872
+#define V11872 (V + 45226)
+ 0x1110, 0x116d, 0x11ba, 0,
+#undef V11873
+#define V11873 (V + 45230)
+ 0x1110, 0x116d, 0x11bb, 0,
+#undef V11874
+#define V11874 (V + 45234)
+ 0x1110, 0x116d, 0x11bc, 0,
+#undef V11875
+#define V11875 (V + 45238)
+ 0x1110, 0x116d, 0x11bd, 0,
+#undef V11876
+#define V11876 (V + 45242)
+ 0x1110, 0x116d, 0x11be, 0,
+#undef V11877
+#define V11877 (V + 45246)
+ 0x1110, 0x116d, 0x11bf, 0,
+#undef V11878
+#define V11878 (V + 45250)
+ 0x1110, 0x116d, 0x11c0, 0,
+#undef V11879
+#define V11879 (V + 45254)
+ 0x1110, 0x116d, 0x11c1, 0,
+#undef V11880
+#define V11880 (V + 45258)
+ 0x1110, 0x116d, 0x11c2, 0,
+#undef V11881
+#define V11881 (V + 45262)
+ 0x1110, 0x116e, 0,
+#undef V11882
+#define V11882 (V + 45265)
+ 0x1110, 0x116e, 0x11a8, 0,
+#undef V11883
+#define V11883 (V + 45269)
+ 0x1110, 0x116e, 0x11a9, 0,
+#undef V11884
+#define V11884 (V + 45273)
+ 0x1110, 0x116e, 0x11aa, 0,
+#undef V11885
+#define V11885 (V + 45277)
+ 0x1110, 0x116e, 0x11ab, 0,
+#undef V11886
+#define V11886 (V + 45281)
+ 0x1110, 0x116e, 0x11ac, 0,
+#undef V11887
+#define V11887 (V + 45285)
+ 0x1110, 0x116e, 0x11ad, 0,
+#undef V11888
+#define V11888 (V + 45289)
+ 0x1110, 0x116e, 0x11ae, 0,
+#undef V11889
+#define V11889 (V + 45293)
+ 0x1110, 0x116e, 0x11af, 0,
+#undef V11890
+#define V11890 (V + 45297)
+ 0x1110, 0x116e, 0x11b0, 0,
+#undef V11891
+#define V11891 (V + 45301)
+ 0x1110, 0x116e, 0x11b1, 0,
+#undef V11892
+#define V11892 (V + 45305)
+ 0x1110, 0x116e, 0x11b2, 0,
+#undef V11893
+#define V11893 (V + 45309)
+ 0x1110, 0x116e, 0x11b3, 0,
+#undef V11894
+#define V11894 (V + 45313)
+ 0x1110, 0x116e, 0x11b4, 0,
+#undef V11895
+#define V11895 (V + 45317)
+ 0x1110, 0x116e, 0x11b5, 0,
+#undef V11896
+#define V11896 (V + 45321)
+ 0x1110, 0x116e, 0x11b6, 0,
+#undef V11897
+#define V11897 (V + 45325)
+ 0x1110, 0x116e, 0x11b7, 0,
+#undef V11898
+#define V11898 (V + 45329)
+ 0x1110, 0x116e, 0x11b8, 0,
+#undef V11899
+#define V11899 (V + 45333)
+ 0x1110, 0x116e, 0x11b9, 0,
+#undef V11900
+#define V11900 (V + 45337)
+ 0x1110, 0x116e, 0x11ba, 0,
+#undef V11901
+#define V11901 (V + 45341)
+ 0x1110, 0x116e, 0x11bb, 0,
+#undef V11902
+#define V11902 (V + 45345)
+ 0x1110, 0x116e, 0x11bc, 0,
+#undef V11903
+#define V11903 (V + 45349)
+ 0x1110, 0x116e, 0x11bd, 0,
+#undef V11904
+#define V11904 (V + 45353)
+ 0x1110, 0x116e, 0x11be, 0,
+#undef V11905
+#define V11905 (V + 45357)
+ 0x1110, 0x116e, 0x11bf, 0,
+#undef V11906
+#define V11906 (V + 45361)
+ 0x1110, 0x116e, 0x11c0, 0,
+#undef V11907
+#define V11907 (V + 45365)
+ 0x1110, 0x116e, 0x11c1, 0,
+#undef V11908
+#define V11908 (V + 45369)
+ 0x1110, 0x116e, 0x11c2, 0,
+#undef V11909
+#define V11909 (V + 45373)
+ 0x1110, 0x116f, 0,
+#undef V11910
+#define V11910 (V + 45376)
+ 0x1110, 0x116f, 0x11a8, 0,
+#undef V11911
+#define V11911 (V + 45380)
+ 0x1110, 0x116f, 0x11a9, 0,
+#undef V11912
+#define V11912 (V + 45384)
+ 0x1110, 0x116f, 0x11aa, 0,
+#undef V11913
+#define V11913 (V + 45388)
+ 0x1110, 0x116f, 0x11ab, 0,
+#undef V11914
+#define V11914 (V + 45392)
+ 0x1110, 0x116f, 0x11ac, 0,
+#undef V11915
+#define V11915 (V + 45396)
+ 0x1110, 0x116f, 0x11ad, 0,
+#undef V11916
+#define V11916 (V + 45400)
+ 0x1110, 0x116f, 0x11ae, 0,
+#undef V11917
+#define V11917 (V + 45404)
+ 0x1110, 0x116f, 0x11af, 0,
+#undef V11918
+#define V11918 (V + 45408)
+ 0x1110, 0x116f, 0x11b0, 0,
+#undef V11919
+#define V11919 (V + 45412)
+ 0x1110, 0x116f, 0x11b1, 0,
+#undef V11920
+#define V11920 (V + 45416)
+ 0x1110, 0x116f, 0x11b2, 0,
+#undef V11921
+#define V11921 (V + 45420)
+ 0x1110, 0x116f, 0x11b3, 0,
+#undef V11922
+#define V11922 (V + 45424)
+ 0x1110, 0x116f, 0x11b4, 0,
+#undef V11923
+#define V11923 (V + 45428)
+ 0x1110, 0x116f, 0x11b5, 0,
+#undef V11924
+#define V11924 (V + 45432)
+ 0x1110, 0x116f, 0x11b6, 0,
+#undef V11925
+#define V11925 (V + 45436)
+ 0x1110, 0x116f, 0x11b7, 0,
+#undef V11926
+#define V11926 (V + 45440)
+ 0x1110, 0x116f, 0x11b8, 0,
+#undef V11927
+#define V11927 (V + 45444)
+ 0x1110, 0x116f, 0x11b9, 0,
+#undef V11928
+#define V11928 (V + 45448)
+ 0x1110, 0x116f, 0x11ba, 0,
+#undef V11929
+#define V11929 (V + 45452)
+ 0x1110, 0x116f, 0x11bb, 0,
+#undef V11930
+#define V11930 (V + 45456)
+ 0x1110, 0x116f, 0x11bc, 0,
+#undef V11931
+#define V11931 (V + 45460)
+ 0x1110, 0x116f, 0x11bd, 0,
+#undef V11932
+#define V11932 (V + 45464)
+ 0x1110, 0x116f, 0x11be, 0,
+#undef V11933
+#define V11933 (V + 45468)
+ 0x1110, 0x116f, 0x11bf, 0,
+#undef V11934
+#define V11934 (V + 45472)
+ 0x1110, 0x116f, 0x11c0, 0,
+#undef V11935
+#define V11935 (V + 45476)
+ 0x1110, 0x116f, 0x11c1, 0,
+#undef V11936
+#define V11936 (V + 45480)
+ 0x1110, 0x116f, 0x11c2, 0,
+#undef V11937
+#define V11937 (V + 45484)
+ 0x1110, 0x1170, 0,
+#undef V11938
+#define V11938 (V + 45487)
+ 0x1110, 0x1170, 0x11a8, 0,
+#undef V11939
+#define V11939 (V + 45491)
+ 0x1110, 0x1170, 0x11a9, 0,
+#undef V11940
+#define V11940 (V + 45495)
+ 0x1110, 0x1170, 0x11aa, 0,
+#undef V11941
+#define V11941 (V + 45499)
+ 0x1110, 0x1170, 0x11ab, 0,
+#undef V11942
+#define V11942 (V + 45503)
+ 0x1110, 0x1170, 0x11ac, 0,
+#undef V11943
+#define V11943 (V + 45507)
+ 0x1110, 0x1170, 0x11ad, 0,
+#undef V11944
+#define V11944 (V + 45511)
+ 0x1110, 0x1170, 0x11ae, 0,
+#undef V11945
+#define V11945 (V + 45515)
+ 0x1110, 0x1170, 0x11af, 0,
+#undef V11946
+#define V11946 (V + 45519)
+ 0x1110, 0x1170, 0x11b0, 0,
+#undef V11947
+#define V11947 (V + 45523)
+ 0x1110, 0x1170, 0x11b1, 0,
+#undef V11948
+#define V11948 (V + 45527)
+ 0x1110, 0x1170, 0x11b2, 0,
+#undef V11949
+#define V11949 (V + 45531)
+ 0x1110, 0x1170, 0x11b3, 0,
+#undef V11950
+#define V11950 (V + 45535)
+ 0x1110, 0x1170, 0x11b4, 0,
+#undef V11951
+#define V11951 (V + 45539)
+ 0x1110, 0x1170, 0x11b5, 0,
+#undef V11952
+#define V11952 (V + 45543)
+ 0x1110, 0x1170, 0x11b6, 0,
+#undef V11953
+#define V11953 (V + 45547)
+ 0x1110, 0x1170, 0x11b7, 0,
+#undef V11954
+#define V11954 (V + 45551)
+ 0x1110, 0x1170, 0x11b8, 0,
+#undef V11955
+#define V11955 (V + 45555)
+ 0x1110, 0x1170, 0x11b9, 0,
+#undef V11956
+#define V11956 (V + 45559)
+ 0x1110, 0x1170, 0x11ba, 0,
+#undef V11957
+#define V11957 (V + 45563)
+ 0x1110, 0x1170, 0x11bb, 0,
+#undef V11958
+#define V11958 (V + 45567)
+ 0x1110, 0x1170, 0x11bc, 0,
+#undef V11959
+#define V11959 (V + 45571)
+ 0x1110, 0x1170, 0x11bd, 0,
+#undef V11960
+#define V11960 (V + 45575)
+ 0x1110, 0x1170, 0x11be, 0,
+#undef V11961
+#define V11961 (V + 45579)
+ 0x1110, 0x1170, 0x11bf, 0,
+#undef V11962
+#define V11962 (V + 45583)
+ 0x1110, 0x1170, 0x11c0, 0,
+#undef V11963
+#define V11963 (V + 45587)
+ 0x1110, 0x1170, 0x11c1, 0,
+#undef V11964
+#define V11964 (V + 45591)
+ 0x1110, 0x1170, 0x11c2, 0,
+#undef V11965
+#define V11965 (V + 45595)
+ 0x1110, 0x1171, 0,
+#undef V11966
+#define V11966 (V + 45598)
+ 0x1110, 0x1171, 0x11a8, 0,
+#undef V11967
+#define V11967 (V + 45602)
+ 0x1110, 0x1171, 0x11a9, 0,
+#undef V11968
+#define V11968 (V + 45606)
+ 0x1110, 0x1171, 0x11aa, 0,
+#undef V11969
+#define V11969 (V + 45610)
+ 0x1110, 0x1171, 0x11ab, 0,
+#undef V11970
+#define V11970 (V + 45614)
+ 0x1110, 0x1171, 0x11ac, 0,
+#undef V11971
+#define V11971 (V + 45618)
+ 0x1110, 0x1171, 0x11ad, 0,
+#undef V11972
+#define V11972 (V + 45622)
+ 0x1110, 0x1171, 0x11ae, 0,
+#undef V11973
+#define V11973 (V + 45626)
+ 0x1110, 0x1171, 0x11af, 0,
+#undef V11974
+#define V11974 (V + 45630)
+ 0x1110, 0x1171, 0x11b0, 0,
+#undef V11975
+#define V11975 (V + 45634)
+ 0x1110, 0x1171, 0x11b1, 0,
+#undef V11976
+#define V11976 (V + 45638)
+ 0x1110, 0x1171, 0x11b2, 0,
+#undef V11977
+#define V11977 (V + 45642)
+ 0x1110, 0x1171, 0x11b3, 0,
+#undef V11978
+#define V11978 (V + 45646)
+ 0x1110, 0x1171, 0x11b4, 0,
+#undef V11979
+#define V11979 (V + 45650)
+ 0x1110, 0x1171, 0x11b5, 0,
+#undef V11980
+#define V11980 (V + 45654)
+ 0x1110, 0x1171, 0x11b6, 0,
+#undef V11981
+#define V11981 (V + 45658)
+ 0x1110, 0x1171, 0x11b7, 0,
+#undef V11982
+#define V11982 (V + 45662)
+ 0x1110, 0x1171, 0x11b8, 0,
+#undef V11983
+#define V11983 (V + 45666)
+ 0x1110, 0x1171, 0x11b9, 0,
+#undef V11984
+#define V11984 (V + 45670)
+ 0x1110, 0x1171, 0x11ba, 0,
+#undef V11985
+#define V11985 (V + 45674)
+ 0x1110, 0x1171, 0x11bb, 0,
+#undef V11986
+#define V11986 (V + 45678)
+ 0x1110, 0x1171, 0x11bc, 0,
+#undef V11987
+#define V11987 (V + 45682)
+ 0x1110, 0x1171, 0x11bd, 0,
+#undef V11988
+#define V11988 (V + 45686)
+ 0x1110, 0x1171, 0x11be, 0,
+#undef V11989
+#define V11989 (V + 45690)
+ 0x1110, 0x1171, 0x11bf, 0,
+#undef V11990
+#define V11990 (V + 45694)
+ 0x1110, 0x1171, 0x11c0, 0,
+#undef V11991
+#define V11991 (V + 45698)
+ 0x1110, 0x1171, 0x11c1, 0,
+#undef V11992
+#define V11992 (V + 45702)
+ 0x1110, 0x1171, 0x11c2, 0,
+#undef V11993
+#define V11993 (V + 45706)
+ 0x1110, 0x1172, 0,
+#undef V11994
+#define V11994 (V + 45709)
+ 0x1110, 0x1172, 0x11a8, 0,
+#undef V11995
+#define V11995 (V + 45713)
+ 0x1110, 0x1172, 0x11a9, 0,
+#undef V11996
+#define V11996 (V + 45717)
+ 0x1110, 0x1172, 0x11aa, 0,
+#undef V11997
+#define V11997 (V + 45721)
+ 0x1110, 0x1172, 0x11ab, 0,
+#undef V11998
+#define V11998 (V + 45725)
+ 0x1110, 0x1172, 0x11ac, 0,
+#undef V11999
+#define V11999 (V + 45729)
+ 0x1110, 0x1172, 0x11ad, 0,
+#undef V12000
+#define V12000 (V + 45733)
+ 0x1110, 0x1172, 0x11ae, 0,
+#undef V12001
+#define V12001 (V + 45737)
+ 0x1110, 0x1172, 0x11af, 0,
+#undef V12002
+#define V12002 (V + 45741)
+ 0x1110, 0x1172, 0x11b0, 0,
+#undef V12003
+#define V12003 (V + 45745)
+ 0x1110, 0x1172, 0x11b1, 0,
+#undef V12004
+#define V12004 (V + 45749)
+ 0x1110, 0x1172, 0x11b2, 0,
+#undef V12005
+#define V12005 (V + 45753)
+ 0x1110, 0x1172, 0x11b3, 0,
+#undef V12006
+#define V12006 (V + 45757)
+ 0x1110, 0x1172, 0x11b4, 0,
+#undef V12007
+#define V12007 (V + 45761)
+ 0x1110, 0x1172, 0x11b5, 0,
+#undef V12008
+#define V12008 (V + 45765)
+ 0x1110, 0x1172, 0x11b6, 0,
+#undef V12009
+#define V12009 (V + 45769)
+ 0x1110, 0x1172, 0x11b7, 0,
+#undef V12010
+#define V12010 (V + 45773)
+ 0x1110, 0x1172, 0x11b8, 0,
+#undef V12011
+#define V12011 (V + 45777)
+ 0x1110, 0x1172, 0x11b9, 0,
+#undef V12012
+#define V12012 (V + 45781)
+ 0x1110, 0x1172, 0x11ba, 0,
+#undef V12013
+#define V12013 (V + 45785)
+ 0x1110, 0x1172, 0x11bb, 0,
+#undef V12014
+#define V12014 (V + 45789)
+ 0x1110, 0x1172, 0x11bc, 0,
+#undef V12015
+#define V12015 (V + 45793)
+ 0x1110, 0x1172, 0x11bd, 0,
+#undef V12016
+#define V12016 (V + 45797)
+ 0x1110, 0x1172, 0x11be, 0,
+#undef V12017
+#define V12017 (V + 45801)
+ 0x1110, 0x1172, 0x11bf, 0,
+#undef V12018
+#define V12018 (V + 45805)
+ 0x1110, 0x1172, 0x11c0, 0,
+#undef V12019
+#define V12019 (V + 45809)
+ 0x1110, 0x1172, 0x11c1, 0,
+#undef V12020
+#define V12020 (V + 45813)
+ 0x1110, 0x1172, 0x11c2, 0,
+#undef V12021
+#define V12021 (V + 45817)
+ 0x1110, 0x1173, 0,
+#undef V12022
+#define V12022 (V + 45820)
+ 0x1110, 0x1173, 0x11a8, 0,
+#undef V12023
+#define V12023 (V + 45824)
+ 0x1110, 0x1173, 0x11a9, 0,
+#undef V12024
+#define V12024 (V + 45828)
+ 0x1110, 0x1173, 0x11aa, 0,
+#undef V12025
+#define V12025 (V + 45832)
+ 0x1110, 0x1173, 0x11ab, 0,
+#undef V12026
+#define V12026 (V + 45836)
+ 0x1110, 0x1173, 0x11ac, 0,
+#undef V12027
+#define V12027 (V + 45840)
+ 0x1110, 0x1173, 0x11ad, 0,
+#undef V12028
+#define V12028 (V + 45844)
+ 0x1110, 0x1173, 0x11ae, 0,
+#undef V12029
+#define V12029 (V + 45848)
+ 0x1110, 0x1173, 0x11af, 0,
+#undef V12030
+#define V12030 (V + 45852)
+ 0x1110, 0x1173, 0x11b0, 0,
+#undef V12031
+#define V12031 (V + 45856)
+ 0x1110, 0x1173, 0x11b1, 0,
+#undef V12032
+#define V12032 (V + 45860)
+ 0x1110, 0x1173, 0x11b2, 0,
+#undef V12033
+#define V12033 (V + 45864)
+ 0x1110, 0x1173, 0x11b3, 0,
+#undef V12034
+#define V12034 (V + 45868)
+ 0x1110, 0x1173, 0x11b4, 0,
+#undef V12035
+#define V12035 (V + 45872)
+ 0x1110, 0x1173, 0x11b5, 0,
+#undef V12036
+#define V12036 (V + 45876)
+ 0x1110, 0x1173, 0x11b6, 0,
+#undef V12037
+#define V12037 (V + 45880)
+ 0x1110, 0x1173, 0x11b7, 0,
+#undef V12038
+#define V12038 (V + 45884)
+ 0x1110, 0x1173, 0x11b8, 0,
+#undef V12039
+#define V12039 (V + 45888)
+ 0x1110, 0x1173, 0x11b9, 0,
+#undef V12040
+#define V12040 (V + 45892)
+ 0x1110, 0x1173, 0x11ba, 0,
+#undef V12041
+#define V12041 (V + 45896)
+ 0x1110, 0x1173, 0x11bb, 0,
+#undef V12042
+#define V12042 (V + 45900)
+ 0x1110, 0x1173, 0x11bc, 0,
+#undef V12043
+#define V12043 (V + 45904)
+ 0x1110, 0x1173, 0x11bd, 0,
+#undef V12044
+#define V12044 (V + 45908)
+ 0x1110, 0x1173, 0x11be, 0,
+#undef V12045
+#define V12045 (V + 45912)
+ 0x1110, 0x1173, 0x11bf, 0,
+#undef V12046
+#define V12046 (V + 45916)
+ 0x1110, 0x1173, 0x11c0, 0,
+#undef V12047
+#define V12047 (V + 45920)
+ 0x1110, 0x1173, 0x11c1, 0,
+#undef V12048
+#define V12048 (V + 45924)
+ 0x1110, 0x1173, 0x11c2, 0,
+#undef V12049
+#define V12049 (V + 45928)
+ 0x1110, 0x1174, 0,
+#undef V12050
+#define V12050 (V + 45931)
+ 0x1110, 0x1174, 0x11a8, 0,
+#undef V12051
+#define V12051 (V + 45935)
+ 0x1110, 0x1174, 0x11a9, 0,
+#undef V12052
+#define V12052 (V + 45939)
+ 0x1110, 0x1174, 0x11aa, 0,
+#undef V12053
+#define V12053 (V + 45943)
+ 0x1110, 0x1174, 0x11ab, 0,
+#undef V12054
+#define V12054 (V + 45947)
+ 0x1110, 0x1174, 0x11ac, 0,
+#undef V12055
+#define V12055 (V + 45951)
+ 0x1110, 0x1174, 0x11ad, 0,
+#undef V12056
+#define V12056 (V + 45955)
+ 0x1110, 0x1174, 0x11ae, 0,
+#undef V12057
+#define V12057 (V + 45959)
+ 0x1110, 0x1174, 0x11af, 0,
+#undef V12058
+#define V12058 (V + 45963)
+ 0x1110, 0x1174, 0x11b0, 0,
+#undef V12059
+#define V12059 (V + 45967)
+ 0x1110, 0x1174, 0x11b1, 0,
+#undef V12060
+#define V12060 (V + 45971)
+ 0x1110, 0x1174, 0x11b2, 0,
+#undef V12061
+#define V12061 (V + 45975)
+ 0x1110, 0x1174, 0x11b3, 0,
+#undef V12062
+#define V12062 (V + 45979)
+ 0x1110, 0x1174, 0x11b4, 0,
+#undef V12063
+#define V12063 (V + 45983)
+ 0x1110, 0x1174, 0x11b5, 0,
+#undef V12064
+#define V12064 (V + 45987)
+ 0x1110, 0x1174, 0x11b6, 0,
+#undef V12065
+#define V12065 (V + 45991)
+ 0x1110, 0x1174, 0x11b7, 0,
+#undef V12066
+#define V12066 (V + 45995)
+ 0x1110, 0x1174, 0x11b8, 0,
+#undef V12067
+#define V12067 (V + 45999)
+ 0x1110, 0x1174, 0x11b9, 0,
+#undef V12068
+#define V12068 (V + 46003)
+ 0x1110, 0x1174, 0x11ba, 0,
+#undef V12069
+#define V12069 (V + 46007)
+ 0x1110, 0x1174, 0x11bb, 0,
+#undef V12070
+#define V12070 (V + 46011)
+ 0x1110, 0x1174, 0x11bc, 0,
+#undef V12071
+#define V12071 (V + 46015)
+ 0x1110, 0x1174, 0x11bd, 0,
+#undef V12072
+#define V12072 (V + 46019)
+ 0x1110, 0x1174, 0x11be, 0,
+#undef V12073
+#define V12073 (V + 46023)
+ 0x1110, 0x1174, 0x11bf, 0,
+#undef V12074
+#define V12074 (V + 46027)
+ 0x1110, 0x1174, 0x11c0, 0,
+#undef V12075
+#define V12075 (V + 46031)
+ 0x1110, 0x1174, 0x11c1, 0,
+#undef V12076
+#define V12076 (V + 46035)
+ 0x1110, 0x1174, 0x11c2, 0,
+#undef V12077
+#define V12077 (V + 46039)
+ 0x1110, 0x1175, 0,
+#undef V12078
+#define V12078 (V + 46042)
+ 0x1110, 0x1175, 0x11a8, 0,
+#undef V12079
+#define V12079 (V + 46046)
+ 0x1110, 0x1175, 0x11a9, 0,
+#undef V12080
+#define V12080 (V + 46050)
+ 0x1110, 0x1175, 0x11aa, 0,
+#undef V12081
+#define V12081 (V + 46054)
+ 0x1110, 0x1175, 0x11ab, 0,
+#undef V12082
+#define V12082 (V + 46058)
+ 0x1110, 0x1175, 0x11ac, 0,
+#undef V12083
+#define V12083 (V + 46062)
+ 0x1110, 0x1175, 0x11ad, 0,
+#undef V12084
+#define V12084 (V + 46066)
+ 0x1110, 0x1175, 0x11ae, 0,
+#undef V12085
+#define V12085 (V + 46070)
+ 0x1110, 0x1175, 0x11af, 0,
+#undef V12086
+#define V12086 (V + 46074)
+ 0x1110, 0x1175, 0x11b0, 0,
+#undef V12087
+#define V12087 (V + 46078)
+ 0x1110, 0x1175, 0x11b1, 0,
+#undef V12088
+#define V12088 (V + 46082)
+ 0x1110, 0x1175, 0x11b2, 0,
+#undef V12089
+#define V12089 (V + 46086)
+ 0x1110, 0x1175, 0x11b3, 0,
+#undef V12090
+#define V12090 (V + 46090)
+ 0x1110, 0x1175, 0x11b4, 0,
+#undef V12091
+#define V12091 (V + 46094)
+ 0x1110, 0x1175, 0x11b5, 0,
+#undef V12092
+#define V12092 (V + 46098)
+ 0x1110, 0x1175, 0x11b6, 0,
+#undef V12093
+#define V12093 (V + 46102)
+ 0x1110, 0x1175, 0x11b7, 0,
+#undef V12094
+#define V12094 (V + 46106)
+ 0x1110, 0x1175, 0x11b8, 0,
+#undef V12095
+#define V12095 (V + 46110)
+ 0x1110, 0x1175, 0x11b9, 0,
+#undef V12096
+#define V12096 (V + 46114)
+ 0x1110, 0x1175, 0x11ba, 0,
+#undef V12097
+#define V12097 (V + 46118)
+ 0x1110, 0x1175, 0x11bb, 0,
+#undef V12098
+#define V12098 (V + 46122)
+ 0x1110, 0x1175, 0x11bc, 0,
+#undef V12099
+#define V12099 (V + 46126)
+ 0x1110, 0x1175, 0x11bd, 0,
+#undef V12100
+#define V12100 (V + 46130)
+ 0x1110, 0x1175, 0x11be, 0,
+#undef V12101
+#define V12101 (V + 46134)
+ 0x1110, 0x1175, 0x11bf, 0,
+#undef V12102
+#define V12102 (V + 46138)
+ 0x1110, 0x1175, 0x11c0, 0,
+#undef V12103
+#define V12103 (V + 46142)
+ 0x1110, 0x1175, 0x11c1, 0,
+#undef V12104
+#define V12104 (V + 46146)
+ 0x1110, 0x1175, 0x11c2, 0,
+#undef V12105
+#define V12105 (V + 46150)
+ 0x1111, 0x1161, 0x11a8, 0,
+#undef V12106
+#define V12106 (V + 46154)
+ 0x1111, 0x1161, 0x11a9, 0,
+#undef V12107
+#define V12107 (V + 46158)
+ 0x1111, 0x1161, 0x11aa, 0,
+#undef V12108
+#define V12108 (V + 46162)
+ 0x1111, 0x1161, 0x11ab, 0,
+#undef V12109
+#define V12109 (V + 46166)
+ 0x1111, 0x1161, 0x11ac, 0,
+#undef V12110
+#define V12110 (V + 46170)
+ 0x1111, 0x1161, 0x11ad, 0,
+#undef V12111
+#define V12111 (V + 46174)
+ 0x1111, 0x1161, 0x11ae, 0,
+#undef V12112
+#define V12112 (V + 46178)
+ 0x1111, 0x1161, 0x11af, 0,
+#undef V12113
+#define V12113 (V + 46182)
+ 0x1111, 0x1161, 0x11b0, 0,
+#undef V12114
+#define V12114 (V + 46186)
+ 0x1111, 0x1161, 0x11b1, 0,
+#undef V12115
+#define V12115 (V + 46190)
+ 0x1111, 0x1161, 0x11b2, 0,
+#undef V12116
+#define V12116 (V + 46194)
+ 0x1111, 0x1161, 0x11b3, 0,
+#undef V12117
+#define V12117 (V + 46198)
+ 0x1111, 0x1161, 0x11b4, 0,
+#undef V12118
+#define V12118 (V + 46202)
+ 0x1111, 0x1161, 0x11b5, 0,
+#undef V12119
+#define V12119 (V + 46206)
+ 0x1111, 0x1161, 0x11b6, 0,
+#undef V12120
+#define V12120 (V + 46210)
+ 0x1111, 0x1161, 0x11b7, 0,
+#undef V12121
+#define V12121 (V + 46214)
+ 0x1111, 0x1161, 0x11b8, 0,
+#undef V12122
+#define V12122 (V + 46218)
+ 0x1111, 0x1161, 0x11b9, 0,
+#undef V12123
+#define V12123 (V + 46222)
+ 0x1111, 0x1161, 0x11ba, 0,
+#undef V12124
+#define V12124 (V + 46226)
+ 0x1111, 0x1161, 0x11bb, 0,
+#undef V12125
+#define V12125 (V + 46230)
+ 0x1111, 0x1161, 0x11bc, 0,
+#undef V12126
+#define V12126 (V + 46234)
+ 0x1111, 0x1161, 0x11bd, 0,
+#undef V12127
+#define V12127 (V + 46238)
+ 0x1111, 0x1161, 0x11be, 0,
+#undef V12128
+#define V12128 (V + 46242)
+ 0x1111, 0x1161, 0x11bf, 0,
+#undef V12129
+#define V12129 (V + 46246)
+ 0x1111, 0x1161, 0x11c0, 0,
+#undef V12130
+#define V12130 (V + 46250)
+ 0x1111, 0x1161, 0x11c1, 0,
+#undef V12131
+#define V12131 (V + 46254)
+ 0x1111, 0x1161, 0x11c2, 0,
+#undef V12132
+#define V12132 (V + 46258)
+ 0x1111, 0x1162, 0,
+#undef V12133
+#define V12133 (V + 46261)
+ 0x1111, 0x1162, 0x11a8, 0,
+#undef V12134
+#define V12134 (V + 46265)
+ 0x1111, 0x1162, 0x11a9, 0,
+#undef V12135
+#define V12135 (V + 46269)
+ 0x1111, 0x1162, 0x11aa, 0,
+#undef V12136
+#define V12136 (V + 46273)
+ 0x1111, 0x1162, 0x11ab, 0,
+#undef V12137
+#define V12137 (V + 46277)
+ 0x1111, 0x1162, 0x11ac, 0,
+#undef V12138
+#define V12138 (V + 46281)
+ 0x1111, 0x1162, 0x11ad, 0,
+#undef V12139
+#define V12139 (V + 46285)
+ 0x1111, 0x1162, 0x11ae, 0,
+#undef V12140
+#define V12140 (V + 46289)
+ 0x1111, 0x1162, 0x11af, 0,
+#undef V12141
+#define V12141 (V + 46293)
+ 0x1111, 0x1162, 0x11b0, 0,
+#undef V12142
+#define V12142 (V + 46297)
+ 0x1111, 0x1162, 0x11b1, 0,
+#undef V12143
+#define V12143 (V + 46301)
+ 0x1111, 0x1162, 0x11b2, 0,
+#undef V12144
+#define V12144 (V + 46305)
+ 0x1111, 0x1162, 0x11b3, 0,
+#undef V12145
+#define V12145 (V + 46309)
+ 0x1111, 0x1162, 0x11b4, 0,
+#undef V12146
+#define V12146 (V + 46313)
+ 0x1111, 0x1162, 0x11b5, 0,
+#undef V12147
+#define V12147 (V + 46317)
+ 0x1111, 0x1162, 0x11b6, 0,
+#undef V12148
+#define V12148 (V + 46321)
+ 0x1111, 0x1162, 0x11b7, 0,
+#undef V12149
+#define V12149 (V + 46325)
+ 0x1111, 0x1162, 0x11b8, 0,
+#undef V12150
+#define V12150 (V + 46329)
+ 0x1111, 0x1162, 0x11b9, 0,
+#undef V12151
+#define V12151 (V + 46333)
+ 0x1111, 0x1162, 0x11ba, 0,
+#undef V12152
+#define V12152 (V + 46337)
+ 0x1111, 0x1162, 0x11bb, 0,
+#undef V12153
+#define V12153 (V + 46341)
+ 0x1111, 0x1162, 0x11bc, 0,
+#undef V12154
+#define V12154 (V + 46345)
+ 0x1111, 0x1162, 0x11bd, 0,
+#undef V12155
+#define V12155 (V + 46349)
+ 0x1111, 0x1162, 0x11be, 0,
+#undef V12156
+#define V12156 (V + 46353)
+ 0x1111, 0x1162, 0x11bf, 0,
+#undef V12157
+#define V12157 (V + 46357)
+ 0x1111, 0x1162, 0x11c0, 0,
+#undef V12158
+#define V12158 (V + 46361)
+ 0x1111, 0x1162, 0x11c1, 0,
+#undef V12159
+#define V12159 (V + 46365)
+ 0x1111, 0x1162, 0x11c2, 0,
+#undef V12160
+#define V12160 (V + 46369)
+ 0x1111, 0x1163, 0,
+#undef V12161
+#define V12161 (V + 46372)
+ 0x1111, 0x1163, 0x11a8, 0,
+#undef V12162
+#define V12162 (V + 46376)
+ 0x1111, 0x1163, 0x11a9, 0,
+#undef V12163
+#define V12163 (V + 46380)
+ 0x1111, 0x1163, 0x11aa, 0,
+#undef V12164
+#define V12164 (V + 46384)
+ 0x1111, 0x1163, 0x11ab, 0,
+#undef V12165
+#define V12165 (V + 46388)
+ 0x1111, 0x1163, 0x11ac, 0,
+#undef V12166
+#define V12166 (V + 46392)
+ 0x1111, 0x1163, 0x11ad, 0,
+#undef V12167
+#define V12167 (V + 46396)
+ 0x1111, 0x1163, 0x11ae, 0,
+#undef V12168
+#define V12168 (V + 46400)
+ 0x1111, 0x1163, 0x11af, 0,
+#undef V12169
+#define V12169 (V + 46404)
+ 0x1111, 0x1163, 0x11b0, 0,
+#undef V12170
+#define V12170 (V + 46408)
+ 0x1111, 0x1163, 0x11b1, 0,
+#undef V12171
+#define V12171 (V + 46412)
+ 0x1111, 0x1163, 0x11b2, 0,
+#undef V12172
+#define V12172 (V + 46416)
+ 0x1111, 0x1163, 0x11b3, 0,
+#undef V12173
+#define V12173 (V + 46420)
+ 0x1111, 0x1163, 0x11b4, 0,
+#undef V12174
+#define V12174 (V + 46424)
+ 0x1111, 0x1163, 0x11b5, 0,
+#undef V12175
+#define V12175 (V + 46428)
+ 0x1111, 0x1163, 0x11b6, 0,
+#undef V12176
+#define V12176 (V + 46432)
+ 0x1111, 0x1163, 0x11b7, 0,
+#undef V12177
+#define V12177 (V + 46436)
+ 0x1111, 0x1163, 0x11b8, 0,
+#undef V12178
+#define V12178 (V + 46440)
+ 0x1111, 0x1163, 0x11b9, 0,
+#undef V12179
+#define V12179 (V + 46444)
+ 0x1111, 0x1163, 0x11ba, 0,
+#undef V12180
+#define V12180 (V + 46448)
+ 0x1111, 0x1163, 0x11bb, 0,
+#undef V12181
+#define V12181 (V + 46452)
+ 0x1111, 0x1163, 0x11bc, 0,
+#undef V12182
+#define V12182 (V + 46456)
+ 0x1111, 0x1163, 0x11bd, 0,
+#undef V12183
+#define V12183 (V + 46460)
+ 0x1111, 0x1163, 0x11be, 0,
+#undef V12184
+#define V12184 (V + 46464)
+ 0x1111, 0x1163, 0x11bf, 0,
+#undef V12185
+#define V12185 (V + 46468)
+ 0x1111, 0x1163, 0x11c0, 0,
+#undef V12186
+#define V12186 (V + 46472)
+ 0x1111, 0x1163, 0x11c1, 0,
+#undef V12187
+#define V12187 (V + 46476)
+ 0x1111, 0x1163, 0x11c2, 0,
+#undef V12188
+#define V12188 (V + 46480)
+ 0x1111, 0x1164, 0,
+#undef V12189
+#define V12189 (V + 46483)
+ 0x1111, 0x1164, 0x11a8, 0,
+#undef V12190
+#define V12190 (V + 46487)
+ 0x1111, 0x1164, 0x11a9, 0,
+#undef V12191
+#define V12191 (V + 46491)
+ 0x1111, 0x1164, 0x11aa, 0,
+#undef V12192
+#define V12192 (V + 46495)
+ 0x1111, 0x1164, 0x11ab, 0,
+#undef V12193
+#define V12193 (V + 46499)
+ 0x1111, 0x1164, 0x11ac, 0,
+#undef V12194
+#define V12194 (V + 46503)
+ 0x1111, 0x1164, 0x11ad, 0,
+#undef V12195
+#define V12195 (V + 46507)
+ 0x1111, 0x1164, 0x11ae, 0,
+#undef V12196
+#define V12196 (V + 46511)
+ 0x1111, 0x1164, 0x11af, 0,
+#undef V12197
+#define V12197 (V + 46515)
+ 0x1111, 0x1164, 0x11b0, 0,
+#undef V12198
+#define V12198 (V + 46519)
+ 0x1111, 0x1164, 0x11b1, 0,
+#undef V12199
+#define V12199 (V + 46523)
+ 0x1111, 0x1164, 0x11b2, 0,
+#undef V12200
+#define V12200 (V + 46527)
+ 0x1111, 0x1164, 0x11b3, 0,
+#undef V12201
+#define V12201 (V + 46531)
+ 0x1111, 0x1164, 0x11b4, 0,
+#undef V12202
+#define V12202 (V + 46535)
+ 0x1111, 0x1164, 0x11b5, 0,
+#undef V12203
+#define V12203 (V + 46539)
+ 0x1111, 0x1164, 0x11b6, 0,
+#undef V12204
+#define V12204 (V + 46543)
+ 0x1111, 0x1164, 0x11b7, 0,
+#undef V12205
+#define V12205 (V + 46547)
+ 0x1111, 0x1164, 0x11b8, 0,
+#undef V12206
+#define V12206 (V + 46551)
+ 0x1111, 0x1164, 0x11b9, 0,
+#undef V12207
+#define V12207 (V + 46555)
+ 0x1111, 0x1164, 0x11ba, 0,
+#undef V12208
+#define V12208 (V + 46559)
+ 0x1111, 0x1164, 0x11bb, 0,
+#undef V12209
+#define V12209 (V + 46563)
+ 0x1111, 0x1164, 0x11bc, 0,
+#undef V12210
+#define V12210 (V + 46567)
+ 0x1111, 0x1164, 0x11bd, 0,
+#undef V12211
+#define V12211 (V + 46571)
+ 0x1111, 0x1164, 0x11be, 0,
+#undef V12212
+#define V12212 (V + 46575)
+ 0x1111, 0x1164, 0x11bf, 0,
+#undef V12213
+#define V12213 (V + 46579)
+ 0x1111, 0x1164, 0x11c0, 0,
+#undef V12214
+#define V12214 (V + 46583)
+ 0x1111, 0x1164, 0x11c1, 0,
+#undef V12215
+#define V12215 (V + 46587)
+ 0x1111, 0x1164, 0x11c2, 0,
+#undef V12216
+#define V12216 (V + 46591)
+ 0x1111, 0x1165, 0,
+#undef V12217
+#define V12217 (V + 46594)
+ 0x1111, 0x1165, 0x11a8, 0,
+#undef V12218
+#define V12218 (V + 46598)
+ 0x1111, 0x1165, 0x11a9, 0,
+#undef V12219
+#define V12219 (V + 46602)
+ 0x1111, 0x1165, 0x11aa, 0,
+#undef V12220
+#define V12220 (V + 46606)
+ 0x1111, 0x1165, 0x11ab, 0,
+#undef V12221
+#define V12221 (V + 46610)
+ 0x1111, 0x1165, 0x11ac, 0,
+#undef V12222
+#define V12222 (V + 46614)
+ 0x1111, 0x1165, 0x11ad, 0,
+#undef V12223
+#define V12223 (V + 46618)
+ 0x1111, 0x1165, 0x11ae, 0,
+#undef V12224
+#define V12224 (V + 46622)
+ 0x1111, 0x1165, 0x11af, 0,
+#undef V12225
+#define V12225 (V + 46626)
+ 0x1111, 0x1165, 0x11b0, 0,
+#undef V12226
+#define V12226 (V + 46630)
+ 0x1111, 0x1165, 0x11b1, 0,
+#undef V12227
+#define V12227 (V + 46634)
+ 0x1111, 0x1165, 0x11b2, 0,
+#undef V12228
+#define V12228 (V + 46638)
+ 0x1111, 0x1165, 0x11b3, 0,
+#undef V12229
+#define V12229 (V + 46642)
+ 0x1111, 0x1165, 0x11b4, 0,
+#undef V12230
+#define V12230 (V + 46646)
+ 0x1111, 0x1165, 0x11b5, 0,
+#undef V12231
+#define V12231 (V + 46650)
+ 0x1111, 0x1165, 0x11b6, 0,
+#undef V12232
+#define V12232 (V + 46654)
+ 0x1111, 0x1165, 0x11b7, 0,
+#undef V12233
+#define V12233 (V + 46658)
+ 0x1111, 0x1165, 0x11b8, 0,
+#undef V12234
+#define V12234 (V + 46662)
+ 0x1111, 0x1165, 0x11b9, 0,
+#undef V12235
+#define V12235 (V + 46666)
+ 0x1111, 0x1165, 0x11ba, 0,
+#undef V12236
+#define V12236 (V + 46670)
+ 0x1111, 0x1165, 0x11bb, 0,
+#undef V12237
+#define V12237 (V + 46674)
+ 0x1111, 0x1165, 0x11bc, 0,
+#undef V12238
+#define V12238 (V + 46678)
+ 0x1111, 0x1165, 0x11bd, 0,
+#undef V12239
+#define V12239 (V + 46682)
+ 0x1111, 0x1165, 0x11be, 0,
+#undef V12240
+#define V12240 (V + 46686)
+ 0x1111, 0x1165, 0x11bf, 0,
+#undef V12241
+#define V12241 (V + 46690)
+ 0x1111, 0x1165, 0x11c0, 0,
+#undef V12242
+#define V12242 (V + 46694)
+ 0x1111, 0x1165, 0x11c1, 0,
+#undef V12243
+#define V12243 (V + 46698)
+ 0x1111, 0x1165, 0x11c2, 0,
+#undef V12244
+#define V12244 (V + 46702)
+ 0x1111, 0x1166, 0,
+#undef V12245
+#define V12245 (V + 46705)
+ 0x1111, 0x1166, 0x11a8, 0,
+#undef V12246
+#define V12246 (V + 46709)
+ 0x1111, 0x1166, 0x11a9, 0,
+#undef V12247
+#define V12247 (V + 46713)
+ 0x1111, 0x1166, 0x11aa, 0,
+#undef V12248
+#define V12248 (V + 46717)
+ 0x1111, 0x1166, 0x11ab, 0,
+#undef V12249
+#define V12249 (V + 46721)
+ 0x1111, 0x1166, 0x11ac, 0,
+#undef V12250
+#define V12250 (V + 46725)
+ 0x1111, 0x1166, 0x11ad, 0,
+#undef V12251
+#define V12251 (V + 46729)
+ 0x1111, 0x1166, 0x11ae, 0,
+#undef V12252
+#define V12252 (V + 46733)
+ 0x1111, 0x1166, 0x11af, 0,
+#undef V12253
+#define V12253 (V + 46737)
+ 0x1111, 0x1166, 0x11b0, 0,
+#undef V12254
+#define V12254 (V + 46741)
+ 0x1111, 0x1166, 0x11b1, 0,
+#undef V12255
+#define V12255 (V + 46745)
+ 0x1111, 0x1166, 0x11b2, 0,
+#undef V12256
+#define V12256 (V + 46749)
+ 0x1111, 0x1166, 0x11b3, 0,
+#undef V12257
+#define V12257 (V + 46753)
+ 0x1111, 0x1166, 0x11b4, 0,
+#undef V12258
+#define V12258 (V + 46757)
+ 0x1111, 0x1166, 0x11b5, 0,
+#undef V12259
+#define V12259 (V + 46761)
+ 0x1111, 0x1166, 0x11b6, 0,
+#undef V12260
+#define V12260 (V + 46765)
+ 0x1111, 0x1166, 0x11b7, 0,
+#undef V12261
+#define V12261 (V + 46769)
+ 0x1111, 0x1166, 0x11b8, 0,
+#undef V12262
+#define V12262 (V + 46773)
+ 0x1111, 0x1166, 0x11b9, 0,
+#undef V12263
+#define V12263 (V + 46777)
+ 0x1111, 0x1166, 0x11ba, 0,
+#undef V12264
+#define V12264 (V + 46781)
+ 0x1111, 0x1166, 0x11bb, 0,
+#undef V12265
+#define V12265 (V + 46785)
+ 0x1111, 0x1166, 0x11bc, 0,
+#undef V12266
+#define V12266 (V + 46789)
+ 0x1111, 0x1166, 0x11bd, 0,
+#undef V12267
+#define V12267 (V + 46793)
+ 0x1111, 0x1166, 0x11be, 0,
+#undef V12268
+#define V12268 (V + 46797)
+ 0x1111, 0x1166, 0x11bf, 0,
+#undef V12269
+#define V12269 (V + 46801)
+ 0x1111, 0x1166, 0x11c0, 0,
+#undef V12270
+#define V12270 (V + 46805)
+ 0x1111, 0x1166, 0x11c1, 0,
+#undef V12271
+#define V12271 (V + 46809)
+ 0x1111, 0x1166, 0x11c2, 0,
+#undef V12272
+#define V12272 (V + 46813)
+ 0x1111, 0x1167, 0,
+#undef V12273
+#define V12273 (V + 46816)
+ 0x1111, 0x1167, 0x11a8, 0,
+#undef V12274
+#define V12274 (V + 46820)
+ 0x1111, 0x1167, 0x11a9, 0,
+#undef V12275
+#define V12275 (V + 46824)
+ 0x1111, 0x1167, 0x11aa, 0,
+#undef V12276
+#define V12276 (V + 46828)
+ 0x1111, 0x1167, 0x11ab, 0,
+#undef V12277
+#define V12277 (V + 46832)
+ 0x1111, 0x1167, 0x11ac, 0,
+#undef V12278
+#define V12278 (V + 46836)
+ 0x1111, 0x1167, 0x11ad, 0,
+#undef V12279
+#define V12279 (V + 46840)
+ 0x1111, 0x1167, 0x11ae, 0,
+#undef V12280
+#define V12280 (V + 46844)
+ 0x1111, 0x1167, 0x11af, 0,
+#undef V12281
+#define V12281 (V + 46848)
+ 0x1111, 0x1167, 0x11b0, 0,
+#undef V12282
+#define V12282 (V + 46852)
+ 0x1111, 0x1167, 0x11b1, 0,
+#undef V12283
+#define V12283 (V + 46856)
+ 0x1111, 0x1167, 0x11b2, 0,
+#undef V12284
+#define V12284 (V + 46860)
+ 0x1111, 0x1167, 0x11b3, 0,
+#undef V12285
+#define V12285 (V + 46864)
+ 0x1111, 0x1167, 0x11b4, 0,
+#undef V12286
+#define V12286 (V + 46868)
+ 0x1111, 0x1167, 0x11b5, 0,
+#undef V12287
+#define V12287 (V + 46872)
+ 0x1111, 0x1167, 0x11b6, 0,
+#undef V12288
+#define V12288 (V + 46876)
+ 0x1111, 0x1167, 0x11b7, 0,
+#undef V12289
+#define V12289 (V + 46880)
+ 0x1111, 0x1167, 0x11b8, 0,
+#undef V12290
+#define V12290 (V + 46884)
+ 0x1111, 0x1167, 0x11b9, 0,
+#undef V12291
+#define V12291 (V + 46888)
+ 0x1111, 0x1167, 0x11ba, 0,
+#undef V12292
+#define V12292 (V + 46892)
+ 0x1111, 0x1167, 0x11bb, 0,
+#undef V12293
+#define V12293 (V + 46896)
+ 0x1111, 0x1167, 0x11bc, 0,
+#undef V12294
+#define V12294 (V + 46900)
+ 0x1111, 0x1167, 0x11bd, 0,
+#undef V12295
+#define V12295 (V + 46904)
+ 0x1111, 0x1167, 0x11be, 0,
+#undef V12296
+#define V12296 (V + 46908)
+ 0x1111, 0x1167, 0x11bf, 0,
+#undef V12297
+#define V12297 (V + 46912)
+ 0x1111, 0x1167, 0x11c0, 0,
+#undef V12298
+#define V12298 (V + 46916)
+ 0x1111, 0x1167, 0x11c1, 0,
+#undef V12299
+#define V12299 (V + 46920)
+ 0x1111, 0x1167, 0x11c2, 0,
+#undef V12300
+#define V12300 (V + 46924)
+ 0x1111, 0x1168, 0,
+#undef V12301
+#define V12301 (V + 46927)
+ 0x1111, 0x1168, 0x11a8, 0,
+#undef V12302
+#define V12302 (V + 46931)
+ 0x1111, 0x1168, 0x11a9, 0,
+#undef V12303
+#define V12303 (V + 46935)
+ 0x1111, 0x1168, 0x11aa, 0,
+#undef V12304
+#define V12304 (V + 46939)
+ 0x1111, 0x1168, 0x11ab, 0,
+#undef V12305
+#define V12305 (V + 46943)
+ 0x1111, 0x1168, 0x11ac, 0,
+#undef V12306
+#define V12306 (V + 46947)
+ 0x1111, 0x1168, 0x11ad, 0,
+#undef V12307
+#define V12307 (V + 46951)
+ 0x1111, 0x1168, 0x11ae, 0,
+#undef V12308
+#define V12308 (V + 46955)
+ 0x1111, 0x1168, 0x11af, 0,
+#undef V12309
+#define V12309 (V + 46959)
+ 0x1111, 0x1168, 0x11b0, 0,
+#undef V12310
+#define V12310 (V + 46963)
+ 0x1111, 0x1168, 0x11b1, 0,
+#undef V12311
+#define V12311 (V + 46967)
+ 0x1111, 0x1168, 0x11b2, 0,
+#undef V12312
+#define V12312 (V + 46971)
+ 0x1111, 0x1168, 0x11b3, 0,
+#undef V12313
+#define V12313 (V + 46975)
+ 0x1111, 0x1168, 0x11b4, 0,
+#undef V12314
+#define V12314 (V + 46979)
+ 0x1111, 0x1168, 0x11b5, 0,
+#undef V12315
+#define V12315 (V + 46983)
+ 0x1111, 0x1168, 0x11b6, 0,
+#undef V12316
+#define V12316 (V + 46987)
+ 0x1111, 0x1168, 0x11b7, 0,
+#undef V12317
+#define V12317 (V + 46991)
+ 0x1111, 0x1168, 0x11b8, 0,
+#undef V12318
+#define V12318 (V + 46995)
+ 0x1111, 0x1168, 0x11b9, 0,
+#undef V12319
+#define V12319 (V + 46999)
+ 0x1111, 0x1168, 0x11ba, 0,
+#undef V12320
+#define V12320 (V + 47003)
+ 0x1111, 0x1168, 0x11bb, 0,
+#undef V12321
+#define V12321 (V + 47007)
+ 0x1111, 0x1168, 0x11bc, 0,
+#undef V12322
+#define V12322 (V + 47011)
+ 0x1111, 0x1168, 0x11bd, 0,
+#undef V12323
+#define V12323 (V + 47015)
+ 0x1111, 0x1168, 0x11be, 0,
+#undef V12324
+#define V12324 (V + 47019)
+ 0x1111, 0x1168, 0x11bf, 0,
+#undef V12325
+#define V12325 (V + 47023)
+ 0x1111, 0x1168, 0x11c0, 0,
+#undef V12326
+#define V12326 (V + 47027)
+ 0x1111, 0x1168, 0x11c1, 0,
+#undef V12327
+#define V12327 (V + 47031)
+ 0x1111, 0x1168, 0x11c2, 0,
+#undef V12328
+#define V12328 (V + 47035)
+ 0x1111, 0x1169, 0,
+#undef V12329
+#define V12329 (V + 47038)
+ 0x1111, 0x1169, 0x11a8, 0,
+#undef V12330
+#define V12330 (V + 47042)
+ 0x1111, 0x1169, 0x11a9, 0,
+#undef V12331
+#define V12331 (V + 47046)
+ 0x1111, 0x1169, 0x11aa, 0,
+#undef V12332
+#define V12332 (V + 47050)
+ 0x1111, 0x1169, 0x11ab, 0,
+#undef V12333
+#define V12333 (V + 47054)
+ 0x1111, 0x1169, 0x11ac, 0,
+#undef V12334
+#define V12334 (V + 47058)
+ 0x1111, 0x1169, 0x11ad, 0,
+#undef V12335
+#define V12335 (V + 47062)
+ 0x1111, 0x1169, 0x11ae, 0,
+#undef V12336
+#define V12336 (V + 47066)
+ 0x1111, 0x1169, 0x11af, 0,
+#undef V12337
+#define V12337 (V + 47070)
+ 0x1111, 0x1169, 0x11b0, 0,
+#undef V12338
+#define V12338 (V + 47074)
+ 0x1111, 0x1169, 0x11b1, 0,
+#undef V12339
+#define V12339 (V + 47078)
+ 0x1111, 0x1169, 0x11b2, 0,
+#undef V12340
+#define V12340 (V + 47082)
+ 0x1111, 0x1169, 0x11b3, 0,
+#undef V12341
+#define V12341 (V + 47086)
+ 0x1111, 0x1169, 0x11b4, 0,
+#undef V12342
+#define V12342 (V + 47090)
+ 0x1111, 0x1169, 0x11b5, 0,
+#undef V12343
+#define V12343 (V + 47094)
+ 0x1111, 0x1169, 0x11b6, 0,
+#undef V12344
+#define V12344 (V + 47098)
+ 0x1111, 0x1169, 0x11b7, 0,
+#undef V12345
+#define V12345 (V + 47102)
+ 0x1111, 0x1169, 0x11b8, 0,
+#undef V12346
+#define V12346 (V + 47106)
+ 0x1111, 0x1169, 0x11b9, 0,
+#undef V12347
+#define V12347 (V + 47110)
+ 0x1111, 0x1169, 0x11ba, 0,
+#undef V12348
+#define V12348 (V + 47114)
+ 0x1111, 0x1169, 0x11bb, 0,
+#undef V12349
+#define V12349 (V + 47118)
+ 0x1111, 0x1169, 0x11bc, 0,
+#undef V12350
+#define V12350 (V + 47122)
+ 0x1111, 0x1169, 0x11bd, 0,
+#undef V12351
+#define V12351 (V + 47126)
+ 0x1111, 0x1169, 0x11be, 0,
+#undef V12352
+#define V12352 (V + 47130)
+ 0x1111, 0x1169, 0x11bf, 0,
+#undef V12353
+#define V12353 (V + 47134)
+ 0x1111, 0x1169, 0x11c0, 0,
+#undef V12354
+#define V12354 (V + 47138)
+ 0x1111, 0x1169, 0x11c1, 0,
+#undef V12355
+#define V12355 (V + 47142)
+ 0x1111, 0x1169, 0x11c2, 0,
+#undef V12356
+#define V12356 (V + 47146)
+ 0x1111, 0x116a, 0,
+#undef V12357
+#define V12357 (V + 47149)
+ 0x1111, 0x116a, 0x11a8, 0,
+#undef V12358
+#define V12358 (V + 47153)
+ 0x1111, 0x116a, 0x11a9, 0,
+#undef V12359
+#define V12359 (V + 47157)
+ 0x1111, 0x116a, 0x11aa, 0,
+#undef V12360
+#define V12360 (V + 47161)
+ 0x1111, 0x116a, 0x11ab, 0,
+#undef V12361
+#define V12361 (V + 47165)
+ 0x1111, 0x116a, 0x11ac, 0,
+#undef V12362
+#define V12362 (V + 47169)
+ 0x1111, 0x116a, 0x11ad, 0,
+#undef V12363
+#define V12363 (V + 47173)
+ 0x1111, 0x116a, 0x11ae, 0,
+#undef V12364
+#define V12364 (V + 47177)
+ 0x1111, 0x116a, 0x11af, 0,
+#undef V12365
+#define V12365 (V + 47181)
+ 0x1111, 0x116a, 0x11b0, 0,
+#undef V12366
+#define V12366 (V + 47185)
+ 0x1111, 0x116a, 0x11b1, 0,
+#undef V12367
+#define V12367 (V + 47189)
+ 0x1111, 0x116a, 0x11b2, 0,
+#undef V12368
+#define V12368 (V + 47193)
+ 0x1111, 0x116a, 0x11b3, 0,
+#undef V12369
+#define V12369 (V + 47197)
+ 0x1111, 0x116a, 0x11b4, 0,
+#undef V12370
+#define V12370 (V + 47201)
+ 0x1111, 0x116a, 0x11b5, 0,
+#undef V12371
+#define V12371 (V + 47205)
+ 0x1111, 0x116a, 0x11b6, 0,
+#undef V12372
+#define V12372 (V + 47209)
+ 0x1111, 0x116a, 0x11b7, 0,
+#undef V12373
+#define V12373 (V + 47213)
+ 0x1111, 0x116a, 0x11b8, 0,
+#undef V12374
+#define V12374 (V + 47217)
+ 0x1111, 0x116a, 0x11b9, 0,
+#undef V12375
+#define V12375 (V + 47221)
+ 0x1111, 0x116a, 0x11ba, 0,
+#undef V12376
+#define V12376 (V + 47225)
+ 0x1111, 0x116a, 0x11bb, 0,
+#undef V12377
+#define V12377 (V + 47229)
+ 0x1111, 0x116a, 0x11bc, 0,
+#undef V12378
+#define V12378 (V + 47233)
+ 0x1111, 0x116a, 0x11bd, 0,
+#undef V12379
+#define V12379 (V + 47237)
+ 0x1111, 0x116a, 0x11be, 0,
+#undef V12380
+#define V12380 (V + 47241)
+ 0x1111, 0x116a, 0x11bf, 0,
+#undef V12381
+#define V12381 (V + 47245)
+ 0x1111, 0x116a, 0x11c0, 0,
+#undef V12382
+#define V12382 (V + 47249)
+ 0x1111, 0x116a, 0x11c1, 0,
+#undef V12383
+#define V12383 (V + 47253)
+ 0x1111, 0x116a, 0x11c2, 0,
+#undef V12384
+#define V12384 (V + 47257)
+ 0x1111, 0x116b, 0,
+#undef V12385
+#define V12385 (V + 47260)
+ 0x1111, 0x116b, 0x11a8, 0,
+#undef V12386
+#define V12386 (V + 47264)
+ 0x1111, 0x116b, 0x11a9, 0,
+#undef V12387
+#define V12387 (V + 47268)
+ 0x1111, 0x116b, 0x11aa, 0,
+#undef V12388
+#define V12388 (V + 47272)
+ 0x1111, 0x116b, 0x11ab, 0,
+#undef V12389
+#define V12389 (V + 47276)
+ 0x1111, 0x116b, 0x11ac, 0,
+#undef V12390
+#define V12390 (V + 47280)
+ 0x1111, 0x116b, 0x11ad, 0,
+#undef V12391
+#define V12391 (V + 47284)
+ 0x1111, 0x116b, 0x11ae, 0,
+#undef V12392
+#define V12392 (V + 47288)
+ 0x1111, 0x116b, 0x11af, 0,
+#undef V12393
+#define V12393 (V + 47292)
+ 0x1111, 0x116b, 0x11b0, 0,
+#undef V12394
+#define V12394 (V + 47296)
+ 0x1111, 0x116b, 0x11b1, 0,
+#undef V12395
+#define V12395 (V + 47300)
+ 0x1111, 0x116b, 0x11b2, 0,
+#undef V12396
+#define V12396 (V + 47304)
+ 0x1111, 0x116b, 0x11b3, 0,
+#undef V12397
+#define V12397 (V + 47308)
+ 0x1111, 0x116b, 0x11b4, 0,
+#undef V12398
+#define V12398 (V + 47312)
+ 0x1111, 0x116b, 0x11b5, 0,
+#undef V12399
+#define V12399 (V + 47316)
+ 0x1111, 0x116b, 0x11b6, 0,
+#undef V12400
+#define V12400 (V + 47320)
+ 0x1111, 0x116b, 0x11b7, 0,
+#undef V12401
+#define V12401 (V + 47324)
+ 0x1111, 0x116b, 0x11b8, 0,
+#undef V12402
+#define V12402 (V + 47328)
+ 0x1111, 0x116b, 0x11b9, 0,
+#undef V12403
+#define V12403 (V + 47332)
+ 0x1111, 0x116b, 0x11ba, 0,
+#undef V12404
+#define V12404 (V + 47336)
+ 0x1111, 0x116b, 0x11bb, 0,
+#undef V12405
+#define V12405 (V + 47340)
+ 0x1111, 0x116b, 0x11bc, 0,
+#undef V12406
+#define V12406 (V + 47344)
+ 0x1111, 0x116b, 0x11bd, 0,
+#undef V12407
+#define V12407 (V + 47348)
+ 0x1111, 0x116b, 0x11be, 0,
+#undef V12408
+#define V12408 (V + 47352)
+ 0x1111, 0x116b, 0x11bf, 0,
+#undef V12409
+#define V12409 (V + 47356)
+ 0x1111, 0x116b, 0x11c0, 0,
+#undef V12410
+#define V12410 (V + 47360)
+ 0x1111, 0x116b, 0x11c1, 0,
+#undef V12411
+#define V12411 (V + 47364)
+ 0x1111, 0x116b, 0x11c2, 0,
+#undef V12412
+#define V12412 (V + 47368)
+ 0x1111, 0x116c, 0,
+#undef V12413
+#define V12413 (V + 47371)
+ 0x1111, 0x116c, 0x11a8, 0,
+#undef V12414
+#define V12414 (V + 47375)
+ 0x1111, 0x116c, 0x11a9, 0,
+#undef V12415
+#define V12415 (V + 47379)
+ 0x1111, 0x116c, 0x11aa, 0,
+#undef V12416
+#define V12416 (V + 47383)
+ 0x1111, 0x116c, 0x11ab, 0,
+#undef V12417
+#define V12417 (V + 47387)
+ 0x1111, 0x116c, 0x11ac, 0,
+#undef V12418
+#define V12418 (V + 47391)
+ 0x1111, 0x116c, 0x11ad, 0,
+#undef V12419
+#define V12419 (V + 47395)
+ 0x1111, 0x116c, 0x11ae, 0,
+#undef V12420
+#define V12420 (V + 47399)
+ 0x1111, 0x116c, 0x11af, 0,
+#undef V12421
+#define V12421 (V + 47403)
+ 0x1111, 0x116c, 0x11b0, 0,
+#undef V12422
+#define V12422 (V + 47407)
+ 0x1111, 0x116c, 0x11b1, 0,
+#undef V12423
+#define V12423 (V + 47411)
+ 0x1111, 0x116c, 0x11b2, 0,
+#undef V12424
+#define V12424 (V + 47415)
+ 0x1111, 0x116c, 0x11b3, 0,
+#undef V12425
+#define V12425 (V + 47419)
+ 0x1111, 0x116c, 0x11b4, 0,
+#undef V12426
+#define V12426 (V + 47423)
+ 0x1111, 0x116c, 0x11b5, 0,
+#undef V12427
+#define V12427 (V + 47427)
+ 0x1111, 0x116c, 0x11b6, 0,
+#undef V12428
+#define V12428 (V + 47431)
+ 0x1111, 0x116c, 0x11b7, 0,
+#undef V12429
+#define V12429 (V + 47435)
+ 0x1111, 0x116c, 0x11b8, 0,
+#undef V12430
+#define V12430 (V + 47439)
+ 0x1111, 0x116c, 0x11b9, 0,
+#undef V12431
+#define V12431 (V + 47443)
+ 0x1111, 0x116c, 0x11ba, 0,
+#undef V12432
+#define V12432 (V + 47447)
+ 0x1111, 0x116c, 0x11bb, 0,
+#undef V12433
+#define V12433 (V + 47451)
+ 0x1111, 0x116c, 0x11bc, 0,
+#undef V12434
+#define V12434 (V + 47455)
+ 0x1111, 0x116c, 0x11bd, 0,
+#undef V12435
+#define V12435 (V + 47459)
+ 0x1111, 0x116c, 0x11be, 0,
+#undef V12436
+#define V12436 (V + 47463)
+ 0x1111, 0x116c, 0x11bf, 0,
+#undef V12437
+#define V12437 (V + 47467)
+ 0x1111, 0x116c, 0x11c0, 0,
+#undef V12438
+#define V12438 (V + 47471)
+ 0x1111, 0x116c, 0x11c1, 0,
+#undef V12439
+#define V12439 (V + 47475)
+ 0x1111, 0x116c, 0x11c2, 0,
+#undef V12440
+#define V12440 (V + 47479)
+ 0x1111, 0x116d, 0,
+#undef V12441
+#define V12441 (V + 47482)
+ 0x1111, 0x116d, 0x11a8, 0,
+#undef V12442
+#define V12442 (V + 47486)
+ 0x1111, 0x116d, 0x11a9, 0,
+#undef V12443
+#define V12443 (V + 47490)
+ 0x1111, 0x116d, 0x11aa, 0,
+#undef V12444
+#define V12444 (V + 47494)
+ 0x1111, 0x116d, 0x11ab, 0,
+#undef V12445
+#define V12445 (V + 47498)
+ 0x1111, 0x116d, 0x11ac, 0,
+#undef V12446
+#define V12446 (V + 47502)
+ 0x1111, 0x116d, 0x11ad, 0,
+#undef V12447
+#define V12447 (V + 47506)
+ 0x1111, 0x116d, 0x11ae, 0,
+#undef V12448
+#define V12448 (V + 47510)
+ 0x1111, 0x116d, 0x11af, 0,
+#undef V12449
+#define V12449 (V + 47514)
+ 0x1111, 0x116d, 0x11b0, 0,
+#undef V12450
+#define V12450 (V + 47518)
+ 0x1111, 0x116d, 0x11b1, 0,
+#undef V12451
+#define V12451 (V + 47522)
+ 0x1111, 0x116d, 0x11b2, 0,
+#undef V12452
+#define V12452 (V + 47526)
+ 0x1111, 0x116d, 0x11b3, 0,
+#undef V12453
+#define V12453 (V + 47530)
+ 0x1111, 0x116d, 0x11b4, 0,
+#undef V12454
+#define V12454 (V + 47534)
+ 0x1111, 0x116d, 0x11b5, 0,
+#undef V12455
+#define V12455 (V + 47538)
+ 0x1111, 0x116d, 0x11b6, 0,
+#undef V12456
+#define V12456 (V + 47542)
+ 0x1111, 0x116d, 0x11b7, 0,
+#undef V12457
+#define V12457 (V + 47546)
+ 0x1111, 0x116d, 0x11b8, 0,
+#undef V12458
+#define V12458 (V + 47550)
+ 0x1111, 0x116d, 0x11b9, 0,
+#undef V12459
+#define V12459 (V + 47554)
+ 0x1111, 0x116d, 0x11ba, 0,
+#undef V12460
+#define V12460 (V + 47558)
+ 0x1111, 0x116d, 0x11bb, 0,
+#undef V12461
+#define V12461 (V + 47562)
+ 0x1111, 0x116d, 0x11bc, 0,
+#undef V12462
+#define V12462 (V + 47566)
+ 0x1111, 0x116d, 0x11bd, 0,
+#undef V12463
+#define V12463 (V + 47570)
+ 0x1111, 0x116d, 0x11be, 0,
+#undef V12464
+#define V12464 (V + 47574)
+ 0x1111, 0x116d, 0x11bf, 0,
+#undef V12465
+#define V12465 (V + 47578)
+ 0x1111, 0x116d, 0x11c0, 0,
+#undef V12466
+#define V12466 (V + 47582)
+ 0x1111, 0x116d, 0x11c1, 0,
+#undef V12467
+#define V12467 (V + 47586)
+ 0x1111, 0x116d, 0x11c2, 0,
+#undef V12468
+#define V12468 (V + 47590)
+ 0x1111, 0x116e, 0,
+#undef V12469
+#define V12469 (V + 47593)
+ 0x1111, 0x116e, 0x11a8, 0,
+#undef V12470
+#define V12470 (V + 47597)
+ 0x1111, 0x116e, 0x11a9, 0,
+#undef V12471
+#define V12471 (V + 47601)
+ 0x1111, 0x116e, 0x11aa, 0,
+#undef V12472
+#define V12472 (V + 47605)
+ 0x1111, 0x116e, 0x11ab, 0,
+#undef V12473
+#define V12473 (V + 47609)
+ 0x1111, 0x116e, 0x11ac, 0,
+#undef V12474
+#define V12474 (V + 47613)
+ 0x1111, 0x116e, 0x11ad, 0,
+#undef V12475
+#define V12475 (V + 47617)
+ 0x1111, 0x116e, 0x11ae, 0,
+#undef V12476
+#define V12476 (V + 47621)
+ 0x1111, 0x116e, 0x11af, 0,
+#undef V12477
+#define V12477 (V + 47625)
+ 0x1111, 0x116e, 0x11b0, 0,
+#undef V12478
+#define V12478 (V + 47629)
+ 0x1111, 0x116e, 0x11b1, 0,
+#undef V12479
+#define V12479 (V + 47633)
+ 0x1111, 0x116e, 0x11b2, 0,
+#undef V12480
+#define V12480 (V + 47637)
+ 0x1111, 0x116e, 0x11b3, 0,
+#undef V12481
+#define V12481 (V + 47641)
+ 0x1111, 0x116e, 0x11b4, 0,
+#undef V12482
+#define V12482 (V + 47645)
+ 0x1111, 0x116e, 0x11b5, 0,
+#undef V12483
+#define V12483 (V + 47649)
+ 0x1111, 0x116e, 0x11b6, 0,
+#undef V12484
+#define V12484 (V + 47653)
+ 0x1111, 0x116e, 0x11b7, 0,
+#undef V12485
+#define V12485 (V + 47657)
+ 0x1111, 0x116e, 0x11b8, 0,
+#undef V12486
+#define V12486 (V + 47661)
+ 0x1111, 0x116e, 0x11b9, 0,
+#undef V12487
+#define V12487 (V + 47665)
+ 0x1111, 0x116e, 0x11ba, 0,
+#undef V12488
+#define V12488 (V + 47669)
+ 0x1111, 0x116e, 0x11bb, 0,
+#undef V12489
+#define V12489 (V + 47673)
+ 0x1111, 0x116e, 0x11bc, 0,
+#undef V12490
+#define V12490 (V + 47677)
+ 0x1111, 0x116e, 0x11bd, 0,
+#undef V12491
+#define V12491 (V + 47681)
+ 0x1111, 0x116e, 0x11be, 0,
+#undef V12492
+#define V12492 (V + 47685)
+ 0x1111, 0x116e, 0x11bf, 0,
+#undef V12493
+#define V12493 (V + 47689)
+ 0x1111, 0x116e, 0x11c0, 0,
+#undef V12494
+#define V12494 (V + 47693)
+ 0x1111, 0x116e, 0x11c1, 0,
+#undef V12495
+#define V12495 (V + 47697)
+ 0x1111, 0x116e, 0x11c2, 0,
+#undef V12496
+#define V12496 (V + 47701)
+ 0x1111, 0x116f, 0,
+#undef V12497
+#define V12497 (V + 47704)
+ 0x1111, 0x116f, 0x11a8, 0,
+#undef V12498
+#define V12498 (V + 47708)
+ 0x1111, 0x116f, 0x11a9, 0,
+#undef V12499
+#define V12499 (V + 47712)
+ 0x1111, 0x116f, 0x11aa, 0,
+#undef V12500
+#define V12500 (V + 47716)
+ 0x1111, 0x116f, 0x11ab, 0,
+#undef V12501
+#define V12501 (V + 47720)
+ 0x1111, 0x116f, 0x11ac, 0,
+#undef V12502
+#define V12502 (V + 47724)
+ 0x1111, 0x116f, 0x11ad, 0,
+#undef V12503
+#define V12503 (V + 47728)
+ 0x1111, 0x116f, 0x11ae, 0,
+#undef V12504
+#define V12504 (V + 47732)
+ 0x1111, 0x116f, 0x11af, 0,
+#undef V12505
+#define V12505 (V + 47736)
+ 0x1111, 0x116f, 0x11b0, 0,
+#undef V12506
+#define V12506 (V + 47740)
+ 0x1111, 0x116f, 0x11b1, 0,
+#undef V12507
+#define V12507 (V + 47744)
+ 0x1111, 0x116f, 0x11b2, 0,
+#undef V12508
+#define V12508 (V + 47748)
+ 0x1111, 0x116f, 0x11b3, 0,
+#undef V12509
+#define V12509 (V + 47752)
+ 0x1111, 0x116f, 0x11b4, 0,
+#undef V12510
+#define V12510 (V + 47756)
+ 0x1111, 0x116f, 0x11b5, 0,
+#undef V12511
+#define V12511 (V + 47760)
+ 0x1111, 0x116f, 0x11b6, 0,
+#undef V12512
+#define V12512 (V + 47764)
+ 0x1111, 0x116f, 0x11b7, 0,
+#undef V12513
+#define V12513 (V + 47768)
+ 0x1111, 0x116f, 0x11b8, 0,
+#undef V12514
+#define V12514 (V + 47772)
+ 0x1111, 0x116f, 0x11b9, 0,
+#undef V12515
+#define V12515 (V + 47776)
+ 0x1111, 0x116f, 0x11ba, 0,
+#undef V12516
+#define V12516 (V + 47780)
+ 0x1111, 0x116f, 0x11bb, 0,
+#undef V12517
+#define V12517 (V + 47784)
+ 0x1111, 0x116f, 0x11bc, 0,
+#undef V12518
+#define V12518 (V + 47788)
+ 0x1111, 0x116f, 0x11bd, 0,
+#undef V12519
+#define V12519 (V + 47792)
+ 0x1111, 0x116f, 0x11be, 0,
+#undef V12520
+#define V12520 (V + 47796)
+ 0x1111, 0x116f, 0x11bf, 0,
+#undef V12521
+#define V12521 (V + 47800)
+ 0x1111, 0x116f, 0x11c0, 0,
+#undef V12522
+#define V12522 (V + 47804)
+ 0x1111, 0x116f, 0x11c1, 0,
+#undef V12523
+#define V12523 (V + 47808)
+ 0x1111, 0x116f, 0x11c2, 0,
+#undef V12524
+#define V12524 (V + 47812)
+ 0x1111, 0x1170, 0,
+#undef V12525
+#define V12525 (V + 47815)
+ 0x1111, 0x1170, 0x11a8, 0,
+#undef V12526
+#define V12526 (V + 47819)
+ 0x1111, 0x1170, 0x11a9, 0,
+#undef V12527
+#define V12527 (V + 47823)
+ 0x1111, 0x1170, 0x11aa, 0,
+#undef V12528
+#define V12528 (V + 47827)
+ 0x1111, 0x1170, 0x11ab, 0,
+#undef V12529
+#define V12529 (V + 47831)
+ 0x1111, 0x1170, 0x11ac, 0,
+#undef V12530
+#define V12530 (V + 47835)
+ 0x1111, 0x1170, 0x11ad, 0,
+#undef V12531
+#define V12531 (V + 47839)
+ 0x1111, 0x1170, 0x11ae, 0,
+#undef V12532
+#define V12532 (V + 47843)
+ 0x1111, 0x1170, 0x11af, 0,
+#undef V12533
+#define V12533 (V + 47847)
+ 0x1111, 0x1170, 0x11b0, 0,
+#undef V12534
+#define V12534 (V + 47851)
+ 0x1111, 0x1170, 0x11b1, 0,
+#undef V12535
+#define V12535 (V + 47855)
+ 0x1111, 0x1170, 0x11b2, 0,
+#undef V12536
+#define V12536 (V + 47859)
+ 0x1111, 0x1170, 0x11b3, 0,
+#undef V12537
+#define V12537 (V + 47863)
+ 0x1111, 0x1170, 0x11b4, 0,
+#undef V12538
+#define V12538 (V + 47867)
+ 0x1111, 0x1170, 0x11b5, 0,
+#undef V12539
+#define V12539 (V + 47871)
+ 0x1111, 0x1170, 0x11b6, 0,
+#undef V12540
+#define V12540 (V + 47875)
+ 0x1111, 0x1170, 0x11b7, 0,
+#undef V12541
+#define V12541 (V + 47879)
+ 0x1111, 0x1170, 0x11b8, 0,
+#undef V12542
+#define V12542 (V + 47883)
+ 0x1111, 0x1170, 0x11b9, 0,
+#undef V12543
+#define V12543 (V + 47887)
+ 0x1111, 0x1170, 0x11ba, 0,
+#undef V12544
+#define V12544 (V + 47891)
+ 0x1111, 0x1170, 0x11bb, 0,
+#undef V12545
+#define V12545 (V + 47895)
+ 0x1111, 0x1170, 0x11bc, 0,
+#undef V12546
+#define V12546 (V + 47899)
+ 0x1111, 0x1170, 0x11bd, 0,
+#undef V12547
+#define V12547 (V + 47903)
+ 0x1111, 0x1170, 0x11be, 0,
+#undef V12548
+#define V12548 (V + 47907)
+ 0x1111, 0x1170, 0x11bf, 0,
+#undef V12549
+#define V12549 (V + 47911)
+ 0x1111, 0x1170, 0x11c0, 0,
+#undef V12550
+#define V12550 (V + 47915)
+ 0x1111, 0x1170, 0x11c1, 0,
+#undef V12551
+#define V12551 (V + 47919)
+ 0x1111, 0x1170, 0x11c2, 0,
+#undef V12552
+#define V12552 (V + 47923)
+ 0x1111, 0x1171, 0,
+#undef V12553
+#define V12553 (V + 47926)
+ 0x1111, 0x1171, 0x11a8, 0,
+#undef V12554
+#define V12554 (V + 47930)
+ 0x1111, 0x1171, 0x11a9, 0,
+#undef V12555
+#define V12555 (V + 47934)
+ 0x1111, 0x1171, 0x11aa, 0,
+#undef V12556
+#define V12556 (V + 47938)
+ 0x1111, 0x1171, 0x11ab, 0,
+#undef V12557
+#define V12557 (V + 47942)
+ 0x1111, 0x1171, 0x11ac, 0,
+#undef V12558
+#define V12558 (V + 47946)
+ 0x1111, 0x1171, 0x11ad, 0,
+#undef V12559
+#define V12559 (V + 47950)
+ 0x1111, 0x1171, 0x11ae, 0,
+#undef V12560
+#define V12560 (V + 47954)
+ 0x1111, 0x1171, 0x11af, 0,
+#undef V12561
+#define V12561 (V + 47958)
+ 0x1111, 0x1171, 0x11b0, 0,
+#undef V12562
+#define V12562 (V + 47962)
+ 0x1111, 0x1171, 0x11b1, 0,
+#undef V12563
+#define V12563 (V + 47966)
+ 0x1111, 0x1171, 0x11b2, 0,
+#undef V12564
+#define V12564 (V + 47970)
+ 0x1111, 0x1171, 0x11b3, 0,
+#undef V12565
+#define V12565 (V + 47974)
+ 0x1111, 0x1171, 0x11b4, 0,
+#undef V12566
+#define V12566 (V + 47978)
+ 0x1111, 0x1171, 0x11b5, 0,
+#undef V12567
+#define V12567 (V + 47982)
+ 0x1111, 0x1171, 0x11b6, 0,
+#undef V12568
+#define V12568 (V + 47986)
+ 0x1111, 0x1171, 0x11b7, 0,
+#undef V12569
+#define V12569 (V + 47990)
+ 0x1111, 0x1171, 0x11b8, 0,
+#undef V12570
+#define V12570 (V + 47994)
+ 0x1111, 0x1171, 0x11b9, 0,
+#undef V12571
+#define V12571 (V + 47998)
+ 0x1111, 0x1171, 0x11ba, 0,
+#undef V12572
+#define V12572 (V + 48002)
+ 0x1111, 0x1171, 0x11bb, 0,
+#undef V12573
+#define V12573 (V + 48006)
+ 0x1111, 0x1171, 0x11bc, 0,
+#undef V12574
+#define V12574 (V + 48010)
+ 0x1111, 0x1171, 0x11bd, 0,
+#undef V12575
+#define V12575 (V + 48014)
+ 0x1111, 0x1171, 0x11be, 0,
+#undef V12576
+#define V12576 (V + 48018)
+ 0x1111, 0x1171, 0x11bf, 0,
+#undef V12577
+#define V12577 (V + 48022)
+ 0x1111, 0x1171, 0x11c0, 0,
+#undef V12578
+#define V12578 (V + 48026)
+ 0x1111, 0x1171, 0x11c1, 0,
+#undef V12579
+#define V12579 (V + 48030)
+ 0x1111, 0x1171, 0x11c2, 0,
+#undef V12580
+#define V12580 (V + 48034)
+ 0x1111, 0x1172, 0,
+#undef V12581
+#define V12581 (V + 48037)
+ 0x1111, 0x1172, 0x11a8, 0,
+#undef V12582
+#define V12582 (V + 48041)
+ 0x1111, 0x1172, 0x11a9, 0,
+#undef V12583
+#define V12583 (V + 48045)
+ 0x1111, 0x1172, 0x11aa, 0,
+#undef V12584
+#define V12584 (V + 48049)
+ 0x1111, 0x1172, 0x11ab, 0,
+#undef V12585
+#define V12585 (V + 48053)
+ 0x1111, 0x1172, 0x11ac, 0,
+#undef V12586
+#define V12586 (V + 48057)
+ 0x1111, 0x1172, 0x11ad, 0,
+#undef V12587
+#define V12587 (V + 48061)
+ 0x1111, 0x1172, 0x11ae, 0,
+#undef V12588
+#define V12588 (V + 48065)
+ 0x1111, 0x1172, 0x11af, 0,
+#undef V12589
+#define V12589 (V + 48069)
+ 0x1111, 0x1172, 0x11b0, 0,
+#undef V12590
+#define V12590 (V + 48073)
+ 0x1111, 0x1172, 0x11b1, 0,
+#undef V12591
+#define V12591 (V + 48077)
+ 0x1111, 0x1172, 0x11b2, 0,
+#undef V12592
+#define V12592 (V + 48081)
+ 0x1111, 0x1172, 0x11b3, 0,
+#undef V12593
+#define V12593 (V + 48085)
+ 0x1111, 0x1172, 0x11b4, 0,
+#undef V12594
+#define V12594 (V + 48089)
+ 0x1111, 0x1172, 0x11b5, 0,
+#undef V12595
+#define V12595 (V + 48093)
+ 0x1111, 0x1172, 0x11b6, 0,
+#undef V12596
+#define V12596 (V + 48097)
+ 0x1111, 0x1172, 0x11b7, 0,
+#undef V12597
+#define V12597 (V + 48101)
+ 0x1111, 0x1172, 0x11b8, 0,
+#undef V12598
+#define V12598 (V + 48105)
+ 0x1111, 0x1172, 0x11b9, 0,
+#undef V12599
+#define V12599 (V + 48109)
+ 0x1111, 0x1172, 0x11ba, 0,
+#undef V12600
+#define V12600 (V + 48113)
+ 0x1111, 0x1172, 0x11bb, 0,
+#undef V12601
+#define V12601 (V + 48117)
+ 0x1111, 0x1172, 0x11bc, 0,
+#undef V12602
+#define V12602 (V + 48121)
+ 0x1111, 0x1172, 0x11bd, 0,
+#undef V12603
+#define V12603 (V + 48125)
+ 0x1111, 0x1172, 0x11be, 0,
+#undef V12604
+#define V12604 (V + 48129)
+ 0x1111, 0x1172, 0x11bf, 0,
+#undef V12605
+#define V12605 (V + 48133)
+ 0x1111, 0x1172, 0x11c0, 0,
+#undef V12606
+#define V12606 (V + 48137)
+ 0x1111, 0x1172, 0x11c1, 0,
+#undef V12607
+#define V12607 (V + 48141)
+ 0x1111, 0x1172, 0x11c2, 0,
+#undef V12608
+#define V12608 (V + 48145)
+ 0x1111, 0x1173, 0,
+#undef V12609
+#define V12609 (V + 48148)
+ 0x1111, 0x1173, 0x11a8, 0,
+#undef V12610
+#define V12610 (V + 48152)
+ 0x1111, 0x1173, 0x11a9, 0,
+#undef V12611
+#define V12611 (V + 48156)
+ 0x1111, 0x1173, 0x11aa, 0,
+#undef V12612
+#define V12612 (V + 48160)
+ 0x1111, 0x1173, 0x11ab, 0,
+#undef V12613
+#define V12613 (V + 48164)
+ 0x1111, 0x1173, 0x11ac, 0,
+#undef V12614
+#define V12614 (V + 48168)
+ 0x1111, 0x1173, 0x11ad, 0,
+#undef V12615
+#define V12615 (V + 48172)
+ 0x1111, 0x1173, 0x11ae, 0,
+#undef V12616
+#define V12616 (V + 48176)
+ 0x1111, 0x1173, 0x11af, 0,
+#undef V12617
+#define V12617 (V + 48180)
+ 0x1111, 0x1173, 0x11b0, 0,
+#undef V12618
+#define V12618 (V + 48184)
+ 0x1111, 0x1173, 0x11b1, 0,
+#undef V12619
+#define V12619 (V + 48188)
+ 0x1111, 0x1173, 0x11b2, 0,
+#undef V12620
+#define V12620 (V + 48192)
+ 0x1111, 0x1173, 0x11b3, 0,
+#undef V12621
+#define V12621 (V + 48196)
+ 0x1111, 0x1173, 0x11b4, 0,
+#undef V12622
+#define V12622 (V + 48200)
+ 0x1111, 0x1173, 0x11b5, 0,
+#undef V12623
+#define V12623 (V + 48204)
+ 0x1111, 0x1173, 0x11b6, 0,
+#undef V12624
+#define V12624 (V + 48208)
+ 0x1111, 0x1173, 0x11b7, 0,
+#undef V12625
+#define V12625 (V + 48212)
+ 0x1111, 0x1173, 0x11b8, 0,
+#undef V12626
+#define V12626 (V + 48216)
+ 0x1111, 0x1173, 0x11b9, 0,
+#undef V12627
+#define V12627 (V + 48220)
+ 0x1111, 0x1173, 0x11ba, 0,
+#undef V12628
+#define V12628 (V + 48224)
+ 0x1111, 0x1173, 0x11bb, 0,
+#undef V12629
+#define V12629 (V + 48228)
+ 0x1111, 0x1173, 0x11bc, 0,
+#undef V12630
+#define V12630 (V + 48232)
+ 0x1111, 0x1173, 0x11bd, 0,
+#undef V12631
+#define V12631 (V + 48236)
+ 0x1111, 0x1173, 0x11be, 0,
+#undef V12632
+#define V12632 (V + 48240)
+ 0x1111, 0x1173, 0x11bf, 0,
+#undef V12633
+#define V12633 (V + 48244)
+ 0x1111, 0x1173, 0x11c0, 0,
+#undef V12634
+#define V12634 (V + 48248)
+ 0x1111, 0x1173, 0x11c1, 0,
+#undef V12635
+#define V12635 (V + 48252)
+ 0x1111, 0x1173, 0x11c2, 0,
+#undef V12636
+#define V12636 (V + 48256)
+ 0x1111, 0x1174, 0,
+#undef V12637
+#define V12637 (V + 48259)
+ 0x1111, 0x1174, 0x11a8, 0,
+#undef V12638
+#define V12638 (V + 48263)
+ 0x1111, 0x1174, 0x11a9, 0,
+#undef V12639
+#define V12639 (V + 48267)
+ 0x1111, 0x1174, 0x11aa, 0,
+#undef V12640
+#define V12640 (V + 48271)
+ 0x1111, 0x1174, 0x11ab, 0,
+#undef V12641
+#define V12641 (V + 48275)
+ 0x1111, 0x1174, 0x11ac, 0,
+#undef V12642
+#define V12642 (V + 48279)
+ 0x1111, 0x1174, 0x11ad, 0,
+#undef V12643
+#define V12643 (V + 48283)
+ 0x1111, 0x1174, 0x11ae, 0,
+#undef V12644
+#define V12644 (V + 48287)
+ 0x1111, 0x1174, 0x11af, 0,
+#undef V12645
+#define V12645 (V + 48291)
+ 0x1111, 0x1174, 0x11b0, 0,
+#undef V12646
+#define V12646 (V + 48295)
+ 0x1111, 0x1174, 0x11b1, 0,
+#undef V12647
+#define V12647 (V + 48299)
+ 0x1111, 0x1174, 0x11b2, 0,
+#undef V12648
+#define V12648 (V + 48303)
+ 0x1111, 0x1174, 0x11b3, 0,
+#undef V12649
+#define V12649 (V + 48307)
+ 0x1111, 0x1174, 0x11b4, 0,
+#undef V12650
+#define V12650 (V + 48311)
+ 0x1111, 0x1174, 0x11b5, 0,
+#undef V12651
+#define V12651 (V + 48315)
+ 0x1111, 0x1174, 0x11b6, 0,
+#undef V12652
+#define V12652 (V + 48319)
+ 0x1111, 0x1174, 0x11b7, 0,
+#undef V12653
+#define V12653 (V + 48323)
+ 0x1111, 0x1174, 0x11b8, 0,
+#undef V12654
+#define V12654 (V + 48327)
+ 0x1111, 0x1174, 0x11b9, 0,
+#undef V12655
+#define V12655 (V + 48331)
+ 0x1111, 0x1174, 0x11ba, 0,
+#undef V12656
+#define V12656 (V + 48335)
+ 0x1111, 0x1174, 0x11bb, 0,
+#undef V12657
+#define V12657 (V + 48339)
+ 0x1111, 0x1174, 0x11bc, 0,
+#undef V12658
+#define V12658 (V + 48343)
+ 0x1111, 0x1174, 0x11bd, 0,
+#undef V12659
+#define V12659 (V + 48347)
+ 0x1111, 0x1174, 0x11be, 0,
+#undef V12660
+#define V12660 (V + 48351)
+ 0x1111, 0x1174, 0x11bf, 0,
+#undef V12661
+#define V12661 (V + 48355)
+ 0x1111, 0x1174, 0x11c0, 0,
+#undef V12662
+#define V12662 (V + 48359)
+ 0x1111, 0x1174, 0x11c1, 0,
+#undef V12663
+#define V12663 (V + 48363)
+ 0x1111, 0x1174, 0x11c2, 0,
+#undef V12664
+#define V12664 (V + 48367)
+ 0x1111, 0x1175, 0,
+#undef V12665
+#define V12665 (V + 48370)
+ 0x1111, 0x1175, 0x11a8, 0,
+#undef V12666
+#define V12666 (V + 48374)
+ 0x1111, 0x1175, 0x11a9, 0,
+#undef V12667
+#define V12667 (V + 48378)
+ 0x1111, 0x1175, 0x11aa, 0,
+#undef V12668
+#define V12668 (V + 48382)
+ 0x1111, 0x1175, 0x11ab, 0,
+#undef V12669
+#define V12669 (V + 48386)
+ 0x1111, 0x1175, 0x11ac, 0,
+#undef V12670
+#define V12670 (V + 48390)
+ 0x1111, 0x1175, 0x11ad, 0,
+#undef V12671
+#define V12671 (V + 48394)
+ 0x1111, 0x1175, 0x11ae, 0,
+#undef V12672
+#define V12672 (V + 48398)
+ 0x1111, 0x1175, 0x11af, 0,
+#undef V12673
+#define V12673 (V + 48402)
+ 0x1111, 0x1175, 0x11b0, 0,
+#undef V12674
+#define V12674 (V + 48406)
+ 0x1111, 0x1175, 0x11b1, 0,
+#undef V12675
+#define V12675 (V + 48410)
+ 0x1111, 0x1175, 0x11b2, 0,
+#undef V12676
+#define V12676 (V + 48414)
+ 0x1111, 0x1175, 0x11b3, 0,
+#undef V12677
+#define V12677 (V + 48418)
+ 0x1111, 0x1175, 0x11b4, 0,
+#undef V12678
+#define V12678 (V + 48422)
+ 0x1111, 0x1175, 0x11b5, 0,
+#undef V12679
+#define V12679 (V + 48426)
+ 0x1111, 0x1175, 0x11b6, 0,
+#undef V12680
+#define V12680 (V + 48430)
+ 0x1111, 0x1175, 0x11b7, 0,
+#undef V12681
+#define V12681 (V + 48434)
+ 0x1111, 0x1175, 0x11b8, 0,
+#undef V12682
+#define V12682 (V + 48438)
+ 0x1111, 0x1175, 0x11b9, 0,
+#undef V12683
+#define V12683 (V + 48442)
+ 0x1111, 0x1175, 0x11ba, 0,
+#undef V12684
+#define V12684 (V + 48446)
+ 0x1111, 0x1175, 0x11bb, 0,
+#undef V12685
+#define V12685 (V + 48450)
+ 0x1111, 0x1175, 0x11bc, 0,
+#undef V12686
+#define V12686 (V + 48454)
+ 0x1111, 0x1175, 0x11bd, 0,
+#undef V12687
+#define V12687 (V + 48458)
+ 0x1111, 0x1175, 0x11be, 0,
+#undef V12688
+#define V12688 (V + 48462)
+ 0x1111, 0x1175, 0x11bf, 0,
+#undef V12689
+#define V12689 (V + 48466)
+ 0x1111, 0x1175, 0x11c0, 0,
+#undef V12690
+#define V12690 (V + 48470)
+ 0x1111, 0x1175, 0x11c1, 0,
+#undef V12691
+#define V12691 (V + 48474)
+ 0x1111, 0x1175, 0x11c2, 0,
+#undef V12692
+#define V12692 (V + 48478)
+ 0x1112, 0x1161, 0x11a8, 0,
+#undef V12693
+#define V12693 (V + 48482)
+ 0x1112, 0x1161, 0x11a9, 0,
+#undef V12694
+#define V12694 (V + 48486)
+ 0x1112, 0x1161, 0x11aa, 0,
+#undef V12695
+#define V12695 (V + 48490)
+ 0x1112, 0x1161, 0x11ab, 0,
+#undef V12696
+#define V12696 (V + 48494)
+ 0x1112, 0x1161, 0x11ac, 0,
+#undef V12697
+#define V12697 (V + 48498)
+ 0x1112, 0x1161, 0x11ad, 0,
+#undef V12698
+#define V12698 (V + 48502)
+ 0x1112, 0x1161, 0x11ae, 0,
+#undef V12699
+#define V12699 (V + 48506)
+ 0x1112, 0x1161, 0x11af, 0,
+#undef V12700
+#define V12700 (V + 48510)
+ 0x1112, 0x1161, 0x11b0, 0,
+#undef V12701
+#define V12701 (V + 48514)
+ 0x1112, 0x1161, 0x11b1, 0,
+#undef V12702
+#define V12702 (V + 48518)
+ 0x1112, 0x1161, 0x11b2, 0,
+#undef V12703
+#define V12703 (V + 48522)
+ 0x1112, 0x1161, 0x11b3, 0,
+#undef V12704
+#define V12704 (V + 48526)
+ 0x1112, 0x1161, 0x11b4, 0,
+#undef V12705
+#define V12705 (V + 48530)
+ 0x1112, 0x1161, 0x11b5, 0,
+#undef V12706
+#define V12706 (V + 48534)
+ 0x1112, 0x1161, 0x11b6, 0,
+#undef V12707
+#define V12707 (V + 48538)
+ 0x1112, 0x1161, 0x11b7, 0,
+#undef V12708
+#define V12708 (V + 48542)
+ 0x1112, 0x1161, 0x11b8, 0,
+#undef V12709
+#define V12709 (V + 48546)
+ 0x1112, 0x1161, 0x11b9, 0,
+#undef V12710
+#define V12710 (V + 48550)
+ 0x1112, 0x1161, 0x11ba, 0,
+#undef V12711
+#define V12711 (V + 48554)
+ 0x1112, 0x1161, 0x11bb, 0,
+#undef V12712
+#define V12712 (V + 48558)
+ 0x1112, 0x1161, 0x11bc, 0,
+#undef V12713
+#define V12713 (V + 48562)
+ 0x1112, 0x1161, 0x11bd, 0,
+#undef V12714
+#define V12714 (V + 48566)
+ 0x1112, 0x1161, 0x11be, 0,
+#undef V12715
+#define V12715 (V + 48570)
+ 0x1112, 0x1161, 0x11bf, 0,
+#undef V12716
+#define V12716 (V + 48574)
+ 0x1112, 0x1161, 0x11c0, 0,
+#undef V12717
+#define V12717 (V + 48578)
+ 0x1112, 0x1161, 0x11c1, 0,
+#undef V12718
+#define V12718 (V + 48582)
+ 0x1112, 0x1161, 0x11c2, 0,
+#undef V12719
+#define V12719 (V + 48586)
+ 0x1112, 0x1162, 0,
+#undef V12720
+#define V12720 (V + 48589)
+ 0x1112, 0x1162, 0x11a8, 0,
+#undef V12721
+#define V12721 (V + 48593)
+ 0x1112, 0x1162, 0x11a9, 0,
+#undef V12722
+#define V12722 (V + 48597)
+ 0x1112, 0x1162, 0x11aa, 0,
+#undef V12723
+#define V12723 (V + 48601)
+ 0x1112, 0x1162, 0x11ab, 0,
+#undef V12724
+#define V12724 (V + 48605)
+ 0x1112, 0x1162, 0x11ac, 0,
+#undef V12725
+#define V12725 (V + 48609)
+ 0x1112, 0x1162, 0x11ad, 0,
+#undef V12726
+#define V12726 (V + 48613)
+ 0x1112, 0x1162, 0x11ae, 0,
+#undef V12727
+#define V12727 (V + 48617)
+ 0x1112, 0x1162, 0x11af, 0,
+#undef V12728
+#define V12728 (V + 48621)
+ 0x1112, 0x1162, 0x11b0, 0,
+#undef V12729
+#define V12729 (V + 48625)
+ 0x1112, 0x1162, 0x11b1, 0,
+#undef V12730
+#define V12730 (V + 48629)
+ 0x1112, 0x1162, 0x11b2, 0,
+#undef V12731
+#define V12731 (V + 48633)
+ 0x1112, 0x1162, 0x11b3, 0,
+#undef V12732
+#define V12732 (V + 48637)
+ 0x1112, 0x1162, 0x11b4, 0,
+#undef V12733
+#define V12733 (V + 48641)
+ 0x1112, 0x1162, 0x11b5, 0,
+#undef V12734
+#define V12734 (V + 48645)
+ 0x1112, 0x1162, 0x11b6, 0,
+#undef V12735
+#define V12735 (V + 48649)
+ 0x1112, 0x1162, 0x11b7, 0,
+#undef V12736
+#define V12736 (V + 48653)
+ 0x1112, 0x1162, 0x11b8, 0,
+#undef V12737
+#define V12737 (V + 48657)
+ 0x1112, 0x1162, 0x11b9, 0,
+#undef V12738
+#define V12738 (V + 48661)
+ 0x1112, 0x1162, 0x11ba, 0,
+#undef V12739
+#define V12739 (V + 48665)
+ 0x1112, 0x1162, 0x11bb, 0,
+#undef V12740
+#define V12740 (V + 48669)
+ 0x1112, 0x1162, 0x11bc, 0,
+#undef V12741
+#define V12741 (V + 48673)
+ 0x1112, 0x1162, 0x11bd, 0,
+#undef V12742
+#define V12742 (V + 48677)
+ 0x1112, 0x1162, 0x11be, 0,
+#undef V12743
+#define V12743 (V + 48681)
+ 0x1112, 0x1162, 0x11bf, 0,
+#undef V12744
+#define V12744 (V + 48685)
+ 0x1112, 0x1162, 0x11c0, 0,
+#undef V12745
+#define V12745 (V + 48689)
+ 0x1112, 0x1162, 0x11c1, 0,
+#undef V12746
+#define V12746 (V + 48693)
+ 0x1112, 0x1162, 0x11c2, 0,
+#undef V12747
+#define V12747 (V + 48697)
+ 0x1112, 0x1163, 0,
+#undef V12748
+#define V12748 (V + 48700)
+ 0x1112, 0x1163, 0x11a8, 0,
+#undef V12749
+#define V12749 (V + 48704)
+ 0x1112, 0x1163, 0x11a9, 0,
+#undef V12750
+#define V12750 (V + 48708)
+ 0x1112, 0x1163, 0x11aa, 0,
+#undef V12751
+#define V12751 (V + 48712)
+ 0x1112, 0x1163, 0x11ab, 0,
+#undef V12752
+#define V12752 (V + 48716)
+ 0x1112, 0x1163, 0x11ac, 0,
+#undef V12753
+#define V12753 (V + 48720)
+ 0x1112, 0x1163, 0x11ad, 0,
+#undef V12754
+#define V12754 (V + 48724)
+ 0x1112, 0x1163, 0x11ae, 0,
+#undef V12755
+#define V12755 (V + 48728)
+ 0x1112, 0x1163, 0x11af, 0,
+#undef V12756
+#define V12756 (V + 48732)
+ 0x1112, 0x1163, 0x11b0, 0,
+#undef V12757
+#define V12757 (V + 48736)
+ 0x1112, 0x1163, 0x11b1, 0,
+#undef V12758
+#define V12758 (V + 48740)
+ 0x1112, 0x1163, 0x11b2, 0,
+#undef V12759
+#define V12759 (V + 48744)
+ 0x1112, 0x1163, 0x11b3, 0,
+#undef V12760
+#define V12760 (V + 48748)
+ 0x1112, 0x1163, 0x11b4, 0,
+#undef V12761
+#define V12761 (V + 48752)
+ 0x1112, 0x1163, 0x11b5, 0,
+#undef V12762
+#define V12762 (V + 48756)
+ 0x1112, 0x1163, 0x11b6, 0,
+#undef V12763
+#define V12763 (V + 48760)
+ 0x1112, 0x1163, 0x11b7, 0,
+#undef V12764
+#define V12764 (V + 48764)
+ 0x1112, 0x1163, 0x11b8, 0,
+#undef V12765
+#define V12765 (V + 48768)
+ 0x1112, 0x1163, 0x11b9, 0,
+#undef V12766
+#define V12766 (V + 48772)
+ 0x1112, 0x1163, 0x11ba, 0,
+#undef V12767
+#define V12767 (V + 48776)
+ 0x1112, 0x1163, 0x11bb, 0,
+#undef V12768
+#define V12768 (V + 48780)
+ 0x1112, 0x1163, 0x11bc, 0,
+#undef V12769
+#define V12769 (V + 48784)
+ 0x1112, 0x1163, 0x11bd, 0,
+#undef V12770
+#define V12770 (V + 48788)
+ 0x1112, 0x1163, 0x11be, 0,
+#undef V12771
+#define V12771 (V + 48792)
+ 0x1112, 0x1163, 0x11bf, 0,
+#undef V12772
+#define V12772 (V + 48796)
+ 0x1112, 0x1163, 0x11c0, 0,
+#undef V12773
+#define V12773 (V + 48800)
+ 0x1112, 0x1163, 0x11c1, 0,
+#undef V12774
+#define V12774 (V + 48804)
+ 0x1112, 0x1163, 0x11c2, 0,
+#undef V12775
+#define V12775 (V + 48808)
+ 0x1112, 0x1164, 0,
+#undef V12776
+#define V12776 (V + 48811)
+ 0x1112, 0x1164, 0x11a8, 0,
+#undef V12777
+#define V12777 (V + 48815)
+ 0x1112, 0x1164, 0x11a9, 0,
+#undef V12778
+#define V12778 (V + 48819)
+ 0x1112, 0x1164, 0x11aa, 0,
+#undef V12779
+#define V12779 (V + 48823)
+ 0x1112, 0x1164, 0x11ab, 0,
+#undef V12780
+#define V12780 (V + 48827)
+ 0x1112, 0x1164, 0x11ac, 0,
+#undef V12781
+#define V12781 (V + 48831)
+ 0x1112, 0x1164, 0x11ad, 0,
+#undef V12782
+#define V12782 (V + 48835)
+ 0x1112, 0x1164, 0x11ae, 0,
+#undef V12783
+#define V12783 (V + 48839)
+ 0x1112, 0x1164, 0x11af, 0,
+#undef V12784
+#define V12784 (V + 48843)
+ 0x1112, 0x1164, 0x11b0, 0,
+#undef V12785
+#define V12785 (V + 48847)
+ 0x1112, 0x1164, 0x11b1, 0,
+#undef V12786
+#define V12786 (V + 48851)
+ 0x1112, 0x1164, 0x11b2, 0,
+#undef V12787
+#define V12787 (V + 48855)
+ 0x1112, 0x1164, 0x11b3, 0,
+#undef V12788
+#define V12788 (V + 48859)
+ 0x1112, 0x1164, 0x11b4, 0,
+#undef V12789
+#define V12789 (V + 48863)
+ 0x1112, 0x1164, 0x11b5, 0,
+#undef V12790
+#define V12790 (V + 48867)
+ 0x1112, 0x1164, 0x11b6, 0,
+#undef V12791
+#define V12791 (V + 48871)
+ 0x1112, 0x1164, 0x11b7, 0,
+#undef V12792
+#define V12792 (V + 48875)
+ 0x1112, 0x1164, 0x11b8, 0,
+#undef V12793
+#define V12793 (V + 48879)
+ 0x1112, 0x1164, 0x11b9, 0,
+#undef V12794
+#define V12794 (V + 48883)
+ 0x1112, 0x1164, 0x11ba, 0,
+#undef V12795
+#define V12795 (V + 48887)
+ 0x1112, 0x1164, 0x11bb, 0,
+#undef V12796
+#define V12796 (V + 48891)
+ 0x1112, 0x1164, 0x11bc, 0,
+#undef V12797
+#define V12797 (V + 48895)
+ 0x1112, 0x1164, 0x11bd, 0,
+#undef V12798
+#define V12798 (V + 48899)
+ 0x1112, 0x1164, 0x11be, 0,
+#undef V12799
+#define V12799 (V + 48903)
+ 0x1112, 0x1164, 0x11bf, 0,
+#undef V12800
+#define V12800 (V + 48907)
+ 0x1112, 0x1164, 0x11c0, 0,
+#undef V12801
+#define V12801 (V + 48911)
+ 0x1112, 0x1164, 0x11c1, 0,
+#undef V12802
+#define V12802 (V + 48915)
+ 0x1112, 0x1164, 0x11c2, 0,
+#undef V12803
+#define V12803 (V + 48919)
+ 0x1112, 0x1165, 0,
+#undef V12804
+#define V12804 (V + 48922)
+ 0x1112, 0x1165, 0x11a8, 0,
+#undef V12805
+#define V12805 (V + 48926)
+ 0x1112, 0x1165, 0x11a9, 0,
+#undef V12806
+#define V12806 (V + 48930)
+ 0x1112, 0x1165, 0x11aa, 0,
+#undef V12807
+#define V12807 (V + 48934)
+ 0x1112, 0x1165, 0x11ab, 0,
+#undef V12808
+#define V12808 (V + 48938)
+ 0x1112, 0x1165, 0x11ac, 0,
+#undef V12809
+#define V12809 (V + 48942)
+ 0x1112, 0x1165, 0x11ad, 0,
+#undef V12810
+#define V12810 (V + 48946)
+ 0x1112, 0x1165, 0x11ae, 0,
+#undef V12811
+#define V12811 (V + 48950)
+ 0x1112, 0x1165, 0x11af, 0,
+#undef V12812
+#define V12812 (V + 48954)
+ 0x1112, 0x1165, 0x11b0, 0,
+#undef V12813
+#define V12813 (V + 48958)
+ 0x1112, 0x1165, 0x11b1, 0,
+#undef V12814
+#define V12814 (V + 48962)
+ 0x1112, 0x1165, 0x11b2, 0,
+#undef V12815
+#define V12815 (V + 48966)
+ 0x1112, 0x1165, 0x11b3, 0,
+#undef V12816
+#define V12816 (V + 48970)
+ 0x1112, 0x1165, 0x11b4, 0,
+#undef V12817
+#define V12817 (V + 48974)
+ 0x1112, 0x1165, 0x11b5, 0,
+#undef V12818
+#define V12818 (V + 48978)
+ 0x1112, 0x1165, 0x11b6, 0,
+#undef V12819
+#define V12819 (V + 48982)
+ 0x1112, 0x1165, 0x11b7, 0,
+#undef V12820
+#define V12820 (V + 48986)
+ 0x1112, 0x1165, 0x11b8, 0,
+#undef V12821
+#define V12821 (V + 48990)
+ 0x1112, 0x1165, 0x11b9, 0,
+#undef V12822
+#define V12822 (V + 48994)
+ 0x1112, 0x1165, 0x11ba, 0,
+#undef V12823
+#define V12823 (V + 48998)
+ 0x1112, 0x1165, 0x11bb, 0,
+#undef V12824
+#define V12824 (V + 49002)
+ 0x1112, 0x1165, 0x11bc, 0,
+#undef V12825
+#define V12825 (V + 49006)
+ 0x1112, 0x1165, 0x11bd, 0,
+#undef V12826
+#define V12826 (V + 49010)
+ 0x1112, 0x1165, 0x11be, 0,
+#undef V12827
+#define V12827 (V + 49014)
+ 0x1112, 0x1165, 0x11bf, 0,
+#undef V12828
+#define V12828 (V + 49018)
+ 0x1112, 0x1165, 0x11c0, 0,
+#undef V12829
+#define V12829 (V + 49022)
+ 0x1112, 0x1165, 0x11c1, 0,
+#undef V12830
+#define V12830 (V + 49026)
+ 0x1112, 0x1165, 0x11c2, 0,
+#undef V12831
+#define V12831 (V + 49030)
+ 0x1112, 0x1166, 0,
+#undef V12832
+#define V12832 (V + 49033)
+ 0x1112, 0x1166, 0x11a8, 0,
+#undef V12833
+#define V12833 (V + 49037)
+ 0x1112, 0x1166, 0x11a9, 0,
+#undef V12834
+#define V12834 (V + 49041)
+ 0x1112, 0x1166, 0x11aa, 0,
+#undef V12835
+#define V12835 (V + 49045)
+ 0x1112, 0x1166, 0x11ab, 0,
+#undef V12836
+#define V12836 (V + 49049)
+ 0x1112, 0x1166, 0x11ac, 0,
+#undef V12837
+#define V12837 (V + 49053)
+ 0x1112, 0x1166, 0x11ad, 0,
+#undef V12838
+#define V12838 (V + 49057)
+ 0x1112, 0x1166, 0x11ae, 0,
+#undef V12839
+#define V12839 (V + 49061)
+ 0x1112, 0x1166, 0x11af, 0,
+#undef V12840
+#define V12840 (V + 49065)
+ 0x1112, 0x1166, 0x11b0, 0,
+#undef V12841
+#define V12841 (V + 49069)
+ 0x1112, 0x1166, 0x11b1, 0,
+#undef V12842
+#define V12842 (V + 49073)
+ 0x1112, 0x1166, 0x11b2, 0,
+#undef V12843
+#define V12843 (V + 49077)
+ 0x1112, 0x1166, 0x11b3, 0,
+#undef V12844
+#define V12844 (V + 49081)
+ 0x1112, 0x1166, 0x11b4, 0,
+#undef V12845
+#define V12845 (V + 49085)
+ 0x1112, 0x1166, 0x11b5, 0,
+#undef V12846
+#define V12846 (V + 49089)
+ 0x1112, 0x1166, 0x11b6, 0,
+#undef V12847
+#define V12847 (V + 49093)
+ 0x1112, 0x1166, 0x11b7, 0,
+#undef V12848
+#define V12848 (V + 49097)
+ 0x1112, 0x1166, 0x11b8, 0,
+#undef V12849
+#define V12849 (V + 49101)
+ 0x1112, 0x1166, 0x11b9, 0,
+#undef V12850
+#define V12850 (V + 49105)
+ 0x1112, 0x1166, 0x11ba, 0,
+#undef V12851
+#define V12851 (V + 49109)
+ 0x1112, 0x1166, 0x11bb, 0,
+#undef V12852
+#define V12852 (V + 49113)
+ 0x1112, 0x1166, 0x11bc, 0,
+#undef V12853
+#define V12853 (V + 49117)
+ 0x1112, 0x1166, 0x11bd, 0,
+#undef V12854
+#define V12854 (V + 49121)
+ 0x1112, 0x1166, 0x11be, 0,
+#undef V12855
+#define V12855 (V + 49125)
+ 0x1112, 0x1166, 0x11bf, 0,
+#undef V12856
+#define V12856 (V + 49129)
+ 0x1112, 0x1166, 0x11c0, 0,
+#undef V12857
+#define V12857 (V + 49133)
+ 0x1112, 0x1166, 0x11c1, 0,
+#undef V12858
+#define V12858 (V + 49137)
+ 0x1112, 0x1166, 0x11c2, 0,
+#undef V12859
+#define V12859 (V + 49141)
+ 0x1112, 0x1167, 0,
+#undef V12860
+#define V12860 (V + 49144)
+ 0x1112, 0x1167, 0x11a8, 0,
+#undef V12861
+#define V12861 (V + 49148)
+ 0x1112, 0x1167, 0x11a9, 0,
+#undef V12862
+#define V12862 (V + 49152)
+ 0x1112, 0x1167, 0x11aa, 0,
+#undef V12863
+#define V12863 (V + 49156)
+ 0x1112, 0x1167, 0x11ab, 0,
+#undef V12864
+#define V12864 (V + 49160)
+ 0x1112, 0x1167, 0x11ac, 0,
+#undef V12865
+#define V12865 (V + 49164)
+ 0x1112, 0x1167, 0x11ad, 0,
+#undef V12866
+#define V12866 (V + 49168)
+ 0x1112, 0x1167, 0x11ae, 0,
+#undef V12867
+#define V12867 (V + 49172)
+ 0x1112, 0x1167, 0x11af, 0,
+#undef V12868
+#define V12868 (V + 49176)
+ 0x1112, 0x1167, 0x11b0, 0,
+#undef V12869
+#define V12869 (V + 49180)
+ 0x1112, 0x1167, 0x11b1, 0,
+#undef V12870
+#define V12870 (V + 49184)
+ 0x1112, 0x1167, 0x11b2, 0,
+#undef V12871
+#define V12871 (V + 49188)
+ 0x1112, 0x1167, 0x11b3, 0,
+#undef V12872
+#define V12872 (V + 49192)
+ 0x1112, 0x1167, 0x11b4, 0,
+#undef V12873
+#define V12873 (V + 49196)
+ 0x1112, 0x1167, 0x11b5, 0,
+#undef V12874
+#define V12874 (V + 49200)
+ 0x1112, 0x1167, 0x11b6, 0,
+#undef V12875
+#define V12875 (V + 49204)
+ 0x1112, 0x1167, 0x11b7, 0,
+#undef V12876
+#define V12876 (V + 49208)
+ 0x1112, 0x1167, 0x11b8, 0,
+#undef V12877
+#define V12877 (V + 49212)
+ 0x1112, 0x1167, 0x11b9, 0,
+#undef V12878
+#define V12878 (V + 49216)
+ 0x1112, 0x1167, 0x11ba, 0,
+#undef V12879
+#define V12879 (V + 49220)
+ 0x1112, 0x1167, 0x11bb, 0,
+#undef V12880
+#define V12880 (V + 49224)
+ 0x1112, 0x1167, 0x11bc, 0,
+#undef V12881
+#define V12881 (V + 49228)
+ 0x1112, 0x1167, 0x11bd, 0,
+#undef V12882
+#define V12882 (V + 49232)
+ 0x1112, 0x1167, 0x11be, 0,
+#undef V12883
+#define V12883 (V + 49236)
+ 0x1112, 0x1167, 0x11bf, 0,
+#undef V12884
+#define V12884 (V + 49240)
+ 0x1112, 0x1167, 0x11c0, 0,
+#undef V12885
+#define V12885 (V + 49244)
+ 0x1112, 0x1167, 0x11c1, 0,
+#undef V12886
+#define V12886 (V + 49248)
+ 0x1112, 0x1167, 0x11c2, 0,
+#undef V12887
+#define V12887 (V + 49252)
+ 0x1112, 0x1168, 0,
+#undef V12888
+#define V12888 (V + 49255)
+ 0x1112, 0x1168, 0x11a8, 0,
+#undef V12889
+#define V12889 (V + 49259)
+ 0x1112, 0x1168, 0x11a9, 0,
+#undef V12890
+#define V12890 (V + 49263)
+ 0x1112, 0x1168, 0x11aa, 0,
+#undef V12891
+#define V12891 (V + 49267)
+ 0x1112, 0x1168, 0x11ab, 0,
+#undef V12892
+#define V12892 (V + 49271)
+ 0x1112, 0x1168, 0x11ac, 0,
+#undef V12893
+#define V12893 (V + 49275)
+ 0x1112, 0x1168, 0x11ad, 0,
+#undef V12894
+#define V12894 (V + 49279)
+ 0x1112, 0x1168, 0x11ae, 0,
+#undef V12895
+#define V12895 (V + 49283)
+ 0x1112, 0x1168, 0x11af, 0,
+#undef V12896
+#define V12896 (V + 49287)
+ 0x1112, 0x1168, 0x11b0, 0,
+#undef V12897
+#define V12897 (V + 49291)
+ 0x1112, 0x1168, 0x11b1, 0,
+#undef V12898
+#define V12898 (V + 49295)
+ 0x1112, 0x1168, 0x11b2, 0,
+#undef V12899
+#define V12899 (V + 49299)
+ 0x1112, 0x1168, 0x11b3, 0,
+#undef V12900
+#define V12900 (V + 49303)
+ 0x1112, 0x1168, 0x11b4, 0,
+#undef V12901
+#define V12901 (V + 49307)
+ 0x1112, 0x1168, 0x11b5, 0,
+#undef V12902
+#define V12902 (V + 49311)
+ 0x1112, 0x1168, 0x11b6, 0,
+#undef V12903
+#define V12903 (V + 49315)
+ 0x1112, 0x1168, 0x11b7, 0,
+#undef V12904
+#define V12904 (V + 49319)
+ 0x1112, 0x1168, 0x11b8, 0,
+#undef V12905
+#define V12905 (V + 49323)
+ 0x1112, 0x1168, 0x11b9, 0,
+#undef V12906
+#define V12906 (V + 49327)
+ 0x1112, 0x1168, 0x11ba, 0,
+#undef V12907
+#define V12907 (V + 49331)
+ 0x1112, 0x1168, 0x11bb, 0,
+#undef V12908
+#define V12908 (V + 49335)
+ 0x1112, 0x1168, 0x11bc, 0,
+#undef V12909
+#define V12909 (V + 49339)
+ 0x1112, 0x1168, 0x11bd, 0,
+#undef V12910
+#define V12910 (V + 49343)
+ 0x1112, 0x1168, 0x11be, 0,
+#undef V12911
+#define V12911 (V + 49347)
+ 0x1112, 0x1168, 0x11bf, 0,
+#undef V12912
+#define V12912 (V + 49351)
+ 0x1112, 0x1168, 0x11c0, 0,
+#undef V12913
+#define V12913 (V + 49355)
+ 0x1112, 0x1168, 0x11c1, 0,
+#undef V12914
+#define V12914 (V + 49359)
+ 0x1112, 0x1168, 0x11c2, 0,
+#undef V12915
+#define V12915 (V + 49363)
+ 0x1112, 0x1169, 0,
+#undef V12916
+#define V12916 (V + 49366)
+ 0x1112, 0x1169, 0x11a8, 0,
+#undef V12917
+#define V12917 (V + 49370)
+ 0x1112, 0x1169, 0x11a9, 0,
+#undef V12918
+#define V12918 (V + 49374)
+ 0x1112, 0x1169, 0x11aa, 0,
+#undef V12919
+#define V12919 (V + 49378)
+ 0x1112, 0x1169, 0x11ab, 0,
+#undef V12920
+#define V12920 (V + 49382)
+ 0x1112, 0x1169, 0x11ac, 0,
+#undef V12921
+#define V12921 (V + 49386)
+ 0x1112, 0x1169, 0x11ad, 0,
+#undef V12922
+#define V12922 (V + 49390)
+ 0x1112, 0x1169, 0x11ae, 0,
+#undef V12923
+#define V12923 (V + 49394)
+ 0x1112, 0x1169, 0x11af, 0,
+#undef V12924
+#define V12924 (V + 49398)
+ 0x1112, 0x1169, 0x11b0, 0,
+#undef V12925
+#define V12925 (V + 49402)
+ 0x1112, 0x1169, 0x11b1, 0,
+#undef V12926
+#define V12926 (V + 49406)
+ 0x1112, 0x1169, 0x11b2, 0,
+#undef V12927
+#define V12927 (V + 49410)
+ 0x1112, 0x1169, 0x11b3, 0,
+#undef V12928
+#define V12928 (V + 49414)
+ 0x1112, 0x1169, 0x11b4, 0,
+#undef V12929
+#define V12929 (V + 49418)
+ 0x1112, 0x1169, 0x11b5, 0,
+#undef V12930
+#define V12930 (V + 49422)
+ 0x1112, 0x1169, 0x11b6, 0,
+#undef V12931
+#define V12931 (V + 49426)
+ 0x1112, 0x1169, 0x11b7, 0,
+#undef V12932
+#define V12932 (V + 49430)
+ 0x1112, 0x1169, 0x11b8, 0,
+#undef V12933
+#define V12933 (V + 49434)
+ 0x1112, 0x1169, 0x11b9, 0,
+#undef V12934
+#define V12934 (V + 49438)
+ 0x1112, 0x1169, 0x11ba, 0,
+#undef V12935
+#define V12935 (V + 49442)
+ 0x1112, 0x1169, 0x11bb, 0,
+#undef V12936
+#define V12936 (V + 49446)
+ 0x1112, 0x1169, 0x11bc, 0,
+#undef V12937
+#define V12937 (V + 49450)
+ 0x1112, 0x1169, 0x11bd, 0,
+#undef V12938
+#define V12938 (V + 49454)
+ 0x1112, 0x1169, 0x11be, 0,
+#undef V12939
+#define V12939 (V + 49458)
+ 0x1112, 0x1169, 0x11bf, 0,
+#undef V12940
+#define V12940 (V + 49462)
+ 0x1112, 0x1169, 0x11c0, 0,
+#undef V12941
+#define V12941 (V + 49466)
+ 0x1112, 0x1169, 0x11c1, 0,
+#undef V12942
+#define V12942 (V + 49470)
+ 0x1112, 0x1169, 0x11c2, 0,
+#undef V12943
+#define V12943 (V + 49474)
+ 0x1112, 0x116a, 0,
+#undef V12944
+#define V12944 (V + 49477)
+ 0x1112, 0x116a, 0x11a8, 0,
+#undef V12945
+#define V12945 (V + 49481)
+ 0x1112, 0x116a, 0x11a9, 0,
+#undef V12946
+#define V12946 (V + 49485)
+ 0x1112, 0x116a, 0x11aa, 0,
+#undef V12947
+#define V12947 (V + 49489)
+ 0x1112, 0x116a, 0x11ab, 0,
+#undef V12948
+#define V12948 (V + 49493)
+ 0x1112, 0x116a, 0x11ac, 0,
+#undef V12949
+#define V12949 (V + 49497)
+ 0x1112, 0x116a, 0x11ad, 0,
+#undef V12950
+#define V12950 (V + 49501)
+ 0x1112, 0x116a, 0x11ae, 0,
+#undef V12951
+#define V12951 (V + 49505)
+ 0x1112, 0x116a, 0x11af, 0,
+#undef V12952
+#define V12952 (V + 49509)
+ 0x1112, 0x116a, 0x11b0, 0,
+#undef V12953
+#define V12953 (V + 49513)
+ 0x1112, 0x116a, 0x11b1, 0,
+#undef V12954
+#define V12954 (V + 49517)
+ 0x1112, 0x116a, 0x11b2, 0,
+#undef V12955
+#define V12955 (V + 49521)
+ 0x1112, 0x116a, 0x11b3, 0,
+#undef V12956
+#define V12956 (V + 49525)
+ 0x1112, 0x116a, 0x11b4, 0,
+#undef V12957
+#define V12957 (V + 49529)
+ 0x1112, 0x116a, 0x11b5, 0,
+#undef V12958
+#define V12958 (V + 49533)
+ 0x1112, 0x116a, 0x11b6, 0,
+#undef V12959
+#define V12959 (V + 49537)
+ 0x1112, 0x116a, 0x11b7, 0,
+#undef V12960
+#define V12960 (V + 49541)
+ 0x1112, 0x116a, 0x11b8, 0,
+#undef V12961
+#define V12961 (V + 49545)
+ 0x1112, 0x116a, 0x11b9, 0,
+#undef V12962
+#define V12962 (V + 49549)
+ 0x1112, 0x116a, 0x11ba, 0,
+#undef V12963
+#define V12963 (V + 49553)
+ 0x1112, 0x116a, 0x11bb, 0,
+#undef V12964
+#define V12964 (V + 49557)
+ 0x1112, 0x116a, 0x11bc, 0,
+#undef V12965
+#define V12965 (V + 49561)
+ 0x1112, 0x116a, 0x11bd, 0,
+#undef V12966
+#define V12966 (V + 49565)
+ 0x1112, 0x116a, 0x11be, 0,
+#undef V12967
+#define V12967 (V + 49569)
+ 0x1112, 0x116a, 0x11bf, 0,
+#undef V12968
+#define V12968 (V + 49573)
+ 0x1112, 0x116a, 0x11c0, 0,
+#undef V12969
+#define V12969 (V + 49577)
+ 0x1112, 0x116a, 0x11c1, 0,
+#undef V12970
+#define V12970 (V + 49581)
+ 0x1112, 0x116a, 0x11c2, 0,
+#undef V12971
+#define V12971 (V + 49585)
+ 0x1112, 0x116b, 0,
+#undef V12972
+#define V12972 (V + 49588)
+ 0x1112, 0x116b, 0x11a8, 0,
+#undef V12973
+#define V12973 (V + 49592)
+ 0x1112, 0x116b, 0x11a9, 0,
+#undef V12974
+#define V12974 (V + 49596)
+ 0x1112, 0x116b, 0x11aa, 0,
+#undef V12975
+#define V12975 (V + 49600)
+ 0x1112, 0x116b, 0x11ab, 0,
+#undef V12976
+#define V12976 (V + 49604)
+ 0x1112, 0x116b, 0x11ac, 0,
+#undef V12977
+#define V12977 (V + 49608)
+ 0x1112, 0x116b, 0x11ad, 0,
+#undef V12978
+#define V12978 (V + 49612)
+ 0x1112, 0x116b, 0x11ae, 0,
+#undef V12979
+#define V12979 (V + 49616)
+ 0x1112, 0x116b, 0x11af, 0,
+#undef V12980
+#define V12980 (V + 49620)
+ 0x1112, 0x116b, 0x11b0, 0,
+#undef V12981
+#define V12981 (V + 49624)
+ 0x1112, 0x116b, 0x11b1, 0,
+#undef V12982
+#define V12982 (V + 49628)
+ 0x1112, 0x116b, 0x11b2, 0,
+#undef V12983
+#define V12983 (V + 49632)
+ 0x1112, 0x116b, 0x11b3, 0,
+#undef V12984
+#define V12984 (V + 49636)
+ 0x1112, 0x116b, 0x11b4, 0,
+#undef V12985
+#define V12985 (V + 49640)
+ 0x1112, 0x116b, 0x11b5, 0,
+#undef V12986
+#define V12986 (V + 49644)
+ 0x1112, 0x116b, 0x11b6, 0,
+#undef V12987
+#define V12987 (V + 49648)
+ 0x1112, 0x116b, 0x11b7, 0,
+#undef V12988
+#define V12988 (V + 49652)
+ 0x1112, 0x116b, 0x11b8, 0,
+#undef V12989
+#define V12989 (V + 49656)
+ 0x1112, 0x116b, 0x11b9, 0,
+#undef V12990
+#define V12990 (V + 49660)
+ 0x1112, 0x116b, 0x11ba, 0,
+#undef V12991
+#define V12991 (V + 49664)
+ 0x1112, 0x116b, 0x11bb, 0,
+#undef V12992
+#define V12992 (V + 49668)
+ 0x1112, 0x116b, 0x11bc, 0,
+#undef V12993
+#define V12993 (V + 49672)
+ 0x1112, 0x116b, 0x11bd, 0,
+#undef V12994
+#define V12994 (V + 49676)
+ 0x1112, 0x116b, 0x11be, 0,
+#undef V12995
+#define V12995 (V + 49680)
+ 0x1112, 0x116b, 0x11bf, 0,
+#undef V12996
+#define V12996 (V + 49684)
+ 0x1112, 0x116b, 0x11c0, 0,
+#undef V12997
+#define V12997 (V + 49688)
+ 0x1112, 0x116b, 0x11c1, 0,
+#undef V12998
+#define V12998 (V + 49692)
+ 0x1112, 0x116b, 0x11c2, 0,
+#undef V12999
+#define V12999 (V + 49696)
+ 0x1112, 0x116c, 0,
+#undef V13000
+#define V13000 (V + 49699)
+ 0x1112, 0x116c, 0x11a8, 0,
+#undef V13001
+#define V13001 (V + 49703)
+ 0x1112, 0x116c, 0x11a9, 0,
+#undef V13002
+#define V13002 (V + 49707)
+ 0x1112, 0x116c, 0x11aa, 0,
+#undef V13003
+#define V13003 (V + 49711)
+ 0x1112, 0x116c, 0x11ab, 0,
+#undef V13004
+#define V13004 (V + 49715)
+ 0x1112, 0x116c, 0x11ac, 0,
+#undef V13005
+#define V13005 (V + 49719)
+ 0x1112, 0x116c, 0x11ad, 0,
+#undef V13006
+#define V13006 (V + 49723)
+ 0x1112, 0x116c, 0x11ae, 0,
+#undef V13007
+#define V13007 (V + 49727)
+ 0x1112, 0x116c, 0x11af, 0,
+#undef V13008
+#define V13008 (V + 49731)
+ 0x1112, 0x116c, 0x11b0, 0,
+#undef V13009
+#define V13009 (V + 49735)
+ 0x1112, 0x116c, 0x11b1, 0,
+#undef V13010
+#define V13010 (V + 49739)
+ 0x1112, 0x116c, 0x11b2, 0,
+#undef V13011
+#define V13011 (V + 49743)
+ 0x1112, 0x116c, 0x11b3, 0,
+#undef V13012
+#define V13012 (V + 49747)
+ 0x1112, 0x116c, 0x11b4, 0,
+#undef V13013
+#define V13013 (V + 49751)
+ 0x1112, 0x116c, 0x11b5, 0,
+#undef V13014
+#define V13014 (V + 49755)
+ 0x1112, 0x116c, 0x11b6, 0,
+#undef V13015
+#define V13015 (V + 49759)
+ 0x1112, 0x116c, 0x11b7, 0,
+#undef V13016
+#define V13016 (V + 49763)
+ 0x1112, 0x116c, 0x11b8, 0,
+#undef V13017
+#define V13017 (V + 49767)
+ 0x1112, 0x116c, 0x11b9, 0,
+#undef V13018
+#define V13018 (V + 49771)
+ 0x1112, 0x116c, 0x11ba, 0,
+#undef V13019
+#define V13019 (V + 49775)
+ 0x1112, 0x116c, 0x11bb, 0,
+#undef V13020
+#define V13020 (V + 49779)
+ 0x1112, 0x116c, 0x11bc, 0,
+#undef V13021
+#define V13021 (V + 49783)
+ 0x1112, 0x116c, 0x11bd, 0,
+#undef V13022
+#define V13022 (V + 49787)
+ 0x1112, 0x116c, 0x11be, 0,
+#undef V13023
+#define V13023 (V + 49791)
+ 0x1112, 0x116c, 0x11bf, 0,
+#undef V13024
+#define V13024 (V + 49795)
+ 0x1112, 0x116c, 0x11c0, 0,
+#undef V13025
+#define V13025 (V + 49799)
+ 0x1112, 0x116c, 0x11c1, 0,
+#undef V13026
+#define V13026 (V + 49803)
+ 0x1112, 0x116c, 0x11c2, 0,
+#undef V13027
+#define V13027 (V + 49807)
+ 0x1112, 0x116d, 0,
+#undef V13028
+#define V13028 (V + 49810)
+ 0x1112, 0x116d, 0x11a8, 0,
+#undef V13029
+#define V13029 (V + 49814)
+ 0x1112, 0x116d, 0x11a9, 0,
+#undef V13030
+#define V13030 (V + 49818)
+ 0x1112, 0x116d, 0x11aa, 0,
+#undef V13031
+#define V13031 (V + 49822)
+ 0x1112, 0x116d, 0x11ab, 0,
+#undef V13032
+#define V13032 (V + 49826)
+ 0x1112, 0x116d, 0x11ac, 0,
+#undef V13033
+#define V13033 (V + 49830)
+ 0x1112, 0x116d, 0x11ad, 0,
+#undef V13034
+#define V13034 (V + 49834)
+ 0x1112, 0x116d, 0x11ae, 0,
+#undef V13035
+#define V13035 (V + 49838)
+ 0x1112, 0x116d, 0x11af, 0,
+#undef V13036
+#define V13036 (V + 49842)
+ 0x1112, 0x116d, 0x11b0, 0,
+#undef V13037
+#define V13037 (V + 49846)
+ 0x1112, 0x116d, 0x11b1, 0,
+#undef V13038
+#define V13038 (V + 49850)
+ 0x1112, 0x116d, 0x11b2, 0,
+#undef V13039
+#define V13039 (V + 49854)
+ 0x1112, 0x116d, 0x11b3, 0,
+#undef V13040
+#define V13040 (V + 49858)
+ 0x1112, 0x116d, 0x11b4, 0,
+#undef V13041
+#define V13041 (V + 49862)
+ 0x1112, 0x116d, 0x11b5, 0,
+#undef V13042
+#define V13042 (V + 49866)
+ 0x1112, 0x116d, 0x11b6, 0,
+#undef V13043
+#define V13043 (V + 49870)
+ 0x1112, 0x116d, 0x11b7, 0,
+#undef V13044
+#define V13044 (V + 49874)
+ 0x1112, 0x116d, 0x11b8, 0,
+#undef V13045
+#define V13045 (V + 49878)
+ 0x1112, 0x116d, 0x11b9, 0,
+#undef V13046
+#define V13046 (V + 49882)
+ 0x1112, 0x116d, 0x11ba, 0,
+#undef V13047
+#define V13047 (V + 49886)
+ 0x1112, 0x116d, 0x11bb, 0,
+#undef V13048
+#define V13048 (V + 49890)
+ 0x1112, 0x116d, 0x11bc, 0,
+#undef V13049
+#define V13049 (V + 49894)
+ 0x1112, 0x116d, 0x11bd, 0,
+#undef V13050
+#define V13050 (V + 49898)
+ 0x1112, 0x116d, 0x11be, 0,
+#undef V13051
+#define V13051 (V + 49902)
+ 0x1112, 0x116d, 0x11bf, 0,
+#undef V13052
+#define V13052 (V + 49906)
+ 0x1112, 0x116d, 0x11c0, 0,
+#undef V13053
+#define V13053 (V + 49910)
+ 0x1112, 0x116d, 0x11c1, 0,
+#undef V13054
+#define V13054 (V + 49914)
+ 0x1112, 0x116d, 0x11c2, 0,
+#undef V13055
+#define V13055 (V + 49918)
+ 0x1112, 0x116e, 0,
+#undef V13056
+#define V13056 (V + 49921)
+ 0x1112, 0x116e, 0x11a8, 0,
+#undef V13057
+#define V13057 (V + 49925)
+ 0x1112, 0x116e, 0x11a9, 0,
+#undef V13058
+#define V13058 (V + 49929)
+ 0x1112, 0x116e, 0x11aa, 0,
+#undef V13059
+#define V13059 (V + 49933)
+ 0x1112, 0x116e, 0x11ab, 0,
+#undef V13060
+#define V13060 (V + 49937)
+ 0x1112, 0x116e, 0x11ac, 0,
+#undef V13061
+#define V13061 (V + 49941)
+ 0x1112, 0x116e, 0x11ad, 0,
+#undef V13062
+#define V13062 (V + 49945)
+ 0x1112, 0x116e, 0x11ae, 0,
+#undef V13063
+#define V13063 (V + 49949)
+ 0x1112, 0x116e, 0x11af, 0,
+#undef V13064
+#define V13064 (V + 49953)
+ 0x1112, 0x116e, 0x11b0, 0,
+#undef V13065
+#define V13065 (V + 49957)
+ 0x1112, 0x116e, 0x11b1, 0,
+#undef V13066
+#define V13066 (V + 49961)
+ 0x1112, 0x116e, 0x11b2, 0,
+#undef V13067
+#define V13067 (V + 49965)
+ 0x1112, 0x116e, 0x11b3, 0,
+#undef V13068
+#define V13068 (V + 49969)
+ 0x1112, 0x116e, 0x11b4, 0,
+#undef V13069
+#define V13069 (V + 49973)
+ 0x1112, 0x116e, 0x11b5, 0,
+#undef V13070
+#define V13070 (V + 49977)
+ 0x1112, 0x116e, 0x11b6, 0,
+#undef V13071
+#define V13071 (V + 49981)
+ 0x1112, 0x116e, 0x11b7, 0,
+#undef V13072
+#define V13072 (V + 49985)
+ 0x1112, 0x116e, 0x11b8, 0,
+#undef V13073
+#define V13073 (V + 49989)
+ 0x1112, 0x116e, 0x11b9, 0,
+#undef V13074
+#define V13074 (V + 49993)
+ 0x1112, 0x116e, 0x11ba, 0,
+#undef V13075
+#define V13075 (V + 49997)
+ 0x1112, 0x116e, 0x11bb, 0,
+#undef V13076
+#define V13076 (V + 50001)
+ 0x1112, 0x116e, 0x11bc, 0,
+#undef V13077
+#define V13077 (V + 50005)
+ 0x1112, 0x116e, 0x11bd, 0,
+#undef V13078
+#define V13078 (V + 50009)
+ 0x1112, 0x116e, 0x11be, 0,
+#undef V13079
+#define V13079 (V + 50013)
+ 0x1112, 0x116e, 0x11bf, 0,
+#undef V13080
+#define V13080 (V + 50017)
+ 0x1112, 0x116e, 0x11c0, 0,
+#undef V13081
+#define V13081 (V + 50021)
+ 0x1112, 0x116e, 0x11c1, 0,
+#undef V13082
+#define V13082 (V + 50025)
+ 0x1112, 0x116e, 0x11c2, 0,
+#undef V13083
+#define V13083 (V + 50029)
+ 0x1112, 0x116f, 0,
+#undef V13084
+#define V13084 (V + 50032)
+ 0x1112, 0x116f, 0x11a8, 0,
+#undef V13085
+#define V13085 (V + 50036)
+ 0x1112, 0x116f, 0x11a9, 0,
+#undef V13086
+#define V13086 (V + 50040)
+ 0x1112, 0x116f, 0x11aa, 0,
+#undef V13087
+#define V13087 (V + 50044)
+ 0x1112, 0x116f, 0x11ab, 0,
+#undef V13088
+#define V13088 (V + 50048)
+ 0x1112, 0x116f, 0x11ac, 0,
+#undef V13089
+#define V13089 (V + 50052)
+ 0x1112, 0x116f, 0x11ad, 0,
+#undef V13090
+#define V13090 (V + 50056)
+ 0x1112, 0x116f, 0x11ae, 0,
+#undef V13091
+#define V13091 (V + 50060)
+ 0x1112, 0x116f, 0x11af, 0,
+#undef V13092
+#define V13092 (V + 50064)
+ 0x1112, 0x116f, 0x11b0, 0,
+#undef V13093
+#define V13093 (V + 50068)
+ 0x1112, 0x116f, 0x11b1, 0,
+#undef V13094
+#define V13094 (V + 50072)
+ 0x1112, 0x116f, 0x11b2, 0,
+#undef V13095
+#define V13095 (V + 50076)
+ 0x1112, 0x116f, 0x11b3, 0,
+#undef V13096
+#define V13096 (V + 50080)
+ 0x1112, 0x116f, 0x11b4, 0,
+#undef V13097
+#define V13097 (V + 50084)
+ 0x1112, 0x116f, 0x11b5, 0,
+#undef V13098
+#define V13098 (V + 50088)
+ 0x1112, 0x116f, 0x11b6, 0,
+#undef V13099
+#define V13099 (V + 50092)
+ 0x1112, 0x116f, 0x11b7, 0,
+#undef V13100
+#define V13100 (V + 50096)
+ 0x1112, 0x116f, 0x11b8, 0,
+#undef V13101
+#define V13101 (V + 50100)
+ 0x1112, 0x116f, 0x11b9, 0,
+#undef V13102
+#define V13102 (V + 50104)
+ 0x1112, 0x116f, 0x11ba, 0,
+#undef V13103
+#define V13103 (V + 50108)
+ 0x1112, 0x116f, 0x11bb, 0,
+#undef V13104
+#define V13104 (V + 50112)
+ 0x1112, 0x116f, 0x11bc, 0,
+#undef V13105
+#define V13105 (V + 50116)
+ 0x1112, 0x116f, 0x11bd, 0,
+#undef V13106
+#define V13106 (V + 50120)
+ 0x1112, 0x116f, 0x11be, 0,
+#undef V13107
+#define V13107 (V + 50124)
+ 0x1112, 0x116f, 0x11bf, 0,
+#undef V13108
+#define V13108 (V + 50128)
+ 0x1112, 0x116f, 0x11c0, 0,
+#undef V13109
+#define V13109 (V + 50132)
+ 0x1112, 0x116f, 0x11c1, 0,
+#undef V13110
+#define V13110 (V + 50136)
+ 0x1112, 0x116f, 0x11c2, 0,
+#undef V13111
+#define V13111 (V + 50140)
+ 0x1112, 0x1170, 0,
+#undef V13112
+#define V13112 (V + 50143)
+ 0x1112, 0x1170, 0x11a8, 0,
+#undef V13113
+#define V13113 (V + 50147)
+ 0x1112, 0x1170, 0x11a9, 0,
+#undef V13114
+#define V13114 (V + 50151)
+ 0x1112, 0x1170, 0x11aa, 0,
+#undef V13115
+#define V13115 (V + 50155)
+ 0x1112, 0x1170, 0x11ab, 0,
+#undef V13116
+#define V13116 (V + 50159)
+ 0x1112, 0x1170, 0x11ac, 0,
+#undef V13117
+#define V13117 (V + 50163)
+ 0x1112, 0x1170, 0x11ad, 0,
+#undef V13118
+#define V13118 (V + 50167)
+ 0x1112, 0x1170, 0x11ae, 0,
+#undef V13119
+#define V13119 (V + 50171)
+ 0x1112, 0x1170, 0x11af, 0,
+#undef V13120
+#define V13120 (V + 50175)
+ 0x1112, 0x1170, 0x11b0, 0,
+#undef V13121
+#define V13121 (V + 50179)
+ 0x1112, 0x1170, 0x11b1, 0,
+#undef V13122
+#define V13122 (V + 50183)
+ 0x1112, 0x1170, 0x11b2, 0,
+#undef V13123
+#define V13123 (V + 50187)
+ 0x1112, 0x1170, 0x11b3, 0,
+#undef V13124
+#define V13124 (V + 50191)
+ 0x1112, 0x1170, 0x11b4, 0,
+#undef V13125
+#define V13125 (V + 50195)
+ 0x1112, 0x1170, 0x11b5, 0,
+#undef V13126
+#define V13126 (V + 50199)
+ 0x1112, 0x1170, 0x11b6, 0,
+#undef V13127
+#define V13127 (V + 50203)
+ 0x1112, 0x1170, 0x11b7, 0,
+#undef V13128
+#define V13128 (V + 50207)
+ 0x1112, 0x1170, 0x11b8, 0,
+#undef V13129
+#define V13129 (V + 50211)
+ 0x1112, 0x1170, 0x11b9, 0,
+#undef V13130
+#define V13130 (V + 50215)
+ 0x1112, 0x1170, 0x11ba, 0,
+#undef V13131
+#define V13131 (V + 50219)
+ 0x1112, 0x1170, 0x11bb, 0,
+#undef V13132
+#define V13132 (V + 50223)
+ 0x1112, 0x1170, 0x11bc, 0,
+#undef V13133
+#define V13133 (V + 50227)
+ 0x1112, 0x1170, 0x11bd, 0,
+#undef V13134
+#define V13134 (V + 50231)
+ 0x1112, 0x1170, 0x11be, 0,
+#undef V13135
+#define V13135 (V + 50235)
+ 0x1112, 0x1170, 0x11bf, 0,
+#undef V13136
+#define V13136 (V + 50239)
+ 0x1112, 0x1170, 0x11c0, 0,
+#undef V13137
+#define V13137 (V + 50243)
+ 0x1112, 0x1170, 0x11c1, 0,
+#undef V13138
+#define V13138 (V + 50247)
+ 0x1112, 0x1170, 0x11c2, 0,
+#undef V13139
+#define V13139 (V + 50251)
+ 0x1112, 0x1171, 0,
+#undef V13140
+#define V13140 (V + 50254)
+ 0x1112, 0x1171, 0x11a8, 0,
+#undef V13141
+#define V13141 (V + 50258)
+ 0x1112, 0x1171, 0x11a9, 0,
+#undef V13142
+#define V13142 (V + 50262)
+ 0x1112, 0x1171, 0x11aa, 0,
+#undef V13143
+#define V13143 (V + 50266)
+ 0x1112, 0x1171, 0x11ab, 0,
+#undef V13144
+#define V13144 (V + 50270)
+ 0x1112, 0x1171, 0x11ac, 0,
+#undef V13145
+#define V13145 (V + 50274)
+ 0x1112, 0x1171, 0x11ad, 0,
+#undef V13146
+#define V13146 (V + 50278)
+ 0x1112, 0x1171, 0x11ae, 0,
+#undef V13147
+#define V13147 (V + 50282)
+ 0x1112, 0x1171, 0x11af, 0,
+#undef V13148
+#define V13148 (V + 50286)
+ 0x1112, 0x1171, 0x11b0, 0,
+#undef V13149
+#define V13149 (V + 50290)
+ 0x1112, 0x1171, 0x11b1, 0,
+#undef V13150
+#define V13150 (V + 50294)
+ 0x1112, 0x1171, 0x11b2, 0,
+#undef V13151
+#define V13151 (V + 50298)
+ 0x1112, 0x1171, 0x11b3, 0,
+#undef V13152
+#define V13152 (V + 50302)
+ 0x1112, 0x1171, 0x11b4, 0,
+#undef V13153
+#define V13153 (V + 50306)
+ 0x1112, 0x1171, 0x11b5, 0,
+#undef V13154
+#define V13154 (V + 50310)
+ 0x1112, 0x1171, 0x11b6, 0,
+#undef V13155
+#define V13155 (V + 50314)
+ 0x1112, 0x1171, 0x11b7, 0,
+#undef V13156
+#define V13156 (V + 50318)
+ 0x1112, 0x1171, 0x11b8, 0,
+#undef V13157
+#define V13157 (V + 50322)
+ 0x1112, 0x1171, 0x11b9, 0,
+#undef V13158
+#define V13158 (V + 50326)
+ 0x1112, 0x1171, 0x11ba, 0,
+#undef V13159
+#define V13159 (V + 50330)
+ 0x1112, 0x1171, 0x11bb, 0,
+#undef V13160
+#define V13160 (V + 50334)
+ 0x1112, 0x1171, 0x11bc, 0,
+#undef V13161
+#define V13161 (V + 50338)
+ 0x1112, 0x1171, 0x11bd, 0,
+#undef V13162
+#define V13162 (V + 50342)
+ 0x1112, 0x1171, 0x11be, 0,
+#undef V13163
+#define V13163 (V + 50346)
+ 0x1112, 0x1171, 0x11bf, 0,
+#undef V13164
+#define V13164 (V + 50350)
+ 0x1112, 0x1171, 0x11c0, 0,
+#undef V13165
+#define V13165 (V + 50354)
+ 0x1112, 0x1171, 0x11c1, 0,
+#undef V13166
+#define V13166 (V + 50358)
+ 0x1112, 0x1171, 0x11c2, 0,
+#undef V13167
+#define V13167 (V + 50362)
+ 0x1112, 0x1172, 0,
+#undef V13168
+#define V13168 (V + 50365)
+ 0x1112, 0x1172, 0x11a8, 0,
+#undef V13169
+#define V13169 (V + 50369)
+ 0x1112, 0x1172, 0x11a9, 0,
+#undef V13170
+#define V13170 (V + 50373)
+ 0x1112, 0x1172, 0x11aa, 0,
+#undef V13171
+#define V13171 (V + 50377)
+ 0x1112, 0x1172, 0x11ab, 0,
+#undef V13172
+#define V13172 (V + 50381)
+ 0x1112, 0x1172, 0x11ac, 0,
+#undef V13173
+#define V13173 (V + 50385)
+ 0x1112, 0x1172, 0x11ad, 0,
+#undef V13174
+#define V13174 (V + 50389)
+ 0x1112, 0x1172, 0x11ae, 0,
+#undef V13175
+#define V13175 (V + 50393)
+ 0x1112, 0x1172, 0x11af, 0,
+#undef V13176
+#define V13176 (V + 50397)
+ 0x1112, 0x1172, 0x11b0, 0,
+#undef V13177
+#define V13177 (V + 50401)
+ 0x1112, 0x1172, 0x11b1, 0,
+#undef V13178
+#define V13178 (V + 50405)
+ 0x1112, 0x1172, 0x11b2, 0,
+#undef V13179
+#define V13179 (V + 50409)
+ 0x1112, 0x1172, 0x11b3, 0,
+#undef V13180
+#define V13180 (V + 50413)
+ 0x1112, 0x1172, 0x11b4, 0,
+#undef V13181
+#define V13181 (V + 50417)
+ 0x1112, 0x1172, 0x11b5, 0,
+#undef V13182
+#define V13182 (V + 50421)
+ 0x1112, 0x1172, 0x11b6, 0,
+#undef V13183
+#define V13183 (V + 50425)
+ 0x1112, 0x1172, 0x11b7, 0,
+#undef V13184
+#define V13184 (V + 50429)
+ 0x1112, 0x1172, 0x11b8, 0,
+#undef V13185
+#define V13185 (V + 50433)
+ 0x1112, 0x1172, 0x11b9, 0,
+#undef V13186
+#define V13186 (V + 50437)
+ 0x1112, 0x1172, 0x11ba, 0,
+#undef V13187
+#define V13187 (V + 50441)
+ 0x1112, 0x1172, 0x11bb, 0,
+#undef V13188
+#define V13188 (V + 50445)
+ 0x1112, 0x1172, 0x11bc, 0,
+#undef V13189
+#define V13189 (V + 50449)
+ 0x1112, 0x1172, 0x11bd, 0,
+#undef V13190
+#define V13190 (V + 50453)
+ 0x1112, 0x1172, 0x11be, 0,
+#undef V13191
+#define V13191 (V + 50457)
+ 0x1112, 0x1172, 0x11bf, 0,
+#undef V13192
+#define V13192 (V + 50461)
+ 0x1112, 0x1172, 0x11c0, 0,
+#undef V13193
+#define V13193 (V + 50465)
+ 0x1112, 0x1172, 0x11c1, 0,
+#undef V13194
+#define V13194 (V + 50469)
+ 0x1112, 0x1172, 0x11c2, 0,
+#undef V13195
+#define V13195 (V + 50473)
+ 0x1112, 0x1173, 0,
+#undef V13196
+#define V13196 (V + 50476)
+ 0x1112, 0x1173, 0x11a8, 0,
+#undef V13197
+#define V13197 (V + 50480)
+ 0x1112, 0x1173, 0x11a9, 0,
+#undef V13198
+#define V13198 (V + 50484)
+ 0x1112, 0x1173, 0x11aa, 0,
+#undef V13199
+#define V13199 (V + 50488)
+ 0x1112, 0x1173, 0x11ab, 0,
+#undef V13200
+#define V13200 (V + 50492)
+ 0x1112, 0x1173, 0x11ac, 0,
+#undef V13201
+#define V13201 (V + 50496)
+ 0x1112, 0x1173, 0x11ad, 0,
+#undef V13202
+#define V13202 (V + 50500)
+ 0x1112, 0x1173, 0x11ae, 0,
+#undef V13203
+#define V13203 (V + 50504)
+ 0x1112, 0x1173, 0x11af, 0,
+#undef V13204
+#define V13204 (V + 50508)
+ 0x1112, 0x1173, 0x11b0, 0,
+#undef V13205
+#define V13205 (V + 50512)
+ 0x1112, 0x1173, 0x11b1, 0,
+#undef V13206
+#define V13206 (V + 50516)
+ 0x1112, 0x1173, 0x11b2, 0,
+#undef V13207
+#define V13207 (V + 50520)
+ 0x1112, 0x1173, 0x11b3, 0,
+#undef V13208
+#define V13208 (V + 50524)
+ 0x1112, 0x1173, 0x11b4, 0,
+#undef V13209
+#define V13209 (V + 50528)
+ 0x1112, 0x1173, 0x11b5, 0,
+#undef V13210
+#define V13210 (V + 50532)
+ 0x1112, 0x1173, 0x11b6, 0,
+#undef V13211
+#define V13211 (V + 50536)
+ 0x1112, 0x1173, 0x11b7, 0,
+#undef V13212
+#define V13212 (V + 50540)
+ 0x1112, 0x1173, 0x11b8, 0,
+#undef V13213
+#define V13213 (V + 50544)
+ 0x1112, 0x1173, 0x11b9, 0,
+#undef V13214
+#define V13214 (V + 50548)
+ 0x1112, 0x1173, 0x11ba, 0,
+#undef V13215
+#define V13215 (V + 50552)
+ 0x1112, 0x1173, 0x11bb, 0,
+#undef V13216
+#define V13216 (V + 50556)
+ 0x1112, 0x1173, 0x11bc, 0,
+#undef V13217
+#define V13217 (V + 50560)
+ 0x1112, 0x1173, 0x11bd, 0,
+#undef V13218
+#define V13218 (V + 50564)
+ 0x1112, 0x1173, 0x11be, 0,
+#undef V13219
+#define V13219 (V + 50568)
+ 0x1112, 0x1173, 0x11bf, 0,
+#undef V13220
+#define V13220 (V + 50572)
+ 0x1112, 0x1173, 0x11c0, 0,
+#undef V13221
+#define V13221 (V + 50576)
+ 0x1112, 0x1173, 0x11c1, 0,
+#undef V13222
+#define V13222 (V + 50580)
+ 0x1112, 0x1173, 0x11c2, 0,
+#undef V13223
+#define V13223 (V + 50584)
+ 0x1112, 0x1174, 0,
+#undef V13224
+#define V13224 (V + 50587)
+ 0x1112, 0x1174, 0x11a8, 0,
+#undef V13225
+#define V13225 (V + 50591)
+ 0x1112, 0x1174, 0x11a9, 0,
+#undef V13226
+#define V13226 (V + 50595)
+ 0x1112, 0x1174, 0x11aa, 0,
+#undef V13227
+#define V13227 (V + 50599)
+ 0x1112, 0x1174, 0x11ab, 0,
+#undef V13228
+#define V13228 (V + 50603)
+ 0x1112, 0x1174, 0x11ac, 0,
+#undef V13229
+#define V13229 (V + 50607)
+ 0x1112, 0x1174, 0x11ad, 0,
+#undef V13230
+#define V13230 (V + 50611)
+ 0x1112, 0x1174, 0x11ae, 0,
+#undef V13231
+#define V13231 (V + 50615)
+ 0x1112, 0x1174, 0x11af, 0,
+#undef V13232
+#define V13232 (V + 50619)
+ 0x1112, 0x1174, 0x11b0, 0,
+#undef V13233
+#define V13233 (V + 50623)
+ 0x1112, 0x1174, 0x11b1, 0,
+#undef V13234
+#define V13234 (V + 50627)
+ 0x1112, 0x1174, 0x11b2, 0,
+#undef V13235
+#define V13235 (V + 50631)
+ 0x1112, 0x1174, 0x11b3, 0,
+#undef V13236
+#define V13236 (V + 50635)
+ 0x1112, 0x1174, 0x11b4, 0,
+#undef V13237
+#define V13237 (V + 50639)
+ 0x1112, 0x1174, 0x11b5, 0,
+#undef V13238
+#define V13238 (V + 50643)
+ 0x1112, 0x1174, 0x11b6, 0,
+#undef V13239
+#define V13239 (V + 50647)
+ 0x1112, 0x1174, 0x11b7, 0,
+#undef V13240
+#define V13240 (V + 50651)
+ 0x1112, 0x1174, 0x11b8, 0,
+#undef V13241
+#define V13241 (V + 50655)
+ 0x1112, 0x1174, 0x11b9, 0,
+#undef V13242
+#define V13242 (V + 50659)
+ 0x1112, 0x1174, 0x11ba, 0,
+#undef V13243
+#define V13243 (V + 50663)
+ 0x1112, 0x1174, 0x11bb, 0,
+#undef V13244
+#define V13244 (V + 50667)
+ 0x1112, 0x1174, 0x11bc, 0,
+#undef V13245
+#define V13245 (V + 50671)
+ 0x1112, 0x1174, 0x11bd, 0,
+#undef V13246
+#define V13246 (V + 50675)
+ 0x1112, 0x1174, 0x11be, 0,
+#undef V13247
+#define V13247 (V + 50679)
+ 0x1112, 0x1174, 0x11bf, 0,
+#undef V13248
+#define V13248 (V + 50683)
+ 0x1112, 0x1174, 0x11c0, 0,
+#undef V13249
+#define V13249 (V + 50687)
+ 0x1112, 0x1174, 0x11c1, 0,
+#undef V13250
+#define V13250 (V + 50691)
+ 0x1112, 0x1174, 0x11c2, 0,
+#undef V13251
+#define V13251 (V + 50695)
+ 0x1112, 0x1175, 0,
+#undef V13252
+#define V13252 (V + 50698)
+ 0x1112, 0x1175, 0x11a8, 0,
+#undef V13253
+#define V13253 (V + 50702)
+ 0x1112, 0x1175, 0x11a9, 0,
+#undef V13254
+#define V13254 (V + 50706)
+ 0x1112, 0x1175, 0x11aa, 0,
+#undef V13255
+#define V13255 (V + 50710)
+ 0x1112, 0x1175, 0x11ab, 0,
+#undef V13256
+#define V13256 (V + 50714)
+ 0x1112, 0x1175, 0x11ac, 0,
+#undef V13257
+#define V13257 (V + 50718)
+ 0x1112, 0x1175, 0x11ad, 0,
+#undef V13258
+#define V13258 (V + 50722)
+ 0x1112, 0x1175, 0x11ae, 0,
+#undef V13259
+#define V13259 (V + 50726)
+ 0x1112, 0x1175, 0x11af, 0,
+#undef V13260
+#define V13260 (V + 50730)
+ 0x1112, 0x1175, 0x11b0, 0,
+#undef V13261
+#define V13261 (V + 50734)
+ 0x1112, 0x1175, 0x11b1, 0,
+#undef V13262
+#define V13262 (V + 50738)
+ 0x1112, 0x1175, 0x11b2, 0,
+#undef V13263
+#define V13263 (V + 50742)
+ 0x1112, 0x1175, 0x11b3, 0,
+#undef V13264
+#define V13264 (V + 50746)
+ 0x1112, 0x1175, 0x11b4, 0,
+#undef V13265
+#define V13265 (V + 50750)
+ 0x1112, 0x1175, 0x11b5, 0,
+#undef V13266
+#define V13266 (V + 50754)
+ 0x1112, 0x1175, 0x11b6, 0,
+#undef V13267
+#define V13267 (V + 50758)
+ 0x1112, 0x1175, 0x11b7, 0,
+#undef V13268
+#define V13268 (V + 50762)
+ 0x1112, 0x1175, 0x11b8, 0,
+#undef V13269
+#define V13269 (V + 50766)
+ 0x1112, 0x1175, 0x11b9, 0,
+#undef V13270
+#define V13270 (V + 50770)
+ 0x1112, 0x1175, 0x11ba, 0,
+#undef V13271
+#define V13271 (V + 50774)
+ 0x1112, 0x1175, 0x11bb, 0,
+#undef V13272
+#define V13272 (V + 50778)
+ 0x1112, 0x1175, 0x11bc, 0,
+#undef V13273
+#define V13273 (V + 50782)
+ 0x1112, 0x1175, 0x11bd, 0,
+#undef V13274
+#define V13274 (V + 50786)
+ 0x1112, 0x1175, 0x11be, 0,
+#undef V13275
+#define V13275 (V + 50790)
+ 0x1112, 0x1175, 0x11bf, 0,
+#undef V13276
+#define V13276 (V + 50794)
+ 0x1112, 0x1175, 0x11c0, 0,
+#undef V13277
+#define V13277 (V + 50798)
+ 0x1112, 0x1175, 0x11c1, 0,
+#undef V13278
+#define V13278 (V + 50802)
+ 0x1112, 0x1175, 0x11c2, 0,
+#undef V13279
+#define V13279 (V + 50806)
+ 0x8c48, 0,
+#undef V13280
+#define V13280 (V + 50808)
+ 0x66f4, 0,
+#undef V13281
+#define V13281 (V + 50810)
+ 0x8cc8, 0,
+#undef V13282
+#define V13282 (V + 50812)
+ 0x6ed1, 0,
+#undef V13283
+#define V13283 (V + 50814)
+ 0x4e32, 0,
+#undef V13284
+#define V13284 (V + 50816)
+ 0x53e5, 0,
+#undef V13285
+#define V13285 (V + 50818)
+ 0x5951, 0,
+#undef V13286
+#define V13286 (V + 50820)
+ 0x5587, 0,
+#undef V13287
+#define V13287 (V + 50822)
+ 0x5948, 0,
+#undef V13288
+#define V13288 (V + 50824)
+ 0x61f6, 0,
+#undef V13289
+#define V13289 (V + 50826)
+ 0x7669, 0,
+#undef V13290
+#define V13290 (V + 50828)
+ 0x7f85, 0,
+#undef V13291
+#define V13291 (V + 50830)
+ 0x863f, 0,
+#undef V13292
+#define V13292 (V + 50832)
+ 0x87ba, 0,
+#undef V13293
+#define V13293 (V + 50834)
+ 0x88f8, 0,
+#undef V13294
+#define V13294 (V + 50836)
+ 0x908f, 0,
+#undef V13295
+#define V13295 (V + 50838)
+ 0x6a02, 0,
+#undef V13296
+#define V13296 (V + 50840)
+ 0x6d1b, 0,
+#undef V13297
+#define V13297 (V + 50842)
+ 0x70d9, 0,
+#undef V13298
+#define V13298 (V + 50844)
+ 0x73de, 0,
+#undef V13299
+#define V13299 (V + 50846)
+ 0x843d, 0,
+#undef V13300
+#define V13300 (V + 50848)
+ 0x916a, 0,
+#undef V13301
+#define V13301 (V + 50850)
+ 0x99f1, 0,
+#undef V13302
+#define V13302 (V + 50852)
+ 0x4e82, 0,
+#undef V13303
+#define V13303 (V + 50854)
+ 0x5375, 0,
+#undef V13304
+#define V13304 (V + 50856)
+ 0x6b04, 0,
+#undef V13305
+#define V13305 (V + 50858)
+ 0x721b, 0,
+#undef V13306
+#define V13306 (V + 50860)
+ 0x862d, 0,
+#undef V13307
+#define V13307 (V + 50862)
+ 0x9e1e, 0,
+#undef V13308
+#define V13308 (V + 50864)
+ 0x5d50, 0,
+#undef V13309
+#define V13309 (V + 50866)
+ 0x6feb, 0,
+#undef V13310
+#define V13310 (V + 50868)
+ 0x85cd, 0,
+#undef V13311
+#define V13311 (V + 50870)
+ 0x8964, 0,
+#undef V13312
+#define V13312 (V + 50872)
+ 0x62c9, 0,
+#undef V13313
+#define V13313 (V + 50874)
+ 0x81d8, 0,
+#undef V13314
+#define V13314 (V + 50876)
+ 0x881f, 0,
+#undef V13315
+#define V13315 (V + 50878)
+ 0x5eca, 0,
+#undef V13316
+#define V13316 (V + 50880)
+ 0x6717, 0,
+#undef V13317
+#define V13317 (V + 50882)
+ 0x6d6a, 0,
+#undef V13318
+#define V13318 (V + 50884)
+ 0x72fc, 0,
+#undef V13319
+#define V13319 (V + 50886)
+ 0x90ce, 0,
+#undef V13320
+#define V13320 (V + 50888)
+ 0x4f86, 0,
+#undef V13321
+#define V13321 (V + 50890)
+ 0x51b7, 0,
+#undef V13322
+#define V13322 (V + 50892)
+ 0x52de, 0,
+#undef V13323
+#define V13323 (V + 50894)
+ 0x64c4, 0,
+#undef V13324
+#define V13324 (V + 50896)
+ 0x6ad3, 0,
+#undef V13325
+#define V13325 (V + 50898)
+ 0x7210, 0,
+#undef V13326
+#define V13326 (V + 50900)
+ 0x76e7, 0,
+#undef V13327
+#define V13327 (V + 50902)
+ 0x8606, 0,
+#undef V13328
+#define V13328 (V + 50904)
+ 0x865c, 0,
+#undef V13329
+#define V13329 (V + 50906)
+ 0x8def, 0,
+#undef V13330
+#define V13330 (V + 50908)
+ 0x9732, 0,
+#undef V13331
+#define V13331 (V + 50910)
+ 0x9b6f, 0,
+#undef V13332
+#define V13332 (V + 50912)
+ 0x9dfa, 0,
+#undef V13333
+#define V13333 (V + 50914)
+ 0x788c, 0,
+#undef V13334
+#define V13334 (V + 50916)
+ 0x797f, 0,
+#undef V13335
+#define V13335 (V + 50918)
+ 0x7da0, 0,
+#undef V13336
+#define V13336 (V + 50920)
+ 0x83c9, 0,
+#undef V13337
+#define V13337 (V + 50922)
+ 0x9304, 0,
+#undef V13338
+#define V13338 (V + 50924)
+ 0x8ad6, 0,
+#undef V13339
+#define V13339 (V + 50926)
+ 0x58df, 0,
+#undef V13340
+#define V13340 (V + 50928)
+ 0x5f04, 0,
+#undef V13341
+#define V13341 (V + 50930)
+ 0x7c60, 0,
+#undef V13342
+#define V13342 (V + 50932)
+ 0x807e, 0,
+#undef V13343
+#define V13343 (V + 50934)
+ 0x7262, 0,
+#undef V13344
+#define V13344 (V + 50936)
+ 0x78ca, 0,
+#undef V13345
+#define V13345 (V + 50938)
+ 0x8cc2, 0,
+#undef V13346
+#define V13346 (V + 50940)
+ 0x96f7, 0,
+#undef V13347
+#define V13347 (V + 50942)
+ 0x58d8, 0,
+#undef V13348
+#define V13348 (V + 50944)
+ 0x5c62, 0,
+#undef V13349
+#define V13349 (V + 50946)
+ 0x6a13, 0,
+#undef V13350
+#define V13350 (V + 50948)
+ 0x6dda, 0,
+#undef V13351
+#define V13351 (V + 50950)
+ 0x6f0f, 0,
+#undef V13352
+#define V13352 (V + 50952)
+ 0x7d2f, 0,
+#undef V13353
+#define V13353 (V + 50954)
+ 0x7e37, 0,
+#undef V13354
+#define V13354 (V + 50956)
+ 0x964b, 0,
+#undef V13355
+#define V13355 (V + 50958)
+ 0x52d2, 0,
+#undef V13356
+#define V13356 (V + 50960)
+ 0x808b, 0,
+#undef V13357
+#define V13357 (V + 50962)
+ 0x51dc, 0,
+#undef V13358
+#define V13358 (V + 50964)
+ 0x51cc, 0,
+#undef V13359
+#define V13359 (V + 50966)
+ 0x7a1c, 0,
+#undef V13360
+#define V13360 (V + 50968)
+ 0x7dbe, 0,
+#undef V13361
+#define V13361 (V + 50970)
+ 0x83f1, 0,
+#undef V13362
+#define V13362 (V + 50972)
+ 0x9675, 0,
+#undef V13363
+#define V13363 (V + 50974)
+ 0x8b80, 0,
+#undef V13364
+#define V13364 (V + 50976)
+ 0x62cf, 0,
+#undef V13365
+#define V13365 (V + 50978)
+ 0x8afe, 0,
+#undef V13366
+#define V13366 (V + 50980)
+ 0x4e39, 0,
+#undef V13367
+#define V13367 (V + 50982)
+ 0x5be7, 0,
+#undef V13368
+#define V13368 (V + 50984)
+ 0x6012, 0,
+#undef V13369
+#define V13369 (V + 50986)
+ 0x7387, 0,
+#undef V13370
+#define V13370 (V + 50988)
+ 0x7570, 0,
+#undef V13371
+#define V13371 (V + 50990)
+ 0x5317, 0,
+#undef V13372
+#define V13372 (V + 50992)
+ 0x78fb, 0,
+#undef V13373
+#define V13373 (V + 50994)
+ 0x4fbf, 0,
+#undef V13374
+#define V13374 (V + 50996)
+ 0x5fa9, 0,
+#undef V13375
+#define V13375 (V + 50998)
+ 0x4e0d, 0,
+#undef V13376
+#define V13376 (V + 51000)
+ 0x6ccc, 0,
+#undef V13377
+#define V13377 (V + 51002)
+ 0x6578, 0,
+#undef V13378
+#define V13378 (V + 51004)
+ 0x7d22, 0,
+#undef V13379
+#define V13379 (V + 51006)
+ 0x53c3, 0,
+#undef V13380
+#define V13380 (V + 51008)
+ 0x585e, 0,
+#undef V13381
+#define V13381 (V + 51010)
+ 0x7701, 0,
+#undef V13382
+#define V13382 (V + 51012)
+ 0x8449, 0,
+#undef V13383
+#define V13383 (V + 51014)
+ 0x8aaa, 0,
+#undef V13384
+#define V13384 (V + 51016)
+ 0x6bba, 0,
+#undef V13385
+#define V13385 (V + 51018)
+ 0x6c88, 0,
+#undef V13386
+#define V13386 (V + 51020)
+ 0x62fe, 0,
+#undef V13387
+#define V13387 (V + 51022)
+ 0x82e5, 0,
+#undef V13388
+#define V13388 (V + 51024)
+ 0x63a0, 0,
+#undef V13389
+#define V13389 (V + 51026)
+ 0x7565, 0,
+#undef V13390
+#define V13390 (V + 51028)
+ 0x4eae, 0,
+#undef V13391
+#define V13391 (V + 51030)
+ 0x5169, 0,
+#undef V13392
+#define V13392 (V + 51032)
+ 0x51c9, 0,
+#undef V13393
+#define V13393 (V + 51034)
+ 0x6881, 0,
+#undef V13394
+#define V13394 (V + 51036)
+ 0x7ce7, 0,
+#undef V13395
+#define V13395 (V + 51038)
+ 0x826f, 0,
+#undef V13396
+#define V13396 (V + 51040)
+ 0x8ad2, 0,
+#undef V13397
+#define V13397 (V + 51042)
+ 0x91cf, 0,
+#undef V13398
+#define V13398 (V + 51044)
+ 0x52f5, 0,
+#undef V13399
+#define V13399 (V + 51046)
+ 0x5442, 0,
+#undef V13400
+#define V13400 (V + 51048)
+ 0x5eec, 0,
+#undef V13401
+#define V13401 (V + 51050)
+ 0x65c5, 0,
+#undef V13402
+#define V13402 (V + 51052)
+ 0x6ffe, 0,
+#undef V13403
+#define V13403 (V + 51054)
+ 0x792a, 0,
+#undef V13404
+#define V13404 (V + 51056)
+ 0x95ad, 0,
+#undef V13405
+#define V13405 (V + 51058)
+ 0x9a6a, 0,
+#undef V13406
+#define V13406 (V + 51060)
+ 0x9e97, 0,
+#undef V13407
+#define V13407 (V + 51062)
+ 0x9ece, 0,
+#undef V13408
+#define V13408 (V + 51064)
+ 0x66c6, 0,
+#undef V13409
+#define V13409 (V + 51066)
+ 0x6b77, 0,
+#undef V13410
+#define V13410 (V + 51068)
+ 0x8f62, 0,
+#undef V13411
+#define V13411 (V + 51070)
+ 0x5e74, 0,
+#undef V13412
+#define V13412 (V + 51072)
+ 0x6190, 0,
+#undef V13413
+#define V13413 (V + 51074)
+ 0x6200, 0,
+#undef V13414
+#define V13414 (V + 51076)
+ 0x649a, 0,
+#undef V13415
+#define V13415 (V + 51078)
+ 0x6f23, 0,
+#undef V13416
+#define V13416 (V + 51080)
+ 0x7149, 0,
+#undef V13417
+#define V13417 (V + 51082)
+ 0x7489, 0,
+#undef V13418
+#define V13418 (V + 51084)
+ 0x79ca, 0,
+#undef V13419
+#define V13419 (V + 51086)
+ 0x7df4, 0,
+#undef V13420
+#define V13420 (V + 51088)
+ 0x806f, 0,
+#undef V13421
+#define V13421 (V + 51090)
+ 0x8f26, 0,
+#undef V13422
+#define V13422 (V + 51092)
+ 0x84ee, 0,
+#undef V13423
+#define V13423 (V + 51094)
+ 0x9023, 0,
+#undef V13424
+#define V13424 (V + 51096)
+ 0x934a, 0,
+#undef V13425
+#define V13425 (V + 51098)
+ 0x5217, 0,
+#undef V13426
+#define V13426 (V + 51100)
+ 0x52a3, 0,
+#undef V13427
+#define V13427 (V + 51102)
+ 0x54bd, 0,
+#undef V13428
+#define V13428 (V + 51104)
+ 0x70c8, 0,
+#undef V13429
+#define V13429 (V + 51106)
+ 0x88c2, 0,
+#undef V13430
+#define V13430 (V + 51108)
+ 0x5ec9, 0,
+#undef V13431
+#define V13431 (V + 51110)
+ 0x5ff5, 0,
+#undef V13432
+#define V13432 (V + 51112)
+ 0x637b, 0,
+#undef V13433
+#define V13433 (V + 51114)
+ 0x6bae, 0,
+#undef V13434
+#define V13434 (V + 51116)
+ 0x7c3e, 0,
+#undef V13435
+#define V13435 (V + 51118)
+ 0x7375, 0,
+#undef V13436
+#define V13436 (V + 51120)
+ 0x4ee4, 0,
+#undef V13437
+#define V13437 (V + 51122)
+ 0x56f9, 0,
+#undef V13438
+#define V13438 (V + 51124)
+ 0x5dba, 0,
+#undef V13439
+#define V13439 (V + 51126)
+ 0x601c, 0,
+#undef V13440
+#define V13440 (V + 51128)
+ 0x73b2, 0,
+#undef V13441
+#define V13441 (V + 51130)
+ 0x7469, 0,
+#undef V13442
+#define V13442 (V + 51132)
+ 0x7f9a, 0,
+#undef V13443
+#define V13443 (V + 51134)
+ 0x8046, 0,
+#undef V13444
+#define V13444 (V + 51136)
+ 0x9234, 0,
+#undef V13445
+#define V13445 (V + 51138)
+ 0x96f6, 0,
+#undef V13446
+#define V13446 (V + 51140)
+ 0x9748, 0,
+#undef V13447
+#define V13447 (V + 51142)
+ 0x9818, 0,
+#undef V13448
+#define V13448 (V + 51144)
+ 0x4f8b, 0,
+#undef V13449
+#define V13449 (V + 51146)
+ 0x79ae, 0,
+#undef V13450
+#define V13450 (V + 51148)
+ 0x91b4, 0,
+#undef V13451
+#define V13451 (V + 51150)
+ 0x96b8, 0,
+#undef V13452
+#define V13452 (V + 51152)
+ 0x60e1, 0,
+#undef V13453
+#define V13453 (V + 51154)
+ 0x4e86, 0,
+#undef V13454
+#define V13454 (V + 51156)
+ 0x50da, 0,
+#undef V13455
+#define V13455 (V + 51158)
+ 0x5bee, 0,
+#undef V13456
+#define V13456 (V + 51160)
+ 0x5c3f, 0,
+#undef V13457
+#define V13457 (V + 51162)
+ 0x6599, 0,
+#undef V13458
+#define V13458 (V + 51164)
+ 0x71ce, 0,
+#undef V13459
+#define V13459 (V + 51166)
+ 0x7642, 0,
+#undef V13460
+#define V13460 (V + 51168)
+ 0x84fc, 0,
+#undef V13461
+#define V13461 (V + 51170)
+ 0x907c, 0,
+#undef V13462
+#define V13462 (V + 51172)
+ 0x6688, 0,
+#undef V13463
+#define V13463 (V + 51174)
+ 0x962e, 0,
+#undef V13464
+#define V13464 (V + 51176)
+ 0x5289, 0,
+#undef V13465
+#define V13465 (V + 51178)
+ 0x677b, 0,
+#undef V13466
+#define V13466 (V + 51180)
+ 0x67f3, 0,
+#undef V13467
+#define V13467 (V + 51182)
+ 0x6d41, 0,
+#undef V13468
+#define V13468 (V + 51184)
+ 0x6e9c, 0,
+#undef V13469
+#define V13469 (V + 51186)
+ 0x7409, 0,
+#undef V13470
+#define V13470 (V + 51188)
+ 0x7559, 0,
+#undef V13471
+#define V13471 (V + 51190)
+ 0x786b, 0,
+#undef V13472
+#define V13472 (V + 51192)
+ 0x7d10, 0,
+#undef V13473
+#define V13473 (V + 51194)
+ 0x985e, 0,
+#undef V13474
+#define V13474 (V + 51196)
+ 0x622e, 0,
+#undef V13475
+#define V13475 (V + 51198)
+ 0x9678, 0,
+#undef V13476
+#define V13476 (V + 51200)
+ 0x502b, 0,
+#undef V13477
+#define V13477 (V + 51202)
+ 0x5d19, 0,
+#undef V13478
+#define V13478 (V + 51204)
+ 0x6dea, 0,
+#undef V13479
+#define V13479 (V + 51206)
+ 0x8f2a, 0,
+#undef V13480
+#define V13480 (V + 51208)
+ 0x5f8b, 0,
+#undef V13481
+#define V13481 (V + 51210)
+ 0x6144, 0,
+#undef V13482
+#define V13482 (V + 51212)
+ 0x6817, 0,
+#undef V13483
+#define V13483 (V + 51214)
+ 0x9686, 0,
+#undef V13484
+#define V13484 (V + 51216)
+ 0x5229, 0,
+#undef V13485
+#define V13485 (V + 51218)
+ 0x540f, 0,
+#undef V13486
+#define V13486 (V + 51220)
+ 0x5c65, 0,
+#undef V13487
+#define V13487 (V + 51222)
+ 0x6613, 0,
+#undef V13488
+#define V13488 (V + 51224)
+ 0x674e, 0,
+#undef V13489
+#define V13489 (V + 51226)
+ 0x68a8, 0,
+#undef V13490
+#define V13490 (V + 51228)
+ 0x6ce5, 0,
+#undef V13491
+#define V13491 (V + 51230)
+ 0x7406, 0,
+#undef V13492
+#define V13492 (V + 51232)
+ 0x75e2, 0,
+#undef V13493
+#define V13493 (V + 51234)
+ 0x7f79, 0,
+#undef V13494
+#define V13494 (V + 51236)
+ 0x88cf, 0,
+#undef V13495
+#define V13495 (V + 51238)
+ 0x88e1, 0,
+#undef V13496
+#define V13496 (V + 51240)
+ 0x96e2, 0,
+#undef V13497
+#define V13497 (V + 51242)
+ 0x533f, 0,
+#undef V13498
+#define V13498 (V + 51244)
+ 0x6eba, 0,
+#undef V13499
+#define V13499 (V + 51246)
+ 0x541d, 0,
+#undef V13500
+#define V13500 (V + 51248)
+ 0x71d0, 0,
+#undef V13501
+#define V13501 (V + 51250)
+ 0x7498, 0,
+#undef V13502
+#define V13502 (V + 51252)
+ 0x85fa, 0,
+#undef V13503
+#define V13503 (V + 51254)
+ 0x96a3, 0,
+#undef V13504
+#define V13504 (V + 51256)
+ 0x9c57, 0,
+#undef V13505
+#define V13505 (V + 51258)
+ 0x9e9f, 0,
+#undef V13506
+#define V13506 (V + 51260)
+ 0x6797, 0,
+#undef V13507
+#define V13507 (V + 51262)
+ 0x6dcb, 0,
+#undef V13508
+#define V13508 (V + 51264)
+ 0x81e8, 0,
+#undef V13509
+#define V13509 (V + 51266)
+ 0x7b20, 0,
+#undef V13510
+#define V13510 (V + 51268)
+ 0x7c92, 0,
+#undef V13511
+#define V13511 (V + 51270)
+ 0x72c0, 0,
+#undef V13512
+#define V13512 (V + 51272)
+ 0x7099, 0,
+#undef V13513
+#define V13513 (V + 51274)
+ 0x8b58, 0,
+#undef V13514
+#define V13514 (V + 51276)
+ 0x4ec0, 0,
+#undef V13515
+#define V13515 (V + 51278)
+ 0x8336, 0,
+#undef V13516
+#define V13516 (V + 51280)
+ 0x523a, 0,
+#undef V13517
+#define V13517 (V + 51282)
+ 0x5207, 0,
+#undef V13518
+#define V13518 (V + 51284)
+ 0x5ea6, 0,
+#undef V13519
+#define V13519 (V + 51286)
+ 0x62d3, 0,
+#undef V13520
+#define V13520 (V + 51288)
+ 0x7cd6, 0,
+#undef V13521
+#define V13521 (V + 51290)
+ 0x5b85, 0,
+#undef V13522
+#define V13522 (V + 51292)
+ 0x6d1e, 0,
+#undef V13523
+#define V13523 (V + 51294)
+ 0x66b4, 0,
+#undef V13524
+#define V13524 (V + 51296)
+ 0x8f3b, 0,
+#undef V13525
+#define V13525 (V + 51298)
+ 0x964d, 0,
+#undef V13526
+#define V13526 (V + 51300)
+ 0x5ed3, 0,
+#undef V13527
+#define V13527 (V + 51302)
+ 0x5140, 0,
+#undef V13528
+#define V13528 (V + 51304)
+ 0x55c0, 0,
+#undef V13529
+#define V13529 (V + 51306)
+ 0x585a, 0,
+#undef V13530
+#define V13530 (V + 51308)
+ 0x6674, 0,
+#undef V13531
+#define V13531 (V + 51310)
+ 0x51de, 0,
+#undef V13532
+#define V13532 (V + 51312)
+ 0x732a, 0,
+#undef V13533
+#define V13533 (V + 51314)
+ 0x76ca, 0,
+#undef V13534
+#define V13534 (V + 51316)
+ 0x793c, 0,
+#undef V13535
+#define V13535 (V + 51318)
+ 0x795e, 0,
+#undef V13536
+#define V13536 (V + 51320)
+ 0x7965, 0,
+#undef V13537
+#define V13537 (V + 51322)
+ 0x798f, 0,
+#undef V13538
+#define V13538 (V + 51324)
+ 0x9756, 0,
+#undef V13539
+#define V13539 (V + 51326)
+ 0x7cbe, 0,
+#undef V13540
+#define V13540 (V + 51328)
+ 0x8612, 0,
+#undef V13541
+#define V13541 (V + 51330)
+ 0x8af8, 0,
+#undef V13542
+#define V13542 (V + 51332)
+ 0x9038, 0,
+#undef V13543
+#define V13543 (V + 51334)
+ 0x90fd, 0,
+#undef V13544
+#define V13544 (V + 51336)
+ 0x98ef, 0,
+#undef V13545
+#define V13545 (V + 51338)
+ 0x98fc, 0,
+#undef V13546
+#define V13546 (V + 51340)
+ 0x9928, 0,
+#undef V13547
+#define V13547 (V + 51342)
+ 0x9db4, 0,
+#undef V13548
+#define V13548 (V + 51344)
+ 0x90de, 0,
+#undef V13549
+#define V13549 (V + 51346)
+ 0x96b7, 0,
+#undef V13550
+#define V13550 (V + 51348)
+ 0x4fae, 0,
+#undef V13551
+#define V13551 (V + 51350)
+ 0x50e7, 0,
+#undef V13552
+#define V13552 (V + 51352)
+ 0x514d, 0,
+#undef V13553
+#define V13553 (V + 51354)
+ 0x52c9, 0,
+#undef V13554
+#define V13554 (V + 51356)
+ 0x52e4, 0,
+#undef V13555
+#define V13555 (V + 51358)
+ 0x5351, 0,
+#undef V13556
+#define V13556 (V + 51360)
+ 0x559d, 0,
+#undef V13557
+#define V13557 (V + 51362)
+ 0x5606, 0,
+#undef V13558
+#define V13558 (V + 51364)
+ 0x5668, 0,
+#undef V13559
+#define V13559 (V + 51366)
+ 0x5840, 0,
+#undef V13560
+#define V13560 (V + 51368)
+ 0x58a8, 0,
+#undef V13561
+#define V13561 (V + 51370)
+ 0x5c64, 0,
+#undef V13562
+#define V13562 (V + 51372)
+ 0x6094, 0,
+#undef V13563
+#define V13563 (V + 51374)
+ 0x6168, 0,
+#undef V13564
+#define V13564 (V + 51376)
+ 0x618e, 0,
+#undef V13565
+#define V13565 (V + 51378)
+ 0x61f2, 0,
+#undef V13566
+#define V13566 (V + 51380)
+ 0x654f, 0,
+#undef V13567
+#define V13567 (V + 51382)
+ 0x65e2, 0,
+#undef V13568
+#define V13568 (V + 51384)
+ 0x6691, 0,
+#undef V13569
+#define V13569 (V + 51386)
+ 0x6885, 0,
+#undef V13570
+#define V13570 (V + 51388)
+ 0x6d77, 0,
+#undef V13571
+#define V13571 (V + 51390)
+ 0x6e1a, 0,
+#undef V13572
+#define V13572 (V + 51392)
+ 0x6f22, 0,
+#undef V13573
+#define V13573 (V + 51394)
+ 0x716e, 0,
+#undef V13574
+#define V13574 (V + 51396)
+ 0x722b, 0,
+#undef V13575
+#define V13575 (V + 51398)
+ 0x7422, 0,
+#undef V13576
+#define V13576 (V + 51400)
+ 0x7891, 0,
+#undef V13577
+#define V13577 (V + 51402)
+ 0x7949, 0,
+#undef V13578
+#define V13578 (V + 51404)
+ 0x7948, 0,
+#undef V13579
+#define V13579 (V + 51406)
+ 0x7950, 0,
+#undef V13580
+#define V13580 (V + 51408)
+ 0x7956, 0,
+#undef V13581
+#define V13581 (V + 51410)
+ 0x798d, 0,
+#undef V13582
+#define V13582 (V + 51412)
+ 0x798e, 0,
+#undef V13583
+#define V13583 (V + 51414)
+ 0x7a40, 0,
+#undef V13584
+#define V13584 (V + 51416)
+ 0x7a81, 0,
+#undef V13585
+#define V13585 (V + 51418)
+ 0x7bc0, 0,
+#undef V13586
+#define V13586 (V + 51420)
+ 0x7e09, 0,
+#undef V13587
+#define V13587 (V + 51422)
+ 0x7e41, 0,
+#undef V13588
+#define V13588 (V + 51424)
+ 0x7f72, 0,
+#undef V13589
+#define V13589 (V + 51426)
+ 0x8005, 0,
+#undef V13590
+#define V13590 (V + 51428)
+ 0x81ed, 0,
+#undef V13591
+#define V13591 (V + 51430)
+ 0x8279, 0,
+#undef V13592
+#define V13592 (V + 51432)
+ 0x8457, 0,
+#undef V13593
+#define V13593 (V + 51434)
+ 0x8910, 0,
+#undef V13594
+#define V13594 (V + 51436)
+ 0x8996, 0,
+#undef V13595
+#define V13595 (V + 51438)
+ 0x8b01, 0,
+#undef V13596
+#define V13596 (V + 51440)
+ 0x8b39, 0,
+#undef V13597
+#define V13597 (V + 51442)
+ 0x8cd3, 0,
+#undef V13598
+#define V13598 (V + 51444)
+ 0x8d08, 0,
+#undef V13599
+#define V13599 (V + 51446)
+ 0x8fb6, 0,
+#undef V13600
+#define V13600 (V + 51448)
+ 0x96e3, 0,
+#undef V13601
+#define V13601 (V + 51450)
+ 0x97ff, 0,
+#undef V13602
+#define V13602 (V + 51452)
+ 0x983b, 0,
+#undef V13603
+#define V13603 (V + 51454)
+ 0x6075, 0,
+#undef V13604
+#define V13604 (V + 51456)
+ 0x242ee, 0,
+#undef V13605
+#define V13605 (V + 51458)
+ 0x8218, 0,
+#undef V13606
+#define V13606 (V + 51460)
+ 0x4e26, 0,
+#undef V13607
+#define V13607 (V + 51462)
+ 0x51b5, 0,
+#undef V13608
+#define V13608 (V + 51464)
+ 0x5168, 0,
+#undef V13609
+#define V13609 (V + 51466)
+ 0x4f80, 0,
+#undef V13610
+#define V13610 (V + 51468)
+ 0x5145, 0,
+#undef V13611
+#define V13611 (V + 51470)
+ 0x5180, 0,
+#undef V13612
+#define V13612 (V + 51472)
+ 0x52c7, 0,
+#undef V13613
+#define V13613 (V + 51474)
+ 0x52fa, 0,
+#undef V13614
+#define V13614 (V + 51476)
+ 0x5555, 0,
+#undef V13615
+#define V13615 (V + 51478)
+ 0x5599, 0,
+#undef V13616
+#define V13616 (V + 51480)
+ 0x55e2, 0,
+#undef V13617
+#define V13617 (V + 51482)
+ 0x58b3, 0,
+#undef V13618
+#define V13618 (V + 51484)
+ 0x5944, 0,
+#undef V13619
+#define V13619 (V + 51486)
+ 0x5954, 0,
+#undef V13620
+#define V13620 (V + 51488)
+ 0x5a62, 0,
+#undef V13621
+#define V13621 (V + 51490)
+ 0x5b28, 0,
+#undef V13622
+#define V13622 (V + 51492)
+ 0x5ed2, 0,
+#undef V13623
+#define V13623 (V + 51494)
+ 0x5ed9, 0,
+#undef V13624
+#define V13624 (V + 51496)
+ 0x5f69, 0,
+#undef V13625
+#define V13625 (V + 51498)
+ 0x5fad, 0,
+#undef V13626
+#define V13626 (V + 51500)
+ 0x60d8, 0,
+#undef V13627
+#define V13627 (V + 51502)
+ 0x614e, 0,
+#undef V13628
+#define V13628 (V + 51504)
+ 0x6108, 0,
+#undef V13629
+#define V13629 (V + 51506)
+ 0x6160, 0,
+#undef V13630
+#define V13630 (V + 51508)
+ 0x6234, 0,
+#undef V13631
+#define V13631 (V + 51510)
+ 0x63c4, 0,
+#undef V13632
+#define V13632 (V + 51512)
+ 0x641c, 0,
+#undef V13633
+#define V13633 (V + 51514)
+ 0x6452, 0,
+#undef V13634
+#define V13634 (V + 51516)
+ 0x6556, 0,
+#undef V13635
+#define V13635 (V + 51518)
+ 0x671b, 0,
+#undef V13636
+#define V13636 (V + 51520)
+ 0x6756, 0,
+#undef V13637
+#define V13637 (V + 51522)
+ 0x6edb, 0,
+#undef V13638
+#define V13638 (V + 51524)
+ 0x6ecb, 0,
+#undef V13639
+#define V13639 (V + 51526)
+ 0x701e, 0,
+#undef V13640
+#define V13640 (V + 51528)
+ 0x77a7, 0,
+#undef V13641
+#define V13641 (V + 51530)
+ 0x7235, 0,
+#undef V13642
+#define V13642 (V + 51532)
+ 0x72af, 0,
+#undef V13643
+#define V13643 (V + 51534)
+ 0x7471, 0,
+#undef V13644
+#define V13644 (V + 51536)
+ 0x7506, 0,
+#undef V13645
+#define V13645 (V + 51538)
+ 0x753b, 0,
+#undef V13646
+#define V13646 (V + 51540)
+ 0x761d, 0,
+#undef V13647
+#define V13647 (V + 51542)
+ 0x761f, 0,
+#undef V13648
+#define V13648 (V + 51544)
+ 0x76db, 0,
+#undef V13649
+#define V13649 (V + 51546)
+ 0x76f4, 0,
+#undef V13650
+#define V13650 (V + 51548)
+ 0x774a, 0,
+#undef V13651
+#define V13651 (V + 51550)
+ 0x7740, 0,
+#undef V13652
+#define V13652 (V + 51552)
+ 0x78cc, 0,
+#undef V13653
+#define V13653 (V + 51554)
+ 0x7ab1, 0,
+#undef V13654
+#define V13654 (V + 51556)
+ 0x7c7b, 0,
+#undef V13655
+#define V13655 (V + 51558)
+ 0x7d5b, 0,
+#undef V13656
+#define V13656 (V + 51560)
+ 0x7f3e, 0,
+#undef V13657
+#define V13657 (V + 51562)
+ 0x8352, 0,
+#undef V13658
+#define V13658 (V + 51564)
+ 0x83ef, 0,
+#undef V13659
+#define V13659 (V + 51566)
+ 0x8779, 0,
+#undef V13660
+#define V13660 (V + 51568)
+ 0x8941, 0,
+#undef V13661
+#define V13661 (V + 51570)
+ 0x8986, 0,
+#undef V13662
+#define V13662 (V + 51572)
+ 0x8abf, 0,
+#undef V13663
+#define V13663 (V + 51574)
+ 0x8acb, 0,
+#undef V13664
+#define V13664 (V + 51576)
+ 0x8aed, 0,
+#undef V13665
+#define V13665 (V + 51578)
+ 0x8b8a, 0,
+#undef V13666
+#define V13666 (V + 51580)
+ 0x8f38, 0,
+#undef V13667
+#define V13667 (V + 51582)
+ 0x9072, 0,
+#undef V13668
+#define V13668 (V + 51584)
+ 0x9199, 0,
+#undef V13669
+#define V13669 (V + 51586)
+ 0x9276, 0,
+#undef V13670
+#define V13670 (V + 51588)
+ 0x967c, 0,
+#undef V13671
+#define V13671 (V + 51590)
+ 0x97db, 0,
+#undef V13672
+#define V13672 (V + 51592)
+ 0x980b, 0,
+#undef V13673
+#define V13673 (V + 51594)
+ 0x9b12, 0,
+#undef V13674
+#define V13674 (V + 51596)
+ 0x2284a, 0,
+#undef V13675
+#define V13675 (V + 51598)
+ 0x22844, 0,
+#undef V13676
+#define V13676 (V + 51600)
+ 0x233d5, 0,
+#undef V13677
+#define V13677 (V + 51602)
+ 0x3b9d, 0,
+#undef V13678
+#define V13678 (V + 51604)
+ 0x4018, 0,
+#undef V13679
+#define V13679 (V + 51606)
+ 0x4039, 0,
+#undef V13680
+#define V13680 (V + 51608)
+ 0x25249, 0,
+#undef V13681
+#define V13681 (V + 51610)
+ 0x25cd0, 0,
+#undef V13682
+#define V13682 (V + 51612)
+ 0x27ed3, 0,
+#undef V13683
+#define V13683 (V + 51614)
+ 0x9f43, 0,
+#undef V13684
+#define V13684 (V + 51616)
+ 0x9f8e, 0,
+#undef V13685
+#define V13685 (V + 51618)
+ 0x66, 0x66, 0,
+#undef V13686
+#define V13686 (V + 51621)
+ 0x66, 0x69, 0,
+#undef V13687
+#define V13687 (V + 51624)
+ 0x66, 0x6c, 0,
+#undef V13688
+#define V13688 (V + 51627)
+ 0x66, 0x66, 0x69, 0,
+#undef V13689
+#define V13689 (V + 51631)
+ 0x66, 0x66, 0x6c, 0,
+#undef V13690
+#define V13690 (V + 51635)
+ 0x73, 0x74, 0,
+#undef V13691
+#define V13691 (V + 51638)
+ 0x574, 0x576, 0,
+#undef V13692
+#define V13692 (V + 51641)
+ 0x574, 0x565, 0,
+#undef V13693
+#define V13693 (V + 51644)
+ 0x574, 0x56b, 0,
+#undef V13694
+#define V13694 (V + 51647)
+ 0x57e, 0x576, 0,
+#undef V13695
+#define V13695 (V + 51650)
+ 0x574, 0x56d, 0,
+#undef V13696
+#define V13696 (V + 51653)
+ 0x5d9, 0x5b4, 0,
+#undef V13697
+#define V13697 (V + 51656)
+ 0x5f2, 0x5b7, 0,
+#undef V13698
+#define V13698 (V + 51659)
+ 0x5e2, 0,
+#undef V13699
+#define V13699 (V + 51661)
+ 0x5d4, 0,
+#undef V13700
+#define V13700 (V + 51663)
+ 0x5db, 0,
+#undef V13701
+#define V13701 (V + 51665)
+ 0x5dc, 0,
+#undef V13702
+#define V13702 (V + 51667)
+ 0x5dd, 0,
+#undef V13703
+#define V13703 (V + 51669)
+ 0x5e8, 0,
+#undef V13704
+#define V13704 (V + 51671)
+ 0x5ea, 0,
+#undef V13705
+#define V13705 (V + 51673)
+ 0x5e9, 0x5c1, 0,
+#undef V13706
+#define V13706 (V + 51676)
+ 0x5e9, 0x5c2, 0,
+#undef V13707
+#define V13707 (V + 51679)
+ 0x5e9, 0x5bc, 0x5c1, 0,
+#undef V13708
+#define V13708 (V + 51683)
+ 0x5e9, 0x5bc, 0x5c2, 0,
+#undef V13709
+#define V13709 (V + 51687)
+ 0x5d0, 0x5b7, 0,
+#undef V13710
+#define V13710 (V + 51690)
+ 0x5d0, 0x5b8, 0,
+#undef V13711
+#define V13711 (V + 51693)
+ 0x5d0, 0x5bc, 0,
+#undef V13712
+#define V13712 (V + 51696)
+ 0x5d1, 0x5bc, 0,
+#undef V13713
+#define V13713 (V + 51699)
+ 0x5d2, 0x5bc, 0,
+#undef V13714
+#define V13714 (V + 51702)
+ 0x5d3, 0x5bc, 0,
+#undef V13715
+#define V13715 (V + 51705)
+ 0x5d4, 0x5bc, 0,
+#undef V13716
+#define V13716 (V + 51708)
+ 0x5d5, 0x5bc, 0,
+#undef V13717
+#define V13717 (V + 51711)
+ 0x5d6, 0x5bc, 0,
+#undef V13718
+#define V13718 (V + 51714)
+ 0x5d8, 0x5bc, 0,
+#undef V13719
+#define V13719 (V + 51717)
+ 0x5d9, 0x5bc, 0,
+#undef V13720
+#define V13720 (V + 51720)
+ 0x5da, 0x5bc, 0,
+#undef V13721
+#define V13721 (V + 51723)
+ 0x5db, 0x5bc, 0,
+#undef V13722
+#define V13722 (V + 51726)
+ 0x5dc, 0x5bc, 0,
+#undef V13723
+#define V13723 (V + 51729)
+ 0x5de, 0x5bc, 0,
+#undef V13724
+#define V13724 (V + 51732)
+ 0x5e0, 0x5bc, 0,
+#undef V13725
+#define V13725 (V + 51735)
+ 0x5e1, 0x5bc, 0,
+#undef V13726
+#define V13726 (V + 51738)
+ 0x5e3, 0x5bc, 0,
+#undef V13727
+#define V13727 (V + 51741)
+ 0x5e4, 0x5bc, 0,
+#undef V13728
+#define V13728 (V + 51744)
+ 0x5e6, 0x5bc, 0,
+#undef V13729
+#define V13729 (V + 51747)
+ 0x5e7, 0x5bc, 0,
+#undef V13730
+#define V13730 (V + 51750)
+ 0x5e8, 0x5bc, 0,
+#undef V13731
+#define V13731 (V + 51753)
+ 0x5e9, 0x5bc, 0,
+#undef V13732
+#define V13732 (V + 51756)
+ 0x5ea, 0x5bc, 0,
+#undef V13733
+#define V13733 (V + 51759)
+ 0x5d5, 0x5b9, 0,
+#undef V13734
+#define V13734 (V + 51762)
+ 0x5d1, 0x5bf, 0,
+#undef V13735
+#define V13735 (V + 51765)
+ 0x5db, 0x5bf, 0,
+#undef V13736
+#define V13736 (V + 51768)
+ 0x5e4, 0x5bf, 0,
+#undef V13737
+#define V13737 (V + 51771)
+ 0x5d0, 0x5dc, 0,
+#undef V13738
+#define V13738 (V + 51774)
+ 0x671, 0,
+#undef V13739
+#define V13739 (V + 51776)
+ 0x67b, 0,
+#undef V13740
+#define V13740 (V + 51778)
+ 0x67e, 0,
+#undef V13741
+#define V13741 (V + 51780)
+ 0x680, 0,
+#undef V13742
+#define V13742 (V + 51782)
+ 0x67a, 0,
+#undef V13743
+#define V13743 (V + 51784)
+ 0x67f, 0,
+#undef V13744
+#define V13744 (V + 51786)
+ 0x679, 0,
+#undef V13745
+#define V13745 (V + 51788)
+ 0x6a4, 0,
+#undef V13746
+#define V13746 (V + 51790)
+ 0x6a6, 0,
+#undef V13747
+#define V13747 (V + 51792)
+ 0x684, 0,
+#undef V13748
+#define V13748 (V + 51794)
+ 0x683, 0,
+#undef V13749
+#define V13749 (V + 51796)
+ 0x686, 0,
+#undef V13750
+#define V13750 (V + 51798)
+ 0x687, 0,
+#undef V13751
+#define V13751 (V + 51800)
+ 0x68d, 0,
+#undef V13752
+#define V13752 (V + 51802)
+ 0x68c, 0,
+#undef V13753
+#define V13753 (V + 51804)
+ 0x68e, 0,
+#undef V13754
+#define V13754 (V + 51806)
+ 0x688, 0,
+#undef V13755
+#define V13755 (V + 51808)
+ 0x698, 0,
+#undef V13756
+#define V13756 (V + 51810)
+ 0x691, 0,
+#undef V13757
+#define V13757 (V + 51812)
+ 0x6a9, 0,
+#undef V13758
+#define V13758 (V + 51814)
+ 0x6af, 0,
+#undef V13759
+#define V13759 (V + 51816)
+ 0x6b3, 0,
+#undef V13760
+#define V13760 (V + 51818)
+ 0x6b1, 0,
+#undef V13761
+#define V13761 (V + 51820)
+ 0x6ba, 0,
+#undef V13762
+#define V13762 (V + 51822)
+ 0x6bb, 0,
+#undef V13763
+#define V13763 (V + 51824)
+ 0x6c1, 0,
+#undef V13764
+#define V13764 (V + 51826)
+ 0x6be, 0,
+#undef V13765
+#define V13765 (V + 51828)
+ 0x6d2, 0,
+#undef V13766
+#define V13766 (V + 51830)
+ 0x6ad, 0,
+#undef V13767
+#define V13767 (V + 51832)
+ 0x6c7, 0,
+#undef V13768
+#define V13768 (V + 51834)
+ 0x6c6, 0,
+#undef V13769
+#define V13769 (V + 51836)
+ 0x6c8, 0,
+#undef V13770
+#define V13770 (V + 51838)
+ 0x6cb, 0,
+#undef V13771
+#define V13771 (V + 51840)
+ 0x6c5, 0,
+#undef V13772
+#define V13772 (V + 51842)
+ 0x6c9, 0,
+#undef V13773
+#define V13773 (V + 51844)
+ 0x6d0, 0,
+#undef V13774
+#define V13774 (V + 51846)
+ 0x649, 0,
+#undef V13775
+#define V13775 (V + 51848)
+ 0x64a, 0x654, 0x627, 0,
+#undef V13776
+#define V13776 (V + 51852)
+ 0x64a, 0x654, 0x6d5, 0,
+#undef V13777
+#define V13777 (V + 51856)
+ 0x64a, 0x654, 0x648, 0,
+#undef V13778
+#define V13778 (V + 51860)
+ 0x64a, 0x654, 0x6c7, 0,
+#undef V13779
+#define V13779 (V + 51864)
+ 0x64a, 0x654, 0x6c6, 0,
+#undef V13780
+#define V13780 (V + 51868)
+ 0x64a, 0x654, 0x6c8, 0,
+#undef V13781
+#define V13781 (V + 51872)
+ 0x64a, 0x654, 0x6d0, 0,
+#undef V13782
+#define V13782 (V + 51876)
+ 0x64a, 0x654, 0x649, 0,
+#undef V13783
+#define V13783 (V + 51880)
+ 0x6cc, 0,
+#undef V13784
+#define V13784 (V + 51882)
+ 0x64a, 0x654, 0x62c, 0,
+#undef V13785
+#define V13785 (V + 51886)
+ 0x64a, 0x654, 0x62d, 0,
+#undef V13786
+#define V13786 (V + 51890)
+ 0x64a, 0x654, 0x645, 0,
+#undef V13787
+#define V13787 (V + 51894)
+ 0x64a, 0x654, 0x64a, 0,
+#undef V13788
+#define V13788 (V + 51898)
+ 0x628, 0x62c, 0,
+#undef V13789
+#define V13789 (V + 51901)
+ 0x628, 0x62d, 0,
+#undef V13790
+#define V13790 (V + 51904)
+ 0x628, 0x62e, 0,
+#undef V13791
+#define V13791 (V + 51907)
+ 0x628, 0x645, 0,
+#undef V13792
+#define V13792 (V + 51910)
+ 0x628, 0x649, 0,
+#undef V13793
+#define V13793 (V + 51913)
+ 0x628, 0x64a, 0,
+#undef V13794
+#define V13794 (V + 51916)
+ 0x62a, 0x62c, 0,
+#undef V13795
+#define V13795 (V + 51919)
+ 0x62a, 0x62d, 0,
+#undef V13796
+#define V13796 (V + 51922)
+ 0x62a, 0x62e, 0,
+#undef V13797
+#define V13797 (V + 51925)
+ 0x62a, 0x645, 0,
+#undef V13798
+#define V13798 (V + 51928)
+ 0x62a, 0x649, 0,
+#undef V13799
+#define V13799 (V + 51931)
+ 0x62a, 0x64a, 0,
+#undef V13800
+#define V13800 (V + 51934)
+ 0x62b, 0x62c, 0,
+#undef V13801
+#define V13801 (V + 51937)
+ 0x62b, 0x645, 0,
+#undef V13802
+#define V13802 (V + 51940)
+ 0x62b, 0x649, 0,
+#undef V13803
+#define V13803 (V + 51943)
+ 0x62b, 0x64a, 0,
+#undef V13804
+#define V13804 (V + 51946)
+ 0x62c, 0x62d, 0,
+#undef V13805
+#define V13805 (V + 51949)
+ 0x62c, 0x645, 0,
+#undef V13806
+#define V13806 (V + 51952)
+ 0x62d, 0x62c, 0,
+#undef V13807
+#define V13807 (V + 51955)
+ 0x62d, 0x645, 0,
+#undef V13808
+#define V13808 (V + 51958)
+ 0x62e, 0x62c, 0,
+#undef V13809
+#define V13809 (V + 51961)
+ 0x62e, 0x62d, 0,
+#undef V13810
+#define V13810 (V + 51964)
+ 0x62e, 0x645, 0,
+#undef V13811
+#define V13811 (V + 51967)
+ 0x633, 0x62c, 0,
+#undef V13812
+#define V13812 (V + 51970)
+ 0x633, 0x62d, 0,
+#undef V13813
+#define V13813 (V + 51973)
+ 0x633, 0x62e, 0,
+#undef V13814
+#define V13814 (V + 51976)
+ 0x633, 0x645, 0,
+#undef V13815
+#define V13815 (V + 51979)
+ 0x635, 0x62d, 0,
+#undef V13816
+#define V13816 (V + 51982)
+ 0x635, 0x645, 0,
+#undef V13817
+#define V13817 (V + 51985)
+ 0x636, 0x62c, 0,
+#undef V13818
+#define V13818 (V + 51988)
+ 0x636, 0x62d, 0,
+#undef V13819
+#define V13819 (V + 51991)
+ 0x636, 0x62e, 0,
+#undef V13820
+#define V13820 (V + 51994)
+ 0x636, 0x645, 0,
+#undef V13821
+#define V13821 (V + 51997)
+ 0x637, 0x62d, 0,
+#undef V13822
+#define V13822 (V + 52000)
+ 0x637, 0x645, 0,
+#undef V13823
+#define V13823 (V + 52003)
+ 0x638, 0x645, 0,
+#undef V13824
+#define V13824 (V + 52006)
+ 0x639, 0x62c, 0,
+#undef V13825
+#define V13825 (V + 52009)
+ 0x639, 0x645, 0,
+#undef V13826
+#define V13826 (V + 52012)
+ 0x63a, 0x62c, 0,
+#undef V13827
+#define V13827 (V + 52015)
+ 0x63a, 0x645, 0,
+#undef V13828
+#define V13828 (V + 52018)
+ 0x641, 0x62c, 0,
+#undef V13829
+#define V13829 (V + 52021)
+ 0x641, 0x62d, 0,
+#undef V13830
+#define V13830 (V + 52024)
+ 0x641, 0x62e, 0,
+#undef V13831
+#define V13831 (V + 52027)
+ 0x641, 0x645, 0,
+#undef V13832
+#define V13832 (V + 52030)
+ 0x641, 0x649, 0,
+#undef V13833
+#define V13833 (V + 52033)
+ 0x641, 0x64a, 0,
+#undef V13834
+#define V13834 (V + 52036)
+ 0x642, 0x62d, 0,
+#undef V13835
+#define V13835 (V + 52039)
+ 0x642, 0x645, 0,
+#undef V13836
+#define V13836 (V + 52042)
+ 0x642, 0x649, 0,
+#undef V13837
+#define V13837 (V + 52045)
+ 0x642, 0x64a, 0,
+#undef V13838
+#define V13838 (V + 52048)
+ 0x643, 0x627, 0,
+#undef V13839
+#define V13839 (V + 52051)
+ 0x643, 0x62c, 0,
+#undef V13840
+#define V13840 (V + 52054)
+ 0x643, 0x62d, 0,
+#undef V13841
+#define V13841 (V + 52057)
+ 0x643, 0x62e, 0,
+#undef V13842
+#define V13842 (V + 52060)
+ 0x643, 0x644, 0,
+#undef V13843
+#define V13843 (V + 52063)
+ 0x643, 0x645, 0,
+#undef V13844
+#define V13844 (V + 52066)
+ 0x643, 0x649, 0,
+#undef V13845
+#define V13845 (V + 52069)
+ 0x643, 0x64a, 0,
+#undef V13846
+#define V13846 (V + 52072)
+ 0x644, 0x62c, 0,
+#undef V13847
+#define V13847 (V + 52075)
+ 0x644, 0x62d, 0,
+#undef V13848
+#define V13848 (V + 52078)
+ 0x644, 0x62e, 0,
+#undef V13849
+#define V13849 (V + 52081)
+ 0x644, 0x645, 0,
+#undef V13850
+#define V13850 (V + 52084)
+ 0x644, 0x649, 0,
+#undef V13851
+#define V13851 (V + 52087)
+ 0x644, 0x64a, 0,
+#undef V13852
+#define V13852 (V + 52090)
+ 0x645, 0x62c, 0,
+#undef V13853
+#define V13853 (V + 52093)
+ 0x645, 0x62d, 0,
+#undef V13854
+#define V13854 (V + 52096)
+ 0x645, 0x62e, 0,
+#undef V13855
+#define V13855 (V + 52099)
+ 0x645, 0x645, 0,
+#undef V13856
+#define V13856 (V + 52102)
+ 0x645, 0x649, 0,
+#undef V13857
+#define V13857 (V + 52105)
+ 0x645, 0x64a, 0,
+#undef V13858
+#define V13858 (V + 52108)
+ 0x646, 0x62c, 0,
+#undef V13859
+#define V13859 (V + 52111)
+ 0x646, 0x62d, 0,
+#undef V13860
+#define V13860 (V + 52114)
+ 0x646, 0x62e, 0,
+#undef V13861
+#define V13861 (V + 52117)
+ 0x646, 0x645, 0,
+#undef V13862
+#define V13862 (V + 52120)
+ 0x646, 0x649, 0,
+#undef V13863
+#define V13863 (V + 52123)
+ 0x646, 0x64a, 0,
+#undef V13864
+#define V13864 (V + 52126)
+ 0x647, 0x62c, 0,
+#undef V13865
+#define V13865 (V + 52129)
+ 0x647, 0x645, 0,
+#undef V13866
+#define V13866 (V + 52132)
+ 0x647, 0x649, 0,
+#undef V13867
+#define V13867 (V + 52135)
+ 0x647, 0x64a, 0,
+#undef V13868
+#define V13868 (V + 52138)
+ 0x64a, 0x62c, 0,
+#undef V13869
+#define V13869 (V + 52141)
+ 0x64a, 0x62d, 0,
+#undef V13870
+#define V13870 (V + 52144)
+ 0x64a, 0x62e, 0,
+#undef V13871
+#define V13871 (V + 52147)
+ 0x64a, 0x645, 0,
+#undef V13872
+#define V13872 (V + 52150)
+ 0x64a, 0x649, 0,
+#undef V13873
+#define V13873 (V + 52153)
+ 0x64a, 0x64a, 0,
+#undef V13874
+#define V13874 (V + 52156)
+ 0x630, 0x670, 0,
+#undef V13875
+#define V13875 (V + 52159)
+ 0x631, 0x670, 0,
+#undef V13876
+#define V13876 (V + 52162)
+ 0x649, 0x670, 0,
+#undef V13877
+#define V13877 (V + 52165)
+ 0x20, 0x64c, 0x651, 0,
+#undef V13878
+#define V13878 (V + 52169)
+ 0x20, 0x64d, 0x651, 0,
+#undef V13879
+#define V13879 (V + 52173)
+ 0x20, 0x64e, 0x651, 0,
+#undef V13880
+#define V13880 (V + 52177)
+ 0x20, 0x64f, 0x651, 0,
+#undef V13881
+#define V13881 (V + 52181)
+ 0x20, 0x650, 0x651, 0,
+#undef V13882
+#define V13882 (V + 52185)
+ 0x20, 0x651, 0x670, 0,
+#undef V13883
+#define V13883 (V + 52189)
+ 0x64a, 0x654, 0x631, 0,
+#undef V13884
+#define V13884 (V + 52193)
+ 0x64a, 0x654, 0x632, 0,
+#undef V13885
+#define V13885 (V + 52197)
+ 0x64a, 0x654, 0x646, 0,
+#undef V13886
+#define V13886 (V + 52201)
+ 0x628, 0x631, 0,
+#undef V13887
+#define V13887 (V + 52204)
+ 0x628, 0x632, 0,
+#undef V13888
+#define V13888 (V + 52207)
+ 0x628, 0x646, 0,
+#undef V13889
+#define V13889 (V + 52210)
+ 0x62a, 0x631, 0,
+#undef V13890
+#define V13890 (V + 52213)
+ 0x62a, 0x632, 0,
+#undef V13891
+#define V13891 (V + 52216)
+ 0x62a, 0x646, 0,
+#undef V13892
+#define V13892 (V + 52219)
+ 0x62b, 0x631, 0,
+#undef V13893
+#define V13893 (V + 52222)
+ 0x62b, 0x632, 0,
+#undef V13894
+#define V13894 (V + 52225)
+ 0x62b, 0x646, 0,
+#undef V13895
+#define V13895 (V + 52228)
+ 0x645, 0x627, 0,
+#undef V13896
+#define V13896 (V + 52231)
+ 0x646, 0x631, 0,
+#undef V13897
+#define V13897 (V + 52234)
+ 0x646, 0x632, 0,
+#undef V13898
+#define V13898 (V + 52237)
+ 0x646, 0x646, 0,
+#undef V13899
+#define V13899 (V + 52240)
+ 0x64a, 0x631, 0,
+#undef V13900
+#define V13900 (V + 52243)
+ 0x64a, 0x632, 0,
+#undef V13901
+#define V13901 (V + 52246)
+ 0x64a, 0x646, 0,
+#undef V13902
+#define V13902 (V + 52249)
+ 0x64a, 0x654, 0x62e, 0,
+#undef V13903
+#define V13903 (V + 52253)
+ 0x64a, 0x654, 0x647, 0,
+#undef V13904
+#define V13904 (V + 52257)
+ 0x628, 0x647, 0,
+#undef V13905
+#define V13905 (V + 52260)
+ 0x62a, 0x647, 0,
+#undef V13906
+#define V13906 (V + 52263)
+ 0x635, 0x62e, 0,
+#undef V13907
+#define V13907 (V + 52266)
+ 0x644, 0x647, 0,
+#undef V13908
+#define V13908 (V + 52269)
+ 0x646, 0x647, 0,
+#undef V13909
+#define V13909 (V + 52272)
+ 0x647, 0x670, 0,
+#undef V13910
+#define V13910 (V + 52275)
+ 0x64a, 0x647, 0,
+#undef V13911
+#define V13911 (V + 52278)
+ 0x62b, 0x647, 0,
+#undef V13912
+#define V13912 (V + 52281)
+ 0x633, 0x647, 0,
+#undef V13913
+#define V13913 (V + 52284)
+ 0x634, 0x645, 0,
+#undef V13914
+#define V13914 (V + 52287)
+ 0x634, 0x647, 0,
+#undef V13915
+#define V13915 (V + 52290)
+ 0x640, 0x64e, 0x651, 0,
+#undef V13916
+#define V13916 (V + 52294)
+ 0x640, 0x64f, 0x651, 0,
+#undef V13917
+#define V13917 (V + 52298)
+ 0x640, 0x650, 0x651, 0,
+#undef V13918
+#define V13918 (V + 52302)
+ 0x637, 0x649, 0,
+#undef V13919
+#define V13919 (V + 52305)
+ 0x637, 0x64a, 0,
+#undef V13920
+#define V13920 (V + 52308)
+ 0x639, 0x649, 0,
+#undef V13921
+#define V13921 (V + 52311)
+ 0x639, 0x64a, 0,
+#undef V13922
+#define V13922 (V + 52314)
+ 0x63a, 0x649, 0,
+#undef V13923
+#define V13923 (V + 52317)
+ 0x63a, 0x64a, 0,
+#undef V13924
+#define V13924 (V + 52320)
+ 0x633, 0x649, 0,
+#undef V13925
+#define V13925 (V + 52323)
+ 0x633, 0x64a, 0,
+#undef V13926
+#define V13926 (V + 52326)
+ 0x634, 0x649, 0,
+#undef V13927
+#define V13927 (V + 52329)
+ 0x634, 0x64a, 0,
+#undef V13928
+#define V13928 (V + 52332)
+ 0x62d, 0x649, 0,
+#undef V13929
+#define V13929 (V + 52335)
+ 0x62d, 0x64a, 0,
+#undef V13930
+#define V13930 (V + 52338)
+ 0x62c, 0x649, 0,
+#undef V13931
+#define V13931 (V + 52341)
+ 0x62c, 0x64a, 0,
+#undef V13932
+#define V13932 (V + 52344)
+ 0x62e, 0x649, 0,
+#undef V13933
+#define V13933 (V + 52347)
+ 0x62e, 0x64a, 0,
+#undef V13934
+#define V13934 (V + 52350)
+ 0x635, 0x649, 0,
+#undef V13935
+#define V13935 (V + 52353)
+ 0x635, 0x64a, 0,
+#undef V13936
+#define V13936 (V + 52356)
+ 0x636, 0x649, 0,
+#undef V13937
+#define V13937 (V + 52359)
+ 0x636, 0x64a, 0,
+#undef V13938
+#define V13938 (V + 52362)
+ 0x634, 0x62c, 0,
+#undef V13939
+#define V13939 (V + 52365)
+ 0x634, 0x62d, 0,
+#undef V13940
+#define V13940 (V + 52368)
+ 0x634, 0x62e, 0,
+#undef V13941
+#define V13941 (V + 52371)
+ 0x634, 0x631, 0,
+#undef V13942
+#define V13942 (V + 52374)
+ 0x633, 0x631, 0,
+#undef V13943
+#define V13943 (V + 52377)
+ 0x635, 0x631, 0,
+#undef V13944
+#define V13944 (V + 52380)
+ 0x636, 0x631, 0,
+#undef V13945
+#define V13945 (V + 52383)
+ 0x627, 0x64b, 0,
+#undef V13946
+#define V13946 (V + 52386)
+ 0x62a, 0x62c, 0x645, 0,
+#undef V13947
+#define V13947 (V + 52390)
+ 0x62a, 0x62d, 0x62c, 0,
+#undef V13948
+#define V13948 (V + 52394)
+ 0x62a, 0x62d, 0x645, 0,
+#undef V13949
+#define V13949 (V + 52398)
+ 0x62a, 0x62e, 0x645, 0,
+#undef V13950
+#define V13950 (V + 52402)
+ 0x62a, 0x645, 0x62c, 0,
+#undef V13951
+#define V13951 (V + 52406)
+ 0x62a, 0x645, 0x62d, 0,
+#undef V13952
+#define V13952 (V + 52410)
+ 0x62a, 0x645, 0x62e, 0,
+#undef V13953
+#define V13953 (V + 52414)
+ 0x62c, 0x645, 0x62d, 0,
+#undef V13954
+#define V13954 (V + 52418)
+ 0x62d, 0x645, 0x64a, 0,
+#undef V13955
+#define V13955 (V + 52422)
+ 0x62d, 0x645, 0x649, 0,
+#undef V13956
+#define V13956 (V + 52426)
+ 0x633, 0x62d, 0x62c, 0,
+#undef V13957
+#define V13957 (V + 52430)
+ 0x633, 0x62c, 0x62d, 0,
+#undef V13958
+#define V13958 (V + 52434)
+ 0x633, 0x62c, 0x649, 0,
+#undef V13959
+#define V13959 (V + 52438)
+ 0x633, 0x645, 0x62d, 0,
+#undef V13960
+#define V13960 (V + 52442)
+ 0x633, 0x645, 0x62c, 0,
+#undef V13961
+#define V13961 (V + 52446)
+ 0x633, 0x645, 0x645, 0,
+#undef V13962
+#define V13962 (V + 52450)
+ 0x635, 0x62d, 0x62d, 0,
+#undef V13963
+#define V13963 (V + 52454)
+ 0x635, 0x645, 0x645, 0,
+#undef V13964
+#define V13964 (V + 52458)
+ 0x634, 0x62d, 0x645, 0,
+#undef V13965
+#define V13965 (V + 52462)
+ 0x634, 0x62c, 0x64a, 0,
+#undef V13966
+#define V13966 (V + 52466)
+ 0x634, 0x645, 0x62e, 0,
+#undef V13967
+#define V13967 (V + 52470)
+ 0x634, 0x645, 0x645, 0,
+#undef V13968
+#define V13968 (V + 52474)
+ 0x636, 0x62d, 0x649, 0,
+#undef V13969
+#define V13969 (V + 52478)
+ 0x636, 0x62e, 0x645, 0,
+#undef V13970
+#define V13970 (V + 52482)
+ 0x637, 0x645, 0x62d, 0,
+#undef V13971
+#define V13971 (V + 52486)
+ 0x637, 0x645, 0x645, 0,
+#undef V13972
+#define V13972 (V + 52490)
+ 0x637, 0x645, 0x64a, 0,
+#undef V13973
+#define V13973 (V + 52494)
+ 0x639, 0x62c, 0x645, 0,
+#undef V13974
+#define V13974 (V + 52498)
+ 0x639, 0x645, 0x645, 0,
+#undef V13975
+#define V13975 (V + 52502)
+ 0x639, 0x645, 0x649, 0,
+#undef V13976
+#define V13976 (V + 52506)
+ 0x63a, 0x645, 0x645, 0,
+#undef V13977
+#define V13977 (V + 52510)
+ 0x63a, 0x645, 0x64a, 0,
+#undef V13978
+#define V13978 (V + 52514)
+ 0x63a, 0x645, 0x649, 0,
+#undef V13979
+#define V13979 (V + 52518)
+ 0x641, 0x62e, 0x645, 0,
+#undef V13980
+#define V13980 (V + 52522)
+ 0x642, 0x645, 0x62d, 0,
+#undef V13981
+#define V13981 (V + 52526)
+ 0x642, 0x645, 0x645, 0,
+#undef V13982
+#define V13982 (V + 52530)
+ 0x644, 0x62d, 0x645, 0,
+#undef V13983
+#define V13983 (V + 52534)
+ 0x644, 0x62d, 0x64a, 0,
+#undef V13984
+#define V13984 (V + 52538)
+ 0x644, 0x62d, 0x649, 0,
+#undef V13985
+#define V13985 (V + 52542)
+ 0x644, 0x62c, 0x62c, 0,
+#undef V13986
+#define V13986 (V + 52546)
+ 0x644, 0x62e, 0x645, 0,
+#undef V13987
+#define V13987 (V + 52550)
+ 0x644, 0x645, 0x62d, 0,
+#undef V13988
+#define V13988 (V + 52554)
+ 0x645, 0x62d, 0x62c, 0,
+#undef V13989
+#define V13989 (V + 52558)
+ 0x645, 0x62d, 0x645, 0,
+#undef V13990
+#define V13990 (V + 52562)
+ 0x645, 0x62d, 0x64a, 0,
+#undef V13991
+#define V13991 (V + 52566)
+ 0x645, 0x62c, 0x62d, 0,
+#undef V13992
+#define V13992 (V + 52570)
+ 0x645, 0x62c, 0x645, 0,
+#undef V13993
+#define V13993 (V + 52574)
+ 0x645, 0x62e, 0x62c, 0,
+#undef V13994
+#define V13994 (V + 52578)
+ 0x645, 0x62e, 0x645, 0,
+#undef V13995
+#define V13995 (V + 52582)
+ 0x645, 0x62c, 0x62e, 0,
+#undef V13996
+#define V13996 (V + 52586)
+ 0x647, 0x645, 0x62c, 0,
+#undef V13997
+#define V13997 (V + 52590)
+ 0x647, 0x645, 0x645, 0,
+#undef V13998
+#define V13998 (V + 52594)
+ 0x646, 0x62d, 0x645, 0,
+#undef V13999
+#define V13999 (V + 52598)
+ 0x646, 0x62d, 0x649, 0,
+#undef V14000
+#define V14000 (V + 52602)
+ 0x646, 0x62c, 0x645, 0,
+#undef V14001
+#define V14001 (V + 52606)
+ 0x646, 0x62c, 0x649, 0,
+#undef V14002
+#define V14002 (V + 52610)
+ 0x646, 0x645, 0x64a, 0,
+#undef V14003
+#define V14003 (V + 52614)
+ 0x646, 0x645, 0x649, 0,
+#undef V14004
+#define V14004 (V + 52618)
+ 0x64a, 0x645, 0x645, 0,
+#undef V14005
+#define V14005 (V + 52622)
+ 0x628, 0x62e, 0x64a, 0,
+#undef V14006
+#define V14006 (V + 52626)
+ 0x62a, 0x62c, 0x64a, 0,
+#undef V14007
+#define V14007 (V + 52630)
+ 0x62a, 0x62c, 0x649, 0,
+#undef V14008
+#define V14008 (V + 52634)
+ 0x62a, 0x62e, 0x64a, 0,
+#undef V14009
+#define V14009 (V + 52638)
+ 0x62a, 0x62e, 0x649, 0,
+#undef V14010
+#define V14010 (V + 52642)
+ 0x62a, 0x645, 0x64a, 0,
+#undef V14011
+#define V14011 (V + 52646)
+ 0x62a, 0x645, 0x649, 0,
+#undef V14012
+#define V14012 (V + 52650)
+ 0x62c, 0x645, 0x64a, 0,
+#undef V14013
+#define V14013 (V + 52654)
+ 0x62c, 0x62d, 0x649, 0,
+#undef V14014
+#define V14014 (V + 52658)
+ 0x62c, 0x645, 0x649, 0,
+#undef V14015
+#define V14015 (V + 52662)
+ 0x633, 0x62e, 0x649, 0,
+#undef V14016
+#define V14016 (V + 52666)
+ 0x635, 0x62d, 0x64a, 0,
+#undef V14017
+#define V14017 (V + 52670)
+ 0x634, 0x62d, 0x64a, 0,
+#undef V14018
+#define V14018 (V + 52674)
+ 0x636, 0x62d, 0x64a, 0,
+#undef V14019
+#define V14019 (V + 52678)
+ 0x644, 0x62c, 0x64a, 0,
+#undef V14020
+#define V14020 (V + 52682)
+ 0x644, 0x645, 0x64a, 0,
+#undef V14021
+#define V14021 (V + 52686)
+ 0x64a, 0x62d, 0x64a, 0,
+#undef V14022
+#define V14022 (V + 52690)
+ 0x64a, 0x62c, 0x64a, 0,
+#undef V14023
+#define V14023 (V + 52694)
+ 0x64a, 0x645, 0x64a, 0,
+#undef V14024
+#define V14024 (V + 52698)
+ 0x645, 0x645, 0x64a, 0,
+#undef V14025
+#define V14025 (V + 52702)
+ 0x642, 0x645, 0x64a, 0,
+#undef V14026
+#define V14026 (V + 52706)
+ 0x646, 0x62d, 0x64a, 0,
+#undef V14027
+#define V14027 (V + 52710)
+ 0x639, 0x645, 0x64a, 0,
+#undef V14028
+#define V14028 (V + 52714)
+ 0x643, 0x645, 0x64a, 0,
+#undef V14029
+#define V14029 (V + 52718)
+ 0x646, 0x62c, 0x62d, 0,
+#undef V14030
+#define V14030 (V + 52722)
+ 0x645, 0x62e, 0x64a, 0,
+#undef V14031
+#define V14031 (V + 52726)
+ 0x644, 0x62c, 0x645, 0,
+#undef V14032
+#define V14032 (V + 52730)
+ 0x643, 0x645, 0x645, 0,
+#undef V14033
+#define V14033 (V + 52734)
+ 0x62c, 0x62d, 0x64a, 0,
+#undef V14034
+#define V14034 (V + 52738)
+ 0x62d, 0x62c, 0x64a, 0,
+#undef V14035
+#define V14035 (V + 52742)
+ 0x645, 0x62c, 0x64a, 0,
+#undef V14036
+#define V14036 (V + 52746)
+ 0x641, 0x645, 0x64a, 0,
+#undef V14037
+#define V14037 (V + 52750)
+ 0x628, 0x62d, 0x64a, 0,
+#undef V14038
+#define V14038 (V + 52754)
+ 0x633, 0x62e, 0x64a, 0,
+#undef V14039
+#define V14039 (V + 52758)
+ 0x646, 0x62c, 0x64a, 0,
+#undef V14040
+#define V14040 (V + 52762)
+ 0x635, 0x644, 0x6d2, 0,
+#undef V14041
+#define V14041 (V + 52766)
+ 0x642, 0x644, 0x6d2, 0,
+#undef V14042
+#define V14042 (V + 52770)
+ 0x627, 0x644, 0x644, 0x647, 0,
+#undef V14043
+#define V14043 (V + 52775)
+ 0x627, 0x643, 0x628, 0x631, 0,
+#undef V14044
+#define V14044 (V + 52780)
+ 0x645, 0x62d, 0x645, 0x62f, 0,
+#undef V14045
+#define V14045 (V + 52785)
+ 0x635, 0x644, 0x639, 0x645, 0,
+#undef V14046
+#define V14046 (V + 52790)
+ 0x631, 0x633, 0x648, 0x644, 0,
+#undef V14047
+#define V14047 (V + 52795)
+ 0x639, 0x644, 0x64a, 0x647, 0,
+#undef V14048
+#define V14048 (V + 52800)
+ 0x648, 0x633, 0x644, 0x645, 0,
+#undef V14049
+#define V14049 (V + 52805)
+ 0x635, 0x644, 0x649, 0,
+#undef V14050
+#define V14050 (V + 52809)
+ 0x635, 0x644, 0x649, 0x20, 0x627, 0x644, 0x644, 0x647, 0x20, 0x639, 0x644, 0x64a, 0x647, 0x20, 0x648, 0x633, 0x644, 0x645, 0,
+#undef V14051
+#define V14051 (V + 52828)
+ 0x62c, 0x644, 0x20, 0x62c, 0x644, 0x627, 0x644, 0x647, 0,
+#undef V14052
+#define V14052 (V + 52837)
+ 0x631, 0x6cc, 0x627, 0x644, 0,
+#undef V14053
+#define V14053 (V + 52842)
+ 0x2c, 0,
+#undef V14054
+#define V14054 (V + 52844)
+ 0x3001, 0,
+#undef V14055
+#define V14055 (V + 52846)
+ 0x3002, 0,
+#undef V14056
+#define V14056 (V + 52848)
+ 0x3a, 0,
+#undef V14057
+#define V14057 (V + 52850)
+ 0x21, 0,
+#undef V14058
+#define V14058 (V + 52852)
+ 0x3f, 0,
+#undef V14059
+#define V14059 (V + 52854)
+ 0x3016, 0,
+#undef V14060
+#define V14060 (V + 52856)
+ 0x3017, 0,
+#undef V14061
+#define V14061 (V + 52858)
+ 0x2014, 0,
+#undef V14062
+#define V14062 (V + 52860)
+ 0x2013, 0,
+#undef V14063
+#define V14063 (V + 52862)
+ 0x5f, 0,
+#undef V14064
+#define V14064 (V + 52864)
+ 0x7b, 0,
+#undef V14065
+#define V14065 (V + 52866)
+ 0x7d, 0,
+#undef V14066
+#define V14066 (V + 52868)
+ 0x3014, 0,
+#undef V14067
+#define V14067 (V + 52870)
+ 0x3015, 0,
+#undef V14068
+#define V14068 (V + 52872)
+ 0x3010, 0,
+#undef V14069
+#define V14069 (V + 52874)
+ 0x3011, 0,
+#undef V14070
+#define V14070 (V + 52876)
+ 0x300a, 0,
+#undef V14071
+#define V14071 (V + 52878)
+ 0x300b, 0,
+#undef V14072
+#define V14072 (V + 52880)
+ 0x300c, 0,
+#undef V14073
+#define V14073 (V + 52882)
+ 0x300d, 0,
+#undef V14074
+#define V14074 (V + 52884)
+ 0x300e, 0,
+#undef V14075
+#define V14075 (V + 52886)
+ 0x300f, 0,
+#undef V14076
+#define V14076 (V + 52888)
+ 0x5b, 0,
+#undef V14077
+#define V14077 (V + 52890)
+ 0x5d, 0,
+#undef V14078
+#define V14078 (V + 52892)
+ 0x23, 0,
+#undef V14079
+#define V14079 (V + 52894)
+ 0x26, 0,
+#undef V14080
+#define V14080 (V + 52896)
+ 0x2a, 0,
+#undef V14081
+#define V14081 (V + 52898)
+ 0x2d, 0,
+#undef V14082
+#define V14082 (V + 52900)
+ 0x3c, 0,
+#undef V14083
+#define V14083 (V + 52902)
+ 0x3e, 0,
+#undef V14084
+#define V14084 (V + 52904)
+ 0x5c, 0,
+#undef V14085
+#define V14085 (V + 52906)
+ 0x24, 0,
+#undef V14086
+#define V14086 (V + 52908)
+ 0x25, 0,
+#undef V14087
+#define V14087 (V + 52910)
+ 0x40, 0,
+#undef V14088
+#define V14088 (V + 52912)
+ 0x20, 0x64b, 0,
+#undef V14089
+#define V14089 (V + 52915)
+ 0x640, 0x64b, 0,
+#undef V14090
+#define V14090 (V + 52918)
+ 0x20, 0x64c, 0,
+#undef V14091
+#define V14091 (V + 52921)
+ 0x20, 0x64d, 0,
+#undef V14092
+#define V14092 (V + 52924)
+ 0x20, 0x64e, 0,
+#undef V14093
+#define V14093 (V + 52927)
+ 0x640, 0x64e, 0,
+#undef V14094
+#define V14094 (V + 52930)
+ 0x20, 0x64f, 0,
+#undef V14095
+#define V14095 (V + 52933)
+ 0x640, 0x64f, 0,
+#undef V14096
+#define V14096 (V + 52936)
+ 0x20, 0x650, 0,
+#undef V14097
+#define V14097 (V + 52939)
+ 0x640, 0x650, 0,
+#undef V14098
+#define V14098 (V + 52942)
+ 0x20, 0x651, 0,
+#undef V14099
+#define V14099 (V + 52945)
+ 0x640, 0x651, 0,
+#undef V14100
+#define V14100 (V + 52948)
+ 0x20, 0x652, 0,
+#undef V14101
+#define V14101 (V + 52951)
+ 0x640, 0x652, 0,
+#undef V14102
+#define V14102 (V + 52954)
+ 0x621, 0,
+#undef V14103
+#define V14103 (V + 52956)
+ 0x627, 0,
+#undef V14104
+#define V14104 (V + 52958)
+ 0x628, 0,
+#undef V14105
+#define V14105 (V + 52960)
+ 0x629, 0,
+#undef V14106
+#define V14106 (V + 52962)
+ 0x62a, 0,
+#undef V14107
+#define V14107 (V + 52964)
+ 0x62b, 0,
+#undef V14108
+#define V14108 (V + 52966)
+ 0x62c, 0,
+#undef V14109
+#define V14109 (V + 52968)
+ 0x62d, 0,
+#undef V14110
+#define V14110 (V + 52970)
+ 0x62e, 0,
+#undef V14111
+#define V14111 (V + 52972)
+ 0x62f, 0,
+#undef V14112
+#define V14112 (V + 52974)
+ 0x630, 0,
+#undef V14113
+#define V14113 (V + 52976)
+ 0x631, 0,
+#undef V14114
+#define V14114 (V + 52978)
+ 0x632, 0,
+#undef V14115
+#define V14115 (V + 52980)
+ 0x633, 0,
+#undef V14116
+#define V14116 (V + 52982)
+ 0x634, 0,
+#undef V14117
+#define V14117 (V + 52984)
+ 0x635, 0,
+#undef V14118
+#define V14118 (V + 52986)
+ 0x636, 0,
+#undef V14119
+#define V14119 (V + 52988)
+ 0x637, 0,
+#undef V14120
+#define V14120 (V + 52990)
+ 0x638, 0,
+#undef V14121
+#define V14121 (V + 52992)
+ 0x639, 0,
+#undef V14122
+#define V14122 (V + 52994)
+ 0x63a, 0,
+#undef V14123
+#define V14123 (V + 52996)
+ 0x641, 0,
+#undef V14124
+#define V14124 (V + 52998)
+ 0x642, 0,
+#undef V14125
+#define V14125 (V + 53000)
+ 0x643, 0,
+#undef V14126
+#define V14126 (V + 53002)
+ 0x644, 0,
+#undef V14127
+#define V14127 (V + 53004)
+ 0x645, 0,
+#undef V14128
+#define V14128 (V + 53006)
+ 0x646, 0,
+#undef V14129
+#define V14129 (V + 53008)
+ 0x647, 0,
+#undef V14130
+#define V14130 (V + 53010)
+ 0x648, 0,
+#undef V14131
+#define V14131 (V + 53012)
+ 0x64a, 0,
+#undef V14132
+#define V14132 (V + 53014)
+ 0x644, 0x627, 0x653, 0,
+#undef V14133
+#define V14133 (V + 53018)
+ 0x644, 0x627, 0x654, 0,
+#undef V14134
+#define V14134 (V + 53022)
+ 0x644, 0x627, 0x655, 0,
+#undef V14135
+#define V14135 (V + 53026)
+ 0x644, 0x627, 0,
+#undef V14136
+#define V14136 (V + 53029)
+ 0x22, 0,
+#undef V14137
+#define V14137 (V + 53031)
+ 0x27, 0,
+#undef V14138
+#define V14138 (V + 53033)
+ 0x2f, 0,
+#undef V14139
+#define V14139 (V + 53035)
+ 0x5e, 0,
+#undef V14140
+#define V14140 (V + 53037)
+ 0x7c, 0,
+#undef V14141
+#define V14141 (V + 53039)
+ 0x7e, 0,
+#undef V14142
+#define V14142 (V + 53041)
+ 0x2985, 0,
+#undef V14143
+#define V14143 (V + 53043)
+ 0x2986, 0,
+#undef V14144
+#define V14144 (V + 53045)
+ 0x30fb, 0,
+#undef V14145
+#define V14145 (V + 53047)
+ 0x30a1, 0,
+#undef V14146
+#define V14146 (V + 53049)
+ 0x30a3, 0,
+#undef V14147
+#define V14147 (V + 53051)
+ 0x30a5, 0,
+#undef V14148
+#define V14148 (V + 53053)
+ 0x30a7, 0,
+#undef V14149
+#define V14149 (V + 53055)
+ 0x30a9, 0,
+#undef V14150
+#define V14150 (V + 53057)
+ 0x30e3, 0,
+#undef V14151
+#define V14151 (V + 53059)
+ 0x30e5, 0,
+#undef V14152
+#define V14152 (V + 53061)
+ 0x30e7, 0,
+#undef V14153
+#define V14153 (V + 53063)
+ 0x30c3, 0,
+#undef V14154
+#define V14154 (V + 53065)
+ 0x30fc, 0,
+#undef V14155
+#define V14155 (V + 53067)
+ 0x30f3, 0,
+#undef V14156
+#define V14156 (V + 53069)
+ 0x3099, 0,
+#undef V14157
+#define V14157 (V + 53071)
+ 0x309a, 0,
+#undef V14158
+#define V14158 (V + 53073)
+ 0xa2, 0,
+#undef V14159
+#define V14159 (V + 53075)
+ 0xa3, 0,
+#undef V14160
+#define V14160 (V + 53077)
+ 0xac, 0,
+#undef V14161
+#define V14161 (V + 53079)
+ 0xa6, 0,
+#undef V14162
+#define V14162 (V + 53081)
+ 0xa5, 0,
+#undef V14163
+#define V14163 (V + 53083)
+ 0x20a9, 0,
+#undef V14164
+#define V14164 (V + 53085)
+ 0x2502, 0,
+#undef V14165
+#define V14165 (V + 53087)
+ 0x2190, 0,
+#undef V14166
+#define V14166 (V + 53089)
+ 0x2191, 0,
+#undef V14167
+#define V14167 (V + 53091)
+ 0x2192, 0,
+#undef V14168
+#define V14168 (V + 53093)
+ 0x2193, 0,
+#undef V14169
+#define V14169 (V + 53095)
+ 0x25a0, 0,
+#undef V14170
+#define V14170 (V + 53097)
+ 0x25cb, 0,
+#undef V14171
+#define V14171 (V + 53099)
+ 0x11099, 0x110ba, 0,
+#undef V14172
+#define V14172 (V + 53102)
+ 0x1109b, 0x110ba, 0,
+#undef V14173
+#define V14173 (V + 53105)
+ 0x110a5, 0x110ba, 0,
+#undef V14174
+#define V14174 (V + 53108)
+ 0x11131, 0x11127, 0,
+#undef V14175
+#define V14175 (V + 53111)
+ 0x11132, 0x11127, 0,
+#undef V14176
+#define V14176 (V + 53114)
+ 0x11347, 0x1133e, 0,
+#undef V14177
+#define V14177 (V + 53117)
+ 0x11347, 0x11357, 0,
+#undef V14178
+#define V14178 (V + 53120)
+ 0x114b9, 0x114ba, 0,
+#undef V14179
+#define V14179 (V + 53123)
+ 0x114b9, 0x114b0, 0,
+#undef V14180
+#define V14180 (V + 53126)
+ 0x114b9, 0x114bd, 0,
+#undef V14181
+#define V14181 (V + 53129)
+ 0x115b8, 0x115af, 0,
+#undef V14182
+#define V14182 (V + 53132)
+ 0x115b9, 0x115af, 0,
+#undef V14183
+#define V14183 (V + 53135)
+ 0x1d157, 0x1d165, 0,
+#undef V14184
+#define V14184 (V + 53138)
+ 0x1d158, 0x1d165, 0,
+#undef V14185
+#define V14185 (V + 53141)
+ 0x1d158, 0x1d165, 0x1d16e, 0,
+#undef V14186
+#define V14186 (V + 53145)
+ 0x1d158, 0x1d165, 0x1d16f, 0,
+#undef V14187
+#define V14187 (V + 53149)
+ 0x1d158, 0x1d165, 0x1d170, 0,
+#undef V14188
+#define V14188 (V + 53153)
+ 0x1d158, 0x1d165, 0x1d171, 0,
+#undef V14189
+#define V14189 (V + 53157)
+ 0x1d158, 0x1d165, 0x1d172, 0,
+#undef V14190
+#define V14190 (V + 53161)
+ 0x1d1b9, 0x1d165, 0,
+#undef V14191
+#define V14191 (V + 53164)
+ 0x1d1ba, 0x1d165, 0,
+#undef V14192
+#define V14192 (V + 53167)
+ 0x1d1b9, 0x1d165, 0x1d16e, 0,
+#undef V14193
+#define V14193 (V + 53171)
+ 0x1d1ba, 0x1d165, 0x1d16e, 0,
+#undef V14194
+#define V14194 (V + 53175)
+ 0x1d1b9, 0x1d165, 0x1d16f, 0,
+#undef V14195
+#define V14195 (V + 53179)
+ 0x1d1ba, 0x1d165, 0x1d16f, 0,
+#undef V14196
+#define V14196 (V + 53183)
+ 0x131, 0,
+#undef V14197
+#define V14197 (V + 53185)
+ 0x237, 0,
+#undef V14198
+#define V14198 (V + 53187)
+ 0x391, 0,
+#undef V14199
+#define V14199 (V + 53189)
+ 0x392, 0,
+#undef V14200
+#define V14200 (V + 53191)
+ 0x394, 0,
+#undef V14201
+#define V14201 (V + 53193)
+ 0x395, 0,
+#undef V14202
+#define V14202 (V + 53195)
+ 0x396, 0,
+#undef V14203
+#define V14203 (V + 53197)
+ 0x397, 0,
+#undef V14204
+#define V14204 (V + 53199)
+ 0x399, 0,
+#undef V14205
+#define V14205 (V + 53201)
+ 0x39a, 0,
+#undef V14206
+#define V14206 (V + 53203)
+ 0x39b, 0,
+#undef V14207
+#define V14207 (V + 53205)
+ 0x39c, 0,
+#undef V14208
+#define V14208 (V + 53207)
+ 0x39d, 0,
+#undef V14209
+#define V14209 (V + 53209)
+ 0x39e, 0,
+#undef V14210
+#define V14210 (V + 53211)
+ 0x39f, 0,
+#undef V14211
+#define V14211 (V + 53213)
+ 0x3a1, 0,
+#undef V14212
+#define V14212 (V + 53215)
+ 0x3a4, 0,
+#undef V14213
+#define V14213 (V + 53217)
+ 0x3a6, 0,
+#undef V14214
+#define V14214 (V + 53219)
+ 0x3a7, 0,
+#undef V14215
+#define V14215 (V + 53221)
+ 0x3a8, 0,
+#undef V14216
+#define V14216 (V + 53223)
+ 0x2207, 0,
+#undef V14217
+#define V14217 (V + 53225)
+ 0x3b1, 0,
+#undef V14218
+#define V14218 (V + 53227)
+ 0x3b6, 0,
+#undef V14219
+#define V14219 (V + 53229)
+ 0x3b7, 0,
+#undef V14220
+#define V14220 (V + 53231)
+ 0x3bb, 0,
+#undef V14221
+#define V14221 (V + 53233)
+ 0x3bd, 0,
+#undef V14222
+#define V14222 (V + 53235)
+ 0x3be, 0,
+#undef V14223
+#define V14223 (V + 53237)
+ 0x3bf, 0,
+#undef V14224
+#define V14224 (V + 53239)
+ 0x3c3, 0,
+#undef V14225
+#define V14225 (V + 53241)
+ 0x3c4, 0,
+#undef V14226
+#define V14226 (V + 53243)
+ 0x3c5, 0,
+#undef V14227
+#define V14227 (V + 53245)
+ 0x3c8, 0,
+#undef V14228
+#define V14228 (V + 53247)
+ 0x3c9, 0,
+#undef V14229
+#define V14229 (V + 53249)
+ 0x2202, 0,
+#undef V14230
+#define V14230 (V + 53251)
+ 0x3dc, 0,
+#undef V14231
+#define V14231 (V + 53253)
+ 0x3dd, 0,
+#undef V14232
+#define V14232 (V + 53255)
+ 0x66e, 0,
+#undef V14233
+#define V14233 (V + 53257)
+ 0x6a1, 0,
+#undef V14234
+#define V14234 (V + 53259)
+ 0x66f, 0,
+#undef V14235
+#define V14235 (V + 53261)
+ 0x30, 0x2e, 0,
+#undef V14236
+#define V14236 (V + 53264)
+ 0x30, 0x2c, 0,
+#undef V14237
+#define V14237 (V + 53267)
+ 0x31, 0x2c, 0,
+#undef V14238
+#define V14238 (V + 53270)
+ 0x32, 0x2c, 0,
+#undef V14239
+#define V14239 (V + 53273)
+ 0x33, 0x2c, 0,
+#undef V14240
+#define V14240 (V + 53276)
+ 0x34, 0x2c, 0,
+#undef V14241
+#define V14241 (V + 53279)
+ 0x35, 0x2c, 0,
+#undef V14242
+#define V14242 (V + 53282)
+ 0x36, 0x2c, 0,
+#undef V14243
+#define V14243 (V + 53285)
+ 0x37, 0x2c, 0,
+#undef V14244
+#define V14244 (V + 53288)
+ 0x38, 0x2c, 0,
+#undef V14245
+#define V14245 (V + 53291)
+ 0x39, 0x2c, 0,
+#undef V14246
+#define V14246 (V + 53294)
+ 0x28, 0x41, 0x29, 0,
+#undef V14247
+#define V14247 (V + 53298)
+ 0x28, 0x42, 0x29, 0,
+#undef V14248
+#define V14248 (V + 53302)
+ 0x28, 0x43, 0x29, 0,
+#undef V14249
+#define V14249 (V + 53306)
+ 0x28, 0x44, 0x29, 0,
+#undef V14250
+#define V14250 (V + 53310)
+ 0x28, 0x45, 0x29, 0,
+#undef V14251
+#define V14251 (V + 53314)
+ 0x28, 0x46, 0x29, 0,
+#undef V14252
+#define V14252 (V + 53318)
+ 0x28, 0x47, 0x29, 0,
+#undef V14253
+#define V14253 (V + 53322)
+ 0x28, 0x48, 0x29, 0,
+#undef V14254
+#define V14254 (V + 53326)
+ 0x28, 0x49, 0x29, 0,
+#undef V14255
+#define V14255 (V + 53330)
+ 0x28, 0x4a, 0x29, 0,
+#undef V14256
+#define V14256 (V + 53334)
+ 0x28, 0x4b, 0x29, 0,
+#undef V14257
+#define V14257 (V + 53338)
+ 0x28, 0x4c, 0x29, 0,
+#undef V14258
+#define V14258 (V + 53342)
+ 0x28, 0x4d, 0x29, 0,
+#undef V14259
+#define V14259 (V + 53346)
+ 0x28, 0x4e, 0x29, 0,
+#undef V14260
+#define V14260 (V + 53350)
+ 0x28, 0x4f, 0x29, 0,
+#undef V14261
+#define V14261 (V + 53354)
+ 0x28, 0x50, 0x29, 0,
+#undef V14262
+#define V14262 (V + 53358)
+ 0x28, 0x51, 0x29, 0,
+#undef V14263
+#define V14263 (V + 53362)
+ 0x28, 0x52, 0x29, 0,
+#undef V14264
+#define V14264 (V + 53366)
+ 0x28, 0x53, 0x29, 0,
+#undef V14265
+#define V14265 (V + 53370)
+ 0x28, 0x54, 0x29, 0,
+#undef V14266
+#define V14266 (V + 53374)
+ 0x28, 0x55, 0x29, 0,
+#undef V14267
+#define V14267 (V + 53378)
+ 0x28, 0x56, 0x29, 0,
+#undef V14268
+#define V14268 (V + 53382)
+ 0x28, 0x57, 0x29, 0,
+#undef V14269
+#define V14269 (V + 53386)
+ 0x28, 0x58, 0x29, 0,
+#undef V14270
+#define V14270 (V + 53390)
+ 0x28, 0x59, 0x29, 0,
+#undef V14271
+#define V14271 (V + 53394)
+ 0x28, 0x5a, 0x29, 0,
+#undef V14272
+#define V14272 (V + 53398)
+ 0x3014, 0x53, 0x3015, 0,
+#undef V14273
+#define V14273 (V + 53402)
+ 0x43, 0x44, 0,
+#undef V14274
+#define V14274 (V + 53405)
+ 0x57, 0x5a, 0,
+#undef V14275
+#define V14275 (V + 53408)
+ 0x48, 0x56, 0,
+#undef V14276
+#define V14276 (V + 53411)
+ 0x53, 0x44, 0,
+#undef V14277
+#define V14277 (V + 53414)
+ 0x53, 0x53, 0,
+#undef V14278
+#define V14278 (V + 53417)
+ 0x50, 0x50, 0x56, 0,
+#undef V14279
+#define V14279 (V + 53421)
+ 0x57, 0x43, 0,
+#undef V14280
+#define V14280 (V + 53424)
+ 0x4d, 0x43, 0,
+#undef V14281
+#define V14281 (V + 53427)
+ 0x4d, 0x44, 0,
+#undef V14282
+#define V14282 (V + 53430)
+ 0x44, 0x4a, 0,
+#undef V14283
+#define V14283 (V + 53433)
+ 0x307b, 0x304b, 0,
+#undef V14284
+#define V14284 (V + 53436)
+ 0x30b3, 0x30b3, 0,
+#undef V14285
+#define V14285 (V + 53439)
+ 0x5b57, 0,
+#undef V14286
+#define V14286 (V + 53441)
+ 0x53cc, 0,
+#undef V14287
+#define V14287 (V + 53443)
+ 0x591a, 0,
+#undef V14288
+#define V14288 (V + 53445)
+ 0x89e3, 0,
+#undef V14289
+#define V14289 (V + 53447)
+ 0x4ea4, 0,
+#undef V14290
+#define V14290 (V + 53449)
+ 0x6620, 0,
+#undef V14291
+#define V14291 (V + 53451)
+ 0x7121, 0,
+#undef V14292
+#define V14292 (V + 53453)
+ 0x524d, 0,
+#undef V14293
+#define V14293 (V + 53455)
+ 0x5f8c, 0,
+#undef V14294
+#define V14294 (V + 53457)
+ 0x518d, 0,
+#undef V14295
+#define V14295 (V + 53459)
+ 0x65b0, 0,
+#undef V14296
+#define V14296 (V + 53461)
+ 0x521d, 0,
+#undef V14297
+#define V14297 (V + 53463)
+ 0x7d42, 0,
+#undef V14298
+#define V14298 (V + 53465)
+ 0x8ca9, 0,
+#undef V14299
+#define V14299 (V + 53467)
+ 0x58f0, 0,
+#undef V14300
+#define V14300 (V + 53469)
+ 0x5439, 0,
+#undef V14301
+#define V14301 (V + 53471)
+ 0x6f14, 0,
+#undef V14302
+#define V14302 (V + 53473)
+ 0x6295, 0,
+#undef V14303
+#define V14303 (V + 53475)
+ 0x6355, 0,
+#undef V14304
+#define V14304 (V + 53477)
+ 0x904a, 0,
+#undef V14305
+#define V14305 (V + 53479)
+ 0x6307, 0,
+#undef V14306
+#define V14306 (V + 53481)
+ 0x6253, 0,
+#undef V14307
+#define V14307 (V + 53483)
+ 0x7981, 0,
+#undef V14308
+#define V14308 (V + 53485)
+ 0x7a7a, 0,
+#undef V14309
+#define V14309 (V + 53487)
+ 0x5408, 0,
+#undef V14310
+#define V14310 (V + 53489)
+ 0x6e80, 0,
+#undef V14311
+#define V14311 (V + 53491)
+ 0x7533, 0,
+#undef V14312
+#define V14312 (V + 53493)
+ 0x5272, 0,
+#undef V14313
+#define V14313 (V + 53495)
+ 0x55b6, 0,
+#undef V14314
+#define V14314 (V + 53497)
+ 0x914d, 0,
+#undef V14315
+#define V14315 (V + 53499)
+ 0x3014, 0x672c, 0x3015, 0,
+#undef V14316
+#define V14316 (V + 53503)
+ 0x3014, 0x4e09, 0x3015, 0,
+#undef V14317
+#define V14317 (V + 53507)
+ 0x3014, 0x4e8c, 0x3015, 0,
+#undef V14318
+#define V14318 (V + 53511)
+ 0x3014, 0x5b89, 0x3015, 0,
+#undef V14319
+#define V14319 (V + 53515)
+ 0x3014, 0x70b9, 0x3015, 0,
+#undef V14320
+#define V14320 (V + 53519)
+ 0x3014, 0x6253, 0x3015, 0,
+#undef V14321
+#define V14321 (V + 53523)
+ 0x3014, 0x76d7, 0x3015, 0,
+#undef V14322
+#define V14322 (V + 53527)
+ 0x3014, 0x52dd, 0x3015, 0,
+#undef V14323
+#define V14323 (V + 53531)
+ 0x3014, 0x6557, 0x3015, 0,
+#undef V14324
+#define V14324 (V + 53535)
+ 0x5f97, 0,
+#undef V14325
+#define V14325 (V + 53537)
+ 0x53ef, 0,
+#undef V14326
+#define V14326 (V + 53539)
+ 0x4e3d, 0,
+#undef V14327
+#define V14327 (V + 53541)
+ 0x4e38, 0,
+#undef V14328
+#define V14328 (V + 53543)
+ 0x4e41, 0,
+#undef V14329
+#define V14329 (V + 53545)
+ 0x20122, 0,
+#undef V14330
+#define V14330 (V + 53547)
+ 0x4f60, 0,
+#undef V14331
+#define V14331 (V + 53549)
+ 0x4fbb, 0,
+#undef V14332
+#define V14332 (V + 53551)
+ 0x5002, 0,
+#undef V14333
+#define V14333 (V + 53553)
+ 0x507a, 0,
+#undef V14334
+#define V14334 (V + 53555)
+ 0x5099, 0,
+#undef V14335
+#define V14335 (V + 53557)
+ 0x50cf, 0,
+#undef V14336
+#define V14336 (V + 53559)
+ 0x349e, 0,
+#undef V14337
+#define V14337 (V + 53561)
+ 0x2063a, 0,
+#undef V14338
+#define V14338 (V + 53563)
+ 0x5154, 0,
+#undef V14339
+#define V14339 (V + 53565)
+ 0x5164, 0,
+#undef V14340
+#define V14340 (V + 53567)
+ 0x5177, 0,
+#undef V14341
+#define V14341 (V + 53569)
+ 0x2051c, 0,
+#undef V14342
+#define V14342 (V + 53571)
+ 0x34b9, 0,
+#undef V14343
+#define V14343 (V + 53573)
+ 0x5167, 0,
+#undef V14344
+#define V14344 (V + 53575)
+ 0x2054b, 0,
+#undef V14345
+#define V14345 (V + 53577)
+ 0x5197, 0,
+#undef V14346
+#define V14346 (V + 53579)
+ 0x51a4, 0,
+#undef V14347
+#define V14347 (V + 53581)
+ 0x4ecc, 0,
+#undef V14348
+#define V14348 (V + 53583)
+ 0x51ac, 0,
+#undef V14349
+#define V14349 (V + 53585)
+ 0x291df, 0,
+#undef V14350
+#define V14350 (V + 53587)
+ 0x5203, 0,
+#undef V14351
+#define V14351 (V + 53589)
+ 0x34df, 0,
+#undef V14352
+#define V14352 (V + 53591)
+ 0x523b, 0,
+#undef V14353
+#define V14353 (V + 53593)
+ 0x5246, 0,
+#undef V14354
+#define V14354 (V + 53595)
+ 0x5277, 0,
+#undef V14355
+#define V14355 (V + 53597)
+ 0x3515, 0,
+#undef V14356
+#define V14356 (V + 53599)
+ 0x5305, 0,
+#undef V14357
+#define V14357 (V + 53601)
+ 0x5306, 0,
+#undef V14358
+#define V14358 (V + 53603)
+ 0x5349, 0,
+#undef V14359
+#define V14359 (V + 53605)
+ 0x535a, 0,
+#undef V14360
+#define V14360 (V + 53607)
+ 0x5373, 0,
+#undef V14361
+#define V14361 (V + 53609)
+ 0x537d, 0,
+#undef V14362
+#define V14362 (V + 53611)
+ 0x537f, 0,
+#undef V14363
+#define V14363 (V + 53613)
+ 0x20a2c, 0,
+#undef V14364
+#define V14364 (V + 53615)
+ 0x7070, 0,
+#undef V14365
+#define V14365 (V + 53617)
+ 0x53ca, 0,
+#undef V14366
+#define V14366 (V + 53619)
+ 0x53df, 0,
+#undef V14367
+#define V14367 (V + 53621)
+ 0x20b63, 0,
+#undef V14368
+#define V14368 (V + 53623)
+ 0x53eb, 0,
+#undef V14369
+#define V14369 (V + 53625)
+ 0x53f1, 0,
+#undef V14370
+#define V14370 (V + 53627)
+ 0x5406, 0,
+#undef V14371
+#define V14371 (V + 53629)
+ 0x549e, 0,
+#undef V14372
+#define V14372 (V + 53631)
+ 0x5438, 0,
+#undef V14373
+#define V14373 (V + 53633)
+ 0x5448, 0,
+#undef V14374
+#define V14374 (V + 53635)
+ 0x5468, 0,
+#undef V14375
+#define V14375 (V + 53637)
+ 0x54a2, 0,
+#undef V14376
+#define V14376 (V + 53639)
+ 0x54f6, 0,
+#undef V14377
+#define V14377 (V + 53641)
+ 0x5510, 0,
+#undef V14378
+#define V14378 (V + 53643)
+ 0x5553, 0,
+#undef V14379
+#define V14379 (V + 53645)
+ 0x5563, 0,
+#undef V14380
+#define V14380 (V + 53647)
+ 0x5584, 0,
+#undef V14381
+#define V14381 (V + 53649)
+ 0x55ab, 0,
+#undef V14382
+#define V14382 (V + 53651)
+ 0x55b3, 0,
+#undef V14383
+#define V14383 (V + 53653)
+ 0x55c2, 0,
+#undef V14384
+#define V14384 (V + 53655)
+ 0x5716, 0,
+#undef V14385
+#define V14385 (V + 53657)
+ 0x5717, 0,
+#undef V14386
+#define V14386 (V + 53659)
+ 0x5651, 0,
+#undef V14387
+#define V14387 (V + 53661)
+ 0x5674, 0,
+#undef V14388
+#define V14388 (V + 53663)
+ 0x58ee, 0,
+#undef V14389
+#define V14389 (V + 53665)
+ 0x57ce, 0,
+#undef V14390
+#define V14390 (V + 53667)
+ 0x57f4, 0,
+#undef V14391
+#define V14391 (V + 53669)
+ 0x580d, 0,
+#undef V14392
+#define V14392 (V + 53671)
+ 0x578b, 0,
+#undef V14393
+#define V14393 (V + 53673)
+ 0x5832, 0,
+#undef V14394
+#define V14394 (V + 53675)
+ 0x5831, 0,
+#undef V14395
+#define V14395 (V + 53677)
+ 0x58ac, 0,
+#undef V14396
+#define V14396 (V + 53679)
+ 0x214e4, 0,
+#undef V14397
+#define V14397 (V + 53681)
+ 0x58f2, 0,
+#undef V14398
+#define V14398 (V + 53683)
+ 0x58f7, 0,
+#undef V14399
+#define V14399 (V + 53685)
+ 0x5906, 0,
+#undef V14400
+#define V14400 (V + 53687)
+ 0x5922, 0,
+#undef V14401
+#define V14401 (V + 53689)
+ 0x5962, 0,
+#undef V14402
+#define V14402 (V + 53691)
+ 0x216a8, 0,
+#undef V14403
+#define V14403 (V + 53693)
+ 0x216ea, 0,
+#undef V14404
+#define V14404 (V + 53695)
+ 0x59ec, 0,
+#undef V14405
+#define V14405 (V + 53697)
+ 0x5a1b, 0,
+#undef V14406
+#define V14406 (V + 53699)
+ 0x5a27, 0,
+#undef V14407
+#define V14407 (V + 53701)
+ 0x59d8, 0,
+#undef V14408
+#define V14408 (V + 53703)
+ 0x5a66, 0,
+#undef V14409
+#define V14409 (V + 53705)
+ 0x36ee, 0,
+#undef V14410
+#define V14410 (V + 53707)
+ 0x36fc, 0,
+#undef V14411
+#define V14411 (V + 53709)
+ 0x5b08, 0,
+#undef V14412
+#define V14412 (V + 53711)
+ 0x5b3e, 0,
+#undef V14413
+#define V14413 (V + 53713)
+ 0x219c8, 0,
+#undef V14414
+#define V14414 (V + 53715)
+ 0x5bc3, 0,
+#undef V14415
+#define V14415 (V + 53717)
+ 0x5bd8, 0,
+#undef V14416
+#define V14416 (V + 53719)
+ 0x5bf3, 0,
+#undef V14417
+#define V14417 (V + 53721)
+ 0x21b18, 0,
+#undef V14418
+#define V14418 (V + 53723)
+ 0x5bff, 0,
+#undef V14419
+#define V14419 (V + 53725)
+ 0x5c06, 0,
+#undef V14420
+#define V14420 (V + 53727)
+ 0x5f53, 0,
+#undef V14421
+#define V14421 (V + 53729)
+ 0x3781, 0,
+#undef V14422
+#define V14422 (V + 53731)
+ 0x5c60, 0,
+#undef V14423
+#define V14423 (V + 53733)
+ 0x5cc0, 0,
+#undef V14424
+#define V14424 (V + 53735)
+ 0x5c8d, 0,
+#undef V14425
+#define V14425 (V + 53737)
+ 0x21de4, 0,
+#undef V14426
+#define V14426 (V + 53739)
+ 0x5d43, 0,
+#undef V14427
+#define V14427 (V + 53741)
+ 0x21de6, 0,
+#undef V14428
+#define V14428 (V + 53743)
+ 0x5d6e, 0,
+#undef V14429
+#define V14429 (V + 53745)
+ 0x5d6b, 0,
+#undef V14430
+#define V14430 (V + 53747)
+ 0x5d7c, 0,
+#undef V14431
+#define V14431 (V + 53749)
+ 0x5de1, 0,
+#undef V14432
+#define V14432 (V + 53751)
+ 0x5de2, 0,
+#undef V14433
+#define V14433 (V + 53753)
+ 0x382f, 0,
+#undef V14434
+#define V14434 (V + 53755)
+ 0x5dfd, 0,
+#undef V14435
+#define V14435 (V + 53757)
+ 0x5e28, 0,
+#undef V14436
+#define V14436 (V + 53759)
+ 0x5e3d, 0,
+#undef V14437
+#define V14437 (V + 53761)
+ 0x5e69, 0,
+#undef V14438
+#define V14438 (V + 53763)
+ 0x3862, 0,
+#undef V14439
+#define V14439 (V + 53765)
+ 0x22183, 0,
+#undef V14440
+#define V14440 (V + 53767)
+ 0x387c, 0,
+#undef V14441
+#define V14441 (V + 53769)
+ 0x5eb0, 0,
+#undef V14442
+#define V14442 (V + 53771)
+ 0x5eb3, 0,
+#undef V14443
+#define V14443 (V + 53773)
+ 0x5eb6, 0,
+#undef V14444
+#define V14444 (V + 53775)
+ 0x2a392, 0,
+#undef V14445
+#define V14445 (V + 53777)
+ 0x22331, 0,
+#undef V14446
+#define V14446 (V + 53779)
+ 0x8201, 0,
+#undef V14447
+#define V14447 (V + 53781)
+ 0x5f22, 0,
+#undef V14448
+#define V14448 (V + 53783)
+ 0x38c7, 0,
+#undef V14449
+#define V14449 (V + 53785)
+ 0x232b8, 0,
+#undef V14450
+#define V14450 (V + 53787)
+ 0x261da, 0,
+#undef V14451
+#define V14451 (V + 53789)
+ 0x5f62, 0,
+#undef V14452
+#define V14452 (V + 53791)
+ 0x5f6b, 0,
+#undef V14453
+#define V14453 (V + 53793)
+ 0x38e3, 0,
+#undef V14454
+#define V14454 (V + 53795)
+ 0x5f9a, 0,
+#undef V14455
+#define V14455 (V + 53797)
+ 0x5fcd, 0,
+#undef V14456
+#define V14456 (V + 53799)
+ 0x5fd7, 0,
+#undef V14457
+#define V14457 (V + 53801)
+ 0x5ff9, 0,
+#undef V14458
+#define V14458 (V + 53803)
+ 0x6081, 0,
+#undef V14459
+#define V14459 (V + 53805)
+ 0x393a, 0,
+#undef V14460
+#define V14460 (V + 53807)
+ 0x391c, 0,
+#undef V14461
+#define V14461 (V + 53809)
+ 0x226d4, 0,
+#undef V14462
+#define V14462 (V + 53811)
+ 0x60c7, 0,
+#undef V14463
+#define V14463 (V + 53813)
+ 0x6148, 0,
+#undef V14464
+#define V14464 (V + 53815)
+ 0x614c, 0,
+#undef V14465
+#define V14465 (V + 53817)
+ 0x617a, 0,
+#undef V14466
+#define V14466 (V + 53819)
+ 0x61b2, 0,
+#undef V14467
+#define V14467 (V + 53821)
+ 0x61a4, 0,
+#undef V14468
+#define V14468 (V + 53823)
+ 0x61af, 0,
+#undef V14469
+#define V14469 (V + 53825)
+ 0x61de, 0,
+#undef V14470
+#define V14470 (V + 53827)
+ 0x6210, 0,
+#undef V14471
+#define V14471 (V + 53829)
+ 0x621b, 0,
+#undef V14472
+#define V14472 (V + 53831)
+ 0x625d, 0,
+#undef V14473
+#define V14473 (V + 53833)
+ 0x62b1, 0,
+#undef V14474
+#define V14474 (V + 53835)
+ 0x62d4, 0,
+#undef V14475
+#define V14475 (V + 53837)
+ 0x6350, 0,
+#undef V14476
+#define V14476 (V + 53839)
+ 0x22b0c, 0,
+#undef V14477
+#define V14477 (V + 53841)
+ 0x633d, 0,
+#undef V14478
+#define V14478 (V + 53843)
+ 0x62fc, 0,
+#undef V14479
+#define V14479 (V + 53845)
+ 0x6368, 0,
+#undef V14480
+#define V14480 (V + 53847)
+ 0x6383, 0,
+#undef V14481
+#define V14481 (V + 53849)
+ 0x63e4, 0,
+#undef V14482
+#define V14482 (V + 53851)
+ 0x22bf1, 0,
+#undef V14483
+#define V14483 (V + 53853)
+ 0x6422, 0,
+#undef V14484
+#define V14484 (V + 53855)
+ 0x63c5, 0,
+#undef V14485
+#define V14485 (V + 53857)
+ 0x63a9, 0,
+#undef V14486
+#define V14486 (V + 53859)
+ 0x3a2e, 0,
+#undef V14487
+#define V14487 (V + 53861)
+ 0x6469, 0,
+#undef V14488
+#define V14488 (V + 53863)
+ 0x647e, 0,
+#undef V14489
+#define V14489 (V + 53865)
+ 0x649d, 0,
+#undef V14490
+#define V14490 (V + 53867)
+ 0x6477, 0,
+#undef V14491
+#define V14491 (V + 53869)
+ 0x3a6c, 0,
+#undef V14492
+#define V14492 (V + 53871)
+ 0x656c, 0,
+#undef V14493
+#define V14493 (V + 53873)
+ 0x2300a, 0,
+#undef V14494
+#define V14494 (V + 53875)
+ 0x65e3, 0,
+#undef V14495
+#define V14495 (V + 53877)
+ 0x66f8, 0,
+#undef V14496
+#define V14496 (V + 53879)
+ 0x6649, 0,
+#undef V14497
+#define V14497 (V + 53881)
+ 0x3b19, 0,
+#undef V14498
+#define V14498 (V + 53883)
+ 0x3b08, 0,
+#undef V14499
+#define V14499 (V + 53885)
+ 0x3ae4, 0,
+#undef V14500
+#define V14500 (V + 53887)
+ 0x5192, 0,
+#undef V14501
+#define V14501 (V + 53889)
+ 0x5195, 0,
+#undef V14502
+#define V14502 (V + 53891)
+ 0x6700, 0,
+#undef V14503
+#define V14503 (V + 53893)
+ 0x669c, 0,
+#undef V14504
+#define V14504 (V + 53895)
+ 0x80ad, 0,
+#undef V14505
+#define V14505 (V + 53897)
+ 0x43d9, 0,
+#undef V14506
+#define V14506 (V + 53899)
+ 0x6721, 0,
+#undef V14507
+#define V14507 (V + 53901)
+ 0x675e, 0,
+#undef V14508
+#define V14508 (V + 53903)
+ 0x6753, 0,
+#undef V14509
+#define V14509 (V + 53905)
+ 0x233c3, 0,
+#undef V14510
+#define V14510 (V + 53907)
+ 0x3b49, 0,
+#undef V14511
+#define V14511 (V + 53909)
+ 0x67fa, 0,
+#undef V14512
+#define V14512 (V + 53911)
+ 0x6785, 0,
+#undef V14513
+#define V14513 (V + 53913)
+ 0x6852, 0,
+#undef V14514
+#define V14514 (V + 53915)
+ 0x2346d, 0,
+#undef V14515
+#define V14515 (V + 53917)
+ 0x688e, 0,
+#undef V14516
+#define V14516 (V + 53919)
+ 0x681f, 0,
+#undef V14517
+#define V14517 (V + 53921)
+ 0x6914, 0,
+#undef V14518
+#define V14518 (V + 53923)
+ 0x6942, 0,
+#undef V14519
+#define V14519 (V + 53925)
+ 0x69a3, 0,
+#undef V14520
+#define V14520 (V + 53927)
+ 0x69ea, 0,
+#undef V14521
+#define V14521 (V + 53929)
+ 0x6aa8, 0,
+#undef V14522
+#define V14522 (V + 53931)
+ 0x236a3, 0,
+#undef V14523
+#define V14523 (V + 53933)
+ 0x6adb, 0,
+#undef V14524
+#define V14524 (V + 53935)
+ 0x3c18, 0,
+#undef V14525
+#define V14525 (V + 53937)
+ 0x6b21, 0,
+#undef V14526
+#define V14526 (V + 53939)
+ 0x238a7, 0,
+#undef V14527
+#define V14527 (V + 53941)
+ 0x6b54, 0,
+#undef V14528
+#define V14528 (V + 53943)
+ 0x3c4e, 0,
+#undef V14529
+#define V14529 (V + 53945)
+ 0x6b72, 0,
+#undef V14530
+#define V14530 (V + 53947)
+ 0x6b9f, 0,
+#undef V14531
+#define V14531 (V + 53949)
+ 0x6bbb, 0,
+#undef V14532
+#define V14532 (V + 53951)
+ 0x23a8d, 0,
+#undef V14533
+#define V14533 (V + 53953)
+ 0x21d0b, 0,
+#undef V14534
+#define V14534 (V + 53955)
+ 0x23afa, 0,
+#undef V14535
+#define V14535 (V + 53957)
+ 0x6c4e, 0,
+#undef V14536
+#define V14536 (V + 53959)
+ 0x23cbc, 0,
+#undef V14537
+#define V14537 (V + 53961)
+ 0x6cbf, 0,
+#undef V14538
+#define V14538 (V + 53963)
+ 0x6ccd, 0,
+#undef V14539
+#define V14539 (V + 53965)
+ 0x6c67, 0,
+#undef V14540
+#define V14540 (V + 53967)
+ 0x6d16, 0,
+#undef V14541
+#define V14541 (V + 53969)
+ 0x6d3e, 0,
+#undef V14542
+#define V14542 (V + 53971)
+ 0x6d69, 0,
+#undef V14543
+#define V14543 (V + 53973)
+ 0x6d78, 0,
+#undef V14544
+#define V14544 (V + 53975)
+ 0x6d85, 0,
+#undef V14545
+#define V14545 (V + 53977)
+ 0x23d1e, 0,
+#undef V14546
+#define V14546 (V + 53979)
+ 0x6d34, 0,
+#undef V14547
+#define V14547 (V + 53981)
+ 0x6e2f, 0,
+#undef V14548
+#define V14548 (V + 53983)
+ 0x6e6e, 0,
+#undef V14549
+#define V14549 (V + 53985)
+ 0x3d33, 0,
+#undef V14550
+#define V14550 (V + 53987)
+ 0x6ec7, 0,
+#undef V14551
+#define V14551 (V + 53989)
+ 0x23ed1, 0,
+#undef V14552
+#define V14552 (V + 53991)
+ 0x6df9, 0,
+#undef V14553
+#define V14553 (V + 53993)
+ 0x6f6e, 0,
+#undef V14554
+#define V14554 (V + 53995)
+ 0x23f5e, 0,
+#undef V14555
+#define V14555 (V + 53997)
+ 0x23f8e, 0,
+#undef V14556
+#define V14556 (V + 53999)
+ 0x6fc6, 0,
+#undef V14557
+#define V14557 (V + 54001)
+ 0x7039, 0,
+#undef V14558
+#define V14558 (V + 54003)
+ 0x701b, 0,
+#undef V14559
+#define V14559 (V + 54005)
+ 0x3d96, 0,
+#undef V14560
+#define V14560 (V + 54007)
+ 0x704a, 0,
+#undef V14561
+#define V14561 (V + 54009)
+ 0x707d, 0,
+#undef V14562
+#define V14562 (V + 54011)
+ 0x7077, 0,
+#undef V14563
+#define V14563 (V + 54013)
+ 0x70ad, 0,
+#undef V14564
+#define V14564 (V + 54015)
+ 0x20525, 0,
+#undef V14565
+#define V14565 (V + 54017)
+ 0x7145, 0,
+#undef V14566
+#define V14566 (V + 54019)
+ 0x24263, 0,
+#undef V14567
+#define V14567 (V + 54021)
+ 0x719c, 0,
+#undef V14568
+#define V14568 (V + 54023)
+ 0x243ab, 0,
+#undef V14569
+#define V14569 (V + 54025)
+ 0x7228, 0,
+#undef V14570
+#define V14570 (V + 54027)
+ 0x7250, 0,
+#undef V14571
+#define V14571 (V + 54029)
+ 0x24608, 0,
+#undef V14572
+#define V14572 (V + 54031)
+ 0x7280, 0,
+#undef V14573
+#define V14573 (V + 54033)
+ 0x7295, 0,
+#undef V14574
+#define V14574 (V + 54035)
+ 0x24735, 0,
+#undef V14575
+#define V14575 (V + 54037)
+ 0x24814, 0,
+#undef V14576
+#define V14576 (V + 54039)
+ 0x737a, 0,
+#undef V14577
+#define V14577 (V + 54041)
+ 0x738b, 0,
+#undef V14578
+#define V14578 (V + 54043)
+ 0x3eac, 0,
+#undef V14579
+#define V14579 (V + 54045)
+ 0x73a5, 0,
+#undef V14580
+#define V14580 (V + 54047)
+ 0x3eb8, 0,
+#undef V14581
+#define V14581 (V + 54049)
+ 0x7447, 0,
+#undef V14582
+#define V14582 (V + 54051)
+ 0x745c, 0,
+#undef V14583
+#define V14583 (V + 54053)
+ 0x7485, 0,
+#undef V14584
+#define V14584 (V + 54055)
+ 0x74ca, 0,
+#undef V14585
+#define V14585 (V + 54057)
+ 0x3f1b, 0,
+#undef V14586
+#define V14586 (V + 54059)
+ 0x7524, 0,
+#undef V14587
+#define V14587 (V + 54061)
+ 0x24c36, 0,
+#undef V14588
+#define V14588 (V + 54063)
+ 0x753e, 0,
+#undef V14589
+#define V14589 (V + 54065)
+ 0x24c92, 0,
+#undef V14590
+#define V14590 (V + 54067)
+ 0x2219f, 0,
+#undef V14591
+#define V14591 (V + 54069)
+ 0x7610, 0,
+#undef V14592
+#define V14592 (V + 54071)
+ 0x24fa1, 0,
+#undef V14593
+#define V14593 (V + 54073)
+ 0x24fb8, 0,
+#undef V14594
+#define V14594 (V + 54075)
+ 0x25044, 0,
+#undef V14595
+#define V14595 (V + 54077)
+ 0x3ffc, 0,
+#undef V14596
+#define V14596 (V + 54079)
+ 0x4008, 0,
+#undef V14597
+#define V14597 (V + 54081)
+ 0x250f3, 0,
+#undef V14598
+#define V14598 (V + 54083)
+ 0x250f2, 0,
+#undef V14599
+#define V14599 (V + 54085)
+ 0x25119, 0,
+#undef V14600
+#define V14600 (V + 54087)
+ 0x25133, 0,
+#undef V14601
+#define V14601 (V + 54089)
+ 0x771e, 0,
+#undef V14602
+#define V14602 (V + 54091)
+ 0x771f, 0,
+#undef V14603
+#define V14603 (V + 54093)
+ 0x778b, 0,
+#undef V14604
+#define V14604 (V + 54095)
+ 0x4046, 0,
+#undef V14605
+#define V14605 (V + 54097)
+ 0x4096, 0,
+#undef V14606
+#define V14606 (V + 54099)
+ 0x2541d, 0,
+#undef V14607
+#define V14607 (V + 54101)
+ 0x784e, 0,
+#undef V14608
+#define V14608 (V + 54103)
+ 0x40e3, 0,
+#undef V14609
+#define V14609 (V + 54105)
+ 0x25626, 0,
+#undef V14610
+#define V14610 (V + 54107)
+ 0x2569a, 0,
+#undef V14611
+#define V14611 (V + 54109)
+ 0x256c5, 0,
+#undef V14612
+#define V14612 (V + 54111)
+ 0x79eb, 0,
+#undef V14613
+#define V14613 (V + 54113)
+ 0x412f, 0,
+#undef V14614
+#define V14614 (V + 54115)
+ 0x7a4a, 0,
+#undef V14615
+#define V14615 (V + 54117)
+ 0x7a4f, 0,
+#undef V14616
+#define V14616 (V + 54119)
+ 0x2597c, 0,
+#undef V14617
+#define V14617 (V + 54121)
+ 0x25aa7, 0,
+#undef V14618
+#define V14618 (V + 54123)
+ 0x7aee, 0,
+#undef V14619
+#define V14619 (V + 54125)
+ 0x4202, 0,
+#undef V14620
+#define V14620 (V + 54127)
+ 0x25bab, 0,
+#undef V14621
+#define V14621 (V + 54129)
+ 0x7bc6, 0,
+#undef V14622
+#define V14622 (V + 54131)
+ 0x7bc9, 0,
+#undef V14623
+#define V14623 (V + 54133)
+ 0x4227, 0,
+#undef V14624
+#define V14624 (V + 54135)
+ 0x25c80, 0,
+#undef V14625
+#define V14625 (V + 54137)
+ 0x7cd2, 0,
+#undef V14626
+#define V14626 (V + 54139)
+ 0x42a0, 0,
+#undef V14627
+#define V14627 (V + 54141)
+ 0x7ce8, 0,
+#undef V14628
+#define V14628 (V + 54143)
+ 0x7ce3, 0,
+#undef V14629
+#define V14629 (V + 54145)
+ 0x7d00, 0,
+#undef V14630
+#define V14630 (V + 54147)
+ 0x25f86, 0,
+#undef V14631
+#define V14631 (V + 54149)
+ 0x7d63, 0,
+#undef V14632
+#define V14632 (V + 54151)
+ 0x4301, 0,
+#undef V14633
+#define V14633 (V + 54153)
+ 0x7dc7, 0,
+#undef V14634
+#define V14634 (V + 54155)
+ 0x7e02, 0,
+#undef V14635
+#define V14635 (V + 54157)
+ 0x7e45, 0,
+#undef V14636
+#define V14636 (V + 54159)
+ 0x4334, 0,
+#undef V14637
+#define V14637 (V + 54161)
+ 0x26228, 0,
+#undef V14638
+#define V14638 (V + 54163)
+ 0x26247, 0,
+#undef V14639
+#define V14639 (V + 54165)
+ 0x4359, 0,
+#undef V14640
+#define V14640 (V + 54167)
+ 0x262d9, 0,
+#undef V14641
+#define V14641 (V + 54169)
+ 0x7f7a, 0,
+#undef V14642
+#define V14642 (V + 54171)
+ 0x2633e, 0,
+#undef V14643
+#define V14643 (V + 54173)
+ 0x7f95, 0,
+#undef V14644
+#define V14644 (V + 54175)
+ 0x7ffa, 0,
+#undef V14645
+#define V14645 (V + 54177)
+ 0x264da, 0,
+#undef V14646
+#define V14646 (V + 54179)
+ 0x26523, 0,
+#undef V14647
+#define V14647 (V + 54181)
+ 0x8060, 0,
+#undef V14648
+#define V14648 (V + 54183)
+ 0x265a8, 0,
+#undef V14649
+#define V14649 (V + 54185)
+ 0x8070, 0,
+#undef V14650
+#define V14650 (V + 54187)
+ 0x2335f, 0,
+#undef V14651
+#define V14651 (V + 54189)
+ 0x43d5, 0,
+#undef V14652
+#define V14652 (V + 54191)
+ 0x80b2, 0,
+#undef V14653
+#define V14653 (V + 54193)
+ 0x8103, 0,
+#undef V14654
+#define V14654 (V + 54195)
+ 0x440b, 0,
+#undef V14655
+#define V14655 (V + 54197)
+ 0x813e, 0,
+#undef V14656
+#define V14656 (V + 54199)
+ 0x5ab5, 0,
+#undef V14657
+#define V14657 (V + 54201)
+ 0x267a7, 0,
+#undef V14658
+#define V14658 (V + 54203)
+ 0x267b5, 0,
+#undef V14659
+#define V14659 (V + 54205)
+ 0x23393, 0,
+#undef V14660
+#define V14660 (V + 54207)
+ 0x2339c, 0,
+#undef V14661
+#define V14661 (V + 54209)
+ 0x8204, 0,
+#undef V14662
+#define V14662 (V + 54211)
+ 0x8f9e, 0,
+#undef V14663
+#define V14663 (V + 54213)
+ 0x446b, 0,
+#undef V14664
+#define V14664 (V + 54215)
+ 0x8291, 0,
+#undef V14665
+#define V14665 (V + 54217)
+ 0x828b, 0,
+#undef V14666
+#define V14666 (V + 54219)
+ 0x829d, 0,
+#undef V14667
+#define V14667 (V + 54221)
+ 0x52b3, 0,
+#undef V14668
+#define V14668 (V + 54223)
+ 0x82b1, 0,
+#undef V14669
+#define V14669 (V + 54225)
+ 0x82b3, 0,
+#undef V14670
+#define V14670 (V + 54227)
+ 0x82bd, 0,
+#undef V14671
+#define V14671 (V + 54229)
+ 0x82e6, 0,
+#undef V14672
+#define V14672 (V + 54231)
+ 0x26b3c, 0,
+#undef V14673
+#define V14673 (V + 54233)
+ 0x831d, 0,
+#undef V14674
+#define V14674 (V + 54235)
+ 0x8363, 0,
+#undef V14675
+#define V14675 (V + 54237)
+ 0x83ad, 0,
+#undef V14676
+#define V14676 (V + 54239)
+ 0x8323, 0,
+#undef V14677
+#define V14677 (V + 54241)
+ 0x83bd, 0,
+#undef V14678
+#define V14678 (V + 54243)
+ 0x83e7, 0,
+#undef V14679
+#define V14679 (V + 54245)
+ 0x8353, 0,
+#undef V14680
+#define V14680 (V + 54247)
+ 0x83ca, 0,
+#undef V14681
+#define V14681 (V + 54249)
+ 0x83cc, 0,
+#undef V14682
+#define V14682 (V + 54251)
+ 0x83dc, 0,
+#undef V14683
+#define V14683 (V + 54253)
+ 0x26c36, 0,
+#undef V14684
+#define V14684 (V + 54255)
+ 0x26d6b, 0,
+#undef V14685
+#define V14685 (V + 54257)
+ 0x26cd5, 0,
+#undef V14686
+#define V14686 (V + 54259)
+ 0x452b, 0,
+#undef V14687
+#define V14687 (V + 54261)
+ 0x84f1, 0,
+#undef V14688
+#define V14688 (V + 54263)
+ 0x84f3, 0,
+#undef V14689
+#define V14689 (V + 54265)
+ 0x8516, 0,
+#undef V14690
+#define V14690 (V + 54267)
+ 0x273ca, 0,
+#undef V14691
+#define V14691 (V + 54269)
+ 0x8564, 0,
+#undef V14692
+#define V14692 (V + 54271)
+ 0x26f2c, 0,
+#undef V14693
+#define V14693 (V + 54273)
+ 0x455d, 0,
+#undef V14694
+#define V14694 (V + 54275)
+ 0x4561, 0,
+#undef V14695
+#define V14695 (V + 54277)
+ 0x26fb1, 0,
+#undef V14696
+#define V14696 (V + 54279)
+ 0x270d2, 0,
+#undef V14697
+#define V14697 (V + 54281)
+ 0x456b, 0,
+#undef V14698
+#define V14698 (V + 54283)
+ 0x8650, 0,
+#undef V14699
+#define V14699 (V + 54285)
+ 0x8667, 0,
+#undef V14700
+#define V14700 (V + 54287)
+ 0x8669, 0,
+#undef V14701
+#define V14701 (V + 54289)
+ 0x86a9, 0,
+#undef V14702
+#define V14702 (V + 54291)
+ 0x8688, 0,
+#undef V14703
+#define V14703 (V + 54293)
+ 0x870e, 0,
+#undef V14704
+#define V14704 (V + 54295)
+ 0x86e2, 0,
+#undef V14705
+#define V14705 (V + 54297)
+ 0x8728, 0,
+#undef V14706
+#define V14706 (V + 54299)
+ 0x876b, 0,
+#undef V14707
+#define V14707 (V + 54301)
+ 0x8786, 0,
+#undef V14708
+#define V14708 (V + 54303)
+ 0x45d7, 0,
+#undef V14709
+#define V14709 (V + 54305)
+ 0x87e1, 0,
+#undef V14710
+#define V14710 (V + 54307)
+ 0x8801, 0,
+#undef V14711
+#define V14711 (V + 54309)
+ 0x45f9, 0,
+#undef V14712
+#define V14712 (V + 54311)
+ 0x8860, 0,
+#undef V14713
+#define V14713 (V + 54313)
+ 0x27667, 0,
+#undef V14714
+#define V14714 (V + 54315)
+ 0x88d7, 0,
+#undef V14715
+#define V14715 (V + 54317)
+ 0x88de, 0,
+#undef V14716
+#define V14716 (V + 54319)
+ 0x4635, 0,
+#undef V14717
+#define V14717 (V + 54321)
+ 0x88fa, 0,
+#undef V14718
+#define V14718 (V + 54323)
+ 0x34bb, 0,
+#undef V14719
+#define V14719 (V + 54325)
+ 0x278ae, 0,
+#undef V14720
+#define V14720 (V + 54327)
+ 0x27966, 0,
+#undef V14721
+#define V14721 (V + 54329)
+ 0x46be, 0,
+#undef V14722
+#define V14722 (V + 54331)
+ 0x46c7, 0,
+#undef V14723
+#define V14723 (V + 54333)
+ 0x8aa0, 0,
+#undef V14724
+#define V14724 (V + 54335)
+ 0x27ca8, 0,
+#undef V14725
+#define V14725 (V + 54337)
+ 0x8cab, 0,
+#undef V14726
+#define V14726 (V + 54339)
+ 0x8cc1, 0,
+#undef V14727
+#define V14727 (V + 54341)
+ 0x8d1b, 0,
+#undef V14728
+#define V14728 (V + 54343)
+ 0x8d77, 0,
+#undef V14729
+#define V14729 (V + 54345)
+ 0x27f2f, 0,
+#undef V14730
+#define V14730 (V + 54347)
+ 0x20804, 0,
+#undef V14731
+#define V14731 (V + 54349)
+ 0x8dcb, 0,
+#undef V14732
+#define V14732 (V + 54351)
+ 0x8dbc, 0,
+#undef V14733
+#define V14733 (V + 54353)
+ 0x8df0, 0,
+#undef V14734
+#define V14734 (V + 54355)
+ 0x208de, 0,
+#undef V14735
+#define V14735 (V + 54357)
+ 0x8ed4, 0,
+#undef V14736
+#define V14736 (V + 54359)
+ 0x285d2, 0,
+#undef V14737
+#define V14737 (V + 54361)
+ 0x285ed, 0,
+#undef V14738
+#define V14738 (V + 54363)
+ 0x9094, 0,
+#undef V14739
+#define V14739 (V + 54365)
+ 0x90f1, 0,
+#undef V14740
+#define V14740 (V + 54367)
+ 0x9111, 0,
+#undef V14741
+#define V14741 (V + 54369)
+ 0x2872e, 0,
+#undef V14742
+#define V14742 (V + 54371)
+ 0x911b, 0,
+#undef V14743
+#define V14743 (V + 54373)
+ 0x9238, 0,
+#undef V14744
+#define V14744 (V + 54375)
+ 0x92d7, 0,
+#undef V14745
+#define V14745 (V + 54377)
+ 0x92d8, 0,
+#undef V14746
+#define V14746 (V + 54379)
+ 0x927c, 0,
+#undef V14747
+#define V14747 (V + 54381)
+ 0x93f9, 0,
+#undef V14748
+#define V14748 (V + 54383)
+ 0x9415, 0,
+#undef V14749
+#define V14749 (V + 54385)
+ 0x28bfa, 0,
+#undef V14750
+#define V14750 (V + 54387)
+ 0x958b, 0,
+#undef V14751
+#define V14751 (V + 54389)
+ 0x4995, 0,
+#undef V14752
+#define V14752 (V + 54391)
+ 0x95b7, 0,
+#undef V14753
+#define V14753 (V + 54393)
+ 0x28d77, 0,
+#undef V14754
+#define V14754 (V + 54395)
+ 0x49e6, 0,
+#undef V14755
+#define V14755 (V + 54397)
+ 0x96c3, 0,
+#undef V14756
+#define V14756 (V + 54399)
+ 0x5db2, 0,
+#undef V14757
+#define V14757 (V + 54401)
+ 0x9723, 0,
+#undef V14758
+#define V14758 (V + 54403)
+ 0x29145, 0,
+#undef V14759
+#define V14759 (V + 54405)
+ 0x2921a, 0,
+#undef V14760
+#define V14760 (V + 54407)
+ 0x4a6e, 0,
+#undef V14761
+#define V14761 (V + 54409)
+ 0x4a76, 0,
+#undef V14762
+#define V14762 (V + 54411)
+ 0x97e0, 0,
+#undef V14763
+#define V14763 (V + 54413)
+ 0x2940a, 0,
+#undef V14764
+#define V14764 (V + 54415)
+ 0x4ab2, 0,
+#undef V14765
+#define V14765 (V + 54417)
+ 0x29496, 0,
+#undef V14766
+#define V14766 (V + 54419)
+ 0x9829, 0,
+#undef V14767
+#define V14767 (V + 54421)
+ 0x295b6, 0,
+#undef V14768
+#define V14768 (V + 54423)
+ 0x98e2, 0,
+#undef V14769
+#define V14769 (V + 54425)
+ 0x4b33, 0,
+#undef V14770
+#define V14770 (V + 54427)
+ 0x9929, 0,
+#undef V14771
+#define V14771 (V + 54429)
+ 0x99a7, 0,
+#undef V14772
+#define V14772 (V + 54431)
+ 0x99c2, 0,
+#undef V14773
+#define V14773 (V + 54433)
+ 0x99fe, 0,
+#undef V14774
+#define V14774 (V + 54435)
+ 0x4bce, 0,
+#undef V14775
+#define V14775 (V + 54437)
+ 0x29b30, 0,
+#undef V14776
+#define V14776 (V + 54439)
+ 0x9c40, 0,
+#undef V14777
+#define V14777 (V + 54441)
+ 0x9cfd, 0,
+#undef V14778
+#define V14778 (V + 54443)
+ 0x4cce, 0,
+#undef V14779
+#define V14779 (V + 54445)
+ 0x4ced, 0,
+#undef V14780
+#define V14780 (V + 54447)
+ 0x9d67, 0,
+#undef V14781
+#define V14781 (V + 54449)
+ 0x2a0ce, 0,
+#undef V14782
+#define V14782 (V + 54451)
+ 0x4cf8, 0,
+#undef V14783
+#define V14783 (V + 54453)
+ 0x2a105, 0,
+#undef V14784
+#define V14784 (V + 54455)
+ 0x2a20e, 0,
+#undef V14785
+#define V14785 (V + 54457)
+ 0x2a291, 0,
+#undef V14786
+#define V14786 (V + 54459)
+ 0x4d56, 0,
+#undef V14787
+#define V14787 (V + 54461)
+ 0x9efe, 0,
+#undef V14788
+#define V14788 (V + 54463)
+ 0x9f05, 0,
+#undef V14789
+#define V14789 (V + 54465)
+ 0x9f0f, 0,
+#undef V14790
+#define V14790 (V + 54467)
+ 0x9f16, 0,
+#undef V14791
+#define V14791 (V + 54469)
+ 0x2a600, 0,
+ };
+
+ static const NUnicode::NPrivate::TDecompositionTable::TValuePtr P[][32] = {
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[0]
+ {
+ V0, 0, 0, 0, 0, 0, 0, 0,
+ V1, 0, V2, 0, 0, 0, 0, V3,
+ 0, 0, V4, V5, V6, V7, 0, 0,
+ V8, V9, V10, 0, V11, V12, V13, 0,
+ }, // P[1]
+ {
+ V14, V15, V16, V17, V18, V19, 0, V20,
+ V21, V22, V23, V24, V25, V26, V27, V28,
+ 0, V29, V30, V31, V32, V33, V34, 0,
+ 0, V35, V36, V37, V38, V39, 0, 0,
+ }, // P[2]
+ {
+ V40, V41, V42, V43, V44, V45, 0, V46,
+ V47, V48, V49, V50, V51, V52, V53, V54,
+ 0, V55, V56, V57, V58, V59, V60, 0,
+ 0, V61, V62, V63, V64, V65, 0, V66,
+ }, // P[3]
+ {
+ V67, V68, V69, V70, V71, V72, V73, V74,
+ V75, V76, V77, V78, V79, V80, V81, V82,
+ 0, 0, V83, V84, V85, V86, V87, V88,
+ V89, V90, V91, V92, V93, V94, V95, V96,
+ }, // P[4]
+ {
+ V97, V98, V99, V100, V101, V102, 0, 0,
+ V103, V104, V105, V106, V107, V108, V109, V110,
+ V111, 0, V112, V113, V114, V115, V116, V117,
+ 0, V118, V119, V120, V121, V122, V123, V124,
+ }, // P[5]
+ {
+ V125, 0, 0, V126, V127, V128, V129, V130,
+ V131, V132, 0, 0, V133, V134, V135, V136,
+ V137, V138, 0, 0, V139, V140, V141, V142,
+ V143, V144, V145, V146, V147, V148, V149, V150,
+ }, // P[6]
+ {
+ V151, V152, V153, V154, V155, V156, 0, 0,
+ V157, V158, V159, V160, V161, V162, V163, V164,
+ V165, V166, V167, V168, V169, V170, V171, V172,
+ V173, V174, V175, V176, V177, V178, V179, V180,
+ }, // P[7]
+ {
+ V181, V182, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, V183,
+ V184, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[8]
+ {
+ 0, 0, 0, 0, V185, V186, V187, V188,
+ V189, V190, V191, V192, V193, V194, V195, V196,
+ V197, V198, V199, V200, V201, V202, V203, V204,
+ V205, V206, V207, V208, V209, 0, V210, V211,
+ }, // P[9]
+ {
+ V212, V213, V214, V215, 0, 0, V216, V217,
+ V218, V219, V220, V221, V222, V223, V224, V225,
+ V226, V227, V228, V229, V230, V231, 0, 0,
+ V232, V233, V234, V235, V236, V237, V238, V239,
+ }, // P[10]
+ {
+ V240, V241, V242, V243, V244, V245, V246, V247,
+ V248, V249, V250, V251, V252, V253, V254, V255,
+ V256, V257, V258, V259, V260, V261, V262, V263,
+ V264, V265, V266, V267, 0, 0, V268, V269,
+ }, // P[11]
+ {
+ 0, 0, 0, 0, 0, 0, V270, V271,
+ V272, V273, V274, V275, V276, V277, V278, V279,
+ V280, V281, V282, V283, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[12]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V284, V285, V286, V287, V288, V289, V290, V291,
+ V292, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[13]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V293, V294, V295, V296, V297, V298, 0, 0,
+ }, // P[14]
+ {
+ V299, V300, V180, V301, V302, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[15]
+ {
+ V303, V304, 0, V305, V306, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[16]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V307, 0, 0, 0,
+ 0, 0, V308, 0, 0, 0, V309, 0,
+ }, // P[17]
+ {
+ 0, 0, 0, 0, V6, V310, V311, V312,
+ V313, V314, V315, 0, V316, 0, V317, V318,
+ V319, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[18]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V320, V321, V322, V323, V324, V325,
+ V326, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[19]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V327, V328, V329, V330, V331, 0,
+ V332, V333, V334, V317, V321, V335, V336, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[20]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V337, V338, V339, 0, V340, V341, 0, 0,
+ 0, V342, 0, 0, 0, 0, 0, 0,
+ }, // P[21]
+ {
+ V343, V344, 0, V345, 0, 0, 0, V346,
+ 0, 0, 0, 0, V347, V348, V349, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, V350, 0, 0, 0, 0, 0, 0,
+ }, // P[22]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, V351, 0, 0, 0, 0, 0, 0,
+ }, // P[23]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V352, V353, 0, V354, 0, 0, 0, V355,
+ 0, 0, 0, 0, V356, V357, V358, 0,
+ }, // P[24]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, V359, V360,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[25]
+ {
+ 0, V361, V362, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V363, V364, V365, V366, 0, 0, V367, V368,
+ 0, 0, V369, V370, V371, V372, V373, V374,
+ }, // P[26]
+ {
+ 0, 0, V375, V376, V377, V378, V379, V380,
+ 0, 0, V381, V382, V383, V384, V385, V386,
+ V387, V388, V389, V390, V391, V392, 0, 0,
+ V393, V394, 0, 0, 0, 0, 0, 0,
+ }, // P[27]
+ {
+ 0, 0, 0, 0, 0, 0, 0, V395,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[28]
+ {
+ 0, 0, V396, V397, V398, V399, V400, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[29]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, V401, V402, V403,
+ V404, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[30]
+ {
+ V405, 0, V406, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V407, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[31]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, V408, 0, 0, 0, 0, 0, 0,
+ 0, V409, 0, 0, V410, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[32]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V411, V412, V413, V414, V415, V416, V417, V418,
+ }, // P[33]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V419, V420, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V421, V422, 0, V423,
+ }, // P[34]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V424, 0, 0, V425, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[35]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, V426, V427, V428, 0, 0, V429, 0,
+ }, // P[36]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V430, 0, 0, V431, V432, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V433, V434, 0, 0,
+ }, // P[37]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V435, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[38]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V436, V437, V438, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[39]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V439, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[40]
+ {
+ V440, 0, 0, 0, 0, 0, 0, V441,
+ V442, 0, V443, V444, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[41]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V445, V446, V447, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[42]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V448, 0, V449, V450, V451, 0,
+ }, // P[43]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V452, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[44]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V453, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[45]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V454, V455, 0, 0,
+ }, // P[46]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V456, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[47]
+ {
+ 0, 0, 0, V457, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, V458, 0, 0,
+ 0, 0, V459, 0, 0, 0, 0, V460,
+ 0, 0, 0, 0, V461, 0, 0, 0,
+ }, // P[48]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, V462, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V463, 0, V464, V465, V466,
+ V467, V468, 0, 0, 0, 0, 0, 0,
+ }, // P[49]
+ {
+ 0, V469, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V470, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, V471, 0, 0,
+ }, // P[50]
+ {
+ 0, 0, V472, 0, 0, 0, 0, V473,
+ 0, 0, 0, 0, V474, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, V475, 0, 0, 0, 0, 0, 0,
+ }, // P[51]
+ {
+ 0, 0, 0, 0, 0, 0, V476, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[52]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V477, 0, 0, 0,
+ }, // P[53]
+ {
+ 0, 0, 0, 0, 0, 0, V478, 0,
+ V479, 0, V480, 0, V481, 0, V482, 0,
+ 0, 0, V483, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[54]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V484, 0, V485, 0, 0,
+ }, // P[55]
+ {
+ V486, V487, 0, V488, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[56]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V489, V490, V491, 0,
+ V492, V493, V494, V495, V496, V497, V498, V499,
+ V500, V501, V502, 0, V503, V504, V505, V506,
+ }, // P[57]
+ {
+ V507, V508, V509, V2, V510, V511, V512, V513,
+ V514, V515, V516, V517, V518, V519, 0, V520,
+ V521, V522, V10, V523, V524, V525, V526, V527,
+ V528, V529, V530, V531, V532, V332, V533, V534,
+ }, // P[58]
+ {
+ V335, V535, V536, V287, V528, V531, V332, V533,
+ V338, V335, V535, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V537, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[59]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V538, V539, V540, V541, V518,
+ }, // P[60]
+ {
+ V542, V543, V544, V545, V546, V547, V548, V549,
+ V550, V551, V552, V553, V554, V555, V556, V557,
+ V558, V559, V560, V561, V562, V563, V564, V565,
+ V566, V567, V568, V569, V570, V571, V572, V333,
+ }, // P[61]
+ {
+ V573, V574, V575, V576, V577, V578, V579, V580,
+ V581, V582, V583, V584, V585, V586, V587, V588,
+ V589, V590, V591, V592, V593, V594, V595, V596,
+ V597, V598, V599, V600, V601, V602, V603, V604,
+ }, // P[62]
+ {
+ V605, V606, V607, V608, V609, V610, V611, V612,
+ V613, V614, V615, V616, V617, V618, V619, V620,
+ V621, V622, V623, V624, V625, V626, V627, V628,
+ V629, V630, V631, V632, V633, V634, V635, V636,
+ }, // P[63]
+ {
+ V637, V638, V639, V640, V641, V642, V643, V644,
+ V645, V646, V647, V648, V649, V650, V651, V652,
+ V653, V654, V655, V656, V657, V658, V659, V660,
+ V661, V662, V663, V664, V665, V666, V667, V668,
+ }, // P[64]
+ {
+ V669, V670, V671, V672, V673, V674, V675, V676,
+ V677, V678, V679, V680, V681, V682, V683, V684,
+ V685, V686, V687, V688, V689, V690, V691, V692,
+ V693, V694, V695, V696, V697, V698, V699, V700,
+ }, // P[65]
+ {
+ V701, V702, V703, V704, V705, V706, V707, V708,
+ V709, V710, V711, V712, V713, V714, V715, V716,
+ V717, V718, V719, V720, V721, V722, V723, V724,
+ V725, V726, V727, V670, 0, 0, 0, 0,
+ }, // P[66]
+ {
+ V728, V729, V730, V731, V732, V733, V734, V735,
+ V736, V737, V738, V739, V740, V741, V742, V743,
+ V744, V745, V746, V747, V748, V749, V750, V751,
+ V752, V753, V754, V755, V756, V757, V758, V759,
+ }, // P[67]
+ {
+ V760, V761, V762, V763, V764, V765, V766, V767,
+ V768, V769, V770, V771, V772, V773, V774, V775,
+ V776, V777, V778, V779, V780, V781, V782, V783,
+ V784, V785, V786, V787, V788, V789, V790, V791,
+ }, // P[68]
+ {
+ V792, V793, V794, V795, V796, V797, V798, V799,
+ V800, V801, V802, V803, V804, V805, V806, V807,
+ V808, V809, V810, V811, V812, V813, V814, V815,
+ V816, V817, 0, 0, 0, 0, 0, 0,
+ }, // P[69]
+ {
+ V818, V819, V820, V821, V822, V823, V824, V825,
+ V826, V827, V828, V829, V830, V831, V832, V833,
+ V834, V835, V836, V837, V838, V839, 0, 0,
+ V840, V841, V842, V843, V844, V845, 0, 0,
+ }, // P[70]
+ {
+ V846, V847, V848, V849, V850, V851, V852, V853,
+ V854, V855, V856, V857, V858, V859, V860, V861,
+ V862, V863, V864, V865, V866, V867, V868, V869,
+ V870, V871, V872, V873, V874, V875, V876, V877,
+ }, // P[71]
+ {
+ V878, V879, V880, V881, V882, V883, 0, 0,
+ V884, V885, V886, V887, V888, V889, 0, 0,
+ V890, V891, V892, V893, V894, V895, V896, V897,
+ 0, V898, 0, V899, 0, V900, 0, V901,
+ }, // P[72]
+ {
+ V902, V903, V904, V905, V906, V907, V908, V909,
+ V910, V911, V912, V913, V914, V915, V916, V917,
+ V918, V322, V919, V323, V920, V324, V921, V325,
+ V922, V329, V923, V330, V924, V331, 0, 0,
+ }, // P[73]
+ {
+ V925, V926, V927, V928, V929, V930, V931, V932,
+ V933, V934, V935, V936, V937, V938, V939, V940,
+ V941, V942, V943, V944, V945, V946, V947, V948,
+ V949, V950, V951, V952, V953, V954, V955, V956,
+ }, // P[74]
+ {
+ V957, V958, V959, V960, V961, V962, V963, V964,
+ V965, V966, V967, V968, V969, V970, V971, V972,
+ V973, V974, V975, V976, V977, 0, V978, V979,
+ V980, V981, V982, V311, V983, V984, V985, V984,
+ }, // P[75]
+ {
+ V986, V987, V988, V989, V990, 0, V991, V992,
+ V993, V313, V994, V314, V995, V996, V997, V998,
+ V999, V1000, V1001, V319, 0, 0, V1002, V1003,
+ V1004, V1005, V1006, V315, 0, V1007, V1008, V1009,
+ }, // P[76]
+ {
+ V1010, V1011, V1012, V326, V1013, V1014, V1015, V1016,
+ V1017, V1018, V1019, V317, V1020, V1021, V310, V1022,
+ 0, 0, V1023, V1024, V1025, 0, V1026, V1027,
+ V1028, V316, V1029, V318, V1030, V6, V1031, 0,
+ }, // P[77]
+ {
+ V0, V0, V0, V0, V0, V0, V0, V0,
+ V0, V0, V0, 0, 0, 0, 0, 0,
+ 0, V1032, 0, 0, 0, 0, 0, V1033,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[78]
+ {
+ 0, 0, 0, 0, V1034, V1035, V1036, 0,
+ 0, 0, 0, 0, 0, 0, 0, V0,
+ 0, 0, 0, V1037, V1038, 0, V1039, V1040,
+ 0, 0, 0, 0, V1041, 0, V1042, 0,
+ }, // P[79]
+ {
+ 0, 0, 0, 0, 0, 0, 0, V1043,
+ V1044, V1045, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, V1046,
+ 0, 0, 0, 0, 0, 0, 0, V0,
+ }, // P[80]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V1047, V536, 0, 0, V1048, V1049, V1050, V1051,
+ V1052, V1053, V1054, V1055, V1056, V1057, V1058, V1059,
+ }, // P[81]
+ {
+ V1047, V9, V4, V5, V1048, V1049, V1050, V1051,
+ V1052, V1053, V1054, V1055, V1056, V1057, V1058, 0,
+ V2, V515, V10, V301, V516, V284, V520, V300,
+ V521, V1059, V526, V180, V527, 0, 0, 0,
+ }, // P[82]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V1060, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[83]
+ {
+ V1061, V1062, V1063, V1064, 0, V1065, V1066, V1067,
+ 0, V1068, V519, V496, V496, V496, V284, V1069,
+ V497, V497, V500, V300, 0, V502, V1070, 0,
+ 0, V505, V1071, V506, V506, V506, 0, 0,
+ }, // P[84]
+ {
+ V1072, V1073, V1074, 0, V1075, 0, V1076, 0,
+ V1075, 0, V499, V19, V491, V1063, 0, V515,
+ V493, V1077, 0, V501, V10, V1078, V1079, V1080,
+ V1081, V536, 0, V1082, V336, V533, V1083, V1084,
+ }, // P[85]
+ {
+ V1085, 0, 0, 0, 0, V492, V514, V515,
+ V536, V286, 0, 0, 0, 0, 0, 0,
+ V1086, V1087, V1088, V1089, V1090, V1091, V1092, V1093,
+ V1094, V1095, V1096, V1097, V1098, V1099, V1100, V1101,
+ }, // P[86]
+ {
+ V497, V1102, V1103, V1104, V1105, V1106, V1107, V1108,
+ V1109, V1110, V1111, V1112, V500, V1063, V492, V501,
+ V536, V1113, V1114, V1115, V531, V1116, V1117, V1118,
+ V1119, V301, V1120, V1121, V300, V539, V514, V521,
+ }, // P[87]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, V1122, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V1123, V1124, 0, 0, 0, 0,
+ }, // P[88]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, V1125, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[89]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, V1126, V1127, V1128,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[90]
+ {
+ 0, 0, 0, 0, V1129, 0, 0, 0,
+ 0, V1130, 0, 0, V1131, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[91]
+ {
+ 0, 0, 0, 0, V1132, 0, V1133, 0,
+ 0, 0, 0, 0, V1134, V1135, 0, V1136,
+ V1137, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[92]
+ {
+ 0, V1138, 0, 0, V1139, 0, 0, V1140,
+ 0, V1141, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[93]
+ {
+ V1142, 0, V1143, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, V1144, V1145, V1146,
+ V1147, V1148, 0, 0, V1149, V1150, 0, 0,
+ V1151, V1152, 0, 0, 0, 0, 0, 0,
+ }, // P[94]
+ {
+ V1153, V1154, 0, 0, V1155, V1156, 0, 0,
+ V1157, V1158, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[95]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V1159, V1160, V1161, V1162,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[96]
+ {
+ V1163, V1164, V1165, V1166, 0, 0, 0, 0,
+ 0, 0, V1167, V1168, V1169, V1170, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[97]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, V1171, V1172, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[98]
+ {
+ V9, V4, V5, V1048, V1049, V1050, V1051, V1052,
+ V1053, V1173, V1174, V1175, V1176, V1177, V1178, V1179,
+ V1180, V1181, V1182, V1183, V1184, V1185, V1186, V1187,
+ V1188, V1189, V1190, V1191, V1192, V1193, V1194, V1195,
+ }, // P[99]
+ {
+ V1196, V1197, V1198, V1199, V1200, V1201, V1202, V1203,
+ V1204, V1205, V1206, V1207, V1208, V1209, V1210, V1211,
+ V1212, V1213, V1214, V1215, V1216, V1217, V1218, V1219,
+ V1220, V1221, V1222, V1223, V1224, V1225, V1226, V1227,
+ }, // P[100]
+ {
+ V1228, V1229, V1230, V1231, V1232, V1233, V1234, V1235,
+ V1236, V1237, V1238, V1239, V1240, V1241, V1242, V1243,
+ V1244, V1245, V1246, V1247, V1248, V1249, V489, V491,
+ V1063, V492, V493, V1077, V495, V496, V497, V498,
+ }, // P[101]
+ {
+ V499, V500, V501, V502, V503, V505, V1071, V506,
+ V1250, V507, V508, V1105, V509, V1110, V1251, V1075,
+ V2, V513, V539, V514, V515, V542, V519, V284,
+ V536, V286, V520, V300, V521, V1059, V10, V526,
+ }, // P[102]
+ {
+ V1252, V287, V180, V527, V528, V531, V291, V301,
+ V292, V569, V1047, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[103]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V1253, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[104]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V1254, V1255, V1256, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[105]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V1257, 0, 0, 0,
+ }, // P[106]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V286, V1105, 0, 0,
+ }, // P[107]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, V1258,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[108]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, V1259,
+ }, // P[109]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V1260, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[110]
+ {
+ V1261, V1262, V1263, V1264, V1265, V1266, V1267, V1268,
+ V1269, V1270, V1271, V1272, V1273, V1274, V1275, V1276,
+ V1277, V1278, V1279, V1280, V1281, V1282, V1283, V1284,
+ V1285, V1286, V1287, V1288, V1289, V1290, V1291, V1292,
+ }, // P[111]
+ {
+ V1293, V1294, V1295, V1296, V1297, V1298, V1299, V1300,
+ V1301, V1302, V1303, V1304, V1305, V1306, V1307, V1308,
+ V1309, V1310, V1311, V1312, V1313, V1314, V1315, V1316,
+ V1317, V1318, V1319, V1320, V1321, V1322, V1323, V1324,
+ }, // P[112]
+ {
+ V1325, V1326, V1327, V1328, V1329, V1330, V1331, V1332,
+ V1333, V1334, V1335, V1336, V1337, V1338, V1339, V1340,
+ V1341, V1342, V1343, V1344, V1345, V1346, V1347, V1348,
+ V1349, V1350, V1351, V1352, V1353, V1354, V1355, V1356,
+ }, // P[113]
+ {
+ V1357, V1358, V1359, V1360, V1361, V1362, V1363, V1364,
+ V1365, V1366, V1367, V1368, V1369, V1370, V1371, V1372,
+ V1373, V1374, V1375, V1376, V1377, V1378, V1379, V1380,
+ V1381, V1382, V1383, V1384, V1385, V1386, V1387, V1388,
+ }, // P[114]
+ {
+ V1389, V1390, V1391, V1392, V1393, V1394, V1395, V1396,
+ V1397, V1398, V1399, V1400, V1401, V1402, V1403, V1404,
+ V1405, V1406, V1407, V1408, V1409, V1410, V1411, V1412,
+ V1413, V1414, V1415, V1416, V1417, V1418, V1419, V1420,
+ }, // P[115]
+ {
+ V1421, V1422, V1423, V1424, V1425, V1426, V1427, V1428,
+ V1429, V1430, V1431, V1432, V1433, V1434, V1435, V1436,
+ V1437, V1438, V1439, V1440, V1441, V1442, V1443, V1444,
+ V1445, V1446, V1447, V1448, V1449, V1450, V1451, V1452,
+ }, // P[116]
+ {
+ V1453, V1454, V1455, V1456, V1457, V1458, V1459, V1460,
+ V1461, V1462, V1463, V1464, V1465, V1466, V1467, V1468,
+ V1469, V1470, V1471, V1472, V1473, V1474, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[117]
+ {
+ V0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[118]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, V1475, 0,
+ V1284, V1476, V1477, 0, 0, 0, 0, 0,
+ }, // P[119]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V1478, 0, V1479, 0,
+ V1480, 0, V1481, 0, V1482, 0, V1483, 0,
+ V1484, 0, V1485, 0, V1486, 0, V1487, 0,
+ }, // P[120]
+ {
+ V1488, 0, V1489, 0, 0, V1490, 0, V1491,
+ 0, V1492, 0, 0, 0, 0, 0, 0,
+ V1493, V1494, 0, V1495, V1496, 0, V1497, V1498,
+ 0, V1499, V1500, 0, V1501, V1502, 0, 0,
+ }, // P[121]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V1503, 0, 0, 0,
+ 0, 0, 0, V1504, V1505, 0, V1506, V1507,
+ }, // P[122]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V1508, 0, V1509, 0,
+ V1510, 0, V1511, 0, V1512, 0, V1513, 0,
+ V1514, 0, V1515, 0, V1516, 0, V1517, 0,
+ }, // P[123]
+ {
+ V1518, 0, V1519, 0, 0, V1520, 0, V1521,
+ 0, V1522, 0, 0, 0, 0, 0, 0,
+ V1523, V1524, 0, V1525, V1526, 0, V1527, V1528,
+ 0, V1529, V1530, 0, V1531, V1532, 0, 0,
+ }, // P[124]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V1533, 0, 0, V1534,
+ V1535, V1536, V1537, 0, 0, 0, V1538, V1539,
+ }, // P[125]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, V1540, V1541, V1542, V1543, V1544, V1545, V1546,
+ V1547, V1548, V1549, V1550, V1551, V1552, V1553, V1554,
+ }, // P[126]
+ {
+ V1555, V1556, V1557, V1558, V1559, V1560, V1561, V1562,
+ V1563, V1564, V1565, V1566, V1567, V1568, V1569, V1570,
+ V1571, V1572, V1573, V1574, V1575, V1576, V1577, V1578,
+ V1579, V1580, V1581, V1582, V1583, V1584, V1585, V1586,
+ }, // P[127]
+ {
+ V1587, V1588, V1589, V1590, V1591, V1592, V1593, V1594,
+ V1595, V1596, V1597, V1598, V1599, V1600, V1601, V1602,
+ V1603, V1604, V1605, V1606, V1607, V1608, V1609, V1610,
+ V1611, V1612, V1613, V1614, V1615, V1616, V1617, V1618,
+ }, // P[128]
+ {
+ V1619, V1620, V1621, V1622, V1623, V1624, V1625, V1626,
+ V1627, V1628, V1629, V1630, V1631, V1632, V1633, 0,
+ 0, 0, V1261, V1267, V1634, V1635, V1636, V1637,
+ V1638, V1639, V1265, V1640, V1641, V1642, V1643, V1269,
+ }, // P[129]
+ {
+ V1644, V1645, V1646, V1647, V1648, V1649, V1650, V1651,
+ V1652, V1653, V1654, V1655, V1656, V1657, V1658, V1659,
+ V1660, V1661, V1662, V1663, V1664, V1665, V1666, V1667,
+ V1668, V1669, V1670, V1671, V1672, V1673, V1674, 0,
+ }, // P[130]
+ {
+ V1675, V1676, V1677, V1678, V1679, V1680, V1681, V1682,
+ V1683, V1684, V1685, V1686, V1687, V1688, V1689, V1690,
+ V1691, V1692, V1693, V1694, V1695, V1696, V1697, V1698,
+ V1699, V1700, V1701, V1702, V1703, V1704, V1705, V1706,
+ }, // P[131]
+ {
+ V1707, V1708, V1709, V1710, V1711, V1712, V1327, V1713,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V1714, V1715, V1716, V1717, V1718, V1719, V1720, V1721,
+ V1722, V1723, V1724, V1725, V1726, V1727, V1728, V1729,
+ }, // P[132]
+ {
+ V1540, V1543, V1546, V1548, V1556, V1557, V1560, V1562,
+ V1563, V1565, V1566, V1567, V1568, V1569, V1730, V1731,
+ V1732, V1733, V1734, V1735, V1736, V1737, V1738, V1739,
+ V1740, V1741, V1742, V1743, V1744, V1745, V1746, 0,
+ }, // P[133]
+ {
+ V1261, V1267, V1634, V1635, V1747, V1748, V1749, V1272,
+ V1750, V1284, V1334, V1346, V1345, V1335, V1427, V1292,
+ V1332, V1751, V1752, V1753, V1754, V1755, V1756, V1757,
+ V1758, V1759, V1760, V1298, V1761, V1762, V1763, V1764,
+ }, // P[134]
+ {
+ V1765, V1766, V1767, V1768, V1636, V1637, V1638, V1769,
+ V1770, V1771, V1772, V1773, V1774, V1775, V1776, V1777,
+ V1778, V1779, V1780, V1781, V1782, V1783, V1784, V1785,
+ V1786, V1787, V1788, V1789, V1790, V1791, V1792, V1793,
+ }, // P[135]
+ {
+ V1794, V1795, V1796, V1797, V1798, V1799, V1800, V1801,
+ V1802, V1803, V1804, V1805, V1806, V1807, V1808, V1809,
+ V1810, V1811, V1812, V1813, V1814, V1815, V1816, V1817,
+ V1818, V1819, V1820, V1821, V1822, V1823, V1824, V1825,
+ }, // P[136]
+ {
+ V1826, V1827, V1828, V1829, V1830, V1831, V1832, V1833,
+ V1834, V1835, V1836, V1837, V1838, V1839, V1840, V1841,
+ V1842, V1843, V1844, V1845, V1846, V1847, V1848, V1849,
+ V1850, V1851, V1852, V1853, V1854, V1855, V1856, 0,
+ }, // P[137]
+ {
+ V1857, V1858, V1859, V1860, V1861, V1862, V1863, V1864,
+ V1865, V1866, V1867, V1868, V1869, V1870, V1871, V1872,
+ V1873, V1874, V1875, V1876, V1877, V1878, V1879, V1880,
+ V1881, V1882, V1883, V1884, V1885, V1886, V1887, V1888,
+ }, // P[138]
+ {
+ V1889, V1890, V1891, V1892, V1893, V1894, V1895, V1896,
+ V1897, V1898, V1899, V1900, V1901, V1902, V1903, V1904,
+ V1905, V1906, V1907, V1908, V1909, V1910, V1911, V1912,
+ V1913, V1914, V1915, V1916, V1917, V1918, V1919, V1920,
+ }, // P[139]
+ {
+ V1921, V1922, V1923, V1924, V1925, V1926, V1927, V1928,
+ V1929, V1930, V1931, V1932, V1933, V1934, V1935, V1936,
+ V1937, V1938, V1939, V1940, V1941, V1942, V1943, V1944,
+ V1945, V1946, V1947, V1948, V1949, V1950, V1951, V1952,
+ }, // P[140]
+ {
+ V1953, V1954, V1955, V1956, V1957, V1958, V1959, V1960,
+ V1961, V1962, V1963, V1964, V1965, V1966, V1967, V1968,
+ V1969, V1970, V1971, V1972, V1973, V1974, V1975, V1976,
+ V1977, V1978, V1979, V1980, V1981, V1982, V1983, V1984,
+ }, // P[141]
+ {
+ V1985, V1986, V1987, V1988, V1989, V1990, V1991, V1992,
+ V1993, V1994, V1995, V1996, V1997, V1998, V1999, V2000,
+ V2001, V2002, V2003, V2004, V2005, V2006, V2007, V2008,
+ V2009, V2010, V2011, V2012, V2013, V2014, V2015, V2016,
+ }, // P[142]
+ {
+ V2017, V2018, V2019, V2020, V2021, V2022, V2023, V2024,
+ V2025, V2026, V2027, V2028, V2029, V2030, V2031, V2032,
+ V2033, V2034, V2035, V2036, V2037, V2038, V2039, V2040,
+ V2041, V2042, V2043, V2044, V2045, V2046, V2047, V2048,
+ }, // P[143]
+ {
+ V2049, V2050, V2051, V2052, V2053, V2054, V2055, V2056,
+ V2057, V2058, V2059, V2060, V2061, V2062, V2063, V2064,
+ V2065, V2066, V2067, V2068, V2069, V2070, V2071, V2072,
+ V2073, V2074, V2075, V2076, V2077, V2078, V2079, V2080,
+ }, // P[144]
+ {
+ V2081, V2082, V2083, V2084, V2085, V2086, V2087, V2088,
+ V2089, V2090, V2091, V2092, V2093, V2094, V2095, V2096,
+ V2097, V2098, V2099, V2100, V2101, V2102, V2103, V2104,
+ V2105, V2106, V2107, V2108, V2109, V2110, V2111, V2112,
+ }, // P[145]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V2113, V2114, 0, 0,
+ }, // P[146]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V2115, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[147]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V2116, V2117, 0, 0, 0, 0, 0, 0,
+ }, // P[148]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, V2118, V2119, V2120, V2121,
+ }, // P[149]
+ {
+ V1730, V2122, V2123, V2124, V2125, V2126, V2127, V2128,
+ V2129, V2130, V2131, V2132, V2133, V2134, V2135, V2136,
+ V2137, V2138, V2139, V2140, V2141, V2142, V2143, V2144,
+ V2145, V2146, V2147, V2148, V2149, V2150, V2151, V2152,
+ }, // P[150]
+ {
+ V2153, V2154, V2155, V2156, V2157, V2158, V2159, V2160,
+ V2161, V2162, V2163, V2164, V2165, V2166, V2167, V2168,
+ V2169, V2170, V2171, V2172, V2173, V2174, V2175, V2176,
+ V2177, V2178, V2179, V2180, V2181, V2182, V2183, V2184,
+ }, // P[151]
+ {
+ V2185, V2186, V2187, V2188, V2189, V2190, V2191, V2192,
+ V2193, V2194, V2195, V2196, V2197, V2198, V2199, V2200,
+ V2201, V2202, V2203, V2204, V2205, V2206, V2207, V2208,
+ V2209, V2210, V2211, V2212, V2213, V2214, V2215, V2216,
+ }, // P[152]
+ {
+ V2217, V2218, V2219, V2220, V2221, V2222, V2223, V2224,
+ V2225, V2226, V2227, V2228, V2229, V2230, V2231, V2232,
+ V2233, V2234, V2235, V2236, V2237, V2238, V2239, V2240,
+ V2241, V2242, V2243, V2244, V2245, V2246, V2247, V2248,
+ }, // P[153]
+ {
+ V2249, V2250, V2251, V2252, V2253, V2254, V2255, V2256,
+ V2257, V2258, V2259, V2260, V2261, V2262, V2263, V2264,
+ V2265, V2266, V2267, V2268, V2269, V2270, V2271, V2272,
+ V2273, V2274, V2275, V2276, V2277, V2278, V2279, V2280,
+ }, // P[154]
+ {
+ V2281, V2282, V2283, V2284, V2285, V2286, V2287, V2288,
+ V2289, V2290, V2291, V2292, V2293, V2294, V2295, V2296,
+ V2297, V2298, V2299, V2300, V2301, V2302, V2303, V2304,
+ V2305, V2306, V2307, V2308, V2309, V2310, V2311, V2312,
+ }, // P[155]
+ {
+ V2313, V2314, V2315, V2316, V2317, V2318, V2319, V2320,
+ V2321, V2322, V2323, V2324, V2325, V2326, V2327, V2328,
+ V2329, V2330, V2331, V2332, V2333, V2334, V2335, V2336,
+ V2337, V2338, V2339, V2340, V2341, V2342, V2343, V2344,
+ }, // P[156]
+ {
+ V2345, V2346, V2347, V2348, V2349, V2350, V2351, V2352,
+ V2353, V2354, V2355, V2356, V2357, V2358, V2359, V2360,
+ V2361, V2362, V2363, V2364, V2365, V2366, V2367, V2368,
+ V2369, V2370, V2371, V2372, V2373, V2374, V2375, V2376,
+ }, // P[157]
+ {
+ V2377, V2378, V2379, V2380, V2381, V2382, V2383, V2384,
+ V2385, V2386, V2387, V2388, V2389, V2390, V2391, V2392,
+ V2393, V2394, V2395, V2396, V2397, V2398, V2399, V2400,
+ V2401, V2402, V2403, V2404, V2405, V2406, V2407, V2408,
+ }, // P[158]
+ {
+ V2409, V2410, V2411, V2412, V2413, V2414, V2415, V2416,
+ V2417, V2418, V2419, V2420, V2421, V2422, V2423, V2424,
+ V2425, V2426, V2427, V2428, V2429, V2430, V2431, V2432,
+ V2433, V2434, V2435, V2436, V2437, V2438, V2439, V2440,
+ }, // P[159]
+ {
+ V2441, V2442, V2443, V2444, V2445, V2446, V2447, V2448,
+ V2449, V2450, V2451, V2452, V2453, V2454, V2455, V2456,
+ V2457, V2458, V2459, V2460, V2461, V2462, V2463, V2464,
+ V2465, V2466, V2467, V2468, V2469, V2470, V2471, V2472,
+ }, // P[160]
+ {
+ V2473, V2474, V2475, V2476, V2477, V2478, V2479, V2480,
+ V2481, V2482, V2483, V2484, V2485, V2486, V2487, V2488,
+ V2489, V2490, V2491, V2492, V2493, V2494, V2495, V2496,
+ V2497, V2498, V2499, V2500, V2501, V2502, V2503, V2504,
+ }, // P[161]
+ {
+ V2505, V2506, V2507, V2508, V2509, V2510, V2511, V2512,
+ V2513, V2514, V2515, V2516, V2517, V2518, V2519, V2520,
+ V2521, V2522, V2523, V2524, V2525, V2526, V2527, V2528,
+ V2529, V2530, V2531, V2532, V2533, V2534, V2535, V2536,
+ }, // P[162]
+ {
+ V2537, V2538, V2539, V2540, V2541, V2542, V2543, V2544,
+ V2545, V2546, V2547, V2548, V2549, V2550, V2551, V2552,
+ V2553, V2554, V2555, V2556, V2557, V2558, V2559, V2560,
+ V2561, V2562, V2563, V2564, V2565, V2566, V2567, V2568,
+ }, // P[163]
+ {
+ V2569, V2570, V2571, V2572, V2573, V2574, V2575, V2576,
+ V2577, V2578, V2579, V2580, V2581, V2582, V2583, V2584,
+ V2585, V2586, V2587, V2588, V2589, V2590, V2591, V2592,
+ V2593, V2594, V2595, V2596, V2597, V2598, V2599, V2600,
+ }, // P[164]
+ {
+ V2601, V2602, V2603, V2604, V2605, V2606, V2607, V2608,
+ V2609, V2610, V2611, V2612, V2613, V2614, V2615, V2616,
+ V2617, V2618, V2619, V2620, V2621, V2622, V2623, V2624,
+ V2625, V2626, V2627, V2628, V2629, V2630, V2631, V2632,
+ }, // P[165]
+ {
+ V2633, V2634, V2635, V2636, V2637, V2638, V2639, V2640,
+ V2641, V2642, V2643, V2644, V2645, V2646, V2647, V2648,
+ V2649, V2650, V2651, V2652, V2653, V2654, V2655, V2656,
+ V2657, V2658, V2659, V2660, V2661, V2662, V2663, V2664,
+ }, // P[166]
+ {
+ V2665, V2666, V2667, V2668, V2669, V2670, V2671, V2672,
+ V2673, V2674, V2675, V2676, V2677, V2678, V2679, V2680,
+ V2681, V2682, V2683, V2684, V2685, V2686, V2687, V2688,
+ V2689, V2690, V2691, V2692, V2693, V2694, V2695, V2696,
+ }, // P[167]
+ {
+ V2697, V2698, V2699, V2700, V2701, V2702, V2703, V2704,
+ V2705, V2706, V2707, V2708, V2709, V2710, V2711, V2712,
+ V2713, V2714, V2715, V2716, V2717, V2718, V2719, V2720,
+ V2721, V2722, V2723, V2724, V2725, V2726, V2727, V2728,
+ }, // P[168]
+ {
+ V2729, V2730, V2731, V2732, V2733, V2734, V2735, V2736,
+ V2737, V2738, V2739, V2740, V2741, V2742, V2743, V2744,
+ V2745, V2746, V2747, V2748, V2749, V2750, V2751, V2752,
+ V2753, V2754, V2755, V2756, V2757, V2758, V2759, V2760,
+ }, // P[169]
+ {
+ V2761, V2762, V2763, V2764, V2765, V2766, V2767, V2768,
+ V2769, V2770, V2771, V2772, V2773, V2774, V2775, V2776,
+ V2777, V2778, V2779, V2780, V2781, V2782, V2783, V2784,
+ V2785, V2786, V2787, V2788, V2789, V2790, V2791, V2792,
+ }, // P[170]
+ {
+ V2793, V2794, V2795, V2796, V2797, V2798, V2799, V2800,
+ V2801, V2802, V2803, V2804, V2805, V2806, V2807, V2808,
+ V2809, V2810, V2811, V2812, V2813, V2814, V2815, V2816,
+ V2817, V2818, V2819, V2820, V2821, V2822, V2823, V2824,
+ }, // P[171]
+ {
+ V2825, V2826, V2827, V2828, V2829, V2830, V2831, V2832,
+ V2833, V2834, V2835, V2836, V2837, V2838, V2839, V2840,
+ V2841, V2842, V2843, V2844, V2845, V2846, V2847, V2848,
+ V2849, V2850, V2851, V2852, V2853, V2854, V2855, V2856,
+ }, // P[172]
+ {
+ V2857, V2858, V2859, V2860, V2861, V2862, V2863, V2864,
+ V2865, V2866, V2867, V2868, V2869, V2870, V2871, V2872,
+ V2873, V2874, V2875, V2876, V2877, V2878, V2879, V2880,
+ V2881, V2882, V2883, V2884, V2885, V2886, V2887, V2888,
+ }, // P[173]
+ {
+ V2889, V2890, V2891, V2892, V2893, V2894, V2895, V2896,
+ V2897, V2898, V2899, V2900, V2901, V2902, V2903, V2904,
+ V2905, V2906, V2907, V2908, V2909, V2910, V2911, V2912,
+ V2913, V2914, V2915, V2916, V2917, V2918, V2919, V2920,
+ }, // P[174]
+ {
+ V2921, V2922, V2923, V2924, V2925, V2926, V2927, V2928,
+ V2929, V2930, V2931, V2932, V2933, V2934, V2935, V2936,
+ V2937, V2938, V2939, V2940, V2941, V2942, V2943, V2944,
+ V2945, V2946, V2947, V2948, V2949, V2950, V2951, V2952,
+ }, // P[175]
+ {
+ V2953, V2954, V2955, V2956, V2957, V2958, V2959, V2960,
+ V2961, V2962, V2963, V2964, V2965, V2966, V2967, V2968,
+ V2969, V2970, V2971, V2972, V2973, V2974, V2975, V2976,
+ V2977, V2978, V2979, V2980, V2981, V2982, V2983, V2984,
+ }, // P[176]
+ {
+ V2985, V2986, V2987, V2988, V2989, V2990, V2991, V2992,
+ V2993, V2994, V2995, V2996, V2997, V2998, V2999, V3000,
+ V3001, V3002, V3003, V3004, V3005, V3006, V3007, V3008,
+ V3009, V3010, V3011, V3012, V3013, V3014, V3015, V3016,
+ }, // P[177]
+ {
+ V3017, V3018, V3019, V3020, V3021, V3022, V3023, V3024,
+ V3025, V3026, V3027, V3028, V3029, V3030, V3031, V3032,
+ V3033, V3034, V3035, V3036, V3037, V3038, V3039, V3040,
+ V3041, V3042, V3043, V3044, V3045, V3046, V3047, V3048,
+ }, // P[178]
+ {
+ V3049, V3050, V3051, V3052, V3053, V3054, V3055, V3056,
+ V3057, V3058, V3059, V3060, V3061, V3062, V3063, V3064,
+ V3065, V3066, V3067, V3068, V3069, V3070, V3071, V3072,
+ V3073, V3074, V3075, V3076, V3077, V3078, V3079, V3080,
+ }, // P[179]
+ {
+ V3081, V3082, V3083, V3084, V3085, V3086, V3087, V3088,
+ V3089, V3090, V3091, V3092, V3093, V3094, V3095, V3096,
+ V3097, V3098, V3099, V3100, V3101, V3102, V3103, V3104,
+ V3105, V3106, V3107, V3108, V3109, V3110, V3111, V3112,
+ }, // P[180]
+ {
+ V3113, V3114, V3115, V3116, V3117, V3118, V3119, V3120,
+ V3121, V3122, V3123, V3124, V3125, V3126, V3127, V3128,
+ V3129, V3130, V3131, V3132, V3133, V3134, V3135, V3136,
+ V3137, V3138, V3139, V3140, V3141, V3142, V3143, V3144,
+ }, // P[181]
+ {
+ V3145, V3146, V3147, V3148, V3149, V3150, V3151, V3152,
+ V3153, V3154, V3155, V3156, V3157, V3158, V3159, V3160,
+ V3161, V3162, V3163, V3164, V3165, V3166, V3167, V3168,
+ V3169, V3170, V3171, V3172, V3173, V3174, V3175, V3176,
+ }, // P[182]
+ {
+ V3177, V3178, V3179, V3180, V3181, V3182, V3183, V3184,
+ V3185, V3186, V3187, V3188, V3189, V3190, V3191, V3192,
+ V3193, V3194, V3195, V3196, V3197, V3198, V3199, V3200,
+ V3201, V3202, V3203, V3204, V3205, V3206, V3207, V3208,
+ }, // P[183]
+ {
+ V3209, V3210, V3211, V3212, V3213, V3214, V3215, V3216,
+ V3217, V3218, V3219, V3220, V3221, V3222, V3223, V3224,
+ V3225, V3226, V3227, V3228, V3229, V3230, V3231, V3232,
+ V3233, V3234, V3235, V3236, V3237, V3238, V3239, V3240,
+ }, // P[184]
+ {
+ V3241, V3242, V3243, V3244, V3245, V3246, V3247, V3248,
+ V3249, V3250, V3251, V3252, V3253, V3254, V3255, V3256,
+ V3257, V3258, V3259, V3260, V3261, V3262, V3263, V3264,
+ V3265, V3266, V3267, V3268, V3269, V3270, V3271, V3272,
+ }, // P[185]
+ {
+ V3273, V3274, V3275, V3276, V3277, V3278, V3279, V3280,
+ V3281, V3282, V3283, V3284, V3285, V3286, V3287, V3288,
+ V3289, V3290, V3291, V3292, V3293, V3294, V3295, V3296,
+ V1731, V3297, V3298, V3299, V3300, V3301, V3302, V3303,
+ }, // P[186]
+ {
+ V3304, V3305, V3306, V3307, V3308, V3309, V3310, V3311,
+ V3312, V3313, V3314, V3315, V3316, V3317, V3318, V3319,
+ V3320, V3321, V3322, V3323, V3324, V3325, V3326, V3327,
+ V3328, V3329, V3330, V3331, V3332, V3333, V3334, V3335,
+ }, // P[187]
+ {
+ V3336, V3337, V3338, V3339, V3340, V3341, V3342, V3343,
+ V3344, V3345, V3346, V3347, V3348, V3349, V3350, V3351,
+ V3352, V3353, V3354, V3355, V3356, V3357, V3358, V3359,
+ V3360, V3361, V3362, V3363, V3364, V3365, V3366, V3367,
+ }, // P[188]
+ {
+ V3368, V3369, V3370, V3371, V3372, V3373, V3374, V3375,
+ V3376, V3377, V3378, V3379, V3380, V3381, V3382, V3383,
+ V3384, V3385, V3386, V3387, V3388, V3389, V3390, V3391,
+ V3392, V3393, V3394, V3395, V3396, V3397, V3398, V3399,
+ }, // P[189]
+ {
+ V3400, V3401, V3402, V3403, V3404, V3405, V3406, V3407,
+ V3408, V3409, V3410, V3411, V3412, V3413, V3414, V3415,
+ V3416, V3417, V3418, V3419, V3420, V3421, V3422, V3423,
+ V3424, V3425, V3426, V3427, V3428, V3429, V3430, V3431,
+ }, // P[190]
+ {
+ V3432, V3433, V3434, V3435, V3436, V3437, V3438, V3439,
+ V3440, V3441, V3442, V3443, V3444, V3445, V3446, V3447,
+ V3448, V3449, V3450, V3451, V3452, V3453, V3454, V3455,
+ V3456, V3457, V3458, V3459, V3460, V3461, V3462, V3463,
+ }, // P[191]
+ {
+ V3464, V3465, V3466, V3467, V3468, V3469, V3470, V3471,
+ V3472, V3473, V3474, V3475, V3476, V3477, V3478, V3479,
+ V3480, V3481, V3482, V3483, V3484, V3485, V3486, V3487,
+ V3488, V3489, V3490, V3491, V3492, V3493, V3494, V3495,
+ }, // P[192]
+ {
+ V3496, V3497, V3498, V3499, V3500, V3501, V3502, V3503,
+ V3504, V3505, V3506, V3507, V3508, V3509, V3510, V3511,
+ V3512, V3513, V3514, V3515, V3516, V3517, V3518, V3519,
+ V3520, V3521, V3522, V3523, V3524, V3525, V3526, V3527,
+ }, // P[193]
+ {
+ V3528, V3529, V3530, V3531, V3532, V3533, V3534, V3535,
+ V3536, V3537, V3538, V3539, V3540, V3541, V3542, V3543,
+ V3544, V3545, V3546, V3547, V3548, V3549, V3550, V3551,
+ V3552, V3553, V3554, V3555, V3556, V3557, V3558, V3559,
+ }, // P[194]
+ {
+ V3560, V3561, V3562, V3563, V3564, V3565, V3566, V3567,
+ V3568, V3569, V3570, V3571, V3572, V3573, V3574, V3575,
+ V3576, V3577, V3578, V3579, V3580, V3581, V3582, V3583,
+ V3584, V3585, V3586, V3587, V3588, V3589, V3590, V3591,
+ }, // P[195]
+ {
+ V3592, V3593, V3594, V3595, V3596, V3597, V3598, V3599,
+ V3600, V3601, V3602, V3603, V3604, V3605, V3606, V3607,
+ V3608, V3609, V3610, V3611, V3612, V3613, V3614, V3615,
+ V3616, V3617, V3618, V3619, V3620, V3621, V3622, V3623,
+ }, // P[196]
+ {
+ V3624, V3625, V3626, V3627, V3628, V3629, V3630, V3631,
+ V3632, V3633, V3634, V3635, V3636, V3637, V3638, V3639,
+ V3640, V3641, V3642, V3643, V3644, V3645, V3646, V3647,
+ V3648, V3649, V3650, V3651, V3652, V3653, V3654, V3655,
+ }, // P[197]
+ {
+ V3656, V3657, V3658, V3659, V3660, V3661, V3662, V3663,
+ V3664, V3665, V3666, V3667, V3668, V3669, V3670, V3671,
+ V3672, V3673, V3674, V3675, V3676, V3677, V3678, V3679,
+ V3680, V3681, V3682, V3683, V3684, V3685, V3686, V3687,
+ }, // P[198]
+ {
+ V3688, V3689, V3690, V3691, V3692, V3693, V3694, V3695,
+ V3696, V3697, V3698, V3699, V3700, V3701, V3702, V3703,
+ V3704, V3705, V3706, V3707, V3708, V3709, V3710, V3711,
+ V3712, V3713, V3714, V3715, V3716, V3717, V3718, V3719,
+ }, // P[199]
+ {
+ V3720, V3721, V3722, V3723, V3724, V3725, V3726, V3727,
+ V3728, V3729, V3730, V3731, V3732, V3733, V3734, V3735,
+ V3736, V3737, V3738, V3739, V3740, V3741, V3742, V3743,
+ V3744, V3745, V3746, V3747, V3748, V3749, V3750, V3751,
+ }, // P[200]
+ {
+ V3752, V3753, V3754, V3755, V3756, V3757, V3758, V3759,
+ V3760, V3761, V3762, V3763, V3764, V3765, V3766, V3767,
+ V3768, V3769, V3770, V3771, V3772, V3773, V3774, V3775,
+ V3776, V3777, V3778, V3779, V3780, V3781, V3782, V3783,
+ }, // P[201]
+ {
+ V3784, V3785, V3786, V3787, V3788, V3789, V3790, V3791,
+ V3792, V3793, V3794, V3795, V3796, V3797, V3798, V3799,
+ V3800, V3801, V3802, V3803, V3804, V3805, V3806, V3807,
+ V3808, V3809, V3810, V3811, V3812, V3813, V3814, V3815,
+ }, // P[202]
+ {
+ V3816, V3817, V3818, V3819, V3820, V3821, V3822, V3823,
+ V3824, V3825, V3826, V3827, V3828, V3829, V3830, V3831,
+ V3832, V3833, V3834, V3835, V3836, V3837, V3838, V3839,
+ V3840, V3841, V3842, V3843, V3844, V3845, V3846, V3847,
+ }, // P[203]
+ {
+ V3848, V3849, V3850, V3851, V3852, V3853, V3854, V3855,
+ V3856, V3857, V3858, V3859, V3860, V3861, V3862, V3863,
+ V3864, V3865, V3866, V3867, V3868, V3869, V3870, V3871,
+ V3872, V3873, V3874, V3875, V3876, V3877, V3878, V3879,
+ }, // P[204]
+ {
+ V3880, V3881, V3882, V3883, V1732, V3884, V3885, V3886,
+ V3887, V3888, V3889, V3890, V3891, V3892, V3893, V3894,
+ V3895, V3896, V3897, V3898, V3899, V3900, V3901, V3902,
+ V3903, V3904, V3905, V3906, V3907, V3908, V3909, V3910,
+ }, // P[205]
+ {
+ V3911, V3912, V3913, V3914, V3915, V3916, V3917, V3918,
+ V3919, V3920, V3921, V3922, V3923, V3924, V3925, V3926,
+ V3927, V3928, V3929, V3930, V3931, V3932, V3933, V3934,
+ V3935, V3936, V3937, V3938, V3939, V3940, V3941, V3942,
+ }, // P[206]
+ {
+ V3943, V3944, V3945, V3946, V3947, V3948, V3949, V3950,
+ V3951, V3952, V3953, V3954, V3955, V3956, V3957, V3958,
+ V3959, V3960, V3961, V3962, V3963, V3964, V3965, V3966,
+ V3967, V3968, V3969, V3970, V3971, V3972, V3973, V3974,
+ }, // P[207]
+ {
+ V3975, V3976, V3977, V3978, V3979, V3980, V3981, V3982,
+ V3983, V3984, V3985, V3986, V3987, V3988, V3989, V3990,
+ V3991, V3992, V3993, V3994, V3995, V3996, V3997, V3998,
+ V3999, V4000, V4001, V4002, V4003, V4004, V4005, V4006,
+ }, // P[208]
+ {
+ V4007, V4008, V4009, V4010, V4011, V4012, V4013, V4014,
+ V4015, V4016, V4017, V4018, V4019, V4020, V4021, V4022,
+ V4023, V4024, V4025, V4026, V4027, V4028, V4029, V4030,
+ V4031, V4032, V4033, V4034, V4035, V4036, V4037, V4038,
+ }, // P[209]
+ {
+ V4039, V4040, V4041, V4042, V4043, V4044, V4045, V4046,
+ V4047, V4048, V4049, V4050, V4051, V4052, V4053, V4054,
+ V4055, V4056, V4057, V4058, V4059, V4060, V4061, V4062,
+ V4063, V4064, V4065, V4066, V4067, V4068, V4069, V4070,
+ }, // P[210]
+ {
+ V4071, V4072, V4073, V4074, V4075, V4076, V4077, V4078,
+ V4079, V4080, V4081, V4082, V4083, V4084, V4085, V4086,
+ V4087, V4088, V4089, V4090, V4091, V4092, V4093, V4094,
+ V4095, V4096, V4097, V4098, V4099, V4100, V4101, V4102,
+ }, // P[211]
+ {
+ V4103, V4104, V4105, V4106, V4107, V4108, V4109, V4110,
+ V4111, V4112, V4113, V4114, V4115, V4116, V4117, V4118,
+ V4119, V4120, V4121, V4122, V4123, V4124, V4125, V4126,
+ V4127, V4128, V4129, V4130, V4131, V4132, V4133, V4134,
+ }, // P[212]
+ {
+ V4135, V4136, V4137, V4138, V4139, V4140, V4141, V4142,
+ V4143, V4144, V4145, V4146, V4147, V4148, V4149, V4150,
+ V4151, V4152, V4153, V4154, V4155, V4156, V4157, V4158,
+ V4159, V4160, V4161, V4162, V4163, V4164, V4165, V4166,
+ }, // P[213]
+ {
+ V4167, V4168, V4169, V4170, V4171, V4172, V4173, V4174,
+ V4175, V4176, V4177, V4178, V4179, V4180, V4181, V4182,
+ V4183, V4184, V4185, V4186, V4187, V4188, V4189, V4190,
+ V4191, V4192, V4193, V4194, V4195, V4196, V4197, V4198,
+ }, // P[214]
+ {
+ V4199, V4200, V4201, V4202, V4203, V4204, V4205, V4206,
+ V4207, V4208, V4209, V4210, V4211, V4212, V4213, V4214,
+ V4215, V4216, V4217, V4218, V4219, V4220, V4221, V4222,
+ V4223, V4224, V4225, V4226, V4227, V4228, V4229, V4230,
+ }, // P[215]
+ {
+ V4231, V4232, V4233, V4234, V4235, V4236, V4237, V4238,
+ V4239, V4240, V4241, V4242, V4243, V4244, V4245, V4246,
+ V4247, V4248, V4249, V4250, V4251, V4252, V4253, V4254,
+ V4255, V4256, V4257, V4258, V4259, V4260, V4261, V4262,
+ }, // P[216]
+ {
+ V4263, V4264, V4265, V4266, V4267, V4268, V4269, V4270,
+ V4271, V4272, V4273, V4274, V4275, V4276, V4277, V4278,
+ V4279, V4280, V4281, V4282, V4283, V4284, V4285, V4286,
+ V4287, V4288, V4289, V4290, V4291, V4292, V4293, V4294,
+ }, // P[217]
+ {
+ V4295, V4296, V4297, V4298, V4299, V4300, V4301, V4302,
+ V4303, V4304, V4305, V4306, V4307, V4308, V4309, V4310,
+ V4311, V4312, V4313, V4314, V4315, V4316, V4317, V4318,
+ V4319, V4320, V4321, V4322, V4323, V4324, V4325, V4326,
+ }, // P[218]
+ {
+ V4327, V4328, V4329, V4330, V4331, V4332, V4333, V4334,
+ V4335, V4336, V4337, V4338, V4339, V4340, V4341, V4342,
+ V4343, V4344, V4345, V4346, V4347, V4348, V4349, V4350,
+ V4351, V4352, V4353, V4354, V4355, V4356, V4357, V4358,
+ }, // P[219]
+ {
+ V4359, V4360, V4361, V4362, V4363, V4364, V4365, V4366,
+ V4367, V4368, V4369, V4370, V4371, V4372, V4373, V4374,
+ V4375, V4376, V4377, V4378, V4379, V4380, V4381, V4382,
+ V4383, V4384, V4385, V4386, V4387, V4388, V4389, V4390,
+ }, // P[220]
+ {
+ V4391, V4392, V4393, V4394, V4395, V4396, V4397, V4398,
+ V4399, V4400, V4401, V4402, V4403, V4404, V4405, V4406,
+ V4407, V4408, V4409, V4410, V4411, V4412, V4413, V4414,
+ V4415, V4416, V4417, V4418, V4419, V4420, V4421, V4422,
+ }, // P[221]
+ {
+ V4423, V4424, V4425, V4426, V4427, V4428, V4429, V4430,
+ V4431, V4432, V4433, V4434, V4435, V4436, V4437, V4438,
+ V4439, V4440, V4441, V4442, V4443, V4444, V4445, V4446,
+ V4447, V4448, V4449, V4450, V4451, V4452, V4453, V4454,
+ }, // P[222]
+ {
+ V4455, V4456, V4457, V4458, V4459, V4460, V4461, V4462,
+ V4463, V4464, V4465, V4466, V4467, V4468, V4469, V4470,
+ V4471, V4472, V4473, V4474, V4475, V4476, V4477, V4478,
+ V4479, V4480, V4481, V4482, V4483, V4484, V4485, V4486,
+ }, // P[223]
+ {
+ V4487, V4488, V4489, V4490, V4491, V4492, V4493, V4494,
+ V4495, V4496, V4497, V4498, V4499, V4500, V4501, V4502,
+ V4503, V4504, V4505, V4506, V4507, V4508, V4509, V4510,
+ V4511, V4512, V4513, V4514, V4515, V4516, V4517, V4518,
+ }, // P[224]
+ {
+ V4519, V4520, V4521, V4522, V4523, V4524, V4525, V4526,
+ V4527, V4528, V4529, V4530, V4531, V4532, V4533, V4534,
+ V4535, V4536, V4537, V4538, V4539, V4540, V4541, V4542,
+ V4543, V4544, V4545, V4546, V4547, V4548, V4549, V4550,
+ }, // P[225]
+ {
+ V4551, V4552, V4553, V4554, V4555, V4556, V4557, V4558,
+ V4559, V4560, V4561, V4562, V4563, V4564, V4565, V4566,
+ V4567, V4568, V4569, V4570, V4571, V4572, V4573, V4574,
+ V4575, V4576, V4577, V4578, V4579, V4580, V4581, V4582,
+ }, // P[226]
+ {
+ V4583, V4584, V4585, V4586, V4587, V4588, V4589, V4590,
+ V4591, V4592, V4593, V4594, V4595, V4596, V4597, V4598,
+ V4599, V4600, V4601, V4602, V4603, V4604, V4605, V4606,
+ V4607, V4608, V4609, V4610, V4611, V4612, V4613, V4614,
+ }, // P[227]
+ {
+ V4615, V4616, V4617, V4618, V4619, V4620, V4621, V4622,
+ V4623, V4624, V4625, V4626, V4627, V4628, V4629, V4630,
+ V4631, V4632, V4633, V4634, V4635, V4636, V4637, V4638,
+ V4639, V4640, V4641, V4642, V4643, V4644, V4645, V4646,
+ }, // P[228]
+ {
+ V4647, V4648, V4649, V4650, V4651, V4652, V4653, V4654,
+ V4655, V4656, V4657, V4658, V4659, V4660, V4661, V4662,
+ V4663, V4664, V4665, V4666, V4667, V4668, V4669, V4670,
+ V4671, V4672, V4673, V4674, V4675, V4676, V4677, V4678,
+ }, // P[229]
+ {
+ V4679, V4680, V4681, V4682, V4683, V4684, V4685, V4686,
+ V4687, V4688, V4689, V4690, V4691, V4692, V4693, V4694,
+ V4695, V4696, V4697, V4698, V4699, V4700, V4701, V4702,
+ V4703, V4704, V4705, V4706, V4707, V4708, V4709, V4710,
+ }, // P[230]
+ {
+ V4711, V4712, V4713, V4714, V4715, V4716, V4717, V4718,
+ V4719, V4720, V4721, V4722, V4723, V4724, V4725, V4726,
+ V4727, V4728, V4729, V4730, V4731, V4732, V4733, V4734,
+ V4735, V4736, V4737, V4738, V4739, V4740, V4741, V4742,
+ }, // P[231]
+ {
+ V4743, V4744, V4745, V4746, V4747, V4748, V4749, V4750,
+ V4751, V4752, V4753, V4754, V4755, V4756, V4757, V4758,
+ V4759, V4760, V4761, V4762, V4763, V4764, V4765, V4766,
+ V4767, V4768, V4769, V4770, V4771, V4772, V4773, V4774,
+ }, // P[232]
+ {
+ V4775, V4776, V4777, V4778, V4779, V4780, V4781, V4782,
+ V4783, V4784, V4785, V4786, V4787, V4788, V4789, V4790,
+ V4791, V4792, V4793, V4794, V4795, V4796, V4797, V4798,
+ V4799, V4800, V4801, V4802, V4803, V4804, V4805, V4806,
+ }, // P[233]
+ {
+ V4807, V4808, V4809, V4810, V4811, V4812, V4813, V4814,
+ V4815, V4816, V4817, V4818, V4819, V4820, V4821, V4822,
+ V4823, V4824, V4825, V4826, V4827, V4828, V4829, V4830,
+ V4831, V4832, V4833, V4834, V4835, V4836, V4837, V4838,
+ }, // P[234]
+ {
+ V4839, V4840, V4841, V4842, V4843, V4844, V4845, V4846,
+ V4847, V4848, V4849, V4850, V4851, V4852, V4853, V4854,
+ V4855, V4856, V4857, V4858, V4859, V4860, V4861, V4862,
+ V4863, V4864, V4865, V4866, V4867, V4868, V4869, V4870,
+ }, // P[235]
+ {
+ V4871, V4872, V4873, V4874, V4875, V4876, V4877, V4878,
+ V4879, V4880, V4881, V4882, V4883, V4884, V4885, V4886,
+ V4887, V4888, V4889, V4890, V4891, V4892, V4893, V4894,
+ V4895, V4896, V4897, V4898, V4899, V4900, V4901, V4902,
+ }, // P[236]
+ {
+ V4903, V4904, V4905, V4906, V4907, V4908, V4909, V4910,
+ V4911, V4912, V4913, V4914, V4915, V4916, V4917, V4918,
+ V4919, V4920, V4921, V4922, V4923, V4924, V4925, V4926,
+ V4927, V4928, V4929, V4930, V4931, V4932, V4933, V4934,
+ }, // P[237]
+ {
+ V4935, V4936, V4937, V4938, V4939, V4940, V4941, V4942,
+ V4943, V4944, V4945, V4946, V4947, V4948, V4949, V4950,
+ V4951, V4952, V4953, V4954, V4955, V4956, V4957, V4958,
+ V4959, V4960, V4961, V4962, V4963, V4964, V4965, V4966,
+ }, // P[238]
+ {
+ V4967, V4968, V4969, V4970, V4971, V4972, V4973, V4974,
+ V4975, V4976, V4977, V4978, V4979, V4980, V4981, V4982,
+ V4983, V4984, V4985, V4986, V4987, V4988, V4989, V4990,
+ V4991, V4992, V4993, V4994, V4995, V4996, V4997, V4998,
+ }, // P[239]
+ {
+ V4999, V5000, V5001, V5002, V5003, V5004, V5005, V5006,
+ V5007, V5008, V5009, V5010, V5011, V5012, V5013, V5014,
+ V5015, V5016, V5017, V5018, V5019, V5020, V5021, V5022,
+ V5023, V5024, V5025, V5026, V5027, V5028, V5029, V5030,
+ }, // P[240]
+ {
+ V5031, V5032, V5033, V5034, V5035, V5036, V5037, V5038,
+ V5039, V5040, V5041, V5042, V5043, V5044, V5045, V5046,
+ V5047, V5048, V5049, V5050, V5051, V5052, V5053, V5054,
+ V5055, V5056, V5057, V5058, V1733, V5059, V5060, V5061,
+ }, // P[241]
+ {
+ V5062, V5063, V5064, V5065, V5066, V5067, V5068, V5069,
+ V5070, V5071, V5072, V5073, V5074, V5075, V5076, V5077,
+ V5078, V5079, V5080, V5081, V5082, V5083, V5084, V5085,
+ V5086, V5087, V5088, V5089, V5090, V5091, V5092, V5093,
+ }, // P[242]
+ {
+ V5094, V5095, V5096, V5097, V5098, V5099, V5100, V5101,
+ V5102, V5103, V5104, V5105, V5106, V5107, V5108, V5109,
+ V5110, V5111, V5112, V5113, V5114, V5115, V5116, V5117,
+ V5118, V5119, V5120, V5121, V5122, V5123, V5124, V5125,
+ }, // P[243]
+ {
+ V5126, V5127, V5128, V5129, V5130, V5131, V5132, V5133,
+ V5134, V5135, V5136, V5137, V5138, V5139, V5140, V5141,
+ V5142, V5143, V5144, V5145, V5146, V5147, V5148, V5149,
+ V5150, V5151, V5152, V5153, V5154, V5155, V5156, V5157,
+ }, // P[244]
+ {
+ V5158, V5159, V5160, V5161, V5162, V5163, V5164, V5165,
+ V5166, V5167, V5168, V5169, V5170, V5171, V5172, V5173,
+ V5174, V5175, V5176, V5177, V5178, V5179, V5180, V5181,
+ V5182, V5183, V5184, V5185, V5186, V5187, V5188, V5189,
+ }, // P[245]
+ {
+ V5190, V5191, V5192, V5193, V5194, V5195, V5196, V5197,
+ V5198, V5199, V5200, V5201, V5202, V5203, V5204, V5205,
+ V5206, V5207, V5208, V5209, V5210, V5211, V5212, V5213,
+ V5214, V5215, V5216, V5217, V5218, V5219, V5220, V5221,
+ }, // P[246]
+ {
+ V5222, V5223, V5224, V5225, V5226, V5227, V5228, V5229,
+ V5230, V5231, V5232, V5233, V5234, V5235, V5236, V5237,
+ V5238, V5239, V5240, V5241, V5242, V5243, V5244, V5245,
+ V5246, V5247, V5248, V5249, V5250, V5251, V5252, V5253,
+ }, // P[247]
+ {
+ V5254, V5255, V5256, V5257, V5258, V5259, V5260, V5261,
+ V5262, V5263, V5264, V5265, V5266, V5267, V5268, V5269,
+ V5270, V5271, V5272, V5273, V5274, V5275, V5276, V5277,
+ V5278, V5279, V5280, V5281, V5282, V5283, V5284, V5285,
+ }, // P[248]
+ {
+ V5286, V5287, V5288, V5289, V5290, V5291, V5292, V5293,
+ V5294, V5295, V5296, V5297, V5298, V5299, V5300, V5301,
+ V5302, V5303, V5304, V5305, V5306, V5307, V5308, V5309,
+ V5310, V5311, V5312, V5313, V5314, V5315, V5316, V5317,
+ }, // P[249]
+ {
+ V5318, V5319, V5320, V5321, V5322, V5323, V5324, V5325,
+ V5326, V5327, V5328, V5329, V5330, V5331, V5332, V5333,
+ V5334, V5335, V5336, V5337, V5338, V5339, V5340, V5341,
+ V5342, V5343, V5344, V5345, V5346, V5347, V5348, V5349,
+ }, // P[250]
+ {
+ V5350, V5351, V5352, V5353, V5354, V5355, V5356, V5357,
+ V5358, V5359, V5360, V5361, V5362, V5363, V5364, V5365,
+ V5366, V5367, V5368, V5369, V5370, V5371, V5372, V5373,
+ V5374, V5375, V5376, V5377, V5378, V5379, V5380, V5381,
+ }, // P[251]
+ {
+ V5382, V5383, V5384, V5385, V5386, V5387, V5388, V5389,
+ V5390, V5391, V5392, V5393, V5394, V5395, V5396, V5397,
+ V5398, V5399, V5400, V5401, V5402, V5403, V5404, V5405,
+ V5406, V5407, V5408, V5409, V5410, V5411, V5412, V5413,
+ }, // P[252]
+ {
+ V5414, V5415, V5416, V5417, V5418, V5419, V5420, V5421,
+ V5422, V5423, V5424, V5425, V5426, V5427, V5428, V5429,
+ V5430, V5431, V5432, V5433, V5434, V5435, V5436, V5437,
+ V5438, V5439, V5440, V5441, V5442, V5443, V5444, V5445,
+ }, // P[253]
+ {
+ V5446, V5447, V5448, V5449, V5450, V5451, V5452, V5453,
+ V5454, V5455, V5456, V5457, V5458, V5459, V5460, V5461,
+ V5462, V5463, V5464, V5465, V5466, V5467, V5468, V5469,
+ V5470, V5471, V5472, V5473, V5474, V5475, V5476, V5477,
+ }, // P[254]
+ {
+ V5478, V5479, V5480, V5481, V5482, V5483, V5484, V5485,
+ V5486, V5487, V5488, V5489, V5490, V5491, V5492, V5493,
+ V5494, V5495, V5496, V5497, V5498, V5499, V5500, V5501,
+ V5502, V5503, V5504, V5505, V5506, V5507, V5508, V5509,
+ }, // P[255]
+ {
+ V5510, V5511, V5512, V5513, V5514, V5515, V5516, V5517,
+ V5518, V5519, V5520, V5521, V5522, V5523, V5524, V5525,
+ V5526, V5527, V5528, V5529, V5530, V5531, V5532, V5533,
+ V5534, V5535, V5536, V5537, V5538, V5539, V5540, V5541,
+ }, // P[256]
+ {
+ V5542, V5543, V5544, V5545, V5546, V5547, V5548, V5549,
+ V5550, V5551, V5552, V5553, V5554, V5555, V5556, V5557,
+ V5558, V5559, V5560, V5561, V5562, V5563, V5564, V5565,
+ V5566, V5567, V5568, V5569, V5570, V5571, V5572, V5573,
+ }, // P[257]
+ {
+ V5574, V5575, V5576, V5577, V5578, V5579, V5580, V5581,
+ V5582, V5583, V5584, V5585, V5586, V5587, V5588, V5589,
+ V5590, V5591, V5592, V5593, V5594, V5595, V5596, V5597,
+ V5598, V5599, V5600, V5601, V5602, V5603, V5604, V5605,
+ }, // P[258]
+ {
+ V5606, V5607, V5608, V5609, V5610, V5611, V5612, V5613,
+ V5614, V5615, V5616, V5617, V5618, V5619, V5620, V5621,
+ V5622, V5623, V5624, V5625, V5626, V5627, V5628, V5629,
+ V5630, V5631, V5632, V5633, V5634, V5635, V5636, V5637,
+ }, // P[259]
+ {
+ V5638, V5639, V5640, V5641, V5642, V5643, V5644, V5645,
+ V1734, V5646, V5647, V5648, V5649, V5650, V5651, V5652,
+ V5653, V5654, V5655, V5656, V5657, V5658, V5659, V5660,
+ V5661, V5662, V5663, V5664, V5665, V5666, V5667, V5668,
+ }, // P[260]
+ {
+ V5669, V5670, V5671, V5672, V5673, V5674, V5675, V5676,
+ V5677, V5678, V5679, V5680, V5681, V5682, V5683, V5684,
+ V5685, V5686, V5687, V5688, V5689, V5690, V5691, V5692,
+ V5693, V5694, V5695, V5696, V5697, V5698, V5699, V5700,
+ }, // P[261]
+ {
+ V5701, V5702, V5703, V5704, V5705, V5706, V5707, V5708,
+ V5709, V5710, V5711, V5712, V5713, V5714, V5715, V5716,
+ V5717, V5718, V5719, V5720, V5721, V5722, V5723, V5724,
+ V5725, V5726, V5727, V5728, V5729, V5730, V5731, V5732,
+ }, // P[262]
+ {
+ V5733, V5734, V5735, V5736, V5737, V5738, V5739, V5740,
+ V5741, V5742, V5743, V5744, V5745, V5746, V5747, V5748,
+ V5749, V5750, V5751, V5752, V5753, V5754, V5755, V5756,
+ V5757, V5758, V5759, V5760, V5761, V5762, V5763, V5764,
+ }, // P[263]
+ {
+ V5765, V5766, V5767, V5768, V5769, V5770, V5771, V5772,
+ V5773, V5774, V5775, V5776, V5777, V5778, V5779, V5780,
+ V5781, V5782, V5783, V5784, V5785, V5786, V5787, V5788,
+ V5789, V5790, V5791, V5792, V5793, V5794, V5795, V5796,
+ }, // P[264]
+ {
+ V5797, V5798, V5799, V5800, V5801, V5802, V5803, V5804,
+ V5805, V5806, V5807, V5808, V5809, V5810, V5811, V5812,
+ V5813, V5814, V5815, V5816, V5817, V5818, V5819, V5820,
+ V5821, V5822, V5823, V5824, V5825, V5826, V5827, V5828,
+ }, // P[265]
+ {
+ V5829, V5830, V5831, V5832, V5833, V5834, V5835, V5836,
+ V5837, V5838, V5839, V5840, V5841, V5842, V5843, V5844,
+ V5845, V5846, V5847, V5848, V5849, V5850, V5851, V5852,
+ V5853, V5854, V5855, V5856, V5857, V5858, V5859, V5860,
+ }, // P[266]
+ {
+ V5861, V5862, V5863, V5864, V5865, V5866, V5867, V5868,
+ V5869, V5870, V5871, V5872, V5873, V5874, V5875, V5876,
+ V5877, V5878, V5879, V5880, V5881, V5882, V5883, V5884,
+ V5885, V5886, V5887, V5888, V5889, V5890, V5891, V5892,
+ }, // P[267]
+ {
+ V5893, V5894, V5895, V5896, V5897, V5898, V5899, V5900,
+ V5901, V5902, V5903, V5904, V5905, V5906, V5907, V5908,
+ V5909, V5910, V5911, V5912, V5913, V5914, V5915, V5916,
+ V5917, V5918, V5919, V5920, V5921, V5922, V5923, V5924,
+ }, // P[268]
+ {
+ V5925, V5926, V5927, V5928, V5929, V5930, V5931, V5932,
+ V5933, V5934, V5935, V5936, V5937, V5938, V5939, V5940,
+ V5941, V5942, V5943, V5944, V5945, V5946, V5947, V5948,
+ V5949, V5950, V5951, V5952, V5953, V5954, V5955, V5956,
+ }, // P[269]
+ {
+ V5957, V5958, V5959, V5960, V5961, V5962, V5963, V5964,
+ V5965, V5966, V5967, V5968, V5969, V5970, V5971, V5972,
+ V5973, V5974, V5975, V5976, V5977, V5978, V5979, V5980,
+ V5981, V5982, V5983, V5984, V5985, V5986, V5987, V5988,
+ }, // P[270]
+ {
+ V5989, V5990, V5991, V5992, V5993, V5994, V5995, V5996,
+ V5997, V5998, V5999, V6000, V6001, V6002, V6003, V6004,
+ V6005, V6006, V6007, V6008, V6009, V6010, V6011, V6012,
+ V6013, V6014, V6015, V6016, V6017, V6018, V6019, V6020,
+ }, // P[271]
+ {
+ V6021, V6022, V6023, V6024, V6025, V6026, V6027, V6028,
+ V6029, V6030, V6031, V6032, V6033, V6034, V6035, V6036,
+ V6037, V6038, V6039, V6040, V6041, V6042, V6043, V6044,
+ V6045, V6046, V6047, V6048, V6049, V6050, V6051, V6052,
+ }, // P[272]
+ {
+ V6053, V6054, V6055, V6056, V6057, V6058, V6059, V6060,
+ V6061, V6062, V6063, V6064, V6065, V6066, V6067, V6068,
+ V6069, V6070, V6071, V6072, V6073, V6074, V6075, V6076,
+ V6077, V6078, V6079, V6080, V6081, V6082, V6083, V6084,
+ }, // P[273]
+ {
+ V6085, V6086, V6087, V6088, V6089, V6090, V6091, V6092,
+ V6093, V6094, V6095, V6096, V6097, V6098, V6099, V6100,
+ V6101, V6102, V6103, V6104, V6105, V6106, V6107, V6108,
+ V6109, V6110, V6111, V6112, V6113, V6114, V6115, V6116,
+ }, // P[274]
+ {
+ V6117, V6118, V6119, V6120, V6121, V6122, V6123, V6124,
+ V6125, V6126, V6127, V6128, V6129, V6130, V6131, V6132,
+ V6133, V6134, V6135, V6136, V6137, V6138, V6139, V6140,
+ V6141, V6142, V6143, V6144, V6145, V6146, V6147, V6148,
+ }, // P[275]
+ {
+ V6149, V6150, V6151, V6152, V6153, V6154, V6155, V6156,
+ V6157, V6158, V6159, V6160, V6161, V6162, V6163, V6164,
+ V6165, V6166, V6167, V6168, V6169, V6170, V6171, V6172,
+ V6173, V6174, V6175, V6176, V6177, V6178, V6179, V6180,
+ }, // P[276]
+ {
+ V6181, V6182, V6183, V6184, V6185, V6186, V6187, V6188,
+ V6189, V6190, V6191, V6192, V6193, V6194, V6195, V6196,
+ V6197, V6198, V6199, V6200, V6201, V6202, V6203, V6204,
+ V6205, V6206, V6207, V6208, V6209, V6210, V6211, V6212,
+ }, // P[277]
+ {
+ V6213, V6214, V6215, V6216, V6217, V6218, V6219, V6220,
+ V6221, V6222, V6223, V6224, V6225, V6226, V6227, V6228,
+ V6229, V6230, V6231, V6232, V1735, V6233, V6234, V6235,
+ V6236, V6237, V6238, V6239, V6240, V6241, V6242, V6243,
+ }, // P[278]
+ {
+ V6244, V6245, V6246, V6247, V6248, V6249, V6250, V6251,
+ V6252, V6253, V6254, V6255, V6256, V6257, V6258, V6259,
+ V6260, V6261, V6262, V6263, V6264, V6265, V6266, V6267,
+ V6268, V6269, V6270, V6271, V6272, V6273, V6274, V6275,
+ }, // P[279]
+ {
+ V6276, V6277, V6278, V6279, V6280, V6281, V6282, V6283,
+ V6284, V6285, V6286, V6287, V6288, V6289, V6290, V6291,
+ V6292, V6293, V6294, V6295, V6296, V6297, V6298, V6299,
+ V6300, V6301, V6302, V6303, V6304, V6305, V6306, V6307,
+ }, // P[280]
+ {
+ V6308, V6309, V6310, V6311, V6312, V6313, V6314, V6315,
+ V6316, V6317, V6318, V6319, V6320, V6321, V6322, V6323,
+ V6324, V6325, V6326, V6327, V6328, V6329, V6330, V6331,
+ V6332, V6333, V6334, V6335, V6336, V6337, V6338, V6339,
+ }, // P[281]
+ {
+ V6340, V6341, V6342, V6343, V6344, V6345, V6346, V6347,
+ V6348, V6349, V6350, V6351, V6352, V6353, V6354, V6355,
+ V6356, V6357, V6358, V6359, V6360, V6361, V6362, V6363,
+ V6364, V6365, V6366, V6367, V6368, V6369, V6370, V6371,
+ }, // P[282]
+ {
+ V6372, V6373, V6374, V6375, V6376, V6377, V6378, V6379,
+ V6380, V6381, V6382, V6383, V6384, V6385, V6386, V6387,
+ V6388, V6389, V6390, V6391, V6392, V6393, V6394, V6395,
+ V6396, V6397, V6398, V6399, V6400, V6401, V6402, V6403,
+ }, // P[283]
+ {
+ V6404, V6405, V6406, V6407, V6408, V6409, V6410, V6411,
+ V6412, V6413, V6414, V6415, V6416, V6417, V6418, V6419,
+ V6420, V6421, V6422, V6423, V6424, V6425, V6426, V6427,
+ V6428, V6429, V6430, V6431, V6432, V6433, V6434, V6435,
+ }, // P[284]
+ {
+ V6436, V6437, V6438, V6439, V6440, V6441, V6442, V6443,
+ V6444, V6445, V6446, V6447, V6448, V6449, V6450, V6451,
+ V6452, V6453, V6454, V6455, V6456, V6457, V6458, V6459,
+ V6460, V6461, V6462, V6463, V6464, V6465, V6466, V6467,
+ }, // P[285]
+ {
+ V6468, V6469, V6470, V6471, V6472, V6473, V6474, V6475,
+ V6476, V6477, V6478, V6479, V6480, V6481, V6482, V6483,
+ V6484, V6485, V6486, V6487, V6488, V6489, V6490, V6491,
+ V6492, V6493, V6494, V6495, V6496, V6497, V6498, V6499,
+ }, // P[286]
+ {
+ V6500, V6501, V6502, V6503, V6504, V6505, V6506, V6507,
+ V6508, V6509, V6510, V6511, V6512, V6513, V6514, V6515,
+ V6516, V6517, V6518, V6519, V6520, V6521, V6522, V6523,
+ V6524, V6525, V6526, V6527, V6528, V6529, V6530, V6531,
+ }, // P[287]
+ {
+ V6532, V6533, V6534, V6535, V6536, V6537, V6538, V6539,
+ V6540, V6541, V6542, V6543, V6544, V6545, V6546, V6547,
+ V6548, V6549, V6550, V6551, V6552, V6553, V6554, V6555,
+ V6556, V6557, V6558, V6559, V6560, V6561, V6562, V6563,
+ }, // P[288]
+ {
+ V6564, V6565, V6566, V6567, V6568, V6569, V6570, V6571,
+ V6572, V6573, V6574, V6575, V6576, V6577, V6578, V6579,
+ V6580, V6581, V6582, V6583, V6584, V6585, V6586, V6587,
+ V6588, V6589, V6590, V6591, V6592, V6593, V6594, V6595,
+ }, // P[289]
+ {
+ V6596, V6597, V6598, V6599, V6600, V6601, V6602, V6603,
+ V6604, V6605, V6606, V6607, V6608, V6609, V6610, V6611,
+ V6612, V6613, V6614, V6615, V6616, V6617, V6618, V6619,
+ V6620, V6621, V6622, V6623, V6624, V6625, V6626, V6627,
+ }, // P[290]
+ {
+ V6628, V6629, V6630, V6631, V6632, V6633, V6634, V6635,
+ V6636, V6637, V6638, V6639, V6640, V6641, V6642, V6643,
+ V6644, V6645, V6646, V6647, V6648, V6649, V6650, V6651,
+ V6652, V6653, V6654, V6655, V6656, V6657, V6658, V6659,
+ }, // P[291]
+ {
+ V6660, V6661, V6662, V6663, V6664, V6665, V6666, V6667,
+ V6668, V6669, V6670, V6671, V6672, V6673, V6674, V6675,
+ V6676, V6677, V6678, V6679, V6680, V6681, V6682, V6683,
+ V6684, V6685, V6686, V6687, V6688, V6689, V6690, V6691,
+ }, // P[292]
+ {
+ V6692, V6693, V6694, V6695, V6696, V6697, V6698, V6699,
+ V6700, V6701, V6702, V6703, V6704, V6705, V6706, V6707,
+ V6708, V6709, V6710, V6711, V6712, V6713, V6714, V6715,
+ V6716, V6717, V6718, V6719, V6720, V6721, V6722, V6723,
+ }, // P[293]
+ {
+ V6724, V6725, V6726, V6727, V6728, V6729, V6730, V6731,
+ V6732, V6733, V6734, V6735, V6736, V6737, V6738, V6739,
+ V6740, V6741, V6742, V6743, V6744, V6745, V6746, V6747,
+ V6748, V6749, V6750, V6751, V6752, V6753, V6754, V6755,
+ }, // P[294]
+ {
+ V6756, V6757, V6758, V6759, V6760, V6761, V6762, V6763,
+ V6764, V6765, V6766, V6767, V6768, V6769, V6770, V6771,
+ V6772, V6773, V6774, V6775, V6776, V6777, V6778, V6779,
+ V6780, V6781, V6782, V6783, V6784, V6785, V6786, V6787,
+ }, // P[295]
+ {
+ V6788, V6789, V6790, V6791, V6792, V6793, V6794, V6795,
+ V6796, V6797, V6798, V6799, V6800, V6801, V6802, V6803,
+ V6804, V6805, V6806, V6807, V6808, V6809, V6810, V6811,
+ V6812, V6813, V6814, V6815, V6816, V6817, V6818, V6819,
+ }, // P[296]
+ {
+ V6820, V6821, V6822, V6823, V6824, V6825, V6826, V6827,
+ V6828, V6829, V6830, V6831, V6832, V6833, V6834, V6835,
+ V6836, V6837, V6838, V6839, V6840, V6841, V6842, V6843,
+ V6844, V6845, V6846, V6847, V6848, V6849, V6850, V6851,
+ }, // P[297]
+ {
+ V6852, V6853, V6854, V6855, V6856, V6857, V6858, V6859,
+ V6860, V6861, V6862, V6863, V6864, V6865, V6866, V6867,
+ V6868, V6869, V6870, V6871, V6872, V6873, V6874, V6875,
+ V6876, V6877, V6878, V6879, V6880, V6881, V6882, V6883,
+ }, // P[298]
+ {
+ V6884, V6885, V6886, V6887, V6888, V6889, V6890, V6891,
+ V6892, V6893, V6894, V6895, V6896, V6897, V6898, V6899,
+ V6900, V6901, V6902, V6903, V6904, V6905, V6906, V6907,
+ V6908, V6909, V6910, V6911, V6912, V6913, V6914, V6915,
+ }, // P[299]
+ {
+ V6916, V6917, V6918, V6919, V6920, V6921, V6922, V6923,
+ V6924, V6925, V6926, V6927, V6928, V6929, V6930, V6931,
+ V6932, V6933, V6934, V6935, V6936, V6937, V6938, V6939,
+ V6940, V6941, V6942, V6943, V6944, V6945, V6946, V6947,
+ }, // P[300]
+ {
+ V6948, V6949, V6950, V6951, V6952, V6953, V6954, V6955,
+ V6956, V6957, V6958, V6959, V6960, V6961, V6962, V6963,
+ V6964, V6965, V6966, V6967, V6968, V6969, V6970, V6971,
+ V6972, V6973, V6974, V6975, V6976, V6977, V6978, V6979,
+ }, // P[301]
+ {
+ V6980, V6981, V6982, V6983, V6984, V6985, V6986, V6987,
+ V6988, V6989, V6990, V6991, V6992, V6993, V6994, V6995,
+ V6996, V6997, V6998, V6999, V7000, V7001, V7002, V7003,
+ V7004, V7005, V7006, V7007, V7008, V7009, V7010, V7011,
+ }, // P[302]
+ {
+ V7012, V7013, V7014, V7015, V7016, V7017, V7018, V7019,
+ V7020, V7021, V7022, V7023, V7024, V7025, V7026, V7027,
+ V7028, V7029, V7030, V7031, V7032, V7033, V7034, V7035,
+ V7036, V7037, V7038, V7039, V7040, V7041, V7042, V7043,
+ }, // P[303]
+ {
+ V7044, V7045, V7046, V7047, V7048, V7049, V7050, V7051,
+ V7052, V7053, V7054, V7055, V7056, V7057, V7058, V7059,
+ V7060, V7061, V7062, V7063, V7064, V7065, V7066, V7067,
+ V7068, V7069, V7070, V7071, V7072, V7073, V7074, V7075,
+ }, // P[304]
+ {
+ V7076, V7077, V7078, V7079, V7080, V7081, V7082, V7083,
+ V7084, V7085, V7086, V7087, V7088, V7089, V7090, V7091,
+ V7092, V7093, V7094, V7095, V7096, V7097, V7098, V7099,
+ V7100, V7101, V7102, V7103, V7104, V7105, V7106, V7107,
+ }, // P[305]
+ {
+ V7108, V7109, V7110, V7111, V7112, V7113, V7114, V7115,
+ V7116, V7117, V7118, V7119, V7120, V7121, V7122, V7123,
+ V7124, V7125, V7126, V7127, V7128, V7129, V7130, V7131,
+ V7132, V7133, V7134, V7135, V7136, V7137, V7138, V7139,
+ }, // P[306]
+ {
+ V7140, V7141, V7142, V7143, V7144, V7145, V7146, V7147,
+ V7148, V7149, V7150, V7151, V7152, V7153, V7154, V7155,
+ V7156, V7157, V7158, V7159, V7160, V7161, V7162, V7163,
+ V7164, V7165, V7166, V7167, V7168, V7169, V7170, V7171,
+ }, // P[307]
+ {
+ V7172, V7173, V7174, V7175, V7176, V7177, V7178, V7179,
+ V7180, V7181, V7182, V7183, V7184, V7185, V7186, V7187,
+ V7188, V7189, V7190, V7191, V7192, V7193, V7194, V7195,
+ V7196, V7197, V7198, V7199, V7200, V7201, V7202, V7203,
+ }, // P[308]
+ {
+ V7204, V7205, V7206, V7207, V7208, V7209, V7210, V7211,
+ V7212, V7213, V7214, V7215, V7216, V7217, V7218, V7219,
+ V7220, V7221, V7222, V7223, V7224, V7225, V7226, V7227,
+ V7228, V7229, V7230, V7231, V7232, V7233, V7234, V7235,
+ }, // P[309]
+ {
+ V7236, V7237, V7238, V7239, V7240, V7241, V7242, V7243,
+ V7244, V7245, V7246, V7247, V7248, V7249, V7250, V7251,
+ V7252, V7253, V7254, V7255, V7256, V7257, V7258, V7259,
+ V7260, V7261, V7262, V7263, V7264, V7265, V7266, V7267,
+ }, // P[310]
+ {
+ V7268, V7269, V7270, V7271, V7272, V7273, V7274, V7275,
+ V7276, V7277, V7278, V7279, V7280, V7281, V7282, V7283,
+ V7284, V7285, V7286, V7287, V7288, V7289, V7290, V7291,
+ V7292, V7293, V7294, V7295, V7296, V7297, V7298, V7299,
+ }, // P[311]
+ {
+ V7300, V7301, V7302, V7303, V7304, V7305, V7306, V7307,
+ V7308, V7309, V7310, V7311, V7312, V7313, V7314, V7315,
+ V7316, V7317, V7318, V7319, V7320, V7321, V7322, V7323,
+ V7324, V7325, V7326, V7327, V7328, V7329, V7330, V7331,
+ }, // P[312]
+ {
+ V7332, V7333, V7334, V7335, V7336, V7337, V7338, V7339,
+ V7340, V7341, V7342, V7343, V7344, V7345, V7346, V7347,
+ V7348, V7349, V7350, V7351, V7352, V7353, V7354, V7355,
+ V7356, V7357, V7358, V7359, V7360, V7361, V7362, V7363,
+ }, // P[313]
+ {
+ V7364, V7365, V7366, V7367, V7368, V7369, V7370, V7371,
+ V7372, V7373, V7374, V7375, V7376, V7377, V7378, V7379,
+ V7380, V7381, V7382, V7383, V7384, V7385, V7386, V7387,
+ V7388, V7389, V7390, V7391, V7392, V7393, V7394, V7395,
+ }, // P[314]
+ {
+ V7396, V7397, V7398, V7399, V7400, V7401, V7402, V7403,
+ V7404, V7405, V7406, V7407, V1736, V7408, V7409, V7410,
+ V7411, V7412, V7413, V7414, V7415, V7416, V7417, V7418,
+ V7419, V7420, V7421, V7422, V7423, V7424, V7425, V7426,
+ }, // P[315]
+ {
+ V7427, V7428, V7429, V7430, V7431, V7432, V7433, V7434,
+ V7435, V7436, V7437, V7438, V7439, V7440, V7441, V7442,
+ V7443, V7444, V7445, V7446, V7447, V7448, V7449, V7450,
+ V7451, V7452, V7453, V7454, V7455, V7456, V7457, V7458,
+ }, // P[316]
+ {
+ V7459, V7460, V7461, V7462, V7463, V7464, V7465, V7466,
+ V7467, V7468, V7469, V7470, V7471, V7472, V7473, V7474,
+ V7475, V7476, V7477, V7478, V7479, V7480, V7481, V7482,
+ V7483, V7484, V7485, V7486, V7487, V7488, V7489, V7490,
+ }, // P[317]
+ {
+ V7491, V7492, V7493, V7494, V7495, V7496, V7497, V7498,
+ V7499, V7500, V7501, V7502, V7503, V7504, V7505, V7506,
+ V7507, V7508, V7509, V7510, V7511, V7512, V7513, V7514,
+ V7515, V7516, V7517, V7518, V7519, V7520, V7521, V7522,
+ }, // P[318]
+ {
+ V7523, V7524, V7525, V7526, V7527, V7528, V7529, V7530,
+ V7531, V7532, V7533, V7534, V7535, V7536, V7537, V7538,
+ V7539, V7540, V7541, V7542, V7543, V7544, V7545, V7546,
+ V7547, V7548, V7549, V7550, V7551, V7552, V7553, V7554,
+ }, // P[319]
+ {
+ V7555, V7556, V7557, V7558, V7559, V7560, V7561, V7562,
+ V7563, V7564, V7565, V7566, V7567, V7568, V7569, V7570,
+ V7571, V7572, V7573, V7574, V7575, V7576, V7577, V7578,
+ V7579, V7580, V7581, V7582, V7583, V7584, V7585, V7586,
+ }, // P[320]
+ {
+ V7587, V7588, V7589, V7590, V7591, V7592, V7593, V7594,
+ V7595, V7596, V7597, V7598, V7599, V7600, V7601, V7602,
+ V7603, V7604, V7605, V7606, V7607, V7608, V7609, V7610,
+ V7611, V7612, V7613, V7614, V7615, V7616, V7617, V7618,
+ }, // P[321]
+ {
+ V7619, V7620, V7621, V7622, V7623, V7624, V7625, V7626,
+ V7627, V7628, V7629, V7630, V7631, V7632, V7633, V7634,
+ V7635, V7636, V7637, V7638, V7639, V7640, V7641, V7642,
+ V7643, V7644, V7645, V7646, V7647, V7648, V7649, V7650,
+ }, // P[322]
+ {
+ V7651, V7652, V7653, V7654, V7655, V7656, V7657, V7658,
+ V7659, V7660, V7661, V7662, V7663, V7664, V7665, V7666,
+ V7667, V7668, V7669, V7670, V7671, V7672, V7673, V7674,
+ V7675, V7676, V7677, V7678, V7679, V7680, V7681, V7682,
+ }, // P[323]
+ {
+ V7683, V7684, V7685, V7686, V7687, V7688, V7689, V7690,
+ V7691, V7692, V7693, V7694, V7695, V7696, V7697, V7698,
+ V7699, V7700, V7701, V7702, V7703, V7704, V7705, V7706,
+ V7707, V7708, V7709, V7710, V7711, V7712, V7713, V7714,
+ }, // P[324]
+ {
+ V7715, V7716, V7717, V7718, V7719, V7720, V7721, V7722,
+ V7723, V7724, V7725, V7726, V7727, V7728, V7729, V7730,
+ V7731, V7732, V7733, V7734, V7735, V7736, V7737, V7738,
+ V7739, V7740, V7741, V7742, V7743, V7744, V7745, V7746,
+ }, // P[325]
+ {
+ V7747, V7748, V7749, V7750, V7751, V7752, V7753, V7754,
+ V7755, V7756, V7757, V7758, V7759, V7760, V7761, V7762,
+ V7763, V7764, V7765, V7766, V7767, V7768, V7769, V7770,
+ V7771, V7772, V7773, V7774, V7775, V7776, V7777, V7778,
+ }, // P[326]
+ {
+ V7779, V7780, V7781, V7782, V7783, V7784, V7785, V7786,
+ V7787, V7788, V7789, V7790, V7791, V7792, V7793, V7794,
+ V7795, V7796, V7797, V7798, V7799, V7800, V7801, V7802,
+ V7803, V7804, V7805, V7806, V7807, V7808, V7809, V7810,
+ }, // P[327]
+ {
+ V7811, V7812, V7813, V7814, V7815, V7816, V7817, V7818,
+ V7819, V7820, V7821, V7822, V7823, V7824, V7825, V7826,
+ V7827, V7828, V7829, V7830, V7831, V7832, V7833, V7834,
+ V7835, V7836, V7837, V7838, V7839, V7840, V7841, V7842,
+ }, // P[328]
+ {
+ V7843, V7844, V7845, V7846, V7847, V7848, V7849, V7850,
+ V7851, V7852, V7853, V7854, V7855, V7856, V7857, V7858,
+ V7859, V7860, V7861, V7862, V7863, V7864, V7865, V7866,
+ V7867, V7868, V7869, V7870, V7871, V7872, V7873, V7874,
+ }, // P[329]
+ {
+ V7875, V7876, V7877, V7878, V7879, V7880, V7881, V7882,
+ V7883, V7884, V7885, V7886, V7887, V7888, V7889, V7890,
+ V7891, V7892, V7893, V7894, V7895, V7896, V7897, V7898,
+ V7899, V7900, V7901, V7902, V7903, V7904, V7905, V7906,
+ }, // P[330]
+ {
+ V7907, V7908, V7909, V7910, V7911, V7912, V7913, V7914,
+ V7915, V7916, V7917, V7918, V7919, V7920, V7921, V7922,
+ V7923, V7924, V7925, V7926, V7927, V7928, V7929, V7930,
+ V7931, V7932, V7933, V7934, V7935, V7936, V7937, V7938,
+ }, // P[331]
+ {
+ V7939, V7940, V7941, V7942, V7943, V7944, V7945, V7946,
+ V7947, V7948, V7949, V7950, V7951, V7952, V7953, V7954,
+ V7955, V7956, V7957, V7958, V7959, V7960, V7961, V7962,
+ V7963, V7964, V7965, V7966, V7967, V7968, V7969, V7970,
+ }, // P[332]
+ {
+ V7971, V7972, V7973, V7974, V7975, V7976, V7977, V7978,
+ V7979, V7980, V7981, V7982, V7983, V7984, V7985, V7986,
+ V7987, V7988, V7989, V7990, V7991, V7992, V7993, V7994,
+ V7995, V7996, V7997, V7998, V7999, V8000, V8001, V8002,
+ }, // P[333]
+ {
+ V8003, V8004, V8005, V8006, V8007, V8008, V8009, V8010,
+ V8011, V8012, V8013, V8014, V8015, V8016, V8017, V8018,
+ V8019, V8020, V8021, V8022, V8023, V8024, V8025, V8026,
+ V8027, V8028, V8029, V8030, V8031, V8032, V8033, V8034,
+ }, // P[334]
+ {
+ V8035, V8036, V8037, V8038, V8039, V8040, V8041, V8042,
+ V8043, V8044, V8045, V8046, V8047, V8048, V8049, V8050,
+ V8051, V8052, V8053, V8054, V8055, V8056, V8057, V8058,
+ V8059, V8060, V8061, V8062, V8063, V8064, V8065, V8066,
+ }, // P[335]
+ {
+ V8067, V8068, V8069, V8070, V8071, V8072, V8073, V8074,
+ V8075, V8076, V8077, V8078, V8079, V8080, V8081, V8082,
+ V8083, V8084, V8085, V8086, V8087, V8088, V8089, V8090,
+ V8091, V8092, V8093, V8094, V8095, V8096, V8097, V8098,
+ }, // P[336]
+ {
+ V8099, V8100, V8101, V8102, V8103, V8104, V8105, V8106,
+ V8107, V8108, V8109, V8110, V8111, V8112, V8113, V8114,
+ V8115, V8116, V8117, V8118, V8119, V8120, V8121, V8122,
+ V8123, V8124, V8125, V8126, V8127, V8128, V8129, V8130,
+ }, // P[337]
+ {
+ V8131, V8132, V8133, V8134, V8135, V8136, V8137, V8138,
+ V8139, V8140, V8141, V8142, V8143, V8144, V8145, V8146,
+ V8147, V8148, V8149, V8150, V8151, V8152, V8153, V8154,
+ V8155, V8156, V8157, V8158, V8159, V8160, V8161, V8162,
+ }, // P[338]
+ {
+ V8163, V8164, V8165, V8166, V8167, V8168, V8169, V8170,
+ V8171, V8172, V8173, V8174, V8175, V8176, V8177, V8178,
+ V8179, V8180, V8181, V8182, V8183, V8184, V8185, V8186,
+ V8187, V8188, V8189, V8190, V8191, V8192, V8193, V8194,
+ }, // P[339]
+ {
+ V8195, V8196, V8197, V8198, V8199, V8200, V8201, V8202,
+ V8203, V8204, V8205, V8206, V8207, V8208, V8209, V8210,
+ V8211, V8212, V8213, V8214, V8215, V8216, V8217, V8218,
+ V8219, V8220, V8221, V8222, V8223, V8224, V8225, V8226,
+ }, // P[340]
+ {
+ V8227, V8228, V8229, V8230, V8231, V8232, V8233, V8234,
+ V8235, V8236, V8237, V8238, V8239, V8240, V8241, V8242,
+ V8243, V8244, V8245, V8246, V8247, V8248, V8249, V8250,
+ V8251, V8252, V8253, V8254, V8255, V8256, V8257, V8258,
+ }, // P[341]
+ {
+ V8259, V8260, V8261, V8262, V8263, V8264, V8265, V8266,
+ V8267, V8268, V8269, V8270, V8271, V8272, V8273, V8274,
+ V8275, V8276, V8277, V8278, V8279, V8280, V8281, V8282,
+ V8283, V8284, V8285, V8286, V8287, V8288, V8289, V8290,
+ }, // P[342]
+ {
+ V8291, V8292, V8293, V8294, V8295, V8296, V8297, V8298,
+ V8299, V8300, V8301, V8302, V8303, V8304, V8305, V8306,
+ V8307, V8308, V8309, V8310, V8311, V8312, V8313, V8314,
+ V8315, V8316, V8317, V8318, V8319, V8320, V8321, V8322,
+ }, // P[343]
+ {
+ V8323, V8324, V8325, V8326, V8327, V8328, V8329, V8330,
+ V8331, V8332, V8333, V8334, V8335, V8336, V8337, V8338,
+ V8339, V8340, V8341, V8342, V8343, V8344, V8345, V8346,
+ V8347, V8348, V8349, V8350, V8351, V8352, V8353, V8354,
+ }, // P[344]
+ {
+ V8355, V8356, V8357, V8358, V8359, V8360, V8361, V8362,
+ V8363, V8364, V8365, V8366, V8367, V8368, V8369, V8370,
+ V8371, V8372, V8373, V8374, V8375, V8376, V8377, V8378,
+ V8379, V8380, V8381, V8382, V8383, V8384, V8385, V8386,
+ }, // P[345]
+ {
+ V8387, V8388, V8389, V8390, V8391, V8392, V8393, V8394,
+ V8395, V8396, V8397, V8398, V8399, V8400, V8401, V8402,
+ V8403, V8404, V8405, V8406, V8407, V8408, V8409, V8410,
+ V8411, V8412, V8413, V8414, V8415, V8416, V8417, V8418,
+ }, // P[346]
+ {
+ V8419, V8420, V8421, V8422, V8423, V8424, V8425, V8426,
+ V8427, V8428, V8429, V8430, V8431, V8432, V8433, V8434,
+ V8435, V8436, V8437, V8438, V8439, V8440, V8441, V8442,
+ V8443, V8444, V8445, V8446, V8447, V8448, V8449, V8450,
+ }, // P[347]
+ {
+ V8451, V8452, V8453, V8454, V8455, V8456, V8457, V8458,
+ V8459, V8460, V8461, V8462, V8463, V8464, V8465, V8466,
+ V8467, V8468, V8469, V8470, V8471, V8472, V8473, V8474,
+ V8475, V8476, V8477, V8478, V8479, V8480, V8481, V8482,
+ }, // P[348]
+ {
+ V8483, V8484, V8485, V8486, V8487, V8488, V8489, V8490,
+ V8491, V8492, V8493, V8494, V8495, V8496, V8497, V8498,
+ V8499, V8500, V8501, V8502, V8503, V8504, V8505, V8506,
+ V8507, V8508, V8509, V8510, V8511, V8512, V8513, V8514,
+ }, // P[349]
+ {
+ V8515, V8516, V8517, V8518, V8519, V8520, V8521, V8522,
+ V8523, V8524, V8525, V8526, V8527, V8528, V8529, V8530,
+ V8531, V8532, V8533, V8534, V8535, V8536, V8537, V8538,
+ V8539, V8540, V8541, V8542, V8543, V8544, V8545, V8546,
+ }, // P[350]
+ {
+ V8547, V8548, V8549, V8550, V8551, V8552, V8553, V8554,
+ V8555, V8556, V8557, V8558, V8559, V8560, V8561, V8562,
+ V8563, V8564, V8565, V8566, V8567, V8568, V8569, V8570,
+ V8571, V8572, V8573, V8574, V8575, V8576, V8577, V8578,
+ }, // P[351]
+ {
+ V8579, V8580, V8581, V8582, V1737, V8583, V8584, V8585,
+ V8586, V8587, V8588, V8589, V8590, V8591, V8592, V8593,
+ V8594, V8595, V8596, V8597, V8598, V8599, V8600, V8601,
+ V8602, V8603, V8604, V8605, V8606, V8607, V8608, V8609,
+ }, // P[352]
+ {
+ V8610, V8611, V8612, V8613, V8614, V8615, V8616, V8617,
+ V8618, V8619, V8620, V8621, V8622, V8623, V8624, V8625,
+ V8626, V8627, V8628, V8629, V8630, V8631, V8632, V8633,
+ V8634, V8635, V8636, V8637, V8638, V8639, V8640, V8641,
+ }, // P[353]
+ {
+ V8642, V8643, V8644, V8645, V8646, V8647, V8648, V8649,
+ V8650, V8651, V8652, V8653, V8654, V8655, V8656, V8657,
+ V8658, V8659, V8660, V8661, V8662, V8663, V8664, V8665,
+ V8666, V8667, V8668, V8669, V8670, V8671, V8672, V8673,
+ }, // P[354]
+ {
+ V8674, V8675, V8676, V8677, V8678, V8679, V8680, V8681,
+ V8682, V8683, V8684, V8685, V8686, V8687, V8688, V8689,
+ V8690, V8691, V8692, V8693, V8694, V8695, V8696, V8697,
+ V8698, V8699, V8700, V8701, V8702, V8703, V8704, V8705,
+ }, // P[355]
+ {
+ V8706, V8707, V8708, V8709, V8710, V8711, V8712, V8713,
+ V8714, V8715, V8716, V8717, V8718, V8719, V8720, V8721,
+ V8722, V8723, V8724, V8725, V8726, V8727, V8728, V8729,
+ V8730, V8731, V8732, V8733, V8734, V8735, V8736, V8737,
+ }, // P[356]
+ {
+ V8738, V8739, V8740, V8741, V8742, V8743, V8744, V8745,
+ V8746, V8747, V8748, V8749, V8750, V8751, V8752, V8753,
+ V8754, V8755, V8756, V8757, V8758, V8759, V8760, V8761,
+ V8762, V8763, V8764, V8765, V8766, V8767, V8768, V8769,
+ }, // P[357]
+ {
+ V8770, V8771, V8772, V8773, V8774, V8775, V8776, V8777,
+ V8778, V8779, V8780, V8781, V8782, V8783, V8784, V8785,
+ V8786, V8787, V8788, V8789, V8790, V8791, V8792, V8793,
+ V8794, V8795, V8796, V8797, V8798, V8799, V8800, V8801,
+ }, // P[358]
+ {
+ V8802, V8803, V8804, V8805, V8806, V8807, V8808, V8809,
+ V8810, V8811, V8812, V8813, V8814, V8815, V8816, V8817,
+ V8818, V8819, V8820, V8821, V8822, V8823, V8824, V8825,
+ V8826, V8827, V8828, V8829, V8830, V8831, V8832, V8833,
+ }, // P[359]
+ {
+ V8834, V8835, V8836, V8837, V8838, V8839, V8840, V8841,
+ V8842, V8843, V8844, V8845, V8846, V8847, V8848, V8849,
+ V8850, V8851, V8852, V8853, V8854, V8855, V8856, V8857,
+ V8858, V8859, V8860, V8861, V8862, V8863, V8864, V8865,
+ }, // P[360]
+ {
+ V8866, V8867, V8868, V8869, V8870, V8871, V8872, V8873,
+ V8874, V8875, V8876, V8877, V8878, V8879, V8880, V8881,
+ V8882, V8883, V8884, V8885, V8886, V8887, V8888, V8889,
+ V8890, V8891, V8892, V8893, V8894, V8895, V8896, V8897,
+ }, // P[361]
+ {
+ V8898, V8899, V8900, V8901, V8902, V8903, V8904, V8905,
+ V8906, V8907, V8908, V8909, V8910, V8911, V8912, V8913,
+ V8914, V8915, V8916, V8917, V8918, V8919, V8920, V8921,
+ V8922, V8923, V8924, V8925, V8926, V8927, V8928, V8929,
+ }, // P[362]
+ {
+ V8930, V8931, V8932, V8933, V8934, V8935, V8936, V8937,
+ V8938, V8939, V8940, V8941, V8942, V8943, V8944, V8945,
+ V1746, V8946, V8947, V8948, V8949, V8950, V8951, V8952,
+ V8953, V8954, V8955, V8956, V8957, V8958, V8959, V8960,
+ }, // P[363]
+ {
+ V8961, V8962, V8963, V8964, V8965, V8966, V8967, V8968,
+ V8969, V8970, V8971, V8972, V8973, V8974, V8975, V8976,
+ V8977, V8978, V8979, V8980, V8981, V8982, V8983, V8984,
+ V8985, V8986, V8987, V8988, V8989, V8990, V8991, V8992,
+ }, // P[364]
+ {
+ V8993, V8994, V8995, V8996, V8997, V8998, V8999, V9000,
+ V9001, V9002, V9003, V9004, V9005, V9006, V9007, V9008,
+ V9009, V9010, V9011, V9012, V9013, V9014, V9015, V9016,
+ V9017, V9018, V9019, V9020, V9021, V9022, V9023, V9024,
+ }, // P[365]
+ {
+ V9025, V9026, V9027, V9028, V9029, V9030, V9031, V9032,
+ V9033, V9034, V9035, V9036, V9037, V9038, V9039, V9040,
+ V9041, V9042, V9043, V9044, V9045, V9046, V9047, V9048,
+ V9049, V9050, V9051, V9052, V9053, V9054, V9055, V9056,
+ }, // P[366]
+ {
+ V9057, V9058, V9059, V9060, V9061, V9062, V9063, V9064,
+ V9065, V9066, V9067, V9068, V9069, V9070, V9071, V9072,
+ V9073, V9074, V9075, V9076, V9077, V9078, V9079, V9080,
+ V9081, V9082, V9083, V9084, V9085, V9086, V9087, V9088,
+ }, // P[367]
+ {
+ V9089, V9090, V9091, V9092, V9093, V9094, V9095, V9096,
+ V9097, V9098, V9099, V9100, V9101, V9102, V9103, V9104,
+ V9105, V9106, V9107, V9108, V9109, V9110, V9111, V9112,
+ V9113, V9114, V9115, V9116, V9117, V9118, V9119, V9120,
+ }, // P[368]
+ {
+ V9121, V9122, V9123, V9124, V9125, V9126, V9127, V9128,
+ V9129, V9130, V9131, V9132, V9133, V9134, V9135, V9136,
+ V9137, V9138, V9139, V9140, V9141, V9142, V9143, V9144,
+ V9145, V9146, V9147, V9148, V9149, V9150, V9151, V9152,
+ }, // P[369]
+ {
+ V9153, V9154, V9155, V9156, V9157, V9158, V9159, V9160,
+ V9161, V9162, V9163, V9164, V9165, V9166, V9167, V9168,
+ V1738, V9169, V9170, V9171, V9172, V9173, V9174, V9175,
+ V9176, V9177, V9178, V9179, V9180, V9181, V9182, V9183,
+ }, // P[370]
+ {
+ V9184, V9185, V9186, V9187, V9188, V9189, V9190, V9191,
+ V9192, V9193, V9194, V9195, V9196, V9197, V9198, V9199,
+ V9200, V9201, V9202, V9203, V9204, V9205, V9206, V9207,
+ V9208, V9209, V9210, V9211, V9212, V9213, V9214, V9215,
+ }, // P[371]
+ {
+ V9216, V9217, V9218, V9219, V9220, V9221, V9222, V9223,
+ V9224, V9225, V9226, V9227, V9228, V9229, V9230, V9231,
+ V9232, V9233, V9234, V9235, V9236, V9237, V9238, V9239,
+ V9240, V9241, V9242, V9243, V9244, V9245, V9246, V9247,
+ }, // P[372]
+ {
+ V9248, V9249, V9250, V9251, V9252, V9253, V9254, V9255,
+ V9256, V9257, V9258, V9259, V9260, V9261, V9262, V9263,
+ V9264, V9265, V9266, V9267, V9268, V9269, V9270, V9271,
+ V9272, V9273, V9274, V9275, V9276, V9277, V9278, V9279,
+ }, // P[373]
+ {
+ V9280, V9281, V9282, V9283, V9284, V9285, V9286, V9287,
+ V9288, V9289, V9290, V9291, V9292, V9293, V9294, V9295,
+ V9296, V9297, V9298, V9299, V9300, V9301, V9302, V9303,
+ V9304, V9305, V9306, V9307, V9308, V9309, V9310, V9311,
+ }, // P[374]
+ {
+ V9312, V9313, V9314, V9315, V9316, V9317, V9318, V9319,
+ V9320, V9321, V9322, V9323, V9324, V9325, V9326, V9327,
+ V9328, V9329, V9330, V9331, V9332, V9333, V9334, V9335,
+ V9336, V9337, V9338, V9339, V9340, V9341, V9342, V9343,
+ }, // P[375]
+ {
+ V9344, V9345, V9346, V9347, V9348, V9349, V9350, V9351,
+ V9352, V9353, V9354, V9355, V9356, V9357, V9358, V9359,
+ V9360, V9361, V9362, V9363, V9364, V9365, V9366, V9367,
+ V9368, V9369, V9370, V9371, V9372, V9373, V9374, V9375,
+ }, // P[376]
+ {
+ V9376, V9377, V9378, V9379, V9380, V9381, V9382, V9383,
+ V9384, V9385, V9386, V9387, V9388, V9389, V9390, V9391,
+ V9392, V9393, V9394, V9395, V9396, V9397, V9398, V9399,
+ V9400, V9401, V9402, V9403, V9404, V9405, V9406, V9407,
+ }, // P[377]
+ {
+ V9408, V9409, V9410, V9411, V9412, V9413, V9414, V9415,
+ V9416, V9417, V9418, V9419, V9420, V9421, V9422, V9423,
+ V9424, V9425, V9426, V9427, V9428, V9429, V9430, V9431,
+ V9432, V9433, V9434, V9435, V9436, V9437, V9438, V9439,
+ }, // P[378]
+ {
+ V9440, V9441, V9442, V9443, V9444, V9445, V9446, V9447,
+ V9448, V9449, V9450, V9451, V9452, V9453, V9454, V9455,
+ V9456, V9457, V9458, V9459, V9460, V9461, V9462, V9463,
+ V9464, V9465, V9466, V9467, V9468, V9469, V9470, V9471,
+ }, // P[379]
+ {
+ V9472, V9473, V9474, V9475, V9476, V9477, V9478, V9479,
+ V9480, V9481, V9482, V9483, V9484, V9485, V9486, V9487,
+ V9488, V9489, V9490, V9491, V9492, V9493, V9494, V9495,
+ V9496, V9497, V9498, V9499, V9500, V9501, V9502, V9503,
+ }, // P[380]
+ {
+ V9504, V9505, V9506, V9507, V9508, V9509, V9510, V9511,
+ V9512, V9513, V9514, V9515, V9516, V9517, V9518, V9519,
+ V9520, V9521, V9522, V9523, V9524, V9525, V9526, V9527,
+ V9528, V9529, V9530, V9531, V9532, V9533, V9534, V9535,
+ }, // P[381]
+ {
+ V9536, V9537, V9538, V9539, V9540, V9541, V9542, V9543,
+ V9544, V9545, V9546, V9547, V9548, V9549, V9550, V9551,
+ V9552, V9553, V9554, V9555, V9556, V9557, V9558, V9559,
+ V9560, V9561, V9562, V9563, V9564, V9565, V9566, V9567,
+ }, // P[382]
+ {
+ V9568, V9569, V9570, V9571, V9572, V9573, V9574, V9575,
+ V9576, V9577, V9578, V9579, V9580, V9581, V9582, V9583,
+ V9584, V9585, V9586, V9587, V9588, V9589, V9590, V9591,
+ V9592, V9593, V9594, V9595, V9596, V9597, V9598, V9599,
+ }, // P[383]
+ {
+ V9600, V9601, V9602, V9603, V9604, V9605, V9606, V9607,
+ V9608, V9609, V9610, V9611, V9612, V9613, V9614, V9615,
+ V9616, V9617, V9618, V9619, V9620, V9621, V9622, V9623,
+ V9624, V9625, V9626, V9627, V9628, V9629, V9630, V9631,
+ }, // P[384]
+ {
+ V9632, V9633, V9634, V9635, V9636, V9637, V9638, V9639,
+ V9640, V9641, V9642, V9643, V9644, V9645, V9646, V9647,
+ V9648, V9649, V9650, V9651, V9652, V9653, V9654, V9655,
+ V9656, V9657, V9658, V9659, V9660, V9661, V9662, V9663,
+ }, // P[385]
+ {
+ V9664, V9665, V9666, V9667, V9668, V9669, V9670, V9671,
+ V9672, V9673, V9674, V9675, V9676, V9677, V9678, V9679,
+ V9680, V9681, V9682, V9683, V9684, V9685, V9686, V9687,
+ V9688, V9689, V9690, V9691, V9692, V9693, V9694, V9695,
+ }, // P[386]
+ {
+ V9696, V9697, V9698, V9699, V9700, V9701, V9702, V9703,
+ V9704, V9705, V9706, V9707, V9708, V9709, V9710, V9711,
+ V9712, V9713, V9714, V9715, V9716, V9717, V9718, V9719,
+ V9720, V9721, V9722, V9723, V9724, V9725, V9726, V9727,
+ }, // P[387]
+ {
+ V9728, V9729, V9730, V9731, V9732, V9733, V9734, V9735,
+ V9736, V9737, V9738, V9739, V9740, V9741, V9742, V9743,
+ V9744, V9745, V9746, V9747, V9748, V9749, V9750, V9751,
+ V9752, V9753, V9754, V9755, V9756, V9757, V9758, V9759,
+ }, // P[388]
+ {
+ V9760, V9761, V9762, V9763, V9764, V9765, V9766, V9767,
+ V9768, V9769, V9770, V9771, V9772, V9773, V9774, V9775,
+ V9776, V9777, V9778, V9779, V9780, V9781, V9782, V9783,
+ V9784, V9785, V9786, V9787, V9788, V9789, V9790, V9791,
+ }, // P[389]
+ {
+ V9792, V9793, V9794, V9795, V9796, V9797, V9798, V9799,
+ V9800, V9801, V9802, V9803, V9804, V9805, V9806, V9807,
+ V9808, V9809, V9810, V9811, V9812, V9813, V9814, V9815,
+ V9816, V9817, V9818, V9819, V9820, V9821, V9822, V9823,
+ }, // P[390]
+ {
+ V9824, V9825, V9826, V9827, V9828, V9829, V9830, V9831,
+ V9832, V9833, V9834, V9835, V9836, V9837, V9838, V9839,
+ V9840, V9841, V9842, V9843, V9844, V9845, V9846, V9847,
+ V9848, V9849, V9850, V9851, V9852, V9853, V9854, V9855,
+ }, // P[391]
+ {
+ V9856, V9857, V9858, V9859, V9860, V9861, V9862, V9863,
+ V9864, V9865, V9866, V9867, V9868, V9869, V9870, V9871,
+ V9872, V9873, V9874, V9875, V9876, V9877, V9878, V9879,
+ V9880, V9881, V9882, V9883, V9884, V9885, V9886, V9887,
+ }, // P[392]
+ {
+ V9888, V9889, V9890, V9891, V9892, V9893, V9894, V9895,
+ V9896, V9897, V9898, V9899, V9900, V9901, V9902, V9903,
+ V9904, V9905, V9906, V9907, V9908, V9909, V9910, V9911,
+ V9912, V9913, V9914, V9915, V9916, V9917, V9918, V9919,
+ }, // P[393]
+ {
+ V9920, V9921, V9922, V9923, V9924, V9925, V9926, V9927,
+ V9928, V9929, V9930, V9931, V9932, V9933, V9934, V9935,
+ V9936, V9937, V9938, V9939, V9940, V9941, V9942, V9943,
+ V9944, V9945, V9946, V9947, V9948, V9949, V9950, V9951,
+ }, // P[394]
+ {
+ V9952, V9953, V9954, V9955, V9956, V9957, V9958, V9959,
+ V9960, V9961, V9962, V9963, V9964, V9965, V9966, V9967,
+ V9968, V9969, V9970, V9971, V9972, V9973, V9974, V9975,
+ V9976, V9977, V9978, V9979, V9980, V9981, V9982, V9983,
+ }, // P[395]
+ {
+ V9984, V9985, V9986, V9987, V9988, V9989, V9990, V9991,
+ V9992, V9993, V9994, V9995, V9996, V9997, V9998, V9999,
+ V10000, V10001, V10002, V10003, V10004, V10005, V10006, V10007,
+ V10008, V10009, V10010, V10011, V10012, V10013, V10014, V10015,
+ }, // P[396]
+ {
+ V10016, V10017, V10018, V10019, V10020, V10021, V10022, V10023,
+ V10024, V10025, V10026, V10027, V10028, V10029, V10030, V10031,
+ V10032, V10033, V10034, V10035, V10036, V10037, V10038, V10039,
+ V10040, V10041, V10042, V10043, V10044, V10045, V10046, V10047,
+ }, // P[397]
+ {
+ V10048, V10049, V10050, V10051, V10052, V10053, V10054, V10055,
+ V10056, V10057, V10058, V10059, V10060, V10061, V10062, V10063,
+ V10064, V10065, V10066, V10067, V10068, V10069, V10070, V10071,
+ V10072, V10073, V10074, V10075, V10076, V10077, V10078, V10079,
+ }, // P[398]
+ {
+ V10080, V10081, V10082, V10083, V10084, V10085, V10086, V10087,
+ V10088, V10089, V10090, V10091, V10092, V10093, V10094, V10095,
+ V10096, V10097, V10098, V10099, V10100, V10101, V10102, V10103,
+ V10104, V10105, V10106, V10107, V10108, V10109, V10110, V10111,
+ }, // P[399]
+ {
+ V10112, V10113, V10114, V10115, V10116, V10117, V10118, V10119,
+ V10120, V10121, V10122, V10123, V10124, V10125, V10126, V10127,
+ V10128, V10129, V10130, V10131, V10132, V10133, V10134, V10135,
+ V10136, V10137, V10138, V10139, V10140, V10141, V10142, V10143,
+ }, // P[400]
+ {
+ V10144, V10145, V10146, V10147, V10148, V10149, V10150, V10151,
+ V10152, V10153, V10154, V10155, V10156, V10157, V10158, V10159,
+ V10160, V10161, V10162, V10163, V10164, V10165, V10166, V10167,
+ V10168, V10169, V10170, V10171, V10172, V10173, V10174, V10175,
+ }, // P[401]
+ {
+ V10176, V10177, V10178, V10179, V10180, V10181, V10182, V10183,
+ V10184, V10185, V10186, V10187, V10188, V10189, V10190, V10191,
+ V10192, V10193, V10194, V10195, V10196, V10197, V10198, V10199,
+ V10200, V10201, V10202, V10203, V10204, V10205, V10206, V10207,
+ }, // P[402]
+ {
+ V10208, V10209, V10210, V10211, V10212, V10213, V10214, V10215,
+ V10216, V10217, V10218, V10219, V10220, V10221, V10222, V10223,
+ V10224, V10225, V10226, V10227, V10228, V10229, V10230, V10231,
+ V10232, V10233, V10234, V10235, V10236, V10237, V10238, V10239,
+ }, // P[403]
+ {
+ V10240, V10241, V10242, V10243, V10244, V10245, V10246, V10247,
+ V10248, V10249, V10250, V10251, V10252, V10253, V10254, V10255,
+ V10256, V10257, V10258, V10259, V10260, V10261, V10262, V10263,
+ V10264, V10265, V10266, V10267, V10268, V10269, V10270, V10271,
+ }, // P[404]
+ {
+ V10272, V10273, V10274, V10275, V10276, V10277, V10278, V10279,
+ V10280, V10281, V10282, V10283, V10284, V10285, V10286, V10287,
+ V10288, V10289, V10290, V10291, V10292, V10293, V10294, V10295,
+ V10296, V10297, V10298, V10299, V10300, V10301, V10302, V10303,
+ }, // P[405]
+ {
+ V10304, V10305, V10306, V10307, V10308, V10309, V10310, V10311,
+ V10312, V10313, V10314, V10315, V10316, V10317, V10318, V10319,
+ V10320, V10321, V10322, V10323, V10324, V10325, V10326, V10327,
+ V10328, V10329, V10330, V10331, V10332, V10333, V10334, V10335,
+ }, // P[406]
+ {
+ V10336, V10337, V10338, V10339, V10340, V10341, V10342, V10343,
+ V1739, V10344, V10345, V10346, V10347, V10348, V10349, V10350,
+ V10351, V10352, V10353, V10354, V10355, V10356, V10357, V10358,
+ V10359, V10360, V10361, V10362, V10363, V10364, V10365, V10366,
+ }, // P[407]
+ {
+ V10367, V10368, V10369, V10370, V10371, V10372, V10373, V10374,
+ V10375, V10376, V10377, V10378, V10379, V10380, V10381, V10382,
+ V10383, V10384, V10385, V10386, V10387, V10388, V10389, V10390,
+ V10391, V10392, V10393, V10394, V10395, V10396, V10397, V10398,
+ }, // P[408]
+ {
+ V10399, V10400, V10401, V10402, V10403, V10404, V10405, V10406,
+ V10407, V10408, V10409, V10410, V10411, V10412, V10413, V10414,
+ V10415, V10416, V10417, V10418, V10419, V10420, V10421, V10422,
+ V10423, V10424, V10425, V10426, V10427, V10428, V10429, V10430,
+ }, // P[409]
+ {
+ V10431, V10432, V10433, V10434, V10435, V10436, V10437, V10438,
+ V10439, V10440, V10441, V10442, V10443, V10444, V10445, V10446,
+ V10447, V10448, V10449, V10450, V10451, V10452, V10453, V10454,
+ V10455, V10456, V10457, V10458, V10459, V10460, V10461, V10462,
+ }, // P[410]
+ {
+ V10463, V10464, V10465, V10466, V10467, V10468, V10469, V10470,
+ V10471, V10472, V10473, V10474, V10475, V10476, V10477, V10478,
+ V10479, V10480, V10481, V10482, V10483, V10484, V10485, V10486,
+ V10487, V10488, V10489, V10490, V10491, V10492, V10493, V10494,
+ }, // P[411]
+ {
+ V10495, V10496, V10497, V10498, V10499, V10500, V10501, V10502,
+ V10503, V10504, V10505, V10506, V10507, V10508, V10509, V10510,
+ V10511, V10512, V10513, V10514, V10515, V10516, V10517, V10518,
+ V10519, V10520, V10521, V10522, V10523, V10524, V10525, V10526,
+ }, // P[412]
+ {
+ V10527, V10528, V10529, V10530, V10531, V10532, V10533, V10534,
+ V10535, V10536, V10537, V10538, V10539, V10540, V10541, V10542,
+ V10543, V10544, V10545, V10546, V10547, V10548, V10549, V10550,
+ V10551, V10552, V10553, V10554, V10555, V10556, V10557, V10558,
+ }, // P[413]
+ {
+ V10559, V10560, V10561, V10562, V10563, V10564, V10565, V10566,
+ V10567, V10568, V10569, V10570, V10571, V10572, V10573, V10574,
+ V10575, V10576, V10577, V10578, V10579, V10580, V10581, V10582,
+ V10583, V10584, V10585, V10586, V10587, V10588, V10589, V10590,
+ }, // P[414]
+ {
+ V10591, V10592, V10593, V10594, V10595, V10596, V10597, V10598,
+ V10599, V10600, V10601, V10602, V10603, V10604, V10605, V10606,
+ V10607, V10608, V10609, V10610, V10611, V10612, V10613, V10614,
+ V10615, V10616, V10617, V10618, V10619, V10620, V10621, V10622,
+ }, // P[415]
+ {
+ V10623, V10624, V10625, V10626, V10627, V10628, V10629, V10630,
+ V10631, V10632, V10633, V10634, V10635, V10636, V10637, V10638,
+ V10639, V10640, V10641, V10642, V10643, V10644, V10645, V10646,
+ V10647, V10648, V10649, V10650, V10651, V10652, V10653, V10654,
+ }, // P[416]
+ {
+ V10655, V10656, V10657, V10658, V10659, V10660, V10661, V10662,
+ V10663, V10664, V10665, V10666, V10667, V10668, V10669, V10670,
+ V10671, V10672, V10673, V10674, V10675, V10676, V10677, V10678,
+ V10679, V10680, V10681, V10682, V10683, V10684, V10685, V10686,
+ }, // P[417]
+ {
+ V10687, V10688, V10689, V10690, V10691, V10692, V10693, V10694,
+ V10695, V10696, V10697, V10698, V10699, V10700, V10701, V10702,
+ V10703, V10704, V10705, V10706, V10707, V10708, V10709, V10710,
+ V10711, V10712, V10713, V10714, V10715, V10716, V10717, V10718,
+ }, // P[418]
+ {
+ V10719, V10720, V10721, V10722, V10723, V10724, V10725, V10726,
+ V10727, V10728, V10729, V10730, V10731, V10732, V10733, V10734,
+ V10735, V10736, V10737, V10738, V10739, V10740, V10741, V10742,
+ V10743, V10744, V10745, V10746, V10747, V10748, V10749, V10750,
+ }, // P[419]
+ {
+ V10751, V10752, V10753, V10754, V10755, V10756, V10757, V10758,
+ V10759, V10760, V10761, V10762, V10763, V10764, V10765, V10766,
+ V10767, V10768, V10769, V10770, V10771, V10772, V10773, V10774,
+ V10775, V10776, V10777, V10778, V10779, V10780, V10781, V10782,
+ }, // P[420]
+ {
+ V10783, V10784, V10785, V10786, V10787, V10788, V10789, V10790,
+ V10791, V10792, V10793, V10794, V10795, V10796, V10797, V10798,
+ V10799, V10800, V10801, V10802, V10803, V10804, V10805, V10806,
+ V10807, V10808, V10809, V10810, V10811, V10812, V10813, V10814,
+ }, // P[421]
+ {
+ V10815, V10816, V10817, V10818, V10819, V10820, V10821, V10822,
+ V10823, V10824, V10825, V10826, V10827, V10828, V10829, V10830,
+ V10831, V10832, V10833, V10834, V10835, V10836, V10837, V10838,
+ V10839, V10840, V10841, V10842, V10843, V10844, V10845, V10846,
+ }, // P[422]
+ {
+ V10847, V10848, V10849, V10850, V10851, V10852, V10853, V10854,
+ V10855, V10856, V10857, V10858, V10859, V10860, V10861, V10862,
+ V10863, V10864, V10865, V10866, V10867, V10868, V10869, V10870,
+ V10871, V10872, V10873, V10874, V10875, V10876, V10877, V10878,
+ }, // P[423]
+ {
+ V10879, V10880, V10881, V10882, V10883, V10884, V10885, V10886,
+ V10887, V10888, V10889, V10890, V10891, V10892, V10893, V10894,
+ V10895, V10896, V10897, V10898, V10899, V10900, V10901, V10902,
+ V10903, V10904, V10905, V10906, V10907, V10908, V10909, V10910,
+ }, // P[424]
+ {
+ V10911, V10912, V10913, V10914, V10915, V10916, V10917, V10918,
+ V10919, V10920, V10921, V10922, V10923, V10924, V10925, V10926,
+ V10927, V10928, V10929, V10930, V1740, V10931, V10932, V10933,
+ V10934, V10935, V10936, V10937, V10938, V10939, V10940, V10941,
+ }, // P[425]
+ {
+ V10942, V10943, V10944, V10945, V10946, V10947, V10948, V10949,
+ V10950, V10951, V10952, V10953, V10954, V10955, V10956, V10957,
+ V10958, V10959, V10960, V10961, V10962, V10963, V10964, V10965,
+ V10966, V10967, V10968, V10969, V10970, V10971, V10972, V10973,
+ }, // P[426]
+ {
+ V10974, V10975, V10976, V10977, V10978, V10979, V10980, V10981,
+ V10982, V10983, V10984, V10985, V10986, V10987, V10988, V10989,
+ V10990, V10991, V10992, V10993, V10994, V10995, V10996, V10997,
+ V10998, V10999, V11000, V11001, V11002, V11003, V11004, V11005,
+ }, // P[427]
+ {
+ V11006, V11007, V11008, V11009, V11010, V11011, V11012, V11013,
+ V11014, V11015, V11016, V11017, V11018, V11019, V11020, V11021,
+ V11022, V11023, V11024, V11025, V11026, V11027, V11028, V11029,
+ V11030, V11031, V11032, V11033, V11034, V11035, V11036, V11037,
+ }, // P[428]
+ {
+ V11038, V11039, V11040, V11041, V11042, V11043, V11044, V11045,
+ V11046, V11047, V11048, V11049, V11050, V11051, V11052, V11053,
+ V11054, V11055, V11056, V11057, V11058, V11059, V11060, V11061,
+ V11062, V11063, V11064, V11065, V11066, V11067, V11068, V11069,
+ }, // P[429]
+ {
+ V11070, V11071, V11072, V11073, V11074, V11075, V11076, V11077,
+ V11078, V11079, V11080, V11081, V11082, V11083, V11084, V11085,
+ V11086, V11087, V11088, V11089, V11090, V11091, V11092, V11093,
+ V11094, V11095, V11096, V11097, V11098, V11099, V11100, V11101,
+ }, // P[430]
+ {
+ V11102, V11103, V11104, V11105, V11106, V11107, V11108, V11109,
+ V11110, V11111, V11112, V11113, V11114, V11115, V11116, V11117,
+ V11118, V11119, V11120, V11121, V11122, V11123, V11124, V11125,
+ V11126, V11127, V11128, V11129, V11130, V11131, V11132, V11133,
+ }, // P[431]
+ {
+ V11134, V11135, V11136, V11137, V11138, V11139, V11140, V11141,
+ V11142, V11143, V11144, V11145, V11146, V11147, V11148, V11149,
+ V11150, V11151, V11152, V11153, V11154, V11155, V11156, V11157,
+ V11158, V11159, V11160, V11161, V11162, V11163, V11164, V11165,
+ }, // P[432]
+ {
+ V11166, V11167, V11168, V11169, V11170, V11171, V11172, V11173,
+ V11174, V11175, V11176, V11177, V11178, V11179, V11180, V11181,
+ V11182, V11183, V11184, V11185, V11186, V11187, V11188, V11189,
+ V11190, V11191, V11192, V11193, V11194, V11195, V11196, V11197,
+ }, // P[433]
+ {
+ V11198, V11199, V11200, V11201, V11202, V11203, V11204, V11205,
+ V11206, V11207, V11208, V11209, V11210, V11211, V11212, V11213,
+ V11214, V11215, V11216, V11217, V11218, V11219, V11220, V11221,
+ V11222, V11223, V11224, V11225, V11226, V11227, V11228, V11229,
+ }, // P[434]
+ {
+ V11230, V11231, V11232, V11233, V11234, V11235, V11236, V11237,
+ V11238, V11239, V11240, V11241, V11242, V11243, V11244, V11245,
+ V11246, V11247, V11248, V11249, V11250, V11251, V11252, V11253,
+ V11254, V11255, V11256, V11257, V11258, V11259, V11260, V11261,
+ }, // P[435]
+ {
+ V11262, V11263, V11264, V11265, V11266, V11267, V11268, V11269,
+ V11270, V11271, V11272, V11273, V11274, V11275, V11276, V11277,
+ V11278, V11279, V11280, V11281, V11282, V11283, V11284, V11285,
+ V11286, V11287, V11288, V11289, V11290, V11291, V11292, V11293,
+ }, // P[436]
+ {
+ V11294, V11295, V11296, V11297, V11298, V11299, V11300, V11301,
+ V11302, V11303, V11304, V11305, V11306, V11307, V11308, V11309,
+ V11310, V11311, V11312, V11313, V11314, V11315, V11316, V11317,
+ V11318, V11319, V11320, V11321, V11322, V11323, V11324, V11325,
+ }, // P[437]
+ {
+ V11326, V11327, V11328, V11329, V11330, V11331, V11332, V11333,
+ V11334, V11335, V11336, V11337, V11338, V11339, V11340, V11341,
+ V11342, V11343, V11344, V11345, V11346, V11347, V11348, V11349,
+ V11350, V11351, V11352, V11353, V11354, V11355, V11356, V11357,
+ }, // P[438]
+ {
+ V11358, V11359, V11360, V11361, V11362, V11363, V11364, V11365,
+ V11366, V11367, V11368, V11369, V11370, V11371, V11372, V11373,
+ V11374, V11375, V11376, V11377, V11378, V11379, V11380, V11381,
+ V11382, V11383, V11384, V11385, V11386, V11387, V11388, V11389,
+ }, // P[439]
+ {
+ V11390, V11391, V11392, V11393, V11394, V11395, V11396, V11397,
+ V11398, V11399, V11400, V11401, V11402, V11403, V11404, V11405,
+ V11406, V11407, V11408, V11409, V11410, V11411, V11412, V11413,
+ V11414, V11415, V11416, V11417, V11418, V11419, V11420, V11421,
+ }, // P[440]
+ {
+ V11422, V11423, V11424, V11425, V11426, V11427, V11428, V11429,
+ V11430, V11431, V11432, V11433, V11434, V11435, V11436, V11437,
+ V11438, V11439, V11440, V11441, V11442, V11443, V11444, V11445,
+ V11446, V11447, V11448, V11449, V11450, V11451, V11452, V11453,
+ }, // P[441]
+ {
+ V11454, V11455, V11456, V11457, V11458, V11459, V11460, V11461,
+ V11462, V11463, V11464, V11465, V11466, V11467, V11468, V11469,
+ V11470, V11471, V11472, V11473, V11474, V11475, V11476, V11477,
+ V11478, V11479, V11480, V11481, V11482, V11483, V11484, V11485,
+ }, // P[442]
+ {
+ V11486, V11487, V11488, V11489, V11490, V11491, V11492, V11493,
+ V11494, V11495, V11496, V11497, V11498, V11499, V11500, V11501,
+ V11502, V11503, V11504, V11505, V11506, V11507, V11508, V11509,
+ V11510, V11511, V11512, V11513, V11514, V11515, V11516, V11517,
+ }, // P[443]
+ {
+ V1741, V11518, V11519, V11520, V11521, V11522, V11523, V11524,
+ V11525, V11526, V11527, V11528, V11529, V11530, V11531, V11532,
+ V11533, V11534, V11535, V11536, V11537, V11538, V11539, V11540,
+ V11541, V11542, V11543, V11544, V11545, V11546, V11547, V11548,
+ }, // P[444]
+ {
+ V11549, V11550, V11551, V11552, V11553, V11554, V11555, V11556,
+ V11557, V11558, V11559, V11560, V11561, V11562, V11563, V11564,
+ V11565, V11566, V11567, V11568, V11569, V11570, V11571, V11572,
+ V11573, V11574, V11575, V11576, V11577, V11578, V11579, V11580,
+ }, // P[445]
+ {
+ V11581, V11582, V11583, V11584, V11585, V11586, V11587, V11588,
+ V11589, V11590, V11591, V11592, V11593, V11594, V11595, V11596,
+ V11597, V11598, V11599, V11600, V11601, V11602, V11603, V11604,
+ V11605, V11606, V11607, V11608, V11609, V11610, V11611, V11612,
+ }, // P[446]
+ {
+ V11613, V11614, V11615, V11616, V11617, V11618, V11619, V11620,
+ V11621, V11622, V11623, V11624, V11625, V11626, V11627, V11628,
+ V11629, V11630, V11631, V11632, V11633, V11634, V11635, V11636,
+ V11637, V11638, V11639, V11640, V11641, V11642, V11643, V11644,
+ }, // P[447]
+ {
+ V11645, V11646, V11647, V11648, V11649, V11650, V11651, V11652,
+ V11653, V11654, V11655, V11656, V11657, V11658, V11659, V11660,
+ V11661, V11662, V11663, V11664, V11665, V11666, V11667, V11668,
+ V11669, V11670, V11671, V11672, V11673, V11674, V11675, V11676,
+ }, // P[448]
+ {
+ V11677, V11678, V11679, V11680, V11681, V11682, V11683, V11684,
+ V11685, V11686, V11687, V11688, V11689, V11690, V11691, V11692,
+ V11693, V11694, V11695, V11696, V11697, V11698, V11699, V11700,
+ V11701, V11702, V11703, V11704, V11705, V11706, V11707, V11708,
+ }, // P[449]
+ {
+ V11709, V11710, V11711, V11712, V11713, V11714, V11715, V11716,
+ V11717, V11718, V11719, V11720, V11721, V11722, V11723, V11724,
+ V11725, V11726, V11727, V11728, V11729, V11730, V11731, V11732,
+ V11733, V11734, V11735, V11736, V11737, V11738, V11739, V11740,
+ }, // P[450]
+ {
+ V11741, V11742, V11743, V11744, V11745, V11746, V11747, V11748,
+ V11749, V11750, V11751, V11752, V11753, V11754, V11755, V11756,
+ V11757, V11758, V11759, V11760, V11761, V11762, V11763, V11764,
+ V11765, V11766, V11767, V11768, V11769, V11770, V11771, V11772,
+ }, // P[451]
+ {
+ V11773, V11774, V11775, V11776, V11777, V11778, V11779, V11780,
+ V11781, V11782, V11783, V11784, V11785, V11786, V11787, V11788,
+ V11789, V11790, V11791, V11792, V11793, V11794, V11795, V11796,
+ V11797, V11798, V11799, V11800, V11801, V11802, V11803, V11804,
+ }, // P[452]
+ {
+ V11805, V11806, V11807, V11808, V11809, V11810, V11811, V11812,
+ V11813, V11814, V11815, V11816, V11817, V11818, V11819, V11820,
+ V11821, V11822, V11823, V11824, V11825, V11826, V11827, V11828,
+ V11829, V11830, V11831, V11832, V11833, V11834, V11835, V11836,
+ }, // P[453]
+ {
+ V11837, V11838, V11839, V11840, V11841, V11842, V11843, V11844,
+ V11845, V11846, V11847, V11848, V11849, V11850, V11851, V11852,
+ V11853, V11854, V11855, V11856, V11857, V11858, V11859, V11860,
+ V11861, V11862, V11863, V11864, V11865, V11866, V11867, V11868,
+ }, // P[454]
+ {
+ V11869, V11870, V11871, V11872, V11873, V11874, V11875, V11876,
+ V11877, V11878, V11879, V11880, V11881, V11882, V11883, V11884,
+ V11885, V11886, V11887, V11888, V11889, V11890, V11891, V11892,
+ V11893, V11894, V11895, V11896, V11897, V11898, V11899, V11900,
+ }, // P[455]
+ {
+ V11901, V11902, V11903, V11904, V11905, V11906, V11907, V11908,
+ V11909, V11910, V11911, V11912, V11913, V11914, V11915, V11916,
+ V11917, V11918, V11919, V11920, V11921, V11922, V11923, V11924,
+ V11925, V11926, V11927, V11928, V11929, V11930, V11931, V11932,
+ }, // P[456]
+ {
+ V11933, V11934, V11935, V11936, V11937, V11938, V11939, V11940,
+ V11941, V11942, V11943, V11944, V11945, V11946, V11947, V11948,
+ V11949, V11950, V11951, V11952, V11953, V11954, V11955, V11956,
+ V11957, V11958, V11959, V11960, V11961, V11962, V11963, V11964,
+ }, // P[457]
+ {
+ V11965, V11966, V11967, V11968, V11969, V11970, V11971, V11972,
+ V11973, V11974, V11975, V11976, V11977, V11978, V11979, V11980,
+ V11981, V11982, V11983, V11984, V11985, V11986, V11987, V11988,
+ V11989, V11990, V11991, V11992, V11993, V11994, V11995, V11996,
+ }, // P[458]
+ {
+ V11997, V11998, V11999, V12000, V12001, V12002, V12003, V12004,
+ V12005, V12006, V12007, V12008, V12009, V12010, V12011, V12012,
+ V12013, V12014, V12015, V12016, V12017, V12018, V12019, V12020,
+ V12021, V12022, V12023, V12024, V12025, V12026, V12027, V12028,
+ }, // P[459]
+ {
+ V12029, V12030, V12031, V12032, V12033, V12034, V12035, V12036,
+ V12037, V12038, V12039, V12040, V12041, V12042, V12043, V12044,
+ V12045, V12046, V12047, V12048, V12049, V12050, V12051, V12052,
+ V12053, V12054, V12055, V12056, V12057, V12058, V12059, V12060,
+ }, // P[460]
+ {
+ V12061, V12062, V12063, V12064, V12065, V12066, V12067, V12068,
+ V12069, V12070, V12071, V12072, V12073, V12074, V12075, V12076,
+ V12077, V12078, V12079, V12080, V12081, V12082, V12083, V12084,
+ V12085, V12086, V12087, V12088, V12089, V12090, V12091, V12092,
+ }, // P[461]
+ {
+ V12093, V12094, V12095, V12096, V12097, V12098, V12099, V12100,
+ V12101, V12102, V12103, V12104, V1742, V12105, V12106, V12107,
+ V12108, V12109, V12110, V12111, V12112, V12113, V12114, V12115,
+ V12116, V12117, V12118, V12119, V12120, V12121, V12122, V12123,
+ }, // P[462]
+ {
+ V12124, V12125, V12126, V12127, V12128, V12129, V12130, V12131,
+ V12132, V12133, V12134, V12135, V12136, V12137, V12138, V12139,
+ V12140, V12141, V12142, V12143, V12144, V12145, V12146, V12147,
+ V12148, V12149, V12150, V12151, V12152, V12153, V12154, V12155,
+ }, // P[463]
+ {
+ V12156, V12157, V12158, V12159, V12160, V12161, V12162, V12163,
+ V12164, V12165, V12166, V12167, V12168, V12169, V12170, V12171,
+ V12172, V12173, V12174, V12175, V12176, V12177, V12178, V12179,
+ V12180, V12181, V12182, V12183, V12184, V12185, V12186, V12187,
+ }, // P[464]
+ {
+ V12188, V12189, V12190, V12191, V12192, V12193, V12194, V12195,
+ V12196, V12197, V12198, V12199, V12200, V12201, V12202, V12203,
+ V12204, V12205, V12206, V12207, V12208, V12209, V12210, V12211,
+ V12212, V12213, V12214, V12215, V12216, V12217, V12218, V12219,
+ }, // P[465]
+ {
+ V12220, V12221, V12222, V12223, V12224, V12225, V12226, V12227,
+ V12228, V12229, V12230, V12231, V12232, V12233, V12234, V12235,
+ V12236, V12237, V12238, V12239, V12240, V12241, V12242, V12243,
+ V12244, V12245, V12246, V12247, V12248, V12249, V12250, V12251,
+ }, // P[466]
+ {
+ V12252, V12253, V12254, V12255, V12256, V12257, V12258, V12259,
+ V12260, V12261, V12262, V12263, V12264, V12265, V12266, V12267,
+ V12268, V12269, V12270, V12271, V12272, V12273, V12274, V12275,
+ V12276, V12277, V12278, V12279, V12280, V12281, V12282, V12283,
+ }, // P[467]
+ {
+ V12284, V12285, V12286, V12287, V12288, V12289, V12290, V12291,
+ V12292, V12293, V12294, V12295, V12296, V12297, V12298, V12299,
+ V12300, V12301, V12302, V12303, V12304, V12305, V12306, V12307,
+ V12308, V12309, V12310, V12311, V12312, V12313, V12314, V12315,
+ }, // P[468]
+ {
+ V12316, V12317, V12318, V12319, V12320, V12321, V12322, V12323,
+ V12324, V12325, V12326, V12327, V12328, V12329, V12330, V12331,
+ V12332, V12333, V12334, V12335, V12336, V12337, V12338, V12339,
+ V12340, V12341, V12342, V12343, V12344, V12345, V12346, V12347,
+ }, // P[469]
+ {
+ V12348, V12349, V12350, V12351, V12352, V12353, V12354, V12355,
+ V12356, V12357, V12358, V12359, V12360, V12361, V12362, V12363,
+ V12364, V12365, V12366, V12367, V12368, V12369, V12370, V12371,
+ V12372, V12373, V12374, V12375, V12376, V12377, V12378, V12379,
+ }, // P[470]
+ {
+ V12380, V12381, V12382, V12383, V12384, V12385, V12386, V12387,
+ V12388, V12389, V12390, V12391, V12392, V12393, V12394, V12395,
+ V12396, V12397, V12398, V12399, V12400, V12401, V12402, V12403,
+ V12404, V12405, V12406, V12407, V12408, V12409, V12410, V12411,
+ }, // P[471]
+ {
+ V12412, V12413, V12414, V12415, V12416, V12417, V12418, V12419,
+ V12420, V12421, V12422, V12423, V12424, V12425, V12426, V12427,
+ V12428, V12429, V12430, V12431, V12432, V12433, V12434, V12435,
+ V12436, V12437, V12438, V12439, V12440, V12441, V12442, V12443,
+ }, // P[472]
+ {
+ V12444, V12445, V12446, V12447, V12448, V12449, V12450, V12451,
+ V12452, V12453, V12454, V12455, V12456, V12457, V12458, V12459,
+ V12460, V12461, V12462, V12463, V12464, V12465, V12466, V12467,
+ V12468, V12469, V12470, V12471, V12472, V12473, V12474, V12475,
+ }, // P[473]
+ {
+ V12476, V12477, V12478, V12479, V12480, V12481, V12482, V12483,
+ V12484, V12485, V12486, V12487, V12488, V12489, V12490, V12491,
+ V12492, V12493, V12494, V12495, V12496, V12497, V12498, V12499,
+ V12500, V12501, V12502, V12503, V12504, V12505, V12506, V12507,
+ }, // P[474]
+ {
+ V12508, V12509, V12510, V12511, V12512, V12513, V12514, V12515,
+ V12516, V12517, V12518, V12519, V12520, V12521, V12522, V12523,
+ V12524, V12525, V12526, V12527, V12528, V12529, V12530, V12531,
+ V12532, V12533, V12534, V12535, V12536, V12537, V12538, V12539,
+ }, // P[475]
+ {
+ V12540, V12541, V12542, V12543, V12544, V12545, V12546, V12547,
+ V12548, V12549, V12550, V12551, V12552, V12553, V12554, V12555,
+ V12556, V12557, V12558, V12559, V12560, V12561, V12562, V12563,
+ V12564, V12565, V12566, V12567, V12568, V12569, V12570, V12571,
+ }, // P[476]
+ {
+ V12572, V12573, V12574, V12575, V12576, V12577, V12578, V12579,
+ V12580, V12581, V12582, V12583, V12584, V12585, V12586, V12587,
+ V12588, V12589, V12590, V12591, V12592, V12593, V12594, V12595,
+ V12596, V12597, V12598, V12599, V12600, V12601, V12602, V12603,
+ }, // P[477]
+ {
+ V12604, V12605, V12606, V12607, V12608, V12609, V12610, V12611,
+ V12612, V12613, V12614, V12615, V12616, V12617, V12618, V12619,
+ V12620, V12621, V12622, V12623, V12624, V12625, V12626, V12627,
+ V12628, V12629, V12630, V12631, V12632, V12633, V12634, V12635,
+ }, // P[478]
+ {
+ V12636, V12637, V12638, V12639, V12640, V12641, V12642, V12643,
+ V12644, V12645, V12646, V12647, V12648, V12649, V12650, V12651,
+ V12652, V12653, V12654, V12655, V12656, V12657, V12658, V12659,
+ V12660, V12661, V12662, V12663, V12664, V12665, V12666, V12667,
+ }, // P[479]
+ {
+ V12668, V12669, V12670, V12671, V12672, V12673, V12674, V12675,
+ V12676, V12677, V12678, V12679, V12680, V12681, V12682, V12683,
+ V12684, V12685, V12686, V12687, V12688, V12689, V12690, V12691,
+ V1743, V12692, V12693, V12694, V12695, V12696, V12697, V12698,
+ }, // P[480]
+ {
+ V12699, V12700, V12701, V12702, V12703, V12704, V12705, V12706,
+ V12707, V12708, V12709, V12710, V12711, V12712, V12713, V12714,
+ V12715, V12716, V12717, V12718, V12719, V12720, V12721, V12722,
+ V12723, V12724, V12725, V12726, V12727, V12728, V12729, V12730,
+ }, // P[481]
+ {
+ V12731, V12732, V12733, V12734, V12735, V12736, V12737, V12738,
+ V12739, V12740, V12741, V12742, V12743, V12744, V12745, V12746,
+ V12747, V12748, V12749, V12750, V12751, V12752, V12753, V12754,
+ V12755, V12756, V12757, V12758, V12759, V12760, V12761, V12762,
+ }, // P[482]
+ {
+ V12763, V12764, V12765, V12766, V12767, V12768, V12769, V12770,
+ V12771, V12772, V12773, V12774, V12775, V12776, V12777, V12778,
+ V12779, V12780, V12781, V12782, V12783, V12784, V12785, V12786,
+ V12787, V12788, V12789, V12790, V12791, V12792, V12793, V12794,
+ }, // P[483]
+ {
+ V12795, V12796, V12797, V12798, V12799, V12800, V12801, V12802,
+ V12803, V12804, V12805, V12806, V12807, V12808, V12809, V12810,
+ V12811, V12812, V12813, V12814, V12815, V12816, V12817, V12818,
+ V12819, V12820, V12821, V12822, V12823, V12824, V12825, V12826,
+ }, // P[484]
+ {
+ V12827, V12828, V12829, V12830, V12831, V12832, V12833, V12834,
+ V12835, V12836, V12837, V12838, V12839, V12840, V12841, V12842,
+ V12843, V12844, V12845, V12846, V12847, V12848, V12849, V12850,
+ V12851, V12852, V12853, V12854, V12855, V12856, V12857, V12858,
+ }, // P[485]
+ {
+ V12859, V12860, V12861, V12862, V12863, V12864, V12865, V12866,
+ V12867, V12868, V12869, V12870, V12871, V12872, V12873, V12874,
+ V12875, V12876, V12877, V12878, V12879, V12880, V12881, V12882,
+ V12883, V12884, V12885, V12886, V12887, V12888, V12889, V12890,
+ }, // P[486]
+ {
+ V12891, V12892, V12893, V12894, V12895, V12896, V12897, V12898,
+ V12899, V12900, V12901, V12902, V12903, V12904, V12905, V12906,
+ V12907, V12908, V12909, V12910, V12911, V12912, V12913, V12914,
+ V12915, V12916, V12917, V12918, V12919, V12920, V12921, V12922,
+ }, // P[487]
+ {
+ V12923, V12924, V12925, V12926, V12927, V12928, V12929, V12930,
+ V12931, V12932, V12933, V12934, V12935, V12936, V12937, V12938,
+ V12939, V12940, V12941, V12942, V12943, V12944, V12945, V12946,
+ V12947, V12948, V12949, V12950, V12951, V12952, V12953, V12954,
+ }, // P[488]
+ {
+ V12955, V12956, V12957, V12958, V12959, V12960, V12961, V12962,
+ V12963, V12964, V12965, V12966, V12967, V12968, V12969, V12970,
+ V12971, V12972, V12973, V12974, V12975, V12976, V12977, V12978,
+ V12979, V12980, V12981, V12982, V12983, V12984, V12985, V12986,
+ }, // P[489]
+ {
+ V12987, V12988, V12989, V12990, V12991, V12992, V12993, V12994,
+ V12995, V12996, V12997, V12998, V12999, V13000, V13001, V13002,
+ V13003, V13004, V13005, V13006, V13007, V13008, V13009, V13010,
+ V13011, V13012, V13013, V13014, V13015, V13016, V13017, V13018,
+ }, // P[490]
+ {
+ V13019, V13020, V13021, V13022, V13023, V13024, V13025, V13026,
+ V13027, V13028, V13029, V13030, V13031, V13032, V13033, V13034,
+ V13035, V13036, V13037, V13038, V13039, V13040, V13041, V13042,
+ V13043, V13044, V13045, V13046, V13047, V13048, V13049, V13050,
+ }, // P[491]
+ {
+ V13051, V13052, V13053, V13054, V13055, V13056, V13057, V13058,
+ V13059, V13060, V13061, V13062, V13063, V13064, V13065, V13066,
+ V13067, V13068, V13069, V13070, V13071, V13072, V13073, V13074,
+ V13075, V13076, V13077, V13078, V13079, V13080, V13081, V13082,
+ }, // P[492]
+ {
+ V13083, V13084, V13085, V13086, V13087, V13088, V13089, V13090,
+ V13091, V13092, V13093, V13094, V13095, V13096, V13097, V13098,
+ V13099, V13100, V13101, V13102, V13103, V13104, V13105, V13106,
+ V13107, V13108, V13109, V13110, V13111, V13112, V13113, V13114,
+ }, // P[493]
+ {
+ V13115, V13116, V13117, V13118, V13119, V13120, V13121, V13122,
+ V13123, V13124, V13125, V13126, V13127, V13128, V13129, V13130,
+ V13131, V13132, V13133, V13134, V13135, V13136, V13137, V13138,
+ V13139, V13140, V13141, V13142, V13143, V13144, V13145, V13146,
+ }, // P[494]
+ {
+ V13147, V13148, V13149, V13150, V13151, V13152, V13153, V13154,
+ V13155, V13156, V13157, V13158, V13159, V13160, V13161, V13162,
+ V13163, V13164, V13165, V13166, V13167, V13168, V13169, V13170,
+ V13171, V13172, V13173, V13174, V13175, V13176, V13177, V13178,
+ }, // P[495]
+ {
+ V13179, V13180, V13181, V13182, V13183, V13184, V13185, V13186,
+ V13187, V13188, V13189, V13190, V13191, V13192, V13193, V13194,
+ V13195, V13196, V13197, V13198, V13199, V13200, V13201, V13202,
+ V13203, V13204, V13205, V13206, V13207, V13208, V13209, V13210,
+ }, // P[496]
+ {
+ V13211, V13212, V13213, V13214, V13215, V13216, V13217, V13218,
+ V13219, V13220, V13221, V13222, V13223, V13224, V13225, V13226,
+ V13227, V13228, V13229, V13230, V13231, V13232, V13233, V13234,
+ V13235, V13236, V13237, V13238, V13239, V13240, V13241, V13242,
+ }, // P[497]
+ {
+ V13243, V13244, V13245, V13246, V13247, V13248, V13249, V13250,
+ V13251, V13252, V13253, V13254, V13255, V13256, V13257, V13258,
+ V13259, V13260, V13261, V13262, V13263, V13264, V13265, V13266,
+ V13267, V13268, V13269, V13270, V13271, V13272, V13273, V13274,
+ }, // P[498]
+ {
+ V13275, V13276, V13277, V13278, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[499]
+ {
+ V13279, V13280, V1419, V13281, V13282, V13283, V13284, V1473,
+ V1473, V13285, V1427, V13286, V13287, V13288, V13289, V13290,
+ V13291, V13292, V13293, V13294, V13295, V13296, V13297, V13298,
+ V13299, V13300, V13301, V13302, V13303, V13304, V13305, V13306,
+ }, // P[500]
+ {
+ V13307, V13308, V13309, V13310, V13311, V13312, V13313, V13314,
+ V13315, V13316, V13317, V13318, V13319, V13320, V13321, V13322,
+ V13323, V13324, V13325, V13326, V1385, V13327, V13328, V13329,
+ V13330, V13331, V13332, V13333, V13334, V13335, V13336, V13337,
+ }, // P[501]
+ {
+ V1458, V13338, V13339, V13340, V13341, V13342, V13343, V13344,
+ V13345, V13346, V13347, V13348, V13349, V13350, V13351, V13352,
+ V13353, V13354, V13355, V13356, V13357, V13358, V13359, V13360,
+ V13361, V13362, V13363, V13364, V13295, V13365, V13366, V13367,
+ }, // P[502]
+ {
+ V13368, V13369, V13370, V13371, V13372, V13373, V13374, V13375,
+ V13376, V13377, V13378, V13379, V13380, V13381, V13382, V13383,
+ V13384, V1421, V13385, V13386, V13387, V13388, V13389, V13390,
+ V13391, V13392, V13393, V13394, V13395, V13396, V13397, V13398,
+ }, // P[503]
+ {
+ V13399, V1298, V13400, V13401, V13402, V13403, V13404, V13405,
+ V13406, V13407, V1279, V13408, V13409, V13410, V13411, V13412,
+ V13413, V13414, V13415, V13416, V13417, V13418, V13419, V13420,
+ V13421, V13422, V13423, V13424, V13425, V13426, V13427, V13428,
+ }, // P[504]
+ {
+ V13429, V13383, V13430, V13431, V13432, V13433, V13434, V13435,
+ V13436, V13437, V13367, V13438, V13439, V13440, V13441, V13442,
+ V13443, V13444, V13445, V13446, V13447, V13448, V13449, V13450,
+ V13451, V13452, V13453, V13454, V13455, V13456, V13457, V13295,
+ }, // P[505]
+ {
+ V13458, V13459, V13460, V13461, V1472, V13462, V13463, V13464,
+ V13465, V13466, V13467, V13468, V13469, V13470, V13471, V13472,
+ V13473, V1748, V13474, V13475, V13476, V13477, V13478, V13479,
+ V13480, V13481, V13482, V13369, V13483, V13484, V13485, V13486,
+ }, // P[506]
+ {
+ V13487, V13488, V13489, V13490, V13491, V13492, V13493, V13494,
+ V13495, V1426, V13496, V13497, V13498, V13499, V13500, V13501,
+ V13502, V13503, V13504, V13505, V13506, V13507, V13508, V1377,
+ V13509, V13510, V13511, V13512, V13513, V13514, V13515, V13516,
+ }, // P[507]
+ {
+ V13517, V13518, V13519, V13520, V13521, V13522, V13523, V13524,
+ V1404, V13525, V1407, V13526, V13527, V13528, 0, 0,
+ V13529, 0, V13530, 0, 0, V13531, V13532, V13533,
+ V13534, V13535, V13536, V13537, V13538, V13539, V1384, 0,
+ }, // P[508]
+ {
+ V13540, 0, V13541, 0, 0, V13542, V13543, 0,
+ 0, 0, V13544, V13545, V13546, V13547, V13548, V13549,
+ V13550, V13551, V13552, V13553, V13554, V13555, V13556, V13557,
+ V13558, V13559, V13560, V13561, V1305, V13562, V13563, V13564,
+ }, // P[509]
+ {
+ V13565, V13566, V13567, V13568, V13569, V13570, V13571, V13572,
+ V13573, V13574, V13575, V13576, V1753, V13577, V13578, V13579,
+ V13580, V1757, V13581, V13582, V13583, V13584, V13585, V13419,
+ V13586, V13587, V13588, V13589, V13590, V13591, V13591, V13592,
+ }, // P[510]
+ {
+ V13593, V13594, V13595, V13596, V13597, V13598, V13599, V13542,
+ V13600, V13601, V13602, V13603, V13604, V13605, 0, 0,
+ V13606, V13607, V13608, V13609, V13610, V13611, V13612, V13613,
+ V13556, V13614, V13615, V13616, V13529, V13617, V13618, V13619,
+ }, // P[511]
+ {
+ V13620, V13621, V13622, V13623, V13624, V13625, V13626, V13627,
+ V13628, V13564, V13629, V13565, V13630, V13631, V13632, V13633,
+ V13634, V13530, V13316, V13635, V13636, V1338, V13384, V13467,
+ V13637, V13638, V13572, V13639, V13573, V13640, V13641, V13642,
+ }, // P[512]
+ {
+ V13532, V13643, V13644, V13645, V13646, V13647, V13533, V13648,
+ V13649, V13650, V13651, V13652, V13653, V13585, V13654, V13655,
+ V13419, V13656, V13589, V13657, V13658, V13659, V13660, V13661,
+ V13594, V13662, V13541, V13663, V13595, V13365, V13664, V13596,
+ }, // P[513]
+ {
+ V13665, V13598, V13666, V13667, V13668, V13669, V13670, V13600,
+ V13538, V13671, V13601, V13672, V13602, V13673, V1473, V13674,
+ V13675, V13676, V13677, V13678, V13679, V13680, V13681, V13682,
+ V13683, V13684, 0, 0, 0, 0, 0, 0,
+ }, // P[514]
+ {
+ V13685, V13686, V13687, V13688, V13689, V13690, V13690, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V13691, V13692, V13693, V13694, V13695,
+ 0, 0, 0, 0, 0, V13696, 0, V13697,
+ }, // P[515]
+ {
+ V13698, V1078, V1081, V13699, V13700, V13701, V13702, V13703,
+ V13704, V1054, V13705, V13706, V13707, V13708, V13709, V13710,
+ V13711, V13712, V13713, V13714, V13715, V13716, V13717, 0,
+ V13718, V13719, V13720, V13721, V13722, 0, V13723, 0,
+ }, // P[516]
+ {
+ V13724, V13725, 0, V13726, V13727, 0, V13728, V13729,
+ V13730, V13731, V13732, V13733, V13734, V13735, V13736, V13737,
+ V13738, V13738, V13739, V13739, V13739, V13739, V13740, V13740,
+ V13740, V13740, V13741, V13741, V13741, V13741, V13742, V13742,
+ }, // P[517]
+ {
+ V13742, V13742, V13743, V13743, V13743, V13743, V13744, V13744,
+ V13744, V13744, V13745, V13745, V13745, V13745, V13746, V13746,
+ V13746, V13746, V13747, V13747, V13747, V13747, V13748, V13748,
+ V13748, V13748, V13749, V13749, V13749, V13749, V13750, V13750,
+ }, // P[518]
+ {
+ V13750, V13750, V13751, V13751, V13752, V13752, V13753, V13753,
+ V13754, V13754, V13755, V13755, V13756, V13756, V13757, V13757,
+ V13757, V13757, V13758, V13758, V13758, V13758, V13759, V13759,
+ V13759, V13759, V13760, V13760, V13760, V13760, V13761, V13761,
+ }, // P[519]
+ {
+ V13762, V13762, V13762, V13762, V405, V405, V13763, V13763,
+ V13763, V13763, V13764, V13764, V13764, V13764, V13765, V13765,
+ V407, V407, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[520]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V13766, V13766, V13766, V13766, V13767,
+ V13767, V13768, V13768, V13769, V13769, V403, V13770, V13770,
+ }, // P[521]
+ {
+ V13771, V13771, V13772, V13772, V13773, V13773, V13773, V13773,
+ V13774, V13774, V13775, V13775, V13776, V13776, V13777, V13777,
+ V13778, V13778, V13779, V13779, V13780, V13780, V13781, V13781,
+ V13781, V13782, V13782, V13782, V13783, V13783, V13783, V13783,
+ }, // P[522]
+ {
+ V13784, V13785, V13786, V13782, V13787, V13788, V13789, V13790,
+ V13791, V13792, V13793, V13794, V13795, V13796, V13797, V13798,
+ V13799, V13800, V13801, V13802, V13803, V13804, V13805, V13806,
+ V13807, V13808, V13809, V13810, V13811, V13812, V13813, V13814,
+ }, // P[523]
+ {
+ V13815, V13816, V13817, V13818, V13819, V13820, V13821, V13822,
+ V13823, V13824, V13825, V13826, V13827, V13828, V13829, V13830,
+ V13831, V13832, V13833, V13834, V13835, V13836, V13837, V13838,
+ V13839, V13840, V13841, V13842, V13843, V13844, V13845, V13846,
+ }, // P[524]
+ {
+ V13847, V13848, V13849, V13850, V13851, V13852, V13853, V13854,
+ V13855, V13856, V13857, V13858, V13859, V13860, V13861, V13862,
+ V13863, V13864, V13865, V13866, V13867, V13868, V13869, V13870,
+ V13871, V13872, V13873, V13874, V13875, V13876, V13877, V13878,
+ }, // P[525]
+ {
+ V13879, V13880, V13881, V13882, V13883, V13884, V13786, V13885,
+ V13782, V13787, V13886, V13887, V13791, V13888, V13792, V13793,
+ V13889, V13890, V13797, V13891, V13798, V13799, V13892, V13893,
+ V13801, V13894, V13802, V13803, V13832, V13833, V13836, V13837,
+ }, // P[526]
+ {
+ V13838, V13842, V13843, V13844, V13845, V13849, V13850, V13851,
+ V13895, V13855, V13896, V13897, V13861, V13898, V13862, V13863,
+ V13876, V13899, V13900, V13871, V13901, V13872, V13873, V13784,
+ V13785, V13902, V13786, V13903, V13788, V13789, V13790, V13791,
+ }, // P[527]
+ {
+ V13904, V13794, V13795, V13796, V13797, V13905, V13801, V13804,
+ V13805, V13806, V13807, V13808, V13810, V13811, V13812, V13813,
+ V13814, V13815, V13906, V13816, V13817, V13818, V13819, V13820,
+ V13821, V13823, V13824, V13825, V13826, V13827, V13828, V13829,
+ }, // P[528]
+ {
+ V13830, V13831, V13834, V13835, V13839, V13840, V13841, V13842,
+ V13843, V13846, V13847, V13848, V13849, V13907, V13852, V13853,
+ V13854, V13855, V13858, V13859, V13860, V13861, V13908, V13864,
+ V13865, V13909, V13868, V13869, V13870, V13871, V13910, V13786,
+ }, // P[529]
+ {
+ V13903, V13791, V13904, V13797, V13905, V13801, V13911, V13814,
+ V13912, V13913, V13914, V13842, V13843, V13849, V13861, V13908,
+ V13871, V13910, V13915, V13916, V13917, V13918, V13919, V13920,
+ V13921, V13922, V13923, V13924, V13925, V13926, V13927, V13928,
+ }, // P[530]
+ {
+ V13929, V13930, V13931, V13932, V13933, V13934, V13935, V13936,
+ V13937, V13938, V13939, V13940, V13913, V13941, V13942, V13943,
+ V13944, V13918, V13919, V13920, V13921, V13922, V13923, V13924,
+ V13925, V13926, V13927, V13928, V13929, V13930, V13931, V13932,
+ }, // P[531]
+ {
+ V13933, V13934, V13935, V13936, V13937, V13938, V13939, V13940,
+ V13913, V13941, V13942, V13943, V13944, V13938, V13939, V13940,
+ V13913, V13912, V13914, V13822, V13811, V13812, V13813, V13938,
+ V13939, V13940, V13822, V13823, V13945, V13945, 0, 0,
+ }, // P[532]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V13946, V13947, V13947, V13948, V13949, V13950, V13951, V13952,
+ V13953, V13953, V13954, V13955, V13956, V13957, V13958, V13959,
+ }, // P[533]
+ {
+ V13959, V13960, V13961, V13961, V13962, V13962, V13963, V13964,
+ V13964, V13965, V13966, V13966, V13967, V13967, V13968, V13969,
+ V13969, V13970, V13970, V13971, V13972, V13973, V13974, V13974,
+ V13975, V13976, V13977, V13978, V13979, V13979, V13980, V13981,
+ }, // P[534]
+ {
+ V13982, V13983, V13984, V13985, V13985, V13986, V13986, V13987,
+ V13987, V13988, V13989, V13990, V13991, V13992, V13993, V13994,
+ 0, 0, V13995, V13996, V13997, V13998, V13999, V14000,
+ V14000, V14001, V14002, V14003, V14004, V14004, V14005, V14006,
+ }, // P[535]
+ {
+ V14007, V14008, V14009, V14010, V14011, V14012, V14013, V14014,
+ V14015, V14016, V14017, V14018, V14019, V14020, V14021, V14022,
+ V14023, V14024, V14025, V14026, V13980, V13982, V14027, V14028,
+ V14029, V14030, V14031, V14032, V14031, V14029, V14033, V14034,
+ }, // P[536]
+ {
+ V14035, V14036, V14037, V14032, V13973, V13963, V14038, V14039,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[537]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V14040, V14041, V14042, V14043, V14044, V14045, V14046, V14047,
+ V14048, V14049, V14050, V14051, V14052, 0, 0, 0,
+ }, // P[538]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V14053, V14054, V14055, V14056, V309, V14057, V14058, V14059,
+ V14060, V1036, 0, 0, 0, 0, 0, 0,
+ }, // P[539]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V1035, V14061, V14062, V14063, V14063, V1057, V1058, V14064,
+ V14065, V14066, V14067, V14068, V14069, V14070, V14071, V1171,
+ }, // P[540]
+ {
+ V1172, V14072, V14073, V14074, V14075, 0, 0, V14076,
+ V14077, V1042, V1042, V1042, V1042, V14063, V14063, V14063,
+ V14053, V14054, V1034, 0, V309, V14056, V14058, V14057,
+ V14061, V1057, V1058, V14064, V14065, V14066, V14067, V14078,
+ }, // P[541]
+ {
+ V14079, V14080, V1054, V14081, V14082, V14083, V1056, 0,
+ V14084, V14085, V14086, V14087, 0, 0, 0, 0,
+ V14088, V14089, V14090, 0, V14091, 0, V14092, V14093,
+ V14094, V14095, V14096, V14097, V14098, V14099, V14100, V14101,
+ }, // P[542]
+ {
+ V14102, V396, V396, V397, V397, V398, V398, V399,
+ V399, V400, V400, V400, V400, V14103, V14103, V14104,
+ V14104, V14104, V14104, V14105, V14105, V14106, V14106, V14106,
+ V14106, V14107, V14107, V14107, V14107, V14108, V14108, V14108,
+ }, // P[543]
+ {
+ V14108, V14109, V14109, V14109, V14109, V14110, V14110, V14110,
+ V14110, V14111, V14111, V14112, V14112, V14113, V14113, V14114,
+ V14114, V14115, V14115, V14115, V14115, V14116, V14116, V14116,
+ V14116, V14117, V14117, V14117, V14117, V14118, V14118, V14118,
+ }, // P[544]
+ {
+ V14118, V14119, V14119, V14119, V14119, V14120, V14120, V14120,
+ V14120, V14121, V14121, V14121, V14121, V14122, V14122, V14122,
+ V14122, V14123, V14123, V14123, V14123, V14124, V14124, V14124,
+ V14124, V14125, V14125, V14125, V14125, V14126, V14126, V14126,
+ }, // P[545]
+ {
+ V14126, V14127, V14127, V14127, V14127, V14128, V14128, V14128,
+ V14128, V14129, V14129, V14129, V14129, V14130, V14130, V13774,
+ V13774, V14131, V14131, V14131, V14131, V14132, V14132, V14133,
+ V14133, V14134, V14134, V14135, V14135, 0, 0, 0,
+ }, // P[546]
+ {
+ 0, V14057, V14136, V14078, V14085, V14086, V14079, V14137,
+ V1057, V1058, V14080, V1054, V14053, V14081, V1034, V14138,
+ V1047, V9, V4, V5, V1048, V1049, V1050, V1051,
+ V1052, V1053, V14056, V309, V14082, V1056, V14083, V14058,
+ }, // P[547]
+ {
+ V14087, V489, V491, V1063, V492, V493, V1077, V495,
+ V496, V497, V498, V499, V500, V501, V502, V503,
+ V505, V1071, V506, V1250, V507, V508, V1105, V509,
+ V1110, V1251, V1075, V14076, V14084, V14077, V14139, V14063,
+ }, // P[548]
+ {
+ V1022, V2, V513, V539, V514, V515, V542, V519,
+ V284, V536, V286, V520, V300, V521, V1059, V10,
+ V526, V1252, V287, V180, V527, V528, V531, V291,
+ V301, V292, V569, V14064, V14140, V14065, V14141, V14142,
+ }, // P[549]
+ {
+ V14143, V14055, V14072, V14073, V14054, V14144, V1856, V14145,
+ V14146, V14147, V14148, V14149, V14150, V14151, V14152, V14153,
+ V14154, V1810, V1811, V1812, V1813, V1814, V1815, V1816,
+ V1817, V1818, V1819, V1820, V1821, V1822, V1823, V1824,
+ }, // P[550]
+ {
+ V1825, V1826, V1827, V1828, V1829, V1830, V1831, V1832,
+ V1833, V1834, V1835, V1836, V1837, V1838, V1839, V1840,
+ V1841, V1842, V1843, V1844, V1845, V1846, V1847, V1848,
+ V1849, V1850, V1851, V1852, V1853, V14155, V14156, V14157,
+ }, // P[551]
+ {
+ V1591, V1540, V1541, V1542, V1543, V1544, V1545, V1546,
+ V1547, V1548, V1549, V1550, V1551, V1552, V1553, V1554,
+ V1555, V1556, V1557, V1558, V1559, V1560, V1561, V1562,
+ V1563, V1564, V1565, V1566, V1567, V1568, V1569, 0,
+ }, // P[552]
+ {
+ 0, 0, V1570, V1571, V1572, V1573, V1574, V1575,
+ 0, 0, V1576, V1577, V1578, V1579, V1580, V1581,
+ 0, 0, V1582, V1583, V1584, V1585, V1586, V1587,
+ 0, 0, V1588, V1589, V1590, 0, 0, 0,
+ }, // P[553]
+ {
+ V14158, V14159, V14160, V3, V14161, V14162, V14163, 0,
+ V14164, V14165, V14166, V14167, V14168, V14169, V14170, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[554]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V14171, 0, V14172, 0, 0, 0,
+ }, // P[555]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V14173, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[556]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, V14174, V14175,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[557]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V14176, V14177, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[558]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V14178, V14179, 0, V14180, 0,
+ }, // P[559]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V14181, V14182, 0, 0, 0, 0,
+ }, // P[560]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, V14183, V14184,
+ }, // P[561]
+ {
+ V14185, V14186, V14187, V14188, V14189, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[562]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, V14190, V14191, V14192, V14193, V14194,
+ }, // P[563]
+ {
+ V14195, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[564]
+ {
+ V489, V491, V1063, V492, V493, V1077, V495, V496,
+ V497, V498, V499, V500, V501, V502, V503, V505,
+ V1071, V506, V1250, V507, V508, V1105, V509, V1110,
+ V1251, V1075, V2, V513, V539, V514, V515, V542,
+ }, // P[565]
+ {
+ V519, V284, V536, V286, V520, V300, V521, V1059,
+ V10, V526, V1252, V287, V180, V527, V528, V531,
+ V291, V301, V292, V569, V489, V491, V1063, V492,
+ V493, V1077, V495, V496, V497, V498, V499, V500,
+ }, // P[566]
+ {
+ V501, V502, V503, V505, V1071, V506, V1250, V507,
+ V508, V1105, V509, V1110, V1251, V1075, V2, V513,
+ V539, V514, V515, V542, V519, 0, V536, V286,
+ V520, V300, V521, V1059, V10, V526, V1252, V287,
+ }, // P[567]
+ {
+ V180, V527, V528, V531, V291, V301, V292, V569,
+ V489, V491, V1063, V492, V493, V1077, V495, V496,
+ V497, V498, V499, V500, V501, V502, V503, V505,
+ V1071, V506, V1250, V507, V508, V1105, V509, V1110,
+ }, // P[568]
+ {
+ V1251, V1075, V2, V513, V539, V514, V515, V542,
+ V519, V284, V536, V286, V520, V300, V521, V1059,
+ V10, V526, V1252, V287, V180, V527, V528, V531,
+ V291, V301, V292, V569, V489, 0, V1063, V492,
+ }, // P[569]
+ {
+ 0, 0, V495, 0, 0, V498, V499, 0,
+ 0, V502, V503, V505, V1071, 0, V1250, V507,
+ V508, V1105, V509, V1110, V1251, V1075, V2, V513,
+ V539, V514, 0, V542, 0, V284, V536, V286,
+ }, // P[570]
+ {
+ V520, V300, V521, V1059, 0, V526, V1252, V287,
+ V180, V527, V528, V531, V291, V301, V292, V569,
+ V489, V491, V1063, V492, V493, V1077, V495, V496,
+ V497, V498, V499, V500, V501, V502, V503, V505,
+ }, // P[571]
+ {
+ V1071, V506, V1250, V507, V508, V1105, V509, V1110,
+ V1251, V1075, V2, V513, V539, V514, V515, V542,
+ V519, V284, V536, V286, V520, V300, V521, V1059,
+ V10, V526, V1252, V287, V180, V527, V528, V531,
+ }, // P[572]
+ {
+ V291, V301, V292, V569, V489, V491, 0, V492,
+ V493, V1077, V495, 0, 0, V498, V499, V500,
+ V501, V502, V503, V505, V1071, 0, V1250, V507,
+ V508, V1105, V509, V1110, V1251, 0, V2, V513,
+ }, // P[573]
+ {
+ V539, V514, V515, V542, V519, V284, V536, V286,
+ V520, V300, V521, V1059, V10, V526, V1252, V287,
+ V180, V527, V528, V531, V291, V301, V292, V569,
+ V489, V491, 0, V492, V493, V1077, V495, 0,
+ }, // P[574]
+ {
+ V497, V498, V499, V500, V501, 0, V503, 0,
+ 0, 0, V1250, V507, V508, V1105, V509, V1110,
+ V1251, 0, V2, V513, V539, V514, V515, V542,
+ V519, V284, V536, V286, V520, V300, V521, V1059,
+ }, // P[575]
+ {
+ V10, V526, V1252, V287, V180, V527, V528, V531,
+ V291, V301, V292, V569, V489, V491, V1063, V492,
+ V493, V1077, V495, V496, V497, V498, V499, V500,
+ V501, V502, V503, V505, V1071, V506, V1250, V507,
+ }, // P[576]
+ {
+ V508, V1105, V509, V1110, V1251, V1075, V2, V513,
+ V539, V514, V515, V542, V519, V284, V536, V286,
+ V520, V300, V521, V1059, V10, V526, V1252, V287,
+ V180, V527, V528, V531, V291, V301, V292, V569,
+ }, // P[577]
+ {
+ V501, V502, V503, V505, V1071, V506, V1250, V507,
+ V508, V1105, V509, V1110, V1251, V1075, V2, V513,
+ V539, V514, V515, V542, V519, V284, V536, V286,
+ V520, V300, V521, V1059, V10, V526, V1252, V287,
+ }, // P[578]
+ {
+ V1251, V1075, V2, V513, V539, V514, V515, V542,
+ V519, V284, V536, V286, V520, V300, V521, V1059,
+ V10, V526, V1252, V287, V180, V527, V528, V531,
+ V291, V301, V292, V569, V489, V491, V1063, V492,
+ }, // P[579]
+ {
+ V493, V1077, V495, V496, V497, V498, V499, V500,
+ V501, V502, V503, V505, V1071, V506, V1250, V507,
+ V508, V1105, V509, V1110, V1251, V1075, V2, V513,
+ V539, V514, V515, V542, V519, V284, V536, V286,
+ }, // P[580]
+ {
+ V520, V300, V521, V1059, V10, V526, V1252, V287,
+ V180, V527, V528, V531, V291, V301, V292, V569,
+ V489, V491, V1063, V492, V493, V1077, V495, V496,
+ V497, V498, V499, V500, V501, V502, V503, V505,
+ }, // P[581]
+ {
+ V291, V301, V292, V569, V14196, V14197, 0, 0,
+ V14198, V14199, V1083, V14200, V14201, V14202, V14203, V340,
+ V14204, V14205, V14206, V14207, V14208, V14209, V14210, V1084,
+ V14211, V340, V342, V14212, V334, V14213, V14214, V14215,
+ }, // P[582]
+ {
+ V1076, V14216, V14217, V332, V533, V534, V341, V14218,
+ V14219, V333, V985, V337, V14220, V7, V14221, V14222,
+ V14223, V336, V338, V339, V14224, V14225, V14226, V335,
+ V535, V14227, V14228, V14229, V341, V333, V337, V335,
+ }, // P[583]
+ {
+ V338, V336, V14198, V14199, V1083, V14200, V14201, V14202,
+ V14203, V340, V14204, V14205, V14206, V14207, V14208, V14209,
+ V14210, V1084, V14211, V340, V342, V14212, V334, V14213,
+ V14214, V14215, V1076, V14216, V14217, V332, V533, V534,
+ }, // P[584]
+ {
+ V341, V14218, V14219, V333, V985, V337, V14220, V7,
+ V14221, V14222, V14223, V336, V338, V339, V14224, V14225,
+ V14226, V335, V535, V14227, V14228, V14229, V341, V333,
+ V337, V335, V338, V336, V14198, V14199, V1083, V14200,
+ }, // P[585]
+ {
+ V14201, V14202, V14203, V340, V14204, V14205, V14206, V14207,
+ V14208, V14209, V14210, V1084, V14211, V340, V342, V14212,
+ V334, V14213, V14214, V14215, V1076, V14216, V14217, V332,
+ V533, V534, V341, V14218, V14219, V333, V985, V337,
+ }, // P[586]
+ {
+ V14220, V7, V14221, V14222, V14223, V336, V338, V339,
+ V14224, V14225, V14226, V335, V535, V14227, V14228, V14229,
+ V341, V333, V337, V335, V338, V336, V14198, V14199,
+ V1083, V14200, V14201, V14202, V14203, V340, V14204, V14205,
+ }, // P[587]
+ {
+ V14206, V14207, V14208, V14209, V14210, V1084, V14211, V340,
+ V342, V14212, V334, V14213, V14214, V14215, V1076, V14216,
+ V14217, V332, V533, V534, V341, V14218, V14219, V333,
+ V985, V337, V14220, V7, V14221, V14222, V14223, V336,
+ }, // P[588]
+ {
+ V338, V339, V14224, V14225, V14226, V335, V535, V14227,
+ V14228, V14229, V341, V333, V337, V335, V338, V336,
+ V14198, V14199, V1083, V14200, V14201, V14202, V14203, V340,
+ V14204, V14205, V14206, V14207, V14208, V14209, V14210, V1084,
+ }, // P[589]
+ {
+ V14211, V340, V342, V14212, V334, V14213, V14214, V14215,
+ V1076, V14216, V14217, V332, V533, V534, V341, V14218,
+ V14219, V333, V985, V337, V14220, V7, V14221, V14222,
+ V14223, V336, V338, V339, V14224, V14225, V14226, V335,
+ }, // P[590]
+ {
+ V535, V14227, V14228, V14229, V341, V333, V337, V335,
+ V338, V336, V14230, V14231, 0, 0, V1047, V9,
+ V4, V5, V1048, V1049, V1050, V1051, V1052, V1053,
+ V1047, V9, V4, V5, V1048, V1049, V1050, V1051,
+ }, // P[591]
+ {
+ V1052, V1053, V1047, V9, V4, V5, V1048, V1049,
+ V1050, V1051, V1052, V1053, V1047, V9, V4, V5,
+ V1048, V1049, V1050, V1051, V1052, V1053, V1047, V9,
+ V4, V5, V1048, V1049, V1050, V1051, V1052, V1053,
+ }, // P[592]
+ {
+ V14103, V14104, V14108, V14111, 0, V14130, V14114, V14109,
+ V14119, V14131, V14125, V14126, V14127, V14128, V14115, V14121,
+ V14123, V14117, V14124, V14113, V14116, V14106, V14107, V14110,
+ V14112, V14118, V14120, V14122, V14232, V13761, V14233, V14234,
+ }, // P[593]
+ {
+ 0, V14104, V14108, 0, V14129, 0, 0, V14109,
+ 0, V14131, V14125, V14126, V14127, V14128, V14115, V14121,
+ V14123, V14117, V14124, 0, V14116, V14106, V14107, V14110,
+ 0, V14118, 0, V14122, 0, 0, 0, 0,
+ }, // P[594]
+ {
+ 0, 0, V14108, 0, 0, 0, 0, V14109,
+ 0, V14131, 0, V14126, 0, V14128, V14115, V14121,
+ 0, V14117, V14124, 0, V14116, 0, 0, V14110,
+ 0, V14118, 0, V14122, 0, V13761, 0, V14234,
+ }, // P[595]
+ {
+ 0, V14104, V14108, 0, V14129, 0, 0, V14109,
+ V14119, V14131, V14125, 0, V14127, V14128, V14115, V14121,
+ V14123, V14117, V14124, 0, V14116, V14106, V14107, V14110,
+ 0, V14118, V14120, V14122, V14232, 0, V14233, 0,
+ }, // P[596]
+ {
+ V14103, V14104, V14108, V14111, V14129, V14130, V14114, V14109,
+ V14119, V14131, 0, V14126, V14127, V14128, V14115, V14121,
+ V14123, V14117, V14124, V14113, V14116, V14106, V14107, V14110,
+ V14112, V14118, V14120, V14122, 0, 0, 0, 0,
+ }, // P[597]
+ {
+ 0, V14104, V14108, V14111, 0, V14130, V14114, V14109,
+ V14119, V14131, 0, V14126, V14127, V14128, V14115, V14121,
+ V14123, V14117, V14124, V14113, V14116, V14106, V14107, V14110,
+ V14112, V14118, V14120, V14122, 0, 0, 0, 0,
+ }, // P[598]
+ {
+ V14235, V14236, V14237, V14238, V14239, V14240, V14241, V14242,
+ V14243, V14244, V14245, 0, 0, 0, 0, 0,
+ V14246, V14247, V14248, V14249, V14250, V14251, V14252, V14253,
+ V14254, V14255, V14256, V14257, V14258, V14259, V14260, V14261,
+ }, // P[599]
+ {
+ V14262, V14263, V14264, V14265, V14266, V14267, V14268, V14269,
+ V14270, V14271, V14272, V1063, V506, V14273, V14274, 0,
+ V489, V491, V1063, V492, V493, V1077, V495, V496,
+ V497, V498, V499, V500, V501, V502, V503, V505,
+ }, // P[600]
+ {
+ V1071, V506, V1250, V507, V508, V1105, V509, V1110,
+ V1251, V1075, V14275, V2042, V14276, V14277, V14278, V14279,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[601]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, V14280, V14281, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[602]
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V14282, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[603]
+ {
+ V14283, V14284, V1820, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ V1324, V14285, V14286, V1521, V1267, V14287, V14288, V1642,
+ V14289, V14290, V14291, V13457, V14292, V14293, V14294, V14295,
+ }, // P[604]
+ {
+ V14296, V14297, V1360, V14298, V14299, V14300, V14301, V14302,
+ V14303, V1261, V1634, V14304, V1769, V1637, V1770, V14305,
+ V1416, V14306, V14307, V14308, V14309, V14310, V1752, V1334,
+ V14311, V14312, V14313, V14314, 0, 0, 0, 0,
+ }, // P[605]
+ {
+ V14315, V14316, V14317, V14318, V14319, V14320, V14321, V14322,
+ V14323, 0, 0, 0, 0, 0, 0, 0,
+ V14324, V14325, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ }, // P[606]
+ {
+ V14326, V14327, V14328, V14329, V14330, V13550, V14331, V14332,
+ V14333, V14334, V13551, V14335, V14336, V14337, V13552, V14338,
+ V14339, V14340, V14341, V14342, V14343, V14294, V14344, V14345,
+ V14346, V14347, V14348, V13607, V14349, V1277, V14350, V14351,
+ }, // P[607]
+ {
+ V14352, V14353, V14312, V14354, V14355, V13612, V13553, V13554,
+ V13613, V14356, V14357, V13371, V14358, V13555, V14359, V14360,
+ V14361, V14362, V14362, V14362, V14363, V14364, V14365, V14366,
+ V14367, V14368, V14369, V14370, V14371, V14372, V14373, V14374,
+ }, // P[608]
+ {
+ V14375, V14376, V14377, V14378, V14379, V14380, V14380, V13615,
+ V14381, V14382, V14383, V14384, V13557, V14385, V14386, V14387,
+ V13517, V14388, V14389, V14390, V14391, V14392, V14393, V14394,
+ V14395, V14396, V14397, V14398, V14399, V14287, V14400, V14401,
+ }, // P[609]
+ {
+ V14402, V14403, V14404, V14405, V14406, V14407, V14408, V14409,
+ V14410, V14411, V14412, V14412, V14413, V14414, V14415, V13367,
+ V14416, V14417, V14418, V14419, V14420, V1303, V14421, V14422,
+ V1305, V14423, V14424, V14425, V14426, V14427, V14428, V14429,
+ }, // P[610]
+ {
+ V14430, V14431, V14432, V14433, V14434, V14435, V14436, V14437,
+ V14438, V14439, V14440, V14441, V14442, V14443, V13315, V14444,
+ V1315, V14445, V14445, V14446, V14447, V14447, V14448, V14449,
+ V14450, V14451, V14452, V14453, V14454, V14455, V14456, V14457,
+ }, // P[611]
+ {
+ V14458, V14459, V14460, V13562, V14461, V14462, V14463, V14464,
+ V13627, V14464, V14465, V13564, V14466, V14467, V14468, V14469,
+ V13565, V13288, V14470, V14471, V14472, V14473, V14474, V14475,
+ V14476, V14477, V14478, V14479, V14480, V14481, V14482, V14483,
+ }, // P[612]
+ {
+ V14484, V14485, V14486, V14487, V14488, V14489, V14490, V14491,
+ V13566, V14492, V14493, V14494, V14495, V14496, V14497, V13568,
+ V14498, V14499, V14500, V14501, V14502, V14503, V14504, V14505,
+ V13316, V13635, V14506, V14507, V14508, V14509, V14510, V14511,
+ }, // P[613]
+ {
+ V14512, V14513, V13569, V14514, V14515, V14516, V14517, V13677,
+ V14518, V14519, V14520, V14521, V14522, V14523, V14524, V14525,
+ V14526, V14527, V14528, V14529, V14530, V13384, V14531, V14532,
+ V14533, V14534, V14535, V14536, V14537, V14538, V14539, V14540,
+ }, // P[614]
+ {
+ V14541, V13570, V13467, V14542, V14543, V14544, V14545, V14546,
+ V14547, V14548, V14549, V13638, V14550, V14551, V14552, V14553,
+ V14554, V14555, V14556, V14557, V13639, V14558, V14559, V14560,
+ V14561, V14562, V14563, V14564, V14565, V14566, V14567, V14568,
+ }, // P[615]
+ {
+ V14569, V13641, V14570, V14571, V14572, V14573, V14574, V14575,
+ V14576, V14577, V14578, V14579, V14580, V14580, V14581, V14582,
+ V13643, V14583, V14584, V14585, V14586, V14587, V14588, V14589,
+ V13370, V14590, V14591, V14592, V14593, V14594, V14595, V14596,
+ }, // P[616]
+ {
+ V13649, V14597, V14598, V14599, V14600, V14601, V14602, V14602,
+ V13650, V13679, V14603, V14604, V14605, V14606, V14607, V13333,
+ V13652, V14608, V14609, V13580, V14610, V14611, V13537, V14612,
+ V14613, V13583, V14614, V14615, V14616, V14617, V14617, V14618,
+ }, // P[617]
+ {
+ V14619, V14620, V14621, V14622, V14623, V14624, V14625, V14626,
+ V14627, V14628, V14629, V14630, V14631, V14632, V14633, V14634,
+ V14635, V14636, V14637, V14638, V14639, V14640, V14641, V14642,
+ V14643, V14644, V13589, V14645, V14646, V14647, V14648, V14649,
+ }, // P[618]
+ {
+ V14650, V14651, V14652, V14653, V14654, V14655, V14656, V14657,
+ V14658, V14659, V14660, V14446, V14661, V14662, V14663, V14664,
+ V14665, V14666, V14667, V14668, V14669, V14670, V14671, V14672,
+ V13387, V14673, V14674, V14675, V14676, V14677, V14678, V13592,
+ }, // P[619]
+ {
+ V14679, V14680, V14681, V14682, V14683, V14684, V14685, V14686,
+ V14687, V14688, V14689, V14690, V14691, V14692, V14693, V14694,
+ V14695, V14696, V14697, V14698, V13328, V14699, V14700, V14701,
+ V14702, V14703, V14704, V13659, V14705, V14706, V14707, V14708,
+ }, // P[620]
+ {
+ V14709, V14710, V14711, V14712, V1405, V14713, V14714, V14715,
+ V14716, V14717, V14718, V14719, V14720, V14721, V14722, V14723,
+ V13664, V13665, V1412, V14724, V14725, V14726, V14727, V14728,
+ V14729, V14730, V14731, V14732, V14733, V14734, V14735, V13666,
+ }, // P[621]
+ {
+ V14736, V14737, V14738, V14739, V14740, V14741, V14742, V14743,
+ V14744, V14745, V14746, V14747, V14748, V14749, V14750, V14751,
+ V14752, V14753, V14754, V14755, V14756, V14757, V14758, V14759,
+ V14760, V14761, V14762, V14763, V14764, V14765, V13672, V13672,
+ }, // P[622]
+ {
+ V14766, V14767, V14768, V14769, V14770, V14771, V14772, V14773,
+ V14774, V14775, V13673, V14776, V14777, V14778, V14779, V14780,
+ V14781, V14782, V14783, V14784, V14785, V1460, V14786, V1464,
+ V14787, V14788, V14789, V14790, V1469, V14791,
+ }, // P[623]
+ }; // static const NUnicode::NPrivate::TDecompositionTable::TValuePtr P[][32]
+
+ static const NUnicode::NPrivate::TDecompositionTable::TValuePtr* const Indexes[] = {
+ P[0], P[0], P[0], P[0], P[0], P[1], P[2], P[3], P[4], P[5], P[6], P[7], P[0], P[8], P[9], P[10],
+ P[11], P[12], P[0], P[0], P[0], P[13], P[14], P[15], P[0], P[0], P[16], P[17], P[18], P[19], P[20], P[21],
+ P[22], P[23], P[24], P[25], P[0], P[0], P[26], P[27], P[0], P[0], P[0], P[0], P[28], P[0], P[0], P[0],
+ P[0], P[29], P[0], P[30], P[0], P[0], P[31], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[32], P[33], P[0], P[0], P[0], P[34], P[0],
+ P[0], P[35], P[36], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[37], P[0], P[38], P[0], P[39], P[0],
+ P[0], P[0], P[40], P[0], P[0], P[0], P[41], P[0], P[0], P[0], P[42], P[0], P[0], P[0], P[43], P[0],
+ P[0], P[44], P[0], P[0], P[0], P[45], P[46], P[0], P[47], P[0], P[48], P[49], P[50], P[51], P[0], P[0],
+ P[0], P[52], P[0], P[0], P[0], P[0], P[0], P[53], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[54], P[55], P[56], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[57], P[58], P[59], P[60], P[61], P[0], P[0],
+ P[62], P[63], P[64], P[65], P[66], P[67], P[68], P[69], P[70], P[71], P[72], P[73], P[74], P[75], P[76], P[77],
+ P[78], P[79], P[80], P[81], P[82], P[83], P[0], P[0], P[84], P[85], P[86], P[87], P[88], P[89], P[90], P[0],
+ P[91], P[92], P[93], P[94], P[95], P[96], P[0], P[97], P[0], P[98], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[99], P[100], P[101], P[102], P[103], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[104], P[0], P[0], P[105], P[0], P[0], P[106], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[107], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[108], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[109], P[0], P[0], P[110], P[111], P[112], P[113], P[114], P[115], P[116], P[117], P[0],
+ P[118], P[119], P[120], P[121], P[122], P[123], P[124], P[125], P[0], P[126], P[127], P[128], P[129], P[0], P[0], P[0],
+ P[130], P[131], P[132], P[133], P[134], P[135], P[136], P[137], P[138], P[139], P[140], P[141], P[142], P[143], P[144], P[145],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[146], P[0], P[0], P[0], P[0], P[0], P[0], P[147], P[0], P[0], P[0], P[148],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[149], P[0], P[0], P[0], P[0], P[0],
+ P[150], P[151], P[152], P[153], P[154], P[155], P[156], P[157], P[158], P[159], P[160], P[161], P[162], P[163], P[164], P[165],
+ P[166], P[167], P[168], P[169], P[170], P[171], P[172], P[173], P[174], P[175], P[176], P[177], P[178], P[179], P[180], P[181],
+ P[182], P[183], P[184], P[185], P[186], P[187], P[188], P[189], P[190], P[191], P[192], P[193], P[194], P[195], P[196], P[197],
+ P[198], P[199], P[200], P[201], P[202], P[203], P[204], P[205], P[206], P[207], P[208], P[209], P[210], P[211], P[212], P[213],
+ P[214], P[215], P[216], P[217], P[218], P[219], P[220], P[221], P[222], P[223], P[224], P[225], P[226], P[227], P[228], P[229],
+ P[230], P[231], P[232], P[233], P[234], P[235], P[236], P[237], P[238], P[239], P[240], P[241], P[242], P[243], P[244], P[245],
+ P[246], P[247], P[248], P[249], P[250], P[251], P[252], P[253], P[254], P[255], P[256], P[257], P[258], P[259], P[260], P[261],
+ P[262], P[263], P[264], P[265], P[266], P[267], P[268], P[269], P[270], P[271], P[272], P[273], P[274], P[275], P[276], P[277],
+ P[278], P[279], P[280], P[281], P[282], P[283], P[284], P[285], P[286], P[287], P[288], P[289], P[290], P[291], P[292], P[293],
+ P[294], P[295], P[296], P[297], P[298], P[299], P[300], P[301], P[302], P[303], P[304], P[305], P[306], P[307], P[308], P[309],
+ P[310], P[311], P[312], P[313], P[314], P[315], P[316], P[317], P[318], P[319], P[320], P[321], P[322], P[323], P[324], P[325],
+ P[326], P[327], P[328], P[329], P[330], P[331], P[332], P[333], P[334], P[335], P[336], P[337], P[338], P[339], P[340], P[341],
+ P[342], P[343], P[344], P[345], P[346], P[347], P[348], P[349], P[350], P[351], P[352], P[353], P[354], P[355], P[356], P[357],
+ P[358], P[359], P[360], P[361], P[362], P[363], P[364], P[365], P[366], P[367], P[368], P[369], P[370], P[371], P[372], P[373],
+ P[374], P[375], P[376], P[377], P[378], P[379], P[380], P[381], P[382], P[383], P[384], P[385], P[386], P[387], P[388], P[389],
+ P[390], P[391], P[392], P[393], P[394], P[395], P[396], P[397], P[398], P[399], P[400], P[401], P[402], P[403], P[404], P[405],
+ P[406], P[407], P[408], P[409], P[410], P[411], P[412], P[413], P[414], P[415], P[416], P[417], P[418], P[419], P[420], P[421],
+ P[422], P[423], P[424], P[425], P[426], P[427], P[428], P[429], P[430], P[431], P[432], P[433], P[434], P[435], P[436], P[437],
+ P[438], P[439], P[440], P[441], P[442], P[443], P[444], P[445], P[446], P[447], P[448], P[449], P[450], P[451], P[452], P[453],
+ P[454], P[455], P[456], P[457], P[458], P[459], P[460], P[461], P[462], P[463], P[464], P[465], P[466], P[467], P[468], P[469],
+ P[470], P[471], P[472], P[473], P[474], P[475], P[476], P[477], P[478], P[479], P[480], P[481], P[482], P[483], P[484], P[485],
+ P[486], P[487], P[488], P[489], P[490], P[491], P[492], P[493], P[494], P[495], P[496], P[497], P[498], P[499], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[500], P[501], P[502], P[503], P[504], P[505], P[506], P[507],
+ P[508], P[509], P[510], P[511], P[512], P[513], P[514], P[0], P[515], P[516], P[517], P[518], P[519], P[520], P[521], P[522],
+ P[523], P[524], P[525], P[526], P[527], P[528], P[529], P[530], P[531], P[532], P[533], P[534], P[535], P[536], P[537], P[538],
+ P[539], P[540], P[541], P[542], P[543], P[544], P[545], P[546], P[547], P[548], P[549], P[550], P[551], P[552], P[553], P[554],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[555], P[556], P[0], P[0], P[0], P[557], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[558], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[559], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[560], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[561], P[562], P[0], P[563], P[564], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[565], P[566], P[567], P[568], P[569], P[570], P[571], P[572], P[573], P[574], P[575], P[576], P[577], P[565], P[566], P[578],
+ P[568], P[579], P[580], P[581], P[572], P[582], P[583], P[584], P[585], P[586], P[587], P[588], P[589], P[590], P[591], P[592],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[593], P[594], P[595], P[596], P[597], P[598], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[599], P[600], P[601], P[602], P[603], P[0], P[0], P[0],
+ P[604], P[605], P[606], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0], P[0],
+ P[607], P[608], P[609], P[610], P[611], P[612], P[613], P[614], P[615], P[616], P[617], P[618], P[619], P[620], P[621], P[622],
+ P[623],
+ }; // static const NUnicode::NPrivate::TDecompositionTable::TValuePtr* const Indexes[]
+
+ static const size_t Size = 195102;
+}} // namespace NCompatDecompositionTableGenerated
+
+namespace NUnicode {
+ namespace NPrivate {
+ const NUnicode::NPrivate::TDecompositionTable& CompatDecompositionTable() {
+ static const NUnicode::NPrivate::TDecompositionTable data(NCompatDecompositionTableGenerated::Indexes, NCompatDecompositionTableGenerated::Size);
+ return data;
+ }
+ } // namespace NPrivate
+} // namespace NUnicode
+
diff --git a/library/cpp/unicode/normalization/normalization.cpp b/library/cpp/unicode/normalization/normalization.cpp
new file mode 100644
index 0000000000..7da7211514
--- /dev/null
+++ b/library/cpp/unicode/normalization/normalization.cpp
@@ -0,0 +1,66 @@
+#include "normalization.h"
+
+static const wchar32 S_BASE = 0xAC00;
+static const wchar32 L_BASE = 0x1100;
+static const wchar32 V_BASE = 0x1161;
+static const wchar32 T_BASE = 0x11A7;
+static const int L_COUNT = 19;
+static const int V_COUNT = 21;
+static const int T_COUNT = 28;
+static const int N_COUNT = V_COUNT * T_COUNT; // 588
+static const int S_COUNT = L_COUNT * N_COUNT; // 11172
+
+static inline wchar32 ComposeHangul(wchar32 lead, wchar32 tail) {
+ // 1. check to see if two current characters are L and V
+ int lIndex = lead - L_BASE;
+ if (0 <= lIndex && lIndex < L_COUNT) {
+ int vIndex = tail - V_BASE;
+ if (0 <= vIndex && vIndex < V_COUNT) {
+ // make syllable of form LV
+ lead = (wchar32)(S_BASE + (lIndex * V_COUNT + vIndex) * T_COUNT);
+ return lead;
+ }
+ }
+
+ // 2. check to see if two current characters are LV and T
+ int sIndex = lead - S_BASE;
+ if (0 <= sIndex && sIndex < S_COUNT && (sIndex % T_COUNT) == 0) {
+ int TIndex = tail - T_BASE;
+ if (0 < TIndex && TIndex < T_COUNT) {
+ // make syllable of form LVT
+ lead += TIndex;
+ return lead;
+ }
+ }
+
+ return 0;
+}
+
+NUnicode::NPrivate::TComposition::TComposition() {
+ for (size_t i = 0; i != RawDataSize; ++i) {
+ const TRawData& data = RawData[i];
+
+ if (DecompositionCombining(data.Lead) != 0)
+ continue;
+
+ Data[TKey(data.Lead, data.Tail)] = data.Comp;
+ }
+
+ for (wchar32 s = 0xAC00; s != 0xD7A4; ++s) {
+ const wchar32* decompBegin = NUnicode::Decomposition<true>(s);
+
+ if (decompBegin == nullptr)
+ continue;
+
+ wchar32 lead = *(decompBegin++);
+ while (*decompBegin) {
+ wchar32 tail = *(decompBegin++);
+ wchar32 comp = ComposeHangul(lead, tail);
+ Y_ASSERT(comp != 0);
+
+ Data[TKey(lead, tail)] = comp;
+
+ lead = comp;
+ }
+ }
+}
diff --git a/library/cpp/unicode/normalization/normalization.h b/library/cpp/unicode/normalization/normalization.h
new file mode 100644
index 0000000000..4f5f57881c
--- /dev/null
+++ b/library/cpp/unicode/normalization/normalization.h
@@ -0,0 +1,384 @@
+#pragma once
+
+#include "decomposition_table.h"
+
+#include <util/charset/unidata.h>
+#include <util/charset/wide.h>
+#include <util/generic/hash.h>
+#include <util/generic/vector.h>
+#include <util/generic/algorithm.h>
+#include <util/generic/singleton.h>
+#include <util/generic/noncopyable.h>
+#include <utility>
+
+namespace NUnicode {
+ enum ENormalization {
+ NFD,
+ NFC,
+ NFKD,
+ NFKC,
+ };
+
+ // Грубо говоря:
+ // NFD расскладывает "ё" на "е + диакритику"
+ // NFC сначала всё раскладывает, потом всё что может - складывает
+ // NFKD делает то же, что и NFD. Кроме того, например, римскую IV (\x2163)
+ // превращает в латинские I и V
+ // NFKC - NFKD + композиция (римская четвёрка из I и V, естественно, не образуется)
+
+ // Формальная спецификация: http://www.unicode.org/reports/tr15/
+
+ namespace NPrivate {
+ inline const wchar32* Decomposition(const TDecompositionTable& table, wchar32 ch) {
+ return table.Get(ch, static_cast<const wchar32*>(nullptr));
+ }
+
+ class TDecompositor {
+ private:
+ const TDecompositionTable& Table;
+
+ public:
+ inline TDecompositor(const TDecompositionTable& table)
+ : Table(table)
+ {
+ }
+
+ inline const wchar32* Decomposition(wchar32 ch) const {
+ return NPrivate::Decomposition(Table, ch);
+ }
+ };
+
+ template <bool IsCompat>
+ struct TStandartDecompositor: public TDecompositor {
+ TStandartDecompositor()
+ : TDecompositor(NPrivate::DecompositionTable<IsCompat>())
+ {
+ }
+ };
+
+ template <ENormalization N>
+ struct TShift;
+
+ template <>
+ struct TShift<NFD> {
+ static const WC_TYPE Value = NFD_QC;
+ };
+ template <>
+ struct TShift<NFC> {
+ static const WC_TYPE Value = NFC_QC;
+ };
+ template <>
+ struct TShift<NFKD> {
+ static const WC_TYPE Value = NFKD_QC;
+ };
+ template <>
+ struct TShift<NFKC> {
+ static const WC_TYPE Value = NFKC_QC;
+ };
+
+ template <ENormalization N>
+ inline bool Normalized(wchar32 ch) {
+ return CharInfo(ch) & NPrivate::TShift<N>::Value;
+ }
+
+ class TComposition {
+ private:
+ struct TRawData {
+ wchar32 Lead;
+ wchar32 Tail;
+ wchar32 Comp;
+ };
+
+ static const TRawData RawData[];
+ static const size_t RawDataSize;
+
+ class TKey: public std::pair<wchar32, wchar32> {
+ public:
+ inline TKey(wchar32 a, wchar32 b)
+ : std::pair<wchar32, wchar32>(a, b)
+ {
+ }
+
+ inline size_t Hash() const {
+ return CombineHashes(first, second);
+ }
+ };
+
+ template <class T>
+ struct THash {
+ inline size_t operator()(const T& t) const {
+ return t.Hash();
+ }
+ };
+
+ typedef THashMap<TKey, wchar32, THash<TKey>> TData;
+ TData Data;
+
+ public:
+ TComposition();
+
+ inline wchar32 Composite(wchar32 lead, wchar32 tail) const {
+ TData::const_iterator i = Data.find(TKey(lead, tail));
+ if (i == Data.end())
+ return 0;
+
+ return i->second;
+ }
+ };
+
+ typedef std::pair<wchar32, TCombining> TSymbol;
+ typedef TVector<TSymbol> TBuffer;
+
+ template <bool doCompose>
+ class TCompositor;
+
+ template <>
+ class TCompositor<false> {
+ public:
+ inline void DoComposition(TBuffer& buffer) {
+ Y_UNUSED(buffer);
+ }
+ };
+
+ template <>
+ class TCompositor<true> {
+ private:
+ static const wchar32 NonComposite = 0;
+ const TComposition* Composition;
+
+ public:
+ inline TCompositor()
+ : Composition(Singleton<TComposition>())
+ {
+ }
+
+ inline void DoComposition(TBuffer& buffer) {
+ if (buffer.size() < 2)
+ return;
+
+ const TSymbol& leadSymbol = buffer[0];
+ if (leadSymbol.second != 0)
+ return;
+
+ wchar32 lead = leadSymbol.first;
+ bool oneMoreTurnPlease = false;
+ do {
+ oneMoreTurnPlease = false;
+ TCombining lastCombining = 0;
+ for (TBuffer::iterator i = buffer.begin() + 1, mi = buffer.end(); i != mi; ++i) {
+ TCombining currentCombining = i->second;
+ if (!(currentCombining != lastCombining && currentCombining != 0 || lastCombining == 0 && currentCombining == 0))
+ continue;
+
+ lastCombining = currentCombining;
+ wchar32 comb = Composition->Composite(lead, i->first);
+ if (comb == NonComposite)
+ continue;
+
+ lead = comb;
+ buffer.erase(i);
+ oneMoreTurnPlease = true;
+ break;
+ }
+ } while (oneMoreTurnPlease);
+
+ Y_ASSERT(DecompositionCombining(lead) == 0);
+ buffer[0] = TSymbol(lead, 0);
+ }
+ };
+
+ template <ENormalization N, typename TCharType>
+ inline bool Normalized(const TCharType* begin, const TCharType* end) {
+ TCombining lastCanonicalClass = 0;
+ for (const TCharType* i = begin; i != end;) {
+ wchar32 ch = ReadSymbolAndAdvance(i, end);
+
+ TCombining canonicalClass = DecompositionCombining(ch);
+ if (lastCanonicalClass > canonicalClass && canonicalClass != 0)
+ return false;
+
+ if (!Normalized<N>(ch))
+ return false;
+
+ lastCanonicalClass = canonicalClass;
+ }
+ return true;
+ }
+ }
+
+ template <bool compat>
+ inline const wchar32* Decomposition(wchar32 ch) {
+ return NPrivate::Decomposition(NPrivate::DecompositionTable<compat>(), ch);
+ }
+
+ template <ENormalization N, class TDecompositor = NPrivate::TDecompositor>
+ class TNormalizer : NNonCopyable::TNonCopyable {
+ private:
+ static const ENormalization Norm = N;
+ static const bool IsCompat = Norm == NFKD || Norm == NFKC;
+ static const bool RequireComposition = Norm == NFC || Norm == NFKC;
+
+ typedef NPrivate::TSymbol TSymbol;
+ typedef NPrivate::TBuffer TBuffer;
+
+ TBuffer Buffer;
+
+ NPrivate::TCompositor<RequireComposition> Compositor;
+ const TDecompositor& Decompositor;
+
+ private:
+ static inline bool Compare(const TSymbol& a, const TSymbol& b) {
+ return a.second < b.second;
+ }
+
+ struct TComparer {
+ inline bool operator()(const TSymbol& a, const TSymbol& b) {
+ return Compare(a, b);
+ }
+ };
+
+ template <class T>
+ static inline void Write(const TBuffer::const_iterator& begin, const TBuffer::const_iterator& end, T& out) {
+ for (TBuffer::const_iterator i = begin; i != end; ++i) {
+ WriteSymbol(i->first, out);
+ }
+ }
+
+ static inline void Write(const TBuffer::const_iterator& begin, const TBuffer::const_iterator& end, TUtf32String& out) { // because WriteSymbol from util/charset/wide.h works wrong in this case
+ for (TBuffer::const_iterator i = begin; i != end; ++i) {
+ out += i->first;
+ }
+ }
+
+ inline void SortBuffer() {
+ if (Buffer.size() < 2)
+ return;
+
+ StableSort(Buffer.begin(), Buffer.end(), TComparer());
+ }
+
+ template <class T>
+ inline void AddCharNoDecomposition(wchar32 c, T& out) {
+ TCombining cc = DecompositionCombining(c);
+ if (cc == 0) {
+ SortBuffer();
+ Buffer.push_back(TBuffer::value_type(c, cc));
+
+ Compositor.DoComposition(Buffer);
+
+ if (Buffer.size() > 1) {
+ Write(Buffer.begin(), Buffer.end() - 1, out);
+ Buffer.erase(Buffer.begin(), Buffer.end() - 1); // TODO I don't like this
+ }
+ } else {
+ Buffer.push_back(TBuffer::value_type(c, cc));
+ }
+ }
+
+ template <class T>
+ inline void AddChar(wchar32 c, T& out) {
+ const wchar32* decompBegin = Decompositor.Decomposition(c);
+ if (decompBegin) {
+ while (*decompBegin) {
+ Y_ASSERT(Decompositor.Decomposition(*decompBegin) == nullptr);
+ AddCharNoDecomposition(*(decompBegin++), out);
+ }
+ return;
+ } else {
+ AddCharNoDecomposition(c, out);
+ }
+ }
+
+ template <class T, typename TCharType>
+ inline void DoNormalize(const TCharType* begin, const TCharType* end, T& out) {
+ Buffer.clear();
+
+ for (const TCharType* i = begin; i != end;) {
+ AddChar(ReadSymbolAndAdvance(i, end), out);
+ }
+
+ SortBuffer();
+ Compositor.DoComposition(Buffer);
+ Write(Buffer.begin(), Buffer.end(), out);
+ }
+
+ public:
+ TNormalizer()
+ : Decompositor(*Singleton<NPrivate::TStandartDecompositor<IsCompat>>())
+ {
+ }
+
+ TNormalizer(const TDecompositor& decompositor)
+ : Decompositor(decompositor)
+ {
+ }
+
+ template <class T, typename TCharType>
+ inline void Normalize(const TCharType* begin, const TCharType* end, T& out) {
+ if (NPrivate::Normalized<Norm>(begin, end)) {
+ for (const TCharType* i = begin; i != end; ++i) {
+ WriteSymbol(*i, out);
+ }
+ } else {
+ DoNormalize(begin, end, out);
+ }
+ }
+
+ template <typename TCharType>
+ inline void Normalize(const TCharType* begin, const TCharType* end, TUtf32String& out) {
+ if (NPrivate::Normalized<Norm>(begin, end)) {
+ for (const TCharType* i = begin; i != end;) {
+ out += ReadSymbolAndAdvance(i, end);
+ }
+ } else {
+ DoNormalize(begin, end, out);
+ }
+ }
+
+ template <class T, typename TCharType>
+ inline void Normalize(const TCharType* begin, size_t len, T& out) {
+ return Normalize(begin, begin + len, out);
+ }
+
+ template <typename TCharType>
+ inline TBasicString<TCharType> Normalize(const TBasicString<TCharType>& src) {
+ if (NPrivate::Normalized<Norm>(src.begin(), src.end())) {
+ // nothing to normalize
+ return src;
+ } else {
+ TBasicString<TCharType> res;
+ res.reserve(src.length());
+ DoNormalize(src.begin(), src.end(), res);
+ return res;
+ }
+ }
+ };
+}
+
+//! decompose utf16 or utf32 string to any container supporting push_back or to T*
+template <NUnicode::ENormalization Norm, class T, typename TCharType>
+inline void Normalize(const TCharType* begin, size_t len, T& out) {
+ ::NUnicode::TNormalizer<Norm> dec;
+ dec.Normalize(begin, len, out);
+}
+
+template <NUnicode::ENormalization N, typename TCharType>
+inline TBasicString<TCharType> Normalize(const TCharType* str, size_t len) {
+ TBasicString<TCharType> res;
+ res.reserve(len);
+
+ Normalize<N>(str, len, res);
+
+ return res;
+}
+
+template <NUnicode::ENormalization N, typename TCharType>
+inline TBasicString<TCharType> Normalize(const TBasicString<TCharType>& str) {
+ ::NUnicode::TNormalizer<N> dec;
+ return dec.Normalize(str);
+}
+
+template <NUnicode::ENormalization N, typename TCharType>
+inline TBasicString<TCharType> Normalize(const TBasicStringBuf<TCharType> str) {
+ return Normalize<N>(str.data(), str.size());
+}
diff --git a/library/cpp/unicode/normalization/ut/normalization_ut.cpp b/library/cpp/unicode/normalization/ut/normalization_ut.cpp
new file mode 100644
index 0000000000..54d4940a26
--- /dev/null
+++ b/library/cpp/unicode/normalization/ut/normalization_ut.cpp
@@ -0,0 +1,32 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/charset/wide.h>
+
+#include <library/cpp/unicode/normalization/normalization.h>
+
+Y_UNIT_TEST_SUITE(TUnicodeNormalizationTest) {
+ template <NUnicode::ENormalization NormType>
+ void TestInit() {
+ NUnicode::TNormalizer<NormType> normalizer;
+ TString s("упячка detected");
+ TUtf16String w;
+ UTF8ToWide(s, w);
+ normalizer.Normalize(w);
+ }
+
+ Y_UNIT_TEST(TestInitNFD) {
+ TestInit<NUnicode::NFD>();
+ }
+
+ Y_UNIT_TEST(TestInitNFC) {
+ TestInit<NUnicode::NFC>();
+ }
+
+ Y_UNIT_TEST(TestInitNFKD) {
+ TestInit<NUnicode::NFKD>();
+ }
+
+ Y_UNIT_TEST(TestInitNFKC) {
+ TestInit<NUnicode::NFKC>();
+ }
+}
diff --git a/library/cpp/unicode/normalization/ut/ya.make b/library/cpp/unicode/normalization/ut/ya.make
new file mode 100644
index 0000000000..a74372d9e1
--- /dev/null
+++ b/library/cpp/unicode/normalization/ut/ya.make
@@ -0,0 +1,13 @@
+UNITTEST()
+
+OWNER(mvel)
+
+PEERDIR(
+ library/cpp/unicode/normalization
+)
+
+SRCS(
+ normalization_ut.cpp
+)
+
+END()
diff --git a/library/cpp/unicode/normalization/ya.make b/library/cpp/unicode/normalization/ya.make
new file mode 100644
index 0000000000..95bc93f297
--- /dev/null
+++ b/library/cpp/unicode/normalization/ya.make
@@ -0,0 +1,24 @@
+LIBRARY()
+
+NO_UTIL()
+
+OWNER(alzobnin)
+
+SRCS(
+ generated/composition.cpp
+ generated/decomposition.cpp
+ decomposition_table.h
+ normalization.cpp
+)
+
+IF(NOT CATBOOST_OPENSOURCE)
+ SRCS(
+ custom_encoder.cpp
+ )
+ PEERDIR(
+ library/cpp/charset
+ )
+ GENERATE_ENUM_SERIALIZATION(normalization.h)
+ENDIF()
+
+END()
diff --git a/library/cpp/unicode/punycode/punycode.cpp b/library/cpp/unicode/punycode/punycode.cpp
new file mode 100644
index 0000000000..800d1f19fe
--- /dev/null
+++ b/library/cpp/unicode/punycode/punycode.cpp
@@ -0,0 +1,143 @@
+#include "punycode.h"
+#include <contrib/libs/libidn/idna.h>
+#include <contrib/libs/libidn/punycode.h>
+#include <util/charset/wide.h>
+#include <util/generic/ptr.h>
+#include <util/generic/vector.h>
+
+#include <cstdlib>
+
+static inline void CheckPunycodeResult(int rc) {
+ if (rc != PUNYCODE_SUCCESS)
+ ythrow TPunycodeError() << punycode_strerror(static_cast<Punycode_status>(rc));
+}
+
+static inline void CheckIdnaResult(int rc) {
+ if (rc != IDNA_SUCCESS)
+ ythrow TPunycodeError() << idna_strerror(static_cast<Idna_rc>(rc));
+}
+
+// UTF-32 helpers
+
+static inline void AppendWideToUtf32(const TWtringBuf& in, TVector<ui32>& out) {
+ out.reserve(out.size() + in.size() + 1);
+
+ const wchar16* b = in.begin();
+ const wchar16* e = in.end();
+ while (b < e) {
+ out.push_back(ReadSymbolAndAdvance(b, e));
+ }
+}
+
+static inline void AppendUtf32ToWide(const ui32* in, size_t len, TUtf16String& out) {
+ out.reserve(out.size() + len);
+
+ const ui32* b = in;
+ const ui32* e = in + len;
+ for (; b != e; ++b) {
+ WriteSymbol(wchar32(*b), out);
+ }
+}
+
+TStringBuf WideToPunycode(const TWtringBuf& in16, TString& out) {
+ TVector<ui32> in32;
+ AppendWideToUtf32(in16, in32);
+ size_t outlen = in32.size();
+
+ int rc;
+ do {
+ outlen *= 2;
+ out.ReserveAndResize(outlen);
+ rc = punycode_encode(in32.size(), in32.data(), nullptr, &outlen, out.begin());
+ } while (rc == PUNYCODE_BIG_OUTPUT);
+
+ CheckPunycodeResult(rc);
+
+ out.resize(outlen);
+ return out;
+}
+
+TWtringBuf PunycodeToWide(const TStringBuf& in, TUtf16String& out16) {
+ size_t outlen = in.size();
+ TVector<ui32> out32(outlen);
+
+ int rc = punycode_decode(in.size(), in.data(), &outlen, out32.begin(), nullptr);
+ CheckPunycodeResult(rc);
+
+ AppendUtf32ToWide(out32.begin(), outlen, out16);
+ return out16;
+}
+
+namespace {
+ template <typename TChar>
+ struct TIdnaResult {
+ TChar* Data = nullptr;
+
+ ~TIdnaResult() {
+ free(Data);
+ }
+ };
+}
+
+TString HostNameToPunycode(const TWtringBuf& unicodeHost) {
+ TVector<ui32> in32;
+ AppendWideToUtf32(unicodeHost, in32);
+ in32.push_back(0);
+
+ TIdnaResult<char> out;
+ int rc = idna_to_ascii_4z(in32.begin(), &out.Data, 0);
+ CheckIdnaResult(rc);
+
+ return out.Data;
+}
+
+TUtf16String PunycodeToHostName(const TStringBuf& punycodeHost) {
+ if (!IsStringASCII(punycodeHost.begin(), punycodeHost.end()))
+ ythrow TPunycodeError() << "Non-ASCII punycode input";
+
+ size_t len = punycodeHost.size();
+ TVector<ui32> in32(len + 1, 0);
+ for (size_t i = 0; i < len; ++i)
+ in32[i] = static_cast<ui8>(punycodeHost[i]);
+ in32[len] = 0;
+
+ TIdnaResult<ui32> out;
+ int rc = idna_to_unicode_4z4z(in32.begin(), &out.Data, 0);
+ CheckIdnaResult(rc);
+
+ TUtf16String decoded;
+ AppendUtf32ToWide(out.Data, std::char_traits<ui32>::length(out.Data), decoded);
+ return decoded;
+}
+
+TString ForceHostNameToPunycode(const TWtringBuf& unicodeHost) {
+ try {
+ return HostNameToPunycode(unicodeHost);
+ } catch (const TPunycodeError&) {
+ return WideToUTF8(unicodeHost);
+ }
+}
+
+TUtf16String ForcePunycodeToHostName(const TStringBuf& punycodeHost) {
+ try {
+ return PunycodeToHostName(punycodeHost);
+ } catch (const TPunycodeError&) {
+ return UTF8ToWide(punycodeHost);
+ }
+}
+
+bool CanBePunycodeHostName(const TStringBuf& host) {
+ if (!IsStringASCII(host.begin(), host.end()))
+ return false;
+
+ static constexpr TStringBuf ACE = "xn--";
+
+ TStringBuf tail(host);
+ while (tail) {
+ const TStringBuf label = tail.NextTok('.');
+ if (label.StartsWith(ACE))
+ return true;
+ }
+
+ return false;
+}
diff --git a/library/cpp/unicode/punycode/punycode.h b/library/cpp/unicode/punycode/punycode.h
new file mode 100644
index 0000000000..af4acc25c1
--- /dev/null
+++ b/library/cpp/unicode/punycode/punycode.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/yexception.h>
+
+// Simplified arcadia wrappers for contrib/libs/libidn/
+
+// Raw strings encoder/decoder: does not prepend with ACE prefix ("xn--"),
+// does not limit input length. Throws TPunycodeError on any internal error.
+// Returned strbuf points to @out data.
+TStringBuf WideToPunycode(const TWtringBuf& in, TString& out);
+TWtringBuf PunycodeToWide(const TStringBuf& in, TUtf16String& out);
+
+inline TString WideToPunycode(const TWtringBuf& in) {
+ TString out;
+ WideToPunycode(in, out);
+ return out;
+}
+
+inline TUtf16String PunycodeToWide(const TStringBuf& in) {
+ TUtf16String out;
+ PunycodeToWide(in, out);
+ return out;
+}
+
+// Encode a sequence of point-separated domain labels
+// into a sequence of corresponding punycode labels.
+// Labels containing non-ASCII characters are prefixed with ACE prefix ("xn--").
+// Limits maximal encoded domain label length to IDNA_LABEL_MAX_LENGTH (255 by default).
+// Throws TPunycodeError on failure.
+TString HostNameToPunycode(const TWtringBuf& unicodeHost);
+TUtf16String PunycodeToHostName(const TStringBuf& punycodeHost);
+
+// Robust versions: on failure return original input, converted to/from UTF8
+TString ForceHostNameToPunycode(const TWtringBuf& unicodeHost);
+TUtf16String ForcePunycodeToHostName(const TStringBuf& punycodeHost);
+
+// True if @host looks like punycode domain label sequence,
+// containing at least one ACE-prefixed label.
+// Note that this function does not check all requied IDNA constraints
+// (max label length, empty non-root domains, etc.)
+bool CanBePunycodeHostName(const TStringBuf& host);
+
+class TPunycodeError: public yexception {
+};
diff --git a/library/cpp/unicode/punycode/punycode_ut.cpp b/library/cpp/unicode/punycode/punycode_ut.cpp
new file mode 100644
index 0000000000..97271cf0d8
--- /dev/null
+++ b/library/cpp/unicode/punycode/punycode_ut.cpp
@@ -0,0 +1,126 @@
+#include "punycode.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/charset/wide.h>
+
+namespace {
+ template<typename T1, typename T2>
+ inline bool HasSameBuffer(const T1& s1, const T2& s2) {
+ return s1.begin() == s2.begin();
+ }
+}
+
+Y_UNIT_TEST_SUITE(TPunycodeTest) {
+ static bool TestRaw(const TString& utf8, const TString& punycode) {
+ TUtf16String unicode = UTF8ToWide(utf8);
+ TString buf1;
+ TUtf16String buf2;
+ return HasSameBuffer(WideToPunycode(unicode, buf1), buf1) && buf1 == punycode && HasSameBuffer(PunycodeToWide(punycode, buf2), buf2) && buf2 == unicode && WideToPunycode(unicode) == punycode && PunycodeToWide(punycode) == unicode;
+ }
+
+ Y_UNIT_TEST(RawEncodeDecode) {
+ UNIT_ASSERT(TestRaw("", ""));
+ UNIT_ASSERT(TestRaw(" ", " -"));
+ UNIT_ASSERT(TestRaw("-", "--"));
+ UNIT_ASSERT(TestRaw("!@#$%", "!@#$%-"));
+ UNIT_ASSERT(TestRaw("xn-", "xn--"));
+ UNIT_ASSERT(TestRaw("xn--", "xn---"));
+ UNIT_ASSERT(TestRaw("abc", "abc-"));
+ UNIT_ASSERT(TestRaw("Latin123", "Latin123-"));
+
+ UNIT_ASSERT(TestRaw("München", "Mnchen-3ya"));
+ UNIT_ASSERT(TestRaw("bücher", "bcher-kva"));
+ UNIT_ASSERT(TestRaw("BüüchEr", "BchEr-kvaa"));
+
+ UNIT_ASSERT(TestRaw("президент", "d1abbgf6aiiy"));
+ UNIT_ASSERT(TestRaw("Президент", "r0a6bcbig1bsy"));
+ UNIT_ASSERT(TestRaw("ПРЕЗИДЕНТ", "g0abbgf6aiiy"));
+ UNIT_ASSERT(TestRaw("рф", "p1ai"));
+ UNIT_ASSERT(TestRaw("пример", "e1afmkfd"));
+
+ {
+ const wchar16 tmp[] = {0x82, 0x81, 0x80, 0};
+ UNIT_ASSERT(PunycodeToWide("abc") == tmp); // "abc" is still valid punycode
+ }
+
+ UNIT_ASSERT_EXCEPTION(PunycodeToWide(" "), TPunycodeError);
+ UNIT_ASSERT_EXCEPTION(PunycodeToWide("абвгд"), TPunycodeError);
+ UNIT_ASSERT_EXCEPTION(PunycodeToWide("-"), TPunycodeError);
+
+ {
+ TString longIn;
+ for (size_t i = 0; i < 1024; ++i)
+ longIn += "Qй";
+
+ TString longOut = "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ-lo11fbabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
+ UNIT_ASSERT(TestRaw(longIn, longOut));
+ }
+ }
+
+ static bool TestHostName(const TString& utf8, const TString& punycode, bool canBePunycode = false) {
+ TUtf16String unicode = UTF8ToWide(utf8);
+ TString buf1;
+ TUtf16String buf2;
+ //Cerr << "Testing " << utf8 << Endl;
+ return HostNameToPunycode(unicode) == punycode && HostNameToPunycode(UTF8ToWide(punycode)) == punycode // repeated encoding should give same result
+ && PunycodeToHostName(punycode) == unicode && CanBePunycodeHostName(punycode) == canBePunycode;
+ }
+
+ static bool TestForced(const TString& bad) {
+ return ForceHostNameToPunycode(UTF8ToWide(bad)) == bad && ForcePunycodeToHostName(bad) == UTF8ToWide(bad);
+ }
+
+ Y_UNIT_TEST(HostNameEncodeDecode) {
+ UNIT_ASSERT(TestHostName("президент.рф", "xn--d1abbgf6aiiy.xn--p1ai", true));
+ UNIT_ASSERT(TestHostName("яндекс.ru", "xn--d1acpjx3f.ru", true));
+ UNIT_ASSERT(TestHostName("пример", "xn--e1afmkfd", true));
+ UNIT_ASSERT(TestHostName("ascii.test", "ascii.test"));
+
+ UNIT_ASSERT(TestHostName("", ""));
+ UNIT_ASSERT(TestHostName(".", "."));
+ UNIT_ASSERT(TestHostName("a.", "a.")); // empty root domain is ok
+ UNIT_ASSERT(TestHostName("a.b.c.д.e.f", "a.b.c.xn--d1a.e.f", true));
+ UNIT_ASSERT(TestHostName("а.б.в.г.д", "xn--80a.xn--90a.xn--b1a.xn--c1a.xn--d1a", true));
+
+ UNIT_ASSERT(TestHostName("-", "-"));
+ UNIT_ASSERT(TestHostName("xn--", "xn--", true));
+ UNIT_ASSERT(TestHostName("xn--aaa.-", "xn--aaa.-", true));
+ UNIT_ASSERT(TestHostName("xn--xn--d1acpjx3f.xn--ru", "xn--xn--d1acpjx3f.xn--ru", true));
+
+ {
+ // non-ascii
+ TString bad = "президент.рф";
+ UNIT_ASSERT_EXCEPTION(PunycodeToHostName("президент.рф"), TPunycodeError);
+ UNIT_ASSERT(ForcePunycodeToHostName(bad) == UTF8ToWide(bad));
+ }
+ {
+ // too long domain label
+ TString bad(500, 'a');
+ UNIT_ASSERT_EXCEPTION(HostNameToPunycode(UTF8ToWide(bad)), TPunycodeError);
+ UNIT_ASSERT(TestForced(bad)); // but can decode it
+ }
+ {
+ // already has ACE prefix
+ TString bad("xn--яндекс.xn--рф");
+ UNIT_ASSERT_EXCEPTION(HostNameToPunycode(UTF8ToWide(bad)), TPunycodeError);
+ UNIT_ASSERT(TestForced(bad));
+ }
+ {
+ // empty non-root domain is not allowed (?)
+ TString bad(".яндекс.рф");
+ UNIT_ASSERT_EXCEPTION(HostNameToPunycode(UTF8ToWide(bad)), TPunycodeError);
+ UNIT_ASSERT(TestForced(bad));
+ }
+
+ UNIT_ASSERT(CanBePunycodeHostName("xn--"));
+ UNIT_ASSERT(CanBePunycodeHostName("yandex.xn--p1ai"));
+ UNIT_ASSERT(CanBePunycodeHostName("xn--d1acpjx3f.xn--p1ai"));
+ UNIT_ASSERT(CanBePunycodeHostName("a.b.c.d.xn--e"));
+ UNIT_ASSERT(CanBePunycodeHostName("xn--a.b.c.xn--d.e"));
+ UNIT_ASSERT(!CanBePunycodeHostName("yandex.ru")); // no xn--
+ UNIT_ASSERT(!CanBePunycodeHostName("яндекс.рф")); // non-ascii
+ UNIT_ASSERT(!CanBePunycodeHostName("яндекс.xn--p1ai")); // non-ascii
+ UNIT_ASSERT(!CanBePunycodeHostName(""));
+ UNIT_ASSERT(!CanBePunycodeHostName("http://xn--a.b")); // scheme prefix is not detected here
+ }
+}
diff --git a/library/cpp/unicode/punycode/ut/ya.make b/library/cpp/unicode/punycode/ut/ya.make
new file mode 100644
index 0000000000..74272102a8
--- /dev/null
+++ b/library/cpp/unicode/punycode/ut/ya.make
@@ -0,0 +1,13 @@
+UNITTEST_FOR(library/cpp/unicode/punycode)
+
+OWNER(
+ g:base
+ g:middle
+ g:upper
+)
+
+SRCS(
+ punycode_ut.cpp
+)
+
+END()
diff --git a/library/cpp/unicode/punycode/ya.make b/library/cpp/unicode/punycode/ya.make
new file mode 100644
index 0000000000..62b41b07b7
--- /dev/null
+++ b/library/cpp/unicode/punycode/ya.make
@@ -0,0 +1,17 @@
+LIBRARY()
+
+OWNER(
+ g:base
+ g:middle
+ g:upper
+)
+
+PEERDIR(
+ contrib/libs/libidn
+)
+
+SRCS(
+ punycode.cpp
+)
+
+END()
diff --git a/library/cpp/unicode/ya.make b/library/cpp/unicode/ya.make
new file mode 100644
index 0000000000..4fcd9caacc
--- /dev/null
+++ b/library/cpp/unicode/ya.make
@@ -0,0 +1,14 @@
+RECURSE(
+ folding
+ folding/ut
+ normalization
+ normalization/ut
+ punycode
+ punycode/ut
+ set
+ set/ut
+ utf8_char
+ utf8_char/ut
+ utf8_iter
+ utf8_iter/ut
+)
diff --git a/library/cpp/uri/assign.cpp b/library/cpp/uri/assign.cpp
new file mode 100644
index 0000000000..ea1955a9e9
--- /dev/null
+++ b/library/cpp/uri/assign.cpp
@@ -0,0 +1,426 @@
+#include "uri.h"
+#include "parse.h"
+
+#include <contrib/libs/libidn/idna.h>
+
+#include <library/cpp/charset/recyr.hh>
+#include <util/charset/wide.h>
+#include <util/memory/tempbuf.h>
+#include <util/string/cast.h>
+#include <util/system/maxlen.h>
+#include <util/system/yassert.h>
+#include <util/system/sys_alloc.h>
+
+namespace NUri {
+ TMallocPtr<char> TUri::IDNToAscii(const wchar32* idna) {
+ // XXX: don't use punycode_encode directly as it doesn't include
+ // proper stringprep and splitting on dot-equivalent characters
+ char* buf;
+ static_assert(sizeof(*idna) == sizeof(ui32), "fixme");
+ if (IDNA_SUCCESS != idna_to_ascii_4z((const uint32_t*)idna, &buf, 0))
+ buf = nullptr;
+ return buf;
+ }
+
+ TMallocPtr<char> TUri::IDNToAscii(const TStringBuf& host, ECharset enc) {
+ TTempBuf buf(sizeof(wchar32) * (1 + host.length()));
+ wchar32* wbuf = reinterpret_cast<wchar32*>(buf.Data());
+
+ const size_t written = NDetail::NBaseOps::Recode(host, wbuf, enc).length();
+ wbuf[written] = 0;
+
+ return IDNToAscii(wbuf);
+ }
+
+ TStringBuf TUri::HostToAscii(TStringBuf host, TMallocPtr<char>& buf, bool hasExtended, bool allowIDN, ECharset enc) {
+ TStringBuf outhost; // store the result here before returning it, to get RVO
+
+ size_t buflen = 0;
+
+ if (hasExtended && !allowIDN)
+ return outhost; // definitely can't convert
+
+ // charset-recode: RFC 3986, 3.2.2, requires percent-encoded non-ASCII
+ // chars in reg-name to be UTF-8 so convert to UTF-8 prior to decoding
+ const bool recoding = CODES_UTF8 != enc && hasExtended;
+ if (recoding) {
+ size_t nrd, nwr;
+ buflen = host.length() * 4;
+ buf.Reset(static_cast<char*>(y_allocate(buflen)));
+ if (RECODE_OK != Recode(enc, CODES_UTF8, host.data(), buf.Get(), host.length(), buflen, nrd, nwr))
+ return outhost;
+ host = TStringBuf(buf.Get(), nwr);
+ }
+
+ // percent-decode
+ if (0 == buflen) {
+ buflen = host.length();
+ buf.Reset(static_cast<char*>(y_allocate(buflen)));
+ }
+ // decoding shortens so writing over host in buf is OK
+ TMemoryWriteBuffer out(buf.Get(), buflen);
+ TEncoder decoder(out, FeatureDecodeANY | FeatureToLower);
+ const long outFlags = decoder.ReEncode(host);
+ hasExtended = 0 != (outFlags & FeatureEncodeExtendedASCII);
+
+ // check again
+ if (hasExtended && !allowIDN)
+ return outhost;
+
+ host = out.Str();
+
+ // convert to punycode if needed
+ if (!hasExtended) {
+ outhost = host;
+ return outhost;
+ }
+
+ TMallocPtr<char> puny;
+ try {
+ puny = IDNToAscii(host);
+ } catch (const yexception& /* exc */) {
+ }
+
+ if (!puny) {
+ // XXX: try user charset unless UTF8 or converted to it
+ if (CODES_UTF8 == enc || recoding)
+ return outhost;
+ try {
+ puny = IDNToAscii(host, enc);
+ } catch (const yexception& /* exc */) {
+ return outhost;
+ }
+ if (!puny)
+ return outhost;
+ }
+
+ buf = puny;
+ outhost = buf.Get();
+
+ return outhost;
+ }
+
+ TStringBuf TUri::HostToAscii(const TStringBuf& host, TMallocPtr<char>& buf, bool allowIDN, ECharset enc) {
+ // find what we have
+ long haveFlags = 0;
+ for (size_t i = 0; i != host.length(); ++i)
+ haveFlags |= TEncoder::GetFlags(host[i]).FeatFlags;
+
+ // interested in encoded characters or (if IDN is allowed) extended ascii
+ TStringBuf outhost;
+ const bool haveExtended = haveFlags & FeatureEncodeExtendedASCII;
+
+ if (!haveExtended || allowIDN) {
+ if (!haveExtended && 0 == (haveFlags & FeatureDecodeANY))
+ outhost = host;
+ else
+ outhost = HostToAscii(host, buf, haveExtended, allowIDN, enc);
+ }
+
+ return outhost;
+ }
+
+ static inline bool AppendField(TMemoryWriteBuffer& out, TField::EField fld, const TStringBuf& val, long flags) {
+ if (val.empty())
+ return false;
+ if (flags & TFeature::FeaturesAllEncoder)
+ TUri::ReEncodeField(out, val, fld, flags);
+ else
+ out << val;
+ return true;
+ }
+
+ TState::EParsed TUri::AssignImpl(const TParser& parser, TScheme::EKind defscheme) {
+ Clear();
+
+ TState::EParsed ret = parser.State;
+ if (ParsedBadFormat <= ret)
+ return ret;
+
+ const TSection& scheme = parser.Get(FieldScheme);
+ const TSchemeInfo& schemeInfo = SetSchemeImpl(parser.Scheme);
+
+ // set the scheme always if available
+ if (schemeInfo.Str.empty() && scheme.IsSet())
+ FldSet(FieldScheme, scheme.Get());
+
+ if (ParsedOK != ret)
+ return ret;
+
+ size_t buflen = 0;
+
+ // special processing for fields
+
+ const bool convertIDN = parser.Flags & FeatureConvertHostIDN;
+ long flags = parser.Flags.Allow;
+ if (convertIDN)
+ flags |= FeatureAllowHostIDN | FeatureCheckHost;
+
+ // process non-ASCII host for punycode
+
+ TMallocPtr<char> hostptr;
+ TStringBuf hostascii; // empty: use host field; non-empty: ascii
+ bool hostConverted = false; // hostascii is empty or the original
+ const TSection& host = parser.Get(FieldHost);
+ if (host.IsSet() && !FldIsSet(FieldHost)) {
+ const bool allowIDN = (flags & FeatureAllowHostIDN);
+ const TStringBuf hostbuf = host.Get();
+
+ // if we know we have and allow extended-ASCII chars, no need to check further
+ if (allowIDN && (host.GetFlagsAllPlaintext() & FeatureEncodeExtendedASCII))
+ hostascii = HostToAscii(hostbuf, hostptr, true, true, parser.Enc);
+ else
+ hostascii = HostToAscii(hostbuf, hostptr, allowIDN, parser.Enc);
+
+ if (hostascii.empty())
+ ret = ParsedBadHost; // exists but cannot be converted
+ else if (hostbuf.data() != hostascii.data()) {
+ hostConverted = true;
+ buflen += 1 + hostascii.length();
+ if (convertIDN)
+ FldMarkSet(FieldHost); // so that we don't process host below
+ }
+ }
+
+ // add unprocessed fields
+
+ for (int idx = 0; idx < FieldUrlMAX; ++idx) {
+ const EField fld = EField(idx);
+ const TSection& section = parser.Get(fld);
+ if (section.IsSet() && !FldIsSet(fld))
+ buflen += 1 + section.EncodedLen(); // includes null
+ }
+ if (0 == buflen) // no more sections set?
+ return ret;
+
+ // process #! fragments
+ // https://developers.google.com/webmasters/ajax-crawling/docs/specification
+
+ static const TStringBuf escFragPrefix(TStringBuf("_escaped_fragment_="));
+
+ bool encHashBangFrag = false;
+ TStringBuf qryBeforeEscapedFragment;
+ TStringBuf qryEscapedFragment;
+ do {
+ if (FldIsSet(FieldFrag) || FldIsSet(FieldQuery))
+ break;
+
+ const TSection& frag = parser.Get(FieldFrag);
+ if (frag.IsSet()) {
+ if (0 == (parser.Flags & FeatureHashBangToEscapedFragment))
+ break;
+ const TStringBuf fragbuf = frag.Get();
+ if (fragbuf.empty() || '!' != fragbuf[0])
+ break;
+ encHashBangFrag = true;
+ // '!' will make space for '&' or '\0' if needed
+ buflen += escFragPrefix.length();
+ buflen += 2 * fragbuf.length(); // we don't know how many will be encoded
+ } else {
+ const TSection& qry = parser.Get(FieldQuery);
+ if (!qry.IsSet())
+ break;
+ // FeatureHashBangToEscapedFragment has preference
+ if (FeatureEscapedToHashBangFragment != (parser.Flags & FeaturesEscapedFragment))
+ break;
+ qry.Get().RSplit('&', qryBeforeEscapedFragment, qryEscapedFragment);
+ if (!qryEscapedFragment.StartsWith(escFragPrefix)) {
+ qryEscapedFragment.Clear();
+ break;
+ }
+ qryEscapedFragment.Skip(escFragPrefix.length());
+ buflen += 2; // for '!' and '\0' in fragment
+ buflen -= escFragPrefix.length();
+ }
+ } while (false);
+
+ // now set all fields prior to validating
+
+ Alloc(buflen);
+
+ TMemoryWriteBuffer out(Buffer.data(), Buffer.size());
+ for (int idx = 0; idx < FieldUrlMAX; ++idx) {
+ const EField fld = EField(idx);
+
+ const TSection& section = parser.Get(fld);
+ if (!section.IsSet() || FldIsSet(fld))
+ continue;
+
+ if (FieldQuery == fld && encHashBangFrag)
+ continue;
+
+ if (FieldFrag == fld && qryEscapedFragment.IsInited())
+ continue;
+
+ char* beg = out.Buf();
+ TStringBuf val = section.Get();
+ long careFlags = section.GetFlagsEncode();
+
+ switch (fld) {
+ default:
+ break;
+
+ case FieldQuery:
+ if (qryEscapedFragment.IsInited()) {
+ const EField dstfld = FieldFrag; // that's where we will store
+ out << '!';
+ if (!qryEscapedFragment.empty())
+ ReEncodeToField(out, qryEscapedFragment, fld, FeatureDecodeANY | careFlags, dstfld, FeatureDecodeANY | parser.GetFieldFlags(dstfld));
+ FldSetNoDirty(dstfld, TStringBuf(beg, out.Buf()));
+ if (qryBeforeEscapedFragment.empty())
+ continue;
+ out << '\0';
+ beg = out.Buf();
+ val = qryBeforeEscapedFragment;
+ }
+ break;
+
+ case FieldFrag:
+ if (encHashBangFrag) {
+ const EField dstfld = FieldQuery; // that's where we will store
+ const TSection& qry = parser.Get(dstfld);
+ if (qry.IsSet())
+ if (AppendField(out, dstfld, qry.Get(), qry.GetFlagsEncode()))
+ out << '&';
+ out << escFragPrefix;
+ val.Skip(1); // skip '!'
+ ReEncodeToField(out, val, fld, careFlags, dstfld, parser.GetFieldFlags(dstfld));
+ FldSetNoDirty(dstfld, TStringBuf(beg, out.Buf()));
+ continue;
+ }
+ break;
+ }
+
+ AppendField(out, fld, val, careFlags);
+ char* end = out.Buf();
+
+ if (careFlags & FeaturePathOperation) {
+ if (!PathOperation(beg, end, PathOperationFlag(parser.Flags)))
+ return ParsedBadPath;
+
+ Y_ASSERT(beg >= out.Beg());
+ out.SetPos(end);
+ }
+
+ FldSetNoDirty(fld, TStringBuf(beg, end));
+
+ // special character case
+ const long checkChars = section.GetFlagsAllPlaintext() & FeaturesCheckSpecialChar;
+ if (0 != checkChars) { // has unencoded special chars: check permission
+ const long allowChars = parser.GetFieldFlags(fld) & checkChars;
+ if (checkChars != allowChars)
+ ret = ParsedBadFormat;
+ }
+
+ out << '\0';
+ }
+
+ if (hostConverted) {
+ char* beg = out.Buf();
+ out << hostascii;
+ char* end = out.Buf();
+ const EField fld = convertIDN ? FieldHost : FieldHostAscii;
+ FldSetNoDirty(fld, TStringBuf(beg, end));
+ out << '\0';
+ }
+
+ Buffer.Resize(out.Len());
+
+ if (GetScheme() == SchemeEmpty && SchemeEmpty != defscheme) {
+ if (SchemeUnknown == defscheme)
+ ret = ParsedBadScheme;
+ else
+ SetSchemeImpl(defscheme);
+ }
+
+ if (0 == (parser.Flags & FeatureAllowEmptyPath))
+ CheckMissingFields();
+
+ const TStringBuf& port = GetField(FieldPort);
+ if (!port.empty()) {
+ if (!TryFromString<ui16>(port, Port))
+ ret = ParsedBadPort;
+ }
+
+ if (ParsedOK != ret)
+ return ret;
+
+ // run validity checks now that all fields are set
+
+ // check the host for DNS compliance
+ do {
+ if (0 == (flags & FeatureCheckHost))
+ break;
+ if (hostascii.empty())
+ hostascii = GetField(FieldHost);
+ if (hostascii.empty())
+ break;
+ // IP literal
+ if ('[' == hostascii[0] && ']' == hostascii.back())
+ break;
+ ret = CheckHost(hostascii);
+ if (ParsedOK != ret)
+ return ret;
+ } while (false);
+
+ return ret;
+ }
+
+ TState::EParsed TUri::ParseImpl(const TStringBuf& url, const TParseFlags& flags, ui32 maxlen, TScheme::EKind defscheme, ECharset enc) {
+ Clear();
+
+ if (url.empty())
+ return ParsedEmpty;
+
+ if (maxlen > 0 && url.length() > maxlen)
+ return ParsedTooLong;
+
+ const TParser parser(flags, url, enc);
+
+ return AssignImpl(parser, defscheme);
+ }
+
+ TState::EParsed TUri::Parse(const TStringBuf& url, const TParseFlags& flags, const TStringBuf& url_base, ui32 maxlen, ECharset enc) {
+ const TParseFlags flags1 = flags.Exclude(FeatureNoRelPath);
+ TState::EParsed ret = ParseImpl(url, url_base.empty() ? flags : flags1, maxlen, SchemeEmpty, enc);
+ if (ParsedOK != ret)
+ return ret;
+
+ if (!url_base.empty() && !IsValidAbs()) {
+ TUri base;
+ ret = base.ParseImpl(url_base, flags, maxlen, SchemeEmpty, enc);
+ if (ParsedOK != ret)
+ return ret;
+ Merge(base, PathOperationFlag(flags));
+ }
+
+ Rewrite();
+ return ret;
+ }
+
+ TState::EParsed TUri::Parse(const TStringBuf& url, const TUri& base, const TParseFlags& flags, ui32 maxlen, ECharset enc) {
+ const TState::EParsed ret = ParseImpl(url, flags, maxlen, SchemeEmpty, enc);
+ if (ParsedOK != ret)
+ return ret;
+
+ if (!IsValidAbs())
+ Merge(base, PathOperationFlag(flags));
+
+ Rewrite();
+ return ret;
+ }
+
+ TState::EParsed TUri::ParseAbsUri(const TStringBuf& url, const TParseFlags& flags, ui32 maxlen, TScheme::EKind defscheme, ECharset enc) {
+ const TState::EParsed ret = ParseImpl(
+ url, flags | FeatureNoRelPath, maxlen, defscheme, enc);
+ if (ParsedOK != ret)
+ return ret;
+
+ if (IsNull(FlagHost))
+ return ParsedBadHost;
+
+ Rewrite();
+ return ParsedOK;
+ }
+
+}
diff --git a/library/cpp/uri/benchmark/main.cpp b/library/cpp/uri/benchmark/main.cpp
new file mode 100644
index 0000000000..d39704877e
--- /dev/null
+++ b/library/cpp/uri/benchmark/main.cpp
@@ -0,0 +1,46 @@
+#include <library/cpp/uri/uri.h>
+
+#include <library/cpp/testing/benchmark/bench.h>
+
+#include <util/generic/vector.h>
+
+const TString URLS[] = {
+ "http://www.TEST.Ru:80/InDex.html",
+ "www.ya.ru/index.html",
+ "https://workplace.z.yandex-team.ru/di#vertical=drive&datePreset=week",
+ "https://warden.z.yandex-team.ru/components/web/report?filter_type=action_items&filter_status=total&filter_period=review",
+ "https://meduza.io/news/2021/05/01/italiya-vozobnovila-vydachu-turisticheskih-viz-v-moskve",
+ "https://gcc.gnu.org/projects/cxx-status.html#cxx20",
+ "https://github.com/llvm/llvm-project/commits/main/libcxx",
+ "https://photos.google.com/share/AF1QipNi8VN2pw2Ya_xCV8eFgzEZmiXDy1-GwhXbqFtvXoH3HypF10as9puV8FdoVZpOZA?key=WkZjQTIxQTM5a01oZkNUYTE2ZllKTVJKZk1CMTR3",
+ "https://mag.auto.ru/article/ladasolaris/?from=mag_web_block&utm_campaign=ladasolaris&utm_content=populyarnoe&utm_source=mag_web_block&utm_medium=cpc",
+ "https://yabs.yandex.ru/count/WZ4ejI_zODW1FH40j1nmE7kaiN1MJWK0s08GWY0nuM6EO000000useqKG0H846344d30nU21pYI00GcG0VpCzQaucBW1mCNWWOR1co7e0QG2y0A-meRx0v03yCE0RzqD-0Jozzu1Y0Nozzu1a0Nozzu1m0Nvks_D2-U0-KK5Iga7StZ0vgZ8Ao2m1u20c0ou1-u9q0SIW870W822W07u2DoYy82d4W10oQeB4EBQlCbpU0002zaBbLJ1w0lozzu1y0i6w0oNm808WWuaCaOrC30oGaKjHaCoHIqqDpWoBJX1HZajCaD3HJGtDKH3Gp7Dbvo7cB_HWagW3i24FO0Gm-3DmA8G0w7W4e606EaIQREKnW19jq8oc1C8g1E2WkxBsSo3dXRW4_BttW6W5FBttW6e5FBttW7G5EUCwadO583Nge06w1IC0j0LWDUgW0RO5S6AzkoZZxpyO_2G5i41e1RGWVs31iaMWHUe5md05xGIs1V0X3sm68AikOG6q1WG-1ZKfU3zXERBdee1W1cG6G6W6Qe3i1cu6T8P4dbXOdDVSsLoTcLoBt8rCZGjCkWPWC83y1c0mWE16l__eqZnoGHLc1hyy8W2i1hotyIEmftqxKJr6W40000R02tR-6NBeHRAQn6iQSWtbmq2DFDwGK8a9Muu2wvTOhNWE4vj3Fy-LbbUXS4Y0NLWZWE9MX1ZSNyOanc8rS-k0u1LdAMo0O-fHvO33T0LBwYZBzcF7h0qb3q0~1",
+ "https://yandex.ru/pogoda/nowcast/?utm_campaign=alert&utm_content=alert_separate&utm_medium=web&utm_source=home&utm_term=nowcast&morda_geolocation=1",
+ "https://an.yandex.ru/count/WluejI_zOE02fHS052S_YplH_yoFzGK0u0CGWY0nncwAO000000uYgLImfs4aOKAW06Suha2Y07-gFqAa07-vu2bpu20W0AO0VxdWALFe07Ug07Uk076nFll8S010jW1w9_VcG7W0Soxo1te0Ue40Q02vAG1y0Aasfk_0SOA-0IzX9W1Y0MzX9W1a0Nav9y1e0MCiIwe1ShJ9h05ojCck0NkpoZ9qoOhae0mkgnJ5wa7cB8OEOwtEX-m1u20a2Iu1u05ibB92YPyFmDpJFK_D7ddf9Yo002blSLG6C7e2xs4c07m2mc83BIDthu1gGpzGrRLHHZfF-WCbmBW3OA0mC60288E93OtGqOmC4L4BJ4sDaCjD4P5H2r1EJX5BKKuCZCvGZX4DqGtgwI2XAENwwcOvUBgu_6jdH_P3u0Gz8sO7OWGpz-nX0e1eU0HoV740-WHhS3enS2ScyBwO3_lGEaI3kz-5M87zWKoc1C4g1Eli-_mek7ml1RW4-xFA8WKqRAuZvJoWDi8e1JkpoYe5EJadudj_uC6w1I40iWLhPEErFa4q1MEz9w41jWLmOhsxAEFlFnZyA0Mq87zWmR95j0Mj8tUlW615vWNWfsO8wWN2RWN0S0NjHBO5y24FUWN0PaOe1WBi1ZIlwc41hWO0j0O4FWOeQI_pOMKhhOPW1c96MWs1G000000a1a1e1cg0x0Pk1d_0T8P4dbXOdDVSsLoTcLoBt8rCZCjCkWPWC83y1c0mWE16l__fs_4tYo3a1g0W06O6l70j06m6hkouUoAwFByhm6u6W7r6W4000226nmnDZ4vDZWrC3OnBZasE30pBZWrDJSmBZOuDJSt9I1HX8PYb34CCgLmxEvDy50h8PoKR4c2QKHEe8YaRoCEXF5m_E1rNC99Bpm6wIRbNGAU6GiQ3qguwKm8cq7la7pmUZxo079vS26KW_bTaCPY9QnjKrUHau50oq6yQCyn5TW0kBtjBWG2fE3FRk2DVwuirPJ_lvLb3GlkDKAujdLv~1?stat-id=1",
+ "https://rasp.yandex.ru/?utm_source=yamain&utm_medium=geoblock&utm_campaign=main",
+ "https://dsp-rambler.ru/click?url=hs31lTJpNQdz5IfhdiQZitCij144sWuuLcC3jopSDRPYYlPZNuD1x6OEJg74u0nbP0J0oXWXw7awYsCTgG7Cr*koGqxBBhOnzB5aZ6aLfCVVGlIuP3L194y025VLJAsK04sZwSvJbxEYfnbOWKPgQHOf7c8Gqkope95-kr--aTxpsg18jiwVdEPBENe3F2Iahm3yL*3vvzt-t7Vq6bANhL3DiJglfLw2WVd4tAhoAepFV*QybPJFoGHbdOWGMTyzpWMxWPLKb7MRFQWj1K*58qPyfNkfyQ72vvzjviirTM57xng8Cxbi08-HzM5x7imDOYIY8EvXOqfU3Q0KWsyO1RC1yHHVinVxthuIb16zLjg2aoYFpz-OLiTYhlmk1vyK9t9fLz8*Oiez9i*7TqIwcWZyX5gUFuOOJ4sTWbeQLe6IQEShvKIj7v9yBZRLkRmdHLfrREuTNpBMBtRG80MIxwXyt6SjjFOhSKtK-yDA19Wawzgw9fNOy9DW0TDAehQkPUTz*5-htmszyUqJWk5ovqoyHV3acnOI2-klqMCMfU9w3*GOYS0CuNTrggGCQH376EaeQthtwiUcabSarBEocGEsW7n27kIsrtYh2-SZwPvKC1Ek3dg35nuEO-MWNPMmqJvAhBGXHF*EQkcB3eLUEluJmwTxqPRv00M4PNgdYsYsgKYPU6MMJTxbH7fA*Q2vA7WErGONTSzhSOeNLPP4vR9WalRvzllDB3XH4bNx6Pleb3ZfWmoYTNN0Lux3-VxOSjIvDDGzMirfOVPKZB4qVQWsP4WHCrRgsijW43cKGhcQ0dPORYO5v0xhzMjoZ0qDEsaiXBkfRXccnQ3QGaXk2PC1vu*Zlj0qgJfO5i8e66z4HEiMWRF4JH8ZsbZqrUzKXX-WpPQuVA0MOslhzq8m3KS3UIEurWCn80utY4AWCuHzGooJbb*PcHhYMqIBbLcJW76RK9HQjI8Bxiu4C9wECXeWIqeVuHzbmb7PGizIDVwg-g8I-zrBgd8OH3kWtC09YwSB-F9wOHrrcBG*Sv6fdnwubW1ndv0V1jsok2DhMT9IFBOoa-brtWYIdttkRs2J4m*Ai5IgVOagS2wyboiHKptd7aQ7j1YnJENZbFfs2nSwvPTvvSA8w-vCJHo-xEW6tPWaAOrVVRZscjNb4HovTUKBhxrCm8cZYw0ZahlRWGDpB0QkiI-xSv7YdYzoAQMvEOF8h*MKTn1Had8cI2FJ3WtcaT3siShD*APePK6dwqGsNJRz3lfbeX*hykpwK8kTumfS6z51bv06bjahc*fo1vjNt8ivt2BJPWqnGkYH9-8r76iBia7d1zKKnzfqk-mu3m9eP0kiKkoqMKaugV2muZlt5h4ps29ikmTIc-8vYtwHOdLDay7PUhTC4tKepBVRZh6nXrIa5POmkVNV7hVfeoMXqlid2B-2LM3CWCo*W2r23aefVN8mi3t-dnWNUlVgurAc*674C76Py8Qdr0*EJqmYjhrQw6jbm*nB3O-kd1aYqWXWC3Msg1a5r9sRu1WVLKzmwwzjPX6b44R5ULVhu1OqH6*O7hFIbN584lUhWM6g1nWFqhwhN3**Bam802sRvZjguTILo*UAH7WW1DRRG5MsTs-ZP3tOFMkQKWuJ3LRLDXtnkyN25S0LYEmH8R0vTstUmFwafeJSmm90Iuseu9DKArqrb1Wn2cZv2zgAEYy66U7kkBTQSC76WlwBJTVpoK6MUohrEll23wivbnhNaGzaSe6kWRq1ItpFkqv9gXkCAAAAuty8CgAAAAA",
+ "https://news.rambler.ru/moscow_city/46342947-pogoda-v-moskve-sinoptiki-poobeschali-moskvicham-silnyy-liven-blizhayshey-nochyu/?utm_source=head&utm_campaign=self_promo&utm_medium=news&utm_content=news",
+};
+
+Y_CPU_BENCHMARK(Parsing, iface) {
+ for (size_t i = 0; i < iface.Iterations(); ++i) {
+ for (auto&& url : URLS) {
+ NUri::TUri uri;
+ auto parseResult = uri.Parse(url, uri.FeaturesAll);
+ Y_DO_NOT_OPTIMIZE_AWAY(parseResult);
+ Y_VERIFY(parseResult == NUri::TState::ParsedOK, "cannot parse %s: %d", url.c_str(), static_cast<ui32>(parseResult));
+ }
+ }
+}
+
+Y_CPU_BENCHMARK(ParsingAndCopying, iface) {
+ for (size_t i = 0; i < iface.Iterations(); ++i) {
+ for (auto&& url : URLS) {
+ NUri::TUri uri;
+ auto parseResult = uri.Parse(url, uri.FeaturesAll);
+ Y_VERIFY(parseResult == NUri::TState::ParsedOK, "cannot parse %s: %d", url.c_str(), static_cast<ui32>(parseResult));
+ auto copy = uri;
+ Y_DO_NOT_OPTIMIZE_AWAY(copy);
+ }
+ }
+}
diff --git a/library/cpp/uri/benchmark/ya.make b/library/cpp/uri/benchmark/ya.make
new file mode 100644
index 0000000000..77ea238de7
--- /dev/null
+++ b/library/cpp/uri/benchmark/ya.make
@@ -0,0 +1,17 @@
+Y_BENCHMARK()
+
+OWNER(
+ svshevtsov
+ g:base
+)
+
+PEERDIR(
+ library/cpp/testing/benchmark
+ library/cpp/uri
+)
+
+SRCS(
+ main.cpp
+)
+
+END()
diff --git a/library/cpp/uri/common.cpp b/library/cpp/uri/common.cpp
new file mode 100644
index 0000000000..05af1e57d1
--- /dev/null
+++ b/library/cpp/uri/common.cpp
@@ -0,0 +1,115 @@
+#include "common.h"
+
+#include <util/generic/map.h>
+#include <util/generic/singleton.h>
+
+namespace NUri {
+ static_assert(TFeature::FeatureMAX <= sizeof(unsigned long) * 8, "expect TFeature::FeatureMAX <= sizeof(unsigned long) * 8");
+
+ const TSchemeInfo TSchemeInfo::Registry[] = {
+ TSchemeInfo(TScheme::SchemeEmpty, TStringBuf()), // scheme is empty and inited
+ TSchemeInfo(TScheme::SchemeHTTP, TStringBuf("http"), TField::FlagHost | TField::FlagPath, 80),
+ TSchemeInfo(TScheme::SchemeHTTPS, TStringBuf("https"), TField::FlagHost | TField::FlagPath, 443),
+ TSchemeInfo(TScheme::SchemeFTP, TStringBuf("ftp"), TField::FlagHost | TField::FlagPath, 20),
+ TSchemeInfo(TScheme::SchemeFILE, TStringBuf("file"), TField::FlagPath),
+ TSchemeInfo(TScheme::SchemeWS, TStringBuf("ws"), TField::FlagHost | TField::FlagPath, 80),
+ TSchemeInfo(TScheme::SchemeWSS, TStringBuf("wss"), TField::FlagHost | TField::FlagPath, 443),
+ // add above
+ TSchemeInfo(TScheme::SchemeUnknown, TStringBuf()) // scheme is empty and uninited
+ };
+
+ namespace {
+ struct TLessNoCase {
+ bool operator()(const TStringBuf& lt, const TStringBuf& rt) const {
+ return 0 > CompareNoCase(lt, rt);
+ }
+ };
+
+ class TSchemeInfoMap {
+ typedef TMap<TStringBuf, TScheme::EKind, TLessNoCase> TdMap;
+ TdMap Map_;
+
+ public:
+ TSchemeInfoMap() {
+ for (int i = TScheme::SchemeEmpty; i < TScheme::SchemeUnknown; ++i) {
+ const TSchemeInfo& info = TSchemeInfo::Get(TScheme::EKind(i));
+ Map_.insert(std::make_pair(info.Str, info.Kind));
+ }
+ }
+
+ TScheme::EKind Get(const TStringBuf& scheme) const {
+ const TdMap::const_iterator it = Map_.find(scheme);
+ return Map_.end() == it ? TScheme::SchemeUnknown : it->second;
+ }
+
+ static const TSchemeInfoMap& Instance() {
+ return *Singleton<TSchemeInfoMap>();
+ }
+ };
+
+ }
+
+ const TSchemeInfo& TSchemeInfo::Get(const TStringBuf& scheme) {
+ return Registry[TSchemeInfoMap::Instance().Get(scheme)];
+ }
+
+ const char* ParsedStateToString(const TState::EParsed& t) {
+ switch (t) {
+ case TState::ParsedOK:
+ return "ParsedOK";
+ case TState::ParsedEmpty:
+ return "ParsedEmpty";
+ case TState::ParsedRootless:
+ return "ParsedRootless";
+ case TState::ParsedBadFormat:
+ return "ParsedBadFormat";
+ case TState::ParsedBadPath:
+ return "ParsedBadPath";
+ case TState::ParsedTooLong:
+ return "ParsedTooLong";
+ case TState::ParsedBadPort:
+ return "ParsedBadPort";
+ case TState::ParsedBadAuth:
+ return "ParsedBadAuth";
+ case TState::ParsedBadScheme:
+ return "ParsedBadScheme";
+ case TState::ParsedBadHost:
+ return "ParsedBadHost";
+ default:
+ return "Parsed[Unknown]";
+ }
+ }
+
+ const char* FieldToString(const TField::EField& t) {
+ switch (t) {
+ case TField::FieldScheme:
+ return "scheme";
+ case TField::FieldUser:
+ return "username";
+ case TField::FieldPass:
+ return "password";
+ case TField::FieldHost:
+ return "host";
+ case TField::FieldHostAscii:
+ return "hostascii";
+ case TField::FieldPort:
+ return "port";
+ case TField::FieldPath:
+ return "path";
+ case TField::FieldQuery:
+ return "query";
+ case TField::FieldFrag:
+ return "fragment";
+ default:
+ return "Field[Unknown]";
+ }
+ }
+
+ const char* SchemeKindToString(const TScheme::EKind& t) {
+ const TSchemeInfo& info = TSchemeInfo::Get(t);
+ if (!info.Str.empty())
+ return info.Str.data();
+ return TScheme::SchemeEmpty == t ? "empty" : "unknown";
+ }
+
+}
diff --git a/library/cpp/uri/common.h b/library/cpp/uri/common.h
new file mode 100644
index 0000000000..8025357763
--- /dev/null
+++ b/library/cpp/uri/common.h
@@ -0,0 +1,511 @@
+#pragma once
+
+#include <util/stream/output.h>
+#include <util/system/compat.h>
+#include <util/generic/strbuf.h>
+
+namespace NUri {
+ namespace NEncode {
+ class TEncoder;
+ class TEncodeMapperBase;
+ struct TCharFlags;
+ }
+
+ namespace NParse {
+ class TRange;
+ }
+
+ class TParser;
+
+ struct TField {
+#define FIELD_NAME(f) Field##f
+#define FIELD_FLAG(f) Flag##f = 1U << FIELD_NAME(f)
+
+ enum EField {
+ FIELD_NAME(Scheme),
+ FIELD_NAME(User),
+ FIELD_NAME(Pass),
+ FIELD_NAME(Host),
+ FIELD_NAME(Port),
+ FIELD_NAME(Path),
+ FIELD_NAME(Query),
+ FIELD_NAME(Frag),
+
+ // add fields above
+ FieldUrlMAX,
+ // reset count so actual field offsets are not interrupted
+ FieldUrlLast = FieldUrlMAX - 1,
+ // add extra fields below
+
+ FIELD_NAME(HostAscii),
+
+ // add extra fields above
+ FieldAllMAX,
+ // add aliases below
+
+ FieldUsername = FieldUser,
+ FieldPassword = FieldPass,
+ FieldFragment = FieldFrag,
+ };
+
+ enum EFlags {
+ FIELD_FLAG(Scheme),
+ FIELD_FLAG(User),
+ FIELD_FLAG(Pass),
+ FIELD_FLAG(Host),
+ FIELD_FLAG(Port),
+ FIELD_FLAG(Path),
+ FIELD_FLAG(Query),
+ FIELD_FLAG(Frag),
+ FIELD_FLAG(UrlMAX),
+ FIELD_FLAG(HostAscii),
+ FIELD_FLAG(AllMAX),
+
+ FlagHostPort = FlagHost | FlagPort,
+ FlagAuth = FlagUser | FlagPass,
+ FlagFragment = FlagFrag,
+ FlagAction = FlagScheme | FlagHostPort | FlagPath,
+ FlagNoFrag = FlagAction | FlagQuery,
+ FlagUrlFields = FlagUrlMAX - 1,
+ FlagAll = FlagUrlFields, // obsolete, for backwards compatibility
+ FlagAllFields = FlagAllMAX - 1
+ };
+
+#undef FIELD_NAME
+#undef FIELD_FLAG
+ };
+
+ struct TState {
+ enum EParsed {
+ ParsedOK = 0,
+ ParsedEmpty = 1,
+ ParsedOpaque = 2,
+ ParsedRootless = ParsedOpaque,
+ ParsedBadFormat, // must follow all non-error states immediately
+ ParsedBadPath,
+ ParsedTooLong,
+ ParsedBadPort,
+ ParsedBadAuth,
+ ParsedBadScheme,
+ ParsedBadHost,
+
+ // add before this line
+ ParsedMAX
+ };
+ };
+
+ struct TScheme {
+ // don't forget to define a SchemeRegistry entry
+ enum EKind {
+ SchemeEmpty
+ // add schemes below this line
+ ,
+ SchemeHTTP,
+ SchemeHTTPS,
+ SchemeFTP,
+ SchemeFILE,
+ SchemeWS,
+ SchemeWSS
+ // add schemes above this line
+ ,
+ SchemeUnknown
+ };
+ };
+
+ class TFeature {
+ friend class NEncode::TEncoder;
+ friend class NEncode::TEncodeMapperBase;
+ friend struct NEncode::TCharFlags;
+ friend class TParser;
+ friend class NParse::TRange;
+
+#define FEATURE_NAME(f) _BitFeature##f
+#define FEATURE_FLAG_NAME(f) Feature##f
+#define FEATURE_FLAG(f) FEATURE_FLAG_NAME(f) = 1UL << FEATURE_NAME(f)
+
+ protected:
+ enum EBit {
+ //==============================
+ // Cases interpreted as errors:
+ //==============================
+
+ // allows authorization user/password in URL
+ FEATURE_NAME(AuthSupported),
+
+ // allows all known schemes in URL
+ FEATURE_NAME(SchemeKnown),
+
+ // allows all schemes, not only known
+ FEATURE_NAME(SchemeFlexible),
+
+ // allow opaque (RFC 2396) or rootless (RFC 3986) urls
+ FEATURE_NAME(AllowRootless),
+
+ //==============================
+ // Cases interpreted for processing (if required):
+ // (effects on result of Parse method)
+ //==============================
+
+ // path needs normalization
+ // (simplification of directory tree: /../, /./, etc.
+ FEATURE_NAME(PathOperation),
+
+ // don't force empty path to "/"
+ FEATURE_NAME(AllowEmptyPath),
+
+ // in scheme and host segments:
+ // change upper case letters onto lower case ones
+ FEATURE_NAME(ToLower),
+
+ // decode unreserved symbols
+ FEATURE_NAME(DecodeUnreserved),
+
+ // legacy: decode standard symbols which may be safe for some fields
+ FEATURE_NAME(DecodeStandardExtra),
+
+ // decode symbols allowed (not necessarily safe to decode) only for a given field
+ // (do not use directly, instead use FeatureDecodeSafe mask below)
+ FEATURE_NAME(DecodeFieldAllowed),
+
+ // handling of spaces
+ FEATURE_NAME(EncodeSpace),
+
+ // in query segment: change escaped space to '+'
+ FEATURE_NAME(EncodeSpaceAsPlus),
+
+ // escape all string 'markup' symbols
+ FEATURE_NAME(EncodeForSQL),
+
+ // encoding of extended ascii symbols (8-bit)
+ FEATURE_NAME(EncodeExtendedASCII),
+
+ // decoding of extended ascii symbols (8-bit)
+ FEATURE_NAME(DecodeExtendedASCII),
+
+ // encoding of extended delimiter set
+ FEATURE_NAME(EncodeExtendedDelim),
+
+ // decoding of extended delimiter set
+ FEATURE_NAME(DecodeExtendedDelim),
+
+ // control characters [0x00 .. 0x20)
+ FEATURE_NAME(EncodeCntrl),
+
+ // raw percent character
+ FEATURE_NAME(EncodePercent),
+
+ // hash fragments
+ // https://developers.google.com/webmasters/ajax-crawling/docs/specification
+ // move and encode #! fragments to the query
+ FEATURE_NAME(HashBangToEscapedFragment),
+ // move and decode _escaped_fragment_ to the fragment
+ FEATURE_NAME(EscapedToHashBangFragment),
+
+ // reject absolute paths started by "/../"
+ FEATURE_NAME(PathDenyRootParent),
+
+ // paths started by "/../" - ignore head
+ FEATURE_NAME(PathStripRootParent),
+
+ // tries to fix errors (in particular, in fragment)
+ FEATURE_NAME(TryToFix),
+
+ // check host for DNS compliance
+ FEATURE_NAME(CheckHost),
+
+ // allow IDN hosts
+ // host is converted to punycode and stored in FieldHostAscii
+ // @note host contains characters in the charset of the document
+ // and percent-encoded characters in UTF-8 (RFC 3986, 3.2.2)
+ // @note if host contains no extended-ASCII characters and after
+ // percent-decoding cannot be converted from UTF-8 to UCS-4,
+ // try to recode from the document charset (if not UTF-8)
+ FEATURE_NAME(AllowHostIDN),
+
+ // forces AllowHostIDN, but host is replaced with punycode
+ // forces CheckHost since this replacement is irreversible
+ FEATURE_NAME(ConvertHostIDN),
+
+ // robot interpreted network paths as BadFormat urls
+ FEATURE_NAME(DenyNetworkPath),
+
+ // robot interprets URLs without a host as BadFormat
+ FEATURE_NAME(RemoteOnly),
+
+ /* non-RFC use case:
+ * 1. do not allow relative-path-only URIs when they can conflict with
+ * "host/path" (that is, only "./path" or "../path" are allowed);
+ * 2. if neither scheme nor userinfo are present but port is, it must
+ * be non-empty, to avoid conflict with "scheme:/...";
+ * 3. if AllowRootless is not specified, rootless (or opaque) URIs are
+ * not recognized;
+ * 4. if AllowRootless is specified, disallow userinfo, preferring
+ * "scheme:pa@th" over "user:pass@host", and even "host:port" when
+ * host contains only scheme-legal characters.
+ */
+ FEATURE_NAME(NoRelPath),
+
+ // standard prefers that all hex escapes were using uppercase A-F
+ FEATURE_NAME(UpperEncoded),
+
+ // internal usage: decode all encoded symbols
+ FEATURE_NAME(DecodeANY),
+
+ // add before this line
+ _FeatureMAX
+ };
+
+ protected:
+ enum EPrivate : ui32 {
+ FEATURE_FLAG(DecodeANY),
+ FEATURE_FLAG(DecodeFieldAllowed),
+ FEATURE_FLAG(DecodeStandardExtra),
+ };
+
+ public:
+ enum EPublic : ui32 {
+ FeatureMAX = _FeatureMAX,
+ FEATURE_FLAG(AuthSupported),
+ FEATURE_FLAG(SchemeKnown),
+ FEATURE_FLAG(SchemeFlexible),
+ FEATURE_FLAG(AllowRootless),
+ FEATURE_FLAG_NAME(AllowOpaque) = FEATURE_FLAG_NAME(AllowRootless),
+ FEATURE_FLAG(PathOperation),
+ FEATURE_FLAG(AllowEmptyPath),
+ FEATURE_FLAG(ToLower),
+ FEATURE_FLAG(DecodeUnreserved),
+ FEATURE_FLAG(EncodeSpace),
+ FEATURE_FLAG(EncodeSpaceAsPlus),
+ FEATURE_FLAG(EncodeForSQL),
+ FEATURE_FLAG(EncodeExtendedASCII),
+ FEATURE_FLAG(DecodeExtendedASCII),
+ FEATURE_FLAG(EncodeExtendedDelim),
+ FEATURE_FLAG(DecodeExtendedDelim),
+ FEATURE_FLAG(EncodeCntrl),
+ FEATURE_FLAG(EncodePercent),
+ FEATURE_FLAG(HashBangToEscapedFragment),
+ FEATURE_FLAG(EscapedToHashBangFragment),
+ FEATURE_FLAG(PathDenyRootParent),
+ FEATURE_FLAG(PathStripRootParent),
+ FEATURE_FLAG(TryToFix),
+ FEATURE_FLAG(CheckHost),
+ FEATURE_FLAG(AllowHostIDN),
+ FEATURE_FLAG(ConvertHostIDN),
+ FEATURE_FLAG(DenyNetworkPath),
+ FEATURE_FLAG(RemoteOnly),
+ FEATURE_FLAG(NoRelPath),
+ FEATURE_FLAG_NAME(HierURI) = FEATURE_FLAG_NAME(NoRelPath),
+ FEATURE_FLAG(UpperEncoded),
+ };
+
+#undef FEATURE_NAME
+#undef FEATURE_FLAG
+
+ public:
+ //==============================
+ enum ESets {
+ // these are guaranteed and will change buffer size
+
+ FeatureDecodeStandard = 0 | FeatureDecodeUnreserved | FeatureDecodeStandardExtra,
+
+ FeaturesDecodeExtended = 0 | FeatureDecodeExtendedASCII | FeatureDecodeExtendedDelim,
+
+ FeaturesDecode = 0 | FeatureDecodeUnreserved | FeatureDecodeStandard | FeaturesDecodeExtended,
+
+ FeaturesEncodeExtended = 0 | FeatureEncodeExtendedASCII | FeatureEncodeExtendedDelim,
+
+ FeaturesEncode = 0 | FeatureEncodeForSQL | FeatureEncodeSpace | FeatureEncodeCntrl | FeatureEncodePercent | FeaturesEncodeExtended,
+
+ // these are not guaranteed to apply to a given field
+
+ FeatureDecodeAllowed = 0 | FeatureDecodeUnreserved | FeatureDecodeFieldAllowed,
+
+ FeaturesMaybeDecode = 0 | FeaturesDecode | FeatureDecodeAllowed,
+
+ FeaturesMaybeEncode = 0 | FeaturesEncode,
+
+ FeaturesEncodeDecode = 0 | FeaturesMaybeEncode | FeaturesMaybeDecode,
+
+ FeaturesAllEncoder = 0 | FeaturesEncodeDecode | FeatureDecodeANY | FeatureToLower | FeatureUpperEncoded | FeatureEncodeSpaceAsPlus,
+
+ //==============================
+ FeaturesNormalizeSet = 0 | FeaturePathOperation | FeatureToLower | FeatureDecodeAllowed | FeatureEncodeSpaceAsPlus | FeatureEncodeForSQL | FeaturePathStripRootParent | FeatureTryToFix | FeatureUpperEncoded,
+
+ FeaturesDefault = 0 // it reproduces old parsedURL
+ | FeaturePathOperation | FeaturePathDenyRootParent | FeatureCheckHost,
+
+ // essentially allows all valid RFC urls and keeps them as-is
+ FeaturesBare = 0 | FeatureAuthSupported | FeatureSchemeFlexible | FeatureAllowEmptyPath,
+
+ FeaturesAll = 0 | FeatureAuthSupported | FeatureSchemeFlexible | FeatureCheckHost | FeaturesNormalizeSet,
+
+ // Deprecated, use FeaturesRecommended
+ FeaturesRobotOld = 0
+ // http://tools.ietf.org/html/rfc3986#section-6.2.2
+ | FeatureToLower // 6.2.2.1
+ | FeatureUpperEncoded // 6.2.2.1
+ | FeatureDecodeUnreserved // 6.2.2.2
+ | FeaturePathOperation // 6.2.2.3
+ | FeaturePathDenyRootParent | FeatureSchemeKnown | FeatureConvertHostIDN | FeatureRemoteOnly | FeatureHashBangToEscapedFragment | FeatureCheckHost,
+
+ // these are mutually exclusive
+ FeaturesPath = 0 | FeaturePathDenyRootParent | FeaturePathStripRootParent,
+
+ FeaturesEscapedFragment = 0 | FeatureEscapedToHashBangFragment | FeatureHashBangToEscapedFragment,
+
+ FeaturesCheckSpecialChar = 0 | FeatureEncodeSpace | FeatureEncodeCntrl | FeatureEncodePercent,
+
+ FeaturesEncodePChar = 0 | FeatureUpperEncoded | FeaturesEncodeDecode | FeaturesCheckSpecialChar,
+
+ // http://wiki.yandex-team.ru/robot/newDesign/dups/normolization
+ FeaturesRecommended = 0 | FeatureSchemeKnown | FeatureRemoteOnly | FeatureToLower | FeatureCheckHost | FeatureConvertHostIDN | FeatureHashBangToEscapedFragment | FeatureEncodeSpace | FeatureEncodeCntrl | FeatureEncodeExtendedASCII | FeatureUpperEncoded | FeatureDecodeUnreserved | FeaturePathOperation | FeaturePathStripRootParent,
+
+ FeaturesRobot = FeaturesRecommended
+ };
+ };
+
+ static inline int strnicmp(const char* lt, const char* rt, size_t len) {
+ return lt == rt ? 0 : ::strnicmp(lt, rt, len);
+ }
+
+ static inline int CompareNoCasePrefix(const TStringBuf& lt, const TStringBuf& rt) {
+ return strnicmp(lt.data(), rt.data(), rt.length());
+ }
+
+ static inline bool EqualNoCase(const TStringBuf& lt, const TStringBuf& rt) {
+ return lt.length() == rt.length() && 0 == CompareNoCasePrefix(lt, rt);
+ }
+
+ static inline int CompareNoCase(const TStringBuf& lt, const TStringBuf& rt) {
+ if (lt.length() == rt.length())
+ return CompareNoCasePrefix(lt, rt);
+ return lt.length() < rt.length() ? -1 : 1;
+ }
+
+ class TSchemeInfo {
+ public:
+ const TScheme::EKind Kind;
+ const ui16 Port;
+ const TStringBuf Str;
+ const ui32 FldReq;
+ TSchemeInfo(TScheme::EKind kind, TStringBuf str, ui32 fldReq = 0, ui16 port = 0)
+ : Kind(kind)
+ , Port(port)
+ , Str(str)
+ , FldReq(fldReq)
+ {
+ }
+ bool Matches(const TStringBuf& scheme) const {
+ return EqualNoCase(scheme, Str);
+ }
+
+ public:
+ static const TSchemeInfo& Get(const TStringBuf& scheme);
+ static const TSchemeInfo& Get(TScheme::EKind scheme) {
+ return Registry[scheme];
+ }
+ static TScheme::EKind GetKind(const TStringBuf& scheme) {
+ return Get(scheme).Kind;
+ }
+ static TStringBuf GetCanon(TScheme::EKind scheme) {
+ return Get(scheme).Str;
+ }
+ static ui16 GetDefaultPort(TScheme::EKind scheme) {
+ return Get(scheme).Port;
+ }
+
+ private:
+ static const TSchemeInfo Registry[];
+ };
+
+ struct TParseFlags {
+ const ui64 Allow;
+ const ui64 Extra;
+ TParseFlags(ui64 allow = 0, ui64 extra = 0)
+ : Allow(allow)
+ , Extra(extra)
+ {
+ }
+ ui64 operator&(const TParseFlags& flags) const {
+ return (Allow & flags.Allow) | (Extra & flags.Extra);
+ }
+ ui64 operator&(ui64 flags) const {
+ return (Allow & flags);
+ }
+ TParseFlags operator|(const TParseFlags& flags) const {
+ return TParseFlags(Allow | flags.Allow, Extra | flags.Extra);
+ }
+ TParseFlags Exclude(ui64 flags) const {
+ return TParseFlags(Allow & ~flags, Extra & ~flags);
+ }
+ };
+
+#define FEATURE_NAME(f) _BitFeature##f
+#define FEATURE_FLAG_NAME(f) Feature##f
+#define FEATURE_FLAG(f) FEATURE_FLAG_NAME(f) = 1UL << FEATURE_NAME(f)
+
+ struct TQueryArg {
+ TStringBuf Name;
+ TStringBuf Value;
+
+ private:
+ enum EBit {
+ FEATURE_NAME(Filter),
+ FEATURE_NAME(SortByName),
+ FEATURE_NAME(RemoveEmptyQuery),
+ FEATURE_NAME(RewriteDirty),
+ _FeatureMAX
+ };
+
+ public:
+ enum EPublic : ui32 {
+ FeatureMAX = _FeatureMAX,
+ FEATURE_FLAG(Filter),
+ FEATURE_FLAG(SortByName),
+ FEATURE_FLAG(RemoveEmptyQuery),
+ FEATURE_FLAG(RewriteDirty),
+ };
+
+ enum EProcessed {
+ // OK and clean.
+ ProcessedOK = 0,
+
+ // OK, but query stored in internal buffer and TUri::Rewrite() is required.
+ ProcessedDirty = 1,
+
+ ProcessedMalformed = 2,
+ ProcessedTooMany = 3,
+ };
+ };
+
+ typedef bool (*TQueryArgFilter)(const TQueryArg& arg, void* filterData);
+
+#undef FEATURE_NAME
+#undef FEATURE_FLAG_NAME
+#undef FEATURE_FLAG
+
+ const char* FieldToString(const TField::EField& t);
+ const char* ParsedStateToString(const TState::EParsed& t);
+ const char* SchemeKindToString(const TScheme::EKind& t);
+
+}
+
+Y_DECLARE_OUT_SPEC(inline, NUri::TField::EField, out, t) {
+ out << NUri::FieldToString(t);
+}
+
+Y_DECLARE_OUT_SPEC(inline, NUri::TScheme::EKind, out, t) {
+ out << NUri::SchemeKindToString(t);
+}
+
+Y_DECLARE_OUT_SPEC(inline, NUri::TState::EParsed, out, t) {
+ out << NUri::ParsedStateToString(t);
+}
+
+static inline ui16 DefaultPort(NUri::TScheme::EKind scheme) {
+ return NUri::TSchemeInfo::GetDefaultPort(scheme);
+}
+
+static inline NUri::TScheme::EKind SchemeKind(const TStringBuf& scheme) {
+ return NUri::TSchemeInfo::GetKind(scheme);
+}
diff --git a/library/cpp/uri/encode.cpp b/library/cpp/uri/encode.cpp
new file mode 100644
index 0000000000..9eab1535bc
--- /dev/null
+++ b/library/cpp/uri/encode.cpp
@@ -0,0 +1,221 @@
+#include "encode.h"
+
+#include <util/string/cast.h>
+#include <util/generic/singleton.h>
+
+namespace NUri {
+ namespace NEncode {
+// http://tools.ietf.org/html/rfc3986#section-2.2
+#define GENDELIMS0 ":/?#[]@"
+#define SUBDELIMS0 "!$&'()*+,;="
+// http://tools.ietf.org/html/rfc3986#section-2.3
+#define UNRESERVED "-._~"
+
+// now find subsets which can sometimes be decoded
+
+// remove '#' which can't ever be decoded
+// don't mark anything allowed for pass (pass is completely encoded)
+// safe in path, qry, frag
+#define GENDELIMS1 ":@"
+// allowed in qry, frag
+#define GENDELIMS2 "/?"
+
+// qry-unsafe chars
+#define SUBDELIMS1 "&+=;"
+// rest allowed in qry, frag
+#define SUBDELIMS2 "!$'()*,"
+
+ const TEncoder::TGrammar& TEncoder::Grammar() {
+ return *Singleton<TEncoder::TGrammar>();
+ }
+
+ // initialize the grammar map
+ TEncoder::TGrammar::TGrammar() {
+ // first set up unreserved characters safe in any field
+ const ui64 featUnres = TFeature::FeatureDecodeUnreserved;
+ AddRng('0', '9', ECFDigit, featUnres);
+ AddRng('A', 'Z', ECFUpper, featUnres | TFeature::FeatureToLower);
+ AddRng('a', 'z', ECFLower, featUnres);
+ Add(UNRESERVED, ECFUnres, featUnres);
+
+ // XXX: standard "safe" set used previously "-_.!~*();/:@$,", with comment:
+ // alnum + reserved + mark + ( '[', ']') - ('=' '+' '&' '\'' '"' '\\' '?')
+ Add("!*();/:@$,", ECFStdrd, TFeature::FeatureDecodeStandardExtra);
+
+ // now field-specific subsets of reserved characters (gen-delims + sub-delims)
+ const ui64 featSafe = TFeature::FeatureDecodeFieldAllowed;
+
+ Add(GENDELIMS1, 0, featSafe, TField::FlagPath | TField::FlagQuery | TField::FlagFrag);
+ Add(GENDELIMS2, 0, featSafe, TField::FlagQuery | TField::FlagFrag);
+
+ Add(SUBDELIMS1, 0, featSafe, TField::FlagUser);
+ Add(SUBDELIMS2, 0, featSafe, TField::FlagUser | TField::FlagQuery | TField::FlagFrag);
+
+ // control chars
+ AddRng(0x00, 0x20, TFeature::FeatureEncodeCntrl);
+ Add(0x7f, TFeature::FeatureEncodeCntrl);
+
+ // '%' starts a percent-encoded sequence
+ Add('%', TFeature::FeatureDecodeANY | TFeature::FeatureEncodePercent);
+
+ // extended ASCII
+ AddRng(128, 255, TFeature::FeatureEncodeExtendedASCII | TFeature::FeatureDecodeExtendedASCII);
+
+ // extended delims
+ Add("\"<>[\\]^`{|}", TFeature::FeatureEncodeExtendedDelim | TFeature::FeatureDecodeExtendedDelim);
+
+ // add characters with other features
+ Add(' ', TFeature::FeatureEncodeSpace | TFeature::FeatureEncodeSpaceAsPlus);
+ Add("'\"\\", TFeature::FeatureEncodeForSQL);
+
+ GetMutable(':').EncodeFld |= TField::FlagUser;
+ GetMutable('?').EncodeFld |= TField::FlagPath;
+ GetMutable('#').EncodeFld |= TField::FlagPath | TField::FlagQuery;
+ GetMutable('&').EncodeFld |= TField::FlagQuery;
+ GetMutable('+').EncodeFld |= TField::FlagQuery;
+ }
+
+ // should we decode an encoded character
+ bool TCharFlags::IsDecode(ui32 fldmask, ui64 flags) const {
+ const ui64 myflags = flags & FeatFlags;
+ if (myflags & TFeature::FeaturesEncode)
+ return false;
+ if (myflags & TFeature::FeaturesDecode)
+ return true;
+ return (fldmask & DecodeFld) && (flags & TFeature::FeatureDecodeFieldAllowed);
+ }
+
+ const int dD = 'a' - 'A';
+
+ int TEncodeMapper::EncodeSym(unsigned char& ch) const {
+ const TCharFlags& chflags = TEncoder::GetFlags(ch);
+ const ui64 flags = Flags & chflags.FeatFlags;
+
+ if (flags & TFeature::FeatureToLower)
+ ch += dD;
+
+ if (Q_DecodeAny)
+ return -1;
+
+ if (flags & TFeature::FeaturesEncode)
+ return 1;
+
+ if (' ' == ch) {
+ if (Q_EncodeSpcAsPlus)
+ ch = '+';
+ return 0;
+ }
+
+ return 0;
+ }
+
+ int TEncodeMapper::EncodeHex(unsigned char& ch) const {
+ const TCharFlags& chflags = TEncoder::GetFlags(ch);
+ const ui64 flags = Flags & chflags.FeatFlags;
+
+ if (flags & TFeature::FeatureToLower)
+ ch += dD;
+
+ if (Q_DecodeAny)
+ return -1;
+
+ if (chflags.IsDecode(FldMask, Flags))
+ return 0;
+
+ if (' ' == ch) {
+ if (!Q_EncodeSpcAsPlus)
+ return 1;
+ ch = '+';
+ return 0;
+ }
+
+ return 1;
+ }
+
+ bool TEncodeToMapper::Encode(unsigned char ch) const {
+ if (Q_DecodeAny)
+ return false;
+
+ const TCharFlags& chflags = TEncoder::GetFlags(ch);
+ if (FldMask & chflags.EncodeFld)
+ return true;
+
+ const ui64 flags = Flags & chflags.FeatFlags;
+ return (flags & TFeature::FeaturesEncode);
+ }
+
+ TEncoder::TEncoder(IOutputStream& out, const TEncodeMapper& fldsrc, const TEncodeToMapper& flddst)
+ : Out(out)
+ , FldSrc(fldsrc)
+ , FldDst(flddst)
+ , OutFlags(0)
+ , HexValue(0)
+ {
+ }
+
+ IOutputStream& TEncoder::Hex(IOutputStream& out, unsigned char val) {
+ static const char sHexCodes[] = "0123456789ABCDEF";
+ return out << sHexCodes[(val >> 4) & 0xF] << sHexCodes[val & 0xF];
+ }
+
+ IOutputStream& TEncoder::EncodeAll(IOutputStream& out, const TStringBuf& val) {
+ for (size_t i = 0; i != val.length(); ++i)
+ Encode(out, val[i]);
+ return out;
+ }
+
+ IOutputStream& TEncoder::EncodeNotAlnum(IOutputStream& out, const TStringBuf& val) {
+ for (size_t i = 0; i != val.length(); ++i) {
+ const char c = val[i];
+ if (IsAlnum(c))
+ out << c;
+ else
+ Encode(out, c);
+ }
+ return out;
+ }
+
+ IOutputStream& TEncoder::EncodeField(
+ IOutputStream& out, const TStringBuf& val, TField::EField fld) {
+ const ui32 fldmask = ui32(1) << fld;
+ for (size_t i = 0; i != val.length(); ++i) {
+ const char ch = val[i];
+ if (GetFlags(ch).IsAllowed(fldmask))
+ out << ch;
+ else
+ Encode(out, ch);
+ }
+ return out;
+ }
+
+ IOutputStream& TEncoder::EncodeField(
+ IOutputStream& out, const TStringBuf& val, TField::EField fld, ui64 flags) {
+ const ui32 fldmask = ui32(1) << fld;
+ for (size_t i = 0; i != val.length(); ++i) {
+ const char ch = val[i];
+ if (GetFlags(ch).IsDecode(fldmask, flags))
+ out << ch;
+ else
+ Encode(out, ch);
+ }
+ return out;
+ }
+
+ void TEncoder::Do(unsigned char ch, int res) {
+ OutFlags |= GetFlags(ch).FeatFlags;
+
+ bool escapepct = false;
+ if (0 < res) // definitely encode
+ escapepct = FldDst.Enabled();
+ else if (0 != res || !FldDst.Enabled() || !FldDst.Encode(ch)) {
+ Out << ch;
+ return;
+ }
+
+ Out << '%';
+ if (escapepct)
+ Out.Write("25", 2); // '%'
+ Hex(Out, ch);
+ }
+ }
+}
diff --git a/library/cpp/uri/encode.h b/library/cpp/uri/encode.h
new file mode 100644
index 0000000000..a9ece15427
--- /dev/null
+++ b/library/cpp/uri/encode.h
@@ -0,0 +1,282 @@
+#pragma once
+
+#include "common.h"
+
+#include <util/stream/output.h>
+
+namespace NUri {
+ namespace NEncode {
+#define CHAR_TYPE_NAME(f) _ECT##f
+#define CHAR_TYPE_FLAG(f) ECF##f = 1u << CHAR_TYPE_NAME(f)
+
+ enum ECharType {
+ CHAR_TYPE_NAME(Digit),
+ CHAR_TYPE_NAME(Lower),
+ CHAR_TYPE_NAME(Upper),
+ CHAR_TYPE_NAME(Unres),
+ CHAR_TYPE_NAME(Stdrd),
+ };
+
+ enum ECharFlag {
+ CHAR_TYPE_FLAG(Digit),
+ CHAR_TYPE_FLAG(Lower),
+ CHAR_TYPE_FLAG(Upper),
+ CHAR_TYPE_FLAG(Unres),
+ CHAR_TYPE_FLAG(Stdrd),
+ // compound group flags
+ ECGAlpha = ECFUpper | ECFLower,
+ ECGAlnum = ECGAlpha | ECFDigit,
+ ECGUnres = ECGAlnum | ECFUnres,
+ ECGStdrd = ECGUnres | ECFStdrd,
+ };
+
+#undef CHAR_TYPE_NAME
+#undef CHAR_TYPE_FLAG
+
+ struct TCharFlags {
+ ui32 TypeFlags;
+ ui64 FeatFlags;
+ ui32 DecodeFld; // decode if FeatureDecodeFieldAllowed
+ ui32 EncodeFld; // encode if shouldn't be treated as delimiter
+ TCharFlags(ui64 feat = 0)
+ : TypeFlags(0)
+ , FeatFlags(feat)
+ , DecodeFld(0)
+ , EncodeFld(0)
+ {
+ }
+ TCharFlags(ui32 type, ui64 feat, ui32 decmask = 0, ui32 encmask = 0)
+ : TypeFlags(type)
+ , FeatFlags(feat)
+ , DecodeFld(decmask)
+ , EncodeFld(encmask)
+ {
+ }
+ TCharFlags& Add(const TCharFlags& val) {
+ TypeFlags |= val.TypeFlags;
+ FeatFlags |= val.FeatFlags;
+ DecodeFld |= val.DecodeFld;
+ EncodeFld |= val.EncodeFld;
+ return *this;
+ }
+ bool IsAllowed(ui32 fldmask) const {
+ return (TypeFlags & ECGUnres) || (DecodeFld & ~EncodeFld & fldmask);
+ }
+ // should we decode an encoded character
+ bool IsDecode(ui32 fldmask, ui64 flags) const;
+ };
+
+ class TEncodeMapperBase {
+ protected:
+ TEncodeMapperBase()
+ : Flags(0)
+ , FldMask(0)
+ , Q_DecodeAny(false)
+ {
+ }
+ TEncodeMapperBase(ui64 flags, TField::EField fld)
+ : Flags(flags)
+ , FldMask(1u << fld)
+ , Q_DecodeAny(flags & TFeature::FeatureDecodeANY)
+ {
+ }
+
+ protected:
+ const ui64 Flags;
+ const ui32 FldMask;
+ const bool Q_DecodeAny; // this is a special option for username/password
+ };
+
+ // maps a sym or hex character and indicates whether it has to be encoded
+ class TEncodeMapper
+ : public TEncodeMapperBase {
+ public:
+ TEncodeMapper(ui64 flags, TField::EField fld = TField::FieldAllMAX)
+ : TEncodeMapperBase(flags, fld)
+ , Q_EncodeSpcAsPlus(flags & TFeature::FeatureEncodeSpaceAsPlus)
+ {
+ }
+ // negative=sym, positive=hex, zero=maybesym
+ int EncodeSym(unsigned char&) const;
+ int EncodeHex(unsigned char&) const;
+
+ protected:
+ const bool Q_EncodeSpcAsPlus;
+ };
+
+ // indicates whether a character has to be encoded when copying to a field
+ class TEncodeToMapper
+ : public TEncodeMapperBase {
+ public:
+ TEncodeToMapper()
+ : TEncodeMapperBase()
+ {
+ }
+ TEncodeToMapper(ui64 flags, TField::EField fld = TField::FieldAllMAX)
+ : TEncodeMapperBase(flags, fld)
+ {
+ }
+ bool Enabled() const {
+ return 0 != FldMask;
+ }
+ bool Encode(unsigned char) const;
+ };
+
+ class TEncoder {
+ public:
+ TEncoder(IOutputStream& out, const TEncodeMapper& fldsrc, const TEncodeToMapper& flddst = TEncodeToMapper());
+
+ ui64 ReEncode(const TStringBuf& url);
+ ui64 ReEncode(const char* str, size_t len) {
+ return ReEncode(TStringBuf(str, len));
+ }
+
+ protected:
+ static bool IsType(unsigned char c, ui64 flags) {
+ return GetFlags(c).TypeFlags & flags;
+ }
+
+ public:
+ static bool IsDigit(unsigned char c) {
+ return IsType(c, ECFDigit);
+ }
+ static bool IsUpper(unsigned char c) {
+ return IsType(c, ECFUpper);
+ }
+ static bool IsLower(unsigned char c) {
+ return IsType(c, ECFLower);
+ }
+ static bool IsAlpha(unsigned char c) {
+ return IsType(c, ECGAlpha);
+ }
+ static bool IsAlnum(unsigned char c) {
+ return IsType(c, ECGAlnum);
+ }
+ static bool IsUnres(unsigned char c) {
+ return IsType(c, ECGUnres);
+ }
+ static const TCharFlags& GetFlags(unsigned char c) {
+ return Grammar().Get(c);
+ }
+
+ public:
+ // process an encoded string, decoding safe chars and encoding unsafe
+ static IOutputStream& ReEncode(IOutputStream& out, const TStringBuf& val, const TEncodeMapper& srcfld) {
+ TEncoder(out, srcfld).ReEncode(val);
+ return out;
+ }
+ static IOutputStream& ReEncodeTo(IOutputStream& out, const TStringBuf& val, const TEncodeMapper& srcfld, const TEncodeToMapper& dstfld) {
+ TEncoder(out, srcfld, dstfld).ReEncode(val);
+ return out;
+ }
+
+ // see also UrlUnescape() from string/quote.h
+ static IOutputStream& Decode(
+ IOutputStream& out, const TStringBuf& val, ui64 flags) {
+ return ReEncode(out, val, flags | TFeature::FeatureDecodeANY);
+ }
+
+ public:
+ // process a raw string or char, encode as needed
+ static IOutputStream& Hex(IOutputStream& out, unsigned char val);
+ static IOutputStream& Encode(IOutputStream& out, unsigned char val) {
+ out << '%';
+ return Hex(out, val);
+ }
+ static IOutputStream& EncodeAll(IOutputStream& out, const TStringBuf& val);
+ static IOutputStream& EncodeNotAlnum(IOutputStream& out, const TStringBuf& val);
+
+ static IOutputStream& EncodeField(IOutputStream& out, const TStringBuf& val, TField::EField fld);
+ static IOutputStream& EncodeField(IOutputStream& out, const TStringBuf& val, TField::EField fld, ui64 flags);
+
+ static IOutputStream& Encode(IOutputStream& out, const TStringBuf& val) {
+ return EncodeField(out, val, TField::FieldAllMAX);
+ }
+
+ static IOutputStream& Encode(IOutputStream& out, const TStringBuf& val, ui64 flags) {
+ return EncodeField(out, val, TField::FieldAllMAX, flags);
+ }
+
+ public:
+ class TGrammar {
+ TCharFlags Map_[256];
+
+ public:
+ TGrammar();
+ const TCharFlags& Get(unsigned char ch) const {
+ return Map_[ch];
+ }
+
+ TCharFlags& GetMutable(unsigned char ch) {
+ return Map_[ch];
+ }
+ TCharFlags& Add(unsigned char ch, const TCharFlags& val) {
+ return GetMutable(ch).Add(val);
+ }
+
+ void AddRng(unsigned char lo, unsigned char hi, const TCharFlags& val) {
+ for (unsigned i = lo; i <= hi; ++i)
+ Add(i, val);
+ }
+ void AddRng(unsigned char lo, unsigned char hi, ui32 type, ui64 feat, ui32 decmask = 0, ui32 encmask = 0) {
+ AddRng(lo, hi, TCharFlags(type, feat, decmask, encmask));
+ }
+
+ void Add(const TStringBuf& set, const TCharFlags& val) {
+ for (size_t i = 0; i != set.length(); ++i)
+ Add(set[i], val);
+ }
+ void Add(const TStringBuf& set, ui32 type, ui64 feat, ui32 decmask = 0, ui32 encmask = 0) {
+ Add(set, TCharFlags(type, feat, decmask, encmask));
+ }
+ };
+
+ static const TGrammar& Grammar();
+
+ protected:
+ IOutputStream& Out;
+ const TEncodeMapper FldSrc;
+ const TEncodeToMapper FldDst;
+ ui64 OutFlags;
+ int HexValue;
+
+ protected:
+ void HexReset() {
+ HexValue = 0;
+ }
+
+ void HexDigit(char c) {
+ HexAdd(c - '0');
+ }
+ void HexUpper(char c) {
+ HexAdd(c - 'A' + 10);
+ }
+ void HexLower(char c) {
+ HexAdd(c - 'a' + 10);
+ }
+
+ void HexAdd(int val) {
+ HexValue <<= 4;
+ HexValue += val;
+ }
+
+ protected:
+ void DoSym(unsigned char ch) {
+ const int res = FldSrc.EncodeSym(ch);
+ Do(ch, res);
+ }
+ void DoHex(unsigned char ch) {
+ const int res = FldSrc.EncodeHex(ch);
+ Do(ch, res);
+ }
+ void DoHex() {
+ DoHex(HexValue);
+ HexValue = 0;
+ }
+ void Do(unsigned char, int);
+ };
+ }
+
+ using TEncoder = NEncode::TEncoder;
+
+}
diff --git a/library/cpp/uri/encodefsm.rl6 b/library/cpp/uri/encodefsm.rl6
new file mode 100644
index 0000000000..6a323aa85a
--- /dev/null
+++ b/library/cpp/uri/encodefsm.rl6
@@ -0,0 +1,51 @@
+#include <library/cpp/uri/encode.h>
+
+#ifdef __clang__
+ #pragma clang diagnostic ignored "-Wunused-variable"
+#endif
+
+namespace NUri {
+namespace NEncode {
+
+%%{
+ machine TEncoder;
+
+ hex = (
+ digit >{ HexDigit(fc); } |
+ [A-F] >{ HexUpper(fc); } |
+ [a-f] >{ HexLower(fc); }
+ );
+
+ escaped = ( "%" hex hex )
+ > { HexReset(); }
+ % { DoHex(); };
+
+ bad_escaped = ( "%" hex )
+ % {
+ DoSym(*(fpc - 2));
+ DoSym(*(fpc - 1));
+ };
+
+ sym = (any - bad_escaped - escaped) %{ DoSym(*(fpc - 1)); };
+
+ main := ( escaped | bad_escaped | sym )**;
+
+ write data;
+}%%
+
+ui64 TEncoder::ReEncode(const TStringBuf &url)
+{
+ const char *p = url.data();
+ const char *pe = p + url.length();
+ const char *eof = pe;
+ int cs;
+ OutFlags = 0;
+
+ %% write init;
+ %% write exec;
+
+ return OutFlags;
+}
+
+}
+}
diff --git a/library/cpp/uri/http_url.h b/library/cpp/uri/http_url.h
new file mode 100644
index 0000000000..7c8e8d844d
--- /dev/null
+++ b/library/cpp/uri/http_url.h
@@ -0,0 +1,77 @@
+#pragma once
+
+#include "uri.h"
+#include "other.h"
+
+// XXX: use NUri::TUri directly; this whole file is for backwards compatibility
+
+class THttpURL
+ : public NUri::TUri {
+public:
+ typedef TField::EFlags TFlags;
+ typedef TField::EField TField;
+ typedef TScheme::EKind TSchemeKind;
+ typedef TState::EParsed TParsedState;
+
+public:
+ enum {
+ FeatureUnescapeStandard = TFeature::FeatureDecodeStandard,
+ FeatureEscSpace = TFeature::FeatureEncodeSpaceAsPlus,
+ FeatureEscapeUnescaped = TFeature::FeatureEncodeExtendedASCII,
+ FeatureNormalPath = TFeature::FeaturePathStripRootParent,
+ };
+
+public:
+ THttpURL(unsigned defaultPort = 80)
+ : TUri(defaultPort)
+ {
+ }
+
+ THttpURL(const TStringBuf& host, ui16 port, const TStringBuf& path, const TStringBuf& query = TStringBuf(), const TStringBuf& scheme = "http", unsigned defaultPort = 0)
+ : TUri(host, port, path, query, scheme, defaultPort)
+ {
+ }
+
+ THttpURL(const TUri& url)
+ : TUri(url)
+ {
+ }
+
+public: // XXX: don't use any of these legacy methods below
+public: // use TUri::GetField() instead
+ /// will return null-terminated if fld is not dirty
+ const char* Get(EField fld) const {
+ return GetField(fld).data();
+ }
+
+public: // use TUriUpdate class so that Rewrite() is only called once
+ void Set(EField field, const TStringBuf& value) {
+ if (SetInMemory(field, value))
+ Rewrite();
+ }
+
+ template <size_t size>
+ void Set(EField field, const char (&value)[size]) {
+ if (SetInMemory(field, value))
+ Rewrite();
+ }
+
+public: // use TUri::FldXXX methods for better control
+ // Partial quick set of the field, can be called for
+ // multiple fields
+ bool SetInMemory(EField field, const TStringBuf& value) {
+ return FldMemSet(field, value);
+ }
+
+ // clears a field
+ void Reset(EField field) {
+ FldClr(field);
+ }
+};
+
+static inline const char* HttpURLParsedStateToString(const NUri::TState::EParsed& t) {
+ return NUri::ParsedStateToString(t);
+}
+static inline const char* HttpUrlSchemeKindToString(const NUri::TScheme::EKind& t) {
+ return NUri::SchemeKindToString(t);
+}
diff --git a/library/cpp/uri/location.cpp b/library/cpp/uri/location.cpp
new file mode 100644
index 0000000000..a6a4d11ffa
--- /dev/null
+++ b/library/cpp/uri/location.cpp
@@ -0,0 +1,31 @@
+#include "location.h"
+#include "uri.h"
+
+namespace NUri {
+ static const int URI_PARSE_FLAGS =
+ (TFeature::FeaturesRecommended | TFeature::FeatureConvertHostIDN | TFeature::FeatureEncodeExtendedDelim | TFeature::FeatureEncodePercent) & ~TFeature::FeatureHashBangToEscapedFragment;
+
+ TString ResolveRedirectLocation(const TStringBuf& baseUrl,
+ const TStringBuf& location) {
+ TUri baseUri;
+ TUri locationUri;
+
+ // Parse base URL.
+ if (baseUri.Parse(baseUrl, URI_PARSE_FLAGS) != NUri::TState::ParsedOK) {
+ return "";
+ }
+ // Parse location with respect to the base URL.
+ if (locationUri.Parse(location, baseUri, URI_PARSE_FLAGS) != NUri::TState::ParsedOK) {
+ return "";
+ }
+ // Inherit fragment.
+ if (!locationUri.GetField(NUri::TField::FieldFragment)) {
+ NUri::TUriUpdate update(locationUri);
+ update.Set(NUri::TField::FieldFragment, baseUri.GetField(NUri::TField::FieldFragment));
+ }
+ TString res;
+ locationUri.Print(res, NUri::TField::FlagAllFields);
+ return res;
+ }
+
+}
diff --git a/library/cpp/uri/location.h b/library/cpp/uri/location.h
new file mode 100644
index 0000000000..0f533fe0b5
--- /dev/null
+++ b/library/cpp/uri/location.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <util/generic/string.h>
+
+namespace NUri {
+ /**
+ * Resolve Location header according to https://tools.ietf.org/html/rfc7231#section-7.1.2
+ *
+ * @return Resolved location's url or empty string in case of any error.
+ */
+ TString ResolveRedirectLocation(const TStringBuf& baseUrl, const TStringBuf& location);
+
+}
diff --git a/library/cpp/uri/location_ut.cpp b/library/cpp/uri/location_ut.cpp
new file mode 100644
index 0000000000..26a0f64471
--- /dev/null
+++ b/library/cpp/uri/location_ut.cpp
@@ -0,0 +1,40 @@
+#include "location.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TResolveRedirectTests) {
+ Y_UNIT_TEST(Absolute) {
+ UNIT_ASSERT_EQUAL(
+ NUri::ResolveRedirectLocation("http://example.com", "http://redir-example.com/sub"), "http://redir-example.com/sub");
+ }
+ Y_UNIT_TEST(AbsWithFragment) {
+ UNIT_ASSERT_EQUAL(
+ NUri::ResolveRedirectLocation("http://example.com", "http://redir-example.com/sub#Hello"), "http://redir-example.com/sub#Hello");
+ UNIT_ASSERT_EQUAL(
+ NUri::ResolveRedirectLocation("http://example.com/#Hello", "http://redir-example.com/sub"), "http://redir-example.com/sub#Hello");
+ }
+ Y_UNIT_TEST(Rel) {
+ UNIT_ASSERT_EQUAL(
+ NUri::ResolveRedirectLocation("http://example.com", "/sub"), "http://example.com/sub");
+ }
+ Y_UNIT_TEST(RelWithFragment) {
+ UNIT_ASSERT_EQUAL(
+ NUri::ResolveRedirectLocation("http://example.com", "/sub#Hello"), "http://example.com/sub#Hello");
+ UNIT_ASSERT_EQUAL(
+ NUri::ResolveRedirectLocation("http://example.com/#Hello", "/sub"), "http://example.com/sub#Hello");
+ }
+ Y_UNIT_TEST(WrongLocation) {
+ UNIT_ASSERT_EQUAL(
+ NUri::ResolveRedirectLocation("http://example.com", ""), "");
+ }
+ Y_UNIT_TEST(WrongBase) {
+ UNIT_ASSERT_EQUAL(
+ NUri::ResolveRedirectLocation("", "http://example.com"), "");
+ }
+ Y_UNIT_TEST(HashBangIsNothingSpecial) {
+ UNIT_ASSERT_EQUAL(
+ NUri::ResolveRedirectLocation("http://example.com", "http://redir-example.com/sub#!Hello"), "http://redir-example.com/sub#!Hello");
+ UNIT_ASSERT_EQUAL(
+ NUri::ResolveRedirectLocation("http://example.com/#!Hello", "http://redir-example.com/sub"), "http://redir-example.com/sub#!Hello");
+ }
+}
diff --git a/library/cpp/uri/other.cpp b/library/cpp/uri/other.cpp
new file mode 100644
index 0000000000..b23a5b68a9
--- /dev/null
+++ b/library/cpp/uri/other.cpp
@@ -0,0 +1,82 @@
+#include "other.h"
+
+#include <util/string/util.h>
+#include <util/system/yassert.h>
+
+/********************************************************/
+/********************************************************/
+
+static const Tr InvertTr(".:/?#", "\005\004\003\002\001");
+static const Tr RevertTr("\005\004\003\002\001", ".:/?#");
+
+void TrspChars(char* s) {
+ InvertTr.Do(s);
+}
+
+void UnTrspChars(char* s) {
+ RevertTr.Do(s);
+}
+
+void TrspChars(char* s, size_t l) {
+ InvertTr.Do(s, l);
+}
+
+void UnTrspChars(char* s, size_t l) {
+ RevertTr.Do(s, l);
+}
+
+void TrspChars(const char* s, char* d) {
+ InvertTr.Do(s, d);
+}
+
+void UnTrspChars(const char* s, char* d) {
+ RevertTr.Do(s, d);
+}
+
+void InvertDomain(char* begin, char* end) {
+ // skip schema if it is present
+ const auto dotPos = TStringBuf{begin, end}.find('.');
+ if (dotPos == TStringBuf::npos)
+ return; // no need to invert anything
+ const auto schemaendPos = TStringBuf{begin, end}.find("://", 3);
+ if (schemaendPos < dotPos)
+ begin += schemaendPos + 3;
+ char* sl = (char*)memchr(begin, '/', end - begin);
+ char* cl = (char*)memchr(begin, ':', sl ? sl - begin : end - begin);
+ end = cl ? cl : (sl ? sl : end);
+
+ // invert string
+ for (size_t i = 0, n = end - begin; i < n / 2; ++i)
+ DoSwap(begin[i], begin[n - i - 1]);
+
+ // invert back each host name segment
+ char* b = begin;
+ while (true) {
+ char* e = (char*)memchr(b, '.', end - b);
+ if (!e)
+ e = end;
+ for (size_t i = 0, n = e - b; i < n / 2; ++i)
+ DoSwap(b[i], b[n - i - 1]);
+ if (e == end)
+ break;
+ b = e + 1;
+ }
+}
+
+void InvertUrl(char* begin, char* end) {
+ char* slash = strchr(begin, '/');
+ if (slash) {
+ *slash = 0;
+ }
+ strlwr(begin);
+ if (slash) {
+ *slash = '/';
+ }
+ InvertDomain(begin, end);
+ TrspChars(begin);
+}
+
+void RevertUrl(char* begin, char* end) {
+ UnTrspChars(begin);
+ InvertDomain(begin, end);
+}
diff --git a/library/cpp/uri/other.h b/library/cpp/uri/other.h
new file mode 100644
index 0000000000..7aec22e77b
--- /dev/null
+++ b/library/cpp/uri/other.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <util/generic/string.h>
+
+// Some functions for inverted url representation
+// No scheme cut-off, no 80th port normalization
+
+void TrspChars(char* s);
+void UnTrspChars(char* s);
+void TrspChars(char* s, size_t l);
+void UnTrspChars(char* s, size_t l);
+void TrspChars(const char* s, char* d);
+void UnTrspChars(const char* s, char* d);
+
+void InvertDomain(char* begin, char* end);
+
+inline TString& InvertDomain(TString& url) {
+ InvertDomain(url.begin(), url.begin() + url.size());
+ return url;
+}
+
+void InvertUrl(char* begin, char* end);
+
+inline void InvertUrl(char* url) {
+ InvertUrl(url, url + strlen(url));
+}
+
+inline TString& InvertUrl(TString& url) {
+ InvertUrl(url.begin(), url.begin() + url.size());
+ return url;
+}
+
+void RevertUrl(char* begin, char* end);
+
+inline void RevertUrl(char* url) {
+ RevertUrl(url, url + strlen(url));
+}
+
+inline TString& RevertUrl(TString& url) {
+ RevertUrl(url.begin(), url.begin() + url.size());
+ return url;
+}
diff --git a/library/cpp/uri/parse.cpp b/library/cpp/uri/parse.cpp
new file mode 100644
index 0000000000..1db4e008c4
--- /dev/null
+++ b/library/cpp/uri/parse.cpp
@@ -0,0 +1,207 @@
+#include "parse.h"
+#include "common.h"
+#include "encode.h"
+
+namespace NUri {
+ const TParseFlags TParser::FieldFlags[] =
+ {
+ TParseFlags(0 // FieldScheme
+ | TFeature::FeatureToLower,
+ 0)
+
+ ,
+ TParseFlags(0 // FieldUsername
+ | TFeature::FeatureDecodeANY | TFeature::FeaturesDecode | TFeature::FeatureEncodePercent,
+ 0 | TFeature::FeatureToLower)
+
+ ,
+ TParseFlags(0 // FieldPassword
+ | TFeature::FeatureDecodeANY | TFeature::FeaturesDecode | TFeature::FeatureEncodePercent,
+ 0 | TFeature::FeatureToLower)
+
+ ,
+ TParseFlags(0 // FieldHost
+ | TFeature::FeatureToLower | TFeature::FeatureUpperEncoded | (TFeature::FeaturesMaybeEncode & ~TFeature::FeatureEncodeExtendedDelim),
+ 0 | TFeature::FeaturesMaybeDecode)
+
+ ,
+ TParseFlags(0 // FieldPort
+ ,
+ 0)
+
+ ,
+ TParseFlags(0 // FieldPath
+ | TFeature::FeaturesEncodePChar | TFeature::FeaturePathOperation,
+ 0 | TFeature::FeatureToLower | TFeature::FeatureEncodeSpaceAsPlus)
+
+ ,
+ TParseFlags(0 // FieldQuery
+ | TFeature::FeaturesEncodePChar | TFeature::FeatureEncodeSpaceAsPlus,
+ 0 | TFeature::FeatureToLower)
+
+ ,
+ TParseFlags(0 // FieldFragment
+ | TFeature::FeaturesEncodePChar,
+ 0 | TFeature::FeatureToLower | TFeature::FeatureEncodeSpaceAsPlus)};
+
+ namespace NParse {
+ void TRange::AddRange(const TRange& range, ui64 mask) {
+ FlagsAllPlaintext |= range.FlagsAllPlaintext;
+ // update only if flags apply here
+ mask &= range.FlagsEncodeMasked;
+ if (0 == mask)
+ return;
+ FlagsEncodeMasked |= mask;
+ if (mask & TFeature::FeaturesMaybeEncode)
+ Encode += range.Encode;
+ if (mask & TFeature::FeaturesDecode)
+ Decode += range.Decode;
+ }
+
+ }
+
+ void TParser::copyRequirementsImpl(const char* ptr) {
+ Y_ASSERT(0 != CurRange.FlagsAllPlaintext);
+ Y_UNUSED(ptr);
+#ifdef DO_PRN
+ PrintHead(ptr, __FUNCTION__)
+ << " all=[" << IntToString<16>(CurRange.FlagsAllPlaintext)
+ << "] enc=[" << IntToString<16>(CurRange.FlagsEncodeMasked)
+ << " & " << IntToString<16>(Flags.Allow | Flags.Extra) << "]";
+ PrintTail(CurRange.Beg, ptr);
+#endif
+ for (int i = 0; i < TField::FieldUrlMAX; ++i) {
+ const TField::EField fld = TField::EField(i);
+ TSection& section = Sections[fld];
+ // update only sections in progress
+ if (nullptr == section.Beg)
+ continue;
+ // and overlapping with the range
+ if (nullptr != section.End && section.End < CurRange.Beg)
+ continue;
+#ifdef DO_PRN
+ PrintHead(ptr, __FUNCTION__, fld)
+ << " all=[" << IntToString<16>(CurRange.FlagsAllPlaintext)
+ << "] enc=[" << IntToString<16>(CurRange.FlagsEncodeMasked)
+ << " & " << IntToString<16>(GetFieldFlags(fld)) << "]";
+ PrintTail(section.Beg, ptr);
+#endif
+ section.AddRange(CurRange, GetFieldFlags(fld));
+ }
+ CurRange.Reset();
+ }
+
+ void TParser::PctEndImpl(const char* ptr) {
+#ifdef DO_PRN
+ PrintHead(PctBegin, __FUNCTION__);
+ PrintTail(PctBegin, ptr);
+#else
+ Y_UNUSED(ptr);
+#endif
+ setRequirement(PctBegin, TEncoder::GetFlags('%').FeatFlags);
+ PctBegin = nullptr;
+ }
+
+ void TParser::HexSet(const char* ptr) {
+ Y_ASSERT(nullptr != PctBegin);
+#ifdef DO_PRN
+ PrintHead(ptr, __FUNCTION__);
+ PrintTail(PctBegin, ptr + 1);
+#endif
+ PctBegin = nullptr;
+ const unsigned char ch = HexValue;
+ ui64 flags = TEncoder::GetFlags('%').FeatFlags | TEncoder::GetFlags(ch).FeatFlags;
+
+ setRequirementExcept(ptr, flags, TFeature::FeaturesMaybeEncode);
+ }
+
+ TState::EParsed TParser::ParseImpl() {
+#ifdef DO_PRN
+ PrintHead(UriStr.data(), "[Parsing]") << "URL";
+ PrintTail(UriStr);
+#endif
+
+ const bool ok = doParse(UriStr.data(), UriStr.length());
+
+#ifdef DO_PRN
+ Cdbg << (ok ? "[Parsed]" : "[Failed]");
+ for (int idx = 0; idx < TField::FieldUrlMAX; ++idx) {
+ const TSection& section = Sections[idx];
+ if (section.IsSet())
+ Cdbg << ' ' << TField::EField(idx) << "=[" << section.Get() << ']';
+ }
+ Cdbg << Endl;
+#endif
+
+ if (!ok) {
+ if (!(Flags & TFeature::FeatureTryToFix) || !Sections[TField::FieldFrag].Beg)
+ return TState::ParsedBadFormat;
+ //Here: error was in fragment, just ignore it
+ ResetSection(TField::FieldFrag);
+ }
+
+ if ((Flags & TFeature::FeatureDenyNetworkPath) && IsNetPath())
+ return TState::ParsedBadFormat;
+
+ const TSection& scheme = Sections[TField::FieldScheme];
+ Scheme = scheme.IsSet() ? TSchemeInfo::GetKind(scheme.Get()) : TScheme::SchemeEmpty;
+ const TSchemeInfo& schemeInfo = TSchemeInfo::Get(Scheme);
+
+ if (IsRootless()) {
+ // opaque case happens
+ if (schemeInfo.FldReq & TField::FlagHost)
+ return TState::ParsedBadFormat;
+
+ if (TScheme::SchemeEmpty == Scheme)
+ return TState::ParsedBadScheme;
+
+ if (Flags & TFeature::FeatureAllowRootless)
+ return TState::ParsedOK;
+
+ if (!(Flags & TFeature::FeatureSchemeFlexible))
+ return TState::ParsedBadScheme;
+
+ return TState::ParsedRootless;
+ }
+
+ checkSectionCollision(TField::FieldUser, TField::FieldHost);
+ checkSectionCollision(TField::FieldPass, TField::FieldPort);
+
+ if (0 == (Flags & TFeature::FeatureAuthSupported))
+ if (Sections[TField::FieldUser].IsSet() || Sections[TField::FieldPass].IsSet())
+ return TState::ParsedBadAuth;
+
+ TSection& host = Sections[TField::FieldHost];
+ if (host.IsSet())
+ for (; host.End != host.Beg && '.' == host.End[-1];)
+ --host.End;
+
+ if (scheme.IsSet()) {
+ ui64 wantCareFlags = 0;
+ switch (Scheme) {
+ case TScheme::SchemeHTTP:
+ break;
+ case TScheme::SchemeEmpty:
+ Scheme = TScheme::SchemeUnknown;
+ [[fallthrough]];
+ case TScheme::SchemeUnknown:
+ wantCareFlags =
+ TFeature::FeatureSchemeFlexible | TFeature::FeatureNoRelPath;
+ break;
+ default:
+ wantCareFlags =
+ TFeature::FeatureSchemeFlexible | TFeature::FeatureSchemeKnown;
+ break;
+ }
+
+ if (0 != wantCareFlags && 0 == (Flags & wantCareFlags))
+ return TState::ParsedBadScheme;
+ if ((schemeInfo.FldReq & TField::FlagHost) || (Flags & TFeature::FeatureRemoteOnly))
+ if (!host.IsSet() || 0 == host.Len())
+ return TState::ParsedBadFormat;
+ }
+
+ return TState::ParsedOK;
+ }
+
+}
diff --git a/library/cpp/uri/parse.h b/library/cpp/uri/parse.h
new file mode 100644
index 0000000000..ca2358e572
--- /dev/null
+++ b/library/cpp/uri/parse.h
@@ -0,0 +1,361 @@
+#pragma once
+
+// #define DO_PRN
+
+#include <cstddef>
+
+#include "common.h"
+
+#include <library/cpp/charset/doccodes.h>
+#include <util/generic/strbuf.h>
+#include <util/stream/output.h>
+#include <util/string/cast.h>
+#include <util/system/yassert.h>
+
+namespace NUri {
+ class TParser;
+
+ namespace NParse {
+ class TRange {
+ public:
+ const char* Beg;
+ ui64 FlagsEncodeMasked;
+ ui64 FlagsAllPlaintext;
+ ui32 Encode;
+ ui32 Decode;
+
+ public:
+ TRange(const char* beg = nullptr)
+ : Beg(beg)
+ , FlagsEncodeMasked(0)
+ , FlagsAllPlaintext(0)
+ , Encode(0)
+ , Decode(0)
+ {
+ }
+
+ void Reset(const char* beg = nullptr) {
+ *this = TRange(beg);
+ }
+
+ void AddRange(const TRange& range, ui64 mask);
+
+ void AddFlag(const char* ptr, ui64 mask, ui64 flag) {
+ if (0 != flag)
+ AddFlagImpl(ptr, mask, flag, flag);
+ }
+
+ void AddFlagExcept(const char* ptr, ui64 mask, ui64 flag, ui64 exclflag) {
+ if (0 != flag)
+ AddFlagImpl(ptr, mask, flag & ~exclflag, flag);
+ }
+
+ void AddFlagUnless(const char* ptr, ui64 mask, ui64 flag, ui64 exclmask) {
+ if (0 != flag)
+ AddFlagImpl(ptr, mask, flag, flag, exclmask);
+ }
+
+ void AddFlag(const char* ptr, ui64 mask, ui64 flag, ui64 exclflag, ui64 exclmask) {
+ if (0 != flag)
+ AddFlagImpl(ptr, mask, flag & ~exclflag, flag, exclmask);
+ }
+
+ private:
+ void AddFlagImpl(const char* ptr, ui64 mask, ui64 plainflag, ui64 encflag) {
+ AddFlagAllPlaintextImpl(ptr, plainflag);
+ AddFlagEncodeMaskedImpl(encflag & mask);
+ }
+
+ void AddFlagImpl(const char* ptr, ui64 mask, ui64 plainflag, ui64 encflag, ui64 exclmask) {
+ AddFlagAllPlaintextImpl(ptr, plainflag);
+ if (0 == (mask & exclmask))
+ AddFlagEncodeMaskedImpl(encflag & mask);
+ }
+
+ void AddFlagAllPlaintextImpl(const char* ptr, ui64 flag) {
+ if (nullptr == Beg)
+ Beg = ptr;
+ FlagsAllPlaintext |= flag;
+ }
+
+ void AddFlagEncodeMaskedImpl(ui64 flag) {
+ if (0 == flag)
+ return;
+ FlagsEncodeMasked |= flag;
+ if (flag & TFeature::FeaturesMaybeEncode)
+ ++Encode;
+ else if (flag & TFeature::FeaturesDecode)
+ ++Decode;
+ }
+ };
+
+ }
+
+ class TSection
+ : protected NParse::TRange {
+ private:
+ friend class TParser;
+
+ private:
+ const char* End;
+
+ TSection(const char* beg = nullptr)
+ : NParse::TRange(beg)
+ , End(nullptr)
+ {
+ }
+
+ void Reset() {
+ Enter(nullptr);
+ }
+
+ void Reset(const char* pc) {
+ Y_ASSERT(!Beg || !pc || Beg < pc);
+ Reset();
+ }
+
+ void Enter(const char* pc) {
+ *this = TSection(pc);
+ }
+
+ bool Leave(const char* pc) {
+ Y_ASSERT(Beg);
+ End = pc;
+ return true;
+ }
+
+ void Set(const TStringBuf& buf) {
+ Enter(buf.data());
+ Leave(buf.data() + buf.length());
+ }
+
+ public:
+ bool IsSet() const {
+ return End;
+ }
+
+ TStringBuf Get() const {
+ return TStringBuf(Beg, End);
+ }
+
+ size_t Len() const {
+ return End - Beg;
+ }
+
+ size_t DecodedLen() const {
+ return Len() - 2 * Decode;
+ }
+
+ size_t EncodedLen() const {
+ return 2 * Encode + DecodedLen();
+ }
+
+ ui32 GetEncode() const {
+ return Encode;
+ }
+
+ ui32 GetDecode() const {
+ return Decode;
+ }
+
+ ui64 GetFlagsEncode() const {
+ return FlagsEncodeMasked;
+ }
+
+ ui64 GetFlagsAllPlaintext() const {
+ return FlagsAllPlaintext;
+ }
+ };
+
+ class TParser {
+ public:
+ TSection Sections[TField::FieldUrlMAX];
+ TScheme::EKind Scheme;
+ const TParseFlags Flags;
+ const TStringBuf UriStr;
+ TState::EParsed State;
+ ECharset Enc;
+
+ public:
+ TParser(const TParseFlags& flags, const TStringBuf& uri, ECharset enc = CODES_UTF8)
+ : Scheme(TScheme::SchemeEmpty)
+ , Flags(flags | TFeature::FeatureDecodeANY)
+ , UriStr(uri)
+ , State(TState::ParsedEmpty)
+ , Enc(enc)
+ , HexValue(0)
+ , PctBegin(nullptr)
+ {
+ Y_ASSERT(0 == (Flags & TFeature::FeaturePathOperation)
+ // can't define all of them
+ || TFeature::FeaturesPath != (Flags & TFeature::FeaturesPath));
+ State = ParseImpl();
+ }
+
+ public:
+ const TSection& Get(TField::EField fld) const {
+ return Sections[fld];
+ }
+ TSection& GetMutable(TField::EField fld) {
+ return Sections[fld];
+ }
+ bool Has(TField::EField fld) const {
+ return Get(fld).IsSet();
+ }
+ bool IsNetPath() const {
+ return Has(TField::FieldHost) && 2 < UriStr.length() && '/' == UriStr[0] && '/' == UriStr[1];
+ }
+ bool IsRootless() const {
+ return Has(TField::FieldScheme) && !Has(TField::FieldHost) && (!Has(TField::FieldPath) || '/' != Get(TField::FieldPath).Get()[0]);
+ }
+ // for RFC 2396 compatibility
+ bool IsOpaque() const {
+ return IsRootless();
+ }
+ static ui64 GetFieldFlags(TField::EField fld, const TParseFlags& flags) {
+ return FieldFlags[fld] & flags;
+ }
+ ui64 GetFieldFlags(TField::EField fld) const {
+ return GetFieldFlags(fld, Flags);
+ }
+
+ protected:
+ static const TParseFlags FieldFlags[TField::FieldUrlMAX];
+ TSection::TRange CurRange;
+ unsigned HexValue;
+ const char* PctBegin;
+
+#ifdef DO_PRN
+ IOutputStream& PrintAddr(const char* ptr) const {
+ return Cdbg << "[" << IntToString<16>(ui64(ptr)) << "] ";
+ }
+
+ IOutputStream& PrintHead(const char* ptr, const char* func) const {
+ return PrintAddr(ptr) << func << " ";
+ }
+
+ IOutputStream& PrintHead(const char* ptr, const char* func, const TField::EField& fld) const {
+ return PrintHead(ptr, func) << fld;
+ }
+
+ IOutputStream& PrintTail(const TStringBuf& val) const {
+ return Cdbg << " [" << val << "]" << Endl;
+ }
+ IOutputStream& PrintTail(const char* beg, const char* end) const {
+ return PrintTail(TStringBuf(beg, end));
+ }
+#endif
+
+ void ResetSection(TField::EField fld, const char* pc = nullptr) {
+#ifdef DO_PRN
+ PrintHead(pc, __FUNCTION__, fld);
+ PrintTail(pc);
+#endif
+ Sections[fld].Reset(pc);
+ }
+
+ void storeSection(const TStringBuf& val, TField::EField fld) {
+#ifdef DO_PRN
+ PrintHead(val.data(), __FUNCTION__, fld);
+ PrintTail(val);
+#endif
+ Sections[fld].Set(val);
+ }
+
+ void startSection(const char* pc, TField::EField fld) {
+#ifdef DO_PRN
+ PrintHead(pc, __FUNCTION__, fld);
+ PrintTail(pc);
+#endif
+ copyRequirements(pc);
+ Sections[fld].Enter(pc);
+ }
+
+ void finishSection(const char* pc, TField::EField fld) {
+#ifdef DO_PRN
+ PrintHead(pc, __FUNCTION__, fld);
+ PrintTail(pc);
+#endif
+ if (Sections[fld].Leave(pc))
+ copyRequirements(pc);
+ }
+
+ void setRequirement(const char* ptr, ui64 flags) {
+#ifdef DO_PRN
+ PrintHead(ptr, __FUNCTION__) << IntToString<16>(flags)
+ << " & mask=" << IntToString<16>(Flags.Allow | Flags.Extra);
+ PrintTail(ptr);
+#endif
+ CurRange.AddFlag(ptr, Flags.Allow | Flags.Extra, flags);
+ }
+
+ void setRequirementExcept(const char* ptr, ui64 flags, ui64 exclflag) {
+#ifdef DO_PRN
+ PrintHead(ptr, __FUNCTION__) << IntToString<16>(flags)
+ << " & exclflag=" << IntToString<16>(exclflag)
+ << " & mask=" << IntToString<16>(Flags.Allow | Flags.Extra);
+ PrintTail(ptr);
+#endif
+ CurRange.AddFlagExcept(ptr, Flags.Allow | Flags.Extra, flags, exclflag);
+ }
+
+ void setRequirementUnless(const char* ptr, ui64 flags, ui64 exclmask) {
+#ifdef DO_PRN
+ PrintHead(ptr, __FUNCTION__) << IntToString<16>(flags)
+ << " & exclmask=" << IntToString<16>(exclmask)
+ << " & mask=" << IntToString<16>(Flags.Allow | Flags.Extra);
+ PrintTail(ptr);
+#endif
+ CurRange.AddFlagUnless(ptr, Flags.Allow | Flags.Extra, flags, exclmask);
+ }
+
+ void copyRequirementsImpl(const char* ptr);
+ void copyRequirements(const char* ptr) {
+ PctEnd(ptr);
+ if (nullptr != CurRange.Beg && CurRange.Beg != ptr)
+ copyRequirementsImpl(ptr);
+ }
+
+ void HexDigit(const char* ptr, char c) {
+ Y_UNUSED(ptr);
+ HexAdd(c - '0');
+ }
+ void HexUpper(const char* ptr, char c) {
+ setRequirementUnless(ptr, TFeature::FeatureToLower, TFeature::FeatureUpperEncoded);
+ HexAdd(c - 'A' + 10);
+ }
+ void HexLower(const char* ptr, char c) {
+ setRequirement(ptr, TFeature::FeatureUpperEncoded);
+ HexAdd(c - 'a' + 10);
+ }
+ void HexAdd(unsigned val) {
+ HexValue <<= 4;
+ HexValue += val;
+ }
+ void HexReset() {
+ HexValue = 0;
+ }
+ void HexSet(const char* ptr);
+
+ void PctEndImpl(const char* ptr);
+ void PctEnd(const char* ptr) {
+ if (nullptr != PctBegin && ptr != PctBegin)
+ PctEndImpl(ptr);
+ }
+ void PctBeg(const char* ptr) {
+ PctEnd(ptr);
+ HexReset();
+ PctBegin = ptr;
+ }
+
+ void checkSectionCollision(TField::EField fld1, TField::EField fld2) {
+ if (Sections[fld1].IsSet() && Sections[fld2].IsSet() && Sections[fld1].Beg == Sections[fld2].Beg) {
+ Sections[fld1].Reset();
+ }
+ }
+
+ bool doParse(const char* str_beg, size_t length);
+ TState::EParsed ParseImpl();
+ };
+
+}
diff --git a/library/cpp/uri/parsefsm.rl6 b/library/cpp/uri/parsefsm.rl6
new file mode 100644
index 0000000000..7097723650
--- /dev/null
+++ b/library/cpp/uri/parsefsm.rl6
@@ -0,0 +1,501 @@
+#include <library/cpp/uri/parse.h>
+
+#ifdef __clang__
+ #pragma clang diagnostic ignored "-Wunused-variable"
+#endif
+
+%%{
+ machine TParser;
+
+ #================================================
+ # RFC 3986 http://tools.ietf.org/html/rfc3986
+ # with some modifications
+ #================================================
+ # The RegEx
+ #
+ # http://www.ics.uci.edu/pub/ietf/uri/#Related
+ # ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ # 12 3 4 5 6 7 8 9
+ #results in the following subexpression matches:
+ # $1 = http:
+ # $2 = http
+ # $3 = //www.ics.uci.edu
+ # $4 = www.ics.uci.edu
+ # $5 = /pub/ietf/uri/
+ # $6 = <undefined>
+ # $7 = <undefined>
+ # $8 = #Related
+ # $9 = Related
+ #
+ # So $2:scheme $4:authority $5:path $7:query $9:fragment
+ #================================================
+
+
+ #================================================
+ # List of all ASCII characters and where they can be used
+ #================================================
+
+ # 0-31 x00-1F cntrl ext_cntrl
+ # 32 x20 space ext_space
+ # 33 x21 ! sub_delims
+ # 34 x22 " ext_delims
+ # 35 x23 # gen_delims / f=frag
+ # 36 x24 $ sub_delims
+ # 37 x25 % PCT
+ # 38 x26 & sub_delims
+ # 39 x27 ' sub_delims
+ # 40 x28 ( sub_delims
+ # 41 x29 ) sub_delims
+ # 42 x2A * sub_delims
+ # 43 x2B + sub_delims
+ # 44 x2C , sub_delims
+ # 45 x2D - unreserved
+ # 46 x2E . unreserved
+ # 47 x2F / gen_delims / f=path,qry,frag
+ # 48-57 x30-39 0-9 unreserved
+ # 58 x3A : gen_delims / f=pass,path,qry,frag
+ # 59 x3B ; sub_delims
+ # 60 x3C < ext_delims
+ # 61 x3D = sub_delims
+ # 62 x3E > ext_delims
+ # 63 x3F ? gen_delims / f=qry,frag
+ # 64 x40 @ gen_delims / f=path,qry,frag
+ # 65-90 x41-5A A-Z unreserved
+ # 91 x5B [ gen_delims / ext_delims
+ # 92 x5C \ ext_delims
+ # 93 x5D ] gen_delims / ext_delims
+ # 94 x5E ^ ext_delims
+ # 95 x5F _ unreserved
+ # 96 x60 ` ext_delims
+ # 97-122 x61-7A a-z unreserved
+ # 123 x7B { ext_delims
+ # 124 x7C | ext_delims
+ # 125 x7D } ext_delims
+ # 126 x7E ~ unreserved
+ # 127 x7F DEL ext_cntrl
+ # 128-255 x80-FF ext_ascii
+
+
+ #================================================
+ # Actions used in multiple definitions
+ #================================================
+
+ action act_req_enc_sql { REQ(fpc, FeatureEncodeForSQL) }
+
+ # REQ must apply to a char in range but not after the range has been reset
+ action act_req_pathop { REQ(fpc - 1, FeaturePathOperation) }
+
+ action act_clr_scheme { CLR(fpc, Scheme) }
+ action act_clr_user { CLR(fpc, User) }
+ action act_clr_host { CLR(fpc, Host) }
+ action act_beg_host { BEG(fpc, Host) }
+ action act_end_host { END(fpc, Host) }
+ action act_beg_path { BEG(fpc, Path) }
+ action act_end_path { END(fpc, Path) }
+
+
+ #================================================
+ # RFC 3986 ABNFs
+ #================================================
+
+ DIGIT = digit;
+
+ ALPHA = ( upper >{ REQ(fpc, FeatureToLower) } ) |
+ lower;
+
+ ALNUM = ALPHA | DIGIT;
+
+ PCT = "%" >{ PctBeg(fpc); } ;
+
+ HEXDIG = (
+ DIGIT >{ HexDigit(fpc, fc); }
+ | [A-F] >{ HexUpper(fpc, fc); }
+ | [a-f] >{ HexLower(fpc, fc); }
+ );
+
+ # HexSet sets REQ so must apply in range
+ HEXNUM = ( HEXDIG HEXDIG ) %{ HexSet(fpc - 1); };
+
+ pct_encoded = PCT HEXNUM;
+
+ unreserved = ALNUM | "-" | "." | "_" | "~";
+
+ gen_delims = ":" | "/" | "?" | "#" | "[" | "]" | "@";
+
+ sub_delims = "!" | "$" | "&" | "(" | ")"
+ | "*" | "+" | "," | ";" | "="
+ | ( ['] >act_req_enc_sql );
+
+
+ #================================================
+ # Local ABNFs
+ #================================================
+
+ VALID = ^(cntrl | space) | " ";
+
+ # safe character sequences
+ safe = unreserved | pct_encoded | sub_delims;
+
+ # MOD: Yandex extensions
+
+ ext_ascii = (VALID - ascii) >{ REQ(fpc, FeatureEncodeExtendedASCII) };
+ ext_delims = ( "[" | "]" | "|" | "{" | "}" | "`" | "^" | "<" | ">"
+ | ( ["\\] >act_req_enc_sql )
+ ) >{ REQ(fpc, FeatureEncodeExtendedDelim) }; # " fix hilite
+ ext_space = " " >{ REQ(fpc, FeatureEncodeSpace) };
+ ext_cntrl = cntrl >{ REQ(fpc, FeatureEncodeCntrl) };
+
+ pct_maybe_encoded = PCT (HEXDIG | HEXNUM)? ;
+ ext_safe = unreserved
+ | pct_maybe_encoded
+ | sub_delims
+ | ext_delims
+ | ext_space
+ | ext_cntrl
+ | ext_ascii;
+
+ # pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ # uric (RFC 2396)
+ # MOD: extension to format, add extended delimiters and 8-bit ascii
+
+ pchar_nc = ext_safe | "@";
+ pchar = pchar_nc | ":";
+ path_sep = "/";
+ uric = pchar | path_sep | "?";
+
+
+ #================================================
+ # Fields
+ #================================================
+ # Single fields use fXXX as machine definitions
+
+
+ #================================================
+ # Scheme
+ # scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ #================================================
+
+ scheme = ( ALPHA ( ALPHA | DIGIT | "+" | "-" | "." )** );
+ fscheme = scheme >{ BEG(fpc, Scheme) } %{ END(fpc, Scheme) };
+
+
+ #================================================
+ # UserInfo
+ # userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+ #================================================
+
+ # MOD: split into a pair of sections: username and password
+
+ fuser = ( ext_safe )** >{ BEG(fpc, User) } %{ END(fpc, User) };
+ fpass = ( ext_safe | ":" )** >{ BEG(fpc, Pass) } %{ END(fpc, Pass) };
+ userinfo = ( fuser ( ":" fpass )? ) ( "@" %act_clr_host @^act_clr_user );
+
+
+ #================================================
+ # Hostname
+ # host = IP-literal / IPv4address / reg-name
+ #================================================
+
+ # MOD: simplify IP-literal for now
+ IPv6address = (HEXDIG | ":" | ".")+;
+ IP_literal = "[" IPv6address "]";
+
+ # IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
+ # MOD: simplify dec-octet which originally matches only 0-255
+
+ dec_octet = DIGIT+;
+ IPv4address = dec_octet "." dec_octet "." dec_octet "." dec_octet;
+
+ # MOD: non-empty; will use host?
+ # reg-name = *( unreserved / pct-encoded / sub-delims )
+ ### todo: allow ':' (need to fix grammar to disambiguate port)
+ achar = any - (0x00 .. 0x20) - '/' - '#' - '?' - ':' - '%';
+ upperhalf = any - (0x00 .. 0x7F);
+ hostname = (((achar | pct_encoded)+) & (any* (alnum | upperhalf) any*));
+ reg_name = hostname - IPv4address - IP_literal;
+
+ # uses first-match-wins approach
+ host = IP_literal | IPv4address | (reg_name - IPv4address);
+ fhost = host? >act_beg_host %act_end_host;
+ fhost_nempty = host >act_beg_host %act_end_host;
+
+
+ #================================================
+ # Port
+ # port = *DIGIT
+ #================================================
+
+ # MOD: use fport? for empty
+ fport = DIGIT+ >{ BEG(fpc, Port) } %{ END(fpc, Port) };
+
+
+ #================================================
+ # Authority
+ # authority = [ userinfo "@" ] host [ ":" port ]
+ #================================================
+
+ authority = userinfo? fhost ( ":" fport? )? ;
+
+
+ #================================================
+ # Path
+ #================================================
+ # path = path-abempty ; begins with "/" or is empty
+ # / path-absolute ; begins with "/" but not "//"
+ # / path-noscheme ; begins with a non-colon segment
+ # / path-rootless ; begins with a segment
+ # / path-empty ; zero characters
+ #================================================
+
+ # checkPath rules
+
+ checkPathHead =
+ "." ( "."? path_sep VALID* )? %act_req_pathop ;
+
+ checkPathTail =
+ VALID*
+ ( path_sep "."{1,2} ) %act_req_pathop ;
+
+ checkPathMid = VALID*
+ ( path_sep "."{,2} path_sep ) %act_req_pathop
+ VALID*;
+
+ checkAbsPath = checkPathMid | checkPathTail | VALID*;
+ checkRelPath = checkPathHead | checkAbsPath;
+
+ # segment = *pchar
+ segment = pchar**;
+
+ # segment-nz = 1*pchar
+ segment_nz = pchar+;
+
+ # segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
+ segment_nz_nc = pchar_nc+;
+
+ sep_segment = path_sep segment;
+
+ # non-standard definitions
+
+ fpath_abnempty =
+ (
+ ( sep_segment+ )
+ & checkAbsPath
+ )
+ >act_beg_path %act_end_path
+ ;
+
+ fpath_relative =
+ (
+ "."
+ ( "."? sep_segment+ )?
+ )
+ >act_beg_path %act_req_pathop %act_end_path
+ ;
+
+ # standard definitions
+
+ # do not save empty paths, they behave differently in relative resolutions
+ fpath_empty = zlen;
+
+ fpath_abempty = fpath_abnempty?;
+
+ fpath_absolute =
+ (
+ ( path_sep ( segment_nz sep_segment* )? )
+ & checkAbsPath
+ )
+ >act_beg_path %act_end_path
+ ;
+
+ fpath_noscheme =
+ (
+ ( segment_nz_nc sep_segment* )
+ & checkRelPath
+ )
+ >act_beg_path %act_end_path
+ ;
+
+ fpath_rootless =
+ (
+ ( segment_nz sep_segment* )
+ )
+ >act_beg_path %act_end_path
+ ;
+
+ #================================================
+ # Query and fragment
+ # query = *( pchar / "/" / "?" )
+ # fragment = *( pchar / "/" / "?" )
+ #================================================
+
+ # MOD: fragment allows '#' characters
+
+ fquery = (uric )** >{ BEG(fpc, Query) } %{ END(fpc, Query) };
+ ffrag = (uric | "#")** >{ BEG(fpc, Frag) } %{ END(fpc, Frag) };
+ query_frag = ("?" fquery)? ("#" ffrag)? ;
+
+
+ #================================================
+ # final ABNFs
+ # URI-reference = URI / relative-ref
+ #================================================
+ # URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+ # hier-part = "//" authority path-abempty
+ # / path-absolute
+ # / path-rootless
+ # / path-empty
+ # relative-ref = relative-part [ "?" query ] [ "#" fragment ]
+ # relative-part = "//" authority path-abempty
+ # / path-absolute
+ # / path-noscheme
+ # / path-empty
+
+ net_path = "//" authority fpath_abempty;
+
+ URI =
+ fscheme ":"
+ (
+ net_path
+ | fpath_absolute
+ | fpath_rootless
+ | fpath_empty
+ )
+ $^act_clr_scheme
+ query_frag
+ ;
+
+ relative_ref =
+ (
+ net_path
+ | fpath_absolute
+ | fpath_noscheme
+ | fpath_empty
+ )
+ %act_clr_scheme
+ query_frag
+ ;
+
+ # non-standard definitions
+
+ URI_no_rootless =
+ fscheme ":"
+ (
+ net_path
+ | fpath_absolute
+ | fpath_empty
+ )
+ $^act_clr_scheme
+ query_frag
+ ;
+
+ host_path =
+ (
+ fhost_nempty fpath_abempty
+ | (fhost_nempty - scheme) ":" fport fpath_abempty
+ )
+ @^act_clr_host
+ ;
+
+ # no userinfo, path absolute, empty or clearly relative, starting with "./" | "../"
+ relative_ref_host_pabem =
+ (
+ net_path
+ | host_path
+ | fpath_absolute
+ | fpath_relative
+ | fpath_empty
+ )
+ %act_clr_scheme
+ query_frag
+ ;
+
+ # port must be non-empty, to avoid clash with "scheme:/..."
+ auth_path =
+ (
+ fhost_nempty ( ":" fport )? fpath_abempty
+ | userinfo fhost ( ":" fport? )? fpath_abempty
+ )
+ @^act_clr_host
+ @^act_clr_user
+ ;
+
+ # userinfo, path absolute, empty or clearly relative, starting with "./" | "../"
+ relative_ref_auth_pabem =
+ (
+ net_path
+ | auth_path
+ | fpath_absolute
+ | fpath_relative
+ | fpath_empty
+ )
+ %act_clr_scheme
+ query_frag
+ ;
+
+
+ # machine instantiations
+
+ URI_ref_no_rootless :=
+ (
+ URI_no_rootless
+ # scheme://user@host preferred over user://pass@host/path
+ | relative_ref_auth_pabem
+ )
+ ;
+
+ URI_ref_no_relpath :=
+ (
+ relative_ref_host_pabem
+ # host:port/path preferred over scheme:path/rootless
+ | (URI - relative_ref_host_pabem)
+ )
+ ;
+
+ URI_ref :=
+ (
+ relative_ref
+ | URI
+ )
+ ;
+
+ write data;
+
+}%%
+
+namespace NUri {
+
+bool TParser::doParse(const char* str_beg, size_t length)
+{
+ const char* p = str_beg;
+ const char* pe = str_beg + length;
+ const char* eof = pe;
+ int cs;
+
+#define BEG(ptr, fld) startSection (ptr, TField::Field ## fld);
+#define END(ptr, fld) finishSection(ptr, TField::Field ## fld);
+#define SET(val, fld) storeSection(val, TField::Field ## fld);
+#define CLR(ptr, fld) ResetSection (TField::Field ## fld, ptr);
+#define REQ(ptr, req) setRequirement(ptr, TFeature :: req);
+
+ %% write init nocs;
+
+ if (0 == (Flags & TFeature::FeatureNoRelPath)) {
+ cs = TParser_en_URI_ref;
+ } else if (0 == (Flags & TFeature::FeatureAllowRootless)) {
+ cs = TParser_en_URI_ref_no_rootless;
+ } else {
+ cs = TParser_en_URI_ref_no_relpath;
+ }
+
+ %% write exec;
+
+#undef BEG
+#undef END
+#undef SET
+#undef CLR
+#undef REQ
+
+ return cs >= TParser_first_final;
+}
+
+}
diff --git a/library/cpp/uri/qargs.cpp b/library/cpp/uri/qargs.cpp
new file mode 100644
index 0000000000..23058f8102
--- /dev/null
+++ b/library/cpp/uri/qargs.cpp
@@ -0,0 +1,279 @@
+#include "qargs.h"
+#include <string>
+
+namespace NUri {
+ namespace NOnStackArgsList {
+ struct TQArgNode {
+ TQArgNode* Prev;
+ TQArgNode* Next;
+
+ TStringBuf Name;
+ TStringBuf Value;
+ TStringBuf All;
+ };
+
+ TQArgNode MakeArg(TQArgNode* prev) {
+ return {prev, 0, {}, {}, {}};
+ }
+
+ const char* SkipDelimiter(const char* str, const char* end) {
+ while (str != end)
+ if (*str == '&')
+ ++str;
+ else
+ break;
+ return str;
+ }
+
+ /// return next pos or 0 if error
+ const char* ExtractArgData(const char* pos, const char* end, TQArgNode* arg) {
+ const char* nameStart = pos;
+ const char* nextArg = strchr(pos, '&');
+ const char* valueStart = strchr(pos, '=');
+ if (valueStart && nextArg && valueStart < nextArg) // a=1& or a=&
+ {
+ arg->Name = TStringBuf(nameStart, valueStart - nameStart);
+ arg->Value = TStringBuf(valueStart + 1, nextArg - valueStart - 1);
+ arg->All = TStringBuf(nameStart, nextArg - nameStart);
+ return nextArg;
+ } else if (valueStart && nextArg && valueStart > nextArg) // a&b=2
+ {
+ arg->Name = TStringBuf(nameStart, nextArg - nameStart);
+ arg->All = arg->Name;
+ return nextArg;
+ } else if (valueStart && !nextArg) // a=1 or a=
+ {
+ arg->Name = TStringBuf(nameStart, valueStart - nameStart);
+ arg->Value = TStringBuf(valueStart + 1, end - valueStart - 1);
+ arg->All = TStringBuf(nameStart, end - nameStart);
+ return end;
+ } else if (!valueStart && nextArg) // a&b
+ {
+ arg->Name = TStringBuf(nameStart, nextArg - nameStart);
+ arg->All = arg->Name;
+ return nextArg;
+ } else { // a
+ arg->Name = TStringBuf(nameStart, end - nameStart);
+ arg->All = arg->Name;
+ return end;
+ }
+ }
+
+ // arg can be null
+ TQArgNode* GetHead(TQArgNode* arg) {
+ TQArgNode* prev = arg;
+ while (prev) {
+ arg = prev;
+ prev = prev->Prev;
+ }
+ return arg;
+ }
+
+ // arg can be null
+ TQArgNode* GetLast(TQArgNode* arg) {
+ TQArgNode* next = arg;
+ while (next) {
+ arg = next;
+ next = arg->Next;
+ }
+ return arg;
+ }
+
+ int CompareName(const TQArgNode* l, const TQArgNode* r) {
+ return l->Name.compare(r->Name);
+ }
+
+ TQArgNode* Move(TQArgNode* before, TQArgNode* node) {
+ TQArgNode* tn = node->Next;
+ TQArgNode* tp = node->Prev;
+
+ node->Prev = before->Prev;
+ if (node->Prev)
+ node->Prev->Next = node;
+
+ node->Next = before;
+ before->Prev = node;
+
+ if (tn)
+ tn->Prev = tp;
+ if (tp)
+ tp->Next = tn;
+
+ return node;
+ }
+
+ // return new head
+ TQArgNode* QSortByName(TQArgNode* iter, TQArgNode* last) {
+ if (iter == last)
+ return iter;
+ if (iter->Next == last) {
+ int c = CompareName(iter, last);
+ return c <= 0 ? iter : Move(iter, last);
+ } else {
+ TQArgNode* pivot = iter;
+ iter = iter->Next;
+ TQArgNode* head = 0;
+ TQArgNode* tail = 0;
+ TQArgNode* tailPartitionStart = pivot;
+ while (true) {
+ TQArgNode* next = iter->Next;
+ int c = CompareName(iter, pivot);
+ int sign = (0 < c) - (c < 0);
+ switch (sign) {
+ case -1:
+ head = head ? Move(head, iter) : Move(pivot, iter);
+ break;
+
+ case 0:
+ pivot = Move(pivot, iter);
+ break;
+
+ case 1:
+ tail = iter;
+ break;
+ }
+
+ if (iter == last)
+ break;
+ iter = next;
+ }
+
+ if (head)
+ head = QSortByName(head, pivot->Prev);
+ if (tail)
+ QSortByName(tailPartitionStart->Next, tail);
+ return head ? head : pivot;
+ }
+ }
+ }
+
+ using namespace NOnStackArgsList;
+
+ class TQueryArgProcessing::Pipeline {
+ public:
+ Pipeline(TQueryArgProcessing& parent, TUri& subject)
+ : Parent(parent)
+ , Subject(subject)
+ , ArgsCount(0)
+ , IsDirty(false)
+ {
+ }
+
+ TQueryArg::EProcessed Process() {
+ const TStringBuf& query = Subject.GetField(NUri::TField::FieldQuery);
+ if (query.empty())
+ return ProcessEmpty();
+
+ const char* start = query.data();
+ return Parse(start, start + query.length(), 0);
+ }
+
+ TQueryArg::EProcessed ProcessEmpty() {
+ if (Parent.Flags & TQueryArg::FeatureRemoveEmptyQuery)
+ Subject.FldClr(NUri::TField::FieldQuery);
+
+ return TQueryArg::ProcessedOK;
+ }
+
+ TQueryArg::EProcessed Parse(const char* str, const char* end, TQArgNode* prev) {
+ str = SkipDelimiter(str, end);
+
+ if (str == end) {
+ TQArgNode* head = GetHead(prev);
+ TQArgNode* last = GetLast(prev);
+ return FinalizeParsing(head, last);
+ } else {
+ TQArgNode current = MakeArg(prev);
+ const char* next = ExtractArgData(str, end, &current);
+ if (!next)
+ return TQueryArg::ProcessedMalformed;
+
+ TQArgNode* tail = ApplyFilter(prev, &current);
+
+ if (++ArgsCount > MaxCount)
+ return TQueryArg::ProcessedTooMany;
+
+ return Parse(next, end, tail);
+ }
+ }
+
+ TQArgNode* ApplyFilter(TQArgNode* prev, TQArgNode* current) {
+ if (Parent.Flags & TQueryArg::FeatureFilter) {
+ TQueryArg arg = {current->Name, current->Value};
+ if (!Parent.Filter(arg, Parent.FilterData)) {
+ IsDirty = true;
+ return prev;
+ }
+ }
+
+ if (prev)
+ prev->Next = current;
+ return current;
+ }
+
+ TQueryArg::EProcessed FinalizeParsing(TQArgNode* head, TQArgNode* last) {
+ if (Parent.Flags & TQueryArg::FeatureSortByName) {
+ head = QSortByName(head, last);
+ IsDirty = true;
+ }
+
+ if (!IsDirty)
+ return TQueryArg::ProcessedOK;
+
+ bool dirty = Render(head);
+
+ bool rewrite = Parent.Flags & TQueryArg::FeatureRewriteDirty;
+ if (dirty && rewrite)
+ Subject.Rewrite();
+ return (!dirty || rewrite) ? TQueryArg::ProcessedOK : TQueryArg::ProcessedDirty;
+ }
+
+ bool Render(TQArgNode* head) {
+ std::string& result = Parent.Buffer;
+ result.clear();
+ result.reserve(Subject.GetField(NUri::TField::FieldQuery).length());
+ bool first = true;
+ while (head) {
+ if (first)
+ first = false;
+ else
+ result.append("&");
+
+ result.append(head->All);
+ head = head->Next;
+ }
+
+ if (result.empty())
+ return RenderEmpty();
+ else
+ return Subject.FldMemSet(NUri::TField::FieldQuery, result);
+ }
+
+ bool RenderEmpty() {
+ if (Parent.Flags & TQueryArg::FeatureRemoveEmptyQuery)
+ Subject.FldClr(NUri::TField::FieldQuery);
+ return false;
+ }
+
+ private:
+ TQueryArgProcessing& Parent;
+ TUri& Subject;
+
+ unsigned ArgsCount;
+ bool IsDirty;
+
+ static const unsigned MaxCount = 100;
+ };
+
+ TQueryArgProcessing::TQueryArgProcessing(ui32 flags, TQueryArgFilter filter, void* filterData)
+ : Flags(flags)
+ , Filter(filter)
+ , FilterData(filterData)
+ {
+ }
+
+ TQueryArg::EProcessed TQueryArgProcessing::Process(TUri& uri) {
+ Pipeline pipeline(*this, uri);
+ return pipeline.Process();
+ }
+}
diff --git a/library/cpp/uri/qargs.h b/library/cpp/uri/qargs.h
new file mode 100644
index 0000000000..fcba7cbd0c
--- /dev/null
+++ b/library/cpp/uri/qargs.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "common.h"
+#include "uri.h"
+#include <string>
+
+namespace NUri {
+ class TQueryArgProcessing {
+ public:
+ TQueryArgProcessing(ui32 flags, TQueryArgFilter filter = 0, void* filterData = 0);
+
+ TQueryArg::EProcessed Process(TUri& uri);
+
+ private:
+ ui32 Flags;
+ TQueryArgFilter Filter;
+ void* FilterData;
+
+ class Pipeline;
+ std::string Buffer;
+ };
+}
diff --git a/library/cpp/uri/uri-ru_ut.cpp b/library/cpp/uri/uri-ru_ut.cpp
new file mode 100644
index 0000000000..ec35a164d2
--- /dev/null
+++ b/library/cpp/uri/uri-ru_ut.cpp
@@ -0,0 +1,163 @@
+#include "uri_ut.h"
+#include <library/cpp/charset/recyr.hh>
+#include <library/cpp/html/entity/htmlentity.h>
+#include <util/system/maxlen.h>
+
+namespace NUri {
+ namespace {
+ TString AsWin1251(const TString& s) {
+ return Recode(CODES_UTF8, CODES_WIN, s);
+ }
+ TString AsKoi8(const TString& s) {
+ return Recode(CODES_UTF8, CODES_KOI8, s);
+ }
+ }
+
+ Y_UNIT_TEST_SUITE(URLTestRU) {
+ Y_UNIT_TEST(test_httpURL2) {
+ TUri url;
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("g:h"), TState::ParsedBadScheme);
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("http:g"), TState::ParsedBadFormat);
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("/../g"), TState::ParsedBadPath);
+ const char* const UpCaseUrl = "http://www.TEST.Ru:80/InDex.html";
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse(UpCaseUrl), TState::ParsedOK);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://www.TEST.Ru/InDex.html");
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse(UpCaseUrl, TFeature::FeaturesDefault | TFeature::FeatureToLower), TState::ParsedOK);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://www.test.ru/InDex.html");
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(TField::FlagScheme), "http:");
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(TField::FlagScheme | TField::FlagHost), "http://www.test.ru");
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(TField::FlagHost), "www.test.ru");
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(TField::FlagHost | TField::FlagPath), "www.test.ru/InDex.html");
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(TField::FlagQuery), "");
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("http://www.TEST.Ru:90/InDex.html"), TState::ParsedOK);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(TField::FlagHostPort | TField::FlagPath), "www.TEST.Ru:90/InDex.html");
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("www.ya.ru/index.html"), TState::ParsedOK);
+ UNIT_ASSERT(!url.IsValidAbs());
+ UNIT_ASSERT(url.IsNull(TField::FlagHost));
+ UNIT_ASSERT(!url.IsNull(TField::FlagPath));
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(TField::FlagPath), "www.ya.ru/index.html");
+
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse(AsWin1251("www.TEST.Ru/ФЕУФ\\'\".html?ФЕУФ\\'\"=ФЕУФ+\\'\"%10")), TState::ParsedOK);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), AsWin1251("www.TEST.Ru/ФЕУФ\\'\".html?ФЕУФ\\'\"=ФЕУФ+\\'\"%10"));
+
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse(AsWin1251("www.TEST.Ru/ФЕУФ\\'\".html?ФЕУФ\\'\"=ФЕУФ+\\'\"%10"),
+ TFeature::FeaturesDefault | TFeature::FeatureEncodeExtendedASCII),
+ TState::ParsedOK);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(),
+ AsWin1251("www.TEST.Ru/%D4%C5%D3%D4\\'\".html?%D4%C5%D3%D4\\'\"=%D4%C5%D3%D4+\\'\"%10"));
+
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse(AsWin1251("www.TEST.Ru/ФЕУФ\\'\".html?ФЕУФ\\'\"=ФЕУФ+\\'\"%10"),
+ TFeature::FeaturesDefault | TFeature::FeatureEncodeForSQL),
+ TState::ParsedOK);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), AsWin1251("www.TEST.Ru/ФЕУФ%5C%27%22.html?ФЕУФ%5C%27%22=ФЕУФ+%5C%27%22%10"));
+
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("q/%33%26%13%2f%2b%30%20",
+ TFeature::FeaturesDefault | TFeature::FeatureDecodeStandard),
+ TState::ParsedOK);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "q/3%26%13/%2B0%20");
+
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("http://www.prime-tass.ru/news/0/{656F5BAE-6677-4762-9BED-9E3B77E72055}.uif"),
+ TState::ParsedOK);
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("//server/path"), TState::ParsedOK);
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("//server/path", TFeature::FeaturesRobot), TState::ParsedOK);
+ }
+
+ const TString links[] = {
+ "viewforum.php?f=1&amp;sid=b4568481b67b1d7683bea78634b2e240", "viewforum.php?f=1&sid=b4568481b67b1d7683bea78634b2e240",
+ "./viewtopic.php?p=74&amp;sid=6#p74", "./viewtopic.php?p=74&sid=6#p74",
+ "viewtopic.php?p=9313&amp;sid=8#9313", "viewtopic.php?p=9313&sid=8#9313",
+ "profile.php?mode=viewprofile&u=-1#drafts&amp;sid=a6e5989cee27adb5996bfff044af04ca", "profile.php?mode=viewprofile&u=-1#drafts&sid=a6e5989cee27adb5996bfff044af04ca",
+
+ "images\nil.jpg", "images%0Ail.jpg",
+ "http://caedebaturque.termez.su\r\n/?article=218", "http://caedebaturque.termez.su%0D%0A/?article=218",
+
+ AsKoi8("javascript:window.external.AddFavorite(\'http://www.humor.look.ru/\',\'Злобные Деды Морозы!!!\')"), "javascript:window.external.AddFavorite(\'http://www.humor.look.ru/\',\'%FA%CC%CF%C2%CE%D9%C5%20%E4%C5%C4%D9%20%ED%CF%D2%CF%DA%D9!!!\')",
+ "search.php?search_author=%CB%FE%E4%EC%E8%EB%E0+%C3%F3%F1%E5%E2%E0&amp;showresults=posts&amp;sid=8", "search.php?search_author=%CB%FE%E4%EC%E8%EB%E0+%C3%F3%F1%E5%E2%E0&showresults=posts&sid=8",
+ AsWin1251("/Search/author/?q=Штрибель Х.В."), "/Search/author/?q=%D8%F2%F0%E8%E1%E5%EB%FC%20%D5.%C2.",
+ AsWin1251("javascript:ins(\'ГОРШОК\')"), "javascript:ins(\'%C3%CE%D0%D8%CE%CA\')",
+ AsWin1251("?l=я"), "?l=%FF",
+ AsWin1251("content.php?id=3392&theme=Цена"), "content.php?id=3392&theme=%D6%E5%ED%E0",
+ "/a-mp3/stype-1/?search=А", "/a-mp3/stype-1/?search=%D0%90",
+ "/a-mp3/stype-1/?search=Б", "/a-mp3/stype-1/?search=%D0%91",
+ "/a-mp3/stype-1/?search=В", "/a-mp3/stype-1/?search=%D0%92",
+ "/a-mp3/stype-1/?search=Г", "/a-mp3/stype-1/?search=%D0%93",
+ "/a-mp3/stype-1/?search=Д", "/a-mp3/stype-1/?search=%D0%94",
+ "/a-mp3/stype-1/?search=Е", "/a-mp3/stype-1/?search=%D0%95",
+ "/a-mp3/stype-1/?search=Ж", "/a-mp3/stype-1/?search=%D0%96",
+ "/a-mp3/stype-1/?search=З", "/a-mp3/stype-1/?search=%D0%97",
+ // %98 is not defined in CP1251 so don't put it here explicitly
+ "/a-mp3/stype-1/?search=\xD0\x98", "/a-mp3/stype-1/?search=%D0%98",
+ "/a-mp3/stype-1/?search=Й", "/a-mp3/stype-1/?search=%D0%99",
+ "/a-mp3/stype-1/?search=К", "/a-mp3/stype-1/?search=%D0%9A",
+ "/a-mp3/stype-1/?search=Л", "/a-mp3/stype-1/?search=%D0%9B",
+ "/a-mp3/stype-1/?search=М", "/a-mp3/stype-1/?search=%D0%9C",
+ "/a-mp3/stype-1/?search=Н", "/a-mp3/stype-1/?search=%D0%9D",
+ "/a-mp3/stype-1/?search=О", "/a-mp3/stype-1/?search=%D0%9E",
+ "/a-mp3/stype-1/?search=П", "/a-mp3/stype-1/?search=%D0%9F",
+ "/a-mp3/stype-1/?search=\xD0", "/a-mp3/stype-1/?search=%D0",
+ "/a-mp3/stype-1/?search=С", "/a-mp3/stype-1/?search=%D0%A1",
+ "/a-mp3/stype-1/?search=Т", "/a-mp3/stype-1/?search=%D0%A2",
+ "/a-mp3/stype-1/?search=У", "/a-mp3/stype-1/?search=%D0%A3",
+ "/a-mp3/stype-1/?search=Ф", "/a-mp3/stype-1/?search=%D0%A4",
+ "/a-mp3/stype-1/?search=Х", "/a-mp3/stype-1/?search=%D0%A5",
+ "/a-mp3/stype-1/?search=Ц", "/a-mp3/stype-1/?search=%D0%A6",
+ "/a-mp3/stype-1/?search=Ч", "/a-mp3/stype-1/?search=%D0%A7",
+ "/a-mp3/stype-1/?search=Ш", "/a-mp3/stype-1/?search=%D0%A8",
+ "/a-mp3/stype-1/?search=Щ", "/a-mp3/stype-1/?search=%D0%A9",
+ "/a-mp3/stype-1/?search=Ы", "/a-mp3/stype-1/?search=%D0%AB",
+ "/a-mp3/stype-1/?search=Э", "/a-mp3/stype-1/?search=%D0%AD",
+ "/a-mp3/stype-1/?search=Ю", "/a-mp3/stype-1/?search=%D0%AE",
+ "/a-mp3/stype-1/?search=Я", "/a-mp3/stype-1/?search=%D0%AF",
+
+ "javascript:emoticon(\":&#39;(\")", "javascript:emoticon(\":\'(\")",
+ "javascript:emoticon(\'&gt;:o\')", "javascript:emoticon(\'>:o\')",
+ "javascript:emoticon(\']:-&gt;\')", "javascript:emoticon(\']:->\')",
+ "javascript:emoticon(\':-&#33;\')", "javascript:emoticon(\':-!\')",
+ "javascript:emoticon(\'@}-&gt;--\')", "javascript:emoticon(\'@}->--\')",
+ "http&#58;//www.is-ufa.ru/price2/price_IS.rar", "http://www.is-ufa.ru/price2/price_IS.rar",
+ "&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#105;&#110;&#102;&#111;&#64;&#101;&#116;&#101;&#109;&#46;&#100;&#101;", "mailto:info@etem.de",
+ "&quot;http://www.fubix.ru&quot;", "\"http://www.fubix.ru\"",
+ AsWin1251("mailto:&#107;&#97;&#109;&#112;&#97;&#64;&#117;&#107;&#114;&#46;&#110;&#101;&#116;?subject=Арабский язык"), "mailto:kampa@ukr.net?subject=%C0%F0%E0%E1%F1%EA%E8%E9%20%FF%E7%FB%EA",
+ {}};
+
+ Y_UNIT_TEST(testHtLinkDecode) {
+ char decodedlink[URL_MAXLEN + 10];
+ for (int i = 0; links[i]; i += 2) {
+ UNIT_ASSERT(HtLinkDecode(links[i].c_str(), decodedlink, sizeof(decodedlink)));
+ UNIT_ASSERT_VALUES_EQUAL(decodedlink, links[i + 1]);
+ }
+ }
+
+ Y_UNIT_TEST(testRuIDNA) {
+ {
+#define DEC "\xD7\xE5\xF0\xE5\xEf\xEE\xE2\xE5\xF6.\xF0\xF4" /* "Череповец.рф" in Windows-1251 */
+#define ENC "%D7%E5%F0%E5%EF%EE%E2%E5%F6.%F0%F4"
+// punycode corresponds to lowercase
+#define PNC "xn--b1afab7bff7cb.xn--p1ai"
+ TTest test = {
+ "http://" ENC "/" ENC "?" ENC "#" ENC, TParseFlags(TFeature::FeaturesAll | TFeature::FeatureAllowHostIDN, TFeature::FeatureDecodeExtendedASCII), TState::ParsedOK, "http", "", "", DEC, 80, "/" ENC, ENC, ENC};
+ TUri url;
+ URL_TEST_ENC(url, test, CODES_WIN);
+ UNIT_ASSERT_VALUES_EQUAL(url.GetField(TField::FieldHostAscii), PNC);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://" DEC "/" ENC "?" ENC "#" ENC);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(TField::FlagHostAscii), "http://" PNC "/" ENC "?" ENC "#" ENC);
+#undef PNC
+#undef DEC
+#undef ENC
+ }
+ }
+
+ // Regression test for SEARCH-11283
+ Y_UNIT_TEST(RegressionTest11283) {
+ TStringBuf url = "http://xn--n1aaa.пидорасы.com/";
+
+ TUri uri;
+ TState::EParsed er = uri.Parse(url, NUri::TParseFlags(NUri::TFeature::FeaturesRobot | NUri::TFeature::FeatureNoRelPath));
+ UNIT_ASSERT_VALUES_EQUAL(er, TState::ParsedOK);
+ TStringBuf host = uri.GetHost();
+ // Should be properly null-terminated
+ UNIT_ASSERT_VALUES_EQUAL(host.size(), strlen(host.data()));
+ }
+ }
+
+}
diff --git a/library/cpp/uri/uri.cpp b/library/cpp/uri/uri.cpp
new file mode 100644
index 0000000000..1664e8c8dd
--- /dev/null
+++ b/library/cpp/uri/uri.cpp
@@ -0,0 +1,623 @@
+#include "uri.h"
+#include "parse.h"
+
+#include <util/string/cast.h>
+#include <util/string/util.h>
+#include <util/system/maxlen.h>
+#include <util/system/yassert.h>
+#include <util/generic/map.h>
+
+namespace NUri {
+ TState::EParsed TUri::CheckHost(const TStringBuf& host) {
+ if (host.empty())
+ return ParsedOK;
+
+ unsigned domainLevel = 0;
+ unsigned domainLevelOfUnderscore = 0;
+
+ bool isAlnum = false;
+ bool startLabel = true;
+ for (size_t i = 0; i != host.length(); ++i) {
+ const char ch = host[i];
+
+ if ('.' == ch) { // label separator
+ if (!isAlnum || startLabel) // previous label must end in alnum
+ return ParsedBadHost;
+ startLabel = true;
+ continue;
+ }
+
+ isAlnum = isalnum((const unsigned char)ch);
+
+ if (startLabel) { // label is starting
+ if (!isAlnum && '_' != ch) // new label must start with alnum or '_'
+ return ParsedBadHost;
+ startLabel = false;
+ ++domainLevel;
+ if (ch == '_')
+ domainLevelOfUnderscore = domainLevel;
+ continue;
+ }
+
+ if (isAlnum || '-' == ch)
+ continue;
+
+ if (ch == '_') { // non-standard case we allow for certain hosts
+ domainLevelOfUnderscore = domainLevel;
+ continue;
+ }
+
+ return ParsedBadHost;
+ }
+
+ if (0 < domainLevelOfUnderscore && domainLevel < 2 + domainLevelOfUnderscore)
+ return ParsedBadHost;
+
+ return ParsedOK;
+ }
+
+ /********************************************************/
+ TUri::TUri(const TStringBuf& host, ui16 port, const TStringBuf& path, const TStringBuf& query, const TStringBuf& scheme, unsigned defaultPort)
+ : FieldsSet(0)
+ , Port(port)
+ , DefaultPort(0)
+ , Scheme(SchemeEmpty)
+ , FieldsDirty(0)
+ {
+ if (!scheme.empty()) {
+ if (SetSchemeImpl(TSchemeInfo::Get(scheme)).Str.empty())
+ FldSet(FieldScheme, scheme);
+ }
+
+ if (0 < defaultPort) // override the scheme's default port
+ DefaultPort = static_cast<ui16>(defaultPort);
+
+ char sport[6]; // enough for ui16
+ if (0 != port) {
+ const size_t len = ToString(port, sport, sizeof(sport));
+ FldSet(FieldPort, TStringBuf(sport, len));
+ }
+
+ FldTrySet(FieldHost, host);
+ FldTrySet(FieldPath, path);
+ FldTrySet(FieldQuery, query);
+
+ Rewrite();
+ }
+
+ /********************************************************/
+ bool TUri::FldSetImpl(
+ EField field, TStringBuf value, bool strconst, bool nocopy) {
+ if (!FldIsValid(field))
+ return false;
+
+ switch (field) {
+ case FieldScheme:
+ if (!SetScheme(TSchemeInfo::Get(value)).Str.empty())
+ return false;
+ break;
+
+ case FieldPort:
+ Port = value.empty() ? 0 : FromString<ui16>(value);
+ break;
+
+ default:
+ break;
+ }
+
+ if (!value.IsInited()) {
+ FldClr(field);
+ return false;
+ }
+
+ if (strconst) { // string constants don't need to be saved in the buffer
+ FldMarkClean(field);
+ FldSetNoDirty(field, value);
+ return false;
+ }
+
+ if (nocopy) {
+ FldSet(field, value);
+ return true;
+ }
+
+ return FldTryCpy(field, value);
+ }
+
+ /********************************************************/
+ bool TUri::FldTryCpy(EField field, const TStringBuf& value) {
+ if (!FldIsDirty(field)) {
+ do {
+ if (!FldIsSet(field))
+ break;
+
+ TStringBuf& fld = Fields[field];
+ if (fld.length() < value.length())
+ break;
+
+ char* oldV = (char*)fld.data();
+ if (!IsInBuffer(oldV))
+ break;
+
+ memcpy(oldV, value.data(), value.length());
+ oldV[value.length()] = 0;
+ fld.Trunc(value.length());
+ return false;
+ } while (false);
+
+ FldMarkDirty(field);
+ }
+
+ FldSetNoDirty(field, value);
+ return true;
+ }
+
+ /********************************************************/
+ void TUri::RewriteImpl() {
+ size_t len = 0;
+ for (int i = 0; i < FieldAllMAX; ++i) {
+ const EField fld = EField(i);
+ if (FldIsSet(fld))
+ len += 1 + Fields[fld].length();
+ }
+
+ if (!len)
+ Buffer.Clear();
+ else {
+ TBuffer newbuf;
+ newbuf.Resize(len);
+ TMemoryWriteBuffer out(newbuf.data(), newbuf.size());
+ for (int i = 0; i < FieldAllMAX; ++i) {
+ const EField fld = EField(i);
+ if (!FldIsSet(fld))
+ continue;
+
+ const char* beg = out.Buf();
+ const TStringBuf& val = Fields[fld];
+ out << val;
+ FldSetNoDirty(fld, TStringBuf(beg, val.length()));
+ out << '\0';
+ }
+ Buffer = std::move(newbuf);
+ }
+
+ CheckMissingFields();
+
+ FieldsDirty = 0;
+ }
+
+ void TUri::CheckMissingFields() {
+ // if host is set but path is not...
+ if (FldSetCmp(FlagPath | FlagHost, FlagHost))
+ // ... and the scheme requires a path...
+ if (GetSchemeInfo().FldReq & FlagPath)
+ // ... set path
+ FldSetNoDirty(FieldPath, TStringBuf("/"));
+ }
+
+ /********************************************************/
+ void TUri::Merge(const TUri& base, int correctAbs) {
+ if (base.Scheme == SchemeUnknown)
+ return;
+
+ if (!base.IsValidGlobal())
+ return;
+
+ const TStringBuf& selfscheme = GetField(FieldScheme);
+ // basescheme is present since IsValidGlobal() succeeded
+ const TStringBuf& basescheme = base.GetField(FieldScheme);
+ const bool noscheme = !selfscheme.IsInited();
+ if (!noscheme && !EqualNoCase(selfscheme, basescheme))
+ return;
+
+ const ui32 cleanFields = ~FieldsDirty;
+ do {
+ static constexpr TStringBuf rootPath = "/";
+
+ if (noscheme) {
+ if (!basescheme.empty()) {
+ FldSetNoDirty(FieldScheme, basescheme);
+ // check if it is canonical
+ if (basescheme.data() != base.GetSchemeInfo().Str.data())
+ FldMarkDirty(FieldScheme);
+ }
+ Scheme = base.Scheme;
+ DefaultPort = base.DefaultPort;
+ }
+
+ if (!IsNull(FlagHost))
+ break; // no merge
+
+ FldTrySet(FieldHost, base);
+ FldChkSet(FieldPort, base);
+ Port = base.Port;
+
+ if (noscheme && IsNull(FlagQuery) && IsNull(FlagPath))
+ FldTrySet(FieldQuery, base);
+
+ if (IsNull(FlagAuth) && !base.IsNull(FlagAuth)) {
+ FldChkSet(FieldUser, base);
+ FldChkSet(FieldPass, base);
+ }
+
+ if (IsValidAbs())
+ break;
+
+ TStringBuf p0 = base.GetField(FieldPath);
+ if (!p0.IsInited())
+ p0 = rootPath;
+
+ TStringBuf p1 = GetField(FieldPath);
+ if (!p1.IsInited()) {
+ if (p0.data() != rootPath.data())
+ FldSet(FieldPath, p0);
+ else
+ FldSetNoDirty(FieldPath, rootPath);
+ break;
+ }
+ if (p1 && '/' == p1[0])
+ p1.Skip(1); // p0 will have one
+
+ bool pathop = true;
+
+ TTempBufOutput out(p0.length() + p1.length() + 4);
+ out << p0;
+ if ('/' != p0.back())
+ out << "/../";
+ else if (p1.empty() || '.' != p1[0])
+ pathop = false;
+ out << p1;
+
+ char* beg = out.Data();
+ char* end = beg + out.Filled();
+ if (pathop && !PathOperation(beg, end, correctAbs)) {
+ Clear();
+ break;
+ }
+
+ // Needs immediate forced rewrite because of TTempBuf
+ FldSetNoDirty(FieldPath, TStringBuf(beg, end));
+ RewriteImpl();
+ } while (false);
+
+ CheckMissingFields();
+
+ // rewrite only if borrowed fields from base
+ if (cleanFields & FieldsDirty)
+ RewriteImpl();
+ }
+
+ /********************************************************/
+ TUri::TLinkType TUri::Normalize(const TUri& base,
+ const TStringBuf& link, const TStringBuf& codebase, long careFlags, ECharset enc) {
+ // parse URL
+ if (ParsedOK != ParseImpl(link, careFlags, 0, SchemeEmpty, enc))
+ return LinkIsBad;
+
+ const TStringBuf& host = GetHost();
+
+ // merge with base URL
+ // taken either from _BASE_ property or from optional argument
+ if (!codebase.empty()) {
+ // if optional code base given -- parse it
+ TUri codebaseUrl;
+ if (codebaseUrl.ParseImpl(codebase, careFlags, 0, SchemeEmpty, enc) != ParsedOK || !codebaseUrl.IsValidAbs())
+ return LinkIsBad;
+ Merge(codebaseUrl);
+ } else {
+ // Base is already in this variable
+ // see SetProperty() for details
+ Merge(base);
+ }
+
+ // check result: must be correct absolute URL
+ if (!IsValidAbs())
+ return LinkBadAbs;
+
+ if (!host.empty()) {
+ // - we don't care about different ports for the same server
+ // - we don't care about win|www|koi|etc. preffixes for the same server
+ if (GetPort() != base.GetPort() || !EqualNoCase(host, base.GetHost()))
+ return LinkIsGlobal;
+ }
+
+ // find out if it is link to itself then ignore it
+ if (!Compare(base, FlagPath | FlagQuery))
+ return LinkIsFragment;
+
+ return LinkIsLocal;
+ }
+
+ /********************************************************/
+
+ size_t TUri::PrintSize(ui32 flags) const {
+ size_t len = 10;
+ flags &= FieldsSet; // can't output what we don't have
+ if (flags & FlagHostAscii)
+ flags &= ~FlagHost; // don't want to print both of them
+ ui32 opt = 1;
+ for (int fld = 0; opt <= flags && fld < FieldAllMAX; ++fld, opt <<= 1) {
+ if (opt & flags) {
+ const TStringBuf& v = Fields[fld];
+ if (v.IsInited()) {
+ if (opt & FlagAuth)
+ len += 3 * v.length() + 1;
+ else
+ len += v.length() + 1;
+ }
+ }
+ }
+
+ return len;
+ }
+
+ IOutputStream& TUri::PrintImpl(IOutputStream& out, int flags) const {
+ TStringBuf v;
+
+ const int wantFlags = flags; // save the original
+ flags &= FieldsSet; // can't print what we don't have
+ if (flags & FlagHostAscii)
+ flags |= FlagHost; // to make host checks simpler below
+
+ if (flags & FlagScheme) {
+ v = Fields[FieldScheme];
+ if (!v.empty())
+ out << v << ':';
+ }
+
+ TStringBuf host;
+ if (flags & FlagHost) {
+ const EField fldhost =
+ flags & FlagHostAscii ? FieldHostAscii : FieldHost;
+ host = Fields[fldhost];
+ }
+
+ TStringBuf port;
+ if ((flags & FlagPort) && 0 != Port && Port != DefaultPort)
+ port = Fields[FieldPort];
+
+ if (host) {
+ if (wantFlags & FlagScheme)
+ out << "//";
+
+ if (flags & FlagAuth) {
+ if (flags & FlagUser) {
+ v = Fields[FieldUser];
+ if (!v.empty())
+ TEncoder::EncodeNotAlnum(out, v);
+ }
+
+ if (flags & FlagPass) {
+ v = Fields[FieldPass];
+ if (v.IsInited()) {
+ out << ':';
+ TEncoder::EncodeAll(out, v);
+ }
+ }
+
+ out << '@';
+ }
+
+ out << host;
+
+ if (port)
+ out << ':';
+ }
+ if (port)
+ out << port;
+
+ if (flags & FlagPath) {
+ v = Fields[FieldPath];
+ // for relative, empty path is not the same as missing
+ if (v.empty() && 0 == (flags & FlagHost))
+ v = TStringBuf(".");
+ out << v;
+ }
+
+ if (flags & FlagQuery) {
+ v = Fields[FieldQuery];
+ if (v.IsInited())
+ out << '?' << v;
+ }
+
+ if (flags & FlagFrag) {
+ v = Fields[FieldFrag];
+ if (v.IsInited())
+ out << '#' << v;
+ }
+
+ return out;
+ }
+
+ /********************************************************/
+ int TUri::CompareField(EField fld, const TUri& url) const {
+ const TStringBuf& v0 = GetField(fld);
+ const TStringBuf& v1 = url.GetField(fld);
+ switch (fld) {
+ case FieldScheme:
+ case FieldHost:
+ return CompareNoCase(v0, v1);
+ default:
+ return v0.compare(v1);
+ }
+ }
+
+ /********************************************************/
+ int TUri::Compare(const TUri& url, int flags) const {
+ // first compare fields with default values
+ if (flags & FlagPort) {
+ const int ret = GetPort() - url.GetPort();
+ if (ret)
+ return ret;
+ flags &= ~FlagPort;
+ }
+
+ // compare remaining sets of available fields
+ const int rtflags = flags & url.FieldsSet;
+ flags &= FieldsSet;
+ const int fldcmp = flags - rtflags;
+ if (fldcmp)
+ return fldcmp;
+
+ // field sets are the same, compare the fields themselves
+ for (int i = 0; i < FieldAllMAX; ++i) {
+ const EField fld = EField(i);
+ if (flags & FldFlag(fld)) {
+ const int ret = CompareField(fld, url);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+ }
+
+ /********************************************************/
+ bool TUri::PathOperation(char*& pathPtr, char*& pathEnd, int correctAbs) {
+ if (!pathPtr)
+ return false;
+ if (pathPtr == pathEnd)
+ return true;
+
+ if ((pathEnd - pathPtr) >= 2 && *(pathEnd - 2) == '/' && *(pathEnd - 1) == '.') {
+ --pathEnd;
+ }
+
+ char* p_wr = pathEnd;
+ int upCount = 0;
+
+ char* p_prev = pathEnd;
+ Y_ASSERT(p_prev > pathPtr);
+ while (p_prev > pathPtr && *(p_prev - 1) == '/')
+ p_prev--;
+
+ for (char* p_rd = p_prev; p_rd; p_rd = p_prev) {
+ Y_ASSERT(p_rd == pathEnd || p_rd[0] == '/');
+ p_prev = nullptr;
+
+ char* p = p_rd;
+
+ if (p > pathPtr) {
+ for (p--; *p != '/'; p--) {
+ if (p == pathPtr)
+ break;
+ }
+ if (*p == '/') {
+ p_prev = p++;
+ if ((p_prev - pathPtr >= 6 && !strnicmp(p_prev - 6, "http://", 7)) ||
+ (p_prev - pathPtr >= 7 && !strnicmp(p_prev - 7, "https://", 8))) {
+ --p_prev;
+ --p;
+ } else {
+ //skip multiple from head '/'
+ while (p_prev > pathPtr && *(p_prev - 1) == '/')
+ p_prev--;
+ }
+ }
+ }
+
+ Y_ASSERT(p_prev == nullptr || p_prev[0] == '/');
+ //and the first symbol !='/' after p_prev is p
+
+ if (p == p_rd) {
+ //empty block:
+ if (p_prev) { //either tail:
+ Y_ASSERT(p_rd == p_wr && *(p - 1) == '/');
+ --p_wr;
+ continue;
+ } else { //or head of abs path
+ *(--p_wr) = '/';
+ break;
+ }
+ }
+
+ if (p[0] == '.') {
+ if (p + 1 == p_rd) {
+ if (correctAbs || p_prev > pathPtr || pathPtr[0] != '/')
+ // ignore "./"
+ continue;
+ } else {
+ if ((p[1] == '.') && (p + 2 == p_rd)) {
+ // register "../" but not print
+ upCount++;
+ continue;
+ }
+ }
+ }
+
+ if (upCount) {
+ //unregister "../" and not print
+ upCount--;
+ continue;
+ }
+
+ // print
+ Y_ASSERT(p < p_rd);
+ Y_ASSERT(!p_prev || *(p - 1) == '/');
+ if (p_wr == p_rd) { //just skip
+ p_wr = p;
+ } else { //copy
+ int l = p_rd - p + 1;
+ p_wr -= l;
+ memmove(p_wr, p, l);
+ }
+ }
+
+ if (upCount) {
+ if (*pathPtr != '/') {
+ if (pathEnd == p_wr && *(p_wr - 1) == '.') {
+ Y_ASSERT(*(p_wr - 2) == '.');
+ p_wr -= 2;
+ upCount--;
+ }
+ for (; upCount > 0; upCount--) {
+ *(--p_wr) = '/';
+ *(--p_wr) = '.';
+ *(--p_wr) = '.';
+ }
+ } else {
+ if (correctAbs > 0)
+ return false;
+ if (correctAbs == 0) {
+ //Bad path but present in RFC:
+ // "Similarly, parsers must avoid treating "." and ".."
+ // as special when they are not complete components of
+ // a relative path. "
+ for (; upCount > 0; upCount--) {
+ *(--p_wr) = '.';
+ *(--p_wr) = '.';
+ *(--p_wr) = '/';
+ }
+ } else {
+ upCount = false;
+ }
+ }
+ }
+
+ Y_ASSERT(p_wr >= pathPtr);
+
+ if (upCount)
+ return false;
+ pathPtr = p_wr;
+ return true;
+ }
+
+ /********************************************************/
+ const char* LinkTypeToString(const TUri::TLinkType& t) {
+ switch (t) {
+ case TUri::LinkIsBad:
+ return "LinkIsBad";
+ case TUri::LinkBadAbs:
+ return "LinkBadAbs";
+ case TUri::LinkIsFragment:
+ return "LinkIsFragment";
+ case TUri::LinkIsLocal:
+ return "LinkIsLocal";
+ case TUri::LinkIsGlobal:
+ return "LinkIsGlobal";
+ }
+ Y_ASSERT(0);
+ return "";
+ }
+
+}
diff --git a/library/cpp/uri/uri.h b/library/cpp/uri/uri.h
new file mode 100644
index 0000000000..3b6c19fe4a
--- /dev/null
+++ b/library/cpp/uri/uri.h
@@ -0,0 +1,626 @@
+#pragma once
+
+#include "common.h"
+#include "encode.h"
+
+#include <library/cpp/charset/doccodes.h>
+#include <util/generic/buffer.h>
+#include <util/generic/ptr.h>
+#include <util/generic/singleton.h>
+#include <util/generic/string.h>
+#include <util/memory/alloc.h>
+#include <util/stream/mem.h>
+#include <util/stream/output.h>
+#include <util/stream/str.h>
+#include <util/system/yassert.h>
+
+#include <cstdlib>
+
+namespace NUri {
+ /********************************************************/
+ class TUri
+ : public TFeature,
+ public TField,
+ public TScheme,
+ public TState {
+ public:
+ enum TLinkType {
+ LinkIsBad,
+ LinkBadAbs,
+ LinkIsFragment,
+ LinkIsLocal,
+ LinkIsGlobal
+ };
+
+ private:
+ TBuffer Buffer;
+ TStringBuf Fields[FieldAllMAX];
+ ui32 FieldsSet;
+ ui16 Port;
+ ui16 DefaultPort;
+ TScheme::EKind Scheme;
+ /// contains fields out of buffer (and possibly not null-terminated)
+ ui32 FieldsDirty;
+
+ private:
+ void Alloc(size_t len) {
+ Dealloc(); // to prevent copy below
+ Buffer.Resize(len);
+ }
+ void Dealloc() {
+ Buffer.Clear();
+ }
+
+ void ClearImpl() {
+ Port = 0;
+ FieldsSet = 0;
+ Scheme = SchemeEmpty;
+ FieldsDirty = 0;
+ }
+
+ void CopyData(const TUri& url) {
+ FieldsSet = url.FieldsSet;
+ Port = url.Port;
+ DefaultPort = url.DefaultPort;
+ Scheme = url.Scheme;
+ FieldsDirty = url.FieldsDirty;
+ }
+
+ void CopyImpl(const TUri& url) {
+ for (int i = 0; i < FieldAllMAX; ++i)
+ Fields[i] = url.Fields[i];
+
+ RewriteImpl();
+ }
+
+ private:
+ static ui32 FldFlag(EField fld) {
+ return 1 << fld;
+ }
+
+ public:
+ static bool FldIsValid(EField fld) {
+ return 0 <= fld && FieldAllMAX > fld;
+ }
+
+ bool FldSetCmp(ui32 chk, ui32 exp) const {
+ return (FieldsSet & chk) == exp;
+ }
+
+ bool FldSetCmp(ui32 chk) const {
+ return FldSetCmp(chk, chk);
+ }
+
+ bool FldIsSet(EField fld) const {
+ return !FldSetCmp(FldFlag(fld), 0);
+ }
+
+ private:
+ void FldMarkSet(EField fld) {
+ FieldsSet |= FldFlag(fld);
+ }
+
+ void FldMarkUnset(EField fld) {
+ FieldsSet &= ~FldFlag(fld);
+ }
+
+ // use when we know the field is dirty or RewriteImpl will be called
+ void FldSetNoDirty(EField fld, const TStringBuf& value) {
+ Fields[fld] = value;
+ FldMarkSet(fld);
+ }
+
+ void FldSet(EField fld, const TStringBuf& value) {
+ FldSetNoDirty(fld, value);
+ FldMarkDirty(fld);
+ }
+
+ const TStringBuf& FldGet(EField fld) const {
+ return Fields[fld];
+ }
+
+ private:
+ /// depending on value, clears or sets it
+ void FldChkSet(EField fld, const TStringBuf& value) {
+ if (value.IsInited())
+ FldSet(fld, value);
+ else
+ FldClr(fld);
+ }
+ void FldChkSet(EField fld, const TUri& other) {
+ FldChkSet(fld, other.GetField(fld));
+ }
+
+ /// set only if initialized
+ bool FldTrySet(EField fld, const TStringBuf& value) {
+ const bool ok = value.IsInited();
+ if (ok)
+ FldSet(fld, value);
+ return ok;
+ }
+ bool FldTrySet(EField fld, const TUri& other) {
+ return FldTrySet(fld, other.GetField(fld));
+ }
+
+ private:
+ /// copies the value if it fits
+ bool FldTryCpy(EField fld, const TStringBuf& value);
+
+ // main method: sets the field value, possibly copies, etc.
+ bool FldSetImpl(EField fld, TStringBuf value, bool strconst = false, bool nocopy = false);
+
+ public: // clear a field
+ void FldClr(EField fld) {
+ Fields[fld].Clear();
+ FldMarkUnset(fld);
+ FldMarkClean(fld);
+ }
+
+ bool FldTryClr(EField field) {
+ const bool ok = FldIsSet(field);
+ if (ok)
+ FldClr(field);
+ return ok;
+ }
+
+ public: // set a field value: might leave state dirty and require a Rewrite()
+ // copies if fits and not dirty, sets and marks dirty otherwise
+ bool FldMemCpy(EField field, const TStringBuf& value) {
+ return FldSetImpl(field, value, false);
+ }
+
+ // uses directly, marks dirty
+ /// @note client MUST guarantee value will be alive until Rewrite is called
+ bool FldMemSet(EField field, const TStringBuf& value) {
+ return FldSetImpl(field, value, false, true);
+ }
+
+ // uses directly, doesn't mark dirty (value scope exceeds "this")
+ bool FldMemUse(EField field, const TStringBuf& value) {
+ return FldSetImpl(field, value, true);
+ }
+
+ // uses directly, doesn't mark dirty
+ template <size_t size>
+ bool FldMemSet(EField field, const char (&value)[size]) {
+ static_assert(size > 0);
+ return FldSetImpl(field, TStringBuf(value, size - 1), true);
+ }
+
+ // duplicate one field to another
+ bool FldDup(EField src, EField dst) {
+ if (!FldIsSet(src) || !FldIsValid(dst))
+ return false;
+ FldSetNoDirty(dst, FldGet(src));
+ if (FldIsDirty(src))
+ FldMarkDirty(dst);
+ else
+ FldMarkClean(dst);
+ return true;
+ }
+
+ // move one field to another
+ bool FldMov(EField src, EField dst) {
+ if (!FldDup(src, dst))
+ return false;
+ FldClr(src);
+ return true;
+ }
+
+ private:
+ bool IsInBuffer(const char* buf) const {
+ return buf >= Buffer.data() && buf < Buffer.data() + Buffer.size();
+ }
+
+ public:
+ bool FldIsDirty() const {
+ return 0 != FieldsDirty;
+ }
+
+ bool FldIsDirty(EField fld) const {
+ return 0 != (FieldsDirty & FldFlag(fld));
+ }
+
+ private:
+ void FldMarkDirty(EField fld) {
+ FieldsDirty |= FldFlag(fld);
+ }
+
+ void FldMarkClean(EField fld) {
+ FieldsDirty &= ~FldFlag(fld);
+ }
+
+ void RewriteImpl();
+
+ public:
+ static TState::EParsed CheckHost(const TStringBuf& host);
+
+ // convert a [potential] IDN to ascii
+ static TMallocPtr<char> IDNToAscii(const wchar32* idna);
+ static TMallocPtr<char> IDNToAscii(const TStringBuf& host, ECharset enc = CODES_UTF8);
+
+ // convert hosts with percent-encoded or extended chars
+
+ // returns non-empty string if host can be converted to ASCII with given parameters
+ static TStringBuf HostToAscii(TStringBuf host, TMallocPtr<char>& buf, bool hasExtended, bool allowIDN, ECharset enc = CODES_UTF8);
+
+ // returns host if already ascii, or non-empty if it can be converted
+ static TStringBuf HostToAscii(const TStringBuf& host, TMallocPtr<char>& buf, bool allowIDN, ECharset enc = CODES_UTF8);
+
+ public:
+ explicit TUri(unsigned defaultPort = 0)
+ : FieldsSet(0)
+ , Port(0)
+ , DefaultPort(static_cast<ui16>(defaultPort))
+ , Scheme(SchemeEmpty)
+ , FieldsDirty(0)
+ {
+ }
+
+ TUri(const TStringBuf& host, ui16 port, const TStringBuf& path, const TStringBuf& query = TStringBuf(), const TStringBuf& scheme = "http", unsigned defaultPort = 0);
+
+ TUri(const TUri& url)
+ : FieldsSet(url.FieldsSet)
+ , Port(url.Port)
+ , DefaultPort(url.DefaultPort)
+ , Scheme(url.Scheme)
+ , FieldsDirty(url.FieldsDirty)
+ {
+ CopyImpl(url);
+ }
+
+ ~TUri() {
+ Clear();
+ }
+
+ void Copy(const TUri& url) {
+ if (&url != this) {
+ CopyData(url);
+ CopyImpl(url);
+ }
+ }
+
+ void Clear() {
+ Dealloc();
+ ClearImpl();
+ }
+
+ ui32 GetFieldMask() const {
+ return FieldsSet;
+ }
+
+ ui32 GetUrlFieldMask() const {
+ return GetFieldMask() & FlagUrlFields;
+ }
+
+ ui32 GetDirtyMask() const {
+ return FieldsDirty;
+ }
+
+ void CheckMissingFields();
+
+ // Process methods
+
+ void Rewrite() {
+ if (FldIsDirty())
+ RewriteImpl();
+ }
+
+ private:
+ TState::EParsed AssignImpl(const TParser& parser, TScheme::EKind defscheme = SchemeEmpty);
+
+ TState::EParsed ParseImpl(const TStringBuf& url, const TParseFlags& flags = FeaturesDefault, ui32 maxlen = 0, TScheme::EKind defscheme = SchemeEmpty, ECharset enc = CODES_UTF8);
+
+ public:
+ TState::EParsed Assign(const TParser& parser, TScheme::EKind defscheme = SchemeEmpty) {
+ const TState::EParsed ret = AssignImpl(parser, defscheme);
+ if (ParsedOK == ret)
+ Rewrite();
+ return ret;
+ }
+
+ TState::EParsed ParseUri(const TStringBuf& url, const TParseFlags& flags = FeaturesDefault, ui32 maxlen = 0, ECharset enc = CODES_UTF8) {
+ const TState::EParsed ret = ParseImpl(url, flags, maxlen, SchemeEmpty, enc);
+ if (ParsedOK == ret)
+ Rewrite();
+ return ret;
+ }
+
+ // parses absolute URIs
+ // prepends default scheme (unless unknown) if URI has none
+ TState::EParsed ParseAbsUri(const TStringBuf& url, const TParseFlags& flags = FeaturesDefault, ui32 maxlen = 0, TScheme::EKind defscheme = SchemeUnknown, ECharset enc = CODES_UTF8);
+
+ TState::EParsed ParseAbsOrHttpUri(const TStringBuf& url, const TParseFlags& flags = FeaturesDefault, ui32 maxlen = 0, ECharset enc = CODES_UTF8) {
+ return ParseAbsUri(url, flags, maxlen, SchemeHTTP, enc);
+ }
+
+ TState::EParsed Parse(const TStringBuf& url, const TUri& base, const TParseFlags& flags = FeaturesDefault, ui32 maxlen = 0, ECharset enc = CODES_UTF8);
+
+ TState::EParsed Parse(const TStringBuf& url, const TParseFlags& flags = FeaturesDefault) {
+ return ParseUri(url, flags);
+ }
+
+ TState::EParsed Parse(const TStringBuf& url, const TParseFlags& flags, const TStringBuf& base_url, ui32 maxlen = 0, ECharset enc = CODES_UTF8);
+
+ TState::EParsed ParseAbs(const TStringBuf& url, const TParseFlags& flags = FeaturesDefault, const TStringBuf& base_url = TStringBuf(), ui32 maxlen = 0, ECharset enc = CODES_UTF8) {
+ const TState::EParsed result = Parse(url, flags, base_url, maxlen, enc);
+ return ParsedOK != result || IsValidGlobal() ? result : ParsedBadFormat;
+ }
+
+ // correctAbs works with head "/.." portions:
+ // 1 - reject URL
+ // 0 - keep portions
+ // -1 - ignore portions
+
+ void Merge(const TUri& base, int correctAbs = -1);
+
+ TLinkType Normalize(const TUri& base, const TStringBuf& link, const TStringBuf& codebase = TStringBuf(), long careFlags = FeaturesDefault, ECharset enc = CODES_UTF8);
+
+ private:
+ int PrintFlags(int flags) const {
+ if (0 == (FlagUrlFields & flags))
+ flags |= FlagUrlFields;
+ return flags;
+ }
+
+ protected:
+ size_t PrintSize(ui32 flags) const;
+
+ // Output method, prints to stream
+ IOutputStream& PrintImpl(IOutputStream& out, int flags) const;
+
+ char* PrintImpl(char* str, size_t size, int flags) const {
+ TMemoryOutput out(str, size);
+ PrintImpl(out, flags) << '\0';
+ return str;
+ }
+
+ static bool IsAbsPath(const TStringBuf& path) {
+ return 1 <= path.length() && path[0] == '/';
+ }
+
+ bool IsAbsPathImpl() const {
+ return IsAbsPath(GetField(FieldPath));
+ }
+
+ public:
+ // Output method, prints to stream
+ IOutputStream& Print(IOutputStream& out, int flags = FlagUrlFields) const {
+ return PrintImpl(out, PrintFlags(flags));
+ }
+
+ // Output method, print to str, allocate memory if str is NULL
+ // Should be deprecated
+ char* Print(char* str, size_t size, int flags = FlagUrlFields) const {
+ return nullptr == str ? Serialize(flags) : Serialize(str, size, flags);
+ }
+
+ char* Serialize(char* str, size_t size, int flags = FlagUrlFields) const {
+ Y_ASSERT(str);
+ flags = PrintFlags(flags);
+ const size_t printSize = PrintSize(flags) + 1;
+ return printSize > size ? nullptr : PrintImpl(str, size, flags);
+ }
+
+ char* Serialize(int flags = FlagUrlFields) const {
+ flags = PrintFlags(flags);
+ const size_t size = PrintSize(flags) + 1;
+ return PrintImpl(static_cast<char*>(malloc(size)), size, flags);
+ }
+
+ // Output method to str
+ void Print(TString& str, int flags = FlagUrlFields) const {
+ flags = PrintFlags(flags);
+ str.reserve(str.length() + PrintSize(flags));
+ TStringOutput out(str);
+ PrintImpl(out, flags);
+ }
+
+ TString PrintS(int flags = FlagUrlFields) const {
+ TString str;
+ Print(str, flags);
+ return str;
+ }
+
+ // Only non-default scheme and port are printed
+ char* PrintHost(char* str, size_t size) const {
+ return Print(str, size, (Scheme != SchemeHTTP ? FlagScheme : 0) | FlagHostPort);
+ }
+ TString PrintHostS() const {
+ return PrintS((Scheme != SchemeHTTP ? FlagScheme : 0) | FlagHostPort);
+ }
+
+ // Info methods
+ int Compare(const TUri& A, int flags = FlagUrlFields) const;
+
+ int CompareField(EField fld, const TUri& url) const;
+
+ const TStringBuf& GetField(EField fld) const {
+ return FldIsValid(fld) && FldIsSet(fld) ? FldGet(fld) : Default<TStringBuf>();
+ }
+
+ ui16 GetPort() const {
+ return 0 == Port ? DefaultPort : Port;
+ }
+
+ const TStringBuf& GetHost() const {
+ if (GetFieldMask() & FlagHostAscii)
+ return FldGet(FieldHostAscii);
+ if (GetFieldMask() & FlagHost)
+ return FldGet(FieldHost);
+ return Default<TStringBuf>();
+ }
+
+ bool UseHostAscii() {
+ return FldMov(FieldHostAscii, FieldHost);
+ }
+
+ TScheme::EKind GetScheme() const {
+ return Scheme;
+ }
+ const TSchemeInfo& GetSchemeInfo() const {
+ return TSchemeInfo::Get(Scheme);
+ }
+
+ bool IsNull(ui32 flags = FlagScheme | FlagHost | FlagPath) const {
+ return !FldSetCmp(flags);
+ }
+
+ bool IsNull(EField fld) const {
+ return !FldIsSet(fld);
+ }
+
+ bool IsValidAbs() const {
+ if (IsNull(FlagScheme | FlagHost | FlagPath))
+ return false;
+ return IsAbsPathImpl();
+ }
+
+ bool IsValidGlobal() const {
+ if (IsNull(FlagScheme | FlagHost))
+ return false;
+ if (IsNull(FlagPath))
+ return true;
+ return IsAbsPathImpl();
+ }
+
+ bool IsRootless() const {
+ return FldSetCmp(FlagScheme | FlagHost | FlagPath, FlagScheme | FlagPath) && !IsAbsPathImpl();
+ }
+
+ // for RFC 2396 compatibility
+ bool IsOpaque() const {
+ return IsRootless();
+ }
+
+ // Inline helpers
+ TUri& operator=(const TUri& u) {
+ Copy(u);
+ return *this;
+ }
+
+ bool operator!() const {
+ return IsNull();
+ }
+
+ bool Equal(const TUri& A, int flags = FlagUrlFields) const {
+ return (Compare(A, flags) == 0);
+ }
+
+ bool Less(const TUri& A, int flags = FlagUrlFields) const {
+ return (Compare(A, flags) < 0);
+ }
+
+ bool operator==(const TUri& A) const {
+ return Equal(A, FlagNoFrag);
+ }
+
+ bool operator!=(const TUri& A) const {
+ return !Equal(A, FlagNoFrag);
+ }
+
+ bool operator<(const TUri& A) const {
+ return Less(A, FlagNoFrag);
+ }
+
+ bool IsSameDocument(const TUri& other) const {
+ // pre: both *this and 'other' should be normalized to valid abs
+ Y_ASSERT(IsValidAbs());
+ return Equal(other, FlagNoFrag);
+ }
+
+ bool IsLocal(const TUri& other) const {
+ // pre: both *this and 'other' should be normalized to valid abs
+ Y_ASSERT(IsValidAbs() && other.IsValidAbs());
+ return Equal(other, FlagScheme | FlagHostPort);
+ }
+
+ TLinkType Locality(const TUri& other) const {
+ if (IsSameDocument(other))
+ return LinkIsFragment;
+ else if (IsLocal(other))
+ return LinkIsLocal;
+ return LinkIsGlobal;
+ }
+
+ static IOutputStream& ReEncodeField(IOutputStream& out, const TStringBuf& val, EField fld, long flags = FeaturesEncodeDecode) {
+ return NEncode::TEncoder::ReEncode(out, val, NEncode::TEncodeMapper(flags, fld));
+ }
+
+ static IOutputStream& ReEncodeToField(IOutputStream& out, const TStringBuf& val, EField srcfld, long srcflags, EField dstfld, long dstflags) {
+ return NEncode::TEncoder::ReEncodeTo(out, val, NEncode::TEncodeMapper(srcflags, srcfld), NEncode::TEncodeToMapper(dstflags, dstfld));
+ }
+
+ static IOutputStream& ReEncode(IOutputStream& out, const TStringBuf& val, long flags = FeaturesEncodeDecode) {
+ return ReEncodeField(out, val, FieldAllMAX, flags);
+ }
+
+ static int PathOperationFlag(const TParseFlags& flags) {
+ return flags & FeaturePathDenyRootParent ? 1
+ : flags & FeaturePathStripRootParent ? -1 : 0;
+ }
+
+ static bool PathOperation(char*& pathBeg, char*& pathEnd, int correctAbs);
+
+ private:
+ const TSchemeInfo& SetSchemeImpl(const TSchemeInfo& info) {
+ Scheme = info.Kind;
+ DefaultPort = info.Port;
+ if (!info.Str.empty())
+ FldSetNoDirty(FieldScheme, info.Str);
+ return info;
+ }
+ const TSchemeInfo& SetSchemeImpl(TScheme::EKind scheme) {
+ return SetSchemeImpl(TSchemeInfo::Get(scheme));
+ }
+
+ public:
+ const TSchemeInfo& SetScheme(const TSchemeInfo& info) {
+ SetSchemeImpl(info);
+ if (!info.Str.empty())
+ FldMarkClean(FieldScheme);
+ return info;
+ }
+ const TSchemeInfo& SetScheme(TScheme::EKind scheme) {
+ return SetScheme(TSchemeInfo::Get(scheme));
+ }
+ };
+
+ class TUriUpdate {
+ TUri& Uri_;
+
+ public:
+ TUriUpdate(TUri& uri)
+ : Uri_(uri)
+ {
+ }
+ ~TUriUpdate() {
+ Uri_.Rewrite();
+ }
+
+ public:
+ bool Set(TField::EField field, const TStringBuf& value) {
+ return Uri_.FldMemSet(field, value);
+ }
+
+ template <size_t size>
+ bool Set(TField::EField field, const char (&value)[size]) {
+ return Uri_.FldMemSet(field, value);
+ }
+
+ void Clr(TField::EField field) {
+ Uri_.FldClr(field);
+ }
+ };
+
+ const char* LinkTypeToString(const TUri::TLinkType& t);
+
+}
+
+Y_DECLARE_OUT_SPEC(inline, NUri::TUri, out, url) {
+ url.Print(out);
+}
+
+Y_DECLARE_OUT_SPEC(inline, NUri::TUri::TLinkType, out, t) {
+ out << NUri::LinkTypeToString(t);
+}
diff --git a/library/cpp/uri/uri_ut.cpp b/library/cpp/uri/uri_ut.cpp
new file mode 100644
index 0000000000..2ebd83fc93
--- /dev/null
+++ b/library/cpp/uri/uri_ut.cpp
@@ -0,0 +1,1022 @@
+#include "uri_ut.h"
+#include "other.h"
+#include "qargs.h"
+#include <library/cpp/html/entity/htmlentity.h>
+
+#include <util/system/maxlen.h>
+
+namespace NUri {
+ Y_UNIT_TEST_SUITE(URLTest) {
+ static const char* urls[] = {
+ "http://a/b/c/d;p?q#r",
+ "g", "http://a/b/c/g",
+ "./g", "http://a/b/c/g",
+ "g/", "http://a/b/c/g/",
+ "/g", "http://a/g",
+ "//g", "http://g/",
+ "?y", "http://a/b/c/d;p?y",
+ "g?y", "http://a/b/c/g?y",
+ "#s", "http://a/b/c/d;p?q#s",
+ "g#s", "http://a/b/c/g#s",
+ "g?y#s", "http://a/b/c/g?y#s",
+ ";x", "http://a/b/c/;x",
+ "g;x", "http://a/b/c/g;x",
+ "g;x?y#s", "http://a/b/c/g;x?y#s",
+ ".", "http://a/b/c/",
+ "./", "http://a/b/c/",
+ "./.", "http://a/b/c/",
+ "././", "http://a/b/c/",
+ "././.", "http://a/b/c/",
+ "..", "http://a/b/",
+ "../", "http://a/b/",
+ "../.", "http://a/b/",
+ "../g", "http://a/b/g",
+ "../..", "http://a/",
+ "../../", "http://a/",
+ "../../.", "http://a/",
+ "../../g", "http://a/g",
+ "../../../g", "http://a/g",
+ "../../../../g", "http://a/g",
+ "/./g", "http://a/g",
+ "g.", "http://a/b/c/g.",
+ ".g", "http://a/b/c/.g",
+ "g..", "http://a/b/c/g..",
+ "..g", "http://a/b/c/..g",
+ "./../g", "http://a/b/g",
+ "./g/.", "http://a/b/c/g/",
+ "g/./h", "http://a/b/c/g/h",
+ "g/../h", "http://a/b/c/h",
+ "g;x=1/./y", "http://a/b/c/g;x=1/y",
+ "g;x=1/../y", "http://a/b/c/y",
+ "g?y/./x", "http://a/b/c/g?y/./x",
+ "g?y/../x", "http://a/b/c/g?y/../x",
+ "g#s/./x", "http://a/b/c/g#s/./x",
+ "g#s/../x", "http://a/b/c/g#s/../x",
+ "?", "http://a/b/c/d;p?",
+ "/?", "http://a/?",
+ "x?", "http://a/b/c/x?",
+ "x%20y", "http://a/b/c/x%20y",
+ "%20y", "http://a/b/c/%20y",
+ // "%2zy", "http://a/b/c/%2zy",
+ nullptr};
+
+ Y_UNIT_TEST(test_httpURL) {
+ TUri rel, base, abs;
+ TState::EParsed er = base.Parse(urls[0]);
+ UNIT_ASSERT_VALUES_EQUAL(er, TState::ParsedOK);
+ UNIT_ASSERT(base.IsValidAbs());
+ UNIT_ASSERT_VALUES_EQUAL(base.PrintS(), urls[0]);
+
+ TString errbuf;
+ TStringOutput out(errbuf);
+ const long mflag = TFeature::FeaturesAll;
+ for (int i = 1; urls[i]; i += 2) {
+ er = rel.Parse(urls[i]);
+ UNIT_ASSERT_VALUES_EQUAL_C(er, TState::ParsedOK, urls[i]);
+ rel.Merge(base);
+ UNIT_ASSERT_VALUES_EQUAL_C(rel.PrintS(), urls[i + 1], urls[i]);
+
+ // try the same thing differently
+ er = rel.Parse(urls[i], mflag, urls[0]);
+ UNIT_ASSERT_VALUES_EQUAL_C(er, TState::ParsedOK, urls[i]);
+ UNIT_ASSERT_VALUES_EQUAL_C(rel.PrintS(), urls[i + 1], urls[i]);
+
+ // lastly...
+ er = abs.Parse(urls[i + 1], mflag);
+ UNIT_ASSERT_VALUES_EQUAL(er, TState::ParsedOK);
+ errbuf.clear();
+ out << '[' << rel.PrintS()
+ << "] != [" << abs.PrintS() << ']';
+ UNIT_ASSERT_EQUAL_C(rel, abs, errbuf);
+ }
+ }
+
+ Y_UNIT_TEST(test_Schemes) {
+ TUri url;
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("www.ya.ru/index.html"), TState::ParsedOK);
+ UNIT_ASSERT_EQUAL(url.GetScheme(), TScheme::SchemeEmpty);
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("http://www.ya.ru"), TState::ParsedOK);
+ UNIT_ASSERT_EQUAL(url.GetScheme(), TScheme::SchemeHTTP);
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("https://www.ya.ru"), TState::ParsedBadScheme);
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("https://www.ya.ru", TFeature::FeaturesDefault | TFeature::FeatureSchemeKnown), TState::ParsedOK);
+ UNIT_ASSERT_EQUAL(url.GetScheme(), TScheme::SchemeHTTPS);
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("httpwhatever://www.ya.ru"), TState::ParsedBadScheme);
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("httpwhatever://www.ya.ru", TFeature::FeaturesDefault | TFeature::FeatureSchemeFlexible), TState::ParsedOK);
+ UNIT_ASSERT_EQUAL(url.GetScheme(), TScheme::SchemeUnknown);
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("httpswhatever://www.ya.ru"), TState::ParsedBadScheme);
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("httpswhatever://www.ya.ru", TFeature::FeaturesDefault | TFeature::FeatureSchemeFlexible), TState::ParsedOK);
+ UNIT_ASSERT_EQUAL(url.GetScheme(), TScheme::SchemeUnknown);
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("ftp://www.ya.ru"), TState::ParsedBadScheme);
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("ftp://www.ya.ru", TFeature::FeaturesDefault | TFeature::FeatureSchemeFlexible), TState::ParsedOK);
+ UNIT_ASSERT_EQUAL(url.GetScheme(), TScheme::SchemeFTP);
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("httpsssss://www.ya.ru"), TState::ParsedBadScheme);
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("httpsssss://www.ya.ru", TFeature::FeaturesDefault | TFeature::FeatureSchemeFlexible), TState::ParsedOK);
+ UNIT_ASSERT_EQUAL(url.GetScheme(), TScheme::SchemeUnknown);
+ }
+
+ struct Link4Norm {
+ const char* const base;
+ const char* const link;
+ const char* const result;
+ TUri::TLinkType ltype;
+ };
+
+ static const Link4Norm link4Norm[] = {
+ {"http://www.alltest.ru/all.php?a=aberporth", "http://www.alltest.ru/all.php?a=domestic jobs", "", TUri::LinkIsBad},
+ {"http://www.alltest.ru/all.php?a=aberporth", "http://www.alltest.ru/all.php?a=domestic%20jobs", "http://www.alltest.ru/all.php?a=domestic%20jobs", TUri::LinkIsLocal},
+ {"http://president.rf/%D0%BD%D0%BE%D0%B2%D0%BE%D1%81%D1%82%D0%B8", "http://president.rf/%D0%BD%D0%BE%D0%B2%D0%BE%D1%81%D1%82%D0%B8/1024", "http://president.rf/%D0%BD%D0%BE%D0%B2%D0%BE%D1%81%D1%82%D0%B8/1024", TUri::LinkIsLocal},
+ {nullptr, nullptr, nullptr, TUri::LinkIsBad},
+ };
+
+ Y_UNIT_TEST(test_httpURLNormalize) {
+ TUri normalizedLink;
+
+ for (int i = 0; link4Norm[i].link; i++) {
+ TUri base;
+ TState::EParsed er = base.Parse(link4Norm[i].base);
+ UNIT_ASSERT_VALUES_EQUAL_C(er, TState::ParsedOK, link4Norm[i].base);
+ TUri::TLinkType ltype = normalizedLink.Normalize(base, link4Norm[i].link);
+ UNIT_ASSERT_VALUES_EQUAL_C(ltype, link4Norm[i].ltype, link4Norm[i].link);
+ TString s = TUri::LinkIsBad == ltype ? "" : normalizedLink.PrintS();
+ UNIT_ASSERT_VALUES_EQUAL_C(s, link4Norm[i].result, link4Norm[i].link);
+ }
+ }
+
+ static const char* urlsWithMultipleSlash[] = {
+ "http://a/http://b", "http://a/http://b",
+ "http://a/https://b", "http://a/https://b",
+ "http://a/b://c", "http://a/b:/c",
+ "http://a/b//c", "http://a/b/c",
+ nullptr, nullptr};
+
+ Y_UNIT_TEST(test_httpURLPathOperation) {
+ char copyUrl[URL_MAXLEN];
+ for (int i = 0; urlsWithMultipleSlash[i]; i += 2) {
+ const TStringBuf url(urlsWithMultipleSlash[i]);
+ const TStringBuf normurl(urlsWithMultipleSlash[i + 1]);
+ memcpy(copyUrl, url.data(), url.length());
+ char* p = copyUrl;
+ char* e = copyUrl + url.length();
+ TUri::PathOperation(p, e, 1);
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuf(p, e), normurl);
+ TUri uri;
+ UNIT_ASSERT_VALUES_EQUAL(TState::ParsedOK, uri.Parse(url));
+ UNIT_ASSERT_VALUES_EQUAL_C(uri.PrintS(), normurl, url);
+ }
+ }
+
+ static const char* hostsForCheckHost[] = {
+ "simplehost.ru",
+ "third_level.host.ru",
+ "_ok.somewhere.ru",
+ "a.b",
+ "second_level.ru",
+ "_bad.ru",
+ "_",
+ "yandex.ru:443",
+ nullptr};
+
+ static TState::EParsed answersForCheckHost[] = {
+ TState::ParsedOK,
+ TState::ParsedOK,
+ TState::ParsedOK,
+ TState::ParsedOK,
+ TState::ParsedBadHost,
+ TState::ParsedBadHost,
+ TState::ParsedBadHost,
+ TState::ParsedBadHost,
+ };
+
+ Y_UNIT_TEST(test_httpURLCheckHost) {
+ for (size_t index = 0; hostsForCheckHost[index]; ++index) {
+ TState::EParsed state = TUri::CheckHost(hostsForCheckHost[index]);
+ UNIT_ASSERT_VALUES_EQUAL(state, answersForCheckHost[index]);
+ }
+ }
+
+ Y_UNIT_TEST(test_httpURLSet) {
+ // set port
+ {
+ TUri parsedUrl;
+ parsedUrl.Parse("http://www.host.com/script.cgi?param1=value1&param2=value2");
+ parsedUrl.FldMemSet(TField::FieldPort, "8080");
+ UNIT_ASSERT_VALUES_EQUAL(parsedUrl.GetPort(), 8080);
+ UNIT_ASSERT_VALUES_EQUAL(parsedUrl.PrintS(), "http://www.host.com:8080/script.cgi?param1=value1&param2=value2");
+ }
+
+ // clear port
+ {
+ TUri parsedUrl;
+ parsedUrl.Parse("http://www.host.com:8080/script.cgi?param1=value1&param2=value2");
+ parsedUrl.FldMemSet(TField::FieldPort, nullptr);
+ UNIT_ASSERT_VALUES_EQUAL(parsedUrl.GetPort(), 80);
+ UNIT_ASSERT_VALUES_EQUAL(parsedUrl.PrintS(), "http://www.host.com/script.cgi?param1=value1&param2=value2");
+ }
+
+ // change scheme with default port
+ {
+ TUri parsedUrl;
+ parsedUrl.Parse("http://www.host.com/script.cgi?param1=value1&param2=value2");
+ parsedUrl.FldMemSet(TField::FieldScheme, "https");
+ UNIT_ASSERT_VALUES_EQUAL(parsedUrl.GetPort(), 443);
+ UNIT_ASSERT_VALUES_EQUAL(parsedUrl.PrintS(), "https://www.host.com/script.cgi?param1=value1&param2=value2");
+ }
+
+ // change scheme with non-default port
+ {
+ TUri parsedUrl;
+ parsedUrl.Parse("http://www.host.com:8080/script.cgi?param1=value1&param2=value2");
+ parsedUrl.FldMemSet(TField::FieldScheme, "https");
+ UNIT_ASSERT_VALUES_EQUAL(parsedUrl.GetPort(), 8080);
+ UNIT_ASSERT_VALUES_EQUAL(parsedUrl.PrintS(), "https://www.host.com:8080/script.cgi?param1=value1&param2=value2");
+ }
+ }
+
+ Y_UNIT_TEST(test_httpURLAuth) {
+ {
+ TUri parsedUrl;
+ TState::EParsed st = parsedUrl.Parse("http://@www.host.com/path", TFeature::FeaturesRobot);
+ UNIT_ASSERT_VALUES_EQUAL(st, TState::ParsedBadAuth);
+ }
+
+ {
+ TUri parsedUrl;
+ TState::EParsed st = parsedUrl.Parse("http://loginwithnopass@www.host.com/path", TFeature::FeatureAuthSupported);
+ UNIT_ASSERT_VALUES_EQUAL(st, TState::ParsedOK);
+ UNIT_ASSERT_EQUAL(parsedUrl.GetField(TField::FieldHost), "www.host.com");
+ UNIT_ASSERT_EQUAL(parsedUrl.GetField(TField::FieldUser), "loginwithnopass");
+ UNIT_ASSERT_EQUAL(parsedUrl.GetField(TField::FieldPass), "");
+ }
+
+ {
+ TUri parsedUrl;
+ TState::EParsed st = parsedUrl.Parse("http://login:pass@www.host.com/path", TFeature::FeatureAuthSupported);
+ UNIT_ASSERT_VALUES_EQUAL(st, TState::ParsedOK);
+ UNIT_ASSERT_EQUAL(parsedUrl.GetField(TField::FieldHost), "www.host.com");
+ UNIT_ASSERT_EQUAL(parsedUrl.GetField(TField::FieldUser), "login");
+ UNIT_ASSERT_EQUAL(parsedUrl.GetField(TField::FieldPass), "pass");
+ }
+ }
+
+ Y_UNIT_TEST(test01) {
+ TTest test = {
+ "user:pass@host:8080", TFeature::FeaturesAll, TState::ParsedRootless, "user", "", "", "", 0, "", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+
+ Y_UNIT_TEST(test02) {
+ TTest test = {
+ "http://host", TFeature::FeaturesAll, TState::ParsedOK, "http", "", "", "host", 80, "/", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+
+ Y_UNIT_TEST(test03) {
+ TTest test = {
+ "https://host", TFeature::FeatureSchemeFlexible | TFeature::FeatureAllowHostIDN, TState::ParsedOK, "https", "", "", "host", 443, "/", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+
+ Y_UNIT_TEST(test04) {
+ TTest test = {
+ "user:pass@host:8080", TFeature::FeaturesAll | TFeature::FeatureNoRelPath | TFeature::FeatureAllowRootless, TState::ParsedOK, "user", "", "", "", 0, "pass@host:8080", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ TUri url2(url);
+ CMP_URL(url2, test);
+ URL_EQ(url, url2);
+ }
+
+ Y_UNIT_TEST(test05) {
+ TTest test = {
+ "host:8080", TFeature::FeaturesAll | TFeature::FeatureNoRelPath | TFeature::FeatureAllowRootless, TState::ParsedOK, "host", "", "", "", 0, "8080", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "host:8080");
+ }
+
+ Y_UNIT_TEST(test06) {
+ TTest test = {
+ "http://user:pass@host?q", TFeature::FeaturesAll, TState::ParsedOK, "http", "user", "pass", "host", 80, "/", "q", ""};
+ TUri url;
+ URL_TEST(url, test);
+ url.FldMemSet(TField::FieldScheme, "https");
+ UNIT_ASSERT(!url.FldIsDirty());
+ UNIT_ASSERT_VALUES_EQUAL(url.GetField(TField::FieldScheme), "https");
+ UNIT_ASSERT_VALUES_EQUAL(url.GetPort(), 443);
+
+ // test copying
+ TUri url2(url);
+ // make sure strings are equal...
+ UNIT_ASSERT_VALUES_EQUAL(
+ url.GetField(TField::FieldUser),
+ url2.GetField(TField::FieldUser));
+ // ... and memory locations are the same
+ UNIT_ASSERT_EQUAL(
+ url.GetField(TField::FieldUser),
+ url2.GetField(TField::FieldUser));
+ // and urls compare the same
+ URL_EQ(url, url2);
+
+ // cause a dirty field
+ url.FldMemSet(TField::FieldUser, "use"); // it is now shorter
+ UNIT_ASSERT(!url.FldIsDirty());
+ url.FldMemSet(TField::FieldUser, TStringBuf("user"));
+ UNIT_ASSERT(url.FldIsDirty());
+
+ // copy again
+ url2 = url;
+ UNIT_ASSERT(url.FldIsDirty());
+ UNIT_ASSERT(!url2.FldIsDirty());
+ URL_EQ(url, url2);
+ // make sure strings are equal...
+ UNIT_ASSERT_VALUES_EQUAL(
+ url.GetField(TField::FieldUser),
+ url2.GetField(TField::FieldUser));
+ // ... but memory locations are different
+ UNIT_ASSERT_UNEQUAL(
+ url.GetField(TField::FieldUser).data(),
+ url2.GetField(TField::FieldUser).data());
+ URL_EQ(url, url2);
+
+ // make query empty
+ url.FldMemSet(TField::FieldQuery, "");
+ url2 = url;
+ URL_EQ(url, url2);
+ // set query to null value (should clear it)
+ url2.FldMemSet(TField::FieldQuery, TStringBuf());
+ // make sure they are no longer equal
+ URL_NEQ(url, url2);
+ // reset query
+ url.FldClr(TField::FieldQuery);
+ // equal again
+ URL_EQ(url, url2);
+ // reset port and set the other to default
+ url.FldClr(TField::FieldPort);
+ url2.FldMemSet(TField::FieldPort, "443");
+ URL_EQ(url, url2);
+ }
+
+ Y_UNIT_TEST(test07) {
+ {
+ TTest test = {
+ "http://host/path//", TFeature::FeaturesAll | TFeature::FeatureNoRelPath, TState::ParsedOK, "http", "", "", "host", 80, "/path/", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ url.FldMemSet(TField::FieldScheme, "HTTPs");
+ UNIT_ASSERT_EQUAL(TScheme::SchemeHTTPS, url.GetScheme());
+ UNIT_ASSERT_EQUAL("https", url.GetField(TField::FieldScheme));
+ url.FldMemSet(TField::FieldScheme, "HtTP");
+ UNIT_ASSERT_EQUAL(TScheme::SchemeHTTP, url.GetScheme());
+ UNIT_ASSERT_EQUAL("http", url.GetField(TField::FieldScheme));
+ }
+
+ {
+ const TString scheme = "http";
+ const TString host = "host.com";
+ const TString urlstr = scheme + "://" + host;
+ TTest test = {
+ urlstr, TFeature::FeaturesAll | TFeature::FeatureNoRelPath, TState::ParsedOK, scheme, "", "", host, 80, "/", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), urlstr + "/");
+ }
+ }
+
+ Y_UNIT_TEST(test08) {
+ {
+ TTest test = {
+ "mailto://user@host.com", TFeature::FeaturesAll | TFeature::FeatureNoRelPath, TState::ParsedOK, "mailto", "user", "", "host.com", 0, "", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "host:/path/.path/.", TFeature::FeaturesAll | TFeature::FeatureNoRelPath, TState::ParsedOK, "host", "", "", "", 0, "/path/.path/", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "host:1/path/.path/.", TFeature::FeaturesAll | TFeature::FeatureNoRelPath, TState::ParsedOK, "", "", "", "host", 1, "/path/.path/", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "host:1/path/.path/.", TFeature::FeaturesAll | TFeature::FeatureAllowRootless, TState::ParsedOK, "host", "", "", "", 0, "1/path/.path/.", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "/[foo]:bar", TFeature::FeaturesAll | TFeature::FeatureNoRelPath, TState::ParsedOK, "", "", "", "", 0, "/[foo]:bar", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ ".", TFeature::FeaturesAll, TState::ParsedOK, "", "", "", "", 0, "", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ ".", TFeature::FeaturesAll | TFeature::FeatureNoRelPath, TState::ParsedOK, "", "", "", "", 0, "", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "././.", TFeature::FeaturesAll, TState::ParsedOK, "", "", "", "", 0, "", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "././.", TFeature::FeaturesAll | TFeature::FeatureNoRelPath, TState::ParsedOK, "", "", "", "", 0, "", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "./path", TFeature::FeaturesAll, TState::ParsedOK, "", "", "", "", 0, "path", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "./path", TFeature::FeaturesAll | TFeature::FeatureNoRelPath, TState::ParsedOK, "", "", "", "", 0, "path", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "../path", TFeature::FeaturesAll, TState::ParsedOK, "", "", "", "", 0, "../path", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "../path", TFeature::FeaturesAll | TFeature::FeatureNoRelPath, TState::ParsedOK, "", "", "", "", 0, "../path", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "/../path", TFeature::FeaturesAll, TState::ParsedOK, "", "", "", "", 0, "/path", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ }
+
+ Y_UNIT_TEST(test09) {
+ {
+ TTest test = {
+ "mailto:user@host.com", TFeature::FeaturesAll | TFeature::FeatureAllowRootless, TState::ParsedOK, "mailto", "", "", "", 0, "user@host.com", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "scheme:", TFeature::FeaturesAll | TFeature::FeatureNoRelPath | TFeature::FeatureAllowRootless, TState::ParsedOK, "scheme", "", "", "", 0, "", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "scheme:", TFeature::FeaturesAll | TFeature::FeatureAllowRootless, TState::ParsedOK, "scheme", "", "", "", 0, "", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ }
+
+ Y_UNIT_TEST(test10) {
+ // test some escaping madness, note the ehost vs host
+ {
+ TString host = "президент.рф";
+ TString ehost = "%D0%BF%D1%80%D0%B5%D0%B7%D0%B8%D0%B4%D0%B5%D0%BD%D1%82.%D1%80%D1%84";
+ const TString urlstr = TString::Join("http://", host, "/");
+ TTest test = {
+ urlstr, TFeature::FeatureEncodeExtendedASCII | TFeature::FeaturesDefault | TFeature::FeatureCheckHost, TState::ParsedBadHost, "http", "", "", ehost, 80, "/", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+
+ {
+ TString host = "%D0%BF%D1%80%D0%B5%D0%B7%D0%B8%D0%B4%D0%B5%D0%BD%D1%82.%D1%80%D1%84";
+ const TString urlstr = TString::Join("http://", host, "/");
+ TTest test = {
+ urlstr, TFeature::FeatureEncodeExtendedASCII | TFeature::FeaturesDefault | TFeature::FeatureCheckHost, TState::ParsedBadHost, "http", "", "", host, 80, "/", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+
+ {
+ TString host = "Фilip.ru";
+ TString ehost = "%D0%A4ilip.ru";
+ const TString urlstr = TString::Join("http://", host);
+ TTest test = {
+ urlstr, TFeature::FeatureEncodeExtendedASCII | TFeature::FeaturesDefault, TState::ParsedBadHost, "http", "", "", ehost, 80, "/", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+
+ {
+ TString host = "%D0%A4ilip.ru";
+ const TString urlstr = TString::Join("http://", host);
+ TTest test = {
+ urlstr, TFeature::FeatureEncodeExtendedASCII | TFeature::FeaturesDefault, TState::ParsedBadHost, "http", "", "", host, 80, "/", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+
+ {
+ TString host = "Filip%90.rЯ";
+ TString ehost = "Filip%90.r%D0%AF";
+ const TString urlstr = TString::Join(host, ":8080");
+ TTest test = {
+ urlstr, TFeature::FeatureEncodeExtendedASCII | TFeature::FeatureDecodeAllowed | TFeature::FeaturesDefault | TFeature::FeatureNoRelPath, TState::ParsedBadHost, "", "", "", ehost, 8080, "", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+
+ {
+ TString host = "Filip%90.r%D0%AF";
+ const TString urlstr = TString::Join(host, ":8080");
+ TTest test = {
+ urlstr, TFeature::FeatureEncodeExtendedASCII | TFeature::FeatureDecodeAllowed | TFeature::FeaturesDefault | TFeature::FeatureNoRelPath, TState::ParsedBadHost, "", "", "", host, 8080, "", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ }
+
+ Y_UNIT_TEST(test11) {
+ {
+ TTest test = {
+ "HtTp://HoSt/%50aTh/?Query#Frag", TFeature::FeaturesAll | TFeature::FeatureNoRelPath, TState::ParsedOK, "http", "", "", "host", 80, "/PaTh/", "Query", "Frag"};
+ TUri url;
+ URL_TEST(url, test);
+ }
+
+ {
+ TTest test = {
+ "HtTp://HoSt/%50a%54h/?Query#Frag", TParseFlags(TFeature::FeaturesAll | TFeature::FeatureNoRelPath, TFeature::FeatureToLower), TState::ParsedOK, "http", "", "", "host", 80, "/path/", "query", "frag"};
+ TUri url;
+ URL_TEST(url, test);
+ }
+ }
+
+ Y_UNIT_TEST(test12) {
+ // test characters which are not always safe
+ {
+#define RAW "/:"
+#define DEC "%2F:"
+#define ENC "%2F%3A"
+ TTest test = {
+ "http://" ENC ":" ENC "@host/" ENC "?" ENC "#" ENC, TFeature::FeaturesAll, TState::ParsedOK, "http", RAW, RAW, "host", 80, "/" DEC, RAW, RAW};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://" ENC ":" ENC "@host/" DEC "?" RAW "#" RAW);
+#undef RAW
+#undef DEC
+#undef ENC
+ }
+ {
+#define RAW "?@"
+#define DEC "%3F@"
+#define ENC "%3F%40"
+ TTest test = {
+ "http://" ENC ":" ENC "@host/" ENC "?" ENC "#" ENC, TFeature::FeaturesAll, TState::ParsedOK, "http", RAW, RAW, "host", 80, "/" DEC, RAW, RAW};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://" ENC ":" ENC "@host/" DEC "?" RAW "#" RAW);
+#undef RAW
+#undef DEC
+#undef ENC
+ }
+ {
+#define RAW "%&;="
+#define DEC "%25&;="
+#define ENC "%25%26%3B%3D"
+ TTest test = {
+ "http://" ENC ":" ENC "@host/" ENC "?" ENC "#" ENC, TFeature::FeaturesAll, TState::ParsedOK, "http", RAW, RAW, "host", 80, "/" ENC, ENC, ENC};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://" ENC ":" ENC "@host/" ENC "?" ENC "#" ENC);
+#undef RAW
+#undef DEC
+#undef ENC
+ }
+ {
+#define RAW "!$'()*,"
+#define DEC "!$%27()*,"
+#define ENC "%21%24%27%28%29%2A%2C"
+ TTest test = {
+ "http://" ENC ":" ENC "@host/" ENC "?" ENC "#" ENC, TFeature::FeaturesAll, TState::ParsedOK, "http", RAW, RAW, "host", 80, "/" ENC, DEC, DEC};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://" ENC ":" ENC "@host/" ENC "?" DEC "#" DEC);
+#undef RAW
+#undef DEC
+#undef ENC
+ }
+ {
+#define DEC "Череповец。рф"
+#define ENC "%D0%A7%D0%B5%D1%80%D0%B5%D0%BF%D0%BE%D0%B2%D0%B5%D1%86%E3%80%82%D1%80%D1%84"
+// punycode corresponds to lowercase
+#define PNC "xn--b1afab7bff7cb.xn--p1ai"
+ TTest test = {
+ "http://" ENC "/" ENC "?" ENC "#" ENC, TParseFlags(TFeature::FeaturesAll | TFeature::FeatureAllowHostIDN, TFeature::FeatureDecodeExtendedASCII), TState::ParsedOK, "http", "", "", DEC, 80, "/" ENC, ENC, ENC};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.GetField(TField::FieldHostAscii), PNC);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://" DEC "/" ENC "?" ENC "#" ENC);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(TField::FlagHostAscii), "http://" PNC "/" ENC "?" ENC "#" ENC);
+#undef PNC
+#undef DEC
+#undef ENC
+ }
+ {
+#define DEC "Череповец。рф"
+#define ENC "%D0%A7%D0%B5%D1%80%D0%B5%D0%BF%D0%BE%D0%B2%D0%B5%D1%86%E3%80%82%D1%80%D1%84"
+// punycode corresponds to lowercase
+#define PNC "xn--b1afab7bff7cb.xn--p1ai"
+ TTest test = {
+ "http://" DEC "/" DEC "?" DEC "#" DEC, TParseFlags(TFeature::FeaturesRobot | TFeature::FeatureEncodeExtendedASCII), TState::ParsedOK, "http", "", "", PNC, 80, "/" ENC, ENC, ENC};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://" PNC "/" ENC "?" ENC "#" ENC);
+#undef PNC
+#undef DEC
+#undef ENC
+ }
+ {
+#define DEC "независимая-экспертиза-оценка-ущерба-авто-дтп.рф"
+#define PNC "xn--------3veabbbbjgk5abecc3afsad2cg8bvq2alouolqf5brd3a4jzftgqd.xn--p1ai"
+ TTest test = {
+ "http://" DEC "/", TParseFlags(TFeature::FeaturesRobot), TState::ParsedOK, "http", "", "", PNC, 80, "/", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://" PNC "/");
+#undef PNC
+#undef DEC
+ }
+ }
+
+ Y_UNIT_TEST(testFlexibleAuthority) {
+ TUri uri;
+ UNIT_ASSERT_EQUAL(uri.Parse("http://hello_world", TFeature::FeatureCheckHost), TState::ParsedBadHost);
+ UNIT_ASSERT_EQUAL(uri.Parse("http://hello_world", TFeature::FeatureSchemeFlexible), TState::ParsedOK);
+ UNIT_ASSERT_VALUES_EQUAL(uri.GetHost(), "hello_world");
+
+ UNIT_ASSERT_EQUAL(uri.Parse("httpzzzzz://)(*&^$!\\][';<>`~,q?./index.html", TFeature::FeatureSchemeFlexible), TState::ParsedOK);
+ UNIT_ASSERT_VALUES_EQUAL(uri.GetHost(), ")(*&^$!\\][';<>`~,q");
+ UNIT_ASSERT_VALUES_EQUAL(uri.GetField(TField::FieldPath), "");
+ UNIT_ASSERT_VALUES_EQUAL(uri.GetField(TField::FieldQuery), "./index.html");
+
+ UNIT_ASSERT_EQUAL(uri.Parse("htttttttp://)(*&^%45$!\\][';<>`~,.q/index.html", TFeature::FeatureSchemeFlexible), TState::ParsedOK);
+ UNIT_ASSERT_VALUES_EQUAL(uri.GetHost(), ")(*&^e$!\\][';<>`~,.q");
+ UNIT_ASSERT_VALUES_EQUAL(uri.GetField(TField::FieldPath), "/index.html");
+ UNIT_ASSERT_VALUES_EQUAL(uri.GetField(TField::FieldQuery), "");
+ }
+
+ Y_UNIT_TEST(testSpecialChar) {
+ // test characters which are not always allowed
+ {
+ TTest test = {
+ "http://host/pa th", TFeature::FeaturesAll | TFeature::FeatureEncodeSpace, TState::ParsedOK, "http", "", "", "host", 80, "/pa%20th", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://host/pa%20th");
+ }
+ {
+ TTest test = {
+ "http://host/pa th", TFeature::FeaturesAll, TState::ParsedBadFormat, "http", "", "", "host", 80, "/pa th", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://host/pa th");
+ }
+ {
+ TTest test = {
+ "http://host/pa%th%41", TFeature::FeaturesAll | TFeature::FeatureEncodePercent, TState::ParsedOK, "http", "", "", "host", 80, "/pa%25thA", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://host/pa%25thA");
+ }
+ {
+ TTest test = {
+ "http://host/invalid_second_char%az%1G", TFeature::FeaturesAll | TFeature::FeatureEncodePercent, TState::ParsedOK, "http", "", "", "host", 80, "/invalid_second_char%25az%251G", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://host/invalid_second_char%25az%251G");
+ }
+ {
+ TTest test = {
+ "http://host/border%2", TFeature::FeaturesAll | TFeature::FeatureEncodePercent, TState::ParsedOK, "http", "", "", "host", 80, "/border%252", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://host/border%252");
+ }
+ {
+ TTest test = {
+ "http://host/pa%th%41", TFeature::FeaturesAll, TState::ParsedBadFormat, "http", "", "", "host", 80, "/pa%thA", "", ""};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://host/pa%thA");
+ }
+ }
+
+ Y_UNIT_TEST(testIPv6) {
+ {
+#define RAW "[1080:0:0:0:8:800:200C:417A]"
+#define DEC "[1080:0:0:0:8:800:200c:417a]"
+ TTest test = {
+ "http://" RAW "/" RAW "?" RAW "#" RAW, TParseFlags(TFeature::FeaturesAll), TState::ParsedOK, "http", "", "", DEC, 80, "/" RAW, RAW, RAW};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://" DEC "/" RAW "?" RAW "#" RAW);
+#undef DEC
+#undef RAW
+ }
+ }
+
+ Y_UNIT_TEST(testEscapedFragment) {
+ {
+ TTest test = {
+ "http://host.com#!a=b&c=d#e+g%41%25", TParseFlags(TFeature::FeaturesAll | TFeature::FeatureHashBangToEscapedFragment), TState::ParsedOK, "http", "", "", "host.com", 80, "/", "_escaped_fragment_=a=b%26c=d%23e%2BgA%2525", ""};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://host.com/?_escaped_fragment_=a=b%26c=d%23e%2BgA%2525");
+ }
+ {
+ TTest test = {
+ "http://host.com?_escaped_fragment_=a=b%26c=d%23e%2bg%2525", TParseFlags(TFeature::FeaturesAll | TFeature::FeatureEscapedToHashBangFragment), TState::ParsedOK, "http", "", "", "host.com", 80, "/", "", "!a=b&c=d#e+g%25"};
+ TUri url;
+ URL_TEST(url, test);
+ UNIT_ASSERT_VALUES_EQUAL(url.PrintS(), "http://host.com/#!a=b&c=d#e+g%25");
+ }
+ }
+
+ Y_UNIT_TEST(testReEncode) {
+ {
+ TStringStream out;
+ TUri::ReEncode(out, "foo bar");
+ UNIT_ASSERT_VALUES_EQUAL(out.Str(), "foo%20bar");
+ }
+ }
+
+ static const TStringBuf NonRfcUrls[] = {
+ "http://deshevle.ru/price/price=&SrchTp=1&clID=24&BL=SrchTp=0|clID=24&frmID=75&SortBy=P&PreSort=&NmDir=0&VndDir=0&PrDir=0&SPP=44",
+ "http://secure.rollerwarehouse.com/skates/aggressive/skates/c/11[03]/tx/$$$+11[03][a-z]",
+ "http://secure.rollerwarehouse.com/skates/aggressive/skates/tx/$$$+110[a-z]",
+ "http://translate.google.com/translate_t?langpair=en|ru",
+ "http://www.garnier.com.ru/_ru/_ru/our_products/products_trade.aspx?tpcode=OUR_PRODUCTS^PRD_BODYCARE^EXTRA_SKIN^EXTRA_SKIN_BENEFITS",
+ "http://www.km.ru/magazin/view_print.asp?id={1846295A-223B-41DC-9F51-90D5D6236C49}",
+ "http://www.manutd.com/default.sps?pagegid={78F24B85-702C-4DC8-A5D4-2F67252C28AA}&itype=12977&pagebuildpageid=2716&bg=1",
+ "http://www.pokupay.ru/price/price=&SrchTp=1&clID=24&BL=SrchTp=0|clID=24&frmID=75&SPP=35&SortBy=N&PreSort=V&NmDir=0&VndDir=1&PrDir=0",
+ "http://www.rodnoyspb.ru/rest/plager/page[0].html",
+ "http://www.trinity.by/?section_id=46,47,48&cat=1&filters[]=2^_^Sony",
+ "http://translate.yandex.net/api/v1/tr.json/translate?lang=en-ru&text=>",
+ nullptr};
+
+ Y_UNIT_TEST(test_NonRfcUrls) {
+ TUri url;
+ const long flags = TFeature::FeaturesRobot;
+ for (size_t i = 0;; ++i) {
+ const TStringBuf& buf = NonRfcUrls[i];
+ if (!buf.IsInited())
+ break;
+ UNIT_ASSERT_VALUES_EQUAL(TState::ParsedOK, url.Parse(buf, flags));
+ }
+ }
+
+ static const TStringBuf CheckParseException[] = {
+ "http://www.'>'.com/?.net/",
+ nullptr};
+
+ Y_UNIT_TEST(test_CheckParseException) {
+ TUri url;
+ const long flags = TFeature::FeaturesRobot | TFeature::FeaturesEncode;
+ for (size_t i = 0;; ++i) {
+ const TStringBuf& buf = CheckParseException[i];
+ if (!buf.IsInited())
+ break;
+ TString what;
+ try {
+ // we care only about exceptions, not whether it parses correctly
+ url.Parse(buf, flags);
+ continue;
+ } catch (const std::exception& exc) {
+ what = exc.what();
+ } catch (...) {
+ what = "exception thrown";
+ }
+ ythrow yexception() << "failed to parse URL [" << buf << "]: " << what;
+ }
+ }
+
+ Y_UNIT_TEST(test_PrintPort) {
+ TUri uri;
+ {
+ uri.Parse("http://srv.net:9100/print", TFeature::FeaturesRecommended);
+ TString s = uri.PrintS(TUri::FlagPort);
+ Cdbg << uri.PrintS() << ',' << uri.PrintS(TUri::FlagPort) << Endl;
+ UNIT_ASSERT_VALUES_EQUAL(9100, FromString<ui32>(s));
+ }
+ {
+ uri.Parse("http://srv.net:80/print", TFeature::FeaturesRecommended);
+ TString s = uri.PrintS(TUri::FlagPort);
+ Cdbg << uri.PrintS() << ',' << uri.PrintS(TUri::FlagPort) << Endl;
+ UNIT_ASSERT(s.Empty());
+ }
+ }
+
+ Y_UNIT_TEST(test_ParseFailures) {
+ {
+ TTest test = {
+ "http://host:port", TFeature::FeaturesAll | TFeature::FeatureNoRelPath, TState::ParsedBadFormat, "", "", "", "", Max<ui16>(), "", "", ""};
+ TUri url(-1);
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "http://javascript:alert(hi)", TFeature::FeaturesRobot, TState::ParsedBadFormat, "", "", "", "", Max<ui16>(), "", "", ""};
+ TUri url(-1);
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "http://host::0", TFeature::FeaturesAll | TFeature::FeatureNoRelPath, TState::ParsedBadFormat, "", "", "", "", Max<ui16>(), "", "", ""};
+ TUri url(-1);
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "http://host ", TFeature::FeaturesAll, TState::ParsedBadFormat, "", "", "", "", Max<ui16>(), "", "", ""};
+ TUri url(-1);
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "http:00..03", TFeature::FeaturesAll | TFeature::FeatureNoRelPath, TState::ParsedBadFormat, "", "", "", "", Max<ui16>(), "", "", ""};
+ TUri url(-1);
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "host:00..03", TFeature::FeaturesAll, TState::ParsedRootless, "host", "", "", "", 0, "", "", ""};
+ TUri url(-1);
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "http://roduct;isbn,0307371549;at,aid4c00179ab018www.mcnamarasband.wordpress.com/", TFeature::FeaturesAll, TState::ParsedBadHost, "http", "", "", "roduct;isbn,0307371549;at,aid4c00179ab018www.mcnamarasband.wordpress.com", 80, "/", "", ""};
+ TUri url(-1);
+ URL_TEST(url, test);
+ }
+ {
+ TTest test = {
+ "invalid url", TFeature::FeaturesDefault, TState::ParsedBadFormat, "", "", "", "", 0, "invalid url", "", ""};
+ TUri url(-1);
+ URL_TEST(url, test);
+ }
+ }
+ Y_UNIT_TEST(test_scheme_related_url) {
+ TUri url;
+ UNIT_ASSERT_VALUES_EQUAL(url.Parse("//www.hostname.ru/path", TFeature::FeaturesRobot), TState::ParsedOK);
+ UNIT_ASSERT_EQUAL(url.GetScheme(), TScheme::SchemeEmpty);
+ UNIT_ASSERT_VALUES_EQUAL(url.GetHost(), "www.hostname.ru");
+ UNIT_ASSERT_VALUES_EQUAL(url.GetField(TField::FieldPath), "/path");
+
+ TUri baseUrl;
+ UNIT_ASSERT_VALUES_EQUAL(baseUrl.Parse("https://trololo.com", TFeature::FeaturesRobot), TState::ParsedOK);
+ UNIT_ASSERT_EQUAL(baseUrl.GetScheme(), TScheme::SchemeHTTPS);
+ url.Merge(baseUrl);
+ UNIT_ASSERT_EQUAL(url.GetScheme(), TScheme::SchemeHTTPS);
+ UNIT_ASSERT_VALUES_EQUAL(url.GetHost(), "www.hostname.ru");
+ UNIT_ASSERT_VALUES_EQUAL(url.GetField(TField::FieldPath), "/path");
+ }
+ }
+
+ Y_UNIT_TEST_SUITE(TInvertDomainTest) {
+ Y_UNIT_TEST(TestInvert) {
+ TString a;
+ UNIT_ASSERT_EQUAL(InvertDomain(a), "");
+ TString aa(".:/foo");
+ UNIT_ASSERT_EQUAL(InvertDomain(aa), ".:/foo");
+ TString aaa("/foo.bar:");
+ UNIT_ASSERT_EQUAL(InvertDomain(aaa), "/foo.bar:");
+ TString b("ru");
+ UNIT_ASSERT_EQUAL(InvertDomain(b), "ru");
+ TString c(".ru");
+ UNIT_ASSERT_EQUAL(InvertDomain(c), "ru.");
+ TString d("ru.");
+ UNIT_ASSERT_EQUAL(InvertDomain(d), ".ru");
+ TString e("www.yandex.ru:80/yandsearch?text=foo");
+ UNIT_ASSERT_EQUAL(InvertDomain(e), "ru.yandex.www:80/yandsearch?text=foo");
+ TString f("www.yandex.ru:80/yandsearch?text=foo");
+ InvertDomain(f.begin(), f.begin() + 10);
+ UNIT_ASSERT_EQUAL(f, "yandex.www.ru:80/yandsearch?text=foo");
+ TString g("https://www.yandex.ru:80//");
+ UNIT_ASSERT_EQUAL(InvertDomain(g), "https://ru.yandex.www:80//");
+ TString h("www.yandex.ru:8080/redir.pl?url=https://google.com/");
+ UNIT_ASSERT_EQUAL(InvertDomain(h), "ru.yandex.www:8080/redir.pl?url=https://google.com/");
+ }
+ }
+
+ TQueryArg::EProcessed ProcessQargs(TString url, TString& processed, TQueryArgFilter filter = 0, void* filterData = 0) {
+ TUri uri;
+ uri.Parse(url, NUri::TFeature::FeaturesRecommended);
+
+ TQueryArgProcessing processing(TQueryArg::FeatureSortByName | (filter ? TQueryArg::FeatureFilter : 0) | TQueryArg::FeatureRewriteDirty, filter, filterData);
+ auto result = processing.Process(uri);
+ processed = uri.PrintS();
+ return result;
+ }
+
+ TString SortQargs(TString url) {
+ TString r;
+ ProcessQargs(url, r);
+ return r;
+ }
+
+ bool QueryArgsFilter(const TQueryArg& arg, void* filterData) {
+ const char* skipName = static_cast<const char*>(filterData);
+ return arg.Name != skipName;
+ }
+
+ TString FilterQargs(TString url, const char* name) {
+ TString r;
+ ProcessQargs(url, r, &QueryArgsFilter, const_cast<char*>(name));
+ return r;
+ }
+
+ Y_UNIT_TEST_SUITE(QargsTest) {
+ Y_UNIT_TEST(TestSorting) {
+ UNIT_ASSERT_STRINGS_EQUAL(SortQargs("http://ya.ru/"), "http://ya.ru/");
+ UNIT_ASSERT_STRINGS_EQUAL(SortQargs("http://ya.ru/?"), "http://ya.ru/?");
+ UNIT_ASSERT_STRINGS_EQUAL(SortQargs("http://ya.ru/?some=value"), "http://ya.ru/?some=value");
+ UNIT_ASSERT_STRINGS_EQUAL(SortQargs("http://ya.ru/?b=1&a=2"), "http://ya.ru/?a=2&b=1");
+ UNIT_ASSERT_STRINGS_EQUAL(SortQargs("http://ya.ru/?b=1&a=2&a=3"), "http://ya.ru/?a=3&a=2&b=1");
+
+ UNIT_ASSERT_STRINGS_EQUAL(SortQargs("http://ya.ru/?aaa=3&b=b&a=1&aa=2"), "http://ya.ru/?a=1&aa=2&aaa=3&b=b");
+
+ UNIT_ASSERT_STRINGS_EQUAL(SortQargs("http://ya.ru/?a=1&b=1&c=1"), "http://ya.ru/?a=1&b=1&c=1");
+ UNIT_ASSERT_STRINGS_EQUAL(SortQargs("http://ya.ru/?b=1&a=1&c=1"), "http://ya.ru/?a=1&b=1&c=1");
+ UNIT_ASSERT_STRINGS_EQUAL(SortQargs("http://ya.ru/?c=1&a=1&b=1"), "http://ya.ru/?a=1&b=1&c=1");
+
+ UNIT_ASSERT_STRINGS_EQUAL(SortQargs("http://ya.ru/?c=1&a=1&a=1&b=1&c=1&b=1"), "http://ya.ru/?a=1&a=1&b=1&b=1&c=1&c=1");
+
+ UNIT_ASSERT_STRINGS_EQUAL(SortQargs("http://ya.ru/?b==&a=&&c="), "http://ya.ru/?a=&b==&c=");
+ }
+
+ Y_UNIT_TEST(TestParsingCorners) {
+ TString s;
+
+ UNIT_ASSERT_EQUAL(ProcessQargs("http://ya.ru/?=", s), TQueryArg::ProcessedOK);
+ UNIT_ASSERT_EQUAL(ProcessQargs("http://ya.ru/?some", s), TQueryArg::ProcessedOK);
+ UNIT_ASSERT_EQUAL(ProcessQargs("http://ya.ru/?some=", s), TQueryArg::ProcessedOK);
+ UNIT_ASSERT_EQUAL(ProcessQargs("http://ya.ru/", s), TQueryArg::ProcessedOK);
+ UNIT_ASSERT_EQUAL(ProcessQargs("http://ya.ru/?&", s), TQueryArg::ProcessedOK);
+ UNIT_ASSERT_EQUAL(ProcessQargs("http://ya.ru/?&&", s), TQueryArg::ProcessedOK);
+ UNIT_ASSERT_EQUAL(ProcessQargs("http://ya.ru/?some=", s), TQueryArg::ProcessedOK);
+ UNIT_ASSERT_EQUAL(ProcessQargs("http://ya.ru/?some==", s), TQueryArg::ProcessedOK);
+ UNIT_ASSERT_EQUAL(ProcessQargs("http://ya.ru/?some=&&", s), TQueryArg::ProcessedOK);
+
+ UNIT_ASSERT_STRINGS_EQUAL(SortQargs("http://ya.ru/?="), "http://ya.ru/?=");
+ UNIT_ASSERT_STRINGS_EQUAL(SortQargs("http://ya.ru/?some=="), "http://ya.ru/?some==");
+ UNIT_ASSERT_STRINGS_EQUAL(SortQargs("http://ya.ru/?&&"), "http://ya.ru/?&&");
+ UNIT_ASSERT_STRINGS_EQUAL(SortQargs("http://ya.ru/?a"), "http://ya.ru/?a");
+ }
+
+ Y_UNIT_TEST(TestFiltering) {
+ UNIT_ASSERT_STRINGS_EQUAL(FilterQargs("http://ya.ru/?some=value", "missing"), "http://ya.ru/?some=value");
+ UNIT_ASSERT_STRINGS_EQUAL(FilterQargs("http://ya.ru/?b=1&a=2", "b"), "http://ya.ru/?a=2");
+ UNIT_ASSERT_STRINGS_EQUAL(FilterQargs("http://ya.ru/?b=1&a=2&a=3", "a"), "http://ya.ru/?b=1");
+ UNIT_ASSERT_STRINGS_EQUAL(FilterQargs("http://ya.ru/?some=&another=", "another"), "http://ya.ru/?some=");
+ }
+
+ Y_UNIT_TEST(TestRemoveEmptyFeature) {
+ TUri uri;
+ uri.Parse("http://ya.ru/?", NUri::TFeature::FeaturesRecommended);
+
+ TQueryArgProcessing processing(TQueryArg::FeatureRemoveEmptyQuery | TQueryArg::FeatureRewriteDirty);
+ auto result = processing.Process(uri);
+ UNIT_ASSERT_EQUAL(result, TQueryArg::ProcessedOK);
+ UNIT_ASSERT_STRINGS_EQUAL(uri.PrintS(), "http://ya.ru/");
+ }
+
+ Y_UNIT_TEST(TestNoRemoveEmptyFeature) {
+ TUri uri;
+ uri.Parse("http://ya.ru/?", NUri::TFeature::FeaturesRecommended);
+
+ TQueryArgProcessing processing(0);
+ auto result = processing.Process(uri);
+ UNIT_ASSERT_EQUAL(result, TQueryArg::ProcessedOK);
+ UNIT_ASSERT_STRINGS_EQUAL(uri.PrintS(), "http://ya.ru/?");
+ }
+ }
+}
diff --git a/library/cpp/uri/uri_ut.h b/library/cpp/uri/uri_ut.h
new file mode 100644
index 0000000000..f8ac6e4092
--- /dev/null
+++ b/library/cpp/uri/uri_ut.h
@@ -0,0 +1,81 @@
+#pragma once
+
+#include "uri.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+namespace NUri {
+ struct TTest {
+ TStringBuf Val;
+ TParseFlags Flags;
+ TState::EParsed State;
+ TStringBuf Scheme;
+ TStringBuf User;
+ TStringBuf Pass;
+ TStringBuf Host;
+ ui16 Port;
+ TStringBuf Path;
+ TStringBuf Query;
+ TStringBuf Frag;
+ };
+
+}
+
+#define URL_MSG(url1, url2, cmp) \
+ (TString("[") + url1.PrintS() + ("] " cmp " [") + url2.PrintS() + "]")
+#define URL_EQ(url1, url2) \
+ UNIT_ASSERT_EQUAL_C(url, url2, URL_MSG(url1, url2, "!="))
+#define URL_NEQ(url1, url2) \
+ UNIT_ASSERT_UNEQUAL_C(url, url2, URL_MSG(url1, url2, "=="))
+
+#define CMP_FLD(url, test, fld) \
+ UNIT_ASSERT_VALUES_EQUAL(url.GetField(TField::Field##fld), test.fld)
+
+#define CMP_URL(url, test) \
+ do { \
+ CMP_FLD(url, test, Scheme); \
+ CMP_FLD(url, test, User); \
+ CMP_FLD(url, test, Pass); \
+ CMP_FLD(url, test, Host); \
+ UNIT_ASSERT_VALUES_EQUAL(url.GetPort(), test.Port); \
+ CMP_FLD(url, test, Path); \
+ CMP_FLD(url, test, Query); \
+ CMP_FLD(url, test, Frag); \
+ } while (false)
+
+#define URL_TEST_ENC(url, test, enc) \
+ do { \
+ TState::EParsed st = url.ParseUri(test.Val, test.Flags, 0, enc); \
+ UNIT_ASSERT_VALUES_EQUAL(st, test.State); \
+ CMP_URL(url, test); \
+ if (TState::ParsedOK != st) \
+ break; \
+ TUri _url; \
+ TString urlstr, urlstr2; \
+ urlstr = url.PrintS(); \
+ TState::EParsed st2 = _url.ParseUri(urlstr, \
+ (test.Flags & ~TFeature::FeatureNoRelPath) | TFeature::FeatureAllowRootless, 0, enc); \
+ if (TState::ParsedEmpty != st2) \
+ UNIT_ASSERT_VALUES_EQUAL(st2, test.State); \
+ urlstr2 = _url.PrintS(); \
+ UNIT_ASSERT_VALUES_EQUAL(urlstr, urlstr2); \
+ CMP_URL(_url, test); \
+ UNIT_ASSERT_VALUES_EQUAL(url.GetUrlFieldMask(), _url.GetUrlFieldMask()); \
+ URL_EQ(url, _url); \
+ const TStringBuf hostascii = url.GetField(TField::FieldHostAscii); \
+ if (hostascii.Empty()) \
+ break; \
+ urlstr = url.PrintS(TField::FlagHostAscii); \
+ st2 = _url.ParseUri(urlstr, \
+ (test.Flags & ~TFeature::FeatureNoRelPath) | TFeature::FeatureAllowRootless, 0, enc); \
+ UNIT_ASSERT_VALUES_EQUAL(st2, test.State); \
+ urlstr2 = _url.PrintS(); \
+ UNIT_ASSERT_VALUES_EQUAL(urlstr, urlstr2); \
+ TTest test2 = test; \
+ test2.Host = hostascii; \
+ CMP_URL(_url, test2); \
+ UNIT_ASSERT_VALUES_EQUAL(url.GetUrlFieldMask(), _url.GetUrlFieldMask()); \
+ } while (false)
+
+#define URL_TEST(url, test) \
+ URL_TEST_ENC(url, test, CODES_UTF8)
diff --git a/library/cpp/uri/ut/ya.make b/library/cpp/uri/ut/ya.make
new file mode 100644
index 0000000000..b2b2c1291a
--- /dev/null
+++ b/library/cpp/uri/ut/ya.make
@@ -0,0 +1,19 @@
+UNITTEST_FOR(library/cpp/uri)
+
+OWNER(leo)
+
+NO_OPTIMIZE()
+
+NO_WSHADOW()
+
+PEERDIR(
+ library/cpp/html/entity
+)
+
+SRCS(
+ location_ut.cpp
+ uri-ru_ut.cpp
+ uri_ut.cpp
+)
+
+END()
diff --git a/library/cpp/uri/ya.make b/library/cpp/uri/ya.make
new file mode 100644
index 0000000000..8fc808a6af
--- /dev/null
+++ b/library/cpp/uri/ya.make
@@ -0,0 +1,32 @@
+LIBRARY()
+
+OWNER(
+ mvel
+ g:base
+)
+
+SRCS(
+ assign.cpp
+ common.cpp
+ encode.cpp
+ http_url.h
+ location.cpp
+ other.cpp
+ parse.cpp
+ qargs.cpp
+ uri.cpp
+ encodefsm.rl6
+ parsefsm.rl6
+)
+
+PEERDIR(
+ contrib/libs/libidn
+ library/cpp/charset
+)
+
+END()
+
+RECURSE(
+ benchmark
+ ut
+)
diff --git a/library/cpp/xml/document/README b/library/cpp/xml/document/README
new file mode 100644
index 0000000000..b2649523d8
--- /dev/null
+++ b/library/cpp/xml/document/README
@@ -0,0 +1,42 @@
+A wrapper around the DOM interface of libxml2.
+
+The standard way to use it is as follows:
+
+ #include <library/cpp/xml/document/xml-document.h>
+ ...
+
+ // open a document
+ NXml::TDocument xml("filename.xml");
+
+ // get a nodeset from an XPath query
+ NXml::TConstNodes nodes = xml.Root().Nodes("xpath/expression/here");
+
+ // iterate over the nodeset
+ for (size_t i = 0; i < nodes.size(); ++i) {
+ using namespace NXml;
+ TConstNode& node = nodes[i];
+ // query node
+ TString name = node.Name();
+ TString lang = node.Attr<TString>("lang");
+ TString text = node.Value<TString>();
+ TConstNode child = node.GetFirstChild("");
+ // edit node
+ TNode node = child.ConstCast();
+ node.DelAttr("id");
+ node.SetAttr("x", 2);
+ node.SetValue(5);
+ node.AddText(" apples");
+ }
+
+ // edit documents with copy-paste
+ NXml::TDocument xml2("<xpath><node/></xpath>", NXml::TDocument::String);
+ NXml::TNode place = xml2.Root().Node("xpath/node");
+ // copy node's subtree from one document to another
+ place.AddChild(xml.Root());
+ // save (render) single element
+ TString modifiedNode = place.ToString();
+ // save whole document with optional encoding
+ TString modifiedDoc = xml2.ToString("ISO-8559-1");
+
+
+See xml-document_ut.cpp for more examples.
diff --git a/library/cpp/xml/document/libxml-guards.h b/library/cpp/xml/document/libxml-guards.h
new file mode 100644
index 0000000000..4188cecff1
--- /dev/null
+++ b/library/cpp/xml/document/libxml-guards.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <library/cpp/xml/init/ptr.h>
+#include <util/generic/ptr.h>
+#include <libxml/xmlstring.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/uri.h>
+#include <libxml/xmlsave.h>
+
+namespace NXml {
+ namespace NDetail {
+ struct TSignedCharPtrTraits {
+ static void Destroy(char* handle) {
+ xmlFree(handle);
+ }
+ };
+
+ struct TCharPtrTraits {
+ static void Destroy(xmlChar* handle) {
+ xmlFree(handle);
+ }
+ };
+
+ struct TOutputBufferPtrTraits {
+ static void Destroy(xmlOutputBufferPtr handle) {
+ xmlOutputBufferClose(handle);
+ }
+ };
+
+ struct TSaveCtxtPtrTraits {
+ static void Destroy(xmlSaveCtxtPtr handle) {
+ xmlSaveClose(handle);
+ }
+ };
+
+ }
+
+ typedef TxmlXPathContextPtr TXPathContextPtr;
+ typedef TxmlXPathObjectPtr TXPathObjectPtr;
+ typedef TAutoPtr<char, NDetail::TSignedCharPtrTraits> TSignedCharPtr;
+ typedef TAutoPtr<xmlChar, NDetail::TCharPtrTraits> TCharPtr;
+ typedef TxmlDocHolder TDocHolder;
+ typedef TxmlURIPtr TURIPtr;
+ typedef TxmlNodePtr TNodePtr;
+ typedef TAutoPtr<xmlOutputBuffer, NDetail::TOutputBufferPtrTraits> TOutputBufferPtr;
+ typedef TxmlParserCtxtPtr TParserCtxtPtr;
+ typedef TAutoPtr<xmlSaveCtxt, NDetail::TSaveCtxtPtrTraits> TSaveCtxtPtr;
+
+}
diff --git a/library/cpp/xml/document/node-attr.h b/library/cpp/xml/document/node-attr.h
new file mode 100644
index 0000000000..6e74403943
--- /dev/null
+++ b/library/cpp/xml/document/node-attr.h
@@ -0,0 +1,209 @@
+#pragma once
+
+#include "xml-document-decl.h"
+#include "libxml-guards.h"
+#include <util/stream/str.h>
+#include <util/string/cast.h>
+
+namespace NXml {
+#define THROW(x, y) ythrow yexception() << #x << ": " << y
+
+ // libxml defines unsigned char -> xmlChar,
+ // and all functions use xmlChar.
+ inline static const char* CAST2CHAR(const xmlChar* x) {
+ return reinterpret_cast<const char*>(x);
+ }
+ inline static const xmlChar* XMLCHAR(const char* x) {
+ return reinterpret_cast<const xmlChar*>(x);
+ }
+
+ template <class T>
+ void TNode::AttrInternal(TCharPtr& value, T& res, TStringBuf errContext) const {
+ try {
+ res = FromString<T>(CAST2CHAR(value.Get()));
+ } catch (TFromStringException&) {
+ THROW(XmlException, "Failed to convert string " << TString{TStringBuf(CAST2CHAR(value.Get())).substr(0, 50)}.Quote() << " from '" << errContext << "' to requested type");
+ }
+ }
+
+ template <>
+ inline void TNode::AttrInternal(TCharPtr& value, TString& res, TStringBuf /*errContext*/) const {
+ TString tmp(CAST2CHAR(value.Get()));
+ res.swap(tmp);
+ }
+
+ template <class T>
+ T TNode::Attr(TZtStringBuf name) const {
+ TCharPtr value(xmlGetProp(NodePointer, XMLCHAR(name.c_str())));
+ if (!value) {
+ THROW(AttributeNotFound, Path() << "@" << name);
+ }
+
+ T t;
+ AttrInternal(value, t, name);
+ return t;
+ }
+
+ template <class T>
+ T TNode::Attr(TZtStringBuf name, const T& defvalue) const {
+ TCharPtr attr(xmlGetProp(NodePointer, XMLCHAR(name.c_str())));
+ if (!attr) {
+ return defvalue;
+ }
+
+ T t;
+ AttrInternal(attr, t, name);
+ return t;
+ }
+
+ template <class T>
+ void TNode::Attr(TZtStringBuf name, T& value) const {
+ TCharPtr attr(xmlGetProp(NodePointer, XMLCHAR(name.c_str())));
+ if (!attr) {
+ THROW(AttributeNotFound, Path() << name);
+ }
+
+ AttrInternal(attr, value, name);
+ }
+
+ template <class T>
+ void TNode::Attr(TZtStringBuf name, T& value, const T& defvalue) const {
+ TCharPtr attr(xmlGetProp(NodePointer, XMLCHAR(name.c_str())));
+
+ if (!attr) {
+ value = defvalue;
+ } else {
+ AttrInternal(attr, value, name);
+ }
+ }
+
+ template <class T>
+ T TNode::Value() const {
+ if (!NodePointer || xmlIsBlankNode(NodePointer)) {
+ THROW(NodeIsBlank, Path());
+ }
+
+ TCharPtr val(xmlNodeGetContent(NodePointer));
+ T t;
+ AttrInternal(val, t, this->Name());
+ return t;
+ }
+
+ template <class T>
+ T TNode::Value(const T& defvalue) const {
+ if (!NodePointer || xmlIsBlankNode(NodePointer)) {
+ return defvalue;
+ }
+
+ TCharPtr val(xmlNodeGetContent(NodePointer));
+ T t;
+ AttrInternal(val, t, this->Name());
+ return t;
+ }
+
+ template <class T>
+ typename std::enable_if<!std::is_convertible_v<T, TStringBuf>, void>::type
+ TNode::SetValue(const T& value) {
+ TStringStream ss;
+ ss << value;
+ SetValue(ss.Str());
+ }
+
+ inline void TNode::SetValue(TStringBuf value) {
+ xmlNodeSetContent(NodePointer, XMLCHAR(""));
+ xmlNodeAddContentLen(NodePointer, XMLCHAR(value.data()), value.Size());
+ }
+
+ inline void TNode::SetAttr(TZtStringBuf name, TZtStringBuf value) {
+ xmlAttr* attr = xmlSetProp(NodePointer, XMLCHAR(name.c_str()), XMLCHAR(value.c_str()));
+
+ if (!attr) {
+ THROW(XmlException, "Can't set node attribute <"
+ << name
+ << "> to <"
+ << value
+ << ">");
+ }
+ }
+
+ template <class T>
+ typename std::enable_if<!std::is_convertible_v<T, TZtStringBuf>, void>::type
+ TNode::SetAttr(TZtStringBuf name, const T& value) {
+ TStringStream ss;
+ ss << value;
+ SetAttr(name, TZtStringBuf(ss.Str()));
+ }
+
+ inline void TNode::SetAttr(TZtStringBuf name) {
+ xmlAttr* attr = xmlSetProp(NodePointer, XMLCHAR(name.c_str()), nullptr);
+
+ if (!attr) {
+ THROW(XmlException, "Can't set node empty attribute <"
+ << name
+ << ">");
+ }
+ }
+
+ inline void TNode::DelAttr(TZtStringBuf name) {
+ if (xmlUnsetProp(NodePointer, XMLCHAR(name.c_str())) < 0)
+ THROW(XmlException, "Can't delete node attribute <"
+ << name
+ << ">");
+ }
+
+ template <class T>
+ typename std::enable_if<!std::is_convertible_v<T, TZtStringBuf>, TNode>::type
+ TNode::AddChild(TZtStringBuf name, const T& value) {
+ TStringStream ss;
+ ss << value;
+ return AddChild(name, TZtStringBuf(ss.Str()));
+ }
+
+ inline TNode TNode::AddChild(TZtStringBuf name, TZtStringBuf value) {
+ if (IsNull()) {
+ THROW(XmlException, "addChild [name=" << name << ", value=" << value
+ << "]: can't add child to null node");
+ }
+
+ xmlNode* child = nullptr;
+
+ if (value.empty()) {
+ child = xmlNewTextChild(NodePointer, nullptr, XMLCHAR(name.c_str()), nullptr);
+ } else {
+ child = xmlNewTextChild(
+ NodePointer, nullptr, XMLCHAR(name.c_str()), XMLCHAR(value.c_str()));
+ }
+
+ if (!child) {
+ THROW(XmlException, "addChild [name=" << name << ", value=" << value
+ << "]: xmlNewTextChild returned NULL");
+ }
+
+ return TNode(DocPointer, child);
+ }
+
+ template <class T>
+ typename std::enable_if<!std::is_convertible_v<T, TStringBuf>, TNode>::type
+ TNode::AddText(const T& value) {
+ TStringStream ss;
+ ss << value;
+ return AddText(ss.Str());
+ }
+
+ inline TNode TNode::AddText(TStringBuf value) {
+ if (IsNull()) {
+ THROW(XmlException, "addChild [value=" << value
+ << "]: can't add child to null node");
+ }
+
+ xmlNode* child = xmlNewTextLen((xmlChar*)value.data(), value.size());
+ child = xmlAddChild(NodePointer, child);
+
+ if (!child) {
+ THROW(XmlException, "addChild [value=" << value
+ << "]: xmlNewTextChild returned NULL");
+ }
+
+ return TNode(DocPointer, child);
+ }
+}
diff --git a/library/cpp/xml/document/ut/ya.make b/library/cpp/xml/document/ut/ya.make
new file mode 100644
index 0000000000..e955448c66
--- /dev/null
+++ b/library/cpp/xml/document/ut/ya.make
@@ -0,0 +1,11 @@
+UNITTEST_FOR(library/cpp/xml/document)
+
+OWNER(finder)
+
+SRCS(
+ xml-document_ut.cpp
+ xml-textreader_ut.cpp
+ xml-options_ut.cpp
+)
+
+END()
diff --git a/library/cpp/xml/document/xml-document-decl.h b/library/cpp/xml/document/xml-document-decl.h
new file mode 100644
index 0000000000..bfda1fb7e6
--- /dev/null
+++ b/library/cpp/xml/document/xml-document-decl.h
@@ -0,0 +1,718 @@
+#pragma once
+
+#include <library/cpp/string_utils/ztstrbuf/ztstrbuf.h>
+
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/stream/output.h>
+#include <util/stream/str.h>
+#include <algorithm>
+#include "libxml-guards.h"
+
+namespace NXml {
+ class TNode;
+
+ class TConstNodes;
+ class TConstNode;
+
+ using TXPathContext = xmlXPathContext;
+
+ class TDocument {
+ public:
+ enum Source {
+ File,
+ String,
+ RootName,
+ };
+
+ public:
+ /**
+ * create TDocument
+ * @param source: filename, XML string, or name for the root element (depends on @src)
+ * @param src: source type: File | String | RootName
+ * throws if file not found or cannot be parsed
+ */
+ TDocument(const TString& source, Source type = File);
+
+ public:
+ TDocument(const TDocument& that) = delete;
+ TDocument& operator=(const TDocument& that) = delete;
+
+ TDocument(TDocument&& that);
+ TDocument& operator=(TDocument&& that);
+
+ /**
+ * get root element
+ */
+ TNode Root();
+ TConstNode Root() const;
+
+ void Save(IOutputStream& stream, TZtStringBuf enc = "", bool shouldFormat = true) const {
+ int bufferSize = 0;
+ xmlChar* xmlBuff = nullptr;
+ const char* encoding = enc.size() ? enc.data() : Doc->encoding ? nullptr : "UTF-8";
+ xmlDocDumpFormatMemoryEnc(Doc.Get(), &xmlBuff, &bufferSize, encoding, shouldFormat);
+ TCharPtr xmlCharBuffPtr(xmlBuff);
+ stream.Write(xmlBuff, bufferSize);
+ }
+
+ TString ToString(TZtStringBuf enc = "", bool shouldFormat = true) const {
+ TStringStream s;
+ Save(s, enc, shouldFormat);
+ return s.Str();
+ }
+
+ void Swap(TDocument& that) {
+ std::swap(this->Doc, that.Doc);
+ }
+
+ xmlDocPtr GetImpl() {
+ return Doc.Get();
+ }
+
+ private:
+ void ParseFile(const TString& file);
+ void ParseString(TZtStringBuf xml);
+
+ TDocument(TDocHolder doc)
+ : Doc(std::move(doc))
+ {
+ }
+
+ TDocHolder Doc;
+ };
+
+ struct TNamespaceForXPath {
+ TString Prefix;
+ TString Url;
+ };
+ typedef TVector<TNamespaceForXPath> TNamespacesForXPath;
+
+ class TConstNodes {
+ private:
+ struct TConstNodesRef {
+ explicit TConstNodesRef(TConstNodes& n)
+ : r_(n)
+ {
+ }
+ TConstNodes& r_;
+ };
+
+ public:
+ TConstNodes(const TConstNodes& nodes);
+ TConstNodes& operator=(const TConstNodes& nodes);
+
+ TConstNodes(TConstNodesRef ref);
+ TConstNodes& operator=(TConstNodesRef ref);
+
+ operator TConstNodesRef();
+
+ /**
+ * get node by id
+ * @param number: node id
+ */
+ TConstNode operator[](size_t number) const;
+
+ /**
+ * get number of nodes
+ */
+ size_t Size() const {
+ return SizeValue;
+ }
+ size_t size() const {
+ return SizeValue;
+ }
+
+ struct TNodeIter {
+ const TConstNodes& Nodes;
+ size_t Index;
+ TConstNode operator*() const;
+ bool operator==(const TNodeIter& other) const {
+ return Index == other.Index;
+ }
+ bool operator!=(const TNodeIter& other) const {
+ return !(*this == other);
+ }
+ TNodeIter operator++() {
+ Index++;
+ return *this;
+ }
+ };
+ TNodeIter begin() const {
+ return TNodeIter{*this, 0};
+ }
+ TNodeIter end() const {
+ return TNodeIter{*this, size()};
+ }
+
+ private:
+ friend class TDocument;
+ friend class TConstNode;
+ friend class TNode;
+
+ TConstNodes(xmlDoc* doc, TXPathObjectPtr obj);
+
+ size_t SizeValue;
+ xmlDoc* Doc;
+ TXPathObjectPtr Obj;
+ };
+
+ class TNode {
+ public:
+ friend class TDocument;
+ friend class TConstNode;
+ friend class TTextReader;
+
+ /**
+ * check if node is null
+ */
+ bool IsNull() const;
+
+ /**
+ * check if node is element node
+ */
+ bool IsElementNode() const;
+
+ /**
+ * Create xpath context to be used later for fast xpath evaluation.
+ * @param nss: explicitly specify XML namespaces to use and their prefixes
+ *
+ * For better performance, when you need to evaluate several xpath expressions,
+ * it makes sense to create a context, load namespace prefixes once
+ * and use the context several times in Node(), Nodes(), XPath() function calls for several nodes.
+ * The context may be used with any node of the current document, but
+ * cannot be shared between different XML documents.
+ */
+ TXPathContextPtr CreateXPathContext(const TNamespacesForXPath& nss = TNamespacesForXPath()) const;
+
+ /**
+ * get all element nodes matching given xpath expression
+ * @param xpath: xpath expression
+ * @param quiet: don't throw exception if zero nodes found
+ * @param ns: explicitly specify XML namespaces to use and their prefixes
+ *
+ * For historical reasons, this only works for *element* nodes.
+ * Use the XPath function if you need other kinds of nodes.
+ */
+ TConstNodes Nodes(TZtStringBuf xpath, bool quiet = false, const TNamespacesForXPath& ns = TNamespacesForXPath()) const;
+
+ /**
+ * get all element nodes matching given xpath expression
+ * @param xpath: xpath expression
+ * @param quiet: don't throw exception if zero nodes found
+ * @param ctxt: reusable xpath context
+ *
+ * For historical reasons, this only works for *element* nodes.
+ * Use the XPath function if you need other kinds of nodes.
+ */
+ TConstNodes Nodes(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt) const;
+
+ /**
+ * get all nodes matching given xpath expression
+ * @param xpath: xpath expression
+ * @param quiet: don't throw exception if zero nodes found
+ * @param ns: explicitly specify XML namespaces to use and their prefixes
+ */
+ TConstNodes XPath(TZtStringBuf xpath, bool quiet = false, const TNamespacesForXPath& ns = TNamespacesForXPath()) const;
+
+ /**
+ * get all nodes matching given xpath expression
+ * @param xpath: xpath expression
+ * @param quiet: don't throw exception if zero nodes found
+ * @param ctxt: reusable xpath context
+ */
+ TConstNodes XPath(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt) const;
+
+ /**
+ * get the first element node matching given xpath expression
+ * @param xpath: path to node (from current node)
+ * @param quiet: don't throw exception if node not found,
+ * return null node (@see IsNull())
+ * @param ns: explicitly specify XML namespaces to use and their prefixes
+ *
+ * For historical reasons, this only works for *element* nodes.
+ * Use the XPath function if you need other kinds of nodes.
+ */
+ /// @todo: quiet should be default, empty nodeset is not an error
+ TNode Node(TZtStringBuf xpath, bool quiet = false, const TNamespacesForXPath& ns = TNamespacesForXPath());
+ TConstNode Node(TZtStringBuf xpath, bool quiet = false, const TNamespacesForXPath& ns = TNamespacesForXPath()) const;
+
+ /**
+ * get the first element node matching given xpath expression
+ * @param xpath: path to node (from current node)
+ * @param quiet: don't throw exception if node not found,
+ * return null node (@see IsNull())
+ * @param ctxt: reusable xpath context
+ *
+ * For historical reasons, this only works for *element* nodes.
+ * Use the XPath function if you need other kinds of nodes.
+ */
+ TNode Node(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt);
+ TConstNode Node(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt) const;
+
+ /**
+ * get node first child
+ * @param name: child name
+ * @note if name is empty, returns the first child node of type "element"
+ * @note returns null node if no child found
+ */
+ TNode FirstChild(TZtStringBuf name);
+ TConstNode FirstChild(TZtStringBuf name) const;
+
+ TNode FirstChild();
+ TConstNode FirstChild() const;
+
+ /**
+ * get parent node
+ * throws exception if has no parent
+ */
+ TNode Parent();
+ TConstNode Parent() const;
+
+ /**
+ * get node neighbour
+ * @param name: neighbour name
+ * @note if name is empty, returns the next sibling node of type "element"
+ * @node returns null node if no neighbour found
+ */
+ TNode NextSibling(TZtStringBuf name);
+ TConstNode NextSibling(TZtStringBuf name) const;
+
+ TNode NextSibling();
+ TConstNode NextSibling() const;
+
+ /**
+ * create child node
+ * @param name: child name
+ * returns new empty node
+ */
+ TNode AddChild(TZtStringBuf name);
+
+ /**
+ * create child node with given value
+ * @param name: child name
+ * @param value: node value
+ */
+ template <class T>
+ typename std::enable_if<!std::is_convertible_v<T, TZtStringBuf>, TNode>::type
+ AddChild(TZtStringBuf name, const T& value);
+
+ TNode AddChild(TZtStringBuf name, TZtStringBuf value);
+
+ /**
+ * add child node, making recursive copy of original
+ * @param node: node to copy from
+ * returns added node
+ */
+ TNode AddChild(const TConstNode& node);
+
+ /**
+ * create text child node
+ * @param name: child name
+ * @param value: node value
+ */
+ template <class T>
+ typename std::enable_if<!std::is_convertible_v<T, TStringBuf>, TNode>::type
+ AddText(const T& value);
+
+ TNode AddText(TStringBuf value);
+
+ /**
+ * get node attribute
+ * @param name: attribute name
+ * throws exception if attribute not found
+ */
+ template <class T>
+ T Attr(TZtStringBuf name) const;
+
+ /**
+ * get node attribute
+ * @param name: attribute name
+ * returns default value if attribute not found
+ */
+ template <class T>
+ T Attr(TZtStringBuf name, const T& defvalue) const;
+
+ /**
+ * get node attribute
+ * @param name: attribute name
+ * @param value: return-value
+ * throws exception if attribute not found
+ */
+ template <class T>
+ void Attr(TZtStringBuf name, T& value) const;
+
+ /**
+ * get node attribute
+ * @param name: attribute name
+ * @param defvalue: default value
+ * @param value: return-value
+ * returns default value if attribute not found, attr value otherwise
+ */
+ template <class T>
+ void Attr(TZtStringBuf name, T& value, const T& defvalue) const;
+
+ /**
+ * get node value (text)
+ * @throws exception if node is blank
+ */
+ template <class T>
+ T Value() const;
+
+ /**
+ * get node value
+ * @param defvalue: default value
+ * returns default value if node is blank
+ */
+ template <class T>
+ T Value(const T& defvalue) const;
+
+ /**
+ * set node value
+ * @param value: new text value
+ */
+ template <class T>
+ typename std::enable_if<!std::is_convertible_v<T, TStringBuf>, void>::type
+ SetValue(const T& value);
+
+ void SetValue(TStringBuf value);
+
+ /**
+ * set/reset node attribute value,
+ * if attribute does not exist, it'll be created
+ * @param name: attribute name
+ * @param value: attribute value
+ */
+ template<class T>
+ typename std::enable_if<!std::is_convertible_v<T, TZtStringBuf>, void>::type
+ SetAttr(TZtStringBuf name, const T& value);
+
+ void SetAttr(TZtStringBuf name, TZtStringBuf value);
+
+ void SetAttr(TZtStringBuf name);
+
+ /**
+ * delete node attribute
+ * @param name: attribute name
+ */
+ void DelAttr(TZtStringBuf name);
+
+ /**
+ * set node application data
+ * @param priv: new application data pointer
+ */
+ void SetPrivate(void* priv);
+
+ /**
+ * @return application data pointer, passed by SetPrivate
+ */
+ void* GetPrivate() const;
+
+ /**
+ * get node name
+ */
+ TString Name() const;
+
+ /**
+ * get node xpath
+ */
+ TString Path() const;
+
+ /**
+ * get node xml representation
+ */
+ TString ToString(TZtStringBuf enc = "") const {
+ TStringStream s;
+ Save(s, enc);
+ return s.Str();
+ }
+ void Save(IOutputStream& stream, TZtStringBuf enc = "", bool shouldFormat = false) const;
+ void SaveAsHtml(IOutputStream& stream, TZtStringBuf enc = "", bool shouldFormat = false) const;
+
+ /**
+ * get pointer to internal node
+ */
+ xmlNode* GetPtr();
+ const xmlNode* GetPtr() const;
+
+ /**
+ * check if node is text-only node
+ */
+ bool IsText() const;
+
+ /**
+ * unlink node from parent and free
+ */
+ void Remove();
+
+ /**
+ * constructs null node
+ */
+ TNode()
+ : NodePointer(nullptr)
+ , DocPointer(nullptr)
+ {
+ }
+
+ private:
+ friend class TConstNodes;
+
+ TNode(xmlDoc* doc, xmlNode* node)
+ : NodePointer(node)
+ , DocPointer(doc)
+ {
+ }
+
+ TNode Find(xmlNode* start, TZtStringBuf name);
+
+ template <class T>
+ void AttrInternal(TCharPtr& value, T& res, TStringBuf errContext) const;
+
+ void SaveInternal(IOutputStream& stream, TZtStringBuf enc, int options) const;
+
+ xmlNode* NodePointer;
+ xmlDoc* DocPointer;
+ };
+
+ class TConstNode {
+ public:
+ friend class TDocument;
+ friend class TConstNodes;
+ friend class TNode;
+ /**
+ * check if node is null
+ */
+ bool IsNull() const {
+ return ActualNode.IsNull();
+ }
+
+ bool IsElementNode() const {
+ return ActualNode.IsElementNode();
+ }
+
+ TConstNode Parent() const {
+ return ActualNode.Parent();
+ }
+
+ /**
+ * Create xpath context to be used later for fast xpath evaluation.
+ * @param nss: explicitly specify XML namespaces to use and their prefixes
+ */
+ TXPathContextPtr CreateXPathContext(const TNamespacesForXPath& nss = TNamespacesForXPath()) const {
+ return ActualNode.CreateXPathContext(nss);
+ }
+
+ /**
+ * get all element nodes matching given xpath expression
+ * @param xpath: xpath expression
+ * @param quiet: don't throw exception if zero nodes found
+ * @param ns: explicitly specify XML namespaces to use and their prefixes
+ *
+ * For historical reasons, this only works for *element* nodes.
+ * Use the XPath function if you need other kinds of nodes.
+ */
+ TConstNodes Nodes(TZtStringBuf xpath, bool quiet = false, const TNamespacesForXPath& ns = TNamespacesForXPath()) const {
+ return ActualNode.Nodes(xpath, quiet, ns);
+ }
+
+ /**
+ * get all element nodes matching given xpath expression
+ * @param xpath: xpath expression
+ * @param quiet: don't throw exception if zero nodes found
+ * @param ctxt: reusable xpath context
+ *
+ * For historical reasons, this only works for *element* nodes.
+ * Use the XPath function if you need other kinds of nodes.
+ */
+ TConstNodes Nodes(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt) const {
+ return ActualNode.Nodes(xpath, quiet, ctxt);
+ }
+
+ /**
+ * get all nodes matching given xpath expression
+ * @param xpath: xpath expression
+ * @param quiet: don't throw exception if zero nodes found
+ * @param ns: explicitly specify XML namespaces to use and their prefixes
+ */
+ TConstNodes XPath(TZtStringBuf xpath, bool quiet = false, const TNamespacesForXPath& ns = TNamespacesForXPath()) const {
+ return ActualNode.XPath(xpath, quiet, ns);
+ }
+
+ /**
+ * get all nodes matching given xpath expression
+ * @param xpath: xpath expression
+ * @param quiet: don't throw exception if zero nodes found
+ * @param ctxt: reusable xpath context
+ */
+ TConstNodes XPath(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt) const {
+ return ActualNode.XPath(xpath, quiet, ctxt);
+ }
+
+ /**
+ * get the first element node matching given xpath expression
+ * @param xpath: path to node (from current node)
+ * @param quiet: don't throw exception if node not found,
+ * return null node (@see IsNull())
+ * @param ns: explicitly specify XML namespaces to use and their prefixes
+ *
+ * For historical reasons, this only works for *element* nodes.
+ * Use the XPath function if you need other kinds of nodes.
+ */
+ TConstNode Node(TZtStringBuf xpath, bool quiet = false, const TNamespacesForXPath& ns = TNamespacesForXPath()) const {
+ return ActualNode.Node(xpath, quiet, ns);
+ }
+
+ /**
+ * get the first element node matching given xpath expression
+ * @param xpath: path to node (from current node)
+ * @param quiet: don't throw exception if node not found,
+ * return null node (@see IsNull())
+ * @param ctxt: reusable xpath context
+ *
+ * For historical reasons, this only works for *element* nodes.
+ * Use the XPath function if you need other kinds of nodes.
+ */
+ TConstNode Node(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt) const {
+ return ActualNode.Node(xpath, quiet, ctxt);
+ }
+
+ TConstNode FirstChild(TZtStringBuf name) const {
+ return ActualNode.FirstChild(name);
+ }
+
+ TConstNode FirstChild() const {
+ return ActualNode.FirstChild();
+ }
+
+ /**
+ * get node neighbour
+ * @param name: neighbour name
+ * throws exception if no neighbour found
+ */
+ TConstNode NextSibling(TZtStringBuf name) const {
+ return ActualNode.NextSibling(name);
+ }
+
+ TConstNode NextSibling() const {
+ return ActualNode.NextSibling();
+ }
+
+ /**
+ * get node attribute
+ * @param name: attribute name
+ * throws exception if attribute not found
+ */
+ template <class T>
+ T Attr(TZtStringBuf name) const {
+ return ActualNode.Attr<T>(name);
+ }
+
+ /**
+ * get node attribute
+ * @param name: attribute name
+ * returns default value if attribute not found
+ */
+ template <class T>
+ T Attr(TZtStringBuf name, const T& defvalue) const {
+ return ActualNode.Attr(name, defvalue);
+ }
+
+ /**
+ * get node attribute
+ * @param name: attribute name
+ * @param value: return-value
+ * throws exception if attribute not found
+ */
+ template <class T>
+ void Attr(TZtStringBuf name, T& value) const {
+ return ActualNode.Attr(name, value);
+ }
+
+ /**
+ * get node attribute
+ * @param name: attribute name
+ * @param defvalue: default value
+ * @param value: return-value
+ * returns default value if attribute not found, attr value otherwise
+ */
+ template <class T>
+ void Attr(TZtStringBuf name, T& value, const T& defvalue) const {
+ return ActualNode.Attr(name, value, defvalue);
+ }
+
+ /**
+ * get node value (text)
+ * @throws exception if node is blank
+ */
+ template <class T>
+ T Value() const {
+ return ActualNode.Value<T>();
+ }
+
+ /**
+ * get node value
+ * @param defvalue: default value
+ * returns default value if node is blank
+ */
+ template <class T>
+ T Value(const T& defvalue) const {
+ return ActualNode.Value(defvalue);
+ }
+
+ /**
+ * get node name
+ */
+ TString Name() const {
+ return ActualNode.Name();
+ }
+
+ /**
+ * @return application data pointer, passed by SetPrivate
+ */
+ void* GetPrivate() const {
+ return ActualNode.GetPrivate();
+ }
+
+ /**
+ * get pointer to internal node
+ */
+ const xmlNode* GetPtr() const {
+ return ActualNode.GetPtr();
+ }
+
+ /**
+ * check if node is text-only node
+ */
+ bool IsText() const {
+ return ActualNode.IsText();
+ }
+
+ /**
+ * get node xpath
+ */
+ TString Path() const {
+ return ActualNode.Path();
+ }
+
+ /**
+ * get node xml representation
+ */
+ TString ToString(TZtStringBuf enc = "") const {
+ return ActualNode.ToString(enc);
+ }
+
+ TConstNode() = default;
+ TConstNode(TNode node)
+ : ActualNode(node)
+ {
+ }
+
+ TNode ConstCast() const {
+ return ActualNode;
+ }
+
+ private:
+ TNode ActualNode;
+ };
+
+}
diff --git a/library/cpp/xml/document/xml-document.cpp b/library/cpp/xml/document/xml-document.cpp
new file mode 100644
index 0000000000..18a554d732
--- /dev/null
+++ b/library/cpp/xml/document/xml-document.cpp
@@ -0,0 +1,393 @@
+#include "xml-document.h"
+
+#include <libxml/xinclude.h>
+#include <libxml/xpathInternals.h>
+
+#include <library/cpp/xml/init/init.h>
+
+#include <util/generic/yexception.h>
+#include <util/folder/dirut.h>
+
+namespace {
+ struct TInit {
+ inline TInit() {
+ NXml::InitEngine();
+ }
+ } initer;
+}
+
+namespace NXml {
+ TDocument::TDocument(const TString& xml, Source type) {
+ switch (type) {
+ case File:
+ ParseFile(xml);
+ break;
+ case String:
+ ParseString(xml);
+ break;
+ case RootName: {
+ TDocHolder doc(xmlNewDoc(XMLCHAR("1.0")));
+ if (!doc)
+ THROW(XmlException, "Can't create xml document.");
+ doc->encoding = xmlStrdup(XMLCHAR("utf-8"));
+
+ TNodePtr node(xmlNewNode(nullptr, XMLCHAR(xml.c_str())));
+ if (!node)
+ THROW(XmlException, "Can't create root node.");
+ xmlDocSetRootElement(doc.Get(), node.Get());
+ Y_UNUSED(node.Release());
+ Doc = std::move(doc);
+ } break;
+ default:
+ THROW(InvalidArgument, "Wrong source type");
+ }
+ }
+
+ TDocument::TDocument(TDocument&& doc)
+ : Doc(std::move(doc.Doc))
+ {
+ }
+
+ TDocument& TDocument::operator=(TDocument&& doc) {
+ if (this != &doc)
+ doc.Swap(*this);
+
+ return *this;
+ }
+
+ void TDocument::ParseFile(const TString& file) {
+ if (!NFs::Exists(file))
+ THROW(XmlException, "File " << file << " doesn't exist");
+
+ TParserCtxtPtr pctx(xmlNewParserCtxt());
+ if (!pctx)
+ THROW(XmlException, "Can't create parser context");
+
+ TDocHolder doc(xmlCtxtReadFile(pctx.Get(), file.c_str(), nullptr, XML_PARSE_NOCDATA));
+ if (!doc)
+ THROW(XmlException, "Can't parse file " << file);
+
+ int res = xmlXIncludeProcessFlags(doc.Get(), XML_PARSE_XINCLUDE | XML_PARSE_NOCDATA | XML_PARSE_NOXINCNODE);
+
+ if (res == -1)
+ THROW(XmlException, "XIncludes processing failed");
+
+ Doc = std::move(doc);
+ }
+
+ void TDocument::ParseString(TZtStringBuf xml) {
+ TParserCtxtPtr pctx(xmlNewParserCtxt());
+ if (pctx.Get() == nullptr)
+ THROW(XmlException, "Can't create parser context");
+
+ TDocHolder doc(xmlCtxtReadMemory(pctx.Get(), xml.c_str(), (int)xml.size(), nullptr, nullptr, XML_PARSE_NOCDATA));
+
+ if (!doc)
+ THROW(XmlException, "Can't parse string");
+
+ Doc = std::move(doc);
+ }
+
+ TNode TDocument::Root() {
+ xmlNode* r = xmlDocGetRootElement(Doc.Get());
+ if (r == nullptr)
+ THROW(XmlException, "TDocument hasn't root element");
+
+ return TNode(Doc.Get(), r);
+ }
+
+ TConstNode TDocument::Root() const {
+ xmlNode* r = xmlDocGetRootElement(Doc.Get());
+ if (r == nullptr)
+ THROW(XmlException, "TDocument hasn't root element");
+
+ return TConstNode(TNode(Doc.Get(), r));
+ }
+
+ bool TNode::IsNull() const {
+ return NodePointer == nullptr;
+ }
+
+ bool TNode::IsElementNode() const {
+ return !IsNull() && (NodePointer->type == XML_ELEMENT_NODE);
+ }
+
+ TXPathContextPtr TNode::CreateXPathContext(const TNamespacesForXPath& nss) const {
+ TXPathContextPtr ctx = xmlXPathNewContext(DocPointer);
+ if (!ctx)
+ THROW(XmlException, "Can't create empty xpath context");
+
+ for (const auto& ns : nss) {
+ const int r = xmlXPathRegisterNs(ctx.Get(), XMLCHAR(ns.Prefix.c_str()), XMLCHAR(ns.Url.c_str()));
+ if (r != 0)
+ THROW(XmlException, "Can't register namespace " << ns.Url << " with prefix " << ns.Prefix);
+ }
+
+ return ctx;
+ }
+
+ TConstNodes TNode::XPath(TZtStringBuf xpath, bool quiet, const TNamespacesForXPath& ns) const {
+ TXPathContextPtr ctxt = CreateXPathContext(ns);
+ return XPath(xpath, quiet, *ctxt);
+ }
+
+ TConstNodes TNode::XPath(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt) const {
+ if (xmlXPathSetContextNode(NodePointer, &ctxt) != 0)
+ THROW(XmlException, "Can't set xpath context node, probably the context is associated with another document");
+
+ TXPathObjectPtr obj = xmlXPathEvalExpression(XMLCHAR(xpath.c_str()), &ctxt);
+ if (!obj)
+ THROW(XmlException, "Can't evaluate xpath expression " << xpath);
+
+ TConstNodes nodes(DocPointer, obj);
+
+ if (nodes.Size() == 0 && !quiet)
+ THROW(NodeNotFound, xpath);
+
+ return nodes;
+ }
+
+ TConstNodes TNode::Nodes(TZtStringBuf xpath, bool quiet, const TNamespacesForXPath& ns) const {
+ TXPathContextPtr ctxt = CreateXPathContext(ns);
+ return Nodes(xpath, quiet, *ctxt);
+ }
+
+ TConstNodes TNode::Nodes(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt) const {
+ TConstNodes nodes = XPath(xpath, quiet, ctxt);
+ if (nodes.Size() != 0 && !nodes[0].IsElementNode())
+ THROW(XmlException, "xpath points to non-element nodes: " << xpath);
+ return nodes;
+ }
+
+ TNode TNode::Node(TZtStringBuf xpath, bool quiet, const TNamespacesForXPath& ns) {
+ TXPathContextPtr ctxt = CreateXPathContext(ns);
+ return Node(xpath, quiet, *ctxt);
+ }
+
+ TConstNode TNode::Node(TZtStringBuf xpath, bool quiet, const TNamespacesForXPath& ns) const {
+ TXPathContextPtr ctxt = CreateXPathContext(ns);
+ return Node(xpath, quiet, *ctxt);
+ }
+
+ TNode TNode::Node(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt) {
+ TConstNodes n = Nodes(xpath, quiet, ctxt);
+
+ if (n.Size() == 0 && !quiet)
+ THROW(NodeNotFound, xpath);
+
+ if (n.Size() == 0)
+ return TNode();
+ else
+ return n[0].ConstCast();
+ }
+
+ TConstNode TNode::Node(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt) const {
+ return const_cast<TNode*>(this)->Node(xpath, quiet, ctxt);
+ }
+
+ TNode TNode::FirstChild(TZtStringBuf name) {
+ if (IsNull())
+ THROW(XmlException, "Node is null");
+
+ return Find(NodePointer->children, name);
+ }
+
+ TConstNode TNode::FirstChild(TZtStringBuf name) const {
+ return const_cast<TNode*>(this)->FirstChild(name);
+ }
+
+ TNode TNode::FirstChild() {
+ if (IsNull())
+ THROW(XmlException, "Node is null");
+
+ return TNode(DocPointer, NodePointer->children);
+ }
+
+ TConstNode TNode::FirstChild() const {
+ return const_cast<TNode*>(this)->FirstChild();
+ }
+
+ TNode TNode::Parent() {
+ if (nullptr == NodePointer->parent)
+ THROW(XmlException, "Parent node not exists");
+
+ return TNode(DocPointer, NodePointer->parent);
+ }
+
+ TConstNode TNode::Parent() const {
+ return const_cast<TNode*>(this)->Parent();
+ }
+
+ TNode TNode::NextSibling(TZtStringBuf name) {
+ if (IsNull())
+ THROW(XmlException, "Node is null");
+
+ return Find(NodePointer->next, name);
+ }
+
+ TConstNode TNode::NextSibling(TZtStringBuf name) const {
+ return const_cast<TNode*>(this)->NextSibling(name);
+ }
+
+ TNode TNode::NextSibling() {
+ if (IsNull())
+ THROW(XmlException, "Node is null");
+
+ return TNode(DocPointer, NodePointer->next);
+ }
+
+ TConstNode TNode::NextSibling() const {
+ return const_cast<TNode*>(this)->NextSibling();
+ }
+
+ /* NOTE: by default child will inherit it's parent ns */
+
+ TNode TNode::AddChild(TZtStringBuf name) {
+ return AddChild(name, "");
+ }
+
+ /* NOTE: source node will be copied, as otherwise it will be double-freed from this and its own document */
+
+ TNode TNode::AddChild(const TConstNode& node) {
+ xmlNodePtr copy = xmlDocCopyNode(node.ConstCast().NodePointer, DocPointer, 1 /* recursive */);
+ copy = xmlAddChild(NodePointer, copy);
+ return TNode(DocPointer, copy);
+ }
+
+ void TNode::SetPrivate(void* priv) {
+ NodePointer->_private = priv;
+ }
+
+ void* TNode::GetPrivate() const {
+ return NodePointer->_private;
+ }
+
+ TNode TNode::Find(xmlNode* start, TZtStringBuf name) {
+ for (; start; start = start->next)
+ if (start->type == XML_ELEMENT_NODE && (name.empty() || !xmlStrcmp(start->name, XMLCHAR(name.c_str()))))
+ return TNode(DocPointer, start);
+
+ return TNode();
+ }
+
+ TString TNode::Name() const {
+ if (IsNull())
+ THROW(XmlException, "Node is null");
+
+ return CAST2CHAR(NodePointer->name);
+ }
+
+ TString TNode::Path() const {
+ TCharPtr path(xmlGetNodePath(NodePointer));
+ if (!!path)
+ return CAST2CHAR(path.Get());
+ else
+ return "";
+ }
+
+ xmlNode* TNode::GetPtr() {
+ return NodePointer;
+ }
+
+ const xmlNode* TNode::GetPtr() const {
+ return NodePointer;
+ }
+
+ bool TNode::IsText() const {
+ if (IsNull())
+ THROW(XmlException, "Node is null");
+
+ return NodePointer->type == XML_TEXT_NODE;
+ }
+
+ void TNode::Remove() {
+ xmlNode* nodePtr = GetPtr();
+ xmlUnlinkNode(nodePtr);
+ xmlFreeNode(nodePtr);
+ }
+
+ static int XmlWriteToOstream(void* context, const char* buffer, int len) {
+ // possibly use to save doc as well
+ IOutputStream* out = (IOutputStream*)context;
+ out->Write(buffer, len);
+ return len;
+ }
+
+ void TNode::SaveInternal(IOutputStream& stream, TZtStringBuf enc, int options) const {
+ const char* encoding = enc.size() ? enc.data() : "utf-8";
+ TSaveCtxtPtr ctx(xmlSaveToIO(XmlWriteToOstream, /* close */ nullptr, &stream,
+ encoding, options));
+ if (xmlSaveTree(ctx.Get(), (xmlNode*)GetPtr()) < 0)
+ THROW(XmlException, "Failed saving node to stream");
+ }
+
+ void TNode::Save(IOutputStream& stream, TZtStringBuf enc, bool shouldFormat) const {
+ SaveInternal(stream, enc, shouldFormat ? XML_SAVE_FORMAT : 0);
+ }
+
+ void TNode::SaveAsHtml(IOutputStream& stream, TZtStringBuf enc, bool shouldFormat) const {
+ int options = XML_SAVE_AS_HTML;
+ options |= shouldFormat ? XML_SAVE_FORMAT : 0;
+ SaveInternal(stream, enc, options);
+ }
+
+ TConstNodes::TConstNodes(const TConstNodes& nodes)
+ : SizeValue(nodes.Size())
+ , Doc(nodes.Doc)
+ , Obj(nodes.Obj)
+ {
+ }
+
+ TConstNodes& TConstNodes::operator=(const TConstNodes& nodes) {
+ if (this != &nodes) {
+ SizeValue = nodes.Size();
+ Doc = nodes.Doc;
+ Obj = nodes.Obj;
+ }
+
+ return *this;
+ }
+
+ TConstNodes::TConstNodes(TConstNodesRef ref)
+ : SizeValue(ref.r_.Size())
+ , Doc(ref.r_.Doc)
+ , Obj(ref.r_.Obj)
+ {
+ }
+
+ TConstNodes& TConstNodes::operator=(TConstNodesRef ref) {
+ if (this != &ref.r_) {
+ SizeValue = ref.r_.Size();
+ Doc = ref.r_.Doc;
+ Obj = ref.r_.Obj;
+ }
+ return *this;
+ }
+
+ TConstNodes::operator TConstNodesRef() {
+ return TConstNodesRef(*this);
+ }
+
+ TConstNodes::TConstNodes(xmlDoc* doc, TXPathObjectPtr obj)
+ : SizeValue(obj && obj->nodesetval ? obj->nodesetval->nodeNr : 0)
+ , Doc(doc)
+ , Obj(obj)
+ {
+ }
+
+ TConstNode TConstNodes::operator[](size_t number) const {
+ if (number + 1 > Size())
+ THROW(XmlException, "index out of range " << number);
+
+ if (!Obj || !Obj->nodesetval)
+ THROW(XmlException, "Broken TConstNodes object, Obj is null");
+
+ xmlNode* node = Obj->nodesetval->nodeTab[number];
+ return TNode(Doc, node);
+ }
+
+ TConstNode TConstNodes::TNodeIter::operator*() const {
+ return Nodes[Index];
+ }
+
+}
diff --git a/library/cpp/xml/document/xml-document.h b/library/cpp/xml/document/xml-document.h
new file mode 100644
index 0000000000..829ba09cc4
--- /dev/null
+++ b/library/cpp/xml/document/xml-document.h
@@ -0,0 +1,4 @@
+#pragma once
+
+#include "xml-document-decl.h"
+#include "node-attr.h"
diff --git a/library/cpp/xml/document/xml-document_ut.cpp b/library/cpp/xml/document/xml-document_ut.cpp
new file mode 100644
index 0000000000..9f537b75c4
--- /dev/null
+++ b/library/cpp/xml/document/xml-document_ut.cpp
@@ -0,0 +1,319 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <util/generic/map.h>
+
+#include "xml-document.h"
+
+Y_UNIT_TEST_SUITE(TestXmlDocument) {
+ Y_UNIT_TEST(Iteration) {
+ NXml::TDocument xml(
+ "<?xml version=\"1.0\"?>\n"
+ "<root>qq<a><b></b></a>ww<c></c></root>",
+ NXml::TDocument::String);
+
+ NXml::TConstNode root = xml.Root();
+ UNIT_ASSERT_EQUAL(root.Name(), "root");
+ NXml::TConstNode n = root.FirstChild().NextSibling();
+ UNIT_ASSERT_EQUAL(n.Name(), "a");
+ n = n.NextSibling().NextSibling();
+ UNIT_ASSERT_EQUAL(n.Name(), "c");
+ }
+
+ Y_UNIT_TEST(ParseString) {
+ NXml::TDocument xml(
+ "<?xml version=\"1.0\"?>\n"
+ "<root>\n"
+ "<a><b len=\"15\" correct=\"1\">hello world</b></a>\n"
+ "<text>Некоторый текст</text>\n"
+ "</root>",
+ NXml::TDocument::String);
+
+ NXml::TConstNode root = xml.Root();
+ NXml::TConstNode b = root.Node("a/b");
+ UNIT_ASSERT_EQUAL(b.Attr<int>("len"), 15);
+ UNIT_ASSERT_EQUAL(b.Attr<bool>("correct"), true);
+
+ NXml::TConstNode text = root.Node("text");
+ UNIT_ASSERT_EQUAL(text.Value<TString>(), "Некоторый текст");
+ }
+ Y_UNIT_TEST(SerializeString) {
+ NXml::TDocument xml("frob", NXml::TDocument::RootName);
+ xml.Root().SetAttr("xyzzy", "Frobozz");
+ xml.Root().SetAttr("kulness", 0.3);
+ xml.Root().SetAttr("timelimit", 3);
+
+ NXml::TNode authors = xml.Root().AddChild("authors");
+ authors.AddChild("graham").SetAttr("name", "Nelson");
+ authors.AddChild("zarf").SetValue("Andrew Plotkin");
+ authors.AddChild("emshort", "Emily Short");
+
+ TString data = xml.ToString("utf-8");
+ UNIT_ASSERT_EQUAL(data, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<frob xyzzy=\"Frobozz\" kulness=\"0.3\" timelimit=\"3\">\n"
+ " <authors>\n"
+ " <graham name=\"Nelson\"/>\n"
+ " <zarf>Andrew Plotkin</zarf>\n"
+ " <emshort>Emily Short</emshort>\n"
+ " </authors>\n"
+ "</frob>\n");
+ // check default utf8 output with ru
+ {
+ NXml::TDocument xml2("frob", NXml::TDocument::RootName);
+ xml2.Root().SetAttr("xyzzy", "привет =)");
+ UNIT_ASSERT_VALUES_EQUAL(xml2.ToString(), "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<frob xyzzy=\"привет =)\"/>\n");
+ }
+ }
+ Y_UNIT_TEST(XPathNs) {
+ using namespace NXml;
+ TDocument xml(
+ "<?xml version=\"1.0\"?>\n"
+ "<root xmlns='http://hello.com/hello'>\n"
+ "<a><b len=\"15\" correct=\"1\">hello world</b></a>\n"
+ "<text>Некоторый текст</text>\n"
+ "</root>",
+ TDocument::String);
+
+ TNamespacesForXPath nss;
+ TNamespaceForXPath ns = {"h", "http://hello.com/hello"};
+ nss.push_back(ns);
+
+ TConstNode root = xml.Root();
+ TConstNode b = root.Node("h:a/h:b", false, nss);
+ UNIT_ASSERT_EQUAL(b.Attr<int>("len"), 15);
+ UNIT_ASSERT_EQUAL(b.Attr<bool>("correct"), true);
+
+ TConstNode text = root.Node("h:text", false, nss);
+ UNIT_ASSERT_EQUAL(text.Value<TString>(), "Некоторый текст");
+
+ // For performance you can create xpath context once using nss and pass it.
+ TXPathContextPtr ctxt = root.CreateXPathContext(nss);
+ UNIT_ASSERT(root.Node("text", true, *ctxt).IsNull());
+ UNIT_ASSERT_EXCEPTION(root.Node("text", false, *ctxt), yexception);
+ UNIT_ASSERT_EQUAL(root.Node("h:text", false, *ctxt).Value<TString>(), "Некоторый текст");
+ }
+ Y_UNIT_TEST(XmlNodes) {
+ using namespace NXml;
+ TDocument xml("<?xml version=\"1.0\"?>\n"
+ "<root>qq<a><b>asdfg</b></a>ww<c></c></root>",
+ NXml::TDocument::String);
+ TNode root = xml.Root();
+ UNIT_ASSERT_EQUAL(root.Value<TString>(), "qqasdfgww");
+ TConstNode node = root.FirstChild();
+ UNIT_ASSERT_EQUAL(node.IsText(), true);
+ UNIT_ASSERT_EQUAL(node.Value<TString>(), "qq");
+ node = node.NextSibling();
+ UNIT_ASSERT_EQUAL(node.IsText(), false);
+ UNIT_ASSERT_EQUAL(node.Name(), "a");
+ UNIT_ASSERT_EQUAL(node.Value<TString>(), "asdfg");
+ node = node.NextSibling();
+ UNIT_ASSERT_EQUAL(node.IsText(), true);
+ UNIT_ASSERT_EQUAL(node.Value<TString>(), "ww");
+ node = node.NextSibling();
+ UNIT_ASSERT_EQUAL(node.IsText(), false);
+ UNIT_ASSERT_EQUAL(node.Name(), "c");
+ UNIT_ASSERT_EQUAL(node.Value<TString>(), "");
+ node = node.NextSibling();
+ UNIT_ASSERT_EQUAL(node.IsNull(), true);
+ TStringStream iterLog;
+ for (const auto& node2 : root.Nodes("/root/*")) {
+ iterLog << node2.Name() << ';';
+ }
+ UNIT_ASSERT_STRINGS_EQUAL(iterLog.Str(), "a;c;");
+
+ // get only element nodes, ignore text nodes with empty "name" param
+ node = root.FirstChild(TString());
+ UNIT_ASSERT_EQUAL(node.IsText(), false);
+ UNIT_ASSERT_EQUAL(node.Name(), "a");
+ node = node.NextSibling(TString());
+ UNIT_ASSERT_EQUAL(node.IsText(), false);
+ UNIT_ASSERT_EQUAL(node.Name(), "c");
+
+ // use exact "name" to retrieve children and siblings
+ node = root.FirstChild("a");
+ UNIT_ASSERT_EQUAL(node.IsNull(), false);
+ UNIT_ASSERT_EQUAL(node.Name(), "a");
+ node = node.NextSibling("c");
+ UNIT_ASSERT_EQUAL(node.IsNull(), false);
+ UNIT_ASSERT_EQUAL(node.Name(), "c");
+ node = root.FirstChild("c"); // skip "a"
+ UNIT_ASSERT_EQUAL(node.IsNull(), false);
+ UNIT_ASSERT_EQUAL(node.Name(), "c");
+
+ // node not found: no exceptions, null nodes are returned
+ node = root.FirstChild("b"); // b is not direct child of root
+ UNIT_ASSERT_EQUAL(node.IsNull(), true);
+ node = root.FirstChild("nosuchnode");
+ UNIT_ASSERT_EQUAL(node.IsNull(), true);
+ node = root.FirstChild();
+ node = root.NextSibling("unknownnode");
+ UNIT_ASSERT_EQUAL(node.IsNull(), true);
+ UNIT_ASSERT_EXCEPTION(node.Name(), yexception);
+ UNIT_ASSERT_EXCEPTION(node.Value<TString>(), yexception);
+ UNIT_ASSERT_EXCEPTION(node.IsText(), yexception);
+ }
+ Y_UNIT_TEST(DefVal) {
+ using namespace NXml;
+ TDocument xml("<?xml version=\"1.0\"?>\n"
+ "<root><a></a></root>",
+ NXml::TDocument::String);
+ UNIT_ASSERT_EQUAL(xml.Root().Node("a", true).Node("b", true).Value<int>(3), 3);
+ }
+ Y_UNIT_TEST(NodesVsXPath) {
+ using namespace NXml;
+ TDocument xml("<?xml version=\"1.0\"?>\n"
+ "<root><a x=\"y\"></a></root>",
+ NXml::TDocument::String);
+ UNIT_ASSERT_EXCEPTION(xml.Root().Nodes("/root/a/@x"), yexception);
+ UNIT_ASSERT_VALUES_EQUAL(xml.Root().XPath("/root/a/@x").Size(), 1);
+ }
+ Y_UNIT_TEST(NodeIsFirst) {
+ using namespace NXml;
+ TDocument xml("<?xml version=\"1.0\"?>\n"
+ "<root><a x=\"y\">first</a>"
+ "<a>second</a></root>",
+ NXml::TDocument::String);
+ UNIT_ASSERT_EXCEPTION(xml.Root().Node("/root/a/@x"), yexception);
+ UNIT_ASSERT_STRINGS_EQUAL(xml.Root().Node("/root/a").Value<TString>(), "first");
+ }
+ Y_UNIT_TEST(CopyNode) {
+ using namespace NXml;
+ // default-construct empty node
+ TNode empty;
+ // put to container
+ TMap<int, TNode> nmap;
+ nmap[2];
+
+ // do copy
+ TDocument xml("<?xml version=\"1.0\"?>\n"
+ "<root><a></a></root>",
+ TDocument::String);
+
+ TDocument xml2("<?xml version=\"1.0\"?>\n"
+ "<root><node><b>bold</b><i>ita</i></node></root>",
+ TDocument::String);
+
+ TNode node = xml2.Root().Node("//node");
+ TNode place = xml.Root().Node("//a");
+
+ place.AddChild(node);
+
+ TStringStream s;
+ xml.Save(s, "", false);
+ UNIT_ASSERT_VALUES_EQUAL(s.Str(),
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<root><a><node><b>bold</b><i>ita</i></node></a></root>\n");
+ }
+
+ Y_UNIT_TEST(RenderNode) {
+ using namespace NXml;
+ {
+ // no namespaces
+ TDocument xml(
+ "<?xml version=\"1.0\"?>\n"
+ "<root>\n"
+ "<a><b len=\"15\" correct=\"1\">hello world</b></a>\n"
+ "<text>Некоторый текст</text>\n"
+ "</root>",
+ TDocument::String);
+ TNode n = xml.Root().Node("//a");
+ UNIT_ASSERT_VALUES_EQUAL(n.ToString(), "<a><b len=\"15\" correct=\"1\">hello world</b></a>");
+ }
+ {
+ // namespaces
+ TDocument xml(
+ "<?xml version=\"1.0\"?>\n"
+ "<root xmlns='http://hello.com/hello'>\n"
+ "<a><b len=\"15\" correct=\"1\">hello world</b></a>\n"
+ "<text>Некоторый текст</text>\n"
+ "</root>",
+ TDocument::String);
+ TNamespacesForXPath nss;
+ TNamespaceForXPath ns = {"h", "http://hello.com/hello"};
+ nss.push_back(ns);
+
+ TNode n = xml.Root().Node("//h:a", false, nss);
+ UNIT_ASSERT_VALUES_EQUAL(n.ToString(), "<a><b len=\"15\" correct=\"1\">hello world</b></a>");
+ }
+ }
+
+ Y_UNIT_TEST(ReuseXPathContext) {
+ using namespace NXml;
+
+ TDocument xml(
+ "<?xml version=\"1.0\"?>\n"
+ "<root>\n"
+ "<a><b><c>Hello, world!</c></b></a>\n"
+ "<text x=\"10\">First</text>\n"
+ "<text y=\"20\">Second</text>\n"
+ "</root>",
+ TDocument::String);
+
+ TXPathContextPtr rootCtxt = xml.Root().CreateXPathContext();
+
+ // Check Node()
+ TConstNode b = xml.Root().Node("a/b", false, *rootCtxt);
+
+ // We can use root node context for xpath evaluation in any node
+ TConstNode c1 = b.Node("c", false, *rootCtxt);
+ UNIT_ASSERT_EQUAL(c1.Value<TString>(), "Hello, world!");
+
+ TXPathContextPtr bCtxt = b.CreateXPathContext();
+ TConstNode c2 = b.Node("c", false, *bCtxt);
+ UNIT_ASSERT_EQUAL(c2.Value<TString>(), "Hello, world!");
+
+ // Mixing contexts from different documents is forbidden
+ TDocument otherXml("<root></root>", TDocument::String);
+ TXPathContextPtr otherCtxt = otherXml.Root().CreateXPathContext();
+ UNIT_ASSERT_EXCEPTION(b.Node("c", false, *otherCtxt), yexception);
+
+ // Check Nodes()
+ TConstNodes texts = xml.Root().Nodes("text", true, *rootCtxt);
+ UNIT_ASSERT_EQUAL(texts.Size(), 2);
+
+ // Nodes() does't work for non-element nodes
+ UNIT_ASSERT_EXCEPTION(xml.Root().Nodes("text/@x", true, *rootCtxt), yexception);
+
+ // Check XPath()
+ TConstNodes ys = xml.Root().XPath("text/@y", true, *rootCtxt);
+ UNIT_ASSERT_EQUAL(ys.Size(), 1);
+ UNIT_ASSERT_EQUAL(ys[0].Value<int>(), 20);
+ }
+
+ Y_UNIT_TEST(Html) {
+ using namespace NXml;
+
+ TDocument htmlChunk("video", TDocument::RootName);
+ TNode videoNode = htmlChunk.Root();
+
+ videoNode.SetAttr("controls");
+
+ TStringStream ss;
+ videoNode.SaveAsHtml(ss);
+ UNIT_ASSERT_EQUAL(ss.Str(), "<video controls></video>");
+ }
+
+ Y_UNIT_TEST(Move) {
+ using namespace NXml;
+
+ TDocument xml1("foo", TDocument::RootName);
+ xml1.Root().AddChild("bar");
+
+ UNIT_ASSERT_VALUES_EQUAL(xml1.Root().ToString(), "<foo><bar/></foo>");
+
+ TDocument xml2 = std::move(xml1);
+ UNIT_ASSERT_EXCEPTION(xml1.Root(), yexception);
+ UNIT_ASSERT_VALUES_EQUAL(xml2.Root().ToString(), "<foo><bar/></foo>");
+ }
+
+ Y_UNIT_TEST(StringConversion) {
+ using namespace NXml;
+ TDocument xml("foo", TDocument::RootName);
+ auto root = xml.Root();
+ const TStringBuf stringBuf = "bar";
+ root.SetAttr("bar", stringBuf);
+ const TString tString = "baz";
+ root.SetAttr("baz", tString);
+ root.SetAttr("quux", "literal");
+ root.SetAttr("frob", 500);
+ }
+}
diff --git a/library/cpp/xml/document/xml-options.cpp b/library/cpp/xml/document/xml-options.cpp
new file mode 100644
index 0000000000..74e7545de3
--- /dev/null
+++ b/library/cpp/xml/document/xml-options.cpp
@@ -0,0 +1 @@
+#include "xml-options.h"
diff --git a/library/cpp/xml/document/xml-options.h b/library/cpp/xml/document/xml-options.h
new file mode 100644
index 0000000000..bb07da0cfb
--- /dev/null
+++ b/library/cpp/xml/document/xml-options.h
@@ -0,0 +1,67 @@
+#pragma once
+
+#include <contrib/libs/libxml/include/libxml/parser.h>
+
+namespace NXml {
+ enum class EOption : int {
+ // clang-format off
+ Recover = XML_PARSE_RECOVER,
+ NoEnt = XML_PARSE_NOENT,
+ DTDLoad = XML_PARSE_DTDLOAD,
+ DTDAttr = XML_PARSE_DTDATTR,
+ DTDValid = XML_PARSE_DTDVALID,
+ NoError = XML_PARSE_NOERROR,
+ NoWarning = XML_PARSE_NOWARNING,
+ Pedantic = XML_PARSE_PEDANTIC,
+ NoBlanks = XML_PARSE_NOBLANKS,
+ SAX1 = XML_PARSE_SAX1,
+ XInclude = XML_PARSE_XINCLUDE,
+ NoNet = XML_PARSE_NONET,
+ NoDict = XML_PARSE_NODICT,
+ NSClean = XML_PARSE_NSCLEAN,
+ NoCData = XML_PARSE_NOCDATA,
+ NoXInclude = XML_PARSE_NOXINCNODE,
+ Compact = XML_PARSE_COMPACT,
+ Old10 = XML_PARSE_OLD10,
+ NoBaseFix = XML_PARSE_NOBASEFIX,
+ Huge = XML_PARSE_HUGE,
+ OldSAX = XML_PARSE_OLDSAX,
+ IgnoreEnc = XML_PARSE_IGNORE_ENC,
+ BigLines = XML_PARSE_BIG_LINES,
+ // clang-format on
+ };
+
+ class TOptions {
+ public:
+ TOptions()
+ : Mask(0)
+ {
+ }
+
+ template <typename... TArgs>
+ TOptions(TArgs... args)
+ : Mask(0)
+ {
+ Set(args...);
+ }
+
+ TOptions& Set(EOption option) {
+ Mask |= static_cast<int>(option);
+ return *this;
+ }
+
+ template <typename... TArgs>
+ TOptions& Set(EOption arg, TArgs... args) {
+ Set(arg);
+ return Set(args...);
+ }
+
+ int GetMask() const {
+ return Mask;
+ }
+
+ private:
+ int Mask;
+ };
+
+}
diff --git a/library/cpp/xml/document/xml-options_ut.cpp b/library/cpp/xml/document/xml-options_ut.cpp
new file mode 100644
index 0000000000..9be16baf3d
--- /dev/null
+++ b/library/cpp/xml/document/xml-options_ut.cpp
@@ -0,0 +1,26 @@
+#include "xml-options.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+Y_UNIT_TEST_SUITE(TestXmlOptions) {
+ Y_UNIT_TEST(SetHuge) {
+ NXml::TOptions opts;
+ opts.Set(NXml::EOption::Huge);
+ UNIT_ASSERT_EQUAL(XML_PARSE_HUGE, opts.GetMask());
+ }
+
+ Y_UNIT_TEST(VariadicContructor) {
+ NXml::TOptions opts(NXml::EOption::Huge, NXml::EOption::Compact, NXml::EOption::SAX1);
+ UNIT_ASSERT_EQUAL(XML_PARSE_HUGE | XML_PARSE_COMPACT | XML_PARSE_SAX1, opts.GetMask());
+ }
+
+ Y_UNIT_TEST(Chaining) {
+ NXml::TOptions opts;
+
+ opts
+ .Set(NXml::EOption::Huge)
+ .Set(NXml::EOption::Compact);
+
+ UNIT_ASSERT_EQUAL(XML_PARSE_HUGE | XML_PARSE_COMPACT, opts.GetMask());
+ }
+}
diff --git a/library/cpp/xml/document/xml-textreader.cpp b/library/cpp/xml/document/xml-textreader.cpp
new file mode 100644
index 0000000000..b946f1fbf2
--- /dev/null
+++ b/library/cpp/xml/document/xml-textreader.cpp
@@ -0,0 +1,318 @@
+#include "xml-textreader.h"
+
+#include <contrib/libs/libxml/include/libxml/xmlreader.h>
+
+#include <util/generic/yexception.h>
+#include <util/string/strip.h>
+#include <util/system/compiler.h>
+
+namespace NXml {
+ TTextReader::TTextReader(IInputStream& stream, const TOptions& options)
+ : Stream(stream)
+ , IsError(false)
+ {
+ Impl.Reset(xmlReaderForIO(ReadFromInputStreamCallback, nullptr, this, nullptr, nullptr, options.GetMask()));
+
+ if (!Impl) {
+ ythrow yexception() << "cannot instantiate underlying xmlTextReader structure";
+ }
+ SetupErrorHandler();
+ CheckForExceptions();
+ }
+
+ TTextReader::~TTextReader() {
+ }
+
+ bool TTextReader::Read() {
+ return BoolResult(xmlTextReaderRead(Impl.Get()));
+ }
+
+ TString TTextReader::ReadInnerXml() const {
+ return TempStringOrEmptyResult(xmlTextReaderReadInnerXml(Impl.Get()));
+ }
+
+ TString TTextReader::ReadOuterXml() const {
+ return TempStringOrEmptyResult(xmlTextReaderReadOuterXml(Impl.Get()));
+ }
+
+ TString TTextReader::ReadString() const {
+ return TempStringOrEmptyResult(xmlTextReaderReadString(Impl.Get()));
+ }
+
+ bool TTextReader::ReadAttributeValue() const {
+ return BoolResult(xmlTextReaderReadAttributeValue(Impl.Get()));
+ }
+
+ int TTextReader::GetAttributeCount() const {
+ return IntResult(xmlTextReaderAttributeCount(Impl.Get()));
+ }
+
+ TStringBuf TTextReader::GetBaseUri() const {
+ return ConstStringOrEmptyResult(xmlTextReaderConstBaseUri(Impl.Get()));
+ }
+
+ int TTextReader::GetDepth() const {
+ return IntResult(xmlTextReaderDepth(Impl.Get()));
+ }
+
+ bool TTextReader::HasAttributes() const {
+ return BoolResult(xmlTextReaderHasAttributes(Impl.Get()));
+ }
+
+ bool TTextReader::HasValue() const {
+ return BoolResult(xmlTextReaderHasValue(Impl.Get()));
+ }
+
+ bool TTextReader::IsDefault() const {
+ return BoolResult(xmlTextReaderIsDefault(Impl.Get()));
+ }
+
+ bool TTextReader::IsEmptyElement() const {
+ return BoolResult(xmlTextReaderIsEmptyElement(Impl.Get()));
+ }
+
+ TStringBuf TTextReader::GetLocalName() const {
+ return ConstStringOrEmptyResult(xmlTextReaderConstLocalName(Impl.Get()));
+ }
+
+ TStringBuf TTextReader::GetName() const {
+ return ConstStringOrEmptyResult(xmlTextReaderConstName(Impl.Get()));
+ }
+
+ TStringBuf TTextReader::GetNamespaceUri() const {
+ return ConstStringOrEmptyResult(xmlTextReaderConstNamespaceUri(Impl.Get()));
+ }
+
+ TTextReader::ENodeType TTextReader::GetNodeType() const {
+ return static_cast<ENodeType>(IntResult(xmlTextReaderNodeType(Impl.Get())));
+ }
+
+ TStringBuf TTextReader::GetPrefix() const {
+ return ConstStringOrEmptyResult(xmlTextReaderConstPrefix(Impl.Get()));
+ }
+
+ char TTextReader::GetQuoteChar() const {
+ return CharResult(xmlTextReaderQuoteChar(Impl.Get()));
+ }
+
+ TStringBuf TTextReader::GetValue() const {
+ return ConstStringOrEmptyResult(xmlTextReaderConstValue(Impl.Get()));
+ }
+
+ TTextReader::EReadState TTextReader::GetReadState() const {
+ return static_cast<EReadState>(IntResult(xmlTextReaderReadState(Impl.Get())));
+ }
+
+ void TTextReader::Close() {
+ if (xmlTextReaderClose(Impl.Get()) == -1) {
+ ThrowException();
+ }
+ }
+
+ TString TTextReader::GetAttribute(int number) const {
+ return TempStringResult(xmlTextReaderGetAttributeNo(Impl.Get(), number));
+ }
+
+ TString TTextReader::GetAttribute(TZtStringBuf name) const {
+ return TempStringResult(xmlTextReaderGetAttribute(Impl.Get(), XMLCHAR(name.data())));
+ }
+
+ TString TTextReader::GetAttribute(TZtStringBuf localName, TZtStringBuf nsUri) const {
+ return TempStringResult(xmlTextReaderGetAttributeNs(Impl.Get(), XMLCHAR(localName.data()), XMLCHAR(nsUri.data())));
+ }
+
+ TString TTextReader::LookupNamespace(TZtStringBuf prefix) const {
+ return TempStringResult(xmlTextReaderLookupNamespace(Impl.Get(), XMLCHAR(prefix.data())));
+ }
+
+ bool TTextReader::MoveToAttribute(int number) {
+ return BoolResult(xmlTextReaderMoveToAttributeNo(Impl.Get(), number));
+ }
+
+ bool TTextReader::MoveToAttribute(TZtStringBuf name) {
+ return BoolResult(xmlTextReaderMoveToAttribute(Impl.Get(), XMLCHAR(name.data())));
+ }
+
+ bool TTextReader::MoveToAttribute(TZtStringBuf localName, TZtStringBuf nsUri) {
+ return BoolResult(xmlTextReaderMoveToAttributeNs(Impl.Get(), XMLCHAR(localName.data()), XMLCHAR(nsUri.data())));
+ }
+
+ bool TTextReader::MoveToFirstAttribute() {
+ return BoolResult(xmlTextReaderMoveToFirstAttribute(Impl.Get()));
+ }
+
+ bool TTextReader::MoveToNextAttribute() {
+ return BoolResult(xmlTextReaderMoveToNextAttribute(Impl.Get()));
+ }
+
+ bool TTextReader::MoveToElement() {
+ return BoolResult(xmlTextReaderMoveToElement(Impl.Get()));
+ }
+
+ TConstNode TTextReader::Expand() const {
+ const xmlNodePtr node = xmlTextReaderExpand(Impl.Get());
+ if (node == nullptr) {
+ ThrowException();
+ }
+ return TConstNode(TNode(node->doc, node));
+ }
+
+ bool TTextReader::Next() {
+ return BoolResult(xmlTextReaderNext(Impl.Get()));
+ }
+
+ bool TTextReader::IsValid() const {
+ return BoolResult(xmlTextReaderIsValid(Impl.Get()));
+ }
+
+ // Callback for xmlReaderForIO() to read more data.
+ // It is almost "noexcept" (std::bad_alloc may happen when saving exception message to new TString).
+ // Waiting for std::exception_ptr and std::rethrow_exception from C++11 in Arcadia to make it really "noexcept".
+ int TTextReader::ReadFromInputStreamCallback(void* context, char* buffer, int len) {
+ Y_ASSERT(len >= 0);
+ TTextReader* reader = static_cast<TTextReader*>(context);
+
+ int result = -1;
+
+ // Exception may be thrown by IInputStream::Read().
+ // It is caught unconditionally because exceptions cannot safely pass through libxml2 plain C code
+ // (no destructors, no RAII, raw pointers, so in case of stack unwinding some memory gets leaked).
+
+ try {
+ result = reader->Stream.Read(buffer, len);
+ } catch (const yexception& ex) {
+ reader->LogError() << "read from input stream failed: " << ex;
+ } catch (...) {
+ reader->LogError() << "read from input stream failed";
+ }
+
+ return result;
+ }
+
+ void TTextReader::OnLibxmlError(void* arg, const char* msg, xmlParserSeverities severity, xmlTextReaderLocatorPtr locator) {
+ TTextReader* reader = static_cast<TTextReader*>(arg);
+ Y_ASSERT(reader != nullptr);
+
+ TStringStream& out = reader->LogError();
+
+ if (severity == XML_PARSER_SEVERITY_ERROR) {
+ out << "libxml parse error";
+ } else if (severity == XML_PARSER_SEVERITY_VALIDITY_ERROR) {
+ out << "libxml validity error";
+ } else {
+ out << "libxml error";
+ }
+
+ if (locator != nullptr) {
+ const int line = xmlTextReaderLocatorLineNumber(locator);
+ const TCharPtr baseUri = xmlTextReaderLocatorBaseURI(locator);
+ out << " (";
+ if (line != -1) {
+ out << "at line " << line;
+ if (baseUri) {
+ out << ", ";
+ }
+ }
+ if (baseUri) {
+ out << "base URI " << CAST2CHAR(baseUri.Get());
+ }
+ out << ")";
+ }
+
+ TStringBuf message = (msg != nullptr) ? msg : "unknown";
+ message = StripStringRight(message); // remove trailing \n that is added by libxml
+ if (!message.empty()) {
+ out << ": " << message;
+ }
+ }
+
+ void TTextReader::SetupErrorHandler() {
+ xmlTextReaderErrorFunc func = nullptr;
+ void* arg = nullptr;
+
+ // We respect any other error handlers already set up:
+ xmlTextReaderGetErrorHandler(Impl.Get(), &func, &arg);
+ if (!func) {
+ func = TTextReader::OnLibxmlError;
+ xmlTextReaderSetErrorHandler(Impl.Get(), func, this);
+ }
+ }
+
+ TStringStream& TTextReader::LogError() const {
+ if (IsError) { // maybe there are previous errors
+ ErrorBuffer << Endl;
+ }
+ IsError = true;
+ return ErrorBuffer;
+ }
+
+ void TTextReader::CheckForExceptions() const {
+ if (Y_LIKELY(!IsError)) {
+ return;
+ }
+
+ const TString message = ErrorBuffer.Str();
+ ErrorBuffer.clear();
+ IsError = false;
+
+ ythrow yexception() << message;
+ }
+
+ void TTextReader::ThrowException() const {
+ CheckForExceptions();
+ // Probably CheckForExceptions() would throw an exception with more verbose message. As the last resort
+ // (we do not even know the name of the failed libxml function, but it's possible to deduce it from stacktrace):
+ ythrow yexception() << "libxml function returned error exit code";
+ }
+
+ bool TTextReader::BoolResult(int value) const {
+ if (Y_UNLIKELY(value == -1)) {
+ ThrowException();
+ }
+ return (value != 0);
+ }
+
+ int TTextReader::IntResult(int value) const {
+ if (Y_UNLIKELY(value == -1)) {
+ ThrowException();
+ }
+ return value;
+ }
+
+ char TTextReader::CharResult(int value) const {
+ if (Y_UNLIKELY(value == -1)) {
+ ThrowException();
+ }
+ return static_cast<char>(value);
+ }
+
+ TStringBuf TTextReader::ConstStringResult(const xmlChar* value) const {
+ if (Y_UNLIKELY(value == nullptr)) {
+ ThrowException();
+ }
+ return CAST2CHAR(value);
+ }
+
+ TStringBuf TTextReader::ConstStringOrEmptyResult(const xmlChar* value) const {
+ CheckForExceptions();
+ return (value != nullptr) ? TStringBuf(CAST2CHAR(value)) : TStringBuf();
+ }
+
+ TString TTextReader::TempStringResult(TCharPtr value) const {
+ if (Y_UNLIKELY(value == nullptr)) {
+ ThrowException();
+ }
+ return TString(CAST2CHAR(value.Get()));
+ }
+
+ TString TTextReader::TempStringOrEmptyResult(TCharPtr value) const {
+ CheckForExceptions();
+ return (value != nullptr) ? TString(CAST2CHAR(value.Get())) : TString();
+ }
+
+ struct TTextReader::TDeleter {
+ static inline void Destroy(xmlTextReaderPtr handle) {
+ xmlFreeTextReader(handle);
+ }
+ };
+}
diff --git a/library/cpp/xml/document/xml-textreader.h b/library/cpp/xml/document/xml-textreader.h
new file mode 100644
index 0000000000..ab4c329d26
--- /dev/null
+++ b/library/cpp/xml/document/xml-textreader.h
@@ -0,0 +1,325 @@
+#pragma once
+
+#include "xml-document.h"
+#include "xml-options.h"
+
+#include <contrib/libs/libxml/include/libxml/xmlreader.h>
+
+#include <library/cpp/string_utils/ztstrbuf/ztstrbuf.h>
+
+#include <util/generic/noncopyable.h>
+#include <util/generic/ptr.h>
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+#include <functional>
+#include <util/stream/input.h>
+#include <util/stream/str.h>
+
+namespace NXml {
+ /**
+ * TextReader Parser
+ *
+ * API of the XML streaming API based on C# interfaces.
+ * Provides fast, non-cached, forward-only access to XML data.
+ *
+ * Like the SAX parser, the TextReader parser is suitable for sequential
+ * parsing, but instead of implementing handlers for specific parts of the
+ * document, it allows you to detect the current node type, process the node
+ * accordingly, and skip forward in the document as much as necessary.
+ *
+ * Unlike the DOM parser, you may not move backwards in the XML document.
+ * And unlike the SAX parser, you must not waste time processing nodes that do not
+ * interest you.
+ *
+ * All methods are on the single parser instance, but their result depends on the current context.
+ * For instance, use Read() to move to the next node, and MoveToElement() to navigate to child nodes.
+ * These methods will return false when no more nodes are available. Then use
+ * methods such as GetName() and GetValue() to examine the elements and their attributes.
+ *
+ * This wrapper is inspired by TextReader from libxml++.
+ */
+
+ class TTextReader: private TNonCopyable {
+ public:
+ // strongly-typed alias for enum from xmlreader.h
+ enum class ENodeType : int {
+ // clang-format off
+ Attribute = XML_READER_TYPE_ATTRIBUTE,
+ CDATA = XML_READER_TYPE_CDATA,
+ Comment = XML_READER_TYPE_COMMENT,
+ Document = XML_READER_TYPE_DOCUMENT,
+ DocumentFragment = XML_READER_TYPE_DOCUMENT_FRAGMENT,
+ DocumentType = XML_READER_TYPE_DOCUMENT_TYPE,
+ Element = XML_READER_TYPE_ELEMENT,
+ EndElement = XML_READER_TYPE_END_ELEMENT,
+ EndEntity = XML_READER_TYPE_END_ENTITY,
+ Entity = XML_READER_TYPE_ENTITY,
+ EntityReference = XML_READER_TYPE_ENTITY_REFERENCE,
+ None = XML_READER_TYPE_NONE,
+ Notation = XML_READER_TYPE_NOTATION,
+ ProcessingInstruction = XML_READER_TYPE_PROCESSING_INSTRUCTION,
+ SignificantWhitespace = XML_READER_TYPE_SIGNIFICANT_WHITESPACE,
+ Text = XML_READER_TYPE_TEXT,
+ Whitespace = XML_READER_TYPE_WHITESPACE,
+ XmlDeclaration = XML_READER_TYPE_XML_DECLARATION,
+ // clang-format on
+ };
+
+ enum class EReadState : int {
+ // clang-format off
+ Closed = XML_TEXTREADER_MODE_CLOSED,
+ EndOfFile = XML_TEXTREADER_MODE_EOF,
+ Error = XML_TEXTREADER_MODE_ERROR,
+ Initial = XML_TEXTREADER_MODE_INITIAL,
+ Interactive = XML_TEXTREADER_MODE_INTERACTIVE,
+ Reading = XML_TEXTREADER_MODE_READING,
+ // clang-format on
+ };
+
+ public:
+ TTextReader(IInputStream& stream, const TOptions& options = TOptions());
+ ~TTextReader();
+
+ /**
+ * Moves the position of the current instance to the next node in the stream, exposing its properties.
+ * @return true if the node was read successfully, false if there are no more nodes to read
+ */
+ bool Read();
+
+ /**
+ * Reads the contents of the current node, including child nodes and markup.
+ * @return A string containing the XML content, or an empty string
+ * if the current node is neither an element nor attribute, or has no child nodes
+ */
+ TString ReadInnerXml() const;
+
+ /**
+ * Reads the current node and its contents, including child nodes and markup.
+ * @return A string containing the XML content, or an empty string
+ * if the current node is neither an element nor attribute
+ */
+ TString ReadOuterXml() const;
+
+ /**
+ * Reads the contents of an element or a text node as a string.
+ * @return A string containing the contents of the Element or Text node,
+ * or an empty string if the reader is positioned on any other type of node
+ */
+ TString ReadString() const;
+
+ /**
+ * Parses an attribute value into one or more Text and EntityReference nodes.
+ * @return A bool where true indicates the attribute value was parsed,
+ * and false indicates the reader was not positioned on an attribute node
+ * or all the attribute values have been read
+ */
+ bool ReadAttributeValue() const;
+
+ /**
+ * Gets the number of attributes on the current node.
+ * @return The number of attributes on the current node, or zero if the current node
+ * does not support attributes
+ */
+ int GetAttributeCount() const;
+
+ /**
+ * Gets the base Uniform Resource Identifier (URI) of the current node.
+ * @return The base URI of the current node or an empty string if not available
+ */
+ TStringBuf GetBaseUri() const;
+
+ /**
+ * Gets the depth of the current node in the XML document.
+ * @return The depth of the current node in the XML document
+ */
+ int GetDepth() const;
+
+ /**
+ * Gets a value indicating whether the current node has any attributes.
+ * @return true if the current has attributes, false otherwise
+ */
+ bool HasAttributes() const;
+
+ /**
+ * Whether the node can have a text value.
+ * @return true if the current node can have an associated text value, false otherwise
+ */
+ bool HasValue() const;
+
+ /**
+ * Whether an Attribute node was generated from the default value defined in the DTD or schema.
+ * @return true if defaulted, false otherwise
+ */
+ bool IsDefault() const;
+
+ /**
+ * Check if the current node is empty.
+ * @return true if empty, false otherwise
+ */
+ bool IsEmptyElement() const;
+
+ /**
+ * The local name of the node.
+ * @return the local name or empty string if not available
+ */
+ TStringBuf GetLocalName() const;
+
+ /**
+ * The qualified name of the node, equal to Prefix:LocalName.
+ * @return the name or empty string if not available
+ */
+ TStringBuf GetName() const;
+
+ /**
+ * The URI defining the namespace associated with the node.
+ * @return the namespace URI or empty string if not available
+ */
+ TStringBuf GetNamespaceUri() const;
+
+ /**
+ * Get the node type of the current node.
+ * @return the ENodeType of the current node
+ */
+ ENodeType GetNodeType() const;
+
+ /**
+ * Get the namespace prefix associated with the current node.
+ * @return the namespace prefix, or an empty string if not available
+ */
+ TStringBuf GetPrefix() const;
+
+ /**
+ * Get the quotation mark character used to enclose the value of an attribute.
+ * @return " or '
+ */
+ char GetQuoteChar() const;
+
+ /**
+ * Provides the text value of the node if present.
+ * @return the string or empty if not available
+ */
+ TStringBuf GetValue() const;
+
+ /**
+ * Gets the read state of the reader.
+ * @return the state value
+ */
+ EReadState GetReadState() const;
+
+ /**
+ * This method releases any resources allocated by the current instance
+ * changes the state to Closed and close any underlying input.
+ */
+ void Close();
+
+ /**
+ * Provides the value of the attribute with the specified index relative to the containing element.
+ * @param number the zero-based index of the attribute relative to the containing element
+ */
+ TString GetAttribute(int number) const;
+
+ /**
+ * Provides the value of the attribute with the specified qualified name.
+ * @param name the qualified name of the attribute
+ */
+ TString GetAttribute(TZtStringBuf name) const;
+
+ /**
+ * Provides the value of the specified attribute.
+ * @param localName the local name of the attribute
+ * @param nsUri the namespace URI of the attribute
+ */
+ TString GetAttribute(TZtStringBuf localName, TZtStringBuf nsUri) const;
+
+ /**
+ * Resolves a namespace prefix in the scope of the current element.
+ * @param prefix the prefix whose namespace URI is to be resolved. To return the default namespace, specify empty string.
+ * @return a string containing the namespace URI to which the prefix maps.
+ */
+ TString LookupNamespace(TZtStringBuf prefix) const;
+
+ /**
+ * Moves the position of the current instance to the attribute with the specified index relative to the containing element.
+ * @param number the zero-based index of the attribute relative to the containing element
+ * @return true in case of success, false if not found
+ */
+ bool MoveToAttribute(int number);
+
+ /**
+ * Moves the position of the current instance to the attribute with the specified qualified name.
+ * @param name the qualified name of the attribute
+ * @return true in case of success, false if not found
+ */
+ bool MoveToAttribute(TZtStringBuf name);
+
+ /**
+ * Moves the position of the current instance to the attribute with the specified local name and namespace URI.
+ * @param localName the local name of the attribute
+ * @param nsUri the namespace URI of the attribute
+ * @return true in case of success, false if not found
+ */
+ bool MoveToAttribute(TZtStringBuf localName, TZtStringBuf nsUri);
+
+ /**
+ * Moves the position of the current instance to the first attribute associated with the current node.
+ * @return true in case of success, false if not found
+ */
+ bool MoveToFirstAttribute();
+
+ /**
+ * Moves the position of the current instance to the next attribute associated with the current node.
+ * @return true in case of success, false if not found
+ */
+ bool MoveToNextAttribute();
+
+ /**
+ * Moves the position of the current instance to the node that contains the current Attribute node.
+ * @return true in case of success, false if not found
+ */
+ bool MoveToElement();
+
+ /**
+ * Reads the contents of the current node and the full subtree. It then makes the subtree available until the next Read() call.
+ */
+ TConstNode Expand() const;
+
+ /**
+ * Skip to the node following the current one in document order while avoiding the subtree if any.
+ * @return true if the node was read successfully, false if there is no more nodes to read
+ */
+ bool Next();
+
+ /**
+ * Retrieve the validity status from the parser context.
+ */
+ bool IsValid() const;
+
+ private:
+ static int ReadFromInputStreamCallback(void* context, char* buffer, int len);
+ static void OnLibxmlError(void* arg, const char* msg, xmlParserSeverities severity, xmlTextReaderLocatorPtr locator);
+
+ void SetupErrorHandler();
+ TStringStream& LogError() const;
+ void CheckForExceptions() const;
+ void ThrowException() const;
+
+ // helpers that check return codes of C functions from libxml
+ bool BoolResult(int value) const;
+ int IntResult(int value) const;
+ char CharResult(int value) const;
+ TStringBuf ConstStringResult(const xmlChar* value) const;
+ TStringBuf ConstStringOrEmptyResult(const xmlChar* value) const;
+ TString TempStringResult(TCharPtr value) const;
+ TString TempStringOrEmptyResult(TCharPtr value) const;
+
+ private:
+ IInputStream& Stream;
+
+ mutable bool IsError;
+ mutable TStringStream ErrorBuffer;
+
+ struct TDeleter;
+ THolder<xmlTextReader, TDeleter> Impl;
+ };
+
+}
diff --git a/library/cpp/xml/document/xml-textreader_ut.cpp b/library/cpp/xml/document/xml-textreader_ut.cpp
new file mode 100644
index 0000000000..6232dfe47e
--- /dev/null
+++ b/library/cpp/xml/document/xml-textreader_ut.cpp
@@ -0,0 +1,290 @@
+#include "xml-textreader.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/hash.h>
+#include <util/generic/vector.h>
+#include <util/string/join.h>
+
+namespace {
+ /**
+ * Simple wrapper around the xmlTextReader wrapper
+ */
+ void ParseXml(const TString& xmlData,
+ std::function<void(NXml::TConstNode)> nodeHandlerFunc,
+ const TString& localName,
+ const TString& namespaceUri = TString()) {
+ TStringInput in(xmlData);
+ NXml::TTextReader reader(in);
+
+ while (reader.Read()) {
+ if (reader.GetNodeType() == NXml::TTextReader::ENodeType::Element &&
+ reader.GetLocalName() == localName &&
+ reader.GetNamespaceUri() == namespaceUri)
+ {
+ const NXml::TConstNode node = reader.Expand();
+ nodeHandlerFunc(node);
+ }
+ }
+ }
+}
+
+Y_UNIT_TEST_SUITE(TestXmlTextReader) {
+ Y_UNIT_TEST(BasicExample) {
+ const TString xml = "<?xml version=\"1.0\"?>\n"
+ "<example toto=\"1\">\n"
+ " <examplechild id=\"1\">\n"
+ " <child_of_child/>\n"
+ " </examplechild>\n"
+ " <examplechild id=\"2\" toto=\"3\">\n"
+ " <child_of_child>Some content : -)</child_of_child>\n"
+ " </examplechild>\n"
+ "</example>\n";
+
+ TStringInput input(xml);
+ NXml::TTextReader reader(input);
+
+ using ENT = NXml::TTextReader::ENodeType;
+
+ struct TItem {
+ int Depth;
+ ENT Type;
+ TString Name;
+ TString Attrs;
+ TString Value;
+ };
+
+ TVector<TItem> found;
+ TVector<TString> msgs;
+
+ while (reader.Read()) {
+ // dump attributes as "k1: v1, k2: v2, ..."
+ TVector<TString> kv;
+ if (reader.HasAttributes()) {
+ reader.MoveToFirstAttribute();
+ do {
+ kv.push_back(TString::Join(reader.GetName(), ": ", reader.GetValue()));
+ } while (reader.MoveToNextAttribute());
+ reader.MoveToElement();
+ }
+
+ found.push_back(TItem{
+ reader.GetDepth(),
+ reader.GetNodeType(),
+ TString(reader.GetName()),
+ JoinSeq(", ", kv),
+ reader.HasValue() ? TString(reader.GetValue()) : TString(),
+ });
+ }
+
+ const TVector<TItem> expected = {
+ TItem{0, ENT::Element, "example", "toto: 1", ""},
+ TItem{1, ENT::SignificantWhitespace, "#text", "", "\n "},
+ TItem{1, ENT::Element, "examplechild", "id: 1", ""},
+ TItem{2, ENT::SignificantWhitespace, "#text", "", "\n "},
+ TItem{2, ENT::Element, "child_of_child", "", ""},
+ TItem{2, ENT::SignificantWhitespace, "#text", "", "\n "},
+ TItem{1, ENT::EndElement, "examplechild", "id: 1", ""},
+ TItem{1, ENT::SignificantWhitespace, "#text", "", "\n "},
+ TItem{1, ENT::Element, "examplechild", "id: 2, toto: 3", ""},
+ TItem{2, ENT::SignificantWhitespace, "#text", "", "\n "},
+ TItem{2, ENT::Element, "child_of_child", "", ""},
+ TItem{3, ENT::Text, "#text", "", "Some content : -)"},
+ TItem{2, ENT::EndElement, "child_of_child", "", ""},
+ TItem{2, ENT::SignificantWhitespace, "#text", "", "\n "},
+ TItem{1, ENT::EndElement, "examplechild", "id: 2, toto: 3", ""},
+ TItem{1, ENT::SignificantWhitespace, "#text", "", "\n"},
+ TItem{0, ENT::EndElement, "example", "toto: 1", ""}};
+
+ UNIT_ASSERT_VALUES_EQUAL(found.size(), expected.size());
+
+ for (size_t i = 0; i < expected.size(); ++i) {
+ UNIT_ASSERT_VALUES_EQUAL_C(found[i].Depth, expected[i].Depth, "line " << i);
+ UNIT_ASSERT_EQUAL_C(found[i].Type, expected[i].Type, "line " << i);
+ UNIT_ASSERT_VALUES_EQUAL_C(found[i].Name, expected[i].Name, "line " << i);
+ UNIT_ASSERT_VALUES_EQUAL_C(found[i].Attrs, expected[i].Attrs, "line " << i);
+ UNIT_ASSERT_VALUES_EQUAL_C(found[i].Value, expected[i].Value, "line " << i);
+ }
+ }
+
+ const TString GEODATA = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<root>"
+ ""
+ " <country id=\"225\">"
+ " <name>Россия</name>"
+ " <cities>"
+ " <city>Москва</city>"
+ " <city>Санкт-Петербург</city>"
+ " </cities>"
+ " </country>"
+ ""
+ " <country id=\"149\">"
+ " <name>Беларусь</name>"
+ " <cities>"
+ " <city>Минск</city>"
+ " </cities>"
+ " </country>"
+ ""
+ " <country id=\"187\">"
+ " <name>Украина</name>"
+ " <cities>"
+ " <city>Киев</city>"
+ " </cities>"
+ " </country>"
+ ""
+ "</root>";
+
+ Y_UNIT_TEST(ParseXmlSimple) {
+ struct TCountry {
+ TString Name;
+ TVector<TString> Cities;
+ };
+
+ THashMap<int, TCountry> data;
+
+ auto handler = [&data](NXml::TConstNode node) {
+ const int id = node.Attr<int>("id");
+
+ TCountry& c = data[id];
+
+ c.Name = node.FirstChild("name").Value<TString>();
+
+ const NXml::TConstNodes cityNodes = node.Nodes("cities/city");
+ for (auto cityNode : cityNodes) {
+ c.Cities.push_back(cityNode.Value<TString>());
+ }
+ };
+
+ ParseXml(GEODATA, handler, "country");
+
+ UNIT_ASSERT_EQUAL(data.size(), 3);
+
+ UNIT_ASSERT(data.contains(225));
+ const TCountry& russia = data.at(225);
+ UNIT_ASSERT_EQUAL(russia.Name, "Россия");
+ UNIT_ASSERT_EQUAL(russia.Cities.size(), 2);
+ UNIT_ASSERT_EQUAL(russia.Cities[0], "Москва");
+ UNIT_ASSERT_EQUAL(russia.Cities[1], "Санкт-Петербург");
+
+ UNIT_ASSERT(data.contains(149));
+ const TCountry& belarus = data.at(149);
+ UNIT_ASSERT_EQUAL(belarus.Name, "Беларусь");
+ UNIT_ASSERT_EQUAL(belarus.Cities.size(), 1);
+ UNIT_ASSERT_EQUAL(belarus.Cities[0], "Минск");
+
+ UNIT_ASSERT(data.contains(187));
+ const TCountry& ukraine = data.at(187);
+ UNIT_ASSERT_EQUAL(ukraine.Name, "Украина");
+ UNIT_ASSERT_EQUAL(ukraine.Cities.size(), 1);
+ UNIT_ASSERT_EQUAL(ukraine.Cities[0], "Киев");
+ }
+
+ Y_UNIT_TEST(ParseXmlDeepLevel) {
+ TVector<TString> cities;
+
+ auto handler = [&cities](NXml::TConstNode node) {
+ cities.push_back(node.Value<TString>());
+ };
+
+ ParseXml(GEODATA, handler, "city");
+
+ UNIT_ASSERT_EQUAL(cities.size(), 4);
+ UNIT_ASSERT_EQUAL(cities[0], "Москва");
+ UNIT_ASSERT_EQUAL(cities[1], "Санкт-Петербург");
+ UNIT_ASSERT_EQUAL(cities[2], "Минск");
+ UNIT_ASSERT_EQUAL(cities[3], "Киев");
+ }
+
+ Y_UNIT_TEST(ParseXmlException) {
+ // Check that exception properly passes through plain C code of libxml,
+ // no leaks are detected by valgrind.
+ auto handler = [](NXml::TConstNode node) {
+ const int id = node.Attr<int>("id");
+ if (id != 225) {
+ ythrow yexception() << "unsupported id: " << id;
+ }
+ };
+
+ UNIT_ASSERT_EXCEPTION(ParseXml(GEODATA, handler, "country"), yexception);
+ UNIT_ASSERT_EXCEPTION(ParseXml("<a></b>", handler, "a"), yexception);
+ UNIT_ASSERT_EXCEPTION(ParseXml("<root><a id=\"1\"></a><a id=\"2\"></b></root>", handler, "a"), yexception);
+ UNIT_ASSERT_EXCEPTION(ParseXml("<root><a id=\"1\"></a><a id=\"2></a></root>", handler, "a"), yexception);
+ }
+
+ const TString BACKA = // UTF-8 encoding is used implicitly
+ "<Companies"
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
+ " xmlns=\"http://maps.yandex.ru/backa/1.x\""
+ " xmlns:atom=\"http://www.w3.org/2005/Atom\""
+ " xmlns:biz=\"http://maps.yandex.ru/business/1.x\""
+ " xmlns:xal=\"urn:oasis:names:tc:ciq:xsdschema:xAL:2.0\""
+ " xmlns:gml=\"http://www.opengis.net/gml\""
+ ">"
+ ""
+ " <Company id=\"0001\">"
+ " <Geo>"
+ " <Location>"
+ " <gml:pos>37.62669 55.664827</gml:pos>"
+ " <kind>house</kind>"
+ " </Location>"
+ " <AddressDetails xmlns=\"urn:oasis:names:tc:ciq:xsdschema:xAL:2.0\">"
+ " <Country>"
+ " <AddressLine xml:lang=\"ru\">Москва, Каширское ш., 14</AddressLine>"
+ " </Country>"
+ " </AddressDetails>"
+ " </Geo>"
+ " </Company>"
+ ""
+ " <Company id=\"0002\">"
+ " <Geo>"
+ " <Location>"
+ " <pos xmlns=\"http://www.opengis.net/gml\">150.819797 59.56092</pos>"
+ " <kind>locality</kind>"
+ " </Location>"
+ " <xal:AddressDetails>"
+ " <xal:Country>"
+ " <xal:AddressLine xml:lang=\"ru\">Магадан, ул. Пролетарская, 43</xal:AddressLine>"
+ " </xal:Country>"
+ " </xal:AddressDetails>"
+ " </Geo>"
+ " </Company>"
+ ""
+ "</Companies>";
+
+ Y_UNIT_TEST(NamespaceHell) {
+ using TNS = NXml::TNamespaceForXPath;
+ const NXml::TNamespacesForXPath ns = {
+ TNS{"b", "http://maps.yandex.ru/backa/1.x"},
+ TNS{"gml", "http://www.opengis.net/gml"},
+ TNS{"xal", "urn:oasis:names:tc:ciq:xsdschema:xAL:2.0"}};
+
+ int count = 0;
+ THashMap<TString, TString> positions;
+ THashMap<TString, TString> addresses;
+
+ auto handler = [&](NXml::TConstNode node) {
+ count++;
+ const auto id = node.Attr<TString>("id");
+
+ NXml::TXPathContextPtr ctxt = node.CreateXPathContext(ns);
+
+ const NXml::TConstNode location = node.Node("b:Geo/b:Location", false, *ctxt);
+ positions[id] = location.Node("gml:pos", false, *ctxt).Value<TString>();
+ addresses[id] = node.Node("b:Geo/xal:AddressDetails/xal:Country/xal:AddressLine", false, *ctxt).Value<TString>();
+ };
+
+ ParseXml(BACKA, handler, "Company");
+ UNIT_ASSERT_EQUAL(count, 0);
+ // nothing found because namespace was not specified
+
+ ParseXml(BACKA, handler, "Company", "http://maps.yandex.ru/backa/1.x");
+
+ UNIT_ASSERT_VALUES_EQUAL(count, 2);
+
+ UNIT_ASSERT_VALUES_EQUAL(positions["0001"], "37.62669 55.664827");
+ UNIT_ASSERT_VALUES_EQUAL(positions["0002"], "150.819797 59.56092");
+
+ UNIT_ASSERT_VALUES_EQUAL(addresses["0001"], "Москва, Каширское ш., 14");
+ UNIT_ASSERT_VALUES_EQUAL(addresses["0002"], "Магадан, ул. Пролетарская, 43");
+ }
+}
diff --git a/library/cpp/xml/document/ya.make b/library/cpp/xml/document/ya.make
new file mode 100644
index 0000000000..86bbd639cf
--- /dev/null
+++ b/library/cpp/xml/document/ya.make
@@ -0,0 +1,17 @@
+LIBRARY()
+
+OWNER(finder)
+
+SRCS(
+ xml-document.cpp
+ xml-textreader.cpp
+ xml-options.cpp
+)
+
+PEERDIR(
+ library/cpp/xml/init
+ contrib/libs/libxml
+ library/cpp/string_utils/ztstrbuf
+)
+
+END()
diff --git a/library/cpp/xml/init/init.cpp b/library/cpp/xml/init/init.cpp
new file mode 100644
index 0000000000..aa96c2dd31
--- /dev/null
+++ b/library/cpp/xml/init/init.cpp
@@ -0,0 +1,39 @@
+#include "init.h"
+
+#include <libxml/xmlIO.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/tree.h>
+
+#include <library/cpp/charset/recyr.hh>
+#include <util/generic/singleton.h>
+
+namespace {
+ int CharEncodingInput(unsigned char* out, int* outlen, const unsigned char* in, int* inlen) {
+ size_t read = 0, written = 0;
+ RECODE_RESULT r = Recode(CODES_WIN, CODES_UTF8, (const char*)in, (char*)out, (size_t)*inlen, (size_t)*outlen, read, written);
+ if (r == RECODE_EOOUTPUT)
+ return -1;
+ if (r != RECODE_OK)
+ return -2;
+ *inlen = (int)read;
+ *outlen = (int)written;
+ return (int)written;
+ }
+
+ class TLibXml2 {
+ public:
+ inline TLibXml2() {
+ xmlInitParser();
+ xmlNewCharEncodingHandler("windows-1251", CharEncodingInput, nullptr);
+ }
+
+ inline ~TLibXml2() {
+ xmlCleanupParser();
+ }
+ };
+}
+
+void NXml::InitEngine() {
+ Singleton<TLibXml2>();
+}
diff --git a/library/cpp/xml/init/init.h b/library/cpp/xml/init/init.h
new file mode 100644
index 0000000000..2cdc46c655
--- /dev/null
+++ b/library/cpp/xml/init/init.h
@@ -0,0 +1,5 @@
+#pragma once
+
+namespace NXml {
+ void InitEngine();
+}
diff --git a/library/cpp/xml/init/ptr.cpp b/library/cpp/xml/init/ptr.cpp
new file mode 100644
index 0000000000..e11a6460c3
--- /dev/null
+++ b/library/cpp/xml/init/ptr.cpp
@@ -0,0 +1 @@
+#include "ptr.h"
diff --git a/library/cpp/xml/init/ptr.h b/library/cpp/xml/init/ptr.h
new file mode 100644
index 0000000000..7387c7cc40
--- /dev/null
+++ b/library/cpp/xml/init/ptr.h
@@ -0,0 +1,69 @@
+#pragma once
+
+#include <util/generic/ptr.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/xmlsave.h>
+#include <libxml/uri.h>
+#include <libxml/xmlschemas.h>
+
+template <class T, void (*DestroyFun)(T*)>
+struct TFunctionDestroy {
+ static inline void Destroy(T* t) noexcept {
+ if (t)
+ DestroyFun(t);
+ }
+};
+
+namespace NXml {
+#define DEF_HOLDER(type, free) typedef THolder<type, TFunctionDestroy<type, free>> T##type##Holder
+#define DEF_PTR(type, free) typedef TAutoPtr<type, TFunctionDestroy<type, free>> T##type##Ptr
+
+ // define xmlDocPtr -> TxmlDocHolder TxmlDocPtr
+ DEF_HOLDER(xmlDoc, xmlFreeDoc);
+ DEF_PTR(xmlDoc, xmlFreeDoc);
+
+ // xmlXPathContextPtr xpathCtx;
+ DEF_HOLDER(xmlXPathContext, xmlXPathFreeContext);
+ DEF_PTR(xmlXPathContext, xmlXPathFreeContext);
+
+ // xmlXPathObjectPtr xpathObj;
+ DEF_HOLDER(xmlXPathObject, xmlXPathFreeObject);
+ DEF_PTR(xmlXPathObject, xmlXPathFreeObject);
+
+ // xmlNodeSetPtr nodes
+ DEF_HOLDER(xmlNodeSet, xmlXPathFreeNodeSet);
+ DEF_PTR(xmlNodeSet, xmlXPathFreeNodeSet);
+
+ // xmlSchemaParserCtxtPtr ctxt;
+ DEF_HOLDER(xmlSchemaParserCtxt, xmlSchemaFreeParserCtxt);
+ DEF_PTR(xmlSchemaParserCtxt, xmlSchemaFreeParserCtxt);
+
+ // xmlSchemaPtr schema;
+ DEF_HOLDER(xmlSchema, xmlSchemaFree);
+ DEF_PTR(xmlSchema, xmlSchemaFree);
+
+ // xmlSchemaValidCtxt ctxt;
+ DEF_HOLDER(xmlSchemaValidCtxt, xmlSchemaFreeValidCtxt);
+ DEF_PTR(xmlSchemaValidCtxt, xmlSchemaFreeValidCtxt);
+
+ // xmlSaveCtxtPtr
+ inline void xmlFreeSave(xmlSaveCtxt* c) {
+ // returns int
+ xmlSaveClose(c);
+ }
+ DEF_HOLDER(xmlSaveCtxt, xmlFreeSave);
+ DEF_PTR(xmlSaveCtxt, xmlFreeSave);
+
+ DEF_PTR(xmlURI, xmlFreeURI);
+ DEF_PTR(xmlNode, xmlFreeNode);
+ DEF_PTR(xmlParserCtxt, xmlFreeParserCtxt);
+ DEF_PTR(xmlParserInputBuffer, xmlFreeParserInputBuffer);
+ DEF_PTR(xmlDtd, xmlFreeDtd);
+ DEF_PTR(xmlValidCtxt, xmlFreeValidCtxt);
+
+#undef DEF_HOLDER
+#undef DEF_PTR
+}
diff --git a/library/cpp/xml/init/ya.make b/library/cpp/xml/init/ya.make
new file mode 100644
index 0000000000..5f3883c2c9
--- /dev/null
+++ b/library/cpp/xml/init/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ contrib/libs/libxml
+ library/cpp/charset
+)
+
+SRCS(
+ ptr.cpp
+ init.cpp
+)
+
+END()
diff --git a/library/cpp/xml/ya.make b/library/cpp/xml/ya.make
new file mode 100644
index 0000000000..5a685b70e6
--- /dev/null
+++ b/library/cpp/xml/ya.make
@@ -0,0 +1,13 @@
+RECURSE(
+ doc
+ document/ut
+ encode
+ encode/ut
+ init
+ parslib
+ parslib/ut
+ sax
+ sax/ut
+ validator
+ validator/ut
+)
diff --git a/library/cpp/ya.make b/library/cpp/ya.make
new file mode 100644
index 0000000000..8c1193b007
--- /dev/null
+++ b/library/cpp/ya.make
@@ -0,0 +1,450 @@
+OWNER(g:cpp-contrib)
+
+RECURSE(
+ accurate_accumulate
+ accurate_accumulate/benchmark
+ accurate_accumulate/benchmark/metrics
+ actors
+ actors/ut
+ aio
+ any
+ any/ut
+ archive/ut
+ auth_client_parser
+ barcode
+ barcode/ut
+ binsaver
+ binsaver/ut
+ binsaver/ut_util
+ bit_io
+ bit_io/ut
+ blackbox2
+ blob_cache
+ blob_cache/ut
+ blockcodecs
+ blockcodecs/fuzz
+ bloom_filter
+ bloom_filter/benchmark
+ bloom_filter/ut
+ bucket_quoter
+ build_info
+ cache
+ case_insensitive_string
+ cgiparam
+ cgiparam/fuzz
+ cgiparam/ut
+ charset
+ charset/ut
+ chromium_trace
+ clang_tidy
+ clickhouse
+ clustered_hnsw
+ clustered_hnsw/ut
+ codecs
+ codecs/float_huffman_bench
+ codecs/greedy_dict/ut
+ codecs/static/tools
+ codecs/static/tools/tests
+ codecs/static/ut
+ codecs/ut
+ colorizer
+ colorizer/ut
+ compproto
+ compproto/ut
+ comptable
+ comptable/usage
+ comptable/ut
+ compute_graph
+ compute_rt_graph
+ compute_rt_graph/ut
+ config
+ config/extra
+ config/ut
+ consistent_hash_ring
+ consistent_hash_ring/ut
+ consistent_hashing
+ consistent_hashing/ut
+ containers
+ coroutine
+ cppparser
+ cpuid_check
+ cpuload
+ dbg_output
+ dbg_output/ut
+ deprecated
+ diff
+ diff/ut
+ digest
+ disjoint_sets
+ disjoint_sets/ut
+ dns
+ dns/ut
+ dolbilo
+ dolbilo/ut
+ domtree
+ domtree/tool
+ dot_product
+ dot_product/bench
+ dot_product/ut
+ dwarf_backtrace
+ dwarf_backtrace/registry
+ edit_distance
+ edit_distance/ut
+ enumbitset
+ enumbitset/ut
+ erasure
+ erasure/benchmark
+ erasure/ut
+ eventlog
+ eventlog/dumper
+ eventlog/dumper/ut
+ eventlog/rt
+ eventlog/rt/tool
+ eventlog/test
+ eventlog/ut
+ eventlog/yt
+ exception_counter
+ execprofile
+ execprofile/autostart
+ expression
+ expression/ut
+ ext
+ ext/ut
+ fast_exp
+ fast_exp/benchmark
+ fast_exp/ut
+ fast_log
+ fieldcalc
+ fieldcalc/ut
+ file_checker
+ file_checker/test
+ file_checker/test/tests
+ file_checker/ut
+ flatbuffers64_introspection
+ flatbuffers64_introspection/example
+ float16
+ float16/ut
+ framing
+ framing/ut
+ fuid
+ fuid/ut
+ function_tracer
+ geo
+ geobase
+ geobase/ut
+ geohash
+ geohash/tile
+ geohash/tile/ut
+ geohash/ut
+ geolocation
+ geotarget
+ getopt
+ getopt/last_getopt_demo
+ getopt/small
+ getopt/ut
+ getoptpb
+ gettimeofday
+ gradient_optimize
+ gradient_optimize/ut
+ graph
+ grid_creator
+ grid_creator/fuzz
+ grid_creator/ut
+ grpc
+ histogram
+ hnsw
+ html
+ html/dehtml/ut
+ http
+ hyperloglog
+ hyperloglog/ut
+ inf_buffer
+ infected_masks
+ infected_masks/tools
+ infected_masks/ut
+ int128
+ int128/ut
+ introspection
+ ipmath
+ ipreg
+ ipreg/ut
+ ipv6_address
+ ipv6_address/ut
+ iterator
+ json
+ json/fast_sax
+ json/flex_buffers
+ json/flex_buffers/ut
+ json/fuzzy_test
+ json/ut
+ json/writer/ut
+ json/yson
+ json/yson/ut
+ kmeans_hnsw
+ kmeans_hnsw/ut
+ knn_index
+ knn_index/bench
+ knn_index/ut
+ l1_distance
+ l1_distance/bench
+ l1_distance/ut
+ l2_distance
+ l2_distance/bench
+ l2_distance/ut
+ langmask
+ langmask/proto
+ langmask/serialization
+ langmask/ut
+ langs
+ langs/ut
+ lcookie
+ lcookie/ut
+ lcs
+ lcs/ut
+ lfalloc
+ lfalloc/dbg
+ lfalloc/dbg_info
+ lfalloc/yt
+ libgit2_wrapper
+ linear_regression
+ linear_regression/benchmark
+ linear_regression/ut
+ logger
+ logger/global
+ logger/global/ut
+ logger/ut
+ lua
+ lua/check
+ lua/check/ut
+ lua/sandbox/ut
+ lua/ut
+ lwtrace
+ lwtrace/example1
+ lwtrace/example2
+ lwtrace/example3
+ lwtrace/example4
+ lwtrace/example5
+ lwtrace/tests
+ lwtrace/ut
+ malloc
+ map_text_file
+ map_text_file/ut
+ matrix
+ matrix/test
+ md5_checker
+ md5_checker/ut
+ mediator
+ mediator/ut
+ messagebus/all
+ messagebus/test
+ microbdb
+ microbdb/ut
+ mime
+ minhash
+ minhash/tools
+ minhash/ut
+ mongo
+ monlib
+ msgpack
+ msgpack2json
+ msgpack2json/ut
+ neh
+ neh/asio/ut
+ neh/ut
+ netliba
+ nirvana
+ nth_elements
+ nth_elements/fuzz
+ nth_elements/ut
+ numerator
+ numerator/blob
+ oauth
+ object_factory
+ object_factory/ut
+ offroad
+ on_disk
+ online_hnsw
+ online_hnsw/ut
+ openssl
+ os_family
+ os_family/protos
+ os_family/ut
+ packedtypes/ut
+ packers
+ packers/ut
+ par
+ perceptron
+ pop_count
+ pop_count/benchmark
+ pop_count/ut
+ presort
+ presort/ut
+ prob_counter
+ prob_counter/ut
+ progress_bar
+ proto_config
+ proto_config/codegen
+ proto_config/exec_test
+ proto_config/exec_test/tool
+ proto_config/exec_test/tool_resource
+ proto_config/plugin
+ proto_config/protos
+ proto_config/ut
+ protobuf
+ pybind
+ pybind/example
+ pybind/example/dynamic
+ pybind/example/static
+ pybind/example/ut
+ query_marker
+ randomforest
+ regex
+ region
+ region/ut
+ resource
+ resource/ut
+ retry
+ retry/protos
+ retry/ut
+ reverse_geocoder
+ robots_txt
+ robots_txt/ut
+ safe_stats
+ safe_stats/ut
+ sampling
+ sampling/benchmark
+ sampling/benchmark/metrics
+ sampling/bin
+ sampling/ut
+ scheme
+ scheme/tests
+ scheme/ut_utils
+ scores
+ scores/ut
+ select_in_word
+ select_in_word/bench
+ select_in_word/ut
+ semver
+ semver/ut
+ shingles
+ shingles/ut
+ sighandler
+ simhash
+ simhash/ut
+ skiff
+ sliding_window
+ sliding_window/ut
+ solve_ambig
+ solve_ambig/ut
+ sorter
+ sorter/ut
+ sqlite3
+ sqlite3/ut
+ sse
+ ssh
+ ssh/ut
+ ssh_sign
+ ssh_sign/ut
+ stat-handle
+ stat-handle/ut
+ statistics
+ statistics/ut
+ stopwords
+ stopwords/ut
+ streams
+ string_utils
+ succinct_arrays
+ succinct_arrays/ut
+ svnversion
+ telfinder
+ telfinder/ut
+ terminate_handler
+ terminate_handler/sample
+ testing
+ text_processing
+ threading
+ timezone_conversion
+ timezone_conversion/ut
+ tld
+ tld/ut
+ token
+ token/lite
+ token/serialization
+ token/serialization/ut
+ token/ut
+ tokenclassifiers
+ tokenizer
+ tokenizer/ut
+ trace_usage
+ trace_usage/benchmark
+ trace_usage/ut
+ tvmauth
+ tvmknife
+ type_info
+ type_info/bench
+ ucompress
+ udp
+ uilangdetect
+ uilangdetect/ut
+ unicode
+ unistat
+ unistat/ut
+ uri
+ user_agent
+ vec4
+ vec4/ut
+ vl_feat
+ vowpalwabbit
+ vowpalwabbit/tools
+ vowpalwabbit/ut
+ watchdog
+ watchdog/timeout/ut
+ wordlistreader
+ xml
+ xmlrpc
+ xsltransform
+ xsltransform/ut
+ yaml
+ yappy
+ yconf
+ yconf/patcher
+ yconf/patcher/ut
+ yconf/ut
+ yson
+ yson/json
+ yson/node
+ yson/node/pybind
+ yson_pull
+ yson_pull/ut
+ yt
+ zipatch
+)
+
+IF (OS_LINUX)
+ RECURSE(
+ balloc/test
+ balloc/aba_agri_test
+ balloc_market/test
+ balloc_market/aba_agri_test
+ ytalloc
+ rseq
+ )
+ENDIF()
+
+IF (OS_WINDOWS)
+ RECURSE(
+ winservice
+ )
+ELSE()
+ RECURSE(
+ fuse
+ sse/ut
+ tf
+ xdelta3
+ zookeeper
+ )
+ENDIF()
+
+IF (HAVE_CUDA)
+ RECURSE(cuda)
+ENDIF()
diff --git a/library/cpp/yaml/as/tstring.h b/library/cpp/yaml/as/tstring.h
new file mode 100644
index 0000000000..1037e46706
--- /dev/null
+++ b/library/cpp/yaml/as/tstring.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <contrib/libs/yaml-cpp/include/yaml-cpp/yaml.h>
+
+#include <util/generic/string.h>
+
+namespace YAML {
+ template <>
+ inline TString Node::as<TString>() const {
+ const auto& converted = as<std::string>();
+ return TString(converted.c_str(), converted.size());
+ }
+
+ template <>
+ struct convert<TString> {
+ static Node encode(const TString& rhs) {
+ return Node(std::string(rhs));
+ }
+
+ static bool decode(const Node& node, TString& rhs) {
+ if (!node.IsScalar())
+ return false;
+ rhs = node.Scalar();
+ return true;
+ }
+ };
+}
diff --git a/library/cpp/yaml/as/ut/tstring_test.cpp b/library/cpp/yaml/as/ut/tstring_test.cpp
new file mode 100644
index 0000000000..2ad4f6c572
--- /dev/null
+++ b/library/cpp/yaml/as/ut/tstring_test.cpp
@@ -0,0 +1,59 @@
+#include <library/cpp/testing/unittest/registar.h>
+#include <library/cpp/yaml/as/tstring.h>
+
+#include <contrib/libs/yaml-cpp/include/yaml-cpp/yaml.h>
+
+#include <array>
+
+Y_UNIT_TEST_SUITE(YamlTstringTest) {
+ Y_UNIT_TEST(As) {
+ const auto* key1 = "key1";
+ const auto* key2 = "key2";
+ const TString string = "string";
+ const TString anotherString = "another string";
+
+ YAML::Node map;
+ map[key1] = std::string(string);
+
+ UNIT_ASSERT_VALUES_EQUAL(map[key1].as<TString>(), string);
+ UNIT_ASSERT_VALUES_EQUAL(map[key1].as<TString>(anotherString), string);
+
+ UNIT_ASSERT_VALUES_EQUAL(map[key2].as<TString>(anotherString), anotherString);
+
+ UNIT_ASSERT_EXCEPTION(map[key1].as<int>(), YAML::BadConversion);
+
+ UNIT_ASSERT_EXCEPTION(map[key2].as<int>(), YAML::BadConversion);
+ UNIT_ASSERT_EXCEPTION(map[key2].as<TString>(), YAML::BadConversion);
+ }
+
+ Y_UNIT_TEST(Convert) {
+ const TString string("string");
+ auto node = YAML::Node(std::string(string));
+
+ UNIT_ASSERT_VALUES_EQUAL(node.Scalar(), YAML::convert<TString>::encode(string).Scalar());
+
+ TString buffer;
+ YAML::convert<TString>::decode(node, buffer);
+ UNIT_ASSERT_VALUES_EQUAL(string, buffer);
+ }
+
+ Y_UNIT_TEST(NullCharactersInString) {
+ const std::array<char, 3> characters = {{'a', '\0', 'b'}};
+ const std::string testString(characters.data(), characters.size());
+ const TString refString(characters.data(), characters.size());
+ const std::string key = "key";
+
+ YAML::Node node;
+ node[key] = testString;
+
+ UNIT_ASSERT_VALUES_EQUAL(node[key].as<TString>(), refString);
+ UNIT_ASSERT_VALUES_EQUAL(node[key].as<TString>(TString("fallback")), refString);
+
+ auto stringNode = YAML::Node(testString);
+ UNIT_ASSERT_VALUES_EQUAL(stringNode.Scalar(), YAML::convert<TString>::encode(refString).Scalar());
+
+ TString buffer;
+ YAML::convert<TString>::decode(stringNode, buffer);
+ UNIT_ASSERT_VALUES_EQUAL(refString, buffer);
+ }
+}
diff --git a/library/cpp/yaml/as/ut/ya.make b/library/cpp/yaml/as/ut/ya.make
new file mode 100644
index 0000000000..4eb394dd54
--- /dev/null
+++ b/library/cpp/yaml/as/ut/ya.make
@@ -0,0 +1,14 @@
+UNITTEST()
+
+OWNER(g:crypta)
+
+SRCS(
+ tstring_test.cpp
+)
+
+PEERDIR(
+ contrib/libs/yaml-cpp
+ library/cpp/yaml/as
+)
+
+END()
diff --git a/library/cpp/yaml/as/ya.make b/library/cpp/yaml/as/ya.make
new file mode 100644
index 0000000000..80d60b957b
--- /dev/null
+++ b/library/cpp/yaml/as/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(g:crypta)
+
+PEERDIR(
+ contrib/libs/yaml-cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ ut
+)
diff --git a/library/cpp/yaml/ya.make b/library/cpp/yaml/ya.make
new file mode 100644
index 0000000000..e9689fe65b
--- /dev/null
+++ b/library/cpp/yaml/ya.make
@@ -0,0 +1,4 @@
+RECURSE(
+ as
+ scheme
+)
diff --git a/library/cpp/yson/consumer.cpp b/library/cpp/yson/consumer.cpp
new file mode 100644
index 0000000000..40ae452978
--- /dev/null
+++ b/library/cpp/yson/consumer.cpp
@@ -0,0 +1,15 @@
+#include "consumer.h"
+#include "string.h"
+#include "parser.h"
+
+namespace NYson {
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ void TYsonConsumerBase::OnRaw(TStringBuf str, NYT::NYson::EYsonType type) {
+ ParseYsonStringBuffer(str, this, type);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/consumer.h b/library/cpp/yson/consumer.h
new file mode 100644
index 0000000000..d5a9d66335
--- /dev/null
+++ b/library/cpp/yson/consumer.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <library/cpp/yt/yson/consumer.h>
+
+#include <util/generic/strbuf.h>
+#include <util/system/defaults.h>
+
+namespace NYson {
+ struct TYsonConsumerBase
+ : public virtual NYT::NYson::IYsonConsumer {
+ void OnRaw(TStringBuf ysonNode, NYT::NYson::EYsonType type) override;
+ };
+} // namespace NYson
diff --git a/library/cpp/yson/detail.h b/library/cpp/yson/detail.h
new file mode 100644
index 0000000000..27f5e8ffff
--- /dev/null
+++ b/library/cpp/yson/detail.h
@@ -0,0 +1,806 @@
+#pragma once
+
+#include "public.h"
+#include "zigzag.h"
+
+#include <util/generic/vector.h>
+#include <util/generic/maybe.h>
+#include <util/generic/buffer.h>
+#include <util/string/escape.h>
+#include <util/string/cast.h>
+#include <util/stream/input.h>
+
+namespace NYson {
+ namespace NDetail {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ //! Indicates the beginning of a list.
+ const char BeginListSymbol = '[';
+ //! Indicates the end of a list.
+ const char EndListSymbol = ']';
+
+ //! Indicates the beginning of a map.
+ const char BeginMapSymbol = '{';
+ //! Indicates the end of a map.
+ const char EndMapSymbol = '}';
+
+ //! Indicates the beginning of an attribute map.
+ const char BeginAttributesSymbol = '<';
+ //! Indicates the end of an attribute map.
+ const char EndAttributesSymbol = '>';
+
+ //! Separates items in lists.
+ const char ListItemSeparatorSymbol = ';';
+ //! Separates items in maps, attributes.
+ const char KeyedItemSeparatorSymbol = ';';
+ //! Separates keys from values in maps.
+ const char KeyValueSeparatorSymbol = '=';
+
+ //! Indicates an entity.
+ const char EntitySymbol = '#';
+
+ //! Indicates end of stream.
+ const char EndSymbol = '\0';
+
+ //! Marks the beginning of a binary string literal.
+ const char StringMarker = '\x01';
+ //! Marks the beginning of a binary i64 literal.
+ const char Int64Marker = '\x02';
+ //! Marks the beginning of a binary double literal.
+ const char DoubleMarker = '\x03';
+ //! Marks true and false values of boolean.
+ const char FalseMarker = '\x04';
+ const char TrueMarker = '\x05';
+ //! Marks the beginning of a binary ui64 literal.
+ const char Uint64Marker = '\x06';
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <bool EnableLinePositionInfo>
+ class TPositionInfo;
+
+ template <>
+ class TPositionInfo<true> {
+ private:
+ int Offset;
+ int Line;
+ int Column;
+
+ public:
+ TPositionInfo()
+ : Offset(0)
+ , Line(1)
+ , Column(1)
+ {
+ }
+
+ void OnRangeConsumed(const char* begin, const char* end) {
+ Offset += end - begin;
+ for (auto current = begin; current != end; ++current) {
+ ++Column;
+ if (*current == '\n') { //TODO: memchr
+ ++Line;
+ Column = 1;
+ }
+ }
+ }
+ };
+
+ template <>
+ class TPositionInfo<false> {
+ private:
+ int Offset;
+
+ public:
+ TPositionInfo()
+ : Offset(0)
+ {
+ }
+
+ void OnRangeConsumed(const char* begin, const char* end) {
+ Offset += end - begin;
+ }
+ };
+
+ template <class TBlockStream, class TPositionBase>
+ class TCharStream
+ : public TBlockStream,
+ public TPositionBase {
+ public:
+ TCharStream(const TBlockStream& blockStream)
+ : TBlockStream(blockStream)
+ {
+ }
+
+ bool IsEmpty() const {
+ return TBlockStream::Begin() == TBlockStream::End();
+ }
+
+ template <bool AllowFinish>
+ void Refresh() {
+ while (IsEmpty() && !TBlockStream::IsFinished()) {
+ TBlockStream::RefreshBlock();
+ }
+ if (IsEmpty() && TBlockStream::IsFinished() && !AllowFinish) {
+ ythrow TYsonException() << "Premature end of yson stream";
+ }
+ }
+
+ void Refresh() {
+ return Refresh<false>();
+ }
+
+ template <bool AllowFinish>
+ char GetChar() {
+ Refresh<AllowFinish>();
+ return !IsEmpty() ? *TBlockStream::Begin() : '\0';
+ }
+
+ char GetChar() {
+ return GetChar<false>();
+ }
+
+ void Advance(size_t bytes) {
+ TPositionBase::OnRangeConsumed(TBlockStream::Begin(), TBlockStream::Begin() + bytes);
+ TBlockStream::Advance(bytes);
+ }
+
+ size_t Length() const {
+ return TBlockStream::End() - TBlockStream::Begin();
+ }
+ };
+
+ template <class TBaseStream>
+ class TCodedStream
+ : public TBaseStream {
+ private:
+ static const int MaxVarintBytes = 10;
+ static const int MaxVarint32Bytes = 5;
+
+ const ui8* BeginByte() const {
+ return reinterpret_cast<const ui8*>(TBaseStream::Begin());
+ }
+
+ const ui8* EndByte() const {
+ return reinterpret_cast<const ui8*>(TBaseStream::End());
+ }
+
+ // Following functions is an adaptation Protobuf code from coded_stream.cc
+ bool ReadVarint32FromArray(ui32* value) {
+ // Fast path: We have enough bytes left in the buffer to guarantee that
+ // this read won't cross the end, so we can skip the checks.
+ const ui8* ptr = BeginByte();
+ ui32 b;
+ ui32 result;
+
+ b = *(ptr++);
+ result = (b & 0x7F);
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ result |= (b & 0x7F) << 7;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ result |= (b & 0x7F) << 14;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ result |= (b & 0x7F) << 21;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ result |= b << 28;
+ if (!(b & 0x80))
+ goto done;
+
+ // If the input is larger than 32 bits, we still need to read it all
+ // and discard the high-order bits.
+
+ for (int i = 0; i < MaxVarintBytes - MaxVarint32Bytes; i++) {
+ b = *(ptr++);
+ if (!(b & 0x80))
+ goto done;
+ }
+
+ // We have overrun the maximum size of a Varint (10 bytes). Assume
+ // the data is corrupt.
+ return false;
+
+ done:
+ TBaseStream::Advance(ptr - BeginByte());
+ *value = result;
+ return true;
+ }
+
+ bool ReadVarint32Fallback(ui32* value) {
+ if (BeginByte() + MaxVarint32Bytes <= EndByte() ||
+ // Optimization: If the Varint ends at exactly the end of the buffer,
+ // we can detect that and still use the fast path.
+ (BeginByte() < EndByte() && !(EndByte()[-1] & 0x80)))
+ {
+ return ReadVarint32FromArray(value);
+ } else {
+ // Really slow case: we will incur the cost of an extra function call here,
+ // but moving this out of line reduces the size of this function, which
+ // improves the common case. In micro benchmarks, this is worth about 10-15%
+ return ReadVarint32Slow(value);
+ }
+ }
+
+ bool ReadVarint32Slow(ui32* value) {
+ ui64 result;
+ // Directly invoke ReadVarint64Fallback, since we already tried to optimize
+ // for one-byte Varints.
+ if (ReadVarint64Fallback(&result)) {
+ *value = static_cast<ui32>(result);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ bool ReadVarint64Slow(ui64* value) {
+ // Slow path: This read might cross the end of the buffer, so we
+ // need to check and refresh the buffer if and when it does.
+
+ ui64 result = 0;
+ int count = 0;
+ ui32 b;
+
+ do {
+ if (count == MaxVarintBytes) {
+ return false;
+ }
+ while (BeginByte() == EndByte()) {
+ TBaseStream::Refresh();
+ }
+ b = *BeginByte();
+ result |= static_cast<ui64>(b & 0x7F) << (7 * count);
+ TBaseStream::Advance(1);
+ ++count;
+ } while (b & 0x80);
+
+ *value = result;
+ return true;
+ }
+
+ bool ReadVarint64Fallback(ui64* value) {
+ if (BeginByte() + MaxVarintBytes <= EndByte() ||
+ // Optimization: If the Varint ends at exactly the end of the buffer,
+ // we can detect that and still use the fast path.
+ (BeginByte() < EndByte() && !(EndByte()[-1] & 0x80)))
+ {
+ // Fast path: We have enough bytes left in the buffer to guarantee that
+ // this read won't cross the end, so we can skip the checks.
+
+ const ui8* ptr = BeginByte();
+ ui32 b;
+
+ // Splitting into 32-bit pieces gives better performance on 32-bit
+ // processors.
+ ui32 part0 = 0, part1 = 0, part2 = 0;
+
+ b = *(ptr++);
+ part0 = (b & 0x7F);
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part0 |= (b & 0x7F) << 7;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part0 |= (b & 0x7F) << 14;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part0 |= (b & 0x7F) << 21;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part1 = (b & 0x7F);
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part1 |= (b & 0x7F) << 7;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part1 |= (b & 0x7F) << 14;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part1 |= (b & 0x7F) << 21;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part2 = (b & 0x7F);
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part2 |= (b & 0x7F) << 7;
+ if (!(b & 0x80))
+ goto done;
+
+ // We have overrun the maximum size of a Varint (10 bytes). The data
+ // must be corrupt.
+ return false;
+
+ done:
+ TBaseStream::Advance(ptr - BeginByte());
+ *value = (static_cast<ui64>(part0)) |
+ (static_cast<ui64>(part1) << 28) |
+ (static_cast<ui64>(part2) << 56);
+ return true;
+ } else {
+ return ReadVarint64Slow(value);
+ }
+ }
+
+ public:
+ TCodedStream(const TBaseStream& baseStream)
+ : TBaseStream(baseStream)
+ {
+ }
+
+ bool ReadVarint64(ui64* value) {
+ if (BeginByte() < EndByte() && *BeginByte() < 0x80) {
+ *value = *BeginByte();
+ TBaseStream::Advance(1);
+ return true;
+ } else {
+ return ReadVarint64Fallback(value);
+ }
+ }
+
+ bool ReadVarint32(ui32* value) {
+ if (BeginByte() < EndByte() && *BeginByte() < 0x80) {
+ *value = *BeginByte();
+ TBaseStream::Advance(1);
+ return true;
+ } else {
+ return ReadVarint32Fallback(value);
+ }
+ }
+ };
+
+ enum ENumericResult {
+ Int64 = 0,
+ Uint64 = 1,
+ Double = 2
+ };
+
+ template <class TBlockStream, bool EnableLinePositionInfo>
+ class TLexerBase
+ : public TCodedStream<TCharStream<TBlockStream, TPositionInfo<EnableLinePositionInfo>>> {
+ private:
+ using TBaseStream = TCodedStream<TCharStream<TBlockStream, TPositionInfo<EnableLinePositionInfo>>>;
+ TVector<char> Buffer_;
+ TMaybe<ui64> MemoryLimit_;
+
+ void CheckMemoryLimit() {
+ if (MemoryLimit_ && Buffer_.capacity() > *MemoryLimit_) {
+ ythrow TYsonException()
+ << "Memory limit exceeded while parsing YSON stream: allocated "
+ << Buffer_.capacity() << ", limit " << (*MemoryLimit_);
+ }
+ }
+
+ public:
+ TLexerBase(const TBlockStream& blockStream, TMaybe<ui64> memoryLimit)
+ : TBaseStream(blockStream)
+ , MemoryLimit_(memoryLimit)
+ {
+ }
+
+ protected:
+ /// Lexer routines
+
+ template <bool AllowFinish>
+ ENumericResult ReadNumeric(TStringBuf* value) {
+ Buffer_.clear();
+ ENumericResult result = ENumericResult::Int64;
+ while (true) {
+ char ch = TBaseStream::template GetChar<AllowFinish>();
+ if (isdigit(ch) || ch == '+' || ch == '-') { // Seems like it can't be '+' or '-'
+ Buffer_.push_back(ch);
+ } else if (ch == '.' || ch == 'e' || ch == 'E') {
+ Buffer_.push_back(ch);
+ result = ENumericResult::Double;
+ } else if (ch == 'u') {
+ Buffer_.push_back(ch);
+ result = ENumericResult::Uint64;
+ } else if (isalpha(ch)) {
+ ythrow TYsonException() << "Unexpected '" << ch << "' in numeric literal";
+ } else {
+ break;
+ }
+ CheckMemoryLimit();
+ TBaseStream::Advance(1);
+ }
+
+ *value = TStringBuf(Buffer_.data(), Buffer_.size());
+ return result;
+ }
+
+ template <bool AllowFinish>
+ double ReadNanOrInf() {
+ static const TStringBuf nanString = "nan";
+ static const TStringBuf infString = "inf";
+ static const TStringBuf plusInfString = "+inf";
+ static const TStringBuf minusInfString = "-inf";
+
+ TStringBuf expectedString;
+ double expectedValue;
+ char ch = TBaseStream::template GetChar<AllowFinish>();
+ switch (ch) {
+ case '+':
+ expectedString = plusInfString;
+ expectedValue = std::numeric_limits<double>::infinity();
+ break;
+ case '-':
+ expectedString = minusInfString;
+ expectedValue = -std::numeric_limits<double>::infinity();
+ break;
+ case 'i':
+ expectedString = infString;
+ expectedValue = std::numeric_limits<double>::infinity();
+ break;
+ case 'n':
+ expectedString = nanString;
+ expectedValue = std::numeric_limits<double>::quiet_NaN();
+ break;
+ default:
+ ythrow TYsonException() << "Incorrect %-literal prefix: '" << ch << "'";
+ }
+
+ for (size_t i = 0; i < expectedString.size(); ++i) {
+ if (expectedString[i] != ch) {
+ ythrow TYsonException()
+ << "Incorrect %-literal prefix "
+ << "'" << expectedString.SubStr(0, i) << ch << "',"
+ << "expected " << expectedString;
+ }
+ TBaseStream::Advance(1);
+ ch = TBaseStream::template GetChar<AllowFinish>();
+ }
+
+ return expectedValue;
+ }
+
+ void ReadQuotedString(TStringBuf* value) {
+ Buffer_.clear();
+ while (true) {
+ if (TBaseStream::IsEmpty()) {
+ TBaseStream::Refresh();
+ }
+ char ch = *TBaseStream::Begin();
+ TBaseStream::Advance(1);
+ if (ch != '"') {
+ Buffer_.push_back(ch);
+ } else {
+ // We must count the number of '\' at the end of StringValue
+ // to check if it's not \"
+ int slashCount = 0;
+ int length = Buffer_.size();
+ while (slashCount < length && Buffer_[length - 1 - slashCount] == '\\') {
+ ++slashCount;
+ }
+ if (slashCount % 2 == 0) {
+ break;
+ } else {
+ Buffer_.push_back(ch);
+ }
+ }
+ CheckMemoryLimit();
+ }
+
+ auto unquotedValue = UnescapeC(Buffer_.data(), Buffer_.size());
+ Buffer_.clear();
+ Buffer_.insert(Buffer_.end(), unquotedValue.data(), unquotedValue.data() + unquotedValue.size());
+ CheckMemoryLimit();
+ *value = TStringBuf(Buffer_.data(), Buffer_.size());
+ }
+
+ template <bool AllowFinish>
+ void ReadUnquotedString(TStringBuf* value) {
+ Buffer_.clear();
+ while (true) {
+ char ch = TBaseStream::template GetChar<AllowFinish>();
+ if (isalpha(ch) || isdigit(ch) ||
+ ch == '_' || ch == '-' || ch == '%' || ch == '.') {
+ Buffer_.push_back(ch);
+ } else {
+ break;
+ }
+ CheckMemoryLimit();
+ TBaseStream::Advance(1);
+ }
+ *value = TStringBuf(Buffer_.data(), Buffer_.size());
+ }
+
+ void ReadUnquotedString(TStringBuf* value) {
+ return ReadUnquotedString<false>(value);
+ }
+
+ void ReadBinaryString(TStringBuf* value) {
+ ui32 ulength = 0;
+ if (!TBaseStream::ReadVarint32(&ulength)) {
+ ythrow TYsonException() << "Error parsing varint value";
+ }
+
+ i32 length = ZigZagDecode32(ulength);
+ if (length < 0) {
+ ythrow TYsonException() << "Negative binary string literal length " << length;
+ }
+
+ if (TBaseStream::Begin() + length <= TBaseStream::End()) {
+ *value = TStringBuf(TBaseStream::Begin(), length);
+ TBaseStream::Advance(length);
+ } else { // reading in Buffer
+ size_t needToRead = length;
+ Buffer_.clear();
+ while (needToRead) {
+ if (TBaseStream::IsEmpty()) {
+ TBaseStream::Refresh();
+ continue;
+ }
+ size_t readingBytes = Min(needToRead, TBaseStream::Length());
+
+ Buffer_.insert(Buffer_.end(), TBaseStream::Begin(), TBaseStream::Begin() + readingBytes);
+ CheckMemoryLimit();
+ needToRead -= readingBytes;
+ TBaseStream::Advance(readingBytes);
+ }
+ *value = TStringBuf(Buffer_.data(), Buffer_.size());
+ }
+ }
+
+ template <bool AllowFinish>
+ bool ReadBoolean() {
+ Buffer_.clear();
+
+ static TStringBuf trueString = "true";
+ static TStringBuf falseString = "false";
+
+ auto throwIncorrectBoolean = [&]() {
+ ythrow TYsonException() << "Incorrect boolean string " << TString(Buffer_.data(), Buffer_.size());
+ };
+
+ Buffer_.push_back(TBaseStream::template GetChar<AllowFinish>());
+ TBaseStream::Advance(1);
+ if (Buffer_[0] == trueString[0]) {
+ for (size_t i = 1; i < trueString.size(); ++i) {
+ Buffer_.push_back(TBaseStream::template GetChar<AllowFinish>());
+ TBaseStream::Advance(1);
+ if (Buffer_.back() != trueString[i]) {
+ throwIncorrectBoolean();
+ }
+ }
+ return true;
+ } else if (Buffer_[0] == falseString[0]) {
+ for (size_t i = 1; i < falseString.size(); ++i) {
+ Buffer_.push_back(TBaseStream::template GetChar<AllowFinish>());
+ TBaseStream::Advance(1);
+ if (Buffer_.back() != falseString[i]) {
+ throwIncorrectBoolean();
+ }
+ }
+ return false;
+ } else {
+ throwIncorrectBoolean();
+ }
+
+ Y_FAIL("unreachable");
+ ;
+ }
+
+ void ReadBinaryInt64(i64* result) {
+ ui64 uvalue;
+ if (!TBaseStream::ReadVarint64(&uvalue)) {
+ ythrow TYsonException() << "Error parsing varint value";
+ }
+ *result = ZigZagDecode64(uvalue);
+ }
+
+ void ReadBinaryUint64(ui64* result) {
+ ui64 uvalue;
+ if (!TBaseStream::ReadVarint64(&uvalue)) {
+ ythrow TYsonException() << "Error parsing varint value";
+ }
+ *result = uvalue;
+ }
+
+ void ReadBinaryDouble(double* value) {
+ size_t needToRead = sizeof(double);
+
+ while (needToRead != 0) {
+ if (TBaseStream::IsEmpty()) {
+ TBaseStream::Refresh();
+ continue;
+ }
+
+ size_t chunkSize = Min(needToRead, TBaseStream::Length());
+ if (chunkSize == 0) {
+ ythrow TYsonException() << "Error parsing binary double literal";
+ }
+ std::copy(
+ TBaseStream::Begin(),
+ TBaseStream::Begin() + chunkSize,
+ reinterpret_cast<char*>(value) + (sizeof(double) - needToRead));
+ needToRead -= chunkSize;
+ TBaseStream::Advance(chunkSize);
+ }
+ }
+
+ /// Helpers
+ void SkipCharToken(char symbol) {
+ char ch = SkipSpaceAndGetChar();
+ if (ch != symbol) {
+ ythrow TYsonException() << "Expected '" << symbol << "' but found '" << ch << "'";
+ }
+
+ TBaseStream::Advance(1);
+ }
+
+ static bool IsSpaceFast(char ch) {
+ static const ui8 lookupTable[] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ return lookupTable[static_cast<ui8>(ch)];
+ }
+
+ template <bool AllowFinish>
+ char SkipSpaceAndGetChar() {
+ if (!TBaseStream::IsEmpty()) {
+ char ch = *TBaseStream::Begin();
+ if (!IsSpaceFast(ch)) {
+ return ch;
+ }
+ }
+ return SkipSpaceAndGetCharFallback<AllowFinish>();
+ }
+
+ char SkipSpaceAndGetChar() {
+ return SkipSpaceAndGetChar<false>();
+ }
+
+ template <bool AllowFinish>
+ char SkipSpaceAndGetCharFallback() {
+ while (true) {
+ if (TBaseStream::IsEmpty()) {
+ if (TBaseStream::IsFinished()) {
+ return '\0';
+ }
+ TBaseStream::template Refresh<AllowFinish>();
+ continue;
+ }
+ if (!IsSpaceFast(*TBaseStream::Begin())) {
+ break;
+ }
+ TBaseStream::Advance(1);
+ }
+ return TBaseStream::template GetChar<AllowFinish>();
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TStringReader {
+ private:
+ const char* BeginPtr;
+ const char* EndPtr;
+
+ public:
+ TStringReader()
+ : BeginPtr(nullptr)
+ , EndPtr(nullptr)
+ {
+ }
+
+ TStringReader(const char* begin, const char* end)
+ : BeginPtr(begin)
+ , EndPtr(end)
+ {
+ }
+
+ const char* Begin() const {
+ return BeginPtr;
+ }
+
+ const char* End() const {
+ return EndPtr;
+ }
+
+ void RefreshBlock() {
+ Y_FAIL("unreachable");
+ }
+
+ void Advance(size_t bytes) {
+ BeginPtr += bytes;
+ }
+
+ bool IsFinished() const {
+ return true;
+ }
+
+ void SetBuffer(const char* begin, const char* end) {
+ BeginPtr = begin;
+ EndPtr = end;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TStreamReader {
+ public:
+ TStreamReader(
+ IInputStream* stream,
+ char* buffer,
+ size_t bufferSize)
+ : Stream(stream)
+ , Buffer(buffer)
+ , BufferSize(bufferSize)
+ {
+ BeginPtr = EndPtr = Buffer;
+ FinishFlag = false;
+ }
+
+ const char* Begin() const {
+ return BeginPtr;
+ }
+
+ const char* End() const {
+ return EndPtr;
+ }
+
+ void RefreshBlock() {
+ size_t bytes = Stream->Read(Buffer, BufferSize);
+ BeginPtr = Buffer;
+ EndPtr = Buffer + bytes;
+ FinishFlag = (bytes == 0);
+ }
+
+ void Advance(size_t bytes) {
+ BeginPtr += bytes;
+ }
+
+ bool IsFinished() const {
+ return FinishFlag;
+ }
+
+ private:
+ IInputStream* Stream;
+ char* Buffer;
+ size_t BufferSize;
+
+ const char* BeginPtr;
+ const char* EndPtr;
+ bool FinishFlag;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/format.h b/library/cpp/yson/format.h
new file mode 100644
index 0000000000..2ff6dc9f6e
--- /dev/null
+++ b/library/cpp/yson/format.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "token.h"
+
+namespace NYson {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ const ETokenType BeginListToken = LeftBracket;
+ const ETokenType EndListToken = RightBracket;
+
+ const ETokenType BeginMapToken = LeftBrace;
+ const ETokenType EndMapToken = RightBrace;
+
+ const ETokenType BeginAttributesToken = LeftAngle;
+ const ETokenType EndAttributesToken = RightAngle;
+
+ const ETokenType ListItemSeparatorToken = Semicolon;
+ const ETokenType KeyedItemSeparatorToken = Semicolon;
+ const ETokenType KeyValueSeparatorToken = Equals;
+
+ const ETokenType EntityToken = Hash;
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/json/json_writer.cpp b/library/cpp/yson/json/json_writer.cpp
new file mode 100644
index 0000000000..87481256ec
--- /dev/null
+++ b/library/cpp/yson/json/json_writer.cpp
@@ -0,0 +1,220 @@
+#include "json_writer.h"
+
+#include <library/cpp/json/json_writer.h>
+
+namespace NYT {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ static bool IsSpecialJsonKey(const TStringBuf& key) {
+ return key.size() > 0 && key[0] == '$';
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ TJsonWriter::TJsonWriter(
+ IOutputStream* output,
+ ::NYson::EYsonType type,
+ EJsonFormat format,
+ EJsonAttributesMode attributesMode,
+ ESerializedBoolFormat booleanFormat)
+ : TJsonWriter(
+ output,
+ NJson::TJsonWriterConfig{}.SetFormatOutput(format == JF_PRETTY),
+ type,
+ attributesMode,
+ booleanFormat
+ )
+ {}
+
+ TJsonWriter::TJsonWriter(
+ IOutputStream* output,
+ NJson::TJsonWriterConfig config,
+ ::NYson::EYsonType type,
+ EJsonAttributesMode attributesMode,
+ ESerializedBoolFormat booleanFormat)
+ : Output(output)
+ , Type(type)
+ , AttributesMode(attributesMode)
+ , BooleanFormat(booleanFormat)
+ , Depth(0)
+ {
+ if (Type == ::NYson::EYsonType::MapFragment) {
+ ythrow ::NYson::TYsonException() << ("Map fragments are not supported by Json");
+ }
+
+ UnderlyingJsonWriter.Reset(new NJson::TJsonWriter(
+ output,
+ config));
+ JsonWriter = UnderlyingJsonWriter.Get();
+ HasAttributes = false;
+ InAttributesBalance = 0;
+ }
+
+ void TJsonWriter::EnterNode() {
+ if (AttributesMode == JAM_NEVER) {
+ HasAttributes = false;
+ } else if (AttributesMode == JAM_ON_DEMAND) {
+ // Do nothing
+ } else if (AttributesMode == JAM_ALWAYS) {
+ if (!HasAttributes) {
+ JsonWriter->OpenMap();
+ JsonWriter->Write("$attributes");
+ JsonWriter->OpenMap();
+ JsonWriter->CloseMap();
+ }
+ HasAttributes = true;
+ }
+ HasUnfoldedStructureStack.push_back(HasAttributes);
+
+ if (HasAttributes) {
+ JsonWriter->Write("$value");
+ HasAttributes = false;
+ }
+
+ Depth += 1;
+ }
+
+ void TJsonWriter::LeaveNode() {
+ Y_ASSERT(!HasUnfoldedStructureStack.empty());
+ if (HasUnfoldedStructureStack.back()) {
+ // Close map of the {$attributes, $value}
+ JsonWriter->CloseMap();
+ }
+ HasUnfoldedStructureStack.pop_back();
+
+ Depth -= 1;
+
+ if (Depth == 0 && Type == ::NYson::EYsonType::ListFragment && InAttributesBalance == 0) {
+ JsonWriter->Flush();
+ Output->Write("\n");
+ }
+ }
+
+ bool TJsonWriter::IsWriteAllowed() {
+ if (AttributesMode == JAM_NEVER) {
+ return InAttributesBalance == 0;
+ }
+ return true;
+ }
+
+ void TJsonWriter::OnStringScalar(TStringBuf value) {
+ if (IsWriteAllowed()) {
+ EnterNode();
+ WriteStringScalar(value);
+ LeaveNode();
+ }
+ }
+
+ void TJsonWriter::OnInt64Scalar(i64 value) {
+ if (IsWriteAllowed()) {
+ EnterNode();
+ JsonWriter->Write(value);
+ LeaveNode();
+ }
+ }
+
+ void TJsonWriter::OnUint64Scalar(ui64 value) {
+ if (IsWriteAllowed()) {
+ EnterNode();
+ JsonWriter->Write(value);
+ LeaveNode();
+ }
+ }
+
+ void TJsonWriter::OnDoubleScalar(double value) {
+ if (IsWriteAllowed()) {
+ EnterNode();
+ JsonWriter->Write(value);
+ LeaveNode();
+ }
+ }
+
+ void TJsonWriter::OnBooleanScalar(bool value) {
+ if (IsWriteAllowed()) {
+ if (BooleanFormat == SBF_STRING) {
+ OnStringScalar(value ? "true" : "false");
+ } else {
+ EnterNode();
+ JsonWriter->Write(value);
+ LeaveNode();
+ }
+ }
+ }
+
+ void TJsonWriter::OnEntity() {
+ if (IsWriteAllowed()) {
+ EnterNode();
+ JsonWriter->WriteNull();
+ LeaveNode();
+ }
+ }
+
+ void TJsonWriter::OnBeginList() {
+ if (IsWriteAllowed()) {
+ EnterNode();
+ JsonWriter->OpenArray();
+ }
+ }
+
+ void TJsonWriter::OnListItem() {
+ }
+
+ void TJsonWriter::OnEndList() {
+ if (IsWriteAllowed()) {
+ JsonWriter->CloseArray();
+ LeaveNode();
+ }
+ }
+
+ void TJsonWriter::OnBeginMap() {
+ if (IsWriteAllowed()) {
+ EnterNode();
+ JsonWriter->OpenMap();
+ }
+ }
+
+ void TJsonWriter::OnKeyedItem(TStringBuf name) {
+ if (IsWriteAllowed()) {
+ if (IsSpecialJsonKey(name)) {
+ WriteStringScalar(TString("$") + name);
+ } else {
+ WriteStringScalar(name);
+ }
+ }
+ }
+
+ void TJsonWriter::OnEndMap() {
+ if (IsWriteAllowed()) {
+ JsonWriter->CloseMap();
+ LeaveNode();
+ }
+ }
+
+ void TJsonWriter::OnBeginAttributes() {
+ InAttributesBalance += 1;
+ if (AttributesMode != JAM_NEVER) {
+ JsonWriter->OpenMap();
+ JsonWriter->Write("$attributes");
+ JsonWriter->OpenMap();
+ }
+ }
+
+ void TJsonWriter::OnEndAttributes() {
+ InAttributesBalance -= 1;
+ if (AttributesMode != JAM_NEVER) {
+ HasAttributes = true;
+ JsonWriter->CloseMap();
+ }
+ }
+
+ void TJsonWriter::WriteStringScalar(const TStringBuf& value) {
+ JsonWriter->Write(value);
+ }
+
+ void TJsonWriter::Flush() {
+ JsonWriter->Flush();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+}
diff --git a/library/cpp/yson/json/json_writer.h b/library/cpp/yson/json/json_writer.h
new file mode 100644
index 0000000000..d84ac0de53
--- /dev/null
+++ b/library/cpp/yson/json/json_writer.h
@@ -0,0 +1,89 @@
+#pragma once
+
+#include <library/cpp/yson/public.h>
+#include <library/cpp/yson/consumer.h>
+
+#include <library/cpp/json/json_writer.h>
+
+#include <util/generic/vector.h>
+
+namespace NYT {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ enum EJsonFormat {
+ JF_TEXT,
+ JF_PRETTY
+ };
+
+ enum EJsonAttributesMode {
+ JAM_NEVER,
+ JAM_ON_DEMAND,
+ JAM_ALWAYS
+ };
+
+ enum ESerializedBoolFormat {
+ SBF_BOOLEAN,
+ SBF_STRING
+ };
+
+ class TJsonWriter
+ : public ::NYson::TYsonConsumerBase {
+ public:
+ TJsonWriter(
+ IOutputStream* output,
+ ::NYson::EYsonType type = ::NYson::EYsonType::Node,
+ EJsonFormat format = JF_TEXT,
+ EJsonAttributesMode attributesMode = JAM_ON_DEMAND,
+ ESerializedBoolFormat booleanFormat = SBF_STRING);
+
+ TJsonWriter(
+ IOutputStream* output,
+ NJson::TJsonWriterConfig config,
+ ::NYson::EYsonType type = ::NYson::EYsonType::Node,
+ EJsonAttributesMode attributesMode = JAM_ON_DEMAND,
+ ESerializedBoolFormat booleanFormat = SBF_STRING);
+
+ void Flush();
+
+ void OnStringScalar(TStringBuf value) override;
+ void OnInt64Scalar(i64 value) override;
+ void OnUint64Scalar(ui64 value) override;
+ void OnDoubleScalar(double value) override;
+ void OnBooleanScalar(bool value) override;
+
+ void OnEntity() override;
+
+ void OnBeginList() override;
+ void OnListItem() override;
+ void OnEndList() override;
+
+ void OnBeginMap() override;
+ void OnKeyedItem(TStringBuf key) override;
+ void OnEndMap() override;
+
+ void OnBeginAttributes() override;
+ void OnEndAttributes() override;
+
+ private:
+ THolder<NJson::TJsonWriter> UnderlyingJsonWriter;
+ NJson::TJsonWriter* JsonWriter;
+ IOutputStream* Output;
+ ::NYson::EYsonType Type;
+ EJsonAttributesMode AttributesMode;
+ ESerializedBoolFormat BooleanFormat;
+
+ void WriteStringScalar(const TStringBuf& value);
+
+ void EnterNode();
+ void LeaveNode();
+ bool IsWriteAllowed();
+
+ TVector<bool> HasUnfoldedStructureStack;
+ int InAttributesBalance;
+ bool HasAttributes;
+ int Depth;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+}
diff --git a/library/cpp/yson/json/ya.make b/library/cpp/yson/json/ya.make
new file mode 100644
index 0000000000..625a6b231e
--- /dev/null
+++ b/library/cpp/yson/json/ya.make
@@ -0,0 +1,17 @@
+LIBRARY()
+
+OWNER(
+ ermolovd
+ g:yt
+)
+
+SRCS(
+ json_writer.cpp
+ yson2json_adapter.cpp
+)
+
+PEERDIR(
+ library/cpp/json
+)
+
+END()
diff --git a/library/cpp/yson/json/yson2json_adapter.cpp b/library/cpp/yson/json/yson2json_adapter.cpp
new file mode 100644
index 0000000000..b5e7c49d4d
--- /dev/null
+++ b/library/cpp/yson/json/yson2json_adapter.cpp
@@ -0,0 +1,82 @@
+#include "yson2json_adapter.h"
+
+namespace NYT {
+ TYson2JsonCallbacksAdapter::TYson2JsonCallbacksAdapter(::NYson::TYsonConsumerBase* impl, bool throwException)
+ : NJson::TJsonCallbacks(throwException)
+ , Impl_(impl)
+ {
+ }
+
+ bool TYson2JsonCallbacksAdapter::OnNull() {
+ WrapIfListItem();
+ Impl_->OnEntity();
+ return true;
+ }
+
+ bool TYson2JsonCallbacksAdapter::OnBoolean(bool val) {
+ WrapIfListItem();
+ Impl_->OnBooleanScalar(val);
+ return true;
+ }
+
+ bool TYson2JsonCallbacksAdapter::OnInteger(long long val) {
+ WrapIfListItem();
+ Impl_->OnInt64Scalar(val);
+ return true;
+ }
+
+ bool TYson2JsonCallbacksAdapter::OnUInteger(unsigned long long val) {
+ WrapIfListItem();
+ Impl_->OnUint64Scalar(val);
+ return true;
+ }
+
+ bool TYson2JsonCallbacksAdapter::OnString(const TStringBuf& val) {
+ WrapIfListItem();
+ Impl_->OnStringScalar(val);
+ return true;
+ }
+
+ bool TYson2JsonCallbacksAdapter::OnDouble(double val) {
+ WrapIfListItem();
+ Impl_->OnDoubleScalar(val);
+ return true;
+ }
+
+ bool TYson2JsonCallbacksAdapter::OnOpenArray() {
+ WrapIfListItem();
+ State_.ContextStack.push(true);
+ Impl_->OnBeginList();
+ return true;
+ }
+
+ bool TYson2JsonCallbacksAdapter::OnCloseArray() {
+ State_.ContextStack.pop();
+ Impl_->OnEndList();
+ return true;
+ }
+
+ bool TYson2JsonCallbacksAdapter::OnOpenMap() {
+ WrapIfListItem();
+ State_.ContextStack.push(false);
+ Impl_->OnBeginMap();
+ return true;
+ }
+
+ bool TYson2JsonCallbacksAdapter::OnCloseMap() {
+ State_.ContextStack.pop();
+ Impl_->OnEndMap();
+ return true;
+ }
+
+ bool TYson2JsonCallbacksAdapter::OnMapKey(const TStringBuf& val) {
+ Impl_->OnKeyedItem(val);
+ return true;
+ }
+
+ void TYson2JsonCallbacksAdapter::WrapIfListItem() {
+ if (!State_.ContextStack.empty() && State_.ContextStack.top()) {
+ Impl_->OnListItem();
+ }
+ }
+}
diff --git a/library/cpp/yson/json/yson2json_adapter.h b/library/cpp/yson/json/yson2json_adapter.h
new file mode 100644
index 0000000000..da1bf5ba70
--- /dev/null
+++ b/library/cpp/yson/json/yson2json_adapter.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <library/cpp/yson/consumer.h>
+
+#include <library/cpp/json/json_reader.h>
+
+#include <util/generic/stack.h>
+
+namespace NYT {
+ class TYson2JsonCallbacksAdapter
+ : public NJson::TJsonCallbacks {
+ public:
+ class TState {
+ private:
+ // Stores current context stack
+ // If true - we are in a list
+ // If false - we are in a map
+ TStack<bool> ContextStack;
+
+ friend class TYson2JsonCallbacksAdapter;
+ };
+
+ public:
+ TYson2JsonCallbacksAdapter(::NYson::TYsonConsumerBase* impl, bool throwException = false);
+
+ bool OnNull() override;
+ bool OnBoolean(bool val) override;
+ bool OnInteger(long long val) override;
+ bool OnUInteger(unsigned long long val) override;
+ bool OnString(const TStringBuf& val) override;
+ bool OnDouble(double val) override;
+ bool OnOpenArray() override;
+ bool OnCloseArray() override;
+ bool OnOpenMap() override;
+ bool OnCloseMap() override;
+ bool OnMapKey(const TStringBuf& val) override;
+
+ TState State() const {
+ return State_;
+ }
+
+ void Reset(const TState& state) {
+ State_ = state;
+ }
+
+ private:
+ void WrapIfListItem();
+
+ private:
+ ::NYson::TYsonConsumerBase* Impl_;
+ TState State_;
+ };
+}
diff --git a/library/cpp/yson/lexer.cpp b/library/cpp/yson/lexer.cpp
new file mode 100644
index 0000000000..5eae94273b
--- /dev/null
+++ b/library/cpp/yson/lexer.cpp
@@ -0,0 +1,43 @@
+#include "lexer.h"
+#include "lexer_detail.h"
+#include "token.h"
+
+#include <util/generic/ptr.h>
+
+namespace NYson {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TStatelessLexer::TImpl {
+ private:
+ THolder<TStatelessYsonLexerImplBase> Impl;
+
+ public:
+ TImpl(bool enableLinePositionInfo = false)
+ : Impl(enableLinePositionInfo
+ ? static_cast<TStatelessYsonLexerImplBase*>(new TStatelesYsonLexerImpl<true>())
+ : static_cast<TStatelessYsonLexerImplBase*>(new TStatelesYsonLexerImpl<false>()))
+ {
+ }
+
+ size_t GetToken(const TStringBuf& data, TToken* token) {
+ return Impl->GetToken(data, token);
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ TStatelessLexer::TStatelessLexer()
+ : Impl(new TImpl())
+ {
+ }
+
+ TStatelessLexer::~TStatelessLexer() {
+ }
+
+ size_t TStatelessLexer::GetToken(const TStringBuf& data, TToken* token) {
+ return Impl->GetToken(data, token);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/lexer.h b/library/cpp/yson/lexer.h
new file mode 100644
index 0000000000..d9d701874d
--- /dev/null
+++ b/library/cpp/yson/lexer.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "public.h"
+#include "token.h"
+
+#include <util/generic/ptr.h>
+
+namespace NYson {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TStatelessLexer {
+ public:
+ TStatelessLexer();
+
+ ~TStatelessLexer();
+
+ size_t GetToken(const TStringBuf& data, TToken* token);
+
+ private:
+ class TImpl;
+ THolder<TImpl> Impl;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/lexer_detail.h b/library/cpp/yson/lexer_detail.h
new file mode 100644
index 0000000000..0bba30acdd
--- /dev/null
+++ b/library/cpp/yson/lexer_detail.h
@@ -0,0 +1,296 @@
+#pragma once
+
+#include "detail.h"
+#include "token.h"
+
+namespace NYson {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ namespace NDetail {
+ /*! \internal */
+ ////////////////////////////////////////////////////////////////////////////////
+
+ // EReadStartCase tree representation:
+ // Root = xb
+ // BinaryStringOrOtherSpecialToken = x0b
+ // BinaryString = 00b
+ // OtherSpecialToken = 10b
+ // Other = x1b
+ // BinaryScalar = xx01b
+ // BinaryInt64 = 0001b
+ // BinaryDouble = 0101b
+ // BinaryFalse = 1001b
+ // BinaryTrue = 1101b
+ // Other = xxx11b
+ // Quote = 00011b
+ // DigitOrMinus = 00111b
+ // String = 01011b
+ // Space = 01111b
+ // Plus = 10011b
+ // None = 10111b
+ // Percent = 11011b
+
+ enum EReadStartCase : unsigned {
+ BinaryString = 0, // = 00b
+ OtherSpecialToken = 2, // = 10b
+
+ BinaryInt64 = 1, // = 001b
+ BinaryDouble = 5, // = 101b
+ BinaryFalse = 9, // = 1001b
+ BinaryTrue = 13, // = 1101b
+ BinaryUint64 = 17, // = 10001b
+
+ Quote = 3, // = 00011b
+ DigitOrMinus = 7, // = 00111b
+ String = 11, // = 01011b
+ Space = 15, // = 01111b
+ Plus = 19, // = 10011b
+ None = 23, // = 10111b
+ Percent = 27 // = 11011b
+ };
+
+ template <class TBlockStream, bool EnableLinePositionInfo>
+ class TLexer
+ : public TLexerBase<TBlockStream, EnableLinePositionInfo> {
+ private:
+ using TBase = TLexerBase<TBlockStream, EnableLinePositionInfo>;
+
+ static EReadStartCase GetStartState(char ch) {
+#define NN EReadStartCase::None
+#define BS EReadStartCase::BinaryString
+#define BI EReadStartCase::BinaryInt64
+#define BD EReadStartCase::BinaryDouble
+#define BF EReadStartCase::BinaryFalse
+#define BT EReadStartCase::BinaryTrue
+#define BU EReadStartCase::BinaryUint64
+#define SP NN // EReadStartCase::Space
+#define DM EReadStartCase::DigitOrMinus
+#define ST EReadStartCase::String
+#define PL EReadStartCase::Plus
+#define QU EReadStartCase::Quote
+#define PC EReadStartCase::Percent
+#define TT(name) (EReadStartCase(static_cast<ui8>(ETokenType::name) << 2) | EReadStartCase::OtherSpecialToken)
+
+ static const ui8 lookupTable[] =
+ {
+ NN, BS, BI, BD, BF, BT, BU, NN, NN, SP, SP, SP, SP, SP, NN, NN,
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN,
+
+ // 32
+ SP, // ' '
+ NN, // '!'
+ QU, // '"'
+ TT(Hash), // '#'
+ NN, // '$'
+ PC, // '%'
+ NN, // '&'
+ NN, // "'"
+ TT(LeftParenthesis), // '('
+ TT(RightParenthesis), // ')'
+ NN, // '*'
+ PL, // '+'
+ TT(Comma), // ','
+ DM, // '-'
+ NN, // '.'
+ NN, // '/'
+
+ // 48
+ DM, DM, DM, DM, DM, DM, DM, DM, DM, DM, // '0' - '9'
+ TT(Colon), // ':'
+ TT(Semicolon), // ';'
+ TT(LeftAngle), // '<'
+ TT(Equals), // '='
+ TT(RightAngle), // '>'
+ NN, // '?'
+
+ // 64
+ NN, // '@'
+ ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, // 'A' - 'M'
+ ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, // 'N' - 'Z'
+ TT(LeftBracket), // '['
+ NN, // '\'
+ TT(RightBracket), // ']'
+ NN, // '^'
+ ST, // '_'
+
+ // 96
+ NN, // '`'
+
+ ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, // 'a' - 'm'
+ ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, // 'n' - 'z'
+ TT(LeftBrace), // '{'
+ NN, // '|'
+ TT(RightBrace), // '}'
+ NN, // '~'
+ NN, // '^?' non-printable
+ // 128
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN,
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN,
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN,
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN,
+
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN,
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN,
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN,
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN};
+
+#undef NN
+#undef BS
+#undef BI
+#undef BD
+#undef SP
+#undef DM
+#undef ST
+#undef PL
+#undef QU
+#undef TT
+ return static_cast<EReadStartCase>(lookupTable[static_cast<ui8>(ch)]);
+ }
+
+ public:
+ TLexer(const TBlockStream& blockStream, TMaybe<ui64> memoryLimit)
+ : TBase(blockStream, memoryLimit)
+ {
+ }
+
+ void GetToken(TToken* token) {
+ char ch1 = TBase::SkipSpaceAndGetChar();
+ auto state = GetStartState(ch1);
+ auto stateBits = static_cast<unsigned>(state);
+
+ if (ch1 == '\0') {
+ *token = TToken::EndOfStream;
+ return;
+ }
+
+ if (stateBits & 1) { // Other = x1b
+ if (stateBits & 1 << 1) { // Other = xxx11b
+ if (state == EReadStartCase::Quote) {
+ TStringBuf value;
+ TBase::Advance(1);
+ TBase::ReadQuotedString(&value);
+ *token = TToken(value);
+ } else if (state == EReadStartCase::DigitOrMinus) {
+ ReadNumeric<true>(token);
+ } else if (state == EReadStartCase::Plus) {
+ TBase::Advance(1);
+
+ char ch2 = TBase::template GetChar<true>();
+
+ if (!isdigit(ch2)) {
+ *token = TToken(ETokenType::Plus);
+ } else {
+ ReadNumeric<true>(token);
+ }
+ } else if (state == EReadStartCase::String) {
+ TStringBuf value;
+ TBase::template ReadUnquotedString<true>(&value);
+ *token = TToken(value);
+ } else if (state == EReadStartCase::Percent) {
+ TBase::Advance(1);
+ char ch3 = TBase::template GetChar<true>();
+ if (ch3 == 't' || ch3 == 'f') {
+ *token = TToken(TBase::template ReadBoolean<true>());
+ } else {
+ *token = TToken(TBase::template ReadNanOrInf<true>());
+ }
+ } else { // None
+ Y_ASSERT(state == EReadStartCase::None);
+ ythrow TYsonException() << "Unexpected " << ch1;
+ }
+ } else { // BinaryScalar = x01b
+ TBase::Advance(1);
+ if (state == EReadStartCase::BinaryDouble) {
+ double value;
+ TBase::ReadBinaryDouble(&value);
+ *token = TToken(value);
+ } else if (state == EReadStartCase::BinaryInt64) {
+ i64 value;
+ TBase::ReadBinaryInt64(&value);
+ *token = TToken(value);
+ } else if (state == EReadStartCase::BinaryUint64) {
+ ui64 value;
+ TBase::ReadBinaryUint64(&value);
+ *token = TToken(value);
+ } else if (state == EReadStartCase::BinaryFalse) {
+ *token = TToken(false);
+ } else if (state == EReadStartCase::BinaryTrue) {
+ *token = TToken(true);
+ } else {
+ Y_FAIL("unreachable");
+ }
+ }
+ } else { // BinaryStringOrOtherSpecialToken = x0b
+ TBase::Advance(1);
+ if (stateBits & 1 << 1) { // OtherSpecialToken = 10b
+ Y_ASSERT((stateBits & 3) == static_cast<unsigned>(EReadStartCase::OtherSpecialToken));
+ *token = TToken(ETokenType(stateBits >> 2));
+ } else { // BinaryString = 00b
+ Y_ASSERT((stateBits & 3) == static_cast<unsigned>(EReadStartCase::BinaryString));
+ TStringBuf value;
+ TBase::ReadBinaryString(&value);
+ *token = TToken(value);
+ }
+ }
+ }
+
+ template <bool AllowFinish>
+ void ReadNumeric(TToken* token) {
+ TStringBuf valueBuffer;
+ ENumericResult numericResult = TBase::template ReadNumeric<AllowFinish>(&valueBuffer);
+
+ if (numericResult == ENumericResult::Double) {
+ try {
+ *token = TToken(FromString<double>(valueBuffer));
+ } catch (yexception&) {
+ ythrow TYsonException() << "Error parsing double literal " << valueBuffer;
+ }
+ } else if (numericResult == ENumericResult::Int64) {
+ try {
+ *token = TToken(FromString<i64>(valueBuffer));
+ } catch (yexception&) {
+ ythrow TYsonException() << "Error parsing int64 literal " << valueBuffer;
+ }
+ } else if (numericResult == ENumericResult::Uint64) {
+ try {
+ *token = TToken(FromString<ui64>(valueBuffer.SubStr(0, valueBuffer.size() - 1)));
+ } catch (yexception&) {
+ ythrow TYsonException() << "Error parsing uint64 literal " << valueBuffer;
+ }
+ }
+ }
+ };
+ ////////////////////////////////////////////////////////////////////////////////
+ /*! \endinternal */
+ }
+
+ class TStatelessYsonLexerImplBase {
+ public:
+ virtual size_t GetToken(const TStringBuf& data, TToken* token) = 0;
+
+ virtual ~TStatelessYsonLexerImplBase() {
+ }
+ };
+
+ template <bool EnableLinePositionInfo>
+ class TStatelesYsonLexerImpl: public TStatelessYsonLexerImplBase {
+ private:
+ using TLexer = NDetail::TLexer<TStringReader, EnableLinePositionInfo>;
+ TLexer Lexer;
+
+ public:
+ TStatelesYsonLexerImpl()
+ : Lexer(TStringReader(), Nothing())
+ {
+ }
+
+ size_t GetToken(const TStringBuf& data, TToken* token) override {
+ Lexer.SetBuffer(data.begin(), data.end());
+ Lexer.GetToken(token);
+ return Lexer.Begin() - data.begin();
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/node/node.cpp b/library/cpp/yson/node/node.cpp
new file mode 100644
index 0000000000..b39e070718
--- /dev/null
+++ b/library/cpp/yson/node/node.cpp
@@ -0,0 +1,915 @@
+#include "node.h"
+
+#include "node_io.h"
+
+#include <library/cpp/yson/writer.h>
+
+#include <util/generic/overloaded.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool TNode::TNull::operator==(const TNull&) const {
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool TNode::TUndefined::operator==(const TUndefined&) const {
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace NNodeCmp {
+
+bool IsComparableType(const TNode::EType type) {
+ switch (type) {
+ case TNode::String:
+ case TNode::Int64:
+ case TNode::Uint64:
+ case TNode::Double:
+ case TNode::Bool:
+ case TNode::Null:
+ case TNode::Undefined:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool operator<(const TNode& lhs, const TNode& rhs)
+{
+ if (!lhs.GetAttributes().Empty() || !rhs.GetAttributes().Empty()) {
+ ythrow TNode::TTypeError() << "Unsupported attributes comparison";
+ }
+
+ if (!IsComparableType(lhs.GetType()) || !IsComparableType(rhs.GetType())) {
+ ythrow TNode::TTypeError() << "Unsupported types for comparison: " << lhs.GetType() << " with " << rhs.GetType();
+ }
+
+ if (lhs.GetType() != rhs.GetType()) {
+ return lhs.GetType() < rhs.GetType();
+ }
+
+ switch (lhs.GetType()) {
+ case TNode::String:
+ return lhs.AsString() < rhs.AsString();
+ case TNode::Int64:
+ return lhs.AsInt64() < rhs.AsInt64();
+ case TNode::Uint64:
+ return lhs.AsUint64() < rhs.AsUint64();
+ case TNode::Double:
+ return lhs.AsDouble() < rhs.AsDouble();
+ case TNode::Bool:
+ return lhs.AsBool() < rhs.AsBool();
+ case TNode::Null:
+ case TNode::Undefined:
+ return false;
+ default:
+ Y_FAIL("Unexpected type: %d", lhs.GetType());
+ }
+}
+
+bool operator>(const TNode& lhs, const TNode& rhs)
+{
+ return rhs < lhs;
+}
+
+bool operator<=(const TNode& lhs, const TNode& rhs)
+{
+ return !(lhs > rhs);
+}
+
+bool operator>=(const TNode& lhs, const TNode& rhs)
+{
+ return !(lhs < rhs);
+}
+
+} // namespace NNodeCmp
+
+////////////////////////////////////////////////////////////////////////////////
+
+TNode::TNode()
+ : Value_(TUndefined{})
+{ }
+
+TNode::TNode(const char* s)
+ : Value_(TString(s))
+{ }
+
+TNode::TNode(TStringBuf s)
+ : Value_(TString(s))
+{ }
+
+TNode::TNode(std::string_view s)
+ : Value_(TString(s))
+{ }
+
+TNode::TNode(const std::string& s)
+ : Value_(TString(s))
+{ }
+
+TNode::TNode(TString s)
+ : Value_(std::move(s))
+{ }
+
+TNode::TNode(int i)
+ : Value_(static_cast<i64>(i))
+{ }
+
+
+TNode::TNode(unsigned int ui)
+ : Value_(static_cast<ui64>(ui))
+{ }
+
+TNode::TNode(long i)
+ : Value_(static_cast<i64>(i))
+{ }
+
+TNode::TNode(unsigned long ui)
+ : Value_(static_cast<ui64>(ui))
+{ }
+
+TNode::TNode(long long i)
+ : Value_(static_cast<i64>(i))
+{ }
+
+TNode::TNode(unsigned long long ui)
+ : Value_(static_cast<ui64>(ui))
+{ }
+
+TNode::TNode(double d)
+ : Value_(d)
+{ }
+
+TNode::TNode(bool b)
+ : Value_(b)
+{ }
+
+TNode::TNode(TMapType map)
+ : Value_(std::move(map))
+{ }
+
+TNode::TNode(const TNode& rhs)
+ : TNode()
+{
+ if (rhs.Attributes_) {
+ CreateAttributes();
+ *Attributes_ = *rhs.Attributes_;
+ }
+ Value_ = rhs.Value_;
+}
+
+TNode& TNode::operator=(const TNode& rhs)
+{
+ if (this != &rhs) {
+ TNode tmp = rhs;
+ Move(std::move(tmp));
+ }
+ return *this;
+}
+
+TNode::TNode(TNode&& rhs) noexcept
+ : TNode()
+{
+ Move(std::move(rhs));
+}
+
+TNode& TNode::operator=(TNode&& rhs) noexcept
+{
+ if (this != &rhs) {
+ TNode tmp = std::move(rhs);
+ Move(std::move(tmp));
+ }
+ return *this;
+}
+
+TNode::~TNode() = default;
+
+void TNode::Clear()
+{
+ ClearAttributes();
+ Value_ = TUndefined();
+}
+
+bool TNode::IsString() const
+{
+ return std::holds_alternative<TString>(Value_);
+}
+
+bool TNode::IsInt64() const
+{
+ return std::holds_alternative<i64>(Value_);
+}
+
+bool TNode::IsUint64() const
+{
+ return std::holds_alternative<ui64>(Value_);
+}
+
+bool TNode::IsDouble() const
+{
+ return std::holds_alternative<double>(Value_);
+}
+
+bool TNode::IsBool() const
+{
+ return std::holds_alternative<bool>(Value_);
+}
+
+bool TNode::IsList() const
+{
+ return std::holds_alternative<TListType>(Value_);
+}
+
+bool TNode::IsMap() const
+{
+ return std::holds_alternative<TMapType>(Value_);
+}
+
+bool TNode::IsEntity() const
+{
+ return IsNull();
+}
+
+bool TNode::IsNull() const
+{
+ return std::holds_alternative<TNull>(Value_);
+}
+
+bool TNode::IsUndefined() const
+{
+ return std::holds_alternative<TUndefined>(Value_);
+}
+
+bool TNode::HasValue() const
+{
+ return !IsNull() && !IsUndefined();
+}
+
+bool TNode::Empty() const
+{
+ switch (GetType()) {
+ case String:
+ return std::get<TString>(Value_).empty();
+ case List:
+ return std::get<TListType>(Value_).empty();
+ case Map:
+ return std::get<TMapType>(Value_).empty();
+ default:
+ ythrow TTypeError() << "Empty() called for type " << GetType();
+ }
+}
+
+size_t TNode::Size() const
+{
+ switch (GetType()) {
+ case String:
+ return std::get<TString>(Value_).size();
+ case List:
+ return std::get<TListType>(Value_).size();
+ case Map:
+ return std::get<TMapType>(Value_).size();
+ default:
+ ythrow TTypeError() << "Size() called for type " << GetType();
+ }
+}
+
+TNode::EType TNode::GetType() const
+{
+ return std::visit(TOverloaded{
+ [](const TUndefined&) { return Undefined; },
+ [](const TString&) { return String; },
+ [](i64) { return Int64; },
+ [](ui64) { return Uint64; },
+ [](double) { return Double; },
+ [](bool) { return Bool; },
+ [](const TListType&) { return List; },
+ [](const TMapType&) { return Map; },
+ [](const TNull&) { return Null; }
+ }, Value_);
+}
+
+const TString& TNode::AsString() const
+{
+ CheckType(String);
+ return std::get<TString>(Value_);
+}
+
+i64 TNode::AsInt64() const
+{
+ CheckType(Int64);
+ return std::get<i64>(Value_);
+}
+
+ui64 TNode::AsUint64() const
+{
+ CheckType(Uint64);
+ return std::get<ui64>(Value_);
+}
+
+double TNode::AsDouble() const
+{
+ CheckType(Double);
+ return std::get<double>(Value_);
+}
+
+bool TNode::AsBool() const
+{
+ CheckType(Bool);
+ return std::get<bool>(Value_);
+}
+
+const TNode::TListType& TNode::AsList() const
+{
+ CheckType(List);
+ return std::get<TListType>(Value_);
+}
+
+const TNode::TMapType& TNode::AsMap() const
+{
+ CheckType(Map);
+ return std::get<TMapType>(Value_);
+}
+
+TNode::TListType& TNode::AsList()
+{
+ CheckType(List);
+ return std::get<TListType>(Value_);
+}
+
+TNode::TMapType& TNode::AsMap()
+{
+ CheckType(Map);
+ return std::get<TMapType>(Value_);
+}
+
+const TString& TNode::UncheckedAsString() const noexcept
+{
+ return std::get<TString>(Value_);
+}
+
+i64 TNode::UncheckedAsInt64() const noexcept
+{
+ return std::get<i64>(Value_);
+}
+
+ui64 TNode::UncheckedAsUint64() const noexcept
+{
+ return std::get<ui64>(Value_);
+}
+
+double TNode::UncheckedAsDouble() const noexcept
+{
+ return std::get<double>(Value_);
+}
+
+bool TNode::UncheckedAsBool() const noexcept
+{
+ return std::get<bool>(Value_);
+}
+
+const TNode::TListType& TNode::UncheckedAsList() const noexcept
+{
+ return std::get<TListType>(Value_);
+}
+
+const TNode::TMapType& TNode::UncheckedAsMap() const noexcept
+{
+ return std::get<TMapType>(Value_);
+}
+
+TNode::TListType& TNode::UncheckedAsList() noexcept
+{
+ return std::get<TListType>(Value_);
+}
+
+TNode::TMapType& TNode::UncheckedAsMap() noexcept
+{
+ return std::get<TMapType>(Value_);
+}
+
+TNode TNode::CreateList()
+{
+ TNode node;
+ node.Value_ = TListType{};
+ return node;
+}
+
+TNode TNode::CreateList(TListType list)
+{
+ TNode node;
+ node.Value_ = std::move(list);
+ return node;
+}
+
+TNode TNode::CreateMap()
+{
+ TNode node;
+ node.Value_ = TMapType{};
+ return node;
+}
+
+TNode TNode::CreateMap(TMapType map)
+{
+ TNode node;
+ node.Value_ = std::move(map);
+ return node;
+}
+
+TNode TNode::CreateEntity()
+{
+ TNode node;
+ node.Value_ = TNull{};
+ return node;
+}
+
+const TNode& TNode::operator[](size_t index) const
+{
+ CheckType(List);
+ return std::get<TListType>(Value_)[index];
+}
+
+TNode& TNode::operator[](size_t index)
+{
+ CheckType(List);
+ return std::get<TListType>(Value_)[index];
+}
+
+const TNode& TNode::At(size_t index) const {
+ CheckType(List);
+ const auto& list = std::get<TListType>(Value_);
+ if (index >= list.size()) {
+ ythrow TLookupError() << "List out-of-range: requested index=" << index << ", but size=" << list.size();
+ }
+ return list[index];
+}
+
+TNode& TNode::At(size_t index) {
+ CheckType(List);
+ auto& list = std::get<TListType>(Value_);
+ if (index >= list.size()) {
+ ythrow TLookupError() << "List out-of-range: requested index=" << index << ", but size=" << list.size();
+ }
+ return list[index];
+}
+
+TNode& TNode::Add() &
+{
+ AssureList();
+ return std::get<TListType>(Value_).emplace_back();
+}
+
+TNode TNode::Add() &&
+{
+ return std::move(Add());
+}
+
+TNode& TNode::Add(const TNode& node) &
+{
+ AssureList();
+ std::get<TListType>(Value_).emplace_back(node);
+ return *this;
+}
+
+TNode TNode::Add(const TNode& node) &&
+{
+ return std::move(Add(node));
+}
+
+TNode& TNode::Add(TNode&& node) &
+{
+ AssureList();
+ std::get<TListType>(Value_).emplace_back(std::move(node));
+ return *this;
+}
+
+TNode TNode::Add(TNode&& node) &&
+{
+ return std::move(Add(std::move(node)));
+}
+
+bool TNode::HasKey(const TStringBuf key) const
+{
+ CheckType(Map);
+ return std::get<TMapType>(Value_).contains(key);
+}
+
+TNode& TNode::operator()(const TString& key, const TNode& value) &
+{
+ AssureMap();
+ std::get<TMapType>(Value_)[key] = value;
+ return *this;
+}
+
+TNode TNode::operator()(const TString& key, const TNode& value) &&
+{
+ return std::move(operator()(key, value));
+}
+
+TNode& TNode::operator()(const TString& key, TNode&& value) &
+{
+ AssureMap();
+ std::get<TMapType>(Value_)[key] = std::move(value);
+ return *this;
+}
+
+TNode TNode::operator()(const TString& key, TNode&& value) &&
+{
+ return std::move(operator()(key, std::move(value)));
+}
+
+const TNode& TNode::operator[](const TStringBuf key) const
+{
+ CheckType(Map);
+ static TNode notFound;
+ const auto& map = std::get<TMapType>(Value_);
+ TMapType::const_iterator i = map.find(key);
+ if (i == map.end()) {
+ return notFound;
+ } else {
+ return i->second;
+ }
+}
+
+TNode& TNode::operator[](const TStringBuf key)
+{
+ AssureMap();
+ return std::get<TMapType>(Value_)[key];
+}
+
+const TNode& TNode::At(const TStringBuf key) const {
+ CheckType(Map);
+ const auto& map = std::get<TMapType>(Value_);
+ TMapType::const_iterator i = map.find(key);
+ if (i == map.end()) {
+ ythrow TLookupError() << "Cannot find key " << key;
+ } else {
+ return i->second;
+ }
+}
+
+TNode& TNode::At(const TStringBuf key) {
+ CheckType(Map);
+ auto& map = std::get<TMapType>(Value_);
+ TMapType::iterator i = map.find(key);
+ if (i == map.end()) {
+ ythrow TLookupError() << "Cannot find key " << key;
+ } else {
+ return i->second;
+ }
+}
+
+const TString& TNode::ChildAsString(const TStringBuf key) const {
+ const auto& node = At(key);
+ try {
+ return node.AsString();
+ } catch (TTypeError& e) {
+ e << ", during getting key=" << key;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting key=" << key;
+ }
+}
+
+i64 TNode::ChildAsInt64(const TStringBuf key) const {
+ const auto& node = At(key);
+ try {
+ return node.AsInt64();
+ } catch (TTypeError& e) {
+ e << ", during getting key=" << key;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting key=" << key;
+ }
+}
+
+ui64 TNode::ChildAsUint64(const TStringBuf key) const {
+ const auto& node = At(key);
+ try {
+ return node.AsUint64();
+ } catch (TTypeError& e) {
+ e << ", during getting key=" << key;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting key=" << key;
+ }
+}
+
+double TNode::ChildAsDouble(const TStringBuf key) const {
+ const auto& node = At(key);
+ try {
+ return node.AsDouble();
+ } catch (TTypeError& e) {
+ e << ", during getting key=" << key;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting key=" << key;
+ }
+}
+
+bool TNode::ChildAsBool(const TStringBuf key) const {
+ const auto& node = At(key);
+ try {
+ return node.AsBool();
+ } catch (TTypeError& e) {
+ e << ", during getting key=" << key;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting key=" << key;
+ }
+}
+
+const TNode::TListType& TNode::ChildAsList(const TStringBuf key) const {
+ const auto& node = At(key);
+ try {
+ return node.AsList();
+ } catch (TTypeError& e) {
+ e << ", during getting key=" << key;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting key=" << key;
+ }
+}
+
+const TNode::TMapType& TNode::ChildAsMap(const TStringBuf key) const {
+ const auto& node = At(key);
+ try {
+ return node.AsMap();
+ } catch (TTypeError& e) {
+ e << ", during getting key=" << key;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting key=" << key;
+ }
+}
+
+TNode::TListType& TNode::ChildAsList(const TStringBuf key) {
+ auto& node = At(key);
+ try {
+ return node.AsList();
+ } catch (TTypeError& e) {
+ e << ", during getting key=" << key;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting key=" << key;
+ }
+}
+
+TNode::TMapType& TNode::ChildAsMap(const TStringBuf key) {
+ auto& node = At(key);
+ try {
+ return node.AsMap();
+ } catch (TTypeError& e) {
+ e << ", during getting key=" << key;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting key=" << key;
+ }
+}
+
+const TString& TNode::ChildAsString(size_t index) const {
+ const auto& node = At(index);
+ try {
+ return node.AsString();
+ } catch (TTypeError& e) {
+ e << ", during getting index=" << index;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting index=" << index;
+ }
+}
+
+i64 TNode::ChildAsInt64(size_t index) const {
+ const auto& node = At(index);
+ try {
+ return node.AsInt64();
+ } catch (TTypeError& e) {
+ e << ", during getting index=" << index;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting index=" << index;
+ }
+}
+
+ui64 TNode::ChildAsUint64(size_t index) const {
+ const auto& node = At(index);
+ try {
+ return node.AsUint64();
+ } catch (TTypeError& e) {
+ e << ", during getting index=" << index;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting index=" << index;
+ }
+}
+
+double TNode::ChildAsDouble(size_t index) const {
+ const auto& node = At(index);
+ try {
+ return node.AsDouble();
+ } catch (TTypeError& e) {
+ e << ", during getting index=" << index;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting index=" << index;
+ }
+}
+
+bool TNode::ChildAsBool(size_t index) const {
+ const auto& node = At(index);
+ try {
+ return node.AsBool();
+ } catch (TTypeError& e) {
+ e << ", during getting index=" << index;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting index=" << index;
+ }
+}
+
+const TNode::TListType& TNode::ChildAsList(size_t index) const {
+ const auto& node = At(index);
+ try {
+ return node.AsList();
+ } catch (TTypeError& e) {
+ e << ", during getting index=" << index;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting index=" << index;
+ }
+}
+
+const TNode::TMapType& TNode::ChildAsMap(size_t index) const {
+ const auto& node = At(index);
+ try {
+ return node.AsMap();
+ } catch (TTypeError& e) {
+ e << ", during getting index=" << index;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting index=" << index;
+ }
+}
+
+TNode::TListType& TNode::ChildAsList(size_t index) {
+ auto& node = At(index);
+ try {
+ return node.AsList();
+ } catch (TTypeError& e) {
+ e << ", during getting index=" << index;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting index=" << index;
+ }
+}
+
+TNode::TMapType& TNode::ChildAsMap(size_t index) {
+ auto& node = At(index);
+ try {
+ return node.AsMap();
+ } catch (TTypeError& e) {
+ e << ", during getting index=" << index;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting index=" << index;
+ }
+}
+
+bool TNode::HasAttributes() const
+{
+ return Attributes_ && !Attributes_->Empty();
+}
+
+void TNode::ClearAttributes()
+{
+ if (Attributes_) {
+ Attributes_.Destroy();
+ }
+}
+
+const TNode& TNode::GetAttributes() const
+{
+ static TNode notFound = TNode::CreateMap();
+ if (!Attributes_) {
+ return notFound;
+ }
+ return *Attributes_;
+}
+
+TNode& TNode::Attributes()
+{
+ if (!Attributes_) {
+ CreateAttributes();
+ }
+ return *Attributes_;
+}
+
+void TNode::MoveWithoutAttributes(TNode&& rhs)
+{
+ Value_ = std::move(rhs.Value_);
+ rhs.Clear();
+}
+
+void TNode::Move(TNode&& rhs)
+{
+ Value_ = std::move(rhs.Value_);
+ Attributes_ = std::move(rhs.Attributes_);
+}
+
+void TNode::CheckType(EType type) const
+{
+ Y_ENSURE_EX(GetType() == type,
+ TTypeError() << "TNode type " << type << " expected, actual type " << GetType();
+ );
+}
+
+void TNode::AssureMap()
+{
+ if (std::holds_alternative<TUndefined>(Value_)) {
+ Value_ = TMapType();
+ } else {
+ CheckType(Map);
+ }
+}
+
+void TNode::AssureList()
+{
+ if (std::holds_alternative<TUndefined>(Value_)) {
+ Value_ = TListType();
+ } else {
+ CheckType(List);
+ }
+}
+
+void TNode::CreateAttributes()
+{
+ Attributes_ = MakeHolder<TNode>();
+ Attributes_->Value_ = TMapType();
+}
+
+void TNode::Save(IOutputStream* out) const
+{
+ NodeToYsonStream(*this, out, NYson::EYsonFormat::Binary);
+}
+
+void TNode::Load(IInputStream* in)
+{
+ Clear();
+ *this = NodeFromYsonStream(in, ::NYson::EYsonType::Node);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool operator==(const TNode& lhs, const TNode& rhs)
+{
+ if (std::holds_alternative<TNode::TUndefined>(lhs.Value_) ||
+ std::holds_alternative<TNode::TUndefined>(rhs.Value_))
+ {
+ // TODO: should try to remove this behaviour if nobody uses it.
+ return false;
+ }
+
+ if (lhs.GetType() != rhs.GetType()) {
+ return false;
+ }
+
+ if (lhs.Attributes_) {
+ if (rhs.Attributes_) {
+ if (*lhs.Attributes_ != *rhs.Attributes_) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ } else {
+ if (rhs.Attributes_) {
+ return false;
+ }
+ }
+
+ return rhs.Value_ == lhs.Value_;
+}
+
+bool operator!=(const TNode& lhs, const TNode& rhs)
+{
+ return !(lhs == rhs);
+}
+
+bool GetBool(const TNode& node)
+{
+ if (node.IsBool()) {
+ return node.AsBool();
+ } else if (node.IsString()) {
+ return node.AsString() == "true";
+ } else {
+ ythrow TNode::TTypeError()
+ << "GetBool(): not a boolean or string type";
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yson/node/node.h b/library/cpp/yson/node/node.h
new file mode 100644
index 0000000000..5f90f95df0
--- /dev/null
+++ b/library/cpp/yson/node/node.h
@@ -0,0 +1,523 @@
+#pragma once
+
+#include <util/generic/bt_exception.h>
+#include <util/generic/cast.h>
+#include <util/generic/hash.h>
+#include <util/generic/variant.h>
+#include <util/generic/vector.h>
+#include <util/generic/yexception.h>
+#include <util/generic/ylimits.h>
+#include <util/string/cast.h>
+
+#include <cmath>
+#include <variant>
+
+class IInputStream;
+class IOutputStream;
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TNode
+{
+public:
+ class TLookupError
+ : public TWithBackTrace<yexception>
+ { };
+
+ class TTypeError
+ : public TWithBackTrace<yexception>
+ { };
+
+ enum EType {
+ Undefined = 0 /*"undefined"*/,
+
+ // NOTE: string representation of all node types
+ // are compatible with server node type (except `Undefined' which is missing on server).
+ String = 1 /*"string_node"*/,
+ Int64 = 2 /*"int64_node"*/,
+ Uint64 = 3 /*"uint64_node"*/,
+ Double = 4 /*"double_node"*/,
+ Bool = 5 /*"boolean_node"*/,
+ List = 6 /*"list_node"*/,
+ Map = 7 /*"map_node"*/,
+ Null = 8 /*"null"*/,
+ };
+
+ using TListType = TVector<TNode>;
+ using TMapType = THashMap<TString, TNode>;
+
+private:
+ struct TNull {
+ bool operator==(const TNull&) const;
+ };
+
+ struct TUndefined {
+ bool operator==(const TUndefined&) const;
+ };
+
+ using TValue = std::variant<
+ bool,
+ i64,
+ ui64,
+ double,
+ TString,
+ TListType,
+ TMapType,
+ TNull,
+ TUndefined
+ >;
+
+public:
+
+ TNode();
+ TNode(const char* s);
+ TNode(TStringBuf s);
+ explicit TNode(std::string_view s);
+ explicit TNode(const std::string& s);
+ TNode(TString s);
+ TNode(int i);
+
+ //this case made speccially for prevent mess cast of EType into TNode through TNode(int) constructor
+ //usual case of error SomeNode == TNode::Undefined <-- SomeNode indeed will be compared with TNode(0) without this method
+ //correct way is SomeNode.GetType() == TNode::Undefined
+ template<class T = EType>
+ Y_FORCE_INLINE TNode(EType)
+ {
+ static_assert(!std::is_same<T, EType>::value, "looks like a mistake, may be you forget .GetType()");
+ }
+
+ //this case made speccially for prevent mess cast of T* into TNode through implicit bool ctr
+ template<class T = int>
+ Y_FORCE_INLINE TNode(const T*) : TNode() {
+ static_assert(!std::is_same<T,T>::value, "looks like a mistake, and pointer have converted to bool");
+ }
+
+ TNode(unsigned int ui);
+ TNode(long i);
+ TNode(unsigned long ui);
+ TNode(long long i);
+ TNode(unsigned long long ui);
+ TNode(double d);
+ TNode(bool b);
+ TNode(TMapType map);
+
+ TNode(const TNode& rhs);
+ TNode& operator=(const TNode& rhs);
+
+ TNode(TNode&& rhs) noexcept;
+ TNode& operator=(TNode&& rhs) noexcept;
+
+ ~TNode();
+
+ void Clear();
+
+ bool IsString() const;
+ bool IsInt64() const;
+ bool IsUint64() const;
+ bool IsDouble() const;
+ bool IsBool() const;
+ bool IsList() const;
+ bool IsMap() const;
+
+ // `IsEntity' is deprecated use `IsNull' instead.
+ bool IsEntity() const;
+ bool IsNull() const;
+ bool IsUndefined() const;
+ // Returns true if TNode is neither Null, nor Undefined
+ bool HasValue() const;
+
+ template<typename T>
+ bool IsOfType() const noexcept;
+
+ // Int64, Uint64, Double, or Bool
+ bool IsArithmetic() const;
+
+ bool Empty() const;
+ size_t Size() const;
+
+ EType GetType() const;
+
+ const TString& AsString() const;
+ i64 AsInt64() const;
+ ui64 AsUint64() const;
+ double AsDouble() const;
+ bool AsBool() const;
+ const TListType& AsList() const;
+ const TMapType& AsMap() const;
+ TListType& AsList();
+ TMapType& AsMap();
+
+ const TString& UncheckedAsString() const noexcept;
+ i64 UncheckedAsInt64() const noexcept;
+ ui64 UncheckedAsUint64() const noexcept;
+ double UncheckedAsDouble() const noexcept;
+ bool UncheckedAsBool() const noexcept;
+ const TListType& UncheckedAsList() const noexcept;
+ const TMapType& UncheckedAsMap() const noexcept;
+ TListType& UncheckedAsList() noexcept;
+ TMapType& UncheckedAsMap() noexcept;
+
+ // integer types cast
+ // makes overflow checks
+ template<typename T>
+ T IntCast() const;
+
+ // integers <-> double <-> string
+ // makes overflow checks
+ template<typename T>
+ T ConvertTo() const;
+
+ template<typename T>
+ T& As();
+
+ template<typename T>
+ const T& As() const;
+
+ static TNode CreateList();
+ static TNode CreateList(TListType list);
+ static TNode CreateMap();
+ static TNode CreateMap(TMapType map);
+ static TNode CreateEntity();
+
+ const TNode& operator[](size_t index) const;
+ TNode& operator[](size_t index);
+ const TNode& At(size_t index) const;
+ TNode& At(size_t index);
+
+ TNode& Add() &;
+ TNode Add() &&;
+ TNode& Add(const TNode& node) &;
+ TNode Add(const TNode& node) &&;
+ TNode& Add(TNode&& node) &;
+ TNode Add(TNode&& node) &&;
+
+ bool HasKey(const TStringBuf key) const;
+
+ TNode& operator()(const TString& key, const TNode& value) &;
+ TNode operator()(const TString& key, const TNode& value) &&;
+ TNode& operator()(const TString& key, TNode&& value) &;
+ TNode operator()(const TString& key, TNode&& value) &&;
+
+ const TNode& operator[](const TStringBuf key) const;
+ TNode& operator[](const TStringBuf key);
+ const TNode& At(const TStringBuf key) const;
+ TNode& At(const TStringBuf key);
+
+ // map getters
+ // works the same way like simple getters
+ const TString& ChildAsString(const TStringBuf key) const;
+ i64 ChildAsInt64(const TStringBuf key) const;
+ ui64 ChildAsUint64(const TStringBuf key) const;
+ double ChildAsDouble(const TStringBuf key) const;
+ bool ChildAsBool(const TStringBuf key) const;
+ const TListType& ChildAsList(const TStringBuf key) const;
+ const TMapType& ChildAsMap(const TStringBuf key) const;
+ TListType& ChildAsList(const TStringBuf key);
+ TMapType& ChildAsMap(const TStringBuf key);
+
+ template<typename T>
+ T ChildIntCast(const TStringBuf key) const;
+
+ template<typename T>
+ T ChildConvertTo(const TStringBuf key) const;
+
+ template<typename T>
+ const T& ChildAs(const TStringBuf key) const;
+
+ template<typename T>
+ T& ChildAs(const TStringBuf key);
+
+ // list getters
+ // works the same way like simple getters
+ const TString& ChildAsString(size_t index) const;
+ i64 ChildAsInt64(size_t index) const;
+ ui64 ChildAsUint64(size_t index) const;
+ double ChildAsDouble(size_t index) const;
+ bool ChildAsBool(size_t index) const;
+ const TListType& ChildAsList(size_t index) const;
+ const TMapType& ChildAsMap(size_t index) const;
+ TListType& ChildAsList(size_t index);
+ TMapType& ChildAsMap(size_t index);
+
+ template<typename T>
+ T ChildIntCast(size_t index) const;
+
+ template<typename T>
+ T ChildConvertTo(size_t index) const;
+
+ template<typename T>
+ const T& ChildAs(size_t index) const;
+
+ template<typename T>
+ T& ChildAs(size_t index);
+
+
+ // attributes
+ bool HasAttributes() const;
+ void ClearAttributes();
+ const TNode& GetAttributes() const;
+ TNode& Attributes();
+
+ void MoveWithoutAttributes(TNode&& rhs);
+
+ // Serialize TNode using binary yson format.
+ // Methods for ysaveload.
+ void Save(IOutputStream* output) const;
+ void Load(IInputStream* input);
+
+private:
+ void Move(TNode&& rhs);
+
+ void CheckType(EType type) const;
+
+ void AssureMap();
+ void AssureList();
+
+ void CreateAttributes();
+
+private:
+ TValue Value_;
+ THolder<TNode> Attributes_;
+
+ friend bool operator==(const TNode& lhs, const TNode& rhs);
+ friend bool operator!=(const TNode& lhs, const TNode& rhs);
+};
+
+bool operator==(const TNode& lhs, const TNode& rhs);
+bool operator!=(const TNode& lhs, const TNode& rhs);
+
+bool GetBool(const TNode& node);
+
+inline bool TNode::IsArithmetic() const {
+ return IsInt64() || IsUint64() || IsDouble() || IsBool();
+}
+
+template<typename T>
+inline T TNode::IntCast() const {
+ if constexpr (std::is_integral<T>::value) {
+ try {
+ switch (GetType()) {
+ case TNode::Uint64:
+ return SafeIntegerCast<T>(AsUint64());
+ case TNode::Int64:
+ return SafeIntegerCast<T>(AsInt64());
+ default:
+ ythrow TTypeError() << "IntCast() called for type " << GetType();
+ }
+ } catch(TBadCastException& exc) {
+ ythrow TTypeError() << "TBadCastException during IntCast(): " << exc.what();
+ }
+ } else {
+ static_assert(sizeof(T) != sizeof(T), "implemented only for std::is_integral types");
+ }
+}
+
+template<typename T>
+inline T TNode::ConvertTo() const {
+ if constexpr (std::is_integral<T>::value) {
+ switch (GetType()) {
+ case NYT::TNode::String:
+ return ::FromString(AsString());
+ case NYT::TNode::Int64:
+ case NYT::TNode::Uint64:
+ return IntCast<T>();
+ case NYT::TNode::Double:
+ if (AsDouble() < Min<T>() || AsDouble() > MaxFloor<T>() || !std::isfinite(AsDouble())) {
+ ythrow TTypeError() << AsDouble() << " can't be converted to " << TypeName<T>();
+ }
+ return AsDouble();
+ case NYT::TNode::Bool:
+ return AsBool();
+ case NYT::TNode::List:
+ case NYT::TNode::Map:
+ case NYT::TNode::Null:
+ case NYT::TNode::Undefined:
+ ythrow TTypeError() << "ConvertTo<" << TypeName<T>() << ">() called for type " << GetType();
+ };
+ } else {
+ static_assert(sizeof(T) != sizeof(T), "should have template specialization");
+ }
+}
+
+template<>
+inline TString TNode::ConvertTo<TString>() const {
+ switch (GetType()) {
+ case NYT::TNode::String:
+ return AsString();
+ case NYT::TNode::Int64:
+ return ::ToString(AsInt64());
+ case NYT::TNode::Uint64:
+ return ::ToString(AsUint64());
+ case NYT::TNode::Double:
+ return ::ToString(AsDouble());
+ case NYT::TNode::Bool:
+ return ::ToString(AsBool());
+ case NYT::TNode::List:
+ case NYT::TNode::Map:
+ case NYT::TNode::Null:
+ case NYT::TNode::Undefined:
+ ythrow TTypeError() << "ConvertTo<TString>() called for type " << GetType();
+ }
+ Y_UNREACHABLE();
+}
+
+template<>
+inline double TNode::ConvertTo<double>() const {
+ switch (GetType()) {
+ case NYT::TNode::String:
+ return ::FromString(AsString());
+ case NYT::TNode::Int64:
+ return AsInt64();
+ case NYT::TNode::Uint64:
+ return AsUint64();
+ case NYT::TNode::Double:
+ return AsDouble();
+ case NYT::TNode::Bool:
+ return AsBool();
+ case NYT::TNode::List:
+ case NYT::TNode::Map:
+ case NYT::TNode::Null:
+ case NYT::TNode::Undefined:
+ ythrow TTypeError() << "ConvertTo<double>() called for type " << GetType();
+ }
+}
+
+template<>
+inline bool TNode::ConvertTo<bool>() const {
+ switch (GetType()) {
+ case NYT::TNode::String:
+ return ::FromString(AsString());
+ case NYT::TNode::Int64:
+ return AsInt64();
+ case NYT::TNode::Uint64:
+ return AsUint64();
+ case NYT::TNode::Double:
+ return AsDouble();
+ case NYT::TNode::Bool:
+ return AsBool();
+ case NYT::TNode::List:
+ case NYT::TNode::Map:
+ case NYT::TNode::Null:
+ case NYT::TNode::Undefined:
+ ythrow TTypeError() << "ConvertTo<bool>() called for type " << GetType();
+ }
+}
+
+template<typename T>
+inline T TNode::ChildIntCast(const TStringBuf key) const {
+ const auto& node = At(key);
+ try {
+ return node.IntCast<T>();
+ } catch (TTypeError& e) {
+ e << ", during getting key=" << key;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting key=" << key;
+ }
+}
+
+template<typename T>
+inline T TNode::ChildIntCast(size_t index) const {
+ const auto& node = At(index);
+ try {
+ return node.IntCast<T>();
+ } catch (TTypeError& e) {
+ e << ", during getting index=" << index;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting index=" << index;
+ }
+}
+
+template<typename T>
+inline T TNode::ChildConvertTo(const TStringBuf key) const {
+ const auto& node = At(key);
+ try {
+ return node.ConvertTo<T>();
+ } catch (TTypeError& e) {
+ e << ", during getting key=" << key;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting key=" << key;
+ }
+}
+
+template<typename T>
+inline T TNode::ChildConvertTo(size_t index) const {
+ const auto& node = At(index);
+ try {
+ return node.ConvertTo<T>();
+ } catch (TTypeError& e) {
+ e << ", during getting index=" << index;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting index=" << index;
+ }
+}
+
+template<typename T>
+inline const T& TNode::ChildAs(const TStringBuf key) const {
+ const auto& node = At(key);
+ try {
+ return node.As<T>();
+ } catch (TTypeError& e) {
+ e << ", during getting key=" << key;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting key=" << key;
+ }
+}
+
+template<typename T>
+inline const T& TNode::ChildAs(size_t index) const {
+ const auto& node = At(index);
+ try {
+ return node.As<T>();
+ } catch (TTypeError& e) {
+ e << ", during getting index=" << index;
+ throw e;
+ } catch (...) {
+ ythrow TTypeError() << CurrentExceptionMessage() << ", during getting index=" << index;
+ }
+}
+
+template<typename T>
+inline T& TNode::ChildAs(const TStringBuf key) {
+ return const_cast<T&>(static_cast<const TNode*>(this)->ChildAs<T>(key));
+}
+
+template<typename T>
+inline T& TNode::ChildAs(size_t index) {
+ return const_cast<T&>(static_cast<const TNode*>(this)->ChildAs<T>(index));
+}
+
+template<typename T>
+inline bool TNode::IsOfType() const noexcept {
+ return std::holds_alternative<T>(Value_);
+}
+
+template<typename T>
+inline T& TNode::As() {
+ return std::get<T>(Value_);
+}
+
+template<typename T>
+inline const T& TNode::As() const {
+ return std::get<T>(Value_);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace NNodeCmp {
+ bool operator<(const TNode& lhs, const TNode& rhs);
+ bool operator<=(const TNode& lhs, const TNode& rhs);
+ bool operator>(const TNode& lhs, const TNode& rhs);
+ bool operator>=(const TNode& lhs, const TNode& rhs);
+ bool IsComparableType(const TNode::EType type);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yson/node/node_builder.cpp b/library/cpp/yson/node/node_builder.cpp
new file mode 100644
index 0000000000..b4431bc77a
--- /dev/null
+++ b/library/cpp/yson/node/node_builder.cpp
@@ -0,0 +1,96 @@
+#include "node_builder.h"
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TNodeBuilder::TNodeBuilder(TNode* node)
+{
+ Stack_.push(node);
+}
+
+void TNodeBuilder::OnStringScalar(TStringBuf value)
+{
+ AddNode(value, true);
+}
+
+void TNodeBuilder::OnInt64Scalar(i64 value)
+{
+ AddNode(value, true);
+}
+
+void TNodeBuilder::OnUint64Scalar(ui64 value)
+{
+ AddNode(value, true);
+}
+
+void TNodeBuilder::OnDoubleScalar(double value)
+{
+ AddNode(value, true);
+}
+
+void TNodeBuilder::OnBooleanScalar(bool value)
+{
+ AddNode(value, true);
+}
+
+void TNodeBuilder::OnEntity()
+{
+ AddNode(TNode::CreateEntity(), true);
+}
+
+void TNodeBuilder::OnBeginList()
+{
+ AddNode(TNode::CreateList(), false);
+}
+
+void TNodeBuilder::OnListItem()
+{
+ Stack_.push(&Stack_.top()->Add());
+}
+
+void TNodeBuilder::OnEndList()
+{
+ Stack_.pop();
+}
+
+void TNodeBuilder::OnBeginMap()
+{
+ AddNode(TNode::CreateMap(), false);
+}
+
+void TNodeBuilder::OnKeyedItem(TStringBuf key)
+{
+ Stack_.push(&(*Stack_.top())[TString(key)]);
+}
+
+void TNodeBuilder::OnEndMap()
+{
+ Stack_.pop();
+}
+
+void TNodeBuilder::OnBeginAttributes()
+{
+ Stack_.push(&Stack_.top()->Attributes());
+}
+
+void TNodeBuilder::OnEndAttributes()
+{
+ Stack_.pop();
+}
+
+void TNodeBuilder::OnNode(TNode node)
+{
+ AddNode(std::move(node), true);
+}
+
+void TNodeBuilder::AddNode(TNode value, bool pop)
+{
+ Stack_.top()->MoveWithoutAttributes(std::move(value));
+ if (pop)
+ Stack_.pop();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yson/node/node_builder.h b/library/cpp/yson/node/node_builder.h
new file mode 100644
index 0000000000..69800016e0
--- /dev/null
+++ b/library/cpp/yson/node/node_builder.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "node.h"
+
+#include <library/cpp/json/json_reader.h>
+
+#include <library/cpp/yson/consumer.h>
+
+#include <util/generic/stack.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TNodeBuilder
+ : public ::NYson::TYsonConsumerBase
+{
+public:
+ TNodeBuilder(TNode* node);
+
+ void OnStringScalar(TStringBuf) override;
+ void OnInt64Scalar(i64) override;
+ void OnUint64Scalar(ui64) override;
+ void OnDoubleScalar(double) override;
+ void OnBooleanScalar(bool) override;
+ void OnEntity() override;
+ void OnBeginList() override;
+ void OnListItem() override;
+ void OnEndList() override;
+ void OnBeginMap() override;
+ void OnKeyedItem(TStringBuf) override;
+ void OnEndMap() override;
+ void OnBeginAttributes() override;
+ void OnEndAttributes() override;
+ void OnNode(TNode node);
+
+private:
+ TStack<TNode*> Stack_;
+
+private:
+ inline void AddNode(TNode node, bool pop);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yson/node/node_io.cpp b/library/cpp/yson/node/node_io.cpp
new file mode 100644
index 0000000000..294a7f7217
--- /dev/null
+++ b/library/cpp/yson/node/node_io.cpp
@@ -0,0 +1,154 @@
+#include "node_io.h"
+
+#include "node_builder.h"
+#include "node_visitor.h"
+
+#include <library/cpp/yson/json/json_writer.h>
+#include <library/cpp/yson/parser.h>
+#include <library/cpp/yson/writer.h>
+#include <library/cpp/yson/json/yson2json_adapter.h>
+
+#include <library/cpp/json/json_reader.h>
+#include <library/cpp/json/json_value.h>
+
+#include <util/stream/input.h>
+#include <util/stream/output.h>
+#include <util/stream/str.h>
+#include <util/stream/mem.h>
+
+namespace NYT {
+
+static void WalkJsonTree(const NJson::TJsonValue& jsonValue, NJson::TJsonCallbacks* callbacks)
+{
+ using namespace NJson;
+ switch (jsonValue.GetType()) {
+ case JSON_NULL:
+ callbacks->OnNull();
+ return;
+ case JSON_BOOLEAN:
+ callbacks->OnBoolean(jsonValue.GetBoolean());
+ return;
+ case JSON_INTEGER:
+ callbacks->OnInteger(jsonValue.GetInteger());
+ return;
+ case JSON_UINTEGER:
+ callbacks->OnUInteger(jsonValue.GetUInteger());
+ return;
+ case JSON_DOUBLE:
+ callbacks->OnDouble(jsonValue.GetDouble());
+ return;
+ case JSON_STRING:
+ callbacks->OnString(jsonValue.GetString());
+ return;
+ case JSON_MAP:
+ {
+ callbacks->OnOpenMap();
+ for (const auto& item : jsonValue.GetMap()) {
+ callbacks->OnMapKey(item.first);
+ WalkJsonTree(item.second, callbacks);
+ }
+ callbacks->OnCloseMap();
+ }
+ return;
+ case JSON_ARRAY:
+ {
+ callbacks->OnOpenArray();
+ for (const auto& item : jsonValue.GetArray()) {
+ WalkJsonTree(item, callbacks);
+ }
+ callbacks->OnCloseArray();
+ }
+ return;
+ case JSON_UNDEFINED:
+ ythrow yexception() << "cannot consume undefined json value";
+ return;
+ }
+ Y_UNREACHABLE();
+}
+
+static TNode CreateEmptyNodeByType(::NYson::EYsonType type)
+{
+ TNode result;
+ switch (type) {
+ case ::NYson::EYsonType::ListFragment:
+ result = TNode::CreateList();
+ break;
+ case ::NYson::EYsonType::MapFragment:
+ result = TNode::CreateMap();
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+TNode NodeFromYsonString(const TStringBuf input, ::NYson::EYsonType type)
+{
+ TMemoryInput stream(input);
+ return NodeFromYsonStream(&stream, type);
+}
+
+TString NodeToYsonString(const TNode& node, NYson::EYsonFormat format)
+{
+ TStringStream stream;
+ NodeToYsonStream(node, &stream, format);
+ return stream.Str();
+}
+
+TString NodeToCanonicalYsonString(const TNode& node, NYson::EYsonFormat format)
+{
+ TStringStream stream;
+ NodeToCanonicalYsonStream(node, &stream, format);
+ return stream.Str();
+}
+
+TNode NodeFromYsonStream(IInputStream* input, ::NYson::EYsonType type)
+{
+ TNode result = CreateEmptyNodeByType(type);
+
+ TNodeBuilder builder(&result);
+ ::NYson::TYsonParser parser(&builder, input, type);
+ parser.Parse();
+ return result;
+}
+
+void NodeToYsonStream(const TNode& node, IOutputStream* output, NYson::EYsonFormat format)
+{
+ ::NYson::TYsonWriter writer(output, format);
+ TNodeVisitor visitor(&writer);
+ visitor.Visit(node);
+}
+
+void NodeToCanonicalYsonStream(const TNode& node, IOutputStream* output, NYson::EYsonFormat format)
+{
+ ::NYson::TYsonWriter writer(output, format);
+ TNodeVisitor visitor(&writer, /*sortMapKeys*/ true);
+ visitor.Visit(node);
+}
+
+TNode NodeFromJsonString(const TStringBuf input)
+{
+ TMemoryInput stream(input);
+
+ TNode result;
+
+ TNodeBuilder builder(&result);
+ TYson2JsonCallbacksAdapter callbacks(&builder, /*throwException*/ true);
+ NJson::TJsonReaderConfig config;
+ config.DontValidateUtf8 = true;
+ NJson::ReadJson(&stream, &config, &callbacks);
+ return result;
+}
+
+TNode NodeFromJsonValue(const NJson::TJsonValue& input)
+{
+ TNode result;
+ TNodeBuilder builder(&result);
+ TYson2JsonCallbacksAdapter callbacks(&builder, /*throwException*/ true);
+ WalkJsonTree(input, &callbacks);
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yson/node/node_io.h b/library/cpp/yson/node/node_io.h
new file mode 100644
index 0000000000..2ad23b658f
--- /dev/null
+++ b/library/cpp/yson/node/node_io.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "node.h"
+#include <library/cpp/yson/public.h>
+
+namespace NJson {
+ class TJsonValue;
+} // namespace NJson
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Parse TNode from string in YSON format
+TNode NodeFromYsonString(const TStringBuf input, ::NYson::EYsonType type = ::NYson::EYsonType::Node);
+
+// Serialize TNode to string in one of YSON formats with random order of maps' keys (don't use in tests)
+TString NodeToYsonString(const TNode& node, ::NYson::EYsonFormat format = ::NYson::EYsonFormat::Text);
+
+// Same as the latter, but maps' keys are sorted lexicographically (to be used in tests)
+TString NodeToCanonicalYsonString(const TNode& node, ::NYson::EYsonFormat format = ::NYson::EYsonFormat::Text);
+
+// Parse TNode from stream in YSON format
+TNode NodeFromYsonStream(IInputStream* input, ::NYson::EYsonType type = ::NYson::EYsonType::Node);
+
+// Serialize TNode to stream in one of YSON formats with random order of maps' keys (don't use in tests)
+void NodeToYsonStream(const TNode& node, IOutputStream* output, ::NYson::EYsonFormat format = ::NYson::EYsonFormat::Text);
+
+// Same as the latter, but maps' keys are sorted lexicographically (to be used in tests)
+void NodeToCanonicalYsonStream(const TNode& node, IOutputStream* output, ::NYson::EYsonFormat format = ::NYson::EYsonFormat::Text);
+
+// Parse TNode from string in JSON format
+TNode NodeFromJsonString(const TStringBuf input);
+
+// Convert TJsonValue to TNode
+TNode NodeFromJsonValue(const NJson::TJsonValue& input);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yson/node/node_ut.cpp b/library/cpp/yson/node/node_ut.cpp
new file mode 100644
index 0000000000..448e99f575
--- /dev/null
+++ b/library/cpp/yson/node/node_ut.cpp
@@ -0,0 +1,484 @@
+#include "node.h"
+#include "node_io.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/ysaveload.h>
+
+using namespace NYT;
+
+template<>
+void Out<NYT::TNode>(IOutputStream& s, const NYT::TNode& node)
+{
+ s << "TNode:" << NodeToYsonString(node);
+}
+
+Y_UNIT_TEST_SUITE(YtNodeTest) {
+ Y_UNIT_TEST(TestConstsructors) {
+ TNode nodeEmpty;
+ UNIT_ASSERT_EQUAL(nodeEmpty.GetType(), TNode::Undefined);
+
+ TNode nodeString("foobar");
+ UNIT_ASSERT_EQUAL(nodeString.GetType(), TNode::String);
+ UNIT_ASSERT(nodeString.IsString());
+ UNIT_ASSERT_VALUES_EQUAL(nodeString.AsString(), "foobar");
+
+ TNode nodeInt(int(54));
+ UNIT_ASSERT_EQUAL(nodeInt.GetType(), TNode::Int64);
+ UNIT_ASSERT(nodeInt.IsInt64());
+ UNIT_ASSERT(!nodeInt.IsUint64());
+ UNIT_ASSERT_VALUES_EQUAL(nodeInt.AsInt64(), 54ull);
+
+ TNode nodeUint(ui64(42));
+ UNIT_ASSERT_EQUAL(nodeUint.GetType(), TNode::Uint64);
+ UNIT_ASSERT(nodeUint.IsUint64());
+ UNIT_ASSERT(!nodeUint.IsInt64());
+ UNIT_ASSERT_VALUES_EQUAL(nodeUint.AsUint64(), 42ull);
+
+ TNode nodeDouble(double(2.3));
+ UNIT_ASSERT_EQUAL(nodeDouble.GetType(), TNode::Double);
+ UNIT_ASSERT(nodeDouble.IsDouble());
+ UNIT_ASSERT_VALUES_EQUAL(nodeDouble.AsDouble(), double(2.3));
+
+ TNode nodeBool(true);
+ UNIT_ASSERT_EQUAL(nodeBool.GetType(), TNode::Bool);
+ UNIT_ASSERT(nodeBool.IsBool());
+ UNIT_ASSERT_VALUES_EQUAL(nodeBool.AsBool(), true);
+
+ TNode nodeEntity = TNode::CreateEntity();
+ UNIT_ASSERT_EQUAL(nodeEntity.GetType(), TNode::Null);
+ UNIT_ASSERT(nodeEntity.IsEntity());
+ }
+
+ Y_UNIT_TEST(TestPredicates) {
+ const TNode undefinedNode;
+ UNIT_ASSERT(undefinedNode.IsUndefined());
+ UNIT_ASSERT(!undefinedNode.IsNull());
+ UNIT_ASSERT(!undefinedNode.HasValue());
+
+ const TNode nullNode = TNode::CreateEntity();
+ UNIT_ASSERT(!nullNode.IsUndefined());
+ UNIT_ASSERT(nullNode.IsNull());
+ UNIT_ASSERT(!nullNode.HasValue());
+
+ const TNode intNode(int(64));
+ UNIT_ASSERT(!intNode.IsUndefined());
+ UNIT_ASSERT(!intNode.IsNull());
+ UNIT_ASSERT(intNode.HasValue());
+
+ const TNode stringNode("blah");
+ UNIT_ASSERT(!stringNode.IsUndefined());
+ UNIT_ASSERT(!stringNode.IsNull());
+ UNIT_ASSERT(stringNode.HasValue());
+ }
+
+ Y_UNIT_TEST(TestComplexConstructors) {
+ const TNode listNode = TNode::CreateList({"one", 2, "tree"});
+ const auto expectedListValue = std::vector<TNode>({"one", 2, "tree"});
+ UNIT_ASSERT_VALUES_EQUAL(listNode.AsList(), expectedListValue);
+
+ const TNode mapNode = TNode::CreateMap({{"one", 1}, {"two", 2u}});
+ const auto expectedMapValue = THashMap<TString, TNode>({{"one", 1}, {"two", 2u}});
+ UNIT_ASSERT_VALUES_EQUAL(mapNode.AsMap(), expectedMapValue);
+ }
+
+ Y_UNIT_TEST(TestNodeMap) {
+ TNode nodeMap = TNode()("foo", "bar")("bar", "baz");
+ UNIT_ASSERT(nodeMap.IsMap());
+ UNIT_ASSERT_EQUAL(nodeMap.GetType(), TNode::Map);
+ UNIT_ASSERT_VALUES_EQUAL(nodeMap.Size(), 2);
+
+ UNIT_ASSERT(nodeMap.HasKey("foo"));
+ UNIT_ASSERT(!nodeMap.HasKey("42"));
+ UNIT_ASSERT_EQUAL(nodeMap["foo"], TNode("bar"));
+ UNIT_ASSERT_EQUAL(nodeMap["bar"], TNode("baz"));
+
+ // const version of operator[]
+ UNIT_ASSERT_EQUAL(static_cast<const TNode&>(nodeMap)["42"].GetType(), TNode::Undefined);
+ UNIT_ASSERT(!nodeMap.HasKey("42"));
+
+ // nonconst version of operator[]
+ UNIT_ASSERT_EQUAL(nodeMap["42"].GetType(), TNode::Undefined);
+ UNIT_ASSERT(nodeMap.HasKey("42"));
+
+ nodeMap("rock!!!", TNode()
+ ("Pink", "Floyd")
+ ("Purple", "Deep"));
+
+ TNode copyNode;
+ copyNode = nodeMap;
+ UNIT_ASSERT_EQUAL(copyNode["foo"], TNode("bar"));
+ UNIT_ASSERT_EQUAL(copyNode["bar"], TNode("baz"));
+ UNIT_ASSERT(copyNode["42"].GetType() == TNode::Undefined);
+ UNIT_ASSERT_EQUAL(copyNode["rock!!!"]["Purple"], TNode("Deep"));
+ }
+
+ Y_UNIT_TEST(TestNodeList) {
+ TNode nodeList = TNode().Add("foo").Add(42).Add(3.14);
+ UNIT_ASSERT(nodeList.IsList());
+ UNIT_ASSERT_EQUAL(nodeList.GetType(), TNode::List);
+ UNIT_ASSERT_VALUES_EQUAL(nodeList.Size(), 3);
+
+ UNIT_ASSERT_EQUAL(nodeList[1], TNode(42));
+ nodeList.Add(TNode().Add("ls").Add("pwd"));
+
+ TNode copyNode;
+ copyNode = nodeList;
+ UNIT_ASSERT_EQUAL(copyNode[0], TNode("foo"));
+ UNIT_ASSERT_EQUAL(copyNode[3][1], TNode("pwd"));
+ }
+
+ Y_UNIT_TEST(TestInsertingMethodsFromTemporaryObjects) {
+ // check that .Add(...) doesn't return lvalue reference to temporary object
+ {
+ const TNode& nodeList = TNode().Add(0).Add("pass").Add(0);
+ UNIT_ASSERT_EQUAL(nodeList[1], TNode("pass"));
+ }
+
+ // check that .operator()(...) doesn't return lvalue reference to temporary object
+ {
+ const TNode& nodeMap = TNode()("1", 0)("2", "pass")("3", 0);
+ UNIT_ASSERT_EQUAL(nodeMap["2"], TNode("pass"));
+ }
+ }
+
+ Y_UNIT_TEST(TestAttributes) {
+ TNode node = TNode()("lee", 42)("faa", 54);
+ UNIT_ASSERT(!node.HasAttributes());
+ node.Attributes()("foo", true)("bar", false);
+ UNIT_ASSERT(node.HasAttributes());
+
+ {
+ TNode copyNode;
+ UNIT_ASSERT(!copyNode.HasAttributes());
+ copyNode = node;
+ UNIT_ASSERT(copyNode.HasAttributes());
+ UNIT_ASSERT_EQUAL(copyNode.GetAttributes()["foo"], TNode(true));
+ }
+
+ {
+ TNode movedWithoutAttributes(42);
+ movedWithoutAttributes.Attributes()("one", 1)("two", 2);
+ movedWithoutAttributes.MoveWithoutAttributes(TNode(node));
+ UNIT_ASSERT(movedWithoutAttributes.IsMap());
+ UNIT_ASSERT_EQUAL(movedWithoutAttributes["lee"], TNode(42));
+ UNIT_ASSERT_EQUAL(movedWithoutAttributes.GetAttributes()["one"], TNode(1));
+ UNIT_ASSERT(!movedWithoutAttributes.GetAttributes().HasKey("foo"));
+ }
+
+ {
+ TNode copyNode = node;
+ UNIT_ASSERT(copyNode.HasAttributes());
+ UNIT_ASSERT(copyNode.GetAttributes().HasKey("foo"));
+ copyNode.ClearAttributes();
+ UNIT_ASSERT(!copyNode.HasAttributes());
+ UNIT_ASSERT(!copyNode.GetAttributes().HasKey("foo"));
+ }
+
+ {
+ TNode copyNode = node;
+ UNIT_ASSERT(copyNode.HasAttributes());
+ UNIT_ASSERT(copyNode.GetAttributes().HasKey("foo"));
+ copyNode.Clear();
+ UNIT_ASSERT(!copyNode.HasAttributes());
+ UNIT_ASSERT(!copyNode.GetAttributes().HasKey("foo"));
+ }
+ }
+
+ Y_UNIT_TEST(TestEq) {
+ TNode nodeNoAttributes = TNode()("lee", 42)("faa", 54);
+ TNode node = nodeNoAttributes;
+ node.Attributes()("foo", true)("bar", false);
+ UNIT_ASSERT(node != nodeNoAttributes);
+ UNIT_ASSERT(nodeNoAttributes != node);
+ TNode copyNode = node;
+ UNIT_ASSERT(copyNode == node);
+ UNIT_ASSERT(node == copyNode);
+ }
+
+ Y_UNIT_TEST(TestComparison) {
+ using namespace NYT::NNodeCmp;
+ {
+ TNode nodeNoAttributes = TNode()("lee", 42)("faa", 54);
+ TNode node = nodeNoAttributes;
+ node.Attributes()("foo", true)("bar", false);
+ UNIT_ASSERT_EXCEPTION(node > nodeNoAttributes, TNode::TTypeError);
+ UNIT_ASSERT_EXCEPTION(node >= nodeNoAttributes, TNode::TTypeError);
+ UNIT_ASSERT_EXCEPTION(nodeNoAttributes < node, TNode::TTypeError);
+ UNIT_ASSERT_EXCEPTION(nodeNoAttributes <= node, TNode::TTypeError);
+ }
+ {
+ TNode nodeMap = TNode()("map", 23);
+ TNode nodeList = TNode::CreateList();
+ UNIT_ASSERT_EXCEPTION(nodeList > nodeMap, TNode::TTypeError);
+ UNIT_ASSERT_EXCEPTION(nodeMap < nodeList, TNode::TTypeError);
+ UNIT_ASSERT_EXCEPTION(nodeMap >= nodeMap, TNode::TTypeError);
+ UNIT_ASSERT_EXCEPTION(nodeList <= nodeList, TNode::TTypeError);
+ }
+ {
+ TNode node1("aaa");
+ TNode node2("bbb");
+ TNode node3("ccc");
+ UNIT_ASSERT(node1 < node2);
+ UNIT_ASSERT(node1 <= node2);
+ UNIT_ASSERT(node1 < node3);
+ UNIT_ASSERT(node1 <= node3);
+ UNIT_ASSERT(!(node3 < node1));
+ UNIT_ASSERT(!(node1 > node3));
+ UNIT_ASSERT(!(node3 <= node1));
+ UNIT_ASSERT(!(node1 >= node3));
+
+ UNIT_ASSERT(node3 > node2);
+ UNIT_ASSERT(node3 >= node2);
+ UNIT_ASSERT(node3 > node1);
+ UNIT_ASSERT(node3 >= node1);
+
+ UNIT_ASSERT(node1 <= node1);
+ UNIT_ASSERT(node1 >= node1);
+ }
+ {
+ TNode node1(23);
+ TNode node2("bbb");
+ TNode node3 = TNode::CreateEntity();
+
+ UNIT_ASSERT(node1 > node2);
+ UNIT_ASSERT(node1 >= node2);
+ UNIT_ASSERT(node2 < node1);
+ UNIT_ASSERT(node2 <= node1);
+
+ UNIT_ASSERT(!(node1 < node2));
+ UNIT_ASSERT(!(node1 <= node2));
+ UNIT_ASSERT(!(node2 > node1));
+ UNIT_ASSERT(!(node2 >= node1));
+
+ UNIT_ASSERT(node1 < node3);
+ UNIT_ASSERT(node2 < node3);
+ UNIT_ASSERT(node3 <= node3);
+ UNIT_ASSERT(!(node3 < node3));
+ UNIT_ASSERT(!(node3 > node3));
+ UNIT_ASSERT(!(node2 >= node3));
+ }
+ }
+
+ Y_UNIT_TEST(TestSaveLoad) {
+ TNode node = TNode()("foo", "bar")("baz", 42);
+ node.Attributes()["attr_name"] = "attr_value";
+
+ TString bytes;
+ {
+ TStringOutput s(bytes);
+ ::Save(&s, node);
+ }
+
+ TNode nodeCopy;
+ {
+ TStringInput s(bytes);
+ ::Load(&s, nodeCopy);
+ }
+
+ UNIT_ASSERT_VALUES_EQUAL(node, nodeCopy);
+ }
+
+ Y_UNIT_TEST(TestIntCast) {
+ TNode node = 1ull << 31;
+ UNIT_ASSERT(node.IsUint64());
+ UNIT_ASSERT_EXCEPTION(node.IntCast<i32>(), TNode::TTypeError);
+ UNIT_ASSERT(node.IntCast<ui32>() == static_cast<ui32>(node.AsUint64()));
+ UNIT_ASSERT(node.IntCast<i64>() == static_cast<i64>(node.AsUint64()));
+ UNIT_ASSERT(node.IntCast<ui64>() == node.AsUint64());
+
+ node = 1ull << 63;
+ UNIT_ASSERT(node.IsUint64());
+ UNIT_ASSERT_EXCEPTION(node.IntCast<i64>(), TNode::TTypeError);
+ UNIT_ASSERT(node.IntCast<ui64>() == node.AsUint64());
+
+ node = 12345;
+ UNIT_ASSERT(node.IsInt64());
+ UNIT_ASSERT_EXCEPTION(node.IntCast<i8>(), TNode::TTypeError);
+ UNIT_ASSERT_EXCEPTION(node.IntCast<ui8>(), TNode::TTypeError);
+ UNIT_ASSERT(node.IntCast<i16>() == static_cast<i16>(node.AsInt64()));
+ UNIT_ASSERT(node.IntCast<ui16>() == static_cast<ui16>(node.AsInt64()));
+ UNIT_ASSERT(node.IntCast<i32>() == static_cast<i32>(node.AsInt64()));
+ UNIT_ASSERT(node.IntCast<ui32>() == static_cast<ui32>(node.AsInt64()));
+ UNIT_ASSERT(node.IntCast<i64>() == node.AsInt64());
+ UNIT_ASSERT(node.IntCast<ui64>() == static_cast<ui64>(node.AsInt64()));
+
+ node = -5;
+ UNIT_ASSERT(node.IsInt64());
+ UNIT_ASSERT(node.IntCast<i8>() == static_cast<i8>(node.AsInt64()));
+ UNIT_ASSERT(node.IntCast<i16>() == static_cast<i16>(node.AsInt64()));
+ UNIT_ASSERT(node.IntCast<i32>() == static_cast<i32>(node.AsInt64()));
+ UNIT_ASSERT(node.IntCast<i64>() == node.AsInt64());
+ UNIT_ASSERT_EXCEPTION(node.IntCast<ui8>(), TNode::TTypeError);
+ UNIT_ASSERT_EXCEPTION(node.IntCast<ui16>(), TNode::TTypeError);
+ UNIT_ASSERT_EXCEPTION(node.IntCast<ui32>(), TNode::TTypeError);
+ UNIT_ASSERT_EXCEPTION(node.IntCast<ui64>(), TNode::TTypeError);
+ }
+
+ Y_UNIT_TEST(TestConvertToString) {
+ UNIT_ASSERT_VALUES_EQUAL(TNode(5).ConvertTo<TString>(), "5");
+ UNIT_ASSERT_VALUES_EQUAL(TNode(123432423).ConvertTo<TString>(), "123432423");
+ UNIT_ASSERT_VALUES_EQUAL(TNode(123456789012345678ll).ConvertTo<TString>(), "123456789012345678");
+ UNIT_ASSERT_VALUES_EQUAL(TNode(123456789012345678ull).ConvertTo<TString>(), "123456789012345678");
+ UNIT_ASSERT_VALUES_EQUAL(TNode(-123456789012345678ll).ConvertTo<TString>(), "-123456789012345678");
+ UNIT_ASSERT_VALUES_EQUAL(TNode(true).ConvertTo<TString>(), "1");
+ UNIT_ASSERT_VALUES_EQUAL(TNode(false).ConvertTo<TString>(), "0");
+ UNIT_ASSERT_VALUES_EQUAL(TNode(5.3).ConvertTo<TString>(), "5.3");
+ }
+
+ Y_UNIT_TEST(TestConvertFromString) {
+ UNIT_ASSERT_VALUES_EQUAL(TNode("123456789012345678").ConvertTo<ui64>(), 123456789012345678ull);
+ UNIT_ASSERT_VALUES_EQUAL(TNode("123456789012345678").ConvertTo<i64>(), 123456789012345678);
+ UNIT_ASSERT_VALUES_EQUAL(TNode(ToString(1ull << 63)).ConvertTo<ui64>(), 1ull << 63);
+ UNIT_ASSERT_EXCEPTION(TNode(ToString(1ull << 63)).ConvertTo<i64>(), TFromStringException);
+ UNIT_ASSERT_VALUES_EQUAL(TNode("5.34").ConvertTo<double>(), 5.34);
+ }
+
+ Y_UNIT_TEST(TestConvertDoubleInt) {
+ UNIT_ASSERT_VALUES_EQUAL(TNode(5.3).ConvertTo<i8>(), 5);
+ UNIT_ASSERT_VALUES_EQUAL(TNode(5.3).ConvertTo<ui8>(), 5);
+ UNIT_ASSERT_VALUES_EQUAL(TNode(5.3).ConvertTo<i64>(), 5);
+ UNIT_ASSERT_VALUES_EQUAL(TNode(5.3).ConvertTo<ui64>(), 5);
+
+ UNIT_ASSERT_VALUES_EQUAL(TNode(-5.3).ConvertTo<i8>(), -5);
+ UNIT_ASSERT_VALUES_EQUAL(TNode(-5.3).ConvertTo<i64>(), -5);
+ UNIT_ASSERT_EXCEPTION(TNode(-5.3).ConvertTo<ui8>(), TNode::TTypeError);
+ UNIT_ASSERT_EXCEPTION(TNode(-5.3).ConvertTo<ui64>(), TNode::TTypeError);
+
+ UNIT_ASSERT_VALUES_EQUAL(TNode(127.0).ConvertTo<i8>(), 127);
+ UNIT_ASSERT_EXCEPTION(TNode(128.0).ConvertTo<i8>(), TNode::TTypeError);
+ UNIT_ASSERT_VALUES_EQUAL(TNode(255.0).ConvertTo<ui8>(), 255);
+ UNIT_ASSERT_EXCEPTION(TNode(256.0).ConvertTo<ui8>(), TNode::TTypeError);
+ UNIT_ASSERT_EXCEPTION(TNode(1e100).ConvertTo<i64>(), TNode::TTypeError);
+ UNIT_ASSERT_EXCEPTION(TNode(1e100).ConvertTo<ui64>(), TNode::TTypeError);
+ {
+ double v = 1ull << 63;
+ TNode node = v;
+ UNIT_ASSERT(node.IsDouble());
+ UNIT_ASSERT_EXCEPTION(node.ConvertTo<i64>(), TNode::TTypeError);
+ UNIT_ASSERT_VALUES_EQUAL(node.ConvertTo<ui64>(), static_cast<ui64>(v));
+ }
+ {
+ double v = (double)(1ull << 63) + (1ull << 63);
+ TNode node = v;
+ UNIT_ASSERT(node.IsDouble());
+ UNIT_ASSERT_EXCEPTION(node.ConvertTo<i64>(), TNode::TTypeError);
+ UNIT_ASSERT_EXCEPTION(node.ConvertTo<ui64>(), TNode::TTypeError);
+ }
+ UNIT_ASSERT_EXCEPTION(TNode(NAN).ConvertTo<ui64>(), TNode::TTypeError);
+ UNIT_ASSERT_EXCEPTION(TNode(NAN).ConvertTo<i64>(), TNode::TTypeError);
+
+ UNIT_ASSERT_EXCEPTION(TNode(INFINITY).ConvertTo<ui64>(), TNode::TTypeError);
+ UNIT_ASSERT_EXCEPTION(TNode(INFINITY).ConvertTo<i64>(), TNode::TTypeError);
+ }
+
+ Y_UNIT_TEST(TestConvertToBool) {
+ UNIT_ASSERT_VALUES_EQUAL(TNode("true").ConvertTo<bool>(), true);
+ UNIT_ASSERT_VALUES_EQUAL(TNode("TRUE").ConvertTo<bool>(), true);
+ UNIT_ASSERT_VALUES_EQUAL(TNode("false").ConvertTo<bool>(), false);
+ UNIT_ASSERT_VALUES_EQUAL(TNode("FALSE").ConvertTo<bool>(), false);
+ UNIT_ASSERT_VALUES_EQUAL(TNode(1).ConvertTo<bool>(), true);
+ UNIT_ASSERT_VALUES_EQUAL(TNode(0).ConvertTo<bool>(), false);
+ UNIT_ASSERT_EXCEPTION(TNode("random").ConvertTo<bool>(), TFromStringException);
+ UNIT_ASSERT_EXCEPTION(TNode("").ConvertTo<bool>(), TFromStringException);
+ }
+
+ Y_UNIT_TEST(TestCanonicalSerialization) {
+ auto node = TNode()
+ ("ca", "ca")("c", "c")("a", "a")("b", "b")
+ ("bb", TNode()
+ ("ii", "ii")("i", "i")("jj", "jj"));
+ node.Attributes() = TNode()("za", "za")("z", "z")("xxx", "xxx")("xx", "xx");
+ UNIT_ASSERT_VALUES_EQUAL(NodeToCanonicalYsonString(node),
+ "<\"xx\"=\"xx\";\"xxx\"=\"xxx\";\"z\"=\"z\";\"za\"=\"za\">"
+ "{\"a\"=\"a\";\"b\"=\"b\";\"bb\"="
+ "{\"i\"=\"i\";\"ii\"=\"ii\";\"jj\"=\"jj\"};"
+ "\"c\"=\"c\";\"ca\"=\"ca\"}");
+ }
+
+ Y_UNIT_TEST(OperatorEqualSubnode) {
+ TNode node;
+ node["a"]["b"] = "c";
+
+ node = node["a"];
+ node = node["b"];
+
+ UNIT_ASSERT_VALUES_EQUAL(node.AsString(), "c");
+ }
+
+ Y_UNIT_TEST(TestMapGetters) {
+ auto node = TNode::CreateMap()
+ ("string", "7")
+ ("int64", 3)
+ ("uint64", 5u)
+ ("double", -3.5)
+ ("list", TNode::CreateList().Add(5))
+ ("map", TNode::CreateMap()("key", "value"));
+
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAs<TString>("string"), "7");
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAsString("string"), "7");
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildConvertTo<i64>("string"), 7);
+
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAs<i64>("int64"), 3);
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAsInt64("int64"), 3);
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildIntCast<ui64>("int64"), 3u);
+
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAs<ui64>("uint64"), 5u);
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAsUint64("uint64"), 5u);
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildIntCast<i64>("uint64"), 5);
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildConvertTo<TString>("uint64"), "5");
+
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAs<double>("double"), -3.5);
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAsDouble("double"), -3.5);
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildConvertTo<TString>("double"), "-3.5");
+
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAs<TNode::TListType>("list")[0].AsInt64(), 5);
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAsList("list")[0].AsInt64(), 5);
+
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAs<TNode::TMapType>("map")["key"].AsString(), "value");
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAsMap("map")["key"].AsString(), "value");
+
+ // mutable accessor
+ auto& childString = node.ChildAs<TString>("string");
+ childString = "yaddayadda";
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAs<TString>("string"), "yaddayadda");
+ }
+
+ Y_UNIT_TEST(TestListGetters) {
+ auto node = TNode::CreateList()
+ .Add("7")
+ .Add(3)
+ .Add(5u)
+ .Add(-3.5)
+ .Add(TNode::CreateList().Add(5))
+ .Add(TNode::CreateMap()("key", "value"));
+
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAs<TString>(0), "7");
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAsString(0), "7");
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildConvertTo<i64>(0), 7);
+
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAs<i64>(1), 3);
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAsInt64(1), 3);
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildIntCast<ui64>(1), 3u);
+
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAs<ui64>(2), 5u);
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAsUint64(2), 5u);
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildIntCast<i64>(2), 5);
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildConvertTo<TString>(2), "5");
+
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAs<double>(3), -3.5);
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAsDouble(3), -3.5);
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildConvertTo<TString>(3), "-3.5");
+
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAs<TNode::TListType>(4)[0].AsInt64(), 5);
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAsList(4)[0].AsInt64(), 5);
+
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAs<TNode::TMapType>(5)["key"].AsString(), "value");
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAsMap(5)["key"].AsString(), "value");
+
+ // mutable accessor
+ auto& childString = node.ChildAs<TString>(0);
+ childString = "yaddayadda";
+ UNIT_ASSERT_VALUES_EQUAL(node.ChildAs<TString>(0), "yaddayadda");
+ }
+}
diff --git a/library/cpp/yson/node/node_visitor.cpp b/library/cpp/yson/node/node_visitor.cpp
new file mode 100644
index 0000000000..899fbfa02a
--- /dev/null
+++ b/library/cpp/yson/node/node_visitor.cpp
@@ -0,0 +1,152 @@
+#include "node_visitor.h"
+
+#include <util/generic/algorithm.h>
+#include <util/string/printf.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+template <typename Fun>
+void Iterate(const TNode::TMapType& nodeMap, bool sortByKey, Fun action)
+{
+ if (sortByKey) {
+ TVector<TNode::TMapType::const_iterator> iterators;
+ for (auto it = nodeMap.begin(); it != nodeMap.end(); ++it) {
+ iterators.push_back(it);
+ }
+ SortBy(iterators, [](TNode::TMapType::const_iterator it) { return it->first; });
+ for (const auto& it : iterators) {
+ action(*it);
+ }
+ } else {
+ ForEach(nodeMap.begin(), nodeMap.end(), action);
+ }
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+
+TNodeVisitor::TNodeVisitor(NYson::IYsonConsumer* consumer, bool sortMapKeys)
+ : Consumer_(consumer)
+ , SortMapKeys_(sortMapKeys)
+{ }
+
+void TNodeVisitor::Visit(const TNode& node)
+{
+ VisitAny(node);
+}
+
+void TNodeVisitor::VisitAny(const TNode& node)
+{
+ if (node.HasAttributes()) {
+ Consumer_->OnBeginAttributes();
+ Iterate(node.GetAttributes().AsMap(), SortMapKeys_, [&](const std::pair<TString, TNode>& item) {
+ Consumer_->OnKeyedItem(item.first);
+ if (item.second.IsUndefined()) {
+ ythrow TNode::TTypeError() << "unable to visit attribute value of type "
+ << TNode::EType::Undefined << "; attribute name: `" << item.first << '\'' ;
+ }
+ VisitAny(item.second);
+ });
+ Consumer_->OnEndAttributes();
+ }
+
+ switch (node.GetType()) {
+ case TNode::String:
+ VisitString(node);
+ break;
+ case TNode::Int64:
+ VisitInt64(node);
+ break;
+ case TNode::Uint64:
+ VisitUint64(node);
+ break;
+ case TNode::Double:
+ VisitDouble(node);
+ break;
+ case TNode::Bool:
+ VisitBool(node);
+ break;
+ case TNode::List:
+ VisitList(node.AsList());
+ break;
+ case TNode::Map:
+ VisitMap(node.AsMap());
+ break;
+ case TNode::Null:
+ VisitEntity();
+ break;
+ case TNode::Undefined:
+ ythrow TNode::TTypeError() << "unable to visit TNode of type " << node.GetType();
+ default:
+ Y_FAIL("Unexpected type: %d", node.GetType());
+ }
+}
+
+void TNodeVisitor::VisitString(const TNode& node)
+{
+ Consumer_->OnStringScalar(node.AsString());
+}
+
+void TNodeVisitor::VisitInt64(const TNode& node)
+{
+ Consumer_->OnInt64Scalar(node.AsInt64());
+}
+
+void TNodeVisitor::VisitUint64(const TNode& node)
+{
+ Consumer_->OnUint64Scalar(node.AsUint64());
+}
+
+void TNodeVisitor::VisitDouble(const TNode& node)
+{
+ Consumer_->OnDoubleScalar(node.AsDouble());
+}
+
+void TNodeVisitor::VisitBool(const TNode& node)
+{
+ Consumer_->OnBooleanScalar(node.AsBool());
+}
+
+void TNodeVisitor::VisitList(const TNode::TListType& nodeList)
+{
+ Consumer_->OnBeginList();
+ size_t index = 0;
+ for (const auto& item : nodeList) {
+ Consumer_->OnListItem();
+ if (item.IsUndefined()) {
+ ythrow TNode::TTypeError() << "unable to visit list node child of type "
+ << TNode::EType::Undefined << "; list index: " << index;
+ }
+ VisitAny(item);
+ ++index;
+ }
+ Consumer_->OnEndList();
+}
+
+void TNodeVisitor::VisitMap(const TNode::TMapType& nodeMap)
+{
+ Consumer_->OnBeginMap();
+ Iterate(nodeMap, SortMapKeys_, [&](const std::pair<TString, TNode>& item) {
+ Consumer_->OnKeyedItem(item.first);
+ if (item.second.IsUndefined()) {
+ ythrow TNode::TTypeError() << "unable to visit map node child of type "
+ << TNode::EType::Undefined << "; map key: `" << item.first << '\'' ;
+ }
+ VisitAny(item.second);
+ });
+ Consumer_->OnEndMap();
+}
+
+void TNodeVisitor::VisitEntity()
+{
+ Consumer_->OnEntity();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yson/node/node_visitor.h b/library/cpp/yson/node/node_visitor.h
new file mode 100644
index 0000000000..db25832309
--- /dev/null
+++ b/library/cpp/yson/node/node_visitor.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "node.h"
+
+#include <library/cpp/yson/consumer.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TNodeVisitor
+{
+public:
+ TNodeVisitor(NYson::IYsonConsumer* consumer, bool sortMapKeys = false);
+
+ void Visit(const TNode& node);
+ void VisitMap(const TNode::TMapType& nodeMap);
+ void VisitList(const TNode::TListType& nodeMap);
+
+private:
+ NYson::IYsonConsumer* Consumer_;
+ bool SortMapKeys_;
+
+private:
+ void VisitAny(const TNode& node);
+
+ void VisitString(const TNode& node);
+ void VisitInt64(const TNode& node);
+ void VisitUint64(const TNode& node);
+ void VisitDouble(const TNode& node);
+ void VisitBool(const TNode& node);
+ void VisitEntity();
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yson/node/pybind/node.cpp b/library/cpp/yson/node/pybind/node.cpp
new file mode 100644
index 0000000000..79beba3647
--- /dev/null
+++ b/library/cpp/yson/node/pybind/node.cpp
@@ -0,0 +1,105 @@
+#include "node.h"
+
+#include <library/cpp/yson/node/node.h>
+
+#include <library/cpp/pybind/cast.h>
+
+#include <Python.h>
+
+namespace NYT {
+
+ PyObject* BuildPyObject(const TNode& node) {
+ switch (node.GetType()) {
+ case TNode::Bool:
+ return NPyBind::BuildPyObject(node.AsBool());
+ case TNode::Int64:
+ return NPyBind::BuildPyObject(node.AsInt64());
+ case TNode::Uint64:
+ return NPyBind::BuildPyObject(node.AsUint64());
+ case TNode::Double:
+ return NPyBind::BuildPyObject(node.AsDouble());
+ case TNode::String:
+ return NPyBind::BuildPyObject(node.AsString());
+ case TNode::List:
+ return NPyBind::BuildPyObject(node.AsList());
+ case TNode::Map:
+ return NPyBind::BuildPyObject(node.AsMap());
+ case TNode::Null:
+ Py_RETURN_NONE;
+ case TNode::Undefined:
+ ythrow TNode::TTypeError() << "BuildPyObject called for undefined TNode";
+ }
+ }
+
+} // namespace NYT
+
+namespace NPyBind {
+
+ template <>
+ bool FromPyObject(PyObject* obj, NYT::TNode& res) {
+ if (obj == Py_None) {
+ res = NYT::TNode::CreateEntity();
+ return true;
+ }
+ if (PyBool_Check(obj)) {
+ res = false;
+ return FromPyObject(obj, res.As<bool>());
+ }
+ if (PyFloat_Check(obj)) {
+ res = 0.0;
+ return FromPyObject(obj, res.As<double>());
+ }
+#if PY_MAJOR_VERSION < 3
+ if (PyString_Check(obj)) {
+ res = TString();
+ return FromPyObject(obj, res.As<TString>());
+ }
+#else
+ if (PyUnicode_Check(obj)) {
+ res = TString();
+ return FromPyObject(obj, res.As<TString>());
+ }
+ if (PyBytes_Check(obj)) {
+ res = TString();
+ return FromPyObject(obj, res.As<TString>());
+ }
+#endif
+ if (PyList_Check(obj)) {
+ res = NYT::TNode::CreateList();
+ return FromPyObject(obj, res.AsList());
+ }
+ if (PyDict_Check(obj)) {
+ res = NYT::TNode::CreateMap();
+ return FromPyObject(obj, res.AsMap());
+ }
+#if PY_MAJOR_VERSION < 3
+ if (PyInt_Check(obj)) {
+ auto valAsLong = PyInt_AsLong(obj);
+ if (valAsLong == -1 && PyErr_Occurred()) {
+ return false;
+ }
+ res = valAsLong;
+ return true;
+ }
+#endif
+ if (PyLong_Check(obj)) {
+ int overflow = 0;
+ auto valAsLong = PyLong_AsLongAndOverflow(obj, &overflow);
+ if (!overflow) {
+ if (valAsLong == -1 && PyErr_Occurred()) {
+ return false;
+ }
+ res = valAsLong;
+ return true;
+ }
+ auto valAsULong = PyLong_AsUnsignedLong(obj);
+ if (valAsULong == static_cast<decltype(valAsULong)>(-1) && PyErr_Occurred()) {
+ return false;
+ }
+ res = valAsULong;
+ return true;
+ }
+ return false;
+ }
+
+} // namespace NPyBind
diff --git a/library/cpp/yson/node/pybind/node.h b/library/cpp/yson/node/pybind/node.h
new file mode 100644
index 0000000000..65f7236de6
--- /dev/null
+++ b/library/cpp/yson/node/pybind/node.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <Python.h>
+
+#include <library/cpp/yson/node/node.h>
+
+namespace NYT {
+ PyObject* BuildPyObject(const TNode& val);
+}
diff --git a/library/cpp/yson/node/pybind/ya.make b/library/cpp/yson/node/pybind/ya.make
new file mode 100644
index 0000000000..97b7583e96
--- /dev/null
+++ b/library/cpp/yson/node/pybind/ya.make
@@ -0,0 +1,16 @@
+PY23_NATIVE_LIBRARY()
+
+OWNER(
+ inngonch
+ g:yt
+)
+
+PEERDIR(
+ library/cpp/pybind
+ library/cpp/yson/node
+)
+SRCS(
+ node.cpp
+)
+
+END()
diff --git a/library/cpp/yson/node/serialize.cpp b/library/cpp/yson/node/serialize.cpp
new file mode 100644
index 0000000000..aeb467622b
--- /dev/null
+++ b/library/cpp/yson/node/serialize.cpp
@@ -0,0 +1,101 @@
+#include "serialize.h"
+
+#include "node_visitor.h"
+
+#include <library/cpp/yson/consumer.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+void Serialize(const TString& value, NYson::IYsonConsumer* consumer)
+{
+ consumer->OnStringScalar(value);
+}
+
+void Serialize(const TStringBuf& value, NYson::IYsonConsumer* consumer)
+{
+ consumer->OnStringScalar(value);
+}
+
+void Serialize(const char* value, NYson::IYsonConsumer* consumer)
+{
+ consumer->OnStringScalar(value);
+}
+
+void Deserialize(TString& value, const TNode& node)
+{
+ value = node.AsString();
+}
+
+#define SERIALIZE_SIGNED(type) \
+void Serialize(type value, NYson::IYsonConsumer* consumer) \
+{ \
+ consumer->OnInt64Scalar(static_cast<i64>(value)); \
+}
+
+#define SERIALIZE_UNSIGNED(type) \
+void Serialize(type value, NYson::IYsonConsumer* consumer) \
+{ \
+ consumer->OnUint64Scalar(static_cast<ui64>(value)); \
+}
+
+SERIALIZE_SIGNED(signed char);
+SERIALIZE_SIGNED(short);
+SERIALIZE_SIGNED(int);
+SERIALIZE_SIGNED(long);
+SERIALIZE_SIGNED(long long);
+
+SERIALIZE_UNSIGNED(unsigned char);
+SERIALIZE_UNSIGNED(unsigned short);
+SERIALIZE_UNSIGNED(unsigned int);
+SERIALIZE_UNSIGNED(unsigned long);
+SERIALIZE_UNSIGNED(unsigned long long);
+
+#undef SERIALIZE_SIGNED
+#undef SERIALIZE_UNSIGNED
+
+void Deserialize(i64& value, const TNode& node)
+{
+ value = node.AsInt64();
+}
+
+void Deserialize(ui64& value, const TNode& node)
+{
+ value = node.AsUint64();
+}
+
+void Serialize(double value, NYson::IYsonConsumer* consumer)
+{
+ consumer->OnDoubleScalar(value);
+}
+
+void Deserialize(double& value, const TNode& node)
+{
+ value = node.AsDouble();
+}
+
+void Serialize(bool value, NYson::IYsonConsumer* consumer)
+{
+ consumer->OnBooleanScalar(value);
+}
+
+void Deserialize(bool& value, const TNode& node)
+{
+ value = node.AsBool();
+}
+
+void Serialize(const TNode& node, NYson::IYsonConsumer* consumer)
+{
+ TNodeVisitor visitor(consumer);
+ visitor.Visit(node);
+}
+
+void Deserialize(TNode& value, const TNode& node)
+{
+ value = node;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yson/node/serialize.h b/library/cpp/yson/node/serialize.h
new file mode 100644
index 0000000000..99b598a44c
--- /dev/null
+++ b/library/cpp/yson/node/serialize.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include "node.h"
+
+namespace NYT {
+
+namespace NYson {
+struct IYsonConsumer;
+} // namespace NYson
+
+////////////////////////////////////////////////////////////////////////////////
+
+void Serialize(const TString& value, NYson::IYsonConsumer* consumer);
+void Serialize(const TStringBuf& value, NYson::IYsonConsumer* consumer);
+void Serialize(const char* value, NYson::IYsonConsumer* consumer);
+void Deserialize(TString& value, const TNode& node);
+
+void Serialize(signed char value, NYson::IYsonConsumer* consumer);
+void Serialize(short value, NYson::IYsonConsumer* consumer);
+void Serialize(int value, NYson::IYsonConsumer* consumer);
+void Serialize(long value, NYson::IYsonConsumer* consumer);
+void Serialize(long long value, NYson::IYsonConsumer* consumer);
+void Deserialize(i64& value, const TNode& node);
+
+void Serialize(unsigned char value, NYson::IYsonConsumer* consumer);
+void Serialize(unsigned short value, NYson::IYsonConsumer* consumer);
+void Serialize(unsigned int value, NYson::IYsonConsumer* consumer);
+void Serialize(unsigned long value, NYson::IYsonConsumer* consumer);
+void Serialize(unsigned long long value, NYson::IYsonConsumer* consumer);
+void Deserialize(ui64& value, const TNode& node);
+
+void Serialize(double value, NYson::IYsonConsumer* consumer);
+void Deserialize(double& value, const TNode& node);
+
+void Serialize(bool value, NYson::IYsonConsumer* consumer);
+void Deserialize(bool& value, const TNode& node);
+
+void Serialize(const TNode& node, NYson::IYsonConsumer* consumer);
+void Deserialize(TNode& value, const TNode& node);
+
+void Serialize(const THashMap<TString, TString>& renameColumns, NYson::IYsonConsumer* consumer);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yson/node/ut/ya.make b/library/cpp/yson/node/ut/ya.make
new file mode 100644
index 0000000000..f49a0bf7df
--- /dev/null
+++ b/library/cpp/yson/node/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/yson/node)
+
+OWNER(
+ ermolovd
+ g:yt
+)
+
+SRCS(
+ node_ut.cpp
+)
+
+END()
diff --git a/library/cpp/yson/node/ya.make b/library/cpp/yson/node/ya.make
new file mode 100644
index 0000000000..a082b293c4
--- /dev/null
+++ b/library/cpp/yson/node/ya.make
@@ -0,0 +1,25 @@
+LIBRARY()
+
+GENERATE_ENUM_SERIALIZATION(node.h)
+
+PEERDIR(
+ library/cpp/yson
+ library/cpp/yson/json
+)
+
+OWNER(
+ ermolovd
+ g:yt
+)
+
+SRCS(
+ node.cpp
+ node_io.cpp
+ node_builder.cpp
+ node_visitor.cpp
+ serialize.cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/cpp/yson/parser.cpp b/library/cpp/yson/parser.cpp
new file mode 100644
index 0000000000..783f9b9047
--- /dev/null
+++ b/library/cpp/yson/parser.cpp
@@ -0,0 +1,179 @@
+#include "parser.h"
+#include "consumer.h"
+#include "format.h"
+#include "parser_detail.h"
+
+#include <util/stream/input.h>
+#include <util/generic/buffer.h>
+
+namespace NYson {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TYsonParser::TImpl {
+ public:
+ TImpl(
+ NYT::NYson::IYsonConsumer* consumer,
+ IInputStream* stream,
+ EYsonType type,
+ bool enableLinePositionInfo,
+ TMaybe<ui64> memoryLimit = Nothing())
+ : Consumer_(consumer)
+ , Stream_(stream)
+ , Type_(type)
+ , EnableLinePositionInfo_(enableLinePositionInfo)
+ , MemoryLimit_(memoryLimit)
+ {
+ }
+
+ void Parse() {
+ TBuffer buffer(64 << 10);
+ ParseYsonStreamImpl<NYT::NYson::IYsonConsumer, TStreamReader>(
+ TStreamReader(Stream_, buffer.Data(), buffer.Capacity()),
+ Consumer_,
+ Type_,
+ EnableLinePositionInfo_,
+ MemoryLimit_);
+ }
+
+ private:
+ NYT::NYson::IYsonConsumer* Consumer_;
+ IInputStream* Stream_;
+ EYsonType Type_;
+ bool EnableLinePositionInfo_;
+ TMaybe<ui64> MemoryLimit_;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ TYsonParser::TYsonParser(
+ NYT::NYson::IYsonConsumer* consumer,
+ IInputStream* stream,
+ EYsonType type,
+ bool enableLinePositionInfo,
+ TMaybe<ui64> memoryLimit)
+ : Impl(new TImpl(consumer, stream, type, enableLinePositionInfo, memoryLimit))
+ {
+ }
+
+ TYsonParser::~TYsonParser() {
+ }
+
+ void TYsonParser::Parse() {
+ Impl->Parse();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TStatelessYsonParser::TImpl {
+ private:
+ THolder<TStatelessYsonParserImplBase> Impl;
+
+ public:
+ TImpl(
+ NYT::NYson::IYsonConsumer* consumer,
+ bool enableLinePositionInfo,
+ TMaybe<ui64> memoryLimit)
+ : Impl(
+ enableLinePositionInfo
+ ? static_cast<TStatelessYsonParserImplBase*>(new TStatelessYsonParserImpl<NYT::NYson::IYsonConsumer, true>(consumer, memoryLimit))
+ : static_cast<TStatelessYsonParserImplBase*>(new TStatelessYsonParserImpl<NYT::NYson::IYsonConsumer, false>(consumer, memoryLimit)))
+ {
+ }
+
+ void Parse(const TStringBuf& data, EYsonType type = ::NYson::EYsonType::Node) {
+ Impl->Parse(data, type);
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ TStatelessYsonParser::TStatelessYsonParser(
+ NYT::NYson::IYsonConsumer* consumer,
+ bool enableLinePositionInfo,
+ TMaybe<ui64> memoryLimit)
+ : Impl(new TImpl(consumer, enableLinePositionInfo, memoryLimit))
+ {
+ }
+
+ TStatelessYsonParser::~TStatelessYsonParser() {
+ }
+
+ void TStatelessYsonParser::Parse(const TStringBuf& data, EYsonType type) {
+ Impl->Parse(data, type);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ void ParseYsonStringBuffer(
+ const TStringBuf& buffer,
+ NYT::NYson::IYsonConsumer* consumer,
+ EYsonType type,
+ bool enableLinePositionInfo,
+ TMaybe<ui64> memoryLimit) {
+ ParseYsonStreamImpl<NYT::NYson::IYsonConsumer, TStringReader>(
+ TStringReader(buffer.begin(), buffer.end()),
+ consumer,
+ type,
+ enableLinePositionInfo,
+ memoryLimit);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TYsonListParser::TImpl {
+ public:
+ TImpl(
+ NYT::NYson::IYsonConsumer* consumer,
+ IInputStream* stream,
+ bool enableLinePositionInfo,
+ TMaybe<ui64> memoryLimit = Nothing())
+ : Consumer_(consumer)
+ , Stream_(stream)
+ , EnableLinePositionInfo_(enableLinePositionInfo)
+ , MemoryLimit_(memoryLimit)
+ , Buffer_(64 << 10)
+ , Reader_(Stream_, Buffer_.Data(), Buffer_.Capacity())
+ {
+ }
+
+ bool Parse() {
+ if (!Impl_) {
+ Impl_.Reset(
+ EnableLinePositionInfo_
+ ? static_cast<TYsonListParserImplBase*>(new TYsonListParserImpl<NYT::NYson::IYsonConsumer, TStreamReader, true>(Reader_, Consumer_, MemoryLimit_))
+ : static_cast<TYsonListParserImplBase*>(new TYsonListParserImpl<NYT::NYson::IYsonConsumer, TStreamReader, false>(Reader_, Consumer_, MemoryLimit_)));
+ }
+ return Impl_->Parse();
+ }
+
+ private:
+ NYT::NYson::IYsonConsumer* Consumer_;
+ IInputStream* Stream_;
+ bool EnableLinePositionInfo_;
+ TMaybe<ui64> MemoryLimit_;
+ TBuffer Buffer_;
+ TStreamReader Reader_;
+ THolder<TYsonListParserImplBase> Impl_;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ TYsonListParser::TYsonListParser(
+ NYT::NYson::IYsonConsumer* consumer,
+ IInputStream* stream,
+ bool enableLinePositionInfo,
+ TMaybe<ui64> memoryLimit)
+ : Impl(new TImpl(consumer, stream, enableLinePositionInfo, memoryLimit))
+ {
+ }
+
+ TYsonListParser::~TYsonListParser() {
+ }
+
+ bool TYsonListParser::Parse() {
+ return Impl->Parse();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/parser.h b/library/cpp/yson/parser.h
new file mode 100644
index 0000000000..dce35a8cd4
--- /dev/null
+++ b/library/cpp/yson/parser.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#include "public.h"
+
+#include <util/generic/maybe.h>
+#include <util/generic/ptr.h>
+
+class IInputStream;
+
+namespace NYT::NYson {
+struct IYsonConsumer;
+} // namespace NYT::NYson
+
+namespace NYson {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TYsonParser {
+ public:
+ TYsonParser(
+ NYT::NYson::IYsonConsumer* consumer,
+ IInputStream* stream,
+ EYsonType type = ::NYson::EYsonType::Node,
+ bool enableLinePositionInfo = false,
+ TMaybe<ui64> memoryLimit = Nothing());
+
+ ~TYsonParser();
+
+ void Parse();
+
+ private:
+ class TImpl;
+ THolder<TImpl> Impl;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TStatelessYsonParser {
+ public:
+ TStatelessYsonParser(
+ NYT::NYson::IYsonConsumer* consumer,
+ bool enableLinePositionInfo = false,
+ TMaybe<ui64> memoryLimit = Nothing());
+
+ ~TStatelessYsonParser();
+
+ void Parse(const TStringBuf& data, EYsonType type = ::NYson::EYsonType::Node);
+
+ private:
+ class TImpl;
+ THolder<TImpl> Impl;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TYsonListParser {
+ public:
+ TYsonListParser(
+ NYT::NYson::IYsonConsumer* consumer,
+ IInputStream* stream,
+ bool enableLinePositionInfo = false,
+ TMaybe<ui64> memoryLimit = Nothing());
+
+ ~TYsonListParser();
+
+ bool Parse(); // Returns false, if there is no more list items
+
+ private:
+ class TImpl;
+ THolder<TImpl> Impl;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ void ParseYsonStringBuffer(
+ const TStringBuf& buffer,
+ NYT::NYson::IYsonConsumer* consumer,
+ EYsonType type = ::NYson::EYsonType::Node,
+ bool enableLinePositionInfo = false,
+ TMaybe<ui64> memoryLimit = Nothing());
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/parser_detail.h b/library/cpp/yson/parser_detail.h
new file mode 100644
index 0000000000..44223caf12
--- /dev/null
+++ b/library/cpp/yson/parser_detail.h
@@ -0,0 +1,381 @@
+#pragma once
+
+#include "detail.h"
+
+namespace NYson {
+ namespace NDetail {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ template <class TConsumer, class TBlockStream, bool EnableLinePositionInfo>
+ class TParser
+ : public TLexerBase<TBlockStream, EnableLinePositionInfo> {
+ private:
+ using TBase = TLexerBase<TBlockStream, EnableLinePositionInfo>;
+ TConsumer* Consumer;
+
+ public:
+ TParser(const TBlockStream& blockStream, TConsumer* consumer, TMaybe<ui64> memoryLimit)
+ : TBase(blockStream, memoryLimit)
+ , Consumer(consumer)
+ {
+ }
+
+ void DoParse(EYsonType ysonType) {
+ switch (ysonType) {
+ case ::NYson::EYsonType::Node:
+ ParseNode<true>();
+ break;
+
+ case ::NYson::EYsonType::ListFragment:
+ ParseListFragment<true>(EndSymbol);
+ break;
+
+ case ::NYson::EYsonType::MapFragment:
+ ParseMapFragment<true>(EndSymbol);
+ break;
+
+ default:
+ Y_FAIL("unreachable");
+ }
+
+ while (!(TBase::IsFinished() && TBase::IsEmpty())) {
+ if (TBase::template SkipSpaceAndGetChar<true>() != EndSymbol) {
+ ythrow TYsonException() << "Stray '" << (*TBase::Begin()) << "' found";
+ } else if (!TBase::IsEmpty()) {
+ TBase::Advance(1);
+ }
+ }
+ }
+
+ bool DoParseListFragment(bool first) {
+ bool ret = first ? first : ParseListSeparator<true>(EndSymbol);
+ return ret && ParseListItem<true>(EndSymbol);
+ }
+
+ void ParseAttributes() {
+ Consumer->OnBeginAttributes();
+ ParseMapFragment(EndAttributesSymbol);
+ TBase::SkipCharToken(EndAttributesSymbol);
+ Consumer->OnEndAttributes();
+ }
+
+ void ParseMap() {
+ Consumer->OnBeginMap();
+ ParseMapFragment(EndMapSymbol);
+ TBase::SkipCharToken(EndMapSymbol);
+ Consumer->OnEndMap();
+ }
+
+ void ParseList() {
+ Consumer->OnBeginList();
+ ParseListFragment(EndListSymbol);
+ TBase::SkipCharToken(EndListSymbol);
+ Consumer->OnEndList();
+ }
+
+ template <bool AllowFinish>
+ void ParseNode() {
+ return ParseNode<AllowFinish>(TBase::SkipSpaceAndGetChar());
+ }
+
+ template <bool AllowFinish>
+ void ParseNode(char ch) {
+ if (ch == BeginAttributesSymbol) {
+ TBase::Advance(1);
+ ParseAttributes();
+ ch = TBase::SkipSpaceAndGetChar();
+ }
+
+ switch (ch) {
+ case BeginMapSymbol:
+ TBase::Advance(1);
+ ParseMap();
+ break;
+
+ case BeginListSymbol:
+ TBase::Advance(1);
+ ParseList();
+ break;
+
+ case '"': {
+ TBase::Advance(1);
+ TStringBuf value;
+ TBase::ReadQuotedString(&value);
+ Consumer->OnStringScalar(value);
+ break;
+ }
+ case StringMarker: {
+ TBase::Advance(1);
+ TStringBuf value;
+ TBase::ReadBinaryString(&value);
+ Consumer->OnStringScalar(value);
+ break;
+ }
+ case Int64Marker: {
+ TBase::Advance(1);
+ i64 value;
+ TBase::ReadBinaryInt64(&value);
+ Consumer->OnInt64Scalar(value);
+ break;
+ }
+ case Uint64Marker: {
+ TBase::Advance(1);
+ ui64 value;
+ TBase::ReadBinaryUint64(&value);
+ Consumer->OnUint64Scalar(value);
+ break;
+ }
+ case DoubleMarker: {
+ TBase::Advance(1);
+ double value;
+ TBase::ReadBinaryDouble(&value);
+ Consumer->OnDoubleScalar(value);
+ break;
+ }
+ case FalseMarker: {
+ TBase::Advance(1);
+ Consumer->OnBooleanScalar(false);
+ break;
+ }
+ case TrueMarker: {
+ TBase::Advance(1);
+ Consumer->OnBooleanScalar(true);
+ break;
+ }
+ case EntitySymbol:
+ TBase::Advance(1);
+ Consumer->OnEntity();
+ break;
+
+ default: {
+ if (isdigit((unsigned char)ch) || ch == '-' || ch == '+') { // case of '+' is handled in AfterPlus state
+ ReadNumeric<AllowFinish>();
+ } else if (isalpha((unsigned char)ch) || ch == '_') {
+ TStringBuf value;
+ TBase::template ReadUnquotedString<AllowFinish>(&value);
+ Consumer->OnStringScalar(value);
+ } else if (ch == '%') {
+ TBase::Advance(1);
+ ch = TBase::template GetChar<AllowFinish>();
+ if (ch == 't' || ch == 'f') {
+ Consumer->OnBooleanScalar(TBase::template ReadBoolean<AllowFinish>());
+ } else {
+ Consumer->OnDoubleScalar(TBase::template ReadNanOrInf<AllowFinish>());
+ }
+ } else {
+ ythrow TYsonException() << "Unexpected '" << ch << "' while parsing node";
+ }
+ }
+ }
+ }
+
+ void ParseKey() {
+ return ParseKey(TBase::SkipSpaceAndGetChar());
+ }
+
+ void ParseKey(char ch) {
+ switch (ch) {
+ case '"': {
+ TBase::Advance(1);
+ TStringBuf value;
+ TBase::ReadQuotedString(&value);
+ Consumer->OnKeyedItem(value);
+ break;
+ }
+ case StringMarker: {
+ TBase::Advance(1);
+ TStringBuf value;
+ TBase::ReadBinaryString(&value);
+ Consumer->OnKeyedItem(value);
+ break;
+ }
+ default: {
+ if (isalpha(ch) || ch == '_') {
+ TStringBuf value;
+ TBase::ReadUnquotedString(&value);
+ Consumer->OnKeyedItem(value);
+ } else {
+ ythrow TYsonException() << "Unexpected '" << ch << "' while parsing key";
+ }
+ }
+ }
+ }
+
+ template <bool AllowFinish>
+ void ParseMapFragment(char endSymbol) {
+ char ch = TBase::template SkipSpaceAndGetChar<AllowFinish>();
+ while (ch != endSymbol) {
+ ParseKey(ch);
+ ch = TBase::template SkipSpaceAndGetChar<AllowFinish>();
+ if (ch == KeyValueSeparatorSymbol) {
+ TBase::Advance(1);
+ } else {
+ ythrow TYsonException() << "Expected '" << KeyValueSeparatorSymbol << "' but '" << ch << "' found";
+ }
+ ParseNode<AllowFinish>();
+ ch = TBase::template SkipSpaceAndGetChar<AllowFinish>();
+ if (ch == KeyedItemSeparatorSymbol) {
+ TBase::Advance(1);
+ ch = TBase::template SkipSpaceAndGetChar<AllowFinish>();
+ } else if (ch != endSymbol) {
+ ythrow TYsonException() << "Expected '" << KeyedItemSeparatorSymbol
+ << "' or '" << endSymbol << "' but '" << ch << "' found";
+ }
+ }
+ }
+
+ void ParseMapFragment(char endSymbol) {
+ ParseMapFragment<false>(endSymbol);
+ }
+
+ template <bool AllowFinish>
+ bool ParseListItem(char endSymbol) {
+ char ch = TBase::template SkipSpaceAndGetChar<AllowFinish>();
+ if (ch != endSymbol) {
+ Consumer->OnListItem();
+ ParseNode<AllowFinish>(ch);
+ return true;
+ }
+ return false;
+ }
+
+ template <bool AllowFinish>
+ bool ParseListSeparator(char endSymbol) {
+ char ch = TBase::template SkipSpaceAndGetChar<AllowFinish>();
+ if (ch == ListItemSeparatorSymbol) {
+ TBase::Advance(1);
+ return true;
+ } else if (ch != endSymbol) {
+ ythrow TYsonException() << "Expected '" << ListItemSeparatorSymbol
+ << "' or '" << endSymbol << "' but '" << ch << "' found";
+ }
+ return false;
+ }
+
+ template <bool AllowFinish>
+ void ParseListFragment(char endSymbol) {
+ while (ParseListItem<AllowFinish>(endSymbol) && ParseListSeparator<AllowFinish>(endSymbol)) {
+ }
+ }
+
+ void ParseListFragment(char endSymbol) {
+ ParseListFragment<false>(endSymbol);
+ }
+
+ template <bool AllowFinish>
+ void ReadNumeric() {
+ TStringBuf valueBuffer;
+ ENumericResult numericResult = TBase::template ReadNumeric<AllowFinish>(&valueBuffer);
+
+ if (numericResult == ENumericResult::Double) {
+ double value;
+ try {
+ value = FromString<double>(valueBuffer);
+ } catch (yexception& e) {
+ // This exception is wrapped in parser.
+ ythrow TYsonException() << "Failed to parse double literal '" << valueBuffer << "'" << e;
+ }
+ Consumer->OnDoubleScalar(value);
+ } else if (numericResult == ENumericResult::Int64) {
+ i64 value;
+ try {
+ value = FromString<i64>(valueBuffer);
+ } catch (yexception& e) {
+ // This exception is wrapped in parser.
+ ythrow TYsonException() << "Failed to parse int64 literal '" << valueBuffer << "'" << e;
+ }
+ Consumer->OnInt64Scalar(value);
+ } else if (numericResult == ENumericResult::Uint64) {
+ ui64 value;
+ try {
+ value = FromString<ui64>(valueBuffer.SubStr(0, valueBuffer.size() - 1));
+ } catch (yexception& e) {
+ // This exception is wrapped in parser.
+ ythrow TYsonException() << "Failed to parse uint64 literal '" << valueBuffer << "'" << e;
+ }
+ Consumer->OnUint64Scalar(value);
+ }
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ }
+
+ template <class TConsumer, class TBlockStream>
+ void ParseYsonStreamImpl(
+ const TBlockStream& blockStream,
+ NYT::NYson::IYsonConsumer* consumer,
+ EYsonType parsingMode,
+ bool enableLinePositionInfo,
+ TMaybe<ui64> memoryLimit) {
+ if (enableLinePositionInfo) {
+ using TImpl = NDetail::TParser<TConsumer, TBlockStream, true>;
+ TImpl impl(blockStream, consumer, memoryLimit);
+ impl.DoParse(parsingMode);
+ } else {
+ using TImpl = NDetail::TParser<TConsumer, TBlockStream, false>;
+ TImpl impl(blockStream, consumer, memoryLimit);
+ impl.DoParse(parsingMode);
+ }
+ }
+
+ class TStatelessYsonParserImplBase {
+ public:
+ virtual void Parse(const TStringBuf& data, EYsonType type = ::NYson::EYsonType::Node) = 0;
+
+ virtual ~TStatelessYsonParserImplBase() {
+ }
+ };
+
+ template <class TConsumer, bool EnableLinePositionInfo>
+ class TStatelessYsonParserImpl
+ : public TStatelessYsonParserImplBase {
+ private:
+ using TParser = NDetail::TParser<TConsumer, TStringReader, EnableLinePositionInfo>;
+ TParser Parser;
+
+ public:
+ TStatelessYsonParserImpl(TConsumer* consumer, TMaybe<ui64> memoryLimit)
+ : Parser(TStringReader(), consumer, memoryLimit)
+ {
+ }
+
+ void Parse(const TStringBuf& data, EYsonType type = ::NYson::EYsonType::Node) override {
+ Parser.SetBuffer(data.begin(), data.end());
+ Parser.DoParse(type);
+ }
+ };
+
+ class TYsonListParserImplBase {
+ public:
+ virtual bool Parse() = 0;
+
+ virtual ~TYsonListParserImplBase() {
+ }
+ };
+
+ template <class TConsumer, class TBlockStream, bool EnableLinePositionInfo>
+ class TYsonListParserImpl
+ : public TYsonListParserImplBase {
+ private:
+ using TParser = NDetail::TParser<TConsumer, TBlockStream, EnableLinePositionInfo>;
+ TParser Parser;
+ bool First = true;
+
+ public:
+ TYsonListParserImpl(const TBlockStream& blockStream, TConsumer* consumer, TMaybe<ui64> memoryLimit)
+ : Parser(blockStream, consumer, memoryLimit)
+ {
+ }
+
+ bool Parse() override {
+ bool ret = Parser.DoParseListFragment(First);
+ First = false;
+ return ret;
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/public.h b/library/cpp/yson/public.h
new file mode 100644
index 0000000000..1ed793592b
--- /dev/null
+++ b/library/cpp/yson/public.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <library/cpp/yt/misc/enum.h>
+#include <util/generic/yexception.h>
+
+#include <library/cpp/yt/yson_string/public.h>
+#include <library/cpp/yt/yson/public.h>
+
+namespace NYson {
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ using NYT::NYson::EYsonFormat;
+ using NYT::NYson::EYsonType;
+
+ class TYsonStringBuf;
+
+ struct TYsonConsumerBase;
+
+ class TYsonWriter;
+ class TYsonParser;
+ class TStatelessYsonParser;
+ class TYsonListParser;
+
+ class TYsonException
+ : public yexception {};
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/string-inl.h b/library/cpp/yson/string-inl.h
new file mode 100644
index 0000000000..92e9ab4531
--- /dev/null
+++ b/library/cpp/yson/string-inl.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#ifndef STRING_INL_H_
+#error "Direct inclusion of this file is not allowed, include string.h"
+// For the sake of sane code completion.
+#include "string.h"
+#endif
+
+#include <util/str_stl.h>
+
+namespace NYson {
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace NDetail {
+
+template <typename TLeft, typename TRight>
+bool Equals(const TLeft& lhs, const TRight& rhs)
+{
+ auto lhsNull = !lhs.operator bool();
+ auto rhsNull = !rhs.operator bool();
+ if (lhsNull != rhsNull) {
+ return false;
+ }
+ if (lhsNull && rhsNull) {
+ return true;
+ }
+ return
+ lhs.AsStringBuf() == rhs.AsStringBuf() &&
+ lhs.GetType() == rhs.GetType();
+}
+
+} // namespace NDetail
+
+inline bool operator == (const TYsonStringBuf& lhs, const TYsonStringBuf& rhs)
+{
+ return NDetail::Equals(lhs, rhs);
+}
+
+inline bool operator != (const TYsonStringBuf& lhs, const TYsonStringBuf& rhs)
+{
+ return !(lhs == rhs);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
+
+//! A hasher for TYsonStringBuf
+template <>
+struct THash<NYson::TYsonStringBuf>
+{
+ size_t operator () (const NYson::TYsonStringBuf& str) const
+ {
+ return THash<TStringBuf>()(str.AsStringBuf());
+ }
+};
diff --git a/library/cpp/yson/token.cpp b/library/cpp/yson/token.cpp
new file mode 100644
index 0000000000..c8584c8c2e
--- /dev/null
+++ b/library/cpp/yson/token.cpp
@@ -0,0 +1,236 @@
+#include "token.h"
+
+#include <util/string/vector.h>
+#include <util/string/printf.h>
+
+namespace NYson {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ ETokenType CharToTokenType(char ch) {
+ switch (ch) {
+ case ';':
+ return ETokenType::Semicolon;
+ case '=':
+ return ETokenType::Equals;
+ case '{':
+ return ETokenType::LeftBrace;
+ case '}':
+ return ETokenType::RightBrace;
+ case '#':
+ return ETokenType::Hash;
+ case '[':
+ return ETokenType::LeftBracket;
+ case ']':
+ return ETokenType::RightBracket;
+ case '<':
+ return ETokenType::LeftAngle;
+ case '>':
+ return ETokenType::RightAngle;
+ case '(':
+ return ETokenType::LeftParenthesis;
+ case ')':
+ return ETokenType::RightParenthesis;
+ case '+':
+ return ETokenType::Plus;
+ case ':':
+ return ETokenType::Colon;
+ case ',':
+ return ETokenType::Comma;
+ default:
+ return ETokenType::EndOfStream;
+ }
+ }
+
+ char TokenTypeToChar(ETokenType type) {
+ switch (type) {
+ case ETokenType::Semicolon:
+ return ';';
+ case ETokenType::Equals:
+ return '=';
+ case ETokenType::Hash:
+ return '#';
+ case ETokenType::LeftBracket:
+ return '[';
+ case ETokenType::RightBracket:
+ return ']';
+ case ETokenType::LeftBrace:
+ return '{';
+ case ETokenType::RightBrace:
+ return '}';
+ case ETokenType::LeftAngle:
+ return '<';
+ case ETokenType::RightAngle:
+ return '>';
+ case ETokenType::LeftParenthesis:
+ return '(';
+ case ETokenType::RightParenthesis:
+ return ')';
+ case ETokenType::Plus:
+ return '+';
+ case ETokenType::Colon:
+ return ':';
+ case ETokenType::Comma:
+ return ',';
+ default:
+ Y_FAIL("unreachable");
+ }
+ }
+
+ TString TokenTypeToString(ETokenType type) {
+ return TString(1, TokenTypeToChar(type));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ const TToken TToken::EndOfStream;
+
+ TToken::TToken()
+ : Type_(ETokenType::EndOfStream)
+ , Int64Value(0)
+ , Uint64Value(0)
+ , DoubleValue(0.0)
+ , BooleanValue(false)
+ {
+ }
+
+ TToken::TToken(ETokenType type)
+ : Type_(type)
+ , Int64Value(0)
+ , Uint64Value(0)
+ , DoubleValue(0.0)
+ , BooleanValue(false)
+ {
+ switch (type) {
+ case ETokenType::String:
+ case ETokenType::Int64:
+ case ETokenType::Uint64:
+ case ETokenType::Double:
+ case ETokenType::Boolean:
+ Y_FAIL("unreachable");
+ default:
+ break;
+ }
+ }
+
+ TToken::TToken(const TStringBuf& stringValue)
+ : Type_(ETokenType::String)
+ , StringValue(stringValue)
+ , Int64Value(0)
+ , Uint64Value(0)
+ , DoubleValue(0.0)
+ , BooleanValue(false)
+ {
+ }
+
+ TToken::TToken(i64 int64Value)
+ : Type_(ETokenType::Int64)
+ , Int64Value(int64Value)
+ , Uint64Value(0)
+ , DoubleValue(0.0)
+ {
+ }
+
+ TToken::TToken(ui64 uint64Value)
+ : Type_(ETokenType::Uint64)
+ , Int64Value(0)
+ , Uint64Value(uint64Value)
+ , DoubleValue(0.0)
+ , BooleanValue(false)
+ {
+ }
+
+ TToken::TToken(double doubleValue)
+ : Type_(ETokenType::Double)
+ , Int64Value(0)
+ , Uint64Value(0)
+ , DoubleValue(doubleValue)
+ , BooleanValue(false)
+ {
+ }
+
+ TToken::TToken(bool booleanValue)
+ : Type_(ETokenType::Boolean)
+ , Int64Value(0)
+ , DoubleValue(0.0)
+ , BooleanValue(booleanValue)
+ {
+ }
+
+ bool TToken::IsEmpty() const {
+ return Type_ == ETokenType::EndOfStream;
+ }
+
+ const TStringBuf& TToken::GetStringValue() const {
+ CheckType(ETokenType::String);
+ return StringValue;
+ }
+
+ i64 TToken::GetInt64Value() const {
+ CheckType(ETokenType::Int64);
+ return Int64Value;
+ }
+
+ ui64 TToken::GetUint64Value() const {
+ CheckType(ETokenType::Uint64);
+ return Uint64Value;
+ }
+
+ double TToken::GetDoubleValue() const {
+ CheckType(ETokenType::Double);
+ return DoubleValue;
+ }
+
+ bool TToken::GetBooleanValue() const {
+ CheckType(ETokenType::Boolean);
+ return BooleanValue;
+ }
+
+ void TToken::CheckType(ETokenType expectedType) const {
+ if (Type_ != expectedType) {
+ if (Type_ == ETokenType::EndOfStream) {
+ ythrow TYsonException() << "Unexpected end of stream (ExpectedType: " << TokenTypeToString(expectedType) << ")";
+ } else {
+ ythrow TYsonException() << "Unexpected token (Token: '" << ToString(*this)
+ << "', Type: " << TokenTypeToString(Type_)
+ << ", ExpectedType: " << TokenTypeToString(expectedType) << ")";
+ }
+ }
+ }
+
+ void TToken::Reset() {
+ Type_ = ETokenType::EndOfStream;
+ Int64Value = 0;
+ Uint64Value = 0;
+ DoubleValue = 0.0;
+ StringValue = TStringBuf();
+ BooleanValue = false;
+ }
+
+ TString ToString(const TToken& token) {
+ switch (token.GetType()) {
+ case ETokenType::EndOfStream:
+ return TString();
+
+ case ETokenType::String:
+ return TString(token.GetStringValue());
+
+ case ETokenType::Int64:
+ return ::ToString(token.GetInt64Value());
+
+ case ETokenType::Uint64:
+ return ::ToString(token.GetUint64Value());
+
+ case ETokenType::Double:
+ return ::ToString(token.GetDoubleValue());
+
+ case ETokenType::Boolean:
+ return token.GetBooleanValue() ? "true" : "false";
+
+ default:
+ return TokenTypeToString(token.GetType());
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/token.h b/library/cpp/yson/token.h
new file mode 100644
index 0000000000..7283e56950
--- /dev/null
+++ b/library/cpp/yson/token.h
@@ -0,0 +1,93 @@
+#pragma once
+
+#include "public.h"
+
+#include <util/generic/strbuf.h>
+
+namespace NYson {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ enum ETokenType {
+ EndOfStream,
+
+ String,
+ Int64,
+ Uint64,
+ Double,
+ Boolean,
+
+ // Special values:
+ // YSON
+ Semicolon, // ;
+ Equals, // =
+ Hash, // #
+ LeftBracket, // [
+ RightBracket, // ]
+ LeftBrace, // {
+ RightBrace, // }
+ LeftAngle, // <
+ RightAngle, // >
+
+ // Table ranges
+ LeftParenthesis, // (
+ RightParenthesis, // )
+ Plus, // +
+ Colon, // :
+ Comma, // ,
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ ETokenType CharToTokenType(char ch);
+ char TokenTypeToChar(ETokenType type);
+ TString TokenTypeToString(ETokenType type);
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TLexerImpl;
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TToken {
+ public:
+ static const TToken EndOfStream;
+
+ TToken();
+ TToken(ETokenType type);
+ explicit TToken(const TStringBuf& stringValue);
+ explicit TToken(i64 int64Value);
+ explicit TToken(ui64 int64Value);
+ explicit TToken(double doubleValue);
+ explicit TToken(bool booleanValue);
+
+ ETokenType GetType() const {
+ return Type_;
+ }
+
+ bool IsEmpty() const;
+ const TStringBuf& GetStringValue() const;
+ i64 GetInt64Value() const;
+ ui64 GetUint64Value() const;
+ double GetDoubleValue() const;
+ bool GetBooleanValue() const;
+
+ void CheckType(ETokenType expectedType) const;
+ void Reset();
+
+ private:
+ friend class TLexerImpl;
+
+ ETokenType Type_;
+
+ TStringBuf StringValue;
+ i64 Int64Value;
+ ui64 Uint64Value;
+ double DoubleValue;
+ bool BooleanValue;
+ };
+
+ TString ToString(const TToken& token);
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/tokenizer.cpp b/library/cpp/yson/tokenizer.cpp
new file mode 100644
index 0000000000..06760170d4
--- /dev/null
+++ b/library/cpp/yson/tokenizer.cpp
@@ -0,0 +1,37 @@
+#include "tokenizer.h"
+
+namespace NYson {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ TTokenizer::TTokenizer(const TStringBuf& input)
+ : Input(input)
+ , Parsed(0)
+ {
+ }
+
+ bool TTokenizer::ParseNext() {
+ Input = Input.Tail(Parsed);
+ Token.Reset();
+ Parsed = Lexer.GetToken(Input, &Token);
+ return !CurrentToken().IsEmpty();
+ }
+
+ const TToken& TTokenizer::CurrentToken() const {
+ return Token;
+ }
+
+ ETokenType TTokenizer::GetCurrentType() const {
+ return CurrentToken().GetType();
+ }
+
+ TStringBuf TTokenizer::GetCurrentSuffix() const {
+ return Input.Tail(Parsed);
+ }
+
+ const TStringBuf& TTokenizer::CurrentInput() const {
+ return Input;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/tokenizer.h b/library/cpp/yson/tokenizer.h
new file mode 100644
index 0000000000..0576aace95
--- /dev/null
+++ b/library/cpp/yson/tokenizer.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "public.h"
+#include "lexer.h"
+
+namespace NYson {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TTokenizer {
+ public:
+ explicit TTokenizer(const TStringBuf& input);
+
+ bool ParseNext();
+ const TToken& CurrentToken() const;
+ ETokenType GetCurrentType() const;
+ TStringBuf GetCurrentSuffix() const;
+ const TStringBuf& CurrentInput() const;
+
+ private:
+ TStringBuf Input;
+ TToken Token;
+ TStatelessLexer Lexer;
+ size_t Parsed;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/varint.cpp b/library/cpp/yson/varint.cpp
new file mode 100644
index 0000000000..d538ee3cff
--- /dev/null
+++ b/library/cpp/yson/varint.cpp
@@ -0,0 +1,71 @@
+#include "varint.h"
+
+#include "zigzag.h"
+
+#include <util/generic/yexception.h>
+
+namespace NYson {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ int WriteVarUInt64(IOutputStream* output, ui64 value) {
+ bool stop = false;
+ int bytesWritten = 0;
+ while (!stop) {
+ ++bytesWritten;
+ ui8 byte = static_cast<ui8>(value | 0x80);
+ value >>= 7;
+ if (value == 0) {
+ stop = true;
+ byte &= 0x7F;
+ }
+ output->Write(byte);
+ }
+ return bytesWritten;
+ }
+
+ int WriteVarInt32(IOutputStream* output, i32 value) {
+ return WriteVarUInt64(output, static_cast<ui64>(ZigZagEncode32(value)));
+ }
+
+ int WriteVarInt64(IOutputStream* output, i64 value) {
+ return WriteVarUInt64(output, static_cast<ui64>(ZigZagEncode64(value)));
+ }
+
+ int ReadVarUInt64(IInputStream* input, ui64* value) {
+ size_t count = 0;
+ ui64 result = 0;
+
+ ui8 byte = 0;
+ do {
+ if (7 * count > 8 * sizeof(ui64)) {
+ ythrow yexception() << "The data is too long to read ui64";
+ }
+ if (input->Read(&byte, 1) != 1) {
+ ythrow yexception() << "The data is too long to read ui64";
+ }
+ result |= (static_cast<ui64>(byte & 0x7F)) << (7 * count);
+ ++count;
+ } while (byte & 0x80);
+
+ *value = result;
+ return count;
+ }
+
+ int ReadVarInt32(IInputStream* input, i32* value) {
+ ui64 varInt;
+ int bytesRead = ReadVarUInt64(input, &varInt);
+ if (varInt > Max<ui32>()) {
+ ythrow yexception() << "The data is too long to read ui64";
+ }
+ *value = ZigZagDecode32(static_cast<ui32>(varInt));
+ return bytesRead;
+ }
+
+ int ReadVarInt64(IInputStream* input, i64* value) {
+ ui64 varInt;
+ int bytesRead = ReadVarUInt64(input, &varInt);
+ *value = ZigZagDecode64(varInt);
+ return bytesRead;
+ }
+
+} // namespace NYson
diff --git a/library/cpp/yson/varint.h b/library/cpp/yson/varint.h
new file mode 100644
index 0000000000..80b1184e57
--- /dev/null
+++ b/library/cpp/yson/varint.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <util/stream/input.h>
+#include <util/stream/output.h>
+#include <util/system/defaults.h>
+
+namespace NYson {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ // Various functions that read/write varints from/to a stream.
+
+ // Returns the number of bytes written.
+ int WriteVarUInt64(IOutputStream* output, ui64 value);
+ int WriteVarInt32(IOutputStream* output, i32 value);
+ int WriteVarInt64(IOutputStream* output, i64 value);
+
+ // Returns the number of bytes read.
+ int ReadVarUInt64(IInputStream* input, ui64* value);
+ int ReadVarInt32(IInputStream* input, i32* value);
+ int ReadVarInt64(IInputStream* input, i64* value);
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/writer.cpp b/library/cpp/yson/writer.cpp
new file mode 100644
index 0000000000..054459f9f5
--- /dev/null
+++ b/library/cpp/yson/writer.cpp
@@ -0,0 +1,355 @@
+#include "writer.h"
+
+#include "detail.h"
+#include "format.h"
+#include "parser.h"
+#include "varint.h"
+#include "zigzag.h"
+
+#include <util/string/cast.h>
+
+#include <cmath>
+
+namespace NYson {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ // Copied from <util/string/escape.cpp>
+ namespace {
+ inline char HexDigit(char value) {
+ Y_ASSERT(value < 16);
+ if (value < 10)
+ return '0' + value;
+ else
+ return 'A' + value - 10;
+ }
+
+ inline char OctDigit(char value) {
+ Y_ASSERT(value < 8);
+ return '0' + value;
+ }
+
+ inline bool IsPrintable(char c) {
+ return c >= 32 && c <= 126;
+ }
+
+ inline bool IsHexDigit(char c) {
+ return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
+ }
+
+ inline bool IsOctDigit(char c) {
+ return c >= '0' && c <= '7';
+ }
+
+ const size_t ESCAPE_C_BUFFER_SIZE = 4;
+
+ inline size_t EscapeC(unsigned char c, char next, char r[ESCAPE_C_BUFFER_SIZE]) {
+ // (1) Printable characters go as-is, except backslash and double quote.
+ // (2) Characters \r, \n, \t and \0 ... \7 replaced by their simple escape characters (if possible).
+ // (3) Otherwise, character is encoded using hexadecimal escape sequence (if possible), or octal.
+ if (c == '\"') {
+ r[0] = '\\';
+ r[1] = '\"';
+ return 2;
+ } else if (c == '\\') {
+ r[0] = '\\';
+ r[1] = '\\';
+ return 2;
+ } else if (IsPrintable(c)) {
+ r[0] = c;
+ return 1;
+ } else if (c == '\r') {
+ r[0] = '\\';
+ r[1] = 'r';
+ return 2;
+ } else if (c == '\n') {
+ r[0] = '\\';
+ r[1] = 'n';
+ return 2;
+ } else if (c == '\t') {
+ r[0] = '\\';
+ r[1] = 't';
+ return 2;
+ } else if (c < 8 && !IsOctDigit(next)) {
+ r[0] = '\\';
+ r[1] = OctDigit(c);
+ return 2;
+ } else if (!IsHexDigit(next)) {
+ r[0] = '\\';
+ r[1] = 'x';
+ r[2] = HexDigit((c & 0xF0) >> 4);
+ r[3] = HexDigit((c & 0x0F) >> 0);
+ return 4;
+ } else {
+ r[0] = '\\';
+ r[1] = OctDigit((c & 0700) >> 6);
+ r[2] = OctDigit((c & 0070) >> 3);
+ r[3] = OctDigit((c & 0007) >> 0);
+ return 4;
+ }
+ }
+
+ void EscapeC(const char* str, size_t len, IOutputStream& output) {
+ char buffer[ESCAPE_C_BUFFER_SIZE];
+
+ size_t i, j;
+ for (i = 0, j = 0; i < len; ++i) {
+ size_t rlen = EscapeC(str[i], (i + 1 < len ? str[i + 1] : 0), buffer);
+
+ if (rlen > 1) {
+ output.Write(str + j, i - j);
+ j = i + 1;
+ output.Write(buffer, rlen);
+ }
+ }
+
+ if (j > 0) {
+ output.Write(str + j, len - j);
+ } else {
+ output.Write(str, len);
+ }
+ }
+
+ TString FloatToStringWithNanInf(double value) {
+ if (std::isfinite(value)) {
+ return ::ToString(value);
+ }
+
+ static const TStringBuf nanLiteral = "%nan";
+ static const TStringBuf infLiteral = "%inf";
+ static const TStringBuf negativeInfLiteral = "%-inf";
+
+ TStringBuf str;
+ if (std::isnan(value)) {
+ str = nanLiteral;
+ } else if (value > 0) {
+ str = infLiteral;
+ } else {
+ str = negativeInfLiteral;
+ }
+ return TString(str.data(), str.size());
+ }
+
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ TYsonWriter::TYsonWriter(
+ IOutputStream* stream,
+ EYsonFormat format,
+ EYsonType type,
+ bool enableRaw)
+ : Stream(stream)
+ , Format(format)
+ , Type(type)
+ , EnableRaw(enableRaw)
+ , Depth(0)
+ , BeforeFirstItem(true)
+ {
+ Y_ASSERT(stream);
+ }
+
+ void TYsonWriter::WriteIndent() {
+ for (int i = 0; i < IndentSize * Depth; ++i) {
+ Stream->Write(' ');
+ }
+ }
+
+ bool TYsonWriter::IsTopLevelFragmentContext() const {
+ return Depth == 0 && (Type == ::NYson::EYsonType::ListFragment || Type == ::NYson::EYsonType::MapFragment);
+ }
+
+ void TYsonWriter::EndNode() {
+ if (IsTopLevelFragmentContext()) {
+ ETokenType separatorToken =
+ Type == ::NYson::EYsonType::ListFragment
+ ? ListItemSeparatorToken
+ : KeyedItemSeparatorToken;
+ Stream->Write(TokenTypeToChar(separatorToken));
+ if (Format == EYsonFormat::Text || Format == EYsonFormat::Pretty) {
+ Stream->Write('\n');
+ }
+ }
+ }
+
+ void TYsonWriter::BeginCollection(ETokenType beginToken) {
+ Stream->Write(TokenTypeToChar(beginToken));
+ ++Depth;
+ BeforeFirstItem = true;
+ }
+
+ void TYsonWriter::CollectionItem(ETokenType separatorToken) {
+ if (!IsTopLevelFragmentContext()) {
+ if (!BeforeFirstItem) {
+ Stream->Write(TokenTypeToChar(separatorToken));
+ }
+
+ if (Format == EYsonFormat::Pretty) {
+ Stream->Write('\n');
+ WriteIndent();
+ }
+ }
+
+ BeforeFirstItem = false;
+ }
+
+ void TYsonWriter::EndCollection(ETokenType endToken) {
+ --Depth;
+ if (Format == EYsonFormat::Pretty && !BeforeFirstItem) {
+ Stream->Write('\n');
+ WriteIndent();
+ }
+ Stream->Write(TokenTypeToChar(endToken));
+ BeforeFirstItem = false;
+ }
+
+ void TYsonWriter::WriteStringScalar(const TStringBuf& value) {
+ if (Format == EYsonFormat::Binary) {
+ Stream->Write(NDetail::StringMarker);
+ WriteVarInt32(Stream, static_cast<i32>(value.length()));
+ Stream->Write(value.begin(), value.length());
+ } else {
+ Stream->Write('"');
+ EscapeC(value.data(), value.length(), *Stream);
+ Stream->Write('"');
+ }
+ }
+
+ void TYsonWriter::OnStringScalar(TStringBuf value) {
+ WriteStringScalar(value);
+ EndNode();
+ }
+
+ void TYsonWriter::OnInt64Scalar(i64 value) {
+ if (Format == EYsonFormat::Binary) {
+ Stream->Write(NDetail::Int64Marker);
+ WriteVarInt64(Stream, value);
+ } else {
+ Stream->Write(::ToString(value));
+ }
+ EndNode();
+ }
+
+ void TYsonWriter::OnUint64Scalar(ui64 value) {
+ if (Format == EYsonFormat::Binary) {
+ Stream->Write(NDetail::Uint64Marker);
+ WriteVarUInt64(Stream, value);
+ } else {
+ Stream->Write(::ToString(value));
+ Stream->Write("u");
+ }
+ EndNode();
+ }
+
+ void TYsonWriter::OnDoubleScalar(double value) {
+ if (Format == EYsonFormat::Binary) {
+ Stream->Write(NDetail::DoubleMarker);
+ Stream->Write(&value, sizeof(double));
+ } else {
+ auto str = FloatToStringWithNanInf(value);
+ Stream->Write(str);
+ if (str.find('.') == TString::npos && str.find('e') == TString::npos && std::isfinite(value)) {
+ Stream->Write(".");
+ }
+ }
+ EndNode();
+ }
+
+ void TYsonWriter::OnBooleanScalar(bool value) {
+ if (Format == EYsonFormat::Binary) {
+ Stream->Write(value ? NDetail::TrueMarker : NDetail::FalseMarker);
+ } else {
+ Stream->Write(value ? "%true" : "%false");
+ }
+ EndNode();
+ }
+
+ void TYsonWriter::OnEntity() {
+ Stream->Write(TokenTypeToChar(EntityToken));
+ EndNode();
+ }
+
+ void TYsonWriter::OnBeginList() {
+ BeginCollection(BeginListToken);
+ }
+
+ void TYsonWriter::OnListItem() {
+ CollectionItem(ListItemSeparatorToken);
+ }
+
+ void TYsonWriter::OnEndList() {
+ EndCollection(EndListToken);
+ EndNode();
+ }
+
+ void TYsonWriter::OnBeginMap() {
+ BeginCollection(BeginMapToken);
+ }
+
+ void TYsonWriter::OnKeyedItem(TStringBuf key) {
+ CollectionItem(KeyedItemSeparatorToken);
+
+ WriteStringScalar(key);
+
+ if (Format == NYson::EYsonFormat::Pretty) {
+ Stream->Write(' ');
+ }
+ Stream->Write(TokenTypeToChar(KeyValueSeparatorToken));
+ if (Format == NYson::EYsonFormat::Pretty) {
+ Stream->Write(' ');
+ }
+
+ BeforeFirstItem = false;
+ }
+
+ void TYsonWriter::OnEndMap() {
+ EndCollection(EndMapToken);
+ EndNode();
+ }
+
+ void TYsonWriter::OnBeginAttributes() {
+ BeginCollection(BeginAttributesToken);
+ }
+
+ void TYsonWriter::OnEndAttributes() {
+ EndCollection(EndAttributesToken);
+ if (Format == NYson::EYsonFormat::Pretty) {
+ Stream->Write(' ');
+ }
+ }
+
+ void TYsonWriter::OnRaw(TStringBuf yson, EYsonType type) {
+ if (EnableRaw) {
+ Stream->Write(yson);
+ BeforeFirstItem = false;
+ } else {
+ TYsonConsumerBase::OnRaw(yson, type);
+ }
+ }
+
+ TYsonWriter::TState TYsonWriter::State() const {
+ TState state;
+ state.Depth = Depth;
+ state.BeforeFirstItem = BeforeFirstItem;
+ return state;
+ }
+
+ void TYsonWriter::Reset(const TState& state) {
+ Depth = state.Depth;
+ BeforeFirstItem = state.BeforeFirstItem;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ void ReformatYsonStream(
+ IInputStream* input,
+ IOutputStream* output,
+ EYsonFormat format,
+ EYsonType type) {
+ TYsonWriter writer(output, format, type);
+ TYsonParser parser(&writer, input, type);
+ parser.Parse();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/writer.h b/library/cpp/yson/writer.h
new file mode 100644
index 0000000000..40f5d7d501
--- /dev/null
+++ b/library/cpp/yson/writer.h
@@ -0,0 +1,89 @@
+#pragma once
+
+#include "public.h"
+#include "token.h"
+#include "consumer.h"
+
+#include <util/generic/noncopyable.h>
+
+class IOutputStream;
+class IZeroCopyInput;
+
+namespace NYson {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ class TYsonWriter
+ : public TYsonConsumerBase,
+ private TNonCopyable {
+ public:
+ class TState {
+ private:
+ int Depth;
+ bool BeforeFirstItem;
+
+ friend class TYsonWriter;
+ };
+
+ public:
+ TYsonWriter(
+ IOutputStream* stream,
+ EYsonFormat format = EYsonFormat::Binary,
+ EYsonType type = ::NYson::EYsonType::Node,
+ bool enableRaw = false);
+
+ void OnStringScalar(TStringBuf value) override;
+ void OnInt64Scalar(i64 value) override;
+ void OnUint64Scalar(ui64 value) override;
+ void OnDoubleScalar(double value) override;
+ void OnBooleanScalar(bool value) override;
+ void OnEntity() override;
+
+ void OnBeginList() override;
+ void OnListItem() override;
+ void OnEndList() override;
+
+ void OnBeginMap() override;
+ void OnKeyedItem(TStringBuf key) override;
+ void OnEndMap() override;
+
+ void OnBeginAttributes() override;
+ void OnEndAttributes() override;
+
+ void OnRaw(TStringBuf yson, EYsonType type = ::NYson::EYsonType::Node) override;
+
+ TState State() const;
+ void Reset(const TState& state);
+
+ protected:
+ IOutputStream* Stream;
+ EYsonFormat Format;
+ EYsonType Type;
+ bool EnableRaw;
+
+ int Depth;
+ bool BeforeFirstItem;
+
+ static const int IndentSize = 4;
+
+ void WriteIndent();
+ void WriteStringScalar(const TStringBuf& value);
+
+ void BeginCollection(ETokenType beginToken);
+ void CollectionItem(ETokenType separatorToken);
+ void EndCollection(ETokenType endToken);
+
+ bool IsTopLevelFragmentContext() const;
+ void EndNode();
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+ void ReformatYsonStream(
+ IInputStream* input,
+ IOutputStream* output,
+ EYsonFormat format = EYsonFormat::Binary,
+ EYsonType type = ::NYson::EYsonType::Node);
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson/ya.make b/library/cpp/yson/ya.make
new file mode 100644
index 0000000000..c55a189b10
--- /dev/null
+++ b/library/cpp/yson/ya.make
@@ -0,0 +1,23 @@
+LIBRARY()
+
+OWNER(
+ ermolovd
+ g:yt
+)
+
+PEERDIR(
+ library/cpp/yt/misc
+ library/cpp/yt/yson
+)
+
+SRCS(
+ consumer.cpp
+ lexer.cpp
+ parser.cpp
+ token.cpp
+ tokenizer.cpp
+ varint.cpp
+ writer.cpp
+)
+
+END()
diff --git a/library/cpp/yson/zigzag.h b/library/cpp/yson/zigzag.h
new file mode 100644
index 0000000000..2f1190508f
--- /dev/null
+++ b/library/cpp/yson/zigzag.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <util/system/defaults.h>
+
+namespace NYson {
+ ////////////////////////////////////////////////////////////////////////////////
+
+ //! Functions that provide coding of integers with property: 0 <= f(x) <= 2 * |x|
+ //! Actually taken 'as is' from protobuf/wire_format_lite.h
+
+ inline ui32 ZigZagEncode32(i32 n) {
+ // Note: the right-shift must be arithmetic
+ return (ui32(n) << 1) ^ (n >> 31);
+ }
+
+ inline i32 ZigZagDecode32(ui32 n) {
+ return (n >> 1) ^ -static_cast<i32>(n & 1);
+ }
+
+ inline ui64 ZigZagEncode64(i64 n) {
+ // Note: the right-shift must be arithmetic
+ return (ui64(n) << 1) ^ (n >> 63);
+ }
+
+ inline i64 ZigZagDecode64(ui64 n) {
+ return (n >> 1) ^ -static_cast<i64>(n & 1);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYson
diff --git a/library/cpp/yson_pull/bridge.h b/library/cpp/yson_pull/bridge.h
new file mode 100644
index 0000000000..ac767dcba0
--- /dev/null
+++ b/library/cpp/yson_pull/bridge.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "consumer.h"
+#include "event.h"
+#include "writer.h"
+
+namespace NYsonPull {
+ //! \brief Connect YSON stream producer and consumer.
+ //!
+ //! Useful for writing YSON stream filters.
+ //! \p Producer must have a \p next_event() method (like \p NYsonPull::reader).
+ //! \p Consumer must be like \p NYsonPull::consumer interface.
+ template <typename Producer, typename Consumer>
+ inline void Bridge(Producer&& producer, Consumer&& consumer) {
+ for (;;) {
+ auto& event = producer.NextEvent();
+ consumer.OnEvent(event);
+ if (event.Type() == EEventType::EndStream) {
+ break;
+ }
+ }
+ }
+
+ template <typename Producer>
+ inline void Bridge(Producer&& producer, TWriter& writer_) {
+ Bridge(std::forward<Producer>(producer), writer_.GetConsumer());
+ }
+
+ template <typename Producer>
+ inline void Bridge(Producer&& producer, TWriter&& writer_) {
+ Bridge(std::forward<Producer>(producer), writer_.GetConsumer());
+ }
+
+}
diff --git a/library/cpp/yson_pull/buffer.h b/library/cpp/yson_pull/buffer.h
new file mode 100644
index 0000000000..04c9220ef3
--- /dev/null
+++ b/library/cpp/yson_pull/buffer.h
@@ -0,0 +1,79 @@
+#pragma once
+
+#include <util/system/types.h>
+#include <util/system/yassert.h>
+
+#include <cstddef>
+
+namespace NYsonPull {
+ //! \brief A non-owning buffer model.
+ //!
+ //! Represents a \p pos pointer moving between \p begin and \p end.
+ template <typename T>
+ class buffer {
+ T* begin_ = nullptr;
+ T* pos_ = nullptr;
+ T* end_ = nullptr;
+
+ public:
+ T* begin() const noexcept {
+ return begin_;
+ }
+ T* pos() const noexcept {
+ return pos_;
+ }
+ T* end() const noexcept {
+ return end_;
+ }
+
+ //! \brief Amount of data after current position.
+ size_t available() const noexcept {
+ return end_ - pos_;
+ }
+
+ //! \brief Amount of data before current position.
+ size_t used() const noexcept {
+ return pos_ - begin_;
+ }
+
+ //! \brief Move current position \p nbytes forward.
+ void advance(size_t nbytes) noexcept {
+ Y_ASSERT(pos_ + nbytes <= end_);
+ pos_ += nbytes;
+ }
+
+ //! \brief Reset buffer pointers.
+ void reset(T* new_begin, T* new_end, T* new_pos) {
+ begin_ = new_begin;
+ pos_ = new_pos;
+ end_ = new_end;
+ }
+
+ //! \brief Reset buffer to beginning
+ void reset(T* new_begin, T* new_end) {
+ reset(new_begin, new_end, new_begin);
+ }
+ };
+
+ class output_buffer: public buffer<ui8> {
+ public:
+ //! \brief An output buffer is empty when there is no data written to it.
+ bool is_empty() const noexcept {
+ return pos() == begin();
+ }
+
+ //! \brief An output buffer is full when there is no space to write more data to it.
+ bool is_full() const noexcept {
+ return pos() == end();
+ }
+ };
+
+ class input_buffer: public buffer<const ui8> {
+ public:
+ //! An input stream is empty when there is no data to read in it.
+ bool is_empty() const noexcept {
+ return pos() == end();
+ }
+ };
+
+}
diff --git a/library/cpp/yson_pull/consumer.cpp b/library/cpp/yson_pull/consumer.cpp
new file mode 100644
index 0000000000..c238e0a6fb
--- /dev/null
+++ b/library/cpp/yson_pull/consumer.cpp
@@ -0,0 +1,83 @@
+#include "consumer.h"
+
+#include <library/cpp/yson_pull/detail/macros.h>
+
+using namespace NYsonPull;
+
+void IConsumer::OnScalar(const TScalar& value) {
+ switch (value.Type()) {
+ case EScalarType::Entity:
+ OnEntity();
+ break;
+
+ case EScalarType::Boolean:
+ OnScalarBoolean(value.AsBoolean());
+ break;
+
+ case EScalarType::Int64:
+ OnScalarInt64(value.AsInt64());
+ break;
+
+ case EScalarType::UInt64:
+ OnScalarUInt64(value.AsUInt64());
+ break;
+
+ case EScalarType::Float64:
+ OnScalarFloat64(value.AsFloat64());
+ break;
+
+ case EScalarType::String:
+ OnScalarString(value.AsString());
+ break;
+
+ default:
+ Y_UNREACHABLE();
+ }
+}
+
+void IConsumer::OnEvent(const TEvent& value) {
+ switch (value.Type()) {
+ case EEventType::BeginStream:
+ OnBeginStream();
+ break;
+
+ case EEventType::EndStream:
+ OnEndStream();
+ break;
+
+ case EEventType::BeginList:
+ OnBeginList();
+ break;
+
+ case EEventType::EndList:
+ OnEndList();
+ break;
+
+ case EEventType::BeginMap:
+ OnBeginMap();
+ break;
+
+ case EEventType::Key:
+ OnKey(value.AsString());
+ break;
+
+ case EEventType::EndMap:
+ OnEndMap();
+ break;
+
+ case EEventType::BeginAttributes:
+ OnBeginAttributes();
+ break;
+
+ case EEventType::EndAttributes:
+ OnEndAttributes();
+ break;
+
+ case EEventType::Scalar:
+ OnScalar(value.AsScalar());
+ break;
+
+ default:
+ Y_UNREACHABLE();
+ }
+}
diff --git a/library/cpp/yson_pull/consumer.h b/library/cpp/yson_pull/consumer.h
new file mode 100644
index 0000000000..f3b1398d4c
--- /dev/null
+++ b/library/cpp/yson_pull/consumer.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "event.h"
+
+#include <util/generic/strbuf.h>
+#include <util/system/types.h>
+
+namespace NYsonPull {
+ class IConsumer {
+ public:
+ virtual ~IConsumer() = default;
+
+ virtual void OnBeginStream() = 0;
+ virtual void OnEndStream() = 0;
+
+ virtual void OnBeginList() = 0;
+ virtual void OnEndList() = 0;
+
+ virtual void OnBeginMap() = 0;
+ virtual void OnEndMap() = 0;
+
+ virtual void OnBeginAttributes() = 0;
+ virtual void OnEndAttributes() = 0;
+
+ virtual void OnKey(TStringBuf name) = 0;
+
+ virtual void OnEntity() = 0;
+ virtual void OnScalarBoolean(bool value) = 0;
+ virtual void OnScalarInt64(i64 value) = 0;
+ virtual void OnScalarUInt64(ui64 value) = 0;
+ virtual void OnScalarFloat64(double value) = 0;
+ virtual void OnScalarString(TStringBuf value) = 0;
+
+ virtual void OnScalar(const TScalar& value);
+ virtual void OnEvent(const TEvent& value);
+ };
+}
diff --git a/library/cpp/yson_pull/cyson_enums.h b/library/cpp/yson_pull/cyson_enums.h
new file mode 100644
index 0000000000..315de97307
--- /dev/null
+++ b/library/cpp/yson_pull/cyson_enums.h
@@ -0,0 +1,47 @@
+#pragma once
+
+typedef enum yson_event_type {
+ YSON_EVENT_BEGIN_STREAM = 0,
+ YSON_EVENT_END_STREAM = 1,
+ YSON_EVENT_BEGIN_LIST = 2,
+ YSON_EVENT_END_LIST = 3,
+ YSON_EVENT_BEGIN_MAP = 4,
+ YSON_EVENT_END_MAP = 5,
+ YSON_EVENT_BEGIN_ATTRIBUTES = 6,
+ YSON_EVENT_END_ATTRIBUTES = 7,
+ YSON_EVENT_KEY = 8,
+ YSON_EVENT_SCALAR = 9,
+ YSON_EVENT_ERROR = 10
+} yson_event_type;
+
+typedef enum yson_scalar_type {
+ YSON_SCALAR_ENTITY = 0,
+ YSON_SCALAR_BOOLEAN = 1,
+ YSON_SCALAR_INT64 = 2,
+ YSON_SCALAR_UINT64 = 3,
+ YSON_SCALAR_FLOAT64 = 4,
+ YSON_SCALAR_STRING = 5
+} yson_scalar_type;
+
+typedef enum yson_input_stream_result {
+ YSON_INPUT_STREAM_RESULT_OK = 0,
+ YSON_INPUT_STREAM_RESULT_EOF = 1,
+ YSON_INPUT_STREAM_RESULT_ERROR = 2
+} yson_input_stream_result;
+
+typedef enum yson_output_stream_result {
+ YSON_OUTPUT_STREAM_RESULT_OK = 0,
+ YSON_OUTPUT_STREAM_RESULT_ERROR = 1
+} yson_output_stream_result;
+
+typedef enum yson_writer_result {
+ YSON_WRITER_RESULT_OK = 0,
+ YSON_WRITER_RESULT_BAD_STREAM = 1,
+ YSON_WRITER_RESULT_ERROR = 2
+} yson_writer_result;
+
+typedef enum yson_stream_type {
+ YSON_STREAM_TYPE_NODE = 0,
+ YSON_STREAM_TYPE_LIST_FRAGMENT = 1,
+ YSON_STREAM_TYPE_MAP_FRAGMENT = 2
+} yson_stream_type;
diff --git a/library/cpp/yson_pull/detail/byte_reader.h b/library/cpp/yson_pull/detail/byte_reader.h
new file mode 100644
index 0000000000..7cea50d323
--- /dev/null
+++ b/library/cpp/yson_pull/detail/byte_reader.h
@@ -0,0 +1,74 @@
+#pragma once
+
+#include "cescape.h"
+#include "fail.h"
+#include "stream_counter.h"
+
+#include <library/cpp/yson_pull/input.h>
+
+namespace NYsonPull {
+ namespace NDetail {
+ template <class StreamCounter>
+ class byte_reader {
+ NYsonPull::NInput::IStream& stream_;
+ StreamCounter stream_counter_;
+
+ public:
+ byte_reader(NYsonPull::NInput::IStream& stream)
+ : stream_(stream)
+ {
+ }
+
+ // const-ness added to prevent direct stream mutation
+ const NYsonPull::NInput::IStream& stream() {
+ return stream_;
+ }
+
+ template <typename... Args>
+ ATTRIBUTE(noinline, cold)
+ void fail[[noreturn]](const char* msg, Args&&... args) {
+ NYsonPull::NDetail::fail(
+ stream_counter_.info(),
+ msg,
+ std::forward<Args>(args)...);
+ }
+
+ template <bool AllowFinish>
+ void fill_buffer() {
+ stream_.fill_buffer();
+
+ if (!AllowFinish) {
+ auto& buf = stream_.buffer();
+ if (Y_UNLIKELY(buf.is_empty() && stream_.at_end())) {
+ fail("Premature end of stream");
+ }
+ }
+ }
+
+ void fill_buffer() {
+ return fill_buffer<true>();
+ }
+
+ template <bool AllowFinish>
+ ui8 get_byte() {
+ fill_buffer<AllowFinish>();
+ auto& buf = stream_.buffer();
+ return !buf.is_empty()
+ ? *buf.pos()
+ : ui8{'\0'};
+ }
+
+ ui8 get_byte() {
+ return get_byte<true>();
+ }
+
+ void advance(size_t bytes) {
+ auto& buf = stream_.buffer();
+ stream_counter_.update(
+ buf.pos(),
+ buf.pos() + bytes);
+ buf.advance(bytes);
+ }
+ };
+ }
+}
diff --git a/library/cpp/yson_pull/detail/byte_writer.h b/library/cpp/yson_pull/detail/byte_writer.h
new file mode 100644
index 0000000000..dc1d4b4b96
--- /dev/null
+++ b/library/cpp/yson_pull/detail/byte_writer.h
@@ -0,0 +1,77 @@
+#pragma once
+
+#include "macros.h"
+
+#include <library/cpp/yson_pull/output.h>
+
+#include <util/system/types.h>
+
+#include <cstddef>
+#include <cstring>
+
+namespace NYsonPull {
+ namespace NDetail {
+ template <class StreamCounter>
+ class byte_writer {
+ NYsonPull::NOutput::IStream& stream_;
+ StreamCounter stream_counter_;
+
+ public:
+ byte_writer(NYsonPull::NOutput::IStream& stream)
+ : stream_(stream)
+ {
+ }
+
+ // const-ness added to prevent direct stream mutation
+ const NYsonPull::NOutput::IStream& stream() {
+ return stream_;
+ }
+ const StreamCounter& counter() {
+ return stream_counter_;
+ }
+
+ void flush_buffer() {
+ stream_.flush_buffer();
+ }
+
+ void advance(size_t bytes) {
+ auto& buf = stream_.buffer();
+ stream_counter_.update(
+ buf.pos(),
+ buf.pos() + bytes);
+ buf.advance(bytes);
+ }
+
+ void write(ui8 c) {
+ auto& buf = stream_.buffer();
+ if (Y_LIKELY(!buf.is_full())) {
+ *buf.pos() = c;
+ advance(1);
+ } else {
+ auto ptr = reinterpret_cast<char*>(&c);
+ stream_counter_.update(&c, &c + 1);
+ stream_.flush_buffer({ptr, 1});
+ }
+ }
+
+ void write(const ui8* data, size_t size) {
+ auto& buf = stream_.buffer();
+ auto free_buf = buf.available();
+ if (Y_LIKELY(size < free_buf)) {
+ ::memcpy(buf.pos(), data, size);
+ advance(size);
+ } else {
+ if (!buf.is_full()) {
+ ::memcpy(buf.pos(), data, free_buf);
+ advance(free_buf);
+ data += free_buf;
+ size -= free_buf;
+ }
+ stream_counter_.update(data, data + size);
+ stream_.flush_buffer({reinterpret_cast<const char*>(data),
+ size});
+ }
+ }
+ };
+ }
+}
diff --git a/library/cpp/yson_pull/detail/cescape.h b/library/cpp/yson_pull/detail/cescape.h
new file mode 100644
index 0000000000..1ea150e69a
--- /dev/null
+++ b/library/cpp/yson_pull/detail/cescape.h
@@ -0,0 +1,143 @@
+#pragma once
+
+#include "byte_writer.h"
+#include "cescape_decode.h"
+#include "cescape_encode.h"
+#include "macros.h"
+
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+
+/* REFERENCES FOR ESCAPE SEQUENCE INTERPRETATION:
+ * C99 p. 6.4.3 Universal character names.
+ * C99 p. 6.4.4.4 Character constants.
+ *
+ * <simple-escape-sequence> ::= {
+ * \' , \" , \? , \\ ,
+ * \a , \b , \f , \n , \r , \t , \v
+ * }
+ *
+ * <octal-escape-sequence> ::= \ <octal-digit> {1, 3}
+ * <hexadecimal-escape-sequence> ::= \x <hexadecimal-digit> +
+ * <universal-character-name> ::= \u <hexadecimal-digit> {4}
+ * || \U <hexadecimal-digit> {8}
+ *
+ * NOTE (6.4.4.4.7):
+ * Each octal or hexadecimal escape sequence is the longest sequence of characters that can
+ * constitute the escape sequence.
+ *
+ * THEREFORE:
+ * - Octal escape sequence spans until rightmost non-octal-digit character.
+ * - Octal escape sequence always terminates after three octal digits.
+ * - Hexadecimal escape sequence spans until rightmost non-hexadecimal-digit character.
+ * - Universal character name consists of exactly 4 or 8 hexadecimal digit.
+ *
+ */
+
+namespace NYsonPull {
+ namespace NDetail {
+ namespace NCEscape {
+ inline void encode(TString& dest, TStringBuf data) {
+ NImpl::escape_impl(
+ reinterpret_cast<const ui8*>(data.data()),
+ data.size(),
+ [&](const ui8* str, size_t size) {
+ dest.append(
+ reinterpret_cast<const char*>(str),
+ size);
+ });
+ }
+
+ // dest must have at least 4*data.size() bytes available
+ inline size_t encode(ui8* dest, TStringBuf data) {
+ auto* dest_begin = dest;
+ NImpl::escape_impl(
+ reinterpret_cast<const ui8*>(data.data()),
+ data.size(),
+ [&](const ui8* str, size_t size) {
+ ::memcpy(dest, str, size);
+ dest += size;
+ });
+ return dest - dest_begin;
+ }
+
+ template <typename U>
+ void encode(byte_writer<U>& dest, TStringBuf data) {
+ auto& buffer = dest.stream().buffer();
+ if (Y_LIKELY(buffer.available() >= data.size() * 4)) {
+ auto size = encode(buffer.pos(), data);
+ dest.advance(size);
+ } else {
+ NImpl::escape_impl(
+ reinterpret_cast<const ui8*>(data.data()),
+ data.size(),
+ [&](const ui8* str, size_t size) {
+ dest.write(str, size);
+ });
+ }
+ }
+
+ inline TString encode(TStringBuf data) {
+ TString result;
+ result.reserve(data.size());
+ encode(result, data);
+ return result;
+ }
+
+ inline void decode(TString& dest, TStringBuf data) {
+ NImpl::unescape_impl(
+ reinterpret_cast<const ui8*>(data.begin()),
+ reinterpret_cast<const ui8*>(data.end()),
+ [&](ui8 c) {
+ dest += c;
+ },
+ [&](const ui8* p, size_t len) {
+ dest.append(reinterpret_cast<const char*>(p), len);
+ });
+ }
+
+ inline void decode_inplace(TVector<ui8>& data) {
+ auto* out = static_cast<ui8*>(
+ ::memchr(data.data(), '\\', data.size()));
+ if (out == nullptr) {
+ return;
+ }
+ NImpl::unescape_impl(
+ out,
+ data.data() + data.size(),
+ [&](ui8 c) {
+ *out++ = c;
+ },
+ [&](const ui8* p, size_t len) {
+ ::memmove(out, p, len);
+ out += len;
+ });
+ data.resize(out - &data[0]);
+ }
+
+ inline TString decode(TStringBuf data) {
+ TString result;
+ result.reserve(data.size());
+ decode(result, data);
+ return result;
+ }
+
+ ATTRIBUTE(noinline, cold)
+ inline TString quote(TStringBuf str) {
+ TString result;
+ result.reserve(str.size() + 16);
+ result += '"';
+ encode(result, str);
+ result += '"';
+ return result;
+ }
+
+ ATTRIBUTE(noinline, cold)
+ inline TString quote(ui8 ch) {
+ char c = ch;
+ return quote(TStringBuf(&c, 1));
+ }
+ }
+ } // namespace NDetail
+}
diff --git a/library/cpp/yson_pull/detail/cescape_decode.h b/library/cpp/yson_pull/detail/cescape_decode.h
new file mode 100644
index 0000000000..2ee5dd9500
--- /dev/null
+++ b/library/cpp/yson_pull/detail/cescape_decode.h
@@ -0,0 +1,154 @@
+#pragma once
+
+#include <util/system/types.h>
+
+#include <algorithm>
+#include <cstring>
+
+namespace NYsonPull {
+ namespace NDetail {
+ namespace NCEscape {
+ namespace NImpl {
+ inline ui8 as_digit(ui8 c) {
+ return c - ui8{'0'};
+ }
+
+ inline ui8 as_hexdigit(ui8 c) {
+ static constexpr ui8 hex_decode_map[256] = {
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255,
+ 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255};
+
+ return hex_decode_map[c];
+ }
+
+ inline const ui8* read_oct(ui8& result, const ui8* p, ui8 n) {
+ auto digit = ui8{0};
+ while (n-- && (digit = as_digit(*p)) < 8) {
+ result = result * 8 + digit;
+ ++p;
+ }
+ return p;
+ }
+
+ inline const ui8* read_hex(ui8& result, const ui8* p, ui8 n) {
+ auto digit = ui8{0};
+ while (n-- && (digit = as_hexdigit(*p)) < 16) {
+ result = result * 16 + digit;
+ ++p;
+ }
+ return p;
+ }
+
+ inline const ui8* unescape_char_and_advance(
+ ui8& result,
+ const ui8* p,
+ const ui8* end) {
+ switch (*p) {
+ default:
+ result = *p;
+ ++p;
+ break;
+ case 'b':
+ result = '\b';
+ ++p;
+ break;
+ case 'f':
+ result = '\f';
+ ++p;
+ break;
+ case 'n':
+ result = '\n';
+ ++p;
+ break;
+ case 'r':
+ result = '\r';
+ ++p;
+ break;
+ case 't':
+ result = '\t';
+ ++p;
+ break;
+
+ case 'x': {
+ ++p;
+ result = 0;
+ auto* next = read_hex(
+ result,
+ p, std::min<ptrdiff_t>(2, end - p));
+ if (next > p) {
+ p = next;
+ } else {
+ result = 'x';
+ }
+ } break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ result = 0;
+ p = read_oct(
+ result,
+ p, std::min<ptrdiff_t>(3, end - p));
+ break;
+
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ result = 0;
+ p = read_oct(
+ result,
+ p, std::min<ptrdiff_t>(2, end - p));
+ break;
+ }
+ return p;
+ }
+
+ template <typename T, typename U>
+ inline void unescape_impl(
+ const ui8* p,
+ const ui8* end,
+ T&& consume_one,
+ U&& consume_span) {
+ while (p < end) {
+ auto* escaped = static_cast<const ui8*>(
+ ::memchr(p, '\\', end - p));
+ if (escaped == nullptr) {
+ consume_span(p, end - p);
+ return;
+ } else {
+ consume_span(p, escaped - p);
+ auto c = ui8{'\\'};
+ p = escaped + 1;
+ if (p < end) {
+ p = unescape_char_and_advance(c, p, end);
+ }
+ consume_one(c);
+ }
+ }
+ }
+ }
+ } // namespace NCEscape
+ } // namespace NDetail
+}
diff --git a/library/cpp/yson_pull/detail/cescape_encode.h b/library/cpp/yson_pull/detail/cescape_encode.h
new file mode 100644
index 0000000000..bf5765f1d9
--- /dev/null
+++ b/library/cpp/yson_pull/detail/cescape_encode.h
@@ -0,0 +1,114 @@
+#pragma once
+
+#include <util/system/types.h>
+
+// Whether to ensure strict ASCII compatibility
+// Turns UTF-8 strings into unreadable garbage for no known reason
+//#define CESCAPE_STRICT_ASCII
+
+namespace NYsonPull {
+ namespace NDetail {
+ namespace NCEscape {
+ namespace NImpl {
+ inline ui8 hex_digit(ui8 value) {
+ constexpr ui8 hex_digits[] = "0123456789ABCDEF";
+ return hex_digits[value];
+ }
+
+ inline ui8 oct_digit(ui8 value) {
+ return '0' + value;
+ }
+
+ inline bool is_printable(ui8 c) {
+#ifdef CESCAPE_STRICT_ASCII
+ return c >= 32 && c <= 126;
+#else
+ return c >= 32;
+#endif
+ }
+
+ inline bool is_hex_digit(ui8 c) {
+ return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
+ }
+
+ inline bool is_oct_digit(ui8 c) {
+ return c >= '0' && c <= '7';
+ }
+
+ constexpr size_t ESCAPE_C_BUFFER_SIZE = 4;
+
+ inline size_t escape_char(
+ ui8 c,
+ ui8 next,
+ ui8 r[ESCAPE_C_BUFFER_SIZE]) {
+ // (1) Printable characters go as-is, except backslash and double quote.
+ // (2) Characters \r, \n, \t and \0 ... \7 replaced by their simple escape characters (if possible).
+ // (3) Otherwise, character is encoded using hexadecimal escape sequence (if possible), or octal.
+ if (c == '\"') {
+ r[0] = '\\';
+ r[1] = '\"';
+ return 2;
+ } else if (c == '\\') {
+ r[0] = '\\';
+ r[1] = '\\';
+ return 2;
+ } else if (is_printable(c)) {
+ r[0] = c;
+ return 1;
+ } else if (c == '\r') {
+ r[0] = '\\';
+ r[1] = 'r';
+ return 2;
+ } else if (c == '\n') {
+ r[0] = '\\';
+ r[1] = 'n';
+ return 2;
+ } else if (c == '\t') {
+ r[0] = '\\';
+ r[1] = 't';
+ return 2;
+ } else if (c < 8 && !is_oct_digit(next)) {
+ r[0] = '\\';
+ r[1] = oct_digit(c);
+ return 2;
+ } else if (!is_hex_digit(next)) {
+ r[0] = '\\';
+ r[1] = 'x';
+ r[2] = hex_digit((c & 0xF0) >> 4);
+ r[3] = hex_digit((c & 0x0F) >> 0);
+ return 4;
+ } else {
+ r[0] = '\\';
+ r[1] = oct_digit((c & 0700) >> 6);
+ r[2] = oct_digit((c & 0070) >> 3);
+ r[3] = oct_digit((c & 0007) >> 0);
+ return 4;
+ }
+ }
+
+ template <typename T>
+ inline void escape_impl(const ui8* str, size_t len, T&& consume) {
+ ui8 buffer[ESCAPE_C_BUFFER_SIZE];
+
+ size_t i, j;
+ for (i = 0, j = 0; i < len; ++i) {
+ auto next_char = i + 1 < len ? str[i + 1] : 0;
+ size_t rlen = escape_char(str[i], next_char, buffer);
+
+ if (rlen > 1) {
+ consume(str + j, i - j);
+ j = i + 1;
+ consume(buffer, rlen);
+ }
+ }
+
+ if (j > 0) {
+ consume(str + j, len - j);
+ } else {
+ consume(str, len);
+ }
+ }
+ }
+ } // namespace NCEscape
+ } // namespace NDetail
+}
diff --git a/library/cpp/yson_pull/detail/fail.h b/library/cpp/yson_pull/detail/fail.h
new file mode 100644
index 0000000000..6937612d0b
--- /dev/null
+++ b/library/cpp/yson_pull/detail/fail.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "format_string.h"
+#include "macros.h"
+
+#include <library/cpp/yson_pull/exceptions.h>
+#include <library/cpp/yson_pull/position_info.h>
+
+namespace NYsonPull {
+ namespace NDetail {
+ template <typename... Args>
+ ATTRIBUTE(noreturn, noinline, cold)
+ void fail(
+ const TPositionInfo& info,
+ Args&&... args) {
+ auto formatted_message = format_string(std::forward<Args>(args)...);
+ throw NException::TBadInput(formatted_message, info);
+ }
+ }
+}
diff --git a/library/cpp/yson_pull/detail/format_string.h b/library/cpp/yson_pull/detail/format_string.h
new file mode 100644
index 0000000000..683fd1bf36
--- /dev/null
+++ b/library/cpp/yson_pull/detail/format_string.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+#include <util/generic/string.h>
+#include <util/string/builder.h>
+
+namespace NYsonPull {
+ namespace NDetail {
+ namespace NImpl {
+ inline void apply_args(TStringBuilder&) {
+ }
+
+ template <typename T, typename... Args>
+ inline void apply_args(TStringBuilder& builder, T&& arg, Args&&... args) {
+ apply_args(builder << arg, std::forward<Args>(args)...);
+ }
+ }
+
+ template <typename... Args>
+ TString format_string(Args&&... args) {
+ TStringBuilder builder;
+ NImpl::apply_args(builder, std::forward<Args>(args)...);
+ return TString(std::move(builder));
+ }
+ }
+}
diff --git a/library/cpp/yson_pull/detail/input/buffered.h b/library/cpp/yson_pull/detail/input/buffered.h
new file mode 100644
index 0000000000..9b1482577f
--- /dev/null
+++ b/library/cpp/yson_pull/detail/input/buffered.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <library/cpp/yson_pull/detail/macros.h>
+
+#include <library/cpp/yson_pull/exceptions.h>
+#include <library/cpp/yson_pull/input.h>
+
+#include <cstdio>
+#include <memory>
+
+namespace NYsonPull {
+ namespace NDetail {
+ namespace NInput {
+ class TBuffered: public NYsonPull::NInput::IStream {
+ TArrayHolder<ui8> buffer_;
+ size_t size_;
+
+ public:
+ explicit TBuffered(size_t buffer_size)
+ : buffer_{new ui8[buffer_size]}
+ , size_{buffer_size} {
+ }
+
+ protected:
+ ui8* buffer_data() const {
+ return buffer_.Get();
+ }
+
+ size_t buffer_size() const {
+ return size_;
+ }
+ };
+ }
+ } // namespace NDetail
+}
diff --git a/library/cpp/yson_pull/detail/input/stdio_file.h b/library/cpp/yson_pull/detail/input/stdio_file.h
new file mode 100644
index 0000000000..c412b7e59b
--- /dev/null
+++ b/library/cpp/yson_pull/detail/input/stdio_file.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "buffered.h"
+
+#include <library/cpp/yson_pull/detail/macros.h>
+
+#include <library/cpp/yson_pull/exceptions.h>
+#include <library/cpp/yson_pull/input.h>
+
+#include <cstdio>
+#include <memory>
+
+namespace NYsonPull {
+ namespace NDetail {
+ namespace NInput {
+ class TStdioFile: public TBuffered {
+ FILE* file_;
+
+ public:
+ TStdioFile(FILE* file, size_t buffer_size)
+ : TBuffered(buffer_size)
+ , file_{file} {
+ }
+
+ protected:
+ result do_fill_buffer() override {
+ auto nread = ::fread(buffer_data(), 1, buffer_size(), file_);
+ if (Y_UNLIKELY(nread == 0)) {
+ if (ferror(file_)) {
+ throw NException::TSystemError();
+ }
+ if (feof(file_)) {
+ return result::at_end;
+ }
+ }
+ buffer().reset(buffer_data(), buffer_data() + nread);
+ return result::have_more_data;
+ }
+ };
+ }
+ } // namespace NDetail
+}
diff --git a/library/cpp/yson_pull/detail/input/stream.h b/library/cpp/yson_pull/detail/input/stream.h
new file mode 100644
index 0000000000..791cd5a3f5
--- /dev/null
+++ b/library/cpp/yson_pull/detail/input/stream.h
@@ -0,0 +1,69 @@
+#pragma once
+
+#include <library/cpp/yson_pull/detail/macros.h>
+
+#include <library/cpp/yson_pull/input.h>
+
+#include <util/stream/buffered.h>
+#include <util/stream/file.h>
+#include <util/stream/zerocopy.h>
+#include <util/system/file.h>
+
+namespace NYsonPull {
+ namespace NDetail {
+ namespace NInput {
+ class TStreamBase: public NYsonPull::NInput::IStream {
+ protected:
+ result DoFillBufferFrom(IZeroCopyInput& input) {
+ void* ptr = nullptr;
+ size_t size = input.Next(&ptr);
+ if (Y_UNLIKELY(size == 0)) {
+ return result::at_end;
+ }
+ buffer().reset(static_cast<ui8*>(ptr), static_cast<ui8*>(ptr) + size);
+ return result::have_more_data;
+ }
+ };
+
+ class TZeroCopy: public TStreamBase {
+ IZeroCopyInput* Input;
+
+ public:
+ explicit TZeroCopy(IZeroCopyInput* input)
+ : Input(input)
+ {
+ }
+
+ protected:
+ result do_fill_buffer() override {
+ return DoFillBufferFrom(*Input);
+ }
+ };
+
+ template <typename TBuffered>
+ class TOwned: public TStreamBase {
+ TBuffered Input;
+
+ public:
+ template <typename... Args>
+ explicit TOwned(Args&&... args)
+ : Input(std::forward<Args>(args)...)
+ {
+ }
+
+ protected:
+ result do_fill_buffer() override {
+ return DoFillBufferFrom(Input);
+ }
+ };
+
+ class TFHandle: public TOwned<TFileInput> {
+ public:
+ TFHandle(int fd, size_t buffer_size)
+ : TOwned<TFileInput>(Duplicate(fd), buffer_size)
+ {
+ }
+ };
+ }
+ } // namespace NDetail
+}
diff --git a/library/cpp/yson_pull/detail/lexer_base.h b/library/cpp/yson_pull/detail/lexer_base.h
new file mode 100644
index 0000000000..572bdb3d18
--- /dev/null
+++ b/library/cpp/yson_pull/detail/lexer_base.h
@@ -0,0 +1,343 @@
+#pragma once
+
+#include "byte_reader.h"
+#include "cescape.h"
+#include "macros.h"
+#include "number.h"
+#include "percent_scalar.h"
+#include "stream_counter.h"
+#include "varint.h"
+
+#include <util/generic/maybe.h>
+#include <util/generic/vector.h>
+#include <util/string/cast.h>
+
+namespace NYsonPull {
+ namespace NDetail {
+ template <bool EnableLinePositionInfo>
+ class lexer_base: public byte_reader<stream_counter<EnableLinePositionInfo>> {
+ using Base = byte_reader<
+ stream_counter<EnableLinePositionInfo>>;
+
+ TVector<ui8> token_buffer_;
+ TMaybe<size_t> memory_limit_;
+
+ public:
+ lexer_base(
+ NYsonPull::NInput::IStream& buffer,
+ TMaybe<size_t> memory_limit)
+ : Base(buffer)
+ , memory_limit_{memory_limit} {
+ }
+
+ ATTRIBUTE(noinline, hot)
+ ui8 skip_space_and_get_byte() {
+ auto& buf = Base::stream().buffer();
+ if (Y_LIKELY(!buf.is_empty())) {
+ auto ch = *buf.pos();
+ if (Y_LIKELY(!is_space(ch))) {
+ return ch;
+ }
+ }
+ return skip_space_and_get_byte_fallback();
+ }
+
+ ATTRIBUTE(hot)
+ ui8 get_byte() {
+ auto& buf = Base::stream().buffer();
+ if (Y_LIKELY(!buf.is_empty())) {
+ return *buf.pos();
+ }
+ return Base::get_byte();
+ }
+
+ number read_numeric() {
+ token_buffer_.clear();
+ auto type = number_type::int64;
+ while (true) {
+ auto ch = this->Base::template get_byte<true>();
+ if (isdigit(ch) || ch == '+' || ch == '-') {
+ token_buffer_.push_back(ch);
+ } else if (ch == '.' || ch == 'e' || ch == 'E') {
+ token_buffer_.push_back(ch);
+ type = number_type::float64;
+ } else if (ch == 'u') {
+ token_buffer_.push_back(ch);
+ type = number_type::uint64;
+ } else if (Y_UNLIKELY(isalpha(ch))) {
+ COLD_BLOCK_BYVALUE
+ Base::fail("Unexpected ", NCEscape::quote(ch), " in numeric literal");
+ COLD_BLOCK_END
+ } else {
+ break;
+ }
+ check_memory_limit();
+ Base::advance(1);
+ }
+
+ auto str = token_buffer();
+ try {
+ switch (type) {
+ case number_type::float64:
+ return FromString<double>(str);
+ case number_type::int64:
+ return FromString<i64>(str);
+ case number_type::uint64:
+ str.Chop(1); // 'u' suffix
+ return FromString<ui64>(str);
+ }
+ Y_UNREACHABLE();
+ } catch (const std::exception& err) {
+ Base::fail(err.what());
+ }
+ }
+
+ TStringBuf read_quoted_string() {
+ auto count_trailing_slashes = [](ui8* begin, ui8* end) {
+ auto count = size_t{0};
+ if (begin < end) {
+ for (auto p = end - 1; p >= begin && *p == '\\'; --p) {
+ ++count;
+ }
+ }
+ return count;
+ };
+
+ token_buffer_.clear();
+ auto& buf = Base::stream().buffer();
+ while (true) {
+ this->Base::template fill_buffer<false>();
+ auto* quote = reinterpret_cast<const ui8*>(
+ ::memchr(buf.pos(), '"', buf.available()));
+ if (quote == nullptr) {
+ token_buffer_.insert(
+ token_buffer_.end(),
+ buf.pos(),
+ buf.end());
+ Base::advance(buf.available());
+ continue;
+ }
+
+ token_buffer_.insert(
+ token_buffer_.end(),
+ buf.pos(),
+ quote);
+ Base::advance(quote - buf.pos() + 1); // +1 for the quote itself
+
+ // We must count the number of '\' at the end of StringValue
+ // to check if it's not \"
+ int slash_count = count_trailing_slashes(
+ token_buffer_.data(),
+ token_buffer_.data() + token_buffer_.size());
+ if (slash_count % 2 == 0) {
+ break;
+ } else {
+ token_buffer_.push_back('"');
+ }
+ check_memory_limit();
+ }
+
+ NCEscape::decode_inplace(token_buffer_);
+ return token_buffer();
+ }
+
+ TStringBuf read_unquoted_string() {
+ token_buffer_.clear();
+ while (true) {
+ auto ch = this->Base::template get_byte<true>();
+ if (isalpha(ch) || isdigit(ch) ||
+ ch == '_' || ch == '-' || ch == '%' || ch == '.') {
+ token_buffer_.push_back(ch);
+ } else {
+ break;
+ }
+ check_memory_limit();
+ Base::advance(1);
+ }
+ return token_buffer();
+ }
+
+ ATTRIBUTE(noinline, hot)
+ TStringBuf read_binary_string() {
+ auto slength = NVarInt::read<i32>(*this);
+ if (Y_UNLIKELY(slength < 0)) {
+ COLD_BLOCK_BYVALUE
+ Base::fail("Negative binary string literal length ", slength);
+ COLD_BLOCK_END
+ }
+ auto length = static_cast<ui32>(slength);
+
+ auto& buf = Base::stream().buffer();
+ if (Y_LIKELY(buf.available() >= length)) {
+ auto result = TStringBuf{
+ reinterpret_cast<const char*>(buf.pos()),
+ length};
+ Base::advance(length);
+ return result;
+ } else { // reading in Buffer
+ return read_binary_string_fallback(length);
+ }
+ }
+
+ ATTRIBUTE(noinline)
+ TStringBuf read_binary_string_fallback(size_t length) {
+ auto& buf = Base::stream().buffer();
+ auto needToRead = length;
+ token_buffer_.clear();
+ while (needToRead) {
+ this->Base::template fill_buffer<false>();
+ auto chunk_size = std::min(needToRead, buf.available());
+
+ token_buffer_.insert(
+ token_buffer_.end(),
+ buf.pos(),
+ buf.pos() + chunk_size);
+ check_memory_limit();
+ needToRead -= chunk_size;
+ Base::advance(chunk_size);
+ }
+ return token_buffer();
+ }
+
+ percent_scalar read_percent_scalar() {
+ auto throw_incorrect_percent_scalar = [&]() {
+ Base::fail("Incorrect %-literal prefix ", NCEscape::quote(token_buffer()));
+ };
+
+ auto assert_literal = [&](TStringBuf literal) -> void {
+ for (size_t i = 2; i < literal.size(); ++i) {
+ token_buffer_.push_back(this->Base::template get_byte<false>());
+ Base::advance(1);
+ if (Y_UNLIKELY(token_buffer_.back() != literal[i])) {
+ throw_incorrect_percent_scalar();
+ }
+ }
+ };
+
+ token_buffer_.clear();
+ token_buffer_.push_back(this->Base::template get_byte<false>());
+ Base::advance(1);
+
+ switch (token_buffer_[0]) {
+ case 't':
+ assert_literal(percent_scalar::true_literal);
+ return percent_scalar(true);
+ case 'f':
+ assert_literal(percent_scalar::false_literal);
+ return percent_scalar(false);
+ case 'n':
+ assert_literal(percent_scalar::nan_literal);
+ return percent_scalar(std::numeric_limits<double>::quiet_NaN());
+ case 'i':
+ assert_literal(percent_scalar::positive_inf_literal);
+ return percent_scalar(std::numeric_limits<double>::infinity());
+ case '-':
+ assert_literal(percent_scalar::negative_inf_literal);
+ return percent_scalar(-std::numeric_limits<double>::infinity());
+ default:
+ throw_incorrect_percent_scalar();
+ }
+
+ Y_UNREACHABLE();
+ }
+
+ i64 read_binary_int64() {
+ return NVarInt::read<i64>(*this);
+ }
+
+ ui64 read_binary_uint64() {
+ return NVarInt::read<ui64>(*this);
+ }
+
+ double read_binary_double() {
+ union {
+ double as_double;
+ ui8 as_bytes[sizeof(double)];
+ } data;
+ static_assert(sizeof(data) == sizeof(double), "bad union size");
+
+ auto needToRead = sizeof(double);
+
+ auto& buf = Base::stream().buffer();
+ while (needToRead != 0) {
+ Base::fill_buffer();
+
+ auto chunk_size = std::min(needToRead, buf.available());
+ if (chunk_size == 0) {
+ Base::fail("Error parsing binary double literal");
+ }
+ std::copy(
+ buf.pos(),
+ buf.pos() + chunk_size,
+ data.as_bytes + (sizeof(double) - needToRead));
+ needToRead -= chunk_size;
+ Base::advance(chunk_size);
+ }
+ return data.as_double;
+ }
+
+ private:
+ static bool is_space(ui8 ch) {
+ static const ui8 lookupTable[] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ return lookupTable[ch];
+ }
+
+ ATTRIBUTE(noinline, cold)
+ ui8 skip_space_and_get_byte_fallback() {
+ auto& buf = Base::stream().buffer();
+ while (true) {
+ // FIXME
+ if (buf.is_empty()) {
+ if (Base::stream().at_end()) {
+ return '\0';
+ }
+ Base::fill_buffer();
+ } else {
+ if (!is_space(*buf.pos())) {
+ break;
+ }
+ Base::advance(1);
+ }
+ }
+ return Base::get_byte();
+ }
+
+ void check_memory_limit() {
+ if (Y_UNLIKELY(memory_limit_ && token_buffer_.capacity() > *memory_limit_)) {
+ COLD_BLOCK_BYVALUE
+ Base::fail(
+ "Memory limit exceeded while parsing YSON stream: "
+ "allocated ",
+ token_buffer_.capacity(),
+ ", limit ", *memory_limit_);
+ COLD_BLOCK_END
+ }
+ }
+
+ TStringBuf token_buffer() const {
+ auto* begin = reinterpret_cast<const char*>(token_buffer_.data());
+ return {begin, token_buffer_.size()};
+ }
+ };
+ }
+}
diff --git a/library/cpp/yson_pull/detail/macros.h b/library/cpp/yson_pull/detail/macros.h
new file mode 100644
index 0000000000..7243f9cfe1
--- /dev/null
+++ b/library/cpp/yson_pull/detail/macros.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <util/system/compiler.h>
+
+#if defined(__GNUC__)
+#define ATTRIBUTE(args...) __attribute__((args))
+#else
+#define ATTRIBUTE(...)
+#endif
+
+#if defined(__GNUC__) && !defined(__clang__)
+#define COLD_BLOCK_BYVALUE [=]() ATTRIBUTE(noinline, cold) {
+#define COLD_BLOCK_BYREF [&]() ATTRIBUTE(noinline, cold) {
+#define COLD_BLOCK_END \
+ } \
+ ();
+#else
+// Clang does not support gnu-style attributes on lambda functions yet
+#define COLD_BLOCK_BYVALUE [=]() {
+#define COLD_BLOCK_BYREF [&]() {
+#define COLD_BLOCK_END \
+ } \
+ ();
+#endif
diff --git a/library/cpp/yson_pull/detail/number.h b/library/cpp/yson_pull/detail/number.h
new file mode 100644
index 0000000000..5595f55e05
--- /dev/null
+++ b/library/cpp/yson_pull/detail/number.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include <util/system/types.h>
+
+namespace NYsonPull {
+ namespace NDetail {
+ enum class number_type {
+ float64,
+ uint64,
+ int64
+ };
+
+ struct number {
+ number_type type;
+ union {
+ double as_float64;
+ ui64 as_uint64;
+ i64 as_int64;
+ } value;
+
+ number(double v) {
+ type = number_type::float64;
+ value.as_float64 = v;
+ }
+
+ number(i64 v) {
+ type = number_type::int64;
+ value.as_int64 = v;
+ }
+
+ number(ui64 v) {
+ type = number_type::uint64;
+ value.as_uint64 = v;
+ }
+ };
+ }
+}
diff --git a/library/cpp/yson_pull/detail/output/buffered.h b/library/cpp/yson_pull/detail/output/buffered.h
new file mode 100644
index 0000000000..475cf34785
--- /dev/null
+++ b/library/cpp/yson_pull/detail/output/buffered.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <library/cpp/yson_pull/detail/macros.h>
+
+#include <library/cpp/yson_pull/output.h>
+
+#include <util/generic/strbuf.h>
+
+namespace NYsonPull {
+ namespace NDetail {
+ namespace NOutput {
+ template <typename T>
+ class TBuffered: public NYsonPull::NOutput::IStream {
+ TArrayHolder<ui8> buffer_;
+ size_t size_;
+
+ public:
+ TBuffered(size_t buffer_size)
+ : buffer_{new ui8[buffer_size]}
+ , size_{buffer_size} {
+ reset_buffer();
+ }
+
+ protected:
+ void do_flush_buffer(TStringBuf extra) override {
+ auto& buf = buffer();
+ if (!buf.is_empty()) {
+ do_write({reinterpret_cast<const char*>(buf.begin()), buf.used()});
+ reset_buffer();
+ }
+ if (extra.size() >= buf.available()) {
+ do_write(extra);
+ } else if (extra.size() > 0) {
+ ::memcpy(buf.pos(), extra.data(), extra.size());
+ buf.advance(extra.size());
+ }
+ }
+
+ private:
+ void do_write(TStringBuf data) {
+ // CRTP dispatch
+ static_cast<T*>(this)->write(data);
+ }
+
+ void reset_buffer() {
+ buffer().reset(buffer_.Get(), buffer_.Get() + size_);
+ }
+ };
+ }
+ } // namespace NDetail
+}
diff --git a/library/cpp/yson_pull/detail/output/stdio_file.h b/library/cpp/yson_pull/detail/output/stdio_file.h
new file mode 100644
index 0000000000..03f2b40dc5
--- /dev/null
+++ b/library/cpp/yson_pull/detail/output/stdio_file.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "buffered.h"
+
+#include <library/cpp/yson_pull/detail/macros.h>
+
+#include <library/cpp/yson_pull/exceptions.h>
+
+#include <cstdio>
+
+namespace NYsonPull {
+ namespace NDetail {
+ namespace NOutput {
+ class TStdioFile: public TBuffered<TStdioFile> {
+ FILE* file_;
+
+ public:
+ TStdioFile(FILE* file, size_t buffer_size)
+ : TBuffered<TStdioFile>(buffer_size)
+ , file_(file)
+ {
+ }
+
+ void write(TStringBuf data) {
+ auto nwritten = ::fwrite(data.data(), 1, data.size(), file_);
+ if (Y_UNLIKELY(static_cast<size_t>(nwritten) != data.size())) {
+ throw NException::TSystemError();
+ }
+ }
+ };
+ }
+ } // namespace NDetail
+}
diff --git a/library/cpp/yson_pull/detail/output/stream.h b/library/cpp/yson_pull/detail/output/stream.h
new file mode 100644
index 0000000000..d4810f3353
--- /dev/null
+++ b/library/cpp/yson_pull/detail/output/stream.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#include "buffered.h"
+
+#include <library/cpp/yson_pull/detail/macros.h>
+#include <library/cpp/yson_pull/exceptions.h>
+
+#include <util/stream/output.h>
+#include <util/stream/file.h>
+#include <util/system/file.h>
+
+namespace NYsonPull {
+ namespace NDetail {
+ namespace NOutput {
+ class TStream: public TBuffered<TStream> {
+ IOutputStream* Output;
+
+ public:
+ TStream(IOutputStream* output, size_t buffer_size)
+ : TBuffered<TStream>(buffer_size)
+ , Output(output)
+ {
+ }
+
+ void write(TStringBuf data) {
+ Output->Write(data);
+ }
+ };
+
+ template <typename TOutput>
+ class TOwned: public TBuffered<TOwned<TOutput>> {
+ TOutput Output;
+
+ public:
+ template <typename... Args>
+ TOwned(size_t buffer_size, Args&&... args)
+ : TBuffered<TOwned>(buffer_size)
+ , Output(std::forward<Args>(args)...)
+ {
+ }
+
+ void write(TStringBuf data) {
+ Output.Write(data);
+ }
+ };
+
+ class TFHandle: public TOwned<TUnbufferedFileOutput> {
+ public:
+ TFHandle(int fd, size_t buffer_size)
+ : TOwned<TUnbufferedFileOutput>(buffer_size, Duplicate(fd))
+ {
+ }
+ };
+ }
+ } // namespace NDetail
+}
diff --git a/library/cpp/yson_pull/detail/percent_scalar.h b/library/cpp/yson_pull/detail/percent_scalar.h
new file mode 100644
index 0000000000..ff4571842e
--- /dev/null
+++ b/library/cpp/yson_pull/detail/percent_scalar.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+namespace NYsonPull::NDetail {
+ enum class percent_scalar_type {
+ boolean,
+ float64
+ };
+
+ struct percent_scalar {
+ //! Text boolean literals
+ static constexpr TStringBuf true_literal = "%true";
+ static constexpr TStringBuf false_literal = "%false";
+ //! Text floating-point literals
+ static constexpr TStringBuf nan_literal = "%nan";
+ static constexpr TStringBuf positive_inf_literal = "%inf";
+ static constexpr TStringBuf negative_inf_literal = "%-inf";
+
+ percent_scalar_type type;
+ union {
+ double as_float64;
+ bool as_boolean;
+ } value;
+
+ percent_scalar(double v) {
+ type = percent_scalar_type::float64;
+ value.as_float64 = v;
+ }
+
+ percent_scalar(bool v) {
+ type = percent_scalar_type::boolean;
+ value.as_boolean = v;
+ }
+ };
+}
diff --git a/library/cpp/yson_pull/detail/reader.h b/library/cpp/yson_pull/detail/reader.h
new file mode 100644
index 0000000000..0e02396358
--- /dev/null
+++ b/library/cpp/yson_pull/detail/reader.h
@@ -0,0 +1,677 @@
+#pragma once
+
+#include "lexer_base.h"
+#include "symbols.h"
+
+#include <library/cpp/yson_pull/reader.h>
+
+#include <util/generic/maybe.h>
+#include <util/generic/vector.h>
+
+namespace NYsonPull {
+ namespace NDetail {
+ /*! \internal */
+ ////////////////////////////////////////////////////////////////////////////////
+
+ enum class special_token : ui8 {
+ // Special values:
+ // YSON
+ semicolon = 0, // ;
+ equals = 1, // =
+ hash = 2, // #
+ left_bracket = 3, // [
+ right_bracket = 4, // ]
+ left_brace = 5, // {
+ right_brace = 6, // }
+ left_angle = 7, // <
+ right_angle = 8, // >
+ };
+
+ // char_class tree representation:
+ // Root = xb
+ // BinaryStringOrOtherSpecialToken = x0b
+ // BinaryString = 00b
+ // OtherSpecialToken = 10b
+ // Other = x1b
+ // BinaryScalar = xx01b
+ // BinaryInt64 = 0001b
+ // BinaryDouble = 0101b
+ // BinaryFalse = 1001b
+ // BinaryTrue = 1101b
+ // Other = xxx11b
+ // Quote = 00011b
+ // DigitOrMinus = 00111b
+ // String = 01011b
+ // Space = 01111b
+ // Plus = 10011b
+ // None = 10111b
+ // Percent = 11011b
+ enum class char_class : ui8 {
+ binary_string = 0, // = 00b
+
+ special_token_mask = 2, // = 10b
+ semicolon = 2 + (0 << 2),
+ equals = 2 + (1 << 2),
+ hash = 2 + (2 << 2),
+ left_bracket = 2 + (3 << 2),
+ right_bracket = 2 + (4 << 2),
+ left_brace = 2 + (5 << 2),
+ right_brace = 2 + (6 << 2),
+ left_angle = 2 + (7 << 2),
+ right_angle = 2 + (8 << 2),
+
+ binary_scalar_mask = 1,
+ binary_int64 = 1 + (0 << 2), // = 001b
+ binary_double = 1 + (1 << 2), // = 101b
+ binary_false = 1 + (2 << 2), // = 1001b
+ binary_true = 1 + (3 << 2), // = 1101b
+ binary_uint64 = 1 + (4 << 2), // = 10001b
+
+ other_mask = 3,
+ quote = 3 + (0 << 2), // = 00011b
+ number = 3 + (1 << 2), // = 00111b
+ string = 3 + (2 << 2), // = 01011b
+ percent = 3 + (6 << 2), // = 11011b
+ none = 3 + (5 << 2), // = 10111b
+ };
+
+#define CHAR_SUBCLASS(x) (static_cast<ui8>(x) >> 2)
+
+ inline char_class get_char_class(ui8 ch) {
+#define NN char_class::none
+#define BS char_class::binary_string
+#define BI char_class::binary_int64
+#define BD char_class::binary_double
+#define BF char_class::binary_false
+#define BT char_class::binary_true
+#define BU char_class::binary_uint64
+#define SP NN // char_class::space
+#define NB char_class::number
+#define ST char_class::string
+#define QU char_class::quote
+#define PC char_class::percent
+#define TT(name) (static_cast<char_class>( \
+ (static_cast<ui8>(special_token::name) << 2) | static_cast<ui8>(char_class::special_token_mask)))
+
+ static constexpr char_class lookup[256] =
+ {
+ NN, BS, BI, BD, BF, BT, BU, NN, NN, SP, SP, SP, SP, SP, NN, NN,
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN,
+
+ // 32
+ SP, // ' '
+ NN, // '!'
+ QU, // '"'
+ TT(hash), // '#'
+ NN, // '$'
+ PC, // '%'
+ NN, // '&'
+ NN, // "'"
+ NN, // '('
+ NN, // ')'
+ NN, // '*'
+ NB, // '+'
+ NN, // ','
+ NB, // '-'
+ NN, // '.'
+ NN, // '/'
+
+ // 48
+ NB, NB, NB, NB, NB, NB, NB, NB, NB, NB, // '0' - '9'
+ NN, // ':'
+ TT(semicolon), // ';'
+ TT(left_angle), // '<'
+ TT(equals), // '='
+ TT(right_angle), // '>'
+ NN, // '?'
+
+ // 64
+ NN, // '@'
+ ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, // 'A' - 'M'
+ ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, // 'N' - 'Z'
+ TT(left_bracket), // '['
+ NN, // '\'
+ TT(right_bracket), // ']'
+ NN, // '^'
+ ST, // '_'
+
+ // 96
+ NN, // '`'
+
+ ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, // 'a' - 'm'
+ ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, ST, // 'n' - 'z'
+ TT(left_brace), // '{'
+ NN, // '|'
+ TT(right_brace), // '}'
+ NN, // '~'
+ NN, // '^?' non-printable
+ // 128
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN,
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN,
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN,
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN,
+
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN,
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN,
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN,
+ NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN, NN};
+
+#undef NN
+#undef BS
+#undef BI
+#undef BD
+#undef SP
+#undef NB
+#undef ST
+#undef QU
+#undef TT
+ return lookup[ch];
+ }
+
+ template <bool EnableLinePositionInfo>
+ class gen_reader_impl {
+ enum class state {
+ delimiter = 0, //! expecting ';' or closing-char ('>', ']', '}')
+ maybe_value = 1, //! expecting a value or closing-char
+ maybe_key = 2, //! expecting a key or closing-char
+ equals = 3, //! expecting '=' (followed by value)
+ value = 4, //! expecting a value
+ value_noattr = 5, //! expecting a value w/o attrs (after attrs)
+
+ // by design, rare states have numbers starting from first_rare_state
+ first_rare_state = 6,
+ before_begin = first_rare_state, //! before started reading the stream
+ before_end = first_rare_state + 1, //! Expecting end of stream
+ after_end = first_rare_state + 2, //! after end of stream
+ };
+
+ lexer_base<EnableLinePositionInfo> lexer_;
+ state state_;
+ TEvent event_;
+ TVector<EEventType> stack_;
+ EStreamType mode_;
+
+ public:
+ gen_reader_impl(
+ NYsonPull::NInput::IStream& buffer,
+ EStreamType mode,
+ TMaybe<size_t> memoryLimit = {})
+ : lexer_(buffer, memoryLimit)
+ , state_{state::before_begin}
+ , mode_{mode} {
+ }
+
+ const TEvent& last_event() const {
+ return event_;
+ }
+
+ ATTRIBUTE(hot)
+ const TEvent& next_event() {
+ if (Y_LIKELY(state_ < state::first_rare_state)) {
+ // 'hot' handler for in-stream events
+ next_event_hot();
+ } else {
+ // these events happen no more than once per stream
+ next_event_cold();
+ }
+ return event_;
+ }
+
+ private:
+ ATTRIBUTE(hot)
+ void next_event_hot() {
+ auto ch = lexer_.get_byte();
+ auto cls = get_char_class(ch);
+ if (Y_UNLIKELY(cls == char_class::none)) {
+ ch = lexer_.skip_space_and_get_byte();
+ if (Y_UNLIKELY(ch == NSymbol::eof)) {
+ handle_eof();
+ return;
+ }
+ cls = get_char_class(ch);
+ }
+
+ // states maybe_value/value/value_noattr are distinguished
+ // later in state_value_special
+ switch (state_) {
+ case state::maybe_value:
+ state_value(ch, cls);
+ break;
+ case state::maybe_key:
+ state_maybe_key(ch, cls);
+ break;
+ case state::equals:
+ state_equals(ch);
+ break;
+ case state::value:
+ state_value(ch, cls);
+ break;
+ case state::value_noattr:
+ state_value(ch, cls);
+ break;
+ case state::delimiter:
+ state_delimiter(ch, cls);
+ break;
+ default:
+ Y_UNREACHABLE();
+ }
+ }
+
+ ATTRIBUTE(noinline, cold)
+ void next_event_cold() {
+ switch (state_) {
+ case state::before_begin:
+ state_before_begin();
+ break;
+ case state::after_end:
+ lexer_.fail("Attempted read past stream end");
+ case state::before_end:
+ state_before_end();
+ break;
+ default:
+ Y_UNREACHABLE();
+ }
+ }
+
+ //! Present a scalar value for caller
+ template <typename T>
+ void yield(T value) {
+ event_ = TEvent{TScalar{value}};
+ }
+
+ //! Present a scalar value with non-scalar tag (i.e. key)
+ template <typename T>
+ void yield(EEventType type, T value) {
+ event_ = TEvent{type, TScalar{value}};
+ }
+
+ //! Present a value from number variant
+ void yield(const number& value) {
+ switch (value.type) {
+ case number_type::int64:
+ yield(value.value.as_int64);
+ break;
+ case number_type::uint64:
+ yield(value.value.as_uint64);
+ break;
+ case number_type::float64:
+ yield(value.value.as_float64);
+ break;
+ }
+ }
+
+ //! Present a value from %-literal variant
+ void yield(const percent_scalar& value) {
+ switch (value.type) {
+ case percent_scalar_type::boolean:
+ yield(value.value.as_boolean);
+ break;
+ case percent_scalar_type::float64:
+ yield(value.value.as_float64);
+ break;
+ }
+ }
+
+ //! Present a value-less event
+ void yield(EEventType type) {
+ event_ = TEvent{type};
+ }
+
+ //! Push the opening of a paired event
+ void push(EEventType type) {
+ stack_.push_back(type);
+ }
+
+ //! Close the paired_event, verify that delimiters are well-formed
+ void pop(EEventType first, EEventType last) {
+ if (Y_UNLIKELY(stack_.empty() || stack_.back() != first)) {
+ pop_fail(first, last);
+ return;
+ }
+ stack_.pop_back();
+
+ yield(last);
+ switch (first) {
+ case EEventType::BeginList:
+ next(state::delimiter);
+ break;
+
+ case EEventType::BeginMap:
+ next(state::delimiter);
+ break;
+
+ case EEventType::BeginAttributes:
+ next(state::value_noattr);
+ break;
+
+ case EEventType::BeginStream:
+ next(state::after_end);
+ break;
+
+ default:
+ Y_UNREACHABLE();
+ }
+
+ if (Y_UNLIKELY(mode_ == EStreamType::Node && stack_.size() == 1 && state_ == state::delimiter)) {
+ next(state::before_end);
+ }
+ }
+
+ ATTRIBUTE(noinline, cold)
+ void pop_fail(EEventType first, EEventType last) {
+ if (stack_.empty()) {
+ lexer_.fail("Unpaired events: expected opening '", first, "' for '", last, "', but event stack is empty");
+ } else {
+ lexer_.fail("Unpaired events: expected opening '", first, "' for '", last, "', but '", stack_.back(), "' is found.");
+ }
+ }
+
+ //! Transition to new_state
+ void next(state new_state) {
+ state_ = new_state;
+ }
+
+ bool in_map() {
+ return (stack_.back() == EEventType::BeginMap) || (stack_.back() == EEventType::BeginAttributes) || (stack_.back() == EEventType::BeginStream && mode_ == EStreamType::MapFragment);
+ }
+
+ ATTRIBUTE(noinline, cold)
+ void handle_eof() {
+ switch (state_) {
+ case state::maybe_value:
+ case state::maybe_key:
+ case state::delimiter:
+ case state::before_end:
+ pop(EEventType::BeginStream, EEventType::EndStream);
+ return;
+
+ default:
+ lexer_.fail("Unexpected end of stream");
+ }
+ }
+
+ ATTRIBUTE(noinline, cold)
+ void state_before_begin() {
+ push(EEventType::BeginStream);
+ yield(EEventType::BeginStream);
+ switch (mode_) {
+ case EStreamType::Node:
+ next(state::value);
+ break;
+ case EStreamType::ListFragment:
+ next(state::maybe_value);
+ break;
+ case EStreamType::MapFragment:
+ next(state::maybe_key);
+ break;
+ default:
+ Y_UNREACHABLE();
+ }
+ }
+
+ ATTRIBUTE(noinline, cold)
+ void state_before_end() {
+ auto ch = lexer_.skip_space_and_get_byte();
+ if (ch == NSymbol::eof) {
+ handle_eof();
+ } else {
+ lexer_.fail("Expected stream end, but found ", NCEscape::quote(ch));
+ }
+ }
+
+ ATTRIBUTE(hot)
+ void state_delimiter(ui8 ch, char_class cls) {
+ if (Y_LIKELY(ch == NSymbol::item_separator)) {
+ lexer_.advance(1);
+ next(in_map() ? state::maybe_key : state::maybe_value);
+ // immediately read next value
+ next_event_hot();
+ return;
+ }
+ state_delimiter_fallback(ch, cls);
+ }
+
+ ATTRIBUTE(noinline, hot)
+ void state_delimiter_fallback(ui8 ch, char_class cls) {
+ auto cls_bits = static_cast<ui8>(cls);
+ if ((cls_bits & 3) == static_cast<ui8>(char_class::special_token_mask)) {
+ auto token = static_cast<special_token>(cls_bits >> 2);
+ lexer_.advance(1);
+ switch (token) {
+ /* // handled in the fast track
+ case special_token::semicolon:
+ next(in_map()? state::maybe_key : state::maybe_value);
+ // immediately read next value
+ return next_event();
+ */
+
+ case special_token::right_bracket:
+ pop(EEventType::BeginList, EEventType::EndList);
+ return;
+
+ case special_token::right_brace:
+ pop(EEventType::BeginMap, EEventType::EndMap);
+ return;
+
+ case special_token::right_angle:
+ pop(EEventType::BeginAttributes, EEventType::EndAttributes);
+ return;
+
+ default:
+ break;
+ }
+ }
+
+ COLD_BLOCK_BYVALUE
+ lexer_.fail(
+ "Unexpected ", NCEscape::quote(ch), ", expected one of ",
+ NCEscape::quote(NSymbol::item_separator), ", ",
+ NCEscape::quote(NSymbol::end_list), ", ",
+ NCEscape::quote(NSymbol::end_map), ", ",
+ NCEscape::quote(NSymbol::end_attributes));
+ COLD_BLOCK_END
+ }
+
+ ATTRIBUTE(noinline, hot)
+ void state_maybe_key(ui8 ch, char_class cls) {
+ auto key = TStringBuf{};
+ // Keys are always strings, put binary-string key into fast lane
+ if (Y_LIKELY(ch == NSymbol::string_marker)) {
+ lexer_.advance(1);
+ key = lexer_.read_binary_string();
+ } else {
+ switch (cls) {
+ case char_class::quote:
+ lexer_.advance(1);
+ key = lexer_.read_quoted_string();
+ break;
+
+ case char_class::string:
+ key = lexer_.read_unquoted_string();
+ break;
+
+ case char_class::right_brace:
+ lexer_.advance(1);
+ pop(EEventType::BeginMap, EEventType::EndMap);
+ return;
+
+ case char_class::right_angle:
+ lexer_.advance(1);
+ pop(EEventType::BeginAttributes, EEventType::EndAttributes);
+ return;
+
+ default:
+ COLD_BLOCK_BYVALUE
+ lexer_.fail("Unexpected ", NCEscape::quote(ch), ", expected key string");
+ COLD_BLOCK_END
+ }
+ }
+
+ yield(EEventType::Key, key);
+ next(state::equals);
+ }
+
+ ATTRIBUTE(hot)
+ void state_equals(ui8 ch) {
+ // skip '='
+ if (Y_UNLIKELY(ch != NSymbol::key_value_separator)) {
+ COLD_BLOCK_BYVALUE
+ lexer_.fail("Unexpected ", NCEscape::quote(ch), ", expected ", NCEscape::quote(NSymbol::key_value_separator));
+ COLD_BLOCK_END
+ }
+ lexer_.advance(1);
+ next(state::value);
+ // immediately read the following value
+ // (this symbol yields no result)
+ next_event_hot();
+ }
+
+ ATTRIBUTE(noinline, hot)
+ void state_value(ui8 ch, char_class cls) {
+ auto cls_bits = static_cast<ui8>(cls);
+ if (cls_bits & 1) { // Other = x1b
+ if (cls_bits & (1 << 1)) { // Other = xxx11b
+ state_value_text_scalar(cls);
+ } else { // BinaryScalar = x01b
+ state_value_binary_scalar(cls);
+ }
+ next(state::delimiter);
+ } else { // BinaryStringOrOtherSpecialToken = x0b
+ lexer_.advance(1);
+ if (cls_bits & 1 << 1) {
+ // special token
+ auto token = static_cast<special_token>(cls_bits >> 2);
+ state_value_special(token, ch);
+ } else {
+ // binary string
+ yield(lexer_.read_binary_string());
+ next(state::delimiter);
+ }
+ }
+ }
+
+ ATTRIBUTE(noinline)
+ void state_value_special(special_token token, ui8 ch) {
+ // Value starters are always accepted values
+ switch (token) {
+ case special_token::hash:
+ yield(TScalar{});
+ next(state::delimiter);
+ return;
+
+ case special_token::left_bracket:
+ push(EEventType::BeginList);
+ yield(EEventType::BeginList);
+ next(state::maybe_value);
+ return;
+
+ case special_token::left_brace:
+ push(EEventType::BeginMap);
+ yield(EEventType::BeginMap);
+ next(state::maybe_key);
+ return;
+
+ default:
+ break;
+ }
+
+ // ...closing-chars are only allowed in maybe_value state
+ if (state_ == state::maybe_value) {
+ switch (token) {
+ case special_token::right_bracket:
+ pop(EEventType::BeginList, EEventType::EndList);
+ return;
+
+ case special_token::right_brace:
+ pop(EEventType::BeginMap, EEventType::EndMap);
+ return;
+
+ // right_angle is impossible in maybe_value state
+ // (only in delimiter, maybe_key)
+
+ default:
+ break;
+ }
+ }
+
+ // attributes are not allowed after attributes (thus, value_noattr state)
+ if (state_ != state::value_noattr && token == special_token::left_angle) {
+ push(EEventType::BeginAttributes);
+ yield(EEventType::BeginAttributes);
+ next(state::maybe_key);
+ return;
+ }
+
+ COLD_BLOCK_BYVALUE
+ lexer_.fail("Unexpected ", NCEscape::quote(ch));
+ COLD_BLOCK_END
+ }
+
+ ATTRIBUTE(hot)
+ void state_value_binary_scalar(char_class cls) {
+ lexer_.advance(1);
+ switch (cls) {
+ case char_class::binary_double:
+ yield(lexer_.read_binary_double());
+ break;
+
+ case char_class::binary_int64:
+ yield(lexer_.read_binary_int64());
+ break;
+
+ case char_class::binary_uint64:
+ yield(lexer_.read_binary_uint64());
+ break;
+
+ case char_class::binary_false:
+ yield(false);
+ break;
+
+ case char_class::binary_true:
+ yield(true);
+ break;
+
+ default:
+ Y_UNREACHABLE();
+ }
+ }
+
+ ATTRIBUTE(noinline)
+ void state_value_text_scalar(char_class cls) {
+ switch (cls) {
+ case char_class::quote:
+ lexer_.advance(1);
+ yield(lexer_.read_quoted_string());
+ break;
+
+ case char_class::number:
+ yield(lexer_.read_numeric());
+ break;
+
+ case char_class::string:
+ yield(lexer_.read_unquoted_string());
+ break;
+
+ case char_class::percent:
+ lexer_.advance(1);
+ yield(lexer_.read_percent_scalar());
+ break;
+
+ case char_class::none:
+ COLD_BLOCK_BYVALUE
+ lexer_.fail("Invalid yson value.");
+ COLD_BLOCK_END
+ break;
+
+ default:
+ Y_UNREACHABLE();
+ }
+ }
+ };
+
+ class reader_impl: public gen_reader_impl<false> {
+ public:
+ using gen_reader_impl<false>::gen_reader_impl;
+ };
+ }
+}
diff --git a/library/cpp/yson_pull/detail/stream_counter.h b/library/cpp/yson_pull/detail/stream_counter.h
new file mode 100644
index 0000000000..3b41b27eb6
--- /dev/null
+++ b/library/cpp/yson_pull/detail/stream_counter.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <library/cpp/yson_pull/position_info.h>
+
+#include <cstddef>
+
+namespace NYsonPull {
+ namespace NDetail {
+ template <bool EnableLinePositionInfo>
+ class stream_counter;
+
+ template <>
+ class stream_counter<true> {
+ private:
+ size_t offset_ = 0;
+ size_t line_ = 1;
+ size_t column_ = 1;
+
+ public:
+ TPositionInfo info() const {
+ return {offset_, line_, column_};
+ }
+
+ void update(const ui8* begin, const ui8* end) {
+ offset_ += end - begin;
+ for (auto current = begin; current != end; ++current) {
+ ++column_;
+ if (*current == '\n') { //TODO: memchr
+ ++line_;
+ column_ = 1;
+ }
+ }
+ }
+ };
+
+ template <>
+ class stream_counter<false> {
+ private:
+ size_t offset_ = 0;
+
+ public:
+ TPositionInfo info() const {
+ return {offset_, {}, {}};
+ }
+
+ void update(const ui8* begin, const ui8* end) {
+ offset_ += end - begin;
+ }
+ };
+ }
+}
diff --git a/library/cpp/yson_pull/detail/symbols.h b/library/cpp/yson_pull/detail/symbols.h
new file mode 100644
index 0000000000..fe94bb9c41
--- /dev/null
+++ b/library/cpp/yson_pull/detail/symbols.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+#include <util/system/types.h>
+
+namespace NYsonPull {
+ namespace NDetail {
+ namespace NSymbol {
+#define SYM(name, value) constexpr ui8 name = value
+
+ //! Indicates the beginning of a list.
+ SYM(begin_list, '[');
+ //! Indicates the end of a list.
+ SYM(end_list, ']');
+
+ //! Indicates the beginning of a map.
+ SYM(begin_map, '{');
+ //! Indicates the end of a map.
+ SYM(end_map, '}');
+
+ //! Indicates the beginning of an attribute map.
+ SYM(begin_attributes, '<');
+ //! Indicates the end of an attribute map.
+ SYM(end_attributes, '>');
+
+ //! Separates items in lists and pairs in maps or attribute maps.
+ SYM(item_separator, ';');
+ //! Separates keys from values in maps and attribute maps.
+ SYM(key_value_separator, '=');
+
+ //! Indicates an entity.
+ SYM(entity, '#');
+ //! Indicates end of stream.
+ SYM(eof, '\0');
+
+ //! Marks the beginning of a binary string literal.
+ SYM(string_marker, '\x01');
+ //! Marks the beginning of a binary int64 literal.
+ SYM(int64_marker, '\x02');
+ //! Marks the beginning of a binary uint64 literal.
+ SYM(uint64_marker, '\x06');
+ //! Marks the beginning of a binary double literal.
+ SYM(double_marker, '\x03');
+ //! Marks a binary `false' boolean value.
+ SYM(false_marker, '\x04');
+ //! Marks a binary `true' boolean value.
+ SYM(true_marker, '\x05');
+
+ //! Text string quote symbol
+ SYM(quote, '"');
+
+#undef SYM
+ }
+ }
+}
diff --git a/library/cpp/yson_pull/detail/traits.h b/library/cpp/yson_pull/detail/traits.h
new file mode 100644
index 0000000000..869a3b9c44
--- /dev/null
+++ b/library/cpp/yson_pull/detail/traits.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <type_traits>
+
+namespace NYsonPull {
+ namespace NDetail {
+ namespace NTraits {
+ template <typename T, typename U>
+ using if_signed = typename std::enable_if<
+ std::is_signed<T>::value,
+ U>::type;
+
+ template <typename T, typename U>
+ using if_unsigned = typename std::enable_if<
+ std::is_unsigned<T>::value,
+ U>::type;
+
+ template <typename T>
+ using to_unsigned = typename std::enable_if<
+ std::is_signed<T>::value,
+ typename std::make_unsigned<T>::type>::type;
+
+ template <typename T>
+ using to_signed = typename std::enable_if<
+ std::is_unsigned<T>::value,
+ typename std::make_signed<T>::type>::type;
+ }
+ } // namespace NDetail
+}
diff --git a/library/cpp/yson_pull/detail/varint.h b/library/cpp/yson_pull/detail/varint.h
new file mode 100644
index 0000000000..38bf45d925
--- /dev/null
+++ b/library/cpp/yson_pull/detail/varint.h
@@ -0,0 +1,260 @@
+#pragma once
+
+#include "byte_reader.h"
+#include "byte_writer.h"
+#include "traits.h"
+#include "zigzag.h"
+
+#include <util/system/types.h>
+
+#include <cstddef>
+#include <type_traits>
+
+namespace NYsonPull {
+ namespace NDetail {
+ namespace NVarInt {
+ namespace NImpl {
+ template <typename T>
+ constexpr inline size_t max_size() {
+ return (8 * sizeof(T) - 1) / 7 + 1;
+ }
+
+ template <typename T>
+ inline size_t write(ui64 value, T&& consume) {
+ auto stop = false;
+ auto nwritten = size_t{0};
+ while (!stop) {
+ ++nwritten;
+ auto byte = static_cast<ui8>(value | 0x80);
+ value >>= 7;
+ if (value == 0) {
+ stop = true;
+ byte &= 0x7F;
+ }
+ consume(byte);
+ }
+ return nwritten;
+ }
+
+ template <typename U>
+ inline bool read_fast(byte_reader<U>& reader, ui64* value) {
+ auto& buf = reader.stream().buffer();
+ auto* ptr = buf.pos();
+ ui32 b;
+
+ // Splitting into 32-bit pieces gives better performance on 32-bit
+ // processors.
+ ui32 part0 = 0, part1 = 0, part2 = 0;
+
+ b = *(ptr++);
+ part0 = (b & 0x7F);
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part0 |= (b & 0x7F) << 7;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part0 |= (b & 0x7F) << 14;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part0 |= (b & 0x7F) << 21;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part1 = (b & 0x7F);
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part1 |= (b & 0x7F) << 7;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part1 |= (b & 0x7F) << 14;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part1 |= (b & 0x7F) << 21;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part2 = (b & 0x7F);
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ part2 |= (b & 0x7F) << 7;
+ if (!(b & 0x80))
+ goto done;
+
+ // We have overrun the maximum size of a Varint (10 bytes). The data
+ // must be corrupt.
+ return false;
+
+ done:
+ reader.advance(ptr - buf.pos());
+ *value = (static_cast<ui64>(part0)) | (static_cast<ui64>(part1) << 28) | (static_cast<ui64>(part2) << 56);
+ return true;
+ }
+
+ template <typename U>
+ inline bool read_fast(byte_reader<U>& reader, ui32* value) {
+ // Fast path: We have enough bytes left in the buffer to guarantee that
+ // this read won't cross the end, so we can skip the checks.
+ auto& buf = reader.stream().buffer();
+ auto* ptr = buf.pos();
+ ui32 b;
+ ui32 result;
+
+ b = *(ptr++);
+ result = (b & 0x7F);
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ result |= (b & 0x7F) << 7;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ result |= (b & 0x7F) << 14;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ result |= (b & 0x7F) << 21;
+ if (!(b & 0x80))
+ goto done;
+ b = *(ptr++);
+ result |= b << 28;
+ if (!(b & 0x80))
+ goto done;
+
+ // FIXME
+ // If the input is larger than 32 bits, we still need to read it all
+ // and discard the high-order bits.
+
+ for (size_t i = 0; i < max_size<ui64>() - max_size<ui32>(); i++) {
+ b = *(ptr++);
+ if (!(b & 0x80))
+ goto done;
+ }
+
+ // We have overrun the maximum size of a Varint (10 bytes). Assume
+ // the data is corrupt.
+ return false;
+
+ done:
+ reader.advance(ptr - buf.pos());
+ *value = result;
+ return true;
+ }
+
+ template <typename U>
+ inline bool read_slow(byte_reader<U>& reader, ui64* value) {
+ // Slow path: This read might cross the end of the buffer, so we
+ // need to check and refresh the buffer if and when it does.
+
+ auto& buf = reader.stream().buffer();
+ ui64 result = 0;
+ int count = 0;
+ ui32 b;
+
+ do {
+ if (count == max_size<ui64>()) {
+ return false;
+ }
+ reader.fill_buffer();
+ if (reader.stream().at_end()) {
+ return false;
+ }
+ b = *buf.pos();
+ result |= static_cast<ui64>(b & 0x7F) << (7 * count);
+ reader.advance(1);
+ ++count;
+ } while (b & 0x80);
+
+ *value = result;
+ return true;
+ }
+
+ template <typename U>
+ inline bool read_slow(byte_reader<U>& reader, ui32* value) {
+ ui64 result;
+ // fallback to 64-bit reading
+ if (read_slow(reader, &result) && result <= std::numeric_limits<ui32>::max()) {
+ *value = static_cast<ui32>(result);
+ return true;
+ }
+
+ return false;
+ }
+
+ // Following functions is an adaptation
+ // of Protobuf code from coded_stream.cc
+ template <typename T, typename U>
+ inline bool read_dispatch(byte_reader<U>& reader, T* value) {
+ auto& buf = reader.stream().buffer();
+ // NOTE: checking for 64-bit max_size(), since 32-bit
+ // read_fast() might fallback to 64-bit reading
+ if (buf.available() >= max_size<ui64>() ||
+ // Optimization: If the Varint ends at exactly the end of the buffer,
+ // we can detect that and still use the fast path.
+ (!buf.is_empty() && !(buf.end()[-1] & 0x80)))
+ {
+ return read_fast(reader, value);
+ } else {
+ // Really slow case: we will incur the cost of an extra function call here,
+ // but moving this out of line reduces the size of this function, which
+ // improves the common case. In micro benchmarks, this is worth about 10-15%
+ return read_slow(reader, value);
+ }
+ }
+
+ }
+
+ // Various functions to read/write varints.
+
+ // Returns the number of bytes written.
+ template <typename T>
+ inline NTraits::if_unsigned<T, size_t> write(ui8* data, T value) {
+ return NImpl::write(
+ static_cast<ui64>(value),
+ [&](ui8 byte) { *data++ = byte; });
+ }
+
+ template <typename T>
+ inline NTraits::if_signed<T, size_t> write(ui8* data, T value) {
+ return NImpl::write(
+ static_cast<ui64>(NZigZag::encode(value)),
+ [&](ui8 byte) { *data++ = byte; });
+ }
+
+ template <typename T, typename U>
+ inline void write(byte_writer<U>& stream, T value) {
+ ui8 data[NImpl::max_size<T>()];
+ auto size = write(data, value);
+ stream.write(data, size);
+ }
+
+ template <typename T, typename U>
+ inline NTraits::if_unsigned<T, T> read(byte_reader<U>& reader) {
+ auto value = T{};
+ auto& buf = reader.stream().buffer();
+ if (!buf.is_empty() && *buf.pos() < 0x80) {
+ value = *buf.pos();
+ reader.advance(1);
+ return value;
+ }
+
+ if (Y_UNLIKELY(!NImpl::read_dispatch(reader, &value))) {
+ reader.fail("Error parsing varint value");
+ }
+ return value;
+ }
+
+ template <typename T, typename U>
+ inline NTraits::if_signed<T, T> read(byte_reader<U>& reader) {
+ return NZigZag::decode(
+ read<NTraits::to_unsigned<T>>(reader));
+ }
+ }
+ } // namespace NDetail
+}
diff --git a/library/cpp/yson_pull/detail/writer.h b/library/cpp/yson_pull/detail/writer.h
new file mode 100644
index 0000000000..b24b994292
--- /dev/null
+++ b/library/cpp/yson_pull/detail/writer.h
@@ -0,0 +1,566 @@
+#pragma once
+
+#include "byte_writer.h"
+#include "cescape.h"
+#include "percent_scalar.h"
+#include "stream_counter.h"
+#include "symbols.h"
+#include "varint.h"
+
+#include <library/cpp/yson_pull/consumer.h>
+#include <library/cpp/yson_pull/event.h>
+#include <library/cpp/yson_pull/output.h>
+#include <library/cpp/yson_pull/stream_type.h>
+#include <library/cpp/yson_pull/writer.h>
+
+#include <util/generic/vector.h>
+#include <util/system/yassert.h>
+
+#include <cmath>
+
+namespace NYsonPull {
+ namespace NDetail {
+ class writer: public IConsumer {
+ enum class state {
+ maybe_key,
+ maybe_value,
+ value,
+ value_noattr,
+ before_begin,
+ before_end,
+ after_end,
+ };
+
+ byte_writer<stream_counter<false>> stream_;
+ TVector<EEventType> stack_;
+ bool need_item_separator_ = false;
+ EStreamType mode_ = EStreamType::ListFragment;
+ state state_ = state::before_begin;
+
+ public:
+ void OnBeginStream() override {
+ update_state(EEventType::BeginStream);
+ }
+
+ void OnEndStream() override {
+ update_state(EEventType::EndStream);
+ stream_.flush_buffer();
+ }
+
+ void OnBeginList() override {
+ begin_node();
+ write(NSymbol::begin_list);
+ update_state(EEventType::BeginList);
+ begin_collection(collection_type::list);
+ }
+
+ void OnEndList() override {
+ update_state(EEventType::EndList);
+ end_collection(collection_type::list);
+ write(NSymbol::end_list);
+ end_node();
+ }
+
+ void OnBeginMap() override {
+ begin_node();
+ write(NSymbol::begin_map);
+ update_state(EEventType::BeginMap);
+ begin_collection(collection_type::map);
+ }
+
+ void OnEndMap() override {
+ update_state(EEventType::EndMap);
+ end_collection(collection_type::map);
+ write(NSymbol::end_map);
+ end_node();
+ }
+
+ void OnBeginAttributes() override {
+ begin_node();
+ write(NSymbol::begin_attributes);
+ update_state(EEventType::BeginAttributes);
+ begin_collection(collection_type::attributes);
+ }
+
+ void OnEndAttributes() override {
+ update_state(EEventType::EndAttributes);
+ end_collection(collection_type::attributes);
+ write(NSymbol::end_attributes);
+ // no end_node
+ }
+
+ void OnEntity() override {
+ begin_node();
+ update_state(EEventType::Scalar);
+ write(NSymbol::entity);
+ end_node();
+ }
+
+ protected:
+ enum class collection_type {
+ list,
+ map,
+ attributes,
+ };
+
+ writer(NYsonPull::NOutput::IStream& stream, EStreamType mode)
+ : stream_(stream)
+ , mode_{mode} {
+ }
+
+ bool need_item_separator() const {
+ return need_item_separator_;
+ }
+ void need_item_separator(bool value) {
+ need_item_separator_ = value;
+ }
+
+ size_t depth() const {
+ Y_ASSERT(!stack_.empty());
+ if (mode_ == EStreamType::Node) {
+ return stack_.size() - 1;
+ } else {
+ return stack_.size() - 2;
+ }
+ }
+ EStreamType mode() const {
+ return mode_;
+ }
+
+ void write(ui8 c) {
+ stream_.write(c);
+ }
+
+ void write(TStringBuf value) {
+ write_raw(value.data(), value.size());
+ }
+
+ void write_raw(const void* ptr, size_t len) {
+ stream_.write(static_cast<const ui8*>(ptr), len);
+ }
+
+ template <typename T>
+ void write_varint(T value) {
+ NVarInt::write(stream_, value);
+ }
+
+ void write_escaped_string(TStringBuf value) {
+ write(NSymbol::quote);
+ NCEscape::encode(stream_, value);
+ write(NSymbol::quote);
+ }
+
+ void push(EEventType type) {
+ stack_.push_back(type);
+ }
+
+ void pop(EEventType type) {
+ if (stack_.empty()) {
+ fail("Unpaired events: empty event stack");
+ }
+ if (stack_.back() != type) {
+ fail("Unpaired events: expected ", type, ", got ", stack_.back());
+ }
+ stack_.pop_back();
+ }
+
+ void update_state(EEventType event) {
+ switch (state_) {
+ case state::before_begin:
+ if (event != EEventType::BeginStream) {
+ fail("Expected begin_stream, got ", event);
+ }
+ begin_stream();
+ return;
+
+ case state::before_end:
+ if (event != EEventType::EndStream) {
+ fail("Expected end_stream, got ", event);
+ }
+ end_stream();
+ return;
+
+ case state::after_end:
+ fail("Attempted write past stream end");
+
+ case state::maybe_key:
+ if (event == EEventType::Key) {
+ state_ = state::value;
+ return;
+ }
+
+ switch (event) {
+ case EEventType::EndStream:
+ end_stream();
+ return;
+
+ case EEventType::EndMap:
+ pop(EEventType::BeginMap);
+ next_state();
+ return;
+
+ case EEventType::EndAttributes:
+ pop(EEventType::BeginAttributes);
+ state_ = state::value_noattr;
+ return;
+
+ default:
+ fail("Unexpected event ", event, " in maybe_key");
+ }
+ break;
+
+ case state::maybe_value:
+ switch (event) {
+ case EEventType::EndList:
+ pop(EEventType::BeginList);
+ next_state();
+ return;
+
+ case EEventType::EndStream:
+ end_stream();
+ return;
+
+ default:
+ break;
+ }
+ [[fallthrough]];
+ case state::value:
+ if (event == EEventType::BeginAttributes) {
+ push(EEventType::BeginAttributes);
+ next_state();
+ return;
+ }
+ [[fallthrough]];
+ case state::value_noattr:
+ switch (event) {
+ case EEventType::Scalar:
+ next_state();
+ return;
+
+ case EEventType::BeginList:
+ push(EEventType::BeginList);
+ next_state();
+ return;
+
+ case EEventType::BeginMap:
+ push(EEventType::BeginMap);
+ next_state();
+ return;
+
+ default:
+ fail("Unexpected event ", event, " (in value_*)");
+ }
+ break;
+ }
+ }
+
+ void next_state() {
+ Y_ASSERT(!stack_.empty());
+ switch (stack_.back()) {
+ case EEventType::BeginMap:
+ case EEventType::BeginAttributes:
+ state_ = state::maybe_key;
+ break;
+
+ case EEventType::BeginList:
+ state_ = state::maybe_value;
+ break;
+
+ case EEventType::BeginStream:
+ state_ = state::before_end;
+ break;
+
+ default:
+ Y_UNREACHABLE();
+ }
+ }
+
+ void begin_stream() {
+ push(EEventType::BeginStream);
+ switch (mode_) {
+ case EStreamType::ListFragment:
+ push(EEventType::BeginList);
+ state_ = state::maybe_value;
+ break;
+
+ case EStreamType::MapFragment:
+ push(EEventType::BeginMap);
+ state_ = state::maybe_key;
+ break;
+
+ case EStreamType::Node:
+ state_ = state::value;
+ break;
+ }
+ }
+
+ void end_stream() {
+ switch (mode_) {
+ case EStreamType::ListFragment:
+ pop(EEventType::BeginList);
+ break;
+
+ case EStreamType::MapFragment:
+ pop(EEventType::BeginMap);
+ break;
+
+ case EStreamType::Node:
+ break;
+ }
+ pop(EEventType::BeginStream);
+ state_ = state::after_end;
+ }
+
+ virtual void begin_node() {
+ if (need_item_separator_) {
+ write(NSymbol::item_separator);
+ }
+ }
+
+ virtual void end_node() {
+ need_item_separator_ = true;
+ }
+
+ virtual void begin_key() {
+ begin_node();
+ }
+
+ virtual void end_key() {
+ need_item_separator_ = false;
+ write(NSymbol::key_value_separator);
+ }
+
+ virtual void begin_collection(collection_type type) {
+ Y_UNUSED(type);
+ need_item_separator_ = false;
+ }
+
+ virtual void end_collection(collection_type type) {
+ need_item_separator_ = (type != collection_type::attributes);
+ }
+
+ template <typename... Args>
+ ATTRIBUTE(noinline, cold)
+ void fail[[noreturn]](const char* msg, Args&&... args) {
+ auto formatted_message = format_string(
+ msg,
+ std::forward<Args>(args)...);
+ throw NException::TBadOutput(
+ formatted_message,
+ stream_.counter().info());
+ }
+ };
+
+ class TBinaryWriterImpl final: public writer {
+ public:
+ TBinaryWriterImpl(NYsonPull::NOutput::IStream& stream, EStreamType mode)
+ : writer(stream, mode)
+ {
+ }
+
+ void OnScalarBoolean(bool value) override {
+ update_state(EEventType::Scalar);
+
+ begin_node();
+ write(value ? NSymbol::true_marker : NSymbol::false_marker);
+ end_node();
+ }
+
+ void OnScalarInt64(i64 value) override {
+ update_state(EEventType::Scalar);
+
+ begin_node();
+ write(NSymbol::int64_marker);
+ write_varint(value);
+ end_node();
+ }
+
+ void OnScalarUInt64(ui64 value) override {
+ update_state(EEventType::Scalar);
+
+ begin_node();
+ write(NSymbol::uint64_marker);
+ write_varint(value);
+ end_node();
+ }
+
+ void OnScalarFloat64(double value) override {
+ update_state(EEventType::Scalar);
+
+ begin_node();
+ write(NSymbol::double_marker);
+ write_raw(&value, sizeof value);
+ end_node();
+ }
+
+ void OnScalarString(TStringBuf value) override {
+ update_state(EEventType::Scalar);
+
+ begin_node();
+ write(NSymbol::string_marker);
+ write_varint(static_cast<i32>(value.size()));
+ write_raw(value.data(), value.size());
+ end_node();
+ }
+
+ void OnKey(TStringBuf name) override {
+ update_state(EEventType::Key);
+
+ begin_key();
+ write(NSymbol::string_marker);
+ write_varint(static_cast<i32>(name.size()));
+ write_raw(name.data(), name.size());
+ end_key();
+ }
+ };
+
+ class TTextWriterImpl: public writer {
+ public:
+ TTextWriterImpl(NYsonPull::NOutput::IStream& stream, EStreamType mode)
+ : writer(stream, mode)
+ {
+ }
+
+ void OnScalarBoolean(bool value) override {
+ update_state(EEventType::Scalar);
+
+ begin_node();
+ write(value ? percent_scalar::true_literal : percent_scalar::false_literal);
+ end_node();
+ }
+
+ void OnScalarInt64(i64 value) override {
+ update_state(EEventType::Scalar);
+
+ char buf[32];
+ auto len = ::snprintf(buf, sizeof(buf), "%" PRIi64, value);
+
+ begin_node();
+ write_raw(buf, len);
+ end_node();
+ }
+
+ void OnScalarUInt64(ui64 value) override {
+ update_state(EEventType::Scalar);
+
+ char buf[32];
+ auto len = ::snprintf(buf, sizeof(buf), "%" PRIu64, value);
+
+ begin_node();
+ write_raw(buf, len);
+ write('u');
+ end_node();
+ }
+
+ void OnScalarFloat64(double value) override {
+ update_state(EEventType::Scalar);
+
+ begin_node();
+
+ if (std::isfinite(value)) {
+ char buf[32];
+ auto len = ::snprintf(buf, sizeof(buf), "%#.17lg", value);
+ write_raw(buf, len);
+ } else if (std::isnan(value)) {
+ write(percent_scalar::nan_literal);
+ } else if (value > 0) {
+ write(percent_scalar::positive_inf_literal);
+ } else {
+ write(percent_scalar::negative_inf_literal);
+ }
+
+ end_node();
+ }
+
+ void OnScalarString(TStringBuf value) override {
+ update_state(EEventType::Scalar);
+
+ begin_node();
+ write_escaped_string(value);
+ end_node();
+ }
+
+ void OnKey(TStringBuf name) override {
+ update_state(EEventType::Key);
+
+ begin_key();
+ write_escaped_string(name);
+ end_key();
+ }
+
+ protected:
+ void begin_node() override {
+ if (need_item_separator()) {
+ write(NSymbol::item_separator);
+ write(' ');
+ }
+ }
+
+ void end_node() override {
+ if (mode() != EStreamType::Node && depth() == 0) {
+ write(NSymbol::item_separator);
+ write('\n');
+ need_item_separator(false);
+ } else {
+ writer::end_node();
+ }
+ }
+
+ void end_key() override {
+ write(' ');
+ writer::end_key();
+ write(' ');
+ }
+ };
+
+ class TPrettyWriterImpl final: public TTextWriterImpl {
+ size_t indent_size_;
+
+ public:
+ TPrettyWriterImpl(
+ NYsonPull::NOutput::IStream& stream,
+ EStreamType mode,
+ size_t indent_size)
+ : TTextWriterImpl(stream, mode)
+ , indent_size_{indent_size} {
+ }
+
+ protected:
+ void begin_node() override {
+ if (need_item_separator()) {
+ write(NSymbol::item_separator);
+ newline();
+ }
+ }
+
+ void begin_collection(collection_type type) override {
+ TTextWriterImpl::begin_collection(type);
+ newline();
+ }
+
+ void end_collection(collection_type type) override {
+ TTextWriterImpl::end_collection(type);
+ newline();
+ }
+
+ void newline() {
+ write('\n');
+ indent(depth());
+ }
+
+ void indent(size_t count) {
+ for (size_t i = 0; i < count * indent_size_; ++i) {
+ write(' ');
+ }
+ }
+ };
+
+ template <typename T, typename... Args>
+ NYsonPull::TWriter make_writer(
+ THolder<NYsonPull::NOutput::IStream> stream,
+ Args&&... args) {
+ auto impl = MakeHolder<T>(*stream, std::forward<Args>(args)...);
+ return NYsonPull::TWriter(std::move(stream), std::move(impl));
+ }
+ }
+}
diff --git a/library/cpp/yson_pull/detail/zigzag.h b/library/cpp/yson_pull/detail/zigzag.h
new file mode 100644
index 0000000000..98fcac0e9f
--- /dev/null
+++ b/library/cpp/yson_pull/detail/zigzag.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "traits.h"
+
+namespace NYsonPull {
+ namespace NDetail {
+ namespace NZigZag {
+ //! Functions that provide coding of integers with property: 0 <= f(x) <= 2 * |x|
+
+ template <typename TSigned>
+ inline NTraits::to_unsigned<TSigned> encode(TSigned x) {
+ using TUnsigned = NTraits::to_unsigned<TSigned>;
+ constexpr auto rshift = sizeof(TSigned) * 8 - 1;
+ return (static_cast<TUnsigned>(x) << 1) ^ static_cast<TUnsigned>(x >> rshift);
+ }
+
+ template <typename TUnsigned>
+ inline NTraits::to_signed<TUnsigned> decode(TUnsigned x) {
+ using TSigned = NTraits::to_signed<TUnsigned>;
+ return static_cast<TSigned>(x >> 1) ^ -static_cast<TSigned>(x & 1);
+ }
+ }
+ } // namespace NDetail
+}
diff --git a/library/cpp/yson_pull/event.cpp b/library/cpp/yson_pull/event.cpp
new file mode 100644
index 0000000000..b7ede494b6
--- /dev/null
+++ b/library/cpp/yson_pull/event.cpp
@@ -0,0 +1,18 @@
+#include "event.h"
+
+#include <library/cpp/yson_pull/detail/cescape.h>
+
+#include <util/stream/output.h>
+
+using namespace NYsonPull;
+
+template <>
+void Out<TEvent>(IOutputStream& out, const TEvent& value) {
+ out << '(' << value.Type();
+ if (value.Type() == EEventType::Scalar) {
+ out << ' ' << value.AsScalar();
+ } else if (value.Type() == EEventType::Key) {
+ out << ' ' << NYsonPull::NDetail::NCEscape::quote(value.AsString());
+ }
+ out << ')';
+}
diff --git a/library/cpp/yson_pull/event.h b/library/cpp/yson_pull/event.h
new file mode 100644
index 0000000000..b41d5ea3b5
--- /dev/null
+++ b/library/cpp/yson_pull/event.h
@@ -0,0 +1,85 @@
+#pragma once
+
+#include "cyson_enums.h"
+#include "scalar.h"
+
+#include <util/generic/strbuf.h>
+#include <util/system/types.h>
+#include <util/system/yassert.h>
+
+namespace NYsonPull {
+ //! A well-formed decoded YSON stream can be described by the following grammar:
+ //!
+ //! STREAM[node] ::= begin_stream VALUE end_stream
+ //! STREAM[list_fragment] ::= begin_stream LIST_FRAGMENT end_stream
+ //! STREAM[map_fragment] ::= begin_stream MAP_FRAGMENT end_stream
+ //! LIST_FRAGMENT ::= { VALUE; }
+ //! MAP_FRAGMENT ::= { KEY VALUE; }
+ //! KEY ::= key(String)
+ //! VALUE ::= VALUE_NOATTR | ATTRIBUTES VALUE_NOATTR
+ //! ATTRIBUTES ::= begin_attributes MAP_FRAGMENT end_attributes
+ //! VALUE_NOATTR ::= scalar(Scalar) | LIST | MAP
+ //! LIST ::= begin_list LIST_FRAGMENT end_list
+ //! MAP ::= begin_map MAP_FRAGMENT end_map
+
+ //! \brief YSON event type tag. Corresponds to YSON grammar.
+ enum class EEventType {
+ BeginStream = YSON_EVENT_BEGIN_STREAM,
+ EndStream = YSON_EVENT_END_STREAM,
+ BeginList = YSON_EVENT_BEGIN_LIST,
+ EndList = YSON_EVENT_END_LIST,
+ BeginMap = YSON_EVENT_BEGIN_MAP,
+ EndMap = YSON_EVENT_END_MAP,
+ BeginAttributes = YSON_EVENT_BEGIN_ATTRIBUTES,
+ EndAttributes = YSON_EVENT_END_ATTRIBUTES,
+ Key = YSON_EVENT_KEY,
+ Scalar = YSON_EVENT_SCALAR,
+ };
+
+ //! \brief YSON event variant type.
+ class TEvent {
+ EEventType Type_;
+ TScalar Value_;
+
+ public:
+ //! \brief Construct a tag-only event.
+ explicit constexpr TEvent(EEventType type = EEventType::BeginStream)
+ : Type_{type} {
+ }
+
+ //! \brief Construct a tag+value event.
+ //!
+ //! Only \p EEventType::key is meaningful.
+ constexpr TEvent(EEventType type, const TScalar& value)
+ : Type_{type}
+ , Value_{value} {
+ }
+
+ //! \brief Construct a \p EEventType::scalar event.
+ explicit constexpr TEvent(const TScalar& value)
+ : Type_{EEventType::Scalar}
+ , Value_{value} {
+ }
+
+ EEventType Type() const {
+ return Type_;
+ }
+
+ //! \brief Get TScalar value.
+ //!
+ //! Undefined behaviour when event type is not \p EEventType::scalar.
+ const TScalar& AsScalar() const {
+ Y_ASSERT(Type_ == EEventType::Scalar || Type_ == EEventType::Key);
+ return Value_;
+ }
+
+ //! \brief Get string value.
+ //!
+ //! Undefined behaviour when event type is not \p EEventType::key.
+ TStringBuf AsString() const {
+ Y_ASSERT(Type_ == EEventType::Key || (Type_ == EEventType::Scalar && Value_.Type() == EScalarType::String));
+ return Value_.AsString();
+ }
+ };
+
+}
diff --git a/library/cpp/yson_pull/exceptions.cpp b/library/cpp/yson_pull/exceptions.cpp
new file mode 100644
index 0000000000..e1d68493e7
--- /dev/null
+++ b/library/cpp/yson_pull/exceptions.cpp
@@ -0,0 +1,45 @@
+#include "exceptions.h"
+
+#include <util/string/builder.h>
+
+#include <cerrno>
+#include <cstring>
+
+using namespace NYsonPull::NException;
+
+const char* TBadStream::what() const noexcept {
+ TStringBuilder stream;
+ stream << "Invalid YSON";
+ if (Position_.Offset || Position_.Line || Position_.Column) {
+ bool first = true;
+ stream << " at ";
+ if (Position_.Offset) {
+ stream << "offset " << *Position_.Offset;
+ first = false;
+ }
+ if (Position_.Line) {
+ if (!first) {
+ stream << ", ";
+ }
+ stream << "line " << *Position_.Line;
+ first = false;
+ }
+ if (Position_.Column) {
+ if (!first) {
+ stream << ", ";
+ }
+ stream << "column " << *Position_.Column;
+ }
+ }
+ stream << ": " << Message_;
+ FormattedMessage_ = stream;
+ return FormattedMessage_.c_str();
+}
+
+NYsonPull::NException::TSystemError::TSystemError()
+ : SavedErrno_{errno} {
+}
+
+const char* NYsonPull::NException::TSystemError::what() const noexcept {
+ return ::strerror(SavedErrno_);
+}
diff --git a/library/cpp/yson_pull/exceptions.h b/library/cpp/yson_pull/exceptions.h
new file mode 100644
index 0000000000..ebfed950a5
--- /dev/null
+++ b/library/cpp/yson_pull/exceptions.h
@@ -0,0 +1,59 @@
+#pragma once
+
+#include "position_info.h"
+
+#include <util/generic/string.h>
+
+#include <stdexcept>
+#include <string>
+
+namespace NYsonPull {
+ namespace NException {
+ class TBadStream: public std::exception {
+ TString Message_;
+ TPositionInfo Position_;
+ mutable TString FormattedMessage_;
+
+ public:
+ TBadStream(
+ TString message,
+ const TPositionInfo& position)
+ : Message_(std::move(message))
+ , Position_(position)
+ {
+ }
+
+ const TPositionInfo& Position() const {
+ return Position_;
+ }
+
+ const char* what() const noexcept override;
+ };
+
+ class TBadInput: public TBadStream {
+ public:
+ using TBadStream::TBadStream;
+ };
+
+ class TBadOutput: public TBadStream {
+ public:
+ using TBadStream::TBadStream;
+ };
+
+ class TSystemError: public std::exception {
+ int SavedErrno_;
+
+ public:
+ TSystemError();
+ TSystemError(int saved_errno)
+ : SavedErrno_{saved_errno} {
+ }
+
+ int saved_errno() const noexcept {
+ return SavedErrno_;
+ }
+
+ const char* what() const noexcept override;
+ };
+ }
+}
diff --git a/library/cpp/yson_pull/input.cpp b/library/cpp/yson_pull/input.cpp
new file mode 100644
index 0000000000..1373c89868
--- /dev/null
+++ b/library/cpp/yson_pull/input.cpp
@@ -0,0 +1,33 @@
+#include "input.h"
+
+#include <library/cpp/yson_pull/detail/input/stdio_file.h>
+#include <library/cpp/yson_pull/detail/input/stream.h>
+
+#include <util/generic/ptr.h>
+#include <util/stream/file.h>
+#include <util/stream/mem.h>
+
+using namespace NYsonPull::NInput;
+using namespace NYsonPull::NDetail::NInput;
+
+namespace NInput = NYsonPull::NInput;
+
+THolder<IStream> NInput::FromStdioFile(FILE* file, size_t buffer_size) {
+ return MakeHolder<TStdioFile>(file, buffer_size);
+}
+
+THolder<IStream> NInput::FromPosixFd(int fd, size_t buffer_size) {
+ return MakeHolder<TFHandle>(fd, buffer_size);
+}
+
+THolder<IStream> NInput::FromMemory(TStringBuf data) {
+ return MakeHolder<TOwned<TMemoryInput>>(data);
+}
+
+THolder<IStream> NInput::FromInputStream(IInputStream* input, size_t buffer_size) {
+ return MakeHolder<TOwned<TBufferedInput>>(input, buffer_size);
+}
+
+THolder<IStream> NInput::FromZeroCopyInput(IZeroCopyInput* input) {
+ return MakeHolder<TZeroCopy>(input);
+}
diff --git a/library/cpp/yson_pull/input.h b/library/cpp/yson_pull/input.h
new file mode 100644
index 0000000000..2cdfae857e
--- /dev/null
+++ b/library/cpp/yson_pull/input.h
@@ -0,0 +1,81 @@
+#pragma once
+
+#include "buffer.h"
+
+#include <util/generic/ptr.h>
+#include <util/generic/strbuf.h>
+#include <util/system/types.h>
+#include <util/system/yassert.h>
+
+#include <cstddef>
+#include <memory>
+
+class IInputStream;
+class IZeroCopyInput;
+
+namespace NYsonPull {
+ namespace NInput {
+ //! \brief Input stream adaptor interface.
+ //!
+ //! Represents a model of a chunked input data stream.
+ class IStream {
+ input_buffer buffer_;
+ bool at_end_ = false;
+
+ public:
+ virtual ~IStream() = default;
+
+ bool at_end() const {
+ return at_end_;
+ }
+
+ input_buffer& buffer() noexcept {
+ return buffer_;
+ }
+ const input_buffer& buffer() const noexcept {
+ return buffer_;
+ }
+
+ void fill_buffer() {
+ while (buffer_.is_empty() && !at_end()) {
+ at_end_ = do_fill_buffer() == result::at_end;
+ }
+ }
+
+ protected:
+ enum class result {
+ have_more_data, //! May continue reading
+ at_end, //! Reached end of stream
+ };
+
+ //! \brief Read next chunk of data.
+ //!
+ //! The implementation is to discard the buffer contents
+ //! and reset the buffer to a next chunk of data.
+ //! End-of-stream condition is to be reported via return value.
+ //!
+ //! Read is assumed to always succeed unless it throws an exception.
+ virtual result do_fill_buffer() = 0;
+ };
+
+ //! \brief Read data from a contiguous memory block (i.e. a string)
+ //!
+ //! Does not take ownership on memory.
+ THolder<IStream> FromMemory(TStringBuf data);
+
+ //! \brief Read data from C FILE* object.
+ //!
+ //! Does not take ownership on file object.
+ //! Data is buffered internally regardless of file buffering.
+ THolder<IStream> FromStdioFile(FILE* file, size_t buffer_size = 65536);
+
+ //! \brief Read data from POSIX file descriptor.
+ //!
+ //! Does not take ownership on streambuf.
+ THolder<IStream> FromPosixFd(int fd, size_t buffer_size = 65536);
+
+ THolder<IStream> FromZeroCopyInput(IZeroCopyInput* input);
+
+ THolder<IStream> FromInputStream(IInputStream* input, size_t buffer_size = 65536);
+ }
+}
diff --git a/library/cpp/yson_pull/output.cpp b/library/cpp/yson_pull/output.cpp
new file mode 100644
index 0000000000..27c9ef9e69
--- /dev/null
+++ b/library/cpp/yson_pull/output.cpp
@@ -0,0 +1,29 @@
+#include "output.h"
+
+#include <library/cpp/yson_pull/detail/output/stdio_file.h>
+#include <library/cpp/yson_pull/detail/output/stream.h>
+
+#include <util/generic/ptr.h>
+#include <util/stream/file.h>
+#include <util/stream/str.h>
+
+using namespace NYsonPull::NOutput;
+using namespace NYsonPull::NDetail::NOutput;
+
+namespace NOutput = NYsonPull::NOutput;
+
+THolder<IStream> NOutput::FromStdioFile(FILE* file, size_t buffer_size) {
+ return MakeHolder<TStdioFile>(file, buffer_size);
+}
+
+THolder<IStream> NOutput::FromPosixFd(int fd, size_t buffer_size) {
+ return MakeHolder<TFHandle>(fd, buffer_size);
+}
+
+THolder<IStream> NOutput::FromString(TString* output, size_t buffer_size) {
+ return MakeHolder<TOwned<TStringOutput>>(buffer_size, *output);
+}
+
+THolder<IStream> NOutput::FromOutputStream(IOutputStream* output, size_t buffer_size) {
+ return MakeHolder<TStream>(output, buffer_size);
+}
diff --git a/library/cpp/yson_pull/output.h b/library/cpp/yson_pull/output.h
new file mode 100644
index 0000000000..2d78107a93
--- /dev/null
+++ b/library/cpp/yson_pull/output.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include "buffer.h"
+
+#include <util/generic/ptr.h>
+#include <util/generic/strbuf.h>
+#include <util/system/types.h>
+#include <util/system/yassert.h>
+
+#include <cstddef>
+#include <cstdio>
+#include <cstring>
+#include <memory>
+
+//! \brief Output stream adaptor interface.
+//!
+//! Represents a model of an optionally-buffered writer.
+namespace NYsonPull {
+ namespace NOutput {
+ class IStream {
+ output_buffer buffer_;
+
+ public:
+ virtual ~IStream() = default;
+
+ output_buffer& buffer() noexcept {
+ return buffer_;
+ }
+ const output_buffer& buffer() const noexcept {
+ return buffer_;
+ }
+
+ void flush_buffer(TStringBuf extra = {}) {
+ if (!extra.empty() || !buffer_.is_empty()) {
+ do_flush_buffer(extra);
+ }
+ while (!buffer_.is_empty()) {
+ do_flush_buffer({});
+ }
+ }
+
+ protected:
+ //! \brief Flush data to underlying stream.
+ //!
+ //! The implementation is to flush the buffer contents AND
+ //! extra argument to underlying stream.
+ //!
+ //! This way, at zero buffer size this interface implements an unbuffered
+ //! stream (with an added cost of a virtual call per each write).
+ //!
+ //! Write is assumed to always succeed unless it throws an exception.
+ virtual void do_flush_buffer(TStringBuf extra) = 0;
+ };
+
+ //! \brief Write data to C FILE* object.
+ THolder<IStream> FromStdioFile(FILE* file, size_t buffer_size = 0);
+
+ //! \brief Write data to POSIX file descriptor
+ THolder<IStream> FromPosixFd(int fd, size_t buffer_size = 65536);
+
+ THolder<IStream> FromOutputStream(IOutputStream* output, size_t buffer_size = 65536);
+
+ THolder<IStream> FromString(TString* output, size_t buffer_size = 1024);
+ }
+}
diff --git a/library/cpp/yson_pull/position_info.h b/library/cpp/yson_pull/position_info.h
new file mode 100644
index 0000000000..a65c4663a9
--- /dev/null
+++ b/library/cpp/yson_pull/position_info.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <util/generic/maybe.h>
+#include <util/system/types.h>
+
+namespace NYsonPull {
+ struct TPositionInfo {
+ TMaybe<ui64> Offset;
+ TMaybe<ui64> Line;
+ TMaybe<ui64> Column;
+
+ TPositionInfo() = default;
+ TPositionInfo(
+ TMaybe<ui64> offset_,
+ TMaybe<ui64> line_ = Nothing(),
+ TMaybe<ui64> column_ = Nothing())
+ : Offset{offset_}
+ , Line{line_}
+ , Column{column_} {
+ }
+ };
+
+}
diff --git a/library/cpp/yson_pull/range.h b/library/cpp/yson_pull/range.h
new file mode 100644
index 0000000000..f4fcf3f206
--- /dev/null
+++ b/library/cpp/yson_pull/range.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "reader.h"
+
+#include <util/generic/iterator.h>
+
+namespace NYsonPull {
+ class TStreamEventsRange: public TInputRangeAdaptor<TStreamEventsRange> {
+ TReader Reader_;
+ bool AtEnd;
+
+ public:
+ TStreamEventsRange(THolder<NInput::IStream> stream, EStreamType mode)
+ : Reader_{std::move(stream), mode}
+ , AtEnd(false)
+ {
+ }
+
+ const TEvent* Last() const noexcept {
+ return &Reader_.LastEvent();
+ }
+
+ const TEvent* Next() {
+ if (Y_UNLIKELY(AtEnd)) {
+ return nullptr;
+ }
+
+ auto* event = &Reader_.NextEvent();
+ if (event->Type() == EEventType::EndStream) {
+ AtEnd = true;
+ }
+ return event;
+ }
+ };
+}
diff --git a/library/cpp/yson_pull/read_ops.cpp b/library/cpp/yson_pull/read_ops.cpp
new file mode 100644
index 0000000000..9d7e6a4a2d
--- /dev/null
+++ b/library/cpp/yson_pull/read_ops.cpp
@@ -0,0 +1,66 @@
+#include "read_ops.h"
+
+using namespace NYsonPull;
+using namespace NYsonPull::NReadOps;
+
+namespace {
+ bool TrySkipValueUntil(EEventType end, TReader& reader) {
+ const auto& event = reader.NextEvent();
+ if (event.Type() == end) {
+ return false;
+ }
+ SkipCurrentValue(event, reader);
+ return true;
+ }
+
+ bool TrySkipKeyValueUntil(EEventType end, TReader& reader) {
+ const auto& event = reader.NextEvent();
+ if (event.Type() == end) {
+ return false;
+ }
+ Expect(event, EEventType::Key);
+ SkipValue(reader);
+ return true;
+ }
+}
+
+void NYsonPull::NReadOps::SkipCurrentValue(const TEvent& event, TReader& reader) {
+ switch (event.Type()) {
+ case EEventType::BeginList:
+ while (TrySkipValueUntil(EEventType::EndList, reader)) {
+ }
+ return;
+
+ case EEventType::BeginMap:
+ while (TrySkipKeyValueUntil(EEventType::EndMap, reader)) {
+ }
+ return;
+
+ case EEventType::BeginAttributes:
+ while (TrySkipKeyValueUntil(EEventType::EndAttributes, reader)) {
+ }
+ // attributes after attributes are disallowed in TReader
+ SkipValue(reader);
+ return;
+
+ case EEventType::Scalar:
+ return;
+
+ default:
+ throw yexception() << "Unexpected event: " << event;
+ }
+}
+
+void NYsonPull::NReadOps::SkipValue(TReader& reader) {
+ const auto& event = reader.NextEvent();
+ SkipCurrentValue(event, reader);
+}
+
+void NYsonPull::NReadOps::SkipControlRecords(TReader& reader) {
+ const auto* event = &reader.LastEvent();
+ while (event->Type() == EEventType::BeginAttributes) {
+ SkipCurrentValue(*event, reader);
+ event = &reader.NextEvent();
+ }
+ Expect(*event, EEventType::BeginMap);
+}
diff --git a/library/cpp/yson_pull/read_ops.h b/library/cpp/yson_pull/read_ops.h
new file mode 100644
index 0000000000..5c084983ea
--- /dev/null
+++ b/library/cpp/yson_pull/read_ops.h
@@ -0,0 +1,142 @@
+#pragma once
+
+#include "reader.h"
+
+#include <util/generic/maybe.h>
+#include <util/generic/bt_exception.h>
+#include <util/generic/yexception.h>
+#include <util/system/yassert.h>
+
+/** Imperative recursive-descent parsing helpers.
+ *
+ * These functions help verify conditions and advance parser state.
+ * For aggregate parsing functions, common precondition is to require Begin{X}
+ * event prior to function invocation. Thus, parsers are composable by calling
+ * sub-parser after dispatching on opening event, e.g.:
+ *
+ * if (reader.LastEvent().Type() == EEventType::BeginMap) {
+ * ReadSomeMap(reader)
+ * }
+ *
+ */
+
+namespace NYsonPull {
+ namespace NReadOps {
+ class TExpectationFailure: public TWithBackTrace<yexception> {
+ };
+
+ inline void Expect(const TEvent& got, EEventType expected) {
+ Y_ENSURE_EX(
+ got.Type() == expected,
+ TExpectationFailure() << "expected " << expected << ", got " << got);
+ }
+
+ inline void Expect(const TScalar& got, EScalarType expected) {
+ Y_ENSURE_EX(
+ got.Type() == expected,
+ TExpectationFailure() << "expected scalar " << expected << ", got " << got);
+ }
+
+ // ExpectBegin{X} functions verify that last event WAS X
+ // SkipBegin{X} functions verify that next event WILL BE X and CONSUME it
+
+ inline void ExpectBeginStream(TReader& reader) {
+ Expect(reader.LastEvent(), EEventType::BeginStream);
+ }
+
+ inline void SkipBeginStream(TReader& reader) {
+ Expect(reader.NextEvent(), EEventType::BeginStream);
+ }
+
+ inline void ExpectBeginMap(TReader& reader) {
+ Expect(reader.LastEvent(), EEventType::BeginMap);
+ }
+
+ inline void SkipBeginMap(TReader& reader) {
+ Expect(reader.NextEvent(), EEventType::BeginMap);
+ }
+
+ inline void ExpectBeginList(TReader& reader) {
+ Expect(reader.LastEvent(), EEventType::BeginList);
+ }
+
+ inline void SkipBeginList(TReader& reader) {
+ Expect(reader.NextEvent(), EEventType::BeginList);
+ }
+
+ inline bool ReadListItem(TReader& reader) {
+ return reader.NextEvent().Type() != EEventType::EndList;
+ }
+
+ inline TMaybe<TStringBuf> ReadKey(TReader& reader) {
+ const auto& event = reader.NextEvent();
+ switch (event.Type()) {
+ case EEventType::Key:
+ return event.AsString();
+ case EEventType::EndMap:
+ return Nothing();
+ default:
+ ythrow yexception() << "Unexpected event: " << event;
+ }
+ }
+
+ template <typename T = const TScalar&>
+ inline T ReadScalar(TReader& reader);
+
+ template <>
+ inline const TScalar& ReadScalar<const TScalar&>(TReader& reader) {
+ const auto& event = reader.NextEvent();
+ Expect(event, EEventType::Scalar);
+ return event.AsScalar();
+ }
+
+ template <>
+ inline i64 ReadScalar<i64>(TReader& reader) {
+ const auto& scalar = ReadScalar(reader);
+ Expect(scalar, EScalarType::Int64);
+ return scalar.AsInt64();
+ }
+
+ template <>
+ inline ui64 ReadScalar<ui64>(TReader& reader) {
+ const auto& scalar = ReadScalar(reader);
+ Expect(scalar, EScalarType::UInt64);
+ return scalar.AsUInt64();
+ }
+
+ template <>
+ inline double ReadScalar<double>(TReader& reader) {
+ const auto& scalar = ReadScalar(reader);
+ Expect(scalar, EScalarType::Float64);
+ return scalar.AsFloat64();
+ }
+
+ template <>
+ inline TStringBuf ReadScalar<TStringBuf>(TReader& reader) {
+ const auto& scalar = ReadScalar(reader);
+ Expect(scalar, EScalarType::String);
+ return scalar.AsString();
+ }
+
+ template <>
+ inline TString ReadScalar<TString>(TReader& reader) {
+ return TString(ReadScalar<TStringBuf>(reader));
+ }
+
+ template <>
+ inline bool ReadScalar<bool>(TReader& reader) {
+ const auto& scalar = ReadScalar(reader);
+ Expect(scalar, EScalarType::Boolean);
+ return scalar.AsBoolean();
+ }
+
+ // Skip value that was already started with `event`
+ void SkipCurrentValue(const TEvent& event, TReader& reader);
+
+ // Skip value that starts at `reader.next_event()`
+ void SkipValue(TReader& reader);
+
+ // Skip values with attributes, wait for map value
+ void SkipControlRecords(TReader& reader);
+ }
+}
diff --git a/library/cpp/yson_pull/reader.cpp b/library/cpp/yson_pull/reader.cpp
new file mode 100644
index 0000000000..ea26852756
--- /dev/null
+++ b/library/cpp/yson_pull/reader.cpp
@@ -0,0 +1,27 @@
+#include "reader.h"
+#include <library/cpp/yson_pull/detail/reader.h>
+
+using namespace NYsonPull;
+
+TReader::TReader(
+ THolder<NInput::IStream> stream,
+ EStreamType mode)
+ : Stream_{std::move(stream)}
+ , Impl_{MakeHolder<NDetail::reader_impl>(*Stream_, mode)} {
+}
+
+TReader::TReader(TReader&& other) noexcept
+ : Stream_{std::move(other.Stream_)}
+ , Impl_{std::move(other.Impl_)} {
+}
+
+TReader::~TReader() {
+}
+
+const TEvent& TReader::NextEvent() {
+ return Impl_->next_event();
+}
+
+const TEvent& TReader::LastEvent() const noexcept {
+ return Impl_->last_event();
+}
diff --git a/library/cpp/yson_pull/reader.h b/library/cpp/yson_pull/reader.h
new file mode 100644
index 0000000000..f839b19071
--- /dev/null
+++ b/library/cpp/yson_pull/reader.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "event.h"
+#include "input.h"
+#include "stream_type.h"
+
+#include <util/system/yassert.h>
+
+#include <memory>
+
+namespace NYsonPull {
+ namespace NDetail {
+ class reader_impl;
+ }
+
+ //! \brief YSON reader facade class.
+ //!
+ //! Owns an input stream.
+ class TReader {
+ THolder<NInput::IStream> Stream_;
+ THolder<NDetail::reader_impl> Impl_;
+
+ public:
+ TReader(THolder<NInput::IStream> stream, EStreamType mode);
+ TReader(TReader&&) noexcept;
+ ~TReader();
+
+ //! \brief Advance stream to next event and return it.
+ //!
+ //! Any event data is invalidated by a call to NextEvent();
+ const TEvent& NextEvent();
+
+ //! \brief Get last returned event.
+ const TEvent& LastEvent() const noexcept;
+ };
+
+}
diff --git a/library/cpp/yson_pull/scalar.cpp b/library/cpp/yson_pull/scalar.cpp
new file mode 100644
index 0000000000..4325542e7a
--- /dev/null
+++ b/library/cpp/yson_pull/scalar.cpp
@@ -0,0 +1,57 @@
+#include "scalar.h"
+
+#include <library/cpp/yson_pull/detail/cescape.h>
+
+#include <util/stream/output.h>
+
+using namespace NYsonPull;
+
+template <>
+void Out<TScalar>(IOutputStream& out, const TScalar& value) {
+ out << '(' << value.Type();
+ if (value.Type() != EScalarType::Entity) {
+ out << ' ';
+ }
+ switch (value.Type()) {
+ case EScalarType::Boolean:
+ out << (value.AsBoolean() ? "true" : "false");
+ break;
+ case EScalarType::String:
+ out << NYsonPull::NDetail::NCEscape::quote(value.AsString());
+ break;
+ case EScalarType::Int64:
+ out << value.AsInt64();
+ break;
+ case EScalarType::UInt64:
+ out << value.AsUInt64();
+ break;
+ case EScalarType::Float64:
+ out << value.AsFloat64();
+ break;
+ default:
+ break;
+ }
+ out << ')';
+}
+
+bool NYsonPull::operator==(const TScalar& left, const TScalar& right) noexcept {
+ if (left.Type() != right.Type()) {
+ return false;
+ }
+ switch (left.Type()) {
+ case EScalarType::Boolean:
+ return left.AsBoolean() == right.AsBoolean();
+ case EScalarType::String:
+ return left.AsString() == right.AsString();
+ case EScalarType::Int64:
+ return left.AsInt64() == right.AsInt64();
+ case EScalarType::UInt64:
+ return left.AsUInt64() == right.AsUInt64();
+ case EScalarType::Float64:
+ return left.AsFloat64() == right.AsFloat64();
+ case EScalarType::Entity:
+ return true;
+ default:
+ Y_UNREACHABLE();
+ }
+}
diff --git a/library/cpp/yson_pull/scalar.h b/library/cpp/yson_pull/scalar.h
new file mode 100644
index 0000000000..509fce8b5e
--- /dev/null
+++ b/library/cpp/yson_pull/scalar.h
@@ -0,0 +1,146 @@
+#pragma once
+
+#include "cyson_enums.h"
+
+#include <util/generic/strbuf.h>
+#include <util/system/types.h>
+#include <util/system/yassert.h>
+
+namespace NYsonPull {
+ //! \brief YSON TScalar value type tag
+ enum class EScalarType {
+ Entity = YSON_SCALAR_ENTITY,
+ Boolean = YSON_SCALAR_BOOLEAN,
+ Int64 = YSON_SCALAR_INT64,
+ UInt64 = YSON_SCALAR_UINT64,
+ Float64 = YSON_SCALAR_FLOAT64,
+ String = YSON_SCALAR_STRING,
+ };
+
+ //! \brief YSON TScalar value variant
+ class TScalar {
+ //! \internal \brief YSON TScalar value underlying representation
+ union TScalarValue {
+ struct TScalarStringRef {
+ const char* Data;
+ size_t Size;
+ };
+
+ ui8 AsNothing[1];
+ bool AsBoolean;
+ i64 AsInt64;
+ ui64 AsUInt64;
+ double AsFloat64;
+ TScalarStringRef AsString;
+
+ constexpr TScalarValue()
+ : AsNothing{} {
+ }
+
+ explicit constexpr TScalarValue(bool value)
+ : AsBoolean{value} {
+ }
+
+ explicit constexpr TScalarValue(i64 value)
+ : AsInt64{value} {
+ }
+
+ explicit constexpr TScalarValue(ui64 value)
+ : AsUInt64{value} {
+ }
+
+ explicit constexpr TScalarValue(double value)
+ : AsFloat64{value} {
+ }
+
+ explicit constexpr TScalarValue(TStringBuf value)
+ : AsString{value.data(), value.size()} {
+ }
+ };
+ static_assert(
+ sizeof(TScalarValue) == sizeof(TStringBuf),
+ "bad scalar_value size");
+
+ EScalarType Type_;
+ TScalarValue Value_;
+
+ public:
+ constexpr TScalar()
+ : Type_{EScalarType::Entity} {
+ }
+
+ explicit constexpr TScalar(bool value)
+ : Type_{EScalarType::Boolean}
+ , Value_{value} {
+ }
+
+ explicit constexpr TScalar(i64 value)
+ : Type_{EScalarType::Int64}
+ , Value_{value} {
+ }
+
+ explicit constexpr TScalar(ui64 value)
+ : Type_{EScalarType::UInt64}
+ , Value_{value} {
+ }
+
+ explicit constexpr TScalar(double value)
+ : Type_{EScalarType::Float64}
+ , Value_{value} {
+ }
+
+ explicit constexpr TScalar(TStringBuf value)
+ : Type_{EScalarType::String}
+ , Value_{value} {
+ }
+
+ // Disambiguation for literal constants
+ // In the absence of this constructor,
+ // they get implicitly converted to bool (yikes!)
+ explicit TScalar(const char* value)
+ : Type_{EScalarType::String}
+ , Value_{TStringBuf{value}} {
+ }
+
+ EScalarType Type() const {
+ return Type_;
+ }
+
+#define CAST_TO(Type) \
+ Y_ASSERT(Type_ == EScalarType::Type); \
+ return Value_.As##Type
+
+ bool AsBoolean() const {
+ CAST_TO(Boolean);
+ }
+ i64 AsInt64() const {
+ CAST_TO(Int64);
+ }
+ ui64 AsUInt64() const {
+ CAST_TO(UInt64);
+ }
+ double AsFloat64() const {
+ CAST_TO(Float64);
+ }
+#undef CAST_TO
+
+ TStringBuf AsString() const {
+ Y_ASSERT(Type_ == EScalarType::String);
+ return TStringBuf{
+ Value_.AsString.Data,
+ Value_.AsString.Size,
+ };
+ }
+
+ const TScalarValue& AsUnsafeValue() const {
+ return Value_;
+ }
+ };
+
+ bool operator==(const TScalar& left, const TScalar& right) noexcept;
+
+ inline bool operator!=(const TScalar& left, const TScalar& right) noexcept {
+ return !(left == right);
+ }
+
+}
diff --git a/library/cpp/yson_pull/stream_type.h b/library/cpp/yson_pull/stream_type.h
new file mode 100644
index 0000000000..beac87fe1b
--- /dev/null
+++ b/library/cpp/yson_pull/stream_type.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "cyson_enums.h"
+
+namespace NYsonPull {
+ enum class EStreamType {
+ Node = YSON_STREAM_TYPE_NODE,
+ ListFragment = YSON_STREAM_TYPE_LIST_FRAGMENT,
+ MapFragment = YSON_STREAM_TYPE_MAP_FRAGMENT,
+ };
+}
diff --git a/library/cpp/yson_pull/ut/cescape_ut.cpp b/library/cpp/yson_pull/ut/cescape_ut.cpp
new file mode 100644
index 0000000000..6628ba1d15
--- /dev/null
+++ b/library/cpp/yson_pull/ut/cescape_ut.cpp
@@ -0,0 +1,71 @@
+#include <library/cpp/yson_pull/detail/cescape.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+using namespace NYsonPull::NDetail;
+
+namespace {
+ void test_roundtrip(const TVector<ui8>& str) {
+ TStringBuf str_buf(
+ reinterpret_cast<const char*>(str.data()),
+ str.size());
+ auto tmp = NCEscape::encode(str_buf);
+ auto dest = NCEscape::decode(tmp);
+ UNIT_ASSERT_VALUES_EQUAL_C(
+ str_buf, TStringBuf(dest),
+ "A[" << str.size() << "]: " << str_buf << '\n'
+ << "B[" << tmp.size() << "]: " << tmp << '\n'
+ << "C[" << dest.size() << "]: " << dest);
+ }
+
+ template <size_t N>
+ void test_exhaustive(TVector<ui8>& str) {
+ for (int i = 0; i < 256; ++i) {
+ str[str.size() - N] = static_cast<char>(i);
+ test_exhaustive<N - 1>(str);
+ }
+ }
+
+ template <>
+ void test_exhaustive<0>(TVector<ui8>& str) {
+ test_roundtrip(str);
+ }
+
+ template <size_t N>
+ void test_exhaustive() {
+ TVector<ui8> str(N, ' ');
+ test_exhaustive<N>(str);
+ }
+
+} // anonymous namespace
+
+Y_UNIT_TEST_SUITE(CEscape) {
+ Y_UNIT_TEST(ExhaustiveOneChar) {
+ test_exhaustive<1>();
+ }
+
+ Y_UNIT_TEST(ExhaustiveTwoChars) {
+ test_exhaustive<2>();
+ }
+
+ Y_UNIT_TEST(ExhaustiveThreeChars) {
+ test_exhaustive<3>();
+ }
+
+ Y_UNIT_TEST(SpecialEscapeEncode) {
+ //UNIT_ASSERT_VALUES_EQUAL(R"(\b)", NCEscape::encode("\b"));
+ //UNIT_ASSERT_VALUES_EQUAL(R"(\f)", NCEscape::encode("\f"));
+ UNIT_ASSERT_VALUES_EQUAL(R"(\n)", NCEscape::encode("\n"));
+ UNIT_ASSERT_VALUES_EQUAL(R"(\r)", NCEscape::encode("\r"));
+ UNIT_ASSERT_VALUES_EQUAL(R"(\t)", NCEscape::encode("\t"));
+ }
+
+ Y_UNIT_TEST(SpecialEscapeDecode) {
+ UNIT_ASSERT_VALUES_EQUAL("\b", NCEscape::decode(R"(\b)"));
+ UNIT_ASSERT_VALUES_EQUAL("\f", NCEscape::decode(R"(\f)"));
+ UNIT_ASSERT_VALUES_EQUAL("\n", NCEscape::decode(R"(\n)"));
+ UNIT_ASSERT_VALUES_EQUAL("\r", NCEscape::decode(R"(\r)"));
+ UNIT_ASSERT_VALUES_EQUAL("\t", NCEscape::decode(R"(\t)"));
+ }
+
+} // Y_UNIT_TEST_SUITE(CEscape)
diff --git a/library/cpp/yson_pull/ut/loop_ut.cpp b/library/cpp/yson_pull/ut/loop_ut.cpp
new file mode 100644
index 0000000000..8c7b11dd1c
--- /dev/null
+++ b/library/cpp/yson_pull/ut/loop_ut.cpp
@@ -0,0 +1,382 @@
+#include <library/cpp/yson_pull/input.h>
+#include <library/cpp/yson_pull/output.h>
+#include <library/cpp/yson_pull/reader.h>
+#include <library/cpp/yson_pull/writer.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <cerrno>
+#include <cmath>
+
+#ifdef _unix_
+#include <unistd.h>
+#include <sys/wait.h>
+#endif
+
+namespace {
+ constexpr const char* alphabet =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ void generate(NYsonPull::TWriter& writer, size_t count) {
+ writer.BeginStream();
+ for (size_t i = 0; i < count; ++i) {
+ writer.BeginMap()
+ .Key("ints")
+ .BeginList()
+ .Int64(0)
+ .Int64(-1)
+ .Int64(1000)
+ .Int64(-1000)
+ .EndList()
+ .Key("uints")
+ .BeginList()
+ .UInt64(0)
+ .UInt64(1000)
+ .UInt64(10000000)
+ .EndList()
+ .Key("entities")
+ .BeginList()
+ .Entity()
+ .BeginAttributes()
+ .Key("color")
+ .String("blue")
+ .Key("size")
+ .Int64(100)
+ .EndAttributes()
+ .Entity()
+ .Entity()
+ .EndList()
+ .Key("booleans")
+ .BeginList()
+ .Boolean(true)
+ .Boolean(false)
+ .Boolean(true)
+ .EndList()
+ .Key("floats")
+ .BeginList()
+ .Float64(0.0)
+ .Float64(13.0e30)
+ .Float64(M_PI)
+ .EndList()
+ .Key("strings")
+ .BeginList()
+ .String("hello")
+ .String("")
+ .String("foo \"-bar-\" baz")
+ .String("oh\nwow")
+ .String(alphabet)
+ .EndList()
+ .EndMap();
+ }
+ writer.EndStream();
+ }
+
+#ifdef __clang__
+ // XXX: With all the macros below (esp. UNIT_ASSERT_VALUES_EQUAL) unfolded,
+ // the time it takes clang to optimize generated code becomes abysmal.
+ // Locally disabling optimization brings it back to normal.
+ __attribute__((optnone))
+#endif // __clang__
+ void
+ verify(NYsonPull::TReader& reader, size_t count) {
+#define NEXT(name__) \
+ { \
+ auto& name__ = reader.NextEvent(); // SCOPED_TRACE(e);
+#define END_NEXT }
+#define NEXT_TYPE(type__) \
+ NEXT(e) { \
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::type__, e.Type()); \
+ } \
+ END_NEXT
+#define NEXT_KEY(key__) \
+ NEXT(e) { \
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Key, e.Type()); \
+ UNIT_ASSERT_VALUES_EQUAL(key__, e.AsString()); \
+ } \
+ END_NEXT
+#define NEXT_SCALAR(type__, value__) \
+ NEXT(e) { \
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Scalar, e.Type()); \
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EScalarType::type__, e.AsScalar().Type()); \
+ UNIT_ASSERT_VALUES_EQUAL(value__, e.AsScalar().As##type__()); \
+ } \
+ END_NEXT
+#define NEXT_ENTITY() \
+ NEXT(e) { \
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Scalar, e.Type()); \
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EScalarType::Entity, e.AsScalar().Type()); \
+ } \
+ END_NEXT
+#define NEXT_FLOAT64(value__) \
+ NEXT(e) { \
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Scalar, e.Type()); \
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EScalarType::Float64, e.AsScalar().Type()); \
+ UNIT_ASSERT_DOUBLES_EQUAL(value__, e.AsScalar().AsFloat64(), 1e-5); \
+ } \
+ END_NEXT
+
+ constexpr auto true_ = true;
+ constexpr auto false_ = false;
+
+ NEXT_TYPE(BeginStream);
+ for (size_t i = 0; i < count; ++i) {
+ NEXT_TYPE(BeginMap);
+ NEXT_KEY("ints") {
+ NEXT_TYPE(BeginList);
+ NEXT_SCALAR(Int64, 0);
+ NEXT_SCALAR(Int64, -1);
+ NEXT_SCALAR(Int64, 1000);
+ NEXT_SCALAR(Int64, -1000);
+ NEXT_TYPE(EndList);
+ }
+ NEXT_KEY("uints") {
+ NEXT_TYPE(BeginList);
+ NEXT_SCALAR(UInt64, 0U);
+ NEXT_SCALAR(UInt64, 1000U);
+ NEXT_SCALAR(UInt64, 10000000U);
+ NEXT_TYPE(EndList);
+ }
+ NEXT_KEY("entities") {
+ NEXT_TYPE(BeginList);
+ NEXT_ENTITY();
+ NEXT_TYPE(BeginAttributes) {
+ NEXT_KEY("color") {
+ NEXT_SCALAR(String, "blue");
+ }
+ NEXT_KEY("size") {
+ NEXT_SCALAR(Int64, 100);
+ }
+ }
+ NEXT_TYPE(EndAttributes);
+ NEXT_ENTITY();
+ NEXT_ENTITY();
+ NEXT_TYPE(EndList);
+ }
+ NEXT_KEY("booleans") {
+ NEXT_TYPE(BeginList);
+ NEXT_SCALAR(Boolean, true_);
+ NEXT_SCALAR(Boolean, false_);
+ NEXT_SCALAR(Boolean, true_);
+ NEXT_TYPE(EndList);
+ }
+ NEXT_KEY("floats") {
+ NEXT_TYPE(BeginList);
+ NEXT_FLOAT64(0.0);
+ NEXT_FLOAT64(13.0e30);
+ NEXT_FLOAT64(M_PI);
+ NEXT_TYPE(EndList);
+ }
+ NEXT_KEY("strings") {
+ NEXT_TYPE(BeginList);
+ NEXT_SCALAR(String, "hello");
+ NEXT_SCALAR(String, "");
+ NEXT_SCALAR(String, "foo \"-bar-\" baz");
+ NEXT_SCALAR(String, "oh\nwow");
+ NEXT_SCALAR(String, alphabet);
+ NEXT_TYPE(EndList);
+ }
+ NEXT_TYPE(EndMap);
+ }
+ NEXT_TYPE(EndStream);
+
+#undef NEXT
+#undef END_NEXT
+#undef NEXT_TYPE
+#undef NEXT_KEY
+#undef NEXT_SCALAR
+ }
+
+ class sys_error {};
+
+ IOutputStream& operator<<(IOutputStream& stream, const sys_error&) {
+ stream << strerror(errno);
+ return stream;
+ }
+
+ NYsonPull::TReader make_reader(THolder<NYsonPull::NInput::IStream> stream) {
+ return NYsonPull::TReader(
+ std::move(stream),
+ NYsonPull::EStreamType::ListFragment);
+ }
+
+ template <typename Function>
+ void test_memory(Function make_writer, size_t nrepeat) {
+ TString text;
+ {
+ auto writer = make_writer(NYsonPull::NOutput::FromString(&text));
+ generate(writer, nrepeat);
+ }
+ {
+ auto reader = make_reader(NYsonPull::NInput::FromMemory(text));
+ verify(reader, nrepeat);
+ }
+ {
+ TStringInput input(text);
+ auto reader = make_reader(NYsonPull::NInput::FromInputStream(&input, /* buffer_size = */ 1));
+ verify(reader, nrepeat);
+ }
+ }
+
+#ifdef _unix_
+ template <typename Here, typename There>
+ void pipe(Here&& reader, There&& writer) {
+ int fildes[2];
+ UNIT_ASSERT_VALUES_EQUAL_C(0, ::pipe(fildes), sys_error());
+ auto read_fd = fildes[0];
+ auto write_fd = fildes[1];
+
+ auto pid = ::fork();
+ UNIT_ASSERT_C(pid >= 0, sys_error());
+ if (pid > 0) {
+ // parent
+ UNIT_ASSERT_VALUES_EQUAL_C(0, ::close(write_fd), sys_error());
+ reader(read_fd);
+ UNIT_ASSERT_VALUES_EQUAL_C(0, ::close(read_fd), sys_error());
+ } else {
+ // child
+ UNIT_ASSERT_VALUES_EQUAL_C(0, ::close(read_fd), sys_error());
+ UNIT_ASSERT_NO_EXCEPTION(writer(write_fd));
+ UNIT_ASSERT_VALUES_EQUAL_C(0, ::close(write_fd), sys_error());
+ ::exit(0);
+ }
+ int stat_loc;
+ UNIT_ASSERT_VALUES_EQUAL_C(pid, ::waitpid(pid, &stat_loc, 0), sys_error());
+ }
+
+ template <typename Function>
+ void test_posix_fd(
+ Function make_writer,
+ size_t nrepeat,
+ size_t read_buffer_size,
+ size_t write_buffer_size) {
+ pipe(
+ [&](int fd) {
+ auto reader = make_reader(NYsonPull::NInput::FromPosixFd(fd, read_buffer_size));
+ verify(reader, nrepeat);
+ },
+ [&](int fd) {
+ auto writer = make_writer(NYsonPull::NOutput::FromPosixFd(fd, write_buffer_size));
+ generate(writer, nrepeat);
+ });
+ }
+
+ template <typename Function>
+ void test_stdio_file(
+ Function make_writer,
+ size_t nrepeat,
+ size_t read_buffer_size,
+ size_t write_buffer_size) {
+ pipe(
+ [&](int fd) {
+ auto file = ::fdopen(fd, "rb");
+ UNIT_ASSERT_C(file != nullptr, sys_error());
+ auto reader = make_reader(NYsonPull::NInput::FromStdioFile(file, read_buffer_size));
+ verify(reader, nrepeat);
+ },
+ [&](int fd) {
+ auto file = ::fdopen(fd, "wb");
+ Y_UNUSED(write_buffer_size);
+ auto writer = make_writer(NYsonPull::NOutput::FromStdioFile(file, write_buffer_size));
+ generate(writer, nrepeat);
+ fflush(file);
+ });
+ }
+#endif
+
+ NYsonPull::TWriter text(THolder<NYsonPull::NOutput::IStream> stream) {
+ return NYsonPull::MakeTextWriter(
+ std::move(stream),
+ NYsonPull::EStreamType::ListFragment);
+ }
+
+ NYsonPull::TWriter pretty_text(THolder<NYsonPull::NOutput::IStream> stream) {
+ return NYsonPull::MakePrettyTextWriter(
+ std::move(stream),
+ NYsonPull::EStreamType::ListFragment);
+ }
+
+ NYsonPull::TWriter binary(THolder<NYsonPull::NOutput::IStream> stream) {
+ return NYsonPull::MakeBinaryWriter(
+ std::move(stream),
+ NYsonPull::EStreamType::ListFragment);
+ }
+
+} // anonymous namespace
+
+Y_UNIT_TEST_SUITE(Loop) {
+ Y_UNIT_TEST(memory_pretty_text) {
+ test_memory(pretty_text, 100);
+ }
+
+ Y_UNIT_TEST(memory_text) {
+ test_memory(text, 100);
+ }
+
+ Y_UNIT_TEST(memory_binary) {
+ test_memory(binary, 100);
+ }
+
+#ifdef _unix_
+ Y_UNIT_TEST(posix_fd_pretty_text_buffered) {
+ test_posix_fd(pretty_text, 100, 1024, 1024);
+ }
+
+ Y_UNIT_TEST(posix_fd_pretty_text_unbuffered) {
+ test_posix_fd(pretty_text, 100, 1, 0);
+ }
+
+ Y_UNIT_TEST(posix_fd_text_buffered) {
+ test_posix_fd(text, 100, 1024, 1024);
+ }
+
+ Y_UNIT_TEST(posix_fd_text_unbuffered) {
+ test_posix_fd(text, 100, 1, 0);
+ }
+
+ Y_UNIT_TEST(posix_fd_binary_buffered) {
+ test_posix_fd(binary, 100, 1024, 1024);
+ }
+
+ Y_UNIT_TEST(posix_fd_binary_unbuffered) {
+ test_posix_fd(binary, 100, 1, 0);
+ }
+
+ Y_UNIT_TEST(stdio_file_pretty_text_buffered) {
+ test_stdio_file(pretty_text, 100, 1024, 1024);
+ }
+
+ Y_UNIT_TEST(stdio_file_pretty_text_unbuffered) {
+ test_stdio_file(pretty_text, 100, 1, 0);
+ }
+
+ Y_UNIT_TEST(stdio_file_text_buffered) {
+ test_stdio_file(text, 100, 1024, 1024);
+ }
+
+ Y_UNIT_TEST(stdio_file_text_unbuffered) {
+ test_stdio_file(text, 100, 1, 0);
+ }
+
+ Y_UNIT_TEST(stdio_file_binary_buffered) {
+ test_stdio_file(binary, 100, 1024, 1024);
+ }
+
+ Y_UNIT_TEST(stdio_file_binary_unbuffered) {
+ test_stdio_file(binary, 100, 1, 0);
+ }
+#endif
+} // Y_UNIT_TEST_SUITE(Loop)
diff --git a/library/cpp/yson_pull/ut/reader_ut.cpp b/library/cpp/yson_pull/ut/reader_ut.cpp
new file mode 100644
index 0000000000..1184265ddb
--- /dev/null
+++ b/library/cpp/yson_pull/ut/reader_ut.cpp
@@ -0,0 +1,410 @@
+#include <library/cpp/yson_pull/exceptions.h>
+#include <library/cpp/yson_pull/range.h>
+#include <library/cpp/yson_pull/reader.h>
+#include <library/cpp/yson_pull/detail/cescape.h>
+#include <library/cpp/yson_pull/detail/macros.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+namespace {
+ NYsonPull::TReader memory_reader(TStringBuf data, NYsonPull::EStreamType mode) {
+ return NYsonPull::TReader(
+ NYsonPull::NInput::FromMemory(data),
+ mode);
+ }
+
+ template <typename T>
+ void expect_scalar(const NYsonPull::TScalar& scalar, T value) {
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::TScalar{value}, scalar);
+ }
+
+ template <>
+ void expect_scalar(const NYsonPull::TScalar& scalar, double value) {
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EScalarType::Float64, scalar.Type());
+
+ auto scalarValue = scalar.AsFloat64();
+ auto message = TStringBuilder() << "expected " << value << ", got " << scalarValue;
+
+ if (std::isfinite(value)) {
+ UNIT_ASSERT_C(std::isfinite(scalarValue), message);
+ UNIT_ASSERT_DOUBLES_EQUAL(value, scalarValue, 1e-5);
+ } else if (std::isnan(value)) {
+ UNIT_ASSERT_C(std::isnan(scalarValue), message);
+ } else if (value > 0) {
+ UNIT_ASSERT_C(std::isinf(scalarValue) && (scalarValue > 0), message);
+ } else {
+ UNIT_ASSERT_C(std::isinf(scalarValue) && (scalarValue < 0), message);
+ }
+ }
+
+ template <typename T>
+ void test_scalar(TStringBuf data, T value) {
+ // SCOPED_TRACE(NYsonPull::detail::cescape::quote(data));
+ auto reader = memory_reader(data, NYsonPull::EStreamType::Node);
+
+ try {
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::BeginStream, reader.NextEvent().Type());
+ {
+ auto& event = reader.NextEvent();
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Scalar, event.Type());
+ expect_scalar(event.AsScalar(), value);
+ }
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::EndStream, reader.NextEvent().Type());
+ } catch (const std::exception& err) {
+ UNIT_FAIL(err.what());
+ }
+ }
+
+ void consume(TStringBuf data, NYsonPull::EStreamType mode = NYsonPull::EStreamType::Node) {
+ // SCOPED_TRACE(NYsonPull::detail::cescape::quote(data));
+ auto input_range = NYsonPull::TStreamEventsRange(
+ NYsonPull::NInput::FromMemory(data),
+ mode);
+ for (auto& event : input_range) {
+ Y_UNUSED(event);
+ }
+ }
+
+#define ACCEPT(data) UNIT_ASSERT_NO_EXCEPTION(consume(data))
+#define REJECT(data) UNIT_ASSERT_EXCEPTION(consume(data), NYsonPull::NException::TBadInput)
+
+#define ACCEPT2(data, mode) UNIT_ASSERT_NO_EXCEPTION(consume(data, mode))
+#define REJECT2(data, mode) UNIT_ASSERT_EXCEPTION(consume(data, mode), NYsonPull::NException::TBadInput)
+
+} // anonymous namespace
+
+Y_UNIT_TEST_SUITE(Reader) {
+ Y_UNIT_TEST(ScalarEntity) {
+ test_scalar(TStringBuf("#"), NYsonPull::TScalar{});
+ }
+
+ Y_UNIT_TEST(ScalarBoolean) {
+ test_scalar(TStringBuf("%true"), true);
+ test_scalar(TStringBuf("%false"), false);
+
+ test_scalar(TStringBuf("\x05"sv), true);
+ test_scalar(TStringBuf("\x04"sv), false);
+
+ REJECT("%");
+ REJECT("%trueth");
+ REJECT("%tru");
+ REJECT("%falseth");
+ REJECT("%fals");
+ REJECT("%hithere");
+ }
+
+ Y_UNIT_TEST(ScalarInt64) {
+ test_scalar(TStringBuf("1"), i64{1});
+ test_scalar(TStringBuf("+1"), i64{1});
+ test_scalar(TStringBuf("100000"), i64{100000});
+ test_scalar(TStringBuf("+100000"), i64{100000});
+ test_scalar(TStringBuf("-100000"), i64{-100000});
+ test_scalar(TStringBuf("9223372036854775807"), i64{9223372036854775807});
+ test_scalar(TStringBuf("+9223372036854775807"), i64{9223372036854775807});
+
+ test_scalar(TStringBuf("\x02\x02"sv), i64{1});
+ test_scalar(TStringBuf("\x02\xc0\x9a\x0c"sv), i64{100000});
+ test_scalar(TStringBuf("\x02\xbf\x9a\x0c"sv), i64{-100000});
+ test_scalar(TStringBuf("\x02\xfe\xff\xff\xff\xff\xff\xff\xff\xff\x01"sv), i64{9223372036854775807});
+
+ REJECT("1a2");
+ REJECT("1-1-1-1");
+ REJECT("1+0");
+ }
+
+ Y_UNIT_TEST(SclarUInt64) {
+ test_scalar(TStringBuf("1u"), ui64{1});
+ test_scalar(TStringBuf("+1u"), ui64{1});
+ test_scalar(TStringBuf("100000u"), ui64{100000});
+ test_scalar(TStringBuf("+100000u"), ui64{100000});
+ test_scalar(TStringBuf("9223372036854775807u"), ui64{9223372036854775807u});
+ test_scalar(TStringBuf("+9223372036854775807u"), ui64{9223372036854775807u});
+ test_scalar(TStringBuf("18446744073709551615u"), ui64{18446744073709551615u});
+ test_scalar(TStringBuf("+18446744073709551615u"), ui64{18446744073709551615u});
+
+ REJECT("1a2u");
+ REJECT("1-1-1-1u");
+ REJECT("1+0u");
+
+ // TODO: binary
+ }
+
+ Y_UNIT_TEST(ScalarFloat64) {
+ test_scalar(TStringBuf("0.0"), double{0.0});
+ test_scalar(TStringBuf("+0.0"), double{0.0});
+ test_scalar(TStringBuf("+.0"), double{0.0});
+ test_scalar(TStringBuf("+.5"), double{0.5});
+ test_scalar(TStringBuf("-.5"), double{-0.5});
+ test_scalar(TStringBuf("1.0"), double{1.0});
+ test_scalar(TStringBuf("+1.0"), double{1.0});
+ test_scalar(TStringBuf("-1.0"), double{-1.0});
+ test_scalar(TStringBuf("1000.0"), double{1000.0});
+ test_scalar(TStringBuf("+1000.0"), double{1000.0});
+ test_scalar(TStringBuf("-1000.0"), double{-1000.0});
+ test_scalar(TStringBuf("1e12"), double{1e12});
+ test_scalar(TStringBuf("1e+12"), double{1e12});
+ test_scalar(TStringBuf("+1e+12"), double{1e12});
+ test_scalar(TStringBuf("-1e+12"), double{-1e12});
+ test_scalar(TStringBuf("1e-12"), double{1e-12});
+ test_scalar(TStringBuf("+1e-12"), double{1e-12});
+ test_scalar(TStringBuf("-1e-12"), double{-1e-12});
+
+ test_scalar(TStringBuf("\x03\x00\x00\x00\x00\x00\x00\x00\x00"sv), double{0.0});
+
+ test_scalar(
+ TStringBuf("\x03\x00\x00\x00\x00\x00\x00\xf8\x7f"sv),
+ double{std::numeric_limits<double>::quiet_NaN()});
+ test_scalar(
+ TStringBuf("\x03\x00\x00\x00\x00\x00\x00\xf0\x7f"sv),
+ double{std::numeric_limits<double>::infinity()});
+ test_scalar(
+ TStringBuf("\x03\x00\x00\x00\x00\x00\x00\xf0\xff"sv),
+ double{-std::numeric_limits<double>::infinity()});
+
+ test_scalar(
+ TStringBuf("%nan"),
+ double{std::numeric_limits<double>::quiet_NaN()});
+ test_scalar(
+ TStringBuf("%inf"),
+ double{std::numeric_limits<double>::infinity()});
+ test_scalar(
+ TStringBuf("%-inf"),
+ double{-std::numeric_limits<double>::infinity()});
+
+ REJECT("++0.0");
+ REJECT("++1.0");
+ REJECT("++.1");
+ REJECT("1.0.0");
+ //REJECT("1e+10000");
+ REJECT(TStringBuf("\x03\x00\x00\x00\x00\x00\x00\x00"sv));
+
+ // XXX: Questionable behaviour?
+ ACCEPT("+.0");
+ ACCEPT("-.0");
+ // XXX: Rejected on Mac OS, accepted on Linux (?!)
+ //REJECT(".0");
+ //REJECT(".5");
+
+ REJECT("%NaN");
+ REJECT("%+inf");
+ REJECT("%infinity");
+ REJECT("%na");
+ REJECT("%in");
+ REJECT("%-in");
+ }
+
+ Y_UNIT_TEST(ScalarString) {
+ test_scalar(TStringBuf(R"(foobar)"), TStringBuf("foobar"));
+ test_scalar(TStringBuf(R"(foobar11)"), TStringBuf("foobar11"));
+ test_scalar(TStringBuf(R"("foobar")"), TStringBuf("foobar"));
+ // wat? "\x0cf" parsed as a single char? no way!
+ test_scalar("\x01\x0c" "foobar"sv,
+ TStringBuf("foobar"));
+
+ REJECT(R"("foobar)");
+ REJECT("\x01\x0c" "fooba"sv);
+ REJECT("\x01\x0d" "foobar"sv); // negative length
+ }
+
+ Y_UNIT_TEST(EmptyList) {
+ auto reader = memory_reader("[]", NYsonPull::EStreamType::Node);
+
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::BeginStream, reader.NextEvent().Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::BeginList, reader.NextEvent().Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::EndList, reader.NextEvent().Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::EndStream, reader.NextEvent().Type());
+
+ REJECT("[");
+ REJECT("]");
+ }
+
+ Y_UNIT_TEST(EmptyMap) {
+ auto reader = memory_reader("{}", NYsonPull::EStreamType::Node);
+
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::BeginStream, reader.NextEvent().Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::BeginMap, reader.NextEvent().Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::EndMap, reader.NextEvent().Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::EndStream, reader.NextEvent().Type());
+
+ REJECT("{");
+ REJECT("}");
+ }
+
+ Y_UNIT_TEST(Sample) {
+ auto reader = memory_reader(
+ R"({"11"=11;"nothing"=#;"zero"=0.;"foo"="bar";"list"=[1;2;3]})",
+ NYsonPull::EStreamType::Node);
+
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::BeginStream, reader.NextEvent().Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::BeginMap, reader.NextEvent().Type());
+
+ {
+ auto& e = reader.NextEvent();
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Key, e.Type());
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuf("11"), e.AsString());
+ }
+ {
+ auto& e = reader.NextEvent();
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Scalar, e.Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::TScalar{i64{11}}, e.AsScalar());
+ }
+
+ {
+ auto& e = reader.NextEvent();
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Key, e.Type());
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuf("nothing"), e.AsString());
+ }
+ {
+ auto& e = reader.NextEvent();
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Scalar, e.Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::TScalar{}, e.AsScalar());
+ }
+
+ {
+ auto& e = reader.NextEvent();
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Key, e.Type());
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuf("zero"), e.AsString());
+ }
+ {
+ auto& e = reader.NextEvent();
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Scalar, e.Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::TScalar{0.0}, e.AsScalar());
+ }
+
+ {
+ auto& e = reader.NextEvent();
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Key, e.Type());
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuf("foo"), e.AsString());
+ }
+ {
+ auto& e = reader.NextEvent();
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Scalar, e.Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::TScalar{TStringBuf("bar")}, e.AsScalar());
+ }
+
+ {
+ auto& e = reader.NextEvent();
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Key, e.Type());
+ UNIT_ASSERT_VALUES_EQUAL(TStringBuf("list"), e.AsString());
+ }
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::BeginList, reader.NextEvent().Type());
+ {
+ auto& e = reader.NextEvent();
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Scalar, e.Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::TScalar{i64{1}}, e.AsScalar());
+ }
+ {
+ auto& e = reader.NextEvent();
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Scalar, e.Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::TScalar{i64{2}}, e.AsScalar());
+ }
+ {
+ auto& e = reader.NextEvent();
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Scalar, e.Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::TScalar{i64{3}}, e.AsScalar());
+ }
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::EndList, reader.NextEvent().Type());
+
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::EndMap, reader.NextEvent().Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::EndStream, reader.NextEvent().Type());
+ }
+
+ Y_UNIT_TEST(Accept) {
+ ACCEPT("[]");
+ ACCEPT("{}");
+ ACCEPT("<>[]");
+ ACCEPT("<>{}");
+ ACCEPT("[{};{};{}]");
+ ACCEPT("[{};{};{};]");
+ ACCEPT("[<>{};<>{};<>{}]");
+ ACCEPT("[<>{};<>{};<>{};]");
+
+ ACCEPT("foo");
+ ACCEPT("[foo]");
+ ACCEPT("[foo;]");
+ ACCEPT("{foo=foo}");
+ ACCEPT("{foo=foo;}");
+ ACCEPT("<>{foo=foo}");
+ ACCEPT("{foo=<foo=foo>foo}");
+ ACCEPT("{foo=<foo=foo;>foo}");
+ ACCEPT("{foo=<foo=foo>[foo;foo]}");
+ }
+
+ Y_UNIT_TEST(Reject) {
+ REJECT("[");
+ REJECT("{");
+ REJECT("<");
+
+ REJECT("[[}]");
+ REJECT("<>{]");
+ REJECT("[>]");
+
+ REJECT("<><>[]");
+ REJECT("[<>;<>]");
+
+ REJECT("{<>foo=foo}");
+ REJECT("{foo=<>}");
+ REJECT("{foo}");
+
+ REJECT("<a=b>");
+ REJECT("<>");
+
+ REJECT("@");
+ }
+
+ Y_UNIT_TEST(ReadPastEnd) {
+ auto reader = memory_reader("#", NYsonPull::EStreamType::Node);
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::BeginStream, reader.NextEvent().Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::Scalar, reader.NextEvent().Type());
+ UNIT_ASSERT_VALUES_EQUAL(NYsonPull::EEventType::EndStream, reader.NextEvent().Type());
+ UNIT_ASSERT_EXCEPTION(reader.NextEvent(), NYsonPull::NException::TBadInput);
+ }
+
+ Y_UNIT_TEST(BadInput) {
+ // max_size<ui32> < varint size < max_size<ui64>
+ auto t = TString("\x01\xff\xff\xff\xff\xff\xff\xff\xff");
+ auto reader = memory_reader(t, NYsonPull::EStreamType::Node);
+
+ UNIT_ASSERT_EQUAL(reader.NextEvent().Type(), NYsonPull::EEventType::BeginStream);
+ UNIT_ASSERT_EXCEPTION(reader.NextEvent(), NYsonPull::NException::TBadInput);
+ }
+
+ Y_UNIT_TEST(StreamType) {
+ REJECT2("", NYsonPull::EStreamType::Node);
+ ACCEPT2("", NYsonPull::EStreamType::ListFragment);
+ ACCEPT2("", NYsonPull::EStreamType::MapFragment);
+
+ ACCEPT2("[1]", NYsonPull::EStreamType::Node);
+ ACCEPT2("[1]", NYsonPull::EStreamType::ListFragment);
+ REJECT2("[1]", NYsonPull::EStreamType::MapFragment);
+
+ ACCEPT2("<foo=bar>[1]", NYsonPull::EStreamType::Node);
+ ACCEPT2("<foo=bar>[1]", NYsonPull::EStreamType::ListFragment);
+ REJECT2("<foo=bar>[1]", NYsonPull::EStreamType::MapFragment);
+
+ ACCEPT2(" [1] \t \t ", NYsonPull::EStreamType::Node);
+ ACCEPT2(" [1] \t \t ", NYsonPull::EStreamType::ListFragment);
+ REJECT2(" [1] \t \t ", NYsonPull::EStreamType::MapFragment);
+
+ REJECT2("[1];", NYsonPull::EStreamType::Node);
+ ACCEPT2("[1];", NYsonPull::EStreamType::ListFragment);
+ REJECT2("[1];", NYsonPull::EStreamType::MapFragment);
+
+ REJECT2("[1]; foobar", NYsonPull::EStreamType::Node);
+ ACCEPT2("[1]; foobar", NYsonPull::EStreamType::ListFragment);
+ REJECT2("[1]; foobar", NYsonPull::EStreamType::MapFragment);
+
+ REJECT2("a=[1]", NYsonPull::EStreamType::Node);
+ REJECT2("a=[1]", NYsonPull::EStreamType::ListFragment);
+ ACCEPT2("a=[1]", NYsonPull::EStreamType::MapFragment);
+
+ REJECT2("a=[1]; ", NYsonPull::EStreamType::Node);
+ REJECT2("a=[1]; ", NYsonPull::EStreamType::ListFragment);
+ ACCEPT2("a=[1]; ", NYsonPull::EStreamType::MapFragment);
+
+ REJECT2("a=[1]; b=foobar", NYsonPull::EStreamType::Node);
+ REJECT2("a=[1]; b=foobar", NYsonPull::EStreamType::ListFragment);
+ ACCEPT2("a=[1]; b=foobar", NYsonPull::EStreamType::MapFragment);
+ }
+
+} // Y_UNIT_TEST_SUITE(Reader)
diff --git a/library/cpp/yson_pull/ut/writer_ut.cpp b/library/cpp/yson_pull/ut/writer_ut.cpp
new file mode 100644
index 0000000000..5c304bad0f
--- /dev/null
+++ b/library/cpp/yson_pull/ut/writer_ut.cpp
@@ -0,0 +1,256 @@
+#include <library/cpp/yson_pull/scalar.h>
+#include <library/cpp/yson_pull/detail/writer.h>
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/generic/string.h>
+
+#include <climits>
+#include <limits>
+
+using namespace std::string_view_literals;
+
+namespace {
+ template <typename Writer, typename Function>
+ TString with_writer(Function&& function) {
+ TString result;
+ auto writer = NYsonPull::NDetail::make_writer<Writer>(
+ NYsonPull::NOutput::FromString(&result),
+ NYsonPull::EStreamType::Node);
+
+ function(writer);
+
+ return result;
+ }
+
+ template <typename Writer>
+ TString to_yson_string(const NYsonPull::TScalar& value) {
+ return with_writer<Writer>([&](NYsonPull::TWriter& writer) {
+ writer.BeginStream().Scalar(value).EndStream();
+ });
+ }
+
+ template <typename T>
+ TString to_yson_binary_string(T&& value) {
+ return to_yson_string<NYsonPull::NDetail::TBinaryWriterImpl>(std::forward<T>(value));
+ }
+
+ template <typename T>
+ TString to_yson_text_string(T&& value) {
+ return to_yson_string<NYsonPull::NDetail::TTextWriterImpl>(std::forward<T>(value));
+ }
+
+} // anonymous namespace
+
+// =================== Text format =====================
+
+Y_UNIT_TEST_SUITE(Writer) {
+ Y_UNIT_TEST(TextEntity) {
+ UNIT_ASSERT_VALUES_EQUAL(
+ "#",
+ to_yson_text_string(NYsonPull::TScalar{}));
+ }
+
+ Y_UNIT_TEST(TextBoolean) {
+ UNIT_ASSERT_VALUES_EQUAL(
+ "%false",
+ to_yson_text_string(NYsonPull::TScalar{false}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "%true",
+ to_yson_text_string(NYsonPull::TScalar{true}));
+ }
+
+ Y_UNIT_TEST(TextInt64) {
+ UNIT_ASSERT_VALUES_EQUAL(
+ "0",
+ to_yson_text_string(NYsonPull::TScalar{i64{0}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "200",
+ to_yson_text_string(NYsonPull::TScalar{i64{200}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "20000",
+ to_yson_text_string(NYsonPull::TScalar{i64{20000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "200000000",
+ to_yson_text_string(NYsonPull::TScalar{i64{200000000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "20000000000000000",
+ to_yson_text_string(NYsonPull::TScalar{i64{20000000000000000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "9223372036854775807",
+ to_yson_text_string(NYsonPull::TScalar{i64{INT64_MAX}}));
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ "-200",
+ to_yson_text_string(NYsonPull::TScalar{i64{-200}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "-20000",
+ to_yson_text_string(NYsonPull::TScalar{i64{-20000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "-200000000",
+ to_yson_text_string(NYsonPull::TScalar{i64{-200000000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "-20000000000000000",
+ to_yson_text_string(NYsonPull::TScalar{i64{-20000000000000000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "-9223372036854775808",
+ to_yson_text_string(NYsonPull::TScalar{i64{INT64_MIN}}));
+ }
+
+ Y_UNIT_TEST(TextUInt64) {
+ UNIT_ASSERT_VALUES_EQUAL(
+ "0u",
+ to_yson_text_string(NYsonPull::TScalar{ui64{0}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "200u",
+ to_yson_text_string(NYsonPull::TScalar{ui64{200}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "20000u",
+ to_yson_text_string(NYsonPull::TScalar{ui64{20000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "200000000u",
+ to_yson_text_string(NYsonPull::TScalar{ui64{200000000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "20000000000000000u",
+ to_yson_text_string(NYsonPull::TScalar{ui64{20000000000000000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "9223372036854775807u",
+ to_yson_text_string(NYsonPull::TScalar{ui64{INT64_MAX}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "18446744073709551615u",
+ to_yson_text_string(NYsonPull::TScalar{ui64{UINT64_MAX}}));
+ }
+
+ Y_UNIT_TEST(TextFloat64) {
+ UNIT_ASSERT_VALUES_EQUAL(
+ "%inf",
+ to_yson_text_string(NYsonPull::TScalar{std::numeric_limits<double>::infinity()}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "%-inf",
+ to_yson_text_string(NYsonPull::TScalar{-std::numeric_limits<double>::infinity()}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ "%nan",
+ to_yson_text_string(NYsonPull::TScalar{std::numeric_limits<double>::quiet_NaN()}));
+ }
+
+ Y_UNIT_TEST(TextString) {
+ UNIT_ASSERT_VALUES_EQUAL(
+ R"("")",
+ to_yson_text_string(NYsonPull::TScalar{""}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ R"("hello")",
+ to_yson_text_string(NYsonPull::TScalar{"hello"}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ R"("hello\nworld")",
+ to_yson_text_string(NYsonPull::TScalar{"hello\nworld"}));
+ }
+
+ // =================== Binary format =====================
+
+ Y_UNIT_TEST(BinaryEntity) {
+ UNIT_ASSERT_VALUES_EQUAL(
+ "#",
+ to_yson_binary_string(NYsonPull::TScalar{}));
+ }
+
+ Y_UNIT_TEST(BinaryBoolean) {
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x4"),
+ to_yson_binary_string(NYsonPull::TScalar{false}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x5"),
+ to_yson_binary_string(NYsonPull::TScalar{true}));
+ }
+
+ Y_UNIT_TEST(BinaryInt64) {
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x2\0"sv),
+ to_yson_binary_string(NYsonPull::TScalar{i64{0}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x2\x90\x3"),
+ to_yson_binary_string(NYsonPull::TScalar{i64{200}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x2\xC0\xB8\x2"),
+ to_yson_binary_string(NYsonPull::TScalar{i64{20000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x2\x80\x88\xDE\xBE\x1"),
+ to_yson_binary_string(NYsonPull::TScalar{i64{200000000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x2\x80\x80\x90\xF8\x9B\xF9\x86G"),
+ to_yson_binary_string(NYsonPull::TScalar{i64{20000000000000000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x2\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1"),
+ to_yson_binary_string(NYsonPull::TScalar{i64{INT64_MAX}}));
+
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x2\x8F\x3"),
+ to_yson_binary_string(NYsonPull::TScalar{i64{-200}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x2\xBF\xB8\x2"),
+ to_yson_binary_string(NYsonPull::TScalar{i64{-20000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x2\xFF\x87\xDE\xBE\x1"),
+ to_yson_binary_string(NYsonPull::TScalar{i64{-200000000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x2\xFF\xFF\x8F\xF8\x9B\xF9\x86G"),
+ to_yson_binary_string(NYsonPull::TScalar{i64{-20000000000000000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x2\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1"),
+ to_yson_binary_string(NYsonPull::TScalar{i64{INT64_MIN}}));
+ }
+
+ Y_UNIT_TEST(BinaryUInt64) {
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x6\0"sv),
+ to_yson_binary_string(NYsonPull::TScalar{ui64{0}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x6\xC8\x1"),
+ to_yson_binary_string(NYsonPull::TScalar{ui64{200}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x6\xA0\x9C\x1"),
+ to_yson_binary_string(NYsonPull::TScalar{ui64{20000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x6\x80\x84\xAF_"),
+ to_yson_binary_string(NYsonPull::TScalar{ui64{200000000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x6\x80\x80\x88\xFC\xCD\xBC\xC3#"),
+ to_yson_binary_string(NYsonPull::TScalar{ui64{20000000000000000}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x6\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"),
+ to_yson_binary_string(NYsonPull::TScalar{ui64{INT64_MAX}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x6\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x1"),
+ to_yson_binary_string(NYsonPull::TScalar{ui64{UINT64_MAX}}));
+ }
+
+ Y_UNIT_TEST(BinaryFloat64) {
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x03\x00\x00\x00\x00\x00\x00\xf0\x7f"sv),
+ to_yson_binary_string(NYsonPull::TScalar{std::numeric_limits<double>::infinity()}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x03\x00\x00\x00\x00\x00\x00\xf0\xff"sv),
+ to_yson_binary_string(NYsonPull::TScalar{-std::numeric_limits<double>::infinity()}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x03\x00\x00\x00\x00\x00\x00\xf8\x7f"sv),
+ to_yson_binary_string(NYsonPull::TScalar{std::numeric_limits<double>::quiet_NaN()}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x03\x9a\x99\x99\x99\x99\x99\xf1\x3f"),
+ to_yson_binary_string(NYsonPull::TScalar{double{1.1}}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x03\x9a\x99\x99\x99\x99\x99\xf1\xbf"),
+ to_yson_binary_string(NYsonPull::TScalar{double{-1.1}}));
+ }
+
+ Y_UNIT_TEST(BinaryString) {
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x1\0"sv),
+ to_yson_binary_string(NYsonPull::TScalar{""}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x1\nhello"),
+ to_yson_binary_string(NYsonPull::TScalar{"hello"}));
+ UNIT_ASSERT_VALUES_EQUAL(
+ TStringBuf("\x1\x16hello\nworld"),
+ to_yson_binary_string(NYsonPull::TScalar{"hello\nworld"}));
+ }
+
+} // Y_UNIT_TEST_SUITE(Writer)
diff --git a/library/cpp/yson_pull/ut/ya.make b/library/cpp/yson_pull/ut/ya.make
new file mode 100644
index 0000000000..a269dfd2ad
--- /dev/null
+++ b/library/cpp/yson_pull/ut/ya.make
@@ -0,0 +1,12 @@
+UNITTEST_FOR(library/cpp/yson_pull)
+
+OWNER(borman)
+
+SRCS(
+ cescape_ut.cpp
+ reader_ut.cpp
+ writer_ut.cpp
+ loop_ut.cpp
+)
+
+END()
diff --git a/library/cpp/yson_pull/writer.cpp b/library/cpp/yson_pull/writer.cpp
new file mode 100644
index 0000000000..1df92bf40f
--- /dev/null
+++ b/library/cpp/yson_pull/writer.cpp
@@ -0,0 +1,30 @@
+#include "writer.h"
+#include <library/cpp/yson_pull/detail/writer.h>
+
+using namespace NYsonPull;
+
+TWriter NYsonPull::MakeBinaryWriter(
+ THolder<NOutput::IStream> stream,
+ EStreamType mode) {
+ return NYsonPull::NDetail::make_writer<NYsonPull::NDetail::TBinaryWriterImpl>(
+ std::move(stream),
+ mode);
+}
+
+TWriter NYsonPull::MakeTextWriter(
+ THolder<NOutput::IStream> stream,
+ EStreamType mode) {
+ return NYsonPull::NDetail::make_writer<NYsonPull::NDetail::TTextWriterImpl>(
+ std::move(stream),
+ mode);
+}
+
+TWriter NYsonPull::MakePrettyTextWriter(
+ THolder<NOutput::IStream> stream,
+ EStreamType mode,
+ size_t indent_size) {
+ return NYsonPull::NDetail::make_writer<NYsonPull::NDetail::TPrettyWriterImpl>(
+ std::move(stream),
+ mode,
+ indent_size);
+}
diff --git a/library/cpp/yson_pull/writer.h b/library/cpp/yson_pull/writer.h
new file mode 100644
index 0000000000..dec63328be
--- /dev/null
+++ b/library/cpp/yson_pull/writer.h
@@ -0,0 +1,126 @@
+#pragma once
+
+#include "consumer.h"
+#include "output.h"
+#include "scalar.h"
+#include "stream_type.h"
+
+#include <memory>
+
+namespace NYsonPull {
+ //! \brief YSON writer facade class
+ //!
+ //! Owns a YSON consumer and a corresponding output stream.
+ //! Methods invoke corresponding \p NYsonPull::IConsumer methods and can be chained.
+ class TWriter {
+ THolder<NOutput::IStream> Stream_;
+ THolder<IConsumer> Impl_;
+
+ public:
+ TWriter(
+ THolder<NOutput::IStream> stream,
+ THolder<IConsumer> impl)
+ : Stream_{std::move(stream)}
+ , Impl_{std::move(impl)} {
+ }
+
+ //! \brief Get a reference to underlying consumer.
+ //!
+ //! Useful with \p NYsonPull::bridge
+ IConsumer& GetConsumer() {
+ return *Impl_;
+ }
+
+ TWriter& BeginStream() {
+ Impl_->OnBeginStream();
+ return *this;
+ }
+ TWriter& EndStream() {
+ Impl_->OnEndStream();
+ return *this;
+ }
+
+ TWriter& BeginList() {
+ Impl_->OnBeginList();
+ return *this;
+ }
+ TWriter& EndList() {
+ Impl_->OnEndList();
+ return *this;
+ }
+
+ TWriter& BeginMap() {
+ Impl_->OnBeginMap();
+ return *this;
+ }
+ TWriter& EndMap() {
+ Impl_->OnEndMap();
+ return *this;
+ }
+
+ TWriter& BeginAttributes() {
+ Impl_->OnBeginAttributes();
+ return *this;
+ }
+ TWriter& EndAttributes() {
+ Impl_->OnEndAttributes();
+ return *this;
+ }
+
+ TWriter& Key(TStringBuf name) {
+ Impl_->OnKey(name);
+ return *this;
+ }
+
+ TWriter& Entity() {
+ Impl_->OnEntity();
+ return *this;
+ }
+ TWriter& Boolean(bool value) {
+ Impl_->OnScalarBoolean(value);
+ return *this;
+ }
+ TWriter& Int64(i64 value) {
+ Impl_->OnScalarInt64(value);
+ return *this;
+ }
+ TWriter& UInt64(ui64 value) {
+ Impl_->OnScalarUInt64(value);
+ return *this;
+ }
+ TWriter& Float64(double value) {
+ Impl_->OnScalarFloat64(value);
+ return *this;
+ }
+ TWriter& String(TStringBuf value) {
+ Impl_->OnScalarString(value);
+ return *this;
+ }
+
+ TWriter& Scalar(const TScalar& value) {
+ Impl_->OnScalar(value);
+ return *this;
+ }
+ TWriter& Event(const TEvent& value) {
+ Impl_->OnEvent(value);
+ return *this;
+ }
+ };
+
+ //! \brief Construct a writer for binary YSON format.
+ TWriter MakeBinaryWriter(
+ THolder<NOutput::IStream> stream,
+ EStreamType mode);
+
+ //! \brief Construct a writer for text YSON format.
+ TWriter MakeTextWriter(
+ THolder<NOutput::IStream> stream,
+ EStreamType mode);
+
+ //! \brief Construct a writer for pretty text YSON format.
+ TWriter MakePrettyTextWriter(
+ THolder<NOutput::IStream> stream,
+ EStreamType mode,
+ size_t indent_size = 4);
+
+}
diff --git a/library/cpp/yson_pull/ya.make b/library/cpp/yson_pull/ya.make
new file mode 100644
index 0000000000..a373e0a6ba
--- /dev/null
+++ b/library/cpp/yson_pull/ya.make
@@ -0,0 +1,21 @@
+LIBRARY(yson_pull)
+
+OWNER(borman)
+
+SRCS(
+ consumer.cpp
+ event.cpp
+ exceptions.cpp
+ input.cpp
+ output.cpp
+ read_ops.cpp
+ reader.cpp
+ scalar.cpp
+ writer.cpp
+)
+
+GENERATE_ENUM_SERIALIZATION(event.h)
+
+GENERATE_ENUM_SERIALIZATION(scalar.h)
+
+END()
diff --git a/library/cpp/yson_pull/yson.h b/library/cpp/yson_pull/yson.h
new file mode 100644
index 0000000000..a77eaa5c94
--- /dev/null
+++ b/library/cpp/yson_pull/yson.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "bridge.h"
+#include "consumer.h"
+#include "event.h"
+#include "exceptions.h"
+#include "input.h"
+#include "output.h"
+#include "position_info.h"
+#include "range.h"
+#include "reader.h"
+#include "scalar.h"
+#include "stream_type.h"
+#include "writer.h"
diff --git a/library/cpp/yt/assert/assert.cpp b/library/cpp/yt/assert/assert.cpp
new file mode 100644
index 0000000000..095357cdfa
--- /dev/null
+++ b/library/cpp/yt/assert/assert.cpp
@@ -0,0 +1,29 @@
+#include "assert.h"
+
+#include <util/system/yassert.h>
+#include <util/system/compiler.h>
+
+namespace NYT::NDetail {
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_WEAK void AssertTrapImpl(
+ TStringBuf trapType,
+ TStringBuf expr,
+ TStringBuf file,
+ int line,
+ TStringBuf function)
+{
+ // Map to Arcadia assert, poorly...
+ ::NPrivate::Panic(
+ ::NPrivate::TStaticBuf(file.data(), file.length()),
+ line,
+ function.data(),
+ expr.data(),
+ "%s",
+ trapType.data());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NDetail
diff --git a/library/cpp/yt/assert/assert.h b/library/cpp/yt/assert/assert.h
new file mode 100644
index 0000000000..7a9e761a3a
--- /dev/null
+++ b/library/cpp/yt/assert/assert.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#include <util/system/compiler.h>
+#include <util/system/src_root.h>
+
+#include <util/generic/strbuf.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace NDetail {
+
+[[noreturn]]
+void AssertTrapImpl(
+ TStringBuf trapType,
+ TStringBuf expr,
+ TStringBuf file,
+ int line,
+ TStringBuf function);
+
+} // namespace NDetail
+
+#ifdef __GNUC__
+ #define YT_BUILTIN_TRAP() __builtin_trap()
+#else
+ #define YT_BUILTIN_TRAP() std::terminate()
+#endif
+
+#define YT_ASSERT_TRAP(trapType, expr) \
+ ::NYT::NDetail::AssertTrapImpl(TStringBuf(trapType), TStringBuf(expr), __SOURCE_FILE_IMPL__.As<TStringBuf>(), __LINE__, TStringBuf(__FUNCTION__)); \
+ Y_UNREACHABLE() \
+
+#ifdef NDEBUG
+ #define YT_ASSERT(expr) \
+ do { \
+ if (false) { \
+ (void) (expr); \
+ } \
+ } while (false)
+#else
+ #define YT_ASSERT(expr) \
+ do { \
+ if (Y_UNLIKELY(!(expr))) { \
+ YT_ASSERT_TRAP("YT_ASSERT", #expr); \
+ } \
+ } while (false)
+#endif
+
+//! Same as |YT_ASSERT| but evaluates and checks the expression in both release and debug mode.
+#define YT_VERIFY(expr) \
+ do { \
+ if (Y_UNLIKELY(!(expr))) { \
+ YT_ASSERT_TRAP("YT_VERIFY", #expr); \
+ } \
+ } while (false)
+
+//! Fatal error code marker. Abnormally terminates the current process.
+#ifdef YT_COMPILING_UDF
+ #define YT_ABORT() __YT_BUILTIN_ABORT()
+#else
+ #define YT_ABORT() \
+ do { \
+ YT_ASSERT_TRAP("YT_ABORT", ""); \
+ } while (false)
+#endif
+
+//! Unimplemented code marker. Abnormally terminates the current process.
+#define YT_UNIMPLEMENTED() \
+ do { \
+ YT_ASSERT_TRAP("YT_UNIMPLEMENTED", ""); \
+ } while (false)
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/assert/ya.make b/library/cpp/yt/assert/ya.make
new file mode 100644
index 0000000000..df74a4f1fa
--- /dev/null
+++ b/library/cpp/yt/assert/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(g:yt)
+
+SRCS(
+ assert.cpp
+)
+
+END()
diff --git a/library/cpp/yt/coding/unittests/varint_ut.cpp b/library/cpp/yt/coding/unittests/varint_ut.cpp
new file mode 100644
index 0000000000..ed83ab5c92
--- /dev/null
+++ b/library/cpp/yt/coding/unittests/varint_ut.cpp
@@ -0,0 +1,134 @@
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <library/cpp/yt/coding/varint.h>
+
+#include <util/random/random.h>
+
+#include <util/string/escape.h>
+
+#include <tuple>
+
+namespace NYT {
+namespace {
+
+using ::testing::Values;
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TWriteVarIntTest: public ::testing::TestWithParam<std::tuple<ui64, TString> >
+{ };
+
+TEST_P(TWriteVarIntTest, Serialization)
+{
+ ui64 value = std::get<0>(GetParam());
+ TString rightAnswer = std::get<1>(GetParam());
+
+ TStringStream outputStream;
+ WriteVarUint64(&outputStream, value);
+ EXPECT_EQ(rightAnswer, outputStream.Str());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TReadVarIntTest: public ::testing::TestWithParam<std::tuple<ui64, TString> >
+{ };
+
+TEST_P(TReadVarIntTest, Serialization)
+{
+ ui64 rightAnswer = std::get<0>(GetParam());
+ TString input = std::get<1>(GetParam());
+
+ TStringInput inputStream(input);
+ ui64 value;
+ ReadVarUint64(&inputStream, &value);
+ EXPECT_EQ(rightAnswer, value);
+}
+
+TEST(TReadVarIntTest, Overflow)
+{
+ TString input("\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01", 11);
+ TStringInput inputStream(input);
+ ui64 value;
+ EXPECT_ANY_THROW(ReadVarUint64(&inputStream, &value));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+auto ValuesForVarIntTests = Values(
+ // Simple cases.
+ std::make_tuple(0x0ull, TString("\x00", 1)),
+ std::make_tuple(0x1ull, TString("\x01", 1)),
+ std::make_tuple(0x2ull, TString("\x02", 1)),
+ std::make_tuple(0x3ull, TString("\x03", 1)),
+ std::make_tuple(0x4ull, TString("\x04", 1)),
+
+ // The following "magic numbers" are critical points for varint encoding.
+ std::make_tuple((1ull << 7) - 1, TString("\x7f", 1)),
+ std::make_tuple((1ull << 7), TString("\x80\x01", 2)),
+ std::make_tuple((1ull << 14) - 1, TString("\xff\x7f", 2)),
+ std::make_tuple((1ull << 14), TString("\x80\x80\x01", 3)),
+ std::make_tuple((1ull << 21) - 1, TString("\xff\xff\x7f", 3)),
+ std::make_tuple((1ull << 21), TString("\x80\x80\x80\x01", 4)),
+ std::make_tuple((1ull << 28) - 1, TString("\xff\xff\xff\x7f", 4)),
+ std::make_tuple((1ull << 28), TString("\x80\x80\x80\x80\x01", 5)),
+ std::make_tuple((1ull << 35) - 1, TString("\xff\xff\xff\xff\x7f", 5)),
+ std::make_tuple((1ull << 35), TString("\x80\x80\x80\x80\x80\x01", 6)),
+ std::make_tuple((1ull << 42) - 1, TString("\xff\xff\xff\xff\xff\x7f", 6)),
+ std::make_tuple((1ull << 42), TString("\x80\x80\x80\x80\x80\x80\x01", 7)),
+ std::make_tuple((1ull << 49) - 1, TString("\xff\xff\xff\xff\xff\xff\x7f", 7)),
+ std::make_tuple((1ull << 49), TString("\x80\x80\x80\x80\x80\x80\x80\x01", 8)),
+ std::make_tuple((1ull << 56) - 1, TString("\xff\xff\xff\xff\xff\xff\xff\x7f", 8)),
+ std::make_tuple((1ull << 56), TString("\x80\x80\x80\x80\x80\x80\x80\x80\x01", 9)),
+ std::make_tuple((1ull << 63) - 1, TString("\xff\xff\xff\xff\xff\xff\xff\xff\x7f", 9)),
+ std::make_tuple((1ull << 63), TString("\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01", 10)),
+
+ // Boundary case.
+ std::make_tuple(static_cast<ui64>(-1), TString("\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01", 10))
+);
+
+INSTANTIATE_TEST_SUITE_P(ValueParametrized, TWriteVarIntTest,
+ ValuesForVarIntTests);
+
+INSTANTIATE_TEST_SUITE_P(ValueParametrized, TReadVarIntTest,
+ ValuesForVarIntTests);
+
+////////////////////////////////////////////////////////////////////////////////
+
+TEST(TVarInt32Test, RandomValues)
+{
+ srand(100500); // Set seed
+ const int numberOfValues = 10000;
+
+ TStringStream stream;
+ for (int i = 0; i < numberOfValues; ++i) {
+ i32 expected = static_cast<i32>(RandomNumber<ui32>());
+ WriteVarInt32(&stream, expected);
+ i32 actual;
+ ReadVarInt32(&stream, &actual);
+ EXPECT_EQ(expected, actual)
+ << "Encoded Variant: " << EscapeC(stream.Str());
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+TEST(TVarInt64Test, RandomValues)
+{
+ srand(100500); // Set seed
+ const int numberOfValues = 10000;
+
+ TStringStream stream;
+ for (int i = 0; i < numberOfValues; ++i) {
+ i64 expected = static_cast<i64>(RandomNumber<ui64>());
+ WriteVarInt64(&stream, expected);
+ i64 actual;
+ ReadVarInt64(&stream, &actual);
+ EXPECT_EQ(expected, actual)
+ << "Encoded Variant: " << EscapeC(stream.Str());
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT
diff --git a/library/cpp/yt/coding/unittests/ya.make b/library/cpp/yt/coding/unittests/ya.make
new file mode 100644
index 0000000000..e0622db22d
--- /dev/null
+++ b/library/cpp/yt/coding/unittests/ya.make
@@ -0,0 +1,15 @@
+GTEST()
+
+OWNER(g:yt)
+
+SRCS(
+ zig_zag_ut.cpp
+ varint_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/yt/coding
+ library/cpp/testing/gtest
+)
+
+END()
diff --git a/library/cpp/yt/coding/unittests/zig_zag_ut.cpp b/library/cpp/yt/coding/unittests/zig_zag_ut.cpp
new file mode 100644
index 0000000000..fae4e63064
--- /dev/null
+++ b/library/cpp/yt/coding/unittests/zig_zag_ut.cpp
@@ -0,0 +1,57 @@
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <library/cpp/yt/coding/zig_zag.h>
+
+namespace NYT {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TEST(TZigZagTest, Encode32)
+{
+ EXPECT_EQ(0u, ZigZagEncode32( 0));
+ EXPECT_EQ(1u, ZigZagEncode32(-1));
+ EXPECT_EQ(2u, ZigZagEncode32( 1));
+ EXPECT_EQ(3u, ZigZagEncode32(-2));
+ // ...
+ EXPECT_EQ(std::numeric_limits<ui32>::max() - 1, ZigZagEncode32(std::numeric_limits<i32>::max()));
+ EXPECT_EQ(std::numeric_limits<ui32>::max(), ZigZagEncode32(std::numeric_limits<i32>::min()));
+}
+
+TEST(TZigZagTest, Decode32)
+{
+ EXPECT_EQ( 0, ZigZagDecode32(0));
+ EXPECT_EQ(-1, ZigZagDecode32(1));
+ EXPECT_EQ( 1, ZigZagDecode32(2));
+ EXPECT_EQ(-2, ZigZagDecode32(3));
+ // ...
+ EXPECT_EQ(std::numeric_limits<i32>::max(), ZigZagDecode32(std::numeric_limits<ui32>::max() - 1));
+ EXPECT_EQ(std::numeric_limits<i32>::min(), ZigZagDecode32(std::numeric_limits<ui32>::max()));
+}
+
+TEST(TZigZagTest, Encode64)
+{
+ EXPECT_EQ(0ull, ZigZagEncode64( 0));
+ EXPECT_EQ(1ull, ZigZagEncode64(-1));
+ EXPECT_EQ(2ull, ZigZagEncode64( 1));
+ EXPECT_EQ(3ull, ZigZagEncode64(-2));
+ // ...
+ EXPECT_EQ(std::numeric_limits<ui64>::max() - 1, ZigZagEncode64(std::numeric_limits<i64>::max()));
+ EXPECT_EQ(std::numeric_limits<ui64>::max(), ZigZagEncode64(std::numeric_limits<i64>::min()));
+}
+
+TEST(TZigZagTest, Decode64)
+{
+ EXPECT_EQ(ZigZagDecode64(0), 0ll);
+ EXPECT_EQ(ZigZagDecode64(1), -1ll);
+ EXPECT_EQ(ZigZagDecode64(2), 1ll);
+ EXPECT_EQ(ZigZagDecode64(3), -2ll);
+ // ...
+ EXPECT_EQ(std::numeric_limits<i64>::max(), ZigZagDecode64(std::numeric_limits<ui64>::max() - 1));
+ EXPECT_EQ(std::numeric_limits<i64>::min(), ZigZagDecode64(std::numeric_limits<ui64>::max()));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT
diff --git a/library/cpp/yt/coding/varint-inl.h b/library/cpp/yt/coding/varint-inl.h
new file mode 100644
index 0000000000..f0a09e9d30
--- /dev/null
+++ b/library/cpp/yt/coding/varint-inl.h
@@ -0,0 +1,240 @@
+#ifndef VARINT_INL_H_
+#error "Direct inclusion of this file is not allowed, include varint.h"
+// For the sake of sane code completion.
+#include "varint.h"
+#endif
+
+#include "zig_zag.h"
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TWriteCallback>
+Y_FORCE_INLINE int WriteVarUint64Impl(TWriteCallback doWrite, ui64 value)
+{
+ bool stop = false;
+ int bytesWritten = 0;
+ while (!stop) {
+ ++bytesWritten;
+ ui8 byte = static_cast<ui8>(value | 0x80);
+ value >>= 7;
+ if (value == 0) {
+ stop = true;
+ byte &= 0x7F;
+ }
+ doWrite(byte);
+ }
+ return bytesWritten;
+}
+
+// These are optimized versions of these Read/Write functions in protobuf/io/coded_stream.cc.
+Y_FORCE_INLINE int WriteVarUint64(IOutputStream* output, ui64 value)
+{
+ return WriteVarUint64Impl([&] (ui8 byte) {
+ output->Write(byte);
+ }, value);
+}
+
+Y_FORCE_INLINE int WriteVarUint64(char* output, ui64 value)
+{
+ return WriteVarUint64Impl([&] (ui8 byte) {
+ *output++ = byte;
+ }, value);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TOutput>
+Y_FORCE_INLINE int WriteVarUint32Impl(TOutput output, ui32 value)
+{
+ return WriteVarUint64(output, static_cast<ui64>(value));
+}
+
+Y_FORCE_INLINE int WriteVarUint32(IOutputStream* output, ui32 value)
+{
+ return WriteVarUint32Impl(output, value);
+}
+
+Y_FORCE_INLINE int WriteVarUint32(char* output, ui32 value)
+{
+ return WriteVarUint32Impl(output, value);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TOutput>
+Y_FORCE_INLINE int WriteVarInt32Impl(TOutput output, i32 value)
+{
+ return WriteVarUint64(output, static_cast<ui64>(ZigZagEncode32(value)));
+}
+
+Y_FORCE_INLINE int WriteVarInt32(IOutputStream* output, i32 value)
+{
+ return WriteVarInt32Impl(output, value);
+}
+
+Y_FORCE_INLINE int WriteVarInt32(char* output, i32 value)
+{
+ return WriteVarInt32Impl(output, value);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TOutput>
+Y_FORCE_INLINE int WriteVarInt64Impl(TOutput output, i64 value)
+{
+ return WriteVarUint64(output, static_cast<ui64>(ZigZagEncode64(value)));
+}
+
+Y_FORCE_INLINE int WriteVarInt64(IOutputStream* output, i64 value)
+{
+ return WriteVarInt64Impl(output, value);
+}
+
+Y_FORCE_INLINE int WriteVarInt64(char* output, i64 value)
+{
+ return WriteVarInt64Impl(output, value);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TReadCallback>
+Y_FORCE_INLINE int ReadVarUint64Impl(TReadCallback doRead, ui64* value)
+{
+ size_t count = 0;
+ ui64 result = 0;
+
+ ui8 byte;
+ do {
+ if (7 * count > 8 * sizeof(ui64) ) {
+ throw TSimpleException("Value is too big for varuint64");
+ }
+ byte = doRead();
+ result |= (static_cast<ui64> (byte & 0x7F)) << (7 * count);
+ ++count;
+ } while (byte & 0x80);
+
+ *value = result;
+ return count;
+}
+
+Y_FORCE_INLINE int ReadVarUint64(IInputStream* input, ui64* value)
+{
+ return ReadVarUint64Impl([&] () {
+ char byte;
+ if (input->Read(&byte, 1) != 1) {
+ throw TSimpleException("Premature end of stream while reading varuint64");
+ }
+ return byte;
+ }, value);
+}
+
+Y_FORCE_INLINE int ReadVarUint64(const char* input, ui64* value)
+{
+ return ReadVarUint64Impl([&] () {
+ char byte = *input;
+ ++input;
+ return byte;
+ }, value);
+}
+
+Y_FORCE_INLINE int ReadVarUint64(const char* input, const char* end, ui64* value)
+{
+ return ReadVarUint64Impl([&] () {
+ if (input == end) {
+ throw TSimpleException("Premature end of data while reading varuint64");
+ }
+ char byte = *input;
+ ++input;
+ return byte;
+ }, value);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class... Args>
+Y_FORCE_INLINE int ReadVarUint32Impl(ui32* value, Args... args)
+{
+ ui64 varInt;
+ int bytesRead = ReadVarUint64(args..., &varInt);
+ if (varInt > std::numeric_limits<ui32>::max()) {
+ throw TSimpleException("Value is too big for varuint32");
+ }
+ *value = static_cast<ui32>(varInt);
+ return bytesRead;
+}
+
+Y_FORCE_INLINE int ReadVarUint32(IInputStream* input, ui32* value)
+{
+ return ReadVarUint32Impl(value, input);
+}
+
+Y_FORCE_INLINE int ReadVarUint32(const char* input, ui32* value)
+{
+ return ReadVarUint32Impl(value, input);
+}
+
+Y_FORCE_INLINE int ReadVarUint32(const char* input, const char* end, ui32* value)
+{
+ return ReadVarUint32Impl(value, input, end);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class... Args>
+Y_FORCE_INLINE int ReadVarInt32Impl(i32* value, Args... args)
+{
+ ui64 varInt;
+ int bytesRead = ReadVarUint64(args..., &varInt);
+ if (varInt > std::numeric_limits<ui32>::max()) {
+ throw TSimpleException("Value is too big for varint32");
+ }
+ *value = ZigZagDecode32(static_cast<ui32>(varInt));
+ return bytesRead;
+}
+
+Y_FORCE_INLINE int ReadVarInt32(IInputStream* input, i32* value)
+{
+ return ReadVarInt32Impl(value, input);
+}
+
+Y_FORCE_INLINE int ReadVarInt32(const char* input, i32* value)
+{
+ return ReadVarInt32Impl(value, input);
+}
+
+Y_FORCE_INLINE int ReadVarInt32(const char* input, const char* end, i32* value)
+{
+ return ReadVarInt32Impl(value, input, end);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class... Args>
+Y_FORCE_INLINE int ReadVarInt64Impl(i64* value, Args... args)
+{
+ ui64 varInt;
+ int bytesRead = ReadVarUint64(args..., &varInt);
+ *value = ZigZagDecode64(varInt);
+ return bytesRead;
+}
+
+Y_FORCE_INLINE int ReadVarInt64(IInputStream* input, i64* value)
+{
+ return ReadVarInt64Impl(value, input);
+}
+
+Y_FORCE_INLINE int ReadVarInt64(const char* input, i64* value)
+{
+ return ReadVarInt64Impl(value, input);
+}
+
+Y_FORCE_INLINE int ReadVarInt64(const char* input, const char* end, i64* value)
+{
+ return ReadVarInt64Impl(value, input, end);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/coding/varint.h b/library/cpp/yt/coding/varint.h
new file mode 100644
index 0000000000..c5399f8b06
--- /dev/null
+++ b/library/cpp/yt/coding/varint.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <library/cpp/yt/exception/exception.h>
+
+#include <util/system/defaults.h>
+
+#include <util/stream/input.h>
+#include <util/stream/output.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+constexpr size_t MaxVarInt64Size = (8 * sizeof(ui64) - 1) / 7 + 1;
+constexpr size_t MaxVarUint64Size = (8 * sizeof(ui64) - 1) / 7 + 1;
+
+constexpr size_t MaxVarInt32Size = (8 * sizeof(ui32) - 1) / 7 + 1;
+constexpr size_t MaxVarUint32Size = (8 * sizeof(ui32) - 1) / 7 + 1;
+
+// Various functions to read/write varints.
+
+// Returns the number of bytes written.
+int WriteVarUint64(IOutputStream* output, ui64 value);
+int WriteVarUint32(IOutputStream* output, ui32 value);
+int WriteVarInt32(IOutputStream* output, i32 value);
+int WriteVarInt64(IOutputStream* output, i64 value);
+
+int WriteVarUint64(char* output, ui64 value);
+int WriteVarUint32(char* output, ui32 value);
+int WriteVarInt32(char* output, i32 value);
+int WriteVarInt64(char* output, i64 value);
+
+// Returns the number of bytes read.
+int ReadVarUint64(IInputStream* input, ui64* value);
+int ReadVarUint32(IInputStream* input, ui32* value);
+int ReadVarInt32(IInputStream* input, i32* value);
+int ReadVarInt64(IInputStream* input, i64* value);
+
+int ReadVarUint64(const char* input, ui64* value);
+int ReadVarUint32(const char* input, ui32* value);
+int ReadVarInt32(const char* input, i32* value);
+int ReadVarInt64(const char* input, i64* value);
+
+// Throws exception if integer is not complete when `end' is reached.
+int ReadVarUint64(const char* input, const char* end, ui64* value);
+int ReadVarUint32(const char* input, const char* end, ui32* value);
+int ReadVarInt32(const char* input, const char* end, i32* value);
+int ReadVarInt64(const char* input, const char* end, i64* value);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define VARINT_INL_H_
+#include "varint-inl.h"
+#undef VARINT_INL_H_
diff --git a/library/cpp/yt/coding/ya.make b/library/cpp/yt/coding/ya.make
new file mode 100644
index 0000000000..3dae919e57
--- /dev/null
+++ b/library/cpp/yt/coding/ya.make
@@ -0,0 +1,12 @@
+LIBRARY()
+
+SRCS(
+)
+
+PEERDIR(
+ library/cpp/yt/exception
+)
+
+END()
+
+RECURSE_FOR_TESTS(unittests)
diff --git a/library/cpp/yt/coding/zig_zag-inl.h b/library/cpp/yt/coding/zig_zag-inl.h
new file mode 100644
index 0000000000..c611f7e1d4
--- /dev/null
+++ b/library/cpp/yt/coding/zig_zag-inl.h
@@ -0,0 +1,40 @@
+#ifndef ZIG_ZAG_INL_H_
+#error "Direct inclusion of this file is not allowed, include zig_zag.h"
+// For the sake of sane code completion.
+#include "zig_zag.h"
+#endif
+#undef ZIG_ZAG_INL_H_
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+inline ui32 ZigZagEncode32(i32 n)
+{
+ // Note: the right-shift must be arithmetic.
+ // Note: left shift must be unsigned because of overflow.
+ return (static_cast<ui32>(n) << 1) ^ static_cast<ui32>(n >> 31);
+}
+
+inline i32 ZigZagDecode32(ui32 n)
+{
+ // Note: using unsigned types prevent undefined behavior.
+ return static_cast<i32>((n >> 1) ^ (~(n & 1) + 1));
+}
+
+inline ui64 ZigZagEncode64(i64 n)
+{
+ // Note: the right-shift must be arithmetic.
+ // Note: left shift must be unsigned because of overflow.
+ return (static_cast<ui64>(n) << 1) ^ static_cast<ui64>(n >> 63);
+}
+
+inline i64 ZigZagDecode64(ui64 n)
+{
+ // Note: using unsigned types prevent undefined behavior.
+ return static_cast<i64>((n >> 1) ^ (~(n & 1) + 1));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/coding/zig_zag.h b/library/cpp/yt/coding/zig_zag.h
new file mode 100644
index 0000000000..aa6d425a1c
--- /dev/null
+++ b/library/cpp/yt/coding/zig_zag.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <util/system/types.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+// These Functions provide coding of integers with property: 0 <= f(x) <= 2 * |x|
+// Actually taken 'as is' from protobuf/wire_format_lite.h
+
+ui32 ZigZagEncode32(i32 n);
+i32 ZigZagDecode32(ui32 n);
+
+ui64 ZigZagEncode64(i64 n);
+i64 ZigZagDecode64(ui64 n);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define ZIG_ZAG_INL_H_
+#include "zig_zag-inl.h"
+#undef ZIG_ZAG_INL_H_
diff --git a/library/cpp/yt/exception/exception.cpp b/library/cpp/yt/exception/exception.cpp
new file mode 100644
index 0000000000..1059d497e8
--- /dev/null
+++ b/library/cpp/yt/exception/exception.cpp
@@ -0,0 +1,48 @@
+#include "exception.h"
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TSimpleException::TSimpleException(TString message)
+ : Message_(std::move(message))
+{ }
+
+const TString& TSimpleException::GetMesage() const
+{
+ return Message_;
+}
+
+const char* TSimpleException::what() const noexcept
+{
+ return Message_.c_str();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+TCompositeException::TCompositeException(TString message)
+ : TSimpleException(std::move(message))
+ , What_(Message_)
+{ }
+
+TCompositeException::TCompositeException(
+ const std::exception& exception,
+ TString message)
+ : TSimpleException(message)
+ , InnerException_(std::current_exception())
+ , What_(message + "\n" + exception.what())
+{ }
+
+const std::exception_ptr& TCompositeException::GetInnerException() const
+{
+ return InnerException_;
+}
+
+const char* TCompositeException::what() const noexcept
+{
+ return What_.c_str();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/exception/exception.h b/library/cpp/yt/exception/exception.h
new file mode 100644
index 0000000000..7d35637d60
--- /dev/null
+++ b/library/cpp/yt/exception/exception.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <util/generic/string.h>
+
+#include <exception>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+// These are poor man's versions of NYT::TErrorException to be used in
+// a limited subset of core libraries that are needed to implement NYT::TError.
+
+class TSimpleException
+ : public std::exception
+{
+public:
+ explicit TSimpleException(TString message);
+
+ const TString& GetMesage() const;
+ const char* what() const noexcept override;
+
+protected:
+ const TString Message_;
+};
+
+class TCompositeException
+ : public TSimpleException
+{
+public:
+ explicit TCompositeException(TString message);
+ TCompositeException(
+ const std::exception& exception,
+ TString message);
+
+ const std::exception_ptr& GetInnerException() const;
+ const char* what() const noexcept override;
+
+private:
+ const std::exception_ptr InnerException_;
+ const TString What_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/exception/ya.make b/library/cpp/yt/exception/ya.make
new file mode 100644
index 0000000000..0c89c31dc3
--- /dev/null
+++ b/library/cpp/yt/exception/ya.make
@@ -0,0 +1,7 @@
+LIBRARY()
+
+SRCS(
+ exception.cpp
+)
+
+END()
diff --git a/library/cpp/yt/malloc/malloc.cpp b/library/cpp/yt/malloc/malloc.cpp
new file mode 100644
index 0000000000..808afacdfb
--- /dev/null
+++ b/library/cpp/yt/malloc/malloc.cpp
@@ -0,0 +1,19 @@
+#include "malloc.h"
+
+#include <util/system/compiler.h>
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_WEAK extern "C" size_t nallocx(size_t size, int /* flags */) noexcept
+{
+ return size;
+}
+
+#ifndef _win_
+Y_WEAK extern "C" size_t malloc_usable_size(void* /* ptr */) noexcept
+{
+ return 0;
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/library/cpp/yt/malloc/malloc.h b/library/cpp/yt/malloc/malloc.h
new file mode 100644
index 0000000000..b3c16d7849
--- /dev/null
+++ b/library/cpp/yt/malloc/malloc.h
@@ -0,0 +1,8 @@
+#include <cstddef>
+
+////////////////////////////////////////////////////////////////////////////////
+
+extern "C" size_t malloc_usable_size(void* ptr) noexcept;
+extern "C" size_t nallocx(size_t size, int flags) noexcept;
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/library/cpp/yt/malloc/ya.make b/library/cpp/yt/malloc/ya.make
new file mode 100644
index 0000000000..0a07d93b36
--- /dev/null
+++ b/library/cpp/yt/malloc/ya.make
@@ -0,0 +1,7 @@
+LIBRARY()
+
+SRCS(
+ malloc.cpp
+)
+
+END()
diff --git a/library/cpp/yt/memory/blob.cpp b/library/cpp/yt/memory/blob.cpp
new file mode 100644
index 0000000000..86000b033b
--- /dev/null
+++ b/library/cpp/yt/memory/blob.cpp
@@ -0,0 +1,224 @@
+#include "blob.h"
+#include "ref.h"
+
+#include <library/cpp/ytalloc/api/ytalloc.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+static constexpr size_t InitialBlobCapacity = 16;
+static constexpr double BlobCapacityMultiplier = 1.5;
+
+TBlob::TBlob(
+ TRefCountedTypeCookie tagCookie,
+ size_t size,
+ bool initiailizeStorage,
+ bool pageAligned)
+ : PageAligned_(pageAligned)
+{
+ SetTagCookie(tagCookie);
+ if (size == 0) {
+ Reset();
+ } else {
+ Allocate(std::max(size, InitialBlobCapacity));
+ Size_ = size;
+ if (initiailizeStorage) {
+ ::memset(Begin_, 0, Size_);
+ }
+ }
+}
+
+TBlob::TBlob(
+ TRefCountedTypeCookie tagCookie,
+ TRef data,
+ bool pageAligned)
+ : PageAligned_(pageAligned)
+{
+ SetTagCookie(tagCookie);
+ Reset();
+ Append(data);
+}
+
+TBlob::TBlob(const TBlob& other)
+ : PageAligned_(other.PageAligned_)
+{
+ SetTagCookie(other);
+ if (other.Size_ == 0) {
+ Reset();
+ } else {
+ Allocate(std::max(InitialBlobCapacity, other.Size_));
+ ::memcpy(Begin_, other.Begin_, other.Size_);
+ Size_ = other.Size_;
+ }
+}
+
+TBlob::TBlob(TBlob&& other) noexcept
+ : Begin_(other.Begin_)
+ , Size_(other.Size_)
+ , Capacity_(other.Capacity_)
+ , PageAligned_(other.PageAligned_)
+{
+ SetTagCookie(other);
+ other.Reset();
+}
+
+TBlob::~TBlob()
+{
+ Free();
+}
+
+void TBlob::Reserve(size_t newCapacity)
+{
+ if (newCapacity > Capacity_) {
+ Reallocate(newCapacity);
+ }
+}
+
+void TBlob::Resize(size_t newSize, bool initializeStorage /*= true*/)
+{
+ if (newSize > Size_) {
+ if (newSize > Capacity_) {
+ size_t newCapacity;
+ if (Capacity_ == 0) {
+ newCapacity = std::max(InitialBlobCapacity, newSize);
+ } else {
+ newCapacity = std::max(static_cast<size_t>(Capacity_ * BlobCapacityMultiplier), newSize);
+ }
+ Reallocate(newCapacity);
+ }
+ if (initializeStorage) {
+ ::memset(Begin_ + Size_, 0, newSize - Size_);
+ }
+ }
+ Size_ = newSize;
+}
+
+TBlob& TBlob::operator = (const TBlob& rhs)
+{
+ if (this != &rhs) {
+ this->~TBlob();
+ new(this) TBlob(rhs);
+ }
+ return *this;
+}
+
+TBlob& TBlob::operator = (TBlob&& rhs) noexcept
+{
+ if (this != &rhs) {
+ this->~TBlob();
+ new(this) TBlob(std::move(rhs));
+ }
+ return *this;
+}
+
+void TBlob::Append(const void* data, size_t size)
+{
+ if (Size_ + size > Capacity_) {
+ Resize(Size_ + size, false);
+ ::memcpy(Begin_ + Size_ - size, data, size);
+ } else {
+ ::memcpy(Begin_ + Size_, data, size);
+ Size_ += size;
+ }
+}
+
+void TBlob::Append(TRef ref)
+{
+ Append(ref.Begin(), ref.Size());
+}
+
+void TBlob::Append(char ch)
+{
+ if (Size_ + 1 > Capacity_) {
+ Resize(Size_ + 1, false);
+ Begin_[Size_ - 1] = ch;
+ } else {
+ Begin_[Size_++] = ch;
+ }
+}
+
+void TBlob::Reset()
+{
+ Begin_ = nullptr;
+ Size_ = Capacity_ = 0;
+}
+
+char* TBlob::DoAllocate(size_t size)
+{
+ return static_cast<char*>(PageAligned_
+ ? NYTAlloc::AllocatePageAligned(size)
+ : NYTAlloc::Allocate(size));
+}
+
+void TBlob::Allocate(size_t newCapacity)
+{
+ YT_VERIFY(!Begin_);
+ Begin_ = DoAllocate(newCapacity);
+ Capacity_ = newCapacity;
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TRefCountedTrackerFacade::AllocateTagInstance(TagCookie_);
+ TRefCountedTrackerFacade::AllocateSpace(TagCookie_, newCapacity);
+#endif
+}
+
+void TBlob::Reallocate(size_t newCapacity)
+{
+ if (!Begin_) {
+ Allocate(newCapacity);
+ return;
+ }
+ char* newBegin = DoAllocate(newCapacity);
+ ::memcpy(newBegin, Begin_, Size_);
+ NYTAlloc::FreeNonNull(Begin_);
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TRefCountedTrackerFacade::AllocateSpace(TagCookie_, newCapacity);
+ TRefCountedTrackerFacade::FreeSpace(TagCookie_, Capacity_);
+#endif
+ Begin_ = newBegin;
+ Capacity_ = newCapacity;
+}
+
+void TBlob::Free()
+{
+ if (!Begin_) {
+ return;
+ }
+ NYTAlloc::FreeNonNull(Begin_);
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TRefCountedTrackerFacade::FreeTagInstance(TagCookie_);
+ TRefCountedTrackerFacade::FreeSpace(TagCookie_, Capacity_);
+#endif
+ Reset();
+}
+
+void TBlob::SetTagCookie(TRefCountedTypeCookie tagCookie)
+{
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TagCookie_ = tagCookie;
+#endif
+}
+
+void TBlob::SetTagCookie(const TBlob& other)
+{
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TagCookie_ = other.TagCookie_;
+#endif
+}
+
+void swap(TBlob& left, TBlob& right)
+{
+ if (&left != &right) {
+ std::swap(left.Begin_, right.Begin_);
+ std::swap(left.Size_, right.Size_);
+ std::swap(left.Capacity_, right.Capacity_);
+ std::swap(left.PageAligned_, right.PageAligned_);
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ std::swap(left.TagCookie_, right.TagCookie_);
+#endif
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/memory/blob.h b/library/cpp/yt/memory/blob.h
new file mode 100644
index 0000000000..99441fb8c9
--- /dev/null
+++ b/library/cpp/yt/memory/blob.h
@@ -0,0 +1,221 @@
+#pragma once
+
+#include "ref.h"
+#include "ref_counted.h"
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Default memory tag for TBlob.
+struct TDefaultBlobTag
+{ };
+
+//! A home-grown optimized replacement for |std::vector<char>| suitable for carrying
+//! large chunks of data.
+/*!
+ * Compared to |std::vector<char>|, this class supports uninitialized allocations
+ * when explicitly requested to.
+ */
+class TBlob
+{
+public:
+ //! Constructs a blob with a given size.
+ TBlob(
+ TRefCountedTypeCookie tagCookie,
+ size_t size,
+ bool initiailizeStorage = true,
+ bool pageAligned = false);
+
+ //! Copies a chunk of memory into a new instance.
+ TBlob(
+ TRefCountedTypeCookie tagCookie,
+ TRef data,
+ bool pageAligned = false);
+
+ //! Constructs an empty blob.
+ template <class TTag = TDefaultBlobTag>
+ explicit TBlob(TTag tag = {})
+ : TBlob(tag, 0, true, false)
+ { }
+
+ //! Constructs a blob with a given size.
+ template <class TTag>
+ explicit TBlob(
+ TTag,
+ size_t size,
+ bool initiailizeStorage = true,
+ bool pageAligned = false)
+ : TBlob(
+ GetRefCountedTypeCookie<TTag>(),
+ size,
+ initiailizeStorage,
+ pageAligned)
+ { }
+
+ //! Copies a chunk of memory into a new instance.
+ template <class TTag>
+ TBlob(
+ TTag,
+ TRef data,
+ bool pageAligned = false)
+ : TBlob(
+ GetRefCountedTypeCookie<TTag>(),
+ data,
+ pageAligned)
+ { }
+
+ //! Remind user about the tag argument.
+ TBlob(i32 size, bool initiailizeStorage = true) = delete;
+ TBlob(i64 size, bool initiailizeStorage = true) = delete;
+ TBlob(ui32 size, bool initiailizeStorage = true) = delete;
+ TBlob(ui64 size, bool initiailizeStorage = true) = delete;
+ template <typename T, typename U>
+ TBlob(const T*, U) = delete;
+
+ //! Copies the data.
+ TBlob(const TBlob& other);
+
+ //! Moves the data (takes the ownership).
+ TBlob(TBlob&& other) noexcept;
+
+ //! Reclaims the memory.
+ ~TBlob();
+
+ //! Ensures that capacity is at least #capacity.
+ void Reserve(size_t newCapacity);
+
+ //! Changes the size to #newSize.
+ /*!
+ * If #size exceeds the current capacity,
+ * we make sure the new capacity grows exponentially.
+ * Hence calling #Resize N times to increase the size by N only
+ * takes amortized O(1) time per call.
+ */
+ void Resize(size_t newSize, bool initializeStorage = true);
+
+ //! Returns the start pointer.
+ Y_FORCE_INLINE const char* Begin() const
+ {
+ return Begin_;
+ }
+
+ //! Returns the start pointer.
+ Y_FORCE_INLINE char* Begin()
+ {
+ return Begin_;
+ }
+
+ //! Returns the end pointer.
+ Y_FORCE_INLINE const char* End() const
+ {
+ return Begin_ + Size_;
+ }
+
+ //! Returns the end pointer.
+ Y_FORCE_INLINE char* End()
+ {
+ return Begin_ + Size_;
+ }
+
+ //! Returns the size.
+ Y_FORCE_INLINE size_t size() const
+ {
+ return Size_;
+ }
+
+ //! Returns the size.
+ Y_FORCE_INLINE size_t Size() const
+ {
+ return Size_;
+ }
+
+ //! Returns the capacity.
+ Y_FORCE_INLINE size_t Capacity() const
+ {
+ return Capacity_;
+ }
+
+ //! Returns the TStringBuf instance for the occupied part of the blob.
+ Y_FORCE_INLINE TStringBuf ToStringBuf() const
+ {
+ return TStringBuf(Begin_, Size_);
+ }
+
+ //! Returns the TRef instance for the occupied part of the blob.
+ Y_FORCE_INLINE TRef ToRef() const
+ {
+ return TRef(Begin_, Size_);
+ }
+
+ //! Provides by-value access to the underlying storage.
+ Y_FORCE_INLINE char operator [] (size_t index) const
+ {
+ return Begin_[index];
+ }
+
+ //! Provides by-ref access to the underlying storage.
+ Y_FORCE_INLINE char& operator [] (size_t index)
+ {
+ return Begin_[index];
+ }
+
+ //! Clears the instance but does not reclaim the memory.
+ Y_FORCE_INLINE void Clear()
+ {
+ Size_ = 0;
+ }
+
+ //! Returns |true| if size is zero.
+ Y_FORCE_INLINE bool IsEmpty() const
+ {
+ return Size_ == 0;
+ }
+
+ //! Overwrites the current instance.
+ TBlob& operator = (const TBlob& rhs);
+
+ //! Takes the ownership.
+ TBlob& operator = (TBlob&& rhs) noexcept;
+
+ //! Appends a chunk of memory to the end.
+ void Append(const void* data, size_t size);
+
+ //! Appends a chunk of memory to the end.
+ void Append(TRef ref);
+
+ //! Appends a single char to the end.
+ void Append(char ch);
+
+ //! Swaps the current and other instances
+ void Swap(TBlob& other);
+
+ friend void swap(TBlob& left, TBlob& right);
+
+private:
+ char* Begin_ = nullptr;
+ size_t Size_ = 0;
+ size_t Capacity_ = 0;
+ bool PageAligned_ = false;
+
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TRefCountedTypeCookie TagCookie_ = NullRefCountedTypeCookie;
+#endif
+
+ char* DoAllocate(size_t newCapacity);
+ void Allocate(size_t newCapacity);
+ void Reallocate(size_t newCapacity);
+ void Free();
+
+ void Reset();
+
+ void SetTagCookie(TRefCountedTypeCookie tagCookie);
+ void SetTagCookie(const TBlob& other);
+};
+
+void swap(TBlob& left, TBlob& right);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
diff --git a/library/cpp/yt/memory/intrusive_ptr.h b/library/cpp/yt/memory/intrusive_ptr.h
new file mode 100644
index 0000000000..3dead7db1d
--- /dev/null
+++ b/library/cpp/yt/memory/intrusive_ptr.h
@@ -0,0 +1,360 @@
+#pragma once
+
+#include "ref_counted.h"
+
+#include <util/generic/hash.h>
+#include <util/generic/utility.h>
+
+#include <utility>
+#include <type_traits>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+class TIntrusivePtr
+{
+public:
+ typedef T TUnderlying;
+
+ constexpr TIntrusivePtr() noexcept
+ { }
+
+ constexpr TIntrusivePtr(std::nullptr_t) noexcept
+ { }
+
+ //! Constructor from an unqualified reference.
+ /*!
+ * Note that this constructor could be racy due to unsynchronized operations
+ * on the object and on the counter.
+ *
+ * Note that it notoriously hard to make this constructor explicit
+ * given the current amount of code written.
+ */
+ TIntrusivePtr(T* obj, bool addReference = true) noexcept
+ : T_(obj)
+ {
+ if (T_ && addReference) {
+ Ref(T_);
+ }
+ }
+
+ //! Copy constructor.
+ TIntrusivePtr(const TIntrusivePtr& other) noexcept
+ : T_(other.Get())
+ {
+ if (T_) {
+ Ref(T_);
+ }
+ }
+
+ //! Copy constructor with an upcast.
+ template <class U, class = typename std::enable_if_t<std::is_convertible_v<U*, T*>>>
+ TIntrusivePtr(const TIntrusivePtr<U>& other) noexcept
+ : T_(other.Get())
+ {
+ static_assert(
+ std::is_base_of_v<TRefCountedBase, T>,
+ "Cast allowed only for types derived from TRefCountedBase");
+ if (T_) {
+ Ref(T_);
+ }
+ }
+
+ //! Move constructor.
+ TIntrusivePtr(TIntrusivePtr&& other) noexcept
+ : T_(other.Get())
+ {
+ other.T_ = nullptr;
+ }
+
+ //! Move constructor with an upcast.
+ template <class U, class = typename std::enable_if_t<std::is_convertible_v<U*, T*>>>
+ TIntrusivePtr(TIntrusivePtr<U>&& other) noexcept
+ : T_(other.Get())
+ {
+ static_assert(
+ std::is_base_of_v<TRefCountedBase, T>,
+ "Cast allowed only for types derived from TRefCountedBase");
+ other.T_ = nullptr;
+ }
+
+ //! Destructor.
+ ~TIntrusivePtr()
+ {
+ if (T_) {
+ Unref(T_);
+ }
+ }
+
+ //! Copy assignment operator.
+ TIntrusivePtr& operator=(const TIntrusivePtr& other) noexcept
+ {
+ TIntrusivePtr(other).Swap(*this);
+ return *this;
+ }
+
+ //! Copy assignment operator with an upcast.
+ template <class U>
+ TIntrusivePtr& operator=(const TIntrusivePtr<U>& other) noexcept
+ {
+ static_assert(
+ std::is_convertible_v<U*, T*>,
+ "U* must be convertible to T*");
+ static_assert(
+ std::is_base_of_v<TRefCountedBase, T>,
+ "Cast allowed only for types derived from TRefCountedBase");
+ TIntrusivePtr(other).Swap(*this);
+ return *this;
+ }
+
+ //! Move assignment operator.
+ TIntrusivePtr& operator=(TIntrusivePtr&& other) noexcept
+ {
+ TIntrusivePtr(std::move(other)).Swap(*this);
+ return *this;
+ }
+
+ //! Move assignment operator with an upcast.
+ template <class U>
+ TIntrusivePtr& operator=(TIntrusivePtr<U>&& other) noexcept
+ {
+ static_assert(
+ std::is_convertible_v<U*, T*>,
+ "U* must be convertible to T*");
+ static_assert(
+ std::is_base_of_v<TRefCountedBase, T>,
+ "Cast allowed only for types derived from TRefCountedBase");
+ TIntrusivePtr(std::move(other)).Swap(*this);
+ return *this;
+ }
+
+ //! Drop the pointer.
+ void Reset() // noexcept
+ {
+ TIntrusivePtr().Swap(*this);
+ }
+
+ //! Replace the pointer with a specified one.
+ void Reset(T* p) // noexcept
+ {
+ TIntrusivePtr(p).Swap(*this);
+ }
+
+ //! Returns the pointer.
+ T* Get() const noexcept
+ {
+ return T_;
+ }
+
+ //! Returns the pointer and releases the ownership.
+ T* Release() noexcept
+ {
+ auto* p = T_;
+ T_ = nullptr;
+ return p;
+ }
+
+ T& operator*() const noexcept
+ {
+ YT_ASSERT(T_);
+ return *T_;
+ }
+
+ T* operator->() const noexcept
+ {
+ YT_ASSERT(T_);
+ return T_;
+ }
+
+ explicit operator bool() const noexcept
+ {
+ return T_ != nullptr;
+ }
+
+ //! Swap the pointer with the other one.
+ void Swap(TIntrusivePtr& r) noexcept
+ {
+ DoSwap(T_, r.T_);
+ }
+
+private:
+ template <class U>
+ friend class TIntrusivePtr;
+
+ T* T_ = nullptr;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Creates a strong pointer wrapper for a given raw pointer.
+//! Compared to |TIntrusivePtr<T>::ctor|, type inference enables omitting |T|.
+template <class T>
+TIntrusivePtr<T> MakeStrong(T* p)
+{
+ return TIntrusivePtr<T>(p);
+}
+
+//! Tries to obtain an intrusive pointer for an object that may had
+//! already lost all of its references and, thus, is about to be deleted.
+/*!
+ * You may call this method at any time provided that you have a valid
+ * raw pointer to an object. The call either returns an intrusive pointer
+ * for the object (thus ensuring that the object won't be destroyed until
+ * you're holding this pointer) or NULL indicating that the last reference
+ * had already been lost and the object is on its way to heavens.
+ * All these steps happen atomically.
+ *
+ * Under all circumstances it is caller's responsibility the make sure that
+ * the object is not destroyed during the call to #DangerousGetPtr.
+ * Typically this is achieved by keeping a (lock-protected) collection of
+ * raw pointers, taking a lock in object's destructor, and unregistering
+ * its raw pointer from the collection there.
+ */
+
+template <class T>
+Y_FORCE_INLINE TIntrusivePtr<T> DangerousGetPtr(T* object)
+{
+ return object->TryRef()
+ ? TIntrusivePtr<T>(object, false)
+ : TIntrusivePtr<T>();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, class U>
+TIntrusivePtr<T> StaticPointerCast(const TIntrusivePtr<U>& ptr)
+{
+ return {static_cast<T*>(ptr.Get())};
+}
+
+template <class T, class U>
+TIntrusivePtr<T> StaticPointerCast(TIntrusivePtr<U>&& ptr)
+{
+ return {static_cast<T*>(ptr.Release()), false};
+}
+
+template <class T, class U>
+TIntrusivePtr<T> ConstPointerCast(const TIntrusivePtr<U>& ptr)
+{
+ return {const_cast<T*>(ptr.Get())};
+}
+
+template <class T, class U>
+TIntrusivePtr<T> ConstPointerCast(TIntrusivePtr<U>&& ptr)
+{
+ return {const_cast<T*>(ptr.Release()), false};
+}
+
+template <class T, class U>
+TIntrusivePtr<T> DynamicPointerCast(const TIntrusivePtr<U>& ptr)
+{
+ return {dynamic_cast<T*>(ptr.Get())};
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+bool operator<(const TIntrusivePtr<T>& lhs, const TIntrusivePtr<T>& rhs)
+{
+ return lhs.Get() < rhs.Get();
+}
+
+template <class T>
+bool operator>(const TIntrusivePtr<T>& lhs, const TIntrusivePtr<T>& rhs)
+{
+ return lhs.Get() > rhs.Get();
+}
+
+template <class T, class U>
+bool operator==(const TIntrusivePtr<T>& lhs, const TIntrusivePtr<U>& rhs)
+{
+ static_assert(
+ std::is_convertible_v<U*, T*>,
+ "U* must be convertible to T*");
+ return lhs.Get() == rhs.Get();
+}
+
+template <class T, class U>
+bool operator!=(const TIntrusivePtr<T>& lhs, const TIntrusivePtr<U>& rhs)
+{
+ static_assert(
+ std::is_convertible_v<U*, T*>,
+ "U* must be convertible to T*");
+ return lhs.Get() != rhs.Get();
+}
+
+template <class T, class U>
+bool operator==(const TIntrusivePtr<T>& lhs, U* rhs)
+{
+ static_assert(
+ std::is_convertible_v<U*, T*>,
+ "U* must be convertible to T*");
+ return lhs.Get() == rhs;
+}
+
+template <class T, class U>
+bool operator!=(const TIntrusivePtr<T>& lhs, U* rhs)
+{
+ static_assert(
+ std::is_convertible_v<U*, T*>,
+ "U* must be convertible to T*");
+ return lhs.Get() != rhs;
+}
+
+template <class T, class U>
+bool operator==(T* lhs, const TIntrusivePtr<U>& rhs)
+{
+ static_assert(
+ std::is_convertible_v<U*, T*>,
+ "U* must be convertible to T*");
+ return lhs == rhs.Get();
+}
+
+template <class T, class U>
+bool operator!=(T* lhs, const TIntrusivePtr<U>& rhs)
+{
+ static_assert(
+ std::is_convertible_v<U*, T*>,
+ "U* must be convertible to T*");
+ return lhs != rhs.Get();
+}
+
+template <class T>
+bool operator==(std::nullptr_t, const TIntrusivePtr<T>& rhs)
+{
+ return nullptr == rhs.Get();
+}
+
+template <class T>
+bool operator!=(std::nullptr_t, const TIntrusivePtr<T>& rhs)
+{
+ return nullptr != rhs.Get();
+}
+
+template <class T>
+bool operator==(const TIntrusivePtr<T>& lhs, std::nullptr_t)
+{
+ return nullptr == lhs.Get();
+}
+
+template <class T>
+bool operator!=(const TIntrusivePtr<T>& lhs, std::nullptr_t)
+{
+ return nullptr != lhs.Get();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} //namespace NYT
+
+//! A hasher for TIntrusivePtr.
+template <class T>
+struct THash<NYT::TIntrusivePtr<T>>
+{
+ Y_FORCE_INLINE size_t operator () (const NYT::TIntrusivePtr<T>& ptr) const
+ {
+ return THash<T*>()(ptr.Get());
+ }
+};
diff --git a/library/cpp/yt/memory/leaky_ref_counted_singleton-inl.h b/library/cpp/yt/memory/leaky_ref_counted_singleton-inl.h
new file mode 100644
index 0000000000..a68ec5ed6a
--- /dev/null
+++ b/library/cpp/yt/memory/leaky_ref_counted_singleton-inl.h
@@ -0,0 +1,43 @@
+#ifndef LEAKY_REF_COUNTED_SINGLETON_INL_H_
+#error "Direct inclusion of this file is not allowed, include leaky_ref_counted_singleton.h"
+// For the sake of sane code completion.
+#include "leaky_ref_counted_singleton.h"
+#endif
+
+#include "new.h"
+
+#include <atomic>
+#include <mutex>
+
+#include <util/system/compiler.h>
+#include <util/system/sanitizers.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+TIntrusivePtr<T> LeakyRefCountedSingleton()
+{
+ static std::atomic<T*> Ptr;
+ auto* ptr = Ptr.load(std::memory_order_acquire);
+ if (Y_LIKELY(ptr)) {
+ return ptr;
+ }
+
+ static std::once_flag Initialized;
+ std::call_once(Initialized, [] {
+ auto ptr = New<T>();
+ Ref(ptr.Get());
+ Ptr.store(ptr.Get());
+#if defined(_asan_enabled_)
+ NSan::MarkAsIntentionallyLeaked(ptr.Get());
+#endif
+ });
+
+ return Ptr.load();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/memory/leaky_ref_counted_singleton.h b/library/cpp/yt/memory/leaky_ref_counted_singleton.h
new file mode 100644
index 0000000000..1d5761bd9d
--- /dev/null
+++ b/library/cpp/yt/memory/leaky_ref_counted_singleton.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "intrusive_ptr.h"
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+TIntrusivePtr<T> LeakyRefCountedSingleton();
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define LEAKY_REF_COUNTED_SINGLETON_INL_H_
+#include "leaky_ref_counted_singleton-inl.h"
+#undef LEAKY_REF_COUNTED_SINGLETON_INL_H_
diff --git a/library/cpp/yt/memory/leaky_singleton-inl.h b/library/cpp/yt/memory/leaky_singleton-inl.h
new file mode 100644
index 0000000000..932747c921
--- /dev/null
+++ b/library/cpp/yt/memory/leaky_singleton-inl.h
@@ -0,0 +1,34 @@
+#ifndef LEAKY_SINGLETON_INL_H_
+#error "Direct inclusion of this file is not allowed, include leaky_singleton.h"
+// For the sake of sane code completion.
+#include "leaky_singleton.h"
+#endif
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+TLeakyStorage<T>::TLeakyStorage()
+{
+ new (Get()) T();
+}
+
+template <class T>
+T* TLeakyStorage<T>::Get()
+{
+ return reinterpret_cast<T*>(Buffer_);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+T* LeakySingleton()
+{
+ static TLeakyStorage<T> Storage;
+ return Storage.Get();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/memory/leaky_singleton.h b/library/cpp/yt/memory/leaky_singleton.h
new file mode 100644
index 0000000000..03b5e51d78
--- /dev/null
+++ b/library/cpp/yt/memory/leaky_singleton.h
@@ -0,0 +1,34 @@
+#pragma once
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+class TLeakyStorage
+{
+public:
+ TLeakyStorage();
+
+ T* Get();
+
+private:
+ alignas(T) char Buffer_[sizeof(T)];
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define DECLARE_LEAKY_SINGLETON_FRIEND() \
+ template <class T> \
+ friend class ::NYT::TLeakyStorage;
+
+template <class T>
+T* LeakySingleton();
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define LEAKY_SINGLETON_INL_H_
+#include "leaky_singleton-inl.h"
+#undef LEAKY_SINGLETON_INL_H_
diff --git a/library/cpp/yt/memory/new-inl.h b/library/cpp/yt/memory/new-inl.h
new file mode 100644
index 0000000000..0a84818516
--- /dev/null
+++ b/library/cpp/yt/memory/new-inl.h
@@ -0,0 +1,310 @@
+#ifndef NEW_INL_H_
+#error "Direct inclusion of this file is not allowed, include new.h"
+// For the sake of sane code completion.
+#include "new.h"
+#endif
+
+#include <library/cpp/ytalloc/api/ytalloc.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct TRefCountedCookieHolder
+{
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TRefCountedTypeCookie Cookie = NullRefCountedTypeCookie;
+
+ void InitializeTracking(TRefCountedTypeCookie cookie)
+ {
+ YT_ASSERT(Cookie == NullRefCountedTypeCookie);
+ Cookie = cookie;
+ TRefCountedTrackerFacade::AllocateInstance(Cookie);
+ }
+
+ ~TRefCountedCookieHolder()
+ {
+ if (Cookie != NullRefCountedTypeCookie) {
+ TRefCountedTrackerFacade::FreeInstance(Cookie);
+ }
+ }
+#endif
+};
+
+template <class T>
+struct TRefCountedWrapper final
+ : public T
+ , public TRefTracked<T>
+{
+ template <class... TArgs>
+ explicit TRefCountedWrapper(TArgs&&... args)
+ : T(std::forward<TArgs>(args)...)
+ { }
+
+ ~TRefCountedWrapper() = default;
+
+ void DestroyRefCounted() override
+ {
+ T::DestroyRefCountedImpl(this);
+ }
+};
+
+template <class T, class TDeleter>
+class TRefCountedWrapperWithDeleter final
+ : public T
+ , public TRefTracked<T>
+{
+public:
+ template <class... TArgs>
+ explicit TRefCountedWrapperWithDeleter(const TDeleter& deleter, TArgs&&... args)
+ : T(std::forward<TArgs>(args)...)
+ , Deleter_(deleter)
+ { }
+
+ ~TRefCountedWrapperWithDeleter() = default;
+
+ void DestroyRefCounted() override
+ {
+ Deleter_(this);
+ }
+
+private:
+ TDeleter Deleter_;
+};
+
+template <class T>
+struct TRefCountedWrapperWithCookie final
+ : public T
+ , public TRefCountedCookieHolder
+{
+ template <class... TArgs>
+ explicit TRefCountedWrapperWithCookie(TArgs&&... args)
+ : T(std::forward<TArgs>(args)...)
+ { }
+
+ ~TRefCountedWrapperWithCookie() = default;
+
+ void DestroyRefCounted() override
+ {
+ T::DestroyRefCountedImpl(this);
+ }
+};
+
+namespace NDetail {
+
+Y_FORCE_INLINE void* AllignedMalloc(size_t size, size_t allignment)
+{
+#ifdef _win_
+ return ::_aligned_malloc(size, allignment);
+#else
+ void* ptr = nullptr;
+ ::posix_memalign(&ptr, allignment, size);
+ return ptr;
+#endif
+}
+
+template <class... Args>
+Y_FORCE_INLINE void CustomInitialize(Args... args)
+{
+ Y_UNUSED(args...);
+}
+
+template <class T>
+Y_FORCE_INLINE auto CustomInitialize(T* ptr) -> decltype(&T::InitializeRefCounted, void())
+{
+ ptr->InitializeRefCounted();
+}
+
+template <class T, class... As>
+Y_FORCE_INLINE T* NewEpilogue(void* ptr, As&& ... args)
+{
+ try {
+ auto* instance = static_cast<T*>(ptr);
+ new (instance) T(std::forward<As>(args)...);
+ CustomInitialize(instance);
+ return instance;
+ } catch (const std::exception& ex) {
+ // Do not forget to free the memory.
+ TFreeMemory<T>::Do(ptr);
+ throw;
+ }
+}
+
+template <class T, bool = std::is_base_of_v<TRefCountedBase, T>>
+struct TConstructHelper
+{
+ static constexpr size_t RefCounterSpace = (sizeof(TRefCounter) + alignof(T) - 1) & ~(alignof(T) - 1);
+ static constexpr size_t RefCounterOffset = RefCounterSpace - sizeof(TRefCounter);
+ static constexpr size_t Size = RefCounterSpace + sizeof(T);
+ static constexpr size_t Alignment = alignof(T);
+
+ template <class... As>
+ Y_FORCE_INLINE static T* Construct(void* ptr, As&&... args)
+ {
+ auto* refCounter = reinterpret_cast<TRefCounter*>(static_cast<char*>(ptr) + RefCounterOffset);
+ new (refCounter) TRefCounter();
+ auto* object = reinterpret_cast<T*>(refCounter + 1);
+ if constexpr (std::is_constructible_v<T, As...>) {
+ new(object) T(std::forward<As>(args)...);
+ } else {
+ new(object) T{std::forward<As>(args)...};
+ }
+ CustomInitialize(object);
+ return object;
+ }
+};
+
+template <class T>
+struct TConstructHelper<T, true>
+{
+ static constexpr size_t Size = sizeof(TRefCountedWrapper<T>);
+ static constexpr size_t Alignment = alignof(TRefCountedWrapper<T>);
+
+ template <class... As>
+ Y_FORCE_INLINE static TRefCountedWrapper<T>* Construct(void* ptr, As&&... args)
+ {
+ using TDerived = TRefCountedWrapper<T>;
+ auto* object = new(static_cast<TDerived*>(ptr)) TDerived(std::forward<As>(args)...);
+ CustomInitialize(object);
+ return object;
+ }
+};
+
+template <class T, class... As>
+Y_FORCE_INLINE TIntrusivePtr<T> SafeConstruct(void* ptr, As&&... args)
+{
+ try {
+ auto* instance = TConstructHelper<T>::Construct(ptr, std::forward<As>(args)...);
+ return TIntrusivePtr<T>(instance, false);
+ } catch (const std::exception& ex) {
+ // Do not forget to free the memory.
+ TFreeMemory<T>::Do(ptr);
+ throw;
+ }
+}
+
+template <size_t Size, size_t Alignment>
+void* AllocateConstSizeAligned()
+{
+ if (Alignment <= 16) {
+ return NYTAlloc::AllocateConstSize<Size>();
+ } else {
+ return AllignedMalloc(Size, Alignment);
+ }
+}
+
+} // namespace NDetail
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, class... As, class>
+Y_FORCE_INLINE TIntrusivePtr<T> New(
+ As&&... args)
+{
+ void* ptr = NDetail::AllocateConstSizeAligned<
+ NDetail::TConstructHelper<T>::Size,
+ NDetail::TConstructHelper<T>::Alignment>();
+
+ return NDetail::SafeConstruct<T>(ptr, std::forward<As>(args)...);
+}
+
+template <class T, class... As, class>
+Y_FORCE_INLINE TIntrusivePtr<T> New(
+ typename T::TAllocator* allocator,
+ As&&... args)
+{
+ auto* ptr = allocator->Allocate(NDetail::TConstructHelper<T>::Size);
+ if (!ptr) {
+ return nullptr;
+ }
+ return NDetail::SafeConstruct<T>(ptr, std::forward<As>(args)...);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, class... As, class>
+Y_FORCE_INLINE TIntrusivePtr<T> NewWithExtraSpace(
+ size_t extraSpaceSize,
+ As&&... args)
+{
+ auto totalSize = NYT::NDetail::TConstructHelper<T>::Size + extraSpaceSize;
+ void* ptr = nullptr;
+
+ if (NYT::NDetail::TConstructHelper<T>::Alignment <= 16) {
+ ptr = NYTAlloc::Allocate(totalSize);
+ } else {
+ ptr = NYT::NDetail::AllignedMalloc(totalSize, NYT::NDetail::TConstructHelper<T>::Alignment);
+ }
+
+ return NYT::NDetail::SafeConstruct<T>(ptr, std::forward<As>(args)...);
+}
+
+template <class T, class... As, class>
+Y_FORCE_INLINE TIntrusivePtr<T> NewWithExtraSpace(
+ typename T::TAllocator* allocator,
+ size_t extraSpaceSize,
+ As&&... args)
+{
+ auto totalSize = NYT::NDetail::TConstructHelper<T>::Size + extraSpaceSize;
+ auto* ptr = allocator->Allocate(totalSize);
+ if (!ptr) {
+ return nullptr;
+ }
+ return NYT::NDetail::SafeConstruct<T>(ptr, std::forward<As>(args)...);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Support for polymorphic only
+template <class T, class TDeleter, class... As>
+Y_FORCE_INLINE TIntrusivePtr<T> NewWithDelete(const TDeleter& deleter, As&&... args)
+{
+ using TWrapper = TRefCountedWrapperWithDeleter<T, TDeleter>;
+ void* ptr = NDetail::AllocateConstSizeAligned<sizeof(TWrapper), alignof(TWrapper)>();
+
+ auto* instance = NDetail::NewEpilogue<TWrapper>(
+ ptr,
+ deleter,
+ std::forward<As>(args)...);
+
+ return TIntrusivePtr<T>(instance, false);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, class TTag, int Counter, class... As>
+Y_FORCE_INLINE TIntrusivePtr<T> NewWithLocation(
+ const TSourceLocation& location,
+ As&&... args)
+{
+ using TWrapper = TRefCountedWrapperWithCookie<T>;
+ void* ptr = NDetail::AllocateConstSizeAligned<sizeof(TWrapper), alignof(TWrapper)>();
+
+ auto* instance = NDetail::NewEpilogue<TWrapper>(ptr, std::forward<As>(args)...);
+
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ instance->InitializeTracking(GetRefCountedTypeCookieWithLocation<T, TTag, Counter>(location));
+#else
+ Y_UNUSED(location);
+#endif
+
+ return TIntrusivePtr<T>(instance, false);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+const void* TWithExtraSpace<T>::GetExtraSpacePtr() const
+{
+ return static_cast<const T*>(this) + 1;
+}
+
+template <class T>
+void* TWithExtraSpace<T>::GetExtraSpacePtr()
+{
+ return static_cast<T*>(this) + 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/memory/new.h b/library/cpp/yt/memory/new.h
new file mode 100644
index 0000000000..2db45e0465
--- /dev/null
+++ b/library/cpp/yt/memory/new.h
@@ -0,0 +1,127 @@
+#pragma once
+
+#include "intrusive_ptr.h"
+#include "ref_tracked.h"
+
+#include <library/cpp/yt/misc/source_location.h>
+
+#include <util/system/defaults.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+/*!
+ * \defgroup yt_new New<T> safe smart pointer constructors
+ * \ingroup yt_new
+ *
+ * This is collection of safe smart pointer constructors.
+ *
+ * \page yt_new_rationale Rationale
+ * New<T> function family was designed to prevent the following problem.
+ * Consider the following piece of code.
+ *
+ * \code
+ * class TFoo
+ * : public virtual TRefCounted
+ * {
+ * public:
+ * TFoo();
+ * };
+ *
+ * typedef TIntrusivePtr<TFoo> TFooPtr;
+ *
+ * void RegisterObject(TFooPtr foo)
+ * {
+ * ...
+ * }
+ *
+ * TFoo::TFoo()
+ * {
+ * // ... do something before
+ * RegisterObject(this);
+ * // ... do something after
+ * }
+ * \endcode
+ *
+ * What will happen on <tt>new TFoo()</tt> construction? After memory allocation
+ * the reference counter for newly created instance would be initialized to zero.
+ * Afterwards, the control goes to TFoo constructor. To invoke
+ * <tt>RegisterObject</tt> a new temporary smart pointer to the current instance
+ * have to be created effectively incrementing the reference counter (now one).
+ * After <tt>RegisterObject</tt> returns the control to the constructor
+ * the temporary pointer is destroyed effectively decrementing the reference
+ * counter to zero hence triggering object destruction during its initialization.
+ *
+ * To avoid this undefined behavior <tt>New<T></tt> was introduced.
+ * <tt>New<T></tt> holds a fake
+ * reference to the object during its construction effectively preventing
+ * premature destruction.
+ *
+ * \note An initialization like <tt>TIntrusivePtr&lt;T&gt; p = new T()</tt>
+ * would result in a dangling reference due to internals of #New<T> and
+ * #TRefCountedBase.
+ */
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, class = void>
+struct THasAllocator
+{
+ using TFalse = void;
+};
+
+template <class T>
+struct THasAllocator<T, std::void_t<typename T::TAllocator>>
+{
+ using TTrue = void;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Allocates a new instance of |T|.
+template <class T, class... As, class = typename THasAllocator<T>::TFalse>
+TIntrusivePtr<T> New(As&&... args);
+
+template <class T, class... As, class = typename THasAllocator<T>::TTrue>
+TIntrusivePtr<T> New(typename T::TAllocator* allocator, As&&... args);
+
+//! Allocates an instance of |T| with additional storage of #extraSpaceSize bytes.
+template <class T, class... As, class = typename THasAllocator<T>::TFalse>
+TIntrusivePtr<T> NewWithExtraSpace(size_t extraSpaceSize, As&&... args);
+
+template <class T, class... As, class = typename THasAllocator<T>::TTrue>
+TIntrusivePtr<T> NewWithExtraSpace(typename T::TAllocator* allocator, size_t extraSpaceSize, As&&... args);
+
+//! Allocates a new instance of |T| with user deleter.
+template <class T, class TDeleter, class... As>
+TIntrusivePtr<T> NewWithDelete(const TDeleter& deleter, As&&... args);
+
+//! Allocates a new instance of |T|.
+//! The allocation is additionally marked with #location.
+template <class T, class TTag, int Counter, class... As>
+TIntrusivePtr<T> NewWithLocation(const TSourceLocation& location, As&&... args);
+
+//! Enables calling #New and co for types with private ctors.
+#define DECLARE_NEW_FRIEND() \
+ template <class DECLARE_NEW_FRIEND_T> \
+ friend struct NYT::TRefCountedWrapper;
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! CRTP mixin enabling access to instance's extra space.
+template <class T>
+class TWithExtraSpace
+{
+protected:
+ const void* GetExtraSpacePtr() const;
+ void* GetExtraSpacePtr();
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define NEW_INL_H_
+#include "new-inl.h"
+#undef NEW_INL_H_
diff --git a/library/cpp/yt/memory/range.h b/library/cpp/yt/memory/range.h
new file mode 100644
index 0000000000..6c71aa9496
--- /dev/null
+++ b/library/cpp/yt/memory/range.h
@@ -0,0 +1,556 @@
+#pragma once
+
+#include <library/cpp/yt/assert/assert.h>
+
+#include <library/cpp/yt/misc/hash.h>
+
+#include <vector>
+#include <array>
+#include <optional>
+#include <initializer_list>
+
+// For size_t.
+#include <stddef.h>
+
+namespace google::protobuf {
+
+////////////////////////////////////////////////////////////////////////////////
+// Forward declarations
+
+template <class T>
+class RepeatedField;
+
+template <class T>
+class RepeatedPtrField;
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace google::protobuf
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+// Forward declarations
+
+template <class T, size_t N>
+class TCompactVector;
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! TRange (inspired by TArrayRef from LLVM)
+/*!
+ * Represents a constant reference to an array (zero or more elements
+ * consecutively in memory), i. e. a start pointer and a length. It allows
+ * various APIs to take consecutive elements easily and conveniently.
+ *
+ * This class does not own the underlying data, it is expected to be used in
+ * situations where the data resides in some other buffer, whose lifetime
+ * extends past that of the TRange. For this reason, it is not in general
+ * safe to store an TRange.
+ *
+ * This is intended to be trivially copyable, so it should be passed by
+ * value.
+ */
+template <class T>
+class TRange
+{
+public:
+ typedef const T* iterator;
+ typedef const T* const_iterator;
+ typedef size_t size_type;
+
+ //! Constructs a null TRange.
+ TRange()
+ : Data_(nullptr)
+ , Length_(0)
+ { }
+
+ //! Constructs a TRange from a pointer and length.
+ TRange(const T* data, size_t length)
+ : Data_(data)
+ , Length_(length)
+ { }
+
+ //! Constructs a TRange from a range.
+ TRange(const T* begin, const T* end)
+ : Data_(begin)
+ , Length_(end - begin)
+ { }
+
+ //! Constructs a TRange from a TCompactVector.
+ template <size_t N>
+ TRange(const TCompactVector<T, N>& elements)
+ : Data_(elements.data())
+ , Length_(elements.size())
+ { }
+
+ //! Constructs a TRange from an std::vector.
+ template <class A>
+ TRange(const std::vector<T, A>& elements)
+ : Data_(elements.empty() ? nullptr : elements.data())
+ , Length_(elements.size())
+ { }
+
+ //! Constructs a TRange from a C array.
+ template <size_t N>
+ TRange(const T (&elements)[N])
+ : Data_(elements)
+ , Length_(N)
+ { }
+
+ //! Constructs a TRange from std::initializer_list.
+ TRange(std::initializer_list<T> elements)
+ : Data_(elements.begin())
+ , Length_(elements.size())
+ { }
+
+ //! Constructs a TRange from std::array.
+ template <size_t N>
+ TRange(const std::array<T, N>& elements)
+ : Data_(elements.data())
+ , Length_(N)
+ { }
+
+ //! Constructs a TRange from std::optional.
+ //! Range will contain 0-1 elements.
+ explicit TRange(const std::optional<T>& element)
+ : Data_(element ? &*element : nullptr)
+ , Length_(element ? 1 : 0)
+ { }
+
+ const_iterator Begin() const
+ {
+ return Data_;
+ }
+
+ // STL interop, for gcc.
+ const_iterator begin() const
+ {
+ return Begin();
+ }
+
+ const_iterator End() const
+ {
+ return Data_ + Length_;
+ }
+
+ // STL interop, for gcc.
+ const_iterator end() const
+ {
+ return End();
+ }
+
+ bool Empty() const
+ {
+ return Length_ == 0;
+ }
+
+ bool empty() const
+ {
+ return Empty();
+ }
+
+ explicit operator bool() const
+ {
+ return Data_ != nullptr;
+ }
+
+ size_t Size() const
+ {
+ return Length_;
+ }
+
+ size_t size() const
+ {
+ return Size();
+ }
+
+ const T& operator[](size_t index) const
+ {
+ YT_ASSERT(index < Size());
+ return Data_[index];
+ }
+
+
+ const T& Front() const
+ {
+ YT_ASSERT(Length_ > 0);
+ return Data_[0];
+ }
+
+ const T& Back() const
+ {
+ YT_ASSERT(Length_ > 0);
+ return Data_[Length_ - 1];
+ }
+
+
+ TRange<T> Slice(size_t startOffset, size_t endOffset) const
+ {
+ YT_ASSERT(startOffset <= endOffset && endOffset <= Size());
+ return TRange<T>(Begin() + startOffset, endOffset - startOffset);
+ }
+
+ std::vector<T> ToVector() const
+ {
+ return std::vector<T>(Data_, Data_ + Length_);
+ }
+
+protected:
+ //! The start of the array, in an external buffer.
+ const T* Data_;
+
+ //! The number of elements.
+ size_t Length_;
+
+};
+
+// STL interop.
+template <class T>
+typename TRange<T>::const_iterator begin(TRange<T> ref)
+{
+ return ref.Begin();
+}
+
+template <class T>
+typename TRange<T>::const_iterator end(TRange<T> ref)
+{
+ return ref.End();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Constructs a TRange from a pointer and length.
+template <class T>
+TRange<T> MakeRange(const T* data, size_t length)
+{
+ return TRange<T>(data, length);
+}
+
+//! Constructs a TRange from a native range.
+template <class T>
+TRange<T> MakeRange(const T* begin, const T* end)
+{
+ return TRange<T>(begin, end);
+}
+
+//! Constructs a TRange from a TCompactVector.
+template <class T, size_t N>
+TRange<T> MakeRange(const TCompactVector<T, N>& elements)
+{
+ return elements;
+}
+
+//! "Copy-constructor".
+template <class T>
+TRange<T> MakeRange(TRange<T> range)
+{
+ return range;
+}
+
+//! Constructs a TRange from an std::vector.
+template <class T>
+TRange<T> MakeRange(const std::vector<T>& elements)
+{
+ return elements;
+}
+
+//! Constructs a TRange from an std::array.
+template <class T, size_t N>
+TRange<T> MakeRange(const std::array<T, N>& elements)
+{
+ return elements;
+}
+
+//! Constructs a TRange from a C array.
+template <class T, size_t N>
+TRange<T> MakeRange(const T (& elements)[N])
+{
+ return TRange<T>(elements);
+}
+
+//! Constructs a TRange from RepeatedField.
+template <class T>
+TRange<T> MakeRange(const google::protobuf::RepeatedField<T>& elements)
+{
+ return TRange<T>(elements.data(), elements.size());
+}
+
+//! Constructs a TRange from RepeatedPtrField.
+template <class T>
+TRange<const T*> MakeRange(const google::protobuf::RepeatedPtrField<T>& elements)
+{
+ return TRange<const T*>(elements.data(), elements.size());
+}
+
+template <class U, class T>
+TRange<U> ReinterpretCastRange(TRange<T> range)
+{
+ static_assert(sizeof(T) == sizeof(U), "T and U must have equal sizes.");
+ return TRange<U>(reinterpret_cast<const U*>(range.Begin()), range.Size());
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+// TMutableRange (inspired by TMutableArrayRef from LLVM)
+/*
+ * Represents a mutable reference to an array (zero or more elements
+ * consecutively in memory), i. e. a start pointer and a length.
+ * It allows various APIs to take and modify consecutive elements easily and
+ * conveniently.
+ *
+ * This class does not own the underlying data, it is expected to be used in
+ * situations where the data resides in some other buffer, whose lifetime
+ * extends past that of the TMutableRange. For this reason, it is not in
+ * general safe to store a TMutableRange.
+ *
+ * This is intended to be trivially copyable, so it should be passed by value.
+ */
+template <class T>
+class TMutableRange
+ : public TRange<T>
+{
+public:
+ typedef T* iterator;
+
+ //! Constructs a null TMutableRange.
+ TMutableRange()
+ { }
+
+ //! Constructs a TMutableRange from a pointer and length.
+ TMutableRange(T* data, size_t length)
+ : TRange<T>(data, length)
+ { }
+
+ //! Constructs a TMutableRange from a range.
+ TMutableRange(T* begin, T* end)
+ : TRange<T>(begin, end)
+ { }
+
+ //! Constructs a TMutableRange from a TCompactVector.
+ template <size_t N>
+ TMutableRange(TCompactVector<T, N>& elements)
+ : TRange<T>(elements)
+ { }
+
+ //! Constructs a TMutableRange from an std::vector.
+ TMutableRange(std::vector<T>& elements)
+ : TRange<T>(elements)
+ { }
+
+ //! Constructs a TMutableRange from std::array.
+ template <size_t N>
+ TMutableRange(std::array<T, N>& elements)
+ : TRange<T>(elements.data(), N)
+ { }
+
+ //! Construct a TMutableRange from an std::optional
+ //! Range will contain 0-1 elements.
+ explicit TMutableRange(std::optional<T>& optional)
+ : TRange<T>(optional)
+ { }
+
+ //! Constructs a TMutableRange from a C array.
+ template <size_t N>
+ TMutableRange(T (& elements)[N])
+ : TRange<T>(elements)
+ { }
+
+ using TRange<T>::Begin;
+ using TRange<T>::End;
+ using TRange<T>::Front;
+ using TRange<T>::Back;
+ using TRange<T>::operator[];
+
+ iterator Begin() const
+ {
+ return const_cast<T*>(this->Data_);
+ }
+
+ // STL interop, for gcc.
+ iterator begin() const
+ {
+ return Begin();
+ }
+
+ iterator End() const
+ {
+ return this->Begin() + this->Size();
+ }
+
+ // STL interop, for gcc.
+ iterator end() const
+ {
+ return End();
+ }
+
+ T& operator[](size_t index)
+ {
+ YT_ASSERT(index <= this->Size());
+ return Begin()[index];
+ }
+
+ T& Front()
+ {
+ YT_ASSERT(this->Length_ > 0);
+ return Begin()[0];
+ }
+
+ T& Back()
+ {
+ YT_ASSERT(this->Length_ > 0);
+ return Begin()[this->Length_ - 1];
+ }
+
+ TMutableRange<T> Slice(size_t startOffset, size_t endOffset) const
+ {
+ YT_ASSERT(startOffset <= endOffset && endOffset <= this->Size());
+ return TMutableRange<T>(Begin() + startOffset, endOffset - startOffset);
+ }
+
+ TMutableRange<T> Slice(T* begin, T* end) const
+ {
+ YT_ASSERT(begin >= Begin());
+ YT_ASSERT(end <= End());
+ return TMutableRange<T>(begin, end);
+ }
+};
+
+// STL interop.
+template <class T>
+typename TMutableRange<T>::iterator begin(TMutableRange<T> ref)
+{
+ return ref.Begin();
+}
+
+template <class T>
+typename TMutableRange<T>::iterator end(TMutableRange<T> ref)
+{
+ return ref.End();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Constructs a TMutableRange from a pointer and length.
+template <class T>
+TMutableRange<T> MakeMutableRange(T* data, size_t length)
+{
+ return TMutableRange<T>(data, length);
+}
+
+//! Constructs a TMutableRange from a native range.
+template <class T>
+TMutableRange<T> MakeMutableRange(T* begin, T* end)
+{
+ return TMutableRange<T>(begin, end);
+}
+
+//! Constructs a TMutableRange from a TCompactVector.
+template <class T, size_t N>
+TMutableRange<T> MakeMutableRange(TCompactVector<T, N>& elements)
+{
+ return elements;
+}
+
+//! "Copy-constructor".
+template <class T>
+TMutableRange<T> MakeMutableRange(TMutableRange<T> range)
+{
+ return range;
+}
+
+//! Constructs a TMutableRange from an std::vector.
+template <class T>
+TMutableRange<T> MakeMutableRange(std::vector<T>& elements)
+{
+ return elements;
+}
+
+//! Constructs a TMutableRange from an std::array.
+template <class T, size_t N>
+TMutableRange<T> MakeMutableRange(std::array<T, N>& elements)
+{
+ return elements;
+}
+
+//! Constructs a TMutableRange from a C array.
+template <class T, size_t N>
+TMutableRange<T> MakeMutableRange(T (& elements)[N])
+{
+ return TMutableRange<T>(elements);
+}
+
+//! Constructs a TMutableRange from RepeatedField.
+template <class T>
+TMutableRange<T> MakeMutableRange(google::protobuf::RepeatedField<T>& elements)
+{
+ return TMutableRange<T>(elements.data(), elements.size());
+}
+
+//! Constructs a TMutableRange from RepeatedPtrField.
+template <class T>
+TMutableRange<T*> MakeMutableRange(google::protobuf::RepeatedPtrField<T>& elements)
+{
+ return TMutableRange<const T*>(elements.data(), elements.size());
+}
+
+template <class U, class T>
+TMutableRange<U> ReinterpretCastMutableRange(TMutableRange<T> range)
+{
+ static_assert(sizeof(T) == sizeof(U), "T and U must have equal sizes.");
+ return TMutableRange<U>(reinterpret_cast<U*>(range.Begin()), range.Size());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Mark TMutableRange and TMutableRange as PODs.
+namespace NMpl {
+
+template <class T>
+struct TIsPod;
+
+template <class T>
+struct TIsPod<TRange<T>>
+{
+ static const bool Value = true;
+};
+
+template <class T>
+struct TIsPod<TMutableRange<T>>
+{
+ static const bool Value = true;
+};
+
+} // namespace NMpl
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+template <class T>
+struct hash<NYT::TRange<T>>
+{
+ size_t operator()(const NYT::TRange<T>& range) const
+ {
+ size_t result = 0;
+ for (const auto& element : range) {
+ NYT::HashCombine(result, element);
+ }
+ return result;
+ }
+};
+
+template <class T>
+struct hash<NYT::TMutableRange<T>>
+{
+ size_t operator()(const NYT::TMutableRange<T>& range) const
+ {
+ size_t result = 0;
+ for (const auto& element : range) {
+ NYT::HashCombine(result, element);
+ }
+ return result;
+ }
+};
+
+
diff --git a/library/cpp/yt/memory/ref-inl.h b/library/cpp/yt/memory/ref-inl.h
new file mode 100644
index 0000000000..79be8356c5
--- /dev/null
+++ b/library/cpp/yt/memory/ref-inl.h
@@ -0,0 +1,517 @@
+#ifndef REF_INL_H_
+#error "Direct inclusion of this file is not allowed, include ref.h"
+// For the sake of sane code completion.
+#include "ref.h"
+#endif
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace NDetail {
+
+extern const char EmptyRefData[];
+extern char MutableEmptyRefData[];
+
+} // namespace NDetail
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_FORCE_INLINE TRef::TRef(const void* data, size_t size)
+ : TRange<char>(static_cast<const char*>(data), size)
+{ }
+
+Y_FORCE_INLINE TRef::TRef(const void* begin, const void* end)
+ : TRange<char>(static_cast<const char*>(begin), static_cast<const char*>(end))
+{ }
+
+Y_FORCE_INLINE TRef TRef::MakeEmpty()
+{
+ return TRef(NDetail::EmptyRefData, NDetail::EmptyRefData);
+}
+
+Y_FORCE_INLINE TRef TRef::FromString(const TString& str)
+{
+ return FromStringBuf(str);
+}
+
+Y_FORCE_INLINE TRef TRef::FromStringBuf(TStringBuf strBuf)
+{
+ return TRef(strBuf.data(), strBuf.length());
+}
+
+template <class T>
+Y_FORCE_INLINE TRef TRef::FromPod(const T& data)
+{
+ static_assert(TTypeTraits<T>::IsPod || std::is_pod<T>::value, "T must be a pod-type.");
+ return TRef(&data, sizeof (data));
+}
+
+Y_FORCE_INLINE TRef TRef::Slice(size_t startOffset, size_t endOffset) const
+{
+ YT_ASSERT(endOffset >= startOffset && endOffset <= Size());
+ return TRef(Begin() + startOffset, endOffset - startOffset);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_FORCE_INLINE TMutableRef::TMutableRef(void* data, size_t size)
+ : TMutableRange<char>(static_cast<char*>(data), size)
+{ }
+
+Y_FORCE_INLINE TMutableRef::TMutableRef(void* begin, void* end)
+ : TMutableRange<char>(static_cast<char*>(begin), static_cast<char*>(end))
+{ }
+
+Y_FORCE_INLINE TMutableRef TMutableRef::MakeEmpty()
+{
+ return TMutableRef(NDetail::MutableEmptyRefData, NDetail::MutableEmptyRefData);
+}
+
+Y_FORCE_INLINE TMutableRef::operator TRef() const
+{
+ return TRef(Begin(), Size());
+}
+
+template <class T>
+Y_FORCE_INLINE TMutableRef TMutableRef::FromPod(T& data)
+{
+ static_assert(TTypeTraits<T>::IsPod || std::is_pod<T>::value, "T must be a pod-type.");
+ return TMutableRef(&data, sizeof (data));
+}
+
+Y_FORCE_INLINE TMutableRef TMutableRef::FromString(TString& str)
+{
+ // NB: begin() invokes CloneIfShared().
+ return TMutableRef(str.begin(), str.length());
+}
+
+Y_FORCE_INLINE TMutableRef TMutableRef::Slice(size_t startOffset, size_t endOffset) const
+{
+ YT_ASSERT(endOffset >= startOffset && endOffset <= Size());
+ return TMutableRef(Begin() + startOffset, endOffset - startOffset);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_FORCE_INLINE TSharedRef::TSharedRef(TRef ref, TSharedRange<char>::THolderPtr holder)
+ : TSharedRange<char>(ref, std::move(holder))
+{ }
+
+Y_FORCE_INLINE TSharedRef::TSharedRef(const void* data, size_t length, TSharedRange<char>::THolderPtr holder)
+ : TSharedRange<char>(static_cast<const char*>(data), length, std::move(holder))
+{ }
+
+Y_FORCE_INLINE TSharedRef::TSharedRef(const void* begin, const void* end, TSharedRange<char>::THolderPtr holder)
+ : TSharedRange<char>(static_cast<const char*>(begin), static_cast<const char*>(end), std::move(holder))
+{ }
+
+Y_FORCE_INLINE TSharedRef TSharedRef::MakeEmpty()
+{
+ return TSharedRef(TRef::MakeEmpty(), nullptr);
+}
+
+Y_FORCE_INLINE TSharedRef::operator TRef() const
+{
+ return TRef(Begin(), Size());
+}
+
+template <class TTag>
+Y_FORCE_INLINE TSharedRef TSharedRef::FromString(TString str)
+{
+ return FromString(std::move(str), GetRefCountedTypeCookie<TTag>());
+}
+
+Y_FORCE_INLINE TSharedRef TSharedRef::FromString(TString str)
+{
+ return FromString<TDefaultSharedBlobTag>(std::move(str));
+}
+
+template <class TTag>
+Y_FORCE_INLINE TSharedRef TSharedRef::MakeCopy(TRef ref)
+{
+ return MakeCopy(ref, GetRefCountedTypeCookie<TTag>());
+}
+
+Y_FORCE_INLINE TSharedRef TSharedRef::Slice(size_t startOffset, size_t endOffset) const
+{
+ YT_ASSERT(endOffset >= startOffset && endOffset <= Size());
+ return TSharedRef(Begin() + startOffset, endOffset - startOffset, Holder_);
+}
+
+Y_FORCE_INLINE TSharedRef TSharedRef::Slice(const void* begin, const void* end) const
+{
+ YT_ASSERT(begin >= Begin());
+ YT_ASSERT(end <= End());
+ return TSharedRef(begin, end, Holder_);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_FORCE_INLINE TSharedMutableRef::TSharedMutableRef(const TMutableRef& ref, TSharedMutableRange<char>::THolderPtr holder)
+ : TSharedMutableRange<char>(ref, std::move(holder))
+{ }
+
+Y_FORCE_INLINE TSharedMutableRef::TSharedMutableRef(void* data, size_t length, TSharedMutableRange<char>::THolderPtr holder)
+ : TSharedMutableRange<char>(static_cast<char*>(data), length, std::move(holder))
+{ }
+
+Y_FORCE_INLINE TSharedMutableRef::TSharedMutableRef(void* begin, void* end, TSharedMutableRange<char>::THolderPtr holder)
+ : TSharedMutableRange<char>(static_cast<char*>(begin), static_cast<char*>(end), std::move(holder))
+{ }
+
+Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::MakeEmpty()
+{
+ return TSharedMutableRef(TMutableRef::MakeEmpty(), nullptr);
+}
+
+Y_FORCE_INLINE TSharedMutableRef::operator TMutableRef() const
+{
+ return TMutableRef(Begin(), Size());
+}
+
+Y_FORCE_INLINE TSharedMutableRef::operator TSharedRef() const
+{
+ return TSharedRef(Begin(), Size(), Holder_);
+}
+
+Y_FORCE_INLINE TSharedMutableRef::operator TRef() const
+{
+ return TRef(Begin(), Size());
+}
+
+Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::Allocate(size_t size, bool initializeStorage)
+{
+ return Allocate<TDefaultSharedBlobTag>(size, initializeStorage);
+}
+
+Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::AllocatePageAligned(size_t size, bool initializeStorage)
+{
+ return AllocatePageAligned<TDefaultSharedBlobTag>(size, initializeStorage);
+}
+
+template <class TTag>
+Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::MakeCopy(TRef ref)
+{
+ return MakeCopy(ref, GetRefCountedTypeCookie<TTag>());
+}
+
+Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::Slice(size_t startOffset, size_t endOffset) const
+{
+ YT_ASSERT(endOffset >= startOffset && endOffset <= Size());
+ return TSharedMutableRef(Begin() + startOffset, endOffset - startOffset, Holder_);
+}
+
+Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::Slice(void* begin, void* end) const
+{
+ YT_ASSERT(begin >= Begin());
+ YT_ASSERT(end <= End());
+ return TSharedMutableRef(begin, end, Holder_);
+}
+
+template <class TTag>
+Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::Allocate(size_t size, bool initializeStorage)
+{
+ return Allocate(size, initializeStorage, GetRefCountedTypeCookie<TTag>());
+}
+
+template <class TTag>
+Y_FORCE_INLINE TSharedMutableRef TSharedMutableRef::AllocatePageAligned(size_t size, bool initializeStorage)
+{
+ return AllocatePageAligned(size, initializeStorage, GetRefCountedTypeCookie<TTag>());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_FORCE_INLINE size_t GetByteSize(TRef ref)
+{
+ return ref ? ref.Size() : 0;
+}
+
+template <class T>
+size_t GetByteSize(TRange<T> parts)
+{
+ size_t size = 0;
+ for (const auto& part : parts) {
+ size += part.Size();
+ }
+ return size;
+}
+
+template <class T>
+size_t GetByteSize(const std::vector<T>& parts)
+{
+ return GetByteSize(MakeRange(parts));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TSharedRefArrayImpl
+ : public TRefCounted
+ , public TWithExtraSpace<TSharedRefArrayImpl>
+{
+public:
+ TSharedRefArrayImpl(
+ size_t extraSpaceSize,
+ TRefCountedTypeCookie tagCookie,
+ size_t size)
+ : Size_(size)
+ , ExtraSpaceSize_(extraSpaceSize)
+ , TagCookie_(tagCookie)
+ {
+ for (size_t index = 0; index < Size_; ++index) {
+ new (MutableBegin() + index) TSharedRef();
+ }
+ RegisterWithRefCountedTracker();
+ }
+
+ TSharedRefArrayImpl(
+ size_t extraSpaceSize,
+ TRefCountedTypeCookie tagCookie,
+ const TSharedRef& part)
+ : Size_(1)
+ , ExtraSpaceSize_(extraSpaceSize)
+ , TagCookie_(tagCookie)
+ {
+ new (MutableBegin()) TSharedRef(part);
+ RegisterWithRefCountedTracker();
+ }
+
+ TSharedRefArrayImpl(
+ size_t extraSpaceSize,
+ TRefCountedTypeCookie tagCookie,
+ TSharedRef&& part)
+ : Size_(1)
+ , ExtraSpaceSize_(extraSpaceSize)
+ , TagCookie_(tagCookie)
+ {
+ new (MutableBegin()) TSharedRef(std::move(part));
+ RegisterWithRefCountedTracker();
+ }
+
+ template <class TParts>
+ TSharedRefArrayImpl(
+ size_t extraSpaceSize,
+ TRefCountedTypeCookie tagCookie,
+ const TParts& parts,
+ TSharedRefArray::TCopyParts)
+ : Size_(parts.size())
+ , ExtraSpaceSize_(extraSpaceSize)
+ , TagCookie_(tagCookie)
+ {
+ for (size_t index = 0; index < Size_; ++index) {
+ new (MutableBegin() + index) TSharedRef(parts[index]);
+ }
+ RegisterWithRefCountedTracker();
+ }
+
+ template <class TParts>
+ TSharedRefArrayImpl(
+ size_t extraSpaceSize,
+ TRefCountedTypeCookie tagCookie,
+ TParts&& parts,
+ TSharedRefArray::TMoveParts)
+ : Size_(parts.size())
+ , ExtraSpaceSize_(extraSpaceSize)
+ , TagCookie_(tagCookie)
+ {
+ for (size_t index = 0; index < Size_; ++index) {
+ new (MutableBegin() + index) TSharedRef(std::move(parts[index]));
+ }
+ RegisterWithRefCountedTracker();
+ }
+
+ ~TSharedRefArrayImpl()
+ {
+ for (size_t index = 0; index < Size_; ++index) {
+ auto& part = MutableBegin()[index];
+ if (part.GetHolder() == this) {
+ part.Holder_.Release();
+ }
+ part.TSharedRef::~TSharedRef();
+ }
+ UnregisterFromRefCountedTracker();
+ }
+
+
+ size_t Size() const
+ {
+ return Size_;
+ }
+
+ bool Empty() const
+ {
+ return Size_ == 0;
+ }
+
+ const TSharedRef& operator [] (size_t index) const
+ {
+ YT_ASSERT(index < Size());
+ return Begin()[index];
+ }
+
+
+ const TSharedRef* Begin() const
+ {
+ return static_cast<const TSharedRef*>(GetExtraSpacePtr());
+ }
+
+ const TSharedRef* End() const
+ {
+ return Begin() + Size_;
+ }
+
+private:
+ friend class TSharedRefArrayBuilder;
+
+ const size_t Size_;
+ const size_t ExtraSpaceSize_;
+ const TRefCountedTypeCookie TagCookie_;
+
+
+ void RegisterWithRefCountedTracker()
+ {
+ TRefCountedTrackerFacade::AllocateTagInstance(TagCookie_);
+ TRefCountedTrackerFacade::AllocateSpace(TagCookie_, ExtraSpaceSize_);
+ }
+
+ void UnregisterFromRefCountedTracker()
+ {
+ TRefCountedTrackerFacade::FreeTagInstance(TagCookie_);
+ TRefCountedTrackerFacade::FreeSpace(TagCookie_, ExtraSpaceSize_);
+ }
+
+
+ TSharedRef* MutableBegin()
+ {
+ return static_cast<TSharedRef*>(GetExtraSpacePtr());
+ }
+
+ TSharedRef* MutableEnd()
+ {
+ return MutableBegin() + Size_;
+ }
+
+ char* GetBeginAllocationPtr()
+ {
+ return static_cast<char*>(static_cast<void*>(MutableEnd()));
+ }
+};
+
+DEFINE_REFCOUNTED_TYPE(TSharedRefArrayImpl)
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct TSharedRefArrayTag { };
+
+Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(TIntrusivePtr<TSharedRefArrayImpl> impl)
+ : Impl_(std::move(impl))
+{ }
+
+Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(const TSharedRefArray& other)
+ : Impl_(other.Impl_)
+{ }
+
+Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(TSharedRefArray&& other) noexcept
+ : Impl_(std::move(other.Impl_))
+{ }
+
+Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(const TSharedRef& part)
+ : Impl_(NewImpl(1, 0, GetRefCountedTypeCookie<TSharedRefArrayTag>(), part))
+{ }
+
+Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(TSharedRef&& part)
+ : Impl_(NewImpl(1, 0, GetRefCountedTypeCookie<TSharedRefArrayTag>(), std::move(part)))
+{ }
+
+template <class TParts>
+Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(const TParts& parts, TSharedRefArray::TCopyParts)
+ : Impl_(NewImpl(parts.size(), 0, GetRefCountedTypeCookie<TSharedRefArrayTag>(), parts, TSharedRefArray::TCopyParts{}))
+{ }
+
+template <class TParts>
+Y_FORCE_INLINE TSharedRefArray::TSharedRefArray(TParts&& parts, TSharedRefArray::TMoveParts)
+ : Impl_(NewImpl(parts.size(), 0, GetRefCountedTypeCookie<TSharedRefArrayTag>(), std::move(parts), TSharedRefArray::TMoveParts{}))
+{ }
+
+Y_FORCE_INLINE TSharedRefArray& TSharedRefArray::operator=(const TSharedRefArray& other)
+{
+ Impl_ = other.Impl_;
+ return *this;
+}
+
+Y_FORCE_INLINE TSharedRefArray& TSharedRefArray::operator=(TSharedRefArray&& other)
+{
+ Impl_ = std::move(other.Impl_);
+ return *this;
+}
+
+Y_FORCE_INLINE void TSharedRefArray::Reset()
+{
+ Impl_.Reset();
+}
+
+Y_FORCE_INLINE TSharedRefArray::operator bool() const
+{
+ return Impl_.operator bool();
+}
+
+Y_FORCE_INLINE size_t TSharedRefArray::Size() const
+{
+ return Impl_ ? Impl_->Size() : 0;
+}
+
+Y_FORCE_INLINE size_t TSharedRefArray::size() const
+{
+ return Impl_ ? Impl_->Size() : 0;
+}
+
+Y_FORCE_INLINE bool TSharedRefArray::Empty() const
+{
+ return Impl_ ? Impl_->Empty() : true;
+}
+
+Y_FORCE_INLINE const TSharedRef& TSharedRefArray::operator[](size_t index) const
+{
+ YT_ASSERT(Impl_);
+ return (*Impl_)[index];
+}
+
+Y_FORCE_INLINE const TSharedRef* TSharedRefArray::Begin() const
+{
+ return Impl_ ? Impl_->Begin() : nullptr;
+}
+
+Y_FORCE_INLINE const TSharedRef* TSharedRefArray::End() const
+{
+ return Impl_ ? Impl_->End() : nullptr;
+}
+
+template <class... As>
+TSharedRefArrayImplPtr TSharedRefArray::NewImpl(
+ size_t size,
+ size_t poolCapacity,
+ TRefCountedTypeCookie tagCookie,
+ As&&... args)
+{
+ auto extraSpaceSize = sizeof (TSharedRef) * size + poolCapacity;
+ return NewWithExtraSpace<TSharedRefArrayImpl>(
+ extraSpaceSize,
+ extraSpaceSize,
+ tagCookie,
+ std::forward<As>(args)...);
+}
+
+Y_FORCE_INLINE const TSharedRef* begin(const TSharedRefArray& array)
+{
+ return array.Begin();
+}
+
+Y_FORCE_INLINE const TSharedRef* end(const TSharedRefArray& array)
+{
+ return array.End();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/memory/ref.cpp b/library/cpp/yt/memory/ref.cpp
new file mode 100644
index 0000000000..e8ff42e976
--- /dev/null
+++ b/library/cpp/yt/memory/ref.cpp
@@ -0,0 +1,378 @@
+#include "ref.h"
+#include "blob.h"
+
+#include <library/cpp/ytalloc/api/ytalloc.h>
+
+#include <util/system/info.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace NDetail {
+
+// N.B. We would prefer these arrays to be zero sized
+// but zero sized arrays are not supported in MSVC.
+const char EmptyRefData[1] = {0};
+char MutableEmptyRefData[1] = {0};
+
+} // namespace NDetail
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TBlobHolder
+ : public TRefCounted
+{
+public:
+ explicit TBlobHolder(TBlob&& blob)
+ : Blob_(std::move(blob))
+ { }
+
+private:
+ const TBlob Blob_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TStringHolder
+ : public TRefCounted
+{
+public:
+ TStringHolder(TString&& string, TRefCountedTypeCookie cookie)
+ : String_(std::move(string))
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ , Cookie_(cookie)
+#endif
+ {
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TRefCountedTrackerFacade::AllocateTagInstance(Cookie_);
+ TRefCountedTrackerFacade::AllocateSpace(Cookie_, String_.length());
+#endif
+ }
+ ~TStringHolder()
+ {
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TRefCountedTrackerFacade::FreeTagInstance(Cookie_);
+ TRefCountedTrackerFacade::FreeSpace(Cookie_, String_.length());
+#endif
+ }
+
+ const TString& String() const
+ {
+ return String_;
+ }
+
+private:
+ const TString String_;
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ const TRefCountedTypeCookie Cookie_;
+#endif
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TDerived>
+class TAllocationHolderBase
+ : public TRefCounted
+{
+public:
+ TAllocationHolderBase(size_t size, TRefCountedTypeCookie cookie)
+ : Size_(size)
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ , Cookie_(cookie)
+#endif
+ { }
+
+ ~TAllocationHolderBase()
+ {
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TRefCountedTrackerFacade::FreeTagInstance(Cookie_);
+ TRefCountedTrackerFacade::FreeSpace(Cookie_, Size_);
+#endif
+ }
+
+ TMutableRef GetRef()
+ {
+ return TMutableRef(static_cast<TDerived*>(this)->GetBegin(), Size_);
+ }
+
+protected:
+ const size_t Size_;
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ const TRefCountedTypeCookie Cookie_;
+#endif
+
+ void Initialize(bool initializeStorage)
+ {
+ if (initializeStorage) {
+ ::memset(static_cast<TDerived*>(this)->GetBegin(), 0, Size_);
+ }
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TRefCountedTrackerFacade::AllocateTagInstance(Cookie_);
+ TRefCountedTrackerFacade::AllocateSpace(Cookie_, Size_);
+#endif
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TDefaultAllocationHolder
+ : public TAllocationHolderBase<TDefaultAllocationHolder>
+ , public TWithExtraSpace<TDefaultAllocationHolder>
+{
+public:
+ TDefaultAllocationHolder(size_t size, bool initializeStorage, TRefCountedTypeCookie cookie)
+ : TAllocationHolderBase(size, cookie)
+ {
+ Initialize(initializeStorage);
+ }
+
+ char* GetBegin()
+ {
+ return static_cast<char*>(GetExtraSpacePtr());
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TPageAlignedAllocationHolder
+ : public TAllocationHolderBase<TPageAlignedAllocationHolder>
+{
+public:
+ TPageAlignedAllocationHolder(size_t size, bool initializeStorage, TRefCountedTypeCookie cookie)
+ : TAllocationHolderBase(size, cookie)
+ , Begin_(static_cast<char*>(NYTAlloc::AllocatePageAligned(size)))
+ {
+ Initialize(initializeStorage);
+ }
+
+ ~TPageAlignedAllocationHolder()
+ {
+ NYTAlloc::Free(Begin_);
+ }
+
+ char* GetBegin()
+ {
+ return Begin_;
+ }
+
+private:
+ char* const Begin_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+TRef TRef::FromBlob(const TBlob& blob)
+{
+ return TRef(blob.Begin(), blob.Size());
+}
+
+bool TRef::AreBitwiseEqual(TRef lhs, TRef rhs)
+{
+ if (lhs.Size() != rhs.Size()) {
+ return false;
+ }
+ if (lhs.Size() == 0) {
+ return true;
+ }
+ return ::memcmp(lhs.Begin(), rhs.Begin(), lhs.Size()) == 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+TMutableRef TMutableRef::FromBlob(TBlob& blob)
+{
+ return TMutableRef(blob.Begin(), blob.Size());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+TSharedRef TSharedRef::FromString(TString str, TRefCountedTypeCookie tagCookie)
+{
+ auto holder = New<TStringHolder>(std::move(str), tagCookie);
+ auto ref = TRef::FromString(holder->String());
+ return TSharedRef(ref, std::move(holder));
+}
+
+TSharedRef TSharedRef::FromBlob(TBlob&& blob)
+{
+ auto ref = TRef::FromBlob(blob);
+ auto holder = New<TBlobHolder>(std::move(blob));
+ return TSharedRef(ref, std::move(holder));
+}
+
+TSharedRef TSharedRef::MakeCopy(TRef ref, TRefCountedTypeCookie tagCookie)
+{
+ if (!ref) {
+ return {};
+ }
+ if (ref.Empty()) {
+ return TSharedRef::MakeEmpty();
+ }
+ auto result = TSharedMutableRef::Allocate(ref.Size(), false, tagCookie);
+ ::memcpy(result.Begin(), ref.Begin(), ref.Size());
+ return result;
+}
+
+std::vector<TSharedRef> TSharedRef::Split(size_t partSize) const
+{
+ YT_VERIFY(partSize > 0);
+ std::vector<TSharedRef> result;
+ result.reserve(Size() / partSize + 1);
+ auto sliceBegin = Begin();
+ while (sliceBegin < End()) {
+ auto sliceEnd = sliceBegin + partSize;
+ if (sliceEnd < sliceBegin || sliceEnd > End()) {
+ sliceEnd = End();
+ }
+ result.push_back(Slice(sliceBegin, sliceEnd));
+ sliceBegin = sliceEnd;
+ }
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+TSharedMutableRef TSharedMutableRef::Allocate(size_t size, bool initializeStorage, TRefCountedTypeCookie tagCookie)
+{
+ auto holder = NewWithExtraSpace<TDefaultAllocationHolder>(size, size, initializeStorage, tagCookie);
+ auto ref = holder->GetRef();
+ return TSharedMutableRef(ref, std::move(holder));
+}
+
+TSharedMutableRef TSharedMutableRef::AllocatePageAligned(size_t size, bool initializeStorage, TRefCountedTypeCookie tagCookie)
+{
+ auto holder = New<TPageAlignedAllocationHolder>(size, initializeStorage, tagCookie);
+ auto ref = holder->GetRef();
+ return TSharedMutableRef(ref, std::move(holder));
+}
+
+TSharedMutableRef TSharedMutableRef::FromBlob(TBlob&& blob)
+{
+ auto ref = TMutableRef::FromBlob(blob);
+ auto holder = New<TBlobHolder>(std::move(blob));
+ return TSharedMutableRef(ref, std::move(holder));
+}
+
+TSharedMutableRef TSharedMutableRef::MakeCopy(TRef ref, TRefCountedTypeCookie tagCookie)
+{
+ if (!ref) {
+ return {};
+ }
+ if (ref.Empty()) {
+ return TSharedMutableRef::MakeEmpty();
+ }
+ auto result = Allocate(ref.Size(), false, tagCookie);
+ ::memcpy(result.Begin(), ref.Begin(), ref.Size());
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+TString ToString(TRef ref)
+{
+ return TString(ref.Begin(), ref.End());
+}
+
+TString ToString(const TMutableRef& ref)
+{
+ return ToString(TRef(ref));
+}
+
+TString ToString(const TSharedRef& ref)
+{
+ return ToString(TRef(ref));
+}
+
+TString ToString(const TSharedMutableRef& ref)
+{
+ return ToString(TRef(ref));
+}
+
+size_t GetPageSize()
+{
+ static const size_t PageSize = NSystemInfo::GetPageSize();
+ return PageSize;
+}
+
+size_t RoundUpToPage(size_t bytes)
+{
+ static const size_t PageSize = NSystemInfo::GetPageSize();
+ YT_ASSERT((PageSize & (PageSize - 1)) == 0);
+ return (bytes + PageSize - 1) & (~(PageSize - 1));
+}
+
+size_t GetByteSize(const TSharedRefArray& array)
+{
+ size_t size = 0;
+ if (array) {
+ for (const auto& part : array) {
+ size += part.Size();
+ }
+ }
+ return size;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+i64 TSharedRefArray::ByteSize() const
+{
+ i64 result = 0;
+ if (*this) {
+ for (const auto& part : *this) {
+ result += part.Size();
+ }
+ }
+ return result;
+}
+
+std::vector<TSharedRef> TSharedRefArray::ToVector() const
+{
+ if (!Impl_) {
+ return {};
+ }
+
+ return std::vector<TSharedRef>(Begin(), End());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+TSharedRefArrayBuilder::TSharedRefArrayBuilder(
+ size_t size,
+ size_t poolCapacity,
+ TRefCountedTypeCookie tagCookie)
+ : AllocationCapacity_(poolCapacity)
+ , Impl_(TSharedRefArray::NewImpl(
+ size,
+ poolCapacity,
+ tagCookie,
+ size))
+ , CurrentAllocationPtr_(Impl_->GetBeginAllocationPtr())
+{ }
+
+void TSharedRefArrayBuilder::Add(TSharedRef part)
+{
+ YT_ASSERT(CurrentPartIndex_ < Impl_->Size());
+ Impl_->MutableBegin()[CurrentPartIndex_++] = std::move(part);
+}
+
+TMutableRef TSharedRefArrayBuilder::AllocateAndAdd(size_t size)
+{
+ YT_ASSERT(CurrentPartIndex_ < Impl_->Size());
+ YT_ASSERT(CurrentAllocationPtr_ + size <= Impl_->GetBeginAllocationPtr() + AllocationCapacity_);
+ TMutableRef ref(CurrentAllocationPtr_, size);
+ CurrentAllocationPtr_ += size;
+ TRefCountedPtr holder(Impl_.Get(), false);
+ TSharedRef sharedRef(ref, std::move(holder));
+ Add(std::move(sharedRef));
+ return ref;
+}
+
+TSharedRefArray TSharedRefArrayBuilder::Finish()
+{
+ return TSharedRefArray(std::move(Impl_));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/memory/ref.h b/library/cpp/yt/memory/ref.h
new file mode 100644
index 0000000000..73d19d9013
--- /dev/null
+++ b/library/cpp/yt/memory/ref.h
@@ -0,0 +1,384 @@
+#pragma once
+
+#include "new.h"
+#include "range.h"
+#include "shared_range.h"
+
+#include <type_traits>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Forward declaration.
+class TBlob;
+
+//! A non-owning reference to a range of memory.
+class TRef
+ : public TRange<char>
+{
+public:
+ //! Creates a null TRef.
+ TRef() = default;
+
+ //! Creates a TRef for a given block of memory.
+ TRef(const void* data, size_t size);
+
+ //! Creates a TRef for a given range of memory.
+ TRef(const void* begin, const void* end);
+
+ //! Creates an empty TRef.
+ static TRef MakeEmpty();
+
+ //! Creates a non-owning TRef for a given blob.
+ static TRef FromBlob(const TBlob& blob);
+
+ //! Creates a non-owning TRef for a given string.
+ static TRef FromString(const TString& str);
+
+ //! Creates a non-owning TRef for a given stringbuf.
+ static TRef FromStringBuf(TStringBuf strBuf);
+
+ //! Creates a non-owning TRef for a given pod structure.
+ template <class T>
+ static TRef FromPod(const T& data);
+
+ //! Creates a TRef for a part of existing range.
+ TRef Slice(size_t startOffset, size_t endOffset) const;
+
+ //! Compares the content for bitwise equality.
+ static bool AreBitwiseEqual(TRef lhs, TRef rhs);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! A non-owning reference to a mutable range of memory.
+//! Use with caution :)
+class TMutableRef
+ : public TMutableRange<char>
+{
+public:
+ //! Creates a null TMutableRef.
+ //! Note empty TMutableRef is not the same as null TMutableRef.
+ //! `operator bool` can be used to check if ref is nonnull.
+ TMutableRef() = default;
+
+ //! Creates a TMutableRef for a given block of memory.
+ TMutableRef(void* data, size_t size);
+
+ //! Creates a TMutableRef for a given range of memory.
+ TMutableRef(void* begin, void* end);
+
+ //! Creates an empty TMutableRef.
+ static TMutableRef MakeEmpty();
+
+ //! Converts a TMutableRef to TRef.
+ operator TRef() const;
+
+ //! Creates a non-owning TMutableRef for a given blob.
+ static TMutableRef FromBlob(TBlob& blob);
+
+ //! Creates a non-owning TMutableRef for a given pod structure.
+ template <class T>
+ static TMutableRef FromPod(T& data);
+
+ //! Creates a non-owning TMutableRef for a given string.
+ //! Ensures that the string is not shared.
+ static TMutableRef FromString(TString& str);
+
+ //! Creates a TMutableRef for a part of existing range.
+ TMutableRef Slice(size_t startOffset, size_t endOffset) const;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Default tag type for memory blocks allocated via TSharedRef.
+/*!
+ * Each newly allocated TSharedRef blob is associated with a tag type
+ * that appears in ref-counted statistics.
+ */
+struct TDefaultSharedBlobTag { };
+
+//! A reference to a range of memory with shared ownership.
+class TSharedRef
+ : public TSharedRange<char>
+{
+public:
+ //! Creates a null TSharedRef.
+ TSharedRef() = default;
+
+ //! Creates a TSharedRef with a given holder.
+ TSharedRef(TRef ref, THolderPtr holder);
+
+ //! Creates a TSharedRef from a pointer and length.
+ TSharedRef(const void* data, size_t length, THolderPtr holder);
+
+ //! Creates a TSharedRef from a range.
+ TSharedRef(const void* begin, const void* end, THolderPtr holder);
+
+ //! Creates an empty TSharedRef.
+ static TSharedRef MakeEmpty();
+
+ //! Converts a TSharedRef to TRef.
+ operator TRef() const;
+
+
+ //! Creates a TSharedRef from a string.
+ //! Since strings are ref-counted, no data is copied.
+ //! The memory is marked with a given tag.
+ template <class TTag>
+ static TSharedRef FromString(TString str);
+
+ //! Creates a TSharedRef from a string.
+ //! Since strings are ref-counted, no data is copied.
+ //! The memory is marked with TDefaultSharedBlobTag.
+ static TSharedRef FromString(TString str);
+
+ //! Creates a TSharedRef reference from a string.
+ //! Since strings are ref-counted, no data is copied.
+ //! The memory is marked with a given tag.
+ static TSharedRef FromString(TString str, TRefCountedTypeCookie tagCookie);
+
+ //! Creates a TSharedRef for a given blob taking ownership of its content.
+ static TSharedRef FromBlob(TBlob&& blob);
+
+ //! Creates a copy of a given TRef.
+ //! The memory is marked with a given tag.
+ static TSharedRef MakeCopy(TRef ref, TRefCountedTypeCookie tagCookie);
+
+ //! Creates a copy of a given TRef.
+ //! The memory is marked with a given tag.
+ template <class TTag>
+ static TSharedRef MakeCopy(TRef ref);
+
+ //! Creates a TSharedRef for a part of existing range.
+ TSharedRef Slice(size_t startOffset, size_t endOffset) const;
+
+ //! Creates a TSharedRef for a part of existing range.
+ TSharedRef Slice(const void* begin, const void* end) const;
+
+ //! Creates a vector of slices with specified size.
+ std::vector<TSharedRef> Split(size_t partSize) const;
+
+private:
+ friend class TSharedRefArrayImpl;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! A reference to a mutable range of memory with shared ownership.
+//! Use with caution :)
+class TSharedMutableRef
+ : public TSharedMutableRange<char>
+{
+public:
+ //! Creates a null TSharedMutableRef.
+ TSharedMutableRef() = default;
+
+ //! Creates a TSharedMutableRef with a given holder.
+ TSharedMutableRef(const TMutableRef& ref, THolderPtr holder);
+
+ //! Creates a TSharedMutableRef from a pointer and length.
+ TSharedMutableRef(void* data, size_t length, THolderPtr holder);
+
+ //! Creates a TSharedMutableRef from a range.
+ TSharedMutableRef(void* begin, void* end, THolderPtr holder);
+
+ //! Creates an empty TSharedMutableRef.
+ static TSharedMutableRef MakeEmpty();
+
+ //! Converts a TSharedMutableRef to TMutableRef.
+ operator TMutableRef() const;
+
+ //! Converts a TSharedMutableRef to TSharedRef.
+ operator TSharedRef() const;
+
+ //! Converts a TSharedMutableRef to TRef.
+ operator TRef() const;
+
+
+ //! Allocates a new shared block of memory.
+ //! The memory is marked with a given tag.
+ template <class TTag>
+ static TSharedMutableRef Allocate(size_t size, bool initializeStorage = true);
+
+ //! Allocates a new shared block of memory.
+ //! The memory is marked with TDefaultSharedBlobTag.
+ static TSharedMutableRef Allocate(size_t size, bool initializeStorage = true);
+
+ //! Allocates a new shared block of memory.
+ //! The memory is marked with a given tag.
+ static TSharedMutableRef Allocate(size_t size, bool initializeStorage, TRefCountedTypeCookie tagCookie);
+
+ //! Allocates a new page aligned shared block of memory.
+ //! #size must be divisible by page size.
+ //! The memory is marked with a given tag.
+ template <class TTag>
+ static TSharedMutableRef AllocatePageAligned(size_t size, bool initializeStorage = true);
+
+ //! Allocates a new page aligned shared block of memory.
+ //! #size must be divisible by page size.
+ //! The memory is marked with TDefaultSharedBlobTag.
+ static TSharedMutableRef AllocatePageAligned(size_t size, bool initializeStorage = true);
+
+ //! Allocates a new page aligned shared block of memory.
+ //! #size must be divisible by page size.
+ //! The memory is marked with a given tag.
+ static TSharedMutableRef AllocatePageAligned(size_t size, bool initializeStorage, TRefCountedTypeCookie tagCookie);
+
+ //! Creates a TSharedMutableRef for the whole blob taking ownership of its content.
+ static TSharedMutableRef FromBlob(TBlob&& blob);
+
+ //! Creates a copy of a given TRef.
+ //! The memory is marked with a given tag.
+ static TSharedMutableRef MakeCopy(TRef ref, TRefCountedTypeCookie tagCookie);
+
+ //! Creates a copy of a given TRef.
+ //! The memory is marked with a given tag.
+ template <class TTag>
+ static TSharedMutableRef MakeCopy(TRef ref);
+
+ //! Creates a reference for a part of existing range.
+ TSharedMutableRef Slice(size_t startOffset, size_t endOffset) const;
+
+ //! Creates a reference for a part of existing range.
+ TSharedMutableRef Slice(void* begin, void* end) const;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+DECLARE_REFCOUNTED_CLASS(TSharedRefArrayImpl)
+
+//! A smart-pointer to a ref-counted immutable sequence of TSharedRef-s.
+class TSharedRefArray
+{
+public:
+ TSharedRefArray() = default;
+ TSharedRefArray(const TSharedRefArray& other);
+ TSharedRefArray(TSharedRefArray&& other) noexcept;
+
+ explicit TSharedRefArray(const TSharedRef& part);
+ explicit TSharedRefArray(TSharedRef&& part);
+
+ struct TCopyParts
+ { };
+ struct TMoveParts
+ { };
+
+ template <class TParts>
+ TSharedRefArray(const TParts& parts, TCopyParts);
+ template <class TParts>
+ TSharedRefArray(TParts&& parts, TMoveParts);
+
+ TSharedRefArray& operator = (const TSharedRefArray& other);
+ TSharedRefArray& operator = (TSharedRefArray&& other);
+
+ explicit operator bool() const;
+
+ void Reset();
+
+ size_t Size() const;
+ size_t size() const;
+ i64 ByteSize() const;
+ bool Empty() const;
+ const TSharedRef& operator [] (size_t index) const;
+
+ const TSharedRef* Begin() const;
+ const TSharedRef* End() const;
+
+ std::vector<TSharedRef> ToVector() const;
+
+private:
+ friend class TSharedRefArrayBuilder;
+
+ TSharedRefArrayImplPtr Impl_;
+
+ explicit TSharedRefArray(TSharedRefArrayImplPtr impl);
+
+ template <class... As>
+ static TSharedRefArrayImplPtr NewImpl(
+ size_t size,
+ size_t poolCapacity,
+ TRefCountedTypeCookie cookie,
+ As&&... args);
+};
+
+// STL interop.
+const TSharedRef* begin(const TSharedRefArray& array);
+const TSharedRef* end(const TSharedRefArray& array);
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct TDefaultSharedRefArrayBuilderTag { };
+
+//! A helper for creating TSharedRefArray.
+class TSharedRefArrayBuilder
+{
+public:
+ //! Creates a builder instance.
+ /*
+ * The user must provide the total (resulting) part count in #size.
+ *
+ * Additionally, the user may request a certain memory pool of size #poolCapacity
+ * to be created. Parts occupiying space in the above pool are created with #AllocateAndAdd
+ * calls.
+ *
+ * The pool (if any) and the array are created within a single memory allocation tagged with
+ * #tagCookie.
+ *
+ * If less than #size parts are added, the trailing ones are null.
+ */
+ explicit TSharedRefArrayBuilder(
+ size_t size,
+ size_t poolCapacity = 0,
+ TRefCountedTypeCookie tagCookie = GetRefCountedTypeCookie<TDefaultSharedRefArrayBuilderTag>());
+
+ //! Adds an existing TSharedRef part to the constructed array.
+ void Add(TSharedRef part);
+
+ //! Allocates #size memory from the pool and adds a part to the constuctured array.
+ /*!
+ * The resulting TMutableRef enables the user to fill the just-created part appropriately.
+ * The total sum of #size during all #AllocateAndAll calls must now exceed #allocationCapacity
+ * passed to the ctor.
+ *
+ * The memory is being claimed from the pool contiguously; the user must
+ * take care of the alignment issues on its own.
+ */
+ TMutableRef AllocateAndAdd(size_t size);
+
+ //! Finalizes the construction; returns the constructed TSharedRefArray.
+ TSharedRefArray Finish();
+
+private:
+ const size_t AllocationCapacity_;
+ TSharedRefArrayImplPtr Impl_;
+ char* CurrentAllocationPtr_;
+ size_t CurrentPartIndex_ = 0;
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+TString ToString(TRef ref);
+TString ToString(const TMutableRef& ref);
+TString ToString(const TSharedRef& ref);
+TString ToString(const TSharedMutableRef& ref);
+
+size_t GetPageSize();
+size_t RoundUpToPage(size_t bytes);
+
+size_t GetByteSize(TRef ref);
+size_t GetByteSize(const TSharedRefArray& array);
+template <class T>
+size_t GetByteSize(TRange<T> parts);
+template <class T>
+size_t GetByteSize(const std::vector<T>& parts);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define REF_INL_H_
+#include "ref-inl.h"
+#undef REF_INL_H_
diff --git a/library/cpp/yt/memory/ref_counted-inl.h b/library/cpp/yt/memory/ref_counted-inl.h
new file mode 100644
index 0000000000..e6d64fec18
--- /dev/null
+++ b/library/cpp/yt/memory/ref_counted-inl.h
@@ -0,0 +1,278 @@
+#ifndef REF_COUNTED_INL_H_
+#error "Direct inclusion of this file is not allowed, include ref_counted.h"
+// For the sake of sane code completion.
+#include "ref_counted.h"
+#endif
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+constexpr uint16_t PtrBits = 48;
+constexpr uintptr_t PtrMask = (1ULL << PtrBits) - 1;
+
+template <class T>
+Y_FORCE_INLINE char* PackPointer(T* ptr, uint16_t data)
+{
+ return reinterpret_cast<char*>((static_cast<uintptr_t>(data) << PtrBits) | reinterpret_cast<uintptr_t>(ptr));
+}
+
+template <class T>
+struct TPackedPointer
+{
+ uint16_t Data;
+ T* Ptr;
+};
+
+template <class T>
+Y_FORCE_INLINE TPackedPointer<T> UnpackPointer(void* packedPtr)
+{
+ auto castedPtr = reinterpret_cast<uintptr_t>(packedPtr);
+ return {static_cast<uint16_t>(castedPtr >> PtrBits), reinterpret_cast<T*>(castedPtr & PtrMask)};
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, class = void>
+struct TMemoryReleaser
+{
+ static void Do(void* ptr, uint16_t /*offset*/)
+ {
+ TFreeMemory<T>::Do(ptr);
+ }
+};
+
+using TDeleter = void (*)(void*);
+
+void ScheduleObjectDeletion(void* ptr, TDeleter deleter);
+
+template <class T>
+struct TMemoryReleaser<T, std::enable_if_t<T::EnableHazard>>
+{
+ static void Do(void* ptr, uint16_t offset)
+ {
+ // Base pointer is used in HazardPtr as the identity of object.
+ auto* basePtr = PackPointer(static_cast<char*>(ptr) + offset, offset);
+
+ ScheduleObjectDeletion(basePtr, [] (void* ptr) {
+ // Base ptr and the beginning of allocated memory region may differ.
+ auto [offset, basePtr] = UnpackPointer<char>(ptr);
+ TFreeMemory<T>::Do(basePtr - offset);
+ });
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_FORCE_INLINE int TRefCounter::GetRefCount() const noexcept
+{
+ return StrongCount_.load(std::memory_order_relaxed);
+}
+
+Y_FORCE_INLINE void TRefCounter::Ref() const noexcept
+{
+ // It is safe to use relaxed here, since new reference is always created from another live reference.
+ StrongCount_.fetch_add(1, std::memory_order_relaxed);
+
+ YT_ASSERT(WeakCount_.load(std::memory_order_relaxed) > 0);
+}
+
+Y_FORCE_INLINE bool TRefCounter::TryRef() const noexcept
+{
+ auto value = StrongCount_.load(std::memory_order_relaxed);
+ YT_ASSERT(WeakCount_.load(std::memory_order_relaxed) > 0);
+
+ while (value != 0 && !StrongCount_.compare_exchange_weak(value, value + 1));
+ return value != 0;
+}
+
+Y_FORCE_INLINE bool TRefCounter::Unref() const
+{
+ // We must properly synchronize last access to object with it destruction.
+ // Otherwise compiler might reorder access to object past this decrement.
+ //
+ // See http://www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html#boost_atomic.usage_examples.example_reference_counters
+ //
+ auto oldStrongCount = StrongCount_.fetch_sub(1, std::memory_order_release);
+ YT_ASSERT(oldStrongCount > 0);
+ if (oldStrongCount == 1) {
+ StrongCount_.load(std::memory_order_acquire);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Y_FORCE_INLINE int TRefCounter::GetWeakRefCount() const noexcept
+{
+ return WeakCount_.load(std::memory_order_acquire);
+}
+
+Y_FORCE_INLINE void TRefCounter::WeakRef() const noexcept
+{
+ auto oldWeakCount = WeakCount_.fetch_add(1, std::memory_order_relaxed);
+ YT_ASSERT(oldWeakCount > 0);
+}
+
+Y_FORCE_INLINE bool TRefCounter::WeakUnref() const
+{
+ auto oldWeakCount = WeakCount_.fetch_sub(1, std::memory_order_release);
+ YT_ASSERT(oldWeakCount > 0);
+ if (oldWeakCount == 1) {
+ WeakCount_.load(std::memory_order_acquire);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, bool = std::is_base_of_v<TRefCountedBase, T>>
+struct TRefCountedHelper
+{
+ static_assert(
+ std::is_final_v<T>,
+ "Ref-counted objects must be derived from TRefCountedBase or to be final");
+
+ static constexpr size_t RefCounterSpace = (sizeof(TRefCounter) + alignof(T) - 1) & ~(alignof(T) - 1);
+ static constexpr size_t RefCounterOffset = RefCounterSpace - sizeof(TRefCounter);
+
+ Y_FORCE_INLINE static const TRefCounter* GetRefCounter(const T* obj)
+ {
+ return reinterpret_cast<const TRefCounter*>(obj) - 1;
+ }
+
+ Y_FORCE_INLINE static void Destroy(const T* obj)
+ {
+ auto* refCounter = GetRefCounter(obj);
+
+ // No virtual call when T is final.
+ obj->~T();
+
+ char* ptr = reinterpret_cast<char*>(const_cast<TRefCounter*>(refCounter));
+
+ // Fast path. Weak refs cannot appear if there are neither strong nor weak refs.
+ if (refCounter->GetWeakRefCount() == 1) {
+ TMemoryReleaser<T>::Do(ptr - RefCounterOffset, RefCounterSpace);
+ return;
+ }
+
+ if (refCounter->WeakUnref()) {
+ TMemoryReleaser<T>::Do(ptr - RefCounterOffset, RefCounterSpace);
+ }
+ }
+
+ Y_FORCE_INLINE static void Deallocate(const T* obj)
+ {
+ char* ptr = reinterpret_cast<char*>(const_cast<TRefCounter*>(GetRefCounter(obj)));
+ TMemoryReleaser<T>::Do(ptr - RefCounterOffset, RefCounterSpace);
+ }
+};
+
+template <class T>
+struct TRefCountedHelper<T, true>
+{
+ Y_FORCE_INLINE static const TRefCounter* GetRefCounter(const T* obj)
+ {
+ return obj;
+ }
+
+ Y_FORCE_INLINE static void Destroy(const TRefCountedBase* obj)
+ {
+ const_cast<TRefCountedBase*>(obj)->DestroyRefCounted();
+ }
+
+ Y_FORCE_INLINE static void Deallocate(const TRefCountedBase* obj)
+ {
+ auto* ptr = reinterpret_cast<void**>(const_cast<TRefCountedBase*>(obj));
+ auto [offset, ptrToDeleter] = UnpackPointer<void(void*, uint16_t)>(*ptr);
+
+ // The most derived type is erased here. So we cannot call TMemoryReleaser with derived type.
+ ptrToDeleter(reinterpret_cast<char*>(ptr) - offset, offset);
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+Y_FORCE_INLINE const TRefCounter* GetRefCounter(const T* obj)
+{
+ return TRefCountedHelper<T>::GetRefCounter(obj);
+}
+
+template <class T>
+Y_FORCE_INLINE void DestroyRefCounted(const T* obj)
+{
+ TRefCountedHelper<T>::Destroy(obj);
+}
+
+template <class T>
+Y_FORCE_INLINE void DeallocateRefCounted(const T* obj)
+{
+ TRefCountedHelper<T>::Deallocate(obj);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+Y_FORCE_INLINE void Ref(T* obj)
+{
+ GetRefCounter(obj)->Ref();
+}
+
+template <class T>
+Y_FORCE_INLINE void Unref(T* obj)
+{
+ if (GetRefCounter(obj)->Unref()) {
+ DestroyRefCounted(obj);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_FORCE_INLINE void TRefCounted::Unref() const
+{
+ ::NYT::Unref(this);
+}
+
+Y_FORCE_INLINE void TRefCounted::WeakUnref() const
+{
+ if (TRefCounter::WeakUnref()) {
+ DeallocateRefCounted(this);
+ }
+}
+
+
+template <class T>
+void TRefCounted::DestroyRefCountedImpl(T* ptr)
+{
+ // No standard way to statically calculate the base offset even if T is final.
+ // static_cast<TFinalDerived*>(virtualBasePtr) does not work.
+
+ auto* basePtr = static_cast<TRefCountedBase*>(ptr);
+ auto offset = reinterpret_cast<uintptr_t>(basePtr) - reinterpret_cast<uintptr_t>(ptr);
+ auto* refCounter = GetRefCounter(ptr);
+
+ // No virtual call when T is final.
+ ptr->~T();
+
+ // Fast path. Weak refs cannot appear if there are neither strong nor weak refs.
+ if (refCounter->GetWeakRefCount() == 1) {
+ TMemoryReleaser<T>::Do(ptr, offset);
+ return;
+ }
+
+ YT_ASSERT(offset < std::numeric_limits<uint16_t>::max());
+
+ auto* vTablePtr = reinterpret_cast<char**>(basePtr);
+ *vTablePtr = PackPointer(&TMemoryReleaser<T>::Do, offset);
+
+ if (refCounter->WeakUnref()) {
+ TMemoryReleaser<T>::Do(ptr, offset);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/memory/ref_counted.h b/library/cpp/yt/memory/ref_counted.h
new file mode 100644
index 0000000000..b683615b83
--- /dev/null
+++ b/library/cpp/yt/memory/ref_counted.h
@@ -0,0 +1,190 @@
+#pragma once
+
+#include <library/cpp/yt/misc/port.h>
+
+#include <library/cpp/yt/assert/assert.h>
+
+#include <library/cpp/ytalloc/api/ytalloc.h>
+
+#include <atomic>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! A technical base class for ref-counted objects and promise states.
+class TRefCountedBase
+{
+public:
+ TRefCountedBase() = default;
+
+ // Make destructor protected
+ virtual ~TRefCountedBase() noexcept = default;
+
+ virtual void DestroyRefCounted() = 0;
+
+private:
+ TRefCountedBase(const TRefCountedBase&) = delete;
+ TRefCountedBase(TRefCountedBase&&) = delete;
+
+ TRefCountedBase& operator=(const TRefCountedBase&) = delete;
+ TRefCountedBase& operator=(TRefCountedBase&&) = delete;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, class = void>
+struct TFreeMemory
+{
+ static void Do(void* ptr)
+ {
+ NYTAlloc::FreeNonNull(ptr);
+ }
+};
+
+template <class T>
+struct TFreeMemory<T, std::void_t<typename T::TAllocator>>
+{
+ static void Do(void* ptr)
+ {
+ using TAllocator = typename T::TAllocator;
+ TAllocator::Free(ptr);
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TRefCounter
+{
+public:
+ //! Returns current number of strong references to the object.
+ /*!
+ * Note that you should never ever use this method in production code.
+ * This method is mainly for debugging purposes.
+ */
+ int GetRefCount() const noexcept;
+
+ //! Increments the strong reference counter.
+ void Ref() const noexcept;
+
+ //! Increments the strong reference counter if it is not null.
+ bool TryRef() const noexcept;
+
+ //! Decrements the strong reference counter.
+ bool Unref() const;
+
+ //! Returns current number of weak references to the object.
+ int GetWeakRefCount() const noexcept;
+
+ //! Increments the weak reference counter.
+ void WeakRef() const noexcept;
+
+ //! Decrements the weak reference counter.
+ bool WeakUnref() const;
+
+private:
+ mutable std::atomic<int> StrongCount_ = 1;
+ mutable std::atomic<int> WeakCount_ = 1;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+const TRefCounter* GetRefCounter(const T* obj);
+
+template <class T>
+void DestroyRefCounted(const T* obj);
+
+template <class T>
+void DeallocateRefCounted(const T* obj);
+
+////////////////////////////////////////////////////////////////////////////////
+
+// API
+
+template <class T>
+void Ref(T* obj);
+
+template <class T>
+void Unref(T* obj);
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct TRefCounted
+ : public TRefCountedBase
+ , public TRefCounter
+{
+ void Unref() const;
+
+ void WeakUnref() const;
+
+ template <class T>
+ static void DestroyRefCountedImpl(T* ptr);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Forward declaration.
+template <class T>
+class TIntrusivePtr;
+
+using TRefCountedPtr = TIntrusivePtr<TRefCounted>;
+
+// A bunch of helpful macros that enable working with intrusive pointers to incomplete types.
+/*
+ * Typically when you have a forward-declared type |T| and an instance
+ * of |TIntrusivePtr<T>| you need the complete definition of |T| to work with
+ * the pointer even if you're not actually using the members of |T|.
+ * E.g. the dtor of |TIntrusivePtr<T>|, should you ever need it, must be able
+ * to unref an instance of |T| and eventually destroy it.
+ * This may force #inclusion of way more headers than really seems necessary.
+ *
+ * |DECLARE_REFCOUNTED_STRUCT|, |DECLARE_REFCOUNTED_CLASS|, and |DEFINE_REFCOUNTED_TYPE|
+ * alleviate this issue by forcing TIntrusivePtr to work with the free-standing overloads
+ * of |Ref| and |Unref| instead of their template version.
+ * These overloads are declared together with the forward declaration of |T| and
+ * are subsequently defined afterwards.
+ */
+
+#define DECLARE_REFCOUNTED_TYPE(type) \
+ using type ## Ptr = ::NYT::TIntrusivePtr<type>; \
+ \
+ [[maybe_unused]] ATTRIBUTE_USED const ::NYT::TRefCounter* GetRefCounter(const type* obj); \
+ [[maybe_unused]] ATTRIBUTE_USED void DestroyRefCounted(const type* obj); \
+ [[maybe_unused]] ATTRIBUTE_USED void DeallocateRefCounted(const type* obj);
+
+//! Forward-declares a class type, defines an intrusive pointer for it, and finally
+//! declares Ref/Unref overloads. Use this macro in |public.h|-like files.
+#define DECLARE_REFCOUNTED_CLASS(type) \
+ class type; \
+ DECLARE_REFCOUNTED_TYPE(type)
+
+//! Forward-declares a struct type, defines an intrusive pointer for it, and finally
+//! declares Ref/Unref overloads. Use this macro in |public.h|-like files.
+#define DECLARE_REFCOUNTED_STRUCT(type) \
+ struct type; \
+ DECLARE_REFCOUNTED_TYPE(type)
+
+//! Provides implementations for Ref/Unref overloads. Use this macro right
+//! after the type's full definition.
+#define DEFINE_REFCOUNTED_TYPE(type) \
+ [[maybe_unused]] ATTRIBUTE_USED Y_FORCE_INLINE const ::NYT::TRefCounter* GetRefCounter(const type* obj) \
+ { \
+ return ::NYT::TRefCountedHelper<type>::GetRefCounter(obj); \
+ } \
+ [[maybe_unused]] ATTRIBUTE_USED Y_FORCE_INLINE void DestroyRefCounted(const type* obj) \
+ { \
+ ::NYT::TRefCountedHelper<type>::Destroy(obj); \
+ } \
+ [[maybe_unused]] ATTRIBUTE_USED Y_FORCE_INLINE void DeallocateRefCounted(const type* obj) \
+ { \
+ ::NYT::TRefCountedHelper<type>::Deallocate(obj); \
+ }
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define REF_COUNTED_INL_H_
+#include "ref_counted-inl.h"
+#undef REF_COUNTED_INL_H_
diff --git a/library/cpp/yt/memory/ref_tracked-inl.h b/library/cpp/yt/memory/ref_tracked-inl.h
new file mode 100644
index 0000000000..4bde72881d
--- /dev/null
+++ b/library/cpp/yt/memory/ref_tracked-inl.h
@@ -0,0 +1,49 @@
+#ifndef REF_TRACKED_INL_H_
+#error "Direct inclusion of this file is not allowed, include ref_tracked.h"
+// For the sake of sane code completion.
+#include "ref_tracked.h"
+#endif
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+TRefCountedTypeKey GetRefCountedTypeKey()
+{
+ return &typeid(T);
+}
+
+template <class T>
+Y_FORCE_INLINE TRefCountedTypeCookie GetRefCountedTypeCookie()
+{
+ static std::atomic<TRefCountedTypeCookie> cookie{NullRefCountedTypeCookie};
+ auto cookieValue = cookie.load(std::memory_order_relaxed);
+ if (Y_UNLIKELY(cookieValue == NullRefCountedTypeCookie)) {
+ cookieValue = TRefCountedTrackerFacade::GetCookie(
+ GetRefCountedTypeKey<T>(),
+ sizeof(T),
+ NYT::TSourceLocation());
+ cookie.store(cookieValue, std::memory_order_relaxed);
+ }
+ return cookieValue;
+}
+
+template <class T, class TTag, int Counter>
+Y_FORCE_INLINE TRefCountedTypeCookie GetRefCountedTypeCookieWithLocation(const TSourceLocation& location)
+{
+ static std::atomic<TRefCountedTypeCookie> cookie{NullRefCountedTypeCookie};
+ auto cookieValue = cookie.load(std::memory_order_relaxed);
+ if (Y_UNLIKELY(cookieValue == NullRefCountedTypeCookie)) {
+ cookieValue = TRefCountedTrackerFacade::GetCookie(
+ GetRefCountedTypeKey<T>(),
+ sizeof(T),
+ location);
+ cookie.store(cookieValue, std::memory_order_relaxed);
+ }
+ return cookieValue;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/memory/ref_tracked.cpp b/library/cpp/yt/memory/ref_tracked.cpp
new file mode 100644
index 0000000000..4dafbc0849
--- /dev/null
+++ b/library/cpp/yt/memory/ref_tracked.cpp
@@ -0,0 +1,38 @@
+#include "ref_tracked.h"
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_WEAK TRefCountedTypeCookie TRefCountedTrackerFacade::GetCookie(
+ TRefCountedTypeKey /*typeKey*/,
+ size_t /*instanceSize*/,
+ const TSourceLocation& /*location*/)
+{
+ return NullRefCountedTypeCookie;
+}
+
+Y_WEAK void TRefCountedTrackerFacade::AllocateInstance(TRefCountedTypeCookie /*cookie*/)
+{ }
+
+Y_WEAK void TRefCountedTrackerFacade::FreeInstance(TRefCountedTypeCookie /*cookie*/)
+{ }
+
+Y_WEAK void TRefCountedTrackerFacade::AllocateTagInstance(TRefCountedTypeCookie /*cookie*/)
+{ }
+
+Y_WEAK void TRefCountedTrackerFacade::FreeTagInstance(TRefCountedTypeCookie /*cookie*/)
+{ }
+
+Y_WEAK void TRefCountedTrackerFacade::AllocateSpace(TRefCountedTypeCookie /*cookie*/, size_t /*size*/)
+{ }
+
+Y_WEAK void TRefCountedTrackerFacade::FreeSpace(TRefCountedTypeCookie /*cookie*/, size_t /*size*/)
+{ }
+
+Y_WEAK void TRefCountedTrackerFacade::Dump()
+{ }
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/memory/ref_tracked.h b/library/cpp/yt/memory/ref_tracked.h
new file mode 100644
index 0000000000..75c1eb5985
--- /dev/null
+++ b/library/cpp/yt/memory/ref_tracked.h
@@ -0,0 +1,111 @@
+#pragma once
+
+#include <library/cpp/yt/misc/port.h>
+#include <library/cpp/yt/misc/source_location.h>
+
+#include <util/system/defaults.h>
+
+#include <atomic>
+#include <typeinfo>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+using TRefCountedTypeCookie = int;
+const int NullRefCountedTypeCookie = -1;
+
+using TRefCountedTypeKey = const void*;
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Used to avoid including heavy ref_counted_tracker.h
+class TRefCountedTrackerFacade
+{
+public:
+ static TRefCountedTypeCookie GetCookie(
+ TRefCountedTypeKey typeKey,
+ size_t instanceSize,
+ const NYT::TSourceLocation& location);
+
+ static void AllocateInstance(TRefCountedTypeCookie cookie);
+ static void FreeInstance(TRefCountedTypeCookie cookie);
+
+ static void AllocateTagInstance(TRefCountedTypeCookie cookie);
+ static void FreeTagInstance(TRefCountedTypeCookie cookie);
+
+ static void AllocateSpace(TRefCountedTypeCookie cookie, size_t size);
+ static void FreeSpace(TRefCountedTypeCookie cookie, size_t size);
+
+ // Typically invoked from GDB console.
+ // Dumps the ref-counted statistics sorted by "bytes alive".
+ static void Dump();
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+//! A per-translation unit tag type.
+struct TCurrentTranslationUnitTag
+{ };
+
+} // namespace
+
+template <class T>
+TRefCountedTypeKey GetRefCountedTypeKey();
+
+template <class T>
+TRefCountedTypeCookie GetRefCountedTypeCookie();
+
+template <class T, class TTag, int Counter>
+TRefCountedTypeCookie GetRefCountedTypeCookieWithLocation(
+ const TSourceLocation& location);
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! A lightweight mix-in that integrates any class into TRefCountedTracker statistics.
+/*!
+ * |T| must be the actual derived type.
+ *
+ * This mix-in provides statistical tracking only, |T| is responsible for implementing
+ * lifetime management on its own.
+ */
+template <class T>
+class TRefTracked
+{
+public:
+#ifdef YT_ENABLE_REF_COUNTED_TRACKING
+ TRefTracked()
+ {
+ auto cookie = GetRefCountedTypeCookie<T>();
+ TRefCountedTrackerFacade::AllocateInstance(cookie);
+ }
+
+ TRefTracked(const TRefTracked&)
+ {
+ auto cookie = GetRefCountedTypeCookie<T>();
+ TRefCountedTrackerFacade::AllocateInstance(cookie);
+ }
+
+ TRefTracked(TRefTracked&&)
+ {
+ auto cookie = GetRefCountedTypeCookie<T>();
+ TRefCountedTrackerFacade::AllocateInstance(cookie);
+ }
+
+ ~TRefTracked()
+ {
+ auto cookie = GetRefCountedTypeCookie<T>();
+ TRefCountedTrackerFacade::FreeInstance(cookie);
+ }
+#endif
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define REF_TRACKED_INL_H_
+#include "ref_tracked-inl.h"
+#undef REF_TRACKED_INL_H_
diff --git a/library/cpp/yt/memory/shared_range.h b/library/cpp/yt/memory/shared_range.h
new file mode 100644
index 0000000000..9841d7a0df
--- /dev/null
+++ b/library/cpp/yt/memory/shared_range.h
@@ -0,0 +1,297 @@
+#pragma once
+
+#include "intrusive_ptr.h"
+#include "range.h"
+#include "ref_counted.h"
+
+#include <library/cpp/yt/assert/assert.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, size_t N>
+class TCompactVector;
+
+//! TRange with ownership semantics.
+template <class T>
+class TSharedRange
+ : public TRange<T>
+{
+public:
+ using THolderPtr = TRefCountedPtr;
+
+ //! Constructs a null TSharedRange.
+ TSharedRange()
+ { }
+
+ //! Constructs a TSharedRange from TRange.
+ TSharedRange(TRange<T> range, THolderPtr holder)
+ : TRange<T>(range)
+ , Holder_(std::move(holder))
+ { }
+
+ //! Constructs a TSharedRange from a pointer and length.
+ TSharedRange(const T* data, size_t length, THolderPtr holder)
+ : TRange<T>(data, length)
+ , Holder_(std::move(holder))
+ { }
+
+ //! Constructs a TSharedRange from a range.
+ TSharedRange(const T* begin, const T* end, THolderPtr holder)
+ : TRange<T>(begin, end)
+ , Holder_(std::move(holder))
+ { }
+
+ //! Constructs a TSharedRange from a TCompactVector.
+ template <size_t N>
+ TSharedRange(const TCompactVector<T, N>& elements, THolderPtr holder)
+ : TRange<T>(elements)
+ , Holder_(std::move(holder))
+ { }
+
+ //! Constructs a TSharedRange from an std::vector.
+ TSharedRange(const std::vector<T>& elements, THolderPtr holder)
+ : TRange<T>(elements)
+ , Holder_(std::move(holder))
+ { }
+
+ //! Constructs a TSharedRange from a C array.
+ template <size_t N>
+ TSharedRange(const T (& elements)[N], THolderPtr holder)
+ : TRange<T>(elements)
+ , Holder_(std::move(holder))
+ { }
+
+
+ void Reset()
+ {
+ TRange<T>::Data_ = nullptr;
+ TRange<T>::Length_ = 0;
+ Holder_.Reset();
+ }
+
+ TSharedRange<T> Slice(size_t startOffset, size_t endOffset) const
+ {
+ YT_ASSERT(startOffset <= this->Size());
+ YT_ASSERT(endOffset >= startOffset && endOffset <= this->Size());
+ return TSharedRange<T>(this->Begin() + startOffset, endOffset - startOffset, Holder_);
+ }
+
+ TSharedRange<T> Slice(const T* begin, const T* end) const
+ {
+ YT_ASSERT(begin >= this->Begin());
+ YT_ASSERT(end <= this->End());
+ return TSharedRange<T>(begin, end, Holder_);
+ }
+
+ const THolderPtr& GetHolder() const
+ {
+ return Holder_;
+ }
+
+ THolderPtr&& ReleaseHolder()
+ {
+ return std::move(Holder_);
+ }
+
+protected:
+ THolderPtr Holder_;
+
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Constructs a combined holder instance by taking ownership of a given list of holders.
+template <class... THolders>
+TRefCountedPtr MakeCompositeHolder(THolders&&... holders)
+{
+ struct THolder
+ : public TRefCounted
+ {
+ std::tuple<typename std::decay<THolders>::type...> Holders;
+ };
+
+ auto holder = New<THolder>();
+ holder->Holders = std::tuple<THolders...>(std::forward<THolders>(holders)...);
+ return holder;
+}
+
+template <class T, class TContainer, class... THolders>
+TSharedRange<T> DoMakeSharedRange(TContainer&& elements, THolders&&... holders)
+{
+ struct THolder
+ : public TRefCounted
+ {
+ typename std::decay<TContainer>::type Elements;
+ std::tuple<typename std::decay<THolders>::type...> Holders;
+ };
+
+ auto holder = New<THolder>();
+ holder->Holders = std::tuple<THolders...>(std::forward<THolders>(holders)...);
+ holder->Elements = std::forward<TContainer>(elements);
+
+ auto range = MakeRange<T>(holder->Elements);
+
+ return TSharedRange<T>(range, std::move(holder));
+}
+
+//! Constructs a TSharedRange by taking ownership of an std::vector.
+template <class T, class... THolders>
+TSharedRange<T> MakeSharedRange(std::vector<T>&& elements, THolders&&... holders)
+{
+ return DoMakeSharedRange<T>(std::move(elements), std::forward<THolders>(holders)...);
+}
+
+//! Constructs a TSharedRange by taking ownership of an TCompactVector.
+template <class T, size_t N, class... THolders>
+TSharedRange<T> MakeSharedRange(TCompactVector<T, N>&& elements, THolders&&... holders)
+{
+ return DoMakeSharedRange<T>(std::move(elements), std::forward<THolders>(holders)...);
+}
+
+//! Constructs a TSharedRange by copying an std::vector.
+template <class T, class... THolders>
+TSharedRange<T> MakeSharedRange(const std::vector<T>& elements, THolders&&... holders)
+{
+ return DoMakeSharedRange<T>(elements, std::forward<THolders>(holders)...);
+}
+
+template <class T, class... THolders>
+TSharedRange<T> MakeSharedRange(TRange<T> range, THolders&&... holders)
+{
+ return TSharedRange<T>(range, MakeCompositeHolder(std::forward<THolders>(holders)...));
+}
+
+template <class T, class THolder>
+TSharedRange<T> MakeSharedRange(TRange<T> range, TIntrusivePtr<THolder> holder)
+{
+ return TSharedRange<T>(range, std::move(holder));
+}
+
+template <class U, class T>
+TSharedRange<U> ReinterpretCastRange(const TSharedRange<T>& range)
+{
+ static_assert(sizeof(T) == sizeof(U), "T and U must have equal sizes.");
+ return TSharedRange<U>(reinterpret_cast<const U*>(range.Begin()), range.Size(), range.GetHolder());
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! TMutableRange with ownership semantics.
+//! Use with caution :)
+template <class T>
+class TSharedMutableRange
+ : public TMutableRange<T>
+{
+public:
+ using THolderPtr = TRefCountedPtr;
+
+ //! Constructs a null TSharedMutableRange.
+ TSharedMutableRange()
+ { }
+
+ //! Constructs a TSharedMutableRange from TMutableRange.
+ TSharedMutableRange(TMutableRange<T> range, THolderPtr holder)
+ : TMutableRange<T>(range)
+ , Holder_(std::move(holder))
+ { }
+
+ //! Constructs a TSharedMutableRange from a pointer and length.
+ TSharedMutableRange(T* data, size_t length, THolderPtr holder)
+ : TMutableRange<T>(data, length)
+ , Holder_(std::move(holder))
+ { }
+
+ //! Constructs a TSharedMutableRange from a range.
+ TSharedMutableRange(T* begin, T* end, THolderPtr holder)
+ : TMutableRange<T>(begin, end)
+ , Holder_(std::move(holder))
+ { }
+
+ //! Constructs a TSharedMutableRange from a TCompactVector.
+ template <size_t N>
+ TSharedMutableRange(TCompactVector<T, N>& elements, THolderPtr holder)
+ : TMutableRange<T>(elements)
+ , Holder_(std::move(holder))
+ { }
+
+ //! Constructs a TSharedMutableRange from an std::vector.
+ TSharedMutableRange(std::vector<T>& elements, THolderPtr holder)
+ : TMutableRange<T>(elements)
+ , Holder_(std::move(holder))
+ { }
+
+ //! Constructs a TSharedMutableRange from a C array.
+ template <size_t N>
+ TSharedMutableRange(T (& elements)[N], THolderPtr holder)
+ : TMutableRange<T>(elements)
+ , Holder_(std::move(holder))
+ { }
+
+
+ void Reset()
+ {
+ TRange<T>::Data_ = nullptr;
+ TRange<T>::Length_ = 0;
+ Holder_.Reset();
+ }
+
+ TSharedMutableRange<T> Slice(size_t startOffset, size_t endOffset) const
+ {
+ YT_ASSERT(startOffset <= this->Size());
+ YT_ASSERT(endOffset >= startOffset && endOffset <= this->Size());
+ return TSharedMutableRange<T>(this->Begin() + startOffset, endOffset - startOffset, Holder_);
+ }
+
+ TSharedMutableRange<T> Slice(T* begin, T* end) const
+ {
+ YT_ASSERT(begin >= this->Begin());
+ YT_ASSERT(end <= this->End());
+ return TSharedMutableRange<T>(begin, end, Holder_);
+ }
+
+ THolderPtr GetHolder() const
+ {
+ return Holder_;
+ }
+
+ THolderPtr&& ReleaseHolder()
+ {
+ return std::move(Holder_);
+ }
+
+protected:
+ THolderPtr Holder_;
+
+};
+
+template <class T, class TContainer, class... THolders>
+TSharedMutableRange<T> DoMakeSharedMutableRange(TContainer&& elements, THolders&&... holders)
+{
+ struct THolder
+ : public TRefCounted
+ {
+ typename std::decay<TContainer>::type Elements;
+ std::tuple<typename std::decay<THolders>::type...> Holders;
+ };
+
+ auto holder = New<THolder>();
+ holder->Holders = std::tuple<THolders...>(std::forward<THolders>(holders)...);
+ holder->Elements = std::forward<TContainer>(elements);
+
+ auto range = TMutableRange<T>(holder->Elements);
+
+ return TSharedMutableRange<T>(range, holder);
+}
+
+//! Constructs a TSharedMutableRange by taking ownership of an std::vector.
+template <class T, class... THolders>
+TSharedMutableRange<T> MakeSharedMutableRange(std::vector<T>&& elements, THolders&&... holders)
+{
+ return DoMakeSharedMutableRange<T>(std::move(elements), std::forward<THolders>(holders)...);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/memory/unittests/intrusive_ptr_ut.cpp b/library/cpp/yt/memory/unittests/intrusive_ptr_ut.cpp
new file mode 100644
index 0000000000..622bed0eb0
--- /dev/null
+++ b/library/cpp/yt/memory/unittests/intrusive_ptr_ut.cpp
@@ -0,0 +1,562 @@
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <library/cpp/yt/memory/new.h>
+#include <library/cpp/yt/memory/ref_counted.h>
+
+namespace NYT {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+using ::testing::IsNull;
+using ::testing::NotNull;
+using ::testing::InSequence;
+using ::testing::MockFunction;
+using ::testing::StrictMock;
+
+////////////////////////////////////////////////////////////////////////////////
+// Auxiliary types and functions.
+////////////////////////////////////////////////////////////////////////////////
+
+// This object tracks number of increments and decrements
+// to the reference counter (see traits specialization below).
+struct TIntricateObject
+ : private TNonCopyable
+{
+ int Increments = 0;
+ int Decrements = 0;
+ int Zeros = 0;
+
+ void Ref()
+ {
+ ++Increments;
+ }
+
+ void Unref()
+ {
+ ++Decrements;
+ if (Increments == Decrements) {
+ ++Zeros;
+ }
+ }
+};
+
+typedef TIntrusivePtr<TIntricateObject> TIntricateObjectPtr;
+
+void Ref(TIntricateObject* obj)
+{
+ obj->Ref();
+}
+
+void Unref(TIntricateObject* obj)
+{
+ obj->Unref();
+}
+
+MATCHER_P3(HasRefCounts, increments, decrements, zeros,
+ "Reference counter " \
+ "was incremented " + ::testing::PrintToString(increments) + " times, " +
+ "was decremented " + ::testing::PrintToString(decrements) + " times, " +
+ "vanished to zero " + ::testing::PrintToString(zeros) + " times")
+{
+ Y_UNUSED(result_listener);
+ return
+ arg.Increments == increments &&
+ arg.Decrements == decrements &&
+ arg.Zeros == zeros;
+}
+
+void PrintTo(const TIntricateObject& arg, ::std::ostream* os)
+{
+ *os << arg.Increments << " increments, "
+ << arg.Decrements << " decrements and "
+ << arg.Zeros << " times vanished";
+}
+
+// This is an object which creates intrusive pointers to the self
+// during its construction.
+class TObjectWithSelfPointers
+ : public TRefCounted
+{
+public:
+ explicit TObjectWithSelfPointers(IOutputStream* output)
+ : Output_(output)
+ {
+ *Output_ << "Cb";
+
+ for (int i = 0; i < 3; ++i) {
+ *Output_ << '!';
+ TIntrusivePtr<TObjectWithSelfPointers> ptr(this);
+ }
+
+ *Output_ << "Ca";
+ }
+
+ virtual ~TObjectWithSelfPointers()
+ {
+ *Output_ << 'D';
+ }
+
+private:
+ IOutputStream* const Output_;
+
+};
+
+// This is a simple object with simple reference counting.
+class TObjectWithSimpleRC
+ : public TRefCounted
+{
+public:
+ explicit TObjectWithSimpleRC(IOutputStream* output)
+ : Output_(output)
+ {
+ *Output_ << 'C';
+ }
+
+ virtual ~TObjectWithSimpleRC()
+ {
+ *Output_ << 'D';
+ }
+
+ void DoSomething()
+ {
+ *Output_ << '!';
+ }
+
+private:
+ IOutputStream* const Output_;
+
+};
+
+// This is a simple object with full-fledged reference counting.
+class TObjectWithFullRC
+ : public TRefCounted
+{
+public:
+ explicit TObjectWithFullRC(IOutputStream* output)
+ : Output_(output)
+ {
+ *Output_ << 'C';
+ }
+
+ virtual ~TObjectWithFullRC()
+ {
+ *Output_ << 'D';
+ }
+
+ void DoSomething()
+ {
+ *Output_ << '!';
+ }
+
+private:
+ IOutputStream* const Output_;
+
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+TEST(TIntrusivePtrTest, Empty)
+{
+ TIntricateObjectPtr emptyPointer;
+ EXPECT_EQ(nullptr, emptyPointer.Get());
+}
+
+TEST(TIntrusivePtrTest, Basic)
+{
+ TIntricateObject object;
+
+ EXPECT_THAT(object, HasRefCounts(0, 0, 0));
+
+ {
+ TIntricateObjectPtr owningPointer(&object);
+ EXPECT_THAT(object, HasRefCounts(1, 0, 0));
+ EXPECT_EQ(&object, owningPointer.Get());
+ }
+
+ EXPECT_THAT(object, HasRefCounts(1, 1, 1));
+
+ {
+ TIntricateObjectPtr nonOwningPointer(&object, false);
+ EXPECT_THAT(object, HasRefCounts(1, 1, 1));
+ EXPECT_EQ(&object, nonOwningPointer.Get());
+ }
+
+ EXPECT_THAT(object, HasRefCounts(1, 2, 1));
+}
+
+TEST(TIntrusivePtrTest, ResetToNull)
+{
+ TIntricateObject object;
+ TIntricateObjectPtr ptr(&object);
+
+ EXPECT_THAT(object, HasRefCounts(1, 0, 0));
+ EXPECT_EQ(&object, ptr.Get());
+
+ ptr.Reset();
+
+ EXPECT_THAT(object, HasRefCounts(1, 1, 1));
+ EXPECT_EQ(nullptr, ptr.Get());
+}
+
+TEST(TIntrusivePtrTest, ResetToOtherObject)
+{
+ TIntricateObject firstObject;
+ TIntricateObject secondObject;
+
+ TIntricateObjectPtr ptr(&firstObject);
+
+ EXPECT_THAT(firstObject, HasRefCounts(1, 0, 0));
+ EXPECT_THAT(secondObject, HasRefCounts(0, 0, 0));
+ EXPECT_EQ(&firstObject, ptr.Get());
+
+ ptr.Reset(&secondObject);
+
+ EXPECT_THAT(firstObject, HasRefCounts(1, 1, 1));
+ EXPECT_THAT(secondObject, HasRefCounts(1, 0, 0));
+ EXPECT_EQ(&secondObject, ptr.Get());
+}
+
+TEST(TIntrusivePtrTest, CopySemantics)
+{
+ TIntricateObject object;
+
+ TIntricateObjectPtr foo(&object);
+ EXPECT_THAT(object, HasRefCounts(1, 0, 0));
+
+ {
+ TIntricateObjectPtr bar(foo);
+ EXPECT_THAT(object, HasRefCounts(2, 0, 0));
+ EXPECT_EQ(&object, foo.Get());
+ EXPECT_EQ(&object, bar.Get());
+ }
+
+ EXPECT_THAT(object, HasRefCounts(2, 1, 0));
+
+ {
+ TIntricateObjectPtr bar;
+ bar = foo;
+
+ EXPECT_THAT(object, HasRefCounts(3, 1, 0));
+ EXPECT_EQ(&object, foo.Get());
+ EXPECT_EQ(&object, bar.Get());
+ }
+
+ EXPECT_THAT(object, HasRefCounts(3, 2, 0));
+}
+
+TEST(TIntrusivePtrTest, MoveSemantics)
+{
+ TIntricateObject object;
+
+ TIntricateObjectPtr foo(&object);
+ EXPECT_THAT(object, HasRefCounts(1, 0, 0));
+
+ {
+ TIntricateObjectPtr bar(std::move(foo));
+ EXPECT_THAT(object, HasRefCounts(1, 0, 0));
+ EXPECT_THAT(foo.Get(), IsNull());
+ EXPECT_EQ(&object, bar.Get());
+ }
+
+ EXPECT_THAT(object, HasRefCounts(1, 1, 1));
+ foo.Reset(&object);
+ EXPECT_THAT(object, HasRefCounts(2, 1, 1));
+
+ {
+ TIntricateObjectPtr bar;
+ bar = std::move(foo);
+ EXPECT_THAT(object, HasRefCounts(2, 1, 1));
+ EXPECT_THAT(foo.Get(), IsNull());
+ EXPECT_EQ(&object, bar.Get());
+ }
+}
+
+TEST(TIntrusivePtrTest, Swap)
+{
+ TIntricateObject object;
+
+ TIntricateObjectPtr foo(&object);
+ TIntricateObjectPtr bar;
+
+ EXPECT_THAT(object, HasRefCounts(1, 0, 0));
+ EXPECT_THAT(foo.Get(), NotNull());
+ EXPECT_THAT(bar.Get(), IsNull());
+
+ foo.Swap(bar);
+
+ EXPECT_THAT(object, HasRefCounts(1, 0, 0));
+ EXPECT_THAT(foo.Get(), IsNull());
+ EXPECT_THAT(bar.Get(), NotNull());
+
+ foo.Swap(bar);
+
+ EXPECT_THAT(object, HasRefCounts(1, 0, 0));
+ EXPECT_THAT(foo.Get(), NotNull());
+ EXPECT_THAT(bar.Get(), IsNull());
+}
+
+TEST(TIntrusivePtrTest, UpCast)
+{
+ //! This is a simple typical reference-counted object.
+ class TSimpleObject
+ : public TRefCounted
+ { };
+
+ //! This is a simple inherited reference-counted object.
+ class TAnotherObject
+ : public TSimpleObject
+ { };
+
+ auto foo = New<TSimpleObject>();
+ auto bar = New<TAnotherObject>();
+ auto baz = New<TAnotherObject>();
+
+ foo = baz;
+
+ EXPECT_TRUE(foo == baz);
+}
+
+TEST(TIntrusivePtrTest, DownCast)
+{
+ class TBaseObject
+ : public TRefCounted
+ { };
+
+ class TDerivedObject
+ : public TBaseObject
+ { };
+
+ //! This is a simple inherited reference-counted object.
+ class TAnotherObject
+ : public TBaseObject
+ { };
+
+ TIntrusivePtr<TBaseObject> foo = New<TDerivedObject>();
+ TIntrusivePtr<TBaseObject> bar = New<TAnotherObject>();
+ {
+ auto baz = StaticPointerCast<TDerivedObject>(foo);
+ EXPECT_TRUE(foo == baz);
+ }
+ {
+ auto baz = StaticPointerCast<TDerivedObject>(TIntrusivePtr<TBaseObject>{foo});
+ EXPECT_TRUE(foo == baz);
+ }
+ {
+ auto baz = DynamicPointerCast<TDerivedObject>(foo);
+ EXPECT_TRUE(foo == baz);
+ }
+ {
+ auto baz = DynamicPointerCast<TDerivedObject>(bar);
+ EXPECT_TRUE(nullptr == baz);
+ }
+ {
+ auto baz = ConstPointerCast<const TBaseObject>(foo);
+ EXPECT_TRUE(foo.Get() == baz.Get());
+ }
+ {
+ auto baz = ConstPointerCast<const TBaseObject>(TIntrusivePtr<TBaseObject>{foo});
+ EXPECT_TRUE(foo.Get() == baz.Get());
+ }
+}
+
+TEST(TIntrusivePtrTest, UnspecifiedBoolType)
+{
+ TIntricateObject object;
+
+ TIntricateObjectPtr foo;
+ TIntricateObjectPtr bar(&object);
+
+ EXPECT_FALSE(foo);
+ EXPECT_TRUE(bar);
+}
+
+TEST(TIntrusivePtrTest, ObjectIsNotDestroyedPrematurely)
+{
+ TStringStream output;
+ New<TObjectWithSelfPointers>(&output);
+
+ // TObject... appends symbols to the output; see definitions.
+ EXPECT_STREQ("Cb!!!CaD", output.Str().c_str());
+}
+
+TEST(TIntrusivePtrTest, EqualityOperator)
+{
+ TIntricateObject object, anotherObject;
+
+ TIntricateObjectPtr emptyPointer;
+ TIntricateObjectPtr somePointer(&object);
+ TIntricateObjectPtr samePointer(&object);
+ TIntricateObjectPtr anotherPointer(&anotherObject);
+
+ EXPECT_FALSE(somePointer == emptyPointer);
+ EXPECT_FALSE(samePointer == emptyPointer);
+
+ EXPECT_TRUE(somePointer != emptyPointer);
+ EXPECT_TRUE(samePointer != emptyPointer);
+
+ EXPECT_TRUE(somePointer == samePointer);
+
+ EXPECT_TRUE(&object == somePointer);
+ EXPECT_TRUE(&object == samePointer);
+
+ EXPECT_FALSE(somePointer == anotherPointer);
+ EXPECT_TRUE(somePointer != anotherPointer);
+
+ EXPECT_TRUE(&anotherObject == anotherPointer);
+}
+
+TEST(TIntrusivePtrTest, Reset)
+{
+ TIntricateObject object;
+ TIntricateObjectPtr pointer(&object);
+ EXPECT_THAT(object, HasRefCounts(1, 0, 0));
+ EXPECT_EQ(&object, pointer.Release());
+ EXPECT_THAT(object, HasRefCounts(1, 0, 0));
+}
+
+TEST(TIntrusivePtrTest, CompareWithNullptr)
+{
+ TIntricateObjectPtr pointer1;
+ EXPECT_TRUE(nullptr == pointer1);
+ EXPECT_FALSE(nullptr != pointer1);
+ TIntricateObject object;
+ TIntricateObjectPtr pointer2(&object);
+ EXPECT_TRUE(pointer2 != nullptr);
+ EXPECT_FALSE(pointer2 == nullptr);
+}
+
+
+template <class T>
+void TestIntrusivePtrBehavior()
+{
+ typedef TIntrusivePtr<T> TMyPtr;
+
+ TStringStream output;
+ {
+ TMyPtr ptr(New<T>(&output));
+ {
+ TMyPtr anotherPtr(ptr);
+ anotherPtr->DoSomething();
+ }
+ {
+ TMyPtr anotherPtr(ptr);
+ anotherPtr->DoSomething();
+ }
+ ptr->DoSomething();
+ }
+
+ // TObject... appends symbols to the output; see definitions.
+ EXPECT_STREQ("C!!!D", output.Str().c_str());
+}
+
+TEST(TIntrusivePtrTest, SimpleRCBehaviour)
+{
+ TestIntrusivePtrBehavior<TObjectWithSimpleRC>();
+}
+
+TEST(TIntrusivePtrTest, FullRCBehaviour)
+{
+ TestIntrusivePtrBehavior<TObjectWithFullRC>();
+}
+
+TEST(TIntrusivePtrTest, ObjectAlignment)
+{
+ struct TObject
+ : public TRefCounted
+ {
+ alignas(64) ui64 Data;
+ };
+
+ struct TPODObject final
+ {
+ alignas(64) ui64 Data;
+ };
+
+ auto foo = New<TObject>();
+ auto bar = New<TPODObject>();
+
+ EXPECT_TRUE(reinterpret_cast<uintptr_t>(foo.Get()) % 64 == 0);
+ EXPECT_TRUE(reinterpret_cast<uintptr_t>(bar.Get()) % 64 == 0);
+}
+
+TEST(TIntrusivePtrTest, InitStruct)
+{
+ struct TObj1 final
+ {
+ const int A;
+ const int B;
+ };
+
+ New<TObj1>(1, 2);
+
+ struct TExplicitObj final
+ {
+ explicit TExplicitObj(int a = 0)
+ : A(a)
+ { }
+
+ const int A;
+ };
+
+ New<TExplicitObj>();
+ New<TExplicitObj>(1);
+
+ struct TObj2 final
+ {
+ TObj2(i64 a = 0)
+ : A(a)
+ { }
+
+ const i64 A;
+ };
+
+ New<TObj2>(123);
+
+ struct TObj3 final
+ {
+ TObj3(ui64 a = 0)
+ : A(a)
+ { }
+
+ const ui64 A;
+ };
+
+ New<TObj3>(123);
+
+ struct TObj4 final
+ {
+ TObj4(int a, ui64 b = 0)
+ : A(a)
+ , B(b)
+ { }
+
+ int A;
+ const ui64 B;
+ };
+
+ New<TObj4>(123);
+ New<TObj4>(123, 123);
+
+ struct TObj5 final
+ {
+ TExplicitObj E;
+ int B;
+ };
+
+ New<TObj5>();
+
+ struct TObj6 final
+ {
+ TObj2 O;
+ int B;
+ };
+
+ New<TObj6>();
+ New<TObj6>(1, 2);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT
diff --git a/library/cpp/yt/memory/unittests/weak_ptr_ut.cpp b/library/cpp/yt/memory/unittests/weak_ptr_ut.cpp
new file mode 100644
index 0000000000..180c16b5ca
--- /dev/null
+++ b/library/cpp/yt/memory/unittests/weak_ptr_ut.cpp
@@ -0,0 +1,433 @@
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <library/cpp/yt/memory/new.h>
+#include <library/cpp/yt/memory/weak_ptr.h>
+
+#include <array>
+
+namespace NYT {
+namespace {
+
+using ::testing::IsNull;
+using ::testing::NotNull;
+using ::testing::InSequence;
+using ::testing::MockFunction;
+using ::testing::StrictMock;
+
+////////////////////////////////////////////////////////////////////////////////
+// Auxiliary types and functions.
+////////////////////////////////////////////////////////////////////////////////
+
+static int ConstructorShadowState = 0;
+static int DestructorShadowState = 0;
+
+void ResetShadowState()
+{
+ ConstructorShadowState = 0;
+ DestructorShadowState = 0;
+}
+
+class TIntricateObject
+ : public TRefCounted
+{
+public:
+ TIntricateObject()
+ {
+ ++ConstructorShadowState;
+ }
+
+ virtual ~TIntricateObject()
+ {
+ ++DestructorShadowState;
+ }
+
+ // Prevent the counter from destruction by holding an additional
+ // reference to the counter.
+ void LockCounter()
+ {
+ WeakRef();
+ }
+
+ // Release an additional reference to the reference counter acquired by
+ // #LockCounter().
+ void UnlockCounter()
+ {
+ WeakUnref();
+ }
+
+private:
+ // Explicitly non-copyable.
+ TIntricateObject(const TIntricateObject&);
+ TIntricateObject(TIntricateObject&&);
+ TIntricateObject& operator=(const TIntricateObject&);
+ TIntricateObject& operator=(TIntricateObject&&);
+};
+
+typedef TIntrusivePtr<TIntricateObject> TIntricateObjectPtr;
+typedef TWeakPtr<TIntricateObject> TIntricateObjectWkPtr;
+
+class TDerivedIntricateObject
+ : public TIntricateObject
+{
+private:
+ // Payload.
+ [[maybe_unused]] std::array<char, 32> Payload;
+};
+
+typedef TIntrusivePtr<TDerivedIntricateObject> TDerivedIntricateObjectPtr;
+typedef TWeakPtr<TDerivedIntricateObject> TDerivedIntricateObjectWkPtr;
+
+MATCHER_P2(HasRefCounts, strongRefs, weakRefs,
+ "The object has "
+ + ::testing::PrintToString(strongRefs) + " strong and "
+ + ::testing::PrintToString(weakRefs) + " weak references")
+{
+ Y_UNUSED(result_listener);
+ return
+ arg.GetRefCount() == strongRefs &&
+ arg.GetWeakRefCount() == weakRefs;
+}
+
+template <class T>
+void PrintExtrinsicRefCounted(const T& arg, ::std::ostream* os)
+{
+ *os << arg.GetRefCount() << " strong and "
+ << arg.GetWeakRefCount() << " weak references";
+}
+
+void PrintTo(const TIntricateObject& arg, ::std::ostream* os)
+{
+ PrintExtrinsicRefCounted(arg, os);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TWeakPtrTest
+ : public ::testing::Test
+{
+public:
+ virtual void SetUp()
+ {
+ ResetShadowState();
+ }
+};
+
+TEST_F(TWeakPtrTest, Empty)
+{
+ TIntricateObjectWkPtr emptyPointer;
+ EXPECT_EQ(TIntricateObjectPtr(), emptyPointer.Lock());
+}
+
+TEST_F(TWeakPtrTest, Basic)
+{
+ TIntricateObjectPtr object = New<TIntricateObject>();
+ TIntricateObject* objectPtr = object.Get();
+
+ EXPECT_THAT(*object, HasRefCounts(1, 1));
+
+ {
+ TIntricateObjectWkPtr ptr(objectPtr);
+ EXPECT_THAT(*object, HasRefCounts(1, 2));
+ EXPECT_EQ(object, ptr.Lock());
+ }
+
+ EXPECT_THAT(*object, HasRefCounts(1, 1));
+
+ {
+ TIntricateObjectWkPtr ptr(object);
+ EXPECT_THAT(*object, HasRefCounts(1, 2));
+ EXPECT_EQ(object, ptr.Lock());
+ }
+
+ EXPECT_THAT(*object, HasRefCounts(1, 1));
+
+ object.Reset();
+
+ EXPECT_EQ(1, ConstructorShadowState);
+ EXPECT_EQ(1, DestructorShadowState);
+}
+
+TEST_F(TWeakPtrTest, ResetToNull)
+{
+ TIntricateObjectPtr object = New<TIntricateObject>();
+ TIntricateObjectWkPtr ptr(object);
+
+ EXPECT_THAT(*object, HasRefCounts(1, 2));
+ EXPECT_EQ(object, ptr.Lock());
+
+ ptr.Reset();
+
+ EXPECT_THAT(*object, HasRefCounts(1, 1));
+ EXPECT_EQ(TIntricateObjectPtr(), ptr.Lock());
+}
+
+TEST_F(TWeakPtrTest, ResetToOtherObject)
+{
+ TIntricateObjectPtr firstObject = New<TIntricateObject>();
+ TIntricateObjectPtr secondObject = New<TIntricateObject>();
+
+ {
+ TIntricateObjectWkPtr ptr(firstObject);
+
+ EXPECT_THAT(*firstObject, HasRefCounts(1, 2));
+ EXPECT_THAT(*secondObject, HasRefCounts(1, 1));
+ EXPECT_EQ(firstObject, ptr.Lock());
+
+ ptr.Reset(secondObject);
+
+ EXPECT_THAT(*firstObject, HasRefCounts(1, 1));
+ EXPECT_THAT(*secondObject, HasRefCounts(1, 2));
+ EXPECT_EQ(secondObject, ptr.Lock());
+ }
+
+ TIntricateObject* firstObjectPtr = firstObject.Get();
+ TIntricateObject* secondObjectPtr = secondObject.Get();
+
+ {
+ TIntricateObjectWkPtr ptr(firstObjectPtr);
+
+ EXPECT_THAT(*firstObject, HasRefCounts(1, 2));
+ EXPECT_THAT(*secondObject, HasRefCounts(1, 1));
+ EXPECT_EQ(firstObject, ptr.Lock());
+
+ ptr.Reset(secondObjectPtr);
+
+ EXPECT_THAT(*firstObject, HasRefCounts(1, 1));
+ EXPECT_THAT(*secondObject, HasRefCounts(1, 2));
+ EXPECT_EQ(secondObject, ptr.Lock());
+ }
+}
+
+TEST_F(TWeakPtrTest, CopySemantics)
+{
+ TIntricateObjectPtr object = New<TIntricateObject>();
+ TIntricateObjectWkPtr foo(object);
+
+ {
+ EXPECT_THAT(*object, HasRefCounts(1, 2));
+ TIntricateObjectWkPtr bar(foo);
+ EXPECT_THAT(*object, HasRefCounts(1, 3));
+
+ EXPECT_EQ(object, foo.Lock());
+ EXPECT_EQ(object, bar.Lock());
+ }
+
+ {
+ EXPECT_THAT(*object, HasRefCounts(1, 2));
+ TIntricateObjectWkPtr bar;
+ bar = foo;
+ EXPECT_THAT(*object, HasRefCounts(1, 3));
+
+ EXPECT_EQ(object, foo.Lock());
+ EXPECT_EQ(object, bar.Lock());
+ }
+}
+
+TEST_F(TWeakPtrTest, MoveSemantics)
+{
+ TIntricateObjectPtr object = New<TIntricateObject>();
+ TIntricateObjectWkPtr foo(object);
+
+ {
+ EXPECT_THAT(*object, HasRefCounts(1, 2));
+ TIntricateObjectWkPtr bar(std::move(foo));
+ EXPECT_THAT(*object, HasRefCounts(1, 2));
+
+ EXPECT_EQ(TIntricateObjectPtr(), foo.Lock());
+ EXPECT_EQ(object, bar.Lock());
+ }
+
+ foo.Reset(object);
+
+ {
+ EXPECT_THAT(*object, HasRefCounts(1, 2));
+ TIntricateObjectWkPtr bar;
+ bar = std::move(foo);
+ EXPECT_THAT(*object, HasRefCounts(1, 2));
+
+ EXPECT_EQ(TIntricateObjectPtr(), foo.Lock());
+ EXPECT_EQ(object, bar.Lock());
+ }
+}
+
+TEST_F(TWeakPtrTest, OutOfScope)
+{
+ TIntricateObjectWkPtr ptr;
+
+ EXPECT_EQ(TIntricateObjectPtr(), ptr.Lock());
+ {
+ TIntricateObjectPtr object = New<TIntricateObject>();
+ ptr = object;
+ EXPECT_EQ(object, ptr.Lock());
+ }
+ EXPECT_EQ(TIntricateObjectPtr(), ptr.Lock());
+}
+
+TEST_F(TWeakPtrTest, OutOfNestedScope)
+{
+ TIntricateObjectWkPtr foo;
+
+ EXPECT_EQ(TIntricateObjectPtr(), foo.Lock());
+ {
+ TIntricateObjectPtr object = New<TIntricateObject>();
+ foo = object;
+
+ EXPECT_EQ(object, foo.Lock());
+ {
+ TIntricateObjectWkPtr bar;
+ bar = object;
+
+ EXPECT_EQ(object, bar.Lock());
+ }
+ EXPECT_EQ(object, foo.Lock());
+ }
+ EXPECT_EQ(TIntricateObjectPtr(), foo.Lock());
+
+ EXPECT_EQ(1, ConstructorShadowState);
+ EXPECT_EQ(1, DestructorShadowState);
+}
+
+TEST_F(TWeakPtrTest, IsExpired)
+{
+ TIntricateObjectWkPtr ptr;
+
+ EXPECT_TRUE(ptr.IsExpired());
+ {
+ TIntricateObjectPtr object = New<TIntricateObject>();
+ ptr = object;
+ EXPECT_FALSE(ptr.IsExpired());
+ }
+ EXPECT_TRUE(ptr.IsExpired());
+}
+
+TEST_F(TWeakPtrTest, UpCast)
+{
+ TDerivedIntricateObjectPtr object = New<TDerivedIntricateObject>();
+ TIntricateObjectWkPtr ptr = object;
+
+ EXPECT_EQ(object.Get(), ptr.Lock().Get());
+}
+
+class TIntricateObjectVirtual
+ : public virtual TRefCounted
+{
+public:
+ TIntricateObjectVirtual()
+ {
+ ++ConstructorShadowState;
+ }
+
+ virtual ~TIntricateObjectVirtual()
+ {
+ ++DestructorShadowState;
+ }
+
+ // Prevent the counter from destruction by holding an additional
+ // reference to the counter.
+ void LockCounter()
+ {
+ WeakRef();
+ }
+
+ // Release an additional reference to the reference counter acquired by
+ // #LockCounter().
+ void UnlockCounter()
+ {
+ WeakUnref();
+ }
+
+private:
+ // Explicitly non-copyable.
+ TIntricateObjectVirtual(const TIntricateObjectVirtual&);
+ TIntricateObjectVirtual(TIntricateObjectVirtual&&);
+ TIntricateObjectVirtual& operator=(const TIntricateObjectVirtual&);
+ TIntricateObjectVirtual& operator=(TIntricateObjectVirtual&&);
+};
+
+TEST_F(TWeakPtrTest, VirtualBase)
+{
+ auto object = New<TIntricateObjectVirtual>();
+ TWeakPtr<TIntricateObjectVirtual> ptr = object;
+
+ object.Reset();
+ ptr.Reset();
+}
+
+#if 0
+class TSlowlyDyingObject
+ : public TRefCounted
+{
+public:
+ TSlowlyDyingObject()
+ {
+ ++ConstructorShadowState;
+ }
+
+ virtual ~TSlowlyDyingObject()
+ {
+ ++DestructorShadowState;
+ DeathEvent->Wait();
+ ++DestructorShadowState;
+ }
+};
+
+void PrintTo(const TSlowlyDyingObject& arg, ::std::ostream* os)
+{
+ PrintExtrinsicRefCounted(arg, os);
+}
+
+typedef TIntrusivePtr<TSlowlyDyingObject> TSlowlyDyingObjectPtr;
+typedef TWeakPtr<TSlowlyDyingObject> TSlowlyDyingObjectWkPtr;
+
+static void* AsynchronousDeleter(void* param)
+{
+ TSlowlyDyingObjectPtr* indirectObject =
+ reinterpret_cast<TSlowlyDyingObjectPtr*>(param);
+ indirectObject->Reset();
+ return nullptr;
+}
+
+std::unique_ptr<NThreading::TEvent> DeathEvent;
+
+TEST_F(TWeakPtrTest, DISABLED_AcquisionOfSlowlyDyingObject)
+{
+ DeathEvent.reset(new NThreading::TEvent());
+
+ TSlowlyDyingObjectPtr object = New<TSlowlyDyingObject>();
+ TSlowlyDyingObjectWkPtr ptr(object);
+
+ TSlowlyDyingObject* objectPtr = object.Get();
+
+ EXPECT_EQ(object, ptr.Lock());
+ EXPECT_THAT(*objectPtr, HasRefCounts(1, 2));
+
+ ASSERT_EQ(1, ConstructorShadowState);
+ ASSERT_EQ(0, DestructorShadowState);
+
+ // Kick off object deletion in the background.
+ TThread thread(&AsynchronousDeleter, &object);
+ thread.Start();
+ Sleep(TDuration::Seconds(0.100));
+
+ ASSERT_EQ(1, ConstructorShadowState);
+ ASSERT_EQ(1, DestructorShadowState);
+
+ EXPECT_EQ(TSlowlyDyingObjectPtr(), ptr.Lock());
+ EXPECT_THAT(*objectPtr, HasRefCounts(0, 2));
+
+ // Finalize object destruction.
+ DeathEvent->NotifyAll();
+ thread.Join();
+
+ ASSERT_EQ(1, ConstructorShadowState);
+ ASSERT_EQ(2, DestructorShadowState);
+
+ EXPECT_EQ(TSlowlyDyingObjectPtr(), ptr.Lock());
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT
diff --git a/library/cpp/yt/memory/unittests/ya.make b/library/cpp/yt/memory/unittests/ya.make
new file mode 100644
index 0000000000..f09ad7d0c9
--- /dev/null
+++ b/library/cpp/yt/memory/unittests/ya.make
@@ -0,0 +1,19 @@
+GTEST(unittester-library-memory)
+
+OWNER(g:yt)
+
+IF (NOT OS_WINDOWS)
+ ALLOCATOR(YT)
+ENDIF()
+
+SRCS(
+ intrusive_ptr_ut.cpp
+ weak_ptr_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/testing/gtest
+ library/cpp/yt/memory
+)
+
+END()
diff --git a/library/cpp/yt/memory/weak_ptr.h b/library/cpp/yt/memory/weak_ptr.h
new file mode 100644
index 0000000000..25a242bb8a
--- /dev/null
+++ b/library/cpp/yt/memory/weak_ptr.h
@@ -0,0 +1,314 @@
+#pragma once
+
+#include "ref_counted.h"
+
+#include <util/generic/hash.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+class TWeakPtr
+{
+public:
+ typedef T TUnderlying;
+
+ //! Empty constructor.
+ TWeakPtr() = default;
+
+ TWeakPtr(std::nullptr_t)
+ { }
+
+ //! Constructor from an unqualified reference.
+ /*!
+ * Note that this constructor could be racy due to unsynchronized operations
+ * on the object and on the counter.
+ */
+ explicit TWeakPtr(T* p) noexcept
+ : T_(p)
+ {
+
+#if defined(_tsan_enabled_)
+ if (T_) {
+ RefCounter_ = GetRefCounter(T_);
+ }
+#endif
+ AcquireRef();
+ }
+
+ //! Constructor from a strong reference.
+ TWeakPtr(const TIntrusivePtr<T>& ptr) noexcept
+ : TWeakPtr(ptr.Get())
+ { }
+
+ //! Constructor from a strong reference with an upcast.
+ template <class U, class = typename std::enable_if_t<std::is_convertible_v<U*, T*>>>
+ TWeakPtr(const TIntrusivePtr<U>& ptr) noexcept
+ : TWeakPtr(ptr.Get())
+ {
+ static_assert(
+ std::is_base_of_v<TRefCountedBase, T>,
+ "Cast allowed only for types derived from TRefCountedBase");
+ }
+
+ //! Copy constructor.
+ TWeakPtr(const TWeakPtr& other) noexcept
+ : TWeakPtr(other.T_)
+ { }
+
+ //! Copy constructor with an upcast.
+ template <class U, class = typename std::enable_if_t<std::is_convertible_v<U*, T*>>>
+ TWeakPtr(const TWeakPtr<U>& other) noexcept
+ : TWeakPtr(other.Lock())
+ {
+ static_assert(
+ std::is_base_of_v<TRefCountedBase, T>,
+ "Cast allowed only for types derived from TRefCountedBase");
+ }
+
+ //! Move constructor.
+ TWeakPtr(TWeakPtr&& other) noexcept
+ {
+ other.Swap(*this);
+ }
+
+ //! Move constructor with an upcast.
+ template <class U, class = typename std::enable_if_t<std::is_convertible_v<U*, T*>>>
+ TWeakPtr(TWeakPtr<U>&& other) noexcept
+ {
+ static_assert(
+ std::is_base_of_v<TRefCountedBase, T>,
+ "Cast allowed only for types derived from TRefCountedBase");
+ TIntrusivePtr<U> strongOther = other.Lock();
+ if (strongOther) {
+ T_ = other.T_;
+ other.T_ = nullptr;
+
+#if defined(_tsan_enabled_)
+ RefCounter_ = other.RefCounter_;
+ other.RefCounter_ = nullptr;
+#endif
+ }
+ }
+
+ //! Destructor.
+ ~TWeakPtr()
+ {
+ ReleaseRef();
+ }
+
+ //! Assignment operator from a strong reference.
+ template <class U>
+ TWeakPtr& operator=(const TIntrusivePtr<U>& ptr) noexcept
+ {
+ static_assert(
+ std::is_convertible_v<U*, T*>,
+ "U* must be convertible to T*");
+ TWeakPtr(ptr).Swap(*this);
+ return *this;
+ }
+
+ //! Copy assignment operator.
+ TWeakPtr& operator=(const TWeakPtr& other) noexcept
+ {
+ TWeakPtr(other).Swap(*this);
+ return *this;
+ }
+
+ //! Copy assignment operator with an upcast.
+ template <class U>
+ TWeakPtr& operator=(const TWeakPtr<U>& other) noexcept
+ {
+ static_assert(
+ std::is_convertible_v<U*, T*>,
+ "U* must be convertible to T*");
+ TWeakPtr(other).Swap(*this);
+ return *this;
+ }
+
+ //! Move assignment operator.
+ TWeakPtr& operator=(TWeakPtr&& other) noexcept
+ {
+ other.Swap(*this);
+ return *this;
+ }
+
+ //! Move assignment operator with an upcast.
+ template <class U>
+ TWeakPtr& operator=(TWeakPtr<U>&& other) noexcept
+ {
+ static_assert(
+ std::is_convertible_v<U*, T*>,
+ "U* must be convertible to T*");
+ TWeakPtr(std::move(other)).Swap(*this);
+ return *this;
+ }
+
+ //! Drop the pointer.
+ void Reset() // noexcept
+ {
+ TWeakPtr().Swap(*this);
+ }
+
+ //! Replace the pointer with a specified one.
+ void Reset(T* p) // noexcept
+ {
+ TWeakPtr(p).Swap(*this);
+ }
+
+ //! Replace the pointer with a specified one.
+ template <class U>
+ void Reset(const TIntrusivePtr<U>& ptr) // noexcept
+ {
+ static_assert(
+ std::is_convertible_v<U*, T*>,
+ "U* must be convertible to T*");
+ TWeakPtr(ptr).Swap(*this);
+ }
+
+ //! Swap the pointer with the other one.
+ void Swap(TWeakPtr& other) noexcept
+ {
+ DoSwap(T_, other.T_);
+#if defined(_tsan_enabled_)
+ DoSwap(RefCounter_, other.RefCounter_);
+#endif
+ }
+
+ //! Acquire a strong reference to the pointee and return a strong pointer.
+ TIntrusivePtr<T> Lock() const noexcept
+ {
+ return T_ && RefCounter()->TryRef()
+ ? TIntrusivePtr<T>(T_, false)
+ : TIntrusivePtr<T>();
+ }
+
+ bool IsExpired() const noexcept
+ {
+ return !T_ || (RefCounter()->GetRefCount() == 0);
+ }
+
+private:
+ void AcquireRef()
+ {
+ if (T_) {
+ RefCounter()->WeakRef();
+ }
+ }
+
+ void ReleaseRef()
+ {
+ if (T_) {
+ // Support incomplete type.
+ if (RefCounter()->WeakUnref()) {
+ DeallocateRefCounted(T_);
+ }
+ }
+ }
+
+ template <class U>
+ friend class TWeakPtr;
+ template <class U>
+ friend struct ::THash;
+
+ T* T_ = nullptr;
+#if defined(_tsan_enabled_)
+ const TRefCounter* RefCounter_ = nullptr;
+
+ const TRefCounter* RefCounter() const
+ {
+ return RefCounter_;
+ }
+#else
+ const TRefCounter* RefCounter() const
+ {
+ return GetRefCounter(T_);
+ }
+#endif
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Creates a weak pointer wrapper for a given raw pointer.
+//! Compared to |TWeakPtr<T>::ctor|, type inference enables omitting |T|.
+template <class T>
+TWeakPtr<T> MakeWeak(T* p)
+{
+ return TWeakPtr<T>(p);
+}
+
+//! Creates a weak pointer wrapper for a given intrusive pointer.
+//! Compared to |TWeakPtr<T>::ctor|, type inference enables omitting |T|.
+template <class T>
+TWeakPtr<T> MakeWeak(const TIntrusivePtr<T>& p)
+{
+ return TWeakPtr<T>(p);
+}
+
+//! A helper for acquiring weak pointer for pointee, resetting intrusive pointer and then
+//! returning the pointee reference count using the acquired weak pointer.
+//! This helper is designed for best effort in checking that the object is not leaked after
+//! destructing (what seems to be) the last pointer to it.
+//! NB: it is possible to rewrite this helper making it working event with intrinsic refcounted objects,
+//! but it requires much nastier integration with the intrusive pointer destruction routines.
+template <typename T>
+int ResetAndGetResidualRefCount(TIntrusivePtr<T>& pointer)
+{
+ auto weakPointer = MakeWeak(pointer);
+ pointer.Reset();
+ if (pointer = weakPointer.Lock()) {
+ // This _may_ return 0 if we are again the only holder of the pointee.
+ return pointer->GetRefCount() - 1;
+ } else {
+ return 0;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// TODO(sandello): Kill comparsions.
+template <class T>
+bool operator<(const TWeakPtr<T>& lhs, const TWeakPtr<T>& rhs)
+{
+ return lhs.Lock().Get() < rhs.Lock().Get();
+}
+
+template <class T>
+bool operator>(const TWeakPtr<T>& lhs, const TWeakPtr<T>& rhs)
+{
+ return lhs.Lock().Get() > rhs.Lock().Get();
+}
+
+template <class T, class U>
+bool operator==(const TWeakPtr<T>& lhs, const TWeakPtr<U>& rhs)
+{
+ static_assert(
+ std::is_convertible_v<U*, T*>,
+ "U* must be convertible to T*");
+ return lhs.Lock().Get() == rhs.Lock().Get();
+}
+
+template <class T, class U>
+bool operator!=(const TWeakPtr<T>& lhs, const TWeakPtr<U>& rhs)
+{
+ static_assert(
+ std::is_convertible_v<U*, T*>,
+ "U* must be convertible to T*");
+ return lhs.Lock().Get() != rhs.Lock().Get();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+
+//! A hasher for TWeakPtr.
+template <class T>
+struct THash<NYT::TWeakPtr<T>>
+{
+ size_t operator () (const NYT::TWeakPtr<T>& ptr) const
+ {
+ return THash<const NYT::TRefCountedBase*>()(ptr.T_);
+ }
+};
diff --git a/library/cpp/yt/memory/ya.make b/library/cpp/yt/memory/ya.make
new file mode 100644
index 0000000000..a925c714ee
--- /dev/null
+++ b/library/cpp/yt/memory/ya.make
@@ -0,0 +1,31 @@
+LIBRARY()
+
+OWNER(g:yt)
+
+SRCS(
+ blob.cpp
+ ref.cpp
+ ref_tracked.cpp
+)
+
+PEERDIR(
+ library/cpp/yt/assert
+ library/cpp/yt/misc
+ library/cpp/ytalloc/api
+)
+
+CHECK_DEPENDENT_DIRS(
+ ALLOW_ONLY ALL
+ build
+ contrib
+ library
+ util
+ library/cpp/yt/assert
+ library/cpp/yt/misc
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ unittests
+)
diff --git a/library/cpp/yt/misc/cast-inl.h b/library/cpp/yt/misc/cast-inl.h
new file mode 100644
index 0000000000..1920b7c0b7
--- /dev/null
+++ b/library/cpp/yt/misc/cast-inl.h
@@ -0,0 +1,113 @@
+#ifndef CAST_INL_H_
+#error "Direct inclusion of this file is not allowed, include cast.h"
+// For the sake of sane code completion.
+#include "cast.h"
+#endif
+
+#include <util/string/cast.h>
+#include <util/string/printf.h>
+
+#include <type_traits>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace NDetail {
+
+template <class T, class S>
+typename std::enable_if<std::is_signed<T>::value && std::is_signed<S>::value, bool>::type IsInIntegralRange(S value)
+{
+ return value >= std::numeric_limits<T>::min() && value <= std::numeric_limits<T>::max();
+}
+
+template <class T, class S>
+static typename std::enable_if<std::is_signed<T>::value && std::is_unsigned<S>::value, bool>::type IsInIntegralRange(S value)
+{
+ return value <= static_cast<typename std::make_unsigned<T>::type>(std::numeric_limits<T>::max());
+}
+
+template <class T, class S>
+static typename std::enable_if<std::is_unsigned<T>::value && std::is_signed<S>::value, bool>::type IsInIntegralRange(S value)
+{
+ return value >= 0 && static_cast<typename std::make_unsigned<S>::type>(value) <= std::numeric_limits<T>::max();
+}
+
+template <class T, class S>
+typename std::enable_if<std::is_unsigned<T>::value && std::is_unsigned<S>::value, bool>::type IsInIntegralRange(S value)
+{
+ return value <= std::numeric_limits<T>::max();
+}
+
+template <class T>
+TString FormatInvalidCastValue(T value)
+{
+ return ::ToString(value);
+}
+
+inline TString FormatInvalidCastValue(signed char value)
+{
+ return TString("'") + value + TString("'");
+}
+
+inline TString FormatInvalidCastValue(unsigned char value)
+{
+ return TString("'") + value + TString("'");
+}
+
+#ifdef __cpp_char8_t
+inline TString FormatInvalidCastValue(char8_t value)
+{
+ return FormatInvalidCastValue(static_cast<unsigned char>(value));
+}
+#endif
+
+} // namespace NDetail
+
+template <class T, class S>
+bool TryIntegralCast(S value, T* result)
+{
+ if (!NDetail::IsInIntegralRange<T>(value)) {
+ return false;
+ }
+ *result = static_cast<T>(value);
+ return true;
+}
+
+template <class T, class S>
+T CheckedIntegralCast(S value)
+{
+ T result;
+ if (!TryIntegralCast<T>(value, &result)) {
+ throw TSimpleException(Sprintf("Argument value %s is out of expected range",
+ NDetail::FormatInvalidCastValue(value).c_str()));
+ }
+ return result;
+}
+
+template <class T, class S>
+bool TryEnumCast(S value, T* result)
+{
+ auto candidate = static_cast<T>(value);
+ if (!TEnumTraits<T>::FindLiteralByValue(candidate)) {
+ return false;
+ }
+ *result = candidate;
+ return true;
+}
+
+template <class T, class S>
+T CheckedEnumCast(S value)
+{
+ T result;
+ if (!TryEnumCast<T>(value, &result)) {
+ throw TSimpleException(Sprintf("Invalid value %d of enum type %s",
+ static_cast<int>(value),
+ TEnumTraits<T>::GetTypeName().data()));
+ }
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/misc/cast.h b/library/cpp/yt/misc/cast.h
new file mode 100644
index 0000000000..c7565c9e6d
--- /dev/null
+++ b/library/cpp/yt/misc/cast.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <library/cpp/yt/exception/exception.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, class S>
+bool TryIntegralCast(S value, T* result);
+
+template <class T, class S>
+T CheckedIntegralCast(S value);
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, class S>
+bool TryEnumCast(S value, T* result);
+
+template <class T, class S>
+T CheckedEnumCast(S value);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define CAST_INL_H_
+#include "cast-inl.h"
+#undef CAST_INL_H_
diff --git a/library/cpp/yt/misc/enum-inl.h b/library/cpp/yt/misc/enum-inl.h
new file mode 100644
index 0000000000..59ef704775
--- /dev/null
+++ b/library/cpp/yt/misc/enum-inl.h
@@ -0,0 +1,385 @@
+#pragma once
+#ifndef ENUM_INL_H_
+#error "Direct inclusion of this file is not allowed, include enum.h"
+// For the sake of sane code completion.
+#include "enum.h"
+#endif
+
+#include <util/string/printf.h>
+#include <util/string/cast.h>
+
+#include <algorithm>
+#include <stdexcept>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define ENUM__CLASS(name, underlyingType, seq) \
+ enum class name : underlyingType \
+ { \
+ PP_FOR_EACH(ENUM__DOMAIN_ITEM, seq) \
+ };
+
+#define ENUM__DOMAIN_ITEM(item) \
+ PP_IF( \
+ PP_IS_SEQUENCE(item), \
+ ENUM__DOMAIN_ITEM_SEQ, \
+ ENUM__DOMAIN_ITEM_ATOMIC \
+ )(item)()
+
+#define ENUM__DOMAIN_ITEM_ATOMIC(item) \
+ item PP_COMMA
+
+#define ENUM__DOMAIN_ITEM_SEQ(seq) \
+ PP_ELEMENT(seq, 0) = PP_ELEMENT(seq, 1) PP_COMMA
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace NDetail {
+
+template <typename TValues>
+static constexpr bool AreValuesDistinct(const TValues& values)
+{
+ for (int i = 0; i < static_cast<int>(values.size()); ++i) {
+ for (int j = i + 1; j < static_cast<int>(values.size()); ++j) {
+ if (values[i] == values[j]) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace NDetail
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define ENUM__BEGIN_TRAITS(name, underlyingType, isBit, isStringSerializable, seq) \
+ struct TEnumTraitsImpl_##name \
+ { \
+ using TType = name; \
+ using TUnderlying = underlyingType; \
+ [[maybe_unused]] static constexpr bool IsBitEnum = isBit; \
+ [[maybe_unused]] static constexpr bool IsStringSerializableEnum = isStringSerializable; \
+ [[maybe_unused]] static constexpr int DomainSize = PP_COUNT(seq); \
+ \
+ static constexpr std::array<TStringBuf, DomainSize> Names{{ \
+ PP_FOR_EACH(ENUM__GET_DOMAIN_NAMES_ITEM, seq) \
+ }}; \
+ static constexpr std::array<TType, DomainSize> Values{{ \
+ PP_FOR_EACH(ENUM__GET_DOMAIN_VALUES_ITEM, seq) \
+ }}; \
+ \
+ static TStringBuf GetTypeName() \
+ { \
+ static constexpr TStringBuf typeName = PP_STRINGIZE(name); \
+ return typeName; \
+ } \
+ \
+ static const TStringBuf* FindLiteralByValue(TType value) \
+ { \
+ for (int i = 0; i < DomainSize; ++i) { \
+ if (Values[i] == value) { \
+ return &Names[i]; \
+ } \
+ } \
+ return nullptr; \
+ } \
+ \
+ static bool FindValueByLiteral(TStringBuf literal, TType* result) \
+ { \
+ for (int i = 0; i < DomainSize; ++i) { \
+ if (Names[i] == literal) { \
+ *result = Values[i]; \
+ return true; \
+ } \
+ } \
+ return false; \
+ } \
+ \
+ static const std::array<TStringBuf, DomainSize>& GetDomainNames() \
+ { \
+ return Names; \
+ } \
+ \
+ static const std::array<TType, DomainSize>& GetDomainValues() \
+ { \
+ return Values; \
+ } \
+ \
+ static TType FromString(TStringBuf str) \
+ { \
+ TType value; \
+ if (!FindValueByLiteral(str, &value)) { \
+ throw ::NYT::TSimpleException(Sprintf("Error parsing %s value %s", \
+ PP_STRINGIZE(name), \
+ TString(str).Quote().c_str()).c_str()); \
+ } \
+ return value; \
+ }
+
+#define ENUM__GET_DOMAIN_VALUES_ITEM(item) \
+ PP_IF( \
+ PP_IS_SEQUENCE(item), \
+ ENUM__GET_DOMAIN_VALUES_ITEM_SEQ, \
+ ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC \
+ )(item)
+
+#define ENUM__GET_DOMAIN_VALUES_ITEM_SEQ(seq) \
+ ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC(PP_ELEMENT(seq, 0))
+
+#define ENUM__GET_DOMAIN_VALUES_ITEM_ATOMIC(item) \
+ TType::item,
+
+#define ENUM__GET_DOMAIN_NAMES_ITEM(item) \
+ PP_IF( \
+ PP_IS_SEQUENCE(item), \
+ ENUM__GET_DOMAIN_NAMES_ITEM_SEQ, \
+ ENUM__GET_DOMAIN_NAMES_ITEM_ATOMIC \
+ )(item)
+
+#define ENUM__GET_DOMAIN_NAMES_ITEM_SEQ(seq) \
+ ENUM__GET_DOMAIN_NAMES_ITEM_ATOMIC(PP_ELEMENT(seq, 0))
+
+#define ENUM__GET_DOMAIN_NAMES_ITEM_ATOMIC(item) \
+ TStringBuf(PP_STRINGIZE(item)),
+
+#define ENUM__DECOMPOSE \
+ static std::vector<TType> Decompose(TType value) \
+ { \
+ std::vector<TType> result; \
+ for (int i = 0; i < DomainSize; ++i) { \
+ if (static_cast<TUnderlying>(value) & static_cast<TUnderlying>(Values[i])) { \
+ result.push_back(Values[i]); \
+ } \
+ } \
+ return result; \
+ }
+
+#define ENUM__MINMAX \
+ static constexpr TType GetMinValue() \
+ { \
+ static_assert(!Values.empty()); \
+ return *std::min_element(std::begin(Values), std::end(Values)); \
+ } \
+ \
+ static constexpr TType GetMaxValue() \
+ { \
+ static_assert(!Values.empty()); \
+ return *std::max_element(std::begin(Values), std::end(Values)); \
+ }
+
+#define ENUM__VALIDATE_UNIQUE(name) \
+ static_assert(::NYT::NDetail::AreValuesDistinct(Values), \
+ "Enumeration " #name " contains duplicate values");
+
+#define ENUM__END_TRAITS(name) \
+ }; \
+ \
+ [[maybe_unused]] inline TEnumTraitsImpl_##name GetEnumTraitsImpl(name) \
+ { \
+ return TEnumTraitsImpl_##name(); \
+ } \
+ \
+ using ::ToString; \
+ [[maybe_unused]] inline TString ToString(name value) \
+ { \
+ return ::NYT::TEnumTraits<name>::ToString(value); \
+ }
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+std::vector<T> TEnumTraits<T, true>::Decompose(T value)
+{
+ return TImpl::Decompose(value);
+}
+
+template <class T>
+T TEnumTraits<T, true>::FromString(TStringBuf str)
+{
+ return TImpl::FromString(str);
+}
+
+template <class T>
+TString TEnumTraits<T, true>::ToString(TType value)
+{
+ TString result;
+ const auto* literal = FindLiteralByValue(value);
+ if (literal) {
+ result = *literal;
+ } else {
+ result = GetTypeName();
+ result += "(";
+ result += ::ToString(static_cast<TUnderlying>(value));
+ result += ")";
+ }
+ return result;
+}
+
+template <class T>
+auto TEnumTraits<T, true>::GetDomainValues() -> const std::array<T, DomainSize>&
+{
+ return TImpl::GetDomainValues();
+}
+
+template <class T>
+auto TEnumTraits<T, true>::GetDomainNames() -> const std::array<TStringBuf, DomainSize>&
+{
+ return TImpl::GetDomainNames();
+}
+
+template <class T>
+constexpr T TEnumTraits<T, true>::GetMaxValue()
+{
+ return TImpl::GetMaxValue();
+}
+
+template <class T>
+constexpr T TEnumTraits<T, true>::GetMinValue()
+{
+ return TImpl::GetMinValue();
+}
+
+template <class T>
+bool TEnumTraits<T, true>::FindValueByLiteral(TStringBuf literal, TType* result)
+{
+ return TImpl::FindValueByLiteral(literal, result);
+}
+
+template <class T>
+const TStringBuf* TEnumTraits<T, true>::FindLiteralByValue(TType value)
+{
+ return TImpl::FindLiteralByValue(value);
+}
+
+template <class T>
+TStringBuf TEnumTraits<T, true>::GetTypeName()
+{
+ return TImpl::GetTypeName();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class E, class T, E Min, E Max>
+TEnumIndexedVector<E, T, Min, Max>::TEnumIndexedVector()
+ : Items_{}
+{ }
+
+template <class E, class T, E Min, E Max>
+TEnumIndexedVector<E, T, Min, Max>::TEnumIndexedVector(std::initializer_list<T> elements)
+ : Items_{}
+{
+ Y_ASSERT(std::distance(elements.begin(), elements.end()) <= N);
+ size_t index = 0;
+ for (const auto& element : elements) {
+ Items_[index++] = element;
+ }
+}
+
+template <class E, class T, E Min, E Max>
+T& TEnumIndexedVector<E, T, Min, Max>::operator[] (E index)
+{
+ Y_ASSERT(index >= Min && index <= Max);
+ return Items_[static_cast<TUnderlying>(index) - static_cast<TUnderlying>(Min)];
+}
+
+template <class E, class T, E Min, E Max>
+const T& TEnumIndexedVector<E, T, Min, Max>::operator[] (E index) const
+{
+ return const_cast<TEnumIndexedVector&>(*this)[index];
+}
+
+template <class E, class T, E Min, E Max>
+T* TEnumIndexedVector<E, T, Min, Max>::begin()
+{
+ return Items_.data();
+}
+
+template <class E, class T, E Min, E Max>
+const T* TEnumIndexedVector<E, T, Min, Max>::begin() const
+{
+ return Items_.data();
+}
+
+template <class E, class T, E Min, E Max>
+T* TEnumIndexedVector<E, T, Min, Max>::end()
+{
+ return begin() + N;
+}
+
+template <class E, class T, E Min, E Max>
+const T* TEnumIndexedVector<E, T, Min, Max>::end() const
+{
+ return begin() + N;
+}
+
+template <class E, class T, E Min, E Max>
+bool TEnumIndexedVector<E, T, Min, Max>::IsDomainValue(E value)
+{
+ return value >= Min && value <= Max;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define ENUM__BINARY_BITWISE_OPERATOR(T, assignOp, op) \
+ [[maybe_unused]] inline constexpr T operator op (T lhs, T rhs) \
+ { \
+ using TUnderlying = typename TEnumTraits<T>::TUnderlying; \
+ return T(static_cast<TUnderlying>(lhs) op static_cast<TUnderlying>(rhs)); \
+ } \
+ \
+ [[maybe_unused]] inline T& operator assignOp (T& lhs, T rhs) \
+ { \
+ using TUnderlying = typename TEnumTraits<T>::TUnderlying; \
+ lhs = T(static_cast<TUnderlying>(lhs) op static_cast<TUnderlying>(rhs)); \
+ return lhs; \
+ }
+
+#define ENUM__UNARY_BITWISE_OPERATOR(T, op) \
+ [[maybe_unused]] inline constexpr T operator op (T value) \
+ { \
+ using TUnderlying = typename TEnumTraits<T>::TUnderlying; \
+ return T(op static_cast<TUnderlying>(value)); \
+ }
+
+#define ENUM__BIT_SHIFT_OPERATOR(T, assignOp, op) \
+ [[maybe_unused]] inline constexpr T operator op (T lhs, size_t rhs) \
+ { \
+ using TUnderlying = typename TEnumTraits<T>::TUnderlying; \
+ return T(static_cast<TUnderlying>(lhs) op rhs); \
+ } \
+ \
+ [[maybe_unused]] inline T& operator assignOp (T& lhs, size_t rhs) \
+ { \
+ using TUnderlying = typename TEnumTraits<T>::TUnderlying; \
+ lhs = T(static_cast<TUnderlying>(lhs) op rhs); \
+ return lhs; \
+ }
+
+#define ENUM__BITWISE_OPS(name) \
+ ENUM__BINARY_BITWISE_OPERATOR(name, &=, &) \
+ ENUM__BINARY_BITWISE_OPERATOR(name, |=, | ) \
+ ENUM__BINARY_BITWISE_OPERATOR(name, ^=, ^) \
+ ENUM__UNARY_BITWISE_OPERATOR(name, ~) \
+ ENUM__BIT_SHIFT_OPERATOR(name, <<=, << ) \
+ ENUM__BIT_SHIFT_OPERATOR(name, >>=, >> )
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename E, typename>
+bool Any(E value)
+{
+ return static_cast<typename TEnumTraits<E>::TUnderlying>(value) != 0;
+}
+
+template <class E, typename>
+bool None(E value)
+{
+ return static_cast<typename TEnumTraits<E>::TUnderlying>(value) == 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/misc/enum.h b/library/cpp/yt/misc/enum.h
new file mode 100644
index 0000000000..894364aa43
--- /dev/null
+++ b/library/cpp/yt/misc/enum.h
@@ -0,0 +1,243 @@
+#pragma once
+
+#include "preprocessor.h"
+
+#include <util/generic/strbuf.h>
+
+#include <stdexcept>
+#include <type_traits>
+#include <array>
+#include <vector>
+
+#include <library/cpp/yt/exception/exception.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+/*
+ * Smart enumerations augment C++ enum classes with a bunch of reflection
+ * capabilities accessible via TEnumTraits class specialization.
+ *
+ * Please refer to the unit test for an actual example of usage
+ * (unittests/enum_ut.cpp).
+ */
+
+// Actual overload must be provided with defines DEFINE_ENUM_XXX (see below).
+template <class T>
+void GetEnumTraitsImpl(T);
+
+template <
+ class T,
+ bool = std::is_enum<T>::value &&
+ !std::is_convertible<T, int>::value &&
+ !std::is_same<void, decltype(GetEnumTraitsImpl(T()))>::value
+>
+struct TEnumTraits
+{
+ static constexpr bool IsEnum = false;
+ static constexpr bool IsBitEnum = false;
+ static constexpr bool IsStringSerializableEnum = false;
+};
+
+template <class T>
+struct TEnumTraits<T, true>
+{
+ using TImpl = decltype(GetEnumTraitsImpl(T()));
+ using TType = T;
+ using TUnderlying = typename TImpl::TUnderlying;
+
+ static constexpr bool IsEnum = true;
+ static constexpr bool IsBitEnum = TImpl::IsBitEnum;
+ static constexpr bool IsStringSerializableEnum = TImpl::IsStringSerializableEnum;
+
+ static constexpr int DomainSize = TImpl::DomainSize;
+
+ static TStringBuf GetTypeName();
+
+ static const TStringBuf* FindLiteralByValue(TType value);
+ static bool FindValueByLiteral(TStringBuf literal, TType* result);
+
+ static const std::array<TStringBuf, DomainSize>& GetDomainNames();
+ static const std::array<TType, DomainSize>& GetDomainValues();
+
+ static TType FromString(TStringBuf str);
+ static TString ToString(TType value);
+
+ // For non-bit enums only.
+ static constexpr TType GetMinValue();
+ static constexpr TType GetMaxValue();
+
+ // For bit enums only.
+ static std::vector<TType> Decompose(TType value);
+
+ // LLVM SmallDenseMap interop.
+ // This should only be used for enums whose underlying type has big enough range
+ // (see getEmptyKey and getTombstoneKey functions).
+ struct TDenseMapInfo
+ {
+ static inline TType getEmptyKey()
+ {
+ return static_cast<TType>(-1);
+ }
+
+ static inline TType getTombstoneKey()
+ {
+ return static_cast<TType>(-2);
+ }
+
+ static unsigned getHashValue(const TType& key)
+ {
+ return static_cast<unsigned>(key) * 37U;
+ }
+
+ static bool isEqual(const TType& lhs, const TType& rhs)
+ {
+ return lhs == rhs;
+ }
+ };
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Defines a smart enumeration with a specific underlying type.
+/*!
+ * \param name Enumeration name.
+ * \param seq Enumeration domain encoded as a <em>sequence</em>.
+ * \param underlyingType Underlying type.
+ */
+#define DEFINE_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \
+ ENUM__CLASS(name, underlyingType, seq) \
+ ENUM__BEGIN_TRAITS(name, underlyingType, false, false, seq) \
+ ENUM__MINMAX \
+ ENUM__VALIDATE_UNIQUE(name) \
+ ENUM__END_TRAITS(name)
+
+//! Defines a smart enumeration with a specific underlying type.
+//! Duplicate enumeration values are allowed.
+#define DEFINE_AMBIGUOUS_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \
+ ENUM__CLASS(name, underlyingType, seq) \
+ ENUM__BEGIN_TRAITS(name, underlyingType, false, false, seq) \
+ ENUM__MINMAX \
+ ENUM__END_TRAITS(name)
+
+//! Defines a smart enumeration with the default |int| underlying type.
+#define DEFINE_ENUM(name, seq) \
+ DEFINE_ENUM_WITH_UNDERLYING_TYPE(name, int, seq)
+
+//! Defines a smart enumeration with a specific underlying type.
+/*!
+ * \param name Enumeration name.
+ * \param seq Enumeration domain encoded as a <em>sequence</em>.
+ * \param underlyingType Underlying type.
+ */
+#define DEFINE_BIT_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \
+ ENUM__CLASS(name, underlyingType, seq) \
+ ENUM__BEGIN_TRAITS(name, underlyingType, true, false, seq) \
+ ENUM__DECOMPOSE \
+ ENUM__VALIDATE_UNIQUE(name) \
+ ENUM__END_TRAITS(name) \
+ ENUM__BITWISE_OPS(name)
+
+//! Defines a smart enumeration with a specific underlying type.
+//! Duplicate enumeration values are allowed.
+/*!
+ * \param name Enumeration name.
+ * \param seq Enumeration domain encoded as a <em>sequence</em>.
+ * \param underlyingType Underlying type.
+ */
+#define DEFINE_AMBIGUOUS_BIT_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \
+ ENUM__CLASS(name, underlyingType, seq) \
+ ENUM__BEGIN_TRAITS(name, underlyingType, true, false, seq) \
+ ENUM__DECOMPOSE \
+ ENUM__END_TRAITS(name) \
+ ENUM__BITWISE_OPS(name)
+
+//! Defines a smart enumeration with the default |unsigned| underlying type.
+/*!
+ * \param name Enumeration name.
+ * \param seq Enumeration domain encoded as a <em>sequence</em>.
+ */
+#define DEFINE_BIT_ENUM(name, seq) \
+ DEFINE_BIT_ENUM_WITH_UNDERLYING_TYPE(name, unsigned, seq)
+
+//! Defines a smart enumeration with a specific underlying type and IsStringSerializable attribute.
+/*!
+ * \param name Enumeration name.
+ * \param seq Enumeration domain encoded as a <em>sequence</em>.
+ * \param underlyingType Underlying type.
+ */
+#define DEFINE_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \
+ ENUM__CLASS(name, underlyingType, seq) \
+ ENUM__BEGIN_TRAITS(name, underlyingType, false, true, seq) \
+ ENUM__MINMAX \
+ ENUM__VALIDATE_UNIQUE(name) \
+ ENUM__END_TRAITS(name) \
+
+//! Defines a smart enumeration with a specific underlying type and IsStringSerializable attribute.
+//! Duplicate enumeration values are allowed.
+#define DEFINE_AMBIGUOUS_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(name, underlyingType, seq) \
+ ENUM__CLASS(name, underlyingType, seq) \
+ ENUM__BEGIN_TRAITS(name, underlyingType, false, true, seq) \
+ ENUM__MINMAX \
+ ENUM__END_TRAITS(name)
+
+//! Defines a smart enumeration with the default |int| underlying type and IsStringSerializable attribute.
+#define DEFINE_STRING_SERIALIZABLE_ENUM(name, seq) \
+ DEFINE_STRING_SERIALIZABLE_ENUM_WITH_UNDERLYING_TYPE(name, int, seq)
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! A statically sized vector with elements of type |T| indexed by
+//! the items of enumeration type |E|.
+/*!
+ * Items are value-initialized on construction.
+ */
+template <
+ class E,
+ class T,
+ E Min = TEnumTraits<E>::GetMinValue(),
+ E Max = TEnumTraits<E>::GetMaxValue()
+>
+class TEnumIndexedVector
+{
+public:
+ using TIndex = E;
+ using TValue = T;
+
+ TEnumIndexedVector();
+ TEnumIndexedVector(std::initializer_list<T> elements);
+
+ T& operator[] (E index);
+ const T& operator[] (E index) const;
+
+ // STL interop.
+ T* begin();
+ const T* begin() const;
+ T* end();
+ const T* end() const;
+
+ static bool IsDomainValue(E value);
+
+private:
+ using TUnderlying = typename TEnumTraits<E>::TUnderlying;
+ static constexpr int N = static_cast<TUnderlying>(Max) - static_cast<TUnderlying>(Min) + 1;
+ std::array<T, N> Items_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Returns |true| iff the enumeration value is not bitwise zero.
+template <typename E, typename = std::enable_if_t<NYT::TEnumTraits<E>::IsBitEnum, E>>
+bool Any(E value);
+
+//! Returns |true| iff the enumeration value is bitwise zero.
+template <typename E, typename = std::enable_if_t<NYT::TEnumTraits<E>::IsBitEnum, E>>
+bool None(E value);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define ENUM_INL_H_
+#include "enum-inl.h"
+#undef ENUM_INL_H_
diff --git a/library/cpp/yt/misc/guid-inl.h b/library/cpp/yt/misc/guid-inl.h
new file mode 100644
index 0000000000..2d94b5701b
--- /dev/null
+++ b/library/cpp/yt/misc/guid-inl.h
@@ -0,0 +1,76 @@
+#ifndef GUID_INL_H_
+#error "Direct inclusion of this file is not allowed, include guid.h"
+// For the sake of sane code completion.
+#include "guid.h"
+#endif
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_FORCE_INLINE constexpr TGuid::TGuid()
+ : Parts32{}
+{ }
+
+Y_FORCE_INLINE constexpr TGuid::TGuid(ui32 part0, ui32 part1, ui32 part2, ui32 part3)
+ : Parts32{part0, part1, part2, part3}
+{ }
+
+Y_FORCE_INLINE constexpr TGuid::TGuid(ui64 part0, ui64 part1)
+ : Parts64{part0, part1}
+{ }
+
+Y_FORCE_INLINE bool TGuid::IsEmpty() const
+{
+ return Parts64[0] == 0 && Parts64[1] == 0;
+}
+
+Y_FORCE_INLINE TGuid::operator bool() const
+{
+ return !IsEmpty();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_FORCE_INLINE bool operator == (TGuid lhs, TGuid rhs)
+{
+ return lhs.Parts64[0] == rhs.Parts64[0] &&
+ lhs.Parts64[1] == rhs.Parts64[1];
+}
+
+Y_FORCE_INLINE bool operator != (TGuid lhs, TGuid rhs)
+{
+ return !(lhs == rhs);
+}
+
+Y_FORCE_INLINE bool operator < (TGuid lhs, TGuid rhs)
+{
+#ifdef __GNUC__
+ ui64 lhs0 = __builtin_bswap64(lhs.Parts64[0]);
+ ui64 rhs0 = __builtin_bswap64(rhs.Parts64[0]);
+ if (lhs0 < rhs0) {
+ return true;
+ }
+ if (lhs0 > rhs0) {
+ return false;
+ }
+ ui64 lhs1 = __builtin_bswap64(lhs.Parts64[1]);
+ ui64 rhs1 = __builtin_bswap64(rhs.Parts64[1]);
+ return lhs1 < rhs1;
+#else
+ return memcmp(&lhs, &rhs, sizeof(TGuid)) < 0;
+#endif
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+Y_FORCE_INLINE size_t THash<NYT::TGuid>::operator()(const NYT::TGuid& guid) const
+{
+ const size_t p = 1000000009; // prime number
+ return guid.Parts32[0] +
+ guid.Parts32[1] * p +
+ guid.Parts32[2] * p * p +
+ guid.Parts32[3] * p * p * p;
+}
diff --git a/library/cpp/yt/misc/guid.cpp b/library/cpp/yt/misc/guid.cpp
new file mode 100644
index 0000000000..882787d7a2
--- /dev/null
+++ b/library/cpp/yt/misc/guid.cpp
@@ -0,0 +1,203 @@
+#include "guid.h"
+
+#include <util/random/random.h>
+
+#include <util/string/printf.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+const ui8 HexDigits1[16] = {
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
+};
+
+const ui16 HexDigits2[256] = {
+ 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, 0x6630,
+ 0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931, 0x6131, 0x6231, 0x6331, 0x6431, 0x6531, 0x6631,
+ 0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932, 0x6132, 0x6232, 0x6332, 0x6432, 0x6532, 0x6632,
+ 0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933, 0x6133, 0x6233, 0x6333, 0x6433, 0x6533, 0x6633,
+ 0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934, 0x6134, 0x6234, 0x6334, 0x6434, 0x6534, 0x6634,
+ 0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935, 0x6135, 0x6235, 0x6335, 0x6435, 0x6535, 0x6635,
+ 0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936, 0x6136, 0x6236, 0x6336, 0x6436, 0x6536, 0x6636,
+ 0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937, 0x6137, 0x6237, 0x6337, 0x6437, 0x6537, 0x6637,
+ 0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938, 0x6138, 0x6238, 0x6338, 0x6438, 0x6538, 0x6638,
+ 0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939, 0x6139, 0x6239, 0x6339, 0x6439, 0x6539, 0x6639,
+ 0x3061, 0x3161, 0x3261, 0x3361, 0x3461, 0x3561, 0x3661, 0x3761, 0x3861, 0x3961, 0x6161, 0x6261, 0x6361, 0x6461, 0x6561, 0x6661,
+ 0x3062, 0x3162, 0x3262, 0x3362, 0x3462, 0x3562, 0x3662, 0x3762, 0x3862, 0x3962, 0x6162, 0x6262, 0x6362, 0x6462, 0x6562, 0x6662,
+ 0x3063, 0x3163, 0x3263, 0x3363, 0x3463, 0x3563, 0x3663, 0x3763, 0x3863, 0x3963, 0x6163, 0x6263, 0x6363, 0x6463, 0x6563, 0x6663,
+ 0x3064, 0x3164, 0x3264, 0x3364, 0x3464, 0x3564, 0x3664, 0x3764, 0x3864, 0x3964, 0x6164, 0x6264, 0x6364, 0x6464, 0x6564, 0x6664,
+ 0x3065, 0x3165, 0x3265, 0x3365, 0x3465, 0x3565, 0x3665, 0x3765, 0x3865, 0x3965, 0x6165, 0x6265, 0x6365, 0x6465, 0x6565, 0x6665,
+ 0x3066, 0x3166, 0x3266, 0x3366, 0x3466, 0x3566, 0x3666, 0x3766, 0x3866, 0x3966, 0x6166, 0x6266, 0x6366, 0x6466, 0x6566, 0x6666
+};
+
+} // anonymous namespace
+
+////////////////////////////////////////////////////////////////////////////////
+
+TGuid TGuid::Create()
+{
+ return TGuid(RandomNumber<ui64>(), RandomNumber<ui64>());
+}
+
+TGuid TGuid::FromString(TStringBuf str)
+{
+ TGuid guid;
+ if (!FromString(str, &guid)) {
+ throw TSimpleException(Sprintf("Error parsing GUID \"%s\"",
+ TString(str).c_str()));
+ }
+ return guid;
+}
+
+bool TGuid::FromString(TStringBuf str, TGuid* result)
+{
+ size_t partId = 3;
+ ui64 partValue = 0;
+ bool isEmptyPart = true;
+
+ for (size_t i = 0; i != str.size(); ++i) {
+ const char c = str[i];
+
+ if (c == '-') {
+ if (isEmptyPart || partId == 0) { // x-y--z, -x-y-z or x-y-z-m-...
+ return false;
+ }
+ result->Parts32[partId] = static_cast<ui32>(partValue);
+ --partId;
+ partValue = 0;
+ isEmptyPart = true;
+ continue;
+ }
+
+ ui32 digit = 0;
+ if ('0' <= c && c <= '9') {
+ digit = c - '0';
+ } else if ('a' <= c && c <= 'f') {
+ digit = c - 'a' + 10;
+ } else if ('A' <= c && c <= 'F') {
+ digit = c - 'A' + 10;
+ } else {
+ return false; // non-hex character
+ }
+
+ partValue = partValue * 16 + digit;
+ isEmptyPart = false;
+
+ // overflow check
+ if (partValue > Max<ui32>()) {
+ return false;
+ }
+ }
+
+ if (partId != 0 || isEmptyPart) { // x-y or x-y-z-
+ return false;
+ }
+ result->Parts32[partId] = static_cast<ui32>(partValue);
+ return true;
+}
+
+TGuid TGuid::FromStringHex32(TStringBuf str)
+{
+ TGuid guid;
+ if (!FromStringHex32(str, &guid)) {
+ throw TSimpleException(Sprintf("Error parsing Hex32 GUID \"%s\"",
+ TString(str).c_str()));
+ }
+ return guid;
+}
+
+bool TGuid::FromStringHex32(TStringBuf str, TGuid* result)
+{
+ if (str.size() != 32) {
+ return false;
+ }
+
+ bool ok = true;
+ int i = 0;
+ auto parseChar = [&] {
+ const char c = str[i++];
+ ui32 digit = 0;
+ if ('0' <= c && c <= '9') {
+ digit = c - '0';
+ } else if ('a' <= c && c <= 'f') {
+ digit = c - 'a' + 10;
+ } else if ('A' <= c && c <= 'F') {
+ digit = c - 'A' + 10;
+ } else {
+ ok = false;
+ }
+ return digit;
+ };
+
+ for (size_t j = 0; j < 16; ++j) {
+ result->ReversedParts8[15 - j] = parseChar() * 16 + parseChar();
+ }
+
+ return ok;
+}
+
+char* WriteGuidToBuffer(char* ptr, TGuid value)
+{
+ auto writeHex1 = [&] (ui8 x) {
+ *ptr = HexDigits1[x];
+ ptr += 1;
+ };
+
+ auto writeHex2 = [&] (ui8 x) {
+ ::memcpy(ptr, &HexDigits2[x], 2);
+ ptr += 2;
+ };
+
+ auto writeComponent = [&] (ui32 x) {
+ /* */ if (x >= 0x10000000) {
+ writeHex2((x >> 24) & 0xff);
+ writeHex2((x >> 16) & 0xff);
+ writeHex2((x >> 8) & 0xff);
+ writeHex2( x & 0xff);
+ } else if (x >= 0x1000000) {
+ writeHex1( x >> 24);
+ writeHex2((x >> 16) & 0xff);
+ writeHex2((x >> 8) & 0xff);
+ writeHex2( x & 0xff);
+ } else if (x >= 0x100000) {
+ writeHex2((x >> 16) & 0xff);
+ writeHex2((x >> 8) & 0xff);
+ writeHex2( x & 0xff);
+ } else if (x >= 0x10000) {
+ writeHex1( x >> 16);
+ writeHex2((x >> 8) & 0xff);
+ writeHex2( x & 0xff);
+ } else if (x >= 0x1000) {
+ writeHex2( x >> 8);
+ writeHex2( x & 0xff);
+ } else if (x >= 0x100) {
+ writeHex1( x >> 8);
+ writeHex2( x & 0xff);
+ } else if (x >= 0x10) {
+ writeHex2( x);
+ } else {
+ writeHex1( x);
+ }
+ };
+
+ auto writeDash = [&] () {
+ *ptr++ = '-';
+ };
+
+ writeComponent(value.Parts32[3]);
+ writeDash();
+ writeComponent(value.Parts32[2]);
+ writeDash();
+ writeComponent(value.Parts32[1]);
+ writeDash();
+ writeComponent(value.Parts32[0]);
+
+ return ptr;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/misc/guid.h b/library/cpp/yt/misc/guid.h
new file mode 100644
index 0000000000..ec4ba3526a
--- /dev/null
+++ b/library/cpp/yt/misc/guid.h
@@ -0,0 +1,109 @@
+#pragma once
+
+#include <util/generic/string.h>
+#include <util/generic/typetraits.h>
+
+#include <library/cpp/yt/exception/exception.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! TGuid is 16-byte value that might be interpreted as four little-endian 32-bit integers or two 64-bit little-endian integers.
+/*!
+ * *-------------------------*-------------------------*
+ * | Parts64[0] | Parts64[1] |
+ * *------------*------------*------------*------------*
+ * | Parts32[0] | Parts32[1] | Parts32[2] | Parts32[3] |
+ * *------------*------------*------------*------------*
+ * | 15..............................................0 |
+ * *---------------------------------------------------*
+ *
+ * Note, that bytes are kept in memory in reverse order.
+ *
+ * Canonical text representation of guid consists of four base-16 numbers.
+ * In text form, Parts32[3] comes first, and Parts32[0] comes last.
+ *
+ * For example:
+ *
+ * xxyyzzaa-0-1234-ff
+ *
+ * xx is byte [0]
+ * yy is byte [1]
+ * zz is byte [2]
+ * 12 is byte [8]
+ * 34 is byte [9]
+ * ff is byte [15]
+ */
+struct TGuid
+{
+ union
+ {
+ ui32 Parts32[4];
+ ui64 Parts64[2];
+ ui8 ReversedParts8[16];
+ };
+
+ //! Constructs a null (zero) guid.
+ constexpr TGuid();
+
+ //! Constructs guid from parts.
+ constexpr TGuid(ui32 part0, ui32 part1, ui32 part2, ui32 part3);
+
+ //! Constructs guid from parts.
+ constexpr TGuid(ui64 part0, ui64 part1);
+
+ //! Copies an existing guid.
+ TGuid(const TGuid& other) = default;
+
+ //! Checks if TGuid is zero.
+ bool IsEmpty() const;
+
+ //! Converts TGuid to bool, returns |false| iff TGuid is zero.
+ explicit operator bool() const;
+
+ //! Creates a new instance.
+ static TGuid Create();
+
+ //! Parses guid from TStringBuf, throws an exception if something went wrong.
+ static TGuid FromString(TStringBuf str);
+
+ //! Parses guid from TStringBuf, returns |true| if everything was ok.
+ static bool FromString(TStringBuf str, TGuid* guid);
+
+ //! Same as FromString, but expects exactly 32 hex digits without dashes.
+ static TGuid FromStringHex32(TStringBuf str);
+
+ //! Same as TryFromString, but expects exactly 32 hex digits without dashes.
+ static bool FromStringHex32(TStringBuf str, TGuid* guid);
+};
+
+bool operator == (TGuid lhs, TGuid rhs);
+bool operator != (TGuid lhs, TGuid rhs);
+bool operator < (TGuid lhs, TGuid rhs);
+
+////////////////////////////////////////////////////////////////////////////////
+
+constexpr int MaxGuidStringSize = 4 * 8 + 3;
+char* WriteGuidToBuffer(char* ptr, TGuid value);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_DECLARE_PODTYPE(NYT::TGuid);
+
+//! A hasher for TGuid.
+template <>
+struct THash<NYT::TGuid>
+{
+ size_t operator()(const NYT::TGuid& guid) const;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define GUID_INL_H_
+#include "guid-inl.h"
+#undef GUID_INL_H_
diff --git a/library/cpp/yt/misc/hash-inl.h b/library/cpp/yt/misc/hash-inl.h
new file mode 100644
index 0000000000..46eeefe620
--- /dev/null
+++ b/library/cpp/yt/misc/hash-inl.h
@@ -0,0 +1,47 @@
+#ifndef HASH_INL_H_
+#error "Direct inclusion of this file is not allowed, include hash.h"
+// For the sake of sane code completion.
+#include "hash.h"
+#endif
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+inline void HashCombine(size_t& h, size_t k)
+{
+ static_assert(sizeof(size_t) == 8, "size_t must be 64 bit.");
+
+ const size_t m = 0xc6a4a7935bd1e995ULL;
+ const int r = 47;
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h ^= k;
+ h *= m;
+}
+
+template <class T>
+void HashCombine(size_t& h, const T& k)
+{
+ HashCombine(h, THash<T>()(k));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TElement, class TUnderlying>
+TRandomizedHash<TElement, TUnderlying>::TRandomizedHash()
+ : Seed_(RandomNumber<size_t>())
+{ }
+
+template <class TElement, class TUnderlying>
+size_t TRandomizedHash<TElement, TUnderlying>::operator ()(const TElement& element) const
+{
+ return Underlying_(element) + Seed_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/misc/hash.h b/library/cpp/yt/misc/hash.h
new file mode 100644
index 0000000000..2fecf89506
--- /dev/null
+++ b/library/cpp/yt/misc/hash.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <util/generic/hash.h>
+
+#include <util/random/random.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Updates #h with #k.
+//! Cf. |boost::hash_combine|.
+void HashCombine(size_t& h, size_t k);
+
+//! Updates #h with the hash of #k.
+//! Cf. |boost::hash_combine|.
+template <class T>
+void HashCombine(size_t& h, const T& k);
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Provides a hasher that randomizes the results of another one.
+template <class TElement, class TUnderlying = ::THash<TElement>>
+class TRandomizedHash
+{
+public:
+ TRandomizedHash();
+ size_t operator () (const TElement& element) const;
+
+private:
+ size_t Seed_;
+ TUnderlying Underlying_;
+
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define HASH_INL_H_
+#include "hash-inl.h"
+#undef HASH_INL_H_
diff --git a/library/cpp/yt/misc/port.h b/library/cpp/yt/misc/port.h
new file mode 100644
index 0000000000..b24ac50995
--- /dev/null
+++ b/library/cpp/yt/misc/port.h
@@ -0,0 +1,70 @@
+#pragma once
+
+#include <util/system/platform.h>
+
+// Check platform bitness.
+#if !defined(_64_)
+ #error YT requires 64-bit platform
+#endif
+
+// This define enables tracking of reference-counted objects to provide
+// various insightful information on memory usage and object creation patterns.
+#define YT_ENABLE_REF_COUNTED_TRACKING
+
+// This define enables logging with TRACE level. You can still disable trace logging
+// for particular TU by discarding this macro identifier.
+#define YT_ENABLE_TRACE_LOGGING
+
+#ifndef NDEBUG
+ // This define enables thread affinity check -- a user-defined verification ensuring
+ // that some functions are called from particular threads.
+ #define YT_ENABLE_THREAD_AFFINITY_CHECK
+
+ // This define enables tracking of BIND callbacks location.
+ #define YT_ENABLE_BIND_LOCATION_TRACKING
+
+ // This define enables checking that all required protobuf fields are present
+ // during serialization.
+ #define YT_VALIDATE_REQUIRED_PROTO_FIELDS
+
+ // Detects deadlocks caused by recursive acquisitions of (non-recursive) spin locks.
+ #define YT_ENABLE_SPIN_LOCK_OWNERSHIP_TRACKING
+#endif
+
+// Configure SSE usage.
+#ifdef SSE42_ENABLED
+ #define YT_USE_SSE42
+#endif
+
+#ifdef _win_
+ // Someone above has defined this by including one of Windows headers.
+ #undef GetMessage
+ #undef Yield
+
+ // For protobuf-generated files:
+ // C4125: decimal digit terminates octal escape sequence
+ #pragma warning (disable: 4125)
+ // C4505: unreferenced local function has been removed
+ #pragma warning (disable : 4505)
+ // C4121: alignment of a member was sensitive to packing
+ #pragma warning (disable: 4121)
+ // C4503: decorated name length exceeded, name was truncated
+ #pragma warning (disable : 4503)
+ // C4714: function marked as __forceinline not inlined
+ #pragma warning (disable: 4714)
+ // C4250: inherits via dominance
+ #pragma warning (disable: 4250)
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+ #define PER_THREAD __thread
+ #define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
+ // Prevent GCC from throwing out functions in release builds.
+ #define ATTRIBUTE_USED __attribute__((used))
+#elif defined(_MSC_VER)
+ #define PER_THREAD __declspec(thread)
+ #define ATTRIBUTE_NO_SANITIZE_ADDRESS
+ #define ATTRIBUTE_USED
+#else
+ #error Unsupported compiler
+#endif
diff --git a/library/cpp/yt/misc/preprocessor-gen.h b/library/cpp/yt/misc/preprocessor-gen.h
new file mode 100644
index 0000000000..b809941bcd
--- /dev/null
+++ b/library/cpp/yt/misc/preprocessor-gen.h
@@ -0,0 +1,1249 @@
+#pragma once
+
+// WARNING: This file was auto-generated.
+// Please, consider incorporating any changes into the generator.
+
+// Generated on Wed Dec 9 14:20:20 2015.
+
+
+/*!
+ \internal
+*/
+
+#ifndef PREPROCESSOR_GEN_H_
+#error "Direct inclusion of this file is not allowed, include preprocessor.h"
+// For the sake of sane code completion.
+#include "preprocessor.h"
+#endif
+#undef PREPROCESSOR_GEN_H_
+
+////////////////////////////////////////////////////////////////////////////////
+#define PP_COUNT_IMPL(...) PP_CONCAT(PP_COUNT_CONST_, \
+ PP_COUNT_IMPL_0 __VA_ARGS__)
+#define PP_COUNT_CONST_PP_COUNT_IMPL_0 0
+#define PP_COUNT_CONST_PP_COUNT_IMPL_1 1
+#define PP_COUNT_CONST_PP_COUNT_IMPL_2 2
+#define PP_COUNT_CONST_PP_COUNT_IMPL_3 3
+#define PP_COUNT_CONST_PP_COUNT_IMPL_4 4
+#define PP_COUNT_CONST_PP_COUNT_IMPL_5 5
+#define PP_COUNT_CONST_PP_COUNT_IMPL_6 6
+#define PP_COUNT_CONST_PP_COUNT_IMPL_7 7
+#define PP_COUNT_CONST_PP_COUNT_IMPL_8 8
+#define PP_COUNT_CONST_PP_COUNT_IMPL_9 9
+#define PP_COUNT_CONST_PP_COUNT_IMPL_10 10
+#define PP_COUNT_CONST_PP_COUNT_IMPL_11 11
+#define PP_COUNT_CONST_PP_COUNT_IMPL_12 12
+#define PP_COUNT_CONST_PP_COUNT_IMPL_13 13
+#define PP_COUNT_CONST_PP_COUNT_IMPL_14 14
+#define PP_COUNT_CONST_PP_COUNT_IMPL_15 15
+#define PP_COUNT_CONST_PP_COUNT_IMPL_16 16
+#define PP_COUNT_CONST_PP_COUNT_IMPL_17 17
+#define PP_COUNT_CONST_PP_COUNT_IMPL_18 18
+#define PP_COUNT_CONST_PP_COUNT_IMPL_19 19
+#define PP_COUNT_CONST_PP_COUNT_IMPL_20 20
+#define PP_COUNT_CONST_PP_COUNT_IMPL_21 21
+#define PP_COUNT_CONST_PP_COUNT_IMPL_22 22
+#define PP_COUNT_CONST_PP_COUNT_IMPL_23 23
+#define PP_COUNT_CONST_PP_COUNT_IMPL_24 24
+#define PP_COUNT_CONST_PP_COUNT_IMPL_25 25
+#define PP_COUNT_CONST_PP_COUNT_IMPL_26 26
+#define PP_COUNT_CONST_PP_COUNT_IMPL_27 27
+#define PP_COUNT_CONST_PP_COUNT_IMPL_28 28
+#define PP_COUNT_CONST_PP_COUNT_IMPL_29 29
+#define PP_COUNT_CONST_PP_COUNT_IMPL_30 30
+#define PP_COUNT_CONST_PP_COUNT_IMPL_31 31
+#define PP_COUNT_CONST_PP_COUNT_IMPL_32 32
+#define PP_COUNT_CONST_PP_COUNT_IMPL_33 33
+#define PP_COUNT_CONST_PP_COUNT_IMPL_34 34
+#define PP_COUNT_CONST_PP_COUNT_IMPL_35 35
+#define PP_COUNT_CONST_PP_COUNT_IMPL_36 36
+#define PP_COUNT_CONST_PP_COUNT_IMPL_37 37
+#define PP_COUNT_CONST_PP_COUNT_IMPL_38 38
+#define PP_COUNT_CONST_PP_COUNT_IMPL_39 39
+#define PP_COUNT_CONST_PP_COUNT_IMPL_40 40
+#define PP_COUNT_CONST_PP_COUNT_IMPL_41 41
+#define PP_COUNT_CONST_PP_COUNT_IMPL_42 42
+#define PP_COUNT_CONST_PP_COUNT_IMPL_43 43
+#define PP_COUNT_CONST_PP_COUNT_IMPL_44 44
+#define PP_COUNT_CONST_PP_COUNT_IMPL_45 45
+#define PP_COUNT_CONST_PP_COUNT_IMPL_46 46
+#define PP_COUNT_CONST_PP_COUNT_IMPL_47 47
+#define PP_COUNT_CONST_PP_COUNT_IMPL_48 48
+#define PP_COUNT_CONST_PP_COUNT_IMPL_49 49
+#define PP_COUNT_CONST_PP_COUNT_IMPL_50 50
+#define PP_COUNT_CONST_PP_COUNT_IMPL_51 51
+#define PP_COUNT_CONST_PP_COUNT_IMPL_52 52
+#define PP_COUNT_CONST_PP_COUNT_IMPL_53 53
+#define PP_COUNT_CONST_PP_COUNT_IMPL_54 54
+#define PP_COUNT_CONST_PP_COUNT_IMPL_55 55
+#define PP_COUNT_CONST_PP_COUNT_IMPL_56 56
+#define PP_COUNT_CONST_PP_COUNT_IMPL_57 57
+#define PP_COUNT_CONST_PP_COUNT_IMPL_58 58
+#define PP_COUNT_CONST_PP_COUNT_IMPL_59 59
+#define PP_COUNT_CONST_PP_COUNT_IMPL_60 60
+#define PP_COUNT_CONST_PP_COUNT_IMPL_61 61
+#define PP_COUNT_CONST_PP_COUNT_IMPL_62 62
+#define PP_COUNT_CONST_PP_COUNT_IMPL_63 63
+#define PP_COUNT_CONST_PP_COUNT_IMPL_64 64
+#define PP_COUNT_CONST_PP_COUNT_IMPL_65 65
+#define PP_COUNT_CONST_PP_COUNT_IMPL_66 66
+#define PP_COUNT_CONST_PP_COUNT_IMPL_67 67
+#define PP_COUNT_CONST_PP_COUNT_IMPL_68 68
+#define PP_COUNT_CONST_PP_COUNT_IMPL_69 69
+#define PP_COUNT_CONST_PP_COUNT_IMPL_70 70
+#define PP_COUNT_CONST_PP_COUNT_IMPL_71 71
+#define PP_COUNT_CONST_PP_COUNT_IMPL_72 72
+#define PP_COUNT_CONST_PP_COUNT_IMPL_73 73
+#define PP_COUNT_CONST_PP_COUNT_IMPL_74 74
+#define PP_COUNT_CONST_PP_COUNT_IMPL_75 75
+#define PP_COUNT_CONST_PP_COUNT_IMPL_76 76
+#define PP_COUNT_CONST_PP_COUNT_IMPL_77 77
+#define PP_COUNT_CONST_PP_COUNT_IMPL_78 78
+#define PP_COUNT_CONST_PP_COUNT_IMPL_79 79
+#define PP_COUNT_CONST_PP_COUNT_IMPL_80 80
+#define PP_COUNT_CONST_PP_COUNT_IMPL_81 81
+#define PP_COUNT_CONST_PP_COUNT_IMPL_82 82
+#define PP_COUNT_CONST_PP_COUNT_IMPL_83 83
+#define PP_COUNT_CONST_PP_COUNT_IMPL_84 84
+#define PP_COUNT_CONST_PP_COUNT_IMPL_85 85
+#define PP_COUNT_CONST_PP_COUNT_IMPL_86 86
+#define PP_COUNT_CONST_PP_COUNT_IMPL_87 87
+#define PP_COUNT_CONST_PP_COUNT_IMPL_88 88
+#define PP_COUNT_CONST_PP_COUNT_IMPL_89 89
+#define PP_COUNT_CONST_PP_COUNT_IMPL_90 90
+#define PP_COUNT_CONST_PP_COUNT_IMPL_91 91
+#define PP_COUNT_CONST_PP_COUNT_IMPL_92 92
+#define PP_COUNT_CONST_PP_COUNT_IMPL_93 93
+#define PP_COUNT_CONST_PP_COUNT_IMPL_94 94
+#define PP_COUNT_CONST_PP_COUNT_IMPL_95 95
+#define PP_COUNT_CONST_PP_COUNT_IMPL_96 96
+#define PP_COUNT_CONST_PP_COUNT_IMPL_97 97
+#define PP_COUNT_CONST_PP_COUNT_IMPL_98 98
+#define PP_COUNT_CONST_PP_COUNT_IMPL_99 99
+#define PP_COUNT_CONST_PP_COUNT_IMPL_100 100
+#define PP_COUNT_CONST_PP_COUNT_IMPL_101 101
+#define PP_COUNT_CONST_PP_COUNT_IMPL_102 102
+#define PP_COUNT_CONST_PP_COUNT_IMPL_103 103
+#define PP_COUNT_CONST_PP_COUNT_IMPL_104 104
+#define PP_COUNT_CONST_PP_COUNT_IMPL_105 105
+#define PP_COUNT_CONST_PP_COUNT_IMPL_106 106
+#define PP_COUNT_CONST_PP_COUNT_IMPL_107 107
+#define PP_COUNT_CONST_PP_COUNT_IMPL_108 108
+#define PP_COUNT_CONST_PP_COUNT_IMPL_109 109
+#define PP_COUNT_CONST_PP_COUNT_IMPL_110 110
+#define PP_COUNT_CONST_PP_COUNT_IMPL_111 111
+#define PP_COUNT_CONST_PP_COUNT_IMPL_112 112
+#define PP_COUNT_CONST_PP_COUNT_IMPL_113 113
+#define PP_COUNT_CONST_PP_COUNT_IMPL_114 114
+#define PP_COUNT_CONST_PP_COUNT_IMPL_115 115
+#define PP_COUNT_CONST_PP_COUNT_IMPL_116 116
+#define PP_COUNT_CONST_PP_COUNT_IMPL_117 117
+#define PP_COUNT_CONST_PP_COUNT_IMPL_118 118
+#define PP_COUNT_CONST_PP_COUNT_IMPL_119 119
+#define PP_COUNT_CONST_PP_COUNT_IMPL_120 120
+#define PP_COUNT_CONST_PP_COUNT_IMPL_121 121
+#define PP_COUNT_CONST_PP_COUNT_IMPL_122 122
+#define PP_COUNT_CONST_PP_COUNT_IMPL_123 123
+#define PP_COUNT_CONST_PP_COUNT_IMPL_124 124
+#define PP_COUNT_CONST_PP_COUNT_IMPL_125 125
+#define PP_COUNT_CONST_PP_COUNT_IMPL_126 126
+#define PP_COUNT_CONST_PP_COUNT_IMPL_127 127
+#define PP_COUNT_CONST_PP_COUNT_IMPL_128 128
+#define PP_COUNT_CONST_PP_COUNT_IMPL_129 129
+#define PP_COUNT_CONST_PP_COUNT_IMPL_130 130
+#define PP_COUNT_CONST_PP_COUNT_IMPL_131 131
+#define PP_COUNT_CONST_PP_COUNT_IMPL_132 132
+#define PP_COUNT_CONST_PP_COUNT_IMPL_133 133
+#define PP_COUNT_CONST_PP_COUNT_IMPL_134 134
+#define PP_COUNT_CONST_PP_COUNT_IMPL_135 135
+#define PP_COUNT_CONST_PP_COUNT_IMPL_136 136
+#define PP_COUNT_CONST_PP_COUNT_IMPL_137 137
+#define PP_COUNT_CONST_PP_COUNT_IMPL_138 138
+#define PP_COUNT_CONST_PP_COUNT_IMPL_139 139
+#define PP_COUNT_CONST_PP_COUNT_IMPL_140 140
+#define PP_COUNT_CONST_PP_COUNT_IMPL_141 141
+#define PP_COUNT_CONST_PP_COUNT_IMPL_142 142
+#define PP_COUNT_CONST_PP_COUNT_IMPL_143 143
+#define PP_COUNT_CONST_PP_COUNT_IMPL_144 144
+#define PP_COUNT_CONST_PP_COUNT_IMPL_145 145
+#define PP_COUNT_CONST_PP_COUNT_IMPL_146 146
+#define PP_COUNT_CONST_PP_COUNT_IMPL_147 147
+#define PP_COUNT_CONST_PP_COUNT_IMPL_148 148
+#define PP_COUNT_CONST_PP_COUNT_IMPL_149 149
+#define PP_COUNT_CONST_PP_COUNT_IMPL_150 150
+#define PP_COUNT_CONST_PP_COUNT_IMPL_151 151
+#define PP_COUNT_CONST_PP_COUNT_IMPL_152 152
+#define PP_COUNT_CONST_PP_COUNT_IMPL_153 153
+#define PP_COUNT_CONST_PP_COUNT_IMPL_154 154
+#define PP_COUNT_CONST_PP_COUNT_IMPL_155 155
+#define PP_COUNT_CONST_PP_COUNT_IMPL_156 156
+#define PP_COUNT_CONST_PP_COUNT_IMPL_157 157
+#define PP_COUNT_CONST_PP_COUNT_IMPL_158 158
+#define PP_COUNT_CONST_PP_COUNT_IMPL_159 159
+#define PP_COUNT_CONST_PP_COUNT_IMPL_160 160
+#define PP_COUNT_CONST_PP_COUNT_IMPL_161 161
+#define PP_COUNT_CONST_PP_COUNT_IMPL_162 162
+#define PP_COUNT_CONST_PP_COUNT_IMPL_163 163
+#define PP_COUNT_CONST_PP_COUNT_IMPL_164 164
+#define PP_COUNT_CONST_PP_COUNT_IMPL_165 165
+#define PP_COUNT_CONST_PP_COUNT_IMPL_166 166
+#define PP_COUNT_CONST_PP_COUNT_IMPL_167 167
+#define PP_COUNT_CONST_PP_COUNT_IMPL_168 168
+#define PP_COUNT_CONST_PP_COUNT_IMPL_169 169
+#define PP_COUNT_CONST_PP_COUNT_IMPL_170 170
+#define PP_COUNT_CONST_PP_COUNT_IMPL_171 171
+#define PP_COUNT_CONST_PP_COUNT_IMPL_172 172
+#define PP_COUNT_CONST_PP_COUNT_IMPL_173 173
+#define PP_COUNT_CONST_PP_COUNT_IMPL_174 174
+#define PP_COUNT_CONST_PP_COUNT_IMPL_175 175
+#define PP_COUNT_CONST_PP_COUNT_IMPL_176 176
+#define PP_COUNT_CONST_PP_COUNT_IMPL_177 177
+#define PP_COUNT_CONST_PP_COUNT_IMPL_178 178
+#define PP_COUNT_CONST_PP_COUNT_IMPL_179 179
+#define PP_COUNT_CONST_PP_COUNT_IMPL_180 180
+#define PP_COUNT_CONST_PP_COUNT_IMPL_181 181
+#define PP_COUNT_CONST_PP_COUNT_IMPL_182 182
+#define PP_COUNT_CONST_PP_COUNT_IMPL_183 183
+#define PP_COUNT_CONST_PP_COUNT_IMPL_184 184
+#define PP_COUNT_CONST_PP_COUNT_IMPL_185 185
+#define PP_COUNT_CONST_PP_COUNT_IMPL_186 186
+#define PP_COUNT_CONST_PP_COUNT_IMPL_187 187
+#define PP_COUNT_CONST_PP_COUNT_IMPL_188 188
+#define PP_COUNT_CONST_PP_COUNT_IMPL_189 189
+#define PP_COUNT_CONST_PP_COUNT_IMPL_190 190
+#define PP_COUNT_CONST_PP_COUNT_IMPL_191 191
+#define PP_COUNT_CONST_PP_COUNT_IMPL_192 192
+#define PP_COUNT_CONST_PP_COUNT_IMPL_193 193
+#define PP_COUNT_CONST_PP_COUNT_IMPL_194 194
+#define PP_COUNT_CONST_PP_COUNT_IMPL_195 195
+#define PP_COUNT_CONST_PP_COUNT_IMPL_196 196
+#define PP_COUNT_CONST_PP_COUNT_IMPL_197 197
+#define PP_COUNT_CONST_PP_COUNT_IMPL_198 198
+#define PP_COUNT_CONST_PP_COUNT_IMPL_199 199
+#define PP_COUNT_IMPL_0(_) PP_COUNT_IMPL_1
+#define PP_COUNT_IMPL_1(_) PP_COUNT_IMPL_2
+#define PP_COUNT_IMPL_2(_) PP_COUNT_IMPL_3
+#define PP_COUNT_IMPL_3(_) PP_COUNT_IMPL_4
+#define PP_COUNT_IMPL_4(_) PP_COUNT_IMPL_5
+#define PP_COUNT_IMPL_5(_) PP_COUNT_IMPL_6
+#define PP_COUNT_IMPL_6(_) PP_COUNT_IMPL_7
+#define PP_COUNT_IMPL_7(_) PP_COUNT_IMPL_8
+#define PP_COUNT_IMPL_8(_) PP_COUNT_IMPL_9
+#define PP_COUNT_IMPL_9(_) PP_COUNT_IMPL_10
+#define PP_COUNT_IMPL_10(_) PP_COUNT_IMPL_11
+#define PP_COUNT_IMPL_11(_) PP_COUNT_IMPL_12
+#define PP_COUNT_IMPL_12(_) PP_COUNT_IMPL_13
+#define PP_COUNT_IMPL_13(_) PP_COUNT_IMPL_14
+#define PP_COUNT_IMPL_14(_) PP_COUNT_IMPL_15
+#define PP_COUNT_IMPL_15(_) PP_COUNT_IMPL_16
+#define PP_COUNT_IMPL_16(_) PP_COUNT_IMPL_17
+#define PP_COUNT_IMPL_17(_) PP_COUNT_IMPL_18
+#define PP_COUNT_IMPL_18(_) PP_COUNT_IMPL_19
+#define PP_COUNT_IMPL_19(_) PP_COUNT_IMPL_20
+#define PP_COUNT_IMPL_20(_) PP_COUNT_IMPL_21
+#define PP_COUNT_IMPL_21(_) PP_COUNT_IMPL_22
+#define PP_COUNT_IMPL_22(_) PP_COUNT_IMPL_23
+#define PP_COUNT_IMPL_23(_) PP_COUNT_IMPL_24
+#define PP_COUNT_IMPL_24(_) PP_COUNT_IMPL_25
+#define PP_COUNT_IMPL_25(_) PP_COUNT_IMPL_26
+#define PP_COUNT_IMPL_26(_) PP_COUNT_IMPL_27
+#define PP_COUNT_IMPL_27(_) PP_COUNT_IMPL_28
+#define PP_COUNT_IMPL_28(_) PP_COUNT_IMPL_29
+#define PP_COUNT_IMPL_29(_) PP_COUNT_IMPL_30
+#define PP_COUNT_IMPL_30(_) PP_COUNT_IMPL_31
+#define PP_COUNT_IMPL_31(_) PP_COUNT_IMPL_32
+#define PP_COUNT_IMPL_32(_) PP_COUNT_IMPL_33
+#define PP_COUNT_IMPL_33(_) PP_COUNT_IMPL_34
+#define PP_COUNT_IMPL_34(_) PP_COUNT_IMPL_35
+#define PP_COUNT_IMPL_35(_) PP_COUNT_IMPL_36
+#define PP_COUNT_IMPL_36(_) PP_COUNT_IMPL_37
+#define PP_COUNT_IMPL_37(_) PP_COUNT_IMPL_38
+#define PP_COUNT_IMPL_38(_) PP_COUNT_IMPL_39
+#define PP_COUNT_IMPL_39(_) PP_COUNT_IMPL_40
+#define PP_COUNT_IMPL_40(_) PP_COUNT_IMPL_41
+#define PP_COUNT_IMPL_41(_) PP_COUNT_IMPL_42
+#define PP_COUNT_IMPL_42(_) PP_COUNT_IMPL_43
+#define PP_COUNT_IMPL_43(_) PP_COUNT_IMPL_44
+#define PP_COUNT_IMPL_44(_) PP_COUNT_IMPL_45
+#define PP_COUNT_IMPL_45(_) PP_COUNT_IMPL_46
+#define PP_COUNT_IMPL_46(_) PP_COUNT_IMPL_47
+#define PP_COUNT_IMPL_47(_) PP_COUNT_IMPL_48
+#define PP_COUNT_IMPL_48(_) PP_COUNT_IMPL_49
+#define PP_COUNT_IMPL_49(_) PP_COUNT_IMPL_50
+#define PP_COUNT_IMPL_50(_) PP_COUNT_IMPL_51
+#define PP_COUNT_IMPL_51(_) PP_COUNT_IMPL_52
+#define PP_COUNT_IMPL_52(_) PP_COUNT_IMPL_53
+#define PP_COUNT_IMPL_53(_) PP_COUNT_IMPL_54
+#define PP_COUNT_IMPL_54(_) PP_COUNT_IMPL_55
+#define PP_COUNT_IMPL_55(_) PP_COUNT_IMPL_56
+#define PP_COUNT_IMPL_56(_) PP_COUNT_IMPL_57
+#define PP_COUNT_IMPL_57(_) PP_COUNT_IMPL_58
+#define PP_COUNT_IMPL_58(_) PP_COUNT_IMPL_59
+#define PP_COUNT_IMPL_59(_) PP_COUNT_IMPL_60
+#define PP_COUNT_IMPL_60(_) PP_COUNT_IMPL_61
+#define PP_COUNT_IMPL_61(_) PP_COUNT_IMPL_62
+#define PP_COUNT_IMPL_62(_) PP_COUNT_IMPL_63
+#define PP_COUNT_IMPL_63(_) PP_COUNT_IMPL_64
+#define PP_COUNT_IMPL_64(_) PP_COUNT_IMPL_65
+#define PP_COUNT_IMPL_65(_) PP_COUNT_IMPL_66
+#define PP_COUNT_IMPL_66(_) PP_COUNT_IMPL_67
+#define PP_COUNT_IMPL_67(_) PP_COUNT_IMPL_68
+#define PP_COUNT_IMPL_68(_) PP_COUNT_IMPL_69
+#define PP_COUNT_IMPL_69(_) PP_COUNT_IMPL_70
+#define PP_COUNT_IMPL_70(_) PP_COUNT_IMPL_71
+#define PP_COUNT_IMPL_71(_) PP_COUNT_IMPL_72
+#define PP_COUNT_IMPL_72(_) PP_COUNT_IMPL_73
+#define PP_COUNT_IMPL_73(_) PP_COUNT_IMPL_74
+#define PP_COUNT_IMPL_74(_) PP_COUNT_IMPL_75
+#define PP_COUNT_IMPL_75(_) PP_COUNT_IMPL_76
+#define PP_COUNT_IMPL_76(_) PP_COUNT_IMPL_77
+#define PP_COUNT_IMPL_77(_) PP_COUNT_IMPL_78
+#define PP_COUNT_IMPL_78(_) PP_COUNT_IMPL_79
+#define PP_COUNT_IMPL_79(_) PP_COUNT_IMPL_80
+#define PP_COUNT_IMPL_80(_) PP_COUNT_IMPL_81
+#define PP_COUNT_IMPL_81(_) PP_COUNT_IMPL_82
+#define PP_COUNT_IMPL_82(_) PP_COUNT_IMPL_83
+#define PP_COUNT_IMPL_83(_) PP_COUNT_IMPL_84
+#define PP_COUNT_IMPL_84(_) PP_COUNT_IMPL_85
+#define PP_COUNT_IMPL_85(_) PP_COUNT_IMPL_86
+#define PP_COUNT_IMPL_86(_) PP_COUNT_IMPL_87
+#define PP_COUNT_IMPL_87(_) PP_COUNT_IMPL_88
+#define PP_COUNT_IMPL_88(_) PP_COUNT_IMPL_89
+#define PP_COUNT_IMPL_89(_) PP_COUNT_IMPL_90
+#define PP_COUNT_IMPL_90(_) PP_COUNT_IMPL_91
+#define PP_COUNT_IMPL_91(_) PP_COUNT_IMPL_92
+#define PP_COUNT_IMPL_92(_) PP_COUNT_IMPL_93
+#define PP_COUNT_IMPL_93(_) PP_COUNT_IMPL_94
+#define PP_COUNT_IMPL_94(_) PP_COUNT_IMPL_95
+#define PP_COUNT_IMPL_95(_) PP_COUNT_IMPL_96
+#define PP_COUNT_IMPL_96(_) PP_COUNT_IMPL_97
+#define PP_COUNT_IMPL_97(_) PP_COUNT_IMPL_98
+#define PP_COUNT_IMPL_98(_) PP_COUNT_IMPL_99
+#define PP_COUNT_IMPL_99(_) PP_COUNT_IMPL_100
+#define PP_COUNT_IMPL_100(_) PP_COUNT_IMPL_101
+#define PP_COUNT_IMPL_101(_) PP_COUNT_IMPL_102
+#define PP_COUNT_IMPL_102(_) PP_COUNT_IMPL_103
+#define PP_COUNT_IMPL_103(_) PP_COUNT_IMPL_104
+#define PP_COUNT_IMPL_104(_) PP_COUNT_IMPL_105
+#define PP_COUNT_IMPL_105(_) PP_COUNT_IMPL_106
+#define PP_COUNT_IMPL_106(_) PP_COUNT_IMPL_107
+#define PP_COUNT_IMPL_107(_) PP_COUNT_IMPL_108
+#define PP_COUNT_IMPL_108(_) PP_COUNT_IMPL_109
+#define PP_COUNT_IMPL_109(_) PP_COUNT_IMPL_110
+#define PP_COUNT_IMPL_110(_) PP_COUNT_IMPL_111
+#define PP_COUNT_IMPL_111(_) PP_COUNT_IMPL_112
+#define PP_COUNT_IMPL_112(_) PP_COUNT_IMPL_113
+#define PP_COUNT_IMPL_113(_) PP_COUNT_IMPL_114
+#define PP_COUNT_IMPL_114(_) PP_COUNT_IMPL_115
+#define PP_COUNT_IMPL_115(_) PP_COUNT_IMPL_116
+#define PP_COUNT_IMPL_116(_) PP_COUNT_IMPL_117
+#define PP_COUNT_IMPL_117(_) PP_COUNT_IMPL_118
+#define PP_COUNT_IMPL_118(_) PP_COUNT_IMPL_119
+#define PP_COUNT_IMPL_119(_) PP_COUNT_IMPL_120
+#define PP_COUNT_IMPL_120(_) PP_COUNT_IMPL_121
+#define PP_COUNT_IMPL_121(_) PP_COUNT_IMPL_122
+#define PP_COUNT_IMPL_122(_) PP_COUNT_IMPL_123
+#define PP_COUNT_IMPL_123(_) PP_COUNT_IMPL_124
+#define PP_COUNT_IMPL_124(_) PP_COUNT_IMPL_125
+#define PP_COUNT_IMPL_125(_) PP_COUNT_IMPL_126
+#define PP_COUNT_IMPL_126(_) PP_COUNT_IMPL_127
+#define PP_COUNT_IMPL_127(_) PP_COUNT_IMPL_128
+#define PP_COUNT_IMPL_128(_) PP_COUNT_IMPL_129
+#define PP_COUNT_IMPL_129(_) PP_COUNT_IMPL_130
+#define PP_COUNT_IMPL_130(_) PP_COUNT_IMPL_131
+#define PP_COUNT_IMPL_131(_) PP_COUNT_IMPL_132
+#define PP_COUNT_IMPL_132(_) PP_COUNT_IMPL_133
+#define PP_COUNT_IMPL_133(_) PP_COUNT_IMPL_134
+#define PP_COUNT_IMPL_134(_) PP_COUNT_IMPL_135
+#define PP_COUNT_IMPL_135(_) PP_COUNT_IMPL_136
+#define PP_COUNT_IMPL_136(_) PP_COUNT_IMPL_137
+#define PP_COUNT_IMPL_137(_) PP_COUNT_IMPL_138
+#define PP_COUNT_IMPL_138(_) PP_COUNT_IMPL_139
+#define PP_COUNT_IMPL_139(_) PP_COUNT_IMPL_140
+#define PP_COUNT_IMPL_140(_) PP_COUNT_IMPL_141
+#define PP_COUNT_IMPL_141(_) PP_COUNT_IMPL_142
+#define PP_COUNT_IMPL_142(_) PP_COUNT_IMPL_143
+#define PP_COUNT_IMPL_143(_) PP_COUNT_IMPL_144
+#define PP_COUNT_IMPL_144(_) PP_COUNT_IMPL_145
+#define PP_COUNT_IMPL_145(_) PP_COUNT_IMPL_146
+#define PP_COUNT_IMPL_146(_) PP_COUNT_IMPL_147
+#define PP_COUNT_IMPL_147(_) PP_COUNT_IMPL_148
+#define PP_COUNT_IMPL_148(_) PP_COUNT_IMPL_149
+#define PP_COUNT_IMPL_149(_) PP_COUNT_IMPL_150
+#define PP_COUNT_IMPL_150(_) PP_COUNT_IMPL_151
+#define PP_COUNT_IMPL_151(_) PP_COUNT_IMPL_152
+#define PP_COUNT_IMPL_152(_) PP_COUNT_IMPL_153
+#define PP_COUNT_IMPL_153(_) PP_COUNT_IMPL_154
+#define PP_COUNT_IMPL_154(_) PP_COUNT_IMPL_155
+#define PP_COUNT_IMPL_155(_) PP_COUNT_IMPL_156
+#define PP_COUNT_IMPL_156(_) PP_COUNT_IMPL_157
+#define PP_COUNT_IMPL_157(_) PP_COUNT_IMPL_158
+#define PP_COUNT_IMPL_158(_) PP_COUNT_IMPL_159
+#define PP_COUNT_IMPL_159(_) PP_COUNT_IMPL_160
+#define PP_COUNT_IMPL_160(_) PP_COUNT_IMPL_161
+#define PP_COUNT_IMPL_161(_) PP_COUNT_IMPL_162
+#define PP_COUNT_IMPL_162(_) PP_COUNT_IMPL_163
+#define PP_COUNT_IMPL_163(_) PP_COUNT_IMPL_164
+#define PP_COUNT_IMPL_164(_) PP_COUNT_IMPL_165
+#define PP_COUNT_IMPL_165(_) PP_COUNT_IMPL_166
+#define PP_COUNT_IMPL_166(_) PP_COUNT_IMPL_167
+#define PP_COUNT_IMPL_167(_) PP_COUNT_IMPL_168
+#define PP_COUNT_IMPL_168(_) PP_COUNT_IMPL_169
+#define PP_COUNT_IMPL_169(_) PP_COUNT_IMPL_170
+#define PP_COUNT_IMPL_170(_) PP_COUNT_IMPL_171
+#define PP_COUNT_IMPL_171(_) PP_COUNT_IMPL_172
+#define PP_COUNT_IMPL_172(_) PP_COUNT_IMPL_173
+#define PP_COUNT_IMPL_173(_) PP_COUNT_IMPL_174
+#define PP_COUNT_IMPL_174(_) PP_COUNT_IMPL_175
+#define PP_COUNT_IMPL_175(_) PP_COUNT_IMPL_176
+#define PP_COUNT_IMPL_176(_) PP_COUNT_IMPL_177
+#define PP_COUNT_IMPL_177(_) PP_COUNT_IMPL_178
+#define PP_COUNT_IMPL_178(_) PP_COUNT_IMPL_179
+#define PP_COUNT_IMPL_179(_) PP_COUNT_IMPL_180
+#define PP_COUNT_IMPL_180(_) PP_COUNT_IMPL_181
+#define PP_COUNT_IMPL_181(_) PP_COUNT_IMPL_182
+#define PP_COUNT_IMPL_182(_) PP_COUNT_IMPL_183
+#define PP_COUNT_IMPL_183(_) PP_COUNT_IMPL_184
+#define PP_COUNT_IMPL_184(_) PP_COUNT_IMPL_185
+#define PP_COUNT_IMPL_185(_) PP_COUNT_IMPL_186
+#define PP_COUNT_IMPL_186(_) PP_COUNT_IMPL_187
+#define PP_COUNT_IMPL_187(_) PP_COUNT_IMPL_188
+#define PP_COUNT_IMPL_188(_) PP_COUNT_IMPL_189
+#define PP_COUNT_IMPL_189(_) PP_COUNT_IMPL_190
+#define PP_COUNT_IMPL_190(_) PP_COUNT_IMPL_191
+#define PP_COUNT_IMPL_191(_) PP_COUNT_IMPL_192
+#define PP_COUNT_IMPL_192(_) PP_COUNT_IMPL_193
+#define PP_COUNT_IMPL_193(_) PP_COUNT_IMPL_194
+#define PP_COUNT_IMPL_194(_) PP_COUNT_IMPL_195
+#define PP_COUNT_IMPL_195(_) PP_COUNT_IMPL_196
+#define PP_COUNT_IMPL_196(_) PP_COUNT_IMPL_197
+#define PP_COUNT_IMPL_197(_) PP_COUNT_IMPL_198
+#define PP_COUNT_IMPL_198(_) PP_COUNT_IMPL_199
+#define PP_COUNT_IMPL_199(_) PP_COUNT_IMPL_200
+
+////////////////////////////////////////////////////////////////////////////////
+#define PP_KILL_IMPL(seq, index) PP_CONCAT(PP_KILL_IMPL_, index) seq
+#define PP_KILL_IMPL_0
+#define PP_KILL_IMPL_1(_) PP_KILL_IMPL_0
+#define PP_KILL_IMPL_2(_) PP_KILL_IMPL_1
+#define PP_KILL_IMPL_3(_) PP_KILL_IMPL_2
+#define PP_KILL_IMPL_4(_) PP_KILL_IMPL_3
+#define PP_KILL_IMPL_5(_) PP_KILL_IMPL_4
+#define PP_KILL_IMPL_6(_) PP_KILL_IMPL_5
+#define PP_KILL_IMPL_7(_) PP_KILL_IMPL_6
+#define PP_KILL_IMPL_8(_) PP_KILL_IMPL_7
+#define PP_KILL_IMPL_9(_) PP_KILL_IMPL_8
+#define PP_KILL_IMPL_10(_) PP_KILL_IMPL_9
+#define PP_KILL_IMPL_11(_) PP_KILL_IMPL_10
+#define PP_KILL_IMPL_12(_) PP_KILL_IMPL_11
+#define PP_KILL_IMPL_13(_) PP_KILL_IMPL_12
+#define PP_KILL_IMPL_14(_) PP_KILL_IMPL_13
+#define PP_KILL_IMPL_15(_) PP_KILL_IMPL_14
+#define PP_KILL_IMPL_16(_) PP_KILL_IMPL_15
+#define PP_KILL_IMPL_17(_) PP_KILL_IMPL_16
+#define PP_KILL_IMPL_18(_) PP_KILL_IMPL_17
+#define PP_KILL_IMPL_19(_) PP_KILL_IMPL_18
+#define PP_KILL_IMPL_20(_) PP_KILL_IMPL_19
+#define PP_KILL_IMPL_21(_) PP_KILL_IMPL_20
+#define PP_KILL_IMPL_22(_) PP_KILL_IMPL_21
+#define PP_KILL_IMPL_23(_) PP_KILL_IMPL_22
+#define PP_KILL_IMPL_24(_) PP_KILL_IMPL_23
+#define PP_KILL_IMPL_25(_) PP_KILL_IMPL_24
+#define PP_KILL_IMPL_26(_) PP_KILL_IMPL_25
+#define PP_KILL_IMPL_27(_) PP_KILL_IMPL_26
+#define PP_KILL_IMPL_28(_) PP_KILL_IMPL_27
+#define PP_KILL_IMPL_29(_) PP_KILL_IMPL_28
+#define PP_KILL_IMPL_30(_) PP_KILL_IMPL_29
+#define PP_KILL_IMPL_31(_) PP_KILL_IMPL_30
+#define PP_KILL_IMPL_32(_) PP_KILL_IMPL_31
+#define PP_KILL_IMPL_33(_) PP_KILL_IMPL_32
+#define PP_KILL_IMPL_34(_) PP_KILL_IMPL_33
+#define PP_KILL_IMPL_35(_) PP_KILL_IMPL_34
+#define PP_KILL_IMPL_36(_) PP_KILL_IMPL_35
+#define PP_KILL_IMPL_37(_) PP_KILL_IMPL_36
+#define PP_KILL_IMPL_38(_) PP_KILL_IMPL_37
+#define PP_KILL_IMPL_39(_) PP_KILL_IMPL_38
+#define PP_KILL_IMPL_40(_) PP_KILL_IMPL_39
+#define PP_KILL_IMPL_41(_) PP_KILL_IMPL_40
+#define PP_KILL_IMPL_42(_) PP_KILL_IMPL_41
+#define PP_KILL_IMPL_43(_) PP_KILL_IMPL_42
+#define PP_KILL_IMPL_44(_) PP_KILL_IMPL_43
+#define PP_KILL_IMPL_45(_) PP_KILL_IMPL_44
+#define PP_KILL_IMPL_46(_) PP_KILL_IMPL_45
+#define PP_KILL_IMPL_47(_) PP_KILL_IMPL_46
+#define PP_KILL_IMPL_48(_) PP_KILL_IMPL_47
+#define PP_KILL_IMPL_49(_) PP_KILL_IMPL_48
+#define PP_KILL_IMPL_50(_) PP_KILL_IMPL_49
+#define PP_KILL_IMPL_51(_) PP_KILL_IMPL_50
+#define PP_KILL_IMPL_52(_) PP_KILL_IMPL_51
+#define PP_KILL_IMPL_53(_) PP_KILL_IMPL_52
+#define PP_KILL_IMPL_54(_) PP_KILL_IMPL_53
+#define PP_KILL_IMPL_55(_) PP_KILL_IMPL_54
+#define PP_KILL_IMPL_56(_) PP_KILL_IMPL_55
+#define PP_KILL_IMPL_57(_) PP_KILL_IMPL_56
+#define PP_KILL_IMPL_58(_) PP_KILL_IMPL_57
+#define PP_KILL_IMPL_59(_) PP_KILL_IMPL_58
+#define PP_KILL_IMPL_60(_) PP_KILL_IMPL_59
+#define PP_KILL_IMPL_61(_) PP_KILL_IMPL_60
+#define PP_KILL_IMPL_62(_) PP_KILL_IMPL_61
+#define PP_KILL_IMPL_63(_) PP_KILL_IMPL_62
+#define PP_KILL_IMPL_64(_) PP_KILL_IMPL_63
+#define PP_KILL_IMPL_65(_) PP_KILL_IMPL_64
+#define PP_KILL_IMPL_66(_) PP_KILL_IMPL_65
+#define PP_KILL_IMPL_67(_) PP_KILL_IMPL_66
+#define PP_KILL_IMPL_68(_) PP_KILL_IMPL_67
+#define PP_KILL_IMPL_69(_) PP_KILL_IMPL_68
+#define PP_KILL_IMPL_70(_) PP_KILL_IMPL_69
+#define PP_KILL_IMPL_71(_) PP_KILL_IMPL_70
+#define PP_KILL_IMPL_72(_) PP_KILL_IMPL_71
+#define PP_KILL_IMPL_73(_) PP_KILL_IMPL_72
+#define PP_KILL_IMPL_74(_) PP_KILL_IMPL_73
+#define PP_KILL_IMPL_75(_) PP_KILL_IMPL_74
+#define PP_KILL_IMPL_76(_) PP_KILL_IMPL_75
+#define PP_KILL_IMPL_77(_) PP_KILL_IMPL_76
+#define PP_KILL_IMPL_78(_) PP_KILL_IMPL_77
+#define PP_KILL_IMPL_79(_) PP_KILL_IMPL_78
+#define PP_KILL_IMPL_80(_) PP_KILL_IMPL_79
+#define PP_KILL_IMPL_81(_) PP_KILL_IMPL_80
+#define PP_KILL_IMPL_82(_) PP_KILL_IMPL_81
+#define PP_KILL_IMPL_83(_) PP_KILL_IMPL_82
+#define PP_KILL_IMPL_84(_) PP_KILL_IMPL_83
+#define PP_KILL_IMPL_85(_) PP_KILL_IMPL_84
+#define PP_KILL_IMPL_86(_) PP_KILL_IMPL_85
+#define PP_KILL_IMPL_87(_) PP_KILL_IMPL_86
+#define PP_KILL_IMPL_88(_) PP_KILL_IMPL_87
+#define PP_KILL_IMPL_89(_) PP_KILL_IMPL_88
+#define PP_KILL_IMPL_90(_) PP_KILL_IMPL_89
+#define PP_KILL_IMPL_91(_) PP_KILL_IMPL_90
+#define PP_KILL_IMPL_92(_) PP_KILL_IMPL_91
+#define PP_KILL_IMPL_93(_) PP_KILL_IMPL_92
+#define PP_KILL_IMPL_94(_) PP_KILL_IMPL_93
+#define PP_KILL_IMPL_95(_) PP_KILL_IMPL_94
+#define PP_KILL_IMPL_96(_) PP_KILL_IMPL_95
+#define PP_KILL_IMPL_97(_) PP_KILL_IMPL_96
+#define PP_KILL_IMPL_98(_) PP_KILL_IMPL_97
+#define PP_KILL_IMPL_99(_) PP_KILL_IMPL_98
+#define PP_KILL_IMPL_100(_) PP_KILL_IMPL_99
+#define PP_KILL_IMPL_101(_) PP_KILL_IMPL_100
+#define PP_KILL_IMPL_102(_) PP_KILL_IMPL_101
+#define PP_KILL_IMPL_103(_) PP_KILL_IMPL_102
+#define PP_KILL_IMPL_104(_) PP_KILL_IMPL_103
+#define PP_KILL_IMPL_105(_) PP_KILL_IMPL_104
+#define PP_KILL_IMPL_106(_) PP_KILL_IMPL_105
+#define PP_KILL_IMPL_107(_) PP_KILL_IMPL_106
+#define PP_KILL_IMPL_108(_) PP_KILL_IMPL_107
+#define PP_KILL_IMPL_109(_) PP_KILL_IMPL_108
+#define PP_KILL_IMPL_110(_) PP_KILL_IMPL_109
+#define PP_KILL_IMPL_111(_) PP_KILL_IMPL_110
+#define PP_KILL_IMPL_112(_) PP_KILL_IMPL_111
+#define PP_KILL_IMPL_113(_) PP_KILL_IMPL_112
+#define PP_KILL_IMPL_114(_) PP_KILL_IMPL_113
+#define PP_KILL_IMPL_115(_) PP_KILL_IMPL_114
+#define PP_KILL_IMPL_116(_) PP_KILL_IMPL_115
+#define PP_KILL_IMPL_117(_) PP_KILL_IMPL_116
+#define PP_KILL_IMPL_118(_) PP_KILL_IMPL_117
+#define PP_KILL_IMPL_119(_) PP_KILL_IMPL_118
+#define PP_KILL_IMPL_120(_) PP_KILL_IMPL_119
+#define PP_KILL_IMPL_121(_) PP_KILL_IMPL_120
+#define PP_KILL_IMPL_122(_) PP_KILL_IMPL_121
+#define PP_KILL_IMPL_123(_) PP_KILL_IMPL_122
+#define PP_KILL_IMPL_124(_) PP_KILL_IMPL_123
+#define PP_KILL_IMPL_125(_) PP_KILL_IMPL_124
+#define PP_KILL_IMPL_126(_) PP_KILL_IMPL_125
+#define PP_KILL_IMPL_127(_) PP_KILL_IMPL_126
+#define PP_KILL_IMPL_128(_) PP_KILL_IMPL_127
+#define PP_KILL_IMPL_129(_) PP_KILL_IMPL_128
+#define PP_KILL_IMPL_130(_) PP_KILL_IMPL_129
+#define PP_KILL_IMPL_131(_) PP_KILL_IMPL_130
+#define PP_KILL_IMPL_132(_) PP_KILL_IMPL_131
+#define PP_KILL_IMPL_133(_) PP_KILL_IMPL_132
+#define PP_KILL_IMPL_134(_) PP_KILL_IMPL_133
+#define PP_KILL_IMPL_135(_) PP_KILL_IMPL_134
+#define PP_KILL_IMPL_136(_) PP_KILL_IMPL_135
+#define PP_KILL_IMPL_137(_) PP_KILL_IMPL_136
+#define PP_KILL_IMPL_138(_) PP_KILL_IMPL_137
+#define PP_KILL_IMPL_139(_) PP_KILL_IMPL_138
+#define PP_KILL_IMPL_140(_) PP_KILL_IMPL_139
+#define PP_KILL_IMPL_141(_) PP_KILL_IMPL_140
+#define PP_KILL_IMPL_142(_) PP_KILL_IMPL_141
+#define PP_KILL_IMPL_143(_) PP_KILL_IMPL_142
+#define PP_KILL_IMPL_144(_) PP_KILL_IMPL_143
+#define PP_KILL_IMPL_145(_) PP_KILL_IMPL_144
+#define PP_KILL_IMPL_146(_) PP_KILL_IMPL_145
+#define PP_KILL_IMPL_147(_) PP_KILL_IMPL_146
+#define PP_KILL_IMPL_148(_) PP_KILL_IMPL_147
+#define PP_KILL_IMPL_149(_) PP_KILL_IMPL_148
+#define PP_KILL_IMPL_150(_) PP_KILL_IMPL_149
+#define PP_KILL_IMPL_151(_) PP_KILL_IMPL_150
+#define PP_KILL_IMPL_152(_) PP_KILL_IMPL_151
+#define PP_KILL_IMPL_153(_) PP_KILL_IMPL_152
+#define PP_KILL_IMPL_154(_) PP_KILL_IMPL_153
+#define PP_KILL_IMPL_155(_) PP_KILL_IMPL_154
+#define PP_KILL_IMPL_156(_) PP_KILL_IMPL_155
+#define PP_KILL_IMPL_157(_) PP_KILL_IMPL_156
+#define PP_KILL_IMPL_158(_) PP_KILL_IMPL_157
+#define PP_KILL_IMPL_159(_) PP_KILL_IMPL_158
+#define PP_KILL_IMPL_160(_) PP_KILL_IMPL_159
+#define PP_KILL_IMPL_161(_) PP_KILL_IMPL_160
+#define PP_KILL_IMPL_162(_) PP_KILL_IMPL_161
+#define PP_KILL_IMPL_163(_) PP_KILL_IMPL_162
+#define PP_KILL_IMPL_164(_) PP_KILL_IMPL_163
+#define PP_KILL_IMPL_165(_) PP_KILL_IMPL_164
+#define PP_KILL_IMPL_166(_) PP_KILL_IMPL_165
+#define PP_KILL_IMPL_167(_) PP_KILL_IMPL_166
+#define PP_KILL_IMPL_168(_) PP_KILL_IMPL_167
+#define PP_KILL_IMPL_169(_) PP_KILL_IMPL_168
+#define PP_KILL_IMPL_170(_) PP_KILL_IMPL_169
+#define PP_KILL_IMPL_171(_) PP_KILL_IMPL_170
+#define PP_KILL_IMPL_172(_) PP_KILL_IMPL_171
+#define PP_KILL_IMPL_173(_) PP_KILL_IMPL_172
+#define PP_KILL_IMPL_174(_) PP_KILL_IMPL_173
+#define PP_KILL_IMPL_175(_) PP_KILL_IMPL_174
+#define PP_KILL_IMPL_176(_) PP_KILL_IMPL_175
+#define PP_KILL_IMPL_177(_) PP_KILL_IMPL_176
+#define PP_KILL_IMPL_178(_) PP_KILL_IMPL_177
+#define PP_KILL_IMPL_179(_) PP_KILL_IMPL_178
+#define PP_KILL_IMPL_180(_) PP_KILL_IMPL_179
+#define PP_KILL_IMPL_181(_) PP_KILL_IMPL_180
+#define PP_KILL_IMPL_182(_) PP_KILL_IMPL_181
+#define PP_KILL_IMPL_183(_) PP_KILL_IMPL_182
+#define PP_KILL_IMPL_184(_) PP_KILL_IMPL_183
+#define PP_KILL_IMPL_185(_) PP_KILL_IMPL_184
+#define PP_KILL_IMPL_186(_) PP_KILL_IMPL_185
+#define PP_KILL_IMPL_187(_) PP_KILL_IMPL_186
+#define PP_KILL_IMPL_188(_) PP_KILL_IMPL_187
+#define PP_KILL_IMPL_189(_) PP_KILL_IMPL_188
+#define PP_KILL_IMPL_190(_) PP_KILL_IMPL_189
+#define PP_KILL_IMPL_191(_) PP_KILL_IMPL_190
+#define PP_KILL_IMPL_192(_) PP_KILL_IMPL_191
+#define PP_KILL_IMPL_193(_) PP_KILL_IMPL_192
+#define PP_KILL_IMPL_194(_) PP_KILL_IMPL_193
+#define PP_KILL_IMPL_195(_) PP_KILL_IMPL_194
+#define PP_KILL_IMPL_196(_) PP_KILL_IMPL_195
+#define PP_KILL_IMPL_197(_) PP_KILL_IMPL_196
+#define PP_KILL_IMPL_198(_) PP_KILL_IMPL_197
+#define PP_KILL_IMPL_199(_) PP_KILL_IMPL_198
+#define PP_KILL_IMPL_200(_) PP_KILL_IMPL_199
+
+////////////////////////////////////////////////////////////////////////////////
+#define PP_ELEMENT_IMPL(seq, \
+ index) PP_ELEMENT_IMPL_A((PP_CONCAT(PP_ELEMENT_IMPL_, index) seq))
+#define PP_ELEMENT_IMPL_A(x) PP_ELEMENT_IMPL_C(PP_ELEMENT_IMPL_B x)
+#define PP_ELEMENT_IMPL_B(x, _) x
+#define PP_ELEMENT_IMPL_C(x) x
+#define PP_ELEMENT_IMPL_0(x) x, PP_NIL
+#define PP_ELEMENT_IMPL_1(_) PP_ELEMENT_IMPL_0
+#define PP_ELEMENT_IMPL_2(_) PP_ELEMENT_IMPL_1
+#define PP_ELEMENT_IMPL_3(_) PP_ELEMENT_IMPL_2
+#define PP_ELEMENT_IMPL_4(_) PP_ELEMENT_IMPL_3
+#define PP_ELEMENT_IMPL_5(_) PP_ELEMENT_IMPL_4
+#define PP_ELEMENT_IMPL_6(_) PP_ELEMENT_IMPL_5
+#define PP_ELEMENT_IMPL_7(_) PP_ELEMENT_IMPL_6
+#define PP_ELEMENT_IMPL_8(_) PP_ELEMENT_IMPL_7
+#define PP_ELEMENT_IMPL_9(_) PP_ELEMENT_IMPL_8
+#define PP_ELEMENT_IMPL_10(_) PP_ELEMENT_IMPL_9
+#define PP_ELEMENT_IMPL_11(_) PP_ELEMENT_IMPL_10
+#define PP_ELEMENT_IMPL_12(_) PP_ELEMENT_IMPL_11
+#define PP_ELEMENT_IMPL_13(_) PP_ELEMENT_IMPL_12
+#define PP_ELEMENT_IMPL_14(_) PP_ELEMENT_IMPL_13
+#define PP_ELEMENT_IMPL_15(_) PP_ELEMENT_IMPL_14
+#define PP_ELEMENT_IMPL_16(_) PP_ELEMENT_IMPL_15
+#define PP_ELEMENT_IMPL_17(_) PP_ELEMENT_IMPL_16
+#define PP_ELEMENT_IMPL_18(_) PP_ELEMENT_IMPL_17
+#define PP_ELEMENT_IMPL_19(_) PP_ELEMENT_IMPL_18
+#define PP_ELEMENT_IMPL_20(_) PP_ELEMENT_IMPL_19
+#define PP_ELEMENT_IMPL_21(_) PP_ELEMENT_IMPL_20
+#define PP_ELEMENT_IMPL_22(_) PP_ELEMENT_IMPL_21
+#define PP_ELEMENT_IMPL_23(_) PP_ELEMENT_IMPL_22
+#define PP_ELEMENT_IMPL_24(_) PP_ELEMENT_IMPL_23
+#define PP_ELEMENT_IMPL_25(_) PP_ELEMENT_IMPL_24
+#define PP_ELEMENT_IMPL_26(_) PP_ELEMENT_IMPL_25
+#define PP_ELEMENT_IMPL_27(_) PP_ELEMENT_IMPL_26
+#define PP_ELEMENT_IMPL_28(_) PP_ELEMENT_IMPL_27
+#define PP_ELEMENT_IMPL_29(_) PP_ELEMENT_IMPL_28
+#define PP_ELEMENT_IMPL_30(_) PP_ELEMENT_IMPL_29
+#define PP_ELEMENT_IMPL_31(_) PP_ELEMENT_IMPL_30
+#define PP_ELEMENT_IMPL_32(_) PP_ELEMENT_IMPL_31
+#define PP_ELEMENT_IMPL_33(_) PP_ELEMENT_IMPL_32
+#define PP_ELEMENT_IMPL_34(_) PP_ELEMENT_IMPL_33
+#define PP_ELEMENT_IMPL_35(_) PP_ELEMENT_IMPL_34
+#define PP_ELEMENT_IMPL_36(_) PP_ELEMENT_IMPL_35
+#define PP_ELEMENT_IMPL_37(_) PP_ELEMENT_IMPL_36
+#define PP_ELEMENT_IMPL_38(_) PP_ELEMENT_IMPL_37
+#define PP_ELEMENT_IMPL_39(_) PP_ELEMENT_IMPL_38
+#define PP_ELEMENT_IMPL_40(_) PP_ELEMENT_IMPL_39
+#define PP_ELEMENT_IMPL_41(_) PP_ELEMENT_IMPL_40
+#define PP_ELEMENT_IMPL_42(_) PP_ELEMENT_IMPL_41
+#define PP_ELEMENT_IMPL_43(_) PP_ELEMENT_IMPL_42
+#define PP_ELEMENT_IMPL_44(_) PP_ELEMENT_IMPL_43
+#define PP_ELEMENT_IMPL_45(_) PP_ELEMENT_IMPL_44
+#define PP_ELEMENT_IMPL_46(_) PP_ELEMENT_IMPL_45
+#define PP_ELEMENT_IMPL_47(_) PP_ELEMENT_IMPL_46
+#define PP_ELEMENT_IMPL_48(_) PP_ELEMENT_IMPL_47
+#define PP_ELEMENT_IMPL_49(_) PP_ELEMENT_IMPL_48
+#define PP_ELEMENT_IMPL_50(_) PP_ELEMENT_IMPL_49
+#define PP_ELEMENT_IMPL_51(_) PP_ELEMENT_IMPL_50
+#define PP_ELEMENT_IMPL_52(_) PP_ELEMENT_IMPL_51
+#define PP_ELEMENT_IMPL_53(_) PP_ELEMENT_IMPL_52
+#define PP_ELEMENT_IMPL_54(_) PP_ELEMENT_IMPL_53
+#define PP_ELEMENT_IMPL_55(_) PP_ELEMENT_IMPL_54
+#define PP_ELEMENT_IMPL_56(_) PP_ELEMENT_IMPL_55
+#define PP_ELEMENT_IMPL_57(_) PP_ELEMENT_IMPL_56
+#define PP_ELEMENT_IMPL_58(_) PP_ELEMENT_IMPL_57
+#define PP_ELEMENT_IMPL_59(_) PP_ELEMENT_IMPL_58
+#define PP_ELEMENT_IMPL_60(_) PP_ELEMENT_IMPL_59
+#define PP_ELEMENT_IMPL_61(_) PP_ELEMENT_IMPL_60
+#define PP_ELEMENT_IMPL_62(_) PP_ELEMENT_IMPL_61
+#define PP_ELEMENT_IMPL_63(_) PP_ELEMENT_IMPL_62
+#define PP_ELEMENT_IMPL_64(_) PP_ELEMENT_IMPL_63
+#define PP_ELEMENT_IMPL_65(_) PP_ELEMENT_IMPL_64
+#define PP_ELEMENT_IMPL_66(_) PP_ELEMENT_IMPL_65
+#define PP_ELEMENT_IMPL_67(_) PP_ELEMENT_IMPL_66
+#define PP_ELEMENT_IMPL_68(_) PP_ELEMENT_IMPL_67
+#define PP_ELEMENT_IMPL_69(_) PP_ELEMENT_IMPL_68
+#define PP_ELEMENT_IMPL_70(_) PP_ELEMENT_IMPL_69
+#define PP_ELEMENT_IMPL_71(_) PP_ELEMENT_IMPL_70
+#define PP_ELEMENT_IMPL_72(_) PP_ELEMENT_IMPL_71
+#define PP_ELEMENT_IMPL_73(_) PP_ELEMENT_IMPL_72
+#define PP_ELEMENT_IMPL_74(_) PP_ELEMENT_IMPL_73
+#define PP_ELEMENT_IMPL_75(_) PP_ELEMENT_IMPL_74
+#define PP_ELEMENT_IMPL_76(_) PP_ELEMENT_IMPL_75
+#define PP_ELEMENT_IMPL_77(_) PP_ELEMENT_IMPL_76
+#define PP_ELEMENT_IMPL_78(_) PP_ELEMENT_IMPL_77
+#define PP_ELEMENT_IMPL_79(_) PP_ELEMENT_IMPL_78
+#define PP_ELEMENT_IMPL_80(_) PP_ELEMENT_IMPL_79
+#define PP_ELEMENT_IMPL_81(_) PP_ELEMENT_IMPL_80
+#define PP_ELEMENT_IMPL_82(_) PP_ELEMENT_IMPL_81
+#define PP_ELEMENT_IMPL_83(_) PP_ELEMENT_IMPL_82
+#define PP_ELEMENT_IMPL_84(_) PP_ELEMENT_IMPL_83
+#define PP_ELEMENT_IMPL_85(_) PP_ELEMENT_IMPL_84
+#define PP_ELEMENT_IMPL_86(_) PP_ELEMENT_IMPL_85
+#define PP_ELEMENT_IMPL_87(_) PP_ELEMENT_IMPL_86
+#define PP_ELEMENT_IMPL_88(_) PP_ELEMENT_IMPL_87
+#define PP_ELEMENT_IMPL_89(_) PP_ELEMENT_IMPL_88
+#define PP_ELEMENT_IMPL_90(_) PP_ELEMENT_IMPL_89
+#define PP_ELEMENT_IMPL_91(_) PP_ELEMENT_IMPL_90
+#define PP_ELEMENT_IMPL_92(_) PP_ELEMENT_IMPL_91
+#define PP_ELEMENT_IMPL_93(_) PP_ELEMENT_IMPL_92
+#define PP_ELEMENT_IMPL_94(_) PP_ELEMENT_IMPL_93
+#define PP_ELEMENT_IMPL_95(_) PP_ELEMENT_IMPL_94
+#define PP_ELEMENT_IMPL_96(_) PP_ELEMENT_IMPL_95
+#define PP_ELEMENT_IMPL_97(_) PP_ELEMENT_IMPL_96
+#define PP_ELEMENT_IMPL_98(_) PP_ELEMENT_IMPL_97
+#define PP_ELEMENT_IMPL_99(_) PP_ELEMENT_IMPL_98
+#define PP_ELEMENT_IMPL_100(_) PP_ELEMENT_IMPL_99
+#define PP_ELEMENT_IMPL_101(_) PP_ELEMENT_IMPL_100
+#define PP_ELEMENT_IMPL_102(_) PP_ELEMENT_IMPL_101
+#define PP_ELEMENT_IMPL_103(_) PP_ELEMENT_IMPL_102
+#define PP_ELEMENT_IMPL_104(_) PP_ELEMENT_IMPL_103
+#define PP_ELEMENT_IMPL_105(_) PP_ELEMENT_IMPL_104
+#define PP_ELEMENT_IMPL_106(_) PP_ELEMENT_IMPL_105
+#define PP_ELEMENT_IMPL_107(_) PP_ELEMENT_IMPL_106
+#define PP_ELEMENT_IMPL_108(_) PP_ELEMENT_IMPL_107
+#define PP_ELEMENT_IMPL_109(_) PP_ELEMENT_IMPL_108
+#define PP_ELEMENT_IMPL_110(_) PP_ELEMENT_IMPL_109
+#define PP_ELEMENT_IMPL_111(_) PP_ELEMENT_IMPL_110
+#define PP_ELEMENT_IMPL_112(_) PP_ELEMENT_IMPL_111
+#define PP_ELEMENT_IMPL_113(_) PP_ELEMENT_IMPL_112
+#define PP_ELEMENT_IMPL_114(_) PP_ELEMENT_IMPL_113
+#define PP_ELEMENT_IMPL_115(_) PP_ELEMENT_IMPL_114
+#define PP_ELEMENT_IMPL_116(_) PP_ELEMENT_IMPL_115
+#define PP_ELEMENT_IMPL_117(_) PP_ELEMENT_IMPL_116
+#define PP_ELEMENT_IMPL_118(_) PP_ELEMENT_IMPL_117
+#define PP_ELEMENT_IMPL_119(_) PP_ELEMENT_IMPL_118
+#define PP_ELEMENT_IMPL_120(_) PP_ELEMENT_IMPL_119
+#define PP_ELEMENT_IMPL_121(_) PP_ELEMENT_IMPL_120
+#define PP_ELEMENT_IMPL_122(_) PP_ELEMENT_IMPL_121
+#define PP_ELEMENT_IMPL_123(_) PP_ELEMENT_IMPL_122
+#define PP_ELEMENT_IMPL_124(_) PP_ELEMENT_IMPL_123
+#define PP_ELEMENT_IMPL_125(_) PP_ELEMENT_IMPL_124
+#define PP_ELEMENT_IMPL_126(_) PP_ELEMENT_IMPL_125
+#define PP_ELEMENT_IMPL_127(_) PP_ELEMENT_IMPL_126
+#define PP_ELEMENT_IMPL_128(_) PP_ELEMENT_IMPL_127
+#define PP_ELEMENT_IMPL_129(_) PP_ELEMENT_IMPL_128
+#define PP_ELEMENT_IMPL_130(_) PP_ELEMENT_IMPL_129
+#define PP_ELEMENT_IMPL_131(_) PP_ELEMENT_IMPL_130
+#define PP_ELEMENT_IMPL_132(_) PP_ELEMENT_IMPL_131
+#define PP_ELEMENT_IMPL_133(_) PP_ELEMENT_IMPL_132
+#define PP_ELEMENT_IMPL_134(_) PP_ELEMENT_IMPL_133
+#define PP_ELEMENT_IMPL_135(_) PP_ELEMENT_IMPL_134
+#define PP_ELEMENT_IMPL_136(_) PP_ELEMENT_IMPL_135
+#define PP_ELEMENT_IMPL_137(_) PP_ELEMENT_IMPL_136
+#define PP_ELEMENT_IMPL_138(_) PP_ELEMENT_IMPL_137
+#define PP_ELEMENT_IMPL_139(_) PP_ELEMENT_IMPL_138
+#define PP_ELEMENT_IMPL_140(_) PP_ELEMENT_IMPL_139
+#define PP_ELEMENT_IMPL_141(_) PP_ELEMENT_IMPL_140
+#define PP_ELEMENT_IMPL_142(_) PP_ELEMENT_IMPL_141
+#define PP_ELEMENT_IMPL_143(_) PP_ELEMENT_IMPL_142
+#define PP_ELEMENT_IMPL_144(_) PP_ELEMENT_IMPL_143
+#define PP_ELEMENT_IMPL_145(_) PP_ELEMENT_IMPL_144
+#define PP_ELEMENT_IMPL_146(_) PP_ELEMENT_IMPL_145
+#define PP_ELEMENT_IMPL_147(_) PP_ELEMENT_IMPL_146
+#define PP_ELEMENT_IMPL_148(_) PP_ELEMENT_IMPL_147
+#define PP_ELEMENT_IMPL_149(_) PP_ELEMENT_IMPL_148
+#define PP_ELEMENT_IMPL_150(_) PP_ELEMENT_IMPL_149
+#define PP_ELEMENT_IMPL_151(_) PP_ELEMENT_IMPL_150
+#define PP_ELEMENT_IMPL_152(_) PP_ELEMENT_IMPL_151
+#define PP_ELEMENT_IMPL_153(_) PP_ELEMENT_IMPL_152
+#define PP_ELEMENT_IMPL_154(_) PP_ELEMENT_IMPL_153
+#define PP_ELEMENT_IMPL_155(_) PP_ELEMENT_IMPL_154
+#define PP_ELEMENT_IMPL_156(_) PP_ELEMENT_IMPL_155
+#define PP_ELEMENT_IMPL_157(_) PP_ELEMENT_IMPL_156
+#define PP_ELEMENT_IMPL_158(_) PP_ELEMENT_IMPL_157
+#define PP_ELEMENT_IMPL_159(_) PP_ELEMENT_IMPL_158
+#define PP_ELEMENT_IMPL_160(_) PP_ELEMENT_IMPL_159
+#define PP_ELEMENT_IMPL_161(_) PP_ELEMENT_IMPL_160
+#define PP_ELEMENT_IMPL_162(_) PP_ELEMENT_IMPL_161
+#define PP_ELEMENT_IMPL_163(_) PP_ELEMENT_IMPL_162
+#define PP_ELEMENT_IMPL_164(_) PP_ELEMENT_IMPL_163
+#define PP_ELEMENT_IMPL_165(_) PP_ELEMENT_IMPL_164
+#define PP_ELEMENT_IMPL_166(_) PP_ELEMENT_IMPL_165
+#define PP_ELEMENT_IMPL_167(_) PP_ELEMENT_IMPL_166
+#define PP_ELEMENT_IMPL_168(_) PP_ELEMENT_IMPL_167
+#define PP_ELEMENT_IMPL_169(_) PP_ELEMENT_IMPL_168
+#define PP_ELEMENT_IMPL_170(_) PP_ELEMENT_IMPL_169
+#define PP_ELEMENT_IMPL_171(_) PP_ELEMENT_IMPL_170
+#define PP_ELEMENT_IMPL_172(_) PP_ELEMENT_IMPL_171
+#define PP_ELEMENT_IMPL_173(_) PP_ELEMENT_IMPL_172
+#define PP_ELEMENT_IMPL_174(_) PP_ELEMENT_IMPL_173
+#define PP_ELEMENT_IMPL_175(_) PP_ELEMENT_IMPL_174
+#define PP_ELEMENT_IMPL_176(_) PP_ELEMENT_IMPL_175
+#define PP_ELEMENT_IMPL_177(_) PP_ELEMENT_IMPL_176
+#define PP_ELEMENT_IMPL_178(_) PP_ELEMENT_IMPL_177
+#define PP_ELEMENT_IMPL_179(_) PP_ELEMENT_IMPL_178
+#define PP_ELEMENT_IMPL_180(_) PP_ELEMENT_IMPL_179
+#define PP_ELEMENT_IMPL_181(_) PP_ELEMENT_IMPL_180
+#define PP_ELEMENT_IMPL_182(_) PP_ELEMENT_IMPL_181
+#define PP_ELEMENT_IMPL_183(_) PP_ELEMENT_IMPL_182
+#define PP_ELEMENT_IMPL_184(_) PP_ELEMENT_IMPL_183
+#define PP_ELEMENT_IMPL_185(_) PP_ELEMENT_IMPL_184
+#define PP_ELEMENT_IMPL_186(_) PP_ELEMENT_IMPL_185
+#define PP_ELEMENT_IMPL_187(_) PP_ELEMENT_IMPL_186
+#define PP_ELEMENT_IMPL_188(_) PP_ELEMENT_IMPL_187
+#define PP_ELEMENT_IMPL_189(_) PP_ELEMENT_IMPL_188
+#define PP_ELEMENT_IMPL_190(_) PP_ELEMENT_IMPL_189
+#define PP_ELEMENT_IMPL_191(_) PP_ELEMENT_IMPL_190
+#define PP_ELEMENT_IMPL_192(_) PP_ELEMENT_IMPL_191
+#define PP_ELEMENT_IMPL_193(_) PP_ELEMENT_IMPL_192
+#define PP_ELEMENT_IMPL_194(_) PP_ELEMENT_IMPL_193
+#define PP_ELEMENT_IMPL_195(_) PP_ELEMENT_IMPL_194
+#define PP_ELEMENT_IMPL_196(_) PP_ELEMENT_IMPL_195
+#define PP_ELEMENT_IMPL_197(_) PP_ELEMENT_IMPL_196
+#define PP_ELEMENT_IMPL_198(_) PP_ELEMENT_IMPL_197
+#define PP_ELEMENT_IMPL_199(_) PP_ELEMENT_IMPL_198
+#define PP_ELEMENT_IMPL_200(_) PP_ELEMENT_IMPL_199
+
+////////////////////////////////////////////////////////////////////////////////
+#define PP_HEAD_IMPL(seq) PP_ELEMENT_IMPL(seq, 0)
+
+////////////////////////////////////////////////////////////////////////////////
+#define PP_TAIL_IMPL(seq) PP_KILL_IMPL(seq, 1)
+
+////////////////////////////////////////////////////////////////////////////////
+#define PP_FOR_EACH_IMPL(what, seq) PP_CONCAT(PP_FOR_EACH_IMPL_, \
+ PP_COUNT(seq))(what, seq)
+#define PP_FOR_EACH_IMPL_0(what, seq)
+#define PP_FOR_EACH_IMPL_1(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_0(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_2(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_1(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_3(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_2(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_4(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_3(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_5(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_4(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_6(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_5(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_7(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_6(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_8(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_7(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_9(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_8(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_10(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_9(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_11(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_10(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_12(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_11(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_13(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_12(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_14(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_13(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_15(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_14(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_16(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_15(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_17(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_16(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_18(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_17(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_19(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_18(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_20(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_19(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_21(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_20(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_22(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_21(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_23(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_22(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_24(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_23(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_25(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_24(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_26(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_25(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_27(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_26(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_28(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_27(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_29(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_28(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_30(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_29(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_31(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_30(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_32(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_31(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_33(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_32(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_34(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_33(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_35(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_34(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_36(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_35(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_37(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_36(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_38(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_37(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_39(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_38(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_40(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_39(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_41(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_40(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_42(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_41(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_43(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_42(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_44(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_43(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_45(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_44(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_46(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_45(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_47(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_46(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_48(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_47(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_49(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_48(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_50(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_49(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_51(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_50(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_52(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_51(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_53(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_52(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_54(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_53(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_55(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_54(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_56(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_55(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_57(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_56(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_58(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_57(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_59(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_58(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_60(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_59(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_61(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_60(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_62(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_61(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_63(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_62(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_64(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_63(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_65(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_64(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_66(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_65(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_67(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_66(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_68(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_67(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_69(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_68(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_70(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_69(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_71(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_70(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_72(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_71(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_73(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_72(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_74(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_73(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_75(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_74(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_76(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_75(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_77(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_76(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_78(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_77(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_79(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_78(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_80(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_79(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_81(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_80(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_82(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_81(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_83(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_82(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_84(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_83(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_85(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_84(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_86(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_85(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_87(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_86(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_88(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_87(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_89(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_88(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_90(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_89(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_91(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_90(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_92(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_91(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_93(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_92(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_94(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_93(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_95(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_94(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_96(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_95(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_97(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_96(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_98(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_97(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_99(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_98(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_100(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_99(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_101(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_100(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_102(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_101(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_103(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_102(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_104(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_103(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_105(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_104(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_106(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_105(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_107(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_106(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_108(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_107(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_109(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_108(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_110(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_109(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_111(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_110(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_112(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_111(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_113(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_112(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_114(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_113(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_115(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_114(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_116(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_115(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_117(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_116(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_118(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_117(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_119(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_118(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_120(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_119(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_121(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_120(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_122(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_121(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_123(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_122(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_124(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_123(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_125(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_124(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_126(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_125(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_127(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_126(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_128(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_127(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_129(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_128(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_130(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_129(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_131(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_130(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_132(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_131(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_133(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_132(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_134(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_133(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_135(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_134(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_136(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_135(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_137(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_136(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_138(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_137(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_139(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_138(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_140(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_139(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_141(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_140(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_142(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_141(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_143(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_142(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_144(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_143(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_145(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_144(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_146(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_145(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_147(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_146(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_148(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_147(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_149(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_148(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_150(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_149(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_151(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_150(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_152(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_151(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_153(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_152(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_154(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_153(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_155(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_154(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_156(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_155(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_157(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_156(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_158(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_157(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_159(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_158(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_160(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_159(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_161(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_160(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_162(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_161(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_163(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_162(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_164(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_163(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_165(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_164(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_166(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_165(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_167(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_166(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_168(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_167(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_169(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_168(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_170(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_169(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_171(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_170(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_172(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_171(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_173(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_172(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_174(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_173(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_175(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_174(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_176(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_175(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_177(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_176(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_178(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_177(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_179(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_178(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_180(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_179(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_181(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_180(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_182(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_181(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_183(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_182(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_184(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_183(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_185(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_184(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_186(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_185(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_187(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_186(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_188(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_187(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_189(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_188(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_190(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_189(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_191(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_190(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_192(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_191(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_193(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_192(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_194(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_193(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_195(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_194(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_196(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_195(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_197(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_196(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_198(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_197(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_199(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_198(what, PP_TAIL(seq))
+#define PP_FOR_EACH_IMPL_200(what, \
+ seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_199(what, PP_TAIL(seq))
+////////////////////////////////////////////////////////////////////////////////
+/*!
+ \endinternal
+*/
diff --git a/library/cpp/yt/misc/preprocessor-gen.h.pump b/library/cpp/yt/misc/preprocessor-gen.h.pump
new file mode 100644
index 0000000000..0f178ae37e
--- /dev/null
+++ b/library/cpp/yt/misc/preprocessor-gen.h.pump
@@ -0,0 +1,70 @@
+#pragma once
+
+$$ Please, use Pump to convert this source file to valid C++ header.
+$$ Note that lines in this file could be longer than 80 symbols.
+$var n = 199
+$range i 0..n
+
+/*!
+ \internal
+*/
+
+#ifndef PREPROCESSOR_GEN_H_
+#error "Direct inclusion of this file is not allowed, include preprocessor.h"
+// For the sake of sane code completion.
+#include "preprocessor.h"
+#endif
+#undef PREPROCESSOR_GEN_H_
+
+////////////////////////////////////////////////////////////////////////////////
+#define PP_COUNT_IMPL(...) PP_CONCAT(PP_COUNT_CONST_, PP_COUNT_IMPL_0 __VA_ARGS__)
+
+$for i [[
+#define PP_COUNT_CONST_PP_COUNT_IMPL_$i $i
+
+]]
+
+$for i [[
+#define PP_COUNT_IMPL_$i(_) PP_COUNT_IMPL_$(i+1)
+
+]]
+
+////////////////////////////////////////////////////////////////////////////////
+#define PP_KILL_IMPL(seq, index) PP_CONCAT(PP_KILL_IMPL_, index) seq
+#define PP_KILL_IMPL_0
+
+$for i [[
+#define PP_KILL_IMPL_$(i+1)(_) PP_KILL_IMPL_$i
+
+]]
+
+////////////////////////////////////////////////////////////////////////////////
+#define PP_ELEMENT_IMPL(seq, index) PP_ELEMENT_IMPL_A((PP_CONCAT(PP_ELEMENT_IMPL_, index) seq))
+#define PP_ELEMENT_IMPL_A(x) PP_ELEMENT_IMPL_C(PP_ELEMENT_IMPL_B x)
+#define PP_ELEMENT_IMPL_B(x, _) x
+#define PP_ELEMENT_IMPL_C(x) x
+#define PP_ELEMENT_IMPL_0(x) x, PP_NIL
+
+$for i [[
+#define PP_ELEMENT_IMPL_$(i+1)(_) PP_ELEMENT_IMPL_$i
+
+]]
+
+////////////////////////////////////////////////////////////////////////////////
+#define PP_HEAD_IMPL(seq) PP_ELEMENT_IMPL(seq, 0)
+
+////////////////////////////////////////////////////////////////////////////////
+#define PP_TAIL_IMPL(seq) PP_KILL_IMPL(seq, 1)
+
+////////////////////////////////////////////////////////////////////////////////
+#define PP_FOR_EACH_IMPL(what, seq) PP_CONCAT(PP_FOR_EACH_IMPL_, PP_COUNT(seq))(what, seq)
+#define PP_FOR_EACH_IMPL_0(what, seq)
+
+$for i [[
+#define PP_FOR_EACH_IMPL_$(i+1)(what, seq) what(PP_HEAD(seq)) PP_FOR_EACH_IMPL_$i(what, PP_TAIL(seq))
+
+]]
+////////////////////////////////////////////////////////////////////////////////
+/*!
+ \endinternal
+*/
diff --git a/library/cpp/yt/misc/preprocessor.h b/library/cpp/yt/misc/preprocessor.h
new file mode 100644
index 0000000000..9afd3ae902
--- /dev/null
+++ b/library/cpp/yt/misc/preprocessor.h
@@ -0,0 +1,124 @@
+#pragma once
+
+/*!
+ * \file preprocesor.h
+ * \brief Preprocessor metaprogramming macroses
+ */
+
+#if !defined(_MSC_VER) && !defined(__GNUC__)
+# error Your compiler is not currently supported.
+#endif
+
+/*!
+ * \defgroup yt_pp Preprocessor metaprogramming macroses
+ * \ingroup yt_commons
+ *
+ * This is collection of macro definitions for various metaprogramming tasks
+ * with the preprocessor.
+ *
+ * \{
+ *
+ * \page yt_pp_sequences Sequences
+ * Everything revolves around the concept of a \em sequence. A typical
+ * sequence is encoded like <tt>(1)(2)(3)...</tt>. Internally this allows
+ * to apply some macro to the every element in the sequence (see #PP_FOR_EACH).
+ *
+ * Note that sequences can be nested, i. e. <tt>((1)(2)(3))(a)(b)(c)</tt>
+ *
+ * \page yt_pp_examples Examples
+ * Please refer to the unit test for an actual example of usage
+ * (unittests/preprocessor_ut.cpp).
+ *
+ */
+
+//! Concatenates two tokens.
+#define PP_CONCAT(x, y) PP_CONCAT_A(x, y)
+//! \cond Implementation
+#define PP_CONCAT_A(x, y) PP_CONCAT_B(x, y)
+#define PP_CONCAT_B(x, y) x ## y
+//! \endcond
+
+//! Transforms token into the string forcing argument expansion.
+#define PP_STRINGIZE(x) PP_STRINGIZE_A(x)
+//! \cond Implementation
+#define PP_STRINGIZE_A(x) PP_STRINGIZE_B(x)
+#define PP_STRINGIZE_B(x) #x
+//! \endcond
+
+//! \cond Implementation
+#define PP_LEFT_PARENTHESIS (
+#define PP_RIGHT_PARENTHESIS )
+#define PP_COMMA() ,
+#define PP_EMPTY()
+//! \endcond
+
+//! Performs (non-lazy) conditional expansion.
+/*!
+ * \param cond Condition; should expands to either \c PP_TRUE or \c PP_FALSE.
+ * \param _then Expansion result in case when \c cond holds.
+ * \param _else Expansion result in case when \c cond does not hold.
+ */
+#define PP_IF(cond, _then, _else) PP_CONCAT(PP_IF_, cond)(_then, _else)
+//! \cond Implementation
+#define PP_IF_PP_TRUE(x, y) x
+#define PP_IF_PP_FALSE(x, y) y
+//! \endcond
+
+//! Tests whether supplied argument can be treated as a sequence
+//! (i. e. <tt>()()()...</tt>)
+#define PP_IS_SEQUENCE(arg) PP_CONCAT(PP_IS_SEQUENCE_B_, PP_COUNT((PP_NIL PP_IS_SEQUENCE_A arg PP_NIL)))
+//! \cond Implementation
+#define PP_IS_SEQUENCE_A(_) PP_RIGHT_PARENTHESIS PP_LEFT_PARENTHESIS
+#define PP_IS_SEQUENCE_B_1 PP_FALSE
+#define PP_IS_SEQUENCE_B_2 PP_TRUE
+//! \endcond
+
+//! Computes the number of elements in the sequence.
+#define PP_COUNT(...) PP_COUNT_IMPL(__VA_ARGS__)
+
+//! Removes first \c n elements from the sequence.
+#define PP_KILL(seq, n) PP_KILL_IMPL(seq, n)
+
+//! Extracts the head of the sequence.
+/*! For example, \code PP_HEAD((0)(1)(2)(3)) == 0 \endcode
+ */
+#define PP_HEAD(...) PP_HEAD_IMPL(__VA_ARGS__)
+
+//! Extracts the tail of the sequence.
+/*! For example, \code PP_TAIL((0)(1)(2)(3)) == (1)(2)(3) \endcode
+ */
+#define PP_TAIL(...) PP_TAIL_IMPL(__VA_ARGS__)
+
+//! Extracts the element with the specified index from the sequence.
+/*! For example, \code PP_ELEMENT((0)(1)(2)(3), 1) == 1 \endcode
+ */
+#define PP_ELEMENT(seq, index) PP_ELEMENT_IMPL(seq, index)
+
+//! Applies the macro to every member of the sequence.
+/*! For example,
+ * \code
+ * #define MyFunctor(x) +x+
+ * PP_FOR_EACH(MyFunctor, (0)(1)(2)(3)) == +0+ +1+ +2+ +3+
+ * \encode
+ */
+#define PP_FOR_EACH(what, seq) PP_FOR_EACH_IMPL(what, seq)
+
+//! Declares an anonymous variable.
+#ifdef __COUNTER__
+#define PP_ANONYMOUS_VARIABLE(str) PP_CONCAT(str, __COUNTER__)
+#else
+#define PP_ANONYMOUS_VARIABLE(str) PP_CONCAT(str, __LINE__)
+#endif
+
+//! Insert prefix based on presence of additional arguments.
+#define PP_ONE_OR_NONE(a, ...) PP_THIRD(a, ## __VA_ARGS__, a)
+#define PP_THIRD(a, b, ...) __VA_ARGS__
+
+//! \cond Implementation
+#define PREPROCESSOR_GEN_H_
+#include "preprocessor-gen.h"
+#undef PREPROCESSOR_GEN_H_
+//! \endcond
+
+/*! \} */
+
diff --git a/library/cpp/yt/misc/property.h b/library/cpp/yt/misc/property.h
new file mode 100644
index 0000000000..bef8024ae1
--- /dev/null
+++ b/library/cpp/yt/misc/property.h
@@ -0,0 +1,289 @@
+#pragma once
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Declares a trivial public read-write property that is passed by reference.
+#define DECLARE_BYREF_RW_PROPERTY(type, name) \
+public: \
+ type& name(); \
+ const type& name() const;
+
+//! Defines a trivial public read-write property that is passed by reference.
+//! All arguments after name are used as default value (via braced-init-list).
+#define DEFINE_BYREF_RW_PROPERTY(type, name, ...) \
+protected: \
+ type name##_ { __VA_ARGS__ }; \
+ \
+public: \
+ Y_FORCE_INLINE type& name() \
+ { \
+ return name##_; \
+ } \
+ \
+ Y_FORCE_INLINE const type& name() const \
+ { \
+ return name##_; \
+ }
+
+//! Defines a trivial public read-write property that is passed by reference
+//! and is not inline-initialized.
+#define DEFINE_BYREF_RW_PROPERTY_NO_INIT(type, name) \
+protected: \
+ type name##_; \
+ \
+public: \
+ Y_FORCE_INLINE type& name() \
+ { \
+ return name##_; \
+ } \
+ \
+ Y_FORCE_INLINE const type& name() const \
+ { \
+ return name##_; \
+ }
+
+//! Forwards a trivial public read-write property that is passed by reference.
+#define DELEGATE_BYREF_RW_PROPERTY(declaringType, type, name, delegateTo) \
+ type& declaringType::name() \
+ { \
+ return (delegateTo).name(); \
+ } \
+ \
+ const type& declaringType::name() const \
+ { \
+ return (delegateTo).name(); \
+ }
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Declares a trivial public read-only property that is passed by reference.
+#define DECLARE_BYREF_RO_PROPERTY(type, name) \
+public: \
+ const type& name() const;
+
+//! Defines a trivial public read-only property that is passed by reference.
+//! All arguments after name are used as default value (via braced-init-list).
+#define DEFINE_BYREF_RO_PROPERTY(type, name, ...) \
+protected: \
+ type name##_ { __VA_ARGS__ }; \
+ \
+public: \
+ Y_FORCE_INLINE const type& name() const \
+ { \
+ return name##_; \
+ }
+
+//! Defines a trivial public read-only property that is passed by reference
+//! and is not inline-initialized.
+#define DEFINE_BYREF_RO_PROPERTY_NO_INIT(type, name) \
+protected: \
+ type name##_; \
+ \
+public: \
+ Y_FORCE_INLINE const type& name() const \
+ { \
+ return name##_; \
+ }
+
+//! Forwards a trivial public read-only property that is passed by reference.
+#define DELEGATE_BYREF_RO_PROPERTY(declaringType, type, name, delegateTo) \
+ const type& declaringType::name() const \
+ { \
+ return (delegateTo).name(); \
+ }
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Declares a trivial public read-write property that is passed by value.
+#define DECLARE_BYVAL_RW_PROPERTY(type, name) \
+public: \
+ type Get##name() const; \
+ void Set##name(type value);
+
+//! Defines a trivial public read-write property that is passed by value.
+//! All arguments after name are used as default value (via braced-init-list).
+#define DEFINE_BYVAL_RW_PROPERTY(type, name, ...) \
+protected: \
+ type name##_ { __VA_ARGS__ }; \
+ \
+public: \
+ Y_FORCE_INLINE type Get##name() const \
+ { \
+ return name##_; \
+ } \
+ \
+ Y_FORCE_INLINE void Set##name(type value) \
+ { \
+ name##_ = value; \
+ } \
+
+//! Defines a trivial public read-write property that is passed by value.
+//! All arguments after name are used as default value (via braced-init-list).
+#define DEFINE_BYVAL_RW_PROPERTY_WITH_FLUENT_SETTER(declaringType, type, name, ...) \
+protected: \
+ type name##_ { __VA_ARGS__ }; \
+ \
+public: \
+ Y_FORCE_INLINE type Get##name() const \
+ { \
+ return name##_; \
+ } \
+ \
+ Y_FORCE_INLINE void Set##name(type value) &\
+ { \
+ name##_ = value; \
+ } \
+ \
+ Y_FORCE_INLINE declaringType&& Set##name(type value) &&\
+ { \
+ name##_ = value; \
+ return std::move(*this); \
+ } \
+
+//! Defines a trivial public read-write property that is passed by value
+//! and is not inline-initialized.
+#define DEFINE_BYVAL_RW_PROPERTY_NO_INIT(type, name, ...) \
+protected: \
+ type name##_; \
+ \
+public: \
+ Y_FORCE_INLINE type Get##name() const \
+ { \
+ return name##_; \
+ } \
+ \
+ Y_FORCE_INLINE void Set##name(type value) \
+ { \
+ name##_ = value; \
+ } \
+
+//! Forwards a trivial public read-write property that is passed by value.
+#define DELEGATE_BYVAL_RW_PROPERTY(declaringType, type, name, delegateTo) \
+ type declaringType::Get##name() const \
+ { \
+ return (delegateTo).Get##name(); \
+ } \
+ \
+ void declaringType::Set##name(type value) \
+ { \
+ (delegateTo).Set##name(value); \
+ }
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Declares a trivial public read-only property that is passed by value.
+#define DECLARE_BYVAL_RO_PROPERTY(type, name) \
+public: \
+ type Get##name() const;
+
+//! Defines a trivial public read-only property that is passed by value.
+//! All arguments after name are used as default value (via braced-init-list).
+#define DEFINE_BYVAL_RO_PROPERTY(type, name, ...) \
+protected: \
+ type name##_ { __VA_ARGS__ }; \
+ \
+public: \
+ Y_FORCE_INLINE type Get##name() const \
+ { \
+ return name##_; \
+ }
+
+
+//! Defines a trivial public read-only property that is passed by value
+//! and is not inline-initialized.
+#define DEFINE_BYVAL_RO_PROPERTY_NO_INIT(type, name) \
+protected: \
+ type name##_; \
+ \
+public: \
+ Y_FORCE_INLINE type Get##name() const \
+ { \
+ return name##_; \
+ }
+
+//! Forwards a trivial public read-only property that is passed by value.
+#define DELEGATE_BYVAL_RO_PROPERTY(declaringType, type, name, delegateTo) \
+ type declaringType::Get##name() \
+ { \
+ return (delegateTo).Get##name(); \
+ }
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Below are macro helpers for extra properties.
+//! Extra properties should be used for lazy memory allocation for properties that
+//! hold default values for the majority of objects.
+
+//! Initializes extra property holder if it is not initialized.
+#define INITIALIZE_EXTRA_PROPERTY_HOLDER(holder) \
+ if (!holder##_) { \
+ holder##_.reset(new decltype(holder##_)::element_type()); \
+ }
+
+//! Declares an extra property holder. Holder contains extra properties values.
+//! Holder is not created until some property is set with a non-default value.
+//! If there is no holder property getter returns default value.
+#define DECLARE_EXTRA_PROPERTY_HOLDER(type, holder) \
+public: \
+ Y_FORCE_INLINE bool HasCustom##holder() const \
+ { \
+ return static_cast<bool>(holder##_); \
+ } \
+ Y_FORCE_INLINE const type* GetCustom##holder() const \
+ { \
+ return holder##_.get(); \
+ } \
+ Y_FORCE_INLINE type* GetCustom##holder() \
+ { \
+ return holder##_.get(); \
+ } \
+ Y_FORCE_INLINE void InitializeCustom##holder() \
+ { \
+ INITIALIZE_EXTRA_PROPERTY_HOLDER(holder) \
+ } \
+private: \
+ std::unique_ptr<type> holder##_; \
+ static const type Default##holder##_;
+
+//! Defines a storage for extra properties default values.
+#define DEFINE_EXTRA_PROPERTY_HOLDER(class, type, holder) \
+ const type class::Default##holder##_;
+
+//! Defines a public read-write extra property that is passed by value.
+#define DEFINE_BYVAL_RW_EXTRA_PROPERTY(holder, name) \
+public: \
+ Y_FORCE_INLINE decltype(holder##_->name) Get##name() const \
+ { \
+ if (!holder##_) { \
+ return Default##holder##_.name; \
+ } \
+ return holder##_->name; \
+ } \
+ Y_FORCE_INLINE void Set##name(decltype(holder##_->name) val) \
+ { \
+ if (!holder##_) { \
+ if (val == Default##holder##_.name) { \
+ return; \
+ } \
+ INITIALIZE_EXTRA_PROPERTY_HOLDER(holder); \
+ } \
+ holder##_->name = val; \
+ }
+
+//! Defines a public read-write extra property that is passed by reference.
+#define DEFINE_BYREF_RW_EXTRA_PROPERTY(holder, name) \
+public: \
+ Y_FORCE_INLINE const decltype(holder##_->name)& name() const \
+ { \
+ if (!holder##_) { \
+ return Default##holder##_.name; \
+ } \
+ return holder##_->name; \
+ } \
+ Y_FORCE_INLINE decltype(holder##_->name)& Mutable##name() \
+ { \
+ INITIALIZE_EXTRA_PROPERTY_HOLDER(holder); \
+ return holder##_->name; \
+ }
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/library/cpp/yt/misc/source_location.cpp b/library/cpp/yt/misc/source_location.cpp
new file mode 100644
index 0000000000..8d22d43636
--- /dev/null
+++ b/library/cpp/yt/misc/source_location.cpp
@@ -0,0 +1,54 @@
+#include "source_location.h"
+
+#include <string.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+const char* TSourceLocation::GetFileName() const
+{
+ return FileName_;
+}
+
+int TSourceLocation::GetLine() const
+{
+ return Line_;
+}
+
+bool TSourceLocation::IsValid() const
+{
+ return FileName_ != nullptr;
+}
+
+bool TSourceLocation::operator<(const TSourceLocation& other) const
+{
+ const char* fileName = FileName_ ? FileName_ : "";
+ const char* otherFileName = other.FileName_ ? other.FileName_ : "";
+ int fileNameResult = strcmp(fileName, otherFileName);
+ if (fileNameResult != 0) {
+ return fileNameResult < 0;
+ }
+
+ if (Line_ < other.Line_) {
+ return true;
+ }
+ if (Line_ > other.Line_) {
+ return false;
+ }
+
+ return false;
+}
+
+bool TSourceLocation::operator==(const TSourceLocation& other) const
+{
+ const char* fileName = FileName_ ? FileName_ : "";
+ const char* otherFileName = other.FileName_ ? other.FileName_ : "";
+ return
+ strcmp(fileName, otherFileName) == 0 &&
+ Line_ == other.Line_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/misc/source_location.h b/library/cpp/yt/misc/source_location.h
new file mode 100644
index 0000000000..84213eea70
--- /dev/null
+++ b/library/cpp/yt/misc/source_location.h
@@ -0,0 +1,38 @@
+#pragma once
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TSourceLocation
+{
+public:
+ TSourceLocation()
+ : FileName_(nullptr)
+ , Line_(-1)
+ { }
+
+ TSourceLocation(const char* fileName, int line)
+ : FileName_(fileName)
+ , Line_(line)
+ { }
+
+ const char* GetFileName() const;
+ int GetLine() const;
+ bool IsValid() const;
+
+ bool operator<(const TSourceLocation& other) const;
+ bool operator==(const TSourceLocation& other) const;
+
+private:
+ const char* FileName_;
+ int Line_;
+
+};
+
+//! Defines a macro to record the current source location.
+#define FROM_HERE ::NYT::TSourceLocation(__FILE__, __LINE__)
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/misc/unittests/enum_ut.cpp b/library/cpp/yt/misc/unittests/enum_ut.cpp
new file mode 100644
index 0000000000..6af11b04dc
--- /dev/null
+++ b/library/cpp/yt/misc/unittests/enum_ut.cpp
@@ -0,0 +1,250 @@
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <library/cpp/yt/misc/enum.h>
+
+namespace NYT {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+DEFINE_ENUM(ESimple,
+ (X)
+ (Y)
+ (Z)
+);
+
+DEFINE_ENUM(EColor,
+ ((Red) (10))
+ ((Green)(20))
+ ((Blue) (30))
+ (Black)
+ (White)
+);
+
+DEFINE_BIT_ENUM(EFlag,
+ ((_1)(0x0001))
+ ((_2)(0x0002))
+ ((_3)(0x0004))
+ ((_4)(0x0008))
+);
+
+DEFINE_AMBIGUOUS_ENUM_WITH_UNDERLYING_TYPE(EMultipleNames, int,
+ (A1)
+ ((A2)(0))
+ (B)
+ (C)
+ ((D1)(100))
+ ((D2)(100))
+);
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, size_t N>
+std::vector<T> ToVector(std::array<T, N> array)
+{
+ return std::vector<T>(array.begin(), array.end());
+}
+
+TEST(TEnumTest, Domain)
+{
+ EXPECT_EQ(3, TEnumTraits<ESimple>::DomainSize);
+ std::vector<ESimple> v {
+ ESimple::X,
+ ESimple::Y,
+ ESimple::Z
+ };
+ EXPECT_EQ(v, ToVector(TEnumTraits<ESimple>::GetDomainValues()));
+ EXPECT_EQ(ESimple::X, TEnumTraits<ESimple>::GetMinValue());
+ EXPECT_EQ(ESimple::Z, TEnumTraits<ESimple>::GetMaxValue());
+}
+
+TEST(TEnumTest, Basic)
+{
+ EXPECT_EQ(0, static_cast<int>(ESimple::X));
+ EXPECT_EQ(1, static_cast<int>(ESimple::Y));
+ EXPECT_EQ(2, static_cast<int>(ESimple::Z));
+
+ EXPECT_EQ(0, static_cast<int>(EColor( )));
+ EXPECT_EQ(5, static_cast<int>(EColor(5)));
+
+ EXPECT_EQ(10, static_cast<int>(EColor::Red ));
+ EXPECT_EQ(20, static_cast<int>(EColor::Green));
+ EXPECT_EQ(30, static_cast<int>(EColor::Blue ));
+ EXPECT_EQ(31, static_cast<int>(EColor::Black));
+ EXPECT_EQ(32, static_cast<int>(EColor::White));
+}
+
+TEST(TEnumTest, ToString)
+{
+ EXPECT_EQ("EColor(0)", ToString(EColor( )));
+ EXPECT_EQ("EColor(5)", ToString(EColor(5)));
+
+ EXPECT_EQ("Red", ToString(EColor(EColor::Red )));
+ EXPECT_EQ("Green", ToString(EColor::Green));
+ EXPECT_EQ("Blue", ToString(EColor(EColor::Blue )));
+ EXPECT_EQ("Black", ToString(EColor::Black));
+ EXPECT_EQ("White", ToString(EColor::White));
+}
+
+TEST(TEnumTest, FromString)
+{
+ EXPECT_EQ(EColor::Red , TEnumTraits<EColor>::FromString("Red" ));
+ EXPECT_EQ(EColor::Green, TEnumTraits<EColor>::FromString("Green"));
+ EXPECT_EQ(EColor::Blue , TEnumTraits<EColor>::FromString("Blue" ));
+ EXPECT_EQ(EColor::Black, TEnumTraits<EColor>::FromString("Black"));
+ EXPECT_EQ(EColor::White, TEnumTraits<EColor>::FromString("White"));
+
+ EXPECT_THROW(TEnumTraits<EColor>::FromString("Pink"), std::exception);
+
+ EColor color;
+ bool returnValue;
+
+ returnValue = TEnumTraits<EColor>::FindValueByLiteral("Red", &color);
+ EXPECT_EQ(EColor::Red, color);
+ EXPECT_TRUE(returnValue);
+
+ returnValue = TEnumTraits<EColor>::FindValueByLiteral("Pink", &color);
+ EXPECT_EQ(EColor::Red, color);
+ EXPECT_FALSE(returnValue);
+}
+
+TEST(TEnumTest, Ordering)
+{
+ ESimple a(ESimple::X);
+ ESimple b(ESimple::Y);
+ ESimple c(ESimple::Y);
+ ESimple d(ESimple::Z);
+
+ EXPECT_FALSE(a < a); EXPECT_FALSE(a > a);
+ EXPECT_TRUE (a < b); EXPECT_TRUE (b > a);
+ EXPECT_TRUE (a < c); EXPECT_TRUE (c > a);
+ EXPECT_TRUE (a < d); EXPECT_TRUE (d > a);
+
+ EXPECT_FALSE(b < a); EXPECT_FALSE(a > b);
+ EXPECT_FALSE(b < b); EXPECT_FALSE(b > b);
+ EXPECT_FALSE(b < c); EXPECT_FALSE(c > b);
+ EXPECT_TRUE (b < d); EXPECT_TRUE (d > b);
+
+ EXPECT_FALSE(c < a); EXPECT_FALSE(a > c);
+ EXPECT_FALSE(c < b); EXPECT_FALSE(b > c);
+ EXPECT_FALSE(c < c); EXPECT_FALSE(c > c);
+ EXPECT_TRUE (c < d); EXPECT_TRUE (d > c);
+
+ EXPECT_FALSE(d < a); EXPECT_FALSE(a > d);
+ EXPECT_FALSE(d < b); EXPECT_FALSE(b > d);
+ EXPECT_FALSE(d < c); EXPECT_FALSE(c > d);
+ EXPECT_FALSE(d < d); EXPECT_FALSE(d > d);
+
+ EXPECT_TRUE (a <= b);
+ EXPECT_TRUE (b <= c);
+ EXPECT_TRUE (c <= d);
+
+ EXPECT_TRUE (a == a);
+ EXPECT_FALSE(a == b);
+ EXPECT_TRUE (b == c);
+ EXPECT_FALSE(c == d);
+ EXPECT_FALSE(d == a);
+
+ EXPECT_FALSE(a != a);
+ EXPECT_TRUE (a != b);
+ EXPECT_FALSE(b != c);
+ EXPECT_TRUE (c != d);
+ EXPECT_TRUE (d != a);
+}
+
+TEST(TEnumTest, OrderingWithDomainValues)
+{
+ EColor color(EColor::Black);
+
+ EXPECT_LT(EColor::Red, color);
+ EXPECT_LT(color, EColor::White);
+
+ EXPECT_GT(color, EColor::Red);
+ EXPECT_GT(EColor::White, color);
+
+ EXPECT_LE(EColor::Red, color);
+ EXPECT_LE(color, EColor::White);
+
+ EXPECT_GE(EColor::White, color);
+ EXPECT_GE(color, EColor::Red);
+
+ EXPECT_EQ(color, EColor::Black);
+ EXPECT_EQ(EColor::Black, color);
+
+ EXPECT_NE(color, EColor::Blue);
+ EXPECT_NE(EColor::Blue, color);
+}
+
+TEST(TEnumTest, DomainSize)
+{
+ EXPECT_EQ(3, TEnumTraits<ESimple>::DomainSize);
+ EXPECT_EQ(5, TEnumTraits<EColor>::DomainSize);
+}
+
+TEST(TEnumTest, DomainValues)
+{
+ std::vector<ESimple> simpleValues;
+ simpleValues.push_back(ESimple::X);
+ simpleValues.push_back(ESimple::Y);
+ simpleValues.push_back(ESimple::Z);
+ EXPECT_EQ(simpleValues, ToVector(TEnumTraits<ESimple>::GetDomainValues()));
+
+ std::vector<EColor> colorValues;
+ colorValues.push_back(EColor::Red);
+ colorValues.push_back(EColor::Green);
+ colorValues.push_back(EColor::Blue);
+ colorValues.push_back(EColor::Black);
+ colorValues.push_back(EColor::White);
+ EXPECT_EQ(colorValues, ToVector(TEnumTraits<EColor>::GetDomainValues()));
+}
+
+TEST(TEnumTest, Decompose1)
+{
+ auto f = EFlag(0);
+ std::vector<EFlag> ff { };
+ EXPECT_EQ(TEnumTraits<EFlag>::Decompose(f), ff);
+}
+
+TEST(TEnumTest, Decompose2)
+{
+ auto f = EFlag::_1;
+ std::vector<EFlag> ff {EFlag::_1};
+ EXPECT_EQ(TEnumTraits<EFlag>::Decompose(f), ff);
+}
+
+TEST(TEnumTest, Decompose3)
+{
+ auto f = EFlag(EFlag::_1|EFlag::_2);
+ std::vector<EFlag> ff{EFlag::_1, EFlag::_2};
+ EXPECT_EQ(TEnumTraits<EFlag>::Decompose(f), ff);
+}
+
+TEST(TEnumTest, Decompose4)
+{
+ auto f = EFlag(EFlag::_2|EFlag::_4);
+ std::vector<EFlag> ff{EFlag::_2, EFlag::_4};
+ EXPECT_EQ(TEnumTraits<EFlag>::Decompose(f), ff);
+}
+
+TEST(TEnumTest, MultipleNames)
+{
+ EXPECT_EQ(EMultipleNames::A1, TEnumTraits<EMultipleNames>::FromString("A1"));
+ EXPECT_EQ(EMultipleNames::A1, TEnumTraits<EMultipleNames>::FromString("A2"));
+ EXPECT_EQ(EMultipleNames::B, TEnumTraits<EMultipleNames>::FromString("B"));
+ EXPECT_EQ(EMultipleNames::C, TEnumTraits<EMultipleNames>::FromString("C"));
+ EXPECT_EQ(EMultipleNames::D1, TEnumTraits<EMultipleNames>::FromString("D1"));
+ EXPECT_EQ(EMultipleNames::D1, TEnumTraits<EMultipleNames>::FromString("D2"));
+
+ EXPECT_EQ("A1", ToString(EMultipleNames::A1));
+ EXPECT_EQ("A1", ToString(EMultipleNames::A2));
+ EXPECT_EQ("B", ToString(EMultipleNames::B));
+ EXPECT_EQ("C", ToString(EMultipleNames::C));
+ EXPECT_EQ("D1", ToString(EMultipleNames::D1));
+ EXPECT_EQ("D1", ToString(EMultipleNames::D2));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT
+
diff --git a/library/cpp/yt/misc/unittests/guid_ut.cpp b/library/cpp/yt/misc/unittests/guid_ut.cpp
new file mode 100644
index 0000000000..ce9ee52109
--- /dev/null
+++ b/library/cpp/yt/misc/unittests/guid_ut.cpp
@@ -0,0 +1,20 @@
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <library/cpp/yt/misc/guid.h>
+
+namespace NYT {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TEST(TGuidTest, RandomGuids)
+{
+ auto guid = TGuid::Create();
+ auto otherGuid = TGuid::Create();
+ EXPECT_FALSE(guid == otherGuid);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT
diff --git a/library/cpp/yt/misc/unittests/preprocessor_ut.cpp b/library/cpp/yt/misc/unittests/preprocessor_ut.cpp
new file mode 100644
index 0000000000..397e2a6a61
--- /dev/null
+++ b/library/cpp/yt/misc/unittests/preprocessor_ut.cpp
@@ -0,0 +1,102 @@
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <library/cpp/yt/misc/preprocessor.h>
+
+namespace NYT {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TEST(TPreprocessorTest, Concatenation)
+{
+ EXPECT_EQ(12, PP_CONCAT(1, 2));
+ EXPECT_STREQ("FooBar", PP_STRINGIZE(PP_CONCAT(Foo, Bar)));
+}
+
+TEST(TPreprocessorTest, Stringize)
+{
+ EXPECT_STREQ(PP_STRINGIZE(123456), "123456");
+ EXPECT_STREQ(PP_STRINGIZE(FooBar), "FooBar");
+ EXPECT_STREQ(PP_STRINGIZE(T::XYZ), "T::XYZ");
+}
+
+TEST(TPreprocessorTest, Count)
+{
+ EXPECT_EQ(0, PP_COUNT());
+ EXPECT_EQ(1, PP_COUNT((0)));
+ EXPECT_EQ(2, PP_COUNT((0)(0)));
+ EXPECT_EQ(3, PP_COUNT((0)(0)(0)));
+ EXPECT_EQ(4, PP_COUNT((0)(0)(0)(0)));
+ EXPECT_EQ(5, PP_COUNT((0)(0)(0)(0)(0)));
+}
+
+TEST(TPreprocessorTest, Kill)
+{
+ EXPECT_STREQ("PP_NIL (0)", PP_STRINGIZE(PP_NIL PP_KILL((0), 0)));
+ EXPECT_STREQ("PP_NIL", PP_STRINGIZE(PP_NIL PP_KILL((0), 1)));
+ EXPECT_STREQ("PP_NIL (0)(1)(2)", PP_STRINGIZE(PP_NIL PP_KILL((0)(1)(2), 0)));
+ EXPECT_STREQ("PP_NIL (1)(2)", PP_STRINGIZE(PP_NIL PP_KILL((0)(1)(2), 1)));
+ EXPECT_STREQ("PP_NIL (2)", PP_STRINGIZE(PP_NIL PP_KILL((0)(1)(2), 2)));
+ EXPECT_STREQ("PP_NIL", PP_STRINGIZE(PP_NIL PP_KILL((0)(1)(2), 3)));
+}
+
+TEST(TPreprocessorTest, Head)
+{
+ EXPECT_STREQ("0", PP_STRINGIZE(PP_HEAD((0))));
+ EXPECT_STREQ("0", PP_STRINGIZE(PP_HEAD((0)(1))));
+ EXPECT_STREQ("0", PP_STRINGIZE(PP_HEAD((0)(1)(2))));
+}
+
+TEST(TPreprocessorTest, Tail)
+{
+ EXPECT_STREQ("PP_NIL", PP_STRINGIZE(PP_NIL PP_TAIL((0))));
+ EXPECT_STREQ("PP_NIL (1)", PP_STRINGIZE(PP_NIL PP_TAIL((0)(1))));
+ EXPECT_STREQ("PP_NIL (1)(2)", PP_STRINGIZE(PP_NIL PP_TAIL((0)(1)(2))));
+}
+
+TEST(TPreprocessorTest, ForEach)
+{
+ EXPECT_STREQ(
+ "\"Foo\" \"Bar\" \"Spam\" \"Ham\"",
+ PP_STRINGIZE(PP_FOR_EACH(PP_STRINGIZE, (Foo)(Bar)(Spam)(Ham)))
+ );
+#define my_functor(x) +x+
+ EXPECT_STREQ(
+ "+1+ +2+ +3+",
+ PP_STRINGIZE(PP_FOR_EACH(my_functor, (1)(2)(3)))
+ );
+#undef my_functor
+}
+
+TEST(TPreprocessorTest, MakeSingleton)
+{
+ EXPECT_EQ(1, PP_ELEMENT((1), 0));
+ EXPECT_EQ(1, PP_ELEMENT((1)(2), 0));
+ EXPECT_EQ(2, PP_ELEMENT((1)(2), 1));
+ EXPECT_EQ(1, PP_ELEMENT((1)(2)(3), 0));
+ EXPECT_EQ(2, PP_ELEMENT((1)(2)(3), 1));
+ EXPECT_EQ(3, PP_ELEMENT((1)(2)(3), 2));
+ EXPECT_EQ(1, PP_ELEMENT((1)(2)(3)(4), 0));
+ EXPECT_EQ(2, PP_ELEMENT((1)(2)(3)(4), 1));
+ EXPECT_EQ(3, PP_ELEMENT((1)(2)(3)(4), 2));
+ EXPECT_EQ(4, PP_ELEMENT((1)(2)(3)(4), 3));
+}
+
+TEST(TPreprocessorTest, Conditional)
+{
+ EXPECT_EQ(1, PP_IF(PP_TRUE, 1, 2));
+ EXPECT_EQ(2, PP_IF(PP_FALSE, 1, 2));
+}
+
+TEST(TPreprocessorTest, IsSequence)
+{
+ EXPECT_STREQ("PP_FALSE", PP_STRINGIZE(PP_IS_SEQUENCE( 0 )));
+ EXPECT_STREQ("PP_TRUE", PP_STRINGIZE(PP_IS_SEQUENCE((0) )));
+ EXPECT_STREQ("PP_TRUE", PP_STRINGIZE(PP_IS_SEQUENCE((0)(0))));
+ EXPECT_STREQ("PP_FALSE", PP_STRINGIZE(PP_IS_SEQUENCE(PP_NIL)));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT
diff --git a/library/cpp/yt/misc/unittests/ya.make b/library/cpp/yt/misc/unittests/ya.make
new file mode 100644
index 0000000000..690082ca59
--- /dev/null
+++ b/library/cpp/yt/misc/unittests/ya.make
@@ -0,0 +1,15 @@
+GTEST(unittester-library-misc)
+
+OWNER(g:yt)
+
+SRCS(
+ enum_ut.cpp
+ guid_ut.cpp
+ preprocessor_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/yt/misc
+)
+
+END()
diff --git a/library/cpp/yt/misc/variant-inl.h b/library/cpp/yt/misc/variant-inl.h
new file mode 100644
index 0000000000..fb7d98d4be
--- /dev/null
+++ b/library/cpp/yt/misc/variant-inl.h
@@ -0,0 +1,70 @@
+#ifndef VARIANT_INL_H_
+#error "Direct inclusion of this file is not allowed, include variant.h"
+// For the sake of sane code completion.
+#include "variant.h"
+#endif
+
+#include <type_traits>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace NDetail {
+
+template <class T>
+struct TIndexOf<T>
+{
+ static constexpr size_t Value = std::numeric_limits<size_t>::max();
+};
+
+template <class T, class T0, class... Ts>
+struct TIndexOf<T, T0, Ts...>
+{
+ static constexpr size_t Value = std::is_same_v<T, T0>
+ ? 0
+ : 1 + TIndexOf<T, Ts...>::Value;
+};
+
+template <size_t Index, class... Ts>
+struct TVariantFormatter;
+
+template <size_t Index>
+struct TVariantFormatter<Index>
+{
+ template <class TVariant>
+ static void Do(TStringBuilderBase* /*builder*/, const TVariant& /*variant*/, TStringBuf /*spec*/)
+ { }
+};
+
+template <size_t Index, class T, class... Ts>
+struct TVariantFormatter<Index, T, Ts...>
+{
+ template <class TVariant>
+ static void Do(TStringBuilderBase* builder, const TVariant& variant, TStringBuf spec)
+ {
+ if (variant.index() == Index) {
+ FormatValue(builder, std::get<Index>(variant), spec);
+ } else {
+ TVariantFormatter<Index + 1, Ts...>::Do(builder, variant, spec);
+ }
+ }
+};
+
+} // namespace NDetail
+
+template <class... Ts>
+void FormatValue(TStringBuilderBase* builder, const std::variant<Ts...>& variant, TStringBuf spec)
+{
+ NDetail::TVariantFormatter<0, Ts...>::Do(builder, variant, spec);
+}
+
+template <class... Ts>
+TString ToString(const std::variant<Ts...>& variant)
+{
+ return ToStringViaBuilder(variant);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/misc/variant.h b/library/cpp/yt/misc/variant.h
new file mode 100644
index 0000000000..27c0a2bc08
--- /dev/null
+++ b/library/cpp/yt/misc/variant.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#include <variant>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace NDetail {
+
+template <class T, class... Ts>
+struct TIndexOf;
+
+} // namespace NDetail
+
+template <class T, class V>
+struct TVariantIndex;
+
+template <class T, class... Ts>
+struct TVariantIndex<T, std::variant<Ts...>>
+ : std::integral_constant<size_t, NDetail::TIndexOf<T, Ts...>::Value>
+{ };
+
+template <class T, class V>
+constexpr size_t VariantIndexV = TVariantIndex<T, V>::value;
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TStringBuilderBase;
+
+template <class... Ts>
+void FormatValue(TStringBuilderBase* builder, const std::variant<Ts...>& variant, TStringBuf spec);
+
+template <class... Ts>
+TString ToString(const std::variant<Ts...>& variant);
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! A concise way of creating a functor with an overloaded operator().
+/*!
+ * Very useful for std::visit-ing variants. For example:
+ *
+ * std::visit(TOverloaded{
+ * [] (int i) { printf("The variant holds an int: %d!", i); },
+ * [] (const std::string& s) { printf("The variant holds a string: '%s'!", s); }
+ * }, variantVariable);
+ */
+template<class... Ts> struct TOverloaded : Ts... { using Ts::operator()...; };
+template<class... Ts> TOverloaded(Ts...) -> TOverloaded<Ts...>;
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! An alternative to std::visit that takes its variant argument first.
+/*!
+ * This deprives it of being able to visit a Cartesian product of variants but
+ * in exchange allows to receive multiple visitor functors. All of operator()s
+ * these functors have are used to visit the variant after a single unified
+ * overload resolution. For example:
+ *
+ * Visit(variantVariable,
+ * [] (int i) { printf("The variant holds an int: %d!", i); },
+ * [] (const std::string& s) { printf("The variant holds a string: '%s'!", s); });
+ */
+template <class T, class... U>
+auto Visit(T&& variant, U&&... visitorOverloads)
+{
+ return std::visit(TOverloaded{std::forward<U>(visitorOverloads)...}, std::forward<T>(variant));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define VARIANT_INL_H_
+#include "variant-inl.h"
+#undef VARIANT_INL_H_
diff --git a/library/cpp/yt/misc/ya.make b/library/cpp/yt/misc/ya.make
new file mode 100644
index 0000000000..bb76711ddd
--- /dev/null
+++ b/library/cpp/yt/misc/ya.make
@@ -0,0 +1,27 @@
+LIBRARY()
+
+OWNER(g:yt)
+
+SRCS(
+ guid.cpp
+ source_location.cpp
+)
+
+PEERDIR(
+ library/cpp/yt/exception
+)
+
+CHECK_DEPENDENT_DIRS(
+ ALLOW_ONLY ALL
+ build
+ contrib
+ library
+ util
+ yt/yt/library/small_containers
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ unittests
+)
diff --git a/library/cpp/yt/small_containers/compact_flat_map-inl.h b/library/cpp/yt/small_containers/compact_flat_map-inl.h
new file mode 100644
index 0000000000..45a4dd1de3
--- /dev/null
+++ b/library/cpp/yt/small_containers/compact_flat_map-inl.h
@@ -0,0 +1,184 @@
+#ifndef COMPACT_FLAT_MAP_INL_H_
+#error "Direct inclusion of this file is not allowed, include compact_flat_map.h"
+// For the sake of sane code completion.
+#include "compact_flat_map.h"
+#endif
+
+namespace NYT {
+
+///////////////////////////////////////////////////////////////////////////////
+
+template <class K, class V, unsigned N>
+template <class TInputIterator>
+TCompactFlatMap<K, V, N>::TCompactFlatMap(TInputIterator begin, TInputIterator end)
+{
+ insert(begin, end);
+}
+
+template <class K, class V, unsigned N>
+bool TCompactFlatMap<K, V, N>::operator==(const TCompactFlatMap& rhs) const
+{
+ return Storage_ == rhs.Storage_;
+}
+
+template <class K, class V, unsigned N>
+bool TCompactFlatMap<K, V, N>::operator!=(const TCompactFlatMap& rhs) const
+{
+ return !(*this == rhs);
+}
+
+template <class K, class V, unsigned N>
+typename TCompactFlatMap<K, V, N>::iterator TCompactFlatMap<K, V, N>::begin()
+{
+ return Storage_.begin();
+}
+
+template <class K, class V, unsigned N>
+typename TCompactFlatMap<K, V, N>::const_iterator TCompactFlatMap<K, V, N>::begin() const
+{
+ return Storage_.begin();
+}
+
+template <class K, class V, unsigned N>
+typename TCompactFlatMap<K, V, N>::iterator TCompactFlatMap<K, V, N>::end()
+{
+ return Storage_.end();
+}
+
+template <class K, class V, unsigned N>
+typename TCompactFlatMap<K, V, N>::const_iterator TCompactFlatMap<K, V, N>::end() const
+{
+ return Storage_.end();
+}
+
+template <class K, class V, unsigned N>
+void TCompactFlatMap<K, V, N>::reserve(size_type n)
+{
+ Storage_.reserve(n);
+}
+
+template <class K, class V, unsigned N>
+typename TCompactFlatMap<K, V, N>::size_type TCompactFlatMap<K, V, N>::size() const
+{
+ return Storage_.size();
+}
+
+template <class K, class V, unsigned N>
+int TCompactFlatMap<K, V, N>::ssize() const
+{
+ return static_cast<int>(Storage_.size());
+}
+
+template <class K, class V, unsigned N>
+bool TCompactFlatMap<K, V, N>::empty() const
+{
+ return Storage_.empty();
+}
+
+template <class K, class V, unsigned N>
+void TCompactFlatMap<K, V, N>::clear()
+{
+ Storage_.clear();
+}
+
+template <class K, class V, unsigned N>
+typename TCompactFlatMap<K, V, N>::iterator TCompactFlatMap<K, V, N>::find(const K& k)
+{
+ auto [rangeBegin, rangeEnd] = EqualRange(k);
+ return rangeBegin == rangeEnd ? end() : rangeBegin;
+}
+
+template <class K, class V, unsigned N>
+typename TCompactFlatMap<K, V, N>::const_iterator TCompactFlatMap<K, V, N>::find(const K& k) const
+{
+ auto [rangeBegin, rangeEnd] = EqualRange(k);
+ return rangeBegin == rangeEnd ? end() : rangeBegin;
+}
+
+template <class K, class V, unsigned N>
+bool TCompactFlatMap<K, V, N>::contains(const K& k) const
+{
+ return find(k) != end();
+}
+
+template <class K, class V, unsigned N>
+auto TCompactFlatMap<K, V, N>::insert(const value_type& value) -> std::pair<iterator, bool>
+{
+ auto [rangeBegin, rangeEnd] = EqualRange(value.first);
+ if (rangeBegin != rangeEnd) {
+ return {rangeBegin, false};
+ } else {
+ auto it = Storage_.insert(rangeBegin, value);
+ return {it, true};
+ }
+}
+
+template <class K, class V, unsigned N>
+template <class TInputIterator>
+void TCompactFlatMap<K, V, N>::insert(TInputIterator begin, TInputIterator end)
+{
+ for (auto it = begin; it != end; ++it) {
+ insert(*it);
+ }
+}
+
+template <class K, class V, unsigned N>
+template <class... TArgs>
+auto TCompactFlatMap<K, V, N>::emplace(TArgs&&... args) -> std::pair<iterator, bool>
+{
+ return insert(value_type(std::forward<TArgs>(args)...));
+}
+
+template <class K, class V, unsigned N>
+V& TCompactFlatMap<K, V, N>::operator[](const K& k)
+{
+ auto [it, inserted] = insert({k, V()});
+ return it->second;
+}
+
+template <class K, class V, unsigned N>
+void TCompactFlatMap<K, V, N>::erase(const K& k)
+{
+ auto [rangeBegin, rangeEnd] = EqualRange(k);
+ erase(rangeBegin, rangeEnd);
+}
+
+template <class K, class V, unsigned N>
+void TCompactFlatMap<K, V, N>::erase(iterator pos)
+{
+ Storage_.erase(pos);
+
+ // Try to keep the storage inline. This is why erase doesn't return an iterator.
+ Storage_.shrink_to_small();
+}
+
+template <class K, class V, unsigned N>
+void TCompactFlatMap<K, V, N>::erase(iterator b, iterator e)
+{
+ Storage_.erase(b, e);
+
+ // Try to keep the storage inline. This is why erase doesn't return an iterator.
+ Storage_.shrink_to_small();
+}
+
+template <class K, class V, unsigned N>
+std::pair<typename TCompactFlatMap<K, V, N>::iterator, typename TCompactFlatMap<K, V, N>::iterator>
+TCompactFlatMap<K, V, N>::EqualRange(const K& k)
+{
+ auto result = std::equal_range(Storage_.begin(), Storage_.end(), k, TKeyComparer());
+ YT_ASSERT(std::distance(result.first, result.second) <= 1);
+ return result;
+}
+
+template <class K, class V, unsigned N>
+std::pair<typename TCompactFlatMap<K, V, N>::const_iterator, typename TCompactFlatMap<K, V, N>::const_iterator>
+TCompactFlatMap<K, V, N>::EqualRange(const K& k) const
+{
+ auto result = std::equal_range(Storage_.begin(), Storage_.end(), k, TKeyComparer());
+ YT_ASSERT(std::distance(result.first, result.second) <= 1);
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/small_containers/compact_flat_map.h b/library/cpp/yt/small_containers/compact_flat_map.h
new file mode 100644
index 0000000000..13bdc0e9da
--- /dev/null
+++ b/library/cpp/yt/small_containers/compact_flat_map.h
@@ -0,0 +1,109 @@
+#pragma once
+
+#include "compact_vector.h"
+
+namespace NYT {
+
+///////////////////////////////////////////////////////////////////////////////
+
+//! A flat map implementation over TCompactVector that tries to keep data inline.
+/*!
+ * Similarly to SmallSet, this is implemented via binary search over a sorted
+ * vector. Unlike SmallSet, however, this one never falls back to std::map (or
+ * set) for larger sizes. This means that the flat map is only useful
+ * - at small sizes, when there's absolutely no chance of it getting big, or
+ * - when it's filled once and is then only read from.
+ *
+ * In return, the flat map provides
+ * - a smaller size overhead and
+ * - a guarantee that if data fits into inline storage, it goes there.
+ *
+ * Because of the latter, one should be very careful with iterators: virtually
+ * any call to insert or erase may potentially invalidate all iterators.
+ */
+template <class K, class V, unsigned N>
+class TCompactFlatMap
+{
+public:
+ // NB: can't make this pair<const K, V> as TCompactVector requires its type
+ // parameter to be copy-assignable.
+ using value_type = std::pair<K, V>;
+ using key_type = K;
+ using mapped_type = V;
+
+private:
+ using TStorage = TCompactVector<value_type, N>;
+
+ struct TKeyComparer
+ {
+ bool operator()(const K& lhs, const value_type& rhs)
+ {
+ return lhs < rhs.first;
+ }
+
+ bool operator()(const value_type& lhs, const K& rhs)
+ {
+ return lhs.first < rhs;
+ }
+ };
+
+public:
+ using iterator = typename TStorage::iterator;
+ using const_iterator = typename TStorage::const_iterator;
+ using size_type = size_t;
+
+ TCompactFlatMap() = default;
+
+ template <class TInputIterator>
+ TCompactFlatMap(TInputIterator begin, TInputIterator end);
+
+ bool operator==(const TCompactFlatMap& rhs) const;
+ bool operator!=(const TCompactFlatMap& rhs) const;
+
+ iterator begin();
+ const_iterator begin() const;
+
+ iterator end();
+ const_iterator end() const;
+
+ void reserve(size_type n);
+
+ size_type size() const;
+ int ssize() const;
+
+ bool empty() const;
+ void clear();
+
+ iterator find(const K& k);
+ const_iterator find(const K& k) const;
+
+ bool contains(const K& k) const;
+
+ std::pair<iterator, bool> insert(const value_type& value);
+
+ template <class TInputIterator>
+ void insert(TInputIterator begin, TInputIterator end);
+
+ template <class... TArgs>
+ std::pair<iterator, bool> emplace(TArgs&&... args);
+
+ V& operator[](const K& k);
+
+ void erase(const K& k);
+ void erase(iterator pos);
+ void erase(iterator b, iterator e);
+
+private:
+ std::pair<iterator, iterator> EqualRange(const K& k);
+ std::pair<const_iterator, const_iterator> EqualRange(const K& k) const;
+
+ TStorage Storage_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define COMPACT_FLAT_MAP_INL_H_
+#include "compact_flat_map-inl.h"
+#undef COMPACT_FLAT_MAP_INL_H_
diff --git a/library/cpp/yt/small_containers/compact_heap-inl.h b/library/cpp/yt/small_containers/compact_heap-inl.h
new file mode 100644
index 0000000000..2c6b3507ba
--- /dev/null
+++ b/library/cpp/yt/small_containers/compact_heap-inl.h
@@ -0,0 +1,152 @@
+#ifndef COMPACT_HEAP_INL_H_
+#error "Direct inclusion of this file is not allowed, include compact_heap.h"
+// For the sake of sane code completion.
+#include "compact_heap.h"
+#endif
+
+#include <library/cpp/yt/assert/assert.h>
+
+#include <algorithm>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, size_t N, class C>
+TCompactHeap<T, N, C>::TCompactHeap(C comparator) noexcept
+ : Comparator_(TReverseComparator(std::move(comparator)))
+{ }
+
+template <class T, size_t N, class C>
+void TCompactHeap<T, N, C>::push(T value)
+{
+ bool wasInline = IsInline();
+ Heap_.push_back(std::move(value));
+ if (Y_UNLIKELY(!IsInline())) {
+ if (wasInline) {
+ std::make_heap(Heap_.begin(), Heap_.end(), Comparator_);
+ } else {
+ std::push_heap(Heap_.begin(), Heap_.end(), Comparator_);
+ }
+ }
+}
+
+template <class T, size_t N, class C>
+void TCompactHeap<T, N, C>::pop()
+{
+ YT_ASSERT(!empty());
+
+ if (Y_LIKELY(IsInline())) {
+ auto minIt = std::max_element(Heap_.begin(), Heap_.end(), Comparator_);
+ std::swap(*minIt, Heap_.back());
+ Heap_.pop_back();
+ } else {
+ std::pop_heap(Heap_.begin(), Heap_.end(), Comparator_);
+ Heap_.pop_back();
+ }
+}
+
+template <class T, size_t N, class C>
+auto TCompactHeap<T, N, C>::get_min() const -> const_reference
+{
+ YT_ASSERT(!empty());
+
+ if (Y_LIKELY(IsInline())) {
+ return *std::max_element(Heap_.begin(), Heap_.end(), Comparator_);
+ } else {
+ return Heap_.front();
+ }
+}
+
+template <class T, size_t N, class C>
+auto TCompactHeap<T, N, C>::extract_min() -> value_type
+{
+ YT_ASSERT(!empty());
+
+ if (Y_LIKELY(IsInline())) {
+ auto minIt = std::max_element(Heap_.begin(), Heap_.end(), Comparator_);
+ std::swap(*minIt, Heap_.back());
+ auto value = Heap_.back();
+ Heap_.pop_back();
+
+ return value;
+ } else {
+ std::pop_heap(Heap_.begin(), Heap_.end(), Comparator_);
+ auto value = std::move(Heap_.back());
+ Heap_.pop_back();
+
+ return value;
+ }
+}
+
+template <class T, size_t N, class C>
+auto TCompactHeap<T, N, C>::begin() const -> const_iterator
+{
+ return Heap_.begin();
+}
+
+template <class T, size_t N, class C>
+auto TCompactHeap<T, N, C>::end() const -> const_iterator
+{
+ return Heap_.end();
+}
+
+template <class T, size_t N, class C>
+void TCompactHeap<T, N, C>::swap(TCompactHeap<T, N, C>& other)
+{
+ Heap_.swap(other.Heap_);
+ std::swap(Comparator_, other.Comparator_);
+}
+
+template <class T, size_t N, class C>
+size_t TCompactHeap<T, N, C>::size() const
+{
+ return Heap_.size();
+}
+
+template <class T, size_t N, class C>
+size_t TCompactHeap<T, N, C>::capacity() const
+{
+ return Heap_.capacity();
+}
+
+template <class T, size_t N, class C>
+size_t TCompactHeap<T, N, C>::max_size() const
+{
+ return Heap_.max_size();
+}
+
+template <class T, size_t N, class C>
+bool TCompactHeap<T, N, C>::empty() const
+{
+ return Heap_.empty();
+}
+
+template <class T, size_t N, class C>
+void TCompactHeap<T, N, C>::shrink_to_small()
+{
+ Heap_.shrink_to_small();
+}
+
+template <class T, size_t N, class C>
+bool TCompactHeap<T, N, C>::IsInline() const
+{
+ return Heap_.capacity() == N;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, size_t N, class C>
+TCompactHeap<T, N, C>::TReverseComparator::TReverseComparator(C underlying)
+ : Underlying_(std::move(underlying))
+{ }
+
+template <class T, size_t N, class C>
+bool TCompactHeap<T, N, C>::TReverseComparator::operator()(const T& lhs, const T& rhs) const
+{
+ return Underlying_(rhs, lhs);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/small_containers/compact_heap.h b/library/cpp/yt/small_containers/compact_heap.h
new file mode 100644
index 0000000000..951b36962d
--- /dev/null
+++ b/library/cpp/yt/small_containers/compact_heap.h
@@ -0,0 +1,75 @@
+#pragma once
+
+#include "compact_vector.h"
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! A heap structure optimized for storing elements inline
+//! and with little memory overhead. See TCompactVector.
+/*!
+ * When inline, uses linear search for selecting minimum
+ * instead of storing heap.
+ */
+template <class T, size_t N, class C = std::less<T>>
+class TCompactHeap
+{
+public:
+ static_assert(N <= 8, "TCompactHeap is not optimal for large N");
+
+ explicit TCompactHeap(C comparator = C()) noexcept;
+
+ using value_type = T;
+
+ using const_reference = const T&;
+
+ using const_iterator = const T*;
+
+ using difference_type = ptrdiff_t;
+ using size_type = size_t;
+
+ void push(T value);
+ void pop();
+
+ const_reference get_min() const;
+ value_type extract_min();
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ void swap(TCompactHeap<T, N, C>& other);
+
+ size_t size() const;
+ size_t capacity() const;
+ size_t max_size() const;
+
+ bool empty() const;
+
+ void shrink_to_small();
+
+private:
+ TCompactVector<T, N> Heap_;
+
+ class TReverseComparator
+ {
+ public:
+ explicit TReverseComparator(C underlying);
+
+ bool operator()(const T& lhs, const T& rhs) const;
+
+ private:
+ C Underlying_;
+ };
+ TReverseComparator Comparator_;
+
+ bool IsInline() const;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define COMPACT_HEAP_INL_H_
+#include "compact_heap-inl.h"
+#undef COMPACT_HEAP_INL_H_
diff --git a/library/cpp/yt/small_containers/compact_set-inl.h b/library/cpp/yt/small_containers/compact_set-inl.h
new file mode 100644
index 0000000000..75b8600175
--- /dev/null
+++ b/library/cpp/yt/small_containers/compact_set-inl.h
@@ -0,0 +1,322 @@
+#ifndef COMPACT_SET_INL_H_
+#error "Direct inclusion of this file is not allowed, include compact_set.h"
+// For the sake of sane code completion.
+#include "compact_set.h"
+#endif
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename T, unsigned N, typename C>
+class TCompactSet<T, N, C>::const_iterator
+{
+private:
+ friend class TCompactSet<T, N, C>;
+
+ union
+ {
+ TVectorConstIterator VIter;
+ TSetConstIterator SIter;
+ };
+
+ bool Small;
+
+ const_iterator(TVectorConstIterator it)
+ : VIter(it)
+ , Small(true)
+ { }
+
+ const_iterator(TSetConstIterator it)
+ : SIter(it)
+ , Small(false)
+ { }
+
+ template <class TOther>
+ void ConstructFrom(TOther&& rhs)
+ {
+ Y_VERIFY_DEBUG(Small == rhs.Small);
+
+ if (Small) {
+ new (&VIter)TVectorConstIterator(std::forward<TOther>(rhs).VIter);
+ } else {
+ new (&SIter)TSetConstIterator(std::forward<TOther>(rhs).SIter);
+ }
+ }
+
+ template <class TOther>
+ const_iterator& AssignFrom(TOther&& rhs)
+ {
+ if (this == &rhs) {
+ return *this;
+ }
+
+ if (Small && rhs.Small) {
+ VIter = std::forward<TOther>(rhs).VIter;
+ } else if (!Small && !rhs.Small) {
+ SIter = std::forward<TOther>(rhs).SIter;
+ } else {
+ if (Small) {
+ VIter.~TVectorConstIterator();
+ } else {
+ SIter.~TSetConstIterator();
+ }
+
+ if (rhs.Small) {
+ new (&VIter)TVectorConstIterator(std::forward<TOther>(rhs).VIter);
+ } else {
+ new (&SIter)TSetConstIterator(std::forward<TOther>(rhs).SIter);
+ }
+ }
+
+ Small = rhs.Small;
+
+ return *this;
+ }
+
+public:
+ static_assert(std::is_same_v<
+ typename std::iterator_traits<TVectorConstIterator>::difference_type,
+ typename std::iterator_traits<TSetConstIterator>::difference_type>);
+ static_assert(std::is_same_v<
+ typename std::iterator_traits<TVectorConstIterator>::value_type,
+ typename std::iterator_traits<TSetConstIterator>::value_type>);
+ static_assert(std::is_same_v<
+ typename std::iterator_traits<TVectorConstIterator>::pointer,
+ typename std::iterator_traits<TSetConstIterator>::pointer>);
+ static_assert(std::is_same_v<
+ typename std::iterator_traits<TVectorConstIterator>::reference,
+ typename std::iterator_traits<TSetConstIterator>::reference>);
+
+ using difference_type = typename std::iterator_traits<TVectorConstIterator>::difference_type;
+ using value_type = typename std::iterator_traits<TVectorConstIterator>::value_type;
+ using pointer = typename std::iterator_traits<TVectorConstIterator>::pointer;
+ using reference = typename std::iterator_traits<TVectorConstIterator>::reference;
+ using iterator_category = std::bidirectional_iterator_tag;
+
+ const_iterator(const const_iterator& rhs)
+ : Small(rhs.Small)
+ {
+ ConstructFrom(rhs);
+ }
+
+ const_iterator(const_iterator&& rhs)
+ : Small(rhs.Small)
+ {
+ ConstructFrom(std::move(rhs));
+ }
+
+ ~const_iterator()
+ {
+ if (Small) {
+ VIter.~TVectorConstIterator();
+ } else {
+ SIter.~TSetConstIterator();
+ }
+ }
+
+ const_iterator& operator=(const const_iterator& rhs)
+ {
+ return AssignFrom(rhs);
+ }
+
+ const_iterator& operator=(const_iterator&& rhs)
+ {
+ return AssignFrom(std::move(rhs));
+ }
+
+ const_iterator& operator++()
+ {
+ if (Small) {
+ ++VIter;
+ } else {
+ ++SIter;
+ }
+
+ return *this;
+ }
+
+ const_iterator operator++(int)
+ {
+ auto result = *this;
+
+ if (Small) {
+ ++VIter;
+ } else {
+ ++SIter;
+ }
+
+ return result;
+ }
+
+ const_iterator& operator--()
+ {
+ if (Small) {
+ --VIter;
+ } else {
+ --SIter;
+ }
+
+ return *this;
+ }
+
+ const_iterator operator--(int)
+ {
+ auto result = *this;
+
+ if (Small) {
+ --VIter;
+ } else {
+ --SIter;
+ }
+
+ return result;
+ }
+
+ bool operator==(const const_iterator& rhs) const
+ {
+ if (Small != rhs.Small) {
+ return false;
+ }
+
+ return Small ? (VIter == rhs.VIter) : (SIter == rhs.SIter);
+ }
+
+ bool operator!=(const const_iterator& rhs) const
+ {
+ return !(*this == rhs);
+ }
+
+ const T& operator*() const
+ {
+ return Small ? *VIter : *SIter;
+ }
+
+ const T* operator->() const
+ {
+ return &operator*();
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename T, unsigned N, typename C>
+bool TCompactSet<T, N, C>::empty() const
+{
+ return Vector.empty() && Set.empty();
+}
+
+template <typename T, unsigned N, typename C>
+typename TCompactSet<T, N, C>::size_type TCompactSet<T, N, C>::size() const
+{
+ return IsSmall() ? Vector.size() : Set.size();
+}
+
+template <typename T, unsigned N, typename C>
+const T& TCompactSet<T, N, C>::front() const
+{
+ return IsSmall() ? Vector.front() : *Set.begin();
+}
+
+
+template <typename T, unsigned N, typename C>
+typename TCompactSet<T, N, C>::size_type TCompactSet<T, N, C>::count(const T& v) const
+{
+ if (IsSmall()) {
+ return std::binary_search(Vector.begin(), Vector.end(), v, C()) ? 1 : 0;
+ } else {
+ return Set.count(v);
+ }
+}
+
+template <typename T, unsigned N, typename C>
+std::pair<typename TCompactSet<T, N, C>::const_iterator, bool> TCompactSet<T, N, C>::insert(const T& v)
+{
+ if (!IsSmall()) {
+ auto [it, inserted] = Set.insert(v);
+ return {const_iterator(std::move(it)), inserted};
+ }
+
+ auto it = std::lower_bound(Vector.begin(), Vector.end(), v, C());
+ if (it != Vector.end() && !C()(v, *it)) {
+ return {const_iterator(std::move(it)), false}; // Don't reinsert if it already exists.
+ }
+
+ if (Vector.size() < N) {
+ auto newIt = Vector.insert(it, v);
+ return {const_iterator(std::move(newIt)), true};
+ }
+
+ Set.insert(Vector.begin(), Vector.end());
+ Vector.clear();
+
+ auto [newIt, inserted] = Set.insert(v);
+ Y_VERIFY_DEBUG(inserted);
+ return {const_iterator(std::move(newIt)), true};
+}
+
+template <typename T, unsigned N, typename C>
+template <typename TIter>
+void TCompactSet<T, N, C>::insert(TIter i, TIter e)
+{
+ for (; i != e; ++i) {
+ insert(*i);
+ }
+}
+
+template <typename T, unsigned N, typename C>
+bool TCompactSet<T, N, C>::erase(const T& v)
+{
+ if (!IsSmall()) {
+ return Set.erase(v);
+ }
+
+ auto [rangeBegin, rangeEnd] = std::equal_range(Vector.begin(), Vector.end(), v, C());
+ if (rangeBegin != rangeEnd) {
+ Vector.erase(rangeBegin, rangeEnd);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+template <typename T, unsigned N, typename C>
+void TCompactSet<T, N, C>::clear()
+{
+ Vector.clear();
+ Set.clear();
+}
+
+template <typename T, unsigned N, typename C>
+typename TCompactSet<T, N, C>::const_iterator TCompactSet<T, N, C>::begin() const
+{
+ return IsSmall() ? const_iterator(Vector.begin()) : const_iterator(Set.begin());
+}
+
+template <typename T, unsigned N, typename C>
+typename TCompactSet<T, N, C>::const_iterator TCompactSet<T, N, C>::cbegin() const
+{
+ return begin();
+}
+
+template <typename T, unsigned N, typename C>
+typename TCompactSet<T, N, C>::const_iterator TCompactSet<T, N, C>::end() const
+{
+ return IsSmall() ? const_iterator(Vector.end()) : const_iterator(Set.end());
+}
+
+template <typename T, unsigned N, typename C>
+typename TCompactSet<T, N, C>::const_iterator TCompactSet<T, N, C>::cend() const
+{
+ return end();
+}
+
+template <typename T, unsigned N, typename C>
+bool TCompactSet<T, N, C>::IsSmall() const
+{
+ return Set.empty();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/small_containers/compact_set.h b/library/cpp/yt/small_containers/compact_set.h
new file mode 100644
index 0000000000..2ca8713ea7
--- /dev/null
+++ b/library/cpp/yt/small_containers/compact_set.h
@@ -0,0 +1,86 @@
+//===- llvm/ADT/SmallSet.h - 'Normally small' sets --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the TCompactSet class.
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+#include "compact_vector.h"
+
+#include <util/system/yassert.h>
+
+#include <cstddef>
+#include <iterator>
+#include <set>
+#include <type_traits>
+
+namespace NYT {
+
+/// TCompactSet - This maintains a set of unique values, optimizing for the case
+/// when the set is small (less than N). In this case, the set can be
+/// maintained with no mallocs. If the set gets large, we expand to using an
+/// std::set to maintain reasonable lookup times.
+///
+/// Note that any modification of the set may invalidate *all* iterators.
+template <typename T, unsigned N, typename C = std::less<T>>
+class TCompactSet
+{
+private:
+ /// Use a CompactVector to hold the elements here (even though it will never
+ /// reach its 'large' stage) to avoid calling the default ctors of elements
+ /// we will never use.
+ TCompactVector<T, N> Vector;
+ std::set<T, C> Set;
+
+ using TSetConstIterator = typename std::set<T, C>::const_iterator;
+ using TVectorConstIterator = typename TCompactVector<T, N>::const_iterator;
+
+public:
+ class const_iterator;
+ using size_type = std::size_t;
+
+ TCompactSet() {}
+
+ [[nodiscard]] bool empty() const;
+
+ size_type size() const;
+
+ const T& front() const;
+
+ /// count - Return true if the element is in the set.
+ size_type count(const T& v) const;
+
+ /// insert - Insert an element into the set if it isn't already there.
+ std::pair<const_iterator, bool> insert(const T& v);
+
+ template <typename TIter>
+ void insert(TIter i, TIter e);
+
+ bool erase(const T& v);
+
+ void clear();
+
+ const_iterator begin() const;
+ const_iterator cbegin() const;
+
+ const_iterator end() const;
+ const_iterator cend() const;
+
+private:
+ bool IsSmall() const;
+};
+
+} // namespace NYT
+
+#define COMPACT_SET_INL_H_
+#include "compact_set-inl.h"
+#undef COMPACT_SET_INL_H_
+
diff --git a/library/cpp/yt/small_containers/compact_vector-inl.h b/library/cpp/yt/small_containers/compact_vector-inl.h
new file mode 100644
index 0000000000..52507e4768
--- /dev/null
+++ b/library/cpp/yt/small_containers/compact_vector-inl.h
@@ -0,0 +1,1011 @@
+#ifndef COMPACT_VECTOR_INL_H_
+#error "Direct inclusion of this file is not allowed, include compact_vector.h"
+// For the sake of sane code completion.
+#include "compact_vector.h"
+#endif
+#undef COMPACT_VECTOR_INL_H_
+
+#include <library/cpp/yt/assert/assert.h>
+
+#include <library/cpp/yt/malloc/malloc.h>
+
+#include <util/system/compiler.h>
+
+#include <algorithm>
+#include <bit>
+
+#include <string.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+static_assert(sizeof(uintptr_t) == 8);
+
+// TODO(gritukan, babenko): Uncomment check below after DEVTOOLS-7870.
+// static_assert(std::endian::native == std::endian::little);
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+struct TCompactVectorOnHeapStorage
+{
+ T* End;
+ T* Capacity;
+ T Elements[0];
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TVector, class TPtr>
+class TCompactVectorReallocationPtrAdjuster
+{
+public:
+ TCompactVectorReallocationPtrAdjuster(TVector* vector, TPtr& ptr)
+ : Vector_(vector)
+ , Ptr_(ptr)
+ , Index_(ptr >= Vector_->begin() && ptr <= Vector_->end()
+ ? std::distance(Vector_->begin(), const_cast<typename TVector::iterator>(ptr))
+ : -1)
+ { }
+
+ ~TCompactVectorReallocationPtrAdjuster()
+ {
+ if (Index_ >= 0) {
+ Ptr_ = Vector_->begin() + Index_;
+ }
+ }
+
+private:
+ TVector* const Vector_;
+ TPtr& Ptr_;
+ const ptrdiff_t Index_;
+};
+
+template <class TVector>
+class TCompactVectorReallocationPtrAdjuster<TVector, std::nullptr_t>
+{
+public:
+ TCompactVectorReallocationPtrAdjuster(TVector* /*vector*/, std::nullptr_t /*ptr*/)
+ { }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, size_t N>
+TCompactVector<T, N>::TCompactVector() noexcept
+{
+ InlineMeta_.SizePlusOne = 1;
+}
+
+template <class T, size_t N>
+TCompactVector<T, N>::TCompactVector(const TCompactVector& other)
+ : TCompactVector()
+{
+ assign(other.begin(), other.end());
+}
+
+template <class T, size_t N>
+template <size_t OtherN>
+TCompactVector<T, N>::TCompactVector(const TCompactVector<T, OtherN>& other)
+ : TCompactVector()
+{
+ assign(other.begin(), other.end());
+}
+
+template <class T, size_t N>
+TCompactVector<T, N>::TCompactVector(TCompactVector&& other) noexcept(std::is_nothrow_move_constructible_v<T>)
+ : TCompactVector()
+{
+ swap(other);
+}
+
+template <class T, size_t N>
+template <size_t OtherN>
+TCompactVector<T, N>::TCompactVector(TCompactVector<T, OtherN>&& other)
+ : TCompactVector()
+{
+ swap(other);
+}
+
+template <class T, size_t N>
+TCompactVector<T, N>::TCompactVector(size_type count)
+ : TCompactVector()
+{
+ assign(count, T());
+}
+
+template <class T, size_t N>
+TCompactVector<T, N>::TCompactVector(size_type count, const T& value)
+ : TCompactVector()
+{
+ assign(count, value);
+}
+
+template <class T, size_t N>
+template <class TIterator>
+TCompactVector<T, N>::TCompactVector(TIterator first, TIterator last)
+ : TCompactVector()
+{
+ assign(first, last);
+}
+
+template <class T, size_t N>
+TCompactVector<T, N>::TCompactVector(std::initializer_list<T> list)
+ : TCompactVector()
+{
+ assign(list.begin(), list.end());
+}
+
+template <class T, size_t N>
+TCompactVector<T, N>::~TCompactVector()
+{
+ if (Y_LIKELY(IsInline())) {
+ Destroy(&InlineElements_[0], &InlineElements_[InlineMeta_.SizePlusOne - 1]);
+ } else {
+ auto* storage = OnHeapMeta_.Storage;
+ Destroy(storage->Elements, storage->End);
+ ::free(storage);
+ }
+}
+
+template <class T, size_t N>
+bool TCompactVector<T, N>::empty() const
+{
+ if (Y_LIKELY(IsInline())) {
+ return InlineMeta_.SizePlusOne == 1;
+ } else {
+ const auto* storage = OnHeapMeta_.Storage;
+ return storage->Elements == storage->End;
+ }
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::begin() -> iterator
+{
+ return Y_LIKELY(IsInline()) ? &InlineElements_[0] : OnHeapMeta_.Storage->Elements;
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::begin() const -> const_iterator
+{
+ return const_cast<TCompactVector*>(this)->begin();
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::end() -> iterator
+{
+ return Y_LIKELY(IsInline()) ? &InlineElements_[InlineMeta_.SizePlusOne - 1] : OnHeapMeta_.Storage->End;
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::end() const -> const_iterator
+{
+ return const_cast<TCompactVector*>(this)->end();
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::rbegin() -> reverse_iterator
+{
+ return static_cast<reverse_iterator>(end());
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::rbegin() const -> const_reverse_iterator
+{
+ return static_cast<const_reverse_iterator>(end());
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::rend() -> reverse_iterator
+{
+ return static_cast<reverse_iterator>(begin());
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::rend() const -> const_reverse_iterator
+{
+ return static_cast<const_reverse_iterator>(begin());
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::size() const -> size_type
+{
+ if (Y_LIKELY(IsInline())) {
+ return InlineMeta_.SizePlusOne - 1;
+ } else {
+ const auto* storage = OnHeapMeta_.Storage;
+ return storage->End - storage->Elements;
+ }
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::capacity() const -> size_type
+{
+ if (Y_LIKELY(IsInline())) {
+ return N;
+ } else {
+ const auto* storage = OnHeapMeta_.Storage;
+ return storage->Capacity - storage->Elements;
+ }
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::max_size() const -> size_type
+{
+ return static_cast<size_type>(-1) / sizeof(T);
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::data() -> pointer
+{
+ return static_cast<pointer>(begin());
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::data() const -> const_pointer
+{
+ return static_cast<const_pointer>(begin());
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::operator[](size_type index) -> reference
+{
+ YT_ASSERT(index < size());
+ return begin()[index];
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::operator[](size_type index) const -> const_reference
+{
+ return const_cast<TCompactVector*>(this)->operator[](index);
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::front() -> reference
+{
+ YT_ASSERT(!empty());
+ return begin()[0];
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::front() const -> const_reference
+{
+ return const_cast<TCompactVector*>(this)->front();
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::back() -> reference
+{
+ YT_ASSERT(!empty());
+ return end()[-1];
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::back() const -> const_reference
+{
+ return const_cast<TCompactVector*>(this)->back();
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::push_back(const T& value)
+{
+ PushBackImpl(
+ &value,
+ [&] (T* dst, const T* value) {
+ ::new(dst) T(*value);
+ });
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::push_back(T&& value)
+{
+ PushBackImpl(
+ &value,
+ [&] (T* dst, T* value) {
+ ::new(dst) T(std::move(*value));
+ });
+}
+
+template <class T, size_t N>
+template <class... TArgs>
+auto TCompactVector<T, N>::emplace(const_iterator pos, TArgs&&... args) -> iterator
+{
+ return InsertOneImpl(
+ pos,
+ nullptr,
+ [&] (auto* dst, std::nullptr_t) {
+ ::new(dst) T(std::forward<TArgs>(args)...);
+ },
+ [&] (auto* dst, std::nullptr_t) {
+ *dst = T(std::forward<TArgs>(args)...);
+ });
+}
+
+template <class T, size_t N>
+template <class... TArgs>
+auto TCompactVector<T, N>::emplace_back(TArgs&&... args) -> reference
+{
+ return PushBackImpl(
+ nullptr,
+ [&] (T* dst, std::nullptr_t) {
+ ::new(dst) T(std::forward<TArgs>(args)...);
+ });
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::pop_back()
+{
+ YT_ASSERT(!empty());
+
+ if (Y_LIKELY(IsInline())) {
+ InlineElements_[InlineMeta_.SizePlusOne - 2].T::~T();
+ --InlineMeta_.SizePlusOne;
+ } else {
+ auto* storage = OnHeapMeta_.Storage;
+ storage->End[-1].T::~T();
+ --storage->End;
+ }
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::erase(const_iterator pos) -> iterator
+{
+ YT_ASSERT(pos >= begin());
+ YT_ASSERT(pos < end());
+
+ auto* mutablePos = const_cast<iterator>(pos);
+ Move(mutablePos + 1, end(), mutablePos);
+ pop_back();
+
+ return mutablePos;
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::erase(const_iterator first, const_iterator last) -> iterator
+{
+ YT_ASSERT(first >= begin());
+ YT_ASSERT(last <= end());
+
+ auto* mutableFirst = const_cast<iterator>(first);
+ auto* mutableLast = const_cast<iterator>(last);
+ auto count = std::distance(mutableFirst, mutableLast);
+
+ if (Y_LIKELY(IsInline())) {
+ auto* end = &InlineElements_[0] + InlineMeta_.SizePlusOne - 1;
+ Move(mutableLast, end, mutableFirst);
+ Destroy(end - count, end);
+ InlineMeta_.SizePlusOne -= count;
+ } else {
+ auto* storage = OnHeapMeta_.Storage;
+ auto* end = storage->End;
+ Move(mutableLast, storage->End, mutableFirst);
+ Destroy(end - count, end);
+ storage->End -= count;
+ }
+
+ return mutableFirst;
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::clear()
+{
+ if (Y_LIKELY(IsInline())) {
+ Destroy(&InlineElements_[0], &InlineElements_[InlineMeta_.SizePlusOne - 1]);
+ InlineMeta_.SizePlusOne = 1;
+ } else {
+ auto* storage = OnHeapMeta_.Storage;
+ Destroy(storage->Elements, storage->End);
+ storage->End = storage->Elements;
+ }
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::resize(size_type newSize)
+{
+ ResizeImpl(
+ newSize,
+ [] (auto* dst) {
+ ::new(dst) T();
+ });
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::resize(size_type newSize, const T& value)
+{
+ ResizeImpl(
+ newSize,
+ [&] (auto* dst) {
+ ::new(dst) T(value);
+ });
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::reserve(size_t newCapacity)
+{
+ if (Y_UNLIKELY(newCapacity > N)) {
+ EnsureOnHeapCapacity(newCapacity, /*incremental*/ false);
+ }
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::swap(TCompactVector& other)
+{
+ if (this == &other) {
+ return;
+ }
+
+ if (!IsInline() && !other.IsInline()) {
+ std::swap(OnHeapMeta_.Storage, other.OnHeapMeta_.Storage);
+ return;
+ }
+
+ auto* lhs = this;
+ auto* rhs = &other;
+ if (lhs->size() < rhs->size()) {
+ std::swap(lhs, rhs);
+ }
+
+ size_t rhsSize = rhs->size();
+ size_t lhsSize = lhs->size();
+ if (lhsSize > rhs->capacity()) {
+ rhs->EnsureOnHeapCapacity(lhs->size(), /*incremental*/ false);
+ }
+
+ for (size_t index = 0; index < rhsSize; ++index) {
+ std::swap((*lhs)[index], (*rhs)[index]);
+ }
+
+ UninitializedMove(lhs->begin() + rhsSize, lhs->end(), rhs->end());
+ Destroy(lhs->begin() + rhsSize, lhs->end());
+
+ rhs->SetSize(lhsSize);
+ lhs->SetSize(rhsSize);
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::assign(size_type count, const T& value)
+{
+ clear();
+
+ if (Y_UNLIKELY(count > capacity())) {
+ EnsureOnHeapCapacity(count, /*incremental*/ false);
+ }
+
+ auto* dst = begin();
+ std::uninitialized_fill(dst, dst + count, value);
+
+ SetSize(count);
+}
+
+template <class T, size_t N>
+template <class TIterator>
+void TCompactVector<T, N>::assign(TIterator first, TIterator last)
+{
+ clear();
+
+ auto count = std::distance(first, last);
+ if (Y_UNLIKELY(count > static_cast<ptrdiff_t>(capacity()))) {
+ EnsureOnHeapCapacity(count, /*incremental*/ false);
+ }
+
+ std::uninitialized_copy(first, last, begin());
+
+ SetSize(count);
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::assign(std::initializer_list<T> list)
+{
+ assign(list.begin(), list.end());
+}
+
+template <class T, size_t N>
+template <size_t OtherN>
+void TCompactVector<T, N>::assign(const TCompactVector<T, OtherN>& other)
+{
+ if constexpr(N == OtherN) {
+ if (this == &other) {
+ return;
+ }
+ }
+
+ auto otherSize = other.size();
+ auto otherBegin = other.begin();
+
+ if (capacity() >= otherSize) {
+ const auto* src = other.begin();
+ auto* dst = begin();
+
+ auto thisSize = size();
+ auto copySize = std::min(thisSize, otherSize);
+ Copy(src, src + copySize, dst);
+ src += copySize;
+ dst += copySize;
+
+ auto uninitializedCopySize = otherSize - copySize;
+ UninitializedCopy(src, src + uninitializedCopySize, dst);
+ // NB: src += uninitializedCopySize is not needed.
+ dst += uninitializedCopySize;
+
+ if (thisSize > otherSize) {
+ Destroy(dst, end());
+ }
+
+ SetSize(otherSize);
+ return;
+ }
+
+ clear();
+
+ EnsureOnHeapCapacity(otherSize, /*incremental*/ false);
+
+ YT_ASSERT(!IsInline());
+ auto* storage = OnHeapMeta_.Storage;
+ UninitializedCopy(otherBegin, otherBegin + otherSize, storage->Elements);
+ storage->End = storage->Elements + otherSize;
+}
+
+template <class T, size_t N>
+template <size_t OtherN>
+void TCompactVector<T, N>::assign(TCompactVector<T, OtherN>&& other)
+{
+ if constexpr(N == OtherN) {
+ if (this == &other) {
+ return;
+ }
+ }
+
+ clear();
+
+ if (!other.IsInline()) {
+ if (Y_UNLIKELY(!IsInline())) {
+ ::free(OnHeapMeta_.Storage);
+ }
+ OnHeapMeta_.Storage = other.OnHeapMeta_.Storage;
+ other.InlineMeta_.SizePlusOne = 1;
+ return;
+ }
+
+ auto otherSize = other.size();
+ if (Y_UNLIKELY(otherSize > capacity())) {
+ EnsureOnHeapCapacity(otherSize, /*incremental*/ false);
+ }
+
+ auto* otherBegin = other.begin();
+ UninitializedMove(otherBegin, otherBegin + otherSize, begin());
+ SetSize(otherSize);
+
+ other.clear();
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::operator=(const TCompactVector& other) -> TCompactVector&
+{
+ assign(other);
+ return *this;
+}
+
+template <class T, size_t N>
+template <size_t OtherN>
+auto TCompactVector<T, N>::operator=(const TCompactVector<T, OtherN>& other) -> TCompactVector&
+{
+ assign(other);
+ return *this;
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::operator=(TCompactVector&& other) -> TCompactVector&
+{
+ assign(std::move(other));
+ return *this;
+}
+
+template <class T, size_t N>
+template <size_t OtherN>
+auto TCompactVector<T, N>::operator=(TCompactVector<T, OtherN>&& other) -> TCompactVector&
+{
+ assign(std::move(other));
+ return *this;
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::operator=(std::initializer_list<T> list) -> TCompactVector&
+{
+ assign(list);
+ return *this;
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::insert(const_iterator pos, const T& value) -> iterator
+{
+ return InsertOneImpl(
+ pos,
+ &value,
+ [&] (auto* dst, const auto* value) {
+ ::new(dst) T(*value);
+ },
+ [&] (auto* dst, const auto* value) {
+ *dst = *value;
+ });
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::insert(const_iterator pos, T&& value) -> iterator
+{
+ return InsertOneImpl(
+ pos,
+ &value,
+ [&] (auto* dst, auto* value) {
+ ::new(dst) T(std::move(*value));
+ },
+ [&] (auto* dst, auto* value) {
+ *dst = std::move(*value);
+ });
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::insert(const_iterator pos, size_type count, const T& value) -> iterator
+{
+ return InsertManyImpl(
+ pos,
+ count,
+ [&] (auto* dstFirst, auto* dstLast) {
+ for (auto* dst = dstFirst; dst != dstLast; ++dst) {
+ ::new(dst) T(value);
+ }
+ },
+ [&] (auto* dstFirst, auto* dstLast) {
+ for (auto* dst = dstFirst; dst != dstLast; ++dst) {
+ *dst = value;
+ }
+ });
+}
+
+template <class T, size_t N>
+template <class TIterator>
+auto TCompactVector<T, N>::insert(const_iterator pos, TIterator first, TIterator last) -> iterator
+{
+ auto current = first;
+ return InsertManyImpl(
+ pos,
+ std::distance(first, last),
+ [&] (auto* dstFirst, auto* dstLast) {
+ for (auto* dst = dstFirst; dst != dstLast; ++dst) {
+ ::new(dst) T(*current++);
+ }
+ },
+ [&] (auto* dstFirst, auto* dstLast) {
+ for (auto* dst = dstFirst; dst != dstLast; ++dst) {
+ *dst = *current++;
+ }
+ });
+}
+
+template <class T, size_t N>
+auto TCompactVector<T, N>::insert(const_iterator pos, std::initializer_list<T> list) -> iterator
+{
+ return insert(pos, list.begin(), list.end());
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::shrink_to_small()
+{
+ if (Y_LIKELY(IsInline())) {
+ return;
+ }
+
+ auto size = this->size();
+ if (size > N) {
+ return;
+ }
+
+ auto* storage = OnHeapMeta_.Storage;
+ UninitializedMove(storage->Elements, storage->End, &InlineElements_[0]);
+ Destroy(storage->Elements, storage->End);
+ ::free(storage);
+
+ InlineMeta_.SizePlusOne = size + 1;
+}
+
+template <class T, size_t N>
+bool TCompactVector<T, N>::IsInline() const
+{
+ return InlineMeta_.SizePlusOne != 0;
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::SetSize(size_t newSize)
+{
+ if (Y_LIKELY(IsInline())) {
+ InlineMeta_.SizePlusOne = newSize + 1;
+ } else {
+ auto* storage = OnHeapMeta_.Storage;
+ storage->End = storage->Elements + newSize;
+ }
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::EnsureOnHeapCapacity(size_t newCapacity, bool incremental)
+{
+ newCapacity = std::max(newCapacity, N + 1);
+ if (incremental) {
+ newCapacity = std::max(newCapacity, capacity() * 2);
+ }
+
+ auto byteSize = sizeof(TOnHeapStorage) + newCapacity * sizeof(T);
+ byteSize = nallocx(byteSize, 0);
+
+ newCapacity = (byteSize - sizeof(TOnHeapStorage)) / sizeof(T);
+
+ auto* newStorage = static_cast<TOnHeapStorage*>(::malloc(byteSize));
+ YT_VERIFY((reinterpret_cast<uintptr_t>(newStorage) >> 56) == 0);
+
+ newStorage->Capacity = newStorage->Elements + newCapacity;
+
+ size_t size;
+ if (IsInline()) {
+ size = InlineMeta_.SizePlusOne - 1;
+ UninitializedMove(&InlineElements_[0], &InlineElements_[0] + size, newStorage->Elements);
+ Destroy(&InlineElements_[0], &InlineElements_[0] + size);
+ } else {
+ auto* storage = OnHeapMeta_.Storage;
+ size = storage->End - storage->Elements;
+ UninitializedMove(storage->Elements, storage->End, newStorage->Elements);
+ Destroy(storage->Elements, storage->End);
+ ::free(storage);
+ }
+
+ newStorage->End = newStorage->Elements + size;
+ OnHeapMeta_.Storage = newStorage;
+}
+
+template <class T, size_t N>
+template <class TPtr, class F>
+auto TCompactVector<T, N>::PushBackImpl(TPtr valuePtr, F&& func) -> reference
+{
+ auto sizePlusOne = InlineMeta_.SizePlusOne;
+ if (Y_LIKELY(sizePlusOne != 0 && sizePlusOne != N + 1)) {
+ auto* dst = &InlineElements_[sizePlusOne - 1];
+ func(dst, valuePtr);
+ ++InlineMeta_.SizePlusOne;
+ return *dst;
+ }
+
+ auto hasSpareOnHeapCapacity = [&] {
+ if (sizePlusOne != 0) {
+ return false;
+ }
+ auto* storage = OnHeapMeta_.Storage;
+ return storage->End < storage->Capacity;
+ };
+
+ if (Y_UNLIKELY(!hasSpareOnHeapCapacity())) {
+ TCompactVectorReallocationPtrAdjuster<TCompactVector, TPtr> valuePtrAdjuster(this, valuePtr);
+ EnsureOnHeapCapacity(0, /*incremental*/ true);
+ }
+
+ YT_ASSERT(!IsInline());
+ auto* storage = OnHeapMeta_.Storage;
+ auto* dst = storage->End++;
+ func(dst, valuePtr);
+
+ return *dst;
+}
+
+template <class T, size_t N>
+template <class F>
+void TCompactVector<T, N>::ResizeImpl(size_type newSize, F&& func)
+{
+ auto size = this->size();
+ if (newSize > size) {
+ if (Y_UNLIKELY(newSize > capacity())) {
+ EnsureOnHeapCapacity(newSize, /*incremental*/ false);
+ }
+
+ auto* first = end();
+ auto* last = first + newSize - size;
+ for (auto* current = first; current != last; ++current) {
+ func(current);
+ }
+ } else if (newSize < size) {
+ Destroy(begin() + newSize, end());
+ }
+
+ SetSize(newSize);
+}
+
+template <class T, size_t N>
+template <class TPtr, class UninitializedF, class InitializedF>
+auto TCompactVector<T, N>::InsertOneImpl(const_iterator pos, TPtr valuePtr, UninitializedF&& uninitializedFunc, InitializedF&& initializedFunc) -> iterator
+{
+ YT_ASSERT(pos >= begin());
+ YT_ASSERT(pos <= end());
+
+ auto* mutablePos = const_cast<iterator>(pos);
+
+ auto newSize = size() + 1;
+ if (Y_UNLIKELY(newSize > capacity())) {
+ TCompactVectorReallocationPtrAdjuster<TCompactVector, iterator> mutablePosAdjuster(this, mutablePos);
+ TCompactVectorReallocationPtrAdjuster<TCompactVector, TPtr> valuePtrAdjuster(this, valuePtr);
+ EnsureOnHeapCapacity(newSize, /*incremental*/ true);
+ }
+
+ auto* end = this->end();
+
+ if constexpr(!std::is_same_v<TPtr, std::nullptr_t>) {
+ if (valuePtr >= mutablePos && valuePtr < end) {
+ ++valuePtr;
+ }
+ }
+
+ auto moveCount = std::distance(mutablePos, end);
+ if (moveCount == 0) {
+ uninitializedFunc(end, valuePtr);
+ } else {
+ if constexpr(std::is_trivially_copyable_v<T>) {
+ ::memmove(mutablePos + 1, mutablePos, moveCount * sizeof(T));
+ } else {
+ ::new(end) T(std::move(end[-1]));
+ MoveBackward(mutablePos, end - 1, mutablePos + 1);
+ }
+ initializedFunc(mutablePos, valuePtr);
+ }
+
+ SetSize(newSize);
+
+ return mutablePos;
+}
+
+template <class T, size_t N>
+template <class UninitializedF, class InitializedF>
+auto TCompactVector<T, N>::InsertManyImpl(const_iterator pos, size_t insertCount, UninitializedF&& uninitializedFunc, InitializedF&& initializedFunc) -> iterator
+{
+ YT_ASSERT(pos >= begin());
+ YT_ASSERT(pos <= end());
+
+ auto* mutablePos = const_cast<iterator>(pos);
+ if (insertCount == 0) {
+ return mutablePos;
+ }
+
+ auto size = this->size();
+ auto newSize = size + insertCount;
+ if (Y_UNLIKELY(newSize > capacity())) {
+ auto index = std::distance(begin(), mutablePos);
+ EnsureOnHeapCapacity(newSize, /*incremental*/ true);
+ mutablePos = begin() + index;
+ }
+
+ auto* end = this->end();
+ auto moveCount = std::distance(mutablePos, end);
+ if constexpr(std::is_trivially_copyable_v<T>) {
+ ::memmove(mutablePos + insertCount, mutablePos, moveCount * sizeof(T));
+ initializedFunc(mutablePos, mutablePos + insertCount);
+ } else {
+ if (static_cast<ptrdiff_t>(insertCount) >= moveCount) {
+ UninitializedMove(mutablePos, end, mutablePos + insertCount);
+ initializedFunc(mutablePos, end);
+ uninitializedFunc(end, end + insertCount - moveCount);
+ } else {
+ auto overlapCount = moveCount - insertCount;
+ UninitializedMove(mutablePos + overlapCount, end, mutablePos + overlapCount + insertCount);
+ MoveBackward(mutablePos, mutablePos + overlapCount, mutablePos + insertCount);
+ initializedFunc(mutablePos, mutablePos + insertCount);
+ }
+ }
+
+ SetSize(newSize);
+
+ return mutablePos;
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::Destroy(T* first, T* last)
+{
+ if constexpr(!std::is_trivially_destructible_v<T>) {
+ for (auto* current = first; current != last; ++current) {
+ current->T::~T();
+ }
+ }
+}
+
+template <class T, size_t N>
+template <class T1, class T2>
+void TCompactVector<T, N>::Copy(const T1* srcFirst, const T1* srcLast, T2* dst)
+{
+ if constexpr(std::is_trivially_copyable_v<T1> && std::is_same_v<T1, T2>) {
+ ::memcpy(dst, srcFirst, (srcLast - srcFirst) * sizeof(T));
+ } else {
+ std::copy(srcFirst, srcLast, dst);
+ }
+}
+
+template <class T, size_t N>
+template <class T1, class T2>
+void TCompactVector<T, N>::UninitializedCopy(const T1* srcFirst, const T1* srcLast, T2* dst)
+{
+ if constexpr(std::is_trivially_copyable_v<T1> && std::is_same_v<T1, T2>) {
+ ::memcpy(dst, srcFirst, (srcLast - srcFirst) * sizeof(T));
+ } else {
+ std::uninitialized_copy(srcFirst, srcLast, dst);
+ }
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::Move(T* srcFirst, T* srcLast, T* dst)
+{
+ if constexpr(std::is_trivially_copyable_v<T>) {
+ ::memmove(dst, srcFirst, (srcLast - srcFirst) * sizeof(T));
+ } else {
+ std::move(srcFirst, srcLast, dst);
+ }
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::UninitializedMove(T* srcFirst, T* srcLast, T* dst)
+{
+ if constexpr(std::is_trivially_copyable_v<T>) {
+ ::memcpy(dst, srcFirst, (srcLast - srcFirst) * sizeof(T));
+ } else {
+ std::uninitialized_move(srcFirst, srcLast, dst);
+ }
+}
+
+template <class T, size_t N>
+void TCompactVector<T, N>::MoveBackward(T* srcFirst, T* srcLast, T* dst)
+{
+ auto* src = srcLast;
+ dst += std::distance(srcFirst, srcLast);
+ while (src > srcFirst) {
+ *--dst = std::move(*--src);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+template <class T, size_t LhsN, size_t RhsN>
+bool operator==(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs)
+{
+ if constexpr(LhsN == RhsN) {
+ if (&lhs == &rhs) {
+ return true;
+ }
+ }
+
+ if (lhs.size() != rhs.size()) {
+ return false;
+ }
+
+ return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+}
+
+template <class T, size_t LhsN, size_t RhsN>
+bool operator!=(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs)
+{
+ return !(lhs == rhs);
+}
+
+template <class T, size_t LhsN, size_t RhsN>
+bool operator<(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs)
+{
+ return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+namespace std {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, size_t N>
+void swap(NYT::TCompactVector<T, N>& lhs, NYT::TCompactVector<T, N>& rhs)
+{
+ lhs.swap(rhs);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace std
diff --git a/library/cpp/yt/small_containers/compact_vector.h b/library/cpp/yt/small_containers/compact_vector.h
new file mode 100644
index 0000000000..6c4a0b0e39
--- /dev/null
+++ b/library/cpp/yt/small_containers/compact_vector.h
@@ -0,0 +1,219 @@
+#pragma once
+
+#include <util/system/defaults.h>
+
+#include <cstdint>
+#include <iterator>
+#include <limits>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+struct TCompactVectorOnHeapStorage;
+
+//! A vector-like structure optimized for storing elements inline
+//! and with little memory overhead.
+/*!
+ * Stores up to #N (<= 254) elements inline.
+ *
+ * When capacity starts exceeding #N, moves all elements to heap;
+ * \see #TCompactVectorOnHeapStorage.
+ *
+ * When linked with YTAlloc, employs its API to adjust the on-heap capacity in accordance
+ * to the actual size of the allocated region.
+ *
+ * Assuming the entropy and the alignment constraints, yields a seemingly optimal memory overhead.
+ * E.g. TCompactVector<uint8_t, 7> takes 8 bytes and TCompactVector<uint32_t, 3> takes 16 bytes.
+ * \see #ByteSize.
+ *
+ * Assumes (and asserts) the following:
+ * 1) the platform is 64 bit;
+ * 2) the highest 8 bits of pointers returned by |malloc| are zeroes;
+ * 3) the platform is little-endian.
+ */
+template <class T, size_t N>
+class TCompactVector
+{
+public:
+ static_assert(N < std::numeric_limits<uint8_t>::max());
+
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+
+ using value_type = T;
+
+ using iterator = T*;
+ using const_iterator = const T*;
+
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+
+ using reference = T&;
+ using const_reference = const T&;
+
+ using pointer = T*;
+ using const_pointer = const T*;
+
+ TCompactVector() noexcept;
+ TCompactVector(const TCompactVector& other);
+ template <size_t OtherN>
+ TCompactVector(const TCompactVector<T, OtherN>& other);
+ TCompactVector(TCompactVector&& other) noexcept(std::is_nothrow_move_constructible_v<T>);
+ template <size_t OtherN>
+ TCompactVector(TCompactVector<T, OtherN>&& other);
+ explicit TCompactVector(size_type count);
+ TCompactVector(size_type count, const T& value);
+ template <class TIterator>
+ TCompactVector(TIterator first, TIterator last);
+ TCompactVector(std::initializer_list<T> list);
+
+ ~TCompactVector();
+
+ [[nodiscard]] bool empty() const;
+
+ iterator begin();
+ const_iterator begin() const;
+ iterator end();
+ const_iterator end() const;
+
+ reverse_iterator rbegin();
+ const_reverse_iterator rbegin() const;
+ reverse_iterator rend();
+ const_reverse_iterator rend() const;
+
+ size_type size() const;
+ size_type capacity() const;
+ size_type max_size() const;
+
+ pointer data();
+ const_pointer data() const;
+
+ reference operator[](size_type index);
+ const_reference operator[](size_type index) const;
+
+ reference front();
+ const_reference front() const;
+ reference back();
+ const_reference back() const;
+
+ void push_back(const T& value);
+ void push_back(T&& value);
+
+ template <class... TArgs>
+ iterator emplace(const_iterator pos, TArgs&&... args);
+ template <class... TArgs>
+ reference emplace_back(TArgs&&... args);
+
+ void pop_back();
+
+ iterator erase(const_iterator pos);
+ iterator erase(const_iterator first, const_iterator last);
+
+ void clear();
+
+ void resize(size_type newSize);
+ void resize(size_type newSize, const T& value);
+
+ void reserve(size_type newCapacity);
+
+ void swap(TCompactVector& other);
+
+ void assign(size_type count, const T& value);
+ template <class TIterator>
+ void assign(TIterator first, TIterator last);
+ void assign(std::initializer_list<T> list);
+ template <size_t OtherN>
+ void assign(const TCompactVector<T, OtherN>& other);
+ template <size_t OtherN>
+ void assign(TCompactVector<T, OtherN>&& other);
+
+ TCompactVector& operator=(const TCompactVector& other);
+ template <size_t OtherN>
+ TCompactVector& operator=(const TCompactVector<T, OtherN>& other);
+ TCompactVector& operator=(TCompactVector&& other);
+ template <size_t OtherN>
+ TCompactVector& operator=(TCompactVector<T, OtherN>&& other);
+ TCompactVector& operator=(std::initializer_list<T> list);
+
+ iterator insert(const_iterator pos, const T& value);
+ iterator insert(const_iterator pos, T&& value);
+ iterator insert(const_iterator pos, size_type count, const T& value);
+ template <class TIterator>
+ iterator insert(const_iterator pos, TIterator first, TIterator last);
+ iterator insert(const_iterator pos, std::initializer_list<T> list);
+
+ void shrink_to_small();
+
+private:
+ template <class OtherT, size_t OtherN>
+ friend class TCompactVector;
+
+ using TOnHeapStorage = TCompactVectorOnHeapStorage<T>;
+
+ static constexpr size_t ByteSize =
+ (sizeof(T) * N + alignof(T) + sizeof(uintptr_t) - 1) &
+ ~(sizeof(uintptr_t) - 1);
+
+ struct TInlineMeta
+ {
+ char Padding[ByteSize - sizeof(uint8_t)];
+ // > 0 indicates inline storage
+ // == 0 indicates on-heap storage
+ uint8_t SizePlusOne;
+ } alias_hack;
+
+ struct TOnHeapMeta
+ {
+ char Padding[ByteSize - sizeof(uintptr_t)];
+ TOnHeapStorage* Storage;
+ } alias_hack;
+
+ union
+ {
+ T InlineElements_[N];
+ TInlineMeta InlineMeta_;
+ TOnHeapMeta OnHeapMeta_;
+ };
+
+ bool IsInline() const;
+ void SetSize(size_t newSize);
+ void EnsureOnHeapCapacity(size_t newCapacity, bool incremental);
+ template <class TPtr, class F>
+ reference PushBackImpl(TPtr valuePtr, F&& func);
+ template <class F>
+ void ResizeImpl(size_t newSize, F&& func);
+ template <class TPtr, class UninitializedF, class InitializedF>
+ iterator InsertOneImpl(const_iterator pos, TPtr valuePtr, UninitializedF&& uninitializedFunc, InitializedF&& initializedFunc);
+ template <class UninitializedF, class InitializedF>
+ iterator InsertManyImpl(const_iterator pos, size_t insertCount, UninitializedF&& uninitializedFunc, InitializedF&& initializedFunc);
+
+ static void Destroy(T* first, T* last);
+ template <class T1, class T2>
+ static void Copy(const T1* srcFirst, const T1* srcLast, T2* dst);
+ template <class T1, class T2>
+ static void UninitializedCopy(const T1* srcFirst, const T1* srcLast, T2* dst);
+ static void Move(T* srcFirst, T* srcLast, T* dst);
+ static void MoveBackward(T* srcFirst, T* srcLast, T* dst);
+ static void UninitializedMove(T* srcFirst, T* srcLast, T* dst);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, size_t LhsN, size_t RhsN>
+bool operator==(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs);
+
+template <class T, size_t LhsN, size_t RhsN>
+bool operator!=(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs);
+
+template <class T, size_t LhsN, size_t RhsN>
+bool operator<(const TCompactVector<T, LhsN>& lhs, const TCompactVector<T, RhsN>& rhs);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define COMPACT_VECTOR_INL_H_
+#include "compact_vector-inl.h"
+#undef COMPACT_VECTOR_INL_H_
diff --git a/library/cpp/yt/small_containers/unittests/compact_flat_map_ut.cpp b/library/cpp/yt/small_containers/unittests/compact_flat_map_ut.cpp
new file mode 100644
index 0000000000..0b2f290692
--- /dev/null
+++ b/library/cpp/yt/small_containers/unittests/compact_flat_map_ut.cpp
@@ -0,0 +1,225 @@
+#include <yt/yt/core/test_framework/framework.h>
+
+#include <yt/yt/core/misc/compact_flat_map.h>
+
+#include <string>
+#include <vector>
+
+namespace NYT {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+using TMap = TCompactFlatMap<std::string, std::string, 2>;
+
+TMap CreateMap()
+{
+ std::vector<std::pair<std::string, std::string>> data = {{"I", "met"}, {"a", "traveller"}, {"from", "an"}, {"antique", "land"}};
+ return {data.begin(), data.end()};
+}
+
+TEST(CompactFlatMapTest, DefaultEmpty)
+{
+ TMap m;
+ EXPECT_TRUE(m.empty());
+ EXPECT_EQ(m.begin(), m.end());
+}
+
+TEST(CompactFlatMapTest, Reserve)
+{
+ // No real way to test reserve - just use it and wiggle about.
+ auto m1 = CreateMap();
+ TMap m2;
+ m2.reserve(m1.size());
+ m2.insert(m1.begin(), m1.end());
+ EXPECT_EQ(m1.size(), m2.size());
+}
+
+TEST(CompactFlatMapTest, Size)
+{
+ auto m = CreateMap();
+
+ EXPECT_EQ(m.size(), 4u);
+ EXPECT_EQ(m.ssize(), 4);
+
+ m.insert({"Who", "said"});
+
+ EXPECT_EQ(m.size(), 5u);
+ EXPECT_EQ(m.ssize(), 5);
+
+ m.erase("antique");
+
+ EXPECT_EQ(m.size(), 4u);
+ EXPECT_EQ(m.ssize(), 4);
+}
+
+TEST(CompactFlatMapTest, ClearAndEmpty)
+{
+ auto m = CreateMap();
+
+ EXPECT_FALSE(m.empty());
+ EXPECT_NE(m.begin(), m.end());
+
+ m.clear();
+
+ EXPECT_TRUE(m.empty());
+ EXPECT_EQ(m.begin(), m.end());
+
+ m.insert({"Who", "said"});
+
+ EXPECT_FALSE(m.empty());
+ EXPECT_NE(m.begin(), m.end());
+}
+
+TEST(CompactFlatMapTest, FindMutable)
+{
+ auto m = CreateMap();
+ {
+ auto it = m.find("from");
+ EXPECT_NE(it, m.end());
+ EXPECT_EQ(it->second, "an");
+ it->second = "the";
+ }
+ {
+ auto it = m.find("from");
+ EXPECT_NE(it, m.end());
+ EXPECT_EQ(it->second, "the");
+ }
+ {
+ auto it = m.find("Who");
+ EXPECT_EQ(it, m.end());
+ }
+}
+
+TEST(CompactFlatMapTest, FindConst)
+{
+ const auto& m = CreateMap();
+ {
+ auto it = m.find("from");
+ EXPECT_NE(it, m.end());
+ EXPECT_EQ(it->second, "an");
+ }
+ {
+ auto it = m.find("Who");
+ EXPECT_EQ(it, m.end());
+ }
+}
+
+TEST(CompactFlatMapTest, Insert)
+{
+ auto m = CreateMap();
+
+ auto [it, inserted] = m.insert({"Who", "said"});
+ EXPECT_TRUE(inserted);
+ EXPECT_EQ(m.ssize(), 5);
+ EXPECT_NE(it, m.end());
+ EXPECT_EQ(it, m.find("Who"));
+ EXPECT_EQ(it->second, "said");
+
+ auto [it2, inserted2] = m.insert({"Who", "told"});
+ EXPECT_FALSE(inserted2);
+ EXPECT_EQ(m.ssize(), 5);
+ EXPECT_EQ(it2, it);
+ EXPECT_EQ(it->second, "said");
+
+ std::vector<std::pair<std::string, std::string>> data = {{"Two", "vast"}, {"and", "trunkless"}, {"legs", "of"}, {"stone", "Stand"}, {"in", "the"}, {"desert", "..."}};
+ m.insert(data.begin(), data.end());
+ EXPECT_EQ(m.ssize(), 11);
+ EXPECT_NE(m.find("and"), m.end());
+ EXPECT_EQ(m.find("and")->second, "trunkless");
+}
+
+TEST(CompactFlatMapTest, Emplace)
+{
+ auto m = CreateMap();
+
+ auto [it, inserted] = m.emplace("Far", "place");
+ EXPECT_TRUE(inserted);
+ EXPECT_EQ(m.ssize(), 5);
+ EXPECT_NE(it, m.end());
+ EXPECT_EQ(it, m.find("Far"));
+ EXPECT_EQ(it->second, "place");
+
+ auto [it2, inserted2] = m.emplace("Far", "behind");
+ EXPECT_FALSE(inserted2);
+ EXPECT_EQ(m.ssize(), 5);
+ EXPECT_EQ(it2, it);
+ EXPECT_EQ(it->second, "place");
+}
+
+TEST(CompactFlatMapTest, Subscript)
+{
+ auto m = CreateMap();
+
+ EXPECT_EQ(m["antique"], "land");
+ EXPECT_EQ(m.ssize(), 4);
+
+ EXPECT_EQ(m["Who"], "");
+ EXPECT_EQ(m.ssize(), 5);
+}
+
+TEST(CompactFlatMapTest, Erase)
+{
+ auto m = CreateMap();
+
+ m.erase("antique");
+ EXPECT_EQ(m.ssize(), 3);
+
+ m.erase("Who");
+ EXPECT_EQ(m.ssize(), 3);
+
+ m.erase(m.begin(), m.end());
+ EXPECT_TRUE(m.empty());
+}
+
+TEST(CompactFlatMapTest, GrowShrink)
+{
+ TMap m;
+ m.insert({"Two", "vast"});
+ m.insert({"and", "trunkless"});
+ m.insert({"legs", "of"});
+ m.insert({"stone", "Stand"});
+ m.insert({"in", "the"});
+ m.insert({"desert", "..."});
+
+ m.erase("legs");
+ m.erase("stone");
+ m.erase("in");
+ m.erase("desert");
+
+ EXPECT_EQ(m.ssize(), 2);
+
+ // Must not crash or trigger asan.
+}
+
+TEST(CompactFlatMapTest, GrowShrinkGrow)
+{
+ TMap m;
+ m.insert({"Two", "vast"});
+ m.insert({"and", "trunkless"});
+ m.insert({"legs", "of"});
+ m.insert({"stone", "Stand"});
+ m.insert({"in", "the"});
+ m.insert({"desert", "..."});
+
+ m.erase("legs");
+ m.erase("stone");
+ m.erase("in");
+ m.erase("desert");
+
+ EXPECT_EQ(m.ssize(), 2);
+
+ m.insert({"I", "met"});
+ m.insert({"a", "traveller"});
+ m.insert({"from", "an"});
+ m.insert({"antique", "land"});
+
+ EXPECT_EQ(m.ssize(), 6);
+
+ // Must not crash or trigger asan.
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT
diff --git a/library/cpp/yt/small_containers/unittests/compact_heap_ut.cpp b/library/cpp/yt/small_containers/unittests/compact_heap_ut.cpp
new file mode 100644
index 0000000000..259c576e87
--- /dev/null
+++ b/library/cpp/yt/small_containers/unittests/compact_heap_ut.cpp
@@ -0,0 +1,108 @@
+#include <library/cpp/yt/small_containers/compact_heap.h>
+
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <random>
+
+namespace NYT {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TEST(CompactHeapTest, Simple)
+{
+ TCompactHeap<int, 2> heap;
+ heap.push(3);
+ heap.push(1);
+ heap.push(2);
+
+ EXPECT_EQ(3u, heap.size());
+ EXPECT_EQ(1, heap.extract_min());
+
+ EXPECT_EQ(2, heap.get_min());
+ EXPECT_EQ(2, heap.extract_min());
+
+ EXPECT_EQ(3, heap.extract_min());
+
+ EXPECT_TRUE(heap.empty());
+}
+
+TEST(CompactHeapTest, SimpleComparator)
+{
+ TCompactHeap<int, 2, std::greater<int>> heap;
+ heap.push(3);
+ heap.push(1);
+ heap.push(2);
+
+ EXPECT_EQ(3u, heap.size());
+ EXPECT_EQ(3, heap.extract_min());
+ EXPECT_EQ(2, heap.get_min());
+ EXPECT_EQ(2, heap.extract_min());
+ EXPECT_EQ(1, heap.extract_min());
+ EXPECT_TRUE(heap.empty());
+}
+
+TEST(CompactHeapTest, Capacity)
+{
+ TCompactHeap<int, 2> heap;
+ EXPECT_EQ(2u, heap.capacity());
+ EXPECT_EQ(0u, heap.size());
+
+ for (int i = 0; i < 100; ++i) {
+ heap.push(i);
+ }
+ EXPECT_LE(100u, heap.capacity());
+ EXPECT_EQ(100u, heap.size());
+
+ for (int i = 0; i < 99; ++i) {
+ heap.pop();
+ }
+ EXPECT_LE(100u, heap.capacity());
+ EXPECT_EQ(1u, heap.size());
+
+ heap.shrink_to_small();
+
+ EXPECT_EQ(2u, heap.capacity());
+ EXPECT_EQ(1u, heap.size());
+}
+
+TEST(CompactHeapTest, Stress)
+{
+ TCompactHeap<int, 3, std::greater<int>> heap;
+ std::vector<int> values;
+
+ std::mt19937 rng(42);
+ for (int iteration = 0; iteration < 1000; ++iteration) {
+ EXPECT_EQ(values.size(), heap.size());
+ EXPECT_EQ(values.empty(), heap.empty());
+
+ {
+ std::vector<int> content(heap.begin(), heap.end());
+ std::sort(content.rbegin(), content.rend());
+ EXPECT_EQ(values, content);
+ }
+
+ if (!values.empty()) {
+ EXPECT_EQ(values[0], heap.get_min());
+ }
+
+ if (values.empty() || rng() % 2 == 0) {
+ int x = rng() % 100;
+ heap.push(x);
+ values.push_back(x);
+ std::sort(values.rbegin(), values.rend());
+ } else {
+ if (rng() % 2 == 0) {
+ EXPECT_EQ(values[0], heap.extract_min());
+ } else {
+ heap.pop();
+ }
+ values.erase(values.begin());
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT
diff --git a/library/cpp/yt/small_containers/unittests/compact_set_ut.cpp b/library/cpp/yt/small_containers/unittests/compact_set_ut.cpp
new file mode 100644
index 0000000000..ebab5846e1
--- /dev/null
+++ b/library/cpp/yt/small_containers/unittests/compact_set_ut.cpp
@@ -0,0 +1,204 @@
+//===- llvm/unittest/ADT/SmallSetTest.cpp ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// CompactSet unit tests.
+//
+//===----------------------------------------------------------------------===//
+
+#include <library/cpp/yt/small_containers/compact_set.h>
+
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <string>
+
+namespace NYT {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TEST(CompactSetTest, Insert) {
+
+ TCompactSet<int, 4> s1;
+
+ for (int i = 0; i < 4; i++)
+ s1.insert(i);
+
+ for (int i = 0; i < 4; i++)
+ s1.insert(i);
+
+ EXPECT_EQ(4u, s1.size());
+
+ for (int i = 0; i < 4; i++)
+ EXPECT_EQ(1u, s1.count(i));
+
+ EXPECT_EQ(0u, s1.count(4));
+}
+
+TEST(CompactSetTest, Grow) {
+ TCompactSet<int, 4> s1;
+
+ for (int i = 0; i < 8; i++)
+ s1.insert(i);
+
+ EXPECT_EQ(8u, s1.size());
+
+ for (int i = 0; i < 8; i++)
+ EXPECT_EQ(1u, s1.count(i));
+
+ EXPECT_EQ(0u, s1.count(8));
+}
+
+TEST(CompactSetTest, Erase) {
+ TCompactSet<int, 4> s1;
+
+ for (int i = 0; i < 8; i++)
+ s1.insert(i);
+
+ EXPECT_EQ(8u, s1.size());
+
+ // Remove elements one by one and check if all other elements are still there.
+ for (int i = 0; i < 8; i++) {
+ EXPECT_EQ(1u, s1.count(i));
+ EXPECT_TRUE(s1.erase(i));
+ EXPECT_EQ(0u, s1.count(i));
+ EXPECT_EQ(8u - i - 1, s1.size());
+ for (int j = i + 1; j < 8; j++)
+ EXPECT_EQ(1u, s1.count(j));
+ }
+
+ EXPECT_EQ(0u, s1.count(8));
+}
+
+TEST(CompactSetTest, IteratorInt) {
+ TCompactSet<int, 4> s1;
+
+ // Test the 'small' case.
+ for (int i = 0; i < 3; i++)
+ s1.insert(i);
+
+ std::vector<int> V(s1.begin(), s1.end());
+ // Make sure the elements are in the expected order.
+ std::sort(V.begin(), V.end());
+ for (int i = 0; i < 3; i++)
+ EXPECT_EQ(i, V[i]);
+
+ // Test the 'big' case by adding a few more elements to switch to std::set
+ // internally.
+ for (int i = 3; i < 6; i++)
+ s1.insert(i);
+
+ V.assign(s1.begin(), s1.end());
+ // Make sure the elements are in the expected order.
+ std::sort(V.begin(), V.end());
+ for (int i = 0; i < 6; i++)
+ EXPECT_EQ(i, V[i]);
+}
+
+TEST(CompactSetTest, IteratorString) {
+ // Test CompactSetIterator for TCompactSet with a type with non-trivial
+ // ctors/dtors.
+ TCompactSet<std::string, 2> s1;
+
+ s1.insert("str 1");
+ s1.insert("str 2");
+ s1.insert("str 1");
+
+ std::vector<std::string> V(s1.begin(), s1.end());
+ std::sort(V.begin(), V.end());
+ EXPECT_EQ(2u, s1.size());
+ EXPECT_EQ("str 1", V[0]);
+ EXPECT_EQ("str 2", V[1]);
+
+ s1.insert("str 4");
+ s1.insert("str 0");
+ s1.insert("str 4");
+
+ V.assign(s1.begin(), s1.end());
+ // Make sure the elements are in the expected order.
+ std::sort(V.begin(), V.end());
+ EXPECT_EQ(4u, s1.size());
+ EXPECT_EQ("str 0", V[0]);
+ EXPECT_EQ("str 1", V[1]);
+ EXPECT_EQ("str 2", V[2]);
+ EXPECT_EQ("str 4", V[3]);
+}
+
+TEST(CompactSetTest, IteratorIncMoveCopy) {
+ // Test CompactSetIterator for TCompactSet with a type with non-trivial
+ // ctors/dtors.
+ TCompactSet<std::string, 2> s1;
+
+ s1.insert("str 1");
+ s1.insert("str 2");
+
+ auto Iter = s1.begin();
+ EXPECT_EQ("str 1", *Iter);
+ ++Iter;
+ EXPECT_EQ("str 2", *Iter);
+
+ s1.insert("str 4");
+ s1.insert("str 0");
+ auto Iter2 = s1.begin();
+ Iter = std::move(Iter2);
+ EXPECT_EQ("str 0", *Iter);
+}
+
+// These test weren't taken from llvm.
+
+TEST(CompactSetTest, Empty) {
+ TCompactSet<int, 10> v;
+ EXPECT_TRUE(v.empty());
+
+ auto data = {1, 2, 3, 4, 5};
+
+ v.insert(data.begin(), data.end()); // not crossing size threshold
+ v.erase(4);
+ v.erase(2);
+ v.erase(3);
+ v.erase(5);
+ v.erase(1);
+ EXPECT_TRUE(v.empty());
+
+ auto data2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ v.insert(data2.begin(), data2.end()); // crossing size threshold
+ v.erase(7);
+ v.erase(3);
+ v.erase(1);
+ v.erase(10);
+ v.erase(9);
+ v.erase(0);
+ v.erase(2);
+ v.erase(6);
+ v.erase(4);
+ v.erase(5);
+ v.erase(8);
+ EXPECT_TRUE(v.empty());
+}
+
+TEST(CompactSetTest, ForEach) {
+ TCompactSet<int, 10> v;
+
+ auto data = {10, 9, 3, 4, 1, 5, 6, 8};
+
+ v.insert(data.begin(), data.end());
+
+ std::vector<int> buf(v.begin(), v.end());
+ std::vector<int> expected{1, 3, 4, 5, 6, 8, 9, 10};
+ EXPECT_EQ(expected, buf);
+
+ auto data2 = {7, 1, 2, 0};
+ v.insert(data2.begin(), data2.end());
+ buf.assign(v.begin(), v.end());
+ expected = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ EXPECT_EQ(expected, buf);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT
diff --git a/library/cpp/yt/small_containers/unittests/compact_vector_ut.cpp b/library/cpp/yt/small_containers/unittests/compact_vector_ut.cpp
new file mode 100644
index 0000000000..770d62b9fd
--- /dev/null
+++ b/library/cpp/yt/small_containers/unittests/compact_vector_ut.cpp
@@ -0,0 +1,1084 @@
+// Adapted from the following:
+//===- llvm/unittest/ADT/CompactVectorTest.cpp ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// TCompactVector unit tests.
+//
+//===----------------------------------------------------------------------===//
+
+#include <yt/yt/core/test_framework/framework.h>
+
+#include <yt/yt/core/misc/compact_vector.h>
+
+#include <algorithm>
+#include <list>
+
+#include <stdarg.h>
+
+namespace NYT {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+/// A helper class that counts the total number of constructor and
+/// destructor calls.
+class Constructable {
+private:
+ static int numConstructorCalls;
+ static int numMoveConstructorCalls;
+ static int numCopyConstructorCalls;
+ static int numDestructorCalls;
+ static int numAssignmentCalls;
+ static int numMoveAssignmentCalls;
+ static int numCopyAssignmentCalls;
+
+ bool constructed;
+ int value;
+
+public:
+ Constructable() : constructed(true), value(0) {
+ ++numConstructorCalls;
+ }
+
+ Constructable(int val) : constructed(true), value(val) {
+ ++numConstructorCalls;
+ }
+
+ Constructable(const Constructable & src) : constructed(true) {
+ value = src.value;
+ ++numConstructorCalls;
+ ++numCopyConstructorCalls;
+ }
+
+ Constructable(Constructable && src) : constructed(true) {
+ value = src.value;
+ ++numConstructorCalls;
+ ++numMoveConstructorCalls;
+ }
+
+ ~Constructable() {
+ EXPECT_TRUE(constructed);
+ ++numDestructorCalls;
+ constructed = false;
+ }
+
+ Constructable & operator=(const Constructable & src) {
+ EXPECT_TRUE(constructed);
+ value = src.value;
+ ++numAssignmentCalls;
+ ++numCopyAssignmentCalls;
+ return *this;
+ }
+
+ Constructable & operator=(Constructable && src) {
+ EXPECT_TRUE(constructed);
+ value = src.value;
+ ++numAssignmentCalls;
+ ++numMoveAssignmentCalls;
+ return *this;
+ }
+
+ int getValue() const {
+ return abs(value);
+ }
+
+ static void reset() {
+ numConstructorCalls = 0;
+ numMoveConstructorCalls = 0;
+ numCopyConstructorCalls = 0;
+ numDestructorCalls = 0;
+ numAssignmentCalls = 0;
+ numMoveAssignmentCalls = 0;
+ numCopyAssignmentCalls = 0;
+ }
+
+ static int getNumConstructorCalls() {
+ return numConstructorCalls;
+ }
+
+ static int getNumMoveConstructorCalls() {
+ return numMoveConstructorCalls;
+ }
+
+ static int getNumCopyConstructorCalls() {
+ return numCopyConstructorCalls;
+ }
+
+ static int getNumDestructorCalls() {
+ return numDestructorCalls;
+ }
+
+ static int getNumAssignmentCalls() {
+ return numAssignmentCalls;
+ }
+
+ static int getNumMoveAssignmentCalls() {
+ return numMoveAssignmentCalls;
+ }
+
+ static int getNumCopyAssignmentCalls() {
+ return numCopyAssignmentCalls;
+ }
+
+ friend bool operator==(const Constructable & c0, const Constructable & c1) {
+ return c0.getValue() == c1.getValue();
+ }
+};
+
+int Constructable::numConstructorCalls;
+int Constructable::numCopyConstructorCalls;
+int Constructable::numMoveConstructorCalls;
+int Constructable::numDestructorCalls;
+int Constructable::numAssignmentCalls;
+int Constructable::numCopyAssignmentCalls;
+int Constructable::numMoveAssignmentCalls;
+
+struct NonCopyable {
+ NonCopyable() {}
+ NonCopyable(NonCopyable &&) {}
+ NonCopyable &operator=(NonCopyable &&) { return *this; }
+private:
+ NonCopyable(const NonCopyable &) = delete;
+ NonCopyable &operator=(const NonCopyable &) = delete;
+};
+
+[[maybe_unused]] void CompileTest() {
+ TCompactVector<NonCopyable, 0> V;
+ V.resize(42);
+}
+
+class CompactVectorTestBase : public testing::Test {
+protected:
+
+ void SetUp() override {
+ Constructable::reset();
+ }
+
+ template <typename VectorT>
+ void assertEmpty(VectorT & v) {
+ // Size tests
+ EXPECT_EQ(0u, v.size());
+ EXPECT_TRUE(v.empty());
+
+ // Iterator tests
+ EXPECT_TRUE(v.begin() == v.end());
+ }
+
+ // Assert that v contains the specified values, in order.
+ template <typename VectorT>
+ void assertValuesInOrder(VectorT & v, size_t size, ...) {
+ EXPECT_EQ(size, v.size());
+
+ va_list ap;
+ va_start(ap, size);
+ for (size_t i = 0; i < size; ++i) {
+ int value = va_arg(ap, int);
+ EXPECT_EQ(value, v[i].getValue());
+ }
+
+ va_end(ap);
+ }
+
+ // Generate a sequence of values to initialize the vector.
+ template <typename VectorT>
+ void makeSequence(VectorT & v, int start, int end) {
+ for (int i = start; i <= end; ++i) {
+ v.push_back(Constructable(i));
+ }
+ }
+};
+
+// Test fixture class
+template <typename VectorT>
+class CompactVectorTest : public CompactVectorTestBase {
+protected:
+ VectorT theVector;
+ VectorT otherVector;
+};
+
+
+typedef ::testing::Types<TCompactVector<Constructable, 0>,
+ TCompactVector<Constructable, 1>,
+ TCompactVector<Constructable, 2>,
+ TCompactVector<Constructable, 4>,
+ TCompactVector<Constructable, 5>
+ > CompactVectorTestTypes;
+TYPED_TEST_SUITE(CompactVectorTest, CompactVectorTestTypes);
+
+// New vector test.
+TYPED_TEST(CompactVectorTest, EmptyVectorTest) {
+ SCOPED_TRACE("EmptyVectorTest");
+ this->assertEmpty(this->theVector);
+ EXPECT_TRUE(this->theVector.rbegin() == this->theVector.rend());
+ EXPECT_EQ(0, Constructable::getNumConstructorCalls());
+ EXPECT_EQ(0, Constructable::getNumDestructorCalls());
+}
+
+// Simple insertions and deletions.
+TYPED_TEST(CompactVectorTest, PushPopTest) {
+ SCOPED_TRACE("PushPopTest");
+
+ // Track whether the vector will potentially have to grow.
+ bool RequiresGrowth = this->theVector.capacity() < 3;
+
+ // Push an element
+ this->theVector.push_back(Constructable(1));
+
+ // Size tests
+ this->assertValuesInOrder(this->theVector, 1u, 1);
+ EXPECT_FALSE(this->theVector.begin() == this->theVector.end());
+ EXPECT_FALSE(this->theVector.empty());
+
+ // Push another element
+ this->theVector.push_back(Constructable(2));
+ this->assertValuesInOrder(this->theVector, 2u, 1, 2);
+
+ // Insert at beginning
+ this->theVector.insert(this->theVector.begin(), this->theVector[1]);
+ this->assertValuesInOrder(this->theVector, 3u, 2, 1, 2);
+
+ // Pop one element
+ this->theVector.pop_back();
+ this->assertValuesInOrder(this->theVector, 2u, 2, 1);
+
+ // Pop remaining elements
+ this->theVector.pop_back();
+ this->theVector.pop_back();
+ this->assertEmpty(this->theVector);
+
+ // Check number of constructor calls. Should be 2 for each list element,
+ // one for the argument to push_back, one for the argument to insert,
+ // and one for the list element itself.
+ if (!RequiresGrowth) {
+ EXPECT_EQ(5, Constructable::getNumConstructorCalls());
+ EXPECT_EQ(5, Constructable::getNumDestructorCalls());
+ } else {
+ // If we had to grow the vector, these only have a lower bound, but should
+ // always be equal.
+ EXPECT_LE(5, Constructable::getNumConstructorCalls());
+ EXPECT_EQ(Constructable::getNumConstructorCalls(),
+ Constructable::getNumDestructorCalls());
+ }
+}
+
+TYPED_TEST(CompactVectorTest, InsertEnd)
+{
+ SCOPED_TRACE("InsertEnd");
+
+ TCompactVector<TString, 5> vector;
+ for (int index = 0; index < 10; ++index) {
+ vector.insert(vector.end(), ToString(index));
+ }
+ for (int index = 0; index < 10; ++index) {
+ EXPECT_EQ(vector[index], ToString(index));
+ }
+}
+
+TYPED_TEST(CompactVectorTest, ShrinkToSmall)
+{
+ SCOPED_TRACE("ShrinkToSmall");
+
+ TCompactVector<TString, 5> vector;
+ for (int index = 0; index < 10; ++index) {
+ vector.shrink_to_small();
+ vector.push_back(ToString(index));
+ }
+
+ for (int index = 0; index < 6; ++index) {
+ vector.pop_back();
+ }
+
+ EXPECT_EQ(std::ssize(vector), 4);
+ EXPECT_GE(static_cast<int>(vector.capacity()), 10);
+ vector.shrink_to_small();
+ EXPECT_EQ(std::ssize(vector), 4);
+ EXPECT_EQ(static_cast<int>(vector.capacity()), 5);
+ for (int index = 0; index < 4; ++index) {
+ EXPECT_EQ(vector[index], ToString(index));
+ }
+}
+
+// Clear test.
+TYPED_TEST(CompactVectorTest, ClearTest) {
+ SCOPED_TRACE("ClearTest");
+
+ this->theVector.reserve(2);
+ this->makeSequence(this->theVector, 1, 2);
+ this->theVector.clear();
+
+ this->assertEmpty(this->theVector);
+ EXPECT_EQ(4, Constructable::getNumConstructorCalls());
+ EXPECT_EQ(4, Constructable::getNumDestructorCalls());
+}
+
+// Resize smaller test.
+TYPED_TEST(CompactVectorTest, ResizeShrinkTest) {
+ SCOPED_TRACE("ResizeShrinkTest");
+
+ this->theVector.reserve(3);
+ this->makeSequence(this->theVector, 1, 3);
+ this->theVector.resize(1);
+
+ this->assertValuesInOrder(this->theVector, 1u, 1);
+ EXPECT_EQ(6, Constructable::getNumConstructorCalls());
+ EXPECT_EQ(5, Constructable::getNumDestructorCalls());
+}
+
+// Resize bigger test.
+TYPED_TEST(CompactVectorTest, ResizeGrowTest) {
+ SCOPED_TRACE("ResizeGrowTest");
+
+ this->theVector.resize(2);
+
+ EXPECT_EQ(2, Constructable::getNumConstructorCalls());
+ EXPECT_EQ(0, Constructable::getNumDestructorCalls());
+ EXPECT_EQ(2u, this->theVector.size());
+}
+
+TYPED_TEST(CompactVectorTest, ResizeWithElementsTest) {
+ this->theVector.resize(2);
+
+ Constructable::reset();
+
+ this->theVector.resize(4);
+
+ size_t Ctors = Constructable::getNumConstructorCalls();
+ EXPECT_TRUE(Ctors == 2 || Ctors == 4);
+ size_t MoveCtors = Constructable::getNumMoveConstructorCalls();
+ EXPECT_TRUE(MoveCtors == 0 || MoveCtors == 2);
+ size_t Dtors = Constructable::getNumDestructorCalls();
+ EXPECT_TRUE(Dtors == 0 || Dtors == 2);
+}
+
+// Resize with fill value.
+TYPED_TEST(CompactVectorTest, ResizeFillTest) {
+ SCOPED_TRACE("ResizeFillTest");
+
+ this->theVector.resize(3, Constructable(77));
+ this->assertValuesInOrder(this->theVector, 3u, 77, 77, 77);
+}
+
+// Overflow past fixed size.
+TYPED_TEST(CompactVectorTest, OverflowTest) {
+ SCOPED_TRACE("OverflowTest");
+
+ // Push more elements than the fixed size.
+ this->makeSequence(this->theVector, 1, 10);
+
+ // Test size and values.
+ EXPECT_EQ(10u, this->theVector.size());
+ for (int i = 0; i < 10; ++i) {
+ EXPECT_EQ(i+1, this->theVector[i].getValue());
+ }
+
+ // Now resize back to fixed size.
+ this->theVector.resize(1);
+
+ this->assertValuesInOrder(this->theVector, 1u, 1);
+}
+
+// Iteration tests.
+TYPED_TEST(CompactVectorTest, IterationTest) {
+ this->makeSequence(this->theVector, 1, 2);
+
+ // Forward Iteration
+ typename TypeParam::iterator it = this->theVector.begin();
+ EXPECT_TRUE(*it == this->theVector.front());
+ EXPECT_TRUE(*it == this->theVector[0]);
+ EXPECT_EQ(1, it->getValue());
+ ++it;
+ EXPECT_TRUE(*it == this->theVector[1]);
+ EXPECT_TRUE(*it == this->theVector.back());
+ EXPECT_EQ(2, it->getValue());
+ ++it;
+ EXPECT_TRUE(it == this->theVector.end());
+ --it;
+ EXPECT_TRUE(*it == this->theVector[1]);
+ EXPECT_EQ(2, it->getValue());
+ --it;
+ EXPECT_TRUE(*it == this->theVector[0]);
+ EXPECT_EQ(1, it->getValue());
+
+ // Reverse Iteration
+ typename TypeParam::reverse_iterator rit = this->theVector.rbegin();
+ EXPECT_TRUE(*rit == this->theVector[1]);
+ EXPECT_EQ(2, rit->getValue());
+ ++rit;
+ EXPECT_TRUE(*rit == this->theVector[0]);
+ EXPECT_EQ(1, rit->getValue());
+ ++rit;
+ EXPECT_TRUE(rit == this->theVector.rend());
+ --rit;
+ EXPECT_TRUE(*rit == this->theVector[0]);
+ EXPECT_EQ(1, rit->getValue());
+ --rit;
+ EXPECT_TRUE(*rit == this->theVector[1]);
+ EXPECT_EQ(2, rit->getValue());
+}
+
+// Swap test.
+TYPED_TEST(CompactVectorTest, SwapTest) {
+ SCOPED_TRACE("SwapTest");
+
+ this->makeSequence(this->theVector, 1, 2);
+ std::swap(this->theVector, this->otherVector);
+
+ this->assertEmpty(this->theVector);
+ this->assertValuesInOrder(this->otherVector, 2u, 1, 2);
+}
+
+// Append test
+TYPED_TEST(CompactVectorTest, AppendTest) {
+ SCOPED_TRACE("AppendTest");
+
+ this->makeSequence(this->otherVector, 2, 3);
+
+ this->theVector.push_back(Constructable(1));
+ this->theVector.insert(this->theVector.end(), this->otherVector.begin(), this->otherVector.end());
+
+ this->assertValuesInOrder(this->theVector, 3u, 1, 2, 3);
+}
+
+// Append repeated test
+TYPED_TEST(CompactVectorTest, AppendRepeatedTest) {
+ SCOPED_TRACE("AppendRepeatedTest");
+
+ this->theVector.push_back(Constructable(1));
+ this->theVector.insert(this->theVector.end(), 2, Constructable(77));
+ this->assertValuesInOrder(this->theVector, 3u, 1, 77, 77);
+}
+
+// Assign test
+TYPED_TEST(CompactVectorTest, AssignTest) {
+ SCOPED_TRACE("AssignTest");
+
+ this->theVector.push_back(Constructable(1));
+ this->theVector.assign(2, Constructable(77));
+ this->assertValuesInOrder(this->theVector, 2u, 77, 77);
+}
+
+// Move-assign test
+TYPED_TEST(CompactVectorTest, MoveAssignTest) {
+ SCOPED_TRACE("MoveAssignTest");
+
+ // Set up our vector with a single element, but enough capacity for 4.
+ this->theVector.reserve(4);
+ this->theVector.push_back(Constructable(1));
+
+ // Set up the other vector with 2 elements.
+ this->otherVector.push_back(Constructable(2));
+ this->otherVector.push_back(Constructable(3));
+
+ // Move-assign from the other vector.
+ this->theVector = std::move(this->otherVector);
+
+ // Make sure we have the right result.
+ this->assertValuesInOrder(this->theVector, 2u, 2, 3);
+
+ // Make sure the # of constructor/destructor calls line up. There
+ // are two live objects after clearing the other vector.
+ this->otherVector.clear();
+ EXPECT_EQ(Constructable::getNumConstructorCalls()-2,
+ Constructable::getNumDestructorCalls());
+
+ // There shouldn't be any live objects any more.
+ this->theVector.clear();
+ EXPECT_EQ(Constructable::getNumConstructorCalls(),
+ Constructable::getNumDestructorCalls());
+}
+
+// Erase a single element
+TYPED_TEST(CompactVectorTest, EraseTest) {
+ SCOPED_TRACE("EraseTest");
+
+ this->makeSequence(this->theVector, 1, 3);
+ this->theVector.erase(this->theVector.begin());
+ this->assertValuesInOrder(this->theVector, 2u, 2, 3);
+}
+
+// Erase a range of elements
+TYPED_TEST(CompactVectorTest, EraseRangeTest) {
+ SCOPED_TRACE("EraseRangeTest");
+
+ this->makeSequence(this->theVector, 1, 3);
+ this->theVector.erase(this->theVector.begin(), this->theVector.begin() + 2);
+ this->assertValuesInOrder(this->theVector, 1u, 3);
+}
+
+// Insert a single element.
+TYPED_TEST(CompactVectorTest, InsertTest) {
+ SCOPED_TRACE("InsertTest");
+
+ this->makeSequence(this->theVector, 1, 3);
+ typename TypeParam::iterator I =
+ this->theVector.insert(this->theVector.begin() + 1, Constructable(77));
+ EXPECT_EQ(this->theVector.begin() + 1, I);
+ this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3);
+}
+
+// Insert a copy of a single element.
+TYPED_TEST(CompactVectorTest, InsertCopy) {
+ SCOPED_TRACE("InsertTest");
+
+ this->makeSequence(this->theVector, 1, 3);
+ Constructable C(77);
+ typename TypeParam::iterator I =
+ this->theVector.insert(this->theVector.begin() + 1, C);
+ EXPECT_EQ(this->theVector.begin() + 1, I);
+ this->assertValuesInOrder(this->theVector, 4u, 1, 77, 2, 3);
+}
+
+// Insert repeated elements.
+TYPED_TEST(CompactVectorTest, InsertRepeatedTest) {
+ SCOPED_TRACE("InsertRepeatedTest");
+
+ this->makeSequence(this->theVector, 1, 4);
+ Constructable::reset();
+ auto I =
+ this->theVector.insert(this->theVector.begin() + 1, 2, Constructable(16));
+ // Move construct the top element into newly allocated space, and optionally
+ // reallocate the whole buffer, move constructing into it.
+ // FIXME: This is inefficient, we shouldn't move things into newly allocated
+ // space, then move them up/around, there should only be 2 or 4 move
+ // constructions here.
+ EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 2 ||
+ Constructable::getNumMoveConstructorCalls() == 6);
+ // Move assign the next two to shift them up and make a gap.
+ EXPECT_EQ(1, Constructable::getNumMoveAssignmentCalls());
+ // Copy construct the two new elements from the parameter.
+ EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls());
+ // All without any copy construction.
+ EXPECT_EQ(0, Constructable::getNumCopyConstructorCalls());
+ EXPECT_EQ(this->theVector.begin() + 1, I);
+ this->assertValuesInOrder(this->theVector, 6u, 1, 16, 16, 2, 3, 4);
+}
+
+
+TYPED_TEST(CompactVectorTest, InsertRepeatedAtEndTest) {
+ SCOPED_TRACE("InsertRepeatedTest");
+
+ this->makeSequence(this->theVector, 1, 4);
+ Constructable::reset();
+ auto I = this->theVector.insert(this->theVector.end(), 2, Constructable(16));
+ // Just copy construct them into newly allocated space
+ EXPECT_EQ(2, Constructable::getNumCopyConstructorCalls());
+ // Move everything across if reallocation is needed.
+ EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 ||
+ Constructable::getNumMoveConstructorCalls() == 4);
+ // Without ever moving or copying anything else.
+ EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls());
+ EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls());
+
+ EXPECT_EQ(this->theVector.begin() + 4, I);
+ this->assertValuesInOrder(this->theVector, 6u, 1, 2, 3, 4, 16, 16);
+}
+
+TYPED_TEST(CompactVectorTest, InsertRepeatedEmptyTest) {
+ SCOPED_TRACE("InsertRepeatedTest");
+
+ this->makeSequence(this->theVector, 10, 15);
+
+ // Empty insert.
+ EXPECT_EQ(this->theVector.end(),
+ this->theVector.insert(this->theVector.end(),
+ 0, Constructable(42)));
+ EXPECT_EQ(this->theVector.begin() + 1,
+ this->theVector.insert(this->theVector.begin() + 1,
+ 0, Constructable(42)));
+}
+
+// Insert range.
+TYPED_TEST(CompactVectorTest, InsertRangeTest) {
+ SCOPED_TRACE("InsertRangeTest");
+
+ Constructable Arr[3] =
+ { Constructable(77), Constructable(77), Constructable(77) };
+
+ this->makeSequence(this->theVector, 1, 3);
+ Constructable::reset();
+ auto I = this->theVector.insert(this->theVector.begin() + 1, Arr, Arr + 3);
+ // Move construct the top 3 elements into newly allocated space.
+ // Possibly move the whole sequence into new space first.
+ // FIXME: This is inefficient, we shouldn't move things into newly allocated
+ // space, then move them up/around, there should only be 2 or 3 move
+ // constructions here.
+ EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 2 ||
+ Constructable::getNumMoveConstructorCalls() == 5);
+ // Copy assign the lower 2 new elements into existing space.
+ EXPECT_EQ(2, Constructable::getNumCopyAssignmentCalls());
+ // Copy construct the third element into newly allocated space.
+ EXPECT_EQ(1, Constructable::getNumCopyConstructorCalls());
+ EXPECT_EQ(this->theVector.begin() + 1, I);
+ this->assertValuesInOrder(this->theVector, 6u, 1, 77, 77, 77, 2, 3);
+}
+
+
+TYPED_TEST(CompactVectorTest, InsertRangeAtEndTest) {
+ SCOPED_TRACE("InsertRangeTest");
+
+ Constructable Arr[3] =
+ { Constructable(77), Constructable(77), Constructable(77) };
+
+ this->makeSequence(this->theVector, 1, 3);
+
+ // Insert at end.
+ Constructable::reset();
+ auto I = this->theVector.insert(this->theVector.end(), Arr, Arr+3);
+ // Copy construct the 3 elements into new space at the top.
+ EXPECT_EQ(3, Constructable::getNumCopyConstructorCalls());
+ // Don't copy/move anything else.
+ EXPECT_EQ(0, Constructable::getNumCopyAssignmentCalls());
+ // Reallocation might occur, causing all elements to be moved into the new
+ // buffer.
+ EXPECT_TRUE(Constructable::getNumMoveConstructorCalls() == 0 ||
+ Constructable::getNumMoveConstructorCalls() == 3);
+ EXPECT_EQ(0, Constructable::getNumMoveAssignmentCalls());
+ EXPECT_EQ(this->theVector.begin() + 3, I);
+ this->assertValuesInOrder(this->theVector, 6u,
+ 1, 2, 3, 77, 77, 77);
+}
+
+TYPED_TEST(CompactVectorTest, InsertEmptyRangeTest) {
+ SCOPED_TRACE("InsertRangeTest");
+
+ this->makeSequence(this->theVector, 1, 3);
+
+ // Empty insert.
+ EXPECT_EQ(this->theVector.end(),
+ this->theVector.insert(this->theVector.end(),
+ this->theVector.begin(),
+ this->theVector.begin()));
+ EXPECT_EQ(this->theVector.begin() + 1,
+ this->theVector.insert(this->theVector.begin() + 1,
+ this->theVector.begin(),
+ this->theVector.begin()));
+}
+
+// Comparison tests.
+TYPED_TEST(CompactVectorTest, ComparisonTest) {
+ SCOPED_TRACE("ComparisonTest");
+
+ this->makeSequence(this->theVector, 1, 3);
+ this->makeSequence(this->otherVector, 1, 3);
+
+ EXPECT_TRUE(this->theVector == this->otherVector);
+ EXPECT_FALSE(this->theVector != this->otherVector);
+
+ this->otherVector.clear();
+ this->makeSequence(this->otherVector, 2, 4);
+
+ EXPECT_FALSE(this->theVector == this->otherVector);
+ EXPECT_TRUE(this->theVector != this->otherVector);
+}
+
+// Constant vector tests.
+TYPED_TEST(CompactVectorTest, ConstVectorTest) {
+ const TypeParam constVector;
+
+ EXPECT_EQ(0u, constVector.size());
+ EXPECT_TRUE(constVector.empty());
+ EXPECT_TRUE(constVector.begin() == constVector.end());
+}
+
+// Direct array access.
+TYPED_TEST(CompactVectorTest, DirectVectorTest) {
+ EXPECT_EQ(0u, this->theVector.size());
+ this->theVector.reserve(4);
+ EXPECT_LE(4u, this->theVector.capacity());
+ EXPECT_EQ(0, Constructable::getNumConstructorCalls());
+ this->theVector.push_back(1);
+ this->theVector.push_back(2);
+ this->theVector.push_back(3);
+ this->theVector.push_back(4);
+ EXPECT_EQ(4u, this->theVector.size());
+ EXPECT_EQ(8, Constructable::getNumConstructorCalls());
+ EXPECT_EQ(1, this->theVector[0].getValue());
+ EXPECT_EQ(2, this->theVector[1].getValue());
+ EXPECT_EQ(3, this->theVector[2].getValue());
+ EXPECT_EQ(4, this->theVector[3].getValue());
+}
+
+TYPED_TEST(CompactVectorTest, IteratorTest) {
+ std::list<int> L;
+ this->theVector.insert(this->theVector.end(), L.begin(), L.end());
+}
+
+template <typename InvalidType> class DualCompactVectorsTest;
+
+template <typename VectorT1, typename VectorT2>
+class DualCompactVectorsTest<std::pair<VectorT1, VectorT2>> : public CompactVectorTestBase {
+protected:
+ VectorT1 theVector;
+ VectorT2 otherVector;
+
+ template <typename T, size_t N>
+ static size_t NumBuiltinElts(const TCompactVector<T, N>&) { return N; }
+};
+
+typedef ::testing::Types<
+ // Small mode -> Small mode.
+ std::pair<TCompactVector<Constructable, 4>, TCompactVector<Constructable, 4>>,
+ // Small mode -> Big mode.
+ std::pair<TCompactVector<Constructable, 4>, TCompactVector<Constructable, 2>>,
+ // Big mode -> Small mode.
+ std::pair<TCompactVector<Constructable, 2>, TCompactVector<Constructable, 4>>,
+ // Big mode -> Big mode.
+ std::pair<TCompactVector<Constructable, 2>, TCompactVector<Constructable, 2>>
+ > DualCompactVectorTestTypes;
+
+TYPED_TEST_SUITE(DualCompactVectorsTest, DualCompactVectorTestTypes);
+
+TYPED_TEST(DualCompactVectorsTest, MoveAssignment) {
+ SCOPED_TRACE("MoveAssignTest-DualVectorTypes");
+
+ // Set up our vector with four elements.
+ for (unsigned I = 0; I < 4; ++I)
+ this->otherVector.push_back(Constructable(I));
+
+ const Constructable *OrigDataPtr = this->otherVector.data();
+
+ // Move-assign from the other vector.
+ this->theVector =
+ std::move(this->otherVector);
+
+ // Make sure we have the right result.
+ this->assertValuesInOrder(this->theVector, 4u, 0, 1, 2, 3);
+
+ // Make sure the # of constructor/destructor calls line up. There
+ // are two live objects after clearing the other vector.
+ this->otherVector.clear();
+ EXPECT_EQ(Constructable::getNumConstructorCalls()-4,
+ Constructable::getNumDestructorCalls());
+
+ // If the source vector (otherVector) was in small-mode, assert that we just
+ // moved the data pointer over.
+ EXPECT_TRUE(this->NumBuiltinElts(this->otherVector) == 4 ||
+ this->theVector.data() == OrigDataPtr);
+
+ // There shouldn't be any live objects any more.
+ this->theVector.clear();
+ EXPECT_EQ(Constructable::getNumConstructorCalls(),
+ Constructable::getNumDestructorCalls());
+
+ // We shouldn't have copied anything in this whole process.
+ EXPECT_EQ(Constructable::getNumCopyConstructorCalls(), 0);
+}
+
+struct notassignable {
+ int &x;
+ notassignable(int &x) : x(x) {}
+};
+
+TEST(CompactVectorCustomTest, NoAssignTest) {
+ int x = 0;
+ TCompactVector<notassignable, 2> vec;
+ vec.push_back(notassignable(x));
+ x = 42;
+ EXPECT_EQ(42, vec.back().x);
+}
+
+struct MovedFrom {
+ bool hasValue;
+ MovedFrom() : hasValue(true) {
+ }
+ MovedFrom(MovedFrom&& m) : hasValue(m.hasValue) {
+ m.hasValue = false;
+ }
+ MovedFrom &operator=(MovedFrom&& m) {
+ hasValue = m.hasValue;
+ m.hasValue = false;
+ return *this;
+ }
+};
+
+TEST(CompactVectorTest, MidInsert) {
+ TCompactVector<MovedFrom, 3> v;
+ v.push_back(MovedFrom());
+ v.insert(v.begin(), MovedFrom());
+ for (MovedFrom &m : v)
+ EXPECT_TRUE(m.hasValue);
+}
+
+enum EmplaceableArgState {
+ EAS_Defaulted,
+ EAS_Arg,
+ EAS_LValue,
+ EAS_RValue,
+ EAS_Failure
+};
+template <int I> struct EmplaceableArg {
+ EmplaceableArgState State;
+ EmplaceableArg() : State(EAS_Defaulted) {}
+ EmplaceableArg(EmplaceableArg &&X)
+ : State(X.State == EAS_Arg ? EAS_RValue : EAS_Failure) {}
+ EmplaceableArg(EmplaceableArg &X)
+ : State(X.State == EAS_Arg ? EAS_LValue : EAS_Failure) {}
+
+ explicit EmplaceableArg(bool) : State(EAS_Arg) {}
+
+private:
+ EmplaceableArg &operator=(EmplaceableArg &&) = delete;
+ EmplaceableArg &operator=(const EmplaceableArg &) = delete;
+};
+
+enum EmplaceableState { ES_Emplaced, ES_Moved };
+struct Emplaceable {
+ EmplaceableArg<0> A0;
+ EmplaceableArg<1> A1;
+ EmplaceableArg<2> A2;
+ EmplaceableArg<3> A3;
+ EmplaceableState State;
+
+ Emplaceable() : State(ES_Emplaced) {}
+
+ template <class A0Ty>
+ explicit Emplaceable(A0Ty &&A0)
+ : A0(std::forward<A0Ty>(A0)), State(ES_Emplaced) {}
+
+ template <class A0Ty, class A1Ty>
+ Emplaceable(A0Ty &&A0, A1Ty &&A1)
+ : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)),
+ State(ES_Emplaced) {}
+
+ template <class A0Ty, class A1Ty, class A2Ty>
+ Emplaceable(A0Ty &&A0, A1Ty &&A1, A2Ty &&A2)
+ : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)),
+ A2(std::forward<A2Ty>(A2)), State(ES_Emplaced) {}
+
+ template <class A0Ty, class A1Ty, class A2Ty, class A3Ty>
+ Emplaceable(A0Ty &&A0, A1Ty &&A1, A2Ty &&A2, A3Ty &&A3)
+ : A0(std::forward<A0Ty>(A0)), A1(std::forward<A1Ty>(A1)),
+ A2(std::forward<A2Ty>(A2)), A3(std::forward<A3Ty>(A3)),
+ State(ES_Emplaced) {}
+
+ Emplaceable(Emplaceable &&) : State(ES_Moved) {}
+ Emplaceable &operator=(Emplaceable &&) {
+ State = ES_Moved;
+ return *this;
+ }
+
+private:
+ Emplaceable(const Emplaceable &) = delete;
+ Emplaceable &operator=(const Emplaceable &) = delete;
+};
+
+TEST(CompactVectorTest, EmplaceBack) {
+ EmplaceableArg<0> A0(true);
+ EmplaceableArg<1> A1(true);
+ EmplaceableArg<2> A2(true);
+ EmplaceableArg<3> A3(true);
+ {
+ TCompactVector<Emplaceable, 3> V;
+ V.emplace_back();
+ EXPECT_TRUE(V.size() == 1);
+ EXPECT_TRUE(V.back().State == ES_Emplaced);
+ EXPECT_TRUE(V.back().A0.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A1.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
+ }
+ {
+ TCompactVector<Emplaceable, 3> V;
+ V.emplace_back(std::move(A0));
+ EXPECT_TRUE(V.size() == 1);
+ EXPECT_TRUE(V.back().State == ES_Emplaced);
+ EXPECT_TRUE(V.back().A0.State == EAS_RValue);
+ EXPECT_TRUE(V.back().A1.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
+ }
+ {
+ TCompactVector<Emplaceable, 3> V;
+ V.emplace_back(A0);
+ EXPECT_TRUE(V.size() == 1);
+ EXPECT_TRUE(V.back().State == ES_Emplaced);
+ EXPECT_TRUE(V.back().A0.State == EAS_LValue);
+ EXPECT_TRUE(V.back().A1.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
+ }
+ {
+ TCompactVector<Emplaceable, 3> V;
+ V.emplace_back(A0, A1);
+ EXPECT_TRUE(V.size() == 1);
+ EXPECT_TRUE(V.back().State == ES_Emplaced);
+ EXPECT_TRUE(V.back().A0.State == EAS_LValue);
+ EXPECT_TRUE(V.back().A1.State == EAS_LValue);
+ EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
+ }
+ {
+ TCompactVector<Emplaceable, 3> V;
+ V.emplace_back(std::move(A0), std::move(A1));
+ EXPECT_TRUE(V.size() == 1);
+ EXPECT_TRUE(V.back().State == ES_Emplaced);
+ EXPECT_TRUE(V.back().A0.State == EAS_RValue);
+ EXPECT_TRUE(V.back().A1.State == EAS_RValue);
+ EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
+ }
+ {
+ TCompactVector<Emplaceable, 3> V;
+ V.emplace_back(std::move(A0), A1, std::move(A2), A3);
+ EXPECT_TRUE(V.size() == 1);
+ EXPECT_TRUE(V.back().State == ES_Emplaced);
+ EXPECT_TRUE(V.back().A0.State == EAS_RValue);
+ EXPECT_TRUE(V.back().A1.State == EAS_LValue);
+ EXPECT_TRUE(V.back().A2.State == EAS_RValue);
+ EXPECT_TRUE(V.back().A3.State == EAS_LValue);
+ }
+ {
+ TCompactVector<int, 1> V;
+ V.emplace_back();
+ V.emplace_back(42);
+ EXPECT_EQ(2U, V.size());
+ EXPECT_EQ(0, V[0]);
+ EXPECT_EQ(42, V[1]);
+ }
+}
+
+TEST(CompactVectorTest, Emplace) {
+ EmplaceableArg<0> A0(true);
+ EmplaceableArg<1> A1(true);
+ EmplaceableArg<2> A2(true);
+ EmplaceableArg<3> A3(true);
+ {
+ TCompactVector<Emplaceable, 3> V;
+ V.emplace(V.end());
+ EXPECT_TRUE(V.size() == 1);
+ EXPECT_TRUE(V.back().State == ES_Emplaced);
+ EXPECT_TRUE(V.back().A0.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A1.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
+ }
+ {
+ TCompactVector<Emplaceable, 3> V;
+ V.emplace(V.end(), std::move(A0));
+ EXPECT_TRUE(V.size() == 1);
+ EXPECT_TRUE(V.back().State == ES_Emplaced);
+ EXPECT_TRUE(V.back().A0.State == EAS_RValue);
+ EXPECT_TRUE(V.back().A1.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
+ }
+ {
+ TCompactVector<Emplaceable, 3> V;
+ V.emplace(V.end(), A0);
+ EXPECT_TRUE(V.size() == 1);
+ EXPECT_TRUE(V.back().State == ES_Emplaced);
+ EXPECT_TRUE(V.back().A0.State == EAS_LValue);
+ EXPECT_TRUE(V.back().A1.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
+ }
+ {
+ TCompactVector<Emplaceable, 3> V;
+ V.emplace(V.end(), A0, A1);
+ EXPECT_TRUE(V.size() == 1);
+ EXPECT_TRUE(V.back().State == ES_Emplaced);
+ EXPECT_TRUE(V.back().A0.State == EAS_LValue);
+ EXPECT_TRUE(V.back().A1.State == EAS_LValue);
+ EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
+ }
+ {
+ TCompactVector<Emplaceable, 3> V;
+ V.emplace(V.end(), std::move(A0), std::move(A1));
+ EXPECT_TRUE(V.size() == 1);
+ EXPECT_TRUE(V.back().State == ES_Emplaced);
+ EXPECT_TRUE(V.back().A0.State == EAS_RValue);
+ EXPECT_TRUE(V.back().A1.State == EAS_RValue);
+ EXPECT_TRUE(V.back().A2.State == EAS_Defaulted);
+ EXPECT_TRUE(V.back().A3.State == EAS_Defaulted);
+ }
+ {
+ TCompactVector<Emplaceable, 3> V;
+ V.emplace(V.end(), std::move(A0), A1, std::move(A2), A3);
+ EXPECT_TRUE(V.size() == 1);
+ EXPECT_TRUE(V.back().State == ES_Emplaced);
+ EXPECT_TRUE(V.back().A0.State == EAS_RValue);
+ EXPECT_TRUE(V.back().A1.State == EAS_LValue);
+ EXPECT_TRUE(V.back().A2.State == EAS_RValue);
+ EXPECT_TRUE(V.back().A3.State == EAS_LValue);
+ }
+ {
+ TCompactVector<int, 1> V;
+ V.emplace_back(42);
+ V.emplace(V.begin(), 0);
+ EXPECT_EQ(2U, V.size());
+ EXPECT_EQ(0, V[0]);
+ EXPECT_EQ(42, V[1]);
+ }
+}
+
+template <class T, size_t N>
+class TStubArray
+{
+public:
+ TStubArray(const TCompactVector<T, N>& vector)
+ : Vector_(vector)
+ { }
+
+ bool equals(std::initializer_list<T> list)
+ {
+ return std::equal(Vector_.begin(), Vector_.end(), list.begin());
+ }
+
+ TCompactVector<T, N> Vector_;
+};
+
+template <typename T, size_t N>
+TStubArray<T, N> makeArrayRef(const TCompactVector<T, N>& vector)
+{
+ return TStubArray<T, N>(vector);
+}
+
+TEST(CompactVectorTest, InitializerList) {
+ TCompactVector<int, 2> V1 = {};
+ EXPECT_TRUE(V1.empty());
+ V1 = {0, 0};
+ EXPECT_TRUE(makeArrayRef(V1).equals({0, 0}));
+ V1 = {-1, -1};
+ EXPECT_TRUE(makeArrayRef(V1).equals({-1, -1}));
+
+ TCompactVector<int, 2> V2 = {1, 2, 3, 4};
+ EXPECT_TRUE(makeArrayRef(V2).equals({1, 2, 3, 4}));
+ V2.assign({4});
+ EXPECT_TRUE(makeArrayRef(V2).equals({4}));
+ V2.insert(V2.end(), {3, 2});
+ EXPECT_TRUE(makeArrayRef(V2).equals({4, 3, 2}));
+ V2.insert(V2.begin() + 1, 5);
+ EXPECT_TRUE(makeArrayRef(V2).equals({4, 5, 3, 2}));
+}
+
+TEST(CompactVectorTest, AssignToShorter) {
+ TCompactVector<TString, 4> lhs;
+ TCompactVector<TString, 4> rhs;
+ rhs.emplace_back("foo");
+ lhs = rhs;
+ EXPECT_EQ(1U, lhs.size());
+ EXPECT_EQ("foo", lhs[0]);
+}
+
+TEST(CompactVectorTest, AssignToLonger) {
+ TCompactVector<TString, 4> lhs;
+ lhs.emplace_back("bar");
+ lhs.emplace_back("baz");
+ TCompactVector<TString, 4> rhs;
+ rhs.emplace_back("foo");
+ lhs = rhs;
+ EXPECT_EQ(1U, lhs.size());
+ EXPECT_EQ("foo", lhs[0]);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT
diff --git a/library/cpp/yt/small_containers/unittests/ya.make b/library/cpp/yt/small_containers/unittests/ya.make
new file mode 100644
index 0000000000..6bd8e1d0ec
--- /dev/null
+++ b/library/cpp/yt/small_containers/unittests/ya.make
@@ -0,0 +1,17 @@
+GTEST(unittester-small-containers)
+
+OWNER(g:yt)
+
+SRCS(
+ compact_flat_map_ut.cpp
+ compact_heap_ut.cpp
+ compact_set_ut.cpp
+ compact_vector_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/yt/small_containers
+ library/cpp/testing/gtest
+)
+
+END()
diff --git a/library/cpp/yt/small_containers/ya.make b/library/cpp/yt/small_containers/ya.make
new file mode 100644
index 0000000000..d886b2ddac
--- /dev/null
+++ b/library/cpp/yt/small_containers/ya.make
@@ -0,0 +1,20 @@
+LIBRARY()
+
+PEERDIR(
+ library/cpp/yt/assert
+ library/cpp/yt/malloc
+)
+
+CHECK_DEPENDENT_DIRS(
+ ALLOW_ONLY ALL
+ build
+ contrib
+ library
+ util
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ unittests
+)
diff --git a/library/cpp/yt/string/enum-inl.h b/library/cpp/yt/string/enum-inl.h
new file mode 100644
index 0000000000..ab8acff71b
--- /dev/null
+++ b/library/cpp/yt/string/enum-inl.h
@@ -0,0 +1,118 @@
+#ifndef ENUM_INL_H_
+#error "Direct inclusion of this file is not allowed, include enum.h"
+// For the sake of sane code completion.
+#include "enum.h"
+#endif
+
+#include <util/string/printf.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace NDetail {
+
+[[noreturn]]
+void ThrowMalformedEnumValueException(
+ TStringBuf typeName,
+ TStringBuf value);
+
+void FormatUnknownEnumValue(
+ TStringBuilderBase* builder,
+ TStringBuf name,
+ i64 value);
+
+} // namespace NDetail
+
+template <class T>
+std::optional<T> TryParseEnum(TStringBuf value)
+{
+ static_assert(TEnumTraits<T>::IsEnum);
+
+ auto tryFromString = [] (TStringBuf value) -> std::optional<T> {
+ T result;
+ if (auto ok = TEnumTraits<T>::FindValueByLiteral(DecodeEnumValue(value), &result)) {
+ return result;
+ }
+ return {};
+ };
+
+ if constexpr (TEnumTraits<T>::IsBitEnum) {
+ T result{};
+ TStringBuf token;
+ while (value.NextTok('|', token)) {
+ if (auto scalar = tryFromString(StripString(token))) {
+ result |= *scalar;
+ } else {
+ return {};
+ }
+ }
+ return result;
+ } else {
+ return tryFromString(value);
+ }
+}
+
+template <class T>
+T ParseEnum(TStringBuf value)
+{
+ if (auto optionalResult = TryParseEnum<T>(value)) {
+ return *optionalResult;
+ }
+ NDetail::ThrowMalformedEnumValueException(TEnumTraits<T>::GetTypeName(), value);
+}
+
+template <class T>
+void FormatEnum(TStringBuilderBase* builder, T value, bool lowerCase)
+{
+ static_assert(TEnumTraits<T>::IsEnum);
+
+ auto formatScalarValue = [builder, lowerCase] (T value) {
+ auto* literal = TEnumTraits<T>::FindLiteralByValue(value);
+ if (!literal) {
+ YT_VERIFY(!TEnumTraits<T>::IsBitEnum);
+ NDetail::FormatUnknownEnumValue(
+ builder,
+ TEnumTraits<T>::GetTypeName(),
+ static_cast<typename TEnumTraits<T>::TUnderlying>(value));
+ return;
+ }
+
+ if (lowerCase) {
+ CamelCaseToUnderscoreCase(builder, *literal);
+ } else {
+ builder->AppendString(*literal);
+ }
+ };
+
+ if constexpr (TEnumTraits<T>::IsBitEnum) {
+ if (auto* literal = TEnumTraits<T>::FindLiteralByValue(value)) {
+ formatScalarValue(value);
+ return;
+ }
+ auto first = true;
+ for (auto scalarValue : TEnumTraits<T>::GetDomainValues()) {
+ if (Any(value & scalarValue)) {
+ if (!first) {
+ builder->AppendString(TStringBuf(" | "));
+ }
+ first = false;
+ formatScalarValue(scalarValue);
+ }
+ }
+ } else {
+ formatScalarValue(value);
+ }
+}
+
+template <class T>
+TString FormatEnum(T value, typename TEnumTraits<T>::TType*)
+{
+ TStringBuilder builder;
+ FormatEnum(&builder, value, /*lowerCase*/ true);
+ return builder.Flush();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/string/enum.cpp b/library/cpp/yt/string/enum.cpp
new file mode 100644
index 0000000000..7cb8e5c6b6
--- /dev/null
+++ b/library/cpp/yt/string/enum.cpp
@@ -0,0 +1,44 @@
+#include "enum.h"
+
+#include "format.h"
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TString DecodeEnumValue(TStringBuf value)
+{
+ auto camelValue = UnderscoreCaseToCamelCase(value);
+ auto underscoreValue = CamelCaseToUnderscoreCase(camelValue);
+ if (value != underscoreValue) {
+ throw TSimpleException(Format("Enum value %Qv is not in a proper underscore case; did you mean %Qv?",
+ value,
+ underscoreValue));
+ }
+ return camelValue;
+}
+
+TString EncodeEnumValue(TStringBuf value)
+{
+ return CamelCaseToUnderscoreCase(value);
+}
+
+namespace NDetail {
+
+void ThrowMalformedEnumValueException(TStringBuf typeName, TStringBuf value)
+{
+ throw TSimpleException(Format("Error parsing %v value %Qv",
+ typeName,
+ value));
+}
+
+void FormatUnknownEnumValue(TStringBuilderBase* builder, TStringBuf name, i64 value)
+{
+ builder->AppendFormat("%v(%v)", name, value);
+}
+
+} // namespace NDetail
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/string/enum.h b/library/cpp/yt/string/enum.h
new file mode 100644
index 0000000000..10dc02610f
--- /dev/null
+++ b/library/cpp/yt/string/enum.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "string.h"
+
+#include <library/cpp/yt/misc/enum.h>
+
+#include <optional>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TString DecodeEnumValue(TStringBuf value);
+TString EncodeEnumValue(TStringBuf value);
+
+template <class T>
+T ParseEnum(TStringBuf value);
+
+template <class T>
+void FormatEnum(TStringBuilderBase* builder, T value, bool lowerCase);
+
+template <class T>
+TString FormatEnum(T value, typename TEnumTraits<T>::TType* = nullptr);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define ENUM_INL_H_
+#include "enum-inl.h"
+#undef ENUM_INL_H_
diff --git a/library/cpp/yt/string/format-inl.h b/library/cpp/yt/string/format-inl.h
new file mode 100644
index 0000000000..5484d4a216
--- /dev/null
+++ b/library/cpp/yt/string/format-inl.h
@@ -0,0 +1,744 @@
+#ifndef FORMAT_INL_H_
+#error "Direct inclusion of this file is not allowed, include format.h"
+// For the sake of sane code completion.
+#include "format.h"
+#endif
+
+#include "enum.h"
+#include "string.h"
+
+#include <library/cpp/yt/assert/assert.h>
+
+#include <library/cpp/yt/small_containers/compact_vector.h>
+
+#include <library/cpp/yt/misc/enum.h>
+
+#include <cctype>
+#include <optional>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+static const char GenericSpecSymbol = 'v';
+
+inline bool IsQuotationSpecSymbol(char symbol)
+{
+ return symbol == 'Q' || symbol == 'q';
+}
+
+// TStringBuf
+inline void FormatValue(TStringBuilderBase* builder, TStringBuf value, TStringBuf format)
+{
+ if (!format) {
+ builder->AppendString(value);
+ return;
+ }
+
+ // Parse alignment.
+ bool alignLeft = false;
+ const char* current = format.begin();
+ if (*current == '-') {
+ alignLeft = true;
+ ++current;
+ }
+
+ bool hasAlign = false;
+ int alignSize = 0;
+ while (*current >= '0' && *current <= '9') {
+ hasAlign = true;
+ alignSize = 10 * alignSize + (*current - '0');
+ if (alignSize > 1000000) {
+ builder->AppendString(TStringBuf("<alignment overflow>"));
+ return;
+ }
+ ++current;
+ }
+
+ int padding = 0;
+ bool padLeft = false;
+ bool padRight = false;
+ if (hasAlign) {
+ padding = alignSize - value.size();
+ if (padding < 0) {
+ padding = 0;
+ }
+ padLeft = !alignLeft;
+ padRight = alignLeft;
+ }
+
+ bool singleQuotes = false;
+ bool doubleQuotes = false;
+ while (current < format.end()) {
+ if (*current == 'q') {
+ singleQuotes = true;
+ } else if (*current == 'Q') {
+ doubleQuotes = true;
+ }
+ ++current;
+ }
+
+ if (padLeft) {
+ builder->AppendChar(' ', padding);
+ }
+
+ if (singleQuotes || doubleQuotes) {
+ for (const char* valueCurrent = value.begin(); valueCurrent < value.end(); ++valueCurrent) {
+ char ch = *valueCurrent;
+ if (ch == '\n') {
+ builder->AppendString("\\n");
+ } else if (ch == '\t') {
+ builder->AppendString("\\t");
+ } else if (ch < PrintableASCIILow || ch > PrintableASCIIHigh) {
+ builder->AppendString("\\x");
+ builder->AppendChar(Int2Hex[static_cast<ui8>(ch) >> 4]);
+ builder->AppendChar(Int2Hex[static_cast<ui8>(ch) & 0xf]);
+ } else if ((singleQuotes && ch == '\'') || (doubleQuotes && ch == '\"')) {
+ builder->AppendChar('\\');
+ builder->AppendChar(ch);
+ } else {
+ builder->AppendChar(ch);
+ }
+ }
+ } else {
+ builder->AppendString(value);
+ }
+
+ if (padRight) {
+ builder->AppendChar(' ', padding);
+ }
+}
+
+// TString
+inline void FormatValue(TStringBuilderBase* builder, const TString& value, TStringBuf format)
+{
+ FormatValue(builder, TStringBuf(value), format);
+}
+
+// const char*
+inline void FormatValue(TStringBuilderBase* builder, const char* value, TStringBuf format)
+{
+ FormatValue(builder, TStringBuf(value), format);
+}
+
+// char
+inline void FormatValue(TStringBuilderBase* builder, char value, TStringBuf format)
+{
+ FormatValue(builder, TStringBuf(&value, 1), format);
+}
+
+// bool
+inline void FormatValue(TStringBuilderBase* builder, bool value, TStringBuf format)
+{
+ // Parse custom flags.
+ bool lowercase = false;
+ const char* current = format.begin();
+ while (current != format.end()) {
+ if (*current == 'l') {
+ ++current;
+ lowercase = true;
+ } else if (IsQuotationSpecSymbol(*current)) {
+ ++current;
+ } else
+ break;
+ }
+
+ auto str = lowercase
+ ? (value ? TStringBuf("true") : TStringBuf("false"))
+ : (value ? TStringBuf("True") : TStringBuf("False"));
+
+ builder->AppendString(str);
+}
+
+// Fallback to ToString
+struct TToStringFallbackValueFormatterTag
+{ };
+
+template <class TValue, class = void>
+struct TValueFormatter
+{
+ static TToStringFallbackValueFormatterTag Do(TStringBuilderBase* builder, const TValue& value, TStringBuf format)
+ {
+ using ::ToString;
+ FormatValue(builder, ToString(value), format);
+ return {};
+ }
+};
+
+// Enum
+template <class TEnum>
+struct TValueFormatter<TEnum, typename std::enable_if<TEnumTraits<TEnum>::IsEnum>::type>
+{
+ static void Do(TStringBuilderBase* builder, TEnum value, TStringBuf format)
+ {
+ // Parse custom flags.
+ bool lowercase = false;
+ const char* current = format.begin();
+ while (current != format.end()) {
+ if (*current == 'l') {
+ ++current;
+ lowercase = true;
+ } else if (IsQuotationSpecSymbol(*current)) {
+ ++current;
+ } else {
+ break;
+ }
+ }
+
+ FormatEnum(builder, value, lowercase);
+ }
+};
+
+template <class TRange, class TFormatter>
+typename TFormattableView<TRange, TFormatter>::TBegin TFormattableView<TRange, TFormatter>::begin() const
+{
+ return RangeBegin;
+}
+
+template <class TRange, class TFormatter>
+typename TFormattableView<TRange, TFormatter>::TEnd TFormattableView<TRange, TFormatter>::end() const
+{
+ return RangeEnd;
+}
+
+template <class TRange, class TFormatter>
+TFormattableView<TRange, TFormatter> MakeFormattableView(
+ const TRange& range,
+ TFormatter&& formatter)
+{
+ return TFormattableView<TRange, std::decay_t<TFormatter>>{range.begin(), range.end(), std::forward<TFormatter>(formatter)};
+}
+
+template <class TRange, class TFormatter>
+TFormattableView<TRange, TFormatter> MakeShrunkFormattableView(
+ const TRange& range,
+ TFormatter&& formatter,
+ size_t limit)
+{
+ return TFormattableView<TRange, std::decay_t<TFormatter>>{range.begin(), range.end(), std::forward<TFormatter>(formatter), limit};
+}
+
+template <class TRange, class TFormatter>
+void FormatRange(TStringBuilderBase* builder, const TRange& range, const TFormatter& formatter, size_t limit = std::numeric_limits<size_t>::max())
+{
+ builder->AppendChar('[');
+ size_t index = 0;
+ for (const auto& item : range) {
+ if (index > 0) {
+ builder->AppendString(DefaultJoinToStringDelimiter);
+ }
+ if (index == limit) {
+ builder->AppendString(DefaultRangeEllipsisFormat);
+ break;
+ }
+ formatter(builder, item);
+ ++index;
+ }
+ builder->AppendChar(']');
+}
+
+template <class TRange, class TFormatter>
+void FormatKeyValueRange(TStringBuilderBase* builder, const TRange& range, const TFormatter& formatter, size_t limit = std::numeric_limits<size_t>::max())
+{
+ builder->AppendChar('{');
+ size_t index = 0;
+ for (const auto& item : range) {
+ if (index > 0) {
+ builder->AppendString(DefaultJoinToStringDelimiter);
+ }
+ if (index == limit) {
+ builder->AppendString(DefaultRangeEllipsisFormat);
+ break;
+ }
+ formatter(builder, item.first);
+ builder->AppendString(DefaultKeyValueDelimiter);
+ formatter(builder, item.second);
+ ++index;
+ }
+ builder->AppendChar('}');
+}
+
+// TFormattableView
+template <class TRange, class TFormatter>
+struct TValueFormatter<TFormattableView<TRange, TFormatter>>
+{
+ static void Do(TStringBuilderBase* builder, const TFormattableView<TRange, TFormatter>& range, TStringBuf /*format*/)
+ {
+ FormatRange(builder, range, range.Formatter, range.Limit);
+ }
+};
+
+template <class TFormatter>
+TFormatterWrapper<TFormatter> MakeFormatterWrapper(
+ TFormatter&& formatter)
+{
+ return TFormatterWrapper<TFormatter>{
+ .Formatter = std::move(formatter)
+ };
+}
+
+// TFormatterWrapper
+template <class TFormatter>
+struct TValueFormatter<TFormatterWrapper<TFormatter>>
+{
+ static void Do(TStringBuilderBase* builder, const TFormatterWrapper<TFormatter>& wrapper, TStringBuf /*format*/)
+ {
+ wrapper.Formatter(builder);
+ }
+};
+
+// std::vector
+template <class T, class TAllocator>
+struct TValueFormatter<std::vector<T, TAllocator>>
+{
+ static void Do(TStringBuilderBase* builder, const std::vector<T, TAllocator>& collection, TStringBuf /*format*/)
+ {
+ FormatRange(builder, collection, TDefaultFormatter());
+ }
+};
+
+// TCompactVector
+template <class T, unsigned N>
+struct TValueFormatter<TCompactVector<T, N>>
+{
+ static void Do(TStringBuilderBase* builder, const TCompactVector<T, N>& collection, TStringBuf /*format*/)
+ {
+ FormatRange(builder, collection, TDefaultFormatter());
+ }
+};
+
+// std::set
+template <class T>
+struct TValueFormatter<std::set<T>>
+{
+ static void Do(TStringBuilderBase* builder, const std::set<T>& collection, TStringBuf /*format*/)
+ {
+ FormatRange(builder, collection, TDefaultFormatter());
+ }
+};
+
+// std::map
+template <class K, class V>
+struct TValueFormatter<std::map<K, V>>
+{
+ static void Do(TStringBuilderBase* builder, const std::map<K, V>& collection, TStringBuf /*format*/)
+ {
+ FormatKeyValueRange(builder, collection, TDefaultFormatter());
+ }
+};
+
+// std::multimap
+template <class K, class V>
+struct TValueFormatter<std::multimap<K, V>>
+{
+ static void Do(TStringBuilderBase* builder, const std::multimap<K, V>& collection, TStringBuf /*format*/)
+ {
+ FormatKeyValueRange(builder, collection, TDefaultFormatter());
+ }
+};
+
+// THashSet
+template <class T>
+struct TValueFormatter<THashSet<T>>
+{
+ static void Do(TStringBuilderBase* builder, const THashSet<T>& collection, TStringBuf /*format*/)
+ {
+ FormatRange(builder, collection, TDefaultFormatter());
+ }
+};
+
+// THashMultiSet
+template <class T>
+struct TValueFormatter<THashMultiSet<T>>
+{
+ static void Do(TStringBuilderBase* builder, const THashMultiSet<T>& collection, TStringBuf /*format*/)
+ {
+ FormatRange(builder, collection, TDefaultFormatter());
+ }
+};
+
+// THashMap
+template <class K, class V>
+struct TValueFormatter<THashMap<K, V>>
+{
+ static void Do(TStringBuilderBase* builder, const THashMap<K, V>& collection, TStringBuf /*format*/)
+ {
+ FormatKeyValueRange(builder, collection, TDefaultFormatter());
+ }
+};
+
+// THashMultiMap
+template <class K, class V>
+struct TValueFormatter<THashMultiMap<K, V>>
+{
+ static void Do(TStringBuilderBase* builder, const THashMultiMap<K, V>& collection, TStringBuf /*format*/)
+ {
+ FormatKeyValueRange(builder, collection, TDefaultFormatter());
+ }
+};
+
+// TEnumIndexedVector
+template <class E, class T>
+struct TValueFormatter<TEnumIndexedVector<E, T>>
+{
+ static void Do(TStringBuilderBase* builder, const TEnumIndexedVector<E, T>& collection, TStringBuf format)
+ {
+ builder->AppendChar('{');
+ bool firstItem = true;
+ for (const auto& index : TEnumTraits<E>::GetDomainValues()) {
+ if (!firstItem) {
+ builder->AppendString(DefaultJoinToStringDelimiter);
+ }
+ FormatValue(builder, index, format);
+ builder->AppendString(": ");
+ FormatValue(builder, collection[index], format);
+ firstItem = false;
+ }
+ builder->AppendChar('}');
+ }
+};
+
+// std::pair
+template <class T1, class T2>
+struct TValueFormatter<std::pair<T1, T2>>
+{
+ static void Do(TStringBuilderBase* builder, const std::pair<T1, T2>& value, TStringBuf format)
+ {
+ builder->AppendChar('{');
+ FormatValue(builder, value.first, format);
+ builder->AppendString(TStringBuf(", "));
+ FormatValue(builder, value.second, format);
+ builder->AppendChar('}');
+ }
+};
+
+// std::optional
+inline void FormatValue(TStringBuilderBase* builder, std::nullopt_t, TStringBuf /*format*/)
+{
+ builder->AppendString(TStringBuf("<null>"));
+}
+
+template <class T>
+struct TValueFormatter<std::optional<T>>
+{
+ static void Do(TStringBuilderBase* builder, const std::optional<T>& value, TStringBuf format)
+ {
+ if (value) {
+ FormatValue(builder, *value, format);
+ } else {
+ FormatValue(builder, std::nullopt, format);
+ }
+ }
+};
+
+template <class TValue>
+auto FormatValue(TStringBuilderBase* builder, const TValue& value, TStringBuf format) ->
+ decltype(TValueFormatter<TValue>::Do(builder, value, format))
+{
+ return TValueFormatter<TValue>::Do(builder, value, format);
+}
+
+template <class TValue>
+void FormatValueViaSprintf(
+ TStringBuilderBase* builder,
+ TValue value,
+ TStringBuf format,
+ TStringBuf genericSpec)
+{
+ constexpr int MaxFormatSize = 64;
+ constexpr int SmallResultSize = 64;
+
+ auto copyFormat = [] (char* destination, const char* source, int length) {
+ int position = 0;
+ for (int index = 0; index < length; ++index) {
+ if (IsQuotationSpecSymbol(source[index])) {
+ continue;
+ }
+ destination[position] = source[index];
+ ++position;
+ }
+ return destination + position;
+ };
+
+ char formatBuf[MaxFormatSize];
+ YT_VERIFY(format.length() >= 1 && format.length() <= MaxFormatSize - 2); // one for %, one for \0
+ formatBuf[0] = '%';
+ if (format[format.length() - 1] == GenericSpecSymbol) {
+ char* formatEnd = copyFormat(formatBuf + 1, format.begin(), format.length() - 1);
+ ::memcpy(formatEnd, genericSpec.begin(), genericSpec.length());
+ formatEnd[genericSpec.length()] = '\0';
+ } else {
+ char* formatEnd = copyFormat(formatBuf + 1, format.begin(), format.length());
+ *formatEnd = '\0';
+ }
+
+ char* result = builder->Preallocate(SmallResultSize);
+ size_t resultSize = ::snprintf(result, SmallResultSize, formatBuf, value);
+ if (resultSize >= SmallResultSize) {
+ result = builder->Preallocate(resultSize + 1);
+ YT_VERIFY(::snprintf(result, resultSize + 1, formatBuf, value) == static_cast<int>(resultSize));
+ }
+ builder->Advance(resultSize);
+}
+
+template <class TValue>
+char* WriteIntToBufferBackwards(char* buffer, TValue value);
+
+template <class TValue>
+void FormatValueViaHelper(TStringBuilderBase* builder, TValue value, TStringBuf format, TStringBuf genericSpec)
+{
+ if (format == TStringBuf("v")) {
+ const int MaxResultSize = 64;
+ char buffer[MaxResultSize];
+ char* end = buffer + MaxResultSize;
+ char* start = WriteIntToBufferBackwards(end, value);
+ builder->AppendString(TStringBuf(start, end));
+ } else {
+ FormatValueViaSprintf(builder, value, format, genericSpec);
+ }
+}
+
+#define XX(valueType, castType, genericSpec) \
+ inline void FormatValue(TStringBuilderBase* builder, valueType value, TStringBuf format) \
+ { \
+ FormatValueViaHelper(builder, static_cast<castType>(value), format, genericSpec); \
+ }
+
+XX(i8, int, TStringBuf("d"))
+XX(ui8, unsigned int, TStringBuf("u"))
+XX(i16, int, TStringBuf("d"))
+XX(ui16, unsigned int, TStringBuf("u"))
+XX(i32, int, TStringBuf("d"))
+XX(ui32, unsigned int, TStringBuf("u"))
+XX(long, long, TStringBuf("ld"))
+XX(unsigned long, unsigned long, TStringBuf("lu"))
+
+#undef XX
+
+#define XX(valueType, castType, genericSpec) \
+ inline void FormatValue(TStringBuilderBase* builder, valueType value, TStringBuf format) \
+ { \
+ FormatValueViaSprintf(builder, static_cast<castType>(value), format, genericSpec); \
+ }
+
+XX(double, double, TStringBuf("lf"))
+XX(float, float, TStringBuf("f"))
+
+#undef XX
+
+// Pointer
+template <class T>
+void FormatValue(TStringBuilderBase* builder, T* value, TStringBuf format)
+{
+ FormatValueViaSprintf(builder, value, format, TStringBuf("p"));
+}
+
+// TDuration (specialize for performance reasons)
+inline void FormatValue(TStringBuilderBase* builder, TDuration value, TStringBuf /*format*/)
+{
+ builder->AppendFormat("%vus", value.MicroSeconds());
+}
+
+// TInstant (specialize for TFormatTraits)
+inline void FormatValue(TStringBuilderBase* builder, TInstant value, TStringBuf format)
+{
+ // TODO(babenko): optimize
+ builder->AppendFormat("%v", ToString(value), format);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TArgFormatter>
+void FormatImpl(
+ TStringBuilderBase* builder,
+ TStringBuf format,
+ const TArgFormatter& argFormatter)
+{
+ size_t argIndex = 0;
+ auto current = format.begin();
+ while (true) {
+ // Scan verbatim part until stop symbol.
+ auto verbatimBegin = current;
+ auto verbatimEnd = verbatimBegin;
+ while (verbatimEnd != format.end() && *verbatimEnd != '%') {
+ ++verbatimEnd;
+ }
+
+ // Copy verbatim part, if any.
+ size_t verbatimSize = verbatimEnd - verbatimBegin;
+ if (verbatimSize > 0) {
+ builder->AppendString(TStringBuf(verbatimBegin, verbatimSize));
+ }
+
+ // Handle stop symbol.
+ current = verbatimEnd;
+ if (current == format.end()) {
+ break;
+ }
+
+ YT_ASSERT(*current == '%');
+ ++current;
+
+ if (*current == '%') {
+ // Verbatim %.
+ builder->AppendChar('%');
+ ++current;
+ } else {
+ // Scan format part until stop symbol.
+ auto argFormatBegin = current;
+ auto argFormatEnd = argFormatBegin;
+ bool singleQuotes = false;
+ bool doubleQuotes = false;
+
+ while (
+ argFormatEnd != format.end() &&
+ *argFormatEnd != GenericSpecSymbol && // value in generic format
+ *argFormatEnd != 'd' && // others are standard specifiers supported by printf
+ *argFormatEnd != 'i' &&
+ *argFormatEnd != 'u' &&
+ *argFormatEnd != 'o' &&
+ *argFormatEnd != 'x' &&
+ *argFormatEnd != 'X' &&
+ *argFormatEnd != 'f' &&
+ *argFormatEnd != 'F' &&
+ *argFormatEnd != 'e' &&
+ *argFormatEnd != 'E' &&
+ *argFormatEnd != 'g' &&
+ *argFormatEnd != 'G' &&
+ *argFormatEnd != 'a' &&
+ *argFormatEnd != 'A' &&
+ *argFormatEnd != 'c' &&
+ *argFormatEnd != 's' &&
+ *argFormatEnd != 'p' &&
+ *argFormatEnd != 'n')
+ {
+ if (*argFormatEnd == 'q') {
+ singleQuotes = true;
+ } else if (*argFormatEnd == 'Q') {
+ doubleQuotes = true;
+ }
+ ++argFormatEnd;
+ }
+
+ // Handle end of format string.
+ if (argFormatEnd != format.end()) {
+ ++argFormatEnd;
+ }
+
+ // 'n' means 'nothing'; skip the argument.
+ if (*argFormatBegin != 'n') {
+ // Format argument.
+ TStringBuf argFormat(argFormatBegin, argFormatEnd);
+ if (singleQuotes) {
+ builder->AppendChar('\'');
+ }
+ if (doubleQuotes) {
+ builder->AppendChar('"');
+ }
+ argFormatter(argIndex++, builder, argFormat);
+ if (singleQuotes) {
+ builder->AppendChar('\'');
+ }
+ if (doubleQuotes) {
+ builder->AppendChar('"');
+ }
+ }
+
+ current = argFormatEnd;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+struct TFormatTraits
+{
+ static constexpr bool HasCustomFormatValue = !std::is_same_v<
+ decltype(FormatValue(
+ static_cast<TStringBuilderBase*>(nullptr),
+ *static_cast<const T*>(nullptr),
+ TStringBuf())),
+ TToStringFallbackValueFormatterTag>;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <size_t IndexBase, class... TArgs>
+struct TArgFormatterImpl;
+
+template <size_t IndexBase>
+struct TArgFormatterImpl<IndexBase>
+{
+ void operator() (size_t /*index*/, TStringBuilderBase* builder, TStringBuf /*format*/) const
+ {
+ builder->AppendString(TStringBuf("<missing argument>"));
+ }
+};
+
+template <size_t IndexBase, class THeadArg, class... TTailArgs>
+struct TArgFormatterImpl<IndexBase, THeadArg, TTailArgs...>
+{
+ explicit TArgFormatterImpl(const THeadArg& headArg, const TTailArgs&... tailArgs)
+ : HeadArg(headArg)
+ , TailFormatter(tailArgs...)
+ { }
+
+ const THeadArg& HeadArg;
+ TArgFormatterImpl<IndexBase + 1, TTailArgs...> TailFormatter;
+
+ void operator() (size_t index, TStringBuilderBase* builder, TStringBuf format) const
+ {
+ YT_ASSERT(index >= IndexBase);
+ if (index == IndexBase) {
+ FormatValue(builder, HeadArg, format);
+ } else {
+ TailFormatter(index, builder, format);
+ }
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <size_t Length, class... TArgs>
+void Format(
+ TStringBuilderBase* builder,
+ const char (&format)[Length],
+ TArgs&&... args)
+{
+ Format(builder, TStringBuf(format, Length - 1), std::forward<TArgs>(args)...);
+}
+
+template <class... TArgs>
+void Format(
+ TStringBuilderBase* builder,
+ TStringBuf format,
+ TArgs&&... args)
+{
+ TArgFormatterImpl<0, TArgs...> argFormatter(args...);
+ FormatImpl(builder, format, argFormatter);
+}
+
+template <size_t Length, class... TArgs>
+TString Format(
+ const char (&format)[Length],
+ TArgs&&... args)
+{
+ TStringBuilder builder;
+ Format(&builder, format, std::forward<TArgs>(args)...);
+ return builder.Flush();
+}
+
+template <class... TArgs>
+TString Format(
+ TStringBuf format,
+ TArgs&&... args)
+{
+ TStringBuilder builder;
+ Format(&builder, format, std::forward<TArgs>(args)...);
+ return builder.Flush();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/string/format.h b/library/cpp/yt/string/format.h
new file mode 100644
index 0000000000..9708fe5906
--- /dev/null
+++ b/library/cpp/yt/string/format.h
@@ -0,0 +1,114 @@
+#pragma once
+
+#include "string_builder.h"
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Format: a type-safe and fast formatting utility.
+ *
+ * Basically works as a type-safe analogue of |sprintf| and is expected to
+ * be backwards-compatible with the latter.
+ *
+ * Like Go's |Sprintf|, supports the ultimate format specifier |v|
+ * causing arguments to be emitted in default format.
+ * This is the default and preferred way of formatting things,
+ * which should be used in newer code.
+ *
+ * |Format| may currently invoke |sprintf| internally for emitting numeric and some other
+ * types. You can always write your own optimized implementation, if you wish :)
+ *
+ * In additional to the usual |sprintf|, supports a number of non-standard flags:
+ *
+ * |q| Causes the argument to be surrounded with single quotes (|'|).
+ * Applies to all types.
+ *
+ * |Q| Causes the argument to be surrounded with double quotes (|"|).
+ * Applies to all types.
+ *
+ * |l| The argument is emitted in "lowercase" style.
+ * Only applies to enums and bools.
+ *
+ * The following argument types are supported:
+ *
+ * Strings (including |const char*|, |TStringBuf|, and |TString|) and chars:
+ * Emitted as is. Fast.
+ *
+ * Numerics and pointers:
+ * Emitted using |sprintf|. Maybe not that fast.
+ *
+ * |bool|:
+ * Emitted either as |True| and |False| or |true| and |false| (if lowercase mode is ON).
+ *
+ * Enums:
+ * Emitted in either camel (|SomeName|) or in lowercase-with-underscores style
+ * (|some_name|, if lowercase mode is ON).
+ *
+ * Nullables:
+ * |std::nullopt| is emitted as |<null>|.
+ *
+ * All others:
+ * Emitted as strings by calling |ToString|.
+ *
+ */
+
+template <size_t Length, class... TArgs>
+void Format(TStringBuilderBase* builder, const char (&format)[Length], TArgs&&... args);
+template <class... TArgs>
+void Format(TStringBuilderBase* builder, TStringBuf format, TArgs&&... args);
+
+template <size_t Length, class... TArgs>
+TString Format(const char (&format)[Length], TArgs&&... args);
+template <class... TArgs>
+TString Format(TStringBuf format, TArgs&&... args);
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TRange, class TFormatter>
+struct TFormattableView
+{
+ using TBegin = std::decay_t<decltype(std::declval<const TRange>().begin())>;
+ using TEnd = std::decay_t<decltype(std::declval<const TRange>().end())>;
+
+ TBegin RangeBegin;
+ TEnd RangeEnd;
+ TFormatter Formatter;
+ size_t Limit = std::numeric_limits<size_t>::max();
+
+ TBegin begin() const;
+ TEnd end() const;
+};
+
+//! Annotates a given #range with #formatter to be applied to each item.
+template <class TRange, class TFormatter>
+TFormattableView<TRange, TFormatter> MakeFormattableView(
+ const TRange& range,
+ TFormatter&& formatter);
+
+template <class TRange, class TFormatter>
+TFormattableView<TRange, TFormatter> MakeShrunkFormattableView(
+ const TRange& range,
+ TFormatter&& formatter,
+ size_t limit);
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class TFormatter>
+struct TFormatterWrapper
+{
+ TFormatter Formatter;
+};
+
+template <class TFormatter>
+TFormatterWrapper<TFormatter> MakeFormatterWrapper(
+ TFormatter&& formatter);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define FORMAT_INL_H_
+#include "format-inl.h"
+#undef FORMAT_INL_H_
diff --git a/library/cpp/yt/string/guid.cpp b/library/cpp/yt/string/guid.cpp
new file mode 100644
index 0000000000..6c133a9778
--- /dev/null
+++ b/library/cpp/yt/string/guid.cpp
@@ -0,0 +1,22 @@
+#include "guid.h"
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+void FormatValue(TStringBuilderBase* builder, TGuid value, TStringBuf /*format*/)
+{
+ char* begin = builder->Preallocate(MaxGuidStringSize);
+ char* end = WriteGuidToBuffer(begin, value);
+ builder->Advance(end - begin);
+}
+
+TString ToString(TGuid guid)
+{
+ return ToStringViaBuilder(guid);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
diff --git a/library/cpp/yt/string/guid.h b/library/cpp/yt/string/guid.h
new file mode 100644
index 0000000000..75edbce5db
--- /dev/null
+++ b/library/cpp/yt/string/guid.h
@@ -0,0 +1,14 @@
+#include <library/cpp/yt/misc/guid.h>
+
+#include "format.h"
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+void FormatValue(TStringBuilderBase* builder, TGuid value, TStringBuf /*format*/);
+TString ToString(TGuid guid);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/string/string.cpp b/library/cpp/yt/string/string.cpp
new file mode 100644
index 0000000000..7440ac3fdd
--- /dev/null
+++ b/library/cpp/yt/string/string.cpp
@@ -0,0 +1,272 @@
+#include "string.h"
+#include "format.h"
+
+#include <library/cpp/yt/assert/assert.h>
+
+#include <util/generic/hash.h>
+
+#include <util/string/ascii.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+void UnderscoreCaseToCamelCase(TStringBuilderBase* builder, TStringBuf str)
+{
+ bool first = true;
+ bool upper = true;
+ for (char c : str) {
+ if (c == '_') {
+ upper = true;
+ } else {
+ if (upper) {
+ if (!std::isalpha(c) && !first) {
+ builder->AppendChar('_');
+ }
+ c = std::toupper(c);
+ }
+ builder->AppendChar(c);
+ upper = false;
+ }
+ first = false;
+ }
+}
+
+TString UnderscoreCaseToCamelCase(TStringBuf str)
+{
+ TStringBuilder builder;
+ UnderscoreCaseToCamelCase(&builder, str);
+ return builder.Flush();
+}
+
+void CamelCaseToUnderscoreCase(TStringBuilderBase* builder, TStringBuf str)
+{
+ bool first = true;
+ for (char c : str) {
+ if (std::isupper(c) && std::isalpha(c)) {
+ if (!first) {
+ builder->AppendChar('_');
+ }
+ c = std::tolower(c);
+ }
+ builder->AppendChar(c);
+ first = false;
+ }
+}
+
+TString CamelCaseToUnderscoreCase(TStringBuf str)
+{
+ TStringBuilder builder;
+ CamelCaseToUnderscoreCase(&builder, str);
+ return builder.Flush();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+TString TrimLeadingWhitespaces(const TString& str)
+{
+ for (int i = 0; i < static_cast<int>(str.size()); ++i) {
+ if (str[i] != ' ') {
+ return str.substr(i);
+ }
+ }
+ return "";
+}
+
+TString Trim(const TString& str, const TString& whitespaces)
+{
+ size_t end = str.size();
+ while (end > 0) {
+ size_t i = end - 1;
+ bool isWhitespace = false;
+ for (auto c : whitespaces) {
+ if (str[i] == c) {
+ isWhitespace = true;
+ break;
+ }
+ }
+ if (!isWhitespace) {
+ break;
+ }
+ --end;
+ }
+
+ if (end == 0) {
+ return "";
+ }
+
+ size_t begin = str.find_first_not_of(whitespaces);
+ YT_VERIFY(begin != TString::npos);
+ YT_VERIFY(begin < end);
+ return str.substr(begin, end - begin);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+ui16 DecimalDigits2[100] = {
+ 12336, 12592, 12848, 13104, 13360, 13616, 13872, 14128, 14384, 14640,
+ 12337, 12593, 12849, 13105, 13361, 13617, 13873, 14129, 14385, 14641,
+ 12338, 12594, 12850, 13106, 13362, 13618, 13874, 14130, 14386, 14642,
+ 12339, 12595, 12851, 13107, 13363, 13619, 13875, 14131, 14387, 14643,
+ 12340, 12596, 12852, 13108, 13364, 13620, 13876, 14132, 14388, 14644,
+ 12341, 12597, 12853, 13109, 13365, 13621, 13877, 14133, 14389, 14645,
+ 12342, 12598, 12854, 13110, 13366, 13622, 13878, 14134, 14390, 14646,
+ 12343, 12599, 12855, 13111, 13367, 13623, 13879, 14135, 14391, 14647,
+ 12344, 12600, 12856, 13112, 13368, 13624, 13880, 14136, 14392, 14648,
+ 12345, 12601, 12857, 13113, 13369, 13625, 13881, 14137, 14393, 14649
+};
+
+template <class T>
+char* WriteSignedIntToBufferBackwardsImpl(char* ptr, T value, TStringBuf min)
+{
+ if (value == 0) {
+ --ptr;
+ *ptr = '0';
+ return ptr;
+ }
+
+ // The negative value handling code below works incorrectly for min values.
+ if (value == std::numeric_limits<T>::min()) {
+ ptr -= min.length();
+ ::memcpy(ptr, min.begin(), min.length());
+ return ptr;
+ }
+
+ bool negative = false;
+ if (value < 0) {
+ negative = true;
+ value = -value;
+ }
+
+ while (value >= 10) {
+ i64 rem = value % 100;
+ i64 quot = value / 100;
+ ptr -= 2;
+ ::memcpy(ptr, &DecimalDigits2[rem], 2);
+ value = quot;
+ }
+
+ if (value > 0) {
+ --ptr;
+ *ptr = ('0' + value);
+ }
+
+ if (negative) {
+ --ptr;
+ *ptr = '-';
+ }
+
+ return ptr;
+}
+
+template <class T>
+char* WriteUnsignedIntToBufferBackwardsImpl(char* ptr, T value)
+{
+ if (value == 0) {
+ --ptr;
+ *ptr = '0';
+ return ptr;
+ }
+
+ while (value >= 10) {
+ i64 rem = value % 100;
+ i64 quot = value / 100;
+ ptr -= 2;
+ ::memcpy(ptr, &DecimalDigits2[rem], 2);
+ value = quot;
+ }
+
+ if (value > 0) {
+ --ptr;
+ *ptr = ('0' + value);
+ }
+
+ return ptr;
+}
+
+} // namespace
+
+template <>
+char* WriteIntToBufferBackwards(char* ptr, i32 value)
+{
+ return WriteSignedIntToBufferBackwardsImpl(ptr, value, TStringBuf("-2147483647"));
+}
+
+template <>
+char* WriteIntToBufferBackwards(char* ptr, i64 value)
+{
+ return WriteSignedIntToBufferBackwardsImpl(ptr, value, TStringBuf("-9223372036854775808"));
+}
+
+template <>
+char* WriteIntToBufferBackwards(char* ptr, ui32 value)
+{
+ return WriteUnsignedIntToBufferBackwardsImpl(ptr, value);
+}
+
+template <>
+char* WriteIntToBufferBackwards(char* ptr, ui64 value)
+{
+ return WriteUnsignedIntToBufferBackwardsImpl(ptr, value);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+size_t TCaseInsensitiveStringHasher::operator()(TStringBuf arg) const
+{
+ auto compute = [&] (char* buffer) {
+ for (size_t index = 0; index < arg.length(); ++index) {
+ buffer[index] = AsciiToLower(arg[index]);
+ }
+ return ComputeHash(TStringBuf(buffer, arg.length()));
+ };
+ const size_t SmallSize = 256;
+ if (arg.length() <= SmallSize) {
+ std::array<char, SmallSize> stackBuffer;
+ return compute(stackBuffer.data());
+ } else {
+ std::unique_ptr<char[]> heapBuffer(new char[arg.length()]);
+ return compute(heapBuffer.get());
+ }
+}
+
+bool TCaseInsensitiveStringEqualityComparer::operator()(TStringBuf lhs, TStringBuf rhs) const
+{
+ return AsciiEqualsIgnoreCase(lhs, rhs);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool TryParseBool(TStringBuf value, bool* result)
+{
+ if (value == "true" || value == "1") {
+ *result = true;
+ return true;
+ } else if (value == "false" || value == "0") {
+ *result = false;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool ParseBool(TStringBuf value)
+{
+ bool result;
+ if (!TryParseBool(value, &result)) {
+ throw TSimpleException(Format("Error parsing boolean value %Qv",
+ value));
+ }
+ return result;
+}
+
+TStringBuf FormatBool(bool value)
+{
+ return value ? TStringBuf("true") : TStringBuf("false");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/string/string.h b/library/cpp/yt/string/string.h
new file mode 100644
index 0000000000..ae6c99caab
--- /dev/null
+++ b/library/cpp/yt/string/string.h
@@ -0,0 +1,221 @@
+#pragma once
+
+#include "string_builder.h"
+
+#include <library/cpp/yt/exception/exception.h>
+
+#include <util/datetime/base.h>
+
+#include <util/generic/string.h>
+
+#include <util/string/strip.h>
+
+#include <vector>
+#include <set>
+#include <map>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Formatters enable customizable way to turn an object into a string.
+//! This default implementation uses |FormatValue|.
+struct TDefaultFormatter
+{
+ template <class T>
+ void operator()(TStringBuilderBase* builder, const T& obj) const
+ {
+ FormatValue(builder, obj, TStringBuf("v"));
+ }
+};
+
+static constexpr TStringBuf DefaultJoinToStringDelimiter = ", ";
+static constexpr TStringBuf DefaultKeyValueDelimiter = ": ";
+static constexpr TStringBuf DefaultRangeEllipsisFormat = "...";
+
+// ASCII characters from 0x20 = ' ' to 0x7e = '~' are printable.
+static constexpr char PrintableASCIILow = 0x20;
+static constexpr char PrintableASCIIHigh = 0x7e;
+static constexpr TStringBuf Int2Hex = "0123456789abcdef";
+
+//! Joins a range of items into a string intermixing them with the delimiter.
+/*!
+ * \param builder String builder where the output goes.
+ * \param begin Iterator pointing to the first item (inclusive).
+ * \param end Iterator pointing to the last item (not inclusive).
+ * \param formatter Formatter to apply to the items.
+ * \param delimiter A delimiter to be inserted between items: ", " by default.
+ * \return The resulting combined string.
+ */
+template <class TIterator, class TFormatter>
+void JoinToString(
+ TStringBuilderBase* builder,
+ const TIterator& begin,
+ const TIterator& end,
+ const TFormatter& formatter,
+ TStringBuf delimiter = DefaultJoinToStringDelimiter)
+{
+ for (auto current = begin; current != end; ++current) {
+ if (current != begin) {
+ builder->AppendString(delimiter);
+ }
+ formatter(builder, *current);
+ }
+}
+
+template <class TIterator, class TFormatter>
+TString JoinToString(
+ const TIterator& begin,
+ const TIterator& end,
+ const TFormatter& formatter,
+ TStringBuf delimiter = DefaultJoinToStringDelimiter)
+{
+ TStringBuilder builder;
+ JoinToString(&builder, begin, end, formatter, delimiter);
+ return builder.Flush();
+}
+
+//! A handy shortcut with default formatter.
+template <class TIterator>
+TString JoinToString(
+ const TIterator& begin,
+ const TIterator& end,
+ TStringBuf delimiter = DefaultJoinToStringDelimiter)
+{
+ return JoinToString(begin, end, TDefaultFormatter(), delimiter);
+}
+
+//! Joins a collection of given items into a string intermixing them with the delimiter.
+/*!
+ * \param collection A collection containing the items to be joined.
+ * \param formatter Formatter to apply to the items.
+ * \param delimiter A delimiter to be inserted between items; ", " by default.
+ */
+template <class TCollection, class TFormatter>
+TString JoinToString(
+ const TCollection& collection,
+ const TFormatter& formatter,
+ TStringBuf delimiter = DefaultJoinToStringDelimiter)
+{
+ using std::begin;
+ using std::end;
+ return JoinToString(begin(collection), end(collection), formatter, delimiter);
+}
+
+//! A handy shortcut with the default formatter.
+template <class TCollection>
+TString JoinToString(
+ const TCollection& collection,
+ TStringBuf delimiter = DefaultJoinToStringDelimiter)
+{
+ return JoinToString(collection, TDefaultFormatter(), delimiter);
+}
+
+//! Concatenates a bunch of TStringBuf-like instances into TString.
+template <class... Ts>
+TString ConcatToString(Ts... args)
+{
+ size_t length = 0;
+ ((length += args.length()), ...);
+
+ TString result;
+ result.reserve(length);
+ (result.append(args), ...);
+
+ return result;
+}
+
+//! Converts a range of items into strings.
+template <class TIter, class TFormatter>
+std::vector<TString> ConvertToStrings(
+ const TIter& begin,
+ const TIter& end,
+ const TFormatter& formatter,
+ size_t maxSize = std::numeric_limits<size_t>::max())
+{
+ std::vector<TString> result;
+ for (auto it = begin; it != end; ++it) {
+ TStringBuilder builder;
+ formatter(&builder, *it);
+ result.push_back(builder.Flush());
+ if (result.size() == maxSize) {
+ break;
+ }
+ }
+ return result;
+}
+
+//! A handy shortcut with the default formatter.
+template <class TIter>
+std::vector<TString> ConvertToStrings(
+ const TIter& begin,
+ const TIter& end,
+ size_t maxSize = std::numeric_limits<size_t>::max())
+{
+ return ConvertToStrings(begin, end, TDefaultFormatter(), maxSize);
+}
+
+//! Converts a given collection of items into strings.
+/*!
+ * \param collection A collection containing the items to be converted.
+ * \param formatter Formatter to apply to the items.
+ * \param maxSize Size limit for the resulting vector.
+ */
+template <class TCollection, class TFormatter>
+std::vector<TString> ConvertToStrings(
+ const TCollection& collection,
+ const TFormatter& formatter,
+ size_t maxSize = std::numeric_limits<size_t>::max())
+{
+ using std::begin;
+ using std::end;
+ return ConvertToStrings(begin(collection), end(collection), formatter, maxSize);
+}
+
+//! A handy shortcut with default formatter.
+template <class TCollection>
+std::vector<TString> ConvertToStrings(
+ const TCollection& collection,
+ size_t maxSize = std::numeric_limits<size_t>::max())
+{
+ return ConvertToStrings(collection, TDefaultFormatter(), maxSize);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void UnderscoreCaseToCamelCase(TStringBuilderBase* builder, TStringBuf str);
+TString UnderscoreCaseToCamelCase(TStringBuf str);
+
+void CamelCaseToUnderscoreCase(TStringBuilderBase* builder, TStringBuf str);
+TString CamelCaseToUnderscoreCase(TStringBuf str);
+
+TString TrimLeadingWhitespaces(const TString& str);
+TString Trim(const TString& str, const TString& whitespaces);
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Implemented for |[u]i(32|64)|.
+template <class T>
+char* WriteIntToBufferBackwards(char* ptr, T value);
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct TCaseInsensitiveStringHasher
+{
+ size_t operator()(TStringBuf arg) const;
+};
+
+struct TCaseInsensitiveStringEqualityComparer
+{
+ bool operator()(TStringBuf lhs, TStringBuf rhs) const;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool TryParseBool(TStringBuf value, bool* result);
+bool ParseBool(TStringBuf value);
+TStringBuf FormatBool(bool value);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/string/string_builder-inl.h b/library/cpp/yt/string/string_builder-inl.h
new file mode 100644
index 0000000000..151fcabf7f
--- /dev/null
+++ b/library/cpp/yt/string/string_builder-inl.h
@@ -0,0 +1,129 @@
+#ifndef STRING_BUILDER_INL_H_
+#error "Direct inclusion of this file is not allowed, include string.h"
+// For the sake of sane code completion.
+#include "string_builder.h"
+#endif
+
+#include <library/cpp/yt/assert/assert.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+inline char* TStringBuilderBase::Preallocate(size_t size)
+{
+ if (Y_UNLIKELY(End_ - Current_ < static_cast<ssize_t>(size))) {
+ size_t length = GetLength();
+ auto newLength = std::max(length + size, MinBufferLength);
+ DoPreallocate(newLength);
+ Current_ = Begin_ + length;
+ }
+ return Current_;
+}
+
+inline size_t TStringBuilderBase::GetLength() const
+{
+ return Current_ ? Current_ - Begin_ : 0;
+}
+
+inline TStringBuf TStringBuilderBase::GetBuffer() const
+{
+ return TStringBuf(Begin_, Current_);
+}
+
+inline void TStringBuilderBase::Advance(size_t size)
+{
+ Current_ += size;
+ YT_ASSERT(Current_ <= End_);
+}
+
+inline void TStringBuilderBase::AppendChar(char ch)
+{
+ *Preallocate(1) = ch;
+ Advance(1);
+}
+
+inline void TStringBuilderBase::AppendChar(char ch, int n)
+{
+ YT_ASSERT(n >= 0);
+ if (Y_LIKELY(0 != n)) {
+ char* dst = Preallocate(n);
+ ::memset(dst, ch, n);
+ Advance(n);
+ }
+}
+
+inline void TStringBuilderBase::AppendString(TStringBuf str)
+{
+ if (Y_LIKELY(str)) {
+ char* dst = Preallocate(str.length());
+ ::memcpy(dst, str.begin(), str.length());
+ Advance(str.length());
+ }
+}
+
+inline void TStringBuilderBase::AppendString(const char* str)
+{
+ AppendString(TStringBuf(str));
+}
+
+inline void TStringBuilderBase::Reset()
+{
+ Begin_ = Current_ = End_ = nullptr;
+ DoReset();
+}
+
+template <class... TArgs>
+void TStringBuilderBase::AppendFormat(TStringBuf format, TArgs&& ... args)
+{
+ Format(this, format, std::forward<TArgs>(args)...);
+}
+
+template <size_t Length, class... TArgs>
+void TStringBuilderBase::AppendFormat(const char (&format)[Length], TArgs&& ... args)
+{
+ Format(this, format, std::forward<TArgs>(args)...);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+inline TString TStringBuilder::Flush()
+{
+ Buffer_.resize(GetLength());
+ auto result = std::move(Buffer_);
+ Reset();
+ return result;
+}
+
+inline void TStringBuilder::DoReset()
+{
+ Buffer_ = {};
+}
+
+inline void TStringBuilder::DoPreallocate(size_t newLength)
+{
+ Buffer_.ReserveAndResize(newLength);
+ auto capacity = Buffer_.capacity();
+ Buffer_.ReserveAndResize(capacity);
+ Begin_ = &*Buffer_.begin();
+ End_ = Begin_ + capacity;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+inline void FormatValue(TStringBuilderBase* builder, const TStringBuilder& value, TStringBuf /*format*/)
+{
+ builder->AppendString(value.GetBuffer());
+}
+
+template <class T>
+TString ToStringViaBuilder(const T& value, TStringBuf spec)
+{
+ TStringBuilder builder;
+ FormatValue(&builder, value, spec);
+ return builder.Flush();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
diff --git a/library/cpp/yt/string/string_builder.h b/library/cpp/yt/string/string_builder.h
new file mode 100644
index 0000000000..0e13e70904
--- /dev/null
+++ b/library/cpp/yt/string/string_builder.h
@@ -0,0 +1,116 @@
+#pragma once
+
+#include <util/generic/string.h>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Forward declarations.
+class TStringBuilderBase;
+class TStringBuilder;
+class TDelimitedStringBuilderWrapper;
+
+template <size_t Length, class... TArgs>
+void Format(TStringBuilderBase* builder, const char (&format)[Length], TArgs&&... args);
+template <class... TArgs>
+void Format(TStringBuilderBase* builder, TStringBuf format, TArgs&&... args);
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! A simple helper for constructing strings by a sequence of appends.
+class TStringBuilderBase
+{
+public:
+ virtual ~TStringBuilderBase() = default;
+
+ char* Preallocate(size_t size);
+
+ size_t GetLength() const;
+
+ TStringBuf GetBuffer() const;
+
+ void Advance(size_t size);
+
+ void AppendChar(char ch);
+ void AppendChar(char ch, int n);
+
+ void AppendString(TStringBuf str);
+ void AppendString(const char* str);
+
+ template <size_t Length, class... TArgs>
+ void AppendFormat(const char (&format)[Length], TArgs&&... args);
+ template <class... TArgs>
+ void AppendFormat(TStringBuf format, TArgs&&... args);
+
+ void Reset();
+
+protected:
+ char* Begin_ = nullptr;
+ char* Current_ = nullptr;
+ char* End_ = nullptr;
+
+ virtual void DoReset() = 0;
+ virtual void DoPreallocate(size_t newLength) = 0;
+
+ // -64 must account for any reasonable overhead in dynamic string allocation.
+ static constexpr size_t MinBufferLength = 1024 - 64;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TStringBuilder
+ : public TStringBuilderBase
+{
+public:
+ TString Flush();
+
+protected:
+ TString Buffer_;
+
+ void DoReset() override;
+ void DoPreallocate(size_t size) override;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+TString ToStringViaBuilder(const T& value, TStringBuf spec = TStringBuf("v"));
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Appends a certain delimiter starting from the second call.
+class TDelimitedStringBuilderWrapper
+ : private TNonCopyable
+{
+public:
+ TDelimitedStringBuilderWrapper(
+ TStringBuilderBase* builder,
+ TStringBuf delimiter = TStringBuf(", "))
+ : Builder_(builder)
+ , Delimiter_(delimiter)
+ { }
+
+ TStringBuilderBase* operator->()
+ {
+ if (!FirstCall_) {
+ Builder_->AppendString(Delimiter_);
+ }
+ FirstCall_ = false;
+ return Builder_;
+ }
+
+private:
+ TStringBuilderBase* const Builder_;
+ const TStringBuf Delimiter_;
+
+ bool FirstCall_ = true;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define STRING_BUILDER_INL_H_
+#include "string_builder-inl.h"
+#undef STRING_BUILDER_INL_H_
diff --git a/library/cpp/yt/string/unittests/enum_ut.cpp b/library/cpp/yt/string/unittests/enum_ut.cpp
new file mode 100644
index 0000000000..b8076fd8ee
--- /dev/null
+++ b/library/cpp/yt/string/unittests/enum_ut.cpp
@@ -0,0 +1,61 @@
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <library/cpp/yt/string/enum.h>
+#include <library/cpp/yt/string/format.h>
+
+#include <limits>
+
+namespace NYT {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Some compile-time sanity checks.
+DEFINE_ENUM(ESample, (One)(Two));
+static_assert(TFormatTraits<ESample>::HasCustomFormatValue);
+static_assert(TFormatTraits<TEnumIndexedVector<ESample, int>>::HasCustomFormatValue);
+
+DEFINE_ENUM(EColor,
+ (Red)
+ (BlackAndWhite)
+);
+
+DEFINE_BIT_ENUM(ELangs,
+ ((None) (0x00))
+ ((Cpp) (0x01))
+ ((Go) (0x02))
+ ((Rust) (0x04))
+ ((Python) (0x08))
+ ((JavaScript) (0x10))
+)
+
+TEST(TFormatTest, Enum)
+{
+ EXPECT_EQ("Red", Format("%v", EColor::Red));
+ EXPECT_EQ("red", Format("%lv", EColor::Red));
+
+ EXPECT_EQ("BlackAndWhite", Format("%v", EColor::BlackAndWhite));
+ EXPECT_EQ("black_and_white", Format("%lv", EColor::BlackAndWhite));
+
+ EXPECT_EQ("EColor(100)", Format("%v", EColor(100)));
+
+ EXPECT_EQ("JavaScript", Format("%v", ELangs::JavaScript));
+ EXPECT_EQ("java_script", Format("%lv", ELangs::JavaScript));
+
+ EXPECT_EQ("None", Format("%v", ELangs::None));
+ EXPECT_EQ("none", Format("%lv", ELangs::None));
+
+ EXPECT_EQ("Cpp | Go", Format("%v", ELangs::Cpp | ELangs::Go));
+ EXPECT_EQ("cpp | go", Format("%lv", ELangs::Cpp | ELangs::Go));
+
+ auto four = ELangs::Cpp | ELangs::Go | ELangs::Python | ELangs::JavaScript;
+ EXPECT_EQ("Cpp | Go | Python | JavaScript", Format("%v", four));
+ EXPECT_EQ("cpp | go | python | java_script", Format("%lv", four));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT
+
+
diff --git a/library/cpp/yt/string/unittests/format_ut.cpp b/library/cpp/yt/string/unittests/format_ut.cpp
new file mode 100644
index 0000000000..ee069bb2c0
--- /dev/null
+++ b/library/cpp/yt/string/unittests/format_ut.cpp
@@ -0,0 +1,149 @@
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <library/cpp/yt/string/format.h>
+
+#include <library/cpp/yt/small_containers/compact_vector.h>
+
+#include <limits>
+
+namespace NYT {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Some compile-time sanity checks.
+static_assert(TFormatTraits<int>::HasCustomFormatValue);
+static_assert(TFormatTraits<double>::HasCustomFormatValue);
+static_assert(TFormatTraits<void*>::HasCustomFormatValue);
+static_assert(TFormatTraits<const char*>::HasCustomFormatValue);
+static_assert(TFormatTraits<TStringBuf>::HasCustomFormatValue);
+static_assert(TFormatTraits<TString>::HasCustomFormatValue);
+static_assert(TFormatTraits<std::vector<int>>::HasCustomFormatValue);
+
+// N.B. TCompactVector<int, 1> is not buildable on Windows
+static_assert(TFormatTraits<TCompactVector<int, 2>>::HasCustomFormatValue);
+static_assert(TFormatTraits<std::set<int>>::HasCustomFormatValue);
+static_assert(TFormatTraits<std::map<int, int>>::HasCustomFormatValue);
+static_assert(TFormatTraits<std::multimap<int, int>>::HasCustomFormatValue);
+static_assert(TFormatTraits<THashSet<int>>::HasCustomFormatValue);
+static_assert(TFormatTraits<THashMap<int, int>>::HasCustomFormatValue);
+static_assert(TFormatTraits<THashMultiSet<int>>::HasCustomFormatValue);
+static_assert(TFormatTraits<std::pair<int, int>>::HasCustomFormatValue);
+static_assert(TFormatTraits<std::optional<int>>::HasCustomFormatValue);
+static_assert(TFormatTraits<TDuration>::HasCustomFormatValue);
+static_assert(TFormatTraits<TInstant>::HasCustomFormatValue);
+
+struct TUnformattable
+{ };
+static_assert(!TFormatTraits<TUnformattable>::HasCustomFormatValue);
+
+////////////////////////////////////////////////////////////////////////////////
+
+TEST(TFormatTest, Nothing)
+{
+ EXPECT_EQ("abc", Format("a%nb%nc", 1, 2));
+}
+
+TEST(TFormatTest, Verbatim)
+{
+ EXPECT_EQ("", Format(""));
+ EXPECT_EQ("test", Format("test"));
+ EXPECT_EQ("%", Format("%%"));
+ EXPECT_EQ("%hello%world%", Format("%%hello%%world%%"));
+}
+
+TEST(TFormatTest, MultipleArgs)
+{
+ EXPECT_EQ("2+2=4", Format("%v+%v=%v", 2, 2, 4));
+}
+
+TEST(TFormatTest, Strings)
+{
+ EXPECT_EQ("test", Format("%s", "test"));
+ EXPECT_EQ("test", Format("%s", TStringBuf("test")));
+ EXPECT_EQ("test", Format("%s", TString("test")));
+
+ EXPECT_EQ(" abc", Format("%6s", TString("abc")));
+ EXPECT_EQ("abc ", Format("%-6s", TString("abc")));
+ EXPECT_EQ(" abc", Format("%10v", TString("abc")));
+ EXPECT_EQ("abc ", Format("%-10v", TString("abc")));
+ EXPECT_EQ("abc", Format("%2s", TString("abc")));
+ EXPECT_EQ("abc", Format("%-2s", TString("abc")));
+ EXPECT_EQ("abc", Format("%0s", TString("abc")));
+ EXPECT_EQ("abc", Format("%-0s", TString("abc")));
+ EXPECT_EQ(100, std::ssize(Format("%100v", "abc")));
+}
+
+TEST(TFormatTest, Integers)
+{
+ EXPECT_EQ("123", Format("%d", 123));
+ EXPECT_EQ("123", Format("%v", 123));
+
+ EXPECT_EQ("042", Format("%03d", 42));
+ EXPECT_EQ("42", Format("%01d", 42));
+
+ EXPECT_EQ("2147483647", Format("%d", std::numeric_limits<i32>::max()));
+ EXPECT_EQ("-2147483648", Format("%d", std::numeric_limits<i32>::min()));
+
+ EXPECT_EQ("0", Format("%u", 0U));
+ EXPECT_EQ("0", Format("%v", 0U));
+ EXPECT_EQ("4294967295", Format("%u", std::numeric_limits<ui32>::max()));
+ EXPECT_EQ("4294967295", Format("%v", std::numeric_limits<ui32>::max()));
+
+ EXPECT_EQ("9223372036854775807", Format("%" PRId64, std::numeric_limits<i64>::max()));
+ EXPECT_EQ("9223372036854775807", Format("%v", std::numeric_limits<i64>::max()));
+ EXPECT_EQ("-9223372036854775808", Format("%" PRId64, std::numeric_limits<i64>::min()));
+ EXPECT_EQ("-9223372036854775808", Format("%v", std::numeric_limits<i64>::min()));
+
+ EXPECT_EQ("0", Format("%" PRIu64, 0ULL));
+ EXPECT_EQ("0", Format("%v", 0ULL));
+ EXPECT_EQ("18446744073709551615", Format("%" PRIu64, std::numeric_limits<ui64>::max()));
+ EXPECT_EQ("18446744073709551615", Format("%v", std::numeric_limits<ui64>::max()));
+}
+
+TEST(TFormatTest, Floats)
+{
+ EXPECT_EQ("3.14", Format("%.2f", 3.1415F));
+ EXPECT_EQ("3.14", Format("%.2v", 3.1415F));
+ EXPECT_EQ("3.14", Format("%.2lf", 3.1415));
+ EXPECT_EQ("3.14", Format("%.2v", 3.1415));
+ EXPECT_EQ(TString(std::to_string(std::numeric_limits<double>::max())),
+ Format("%lF", std::numeric_limits<double>::max()));
+}
+
+TEST(TFormatTest, Bool)
+{
+ EXPECT_EQ("True", Format("%v", true));
+ EXPECT_EQ("False", Format("%v", false));
+ EXPECT_EQ("true", Format("%lv", true));
+ EXPECT_EQ("false", Format("%lv", false));
+}
+
+TEST(TFormatTest, Quotes)
+{
+ EXPECT_EQ("\"True\"", Format("%Qv", true));
+ EXPECT_EQ("'False'", Format("%qv", false));
+ EXPECT_EQ("'\\\'\"'", Format("%qv", "\'\""));
+ EXPECT_EQ("\"\\x01\"", Format("%Qv", "\x1"));
+ EXPECT_EQ("'\\x1b'", Format("%qv", '\x1b'));
+}
+
+TEST(TFormatTest, Nullable)
+{
+ EXPECT_EQ("1", Format("%v", std::make_optional<int>(1)));
+ EXPECT_EQ("<null>", Format("%v", std::nullopt));
+ EXPECT_EQ("<null>", Format("%v", std::optional<int>()));
+ EXPECT_EQ("3.14", Format("%.2f", std::optional<double>(3.1415)));
+}
+
+TEST(TFormatTest, Pointers)
+{
+ // No idea if pointer format is standardized, check against Sprintf.
+ auto p = reinterpret_cast<void*>(123);
+ EXPECT_EQ(Sprintf("%p", reinterpret_cast<void*>(123)), Format("%p", p));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT
diff --git a/library/cpp/yt/string/unittests/guid_ut.cpp b/library/cpp/yt/string/unittests/guid_ut.cpp
new file mode 100644
index 0000000000..4b5eebea16
--- /dev/null
+++ b/library/cpp/yt/string/unittests/guid_ut.cpp
@@ -0,0 +1,58 @@
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <library/cpp/yt/string/guid.h>
+#include <library/cpp/yt/string/format.h>
+
+#include <util/string/hex.h>
+
+namespace NYT {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+static_assert(TFormatTraits<TGuid>::HasCustomFormatValue);
+
+TString CanonicalToString(TGuid value)
+{
+ return Sprintf("%x-%x-%x-%x",
+ value.Parts32[3],
+ value.Parts32[2],
+ value.Parts32[1],
+ value.Parts32[0]);
+}
+
+const ui32 TrickyValues[] = {
+ 0, 0x1, 0x12, 0x123, 0x1234, 0x12345, 0x123456, 0x1234567, 0x12345678
+};
+
+TEST(TGuidTest, FormatAllTricky)
+{
+ for (ui32 a : TrickyValues) {
+ for (ui32 b : TrickyValues) {
+ for (ui32 c : TrickyValues) {
+ for (ui32 d : TrickyValues) {
+ auto value = TGuid(a, b, c, d);
+ EXPECT_EQ(CanonicalToString(value), ToString(value));
+ }
+ }
+ }
+ }
+}
+
+TEST(TGuidTest, FormatAllSymbols)
+{
+ const auto Value = TGuid::FromString("12345678-abcdef01-12345678-abcdef01");
+ EXPECT_EQ(CanonicalToString(Value), ToString(Value));
+}
+
+TEST(TGuidTest, ByteOrder)
+{
+ auto guid = TGuid::FromStringHex32("12345678ABCDEF0112345678ABCDEF01");
+ TString bytes{reinterpret_cast<const char*>(&(guid.Parts32[0])), 16};
+ EXPECT_EQ(HexEncode(bytes), "01EFCDAB7856341201EFCDAB78563412");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT
diff --git a/library/cpp/yt/string/unittests/string_ut.cpp b/library/cpp/yt/string/unittests/string_ut.cpp
new file mode 100644
index 0000000000..3e12312af0
--- /dev/null
+++ b/library/cpp/yt/string/unittests/string_ut.cpp
@@ -0,0 +1,52 @@
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <library/cpp/yt/string/string.h>
+
+namespace NYT {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct TTestCase
+{
+ const char* UnderCase;
+ const char* CamelCase;
+};
+
+static std::vector<TTestCase> TestCases {
+ { "kenny", "Kenny" },
+ { "south_park", "SouthPark" },
+ { "a", "A" },
+ { "a_b_c", "ABC" },
+ { "reed_solomon_6_3", "ReedSolomon_6_3" },
+ { "lrc_12_2_2", "Lrc_12_2_2" },
+ { "0", "0" },
+ { "0_1_2", "0_1_2" },
+ { "int64", "Int64" }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+TEST(TStringTest, UnderscoreCaseToCamelCase)
+{
+ for (const auto& testCase : TestCases) {
+ auto result = UnderscoreCaseToCamelCase(testCase.UnderCase);
+ EXPECT_STREQ(testCase.CamelCase, result.c_str())
+ << "Original: \"" << testCase.UnderCase << '"';
+ }
+}
+
+TEST(TStringTest, CamelCaseToUnderscoreCase)
+{
+ for (const auto& testCase : TestCases) {
+ auto result = CamelCaseToUnderscoreCase(testCase.CamelCase);
+ EXPECT_STREQ(testCase.UnderCase, result.c_str())
+ << "Original: \"" << testCase.CamelCase << '"';
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT
+
diff --git a/library/cpp/yt/string/unittests/ya.make b/library/cpp/yt/string/unittests/ya.make
new file mode 100644
index 0000000000..9d539758d1
--- /dev/null
+++ b/library/cpp/yt/string/unittests/ya.make
@@ -0,0 +1,17 @@
+GTEST(unittester-library-string-helpers)
+
+OWNER(g:yt)
+
+SRCS(
+ enum_ut.cpp
+ format_ut.cpp
+ guid_ut.cpp
+ string_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/yt/string
+ library/cpp/testing/gtest
+)
+
+END()
diff --git a/library/cpp/yt/string/ya.make b/library/cpp/yt/string/ya.make
new file mode 100644
index 0000000000..83efd5eb2f
--- /dev/null
+++ b/library/cpp/yt/string/ya.make
@@ -0,0 +1,30 @@
+LIBRARY()
+
+SRCS(
+ enum.cpp
+ guid.cpp
+ string.cpp
+)
+
+PEERDIR(
+ library/cpp/yt/assert
+ library/cpp/yt/exception
+ library/cpp/yt/misc
+)
+
+CHECK_DEPENDENT_DIRS(
+ ALLOW_ONLY ALL
+ build
+ contrib
+ library
+ util
+ library/cpp/yt/assert
+ library/cpp/yt/misc
+ library/cpp/yt/small_containers
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ unittests
+)
diff --git a/library/cpp/yt/ya.make b/library/cpp/yt/ya.make
new file mode 100644
index 0000000000..f4d43806f4
--- /dev/null
+++ b/library/cpp/yt/ya.make
@@ -0,0 +1,24 @@
+RECURSE(
+ assert
+ coding
+ exception
+ misc
+ string
+ system
+ yson
+ yson_string
+)
+
+IF (NOT OS_WINDOWS)
+ RECURSE(
+ containers
+ cpu_clock
+ logging
+ malloc
+ memory
+ mlock
+ phdr_cache
+ small_containers
+ threading
+ )
+ENDIF()
diff --git a/library/cpp/yt/yson/consumer.cpp b/library/cpp/yt/yson/consumer.cpp
new file mode 100644
index 0000000000..9b68ee8a22
--- /dev/null
+++ b/library/cpp/yt/yson/consumer.cpp
@@ -0,0 +1,16 @@
+#include "consumer.h"
+
+#include <library/cpp/yt/yson_string/string.h>
+
+namespace NYT::NYson {
+
+////////////////////////////////////////////////////////////////////////////////
+
+void IYsonConsumer::OnRaw(const TYsonStringBuf& yson)
+{
+ OnRaw(yson.AsStringBuf(), yson.GetType());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NYson
diff --git a/library/cpp/yt/yson/consumer.h b/library/cpp/yt/yson/consumer.h
new file mode 100644
index 0000000000..ea5f586b91
--- /dev/null
+++ b/library/cpp/yt/yson/consumer.h
@@ -0,0 +1,111 @@
+#pragma once
+
+#include <util/generic/strbuf.h>
+
+#include <util/system/defaults.h>
+
+#include <library/cpp/yt/yson_string/public.h>
+
+namespace NYT::NYson {
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! A SAX-like interface for parsing a YSON stream.
+struct IYsonConsumer
+{
+ virtual ~IYsonConsumer() = default;
+
+ //! The current item is a string scalar (IStringNode).
+ /*!
+ * \param value A scalar value.
+ */
+ virtual void OnStringScalar(TStringBuf value) = 0;
+
+ //! The current item is an integer scalar (IInt64Node).
+ /*!
+ * \param value A scalar value.
+ */
+ virtual void OnInt64Scalar(i64 value) = 0;
+
+ //! The current item is an integer scalar (IUint64Node).
+ /*!
+ * \param value A scalar value.
+ */
+ virtual void OnUint64Scalar(ui64 scalar) = 0;
+
+ //! The current item is an FP scalar (IDoubleNode).
+ /*!
+ * \param value A scalar value.
+ */
+ virtual void OnDoubleScalar(double value) = 0;
+
+ //! The current item is an boolean scalar (IBooleanNode).
+ /*!
+ * \param value A scalar value.
+ */
+ virtual void OnBooleanScalar(bool value) = 0;
+
+ //! The current item is an entity (IEntityNode).
+ virtual void OnEntity() = 0;
+
+ //! Starts a list (IListNode).
+ /*!
+ * The events describing a list are raised as follows:
+ * - #OnBeginList
+ * - For each item: #OnListItem followed by the description of the item
+ * - #OnEndList
+ */
+ virtual void OnBeginList() = 0;
+
+ //! Designates a list item.
+ virtual void OnListItem() = 0;
+
+ //! Ends the current list.
+ virtual void OnEndList() = 0;
+
+ //! Starts a map (IMapNode).
+ /*!
+ * The events describing a map are raised as follows:
+ * - #OnBeginMap
+ * - For each item: #OnKeyedItem followed by the description of the item
+ * - #OnEndMap
+ */
+ virtual void OnBeginMap() = 0;
+
+ //! Designates a keyed item (in map or in attributes).
+ /*!
+ * \param key Item key in the map.
+ */
+ virtual void OnKeyedItem(TStringBuf key) = 0;
+
+ //! Ends the current map.
+ virtual void OnEndMap() = 0;
+
+ //! Starts attributes.
+ /*!
+ * An arbitrary node may be preceeded by attributes.
+ *
+ * The events describing attributes are raised as follows:
+ * - #OnBeginAttributes
+ * - For each item: #OnKeyedItem followed by the description of the item
+ * - #OnEndAttributes
+ */
+ virtual void OnBeginAttributes() = 0;
+
+ //! Ends the current attribute list.
+ virtual void OnEndAttributes() = 0;
+
+ //! Inserts YSON-serialized node or fragment.
+ /*!
+ * \param yson Serialized data.
+ * \param type Type of data.
+ */
+ virtual void OnRaw(TStringBuf yson, EYsonType type) = 0;
+
+ // Extension methods.
+ void OnRaw(const TYsonStringBuf& yson);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NYson
diff --git a/library/cpp/yt/yson/public.h b/library/cpp/yt/yson/public.h
new file mode 100644
index 0000000000..68cdcd38c1
--- /dev/null
+++ b/library/cpp/yt/yson/public.h
@@ -0,0 +1,11 @@
+#pragma once
+
+namespace NYT::NYson {
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct IYsonConsumer;
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NYson
diff --git a/library/cpp/yt/yson/ya.make b/library/cpp/yt/yson/ya.make
new file mode 100644
index 0000000000..d914352c4b
--- /dev/null
+++ b/library/cpp/yt/yson/ya.make
@@ -0,0 +1,11 @@
+LIBRARY()
+
+SRCS(
+ consumer.cpp
+)
+
+PEERDIR(
+ library/cpp/yt/yson_string
+)
+
+END()
diff --git a/library/cpp/yt/yson_string/convert.cpp b/library/cpp/yt/yson_string/convert.cpp
new file mode 100644
index 0000000000..27f5c30d01
--- /dev/null
+++ b/library/cpp/yt/yson_string/convert.cpp
@@ -0,0 +1,381 @@
+#include "convert.h"
+#include "format.h"
+
+#include <library/cpp/yt/assert/assert.h>
+
+#include <library/cpp/yt/string/format.h>
+
+#include <library/cpp/yt/coding/varint.h>
+
+#include <library/cpp/yt/misc/cast.h>
+
+#include <array>
+
+#include <util/stream/mem.h>
+
+namespace NYT::NYson {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <>
+TYsonString ConvertToYsonString<i8>(const i8& value)
+{
+ return ConvertToYsonString(static_cast<i64>(value));
+}
+
+template <>
+TYsonString ConvertToYsonString<i32>(const i32& value)
+{
+ return ConvertToYsonString(static_cast<i64>(value));
+}
+
+template <>
+TYsonString ConvertToYsonString<i64>(const i64& value)
+{
+ std::array<char, 1 + MaxVarInt64Size> buffer;
+ auto* ptr = buffer.data();
+ *ptr++ = NDetail::Int64Marker;
+ ptr += WriteVarInt64(ptr, value);
+ return TYsonString(TStringBuf(buffer.data(), ptr - buffer.data()));
+}
+
+template <>
+TYsonString ConvertToYsonString<ui8>(const ui8& value)
+{
+ return ConvertToYsonString(static_cast<ui64>(value));
+}
+
+template <>
+TYsonString ConvertToYsonString<ui32>(const ui32& value)
+{
+ return ConvertToYsonString(static_cast<ui64>(value));
+}
+
+template <>
+TYsonString ConvertToYsonString<ui64>(const ui64& value)
+{
+ std::array<char, 1 + MaxVarInt64Size> buffer;
+ auto* ptr = buffer.data();
+ *ptr++ = NDetail::Uint64Marker;
+ ptr += WriteVarUint64(ptr, value);
+ return TYsonString(TStringBuf(buffer.data(), ptr - buffer.data()));
+}
+
+template <>
+TYsonString ConvertToYsonString<TString>(const TString& value)
+{
+ return ConvertToYsonString(static_cast<TStringBuf>(value));
+}
+
+struct TConvertStringToYsonStringTag
+{ };
+
+template <>
+TYsonString ConvertToYsonString<TStringBuf>(const TStringBuf& value)
+{
+ auto buffer = TSharedMutableRef::Allocate<TConvertStringToYsonStringTag>(
+ 1 + MaxVarInt64Size + value.length(),
+ /*initializeStorage*/ false);
+ auto* ptr = buffer.Begin();
+ *ptr++ = NDetail::StringMarker;
+ ptr += WriteVarInt64(ptr, static_cast<i64>(value.length()));
+ ::memcpy(ptr, value.data(), value.length());
+ ptr += value.length();
+ return TYsonString(buffer.Slice(buffer.Begin(), ptr));
+}
+
+TYsonString ConvertToYsonString(const char* value)
+{
+ return ConvertToYsonString(TStringBuf(value));
+}
+
+template <>
+TYsonString ConvertToYsonString<float>(const float& value)
+{
+ return ConvertToYsonString(static_cast<double>(value));
+}
+
+template <>
+TYsonString ConvertToYsonString<double>(const double& value)
+{
+ std::array<char, 1 + sizeof(double)> buffer;
+ auto* ptr = buffer.data();
+ *ptr++ = NDetail::DoubleMarker;
+ ::memcpy(ptr, &value, sizeof(value));
+ ptr += sizeof(value);
+ return TYsonString(TStringBuf(buffer.data(), ptr - buffer.data()));
+}
+
+template <>
+TYsonString ConvertToYsonString<bool>(const bool& value)
+{
+ char ch = value ? NDetail::TrueMarker : NDetail::FalseMarker;
+ return TYsonString(TStringBuf(&ch, 1));
+}
+
+template <>
+TYsonString ConvertToYsonString<TInstant>(const TInstant& value)
+{
+ return ConvertToYsonString(value.ToString());
+}
+
+template <>
+TYsonString ConvertToYsonString<TDuration>(const TDuration& value)
+{
+ return ConvertToYsonString(value.MilliSeconds());
+}
+
+template <>
+TYsonString ConvertToYsonString<TGuid>(const TGuid& value)
+{
+ std::array<char, MaxGuidStringSize> guidBuffer;
+ auto guidLength = WriteGuidToBuffer(guidBuffer.data(), value) - guidBuffer.data();
+ std::array<char, 1 + MaxVarInt64Size + MaxGuidStringSize> ysonBuffer;
+ auto* ptr = ysonBuffer.data();
+ *ptr++ = NDetail::StringMarker;
+ ptr += WriteVarInt64(ptr, static_cast<i64>(guidLength));
+ ::memcpy(ptr, guidBuffer.data(), guidLength);
+ ptr += guidLength;
+ return TYsonString(TStringBuf(ysonBuffer.data(), ptr - ysonBuffer.data()));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+TString FormatUnexpectedMarker(char ch)
+{
+ switch (ch) {
+ case NDetail::BeginListSymbol:
+ return "list";
+ case NDetail::BeginMapSymbol:
+ return "map";
+ case NDetail::BeginAttributesSymbol:
+ return "attributes";
+ case NDetail::EntitySymbol:
+ return "\"entity\" literal";
+ case NDetail::StringMarker:
+ return "\"string\" literal";
+ case NDetail::Int64Marker:
+ return "\"int64\" literal";
+ case NDetail::DoubleMarker:
+ return "\"double\" literal";
+ case NDetail::FalseMarker:
+ case NDetail::TrueMarker:
+ return "\"boolean\" literal";
+ case NDetail::Uint64Marker:
+ return "\"uint64\" literal";
+ default:
+ return Format("unexpected symbol %qv", ch);
+ }
+}
+
+i64 ParseInt64FromYsonString(const TYsonStringBuf& str)
+{
+ YT_ASSERT(str.GetType() == EYsonType::Node);
+ auto strBuf = str.AsStringBuf();
+ TMemoryInput input(strBuf.data(), strBuf.length());
+ char ch;
+ if (!input.ReadChar(ch)) {
+ throw TYsonLiteralParseException("Missing type marker");
+ }
+ if (ch != NDetail::Int64Marker) {
+ throw TYsonLiteralParseException(Format("Unexpected %v",
+ FormatUnexpectedMarker(ch)));
+ }
+ i64 result;
+ try {
+ ReadVarInt64(&input, &result);
+ } catch (const std::exception& ex) {
+ throw TYsonLiteralParseException(ex, "Failed to decode \"int64\" value");
+ }
+ return result;
+}
+
+ui64 ParseUint64FromYsonString(const TYsonStringBuf& str)
+{
+ YT_ASSERT(str.GetType() == EYsonType::Node);
+ auto strBuf = str.AsStringBuf();
+ TMemoryInput input(strBuf.data(), strBuf.length());
+ char ch;
+ if (!input.ReadChar(ch)) {
+ throw TYsonLiteralParseException("Missing type marker");
+ }
+ if (ch != NDetail::Uint64Marker) {
+ throw TYsonLiteralParseException(Format("Unexpected %v",
+ FormatUnexpectedMarker(ch)));
+ }
+ ui64 result;
+ try {
+ ReadVarUint64(&input, &result);
+ } catch (const std::exception& ex) {
+ throw TYsonLiteralParseException(ex, "Failed to decode \"uint64\" value");
+ }
+ return result;
+}
+
+TString ParseStringFromYsonString(const TYsonStringBuf& str)
+{
+ YT_ASSERT(str.GetType() == EYsonType::Node);
+ auto strBuf = str.AsStringBuf();
+ TMemoryInput input(strBuf.data(), strBuf.length());
+ char ch;
+ if (!input.ReadChar(ch)) {
+ throw TYsonLiteralParseException("Missing type marker");
+ }
+ if (ch != NDetail::StringMarker) {
+ throw TYsonLiteralParseException(Format("Unexpected %v",
+ FormatUnexpectedMarker(ch)));
+ }
+ i64 length;
+ try {
+ ReadVarInt64(&input, &length);
+ } catch (const std::exception& ex) {
+ throw TYsonLiteralParseException(ex, "Failed to decode string length");
+ }
+ if (length < 0) {
+ throw TYsonLiteralParseException(Format("Negative string length ",
+ length));
+ }
+ if (static_cast<i64>(input.Avail()) != length) {
+ throw TYsonLiteralParseException(Format("Incorrect remaining string length: expected %v, got %v",
+ length,
+ input.Avail()));
+ }
+ TString result;
+ result.ReserveAndResize(length);
+ YT_VERIFY(static_cast<i64>(input.Read(result.Detach(), length)) == length);
+ return result;
+}
+
+double ParseDoubleFromYsonString(const TYsonStringBuf& str)
+{
+ YT_ASSERT(str.GetType() == EYsonType::Node);
+ auto strBuf = str.AsStringBuf();
+ TMemoryInput input(strBuf.data(), strBuf.length());
+ char ch;
+ if (!input.ReadChar(ch)) {
+ throw TYsonLiteralParseException("Missing type marker");
+ }
+ if (ch != NDetail::DoubleMarker) {
+ throw TYsonLiteralParseException(Format("Unexpected %v",
+ FormatUnexpectedMarker(ch)));
+ }
+ if (input.Avail() != sizeof(double)) {
+ throw TYsonLiteralParseException(Format("Incorrect remaining string length: expected %v, got %v",
+ sizeof(double),
+ input.Avail()));
+ }
+ double result;
+ YT_VERIFY(input.Read(&result, sizeof(result)));
+ return result;
+}
+
+} // namespace
+
+#define PARSE(type, underlyingType) \
+ template <> \
+ type ConvertFromYsonString<type>(const TYsonStringBuf& str) \
+ { \
+ try { \
+ return CheckedIntegralCast<type>(Parse ## underlyingType ## FromYsonString(str)); \
+ } catch (const std::exception& ex) { \
+ throw TYsonLiteralParseException(ex, "Error parsing \"" #type "\" value from YSON"); \
+ } \
+ }
+
+PARSE(i8, Int64 )
+PARSE(i16, Int64 )
+PARSE(i32, Int64 )
+PARSE(i64, Int64 )
+PARSE(ui8, Uint64)
+PARSE(ui16, Uint64)
+PARSE(ui32, Uint64)
+PARSE(ui64, Uint64)
+
+#undef PARSE
+
+template <>
+TString ConvertFromYsonString<TString>(const TYsonStringBuf& str)
+{
+ try {
+ return ParseStringFromYsonString(str);
+ } catch (const std::exception& ex) {
+ throw TYsonLiteralParseException(ex, "Error parsing \"string\" value from YSON");
+ }
+}
+
+template <>
+float ConvertFromYsonString<float>(const TYsonStringBuf& str)
+{
+ try {
+ return static_cast<float>(ParseDoubleFromYsonString(str));
+ } catch (const std::exception& ex) {
+ throw TYsonLiteralParseException(ex, "Error parsing \"float\" value from YSON");
+ }
+}
+
+template <>
+double ConvertFromYsonString<double>(const TYsonStringBuf& str)
+{
+ try {
+ return ParseDoubleFromYsonString(str);
+ } catch (const std::exception& ex) {
+ throw TYsonLiteralParseException(ex, "Error parsing \"double\" value from YSON");
+ }
+}
+
+template <>
+bool ConvertFromYsonString<bool>(const TYsonStringBuf& str)
+{
+ try {
+ YT_ASSERT(str.GetType() == EYsonType::Node);
+ auto strBuf = str.AsStringBuf();
+ TMemoryInput input(strBuf.data(), strBuf.length());
+ char ch;
+ if (!input.ReadChar(ch)) {
+ throw TYsonLiteralParseException("Missing type marker");
+ }
+ if (ch != NDetail::TrueMarker && ch != NDetail::FalseMarker) {
+ throw TYsonLiteralParseException(Format("Unexpected %v",
+ FormatUnexpectedMarker(ch)));
+ }
+ return ch == NDetail::TrueMarker;
+ } catch (const std::exception& ex) {
+ throw TYsonLiteralParseException(ex, "Error parsing \"boolean\" value from YSON");
+ }
+}
+
+template <>
+TInstant ConvertFromYsonString<TInstant>(const TYsonStringBuf& str)
+{
+ try {
+ return TInstant::ParseIso8601(ParseStringFromYsonString(str));
+ } catch (const std::exception& ex) {
+ throw TYsonLiteralParseException(ex, "Error parsing \"instant\" value from YSON");
+ }
+}
+
+template <>
+TDuration ConvertFromYsonString<TDuration>(const TYsonStringBuf& str)
+{
+ try {
+ return TDuration::MilliSeconds(ParseUint64FromYsonString(str));
+ } catch (const std::exception& ex) {
+ throw TYsonLiteralParseException(ex, "Error parsing \"duration\" value from YSON");
+ }
+}
+
+template <>
+TGuid ConvertFromYsonString<TGuid>(const TYsonStringBuf& str)
+{
+ try {
+ return TGuid::FromString(ParseStringFromYsonString(str));
+ } catch (const std::exception& ex) {
+ throw TYsonLiteralParseException(ex, "Error parsing \"guid\" value from YSON");
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NYson
diff --git a/library/cpp/yt/yson_string/convert.h b/library/cpp/yt/yson_string/convert.h
new file mode 100644
index 0000000000..3c2cc7d284
--- /dev/null
+++ b/library/cpp/yt/yson_string/convert.h
@@ -0,0 +1,114 @@
+#pragma once
+
+#include "string.h"
+
+#include <library/cpp/yt/misc/guid.h>
+
+#include <library/cpp/yt/exception/exception.h>
+
+#include <util/generic/string.h>
+
+#include <util/datetime/base.h>
+
+namespace NYT::NYson {
+
+////////////////////////////////////////////////////////////////////////////////
+// Generic forward declarations.
+
+template <class T>
+TYsonString ConvertToYsonString(const T& value);
+
+template <class T>
+TYsonString ConvertToYsonString(const T& value, EYsonFormat format);
+
+template <class T>
+T ConvertFromYsonString(const TYsonStringBuf& str);
+
+////////////////////////////////////////////////////////////////////////////////
+// Basic specializations for ConvertToYsonString.
+
+template <>
+TYsonString ConvertToYsonString<i8>(const i8& value);
+template <>
+TYsonString ConvertToYsonString<i32>(const i32& value);
+template <>
+TYsonString ConvertToYsonString<i64>(const i64& value);
+
+template <>
+TYsonString ConvertToYsonString<ui8>(const ui8& value);
+template <>
+TYsonString ConvertToYsonString<ui32>(const ui32& value);
+template <>
+TYsonString ConvertToYsonString<ui64>(const ui64& value);
+
+template <>
+TYsonString ConvertToYsonString<TString>(const TString& value);
+template <>
+TYsonString ConvertToYsonString<TStringBuf>(const TStringBuf& value);
+TYsonString ConvertToYsonString(const char* value);
+
+template <>
+TYsonString ConvertToYsonString<float>(const float& value);
+template <>
+TYsonString ConvertToYsonString<double>(const double& value);
+
+template <>
+TYsonString ConvertToYsonString<bool>(const bool& value);
+
+template <>
+TYsonString ConvertToYsonString<TInstant>(const TInstant& value);
+
+template <>
+TYsonString ConvertToYsonString<TDuration>(const TDuration& value);
+
+template <>
+TYsonString ConvertToYsonString<TGuid>(const TGuid& value);
+
+////////////////////////////////////////////////////////////////////////////////
+// Basic specializations for ConvertFromYsonString.
+// Note: these currently support a subset of NYT::NYTree::Convert features.
+
+class TYsonLiteralParseException
+ : public TCompositeException
+{
+public:
+ using TCompositeException::TCompositeException;
+};
+
+template <>
+i8 ConvertFromYsonString<i8>(const TYsonStringBuf& str);
+template <>
+i32 ConvertFromYsonString<i32>(const TYsonStringBuf& str);
+template <>
+i64 ConvertFromYsonString<i64>(const TYsonStringBuf& str);
+
+template <>
+ui8 ConvertFromYsonString<ui8>(const TYsonStringBuf& str);
+template <>
+ui32 ConvertFromYsonString<ui32>(const TYsonStringBuf& str);
+template <>
+ui64 ConvertFromYsonString<ui64>(const TYsonStringBuf& str);
+
+template <>
+TString ConvertFromYsonString<TString>(const TYsonStringBuf& str);
+
+template <>
+float ConvertFromYsonString<float>(const TYsonStringBuf& str);
+template <>
+double ConvertFromYsonString<double>(const TYsonStringBuf& str);
+
+template <>
+bool ConvertFromYsonString<bool>(const TYsonStringBuf& str);
+
+template <>
+TInstant ConvertFromYsonString<TInstant>(const TYsonStringBuf& str);
+
+template <>
+TDuration ConvertFromYsonString<TDuration>(const TYsonStringBuf& str);
+
+template <>
+TGuid ConvertFromYsonString<TGuid>(const TYsonStringBuf& str);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NYson
diff --git a/library/cpp/yt/yson_string/format.h b/library/cpp/yt/yson_string/format.h
new file mode 100644
index 0000000000..2efd4fa39a
--- /dev/null
+++ b/library/cpp/yt/yson_string/format.h
@@ -0,0 +1,44 @@
+#pragma once
+
+namespace NYT::NYson::NDetail {
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Indicates the beginning of a list.
+constexpr char BeginListSymbol = '[';
+//! Indicates the end of a list.
+constexpr char EndListSymbol = ']';
+
+//! Indicates the beginning of a map.
+constexpr char BeginMapSymbol = '{';
+//! Indicates the end of a map.
+constexpr char EndMapSymbol = '}';
+
+//! Indicates the beginning of an attribute map.
+constexpr char BeginAttributesSymbol = '<';
+//! Indicates the end of an attribute map.
+constexpr char EndAttributesSymbol = '>';
+
+//! Separates items in lists, maps, attributes.
+constexpr char ItemSeparatorSymbol = ';';
+//! Separates keys from values in maps.
+constexpr char KeyValueSeparatorSymbol = '=';
+
+//! Indicates an entity.
+constexpr char EntitySymbol = '#';
+//! Marks the beginning of a binary string literal.
+constexpr char StringMarker = '\x01';
+//! Marks the beginning of a binary i64 literal.
+constexpr char Int64Marker = '\x02';
+//! Marks the beginning of a binary double literal.
+constexpr char DoubleMarker = '\x03';
+//! Marks |false| boolean value.
+constexpr char FalseMarker = '\x04';
+//! Marks |true| boolean value.
+constexpr char TrueMarker = '\x05';
+//! Marks the beginning of a binary ui64 literal.
+constexpr char Uint64Marker = '\x06';
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NYson::NDetail
diff --git a/library/cpp/yt/yson_string/public.h b/library/cpp/yt/yson_string/public.h
new file mode 100644
index 0000000000..42c1ce80bb
--- /dev/null
+++ b/library/cpp/yt/yson_string/public.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <library/cpp/yt/misc/enum.h>
+
+namespace NYT::NYson {
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! The data format.
+DEFINE_ENUM(EYsonFormat,
+ // Binary.
+ // Most compact but not human-readable.
+ (Binary)
+
+ // Text.
+ // Not so compact but human-readable.
+ // Does not use indentation.
+ // Uses escaping for non-text characters.
+ (Text)
+
+ // Text with indentation.
+ // Extremely verbose but human-readable.
+ // Uses escaping for non-text characters.
+ (Pretty)
+);
+
+// NB: -1 is used for serializing null TYsonString.
+DEFINE_ENUM_WITH_UNDERLYING_TYPE(EYsonType, i8,
+ ((Node) (0))
+ ((ListFragment) (1))
+ ((MapFragment) (2))
+);
+
+class TYsonString;
+class TYsonStringBuf;
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NYson
diff --git a/library/cpp/yt/yson_string/string-inl.h b/library/cpp/yt/yson_string/string-inl.h
new file mode 100644
index 0000000000..5c41629cc0
--- /dev/null
+++ b/library/cpp/yt/yson_string/string-inl.h
@@ -0,0 +1,93 @@
+#ifndef STRING_INL_H_
+#error "Direct inclusion of this file is not allowed, include string.h"
+// For the sake of sane code completion.
+#include "string.h"
+#endif
+
+namespace NYT::NYson {
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace NDetail {
+
+template <typename TLeft, typename TRight>
+bool Equals(const TLeft& lhs, const TRight& rhs)
+{
+ auto lhsNull = !lhs.operator bool();
+ auto rhsNull = !rhs.operator bool();
+ if (lhsNull != rhsNull) {
+ return false;
+ }
+ if (lhsNull && rhsNull) {
+ return true;
+ }
+ return
+ lhs.AsStringBuf() == rhs.AsStringBuf() &&
+ lhs.GetType() == rhs.GetType();
+}
+
+} // namespace NDetail
+
+inline bool operator == (const TYsonString& lhs, const TYsonString& rhs)
+{
+ return NDetail::Equals(lhs, rhs);
+}
+
+inline bool operator == (const TYsonString& lhs, const TYsonStringBuf& rhs)
+{
+ return NDetail::Equals(lhs, rhs);
+}
+
+inline bool operator == (const TYsonStringBuf& lhs, const TYsonString& rhs)
+{
+ return NDetail::Equals(lhs, rhs);
+}
+
+inline bool operator == (const TYsonStringBuf& lhs, const TYsonStringBuf& rhs)
+{
+ return NDetail::Equals(lhs, rhs);
+}
+
+inline bool operator != (const TYsonString& lhs, const TYsonString& rhs)
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator != (const TYsonString& lhs, const TYsonStringBuf& rhs)
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator != (const TYsonStringBuf& lhs, const TYsonString& rhs)
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator != (const TYsonStringBuf& lhs, const TYsonStringBuf& rhs)
+{
+ return !(lhs == rhs);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NYson
+
+//! A hasher for TYsonString
+template <>
+struct THash<NYT::NYson::TYsonString>
+{
+ size_t operator () (const NYT::NYson::TYsonString& str) const
+ {
+ return str.ComputeHash();
+ }
+};
+
+//! A hasher for TYsonStringBuf
+template <>
+struct THash<NYT::NYson::TYsonStringBuf>
+{
+ size_t operator () (const NYT::NYson::TYsonStringBuf& str) const
+ {
+ return THash<TStringBuf>()(str.AsStringBuf());
+ }
+};
diff --git a/library/cpp/yt/yson_string/string.cpp b/library/cpp/yt/yson_string/string.cpp
new file mode 100644
index 0000000000..99d45e8616
--- /dev/null
+++ b/library/cpp/yt/yson_string/string.cpp
@@ -0,0 +1,185 @@
+#include "string.h"
+
+#include <library/cpp/yt/assert/assert.h>
+
+#include <library/cpp/yt/misc/variant.h>
+
+#include <library/cpp/yt/memory/new.h>
+
+namespace NYT::NYson {
+
+////////////////////////////////////////////////////////////////////////////////
+
+TYsonStringBuf::TYsonStringBuf()
+{
+ Type_ = EYsonType::Node; // fake
+ Null_ = true;
+}
+
+TYsonStringBuf::TYsonStringBuf(const TYsonString& ysonString)
+{
+ if (ysonString) {
+ Data_ = ysonString.AsStringBuf();
+ Type_ = ysonString.GetType();
+ Null_ = false;
+ } else {
+ Type_ = EYsonType::Node; // fake
+ Null_ = true;
+ }
+}
+
+TYsonStringBuf::TYsonStringBuf(const TString& data, EYsonType type)
+ : TYsonStringBuf(TStringBuf(data), type)
+{ }
+
+TYsonStringBuf::TYsonStringBuf(TStringBuf data, EYsonType type)
+ : Data_(data)
+ , Type_(type)
+ , Null_(false)
+{ }
+
+TYsonStringBuf::TYsonStringBuf(const char* data, EYsonType type)
+ : TYsonStringBuf(TStringBuf(data), type)
+{ }
+
+TYsonStringBuf::operator bool() const
+{
+ return !Null_;
+}
+
+TStringBuf TYsonStringBuf::AsStringBuf() const
+{
+ YT_VERIFY(*this);
+ return Data_;
+}
+
+EYsonType TYsonStringBuf::GetType() const
+{
+ YT_VERIFY(*this);
+ return Type_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+TYsonString::TYsonString()
+{
+ Begin_ = nullptr;
+ Size_ = 0;
+ Type_ = EYsonType::Node; // fake
+}
+
+TYsonString::TYsonString(const TYsonStringBuf& ysonStringBuf)
+{
+ if (ysonStringBuf) {
+ struct TCapturedYsonStringPayload
+ : public TRefCounted
+ , public TWithExtraSpace<TCapturedYsonStringPayload>
+ {
+ char* GetData()
+ {
+ return static_cast<char*>(GetExtraSpacePtr());
+ }
+ };
+
+ auto data = ysonStringBuf.AsStringBuf();
+ auto payload = NewWithExtraSpace<TCapturedYsonStringPayload>(data.length());
+ ::memcpy(payload->GetData(), data.data(), data.length());
+ Payload_ = payload;
+ Begin_ = payload->GetData();
+ Size_ = data.Size();
+ Type_ = ysonStringBuf.GetType();
+ } else {
+ Begin_ = nullptr;
+ Size_ = 0;
+ Type_ = EYsonType::Node; // fake
+ }
+}
+
+TYsonString::TYsonString(
+ TStringBuf data,
+ EYsonType type)
+ : TYsonString(TYsonStringBuf(data, type))
+{ }
+
+#ifdef TSTRING_IS_STD_STRING
+TYsonString::TYsonString(
+ const TString& data,
+ EYsonType type)
+ : TYsonString(TYsonStringBuf(data, type))
+{ }
+#else
+TYsonString::TYsonString(
+ const TString& data,
+ EYsonType type)
+{
+ // NOTE: CoW TString implementation is assumed
+ // Moving the payload MUST NOT invalidate its internal pointers
+ Payload_ = data;
+ Begin_ = data.data();
+ Size_ = data.length();
+ Type_ = type;
+}
+#endif
+
+TYsonString::TYsonString(
+ const TSharedRef& data,
+ EYsonType type)
+{
+ Payload_ = data.GetHolder();
+ Begin_ = data.Begin();
+ Size_ = data.Size();
+ Type_ = type;
+}
+
+TYsonString::operator bool() const
+{
+ return !std::holds_alternative<TNullPayload>(Payload_);
+}
+
+EYsonType TYsonString::GetType() const
+{
+ YT_VERIFY(*this);
+ return Type_;
+}
+
+TStringBuf TYsonString::AsStringBuf() const
+{
+ YT_VERIFY(*this);
+ return TStringBuf(Begin_, Begin_ + Size_);
+}
+
+TString TYsonString::ToString() const
+{
+ return Visit(
+ Payload_,
+ [] (const TNullPayload&) -> TString {
+ YT_ABORT();
+ },
+ [&] (const TRefCountedPtr&) {
+ return TString(AsStringBuf());
+ },
+ [] (const TString& payload) {
+ return payload;
+ });
+}
+
+size_t TYsonString::ComputeHash() const
+{
+ return THash<TStringBuf>()(TStringBuf(Begin_, Begin_ + Size_));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+TString ToString(const TYsonString& yson)
+{
+ return yson.ToString();
+}
+
+TString ToString(const TYsonStringBuf& yson)
+{
+ return TString(yson.AsStringBuf());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NYson
diff --git a/library/cpp/yt/yson_string/string.h b/library/cpp/yt/yson_string/string.h
new file mode 100644
index 0000000000..e13af37a6d
--- /dev/null
+++ b/library/cpp/yt/yson_string/string.h
@@ -0,0 +1,140 @@
+#pragma once
+
+#include "public.h"
+
+#include <library/cpp/yt/memory/ref.h>
+
+#include <variant>
+
+namespace NYT::NYson {
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! Contains a sequence of bytes in YSON encoding annotated with EYsonType describing
+//! the content. Could be null. Non-owning.
+class TYsonStringBuf
+{
+public:
+ //! Constructs a null instance.
+ TYsonStringBuf();
+
+ //! Constructs an instance from TYsonString.
+ TYsonStringBuf(const TYsonString& ysonString);
+
+ //! Constructs a non-null instance with given type and content.
+ explicit TYsonStringBuf(
+ const TString& data,
+ EYsonType type = EYsonType::Node);
+
+ //! Constructs a non-null instance with given type and content.
+ explicit TYsonStringBuf(
+ TStringBuf data,
+ EYsonType type = EYsonType::Node);
+
+ //! Constructs a non-null instance with given type and content
+ //! (without this overload there is no way to construct TYsonStringBuf from
+ //! string literal).
+ explicit TYsonStringBuf(
+ const char* data,
+ EYsonType type = EYsonType::Node);
+
+ //! Returns |true| if the instance is not null.
+ explicit operator bool() const;
+
+ //! Returns the underlying YSON bytes. The instance must be non-null.
+ TStringBuf AsStringBuf() const;
+
+ //! Returns type of YSON contained here. The instance must be non-null.
+ EYsonType GetType() const;
+
+protected:
+ TStringBuf Data_;
+ EYsonType Type_;
+ bool Null_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! An owning version of TYsonStringBuf.
+/*!
+ * Internally captures the data either via TString or a polymorphic ref-counted holder.
+ */
+class TYsonString
+{
+public:
+ //! Constructs a null instance.
+ TYsonString();
+
+ //! Constructs an instance from TYsonStringBuf.
+ //! Copies the data into a ref-counted payload.
+ explicit TYsonString(const TYsonStringBuf& ysonStringBuf);
+
+ //! Constructs an instance from TStringBuf.
+ //! Copies the data into a ref-counted payload.
+ explicit TYsonString(
+ TStringBuf data,
+ EYsonType type = EYsonType::Node);
+
+ //! Constructs an instance from TString.
+ //! Zero-copy for CoW TString: retains the reference to TString in payload.
+ explicit TYsonString(
+ const TString& data,
+ EYsonType type = EYsonType::Node);
+
+ //! Constructs an instance from TSharedRef.
+ //! Zero-copy; retains the reference to TSharedRef holder in payload.
+ explicit TYsonString(
+ const TSharedRef& ref,
+ EYsonType type = EYsonType::Node);
+
+ //! Returns |true| if the instance is not null.
+ explicit operator bool() const;
+
+ //! Returns type of YSON contained here. The instance must be non-null.
+ EYsonType GetType() const;
+
+ //! Returns the non-owning data. The instance must be non-null.
+ TStringBuf AsStringBuf() const;
+
+ //! Returns the data represented by TString. The instance must be non-null.
+ //! Copies the data in case the payload is not TString.
+ TString ToString() const;
+
+ //! Computes the hash code.
+ size_t ComputeHash() const;
+
+private:
+ struct TNullPayload
+ { };
+
+ using THolder = TRefCountedPtr;
+
+ std::variant<TNullPayload, THolder, TString> Payload_;
+
+ const char* Begin_;
+ ui64 Size_ : 56;
+ EYsonType Type_ : 8;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool operator == (const TYsonString& lhs, const TYsonString& rhs);
+bool operator == (const TYsonString& lhs, const TYsonStringBuf& rhs);
+bool operator == (const TYsonStringBuf& lhs, const TYsonString& rhs);
+bool operator == (const TYsonStringBuf& lhs, const TYsonStringBuf& rhs);
+
+bool operator != (const TYsonString& lhs, const TYsonString& rhs);
+bool operator != (const TYsonString& lhs, const TYsonStringBuf& rhs);
+bool operator != (const TYsonStringBuf& lhs, const TYsonString& rhs);
+bool operator != (const TYsonStringBuf& lhs, const TYsonStringBuf& rhs);
+
+TString ToString(const TYsonString& yson);
+TString ToString(const TYsonStringBuf& yson);
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NYson
+
+#define STRING_INL_H_
+#include "string-inl.h"
+#undef STRING_INL_H_
diff --git a/library/cpp/yt/yson_string/unittests/convert_ut.cpp b/library/cpp/yt/yson_string/unittests/convert_ut.cpp
new file mode 100644
index 0000000000..3a64f63896
--- /dev/null
+++ b/library/cpp/yt/yson_string/unittests/convert_ut.cpp
@@ -0,0 +1,79 @@
+#include <library/cpp/testing/gtest/gtest.h>
+
+#include <library/cpp/testing/gtest_extensions/assertions.h>
+
+#include <library/cpp/yt/yson_string/convert.h>
+
+#include <thread>
+
+namespace NYT::NYson {
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, class R = T, class U>
+void Check(const U& value)
+{
+ auto str = ConvertToYsonString(static_cast<T>(value));
+ auto anotherValue = ConvertFromYsonString<R>(str);
+ EXPECT_EQ(static_cast<T>(value), anotherValue);
+}
+
+TEST(TConvertTest, Basic)
+{
+ Check<i8>(13);
+ Check<i32>(13);
+ Check<i64>(13);
+ Check<i8>(-13);
+ Check<i32>(-13);
+ Check<i64>(-13);
+ Check<ui8>(13);
+ Check<ui32>(13);
+ Check<ui64>(13);
+ Check<TString>("");
+ Check<TString>("hello");
+ Check<TStringBuf, TString>("hello");
+ Check<const char*, TString>("hello");
+ Check<float>(3.14);
+ Check<double>(3.14);
+ Check<bool>(true);
+ Check<bool>(false);
+ Check<TInstant>(TInstant::Now());
+ Check<TDuration>(TDuration::Seconds(123));
+ Check<TGuid>(TGuid::FromString("12345678-12345678-abcdabcd-fefefefe"));
+}
+
+TEST(TConvertTest, InRange)
+{
+ EXPECT_EQ(ConvertFromYsonString<i16>(ConvertToYsonString(static_cast<i64>(-123))), -123);
+ EXPECT_EQ(ConvertFromYsonString<ui16>(ConvertToYsonString(static_cast<ui64>(123))), 123U);
+}
+
+TEST(TConvertTest, OutOfRange)
+{
+ EXPECT_THROW_MESSAGE_HAS_SUBSTR(
+ ConvertFromYsonString<i8>(ConvertToYsonString(static_cast<i64>(128))),
+ TYsonLiteralParseException,
+ "is out of expected range");
+ EXPECT_THROW_MESSAGE_HAS_SUBSTR(
+ ConvertFromYsonString<ui8>(ConvertToYsonString(static_cast<ui64>(256))),
+ TYsonLiteralParseException,
+ "is out of expected range");
+}
+
+TEST(TConvertTest, MalformedValues)
+{
+ EXPECT_THROW_MESSAGE_HAS_SUBSTR(
+ ConvertFromYsonString<TInstant>(ConvertToYsonString(TStringBuf("sometime"))),
+ TYsonLiteralParseException,
+ "Error parsing \"instant\" value");
+ EXPECT_THROW_MESSAGE_HAS_SUBSTR(
+ ConvertFromYsonString<TGuid>(ConvertToYsonString(TStringBuf("1-2-3-g"))),
+ TYsonLiteralParseException,
+ "Error parsing \"guid\" value");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace
+} // namespace NYT::NYson
diff --git a/library/cpp/yt/yson_string/unittests/ya.make b/library/cpp/yt/yson_string/unittests/ya.make
new file mode 100644
index 0000000000..f327d298f1
--- /dev/null
+++ b/library/cpp/yt/yson_string/unittests/ya.make
@@ -0,0 +1,15 @@
+GTEST()
+
+OWNER(g:yt)
+
+SRCS(
+ convert_ut.cpp
+)
+
+PEERDIR(
+ library/cpp/yt/yson_string
+ library/cpp/testing/gtest
+ library/cpp/testing/gtest_extensions
+)
+
+END()
diff --git a/library/cpp/yt/yson_string/ya.make b/library/cpp/yt/yson_string/ya.make
new file mode 100644
index 0000000000..b7447d89ff
--- /dev/null
+++ b/library/cpp/yt/yson_string/ya.make
@@ -0,0 +1,21 @@
+LIBRARY()
+
+SRCS(
+ convert.cpp
+ string.cpp
+)
+
+PEERDIR(
+ library/cpp/yt/assert
+ library/cpp/yt/coding
+ library/cpp/yt/exception
+ library/cpp/yt/string
+ library/cpp/yt/memory
+ library/cpp/yt/misc
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ unittests
+)
diff --git a/library/cpp/ytalloc/api/README.md b/library/cpp/ytalloc/api/README.md
new file mode 100644
index 0000000000..1b57e81b5c
--- /dev/null
+++ b/library/cpp/ytalloc/api/README.md
@@ -0,0 +1,6 @@
+This lightweight module can be used by anyone interested in YTAlloc
+functionality (memory allocation and disposal, memory tagging, etc).
+
+If YTAlloc happens to be linked in, it provides an efficient implementation.
+Otherwise (non-YTAlloc build), weak implementations from fallback.cpp
+are used. \ No newline at end of file
diff --git a/library/cpp/ytalloc/api/fallback.cpp b/library/cpp/ytalloc/api/fallback.cpp
new file mode 100644
index 0000000000..5880ede439
--- /dev/null
+++ b/library/cpp/ytalloc/api/fallback.cpp
@@ -0,0 +1,220 @@
+// This file contains the fallback implementations of YTAlloc-specific stuff.
+// These implementations are annotated with Y_WEAK to ensure that if the actual YTAlloc
+// is available at the link time, the latter is preferred over the fallback.
+#include "ytalloc.h"
+
+#include <util/system/compiler.h>
+#include <util/system/yassert.h>
+
+#include <cstdlib>
+
+namespace NYT::NYTAlloc {
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_WEAK void* Allocate(size_t size)
+{
+ return ::malloc(size);
+}
+
+Y_WEAK void* AllocatePageAligned(size_t size)
+{
+#if defined(_win_)
+ return ::_aligned_malloc(size, PageSize);
+#elif defined(_darwin_) || !defined(_musl_)
+ return ::valloc(size);
+#else
+ return ::memalign(PageSize, size);
+#endif
+}
+
+Y_WEAK void* AllocateSmall(size_t rank)
+{
+ return ::malloc(SmallRankToSize[rank]);
+}
+
+Y_WEAK void Free(void* ptr)
+{
+ ::free(ptr);
+}
+
+Y_WEAK void FreeNonNull(void* ptr)
+{
+ Y_ASSERT(ptr);
+ ::free(ptr);
+}
+
+Y_WEAK size_t GetAllocationSize(const void* /*ptr*/)
+{
+ return 0;
+}
+
+Y_WEAK size_t GetAllocationSize(size_t size)
+{
+ return size;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_WEAK TMemoryTag GetCurrentMemoryTag()
+{
+ return NullMemoryTag;
+}
+
+Y_WEAK void SetCurrentMemoryTag(TMemoryTag /*tag*/)
+{ }
+
+Y_WEAK size_t GetMemoryUsageForTag(TMemoryTag /*tag*/)
+{
+ return 0;
+}
+
+Y_WEAK void GetMemoryUsageForTags(const TMemoryTag* /*tags*/, size_t /*count*/, size_t* /*results*/)
+{ }
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_WEAK void SetCurrentMemoryZone(EMemoryZone /*zone*/)
+{ }
+
+Y_WEAK EMemoryZone GetCurrentMemoryZone()
+{
+ return EMemoryZone::Normal;
+}
+
+Y_WEAK EMemoryZone GetAllocationMemoryZone(const void* /*ptr*/)
+{
+ return EMemoryZone::Normal;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_WEAK void SetCurrentFiberId(TFiberId /*id*/)
+{ }
+
+Y_WEAK TFiberId GetCurrentFiberId()
+{
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_WEAK void EnableLogging(TLogHandler /*logHandler*/)
+{ }
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_WEAK void SetBacktraceProvider(TBacktraceProvider /*provider*/)
+{ }
+
+Y_WEAK void SetBacktraceFormatter(TBacktraceFormatter /*formatter*/)
+{ }
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_WEAK void EnableStockpile()
+{ }
+
+Y_WEAK void SetStockpileInterval(TDuration /*value*/)
+{ }
+
+Y_WEAK void SetStockpileThreadCount(int /*value*/)
+{ }
+
+Y_WEAK void SetStockpileSize(size_t /*value*/)
+{ }
+
+Y_WEAK void SetLargeUnreclaimableCoeff(double /*value*/)
+{ }
+
+Y_WEAK void SetMinLargeUnreclaimableBytes(size_t /*value*/)
+{ }
+
+Y_WEAK void SetMaxLargeUnreclaimableBytes(size_t /*value*/)
+{ }
+
+Y_WEAK void SetTimingEventThreshold(TDuration /*value*/)
+{ }
+
+Y_WEAK void SetAllocationProfilingEnabled(bool /*value*/)
+{ }
+
+Y_WEAK void SetAllocationProfilingSamplingRate(double /*rate*/)
+{ }
+
+Y_WEAK void SetSmallArenaAllocationProfilingEnabled(size_t /*rank*/, bool /*value*/)
+{ }
+
+Y_WEAK void SetLargeArenaAllocationProfilingEnabled(size_t /*rank*/, bool /*value*/)
+{ }
+
+Y_WEAK void SetProfilingBacktraceDepth(int /*depth*/)
+{ }
+
+Y_WEAK void SetMinProfilingBytesUsedToReport(size_t /*size*/)
+{ }
+
+Y_WEAK void SetEnableEagerMemoryRelease(bool /*value*/)
+{ }
+
+Y_WEAK void SetEnableMadvisePopulate(bool /*value*/)
+{ }
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_WEAK TEnumIndexedVector<ETotalCounter, ssize_t> GetTotalAllocationCounters()
+{
+ return {};
+}
+
+Y_WEAK TEnumIndexedVector<ESmallCounter, ssize_t> GetSmallAllocationCounters()
+{
+ return {};
+}
+
+Y_WEAK TEnumIndexedVector<ELargeCounter, ssize_t> GetLargeAllocationCounters()
+{
+ return {};
+}
+
+Y_WEAK std::array<TEnumIndexedVector<ESmallArenaCounter, ssize_t>, SmallRankCount> GetSmallArenaAllocationCounters()
+{
+ return {};
+}
+
+Y_WEAK std::array<TEnumIndexedVector<ELargeArenaCounter, ssize_t>, LargeRankCount> GetLargeArenaAllocationCounters()
+{
+ return {};
+}
+
+Y_WEAK TEnumIndexedVector<EHugeCounter, ssize_t> GetHugeAllocationCounters()
+{
+ return {};
+}
+
+Y_WEAK TEnumIndexedVector<ESystemCounter, ssize_t> GetSystemAllocationCounters()
+{
+ return {};
+}
+
+Y_WEAK TEnumIndexedVector<EUndumpableCounter, ssize_t> GetUndumpableAllocationCounters()
+{
+ return {};
+}
+
+Y_WEAK TEnumIndexedVector<ETimingEventType, TTimingEventCounters> GetTimingEventCounters()
+{
+ return {};
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+Y_WEAK std::vector<TProfiledAllocation> GetProfiledAllocationStatistics()
+{
+ return {};
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NYTAlloc
+
diff --git a/library/cpp/ytalloc/api/ya.make b/library/cpp/ytalloc/api/ya.make
new file mode 100644
index 0000000000..26d0efd381
--- /dev/null
+++ b/library/cpp/ytalloc/api/ya.make
@@ -0,0 +1,13 @@
+LIBRARY()
+
+OWNER(g:yt)
+
+SRCS(
+ fallback.cpp
+)
+
+PEERDIR(
+ library/cpp/yt/misc
+)
+
+END()
diff --git a/library/cpp/ytalloc/api/ytalloc-inl.h b/library/cpp/ytalloc/api/ytalloc-inl.h
new file mode 100644
index 0000000000..263108423d
--- /dev/null
+++ b/library/cpp/ytalloc/api/ytalloc-inl.h
@@ -0,0 +1,105 @@
+#pragma once
+#ifndef YT_ALLOC_INL_H_
+#error "Direct inclusion of this file is not allowed, include ytalloc.h"
+// For the sake of sane code completion.
+#include "ytalloc.h"
+#endif
+
+#include <util/system/types.h>
+
+namespace NYT::NYTAlloc {
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Maps small chunk ranks to size in bytes.
+constexpr ui16 SmallRankToSize[SmallRankCount] = {
+ 0,
+ 16, 32, 48, 64, 96, 128,
+ 192, 256, 384, 512, 768, 1024, 1536, 2048,
+ 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768
+};
+
+// Helper array for mapping size to small chunk rank.
+constexpr ui8 SizeToSmallRank1[65] = {
+ 1, 1, 1, 2, 2, // 16, 32
+ 3, 3, 4, 4, // 48, 64
+ 5, 5, 5, 5, 6, 6, 6, 6, // 96, 128
+ 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, // 192, 256
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 384
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 // 512
+};
+
+// Helper array for mapping size to small chunk rank.
+constexpr unsigned char SizeToSmallRank2[128] = {
+ 10, 10, 11, 12, // 512, 512, 768, 1022
+ 13, 13, 14, 14, // 1536, 2048
+ 15, 15, 15, 15, 16, 16, 16, 16, // 3072, 4096
+ 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, // 6144, 8192
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, // 12288
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 16384
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, // 22576
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22 // 32768
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+constexpr size_t SizeToSmallRank(size_t size)
+{
+ if (size <= 512) {
+ return SizeToSmallRank1[(size + 7) >> 3];
+ } else {
+ if (size <= LargeAllocationSizeThreshold) {
+ return SizeToSmallRank2[(size - 1) >> 8];
+ } else {
+ return 0;
+ }
+ }
+}
+
+void* AllocateSmall(size_t rank);
+
+template <size_t Size>
+void* AllocateConstSize()
+{
+ constexpr auto rank = SizeToSmallRank(Size);
+ if constexpr(rank != 0) {
+ return AllocateSmall(rank);
+ } else {
+ return Allocate(Size);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+inline TMemoryTagGuard::TMemoryTagGuard()
+ : Active_(false)
+ , PreviousTag_(NullMemoryTag)
+{ }
+
+inline TMemoryTagGuard::TMemoryTagGuard(TMemoryTag tag)
+ : Active_(true)
+ , PreviousTag_(GetCurrentMemoryTag())
+{
+ SetCurrentMemoryTag(tag);
+}
+
+inline TMemoryTagGuard::TMemoryTagGuard(TMemoryTagGuard&& other)
+ : Active_(other.Active_)
+ , PreviousTag_(other.PreviousTag_)
+{
+ other.Active_ = false;
+ other.PreviousTag_ = NullMemoryTag;
+}
+
+inline TMemoryTagGuard::~TMemoryTagGuard()
+{
+ if (Active_) {
+ SetCurrentMemoryTag(PreviousTag_);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NYTAlloc
diff --git a/library/cpp/ytalloc/api/ytalloc.h b/library/cpp/ytalloc/api/ytalloc.h
new file mode 100644
index 0000000000..d942dde638
--- /dev/null
+++ b/library/cpp/ytalloc/api/ytalloc.h
@@ -0,0 +1,416 @@
+#pragma once
+
+#include <stddef.h>
+
+#include <library/cpp/yt/misc/enum.h>
+
+#include <util/system/types.h>
+
+#include <util/generic/size_literals.h>
+
+#include <util/datetime/base.h>
+
+namespace NYT::NYTAlloc {
+
+////////////////////////////////////////////////////////////////////////////////
+// Macros
+
+#if defined(_linux_) && \
+ !defined(_asan_enabled_) && \
+ !defined(_msan_enabled_) && \
+ !defined(_tsan_enabled_)
+ #define YT_ALLOC_ENABLED
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Constants
+
+constexpr int SmallRankCount = 23;
+constexpr int MinLargeRank = 15;
+constexpr int LargeRankCount = 30;
+constexpr size_t LargeAllocationSizeThreshold = 32_KB;
+constexpr size_t HugeAllocationSizeThreshold = 1ULL << (LargeRankCount - 1);
+constexpr size_t MaxAllocationSize = 1_TB;
+constexpr size_t PageSize = 4_KB;
+constexpr size_t RightReadableAreaSize = 16;
+
+////////////////////////////////////////////////////////////////////////////////
+// Allocation API
+
+// Allocates a chunk of memory of (at least) #size bytes.
+// The returned pointer is guaranteed to be 16-byte aligned.
+// Moreover, it is guaranteeed that #RightReadableAreaSize bytes immediately following
+// the allocated chunk are readable (but may belong to another allocated chunk).
+// This enables eliminating some nasty corner cases in SIMD memory manipulations.
+void* Allocate(size_t size);
+
+// Allocates a chunk of memory of (at least) #size bytes.
+// The returned pointer is guaranteed to be 4K-byte aligned.
+// #size, however, need not be divisible by page size (but internally it will be rounded up).
+void* AllocatePageAligned(size_t size);
+
+// An optimized version of #Allocate with #Size being known at compile-time.
+template <size_t Size>
+void* AllocateConstSize();
+
+// Frees a chunk of memory previously allocated via Allocate functions.
+// Does nothing if #ptr is null.
+void Free(void* ptr);
+
+// Similar to #Free but assumes that #ptr is not null.
+void FreeNonNull(void* ptr);
+
+// Returns the size of the chunk pointed to by #ptr.
+// This size is not guaranteed to be exactly equal to #size passed to allocation functions
+// due to rounding; the returned size, however, is never less than the latter size.
+// If #ptr is null or we are unable to determine the allocation size, then 0 is returned.
+size_t GetAllocationSize(const void* ptr);
+
+// Returns the size of the chunk that will actually be allocated
+// when requesting an allocation of given #size. This is never less than #size.
+size_t GetAllocationSize(size_t size);
+
+////////////////////////////////////////////////////////////////////////////////
+// Memory tagging API
+//
+// Each allocation can be tagged with a number (from 1 to MaxMemoryTag).
+// Setting this to NullMemoryTag disables tagging.
+// Internally, YTAlloc tracks the number of bytes used by each tag.
+//
+// Tagged allocations are somewhat slower. Others (large and huge) are not affected
+// (but for these performance implications are negligible anyway).
+//
+// The current memory tag used for allocations is stored in TLS.
+
+using TMemoryTag = ui32;
+constexpr TMemoryTag NullMemoryTag = 0;
+constexpr TMemoryTag MaxMemoryTag = (1ULL << 22) - 1;
+
+// Updates the current tag value in TLS.
+void SetCurrentMemoryTag(TMemoryTag tag);
+
+// Returns the current tag value from TLS.
+TMemoryTag GetCurrentMemoryTag();
+
+// Returns the memory usage for a given tag.
+// The value is somewhat approxiate and racy.
+size_t GetMemoryUsageForTag(TMemoryTag tag);
+
+// A batched version of GetMemoryUsageForTag.
+void GetMemoryUsageForTags(const TMemoryTag* tags, size_t count, size_t* results);
+
+////////////////////////////////////////////////////////////////////////////////
+// Memory zone API
+//
+// Each allocation is either in the "normal zone" or "undumpable zone".
+// The latter indicates that this memory region will be excluded from a coredump
+// should it happen.
+//
+// The current zone used for allocations is stored in TLS.
+
+// Memory zone is used to pass hint to the allocator.
+DEFINE_ENUM(EMemoryZone,
+ ((Unknown) (-1)) // not a valid zone
+ ((Normal) ( 0)) // default memory type
+ ((Undumpable) ( 1)) // memory is omitted from the core dump
+);
+
+// Updates the current zone in TLS.
+void SetCurrentMemoryZone(EMemoryZone zone);
+
+// Returns the current zone from TLS.
+EMemoryZone GetCurrentMemoryZone();
+
+// Returns the zone where #ptr resides;
+// EMemoryZone::Invalid indicates that #ptr is outside of any recognized memory zone.
+EMemoryZone GetAllocationMemoryZone(const void* ptr);
+
+////////////////////////////////////////////////////////////////////////////////
+// When a "timing event" (hiccup) occurs during an allocation,
+// YTAlloc records this event and captures the current fiber id.
+// The latter is provided externally by calling SetCurrentFiberId.
+//
+// This may be helpful to correlate various application-level timings
+// with internal events in YTAlloc.
+//
+// The current fiber id is stored in TLS.
+
+using TFiberId = ui64;
+
+// Updates the current fiber id in TLS.
+void SetCurrentFiberId(TFiberId id);
+
+// Returns the currently assinged fiber id from TLS.
+TFiberId GetCurrentFiberId();
+
+////////////////////////////////////////////////////////////////////////////////
+// Logging
+
+DEFINE_ENUM(ELogEventSeverity,
+ (Debug)
+ (Info)
+ (Warning)
+ (Error)
+);
+
+struct TLogEvent
+{
+ ELogEventSeverity Severity;
+ TStringBuf Message;
+};
+
+using TLogHandler = void(*)(const TLogEvent& event);
+
+// Sets the handler to be invoked for each log event produced by YTAlloc.
+// Can be called multiple times (but calls to the previous incarnations of the handler
+// are racy).
+void EnableLogging(TLogHandler logHandler);
+
+////////////////////////////////////////////////////////////////////////////////
+// Backtraces
+
+using TBacktraceProvider = int(*)(void** frames, int maxFrames, int skipFrames);
+
+// Sets the provider used for collecting backtraces when allocation profiling
+// is turned ON. Can be called multiple times (but calls to the previous
+// incarnations of the provider are racy).
+void SetBacktraceProvider(TBacktraceProvider provider);
+
+using TBacktraceFormatter = TString(*)(const void* const* frames, int frameCount);
+
+// Sets the callback used for formatting backtraces during large arena mmap calls
+// to help detect memory leaks. Can be called multiple times (but calls to the
+// previous incarnations of the provider are racy).
+void SetBacktraceFormatter(TBacktraceFormatter provider);
+
+////////////////////////////////////////////////////////////////////////////////
+// Misc
+
+//! Tries to mlock all opened file mappings of the current process.
+//! Typically invoked on application startup to lock all binaries in memory
+//! and prevent executable code and static data to be paged out
+//! causing latency spikes.
+void MlockFileMappings(bool populate = true);
+
+////////////////////////////////////////////////////////////////////////////////
+// Configuration API
+
+// Calling this function enables periodic calls to madvise(ADV_STOCKPILE);
+// cf. https://st.yandex-team.ru/KERNEL-186
+void EnableStockpile();
+
+// Sets the interval between madvise(ADV_STOCKPILE) calls.
+// Only makes sense if stockpile was enabled.
+void SetStockpileInterval(TDuration value);
+
+// Sets the number of threads to be invoking madvise(ADV_STOCKPILE).
+// This call should be made before calling #EnableStockpile.
+void SetStockpileThreadCount(int value);
+
+// Sets the size passsed to madvise(ADV_STOCKPILE) calls.
+// Only makes sense if stockpile was enabled.
+void SetStockpileSize(size_t value);
+
+// For large blobs, YTAlloc keeps at least
+// LargeUnreclaimableCoeff * TotalLargeBytesUsed clamped to range
+// [MinLargeUnreclaimableBytes, MaxLargeUnreclaimableBytes]
+// bytes of pooled (unreclaimable) memory.
+void SetLargeUnreclaimableCoeff(double value);
+void SetMinLargeUnreclaimableBytes(size_t value);
+void SetMaxLargeUnreclaimableBytes(size_t value);
+
+// When a syscall (mmap, munmap, or madvise) or an internal lock acquisition
+// takes longer then the configured time, a "timing event" is recorded.
+void SetTimingEventThreshold(TDuration value);
+
+// Toggles the global allocation profiling knob (OFF by default).
+// For profiled allocations, YTAlloc collects (see #SetBacktraceProvider) and aggregates their
+// backtraces.
+void SetAllocationProfilingEnabled(bool value);
+
+// Determines the fraction of allocations to be sampled for profiling.
+void SetAllocationProfilingSamplingRate(double rate);
+
+// Controls if small allocations of a given rank are profiled (OFF by default).
+void SetSmallArenaAllocationProfilingEnabled(size_t rank, bool value);
+
+// Controls if large allocations of a given rank are profiled (OFF by default).
+void SetLargeArenaAllocationProfilingEnabled(size_t rank, bool value);
+
+// Controls the depth of the backtraces to collect. Deeper backtraces
+// take more time and affect the program performance.
+void SetProfilingBacktraceDepth(int depth);
+
+// Controls the minimum number of bytes a certain backtrace must
+// allocate to appear in profiling reports.
+void SetMinProfilingBytesUsedToReport(size_t size);
+
+// If set to true (default), YTAlloc uses madvise with MADV_DONTNEED to release unused large blob pages
+// (slower but leads to more predicable RSS values);
+// if false then MADV_FREE is used instead, if available
+// (faster but RSS may get stuck arbitrary higher than the actual usage as long
+// as no memory pressure is applied).
+void SetEnableEagerMemoryRelease(bool value);
+
+// If set to true, YTAlloc uses madvise with MADV_POPULATE to prefault freshly acclaimed pages.
+// Otherwise (this is the default), these pages are prefaulted with linear memory access.
+// See https://st.yandex-team.ru/KERNEL-185.
+void SetEnableMadvisePopulate(bool value);
+
+////////////////////////////////////////////////////////////////////////////////
+// Statistics API
+
+DEFINE_ENUM(EBasicCounter,
+ (BytesAllocated)
+ (BytesFreed)
+ (BytesUsed)
+);
+
+using ESystemCounter = EBasicCounter;
+using ESmallCounter = EBasicCounter;
+using ELargeCounter = EBasicCounter;
+using EUndumpableCounter = EBasicCounter;
+
+DEFINE_ENUM(ESmallArenaCounter,
+ (PagesMapped)
+ (BytesMapped)
+ (PagesCommitted)
+ (BytesCommitted)
+);
+
+DEFINE_ENUM(ELargeArenaCounter,
+ (BytesSpare)
+ (BytesOverhead)
+ (BlobsAllocated)
+ (BlobsFreed)
+ (BlobsUsed)
+ (BytesAllocated)
+ (BytesFreed)
+ (BytesUsed)
+ (ExtentsAllocated)
+ (PagesMapped)
+ (BytesMapped)
+ (PagesPopulated)
+ (BytesPopulated)
+ (PagesReleased)
+ (BytesReleased)
+ (PagesCommitted)
+ (BytesCommitted)
+ (OverheadBytesReclaimed)
+ (SpareBytesReclaimed)
+);
+
+DEFINE_ENUM(EHugeCounter,
+ (BytesAllocated)
+ (BytesFreed)
+ (BytesUsed)
+ (BlobsAllocated)
+ (BlobsFreed)
+ (BlobsUsed)
+);
+
+DEFINE_ENUM(ETotalCounter,
+ (BytesAllocated)
+ (BytesFreed)
+ (BytesUsed)
+ (BytesCommitted)
+ (BytesUnaccounted)
+);
+
+// Returns statistics for all user allocations.
+TEnumIndexedVector<ETotalCounter, ssize_t> GetTotalAllocationCounters();
+
+// Returns statistics for small allocations; these are included into total statistics.
+TEnumIndexedVector<ESmallCounter, ssize_t> GetSmallAllocationCounters();
+
+// Returns statistics for large allocations; these are included into total statistics.
+TEnumIndexedVector<ELargeCounter, ssize_t> GetLargeAllocationCounters();
+
+// Returns per-arena statistics for small allocations; these are included into total statistics.
+std::array<TEnumIndexedVector<ESmallArenaCounter, ssize_t>, SmallRankCount> GetSmallArenaAllocationCounters();
+
+// Returns per-arena statistics for large allocations; these are included into total statistics.
+std::array<TEnumIndexedVector<ELargeArenaCounter, ssize_t>, LargeRankCount> GetLargeArenaAllocationCounters();
+
+// Returns statistics for huge allocations; these are included into total statistics.
+TEnumIndexedVector<EHugeCounter, ssize_t> GetHugeAllocationCounters();
+
+// Returns statistics for all system allocations; these are not included into total statistics.
+TEnumIndexedVector<ESystemCounter, ssize_t> GetSystemAllocationCounters();
+
+// Returns statistics for undumpable allocations.
+TEnumIndexedVector<EUndumpableCounter, ssize_t> GetUndumpableAllocationCounters();
+
+DEFINE_ENUM(ETimingEventType,
+ (Mmap)
+ (Munmap)
+ (MadvisePopulate)
+ (MadviseFree)
+ (MadviseDontNeed)
+ (Locking)
+ (Prefault)
+ (FilePrefault)
+);
+
+struct TTimingEventCounters
+{
+ // Number of events happened since start.
+ size_t Count = 0;
+ // Total size of memory blocks involved in these events (if applicable).
+ size_t Size = 0;
+};
+
+// Returns statistics for timing events happened since start.
+// See SetTimingEventThreshold.
+TEnumIndexedVector<ETimingEventType, TTimingEventCounters> GetTimingEventCounters();
+
+////////////////////////////////////////////////////////////////////////////////
+
+// We never collect backtraces deeper than this limit.
+constexpr int MaxAllocationProfilingBacktraceDepth = 16;
+
+struct TBacktrace
+{
+ int FrameCount;
+ std::array<void*, MaxAllocationProfilingBacktraceDepth> Frames;
+};
+
+struct TProfiledAllocation
+{
+ TBacktrace Backtrace;
+ TEnumIndexedVector<EBasicCounter, ssize_t> Counters;
+};
+
+// Returns statistics for profiled allocations (available when allocation
+// profiling is ON). Allocations are grouped by backtrace; for each backtrace
+// we provide the counters indicating the number of allocated, freed, and used bytes.
+// To appear here, used bytes counter must be at least the value configured
+// via SetMinProfilingBytesUsedToReport.
+std::vector<TProfiledAllocation> GetProfiledAllocationStatistics();
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! An RAII guard for setting the current memory tag in a scope.
+class TMemoryTagGuard
+{
+public:
+ TMemoryTagGuard();
+ explicit TMemoryTagGuard(TMemoryTag tag);
+
+ TMemoryTagGuard(const TMemoryTagGuard& other) = delete;
+ TMemoryTagGuard(TMemoryTagGuard&& other);
+
+ ~TMemoryTagGuard();
+
+private:
+ bool Active_;
+ TMemoryTag PreviousTag_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT::NYTAlloc
+
+#define YT_ALLOC_INL_H_
+#include "ytalloc-inl.h"
+#undef YT_ALLOC_INL_H_
diff --git a/library/cpp/ytalloc/ya.make b/library/cpp/ytalloc/ya.make
new file mode 100644
index 0000000000..97aa73c135
--- /dev/null
+++ b/library/cpp/ytalloc/ya.make
@@ -0,0 +1,17 @@
+OWNER(g:yt)
+
+IF (NOT OS_DARWIN AND NOT SANITIZER_TYPE)
+ SET(YT_ALLOC_ENABLED yes)
+ENDIF()
+
+RECURSE(
+ api
+ impl
+)
+
+IF (YT_ALLOC_ENABLED)
+ RECURSE(
+ ut
+ benchmarks
+ )
+ENDIF()
diff --git a/library/python/certifi/.dist-info/METADATA b/library/python/certifi/.dist-info/METADATA
new file mode 100644
index 0000000000..4849f81ed4
--- /dev/null
+++ b/library/python/certifi/.dist-info/METADATA
@@ -0,0 +1,2 @@
+Name: certifi
+Version: 2019.7.1
diff --git a/library/python/certifi/.dist-info/top_level.txt b/library/python/certifi/.dist-info/top_level.txt
new file mode 100644
index 0000000000..963eac530b
--- /dev/null
+++ b/library/python/certifi/.dist-info/top_level.txt
@@ -0,0 +1 @@
+certifi
diff --git a/library/python/certifi/README.md b/library/python/certifi/README.md
new file mode 100644
index 0000000000..75a812733c
--- /dev/null
+++ b/library/python/certifi/README.md
@@ -0,0 +1,7 @@
+This library provides arcadia certs via certifi-compatible API.
+
+In binary (single executable) mode it patches python ssl module to
+support loading certs from memory.
+
+.dist-info/METADATA version reflects the last update time of the
+arcadia certs.
diff --git a/library/python/certifi/certifi/__init__.py b/library/python/certifi/certifi/__init__.py
new file mode 100644
index 0000000000..5270d206cd
--- /dev/null
+++ b/library/python/certifi/certifi/__init__.py
@@ -0,0 +1,10 @@
+import ssl
+
+if hasattr(ssl, 'builtin_cadata'):
+ from .binary import where
+else:
+ from .source import where
+
+__all__ = ['where', '__version__']
+
+__version__ = '2020.04.05.2'
diff --git a/library/python/certifi/certifi/binary.py b/library/python/certifi/certifi/binary.py
new file mode 100644
index 0000000000..1050e733a3
--- /dev/null
+++ b/library/python/certifi/certifi/binary.py
@@ -0,0 +1,25 @@
+import ssl
+
+
+def builtin_ca():
+ return None, None, ssl.builtin_cadata()
+
+
+# Normally certifi.where() returns a path to a certificate file;
+# here it returns a callable.
+def where():
+ return builtin_ca
+
+
+# Patch ssl module to accept a callable cafile.
+load_verify_locations = ssl.SSLContext.load_verify_locations
+
+
+def load_verify_locations__callable(self, cafile=None, capath=None, cadata=None):
+ if callable(cafile):
+ cafile, capath, cadata = cafile()
+
+ return load_verify_locations(self, cafile, capath, cadata)
+
+
+ssl.SSLContext.load_verify_locations = load_verify_locations__callable
diff --git a/library/python/certifi/certifi/source.py b/library/python/certifi/certifi/source.py
new file mode 100644
index 0000000000..f539b67002
--- /dev/null
+++ b/library/python/certifi/certifi/source.py
@@ -0,0 +1,13 @@
+import os.path
+
+pem = os.path.abspath(__file__)
+pem = os.path.dirname(pem)
+pem = os.path.dirname(pem)
+pem = os.path.dirname(pem)
+pem = os.path.dirname(pem)
+pem = os.path.dirname(pem)
+pem = os.path.join(pem, 'certs', 'cacert.pem')
+
+
+def where():
+ return pem
diff --git a/library/python/certifi/ya.make b/library/python/certifi/ya.make
new file mode 100644
index 0000000000..64fefe2833
--- /dev/null
+++ b/library/python/certifi/ya.make
@@ -0,0 +1,18 @@
+PY23_LIBRARY()
+
+OWNER(orivej g:python-contrib)
+
+RESOURCE_FILES(
+ PREFIX library/python/certifi/
+ .dist-info/METADATA
+ .dist-info/top_level.txt
+)
+
+PY_SRCS(
+ TOP_LEVEL
+ certifi/__init__.py
+ certifi/binary.py
+ certifi/source.py
+)
+
+END()
diff --git a/library/python/cores/__init__.py b/library/python/cores/__init__.py
new file mode 100644
index 0000000000..fdb1f82a46
--- /dev/null
+++ b/library/python/cores/__init__.py
@@ -0,0 +1,193 @@
+# coding: utf-8
+
+import os
+import re
+import glob
+import socket
+import logging
+import platform
+import subprocess
+
+import six
+
+from library.python.reservoir_sampling import reservoir_sampling
+
+
+logger = logging.getLogger(__name__)
+
+
+def _read_file(filename):
+ with open(filename) as afile:
+ return afile.read().strip("\n")
+
+
+def recover_core_dump_file(binary_path, cwd, pid):
+
+ class CoreFilePattern(object):
+ def __init__(self, path, mask):
+ self.path = path
+ self.mask = mask
+
+ cwd = cwd or os.getcwd()
+ system = platform.system().lower()
+ if system.startswith("linux"):
+ import stat
+ import resource
+
+ logger.debug("hostname = '%s'", socket.gethostname())
+ logger.debug("rlimit_core = '%s'", str(resource.getrlimit(resource.RLIMIT_CORE)))
+ core_pattern = _read_file("/proc/sys/kernel/core_pattern")
+ logger.debug("core_pattern = '%s'", core_pattern)
+ if core_pattern.startswith("/"):
+ default_pattern = CoreFilePattern(os.path.dirname(core_pattern), '*')
+ else:
+ default_pattern = CoreFilePattern(cwd, '*')
+
+ def resolve_core_mask(core_mask):
+ def resolve(text):
+ if text == "%p":
+ return str(pid)
+ elif text == "%e":
+ # https://github.com/torvalds/linux/blob/7876320f88802b22d4e2daf7eb027dd14175a0f8/include/linux/sched.h#L847
+ # https://github.com/torvalds/linux/blob/7876320f88802b22d4e2daf7eb027dd14175a0f8/fs/coredump.c#L278
+ return os.path.basename(binary_path)[:15]
+ elif text == "%E":
+ return binary_path.replace("/", "!")
+ elif text == "%%":
+ return "%"
+ elif text.startswith("%"):
+ return "*"
+ return text
+
+ parts = filter(None, re.split(r"(%.)", core_mask))
+ return "".join([resolve(p) for p in parts])
+
+ # don't interpret a program for piping core dumps as a pattern
+ if core_pattern and not core_pattern.startswith("|"):
+ default_pattern.mask = os.path.basename(core_pattern)
+ else:
+ core_uses_pid = int(_read_file("/proc/sys/kernel/core_uses_pid"))
+ logger.debug("core_uses_pid = '%d'", core_uses_pid)
+ if core_uses_pid == 0:
+ default_pattern.mask = "core"
+ else:
+ default_pattern.mask = "core.%p"
+
+ # widely distributed core dump dir and mask (see DEVTOOLS-4408)
+ yandex_pattern = CoreFilePattern('/coredumps', '%e.%p.%s')
+ yandex_market_pattern = CoreFilePattern('/var/tmp/cores', 'core.%..%e.%s.%p.*')
+
+ for pattern in [default_pattern, yandex_pattern, yandex_market_pattern]:
+ pattern.mask = resolve_core_mask(pattern.mask)
+
+ if not os.path.exists(pattern.path):
+ logger.warning("Core dump dir doesn't exist: %s", pattern.path)
+ continue
+
+ logger.debug(
+ "Core dump dir (%s) permission mask: %s (expected: %s (%s-dir, %s-sticky bit))",
+ pattern.path,
+ oct(os.stat(pattern.path)[stat.ST_MODE]),
+ oct(stat.S_IFDIR | stat.S_ISVTX | 0o777),
+ oct(stat.S_IFDIR),
+ oct(stat.S_ISVTX),
+ )
+ logger.debug("Search for core dump files match pattern '%s' in '%s'", pattern.mask, pattern.path)
+ cores = glob.glob(os.path.join(pattern.path, pattern.mask))
+ files = os.listdir(pattern.path)
+ logger.debug(
+ "Matched core dump files (%d/%d): [%s] (mismatched samples: %s)",
+ len(cores),
+ len(files),
+ ", ".join(cores),
+ ", ".join(reservoir_sampling(files, 5)),
+ )
+
+ if len(cores) == 1:
+ return cores[0]
+ elif len(cores) > 1:
+ stat = [(filename, os.stat(filename).st_mtime) for filename in cores]
+ entry = sorted(stat, key=lambda x: x[1])[-1]
+ logger.debug("Latest core dump file: '%s' with %d mtime", entry[0], entry[1])
+ return entry[0]
+ else:
+ logger.debug("Core dump file recovering is not supported on '%s'", system)
+ return None
+
+
+def get_gdb_full_backtrace(binary, core, gdb_path):
+ cmd = [
+ gdb_path, binary, core,
+ "--eval-command", "set print thread-events off",
+ "--eval-command", "thread apply all backtrace full",
+ "--batch",
+ "--quiet",
+ ]
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ output, stderr = proc.communicate()
+ output = six.ensure_str(output)
+ if stderr:
+ output += "\nstderr >>\n" + six.ensure_str(stderr)
+ return output
+
+
+def get_problem_stack(backtrace):
+ stack = []
+ found_thread1 = False
+ regex = re.compile(r'[Tt]hread (\d+)')
+
+ for line in backtrace.split("\n"):
+ match = regex.search(line)
+ if match:
+ if found_thread1:
+ break
+ if int(match.group(1)) == 1:
+ found_thread1 = True
+ if found_thread1:
+ stack.append(line)
+
+ if not stack:
+ return backtrace
+ return "\n".join(stack)
+
+
+# XXX
+def colorize_backtrace(text):
+ filters = [
+ # Function names and the class they belong to
+ (re.compile(r"^(#[0-9]+ .*?)([a-zA-Z0-9_:\.@]+)(\s?\()", flags=re.MULTILINE), r"\1[[c:cyan]]\2[[rst]]\3"),
+ # Function argument names
+ (re.compile(r"([a-zA-Z0-9_#]*)(\s?=\s?)"), r"[[c:green]]\1[[rst]]\2"),
+ # Stack frame number
+ (re.compile(r"^(#[0-9]+)", flags=re.MULTILINE), r"[[c:red]]\1[[rst]]"),
+ # Thread id colorization
+ (re.compile(r"^([ \*]) ([0-9]+)", flags=re.MULTILINE), r"[[c:light-cyan]]\1 [[c:red]]\2[[rst]]"),
+ # File path and line number
+ (re.compile(r"(\.*[/A-Za-z0-9\+_\.\-]*):(([0-9]+)(:[0-9]+)?)$", flags=re.MULTILINE), r"[[c:light-grey]]\1[[rst]]:[[c:magenta]]\2[[rst]]"),
+ # Addresses
+ (re.compile(r"\b(0x[a-f0-9]{6,})\b"), r"[[c:light-grey]]\1[[rst]]"),
+ ]
+
+ for regex, substitution in filters:
+ text = regex.sub(substitution, text)
+ return text
+
+
+def resolve_addresses(addresses, symbolizer, binary):
+ addresses = list(set(addresses))
+ cmd = [
+ symbolizer,
+ "-demangle",
+ "-obj",
+ binary,
+ ]
+ proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = proc.communicate(input="\n".join(addresses))
+ if proc.returncode:
+ raise Exception("Symbolizer failed with rc:{}\nstderr: {}".format(proc.returncode, err))
+
+ resolved = filter(None, out.split("\n\n"))
+ if len(addresses) != len(resolved):
+ raise Exception("llvm-symbolizer can not extract lines from addresses (count mismatch: {}-{})".format(len(addresses), len(resolved)))
+
+ return {k: v.strip(" \n") for k, v in zip(addresses, resolved)}
diff --git a/library/python/cores/ya.make b/library/python/cores/ya.make
new file mode 100644
index 0000000000..76264e9cce
--- /dev/null
+++ b/library/python/cores/ya.make
@@ -0,0 +1,15 @@
+OWNER(
+ prettyboy
+ g:yatest
+)
+
+PY23_LIBRARY()
+
+PY_SRCS(__init__.py)
+
+PEERDIR(
+ contrib/python/six
+ library/python/reservoir_sampling
+)
+
+END()
diff --git a/library/python/filelock/__init__.py b/library/python/filelock/__init__.py
new file mode 100644
index 0000000000..f81ff67f37
--- /dev/null
+++ b/library/python/filelock/__init__.py
@@ -0,0 +1,122 @@
+import errno
+import logging
+import os
+import sys
+
+import library.python.windows
+
+logger = logging.getLogger(__name__)
+
+
+def set_close_on_exec(stream):
+ if library.python.windows.on_win():
+ library.python.windows.set_handle_information(stream, inherit=False)
+ else:
+ import fcntl
+ fcntl.fcntl(stream, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
+
+
+class AbstractFileLock(object):
+
+ def __init__(self, path):
+ self.path = path
+
+ def acquire(self, blocking=True):
+ raise NotImplementedError
+
+ def release(self):
+ raise NotImplementedError
+
+ def __enter__(self):
+ self.acquire()
+ return self
+
+ def __exit__(self, type, value, traceback):
+ self.release()
+
+
+class _NixFileLock(AbstractFileLock):
+
+ def __init__(self, path):
+ super(_NixFileLock, self).__init__(path)
+ from fcntl import flock, LOCK_EX, LOCK_UN, LOCK_NB
+ self._locker = lambda lock, blocking: flock(lock, LOCK_EX if blocking else LOCK_EX | LOCK_NB)
+ self._unlocker = lambda lock: flock(lock, LOCK_UN)
+ self._lock = open(self.path, 'a')
+ set_close_on_exec(self._lock)
+
+ def acquire(self, blocking=True):
+ import errno
+ try:
+ self._locker(self._lock, blocking)
+ except IOError as e:
+ if e.errno in (errno.EAGAIN, errno.EACCES) and not blocking:
+ return False
+ raise
+ return True
+
+ def release(self):
+ self._unlocker(self._lock)
+
+ def __del__(self):
+ if hasattr(self, "_lock"):
+ self._lock.close()
+
+
+class _WinFileLock(AbstractFileLock):
+ """
+ Based on LockFile / UnlockFile from win32 API
+ https://msdn.microsoft.com/en-us/library/windows/desktop/aa365202(v=vs.85).aspx
+ """
+
+ _LOCKED_BYTES_NUM = 1
+
+ def __init__(self, path):
+ super(_WinFileLock, self).__init__(path)
+ self._lock = None
+ try:
+ with file(path, 'w') as lock_file:
+ lock_file.write(" " * self._LOCKED_BYTES_NUM)
+ except IOError as e:
+ if e.errno != errno.EACCES or not os.path.isfile(path):
+ raise
+
+ def acquire(self, blocking=True):
+ self._lock = open(self.path)
+ set_close_on_exec(self._lock)
+
+ import time
+ locked = False
+ while not locked:
+ locked = library.python.windows.lock_file(self._lock, 0, self._LOCKED_BYTES_NUM, raises=False)
+ if locked:
+ return True
+ if blocking:
+ time.sleep(.5)
+ else:
+ return False
+
+ def release(self):
+ if self._lock:
+ library.python.windows.unlock_file(self._lock, 0, self._LOCKED_BYTES_NUM, raises=False)
+ self._lock.close()
+ self._lock = None
+
+
+class FileLock(AbstractFileLock):
+
+ def __init__(self, path):
+ super(FileLock, self).__init__(path)
+
+ if sys.platform.startswith('win'):
+ self._lock = _WinFileLock(path)
+ else:
+ self._lock = _NixFileLock(path)
+
+ def acquire(self, blocking=True):
+ logger.debug('Acquiring filelock (blocking=%s): %s', blocking, self.path)
+ return self._lock.acquire(blocking)
+
+ def release(self):
+ logger.debug('Ensuring filelock released: %s', self.path)
+ return self._lock.release()
diff --git a/library/python/filelock/ut/lib/test_filelock.py b/library/python/filelock/ut/lib/test_filelock.py
new file mode 100644
index 0000000000..1b11d89123
--- /dev/null
+++ b/library/python/filelock/ut/lib/test_filelock.py
@@ -0,0 +1,83 @@
+import os
+import time
+import logging
+import multiprocessing
+import tempfile
+import threading
+
+import library.python.filelock
+
+
+def _acquire_lock(lock_path, out_file_path):
+ with library.python.filelock.FileLock(lock_path):
+ with open(out_file_path, "a") as out:
+ out.write("{}:{}\n".format(os.getpid(), time.time()))
+ time.sleep(2)
+
+
+def test_filelock():
+ temp_dir = tempfile.mkdtemp()
+ lock_path = os.path.join(temp_dir, "file.lock")
+ out_file_path = os.path.join(temp_dir, "out.txt")
+
+ process_count = 5
+ processes = []
+ for i in range(process_count):
+ process = multiprocessing.Process(target=_acquire_lock, args=(lock_path, out_file_path))
+ process.start()
+ processes.append(process)
+
+ for process in processes:
+ process.join()
+
+ pids = []
+ times = []
+ with open(out_file_path) as out:
+ content = out.read()
+ logging.info("Times:\n%s", content)
+ for line in content.strip().split("\n"):
+ pid, time_val = line.split(":")
+ pids.append(pid)
+ times.append(float(time_val))
+
+ assert len(set(pids)) == process_count
+ time1 = times.pop()
+ while times:
+ time2 = times.pop()
+ assert int(time1) - int(time2) >= 2
+ time1 = time2
+
+
+def test_filelock_init_acquired():
+ temp_dir = tempfile.mkdtemp()
+ lock_path = os.path.join(temp_dir, "file.lock")
+
+ with library.python.filelock.FileLock(lock_path):
+ sublock = library.python.filelock.FileLock(lock_path)
+ del sublock
+
+
+def test_concurrent_lock():
+ filename = 'con.lock'
+
+ def lock():
+ l = library.python.filelock.FileLock(filename)
+ time.sleep(1)
+ l.acquire()
+ l.release()
+ try:
+ os.unlink(filename)
+ except OSError:
+ pass
+
+ threads = []
+ for i in range(100):
+ t = threading.Thread(target=lock)
+ t.daemon = True
+ threads.append(t)
+
+ for t in threads:
+ t.start()
+
+ for t in threads:
+ t.join()
diff --git a/library/python/filelock/ut/lib/ya.make b/library/python/filelock/ut/lib/ya.make
new file mode 100644
index 0000000000..f3f9da5a67
--- /dev/null
+++ b/library/python/filelock/ut/lib/ya.make
@@ -0,0 +1,11 @@
+OWNER(g:yatool)
+
+PY23_LIBRARY()
+
+TEST_SRCS(test_filelock.py)
+
+PEERDIR(
+ library/python/filelock
+)
+
+END()
diff --git a/library/python/filelock/ut/py2/ya.make b/library/python/filelock/ut/py2/ya.make
new file mode 100644
index 0000000000..30b54e0232
--- /dev/null
+++ b/library/python/filelock/ut/py2/ya.make
@@ -0,0 +1,9 @@
+OWNER(g:yatool)
+
+PY2TEST()
+
+PEERDIR(
+ library/python/filelock/ut/lib
+)
+
+END()
diff --git a/library/python/filelock/ut/py3/ya.make b/library/python/filelock/ut/py3/ya.make
new file mode 100644
index 0000000000..05a856a19a
--- /dev/null
+++ b/library/python/filelock/ut/py3/ya.make
@@ -0,0 +1,9 @@
+OWNER(g:yatool)
+
+PY3TEST()
+
+PEERDIR(
+ library/python/filelock/ut/lib
+)
+
+END()
diff --git a/library/python/filelock/ut/ya.make b/library/python/filelock/ut/ya.make
new file mode 100644
index 0000000000..9280ea415e
--- /dev/null
+++ b/library/python/filelock/ut/ya.make
@@ -0,0 +1,7 @@
+OWNER(g:yatool)
+
+RECURSE(
+ lib
+ py2
+ py3
+)
diff --git a/library/python/filelock/ya.make b/library/python/filelock/ya.make
new file mode 100644
index 0000000000..958cc1866f
--- /dev/null
+++ b/library/python/filelock/ya.make
@@ -0,0 +1,11 @@
+OWNER(g:yatool)
+
+PY23_LIBRARY()
+
+PY_SRCS(__init__.py)
+
+PEERDIR(
+ library/python/windows
+)
+
+END()
diff --git a/library/python/find_root/__init__.py b/library/python/find_root/__init__.py
new file mode 100644
index 0000000000..6da604d62e
--- /dev/null
+++ b/library/python/find_root/__init__.py
@@ -0,0 +1,20 @@
+import os
+
+
+def is_root(path):
+ return os.path.exists(os.path.join(path, ".arcadia.root")) or os.path.exists(os.path.join(path, 'devtools', 'ya', 'ya.conf.json'))
+
+
+def detect_root(path, detector=is_root):
+ return _find_path(path, detector)
+
+
+def _find_path(starts_from, check):
+ p = os.path.realpath(starts_from)
+ while True:
+ if check(p):
+ return p
+ next_p = os.path.dirname(p)
+ if next_p == p:
+ return None
+ p = next_p
diff --git a/library/python/find_root/ya.make b/library/python/find_root/ya.make
new file mode 100644
index 0000000000..beaa8e3c52
--- /dev/null
+++ b/library/python/find_root/ya.make
@@ -0,0 +1,7 @@
+PY23_LIBRARY()
+
+OWNER(g:yatool)
+
+PY_SRCS(__init__.py)
+
+END()
diff --git a/library/python/fs/__init__.py b/library/python/fs/__init__.py
new file mode 100644
index 0000000000..b1b7cde079
--- /dev/null
+++ b/library/python/fs/__init__.py
@@ -0,0 +1,501 @@
+# coding: utf-8
+
+import codecs
+import errno
+import logging
+import os
+import random
+import shutil
+import six
+import stat
+import sys
+
+import library.python.func
+import library.python.strings
+import library.python.windows
+
+logger = logging.getLogger(__name__)
+
+
+try:
+ WindowsError
+except NameError:
+ WindowsError = None
+
+
+_diehard_win_tries = 10
+errorfix_win = library.python.windows.errorfix
+
+
+class CustomFsError(OSError):
+ def __init__(self, errno, message='', filename=None):
+ super(CustomFsError, self).__init__(message)
+ self.errno = errno
+ self.strerror = os.strerror(errno)
+ self.filename = filename
+
+
+# Directories creation
+# If dst is already exists and is a directory - does nothing
+# Throws OSError
+@errorfix_win
+def ensure_dir(path):
+ try:
+ os.makedirs(path)
+ except OSError as e:
+ if e.errno != errno.EEXIST or not os.path.isdir(path):
+ raise
+
+
+# Directories creation
+# If dst is already exists and is a directory - does nothing
+# Returns path
+# Throws OSError
+@errorfix_win
+def create_dirs(path):
+ ensure_dir(path)
+ return path
+
+
+# Atomic file/directory move (rename)
+# Doesn't guarantee dst replacement
+# Atomic if no device boundaries are crossed
+# Depends on ctypes on Windows
+# Throws OSError
+# On Unix, if dst exists:
+# if dst is file or empty dir - replaces it
+# if src is dir and dst is not dir - throws OSError (errno ENOTDIR)
+# if src is dir and dst is non-empty dir - throws OSError (errno ENOTEMPTY)
+# if src is file and dst is dir - throws OSError (errno EISDIR)
+# On Windows, if dst exists - throws OSError (errno EEXIST)
+@errorfix_win
+@library.python.windows.diehard(library.python.windows.RETRIABLE_FILE_ERRORS, tries=_diehard_win_tries)
+def move(src, dst):
+ os.rename(src, dst)
+
+
+# Atomic replacing file move (rename)
+# Replaces dst if exists and not a dir
+# Doesn't guarantee dst dir replacement
+# Atomic if no device boundaries are crossed
+# Depends on ctypes on Windows
+# Throws OSError
+# On Unix, if dst exists:
+# if dst is file - replaces it
+# if dst is dir - throws OSError (errno EISDIR)
+# On Windows, if dst exists:
+# if dst is file - replaces it
+# if dst is dir - throws OSError (errno EACCES)
+@errorfix_win
+@library.python.windows.diehard(library.python.windows.RETRIABLE_FILE_ERRORS, tries=_diehard_win_tries)
+def replace_file(src, dst):
+ if library.python.windows.on_win():
+ library.python.windows.replace_file(src, dst)
+ else:
+ os.rename(src, dst)
+
+
+# File/directory replacing move (rename)
+# Removes dst if exists
+# Non-atomic
+# Depends on ctypes on Windows
+# Throws OSError
+@errorfix_win
+def replace(src, dst):
+ try:
+ move(src, dst)
+ except OSError as e:
+ if e.errno not in (errno.EEXIST, errno.EISDIR, errno.ENOTDIR, errno.ENOTEMPTY):
+ raise
+ remove_tree(dst)
+ move(src, dst)
+
+
+# Atomic file remove
+# Throws OSError
+@errorfix_win
+@library.python.windows.diehard(library.python.windows.RETRIABLE_FILE_ERRORS, tries=_diehard_win_tries)
+def remove_file(path):
+ os.remove(path)
+
+
+# Atomic empty directory remove
+# Throws OSError
+@errorfix_win
+@library.python.windows.diehard(library.python.windows.RETRIABLE_DIR_ERRORS, tries=_diehard_win_tries)
+def remove_dir(path):
+ os.rmdir(path)
+
+
+def fix_path_encoding(path):
+ return library.python.strings.to_str(path, library.python.strings.fs_encoding())
+
+
+# File/directory remove
+# Non-atomic
+# Throws OSError, AssertionError
+@errorfix_win
+def remove_tree(path):
+ @library.python.windows.diehard(library.python.windows.RETRIABLE_DIR_ERRORS, tries=_diehard_win_tries)
+ def rmtree(path):
+ if library.python.windows.on_win():
+ library.python.windows.rmtree(path)
+ else:
+ shutil.rmtree(fix_path_encoding(path))
+
+ st = os.lstat(path)
+ if stat.S_ISLNK(st.st_mode) or stat.S_ISREG(st.st_mode):
+ remove_file(path)
+ elif stat.S_ISDIR(st.st_mode):
+ rmtree(path)
+ else:
+ assert False
+
+
+# File/directory remove ignoring errors
+# Non-atomic
+@errorfix_win
+def remove_tree_safe(path):
+ try:
+ st = os.lstat(path)
+ if stat.S_ISLNK(st.st_mode) or stat.S_ISREG(st.st_mode):
+ os.remove(path)
+ elif stat.S_ISDIR(st.st_mode):
+ shutil.rmtree(fix_path_encoding(path), ignore_errors=True)
+ # XXX
+ except UnicodeDecodeError as e:
+ logging.exception(u'remove_tree_safe with argument %s raise exception: %s', path, e)
+ raise
+ except OSError:
+ pass
+
+
+# File/directory remove
+# If path doesn't exist - does nothing
+# Non-atomic
+# Throws OSError, AssertionError
+@errorfix_win
+def ensure_removed(path):
+ try:
+ remove_tree(path)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ raise
+
+
+# Atomic file hardlink
+# Dst must not exist
+# Depends on ctypes on Windows
+# Throws OSError
+# If dst exists - throws OSError (errno EEXIST)
+@errorfix_win
+def hardlink(src, lnk):
+ if library.python.windows.on_win():
+ library.python.windows.hardlink(src, lnk)
+ else:
+ os.link(src, lnk)
+
+
+@errorfix_win
+def hardlink_or_copy(src, lnk):
+ def should_fallback_to_copy(exc):
+ if WindowsError is not None and isinstance(exc, WindowsError) and exc.winerror == 1142: # too many hardlinks
+ return True
+ # cross-device hardlink or too many hardlinks, or some known WSL error
+ if isinstance(exc, OSError) and exc.errno in (
+ errno.EXDEV,
+ errno.EMLINK,
+ errno.EINVAL,
+ errno.EACCES,
+ errno.EPERM,
+ ):
+ return True
+ return False
+
+ try:
+ hardlink(src, lnk)
+ except Exception as e:
+ logger.debug('Failed to hardlink %s to %s with error %s, will copy it', src, lnk, repr(e))
+ if should_fallback_to_copy(e):
+ copy2(src, lnk, follow_symlinks=False)
+ else:
+ raise
+
+
+# Atomic file/directory symlink (Unix only)
+# Dst must not exist
+# Throws OSError
+# If dst exists - throws OSError (errno EEXIST)
+@errorfix_win
+def symlink(src, lnk):
+ if library.python.windows.on_win():
+ library.python.windows.run_disabled(src, lnk)
+ else:
+ os.symlink(src, lnk)
+
+
+# shutil.copy2 with follow_symlinks=False parameter (Unix only)
+def copy2(src, lnk, follow_symlinks=True):
+ if six.PY3:
+ shutil.copy2(src, lnk, follow_symlinks=follow_symlinks)
+ return
+
+ if follow_symlinks or not os.path.islink(src):
+ shutil.copy2(src, lnk)
+ return
+
+ symlink(os.readlink(src), lnk)
+
+
+# Recursively hardlink directory
+# Uses plain hardlink for files
+# Dst must not exist
+# Non-atomic
+# Throws OSError
+@errorfix_win
+def hardlink_tree(src, dst):
+ if not os.path.exists(src):
+ raise CustomFsError(errno.ENOENT, filename=src)
+ if os.path.isfile(src):
+ hardlink(src, dst)
+ return
+ for dirpath, _, filenames in walk_relative(src):
+ src_dirpath = os.path.join(src, dirpath) if dirpath != '.' else src
+ dst_dirpath = os.path.join(dst, dirpath) if dirpath != '.' else dst
+ os.mkdir(dst_dirpath)
+ for filename in filenames:
+ hardlink(os.path.join(src_dirpath, filename), os.path.join(dst_dirpath, filename))
+
+
+# File copy
+# throws EnvironmentError (OSError, IOError)
+@errorfix_win
+def copy_file(src, dst, copy_function=shutil.copy2):
+ if os.path.isdir(dst):
+ raise CustomFsError(errno.EISDIR, filename=dst)
+ copy_function(src, dst)
+
+
+# File/directory copy
+# throws EnvironmentError (OSError, IOError, shutil.Error)
+@errorfix_win
+def copy_tree(src, dst, copy_function=shutil.copy2):
+ if os.path.isfile(src):
+ copy_file(src, dst, copy_function=copy_function)
+ return
+ copytree3(src, dst, copy_function=copy_function)
+
+
+# File read
+# Throws OSError
+@errorfix_win
+def read_file(path, binary=True):
+ with open(path, 'r' + ('b' if binary else '')) as f:
+ return f.read()
+
+
+# Decoding file read
+# Throws OSError
+@errorfix_win
+def read_file_unicode(path, binary=True, enc='utf-8'):
+ if not binary:
+ if six.PY2:
+ with open(path, 'r') as f:
+ return library.python.strings.to_unicode(f.read(), enc)
+ else:
+ with open(path, 'r', encoding=enc) as f:
+ return f.read()
+ # codecs.open is always binary
+ with codecs.open(path, 'r', encoding=enc, errors=library.python.strings.ENCODING_ERRORS_POLICY) as f:
+ return f.read()
+
+
+@errorfix_win
+def open_file(*args, **kwargs):
+ return (
+ library.python.windows.open_file(*args, **kwargs) if library.python.windows.on_win() else open(*args, **kwargs)
+ )
+
+
+# Atomic file write
+# Throws OSError
+@errorfix_win
+def write_file(path, data, binary=True):
+ dir_path = os.path.dirname(path)
+ if dir_path:
+ ensure_dir(dir_path)
+ tmp_path = path + '.tmp.' + str(random.random())
+ with open_file(tmp_path, 'w' + ('b' if binary else '')) as f:
+ if not isinstance(data, bytes) and binary:
+ data = data.encode('UTF-8')
+ f.write(data)
+ replace_file(tmp_path, path)
+
+
+# File size
+# Throws OSError
+@errorfix_win
+def get_file_size(path):
+ return os.path.getsize(path)
+
+
+# File/directory size
+# Non-recursive mode for directory counts size for immediates
+# While raise_all_errors is set to False, file size fallbacks to zero in case of getsize errors
+# Throws OSError
+@errorfix_win
+def get_tree_size(path, recursive=False, raise_all_errors=False):
+ if os.path.isfile(path):
+ return get_file_size(path)
+ total_size = 0
+ for dir_path, _, files in os.walk(path):
+ for f in files:
+ fp = os.path.join(dir_path, f)
+ try:
+ total_size += get_file_size(fp)
+ except OSError as e:
+ if raise_all_errors:
+ raise
+ logger.debug("Cannot calculate file size: %s", e)
+ if not recursive:
+ break
+ return total_size
+
+
+# Directory copy ported from Python 3
+def copytree3(
+ src,
+ dst,
+ symlinks=False,
+ ignore=None,
+ copy_function=shutil.copy2,
+ ignore_dangling_symlinks=False,
+ dirs_exist_ok=False,
+):
+ """Recursively copy a directory tree.
+
+ The copytree3 is a port of shutil.copytree function from python-3.2.
+ It has additional useful parameters and may be helpful while we are
+ on python-2.x. It has to be removed as soon as we have moved to
+ python-3.2 or higher.
+
+ The destination directory must not already exist.
+ If exception(s) occur, an Error is raised with a list of reasons.
+
+ If the optional symlinks flag is true, symbolic links in the
+ source tree result in symbolic links in the destination tree; if
+ it is false, the contents of the files pointed to by symbolic
+ links are copied. If the file pointed by the symlink doesn't
+ exist, an exception will be added in the list of errors raised in
+ an Error exception at the end of the copy process.
+
+ You can set the optional ignore_dangling_symlinks flag to true if you
+ want to silence this exception. Notice that this has no effect on
+ platforms that don't support os.symlink.
+
+ The optional ignore argument is a callable. If given, it
+ is called with the `src` parameter, which is the directory
+ being visited by copytree3(), and `names` which is the list of
+ `src` contents, as returned by os.listdir():
+
+ callable(src, names) -> ignored_names
+
+ Since copytree3() is called recursively, the callable will be
+ called once for each directory that is copied. It returns a
+ list of names relative to the `src` directory that should
+ not be copied.
+
+ The optional copy_function argument is a callable that will be used
+ to copy each file. It will be called with the source path and the
+ destination path as arguments. By default, copy2() is used, but any
+ function that supports the same signature (like copy()) can be used.
+
+ """
+ names = os.listdir(src)
+ if ignore is not None:
+ ignored_names = ignore(src, names)
+ else:
+ ignored_names = set()
+
+ if not (dirs_exist_ok and os.path.isdir(dst)):
+ os.makedirs(dst)
+
+ errors = []
+ for name in names:
+ if name in ignored_names:
+ continue
+ srcname = os.path.join(src, name)
+ dstname = os.path.join(dst, name)
+ try:
+ if os.path.islink(srcname):
+ linkto = os.readlink(srcname)
+ if symlinks:
+ # We can't just leave it to `copy_function` because legacy
+ # code with a custom `copy_function` may rely on copytree3
+ # doing the right thing.
+ os.symlink(linkto, dstname)
+ else:
+ # ignore dangling symlink if the flag is on
+ if not os.path.exists(linkto) and ignore_dangling_symlinks:
+ continue
+ # otherwise let the copy occurs. copy2 will raise an error
+ copy_function(srcname, dstname)
+ elif os.path.isdir(srcname):
+ copytree3(srcname, dstname, symlinks, ignore, copy_function, dirs_exist_ok=dirs_exist_ok)
+ else:
+ # Will raise a SpecialFileError for unsupported file types
+ copy_function(srcname, dstname)
+ # catch the Error from the recursive copytree3 so that we can
+ # continue with other files
+ except shutil.Error as err:
+ errors.extend(err.args[0])
+ except EnvironmentError as why:
+ errors.append((srcname, dstname, str(why)))
+ try:
+ shutil.copystat(src, dst)
+ except OSError as why:
+ if WindowsError is not None and isinstance(why, WindowsError):
+ # Copying file access times may fail on Windows
+ pass
+ else:
+ errors.extend((src, dst, str(why)))
+ if errors:
+ raise shutil.Error(errors)
+
+
+def walk_relative(path, topdown=True, onerror=None, followlinks=False):
+ for dirpath, dirnames, filenames in os.walk(path, topdown=topdown, onerror=onerror, followlinks=followlinks):
+ yield os.path.relpath(dirpath, path), dirnames, filenames
+
+
+def supports_clone():
+ if 'darwin' in sys.platform:
+ import platform
+
+ return list(map(int, platform.mac_ver()[0].split('.'))) >= [10, 13]
+ return False
+
+
+def commonpath(paths):
+ assert paths
+ if len(paths) == 1:
+ return next(iter(paths))
+
+ split_paths = [path.split(os.sep) for path in paths]
+ smin = min(split_paths)
+ smax = max(split_paths)
+
+ common = smin
+ for i, c in enumerate(smin):
+ if c != smax[i]:
+ common = smin[:i]
+ break
+
+ return os.path.sep.join(common)
+
+
+def set_execute_bits(filename):
+ stm = os.stat(filename).st_mode
+ exe = stm | 0o111
+ if stm != exe:
+ os.chmod(filename, exe)
diff --git a/library/python/fs/clonefile.pyx b/library/python/fs/clonefile.pyx
new file mode 100644
index 0000000000..830bb894f2
--- /dev/null
+++ b/library/python/fs/clonefile.pyx
@@ -0,0 +1,18 @@
+import six
+
+cdef extern from "sys/clonefile.h" nogil:
+ int clonefile(const char * src, const char * dst, int flags)
+
+cdef extern from "Python.h":
+ ctypedef struct PyObject
+ cdef PyObject *PyExc_OSError
+ PyObject *PyErr_SetFromErrno(PyObject *)
+
+cdef int _macos_clone_file(const char* src, const char* dst) except? 0:
+ if clonefile(src, dst, 0) == -1:
+ PyErr_SetFromErrno(PyExc_OSError)
+ return 0
+ return 1
+
+def macos_clone_file(src, dst):
+ return _macos_clone_file(six.ensure_binary(src), six.ensure_binary(dst)) != 0
diff --git a/library/python/fs/test/test_fs.py b/library/python/fs/test/test_fs.py
new file mode 100644
index 0000000000..9e2c70c069
--- /dev/null
+++ b/library/python/fs/test/test_fs.py
@@ -0,0 +1,1037 @@
+# coding=utf-8
+
+import errno
+import os
+import pytest
+import shutil
+import six
+
+import library.python.fs
+import library.python.strings
+import library.python.tmp
+import library.python.windows
+
+import yatest.common
+
+
+def in_env(case):
+ def wrapped_case(*args, **kwargs):
+ with library.python.tmp.temp_dir() as temp_dir:
+ case(lambda path: os.path.join(temp_dir, path))
+
+ return wrapped_case
+
+
+def mkfile(path, data=''):
+ with open(path, 'wb') as f:
+ if data:
+ f.write(data) if isinstance(data, six.binary_type) else f.write(
+ data.encode(library.python.strings.fs_encoding())
+ )
+
+
+def mktree_example(path, name):
+ os.mkdir(path(name))
+ mkfile(path(name + '/file1'), 'FILE1')
+ os.mkdir(path(name + '/dir1'))
+ os.mkdir(path(name + '/dir2'))
+ mkfile(path(name + '/dir2/file2'), 'FILE2')
+ mkfile(path(name + '/dir2/file3'), 'FILE3')
+
+
+def file_data(path):
+ with open(path, 'rb') as f:
+ return f.read().decode('utf-8')
+
+
+def serialize_tree(path):
+ if os.path.isfile(path):
+ return file_data(path)
+ data = {'dirs': set(), 'files': {}}
+ for dirpath, dirnames, filenames in os.walk(path):
+ dirpath_rel = os.path.relpath(dirpath, path)
+ if dirpath_rel == '.':
+ dirpath_rel = ''
+ data['dirs'].update(set(os.path.join(dirpath_rel, x) for x in dirnames))
+ data['files'].update({os.path.join(dirpath_rel, x): file_data(os.path.join(dirpath, x)) for x in filenames})
+ return data
+
+
+def trees_equal(dir1, dir2):
+ return serialize_tree(dir1) == serialize_tree(dir2)
+
+
+def inodes_unsupported():
+ return library.python.windows.on_win()
+
+
+def inodes_equal(path1, path2):
+ return os.stat(path1).st_ino == os.stat(path2).st_ino
+
+
+def gen_error_access_denied():
+ if library.python.windows.on_win():
+ err = WindowsError()
+ err.errno = errno.EACCES
+ err.strerror = ''
+ err.winerror = library.python.windows.ERRORS['ACCESS_DENIED']
+ else:
+ err = OSError()
+ err.errno = errno.EACCES
+ err.strerror = os.strerror(err.errno)
+ err.filename = 'unknown/file'
+ raise err
+
+
+def test_errorfix_win():
+ @library.python.fs.errorfix_win
+ def erroneous_func():
+ gen_error_access_denied()
+
+ with pytest.raises(OSError) as errinfo:
+ erroneous_func()
+ assert errinfo.value.errno == errno.EACCES
+ assert errinfo.value.filename == 'unknown/file'
+ # See transcode_error, which encodes strerror, in library/python/windows/__init__.py
+ assert isinstance(errinfo.value.strerror, (six.binary_type, six.text_type))
+ assert errinfo.value.strerror
+
+
+def test_custom_fs_error():
+ with pytest.raises(OSError) as errinfo:
+ raise library.python.fs.CustomFsError(errno.EACCES, filename='some/file')
+ assert errinfo.value.errno == errno.EACCES
+ # See transcode_error, which encodes strerror, in library/python/windows/__init__.py
+ assert isinstance(errinfo.value.strerror, (six.binary_type, six.text_type))
+ assert errinfo.value.filename == 'some/file'
+
+
+@in_env
+def test_ensure_dir(path):
+ library.python.fs.ensure_dir(path('dir/subdir'))
+ assert os.path.isdir(path('dir'))
+ assert os.path.isdir(path('dir/subdir'))
+
+
+@in_env
+def test_ensure_dir_exists(path):
+ os.makedirs(path('dir/subdir'))
+ library.python.fs.ensure_dir(path('dir/subdir'))
+ assert os.path.isdir(path('dir'))
+ assert os.path.isdir(path('dir/subdir'))
+
+
+@in_env
+def test_ensure_dir_exists_partly(path):
+ os.mkdir(path('dir'))
+ library.python.fs.ensure_dir(path('dir/subdir'))
+ assert os.path.isdir(path('dir'))
+ assert os.path.isdir(path('dir/subdir'))
+
+
+@in_env
+def test_ensure_dir_exists_file(path):
+ mkfile(path('dir'))
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.ensure_dir(path('dir/subdir'))
+ # ENOENT on Windows!
+ assert errinfo.value.errno in (errno.ENOTDIR, errno.ENOENT)
+ assert os.path.isfile(path('dir'))
+
+
+@in_env
+def test_create_dirs(path):
+ assert library.python.fs.create_dirs(path('dir/subdir')) == path('dir/subdir')
+ assert os.path.isdir(path('dir'))
+ assert os.path.isdir(path('dir/subdir'))
+
+
+@in_env
+def test_move_file(path):
+ mkfile(path('src'), 'SRC')
+ library.python.fs.move(path('src'), path('dst'))
+ assert not os.path.isfile(path('src'))
+ assert os.path.isfile(path('dst'))
+ assert file_data(path('dst')) == 'SRC'
+
+
+@in_env
+def test_move_file_no_src(path):
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.move(path('src'), path('dst'))
+ assert errinfo.value.errno == errno.ENOENT
+
+
+@in_env
+def test_move_file_exists(path):
+ mkfile(path('src'), 'SRC')
+ mkfile(path('dst'), 'DST')
+ if library.python.windows.on_win():
+ # move is platform-dependent, use replace_file for dst replacement on all platforms
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.move(path('src'), path('dst'))
+ assert errinfo.value.errno == errno.EEXIST
+ assert os.path.isfile(path('src'))
+ assert os.path.isfile(path('dst'))
+ assert file_data(path('dst')) == 'DST'
+ else:
+ library.python.fs.move(path('src'), path('dst'))
+ assert not os.path.isfile(path('src'))
+ assert os.path.isfile(path('dst'))
+ assert file_data(path('dst')) == 'SRC'
+
+
+@in_env
+def test_move_file_exists_dir_empty(path):
+ mkfile(path('src'), 'SRC')
+ os.mkdir(path('dst'))
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.move(path('src'), path('dst'))
+ assert errinfo.value.errno in (errno.EEXIST, errno.EISDIR)
+ assert os.path.isfile(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert not os.path.isfile(path('dst/src'))
+
+
+@in_env
+def test_move_file_exists_dir_nonempty(path):
+ mkfile(path('src'), 'SRC')
+ os.mkdir(path('dst'))
+ mkfile(path('dst/dst_file'))
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.move(path('src'), path('dst'))
+ assert errinfo.value.errno in (errno.EEXIST, errno.EISDIR)
+ assert os.path.isfile(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert os.path.isfile(path('dst/dst_file'))
+ assert not os.path.isfile(path('dst/src'))
+
+
+@in_env
+def test_move_dir(path):
+ os.mkdir(path('src'))
+ mkfile(path('src/src_file'))
+ library.python.fs.move(path('src'), path('dst'))
+ assert not os.path.isdir(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert os.path.isfile(path('dst/src_file'))
+
+
+@in_env
+def test_move_dir_exists_empty(path):
+ os.mkdir(path('src'))
+ mkfile(path('src/src_file'))
+ os.mkdir(path('dst'))
+ if library.python.windows.on_win():
+ # move is platform-dependent, use non-atomic replace for directory replacement
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.move(path('src'), path('dst'))
+ assert errinfo.value.errno == errno.EEXIST
+ assert os.path.isdir(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert not os.path.isfile(path('dst/src_file'))
+ else:
+ library.python.fs.move(path('src'), path('dst'))
+ assert not os.path.isdir(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert os.path.isfile(path('dst/src_file'))
+
+
+@in_env
+def test_move_dir_exists_nonempty(path):
+ os.mkdir(path('src'))
+ mkfile(path('src/src_file'))
+ os.mkdir(path('dst'))
+ mkfile(path('dst/dst_file'))
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.move(path('src'), path('dst'))
+ assert errinfo.value.errno in (errno.EEXIST, errno.ENOTEMPTY)
+ assert os.path.isdir(path('src'))
+ assert os.path.isfile(path('src/src_file'))
+ assert os.path.isdir(path('dst'))
+ assert not os.path.isfile(path('dst/src_file'))
+ assert os.path.isfile(path('dst/dst_file'))
+
+
+@in_env
+def test_move_dir_exists_file(path):
+ os.mkdir(path('src'))
+ mkfile(path('src/src_file'))
+ mkfile(path('dst'), 'DST')
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.move(path('src'), path('dst'))
+ assert errinfo.value.errno in (errno.EEXIST, errno.ENOTDIR)
+ assert os.path.isdir(path('src'))
+ assert os.path.isfile(path('dst'))
+ assert file_data(path('dst')) == 'DST'
+
+
+@in_env
+def test_replace_file(path):
+ mkfile(path('src'), 'SRC')
+ library.python.fs.replace_file(path('src'), path('dst'))
+ assert not os.path.isfile(path('src'))
+ assert os.path.isfile(path('dst'))
+ assert file_data(path('dst')) == 'SRC'
+
+ mkfile(path('src'), 'SRC')
+ library.python.fs.replace(path('src'), path('dst2'))
+ assert not os.path.isfile(path('src'))
+ assert os.path.isfile(path('dst2'))
+ assert file_data(path('dst2')) == 'SRC'
+
+
+@in_env
+def test_replace_file_no_src(path):
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.replace_file(path('src'), path('dst'))
+ assert errinfo.value.errno == errno.ENOENT
+
+ with pytest.raises(OSError) as errinfo2:
+ library.python.fs.replace(path('src'), path('dst2'))
+ assert errinfo2.value.errno == errno.ENOENT
+
+
+@in_env
+def test_replace_file_exists(path):
+ mkfile(path('src'), 'SRC')
+ mkfile(path('dst'), 'DST')
+ library.python.fs.replace_file(path('src'), path('dst'))
+ assert not os.path.isfile(path('src'))
+ assert os.path.isfile(path('dst'))
+ assert file_data(path('dst')) == 'SRC'
+
+ mkfile(path('src'), 'SRC')
+ mkfile(path('dst2'), 'DST')
+ library.python.fs.replace(path('src'), path('dst2'))
+ assert not os.path.isfile(path('src'))
+ assert os.path.isfile(path('dst2'))
+ assert file_data(path('dst2')) == 'SRC'
+
+
+@in_env
+def test_replace_file_exists_dir_empty(path):
+ mkfile(path('src'), 'SRC')
+ os.mkdir(path('dst'))
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.replace_file(path('src'), path('dst'))
+ assert errinfo.value.errno in (errno.EISDIR, errno.EACCES)
+ assert os.path.isfile(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert not os.path.isfile(path('dst/src'))
+
+
+@in_env
+def test_replace_file_exists_dir_empty_overwrite(path):
+ mkfile(path('src'), 'SRC')
+ os.mkdir(path('dst'))
+ library.python.fs.replace(path('src'), path('dst'))
+ assert not os.path.isfile(path('src'))
+ assert os.path.isfile(path('dst'))
+ assert file_data(path('dst')) == 'SRC'
+
+
+@in_env
+def test_replace_file_exists_dir_nonempty(path):
+ mkfile(path('src'), 'SRC')
+ os.mkdir(path('dst'))
+ mkfile(path('dst/dst_file'))
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.replace_file(path('src'), path('dst'))
+ assert errinfo.value.errno in (errno.EISDIR, errno.EACCES)
+ assert os.path.isfile(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert os.path.isfile(path('dst/dst_file'))
+ assert not os.path.isfile(path('dst/src'))
+
+
+@in_env
+def test_replace_file_exists_dir_nonempty_overwrite(path):
+ mkfile(path('src'), 'SRC')
+ os.mkdir(path('dst'))
+ mkfile(path('dst/dst_file'))
+ library.python.fs.replace(path('src'), path('dst'))
+ assert not os.path.isfile(path('src'))
+ assert os.path.isfile(path('dst'))
+ assert file_data(path('dst')) == 'SRC'
+
+
+@in_env
+def test_replace_dir(path):
+ os.mkdir(path('src'))
+ mkfile(path('src/src_file'))
+ library.python.fs.replace(path('src'), path('dst'))
+ assert not os.path.isdir(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert os.path.isfile(path('dst/src_file'))
+
+
+@in_env
+def test_replace_dir_exists_empty(path):
+ os.mkdir(path('src'))
+ mkfile(path('src/src_file'))
+ os.mkdir(path('dst'))
+ library.python.fs.replace(path('src'), path('dst'))
+ assert not os.path.isdir(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert os.path.isfile(path('dst/src_file'))
+
+
+@in_env
+def test_replace_dir_exists_nonempty(path):
+ os.mkdir(path('src'))
+ mkfile(path('src/src_file'))
+ os.mkdir(path('dst'))
+ mkfile(path('dst/dst_file'))
+ library.python.fs.replace(path('src'), path('dst'))
+ assert not os.path.isdir(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert os.path.isfile(path('dst/src_file'))
+ assert not os.path.isfile(path('dst/dst_file'))
+
+
+@in_env
+def test_replace_dir_exists_file(path):
+ os.mkdir(path('src'))
+ mkfile(path('src/src_file'))
+ mkfile(path('dst'), 'DST')
+ library.python.fs.replace(path('src'), path('dst'))
+ assert not os.path.isdir(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert os.path.isfile(path('dst/src_file'))
+
+
+@in_env
+def test_remove_file(path):
+ mkfile(path('path'))
+ library.python.fs.remove_file(path('path'))
+ assert not os.path.exists(path('path'))
+
+
+@in_env
+def test_remove_file_no(path):
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.remove_file(path('path'))
+ assert errinfo.value.errno == errno.ENOENT
+
+
+@in_env
+def test_remove_file_exists_dir(path):
+ os.mkdir(path('path'))
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.remove_file(path('path'))
+ assert errinfo.value.errno in (errno.EISDIR, errno.EACCES)
+ assert os.path.isdir(path('path'))
+
+
+@in_env
+def test_remove_dir(path):
+ os.mkdir(path('path'))
+ library.python.fs.remove_dir(path('path'))
+ assert not os.path.exists(path('path'))
+
+
+@in_env
+def test_remove_dir_no(path):
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.remove_dir(path('path'))
+ assert errinfo.value.errno == errno.ENOENT
+
+
+@in_env
+def test_remove_dir_exists_file(path):
+ mkfile(path('path'))
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.remove_dir(path('path'))
+ assert errinfo.value.errno in (errno.ENOTDIR, errno.EINVAL)
+ assert os.path.isfile(path('path'))
+
+
+@in_env
+def test_remove_tree(path):
+ mktree_example(path, 'path')
+ library.python.fs.remove_tree(path('path'))
+ assert not os.path.exists(path('path'))
+
+
+@in_env
+def test_remove_tree_empty(path):
+ os.mkdir(path('path'))
+ library.python.fs.remove_tree(path('path'))
+ assert not os.path.exists(path('path'))
+
+
+@in_env
+def test_remove_tree_file(path):
+ mkfile(path('path'))
+ library.python.fs.remove_tree(path('path'))
+ assert not os.path.exists(path('path'))
+
+
+@in_env
+def test_remove_tree_no(path):
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.remove_tree(path('path'))
+ assert errinfo.value.errno == errno.ENOENT
+
+
+@in_env
+def test_remove_tree_safe(path):
+ library.python.fs.remove_tree_safe(path('path'))
+
+
+@in_env
+def test_ensure_removed(path):
+ library.python.fs.ensure_removed(path('path'))
+
+
+@in_env
+def test_ensure_removed_exists(path):
+ os.makedirs(path('dir/subdir'))
+ library.python.fs.ensure_removed(path('dir'))
+ assert not os.path.exists(path('dir'))
+
+
+@in_env
+def test_ensure_removed_exists_precise(path):
+ os.makedirs(path('dir/subdir'))
+ library.python.fs.ensure_removed(path('dir/subdir'))
+ assert os.path.exists(path('dir'))
+ assert not os.path.exists(path('dir/subdir'))
+
+
+@in_env
+def test_hardlink_file(path):
+ mkfile(path('src'), 'SRC')
+ library.python.fs.hardlink(path('src'), path('dst'))
+ assert os.path.isfile(path('src'))
+ assert os.path.isfile(path('dst'))
+ assert file_data(path('dst')) == 'SRC'
+ assert inodes_unsupported() or inodes_equal(path('src'), path('dst'))
+
+
+@in_env
+def test_hardlink_file_no_src(path):
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.hardlink(path('src'), path('dst'))
+ assert errinfo.value.errno == errno.ENOENT
+
+
+@in_env
+def test_hardlink_file_exists(path):
+ mkfile(path('src'), 'SRC')
+ mkfile(path('dst'), 'DST')
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.hardlink(path('src'), path('dst'))
+ assert errinfo.value.errno == errno.EEXIST
+ assert os.path.isfile(path('src'))
+ assert os.path.isfile(path('dst'))
+ assert file_data(path('dst')) == 'DST'
+ assert inodes_unsupported() or not inodes_equal(path('src'), path('dst'))
+
+
+@in_env
+def test_hardlink_file_exists_dir(path):
+ mkfile(path('src'), 'SRC')
+ os.mkdir(path('dst'))
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.hardlink(path('src'), path('dst'))
+ assert errinfo.value.errno == errno.EEXIST
+ assert os.path.isfile(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert not os.path.isfile(path('dst/src'))
+
+
+@in_env
+def test_hardlink_dir(path):
+ os.mkdir(path('src'))
+ mkfile(path('src/src_file'))
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.hardlink(path('src'), path('dst'))
+ assert errinfo.value.errno in (errno.EPERM, errno.EACCES)
+ assert os.path.isdir(path('src'))
+ assert not os.path.isdir(path('dst'))
+
+
+@pytest.mark.skipif(library.python.windows.on_win(), reason='Symlinks disabled on Windows')
+@in_env
+def test_symlink_file(path):
+ mkfile(path('src'), 'SRC')
+ library.python.fs.symlink(path('src'), path('dst'))
+ assert os.path.isfile(path('src'))
+ assert os.path.isfile(path('dst'))
+ assert os.path.islink(path('dst'))
+ assert file_data(path('dst')) == 'SRC'
+
+
+@pytest.mark.skipif(library.python.windows.on_win(), reason='Symlinks disabled on Windows')
+@in_env
+def test_symlink_file_no_src(path):
+ library.python.fs.symlink(path('src'), path('dst'))
+ assert not os.path.isfile(path('src'))
+ assert not os.path.isfile(path('dst'))
+ assert os.path.islink(path('dst'))
+
+
+@pytest.mark.skipif(library.python.windows.on_win(), reason='Symlinks disabled on Windows')
+@in_env
+def test_symlink_file_exists(path):
+ mkfile(path('src'), 'SRC')
+ mkfile(path('dst'), 'DST')
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.symlink(path('src'), path('dst'))
+ assert errinfo.value.errno == errno.EEXIST
+ assert os.path.isfile(path('src'))
+ assert os.path.isfile(path('dst'))
+ assert not os.path.islink(path('dst'))
+ assert file_data(path('dst')) == 'DST'
+
+
+@pytest.mark.skipif(library.python.windows.on_win(), reason='Symlinks disabled on Windows')
+@in_env
+def test_symlink_file_exists_dir(path):
+ mkfile(path('src'), 'SRC')
+ os.mkdir(path('dst'))
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.symlink(path('src'), path('dst'))
+ assert errinfo.value.errno == errno.EEXIST
+ assert os.path.isfile(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert not os.path.islink(path('dst'))
+ assert not os.path.isfile(path('dst/src'))
+
+
+@pytest.mark.skipif(library.python.windows.on_win(), reason='Symlinks disabled on Windows')
+@in_env
+def test_symlink_dir(path):
+ os.mkdir(path('src'))
+ mkfile(path('src/src_file'))
+ library.python.fs.symlink(path('src'), path('dst'))
+ assert os.path.isdir(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert os.path.islink(path('dst'))
+ assert os.path.isfile(path('dst/src_file'))
+
+
+@pytest.mark.skipif(library.python.windows.on_win(), reason='Symlinks disabled on Windows')
+@in_env
+def test_symlink_dir_no_src(path):
+ library.python.fs.symlink(path('src'), path('dst'))
+ assert not os.path.isdir(path('src'))
+ assert not os.path.isdir(path('dst'))
+ assert os.path.islink(path('dst'))
+
+
+@pytest.mark.skipif(library.python.windows.on_win(), reason='Symlinks disabled on Windows')
+@in_env
+def test_symlink_dir_exists(path):
+ os.mkdir(path('src'))
+ mkfile(path('src/src_file'))
+ os.mkdir(path('dst'))
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.symlink(path('src'), path('dst'))
+ assert errinfo.value.errno == errno.EEXIST
+ assert os.path.isdir(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert not os.path.islink(path('dst'))
+ assert not os.path.isfile(path('dst/src_file'))
+
+
+@pytest.mark.skipif(library.python.windows.on_win(), reason='Symlinks disabled on Windows')
+@in_env
+def test_symlink_dir_exists_file(path):
+ os.mkdir(path('src'))
+ mkfile(path('src/src_file'))
+ mkfile(path('dst'), 'DST')
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.symlink(path('src'), path('dst'))
+ assert errinfo.value.errno == errno.EEXIST
+ assert os.path.isdir(path('src'))
+ assert os.path.isfile(path('dst'))
+ assert not os.path.islink(path('dst'))
+
+
+@in_env
+def test_hardlink_tree(path):
+ mktree_example(path, 'src')
+ library.python.fs.hardlink_tree(path('src'), path('dst'))
+ assert trees_equal(path('src'), path('dst'))
+
+
+@in_env
+def test_hardlink_tree_empty(path):
+ os.mkdir(path('src'))
+ library.python.fs.hardlink_tree(path('src'), path('dst'))
+ assert trees_equal(path('src'), path('dst'))
+
+
+@in_env
+def test_hardlink_tree_file(path):
+ mkfile(path('src'), 'SRC')
+ library.python.fs.hardlink_tree(path('src'), path('dst'))
+ assert trees_equal(path('src'), path('dst'))
+
+
+@in_env
+def test_hardlink_tree_no_src(path):
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.hardlink_tree(path('src'), path('dst'))
+ assert errinfo.value.errno == errno.ENOENT
+
+
+@in_env
+def test_hardlink_tree_exists(path):
+ mktree_example(path, 'src')
+ os.mkdir(path('dst_dir'))
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.hardlink_tree(path('src'), path('dst_dir'))
+ assert errinfo.value.errno == errno.EEXIST
+ mkfile(path('dst_file'), 'DST')
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.hardlink_tree(path('src'), path('dst_file'))
+ assert errinfo.value.errno == errno.EEXIST
+
+
+@in_env
+def test_hardlink_tree_file_exists(path):
+ mkfile(path('src'), 'SRC')
+ os.mkdir(path('dst_dir'))
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.hardlink_tree(path('src'), path('dst_dir'))
+ assert errinfo.value.errno == errno.EEXIST
+ mkfile(path('dst_file'), 'DST')
+ with pytest.raises(OSError) as errinfo:
+ library.python.fs.hardlink_tree(path('src'), path('dst_file'))
+ assert errinfo.value.errno == errno.EEXIST
+
+
+@in_env
+def test_copy_file(path):
+ mkfile(path('src'), 'SRC')
+ library.python.fs.copy_file(path('src'), path('dst'))
+ assert os.path.isfile(path('src'))
+ assert os.path.isfile(path('dst'))
+ assert file_data(path('dst')) == 'SRC'
+
+
+@in_env
+def test_copy_file_no_src(path):
+ with pytest.raises(EnvironmentError):
+ library.python.fs.copy_file(path('src'), path('dst'))
+
+
+@in_env
+def test_copy_file_exists(path):
+ mkfile(path('src'), 'SRC')
+ mkfile(path('dst'), 'DST')
+ library.python.fs.copy_file(path('src'), path('dst'))
+ assert os.path.isfile(path('src'))
+ assert os.path.isfile(path('dst'))
+ assert file_data(path('dst')) == 'SRC'
+
+
+@in_env
+def test_copy_file_exists_dir_empty(path):
+ mkfile(path('src'), 'SRC')
+ os.mkdir(path('dst'))
+ with pytest.raises(EnvironmentError):
+ library.python.fs.copy_file(path('src'), path('dst'))
+ assert os.path.isfile(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert not os.path.isfile(path('dst/src'))
+
+
+@in_env
+def test_copy_file_exists_dir_nonempty(path):
+ mkfile(path('src'), 'SRC')
+ os.mkdir(path('dst'))
+ mkfile(path('dst/dst_file'))
+ with pytest.raises(EnvironmentError):
+ library.python.fs.copy_file(path('src'), path('dst'))
+ assert os.path.isfile(path('src'))
+ assert os.path.isdir(path('dst'))
+ assert os.path.isfile(path('dst/dst_file'))
+ assert not os.path.isfile(path('dst/src'))
+
+
+@in_env
+def test_copy_tree(path):
+ mktree_example(path, 'src')
+ library.python.fs.copy_tree(path('src'), path('dst'))
+ assert trees_equal(path('src'), path('dst'))
+
+
+@in_env
+def test_copy_tree_empty(path):
+ os.mkdir(path('src'))
+ library.python.fs.copy_tree(path('src'), path('dst'))
+ assert trees_equal(path('src'), path('dst'))
+
+
+@in_env
+def test_copy_tree_file(path):
+ mkfile(path('src'), 'SRC')
+ library.python.fs.copy_tree(path('src'), path('dst'))
+ assert trees_equal(path('src'), path('dst'))
+
+
+@in_env
+def test_copy_tree_no_src(path):
+ with pytest.raises(EnvironmentError):
+ library.python.fs.copy_tree(path('src'), path('dst'))
+
+
+@in_env
+def test_copy_tree_exists(path):
+ mktree_example(path, 'src')
+ os.mkdir(path('dst_dir'))
+ with pytest.raises(EnvironmentError):
+ library.python.fs.copy_tree(path('src'), path('dst_dir'))
+ mkfile(path('dst_file'), 'DST')
+ with pytest.raises(EnvironmentError):
+ library.python.fs.copy_tree(path('src'), path('dst_file'))
+
+
+@in_env
+def test_copy_tree_file_exists(path):
+ mkfile(path('src'), 'SRC')
+ os.mkdir(path('dst_dir'))
+ with pytest.raises(EnvironmentError):
+ library.python.fs.copy_tree(path('src'), path('dst_dir'))
+ mkfile(path('dst_file'), 'DST')
+ library.python.fs.copy_tree(path('src'), path('dst_file'))
+ assert trees_equal(path('src'), path('dst_file'))
+
+
+@in_env
+def test_read_file(path):
+ mkfile(path('src'), 'SRC')
+ assert library.python.fs.read_file(path('src')).decode(library.python.strings.fs_encoding()) == 'SRC'
+ assert library.python.fs.read_file(path('src'), binary=False) == 'SRC'
+
+
+@in_env
+def test_read_file_empty(path):
+ mkfile(path('src'))
+ assert library.python.fs.read_file(path('src')).decode(library.python.strings.fs_encoding()) == ''
+ assert library.python.fs.read_file(path('src'), binary=False) == ''
+
+
+@in_env
+def test_read_file_multiline(path):
+ mkfile(path('src'), 'SRC line 1\nSRC line 2\n')
+ assert (
+ library.python.fs.read_file(path('src')).decode(library.python.strings.fs_encoding())
+ == 'SRC line 1\nSRC line 2\n'
+ )
+ assert library.python.fs.read_file(path('src'), binary=False) == 'SRC line 1\nSRC line 2\n'
+
+
+@in_env
+def test_read_file_multiline_crlf(path):
+ mkfile(path('src'), 'SRC line 1\r\nSRC line 2\r\n')
+ assert (
+ library.python.fs.read_file(path('src')).decode(library.python.strings.fs_encoding())
+ == 'SRC line 1\r\nSRC line 2\r\n'
+ )
+ if library.python.windows.on_win() or six.PY3: # universal newlines are by default in text mode in python3
+ assert library.python.fs.read_file(path('src'), binary=False) == 'SRC line 1\nSRC line 2\n'
+ else:
+ assert library.python.fs.read_file(path('src'), binary=False) == 'SRC line 1\r\nSRC line 2\r\n'
+
+
+@in_env
+def test_read_file_unicode(path):
+ s = u'АБВ'
+ mkfile(path('src'), s.encode('utf-8'))
+ mkfile(path('src_cp1251'), s.encode('cp1251'))
+ assert library.python.fs.read_file_unicode(path('src')) == s
+ assert library.python.fs.read_file_unicode(path('src_cp1251'), enc='cp1251') == s
+ assert library.python.fs.read_file_unicode(path('src'), binary=False) == s
+ assert library.python.fs.read_file_unicode(path('src_cp1251'), binary=False, enc='cp1251') == s
+
+
+@in_env
+def test_read_file_unicode_empty(path):
+ mkfile(path('src'))
+ mkfile(path('src_cp1251'))
+ assert library.python.fs.read_file_unicode(path('src')) == ''
+ assert library.python.fs.read_file_unicode(path('src_cp1251'), enc='cp1251') == ''
+ assert library.python.fs.read_file_unicode(path('src'), binary=False) == ''
+ assert library.python.fs.read_file_unicode(path('src_cp1251'), binary=False, enc='cp1251') == ''
+
+
+@in_env
+def test_read_file_unicode_multiline(path):
+ s = u'АБВ\nИ еще\n'
+ mkfile(path('src'), s.encode('utf-8'))
+ mkfile(path('src_cp1251'), s.encode('cp1251'))
+ assert library.python.fs.read_file_unicode(path('src')) == s
+ assert library.python.fs.read_file_unicode(path('src_cp1251'), enc='cp1251') == s
+ assert library.python.fs.read_file_unicode(path('src'), binary=False) == s
+ assert library.python.fs.read_file_unicode(path('src_cp1251'), binary=False, enc='cp1251') == s
+
+
+@in_env
+def test_read_file_unicode_multiline_crlf(path):
+ s = u'АБВ\r\nИ еще\r\n'
+ mkfile(path('src'), s.encode('utf-8'))
+ mkfile(path('src_cp1251'), s.encode('cp1251'))
+ assert library.python.fs.read_file_unicode(path('src')) == s
+ assert library.python.fs.read_file_unicode(path('src_cp1251'), enc='cp1251') == s
+ if library.python.windows.on_win() or six.PY3: # universal newlines are by default in text mode in python3
+ assert library.python.fs.read_file_unicode(path('src'), binary=False) == u'АБВ\nИ еще\n'
+ assert library.python.fs.read_file_unicode(path('src_cp1251'), binary=False, enc='cp1251') == u'АБВ\nИ еще\n'
+ else:
+ assert library.python.fs.read_file_unicode(path('src'), binary=False) == s
+ assert library.python.fs.read_file_unicode(path('src_cp1251'), binary=False, enc='cp1251') == s
+
+
+@in_env
+def test_write_file(path):
+ library.python.fs.write_file(path('src'), 'SRC')
+ assert file_data(path('src')) == 'SRC'
+ library.python.fs.write_file(path('src2'), 'SRC', binary=False)
+ assert file_data(path('src2')) == 'SRC'
+
+
+@in_env
+def test_write_file_empty(path):
+ library.python.fs.write_file(path('src'), '')
+ assert file_data(path('src')) == ''
+ library.python.fs.write_file(path('src2'), '', binary=False)
+ assert file_data(path('src2')) == ''
+
+
+@in_env
+def test_write_file_multiline(path):
+ library.python.fs.write_file(path('src'), 'SRC line 1\nSRC line 2\n')
+ assert file_data(path('src')) == 'SRC line 1\nSRC line 2\n'
+ library.python.fs.write_file(path('src2'), 'SRC line 1\nSRC line 2\n', binary=False)
+ if library.python.windows.on_win():
+ assert file_data(path('src2')) == 'SRC line 1\r\nSRC line 2\r\n'
+ else:
+ assert file_data(path('src2')) == 'SRC line 1\nSRC line 2\n'
+
+
+@in_env
+def test_write_file_multiline_crlf(path):
+ library.python.fs.write_file(path('src'), 'SRC line 1\r\nSRC line 2\r\n')
+ assert file_data(path('src')) == 'SRC line 1\r\nSRC line 2\r\n'
+ library.python.fs.write_file(path('src2'), 'SRC line 1\r\nSRC line 2\r\n', binary=False)
+ if library.python.windows.on_win():
+ assert file_data(path('src2')) == 'SRC line 1\r\r\nSRC line 2\r\r\n'
+ else:
+ assert file_data(path('src2')) == 'SRC line 1\r\nSRC line 2\r\n'
+
+
+@in_env
+def test_get_file_size(path):
+ mkfile(path('one.txt'), '22')
+ assert library.python.fs.get_file_size(path('one.txt')) == 2
+
+
+@in_env
+def test_get_file_size_empty(path):
+ mkfile(path('one.txt'))
+ assert library.python.fs.get_file_size(path('one.txt')) == 0
+
+
+@in_env
+def test_get_tree_size(path):
+ os.makedirs(path('deeper'))
+ mkfile(path('one.txt'), '1')
+ mkfile(path('deeper/two.txt'), '22')
+ assert library.python.fs.get_tree_size(path('one.txt')) == 1
+ assert library.python.fs.get_tree_size(path('')) == 1
+ assert library.python.fs.get_tree_size(path(''), recursive=True) == 3
+
+
+@pytest.mark.skipif(library.python.windows.on_win(), reason='Symlinks disabled on Windows')
+@in_env
+def test_get_tree_size_dangling_symlink(path):
+ os.makedirs(path('deeper'))
+ mkfile(path('one.txt'), '1')
+ mkfile(path('deeper/two.txt'), '22')
+ os.symlink(path('deeper/two.txt'), path("deeper/link.txt"))
+ os.remove(path('deeper/two.txt'))
+ # does not fail
+ assert library.python.fs.get_tree_size(path(''), recursive=True) == 1
+
+
+@pytest.mark.skipif(not library.python.windows.on_win(), reason='Test hardlinks on windows')
+def test_hardlink_or_copy():
+ max_allowed_hard_links = 1023
+
+ def run(hardlink_function, dir):
+ src = r"test.txt"
+ with open(src, "w") as f:
+ f.write("test")
+ for i in range(max_allowed_hard_links + 1):
+ hardlink_function(src, os.path.join(dir, "{}.txt".format(i)))
+
+ dir1 = library.python.fs.create_dirs("one")
+ with pytest.raises(WindowsError) as e:
+ run(library.python.fs.hardlink, dir1)
+ assert e.value.winerror == 1142
+ assert len(os.listdir(dir1)) == max_allowed_hard_links
+
+ dir2 = library.python.fs.create_dirs("two")
+ run(library.python.fs.hardlink_or_copy, dir2)
+ assert len(os.listdir(dir2)) == max_allowed_hard_links + 1
+
+
+def test_remove_tree_unicode():
+ path = u"test_remove_tree_unicode/русский".encode("utf-8")
+ os.makedirs(path)
+ library.python.fs.remove_tree(six.text_type("test_remove_tree_unicode"))
+ assert not os.path.exists("test_remove_tree_unicode")
+
+
+def test_remove_tree_safe_unicode():
+ path = u"test_remove_tree_safe_unicode/русский".encode("utf-8")
+ os.makedirs(path)
+ library.python.fs.remove_tree_safe(six.text_type("test_remove_tree_safe_unicode"))
+ assert not os.path.exists("test_remove_tree_safe_unicode")
+
+
+def test_copy_tree_custom_copy_function():
+ library.python.fs.create_dirs("test_copy_tree_src/deepper/inner")
+ library.python.fs.write_file("test_copy_tree_src/deepper/deepper.txt", "deepper.txt")
+ library.python.fs.write_file("test_copy_tree_src/deepper/inner/inner.txt", "inner.txt")
+ copied = []
+
+ def copy_function(src, dst):
+ shutil.copy2(src, dst)
+ copied.append(dst)
+
+ library.python.fs.copy_tree(
+ "test_copy_tree_src", yatest.common.work_path("test_copy_tree_dst"), copy_function=copy_function
+ )
+ assert len(copied) == 2
+ assert yatest.common.work_path("test_copy_tree_dst/deepper/deepper.txt") in copied
+ assert yatest.common.work_path("test_copy_tree_dst/deepper/inner/inner.txt") in copied
+
+
+def test_copy2():
+ library.python.fs.symlink("non-existent", "link")
+ library.python.fs.copy2("link", "link2", follow_symlinks=False)
+
+ assert os.path.islink("link2")
+ assert os.readlink("link2") == "non-existent"
+
+
+def test_commonpath():
+ pj = os.path.join
+ pja = lambda *x: os.path.abspath(pj(*x))
+
+ assert library.python.fs.commonpath(['a', 'b']) == ''
+ assert library.python.fs.commonpath([pj('t', '1')]) == pj('t', '1')
+ assert library.python.fs.commonpath([pj('t', '1'), pj('t', '2')]) == pj('t')
+ assert library.python.fs.commonpath([pj('t', '1', '2'), pj('t', '1', '2')]) == pj('t', '1', '2')
+ assert library.python.fs.commonpath([pj('t', '1', '1'), pj('t', '1', '2')]) == pj('t', '1')
+ assert library.python.fs.commonpath([pj('t', '1', '1'), pj('t', '1', '2'), pj('t', '1', '3')]) == pj('t', '1')
+
+ assert library.python.fs.commonpath([pja('t', '1', '1'), pja('t', '1', '2')]) == pja('t', '1')
+
+ assert library.python.fs.commonpath({pj('t', '1'), pj('t', '2')}) == pj('t')
diff --git a/library/python/fs/test/ya.make b/library/python/fs/test/ya.make
new file mode 100644
index 0000000000..33e3f5b4ff
--- /dev/null
+++ b/library/python/fs/test/ya.make
@@ -0,0 +1,14 @@
+OWNER(g:yatool)
+
+PY23_TEST()
+
+TEST_SRCS(
+ test_fs.py
+)
+
+PEERDIR(
+ library/python/fs
+ library/python/tmp
+)
+
+END()
diff --git a/library/python/fs/ya.make b/library/python/fs/ya.make
new file mode 100644
index 0000000000..b3c5092c71
--- /dev/null
+++ b/library/python/fs/ya.make
@@ -0,0 +1,23 @@
+OWNER(g:yatool)
+
+PY23_LIBRARY()
+
+PY_SRCS(
+ __init__.py
+)
+
+IF (OS_DARWIN)
+ PY_SRCS(
+ clonefile.pyx
+ )
+ENDIF()
+
+PEERDIR(
+ library/python/func
+ library/python/strings
+ library/python/windows
+)
+
+END()
+
+RECURSE_FOR_TESTS(test)
diff --git a/library/python/func/__init__.py b/library/python/func/__init__.py
new file mode 100644
index 0000000000..7424361635
--- /dev/null
+++ b/library/python/func/__init__.py
@@ -0,0 +1,170 @@
+import functools
+import threading
+import collections
+
+
+def map0(func, value):
+ return func(value) if value is not None else value
+
+
+def single(x):
+ if len(x) != 1:
+ raise Exception('Length of {} is not equal to 1'.format(x))
+ return x[0]
+
+
+class _Result(object):
+ pass
+
+
+def lazy(func):
+ result = _Result()
+
+ @functools.wraps(func)
+ def wrapper(*args):
+ try:
+ return result.result
+ except AttributeError:
+ result.result = func(*args)
+
+ return result.result
+
+ return wrapper
+
+
+def lazy_property(fn):
+ attr_name = '_lazy_' + fn.__name__
+
+ @property
+ def _lazy_property(self):
+ if not hasattr(self, attr_name):
+ setattr(self, attr_name, fn(self))
+ return getattr(self, attr_name)
+
+ return _lazy_property
+
+
+class classproperty(object):
+ def __init__(self, func):
+ self.func = func
+
+ def __get__(self, _, owner):
+ return self.func(owner)
+
+
+class lazy_classproperty(object):
+ def __init__(self, func):
+ self.func = func
+
+ def __get__(self, _, owner):
+ attr_name = '_lazy_' + self.func.__name__
+
+ if not hasattr(owner, attr_name):
+ setattr(owner, attr_name, self.func(owner))
+ return getattr(owner, attr_name)
+
+
+def memoize(limit=0, thread_local=False):
+ assert limit >= 0
+
+ def decorator(func):
+ memory = {}
+ lock = threading.Lock()
+
+ if limit:
+ keys = collections.deque()
+
+ def get(args):
+ try:
+ return memory[args]
+ except KeyError:
+ with lock:
+ if args not in memory:
+ fargs = args[-1]
+ memory[args] = func(*fargs)
+ keys.append(args)
+ if len(keys) > limit:
+ del memory[keys.popleft()]
+ return memory[args]
+
+ else:
+
+ def get(args):
+ if args not in memory:
+ with lock:
+ if args not in memory:
+ fargs = args[-1]
+ memory[args] = func(*fargs)
+ return memory[args]
+
+ if thread_local:
+
+ @functools.wraps(func)
+ def wrapper(*args):
+ th = threading.current_thread()
+ return get((th.ident, th.name, args))
+
+ else:
+
+ @functools.wraps(func)
+ def wrapper(*args):
+ return get(('', '', args))
+
+ return wrapper
+
+ return decorator
+
+
+# XXX: add test
+def compose(*functions):
+ def compose2(f, g):
+ return lambda x: f(g(x))
+
+ return functools.reduce(compose2, functions, lambda x: x)
+
+
+class Singleton(type):
+ _instances = {}
+
+ def __call__(cls, *args, **kwargs):
+ if cls not in cls._instances:
+ cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
+ return cls._instances[cls]
+
+
+def stable_uniq(it):
+ seen = set()
+ res = []
+ for e in it:
+ if e not in seen:
+ res.append(e)
+ seen.add(e)
+ return res
+
+
+def first(it):
+ for d in it:
+ if d:
+ return d
+
+
+def split(data, func):
+ l, r = [], []
+ for e in data:
+ if func(e):
+ l.append(e)
+ else:
+ r.append(e)
+ return l, r
+
+
+def flatten_dict(dd, separator='.', prefix=''):
+ return (
+ {
+ prefix + separator + k if prefix else k: v
+ for kk, vv in dd.items()
+ for k, v in flatten_dict(vv, separator, kk).items()
+ }
+ if isinstance(dd, dict)
+ else {prefix: dd}
+ )
diff --git a/library/python/func/ut/test_func.py b/library/python/func/ut/test_func.py
new file mode 100644
index 0000000000..3c4fad1a07
--- /dev/null
+++ b/library/python/func/ut/test_func.py
@@ -0,0 +1,162 @@
+import pytest
+import threading
+
+import library.python.func as func
+
+
+def test_map0():
+ assert None is func.map0(lambda x: x + 1, None)
+ assert 3 == func.map0(lambda x: x + 1, 2)
+ assert None is func.map0(len, None)
+ assert 2 == func.map0(len, [1, 2])
+
+
+def test_single():
+ assert 1 == func.single([1])
+ with pytest.raises(Exception):
+ assert 1 == func.single([])
+ with pytest.raises(Exception):
+ assert 1 == func.single([1, 2])
+
+
+def test_memoize():
+ class Counter(object):
+ @staticmethod
+ def inc():
+ Counter._qty = getattr(Counter, '_qty', 0) + 1
+ return Counter._qty
+
+ @func.memoize()
+ def t1(a):
+ return a, Counter.inc()
+
+ @func.memoize()
+ def t2(a):
+ return a, Counter.inc()
+
+ @func.memoize()
+ def t3(a):
+ return a, Counter.inc()
+
+ @func.memoize()
+ def t4(a):
+ return a, Counter.inc()
+
+ @func.memoize()
+ def t5(a, b, c):
+ return a + b + c, Counter.inc()
+
+ @func.memoize()
+ def t6():
+ return Counter.inc()
+
+ @func.memoize(limit=2)
+ def t7(a, _b):
+ return a, Counter.inc()
+
+ assert (1, 1) == t1(1)
+ assert (1, 1) == t1(1)
+ assert (2, 2) == t1(2)
+ assert (2, 2) == t1(2)
+
+ assert (1, 3) == t2(1)
+ assert (1, 3) == t2(1)
+ assert (2, 4) == t2(2)
+ assert (2, 4) == t2(2)
+
+ assert (1, 5) == t3(1)
+ assert (1, 5) == t3(1)
+ assert (2, 6) == t3(2)
+ assert (2, 6) == t3(2)
+
+ assert (1, 7) == t4(1)
+ assert (1, 7) == t4(1)
+ assert (2, 8) == t4(2)
+ assert (2, 8) == t4(2)
+
+ assert (6, 9) == t5(1, 2, 3)
+ assert (6, 9) == t5(1, 2, 3)
+ assert (7, 10) == t5(1, 2, 4)
+ assert (7, 10) == t5(1, 2, 4)
+
+ assert 11 == t6()
+ assert 11 == t6()
+
+ assert (1, 12) == t7(1, None)
+ assert (2, 13) == t7(2, None)
+ assert (1, 12) == t7(1, None)
+ assert (2, 13) == t7(2, None)
+ # removed result for (1, None)
+ assert (3, 14) == t7(3, None)
+ assert (1, 15) == t7(1, None)
+
+ class ClassWithMemoizedMethod(object):
+ def __init__(self):
+ self.a = 0
+
+ @func.memoize(True)
+ def t(self, i):
+ self.a += i
+ return i
+
+ obj = ClassWithMemoizedMethod()
+ assert 10 == obj.t(10)
+ assert 10 == obj.a
+ assert 10 == obj.t(10)
+ assert 10 == obj.a
+
+ assert 20 == obj.t(20)
+ assert 30 == obj.a
+ assert 20 == obj.t(20)
+ assert 30 == obj.a
+
+
+def test_first():
+ assert func.first([0, [], (), None, False, {}, 0.0, '1', 0]) == '1'
+ assert func.first([]) is None
+ assert func.first([0]) is None
+
+
+def test_split():
+ assert func.split([1, 1], lambda x: x) == ([1, 1], [])
+ assert func.split([0, 0], lambda x: x) == ([], [0, 0])
+ assert func.split([], lambda x: x) == ([], [])
+ assert func.split([1, 0, 1], lambda x: x) == ([1, 1], [0])
+
+
+def test_flatten_dict():
+ assert func.flatten_dict({"a": 1, "b": 2}) == {"a": 1, "b": 2}
+ assert func.flatten_dict({"a": 1}) == {"a": 1}
+ assert func.flatten_dict({}) == {}
+ assert func.flatten_dict({"a": 1, "b": {"c": {"d": 2}}}) == {"a": 1, "b.c.d": 2}
+ assert func.flatten_dict({"a": 1, "b": {"c": {"d": 2}}}, separator="/") == {"a": 1, "b/c/d": 2}
+
+
+def test_memoize_thread_local():
+ class Counter(object):
+ def __init__(self, s):
+ self.val = s
+
+ def inc(self):
+ self.val += 1
+ return self.val
+
+ @func.memoize(thread_local=True)
+ def get_counter(start):
+ return Counter(start)
+
+ def th_inc():
+ assert get_counter(0).inc() == 1
+ assert get_counter(0).inc() == 2
+ assert get_counter(10).inc() == 11
+ assert get_counter(10).inc() == 12
+
+ th_inc()
+
+ th = threading.Thread(target=th_inc)
+ th.start()
+ th.join()
+
+
+if __name__ == '__main__':
+ pytest.main([__file__])
diff --git a/library/python/func/ut/ya.make b/library/python/func/ut/ya.make
new file mode 100644
index 0000000000..5ec6c1225e
--- /dev/null
+++ b/library/python/func/ut/ya.make
@@ -0,0 +1,11 @@
+OWNER(g:yatool)
+
+PY23_TEST()
+
+TEST_SRCS(test_func.py)
+
+PEERDIR(
+ library/python/func
+)
+
+END()
diff --git a/library/python/func/ya.make b/library/python/func/ya.make
new file mode 100644
index 0000000000..9d414a976e
--- /dev/null
+++ b/library/python/func/ya.make
@@ -0,0 +1,11 @@
+OWNER(g:yatool)
+
+PY23_LIBRARY()
+
+PY_SRCS(__init__.py)
+
+END()
+
+RECURSE_FOR_TESTS(
+ ut
+)
diff --git a/library/python/pytest/__init__.py b/library/python/pytest/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/library/python/pytest/__init__.py
diff --git a/library/python/pytest/allure/conftest.py b/library/python/pytest/allure/conftest.py
new file mode 100644
index 0000000000..0d5cfda1e5
--- /dev/null
+++ b/library/python/pytest/allure/conftest.py
@@ -0,0 +1,8 @@
+import os
+import pytest
+
+
+@pytest.mark.tryfirst
+def pytest_configure(config):
+ if "ALLURE_REPORT_DIR" in os.environ:
+ config.option.allurereportdir = os.environ["ALLURE_REPORT_DIR"]
diff --git a/library/python/pytest/allure/ya.make b/library/python/pytest/allure/ya.make
new file mode 100644
index 0000000000..ab3f449c7f
--- /dev/null
+++ b/library/python/pytest/allure/ya.make
@@ -0,0 +1,11 @@
+PY23_LIBRARY()
+
+OWNER(exprmntr)
+
+PY_SRCS(conftest.py)
+
+PEERDIR(
+ contrib/python/pytest-allure-adaptor
+)
+
+END()
diff --git a/library/python/pytest/context.py b/library/python/pytest/context.py
new file mode 100644
index 0000000000..bfcdae50b5
--- /dev/null
+++ b/library/python/pytest/context.py
@@ -0,0 +1 @@
+Ctx = {}
diff --git a/library/python/pytest/empty/main.c b/library/python/pytest/empty/main.c
new file mode 100644
index 0000000000..9efa08162a
--- /dev/null
+++ b/library/python/pytest/empty/main.c
@@ -0,0 +1,7 @@
+/*
+to be used for build python tests in a stub binary for the case of using system python
+*/
+
+int main(void) {
+ return 0;
+}
diff --git a/library/python/pytest/empty/ya.make b/library/python/pytest/empty/ya.make
new file mode 100644
index 0000000000..8f0fa37e2a
--- /dev/null
+++ b/library/python/pytest/empty/ya.make
@@ -0,0 +1,12 @@
+LIBRARY()
+
+OWNER(
+ g:yatool
+ dmitko
+)
+
+SRCS(
+ main.c
+)
+
+END()
diff --git a/library/python/pytest/main.py b/library/python/pytest/main.py
new file mode 100644
index 0000000000..6296bd6f0f
--- /dev/null
+++ b/library/python/pytest/main.py
@@ -0,0 +1,116 @@
+import os
+import sys
+import time
+
+import __res
+
+FORCE_EXIT_TESTSFAILED_ENV = 'FORCE_EXIT_TESTSFAILED'
+
+
+def main():
+ import library.python.pytest.context as context
+ context.Ctx["YA_PYTEST_START_TIMESTAMP"] = time.time()
+
+ profile = None
+ if '--profile-pytest' in sys.argv:
+ sys.argv.remove('--profile-pytest')
+
+ import pstats
+ import cProfile
+ profile = cProfile.Profile()
+ profile.enable()
+
+ # Reset influencing env. vars
+ # For more info see library/python/testing/yatest_common/yatest/common/errors.py
+ if FORCE_EXIT_TESTSFAILED_ENV in os.environ:
+ del os.environ[FORCE_EXIT_TESTSFAILED_ENV]
+
+ if "Y_PYTHON_CLEAR_ENTRY_POINT" in os.environ:
+ if "Y_PYTHON_ENTRY_POINT" in os.environ:
+ del os.environ["Y_PYTHON_ENTRY_POINT"]
+ del os.environ["Y_PYTHON_CLEAR_ENTRY_POINT"]
+
+ listing_mode = '--collect-only' in sys.argv
+ yatest_runner = os.environ.get('YA_TEST_RUNNER') == '1'
+
+ import pytest
+
+ import library.python.pytest.plugins.collection as collection
+ import library.python.pytest.plugins.ya as ya
+ import library.python.pytest.plugins.conftests as conftests
+
+ import _pytest.assertion
+ from _pytest.monkeypatch import MonkeyPatch
+ from . import rewrite
+ m = MonkeyPatch()
+ m.setattr(_pytest.assertion.rewrite, "AssertionRewritingHook", rewrite.AssertionRewritingHook)
+
+ prefix = '__tests__.'
+
+ test_modules = [
+ name[len(prefix):] for name in sys.extra_modules
+ if name.startswith(prefix) and not name.endswith('.conftest')
+ ]
+
+ doctest_packages = __res.find("PY_DOCTEST_PACKAGES") or ""
+ if isinstance(doctest_packages, bytes):
+ doctest_packages = doctest_packages.decode('utf-8')
+ doctest_packages = doctest_packages.split()
+
+ def is_doctest_module(name):
+ for package in doctest_packages:
+ if name == package or name.startswith(str(package) + "."):
+ return True
+ return False
+
+ doctest_modules = [
+ name for name in sys.extra_modules
+ if is_doctest_module(name)
+ ]
+
+ def remove_user_site(paths):
+ site_paths = ('site-packages', 'site-python')
+
+ def is_site_path(path):
+ for p in site_paths:
+ if path.find(p) != -1:
+ return True
+ return False
+
+ new_paths = list(paths)
+ for p in paths:
+ if is_site_path(p):
+ new_paths.remove(p)
+
+ return new_paths
+
+ sys.path = remove_user_site(sys.path)
+ rc = pytest.main(plugins=[
+ collection.CollectionPlugin(test_modules, doctest_modules),
+ ya,
+ conftests,
+ ])
+
+ if rc == 5:
+ # don't care about EXIT_NOTESTSCOLLECTED
+ rc = 0
+
+ if rc == 1 and yatest_runner and not listing_mode and not os.environ.get(FORCE_EXIT_TESTSFAILED_ENV) == '1':
+ # XXX it's place for future improvements
+ # Test wrapper should terminate with 0 exit code if there are common test failures
+ # and report it with trace-file machinery.
+ # However, there are several case when we don't want to suppress exit_code:
+ # - listing machinery doesn't use trace-file currently and rely on stdout and exit_code
+ # - RestartTestException and InfrastructureException required non-zero exit_code to be processes correctly
+ rc = 0
+
+ if profile:
+ profile.disable()
+ ps = pstats.Stats(profile, stream=sys.stderr).sort_stats('cumulative')
+ ps.print_stats()
+
+ sys.exit(rc)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/library/python/pytest/plugins/collection.py b/library/python/pytest/plugins/collection.py
new file mode 100644
index 0000000000..e36f47a78f
--- /dev/null
+++ b/library/python/pytest/plugins/collection.py
@@ -0,0 +1,128 @@
+import os
+import sys
+from six import reraise
+
+import py
+
+import pytest # noqa
+import _pytest.python
+import _pytest.doctest
+import json
+import library.python.testing.filter.filter as test_filter
+
+
+class LoadedModule(_pytest.python.Module):
+ def __init__(self, parent, name, **kwargs):
+ self.name = name + '.py'
+ self.session = parent
+ self.parent = parent
+ self.config = parent.config
+ self.keywords = {}
+ self.own_markers = []
+ self.fspath = py.path.local()
+
+ @classmethod
+ def from_parent(cls, **kwargs):
+ namespace = kwargs.pop('namespace', True)
+ kwargs.setdefault('fspath', py.path.local())
+
+ loaded_module = getattr(super(LoadedModule, cls), 'from_parent', cls)(**kwargs)
+ loaded_module.namespace = namespace
+
+ return loaded_module
+
+ @property
+ def _nodeid(self):
+ if os.getenv('CONFTEST_LOAD_POLICY') == 'LOCAL':
+ return self._getobj().__file__
+ else:
+ return self.name
+
+ @property
+ def nodeid(self):
+ return self._nodeid
+
+ def _getobj(self):
+ module_name = self.name[:-len('.py')]
+ if self.namespace:
+ module_name = '__tests__.' + module_name
+ __import__(module_name)
+ return sys.modules[module_name]
+
+
+class DoctestModule(LoadedModule):
+
+ def collect(self):
+ import doctest
+
+ module = self._getobj()
+ # uses internal doctest module parsing mechanism
+ finder = doctest.DocTestFinder()
+ optionflags = _pytest.doctest.get_optionflags(self)
+ runner = doctest.DebugRunner(verbose=0, optionflags=optionflags)
+
+ try:
+ for test in finder.find(module, self.name[:-len('.py')]):
+ if test.examples: # skip empty doctests
+ yield getattr(_pytest.doctest.DoctestItem, 'from_parent', _pytest.doctest.DoctestItem)(
+ name=test.name,
+ parent=self,
+ runner=runner,
+ dtest=test)
+ except Exception:
+ import logging
+ logging.exception('DoctestModule failed, probably you can add NO_DOCTESTS() macro to ya.make')
+ etype, exc, tb = sys.exc_info()
+ msg = 'DoctestModule failed, probably you can add NO_DOCTESTS() macro to ya.make'
+ reraise(etype, type(exc)('{}\n{}'.format(exc, msg)), tb)
+
+
+# NOTE: Since we are overriding collect method of pytest session, pytest hooks are not invoked during collection.
+def pytest_ignore_collect(module, session, filenames_from_full_filters, accept_filename_predicate):
+ if session.config.option.mode == 'list':
+ return not accept_filename_predicate(module.name)
+
+ if filenames_from_full_filters is not None and module.name not in filenames_from_full_filters:
+ return True
+
+ test_file_filter = getattr(session.config.option, 'test_file_filter', None)
+ if test_file_filter is None:
+ return False
+ if module.name != test_file_filter.replace('/', '.'):
+ return True
+ return False
+
+
+class CollectionPlugin(object):
+ def __init__(self, test_modules, doctest_modules):
+ self._test_modules = test_modules
+ self._doctest_modules = doctest_modules
+
+ def pytest_sessionstart(self, session):
+
+ def collect(*args, **kwargs):
+ accept_filename_predicate = test_filter.make_py_file_filter(session.config.option.test_filter)
+ full_test_names_file_path = session.config.option.test_list_path
+ filenames_filter = None
+
+ if full_test_names_file_path and os.path.exists(full_test_names_file_path):
+ with open(full_test_names_file_path, 'r') as afile:
+ # in afile stored 2 dimensional array such that array[modulo_index] contains tests which should be run in this test suite
+ full_names_filter = set(json.load(afile)[int(session.config.option.modulo_index)])
+ filenames_filter = set(map(lambda x: x.split('::')[0], full_names_filter))
+
+ for test_module in self._test_modules:
+ module = LoadedModule.from_parent(name=test_module, parent=session)
+ if not pytest_ignore_collect(module, session, filenames_filter, accept_filename_predicate):
+ yield module
+
+ if os.environ.get('YA_PYTEST_DISABLE_DOCTEST', 'no') == 'no':
+ module = DoctestModule.from_parent(name=test_module, parent=session)
+ if not pytest_ignore_collect(module, session, filenames_filter, accept_filename_predicate):
+ yield module
+
+ if os.environ.get('YA_PYTEST_DISABLE_DOCTEST', 'no') == 'no':
+ for doctest_module in self._doctest_modules:
+ yield DoctestModule.from_parent(name=doctest_module, parent=session, namespace=False)
+
+ session.collect = collect
diff --git a/library/python/pytest/plugins/conftests.py b/library/python/pytest/plugins/conftests.py
new file mode 100644
index 0000000000..522041f5a7
--- /dev/null
+++ b/library/python/pytest/plugins/conftests.py
@@ -0,0 +1,50 @@
+import os
+import importlib
+import sys
+import inspect
+
+from pytest import hookimpl
+
+from .fixtures import metrics, links # noqa
+
+orig_getfile = inspect.getfile
+
+
+def getfile(object):
+ res = orig_getfile(object)
+ if inspect.ismodule(object):
+ if not res and getattr(object, '__orig_file__'):
+ res = object.__orig_file__
+ return res
+
+inspect.getfile = getfile
+conftest_modules = []
+
+
+@hookimpl(trylast=True)
+def pytest_load_initial_conftests(early_config, parser, args):
+ conftests = filter(lambda name: name.endswith(".conftest"), sys.extra_modules)
+
+ def conftest_key(name):
+ if not name.startswith("__tests__."):
+ # Make __tests__ come last
+ return "_." + name
+ return name
+
+ for name in sorted(conftests, key=conftest_key):
+ mod = importlib.import_module(name)
+ if os.getenv("CONFTEST_LOAD_POLICY") != "LOCAL":
+ mod.__orig_file__ = mod.__file__
+ mod.__file__ = ""
+ conftest_modules.append(mod)
+ early_config.pluginmanager.consider_conftest(mod)
+
+
+def getconftestmodules(*args, **kwargs):
+ return conftest_modules
+
+
+def pytest_sessionstart(session):
+ # Override filesystem based relevant conftest discovery on the call path
+ assert session.config.pluginmanager
+ session.config.pluginmanager._getconftestmodules = getconftestmodules
diff --git a/library/python/pytest/plugins/fakeid_py2.py b/library/python/pytest/plugins/fakeid_py2.py
new file mode 100644
index 0000000000..8b26148e2e
--- /dev/null
+++ b/library/python/pytest/plugins/fakeid_py2.py
@@ -0,0 +1,2 @@
+# Inc this number to change uid for every PYTEST() target
+fake_id = 0
diff --git a/library/python/pytest/plugins/fakeid_py3.py b/library/python/pytest/plugins/fakeid_py3.py
new file mode 100644
index 0000000000..247cc8b29d
--- /dev/null
+++ b/library/python/pytest/plugins/fakeid_py3.py
@@ -0,0 +1,2 @@
+# Inc this number to change uid for every PY3TEST() target
+fake_id = 10
diff --git a/library/python/pytest/plugins/fixtures.py b/library/python/pytest/plugins/fixtures.py
new file mode 100644
index 0000000000..6f7e0a27e4
--- /dev/null
+++ b/library/python/pytest/plugins/fixtures.py
@@ -0,0 +1,85 @@
+import os
+import pytest
+import six
+
+
+MAX_ALLOWED_LINKS_COUNT = 10
+
+
+@pytest.fixture
+def metrics(request):
+
+ class Metrics(object):
+ @classmethod
+ def set(cls, name, value):
+ assert len(name) <= 128, "Length of the metric name must less than 128"
+ assert type(value) in [int, float], "Metric value must be of type int or float"
+ test_name = request.node.nodeid
+ if test_name not in request.config.test_metrics:
+ request.config.test_metrics[test_name] = {}
+ request.config.test_metrics[test_name][name] = value
+
+ @classmethod
+ def set_benchmark(cls, benchmark_values):
+ # report of google has key 'benchmarks' which is a list of benchmark results
+ # yandex benchmark has key 'benchmark', which is a list of benchmark results
+ # use this to differentiate which kind of result it is
+ if 'benchmarks' in benchmark_values:
+ cls.set_gbenchmark(benchmark_values)
+ else:
+ cls.set_ybenchmark(benchmark_values)
+
+ @classmethod
+ def set_ybenchmark(cls, benchmark_values):
+ for benchmark in benchmark_values["benchmark"]:
+ name = benchmark["name"]
+ for key, value in six.iteritems(benchmark):
+ if key != "name":
+ cls.set("{}_{}".format(name, key), value)
+
+ @classmethod
+ def set_gbenchmark(cls, benchmark_values):
+ time_unit_multipliers = {"ns": 1, "us": 1000, "ms": 1000000}
+ time_keys = {"real_time", "cpu_time"}
+ ignore_keys = {"name", "run_name", "time_unit", "run_type", "repetition_index"}
+ for benchmark in benchmark_values["benchmarks"]:
+ name = benchmark["name"].replace('/', '_') # ci does not work properly with '/' in metric name
+ time_unit_mult = time_unit_multipliers[benchmark.get("time_unit", "ns")]
+ for k, v in six.iteritems(benchmark):
+ if k in time_keys:
+ cls.set("{}_{}".format(name, k), v * time_unit_mult)
+ elif k not in ignore_keys and isinstance(v, (float, int)):
+ cls.set("{}_{}".format(name, k), v)
+ return Metrics
+
+
+@pytest.fixture
+def links(request):
+
+ class Links(object):
+ @classmethod
+ def set(cls, name, path):
+
+ if len(request.config.test_logs[request.node.nodeid]) >= MAX_ALLOWED_LINKS_COUNT:
+ raise Exception("Cannot add more than {} links to test".format(MAX_ALLOWED_LINKS_COUNT))
+
+ reserved_names = ["log", "logsdir", "stdout", "stderr"]
+ if name in reserved_names:
+ raise Exception("Attachment name should not belong to the reserved list: {}".format(", ".join(reserved_names)))
+ output_dir = request.config.ya.output_dir
+
+ if not os.path.exists(path):
+ raise Exception("Path to be attached does not exist: {}".format(path))
+
+ if os.path.isabs(path) and ".." in os.path.relpath(path, output_dir):
+ raise Exception("Test attachment must be inside yatest.common.output_path()")
+
+ request.config.test_logs[request.node.nodeid][name] = path
+
+ @classmethod
+ def get(cls, name):
+ if name not in request.config.test_logs[request.node.nodeid]:
+ raise KeyError("Attachment with name '{}' does not exist".format(name))
+ return request.config.test_logs[request.node.nodeid][name]
+
+ return Links
diff --git a/library/python/pytest/plugins/ya.make b/library/python/pytest/plugins/ya.make
new file mode 100644
index 0000000000..c15d6f759d
--- /dev/null
+++ b/library/python/pytest/plugins/ya.make
@@ -0,0 +1,32 @@
+OWNER(g:yatest)
+
+PY23_LIBRARY()
+
+PY_SRCS(
+ ya.py
+ collection.py
+ conftests.py
+ fixtures.py
+)
+
+PEERDIR(
+ library/python/filelock
+ library/python/find_root
+ library/python/testing/filter
+)
+
+IF (PYTHON2)
+ PY_SRCS(
+ fakeid_py2.py
+ )
+
+ PEERDIR(
+ contrib/python/faulthandler
+ )
+ELSE()
+ PY_SRCS(
+ fakeid_py3.py
+ )
+ENDIF()
+
+END()
diff --git a/library/python/pytest/plugins/ya.py b/library/python/pytest/plugins/ya.py
new file mode 100644
index 0000000000..1bde03042d
--- /dev/null
+++ b/library/python/pytest/plugins/ya.py
@@ -0,0 +1,963 @@
+# coding: utf-8
+
+import base64
+import errno
+import re
+import sys
+import os
+import logging
+import fnmatch
+import json
+import time
+import traceback
+import collections
+import signal
+import inspect
+import warnings
+
+import attr
+import faulthandler
+import py
+import pytest
+import six
+
+import _pytest
+import _pytest._io
+import _pytest.mark
+import _pytest.outcomes
+import _pytest.skipping
+
+from _pytest.warning_types import PytestUnhandledCoroutineWarning
+
+from yatest_lib import test_splitter
+
+try:
+ import resource
+except ImportError:
+ resource = None
+
+try:
+ import library.python.pytest.yatest_tools as tools
+except ImportError:
+ # fallback for pytest script mode
+ import yatest_tools as tools
+
+try:
+ from library.python import filelock
+except ImportError:
+ filelock = None
+
+
+import yatest_lib.tools
+
+import yatest_lib.external as canon
+
+import yatest_lib.ya
+
+from library.python.pytest import context
+
+console_logger = logging.getLogger("console")
+yatest_logger = logging.getLogger("ya.test")
+
+
+_pytest.main.EXIT_NOTESTSCOLLECTED = 0
+SHUTDOWN_REQUESTED = False
+
+pytest_config = None
+
+
+def configure_pdb_on_demand():
+ import signal
+
+ if hasattr(signal, "SIGUSR1"):
+ def on_signal(*args):
+ import ipdb
+ ipdb.set_trace()
+
+ signal.signal(signal.SIGUSR1, on_signal)
+
+
+class CustomImporter(object):
+ def __init__(self, roots):
+ self._roots = roots
+
+ def find_module(self, fullname, package_path=None):
+ for path in self._roots:
+ full_path = self._get_module_path(path, fullname)
+
+ if os.path.exists(full_path) and os.path.isdir(full_path) and not os.path.exists(os.path.join(full_path, "__init__.py")):
+ open(os.path.join(full_path, "__init__.py"), "w").close()
+
+ return None
+
+ def _get_module_path(self, path, fullname):
+ return os.path.join(path, *fullname.split('.'))
+
+
+class YaTestLoggingFileHandler(logging.FileHandler):
+ pass
+
+
+class _TokenFilterFormatter(logging.Formatter):
+ def __init__(self, fmt):
+ super(_TokenFilterFormatter, self).__init__(fmt)
+ self._replacements = []
+ if not self._replacements:
+ if six.PY2:
+ for k, v in os.environ.iteritems():
+ if k.endswith('TOKEN') and v:
+ self._replacements.append(v)
+ elif six.PY3:
+ for k, v in os.environ.items():
+ if k.endswith('TOKEN') and v:
+ self._replacements.append(v)
+ self._replacements = sorted(self._replacements)
+
+ def _filter(self, s):
+ for r in self._replacements:
+ s = s.replace(r, "[SECRET]")
+
+ return s
+
+ def format(self, record):
+ return self._filter(super(_TokenFilterFormatter, self).format(record))
+
+
+def setup_logging(log_path, level=logging.DEBUG, *other_logs):
+ logs = [log_path] + list(other_logs)
+ root_logger = logging.getLogger()
+ for i in range(len(root_logger.handlers) - 1, -1, -1):
+ if isinstance(root_logger.handlers[i], YaTestLoggingFileHandler):
+ root_logger.handlers.pop(i).close()
+ root_logger.setLevel(level)
+ for log_file in logs:
+ file_handler = YaTestLoggingFileHandler(log_file)
+ log_format = '%(asctime)s - %(levelname)s - %(name)s - %(funcName)s: %(message)s'
+ file_handler.setFormatter(_TokenFilterFormatter(log_format))
+ file_handler.setLevel(level)
+ root_logger.addHandler(file_handler)
+
+
+def pytest_addoption(parser):
+ parser.addoption("--build-root", action="store", dest="build_root", default="", help="path to the build root")
+ parser.addoption("--dep-root", action="append", dest="dep_roots", default=[], help="path to the dep build roots")
+ parser.addoption("--source-root", action="store", dest="source_root", default="", help="path to the source root")
+ parser.addoption("--data-root", action="store", dest="data_root", default="", help="path to the arcadia_tests_data root")
+ parser.addoption("--output-dir", action="store", dest="output_dir", default="", help="path to the test output dir")
+ parser.addoption("--python-path", action="store", dest="python_path", default="", help="path the canonical python binary")
+ parser.addoption("--valgrind-path", action="store", dest="valgrind_path", default="", help="path the canonical valgring binary")
+ parser.addoption("--test-filter", action="append", dest="test_filter", default=None, help="test filter")
+ parser.addoption("--test-file-filter", action="store", dest="test_file_filter", default=None, help="test file filter")
+ parser.addoption("--test-param", action="append", dest="test_params", default=None, help="test parameters")
+ parser.addoption("--test-log-level", action="store", dest="test_log_level", choices=["critical", "error", "warning", "info", "debug"], default="debug", help="test log level")
+ parser.addoption("--mode", action="store", choices=[yatest_lib.ya.RunMode.List, yatest_lib.ya.RunMode.Run], dest="mode", default=yatest_lib.ya.RunMode.Run, help="testing mode")
+ parser.addoption("--test-list-file", action="store", dest="test_list_file")
+ parser.addoption("--modulo", default=1, type=int)
+ parser.addoption("--modulo-index", default=0, type=int)
+ parser.addoption("--partition-mode", default='SEQUENTIAL', help="Split tests according to partitoin mode")
+ parser.addoption("--split-by-tests", action='store_true', help="Split test execution by tests instead of suites", default=False)
+ parser.addoption("--project-path", action="store", default="", help="path to CMakeList where test is declared")
+ parser.addoption("--build-type", action="store", default="", help="build type")
+ parser.addoption("--flags", action="append", dest="flags", default=[], help="build flags (-D)")
+ parser.addoption("--sanitize", action="store", default="", help="sanitize mode")
+ parser.addoption("--test-stderr", action="store_true", default=False, help="test stderr")
+ parser.addoption("--test-debug", action="store_true", default=False, help="test debug mode")
+ parser.addoption("--root-dir", action="store", default=None)
+ parser.addoption("--ya-trace", action="store", dest="ya_trace_path", default=None, help="path to ya trace report")
+ parser.addoption("--ya-version", action="store", dest="ya_version", default=0, type=int, help="allows to be compatible with ya and the new changes in ya-dev")
+ parser.addoption(
+ "--test-suffix", action="store", dest="test_suffix", default=None, help="add suffix to every test name"
+ )
+ parser.addoption("--gdb-path", action="store", dest="gdb_path", default="", help="path the canonical gdb binary")
+ parser.addoption("--collect-cores", action="store_true", dest="collect_cores", default=False, help="allows core dump file recovering during test")
+ parser.addoption("--sanitizer-extra-checks", action="store_true", dest="sanitizer_extra_checks", default=False, help="enables extra checks for tests built with sanitizers")
+ parser.addoption("--report-deselected", action="store_true", dest="report_deselected", default=False, help="report deselected tests to the trace file")
+ parser.addoption("--pdb-on-sigusr1", action="store_true", default=False, help="setup pdb.set_trace on SIGUSR1")
+ parser.addoption("--test-tool-bin", help="Path to test_tool")
+ parser.addoption("--test-list-path", dest="test_list_path", action="store", help="path to test list", default="")
+
+
+def from_ya_test():
+ return "YA_TEST_RUNNER" in os.environ
+
+
+def pytest_configure(config):
+ global pytest_config
+ pytest_config = config
+
+ config.option.continue_on_collection_errors = True
+
+ config.addinivalue_line("markers", "ya:external")
+
+ config.from_ya_test = from_ya_test()
+ config.test_logs = collections.defaultdict(dict)
+ config.test_metrics = {}
+ config.suite_metrics = {}
+ config.configure_timestamp = time.time()
+ context = {
+ "project_path": config.option.project_path,
+ "test_stderr": config.option.test_stderr,
+ "test_debug": config.option.test_debug,
+ "build_type": config.option.build_type,
+ "test_traceback": config.option.tbstyle,
+ "flags": config.option.flags,
+ "sanitize": config.option.sanitize,
+ }
+
+ if config.option.collectonly:
+ config.option.mode = yatest_lib.ya.RunMode.List
+
+ config.ya = yatest_lib.ya.Ya(
+ config.option.mode,
+ config.option.source_root,
+ config.option.build_root,
+ config.option.dep_roots,
+ config.option.output_dir,
+ config.option.test_params,
+ context,
+ config.option.python_path,
+ config.option.valgrind_path,
+ config.option.gdb_path,
+ config.option.data_root,
+ )
+ config.option.test_log_level = {
+ "critical": logging.CRITICAL,
+ "error": logging.ERROR,
+ "warning": logging.WARN,
+ "info": logging.INFO,
+ "debug": logging.DEBUG,
+ }[config.option.test_log_level]
+
+ if not config.option.collectonly:
+ setup_logging(os.path.join(config.ya.output_dir, "run.log"), config.option.test_log_level)
+ config.current_item_nodeid = None
+ config.current_test_name = None
+ config.test_cores_count = 0
+ config.collect_cores = config.option.collect_cores
+ config.sanitizer_extra_checks = config.option.sanitizer_extra_checks
+ try:
+ config.test_tool_bin = config.option.test_tool_bin
+ except AttributeError:
+ logging.info("test_tool_bin not specified")
+
+ if config.sanitizer_extra_checks:
+ for envvar in ['LSAN_OPTIONS', 'ASAN_OPTIONS']:
+ if envvar in os.environ:
+ os.environ.pop(envvar)
+ if envvar + '_ORIGINAL' in os.environ:
+ os.environ[envvar] = os.environ[envvar + '_ORIGINAL']
+
+ if config.option.root_dir:
+ config.rootdir = py.path.local(config.option.root_dir)
+ config.invocation_params = attr.evolve(config.invocation_params, dir=config.rootdir)
+
+ extra_sys_path = []
+ # Arcadia paths from the test DEPENDS section of ya.make
+ extra_sys_path.append(os.path.join(config.option.source_root, config.option.project_path))
+ # Build root is required for correct import of protobufs, because imports are related to the root
+ # (like import devtools.dummy_arcadia.protos.lib.my_proto_pb2)
+ extra_sys_path.append(config.option.build_root)
+
+ for path in config.option.dep_roots:
+ if os.path.isabs(path):
+ extra_sys_path.append(path)
+ else:
+ extra_sys_path.append(os.path.join(config.option.source_root, path))
+
+ sys_path_set = set(sys.path)
+ for path in extra_sys_path:
+ if path not in sys_path_set:
+ sys.path.append(path)
+ sys_path_set.add(path)
+
+ os.environ["PYTHONPATH"] = os.pathsep.join(sys.path)
+
+ if not config.option.collectonly:
+ if config.option.ya_trace_path:
+ config.ya_trace_reporter = TraceReportGenerator(config.option.ya_trace_path)
+ else:
+ config.ya_trace_reporter = DryTraceReportGenerator(config.option.ya_trace_path)
+ config.ya_version = config.option.ya_version
+
+ sys.meta_path.append(CustomImporter([config.option.build_root] + [os.path.join(config.option.build_root, dep) for dep in config.option.dep_roots]))
+ if config.option.pdb_on_sigusr1:
+ configure_pdb_on_demand()
+
+ # Dump python backtrace in case of any errors
+ faulthandler.enable()
+ if hasattr(signal, "SIGQUIT"):
+ # SIGQUIT is used by test_tool to teardown tests which overruns timeout
+ faulthandler.register(signal.SIGQUIT, chain=True)
+
+ if hasattr(signal, "SIGUSR2"):
+ signal.signal(signal.SIGUSR2, _graceful_shutdown)
+
+
+session_should_exit = False
+
+
+def _graceful_shutdown_on_log(should_exit):
+ if should_exit:
+ pytest.exit("Graceful shutdown requested")
+
+
+def pytest_runtest_logreport(report):
+ _graceful_shutdown_on_log(session_should_exit)
+
+
+def pytest_runtest_logstart(nodeid, location):
+ _graceful_shutdown_on_log(session_should_exit)
+
+
+def pytest_runtest_logfinish(nodeid, location):
+ _graceful_shutdown_on_log(session_should_exit)
+
+
+def _graceful_shutdown(*args):
+ global session_should_exit
+ session_should_exit = True
+ try:
+ import library.python.coverage
+ library.python.coverage.stop_coverage_tracing()
+ except ImportError:
+ pass
+ traceback.print_stack(file=sys.stderr)
+ capman = pytest_config.pluginmanager.getplugin("capturemanager")
+ capman.suspend(in_=True)
+ _graceful_shutdown_on_log(not capman.is_globally_capturing())
+
+
+def _get_rusage():
+ return resource and resource.getrusage(resource.RUSAGE_SELF)
+
+
+def _collect_test_rusage(item):
+ if resource and hasattr(item, "rusage"):
+ finish_rusage = _get_rusage()
+ ya_inst = pytest_config.ya
+
+ def add_metric(attr_name, metric_name=None, modifier=None):
+ if not metric_name:
+ metric_name = attr_name
+ if not modifier:
+ modifier = lambda x: x
+ if hasattr(item.rusage, attr_name):
+ ya_inst.set_metric_value(metric_name, modifier(getattr(finish_rusage, attr_name) - getattr(item.rusage, attr_name)))
+
+ for args in [
+ ("ru_maxrss", "ru_rss", lambda x: x*1024), # to be the same as in util/system/rusage.cpp
+ ("ru_utime",),
+ ("ru_stime",),
+ ("ru_ixrss", None, lambda x: x*1024),
+ ("ru_idrss", None, lambda x: x*1024),
+ ("ru_isrss", None, lambda x: x*1024),
+ ("ru_majflt", "ru_major_pagefaults"),
+ ("ru_minflt", "ru_minor_pagefaults"),
+ ("ru_nswap",),
+ ("ru_inblock",),
+ ("ru_oublock",),
+ ("ru_msgsnd",),
+ ("ru_msgrcv",),
+ ("ru_nsignals",),
+ ("ru_nvcsw",),
+ ("ru_nivcsw",),
+ ]:
+ add_metric(*args)
+
+
+def _get_item_tags(item):
+ tags = []
+ for key, value in item.keywords.items():
+ if key == 'pytestmark' and isinstance(value, list):
+ for mark in value:
+ tags.append(mark.name)
+ elif isinstance(value, _pytest.mark.MarkDecorator):
+ tags.append(key)
+ return tags
+
+
+def pytest_runtest_setup(item):
+ item.rusage = _get_rusage()
+ pytest_config.test_cores_count = 0
+ pytest_config.current_item_nodeid = item.nodeid
+ class_name, test_name = tools.split_node_id(item.nodeid)
+ test_log_path = tools.get_test_log_file_path(pytest_config.ya.output_dir, class_name, test_name)
+ setup_logging(
+ os.path.join(pytest_config.ya.output_dir, "run.log"),
+ pytest_config.option.test_log_level,
+ test_log_path
+ )
+ pytest_config.test_logs[item.nodeid]['log'] = test_log_path
+ pytest_config.test_logs[item.nodeid]['logsdir'] = pytest_config.ya.output_dir
+ pytest_config.current_test_log_path = test_log_path
+ pytest_config.current_test_name = "{}::{}".format(class_name, test_name)
+ separator = "#" * 100
+ yatest_logger.info(separator)
+ yatest_logger.info(test_name)
+ yatest_logger.info(separator)
+ yatest_logger.info("Test setup")
+
+ test_item = CrashedTestItem(item.nodeid, pytest_config.option.test_suffix)
+ pytest_config.ya_trace_reporter.on_start_test_class(test_item)
+ pytest_config.ya_trace_reporter.on_start_test_case(test_item)
+
+
+def pytest_runtest_teardown(item, nextitem):
+ yatest_logger.info("Test teardown")
+
+
+def pytest_runtest_call(item):
+ class_name, test_name = tools.split_node_id(item.nodeid)
+ yatest_logger.info("Test call (class_name: %s, test_name: %s)", class_name, test_name)
+
+
+def pytest_deselected(items):
+ config = pytest_config
+ if config.option.report_deselected:
+ for item in items:
+ deselected_item = DeselectedTestItem(item.nodeid, config.option.test_suffix)
+ config.ya_trace_reporter.on_start_test_class(deselected_item)
+ config.ya_trace_reporter.on_finish_test_case(deselected_item)
+ config.ya_trace_reporter.on_finish_test_class(deselected_item)
+
+
+@pytest.mark.trylast
+def pytest_collection_modifyitems(items, config):
+
+ def filter_items(filters):
+ filtered_items = []
+ deselected_items = []
+ for item in items:
+ canonical_node_id = str(CustomTestItem(item.nodeid, pytest_config.option.test_suffix))
+ matched = False
+ for flt in filters:
+ if "::" not in flt and "*" not in flt:
+ flt += "*" # add support for filtering by module name
+ if canonical_node_id.endswith(flt) or fnmatch.fnmatch(tools.escape_for_fnmatch(canonical_node_id), tools.escape_for_fnmatch(flt)):
+ matched = True
+ if matched:
+ filtered_items.append(item)
+ else:
+ deselected_items.append(item)
+
+ config.hook.pytest_deselected(items=deselected_items)
+ items[:] = filtered_items
+
+ def filter_by_full_name(filters):
+ filter_set = {flt for flt in filters}
+ filtered_items = []
+ deselected_items = []
+ for item in items:
+ if item.nodeid in filter_set:
+ filtered_items.append(item)
+ else:
+ deselected_items.append(item)
+
+ config.hook.pytest_deselected(items=deselected_items)
+ items[:] = filtered_items
+
+ # XXX - check to be removed when tests for peerdirs don't run
+ for item in items:
+ if not item.nodeid:
+ item._nodeid = os.path.basename(item.location[0])
+ if os.path.exists(config.option.test_list_path):
+ with open(config.option.test_list_path, 'r') as afile:
+ chunks = json.load(afile)
+ filters = chunks[config.option.modulo_index]
+ filter_by_full_name(filters)
+ else:
+ if config.option.test_filter:
+ filter_items(config.option.test_filter)
+ partition_mode = config.option.partition_mode
+ modulo = config.option.modulo
+ if modulo > 1:
+ items[:] = sorted(items, key=lambda item: item.nodeid)
+ modulo_index = config.option.modulo_index
+ split_by_tests = config.option.split_by_tests
+ items_by_classes = {}
+ res = []
+ for item in items:
+ if item.nodeid.count("::") == 2 and not split_by_tests:
+ class_name = item.nodeid.rsplit("::", 1)[0]
+ if class_name not in items_by_classes:
+ items_by_classes[class_name] = []
+ res.append(items_by_classes[class_name])
+ items_by_classes[class_name].append(item)
+ else:
+ res.append([item])
+ chunk_items = test_splitter.get_splitted_tests(res, modulo, modulo_index, partition_mode, is_sorted=True)
+ items[:] = []
+ for item in chunk_items:
+ items.extend(item)
+ yatest_logger.info("Modulo %s tests are: %s", modulo_index, chunk_items)
+
+ if config.option.mode == yatest_lib.ya.RunMode.Run:
+ for item in items:
+ test_item = NotLaunchedTestItem(item.nodeid, config.option.test_suffix)
+ config.ya_trace_reporter.on_start_test_class(test_item)
+ config.ya_trace_reporter.on_finish_test_case(test_item)
+ config.ya_trace_reporter.on_finish_test_class(test_item)
+ elif config.option.mode == yatest_lib.ya.RunMode.List:
+ tests = []
+ for item in items:
+ item = CustomTestItem(item.nodeid, pytest_config.option.test_suffix, item.keywords)
+ record = {
+ "class": item.class_name,
+ "test": item.test_name,
+ "tags": _get_item_tags(item),
+ }
+ tests.append(record)
+ if config.option.test_list_file:
+ with open(config.option.test_list_file, 'w') as afile:
+ json.dump(tests, afile)
+ # TODO prettyboy remove after test_tool release - currently it's required for backward compatibility
+ sys.stderr.write(json.dumps(tests))
+
+
+def pytest_collectreport(report):
+ if not report.passed:
+ if hasattr(pytest_config, 'ya_trace_reporter'):
+ test_item = TestItem(report, None, pytest_config.option.test_suffix)
+ pytest_config.ya_trace_reporter.on_error(test_item)
+ else:
+ sys.stderr.write(yatest_lib.tools.to_utf8(report.longrepr))
+
+
+@pytest.mark.tryfirst
+def pytest_pyfunc_call(pyfuncitem):
+ testfunction = pyfuncitem.obj
+ iscoroutinefunction = getattr(inspect, "iscoroutinefunction", None)
+ if iscoroutinefunction is not None and iscoroutinefunction(testfunction):
+ msg = "Coroutine functions are not natively supported and have been skipped.\n"
+ msg += "You need to install a suitable plugin for your async framework, for example:\n"
+ msg += " - pytest-asyncio\n"
+ msg += " - pytest-trio\n"
+ msg += " - pytest-tornasync"
+ warnings.warn(PytestUnhandledCoroutineWarning(msg.format(pyfuncitem.nodeid)))
+ _pytest.outcomes.skip(msg="coroutine function and no async plugin installed (see warnings)")
+ funcargs = pyfuncitem.funcargs
+ testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames}
+ pyfuncitem.retval = testfunction(**testargs)
+ return True
+
+
+@pytest.hookimpl(hookwrapper=True)
+def pytest_runtest_makereport(item, call):
+ def logreport(report, result, call):
+ test_item = TestItem(report, result, pytest_config.option.test_suffix)
+ if not pytest_config.suite_metrics and context.Ctx.get("YA_PYTEST_START_TIMESTAMP"):
+ pytest_config.suite_metrics["pytest_startup_duration"] = call.start - context.Ctx["YA_PYTEST_START_TIMESTAMP"]
+ pytest_config.ya_trace_reporter.dump_suite_metrics()
+
+ pytest_config.ya_trace_reporter.on_log_report(test_item)
+
+ if report.outcome == "failed":
+ yatest_logger.error(report.longrepr)
+
+ if report.when == "call":
+ _collect_test_rusage(item)
+ pytest_config.ya_trace_reporter.on_finish_test_case(test_item)
+ elif report.when == "setup":
+ pytest_config.ya_trace_reporter.on_start_test_class(test_item)
+ if report.outcome != "passed":
+ pytest_config.ya_trace_reporter.on_start_test_case(test_item)
+ pytest_config.ya_trace_reporter.on_finish_test_case(test_item)
+ else:
+ pytest_config.ya_trace_reporter.on_start_test_case(test_item)
+ elif report.when == "teardown":
+ if report.outcome == "failed":
+ pytest_config.ya_trace_reporter.on_start_test_case(test_item)
+ pytest_config.ya_trace_reporter.on_finish_test_case(test_item)
+ else:
+ pytest_config.ya_trace_reporter.on_finish_test_case(test_item, duration_only=True)
+ pytest_config.ya_trace_reporter.on_finish_test_class(test_item)
+
+ outcome = yield
+ rep = outcome.get_result()
+ result = None
+ if hasattr(item, 'retval') and item.retval is not None:
+ result = item.retval
+ if not pytest_config.from_ya_test:
+ ti = TestItem(rep, result, pytest_config.option.test_suffix)
+ tr = pytest_config.pluginmanager.getplugin('terminalreporter')
+ tr.write_line("{} - Validating canonical data is not supported when running standalone binary".format(ti), yellow=True, bold=True)
+ logreport(rep, result, call)
+
+
+def pytest_make_parametrize_id(config, val, argname):
+ # Avoid <, > symbols in canondata file names
+ if inspect.isfunction(val) and val.__name__ == "<lambda>":
+ return str(argname)
+ return None
+
+
+def get_formatted_error(report):
+ if isinstance(report.longrepr, tuple):
+ text = ""
+ for entry in report.longrepr:
+ text += colorize(entry)
+ else:
+ text = colorize(report.longrepr)
+ text = yatest_lib.tools.to_utf8(text)
+ return text
+
+
+def colorize(longrepr):
+ # use default pytest colorization
+ if pytest_config.option.tbstyle != "short":
+ io = py.io.TextIO()
+ if six.PY2:
+ writer = py.io.TerminalWriter(file=io)
+ else:
+ writer = _pytest._io.TerminalWriter(file=io)
+ # enable colorization
+ writer.hasmarkup = True
+
+ if hasattr(longrepr, 'reprtraceback') and hasattr(longrepr.reprtraceback, 'toterminal'):
+ longrepr.reprtraceback.toterminal(writer)
+ return io.getvalue().strip()
+ return yatest_lib.tools.to_utf8(longrepr)
+
+ text = yatest_lib.tools.to_utf8(longrepr)
+ pos = text.find("E ")
+ if pos == -1:
+ return text
+
+ bt, error = text[:pos], text[pos:]
+ filters = [
+ # File path, line number and function name
+ (re.compile(r"^(.*?):(\d+): in (\S+)", flags=re.MULTILINE), r"[[unimp]]\1[[rst]]:[[alt2]]\2[[rst]]: in [[alt1]]\3[[rst]]"),
+ ]
+ for regex, substitution in filters:
+ bt = regex.sub(substitution, bt)
+ return "{}[[bad]]{}".format(bt, error)
+
+
+class TestItem(object):
+
+ def __init__(self, report, result, test_suffix):
+ self._result = result
+ self.nodeid = report.nodeid
+ self._class_name, self._test_name = tools.split_node_id(self.nodeid, test_suffix)
+ self._error = None
+ self._status = None
+ self._process_report(report)
+ self._duration = hasattr(report, 'duration') and report.duration or 0
+ self._keywords = getattr(report, "keywords", {})
+
+ def _process_report(self, report):
+ if report.longrepr:
+ self.set_error(report)
+ if hasattr(report, 'when') and report.when != "call":
+ self.set_error(report.when + " failed:\n" + self._error)
+ else:
+ self.set_error("")
+
+ report_teststatus = _pytest.skipping.pytest_report_teststatus(report)
+ if report_teststatus is not None:
+ report_teststatus = report_teststatus[0]
+
+ if report_teststatus == 'xfailed':
+ self._status = 'xfail'
+ self.set_error(report.wasxfail, 'imp')
+ elif report_teststatus == 'xpassed':
+ self._status = 'xpass'
+ self.set_error("Test unexpectedly passed")
+ elif report.skipped:
+ self._status = 'skipped'
+ self.set_error(yatest_lib.tools.to_utf8(report.longrepr[-1]))
+ elif report.passed:
+ self._status = 'good'
+ self.set_error("")
+ else:
+ self._status = 'fail'
+
+ @property
+ def status(self):
+ return self._status
+
+ def set_status(self, status):
+ self._status = status
+
+ @property
+ def test_name(self):
+ return tools.normalize_name(self._test_name)
+
+ @property
+ def class_name(self):
+ return tools.normalize_name(self._class_name)
+
+ @property
+ def error(self):
+ return self._error
+
+ def set_error(self, entry, marker='bad'):
+ if isinstance(entry, _pytest.reports.BaseReport):
+ self._error = get_formatted_error(entry)
+ else:
+ self._error = "[[{}]]{}".format(yatest_lib.tools.to_str(marker), yatest_lib.tools.to_str(entry))
+
+ @property
+ def duration(self):
+ return self._duration
+
+ @property
+ def result(self):
+ if 'not_canonize' in self._keywords:
+ return None
+ return self._result
+
+ @property
+ def keywords(self):
+ return self._keywords
+
+ def __str__(self):
+ return "{}::{}".format(self.class_name, self.test_name)
+
+
+class CustomTestItem(TestItem):
+
+ def __init__(self, nodeid, test_suffix, keywords=None):
+ self._result = None
+ self.nodeid = nodeid
+ self._class_name, self._test_name = tools.split_node_id(nodeid, test_suffix)
+ self._duration = 0
+ self._error = ""
+ self._keywords = keywords if keywords is not None else {}
+
+
+class NotLaunchedTestItem(CustomTestItem):
+
+ def __init__(self, nodeid, test_suffix):
+ super(NotLaunchedTestItem, self).__init__(nodeid, test_suffix)
+ self._status = "not_launched"
+
+
+class CrashedTestItem(CustomTestItem):
+
+ def __init__(self, nodeid, test_suffix):
+ super(CrashedTestItem, self).__init__(nodeid, test_suffix)
+ self._status = "crashed"
+
+
+class DeselectedTestItem(CustomTestItem):
+
+ def __init__(self, nodeid, test_suffix):
+ super(DeselectedTestItem, self).__init__(nodeid, test_suffix)
+ self._status = "deselected"
+
+
+class TraceReportGenerator(object):
+
+ def __init__(self, out_file_path):
+ self._filename = out_file_path
+ self._file = open(out_file_path, 'w')
+ self._wreckage_filename = out_file_path + '.wreckage'
+ self._test_messages = {}
+ self._test_duration = {}
+ # Some machinery to avoid data corruption due sloppy fork()
+ self._current_test = (None, None)
+ self._pid = os.getpid()
+ self._check_intricate_respawn()
+
+ def _check_intricate_respawn(self):
+ pid_file = self._filename + '.pid'
+ try:
+ # python2 doesn't support open(f, 'x')
+ afile = os.fdopen(os.open(pid_file, os.O_WRONLY | os.O_EXCL | os.O_CREAT), 'w')
+ afile.write(str(self._pid))
+ afile.close()
+ return
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise
+
+ # Looks like the test binary was respawned
+ if from_ya_test():
+ try:
+ with open(pid_file) as afile:
+ prev_pid = afile.read()
+ except Exception as e:
+ prev_pid = '(failed to obtain previous pid: {})'.format(e)
+
+ parts = [
+ "Aborting test run: test machinery found that the test binary {} has already been run before.".format(sys.executable),
+ "Looks like test has incorrect respawn/relaunch logic within test binary.",
+ "Test should not try to restart itself - this is a poorly designed test case that leads to errors and could corrupt internal test machinery files.",
+ "Debug info: previous pid:{} current:{}".format(prev_pid, self._pid),
+ ]
+ msg = '\n'.join(parts)
+ yatest_logger.error(msg)
+
+ if filelock:
+ lock = filelock.FileLock(self._wreckage_filename + '.lock')
+ lock.acquire()
+
+ with open(self._wreckage_filename, 'a') as afile:
+ self._file = afile
+
+ self._dump_trace('chunk_event', {"errors": [('fail', '[[bad]]' + msg)]})
+
+ raise Exception(msg)
+ else:
+ # Test binary is launched without `ya make -t`'s testing machinery - don't rely on clean environment
+ pass
+
+ def on_start_test_class(self, test_item):
+ pytest_config.ya.set_test_item_node_id(test_item.nodeid)
+ class_name = test_item.class_name.decode('utf-8') if sys.version_info[0] < 3 else test_item.class_name
+ self._current_test = (class_name, None)
+ self.trace('test-started', {'class': class_name})
+
+ def on_finish_test_class(self, test_item):
+ pytest_config.ya.set_test_item_node_id(test_item.nodeid)
+ self.trace('test-finished', {'class': test_item.class_name.decode('utf-8') if sys.version_info[0] < 3 else test_item.class_name})
+
+ def on_start_test_case(self, test_item):
+ class_name = yatest_lib.tools.to_utf8(test_item.class_name)
+ subtest_name = yatest_lib.tools.to_utf8(test_item.test_name)
+ message = {
+ 'class': class_name,
+ 'subtest': subtest_name,
+ }
+ if test_item.nodeid in pytest_config.test_logs:
+ message['logs'] = pytest_config.test_logs[test_item.nodeid]
+ pytest_config.ya.set_test_item_node_id(test_item.nodeid)
+ self._current_test = (class_name, subtest_name)
+ self.trace('subtest-started', message)
+
+ def on_finish_test_case(self, test_item, duration_only=False):
+ if test_item.result is not None:
+ try:
+ result = canon.serialize(test_item.result)
+ except Exception as e:
+ yatest_logger.exception("Error while serializing test results")
+ test_item.set_error("Invalid test result: {}".format(e))
+ test_item.set_status("fail")
+ result = None
+ else:
+ result = None
+
+ if duration_only and test_item.nodeid in self._test_messages: # add teardown time
+ message = self._test_messages[test_item.nodeid]
+ else:
+ comment = self._test_messages[test_item.nodeid]['comment'] if test_item.nodeid in self._test_messages else ''
+ comment += self._get_comment(test_item)
+ message = {
+ 'class': yatest_lib.tools.to_utf8(test_item.class_name),
+ 'subtest': yatest_lib.tools.to_utf8(test_item.test_name),
+ 'status': test_item.status,
+ 'comment': comment,
+ 'result': result,
+ 'metrics': pytest_config.test_metrics.get(test_item.nodeid),
+ 'is_diff_test': 'diff_test' in test_item.keywords,
+ 'tags': _get_item_tags(test_item),
+ }
+ if test_item.nodeid in pytest_config.test_logs:
+ message['logs'] = pytest_config.test_logs[test_item.nodeid]
+
+ message['time'] = self._test_duration.get(test_item.nodeid, test_item.duration)
+
+ self.trace('subtest-finished', message)
+ self._test_messages[test_item.nodeid] = message
+
+ def dump_suite_metrics(self):
+ message = {"metrics": pytest_config.suite_metrics}
+ self.trace("suite-event", message)
+
+ def on_error(self, test_item):
+ self.trace('chunk_event', {"errors": [(test_item.status, self._get_comment(test_item))]})
+
+ def on_log_report(self, test_item):
+ if test_item.nodeid in self._test_duration:
+ self._test_duration[test_item.nodeid] += test_item._duration
+ else:
+ self._test_duration[test_item.nodeid] = test_item._duration
+
+ @staticmethod
+ def _get_comment(test_item):
+ msg = yatest_lib.tools.to_utf8(test_item.error)
+ if not msg:
+ return ""
+ return msg + "[[rst]]"
+
+ def _dump_trace(self, name, value):
+ event = {
+ 'timestamp': time.time(),
+ 'value': value,
+ 'name': name
+ }
+
+ data = yatest_lib.tools.to_str(json.dumps(event, ensure_ascii=False))
+ self._file.write(data + '\n')
+ self._file.flush()
+
+ def _check_sloppy_fork(self, name, value):
+ if self._pid == os.getpid():
+ return
+
+ yatest_logger.error("Skip tracing to avoid data corruption, name = %s, value = %s", name, value)
+
+ try:
+ # Lock wreckage tracefile to avoid race if multiple tests use fork sloppily
+ if filelock:
+ lock = filelock.FileLock(self._wreckage_filename + '.lock')
+ lock.acquire()
+
+ with open(self._wreckage_filename, 'a') as afile:
+ self._file = afile
+
+ parts = [
+ "It looks like you have leaked process - it could corrupt internal test machinery files.",
+ "Usually it happens when you casually use fork() without os._exit(),",
+ "which results in two pytest processes running at the same time.",
+ "Pid of the original pytest's process is {}, however current process has {} pid.".format(self._pid, os.getpid()),
+ ]
+ if self._current_test[1]:
+ parts.append("Most likely the problem is in '{}' test.".format(self._current_test))
+ else:
+ parts.append("Most likely new process was created before any test was launched (during the import stage?).")
+
+ if value.get('comment'):
+ comment = value.get('comment', '').strip()
+ # multiline comment
+ newline_required = '\n' if '\n' in comment else ''
+ parts.append("Debug info: name = '{}' comment:{}{}".format(name, newline_required, comment))
+ else:
+ val_str = json.dumps(value, ensure_ascii=False).encode('utf-8')
+ parts.append("Debug info: name = '{}' value = '{}'".format(name, base64.b64encode(val_str)))
+
+ msg = "[[bad]]{}".format('\n'.join(parts))
+ class_name, subtest_name = self._current_test
+ if subtest_name:
+ data = {
+ 'class': class_name,
+ 'subtest': subtest_name,
+ 'status': 'fail',
+ 'comment': msg,
+ }
+ # overwrite original status
+ self._dump_trace('subtest-finished', data)
+ else:
+ self._dump_trace('chunk_event', {"errors": [('fail', msg)]})
+ except Exception as e:
+ yatest_logger.exception(e)
+ finally:
+ os._exit(38)
+
+ def trace(self, name, value):
+ self._check_sloppy_fork(name, value)
+ self._dump_trace(name, value)
+
+
+class DryTraceReportGenerator(TraceReportGenerator):
+ """
+ Generator does not write any information.
+ """
+
+ def __init__(self, *args, **kwargs):
+ self._test_messages = {}
+ self._test_duration = {}
+
+ def trace(self, name, value):
+ pass
diff --git a/library/python/pytest/pytest.yatest.ini b/library/python/pytest/pytest.yatest.ini
new file mode 100644
index 0000000000..70d6c98516
--- /dev/null
+++ b/library/python/pytest/pytest.yatest.ini
@@ -0,0 +1,7 @@
+[pytest]
+pep8maxlinelength = 200
+norecursedirs = *
+pep8ignore = E127 E123 E226 E24
+filterwarnings =
+ ignore::pytest.RemovedInPytest4Warning
+addopts = -p no:warnings
diff --git a/library/python/pytest/rewrite.py b/library/python/pytest/rewrite.py
new file mode 100644
index 0000000000..ec188d847f
--- /dev/null
+++ b/library/python/pytest/rewrite.py
@@ -0,0 +1,123 @@
+from __future__ import absolute_import
+from __future__ import print_function
+
+import ast
+
+import py
+
+from _pytest.assertion import rewrite
+try:
+ import importlib.util
+except ImportError:
+ pass
+from __res import importer
+import sys
+import six
+
+
+def _get_state(config):
+ if hasattr(config, '_assertstate'):
+ return config._assertstate
+ return config._store[rewrite.assertstate_key]
+
+
+class AssertionRewritingHook(rewrite.AssertionRewritingHook):
+ def __init__(self, *args, **kwargs):
+ self.modules = {}
+ super(AssertionRewritingHook, self).__init__(*args, **kwargs)
+
+ def find_module(self, name, path=None):
+ co = self._find_module(name, path)
+ if co is not None:
+ return self
+
+ def _find_module(self, name, path=None):
+ state = _get_state(self.config)
+ if not self._should_rewrite(name, None, state):
+ return None
+ state.trace("find_module called for: %s" % name)
+
+ try:
+ if self.is_package(name):
+ return None
+ except ImportError:
+ return None
+
+ self._rewritten_names.add(name)
+
+ state.trace("rewriting %s" % name)
+ co = _rewrite_test(self.config, name)
+ if co is None:
+ # Probably a SyntaxError in the test.
+ return None
+ self.modules[name] = co, None
+ return co
+
+ def find_spec(self, name, path=None, target=None):
+ co = self._find_module(name, path)
+ if co is not None:
+ return importlib.util.spec_from_file_location(
+ name,
+ co.co_filename,
+ loader=self,
+ )
+
+ def _should_rewrite(self, name, fn, state):
+ if name.startswith("__tests__.") or name.endswith(".conftest"):
+ return True
+
+ return self._is_marked_for_rewrite(name, state)
+
+ def is_package(self, name):
+ return importer.is_package(name)
+
+ def get_source(self, name):
+ return importer.get_source(name)
+
+ if six.PY3:
+ def load_module(self, module):
+ co, _ = self.modules.pop(module.__name__)
+ try:
+ module.__file__ = co.co_filename
+ module.__cached__ = None
+ module.__loader__ = self
+ module.__spec__ = importlib.util.spec_from_file_location(module.__name__, co.co_filename, loader=self)
+ exec(co, module.__dict__)
+ except: # noqa
+ if module.__name__ in sys.modules:
+ del sys.modules[module.__name__]
+ raise
+ return sys.modules[module.__name__]
+
+ def exec_module(self, module):
+ if module.__name__ in self.modules:
+ self.load_module(module)
+ else:
+ super(AssertionRewritingHook, self).exec_module(module)
+
+
+def _rewrite_test(config, name):
+ """Try to read and rewrite *fn* and return the code object."""
+ state = _get_state(config)
+
+ source = importer.get_source(name)
+ if source is None:
+ return None
+
+ path = importer.get_filename(name)
+
+ try:
+ tree = ast.parse(source, filename=path)
+ except SyntaxError:
+ # Let this pop up again in the real import.
+ state.trace("failed to parse: %r" % (path,))
+ return None
+ rewrite.rewrite_asserts(tree, py.path.local(path), config)
+ try:
+ co = compile(tree, path, "exec", dont_inherit=True)
+ except SyntaxError:
+ # It's possible that this error is from some bug in the
+ # assertion rewriting, but I don't know of a fast way to tell.
+ state.trace("failed to compile: %r" % (path,))
+ return None
+ return co
diff --git a/library/python/pytest/ya.make b/library/python/pytest/ya.make
new file mode 100644
index 0000000000..060c92c313
--- /dev/null
+++ b/library/python/pytest/ya.make
@@ -0,0 +1,32 @@
+PY23_LIBRARY()
+
+OWNER(
+ g:yatool
+ dmitko
+)
+
+PY_SRCS(
+ __init__.py
+ main.py
+ rewrite.py
+ yatest_tools.py
+ context.py
+)
+
+PEERDIR(
+ contrib/python/dateutil
+ contrib/python/ipdb
+ contrib/python/py
+ contrib/python/pytest
+ contrib/python/requests
+ library/python/pytest/plugins
+ library/python/testing/yatest_common
+ library/python/testing/yatest_lib
+)
+
+RESOURCE_FILES(
+ PREFIX library/python/pytest/
+ pytest.yatest.ini
+)
+
+END()
diff --git a/library/python/pytest/yatest_tools.py b/library/python/pytest/yatest_tools.py
new file mode 100644
index 0000000000..6b8b896394
--- /dev/null
+++ b/library/python/pytest/yatest_tools.py
@@ -0,0 +1,304 @@
+# coding: utf-8
+
+import collections
+import functools
+import math
+import os
+import re
+import sys
+
+import yatest_lib.tools
+
+
+class Subtest(object):
+ def __init__(self, name, test_name, status, comment, elapsed, result=None, test_type=None, logs=None, cwd=None, metrics=None):
+ self._name = name
+ self._test_name = test_name
+ self.status = status
+ self.elapsed = elapsed
+ self.comment = comment
+ self.result = result
+ self.test_type = test_type
+ self.logs = logs or {}
+ self.cwd = cwd
+ self.metrics = metrics
+
+ def __eq__(self, other):
+ if not isinstance(other, Subtest):
+ return False
+ return self.name == other.name and self.test_name == other.test_name
+
+ def __str__(self):
+ return yatest_lib.tools.to_utf8(unicode(self))
+
+ def __unicode__(self):
+ return u"{}::{}".format(self.test_name, self.test_name)
+
+ @property
+ def name(self):
+ return yatest_lib.tools.to_utf8(self._name)
+
+ @property
+ def test_name(self):
+ return yatest_lib.tools.to_utf8(self._test_name)
+
+ def __repr__(self):
+ return "Subtest [{}::{} - {}[{}]: {}]".format(self.name, self.test_name, self.status, self.elapsed, self.comment)
+
+ def __hash__(self):
+ return hash(str(self))
+
+
+class SubtestInfo(object):
+
+ skipped_prefix = '[SKIPPED] '
+
+ @classmethod
+ def from_str(cls, s):
+ if s.startswith(SubtestInfo.skipped_prefix):
+ s = s[len(SubtestInfo.skipped_prefix):]
+ skipped = True
+
+ else:
+ skipped = False
+
+ return SubtestInfo(*s.rsplit(TEST_SUBTEST_SEPARATOR, 1), skipped=skipped)
+
+ def __init__(self, test, subtest="", skipped=False, **kwargs):
+ self.test = test
+ self.subtest = subtest
+ self.skipped = skipped
+ for key, value in kwargs.iteritems():
+ setattr(self, key, value)
+
+ def __str__(self):
+ s = ''
+
+ if self.skipped:
+ s += SubtestInfo.skipped_prefix
+
+ return s + TEST_SUBTEST_SEPARATOR.join([self.test, self.subtest])
+
+ def __repr__(self):
+ return str(self)
+
+
+class Status(object):
+ GOOD, XFAIL, FAIL, XPASS, MISSING, CRASHED, TIMEOUT = range(7)
+ SKIPPED = -100
+ NOT_LAUNCHED = -200
+ CANON_DIFF = -300
+ FLAKY = -1
+ BY_NAME = {'good': GOOD, 'fail': FAIL, 'xfail': XFAIL, 'xpass': XPASS, 'missing': MISSING, 'crashed': CRASHED,
+ 'skipped': SKIPPED, 'flaky': FLAKY, 'not_launched': NOT_LAUNCHED, 'timeout': TIMEOUT, 'diff': CANON_DIFF}
+ TO_STR = {GOOD: 'good', FAIL: 'fail', XFAIL: 'xfail', XPASS: 'xpass', MISSING: 'missing', CRASHED: 'crashed',
+ SKIPPED: 'skipped', FLAKY: 'flaky', NOT_LAUNCHED: 'not_launched', TIMEOUT: 'timeout', CANON_DIFF: 'diff'}
+
+
+class Test(object):
+ def __init__(self, name, path, status=None, comment=None, subtests=None):
+ self.name = name
+ self.path = path
+ self.status = status
+ self.comment = comment
+ self.subtests = subtests or []
+
+ def __eq__(self, other):
+ if not isinstance(other, Test):
+ return False
+ return self.name == other.name and self.path == other.path
+
+ def __str__(self):
+ return "Test [{} {}] - {} - {}".format(self.name, self.path, self.status, self.comment)
+
+ def __repr__(self):
+ return str(self)
+
+ def add_subtest(self, subtest):
+ self.subtests.append(subtest)
+
+ def setup_status(self, status, comment):
+ self.status = Status.BY_NAME[status or 'good']
+ if len(self.subtests) != 0:
+ self.status = max(self.status, max(s.status for s in self.subtests))
+ self.comment = comment
+
+ def subtests_by_status(self, status):
+ return [x.status for x in self.subtests].count(status)
+
+
+class NoMd5FileException(Exception):
+ pass
+
+
+TEST_SUBTEST_SEPARATOR = '::'
+
+
+# TODO: extract color theme logic from ya
+COLOR_THEME = {
+ 'test_name': 'light-blue',
+ 'test_project_path': 'dark-blue',
+ 'test_dir_desc': 'dark-magenta',
+ 'test_binary_path': 'light-gray',
+}
+
+
+# XXX: remove me
+class YaCtx(object):
+ pass
+
+ya_ctx = YaCtx()
+
+TRACE_FILE_NAME = "ytest.report.trace"
+
+
+def lazy(func):
+ mem = {}
+
+ @functools.wraps(func)
+ def wrapper():
+ if "results" not in mem:
+ mem["results"] = func()
+ return mem["results"]
+
+ return wrapper
+
+
+@lazy
+def _get_mtab():
+ if os.path.exists("/etc/mtab"):
+ with open("/etc/mtab") as afile:
+ data = afile.read()
+ return [line.split(" ") for line in data.split("\n") if line]
+ return []
+
+
+def get_max_filename_length(dirname):
+ """
+ Return maximum filename length for the filesystem
+ :return:
+ """
+ if sys.platform.startswith("linux"):
+ # Linux user's may work on mounted ecryptfs filesystem
+ # which has filename length limitations
+ for entry in _get_mtab():
+ mounted_dir, filesystem = entry[1], entry[2]
+ # http://unix.stackexchange.com/questions/32795/what-is-the-maximum-allowed-filename-and-folder-size-with-ecryptfs
+ if filesystem == "ecryptfs" and dirname and dirname.startswith(mounted_dir):
+ return 140
+ # default maximum filename length for most filesystems
+ return 255
+
+
+def get_unique_file_path(dir_path, filename, cache=collections.defaultdict(set)):
+ """
+ Get unique filename in dir with proper filename length, using given filename/dir.
+ File/dir won't be created (thread nonsafe)
+ :param dir_path: path to dir
+ :param filename: original filename
+ :return: unique filename
+ """
+ max_suffix = 10000
+ # + 1 symbol for dot before suffix
+ tail_length = int(round(math.log(max_suffix, 10))) + 1
+ # truncate filename length in accordance with filesystem limitations
+ filename, extension = os.path.splitext(filename)
+ # XXX
+ if sys.platform.startswith("win"):
+ # Trying to fit into MAX_PATH if it's possible.
+ # Remove after DEVTOOLS-1646
+ max_path = 260
+ filename_len = len(dir_path) + len(extension) + tail_length + len(os.sep)
+ if filename_len < max_path:
+ filename = yatest_lib.tools.trim_string(filename, max_path - filename_len)
+ filename = yatest_lib.tools.trim_string(filename, get_max_filename_length(dir_path) - tail_length - len(extension)) + extension
+ candidate = os.path.join(dir_path, filename)
+
+ key = dir_path + filename
+ counter = sorted(cache.get(key, {0, }))[-1]
+ while os.path.exists(candidate):
+ cache[key].add(counter)
+ counter += 1
+ assert counter < max_suffix
+ candidate = os.path.join(dir_path, filename + ".{}".format(counter))
+ return candidate
+
+
+def escape_for_fnmatch(s):
+ return s.replace("[", "&#91;").replace("]", "&#93;")
+
+
+def get_python_cmd(opts=None, use_huge=True, suite=None):
+ if opts and getattr(opts, 'flags', {}).get("USE_ARCADIA_PYTHON") == "no":
+ return ["python"]
+ if suite and not suite._use_arcadia_python:
+ return ["python"]
+ if use_huge:
+ return ["$(PYTHON)/python"]
+ ymake_path = opts.ymake_bin if opts and getattr(opts, 'ymake_bin', None) else "$(YMAKE)/ymake"
+ return [ymake_path, "--python"]
+
+
+def normalize_name(name):
+ replacements = [
+ ("\\", "\\\\"),
+ ("\n", "\\n"),
+ ("\t", "\\t"),
+ ("\r", "\\r"),
+ ]
+ for l, r in replacements:
+ name = name.replace(l, r)
+ return name
+
+
+def normalize_filename(filename):
+ """
+ Replace invalid for file names characters with string equivalents
+ :param some_string: string to be converted to a valid file name
+ :return: valid file name
+ """
+ not_allowed_pattern = r"[\[\]\/:*?\"\'<>|+\0\\\s\x0b\x0c]"
+ filename = re.sub(not_allowed_pattern, ".", filename)
+ return re.sub(r"\.{2,}", ".", filename)
+
+
+def get_test_log_file_path(output_dir, class_name, test_name, extension="log"):
+ """
+ get test log file path, platform dependant
+ :param output_dir: dir where log file should be placed
+ :param class_name: test class name
+ :param test_name: test name
+ :return: test log file name
+ """
+ if os.name == "nt":
+ # don't add class name to the log's filename
+ # to reduce it's length on windows
+ filename = test_name
+ else:
+ filename = "{}.{}".format(class_name, test_name)
+ if not filename:
+ filename = "test"
+ filename += "." + extension
+ filename = normalize_filename(filename)
+ return get_unique_file_path(output_dir, filename)
+
+
+def split_node_id(nodeid, test_suffix=None):
+ path, possible_open_bracket, params = nodeid.partition('[')
+ separator = "::"
+ if separator in path:
+ path, test_name = path.split(separator, 1)
+ else:
+ test_name = os.path.basename(path)
+ if test_suffix:
+ test_name += "::" + test_suffix
+ class_name = os.path.basename(path.strip())
+ if separator in test_name:
+ klass_name, test_name = test_name.split(separator, 1)
+ if not test_suffix:
+ # test suffix is used for flakes and pep8, no need to add class_name as it's === class_name
+ class_name += separator + klass_name
+ if separator in test_name:
+ test_name = test_name.split(separator)[-1]
+ test_name += possible_open_bracket + params
+ return yatest_lib.tools.to_utf8(class_name), yatest_lib.tools.to_utf8(test_name)
diff --git a/library/python/reservoir_sampling/README.md b/library/python/reservoir_sampling/README.md
new file mode 100644
index 0000000000..27674ba4f0
--- /dev/null
+++ b/library/python/reservoir_sampling/README.md
@@ -0,0 +1,11 @@
+### Overview
+Reservoir sampling is a family of randomized algorithms for choosing a simple random sample, without replacement, of k items from a population of unknown size n in a single pass over the items.
+
+### Example
+
+```jupyter
+In [1]: from library.python import reservoir_sampling
+
+In [2]: reservoir_sampling.reservoir_sampling(data=range(100), nsamples=10)
+Out[2]: [27, 19, 81, 45, 89, 78, 13, 36, 29, 9]
+```
diff --git a/library/python/reservoir_sampling/__init__.py b/library/python/reservoir_sampling/__init__.py
new file mode 100644
index 0000000000..4ee46ee5e1
--- /dev/null
+++ b/library/python/reservoir_sampling/__init__.py
@@ -0,0 +1,16 @@
+import random
+
+
+def reservoir_sampling(data, nsamples, prng=None):
+ if prng is None:
+ prng = random
+
+ result = []
+ for i, entry in enumerate(data):
+ if i < nsamples:
+ result.append(entry)
+ else:
+ j = prng.randint(0, i)
+ if j < nsamples:
+ result[j] = entry
+ return result
diff --git a/library/python/reservoir_sampling/ya.make b/library/python/reservoir_sampling/ya.make
new file mode 100644
index 0000000000..24cac20157
--- /dev/null
+++ b/library/python/reservoir_sampling/ya.make
@@ -0,0 +1,10 @@
+OWNER(
+ prettyboy
+ g:yatool
+)
+
+PY23_LIBRARY()
+
+PY_SRCS(__init__.py)
+
+END()
diff --git a/library/python/resource/__init__.py b/library/python/resource/__init__.py
new file mode 100644
index 0000000000..26503ef7fc
--- /dev/null
+++ b/library/python/resource/__init__.py
@@ -0,0 +1,49 @@
+from __res import find as __find, count, key_by_index, resfs_files as __resfs_files
+from __res import resfs_read, resfs_resolve, resfs_src # noqa
+
+import six
+
+
+def iterkeys(prefix='', strip_prefix=False):
+ decode = lambda s: s
+ if isinstance(prefix, six.text_type):
+ prefix = prefix.encode('utf-8')
+ decode = lambda s: s.decode('utf-8')
+
+ for i in six.moves.range(count()):
+ key = key_by_index(i)
+ if key.startswith(prefix):
+ if strip_prefix:
+ key = key[len(prefix):]
+ yield decode(key)
+
+
+def itervalues(prefix=b''):
+ for key in iterkeys(prefix=prefix):
+ value = find(key)
+ yield value
+
+
+def iteritems(prefix='', strip_prefix=False):
+ for key in iterkeys(prefix=prefix):
+ value = find(key)
+ if strip_prefix:
+ key = key[len(prefix):]
+ yield key, value
+
+
+def resfs_file_exists(path):
+ return resfs_src(path, resfs_file=True) is not None
+
+
+def resfs_files(prefix=''):
+ decode = lambda s: s
+ if isinstance(prefix, six.text_type):
+ decode = lambda s: s.decode('utf-8')
+ return [decode(s) for s in __resfs_files(prefix=prefix)]
+
+
+def find(path):
+ if isinstance(path, six.text_type):
+ path = path.encode('utf-8')
+ return __find(path)
diff --git a/library/python/resource/ut/lib/qw.txt b/library/python/resource/ut/lib/qw.txt
new file mode 100644
index 0000000000..50e37d5cac
--- /dev/null
+++ b/library/python/resource/ut/lib/qw.txt
@@ -0,0 +1 @@
+na gorshke sidel korol
diff --git a/library/python/resource/ut/lib/test_simple.py b/library/python/resource/ut/lib/test_simple.py
new file mode 100644
index 0000000000..52f006ff91
--- /dev/null
+++ b/library/python/resource/ut/lib/test_simple.py
@@ -0,0 +1,31 @@
+import six # noqa
+
+import library.python.resource as rs
+
+text = b'na gorshke sidel korol\n'
+
+
+def test_find():
+ assert rs.find('/qw.txt') == text
+
+
+def test_iter():
+ assert set(rs.iterkeys()).issuperset({'/qw.txt', '/prefix/1.txt', '/prefix/2.txt'})
+ assert set(rs.iterkeys(prefix='/prefix/')) == {'/prefix/1.txt', '/prefix/2.txt'}
+ assert set(rs.iterkeys(prefix='/prefix/', strip_prefix=True)) == {'1.txt', '2.txt'}
+ assert set(rs.iteritems(prefix='/prefix')) == {
+ ('/prefix/1.txt', text),
+ ('/prefix/2.txt', text),
+ }
+ assert set(rs.iteritems(prefix='/prefix', strip_prefix=True)) == {
+ ('/1.txt', text),
+ ('/2.txt', text),
+ }
+
+
+def test_resfs_files():
+ assert 'contrib/python/py/.dist-info/METADATA' in set(rs.resfs_files())
+
+
+def test_resfs_read():
+ assert 'Metadata-Version' in rs.resfs_read('contrib/python/py/.dist-info/METADATA').decode('utf-8')
diff --git a/library/python/resource/ut/lib/ya.make b/library/python/resource/ut/lib/ya.make
new file mode 100644
index 0000000000..693e388878
--- /dev/null
+++ b/library/python/resource/ut/lib/ya.make
@@ -0,0 +1,17 @@
+PY23_LIBRARY()
+
+OWNER(pg)
+
+TEST_SRCS(test_simple.py)
+
+PEERDIR(
+ library/python/resource
+)
+
+RESOURCE(
+ qw.txt /qw.txt
+ qw.txt /prefix/1.txt
+ qw.txt /prefix/2.txt
+)
+
+END()
diff --git a/library/python/resource/ut/py2/ya.make b/library/python/resource/ut/py2/ya.make
new file mode 100644
index 0000000000..5085610faf
--- /dev/null
+++ b/library/python/resource/ut/py2/ya.make
@@ -0,0 +1,9 @@
+PY2TEST()
+
+OWNER(pg)
+
+PEERDIR(
+ library/python/resource/ut/lib
+)
+
+END()
diff --git a/library/python/resource/ut/py3/ya.make b/library/python/resource/ut/py3/ya.make
new file mode 100644
index 0000000000..64eb2e83ce
--- /dev/null
+++ b/library/python/resource/ut/py3/ya.make
@@ -0,0 +1,9 @@
+PY3TEST()
+
+OWNER(pg)
+
+PEERDIR(
+ library/python/resource/ut/lib
+)
+
+END()
diff --git a/library/python/resource/ut/ya.make b/library/python/resource/ut/ya.make
new file mode 100644
index 0000000000..a5ec192d74
--- /dev/null
+++ b/library/python/resource/ut/ya.make
@@ -0,0 +1,6 @@
+OWNER(pg)
+
+RECURSE(
+ py2
+ py3
+)
diff --git a/library/python/resource/ya.make b/library/python/resource/ya.make
new file mode 100644
index 0000000000..989329fa4b
--- /dev/null
+++ b/library/python/resource/ya.make
@@ -0,0 +1,13 @@
+PY23_LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ contrib/python/six
+)
+
+PY_SRCS(__init__.py)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/python/runtime_py3/__res.pyx b/library/python/runtime_py3/__res.pyx
new file mode 100644
index 0000000000..97190d9f29
--- /dev/null
+++ b/library/python/runtime_py3/__res.pyx
@@ -0,0 +1,36 @@
+from _codecs import utf_8_decode, utf_8_encode
+
+from libcpp cimport bool
+
+from util.generic.string cimport TString, TStringBuf
+
+
+cdef extern from "library/cpp/resource/resource.h" namespace "NResource":
+ cdef size_t Count() except +
+ cdef TStringBuf KeyByIndex(size_t idx) except +
+ cdef bool FindExact(const TStringBuf key, TString* result) nogil except +
+
+
+def count():
+ return Count()
+
+
+def key_by_index(idx):
+ cdef TStringBuf ret = KeyByIndex(idx)
+
+ return ret.Data()[:ret.Size()]
+
+
+def find(s):
+ cdef TString res
+
+ if isinstance(s, str):
+ s = utf_8_encode(s)[0]
+
+ if FindExact(TStringBuf(s, len(s)), &res):
+ return res.c_str()[:res.length()]
+
+ return None
+
+
+include "importer.pxi"
diff --git a/library/python/runtime_py3/entry_points.py b/library/python/runtime_py3/entry_points.py
new file mode 100644
index 0000000000..05098723cb
--- /dev/null
+++ b/library/python/runtime_py3/entry_points.py
@@ -0,0 +1,52 @@
+import sys
+
+import __res
+
+
+def repl():
+ user_ns = {}
+ py_main = __res.find('PY_MAIN')
+
+ if py_main:
+ mod_name, func_name = (py_main.split(b':', 1) + [None])[:2]
+ try:
+ import importlib
+ mod = importlib.import_module(mod_name.decode('UTF-8'))
+ user_ns = mod.__dict__
+ except:
+ import traceback
+ traceback.print_exc()
+
+ if func_name and '__main__' not in user_ns:
+ def run(args):
+ if isinstance(args, str):
+ import shlex
+ args = shlex.split(args)
+
+ import sys
+ sys.argv = [sys.argv[0]] + args
+ getattr(mod, func_name)()
+
+ user_ns['__main__'] = run
+
+ try:
+ import IPython
+ except ModuleNotFoundError:
+ pass
+ else:
+ return IPython.start_ipython(user_ns=user_ns)
+
+ import code
+ code.interact(local=user_ns)
+
+
+def resource_files():
+ sys.stdout.buffer.write(b'\n'.join(sorted(__res.resfs_files()) + [b'']))
+
+
+def run_constructors():
+ for key, module_name in __res.iter_keys(b'py/constructors/'):
+ import importlib
+ module = importlib.import_module(module_name.decode())
+ init_func = getattr(module, __res.find(key).decode())
+ init_func()
diff --git a/library/python/runtime_py3/importer.pxi b/library/python/runtime_py3/importer.pxi
new file mode 100644
index 0000000000..904f94dea2
--- /dev/null
+++ b/library/python/runtime_py3/importer.pxi
@@ -0,0 +1,571 @@
+import marshal
+import sys
+from _codecs import utf_8_decode, utf_8_encode
+from _frozen_importlib import _call_with_frames_removed, spec_from_loader, BuiltinImporter
+from _frozen_importlib_external import _os, _path_isfile, _path_isdir, _path_isabs, path_sep, _path_join, _path_split
+from _io import FileIO
+
+import __res as __resource
+
+_b = lambda x: x if isinstance(x, bytes) else utf_8_encode(x)[0]
+_s = lambda x: x if isinstance(x, str) else utf_8_decode(x)[0]
+env_entry_point = b'Y_PYTHON_ENTRY_POINT'
+env_source_root = b'Y_PYTHON_SOURCE_ROOT'
+cfg_source_root = b'arcadia-source-root'
+env_extended_source_search = b'Y_PYTHON_EXTENDED_SOURCE_SEARCH'
+res_ya_ide_venv = b'YA_IDE_VENV'
+executable = sys.executable or 'Y_PYTHON'
+sys.modules['run_import_hook'] = __resource
+
+# This is the prefix in contrib/tools/python3/src/Lib/ya.make.
+py_prefix = b'py/'
+py_prefix_len = len(py_prefix)
+
+YA_IDE_VENV = __resource.find(res_ya_ide_venv)
+Y_PYTHON_EXTENDED_SOURCE_SEARCH = _os.environ.get(env_extended_source_search) or YA_IDE_VENV
+
+
+def _init_venv():
+ if not _path_isabs(executable):
+ raise RuntimeError('path in sys.executable is not absolute: {}'.format(executable))
+
+ # Creative copy-paste from site.py
+ exe_dir, _ = _path_split(executable)
+ site_prefix, _ = _path_split(exe_dir)
+ libpath = _path_join(site_prefix, 'lib',
+ 'python%d.%d' % sys.version_info[:2],
+ 'site-packages')
+ sys.path.insert(0, libpath)
+
+ # emulate site.venv()
+ sys.prefix = site_prefix
+ sys.exec_prefix = site_prefix
+
+ conf_basename = 'pyvenv.cfg'
+ candidate_confs = [
+ conffile for conffile in (
+ _path_join(exe_dir, conf_basename),
+ _path_join(site_prefix, conf_basename)
+ )
+ if _path_isfile(conffile)
+ ]
+ if not candidate_confs:
+ raise RuntimeError('{} not found'.format(conf_basename))
+ virtual_conf = candidate_confs[0]
+ with FileIO(virtual_conf, 'r') as f:
+ for line in f:
+ if b'=' in line:
+ key, _, value = line.partition(b'=')
+ key = key.strip().lower()
+ value = value.strip()
+ if key == cfg_source_root:
+ return value
+ raise RuntimeError('{} key not found in {}'.format(cfg_source_root, virtual_conf))
+
+
+def _get_source_root():
+ env_value = _os.environ.get(env_source_root)
+ if env_value or not YA_IDE_VENV:
+ return env_value
+
+ return _init_venv()
+
+
+Y_PYTHON_SOURCE_ROOT = _get_source_root()
+
+
+def _print(*xs):
+ """
+ This is helpful for debugging, since automatic bytes to str conversion is
+ not available yet. It is also possible to debug with GDB by breaking on
+ __Pyx_AddTraceback (with Python GDB pretty printers enabled).
+ """
+ parts = []
+ for s in xs:
+ if not isinstance(s, (bytes, str)):
+ s = str(s)
+ parts.append(_s(s))
+ sys.stderr.write(' '.join(parts) + '\n')
+
+
+def file_bytes(path):
+ # 'open' is not avaiable yet.
+ with FileIO(path, 'r') as f:
+ return f.read()
+
+
+def iter_keys(prefix):
+ l = len(prefix)
+ for idx in range(__resource.count()):
+ key = __resource.key_by_index(idx)
+ if key.startswith(prefix):
+ yield key, key[l:]
+
+
+def iter_py_modules(with_keys=False):
+ for key, path in iter_keys(b'resfs/file/' + py_prefix):
+ if path.endswith(b'.py'): # It may also end with '.pyc'.
+ mod = _s(path[:-3].replace(b'/', b'.'))
+ if with_keys:
+ yield key, mod
+ else:
+ yield mod
+
+
+def iter_prefixes(s):
+ i = s.find('.')
+ while i >= 0:
+ yield s[:i]
+ i = s.find('.', i + 1)
+
+
+def resfs_resolve(path):
+ """
+ Return the absolute path of a root-relative path if it exists.
+ """
+ path = _b(path)
+ if Y_PYTHON_SOURCE_ROOT:
+ if not path.startswith(Y_PYTHON_SOURCE_ROOT):
+ path = _b(path_sep).join((Y_PYTHON_SOURCE_ROOT, path))
+ if _path_isfile(path):
+ return path
+
+
+def resfs_src(key, resfs_file=False):
+ """
+ Return the root-relative file path of a resource key.
+ """
+ if resfs_file:
+ key = b'resfs/file/' + _b(key)
+ return __resource.find(b'resfs/src/' + _b(key))
+
+
+def resfs_read(path, builtin=None):
+ """
+ Return the bytes of the resource file at path, or None.
+ If builtin is True, do not look for it on the filesystem.
+ If builtin is False, do not look in the builtin resources.
+ """
+ if builtin is not True:
+ arcpath = resfs_src(path, resfs_file=True)
+ if arcpath:
+ fspath = resfs_resolve(arcpath)
+ if fspath:
+ return file_bytes(fspath)
+
+ if builtin is not False:
+ return __resource.find(b'resfs/file/' + _b(path))
+
+
+def resfs_files(prefix=b''):
+ """
+ List builtin resource file paths.
+ """
+ return [key[11:] for key, _ in iter_keys(b'resfs/file/' + _b(prefix))]
+
+
+def mod_path(mod):
+ """
+ Return the resfs path to the source code of the module with the given name.
+ """
+ return py_prefix + _b(mod).replace(b'.', b'/') + b'.py'
+
+
+class ResourceImporter(object):
+
+ """ A meta_path importer that loads code from built-in resources.
+ """
+
+ def __init__(self):
+ self.memory = set(iter_py_modules()) # Set of importable module names.
+ self.source_map = {} # Map from file names to module names.
+ self._source_name = {} # Map from original to altered module names.
+ self._package_prefix = ''
+ if Y_PYTHON_SOURCE_ROOT and Y_PYTHON_EXTENDED_SOURCE_SEARCH:
+ self.arcadia_source_finder = ArcadiaSourceFinder(_s(Y_PYTHON_SOURCE_ROOT))
+ else:
+ self.arcadia_source_finder = None
+
+ for p in list(self.memory) + list(sys.builtin_module_names):
+ for pp in iter_prefixes(p):
+ k = pp + '.__init__'
+ if k not in self.memory:
+ self.memory.add(k)
+
+ def for_package(self, name):
+ import copy
+ importer = copy.copy(self)
+ importer._package_prefix = name + '.'
+ return importer
+
+ def _find_mod_path(self, fullname):
+ """Find arcadia relative path by module name"""
+ relpath = resfs_src(mod_path(fullname), resfs_file=True)
+ if relpath or not self.arcadia_source_finder:
+ return relpath
+ return self.arcadia_source_finder.get_module_path(fullname)
+
+ def find_spec(self, fullname, path=None, target=None):
+ try:
+ is_package = self.is_package(fullname)
+ except ImportError:
+ return None
+ return spec_from_loader(fullname, self, is_package=is_package)
+
+ def find_module(self, fullname, path=None):
+ """For backward compatibility."""
+ spec = self.find_spec(fullname, path)
+ return spec.loader if spec is not None else None
+
+ def create_module(self, spec):
+ """Use default semantics for module creation."""
+
+ def exec_module(self, module):
+ code = self.get_code(module.__name__)
+ module.__file__ = code.co_filename
+ if self.is_package(module.__name__):
+ module.__path__= [executable + path_sep + module.__name__.replace('.', path_sep)]
+ # exec(code, module.__dict__)
+ _call_with_frames_removed(exec, code, module.__dict__)
+
+ # PEP-302 extension 1 of 3: data loader.
+ def get_data(self, path):
+ path = _b(path)
+ abspath = resfs_resolve(path)
+ if abspath:
+ return file_bytes(abspath)
+ path = path.replace(_b('\\'), _b('/'))
+ data = resfs_read(path, builtin=True)
+ if data is None:
+ raise IOError(path) # Y_PYTHON_ENTRY_POINT=:resource_files
+ return data
+
+ # PEP-302 extension 2 of 3: get __file__ without importing.
+ def get_filename(self, fullname):
+ modname = fullname
+ if self.is_package(fullname):
+ fullname += '.__init__'
+ relpath = self._find_mod_path(fullname)
+ if isinstance(relpath, bytes):
+ relpath = _s(relpath)
+ return relpath or modname
+
+ # PEP-302 extension 3 of 3: packaging introspection.
+ # Used by `linecache` (while printing tracebacks) unless module filename
+ # exists on the filesystem.
+ def get_source(self, fullname):
+ fullname = self._source_name.get(fullname) or fullname
+ if self.is_package(fullname):
+ fullname += '.__init__'
+
+ relpath = self.get_filename(fullname)
+ if relpath:
+ abspath = resfs_resolve(relpath)
+ if abspath:
+ return _s(file_bytes(abspath))
+ data = resfs_read(mod_path(fullname))
+ return _s(data) if data else ''
+
+ def get_code(self, fullname):
+ modname = fullname
+ if self.is_package(fullname):
+ fullname += '.__init__'
+
+ path = mod_path(fullname)
+ relpath = self._find_mod_path(fullname)
+ if relpath:
+ abspath = resfs_resolve(relpath)
+ if abspath:
+ data = file_bytes(abspath)
+ return compile(data, _s(abspath), 'exec', dont_inherit=True)
+
+ yapyc_path = path + b'.yapyc3'
+ yapyc_data = resfs_read(yapyc_path, builtin=True)
+ if yapyc_data:
+ return marshal.loads(yapyc_data)
+ else:
+ py_data = resfs_read(path, builtin=True)
+ if py_data:
+ return compile(py_data, _s(relpath), 'exec', dont_inherit=True)
+ else:
+ # This covers packages with no __init__.py in resources.
+ return compile('', modname, 'exec', dont_inherit=True)
+
+ def is_package(self, fullname):
+ if fullname in self.memory:
+ return False
+
+ if fullname + '.__init__' in self.memory:
+ return True
+
+ if self.arcadia_source_finder:
+ return self.arcadia_source_finder.is_package(fullname)
+
+ raise ImportError(fullname)
+
+ # Extension for contrib/python/coverage.
+ def file_source(self, filename):
+ """
+ Return the key of the module source by its resource path.
+ """
+ if not self.source_map:
+ for key, mod in iter_py_modules(with_keys=True):
+ path = self.get_filename(mod)
+ self.source_map[path] = key
+
+ if filename in self.source_map:
+ return self.source_map[filename]
+
+ if resfs_read(filename, builtin=True) is not None:
+ return b'resfs/file/' + _b(filename)
+
+ return b''
+
+ # Extension for pkgutil.iter_modules.
+ def iter_modules(self, prefix=''):
+ import re
+ rx = re.compile(re.escape(self._package_prefix) + r'([^.]+)(\.__init__)?$')
+ for p in self.memory:
+ m = rx.match(p)
+ if m:
+ yield prefix + m.group(1), m.group(2) is not None
+ if self.arcadia_source_finder:
+ for m in self.arcadia_source_finder.iter_modules(self._package_prefix, prefix):
+ yield m
+
+ def get_resource_reader(self, fullname):
+ try:
+ if not self.is_package(fullname):
+ return None
+ except ImportError:
+ return None
+ return _ResfsResourceReader(self, fullname)
+
+
+class _ResfsResourceReader:
+
+ def __init__(self, importer, fullname):
+ self.importer = importer
+ self.fullname = fullname
+
+ import os
+ self.prefix = "{}/".format(os.path.dirname(self.importer.get_filename(self.fullname)))
+
+ def open_resource(self, resource):
+ path = f'{self.prefix}{resource}'
+ from io import BytesIO
+ try:
+ return BytesIO(self.importer.get_data(path))
+ except OSError:
+ raise FileNotFoundError(path)
+
+ def resource_path(self, resource):
+ # All resources are in the binary file, so there is no path to the file.
+ # Raising FileNotFoundError tells the higher level API to extract the
+ # binary data and create a temporary file.
+ raise FileNotFoundError
+
+ def is_resource(self, name):
+ path = f'{self.prefix}{name}'
+ try:
+ self.importer.get_data(path)
+ except OSError:
+ return False
+ return True
+
+ def contents(self):
+ subdirs_seen = set()
+ for key in resfs_files(self.prefix):
+ relative = key[len(self.prefix):]
+ res_or_subdir, *other = relative.split(b'/')
+ if not other:
+ yield _s(res_or_subdir)
+ elif res_or_subdir not in subdirs_seen:
+ subdirs_seen.add(res_or_subdir)
+ yield _s(res_or_subdir)
+
+
+class BuiltinSubmoduleImporter(BuiltinImporter):
+ @classmethod
+ def find_spec(cls, fullname, path=None, target=None):
+ if path is not None:
+ return super().find_spec(fullname, None, target)
+ else:
+ return None
+
+
+class ArcadiaSourceFinder:
+ """
+ Search modules and packages in arcadia source tree.
+ See https://wiki.yandex-team.ru/devtools/extended-python-source-search/ for details
+ """
+ NAMESPACE_PREFIX = b'py/namespace/'
+ PY_EXT = '.py'
+ YA_MAKE = 'ya.make'
+
+ def __init__(self, source_root):
+ self.source_root = source_root
+ self.module_path_cache = {'': set()}
+ for key, dirty_path in iter_keys(self.NAMESPACE_PREFIX):
+ # dirty_path contains unique prefix to prevent repeatable keys in the resource storage
+ path = dirty_path.split(b'/', 1)[1]
+ namespaces = __resource.find(key).split(b':')
+ for n in namespaces:
+ package_name = _s(n.rstrip(b'.'))
+ self.module_path_cache.setdefault(package_name, set()).add(_s(path))
+ # Fill parents with default empty path set if parent doesn't exist in the cache yet
+ while package_name:
+ package_name = package_name.rpartition('.')[0]
+ if package_name in self.module_path_cache:
+ break
+ self.module_path_cache.setdefault(package_name, set())
+ for package_name in self.module_path_cache.keys():
+ self._add_parent_dirs(package_name, visited=set())
+
+ def get_module_path(self, fullname):
+ """
+ Find file path for module 'fullname'.
+ For packages caller pass fullname as 'package.__init__'.
+ Return None if nothing is found.
+ """
+ try:
+ if not self.is_package(fullname):
+ return _b(self._cache_module_path(fullname))
+ except ImportError:
+ pass
+
+ def is_package(self, fullname):
+ """Check if fullname is a package. Raise ImportError if fullname is not found"""
+ path = self._cache_module_path(fullname)
+ if isinstance(path, set):
+ return True
+ if isinstance(path, str):
+ return False
+ raise ImportError(fullname)
+
+ def iter_modules(self, package_prefix, prefix):
+ paths = self._cache_module_path(package_prefix.rstrip('.'))
+ if paths is not None:
+ # Note: it's ok to yield duplicates because pkgutil discards them
+
+ # Yield from cache
+ import re
+ rx = re.compile(re.escape(package_prefix) + r'([^.]+)$')
+ for mod, path in self.module_path_cache.items():
+ if path is not None:
+ m = rx.match(mod)
+ if m:
+ yield prefix + m.group(1), self.is_package(mod)
+
+ # Yield from file system
+ for path in paths:
+ abs_path = _path_join(self.source_root, path)
+ for dir_item in _os.listdir(abs_path):
+ if self._path_is_simple_dir(_path_join(abs_path, dir_item)):
+ yield prefix + dir_item, True
+ elif dir_item.endswith(self.PY_EXT) and _path_isfile(_path_join(abs_path, dir_item)):
+ yield prefix + dir_item[:-len(self.PY_EXT)], False
+
+ def _path_is_simple_dir(self, abs_path):
+ """
+ Check if path is a directory but doesn't contain ya.make file.
+ We don't want to steal directory from nested project and treat it as a package
+ """
+ return _path_isdir(abs_path) and not _path_isfile(_path_join(abs_path, self.YA_MAKE))
+
+ def _find_module_in_paths(self, find_package_only, paths, module):
+ """Auxiliary method. See _cache_module_path() for details"""
+ if paths:
+ package_paths = set()
+ for path in paths:
+ rel_path = _path_join(path, module)
+ if not find_package_only:
+ # Check if file_path is a module
+ module_path = rel_path + self.PY_EXT
+ if _path_isfile(_path_join(self.source_root, module_path)):
+ return module_path
+ # Check if file_path is a package
+ if self._path_is_simple_dir(_path_join(self.source_root, rel_path)):
+ package_paths.add(rel_path)
+ if package_paths:
+ return package_paths
+
+ def _cache_module_path(self, fullname, find_package_only=False):
+ """
+ Find module path or package directory paths and save result in the cache
+
+ find_package_only=True - don't try to find module
+
+ Returns:
+ List of relative package paths - for a package
+ Relative module path - for a module
+ None - module or package is not found
+ """
+ if fullname not in self.module_path_cache:
+ parent, _, tail = fullname.rpartition('.')
+ parent_paths = self._cache_module_path(parent, find_package_only=True)
+ self.module_path_cache[fullname] = self._find_module_in_paths(find_package_only, parent_paths, tail)
+ return self.module_path_cache[fullname]
+
+ def _add_parent_dirs(self, package_name, visited):
+ if not package_name or package_name in visited:
+ return
+ visited.add(package_name)
+
+ parent, _, tail = package_name.rpartition('.')
+ self._add_parent_dirs(parent, visited)
+
+ paths = self.module_path_cache[package_name]
+ for parent_path in self.module_path_cache[parent]:
+ rel_path = _path_join(parent_path, tail)
+ if self._path_is_simple_dir(_path_join(self.source_root, rel_path)):
+ paths.add(rel_path)
+
+
+def excepthook(*args, **kws):
+ # traceback module cannot be imported at module level, because interpreter
+ # is not fully initialized yet
+
+ import traceback
+
+ return traceback.print_exception(*args, **kws)
+
+
+importer = ResourceImporter()
+
+
+def executable_path_hook(path):
+ if path == executable:
+ return importer
+
+ if path.startswith(executable + path_sep):
+ return importer.for_package(path[len(executable + path_sep):].replace(path_sep, '.'))
+
+ raise ImportError(path)
+
+
+if YA_IDE_VENV:
+ sys.meta_path.append(importer)
+ sys.meta_path.append(BuiltinSubmoduleImporter)
+ if executable not in sys.path:
+ sys.path.append(executable)
+ sys.path_hooks.append(executable_path_hook)
+else:
+ sys.meta_path.insert(0, BuiltinSubmoduleImporter)
+ sys.meta_path.insert(0, importer)
+ if executable not in sys.path:
+ sys.path.insert(0, executable)
+ sys.path_hooks.insert(0, executable_path_hook)
+
+sys.path_importer_cache[executable] = importer
+
+# Indicator that modules and resources are built-in rather than on the file system.
+sys.is_standalone_binary = True
+sys.frozen = True
+
+# Set of names of importable modules.
+sys.extra_modules = importer.memory
+
+# Use custom implementation of traceback printer.
+# Built-in printer (PyTraceBack_Print) does not support custom module loaders
+sys.excepthook = excepthook
diff --git a/library/python/runtime_py3/main/get_py_main.cpp b/library/python/runtime_py3/main/get_py_main.cpp
new file mode 100644
index 0000000000..67c400d4f4
--- /dev/null
+++ b/library/python/runtime_py3/main/get_py_main.cpp
@@ -0,0 +1,8 @@
+#include <library/cpp/resource/resource.h>
+
+#include <stdlib.h>
+
+extern "C" char* GetPyMain() {
+ TString res = NResource::Find("PY_MAIN");
+ return strdup(res.c_str());
+}
diff --git a/library/python/runtime_py3/main/main.c b/library/python/runtime_py3/main/main.c
new file mode 100644
index 0000000000..3159800615
--- /dev/null
+++ b/library/python/runtime_py3/main/main.c
@@ -0,0 +1,231 @@
+#include <Python.h>
+#include <contrib/tools/python3/src/Include/internal/pycore_runtime.h> // _PyRuntime_Initialize()
+
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+
+void Py_InitArgcArgv(int argc, wchar_t **argv);
+char* GetPyMain();
+
+static const char* env_entry_point = "Y_PYTHON_ENTRY_POINT";
+static const char* env_bytes_warning = "Y_PYTHON_BYTES_WARNING";
+
+#ifdef _MSC_VER
+extern char** environ;
+
+void unsetenv(const char* name) {
+ const int n = strlen(name);
+ char** dst = environ;
+ for (char** src = environ; *src; src++)
+ if (strncmp(*src, name, n) || (*src)[n] != '=')
+ *dst++ = *src;
+ *dst = NULL;
+}
+#endif
+
+static int RunModule(const char *modname)
+{
+ PyObject *module, *runpy, *runmodule, *runargs, *result;
+ runpy = PyImport_ImportModule("runpy");
+ if (runpy == NULL) {
+ fprintf(stderr, "Could not import runpy module\n");
+ PyErr_Print();
+ return -1;
+ }
+ runmodule = PyObject_GetAttrString(runpy, "_run_module_as_main");
+ if (runmodule == NULL) {
+ fprintf(stderr, "Could not access runpy._run_module_as_main\n");
+ PyErr_Print();
+ Py_DECREF(runpy);
+ return -1;
+ }
+ module = PyUnicode_FromString(modname);
+ if (module == NULL) {
+ fprintf(stderr, "Could not convert module name to unicode\n");
+ PyErr_Print();
+ Py_DECREF(runpy);
+ Py_DECREF(runmodule);
+ return -1;
+ }
+ runargs = Py_BuildValue("(Oi)", module, 0);
+ if (runargs == NULL) {
+ fprintf(stderr,
+ "Could not create arguments for runpy._run_module_as_main\n");
+ PyErr_Print();
+ Py_DECREF(runpy);
+ Py_DECREF(runmodule);
+ Py_DECREF(module);
+ return -1;
+ }
+ result = PyObject_Call(runmodule, runargs, NULL);
+ if (result == NULL) {
+ PyErr_Print();
+ }
+ Py_DECREF(runpy);
+ Py_DECREF(runmodule);
+ Py_DECREF(module);
+ Py_DECREF(runargs);
+ if (result == NULL) {
+ return -1;
+ }
+ Py_DECREF(result);
+ return 0;
+}
+
+static int pymain(int argc, char** argv) {
+ PyStatus status = _PyRuntime_Initialize();
+ if (PyStatus_Exception(status)) {
+ Py_ExitStatusException(status);
+ }
+
+ int i, sts = 1;
+ char* oldloc = NULL;
+ wchar_t** argv_copy = NULL;
+ /* We need a second copies, as Python might modify the first one. */
+ wchar_t** argv_copy2 = NULL;
+ char* entry_point_copy = NULL;
+
+ if (argc > 0) {
+ argv_copy = PyMem_RawMalloc(sizeof(wchar_t*) * argc);
+ argv_copy2 = PyMem_RawMalloc(sizeof(wchar_t*) * argc);
+ if (!argv_copy || !argv_copy2) {
+ fprintf(stderr, "out of memory\n");
+ goto error;
+ }
+ }
+
+ PyConfig config;
+ PyConfig_InitPythonConfig(&config);
+ config.pathconfig_warnings = 0; /* Suppress errors from getpath.c */
+
+ const char* bytes_warning = getenv(env_bytes_warning);
+ if (bytes_warning) {
+ config.bytes_warning = atoi(bytes_warning);
+ }
+
+ oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL));
+ if (!oldloc) {
+ fprintf(stderr, "out of memory\n");
+ goto error;
+ }
+
+ setlocale(LC_ALL, "");
+ for (i = 0; i < argc; i++) {
+ argv_copy[i] = Py_DecodeLocale(argv[i], NULL);
+ argv_copy2[i] = argv_copy[i];
+ if (!argv_copy[i]) {
+ fprintf(stderr, "Unable to decode the command line argument #%i\n",
+ i + 1);
+ argc = i;
+ goto error;
+ }
+ }
+ setlocale(LC_ALL, oldloc);
+ PyMem_RawFree(oldloc);
+ oldloc = NULL;
+
+ if (argc >= 1)
+ Py_SetProgramName(argv_copy[0]);
+
+ status = Py_InitializeFromConfig(&config);
+ PyConfig_Clear(&config);
+ if (PyStatus_Exception(status)) {
+ Py_ExitStatusException(status);
+ }
+
+ const char* entry_point = getenv(env_entry_point);
+ if (entry_point) {
+ entry_point_copy = strdup(entry_point);
+ if (!entry_point_copy) {
+ fprintf(stderr, "out of memory\n");
+ goto error;
+ }
+ } else {
+ entry_point_copy = GetPyMain();
+ }
+
+ if (entry_point_copy == NULL) {
+ fprintf(stderr, "No entry point, did you forget PY_MAIN?\n");
+ goto error;
+ }
+
+ if (entry_point_copy && !strcmp(entry_point_copy, ":main")) {
+ unsetenv(env_entry_point);
+ sts = Py_Main(argc, argv_copy);
+ free(entry_point_copy);
+ return sts;
+ }
+
+ Py_InitArgcArgv(argc, argv_copy);
+ PySys_SetArgv(argc, argv_copy);
+
+ {
+ PyObject* module = PyImport_ImportModule("library.python.runtime_py3.entry_points");
+ if (module == NULL) {
+ PyErr_Print();
+ } else {
+ PyObject* res = PyObject_CallMethod(module, "run_constructors", NULL);
+ if (res == NULL) {
+ PyErr_Print();
+ } else {
+ Py_DECREF(res);
+ }
+ Py_DECREF(module);
+ }
+ }
+
+ const char* module_name = entry_point_copy;
+ const char* func_name = NULL;
+
+ char *colon = strchr(entry_point_copy, ':');
+ if (colon != NULL) {
+ colon[0] = '\0';
+ func_name = colon + 1;
+ }
+ if (module_name[0] == '\0') {
+ module_name = "library.python.runtime_py3.entry_points";
+ }
+
+ if (!func_name) {
+ sts = RunModule(module_name);
+ } else {
+ PyObject* module = PyImport_ImportModule(module_name);
+
+ if (module == NULL) {
+ PyErr_Print();
+ } else {
+ PyObject* value = PyObject_CallMethod(module, func_name, NULL);
+
+ if (value == NULL) {
+ PyErr_Print();
+ } else {
+ Py_DECREF(value);
+ sts = 0;
+ }
+
+ Py_DECREF(module);
+ }
+ }
+
+ if (Py_FinalizeEx() < 0) {
+ sts = 120;
+ }
+
+error:
+ free(entry_point_copy);
+ PyMem_RawFree(argv_copy);
+ if (argv_copy2) {
+ for (i = 0; i < argc; i++)
+ PyMem_RawFree(argv_copy2[i]);
+ PyMem_RawFree(argv_copy2);
+ }
+ PyMem_RawFree(oldloc);
+ return sts;
+}
+
+int (*mainptr)(int argc, char** argv) = pymain;
+
+int main(int argc, char** argv) {
+ return mainptr(argc, argv);
+}
diff --git a/library/python/runtime_py3/main/ya.make b/library/python/runtime_py3/main/ya.make
new file mode 100644
index 0000000000..f308a93b28
--- /dev/null
+++ b/library/python/runtime_py3/main/ya.make
@@ -0,0 +1,26 @@
+LIBRARY()
+
+OWNER(
+ pg
+ orivej
+)
+
+PEERDIR(
+ contrib/tools/python3/src
+ library/cpp/resource
+)
+
+ADDINCL(
+ contrib/tools/python3/src/Include
+)
+
+CFLAGS(
+ -DPy_BUILD_CORE
+)
+
+SRCS(
+ main.c
+ get_py_main.cpp
+)
+
+END()
diff --git a/library/python/runtime_py3/sitecustomize.pyx b/library/python/runtime_py3/sitecustomize.pyx
new file mode 100644
index 0000000000..966bbe8ba6
--- /dev/null
+++ b/library/python/runtime_py3/sitecustomize.pyx
@@ -0,0 +1,69 @@
+import re
+import sys
+
+import __res
+
+from importlib.abc import ResourceReader
+from importlib.metadata import Distribution, DistributionFinder, PackageNotFoundError, Prepared
+
+ResourceReader.register(__res._ResfsResourceReader)
+
+METADATA_NAME = re.compile('^Name: (.*)$', re.MULTILINE)
+
+
+class ArcadiaDistribution(Distribution):
+
+ def __init__(self, prefix):
+ self.prefix = prefix
+
+ def read_text(self, filename):
+ data = __res.resfs_read(f'{self.prefix}{filename}')
+ if data:
+ return data.decode('utf-8')
+ read_text.__doc__ = Distribution.read_text.__doc__
+
+ def locate_file(self, path):
+ return f'{self.prefix}{path}'
+
+
+class ArcadiaMetadataFinder(DistributionFinder):
+
+ prefixes = {}
+
+ @classmethod
+ def find_distributions(cls, context=DistributionFinder.Context()):
+ found = cls._search_prefixes(context.name)
+ return map(ArcadiaDistribution, found)
+
+ @classmethod
+ def _init_prefixes(cls):
+ cls.prefixes.clear()
+
+ for resource in __res.resfs_files():
+ resource = resource.decode('utf-8')
+ if not resource.endswith('METADATA'):
+ continue
+ data = __res.resfs_read(resource).decode('utf-8')
+ metadata_name = METADATA_NAME.search(data)
+ if metadata_name:
+ metadata_name = Prepared(metadata_name.group(1))
+ cls.prefixes[metadata_name.normalized] = resource[:-len('METADATA')]
+
+ @classmethod
+ def _search_prefixes(cls, name):
+ if not cls.prefixes:
+ cls._init_prefixes()
+
+ if name:
+ try:
+ yield cls.prefixes[Prepared(name).normalized]
+ except KeyError:
+ raise PackageNotFoundError(name)
+ else:
+ for prefix in sorted(cls.prefixes.values()):
+ yield prefix
+
+
+# monkeypatch standart library
+import importlib.metadata
+importlib.metadata.MetadataPathFinder = ArcadiaMetadataFinder
diff --git a/library/python/runtime_py3/test/.dist-info/METADATA b/library/python/runtime_py3/test/.dist-info/METADATA
new file mode 100644
index 0000000000..bb36162199
--- /dev/null
+++ b/library/python/runtime_py3/test/.dist-info/METADATA
@@ -0,0 +1,14 @@
+Metadata-Version: 2.1
+Name: foo-bar
+Version: 1.2.3
+Summary:
+Home-page: https://foo.org/
+Author: Foo
+Author-email: foo@ya.com
+License: UNKNOWN
+Platform: any
+Classifier: Development Status :: 4 - Beta
+Classifier: Programming Language :: Python :: 3
+Requires-Python: >=3.8
+Requires-Dist: Werkzeug (>=0.15)
+Requires-Dist: Jinja2 (>=2.10.1)
diff --git a/library/python/runtime_py3/test/.dist-info/RECORD b/library/python/runtime_py3/test/.dist-info/RECORD
new file mode 100644
index 0000000000..dabbbff80d
--- /dev/null
+++ b/library/python/runtime_py3/test/.dist-info/RECORD
@@ -0,0 +1 @@
+foo_bar.py,sha256=0000000000000000000000000000000000000000000,20
diff --git a/library/python/runtime_py3/test/.dist-info/entry_points.txt b/library/python/runtime_py3/test/.dist-info/entry_points.txt
new file mode 100644
index 0000000000..f5e2fd2657
--- /dev/null
+++ b/library/python/runtime_py3/test/.dist-info/entry_points.txt
@@ -0,0 +1,2 @@
+[console_scripts]
+foo_cli = foo_bar:cli
diff --git a/library/python/runtime_py3/test/.dist-info/top_level.txt b/library/python/runtime_py3/test/.dist-info/top_level.txt
new file mode 100644
index 0000000000..d2c068bc6b
--- /dev/null
+++ b/library/python/runtime_py3/test/.dist-info/top_level.txt
@@ -0,0 +1 @@
+foo_bar
diff --git a/library/python/runtime_py3/test/canondata/result.json b/library/python/runtime_py3/test/canondata/result.json
new file mode 100644
index 0000000000..a7d045fc9c
--- /dev/null
+++ b/library/python/runtime_py3/test/canondata/result.json
@@ -0,0 +1,62 @@
+{
+ "test_traceback.test_traceback[custom-default]": {
+ "stderr": {
+ "checksum": "6c1a9b47baa51cc6903b85fd43c529b5",
+ "uri": "file://test_traceback.test_traceback_custom-default_/stderr.txt"
+ },
+ "stdout": {
+ "checksum": "e120a1e0b7fdddc8e6b4d4b506403e89",
+ "uri": "file://test_traceback.test_traceback_custom-default_/stdout.txt"
+ }
+ },
+ "test_traceback.test_traceback[custom-ultratb_color]": {
+ "stderr": {
+ "checksum": "048e27049fb8db64bd295b17f505b0ad",
+ "uri": "file://test_traceback.test_traceback_custom-ultratb_color_/stderr.txt"
+ },
+ "stdout": {
+ "checksum": "e120a1e0b7fdddc8e6b4d4b506403e89",
+ "uri": "file://test_traceback.test_traceback_custom-ultratb_color_/stdout.txt"
+ }
+ },
+ "test_traceback.test_traceback[custom-ultratb_verbose]": {
+ "stderr": {
+ "checksum": "e9af42aa3736141d9b67a1652eea412e",
+ "uri": "file://test_traceback.test_traceback_custom-ultratb_verbose_/stderr.txt"
+ },
+ "stdout": {
+ "checksum": "e120a1e0b7fdddc8e6b4d4b506403e89",
+ "uri": "file://test_traceback.test_traceback_custom-ultratb_verbose_/stdout.txt"
+ }
+ },
+ "test_traceback.test_traceback[main-default]": {
+ "stderr": {
+ "checksum": "6c1a9b47baa51cc6903b85fd43c529b5",
+ "uri": "file://test_traceback.test_traceback_main-default_/stderr.txt"
+ },
+ "stdout": {
+ "checksum": "e120a1e0b7fdddc8e6b4d4b506403e89",
+ "uri": "file://test_traceback.test_traceback_main-default_/stdout.txt"
+ }
+ },
+ "test_traceback.test_traceback[main-ultratb_color]": {
+ "stderr": {
+ "checksum": "048e27049fb8db64bd295b17f505b0ad",
+ "uri": "file://test_traceback.test_traceback_main-ultratb_color_/stderr.txt"
+ },
+ "stdout": {
+ "checksum": "e120a1e0b7fdddc8e6b4d4b506403e89",
+ "uri": "file://test_traceback.test_traceback_main-ultratb_color_/stdout.txt"
+ }
+ },
+ "test_traceback.test_traceback[main-ultratb_verbose]": {
+ "stderr": {
+ "checksum": "e9af42aa3736141d9b67a1652eea412e",
+ "uri": "file://test_traceback.test_traceback_main-ultratb_verbose_/stderr.txt"
+ },
+ "stdout": {
+ "checksum": "e120a1e0b7fdddc8e6b4d4b506403e89",
+ "uri": "file://test_traceback.test_traceback_main-ultratb_verbose_/stdout.txt"
+ }
+ }
+} \ No newline at end of file
diff --git a/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-default_/stderr.txt b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-default_/stderr.txt
new file mode 100644
index 0000000000..5eb7da170a
--- /dev/null
+++ b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-default_/stderr.txt
@@ -0,0 +1,12 @@
+Traceback (most recent call last):
+ File "library/python/runtime_py3/test/traceback/crash.py", line 44, in main
+ one()
+ File "library/python/runtime_py3/test/traceback/crash.py", line 12, in one
+ modfunc(two) # aaa
+ File "library/python/runtime_py3/test/traceback/mod/__init__.py", line 3, in modfunc
+ f() # call back to caller
+ File "library/python/runtime_py3/test/traceback/crash.py", line 16, in two
+ three(42)
+ File "library/python/runtime_py3/test/traceback/crash.py", line 20, in three
+ raise RuntimeError('Kaboom! I\'m dead: {}'.format(x))
+RuntimeError: Kaboom! I'm dead: 42
diff --git a/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-default_/stdout.txt b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-default_/stdout.txt
new file mode 100644
index 0000000000..2c9793eb14
--- /dev/null
+++ b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-default_/stdout.txt
@@ -0,0 +1,2 @@
+__name__ = library.python.runtime_py3.test.traceback.crash
+__file__ = library/python/runtime_py3/test/traceback/crash.py
diff --git a/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-ultratb_color_/stderr.txt b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-ultratb_color_/stderr.txt
new file mode 100644
index 0000000000..9e5a474cbd
--- /dev/null
+++ b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-ultratb_color_/stderr.txt
@@ -0,0 +1,13 @@
+Traceback (most recent call last):
+ File "library/python/runtime_py3/test/traceback/crash.py", line 44, in main
+ one()
+ File "library/python/runtime_py3/test/traceback/crash.py", line 12, in one
+ modfunc(two) # aaa
+ File "library/python/runtime_py3/test/traceback/mod/__init__.py", line 3, in modfunc
+ f() # call back to caller
+ File "library/python/runtime_py3/test/traceback/crash.py", line 16, in two
+ three(42)
+ File "library/python/runtime_py3/test/traceback/crash.py", line 20, in three
+ raise RuntimeError('Kaboom! I\'m dead: {}'.format(x))
+RuntimeError: Kaboom! I'm dead: 42
+
diff --git a/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-ultratb_color_/stdout.txt b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-ultratb_color_/stdout.txt
new file mode 100644
index 0000000000..2c9793eb14
--- /dev/null
+++ b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-ultratb_color_/stdout.txt
@@ -0,0 +1,2 @@
+__name__ = library.python.runtime_py3.test.traceback.crash
+__file__ = library/python/runtime_py3/test/traceback/crash.py
diff --git a/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-ultratb_verbose_/stderr.txt b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-ultratb_verbose_/stderr.txt
new file mode 100644
index 0000000000..b0b299ebe6
--- /dev/null
+++ b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-ultratb_verbose_/stderr.txt
@@ -0,0 +1,41 @@
+---------------------------------------------------------------------------
+RuntimeError Traceback (most recent call last)
+library/python/runtime_py3/test/traceback/crash.py in main()
+ 42 sys.executable = '<traceback test>'
+ 43
+---> 44 one()
+ global one = <function one>
+
+library/python/runtime_py3/test/traceback/crash.py in one()
+ 10
+ 11 def one():
+---> 12 modfunc(two) # aaa
+ global modfunc = <function modfunc>
+ global two = <function two>
+ 13
+ 14
+
+library/python/runtime_py3/test/traceback/mod/__init__.py in modfunc(f=<function two>)
+ 1 def modfunc(f):
+ 2 # lalala
+----> 3 f() # call back to caller
+ f = <function two>
+
+library/python/runtime_py3/test/traceback/crash.py in two()
+ 14
+ 15 def two():
+---> 16 three(42)
+ global three = <function three>
+ 17
+ 18
+
+library/python/runtime_py3/test/traceback/crash.py in three(x=42)
+ 18
+ 19 def three(x):
+---> 20 raise RuntimeError('Kaboom! I\'m dead: {}'.format(x))
+ global RuntimeError.format = undefined
+ x = 42
+ 21
+ 22
+
+RuntimeError: Kaboom! I'm dead: 42
diff --git a/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-ultratb_verbose_/stdout.txt b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-ultratb_verbose_/stdout.txt
new file mode 100644
index 0000000000..2c9793eb14
--- /dev/null
+++ b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_custom-ultratb_verbose_/stdout.txt
@@ -0,0 +1,2 @@
+__name__ = library.python.runtime_py3.test.traceback.crash
+__file__ = library/python/runtime_py3/test/traceback/crash.py
diff --git a/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-default_/stderr.txt b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-default_/stderr.txt
new file mode 100644
index 0000000000..5eb7da170a
--- /dev/null
+++ b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-default_/stderr.txt
@@ -0,0 +1,12 @@
+Traceback (most recent call last):
+ File "library/python/runtime_py3/test/traceback/crash.py", line 44, in main
+ one()
+ File "library/python/runtime_py3/test/traceback/crash.py", line 12, in one
+ modfunc(two) # aaa
+ File "library/python/runtime_py3/test/traceback/mod/__init__.py", line 3, in modfunc
+ f() # call back to caller
+ File "library/python/runtime_py3/test/traceback/crash.py", line 16, in two
+ three(42)
+ File "library/python/runtime_py3/test/traceback/crash.py", line 20, in three
+ raise RuntimeError('Kaboom! I\'m dead: {}'.format(x))
+RuntimeError: Kaboom! I'm dead: 42
diff --git a/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-default_/stdout.txt b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-default_/stdout.txt
new file mode 100644
index 0000000000..2c9793eb14
--- /dev/null
+++ b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-default_/stdout.txt
@@ -0,0 +1,2 @@
+__name__ = library.python.runtime_py3.test.traceback.crash
+__file__ = library/python/runtime_py3/test/traceback/crash.py
diff --git a/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-ultratb_color_/stderr.txt b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-ultratb_color_/stderr.txt
new file mode 100644
index 0000000000..9e5a474cbd
--- /dev/null
+++ b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-ultratb_color_/stderr.txt
@@ -0,0 +1,13 @@
+Traceback (most recent call last):
+ File "library/python/runtime_py3/test/traceback/crash.py", line 44, in main
+ one()
+ File "library/python/runtime_py3/test/traceback/crash.py", line 12, in one
+ modfunc(two) # aaa
+ File "library/python/runtime_py3/test/traceback/mod/__init__.py", line 3, in modfunc
+ f() # call back to caller
+ File "library/python/runtime_py3/test/traceback/crash.py", line 16, in two
+ three(42)
+ File "library/python/runtime_py3/test/traceback/crash.py", line 20, in three
+ raise RuntimeError('Kaboom! I\'m dead: {}'.format(x))
+RuntimeError: Kaboom! I'm dead: 42
+
diff --git a/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-ultratb_color_/stdout.txt b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-ultratb_color_/stdout.txt
new file mode 100644
index 0000000000..2c9793eb14
--- /dev/null
+++ b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-ultratb_color_/stdout.txt
@@ -0,0 +1,2 @@
+__name__ = library.python.runtime_py3.test.traceback.crash
+__file__ = library/python/runtime_py3/test/traceback/crash.py
diff --git a/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-ultratb_verbose_/stderr.txt b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-ultratb_verbose_/stderr.txt
new file mode 100644
index 0000000000..b0b299ebe6
--- /dev/null
+++ b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-ultratb_verbose_/stderr.txt
@@ -0,0 +1,41 @@
+---------------------------------------------------------------------------
+RuntimeError Traceback (most recent call last)
+library/python/runtime_py3/test/traceback/crash.py in main()
+ 42 sys.executable = '<traceback test>'
+ 43
+---> 44 one()
+ global one = <function one>
+
+library/python/runtime_py3/test/traceback/crash.py in one()
+ 10
+ 11 def one():
+---> 12 modfunc(two) # aaa
+ global modfunc = <function modfunc>
+ global two = <function two>
+ 13
+ 14
+
+library/python/runtime_py3/test/traceback/mod/__init__.py in modfunc(f=<function two>)
+ 1 def modfunc(f):
+ 2 # lalala
+----> 3 f() # call back to caller
+ f = <function two>
+
+library/python/runtime_py3/test/traceback/crash.py in two()
+ 14
+ 15 def two():
+---> 16 three(42)
+ global three = <function three>
+ 17
+ 18
+
+library/python/runtime_py3/test/traceback/crash.py in three(x=42)
+ 18
+ 19 def three(x):
+---> 20 raise RuntimeError('Kaboom! I\'m dead: {}'.format(x))
+ global RuntimeError.format = undefined
+ x = 42
+ 21
+ 22
+
+RuntimeError: Kaboom! I'm dead: 42
diff --git a/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-ultratb_verbose_/stdout.txt b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-ultratb_verbose_/stdout.txt
new file mode 100644
index 0000000000..2c9793eb14
--- /dev/null
+++ b/library/python/runtime_py3/test/canondata/test_traceback.test_traceback_main-ultratb_verbose_/stdout.txt
@@ -0,0 +1,2 @@
+__name__ = library.python.runtime_py3.test.traceback.crash
+__file__ = library/python/runtime_py3/test/traceback/crash.py
diff --git a/library/python/runtime_py3/test/resources/__init__.py b/library/python/runtime_py3/test/resources/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/library/python/runtime_py3/test/resources/__init__.py
diff --git a/library/python/runtime_py3/test/resources/foo.txt b/library/python/runtime_py3/test/resources/foo.txt
new file mode 100644
index 0000000000..ba0e162e1c
--- /dev/null
+++ b/library/python/runtime_py3/test/resources/foo.txt
@@ -0,0 +1 @@
+bar \ No newline at end of file
diff --git a/library/python/runtime_py3/test/resources/submodule/__init__.py b/library/python/runtime_py3/test/resources/submodule/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/library/python/runtime_py3/test/resources/submodule/__init__.py
diff --git a/library/python/runtime_py3/test/resources/submodule/bar.txt b/library/python/runtime_py3/test/resources/submodule/bar.txt
new file mode 100644
index 0000000000..1910281566
--- /dev/null
+++ b/library/python/runtime_py3/test/resources/submodule/bar.txt
@@ -0,0 +1 @@
+foo \ No newline at end of file
diff --git a/library/python/runtime_py3/test/test_arcadia_source_finder.py b/library/python/runtime_py3/test/test_arcadia_source_finder.py
new file mode 100644
index 0000000000..ff80d0a0a2
--- /dev/null
+++ b/library/python/runtime_py3/test/test_arcadia_source_finder.py
@@ -0,0 +1,317 @@
+import unittest
+import yaml
+from unittest.mock import patch
+from parameterized import parameterized
+
+import __res as res
+
+
+NAMESPACE_PREFIX = b'py/namespace/'
+TEST_SOURCE_ROOT = '/home/arcadia'
+
+
+class ImporterMocks(object):
+ def __init__(self, mock_fs, mock_resources):
+ self._mock_fs = mock_fs
+ self._mock_resources = mock_resources
+ self._patchers = [
+ patch('__res.iter_keys', wraps=self._iter_keys),
+ patch('__res.__resource.find', wraps=self._resource_find),
+ patch('__res._path_isdir', wraps=self._path_isdir),
+ patch('__res._path_isfile', wraps=self._path_isfile),
+ patch('__res._os.listdir', wraps=self._os_listdir),
+ ]
+ for patcher in self._patchers:
+ patcher.start()
+
+ def stop(self):
+ for patcher in self._patchers:
+ patcher.stop()
+
+ def _iter_keys(self, prefix):
+ assert prefix == NAMESPACE_PREFIX
+ l = len(prefix)
+ for k in self._mock_resources.keys():
+ yield k, k[l:]
+
+ def _resource_find(self, key):
+ return self._mock_resources.get(key)
+
+ def _lookup_mock_fs(self, filename):
+ path = filename.lstrip('/').split('/')
+ curdir = self._mock_fs
+ for item in path:
+ if item in curdir:
+ curdir = curdir[item]
+ else:
+ return None
+ return curdir
+
+ def _path_isfile(self, filename):
+ f = self._lookup_mock_fs(filename)
+ return isinstance(f, str)
+
+ def _path_isdir(self, filename):
+ f = self._lookup_mock_fs(filename)
+ return isinstance(f, dict)
+
+ def _os_listdir(self, dirname):
+ f = self._lookup_mock_fs(dirname)
+ if isinstance(f, dict):
+ return f.keys()
+ else:
+ return []
+
+
+class ArcadiaSourceFinderTestCase(unittest.TestCase):
+ def setUp(self):
+ self.import_mock = ImporterMocks(yaml.safe_load(self._get_mock_fs()), self._get_mock_resources())
+ self.arcadia_source_finder = res.ArcadiaSourceFinder(TEST_SOURCE_ROOT)
+
+ def tearDown(self):
+ self.import_mock.stop()
+
+ def _get_mock_fs(self):
+ raise NotImplementedError()
+
+ def _get_mock_resources(self):
+ raise NotImplementedError()
+
+
+class TestLibraryWithoutNamespace(ArcadiaSourceFinderTestCase):
+ def _get_mock_fs(self):
+ return '''
+ home:
+ arcadia:
+ project:
+ lib:
+ mod1.py: ""
+ package1:
+ mod2.py: ""
+ '''
+
+ def _get_mock_resources(self):
+ return {
+ b'py/namespace/unique_prefix1/project/lib': b'project.lib.',
+ }
+
+ @parameterized.expand([
+ ('project.lib.mod1', b'project/lib/mod1.py'),
+ ('project.lib.package1.mod2', b'project/lib/package1/mod2.py'),
+ ('project.lib.unknown_module', None),
+ ('project.lib', None), # package
+ ])
+ def test_get_module_path(self, module, path):
+ assert path == self.arcadia_source_finder.get_module_path(module)
+
+ @parameterized.expand([
+ ('project.lib.mod1', False),
+ ('project.lib.package1.mod2', False),
+ ('project', True),
+ ('project.lib', True),
+ ('project.lib.package1', True),
+ ])
+ def test_is_packages(self, module, is_package):
+ assert is_package == self.arcadia_source_finder.is_package(module)
+
+ def test_is_package_for_unknown_module(self):
+ self.assertRaises(ImportError, lambda: self.arcadia_source_finder.is_package('project.lib.package2'))
+
+ @parameterized.expand([
+ ('', {
+ ('PFX.project', True),
+ }),
+ ('project.', {
+ ('PFX.lib', True),
+ }),
+ ('project.lib.', {
+ ('PFX.mod1', False),
+ ('PFX.package1', True),
+ }),
+ ('project.lib.package1.', {
+ ('PFX.mod2', False),
+ }),
+ ])
+ def test_iter_modules(self, package_prefix, expected):
+ got = self.arcadia_source_finder.iter_modules(package_prefix, 'PFX.')
+ assert expected == set(got)
+
+ # Check iter_modules() don't crash and return correct result after not existing module was requested
+ def test_iter_modules_after_unknown_module_import(self):
+ self.arcadia_source_finder.get_module_path('project.unknown_module')
+ assert {('lib', True)} == set(self.arcadia_source_finder.iter_modules('project.', ''))
+
+
+class TestLibraryExtendedFromAnotherLibrary(ArcadiaSourceFinderTestCase):
+ def _get_mock_fs(self):
+ return '''
+ home:
+ arcadia:
+ project:
+ lib:
+ mod1.py: ''
+ lib_extension:
+ mod2.py: ''
+ '''
+
+ def _get_mock_resources(self):
+ return {
+ b'py/namespace/unique_prefix1/project/lib': b'project.lib.',
+ b'py/namespace/unique_prefix2/project/lib_extension': b'project.lib.',
+ }
+
+ @parameterized.expand([
+ ('project.lib.mod1', b'project/lib/mod1.py'),
+ ('project.lib.mod2', b'project/lib_extension/mod2.py'),
+ ])
+ def test_get_module_path(self, module, path):
+ assert path == self.arcadia_source_finder.get_module_path(module)
+
+ @parameterized.expand([
+ ('project.lib.', {
+ ('PFX.mod1', False),
+ ('PFX.mod2', False),
+ }),
+ ])
+ def test_iter_modules(self, package_prefix, expected):
+ got = self.arcadia_source_finder.iter_modules(package_prefix, 'PFX.')
+ assert expected == set(got)
+
+
+class TestNamespaceAndTopLevelLibraries(ArcadiaSourceFinderTestCase):
+ def _get_mock_fs(self):
+ return '''
+ home:
+ arcadia:
+ project:
+ ns_lib:
+ mod1.py: ''
+ top_level_lib:
+ mod2.py: ''
+ '''
+
+ def _get_mock_resources(self):
+ return {
+ b'py/namespace/unique_prefix1/project/ns_lib': b'ns.',
+ b'py/namespace/unique_prefix2/project/top_level_lib': b'.',
+ }
+
+ @parameterized.expand([
+ ('ns.mod1', b'project/ns_lib/mod1.py'),
+ ('mod2', b'project/top_level_lib/mod2.py'),
+ ])
+ def test_get_module_path(self, module, path):
+ assert path == self.arcadia_source_finder.get_module_path(module)
+
+ @parameterized.expand([
+ ('ns', True),
+ ('ns.mod1', False),
+ ('mod2', False),
+ ])
+ def test_is_packages(self, module, is_package):
+ assert is_package == self.arcadia_source_finder.is_package(module)
+
+ @parameterized.expand([
+ 'project',
+ 'project.ns_lib',
+ 'project.top_level_lib',
+ ])
+ def test_is_package_for_unknown_modules(self, module):
+ self.assertRaises(ImportError, lambda: self.arcadia_source_finder.is_package(module))
+
+ @parameterized.expand([
+ ('', {
+ ('PFX.ns', True),
+ ('PFX.mod2', False),
+ }),
+ ('ns.', {
+ ('PFX.mod1', False),
+ }),
+ ])
+ def test_iter_modules(self, package_prefix, expected):
+ got = self.arcadia_source_finder.iter_modules(package_prefix, 'PFX.')
+ assert expected == set(got)
+
+
+class TestIgnoreDirectoriesWithYaMakeFile(ArcadiaSourceFinderTestCase):
+ ''' Packages and modules from tests should not be part of pylib namespace '''
+ def _get_mock_fs(self):
+ return '''
+ home:
+ arcadia:
+ contrib:
+ python:
+ pylib:
+ mod1.py: ""
+ tests:
+ conftest.py: ""
+ ya.make: ""
+ '''
+
+ def _get_mock_resources(self):
+ return {
+ b'py/namespace/unique_prefix1/contrib/python/pylib': b'pylib.',
+ }
+
+ def test_get_module_path_for_lib(self):
+ assert b'contrib/python/pylib/mod1.py' == self.arcadia_source_finder.get_module_path('pylib.mod1')
+
+ def test_get_module_for_tests(self):
+ assert self.arcadia_source_finder.get_module_path('pylib.tests.conftest') is None
+
+ def test_is_package_for_tests(self):
+ self.assertRaises(ImportError, lambda: self.arcadia_source_finder.is_package('pylib.tests'))
+
+
+class TestMergingNamespaceAndDirectoryPackages(ArcadiaSourceFinderTestCase):
+ ''' Merge parent package (top level in this test) dirs with namespace dirs (DEVTOOLS-8979) '''
+ def _get_mock_fs(self):
+ return '''
+ home:
+ arcadia:
+ contrib:
+ python:
+ pylint:
+ ya.make: ""
+ pylint:
+ __init__.py: ""
+ patcher:
+ patch.py: ""
+ ya.make: ""
+ '''
+
+ def _get_mock_resources(self):
+ return {
+ b'py/namespace/unique_prefix1/contrib/python/pylint': b'.',
+ b'py/namespace/unique_prefix1/contrib/python/pylint/patcher': b'pylint.',
+ }
+
+ @parameterized.expand([
+ ('pylint.__init__', b'contrib/python/pylint/pylint/__init__.py'),
+ ('pylint.patch', b'contrib/python/pylint/patcher/patch.py'),
+ ])
+ def test_get_module_path(self, module, path):
+ assert path == self.arcadia_source_finder.get_module_path(module)
+
+
+class TestEmptyResources(ArcadiaSourceFinderTestCase):
+ def _get_mock_fs(self):
+ return '''
+ home:
+ arcadia:
+ project:
+ lib:
+ mod1.py: ''
+ '''
+
+ def _get_mock_resources(self):
+ return {}
+
+ def test_get_module_path(self):
+ assert self.arcadia_source_finder.get_module_path('project.lib.mod1') is None
+
+ def test_is_package(self):
+ self.assertRaises(ImportError, lambda: self.arcadia_source_finder.is_package('project'))
+
+ def test_iter_modules(self):
+ assert [] == list(self.arcadia_source_finder.iter_modules('', 'PFX.'))
diff --git a/library/python/runtime_py3/test/test_metadata.py b/library/python/runtime_py3/test/test_metadata.py
new file mode 100644
index 0000000000..686c176468
--- /dev/null
+++ b/library/python/runtime_py3/test/test_metadata.py
@@ -0,0 +1,44 @@
+import importlib.metadata as im
+
+import pytest
+
+
+@pytest.mark.parametrize("name", ("foo-bar", "foo_bar", "Foo-Bar"))
+def test_distribution(name):
+ assert im.distribution(name) is not None
+
+
+def test_unknown_package():
+ with pytest.raises(im.PackageNotFoundError):
+ im.distribution("bar")
+
+
+def test_version():
+ assert im.version("foo-bar") == "1.2.3"
+
+
+def test_metadata():
+ assert im.metadata("foo-bar") is not None
+
+
+def test_files():
+ files = im.files("foo-bar")
+ assert len(files) == 1
+ assert files[0].name == "foo_bar.py"
+ assert files[0].size == 20
+
+
+def test_requires():
+ assert im.requires("foo-bar") == ["Werkzeug (>=0.15)", "Jinja2 (>=2.10.1)"]
+
+
+def test_entry_points():
+ entry_points = im.entry_points()
+ assert "console_scripts" in entry_points
+
+ flg_found = False
+ for entry_point in entry_points["console_scripts"]:
+ if entry_point.name == "foo_cli" and entry_point.value == "foo_bar:cli":
+ flg_found = True
+
+ assert flg_found
diff --git a/library/python/runtime_py3/test/test_resources.py b/library/python/runtime_py3/test/test_resources.py
new file mode 100644
index 0000000000..a269329f42
--- /dev/null
+++ b/library/python/runtime_py3/test/test_resources.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+
+import importlib.resources as ir
+
+import pytest
+
+
+@pytest.mark.parametrize("package, resource", (
+ ("resources", "foo.txt"),
+ ("resources.submodule", "bar.txt")
+))
+def test_is_resource_good_path(package, resource):
+ assert ir.is_resource(package, resource)
+
+
+@pytest.mark.parametrize("package, resource", (
+ ("resources", "111.txt"),
+ ("resources.submodule", "222.txt")
+))
+def test_is_resource_missing(package, resource):
+ assert not ir.is_resource(package, resource)
+
+
+def test_is_resource_subresource_directory():
+ # Directories are not resources.
+ assert not ir.is_resource("resources", "submodule")
+
+
+@pytest.mark.parametrize("package, resource, expected", (
+ ("resources", "foo.txt", b"bar"),
+ ("resources.submodule", "bar.txt", b"foo")
+))
+def test_read_binary_good_path(package, resource, expected):
+ assert ir.read_binary(package, resource) == expected
+
+
+def test_read_binary_missing():
+ with pytest.raises(FileNotFoundError):
+ ir.read_binary("resources", "111.txt")
+
+
+@pytest.mark.parametrize("package, resource, expected", (
+ ("resources", "foo.txt", "bar"),
+ ("resources.submodule", "bar.txt", "foo")
+))
+def test_read_text_good_path(package, resource, expected):
+ assert ir.read_text(package, resource) == expected
+
+
+def test_read_text_missing():
+ with pytest.raises(FileNotFoundError):
+ ir.read_text("resources", "111.txt")
+
+
+@pytest.mark.parametrize("package, expected", (
+ ("resources", ["submodule", "foo.txt"]),
+ ("resources.submodule", ["bar.txt"])
+))
+def test_contents_good_path(package, expected):
+ assert sorted(ir.contents(package)) == sorted(expected)
diff --git a/library/python/runtime_py3/test/test_traceback.py b/library/python/runtime_py3/test/test_traceback.py
new file mode 100644
index 0000000000..82087ce98a
--- /dev/null
+++ b/library/python/runtime_py3/test/test_traceback.py
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+
+from __future__ import print_function, absolute_import, division
+
+import os
+import re
+
+import pytest
+
+import yatest.common as yc
+
+
+def clean_traceback(traceback):
+ traceback = re.sub(br'\033\[(\d|;)+?m', b'', traceback) # strip ANSI codes
+ traceback = re.sub(br' at 0x[0-9a-fA-F]+', b'', traceback) # remove object ids
+ return traceback
+
+
+@pytest.mark.parametrize('mode', [
+ 'default',
+ 'ultratb_color',
+ 'ultratb_verbose',
+])
+@pytest.mark.parametrize('entry_point', [
+ 'main',
+ 'custom',
+])
+def test_traceback(mode, entry_point):
+ tb_tool = yc.build_path('library/python/runtime_py3/test/traceback/traceback')
+ stdout_path = yc.test_output_path('stdout_raw.txt')
+ stderr_path = yc.test_output_path('stderr_raw.txt')
+ filtered_stdout_path = yc.test_output_path('stdout.txt')
+ filtered_stderr_path = yc.test_output_path('stderr.txt')
+
+ env = os.environ.copy()
+ env.pop('PYTHONPATH', None) # Do not let program peek into its sources on filesystem
+ if entry_point == 'custom':
+ env['Y_PYTHON_ENTRY_POINT'] = 'library.python.runtime_py3.test.traceback.crash:main'
+
+ proc = yc.execute(
+ command=[tb_tool, mode],
+ env=env,
+ stdout=stdout_path,
+ stderr=stderr_path,
+ check_exit_code=False,
+ )
+
+ with open(filtered_stdout_path, 'wb') as f:
+ f.write(clean_traceback(proc.std_out))
+
+ with open(filtered_stderr_path, 'wb') as f:
+ f.write(clean_traceback(proc.std_err))
+
+ return {
+ 'stdout': yc.canonical_file(
+ filtered_stdout_path,
+ local=True,
+ ),
+ 'stderr': yc.canonical_file(
+ filtered_stderr_path,
+ local=True,
+ ),
+ }
diff --git a/library/python/runtime_py3/test/traceback/__main__.py b/library/python/runtime_py3/test/traceback/__main__.py
new file mode 100644
index 0000000000..364db169f0
--- /dev/null
+++ b/library/python/runtime_py3/test/traceback/__main__.py
@@ -0,0 +1,4 @@
+from library.python.runtime_py3.test.traceback.crash import main
+
+if __name__ == "__main__":
+ main()
diff --git a/library/python/runtime_py3/test/traceback/crash.py b/library/python/runtime_py3/test/traceback/crash.py
new file mode 100644
index 0000000000..b5e36b3dd4
--- /dev/null
+++ b/library/python/runtime_py3/test/traceback/crash.py
@@ -0,0 +1,44 @@
+import argparse
+import cgitb
+import sys
+import time
+
+from IPython.core import ultratb
+
+from .mod import modfunc
+
+
+def one():
+ modfunc(two) # aaa
+
+
+def two():
+ three(42)
+
+
+def three(x):
+ raise RuntimeError('Kaboom! I\'m dead: {}'.format(x))
+
+
+def main():
+ hooks = {
+ 'default': lambda: sys.excepthook,
+ 'cgitb': lambda: cgitb.Hook(format='text'),
+ 'ultratb_color': lambda: ultratb.ColorTB(ostream=sys.stderr),
+ 'ultratb_verbose': lambda: ultratb.VerboseTB(ostream=sys.stderr),
+ }
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('hook', choices=sorted(hooks), default='default')
+
+ args = parser.parse_args()
+
+ sys.excepthook = hooks[args.hook]()
+
+ print('__name__ =', __name__)
+ print('__file__ =', __file__)
+
+ time.time = lambda: 1531996624.0 # Freeze time
+ sys.executable = '<traceback test>'
+
+ one()
diff --git a/library/python/runtime_py3/test/traceback/mod/__init__.py b/library/python/runtime_py3/test/traceback/mod/__init__.py
new file mode 100644
index 0000000000..f00843d786
--- /dev/null
+++ b/library/python/runtime_py3/test/traceback/mod/__init__.py
@@ -0,0 +1,3 @@
+def modfunc(f):
+ # lalala
+ f() # call back to caller
diff --git a/library/python/runtime_py3/test/traceback/ya.make b/library/python/runtime_py3/test/traceback/ya.make
new file mode 100644
index 0000000000..b61fe9550b
--- /dev/null
+++ b/library/python/runtime_py3/test/traceback/ya.make
@@ -0,0 +1,19 @@
+PY3_PROGRAM()
+
+OWNER(
+ abodrov
+ borman
+)
+
+PEERDIR(
+ contrib/python/ipython
+)
+
+PY_SRCS(
+ MAIN
+ __main__.py=main
+ crash.py
+ mod/__init__.py
+)
+
+END()
diff --git a/library/python/runtime_py3/test/ya.make b/library/python/runtime_py3/test/ya.make
new file mode 100644
index 0000000000..4ec3db74f5
--- /dev/null
+++ b/library/python/runtime_py3/test/ya.make
@@ -0,0 +1,40 @@
+PY3TEST()
+
+OWNER(
+ abodrov
+ borman
+)
+
+DEPENDS(library/python/runtime_py3/test/traceback)
+
+PEERDIR(
+ contrib/python/parameterized
+ contrib/python/PyYAML
+)
+
+PY_SRCS(
+ TOP_LEVEL
+ resources/__init__.py
+ resources/submodule/__init__.py
+)
+
+TEST_SRCS(
+ test_metadata.py
+ test_resources.py
+ test_traceback.py
+ test_arcadia_source_finder.py
+)
+
+RESOURCE_FILES(
+ PREFIX library/python/runtime_py3/test/
+ .dist-info/METADATA
+ .dist-info/RECORD
+ .dist-info/entry_points.txt
+ .dist-info/top_level.txt
+ resources/foo.txt
+ resources/submodule/bar.txt
+)
+
+END()
+
+RECURSE_FOR_TESTS(traceback)
diff --git a/library/python/runtime_py3/ya.make b/library/python/runtime_py3/ya.make
new file mode 100644
index 0000000000..fa5c11341a
--- /dev/null
+++ b/library/python/runtime_py3/ya.make
@@ -0,0 +1,49 @@
+PY3_LIBRARY()
+
+OWNER(
+ borman
+ orivej
+ pg
+)
+
+NO_WSHADOW()
+
+PEERDIR(
+ contrib/tools/python3/src
+ contrib/tools/python3/lib/py
+ library/cpp/resource
+)
+
+CFLAGS(-DCYTHON_REGISTER_ABCS=0)
+
+NO_PYTHON_INCLUDES()
+
+ENABLE(PYBUILD_NO_PYC)
+
+PY_SRCS(
+ entry_points.py
+ TOP_LEVEL
+
+ CYTHON_DIRECTIVE
+ language_level=3
+
+ __res.pyx
+ sitecustomize.pyx
+)
+
+IF (CYTHON_COVERAGE)
+ # Let covarage support add all needed files to resources
+ELSE()
+ RESOURCE_FILES(
+ PREFIX ${MODDIR}/
+ __res.pyx
+ importer.pxi
+ sitecustomize.pyx
+ )
+ENDIF()
+
+END()
+
+RECURSE_FOR_TESTS(
+ test
+)
diff --git a/library/python/strings/__init__.py b/library/python/strings/__init__.py
new file mode 100644
index 0000000000..bd6bf6e7ce
--- /dev/null
+++ b/library/python/strings/__init__.py
@@ -0,0 +1,17 @@
+# flake8 noqa: F401
+
+from .strings import (
+ DEFAULT_ENCODING,
+ ENCODING_ERRORS_POLICY,
+ encode,
+ fs_encoding,
+ get_stream_encoding,
+ guess_default_encoding,
+ left_strip,
+ locale_encoding,
+ stringize_deep,
+ to_basestring,
+ to_str,
+ to_unicode,
+ unicodize_deep,
+)
diff --git a/library/python/strings/strings.py b/library/python/strings/strings.py
new file mode 100644
index 0000000000..5bfddfe78a
--- /dev/null
+++ b/library/python/strings/strings.py
@@ -0,0 +1,129 @@
+import locale
+import logging
+import six
+import sys
+import codecs
+
+import library.python.func
+
+logger = logging.getLogger(__name__)
+
+
+DEFAULT_ENCODING = 'utf-8'
+ENCODING_ERRORS_POLICY = 'replace'
+
+
+def left_strip(el, prefix):
+ """
+ Strips prefix at the left of el
+ """
+ if el.startswith(prefix):
+ return el[len(prefix):]
+ return el
+
+
+# Explicit to-text conversion
+# Chooses between str/unicode, i.e. six.binary_type/six.text_type
+def to_basestring(value):
+ if isinstance(value, (six.binary_type, six.text_type)):
+ return value
+ try:
+ if six.PY2:
+ return unicode(value)
+ else:
+ return str(value)
+ except UnicodeDecodeError:
+ try:
+ return str(value)
+ except UnicodeEncodeError:
+ return repr(value)
+to_text = to_basestring
+
+
+def to_unicode(value, from_enc=DEFAULT_ENCODING):
+ if isinstance(value, six.text_type):
+ return value
+ if isinstance(value, six.binary_type):
+ if six.PY2:
+ return unicode(value, from_enc, ENCODING_ERRORS_POLICY)
+ else:
+ return value.decode(from_enc, errors=ENCODING_ERRORS_POLICY)
+ return six.text_type(value)
+
+
+# Optional from_enc enables transcoding
+def to_str(value, to_enc=DEFAULT_ENCODING, from_enc=None):
+ if isinstance(value, six.binary_type):
+ if from_enc is None or to_enc == from_enc:
+ # Unknown input encoding or input and output encoding are the same
+ return value
+ value = to_unicode(value, from_enc=from_enc)
+ if isinstance(value, six.text_type):
+ return value.encode(to_enc, ENCODING_ERRORS_POLICY)
+ return six.binary_type(value)
+
+
+def _convert_deep(x, enc, convert, relaxed=True):
+ if x is None:
+ return None
+ if isinstance(x, (six.text_type, six.binary_type)):
+ return convert(x, enc)
+ if isinstance(x, dict):
+ return {convert(k, enc): _convert_deep(v, enc, convert, relaxed) for k, v in six.iteritems(x)}
+ if isinstance(x, list):
+ return [_convert_deep(e, enc, convert, relaxed) for e in x]
+ if isinstance(x, tuple):
+ return tuple([_convert_deep(e, enc, convert, relaxed) for e in x])
+
+ if relaxed:
+ return x
+ raise TypeError('unsupported type')
+
+
+def unicodize_deep(x, enc=DEFAULT_ENCODING, relaxed=True):
+ return _convert_deep(x, enc, to_unicode, relaxed)
+
+
+def stringize_deep(x, enc=DEFAULT_ENCODING, relaxed=True):
+ return _convert_deep(x, enc, to_str, relaxed)
+
+
+@library.python.func.memoize()
+def locale_encoding():
+ try:
+ loc = locale.getdefaultlocale()[1]
+ if loc:
+ codecs.lookup(loc)
+ return loc
+ except LookupError as e:
+ logger.debug('Cannot get system locale: %s', e)
+ return None
+ except ValueError as e:
+ logger.warn('Cannot get system locale: %s', e)
+ return None
+
+
+def fs_encoding():
+ return sys.getfilesystemencoding()
+
+
+def guess_default_encoding():
+ enc = locale_encoding()
+ return enc if enc else DEFAULT_ENCODING
+
+
+@library.python.func.memoize()
+def get_stream_encoding(stream):
+ if stream.encoding:
+ try:
+ codecs.lookup(stream.encoding)
+ return stream.encoding
+ except LookupError:
+ pass
+ return DEFAULT_ENCODING
+
+
+def encode(value, encoding=DEFAULT_ENCODING):
+ if isinstance(value, six.binary_type):
+ value = value.decode(encoding, errors='ignore')
+ return value.encode(encoding)
diff --git a/library/python/strings/ut/test_strings.py b/library/python/strings/ut/test_strings.py
new file mode 100644
index 0000000000..dd0c694ee1
--- /dev/null
+++ b/library/python/strings/ut/test_strings.py
@@ -0,0 +1,205 @@
+# coding=utf-8
+
+import pytest
+import six
+
+import library.python.strings
+
+
+class Convertible(object):
+ text = u'текст'
+ text_utf8 = text.encode('utf-8')
+
+ def __unicode__(self):
+ return self.text
+
+ def __str__(self):
+ return self.text_utf8
+
+
+class ConvertibleToUnicodeOnly(Convertible):
+ def __str__(self):
+ return self.text.encode('ascii')
+
+
+class ConvertibleToStrOnly(Convertible):
+ def __unicode__(self):
+ return self.text_utf8.decode('ascii')
+
+
+class NonConvertible(ConvertibleToUnicodeOnly, ConvertibleToStrOnly):
+ pass
+
+
+def test_to_basestring():
+ assert library.python.strings.to_basestring('str') == 'str'
+ assert library.python.strings.to_basestring(u'юникод') == u'юникод'
+ if six.PY2: # __str__ should return str not bytes in Python3
+ assert library.python.strings.to_basestring(Convertible()) == Convertible.text
+ assert library.python.strings.to_basestring(ConvertibleToUnicodeOnly()) == Convertible.text
+ assert library.python.strings.to_basestring(ConvertibleToStrOnly()) == Convertible.text_utf8
+ assert library.python.strings.to_basestring(NonConvertible())
+
+
+def test_to_unicode():
+ assert library.python.strings.to_unicode(u'юникод') == u'юникод'
+ assert library.python.strings.to_unicode('str') == u'str'
+ assert library.python.strings.to_unicode(u'строка'.encode('utf-8')) == u'строка'
+ assert library.python.strings.to_unicode(u'строка'.encode('cp1251'), 'cp1251') == u'строка'
+ if six.PY2: # __str__ should return str not bytes in Python3
+ assert library.python.strings.to_unicode(Convertible()) == Convertible.text
+ assert library.python.strings.to_unicode(ConvertibleToUnicodeOnly()) == Convertible.text
+ with pytest.raises(UnicodeDecodeError):
+ library.python.strings.to_unicode(ConvertibleToStrOnly())
+ with pytest.raises(UnicodeDecodeError):
+ library.python.strings.to_unicode(NonConvertible())
+
+
+def test_to_unicode_errors_replace():
+ assert library.python.strings.to_unicode(u'abcабв'.encode('utf-8'), 'ascii')
+ assert library.python.strings.to_unicode(u'абв'.encode('utf-8'), 'ascii')
+
+
+def test_to_str():
+ assert library.python.strings.to_str('str') == 'str' if six.PY2 else b'str'
+ assert library.python.strings.to_str(u'unicode') == 'unicode' if six.PY2 else b'unicode'
+ assert library.python.strings.to_str(u'юникод') == u'юникод'.encode('utf-8')
+ assert library.python.strings.to_str(u'юникод', 'cp1251') == u'юникод'.encode('cp1251')
+ if six.PY2:
+ assert library.python.strings.to_str(Convertible()) == Convertible.text_utf8
+ with pytest.raises(UnicodeEncodeError):
+ library.python.strings.to_str(ConvertibleToUnicodeOnly())
+ assert library.python.strings.to_str(ConvertibleToStrOnly()) == Convertible.text_utf8
+ with pytest.raises(UnicodeEncodeError):
+ library.python.strings.to_str(NonConvertible())
+
+
+def test_to_str_errors_replace():
+ assert library.python.strings.to_str(u'abcабв', 'ascii')
+ assert library.python.strings.to_str(u'абв', 'ascii')
+
+
+def test_to_str_transcode():
+ assert library.python.strings.to_str('str', from_enc='ascii') == 'str' if six.PY2 else b'str'
+ assert library.python.strings.to_str('str', from_enc='utf-8') == 'str' if six.PY2 else b'str'
+
+ assert library.python.strings.to_str(u'юникод'.encode('utf-8'), from_enc='utf-8') == u'юникод'.encode('utf-8')
+ assert library.python.strings.to_str(u'юникод'.encode('utf-8'), to_enc='utf-8', from_enc='utf-8') == u'юникод'.encode('utf-8')
+ assert library.python.strings.to_str(u'юникод'.encode('utf-8'), to_enc='cp1251', from_enc='utf-8') == u'юникод'.encode('cp1251')
+
+ assert library.python.strings.to_str(u'юникод'.encode('cp1251'), from_enc='cp1251') == u'юникод'.encode('utf-8')
+ assert library.python.strings.to_str(u'юникод'.encode('cp1251'), to_enc='cp1251', from_enc='cp1251') == u'юникод'.encode('cp1251')
+ assert library.python.strings.to_str(u'юникод'.encode('cp1251'), to_enc='utf-8', from_enc='cp1251') == u'юникод'.encode('utf-8')
+
+ assert library.python.strings.to_str(u'юникод'.encode('koi8-r'), from_enc='koi8-r') == u'юникод'.encode('utf-8')
+ assert library.python.strings.to_str(u'юникод'.encode('koi8-r'), to_enc='koi8-r', from_enc='koi8-r') == u'юникод'.encode('koi8-r')
+ assert library.python.strings.to_str(u'юникод'.encode('koi8-r'), to_enc='cp1251', from_enc='koi8-r') == u'юникод'.encode('cp1251')
+
+
+def test_to_str_transcode_wrong():
+ assert library.python.strings.to_str(u'юникод'.encode('utf-8'), from_enc='cp1251')
+ assert library.python.strings.to_str(u'юникод'.encode('cp1251'), from_enc='utf-8')
+
+
+def test_to_str_transcode_disabled():
+ # No transcoding enabled, set from_enc to enable
+ assert library.python.strings.to_str(u'юникод'.encode('utf-8'), to_enc='utf-8') == u'юникод'.encode('utf-8')
+ assert library.python.strings.to_str(u'юникод'.encode('utf-8'), to_enc='cp1251') == u'юникод'.encode('utf-8')
+ assert library.python.strings.to_str(u'юникод'.encode('cp1251'), to_enc='utf-8') == u'юникод'.encode('cp1251')
+ assert library.python.strings.to_str(u'юникод'.encode('cp1251'), to_enc='cp1251') == u'юникод'.encode('cp1251')
+ assert library.python.strings.to_str(u'юникод'.encode('cp1251'), to_enc='koi8-r') == u'юникод'.encode('cp1251')
+ assert library.python.strings.to_str(u'юникод'.encode('koi8-r'), to_enc='cp1251') == u'юникод'.encode('koi8-r')
+
+
+def test_stringize_deep():
+ assert library.python.strings.stringize_deep({
+ 'key 1': 'value 1',
+ u'ключ 2': u'значение 2',
+ 'list': [u'ключ 2', 'key 1', (u'к', 2)]
+ }) == {
+ 'key 1' if six.PY2 else b'key 1': 'value 1' if six.PY2 else b'value 1',
+ u'ключ 2'.encode('utf-8'): u'значение 2'.encode('utf-8'),
+ 'list' if six.PY2 else b'list': [u'ключ 2'.encode('utf-8'), 'key 1' if six.PY2 else b'key 1', (u'к'.encode('utf-8'), 2)]
+ }
+
+
+def test_stringize_deep_doesnt_transcode():
+ assert library.python.strings.stringize_deep({
+ u'ключ 1'.encode('utf-8'): u'значение 1'.encode('utf-8'),
+ u'ключ 2'.encode('cp1251'): u'значение 2'.encode('cp1251'),
+ }) == {
+ u'ключ 1'.encode('utf-8'): u'значение 1'.encode('utf-8'),
+ u'ключ 2'.encode('cp1251'): u'значение 2'.encode('cp1251'),
+ }
+
+
+def test_stringize_deep_nested():
+ assert library.python.strings.stringize_deep({
+ 'key 1': 'value 1',
+ u'ключ 2': {
+ 'subkey 1': 'value 1',
+ u'подключ 2': u'value 2',
+ },
+ }) == {
+ 'key 1' if six.PY2 else b'key 1': 'value 1' if six.PY2 else b'value 1',
+ u'ключ 2'.encode('utf-8'): {
+ 'subkey 1' if six.PY2 else b'subkey 1': 'value 1' if six.PY2 else b'value 1',
+ u'подключ 2'.encode('utf-8'): u'value 2'.encode('utf-8'),
+ },
+ }
+
+
+def test_stringize_deep_plain():
+ assert library.python.strings.stringize_deep('str') == 'str' if six.PY2 else b'str'
+ assert library.python.strings.stringize_deep(u'юникод') == u'юникод'.encode('utf-8')
+ assert library.python.strings.stringize_deep(u'юникод'.encode('utf-8')) == u'юникод'.encode('utf-8')
+
+
+def test_stringize_deep_nonstr():
+ with pytest.raises(TypeError):
+ library.python.strings.stringize_deep(Convertible(), relaxed=False)
+ x = Convertible()
+ assert x == library.python.strings.stringize_deep(x)
+
+
+def test_unicodize_deep():
+ assert library.python.strings.unicodize_deep({
+ 'key 1': 'value 1',
+ u'ключ 2': u'значение 2',
+ u'ключ 3'.encode('utf-8'): u'значение 3'.encode('utf-8'),
+ }) == {
+ u'key 1': u'value 1',
+ u'ключ 2': u'значение 2',
+ u'ключ 3': u'значение 3',
+ }
+
+
+def test_unicodize_deep_nested():
+ assert library.python.strings.unicodize_deep({
+ 'key 1': 'value 1',
+ u'ключ 2': {
+ 'subkey 1': 'value 1',
+ u'подключ 2': u'значение 2',
+ u'подключ 3'.encode('utf-8'): u'значение 3'.encode('utf-8'),
+ },
+ }) == {
+ u'key 1': u'value 1',
+ u'ключ 2': {
+ u'subkey 1': u'value 1',
+ u'подключ 2': u'значение 2',
+ u'подключ 3': u'значение 3',
+ },
+ }
+
+
+def test_unicodize_deep_plain():
+ assert library.python.strings.unicodize_deep('str') == u'str'
+ assert library.python.strings.unicodize_deep(u'юникод') == u'юникод'
+ assert library.python.strings.unicodize_deep(u'юникод'.encode('utf-8')) == u'юникод'
+
+
+def test_unicodize_deep_nonstr():
+ with pytest.raises(TypeError):
+ library.python.strings.unicodize_deep(Convertible(), relaxed=False)
+ x = Convertible()
+ assert x == library.python.strings.stringize_deep(x)
diff --git a/library/python/strings/ut/ya.make b/library/python/strings/ut/ya.make
new file mode 100644
index 0000000000..dfacb226c7
--- /dev/null
+++ b/library/python/strings/ut/ya.make
@@ -0,0 +1,11 @@
+OWNER(g:yatool)
+
+PY23_TEST()
+
+TEST_SRCS(test_strings.py)
+
+PEERDIR(
+ library/python/strings
+)
+
+END()
diff --git a/library/python/strings/ya.make b/library/python/strings/ya.make
new file mode 100644
index 0000000000..7e0b033717
--- /dev/null
+++ b/library/python/strings/ya.make
@@ -0,0 +1,16 @@
+OWNER(g:yatool)
+
+PY23_LIBRARY()
+
+PY_SRCS(
+ __init__.py
+ CYTHONIZE_PY
+ strings.py
+)
+
+PEERDIR(
+ library/python/func
+ contrib/python/six
+)
+
+END()
diff --git a/library/python/svn_version/__init__.py b/library/python/svn_version/__init__.py
new file mode 100644
index 0000000000..7ef7d6dac7
--- /dev/null
+++ b/library/python/svn_version/__init__.py
@@ -0,0 +1 @@
+from .__svn_version import svn_version, commit_id, svn_revision, svn_last_revision, hash, svn_branch, svn_tag, patch_number # noqa
diff --git a/library/python/svn_version/__svn_version.pyx b/library/python/svn_version/__svn_version.pyx
new file mode 100644
index 0000000000..d66bc09d24
--- /dev/null
+++ b/library/python/svn_version/__svn_version.pyx
@@ -0,0 +1,35 @@
+import future.utils as fu
+
+cdef extern from "library/cpp/svnversion/svnversion.h":
+ cdef const char* GetProgramSvnVersion() except +;
+ cdef int GetProgramSvnRevision() except +;
+ cdef int GetArcadiaLastChangeNum() except +;
+ cdef const char* GetProgramCommitId() except +;
+ cdef const char* GetProgramHash() except +;
+ cdef const char* GetBranch() except +;
+ cdef const char* GetTag() except +;
+ cdef int GetArcadiaPatchNumber() except +;
+
+def svn_version():
+ return fu.bytes_to_native_str(GetProgramSvnVersion())
+
+def svn_revision():
+ return GetProgramSvnRevision()
+
+def svn_last_revision():
+ return GetArcadiaLastChangeNum()
+
+def commit_id():
+ return fu.bytes_to_native_str(GetProgramCommitId())
+
+def hash():
+ return fu.bytes_to_native_str(GetProgramHash())
+
+def svn_branch():
+ return fu.bytes_to_native_str(GetBranch())
+
+def svn_tag():
+ return fu.bytes_to_native_str(GetTag())
+
+def patch_number():
+ return GetArcadiaPatchNumber()
diff --git a/library/python/svn_version/ut/lib/test_simple.py b/library/python/svn_version/ut/lib/test_simple.py
new file mode 100644
index 0000000000..2c27af6c68
--- /dev/null
+++ b/library/python/svn_version/ut/lib/test_simple.py
@@ -0,0 +1,16 @@
+import library.python.svn_version as sv
+
+
+def test_simple():
+ assert sv.svn_version()
+ assert isinstance(sv.svn_version(), str)
+ assert sv.svn_revision()
+ assert isinstance(sv.svn_revision(), int)
+ assert sv.svn_last_revision()
+ assert isinstance(sv.svn_last_revision(), int)
+ assert sv.svn_last_revision() > 0
+ assert sv.commit_id()
+ assert isinstance(sv.commit_id(), str)
+ assert len(sv.commit_id()) > 0
+ assert isinstance(sv.hash(), str)
+ assert isinstance(sv.patch_number(), int)
diff --git a/library/python/svn_version/ut/lib/ya.make b/library/python/svn_version/ut/lib/ya.make
new file mode 100644
index 0000000000..fb50caf125
--- /dev/null
+++ b/library/python/svn_version/ut/lib/ya.make
@@ -0,0 +1,13 @@
+PY23_LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ library/python/svn_version
+)
+
+TEST_SRCS(
+ test_simple.py
+)
+
+END()
diff --git a/library/python/svn_version/ut/py2/ya.make b/library/python/svn_version/ut/py2/ya.make
new file mode 100644
index 0000000000..c860e16536
--- /dev/null
+++ b/library/python/svn_version/ut/py2/ya.make
@@ -0,0 +1,9 @@
+PY2TEST()
+
+OWNER(pg)
+
+PEERDIR(
+ library/python/svn_version/ut/lib
+)
+
+END()
diff --git a/library/python/svn_version/ut/py3/ya.make b/library/python/svn_version/ut/py3/ya.make
new file mode 100644
index 0000000000..4231565142
--- /dev/null
+++ b/library/python/svn_version/ut/py3/ya.make
@@ -0,0 +1,9 @@
+PY3TEST()
+
+OWNER(pg)
+
+PEERDIR(
+ library/python/svn_version/ut/lib
+)
+
+END()
diff --git a/library/python/svn_version/ut/ya.make b/library/python/svn_version/ut/ya.make
new file mode 100644
index 0000000000..1363b76581
--- /dev/null
+++ b/library/python/svn_version/ut/ya.make
@@ -0,0 +1,5 @@
+RECURSE(
+ lib
+ py2
+ py3
+)
diff --git a/library/python/svn_version/ya.make b/library/python/svn_version/ya.make
new file mode 100644
index 0000000000..747a663f00
--- /dev/null
+++ b/library/python/svn_version/ya.make
@@ -0,0 +1,15 @@
+PY23_LIBRARY()
+
+OWNER(pg)
+
+PEERDIR(
+ library/cpp/svnversion
+ contrib/python/future
+)
+
+PY_SRCS(
+ __init__.py
+ __svn_version.pyx
+)
+
+END()
diff --git a/library/python/symbols/libc/syms.cpp b/library/python/symbols/libc/syms.cpp
new file mode 100644
index 0000000000..6c04a7ef6e
--- /dev/null
+++ b/library/python/symbols/libc/syms.cpp
@@ -0,0 +1,157 @@
+#include <util/system/platform.h>
+
+#include <library/python/symbols/registry/syms.h>
+
+#if !defined(_MSC_VER)
+#if __has_include(<aio.h>)
+#include <aio.h>
+#endif
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <sched.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/ipc.h>
+#include <dlfcn.h>
+
+#if defined(_linux_)
+#include <sys/prctl.h>
+#include <sys/ptrace.h>
+#include <sys/sendfile.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#endif
+
+#if defined(_darwin_)
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <mach/mach_error.h> // Y_IGNORE
+#include <mach/mach_time.h> // Y_IGNORE
+#endif
+
+#if defined(_linux_)
+#include <sys/inotify.h>
+#include <sys/mman.h>
+#endif
+
+namespace {
+ static inline void* ErrnoLocation() {
+ return &errno;
+ }
+
+ static int ClockGetres(clockid_t clk_id, struct timespec* res) {
+#if defined(_darwin_)
+ static auto func = (decltype(&ClockGetres))dlsym(RTLD_SELF, "_clock_getres");
+
+ if (func) {
+ return func(clk_id, res);
+ }
+
+ // https://opensource.apple.com/source/Libc/Libc-1158.1.2/gen/clock_gettime.c.auto.html
+
+ switch (clk_id){
+ case CLOCK_REALTIME:
+ case CLOCK_MONOTONIC:
+ case CLOCK_PROCESS_CPUTIME_ID:
+ res->tv_nsec = NSEC_PER_USEC;
+ res->tv_sec = 0;
+
+ return 0;
+
+ case CLOCK_MONOTONIC_RAW:
+ case CLOCK_MONOTONIC_RAW_APPROX:
+ case CLOCK_UPTIME_RAW:
+ case CLOCK_UPTIME_RAW_APPROX:
+ case CLOCK_THREAD_CPUTIME_ID: {
+ mach_timebase_info_data_t tb_info;
+
+ if (mach_timebase_info(&tb_info)) {
+ return -1;
+ }
+
+ res->tv_nsec = tb_info.numer / tb_info.denom + (tb_info.numer % tb_info.denom != 0);
+ res->tv_sec = 0;
+
+ return 0;
+ }
+
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+#else
+ return clock_getres(clk_id, res);
+#endif
+ }
+}
+
+BEGIN_SYMS("c")
+
+SYM(calloc)
+SYM(clock_gettime)
+SYM_2("clock_getres", ClockGetres)
+SYM(closedir)
+SYM(fdopen)
+SYM(fflush)
+SYM(freeifaddrs)
+SYM(ftok)
+SYM(getifaddrs)
+SYM(getnameinfo)
+SYM(getpwnam)
+SYM(inet_ntop)
+SYM(opendir)
+SYM(printf)
+SYM(pthread_kill)
+SYM(pthread_self)
+SYM(readdir_r)
+SYM(sem_close)
+SYM(sem_getvalue)
+SYM(sem_open)
+SYM(sem_post)
+SYM(sem_trywait)
+SYM(sem_unlink)
+SYM(sem_wait)
+SYM(siginterrupt)
+SYM(strdup)
+SYM(sendfile)
+SYM(strtod)
+SYM_2("__errno_location", ErrnoLocation)
+
+#if defined(_linux_)
+SYM(prctl)
+SYM(ptrace)
+SYM(sched_getaffinity)
+SYM(sched_setaffinity)
+SYM(sem_timedwait)
+SYM(inotify_init)
+SYM(inotify_add_watch)
+SYM(inotify_rm_watch)
+SYM(mlockall)
+#endif
+
+#if defined(_darwin_)
+SYM(mach_absolute_time)
+SYM(mach_timebase_info)
+SYM(sysctlbyname)
+#endif
+
+#if __has_include(<aio.h>)
+SYM(aio_error)
+SYM(aio_read)
+SYM(aio_return)
+SYM(aio_suspend)
+#endif
+
+END_SYMS()
+#endif
diff --git a/library/python/symbols/libc/ya.make b/library/python/symbols/libc/ya.make
new file mode 100644
index 0000000000..7b84cbc961
--- /dev/null
+++ b/library/python/symbols/libc/ya.make
@@ -0,0 +1,19 @@
+LIBRARY()
+
+OWNER(pg orivej)
+
+PEERDIR(
+ library/python/symbols/registry
+)
+
+IF (GCC OR CLANG)
+ CFLAGS(
+ -Wno-deprecated-declarations # For sem_getvalue.
+ )
+ENDIF()
+
+SRCS(
+ GLOBAL syms.cpp
+)
+
+END()
diff --git a/library/python/symbols/module/__init__.py b/library/python/symbols/module/__init__.py
new file mode 100644
index 0000000000..0061b9e598
--- /dev/null
+++ b/library/python/symbols/module/__init__.py
@@ -0,0 +1,48 @@
+import subprocess
+
+from collections import defaultdict
+
+from .syms import syms
+
+
+def gen_builtin():
+ res = defaultdict(dict)
+
+ for k, v in syms.items():
+ mod, sym = k.split('|')
+
+ res[mod][sym] = v
+
+ return res
+
+
+builtin_symbols = gen_builtin()
+caps = builtin_symbols['_capability']
+
+
+def find_library(name, find_next):
+ subst = {
+ 'rt': 'c',
+ 'pthread': 'c',
+ 'm': 'c',
+ }
+
+ builtin = builtin_symbols.get(subst.get(name, name))
+
+ if builtin:
+ return {
+ 'name': name,
+ 'symbols': builtin,
+ }
+
+ if 'musl' in caps:
+ return None
+
+ try:
+ subprocess.Popen.__patched__
+
+ return None
+ except Exception:
+ pass
+
+ return find_next(name)
diff --git a/library/python/symbols/module/module.cpp b/library/python/symbols/module/module.cpp
new file mode 100644
index 0000000000..92bc7f4d67
--- /dev/null
+++ b/library/python/symbols/module/module.cpp
@@ -0,0 +1,85 @@
+#include <Python.h>
+
+#include <library/python/symbols/registry/syms.h>
+
+#include <util/generic/string.h>
+
+#define CAP(x) SYM_2(x, x)
+
+BEGIN_SYMS("_capability")
+#if defined(_musl_)
+CAP("musl")
+#endif
+#if defined(_linux_)
+CAP("linux")
+#endif
+#if defined(_darwin_)
+CAP("darwin")
+#endif
+CAP("_sentinel")
+END_SYMS()
+
+#undef CAP
+
+using namespace NPrivate;
+
+namespace {
+ template <class T>
+ struct TCB: public ICB {
+ inline TCB(T& t)
+ : CB(&t)
+ {
+ }
+
+ void Apply(const char* mod, const char* name, void* sym) override {
+ (*CB)(mod, name, sym);
+ }
+
+ T* CB;
+ };
+
+ template <class T>
+ static inline TCB<T> MakeTCB(T& t) {
+ return t;
+ }
+}
+
+static void DictSetStringPtr(PyObject* dict, const char* name, void* value) {
+ PyObject* p = PyLong_FromVoidPtr(value);
+ PyDict_SetItemString(dict, name, p);
+ Py_DECREF(p);
+}
+
+static PyObject* InitSyms(PyObject* m) {
+ if (!m)
+ return NULL;
+ PyObject* d = PyDict_New();
+ if (!d)
+ return NULL;
+
+ auto f = [&](const char* mod, const char* name, void* sym) {
+ DictSetStringPtr(d, (TString(mod) + "|" + TString(name)).c_str(), sym);
+ };
+
+ auto cb = MakeTCB(f);
+
+ ForEachSymbol(cb);
+
+ if (PyObject_SetAttrString(m, "syms", d))
+ m = NULL;
+ Py_DECREF(d);
+ return m;
+}
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef module = {
+ PyModuleDef_HEAD_INIT, "syms", NULL, -1, NULL, NULL, NULL, NULL, NULL};
+
+extern "C" PyObject* PyInit_syms() {
+ return InitSyms(PyModule_Create(&module));
+}
+#else
+extern "C" void initsyms() {
+ InitSyms(Py_InitModule("syms", NULL));
+}
+#endif
diff --git a/library/python/symbols/module/ya.make b/library/python/symbols/module/ya.make
new file mode 100644
index 0000000000..78e30f2547
--- /dev/null
+++ b/library/python/symbols/module/ya.make
@@ -0,0 +1,23 @@
+PY23_LIBRARY()
+
+OWNER(pg orivej)
+
+NO_PYTHON_INCLUDES()
+
+PEERDIR(
+ contrib/libs/python/Include
+)
+
+SRCS(
+ module.cpp
+)
+
+PY_REGISTER(
+ library.python.symbols.module.syms
+)
+
+PY_SRCS(
+ __init__.py
+)
+
+END()
diff --git a/library/python/symbols/python/syms.cpp b/library/python/symbols/python/syms.cpp
new file mode 100644
index 0000000000..9b52574cb1
--- /dev/null
+++ b/library/python/symbols/python/syms.cpp
@@ -0,0 +1,17 @@
+#define SYM(SYM_NAME) extern "C" void SYM_NAME();
+SYM(PyObject_GetBuffer)
+SYM(PyBuffer_Release)
+SYM(PyCell_New)
+SYM(Py_DecRef)
+SYM(Py_IncRef)
+#undef SYM
+
+#include <library/python/symbols/registry/syms.h>
+
+BEGIN_SYMS("python")
+SYM(PyObject_GetBuffer)
+SYM(PyBuffer_Release)
+SYM(PyCell_New)
+SYM(Py_DecRef)
+SYM(Py_IncRef)
+END_SYMS()
diff --git a/library/python/symbols/python/ut/py2/ya.make b/library/python/symbols/python/ut/py2/ya.make
new file mode 100644
index 0000000000..214194de57
--- /dev/null
+++ b/library/python/symbols/python/ut/py2/ya.make
@@ -0,0 +1,9 @@
+PY2TEST()
+
+OWNER(orivej)
+
+PEERDIR(
+ library/python/symbols/python/ut
+)
+
+END()
diff --git a/library/python/symbols/python/ut/py3/ya.make b/library/python/symbols/python/ut/py3/ya.make
new file mode 100644
index 0000000000..76611c6a19
--- /dev/null
+++ b/library/python/symbols/python/ut/py3/ya.make
@@ -0,0 +1,9 @@
+PY3TEST()
+
+OWNER(orivej)
+
+PEERDIR(
+ library/python/symbols/python/ut
+)
+
+END()
diff --git a/library/python/symbols/python/ut/test_ctypes.py b/library/python/symbols/python/ut/test_ctypes.py
new file mode 100644
index 0000000000..253a10d8b3
--- /dev/null
+++ b/library/python/symbols/python/ut/test_ctypes.py
@@ -0,0 +1,37 @@
+from ctypes import (
+ byref, POINTER, c_int, c_char, c_char_p,
+ c_void_p, py_object, c_ssize_t, pythonapi, Structure
+)
+
+c_ssize_p = POINTER(c_ssize_t)
+
+
+class Py_buffer(Structure):
+ _fields_ = [
+ ('buf', c_void_p),
+ ('obj', py_object),
+ ('len', c_ssize_t),
+ ('itemsize', c_ssize_t),
+ ('readonly', c_int),
+ ('ndim', c_int),
+ ('format', c_char_p),
+ ('shape', c_ssize_p),
+ ('strides', c_ssize_p),
+ ('suboffsets', c_ssize_p),
+ ('smalltable', c_ssize_t * 2),
+ ('internal', c_void_p)
+ ]
+
+
+def get_buffer(obj):
+ buf = Py_buffer()
+ pythonapi.PyObject_GetBuffer(py_object(obj), byref(buf), 0)
+ try:
+ buffer_type = c_char * buf.len
+ return buffer_type.from_address(buf.buf)
+ finally:
+ pythonapi.PyBuffer_Release(byref(buf))
+
+
+def test_buffer():
+ assert get_buffer(b'test string')
diff --git a/library/python/symbols/python/ut/ya.make b/library/python/symbols/python/ut/ya.make
new file mode 100644
index 0000000000..2849e01b1e
--- /dev/null
+++ b/library/python/symbols/python/ut/ya.make
@@ -0,0 +1,16 @@
+PY23_LIBRARY()
+
+OWNER(orivej)
+
+TEST_SRCS(test_ctypes.py)
+
+PEERDIR(
+ library/python/symbols/python
+)
+
+END()
+
+RECURSE_FOR_TESTS(
+ py2
+ py3
+)
diff --git a/library/python/symbols/python/ya.make b/library/python/symbols/python/ya.make
new file mode 100644
index 0000000000..6bfd54f8bc
--- /dev/null
+++ b/library/python/symbols/python/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+OWNER(orivej)
+
+PEERDIR(
+ library/python/symbols/registry
+)
+
+SRCS(
+ GLOBAL syms.cpp
+)
+
+END()
+
+RECURSE_FOR_TESTS(ut)
diff --git a/library/python/symbols/registry/syms.cpp b/library/python/symbols/registry/syms.cpp
new file mode 100644
index 0000000000..ae8e98b32e
--- /dev/null
+++ b/library/python/symbols/registry/syms.cpp
@@ -0,0 +1,31 @@
+#include "syms.h"
+
+#include <util/generic/vector.h>
+#include <util/generic/string.h>
+#include <util/generic/singleton.h>
+
+using namespace NPrivate;
+
+namespace {
+ struct TSym {
+ const char* Mod;
+ const char* Name;
+ void* Sym;
+ };
+
+ struct TSymbols: public TVector<TSym> {
+ static inline TSymbols* Instance() {
+ return Singleton<TSymbols>();
+ }
+ };
+}
+
+void NPrivate::RegisterSymbol(const char* mod, const char* name, void* sym) {
+ TSymbols::Instance()->push_back(TSym{mod, name, sym});
+}
+
+void NPrivate::ForEachSymbol(ICB& cb) {
+ for (auto& x : *TSymbols::Instance()) {
+ cb.Apply(x.Mod, x.Name, x.Sym);
+ }
+}
diff --git a/library/python/symbols/registry/syms.h b/library/python/symbols/registry/syms.h
new file mode 100644
index 0000000000..5e34d35298
--- /dev/null
+++ b/library/python/symbols/registry/syms.h
@@ -0,0 +1,24 @@
+#pragma once
+
+namespace NPrivate {
+ struct ICB {
+ virtual void Apply(const char* mod, const char* name, void* sym) = 0;
+ };
+
+ void ForEachSymbol(ICB& cb);
+ void RegisterSymbol(const char* mod, const char* name, void* sym);
+}
+
+#define BEGIN_SYMS(name) \
+ namespace { \
+ static struct TRegister { \
+ const char* ModuleName = name; \
+ inline TRegister() {
+#define END_SYMS() \
+ } \
+ } \
+ REGISTRY; \
+ }
+
+#define SYM_2(n, s) ::NPrivate::RegisterSymbol(this->ModuleName, n, (void*)&s);
+#define SYM(s) SYM_2(#s, s);
diff --git a/library/python/symbols/registry/ya.make b/library/python/symbols/registry/ya.make
new file mode 100644
index 0000000000..2737b9fce9
--- /dev/null
+++ b/library/python/symbols/registry/ya.make
@@ -0,0 +1,9 @@
+LIBRARY()
+
+OWNER(pg orivej)
+
+SRCS(
+ syms.cpp
+)
+
+END()
diff --git a/library/python/symbols/ya.make b/library/python/symbols/ya.make
new file mode 100644
index 0000000000..340a710c48
--- /dev/null
+++ b/library/python/symbols/ya.make
@@ -0,0 +1,12 @@
+RECURSE(
+ module
+ registry
+ tests
+
+ crypto
+ libc
+ libmagic
+ python
+ uuid
+ win_unicode_console
+)
diff --git a/library/python/testing/__init__.py b/library/python/testing/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/library/python/testing/__init__.py
diff --git a/library/python/testing/filter/filter.py b/library/python/testing/filter/filter.py
new file mode 100644
index 0000000000..a1642bd052
--- /dev/null
+++ b/library/python/testing/filter/filter.py
@@ -0,0 +1,57 @@
+# coding: utf-8
+# TODO move devtools/ya/test/filter.py to library/python/testing/filter/filter.py
+import re
+import fnmatch
+import logging
+
+logger = logging.getLogger(__name__)
+TEST_SUBTEST_SEPARATOR = '::'
+
+PARSE_TAG_RE = re.compile("([+-]?[\w:]*)")
+
+
+class FilterException(Exception):
+ mute = True
+
+
+def fix_filter(flt):
+ if TEST_SUBTEST_SEPARATOR not in flt and "*" not in flt:
+ # user wants to filter by test module name
+ flt = flt + TEST_SUBTEST_SEPARATOR + "*"
+ return flt
+
+
+def escape_for_fnmatch(s):
+ return s.replace("[", "&#91;").replace("]", "&#93;")
+
+
+def make_py_file_filter(filter_names):
+ if filter_names is not None:
+ with_star = []
+ wo_star = set()
+ for flt in filter_names:
+ flt = flt.split(':')[0]
+ if '*' in flt:
+ with_star.append(flt.split('*')[0] + '*')
+ else:
+ wo_star.add(flt)
+
+ def predicate(filename):
+ if filter_names is None:
+ return True
+ return filename in wo_star or any([fnmatch.fnmatch(escape_for_fnmatch(filename), escape_for_fnmatch(filter_name)) for filter_name in with_star])
+
+ return predicate
+
+
+def make_name_filter(filter_names):
+ filter_names = map(fix_filter, filter_names)
+ filter_full_names = set()
+ for name in filter_names:
+ if '*' not in name:
+ filter_full_names.add(name)
+
+ def predicate(testname):
+ return testname in filter_full_names or any([fnmatch.fnmatch(escape_for_fnmatch(testname), escape_for_fnmatch(filter_name)) for filter_name in filter_names])
+
+ return predicate
diff --git a/library/python/testing/filter/ya.make b/library/python/testing/filter/ya.make
new file mode 100644
index 0000000000..22c485d258
--- /dev/null
+++ b/library/python/testing/filter/ya.make
@@ -0,0 +1,5 @@
+PY23_LIBRARY()
+OWNER(g:yatest)
+PY_SRCS(filter.py)
+
+END()
diff --git a/library/python/testing/import_test/import_test.py b/library/python/testing/import_test/import_test.py
new file mode 100644
index 0000000000..3e3b7234ef
--- /dev/null
+++ b/library/python/testing/import_test/import_test.py
@@ -0,0 +1,124 @@
+from __future__ import print_function
+
+import os
+import re
+import sys
+import time
+import traceback
+
+import __res
+from __res import importer
+
+
+def check_imports(no_check=(), extra=(), skip_func=None, py_main=None):
+ """
+ tests all bundled modules are importable
+ just add
+ "PEERDIR(library/python/import_test)" to your CMakeLists.txt and
+ "from import_test import test_imports" to your python test source file.
+ """
+ str_ = lambda s: s
+ if not isinstance(b'', str):
+ str_ = lambda s: s.decode('UTF-8')
+
+ exceptions = list(no_check)
+ for key, _ in __res.iter_keys(b'py/no_check_imports/'):
+ exceptions += str_(__res.find(key)).split()
+ if exceptions:
+ exceptions.sort()
+ print('NO_CHECK_IMPORTS', ' '.join(exceptions))
+
+ patterns = [re.escape(s).replace(r'\*', r'.*') for s in exceptions]
+ rx = re.compile('^({})$'.format('|'.join(patterns)))
+
+ failed = []
+ import_times = {}
+
+ norm = lambda s: s[:-9] if s.endswith('.__init__') else s
+
+ modules = sys.extra_modules | set(extra)
+ modules = sorted(modules, key=norm)
+ if py_main:
+ modules = [py_main] + modules
+
+ for module in modules:
+ if module not in extra and (rx.search(module) or skip_func and skip_func(module)):
+ print('SKIP', module)
+ continue
+
+ name = module.rsplit('.', 1)[-1]
+ if name == '__main__' and 'if __name__ ==' not in importer.get_source(module):
+ print('SKIP', module, '''without "if __name__ == '__main__'" check''')
+ continue
+
+ def print_backtrace_marked(e):
+ tb_exc = traceback.format_exception(*e)
+ for item in tb_exc:
+ for l in item.splitlines():
+ print('FAIL:', l, file=sys.stderr)
+
+ try:
+ print('TRY', module)
+ # XXX waiting for py3 to use print(..., flush=True)
+ sys.stdout.flush()
+
+ s = time.time()
+ if module == '__main__':
+ importer.load_module('__main__', '__main__py')
+ elif module.endswith('.__init__'):
+ __import__(module[:-len('.__init__')])
+ else:
+ __import__(module)
+
+ delay = time.time() - s
+ import_times[str(module)] = delay
+ print('OK ', module, '{:.3f}s'.format(delay))
+
+ except Exception as e:
+ print('FAIL:', module, e, file=sys.stderr)
+ print_backtrace_marked(sys.exc_info())
+ failed.append('{}: {}'.format(module, e))
+
+ except:
+ e = sys.exc_info()
+ print('FAIL:', module, e, file=sys.stderr)
+ print_backtrace_marked(e)
+ failed.append('{}: {}'.format(module, e))
+ raise
+
+ print("Slowest imports:")
+ for m, t in sorted(import_times.items(), key=lambda x: x[1], reverse=True)[:30]:
+ print(' ', '{:.3f}s'.format(t), m)
+
+ if failed:
+ raise ImportError('modules not imported:\n' + '\n'.join(failed))
+
+
+test_imports = check_imports
+
+
+def main():
+ skip_names = sys.argv[1:]
+
+ os.environ['Y_PYTHON_IMPORT_TEST'] = ''
+
+ # We should initialize Django before importing any applications
+ if os.getenv('DJANGO_SETTINGS_MODULE'):
+ try:
+ import django
+ except ImportError:
+ pass
+ else:
+ django.setup()
+
+ py_main = __res.find('PY_MAIN')
+
+ if py_main:
+ py_main_module = py_main.split(b':', 1)[0].decode('UTF-8')
+ else:
+ py_main_module = None
+
+ try:
+ check_imports(no_check=skip_names, py_main=py_main_module)
+ except:
+ sys.exit(1)
diff --git a/library/python/testing/import_test/ya.make b/library/python/testing/import_test/ya.make
new file mode 100644
index 0000000000..fae36ffe8f
--- /dev/null
+++ b/library/python/testing/import_test/ya.make
@@ -0,0 +1,10 @@
+OWNER(
+ g:yatest
+ exprmntr
+)
+
+PY23_LIBRARY()
+
+PY_SRCS(import_test.py)
+
+END()
diff --git a/library/python/testing/recipe/__init__.py b/library/python/testing/recipe/__init__.py
new file mode 100644
index 0000000000..5ef9c5c189
--- /dev/null
+++ b/library/python/testing/recipe/__init__.py
@@ -0,0 +1,102 @@
+from __future__ import print_function
+
+import os
+import sys
+import json
+import logging
+import argparse
+
+from yatest_lib.ya import Ya
+
+RECIPE_START_OPTION = "start"
+RECIPE_STOP_OPTION = "stop"
+
+ya = None
+collect_cores = None
+sanitizer_extra_checks = None
+
+
+def _setup_logging(level=logging.DEBUG):
+ root_logger = logging.getLogger()
+ root_logger.setLevel(level)
+
+ log_format = '%(asctime)s - %(levelname)s - %(name)s - %(funcName)s: %(message)s'
+
+ stdout_handler = logging.StreamHandler(sys.stdout)
+ stdout_handler.setLevel(logging.DEBUG)
+ formatter = logging.Formatter(log_format)
+ stdout_handler.setFormatter(formatter)
+ root_logger.addHandler(stdout_handler)
+
+
+def get_options():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--show-cwd", action="store_true", dest="show_cwd", default=False, help="show recipe cwd")
+ parser.add_argument("--test-debug", action="store_true", dest="test_debug", default=False, help="test debug mode")
+ parser.add_argument("--test-stderr", action="store_true", dest="test_stderr", default=False, help="test stderr")
+ parser.add_argument("--pdb", action="store_true", dest="pdb", default=False, help="run pdb on error")
+ parser.add_argument("--sanitizer-extra-checks", dest="sanitizer_extra_checks", action="store_true", default=False, help="enables extra checks for tests built with sanitizers")
+ parser.add_argument("--collect-cores", dest="collect_cores", action="store_true", default=False, help="allows core dump file recovering during test")
+
+ args, opts = parser.parse_known_args()
+
+ global ya, sanitizer_extra_checks, collect_cores
+ _setup_logging()
+
+ context = {
+ "test_stderr": args.test_stderr,
+ }
+
+ ya = Ya(context=context)
+
+ ya._data_root = "" # XXX remove
+
+ sanitizer_extra_checks = args.sanitizer_extra_checks
+ if sanitizer_extra_checks:
+ for envvar in ['LSAN_OPTIONS', 'ASAN_OPTIONS']:
+ if envvar in os.environ:
+ os.environ.pop(envvar)
+ if envvar + '_ORIGINAL' in os.environ:
+ os.environ[envvar] = os.environ[envvar + '_ORIGINAL']
+ collect_cores = args.collect_cores
+
+ for recipe_option in RECIPE_START_OPTION, RECIPE_STOP_OPTION:
+ if recipe_option in opts:
+ return args, opts[opts.index(recipe_option):]
+
+
+def set_env(key, value):
+ with open(ya.env_file, "a") as f:
+ json.dump({key: value}, f)
+ f.write("\n")
+
+
+def tty():
+ if os.isatty(1):
+ return
+
+ f = open('/dev/tty', 'w+')
+ fd = f.fileno()
+ os.dup2(fd, 0)
+ os.dup2(fd, 1)
+ os.dup2(fd, 2)
+
+
+def declare_recipe(start, stop):
+ parsed_args, argv = get_options()
+
+ if parsed_args.show_cwd:
+ print("Recipe \"{} {}\" working dir is {}".format(sys.argv[0], " ".join(argv), os.getcwd()))
+
+ try:
+ if argv[0] == RECIPE_START_OPTION:
+ start(argv[1:])
+ elif argv[0] == RECIPE_STOP_OPTION:
+ stop(argv[1:])
+ except Exception:
+ if parsed_args.pdb:
+ tty()
+ import ipdb
+ ipdb.post_mortem()
+ else:
+ raise
diff --git a/library/python/testing/recipe/ports.py b/library/python/testing/recipe/ports.py
new file mode 100644
index 0000000000..9f7de1e767
--- /dev/null
+++ b/library/python/testing/recipe/ports.py
@@ -0,0 +1,33 @@
+import os
+import sys
+import subprocess
+import time
+
+from yatest.common.network import PortManager
+
+
+def __get_port_range():
+ port_count = int(sys.argv[1])
+ pid_filename = sys.argv[2]
+ port_manager = PortManager()
+ start_port = port_manager.get_port_range(None, port_count)
+ sys.stderr.write(str(start_port) + "\n")
+ with open(pid_filename, 'w') as afile:
+ afile.write(str(os.getpid()))
+ while 1:
+ time.sleep(1)
+
+
+def get_port_range(port_count=1, pid_filename="recipe_port.pid"):
+ env = os.environ.copy()
+ env["Y_PYTHON_ENTRY_POINT"] = "library.python.testing.recipe.ports:__get_port_range"
+ res = subprocess.Popen([sys.argv[0], str(port_count), pid_filename], env=env, cwd=os.getcwd(), stderr=subprocess.PIPE)
+ while not os.path.exists(pid_filename):
+ time.sleep(0.01)
+ port_start = int(res.stderr.readline())
+ return port_start
+
+
+def release_port_range(pid_filename="recipe_port.pid"):
+ with open(pid_filename, 'r') as afile:
+ os.kill(int(afile.read()), 9)
diff --git a/library/python/testing/recipe/ya.make b/library/python/testing/recipe/ya.make
new file mode 100644
index 0000000000..dd323aa245
--- /dev/null
+++ b/library/python/testing/recipe/ya.make
@@ -0,0 +1,19 @@
+OWNER(
+ exprmntr
+ g:yatest
+)
+
+PY23_LIBRARY()
+
+PY_SRCS(
+ __init__.py
+ ports.py
+)
+
+PEERDIR(
+ contrib/python/ipdb
+ library/python/testing/yatest_common
+ library/python/testing/yatest_lib
+)
+
+END()
diff --git a/library/python/testing/ya.make b/library/python/testing/ya.make
new file mode 100644
index 0000000000..883bc8d7ab
--- /dev/null
+++ b/library/python/testing/ya.make
@@ -0,0 +1,22 @@
+OWNER(g:yatest)
+
+RECURSE(
+ behave
+ deprecated
+ fake_ya_package
+ filter
+ gtest
+ gtest/test
+ gtest/test/gtest
+ pyremock
+ pytest_runner
+ pytest_runner/example
+ pytest_runner/test
+ recipe
+ system_info
+ types_test
+ yapackage
+ yapackage/test
+ yatest_common
+ yatest_lib
+)
diff --git a/library/python/testing/yatest_common/ya.make b/library/python/testing/yatest_common/ya.make
new file mode 100644
index 0000000000..5662db4c5d
--- /dev/null
+++ b/library/python/testing/yatest_common/ya.make
@@ -0,0 +1,40 @@
+OWNER(g:yatest)
+
+PY23_LIBRARY()
+
+OWNER(g:yatest)
+
+NO_EXTENDED_SOURCE_SEARCH()
+
+PY_SRCS(
+ TOP_LEVEL
+ yatest/__init__.py
+ yatest/common/__init__.py
+ yatest/common/benchmark.py
+ yatest/common/canonical.py
+ yatest/common/environment.py
+ yatest/common/errors.py
+ yatest/common/legacy.py
+ yatest/common/misc.py
+ yatest/common/network.py
+ yatest/common/path.py
+ yatest/common/process.py
+ yatest/common/runtime.py
+ yatest/common/runtime_java.py
+ yatest/common/tags.py
+)
+
+PEERDIR(
+ contrib/python/six
+ library/python/cores
+ library/python/filelock
+ library/python/fs
+)
+
+IF (NOT CATBOOST_OPENSOURCE)
+ PEERDIR(
+ library/python/coredump_filter
+ )
+ENDIF()
+
+END()
diff --git a/library/python/testing/yatest_common/yatest/__init__.py b/library/python/testing/yatest_common/yatest/__init__.py
new file mode 100644
index 0000000000..b846b3317a
--- /dev/null
+++ b/library/python/testing/yatest_common/yatest/__init__.py
@@ -0,0 +1,3 @@
+__all__ = ["common"]
+
+from . import common
diff --git a/library/python/testing/yatest_common/yatest/common/__init__.py b/library/python/testing/yatest_common/yatest/common/__init__.py
new file mode 100644
index 0000000000..cf57779e27
--- /dev/null
+++ b/library/python/testing/yatest_common/yatest/common/__init__.py
@@ -0,0 +1,8 @@
+from .benchmark import * # noqa
+from .canonical import * # noqa
+from .errors import * # noqa
+from .misc import * # noqa
+from .path import * # noqa
+from .process import * # noqa
+from .runtime import * # noqa
+from .tags import * # noqa
diff --git a/library/python/testing/yatest_common/yatest/common/benchmark.py b/library/python/testing/yatest_common/yatest/common/benchmark.py
new file mode 100644
index 0000000000..c3784cbe4c
--- /dev/null
+++ b/library/python/testing/yatest_common/yatest/common/benchmark.py
@@ -0,0 +1,22 @@
+import json
+
+from . import process
+from . import runtime
+
+
+def execute_benchmark(path, budget=None, threads=None):
+ """
+ Run benchmark and return values
+ :param path: path to benchmark binary
+ :param budget: time budget, sec (supported only by ybenchmark)
+ :param threads: number of threads to run benchmark (supported only by ybenchmark)
+ :return: map of benchmark values
+ """
+ benchmark_path = runtime.binary_path(path)
+ cmd = [benchmark_path, "--benchmark_format=json"]
+ if budget is not None:
+ cmd += ["-b", str(budget)]
+ if threads is not None:
+ cmd += ["-t", str(threads)]
+ res = process.execute(cmd)
+ return json.loads(res.std_out)
diff --git a/library/python/testing/yatest_common/yatest/common/canonical.py b/library/python/testing/yatest_common/yatest/common/canonical.py
new file mode 100644
index 0000000000..b6a136d3e9
--- /dev/null
+++ b/library/python/testing/yatest_common/yatest/common/canonical.py
@@ -0,0 +1,176 @@
+import os
+import logging
+import shutil
+import tempfile
+
+import six
+
+from . import process
+from . import runtime
+from . import path
+
+yatest_logger = logging.getLogger("ya.test")
+
+
+def _copy(src, dst, universal_lines=False):
+ if universal_lines:
+ with open(dst, "wb") as f:
+ for line in open(src, "rbU"):
+ f.write(line)
+ return
+ shutil.copy(src, dst)
+
+
+def canonical_file(path, diff_tool=None, local=False, universal_lines=False, diff_file_name=None, diff_tool_timeout=None):
+ """
+ Create canonical file that can be returned from a test
+ :param path: path to the file
+ :param diff_tool: custom diff tool to use for comparison with the canonical one, if None - default will be used
+ :param local: save file locally, otherwise move to sandbox
+ :param universal_lines: normalize EOL
+ :param diff_tool_timeout: timeout for running diff tool
+ :return: object that can be canonized
+ """
+ abs_path = os.path.abspath(path)
+ assert os.path.exists(abs_path), "Canonical path {} does not exist".format(path)
+ tempdir = tempfile.mkdtemp(prefix="canon_tmp", dir=runtime.build_path())
+ safe_path = os.path.join(tempdir, os.path.basename(abs_path))
+ # if the created file is in output_path, we copy it, so that it will be available when the tests finishes
+ _copy(path, safe_path, universal_lines=universal_lines)
+ if diff_tool:
+ if not isinstance(diff_tool, six.string_types):
+ try: # check if iterable
+ if not isinstance(diff_tool[0], six.string_types):
+ raise Exception("Invalid custom diff-tool: not cmd")
+ except:
+ raise Exception("Invalid custom diff-tool: not binary path")
+ return runtime._get_ya_plugin_instance().file(safe_path, diff_tool=diff_tool, local=local, diff_file_name=diff_file_name, diff_tool_timeout=diff_tool_timeout)
+
+
+def canonical_dir(path, diff_tool=None, diff_file_name=None, diff_tool_timeout=None):
+ abs_path = os.path.abspath(path)
+ assert os.path.exists(abs_path), "Canonical path {} does not exist".format(path)
+ assert os.path.isdir(abs_path), "Path {} is not a directory".format(path)
+ if diff_file_name and not diff_tool:
+ raise Exception("diff_file_name can be only be used with diff_tool for canonical_dir")
+ tempdir = tempfile.mkdtemp()
+ safe_path = os.path.join(tempdir, os.path.basename(abs_path))
+ shutil.copytree(abs_path, safe_path)
+ return runtime._get_ya_plugin_instance().file(safe_path, diff_tool=diff_tool, diff_file_name=diff_file_name, diff_tool_timeout=diff_tool_timeout)
+
+
+def canonical_execute(
+ binary, args=None, check_exit_code=True,
+ shell=False, timeout=None, cwd=None,
+ env=None, stdin=None, stderr=None, creationflags=0,
+ file_name=None, save_locally=False, close_fds=False,
+ diff_tool=None, diff_file_name=None, diff_tool_timeout=None,
+):
+ """
+ Shortcut to execute a binary and canonize its stdout
+ :param binary: absolute path to the binary
+ :param args: binary arguments
+ :param check_exit_code: will raise ExecutionError if the command exits with non zero code
+ :param shell: use shell to run the command
+ :param timeout: execution timeout
+ :param cwd: working directory
+ :param env: command environment
+ :param stdin: command stdin
+ :param stderr: command stderr
+ :param creationflags: command creation flags
+ :param file_name: output file name. if not specified program name will be used
+ :param diff_tool: path to custome diff tool
+ :param diff_file_name: custom diff file name to create when diff is found
+ :param diff_tool_timeout: timeout for running diff tool
+ :return: object that can be canonized
+ """
+ if type(binary) == list:
+ command = binary
+ else:
+ command = [binary]
+ command += _prepare_args(args)
+ if shell:
+ command = " ".join(command)
+ execute_args = locals()
+ del execute_args["binary"]
+ del execute_args["args"]
+ del execute_args["file_name"]
+ del execute_args["save_locally"]
+ del execute_args["diff_tool"]
+ del execute_args["diff_file_name"]
+ del execute_args["diff_tool_timeout"]
+ if not file_name and stdin:
+ file_name = os.path.basename(stdin.name)
+ return _canonical_execute(process.execute, execute_args, file_name, save_locally, diff_tool, diff_file_name, diff_tool_timeout)
+
+
+def canonical_py_execute(
+ script_path, args=None, check_exit_code=True,
+ shell=False, timeout=None, cwd=None, env=None,
+ stdin=None, stderr=None, creationflags=0,
+ file_name=None, save_locally=False, close_fds=False,
+ diff_tool=None, diff_file_name=None, diff_tool_timeout=None,
+):
+ """
+ Shortcut to execute a python script and canonize its stdout
+ :param script_path: path to the script arcadia relative
+ :param args: script arguments
+ :param check_exit_code: will raise ExecutionError if the command exits with non zero code
+ :param shell: use shell to run the command
+ :param timeout: execution timeout
+ :param cwd: working directory
+ :param env: command environment
+ :param stdin: command stdin
+ :param stderr: command stderr
+ :param creationflags: command creation flags
+ :param file_name: output file name. if not specified program name will be used
+ :param diff_tool: path to custome diff tool
+ :param diff_file_name: custom diff file name to create when diff is found
+ :param diff_tool_timeout: timeout for running diff tool
+ :return: object that can be canonized
+ """
+ command = [runtime.source_path(script_path)] + _prepare_args(args)
+ if shell:
+ command = " ".join(command)
+ execute_args = locals()
+ del execute_args["script_path"]
+ del execute_args["args"]
+ del execute_args["file_name"]
+ del execute_args["save_locally"]
+ del execute_args["diff_tool"]
+ del execute_args["diff_file_name"]
+ del execute_args["diff_tool_timeout"]
+ return _canonical_execute(process.py_execute, execute_args, file_name, save_locally, diff_tool, diff_file_name, diff_tool_timeout)
+
+
+def _prepare_args(args):
+ if args is None:
+ args = []
+ if isinstance(args, six.string_types):
+ args = map(lambda a: a.strip(), args.split())
+ return args
+
+
+def _canonical_execute(excutor, kwargs, file_name, save_locally, diff_tool, diff_file_name, diff_tool_timeout):
+ res = excutor(**kwargs)
+ command = kwargs["command"]
+ file_name = file_name or process.get_command_name(command)
+ if file_name.endswith(".exe"):
+ file_name = os.path.splitext(file_name)[0] # don't want to bring windows stuff in file names
+ out_file_path = path.get_unique_file_path(runtime.output_path(), "{}.out.txt".format(file_name))
+ err_file_path = path.get_unique_file_path(runtime.output_path(), "{}.err.txt".format(file_name))
+
+ try:
+ os.makedirs(os.path.dirname(out_file_path))
+ except OSError:
+ pass
+
+ with open(out_file_path, "wb") as out_file:
+ yatest_logger.debug("Will store file in %s", out_file_path)
+ out_file.write(res.std_out)
+
+ if res.std_err:
+ with open(err_file_path, "wb") as err_file:
+ err_file.write(res.std_err)
+
+ return canonical_file(out_file_path, local=save_locally, diff_tool=diff_tool, diff_file_name=diff_file_name, diff_tool_timeout=diff_tool_timeout)
diff --git a/library/python/testing/yatest_common/yatest/common/environment.py b/library/python/testing/yatest_common/yatest/common/environment.py
new file mode 100644
index 0000000000..43f48d0958
--- /dev/null
+++ b/library/python/testing/yatest_common/yatest/common/environment.py
@@ -0,0 +1,5 @@
+# coding: utf-8
+
+
+def extend_env_var(env, name, value, sep=":"):
+ return sep.join(filter(None, [env.get(name), value]))
diff --git a/library/python/testing/yatest_common/yatest/common/errors.py b/library/python/testing/yatest_common/yatest/common/errors.py
new file mode 100644
index 0000000000..8c038fc381
--- /dev/null
+++ b/library/python/testing/yatest_common/yatest/common/errors.py
@@ -0,0 +1,20 @@
+import os
+import sys
+
+
+class RestartTestException(Exception):
+
+ def __init__(self, *args, **kwargs):
+ super(RestartTestException, self).__init__(*args, **kwargs)
+ sys.stderr.write("##restart-test##\n")
+ sys.stderr.flush()
+ os.environ["FORCE_EXIT_TESTSFAILED"] = "1"
+
+
+class InfrastructureException(Exception):
+
+ def __init__(self, *args, **kwargs):
+ super(InfrastructureException, self).__init__(*args, **kwargs)
+ sys.stderr.write("##infrastructure-error##\n")
+ sys.stderr.flush()
+ os.environ["FORCE_EXIT_TESTSFAILED"] = "1"
diff --git a/library/python/testing/yatest_common/yatest/common/legacy.py b/library/python/testing/yatest_common/yatest/common/legacy.py
new file mode 100644
index 0000000000..459972d253
--- /dev/null
+++ b/library/python/testing/yatest_common/yatest/common/legacy.py
@@ -0,0 +1,12 @@
+from . import canonical
+
+
+def old_canonical_file(output_file_name, storage_md5):
+ import yalibrary.svn
+ yalibrary.svn.run_svn([
+ 'export',
+ 'svn+ssh://arcadia.yandex.ru/arc/trunk/arcadia_tests_data/tests_canonical_output/' + storage_md5,
+ output_file_name,
+ "--force"
+ ])
+ return canonical.canonical_file(output_file_name)
diff --git a/library/python/testing/yatest_common/yatest/common/misc.py b/library/python/testing/yatest_common/yatest/common/misc.py
new file mode 100644
index 0000000000..20d3725ac9
--- /dev/null
+++ b/library/python/testing/yatest_common/yatest/common/misc.py
@@ -0,0 +1,19 @@
+import functools
+
+
+def first(it):
+ for d in it:
+ if d:
+ return d
+
+
+def lazy(func):
+ res = []
+
+ @functools.wraps(func)
+ def wrapper(*args, **kwargs):
+ if not res:
+ res.append(func(*args, **kwargs))
+ return res[0]
+
+ return wrapper
diff --git a/library/python/testing/yatest_common/yatest/common/network.py b/library/python/testing/yatest_common/yatest/common/network.py
new file mode 100644
index 0000000000..37bcb1b8e0
--- /dev/null
+++ b/library/python/testing/yatest_common/yatest/common/network.py
@@ -0,0 +1,271 @@
+# coding=utf-8
+
+import os
+import errno
+import socket
+import random
+import logging
+import platform
+import threading
+
+import six
+
+UI16MAXVAL = (1 << 16) - 1
+logger = logging.getLogger(__name__)
+
+
+class PortManagerException(Exception):
+ pass
+
+
+class PortManager(object):
+ """
+ See documentation here
+
+ https://wiki.yandex-team.ru/yatool/test/#python-acquire-ports
+ """
+
+ def __init__(self, sync_dir=None):
+ self._sync_dir = sync_dir or os.environ.get('PORT_SYNC_PATH')
+ if self._sync_dir:
+ _makedirs(self._sync_dir)
+
+ self._valid_range = get_valid_port_range()
+ self._valid_port_count = self._count_valid_ports()
+ self._filelocks = {}
+ self._lock = threading.Lock()
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, traceback):
+ self.release()
+
+ def get_port(self, port=0):
+ '''
+ Gets free TCP port
+ '''
+ return self.get_tcp_port(port)
+
+ def get_tcp_port(self, port=0):
+ '''
+ Gets free TCP port
+ '''
+ return self._get_port(port, socket.SOCK_STREAM)
+
+ def get_udp_port(self, port=0):
+ '''
+ Gets free UDP port
+ '''
+ return self._get_port(port, socket.SOCK_DGRAM)
+
+ def get_tcp_and_udp_port(self, port=0):
+ '''
+ Gets one free port for use in both TCP and UDP protocols
+ '''
+ if port and self._no_random_ports():
+ return port
+
+ retries = 20
+ while retries > 0:
+ retries -= 1
+
+ result_port = self.get_tcp_port()
+ if not self.is_port_free(result_port, socket.SOCK_DGRAM):
+ self.release_port(result_port)
+ # Don't try to _capture_port(), it's already captured in the get_tcp_port()
+ return result_port
+ raise Exception('Failed to find port')
+
+ def release_port(self, port):
+ with self._lock:
+ self._release_port_no_lock(port)
+
+ def _release_port_no_lock(self, port):
+ filelock = self._filelocks.pop(port, None)
+ if filelock:
+ filelock.release()
+
+ def release(self):
+ with self._lock:
+ while self._filelocks:
+ _, filelock = self._filelocks.popitem()
+ if filelock:
+ filelock.release()
+
+ def get_port_range(self, start_port, count, random_start=True):
+ assert count > 0
+ if start_port and self._no_random_ports():
+ return start_port
+
+ candidates = []
+
+ def drop_candidates():
+ for port in candidates:
+ self._release_port_no_lock(port)
+ candidates[:] = []
+
+ with self._lock:
+ for attempts in six.moves.range(128):
+ for left, right in self._valid_range:
+ if right - left < count:
+ continue
+
+ if random_start:
+ start = random.randint(left, right - ((right - left) // 2))
+ else:
+ start = left
+ for probe_port in six.moves.range(start, right):
+ if self._capture_port_no_lock(probe_port, socket.SOCK_STREAM):
+ candidates.append(probe_port)
+ else:
+ drop_candidates()
+
+ if len(candidates) == count:
+ return candidates[0]
+ # Can't find required number of ports without gap in the current range
+ drop_candidates()
+
+ raise PortManagerException("Failed to find valid port range (start_port: {} count: {}) (range: {} used: {})".format(
+ start_port, count, self._valid_range, self._filelocks))
+
+ def _count_valid_ports(self):
+ res = 0
+ for left, right in self._valid_range:
+ res += right - left
+ assert res, ('There are no available valid ports', self._valid_range)
+ return res
+
+ def _get_port(self, port, sock_type):
+ if port and self._no_random_ports():
+ return port
+
+ if len(self._filelocks) >= self._valid_port_count:
+ raise PortManagerException("All valid ports are taken ({}): {}".format(self._valid_range, self._filelocks))
+
+ salt = random.randint(0, UI16MAXVAL)
+ for attempt in six.moves.range(self._valid_port_count):
+ probe_port = (salt + attempt) % self._valid_port_count
+
+ for left, right in self._valid_range:
+ if probe_port >= (right - left):
+ probe_port -= right - left
+ else:
+ probe_port += left
+ break
+ if not self._capture_port(probe_port, sock_type):
+ continue
+ return probe_port
+
+ raise PortManagerException("Failed to find valid port (range: {} used: {})".format(self._valid_range, self._filelocks))
+
+ def _capture_port(self, port, sock_type):
+ with self._lock:
+ return self._capture_port_no_lock(port, sock_type)
+
+ def is_port_free(self, port, sock_type=socket.SOCK_STREAM):
+ sock = socket.socket(socket.AF_INET6, sock_type)
+ try:
+ sock.bind(('::', port))
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ except socket.error as e:
+ if e.errno == errno.EADDRINUSE:
+ return False
+ raise
+ finally:
+ sock.close()
+ return True
+
+ def _capture_port_no_lock(self, port, sock_type):
+ if port in self._filelocks:
+ return False
+
+ filelock = None
+ if self._sync_dir:
+ # yatest.common should try to be hermetic and don't have peerdirs
+ # otherwise, PYTEST_SCRIPT (aka USE_ARCADIA_PYTHON=no) won't work
+ import library.python.filelock
+
+ filelock = library.python.filelock.FileLock(os.path.join(self._sync_dir, str(port)))
+ if not filelock.acquire(blocking=False):
+ return False
+ if self.is_port_free(port, sock_type):
+ self._filelocks[port] = filelock
+ return True
+ else:
+ filelock.release()
+ return False
+
+ if self.is_port_free(port, sock_type):
+ self._filelocks[port] = filelock
+ return True
+ if filelock:
+ filelock.release()
+ return False
+
+ def _no_random_ports(self):
+ return os.environ.get("NO_RANDOM_PORTS")
+
+
+def get_valid_port_range():
+ first_valid = 1025
+ last_valid = UI16MAXVAL
+
+ given_range = os.environ.get('VALID_PORT_RANGE')
+ if given_range and ':' in given_range:
+ return [list(int(x) for x in given_range.split(':', 2))]
+
+ first_eph, last_eph = get_ephemeral_range()
+ first_invalid = max(first_eph, first_valid)
+ last_invalid = min(last_eph, last_valid)
+
+ ranges = []
+ if first_invalid > first_valid:
+ ranges.append((first_valid, first_invalid - 1))
+ if last_invalid < last_valid:
+ ranges.append((last_invalid + 1, last_valid))
+ return ranges
+
+
+def get_ephemeral_range():
+ if platform.system() == 'Linux':
+ filename = "/proc/sys/net/ipv4/ip_local_port_range"
+ if os.path.exists(filename):
+ with open(filename) as afile:
+ data = afile.read(1024) # fix for musl
+ port_range = tuple(map(int, data.strip().split()))
+ if len(port_range) == 2:
+ return port_range
+ else:
+ logger.warning("Bad ip_local_port_range format: '%s'. Going to use IANA suggestion", data)
+ elif platform.system() == 'Darwin':
+ first = _sysctlbyname_uint("net.inet.ip.portrange.first")
+ last = _sysctlbyname_uint("net.inet.ip.portrange.last")
+ if first and last:
+ return first, last
+ # IANA suggestion
+ return (1 << 15) + (1 << 14), UI16MAXVAL
+
+
+def _sysctlbyname_uint(name):
+ try:
+ from ctypes import CDLL, c_uint, byref
+ from ctypes.util import find_library
+ except ImportError:
+ return
+
+ libc = CDLL(find_library("c"))
+ size = c_uint(0)
+ res = c_uint(0)
+ libc.sysctlbyname(name, None, byref(size), None, 0)
+ libc.sysctlbyname(name, byref(res), byref(size), None, 0)
+ return res.value
+
+
+def _makedirs(path):
+ try:
+ os.makedirs(path)
+ except OSError as e:
+ if e.errno == errno.EEXIST:
+ return
+ raise
diff --git a/library/python/testing/yatest_common/yatest/common/path.py b/library/python/testing/yatest_common/yatest/common/path.py
new file mode 100644
index 0000000000..6fed7dda8a
--- /dev/null
+++ b/library/python/testing/yatest_common/yatest/common/path.py
@@ -0,0 +1,90 @@
+# coding=utf-8
+
+import errno
+import os
+import shutil
+import contextlib
+
+import library.python.fs as lpf
+
+
+def replace_in_file(path, old, new):
+ """
+ Replace text occurrences in a file
+ :param path: path to the file
+ :param old: text to replace
+ :param new: replacement
+ """
+ with open(path) as fp:
+ content = fp.read()
+
+ lpf.ensure_removed(path)
+ with open(path, 'w') as fp:
+ fp.write(content.replace(old, new))
+
+
+@contextlib.contextmanager
+def change_dir(path):
+ old = os.getcwd()
+ try:
+ os.chdir(path)
+ yield path
+ finally:
+ os.chdir(old)
+
+
+def copytree(src, dst, symlinks=False, ignore=None, postprocessing=None):
+ '''
+ Copy an entire directory of files into an existing directory
+ instead of raising Exception what shtuil.copytree does
+ '''
+ if not os.path.exists(dst) and os.path.isdir(src):
+ os.makedirs(dst)
+ for item in os.listdir(src):
+ s = os.path.join(src, item)
+ d = os.path.join(dst, item)
+ if os.path.isdir(s):
+ shutil.copytree(s, d, symlinks, ignore)
+ else:
+ shutil.copy2(s, d)
+ if postprocessing:
+ postprocessing(dst, False)
+ for root, dirs, files in os.walk(dst):
+ for path in dirs:
+ postprocessing(os.path.join(root, path), False)
+ for path in files:
+ postprocessing(os.path.join(root, path), True)
+
+
+def get_unique_file_path(dir_path, file_pattern, create_file=True, max_suffix=10000):
+ def atomic_file_create(path):
+ try:
+ fd = os.open(path, os.O_CREAT | os.O_EXCL, 0o644)
+ os.close(fd)
+ return True
+ except OSError as e:
+ if e.errno in [errno.EEXIST, errno.EISDIR, errno.ETXTBSY]:
+ return False
+ # Access issue with file itself, not parent directory.
+ if e.errno == errno.EACCES and os.path.exists(path):
+ return False
+ raise e
+
+ def atomic_dir_create(path):
+ try:
+ os.mkdir(path)
+ return True
+ except OSError as e:
+ if e.errno == errno.EEXIST:
+ return False
+ raise e
+
+ file_path = os.path.join(dir_path, file_pattern)
+ lpf.ensure_dir(os.path.dirname(file_path))
+ file_counter = 0
+ handler = atomic_file_create if create_file else atomic_dir_create
+ while os.path.exists(file_path) or not handler(file_path):
+ file_path = os.path.join(dir_path, file_pattern + ".{}".format(file_counter))
+ file_counter += 1
+ assert file_counter < max_suffix
+ return file_path
diff --git a/library/python/testing/yatest_common/yatest/common/process.py b/library/python/testing/yatest_common/yatest/common/process.py
new file mode 100644
index 0000000000..a8bcc21f51
--- /dev/null
+++ b/library/python/testing/yatest_common/yatest/common/process.py
@@ -0,0 +1,733 @@
+# coding: utf-8
+
+import os
+import re
+import time
+import signal
+import shutil
+import logging
+import tempfile
+import subprocess
+import errno
+import distutils.version
+
+import six
+
+try:
+ # yatest.common should try to be hermetic, otherwise, PYTEST_SCRIPT (aka USE_ARCADIA_PYTHON=no) won't work.
+ import library.python.cores as cores
+except ImportError:
+ cores = None
+
+from . import runtime
+from . import path
+from . import environment
+
+
+MAX_OUT_LEN = 1000 * 1000 # 1 mb
+MAX_MESSAGE_LEN = 1500
+SANITIZER_ERROR_PATTERN = br": ([A-Z][\w]+Sanitizer)"
+GLIBC_PATTERN = re.compile(r"\S+@GLIBC_([0-9.]+)")
+yatest_logger = logging.getLogger("ya.test")
+
+
+def truncate(s, size):
+ if s is None:
+ return None
+ elif len(s) <= size:
+ return s
+ else:
+ return (b'...' if isinstance(s, bytes) else '...') + s[-(size - 3):]
+
+
+def get_command_name(command):
+ return os.path.basename(command.split()[0] if isinstance(command, six.string_types) else command[0])
+
+
+class ExecutionError(Exception):
+
+ def __init__(self, execution_result):
+ if not isinstance(execution_result.command, six.string_types):
+ command = " ".join(str(arg) for arg in execution_result.command)
+ else:
+ command = execution_result.command
+ message = "Command '{command}' has failed with code {code}.\nErrors:\n{err}\n".format(
+ command=command,
+ code=execution_result.exit_code,
+ err=_format_error(execution_result.std_err))
+ if cores:
+ if execution_result.backtrace:
+ message += "Backtrace:\n[[rst]]{}[[bad]]\n".format(cores.colorize_backtrace(execution_result._backtrace))
+ else:
+ message += "Backtrace is not available: module cores isn't available"
+
+ super(ExecutionError, self).__init__(message)
+ self.execution_result = execution_result
+
+
+class TimeoutError(Exception):
+ pass
+
+
+class ExecutionTimeoutError(TimeoutError):
+ def __init__(self, execution_result, *args, **kwargs):
+ super(ExecutionTimeoutError, self).__init__(args, kwargs)
+ self.execution_result = execution_result
+
+
+class InvalidExecutionStateError(Exception):
+ pass
+
+
+class SignalInterruptionError(Exception):
+ def __init__(self, message=None):
+ super(SignalInterruptionError, self).__init__(message)
+ self.res = None
+
+
+class InvalidCommandError(Exception):
+ pass
+
+
+class _Execution(object):
+
+ def __init__(self, command, process, out_file, err_file, process_progress_listener=None, cwd=None, collect_cores=True, check_sanitizer=True, started=0, user_stdout=False, user_stderr=False):
+ self._command = command
+ self._process = process
+ self._out_file = out_file
+ self._err_file = err_file
+ self._std_out = None
+ self._std_err = None
+ self._elapsed = None
+ self._start = time.time()
+ self._process_progress_listener = process_progress_listener
+ self._cwd = cwd or os.getcwd()
+ self._collect_cores = collect_cores
+ self._backtrace = ''
+ self._check_sanitizer = check_sanitizer
+ self._metrics = {}
+ self._started = started
+ self._user_stdout = bool(user_stdout)
+ self._user_stderr = bool(user_stderr)
+ self._exit_code = None
+ if process_progress_listener:
+ process_progress_listener.open(command, process, out_file, err_file)
+
+ @property
+ def running(self):
+ return self._process.poll() is None
+
+ def kill(self):
+ if self.running:
+ self._save_outputs(False)
+ _kill_process_tree(self._process.pid)
+ self._clean_files()
+ # DEVTOOLS-2347
+ yatest_logger.debug("Process status before wait_for: %s", self.running)
+ try:
+ wait_for(lambda: not self.running, timeout=5, fail_message="Could not kill process {}".format(self._process.pid), sleep_time=.1)
+ except TimeoutError:
+ yatest_logger.debug("Process status after wait_for: %s", self.running)
+ yatest_logger.debug("Process %d info: %s", self._process.pid, _get_proc_tree_info([self._process.pid]))
+ raise
+ else:
+ raise InvalidExecutionStateError("Cannot kill a stopped process")
+
+ def terminate(self):
+ if self.running:
+ self._process.terminate()
+
+ @property
+ def process(self):
+ return self._process
+
+ @property
+ def command(self):
+ return self._command
+
+ @property
+ def returncode(self):
+ return self.exit_code
+
+ @property
+ def exit_code(self):
+ """
+ Deprecated, use returncode
+ """
+ if self._exit_code is None:
+ self._exit_code = self._process.returncode
+ return self._exit_code
+
+ @property
+ def stdout(self):
+ return self.std_out
+
+ @property
+ def std_out(self):
+ """
+ Deprecated, use stdout
+ """
+ if self._std_out is not None:
+ return self._std_out
+ if self._process.stdout and not self._user_stdout:
+ self._std_out = self._process.stdout.read()
+ return self._std_out
+
+ @property
+ def stderr(self):
+ return self.std_err
+
+ @property
+ def std_err(self):
+ """
+ Deprecated, use stderr
+ """
+ if self._std_err is not None:
+ return self._std_err
+ if self._process.stderr and not self._user_stderr:
+ self._std_err = self._process.stderr.read()
+ return self._std_err
+
+ @property
+ def elapsed(self):
+ return self._elapsed
+
+ @property
+ def backtrace(self):
+ return self._backtrace
+
+ @property
+ def metrics(self):
+ return self._metrics
+
+ def _save_outputs(self, clean_files=True):
+ if self._process_progress_listener:
+ self._process_progress_listener()
+ self._process_progress_listener.close()
+ if not self._user_stdout:
+ if self._out_file is None:
+ pass
+ elif self._out_file != subprocess.PIPE:
+ self._out_file.flush()
+ self._out_file.seek(0, os.SEEK_SET)
+ self._std_out = self._out_file.read()
+ else:
+ self._std_out = self._process.stdout.read()
+ if not self._user_stderr:
+ if self._err_file is None:
+ pass
+ elif self._err_file != subprocess.PIPE:
+ self._err_file.flush()
+ self._err_file.seek(0, os.SEEK_SET)
+ self._std_err = self._err_file.read()
+ else:
+ self._std_err = self._process.stderr.read()
+
+ if clean_files:
+ self._clean_files()
+ yatest_logger.debug("Command (pid %s) rc: %s", self._process.pid, self.exit_code)
+ yatest_logger.debug("Command (pid %s) elapsed time (sec): %s", self._process.pid, self.elapsed)
+ if self._metrics:
+ for key, value in six.iteritems(self._metrics):
+ yatest_logger.debug("Command (pid %s) %s: %s", self._process.pid, key, value)
+
+ # Since this code is Python2/3 compatible, we don't know is _std_out/_std_err is real bytes or bytes-str.
+ printable_std_out, err = _try_convert_bytes_to_string(self._std_out)
+ if err:
+ yatest_logger.debug("Got error during parse process stdout: %s", err)
+ yatest_logger.debug("stdout will be displayed as raw bytes.")
+ printable_std_err, err = _try_convert_bytes_to_string(self._std_err)
+ if err:
+ yatest_logger.debug("Got error during parse process stderr: %s", err)
+ yatest_logger.debug("stderr will be displayed as raw bytes.")
+
+ yatest_logger.debug("Command (pid %s) output:\n%s", self._process.pid, truncate(printable_std_out, MAX_OUT_LEN))
+ yatest_logger.debug("Command (pid %s) errors:\n%s", self._process.pid, truncate(printable_std_err, MAX_OUT_LEN))
+
+ def _clean_files(self):
+ if self._err_file and not self._user_stderr and self._err_file != subprocess.PIPE:
+ self._err_file.close()
+ self._err_file = None
+ if self._out_file and not self._user_stdout and self._out_file != subprocess.PIPE:
+ self._out_file.close()
+ self._out_file = None
+
+ def _recover_core(self):
+ core_path = cores.recover_core_dump_file(self.command[0], self._cwd, self.process.pid)
+ if core_path:
+ # Core dump file recovering may be disabled (for distbuild for example) - produce only bt
+ store_cores = runtime._get_ya_config().collect_cores
+ if store_cores:
+ new_core_path = path.get_unique_file_path(runtime.output_path(), "{}.{}.core".format(os.path.basename(self.command[0]), self._process.pid))
+ # Copy core dump file, because it may be overwritten
+ yatest_logger.debug("Coping core dump file from '%s' to the '%s'", core_path, new_core_path)
+ shutil.copyfile(core_path, new_core_path)
+ core_path = new_core_path
+
+ bt_filename = None
+ pbt_filename = None
+
+ if os.path.exists(runtime.gdb_path()):
+ self._backtrace = cores.get_gdb_full_backtrace(self.command[0], core_path, runtime.gdb_path())
+ bt_filename = path.get_unique_file_path(runtime.output_path(), "{}.{}.backtrace".format(os.path.basename(self.command[0]), self._process.pid))
+ with open(bt_filename, "wb") as afile:
+ afile.write(six.ensure_binary(self._backtrace))
+ # generate pretty html version of backtrace aka Tri Korochki
+ pbt_filename = bt_filename + ".html"
+ backtrace_to_html(bt_filename, pbt_filename)
+
+ if store_cores:
+ runtime._register_core(os.path.basename(self.command[0]), self.command[0], core_path, bt_filename, pbt_filename)
+ else:
+ runtime._register_core(os.path.basename(self.command[0]), None, None, bt_filename, pbt_filename)
+
+ def wait(self, check_exit_code=True, timeout=None, on_timeout=None):
+ def _wait():
+ finished = None
+ interrupted = False
+ try:
+ if hasattr(os, "wait4"):
+ try:
+ if hasattr(subprocess, "_eintr_retry_call"):
+ pid, sts, rusage = subprocess._eintr_retry_call(os.wait4, self._process.pid, 0)
+ else:
+ # PEP 475
+ pid, sts, rusage = os.wait4(self._process.pid, 0)
+ finished = time.time()
+ self._process._handle_exitstatus(sts)
+ for field in [
+ "ru_idrss",
+ "ru_inblock",
+ "ru_isrss",
+ "ru_ixrss",
+ "ru_majflt",
+ "ru_maxrss",
+ "ru_minflt",
+ "ru_msgrcv",
+ "ru_msgsnd",
+ "ru_nivcsw",
+ "ru_nsignals",
+ "ru_nswap",
+ "ru_nvcsw",
+ "ru_oublock",
+ "ru_stime",
+ "ru_utime",
+ ]:
+ if hasattr(rusage, field):
+ self._metrics[field.replace("ru_", "")] = getattr(rusage, field)
+ except OSError as exc:
+
+ if exc.errno == errno.ECHILD:
+ yatest_logger.debug("Process resource usage is not available as process finished before wait4 was called")
+ else:
+ raise
+ except SignalInterruptionError:
+ interrupted = True
+ raise
+ finally:
+ if not interrupted:
+ self._process.wait() # this has to be here unconditionally, so that all process properties are set
+
+ if not finished:
+ finished = time.time()
+ self._metrics["wtime"] = round(finished - self._started, 3)
+
+ try:
+ if timeout:
+ process_is_finished = lambda: not self.running
+ fail_message = "Command '%s' stopped by %d seconds timeout" % (self._command, timeout)
+ try:
+ wait_for(process_is_finished, timeout, fail_message, sleep_time=0.1, on_check_condition=self._process_progress_listener)
+ except TimeoutError as e:
+ if on_timeout:
+ yatest_logger.debug("Calling user specified on_timeout function")
+ try:
+ on_timeout(self, timeout)
+ except Exception:
+ yatest_logger.exception("Exception while calling on_timeout")
+ raise ExecutionTimeoutError(self, str(e))
+ # Wait should be always called here, it finalizes internal states of its process and sets up return code
+ _wait()
+ except BaseException as e:
+ _kill_process_tree(self._process.pid)
+ _wait()
+ yatest_logger.debug("Command exception: %s", e)
+ raise
+ finally:
+ self._elapsed = time.time() - self._start
+ self._save_outputs()
+ self.verify_no_coredumps()
+
+ self._finalise(check_exit_code)
+
+ def _finalise(self, check_exit_code):
+ # Set the signal (negative number) which caused the process to exit
+ if check_exit_code and self.exit_code != 0:
+ yatest_logger.error("Execution failed with exit code: %s\n\t,std_out:%s\n\tstd_err:%s\n",
+ self.exit_code, truncate(self.std_out, MAX_OUT_LEN), truncate(self.std_err, MAX_OUT_LEN))
+ raise ExecutionError(self)
+
+ # Don't search for sanitize errors if stderr was redirected
+ self.verify_sanitize_errors()
+
+ def verify_no_coredumps(self):
+ """
+ Verify there is no coredump from this binary. If there is then report backtrace.
+ """
+ if self.exit_code < 0 and self._collect_cores:
+ if cores:
+ try:
+ self._recover_core()
+ except Exception:
+ yatest_logger.exception("Exception while recovering core")
+ else:
+ yatest_logger.warning("Core dump file recovering is skipped: module cores isn't available")
+
+ def verify_sanitize_errors(self):
+ """
+ Verify there are no sanitizer (ASAN, MSAN, TSAN, etc) errors for this binary. If there are any report them.
+ """
+ if self._std_err and self._check_sanitizer and runtime._get_ya_config().sanitizer_extra_checks:
+ build_path = runtime.build_path()
+ if self.command[0].startswith(build_path):
+ match = re.search(SANITIZER_ERROR_PATTERN, self._std_err)
+ if match:
+ yatest_logger.error("%s sanitizer found errors:\n\tstd_err:%s\n", match.group(1), truncate(self.std_err, MAX_OUT_LEN))
+ raise ExecutionError(self)
+ else:
+ yatest_logger.debug("No sanitizer errors found")
+ else:
+ yatest_logger.debug("'%s' doesn't belong to '%s' - no check for sanitize errors", self.command[0], build_path)
+
+
+def on_timeout_gen_coredump(exec_obj, _):
+ """
+ Function can be passed to the execute(..., timeout=X, on_timeout=on_timeout_gen_coredump)
+ to generate core dump file, backtrace ahd html-version of the backtrace in case of timeout.
+ All files will be available in the testing_out_stuff and via links.
+ """
+ try:
+ os.kill(exec_obj.process.pid, signal.SIGQUIT)
+ except OSError:
+ # process might be already terminated
+ pass
+
+
+def execute(
+ command, check_exit_code=True,
+ shell=False, timeout=None,
+ cwd=None, env=None,
+ stdin=None, stdout=None, stderr=None,
+ creationflags=0, wait=True,
+ process_progress_listener=None, close_fds=False,
+ collect_cores=True, check_sanitizer=True, preexec_fn=None, on_timeout=None,
+ executor=_Execution,
+):
+ """
+ Executes a command
+ :param command: command: can be a list of arguments or a string
+ :param check_exit_code: will raise ExecutionError if the command exits with non zero code
+ :param shell: use shell to run the command
+ :param timeout: execution timeout
+ :param cwd: working directory
+ :param env: command environment
+ :param stdin: command stdin
+ :param stdout: command stdout
+ :param stderr: command stderr
+ :param creationflags: command creation flags
+ :param wait: should wait until the command finishes
+ :param process_progress_listener=object that is polled while execution is in progress
+ :param close_fds: subrpocess.Popen close_fds args
+ :param collect_cores: recover core dump files if shell == False
+ :param check_sanitizer: raise ExecutionError if stderr contains sanitize errors
+ :param preexec_fn: subrpocess.Popen preexec_fn arg
+ :param on_timeout: on_timeout(<execution object>, <timeout value>) callback
+
+ :return _Execution: Execution object
+ """
+ if env is None:
+ env = os.environ.copy()
+ else:
+ # Certain environment variables must be present for programs to work properly.
+ # For more info see DEVTOOLSSUPPORT-4907
+ mandatory_env_name = 'YA_MANDATORY_ENV_VARS'
+ mandatory_vars = env.get(mandatory_env_name, os.environ.get(mandatory_env_name)) or ''
+ if mandatory_vars:
+ env[mandatory_env_name] = mandatory_vars
+ mandatory_system_vars = filter(None, mandatory_vars.split(':'))
+ else:
+ mandatory_system_vars = ['TMPDIR']
+
+ for var in mandatory_system_vars:
+ if var not in env and var in os.environ:
+ env[var] = os.environ[var]
+
+ if not wait and timeout is not None:
+ raise ValueError("Incompatible arguments 'timeout' and wait=False")
+
+ # if subprocess.PIPE in [stdout, stderr]:
+ # raise ValueError("Don't use pipe to obtain stream data - it may leads to the deadlock")
+
+ def get_out_stream(stream, default_name):
+ if stream is None:
+ # No stream is supplied: open new temp file
+ return _get_command_output_file(command, default_name), False
+
+ if isinstance(stream, six.string_types):
+ # User filename is supplied: open file for writing
+ return open(stream, 'wb+'), stream.startswith('/dev/')
+
+ # Open file or PIPE sentinel is supplied
+ is_pipe = stream == subprocess.PIPE
+ return stream, not is_pipe
+
+ # to be able to have stdout/stderr and track the process time execution, we don't use subprocess.PIPE,
+ # as it can cause processes hangs, but use tempfiles instead
+ out_file, user_stdout = get_out_stream(stdout, 'out')
+ err_file, user_stderr = get_out_stream(stderr, 'err')
+ in_file = stdin
+
+ if shell and type(command) == list:
+ command = " ".join(command)
+
+ if shell:
+ collect_cores = False
+ check_sanitizer = False
+ else:
+ if isinstance(command, (list, tuple)):
+ executable = command[0]
+ else:
+ executable = command
+ if os.path.isabs(executable):
+ if not os.path.isfile(executable) and not os.path.isfile(executable + ".exe"):
+ exists = os.path.exists(executable)
+ if exists:
+ stat = os.stat(executable)
+ else:
+ stat = None
+ raise InvalidCommandError("Target program is not a file: {} (exists: {} stat: {})".format(executable, exists, stat))
+ if not os.access(executable, os.X_OK) and not os.access(executable + ".exe", os.X_OK):
+ raise InvalidCommandError("Target program is not executable: {}".format(executable))
+
+ if check_sanitizer:
+ env["LSAN_OPTIONS"] = environment.extend_env_var(os.environ, "LSAN_OPTIONS", "exitcode=100")
+
+ if stdin:
+ name = "PIPE" if stdin == subprocess.PIPE else stdin.name
+ yatest_logger.debug("Executing '%s' with input '%s' in '%s'", command, name, cwd)
+ else:
+ yatest_logger.debug("Executing '%s' in '%s'", command, cwd)
+ # XXX
+
+ started = time.time()
+ process = subprocess.Popen(
+ command, shell=shell, universal_newlines=True,
+ stdout=out_file, stderr=err_file, stdin=in_file,
+ cwd=cwd, env=env, creationflags=creationflags, close_fds=close_fds, preexec_fn=preexec_fn,
+ )
+ yatest_logger.debug("Command pid: %s", process.pid)
+
+ res = executor(command, process, out_file, err_file, process_progress_listener, cwd, collect_cores, check_sanitizer, started, user_stdout=user_stdout, user_stderr=user_stderr)
+ if wait:
+ res.wait(check_exit_code, timeout, on_timeout)
+ return res
+
+
+def _get_command_output_file(cmd, ext):
+ parts = [get_command_name(cmd)]
+ if 'YA_RETRY_INDEX' in os.environ:
+ parts.append('retry{}'.format(os.environ.get('YA_RETRY_INDEX')))
+ if int(os.environ.get('YA_SPLIT_COUNT', '0')) > 1:
+ parts.append('chunk{}'.format(os.environ.get('YA_SPLIT_INDEX', '0')))
+
+ filename = '.'.join(parts + [ext])
+ try:
+ # if execution is performed from test, save out / err to the test logs dir
+ import yatest.common
+ import library.python.pytest.plugins.ya
+ if getattr(library.python.pytest.plugins.ya, 'pytest_config', None) is None:
+ raise ImportError("not in test")
+ filename = path.get_unique_file_path(yatest.common.output_path(), filename)
+ yatest_logger.debug("Command %s will be placed to %s", ext, os.path.basename(filename))
+ return open(filename, "wb+")
+ except ImportError:
+ return tempfile.NamedTemporaryFile(delete=False, suffix=filename)
+
+
+def _get_proc_tree_info(pids):
+ if os.name == 'nt':
+ return 'Not supported'
+ else:
+ stdout, _ = subprocess.Popen(["/bin/ps", "-wufp"] + [str(p) for p in pids], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+ return stdout
+
+
+def py_execute(
+ command, check_exit_code=True,
+ shell=False, timeout=None,
+ cwd=None, env=None,
+ stdin=None, stdout=None, stderr=None,
+ creationflags=0, wait=True,
+ process_progress_listener=None, close_fds=False
+):
+ """
+ Executes a command with the arcadia python
+ :param command: command to pass to python
+ :param check_exit_code: will raise ExecutionError if the command exits with non zero code
+ :param shell: use shell to run the command
+ :param timeout: execution timeout
+ :param cwd: working directory
+ :param env: command environment
+ :param stdin: command stdin
+ :param stdout: command stdout
+ :param stderr: command stderr
+ :param creationflags: command creation flags
+ :param wait: should wait until the command finishes
+ :param process_progress_listener=object that is polled while execution is in progress
+ :return _Execution: Execution object
+ """
+ if isinstance(command, six.string_types):
+ command = [command]
+ command = [runtime.python_path()] + command
+ if shell:
+ command = " ".join(command)
+ return execute(**locals())
+
+
+def _format_error(error):
+ return truncate(error, MAX_MESSAGE_LEN)
+
+
+def wait_for(check_function, timeout, fail_message="", sleep_time=1.0, on_check_condition=None):
+ """
+ Tries to execute `check_function` for `timeout` seconds.
+ Continue until function returns nonfalse value.
+ If function doesn't return nonfalse value for `timeout` seconds
+ OperationTimeoutException is raised.
+ Return first nonfalse result returned by `checkFunction`.
+ """
+ if sleep_time <= 0:
+ raise ValueError("Incorrect sleep time value {}".format(sleep_time))
+ if timeout < 0:
+ raise ValueError("Incorrect timeout value {}".format(timeout))
+ start = time.time()
+ while start + timeout > time.time():
+ if on_check_condition:
+ on_check_condition()
+
+ res = check_function()
+ if res:
+ return res
+ time.sleep(sleep_time)
+
+ message = "{} second(s) wait timeout has expired".format(timeout)
+ if fail_message:
+ message += ": {}".format(fail_message)
+ raise TimeoutError(truncate(message, MAX_MESSAGE_LEN))
+
+
+def _kill_process_tree(process_pid, target_pid_signal=None):
+ """
+ Kills child processes, req. Note that psutil should be installed
+ @param process_pid: parent id to search for descendants
+ """
+ yatest_logger.debug("Killing process %s", process_pid)
+ if os.name == 'nt':
+ _win_kill_process_tree(process_pid)
+ else:
+ _nix_kill_process_tree(process_pid, target_pid_signal)
+
+
+def _nix_get_proc_children(pid):
+ try:
+ cmd = ["pgrep", "-P", str(pid)]
+ return [int(p) for p in subprocess.check_output(cmd).split()]
+ except Exception:
+ return []
+
+
+def _get_binname(pid):
+ try:
+ return os.path.basename(os.readlink('/proc/{}/exe'.format(pid)))
+ except Exception as e:
+ return "error({})".format(e)
+
+
+def _nix_kill_process_tree(pid, target_pid_signal=None):
+ """
+ Kills the process tree.
+ """
+ yatest_logger.debug("Killing process tree for pid {} (bin:'{}')".format(pid, _get_binname(pid)))
+
+ def try_to_send_signal(pid, sig):
+ try:
+ os.kill(pid, sig)
+ yatest_logger.debug("Sent signal %d to the pid %d", sig, pid)
+ except Exception as exc:
+ yatest_logger.debug("Error while sending signal {sig} to pid {pid}: {error}".format(sig=sig, pid=pid, error=str(exc)))
+
+ try_to_send_signal(pid, signal.SIGSTOP) # Stop the process to prevent it from starting any child processes.
+
+ # Get the child process PID list.
+ child_pids = _nix_get_proc_children(pid)
+ # Stop the child processes.
+ for child_pid in child_pids:
+ try:
+ # Kill the child recursively.
+ _kill_process_tree(int(child_pid))
+ except Exception as e:
+ # Skip the error and continue killing.
+ yatest_logger.debug("Killing child pid {pid} failed: {error}".format(pid=child_pid, error=e))
+ continue
+
+ try_to_send_signal(pid, target_pid_signal or signal.SIGKILL) # Kill the root process.
+
+ # sometimes on freebsd sigkill cannot kill the process and either sigkill or sigcont should be sent
+ # https://www.mail-archive.com/freebsd-hackers@freebsd.org/msg159646.html
+ try_to_send_signal(pid, signal.SIGCONT)
+
+
+def _win_kill_process_tree(pid):
+ subprocess.call(['taskkill', '/F', '/T', '/PID', str(pid)])
+
+
+def _run_readelf(binary_path):
+ return str(subprocess.check_output([runtime.binary_path('contrib/python/pyelftools/readelf/readelf'), '-s', runtime.binary_path(binary_path)]))
+
+
+def check_glibc_version(binary_path):
+ lucid_glibc_version = distutils.version.LooseVersion("2.11")
+
+ for l in _run_readelf(binary_path).split('\n'):
+ match = GLIBC_PATTERN.search(l)
+ if not match:
+ continue
+ assert distutils.version.LooseVersion(match.group(1)) <= lucid_glibc_version, match.group(0)
+
+
+def backtrace_to_html(bt_filename, output):
+ try:
+ from library.python import coredump_filter
+ with open(output, "wb") as afile:
+ coredump_filter.filter_stackdump(bt_filename, stream=afile)
+ except ImportError as e:
+ yatest_logger.debug("Failed to import coredump_filter: %s", e)
+ with open(output, "wb") as afile:
+ afile.write("<html>Failed to import coredump_filter in USE_ARCADIA_PYTHON=no mode</html>")
+
+
+def _try_convert_bytes_to_string(source):
+ """ Function is necessary while this code Python2/3 compatible, because bytes in Python3 is a real bytes and in Python2 is not """
+ # Bit ugly typecheck, because in Python2 isinstance(str(), bytes) and "type(str()) is bytes" working as True as well
+ if 'bytes' not in str(type(source)):
+ # We already got not bytes. Nothing to do here.
+ return source, False
+
+ result = source
+ error = False
+ try:
+ result = source.decode(encoding='utf-8')
+ except ValueError as e:
+ error = e
+
+ return result, error
diff --git a/library/python/testing/yatest_common/yatest/common/runtime.py b/library/python/testing/yatest_common/yatest/common/runtime.py
new file mode 100644
index 0000000000..e55e193446
--- /dev/null
+++ b/library/python/testing/yatest_common/yatest/common/runtime.py
@@ -0,0 +1,343 @@
+import errno
+import functools
+import json
+import os
+import threading
+
+import six
+
+
+_lock = threading.Lock()
+
+
+def _get_ya_config():
+ try:
+ import library.python.pytest.plugins.ya as ya_plugin
+ if ya_plugin.pytest_config is not None:
+ return ya_plugin.pytest_config
+ import pytest
+ return pytest.config
+ except (ImportError, AttributeError):
+ try:
+ import library.python.testing.recipe
+ if library.python.testing.recipe.ya:
+ return library.python.testing.recipe
+ except (ImportError, AttributeError):
+ pass
+ raise NotImplementedError("yatest.common.* is only available from the testing runtime")
+
+
+def _get_ya_plugin_instance():
+ return _get_ya_config().ya
+
+
+def _norm_path(path):
+ if path is None:
+ return None
+ assert isinstance(path, six.string_types)
+ if "\\" in path:
+ raise AssertionError("path {} contains Windows seprators \\ - replace them with '/'".format(path))
+ return os.path.normpath(path)
+
+
+def _join_path(main_path, path):
+ if not path:
+ return main_path
+ return os.path.join(main_path, _norm_path(path))
+
+
+def not_test(func):
+ """
+ Mark any function as not a test for py.test
+ :param func:
+ :return:
+ """
+ @functools.wraps(func)
+ def wrapper(*args, **kwds):
+ return func(*args, **kwds)
+ setattr(wrapper, '__test__', False)
+ return wrapper
+
+
+def source_path(path=None):
+ """
+ Get source path inside arcadia
+ :param path: path arcadia relative, e.g. yatest.common.source_path('devtools/ya')
+ :return: absolute path to the source folder
+ """
+ return _join_path(_get_ya_plugin_instance().source_root, path)
+
+
+def build_path(path=None):
+ """
+ Get path inside build directory
+ :param path: path relative to the build directory, e.g. yatest.common.build_path('devtools/ya/bin')
+ :return: absolute path inside build directory
+ """
+ return _join_path(_get_ya_plugin_instance().build_root, path)
+
+
+def java_path():
+ """
+ [DEPRECATED] Get path to java
+ :return: absolute path to java
+ """
+ from . import runtime_java
+ return runtime_java.get_java_path(binary_path(os.path.join('contrib', 'tools', 'jdk')))
+
+
+def java_home():
+ """
+ Get jdk directory path
+ """
+ from . import runtime_java
+ jdk_dir = runtime_java.get_build_java_dir(binary_path('jdk'))
+ if not jdk_dir:
+ raise Exception("Cannot find jdk - make sure 'jdk' is added to the DEPENDS section and exists for the current platform")
+ return jdk_dir
+
+
+def java_bin():
+ """
+ Get path to the java binary
+ Requires DEPENDS(jdk)
+ """
+ return os.path.join(java_home(), "bin", "java")
+
+
+def data_path(path=None):
+ """
+ Get path inside arcadia_tests_data directory
+ :param path: path relative to the arcadia_tests_data directory, e.g. yatest.common.data_path("pers/rerank_service")
+ :return: absolute path inside arcadia_tests_data
+ """
+ return _join_path(_get_ya_plugin_instance().data_root, path)
+
+
+def output_path(path=None):
+ """
+ Get path inside the current test suite output dir.
+ Placing files to this dir guarantees that files will be accessible after the test suite execution.
+ :param path: path relative to the test suite output dir
+ :return: absolute path inside the test suite output dir
+ """
+ return _join_path(_get_ya_plugin_instance().output_dir, path)
+
+
+def ram_drive_path(path=None):
+ """
+ :param path: path relative to the ram drive.
+ :return: absolute path inside the ram drive directory or None if no ram drive was provided by environment.
+ """
+ if 'YA_TEST_RAM_DRIVE_PATH' in os.environ:
+ return _join_path(os.environ['YA_TEST_RAM_DRIVE_PATH'], path)
+
+
+def output_ram_drive_path(path=None):
+ """
+ Returns path inside ram drive directory which will be saved in the testing_out_stuff directory after testing.
+ Returns None if no ram drive was provided by environment.
+ :param path: path relative to the output ram drive directory
+ """
+ if 'YA_TEST_OUTPUT_RAM_DRIVE_PATH' in os.environ:
+ return _join_path(os.environ['YA_TEST_OUTPUT_RAM_DRIVE_PATH'], path)
+
+
+def binary_path(path=None):
+ """
+ Get path to the built binary
+ :param path: path to the binary relative to the build directory e.g. yatest.common.binary_path('devtools/ya/bin/ya-bin')
+ :return: absolute path to the binary
+ """
+ path = _norm_path(path)
+ return _get_ya_plugin_instance().get_binary(path)
+
+
+def work_path(path=None):
+ """
+ Get path inside the current test suite working directory. Creating files in the work directory does not guarantee
+ that files will be accessible after the test suite execution
+ :param path: path relative to the test suite working dir
+ :return: absolute path inside the test suite working dir
+ """
+ return _join_path(
+ os.environ.get("TEST_WORK_PATH") or
+ _get_ya_plugin_instance().get_context("work_path") or
+ os.getcwd(),
+ path)
+
+
+def python_path():
+ """
+ Get path to the arcadia python.
+
+ Warn: if you are using build with system python (-DUSE_SYSTEM_PYTHON=X) beware that some python bundles
+ are built in a stripped-down form that is needed for building, not running tests.
+ See comments in the file below to find out which version of python is compatible with tests.
+ https://a.yandex-team.ru/arc/trunk/arcadia/build/platform/python/resources.inc
+ :return: absolute path to python
+ """
+ return _get_ya_plugin_instance().python_path
+
+
+def valgrind_path():
+ """
+ Get path to valgrind
+ :return: absolute path to valgrind
+ """
+ return _get_ya_plugin_instance().valgrind_path
+
+
+def get_param(key, default=None):
+ """
+ Get arbitrary parameter passed via command line
+ :param key: key
+ :param default: default value
+ :return: parameter value or the default
+ """
+ return _get_ya_plugin_instance().get_param(key, default)
+
+
+def get_param_dict_copy():
+ """
+ Return copy of dictionary with all parameters. Changes to this dictionary do *not* change parameters.
+
+ :return: copy of dictionary with all parameters
+ """
+ return _get_ya_plugin_instance().get_param_dict_copy()
+
+
+@not_test
+def test_output_path(path=None):
+ """
+ Get dir in the suite output_path for the current test case
+ """
+ test_out_dir = os.path.splitext(_get_ya_config().current_test_log_path)[0]
+ try:
+ os.makedirs(test_out_dir)
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise
+ return _join_path(test_out_dir, path)
+
+
+def project_path(path=None):
+ """
+ Get path in build root relating to build_root/project path
+ """
+ return _join_path(os.path.join(build_path(), context.project_path), path)
+
+
+def gdb_path():
+ """
+ Get path to the gdb
+ """
+ return _get_ya_plugin_instance().gdb_path
+
+
+def c_compiler_path():
+ """
+ Get path to the gdb
+ """
+ return os.environ.get("YA_CC")
+
+
+def get_yt_hdd_path(path=None):
+ if 'HDD_PATH' in os.environ:
+ return _join_path(os.environ['HDD_PATH'], path)
+
+
+def cxx_compiler_path():
+ """
+ Get path to the gdb
+ """
+ return os.environ.get("YA_CXX")
+
+
+def global_resources():
+ try:
+ return json.loads(os.environ.get("YA_GLOBAL_RESOURCES"))
+ except (TypeError, ValueError):
+ return {}
+
+
+def _register_core(name, binary_path, core_path, bt_path, pbt_path):
+ config = _get_ya_config()
+
+ with _lock:
+ if not hasattr(config, 'test_cores_count'):
+ config.test_cores_count = 0
+ config.test_cores_count += 1
+ count_str = '' if config.test_cores_count == 1 else str(config.test_cores_count)
+
+ log_entry = config.test_logs[config.current_item_nodeid]
+ if binary_path:
+ log_entry['{} binary{}'.format(name, count_str)] = binary_path
+ if core_path:
+ log_entry['{} core{}'.format(name, count_str)] = core_path
+ if bt_path:
+ log_entry['{} backtrace{}'.format(name, count_str)] = bt_path
+ if pbt_path:
+ log_entry['{} backtrace html{}'.format(name, count_str)] = pbt_path
+
+
+@not_test
+def test_source_path(path=None):
+ return _join_path(os.path.join(source_path(), context.project_path), path)
+
+
+class Context(object):
+ """
+ Runtime context
+ """
+
+ @property
+ def build_type(self):
+ return _get_ya_plugin_instance().get_context("build_type")
+
+ @property
+ def project_path(self):
+ return _get_ya_plugin_instance().get_context("project_path")
+
+ @property
+ def test_stderr(self):
+ return _get_ya_plugin_instance().get_context("test_stderr")
+
+ @property
+ def test_debug(self):
+ return _get_ya_plugin_instance().get_context("test_debug")
+
+ @property
+ def test_traceback(self):
+ return _get_ya_plugin_instance().get_context("test_traceback")
+
+ @property
+ def test_name(self):
+ return _get_ya_config().current_test_name
+
+ @property
+ def sanitize(self):
+ """
+ Detect if current test run is under sanitizer
+
+ :return: one of `None`, 'address', 'memory', 'thread', 'undefined'
+ """
+ return _get_ya_plugin_instance().get_context("sanitize")
+
+ @property
+ def flags(self):
+ _flags = _get_ya_plugin_instance().get_context("flags")
+ if _flags:
+ _flags_dict = dict()
+ for f in _flags:
+ key, value = f.split('=', 1)
+ _flags_dict[key] = value
+ return _flags_dict
+ else:
+ return dict()
+
+ def get_context_key(self, key):
+ return _get_ya_plugin_instance().get_context(key)
+
+
+context = Context()
diff --git a/library/python/testing/yatest_common/yatest/common/runtime_java.py b/library/python/testing/yatest_common/yatest/common/runtime_java.py
new file mode 100644
index 0000000000..39bbb45570
--- /dev/null
+++ b/library/python/testing/yatest_common/yatest/common/runtime_java.py
@@ -0,0 +1,46 @@
+import os
+import tarfile
+import contextlib
+
+from . import runtime
+
+_JAVA_DIR = []
+
+
+def get_java_path(jdk_dir):
+ # deprecated - to be deleted
+ java_paths = (os.path.join(jdk_dir, 'bin', 'java'), os.path.join(jdk_dir, 'bin', 'java.exe'))
+
+ for p in java_paths:
+ if os.path.exists(p):
+ return p
+
+ for f in os.listdir(jdk_dir):
+ if f.endswith('.tar'):
+ with contextlib.closing(tarfile.open(os.path.join(jdk_dir, f))) as tf:
+ tf.extractall(jdk_dir)
+
+ for p in java_paths:
+ if os.path.exists(p):
+ return p
+
+ return ''
+
+
+def get_build_java_dir(jdk_dir):
+ versions = [8, 10, 11, 12, 13, 14, 15]
+
+ if not _JAVA_DIR:
+ for version in versions:
+ jdk_tar_path = os.path.join(jdk_dir, "jdk{}.tar".format(version))
+ if os.path.exists(jdk_tar_path):
+ jdk_dir = runtime.build_path('jdk4test')
+ with contextlib.closing(tarfile.open(jdk_tar_path)) as tf:
+ tf.extractall(jdk_dir)
+ assert os.path.exists(os.path.join(jdk_dir, "bin", "java"))
+ _JAVA_DIR.append(jdk_dir)
+ break
+ else:
+ _JAVA_DIR.append(None)
+
+ return _JAVA_DIR[0]
diff --git a/library/python/testing/yatest_common/yatest/common/tags.py b/library/python/testing/yatest_common/yatest/common/tags.py
new file mode 100644
index 0000000000..9e7a74cdf5
--- /dev/null
+++ b/library/python/testing/yatest_common/yatest/common/tags.py
@@ -0,0 +1,5 @@
+try:
+ import pytest
+ ya_external = getattr(pytest.mark, "ya:external")
+except ImportError:
+ ya_external = None
diff --git a/library/python/testing/yatest_common/yatest/common/ya.make b/library/python/testing/yatest_common/yatest/common/ya.make
new file mode 100644
index 0000000000..f7c50dfe64
--- /dev/null
+++ b/library/python/testing/yatest_common/yatest/common/ya.make
@@ -0,0 +1 @@
+OWNER(g:yatest)
diff --git a/library/python/testing/yatest_lib/__init__.py b/library/python/testing/yatest_lib/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/library/python/testing/yatest_lib/__init__.py
diff --git a/library/python/testing/yatest_lib/external.py b/library/python/testing/yatest_lib/external.py
new file mode 100644
index 0000000000..39113230d9
--- /dev/null
+++ b/library/python/testing/yatest_lib/external.py
@@ -0,0 +1,192 @@
+from __future__ import absolute_import
+
+import re
+import sys
+import copy
+import logging
+
+from . import tools
+from datetime import date, datetime
+
+import enum
+import six
+
+logger = logging.getLogger(__name__)
+MDS_URI_PREFIX = 'https://storage.yandex-team.ru/get-devtools/'
+
+
+def apply(func, value, apply_to_keys=False):
+ """
+ Applies func to every possible member of value
+ :param value: could be either a primitive object or a complex one (list, dicts)
+ :param func: func to be applied
+ :return:
+ """
+ def _apply(func, value, value_path):
+ if value_path is None:
+ value_path = []
+
+ if isinstance(value, list) or isinstance(value, tuple):
+ res = []
+ for ind, item in enumerate(value):
+ path = copy.copy(value_path)
+ path.append(ind)
+ res.append(_apply(func, item, path))
+ elif isinstance(value, dict):
+ if is_external(value):
+ # this is a special serialized object pointing to some external place
+ res = func(value, value_path)
+ else:
+ res = {}
+ for key, val in sorted(value.items(), key=lambda dict_item: dict_item[0]):
+ path = copy.copy(value_path)
+ path.append(key)
+ res[_apply(func, key, path) if apply_to_keys else key] = _apply(func, val, path)
+ else:
+ res = func(value, value_path)
+ return res
+ return _apply(func, value, None)
+
+
+def is_coroutine(val):
+ if sys.version_info[0] < 3:
+ return False
+ else:
+ import asyncio
+ return asyncio.iscoroutinefunction(val) or asyncio.iscoroutine(val)
+
+
+def serialize(value):
+ """
+ Serialize value to json-convertible object
+ Ensures that all components of value can be serialized to json
+ :param value: object to be serialized
+ """
+ def _serialize(val, _):
+ if val is None:
+ return val
+ if isinstance(val, six.string_types) or isinstance(val, bytes):
+ return tools.to_utf8(val)
+ if isinstance(val, enum.Enum):
+ return str(val)
+ if isinstance(val, six.integer_types) or type(val) in [float, bool]:
+ return val
+ if is_external(val):
+ return dict(val)
+ if isinstance(val, (date, datetime)):
+ return repr(val)
+ if is_coroutine(val):
+ return None
+ raise ValueError("Cannot serialize value '{}' of type {}".format(val, type(val)))
+ return apply(_serialize, value, apply_to_keys=True)
+
+
+def is_external(value):
+ return isinstance(value, dict) and "uri" in value.keys()
+
+
+class ExternalSchema(object):
+ File = "file"
+ SandboxResource = "sbr"
+ Delayed = "delayed"
+ HTTP = "http"
+
+
+class CanonicalObject(dict):
+ def __iter__(self):
+ raise TypeError("Iterating canonical object is not implemented")
+
+
+class ExternalDataInfo(object):
+
+ def __init__(self, data):
+ assert is_external(data)
+ self._data = data
+
+ def __str__(self):
+ type_str = "File" if self.is_file else "Sandbox resource"
+ return "{}({})".format(type_str, self.path)
+
+ def __repr__(self):
+ return str(self)
+
+ @property
+ def uri(self):
+ return self._data["uri"]
+
+ @property
+ def checksum(self):
+ return self._data.get("checksum")
+
+ @property
+ def is_file(self):
+ return self.uri.startswith(ExternalSchema.File)
+
+ @property
+ def is_sandbox_resource(self):
+ return self.uri.startswith(ExternalSchema.SandboxResource)
+
+ @property
+ def is_delayed(self):
+ return self.uri.startswith(ExternalSchema.Delayed)
+
+ @property
+ def is_http(self):
+ return self.uri.startswith(ExternalSchema.HTTP)
+
+ @property
+ def path(self):
+ if self.uri.count("://") != 1:
+ logger.error("Invalid external data uri: '%s'", self.uri)
+ return self.uri
+ _, path = self.uri.split("://")
+ return path
+
+ def get_mds_key(self):
+ assert self.is_http
+ m = re.match(re.escape(MDS_URI_PREFIX) + r'(.*?)($|#)', self.uri)
+ if m:
+ return m.group(1)
+ raise AssertionError("Failed to extract mds key properly from '{}'".format(self.uri))
+
+ @property
+ def size(self):
+ return self._data.get("size")
+
+ def serialize(self):
+ return self._data
+
+ @classmethod
+ def _serialize(cls, schema, path, checksum=None, attrs=None):
+ res = CanonicalObject({"uri": "{}://{}".format(schema, path)})
+ if checksum:
+ res["checksum"] = checksum
+ if attrs:
+ res.update(attrs)
+ return res
+
+ @classmethod
+ def serialize_file(cls, path, checksum=None, diff_tool=None, local=False, diff_file_name=None, diff_tool_timeout=None, size=None):
+ attrs = {}
+ if diff_tool:
+ attrs["diff_tool"] = diff_tool
+ if local:
+ attrs["local"] = local
+ if diff_file_name:
+ attrs["diff_file_name"] = diff_file_name
+ if diff_tool_timeout:
+ attrs["diff_tool_timeout"] = diff_tool_timeout
+ if size is not None:
+ attrs["size"] = size
+ return cls._serialize(ExternalSchema.File, path, checksum, attrs=attrs)
+
+ @classmethod
+ def serialize_resource(cls, id, checksum=None):
+ return cls._serialize(ExternalSchema.SandboxResource, id, checksum)
+
+ @classmethod
+ def serialize_delayed(cls, upload_id, checksum):
+ return cls._serialize(ExternalSchema.Delayed, upload_id, checksum)
+
+ def get(self, key, default=None):
+ return self._data.get(key, default)
diff --git a/library/python/testing/yatest_lib/test_splitter.py b/library/python/testing/yatest_lib/test_splitter.py
new file mode 100644
index 0000000000..acbcd4300e
--- /dev/null
+++ b/library/python/testing/yatest_lib/test_splitter.py
@@ -0,0 +1,102 @@
+# coding: utf-8
+
+import collections
+
+
+def flatten_tests(test_classes):
+ """
+ >>> test_classes = {x: [x] for x in range(5)}
+ >>> flatten_tests(test_classes)
+ [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
+ >>> test_classes = {x: [x + 1, x + 2] for x in range(2)}
+ >>> flatten_tests(test_classes)
+ [(0, 1), (0, 2), (1, 2), (1, 3)]
+ """
+ tests = []
+ for class_name, test_names in test_classes.items():
+ tests += [(class_name, test_name) for test_name in test_names]
+ return tests
+
+
+def get_sequential_chunk(tests, modulo, modulo_index, is_sorted=False):
+ """
+ >>> get_sequential_chunk(range(10), 4, 0)
+ [0, 1, 2]
+ >>> get_sequential_chunk(range(10), 4, 1)
+ [3, 4, 5]
+ >>> get_sequential_chunk(range(10), 4, 2)
+ [6, 7]
+ >>> get_sequential_chunk(range(10), 4, 3)
+ [8, 9]
+ >>> get_sequential_chunk(range(10), 4, 4)
+ []
+ >>> get_sequential_chunk(range(10), 4, 5)
+ []
+ """
+ if not is_sorted:
+ tests = sorted(tests)
+ chunk_size = len(tests) // modulo
+ not_used = len(tests) % modulo
+ shift = chunk_size + (modulo_index < not_used)
+ start = chunk_size * modulo_index + min(modulo_index, not_used)
+ end = start + shift
+ return [] if end > len(tests) else tests[start:end]
+
+
+def get_shuffled_chunk(tests, modulo, modulo_index, is_sorted=False):
+ """
+ >>> get_shuffled_chunk(range(10), 4, 0)
+ [0, 4, 8]
+ >>> get_shuffled_chunk(range(10), 4, 1)
+ [1, 5, 9]
+ >>> get_shuffled_chunk(range(10), 4, 2)
+ [2, 6]
+ >>> get_shuffled_chunk(range(10), 4, 3)
+ [3, 7]
+ >>> get_shuffled_chunk(range(10), 4, 4)
+ []
+ >>> get_shuffled_chunk(range(10), 4, 5)
+ []
+ """
+ if not is_sorted:
+ tests = sorted(tests)
+ result_tests = []
+ for i, test in enumerate(tests):
+ if i % modulo == modulo_index:
+ result_tests.append(test)
+ return result_tests
+
+
+def get_splitted_tests(test_entities, modulo, modulo_index, partition_mode, is_sorted=False):
+ if partition_mode == 'SEQUENTIAL':
+ return get_sequential_chunk(test_entities, modulo, modulo_index, is_sorted)
+ elif partition_mode == 'MODULO':
+ return get_shuffled_chunk(test_entities, modulo, modulo_index, is_sorted)
+ else:
+ raise ValueError("detected unknown partition mode: {}".format(partition_mode))
+
+
+def filter_tests_by_modulo(test_classes, modulo, modulo_index, split_by_tests, partition_mode="SEQUENTIAL"):
+ """
+ >>> test_classes = {x: [x] for x in range(20)}
+ >>> filter_tests_by_modulo(test_classes, 4, 0, False)
+ {0: [0], 1: [1], 2: [2], 3: [3], 4: [4]}
+ >>> filter_tests_by_modulo(test_classes, 4, 1, False)
+ {8: [8], 9: [9], 5: [5], 6: [6], 7: [7]}
+ >>> filter_tests_by_modulo(test_classes, 4, 2, False)
+ {10: [10], 11: [11], 12: [12], 13: [13], 14: [14]}
+
+ >>> dict(filter_tests_by_modulo(test_classes, 4, 0, True))
+ {0: [0], 1: [1], 2: [2], 3: [3], 4: [4]}
+ >>> dict(filter_tests_by_modulo(test_classes, 4, 1, True))
+ {8: [8], 9: [9], 5: [5], 6: [6], 7: [7]}
+ """
+ if split_by_tests:
+ tests = get_splitted_tests(flatten_tests(test_classes), modulo, modulo_index, partition_mode)
+ test_classes = collections.defaultdict(list)
+ for class_name, test_name in tests:
+ test_classes[class_name].append(test_name)
+ return test_classes
+ else:
+ target_classes = get_splitted_tests(test_classes, modulo, modulo_index, partition_mode)
+ return {class_name: test_classes[class_name] for class_name in target_classes}
diff --git a/library/python/testing/yatest_lib/tests/test_external.py b/library/python/testing/yatest_lib/tests/test_external.py
new file mode 100644
index 0000000000..18cb560b17
--- /dev/null
+++ b/library/python/testing/yatest_lib/tests/test_external.py
@@ -0,0 +1,20 @@
+import enum
+import pytest
+
+from yatest_lib import external
+
+
+class MyEnum(enum.Enum):
+ VAL1 = 1
+ VAL2 = 2
+
+
+@pytest.mark.parametrize("data, expected_val, expected_type", [
+ ({}, {}, dict),
+ (MyEnum.VAL1, "MyEnum.VAL1", str),
+ ({MyEnum.VAL1: MyEnum.VAL2}, {"MyEnum.VAL1": "MyEnum.VAL2"}, dict),
+])
+def test_serialize(data, expected_val, expected_type):
+ data = external.serialize(data)
+ assert expected_type == type(data), data
+ assert expected_val == data
diff --git a/library/python/testing/yatest_lib/tests/test_testsplitter.py b/library/python/testing/yatest_lib/tests/test_testsplitter.py
new file mode 100644
index 0000000000..394bfe5a74
--- /dev/null
+++ b/library/python/testing/yatest_lib/tests/test_testsplitter.py
@@ -0,0 +1,103 @@
+# coding: utf-8
+from yatest_lib import test_splitter
+
+
+def get_chunks(tests, modulo, mode):
+ chunks = []
+ if mode == "MODULO":
+ for modulo_index in range(modulo):
+ chunks.append(test_splitter.get_shuffled_chunk(tests, modulo, modulo_index))
+ elif mode == "SEQUENTIAL":
+ for modulo_index in range(modulo):
+ chunks.append(test_splitter.get_sequential_chunk(tests, modulo, modulo_index))
+ else:
+ raise ValueError("no such mode")
+ return chunks
+
+
+def check_not_intersect(chunk_list):
+ test_set = set()
+ total_size = 0
+ for tests in chunk_list:
+ total_size += len(tests)
+ test_set.update(tests)
+ return total_size == len(test_set)
+
+
+def check_max_diff(chunk_list):
+ return max(map(len, chunk_list)) - min(map(len, chunk_list))
+
+
+def test_lot_of_chunks():
+ for chunk_count in range(10, 20):
+ for tests_count in range(chunk_count):
+ chunks = get_chunks(range(tests_count), chunk_count, "SEQUENTIAL")
+ assert check_not_intersect(chunks)
+ assert check_max_diff(chunks) <= 1
+ assert chunks.count([]) == chunk_count - tests_count
+ assert len(chunks) == chunk_count
+ chunks = get_chunks(range(tests_count), chunk_count, "MODULO")
+ assert check_not_intersect(chunks)
+ assert check_max_diff(chunks) <= 1
+ assert chunks.count([]) == chunk_count - tests_count
+ assert len(chunks) == chunk_count
+
+
+def test_lot_of_tests():
+ for tests_count in range(10, 20):
+ for chunk_count in range(2, tests_count):
+ chunks = get_chunks(range(tests_count), chunk_count, "SEQUENTIAL")
+ assert check_not_intersect(chunks)
+ assert check_max_diff(chunks) <= 1
+ assert len(chunks) == chunk_count
+ chunks = get_chunks(range(tests_count), chunk_count, "MODULO")
+ assert check_not_intersect(chunks)
+ assert check_max_diff(chunks) <= 1
+ assert len(chunks) == chunk_count
+
+
+def prime_chunk_count():
+ for chunk_count in [7, 11, 13, 17, 23, 29]:
+ for tests_count in range(chunk_count):
+ chunks = get_chunks(range(tests_count), chunk_count, "SEQUENTIAL")
+ assert check_not_intersect(chunks)
+ assert check_max_diff(chunks) <= 1
+ assert len(chunks) == chunk_count
+ chunks = get_chunks(range(tests_count), chunk_count, "MODULO")
+ assert check_not_intersect(chunks)
+ assert check_max_diff(chunks) <= 1
+ assert len(chunks) == chunk_count
+
+
+def get_divisors(number):
+ divisors = []
+ for d in range(1, number + 1):
+ if number % d == 0:
+ divisors.append(d)
+ return divisors
+
+
+def equal_chunks():
+ for chunk_count in range(12, 31):
+ for tests_count in get_divisors(chunk_count):
+ chunks = get_chunks(range(tests_count), chunk_count, "SEQUENTIAL")
+ assert check_not_intersect(chunks)
+ assert check_max_diff(chunks) == 0
+ assert len(chunks) == chunk_count
+ chunks = get_chunks(range(tests_count), chunk_count, "MODULO")
+ assert check_not_intersect(chunks)
+ assert check_max_diff(chunks) == 0
+ assert len(chunks) == chunk_count
+
+
+def chunk_count_equal_tests_count():
+ for chunk_count in range(10, 20):
+ tests_count = chunk_count
+ chunks = get_chunks(range(tests_count), chunk_count, "SEQUENTIAL")
+ assert check_not_intersect(chunks)
+ assert check_max_diff(chunks) <= 1
+ assert len(chunks) == chunk_count
+ chunks = get_chunks(range(tests_count), chunk_count, "MODULO")
+ assert check_not_intersect(chunks)
+ assert check_max_diff(chunks) <= 1
+ assert len(chunks) == chunk_count
diff --git a/library/python/testing/yatest_lib/tests/ya.make b/library/python/testing/yatest_lib/tests/ya.make
new file mode 100644
index 0000000000..8586c6ef7d
--- /dev/null
+++ b/library/python/testing/yatest_lib/tests/ya.make
@@ -0,0 +1,14 @@
+OWNER(g:yatest)
+
+PY23_TEST()
+
+PEERDIR(
+ library/python/testing/yatest_lib
+)
+
+TEST_SRCS(
+ test_external.py
+ test_testsplitter.py
+)
+
+END()
diff --git a/library/python/testing/yatest_lib/tools.py b/library/python/testing/yatest_lib/tools.py
new file mode 100644
index 0000000000..b72d79c162
--- /dev/null
+++ b/library/python/testing/yatest_lib/tools.py
@@ -0,0 +1,64 @@
+import six
+import sys
+
+
+def to_utf8(value):
+ """
+ Converts value to string encoded into utf-8
+ :param value:
+ :return:
+ """
+ if sys.version_info[0] < 3:
+ if not isinstance(value, basestring): # noqa
+ value = unicode(value) # noqa
+ if type(value) == str:
+ value = value.decode("utf-8", errors="ignore")
+ return value.encode('utf-8', 'ignore')
+ else:
+ return str(value)
+
+
+def trim_string(s, max_bytes):
+ """
+ Adjusts the length of the string s in order to fit it
+ into max_bytes bytes of storage after encoding as UTF-8.
+ Useful when cutting filesystem paths.
+ :param s: unicode string
+ :param max_bytes: number of bytes
+ :return the prefix of s
+ """
+ if isinstance(s, six.text_type):
+ return _trim_unicode_string(s, max_bytes)
+
+ if isinstance(s, six.binary_type):
+ if len(s) <= max_bytes:
+ return s
+ s = s.decode('utf-8', errors='ignore')
+ s = _trim_unicode_string(s, max_bytes)
+ s = s.encode('utf-8', errors='ignore')
+ return s
+
+ raise TypeError('a string is expected')
+
+
+def _trim_unicode_string(s, max_bytes):
+ if len(s) * 4 <= max_bytes:
+ # UTF-8 uses at most 4 bytes per character
+ return s
+
+ result = []
+ cur_byte_length = 0
+
+ for ch in s:
+ cur_byte_length += len(ch.encode('utf-8'))
+ if cur_byte_length > max_bytes:
+ break
+ result.append(ch)
+
+ return ''.join(result)
+
+
+def to_str(s):
+ if six.PY2 and isinstance(s, six.text_type):
+ return s.encode('utf8')
+ return s
diff --git a/library/python/testing/yatest_lib/ya.make b/library/python/testing/yatest_lib/ya.make
new file mode 100644
index 0000000000..342bae82ba
--- /dev/null
+++ b/library/python/testing/yatest_lib/ya.make
@@ -0,0 +1,26 @@
+OWNER(g:yatest)
+
+PY23_LIBRARY()
+
+PY_SRCS(
+ NAMESPACE
+ yatest_lib
+ external.py
+ test_splitter.py
+ tools.py
+ ya.py
+)
+
+PEERDIR(
+ contrib/python/six
+)
+
+IF(PYTHON2)
+ PEERDIR(
+ contrib/python/enum34
+ )
+ENDIF()
+
+END()
+
+RECURSE_FOR_TESTS(tests)
diff --git a/library/python/testing/yatest_lib/ya.py b/library/python/testing/yatest_lib/ya.py
new file mode 100644
index 0000000000..c13b58a19f
--- /dev/null
+++ b/library/python/testing/yatest_lib/ya.py
@@ -0,0 +1,239 @@
+import os
+import sys
+import logging
+import json
+
+from .tools import to_str
+from .external import ExternalDataInfo
+
+
+TESTING_OUT_DIR_NAME = "testing_out_stuff" # XXX import from test.const
+
+yatest_logger = logging.getLogger("ya.test")
+
+
+class RunMode(object):
+ Run = "run"
+ List = "list"
+
+
+class TestMisconfigurationException(Exception):
+ pass
+
+
+class Ya(object):
+ """
+ Adds integration with ya, helps in finding dependencies
+ """
+
+ def __init__(
+ self,
+ mode=None,
+ source_root=None,
+ build_root=None,
+ dep_roots=None,
+ output_dir=None,
+ test_params=None,
+ context=None,
+ python_path=None,
+ valgrind_path=None,
+ gdb_path=None,
+ data_root=None,
+ ):
+ context_file_path = os.environ.get("YA_TEST_CONTEXT_FILE", None)
+ if context_file_path:
+ with open(context_file_path, 'r') as afile:
+ test_context = json.load(afile)
+ context_runtime = test_context["runtime"]
+ context_internal = test_context.get("internal", {})
+ context_build = test_context.get("build", {})
+ else:
+ context_runtime = {}
+ context_internal = {}
+ context_build = {}
+ self._mode = mode
+ self._build_root = to_str(context_runtime.get("build_root", "")) or build_root
+ self._source_root = to_str(context_runtime.get("source_root", "")) or source_root or self._detect_source_root()
+ self._output_dir = to_str(context_runtime.get("output_path", "")) or output_dir or self._detect_output_root()
+ if not self._output_dir:
+ raise Exception("Run ya make -t before running test binary")
+ if not self._source_root:
+ logging.warning("Source root was not set neither determined, use --source-root to set it explicitly")
+ if not self._build_root:
+ if self._source_root:
+ self._build_root = self._source_root
+ else:
+ logging.warning("Build root was not set neither determined, use --build-root to set it explicitly")
+
+ if data_root:
+ self._data_root = data_root
+ elif self._source_root:
+ self._data_root = os.path.abspath(os.path.join(self._source_root, "..", "arcadia_tests_data"))
+
+ self._dep_roots = dep_roots
+
+ self._python_path = to_str(context_runtime.get("python_bin", "")) or python_path
+ self._valgrind_path = valgrind_path
+ self._gdb_path = to_str(context_runtime.get("gdb_bin", "")) or gdb_path
+ self._test_params = {}
+ self._context = {}
+ self._test_item_node_id = None
+
+ ram_drive_path = to_str(context_runtime.get("ram_drive_path", ""))
+ if ram_drive_path:
+ self._test_params["ram_drive_path"] = ram_drive_path
+ if test_params:
+ self._test_params.update(dict(x.split('=', 1) for x in test_params))
+ self._test_params.update(context_runtime.get("test_params", {}))
+
+ self._context["project_path"] = context_runtime.get("project_path")
+ self._context["modulo"] = context_runtime.get("split_count", 1)
+ self._context["modulo_index"] = context_runtime.get("split_index", 0)
+ self._context["work_path"] = context_runtime.get("work_path")
+
+ self._context["sanitize"] = context_build.get("sanitizer")
+ self._context["ya_trace_path"] = context_internal.get("trace_file")
+
+ self._env_file = context_internal.get("env_file")
+
+ if context:
+ self._context.update(context)
+
+ @property
+ def source_root(self):
+ return self._source_root
+
+ @property
+ def data_root(self):
+ return self._data_root
+
+ @property
+ def build_root(self):
+ return self._build_root
+
+ @property
+ def dep_roots(self):
+ return self._dep_roots
+
+ @property
+ def output_dir(self):
+ return self._output_dir
+
+ @property
+ def python_path(self):
+ return self._python_path or sys.executable
+
+ @property
+ def valgrind_path(self):
+ if not self._valgrind_path:
+ raise ValueError("path to valgrind was not pass correctly, use --valgrind-path to fix it")
+ return self._valgrind_path
+
+ @property
+ def gdb_path(self):
+ return self._gdb_path
+
+ @property
+ def env_file(self):
+ return self._env_file
+
+ def get_binary(self, *path):
+ assert self._build_root, "Build root was not set neither determined, use --build-root to set it explicitly"
+ path = list(path)
+ if os.name == "nt":
+ if not path[-1].endswith(".exe"):
+ path[-1] += ".exe"
+
+ target_dirs = [self.build_root]
+ # Search for binaries within PATH dirs to be able to get path to the binaries specified by basename for exectests
+ if 'PATH' in os.environ:
+ target_dirs += os.environ['PATH'].split(':')
+
+ for target_dir in target_dirs:
+ binary_path = os.path.join(target_dir, *path)
+ if os.path.exists(binary_path):
+ yatest_logger.debug("Binary was found by %s", binary_path)
+ return binary_path
+
+ error_message = "Cannot find binary '{binary}': make sure it was added in the DEPENDS section".format(binary=path)
+ yatest_logger.debug(error_message)
+ if self._mode == RunMode.Run:
+ raise TestMisconfigurationException(error_message)
+
+ def file(self, path, diff_tool=None, local=False, diff_file_name=None, diff_tool_timeout=None):
+ return ExternalDataInfo.serialize_file(path, diff_tool=diff_tool, local=local, diff_file_name=diff_file_name, diff_tool_timeout=diff_tool_timeout)
+
+ def get_param(self, key, default=None):
+ return self._test_params.get(key, default)
+
+ def get_param_dict_copy(self):
+ return dict(self._test_params)
+
+ def get_context(self, key):
+ return self._context.get(key)
+
+ def _detect_source_root(self):
+ root = None
+ try:
+ import library.python.find_root
+ # try to determine source root from cwd
+ cwd = os.getcwd()
+ root = library.python.find_root.detect_root(cwd)
+
+ if not root:
+ # try to determine root pretending we are in the test work dir made from --keep-temps run
+ env_subdir = os.path.join("environment", "arcadia")
+ root = library.python.find_root.detect_root(cwd, detector=lambda p: os.path.exists(os.path.join(p, env_subdir)))
+ except ImportError:
+ logging.warning("Unable to import library.python.find_root")
+
+ return root
+
+ def _detect_output_root(self):
+
+ # if run from kept test working dir
+ if os.path.exists(TESTING_OUT_DIR_NAME):
+ return TESTING_OUT_DIR_NAME
+
+ # if run from source dir
+ if sys.version_info.major == 3:
+ test_results_dir = "py3test"
+ else:
+ test_results_dir = "pytest"
+
+ test_results_output_path = os.path.join("test-results", test_results_dir, TESTING_OUT_DIR_NAME)
+ if os.path.exists(test_results_output_path):
+ return test_results_output_path
+
+ if os.path.exists(os.path.dirname(test_results_output_path)):
+ os.mkdir(test_results_output_path)
+ return test_results_output_path
+
+ return None
+
+ def set_test_item_node_id(self, node_id):
+ self._test_item_node_id = node_id
+
+ def get_test_item_node_id(self):
+ assert self._test_item_node_id
+ return self._test_item_node_id
+
+ @property
+ def pytest_config(self):
+ if not hasattr(self, "_pytest_config"):
+ import library.python.pytest.plugins.ya as ya_plugin
+ self._pytest_config = ya_plugin.pytest_config
+ return self._pytest_config
+
+ def set_metric_value(self, name, val):
+ node_id = self.get_test_item_node_id()
+ if node_id not in self.pytest_config.test_metrics:
+ self.pytest_config.test_metrics[node_id] = {}
+
+ self.pytest_config.test_metrics[node_id][name] = val
+
+ def get_metric_value(self, name, default=None):
+ res = self.pytest_config.test_metrics.get(self.get_test_item_node_id(), {}).get(name)
+ if res is None:
+ return default
+ return res
diff --git a/library/python/windows/__init__.py b/library/python/windows/__init__.py
new file mode 100644
index 0000000000..62861b3309
--- /dev/null
+++ b/library/python/windows/__init__.py
@@ -0,0 +1,364 @@
+# coding: utf-8
+
+import os
+import stat
+import sys
+import shutil
+import logging
+
+from six import reraise
+
+import library.python.func
+import library.python.strings
+
+logger = logging.getLogger(__name__)
+
+
+ERRORS = {
+ 'SUCCESS': 0,
+ 'PATH_NOT_FOUND': 3,
+ 'ACCESS_DENIED': 5,
+ 'SHARING_VIOLATION': 32,
+ 'INSUFFICIENT_BUFFER': 122,
+ 'DIR_NOT_EMPTY': 145,
+}
+
+RETRIABLE_FILE_ERRORS = (ERRORS['ACCESS_DENIED'], ERRORS['SHARING_VIOLATION'])
+RETRIABLE_DIR_ERRORS = (ERRORS['ACCESS_DENIED'], ERRORS['DIR_NOT_EMPTY'], ERRORS['SHARING_VIOLATION'])
+
+
+# Check if on Windows
+@library.python.func.lazy
+def on_win():
+ return os.name == 'nt'
+
+
+class NotOnWindowsError(RuntimeError):
+ def __init__(self, message):
+ super(NotOnWindowsError, self).__init__(message)
+
+
+class DisabledOnWindowsError(RuntimeError):
+ def __init__(self, message):
+ super(DisabledOnWindowsError, self).__init__(message)
+
+
+class NoCTypesError(RuntimeError):
+ def __init__(self, message):
+ super(NoCTypesError, self).__init__(message)
+
+
+# Decorator for Windows-only functions
+def win_only(f):
+ def f_wrapped(*args, **kwargs):
+ if not on_win():
+ raise NotOnWindowsError('Windows-only function is called, but platform is not Windows')
+ return f(*args, **kwargs)
+
+ return f_wrapped
+
+
+# Decorator for functions disabled on Windows
+def win_disabled(f):
+ def f_wrapped(*args, **kwargs):
+ if on_win():
+ run_disabled()
+ return f(*args, **kwargs)
+
+ return f_wrapped
+
+
+def errorfix(f):
+ if not on_win():
+ return f
+
+ def f_wrapped(*args, **kwargs):
+ try:
+ return f(*args, **kwargs)
+ except WindowsError:
+ tp, value, tb = sys.exc_info()
+ fix_error(value)
+ reraise(tp, value, tb)
+
+ return f_wrapped
+
+
+# Decorator for diehard wrapper
+# On Windows platform retries to run function while specific WindowsError is thrown
+# On non-Windows platforms fallbacks to function itself
+def diehard(winerrors, tries=100, delay=1):
+ def wrap(f):
+ if not on_win():
+ return f
+
+ return lambda *args, **kwargs: run_diehard(f, winerrors, tries, delay, *args, **kwargs)
+
+ return wrap
+
+
+if on_win():
+ import msvcrt
+ import time
+
+ import library.python.strings
+
+ _has_ctypes = True
+ try:
+ import ctypes
+ from ctypes import wintypes
+ except ImportError:
+ _has_ctypes = False
+
+ _INVALID_HANDLE_VALUE = -1
+
+ _MOVEFILE_REPLACE_EXISTING = 0x1
+ _MOVEFILE_WRITE_THROUGH = 0x8
+
+ _SEM_FAILCRITICALERRORS = 0x1
+ _SEM_NOGPFAULTERRORBOX = 0x2
+ _SEM_NOALIGNMENTFAULTEXCEPT = 0x4
+ _SEM_NOOPENFILEERRORBOX = 0x8
+
+ _SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1
+
+ _CREATE_NO_WINDOW = 0x8000000
+
+ _ATOMIC_RENAME_FILE_TRANSACTION_DEFAULT_TIMEOUT = 1000
+
+ _HANDLE_FLAG_INHERIT = 0x1
+
+ @win_only
+ def require_ctypes(f):
+ def f_wrapped(*args, **kwargs):
+ if not _has_ctypes:
+ raise NoCTypesError('No ctypes found')
+ return f(*args, **kwargs)
+
+ return f_wrapped
+
+ # Run function in diehard mode (see diehard decorator commentary)
+ @win_only
+ def run_diehard(f, winerrors, tries, delay, *args, **kwargs):
+ if isinstance(winerrors, int):
+ winerrors = (winerrors,)
+
+ ei = None
+ for t in xrange(tries):
+ if t:
+ logger.debug('Diehard [errs %s]: try #%d in %s', ','.join(str(x) for x in winerrors), t, f)
+ try:
+ return f(*args, **kwargs)
+ except WindowsError as e:
+ if e.winerror not in winerrors:
+ raise
+ ei = sys.exc_info()
+ time.sleep(delay)
+ reraise(ei[0], ei[1], ei[2])
+
+ # Placeholder for disabled functions
+ @win_only
+ def run_disabled(*args, **kwargs):
+ raise DisabledOnWindowsError('Function called is disabled on Windows')
+
+ class CustomWinError(WindowsError):
+ def __init__(self, winerror, message='', filename=None):
+ super(CustomWinError, self).__init__(winerror, message)
+ self.message = message
+ self.strerror = self.message if self.message else format_error(self.windows_error)
+ self.filename = filename
+ self.utf8 = True
+
+ @win_only
+ def unicode_path(path):
+ return library.python.strings.to_unicode(path, library.python.strings.fs_encoding())
+
+ @win_only
+ @require_ctypes
+ def format_error(error):
+ if isinstance(error, WindowsError):
+ error = error.winerror
+ if not isinstance(error, int):
+ return 'Unknown'
+ return ctypes.FormatError(error)
+
+ @win_only
+ def fix_error(windows_error):
+ if not windows_error.strerror:
+ windows_error.strerror = format_error(windows_error)
+ transcode_error(windows_error)
+
+ @win_only
+ def transcode_error(windows_error, to_enc='utf-8'):
+ from_enc = 'utf-8' if getattr(windows_error, 'utf8', False) else library.python.strings.guess_default_encoding()
+ if from_enc != to_enc:
+ windows_error.strerror = library.python.strings.to_str(windows_error.strerror, to_enc=to_enc, from_enc=from_enc)
+ setattr(windows_error, 'utf8', to_enc == 'utf-8')
+
+ class Transaction(object):
+ def __init__(self, timeout=None, description=''):
+ self.timeout = timeout
+ self.description = description
+
+ @require_ctypes
+ def __enter__(self):
+ self._handle = ctypes.windll.ktmw32.CreateTransaction(None, 0, 0, 0, 0, self.timeout, self.description)
+ if self._handle == _INVALID_HANDLE_VALUE:
+ raise ctypes.WinError()
+ return self._handle
+
+ @require_ctypes
+ def __exit__(self, t, v, tb):
+ try:
+ if not ctypes.windll.ktmw32.CommitTransaction(self._handle):
+ raise ctypes.WinError()
+ finally:
+ ctypes.windll.kernel32.CloseHandle(self._handle)
+
+ @win_only
+ def file_handle(f):
+ return msvcrt.get_osfhandle(f.fileno())
+
+ # https://www.python.org/dev/peps/pep-0446/
+ # http://mihalop.blogspot.ru/2014/05/python-subprocess-and-file-descriptors.html
+ @require_ctypes
+ @win_only
+ def open_file(*args, **kwargs):
+ f = open(*args, **kwargs)
+ ctypes.windll.kernel32.SetHandleInformation(file_handle(f), _HANDLE_FLAG_INHERIT, 0)
+ return f
+
+ @win_only
+ @require_ctypes
+ def replace_file(src, dst):
+ if not ctypes.windll.kernel32.MoveFileExW(unicode_path(src), unicode_path(dst), _MOVEFILE_REPLACE_EXISTING | _MOVEFILE_WRITE_THROUGH):
+ raise ctypes.WinError()
+
+ @win_only
+ @require_ctypes
+ def replace_file_across_devices(src, dst):
+ with Transaction(timeout=_ATOMIC_RENAME_FILE_TRANSACTION_DEFAULT_TIMEOUT, description='ya library.python.windows replace_file_across_devices') as transaction:
+ if not ctypes.windll.kernel32.MoveFileTransactedW(unicode_path(src), unicode_path(dst), None, None, _MOVEFILE_REPLACE_EXISTING | _MOVEFILE_WRITE_THROUGH, transaction):
+ raise ctypes.WinError()
+
+ @win_only
+ @require_ctypes
+ def hardlink(src, lnk):
+ if not ctypes.windll.kernel32.CreateHardLinkW(unicode_path(lnk), unicode_path(src), None):
+ raise ctypes.WinError()
+
+ # Requires SE_CREATE_SYMBOLIC_LINK_NAME privilege
+ @win_only
+ @win_disabled
+ @require_ctypes
+ def symlink_file(src, lnk):
+ if not ctypes.windll.kernel32.CreateSymbolicLinkW(unicode_path(lnk), unicode_path(src), 0):
+ raise ctypes.WinError()
+
+ # Requires SE_CREATE_SYMBOLIC_LINK_NAME privilege
+ @win_only
+ @win_disabled
+ @require_ctypes
+ def symlink_dir(src, lnk):
+ if not ctypes.windll.kernel32.CreateSymbolicLinkW(unicode_path(lnk), unicode_path(src), _SYMBOLIC_LINK_FLAG_DIRECTORY):
+ raise ctypes.WinError()
+
+ @win_only
+ @require_ctypes
+ def lock_file(f, offset, length, raises=True):
+ locked = ctypes.windll.kernel32.LockFile(file_handle(f), _low_dword(offset), _high_dword(offset), _low_dword(length), _high_dword(length))
+ if not raises:
+ return bool(locked)
+ if not locked:
+ raise ctypes.WinError()
+
+ @win_only
+ @require_ctypes
+ def unlock_file(f, offset, length, raises=True):
+ unlocked = ctypes.windll.kernel32.UnlockFile(file_handle(f), _low_dword(offset), _high_dword(offset), _low_dword(length), _high_dword(length))
+ if not raises:
+ return bool(unlocked)
+ if not unlocked:
+ raise ctypes.WinError()
+
+ @win_only
+ @require_ctypes
+ def set_error_mode(mode):
+ return ctypes.windll.kernel32.SetErrorMode(mode)
+
+ @win_only
+ def rmtree(path):
+ def error_handler(func, handling_path, execinfo):
+ e = execinfo[1]
+ if e.winerror == ERRORS['PATH_NOT_FOUND']:
+ handling_path = "\\\\?\\" + handling_path # handle path over 256 symbols
+ if os.path.exists(path):
+ return func(handling_path)
+ if e.winerror == ERRORS['ACCESS_DENIED']:
+ try:
+ # removing of r/w directory with read-only files in it yields ACCESS_DENIED
+ # which is not an insuperable obstacle https://bugs.python.org/issue19643
+ os.chmod(handling_path, stat.S_IWRITE)
+ except OSError:
+ pass
+ else:
+ # propagate true last error if this attempt fails
+ return func(handling_path)
+ raise e
+ shutil.rmtree(path, onerror=error_handler)
+
+ # Don't display the Windows GPF dialog if the invoked program dies.
+ # http://msdn.microsoft.com/en-us/library/windows/desktop/ms680621.aspx
+ @win_only
+ def disable_error_dialogs():
+ set_error_mode(_SEM_NOGPFAULTERRORBOX | _SEM_FAILCRITICALERRORS)
+
+ @win_only
+ def default_process_creation_flags():
+ return 0
+
+ @require_ctypes
+ def _low_dword(x):
+ return ctypes.c_ulong(x & ((1 << 32) - 1))
+
+ @require_ctypes
+ def _high_dword(x):
+ return ctypes.c_ulong((x >> 32) & ((1 << 32) - 1))
+
+ @win_only
+ @require_ctypes
+ def get_current_process():
+ handle = ctypes.windll.kernel32.GetCurrentProcess()
+ if not handle:
+ raise ctypes.WinError()
+ return wintypes.HANDLE(handle)
+
+ @win_only
+ @require_ctypes
+ def get_process_handle_count(proc_handle):
+ assert isinstance(proc_handle, wintypes.HANDLE)
+
+ GetProcessHandleCount = ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.HANDLE, wintypes.POINTER(wintypes.DWORD))(("GetProcessHandleCount", ctypes.windll.kernel32))
+ hndcnt = wintypes.DWORD()
+ if not GetProcessHandleCount(proc_handle, ctypes.byref(hndcnt)):
+ raise ctypes.WinError()
+ return hndcnt.value
+
+ @win_only
+ @require_ctypes
+ def set_handle_information(file, inherit=None, protect_from_close=None):
+ for flag, value in [(inherit, 1), (protect_from_close, 2)]:
+ if flag is not None:
+ assert isinstance(flag, bool)
+ if not ctypes.windll.kernel32.SetHandleInformation(file_handle(file), _low_dword(value), _low_dword(int(flag))):
+ raise ctypes.WinError()
+
+ @win_only
+ @require_ctypes
+ def get_windows_directory():
+ buf = ctypes.create_unicode_buffer(ctypes.wintypes.MAX_PATH)
+ size = ctypes.windll.kernel32.GetWindowsDirectoryW(buf, ctypes.wintypes.MAX_PATH)
+ if not size:
+ raise ctypes.WinError()
+ if size > ctypes.wintypes.MAX_PATH - 1:
+ raise CustomWinError(ERRORS['INSUFFICIENT_BUFFER'])
+ return ctypes.wstring_at(buf, size)
diff --git a/library/python/windows/ut/test_windows.py b/library/python/windows/ut/test_windows.py
new file mode 100644
index 0000000000..bef3ec2dc5
--- /dev/null
+++ b/library/python/windows/ut/test_windows.py
@@ -0,0 +1,96 @@
+# coding=utf-8
+
+import errno
+import os
+import pytest
+
+import library.python.strings
+import library.python.windows
+
+
+def gen_error_access_denied():
+ if library.python.windows.on_win():
+ err = WindowsError()
+ err.errno = errno.EACCES
+ err.strerror = ''
+ err.winerror = library.python.windows.ERRORS['ACCESS_DENIED']
+ else:
+ err = OSError()
+ err.errno = errno.EACCES
+ err.strerror = os.strerror(err.errno)
+ err.filename = 'unknown/file'
+ raise err
+
+
+def test_errorfix_buggy():
+ @library.python.windows.errorfix
+ def erroneous_func():
+ gen_error_access_denied()
+
+ with pytest.raises(OSError) as errinfo:
+ erroneous_func()
+ assert errinfo.value.errno == errno.EACCES
+ assert errinfo.value.filename == 'unknown/file'
+ assert isinstance(errinfo.value.strerror, basestring)
+ assert errinfo.value.strerror
+
+
+def test_errorfix_explicit():
+ @library.python.windows.errorfix
+ def erroneous_func():
+ if library.python.windows.on_win():
+ err = WindowsError()
+ err.winerror = library.python.windows.ERRORS['ACCESS_DENIED']
+ else:
+ err = OSError()
+ err.errno = errno.EACCES
+ err.strerror = 'Some error description'
+ err.filename = 'unknown/file'
+ raise err
+
+ with pytest.raises(OSError) as errinfo:
+ erroneous_func()
+ assert errinfo.value.errno == errno.EACCES
+ assert errinfo.value.filename == 'unknown/file'
+ assert errinfo.value.strerror == 'Some error description'
+
+
+def test_errorfix_decoding_cp1251():
+ @library.python.windows.errorfix
+ def erroneous_func():
+ model_msg = u'Какое-то описание ошибки'
+ if library.python.windows.on_win():
+ err = WindowsError()
+ err.strerror = library.python.strings.to_str(model_msg, 'cp1251')
+ else:
+ err = OSError()
+ err.strerror = library.python.strings.to_str(model_msg)
+ raise err
+
+ with pytest.raises(OSError) as errinfo:
+ erroneous_func()
+ error_msg = errinfo.value.strerror
+ if not isinstance(errinfo.value.strerror, unicode):
+ error_msg = library.python.strings.to_unicode(error_msg)
+ assert error_msg == u'Какое-то описание ошибки'
+
+
+def test_diehard():
+ @library.python.windows.diehard(library.python.windows.ERRORS['ACCESS_DENIED'], tries=5)
+ def erroneous_func(errors):
+ try:
+ gen_error_access_denied()
+ except Exception as e:
+ errors.append(e)
+ raise
+
+ raised_errors = []
+ with pytest.raises(OSError) as errinfo:
+ erroneous_func(raised_errors)
+ assert errinfo.value.errno == errno.EACCES
+ assert any(e.errno == errno.EACCES for e in raised_errors)
+ assert raised_errors and errinfo.value == raised_errors[-1]
+ if library.python.windows.on_win():
+ assert len(raised_errors) == 5
+ else:
+ assert len(raised_errors) == 1
diff --git a/library/python/windows/ut/ya.make b/library/python/windows/ut/ya.make
new file mode 100644
index 0000000000..c39f1797b8
--- /dev/null
+++ b/library/python/windows/ut/ya.make
@@ -0,0 +1,11 @@
+OWNER(g:yatool)
+
+PY2TEST()
+
+TEST_SRCS(test_windows.py)
+
+PEERDIR(
+ library/python/windows
+)
+
+END()
diff --git a/library/python/windows/ya.make b/library/python/windows/ya.make
new file mode 100644
index 0000000000..e17f86b67e
--- /dev/null
+++ b/library/python/windows/ya.make
@@ -0,0 +1,13 @@
+OWNER(g:yatool)
+
+PY23_LIBRARY()
+
+PY_SRCS(__init__.py)
+
+PEERDIR(
+ library/python/func
+ library/python/strings
+ contrib/python/six
+)
+
+END()
diff --git a/library/python/ya.make b/library/python/ya.make
new file mode 100644
index 0000000000..2e1eb6e0e1
--- /dev/null
+++ b/library/python/ya.make
@@ -0,0 +1,222 @@
+OWNER(g:python-contrib)
+
+RECURSE(
+ aho_corasick
+ aho_corasick/ut
+ archive
+ archive/benchmark
+ archive/test
+ archive/test/data
+ asgi_yauth
+ async_clients
+ auth_client_parser
+ awssdk-extensions
+ awssdk_async_extensions
+ base64
+ base64/test
+ bclclient
+ blackbox
+ blackbox/tests
+ blackbox/tvm2
+ bloom
+ boost_test
+ bstr
+ build_info
+ build_info/ut
+ capabilities
+ celery_dashboard
+ certifi
+ cgroups
+ charset
+ charts_notes
+ charts_notes/example
+ cityhash
+ cityhash/test
+ clickhouse_client
+ cmain
+ codecs
+ codecs/gen_corpus
+ codecs/test
+ compress
+ compress/tests
+ cookiemy
+ coredump_filter
+ cores
+ coverage
+ cpp_test
+ cppdemangle
+ cqueue
+ crowd-kit
+ cyson
+ cyson/pymodule
+ cyson/ut
+ deploy_formatter
+ deprecated
+ dir-sync
+ django
+ django/example
+ django-idm-api
+ django-multic
+ django-sform
+ django-sform/tests
+ django_alive
+ django_celery_monitoring
+ django_russian
+ django_template_common
+ django_tools_log_context
+ dssclient
+ dump_dict
+ edit_distance
+ errorboosterclient
+ filelock
+ filelock/ut
+ filesys
+ filesys/ut
+ find_root
+ flask
+ flask_passport
+ fnvhash
+ fnvhash/test
+ framing
+ framing/ut
+ func
+ func/ut
+ fs
+ geolocation
+ geolocation/ut
+ geohash
+ geohash/ut
+ golovan_stats_aggregator
+ granular_settings
+ granular_settings/tests
+ guid
+ guid/test
+ guid/at_fork_test
+ gunicorn
+ hnsw
+ ids
+ import_test
+ infected_masks
+ infected_masks/ut
+ init_log
+ init_log/example
+ intrasearch_fetcher
+ json
+ json/compare
+ json/perf
+ json/test
+ json/test/py2
+ json/test/py3
+ langdetect
+ langmask
+ langs
+ luigi
+ luigi/data
+ luigi/example
+ luigi/luigid_static
+ maths
+ messagebus
+ metrics_framework
+ mime_types
+ monitoring
+ monlib
+ monlib/examples
+ monlib/so
+ murmurhash
+ nirvana
+ nirvana_api
+ nirvana_api/test_lib
+ nirvana_test
+ nstools
+ nyt
+ oauth
+ oauth/example
+ ok_client
+ openssl
+ par_apply
+ par_apply/test
+ path
+ path/tests
+ protobuf
+ pymain
+ pyscopg2
+ pytest
+ pytest-mongodb
+ pytest/allure
+ pytest/empty
+ pytest/plugins
+ python-blackboxer
+ python-django-tanker
+ python-django-yauth/tests
+ python-django-yauth
+ reactor
+ redis_utils
+ reservoir_sampling
+ refsclient
+ resource
+ retry
+ retry/tests
+ runtime
+ runtime/main
+ runtime/test
+ runtime_py3
+ runtime_py3/main
+ runtime_py3/test
+ runtime_test
+ sanitizers
+ sdms_api
+ sfx
+ selenium_ui_test
+ sendmsg
+ stubmaker
+ solomon
+ spack
+ spyt
+ ssh_client
+ ssh_sign
+ startrek_python_client
+ startrek_python_client/tests_int
+ statface_client
+ step
+ strings
+ strings/ut
+ svn_ssh
+ svn_version
+ svn_version/ut
+ symbols
+ testing
+ tmp
+ toloka_client
+ toloka-kit
+ toloka-airflow
+ toloka-prefect
+ tools_structured_logs
+ thread
+ thread/test
+ tskv
+ tvmauth
+ tvm2
+ tvm2/tests
+ type_info
+ type_info/test
+ unique_id
+ vault_client
+ watch_dog
+ watch_dog/example
+ wiki
+ windows
+ windows/ut
+ yandex_tracker_client
+ yenv
+ yt
+ yt/test
+ ylock
+ ylock/tests
+ zipatch
+)
+
+IF (NOT MUSL)
+ RECURSE(
+ yt/example
+ )
+ENDIF()
diff --git a/library/ya.make b/library/ya.make
new file mode 100644
index 0000000000..86f833bd02
--- /dev/null
+++ b/library/ya.make
@@ -0,0 +1,18 @@
+OWNER(g:cpp-contrib)
+
+RECURSE(
+ c
+ cpp
+ python
+ recipes
+ #lemmer/byk/ut
+)
+
+IF (NOT SANITIZER_TYPE)
+ RECURSE(
+ go
+ java
+ )
+ENDIF()
+
+NEED_CHECK()